From b1b38278e12b04cf9a227f6af2c24651cf6e8a85 Mon Sep 17 00:00:00 2001 From: David Weinehall Date: Wed, 20 May 2015 17:00:13 +0300 Subject: drm/i915: add a context parameter to {en, dis}able zero address mapping Export a new context parameter that can be set/queried through the context_{get,set}param ioctls. This parameter is passed as a context flag and decides whether or not a GPU address mapping is allowed to be made at address zero. The default is to allow such mappings. Signed-off-by: David Weinehall Acked-by: "Zou, Nanhai" Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +++++ drivers/gpu/drm/i915/i915_gem_context.c | 11 +++++++++++ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 13 +++++++++---- 3 files changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 72f5a3f9dbf2..d35b592c7378 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -805,11 +805,15 @@ struct i915_ctx_hang_stats { /* This must match up with the value previously used for execbuf2.rsvd1. */ #define DEFAULT_CONTEXT_HANDLE 0 + +#define CONTEXT_NO_ZEROMAP (1<<0) /** * struct intel_context - as the name implies, represents a context. * @ref: reference count. * @user_handle: userspace tracking identity for this context. * @remap_slice: l3 row remapping information. + * @flags: context specific flags: + * CONTEXT_NO_ZEROMAP: do not allow mapping things to page 0. * @file_priv: filp associated with this context (NULL for global default * context). * @hang_stats: information about the role of this context in possible GPU @@ -826,6 +830,7 @@ struct intel_context { struct kref ref; int user_handle; uint8_t remap_slice; + int flags; struct drm_i915_file_private *file_priv; struct i915_ctx_hang_stats hang_stats; struct i915_hw_ppgtt *ppgtt; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 8867818b1401..133afcf4d79e 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -900,6 +900,9 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, case I915_CONTEXT_PARAM_BAN_PERIOD: args->value = ctx->hang_stats.ban_period_seconds; break; + case I915_CONTEXT_PARAM_NO_ZEROMAP: + args->value = ctx->flags & CONTEXT_NO_ZEROMAP; + break; default: ret = -EINVAL; break; @@ -937,6 +940,14 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, else ctx->hang_stats.ban_period_seconds = args->value; break; + case I915_CONTEXT_PARAM_NO_ZEROMAP: + if (args->size) { + ret = -EINVAL; + } else { + ctx->flags &= ~CONTEXT_NO_ZEROMAP; + ctx->flags |= args->value ? CONTEXT_NO_ZEROMAP : 0; + } + break; default: ret = -EINVAL; break; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index bd0e4bda2c64..3336e1c2c0a5 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -676,6 +676,7 @@ eb_vma_misplaced(struct i915_vma *vma) static int i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, struct list_head *vmas, + struct intel_context *ctx, bool *need_relocs) { struct drm_i915_gem_object *obj; @@ -698,6 +699,9 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, obj = vma->obj; entry = vma->exec_entry; + if (ctx->flags & CONTEXT_NO_ZEROMAP) + entry->flags |= __EXEC_OBJECT_NEEDS_BIAS; + if (!has_fenced_gpu_access) entry->flags &= ~EXEC_OBJECT_NEEDS_FENCE; need_fence = @@ -775,7 +779,8 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, struct drm_file *file, struct intel_engine_cs *ring, struct eb_vmas *eb, - struct drm_i915_gem_exec_object2 *exec) + struct drm_i915_gem_exec_object2 *exec, + struct intel_context *ctx) { struct drm_i915_gem_relocation_entry *reloc; struct i915_address_space *vm; @@ -861,7 +866,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, goto err; need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; - ret = i915_gem_execbuffer_reserve(ring, &eb->vmas, &need_relocs); + ret = i915_gem_execbuffer_reserve(ring, &eb->vmas, ctx, &need_relocs); if (ret) goto err; @@ -1519,7 +1524,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* Move the objects en-masse into the GTT, evicting if necessary. */ need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; - ret = i915_gem_execbuffer_reserve(ring, &eb->vmas, &need_relocs); + ret = i915_gem_execbuffer_reserve(ring, &eb->vmas, ctx, &need_relocs); if (ret) goto err; @@ -1529,7 +1534,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) { if (ret == -EFAULT) { ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, - eb, exec); + eb, exec, ctx); BUG_ON(!mutex_is_locked(&dev->struct_mutex)); } if (ret) -- cgit v1.3-6-gb490 From 0d2e42970cfa8814ce5f73e329f61c94b7ec2dab Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:39 +0300 Subject: drm/i915: reduce indent in i9xx_hpd_irq_handler Bail out early if nothing to do. No functional changes. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e6bb72dca3ff..f0206f63617e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1756,28 +1756,29 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); - if (hotplug_status) { - I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); - /* - * Make sure hotplug status is cleared before we clear IIR, or else we - * may miss hotplug events. - */ - POSTING_READ(PORT_HOTPLUG_STAT); + if (!hotplug_status) + return; - if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { - u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); + /* + * Make sure hotplug status is cleared before we clear IIR, or else we + * may miss hotplug events. + */ + POSTING_READ(PORT_HOTPLUG_STAT); - intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_g4x); - } else { - u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; + if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { + u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; - intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_i915); - } + intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_g4x); + } else { + u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; - if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && - hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) - dp_aux_irq_handler(dev); + intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_i915); } + + if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && + hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) + dp_aux_irq_handler(dev); } static irqreturn_t valleyview_irq_handler(int irq, void *arg) -- cgit v1.3-6-gb490 From 369712e89404089fa559235bb1ee8fc40d976e6b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:40 +0300 Subject: drm/i915: reduce duplicate conditions in i9xx_hpd_irq_handler Move dp aux irq handling within the same branch instead of duplicating the conditions. No functional changes. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f0206f63617e..333b3d9dd5fc 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1770,15 +1770,14 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_g4x); + + if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) + dp_aux_irq_handler(dev); } else { u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_i915); } - - if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && - hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) - dp_aux_irq_handler(dev); } static irqreturn_t valleyview_irq_handler(int irq, void *arg) -- cgit v1.3-6-gb490 From b0c29a33fc80bec3ae0f5862d7733e3782878d6d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:41 +0300 Subject: drm/i915: reduce indent in intel_hpd_irq_handler Continue to loop early if there's nothing to do. No functional changes. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 49 ++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 333b3d9dd5fc..48e5b79a7929 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1442,36 +1442,39 @@ static void intel_hpd_irq_handler(struct drm_device *dev, spin_lock(&dev_priv->irq_lock); for (i = 1; i < HPD_NUM_PINS; i++) { + bool long_hpd; + if (!(hpd[i] & hotplug_trigger)) continue; port = get_port_from_pin(i); - if (port && dev_priv->hpd_irq_port[port]) { - bool long_hpd; + if (!port || !dev_priv->hpd_irq_port[port]) + continue; - if (!HAS_GMCH_DISPLAY(dev_priv)) { - dig_shift = pch_port_to_hotplug_shift(port); - long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } else { - dig_shift = i915_port_to_hotplug_shift(port); - long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } + if (!HAS_GMCH_DISPLAY(dev_priv)) { + dig_shift = pch_port_to_hotplug_shift(port); + long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; + } else { + dig_shift = i915_port_to_hotplug_shift(port); + long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; + } - DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", - port_name(port), - long_hpd ? "long" : "short"); - /* for long HPD pulses we want to have the digital queue happen, - but we still want HPD storm detection to function. */ - if (long_hpd) { - dev_priv->long_hpd_port_mask |= (1 << port); - dig_port_mask |= hpd[i]; - } else { - /* for short HPD just trigger the digital queue */ - dev_priv->short_hpd_port_mask |= (1 << port); - hotplug_trigger &= ~hpd[i]; - } - queue_dig = true; + DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), + long_hpd ? "long" : "short"); + /* + * For long HPD pulses we want to have the digital queue happen, + * but we still want HPD storm detection to function. + */ + if (long_hpd) { + dev_priv->long_hpd_port_mask |= (1 << port); + dig_port_mask |= hpd[i]; + } else { + /* for short HPD just trigger the digital queue */ + dev_priv->short_hpd_port_mask |= (1 << port); + hotplug_trigger &= ~hpd[i]; } + + queue_dig = true; } for (i = 1; i < HPD_NUM_PINS; i++) { -- cgit v1.3-6-gb490 From 5fcece80ecdac932a0acb71e3a239c39dd4af20f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:42 +0300 Subject: drm/i915: group all hotplug related fields into a new struct in dev_priv There are plenty of hotplug related fields in struct drm_i915_private scattered all around. Group them under one hotplug struct. Clean up naming while at it. No functional changes. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 8 ++-- drivers/gpu/drm/i915/i915_drv.c | 12 +++--- drivers/gpu/drm/i915/i915_drv.h | 58 ++++++++++++++------------- drivers/gpu/drm/i915/i915_irq.c | 86 ++++++++++++++++++++-------------------- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_dp.c | 6 +-- 6 files changed, 88 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index d2df321ba634..34248635c36c 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -933,8 +933,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_mtrrfree; } - dev_priv->dp_wq = alloc_ordered_workqueue("i915-dp", 0); - if (dev_priv->dp_wq == NULL) { + dev_priv->hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0); + if (dev_priv->hotplug.dp_wq == NULL) { DRM_ERROR("Failed to create our dp workqueue.\n"); ret = -ENOMEM; goto out_freewq; @@ -1029,7 +1029,7 @@ out_gem_unload: pm_qos_remove_request(&dev_priv->pm_qos); destroy_workqueue(dev_priv->gpu_error.hangcheck_wq); out_freedpwq: - destroy_workqueue(dev_priv->dp_wq); + destroy_workqueue(dev_priv->hotplug.dp_wq); out_freewq: destroy_workqueue(dev_priv->wq); out_mtrrfree: @@ -1123,7 +1123,7 @@ int i915_driver_unload(struct drm_device *dev) intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); - destroy_workqueue(dev_priv->dp_wq); + destroy_workqueue(dev_priv->hotplug.dp_wq); destroy_workqueue(dev_priv->wq); destroy_workqueue(dev_priv->gpu_error.hangcheck_wq); pm_qos_remove_request(&dev_priv->pm_qos); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 884b4f9b81c4..a051a0241883 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -545,15 +545,15 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) { spin_lock_irq(&dev_priv->irq_lock); - dev_priv->long_hpd_port_mask = 0; - dev_priv->short_hpd_port_mask = 0; - dev_priv->hpd_event_bits = 0; + dev_priv->hotplug.long_port_mask = 0; + dev_priv->hotplug.short_port_mask = 0; + dev_priv->hotplug.event_bits = 0; spin_unlock_irq(&dev_priv->irq_lock); - cancel_work_sync(&dev_priv->dig_port_work); - cancel_work_sync(&dev_priv->hotplug_work); - cancel_delayed_work_sync(&dev_priv->hotplug_reenable_work); + cancel_work_sync(&dev_priv->hotplug.dig_port_work); + cancel_work_sync(&dev_priv->hotplug.hotplug_work); + cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work); } void i915_firmware_load_error_print(const char *fw_path, int err) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d35b592c7378..173c9051bf86 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -217,6 +217,36 @@ enum hpd_pin { HPD_NUM_PINS }; +struct i915_hotplug { + struct work_struct hotplug_work; + + struct { + unsigned long last_jiffies; + int count; + enum { + HPD_ENABLED = 0, + HPD_DISABLED = 1, + HPD_MARK_DISABLED = 2 + } state; + } stats[HPD_NUM_PINS]; + u32 event_bits; + struct delayed_work reenable_work; + + struct intel_digital_port *irq_port[I915_MAX_PORTS]; + u32 long_port_mask; + u32 short_port_mask; + struct work_struct dig_port_work; + + /* + * if we get a HPD irq from DP and a HPD irq from non-DP + * the non-DP HPD could block the workqueue on a mode config + * mutex getting, that userspace may have taken. However + * userspace is waiting on the DP workqueue to run which is + * blocked behind the non-DP one. + */ + struct workqueue_struct *dp_wq; +}; + #define I915_GEM_GPU_DOMAINS \ (I915_GEM_DOMAIN_RENDER | \ I915_GEM_DOMAIN_SAMPLER | \ @@ -1684,19 +1714,7 @@ struct drm_i915_private { u32 pm_rps_events; u32 pipestat_irq_mask[I915_MAX_PIPES]; - struct work_struct hotplug_work; - struct { - unsigned long hpd_last_jiffies; - int hpd_cnt; - enum { - HPD_ENABLED = 0, - HPD_DISABLED = 1, - HPD_MARK_DISABLED = 2 - } hpd_mark; - } hpd_stats[HPD_NUM_PINS]; - u32 hpd_event_bits; - struct delayed_work hotplug_reenable_work; - + struct i915_hotplug hotplug; struct i915_fbc fbc; struct i915_drrs drrs; struct intel_opregion opregion; @@ -1862,20 +1880,6 @@ struct drm_i915_private { struct i915_runtime_pm pm; - struct intel_digital_port *hpd_irq_port[I915_MAX_PORTS]; - u32 long_hpd_port_mask; - u32 short_hpd_port_mask; - struct work_struct dig_port_work; - - /* - * if we get a HPD irq from DP and a HPD irq from non-DP - * the non-DP HPD could block the workqueue on a mode config - * mutex getting, that userspace may have taken. However - * userspace is waiting on the DP workqueue to run which is - * blocked behind the non-DP one. - */ - struct workqueue_struct *dp_wq; - /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */ struct { int (*execbuf_submit)(struct drm_device *dev, struct drm_file *file, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 48e5b79a7929..91cb0b6ec47b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -832,23 +832,23 @@ static bool intel_hpd_irq_event(struct drm_device *dev, static void i915_digport_work_func(struct work_struct *work) { struct drm_i915_private *dev_priv = - container_of(work, struct drm_i915_private, dig_port_work); + container_of(work, struct drm_i915_private, hotplug.dig_port_work); u32 long_port_mask, short_port_mask; struct intel_digital_port *intel_dig_port; int i; u32 old_bits = 0; spin_lock_irq(&dev_priv->irq_lock); - long_port_mask = dev_priv->long_hpd_port_mask; - dev_priv->long_hpd_port_mask = 0; - short_port_mask = dev_priv->short_hpd_port_mask; - dev_priv->short_hpd_port_mask = 0; + long_port_mask = dev_priv->hotplug.long_port_mask; + dev_priv->hotplug.long_port_mask = 0; + short_port_mask = dev_priv->hotplug.short_port_mask; + dev_priv->hotplug.short_port_mask = 0; spin_unlock_irq(&dev_priv->irq_lock); for (i = 0; i < I915_MAX_PORTS; i++) { bool valid = false; bool long_hpd = false; - intel_dig_port = dev_priv->hpd_irq_port[i]; + intel_dig_port = dev_priv->hotplug.irq_port[i]; if (!intel_dig_port || !intel_dig_port->hpd_pulse) continue; @@ -871,9 +871,9 @@ static void i915_digport_work_func(struct work_struct *work) if (old_bits) { spin_lock_irq(&dev_priv->irq_lock); - dev_priv->hpd_event_bits |= old_bits; + dev_priv->hotplug.event_bits |= old_bits; spin_unlock_irq(&dev_priv->irq_lock); - schedule_work(&dev_priv->hotplug_work); + schedule_work(&dev_priv->hotplug.hotplug_work); } } @@ -885,7 +885,7 @@ static void i915_digport_work_func(struct work_struct *work) static void i915_hotplug_work_func(struct work_struct *work) { struct drm_i915_private *dev_priv = - container_of(work, struct drm_i915_private, hotplug_work); + container_of(work, struct drm_i915_private, hotplug.hotplug_work); struct drm_device *dev = dev_priv->dev; struct drm_mode_config *mode_config = &dev->mode_config; struct intel_connector *intel_connector; @@ -900,20 +900,20 @@ static void i915_hotplug_work_func(struct work_struct *work) spin_lock_irq(&dev_priv->irq_lock); - hpd_event_bits = dev_priv->hpd_event_bits; - dev_priv->hpd_event_bits = 0; + hpd_event_bits = dev_priv->hotplug.event_bits; + dev_priv->hotplug.event_bits = 0; list_for_each_entry(connector, &mode_config->connector_list, head) { intel_connector = to_intel_connector(connector); if (!intel_connector->encoder) continue; intel_encoder = intel_connector->encoder; if (intel_encoder->hpd_pin > HPD_NONE && - dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_MARK_DISABLED && + dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_MARK_DISABLED && connector->polled == DRM_CONNECTOR_POLL_HPD) { DRM_INFO("HPD interrupt storm detected on connector %s: " "switching from hotplug detection to polling\n", connector->name); - dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark = HPD_DISABLED; + dev_priv->hotplug.stats[intel_encoder->hpd_pin].state = HPD_DISABLED; connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; hpd_disabled = true; @@ -928,7 +928,7 @@ static void i915_hotplug_work_func(struct work_struct *work) * some connectors */ if (hpd_disabled) { drm_kms_helper_poll_enable(dev); - mod_delayed_work(system_wq, &dev_priv->hotplug_reenable_work, + mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); } @@ -1448,7 +1448,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, continue; port = get_port_from_pin(i); - if (!port || !dev_priv->hpd_irq_port[port]) + if (!port || !dev_priv->hotplug.irq_port[port]) continue; if (!HAS_GMCH_DISPLAY(dev_priv)) { @@ -1466,11 +1466,11 @@ static void intel_hpd_irq_handler(struct drm_device *dev, * but we still want HPD storm detection to function. */ if (long_hpd) { - dev_priv->long_hpd_port_mask |= (1 << port); + dev_priv->hotplug.long_port_mask |= (1 << port); dig_port_mask |= hpd[i]; } else { /* for short HPD just trigger the digital queue */ - dev_priv->short_hpd_port_mask |= (1 << port); + dev_priv->hotplug.short_port_mask |= (1 << port); hotplug_trigger &= ~hpd[i]; } @@ -1479,7 +1479,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, for (i = 1; i < HPD_NUM_PINS; i++) { if (hpd[i] & hotplug_trigger && - dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED) { + dev_priv->hotplug.stats[i].state == HPD_DISABLED) { /* * On GMCH platforms the interrupt mask bits only * prevent irq generation, not the setting of the @@ -1494,29 +1494,29 @@ static void intel_hpd_irq_handler(struct drm_device *dev, } if (!(hpd[i] & hotplug_trigger) || - dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) + dev_priv->hotplug.stats[i].state != HPD_ENABLED) continue; if (!(dig_port_mask & hpd[i])) { - dev_priv->hpd_event_bits |= (1 << i); + dev_priv->hotplug.event_bits |= (1 << i); queue_hp = true; } - if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies, - dev_priv->hpd_stats[i].hpd_last_jiffies + if (!time_in_range(jiffies, dev_priv->hotplug.stats[i].last_jiffies, + dev_priv->hotplug.stats[i].last_jiffies + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) { - dev_priv->hpd_stats[i].hpd_last_jiffies = jiffies; - dev_priv->hpd_stats[i].hpd_cnt = 0; + dev_priv->hotplug.stats[i].last_jiffies = jiffies; + dev_priv->hotplug.stats[i].count = 0; DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", i); - } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) { - dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; - dev_priv->hpd_event_bits &= ~(1 << i); + } else if (dev_priv->hotplug.stats[i].count > HPD_STORM_THRESHOLD) { + dev_priv->hotplug.stats[i].state = HPD_MARK_DISABLED; + dev_priv->hotplug.event_bits &= ~(1 << i); DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); storm_detected = true; } else { - dev_priv->hpd_stats[i].hpd_cnt++; + dev_priv->hotplug.stats[i].count++; DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", i, - dev_priv->hpd_stats[i].hpd_cnt); + dev_priv->hotplug.stats[i].count); } } @@ -1531,9 +1531,9 @@ static void intel_hpd_irq_handler(struct drm_device *dev, * deadlock. */ if (queue_dig) - queue_work(dev_priv->dp_wq, &dev_priv->dig_port_work); + queue_work(dev_priv->hotplug.dp_wq, &dev_priv->hotplug.dig_port_work); if (queue_hp) - schedule_work(&dev_priv->hotplug_work); + schedule_work(&dev_priv->hotplug.hotplug_work); } static void gmbus_irq_handler(struct drm_device *dev) @@ -3213,12 +3213,12 @@ static void ibx_hpd_irq_setup(struct drm_device *dev) if (HAS_PCH_IBX(dev)) { hotplug_irqs = SDE_HOTPLUG_MASK; for_each_intel_encoder(dev, intel_encoder) - if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED) enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin]; } else { hotplug_irqs = SDE_HOTPLUG_MASK_CPT; for_each_intel_encoder(dev, intel_encoder) - if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED) enabled_irqs |= hpd_cpt[intel_encoder->hpd_pin]; } @@ -3247,7 +3247,7 @@ static void bxt_hpd_irq_setup(struct drm_device *dev) /* Now, enable HPD */ for_each_intel_encoder(dev, intel_encoder) { - if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark + if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED) hotplug_port |= hpd_bxt[intel_encoder->hpd_pin]; } @@ -4140,7 +4140,7 @@ static void i915_hpd_irq_setup(struct drm_device *dev) /* Note HDMI and DP share hotplug bits */ /* enable bits are the same for all generations */ for_each_intel_encoder(dev, intel_encoder) - if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED) hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin]; /* Programming the CRT detection parameters tends to generate a spurious hotplug event about three @@ -4284,7 +4284,7 @@ static void intel_hpd_irq_reenable_work(struct work_struct *work) { struct drm_i915_private *dev_priv = container_of(work, typeof(*dev_priv), - hotplug_reenable_work.work); + hotplug.reenable_work.work); struct drm_device *dev = dev_priv->dev; struct drm_mode_config *mode_config = &dev->mode_config; int i; @@ -4295,10 +4295,10 @@ static void intel_hpd_irq_reenable_work(struct work_struct *work) for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) { struct drm_connector *connector; - if (dev_priv->hpd_stats[i].hpd_mark != HPD_DISABLED) + if (dev_priv->hotplug.stats[i].state != HPD_DISABLED) continue; - dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; + dev_priv->hotplug.stats[i].state = HPD_ENABLED; list_for_each_entry(connector, &mode_config->connector_list, head) { struct intel_connector *intel_connector = to_intel_connector(connector); @@ -4331,8 +4331,8 @@ void intel_irq_init(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; - INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); - INIT_WORK(&dev_priv->dig_port_work, i915_digport_work_func); + INIT_WORK(&dev_priv->hotplug.hotplug_work, i915_hotplug_work_func); + INIT_WORK(&dev_priv->hotplug.dig_port_work, i915_digport_work_func); INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); @@ -4345,7 +4345,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work, i915_hangcheck_elapsed); - INIT_DELAYED_WORK(&dev_priv->hotplug_reenable_work, + INIT_DELAYED_WORK(&dev_priv->hotplug.reenable_work, intel_hpd_irq_reenable_work); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); @@ -4451,8 +4451,8 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) int i; for (i = 1; i < HPD_NUM_PINS; i++) { - dev_priv->hpd_stats[i].hpd_cnt = 0; - dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; + dev_priv->hotplug.stats[i].count = 0; + dev_priv->hotplug.stats[i].state = HPD_ENABLED; } list_for_each_entry(connector, &mode_config->connector_list, head) { struct intel_connector *intel_connector = to_intel_connector(connector); diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index cacb07b7a8f1..62a7c7f2b5d4 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2832,7 +2832,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) goto err; intel_dig_port->hpd_pulse = intel_dp_hpd_pulse; - dev_priv->hpd_irq_port[port] = intel_dig_port; + dev_priv->hotplug.irq_port[port] = intel_dig_port; } /* In theory we don't need the encoder->type check, but leave it just in diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 280c282da9bd..61c8d28deabe 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5940,7 +5940,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->hot_plug = intel_dp_hot_plug; intel_dig_port->hpd_pulse = intel_dp_hpd_pulse; - dev_priv->hpd_irq_port[port] = intel_dig_port; + dev_priv->hotplug.irq_port[port] = intel_dig_port; if (!intel_dp_init_connector(intel_dig_port, intel_connector)) { drm_encoder_cleanup(encoder); @@ -5956,7 +5956,7 @@ void intel_dp_mst_suspend(struct drm_device *dev) /* disable MST */ for (i = 0; i < I915_MAX_PORTS; i++) { - struct intel_digital_port *intel_dig_port = dev_priv->hpd_irq_port[i]; + struct intel_digital_port *intel_dig_port = dev_priv->hotplug.irq_port[i]; if (!intel_dig_port) continue; @@ -5975,7 +5975,7 @@ void intel_dp_mst_resume(struct drm_device *dev) int i; for (i = 0; i < I915_MAX_PORTS; i++) { - struct intel_digital_port *intel_dig_port = dev_priv->hpd_irq_port[i]; + struct intel_digital_port *intel_dig_port = dev_priv->hotplug.irq_port[i]; if (!intel_dig_port) continue; if (intel_dig_port->base.type == INTEL_OUTPUT_DISPLAYPORT) { -- cgit v1.3-6-gb490 From d66716200a8e8362599ce939df40821bb960e866 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:44 +0300 Subject: drm/i915: remove useless DP and DDI encoder ->hot_plug hooks The hotplug callbacks for DP and DDI effectively did nothing. Remove them. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 15 --------------- drivers/gpu/drm/i915/intel_dp.c | 7 ------- 2 files changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 62a7c7f2b5d4..54b60a97ef2d 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2618,20 +2618,6 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc) I915_WRITE(_FDI_RXA_CTL, val); } -static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) -{ - struct intel_digital_port *intel_dig_port = enc_to_dig_port(&intel_encoder->base); - int type = intel_dig_port->base.type; - - if (type != INTEL_OUTPUT_DISPLAYPORT && - type != INTEL_OUTPUT_EDP && - type != INTEL_OUTPUT_UNKNOWN) { - return; - } - - intel_dp_hot_plug(intel_encoder); -} - void intel_ddi_get_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { @@ -2825,7 +2811,6 @@ 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 = 0; - intel_encoder->hot_plug = intel_ddi_hot_plug; if (init_dp) { if (!intel_ddi_init_dp_connector(intel_dig_port)) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 61c8d28deabe..823a1b31177c 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4920,12 +4920,6 @@ static const struct drm_encoder_funcs intel_dp_enc_funcs = { .destroy = intel_dp_encoder_destroy, }; -void -intel_dp_hot_plug(struct intel_encoder *intel_encoder) -{ - return; -} - enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) { @@ -5937,7 +5931,6 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); } intel_encoder->cloneable = 0; - intel_encoder->hot_plug = intel_dp_hot_plug; intel_dig_port->hpd_pulse = intel_dp_hpd_pulse; dev_priv->hotplug.irq_port[port] = intel_dig_port; -- cgit v1.3-6-gb490 From ea875496360cf8f89ea009239bf7ef12cdd4febc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:45 +0300 Subject: drm/i915/dsi: remove non-op hot plug callback Not needed or used. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index b5a5558ecd63..98998e976dbb 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -261,11 +261,6 @@ static inline bool is_cmd_mode(struct intel_dsi *intel_dsi) return intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE; } -static void intel_dsi_hot_plug(struct intel_encoder *encoder) -{ - DRM_DEBUG_KMS("\n"); -} - static bool intel_dsi_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *config) { @@ -1022,7 +1017,6 @@ void intel_dsi_init(struct drm_device *dev) drm_encoder_init(dev, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI); /* XXX: very likely not all of these are needed */ - intel_encoder->hot_plug = intel_dsi_hot_plug; intel_encoder->compute_config = intel_dsi_compute_config; intel_encoder->pre_pll_enable = intel_dsi_pre_pll_enable; intel_encoder->pre_enable = intel_dsi_pre_enable; -- cgit v1.3-6-gb490 From 6cf75178deacd87af12a657d914e6bbca806b5ba Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:38 +0100 Subject: drm/i915/skl: Make sure to break when not finding suitable PLL dividers Right now, when finishing the cycle with odd dividers without finding a suitable candidate, we end up in an infinite loop. Make sure to break in that case. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 54b60a97ef2d..233467f40a4a 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1184,6 +1184,10 @@ found: } if (min_dco_index > 2 && dco_count == 2) { + /* oh well, we tried... */ + if (retry_with_odd) + break; + retry_with_odd = true; dco_count = 0; } -- cgit v1.3-6-gb490 From 19cdc0e6cdfc29e3ddee1fe56c3bcdfe25f6a916 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:39 +0100 Subject: drm/i915/skl: Display the WRPLL frequency we couldn't accomodate when failing This helps debugging. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 233467f40a4a..c1abe6efff9d 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1194,7 +1194,8 @@ found: } if (min_dco_index > 2) { - WARN(1, "No valid values found for the given pixel clock\n"); + WARN(1, "No valid parameters found for pixel clock: %dHz\n", + clock); } else { wrpll_params->central_freq = dco_central_freq[min_dco_index]; -- cgit v1.3-6-gb490 From 318bd821d65d37fb12c5673607e2b013f7a86a01 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:40 +0100 Subject: drm/i915/skl: Propagate the error if we fail to find a suitable DPLL divider At the moment, even if we fail to find a suitable divider, we'll still try to set the mode with bogus parameters. Just fail the modeset if we can't generate the frequency. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c1abe6efff9d..f10f55690749 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1115,7 +1115,7 @@ struct skl_wrpll_params { uint32_t central_freq; }; -static void +static bool skl_ddi_calculate_wrpll(int clock /* in Hz */, struct skl_wrpll_params *wrpll_params) { @@ -1196,6 +1196,7 @@ found: if (min_dco_index > 2) { WARN(1, "No valid parameters found for pixel clock: %dHz\n", clock); + return false; } else { wrpll_params->central_freq = dco_central_freq[min_dco_index]; @@ -1262,6 +1263,8 @@ found: wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); } + + return true; } @@ -1286,7 +1289,8 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, ctrl1 |= DPLL_CTRL1_HDMI_MODE(0); - skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params); + if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params)) + return false; cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE | DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) | -- cgit v1.3-6-gb490 From 9c2367538de381435503425c22c4f192c72e282e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:41 +0100 Subject: drm/i915/skl: Use a more idomatic early return We can coalesce the WARN() condition with the WARN() itself and, as we are returning early, we can de-intent the rest of the function. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 121 +++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index f10f55690749..c547f03904bc 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1193,76 +1193,73 @@ found: } } - if (min_dco_index > 2) { - WARN(1, "No valid parameters found for pixel clock: %dHz\n", - clock); + if (WARN(min_dco_index > 2, + "No valid parameters found for pixel clock: %dHz\n", clock)) return false; - } else { - wrpll_params->central_freq = dco_central_freq[min_dco_index]; - switch (dco_central_freq[min_dco_index]) { - case 9600000000ULL: - wrpll_params->central_freq = 0; - break; - case 9000000000ULL: - wrpll_params->central_freq = 1; - break; - case 8400000000ULL: - wrpll_params->central_freq = 3; - } + wrpll_params->central_freq = dco_central_freq[min_dco_index]; - switch (candidate_p0[min_dco_index]) { - case 1: - wrpll_params->pdiv = 0; - break; - case 2: - wrpll_params->pdiv = 1; - break; - case 3: - wrpll_params->pdiv = 2; - break; - case 7: - wrpll_params->pdiv = 4; - break; - default: - WARN(1, "Incorrect PDiv\n"); - } + switch (dco_central_freq[min_dco_index]) { + case 9600000000ULL: + wrpll_params->central_freq = 0; + break; + case 9000000000ULL: + wrpll_params->central_freq = 1; + break; + case 8400000000ULL: + wrpll_params->central_freq = 3; + } - switch (candidate_p2[min_dco_index]) { - case 5: - wrpll_params->kdiv = 0; - break; - case 2: - wrpll_params->kdiv = 1; - break; - case 3: - wrpll_params->kdiv = 2; - break; - case 1: - wrpll_params->kdiv = 3; - break; - default: - WARN(1, "Incorrect KDiv\n"); - } + switch (candidate_p0[min_dco_index]) { + case 1: + wrpll_params->pdiv = 0; + break; + case 2: + wrpll_params->pdiv = 1; + break; + case 3: + wrpll_params->pdiv = 2; + break; + case 7: + wrpll_params->pdiv = 4; + break; + default: + WARN(1, "Incorrect PDiv\n"); + } - wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; - wrpll_params->qdiv_mode = - (wrpll_params->qdiv_ratio == 1) ? 0 : 1; + switch (candidate_p2[min_dco_index]) { + case 5: + wrpll_params->kdiv = 0; + break; + case 2: + wrpll_params->kdiv = 1; + break; + case 3: + wrpll_params->kdiv = 2; + break; + case 1: + wrpll_params->kdiv = 3; + break; + default: + WARN(1, "Incorrect KDiv\n"); + } - dco_freq = candidate_p0[min_dco_index] * - candidate_p1[min_dco_index] * - candidate_p2[min_dco_index] * afe_clock; + wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; + wrpll_params->qdiv_mode = + (wrpll_params->qdiv_ratio == 1) ? 0 : 1; - /* - * Intermediate values are in Hz. - * Divide by MHz to match bsepc - */ - wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); - wrpll_params->dco_fraction = - div_u64(((div_u64(dco_freq, 24) - - wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); + dco_freq = candidate_p0[min_dco_index] * + candidate_p1[min_dco_index] * + candidate_p2[min_dco_index] * afe_clock; - } + /* + * Intermediate values are in Hz. + * Divide by MHz to match bsepc + */ + wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); + wrpll_params->dco_fraction = + div_u64(((div_u64(dco_freq, 24) - + wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); return true; } -- cgit v1.3-6-gb490 From 76516fbc294d60481f2427d6a42125364a629386 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:42 +0100 Subject: drm/i915/skl: Factor out computing the DPLL paramaters from the dividers This part doesn't depend on how we compute the DPLL dividers (p and p0/p1/p2) and can be reused even if we change the algorithm to do so. (something that is planned for a followup patch) Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 139 +++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c547f03904bc..a8d3976f7c5f 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1115,6 +1115,75 @@ struct skl_wrpll_params { uint32_t central_freq; }; +static void skl_wrpll_params_populate(struct skl_wrpll_params *params, + uint64_t afe_clock, + uint64_t central_freq, + uint32_t p0, uint32_t p1, uint32_t p2) +{ + uint64_t dco_freq; + + params->central_freq = central_freq; + + switch (central_freq) { + case 9600000000ULL: + params->central_freq = 0; + break; + case 9000000000ULL: + params->central_freq = 1; + break; + case 8400000000ULL: + params->central_freq = 3; + } + + switch (p0) { + case 1: + params->pdiv = 0; + break; + case 2: + params->pdiv = 1; + break; + case 3: + params->pdiv = 2; + break; + case 7: + params->pdiv = 4; + break; + default: + WARN(1, "Incorrect PDiv\n"); + } + + switch (p2) { + case 5: + params->kdiv = 0; + break; + case 2: + params->kdiv = 1; + break; + case 3: + params->kdiv = 2; + break; + case 1: + params->kdiv = 3; + break; + default: + WARN(1, "Incorrect KDiv\n"); + } + + params->qdiv_ratio = p1; + params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1; + + dco_freq = p0 * p1 * p2 * afe_clock; + + /* + * Intermediate values are in Hz. + * Divide by MHz to match bsepc + */ + params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); + params->dco_fraction = + div_u64(((div_u64(dco_freq, 24) - + params->dco_integer * MHz(1)) * 0x8000), MHz(1)); +} + static bool skl_ddi_calculate_wrpll(int clock /* in Hz */, struct skl_wrpll_params *wrpll_params) @@ -1134,7 +1203,6 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */, uint32_t dco_central_freq_deviation[3]; uint32_t i, P1, k, dco_count; bool retry_with_odd = false; - uint64_t dco_freq; /* Determine P0, P1 or P2 */ for (dco_count = 0; dco_count < 3; dco_count++) { @@ -1197,69 +1265,12 @@ found: "No valid parameters found for pixel clock: %dHz\n", clock)) return false; - wrpll_params->central_freq = dco_central_freq[min_dco_index]; - - switch (dco_central_freq[min_dco_index]) { - case 9600000000ULL: - wrpll_params->central_freq = 0; - break; - case 9000000000ULL: - wrpll_params->central_freq = 1; - break; - case 8400000000ULL: - wrpll_params->central_freq = 3; - } - - switch (candidate_p0[min_dco_index]) { - case 1: - wrpll_params->pdiv = 0; - break; - case 2: - wrpll_params->pdiv = 1; - break; - case 3: - wrpll_params->pdiv = 2; - break; - case 7: - wrpll_params->pdiv = 4; - break; - default: - WARN(1, "Incorrect PDiv\n"); - } - - switch (candidate_p2[min_dco_index]) { - case 5: - wrpll_params->kdiv = 0; - break; - case 2: - wrpll_params->kdiv = 1; - break; - case 3: - wrpll_params->kdiv = 2; - break; - case 1: - wrpll_params->kdiv = 3; - break; - default: - WARN(1, "Incorrect KDiv\n"); - } - - wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; - wrpll_params->qdiv_mode = - (wrpll_params->qdiv_ratio == 1) ? 0 : 1; - - dco_freq = candidate_p0[min_dco_index] * - candidate_p1[min_dco_index] * - candidate_p2[min_dco_index] * afe_clock; - - /* - * Intermediate values are in Hz. - * Divide by MHz to match bsepc - */ - wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); - wrpll_params->dco_fraction = - div_u64(((div_u64(dco_freq, 24) - - wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); + skl_wrpll_params_populate(wrpll_params, + afe_clock, + dco_central_freq[min_dco_index], + candidate_p0[min_dco_index], + candidate_p1[min_dco_index], + candidate_p2[min_dco_index]); return true; } -- cgit v1.3-6-gb490 From 30a7862de84e69abc3018c57184f485048eed9d8 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:43 +0100 Subject: drm/i915/skl: Remove unnecessary () used with div_u64() div_u64() can be either a inline function or a define, but in either case it's safe to provide expressions as parameters without outer () around them. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index a8d3976f7c5f..416f8fbea34e 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1178,10 +1178,10 @@ static void skl_wrpll_params_populate(struct skl_wrpll_params *params, * Intermediate values are in Hz. * Divide by MHz to match bsepc */ - params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); + params->dco_integer = div_u64(dco_freq, 24 * MHz(1)); params->dco_fraction = - div_u64(((div_u64(dco_freq, 24) - - params->dco_integer * MHz(1)) * 0x8000), MHz(1)); + div_u64((div_u64(dco_freq, 24) - + params->dco_integer * MHz(1)) * 0x8000, MHz(1)); } static bool -- cgit v1.3-6-gb490 From 64311571a91fdd6d2ddc9055e9ba477f118067ad Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:44 +0100 Subject: drm/i915/skl: Remove unnecessary () used with abs_diff() abs_diff() properly protects its parameters, so no need for the outer () here. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 416f8fbea34e..0f931740149b 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1239,7 +1239,7 @@ found: if (found) { dco_central_freq_deviation[dco_count] = div64_u64(10000 * - abs_diff((candidate_p * afe_clock), + abs_diff(candidate_p * afe_clock, dco_central_freq[dco_count]), dco_central_freq[dco_count]); -- cgit v1.3-6-gb490 From 6358298337abfabcf1e2b211c433f2093e5e9b28 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:46 +0100 Subject: drm/i915: Correctly prefix HSW/BDW HDMI clock functions Those functions were the only one in existence when they were introduced. We now know they are only valid for HSW/BDW. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 0f931740149b..8bb5291ca4da 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -625,11 +625,11 @@ intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state) (void) (&__a == &__b); \ __a > __b ? (__a - __b) : (__b - __a); }) -struct wrpll_rnp { +struct hsw_wrpll_rnp { unsigned p, n2, r2; }; -static unsigned wrpll_get_budget_for_freq(int clock) +static unsigned hsw_wrpll_get_budget_for_freq(int clock) { unsigned budget; @@ -703,9 +703,9 @@ static unsigned wrpll_get_budget_for_freq(int clock) return budget; } -static void wrpll_update_rnp(uint64_t freq2k, unsigned budget, - unsigned r2, unsigned n2, unsigned p, - struct wrpll_rnp *best) +static void hsw_wrpll_update_rnp(uint64_t freq2k, unsigned budget, + unsigned r2, unsigned n2, unsigned p, + struct hsw_wrpll_rnp *best) { uint64_t a, b, c, d, diff, diff_best; @@ -762,8 +762,7 @@ 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) +static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, int reg) { int refclk = LC_FREQ; int n, p, r; @@ -929,10 +928,10 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder, link_clock = 270000; break; case PORT_CLK_SEL_WRPLL1: - link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1); + link_clock = hsw_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); + link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2); break; case PORT_CLK_SEL_SPLL: pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK; @@ -1011,12 +1010,12 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */, { uint64_t freq2k; unsigned p, n2, r2; - struct wrpll_rnp best = { 0, 0, 0 }; + struct hsw_wrpll_rnp best = { 0, 0, 0 }; unsigned budget; freq2k = clock / 100; - budget = wrpll_get_budget_for_freq(clock); + budget = hsw_wrpll_get_budget_for_freq(clock); /* Special case handling for 540 pixel clock: bypass WR PLL entirely * and directly pass the LC PLL to it. */ @@ -1060,8 +1059,8 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */, n2++) { for (p = P_MIN; p <= P_MAX; p += P_INC) - wrpll_update_rnp(freq2k, budget, - r2, n2, p, &best); + hsw_wrpll_update_rnp(freq2k, budget, + r2, n2, p, &best); } } -- cgit v1.3-6-gb490 From 877f61d947b6666205fee4ea7a04faf187a4ede5 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:47 +0100 Subject: drm/i915/skl: Don't try to store the wrong central frequency The orignal code started by storing the actual central frequency (in Hz, using a uint64_t) in a uint32_t which codes for the register value. That can't be right. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 8bb5291ca4da..832e4e141b3d 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1121,8 +1121,6 @@ static void skl_wrpll_params_populate(struct skl_wrpll_params *params, { uint64_t dco_freq; - params->central_freq = central_freq; - switch (central_freq) { case 9600000000ULL: params->central_freq = 0; -- cgit v1.3-6-gb490 From 8d2fdc3f26d150633004a04b53a4398cc2eed343 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 27 May 2015 10:52:32 +0100 Subject: drm/i915: Only show view type for GGTT VMAs Printing it for PPGTT VMAs only adds noise since we have defined view types are only applicable for GGTT. Signed-off-by: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 88cc793c46d3..3e17210c3277 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -156,13 +156,13 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) if (obj->fence_reg != I915_FENCE_REG_NONE) seq_printf(m, " (fence: %d)", obj->fence_reg); list_for_each_entry(vma, &obj->vma_list, vma_link) { - if (!i915_is_ggtt(vma->vm)) - seq_puts(m, " (pp"); + seq_printf(m, " (%sgtt offset: %08llx, size: %08llx", + i915_is_ggtt(vma->vm) ? "g" : "pp", + vma->node.start, vma->node.size); + if (i915_is_ggtt(vma->vm)) + seq_printf(m, ", type: %u)", vma->ggtt_view.type); else - seq_puts(m, " (g"); - seq_printf(m, "gtt offset: %08llx, size: %08llx, type: %u)", - vma->node.start, vma->node.size, - vma->ggtt_view.type); + seq_puts(m, ")"); } if (obj->stolen) seq_printf(m, " (stolen: %08llx)", obj->stolen->start); -- cgit v1.3-6-gb490 From 1b1d27160dad5478f614f95ae5a87bd8382c5612 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 22 May 2015 11:22:31 +0300 Subject: drm/i915: Fix i855 get_display_clock_speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Actually read the HPLLCC register insted of assuming it's 0. Fix the HPLLCC bit definitions and all the missing ones from the 852GME spec. 852GME, 854 and 855 all seem to match the same HPLLC encoding even though only some of the values are valid is some of the platforms. v2: Rebased to the latest v3: Rebased to the latest Signed-off-by: Ville Syrjälä (v1) Signed-off-by: Mika Kahola Acked-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 11 ++++++++--- drivers/gpu/drm/i915/intel_display.c | 15 ++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6d3fead3a358..a2daf599c97d 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -50,12 +50,17 @@ /* PCI config space */ -#define HPLLCC 0xc0 /* 855 only */ -#define GC_CLOCK_CONTROL_MASK (0xf << 0) +#define HPLLCC 0xc0 /* 85x only */ +#define GC_CLOCK_CONTROL_MASK (0x7 << 0) #define GC_CLOCK_133_200 (0 << 0) #define GC_CLOCK_100_200 (1 << 0) #define GC_CLOCK_100_133 (2 << 0) -#define GC_CLOCK_166_250 (3 << 0) +#define GC_CLOCK_133_266 (3 << 0) +#define GC_CLOCK_133_200_2 (4 << 0) +#define GC_CLOCK_133_266_2 (5 << 0) +#define GC_CLOCK_166_266 (6 << 0) +#define GC_CLOCK_166_250 (7 << 0) + #define GCFGC2 0xda #define GCFGC 0xf0 /* 915+ only */ #define GC_LOW_FREQUENCY_ENABLE (1 << 7) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 067b1dee1b90..0b1d8d68ad2b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6822,20 +6822,29 @@ static int i865_get_display_clock_speed(struct drm_device *dev) return 266667; } -static int i855_get_display_clock_speed(struct drm_device *dev) +static int i85x_get_display_clock_speed(struct drm_device *dev) { u16 hpllcc = 0; + + pci_bus_read_config_word(dev->pdev->bus, + PCI_DEVFN(0, 3), HPLLCC, &hpllcc); + /* Assume that the hardware is in the high speed state. This * should be the default. */ switch (hpllcc & GC_CLOCK_CONTROL_MASK) { case GC_CLOCK_133_200: + case GC_CLOCK_133_200_2: case GC_CLOCK_100_200: return 200000; case GC_CLOCK_166_250: return 250000; case GC_CLOCK_100_133: return 133333; + case GC_CLOCK_133_266: + case GC_CLOCK_133_266_2: + case GC_CLOCK_166_266: + return 266667; } /* Shouldn't happen */ @@ -14399,8 +14408,8 @@ static void intel_init_display(struct drm_device *dev) i865_get_display_clock_speed; else if (IS_I85X(dev)) dev_priv->display.get_display_clock_speed = - i855_get_display_clock_speed; - else /* 852, 830 */ + i85x_get_display_clock_speed; + else /* 830 */ dev_priv->display.get_display_clock_speed = i830_get_display_clock_speed; -- cgit v1.3-6-gb490 From 65cd2b3fa521d1abec13dd36bf1bfc8f2469d8bc Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 22 May 2015 11:22:32 +0300 Subject: drm/i915: Fix 852GM/GMV cdclk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems 852GM/GMV uses a different HPLLCC encoding than the other 85x platforms. For 852GM/GMV cdclk is always 133MHz. Try to detect that using the PCI revision (sinc the device ID seems useless for that). I'm not at all sure this is a good idea, but according to the specs it should work. v2: Rebased to the latest v3: Rebased to the latest Signed-off-by: Ville Syrjälä (v1) Signed-off-by: Mika Kahola Acked-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0b1d8d68ad2b..73a46149564a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6826,6 +6826,14 @@ static int i85x_get_display_clock_speed(struct drm_device *dev) { u16 hpllcc = 0; + /* + * 852GM/852GMV only supports 133 MHz and the HPLLCC + * encoding is different :( + * FIXME is this the right way to detect 852GM/852GMV? + */ + if (dev->pdev->revision == 0x1) + return 133333; + pci_bus_read_config_word(dev->pdev->bus, PCI_DEVFN(0, 3), HPLLCC, &hpllcc); -- cgit v1.3-6-gb490 From 34edce2fea6960ce5855d6e09902f82822c374c5 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 22 May 2015 11:22:33 +0300 Subject: drm/i915: Add cdclk extraction for g33, g965gm and g4x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement cdclk extraction for g33, 965gm and g4x platforms. The details came from configdb. Sadly there isn't anything there for other gen3/gen4 chipsets. So far I've tested this on one ELK where it gave me a HPLL VCO of 5333 MHz and cdclk of 444 MHz which seems perfectly sane for this machine. v2: Rebased to the latest v3: Rebased to the latest Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Acked-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 + drivers/gpu/drm/i915/intel_display.c | 183 ++++++++++++++++++++++++++++++++++- 2 files changed, 185 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a2daf599c97d..00cec1f70b64 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2493,6 +2493,9 @@ enum skl_disp_power_wells { #define CLKCFG_MEM_800 (3 << 4) #define CLKCFG_MEM_MASK (7 << 4) +#define HPLLVCO (MCHBAR_MIRROR_BASE + 0xc38) +#define HPLLVCO_MOBILE (MCHBAR_MIRROR_BASE + 0xc0f) + #define TSC1 0x11001 #define TSE (1<<0) #define TR1 0x11006 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 73a46149564a..9aa3c597e5cb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6864,6 +6864,175 @@ static int i830_get_display_clock_speed(struct drm_device *dev) return 133333; } +static unsigned int intel_hpll_vco(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + static const unsigned int blb_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 4800000, + [4] = 6400000, + }; + static const unsigned int pnv_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 4800000, + [4] = 2666667, + }; + static const unsigned int cl_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 6400000, + [4] = 3333333, + [5] = 3566667, + [6] = 4266667, + }; + static const unsigned int elk_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 4800000, + }; + static const unsigned int ctg_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 6400000, + [4] = 2666667, + [5] = 4266667, + }; + const unsigned int *vco_table; + unsigned int vco; + uint8_t tmp = 0; + + /* FIXME other chipsets? */ + if (IS_GM45(dev)) + vco_table = ctg_vco; + else if (IS_G4X(dev)) + vco_table = elk_vco; + else if (IS_CRESTLINE(dev)) + vco_table = cl_vco; + else if (IS_PINEVIEW(dev)) + vco_table = pnv_vco; + else if (IS_G33(dev)) + vco_table = blb_vco; + else + return 0; + + tmp = I915_READ(IS_MOBILE(dev) ? HPLLVCO_MOBILE : HPLLVCO); + + vco = vco_table[tmp & 0x7]; + if (vco == 0) + DRM_ERROR("Bad HPLL VCO (HPLLVCO=0x%02x)\n", tmp); + else + DRM_DEBUG_KMS("HPLL VCO %u kHz\n", vco); + + return vco; +} + +static int gm45_get_display_clock_speed(struct drm_device *dev) +{ + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); + uint16_t tmp = 0; + + pci_read_config_word(dev->pdev, GCFGC, &tmp); + + cdclk_sel = (tmp >> 12) & 0x1; + + switch (vco) { + case 2666667: + case 4000000: + case 5333333: + return cdclk_sel ? 333333 : 222222; + case 3200000: + return cdclk_sel ? 320000 : 228571; + default: + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u, CFGC=0x%04x\n", vco, tmp); + return 222222; + } +} + +static int i965gm_get_display_clock_speed(struct drm_device *dev) +{ + static const uint8_t div_3200[] = { 16, 10, 8 }; + static const uint8_t div_4000[] = { 20, 12, 10 }; + static const uint8_t div_5333[] = { 24, 16, 14 }; + const uint8_t *div_table; + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); + uint16_t tmp = 0; + + pci_read_config_word(dev->pdev, GCFGC, &tmp); + + cdclk_sel = ((tmp >> 8) & 0x1f) - 1; + + if (cdclk_sel >= ARRAY_SIZE(div_3200)) + goto fail; + + switch (vco) { + case 3200000: + div_table = div_3200; + break; + case 4000000: + div_table = div_4000; + break; + case 5333333: + div_table = div_5333; + break; + default: + goto fail; + } + + return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); + + fail: + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%04x\n", vco, tmp); + return 200000; +} + +static int g33_get_display_clock_speed(struct drm_device *dev) +{ + static const uint8_t div_3200[] = { 12, 10, 8, 7, 5, 16 }; + static const uint8_t div_4000[] = { 14, 12, 10, 8, 6, 20 }; + static const uint8_t div_4800[] = { 20, 14, 12, 10, 8, 24 }; + static const uint8_t div_5333[] = { 20, 16, 12, 12, 8, 28 }; + const uint8_t *div_table; + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); + uint16_t tmp = 0; + + pci_read_config_word(dev->pdev, GCFGC, &tmp); + + cdclk_sel = (tmp >> 4) & 0x7; + + if (cdclk_sel >= ARRAY_SIZE(div_3200)) + goto fail; + + switch (vco) { + case 3200000: + div_table = div_3200; + break; + case 4000000: + div_table = div_4000; + break; + case 4800000: + div_table = div_4800; + break; + case 5333333: + div_table = div_5333; + break; + default: + goto fail; + } + + return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); + + fail: + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%08x\n", vco, tmp); + return 190476; +} + static void intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den) { @@ -14396,9 +14565,21 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.get_display_clock_speed = ilk_get_display_clock_speed; else if (IS_I945G(dev) || IS_BROADWATER(dev) || - IS_GEN6(dev) || IS_IVYBRIDGE(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev))) + IS_GEN6(dev) || IS_IVYBRIDGE(dev)) dev_priv->display.get_display_clock_speed = i945_get_display_clock_speed; + else if (IS_GM45(dev)) + dev_priv->display.get_display_clock_speed = + gm45_get_display_clock_speed; + else if (IS_CRESTLINE(dev)) + dev_priv->display.get_display_clock_speed = + i965gm_get_display_clock_speed; + else if (IS_PINEVIEW(dev)) + dev_priv->display.get_display_clock_speed = + pnv_get_display_clock_speed; + else if (IS_G33(dev) || IS_G4X(dev)) + dev_priv->display.get_display_clock_speed = + g33_get_display_clock_speed; else if (IS_I915G(dev)) dev_priv->display.get_display_clock_speed = i915_get_display_clock_speed; -- cgit v1.3-6-gb490 From 623e01e53927b05e96781532bdb40536e833e276 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 22 May 2015 11:22:34 +0300 Subject: drm/i915: Warn when cdclk for the platforms is not known MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print a warning if we fall through the .get_display_clock_speed() function pointer setup. We end up assuming a 133MHz cdclk which should mean that at least we avoid any 0 deivisions and whatnot. But this could at least help remind people that they have to provide this function for new platforms. v2: Rebased to the latest v3: Rebased to the latest Signed-off-by: Ville Syrjälä (v1) Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9aa3c597e5cb..92f6ed3d3c16 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14598,9 +14598,11 @@ static void intel_init_display(struct drm_device *dev) else if (IS_I85X(dev)) dev_priv->display.get_display_clock_speed = i85x_get_display_clock_speed; - else /* 830 */ + else { /* 830 */ + WARN(!IS_I830(dev), "Unknown platform. Assuming 133 MHz CDCLK\n"); dev_priv->display.get_display_clock_speed = i830_get_display_clock_speed; + } if (IS_GEN5(dev)) { dev_priv->display.fdi_link_train = ironlake_fdi_link_train; -- cgit v1.3-6-gb490 From c91711f93f7102c4c71896b6e9273f222bf31989 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:48 +0300 Subject: drm/i915: add for_each_hpd_pin to iterate over hotplug pins No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_irq.c | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 173c9051bf86..60aa9626f91f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -217,6 +217,9 @@ enum hpd_pin { HPD_NUM_PINS }; +#define for_each_hpd_pin(__pin) \ + for ((__pin) = (HPD_NONE + 1); (__pin) < HPD_NUM_PINS; (__pin)++) + struct i915_hotplug { struct work_struct hotplug_work; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 91cb0b6ec47b..ad8897828b0c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1441,7 +1441,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, hotplug_trigger, dig_hotplug_reg); spin_lock(&dev_priv->irq_lock); - for (i = 1; i < HPD_NUM_PINS; i++) { + for_each_hpd_pin(i) { bool long_hpd; if (!(hpd[i] & hotplug_trigger)) @@ -1477,7 +1477,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, queue_dig = true; } - for (i = 1; i < HPD_NUM_PINS; i++) { + for_each_hpd_pin(i) { if (hpd[i] & hotplug_trigger && dev_priv->hotplug.stats[i].state == HPD_DISABLED) { /* @@ -4292,7 +4292,7 @@ static void intel_hpd_irq_reenable_work(struct work_struct *work) intel_runtime_pm_get(dev_priv); spin_lock_irq(&dev_priv->irq_lock); - for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) { + for_each_hpd_pin(i) { struct drm_connector *connector; if (dev_priv->hotplug.stats[i].state != HPD_DISABLED) @@ -4450,7 +4450,7 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) struct drm_connector *connector; int i; - for (i = 1; i < HPD_NUM_PINS; i++) { + for_each_hpd_pin(i) { dev_priv->hotplug.stats[i].count = 0; dev_priv->hotplug.stats[i].state = HPD_ENABLED; } -- cgit v1.3-6-gb490 From 641a969eff3ffb01088736ef9531caffe38a6fd9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:49 +0300 Subject: drm/i915: simplify conditions for skipping the 2nd hpd loop iterations Multiple positive and negative checks for hpd[i] & hotplug_trigger gets hard to read. Simplify. This should make follow-up patches merging the two loops easier. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ad8897828b0c..536e97381cef 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1478,8 +1478,10 @@ static void intel_hpd_irq_handler(struct drm_device *dev, } for_each_hpd_pin(i) { - if (hpd[i] & hotplug_trigger && - dev_priv->hotplug.stats[i].state == HPD_DISABLED) { + if (!(hpd[i] & hotplug_trigger)) + continue; + + if (dev_priv->hotplug.stats[i].state == HPD_DISABLED) { /* * On GMCH platforms the interrupt mask bits only * prevent irq generation, not the setting of the @@ -1493,8 +1495,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, continue; } - if (!(hpd[i] & hotplug_trigger) || - dev_priv->hotplug.stats[i].state != HPD_ENABLED) + if (dev_priv->hotplug.stats[i].state != HPD_ENABLED) continue; if (!(dig_port_mask & hpd[i])) { -- cgit v1.3-6-gb490 From ab68d5bb0b49727e4049b018185f82764cf44736 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:50 +0300 Subject: drm/i915: put back the indent in intel_hpd_irq_handler In an unfortunate back and forth stepping, retract the earlier change to reduce indent. This is to make merging the two loops easier. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 51 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 536e97381cef..4840b21c1869 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1442,39 +1442,38 @@ static void intel_hpd_irq_handler(struct drm_device *dev, spin_lock(&dev_priv->irq_lock); for_each_hpd_pin(i) { - bool long_hpd; - if (!(hpd[i] & hotplug_trigger)) continue; port = get_port_from_pin(i); - if (!port || !dev_priv->hotplug.irq_port[port]) - continue; + if (port && dev_priv->hotplug.irq_port[port]) { + bool long_hpd; - if (!HAS_GMCH_DISPLAY(dev_priv)) { - dig_shift = pch_port_to_hotplug_shift(port); - long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } else { - dig_shift = i915_port_to_hotplug_shift(port); - long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } + if (!HAS_GMCH_DISPLAY(dev_priv)) { + dig_shift = pch_port_to_hotplug_shift(port); + long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; + } else { + dig_shift = i915_port_to_hotplug_shift(port); + long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; + } - DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), - long_hpd ? "long" : "short"); - /* - * For long HPD pulses we want to have the digital queue happen, - * but we still want HPD storm detection to function. - */ - if (long_hpd) { - dev_priv->hotplug.long_port_mask |= (1 << port); - dig_port_mask |= hpd[i]; - } else { - /* for short HPD just trigger the digital queue */ - dev_priv->hotplug.short_port_mask |= (1 << port); - hotplug_trigger &= ~hpd[i]; - } + DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), + long_hpd ? "long" : "short"); + /* + * For long HPD pulses we want to have the digital queue happen, + * but we still want HPD storm detection to function. + */ + if (long_hpd) { + dev_priv->hotplug.long_port_mask |= (1 << port); + dig_port_mask |= hpd[i]; + } else { + /* for short HPD just trigger the digital queue */ + dev_priv->hotplug.short_port_mask |= (1 << port); + hotplug_trigger &= ~hpd[i]; + } - queue_dig = true; + queue_dig = true; + } } for_each_hpd_pin(i) { -- cgit v1.3-6-gb490 From 9ace043310ba4875e08863b9f31f429d853685f2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:51 +0300 Subject: drm/i915: merge the two hpd loops in intel_hpd_irq_handler to one Nothing in the two consecutive loops over hpd pins depends on state in a larger context than the single hpd pin. If we skip the rest of the loop on short hpd pulses, we can merge the two loops into one. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4840b21c1869..b53b91744a17 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1463,22 +1463,17 @@ static void intel_hpd_irq_handler(struct drm_device *dev, * For long HPD pulses we want to have the digital queue happen, * but we still want HPD storm detection to function. */ + queue_dig = true; if (long_hpd) { dev_priv->hotplug.long_port_mask |= (1 << port); + /* FIXME: this can be simplified. */ dig_port_mask |= hpd[i]; } else { /* for short HPD just trigger the digital queue */ dev_priv->hotplug.short_port_mask |= (1 << port); - hotplug_trigger &= ~hpd[i]; + continue; } - - queue_dig = true; } - } - - for_each_hpd_pin(i) { - if (!(hpd[i] & hotplug_trigger)) - continue; if (dev_priv->hotplug.stats[i].state == HPD_DISABLED) { /* -- cgit v1.3-6-gb490 From c8727233aa80cdf54e3460ac5ebc93c05b09ff5d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:52 +0300 Subject: drm/i915: simplify condition for digital port As the hpd loops have been merged together, we don't have to maintain state for all hpd triggers. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b53b91744a17..6fffbfd3121a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1432,7 +1432,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, bool storm_detected = false; bool queue_dig = false, queue_hp = false; u32 dig_shift; - u32 dig_port_mask = 0; + bool is_dig_port; if (!hotplug_trigger) return; @@ -1446,7 +1446,9 @@ static void intel_hpd_irq_handler(struct drm_device *dev, continue; port = get_port_from_pin(i); - if (port && dev_priv->hotplug.irq_port[port]) { + is_dig_port = port && dev_priv->hotplug.irq_port[port]; + + if (is_dig_port) { bool long_hpd; if (!HAS_GMCH_DISPLAY(dev_priv)) { @@ -1466,8 +1468,6 @@ static void intel_hpd_irq_handler(struct drm_device *dev, queue_dig = true; if (long_hpd) { dev_priv->hotplug.long_port_mask |= (1 << port); - /* FIXME: this can be simplified. */ - dig_port_mask |= hpd[i]; } else { /* for short HPD just trigger the digital queue */ dev_priv->hotplug.short_port_mask |= (1 << port); @@ -1492,7 +1492,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, if (dev_priv->hotplug.stats[i].state != HPD_ENABLED) continue; - if (!(dig_port_mask & hpd[i])) { + if (!is_dig_port) { dev_priv->hotplug.event_bits |= (1 << i); queue_hp = true; } -- cgit v1.3-6-gb490 From 676574dffa4d67ff4e8b2ec796eb9f41aad925d8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:53 +0300 Subject: drm/i915: abstract away platform specific parts from hpd handling Split intel_hpd_irq_handler into platforms specific and platform agnostic parts. The platform specific parts decode the registers into information about which hpd pins triggered, and if they were long pulses. The platform agnostic parts do further processing, such as interrupt storm mitigation and scheduling bottom halves. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 147 +++++++++++++++++++++++++++------------- 1 file changed, 101 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6fffbfd3121a..d401c863aeee 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1375,35 +1375,31 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, #define HPD_STORM_DETECT_PERIOD 1000 #define HPD_STORM_THRESHOLD 5 -static int pch_port_to_hotplug_shift(enum port port) +static bool pch_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { - case PORT_A: - case PORT_E: - default: - return -1; case PORT_B: - return 0; + return val & PORTB_HOTPLUG_LONG_DETECT; case PORT_C: - return 8; + return val & PORTC_HOTPLUG_LONG_DETECT; case PORT_D: - return 16; + return val & PORTD_HOTPLUG_LONG_DETECT; + default: + return false; } } -static int i915_port_to_hotplug_shift(enum port port) +static bool i9xx_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { - case PORT_A: - case PORT_E: - default: - return -1; case PORT_B: - return 17; + return val & PORTB_HOTPLUG_INT_LONG_PULSE; case PORT_C: - return 19; + return val & PORTC_HOTPLUG_INT_LONG_PULSE; case PORT_D: - return 21; + return val & PORTD_HOTPLUG_INT_LONG_PULSE; + default: + return false; } } @@ -1421,43 +1417,96 @@ static enum port get_port_from_pin(enum hpd_pin pin) } } +/* Get a bit mask of pins that have triggered, and which ones may be long. */ +static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, + u32 hotplug_trigger, u32 dig_hotplug_reg, const u32 hpd[HPD_NUM_PINS]) +{ + int i; + + *pin_mask = 0; + *long_mask = 0; + + if (!hotplug_trigger) + return; + + for_each_hpd_pin(i) { + if (hpd[i] & hotplug_trigger) { + *pin_mask |= BIT(i); + + if (pch_port_hotplug_long_detect(get_port_from_pin(i), dig_hotplug_reg)) + *long_mask |= BIT(i); + } + } + + DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x\n", + hotplug_trigger, dig_hotplug_reg, *pin_mask); + +} + +/* Get a bit mask of pins that have triggered, and which ones may be long. */ +static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, + u32 hotplug_trigger, const u32 hpd[HPD_NUM_PINS]) +{ + int i; + + *pin_mask = 0; + *long_mask = 0; + + if (!hotplug_trigger) + return; + + for_each_hpd_pin(i) { + if (hpd[i] & hotplug_trigger) { + *pin_mask |= BIT(i); + + if (i9xx_port_hotplug_long_detect(get_port_from_pin(i), hotplug_trigger)) + *long_mask |= BIT(i); + } + } + + DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, pins 0x%08x\n", + hotplug_trigger, *pin_mask); +} + +/** + * intel_hpd_irq_handler - main hotplug irq handler + * @dev: drm device + * @pin_mask: a mask of hpd pins that have triggered the irq + * @long_mask: a mask of hpd pins that may be long hpd pulses + * + * This is the main hotplug irq handler for all platforms. The platform specific + * irq handlers call the platform specific hotplug irq handlers, which read and + * decode the appropriate registers into bitmasks about hpd pins that have + * triggered (@pin_mask), and which of those pins may be long pulses + * (@long_mask). The @long_mask is ignored if the port corresponding to the pin + * is not a digital port. + * + * Here, we do hotplug irq storm detection and mitigation, and pass further + * processing to appropriate bottom halves. + */ static void intel_hpd_irq_handler(struct drm_device *dev, - u32 hotplug_trigger, - u32 dig_hotplug_reg, - const u32 hpd[HPD_NUM_PINS]) + u32 pin_mask, u32 long_mask) { struct drm_i915_private *dev_priv = dev->dev_private; int i; enum port port; bool storm_detected = false; bool queue_dig = false, queue_hp = false; - u32 dig_shift; bool is_dig_port; - if (!hotplug_trigger) + if (!pin_mask) return; - DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x\n", - hotplug_trigger, dig_hotplug_reg); - spin_lock(&dev_priv->irq_lock); for_each_hpd_pin(i) { - if (!(hpd[i] & hotplug_trigger)) + if (!(BIT(i) & pin_mask)) continue; port = get_port_from_pin(i); is_dig_port = port && dev_priv->hotplug.irq_port[port]; if (is_dig_port) { - bool long_hpd; - - if (!HAS_GMCH_DISPLAY(dev_priv)) { - dig_shift = pch_port_to_hotplug_shift(port); - long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } else { - dig_shift = i915_port_to_hotplug_shift(port); - long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } + bool long_hpd = long_mask & BIT(i); DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), long_hpd ? "long" : "short"); @@ -1483,9 +1532,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, * interrupts on saner platforms. */ WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev), - "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n", - hotplug_trigger, i, hpd[i]); - + "Received HPD interrupt on pin %d although disabled\n", i); continue; } @@ -1493,7 +1540,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, continue; if (!is_dig_port) { - dev_priv->hotplug.event_bits |= (1 << i); + dev_priv->hotplug.event_bits |= BIT(i); queue_hp = true; } @@ -1505,7 +1552,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", i); } else if (dev_priv->hotplug.stats[i].count > HPD_STORM_THRESHOLD) { dev_priv->hotplug.stats[i].state = HPD_MARK_DISABLED; - dev_priv->hotplug.event_bits &= ~(1 << i); + dev_priv->hotplug.event_bits &= ~BIT(i); DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); storm_detected = true; } else { @@ -1753,6 +1800,7 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + u32 pin_mask, long_mask; if (!hotplug_status) return; @@ -1767,14 +1815,16 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; - intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_g4x); + i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_g4x); + intel_hpd_irq_handler(dev, pin_mask, long_mask); if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) dp_aux_irq_handler(dev); } else { u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; - intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_i915); + i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_i915); + intel_hpd_irq_handler(dev, pin_mask, long_mask); } } @@ -1874,11 +1924,13 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; u32 dig_hotplug_reg; + u32 pin_mask, long_mask; dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); - intel_hpd_irq_handler(dev, hotplug_trigger, dig_hotplug_reg, hpd_ibx); + pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd_ibx); + intel_hpd_irq_handler(dev, pin_mask, long_mask); if (pch_iir & SDE_AUDIO_POWER_MASK) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> @@ -1971,11 +2023,13 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; u32 dig_hotplug_reg; + u32 pin_mask, long_mask; dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); - intel_hpd_irq_handler(dev, hotplug_trigger, dig_hotplug_reg, hpd_cpt); + pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd_cpt); + intel_hpd_irq_handler(dev, pin_mask, long_mask); if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> @@ -2174,8 +2228,8 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t hp_control; - uint32_t hp_trigger; + u32 hp_control, hp_trigger; + u32 pin_mask, long_mask; /* Get the status */ hp_trigger = iir_status & BXT_DE_PORT_HOTPLUG_MASK; @@ -2191,7 +2245,8 @@ static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status) hp_control & BXT_HOTPLUG_CTL_MASK); /* Check for HPD storm and schedule bottom half */ - intel_hpd_irq_handler(dev, hp_trigger, hp_control, hpd_bxt); + pch_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, hpd_bxt); + intel_hpd_irq_handler(dev, pin_mask, long_mask); /* * FIXME: Save the hot plug status for bottom half before -- cgit v1.3-6-gb490 From 475c2e3b3cfba9283793d56742dc2cae2712574b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:54 +0300 Subject: drm/i915/bxt: clear hpd status sticky bits earlier The hotplug status is cached in hp_control, and will be passed on to bottom halves through intel_hpd_irq_handler(), so we can clear the sticky bits earlier. While at it, drop the redundant logging of the hotplug status, which will also be logged by pch_get_hpd_pins(). Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d401c863aeee..e4260b0924f1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2241,21 +2241,11 @@ static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status) return; } - DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", - hp_control & BXT_HOTPLUG_CTL_MASK); + /* Clear sticky bits in hpd status */ + I915_WRITE(BXT_HOTPLUG_CTL, hp_control); - /* Check for HPD storm and schedule bottom half */ pch_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, hpd_bxt); intel_hpd_irq_handler(dev, pin_mask, long_mask); - - /* - * FIXME: Save the hot plug status for bottom half before - * clearing the sticky status bits, else the status will be - * lost. - */ - - /* Clear sticky bits in hpd status */ - I915_WRITE(BXT_HOTPLUG_CTL, hp_control); } static irqreturn_t gen8_irq_handler(int irq, void *arg) -- cgit v1.3-6-gb490 From bd4b4827acdc00bf9e71f939d160102021d10d4f Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Fri, 29 May 2015 14:28:09 +0300 Subject: drm/i915: Silence compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Silence the following -Wmaybe-uninitialized warnings and make the code more clear. drivers/gpu/drm/i915/intel_display.c: In function ‘__intel_set_mode’: drivers/gpu/drm/i915/intel_display.c:11844:14: warning: ‘crtc_state’ may be used uninitialized in this function [-Wmaybe-uninitialized] return state->mode_changed || state->active_changed; ^ drivers/gpu/drm/i915/intel_display.c:11854:25: note: ‘crtc_state’ was declared here struct drm_crtc_state *crtc_state; ^ drivers/gpu/drm/i915/intel_display.c:11868:6: warning: ‘crtc’ may be used uninitialized in this function [-Wmaybe-uninitialized] if (crtc != intel_encoder->base.crtc) ^ drivers/gpu/drm/i915/intel_display.c:11853:19: note: ‘crtc’ was declared here struct drm_crtc *crtc; Reported-by: Chris Wilson Suggested-by: Chris Wilson Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 42 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 92f6ed3d3c16..475779ae4bec 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12045,15 +12045,15 @@ intel_modeset_update_state(struct drm_atomic_state *state) if (!intel_encoder->base.crtc) continue; - for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc == intel_encoder->base.crtc) - break; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (crtc != intel_encoder->base.crtc) + continue; - if (crtc != intel_encoder->base.crtc) - continue; + if (crtc_state->enable && needs_modeset(crtc_state)) + intel_encoder->connectors_active = false; - if (crtc_state->enable && needs_modeset(crtc_state)) - intel_encoder->connectors_active = false; + break; + } } drm_atomic_helper_swap_state(state->dev, state); @@ -12068,24 +12068,24 @@ intel_modeset_update_state(struct drm_atomic_state *state) if (!connector->encoder || !connector->encoder->crtc) continue; - for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc == connector->encoder->crtc) - break; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (crtc != connector->encoder->crtc) + continue; - if (crtc != connector->encoder->crtc) - continue; + if (crtc->state->enable && needs_modeset(crtc->state)) { + struct drm_property *dpms_property = + dev->mode_config.dpms_property; - if (crtc->state->enable && needs_modeset(crtc->state)) { - struct drm_property *dpms_property = - dev->mode_config.dpms_property; + connector->dpms = DRM_MODE_DPMS_ON; + drm_object_property_set_value(&connector->base, + dpms_property, + DRM_MODE_DPMS_ON); - connector->dpms = DRM_MODE_DPMS_ON; - drm_object_property_set_value(&connector->base, - dpms_property, - DRM_MODE_DPMS_ON); + intel_encoder = to_intel_encoder(connector->encoder); + intel_encoder->connectors_active = true; + } - intel_encoder = to_intel_encoder(connector->encoder); - intel_encoder->connectors_active = true; + break; } } -- cgit v1.3-6-gb490 From a2ee48d60eed9cfb6447a4233370aee4ea88108b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 29 May 2015 16:14:37 +0300 Subject: drm/i915: abstract hpd irq storm detection Simplify intel_hpd_irq_handler() by extracting HPD irq storm detection to a separate function. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 53 +++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e4260b0924f1..eb52a039d628 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1375,6 +1375,45 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, #define HPD_STORM_DETECT_PERIOD 1000 #define HPD_STORM_THRESHOLD 5 +/** + * intel_hpd_irq_storm - gather stats and detect HPD irq storm on a pin + * @dev_priv: private driver data pointer + * @pin: the pin to gather stats on + * + * Gather stats about HPD irqs from the specified @pin, and detect irq + * storms. Only the pin specific stats and state are changed, the caller is + * responsible for further action. + * + * @HPD_STORM_THRESHOLD irqs are allowed within @HPD_STORM_DETECT_PERIOD ms, + * otherwise it's considered an irq storm, and the irq state is set to + * @HPD_MARK_DISABLED. + * + * Return true if an irq storm was detected on @pin. + */ +static bool intel_hpd_irq_storm(struct drm_i915_private *dev_priv, + enum hpd_pin pin) +{ + unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies; + unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); + bool storm = false; + + if (!time_in_range(jiffies, start, end)) { + dev_priv->hotplug.stats[pin].last_jiffies = jiffies; + dev_priv->hotplug.stats[pin].count = 0; + DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", pin); + } else if (dev_priv->hotplug.stats[pin].count > HPD_STORM_THRESHOLD) { + dev_priv->hotplug.stats[pin].state = HPD_MARK_DISABLED; + DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin); + storm = true; + } else { + dev_priv->hotplug.stats[pin].count++; + DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin, + dev_priv->hotplug.stats[pin].count); + } + + return storm; +} + static bool pch_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { @@ -1544,21 +1583,9 @@ static void intel_hpd_irq_handler(struct drm_device *dev, queue_hp = true; } - if (!time_in_range(jiffies, dev_priv->hotplug.stats[i].last_jiffies, - dev_priv->hotplug.stats[i].last_jiffies - + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) { - dev_priv->hotplug.stats[i].last_jiffies = jiffies; - dev_priv->hotplug.stats[i].count = 0; - DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", i); - } else if (dev_priv->hotplug.stats[i].count > HPD_STORM_THRESHOLD) { - dev_priv->hotplug.stats[i].state = HPD_MARK_DISABLED; + if (intel_hpd_irq_storm(dev_priv, i)) { dev_priv->hotplug.event_bits &= ~BIT(i); - DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); storm_detected = true; - } else { - dev_priv->hotplug.stats[i].count++; - DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", i, - dev_priv->hotplug.stats[i].count); } } -- cgit v1.3-6-gb490 From f3b19aa5cab65f7e73613aa37f6851ce56b794d1 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 27 Feb 2015 17:54:14 +0200 Subject: ARM: OMAP2+: clock: export driver API to setup/get clock features As most of the clock driver support code is going to be moved under drivers/clk/ti, an API for setting / getting the SoC specific clock features is needed. This patch provides this API and changes the existing code to use it. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/clkt_dpll.c | 14 +++++++------- arch/arm/mach-omap2/clock.c | 36 +++++++++++++++++------------------- arch/arm/mach-omap2/clock.h | 18 ------------------ arch/arm/mach-omap2/clock3xxx.c | 4 ++-- arch/arm/mach-omap2/dpll3xxx.c | 4 ++-- drivers/clk/ti/clk.c | 25 +++++++++++++++++++++++++ include/linux/clk/ti.h | 16 ++++++++++++++++ 7 files changed, 69 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c index f251a14cbf16..82f0600c35f4 100644 --- a/arch/arm/mach-omap2/clkt_dpll.c +++ b/arch/arm/mach-omap2/clkt_dpll.c @@ -80,8 +80,8 @@ static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n) fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN; fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX; } else { - fint_min = ti_clk_features.fint_min; - fint_max = ti_clk_features.fint_max; + fint_min = ti_clk_get_features()->fint_min; + fint_max = ti_clk_get_features()->fint_max; } if (!fint_min || !fint_max) { @@ -89,18 +89,18 @@ static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n) return DPLL_FINT_INVALID; } - if (fint < ti_clk_features.fint_min) { + if (fint < ti_clk_get_features()->fint_min) { pr_debug("rejecting n=%d due to Fint failure, lowering max_divider\n", n); dd->max_divider = n; ret = DPLL_FINT_UNDERFLOW; - } else if (fint > ti_clk_features.fint_max) { + } else if (fint > ti_clk_get_features()->fint_max) { pr_debug("rejecting n=%d due to Fint failure, boosting min_divider\n", n); dd->min_divider = n; ret = DPLL_FINT_INVALID; - } else if (fint > ti_clk_features.fint_band1_max && - fint < ti_clk_features.fint_band2_min) { + } else if (fint > ti_clk_get_features()->fint_band1_max && + fint < ti_clk_get_features()->fint_band2_min) { pr_debug("rejecting n=%d due to Fint failure\n", n); ret = DPLL_FINT_INVALID; } @@ -183,7 +183,7 @@ static int _omap2_dpll_is_in_bypass(u32 v) { u8 mask, val; - mask = ti_clk_features.dpll_bypass_vals; + mask = ti_clk_get_features()->dpll_bypass_vals; /* * Each set bit in the mask corresponds to a bypass value equal diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index a699d7169307..cbc65b3a3b62 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -48,11 +48,6 @@ u16 cpu_mask; -/* - * Clock features setup. Used instead of CPU type checks. - */ -struct ti_clk_features ti_clk_features; - /* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */ #define OMAP3430_DPLL_FINT_BAND1_MIN 750000 #define OMAP3430_DPLL_FINT_BAND1_MAX 2100000 @@ -367,7 +362,7 @@ void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, * 34xx reverses this, just to keep us on our toes * AM35xx uses both, depending on the module. */ - *idlest_val = ti_clk_features.cm_idlest_val; + *idlest_val = ti_clk_get_features()->cm_idlest_val; } /** @@ -801,29 +796,30 @@ void __init omap2_clk_print_new_rates(const char *hfclkin_ck_name, */ void __init ti_clk_init_features(void) { + struct ti_clk_features features = { 0 }; /* Fint setup for DPLLs */ if (cpu_is_omap3430()) { - ti_clk_features.fint_min = OMAP3430_DPLL_FINT_BAND1_MIN; - ti_clk_features.fint_max = OMAP3430_DPLL_FINT_BAND2_MAX; - ti_clk_features.fint_band1_max = OMAP3430_DPLL_FINT_BAND1_MAX; - ti_clk_features.fint_band2_min = OMAP3430_DPLL_FINT_BAND2_MIN; + features.fint_min = OMAP3430_DPLL_FINT_BAND1_MIN; + features.fint_max = OMAP3430_DPLL_FINT_BAND2_MAX; + features.fint_band1_max = OMAP3430_DPLL_FINT_BAND1_MAX; + features.fint_band2_min = OMAP3430_DPLL_FINT_BAND2_MIN; } else { - ti_clk_features.fint_min = OMAP3PLUS_DPLL_FINT_MIN; - ti_clk_features.fint_max = OMAP3PLUS_DPLL_FINT_MAX; + features.fint_min = OMAP3PLUS_DPLL_FINT_MIN; + features.fint_max = OMAP3PLUS_DPLL_FINT_MAX; } /* Bypass value setup for DPLLs */ if (cpu_is_omap24xx()) { - ti_clk_features.dpll_bypass_vals |= + features.dpll_bypass_vals |= (1 << OMAP2XXX_EN_DPLL_LPBYPASS) | (1 << OMAP2XXX_EN_DPLL_FRBYPASS); } else if (cpu_is_omap34xx()) { - ti_clk_features.dpll_bypass_vals |= + features.dpll_bypass_vals |= (1 << OMAP3XXX_EN_DPLL_LPBYPASS) | (1 << OMAP3XXX_EN_DPLL_FRBYPASS); } else if (soc_is_am33xx() || cpu_is_omap44xx() || soc_is_am43xx() || soc_is_omap54xx() || soc_is_dra7xx()) { - ti_clk_features.dpll_bypass_vals |= + features.dpll_bypass_vals |= (1 << OMAP4XXX_EN_DPLL_LPBYPASS) | (1 << OMAP4XXX_EN_DPLL_FRBYPASS) | (1 << OMAP4XXX_EN_DPLL_MNBYPASS); @@ -831,7 +827,7 @@ void __init ti_clk_init_features(void) /* Jitter correction only available on OMAP343X */ if (cpu_is_omap343x()) - ti_clk_features.flags |= TI_CLK_DPLL_HAS_FREQSEL; + features.flags |= TI_CLK_DPLL_HAS_FREQSEL; /* Idlest value for interface clocks. * 24xx uses 0 to indicate not ready, and 1 to indicate ready. @@ -839,11 +835,13 @@ void __init ti_clk_init_features(void) * AM35xx uses both, depending on the module. */ if (cpu_is_omap24xx()) - ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL; + features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL; else if (cpu_is_omap34xx()) - ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL; + features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL; /* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */ if (omap_rev() == OMAP3430_REV_ES1_0) - ti_clk_features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM; + features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM; + + ti_clk_setup_features(&features); } diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 652ed0ab86ec..ac21856d245d 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -225,24 +225,6 @@ void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg); extern u16 cpu_mask; -/* - * Clock features setup. Used instead of CPU type checks. - */ -struct ti_clk_features { - u32 flags; - long fint_min; - long fint_max; - long fint_band1_max; - long fint_band2_min; - u8 dpll_bypass_vals; - u8 cm_idlest_val; -}; - -#define TI_CLK_DPLL_HAS_FREQSEL (1 << 0) -#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1) - -extern struct ti_clk_features ti_clk_features; - extern const struct clkops clkops_omap2_dflt_wait; extern const struct clkops clkops_omap2_dflt; diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c index a9e86db5daf9..8bede6aec44f 100644 --- a/arch/arm/mach-omap2/clock3xxx.c +++ b/arch/arm/mach-omap2/clock3xxx.c @@ -58,7 +58,7 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, * on 3430ES1 prevents us from changing DPLL multipliers or dividers * on DPLL4. */ - if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) { + if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) { pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); return -EINVAL; } @@ -81,7 +81,7 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate, u8 index) { - if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) { + if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) { pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); return -EINVAL; } diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index 44e57ec225d4..9a80f593ed15 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -307,7 +307,7 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) * Set jitter correction. Jitter correction applicable for OMAP343X * only since freqsel field is no longer present on other devices. */ - if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { + if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) { v = omap2_clk_readl(clk, dd->control_reg); v &= ~dd->freqsel_mask; v |= freqsel << __ffs(dd->freqsel_mask); @@ -559,7 +559,7 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; /* Freqsel is available only on OMAP343X devices */ - if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) { + if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) { freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); WARN_ON(!freqsel); } diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 0ebe5c51062b..e65ae4acff9c 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -30,6 +30,8 @@ struct ti_clk_ll_ops *ti_clk_ll_ops; static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; +struct ti_clk_features ti_clk_features; + /** * ti_dt_clocks_register - register DT alias clocks during boot * @oclks: list of clocks to register @@ -311,3 +313,26 @@ int __init ti_clk_register_legacy_clks(struct ti_clk_alias *clks) return 0; } #endif + +/** + * ti_clk_setup_features - setup clock features flags + * @features: features definition to use + * + * Initializes the clock driver features flags based on platform + * provided data. No return value. + */ +void __init ti_clk_setup_features(struct ti_clk_features *features) +{ + memcpy(&ti_clk_features, features, sizeof(*features)); +} + +/** + * ti_clk_get_features - get clock driver features flags + * + * Get TI clock driver features description. Returns a pointer + * to the current feature setup. + */ +const struct ti_clk_features *ti_clk_get_features(void) +{ + return &ti_clk_features; +} diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 79b76e13d904..1a7f86a68f62 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -338,6 +338,22 @@ int am43xx_dt_clk_init(void); int omap2420_dt_clk_init(void); int omap2430_dt_clk_init(void); +struct ti_clk_features { + u32 flags; + long fint_min; + long fint_max; + long fint_band1_max; + long fint_band2_min; + u8 dpll_bypass_vals; + u8 cm_idlest_val; +}; + +#define TI_CLK_DPLL_HAS_FREQSEL BIT(0) +#define TI_CLK_DPLL4_DENY_REPROGRAM BIT(1) + +void ti_clk_setup_features(struct ti_clk_features *features); +const struct ti_clk_features *ti_clk_get_features(void); + #ifdef CONFIG_OF void of_ti_clk_allow_autoidle_all(void); void of_ti_clk_deny_autoidle_all(void); -- cgit v1.3-6-gb490 From b138b0283d35bed0cd3353d7e39add8ac493eb37 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 2 Mar 2015 09:57:28 +0200 Subject: clk: ti: move generic OMAP DPLL implementation under drivers/clk With the legacy clock data now gone, we can start moving OMAP clock type implementations under clock driver. Start this with moving the generic OMAP DPLL clock type under TI clock driver. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/clkt_dpll.c | 370 ---------------------------------------- drivers/clk/ti/Makefile | 3 +- drivers/clk/ti/clkt_dpll.c | 369 +++++++++++++++++++++++++++++++++++++++ drivers/clk/ti/clock.h | 2 + include/linux/clk/ti.h | 1 - 6 files changed, 374 insertions(+), 373 deletions(-) delete mode 100644 arch/arm/mach-omap2/clkt_dpll.c create mode 100644 drivers/clk/ti/clkt_dpll.c (limited to 'drivers') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index ec002bd4af77..fcb5d47f88ca 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -13,7 +13,7 @@ obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o timer.o pm.o \ hwmod-common = omap_hwmod.o omap_hwmod_reset.o \ omap_hwmod_common_data.o clock-common = clock.o clock_common_data.o \ - clkt_dpll.o clkt_clksel.o + clkt_clksel.o secure-common = omap-smc.o omap-secure.o obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common) diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c deleted file mode 100644 index 82f0600c35f4..000000000000 --- a/arch/arm/mach-omap2/clkt_dpll.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * OMAP2/3/4 DPLL clock functions - * - * Copyright (C) 2005-2008 Texas Instruments, Inc. - * Copyright (C) 2004-2010 Nokia Corporation - * - * Contacts: - * Richard Woodruff - * Paul Walmsley - * - * 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. - */ -#undef DEBUG - -#include -#include -#include -#include - -#include - -#include "clock.h" - -/* DPLL rate rounding: minimum DPLL multiplier, divider values */ -#define DPLL_MIN_MULTIPLIER 2 -#define DPLL_MIN_DIVIDER 1 - -/* Possible error results from _dpll_test_mult */ -#define DPLL_MULT_UNDERFLOW -1 - -/* - * Scale factor to mitigate roundoff errors in DPLL rate rounding. - * The higher the scale factor, the greater the risk of arithmetic overflow, - * but the closer the rounded rate to the target rate. DPLL_SCALE_FACTOR - * must be a power of DPLL_SCALE_BASE. - */ -#define DPLL_SCALE_FACTOR 64 -#define DPLL_SCALE_BASE 2 -#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \ - (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE)) - -/* - * DPLL valid Fint frequency range for OMAP36xx and OMAP4xxx. - * From device data manual section 4.3 "DPLL and DLL Specifications". - */ -#define OMAP3PLUS_DPLL_FINT_JTYPE_MIN 500000 -#define OMAP3PLUS_DPLL_FINT_JTYPE_MAX 2500000 - -/* _dpll_test_fint() return codes */ -#define DPLL_FINT_UNDERFLOW -1 -#define DPLL_FINT_INVALID -2 - -/* Private functions */ - -/* - * _dpll_test_fint - test whether an Fint value is valid for the DPLL - * @clk: DPLL struct clk to test - * @n: divider value (N) to test - * - * Tests whether a particular divider @n will result in a valid DPLL - * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter - * Correction". Returns 0 if OK, -1 if the enclosing loop can terminate - * (assuming that it is counting N upwards), or -2 if the enclosing loop - * should skip to the next iteration (again assuming N is increasing). - */ -static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n) -{ - struct dpll_data *dd; - long fint, fint_min, fint_max; - int ret = 0; - - dd = clk->dpll_data; - - /* DPLL divider must result in a valid jitter correction val */ - fint = __clk_get_rate(__clk_get_parent(clk->hw.clk)) / n; - - if (dd->flags & DPLL_J_TYPE) { - fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN; - fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX; - } else { - fint_min = ti_clk_get_features()->fint_min; - fint_max = ti_clk_get_features()->fint_max; - } - - if (!fint_min || !fint_max) { - WARN(1, "No fint limits available!\n"); - return DPLL_FINT_INVALID; - } - - if (fint < ti_clk_get_features()->fint_min) { - pr_debug("rejecting n=%d due to Fint failure, lowering max_divider\n", - n); - dd->max_divider = n; - ret = DPLL_FINT_UNDERFLOW; - } else if (fint > ti_clk_get_features()->fint_max) { - pr_debug("rejecting n=%d due to Fint failure, boosting min_divider\n", - n); - dd->min_divider = n; - ret = DPLL_FINT_INVALID; - } else if (fint > ti_clk_get_features()->fint_band1_max && - fint < ti_clk_get_features()->fint_band2_min) { - pr_debug("rejecting n=%d due to Fint failure\n", n); - ret = DPLL_FINT_INVALID; - } - - return ret; -} - -static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, - unsigned int m, unsigned int n) -{ - unsigned long long num; - - num = (unsigned long long)parent_rate * m; - do_div(num, n); - return num; -} - -/* - * _dpll_test_mult - test a DPLL multiplier value - * @m: pointer to the DPLL m (multiplier) value under test - * @n: current DPLL n (divider) value under test - * @new_rate: pointer to storage for the resulting rounded rate - * @target_rate: the desired DPLL rate - * @parent_rate: the DPLL's parent clock rate - * - * This code tests a DPLL multiplier value, ensuring that the - * resulting rate will not be higher than the target_rate, and that - * the multiplier value itself is valid for the DPLL. Initially, the - * integer pointed to by the m argument should be prescaled by - * multiplying by DPLL_SCALE_FACTOR. The code will replace this with - * a non-scaled m upon return. This non-scaled m will result in a - * new_rate as close as possible to target_rate (but not greater than - * target_rate) given the current (parent_rate, n, prescaled m) - * triple. Returns DPLL_MULT_UNDERFLOW in the event that the - * non-scaled m attempted to underflow, which can allow the calling - * function to bail out early; or 0 upon success. - */ -static int _dpll_test_mult(int *m, int n, unsigned long *new_rate, - unsigned long target_rate, - unsigned long parent_rate) -{ - int r = 0, carry = 0; - - /* Unscale m and round if necessary */ - if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL) - carry = 1; - *m = (*m / DPLL_SCALE_FACTOR) + carry; - - /* - * The new rate must be <= the target rate to avoid programming - * a rate that is impossible for the hardware to handle - */ - *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); - if (*new_rate > target_rate) { - (*m)--; - *new_rate = 0; - } - - /* Guard against m underflow */ - if (*m < DPLL_MIN_MULTIPLIER) { - *m = DPLL_MIN_MULTIPLIER; - *new_rate = 0; - r = DPLL_MULT_UNDERFLOW; - } - - if (*new_rate == 0) - *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); - - return r; -} - -/** - * _omap2_dpll_is_in_bypass - check if DPLL is in bypass mode or not - * @v: bitfield value of the DPLL enable - * - * Checks given DPLL enable bitfield to see whether the DPLL is in bypass - * mode or not. Returns 1 if the DPLL is in bypass, 0 otherwise. - */ -static int _omap2_dpll_is_in_bypass(u32 v) -{ - u8 mask, val; - - mask = ti_clk_get_features()->dpll_bypass_vals; - - /* - * Each set bit in the mask corresponds to a bypass value equal - * to the bitshift. Go through each set-bit in the mask and - * compare against the given register value. - */ - while (mask) { - val = __ffs(mask); - mask ^= (1 << val); - if (v == val) - return 1; - } - - return 0; -} - -/* Public functions */ -u8 omap2_init_dpll_parent(struct clk_hw *hw) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - u32 v; - struct dpll_data *dd; - - dd = clk->dpll_data; - if (!dd) - return -EINVAL; - - v = omap2_clk_readl(clk, dd->control_reg); - v &= dd->enable_mask; - v >>= __ffs(dd->enable_mask); - - /* Reparent the struct clk in case the dpll is in bypass */ - if (_omap2_dpll_is_in_bypass(v)) - return 1; - - return 0; -} - -/** - * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate - * @clk: struct clk * of a DPLL - * - * DPLLs can be locked or bypassed - basically, enabled or disabled. - * When locked, the DPLL output depends on the M and N values. When - * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock - * or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and - * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively - * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk. - * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is - * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0 - * if the clock @clk is not a DPLL. - */ -unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) -{ - long long dpll_clk; - u32 dpll_mult, dpll_div, v; - struct dpll_data *dd; - - dd = clk->dpll_data; - if (!dd) - return 0; - - /* Return bypass rate if DPLL is bypassed */ - v = omap2_clk_readl(clk, dd->control_reg); - v &= dd->enable_mask; - v >>= __ffs(dd->enable_mask); - - if (_omap2_dpll_is_in_bypass(v)) - return __clk_get_rate(dd->clk_bypass); - - v = omap2_clk_readl(clk, dd->mult_div1_reg); - dpll_mult = v & dd->mult_mask; - dpll_mult >>= __ffs(dd->mult_mask); - dpll_div = v & dd->div1_mask; - dpll_div >>= __ffs(dd->div1_mask); - - dpll_clk = (long long) __clk_get_rate(dd->clk_ref) * dpll_mult; - do_div(dpll_clk, dpll_div + 1); - - return dpll_clk; -} - -/* DPLL rate rounding code */ - -/** - * omap2_dpll_round_rate - round a target rate for an OMAP DPLL - * @clk: struct clk * for a DPLL - * @target_rate: desired DPLL clock rate - * - * Given a DPLL and a desired target rate, round the target rate to a - * possible, programmable rate for this DPLL. Attempts to select the - * minimum possible n. Stores the computed (m, n) in the DPLL's - * dpll_data structure so set_rate() will not need to call this - * (expensive) function again. Returns ~0 if the target rate cannot - * be rounded, or the rounded rate upon success. - */ -long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, - unsigned long *parent_rate) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - int m, n, r, scaled_max_m; - int min_delta_m = INT_MAX, min_delta_n = INT_MAX; - unsigned long scaled_rt_rp; - unsigned long new_rate = 0; - struct dpll_data *dd; - unsigned long ref_rate; - long delta; - long prev_min_delta = LONG_MAX; - const char *clk_name; - - if (!clk || !clk->dpll_data) - return ~0; - - dd = clk->dpll_data; - - ref_rate = __clk_get_rate(dd->clk_ref); - clk_name = __clk_get_name(hw->clk); - pr_debug("clock: %s: starting DPLL round_rate, target rate %lu\n", - clk_name, target_rate); - - scaled_rt_rp = target_rate / (ref_rate / DPLL_SCALE_FACTOR); - scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; - - dd->last_rounded_rate = 0; - - for (n = dd->min_divider; n <= dd->max_divider; n++) { - - /* Is the (input clk, divider) pair valid for the DPLL? */ - r = _dpll_test_fint(clk, n); - if (r == DPLL_FINT_UNDERFLOW) - break; - else if (r == DPLL_FINT_INVALID) - continue; - - /* Compute the scaled DPLL multiplier, based on the divider */ - m = scaled_rt_rp * n; - - /* - * Since we're counting n up, a m overflow means we - * can bail out completely (since as n increases in - * the next iteration, there's no way that m can - * increase beyond the current m) - */ - if (m > scaled_max_m) - break; - - r = _dpll_test_mult(&m, n, &new_rate, target_rate, - ref_rate); - - /* m can't be set low enough for this n - try with a larger n */ - if (r == DPLL_MULT_UNDERFLOW) - continue; - - /* skip rates above our target rate */ - delta = target_rate - new_rate; - if (delta < 0) - continue; - - if (delta < prev_min_delta) { - prev_min_delta = delta; - min_delta_m = m; - min_delta_n = n; - } - - pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\n", - clk_name, m, n, new_rate); - - if (delta == 0) - break; - } - - if (prev_min_delta == LONG_MAX) { - pr_debug("clock: %s: cannot round to rate %lu\n", - clk_name, target_rate); - return ~0; - } - - dd->last_rounded_m = min_delta_m; - dd->last_rounded_n = min_delta_n; - dd->last_rounded_rate = target_rate - prev_min_delta; - - return dd->last_rounded_rate; -} - diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index 105ffd0f5e79..62dae2ad3c69 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile @@ -1,6 +1,7 @@ obj-y += clk.o autoidle.o clockdomain.o clk-common = dpll.o composite.o divider.o gate.o \ - fixed-factor.o mux.o apll.o + fixed-factor.o mux.o apll.o \ + clkt_dpll.o obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o diff --git a/drivers/clk/ti/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c new file mode 100644 index 000000000000..a01fc7f305c1 --- /dev/null +++ b/drivers/clk/ti/clkt_dpll.c @@ -0,0 +1,369 @@ +/* + * OMAP2/3/4 DPLL clock functions + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff + * Paul Walmsley + * + * 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. + */ +#undef DEBUG + +#include +#include +#include +#include +#include + +#include + +#include "clock.h" + +/* DPLL rate rounding: minimum DPLL multiplier, divider values */ +#define DPLL_MIN_MULTIPLIER 2 +#define DPLL_MIN_DIVIDER 1 + +/* Possible error results from _dpll_test_mult */ +#define DPLL_MULT_UNDERFLOW -1 + +/* + * Scale factor to mitigate roundoff errors in DPLL rate rounding. + * The higher the scale factor, the greater the risk of arithmetic overflow, + * but the closer the rounded rate to the target rate. DPLL_SCALE_FACTOR + * must be a power of DPLL_SCALE_BASE. + */ +#define DPLL_SCALE_FACTOR 64 +#define DPLL_SCALE_BASE 2 +#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \ + (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE)) + +/* + * DPLL valid Fint frequency range for OMAP36xx and OMAP4xxx. + * From device data manual section 4.3 "DPLL and DLL Specifications". + */ +#define OMAP3PLUS_DPLL_FINT_JTYPE_MIN 500000 +#define OMAP3PLUS_DPLL_FINT_JTYPE_MAX 2500000 + +/* _dpll_test_fint() return codes */ +#define DPLL_FINT_UNDERFLOW -1 +#define DPLL_FINT_INVALID -2 + +/* Private functions */ + +/* + * _dpll_test_fint - test whether an Fint value is valid for the DPLL + * @clk: DPLL struct clk to test + * @n: divider value (N) to test + * + * Tests whether a particular divider @n will result in a valid DPLL + * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter + * Correction". Returns 0 if OK, -1 if the enclosing loop can terminate + * (assuming that it is counting N upwards), or -2 if the enclosing loop + * should skip to the next iteration (again assuming N is increasing). + */ +static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n) +{ + struct dpll_data *dd; + long fint, fint_min, fint_max; + int ret = 0; + + dd = clk->dpll_data; + + /* DPLL divider must result in a valid jitter correction val */ + fint = __clk_get_rate(__clk_get_parent(clk->hw.clk)) / n; + + if (dd->flags & DPLL_J_TYPE) { + fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN; + fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX; + } else { + fint_min = ti_clk_get_features()->fint_min; + fint_max = ti_clk_get_features()->fint_max; + } + + if (!fint_min || !fint_max) { + WARN(1, "No fint limits available!\n"); + return DPLL_FINT_INVALID; + } + + if (fint < ti_clk_get_features()->fint_min) { + pr_debug("rejecting n=%d due to Fint failure, lowering max_divider\n", + n); + dd->max_divider = n; + ret = DPLL_FINT_UNDERFLOW; + } else if (fint > ti_clk_get_features()->fint_max) { + pr_debug("rejecting n=%d due to Fint failure, boosting min_divider\n", + n); + dd->min_divider = n; + ret = DPLL_FINT_INVALID; + } else if (fint > ti_clk_get_features()->fint_band1_max && + fint < ti_clk_get_features()->fint_band2_min) { + pr_debug("rejecting n=%d due to Fint failure\n", n); + ret = DPLL_FINT_INVALID; + } + + return ret; +} + +static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, + unsigned int m, unsigned int n) +{ + unsigned long long num; + + num = (unsigned long long)parent_rate * m; + do_div(num, n); + return num; +} + +/* + * _dpll_test_mult - test a DPLL multiplier value + * @m: pointer to the DPLL m (multiplier) value under test + * @n: current DPLL n (divider) value under test + * @new_rate: pointer to storage for the resulting rounded rate + * @target_rate: the desired DPLL rate + * @parent_rate: the DPLL's parent clock rate + * + * This code tests a DPLL multiplier value, ensuring that the + * resulting rate will not be higher than the target_rate, and that + * the multiplier value itself is valid for the DPLL. Initially, the + * integer pointed to by the m argument should be prescaled by + * multiplying by DPLL_SCALE_FACTOR. The code will replace this with + * a non-scaled m upon return. This non-scaled m will result in a + * new_rate as close as possible to target_rate (but not greater than + * target_rate) given the current (parent_rate, n, prescaled m) + * triple. Returns DPLL_MULT_UNDERFLOW in the event that the + * non-scaled m attempted to underflow, which can allow the calling + * function to bail out early; or 0 upon success. + */ +static int _dpll_test_mult(int *m, int n, unsigned long *new_rate, + unsigned long target_rate, + unsigned long parent_rate) +{ + int r = 0, carry = 0; + + /* Unscale m and round if necessary */ + if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL) + carry = 1; + *m = (*m / DPLL_SCALE_FACTOR) + carry; + + /* + * The new rate must be <= the target rate to avoid programming + * a rate that is impossible for the hardware to handle + */ + *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); + if (*new_rate > target_rate) { + (*m)--; + *new_rate = 0; + } + + /* Guard against m underflow */ + if (*m < DPLL_MIN_MULTIPLIER) { + *m = DPLL_MIN_MULTIPLIER; + *new_rate = 0; + r = DPLL_MULT_UNDERFLOW; + } + + if (*new_rate == 0) + *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); + + return r; +} + +/** + * _omap2_dpll_is_in_bypass - check if DPLL is in bypass mode or not + * @v: bitfield value of the DPLL enable + * + * Checks given DPLL enable bitfield to see whether the DPLL is in bypass + * mode or not. Returns 1 if the DPLL is in bypass, 0 otherwise. + */ +static int _omap2_dpll_is_in_bypass(u32 v) +{ + u8 mask, val; + + mask = ti_clk_get_features()->dpll_bypass_vals; + + /* + * Each set bit in the mask corresponds to a bypass value equal + * to the bitshift. Go through each set-bit in the mask and + * compare against the given register value. + */ + while (mask) { + val = __ffs(mask); + mask ^= (1 << val); + if (v == val) + return 1; + } + + return 0; +} + +/* Public functions */ +u8 omap2_init_dpll_parent(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + u32 v; + struct dpll_data *dd; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + v = ti_clk_ll_ops->clk_readl(dd->control_reg); + v &= dd->enable_mask; + v >>= __ffs(dd->enable_mask); + + /* Reparent the struct clk in case the dpll is in bypass */ + if (_omap2_dpll_is_in_bypass(v)) + return 1; + + return 0; +} + +/** + * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate + * @clk: struct clk * of a DPLL + * + * DPLLs can be locked or bypassed - basically, enabled or disabled. + * When locked, the DPLL output depends on the M and N values. When + * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock + * or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and + * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively + * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk. + * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is + * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0 + * if the clock @clk is not a DPLL. + */ +unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) +{ + long long dpll_clk; + u32 dpll_mult, dpll_div, v; + struct dpll_data *dd; + + dd = clk->dpll_data; + if (!dd) + return 0; + + /* Return bypass rate if DPLL is bypassed */ + v = ti_clk_ll_ops->clk_readl(dd->control_reg); + v &= dd->enable_mask; + v >>= __ffs(dd->enable_mask); + + if (_omap2_dpll_is_in_bypass(v)) + return __clk_get_rate(dd->clk_bypass); + + v = ti_clk_ll_ops->clk_readl(dd->mult_div1_reg); + dpll_mult = v & dd->mult_mask; + dpll_mult >>= __ffs(dd->mult_mask); + dpll_div = v & dd->div1_mask; + dpll_div >>= __ffs(dd->div1_mask); + + dpll_clk = (long long)__clk_get_rate(dd->clk_ref) * dpll_mult; + do_div(dpll_clk, dpll_div + 1); + + return dpll_clk; +} + +/* DPLL rate rounding code */ + +/** + * omap2_dpll_round_rate - round a target rate for an OMAP DPLL + * @clk: struct clk * for a DPLL + * @target_rate: desired DPLL clock rate + * + * Given a DPLL and a desired target rate, round the target rate to a + * possible, programmable rate for this DPLL. Attempts to select the + * minimum possible n. Stores the computed (m, n) in the DPLL's + * dpll_data structure so set_rate() will not need to call this + * (expensive) function again. Returns ~0 if the target rate cannot + * be rounded, or the rounded rate upon success. + */ +long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, + unsigned long *parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + int m, n, r, scaled_max_m; + int min_delta_m = INT_MAX, min_delta_n = INT_MAX; + unsigned long scaled_rt_rp; + unsigned long new_rate = 0; + struct dpll_data *dd; + unsigned long ref_rate; + long delta; + long prev_min_delta = LONG_MAX; + const char *clk_name; + + if (!clk || !clk->dpll_data) + return ~0; + + dd = clk->dpll_data; + + ref_rate = __clk_get_rate(dd->clk_ref); + clk_name = __clk_get_name(hw->clk); + pr_debug("clock: %s: starting DPLL round_rate, target rate %lu\n", + clk_name, target_rate); + + scaled_rt_rp = target_rate / (ref_rate / DPLL_SCALE_FACTOR); + scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; + + dd->last_rounded_rate = 0; + + for (n = dd->min_divider; n <= dd->max_divider; n++) { + /* Is the (input clk, divider) pair valid for the DPLL? */ + r = _dpll_test_fint(clk, n); + if (r == DPLL_FINT_UNDERFLOW) + break; + else if (r == DPLL_FINT_INVALID) + continue; + + /* Compute the scaled DPLL multiplier, based on the divider */ + m = scaled_rt_rp * n; + + /* + * Since we're counting n up, a m overflow means we + * can bail out completely (since as n increases in + * the next iteration, there's no way that m can + * increase beyond the current m) + */ + if (m > scaled_max_m) + break; + + r = _dpll_test_mult(&m, n, &new_rate, target_rate, + ref_rate); + + /* m can't be set low enough for this n - try with a larger n */ + if (r == DPLL_MULT_UNDERFLOW) + continue; + + /* skip rates above our target rate */ + delta = target_rate - new_rate; + if (delta < 0) + continue; + + if (delta < prev_min_delta) { + prev_min_delta = delta; + min_delta_m = m; + min_delta_n = n; + } + + pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\n", + clk_name, m, n, new_rate); + + if (delta == 0) + break; + } + + if (prev_min_delta == LONG_MAX) { + pr_debug("clock: %s: cannot round to rate %lu\n", + clk_name, target_rate); + return ~0; + } + + dd->last_rounded_m = min_delta_m; + dd->last_rounded_n = min_delta_n; + dd->last_rounded_rate = target_rate - prev_min_delta; + + return dd->last_rounded_rate; +} diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 404158d2d7f8..05ed10a81ace 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -169,4 +169,6 @@ void ti_clk_patch_legacy_clks(struct ti_clk **patch); struct clk *ti_clk_register_clk(struct ti_clk *setup); int ti_clk_register_legacy_clks(struct ti_clk_alias *clks); +u8 omap2_init_dpll_parent(struct clk_hw *hw); + #endif diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 1a7f86a68f62..886b2e9d2204 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -286,7 +286,6 @@ long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long max_rate, unsigned long *best_parent_rate, struct clk_hw **best_parent_clk); -u8 omap2_init_dpll_parent(struct clk_hw *hw); unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, unsigned long *parent_rate); -- cgit v1.3-6-gb490 From 59245ce01a2e3ded836172266e3ac2e576a03333 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 2 Mar 2015 11:07:35 +0200 Subject: clk: ti: move OMAP4+ DPLL implementation under drivers/clk With the legacy clock support gone, the OMAP4 specific DPLL implementations can be moved under the clock driver. Change some of the function prototypes to be static at the same time, and remove some exports from the global TI clock driver header. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/Makefile | 6 +- arch/arm/mach-omap2/clock.h | 4 - arch/arm/mach-omap2/dpll44xx.c | 232 ---------------------------------------- drivers/clk/ti/Makefile | 6 +- drivers/clk/ti/clock.h | 14 +++ drivers/clk/ti/dpll44xx.c | 233 +++++++++++++++++++++++++++++++++++++++++ include/linux/clk/ti.h | 13 +-- 7 files changed, 254 insertions(+), 254 deletions(-) delete mode 100644 arch/arm/mach-omap2/dpll44xx.c create mode 100644 drivers/clk/ti/dpll44xx.c (limited to 'drivers') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index fcb5d47f88ca..5bcd282f04b3 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -193,12 +193,12 @@ obj-$(CONFIG_ARCH_OMAP3) += clock3517.o clock36xx.o obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o obj-$(CONFIG_ARCH_OMAP3) += clkt_iclk.o obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) -obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o dpll44xx.o +obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o obj-$(CONFIG_SOC_AM33XX) += $(clock-common) dpll3xxx.o obj-$(CONFIG_SOC_OMAP5) += $(clock-common) -obj-$(CONFIG_SOC_OMAP5) += dpll3xxx.o dpll44xx.o +obj-$(CONFIG_SOC_OMAP5) += dpll3xxx.o obj-$(CONFIG_SOC_DRA7XX) += $(clock-common) -obj-$(CONFIG_SOC_DRA7XX) += dpll3xxx.o dpll44xx.o +obj-$(CONFIG_SOC_DRA7XX) += dpll3xxx.o obj-$(CONFIG_SOC_AM43XX) += $(clock-common) dpll3xxx.o # OMAP2 clock rate set data (old "OPP" data) diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index ac21856d245d..d7ed2446057c 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -183,8 +183,6 @@ struct clksel { u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk); void omap3_dpll_allow_idle(struct clk_hw_omap *clk); void omap3_dpll_deny_idle(struct clk_hw_omap *clk); -void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk); -void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk); void __init omap2_clk_disable_clkdm_control(void); @@ -204,8 +202,6 @@ int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val); extern void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); extern void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); -unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); - void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, void __iomem **other_reg, u8 *other_bit); diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c deleted file mode 100644 index f231be05b9a6..000000000000 --- a/arch/arm/mach-omap2/dpll44xx.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * OMAP4-specific DPLL control functions - * - * Copyright (C) 2011 Texas Instruments, Inc. - * Rajendra Nayak - * - * 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 "clock.h" - -/* - * Maximum DPLL input frequency (FINT) and output frequency (FOUT) that - * can supported when using the DPLL low-power mode. Frequencies are - * defined in OMAP4430/60 Public TRM section 3.6.3.3.2 "Enable Control, - * Status, and Low-Power Operation Mode". - */ -#define OMAP4_DPLL_LP_FINT_MAX 1000000 -#define OMAP4_DPLL_LP_FOUT_MAX 100000000 - -/* - * Bitfield declarations - */ -#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK (1 << 8) -#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK (1 << 10) -#define OMAP4430_DPLL_REGM4XEN_MASK (1 << 11) - -/* Static rate multiplier for OMAP4 REGM4XEN clocks */ -#define OMAP4430_REGM4XEN_MULT 4 - -void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk) -{ - u32 v; - u32 mask; - - if (!clk || !clk->clksel_reg) - return; - - mask = clk->flags & CLOCK_CLKOUTX2 ? - OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : - OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; - - v = omap2_clk_readl(clk, clk->clksel_reg); - /* Clear the bit to allow gatectrl */ - v &= ~mask; - omap2_clk_writel(v, clk, clk->clksel_reg); -} - -void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) -{ - u32 v; - u32 mask; - - if (!clk || !clk->clksel_reg) - return; - - mask = clk->flags & CLOCK_CLKOUTX2 ? - OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : - OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; - - v = omap2_clk_readl(clk, clk->clksel_reg); - /* Set the bit to deny gatectrl */ - v |= mask; - omap2_clk_writel(v, clk, clk->clksel_reg); -} - -const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = { - .allow_idle = omap4_dpllmx_allow_gatectrl, - .deny_idle = omap4_dpllmx_deny_gatectrl, -}; - -/** - * omap4_dpll_lpmode_recalc - compute DPLL low-power setting - * @dd: pointer to the dpll data structure - * - * Calculates if low-power mode can be enabled based upon the last - * multiplier and divider values calculated. If low-power mode can be - * enabled, then the bit to enable low-power mode is stored in the - * last_rounded_lpmode variable. This implementation is based upon the - * criteria for enabling low-power mode as described in the OMAP4430/60 - * Public TRM section 3.6.3.3.2 "Enable Control, Status, and Low-Power - * Operation Mode". - */ -static void omap4_dpll_lpmode_recalc(struct dpll_data *dd) -{ - long fint, fout; - - fint = __clk_get_rate(dd->clk_ref) / (dd->last_rounded_n + 1); - fout = fint * dd->last_rounded_m; - - if ((fint < OMAP4_DPLL_LP_FINT_MAX) && (fout < OMAP4_DPLL_LP_FOUT_MAX)) - dd->last_rounded_lpmode = 1; - else - dd->last_rounded_lpmode = 0; -} - -/** - * omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit - * @clk: struct clk * of the DPLL to compute the rate for - * - * Compute the output rate for the OMAP4 DPLL represented by @clk. - * Takes the REGM4XEN bit into consideration, which is needed for the - * OMAP4 ABE DPLL. Returns the DPLL's output rate (before M-dividers) - * upon success, or 0 upon error. - */ -unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - u32 v; - unsigned long rate; - struct dpll_data *dd; - - if (!clk || !clk->dpll_data) - return 0; - - dd = clk->dpll_data; - - rate = omap2_get_dpll_rate(clk); - - /* regm4xen adds a multiplier of 4 to DPLL calculations */ - v = omap2_clk_readl(clk, dd->control_reg); - if (v & OMAP4430_DPLL_REGM4XEN_MASK) - rate *= OMAP4430_REGM4XEN_MULT; - - return rate; -} - -/** - * omap4_dpll_regm4xen_round_rate - round DPLL rate, considering REGM4XEN bit - * @clk: struct clk * of the DPLL to round a rate for - * @target_rate: the desired rate of the DPLL - * - * Compute the rate that would be programmed into the DPLL hardware - * for @clk if set_rate() were to be provided with the rate - * @target_rate. Takes the REGM4XEN bit into consideration, which is - * needed for the OMAP4 ABE DPLL. Returns the rounded rate (before - * M-dividers) upon success, -EINVAL if @clk is null or not a DPLL, or - * ~0 if an error occurred in omap2_dpll_round_rate(). - */ -long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, - unsigned long target_rate, - unsigned long *parent_rate) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - struct dpll_data *dd; - long r; - - if (!clk || !clk->dpll_data) - return -EINVAL; - - dd = clk->dpll_data; - - dd->last_rounded_m4xen = 0; - - /* - * First try to compute the DPLL configuration for - * target rate without using the 4X multiplier. - */ - r = omap2_dpll_round_rate(hw, target_rate, NULL); - if (r != ~0) - goto out; - - /* - * If we did not find a valid DPLL configuration, try again, but - * this time see if using the 4X multiplier can help. Enabling the - * 4X multiplier is equivalent to dividing the target rate by 4. - */ - r = omap2_dpll_round_rate(hw, target_rate / OMAP4430_REGM4XEN_MULT, - NULL); - if (r == ~0) - return r; - - dd->last_rounded_rate *= OMAP4430_REGM4XEN_MULT; - dd->last_rounded_m4xen = 1; - -out: - omap4_dpll_lpmode_recalc(dd); - - return dd->last_rounded_rate; -} - -/** - * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL - * @hw: pointer to the clock to determine rate for - * @rate: target rate for the DPLL - * @best_parent_rate: pointer for returning best parent rate - * @best_parent_clk: pointer for returning best parent clock - * - * Determines which DPLL mode to use for reaching a desired rate. - * Checks whether the DPLL shall be in bypass or locked mode, and if - * locked, calculates the M,N values for the DPLL via round-rate. - * Returns a positive clock rate with success, negative error value - * in failure. - */ -long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - struct dpll_data *dd; - - if (!hw || !rate) - return -EINVAL; - - dd = clk->dpll_data; - if (!dd) - return -EINVAL; - - if (__clk_get_rate(dd->clk_bypass) == rate && - (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - *best_parent_clk = __clk_get_hw(dd->clk_bypass); - } else { - rate = omap4_dpll_regm4xen_round_rate(hw, rate, - best_parent_rate); - *best_parent_clk = __clk_get_hw(dd->clk_ref); - } - - *best_parent_rate = rate; - - return rate; -} diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index 62dae2ad3c69..c3ec3014fb2d 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile @@ -7,10 +7,10 @@ obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \ clk-3xxx.o -obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o -obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o +obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o dpll44xx.o +obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o dpll44xx.o obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \ - clk-dra7-atl.o + clk-dra7-atl.o dpll44xx.o obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o ifdef CONFIG_ATAGS diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 05ed10a81ace..c75d4b44cbef 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -169,6 +169,20 @@ void ti_clk_patch_legacy_clks(struct ti_clk **patch); struct clk *ti_clk_register_clk(struct ti_clk *setup); int ti_clk_register_legacy_clks(struct ti_clk_alias *clks); +extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; + u8 omap2_init_dpll_parent(struct clk_hw *hw); +unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, + unsigned long parent_rate); +long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, + unsigned long target_rate, + unsigned long *parent_rate); +long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long min_rate, + unsigned long max_rate, + unsigned long *best_parent_rate, + struct clk_hw **best_parent_clk); + #endif diff --git a/drivers/clk/ti/dpll44xx.c b/drivers/clk/ti/dpll44xx.c new file mode 100644 index 000000000000..ef1a5b43d01f --- /dev/null +++ b/drivers/clk/ti/dpll44xx.c @@ -0,0 +1,233 @@ +/* + * OMAP4-specific DPLL control functions + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Rajendra Nayak + * + * 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 "clock.h" + +/* + * Maximum DPLL input frequency (FINT) and output frequency (FOUT) that + * can supported when using the DPLL low-power mode. Frequencies are + * defined in OMAP4430/60 Public TRM section 3.6.3.3.2 "Enable Control, + * Status, and Low-Power Operation Mode". + */ +#define OMAP4_DPLL_LP_FINT_MAX 1000000 +#define OMAP4_DPLL_LP_FOUT_MAX 100000000 + +/* + * Bitfield declarations + */ +#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK BIT(8) +#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK BIT(10) +#define OMAP4430_DPLL_REGM4XEN_MASK BIT(11) + +/* Static rate multiplier for OMAP4 REGM4XEN clocks */ +#define OMAP4430_REGM4XEN_MULT 4 + +static void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk) +{ + u32 v; + u32 mask; + + if (!clk || !clk->clksel_reg) + return; + + mask = clk->flags & CLOCK_CLKOUTX2 ? + OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : + OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; + + v = ti_clk_ll_ops->clk_readl(clk->clksel_reg); + /* Clear the bit to allow gatectrl */ + v &= ~mask; + ti_clk_ll_ops->clk_writel(v, clk->clksel_reg); +} + +static void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) +{ + u32 v; + u32 mask; + + if (!clk || !clk->clksel_reg) + return; + + mask = clk->flags & CLOCK_CLKOUTX2 ? + OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : + OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; + + v = ti_clk_ll_ops->clk_readl(clk->clksel_reg); + /* Set the bit to deny gatectrl */ + v |= mask; + ti_clk_ll_ops->clk_writel(v, clk->clksel_reg); +} + +const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = { + .allow_idle = omap4_dpllmx_allow_gatectrl, + .deny_idle = omap4_dpllmx_deny_gatectrl, +}; + +/** + * omap4_dpll_lpmode_recalc - compute DPLL low-power setting + * @dd: pointer to the dpll data structure + * + * Calculates if low-power mode can be enabled based upon the last + * multiplier and divider values calculated. If low-power mode can be + * enabled, then the bit to enable low-power mode is stored in the + * last_rounded_lpmode variable. This implementation is based upon the + * criteria for enabling low-power mode as described in the OMAP4430/60 + * Public TRM section 3.6.3.3.2 "Enable Control, Status, and Low-Power + * Operation Mode". + */ +static void omap4_dpll_lpmode_recalc(struct dpll_data *dd) +{ + long fint, fout; + + fint = __clk_get_rate(dd->clk_ref) / (dd->last_rounded_n + 1); + fout = fint * dd->last_rounded_m; + + if ((fint < OMAP4_DPLL_LP_FINT_MAX) && (fout < OMAP4_DPLL_LP_FOUT_MAX)) + dd->last_rounded_lpmode = 1; + else + dd->last_rounded_lpmode = 0; +} + +/** + * omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit + * @clk: struct clk * of the DPLL to compute the rate for + * + * Compute the output rate for the OMAP4 DPLL represented by @clk. + * Takes the REGM4XEN bit into consideration, which is needed for the + * OMAP4 ABE DPLL. Returns the DPLL's output rate (before M-dividers) + * upon success, or 0 upon error. + */ +unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + u32 v; + unsigned long rate; + struct dpll_data *dd; + + if (!clk || !clk->dpll_data) + return 0; + + dd = clk->dpll_data; + + rate = omap2_get_dpll_rate(clk); + + /* regm4xen adds a multiplier of 4 to DPLL calculations */ + v = ti_clk_ll_ops->clk_readl(dd->control_reg); + if (v & OMAP4430_DPLL_REGM4XEN_MASK) + rate *= OMAP4430_REGM4XEN_MULT; + + return rate; +} + +/** + * omap4_dpll_regm4xen_round_rate - round DPLL rate, considering REGM4XEN bit + * @clk: struct clk * of the DPLL to round a rate for + * @target_rate: the desired rate of the DPLL + * + * Compute the rate that would be programmed into the DPLL hardware + * for @clk if set_rate() were to be provided with the rate + * @target_rate. Takes the REGM4XEN bit into consideration, which is + * needed for the OMAP4 ABE DPLL. Returns the rounded rate (before + * M-dividers) upon success, -EINVAL if @clk is null or not a DPLL, or + * ~0 if an error occurred in omap2_dpll_round_rate(). + */ +long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, + unsigned long target_rate, + unsigned long *parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + long r; + + if (!clk || !clk->dpll_data) + return -EINVAL; + + dd = clk->dpll_data; + + dd->last_rounded_m4xen = 0; + + /* + * First try to compute the DPLL configuration for + * target rate without using the 4X multiplier. + */ + r = omap2_dpll_round_rate(hw, target_rate, NULL); + if (r != ~0) + goto out; + + /* + * If we did not find a valid DPLL configuration, try again, but + * this time see if using the 4X multiplier can help. Enabling the + * 4X multiplier is equivalent to dividing the target rate by 4. + */ + r = omap2_dpll_round_rate(hw, target_rate / OMAP4430_REGM4XEN_MULT, + NULL); + if (r == ~0) + return r; + + dd->last_rounded_rate *= OMAP4430_REGM4XEN_MULT; + dd->last_rounded_m4xen = 1; + +out: + omap4_dpll_lpmode_recalc(dd); + + return dd->last_rounded_rate; +} + +/** + * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL + * @hw: pointer to the clock to determine rate for + * @rate: target rate for the DPLL + * @best_parent_rate: pointer for returning best parent rate + * @best_parent_clk: pointer for returning best parent clock + * + * Determines which DPLL mode to use for reaching a desired rate. + * Checks whether the DPLL shall be in bypass or locked mode, and if + * locked, calculates the M,N values for the DPLL via round-rate. + * Returns a positive clock rate with success, negative error value + * in failure. + */ +long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long min_rate, + unsigned long max_rate, + unsigned long *best_parent_rate, + struct clk_hw **best_parent_clk) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + + if (!hw || !rate) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + if (__clk_get_rate(dd->clk_bypass) == rate && + (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { + *best_parent_clk = __clk_get_hw(dd->clk_bypass); + } else { + rate = omap4_dpll_regm4xen_round_rate(hw, rate, + best_parent_rate); + *best_parent_clk = __clk_get_hw(dd->clk_ref); + } + + *best_parent_rate = rate; + + return rate; +} diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 886b2e9d2204..ee59e076340f 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -275,17 +275,6 @@ long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long max_rate, unsigned long *best_parent_rate, struct clk_hw **best_parent_clk); -unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, - unsigned long parent_rate); -long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, - unsigned long target_rate, - unsigned long *parent_rate); -long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk); unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, unsigned long *parent_rate); @@ -314,6 +303,7 @@ int omap2_reprogram_dpllcore(struct clk_hw *clk, unsigned long rate, unsigned long parent_rate); void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw); void omap2xxx_clkt_vps_init(void); +unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); void ti_dt_clocks_register(struct ti_dt_clk *oclks); @@ -364,7 +354,6 @@ static inline void of_ti_clk_deny_autoidle_all(void) { } extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; -extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; extern const struct clk_hw_omap_ops clkhwops_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; -- cgit v1.3-6-gb490 From ef14db0977547b1982d4f6eaa305e1a22eb95778 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 2 Mar 2015 14:33:54 +0200 Subject: clk: ti: move interface clock implementation under drivers/clk With the legacy clock support gone, the OMAP interface clock implementation can be moved under the clock driver. Some temporary header file tweaks are also needed to make this change work properly. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/Makefile | 3 +- arch/arm/mach-omap2/clkt_iclk.c | 68 ----------------------------------------- arch/arm/mach-omap2/clock.h | 11 ------- drivers/clk/ti/Makefile | 2 +- drivers/clk/ti/clkt_iclk.c | 66 +++++++++++++++++++++++++++++++++++++++ drivers/clk/ti/clock.h | 2 ++ include/linux/clk/ti.h | 10 ++++-- 7 files changed, 78 insertions(+), 84 deletions(-) delete mode 100644 arch/arm/mach-omap2/clkt_iclk.c create mode 100644 drivers/clk/ti/clkt_iclk.c (limited to 'drivers') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 5bcd282f04b3..a2f51564e8d4 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -185,13 +185,12 @@ obj-$(CONFIG_SOC_DRA7XX) += clockdomains7xx_data.o obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpllcore.o obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_virt_prcm_set.o -obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o clkt_iclk.o +obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o obj-$(CONFIG_SOC_OMAP2430) += clock2430.o obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o obj-$(CONFIG_ARCH_OMAP3) += clock3517.o clock36xx.o obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o -obj-$(CONFIG_ARCH_OMAP3) += clkt_iclk.o obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o obj-$(CONFIG_SOC_AM33XX) += $(clock-common) dpll3xxx.o diff --git a/arch/arm/mach-omap2/clkt_iclk.c b/arch/arm/mach-omap2/clkt_iclk.c deleted file mode 100644 index 55eb579aeae1..000000000000 --- a/arch/arm/mach-omap2/clkt_iclk.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * OMAP2/3 interface clock control - * - * Copyright (C) 2011 Nokia Corporation - * Paul Walmsley - * - * 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. - */ -#undef DEBUG - -#include -#include -#include - -#include "clock.h" - -/* Register offsets */ -#define CM_AUTOIDLE 0x30 -#define CM_ICLKEN 0x10 - -/* Private functions */ - -/* XXX */ -void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk) -{ - u32 v; - void __iomem *r; - - r = (__force void __iomem *) - ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); - - v = omap2_clk_readl(clk, r); - v |= (1 << clk->enable_bit); - omap2_clk_writel(v, clk, r); -} - -/* XXX */ -void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk) -{ - u32 v; - void __iomem *r; - - r = (__force void __iomem *) - ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); - - v = omap2_clk_readl(clk, r); - v &= ~(1 << clk->enable_bit); - omap2_clk_writel(v, clk, r); -} - -/* Public data */ - -const struct clk_hw_omap_ops clkhwops_iclk = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, -}; - -const struct clk_hw_omap_ops clkhwops_iclk_wait = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, - .find_idlest = omap2_clk_dflt_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - - - diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index d7ed2446057c..ca8c42c70db5 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -198,16 +198,6 @@ int omap2_clksel_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate); int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val); -/* clkt_iclk.c public functions */ -extern void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); -extern void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); - -void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, - void __iomem **other_reg, - u8 *other_bit); -void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, u8 *idlest_val); int omap2_clk_enable_autoidle_all(void); int omap2_clk_allow_idle(struct clk *clk); int omap2_clk_deny_idle(struct clk *clk); @@ -231,7 +221,6 @@ extern const struct clksel_rate gpt_sys_rates[]; extern const struct clksel_rate gfx_l3_rates[]; extern const struct clksel_rate dsp_ick_rates[]; -extern const struct clk_hw_omap_ops clkhwops_iclk_wait; extern const struct clk_hw_omap_ops clkhwops_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index c3ec3014fb2d..23cd72638970 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile @@ -1,7 +1,7 @@ obj-y += clk.o autoidle.o clockdomain.o clk-common = dpll.o composite.o divider.o gate.o \ fixed-factor.o mux.o apll.o \ - clkt_dpll.o + clkt_dpll.o clkt_iclk.o obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o diff --git a/drivers/clk/ti/clkt_iclk.c b/drivers/clk/ti/clkt_iclk.c new file mode 100644 index 000000000000..a03919df00ef --- /dev/null +++ b/drivers/clk/ti/clkt_iclk.c @@ -0,0 +1,66 @@ +/* + * OMAP2/3 interface clock control + * + * Copyright (C) 2011 Nokia Corporation + * Paul Walmsley + * + * 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. + */ +#undef DEBUG + +#include +#include +#include +#include + +#include "clock.h" + +/* Register offsets */ +#define CM_AUTOIDLE 0x30 +#define CM_ICLKEN 0x10 + +/* Private functions */ + +/* XXX */ +void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk) +{ + u32 v; + void __iomem *r; + + r = (__force void __iomem *) + ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + + v = ti_clk_ll_ops->clk_readl(r); + v |= (1 << clk->enable_bit); + ti_clk_ll_ops->clk_writel(v, r); +} + +/* XXX */ +void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk) +{ + u32 v; + void __iomem *r; + + r = (__force void __iomem *) + ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + + v = ti_clk_ll_ops->clk_readl(r); + v &= ~(1 << clk->enable_bit); + ti_clk_ll_ops->clk_writel(v, r); +} + +/* Public data */ + +const struct clk_hw_omap_ops clkhwops_iclk = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, +}; + +const struct clk_hw_omap_ops clkhwops_iclk_wait = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, + .find_idlest = omap2_clk_dflt_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index c75d4b44cbef..a7256a98201d 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -170,6 +170,8 @@ struct clk *ti_clk_register_clk(struct ti_clk *setup); int ti_clk_register_legacy_clks(struct ti_clk_alias *clks); extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; +extern const struct clk_hw_omap_ops clkhwops_iclk; +extern const struct clk_hw_omap_ops clkhwops_iclk_wait; u8 omap2_init_dpll_parent(struct clk_hw *hw); diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index ee59e076340f..79e143dfc793 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -296,6 +296,14 @@ int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, int omap2_dflt_clk_enable(struct clk_hw *hw); void omap2_dflt_clk_disable(struct clk_hw *hw); int omap2_dflt_clk_is_enabled(struct clk_hw *hw); +void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); +void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); +void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, + void __iomem **other_reg, + u8 *other_bit); +void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, u8 *idlest_val); void omap3_clk_lock_dpll5(void); unsigned long omap2_dpllcore_recalc(struct clk_hw *hw, unsigned long parent_rate); @@ -358,8 +366,6 @@ extern const struct clk_hw_omap_ops clkhwops_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; -extern const struct clk_hw_omap_ops clkhwops_iclk; -extern const struct clk_hw_omap_ops clkhwops_iclk_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait; -- cgit v1.3-6-gb490 From bf22bae794d696e411acfcac39b415e160e93834 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 2 Mar 2015 19:06:54 +0200 Subject: clk: ti: autoidle: move generic autoidle handling code to clock driver This is no longer needed in platform directory, as the legacy clock data is gone, so move it under TI clock driver. Some static functions are renamed also. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/clock.c | 104 ------------------------------------ arch/arm/mach-omap2/clock.h | 3 -- drivers/clk/ti/autoidle.c | 119 +++++++++++++++++++++++++++++++++++++++--- drivers/clk/ti/clock.h | 3 ++ drivers/clk/ti/fixed-factor.c | 2 + include/linux/clk/ti.h | 13 ++--- 6 files changed, 119 insertions(+), 125 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index cbc65b3a3b62..42ce860e1d4c 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -69,8 +69,6 @@ u16 cpu_mask; */ static bool clkdm_control = true; -static LIST_HEAD(clk_hw_omap_clocks); - struct clk_iomap { struct regmap *regmap; void __iomem *mem; @@ -578,108 +576,6 @@ static int __init omap_clk_setup(char *str) } __setup("mpurate=", omap_clk_setup); -/** - * omap2_init_clk_hw_omap_clocks - initialize an OMAP clock - * @clk: struct clk * to initialize - * - * Add an OMAP clock @clk to the internal list of OMAP clocks. Used - * temporarily for autoidle handling, until this support can be - * integrated into the common clock framework code in some way. No - * return value. - */ -void omap2_init_clk_hw_omap_clocks(struct clk *clk) -{ - struct clk_hw_omap *c; - - if (__clk_get_flags(clk) & CLK_IS_BASIC) - return; - - c = to_clk_hw_omap(__clk_get_hw(clk)); - list_add(&c->node, &clk_hw_omap_clocks); -} - -/** - * omap2_clk_enable_autoidle_all - enable autoidle on all OMAP clocks that - * support it - * - * Enable clock autoidle on all OMAP clocks that have allow_idle - * function pointers associated with them. This function is intended - * to be temporary until support for this is added to the common clock - * code. Returns 0. - */ -int omap2_clk_enable_autoidle_all(void) -{ - struct clk_hw_omap *c; - - list_for_each_entry(c, &clk_hw_omap_clocks, node) - if (c->ops && c->ops->allow_idle) - c->ops->allow_idle(c); - - of_ti_clk_allow_autoidle_all(); - - return 0; -} - -/** - * omap2_clk_disable_autoidle_all - disable autoidle on all OMAP clocks that - * support it - * - * Disable clock autoidle on all OMAP clocks that have allow_idle - * function pointers associated with them. This function is intended - * to be temporary until support for this is added to the common clock - * code. Returns 0. - */ -int omap2_clk_disable_autoidle_all(void) -{ - struct clk_hw_omap *c; - - list_for_each_entry(c, &clk_hw_omap_clocks, node) - if (c->ops && c->ops->deny_idle) - c->ops->deny_idle(c); - - of_ti_clk_deny_autoidle_all(); - - return 0; -} - -/** - * omap2_clk_deny_idle - disable autoidle on an OMAP clock - * @clk: struct clk * to disable autoidle for - * - * Disable autoidle on an OMAP clock. - */ -int omap2_clk_deny_idle(struct clk *clk) -{ - struct clk_hw_omap *c; - - if (__clk_get_flags(clk) & CLK_IS_BASIC) - return -EINVAL; - - c = to_clk_hw_omap(__clk_get_hw(clk)); - if (c->ops && c->ops->deny_idle) - c->ops->deny_idle(c); - return 0; -} - -/** - * omap2_clk_allow_idle - enable autoidle on an OMAP clock - * @clk: struct clk * to enable autoidle for - * - * Enable autoidle on an OMAP clock. - */ -int omap2_clk_allow_idle(struct clk *clk) -{ - struct clk_hw_omap *c; - - if (__clk_get_flags(clk) & CLK_IS_BASIC) - return -EINVAL; - - c = to_clk_hw_omap(__clk_get_hw(clk)); - if (c->ops && c->ops->allow_idle) - c->ops->allow_idle(c); - return 0; -} - /** * omap2_clk_enable_init_clocks - prepare & enable a list of clocks * @clk_names: ptr to an array of strings of clock names to enable diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index b71d43051c26..950a17ae4f36 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -186,9 +186,6 @@ void omap3_dpll_deny_idle(struct clk_hw_omap *clk); void __init omap2_clk_disable_clkdm_control(void); -int omap2_clk_enable_autoidle_all(void); -int omap2_clk_allow_idle(struct clk *clk); -int omap2_clk_deny_idle(struct clk *clk); int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name); void omap2_clk_print_new_rates(const char *hfclkin_ck_name, const char *core_ck_name, diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c index e75c64c9e81c..3dbcc3681058 100644 --- a/drivers/clk/ti/autoidle.c +++ b/drivers/clk/ti/autoidle.c @@ -33,8 +33,47 @@ struct clk_ti_autoidle { #define AUTOIDLE_LOW 0x1 static LIST_HEAD(autoidle_clks); +static LIST_HEAD(clk_hw_omap_clocks); -static void ti_allow_autoidle(struct clk_ti_autoidle *clk) +/** + * omap2_clk_deny_idle - disable autoidle on an OMAP clock + * @clk: struct clk * to disable autoidle for + * + * Disable autoidle on an OMAP clock. + */ +int omap2_clk_deny_idle(struct clk *clk) +{ + struct clk_hw_omap *c; + + if (__clk_get_flags(clk) & CLK_IS_BASIC) + return -EINVAL; + + c = to_clk_hw_omap(__clk_get_hw(clk)); + if (c->ops && c->ops->deny_idle) + c->ops->deny_idle(c); + return 0; +} + +/** + * omap2_clk_allow_idle - enable autoidle on an OMAP clock + * @clk: struct clk * to enable autoidle for + * + * Enable autoidle on an OMAP clock. + */ +int omap2_clk_allow_idle(struct clk *clk) +{ + struct clk_hw_omap *c; + + if (__clk_get_flags(clk) & CLK_IS_BASIC) + return -EINVAL; + + c = to_clk_hw_omap(__clk_get_hw(clk)); + if (c->ops && c->ops->allow_idle) + c->ops->allow_idle(c); + return 0; +} + +static void _allow_autoidle(struct clk_ti_autoidle *clk) { u32 val; @@ -48,7 +87,7 @@ static void ti_allow_autoidle(struct clk_ti_autoidle *clk) ti_clk_ll_ops->clk_writel(val, clk->reg); } -static void ti_deny_autoidle(struct clk_ti_autoidle *clk) +static void _deny_autoidle(struct clk_ti_autoidle *clk) { u32 val; @@ -63,31 +102,31 @@ static void ti_deny_autoidle(struct clk_ti_autoidle *clk) } /** - * of_ti_clk_allow_autoidle_all - enable autoidle for all clocks + * _clk_generic_allow_autoidle_all - enable autoidle for all clocks * * Enables hardware autoidle for all registered DT clocks, which have * the feature. */ -void of_ti_clk_allow_autoidle_all(void) +static void _clk_generic_allow_autoidle_all(void) { struct clk_ti_autoidle *c; list_for_each_entry(c, &autoidle_clks, node) - ti_allow_autoidle(c); + _allow_autoidle(c); } /** - * of_ti_clk_deny_autoidle_all - disable autoidle for all clocks + * _clk_generic_deny_autoidle_all - disable autoidle for all clocks * * Disables hardware autoidle for all registered DT clocks, which have * the feature. */ -void of_ti_clk_deny_autoidle_all(void) +static void _clk_generic_deny_autoidle_all(void) { struct clk_ti_autoidle *c; list_for_each_entry(c, &autoidle_clks, node) - ti_deny_autoidle(c); + _deny_autoidle(c); } /** @@ -131,3 +170,67 @@ int __init of_ti_clk_autoidle_setup(struct device_node *node) return 0; } + +/** + * omap2_init_clk_hw_omap_clocks - initialize an OMAP clock + * @clk: struct clk * to initialize + * + * Add an OMAP clock @clk to the internal list of OMAP clocks. Used + * temporarily for autoidle handling, until this support can be + * integrated into the common clock framework code in some way. No + * return value. + */ +void omap2_init_clk_hw_omap_clocks(struct clk *clk) +{ + struct clk_hw_omap *c; + + if (__clk_get_flags(clk) & CLK_IS_BASIC) + return; + + c = to_clk_hw_omap(__clk_get_hw(clk)); + list_add(&c->node, &clk_hw_omap_clocks); +} + +/** + * omap2_clk_enable_autoidle_all - enable autoidle on all OMAP clocks that + * support it + * + * Enable clock autoidle on all OMAP clocks that have allow_idle + * function pointers associated with them. This function is intended + * to be temporary until support for this is added to the common clock + * code. Returns 0. + */ +int omap2_clk_enable_autoidle_all(void) +{ + struct clk_hw_omap *c; + + list_for_each_entry(c, &clk_hw_omap_clocks, node) + if (c->ops && c->ops->allow_idle) + c->ops->allow_idle(c); + + _clk_generic_allow_autoidle_all(); + + return 0; +} + +/** + * omap2_clk_disable_autoidle_all - disable autoidle on all OMAP clocks that + * support it + * + * Disable clock autoidle on all OMAP clocks that have allow_idle + * function pointers associated with them. This function is intended + * to be temporary until support for this is added to the common clock + * code. Returns 0. + */ +int omap2_clk_disable_autoidle_all(void) +{ + struct clk_hw_omap *c; + + list_for_each_entry(c, &clk_hw_omap_clocks, node) + if (c->ops && c->ops->deny_idle) + c->ops->deny_idle(c); + + _clk_generic_deny_autoidle_all(); + + return 0; +} diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index a7256a98201d..9b51021f509a 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -169,6 +169,9 @@ void ti_clk_patch_legacy_clks(struct ti_clk **patch); struct clk *ti_clk_register_clk(struct ti_clk *setup); int ti_clk_register_legacy_clks(struct ti_clk_alias *clks); +void omap2_init_clk_hw_omap_clocks(struct clk *clk); +int of_ti_clk_autoidle_setup(struct device_node *node); + extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; extern const struct clk_hw_omap_ops clkhwops_iclk; extern const struct clk_hw_omap_ops clkhwops_iclk_wait; diff --git a/drivers/clk/ti/fixed-factor.c b/drivers/clk/ti/fixed-factor.c index c2c8a287408c..3cd406768909 100644 --- a/drivers/clk/ti/fixed-factor.c +++ b/drivers/clk/ti/fixed-factor.c @@ -22,6 +22,8 @@ #include #include +#include "clock.h" + #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 79e143dfc793..320e107f9a7a 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -259,7 +259,6 @@ extern const struct clk_ops ti_clk_mux_ops; #define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) -void omap2_init_clk_hw_omap_clocks(struct clk *clk); int omap3_noncore_dpll_enable(struct clk_hw *hw); void omap3_noncore_dpll_disable(struct clk_hw *hw); int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index); @@ -288,6 +287,9 @@ long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate, int omap2_clkops_enable_clkdm(struct clk_hw *hw); void omap2_clkops_disable_clkdm(struct clk_hw *hw); int omap2_clk_disable_autoidle_all(void); +int omap2_clk_enable_autoidle_all(void); +int omap2_clk_allow_idle(struct clk *clk); +int omap2_clk_deny_idle(struct clk *clk); void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, unsigned long parent_rate); @@ -320,7 +322,6 @@ void ti_dt_clk_init_retry_clks(void); void ti_dt_clockdomains_setup(void); int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, ti_of_clk_init_cb_t func); -int of_ti_clk_autoidle_setup(struct device_node *node); int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type); int omap3430_dt_clk_init(void); @@ -351,14 +352,6 @@ struct ti_clk_features { void ti_clk_setup_features(struct ti_clk_features *features); const struct ti_clk_features *ti_clk_get_features(void); -#ifdef CONFIG_OF -void of_ti_clk_allow_autoidle_all(void); -void of_ti_clk_deny_autoidle_all(void); -#else -static inline void of_ti_clk_allow_autoidle_all(void) { } -static inline void of_ti_clk_deny_autoidle_all(void) { } -#endif - extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; -- cgit v1.3-6-gb490 From a5aa8a603efa25dd41220bff990da025c93b632b Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 3 Mar 2015 10:51:01 +0200 Subject: clk: ti: move omap2_clk_enable_init_clocks under clock driver This is no longer used outside clock driver, so move it under the driver and remove the export for it from the global header file. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/clock.c | 24 ------------------------ drivers/clk/ti/clk-2xxx.c | 2 ++ drivers/clk/ti/clk-33xx.c | 2 ++ drivers/clk/ti/clk-3xxx.c | 1 + drivers/clk/ti/clk-816x.c | 2 ++ drivers/clk/ti/clk.c | 24 ++++++++++++++++++++++++ drivers/clk/ti/clock.h | 1 + include/linux/clk/ti.h | 1 - 8 files changed, 32 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 42ce860e1d4c..234cedf8967d 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -576,30 +576,6 @@ static int __init omap_clk_setup(char *str) } __setup("mpurate=", omap_clk_setup); -/** - * omap2_clk_enable_init_clocks - prepare & enable a list of clocks - * @clk_names: ptr to an array of strings of clock names to enable - * @num_clocks: number of clock names in @clk_names - * - * Prepare and enable a list of clocks, named by @clk_names. No - * return value. XXX Deprecated; only needed until these clocks are - * properly claimed and enabled by the drivers or core code that uses - * them. XXX What code disables & calls clk_put on these clocks? - */ -void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks) -{ - struct clk *init_clk; - int i; - - for (i = 0; i < num_clocks; i++) { - init_clk = clk_get(NULL, clk_names[i]); - if (WARN(IS_ERR(init_clk), "could not find init clock %s\n", - clk_names[i])) - continue; - clk_prepare_enable(init_clk); - } -} - const struct clk_hw_omap_ops clkhwops_wait = { .find_idlest = omap2_clk_dflt_find_idlest, .find_companion = omap2_clk_dflt_find_companion, diff --git a/drivers/clk/ti/clk-2xxx.c b/drivers/clk/ti/clk-2xxx.c index c808ab3d2bb2..bd8790be2ab1 100644 --- a/drivers/clk/ti/clk-2xxx.c +++ b/drivers/clk/ti/clk-2xxx.c @@ -19,6 +19,8 @@ #include #include +#include "clock.h" + static struct ti_dt_clk omap2xxx_clks[] = { DT_CLK(NULL, "func_32k_ck", "func_32k_ck"), DT_CLK(NULL, "secure_32k_ck", "secure_32k_ck"), diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c index 028b33783d38..733f9d374d0f 100644 --- a/drivers/clk/ti/clk-33xx.c +++ b/drivers/clk/ti/clk-33xx.c @@ -19,6 +19,8 @@ #include #include +#include "clock.h" + static struct ti_dt_clk am33xx_clks[] = { DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c index 757636d166cf..bb3b88359daf 100644 --- a/drivers/clk/ti/clk-3xxx.c +++ b/drivers/clk/ti/clk-3xxx.c @@ -19,6 +19,7 @@ #include #include +#include "clock.h" static struct ti_dt_clk omap3xxx_clks[] = { DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"), diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c index 9451e651a1ff..c69352b24dba 100644 --- a/drivers/clk/ti/clk-816x.c +++ b/drivers/clk/ti/clk-816x.c @@ -14,6 +14,8 @@ #include #include +#include "clock.h" + static struct ti_dt_clk dm816x_clks[] = { DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"), DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index e65ae4acff9c..5baea03cfc92 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -336,3 +336,27 @@ const struct ti_clk_features *ti_clk_get_features(void) { return &ti_clk_features; } + +/** + * omap2_clk_enable_init_clocks - prepare & enable a list of clocks + * @clk_names: ptr to an array of strings of clock names to enable + * @num_clocks: number of clock names in @clk_names + * + * Prepare and enable a list of clocks, named by @clk_names. No + * return value. XXX Deprecated; only needed until these clocks are + * properly claimed and enabled by the drivers or core code that uses + * them. XXX What code disables & calls clk_put on these clocks? + */ +void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks) +{ + struct clk *init_clk; + int i; + + for (i = 0; i < num_clocks; i++) { + init_clk = clk_get(NULL, clk_names[i]); + if (WARN(IS_ERR(init_clk), "could not find init clock %s\n", + clk_names[i])) + continue; + clk_prepare_enable(init_clk); + } +} diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 9b51021f509a..4b26af8a273d 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -171,6 +171,7 @@ int ti_clk_register_legacy_clks(struct ti_clk_alias *clks); void omap2_init_clk_hw_omap_clocks(struct clk *clk); int of_ti_clk_autoidle_setup(struct device_node *node); +void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; extern const struct clk_hw_omap_ops clkhwops_iclk; diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 320e107f9a7a..61deace552ec 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -290,7 +290,6 @@ int omap2_clk_disable_autoidle_all(void); int omap2_clk_enable_autoidle_all(void); int omap2_clk_allow_idle(struct clk *clk); int omap2_clk_deny_idle(struct clk *clk); -void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, unsigned long parent_rate); int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, -- cgit v1.3-6-gb490 From 0565fb168d63f89591ce7dcb85438cb19d939a92 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 3 Mar 2015 13:27:48 +0200 Subject: clk: ti: dpll: move omap3 DPLL functionality to clock driver With the legacy clock support gone, OMAP3 generic DPLL code can now be moved over to the clock driver also. A few un-unused clkoutx2 functions are also removed at the same time. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/Makefile | 8 +- arch/arm/mach-omap2/clock.h | 4 - arch/arm/mach-omap2/clock3xxx.c | 77 ---- arch/arm/mach-omap2/dpll3xxx.c | 818 --------------------------------------- drivers/clk/ti/Makefile | 14 +- drivers/clk/ti/clk-3xxx.c | 31 ++ drivers/clk/ti/clock.h | 27 ++ drivers/clk/ti/dpll3xxx.c | 825 ++++++++++++++++++++++++++++++++++++++++ include/linux/clk/ti.h | 30 -- 9 files changed, 893 insertions(+), 941 deletions(-) delete mode 100644 arch/arm/mach-omap2/dpll3xxx.c create mode 100644 drivers/clk/ti/dpll3xxx.c (limited to 'drivers') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index bf5d71d9fd2b..f9d4ccf39cea 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -189,15 +189,11 @@ obj-$(CONFIG_SOC_OMAP2430) += clock2430.o obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o obj-$(CONFIG_ARCH_OMAP3) += clock3517.o -obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) -obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o -obj-$(CONFIG_SOC_AM33XX) += $(clock-common) dpll3xxx.o +obj-$(CONFIG_SOC_AM33XX) += $(clock-common) obj-$(CONFIG_SOC_OMAP5) += $(clock-common) -obj-$(CONFIG_SOC_OMAP5) += dpll3xxx.o obj-$(CONFIG_SOC_DRA7XX) += $(clock-common) -obj-$(CONFIG_SOC_DRA7XX) += dpll3xxx.o -obj-$(CONFIG_SOC_AM43XX) += $(clock-common) dpll3xxx.o +obj-$(CONFIG_SOC_AM43XX) += $(clock-common) # OMAP2 clock rate set data (old "OPP" data) obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index e2781b4aaeb4..d60691d5626a 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -180,10 +180,6 @@ struct clksel { #define OMAP4XXX_EN_DPLL_FRBYPASS 0x6 #define OMAP4XXX_EN_DPLL_LOCKED 0x7 -u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk); -void omap3_dpll_allow_idle(struct clk_hw_omap *clk); -void omap3_dpll_deny_idle(struct clk_hw_omap *clk); - void __init omap2_clk_disable_clkdm_control(void); void omap2_clk_print_new_rates(const char *hfclkin_ck_name, diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c index 4bd61222aa33..0b0e3a8777d3 100644 --- a/arch/arm/mach-omap2/clock3xxx.c +++ b/arch/arm/mach-omap2/clock3xxx.c @@ -29,82 +29,5 @@ #include "cm2xxx_3xxx.h" #include "cm-regbits-34xx.h" -/* - * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks - * that are sourced by DPLL5, and both of these require this clock - * to be at 120 MHz for proper operation. - */ -#define DPLL5_FREQ_FOR_USBHOST 120000000 - /* needed by omap3_core_dpll_m2_set_rate() */ struct clk *sdrc_ick_p, *arm_fck_p; - -/** - * omap3_dpll4_set_rate - set rate for omap3 per-dpll - * @hw: clock to change - * @rate: target rate for clock - * @parent_rate: rate of the parent clock - * - * Check if the current SoC supports the per-dpll reprogram operation - * or not, and then do the rate change if supported. Returns -EINVAL - * if not supported, 0 for success, and potential error codes from the - * clock rate change. - */ -int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - /* - * According to the 12-5 CDP code from TI, "Limitation 2.5" - * on 3430ES1 prevents us from changing DPLL multipliers or dividers - * on DPLL4. - */ - if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) { - pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); - return -EINVAL; - } - - return omap3_noncore_dpll_set_rate(hw, rate, parent_rate); -} - -/** - * omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll - * @hw: clock to change - * @rate: target rate for clock - * @parent_rate: rate of the parent clock - * @index: parent index, 0 - reference clock, 1 - bypass clock - * - * Check if the current SoC support the per-dpll reprogram operation - * or not, and then do the rate + parent change if supported. Returns - * -EINVAL if not supported, 0 for success, and potential error codes - * from the clock rate change. - */ -int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate, u8 index) -{ - if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) { - pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); - return -EINVAL; - } - - return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate, - index); -} - -void __init omap3_clk_lock_dpll5(void) -{ - struct clk *dpll5_clk; - struct clk *dpll5_m2_clk; - - dpll5_clk = clk_get(NULL, "dpll5_ck"); - clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST); - clk_prepare_enable(dpll5_clk); - - /* Program dpll5_m2_clk divider for no division */ - dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck"); - clk_prepare_enable(dpll5_m2_clk); - clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST); - - clk_disable_unprepare(dpll5_m2_clk); - clk_disable_unprepare(dpll5_clk); - return; -} diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c deleted file mode 100644 index 9a80f593ed15..000000000000 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ /dev/null @@ -1,818 +0,0 @@ -/* - * OMAP3/4 - specific DPLL control functions - * - * Copyright (C) 2009-2010 Texas Instruments, Inc. - * Copyright (C) 2009-2010 Nokia Corporation - * - * Written by Paul Walmsley - * Testing and integration fixes by Jouni Högander - * - * 36xx support added by Vishwanath BS, Richard Woodruff, and Nishanth - * Menon - * - * Parts of this code are based on code written by - * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu - * - * 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 "clockdomain.h" -#include "clock.h" - -/* CM_AUTOIDLE_PLL*.AUTO_* bit values */ -#define DPLL_AUTOIDLE_DISABLE 0x0 -#define DPLL_AUTOIDLE_LOW_POWER_STOP 0x1 - -#define MAX_DPLL_WAIT_TRIES 1000000 - -/* Private functions */ - -/* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */ -static void _omap3_dpll_write_clken(struct clk_hw_omap *clk, u8 clken_bits) -{ - const struct dpll_data *dd; - u32 v; - - dd = clk->dpll_data; - - v = omap2_clk_readl(clk, dd->control_reg); - v &= ~dd->enable_mask; - v |= clken_bits << __ffs(dd->enable_mask); - omap2_clk_writel(v, clk, dd->control_reg); -} - -/* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */ -static int _omap3_wait_dpll_status(struct clk_hw_omap *clk, u8 state) -{ - const struct dpll_data *dd; - int i = 0; - int ret = -EINVAL; - const char *clk_name; - - dd = clk->dpll_data; - clk_name = __clk_get_name(clk->hw.clk); - - state <<= __ffs(dd->idlest_mask); - - while (((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask) - != state) && i < MAX_DPLL_WAIT_TRIES) { - i++; - udelay(1); - } - - if (i == MAX_DPLL_WAIT_TRIES) { - printk(KERN_ERR "clock: %s failed transition to '%s'\n", - clk_name, (state) ? "locked" : "bypassed"); - } else { - pr_debug("clock: %s transition to '%s' in %d loops\n", - clk_name, (state) ? "locked" : "bypassed", i); - - ret = 0; - } - - return ret; -} - -/* From 3430 TRM ES2 4.7.6.2 */ -static u16 _omap3_dpll_compute_freqsel(struct clk_hw_omap *clk, u8 n) -{ - unsigned long fint; - u16 f = 0; - - fint = __clk_get_rate(clk->dpll_data->clk_ref) / n; - - pr_debug("clock: fint is %lu\n", fint); - - if (fint >= 750000 && fint <= 1000000) - f = 0x3; - else if (fint > 1000000 && fint <= 1250000) - f = 0x4; - else if (fint > 1250000 && fint <= 1500000) - f = 0x5; - else if (fint > 1500000 && fint <= 1750000) - f = 0x6; - else if (fint > 1750000 && fint <= 2100000) - f = 0x7; - else if (fint > 7500000 && fint <= 10000000) - f = 0xB; - else if (fint > 10000000 && fint <= 12500000) - f = 0xC; - else if (fint > 12500000 && fint <= 15000000) - f = 0xD; - else if (fint > 15000000 && fint <= 17500000) - f = 0xE; - else if (fint > 17500000 && fint <= 21000000) - f = 0xF; - else - pr_debug("clock: unknown freqsel setting for %d\n", n); - - return f; -} - -/* - * _omap3_noncore_dpll_lock - instruct a DPLL to lock and wait for readiness - * @clk: pointer to a DPLL struct clk - * - * Instructs a non-CORE DPLL to lock. Waits for the DPLL to report - * readiness before returning. Will save and restore the DPLL's - * autoidle state across the enable, per the CDP code. If the DPLL - * locked successfully, return 0; if the DPLL did not lock in the time - * allotted, or DPLL3 was passed in, return -EINVAL. - */ -static int _omap3_noncore_dpll_lock(struct clk_hw_omap *clk) -{ - const struct dpll_data *dd; - u8 ai; - u8 state = 1; - int r = 0; - - pr_debug("clock: locking DPLL %s\n", __clk_get_name(clk->hw.clk)); - - dd = clk->dpll_data; - state <<= __ffs(dd->idlest_mask); - - /* Check if already locked */ - if ((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask) == state) - goto done; - - ai = omap3_dpll_autoidle_read(clk); - - if (ai) - omap3_dpll_deny_idle(clk); - - _omap3_dpll_write_clken(clk, DPLL_LOCKED); - - r = _omap3_wait_dpll_status(clk, 1); - - if (ai) - omap3_dpll_allow_idle(clk); - -done: - return r; -} - -/* - * _omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness - * @clk: pointer to a DPLL struct clk - * - * Instructs a non-CORE DPLL to enter low-power bypass mode. In - * bypass mode, the DPLL's rate is set equal to its parent clock's - * rate. Waits for the DPLL to report readiness before returning. - * Will save and restore the DPLL's autoidle state across the enable, - * per the CDP code. If the DPLL entered bypass mode successfully, - * return 0; if the DPLL did not enter bypass in the time allotted, or - * DPLL3 was passed in, or the DPLL does not support low-power bypass, - * return -EINVAL. - */ -static int _omap3_noncore_dpll_bypass(struct clk_hw_omap *clk) -{ - int r; - u8 ai; - - if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) - return -EINVAL; - - pr_debug("clock: configuring DPLL %s for low-power bypass\n", - __clk_get_name(clk->hw.clk)); - - ai = omap3_dpll_autoidle_read(clk); - - _omap3_dpll_write_clken(clk, DPLL_LOW_POWER_BYPASS); - - r = _omap3_wait_dpll_status(clk, 0); - - if (ai) - omap3_dpll_allow_idle(clk); - - return r; -} - -/* - * _omap3_noncore_dpll_stop - instruct a DPLL to stop - * @clk: pointer to a DPLL struct clk - * - * Instructs a non-CORE DPLL to enter low-power stop. Will save and - * restore the DPLL's autoidle state across the stop, per the CDP - * code. If DPLL3 was passed in, or the DPLL does not support - * low-power stop, return -EINVAL; otherwise, return 0. - */ -static int _omap3_noncore_dpll_stop(struct clk_hw_omap *clk) -{ - u8 ai; - - if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_STOP))) - return -EINVAL; - - pr_debug("clock: stopping DPLL %s\n", __clk_get_name(clk->hw.clk)); - - ai = omap3_dpll_autoidle_read(clk); - - _omap3_dpll_write_clken(clk, DPLL_LOW_POWER_STOP); - - if (ai) - omap3_dpll_allow_idle(clk); - - return 0; -} - -/** - * _lookup_dco - Lookup DCO used by j-type DPLL - * @clk: pointer to a DPLL struct clk - * @dco: digital control oscillator selector - * @m: DPLL multiplier to set - * @n: DPLL divider to set - * - * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)" - * - * XXX This code is not needed for 3430/AM35xx; can it be optimized - * out in non-multi-OMAP builds for those chips? - */ -static void _lookup_dco(struct clk_hw_omap *clk, u8 *dco, u16 m, u8 n) -{ - unsigned long fint, clkinp; /* watch out for overflow */ - - clkinp = __clk_get_rate(__clk_get_parent(clk->hw.clk)); - fint = (clkinp / n) * m; - - if (fint < 1000000000) - *dco = 2; - else - *dco = 4; -} - -/** - * _lookup_sddiv - Calculate sigma delta divider for j-type DPLL - * @clk: pointer to a DPLL struct clk - * @sd_div: target sigma-delta divider - * @m: DPLL multiplier to set - * @n: DPLL divider to set - * - * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)" - * - * XXX This code is not needed for 3430/AM35xx; can it be optimized - * out in non-multi-OMAP builds for those chips? - */ -static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n) -{ - unsigned long clkinp, sd; /* watch out for overflow */ - int mod1, mod2; - - clkinp = __clk_get_rate(__clk_get_parent(clk->hw.clk)); - - /* - * target sigma-delta to near 250MHz - * sd = ceil[(m/(n+1)) * (clkinp_MHz / 250)] - */ - clkinp /= 100000; /* shift from MHz to 10*Hz for 38.4 and 19.2 */ - mod1 = (clkinp * m) % (250 * n); - sd = (clkinp * m) / (250 * n); - mod2 = sd % 10; - sd /= 10; - - if (mod1 || mod2) - sd++; - *sd_div = sd; -} - -/* - * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly - * @clk: struct clk * of DPLL to set - * @freqsel: FREQSEL value to set - * - * Program the DPLL with the last M, N values calculated, and wait for - * the DPLL to lock. Returns -EINVAL upon error, or 0 upon success. - */ -static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) -{ - struct dpll_data *dd = clk->dpll_data; - u8 dco, sd_div; - u32 v; - - /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ - _omap3_noncore_dpll_bypass(clk); - - /* - * Set jitter correction. Jitter correction applicable for OMAP343X - * only since freqsel field is no longer present on other devices. - */ - if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) { - v = omap2_clk_readl(clk, dd->control_reg); - v &= ~dd->freqsel_mask; - v |= freqsel << __ffs(dd->freqsel_mask); - omap2_clk_writel(v, clk, dd->control_reg); - } - - /* Set DPLL multiplier, divider */ - v = omap2_clk_readl(clk, dd->mult_div1_reg); - - /* Handle Duty Cycle Correction */ - if (dd->dcc_mask) { - if (dd->last_rounded_rate >= dd->dcc_rate) - v |= dd->dcc_mask; /* Enable DCC */ - else - v &= ~dd->dcc_mask; /* Disable DCC */ - } - - v &= ~(dd->mult_mask | dd->div1_mask); - v |= dd->last_rounded_m << __ffs(dd->mult_mask); - v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask); - - /* Configure dco and sd_div for dplls that have these fields */ - if (dd->dco_mask) { - _lookup_dco(clk, &dco, dd->last_rounded_m, dd->last_rounded_n); - v &= ~(dd->dco_mask); - v |= dco << __ffs(dd->dco_mask); - } - if (dd->sddiv_mask) { - _lookup_sddiv(clk, &sd_div, dd->last_rounded_m, - dd->last_rounded_n); - v &= ~(dd->sddiv_mask); - v |= sd_div << __ffs(dd->sddiv_mask); - } - - omap2_clk_writel(v, clk, dd->mult_div1_reg); - - /* Set 4X multiplier and low-power mode */ - if (dd->m4xen_mask || dd->lpmode_mask) { - v = omap2_clk_readl(clk, dd->control_reg); - - if (dd->m4xen_mask) { - if (dd->last_rounded_m4xen) - v |= dd->m4xen_mask; - else - v &= ~dd->m4xen_mask; - } - - if (dd->lpmode_mask) { - if (dd->last_rounded_lpmode) - v |= dd->lpmode_mask; - else - v &= ~dd->lpmode_mask; - } - - omap2_clk_writel(v, clk, dd->control_reg); - } - - /* We let the clock framework set the other output dividers later */ - - /* REVISIT: Set ramp-up delay? */ - - _omap3_noncore_dpll_lock(clk); - - return 0; -} - -/* Public functions */ - -/** - * omap3_dpll_recalc - recalculate DPLL rate - * @clk: DPLL struct clk - * - * Recalculate and propagate the DPLL rate. - */ -unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - - return omap2_get_dpll_rate(clk); -} - -/* Non-CORE DPLL (e.g., DPLLs that do not control SDRC) clock functions */ - -/** - * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode - * @clk: pointer to a DPLL struct clk - * - * Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock. - * The choice of modes depends on the DPLL's programmed rate: if it is - * the same as the DPLL's parent clock, it will enter bypass; - * otherwise, it will enter lock. This code will wait for the DPLL to - * indicate readiness before returning, unless the DPLL takes too long - * to enter the target state. Intended to be used as the struct clk's - * enable function. If DPLL3 was passed in, or the DPLL does not - * support low-power stop, or if the DPLL took too long to enter - * bypass or lock, return -EINVAL; otherwise, return 0. - */ -int omap3_noncore_dpll_enable(struct clk_hw *hw) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - int r; - struct dpll_data *dd; - struct clk_hw *parent; - - dd = clk->dpll_data; - if (!dd) - return -EINVAL; - - if (clk->clkdm) { - r = clkdm_clk_enable(clk->clkdm, hw->clk); - if (r) { - WARN(1, - "%s: could not enable %s's clockdomain %s: %d\n", - __func__, __clk_get_name(hw->clk), - clk->clkdm->name, r); - return r; - } - } - - parent = __clk_get_hw(__clk_get_parent(hw->clk)); - - if (__clk_get_rate(hw->clk) == __clk_get_rate(dd->clk_bypass)) { - WARN_ON(parent != __clk_get_hw(dd->clk_bypass)); - r = _omap3_noncore_dpll_bypass(clk); - } else { - WARN_ON(parent != __clk_get_hw(dd->clk_ref)); - r = _omap3_noncore_dpll_lock(clk); - } - - return r; -} - -/** - * omap3_noncore_dpll_disable - instruct a DPLL to enter low-power stop - * @clk: pointer to a DPLL struct clk - * - * Instructs a non-CORE DPLL to enter low-power stop. This function is - * intended for use in struct clkops. No return value. - */ -void omap3_noncore_dpll_disable(struct clk_hw *hw) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - - _omap3_noncore_dpll_stop(clk); - if (clk->clkdm) - clkdm_clk_disable(clk->clkdm, hw->clk); -} - - -/* Non-CORE DPLL rate set code */ - -/** - * omap3_noncore_dpll_determine_rate - determine rate for a DPLL - * @hw: pointer to the clock to determine rate for - * @rate: target rate for the DPLL - * @best_parent_rate: pointer for returning best parent rate - * @best_parent_clk: pointer for returning best parent clock - * - * Determines which DPLL mode to use for reaching a desired target rate. - * Checks whether the DPLL shall be in bypass or locked mode, and if - * locked, calculates the M,N values for the DPLL via round-rate. - * Returns a positive clock rate with success, negative error value - * in failure. - */ -long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - struct dpll_data *dd; - - if (!hw || !rate) - return -EINVAL; - - dd = clk->dpll_data; - if (!dd) - return -EINVAL; - - if (__clk_get_rate(dd->clk_bypass) == rate && - (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - *best_parent_clk = __clk_get_hw(dd->clk_bypass); - } else { - rate = omap2_dpll_round_rate(hw, rate, best_parent_rate); - *best_parent_clk = __clk_get_hw(dd->clk_ref); - } - - *best_parent_rate = rate; - - return rate; -} - -/** - * omap3_noncore_dpll_set_parent - set parent for a DPLL clock - * @hw: pointer to the clock to set parent for - * @index: parent index to select - * - * Sets parent for a DPLL clock. This sets the DPLL into bypass or - * locked mode. Returns 0 with success, negative error value otherwise. - */ -int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - int ret; - - if (!hw) - return -EINVAL; - - if (index) - ret = _omap3_noncore_dpll_bypass(clk); - else - ret = _omap3_noncore_dpll_lock(clk); - - return ret; -} - -/** - * omap3_noncore_dpll_set_rate - set rate for a DPLL clock - * @hw: pointer to the clock to set parent for - * @rate: target rate for the clock - * @parent_rate: rate of the parent clock - * - * Sets rate for a DPLL clock. First checks if the clock parent is - * reference clock (in bypass mode, the rate of the clock can't be - * changed) and proceeds with the rate change operation. Returns 0 - * with success, negative error value otherwise. - */ -int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - struct dpll_data *dd; - u16 freqsel = 0; - int ret; - - if (!hw || !rate) - return -EINVAL; - - dd = clk->dpll_data; - if (!dd) - return -EINVAL; - - if (__clk_get_hw(__clk_get_parent(hw->clk)) != - __clk_get_hw(dd->clk_ref)) - return -EINVAL; - - if (dd->last_rounded_rate == 0) - return -EINVAL; - - /* Freqsel is available only on OMAP343X devices */ - if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) { - freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); - WARN_ON(!freqsel); - } - - pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__, - __clk_get_name(hw->clk), rate); - - ret = omap3_noncore_dpll_program(clk, freqsel); - - return ret; -} - -/** - * omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock - * @hw: pointer to the clock to set rate and parent for - * @rate: target rate for the DPLL - * @parent_rate: clock rate of the DPLL parent - * @index: new parent index for the DPLL, 0 - reference, 1 - bypass - * - * Sets rate and parent for a DPLL clock. If new parent is the bypass - * clock, only selects the parent. Otherwise proceeds with a rate - * change, as this will effectively also change the parent as the - * DPLL is put into locked mode. Returns 0 with success, negative error - * value otherwise. - */ -int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate, - u8 index) -{ - int ret; - - if (!hw || !rate) - return -EINVAL; - - /* - * clk-ref at index[0], in which case we only need to set rate, - * the parent will be changed automatically with the lock sequence. - * With clk-bypass case we only need to change parent. - */ - if (index) - ret = omap3_noncore_dpll_set_parent(hw, index); - else - ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate); - - return ret; -} - -/* DPLL autoidle read/set code */ - -/** - * omap3_dpll_autoidle_read - read a DPLL's autoidle bits - * @clk: struct clk * of the DPLL to read - * - * Return the DPLL's autoidle bits, shifted down to bit 0. Returns - * -EINVAL if passed a null pointer or if the struct clk does not - * appear to refer to a DPLL. - */ -u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk) -{ - const struct dpll_data *dd; - u32 v; - - if (!clk || !clk->dpll_data) - return -EINVAL; - - dd = clk->dpll_data; - - if (!dd->autoidle_reg) - return -EINVAL; - - v = omap2_clk_readl(clk, dd->autoidle_reg); - v &= dd->autoidle_mask; - v >>= __ffs(dd->autoidle_mask); - - return v; -} - -/** - * omap3_dpll_allow_idle - enable DPLL autoidle bits - * @clk: struct clk * of the DPLL to operate on - * - * Enable DPLL automatic idle control. This automatic idle mode - * switching takes effect only when the DPLL is locked, at least on - * OMAP3430. The DPLL will enter low-power stop when its downstream - * clocks are gated. No return value. - */ -void omap3_dpll_allow_idle(struct clk_hw_omap *clk) -{ - const struct dpll_data *dd; - u32 v; - - if (!clk || !clk->dpll_data) - return; - - dd = clk->dpll_data; - - if (!dd->autoidle_reg) - return; - - /* - * REVISIT: CORE DPLL can optionally enter low-power bypass - * by writing 0x5 instead of 0x1. Add some mechanism to - * optionally enter this mode. - */ - v = omap2_clk_readl(clk, dd->autoidle_reg); - v &= ~dd->autoidle_mask; - v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask); - omap2_clk_writel(v, clk, dd->autoidle_reg); - -} - -/** - * omap3_dpll_deny_idle - prevent DPLL from automatically idling - * @clk: struct clk * of the DPLL to operate on - * - * Disable DPLL automatic idle control. No return value. - */ -void omap3_dpll_deny_idle(struct clk_hw_omap *clk) -{ - const struct dpll_data *dd; - u32 v; - - if (!clk || !clk->dpll_data) - return; - - dd = clk->dpll_data; - - if (!dd->autoidle_reg) - return; - - v = omap2_clk_readl(clk, dd->autoidle_reg); - v &= ~dd->autoidle_mask; - v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask); - omap2_clk_writel(v, clk, dd->autoidle_reg); - -} - -/* Clock control for DPLL outputs */ - -/* Find the parent DPLL for the given clkoutx2 clock */ -static struct clk_hw_omap *omap3_find_clkoutx2_dpll(struct clk_hw *hw) -{ - struct clk_hw_omap *pclk = NULL; - struct clk *parent; - - /* Walk up the parents of clk, looking for a DPLL */ - do { - do { - parent = __clk_get_parent(hw->clk); - hw = __clk_get_hw(parent); - } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC)); - if (!hw) - break; - pclk = to_clk_hw_omap(hw); - } while (pclk && !pclk->dpll_data); - - /* clk does not have a DPLL as a parent? error in the clock data */ - if (!pclk) { - WARN_ON(1); - return NULL; - } - - return pclk; -} - -/** - * omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate - * @clk: DPLL output struct clk - * - * Using parent clock DPLL data, look up DPLL state. If locked, set our - * rate to the dpll_clk * 2; otherwise, just use dpll_clk. - */ -unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, - unsigned long parent_rate) -{ - const struct dpll_data *dd; - unsigned long rate; - u32 v; - struct clk_hw_omap *pclk = NULL; - - if (!parent_rate) - return 0; - - pclk = omap3_find_clkoutx2_dpll(hw); - - if (!pclk) - return 0; - - dd = pclk->dpll_data; - - WARN_ON(!dd->enable_mask); - - v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask; - v >>= __ffs(dd->enable_mask); - if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE)) - rate = parent_rate; - else - rate = parent_rate * 2; - return rate; -} - -int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - return 0; -} - -long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - const struct dpll_data *dd; - u32 v; - struct clk_hw_omap *pclk = NULL; - - if (!*prate) - return 0; - - pclk = omap3_find_clkoutx2_dpll(hw); - - if (!pclk) - return 0; - - dd = pclk->dpll_data; - - /* TYPE J does not have a clkoutx2 */ - if (dd->flags & DPLL_J_TYPE) { - *prate = __clk_round_rate(__clk_get_parent(pclk->hw.clk), rate); - return *prate; - } - - WARN_ON(!dd->enable_mask); - - v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask; - v >>= __ffs(dd->enable_mask); - - /* If in bypass, the rate is fixed to the bypass rate*/ - if (v != OMAP3XXX_EN_DPLL_LOCKED) - return *prate; - - if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) { - unsigned long best_parent; - - best_parent = (rate / 2); - *prate = __clk_round_rate(__clk_get_parent(hw->clk), - best_parent); - } - - return *prate * 2; -} - -/* OMAP3/4 non-CORE DPLL clkops */ -const struct clk_hw_omap_ops clkhwops_omap3_dpll = { - .allow_idle = omap3_dpll_allow_idle, - .deny_idle = omap3_dpll_deny_idle, -}; diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index 23cd72638970..05a0294aba10 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile @@ -2,16 +2,18 @@ obj-y += clk.o autoidle.o clockdomain.o clk-common = dpll.o composite.o divider.o gate.o \ fixed-factor.o mux.o apll.o \ clkt_dpll.o clkt_iclk.o -obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o +obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o dpll3xxx.o obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \ - clk-3xxx.o -obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o dpll44xx.o -obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o dpll44xx.o + clk-3xxx.o dpll3xxx.o +obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o \ + dpll3xxx.o dpll44xx.o +obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o \ + dpll3xxx.o dpll44xx.o obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \ - clk-dra7-atl.o dpll44xx.o -obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o + clk-dra7-atl.o dpll3xxx.o dpll44xx.o +obj-$(CONFIG_SOC_AM43XX) += $(clk-common) dpll3xxx.o clk-43xx.o ifdef CONFIG_ATAGS obj-$(CONFIG_ARCH_OMAP3) += clk-3xxx-legacy.o diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c index bb3b88359daf..5489ad8c07d4 100644 --- a/drivers/clk/ti/clk-3xxx.c +++ b/drivers/clk/ti/clk-3xxx.c @@ -21,6 +21,13 @@ #include "clock.h" +/* + * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks + * that are sourced by DPLL5, and both of these require this clock + * to be at 120 MHz for proper operation. + */ +#define DPLL5_FREQ_FOR_USBHOST 120000000 + static struct ti_dt_clk omap3xxx_clks[] = { DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"), DT_CLK(NULL, "omap_32k_fck", "omap_32k_fck"), @@ -325,6 +332,30 @@ enum { OMAP3_SOC_OMAP3630, }; +/** + * omap3_clk_lock_dpll5 - locks DPLL5 + * + * Locks DPLL5 to a pre-defined frequency. This is required for proper + * operation of USB. + */ +void __init omap3_clk_lock_dpll5(void) +{ + struct clk *dpll5_clk; + struct clk *dpll5_m2_clk; + + dpll5_clk = clk_get(NULL, "dpll5_ck"); + clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST); + clk_prepare_enable(dpll5_clk); + + /* Program dpll5_m2_clk divider for no division */ + dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck"); + clk_prepare_enable(dpll5_m2_clk); + clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST); + + clk_disable_unprepare(dpll5_m2_clk); + clk_disable_unprepare(dpll5_clk); +} + static int __init omap3xxx_dt_clk_init(int soc_type) { if (soc_type == OMAP3_SOC_AM35XX || soc_type == OMAP3_SOC_OMAP3630 || diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 4b26af8a273d..688d9e47b2c8 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -173,11 +173,38 @@ void omap2_init_clk_hw_omap_clocks(struct clk *clk); int of_ti_clk_autoidle_setup(struct device_node *node); void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); +extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; extern const struct clk_hw_omap_ops clkhwops_iclk; extern const struct clk_hw_omap_ops clkhwops_iclk_wait; u8 omap2_init_dpll_parent(struct clk_hw *hw); +int omap3_noncore_dpll_enable(struct clk_hw *hw); +void omap3_noncore_dpll_disable(struct clk_hw *hw); +int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index); +int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index); +long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long min_rate, + unsigned long max_rate, + unsigned long *best_parent_rate, + struct clk_hw **best_parent_clk); +long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, + unsigned long *parent_rate); +unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, + unsigned long parent_rate); + +unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); +int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, + unsigned long parent_rate); +int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, u8 index); +void omap3_clk_lock_dpll5(void); unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, unsigned long parent_rate); diff --git a/drivers/clk/ti/dpll3xxx.c b/drivers/clk/ti/dpll3xxx.c new file mode 100644 index 000000000000..22d77a331287 --- /dev/null +++ b/drivers/clk/ti/dpll3xxx.c @@ -0,0 +1,825 @@ +/* + * OMAP3/4 - specific DPLL control functions + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * Copyright (C) 2009-2010 Nokia Corporation + * + * Written by Paul Walmsley + * Testing and integration fixes by Jouni Högander + * + * 36xx support added by Vishwanath BS, Richard Woodruff, and Nishanth + * Menon + * + * Parts of this code are based on code written by + * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu + * + * 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 "clock.h" + +/* CM_AUTOIDLE_PLL*.AUTO_* bit values */ +#define DPLL_AUTOIDLE_DISABLE 0x0 +#define DPLL_AUTOIDLE_LOW_POWER_STOP 0x1 + +#define MAX_DPLL_WAIT_TRIES 1000000 + +#define OMAP3XXX_EN_DPLL_LOCKED 0x7 + +/* Forward declarations */ +static u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk); +static void omap3_dpll_deny_idle(struct clk_hw_omap *clk); +static void omap3_dpll_allow_idle(struct clk_hw_omap *clk); + +/* Private functions */ + +/* _omap3_dpll_write_clken - write clken_bits arg to a DPLL's enable bits */ +static void _omap3_dpll_write_clken(struct clk_hw_omap *clk, u8 clken_bits) +{ + const struct dpll_data *dd; + u32 v; + + dd = clk->dpll_data; + + v = ti_clk_ll_ops->clk_readl(dd->control_reg); + v &= ~dd->enable_mask; + v |= clken_bits << __ffs(dd->enable_mask); + ti_clk_ll_ops->clk_writel(v, dd->control_reg); +} + +/* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */ +static int _omap3_wait_dpll_status(struct clk_hw_omap *clk, u8 state) +{ + const struct dpll_data *dd; + int i = 0; + int ret = -EINVAL; + const char *clk_name; + + dd = clk->dpll_data; + clk_name = __clk_get_name(clk->hw.clk); + + state <<= __ffs(dd->idlest_mask); + + while (((ti_clk_ll_ops->clk_readl(dd->idlest_reg) & dd->idlest_mask) + != state) && i < MAX_DPLL_WAIT_TRIES) { + i++; + udelay(1); + } + + if (i == MAX_DPLL_WAIT_TRIES) { + pr_err("clock: %s failed transition to '%s'\n", + clk_name, (state) ? "locked" : "bypassed"); + } else { + pr_debug("clock: %s transition to '%s' in %d loops\n", + clk_name, (state) ? "locked" : "bypassed", i); + + ret = 0; + } + + return ret; +} + +/* From 3430 TRM ES2 4.7.6.2 */ +static u16 _omap3_dpll_compute_freqsel(struct clk_hw_omap *clk, u8 n) +{ + unsigned long fint; + u16 f = 0; + + fint = __clk_get_rate(clk->dpll_data->clk_ref) / n; + + pr_debug("clock: fint is %lu\n", fint); + + if (fint >= 750000 && fint <= 1000000) + f = 0x3; + else if (fint > 1000000 && fint <= 1250000) + f = 0x4; + else if (fint > 1250000 && fint <= 1500000) + f = 0x5; + else if (fint > 1500000 && fint <= 1750000) + f = 0x6; + else if (fint > 1750000 && fint <= 2100000) + f = 0x7; + else if (fint > 7500000 && fint <= 10000000) + f = 0xB; + else if (fint > 10000000 && fint <= 12500000) + f = 0xC; + else if (fint > 12500000 && fint <= 15000000) + f = 0xD; + else if (fint > 15000000 && fint <= 17500000) + f = 0xE; + else if (fint > 17500000 && fint <= 21000000) + f = 0xF; + else + pr_debug("clock: unknown freqsel setting for %d\n", n); + + return f; +} + +/* + * _omap3_noncore_dpll_lock - instruct a DPLL to lock and wait for readiness + * @clk: pointer to a DPLL struct clk + * + * Instructs a non-CORE DPLL to lock. Waits for the DPLL to report + * readiness before returning. Will save and restore the DPLL's + * autoidle state across the enable, per the CDP code. If the DPLL + * locked successfully, return 0; if the DPLL did not lock in the time + * allotted, or DPLL3 was passed in, return -EINVAL. + */ +static int _omap3_noncore_dpll_lock(struct clk_hw_omap *clk) +{ + const struct dpll_data *dd; + u8 ai; + u8 state = 1; + int r = 0; + + pr_debug("clock: locking DPLL %s\n", __clk_get_name(clk->hw.clk)); + + dd = clk->dpll_data; + state <<= __ffs(dd->idlest_mask); + + /* Check if already locked */ + if ((ti_clk_ll_ops->clk_readl(dd->idlest_reg) & dd->idlest_mask) == + state) + goto done; + + ai = omap3_dpll_autoidle_read(clk); + + if (ai) + omap3_dpll_deny_idle(clk); + + _omap3_dpll_write_clken(clk, DPLL_LOCKED); + + r = _omap3_wait_dpll_status(clk, 1); + + if (ai) + omap3_dpll_allow_idle(clk); + +done: + return r; +} + +/* + * _omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness + * @clk: pointer to a DPLL struct clk + * + * Instructs a non-CORE DPLL to enter low-power bypass mode. In + * bypass mode, the DPLL's rate is set equal to its parent clock's + * rate. Waits for the DPLL to report readiness before returning. + * Will save and restore the DPLL's autoidle state across the enable, + * per the CDP code. If the DPLL entered bypass mode successfully, + * return 0; if the DPLL did not enter bypass in the time allotted, or + * DPLL3 was passed in, or the DPLL does not support low-power bypass, + * return -EINVAL. + */ +static int _omap3_noncore_dpll_bypass(struct clk_hw_omap *clk) +{ + int r; + u8 ai; + + if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) + return -EINVAL; + + pr_debug("clock: configuring DPLL %s for low-power bypass\n", + __clk_get_name(clk->hw.clk)); + + ai = omap3_dpll_autoidle_read(clk); + + _omap3_dpll_write_clken(clk, DPLL_LOW_POWER_BYPASS); + + r = _omap3_wait_dpll_status(clk, 0); + + if (ai) + omap3_dpll_allow_idle(clk); + + return r; +} + +/* + * _omap3_noncore_dpll_stop - instruct a DPLL to stop + * @clk: pointer to a DPLL struct clk + * + * Instructs a non-CORE DPLL to enter low-power stop. Will save and + * restore the DPLL's autoidle state across the stop, per the CDP + * code. If DPLL3 was passed in, or the DPLL does not support + * low-power stop, return -EINVAL; otherwise, return 0. + */ +static int _omap3_noncore_dpll_stop(struct clk_hw_omap *clk) +{ + u8 ai; + + if (!(clk->dpll_data->modes & (1 << DPLL_LOW_POWER_STOP))) + return -EINVAL; + + pr_debug("clock: stopping DPLL %s\n", __clk_get_name(clk->hw.clk)); + + ai = omap3_dpll_autoidle_read(clk); + + _omap3_dpll_write_clken(clk, DPLL_LOW_POWER_STOP); + + if (ai) + omap3_dpll_allow_idle(clk); + + return 0; +} + +/** + * _lookup_dco - Lookup DCO used by j-type DPLL + * @clk: pointer to a DPLL struct clk + * @dco: digital control oscillator selector + * @m: DPLL multiplier to set + * @n: DPLL divider to set + * + * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)" + * + * XXX This code is not needed for 3430/AM35xx; can it be optimized + * out in non-multi-OMAP builds for those chips? + */ +static void _lookup_dco(struct clk_hw_omap *clk, u8 *dco, u16 m, u8 n) +{ + unsigned long fint, clkinp; /* watch out for overflow */ + + clkinp = __clk_get_rate(__clk_get_parent(clk->hw.clk)); + fint = (clkinp / n) * m; + + if (fint < 1000000000) + *dco = 2; + else + *dco = 4; +} + +/** + * _lookup_sddiv - Calculate sigma delta divider for j-type DPLL + * @clk: pointer to a DPLL struct clk + * @sd_div: target sigma-delta divider + * @m: DPLL multiplier to set + * @n: DPLL divider to set + * + * See 36xx TRM section 3.5.3.3.3.2 "Type B DPLL (Low-Jitter)" + * + * XXX This code is not needed for 3430/AM35xx; can it be optimized + * out in non-multi-OMAP builds for those chips? + */ +static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n) +{ + unsigned long clkinp, sd; /* watch out for overflow */ + int mod1, mod2; + + clkinp = __clk_get_rate(__clk_get_parent(clk->hw.clk)); + + /* + * target sigma-delta to near 250MHz + * sd = ceil[(m/(n+1)) * (clkinp_MHz / 250)] + */ + clkinp /= 100000; /* shift from MHz to 10*Hz for 38.4 and 19.2 */ + mod1 = (clkinp * m) % (250 * n); + sd = (clkinp * m) / (250 * n); + mod2 = sd % 10; + sd /= 10; + + if (mod1 || mod2) + sd++; + *sd_div = sd; +} + +/* + * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly + * @clk: struct clk * of DPLL to set + * @freqsel: FREQSEL value to set + * + * Program the DPLL with the last M, N values calculated, and wait for + * the DPLL to lock. Returns -EINVAL upon error, or 0 upon success. + */ +static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel) +{ + struct dpll_data *dd = clk->dpll_data; + u8 dco, sd_div; + u32 v; + + /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */ + _omap3_noncore_dpll_bypass(clk); + + /* + * Set jitter correction. Jitter correction applicable for OMAP343X + * only since freqsel field is no longer present on other devices. + */ + if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) { + v = ti_clk_ll_ops->clk_readl(dd->control_reg); + v &= ~dd->freqsel_mask; + v |= freqsel << __ffs(dd->freqsel_mask); + ti_clk_ll_ops->clk_writel(v, dd->control_reg); + } + + /* Set DPLL multiplier, divider */ + v = ti_clk_ll_ops->clk_readl(dd->mult_div1_reg); + + /* Handle Duty Cycle Correction */ + if (dd->dcc_mask) { + if (dd->last_rounded_rate >= dd->dcc_rate) + v |= dd->dcc_mask; /* Enable DCC */ + else + v &= ~dd->dcc_mask; /* Disable DCC */ + } + + v &= ~(dd->mult_mask | dd->div1_mask); + v |= dd->last_rounded_m << __ffs(dd->mult_mask); + v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask); + + /* Configure dco and sd_div for dplls that have these fields */ + if (dd->dco_mask) { + _lookup_dco(clk, &dco, dd->last_rounded_m, dd->last_rounded_n); + v &= ~(dd->dco_mask); + v |= dco << __ffs(dd->dco_mask); + } + if (dd->sddiv_mask) { + _lookup_sddiv(clk, &sd_div, dd->last_rounded_m, + dd->last_rounded_n); + v &= ~(dd->sddiv_mask); + v |= sd_div << __ffs(dd->sddiv_mask); + } + + ti_clk_ll_ops->clk_writel(v, dd->mult_div1_reg); + + /* Set 4X multiplier and low-power mode */ + if (dd->m4xen_mask || dd->lpmode_mask) { + v = ti_clk_ll_ops->clk_readl(dd->control_reg); + + if (dd->m4xen_mask) { + if (dd->last_rounded_m4xen) + v |= dd->m4xen_mask; + else + v &= ~dd->m4xen_mask; + } + + if (dd->lpmode_mask) { + if (dd->last_rounded_lpmode) + v |= dd->lpmode_mask; + else + v &= ~dd->lpmode_mask; + } + + ti_clk_ll_ops->clk_writel(v, dd->control_reg); + } + + /* We let the clock framework set the other output dividers later */ + + /* REVISIT: Set ramp-up delay? */ + + _omap3_noncore_dpll_lock(clk); + + return 0; +} + +/* Public functions */ + +/** + * omap3_dpll_recalc - recalculate DPLL rate + * @clk: DPLL struct clk + * + * Recalculate and propagate the DPLL rate. + */ +unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + + return omap2_get_dpll_rate(clk); +} + +/* Non-CORE DPLL (e.g., DPLLs that do not control SDRC) clock functions */ + +/** + * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode + * @clk: pointer to a DPLL struct clk + * + * Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock. + * The choice of modes depends on the DPLL's programmed rate: if it is + * the same as the DPLL's parent clock, it will enter bypass; + * otherwise, it will enter lock. This code will wait for the DPLL to + * indicate readiness before returning, unless the DPLL takes too long + * to enter the target state. Intended to be used as the struct clk's + * enable function. If DPLL3 was passed in, or the DPLL does not + * support low-power stop, or if the DPLL took too long to enter + * bypass or lock, return -EINVAL; otherwise, return 0. + */ +int omap3_noncore_dpll_enable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + int r; + struct dpll_data *dd; + struct clk_hw *parent; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + if (clk->clkdm) { + r = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk); + if (r) { + WARN(1, + "%s: could not enable %s's clockdomain %s: %d\n", + __func__, __clk_get_name(hw->clk), + clk->clkdm_name, r); + return r; + } + } + + parent = __clk_get_hw(__clk_get_parent(hw->clk)); + + if (__clk_get_rate(hw->clk) == __clk_get_rate(dd->clk_bypass)) { + WARN_ON(parent != __clk_get_hw(dd->clk_bypass)); + r = _omap3_noncore_dpll_bypass(clk); + } else { + WARN_ON(parent != __clk_get_hw(dd->clk_ref)); + r = _omap3_noncore_dpll_lock(clk); + } + + return r; +} + +/** + * omap3_noncore_dpll_disable - instruct a DPLL to enter low-power stop + * @clk: pointer to a DPLL struct clk + * + * Instructs a non-CORE DPLL to enter low-power stop. This function is + * intended for use in struct clkops. No return value. + */ +void omap3_noncore_dpll_disable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + + _omap3_noncore_dpll_stop(clk); + if (clk->clkdm) + ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); +} + +/* Non-CORE DPLL rate set code */ + +/** + * omap3_noncore_dpll_determine_rate - determine rate for a DPLL + * @hw: pointer to the clock to determine rate for + * @rate: target rate for the DPLL + * @best_parent_rate: pointer for returning best parent rate + * @best_parent_clk: pointer for returning best parent clock + * + * Determines which DPLL mode to use for reaching a desired target rate. + * Checks whether the DPLL shall be in bypass or locked mode, and if + * locked, calculates the M,N values for the DPLL via round-rate. + * Returns a positive clock rate with success, negative error value + * in failure. + */ +long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long min_rate, + unsigned long max_rate, + unsigned long *best_parent_rate, + struct clk_hw **best_parent_clk) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + + if (!hw || !rate) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + if (__clk_get_rate(dd->clk_bypass) == rate && + (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { + *best_parent_clk = __clk_get_hw(dd->clk_bypass); + } else { + rate = omap2_dpll_round_rate(hw, rate, best_parent_rate); + *best_parent_clk = __clk_get_hw(dd->clk_ref); + } + + *best_parent_rate = rate; + + return rate; +} + +/** + * omap3_noncore_dpll_set_parent - set parent for a DPLL clock + * @hw: pointer to the clock to set parent for + * @index: parent index to select + * + * Sets parent for a DPLL clock. This sets the DPLL into bypass or + * locked mode. Returns 0 with success, negative error value otherwise. + */ +int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + int ret; + + if (!hw) + return -EINVAL; + + if (index) + ret = _omap3_noncore_dpll_bypass(clk); + else + ret = _omap3_noncore_dpll_lock(clk); + + return ret; +} + +/** + * omap3_noncore_dpll_set_rate - set rate for a DPLL clock + * @hw: pointer to the clock to set parent for + * @rate: target rate for the clock + * @parent_rate: rate of the parent clock + * + * Sets rate for a DPLL clock. First checks if the clock parent is + * reference clock (in bypass mode, the rate of the clock can't be + * changed) and proceeds with the rate change operation. Returns 0 + * with success, negative error value otherwise. + */ +int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + struct dpll_data *dd; + u16 freqsel = 0; + int ret; + + if (!hw || !rate) + return -EINVAL; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + if (__clk_get_hw(__clk_get_parent(hw->clk)) != + __clk_get_hw(dd->clk_ref)) + return -EINVAL; + + if (dd->last_rounded_rate == 0) + return -EINVAL; + + /* Freqsel is available only on OMAP343X devices */ + if (ti_clk_get_features()->flags & TI_CLK_DPLL_HAS_FREQSEL) { + freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n); + WARN_ON(!freqsel); + } + + pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__, + __clk_get_name(hw->clk), rate); + + ret = omap3_noncore_dpll_program(clk, freqsel); + + return ret; +} + +/** + * omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock + * @hw: pointer to the clock to set rate and parent for + * @rate: target rate for the DPLL + * @parent_rate: clock rate of the DPLL parent + * @index: new parent index for the DPLL, 0 - reference, 1 - bypass + * + * Sets rate and parent for a DPLL clock. If new parent is the bypass + * clock, only selects the parent. Otherwise proceeds with a rate + * change, as this will effectively also change the parent as the + * DPLL is put into locked mode. Returns 0 with success, negative error + * value otherwise. + */ +int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate, + u8 index) +{ + int ret; + + if (!hw || !rate) + return -EINVAL; + + /* + * clk-ref at index[0], in which case we only need to set rate, + * the parent will be changed automatically with the lock sequence. + * With clk-bypass case we only need to change parent. + */ + if (index) + ret = omap3_noncore_dpll_set_parent(hw, index); + else + ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate); + + return ret; +} + +/* DPLL autoidle read/set code */ + +/** + * omap3_dpll_autoidle_read - read a DPLL's autoidle bits + * @clk: struct clk * of the DPLL to read + * + * Return the DPLL's autoidle bits, shifted down to bit 0. Returns + * -EINVAL if passed a null pointer or if the struct clk does not + * appear to refer to a DPLL. + */ +static u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk) +{ + const struct dpll_data *dd; + u32 v; + + if (!clk || !clk->dpll_data) + return -EINVAL; + + dd = clk->dpll_data; + + if (!dd->autoidle_reg) + return -EINVAL; + + v = ti_clk_ll_ops->clk_readl(dd->autoidle_reg); + v &= dd->autoidle_mask; + v >>= __ffs(dd->autoidle_mask); + + return v; +} + +/** + * omap3_dpll_allow_idle - enable DPLL autoidle bits + * @clk: struct clk * of the DPLL to operate on + * + * Enable DPLL automatic idle control. This automatic idle mode + * switching takes effect only when the DPLL is locked, at least on + * OMAP3430. The DPLL will enter low-power stop when its downstream + * clocks are gated. No return value. + */ +static void omap3_dpll_allow_idle(struct clk_hw_omap *clk) +{ + const struct dpll_data *dd; + u32 v; + + if (!clk || !clk->dpll_data) + return; + + dd = clk->dpll_data; + + if (!dd->autoidle_reg) + return; + + /* + * REVISIT: CORE DPLL can optionally enter low-power bypass + * by writing 0x5 instead of 0x1. Add some mechanism to + * optionally enter this mode. + */ + v = ti_clk_ll_ops->clk_readl(dd->autoidle_reg); + v &= ~dd->autoidle_mask; + v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask); + ti_clk_ll_ops->clk_writel(v, dd->autoidle_reg); +} + +/** + * omap3_dpll_deny_idle - prevent DPLL from automatically idling + * @clk: struct clk * of the DPLL to operate on + * + * Disable DPLL automatic idle control. No return value. + */ +static void omap3_dpll_deny_idle(struct clk_hw_omap *clk) +{ + const struct dpll_data *dd; + u32 v; + + if (!clk || !clk->dpll_data) + return; + + dd = clk->dpll_data; + + if (!dd->autoidle_reg) + return; + + v = ti_clk_ll_ops->clk_readl(dd->autoidle_reg); + v &= ~dd->autoidle_mask; + v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask); + ti_clk_ll_ops->clk_writel(v, dd->autoidle_reg); +} + +/* Clock control for DPLL outputs */ + +/* Find the parent DPLL for the given clkoutx2 clock */ +static struct clk_hw_omap *omap3_find_clkoutx2_dpll(struct clk_hw *hw) +{ + struct clk_hw_omap *pclk = NULL; + struct clk *parent; + + /* Walk up the parents of clk, looking for a DPLL */ + do { + do { + parent = __clk_get_parent(hw->clk); + hw = __clk_get_hw(parent); + } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC)); + if (!hw) + break; + pclk = to_clk_hw_omap(hw); + } while (pclk && !pclk->dpll_data); + + /* clk does not have a DPLL as a parent? error in the clock data */ + if (!pclk) { + WARN_ON(1); + return NULL; + } + + return pclk; +} + +/** + * omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate + * @clk: DPLL output struct clk + * + * Using parent clock DPLL data, look up DPLL state. If locked, set our + * rate to the dpll_clk * 2; otherwise, just use dpll_clk. + */ +unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + const struct dpll_data *dd; + unsigned long rate; + u32 v; + struct clk_hw_omap *pclk = NULL; + + if (!parent_rate) + return 0; + + pclk = omap3_find_clkoutx2_dpll(hw); + + if (!pclk) + return 0; + + dd = pclk->dpll_data; + + WARN_ON(!dd->enable_mask); + + v = ti_clk_ll_ops->clk_readl(dd->control_reg) & dd->enable_mask; + v >>= __ffs(dd->enable_mask); + if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE)) + rate = parent_rate; + else + rate = parent_rate * 2; + return rate; +} + +/* OMAP3/4 non-CORE DPLL clkops */ +const struct clk_hw_omap_ops clkhwops_omap3_dpll = { + .allow_idle = omap3_dpll_allow_idle, + .deny_idle = omap3_dpll_deny_idle, +}; + +/** + * omap3_dpll4_set_rate - set rate for omap3 per-dpll + * @hw: clock to change + * @rate: target rate for clock + * @parent_rate: rate of the parent clock + * + * Check if the current SoC supports the per-dpll reprogram operation + * or not, and then do the rate change if supported. Returns -EINVAL + * if not supported, 0 for success, and potential error codes from the + * clock rate change. + */ +int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + /* + * According to the 12-5 CDP code from TI, "Limitation 2.5" + * on 3430ES1 prevents us from changing DPLL multipliers or dividers + * on DPLL4. + */ + if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) { + pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); + return -EINVAL; + } + + return omap3_noncore_dpll_set_rate(hw, rate, parent_rate); +} + +/** + * omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll + * @hw: clock to change + * @rate: target rate for clock + * @parent_rate: rate of the parent clock + * @index: parent index, 0 - reference clock, 1 - bypass clock + * + * Check if the current SoC support the per-dpll reprogram operation + * or not, and then do the rate + parent change if supported. Returns + * -EINVAL if not supported, 0 for success, and potential error codes + * from the clock rate change. + */ +int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate, u8 index) +{ + if (ti_clk_get_features()->flags & TI_CLK_DPLL4_DENY_REPROGRAM) { + pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n"); + return -EINVAL; + } + + return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate, + index); +} diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 25eea896627a..f8e50271ec97 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -271,41 +271,13 @@ extern const struct clk_ops ti_clk_mux_ops; #define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) -int omap3_noncore_dpll_enable(struct clk_hw *hw); -void omap3_noncore_dpll_disable(struct clk_hw *hw); -int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index); -int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate); -int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate, - u8 index); -long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk); -unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); -long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, - unsigned long *parent_rate); void omap2_init_clk_clkdm(struct clk_hw *clk); -unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw, - unsigned long parent_rate); -int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate); -long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate); int omap2_clkops_enable_clkdm(struct clk_hw *hw); void omap2_clkops_disable_clkdm(struct clk_hw *hw); int omap2_clk_disable_autoidle_all(void); int omap2_clk_enable_autoidle_all(void); int omap2_clk_allow_idle(struct clk *clk); int omap2_clk_deny_idle(struct clk *clk); -int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, - unsigned long parent_rate); -int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate, u8 index); int omap2_dflt_clk_enable(struct clk_hw *hw); void omap2_dflt_clk_disable(struct clk_hw *hw); int omap2_dflt_clk_is_enabled(struct clk_hw *hw); @@ -317,7 +289,6 @@ void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, void __iomem **idlest_reg, u8 *idlest_bit, u8 *idlest_val); -void omap3_clk_lock_dpll5(void); unsigned long omap2_dpllcore_recalc(struct clk_hw *hw, unsigned long parent_rate); int omap2_reprogram_dpllcore(struct clk_hw *clk, unsigned long rate, @@ -365,7 +336,6 @@ const struct ti_clk_features *ti_clk_get_features(void); extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; extern const struct clk_hw_omap_ops clkhwops_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; -- cgit v1.3-6-gb490 From 9f37e90efaf0772b8f98bc347b9db77a3f0c27eb Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 3 Mar 2015 15:28:53 +0200 Subject: clk: ti: dflt: move support for default gate clock to clock driver With the legacy support gone, OMAP2+ default gate clock can be moved under clock driver. Create a new file for the purpose, and clean-up the header exports a bit as some clock APIs are no longer needed outside clock driver itself. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/clock.c | 273 -------------------------------------- drivers/clk/ti/Makefile | 2 +- drivers/clk/ti/clkt_dflt.c | 316 ++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/ti/clock.h | 5 + include/linux/clk/ti.h | 4 - 5 files changed, 322 insertions(+), 278 deletions(-) create mode 100644 drivers/clk/ti/clkt_dflt.c (limited to 'drivers') diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 6c17adf40e6f..38a336b4c42b 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -40,12 +40,6 @@ #include "cm-regbits-34xx.h" #include "common.h" -/* - * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait - * for a module to indicate that it is no longer in idle - */ -#define MAX_MODULE_ENABLE_WAIT 100000 - u16 cpu_mask; /* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */ @@ -176,77 +170,6 @@ void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem) /* Private functions */ - -/** - * _wait_idlest_generic - wait for a module to leave the idle state - * @clk: module clock to wait for (needed for register offsets) - * @reg: virtual address of module IDLEST register - * @mask: value to mask against to determine if the module is active - * @idlest: idle state indicator (0 or 1) for the clock - * @name: name of the clock (for printk) - * - * Wait for a module to leave idle, where its idle-status register is - * not inside the CM module. Returns 1 if the module left idle - * promptly, or 0 if the module did not leave idle before the timeout - * elapsed. XXX Deprecated - should be moved into drivers for the - * individual IP block that the IDLEST register exists in. - */ -static int _wait_idlest_generic(struct clk_hw_omap *clk, void __iomem *reg, - u32 mask, u8 idlest, const char *name) -{ - int i = 0, ena = 0; - - ena = (idlest) ? 0 : mask; - - omap_test_timeout(((omap2_clk_readl(clk, reg) & mask) == ena), - MAX_MODULE_ENABLE_WAIT, i); - - if (i < MAX_MODULE_ENABLE_WAIT) - pr_debug("omap clock: module associated with clock %s ready after %d loops\n", - name, i); - else - pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n", - name, MAX_MODULE_ENABLE_WAIT); - - return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0; -}; - -/** - * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE - * @clk: struct clk * belonging to the module - * - * If the necessary clocks for the OMAP hardware IP block that - * corresponds to clock @clk are enabled, then wait for the module to - * indicate readiness (i.e., to leave IDLE). This code does not - * belong in the clock code and will be moved in the medium term to - * module-dependent code. No return value. - */ -static void _omap2_module_wait_ready(struct clk_hw_omap *clk) -{ - void __iomem *companion_reg, *idlest_reg; - u8 other_bit, idlest_bit, idlest_val, idlest_reg_id; - s16 prcm_mod; - int r; - - /* Not all modules have multiple clocks that their IDLEST depends on */ - if (clk->ops->find_companion) { - clk->ops->find_companion(clk, &companion_reg, &other_bit); - if (!(omap2_clk_readl(clk, companion_reg) & (1 << other_bit))) - return; - } - - clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val); - r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id); - if (r) { - /* IDLEST register not in the CM module */ - _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), - idlest_val, __clk_get_name(clk->hw.clk)); - } else { - omap_cm_wait_module_ready(0, prcm_mod, idlest_reg_id, - idlest_bit); - }; -} - /* Public functions */ /** @@ -279,174 +202,6 @@ void omap2_init_clk_clkdm(struct clk_hw *hw) } } -/** - * omap2_clk_dflt_find_companion - find companion clock to @clk - * @clk: struct clk * to find the companion clock of - * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in - * @other_bit: u8 ** to return the companion clock bit shift in - * - * Note: We don't need special code here for INVERT_ENABLE for the - * time being since INVERT_ENABLE only applies to clocks enabled by - * CM_CLKEN_PLL - * - * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's - * just a matter of XORing the bits. - * - * Some clocks don't have companion clocks. For example, modules with - * only an interface clock (such as MAILBOXES) don't have a companion - * clock. Right now, this code relies on the hardware exporting a bit - * in the correct companion register that indicates that the - * nonexistent 'companion clock' is active. Future patches will - * associate this type of code with per-module data structures to - * avoid this issue, and remove the casts. No return value. - */ -void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, - void __iomem **other_reg, u8 *other_bit) -{ - u32 r; - - /* - * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes - * it's just a matter of XORing the bits. - */ - r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN)); - - *other_reg = (__force void __iomem *)r; - *other_bit = clk->enable_bit; -} - -/** - * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk - * @clk: struct clk * to find IDLEST info for - * @idlest_reg: void __iomem ** to return the CM_IDLEST va in - * @idlest_bit: u8 * to return the CM_IDLEST bit shift in - * @idlest_val: u8 * to return the idle status indicator - * - * Return the CM_IDLEST register address and bit shift corresponding - * to the module that "owns" this clock. This default code assumes - * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that - * the IDLEST register address ID corresponds to the CM_*CLKEN - * register address ID (e.g., that CM_FCLKEN2 corresponds to - * CM_IDLEST2). This is not true for all modules. No return value. - */ -void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, u8 *idlest_bit, u8 *idlest_val) -{ - u32 r; - - r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); - *idlest_reg = (__force void __iomem *)r; - *idlest_bit = clk->enable_bit; - - /* - * 24xx uses 0 to indicate not ready, and 1 to indicate ready. - * 34xx reverses this, just to keep us on our toes - * AM35xx uses both, depending on the module. - */ - *idlest_val = ti_clk_get_features()->cm_idlest_val; -} - -/** - * omap2_dflt_clk_enable - enable a clock in the hardware - * @hw: struct clk_hw * of the clock to enable - * - * Enable the clock @hw in the hardware. We first call into the OMAP - * clockdomain code to "enable" the corresponding clockdomain if this - * is the first enabled user of the clockdomain. Then program the - * hardware to enable the clock. Then wait for the IP block that uses - * this clock to leave idle (if applicable). Returns the error value - * from clkdm_clk_enable() if it terminated with an error, or -EINVAL - * if @hw has a null clock enable_reg, or zero upon success. - */ -int omap2_dflt_clk_enable(struct clk_hw *hw) -{ - struct clk_hw_omap *clk; - u32 v; - int ret = 0; - bool clkdm_control; - - if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) - clkdm_control = false; - else - clkdm_control = true; - - clk = to_clk_hw_omap(hw); - - if (clkdm_control && clk->clkdm) { - ret = clkdm_clk_enable(clk->clkdm, hw->clk); - if (ret) { - WARN(1, "%s: could not enable %s's clockdomain %s: %d\n", - __func__, __clk_get_name(hw->clk), - clk->clkdm->name, ret); - return ret; - } - } - - if (unlikely(clk->enable_reg == NULL)) { - pr_err("%s: %s missing enable_reg\n", __func__, - __clk_get_name(hw->clk)); - ret = -EINVAL; - goto err; - } - - /* FIXME should not have INVERT_ENABLE bit here */ - v = omap2_clk_readl(clk, clk->enable_reg); - if (clk->flags & INVERT_ENABLE) - v &= ~(1 << clk->enable_bit); - else - v |= (1 << clk->enable_bit); - omap2_clk_writel(v, clk, clk->enable_reg); - v = omap2_clk_readl(clk, clk->enable_reg); /* OCP barrier */ - - if (clk->ops && clk->ops->find_idlest) - _omap2_module_wait_ready(clk); - - return 0; - -err: - if (clkdm_control && clk->clkdm) - clkdm_clk_disable(clk->clkdm, hw->clk); - return ret; -} - -/** - * omap2_dflt_clk_disable - disable a clock in the hardware - * @hw: struct clk_hw * of the clock to disable - * - * Disable the clock @hw in the hardware, and call into the OMAP - * clockdomain code to "disable" the corresponding clockdomain if all - * clocks/hwmods in that clockdomain are now disabled. No return - * value. - */ -void omap2_dflt_clk_disable(struct clk_hw *hw) -{ - struct clk_hw_omap *clk; - u32 v; - - clk = to_clk_hw_omap(hw); - if (!clk->enable_reg) { - /* - * 'independent' here refers to a clock which is not - * controlled by its parent. - */ - pr_err("%s: independent clock %s has no enable_reg\n", - __func__, __clk_get_name(hw->clk)); - return; - } - - v = omap2_clk_readl(clk, clk->enable_reg); - if (clk->flags & INVERT_ENABLE) - v |= (1 << clk->enable_bit); - else - v &= ~(1 << clk->enable_bit); - omap2_clk_writel(v, clk, clk->enable_reg); - /* No OCP barrier needed here since it is a disable operation */ - - if (!(ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) && - clk->clkdm) - clkdm_clk_disable(clk->clkdm, hw->clk); -} - /** * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw * @hw: struct clk_hw * of the clock being enabled @@ -523,29 +278,6 @@ void omap2_clkops_disable_clkdm(struct clk_hw *hw) clkdm_clk_disable(clk->clkdm, hw->clk); } -/** - * omap2_dflt_clk_is_enabled - is clock enabled in the hardware? - * @hw: struct clk_hw * to check - * - * Return 1 if the clock represented by @hw is enabled in the - * hardware, or 0 otherwise. Intended for use in the struct - * clk_ops.is_enabled function pointer. - */ -int omap2_dflt_clk_is_enabled(struct clk_hw *hw) -{ - struct clk_hw_omap *clk = to_clk_hw_omap(hw); - u32 v; - - v = omap2_clk_readl(clk, clk->enable_reg); - - if (clk->flags & INVERT_ENABLE) - v ^= BIT(clk->enable_bit); - - v &= BIT(clk->enable_bit); - - return v ? 1 : 0; -} - static int __initdata mpurate; /* @@ -566,11 +298,6 @@ static int __init omap_clk_setup(char *str) } __setup("mpurate=", omap_clk_setup); -const struct clk_hw_omap_ops clkhwops_wait = { - .find_idlest = omap2_clk_dflt_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - /** * omap2_clk_print_new_rates - print summary of current clock tree rates * @hfclkin_ck_name: clk name for the off-chip HF oscillator diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index 05a0294aba10..9b93e6904359 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile @@ -1,7 +1,7 @@ obj-y += clk.o autoidle.o clockdomain.o clk-common = dpll.o composite.o divider.o gate.o \ fixed-factor.o mux.o apll.o \ - clkt_dpll.o clkt_iclk.o + clkt_dpll.o clkt_iclk.o clkt_dflt.o obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o dpll3xxx.o obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o diff --git a/drivers/clk/ti/clkt_dflt.c b/drivers/clk/ti/clkt_dflt.c new file mode 100644 index 000000000000..a176b8ac8dd0 --- /dev/null +++ b/drivers/clk/ti/clkt_dflt.c @@ -0,0 +1,316 @@ +/* + * Default clock type + * + * Copyright (C) 2005-2008, 2015 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff + * Paul Walmsley + * Tero Kristo + * + * 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 "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 "clock.h" + +/* + * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait + * for a module to indicate that it is no longer in idle + */ +#define MAX_MODULE_ENABLE_WAIT 100000 + +/* + * CM module register offsets, used for calculating the companion + * register addresses. + */ +#define CM_FCLKEN 0x0000 +#define CM_ICLKEN 0x0010 + +/** + * _wait_idlest_generic - wait for a module to leave the idle state + * @clk: module clock to wait for (needed for register offsets) + * @reg: virtual address of module IDLEST register + * @mask: value to mask against to determine if the module is active + * @idlest: idle state indicator (0 or 1) for the clock + * @name: name of the clock (for printk) + * + * Wait for a module to leave idle, where its idle-status register is + * not inside the CM module. Returns 1 if the module left idle + * promptly, or 0 if the module did not leave idle before the timeout + * elapsed. XXX Deprecated - should be moved into drivers for the + * individual IP block that the IDLEST register exists in. + */ +static int _wait_idlest_generic(struct clk_hw_omap *clk, void __iomem *reg, + u32 mask, u8 idlest, const char *name) +{ + int i = 0, ena = 0; + + ena = (idlest) ? 0 : mask; + + /* Wait until module enters enabled state */ + for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) { + if ((ti_clk_ll_ops->clk_readl(reg) & mask) == ena) + break; + udelay(1); + } + + if (i < MAX_MODULE_ENABLE_WAIT) + pr_debug("omap clock: module associated with clock %s ready after %d loops\n", + name, i); + else + pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n", + name, MAX_MODULE_ENABLE_WAIT); + + return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0; +} + +/** + * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE + * @clk: struct clk * belonging to the module + * + * If the necessary clocks for the OMAP hardware IP block that + * corresponds to clock @clk are enabled, then wait for the module to + * indicate readiness (i.e., to leave IDLE). This code does not + * belong in the clock code and will be moved in the medium term to + * module-dependent code. No return value. + */ +static void _omap2_module_wait_ready(struct clk_hw_omap *clk) +{ + void __iomem *companion_reg, *idlest_reg; + u8 other_bit, idlest_bit, idlest_val, idlest_reg_id; + s16 prcm_mod; + int r; + + /* Not all modules have multiple clocks that their IDLEST depends on */ + if (clk->ops->find_companion) { + clk->ops->find_companion(clk, &companion_reg, &other_bit); + if (!(ti_clk_ll_ops->clk_readl(companion_reg) & + (1 << other_bit))) + return; + } + + clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val); + r = ti_clk_ll_ops->cm_split_idlest_reg(idlest_reg, &prcm_mod, + &idlest_reg_id); + if (r) { + /* IDLEST register not in the CM module */ + _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), + idlest_val, __clk_get_name(clk->hw.clk)); + } else { + ti_clk_ll_ops->cm_wait_module_ready(0, prcm_mod, idlest_reg_id, + idlest_bit); + } +} + +/** + * omap2_clk_dflt_find_companion - find companion clock to @clk + * @clk: struct clk * to find the companion clock of + * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in + * @other_bit: u8 ** to return the companion clock bit shift in + * + * Note: We don't need special code here for INVERT_ENABLE for the + * time being since INVERT_ENABLE only applies to clocks enabled by + * CM_CLKEN_PLL + * + * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's + * just a matter of XORing the bits. + * + * Some clocks don't have companion clocks. For example, modules with + * only an interface clock (such as MAILBOXES) don't have a companion + * clock. Right now, this code relies on the hardware exporting a bit + * in the correct companion register that indicates that the + * nonexistent 'companion clock' is active. Future patches will + * associate this type of code with per-module data structures to + * avoid this issue, and remove the casts. No return value. + */ +void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, + void __iomem **other_reg, u8 *other_bit) +{ + u32 r; + + /* + * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes + * it's just a matter of XORing the bits. + */ + r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN)); + + *other_reg = (__force void __iomem *)r; + *other_bit = clk->enable_bit; +} + +/** + * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk + * @clk: struct clk * to find IDLEST info for + * @idlest_reg: void __iomem ** to return the CM_IDLEST va in + * @idlest_bit: u8 * to return the CM_IDLEST bit shift in + * @idlest_val: u8 * to return the idle status indicator + * + * Return the CM_IDLEST register address and bit shift corresponding + * to the module that "owns" this clock. This default code assumes + * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that + * the IDLEST register address ID corresponds to the CM_*CLKEN + * register address ID (e.g., that CM_FCLKEN2 corresponds to + * CM_IDLEST2). This is not true for all modules. No return value. + */ +void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = clk->enable_bit; + + /* + * 24xx uses 0 to indicate not ready, and 1 to indicate ready. + * 34xx reverses this, just to keep us on our toes + * AM35xx uses both, depending on the module. + */ + *idlest_val = ti_clk_get_features()->cm_idlest_val; +} + +/** + * omap2_dflt_clk_enable - enable a clock in the hardware + * @hw: struct clk_hw * of the clock to enable + * + * Enable the clock @hw in the hardware. We first call into the OMAP + * clockdomain code to "enable" the corresponding clockdomain if this + * is the first enabled user of the clockdomain. Then program the + * hardware to enable the clock. Then wait for the IP block that uses + * this clock to leave idle (if applicable). Returns the error value + * from clkdm_clk_enable() if it terminated with an error, or -EINVAL + * if @hw has a null clock enable_reg, or zero upon success. + */ +int omap2_dflt_clk_enable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk; + u32 v; + int ret = 0; + bool clkdm_control; + + if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) + clkdm_control = false; + else + clkdm_control = true; + + clk = to_clk_hw_omap(hw); + + if (clkdm_control && clk->clkdm) { + ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk); + if (ret) { + WARN(1, + "%s: could not enable %s's clockdomain %s: %d\n", + __func__, __clk_get_name(hw->clk), + clk->clkdm_name, ret); + return ret; + } + } + + if (unlikely(!clk->enable_reg)) { + pr_err("%s: %s missing enable_reg\n", __func__, + __clk_get_name(hw->clk)); + ret = -EINVAL; + goto err; + } + + /* FIXME should not have INVERT_ENABLE bit here */ + v = ti_clk_ll_ops->clk_readl(clk->enable_reg); + if (clk->flags & INVERT_ENABLE) + v &= ~(1 << clk->enable_bit); + else + v |= (1 << clk->enable_bit); + ti_clk_ll_ops->clk_writel(v, clk->enable_reg); + v = ti_clk_ll_ops->clk_readl(clk->enable_reg); /* OCP barrier */ + + if (clk->ops && clk->ops->find_idlest) + _omap2_module_wait_ready(clk); + + return 0; + +err: + if (clkdm_control && clk->clkdm) + ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); + return ret; +} + +/** + * omap2_dflt_clk_disable - disable a clock in the hardware + * @hw: struct clk_hw * of the clock to disable + * + * Disable the clock @hw in the hardware, and call into the OMAP + * clockdomain code to "disable" the corresponding clockdomain if all + * clocks/hwmods in that clockdomain are now disabled. No return + * value. + */ +void omap2_dflt_clk_disable(struct clk_hw *hw) +{ + struct clk_hw_omap *clk; + u32 v; + + clk = to_clk_hw_omap(hw); + if (!clk->enable_reg) { + /* + * 'independent' here refers to a clock which is not + * controlled by its parent. + */ + pr_err("%s: independent clock %s has no enable_reg\n", + __func__, __clk_get_name(hw->clk)); + return; + } + + v = ti_clk_ll_ops->clk_readl(clk->enable_reg); + if (clk->flags & INVERT_ENABLE) + v |= (1 << clk->enable_bit); + else + v &= ~(1 << clk->enable_bit); + ti_clk_ll_ops->clk_writel(v, clk->enable_reg); + /* No OCP barrier needed here since it is a disable operation */ + + if (!(ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) && + clk->clkdm) + ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); +} + +/** + * omap2_dflt_clk_is_enabled - is clock enabled in the hardware? + * @hw: struct clk_hw * to check + * + * Return 1 if the clock represented by @hw is enabled in the + * hardware, or 0 otherwise. Intended for use in the struct + * clk_ops.is_enabled function pointer. + */ +int omap2_dflt_clk_is_enabled(struct clk_hw *hw) +{ + struct clk_hw_omap *clk = to_clk_hw_omap(hw); + u32 v; + + v = ti_clk_ll_ops->clk_readl(clk->enable_reg); + + if (clk->flags & INVERT_ENABLE) + v ^= BIT(clk->enable_bit); + + v &= BIT(clk->enable_bit); + + return v ? 1 : 0; +} + +const struct clk_hw_omap_ops clkhwops_wait = { + .find_idlest = omap2_clk_dflt_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 688d9e47b2c8..f21538364588 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -175,9 +175,14 @@ void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; +extern const struct clk_hw_omap_ops clkhwops_wait; extern const struct clk_hw_omap_ops clkhwops_iclk; extern const struct clk_hw_omap_ops clkhwops_iclk_wait; +int omap2_dflt_clk_enable(struct clk_hw *hw); +void omap2_dflt_clk_disable(struct clk_hw *hw); +int omap2_dflt_clk_is_enabled(struct clk_hw *hw); + u8 omap2_init_dpll_parent(struct clk_hw *hw); int omap3_noncore_dpll_enable(struct clk_hw *hw); void omap3_noncore_dpll_disable(struct clk_hw *hw); diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index fbb65e401d13..81a913edffa7 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -278,9 +278,6 @@ int omap2_clk_disable_autoidle_all(void); int omap2_clk_enable_autoidle_all(void); int omap2_clk_allow_idle(struct clk *clk); int omap2_clk_deny_idle(struct clk *clk); -int omap2_dflt_clk_enable(struct clk_hw *hw); -void omap2_dflt_clk_disable(struct clk_hw *hw); -int omap2_dflt_clk_is_enabled(struct clk_hw *hw); void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, @@ -337,7 +334,6 @@ const struct ti_clk_features *ti_clk_get_features(void); extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; -extern const struct clk_hw_omap_ops clkhwops_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; -- cgit v1.3-6-gb490 From d5a04dddf51e234dc89f21e4e4b91e853cf49ff2 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 3 Mar 2015 16:08:42 +0200 Subject: clk: ti: omap2430: move clock support code under clock driver With the legacy clock support gone, this is no longer needed under platform code-base. Thus, move this under the TI clock driver, and remove the exported API from the public header. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/Makefile | 1 - arch/arm/mach-omap2/clock2430.c | 57 ----------------------------------------- drivers/clk/ti/clkt_iclk.c | 35 +++++++++++++++++++++++++ drivers/clk/ti/clock.h | 1 + include/linux/clk/ti.h | 1 - 5 files changed, 36 insertions(+), 59 deletions(-) delete mode 100644 arch/arm/mach-omap2/clock2430.c (limited to 'drivers') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 070526563698..695d58f81ff3 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -185,7 +185,6 @@ obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpllcore.o obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_virt_prcm_set.o obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o -obj-$(CONFIG_SOC_OMAP2430) += clock2430.o obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o obj-$(CONFIG_ARCH_OMAP3) += clock3517.o diff --git a/arch/arm/mach-omap2/clock2430.c b/arch/arm/mach-omap2/clock2430.c deleted file mode 100644 index cef0c8d1de52..000000000000 --- a/arch/arm/mach-omap2/clock2430.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * clock2430.c - OMAP2430-specific clock integration code - * - * Copyright (C) 2005-2008 Texas Instruments, Inc. - * Copyright (C) 2004-2010 Nokia Corporation - * - * Contacts: - * Richard Woodruff - * Paul Walmsley - * - * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, - * Gordon McNutt and RidgeRun, 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. - */ -#undef DEBUG - -#include -#include -#include - -#include "soc.h" -#include "iomap.h" -#include "clock.h" -#include "clock2xxx.h" -#include "cm2xxx.h" -#include "cm-regbits-24xx.h" - -/** - * omap2430_clk_i2chs_find_idlest - return CM_IDLEST info for 2430 I2CHS - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * OMAP2430 I2CHS CM_IDLEST bits are in CM_IDLEST1_CORE, but the - * CM_*CLKEN bits are in CM_{I,F}CLKEN2_CORE. This custom function - * passes back the correct CM_IDLEST register address for I2CHS - * modules. No return value. - */ -static void omap2430_clk_i2chs_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - *idlest_reg = OMAP2430_CM_REGADDR(CORE_MOD, CM_IDLEST); - *idlest_bit = clk->enable_bit; - *idlest_val = OMAP24XX_CM_IDLEST_VAL; -} - -/* 2430 I2CHS has non-standard IDLEST register */ -const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait = { - .find_idlest = omap2430_clk_i2chs_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; diff --git a/drivers/clk/ti/clkt_iclk.c b/drivers/clk/ti/clkt_iclk.c index a03919df00ef..38c36908cf88 100644 --- a/drivers/clk/ti/clkt_iclk.c +++ b/drivers/clk/ti/clkt_iclk.c @@ -18,8 +18,12 @@ #include "clock.h" /* Register offsets */ +#define OMAP24XX_CM_FCLKEN2 0x04 #define CM_AUTOIDLE 0x30 #define CM_ICLKEN 0x10 +#define CM_IDLEST 0x20 + +#define OMAP24XX_CM_IDLEST_VAL 0 /* Private functions */ @@ -51,6 +55,31 @@ void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk) ti_clk_ll_ops->clk_writel(v, r); } +/** + * omap2430_clk_i2chs_find_idlest - return CM_IDLEST info for 2430 I2CHS + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * OMAP2430 I2CHS CM_IDLEST bits are in CM_IDLEST1_CORE, but the + * CM_*CLKEN bits are in CM_{I,F}CLKEN2_CORE. This custom function + * passes back the correct CM_IDLEST register address for I2CHS + * modules. No return value. + */ +static void omap2430_clk_i2chs_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = ((__force u32)clk->enable_reg ^ (OMAP24XX_CM_FCLKEN2 ^ CM_IDLEST)); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = clk->enable_bit; + *idlest_val = OMAP24XX_CM_IDLEST_VAL; +} + /* Public data */ const struct clk_hw_omap_ops clkhwops_iclk = { @@ -64,3 +93,9 @@ const struct clk_hw_omap_ops clkhwops_iclk_wait = { .find_idlest = omap2_clk_dflt_find_idlest, .find_companion = omap2_clk_dflt_find_companion, }; + +/* 2430 I2CHS has non-standard IDLEST register */ +const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait = { + .find_idlest = omap2430_clk_i2chs_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index f21538364588..3652c267cf81 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -178,6 +178,7 @@ extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; extern const struct clk_hw_omap_ops clkhwops_wait; extern const struct clk_hw_omap_ops clkhwops_iclk; extern const struct clk_hw_omap_ops clkhwops_iclk_wait; +extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; int omap2_dflt_clk_enable(struct clk_hw *hw); void omap2_dflt_clk_disable(struct clk_hw *hw); diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 81a913edffa7..440ace33ea35 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -333,7 +333,6 @@ void ti_clk_setup_features(struct ti_clk_features *features); const struct ti_clk_features *ti_clk_get_features(void); extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; -extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; -- cgit v1.3-6-gb490 From bd86cfdcbd827216fd682d62ffba2667bbe6fbc3 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 3 Mar 2015 16:22:50 +0200 Subject: clk: ti: clkdm: move clkdm gate clock support code to clock driver With the legacy clock data gone, this is no longer needed under platform, so move it under the clock driver itself. Remove the exported clock driver APIs as well, as these are not needed outside clock driver anymore. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/clock.c | 76 -------------------------------------------- arch/arm/mach-omap2/clock.h | 3 -- drivers/clk/ti/clock.h | 3 ++ drivers/clk/ti/clockdomain.c | 76 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk/ti.h | 2 -- 5 files changed, 79 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 38a336b4c42b..99875dba803a 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -202,82 +202,6 @@ void omap2_init_clk_clkdm(struct clk_hw *hw) } } -/** - * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw - * @hw: struct clk_hw * of the clock being enabled - * - * Increment the usecount of the clockdomain of the clock pointed to - * by @hw; if the usecount is 1, the clockdomain will be "enabled." - * Only needed for clocks that don't use omap2_dflt_clk_enable() as - * their enable function pointer. Passes along the return value of - * clkdm_clk_enable(), -EINVAL if @hw is not associated with a - * clockdomain, or 0 if clock framework-based clockdomain control is - * not implemented. - */ -int omap2_clkops_enable_clkdm(struct clk_hw *hw) -{ - struct clk_hw_omap *clk; - int ret = 0; - - clk = to_clk_hw_omap(hw); - - if (unlikely(!clk->clkdm)) { - pr_err("%s: %s: no clkdm set ?!\n", __func__, - __clk_get_name(hw->clk)); - return -EINVAL; - } - - if (unlikely(clk->enable_reg)) - pr_err("%s: %s: should use dflt_clk_enable ?!\n", __func__, - __clk_get_name(hw->clk)); - - if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) { - pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n", - __func__, __clk_get_name(hw->clk)); - return 0; - } - - ret = clkdm_clk_enable(clk->clkdm, hw->clk); - WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n", - __func__, __clk_get_name(hw->clk), clk->clkdm->name, ret); - - return ret; -} - -/** - * omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw - * @hw: struct clk_hw * of the clock being disabled - * - * Decrement the usecount of the clockdomain of the clock pointed to - * by @hw; if the usecount is 0, the clockdomain will be "disabled." - * Only needed for clocks that don't use omap2_dflt_clk_disable() as their - * disable function pointer. No return value. - */ -void omap2_clkops_disable_clkdm(struct clk_hw *hw) -{ - struct clk_hw_omap *clk; - - clk = to_clk_hw_omap(hw); - - if (unlikely(!clk->clkdm)) { - pr_err("%s: %s: no clkdm set ?!\n", __func__, - __clk_get_name(hw->clk)); - return; - } - - if (unlikely(clk->enable_reg)) - pr_err("%s: %s: should use dflt_clk_disable ?!\n", __func__, - __clk_get_name(hw->clk)); - - if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) { - pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n", - __func__, __clk_get_name(hw->clk)); - return; - } - - clkdm_clk_disable(clk->clkdm, hw->clk); -} - static int __initdata mpurate; /* diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 948065497472..a7e951129ffb 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -202,9 +202,6 @@ extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; extern const struct clk_hw_omap_ops clkhwops_apll54; extern const struct clk_hw_omap_ops clkhwops_apll96; -extern int omap2_clkops_enable_clkdm(struct clk_hw *hw); -extern void omap2_clkops_disable_clkdm(struct clk_hw *hw); - struct regmap; int __init omap2_clk_provider_init(struct device_node *np, int index, diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 3652c267cf81..83476d12d561 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -180,6 +180,9 @@ extern const struct clk_hw_omap_ops clkhwops_iclk; extern const struct clk_hw_omap_ops clkhwops_iclk_wait; extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; +int omap2_clkops_enable_clkdm(struct clk_hw *hw); +void omap2_clkops_disable_clkdm(struct clk_hw *hw); + int omap2_dflt_clk_enable(struct clk_hw *hw); void omap2_dflt_clk_disable(struct clk_hw *hw); int omap2_dflt_clk_is_enabled(struct clk_hw *hw); diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index 35fe1085480c..61ef87b1a688 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -24,6 +24,82 @@ #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ +/** + * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw + * @hw: struct clk_hw * of the clock being enabled + * + * Increment the usecount of the clockdomain of the clock pointed to + * by @hw; if the usecount is 1, the clockdomain will be "enabled." + * Only needed for clocks that don't use omap2_dflt_clk_enable() as + * their enable function pointer. Passes along the return value of + * clkdm_clk_enable(), -EINVAL if @hw is not associated with a + * clockdomain, or 0 if clock framework-based clockdomain control is + * not implemented. + */ +int omap2_clkops_enable_clkdm(struct clk_hw *hw) +{ + struct clk_hw_omap *clk; + int ret = 0; + + clk = to_clk_hw_omap(hw); + + if (unlikely(!clk->clkdm)) { + pr_err("%s: %s: no clkdm set ?!\n", __func__, + __clk_get_name(hw->clk)); + return -EINVAL; + } + + if (unlikely(clk->enable_reg)) + pr_err("%s: %s: should use dflt_clk_enable ?!\n", __func__, + __clk_get_name(hw->clk)); + + if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) { + pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n", + __func__, __clk_get_name(hw->clk)); + return 0; + } + + ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk); + WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n", + __func__, __clk_get_name(hw->clk), clk->clkdm_name, ret); + + return ret; +} + +/** + * omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw + * @hw: struct clk_hw * of the clock being disabled + * + * Decrement the usecount of the clockdomain of the clock pointed to + * by @hw; if the usecount is 0, the clockdomain will be "disabled." + * Only needed for clocks that don't use omap2_dflt_clk_disable() as their + * disable function pointer. No return value. + */ +void omap2_clkops_disable_clkdm(struct clk_hw *hw) +{ + struct clk_hw_omap *clk; + + clk = to_clk_hw_omap(hw); + + if (unlikely(!clk->clkdm)) { + pr_err("%s: %s: no clkdm set ?!\n", __func__, + __clk_get_name(hw->clk)); + return; + } + + if (unlikely(clk->enable_reg)) + pr_err("%s: %s: should use dflt_clk_disable ?!\n", __func__, + __clk_get_name(hw->clk)); + + if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) { + pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n", + __func__, __clk_get_name(hw->clk)); + return; + } + + ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); +} + static void __init of_ti_clockdomain_setup(struct device_node *node) { struct clk *clk; diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 440ace33ea35..27828422c9c5 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -272,8 +272,6 @@ extern const struct clk_ops ti_clk_mux_ops; #define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) void omap2_init_clk_clkdm(struct clk_hw *clk); -int omap2_clkops_enable_clkdm(struct clk_hw *hw); -void omap2_clkops_disable_clkdm(struct clk_hw *hw); int omap2_clk_disable_autoidle_all(void); int omap2_clk_enable_autoidle_all(void); int omap2_clk_allow_idle(struct clk *clk); -- cgit v1.3-6-gb490 From f2671d5c6cb4abe4636014cd66fd0eeb8190b2ca Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 3 Mar 2015 17:28:12 +0200 Subject: clk: ti: omap34xx: move omap34xx clock type support code to clock driver With the legacy clock data gone, this is no longer needed under platform, so move it under the clock driver itself. Remove unnecessary declarations from the TI clock header also. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/Makefile | 2 +- arch/arm/mach-omap2/clock34xx.c | 138 ---------------------------------------- drivers/clk/ti/clk-3xxx.c | 118 ++++++++++++++++++++++++++++++++++ drivers/clk/ti/clock.h | 4 ++ include/linux/clk/ti.h | 4 -- 5 files changed, 123 insertions(+), 143 deletions(-) delete mode 100644 arch/arm/mach-omap2/clock34xx.c (limited to 'drivers') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 695d58f81ff3..22d2e48dcff5 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -186,7 +186,7 @@ obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpllcore.o obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_virt_prcm_set.o obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) -obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o +obj-$(CONFIG_ARCH_OMAP3) += clkt34xx_dpll3m2.o obj-$(CONFIG_ARCH_OMAP3) += clock3517.o obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) obj-$(CONFIG_SOC_AM33XX) += $(clock-common) diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c deleted file mode 100644 index 4596468e50ab..000000000000 --- a/arch/arm/mach-omap2/clock34xx.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * OMAP3-specific clock framework functions - * - * Copyright (C) 2007-2008 Texas Instruments, Inc. - * Copyright (C) 2007-2011 Nokia Corporation - * - * Paul Walmsley - * Jouni Högander - * - * Parts of this code are based on code written by - * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu, - * 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. - */ -#undef DEBUG - -#include -#include -#include - -#include "clock.h" -#include "clock34xx.h" -#include "cm3xxx.h" -#include "cm-regbits-34xx.h" - -/** - * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * The OMAP3430ES2 SSI target CM_IDLEST bit is at a different shift - * from the CM_{I,F}CLKEN bit. Pass back the correct info via - * @idlest_reg and @idlest_bit. No return value. - */ -static void omap3430es2_clk_ssi_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - u32 r; - - r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); - *idlest_reg = (__force void __iomem *)r; - *idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT; - *idlest_val = OMAP34XX_CM_IDLEST_VAL; -} -const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait = { - .find_idlest = omap3430es2_clk_ssi_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - -const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, - .find_idlest = omap3430es2_clk_ssi_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - -/** - * omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS, USBHOST - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * Some OMAP modules on OMAP3 ES2+ chips have both initiator and - * target IDLEST bits. For our purposes, we are concerned with the - * target IDLEST bits, which exist at a different bit position than - * the *CLKEN bit position for these modules (DSS and USBHOST) (The - * default find_idlest code assumes that they are at the same - * position.) No return value. - */ -static void omap3430es2_clk_dss_usbhost_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - u32 r; - - r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); - *idlest_reg = (__force void __iomem *)r; - /* USBHOST_IDLE has same shift */ - *idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT; - *idlest_val = OMAP34XX_CM_IDLEST_VAL; -} - -const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait = { - .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - -const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, - .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - -/** - * omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * The OMAP3430ES2 HSOTGUSB target CM_IDLEST bit is at a different - * shift from the CM_{I,F}CLKEN bit. Pass back the correct info via - * @idlest_reg and @idlest_bit. No return value. - */ -static void omap3430es2_clk_hsotgusb_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - u32 r; - - r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); - *idlest_reg = (__force void __iomem *)r; - *idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT; - *idlest_val = OMAP34XX_CM_IDLEST_VAL; -} - -const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, - .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - -const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait = { - .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c index 5489ad8c07d4..58879f0b7949 100644 --- a/drivers/clk/ti/clk-3xxx.c +++ b/drivers/clk/ti/clk-3xxx.c @@ -28,6 +28,124 @@ */ #define DPLL5_FREQ_FOR_USBHOST 120000000 +#define OMAP3430ES2_ST_DSS_IDLE_SHIFT 1 +#define OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT 5 +#define OMAP3430ES2_ST_SSI_IDLE_SHIFT 8 + +#define OMAP34XX_CM_IDLEST_VAL 1 + +/** + * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * The OMAP3430ES2 SSI target CM_IDLEST bit is at a different shift + * from the CM_{I,F}CLKEN bit. Pass back the correct info via + * @idlest_reg and @idlest_bit. No return value. + */ +static void omap3430es2_clk_ssi_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT; + *idlest_val = OMAP34XX_CM_IDLEST_VAL; +} + +const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait = { + .find_idlest = omap3430es2_clk_ssi_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, + .find_idlest = omap3430es2_clk_ssi_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +/** + * omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS, USBHOST + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * Some OMAP modules on OMAP3 ES2+ chips have both initiator and + * target IDLEST bits. For our purposes, we are concerned with the + * target IDLEST bits, which exist at a different bit position than + * the *CLKEN bit position for these modules (DSS and USBHOST) (The + * default find_idlest code assumes that they are at the same + * position.) No return value. + */ +static void omap3430es2_clk_dss_usbhost_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + /* USBHOST_IDLE has same shift */ + *idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT; + *idlest_val = OMAP34XX_CM_IDLEST_VAL; +} + +const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait = { + .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, + .find_idlest = omap3430es2_clk_dss_usbhost_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +/** + * omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * The OMAP3430ES2 HSOTGUSB target CM_IDLEST bit is at a different + * shift from the CM_{I,F}CLKEN bit. Pass back the correct info via + * @idlest_reg and @idlest_bit. No return value. + */ +static void omap3430es2_clk_hsotgusb_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT; + *idlest_val = OMAP34XX_CM_IDLEST_VAL; +} + +const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, + .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + +const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait = { + .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + static struct ti_dt_clk omap3xxx_clks[] = { DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"), DT_CLK(NULL, "omap_32k_fck", "omap_32k_fck"), diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 83476d12d561..c6fbd153b6d4 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -179,6 +179,10 @@ extern const struct clk_hw_omap_ops clkhwops_wait; extern const struct clk_hw_omap_ops clkhwops_iclk; extern const struct clk_hw_omap_ops clkhwops_iclk_wait; extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait; +extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; int omap2_clkops_enable_clkdm(struct clk_hw *hw); void omap2_clkops_disable_clkdm(struct clk_hw *hw); diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 27828422c9c5..cd5b3eadc317 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -331,12 +331,8 @@ void ti_clk_setup_features(struct ti_clk_features *features); const struct ti_clk_features *ti_clk_get_features(void); extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait; -extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait; #ifdef CONFIG_ATAGS int omap3430_clk_legacy_init(void); -- cgit v1.3-6-gb490 From c9a58b0a848e4b88d2dd4690ef19bae8696649eb Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Tue, 3 Mar 2015 21:19:25 +0200 Subject: clk: ti: am3517: move remaining am3517 clock support code to clock driver With legacy clock support gone, this is no longer needed under platform, so move it under the clock driver itself. Make some exports be driver internal definitions at the same time. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/Makefile | 1 - arch/arm/mach-omap2/clock3517.c | 118 ---------------------------------------- arch/arm/mach-omap2/clock3517.h | 14 ----- drivers/clk/ti/clk-3xxx.c | 94 ++++++++++++++++++++++++++++++++ drivers/clk/ti/clock.h | 2 + include/linux/clk/ti.h | 2 - 6 files changed, 96 insertions(+), 135 deletions(-) delete mode 100644 arch/arm/mach-omap2/clock3517.c delete mode 100644 arch/arm/mach-omap2/clock3517.h (limited to 'drivers') diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 22d2e48dcff5..d424920a5e1c 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -187,7 +187,6 @@ obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_virt_prcm_set.o obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) obj-$(CONFIG_ARCH_OMAP3) += clkt34xx_dpll3m2.o -obj-$(CONFIG_ARCH_OMAP3) += clock3517.o obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) obj-$(CONFIG_SOC_AM33XX) += $(clock-common) obj-$(CONFIG_SOC_OMAP5) += $(clock-common) diff --git a/arch/arm/mach-omap2/clock3517.c b/arch/arm/mach-omap2/clock3517.c deleted file mode 100644 index 4d79ae2c0241..000000000000 --- a/arch/arm/mach-omap2/clock3517.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * OMAP3517/3505-specific clock framework functions - * - * Copyright (C) 2010 Texas Instruments, Inc. - * Copyright (C) 2011 Nokia Corporation - * - * Ranjith Lohithakshan - * Paul Walmsley - * - * Parts of this code are based on code written by - * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu, - * 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. - */ -#undef DEBUG - -#include -#include -#include - -#include "clock.h" -#include "clock3517.h" -#include "cm3xxx.h" -#include "cm-regbits-34xx.h" - -/* - * In AM35xx IPSS, the {ICK,FCK} enable bits for modules are exported - * in the same register at a bit offset of 0x8. The EN_ACK for ICK is - * at an offset of 4 from ICK enable bit. - */ -#define AM35XX_IPSS_ICK_MASK 0xF -#define AM35XX_IPSS_ICK_EN_ACK_OFFSET 0x4 -#define AM35XX_IPSS_ICK_FCK_OFFSET 0x8 -#define AM35XX_IPSS_CLK_IDLEST_VAL 0 - -/** - * am35xx_clk_find_idlest - return clock ACK info for AM35XX IPSS - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * The interface clocks on AM35xx IPSS reflects the clock idle status - * in the enable register itsel at a bit offset of 4 from the enable - * bit. A value of 1 indicates that clock is enabled. - */ -static void am35xx_clk_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - *idlest_reg = (__force void __iomem *)(clk->enable_reg); - *idlest_bit = clk->enable_bit + AM35XX_IPSS_ICK_EN_ACK_OFFSET; - *idlest_val = AM35XX_IPSS_CLK_IDLEST_VAL; -} - -/** - * am35xx_clk_find_companion - find companion clock to @clk - * @clk: struct clk * to find the companion clock of - * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in - * @other_bit: u8 ** to return the companion clock bit shift in - * - * Some clocks don't have companion clocks. For example, modules with - * only an interface clock (such as HECC) don't have a companion - * clock. Right now, this code relies on the hardware exporting a bit - * in the correct companion register that indicates that the - * nonexistent 'companion clock' is active. Future patches will - * associate this type of code with per-module data structures to - * avoid this issue, and remove the casts. No return value. - */ -static void am35xx_clk_find_companion(struct clk_hw_omap *clk, - void __iomem **other_reg, - u8 *other_bit) -{ - *other_reg = (__force void __iomem *)(clk->enable_reg); - if (clk->enable_bit & AM35XX_IPSS_ICK_MASK) - *other_bit = clk->enable_bit + AM35XX_IPSS_ICK_FCK_OFFSET; - else - *other_bit = clk->enable_bit - AM35XX_IPSS_ICK_FCK_OFFSET; -} -const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait = { - .find_idlest = am35xx_clk_find_idlest, - .find_companion = am35xx_clk_find_companion, -}; - -/** - * am35xx_clk_ipss_find_idlest - return CM_IDLEST info for IPSS - * @clk: struct clk * being enabled - * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into - * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into - * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator - * - * The IPSS target CM_IDLEST bit is at a different shift from the - * CM_{I,F}CLKEN bit. Pass back the correct info via @idlest_reg - * and @idlest_bit. No return value. - */ -static void am35xx_clk_ipss_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, - u8 *idlest_val) -{ - u32 r; - - r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); - *idlest_reg = (__force void __iomem *)r; - *idlest_bit = AM35XX_ST_IPSS_SHIFT; - *idlest_val = OMAP34XX_CM_IDLEST_VAL; -} - -const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait = { - .allow_idle = omap2_clkt_iclk_allow_idle, - .deny_idle = omap2_clkt_iclk_deny_idle, - .find_idlest = am35xx_clk_ipss_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; diff --git a/arch/arm/mach-omap2/clock3517.h b/arch/arm/mach-omap2/clock3517.h deleted file mode 100644 index ca5e5a64c2e2..000000000000 --- a/arch/arm/mach-omap2/clock3517.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * OMAP3517/3505 clock function prototypes and macros - * - * Copyright (C) 2010 Texas Instruments, Inc. - * Copyright (C) 2010 Nokia Corporation - */ - -#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK3517_H -#define __ARCH_ARM_MACH_OMAP2_CLOCK3517_H - -extern const struct clkops clkops_am35xx_ipss_module_wait; -extern const struct clkops clkops_am35xx_ipss_wait; - -#endif diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c index 58879f0b7949..6e33332b6b34 100644 --- a/drivers/clk/ti/clk-3xxx.c +++ b/drivers/clk/ti/clk-3xxx.c @@ -34,6 +34,18 @@ #define OMAP34XX_CM_IDLEST_VAL 1 +/* + * In AM35xx IPSS, the {ICK,FCK} enable bits for modules are exported + * in the same register at a bit offset of 0x8. The EN_ACK for ICK is + * at an offset of 4 from ICK enable bit. + */ +#define AM35XX_IPSS_ICK_MASK 0xF +#define AM35XX_IPSS_ICK_EN_ACK_OFFSET 0x4 +#define AM35XX_IPSS_ICK_FCK_OFFSET 0x8 +#define AM35XX_IPSS_CLK_IDLEST_VAL 0 + +#define AM35XX_ST_IPSS_SHIFT 5 + /** * omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI * @clk: struct clk * being enabled @@ -146,6 +158,88 @@ const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait = { .find_companion = omap2_clk_dflt_find_companion, }; +/** + * am35xx_clk_find_idlest - return clock ACK info for AM35XX IPSS + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * The interface clocks on AM35xx IPSS reflects the clock idle status + * in the enable register itsel at a bit offset of 4 from the enable + * bit. A value of 1 indicates that clock is enabled. + */ +static void am35xx_clk_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + *idlest_reg = (__force void __iomem *)(clk->enable_reg); + *idlest_bit = clk->enable_bit + AM35XX_IPSS_ICK_EN_ACK_OFFSET; + *idlest_val = AM35XX_IPSS_CLK_IDLEST_VAL; +} + +/** + * am35xx_clk_find_companion - find companion clock to @clk + * @clk: struct clk * to find the companion clock of + * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in + * @other_bit: u8 ** to return the companion clock bit shift in + * + * Some clocks don't have companion clocks. For example, modules with + * only an interface clock (such as HECC) don't have a companion + * clock. Right now, this code relies on the hardware exporting a bit + * in the correct companion register that indicates that the + * nonexistent 'companion clock' is active. Future patches will + * associate this type of code with per-module data structures to + * avoid this issue, and remove the casts. No return value. + */ +static void am35xx_clk_find_companion(struct clk_hw_omap *clk, + void __iomem **other_reg, + u8 *other_bit) +{ + *other_reg = (__force void __iomem *)(clk->enable_reg); + if (clk->enable_bit & AM35XX_IPSS_ICK_MASK) + *other_bit = clk->enable_bit + AM35XX_IPSS_ICK_FCK_OFFSET; + else + *other_bit = clk->enable_bit - AM35XX_IPSS_ICK_FCK_OFFSET; +} + +const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait = { + .find_idlest = am35xx_clk_find_idlest, + .find_companion = am35xx_clk_find_companion, +}; + +/** + * am35xx_clk_ipss_find_idlest - return CM_IDLEST info for IPSS + * @clk: struct clk * being enabled + * @idlest_reg: void __iomem ** to store CM_IDLEST reg address into + * @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into + * @idlest_val: pointer to a u8 to store the CM_IDLEST indicator + * + * The IPSS target CM_IDLEST bit is at a different shift from the + * CM_{I,F}CLKEN bit. Pass back the correct info via @idlest_reg + * and @idlest_bit. No return value. + */ +static void am35xx_clk_ipss_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, + u8 *idlest_val) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = AM35XX_ST_IPSS_SHIFT; + *idlest_val = OMAP34XX_CM_IDLEST_VAL; +} + +const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, + .find_idlest = am35xx_clk_ipss_find_idlest, + .find_companion = omap2_clk_dflt_find_companion, +}; + static struct ti_dt_clk omap3xxx_clks[] = { DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"), DT_CLK(NULL, "omap_32k_fck", "omap_32k_fck"), diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index c6fbd153b6d4..0ca5a36da999 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -183,6 +183,8 @@ extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait; extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; +extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; +extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; int omap2_clkops_enable_clkdm(struct clk_hw *hw); void omap2_clkops_disable_clkdm(struct clk_hw *hw); diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index cd5b3eadc317..15f3c971ccab 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -331,8 +331,6 @@ void ti_clk_setup_features(struct ti_clk_features *features); const struct ti_clk_features *ti_clk_get_features(void); extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; -extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; -extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; #ifdef CONFIG_ATAGS int omap3430_clk_legacy_init(void); -- cgit v1.3-6-gb490 From a3314e9cf69c1d4052017e559ea69a042ccd83e2 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 4 Mar 2015 21:02:05 +0200 Subject: clk: ti: move some public definitions to private header Several exported TI clock driver features are no longer needed outside the clock driver itself, thus move all of these to the driver private header file. Also, update some of the driver files to actually include this header. Signed-off-by: Tero Kristo --- drivers/clk/ti/apll.c | 2 ++ drivers/clk/ti/autoidle.c | 2 ++ drivers/clk/ti/clk-43xx.c | 2 ++ drivers/clk/ti/clk-44xx.c | 2 ++ drivers/clk/ti/clk-54xx.c | 2 ++ drivers/clk/ti/clk-7xx.c | 3 ++- drivers/clk/ti/clock.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/clk/ti.h | 45 --------------------------------------------- 8 files changed, 59 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index 49baf3831546..594b759f02ee 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -27,6 +27,8 @@ #include #include +#include "clock.h" + #define APLL_FORCE_LOCK 0x1 #define APLL_AUTO_IDLE 0x2 #define MAX_APLL_WAIT_TRIES 1000000 diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c index 3dbcc3681058..94f0dcd94181 100644 --- a/drivers/clk/ti/autoidle.c +++ b/drivers/clk/ti/autoidle.c @@ -22,6 +22,8 @@ #include #include +#include "clock.h" + struct clk_ti_autoidle { void __iomem *reg; u8 shift; diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c index 3795fce8a830..894316738459 100644 --- a/drivers/clk/ti/clk-43xx.c +++ b/drivers/clk/ti/clk-43xx.c @@ -19,6 +19,8 @@ #include #include +#include "clock.h" + static struct ti_dt_clk am43xx_clks[] = { DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c index 581db7711f51..7a8b51b35f9f 100644 --- a/drivers/clk/ti/clk-44xx.c +++ b/drivers/clk/ti/clk-44xx.c @@ -16,6 +16,8 @@ #include #include +#include "clock.h" + /* * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c index 96c69a335975..59ce2fa2c104 100644 --- a/drivers/clk/ti/clk-54xx.c +++ b/drivers/clk/ti/clk-54xx.c @@ -17,6 +17,8 @@ #include #include +#include "clock.h" + #define OMAP5_DPLL_ABE_DEFFREQ 98304000 /* diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c index 5d2217ae4478..8b827219d454 100644 --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -16,11 +16,12 @@ #include #include +#include "clock.h" + #define DRA7_DPLL_ABE_DEFFREQ 180633600 #define DRA7_DPLL_GMAC_DEFFREQ 1000000000 #define DRA7_DPLL_USB_DEFFREQ 960000000 - static struct ti_dt_clk dra7xx_clks[] = { DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"), DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"), diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 0ca5a36da999..3c43125b9cc9 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -154,6 +154,35 @@ struct ti_clk_dpll { u8 recal_st_bit; }; +/* Composite clock component types */ +enum { + CLK_COMPONENT_TYPE_GATE = 0, + CLK_COMPONENT_TYPE_DIVIDER, + CLK_COMPONENT_TYPE_MUX, + CLK_COMPONENT_TYPE_MAX, +}; + +/** + * struct ti_dt_clk - OMAP DT clock alias declarations + * @lk: clock lookup definition + * @node_name: clock DT node to map to + */ +struct ti_dt_clk { + struct clk_lookup lk; + char *node_name; +}; + +#define DT_CLK(dev, con, name) \ + { \ + .lk = { \ + .dev_id = dev, \ + .con_id = con, \ + }, \ + .node_name = name, \ + } + +typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *); + struct clk *ti_clk_register_gate(struct ti_clk *setup); struct clk *ti_clk_register_interface(struct ti_clk *setup); struct clk *ti_clk_register_mux(struct ti_clk *setup); @@ -169,6 +198,12 @@ void ti_clk_patch_legacy_clks(struct ti_clk **patch); struct clk *ti_clk_register_clk(struct ti_clk *setup); int ti_clk_register_legacy_clks(struct ti_clk_alias *clks); +void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); +void ti_dt_clocks_register(struct ti_dt_clk *oclks); +int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, + ti_of_clk_init_cb_t func); +int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type); + void omap2_init_clk_hw_omap_clocks(struct clk *clk); int of_ti_clk_autoidle_setup(struct device_node *node); void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); @@ -186,12 +221,24 @@ extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; +extern const struct clk_ops ti_clk_divider_ops; +extern const struct clk_ops ti_clk_mux_ops; + int omap2_clkops_enable_clkdm(struct clk_hw *hw); void omap2_clkops_disable_clkdm(struct clk_hw *hw); int omap2_dflt_clk_enable(struct clk_hw *hw); void omap2_dflt_clk_disable(struct clk_hw *hw); int omap2_dflt_clk_is_enabled(struct clk_hw *hw); +void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, + void __iomem **other_reg, + u8 *other_bit); +void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, + void __iomem **idlest_reg, + u8 *idlest_bit, u8 *idlest_val); + +void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); +void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); u8 omap2_init_dpll_parent(struct clk_hw *hw); int omap3_noncore_dpll_enable(struct clk_hw *hw); diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 15f3c971ccab..5eccdf5c0e84 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -188,33 +188,6 @@ struct clk_hw_omap { /* DPLL Type and DCO Selection Flags */ #define DPLL_J_TYPE 0x1 -/* Composite clock component types */ -enum { - CLK_COMPONENT_TYPE_GATE = 0, - CLK_COMPONENT_TYPE_DIVIDER, - CLK_COMPONENT_TYPE_MUX, - CLK_COMPONENT_TYPE_MAX, -}; - -/** - * struct ti_dt_clk - OMAP DT clock alias declarations - * @lk: clock lookup definition - * @node_name: clock DT node to map to - */ -struct ti_dt_clk { - struct clk_lookup lk; - char *node_name; -}; - -#define DT_CLK(dev, con, name) \ - { \ - .lk = { \ - .dev_id = dev, \ - .con_id = con, \ - }, \ - .node_name = name, \ - } - /* Static memmap indices */ enum { TI_CLKM_CM = 0, @@ -225,8 +198,6 @@ enum { CLK_MAX_MEMMAPS }; -typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *); - /** * struct clk_omap_reg - OMAP register declaration * @offset: offset from the master IP module base address @@ -266,9 +237,6 @@ struct ti_clk_ll_ops { extern struct ti_clk_ll_ops *ti_clk_ll_ops; -extern const struct clk_ops ti_clk_divider_ops; -extern const struct clk_ops ti_clk_mux_ops; - #define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) void omap2_init_clk_clkdm(struct clk_hw *clk); @@ -276,14 +244,6 @@ int omap2_clk_disable_autoidle_all(void); int omap2_clk_enable_autoidle_all(void); int omap2_clk_allow_idle(struct clk *clk); int omap2_clk_deny_idle(struct clk *clk); -void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); -void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); -void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, - void __iomem **other_reg, - u8 *other_bit); -void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, - void __iomem **idlest_reg, - u8 *idlest_bit, u8 *idlest_val); unsigned long omap2_dpllcore_recalc(struct clk_hw *hw, unsigned long parent_rate); int omap2_reprogram_dpllcore(struct clk_hw *clk, unsigned long rate, @@ -292,14 +252,9 @@ void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw); void omap2xxx_clkt_vps_init(void); unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); -void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index); -void ti_dt_clocks_register(struct ti_dt_clk *oclks); void ti_dt_clk_init_provider(struct device_node *np, int index); void ti_dt_clk_init_retry_clks(void); void ti_dt_clockdomains_setup(void); -int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, - ti_of_clk_init_cb_t func); -int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type); int omap3430_dt_clk_init(void); int omap3630_dt_clk_init(void); -- cgit v1.3-6-gb490 From e9e63088e4f93cf4ed7999294c09905b7dcb4d32 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Apr 2015 21:55:42 +0300 Subject: clk: ti: remove exported ll_ops struct, instead add an API for registration We should avoid exporting data from drivers, instead use an API for registering the clock low level operations. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/clock.c | 17 +++++++++++++---- arch/arm/mach-omap2/clock.h | 1 + arch/arm/mach-omap2/io.c | 2 ++ drivers/clk/ti/clk.c | 21 +++++++++++++++++++++ drivers/clk/ti/clock.h | 2 ++ drivers/clk/ti/clockdomain.c | 2 ++ include/linux/clk/ti.h | 3 +-- 7 files changed, 42 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 99875dba803a..40a88c2e4016 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -112,6 +112,19 @@ static struct ti_clk_ll_ops omap_clk_ll_ops = { .cm_split_idlest_reg = cm_split_idlest_reg, }; +/** + * omap2_clk_setup_ll_ops - setup clock driver low-level ops + * + * Sets up clock driver low-level platform ops. These are needed + * for register accesses and various other misc platform operations. + * Returns 0 on success, -EBUSY if low level ops have been registered + * already. + */ +int __init omap2_clk_setup_ll_ops(void) +{ + return ti_clk_setup_ll_ops(&omap_clk_ll_ops); +} + /** * omap2_clk_provider_init - initialize a clock provider * @match_table: DT device table to match for devices to init @@ -130,8 +143,6 @@ int __init omap2_clk_provider_init(struct device_node *np, int index, { struct clk_iomap *io; - ti_clk_ll_ops = &omap_clk_ll_ops; - io = kzalloc(sizeof(*io), GFP_KERNEL); io->regmap = syscon; @@ -155,8 +166,6 @@ void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem) { struct clk_iomap *io; - ti_clk_ll_ops = &omap_clk_ll_ops; - io = memblock_virt_alloc(sizeof(*io), 0); io->mem = mem; diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 1986ab216b1a..a7051d6a05e9 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -83,6 +83,7 @@ struct regmap; int __init omap2_clk_provider_init(struct device_node *np, int index, struct regmap *syscon, void __iomem *mem); void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem); +int __init omap2_clk_setup_ll_ops(void); void __init ti_clk_init_features(void); #endif diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 74678565cd97..a253aafbb9a2 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -722,6 +722,8 @@ int __init omap_clk_init(void) ti_clk_init_features(); + omap2_clk_setup_ll_ops(); + if (of_have_populated_dt()) { ret = omap_control_init(); if (ret) diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 5baea03cfc92..58b83e0af90f 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -32,6 +32,27 @@ static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; struct ti_clk_features ti_clk_features; +/** + * ti_clk_setup_ll_ops - setup low level clock operations + * @ops: low level clock ops descriptor + * + * Sets up low level clock operations for TI clock driver. This is used + * to provide various callbacks for the clock driver towards platform + * specific code. Returns 0 on success, -EBUSY if ll_ops have been + * registered already. + */ +int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops) +{ + if (ti_clk_ll_ops) { + pr_err("Attempt to register ll_ops multiple times.\n"); + return -EBUSY; + } + + ti_clk_ll_ops = ops; + + return 0; +} + /** * ti_dt_clocks_register - register DT alias clocks during boot * @oclks: list of clocks to register diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 3c43125b9cc9..d4d232fd89bc 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -280,4 +280,6 @@ long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long *best_parent_rate, struct clk_hw **best_parent_clk); +extern struct ti_clk_ll_ops *ti_clk_ll_ops; + #endif diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index 61ef87b1a688..80a7b6944d10 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -21,6 +21,8 @@ #include #include +#include "clock.h" + #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 5eccdf5c0e84..5b644313e38a 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -235,8 +235,6 @@ struct ti_clk_ll_ops { u8 *idlest_reg_id); }; -extern struct ti_clk_ll_ops *ti_clk_ll_ops; - #define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) void omap2_init_clk_clkdm(struct clk_hw *clk); @@ -255,6 +253,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); void ti_dt_clk_init_provider(struct device_node *np, int index); void ti_dt_clk_init_retry_clks(void); void ti_dt_clockdomains_setup(void); +int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops); int omap3430_dt_clk_init(void); int omap3630_dt_clk_init(void); -- cgit v1.3-6-gb490 From 989feafb84118a840ff21250a1e5f516f43e3dbb Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Mon, 27 Apr 2015 22:23:06 +0300 Subject: clk: ti: move low-level access and init code under clock driver With most of the clock code under clock driver already, the low-level register access code, and the init code for the same, is no longer needed outside the clock driver. Thus, these can be moved under clock driver also. Signed-off-by: Tero Kristo --- arch/arm/mach-omap2/clock.c | 84 --------------------------------------------- arch/arm/mach-omap2/clock.h | 5 --- drivers/clk/ti/clk.c | 75 ++++++++++++++++++++++++++++++++++++++-- include/linux/clk/ti.h | 7 +++- 4 files changed, 78 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 79cec5fbbe74..4340ba6524d1 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -23,9 +23,7 @@ #include #include #include -#include #include -#include #include #include @@ -55,41 +53,7 @@ u16 cpu_mask; #define OMAP3PLUS_DPLL_FINT_MIN 32000 #define OMAP3PLUS_DPLL_FINT_MAX 52000000 -struct clk_iomap { - struct regmap *regmap; - void __iomem *mem; -}; - -static struct clk_iomap *clk_memmaps[CLK_MAX_MEMMAPS]; - -static void clk_memmap_writel(u32 val, void __iomem *reg) -{ - struct clk_omap_reg *r = (struct clk_omap_reg *)® - struct clk_iomap *io = clk_memmaps[r->index]; - - if (io->regmap) - regmap_write(io->regmap, r->offset, val); - else - writel_relaxed(val, io->mem + r->offset); -} - -static u32 clk_memmap_readl(void __iomem *reg) -{ - u32 val; - struct clk_omap_reg *r = (struct clk_omap_reg *)® - struct clk_iomap *io = clk_memmaps[r->index]; - - if (io->regmap) - regmap_read(io->regmap, r->offset, &val); - else - val = readl_relaxed(io->mem + r->offset); - - return val; -} - static struct ti_clk_ll_ops omap_clk_ll_ops = { - .clk_readl = clk_memmap_readl, - .clk_writel = clk_memmap_writel, .clkdm_clk_enable = clkdm_clk_enable, .clkdm_clk_disable = clkdm_clk_disable, .cm_wait_module_ready = omap_cm_wait_module_ready, @@ -109,54 +73,6 @@ int __init omap2_clk_setup_ll_ops(void) return ti_clk_setup_ll_ops(&omap_clk_ll_ops); } -/** - * omap2_clk_provider_init - initialize a clock provider - * @match_table: DT device table to match for devices to init - * @np: device node pointer for the this clock provider - * @index: index for the clock provider - + @syscon: syscon regmap pointer - * @mem: iomem pointer for the clock provider memory area, only used if - * syscon is not provided - * - * Initializes a clock provider module (CM/PRM etc.), registering - * the memory mapping at specified index and initializing the - * low level driver infrastructure. Returns 0 in success. - */ -int __init omap2_clk_provider_init(struct device_node *np, int index, - struct regmap *syscon, void __iomem *mem) -{ - struct clk_iomap *io; - - io = kzalloc(sizeof(*io), GFP_KERNEL); - - io->regmap = syscon; - io->mem = mem; - - clk_memmaps[index] = io; - - ti_dt_clk_init_provider(np, index); - - return 0; -} - -/** - * omap2_clk_legacy_provider_init - initialize a legacy clock provider - * @index: index for the clock provider - * @mem: iomem pointer for the clock provider memory area - * - * Initializes a legacy clock provider memory mapping. - */ -void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem) -{ - struct clk_iomap *io; - - io = memblock_virt_alloc(sizeof(*io), 0); - - io->mem = mem; - - clk_memmaps[index] = io; -} - /* * OMAP2+ specific clock functions */ diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index f3dc04cd5538..67da640ba1c7 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -75,11 +75,6 @@ extern const struct clkops clkops_omap2_dflt; extern struct clk_functions omap2_clk_functions; -struct regmap; - -int __init omap2_clk_provider_init(struct device_node *np, int index, - struct regmap *syscon, void __iomem *mem); -void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem); int __init omap2_clk_setup_ll_ops(void); void __init ti_clk_init_features(void); diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 58b83e0af90f..07584e00677e 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "clock.h" @@ -32,6 +34,38 @@ static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; struct ti_clk_features ti_clk_features; +struct clk_iomap { + struct regmap *regmap; + void __iomem *mem; +}; + +static struct clk_iomap *clk_memmaps[CLK_MAX_MEMMAPS]; + +static void clk_memmap_writel(u32 val, void __iomem *reg) +{ + struct clk_omap_reg *r = (struct clk_omap_reg *)® + struct clk_iomap *io = clk_memmaps[r->index]; + + if (io->regmap) + regmap_write(io->regmap, r->offset, val); + else + writel_relaxed(val, io->mem + r->offset); +} + +static u32 clk_memmap_readl(void __iomem *reg) +{ + u32 val; + struct clk_omap_reg *r = (struct clk_omap_reg *)® + struct clk_iomap *io = clk_memmaps[r->index]; + + if (io->regmap) + regmap_read(io->regmap, r->offset, &val); + else + val = readl_relaxed(io->mem + r->offset); + + return val; +} + /** * ti_clk_setup_ll_ops - setup low level clock operations * @ops: low level clock ops descriptor @@ -49,6 +83,8 @@ int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops) } ti_clk_ll_ops = ops; + ops->clk_readl = clk_memmap_readl; + ops->clk_writel = clk_memmap_writel; return 0; } @@ -161,28 +197,61 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) } /** - * ti_dt_clk_init_provider - init master clock provider + * omap2_clk_provider_init - init master clock provider * @parent: master node * @index: internal index for clk_reg_ops + * @syscon: syscon regmap pointer for accessing clock registers + * @mem: iomem pointer for the clock provider memory area, only used if + * syscon is not provided * * Initializes a master clock IP block. This basically sets up the * mapping from clocks node to the memory map index. All the clocks * are then initialized through the common of_clk_init call, and the * clocks will access their memory maps based on the node layout. + * Returns 0 in success. */ -void ti_dt_clk_init_provider(struct device_node *parent, int index) +int __init omap2_clk_provider_init(struct device_node *parent, int index, + struct regmap *syscon, void __iomem *mem) { struct device_node *clocks; + struct clk_iomap *io; /* get clocks for this parent */ clocks = of_get_child_by_name(parent, "clocks"); if (!clocks) { pr_err("%s missing 'clocks' child node.\n", parent->name); - return; + return -EINVAL; } /* add clocks node info */ clocks_node_ptr[index] = clocks; + + io = kzalloc(sizeof(*io), GFP_KERNEL); + + io->regmap = syscon; + io->mem = mem; + + clk_memmaps[index] = io; + + return 0; +} + +/** + * omap2_clk_legacy_provider_init - initialize a legacy clock provider + * @index: index for the clock provider + * @mem: iomem pointer for the clock provider memory area + * + * Initializes a legacy clock provider memory mapping. + */ +void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem) +{ + struct clk_iomap *io; + + io = memblock_virt_alloc(sizeof(*io), 0); + + io->mem = mem; + + clk_memmaps[index] = io; } /** diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 5b644313e38a..9299222d680d 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -250,11 +250,16 @@ void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw); void omap2xxx_clkt_vps_init(void); unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk); -void ti_dt_clk_init_provider(struct device_node *np, int index); void ti_dt_clk_init_retry_clks(void); void ti_dt_clockdomains_setup(void); int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops); +struct regmap; + +int omap2_clk_provider_init(struct device_node *parent, int index, + struct regmap *syscon, void __iomem *mem); +void omap2_clk_legacy_provider_init(int index, void __iomem *mem); + int omap3430_dt_clk_init(void); int omap3630_dt_clk_init(void); int am35xx_dt_clk_init(void); -- cgit v1.3-6-gb490 From 5b6fd12a88a7233b58c669dc87979da9a69728b1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 2 Jun 2015 15:37:35 +0300 Subject: drm/i915: Move WaBarrierPerformanceFixDisable:skl to skl code from chv code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 65ca7514e21adbee25b8175fc909759c735d00ff Author: Damien Lespiau Date: Mon Feb 9 19:33:22 2015 +0000 drm/i915/skl: Implement WaBarrierPerformanceFixDisable got misapplied and the code landed in chv_init_workarounds() instead of the intended skl_init_workarounds(). Move it over to the right place. Cc: Damien Lespiau Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Reviewed-by: Ben Widawsky Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ringbuffer.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d934f857394d..edd47baa119c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -901,13 +901,6 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4); - if (INTEL_REVID(dev) == SKL_REVID_C0 || - INTEL_REVID(dev) == SKL_REVID_D0) - /* WaBarrierPerformanceFixDisable:skl */ - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FENCE_DEST_SLM_DISABLE | - HDC_BARRIER_PERFORMANCE_DISABLE); - return 0; } @@ -1041,6 +1034,13 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) HDC_FORCE_NON_COHERENT); } + if (INTEL_REVID(dev) == SKL_REVID_C0 || + INTEL_REVID(dev) == SKL_REVID_D0) + /* WaBarrierPerformanceFixDisable:skl */ + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FENCE_DEST_SLM_DISABLE | + HDC_BARRIER_PERFORMANCE_DISABLE); + return skl_tune_iz_hashing(ring); } -- cgit v1.3-6-gb490 From 64987fc59d90738715703362292f743b7dbbe76b Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Tue, 26 May 2015 17:50:13 +0530 Subject: drm/i915/bxt: edp1.4 Intermediate Freq support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BXT supports following intermediate link rates for edp: 2.16GHz, 2.43GHz, 3.24GHz, 4.32GHz. Adding support for programming the intermediate rates. v2: Adding clock in bxt_clk_div struct and then look for the entry with required rate (Ville) v3: 'clock' has the selected value, no need to use link_bw or rate_select for selecting pll(Ville) v4: Make bxt_dp_clk_val const and remove size (Ville) v5: Rebased v6: Removed setting of vco while rebasing in v5, adding it back Signed-off-by: Sonika Jindal Reviewed-by: Ville Syrjälä (v4) Reviewed-by: Vandana Kannan Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ddi.c | 39 ++++++++++++++++----------------------- drivers/gpu/drm/i915/intel_dp.c | 7 ++++++- 2 files changed, 22 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 832e4e141b3d..3eaf5c050573 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1348,6 +1348,7 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, /* bxt clock parameters */ struct bxt_clk_div { + int clock; uint32_t p1; uint32_t p2; uint32_t m2_int; @@ -1357,14 +1358,14 @@ struct bxt_clk_div { }; /* pre-calculated values for DP linkrates */ -static struct bxt_clk_div bxt_dp_clk_val[7] = { - /* 162 */ {4, 2, 32, 1677722, 1, 1}, - /* 270 */ {4, 1, 27, 0, 0, 1}, - /* 540 */ {2, 1, 27, 0, 0, 1}, - /* 216 */ {3, 2, 32, 1677722, 1, 1}, - /* 243 */ {4, 1, 24, 1258291, 1, 1}, - /* 324 */ {4, 1, 32, 1677722, 1, 1}, - /* 432 */ {3, 1, 32, 1677722, 1, 1} +static const struct bxt_clk_div bxt_dp_clk_val[] = { + {162000, 4, 2, 32, 1677722, 1, 1}, + {270000, 4, 1, 27, 0, 0, 1}, + {540000, 2, 1, 27, 0, 0, 1}, + {216000, 3, 2, 32, 1677722, 1, 1}, + {243000, 4, 1, 24, 1258291, 1, 1}, + {324000, 4, 1, 32, 1677722, 1, 1}, + {432000, 3, 1, 32, 1677722, 1, 1} }; static bool @@ -1404,22 +1405,14 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, vco = best_clock.vco; } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || intel_encoder->type == INTEL_OUTPUT_EDP) { - struct drm_encoder *encoder = &intel_encoder->base; - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + int i; - switch (intel_dp->link_bw) { - case DP_LINK_BW_1_62: - clk_div = bxt_dp_clk_val[0]; - break; - case DP_LINK_BW_2_7: - clk_div = bxt_dp_clk_val[1]; - break; - case DP_LINK_BW_5_4: - clk_div = bxt_dp_clk_val[2]; - break; - default: - clk_div = bxt_dp_clk_val[0]; - DRM_ERROR("Unknown link rate\n"); + clk_div = bxt_dp_clk_val[0]; + for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) { + if (bxt_dp_clk_val[i].clock == clock) { + clk_div = bxt_dp_clk_val[i]; + break; + } } vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 823a1b31177c..fb5c01e46f4b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -91,6 +91,8 @@ static const struct dp_link_dpll chv_dpll[] = { { .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } } }; +static const int bxt_rates[] = { 162000, 216000, 243000, 270000, + 324000, 432000, 540000 }; static const int skl_rates[] = { 162000, 216000, 270000, 324000, 432000, 540000 }; static const int chv_rates[] = { 162000, 202500, 210000, 216000, @@ -1170,7 +1172,10 @@ intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates) static int intel_dp_source_rates(struct drm_device *dev, const int **source_rates) { - if (IS_SKYLAKE(dev)) { + if (IS_BROXTON(dev)) { + *source_rates = bxt_rates; + return ARRAY_SIZE(bxt_rates); + } else if (IS_SKYLAKE(dev)) { *source_rates = skl_rates; return ARRAY_SIZE(skl_rates); } else if (IS_CHERRYVIEW(dev)) { -- cgit v1.3-6-gb490 From 9cc83020616d38339e6c29dc44536e9806abfdb0 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 2 Jun 2015 15:37:36 +0300 Subject: drm/i915: Set INSTPM_FORCE_ORDERING via LRI on gen8, drop it on gen9+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit INSTPM is saved in the logical context so we should initialize it using LRIs on gen8. It actually defaults to 1 starting from HSW, but let's keep the write around anyway. Also drop the INSTPM_FORCE_ORDERING setup entirely on gen9+ since it's now a reserved bit. Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index edd47baa119c..06f4b22c6327 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -800,6 +800,8 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; + WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); + /* WaDisablePartialInstShootdown:bdw */ /* WaDisableThreadStallDopClockGating:bdw (pre-production) */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, @@ -861,6 +863,8 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; + WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); + /* WaDisablePartialInstShootdown:chv */ /* WaDisableThreadStallDopClockGating:chv */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, @@ -1132,7 +1136,7 @@ static int init_render_ring(struct intel_engine_cs *ring) _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB)); } - if (INTEL_INFO(dev)->gen >= 6) + if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); if (HAS_L3_DPF(dev)) -- cgit v1.3-6-gb490 From 2441f8779e886d74389bf78aad149dc99876a900 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 2 Jun 2015 15:37:37 +0300 Subject: drm/i915: Apply WaDisableAsyncFlipPerfMode via LRIs on gen8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MI_MODE is saved in the logical context so WaDisableAsyncFlipPerfMode must be applied using LRIs on gen8. Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ringbuffer.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 06f4b22c6327..b70d25bffb60 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -802,6 +802,9 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); + /* WaDisableAsyncFlipPerfMode:bdw */ + WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); + /* WaDisablePartialInstShootdown:bdw */ /* WaDisableThreadStallDopClockGating:bdw (pre-production) */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, @@ -865,6 +868,9 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); + /* WaDisableAsyncFlipPerfMode:chv */ + WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); + /* WaDisablePartialInstShootdown:chv */ /* WaDisableThreadStallDopClockGating:chv */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, @@ -1109,9 +1115,9 @@ static int init_render_ring(struct intel_engine_cs *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,bdw,chv + * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv */ - if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 9) + if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); /* Required for the hardware to program scanline values for waiting */ -- cgit v1.3-6-gb490 From b6283055b408fd9bee5386bd71fdf5f3b5553ae5 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 3 Jun 2015 15:45:07 +0300 Subject: drm/i915: Cache current cdclk frequency in dev_priv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather that extracting the current cdclk freuqncy every time someone wants to know it, cache the current value and use that. VLV/CHV already stored a cached value there so just expand that to cover all platforms. v2: Rebased to the latest v3: Rebased to the latest v4: Rebased to the latest v5: Removed spurious call to 'intel_update_cdclk(dev)' based on Damien Lespiau's comment Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 16e159db5025..9cf155382a4f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5747,7 +5747,7 @@ static int valleyview_get_vco(struct drm_i915_private *dev_priv) return vco_freq[hpll_freq] * 1000; } -static void vlv_update_cdclk(struct drm_device *dev) +static void intel_update_cdclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5760,7 +5760,14 @@ static void vlv_update_cdclk(struct drm_device *dev) * BSpec erroneously claims we should aim for 4MHz, but * in fact 1MHz is the correct frequency. */ - I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000)); + if (IS_VALLEYVIEW(dev)) { + /* + * Program the gmbus_freq based on the cdclk frequency. + * BSpec erroneously claims we should aim for 4MHz, but + * in fact 1MHz is the correct frequency. + */ + I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000)); + } } /* Adjust CDclk dividers to allow high res or save power if possible */ @@ -5826,7 +5833,7 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) mutex_unlock(&dev_priv->sb_lock); - vlv_update_cdclk(dev); + intel_update_cdclk(dev); } static void cherryview_set_cdclk(struct drm_device *dev, int cdclk) @@ -5867,7 +5874,7 @@ static void cherryview_set_cdclk(struct drm_device *dev, int cdclk) } mutex_unlock(&dev_priv->rps.hw_lock); - vlv_update_cdclk(dev); + intel_update_cdclk(dev); } static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, @@ -9479,6 +9486,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv) } intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); + intel_update_cdclk(dev_priv->dev); } /* @@ -13273,6 +13281,8 @@ static void intel_shared_dpll_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + intel_update_cdclk(dev); + if (HAS_DDI(dev)) intel_ddi_pll_init(dev); else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) @@ -14848,13 +14858,9 @@ static void i915_disable_vga(struct drm_device *dev) void intel_modeset_init_hw(struct drm_device *dev) { + intel_update_cdclk(dev); intel_prepare_ddi(dev); - - if (IS_VALLEYVIEW(dev)) - vlv_update_cdclk(dev); - intel_init_clock_gating(dev); - intel_enable_gt_powersave(dev); } -- cgit v1.3-6-gb490 From 05024da3c2482e26e94fb3a8324a355c066d2faf Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 3 Jun 2015 15:45:08 +0300 Subject: drm/i915: Use cached cdclk value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than reading out the current cdclk value use the cached value we have tucked away in dev_priv. v2: Rebased to the latest v3: Rebased to the latest v4: Fix for patch style problems Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 3 +-- drivers/gpu/drm/i915/intel_dp.c | 5 +++-- drivers/gpu/drm/i915/intel_pm.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9cf155382a4f..d1dd8abaf1f1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6610,8 +6610,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, /* FIXME should check pixel clock limits on all platforms */ if (INTEL_INFO(dev)->gen < 4) { - int clock_limit = - dev_priv->display.get_display_clock_speed(dev); + int clock_limit = dev_priv->cdclk_freq; /* * Enable pixel doubling when the dot clock diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fb5c01e46f4b..f73da99e66b8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -710,7 +710,8 @@ static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index) return 0; if (intel_dig_port->port == PORT_A) { - return DIV_ROUND_UP(dev_priv->display.get_display_clock_speed(dev), 2000); + return DIV_ROUND_UP(dev_priv->cdclk_freq, 2000); + } else { return DIV_ROUND_UP(intel_pch_rawclk(dev), 2); } @@ -725,7 +726,7 @@ static uint32_t hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index) if (intel_dig_port->port == PORT_A) { if (index) return 0; - return DIV_ROUND_CLOSEST(dev_priv->display.get_display_clock_speed(dev), 2000); + return DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 2000); } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { /* Workaround for non-ULT HSW */ switch (index) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index eadc15cddbeb..5db429e92be5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1815,7 +1815,7 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) linetime = DIV_ROUND_CLOSEST(mode->crtc_htotal * 1000 * 8, mode->crtc_clock); ips_linetime = DIV_ROUND_CLOSEST(mode->crtc_htotal * 1000 * 8, - dev_priv->display.get_display_clock_speed(dev_priv->dev)); + dev_priv->cdclk_freq); return PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) | PIPE_WM_LINETIME_TIME(linetime); -- cgit v1.3-6-gb490 From 44913155f036ae966f09a7bc0d299c31876b4383 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 3 Jun 2015 15:45:10 +0300 Subject: drm/i915: Store max cdclk value in dev_priv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep the cdclk maximum supported frequency around in dev_priv so that we can verify certain things against it before actually changing the cdclk frequency. For now only VLV/CHV have support changing cdclk frequency, so other plarforms get to assume cdclk is fixed. v2: Rebased to the latest v3: Rebased to the latest v4: Fix for patch style problems Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_display.c | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 60aa9626f91f..db9e268629b2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1743,7 +1743,7 @@ struct drm_i915_private { unsigned int fsb_freq, mem_freq, is_ddr3; unsigned int skl_boot_cdclk; - unsigned int cdclk_freq; + unsigned int cdclk_freq, max_cdclk_freq; unsigned int hpll_freq; /** diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d1dd8abaf1f1..445385dd062a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5747,6 +5747,21 @@ static int valleyview_get_vco(struct drm_i915_private *dev_priv) return vco_freq[hpll_freq] * 1000; } +static void intel_update_max_cdclk(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_VALLEYVIEW(dev)) { + dev_priv->max_cdclk_freq = 400000; + } else { + /* otherwise assume cdclk is fixed */ + dev_priv->max_cdclk_freq = dev_priv->cdclk_freq; + } + + DRM_DEBUG_DRIVER("Max CD clock rate: %d kHz\n", + dev_priv->max_cdclk_freq); +} + static void intel_update_cdclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5768,6 +5783,9 @@ static void intel_update_cdclk(struct drm_device *dev) */ I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000)); } + + if (dev_priv->max_cdclk_freq == 0) + intel_update_max_cdclk(dev); } /* Adjust CDclk dividers to allow high res or save power if possible */ @@ -6610,7 +6628,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, /* FIXME should check pixel clock limits on all platforms */ if (INTEL_INFO(dev)->gen < 4) { - int clock_limit = dev_priv->cdclk_freq; + int clock_limit = dev_priv->max_cdclk_freq; /* * Enable pixel doubling when the dot clock -- cgit v1.3-6-gb490 From 8cfb340774744438dea08a32072bea4a162dd132 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 3 Jun 2015 15:45:11 +0300 Subject: drm/i915: Don't enable IPS when pixel rate exceeds 95% MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bspec says we shouldn't enable IPS on BDW when the pipe pixel rate exceeds 95% of the core display clock. Apparently this can cause underruns. There's no similar restriction listed for HSW, so leave that one alone for now. v2: Add pipe_config_supports_ips() (Chris) v3: Compare against the max cdclk insted of the current cdclk v4: Rebased to the latest v5: Rebased to the latest v6: Fix for patch style problems Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=83497 Tested-by: Timo Aaltonen Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 30 ++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 17 ++++++++--------- 3 files changed, 37 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 445385dd062a..c3f01aa9b510 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6610,12 +6610,38 @@ retry: return ret; } +static bool pipe_config_supports_ips(struct drm_i915_private *dev_priv, + struct intel_crtc_state *pipe_config) +{ + if (pipe_config->pipe_bpp > 24) + return false; + + /* HSW can handle pixel rate up to cdclk? */ + if (IS_HASWELL(dev_priv->dev)) + return true; + + /* + * FIXME if we compare against max we should then + * increase the cdclk frequency when the current + * value is too low. The other option is to compare + * against the cdclk frequency we're going have post + * modeset (ie. one we computed using other constraints). + * Need to measure whether using a lower cdclk w/o IPS + * is better or worse than a higher cdclk w/ IPS. + */ + return ilk_pipe_pixel_rate(pipe_config) <= + dev_priv->max_cdclk_freq * 95 / 100; +} + static void hsw_compute_ips_config(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + pipe_config->ips_enabled = i915.enable_ips && - hsw_crtc_supports_ips(crtc) && - pipe_config->pipe_bpp <= 24; + hsw_crtc_supports_ips(crtc) && + pipe_config_supports_ips(dev_priv, pipe_config); } static int intel_crtc_compute_config(struct intel_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2afb31a46275..5cb30044acf4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1375,7 +1375,7 @@ void ilk_wm_get_hw_state(struct drm_device *dev); void skl_wm_get_hw_state(struct drm_device *dev); void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, struct skl_ddb_allocation *ddb /* out */); - +uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config); /* intel_sdvo.c */ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5db429e92be5..d091fec1e101 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1434,23 +1434,22 @@ static void i845_update_wm(struct drm_crtc *unused_crtc) I915_WRITE(FW_BLC, fwater_lo); } -static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev, - struct drm_crtc *crtc) +uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t pixel_rate; - pixel_rate = intel_crtc->config->base.adjusted_mode.crtc_clock; + pixel_rate = pipe_config->base.adjusted_mode.crtc_clock; /* We only use IF-ID interlacing. If we ever use PF-ID we'll need to * adjust the pixel_rate here. */ - if (intel_crtc->config->pch_pfit.enabled) { + if (pipe_config->pch_pfit.enabled) { uint64_t pipe_w, pipe_h, pfit_w, pfit_h; - uint32_t pfit_size = intel_crtc->config->pch_pfit.size; + uint32_t pfit_size = pipe_config->pch_pfit.size; + + pipe_w = pipe_config->pipe_src_w; + pipe_h = pipe_config->pipe_src_h; - pipe_w = intel_crtc->config->pipe_src_w; - pipe_h = intel_crtc->config->pipe_src_h; pfit_w = (pfit_size >> 16) & 0xFFFF; pfit_h = pfit_size & 0xFFFF; if (pipe_w < pfit_w) @@ -2066,7 +2065,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc, p->active = true; p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal; - p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc); + p->pixel_rate = ilk_pipe_pixel_rate(intel_crtc->config); if (crtc->primary->state->fb) p->pri.bytes_per_pixel = -- cgit v1.3-6-gb490 From ebb72aad41e231fe5c586785dbbf5910867e7978 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 3 Jun 2015 15:45:12 +0300 Subject: drm/i915: Add IS_BDW_ULX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to tell BDW ULT and ULX apart. v2: Rebased to the latest v3: Rebased to the latest v4: Fix for patch style problems Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index db9e268629b2..46722f85ef76 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2399,6 +2399,9 @@ struct drm_i915_cmd_table { ((INTEL_DEVID(dev) & 0xf) == 0x6 || \ (INTEL_DEVID(dev) & 0xf) == 0xb || \ (INTEL_DEVID(dev) & 0xf) == 0xe)) +/* ULX machines are also considered ULT. */ +#define IS_BDW_ULX(dev) (IS_BROADWELL(dev) && \ + (INTEL_DEVID(dev) & 0xf) == 0xe) #define IS_BDW_GT3(dev) (IS_BROADWELL(dev) && \ (INTEL_DEVID(dev) & 0x00F0) == 0x0020) #define IS_HSW_ULT(dev) (IS_HASWELL(dev) && \ -- cgit v1.3-6-gb490 From b432e5cfd5e92127ad2dd83bfc3083f1dbce43fb Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 3 Jun 2015 15:45:13 +0300 Subject: drm/i915: BDW clock change support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for changing cdclk frequency during runtime on BDW. Also with IPS enabled the actual pixel rate mustn't exceed 95% of cdclk, so take that into account when computing the max pixel rate. v2: Grab rps.hw_lock around sandybridge_pcode_write() v3: Rebase due to power well vs. .global_resources() reordering v4: Rebased to the latest v5: Rebased to the latest v6: Patch order shuffle so that Broadwell CD clock change is applied before the patch for Haswell CD clock change v7: Fix for patch style problems Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_reg.h | 2 + drivers/gpu/drm/i915/intel_display.c | 216 +++++++++++++++++++++++++++++++++-- 2 files changed, 208 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 00cec1f70b64..89fd7c8a1525 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6705,6 +6705,7 @@ enum skl_disp_power_wells { #define GEN6_PCODE_READ_RC6VIDS 0x5 #define GEN6_ENCODE_RC6_VID(mv) (((mv) - 245) / 5) #define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) +#define BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ 0x18 #define GEN9_PCODE_READ_MEM_LATENCY 0x6 #define GEN9_MEM_LATENCY_LEVEL_MASK 0xFF #define GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT 8 @@ -7167,6 +7168,7 @@ enum skl_disp_power_wells { #define LCPLL_CLK_FREQ_337_5_BDW (2<<26) #define LCPLL_CLK_FREQ_675_BDW (3<<26) #define LCPLL_CD_CLOCK_DISABLE (1<<25) +#define LCPLL_ROOT_CD_CLOCK_DISABLE (1<<24) #define LCPLL_CD2X_CLOCK_DISABLE (1<<23) #define LCPLL_POWER_DOWN_ALLOW (1<<22) #define LCPLL_CD_SOURCE_FCLK (1<<21) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c3f01aa9b510..b1e206933b95 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5751,7 +5751,22 @@ static void intel_update_max_cdclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_VALLEYVIEW(dev)) { + if (IS_BROADWELL(dev)) { + /* + * FIXME with extra cooling we can allow + * 540 MHz for ULX and 675 Mhz for ULT. + * How can we know if extra cooling is + * available? PCI ID, VTB, something else? + */ + if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) + dev_priv->max_cdclk_freq = 450000; + else if (IS_BDW_ULX(dev)) + dev_priv->max_cdclk_freq = 450000; + else if (IS_BDW_ULT(dev)) + dev_priv->max_cdclk_freq = 540000; + else + dev_priv->max_cdclk_freq = 675000; + } else if (IS_VALLEYVIEW(dev)) { dev_priv->max_cdclk_freq = 400000; } else { /* otherwise assume cdclk is fixed */ @@ -6621,13 +6636,11 @@ static bool pipe_config_supports_ips(struct drm_i915_private *dev_priv, return true; /* - * FIXME if we compare against max we should then - * increase the cdclk frequency when the current - * value is too low. The other option is to compare - * against the cdclk frequency we're going have post - * modeset (ie. one we computed using other constraints). - * Need to measure whether using a lower cdclk w/o IPS - * is better or worse than a higher cdclk w/ IPS. + * We compare against max which means we must take + * the increased cdclk requirement into account when + * calculating the new cdclk. + * + * Should measure whether using a lower cdclk w/o IPS */ return ilk_pipe_pixel_rate(pipe_config) <= dev_priv->max_cdclk_freq * 95 / 100; @@ -9608,6 +9621,182 @@ static void broxton_modeset_global_resources(struct drm_atomic_state *old_state) broxton_set_cdclk(dev, req_cdclk); } +/* compute the max rate for new configuration */ +static int ilk_max_pixel_rate(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *intel_crtc; + struct drm_crtc *crtc; + int max_pixel_rate = 0; + int pixel_rate; + + for_each_crtc(dev, crtc) { + if (!crtc->state->enable) + continue; + + intel_crtc = to_intel_crtc(crtc); + pixel_rate = ilk_pipe_pixel_rate(intel_crtc->config); + + /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ + if (IS_BROADWELL(dev) && intel_crtc->config->ips_enabled) + pixel_rate = DIV_ROUND_UP(pixel_rate * 100, 95); + + max_pixel_rate = max(max_pixel_rate, pixel_rate); + } + + return max_pixel_rate; +} + +static void broadwell_set_cdclk(struct drm_device *dev, int cdclk) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t val, data; + int ret; + + if (WARN((I915_READ(LCPLL_CTL) & + (LCPLL_PLL_DISABLE | LCPLL_PLL_LOCK | + LCPLL_CD_CLOCK_DISABLE | LCPLL_ROOT_CD_CLOCK_DISABLE | + LCPLL_CD2X_CLOCK_DISABLE | LCPLL_POWER_DOWN_ALLOW | + LCPLL_CD_SOURCE_FCLK)) != LCPLL_PLL_LOCK, + "trying to change cdclk frequency with cdclk not enabled\n")) + return; + + mutex_lock(&dev_priv->rps.hw_lock); + ret = sandybridge_pcode_write(dev_priv, + BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ, 0x0); + mutex_unlock(&dev_priv->rps.hw_lock); + if (ret) { + DRM_ERROR("failed to inform pcode about cdclk change\n"); + return; + } + + val = I915_READ(LCPLL_CTL); + val |= LCPLL_CD_SOURCE_FCLK; + I915_WRITE(LCPLL_CTL, val); + + if (wait_for_atomic_us(I915_READ(LCPLL_CTL) & + LCPLL_CD_SOURCE_FCLK_DONE, 1)) + DRM_ERROR("Switching to FCLK failed\n"); + + val = I915_READ(LCPLL_CTL); + val &= ~LCPLL_CLK_FREQ_MASK; + + switch (cdclk) { + case 450000: + val |= LCPLL_CLK_FREQ_450; + data = 0; + break; + case 540000: + val |= LCPLL_CLK_FREQ_54O_BDW; + data = 1; + break; + case 337500: + val |= LCPLL_CLK_FREQ_337_5_BDW; + data = 2; + break; + case 675000: + val |= LCPLL_CLK_FREQ_675_BDW; + data = 3; + break; + default: + WARN(1, "invalid cdclk frequency\n"); + return; + } + + I915_WRITE(LCPLL_CTL, val); + + val = I915_READ(LCPLL_CTL); + val &= ~LCPLL_CD_SOURCE_FCLK; + I915_WRITE(LCPLL_CTL, val); + + if (wait_for_atomic_us((I915_READ(LCPLL_CTL) & + LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1)) + DRM_ERROR("Switching back to LCPLL failed\n"); + + mutex_lock(&dev_priv->rps.hw_lock); + sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, data); + mutex_unlock(&dev_priv->rps.hw_lock); + + intel_update_cdclk(dev); + + WARN(cdclk != dev_priv->cdclk_freq, + "cdclk requested %d kHz but got %d kHz\n", + cdclk, dev_priv->cdclk_freq); +} + +static int broadwell_calc_cdclk(struct drm_i915_private *dev_priv, + int max_pixel_rate) +{ + int cdclk; + + /* + * FIXME should also account for plane ratio + * once 64bpp pixel formats are supported. + */ + if (max_pixel_rate > 540000) + cdclk = 675000; + else if (max_pixel_rate > 450000) + cdclk = 540000; + else if (max_pixel_rate > 337500) + cdclk = 450000; + else + cdclk = 337500; + + /* + * FIXME move the cdclk caclulation to + * compute_config() so we can fail gracegully. + */ + if (cdclk > dev_priv->max_cdclk_freq) { + DRM_ERROR("requested cdclk (%d kHz) exceeds max (%d kHz)\n", + cdclk, dev_priv->max_cdclk_freq); + cdclk = dev_priv->max_cdclk_freq; + } + + return cdclk; +} + +static int broadwell_modeset_global_pipes(struct drm_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->dev); + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int max_pixclk = ilk_max_pixel_rate(dev_priv); + int cdclk, i; + + cdclk = broadwell_calc_cdclk(dev_priv, max_pixclk); + + if (cdclk == dev_priv->cdclk_freq) + return 0; + + /* add all active pipes to the state */ + for_each_crtc(state->dev, crtc) { + if (!crtc->state->enable) + continue; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + } + + /* disable/enable all currently active pipes while we change cdclk */ + for_each_crtc_in_state(state, crtc, crtc_state, i) + if (crtc_state->enable) + crtc_state->mode_changed = true; + + return 0; +} + +static void broadwell_modeset_global_resources(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixel_rate = ilk_max_pixel_rate(dev_priv); + int req_cdclk = broadwell_calc_cdclk(dev_priv, max_pixel_rate); + + if (req_cdclk != dev_priv->cdclk_freq) + broadwell_set_cdclk(dev, req_cdclk); +} + static int haswell_crtc_compute_clock(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state) { @@ -12788,8 +12977,12 @@ static int __intel_set_mode_checks(struct drm_atomic_state *state) * mode set on this crtc. For other crtcs we need to use the * adjusted_mode bits in the crtc directly. */ - if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) { - ret = valleyview_modeset_global_pipes(state); + if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev) || IS_BROADWELL(dev)) { + if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) + ret = valleyview_modeset_global_pipes(state); + else + ret = broadwell_modeset_global_pipes(state); + if (ret) return ret; } @@ -14677,6 +14870,9 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; + if (IS_BROADWELL(dev)) + dev_priv->display.modeset_global_resources = + broadwell_modeset_global_resources; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.modeset_global_resources = valleyview_modeset_global_resources; -- cgit v1.3-6-gb490 From 70d0c5742013b888a9254f54ee527e9941171297 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:29 +0100 Subject: drm/i915: Make broxton_set_cdclk() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b1e206933b95..7e8b583527e9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5346,7 +5346,7 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) intel_display_set_init_power(dev_priv, false); } -void broxton_set_cdclk(struct drm_device *dev, int frequency) +static void broxton_set_cdclk(struct drm_device *dev, int frequency) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t divider; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5cb30044acf4..5c9d6217f371 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1113,7 +1113,6 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv); void hsw_disable_pc8(struct drm_i915_private *dev_priv); void broxton_init_cdclk(struct drm_device *dev); void broxton_uninit_cdclk(struct drm_device *dev); -void broxton_set_cdclk(struct drm_device *dev, int frequency); void broxton_ddi_phy_init(struct drm_device *dev); void broxton_ddi_phy_uninit(struct drm_device *dev); void bxt_enable_dc9(struct drm_i915_private *dev_priv); -- cgit v1.3-6-gb490 From a9419e846bd8c8e00c1d28282de936523229eff7 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:30 +0100 Subject: drm/i915/skl: Derive the max CDCLK from DFSM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_reg.h | 7 +++++++ drivers/gpu/drm/i915/intel_display.c | 13 ++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 89fd7c8a1525..760dbebc1aef 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5761,6 +5761,13 @@ enum skl_disp_power_wells { #define HSW_NDE_RSTWRN_OPT 0x46408 #define RESET_PCH_HANDSHAKE_ENABLE (1<<4) +#define SKL_DFSM 0x51000 +#define SKL_DFSM_CDCLK_LIMIT_MASK (3 << 23) +#define SKL_DFSM_CDCLK_LIMIT_675 (0 << 23) +#define SKL_DFSM_CDCLK_LIMIT_540 (1 << 23) +#define SKL_DFSM_CDCLK_LIMIT_450 (2 << 23) +#define SKL_DFSM_CDCLK_LIMIT_337_5 (3 << 23) + #define FF_SLICE_CS_CHICKEN2 0x20e4 #define GEN9_TSG_BARRIER_ACK_DISABLE (1<<8) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e8b583527e9..9280e76505fc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5751,7 +5751,18 @@ static void intel_update_max_cdclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_BROADWELL(dev)) { + if (IS_SKYLAKE(dev)) { + u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK; + + if (limit == SKL_DFSM_CDCLK_LIMIT_675) + dev_priv->max_cdclk_freq = 675000; + else if (limit == SKL_DFSM_CDCLK_LIMIT_540) + dev_priv->max_cdclk_freq = 540000; + else if (limit == SKL_DFSM_CDCLK_LIMIT_450) + dev_priv->max_cdclk_freq = 450000; + else + dev_priv->max_cdclk_freq = 337500; + } else if (IS_BROADWELL(dev)) { /* * FIXME with extra cooling we can allow * 540 MHz for ULX and 675 Mhz for ULT. -- cgit v1.3-6-gb490 From 414355a7c3f029b762518d73a6ea7e4d07d48e34 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:31 +0100 Subject: drm/i915/skl: Don't warn if reading back DPLL0 is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can operate with DPLL0 off with CDCLK backed by the 24Mhz reference clock, and that's a supported configuration. Don't warn when notice DPLL0 is off then. We still have a separate warn at boot if cdclk is disabled (because we don't currently try to handle the case (that shouldn't happen on SKL as far as I know) where we boot with display not initialized. Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9280e76505fc..0a3456988c12 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6737,10 +6737,8 @@ static int skylake_get_display_clock_speed(struct drm_device *dev) uint32_t cdctl = I915_READ(CDCLK_CTL); uint32_t linkrate; - if (!(lcpll1 & LCPLL_PLL_ENABLE)) { - WARN(1, "LCPLL1 not enabled\n"); + if (!(lcpll1 & LCPLL_PLL_ENABLE)) return 24000; /* 24MHz is the cd freq with NSSC ref */ - } if ((cdctl & CDCLK_FREQ_SEL_MASK) == CDCLK_FREQ_540) return 540000; -- cgit v1.3-6-gb490 From d9062ae59de1025bdd15988a4030d6e667c389d0 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:32 +0100 Subject: drm/i915: Don't display the boot CDCLK twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_update_cdclk() will already display the boot CDCLK for DDI platforms, no need to repeat there. Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ddi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3eaf5c050573..fff494412fe6 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2517,7 +2517,6 @@ void intel_ddi_pll_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t val = I915_READ(LCPLL_CTL); - int cdclk_freq; if (IS_SKYLAKE(dev)) skl_shared_dplls_init(dev_priv); @@ -2526,10 +2525,10 @@ void intel_ddi_pll_init(struct drm_device *dev) else hsw_shared_dplls_init(dev_priv); - cdclk_freq = dev_priv->display.get_display_clock_speed(dev); - DRM_DEBUG_KMS("CDCLK running at %dKHz\n", cdclk_freq); - if (IS_SKYLAKE(dev)) { + int cdclk_freq; + + cdclk_freq = dev_priv->display.get_display_clock_speed(dev); dev_priv->skl_boot_cdclk = cdclk_freq; if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) DRM_ERROR("LCPLL1 is disabled\n"); -- cgit v1.3-6-gb490 From 560a7ae4b6f679927876b0dfcc1fcdfabdd20684 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:33 +0100 Subject: drm/i915/skl: Update the cached CDCLK at the end of set_cdclk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville's and Mika's cdclk series was in flight at the same time as the SKL S3 patches so we were missing that update. intel_update_max_cdclk() and intel_update_cdclk() had to be moved up a bit to avoid forward declarations. Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 137 ++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0a3456988c12..17070deaf798 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5346,6 +5346,73 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) intel_display_set_init_power(dev_priv, false); } +static void intel_update_max_cdclk(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_SKYLAKE(dev)) { + u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK; + + if (limit == SKL_DFSM_CDCLK_LIMIT_675) + dev_priv->max_cdclk_freq = 675000; + else if (limit == SKL_DFSM_CDCLK_LIMIT_540) + dev_priv->max_cdclk_freq = 540000; + else if (limit == SKL_DFSM_CDCLK_LIMIT_450) + dev_priv->max_cdclk_freq = 450000; + else + dev_priv->max_cdclk_freq = 337500; + } else if (IS_BROADWELL(dev)) { + /* + * FIXME with extra cooling we can allow + * 540 MHz for ULX and 675 Mhz for ULT. + * How can we know if extra cooling is + * available? PCI ID, VTB, something else? + */ + if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) + dev_priv->max_cdclk_freq = 450000; + else if (IS_BDW_ULX(dev)) + dev_priv->max_cdclk_freq = 450000; + else if (IS_BDW_ULT(dev)) + dev_priv->max_cdclk_freq = 540000; + else + dev_priv->max_cdclk_freq = 675000; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->max_cdclk_freq = 400000; + } else { + /* otherwise assume cdclk is fixed */ + dev_priv->max_cdclk_freq = dev_priv->cdclk_freq; + } + + DRM_DEBUG_DRIVER("Max CD clock rate: %d kHz\n", + dev_priv->max_cdclk_freq); +} + +static void intel_update_cdclk(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->cdclk_freq = dev_priv->display.get_display_clock_speed(dev); + DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n", + dev_priv->cdclk_freq); + + /* + * Program the gmbus_freq based on the cdclk frequency. + * BSpec erroneously claims we should aim for 4MHz, but + * in fact 1MHz is the correct frequency. + */ + if (IS_VALLEYVIEW(dev)) { + /* + * Program the gmbus_freq based on the cdclk frequency. + * BSpec erroneously claims we should aim for 4MHz, but + * in fact 1MHz is the correct frequency. + */ + I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000)); + } + + if (dev_priv->max_cdclk_freq == 0) + intel_update_max_cdclk(dev); +} + static void broxton_set_cdclk(struct drm_device *dev, int frequency) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5637,6 +5704,7 @@ static bool skl_cdclk_wait_for_pcu_ready(struct drm_i915_private *dev_priv) static void skl_set_cdclk(struct drm_i915_private *dev_priv, unsigned int freq) { + struct drm_device *dev = dev_priv->dev; u32 freq_select, pcu_ack; DRM_DEBUG_DRIVER("Changing CDCLK to %dKHz\n", freq); @@ -5677,6 +5745,8 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, unsigned int freq) mutex_lock(&dev_priv->rps.hw_lock); sandybridge_pcode_write(dev_priv, SKL_PCODE_CDCLK_CONTROL, pcu_ack); mutex_unlock(&dev_priv->rps.hw_lock); + + intel_update_cdclk(dev); } void skl_uninit_cdclk(struct drm_i915_private *dev_priv) @@ -5747,73 +5817,6 @@ static int valleyview_get_vco(struct drm_i915_private *dev_priv) return vco_freq[hpll_freq] * 1000; } -static void intel_update_max_cdclk(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (IS_SKYLAKE(dev)) { - u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK; - - if (limit == SKL_DFSM_CDCLK_LIMIT_675) - dev_priv->max_cdclk_freq = 675000; - else if (limit == SKL_DFSM_CDCLK_LIMIT_540) - dev_priv->max_cdclk_freq = 540000; - else if (limit == SKL_DFSM_CDCLK_LIMIT_450) - dev_priv->max_cdclk_freq = 450000; - else - dev_priv->max_cdclk_freq = 337500; - } else if (IS_BROADWELL(dev)) { - /* - * FIXME with extra cooling we can allow - * 540 MHz for ULX and 675 Mhz for ULT. - * How can we know if extra cooling is - * available? PCI ID, VTB, something else? - */ - if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) - dev_priv->max_cdclk_freq = 450000; - else if (IS_BDW_ULX(dev)) - dev_priv->max_cdclk_freq = 450000; - else if (IS_BDW_ULT(dev)) - dev_priv->max_cdclk_freq = 540000; - else - dev_priv->max_cdclk_freq = 675000; - } else if (IS_VALLEYVIEW(dev)) { - dev_priv->max_cdclk_freq = 400000; - } else { - /* otherwise assume cdclk is fixed */ - dev_priv->max_cdclk_freq = dev_priv->cdclk_freq; - } - - DRM_DEBUG_DRIVER("Max CD clock rate: %d kHz\n", - dev_priv->max_cdclk_freq); -} - -static void intel_update_cdclk(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - dev_priv->cdclk_freq = dev_priv->display.get_display_clock_speed(dev); - DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n", - dev_priv->cdclk_freq); - - /* - * Program the gmbus_freq based on the cdclk frequency. - * BSpec erroneously claims we should aim for 4MHz, but - * in fact 1MHz is the correct frequency. - */ - if (IS_VALLEYVIEW(dev)) { - /* - * Program the gmbus_freq based on the cdclk frequency. - * BSpec erroneously claims we should aim for 4MHz, but - * in fact 1MHz is the correct frequency. - */ - I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000)); - } - - if (dev_priv->max_cdclk_freq == 0) - intel_update_max_cdclk(dev); -} - /* Adjust CDclk dividers to allow high res or save power if possible */ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) { -- cgit v1.3-6-gb490 From a47871bd8ac2954b486272faa2a92831a69b1b8e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:34 +0100 Subject: drm/i915/bxt: Use intel_update_cdclk() to update dev_priv->cdclk_freq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 17070deaf798..58846b58b676 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5529,7 +5529,7 @@ static void broxton_set_cdclk(struct drm_device *dev, int frequency) return; } - dev_priv->cdclk_freq = frequency; + intel_update_cdclk(dev); } void broxton_init_cdclk(struct drm_device *dev) -- cgit v1.3-6-gb490 From 6455c870e97b7e8a6cf7aacba8ea19087b7db973 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:23:57 +0100 Subject: drm/i915: Make pc8_status report status for all runtime PM platforms Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 3e17210c3277..8d25ce4a40db 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2476,13 +2476,13 @@ static int i915_energy_uJ(struct seq_file *m, void *data) return 0; } -static int i915_pc8_status(struct seq_file *m, void *unused) +static int i915_runtime_pm_status(struct seq_file *m, void *unused) { struct drm_info_node *node = m->private; struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { + if (!HAS_RUNTIME_PM(dev)) { seq_puts(m, "not supported\n"); return 0; } @@ -5039,7 +5039,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"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_runtime_pm_status", i915_runtime_pm_status, 0}, {"i915_power_domain_info", i915_power_domain_info, 0}, {"i915_display_info", i915_display_info, 0}, {"i915_semaphore_status", i915_semaphore_status, 0}, -- cgit v1.3-6-gb490 From a6aaec8be22652a808d6e316d4a92e58cb75e986 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:23:58 +0100 Subject: drm/i915: Add runtime PM's usage_count in i915_runtime_pm_status Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_debugfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 8d25ce4a40db..47d9854434c5 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2490,6 +2490,8 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused) seq_printf(m, "GPU idle: %s\n", yesno(!dev_priv->mm.busy)); seq_printf(m, "IRQs disabled: %s\n", yesno(!intel_irqs_enabled(dev_priv))); + seq_printf(m, "Usage count: %d\n", + atomic_read(&dev->dev->power.usage_count)); return 0; } -- cgit v1.3-6-gb490 From fe4c63c8cbd22251f8ce8bcb7853e46385f7af82 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jun 2015 18:01:35 +0300 Subject: drm/i915/bxt: fix DDI PHY vswing scale value setting According to bspec the DDI PHY vswing scale value is "don't care" in case the scale enable bit [27] is clear. But this doesn't seem to be correct. The scale value seems to also matter if the scale mode bit [26] is set. So both bit 26 and 27 depend on the value. Setting the scale value to 0 while either bit is set results in a failed modeset on HDMI (sink reports no signal). After reset the scale value is 0x98, but according to the spec we have to program it to 0x9a. So for consistency program it always to 0x9a regardless of the scale enable bit. Signed-off-by: Imre Deak Tested-by: Matt Roper Acked-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ddi.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index fff494412fe6..31b29e8781ac 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -181,15 +181,15 @@ struct bxt_ddi_buf_trans { */ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { /* Idx NT mV diff db */ - { 52, 0, 0, 128, true }, /* 0: 400 0 */ - { 78, 0, 0, 85, false }, /* 1: 400 3.5 */ - { 104, 0, 0, 64, false }, /* 2: 400 6 */ - { 154, 0, 0, 43, false }, /* 3: 400 9.5 */ - { 77, 0, 0, 128, false }, /* 4: 600 0 */ - { 116, 0, 0, 85, false }, /* 5: 600 3.5 */ - { 154, 0, 0, 64, false }, /* 6: 600 6 */ - { 102, 0, 0, 128, false }, /* 7: 800 0 */ - { 154, 0, 0, 85, false }, /* 8: 800 3.5 */ + { 52, 0x9A, 0, 128, true }, /* 0: 400 0 */ + { 78, 0x9A, 0, 85, false }, /* 1: 400 3.5 */ + { 104, 0x9A, 0, 64, false }, /* 2: 400 6 */ + { 154, 0x9A, 0, 43, false }, /* 3: 400 9.5 */ + { 77, 0x9A, 0, 128, false }, /* 4: 600 0 */ + { 116, 0x9A, 0, 85, false }, /* 5: 600 3.5 */ + { 154, 0x9A, 0, 64, false }, /* 6: 600 6 */ + { 102, 0x9A, 0, 128, false }, /* 7: 800 0 */ + { 154, 0x9A, 0, 85, false }, /* 8: 800 3.5 */ { 154, 0x9A, 1, 128, false }, /* 9: 1200 0 */ }; @@ -198,15 +198,15 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { */ static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = { /* Idx NT mV diff db */ - { 52, 0, 0, 128, false }, /* 0: 400 0 */ - { 52, 0, 0, 85, false }, /* 1: 400 3.5 */ - { 52, 0, 0, 64, false }, /* 2: 400 6 */ - { 42, 0, 0, 43, false }, /* 3: 400 9.5 */ - { 77, 0, 0, 128, false }, /* 4: 600 0 */ - { 77, 0, 0, 85, false }, /* 5: 600 3.5 */ - { 77, 0, 0, 64, false }, /* 6: 600 6 */ - { 102, 0, 0, 128, false }, /* 7: 800 0 */ - { 102, 0, 0, 85, false }, /* 8: 800 3.5 */ + { 52, 0x9A, 0, 128, false }, /* 0: 400 0 */ + { 52, 0x9A, 0, 85, false }, /* 1: 400 3.5 */ + { 52, 0x9A, 0, 64, false }, /* 2: 400 6 */ + { 42, 0x9A, 0, 43, false }, /* 3: 400 9.5 */ + { 77, 0x9A, 0, 128, false }, /* 4: 600 0 */ + { 77, 0x9A, 0, 85, false }, /* 5: 600 3.5 */ + { 77, 0x9A, 0, 64, false }, /* 6: 600 6 */ + { 102, 0x9A, 0, 128, false }, /* 7: 800 0 */ + { 102, 0x9A, 0, 85, false }, /* 8: 800 3.5 */ { 154, 0x9A, 1, 128, true }, /* 9: 1200 0 */ }; -- cgit v1.3-6-gb490 From 41da1f5d492b4bfef04419feb12ee9b0ea0517cb Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:45 +0200 Subject: drm/i915: get rid of put_shared_dpll Now that the pll updates are staged the put_shared_dpll function consists only of checks that are done in check_shared_dpll_state after a modeset too. The changes to pll->config are overwritten by intel_shared_dpll_commit, so this entire function is a noop. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 34 +++------------------------------- drivers/gpu/drm/i915/intel_drv.h | 1 - 2 files changed, 3 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 58846b58b676..9d271172dddd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4199,27 +4199,6 @@ static void lpt_pch_enable(struct drm_crtc *crtc) lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); } -void intel_put_shared_dpll(struct intel_crtc *crtc) -{ - struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); - - if (pll == NULL) - return; - - if (!(pll->config.crtc_mask & (1 << crtc->pipe))) { - WARN(1, "bad %s crtc mask\n", pll->name); - return; - } - - pll->config.crtc_mask &= ~(1 << crtc->pipe); - if (pll->config.crtc_mask == 0) { - WARN_ON(pll->on); - WARN_ON(pll->active); - } - - crtc->config->shared_dpll = DPLL_ID_PRIVATE; -} - struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state) { @@ -5206,13 +5185,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_disable_shared_dpll(intel_crtc); } -static void ironlake_crtc_off(struct drm_crtc *crtc) -{ - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - intel_put_shared_dpll(intel_crtc); -} - - static void i9xx_pfit_enable(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; @@ -14770,7 +14742,7 @@ static void intel_init_display(struct drm_device *dev) haswell_crtc_compute_clock; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; - dev_priv->display.off = ironlake_crtc_off; + dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = skylake_update_primary_plane; } else if (HAS_DDI(dev)) { @@ -14781,7 +14753,7 @@ static void intel_init_display(struct drm_device *dev) haswell_crtc_compute_clock; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; - dev_priv->display.off = ironlake_crtc_off; + dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = ironlake_update_primary_plane; } else if (HAS_PCH_SPLIT(dev)) { @@ -14792,7 +14764,7 @@ static void intel_init_display(struct drm_device *dev) ironlake_crtc_compute_clock; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; - dev_priv->display.off = ironlake_crtc_off; + dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = ironlake_update_primary_plane; } else if (IS_VALLEYVIEW(dev)) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5c9d6217f371..4635c83e6dc2 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1083,7 +1083,6 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv, #define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false) struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, struct intel_crtc_state *state); -void intel_put_shared_dpll(struct intel_crtc *crtc); void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe, const struct dpll *dpll); -- cgit v1.3-6-gb490 From 69024de8ba9ee28bbb2c0ba2f813d37a7d0be80a Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:46 +0200 Subject: drm/i915: get rid of intel_crtc_disable and related code, v3 Now that the dpll updates are (mostly) atomic, the .off() code is a noop, and intel_crtc_disable does mostly the same as intel_modeset_update_state. Move all logic for connectors_active and setting dpms to that function. Changes since v1: - Move drm_atomic_helper_swap_state up. Changes since v2: - Split out intel_put_shared_dpll removal. Changes since v3: - Rebase on top of latest drm-intel. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_display.c | 93 +++++++++--------------------------- 2 files changed, 23 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 46722f85ef76..03ae50ee4737 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -631,7 +631,6 @@ struct drm_i915_display_funcs { struct intel_crtc_state *crtc_state); void (*crtc_enable)(struct drm_crtc *crtc); void (*crtc_disable)(struct drm_crtc *crtc); - void (*off)(struct drm_crtc *crtc); void (*audio_codec_enable)(struct drm_connector *connector, struct intel_encoder *encoder, struct drm_display_mode *mode); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9d271172dddd..490581081df7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6278,10 +6278,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } -static void i9xx_crtc_off(struct drm_crtc *crtc) -{ -} - /* Master function to enable/disable CRTC and corresponding power wells */ void intel_crtc_control(struct drm_crtc *crtc, bool enable) { @@ -6331,34 +6327,6 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc) crtc->state->active = enable; } -static void intel_crtc_disable(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_connector *connector; - struct drm_i915_private *dev_priv = dev->dev_private; - - /* crtc should still be enabled when we disable it. */ - WARN_ON(!crtc->state->enable); - - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); - dev_priv->display.off(crtc); - - drm_plane_helper_disable(crtc->primary); - - /* Update computed state. */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (!connector->encoder || !connector->encoder->crtc) - continue; - - if (connector->encoder->crtc != crtc) - continue; - - connector->dpms = DRM_MODE_DPMS_OFF; - to_intel_encoder(connector->encoder)->connectors_active = false; - } -} - void intel_encoder_destroy(struct drm_encoder *encoder) { struct intel_encoder *intel_encoder = to_intel_encoder(encoder); @@ -12272,26 +12240,22 @@ intel_modeset_update_state(struct drm_atomic_state *state) struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; struct drm_connector *connector; - int i; intel_shared_dpll_commit(dev_priv); + drm_atomic_helper_swap_state(state->dev, state); for_each_intel_encoder(dev, intel_encoder) { if (!intel_encoder->base.crtc) continue; - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (crtc != intel_encoder->base.crtc) - continue; - - if (crtc_state->enable && needs_modeset(crtc_state)) - intel_encoder->connectors_active = false; + crtc = intel_encoder->base.crtc; + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); + if (!crtc_state || !needs_modeset(crtc->state)) + continue; - break; - } + intel_encoder->connectors_active = false; } - drm_atomic_helper_swap_state(state->dev, state); intel_modeset_fixup_state(state); /* Double check state. */ @@ -12303,27 +12267,23 @@ intel_modeset_update_state(struct drm_atomic_state *state) if (!connector->encoder || !connector->encoder->crtc) continue; - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (crtc != connector->encoder->crtc) - continue; - - if (crtc->state->enable && needs_modeset(crtc->state)) { - struct drm_property *dpms_property = - dev->mode_config.dpms_property; + crtc = connector->encoder->crtc; + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); + if (!crtc_state || !needs_modeset(crtc->state)) + continue; - connector->dpms = DRM_MODE_DPMS_ON; - drm_object_property_set_value(&connector->base, - dpms_property, - DRM_MODE_DPMS_ON); + if (crtc->state->enable) { + struct drm_property *dpms_property = + dev->mode_config.dpms_property; - intel_encoder = to_intel_encoder(connector->encoder); - intel_encoder->connectors_active = true; - } + connector->dpms = DRM_MODE_DPMS_ON; + drm_object_property_set_value(&connector->base, dpms_property, DRM_MODE_DPMS_ON); - break; - } + intel_encoder = to_intel_encoder(connector->encoder); + intel_encoder->connectors_active = true; + } else + connector->dpms = DRM_MODE_DPMS_OFF; } - } static bool intel_fuzzy_clock_check(int clock1, int clock2) @@ -13001,12 +12961,10 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, if (!needs_modeset(crtc_state)) continue; - if (!crtc_state->enable) { - intel_crtc_disable(crtc); - } else if (crtc->state->enable) { - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); - } + intel_crtc_disable_planes(crtc); + dev_priv->display.crtc_disable(crtc); + if (!crtc_state->enable) + drm_plane_helper_disable(crtc->primary); } /* crtc->mode is already used by the ->mode_set callbacks, hence we need @@ -14742,7 +14700,6 @@ static void intel_init_display(struct drm_device *dev) haswell_crtc_compute_clock; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; - dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = skylake_update_primary_plane; } else if (HAS_DDI(dev)) { @@ -14753,7 +14710,6 @@ static void intel_init_display(struct drm_device *dev) haswell_crtc_compute_clock; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; - dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = ironlake_update_primary_plane; } else if (HAS_PCH_SPLIT(dev)) { @@ -14764,7 +14720,6 @@ static void intel_init_display(struct drm_device *dev) ironlake_crtc_compute_clock; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; - dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = ironlake_update_primary_plane; } else if (IS_VALLEYVIEW(dev)) { @@ -14774,7 +14729,6 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock; dev_priv->display.crtc_enable = valleyview_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; - dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = i9xx_update_primary_plane; } else { @@ -14784,7 +14738,6 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock; dev_priv->display.crtc_enable = i9xx_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; - dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = i9xx_update_primary_plane; } -- cgit v1.3-6-gb490 From 6b72d486245265676df9866734bca1b39252e480 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:47 +0200 Subject: drm/i915: add intel_display_suspend, v2 This is a function used to disable all crtc's. This makes it clearer to distinguish between when mode needs to be preserved and when it can be trashed. Changes since v1: - Copy power changes from intel_crtc_control. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.c | 4 +--- drivers/gpu/drm/i915/intel_display.c | 38 ++++++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 30 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a051a0241883..78ef0bb53c36 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -601,7 +601,6 @@ static int bxt_resume_prepare(struct drm_i915_private *dev_priv); static int i915_drm_suspend(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; pci_power_t opregion_target_state; int error; @@ -632,8 +631,7 @@ static int i915_drm_suspend(struct drm_device *dev) * for _thaw. Also, power gate the CRTC power wells. */ drm_modeset_lock_all(dev); - for_each_crtc(dev, crtc) - intel_crtc_control(crtc, false); + intel_display_suspend(dev); drm_modeset_unlock_all(dev); intel_dp_mst_suspend(dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 490581081df7..da7c886026da 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3190,9 +3190,6 @@ void intel_crtc_reset(struct intel_crtc *crtc) void intel_prepare_reset(struct drm_device *dev) { - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_crtc *crtc; - /* no reset support for gen2 */ if (IS_GEN2(dev)) return; @@ -3207,13 +3204,7 @@ void intel_prepare_reset(struct drm_device *dev) * Disabling the crtcs gracefully seems nicer. Also the * g33 docs say we should at least disable all the planes. */ - for_each_intel_crtc(dev, crtc) { - if (!crtc->active) - continue; - - intel_crtc_disable_planes(&crtc->base); - dev_priv->display.crtc_disable(&crtc->base); - } + intel_display_suspend(dev); } void intel_finish_reset(struct drm_device *dev) @@ -6278,6 +6269,33 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } +/* + * turn all crtc's off, but do not adjust state + * This has to be paired with a call to intel_modeset_setup_hw_state. + */ +void intel_display_suspend(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_crtc *crtc; + + for_each_crtc(dev, crtc) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum intel_display_power_domain domain; + unsigned long domains; + + if (!intel_crtc->active) + continue; + + intel_crtc_disable_planes(crtc); + dev_priv->display.crtc_disable(crtc); + + domains = intel_crtc->enabled_power_domains; + for_each_power_domain(domain, domains) + intel_display_power_put(dev_priv, domain); + intel_crtc->enabled_power_domains = 0; + } +} + /* Master function to enable/disable CRTC and corresponding power wells */ void intel_crtc_control(struct drm_crtc *crtc, bool enable) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4635c83e6dc2..31afeb05ea90 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -993,6 +993,7 @@ int intel_pch_rawclk(struct drm_device *dev); void intel_mark_busy(struct drm_device *dev); void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); +void intel_display_suspend(struct drm_device *dev); void intel_crtc_control(struct drm_crtc *crtc, bool enable); void intel_crtc_reset(struct intel_crtc *crtc); void intel_crtc_update_dpms(struct drm_crtc *crtc); -- cgit v1.3-6-gb490 From 1b5092592824d1c91d6e48d820b6047f6ba323ce Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:48 +0200 Subject: drm/i915: use intel_crtc_control everywhere, v3. Having a single path for everything makes it a lot easier to keep crtc_state->active in sync with intel_crtc->active. A crtc cannot be changed to active when not enabled, because it means no mode is set and no connectors are connected. This should also make intel_crtc->active match crtc_state->active. Changes since v1: - Reworded commit message, there's no intel_crtc_toggle. Changes since v2: - Change some callers of intel_crtc_control to intel_display_suspend. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_debugfs.c | 18 ++++++++++-- drivers/gpu/drm/i915/intel_display.c | 54 +++++++++++++----------------------- drivers/gpu/drm/i915/intel_drv.h | 1 - 3 files changed, 35 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 47d9854434c5..aac252ca0bda 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3630,12 +3630,18 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_device *dev) */ if (crtc->config->cpu_transcoder == TRANSCODER_EDP && !crtc->config->pch_pfit.enabled) { + bool active = crtc->active; + + if (active) + intel_crtc_control(&crtc->base, false); + crtc->config->pch_pfit.force_thru = true; intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A)); - intel_crtc_reset(crtc); + if (active) + intel_crtc_control(&crtc->base, true); } drm_modeset_unlock_all(dev); } @@ -3654,12 +3660,18 @@ static void hsw_undo_trans_edp_pipe_A_crc_wa(struct drm_device *dev) * routing. */ if (crtc->config->pch_pfit.force_thru) { - crtc->config->pch_pfit.force_thru = false; + bool active = crtc->active; - intel_crtc_reset(crtc); + if (active) + intel_crtc_control(&crtc->base, false); + + crtc->config->pch_pfit.force_thru = false; intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A)); + + if (active) + intel_crtc_control(&crtc->base, true); } drm_modeset_unlock_all(dev); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index da7c886026da..aab75d3b7d20 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3175,19 +3175,6 @@ static void intel_update_primary_planes(struct drm_device *dev) } } -void intel_crtc_reset(struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - - if (!crtc->active) - return; - - intel_crtc_disable_planes(&crtc->base); - dev_priv->display.crtc_disable(&crtc->base); - dev_priv->display.crtc_enable(&crtc->base); - intel_crtc_enable_planes(&crtc->base); -} - void intel_prepare_reset(struct drm_device *dev) { /* no reset support for gen2 */ @@ -3199,7 +3186,6 @@ void intel_prepare_reset(struct drm_device *dev) return; drm_modeset_lock_all(dev); - /* * Disabling the crtcs gracefully seems nicer. Also the * g33 docs say we should at least disable all the planes. @@ -6305,26 +6291,29 @@ void intel_crtc_control(struct drm_crtc *crtc, bool enable) enum intel_display_power_domain domain; unsigned long domains; + if (enable == intel_crtc->active) + return; + + if (enable && !crtc->state->enable) + return; + + crtc->state->active = enable; if (enable) { - if (!intel_crtc->active) { - domains = get_crtc_power_domains(crtc); - for_each_power_domain(domain, domains) - intel_display_power_get(dev_priv, domain); - intel_crtc->enabled_power_domains = domains; + domains = get_crtc_power_domains(crtc); + for_each_power_domain(domain, domains) + intel_display_power_get(dev_priv, domain); + intel_crtc->enabled_power_domains = domains; - dev_priv->display.crtc_enable(crtc); - intel_crtc_enable_planes(crtc); - } + dev_priv->display.crtc_enable(crtc); + intel_crtc_enable_planes(crtc); } else { - if (intel_crtc->active) { - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); + intel_crtc_disable_planes(crtc); + dev_priv->display.crtc_disable(crtc); - domains = intel_crtc->enabled_power_domains; - for_each_power_domain(domain, domains) - intel_display_power_put(dev_priv, domain); - intel_crtc->enabled_power_domains = 0; - } + domains = intel_crtc->enabled_power_domains; + for_each_power_domain(domain, domains) + intel_display_power_put(dev_priv, domain); + intel_crtc->enabled_power_domains = 0; } } @@ -6341,8 +6330,6 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc) enable |= intel_encoder->connectors_active; intel_crtc_control(crtc, enable); - - crtc->state->active = enable; } void intel_encoder_destroy(struct drm_encoder *encoder) @@ -15240,8 +15227,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) plane = crtc->plane; to_intel_plane_state(crtc->base.primary->state)->visible = true; crtc->plane = !plane; - intel_crtc_disable_planes(&crtc->base); - dev_priv->display.crtc_disable(&crtc->base); + intel_crtc_control(&crtc->base, false); crtc->plane = plane; /* ... and break all links. */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 31afeb05ea90..ea1351f87f0a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -995,7 +995,6 @@ void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); void intel_display_suspend(struct drm_device *dev); void intel_crtc_control(struct drm_crtc *crtc, bool enable); -void intel_crtc_reset(struct intel_crtc *crtc); void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); int intel_connector_init(struct intel_connector *); -- cgit v1.3-6-gb490 From 3cb480bcb3397a1cfdc04115adcdb33393fde4f9 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:49 +0200 Subject: drm/i915: Use drm_atomic_helper_update_legacy_modeset_state, v2. Now that the helper is exported there's no need to duplicate this code any more. Changes since v1: - move intel_modeset_update_staged_output_state call to the right place. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 61 +++--------------------------------- 1 file changed, 4 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aab75d3b7d20..c1042ea50136 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11737,43 +11737,6 @@ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev) } } -/* Fixup legacy state after an atomic state swap. - */ -static void intel_modeset_fixup_state(struct drm_atomic_state *state) -{ - struct intel_crtc *crtc; - struct intel_encoder *encoder; - struct intel_connector *connector; - - for_each_intel_connector(state->dev, connector) { - connector->base.encoder = connector->base.state->best_encoder; - if (connector->base.encoder) - connector->base.encoder->crtc = - connector->base.state->crtc; - } - - /* Update crtc of disabled encoders */ - for_each_intel_encoder(state->dev, encoder) { - int num_connectors = 0; - - for_each_intel_connector(state->dev, connector) - if (connector->base.encoder == &encoder->base) - num_connectors++; - - if (num_connectors == 0) - encoder->base.crtc = NULL; - } - - for_each_intel_crtc(state->dev, crtc) { - crtc->base.enabled = crtc->base.state->enable; - crtc->config = to_intel_crtc_state(crtc->base.state); - } - - /* Copy the new configuration to the staged state, to keep the few - * pieces of code that haven't been converted yet happy */ - intel_modeset_update_staged_output_state(state->dev); -} - static void connected_sink_compute_bpp(struct intel_connector *connector, struct intel_crtc_state *pipe_config) @@ -12261,11 +12224,14 @@ intel_modeset_update_state(struct drm_atomic_state *state) intel_encoder->connectors_active = false; } - intel_modeset_fixup_state(state); + drm_atomic_helper_update_legacy_modeset_state(state->dev, state); + intel_modeset_update_staged_output_state(state->dev); /* Double check state. */ for_each_crtc(dev, crtc) { WARN_ON(crtc->state->enable != intel_crtc_in_use(crtc)); + + to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); } list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -12972,25 +12938,6 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, drm_plane_helper_disable(crtc->primary); } - /* crtc->mode is already used by the ->mode_set callbacks, hence we need - * to set it here already despite that we pass it down the callchain. - * - * Note we'll need to fix this up when we start tracking multiple - * pipes; here we assume a single modeset_pipe and only track the - * single crtc and mode. - */ - if (pipe_config->base.enable && needs_modeset(&pipe_config->base)) { - modeset_crtc->mode = pipe_config->base.mode; - - /* - * Calculate and store various constants which - * are later needed by vblank and swap-completion - * timestamping. They are derived from true hwmode. - */ - drm_calc_timestamping_constants(modeset_crtc, - &pipe_config->base.adjusted_mode); - } - /* Only after disabling all output pipelines that will be changed can we * update the the output configuration. */ intel_modeset_update_state(state); -- cgit v1.3-6-gb490 From c72d969b23253ee8196e4190ec2c15e7cf607372 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 1 Jun 2015 12:49:50 +0200 Subject: drm/i915: Make __intel_set_mode() take only atomic state as argument With the use of drm_atomic_helper_update_legacy_modeset_state the last user of modeset_crtc is removed from this function. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c1042ea50136..7116217ca25b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12909,12 +12909,10 @@ static int __intel_set_mode_checks(struct drm_atomic_state *state) return 0; } -static int __intel_set_mode(struct drm_crtc *modeset_crtc, - struct intel_crtc_state *pipe_config) +static int __intel_set_mode(struct drm_atomic_state *state) { - struct drm_device *dev = modeset_crtc->dev; + struct drm_device *dev = state->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_atomic_state *state = pipe_config->base.state; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int ret = 0; @@ -12974,7 +12972,7 @@ static int intel_set_mode_with_config(struct drm_crtc *crtc, { int ret; - ret = __intel_set_mode(crtc, pipe_config); + ret = __intel_set_mode(pipe_config->base.state); if (ret == 0) intel_modeset_check_state(crtc->dev); -- cgit v1.3-6-gb490 From cdba954e426761cdfe08ce4c9909cd97ce254b9c Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 1 Jun 2015 12:49:51 +0200 Subject: drm/i915: Set mode_changed for audio in intel_modeset_pipe_config() A follow up patch will make intel_modeset_compute_config() deal with multiple crtcs, so move crtc specific stuff into the lower level crtc specific function. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 51 ++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7116217ca25b..eb40f9fc9b44 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -431,6 +431,12 @@ static void vlv_clock(int refclk, intel_clock_t *clock) clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } +static bool +needs_modeset(struct drm_crtc_state *state) +{ + return state->mode_changed || state->active_changed; +} + /** * Returns whether any output on the specified pipe is of the specified type */ @@ -12085,6 +12091,15 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, return -EINVAL; } + /* + * XXX: Add all connectors to make the crtc state match the encoders. + */ + if (!needs_modeset(&pipe_config->base)) { + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + return ret; + } + clear_intel_crtc_state(pipe_config); pipe_config->cpu_transcoder = @@ -12176,6 +12191,18 @@ encoder_retry: DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n", base_bpp, pipe_config->pipe_bpp, pipe_config->dither); + /* Check if we need to force a modeset */ + if (pipe_config->has_audio != + to_intel_crtc_state(crtc->state)->has_audio) + pipe_config->base.mode_changed = true; + + /* + * Note we have an issue here with infoframes: current code + * only updates them on the full mode set path per hw + * requirements. So here we should be checking for any + * required changes and forcing a mode set. + */ + return 0; fail: return ret; @@ -12193,12 +12220,6 @@ static bool intel_crtc_in_use(struct drm_crtc *crtc) return false; } -static bool -needs_modeset(struct drm_crtc_state *state) -{ - return state->mode_changed || state->active_changed; -} - static void intel_modeset_update_state(struct drm_atomic_state *state) { @@ -12785,10 +12806,6 @@ intel_modeset_compute_config(struct drm_crtc *crtc, struct intel_crtc_state *pipe_config; int ret = 0; - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - return ERR_PTR(ret); - ret = drm_atomic_helper_check_modeset(state->dev, state); if (ret) return ERR_PTR(ret); @@ -12810,19 +12827,7 @@ intel_modeset_compute_config(struct drm_crtc *crtc, if (ret) return ERR_PTR(ret); - /* Check things that can only be changed through modeset */ - if (pipe_config->has_audio != - to_intel_crtc(crtc)->config->has_audio) - pipe_config->base.mode_changed = true; - - /* - * Note we have an issue here with infoframes: current code - * only updates them on the full mode set path per hw - * requirements. So here we should be checking for any - * required changes and forcing a mode set. - */ - - intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,"[modeset]"); + intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config, "[modeset]"); ret = drm_atomic_helper_check_planes(state->dev, state); if (ret) -- cgit v1.3-6-gb490 From 53d9f4e99de001374eb06195609cc0451f31a318 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:52 +0200 Subject: drm/i915: Use crtc_state->active instead of crtc_state->enable crtc_state->enable means a crtc is configured, but it may be turned off for dpms. Until the commit "use intel_crtc_control everywhere" crtc_state->active was not updated on crtc off, but now crtc_state->active should be used for tracking whether a crtc is scanning out or not. A few commits from now dpms will be handled by calling intel_set_mode with a different value for crtc_state->active, which causes a crtc to turn on or off. At this point crtc->active should mirror crtc_state->active, so some paranoia from the crtc_disable functions can be removed. intel_set_mode_setup_plls still checks for ->enable, because all resources that are needed have to be calculated, else dpms changes may not succeed. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_irq.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 44 ++++++++++++++++++------------------ 2 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index eb52a039d628..dadd586f0527 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -796,7 +796,7 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, return -EINVAL; } - if (!crtc->state->enable) { + if (!crtc->state->active) { DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); return -EBUSY; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index eb40f9fc9b44..4648fa5ab55a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4629,7 +4629,7 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc) bool reenable_ips = false; /* The clocks have to be on to load the palette. */ - if (!crtc->state->enable || !intel_crtc->active) + if (!crtc->state->active) return; if (HAS_GMCH_DISPLAY(dev_priv->dev)) { @@ -4845,9 +4845,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - WARN_ON(!crtc->state->enable); - - if (intel_crtc->active) + if (WARN_ON(intel_crtc->active)) return; if (intel_crtc->config->has_pch_encoder) @@ -4951,9 +4949,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - WARN_ON(!crtc->state->enable); - - if (intel_crtc->active) + if (WARN_ON(intel_crtc->active)) return; if (intel_crtc_to_shared_dpll(intel_crtc)) @@ -5055,7 +5051,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; u32 reg, temp; - if (!intel_crtc->active) + if (WARN_ON(!intel_crtc->active)) return; for_each_encoder_on_crtc(dev, crtc, encoder) @@ -5118,7 +5114,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; - if (!intel_crtc->active) + if (WARN_ON(!intel_crtc->active)) return; for_each_encoder_on_crtc(dev, crtc, encoder) { @@ -5978,7 +5974,7 @@ static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) /* add all active pipes to the state */ for_each_crtc(state->dev, crtc) { - if (!crtc->state->enable) + if (!crtc->state->active) continue; crtc_state = drm_atomic_get_crtc_state(state, crtc); @@ -5988,7 +5984,7 @@ static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) /* disable/enable all currently active pipes while we change cdclk */ for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc_state->enable) + if (crtc_state->active) crtc_state->mode_changed = true; return 0; @@ -6076,9 +6072,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; bool is_dsi; - WARN_ON(!crtc->state->enable); - - if (intel_crtc->active) + if (WARN_ON(intel_crtc->active)) return; is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI); @@ -6154,9 +6148,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - WARN_ON(!crtc->state->enable); - - if (intel_crtc->active) + if (WARN_ON(intel_crtc->active)) return; i9xx_set_pll_dividers(intel_crtc); @@ -6216,7 +6208,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - if (!intel_crtc->active) + if (WARN_ON(!intel_crtc->active)) return; /* @@ -12264,7 +12256,7 @@ intel_modeset_update_state(struct drm_atomic_state *state) if (!crtc_state || !needs_modeset(crtc->state)) continue; - if (crtc->state->enable) { + if (crtc->state->active) { struct drm_property *dpms_property = dev->mode_config.dpms_property; @@ -12679,6 +12671,10 @@ check_crtc_state(struct drm_device *dev) "crtc active state doesn't match with hw state " "(expected %i, found %i)\n", crtc->active, active); + I915_STATE_WARN(crtc->active != crtc->base.state->active, + "transitional active state does not match atomic hw state " + "(expected %i, found %i)\n", crtc->base.state->active, crtc->active); + if (active && !intel_pipe_config_compare(dev, crtc->config, &pipe_config)) { I915_STATE_WARN(1, "pipe state doesn't match!\n"); @@ -12820,6 +12816,10 @@ intel_modeset_compute_config(struct drm_crtc *crtc, if (IS_ERR(pipe_config)) return pipe_config; + if (!pipe_config->base.enable && + WARN_ON(pipe_config->base.active)) + pipe_config->base.active = false; + if (!pipe_config->base.enable) return pipe_config; @@ -12932,7 +12932,7 @@ static int __intel_set_mode(struct drm_atomic_state *state) return ret; for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc_state)) + if (!needs_modeset(crtc_state) || !crtc->state->active) continue; intel_crtc_disable_planes(crtc); @@ -12954,7 +12954,7 @@ static int __intel_set_mode(struct drm_atomic_state *state) /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc->state) || !crtc->state->enable) + if (!needs_modeset(crtc->state) || !crtc->state->active) continue; update_scanline_offset(to_intel_crtc(crtc)); @@ -15215,7 +15215,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) * have active connectors/encoders. */ intel_crtc_update_dpms(&crtc->base); - if (crtc->active != crtc->base.state->enable) { + if (crtc->active != crtc->base.state->active) { struct intel_encoder *encoder; /* This can happen either due to bugs in the get_hw_state -- cgit v1.3-6-gb490 From 85a96e7a4213de094acc63fd433dcf766e91c782 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:53 +0200 Subject: drm/i915: Make sure all planes and connectors are added on modeset. Add missing calls to drm_atomic_add_affected_*. This is needed to convert to atomic planes. When converting to atomic all planes are needed on modeset. For good measure make sure all connectors are added too. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4648fa5ab55a..2b5b829a98ad 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5959,7 +5959,7 @@ static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int max_pixclk = intel_mode_max_pixclk(state->dev, state); - int cdclk, i; + int cdclk, ret = 0; if (max_pixclk < 0) return max_pixclk; @@ -5974,20 +5974,25 @@ static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) /* add all active pipes to the state */ for_each_crtc(state->dev, crtc) { - if (!crtc->state->active) - continue; - crtc_state = drm_atomic_get_crtc_state(state, crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - } - /* disable/enable all currently active pipes while we change cdclk */ - for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc_state->active) - crtc_state->mode_changed = true; + if (!crtc_state->active || needs_modeset(crtc_state)) + continue; - return 0; + crtc_state->mode_changed = true; + + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + break; + + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + break; + } + + return ret; } static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) @@ -12185,8 +12190,10 @@ encoder_retry: /* Check if we need to force a modeset */ if (pipe_config->has_audio != - to_intel_crtc_state(crtc->state)->has_audio) + to_intel_crtc_state(crtc->state)->has_audio) { pipe_config->base.mode_changed = true; + ret = drm_atomic_add_affected_planes(state, crtc); + } /* * Note we have an issue here with infoframes: current code @@ -12194,8 +12201,6 @@ encoder_retry: * requirements. So here we should be checking for any * required changes and forcing a mode set. */ - - return 0; fail: return ret; } -- cgit v1.3-6-gb490 From 36750f284b3a4f19b304fda1bb7d6e9e1275ea8d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:54 +0200 Subject: drm/i915: update plane state during init Atomic planes updates rely on having a accurate plane_mask. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2b5b829a98ad..91a0f7ca7ed2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2632,9 +2632,9 @@ valid_fb: dev_priv->preserve_bios_swizzle = true; primary->fb = fb; - primary->state->crtc = &intel_crtc->base; - primary->crtc = &intel_crtc->base; + primary->crtc = primary->state->crtc = &intel_crtc->base; update_state_fb(primary); + intel_crtc->base.state->plane_mask |= (1 << drm_plane_index(primary)); obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); } @@ -15563,7 +15563,9 @@ void intel_modeset_gem_init(struct drm_device *dev) to_intel_crtc(c)->pipe); drm_framebuffer_unreference(c->primary->fb); c->primary->fb = NULL; + c->primary->crtc = c->primary->state->crtc = NULL; update_state_fb(c->primary); + c->state->plane_mask &= ~(1 << drm_plane_index(c->primary)); } } -- cgit v1.3-6-gb490 From 8a8f7f44a1b704c482f77a0d31cbcdf1af062263 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:55 +0200 Subject: drm/i915: do not wait for vblank when crtc is off This can happen when turning off a sprite plane. Because the crtc state is not yet always swapped correctly and transitional helpers are used the crtc state cannot be relied on. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 91a0f7ca7ed2..e0edff9d034d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13768,7 +13768,7 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc) intel_runtime_pm_put(dev_priv); - if (intel_crtc->atomic.wait_vblank) + if (intel_crtc->atomic.wait_vblank && intel_crtc->active) intel_wait_for_vblank(dev, intel_crtc->pipe); intel_frontbuffer_flip(dev, intel_crtc->atomic.fb_bits); -- cgit v1.3-6-gb490 From fb9d6cf8c29bfcb0b3c602f7ded87f128d730382 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:56 +0200 Subject: drm/i915: calculate primary visibility changes instead of calling from set_config This should be much cleaner, with the same effects. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 46 ++++++------------------------------ 1 file changed, 7 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e0edff9d034d..52759c03c9e8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13225,20 +13225,11 @@ intel_modeset_stage_output_state(struct drm_device *dev, return 0; } -static bool primary_plane_visible(struct drm_crtc *crtc) -{ - struct intel_plane_state *plane_state = - to_intel_plane_state(crtc->primary->state); - - return plane_state->visible; -} - static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; struct drm_atomic_state *state = NULL; struct intel_crtc_state *pipe_config; - bool primary_plane_was_visible; int ret; BUG_ON(!set); @@ -13277,38 +13268,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) intel_update_pipe_size(to_intel_crtc(set->crtc)); - primary_plane_was_visible = primary_plane_visible(set->crtc); - ret = intel_set_mode_with_config(set->crtc, pipe_config); - if (ret == 0 && - pipe_config->base.enable && - pipe_config->base.planes_changed && - !needs_modeset(&pipe_config->base)) { - struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); - - /* - * We need to make sure the primary plane is re-enabled if it - * has previously been turned off. - */ - if (ret == 0 && !primary_plane_was_visible && - primary_plane_visible(set->crtc)) { - WARN_ON(!intel_crtc->active); - intel_post_enable_primary(set->crtc); - } - - /* - * In the fastboot case this may be our only check of the - * state after boot. It would be better to only do it on - * the first update, but we don't have a nice way of doing that - * (and really, set_config isn't used much for high freq page - * flipping, so increasing its cost here shouldn't be a big - * deal). - */ - if (i915.fastboot && ret == 0) - intel_modeset_check_state(set->crtc->dev); - } - if (ret) { DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n", set->crtc->base.id, ret); @@ -13641,8 +13602,15 @@ intel_check_primary_plane(struct drm_plane *plane, */ if (IS_BROADWELL(dev)) intel_crtc->atomic.wait_vblank = true; + + if (crtc_state && !needs_modeset(&crtc_state->base)) + intel_crtc->atomic.post_enable_primary = true; } + if (!state->visible && old_state->visible && + crtc_state && !needs_modeset(&crtc_state->base)) + intel_crtc->atomic.pre_disable_primary = true; + intel_crtc->atomic.fb_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); -- cgit v1.3-6-gb490 From 568c634a2af62e07ed248a6e7fe9770173f9d9b2 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 1 Jun 2015 12:49:57 +0200 Subject: drm/i915: Support modeset across multiple pipes Compute new pipe_configs for all crtcs in the atomic state. The commit part of the mode set (__intel_set_mode()) is already enabled to support multiple pipes, the only thing missing was calculating a new pipe_config for every crtc. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 108 +++++++++++++++-------------------- 1 file changed, 45 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 52759c03c9e8..e566515e27ca 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -86,8 +86,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, static void ironlake_pch_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); -static int intel_set_mode(struct drm_crtc *crtc, - struct drm_atomic_state *state); +static int intel_set_mode(struct drm_atomic_state *state); static int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, struct drm_mode_fb_cmd2 *mode_cmd, @@ -10482,7 +10481,7 @@ retry: drm_mode_copy(&crtc_state->base.mode, mode); - if (intel_set_mode(crtc, state)) { + if (intel_set_mode(state)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); @@ -10556,7 +10555,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (ret) goto fail; - ret = intel_set_mode(crtc, state); + ret = intel_set_mode(state); if (ret) goto fail; @@ -12068,9 +12067,10 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state) static int intel_modeset_pipe_config(struct drm_crtc *crtc, - struct drm_atomic_state *state, - struct intel_crtc_state *pipe_config) + struct drm_atomic_state *state) { + struct drm_crtc_state *crtc_state; + struct intel_crtc_state *pipe_config; struct intel_encoder *encoder; struct drm_connector *connector; struct drm_connector_state *connector_state; @@ -12088,6 +12088,12 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, return -EINVAL; } + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); + if (WARN_ON(!crtc_state)) + return -EINVAL; + + pipe_config = to_intel_crtc_state(crtc_state); + /* * XXX: Add all connectors to make the crtc state match the encoders. */ @@ -12800,45 +12806,35 @@ static void update_scanline_offset(struct intel_crtc *crtc) crtc->scanline_offset = 1; } -static struct intel_crtc_state * -intel_modeset_compute_config(struct drm_crtc *crtc, - struct drm_atomic_state *state) +static int +intel_modeset_compute_config(struct drm_atomic_state *state) { - struct intel_crtc_state *pipe_config; - int ret = 0; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int ret, i; ret = drm_atomic_helper_check_modeset(state->dev, state); if (ret) - return ERR_PTR(ret); - - /* - * Note this needs changes when we start tracking multiple modes - * and crtcs. At that point we'll need to compute the whole config - * (i.e. one pipe_config for each crtc) rather than just the one - * for this crtc. - */ - pipe_config = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc)); - if (IS_ERR(pipe_config)) - return pipe_config; - - if (!pipe_config->base.enable && - WARN_ON(pipe_config->base.active)) - pipe_config->base.active = false; + return ret; - if (!pipe_config->base.enable) - return pipe_config; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (!crtc_state->enable && + WARN_ON(crtc_state->active)) + crtc_state->active = false; - ret = intel_modeset_pipe_config(crtc, state, pipe_config); - if (ret) - return ERR_PTR(ret); + if (!crtc_state->enable) + continue; - intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config, "[modeset]"); + ret = intel_modeset_pipe_config(crtc, state); + if (ret) + return ret; - ret = drm_atomic_helper_check_planes(state->dev, state); - if (ret) - return ERR_PTR(ret); + intel_dump_pipe_config(to_intel_crtc(crtc), + to_intel_crtc_state(crtc_state), + "[modeset]"); + } - return pipe_config; + return drm_atomic_helper_check_planes(state->dev, state); } static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) @@ -12977,37 +12973,27 @@ static int __intel_set_mode(struct drm_atomic_state *state) return 0; } -static int intel_set_mode_with_config(struct drm_crtc *crtc, - struct intel_crtc_state *pipe_config) +static int intel_set_mode_checked(struct drm_atomic_state *state) { + struct drm_device *dev = state->dev; int ret; - ret = __intel_set_mode(pipe_config->base.state); - + ret = __intel_set_mode(state); if (ret == 0) - intel_modeset_check_state(crtc->dev); + intel_modeset_check_state(dev); return ret; } -static int intel_set_mode(struct drm_crtc *crtc, - struct drm_atomic_state *state) +static int intel_set_mode(struct drm_atomic_state *state) { - struct intel_crtc_state *pipe_config; - int ret = 0; - - pipe_config = intel_modeset_compute_config(crtc, state); - if (IS_ERR(pipe_config)) { - ret = PTR_ERR(pipe_config); - goto out; - } + int ret; - ret = intel_set_mode_with_config(crtc, pipe_config); + ret = intel_modeset_compute_config(state); if (ret) - goto out; + return ret; -out: - return ret; + return intel_set_mode_checked(state); } void intel_crtc_restore_mode(struct drm_crtc *crtc) @@ -13079,7 +13065,7 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) intel_modeset_setup_plane_state(state, crtc, &crtc->mode, crtc->primary->fb, crtc->x, crtc->y); - ret = intel_set_mode(crtc, state); + ret = intel_set_mode(state); if (ret) drm_atomic_state_free(state); } @@ -13229,7 +13215,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; struct drm_atomic_state *state = NULL; - struct intel_crtc_state *pipe_config; int ret; BUG_ON(!set); @@ -13260,16 +13245,13 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (ret) goto out; - pipe_config = intel_modeset_compute_config(set->crtc, state); - if (IS_ERR(pipe_config)) { - ret = PTR_ERR(pipe_config); + ret = intel_modeset_compute_config(state); + if (ret) goto out; - } intel_update_pipe_size(to_intel_crtc(set->crtc)); - ret = intel_set_mode_with_config(set->crtc, pipe_config); - + ret = intel_set_mode_checked(state); if (ret) { DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n", set->crtc->base.id, ret); -- cgit v1.3-6-gb490 From 880fa62648bf193eb17193a9eae00a52c7844ea7 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:58 +0200 Subject: drm/i915: Zap call to drm_plane_helper_disable, v2. The primary plane can still be configured when crtc is off, furthermore this is also a noop now that affected planes are added on modesets. Changes since v1: - Move commit so no frontbuffer_bits warnings are generated. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e566515e27ca..dcd256f47fe5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12938,8 +12938,6 @@ static int __intel_set_mode(struct drm_atomic_state *state) intel_crtc_disable_planes(crtc); dev_priv->display.crtc_disable(crtc); - if (!crtc_state->enable) - drm_plane_helper_disable(crtc->primary); } /* Only after disabling all output pipelines that will be changed can we -- cgit v1.3-6-gb490 From de419ab6b774facc14b2fa71e3d8642027924c86 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 4 Jun 2015 10:21:28 +0200 Subject: drm/i915: Use global atomic state for staged pll, config, v3. Now that we can subclass drm_atomic_state we can also use it to keep track of all the pll settings. atomic_state is a better place to hold all shared state than keeping pll->new_config everywhere. Changes since v1: - Assert connection_mutex is held. Changes since v2: - Fix swapped arguments to kzalloc for intel_atomic_state_alloc. (Jani Nikula) Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_atomic.c | 51 ++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 111 +++++++++++------------------------ drivers/gpu/drm/i915/intel_drv.h | 13 ++++ 4 files changed, 97 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 03ae50ee4737..611fbd86c1cc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -376,7 +376,6 @@ struct intel_shared_dpll_config { struct intel_shared_dpll { struct intel_shared_dpll_config config; - struct intel_shared_dpll_config *new_config; int active; /* count of number of active CRTCs (i.e. DPMS on) */ bool on; /* is the PLL actually active? Disabled during modeset */ diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 7ed8033aae60..45af3cc9d04c 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -421,3 +421,54 @@ int intel_atomic_setup_scalers(struct drm_device *dev, return 0; } + +static void +intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv, + struct intel_shared_dpll_config *shared_dpll) +{ + enum intel_dpll_id i; + + /* Copy shared dpll state */ + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; + + shared_dpll[i] = pll->config; + } +} + +struct intel_shared_dpll_config * +intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s) +{ + struct intel_atomic_state *state = to_intel_atomic_state(s); + + WARN_ON(!drm_modeset_is_locked(&s->dev->mode_config.connection_mutex)); + + if (!state->dpll_set) { + state->dpll_set = true; + + intel_atomic_duplicate_dpll_state(to_i915(s->dev), + state->shared_dpll); + } + + return state->shared_dpll; +} + +struct drm_atomic_state * +intel_atomic_state_alloc(struct drm_device *dev) +{ + struct intel_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL); + + if (!state || drm_atomic_state_init(dev, &state->base) < 0) { + kfree(state); + return NULL; + } + + return &state->base; +} + +void intel_atomic_state_clear(struct drm_atomic_state *s) +{ + struct intel_atomic_state *state = to_intel_atomic_state(s); + drm_atomic_state_default_clear(&state->base); + state->dpll_set = false; +} diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dcd256f47fe5..aec398cd2289 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4186,8 +4186,11 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_shared_dpll *pll; + struct intel_shared_dpll_config *shared_dpll; enum intel_dpll_id i; + shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state); + if (HAS_PCH_IBX(dev_priv->dev)) { /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */ i = (enum intel_dpll_id) crtc->pipe; @@ -4196,7 +4199,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", crtc->base.base.id, pll->name); - WARN_ON(pll->new_config->crtc_mask); + WARN_ON(shared_dpll[i].crtc_mask); goto found; } @@ -4216,7 +4219,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, pll = &dev_priv->shared_dplls[i]; DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", crtc->base.base.id, pll->name); - WARN_ON(pll->new_config->crtc_mask); + WARN_ON(shared_dpll[i].crtc_mask); goto found; } @@ -4225,15 +4228,15 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, pll = &dev_priv->shared_dplls[i]; /* Only want to check enabled timings first */ - if (pll->new_config->crtc_mask == 0) + if (shared_dpll[i].crtc_mask == 0) continue; if (memcmp(&crtc_state->dpll_hw_state, - &pll->new_config->hw_state, - sizeof(pll->new_config->hw_state)) == 0) { + &shared_dpll[i].hw_state, + sizeof(crtc_state->dpll_hw_state)) == 0) { DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, ative %d)\n", crtc->base.base.id, pll->name, - pll->new_config->crtc_mask, + shared_dpll[i].crtc_mask, pll->active); goto found; } @@ -4242,7 +4245,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, /* Ok no matching timings, maybe there's a free one? */ for (i = 0; i < dev_priv->num_shared_dpll; i++) { pll = &dev_priv->shared_dplls[i]; - if (pll->new_config->crtc_mask == 0) { + if (shared_dpll[i].crtc_mask == 0) { DRM_DEBUG_KMS("CRTC:%d allocated %s\n", crtc->base.base.id, pll->name); goto found; @@ -4252,83 +4255,33 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, return NULL; found: - if (pll->new_config->crtc_mask == 0) - pll->new_config->hw_state = crtc_state->dpll_hw_state; + if (shared_dpll[i].crtc_mask == 0) + shared_dpll[i].hw_state = + crtc_state->dpll_hw_state; crtc_state->shared_dpll = i; DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name, pipe_name(crtc->pipe)); - pll->new_config->crtc_mask |= 1 << crtc->pipe; + shared_dpll[i].crtc_mask |= 1 << crtc->pipe; return pll; } -/** - * intel_shared_dpll_start_config - start a new PLL staged config - * @dev_priv: DRM device - * @clear_pipes: mask of pipes that will have their PLLs freed - * - * Starts a new PLL staged config, copying the current config but - * releasing the references of pipes specified in clear_pipes. - */ -static int intel_shared_dpll_start_config(struct drm_i915_private *dev_priv, - unsigned clear_pipes) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id i; - - for (i = 0; i < dev_priv->num_shared_dpll; i++) { - pll = &dev_priv->shared_dplls[i]; - - pll->new_config = kmemdup(&pll->config, sizeof pll->config, - GFP_KERNEL); - if (!pll->new_config) - goto cleanup; - - pll->new_config->crtc_mask &= ~clear_pipes; - } - - return 0; - -cleanup: - while (--i >= 0) { - pll = &dev_priv->shared_dplls[i]; - kfree(pll->new_config); - pll->new_config = NULL; - } - - return -ENOMEM; -} - -static void intel_shared_dpll_commit(struct drm_i915_private *dev_priv) +static void intel_shared_dpll_commit(struct drm_atomic_state *state) { + struct drm_i915_private *dev_priv = to_i915(state->dev); + struct intel_shared_dpll_config *shared_dpll; struct intel_shared_dpll *pll; enum intel_dpll_id i; - for (i = 0; i < dev_priv->num_shared_dpll; i++) { - pll = &dev_priv->shared_dplls[i]; - - WARN_ON(pll->new_config == &pll->config); - - pll->config = *pll->new_config; - kfree(pll->new_config); - pll->new_config = NULL; - } -} - -static void intel_shared_dpll_abort_config(struct drm_i915_private *dev_priv) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id i; + if (!to_intel_atomic_state(state)->dpll_set) + return; + shared_dpll = to_intel_atomic_state(state)->shared_dpll; for (i = 0; i < dev_priv->num_shared_dpll; i++) { pll = &dev_priv->shared_dplls[i]; - - WARN_ON(pll->new_config == &pll->config); - - kfree(pll->new_config); - pll->new_config = NULL; + pll->config = shared_dpll[i]; } } @@ -12227,13 +12180,12 @@ static void intel_modeset_update_state(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; struct drm_connector *connector; - intel_shared_dpll_commit(dev_priv); + intel_shared_dpll_commit(state); drm_atomic_helper_swap_state(state->dev, state); for_each_intel_encoder(dev, intel_encoder) { @@ -12862,9 +12814,13 @@ static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) } } - ret = intel_shared_dpll_start_config(dev_priv, clear_pipes); - if (ret) - goto done; + if (clear_pipes) { + struct intel_shared_dpll_config *shared_dpll = + intel_atomic_get_shared_dpll_state(state); + + for (i = 0; i < dev_priv->num_shared_dpll; i++) + shared_dpll[i].crtc_mask &= ~clear_pipes; + } for_each_crtc_in_state(state, crtc, crtc_state, i) { if (!needs_modeset(crtc_state) || !crtc_state->enable) @@ -12875,13 +12831,10 @@ static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) ret = dev_priv->display.crtc_compute_clock(intel_crtc, intel_crtc_state); - if (ret) { - intel_shared_dpll_abort_config(dev_priv); - goto done; - } + if (ret) + return ret; } -done: return ret; } @@ -14582,6 +14535,8 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { .output_poll_changed = intel_fbdev_output_poll_changed, .atomic_check = intel_atomic_check, .atomic_commit = intel_atomic_commit, + .atomic_state_alloc = intel_atomic_state_alloc, + .atomic_state_clear = intel_atomic_state_clear, }; /* Set up chip specific display functions */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ea1351f87f0a..e15039800cf0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -241,6 +241,13 @@ typedef struct dpll { int p; } intel_clock_t; +struct intel_atomic_state { + struct drm_atomic_state base; + + bool dpll_set; + struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS]; +}; + struct intel_plane_state { struct drm_plane_state base; struct drm_rect src; @@ -628,6 +635,7 @@ struct cxsr_latency { unsigned long cursor_hpll_disable; }; +#define to_intel_atomic_state(x) container_of(x, struct intel_atomic_state, base) #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_crtc_state(x) container_of(x, struct intel_crtc_state, base) #define to_intel_connector(x) container_of(x, struct intel_connector, base) @@ -1404,6 +1412,11 @@ int intel_connector_atomic_get_property(struct drm_connector *connector, struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc); void intel_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); +struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev); +void intel_atomic_state_clear(struct drm_atomic_state *); +struct intel_shared_dpll_config * +intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s); + static inline struct intel_crtc_state * intel_atomic_get_crtc_state(struct drm_atomic_state *state, struct intel_crtc *crtc) -- cgit v1.3-6-gb490 From 61c054983271426f8d31ef9e52eda249b123a7df Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:00 +0200 Subject: drm/i915: Use drm_atomic_helper_swap_state in intel_atomic_commit. And update crtc->config to point to the new state. There is no point in swapping only part of the state when the rest of the state should be untouched. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_atomic.c | 44 ++++++++++--------------------------- 1 file changed, 12 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 45af3cc9d04c..d0b901ddb357 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -129,6 +129,8 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async) { + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; int ret; int i; @@ -142,48 +144,26 @@ int intel_atomic_commit(struct drm_device *dev, return ret; /* Point of no return */ + drm_atomic_helper_swap_state(dev, state); + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); + + if (INTEL_INFO(dev)->gen >= 9) + skl_detach_scalers(to_intel_crtc(crtc)); + } /* * FIXME: The proper sequence here will eventually be: * - * drm_atomic_helper_swap_state(dev, state) * drm_atomic_helper_commit_modeset_disables(dev, state); * drm_atomic_helper_commit_planes(dev, state); * drm_atomic_helper_commit_modeset_enables(dev, state); - * drm_atomic_helper_wait_for_vblanks(dev, state); - * drm_atomic_helper_cleanup_planes(dev, state); - * drm_atomic_state_free(state); * - * once we have full atomic modeset. For now, just manually update - * plane states to avoid clobbering good states with dummy states - * while nuclear pageflipping. + * once we have full atomic modeset. */ - for (i = 0; i < dev->mode_config.num_total_plane; i++) { - struct drm_plane *plane = state->planes[i]; - - if (!plane) - continue; - - plane->state->state = state; - swap(state->plane_states[i], plane->state); - plane->state->state = NULL; - } - - /* swap crtc_scaler_state */ - for (i = 0; i < dev->mode_config.num_crtc; i++) { - struct drm_crtc *crtc = state->crtcs[i]; - if (!crtc) { - continue; - } - - to_intel_crtc(crtc)->config->scaler_state = - to_intel_crtc_state(state->crtc_states[i])->scaler_state; - - if (INTEL_INFO(dev)->gen >= 9) - skl_detach_scalers(to_intel_crtc(crtc)); - } - drm_atomic_helper_commit_planes(dev, state); + drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); drm_atomic_state_free(state); -- cgit v1.3-6-gb490 From 5ac1c4bcf073ad897c4510931518275d9e393dc7 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:01 +0200 Subject: drm/i915: Swap planes on each crtc separately, v2. Repeated calls to begin_crtc_commit can cause warnings like this: [ 169.127746] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:616 [ 169.127835] in_atomic(): 0, irqs_disabled(): 1, pid: 1947, name: kms_flip [ 169.127840] 3 locks held by kms_flip/1947: [ 169.127843] #0: (&dev->mode_config.mutex){+.+.+.}, at: [] __drm_modeset_lock_all+0x9c/0x130 [ 169.127860] #1: (crtc_ww_class_acquire){+.+.+.}, at: [] __drm_modeset_lock_all+0xad/0x130 [ 169.127870] #2: (crtc_ww_class_mutex){+.+.+.}, at: [] drm_modeset_lock+0x38/0x110 [ 169.127879] irq event stamp: 665690 [ 169.127882] hardirqs last enabled at (665689): [] _raw_spin_unlock_irqrestore+0x55/0x70 [ 169.127889] hardirqs last disabled at (665690): [] intel_pipe_update_start+0x113/0x5c0 [i915] [ 169.127936] softirqs last enabled at (665470): [] __do_softirq+0x236/0x650 [ 169.127942] softirqs last disabled at (665465): [] irq_exit+0xc5/0xd0 [ 169.127951] CPU: 1 PID: 1947 Comm: kms_flip Not tainted 4.1.0-rc4-patser+ #4039 [ 169.127954] Hardware name: LENOVO 2349AV8/2349AV8, BIOS G1ETA5WW (2.65 ) 04/15/2014 [ 169.127957] ffff8800c49036f0 ffff8800cde5fa28 ffffffff817f6907 0000000080000001 [ 169.127964] 0000000000000000 ffff8800cde5fa58 ffffffff810aebed 0000000000000046 [ 169.127970] ffffffff81c5d518 0000000000000268 0000000000000000 ffff8800cde5fa88 [ 169.127981] Call Trace: [ 169.127992] [] dump_stack+0x4f/0x7b [ 169.128001] [] ___might_sleep+0x16d/0x270 [ 169.128008] [] __might_sleep+0x48/0x90 [ 169.128017] [] mutex_lock_nested+0x29/0x410 [ 169.128073] [] ? vgpu_write64+0x220/0x220 [i915] [ 169.128138] [] ? ironlake_update_primary_plane+0x2ff/0x410 [i915] [ 169.128198] [] intel_frontbuffer_flush+0x25/0x70 [i915] [ 169.128253] [] intel_finish_crtc_commit+0x4c/0x180 [i915] [ 169.128279] [] drm_atomic_helper_commit_planes+0x12c/0x240 [drm_kms_helper] [ 169.128338] [] __intel_set_mode+0x684/0x830 [i915] [ 169.128378] [] intel_crtc_set_config+0x49a/0x620 [i915] [ 169.128385] [] ? mutex_unlock+0x9/0x10 [ 169.128391] [] drm_mode_set_config_internal+0x69/0x120 [ 169.128398] [] ? might_fault+0x57/0xb0 [ 169.128403] [] drm_mode_setcrtc+0x253/0x620 [ 169.128409] [] drm_ioctl+0x1a0/0x6a0 [ 169.128415] [] ? get_parent_ip+0x11/0x50 [ 169.128424] [] do_vfs_ioctl+0x2f8/0x530 [ 169.128429] [] ? trace_hardirqs_on+0xd/0x10 [ 169.128435] [] ? selinux_file_ioctl+0x56/0x100 [ 169.128439] [] SyS_ioctl+0x81/0xa0 [ 169.128445] [] system_call_fastpath+0x12/0x6f Solve it by using the newly introduced drm_atomic_helper_commit_planes_on_crtc. The problem here was that the drm_atomic_helper_commit_planes() helper we were using was basically designed to do begin_crtc_commit(crtc #1) begin_crtc_commit(crtc #2) ... commit all planes finish_crtc_commit(crtc #1) finish_crtc_commit(crtc #2) The problem here is that since our hardware relies on vblank evasion, our CRTC 'begin' function waits until we're out of the danger zone in which register writes might wind up straddling the vblank, then disables interrupts; our 'finish' function re-enables interrupts after the registers have been written. The expectation is that the operations between 'begin' and 'end' must be performed without sleeping (since interrupts are disabled) and should happen as quickly as possible. By clumping all of the 'begin' calls together, we introducing a couple problems: * Subsequent 'begin' invocations might sleep (which is illegal) * The first 'begin' ensured that we were far enough from the vblank that we could write our registers safely and ensure they all fell within the same frame. Adding extra delay waiting for subsequent CRTC's wasn't accounted for and could put us back into the 'danger zone' for CRTC #1. This commit solves the problem by using a new helper that allows an order of operations like: for each crtc { begin_crtc_commit(crtc) // sleep (maybe), then disable interrupts commit planes for this specific CRTC end_crtc_commit(crtc) // reenable interrupts } so that sleeps will only be performed while interrupts are enabled and we can be sure that registers for a CRTC will be written immediately once we know we're in the safe zone. The crtc->config->base.crtc update may seem unrelated, but the helper will use it to obtain the crtc for the state. Without the update it will dereference NULL and crash. Changes since v1: - Use Matt Roper's commit message. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_atomic.c | 13 +++---------- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 2 files changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index d0b901ddb357..4df6d2d7a9c8 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -151,18 +151,11 @@ int intel_atomic_commit(struct drm_device *dev, if (INTEL_INFO(dev)->gen >= 9) skl_detach_scalers(to_intel_crtc(crtc)); + + drm_atomic_helper_commit_planes_on_crtc(crtc_state); } - /* - * FIXME: The proper sequence here will eventually be: - * - * drm_atomic_helper_commit_modeset_disables(dev, state); - * drm_atomic_helper_commit_planes(dev, state); - * drm_atomic_helper_commit_modeset_enables(dev, state); - * - * once we have full atomic modeset. - */ - drm_atomic_helper_commit_planes(dev, state); + /* FIXME: This function should eventually call __intel_set_mode when needed */ drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aec398cd2289..b56641b6de70 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12902,10 +12902,10 @@ static int __intel_set_mode(struct drm_atomic_state *state) modeset_update_crtc_power_domains(state); - drm_atomic_helper_commit_planes(dev, state); - /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { + drm_atomic_helper_commit_planes_on_crtc(crtc_state); + if (!needs_modeset(crtc->state) || !crtc->state->active) continue; @@ -15267,6 +15267,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) struct intel_plane_state *plane_state; memset(crtc->config, 0, sizeof(*crtc->config)); + crtc->config->base.crtc = &crtc->base; crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; -- cgit v1.3-6-gb490 From c347a6768df15c7145ac16bf4b4f7c5fc2be1179 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 1 Jun 2015 12:50:02 +0200 Subject: drm/i915: Move cdclk and pll setup to intel_modeset_compute_config(), v2. It makes more sense there, since these are computation steps that can fail. Changes since v1: - Rename __intel_set_mode_checks to intel_modeset_checks (Matt Roper) - Move intel_modeset_checks to before check_planes, so it won't have to be moved later. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 74 +++++++++++++++++------------------- 1 file changed, 35 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b56641b6de70..12d6da8f0465 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12758,38 +12758,7 @@ static void update_scanline_offset(struct intel_crtc *crtc) crtc->scanline_offset = 1; } -static int -intel_modeset_compute_config(struct drm_atomic_state *state) -{ - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int ret, i; - - ret = drm_atomic_helper_check_modeset(state->dev, state); - if (ret) - return ret; - - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!crtc_state->enable && - WARN_ON(crtc_state->active)) - crtc_state->active = false; - - if (!crtc_state->enable) - continue; - - ret = intel_modeset_pipe_config(crtc, state); - if (ret) - return ret; - - intel_dump_pipe_config(to_intel_crtc(crtc), - to_intel_crtc_state(crtc_state), - "[modeset]"); - } - - return drm_atomic_helper_check_planes(state->dev, state); -} - -static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) +static int intel_modeset_setup_plls(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct drm_i915_private *dev_priv = to_i915(dev); @@ -12839,7 +12808,7 @@ static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) } /* Code that should eventually be part of atomic_check() */ -static int __intel_set_mode_checks(struct drm_atomic_state *state) +static int intel_modeset_checks(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; int ret; @@ -12861,11 +12830,42 @@ static int __intel_set_mode_checks(struct drm_atomic_state *state) return ret; } - ret = __intel_set_mode_setup_plls(state); + return intel_modeset_setup_plls(state); +} + +static int +intel_modeset_compute_config(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int ret, i; + + ret = drm_atomic_helper_check_modeset(state->dev, state); if (ret) return ret; - return 0; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (!crtc_state->enable && + WARN_ON(crtc_state->active)) + crtc_state->active = false; + + if (!crtc_state->enable) + continue; + + ret = intel_modeset_pipe_config(crtc, state); + if (ret) + return ret; + + intel_dump_pipe_config(to_intel_crtc(crtc), + to_intel_crtc_state(crtc_state), + "[modeset]"); + } + + ret = intel_modeset_checks(state); + if (ret) + return ret; + + return drm_atomic_helper_check_planes(state->dev, state); } static int __intel_set_mode(struct drm_atomic_state *state) @@ -12877,10 +12877,6 @@ static int __intel_set_mode(struct drm_atomic_state *state) int ret = 0; int i; - ret = __intel_set_mode_checks(state); - if (ret < 0) - return ret; - ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) return ret; -- cgit v1.3-6-gb490 From 37ade41794e914103b8db417e480afd20dcea971 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 1 Jun 2015 12:50:03 +0200 Subject: drm/i915: Read hw state into an atomic state struct, v2. To make this work we load the new hardware state into the atomic_state, then swap it with the sw state. This lets us change the force restore path in setup_hw_state() to use a single call to intel_mode_set() to restore all the previous state. As a nice bonus this kills off encoder->new_encoder, connector->new_enabled and crtc->new_enabled. They were used only to restore the state after a modeset. Changes since v1: - Make sure all possible planes are added with their crtc set, so they will be turned off on first modeset. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_atomic.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 379 ++++++++++++++++++++++------------- drivers/gpu/drm/i915/intel_drv.h | 14 +- 3 files changed, 243 insertions(+), 152 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 4df6d2d7a9c8..e47e00e5b130 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -395,7 +395,7 @@ int intel_atomic_setup_scalers(struct drm_device *dev, return 0; } -static void +void intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv, struct intel_shared_dpll_config *shared_dpll) { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 12d6da8f0465..c04bc80d1a65 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10312,7 +10312,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, retry: ret = drm_modeset_lock(&config->connection_mutex, ctx); if (ret) - goto fail_unlock; + goto fail; /* * Algorithm gets a little messy: @@ -10330,10 +10330,10 @@ retry: ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; old->dpms_mode = connector->dpms; old->load_detect_temp = false; @@ -10352,9 +10352,6 @@ retry: continue; if (possible_crtc->state->enable) continue; - /* This can occur when applying the pipe A quirk on resume. */ - if (to_intel_crtc(possible_crtc)->new_enabled) - continue; crtc = possible_crtc; break; @@ -10365,20 +10362,17 @@ retry: */ if (!crtc) { DRM_DEBUG_KMS("no pipe available for load-detect\n"); - goto fail_unlock; + goto fail; } ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail_unlock; - intel_encoder->new_crtc = to_intel_crtc(crtc); - to_intel_connector(connector)->new_encoder = intel_encoder; + goto fail; intel_crtc = to_intel_crtc(crtc); - intel_crtc->new_enabled = true; old->dpms_mode = connector->dpms; old->load_detect_temp = true; old->release_fb = NULL; @@ -10446,9 +10440,7 @@ retry: intel_wait_for_vblank(dev, intel_crtc->pipe); return true; - fail: - intel_crtc->new_enabled = crtc->state->enable; -fail_unlock: +fail: drm_atomic_state_free(state); state = NULL; @@ -10494,10 +10486,6 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (IS_ERR(crtc_state)) goto fail; - to_intel_connector(connector)->new_encoder = NULL; - intel_encoder->new_crtc = NULL; - intel_crtc->new_enabled = false; - connector_state->best_encoder = NULL; connector_state->crtc = NULL; @@ -11644,33 +11632,6 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = { .atomic_flush = intel_finish_crtc_commit, }; -/** - * intel_modeset_update_staged_output_state - * - * Updates the staged output configuration state, e.g. after we've read out the - * current hw state. - */ -static void intel_modeset_update_staged_output_state(struct drm_device *dev) -{ - struct intel_crtc *crtc; - struct intel_encoder *encoder; - struct intel_connector *connector; - - for_each_intel_connector(dev, connector) { - connector->new_encoder = - to_intel_encoder(connector->base.encoder); - } - - for_each_intel_encoder(dev, encoder) { - encoder->new_crtc = - to_intel_crtc(encoder->base.crtc); - } - - for_each_intel_crtc(dev, crtc) { - crtc->new_enabled = crtc->base.state->enable; - } -} - /* Transitional helper to copy current connector/encoder state to * connector->state. This is needed so that code that is partially * converted to atomic does the right thing. @@ -12201,7 +12162,6 @@ intel_modeset_update_state(struct drm_atomic_state *state) } drm_atomic_helper_update_legacy_modeset_state(state->dev, state); - intel_modeset_update_staged_output_state(state->dev); /* Double check state. */ for_each_crtc(dev, crtc) { @@ -12505,11 +12465,14 @@ check_connector_state(struct drm_device *dev) struct intel_connector *connector; for_each_intel_connector(dev, connector) { + struct drm_encoder *encoder = connector->base.encoder; + struct drm_connector_state *state = connector->base.state; + /* This also checks the encoder/connector hw state with the * ->get_hw_state callbacks. */ intel_connector_check_state(connector); - I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder, + I915_STATE_WARN(state->best_encoder != encoder, "connector's staged encoder doesn't match current encoder\n"); } } @@ -12529,8 +12492,6 @@ check_encoder_state(struct drm_device *dev) encoder->base.base.id, encoder->base.name); - I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc, - "encoder's stage crtc doesn't match current crtc\n"); I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc, "encoder's active_connectors set, but no crtc\n"); @@ -12540,6 +12501,9 @@ check_encoder_state(struct drm_device *dev) enabled = true; if (connector->base.dpms != DRM_MODE_DPMS_OFF) active = true; + + I915_STATE_WARN(connector->base.state->crtc != encoder->base.crtc, + "encoder's stage crtc doesn't match current crtc\n"); } /* * for MST connectors if we unplug the connector is gone @@ -12969,11 +12933,11 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) * need to copy the staged config to the atomic state, otherwise the * mode set will just reapply the state the HW is already in. */ for_each_intel_encoder(dev, encoder) { - if (&encoder->new_crtc->base != crtc) + if (encoder->base.crtc != crtc) continue; for_each_intel_connector(dev, connector) { - if (connector->new_encoder != encoder) + if (connector->base.state->best_encoder != &encoder->base) continue; connector_state = drm_atomic_get_connector_state(state, &connector->base); @@ -12986,14 +12950,10 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) } connector_state->crtc = crtc; - connector_state->best_encoder = &encoder->base; } } for_each_intel_crtc(dev, intel_crtc) { - if (intel_crtc->new_enabled == intel_crtc->base.enabled) - continue; - crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); if (IS_ERR(crtc_state)) { DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n", @@ -13002,9 +12962,6 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) continue; } - crtc_state->base.active = crtc_state->base.enable = - intel_crtc->new_enabled; - if (&intel_crtc->base == crtc) drm_mode_copy(&crtc_state->base.mode, &crtc->mode); } @@ -15080,6 +15037,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) * ... */ plane = crtc->plane; to_intel_plane_state(crtc->base.primary->state)->visible = true; + crtc->base.primary->crtc = &crtc->base; crtc->plane = !plane; intel_crtc_control(&crtc->base, false); crtc->plane = plane; @@ -15243,99 +15201,225 @@ static bool primary_get_hw_state(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - if (!crtc->active) + if (!crtc->base.enabled) return false; return I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE; } -static void intel_modeset_readout_hw_state(struct drm_device *dev) +static int readout_hw_crtc_state(struct drm_atomic_state *state, + struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe pipe; - struct intel_crtc *crtc; - struct intel_encoder *encoder; - struct intel_connector *connector; - int i; + struct drm_i915_private *dev_priv = to_i915(state->dev); + struct intel_crtc_state *crtc_state; + struct drm_plane *primary = crtc->base.primary; + struct drm_plane_state *drm_plane_state; + struct intel_plane_state *plane_state; + int ret; - for_each_intel_crtc(dev, crtc) { - struct drm_plane *primary = crtc->base.primary; - struct intel_plane_state *plane_state; + crtc_state = intel_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); - memset(crtc->config, 0, sizeof(*crtc->config)); - crtc->config->base.crtc = &crtc->base; + ret = drm_atomic_add_affected_planes(state, &crtc->base); + if (ret) + return ret; - crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; + memset(crtc_state, 0, sizeof(*crtc_state)); + crtc_state->base.crtc = &crtc->base; + crtc_state->base.state = state; - crtc->active = dev_priv->display.get_pipe_config(crtc, - crtc->config); + crtc_state->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; - crtc->base.state->enable = crtc->active; - crtc->base.state->active = crtc->active; - crtc->base.enabled = crtc->active; + crtc_state->base.enable = crtc_state->base.active = + crtc->base.enabled = dev_priv->display.get_pipe_config(crtc, crtc_state); - plane_state = to_intel_plane_state(primary->state); - plane_state->visible = primary_get_hw_state(crtc); + /* update transitional state */ + crtc->active = crtc_state->base.active; + crtc->config = crtc_state; - DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", - crtc->base.base.id, - crtc->active ? "enabled" : "disabled"); - } + drm_plane_state = drm_atomic_get_plane_state(state, primary); + if (IS_ERR(drm_plane_state)) + return PTR_ERR(drm_plane_state); + + plane_state = to_intel_plane_state(drm_plane_state); + plane_state->visible = primary_get_hw_state(crtc); + if (plane_state->visible) { + primary->crtc = &crtc->base; + crtc_state->base.plane_mask |= 1 << drm_plane_index(primary); + } else + crtc_state->base.plane_mask &= ~(1 << drm_plane_index(primary)); + + DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", + crtc->base.base.id, + crtc_state->base.active ? "enabled" : "disabled"); + + return 0; +} + +static int readout_hw_pll_state(struct drm_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->dev); + struct intel_shared_dpll_config *shared_dpll; + struct intel_crtc *crtc; + struct intel_crtc_state *crtc_state; + int i; + + shared_dpll = intel_atomic_get_shared_dpll_state(state); for (i = 0; i < dev_priv->num_shared_dpll; i++) { struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; pll->on = pll->get_hw_state(dev_priv, pll, - &pll->config.hw_state); + &shared_dpll[i].hw_state); + pll->active = 0; - pll->config.crtc_mask = 0; - for_each_intel_crtc(dev, crtc) { - if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) { + shared_dpll[i].crtc_mask = 0; + + for_each_intel_crtc(state->dev, crtc) { + crtc_state = intel_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (crtc_state->base.active && + crtc_state->shared_dpll == i) { pll->active++; - pll->config.crtc_mask |= 1 << crtc->pipe; + shared_dpll[i].crtc_mask |= + 1 << crtc->pipe; } } DRM_DEBUG_KMS("%s hw state readout: crtc_mask 0x%08x, on %i\n", - pll->name, pll->config.crtc_mask, pll->on); + pll->name, shared_dpll[i].crtc_mask, + pll->on); - if (pll->config.crtc_mask) + if (shared_dpll[i].crtc_mask) intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); } - for_each_intel_encoder(dev, encoder) { - pipe = 0; + return 0; +} - if (encoder->get_hw_state(encoder, &pipe)) { - crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - encoder->base.crtc = &crtc->base; - encoder->get_config(encoder, crtc->config); - } else { - encoder->base.crtc = NULL; - } +static struct drm_connector_state * +get_connector_state_for_encoder(struct drm_atomic_state *state, + struct intel_encoder *encoder) +{ + struct drm_connector *connector; + struct drm_connector_state *connector_state; + int i; - encoder->connectors_active = false; - DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe %c\n", - encoder->base.base.id, - encoder->base.name, - encoder->base.crtc ? "enabled" : "disabled", - pipe_name(pipe)); - } + for_each_connector_in_state(state, connector, connector_state, i) + if (connector_state->best_encoder == &encoder->base) + return connector_state; + + return NULL; +} + +static int readout_hw_connector_encoder_state(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = to_i915(state->dev); + struct intel_crtc *crtc; + struct drm_crtc_state *drm_crtc_state; + struct intel_crtc_state *crtc_state; + struct intel_encoder *encoder; + struct intel_connector *connector; + struct drm_connector_state *connector_state; + enum pipe pipe; for_each_intel_connector(dev, connector) { + connector_state = + drm_atomic_get_connector_state(state, &connector->base); + if (IS_ERR(connector_state)) + return PTR_ERR(connector_state); + if (connector->get_hw_state(connector)) { connector->base.dpms = DRM_MODE_DPMS_ON; - connector->encoder->connectors_active = true; connector->base.encoder = &connector->encoder->base; } else { connector->base.dpms = DRM_MODE_DPMS_OFF; connector->base.encoder = NULL; } + + /* We'll update the crtc field when reading encoder state */ + connector_state->crtc = NULL; + + connector_state->best_encoder = connector->base.encoder; + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n", connector->base.base.id, connector->base.name, connector->base.encoder ? "enabled" : "disabled"); } + + for_each_intel_encoder(dev, encoder) { + pipe = 0; + + connector_state = + get_connector_state_for_encoder(state, encoder); + + encoder->connectors_active = !!connector_state; + + if (encoder->get_hw_state(encoder, &pipe)) { + encoder->base.crtc = + dev_priv->pipe_to_crtc_mapping[pipe]; + crtc = to_intel_crtc(encoder->base.crtc); + + drm_crtc_state = + state->crtc_states[drm_crtc_index(&crtc->base)]; + crtc_state = to_intel_crtc_state(drm_crtc_state); + + encoder->get_config(encoder, crtc_state); + + if (connector_state) + connector_state->crtc = &crtc->base; + } else { + encoder->base.crtc = NULL; + } + + DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe %c\n", + encoder->base.base.id, + encoder->base.name, + encoder->base.crtc ? "enabled" : "disabled", + pipe_name(pipe)); + } + + return 0; +} + +static struct drm_atomic_state * +intel_modeset_readout_hw_state(struct drm_device *dev) +{ + struct intel_crtc *crtc; + int ret = 0; + + struct drm_atomic_state *state; + + state = drm_atomic_state_alloc(dev); + if (!state) + return ERR_PTR(-ENOMEM); + + state->acquire_ctx = dev->mode_config.acquire_ctx; + + for_each_intel_crtc(dev, crtc) { + ret = readout_hw_crtc_state(state, crtc); + if (ret) + goto err_free; + } + + ret = readout_hw_pll_state(state); + if (ret) + goto err_free; + + ret = readout_hw_connector_encoder_state(state); + if (ret) + goto err_free; + + return state; + +err_free: + drm_atomic_state_free(state); + return ERR_PTR(ret); } /* Scan out the current hw modeset state, sanitizes it and maps it into the drm @@ -15344,37 +15428,57 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore) { struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe pipe; - struct intel_crtc *crtc; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; struct intel_encoder *encoder; + struct drm_atomic_state *state; + struct intel_shared_dpll_config shared_dplls[I915_NUM_PLLS]; int i; - intel_modeset_readout_hw_state(dev); - - /* - * Now that we have the config, copy it to each CRTC struct - * Note that this could go away if we move to using crtc_config - * checking everywhere. - */ - for_each_intel_crtc(dev, crtc) { - if (crtc->active && i915.fastboot) { - intel_mode_from_pipe_config(&crtc->base.mode, - crtc->config); - DRM_DEBUG_KMS("[CRTC:%d] found active mode: ", - crtc->base.base.id); - drm_mode_debug_printmodeline(&crtc->base.mode); - } + state = intel_modeset_readout_hw_state(dev); + if (IS_ERR(state)) { + DRM_ERROR("Failed to read out hw state\n"); + return; } + drm_atomic_helper_swap_state(dev, state); + + /* swap sw/hw dpll state */ + intel_atomic_duplicate_dpll_state(dev_priv, shared_dplls); + intel_shared_dpll_commit(state); + memcpy(to_intel_atomic_state(state)->shared_dpll, + shared_dplls, sizeof(*shared_dplls) * dev_priv->num_shared_dpll); + /* HW state is read out, now we need to sanitize this mess. */ for_each_intel_encoder(dev, encoder) { intel_sanitize_encoder(encoder); } - for_each_pipe(dev_priv, pipe) { - crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - intel_sanitize_crtc(crtc); - intel_dump_pipe_config(crtc, crtc->config, + for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + /* prevent unnneeded restores with force_restore */ + crtc_state->active_changed = + crtc_state->mode_changed = + crtc_state->planes_changed = false; + + if (crtc->enabled) { + intel_mode_from_pipe_config(&crtc->state->mode, + to_intel_crtc_state(crtc->state)); + + drm_mode_copy(&crtc->mode, &crtc->state->mode); + drm_mode_copy(&crtc->hwmode, + &crtc->state->adjusted_mode); + } + + intel_sanitize_crtc(intel_crtc); + + /* + * sanitize_crtc may have forced an update of crtc->state, + * so reload in intel_dump_pipe_config + */ + intel_dump_pipe_config(intel_crtc, + to_intel_crtc_state(crtc->state), "[setup_hw_state]"); } @@ -15398,20 +15502,17 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, ilk_wm_get_hw_state(dev); if (force_restore) { - i915_redisable_vga(dev); + int ret; - /* - * We need to use raw interfaces for restoring state to avoid - * checking (bogus) intermediate states. - */ - for_each_pipe(dev_priv, pipe) { - struct drm_crtc *crtc = - dev_priv->pipe_to_crtc_mapping[pipe]; + i915_redisable_vga(dev); - intel_crtc_restore_mode(crtc); + ret = intel_set_mode(state); + if (ret) { + DRM_ERROR("Failed to restore previous mode\n"); + drm_atomic_state_free(state); } } else { - intel_modeset_update_staged_output_state(dev); + drm_atomic_state_free(state); } intel_modeset_check_state(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e15039800cf0..4aa10a5198f6 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -130,11 +130,6 @@ struct intel_fbdev { struct intel_encoder { struct drm_encoder base; - /* - * The new crtc this encoder will be driven from. Only differs from - * base->crtc while a modeset is in progress. - */ - struct intel_crtc *new_crtc; enum intel_output_type type; unsigned int cloneable; @@ -195,12 +190,6 @@ struct intel_connector { */ struct intel_encoder *encoder; - /* - * The new encoder this connector will be driven. Only differs from - * encoder while a modeset is in progress. - */ - struct intel_encoder *new_encoder; - /* Reads out the current hw, returning true if the connector is enabled * and active (i.e. dpms ON state). */ bool (*get_hw_state)(struct intel_connector *); @@ -535,7 +524,6 @@ struct intel_crtc { struct intel_initial_plane_config plane_config; struct intel_crtc_state *config; - bool new_enabled; /* reset counter value when the last flip was submitted */ unsigned int reset_counter; @@ -1416,6 +1404,8 @@ struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev); void intel_atomic_state_clear(struct drm_atomic_state *); struct intel_shared_dpll_config * intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s); +void intel_atomic_duplicate_dpll_state(struct drm_i915_private *, + struct intel_shared_dpll_config *); static inline struct intel_crtc_state * intel_atomic_get_crtc_state(struct drm_atomic_state *state, -- cgit v1.3-6-gb490 From 5da76e94c4b8d40465a907fc3a151051e8021cdc Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:04 +0200 Subject: drm/i915: Implement intel_crtc_control using atomic state, v4 Assume the callers lock everything with drm_modeset_lock_all. This change had to be done after converting suspend/resume to use atomic_state so the atomic state is preserved, otherwise all transitional state is erased. Now all callers of .crtc_enable and .crtc_disable go through atomic modeset! :-D Changes since v1: - Only check for crtc_state->active in valleyview_modeset_global_pipes. - Only check for crtc_state->active in modeset_update_crtc_power_domains. Changes since v2: - Rework on top of the changed patch order. Changes since v3: - Rename intel_crtc_toggle in description to *_control - Change return value to int. - Do not add plane state, should be done implicitly already. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 53 ++++++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 33 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c04bc80d1a65..048a86857d0d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6238,38 +6238,49 @@ void intel_display_suspend(struct drm_device *dev) } /* Master function to enable/disable CRTC and corresponding power wells */ -void intel_crtc_control(struct drm_crtc *crtc, bool enable) +int intel_crtc_control(struct drm_crtc *crtc, bool enable) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum intel_display_power_domain domain; - unsigned long domains; + struct intel_crtc_state *pipe_config; + struct drm_atomic_state *state; + int ret; if (enable == intel_crtc->active) - return; + return 0; if (enable && !crtc->state->enable) - return; + return 0; - crtc->state->active = enable; - if (enable) { - domains = get_crtc_power_domains(crtc); - for_each_power_domain(domain, domains) - intel_display_power_get(dev_priv, domain); - intel_crtc->enabled_power_domains = domains; + /* this function should be called with drm_modeset_lock_all for now */ + if (WARN_ON(!ctx)) + return -EIO; + lockdep_assert_held(&ctx->ww_ctx); - dev_priv->display.crtc_enable(crtc); - intel_crtc_enable_planes(crtc); - } else { - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); + state = drm_atomic_state_alloc(dev); + if (WARN_ON(!state)) + return -ENOMEM; - domains = intel_crtc->enabled_power_domains; - for_each_power_domain(domain, domains) - intel_display_power_put(dev_priv, domain); - intel_crtc->enabled_power_domains = 0; + state->acquire_ctx = ctx; + state->allow_modeset = true; + + pipe_config = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(pipe_config)) { + ret = PTR_ERR(pipe_config); + goto err; } + pipe_config->base.active = enable; + + ret = intel_set_mode(state); + if (!ret) + return ret; + +err: + DRM_ERROR("Updating crtc active failed with %i\n", ret); + drm_atomic_state_free(state); + return ret; } /** diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4aa10a5198f6..7f8fa7f026aa 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -990,7 +990,7 @@ void intel_mark_busy(struct drm_device *dev); void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); void intel_display_suspend(struct drm_device *dev); -void intel_crtc_control(struct drm_crtc *crtc, bool enable); +int intel_crtc_control(struct drm_crtc *crtc, bool enable); void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); int intel_connector_init(struct intel_connector *); -- cgit v1.3-6-gb490 From 06ea0b0897db906c5616f660a34b54d92f7d09cf Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:05 +0200 Subject: drm/i915: Make intel_display_suspend atomic, v2. Calculate all state using a normal transition, but afterwards fudge crtc->state->active back to its old value. This should still allow state restore in setup_hw_state to work properly. Calling intel_set_mode will cause intel_display_set_init_power to be called, make sure init_power gets set again afterwards. Changes since v1: - Fix to compile with v2 of the patch that adds intel_display_suspend. - Add intel_display_set_init_power. - Set return value to int to allow error checking. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.c | 3 ++ drivers/gpu/drm/i915/intel_display.c | 55 ++++++++++++++++++++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 3 files changed, 47 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 78ef0bb53c36..d3632c56fdf7 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -634,6 +634,9 @@ static int i915_drm_suspend(struct drm_device *dev) intel_display_suspend(dev); drm_modeset_unlock_all(dev); + /* suspending displays will unsets init power */ + intel_display_set_init_power(dev_priv, true); + intel_dp_mst_suspend(dev); intel_runtime_pm_disable_interrupts(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 048a86857d0d..547d6db2a6ee 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6214,27 +6214,58 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) * turn all crtc's off, but do not adjust state * This has to be paired with a call to intel_modeset_setup_hw_state. */ -void intel_display_suspend(struct drm_device *dev) +int intel_display_suspend(struct drm_device *dev) { - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; + struct drm_atomic_state *state; struct drm_crtc *crtc; + unsigned crtc_mask = 0; + int ret = 0; + + if (WARN_ON(!ctx)) + return 0; + + lockdep_assert_held(&ctx->ww_ctx); + state = drm_atomic_state_alloc(dev); + if (WARN_ON(!state)) + return -ENOMEM; + + state->acquire_ctx = ctx; + state->allow_modeset = true; for_each_crtc(dev, crtc) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum intel_display_power_domain domain; - unsigned long domains; + struct drm_crtc_state *crtc_state = + drm_atomic_get_crtc_state(state, crtc); - if (!intel_crtc->active) + ret = PTR_ERR_OR_ZERO(crtc_state); + if (ret) + goto free; + + if (!crtc_state->active) continue; - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); + crtc_state->active = false; + crtc_mask |= 1 << drm_crtc_index(crtc); + } - domains = intel_crtc->enabled_power_domains; - for_each_power_domain(domain, domains) - intel_display_power_put(dev_priv, domain); - intel_crtc->enabled_power_domains = 0; + if (crtc_mask) { + ret = intel_set_mode(state); + + if (!ret) { + for_each_crtc(dev, crtc) + if (crtc_mask & (1 << drm_crtc_index(crtc))) + crtc->state->active = true; + + return ret; + } } + +free: + if (ret) + DRM_ERROR("Suspending crtc's failed with %i\n", ret); + drm_atomic_state_free(state); + return ret; } /* Master function to enable/disable CRTC and corresponding power wells */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7f8fa7f026aa..6d9c771747f9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -989,7 +989,7 @@ int intel_pch_rawclk(struct drm_device *dev); void intel_mark_busy(struct drm_device *dev); void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); -void intel_display_suspend(struct drm_device *dev); +int intel_display_suspend(struct drm_device *dev); int intel_crtc_control(struct drm_crtc *crtc, bool enable); void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); -- cgit v1.3-6-gb490 From 1c5e19f8f124b2ff442756e79d9a05c2b9494a28 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:06 +0200 Subject: drm/i915: move swap state to the right place This is a preparation for passing crtc state to the helpers. When converting all users of crtc->config to use the old or new state it's easier to find regressions when swap_state is done first. If crtc->config is swapped at the same place as swap_state bugs will never be found. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 547d6db2a6ee..d4d7708b58a4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12189,7 +12189,6 @@ intel_modeset_update_state(struct drm_atomic_state *state) struct drm_connector *connector; intel_shared_dpll_commit(state); - drm_atomic_helper_swap_state(state->dev, state); for_each_intel_encoder(dev, intel_encoder) { if (!intel_encoder->base.crtc) @@ -12887,8 +12886,10 @@ static int __intel_set_mode(struct drm_atomic_state *state) if (ret) return ret; + drm_atomic_helper_swap_state(dev, state); + for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc_state) || !crtc->state->active) + if (!needs_modeset(crtc->state) || !crtc_state->active) continue; intel_crtc_disable_planes(crtc); -- cgit v1.3-6-gb490 From fc467a221a01c5ec369a3969fcafea077c3677b4 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:07 +0200 Subject: drm/i915: Use crtc->hwmode for vblanks, v2. intel_crtc->config will be removed eventually, so use crtc->hwmode. drm_atomic_helper_update_legacy_modeset_state updates hwmode, but crtc->active will eventually be gone too. Set dotclock to zero to indicate the crtc is inactive. Changes since v1: - With the hwmode update in drm*update_legacy_modeset_state removed, intel_modeset_update_state has to assign it instead. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_irq.c | 13 ++++++------- drivers/gpu/drm/i915/intel_display.c | 6 ++++++ 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index dadd586f0527..56db9e747464 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -564,8 +564,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal; struct intel_crtc *intel_crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - const struct drm_display_mode *mode = - &intel_crtc->config->base.adjusted_mode; + const struct drm_display_mode *mode = &intel_crtc->base.hwmode; htotal = mode->crtc_htotal; hsync_start = mode->crtc_hsync_start; @@ -620,7 +619,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode; + const struct drm_display_mode *mode = &crtc->base.hwmode; enum pipe pipe = crtc->pipe; int position, vtotal; @@ -647,14 +646,14 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, 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); - const struct drm_display_mode *mode = &intel_crtc->config->base.adjusted_mode; + const struct drm_display_mode *mode = &intel_crtc->base.hwmode; int position; int vbl_start, vbl_end, hsync_start, htotal, vtotal; bool in_vbl = true; int ret = 0; unsigned long irqflags; - if (!intel_crtc->active) { + if (WARN_ON(!mode->crtc_clock)) { DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " "pipe %c\n", pipe_name(pipe)); return 0; @@ -796,7 +795,7 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, return -EINVAL; } - if (!crtc->state->active) { + if (!crtc->hwmode.crtc_clock) { DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); return -EBUSY; } @@ -805,7 +804,7 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, vblank_time, flags, crtc, - &to_intel_crtc(crtc)->config->base.adjusted_mode); + &crtc->hwmode); } static bool intel_hpd_irq_event(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d4d7708b58a4..7e2bbd7e6210 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12209,6 +12209,12 @@ intel_modeset_update_state(struct drm_atomic_state *state) WARN_ON(crtc->state->enable != intel_crtc_in_use(crtc)); to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); + + /* Update hwmode for vblank functions */ + if (crtc->state->active) + crtc->hwmode = crtc->state->adjusted_mode; + else + crtc->hwmode.crtc_clock = 0; } list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -- cgit v1.3-6-gb490 From f77076c91d563a07c6519b80e234b4e962306b67 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:08 +0200 Subject: drm/i915: Remove use of crtc->config from i915_debugfs.c crtc->config is updated to always contain to the active crtc_state and only differs from crtc_state during crtc_disable. It will eventually be removed, so start with some low hanging fruit. For crtc->active the situation is the same; it will be removed eventually. Instead use crtc->state->active. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_debugfs.c | 42 ++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index aac252ca0bda..0029c25bf72a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2779,13 +2779,16 @@ static int i915_display_info(struct seq_file *m, void *unused) seq_printf(m, "---------\n"); for_each_intel_crtc(dev, crtc) { bool active; + struct intel_crtc_state *pipe_config; int x, y; + pipe_config = to_intel_crtc_state(crtc->base.state); + seq_printf(m, "CRTC %d: pipe: %c, active=%s (size=%dx%d)\n", crtc->base.base.id, pipe_name(crtc->pipe), - yesno(crtc->active), crtc->config->pipe_src_w, - crtc->config->pipe_src_h); - if (crtc->active) { + yesno(pipe_config->base.active), + pipe_config->pipe_src_w, pipe_config->pipe_src_h); + if (pipe_config->base.active) { intel_crtc_info(m, crtc); active = cursor_position(dev, crtc->pipe, &x, &y); @@ -3026,7 +3029,7 @@ static void drrs_status_per_crtc(struct seq_file *m, seq_puts(m, "\n\n"); - if (intel_crtc->config->has_drrs) { + if (to_intel_crtc_state(intel_crtc->base.state)->has_drrs) { struct intel_panel *panel; mutex_lock(&drrs->mutex); @@ -3078,7 +3081,7 @@ static int i915_drrs_status(struct seq_file *m, void *unused) for_each_intel_crtc(dev, intel_crtc) { drm_modeset_lock(&intel_crtc->base.mutex, NULL); - if (intel_crtc->active) { + if (intel_crtc->base.state->active) { active_crtc_cnt++; seq_printf(m, "\nCRTC %d: ", active_crtc_cnt); @@ -3620,22 +3623,27 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_A]); + struct intel_crtc_state *pipe_config; drm_modeset_lock_all(dev); + pipe_config = to_intel_crtc_state(crtc->base.state); + /* * If we use the eDP transcoder we need to make sure that we don't * bypass the pfit, since otherwise the pipe CRC source won't work. Only * relevant on hsw with pipe A when using the always-on power well * routing. */ - if (crtc->config->cpu_transcoder == TRANSCODER_EDP && - !crtc->config->pch_pfit.enabled) { - bool active = crtc->active; + if (pipe_config->cpu_transcoder == TRANSCODER_EDP && + !pipe_config->pch_pfit.enabled) { + bool active = pipe_config->base.active; - if (active) + if (active) { intel_crtc_control(&crtc->base, false); + pipe_config = to_intel_crtc_state(crtc->base.state); + } - crtc->config->pch_pfit.force_thru = true; + pipe_config->pch_pfit.force_thru = true; intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A)); @@ -3651,6 +3659,7 @@ static void hsw_undo_trans_edp_pipe_A_crc_wa(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_A]); + struct intel_crtc_state *pipe_config; drm_modeset_lock_all(dev); /* @@ -3659,13 +3668,16 @@ static void hsw_undo_trans_edp_pipe_A_crc_wa(struct drm_device *dev) * relevant on hsw with pipe A when using the always-on power well * routing. */ - if (crtc->config->pch_pfit.force_thru) { - bool active = crtc->active; + pipe_config = to_intel_crtc_state(crtc->base.state); + if (pipe_config->pch_pfit.force_thru) { + bool active = pipe_config->base.active; - if (active) + if (active) { intel_crtc_control(&crtc->base, false); + pipe_config = to_intel_crtc_state(crtc->base.state); + } - crtc->config->pch_pfit.force_thru = false; + pipe_config->pch_pfit.force_thru = false; intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A)); @@ -3787,7 +3799,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, pipe_name(pipe)); drm_modeset_lock(&crtc->base.mutex, NULL); - if (crtc->active) + if (crtc->base.state->active) intel_wait_for_vblank(dev, pipe); drm_modeset_unlock(&crtc->base.mutex); -- cgit v1.3-6-gb490 From 99d736a2ce431dbbcf96ee9d26bd41ca2c2284a1 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:09 +0200 Subject: drm/i915: Calculate haswell plane workaround, v5. This needs to be done last after all modesets have been calculated. A modeset first disables all crtc's, so any crtc that undergoes a modeset counts as inactive. If no modeset's done, or > 1 crtc's stay w/a doesn't apply. Apply workaround on the first crtc if 1 crtc stays active. Apply workaround on the second crtc if no crtc was active. Changes since v1: - Use intel_crtc->atomic as a place to put hsw_workaround_pipe. - Make sure quirk only applies to haswell. - Use first loop to iterate over newly enabled crtc's only. This increases readability. Changes since v2: - Move hsw_workaround_pipe back to crtc_state. Changes since v3: - Return errors from haswell_mode_set_planes_workaround. Changes since v4: - Clean up commit message. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 113 +++++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_drv.h | 3 + 2 files changed, 84 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e2bbd7e6210..cd9a7545b0d3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4864,42 +4864,15 @@ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc) return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A; } -/* - * This implements the workaround described in the "notes" section of the mode - * set sequence documentation. When going from no pipes or single pipe to - * multiple pipes, and planes are enabled after the pipe, we need to wait at - * least 2 vblanks on the first pipe before enabling planes on the second pipe. - */ -static void haswell_mode_set_planes_workaround(struct intel_crtc *crtc) -{ - struct drm_device *dev = crtc->base.dev; - struct intel_crtc *crtc_it, *other_active_crtc = NULL; - - /* We want to get the other_active_crtc only if there's only 1 other - * active crtc. */ - for_each_intel_crtc(dev, crtc_it) { - if (!crtc_it->active || crtc_it == crtc) - continue; - - if (other_active_crtc) - return; - - other_active_crtc = crtc_it; - } - if (!other_active_crtc) - return; - - intel_wait_for_vblank(dev, other_active_crtc->pipe); - intel_wait_for_vblank(dev, other_active_crtc->pipe); -} - static void haswell_crtc_enable(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); struct intel_encoder *encoder; - int pipe = intel_crtc->pipe; + int pipe = intel_crtc->pipe, hsw_workaround_pipe; + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc->state); if (WARN_ON(intel_crtc->active)) return; @@ -4976,7 +4949,11 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) /* If we change the relative order between pipe/planes enabling, we need * to change the workaround. */ - haswell_mode_set_planes_workaround(intel_crtc); + hsw_workaround_pipe = pipe_config->hsw_workaround_pipe; + if (IS_HASWELL(dev) && hsw_workaround_pipe != INVALID_PIPE) { + intel_wait_for_vblank(dev, hsw_workaround_pipe); + intel_wait_for_vblank(dev, hsw_workaround_pipe); + } } static void ironlake_pfit_disable(struct intel_crtc *crtc) @@ -12818,6 +12795,71 @@ static int intel_modeset_setup_plls(struct drm_atomic_state *state) return ret; } +/* + * This implements the workaround described in the "notes" section of the mode + * set sequence documentation. When going from no pipes or single pipe to + * multiple pipes, and planes are enabled after the pipe, we need to wait at + * least 2 vblanks on the first pipe before enabling planes on the second pipe. + */ +static int haswell_mode_set_planes_workaround(struct drm_atomic_state *state) +{ + struct drm_crtc_state *crtc_state; + struct intel_crtc *intel_crtc; + struct drm_crtc *crtc; + struct intel_crtc_state *first_crtc_state = NULL; + struct intel_crtc_state *other_crtc_state = NULL; + enum pipe first_pipe = INVALID_PIPE, enabled_pipe = INVALID_PIPE; + int i; + + /* look at all crtc's that are going to be enabled in during modeset */ + for_each_crtc_in_state(state, crtc, crtc_state, i) { + intel_crtc = to_intel_crtc(crtc); + + if (!crtc_state->active || !needs_modeset(crtc_state)) + continue; + + if (first_crtc_state) { + other_crtc_state = to_intel_crtc_state(crtc_state); + break; + } else { + first_crtc_state = to_intel_crtc_state(crtc_state); + first_pipe = intel_crtc->pipe; + } + } + + /* No workaround needed? */ + if (!first_crtc_state) + return 0; + + /* w/a possibly needed, check how many crtc's are already enabled. */ + for_each_intel_crtc(state->dev, intel_crtc) { + struct intel_crtc_state *pipe_config; + + pipe_config = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(pipe_config)) + return PTR_ERR(pipe_config); + + pipe_config->hsw_workaround_pipe = INVALID_PIPE; + + if (!pipe_config->base.active || + needs_modeset(&pipe_config->base)) + continue; + + /* 2 or more enabled crtcs means no need for w/a */ + if (enabled_pipe != INVALID_PIPE) + return 0; + + enabled_pipe = intel_crtc->pipe; + } + + if (enabled_pipe != INVALID_PIPE) + first_crtc_state->hsw_workaround_pipe = enabled_pipe; + else if (other_crtc_state) + other_crtc_state->hsw_workaround_pipe = first_pipe; + + return 0; +} + /* Code that should eventually be part of atomic_check() */ static int intel_modeset_checks(struct drm_atomic_state *state) { @@ -12841,7 +12883,14 @@ static int intel_modeset_checks(struct drm_atomic_state *state) return ret; } - return intel_modeset_setup_plls(state); + ret = intel_modeset_setup_plls(state); + if (ret) + return ret; + + if (IS_HASWELL(dev)) + ret = haswell_mode_set_planes_workaround(state); + + return ret; } static int diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6d9c771747f9..5312160e7c95 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -443,6 +443,9 @@ struct intel_crtc_state { int pbn; struct intel_crtc_scaler_state scaler_state; + + /* w/a for waiting 2 vblanks during crtc enable */ + enum pipe hsw_workaround_pipe; }; struct intel_pipe_wm { -- cgit v1.3-6-gb490 From 3538b9dffd8344cd40413018bcd7dc7b2bc1e21d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:10 +0200 Subject: drm/i915: Use atomic state for calculating DVO_2X_MODE on i830. This is a small behavioral change because it leaves DVO_2X_MODE set between crtc_disable and crtc_enable. This is probably harmless though and if not should be fixed by calculating 2x mode before enable/disable pll. This is needed because intel_crtc->active will be removed eventually. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cd9a7545b0d3..28fc3efa95ed 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1698,7 +1698,7 @@ static int intel_num_dvo_pipes(struct drm_device *dev) int count = 0; for_each_intel_crtc(dev, crtc) - count += crtc->active && + count += crtc->base.state->active && intel_pipe_has_type(crtc, INTEL_OUTPUT_DVO); return count; @@ -1779,7 +1779,7 @@ static void i9xx_disable_pll(struct intel_crtc *crtc) /* Disable DVO 2x clock on both PLLs if necessary */ if (IS_I830(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_DVO) && - intel_num_dvo_pipes(dev) == 1) { + !intel_num_dvo_pipes(dev)) { I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) & ~DPLL_DVO_2X_MODE); I915_WRITE(DPLL(PIPE_A), -- cgit v1.3-6-gb490 From 5c2db1882ab32546c46318d9feb017673c072717 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:11 +0200 Subject: drm/i915: use calculated state for vblank evasion crtc->active will be gone eventually, and this check should be just as good. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 28fc3efa95ed..a232dc9f51f6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13658,6 +13658,7 @@ static void intel_begin_crtc_commit(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); + struct drm_crtc_state *crtc_state = intel_crtc->base.state; struct intel_plane *intel_plane; struct drm_plane *p; unsigned fb_bits = 0; @@ -13701,7 +13702,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) intel_runtime_pm_get(dev_priv); /* Perform vblank evasion around commit operation */ - if (intel_crtc->active) + if (crtc_state->active && !needs_modeset(crtc_state)) intel_crtc->atomic.evade = intel_pipe_update_start(intel_crtc, &intel_crtc->atomic.start_vbl_count); -- cgit v1.3-6-gb490 From 9716c691ce06b043d3e75c8ff93704cb40c52265 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 10 Jun 2015 10:24:19 +0200 Subject: Revert "drm/i915: Make intel_display_suspend atomic, v2." This reverts commit 490f400db5d886fc28566af69b02f6497f31be4b. We're not ready yet to make it atomic, we calculate some state in advance, but without atomic plane support atomic the hw readout will fail. It's required to revert this commit to revert the atomic hw state readout patch. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90868 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90861 Signed-off-by: Maarten Lankhorst Acked-by: Ander Conselvan de Oliveira Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.c | 3 -- drivers/gpu/drm/i915/intel_display.c | 55 ++++++++---------------------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 3 files changed, 13 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index d3632c56fdf7..78ef0bb53c36 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -634,9 +634,6 @@ static int i915_drm_suspend(struct drm_device *dev) intel_display_suspend(dev); drm_modeset_unlock_all(dev); - /* suspending displays will unsets init power */ - intel_display_set_init_power(dev_priv, true); - intel_dp_mst_suspend(dev); intel_runtime_pm_disable_interrupts(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a232dc9f51f6..cc7fad9905b9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6191,58 +6191,27 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) * turn all crtc's off, but do not adjust state * This has to be paired with a call to intel_modeset_setup_hw_state. */ -int intel_display_suspend(struct drm_device *dev) +void intel_display_suspend(struct drm_device *dev) { - struct drm_mode_config *config = &dev->mode_config; - struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; - struct drm_atomic_state *state; + struct drm_i915_private *dev_priv = to_i915(dev); struct drm_crtc *crtc; - unsigned crtc_mask = 0; - int ret = 0; - - if (WARN_ON(!ctx)) - return 0; - - lockdep_assert_held(&ctx->ww_ctx); - state = drm_atomic_state_alloc(dev); - if (WARN_ON(!state)) - return -ENOMEM; - - state->acquire_ctx = ctx; - state->allow_modeset = true; for_each_crtc(dev, crtc) { - struct drm_crtc_state *crtc_state = - drm_atomic_get_crtc_state(state, crtc); - - ret = PTR_ERR_OR_ZERO(crtc_state); - if (ret) - goto free; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum intel_display_power_domain domain; + unsigned long domains; - if (!crtc_state->active) + if (!intel_crtc->active) continue; - crtc_state->active = false; - crtc_mask |= 1 << drm_crtc_index(crtc); - } - - if (crtc_mask) { - ret = intel_set_mode(state); - - if (!ret) { - for_each_crtc(dev, crtc) - if (crtc_mask & (1 << drm_crtc_index(crtc))) - crtc->state->active = true; + intel_crtc_disable_planes(crtc); + dev_priv->display.crtc_disable(crtc); - return ret; - } + domains = intel_crtc->enabled_power_domains; + for_each_power_domain(domain, domains) + intel_display_power_put(dev_priv, domain); + intel_crtc->enabled_power_domains = 0; } - -free: - if (ret) - DRM_ERROR("Suspending crtc's failed with %i\n", ret); - drm_atomic_state_free(state); - return ret; } /* Master function to enable/disable CRTC and corresponding power wells */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5312160e7c95..9ca683ae2dec 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -992,7 +992,7 @@ int intel_pch_rawclk(struct drm_device *dev); void intel_mark_busy(struct drm_device *dev); void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); -int intel_display_suspend(struct drm_device *dev); +void intel_display_suspend(struct drm_device *dev); int intel_crtc_control(struct drm_crtc *crtc, bool enable); void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); -- cgit v1.3-6-gb490 From f721790560be9551c9e7f1644e04960b3ac44d06 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 10 Jun 2015 10:24:20 +0200 Subject: Revert "drm/i915: Read hw state into an atomic state struct, v2." This reverts commit 3bae26eb2991c00670df377cf6c3bc2b0577e82a. Seems it introduces regressions for 3 different reasons, oh boy.. In bug #90868 as I can see the atomic state will be restored on resume without the planes being set up properly. Because plane setup here requires the atomic state, we'll have to settle for committing atomic planes first. In bug #90861 the failure appears to affect mostly DP devices, and happens because reading out the atomic state prevents a modeset on boot, which would require better hw state readout. In bug #90874 it's shown that cdclk should be part of the atomic state, so only performing a single modeset during resume excarbated the issue. It's better to fix those issues first, and then commit this patch, so do that temporarily. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90868 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90861 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90874 Signed-off-by: Maarten Lankhorst Acked-by: Ander Conselvan de Oliveira Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_atomic.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 379 +++++++++++++---------------------- drivers/gpu/drm/i915/intel_drv.h | 14 +- 3 files changed, 152 insertions(+), 243 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index e47e00e5b130..4df6d2d7a9c8 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -395,7 +395,7 @@ int intel_atomic_setup_scalers(struct drm_device *dev, return 0; } -void +static void intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv, struct intel_shared_dpll_config *shared_dpll) { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cc7fad9905b9..5cc2263db199 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10300,7 +10300,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, retry: ret = drm_modeset_lock(&config->connection_mutex, ctx); if (ret) - goto fail; + goto fail_unlock; /* * Algorithm gets a little messy: @@ -10318,10 +10318,10 @@ retry: ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail; + goto fail_unlock; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail; + goto fail_unlock; old->dpms_mode = connector->dpms; old->load_detect_temp = false; @@ -10340,6 +10340,9 @@ retry: continue; if (possible_crtc->state->enable) continue; + /* This can occur when applying the pipe A quirk on resume. */ + if (to_intel_crtc(possible_crtc)->new_enabled) + continue; crtc = possible_crtc; break; @@ -10350,17 +10353,20 @@ retry: */ if (!crtc) { DRM_DEBUG_KMS("no pipe available for load-detect\n"); - goto fail; + goto fail_unlock; } ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail; + goto fail_unlock; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail; + goto fail_unlock; + intel_encoder->new_crtc = to_intel_crtc(crtc); + to_intel_connector(connector)->new_encoder = intel_encoder; intel_crtc = to_intel_crtc(crtc); + intel_crtc->new_enabled = true; old->dpms_mode = connector->dpms; old->load_detect_temp = true; old->release_fb = NULL; @@ -10428,7 +10434,9 @@ retry: intel_wait_for_vblank(dev, intel_crtc->pipe); return true; -fail: + fail: + intel_crtc->new_enabled = crtc->state->enable; +fail_unlock: drm_atomic_state_free(state); state = NULL; @@ -10474,6 +10482,10 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (IS_ERR(crtc_state)) goto fail; + to_intel_connector(connector)->new_encoder = NULL; + intel_encoder->new_crtc = NULL; + intel_crtc->new_enabled = false; + connector_state->best_encoder = NULL; connector_state->crtc = NULL; @@ -11620,6 +11632,33 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = { .atomic_flush = intel_finish_crtc_commit, }; +/** + * intel_modeset_update_staged_output_state + * + * Updates the staged output configuration state, e.g. after we've read out the + * current hw state. + */ +static void intel_modeset_update_staged_output_state(struct drm_device *dev) +{ + struct intel_crtc *crtc; + struct intel_encoder *encoder; + struct intel_connector *connector; + + for_each_intel_connector(dev, connector) { + connector->new_encoder = + to_intel_encoder(connector->base.encoder); + } + + for_each_intel_encoder(dev, encoder) { + encoder->new_crtc = + to_intel_crtc(encoder->base.crtc); + } + + for_each_intel_crtc(dev, crtc) { + crtc->new_enabled = crtc->base.state->enable; + } +} + /* Transitional helper to copy current connector/encoder state to * connector->state. This is needed so that code that is partially * converted to atomic does the right thing. @@ -12149,6 +12188,7 @@ intel_modeset_update_state(struct drm_atomic_state *state) } drm_atomic_helper_update_legacy_modeset_state(state->dev, state); + intel_modeset_update_staged_output_state(state->dev); /* Double check state. */ for_each_crtc(dev, crtc) { @@ -12458,14 +12498,11 @@ check_connector_state(struct drm_device *dev) struct intel_connector *connector; for_each_intel_connector(dev, connector) { - struct drm_encoder *encoder = connector->base.encoder; - struct drm_connector_state *state = connector->base.state; - /* This also checks the encoder/connector hw state with the * ->get_hw_state callbacks. */ intel_connector_check_state(connector); - I915_STATE_WARN(state->best_encoder != encoder, + I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder, "connector's staged encoder doesn't match current encoder\n"); } } @@ -12485,6 +12522,8 @@ check_encoder_state(struct drm_device *dev) encoder->base.base.id, encoder->base.name); + I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc, + "encoder's stage crtc doesn't match current crtc\n"); I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc, "encoder's active_connectors set, but no crtc\n"); @@ -12494,9 +12533,6 @@ check_encoder_state(struct drm_device *dev) enabled = true; if (connector->base.dpms != DRM_MODE_DPMS_OFF) active = true; - - I915_STATE_WARN(connector->base.state->crtc != encoder->base.crtc, - "encoder's stage crtc doesn't match current crtc\n"); } /* * for MST connectors if we unplug the connector is gone @@ -13000,11 +13036,11 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) * need to copy the staged config to the atomic state, otherwise the * mode set will just reapply the state the HW is already in. */ for_each_intel_encoder(dev, encoder) { - if (encoder->base.crtc != crtc) + if (&encoder->new_crtc->base != crtc) continue; for_each_intel_connector(dev, connector) { - if (connector->base.state->best_encoder != &encoder->base) + if (connector->new_encoder != encoder) continue; connector_state = drm_atomic_get_connector_state(state, &connector->base); @@ -13017,10 +13053,14 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) } connector_state->crtc = crtc; + connector_state->best_encoder = &encoder->base; } } for_each_intel_crtc(dev, intel_crtc) { + if (intel_crtc->new_enabled == intel_crtc->base.enabled) + continue; + crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); if (IS_ERR(crtc_state)) { DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n", @@ -13029,6 +13069,9 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) continue; } + crtc_state->base.active = crtc_state->base.enable = + intel_crtc->new_enabled; + if (&intel_crtc->base == crtc) drm_mode_copy(&crtc_state->base.mode, &crtc->mode); } @@ -15105,7 +15148,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) * ... */ plane = crtc->plane; to_intel_plane_state(crtc->base.primary->state)->visible = true; - crtc->base.primary->crtc = &crtc->base; crtc->plane = !plane; intel_crtc_control(&crtc->base, false); crtc->plane = plane; @@ -15269,182 +15311,78 @@ static bool primary_get_hw_state(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - if (!crtc->base.enabled) + if (!crtc->active) return false; return I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE; } -static int readout_hw_crtc_state(struct drm_atomic_state *state, - struct intel_crtc *crtc) +static void intel_modeset_readout_hw_state(struct drm_device *dev) { - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct intel_crtc_state *crtc_state; - struct drm_plane *primary = crtc->base.primary; - struct drm_plane_state *drm_plane_state; - struct intel_plane_state *plane_state; - int ret; - - crtc_state = intel_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - ret = drm_atomic_add_affected_planes(state, &crtc->base); - if (ret) - return ret; - - memset(crtc_state, 0, sizeof(*crtc_state)); - crtc_state->base.crtc = &crtc->base; - crtc_state->base.state = state; - - crtc_state->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; - - crtc_state->base.enable = crtc_state->base.active = - crtc->base.enabled = dev_priv->display.get_pipe_config(crtc, crtc_state); + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + struct intel_connector *connector; + int i; - /* update transitional state */ - crtc->active = crtc_state->base.active; - crtc->config = crtc_state; + for_each_intel_crtc(dev, crtc) { + struct drm_plane *primary = crtc->base.primary; + struct intel_plane_state *plane_state; - drm_plane_state = drm_atomic_get_plane_state(state, primary); - if (IS_ERR(drm_plane_state)) - return PTR_ERR(drm_plane_state); + memset(crtc->config, 0, sizeof(*crtc->config)); + crtc->config->base.crtc = &crtc->base; - plane_state = to_intel_plane_state(drm_plane_state); - plane_state->visible = primary_get_hw_state(crtc); + crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; - if (plane_state->visible) { - primary->crtc = &crtc->base; - crtc_state->base.plane_mask |= 1 << drm_plane_index(primary); - } else - crtc_state->base.plane_mask &= ~(1 << drm_plane_index(primary)); + crtc->active = dev_priv->display.get_pipe_config(crtc, + crtc->config); - DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", - crtc->base.base.id, - crtc_state->base.active ? "enabled" : "disabled"); + crtc->base.state->enable = crtc->active; + crtc->base.state->active = crtc->active; + crtc->base.enabled = crtc->active; - return 0; -} + plane_state = to_intel_plane_state(primary->state); + plane_state->visible = primary_get_hw_state(crtc); -static int readout_hw_pll_state(struct drm_atomic_state *state) -{ - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct intel_shared_dpll_config *shared_dpll; - struct intel_crtc *crtc; - struct intel_crtc_state *crtc_state; - int i; + DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", + crtc->base.base.id, + crtc->active ? "enabled" : "disabled"); + } - shared_dpll = intel_atomic_get_shared_dpll_state(state); for (i = 0; i < dev_priv->num_shared_dpll; i++) { struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; pll->on = pll->get_hw_state(dev_priv, pll, - &shared_dpll[i].hw_state); - + &pll->config.hw_state); pll->active = 0; - shared_dpll[i].crtc_mask = 0; - - for_each_intel_crtc(state->dev, crtc) { - crtc_state = intel_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - if (crtc_state->base.active && - crtc_state->shared_dpll == i) { + pll->config.crtc_mask = 0; + for_each_intel_crtc(dev, crtc) { + if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) { pll->active++; - shared_dpll[i].crtc_mask |= - 1 << crtc->pipe; + pll->config.crtc_mask |= 1 << crtc->pipe; } } DRM_DEBUG_KMS("%s hw state readout: crtc_mask 0x%08x, on %i\n", - pll->name, shared_dpll[i].crtc_mask, - pll->on); + pll->name, pll->config.crtc_mask, pll->on); - if (shared_dpll[i].crtc_mask) + if (pll->config.crtc_mask) intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); } - return 0; -} - -static struct drm_connector_state * -get_connector_state_for_encoder(struct drm_atomic_state *state, - struct intel_encoder *encoder) -{ - struct drm_connector *connector; - struct drm_connector_state *connector_state; - int i; - - for_each_connector_in_state(state, connector, connector_state, i) - if (connector_state->best_encoder == &encoder->base) - return connector_state; - - return NULL; -} - -static int readout_hw_connector_encoder_state(struct drm_atomic_state *state) -{ - struct drm_device *dev = state->dev; - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct intel_crtc *crtc; - struct drm_crtc_state *drm_crtc_state; - struct intel_crtc_state *crtc_state; - struct intel_encoder *encoder; - struct intel_connector *connector; - struct drm_connector_state *connector_state; - enum pipe pipe; - - for_each_intel_connector(dev, connector) { - connector_state = - drm_atomic_get_connector_state(state, &connector->base); - if (IS_ERR(connector_state)) - return PTR_ERR(connector_state); - - if (connector->get_hw_state(connector)) { - connector->base.dpms = DRM_MODE_DPMS_ON; - connector->base.encoder = &connector->encoder->base; - } else { - connector->base.dpms = DRM_MODE_DPMS_OFF; - connector->base.encoder = NULL; - } - - /* We'll update the crtc field when reading encoder state */ - connector_state->crtc = NULL; - - connector_state->best_encoder = connector->base.encoder; - - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n", - connector->base.base.id, - connector->base.name, - connector->base.encoder ? "enabled" : "disabled"); - } - for_each_intel_encoder(dev, encoder) { pipe = 0; - connector_state = - get_connector_state_for_encoder(state, encoder); - - encoder->connectors_active = !!connector_state; - if (encoder->get_hw_state(encoder, &pipe)) { - encoder->base.crtc = - dev_priv->pipe_to_crtc_mapping[pipe]; - crtc = to_intel_crtc(encoder->base.crtc); - - drm_crtc_state = - state->crtc_states[drm_crtc_index(&crtc->base)]; - crtc_state = to_intel_crtc_state(drm_crtc_state); - - encoder->get_config(encoder, crtc_state); - - if (connector_state) - connector_state->crtc = &crtc->base; + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + encoder->base.crtc = &crtc->base; + encoder->get_config(encoder, crtc->config); } else { encoder->base.crtc = NULL; } + encoder->connectors_active = false; DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe %c\n", encoder->base.base.id, encoder->base.name, @@ -15452,42 +15390,20 @@ static int readout_hw_connector_encoder_state(struct drm_atomic_state *state) pipe_name(pipe)); } - return 0; -} - -static struct drm_atomic_state * -intel_modeset_readout_hw_state(struct drm_device *dev) -{ - struct intel_crtc *crtc; - int ret = 0; - - struct drm_atomic_state *state; - - state = drm_atomic_state_alloc(dev); - if (!state) - return ERR_PTR(-ENOMEM); - - state->acquire_ctx = dev->mode_config.acquire_ctx; - - for_each_intel_crtc(dev, crtc) { - ret = readout_hw_crtc_state(state, crtc); - if (ret) - goto err_free; + for_each_intel_connector(dev, connector) { + if (connector->get_hw_state(connector)) { + connector->base.dpms = DRM_MODE_DPMS_ON; + connector->encoder->connectors_active = true; + connector->base.encoder = &connector->encoder->base; + } else { + connector->base.dpms = DRM_MODE_DPMS_OFF; + connector->base.encoder = NULL; + } + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n", + connector->base.base.id, + connector->base.name, + connector->base.encoder ? "enabled" : "disabled"); } - - ret = readout_hw_pll_state(state); - if (ret) - goto err_free; - - ret = readout_hw_connector_encoder_state(state); - if (ret) - goto err_free; - - return state; - -err_free: - drm_atomic_state_free(state); - return ERR_PTR(ret); } /* Scan out the current hw modeset state, sanitizes it and maps it into the drm @@ -15496,57 +15412,37 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; + enum pipe pipe; + struct intel_crtc *crtc; struct intel_encoder *encoder; - struct drm_atomic_state *state; - struct intel_shared_dpll_config shared_dplls[I915_NUM_PLLS]; int i; - state = intel_modeset_readout_hw_state(dev); - if (IS_ERR(state)) { - DRM_ERROR("Failed to read out hw state\n"); - return; - } - - drm_atomic_helper_swap_state(dev, state); + intel_modeset_readout_hw_state(dev); - /* swap sw/hw dpll state */ - intel_atomic_duplicate_dpll_state(dev_priv, shared_dplls); - intel_shared_dpll_commit(state); - memcpy(to_intel_atomic_state(state)->shared_dpll, - shared_dplls, sizeof(*shared_dplls) * dev_priv->num_shared_dpll); + /* + * Now that we have the config, copy it to each CRTC struct + * Note that this could go away if we move to using crtc_config + * checking everywhere. + */ + for_each_intel_crtc(dev, crtc) { + if (crtc->active && i915.fastboot) { + intel_mode_from_pipe_config(&crtc->base.mode, + crtc->config); + DRM_DEBUG_KMS("[CRTC:%d] found active mode: ", + crtc->base.base.id); + drm_mode_debug_printmodeline(&crtc->base.mode); + } + } /* HW state is read out, now we need to sanitize this mess. */ for_each_intel_encoder(dev, encoder) { intel_sanitize_encoder(encoder); } - for_each_crtc_in_state(state, crtc, crtc_state, i) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - /* prevent unnneeded restores with force_restore */ - crtc_state->active_changed = - crtc_state->mode_changed = - crtc_state->planes_changed = false; - - if (crtc->enabled) { - intel_mode_from_pipe_config(&crtc->state->mode, - to_intel_crtc_state(crtc->state)); - - drm_mode_copy(&crtc->mode, &crtc->state->mode); - drm_mode_copy(&crtc->hwmode, - &crtc->state->adjusted_mode); - } - - intel_sanitize_crtc(intel_crtc); - - /* - * sanitize_crtc may have forced an update of crtc->state, - * so reload in intel_dump_pipe_config - */ - intel_dump_pipe_config(intel_crtc, - to_intel_crtc_state(crtc->state), + for_each_pipe(dev_priv, pipe) { + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + intel_sanitize_crtc(crtc); + intel_dump_pipe_config(crtc, crtc->config, "[setup_hw_state]"); } @@ -15570,17 +15466,20 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, ilk_wm_get_hw_state(dev); if (force_restore) { - int ret; - i915_redisable_vga(dev); - ret = intel_set_mode(state); - if (ret) { - DRM_ERROR("Failed to restore previous mode\n"); - drm_atomic_state_free(state); + /* + * We need to use raw interfaces for restoring state to avoid + * checking (bogus) intermediate states. + */ + for_each_pipe(dev_priv, pipe) { + struct drm_crtc *crtc = + dev_priv->pipe_to_crtc_mapping[pipe]; + + intel_crtc_restore_mode(crtc); } } else { - drm_atomic_state_free(state); + intel_modeset_update_staged_output_state(dev); } intel_modeset_check_state(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9ca683ae2dec..b28029a1c8f2 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -130,6 +130,11 @@ struct intel_fbdev { struct intel_encoder { struct drm_encoder base; + /* + * The new crtc this encoder will be driven from. Only differs from + * base->crtc while a modeset is in progress. + */ + struct intel_crtc *new_crtc; enum intel_output_type type; unsigned int cloneable; @@ -190,6 +195,12 @@ struct intel_connector { */ struct intel_encoder *encoder; + /* + * The new encoder this connector will be driven. Only differs from + * encoder while a modeset is in progress. + */ + struct intel_encoder *new_encoder; + /* Reads out the current hw, returning true if the connector is enabled * and active (i.e. dpms ON state). */ bool (*get_hw_state)(struct intel_connector *); @@ -527,6 +538,7 @@ struct intel_crtc { struct intel_initial_plane_config plane_config; struct intel_crtc_state *config; + bool new_enabled; /* reset counter value when the last flip was submitted */ unsigned int reset_counter; @@ -1407,8 +1419,6 @@ struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev); void intel_atomic_state_clear(struct drm_atomic_state *); struct intel_shared_dpll_config * intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s); -void intel_atomic_duplicate_dpll_state(struct drm_i915_private *, - struct intel_shared_dpll_config *); static inline struct intel_crtc_state * intel_atomic_get_crtc_state(struct drm_atomic_state *state, -- cgit v1.3-6-gb490 From b17d48e27d35bc890ff205c9663b58803798b63b Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 12 Jun 2015 11:15:39 +0200 Subject: drm/i915: Do not use atomic modesets in hw readout. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should fix fallout caused by making intel_crtc_control and update_dpms atomic, which became a problem after reverting the atomic hw readout patch. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90929 Reported-by: Ville Syrjälä Signed-off-by: Maarten Lankhorst Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 75 +++++++++++++++--------------------- 1 file changed, 32 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5cc2263db199..7abaffeda7ce 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6187,31 +6187,35 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } +static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum intel_display_power_domain domain; + unsigned long domains; + + if (!intel_crtc->active) + return; + + intel_crtc_disable_planes(crtc); + dev_priv->display.crtc_disable(crtc); + + domains = intel_crtc->enabled_power_domains; + for_each_power_domain(domain, domains) + intel_display_power_put(dev_priv, domain); + intel_crtc->enabled_power_domains = 0; +} + /* * turn all crtc's off, but do not adjust state * This has to be paired with a call to intel_modeset_setup_hw_state. */ void intel_display_suspend(struct drm_device *dev) { - struct drm_i915_private *dev_priv = to_i915(dev); struct drm_crtc *crtc; - for_each_crtc(dev, crtc) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum intel_display_power_domain domain; - unsigned long domains; - - if (!intel_crtc->active) - continue; - - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); - - domains = intel_crtc->enabled_power_domains; - for_each_power_domain(domain, domains) - intel_display_power_put(dev_priv, domain); - intel_crtc->enabled_power_domains = 0; - } + for_each_crtc(dev, crtc) + intel_crtc_disable_noatomic(crtc); } /* Master function to enable/disable CRTC and corresponding power wells */ @@ -15120,7 +15124,9 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *encoder; u32 reg; + bool enable; /* Clear any frame start delays used for debugging left by the BIOS */ reg = PIPECONF(crtc->config->cpu_transcoder); @@ -15137,7 +15143,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) * disable the crtc (and hence change the state) if it is wrong. Note * that gen4+ has a fixed plane -> pipe mapping. */ if (INTEL_INFO(dev)->gen < 4 && !intel_check_plane_mapping(crtc)) { - struct intel_connector *connector; bool plane; DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n", @@ -15149,29 +15154,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) plane = crtc->plane; to_intel_plane_state(crtc->base.primary->state)->visible = true; crtc->plane = !plane; - intel_crtc_control(&crtc->base, false); + intel_crtc_disable_noatomic(&crtc->base); crtc->plane = plane; - - /* ... and break all links. */ - for_each_intel_connector(dev, connector) { - if (connector->encoder->base.crtc != &crtc->base) - continue; - - connector->base.dpms = DRM_MODE_DPMS_OFF; - connector->base.encoder = NULL; - } - /* multiple connectors may have the same encoder: - * handle them and break crtc link separately */ - for_each_intel_connector(dev, connector) - if (connector->encoder->base.crtc == &crtc->base) { - connector->encoder->base.crtc = NULL; - connector->encoder->connectors_active = false; - } - - WARN_ON(crtc->active); - crtc->base.state->enable = false; - crtc->base.state->active = false; - crtc->base.enabled = false; } if (dev_priv->quirks & QUIRK_PIPEA_FORCE && @@ -15185,13 +15169,18 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) /* Adjust the state of the output pipe according to whether we * have active connectors/encoders. */ - intel_crtc_update_dpms(&crtc->base); + enable = false; + for_each_encoder_on_crtc(dev, &crtc->base, encoder) + enable |= encoder->connectors_active; + + if (!enable) + intel_crtc_disable_noatomic(&crtc->base); if (crtc->active != crtc->base.state->active) { - struct intel_encoder *encoder; /* This can happen either due to bugs in the get_hw_state - * functions or because the pipe is force-enabled due to the + * functions or because of calls to intel_crtc_disable_noatomic, + * or because the pipe is force-enabled due to the * pipe A quirk. */ DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n", crtc->base.base.id, -- cgit v1.3-6-gb490 From 02e0efb5b40b42f06668ba38f39654c57feaacdb Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 12 Jun 2015 11:15:40 +0200 Subject: drm/i915: get rid of intel_plane_restore in intel_crtc_page_flip Use a full atomic call instead. intel_crtc_page_flip will still have to live until async updates are allowed. This doesn't seem to be a regression from the convert to atomic, part 3 patch. During GPU reset it fixes the following warning: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 752 at drivers/gpu/drm/drm_crtc.c:5337 drm_mode_page_flip_ioctl+0x27b/0x360() Modules linked in: i915 CPU: 0 PID: 752 Comm: Xorg Not tainted 4.1.0-rc7-patser+ #4090 Hardware name: NUC5i7RYB, BIOS RYBDWi35.86A.0246.2015.0309.1355 03/09/2015 ffffffff81c90866 ffff8800d87c3ca8 ffffffff817f7d87 0000000080000001 0000000000000000 ffff8800d87c3ce8 ffffffff81084955 ffff880000000000 ffff8800d87c3dc0 ffff8800d93d1208 0000000000000000 ffff8800b7d1f3e0 Call Trace: [] dump_stack+0x4f/0x7b [] warn_slowpath_common+0x85/0xc0 [] warn_slowpath_null+0x15/0x20 [] drm_mode_page_flip_ioctl+0x27b/0x360 [] drm_ioctl+0x1a0/0x6a0 [] ? get_parent_ip+0x11/0x50 [] ? avc_has_perm+0x20/0x280 [] ? get_parent_ip+0x11/0x50 [] do_vfs_ioctl+0x2f8/0x530 [] ? expand_files+0x261/0x270 [] ? selinux_file_ioctl+0x56/0x100 [] SyS_ioctl+0x81/0xa0 [] system_call_fastpath+0x12/0x6f ---[ end trace 9ce834560085bd64 ]--- Signed-off-by: Maarten Lankhorst Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7abaffeda7ce..cdf6549c8e74 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11618,8 +11618,35 @@ free_work: kfree(work); if (ret == -EIO) { + struct drm_atomic_state *state; + struct drm_plane_state *plane_state; + out_hang: - ret = intel_plane_restore(primary); + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + +retry: + plane_state = drm_atomic_get_plane_state(state, primary); + ret = PTR_ERR_OR_ZERO(plane_state); + if (!ret) { + drm_atomic_set_fb_for_plane(plane_state, fb); + + ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); + if (!ret) + ret = drm_atomic_commit(state); + } + + if (ret == -EDEADLK) { + drm_modeset_backoff(state->acquire_ctx); + drm_atomic_state_clear(state); + goto retry; + } + + if (ret) + drm_atomic_state_free(state); + if (ret == 0 && event) { spin_lock_irq(&dev->event_lock); drm_send_vblank_event(dev, pipe, event); -- cgit v1.3-6-gb490 From b8b7fadec3c797d7babb3c7fec484971e1604978 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 12 Jun 2015 11:15:41 +0200 Subject: drm/i915: Set hwmode during readout. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was introduced after converting hw readout to atomic, so it should have been part of the revert too. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90929 Reported-by: Ville Syrjälä Tested-by: Ville Syrjälä Signed-off-by: Maarten Lankhorst Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cdf6549c8e74..14ccf49b9067 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15357,6 +15357,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) crtc->base.state->enable = crtc->active; crtc->base.state->active = crtc->active; crtc->base.enabled = crtc->active; + crtc->base.hwmode = crtc->config->base.adjusted_mode; plane_state = to_intel_plane_state(primary->state); plane_state->visible = primary_get_hw_state(crtc); -- cgit v1.3-6-gb490 From c0165304e10f317672e20f2b40770d74c51e287f Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 12 Jun 2015 11:15:42 +0200 Subject: drm/i915: Only enable cursor if it can be enabled. The cursor should only be enabled if it's visible. This fixes igt/kms_cursor_crc, which may otherwise produce the following warning: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 3425 at drivers/gpu/drm/i915/intel_display.c:9995 intel_crtc_update_cursor+0x14c/0x4d0 [i915]() Missing switch case (0) in i9xx_update_cursor Modules linked in: i915 CPU: 0 PID: 3425 Comm: kms_cursor_crc Tainted: G W 4.1.0-rc7-patser+ #4079 Hardware name: LENOVO 2349AV8/2349AV8, BIOS G1ETA5WW (2.65 ) 04/15/2014 ffffffffc01aad10 ffff8800b083faa8 ffffffff817f7827 0000000080000001 ffff8800b083faf8 ffff8800b083fae8 ffffffff81084955 ffff8800b083fad8 ffff8800c4931148 0000000001200000 ffff8800c48b0000 0000000000000000 Call Trace: [] dump_stack+0x4f/0x7b [] warn_slowpath_common+0x85/0xc0 [] warn_slowpath_fmt+0x41/0x50 [] intel_crtc_update_cursor+0x14c/0x4d0 [i915] [] __intel_set_mode+0x6c4/0x750 [i915] [] intel_crtc_set_config+0x473/0x5c0 [i915] [] drm_mode_set_config_internal+0x69/0x120 [] drm_mode_setcrtc+0x189/0x540 [] drm_ioctl+0x1a0/0x6a0 [] ? get_parent_ip+0x11/0x50 [] do_vfs_ioctl+0x2f8/0x530 [] ? trace_hardirqs_on+0xd/0x10 [] ? selinux_file_ioctl+0x56/0x100 [] SyS_ioctl+0x81/0xa0 [] system_call_fastpath+0x12/0x6f ---[ end trace abf0f71163290a96 ]--- Signed-off-by: Maarten Lankhorst Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 14ccf49b9067..afe91a8f7e36 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4748,7 +4748,8 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc) intel_enable_primary_hw_plane(crtc->primary, crtc); intel_enable_sprite_planes(crtc); - intel_crtc_update_cursor(crtc, true); + if (to_intel_plane_state(crtc->cursor->state)->visible) + intel_crtc_update_cursor(crtc, true); intel_post_enable_primary(crtc); -- cgit v1.3-6-gb490 From a858c7dab4b9b6a0b5742c39b10408780ca315c8 Mon Sep 17 00:00:00 2001 From: Adriana Reus Date: Fri, 12 Jun 2015 18:10:22 +0300 Subject: iio: inv-mpu: Export scale_available attributes Export the available scales for accel and gyro in order to hint the user-space as to what are the available valid values. Signed-off-by: Adriana Reus Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 17d4bb15be4d..096e545538b8 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -673,6 +673,10 @@ static const struct iio_chan_spec inv_mpu_channels[] = { /* constant IIO attribute */ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 20 50 100 200 500"); +static IIO_CONST_ATTR(in_anglvel_scale_available, + "0.000133090 0.000266181 0.000532362 0.001064724"); +static IIO_CONST_ATTR(in_accel_scale_available, + "0.000598 0.001196 0.002392 0.004785"); static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show, inv_mpu6050_fifo_rate_store); static IIO_DEVICE_ATTR(in_gyro_matrix, S_IRUGO, inv_attr_show, NULL, @@ -685,6 +689,8 @@ static struct attribute *inv_attributes[] = { &iio_dev_attr_in_accel_matrix.dev_attr.attr, &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_const_attr_in_accel_scale_available.dev_attr.attr, + &iio_const_attr_in_anglvel_scale_available.dev_attr.attr, NULL, }; -- cgit v1.3-6-gb490 From 003f4880bd2eba68c6f9191607ce73787f3402bd Mon Sep 17 00:00:00 2001 From: Tiberiu Breana Date: Wed, 10 Jun 2015 18:07:29 +0300 Subject: iio: accel: STK8BA50: replace scale table with a struct Replaced the stk8ba50_scale_table with an identically named struct in order to make the code a bit more readable. Signed-off-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8ba50.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 30950c6b36de..3302a3d1b4bf 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -50,7 +50,10 @@ * * Locally, the range is stored as a table index. */ -static const int stk8ba50_scale_table[][2] = { +static const struct { + u8 reg_val; + u32 scale_val; +} stk8ba50_scale_table[] = { {3, 38400}, {5, 76700}, {8, 153400}, {12, 306900} }; @@ -114,7 +117,7 @@ static int stk8ba50_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; - *val2 = stk8ba50_scale_table[data->range][1]; + *val2 = stk8ba50_scale_table[data->range].scale_val; return IIO_VAL_INT_PLUS_MICRO; } @@ -136,7 +139,7 @@ static int stk8ba50_write_raw(struct iio_dev *indio_dev, return -EINVAL; for (i = 0; i < ARRAY_SIZE(stk8ba50_scale_table); i++) - if (val2 == stk8ba50_scale_table[i][1]) { + if (val2 == stk8ba50_scale_table[i].scale_val) { index = i; break; } @@ -145,7 +148,7 @@ static int stk8ba50_write_raw(struct iio_dev *indio_dev, ret = i2c_smbus_write_byte_data(data->client, STK8BA50_REG_RANGE, - stk8ba50_scale_table[index][0]); + stk8ba50_scale_table[index].reg_val); if (ret < 0) dev_err(&data->client->dev, "failed to set measurement range\n"); -- cgit v1.3-6-gb490 From eb2c9ce2cc938d7d39fc06430519bf0fc5004566 Mon Sep 17 00:00:00 2001 From: Tiberiu Breana Date: Wed, 10 Jun 2015 18:07:30 +0300 Subject: iio: accel: Add sampling rate support for STK8BA50 Added support for setting the STK8BA50 accelerometer's sampling rate. Signed-off-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8ba50.c | 57 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 3302a3d1b4bf..92229bd8c82d 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -21,6 +21,7 @@ #define STK8BA50_REG_YOUT 0x04 #define STK8BA50_REG_ZOUT 0x06 #define STK8BA50_REG_RANGE 0x0F +#define STK8BA50_REG_BWSEL 0x10 #define STK8BA50_REG_POWMODE 0x11 #define STK8BA50_REG_SWRST 0x14 @@ -29,6 +30,7 @@ #define STK8BA50_MODE_POWERBIT BIT(7) #define STK8BA50_DATA_SHIFT 6 #define STK8BA50_RESET_CMD 0xB6 +#define STK8BA50_SR_1792HZ_IDX 7 #define STK8BA50_DRIVER_NAME "stk8ba50" @@ -57,19 +59,30 @@ static const struct { {3, 38400}, {5, 76700}, {8, 153400}, {12, 306900} }; +/* Sample rates are stored as { , } */ +static const struct { + u8 reg_val; + u16 samp_freq; +} stk8ba50_samp_freq_table[] = { + {0x08, 14}, {0x09, 25}, {0x0A, 56}, {0x0B, 112}, + {0x0C, 224}, {0x0D, 448}, {0x0E, 896}, {0x0F, 1792} +}; + struct stk8ba50_data { struct i2c_client *client; struct mutex lock; int range; + u8 sample_rate_idx; }; -#define STK8BA50_ACCEL_CHANNEL(reg, axis) { \ - .type = IIO_ACCEL, \ - .address = reg, \ - .modified = 1, \ - .channel2 = IIO_MOD_##axis, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +#define STK8BA50_ACCEL_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ } static const struct iio_chan_spec stk8ba50_channels[] = { @@ -80,8 +93,11 @@ static const struct iio_chan_spec stk8ba50_channels[] = { static IIO_CONST_ATTR(in_accel_scale_available, STK8BA50_SCALE_AVAIL); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("14 25 56 112 224 448 896 1792"); + static struct attribute *stk8ba50_attributes[] = { &iio_const_attr_in_accel_scale_available.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, NULL, }; @@ -119,6 +135,11 @@ static int stk8ba50_read_raw(struct iio_dev *indio_dev, *val = 0; *val2 = stk8ba50_scale_table[data->range].scale_val; return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = stk8ba50_samp_freq_table + [data->sample_rate_idx].samp_freq; + *val2 = 0; + return IIO_VAL_INT; } return -EINVAL; @@ -155,6 +176,25 @@ static int stk8ba50_write_raw(struct iio_dev *indio_dev, else data->range = index; + return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + for (i = 0; i < ARRAY_SIZE(stk8ba50_samp_freq_table); i++) + if (val == stk8ba50_samp_freq_table[i].samp_freq) { + index = i; + break; + } + if (index < 0) + return -EINVAL; + + ret = i2c_smbus_write_byte_data(data->client, + STK8BA50_REG_BWSEL, + stk8ba50_samp_freq_table[index].reg_val); + if (ret < 0) + dev_err(&data->client->dev, + "failed to set sampling rate\n"); + else + data->sample_rate_idx = index; + return ret; } @@ -231,6 +271,9 @@ static int stk8ba50_probe(struct i2c_client *client, /* The default range is +/-2g */ data->range = 0; + /* The default sampling rate is 1792 Hz (maximum) */ + data->sample_rate_idx = STK8BA50_SR_1792HZ_IDX; + ret = iio_device_register(indio_dev); if (ret < 0) { dev_err(&client->dev, "device_register failed\n"); -- cgit v1.3-6-gb490 From ae35496230bc792fa76505ab7fcee694c7f7d523 Mon Sep 17 00:00:00 2001 From: Naidu Tellapati Date: Thu, 7 May 2015 18:24:02 -0300 Subject: iio: adc: cc10001: Power-up the ADC at probe time when used remotely The ADC is typically shared with remote CPUs not running Linux. However, there is only one register to power-up/power-down. Remote CPUs aren't able to power-up the ADC, and rely in Linux doing it instead. This commit uses the adc-reserved-channels devicetree property to distinguish shared usage. In this case, the ADC is powered up at probe time. If the ADC is used only by the CPU running Linux, power-up/down at runtime, only when neeeded. Signed-off-by: Naidu Tellapati Signed-off-by: Ezequiel Garcia Signed-off-by: Jonathan Cameron --- drivers/iio/adc/cc10001_adc.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c index 115f6e99a7fa..8254f529b2a9 100644 --- a/drivers/iio/adc/cc10001_adc.c +++ b/drivers/iio/adc/cc10001_adc.c @@ -62,6 +62,7 @@ struct cc10001_adc_device { struct regulator *reg; u16 *buf; + bool shared; struct mutex lock; unsigned int start_delay_ns; unsigned int eoc_delay_ns; @@ -153,7 +154,8 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p) mutex_lock(&adc_dev->lock); - cc10001_adc_power_up(adc_dev); + if (!adc_dev->shared) + cc10001_adc_power_up(adc_dev); /* Calculate delay step for eoc and sampled data */ delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT; @@ -177,7 +179,8 @@ static irqreturn_t cc10001_adc_trigger_h(int irq, void *p) } done: - cc10001_adc_power_down(adc_dev); + if (!adc_dev->shared) + cc10001_adc_power_down(adc_dev); mutex_unlock(&adc_dev->lock); @@ -196,7 +199,8 @@ static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev, unsigned int delay_ns; u16 val; - cc10001_adc_power_up(adc_dev); + if (!adc_dev->shared) + cc10001_adc_power_up(adc_dev); /* Calculate delay step for eoc and sampled data */ delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT; @@ -205,7 +209,8 @@ static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev, val = cc10001_adc_poll_done(indio_dev, chan->channel, delay_ns); - cc10001_adc_power_down(adc_dev); + if (!adc_dev->shared) + cc10001_adc_power_down(adc_dev); return val; } @@ -322,8 +327,10 @@ static int cc10001_adc_probe(struct platform_device *pdev) adc_dev = iio_priv(indio_dev); channel_map = GENMASK(CC10001_ADC_NUM_CHANNELS - 1, 0); - if (!of_property_read_u32(node, "adc-reserved-channels", &ret)) + if (!of_property_read_u32(node, "adc-reserved-channels", &ret)) { + adc_dev->shared = true; channel_map &= ~ret; + } adc_dev->reg = devm_regulator_get(&pdev->dev, "vref"); if (IS_ERR(adc_dev->reg)) @@ -368,6 +375,14 @@ static int cc10001_adc_probe(struct platform_device *pdev) adc_dev->eoc_delay_ns = NSEC_PER_SEC / adc_clk_rate; adc_dev->start_delay_ns = adc_dev->eoc_delay_ns * CC10001_WAIT_CYCLES; + /* + * There is only one register to power-up/power-down the AUX ADC. + * If the ADC is shared among multiple CPUs, always power it up here. + * If the ADC is used only by the MIPS, power-up/power-down at runtime. + */ + if (adc_dev->shared) + cc10001_adc_power_up(adc_dev); + /* Setup the ADC channels available on the device */ ret = cc10001_adc_channel_init(indio_dev, channel_map); if (ret < 0) @@ -402,6 +417,7 @@ static int cc10001_adc_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct cc10001_adc_device *adc_dev = iio_priv(indio_dev); + cc10001_adc_power_down(adc_dev); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); clk_disable_unprepare(adc_dev->adc_clk); -- cgit v1.3-6-gb490 From 1ca0259b18478b2bab6d5c81ca1de52dd519ae5e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 8 May 2015 15:54:00 -0300 Subject: iio: light: hid-sensor-prox: Fit assignment in one line There is no need to do the assignment to indio_dev->num_channels in two lines code. Put it in one line. Signed-off-by: Fabio Estevam Signed-off-by: Jonathan Cameron --- drivers/iio/light/hid-sensor-prox.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index 0d248476f4c9..45ca056f019e 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -284,8 +284,7 @@ static int hid_prox_probe(struct platform_device *pdev) goto error_free_dev_mem; } - indio_dev->num_channels = - ARRAY_SIZE(prox_channels); + indio_dev->num_channels = ARRAY_SIZE(prox_channels); indio_dev->dev.parent = &pdev->dev; indio_dev->info = &prox_info; indio_dev->name = name; -- cgit v1.3-6-gb490 From c0d901cce736cb628d2e15f07ae00ea1029f64df Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Mon, 13 Apr 2015 18:41:01 +0300 Subject: iio: accel: mma9551_core: use size in words for word buffers Change the prototype for the mma9551_read/write_*_words functions to receive the length of the buffer in words (instead of bytes) since we are using a word buffer. This will prevent users from sending an odd number of bytes for a word array. Signed-off-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma9551_core.c | 27 ++++++++++++--------------- drivers/iio/accel/mma9553.c | 9 ++++++--- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c index 2fd2a995686b..583660b74f42 100644 --- a/drivers/iio/accel/mma9551_core.c +++ b/drivers/iio/accel/mma9551_core.c @@ -373,7 +373,7 @@ EXPORT_SYMBOL(mma9551_read_status_word); * @client: I2C client * @app_id: Application ID * @reg: Application register - * @len: Length of array to read in bytes + * @len: Length of array to read (in words) * @buf: Array of words to read * * Read multiple configuration registers (word-sized registers). @@ -388,20 +388,19 @@ int mma9551_read_config_words(struct i2c_client *client, u8 app_id, u16 reg, u8 len, u16 *buf) { int ret, i; - int len_words = len / sizeof(u16); __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2]; - if (len_words > ARRAY_SIZE(be_buf)) { + if (len > ARRAY_SIZE(be_buf)) { dev_err(&client->dev, "Invalid buffer size %d\n", len); return -EINVAL; } ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, - reg, NULL, 0, (u8 *) be_buf, len); + reg, NULL, 0, (u8 *)be_buf, len * sizeof(u16)); if (ret < 0) return ret; - for (i = 0; i < len_words; i++) + for (i = 0; i < len; i++) buf[i] = be16_to_cpu(be_buf[i]); return 0; @@ -413,7 +412,7 @@ EXPORT_SYMBOL(mma9551_read_config_words); * @client: I2C client * @app_id: Application ID * @reg: Application register - * @len: Length of array to read in bytes + * @len: Length of array to read (in words) * @buf: Array of words to read * * Read multiple status registers (word-sized registers). @@ -428,20 +427,19 @@ int mma9551_read_status_words(struct i2c_client *client, u8 app_id, u16 reg, u8 len, u16 *buf) { int ret, i; - int len_words = len / sizeof(u16); __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2]; - if (len_words > ARRAY_SIZE(be_buf)) { + if (len > ARRAY_SIZE(be_buf)) { dev_err(&client->dev, "Invalid buffer size %d\n", len); return -EINVAL; } ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, - reg, NULL, 0, (u8 *) be_buf, len); + reg, NULL, 0, (u8 *)be_buf, len * sizeof(u16)); if (ret < 0) return ret; - for (i = 0; i < len_words; i++) + for (i = 0; i < len; i++) buf[i] = be16_to_cpu(be_buf[i]); return 0; @@ -453,7 +451,7 @@ EXPORT_SYMBOL(mma9551_read_status_words); * @client: I2C client * @app_id: Application ID * @reg: Application register - * @len: Length of array to write in bytes + * @len: Length of array to write (in words) * @buf: Array of words to write * * Write multiple configuration registers (word-sized registers). @@ -468,19 +466,18 @@ int mma9551_write_config_words(struct i2c_client *client, u8 app_id, u16 reg, u8 len, u16 *buf) { int i; - int len_words = len / sizeof(u16); __be16 be_buf[(MMA9551_MAX_MAILBOX_DATA_REGS - 1) / 2]; - if (len_words > ARRAY_SIZE(be_buf)) { + if (len > ARRAY_SIZE(be_buf)) { dev_err(&client->dev, "Invalid buffer size %d\n", len); return -EINVAL; } - for (i = 0; i < len_words; i++) + for (i = 0; i < len; i++) be_buf[i] = cpu_to_be16(buf[i]); return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, - reg, (u8 *) be_buf, len, NULL, 0); + reg, (u8 *)be_buf, len * sizeof(u16), NULL, 0); } EXPORT_SYMBOL(mma9551_write_config_words); diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 8bfc61824fb2..06c870789383 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -322,7 +322,8 @@ static int mma9553_read_activity_stepcnt(struct mma9553_data *data, int ret; ret = mma9551_read_status_words(data->client, MMA9551_APPID_PEDOMETER, - MMA9553_REG_STATUS, sizeof(u32), buf); + MMA9553_REG_STATUS, ARRAY_SIZE(buf), + buf); if (ret < 0) { dev_err(&data->client->dev, "error reading status and stepcnt\n"); @@ -397,7 +398,8 @@ static int mma9553_init(struct mma9553_data *data) ret = mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER, MMA9553_REG_CONF_SLEEPMIN, - sizeof(data->conf), (u16 *) &data->conf); + sizeof(data->conf) / sizeof(u16), + (u16 *)&data->conf); if (ret < 0) { dev_err(&data->client->dev, "failed to read configuration registers\n"); @@ -430,7 +432,8 @@ static int mma9553_init(struct mma9553_data *data) ret = mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER, MMA9553_REG_CONF_SLEEPMIN, - sizeof(data->conf), (u16 *) &data->conf); + sizeof(data->conf) / sizeof(u16), + (u16 *)&data->conf); if (ret < 0) { dev_err(&data->client->dev, "failed to write configuration registers\n"); -- cgit v1.3-6-gb490 From b37c19903a64951f12ae213ce0be7ca3bd26cc12 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Mon, 13 Apr 2015 18:41:02 +0300 Subject: iio: accel: mma9553: fix alignment issues Fix code alignment and wrap parameters. Fix issues reported by checkpatch.pl --strict. Signed-off-by: Irina Tirdea Suggested-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma9551_core.c | 8 ++--- drivers/iio/accel/mma9551_core.h | 6 ++-- drivers/iio/accel/mma9553.c | 76 +++++++++++++++++++--------------------- 3 files changed, 43 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c index 583660b74f42..c34c5ce8123b 100644 --- a/drivers/iio/accel/mma9551_core.c +++ b/drivers/iio/accel/mma9551_core.c @@ -297,7 +297,7 @@ EXPORT_SYMBOL(mma9551_read_status_byte); * Returns: 0 on success, negative value on failure. */ int mma9551_read_config_word(struct i2c_client *client, u8 app_id, - u16 reg, u16 *val) + u16 reg, u16 *val) { int ret; __be16 v; @@ -328,12 +328,12 @@ EXPORT_SYMBOL(mma9551_read_config_word); * Returns: 0 on success, negative value on failure. */ int mma9551_write_config_word(struct i2c_client *client, u8 app_id, - u16 reg, u16 val) + u16 reg, u16 val) { __be16 v = cpu_to_be16(val); return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, - (u8 *) &v, 2, NULL, 0); + (u8 *)&v, 2, NULL, 0); } EXPORT_SYMBOL(mma9551_write_config_word); @@ -385,7 +385,7 @@ EXPORT_SYMBOL(mma9551_read_status_word); * Returns: 0 on success, negative value on failure. */ int mma9551_read_config_words(struct i2c_client *client, u8 app_id, - u16 reg, u8 len, u16 *buf) + u16 reg, u8 len, u16 *buf) { int ret, i; __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS / 2]; diff --git a/drivers/iio/accel/mma9551_core.h b/drivers/iio/accel/mma9551_core.h index 79939e40805a..5e88e6454dfd 100644 --- a/drivers/iio/accel/mma9551_core.h +++ b/drivers/iio/accel/mma9551_core.h @@ -53,13 +53,13 @@ int mma9551_write_config_byte(struct i2c_client *client, u8 app_id, int mma9551_read_status_byte(struct i2c_client *client, u8 app_id, u16 reg, u8 *val); int mma9551_read_config_word(struct i2c_client *client, u8 app_id, - u16 reg, u16 *val); + u16 reg, u16 *val); int mma9551_write_config_word(struct i2c_client *client, u8 app_id, - u16 reg, u16 val); + u16 reg, u16 val); int mma9551_read_status_word(struct i2c_client *client, u8 app_id, u16 reg, u16 *val); int mma9551_read_config_words(struct i2c_client *client, u8 app_id, - u16 reg, u8 len, u16 *buf); + u16 reg, u8 len, u16 *buf); int mma9551_read_status_words(struct i2c_client *client, u8 app_id, u16 reg, u8 len, u16 *buf); int mma9551_write_config_words(struct i2c_client *client, u8 app_id, diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 06c870789383..08f28c3eb6cc 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -343,10 +343,10 @@ static int mma9553_conf_gpio(struct mma9553_data *data) struct mma9553_event *ev_step_detect; bool activity_enabled; - activity_enabled = - mma9553_is_any_event_enabled(data, true, IIO_ACTIVITY); - ev_step_detect = - mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE); + activity_enabled = mma9553_is_any_event_enabled(data, true, + IIO_ACTIVITY); + ev_step_detect = mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, + IIO_EV_DIR_NONE); /* * If both step detector and activity are enabled, use the MRGFL bit. @@ -372,9 +372,8 @@ static int mma9553_conf_gpio(struct mma9553_data *data) return ret; } - ret = mma9551_gpio_config(data->client, - MMA9553_DEFAULT_GPIO_PIN, - appid, bitnum, MMA9553_DEFAULT_GPIO_POLARITY); + ret = mma9551_gpio_config(data->client, MMA9553_DEFAULT_GPIO_PIN, appid, + bitnum, MMA9553_DEFAULT_GPIO_POLARITY); if (ret < 0) return ret; data->gpio_bitnum = bitnum; @@ -395,18 +394,16 @@ static int mma9553_init(struct mma9553_data *data) * a device identification command to differentiate the MMA9553L * from the MMA9550L. */ - ret = - mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER, - MMA9553_REG_CONF_SLEEPMIN, - sizeof(data->conf) / sizeof(u16), - (u16 *)&data->conf); + ret = mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER, + MMA9553_REG_CONF_SLEEPMIN, + sizeof(data->conf) / sizeof(u16), + (u16 *)&data->conf); if (ret < 0) { dev_err(&data->client->dev, "failed to read configuration registers\n"); return ret; } - /* Reset GPIO */ data->gpio_bitnum = MMA9553_MAX_BITNUM; ret = mma9553_conf_gpio(data); @@ -421,19 +418,18 @@ static int mma9553_init(struct mma9553_data *data) data->conf.sleepmin = MMA9553_DEFAULT_SLEEPMIN; data->conf.sleepmax = MMA9553_DEFAULT_SLEEPMAX; data->conf.sleepthd = MMA9553_DEFAULT_SLEEPTHD; - data->conf.config = - mma9553_set_bits(data->conf.config, 1, MMA9553_MASK_CONF_CONFIG); + data->conf.config = mma9553_set_bits(data->conf.config, 1, + MMA9553_MASK_CONF_CONFIG); /* * Clear the activity debounce counter when the activity level changes, * so that the confidence level applies for any activity level. */ data->conf.config = mma9553_set_bits(data->conf.config, 1, MMA9553_MASK_CONF_ACT_DBCNTM); - ret = - mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER, - MMA9553_REG_CONF_SLEEPMIN, - sizeof(data->conf) / sizeof(u16), - (u16 *)&data->conf); + ret = mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER, + MMA9553_REG_CONF_SLEEPMIN, + sizeof(data->conf) / sizeof(u16), + (u16 *)&data->conf); if (ret < 0) { dev_err(&data->client->dev, "failed to write configuration registers\n"); @@ -570,7 +566,7 @@ static int mma9553_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBHEIGHT: tmp = mma9553_get_bits(data->conf.height_weight, - MMA9553_MASK_CONF_HEIGHT); + MMA9553_MASK_CONF_HEIGHT); *val = tmp / 100; /* cm to m */ *val2 = (tmp % 100) * 10000; return IIO_VAL_INT_PLUS_MICRO; @@ -722,7 +718,6 @@ static int mma9553_read_event_config(struct iio_dev *indio_dev, enum iio_event_type type, enum iio_event_direction dir) { - struct mma9553_data *data = iio_priv(indio_dev); struct mma9553_event *event; @@ -1029,22 +1024,22 @@ static irqreturn_t mma9553_event_handler(int irq, void *private) return IRQ_HANDLED; } - ev_prev_activity = - mma9553_get_event(data, IIO_ACTIVITY, - mma9553_activity_to_mod(data->activity), - IIO_EV_DIR_FALLING); - ev_activity = - mma9553_get_event(data, IIO_ACTIVITY, - mma9553_activity_to_mod(activity), - IIO_EV_DIR_RISING); - ev_step_detect = - mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE); + ev_prev_activity = mma9553_get_event(data, IIO_ACTIVITY, + mma9553_activity_to_mod( + data->activity), + IIO_EV_DIR_FALLING); + ev_activity = mma9553_get_event(data, IIO_ACTIVITY, + mma9553_activity_to_mod(activity), + IIO_EV_DIR_RISING); + ev_step_detect = mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, + IIO_EV_DIR_NONE); if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) { data->stepcnt = stepcnt; iio_push_event(indio_dev, IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD, - IIO_EV_DIR_NONE, IIO_EV_TYPE_CHANGE, 0, 0, 0), + IIO_EV_DIR_NONE, + IIO_EV_TYPE_CHANGE, 0, 0, 0), data->timestamp); } @@ -1054,17 +1049,19 @@ static irqreturn_t mma9553_event_handler(int irq, void *private) if (ev_prev_activity && ev_prev_activity->enabled) iio_push_event(indio_dev, IIO_EVENT_CODE(IIO_ACTIVITY, 0, - ev_prev_activity->info->mod, - IIO_EV_DIR_FALLING, - IIO_EV_TYPE_THRESH, 0, 0, 0), + ev_prev_activity->info->mod, + IIO_EV_DIR_FALLING, + IIO_EV_TYPE_THRESH, 0, 0, + 0), data->timestamp); if (ev_activity && ev_activity->enabled) iio_push_event(indio_dev, IIO_EVENT_CODE(IIO_ACTIVITY, 0, - ev_activity->info->mod, - IIO_EV_DIR_RISING, - IIO_EV_TYPE_THRESH, 0, 0, 0), + ev_activity->info->mod, + IIO_EV_DIR_RISING, + IIO_EV_TYPE_THRESH, 0, 0, + 0), data->timestamp); } mutex_unlock(&data->mutex); @@ -1159,7 +1156,6 @@ static int mma9553_probe(struct i2c_client *client, client->irq); goto out_poweroff; } - } ret = iio_device_register(indio_dev); -- cgit v1.3-6-gb490 From 23f93cde93efed59ca82d2687a2fab6a93eaafcc Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Mon, 13 Apr 2015 18:41:03 +0300 Subject: iio: accel: mma9553: document use of mutex Fix checkpatch.pl --strict check: CHECK: struct mutex definition without comment + struct mutex mutex; Signed-off-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma9553.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 08f28c3eb6cc..a605280637e9 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -182,6 +182,10 @@ struct mma9553_conf_regs { struct mma9553_data { struct i2c_client *client; + /* + * 1. Serialize access to HW (requested by mma9551_core API). + * 2. Serialize sequences that power on/off the device and access HW. + */ struct mutex mutex; struct mma9553_conf_regs conf; struct mma9553_event events[MMA9553_EVENTS_INFO_SIZE]; -- cgit v1.3-6-gb490 From d1b1589c4800678a8a2beba83845366b2dff5d70 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 5 May 2015 17:06:19 +0300 Subject: drm/i915: Implement WaEnableHDMI8bpcBefore12bpc:snb, ivb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPT/PPT require a specific procedure for enabling 12bpc HDMI. Implement it, and to keep things neat pull the code into a function. v2: Rebased due to crtc->config changes s/HDMI_GC/HDMIUNIT_GC/ to match spec better Factor out intel_enable_hdmi_audio() Signed-off-by: Ville Syrjälä Reviewed-by: Ander Conselvan de Oliveira Reviewed-By: Chandra Konduru Testecase: igt/kms_render/* Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_hdmi.c | 74 +++++++++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 760dbebc1aef..1db6b4bf68fd 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6200,6 +6200,7 @@ enum skl_disp_power_wells { #define _TRANSA_CHICKEN1 0xf0060 #define _TRANSB_CHICKEN1 0xf1060 #define TRANS_CHICKEN1(pipe) _PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1) +#define TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE (1<<10) #define TRANS_CHICKEN1_DP0UNIT_GC_DISABLE (1<<4) #define _TRANSA_CHICKEN2 0xf0064 #define _TRANSB_CHICKEN2 0xf1064 diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index e97731aab6dc..9ee6176a5f27 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -814,6 +814,16 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, pipe_config->base.adjusted_mode.crtc_clock = dotclock; } +static void intel_enable_hdmi_audio(struct intel_encoder *encoder) +{ + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + + WARN_ON(!crtc->config->has_hdmi_sink); + DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", + pipe_name(crtc->pipe)); + intel_audio_codec_enable(encoder); +} + static void intel_enable_hdmi(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; @@ -854,12 +864,61 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) POSTING_READ(intel_hdmi->hdmi_reg); } - if (intel_crtc->config->has_audio) { - WARN_ON(!intel_crtc->config->has_hdmi_sink); - DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", - pipe_name(intel_crtc->pipe)); - intel_audio_codec_enable(encoder); + if (intel_crtc->config->has_audio) + intel_enable_hdmi_audio(encoder); +} + +static void cpt_enable_hdmi(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + enum pipe pipe = crtc->pipe; + u32 temp; + + temp = I915_READ(intel_hdmi->hdmi_reg); + + temp |= SDVO_ENABLE; + if (crtc->config->has_audio) + temp |= SDVO_AUDIO_ENABLE; + + /* + * WaEnableHDMI8bpcBefore12bpc:snb,ivb + * + * The procedure for 12bpc is as follows: + * 1. disable HDMI clock gating + * 2. enable HDMI with 8bpc + * 3. enable HDMI with 12bpc + * 4. enable HDMI clock gating + */ + + if (crtc->config->pipe_bpp > 24) { + I915_WRITE(TRANS_CHICKEN1(pipe), + I915_READ(TRANS_CHICKEN1(pipe)) | + TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE); + + temp &= ~SDVO_COLOR_FORMAT_MASK; + temp |= SDVO_COLOR_FORMAT_8bpc; } + + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); + + if (crtc->config->pipe_bpp > 24) { + temp &= ~SDVO_COLOR_FORMAT_MASK; + temp |= HDMI_COLOR_FORMAT_12bpc; + + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); + + I915_WRITE(TRANS_CHICKEN1(pipe), + I915_READ(TRANS_CHICKEN1(pipe)) & + ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE); + } + + if (crtc->config->has_audio) + intel_enable_hdmi_audio(encoder); } static void vlv_enable_hdmi(struct intel_encoder *encoder) @@ -1827,7 +1886,10 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->post_disable = vlv_hdmi_post_disable; } else { intel_encoder->pre_enable = intel_hdmi_pre_enable; - intel_encoder->enable = intel_enable_hdmi; + if (HAS_PCH_CPT(dev)) + intel_encoder->enable = cpt_enable_hdmi; + else + intel_encoder->enable = intel_enable_hdmi; } intel_encoder->type = INTEL_OUTPUT_HDMI; -- cgit v1.3-6-gb490 From 6d67415f40b1f166212f37ecc9c23b9f380dfebc Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 5 May 2015 17:06:20 +0300 Subject: drm/i915: Send GCP infoframes for deep color HDMI sinks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCP infoframes are required to inform the HDMI sink about the color depth. Send the GCP infoframe whenever the sink supports any deep color modes since such sinks must anyway be capable of receiving them. For sinks that don't support deep color let's skip the GCP in case it might confuse the sink, although HDMI 1.4 spec does say all sinks must be capable of reciving them. In theory we could skip the GCP infoframe for deep color sinks in 8bpc mode as well since sinks must fall back to 8bpc whenever GCP isn't received for some time. BSpec says we should disable GCP after disabling the port, so do that as well. v2: s/intel_set_gcp_infoframe/intel_hdmi_set_gcp_infoframe/ Rebased due to crtc->config changes Signed-off-by: Ville Syrjälä [danvet: Resolve conflict with lack of chv phy patches and fixup typo Chandra spotted.] Reviewed-by: Chandra Konduru Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 ++ drivers/gpu/drm/i915/intel_hdmi.c | 74 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1db6b4bf68fd..c9f9d3d3adba 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6061,6 +6061,9 @@ enum skl_disp_power_wells { #define _VIDEO_DIP_CTL_A 0xe0200 #define _VIDEO_DIP_DATA_A 0xe0208 #define _VIDEO_DIP_GCP_A 0xe0210 +#define GCP_COLOR_INDICATION (1 << 2) +#define GCP_DEFAULT_PHASE_ENABLE (1 << 1) +#define GCP_AV_MUTE (1 << 0) #define _VIDEO_DIP_CTL_B 0xe1200 #define _VIDEO_DIP_DATA_B 0xe1208 diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 9ee6176a5f27..a422d83b6efb 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -541,6 +541,66 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); } +static bool hdmi_sink_is_deep_color(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct drm_connector *connector; + + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); + + /* + * HDMI cloning is only supported on g4x which doesn't + * support deep color or GCP infoframes anyway so no + * need to worry about multiple HDMI sinks here. + */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + if (connector->encoder == encoder) + return connector->display_info.bpc > 8; + + return false; +} + +static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->dev->dev_private; + struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); + u32 reg, val = 0; + + if (HAS_DDI(dev_priv)) + reg = HSW_TVIDEO_DIP_GCP(crtc->config->cpu_transcoder); + else if (IS_VALLEYVIEW(dev_priv)) + reg = VLV_TVIDEO_DIP_GCP(crtc->pipe); + else if (HAS_PCH_SPLIT(dev_priv->dev)) + reg = TVIDEO_DIP_GCP(crtc->pipe); + else + return false; + + /* Indicate color depth whenever the sink supports deep color */ + if (hdmi_sink_is_deep_color(encoder)) + val |= GCP_COLOR_INDICATION; + + I915_WRITE(reg, val); + + return val != 0; +} + +static void intel_disable_gcp_infoframe(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + u32 reg; + + if (HAS_DDI(dev_priv)) + reg = HSW_TVIDEO_DIP_CTL(crtc->config->cpu_transcoder); + else if (IS_VALLEYVIEW(dev_priv)) + reg = VLV_TVIDEO_DIP_CTL(crtc->pipe); + else if (HAS_PCH_SPLIT(dev_priv->dev)) + reg = TVIDEO_DIP_CTL(crtc->pipe); + else + return; + + I915_WRITE(reg, I915_READ(reg) & ~VIDEO_DIP_ENABLE_GCP); +} + static void ibx_set_infoframes(struct drm_encoder *encoder, bool enable, struct drm_display_mode *adjusted_mode) @@ -581,6 +641,9 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP); + if (intel_hdmi_set_gcp_infoframe(encoder)) + val |= VIDEO_DIP_ENABLE_GCP; + I915_WRITE(reg, val); POSTING_READ(reg); @@ -618,6 +681,9 @@ static void cpt_set_infoframes(struct drm_encoder *encoder, val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP); + if (intel_hdmi_set_gcp_infoframe(encoder)) + val |= VIDEO_DIP_ENABLE_GCP; + I915_WRITE(reg, val); POSTING_READ(reg); @@ -666,6 +732,9 @@ static void vlv_set_infoframes(struct drm_encoder *encoder, val &= ~(VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP); + if (intel_hdmi_set_gcp_infoframe(encoder)) + val |= VIDEO_DIP_ENABLE_GCP; + I915_WRITE(reg, val); POSTING_READ(reg); @@ -695,6 +764,9 @@ static void hsw_set_infoframes(struct drm_encoder *encoder, val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW); + if (intel_hdmi_set_gcp_infoframe(encoder)) + val |= VIDEO_DIP_ENABLE_GCP_HSW; + I915_WRITE(reg, val); POSTING_READ(reg); @@ -960,6 +1032,8 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) I915_WRITE(intel_hdmi->hdmi_reg, temp); POSTING_READ(intel_hdmi->hdmi_reg); } + + intel_disable_gcp_infoframe(to_intel_crtc(encoder->base.crtc)); } static void g4x_disable_hdmi(struct intel_encoder *encoder) -- cgit v1.3-6-gb490 From 12aa32905df59a32a6fb770830799058bf591eed Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 5 May 2015 17:06:21 +0300 Subject: drm/i915: Enable default_phase in GCP when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the video timings are suitably aligned so that all different periods start at phase 0 (ie. none of the periods start mid-pixel) we can inform the sink about this. Supposedly the sink can then optimize certain things. Obviously this is only relevant when outputting >8bpc data since otherwise there are no mid-pixel phases. v2: Rebased due to crtc->config changes Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index a422d83b6efb..b1e1c3d8b8cd 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -560,6 +560,49 @@ static bool hdmi_sink_is_deep_color(struct drm_encoder *encoder) return false; } +/* + * Determine if default_phase=1 can be indicated in the GCP infoframe. + * + * From HDMI specification 1.4a: + * - The first pixel of each Video Data Period shall always have a pixel packing phase of 0 + * - The first pixel following each Video Data Period shall have a pixel packing phase of 0 + * - The PP bits shall be constant for all GCPs and will be equal to the last packing phase + * - The first pixel following every transition of HSYNC or VSYNC shall have a pixel packing + * phase of 0 + */ +static bool gcp_default_phase_possible(int pipe_bpp, + const struct drm_display_mode *mode) +{ + unsigned int pixels_per_group; + + switch (pipe_bpp) { + case 30: + /* 4 pixels in 5 clocks */ + pixels_per_group = 4; + break; + case 36: + /* 2 pixels in 3 clocks */ + pixels_per_group = 2; + break; + case 48: + /* 1 pixel in 2 clocks */ + pixels_per_group = 1; + break; + default: + /* phase information not relevant for 8bpc */ + return false; + } + + return mode->crtc_hdisplay % pixels_per_group == 0 && + mode->crtc_htotal % pixels_per_group == 0 && + mode->crtc_hblank_start % pixels_per_group == 0 && + mode->crtc_hblank_end % pixels_per_group == 0 && + mode->crtc_hsync_start % pixels_per_group == 0 && + mode->crtc_hsync_end % pixels_per_group == 0 && + ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0 || + mode->crtc_htotal/2 % pixels_per_group == 0); +} + static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; @@ -579,6 +622,11 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder) if (hdmi_sink_is_deep_color(encoder)) val |= GCP_COLOR_INDICATION; + /* Enable default_phase whenever the display mode is suitably aligned */ + if (gcp_default_phase_possible(crtc->config->pipe_bpp, + &crtc->config->base.adjusted_mode)) + val |= GCP_DEFAULT_PHASE_ENABLE; + I915_WRITE(reg, val); return val != 0; -- cgit v1.3-6-gb490 From c5de7c6f3b3185ebbb9cf81abb94580c7f2ebd5f Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 5 May 2015 17:06:22 +0300 Subject: drm/i915: Fix HDMI 12bpc TRANSCONF bpc value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IBX BSpec says we must specify 8bpc in TRANSCONF for both 8bpc and 12bpc HDMI output. Do so. v2: Pass intel_crtc to intel_pipe_has_type() Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 58846b58b676..c4ccc376ae44 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2003,11 +2003,15 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, if (HAS_PCH_IBX(dev_priv->dev)) { /* - * make the BPC in transcoder be consistent with - * that in pipeconf reg. + * Make the BPC in transcoder be consistent with + * that in pipeconf reg. For HDMI we must use 8bpc + * here for both 8bpc and 12bpc. */ val &= ~PIPECONF_BPC_MASK; - val |= pipeconf_val & PIPECONF_BPC_MASK; + if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_HDMI)) + val |= PIPECONF_8BPC; + else + val |= pipeconf_val & PIPECONF_BPC_MASK; } val &= ~TRANS_INTERLACE_MASK; -- cgit v1.3-6-gb490 From bf868c7ddaa7fd5645fbc01cf2c4ad6ddd64c142 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 5 May 2015 17:06:23 +0300 Subject: drm/i915: Fix 12bpc HDMI enable for IBX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the procedure listed in Bspec to toggle the port enable bit off and on when enabling HDMI with 12bpc and pixel repeat on IBX. The old code didn't actually enable the port before "toggling" the bit back off, so the whole workaround was essentially a nop. Also take the opportunity to clarify the code by splitting the gmch platforms to a separate (much more straightforward) function. v2: Rebased due to crtc->config changes Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 78 ++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index b1e1c3d8b8cd..14a916437b24 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -944,47 +944,73 @@ static void intel_enable_hdmi_audio(struct intel_encoder *encoder) intel_audio_codec_enable(encoder); } -static void intel_enable_hdmi(struct intel_encoder *encoder) +static void g4x_enable_hdmi(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); u32 temp; - u32 enable_bits = SDVO_ENABLE; - - if (intel_crtc->config->has_audio) - enable_bits |= SDVO_AUDIO_ENABLE; temp = I915_READ(intel_hdmi->hdmi_reg); - /* HW workaround for IBX, we need to move the port to transcoder A - * before disabling it, so restore the transcoder select bit here. */ - if (HAS_PCH_IBX(dev)) - enable_bits |= SDVO_PIPE_SEL(intel_crtc->pipe); + temp |= SDVO_ENABLE; + if (crtc->config->has_audio) + temp |= SDVO_AUDIO_ENABLE; - /* HW workaround, need to toggle enable bit off and on for 12bpc, but - * we do this anyway which shows more stable in testing. - */ - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); - POSTING_READ(intel_hdmi->hdmi_reg); - } + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); + + if (crtc->config->has_audio) + intel_enable_hdmi_audio(encoder); +} + +static void ibx_enable_hdmi(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + u32 temp; + + temp = I915_READ(intel_hdmi->hdmi_reg); - temp |= enable_bits; + temp |= SDVO_ENABLE; + if (crtc->config->has_audio) + temp |= SDVO_AUDIO_ENABLE; + /* + * HW workaround, need to write this twice for issue + * that may result in first write getting masked. + */ + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); I915_WRITE(intel_hdmi->hdmi_reg, temp); POSTING_READ(intel_hdmi->hdmi_reg); - /* HW workaround, need to write this twice for issue that may result - * in first write getting masked. + /* + * HW workaround, need to toggle enable bit off and on + * for 12bpc with pixel repeat. + * + * FIXME: BSpec says this should be done at the end of + * of the modeset sequence, so not sure if this isn't too soon. */ - if (HAS_PCH_SPLIT(dev)) { + if (crtc->config->pipe_bpp > 24 && + crtc->config->pixel_multiplier > 1) { + I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); + POSTING_READ(intel_hdmi->hdmi_reg); + + /* + * HW workaround, need to write this twice for issue + * that may result in first write getting masked. + */ + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); I915_WRITE(intel_hdmi->hdmi_reg, temp); POSTING_READ(intel_hdmi->hdmi_reg); } - if (intel_crtc->config->has_audio) + if (crtc->config->has_audio) intel_enable_hdmi_audio(encoder); } @@ -1504,7 +1530,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) intel_crtc->config->has_hdmi_sink, adjusted_mode); - intel_enable_hdmi(encoder); + g4x_enable_hdmi(encoder); vlv_wait_port_ready(dev_priv, dport, 0x0); } @@ -1821,7 +1847,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder) intel_crtc->config->has_hdmi_sink, adjusted_mode); - intel_enable_hdmi(encoder); + g4x_enable_hdmi(encoder); vlv_wait_port_ready(dev_priv, dport, 0x0); } @@ -2010,8 +2036,10 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->pre_enable = intel_hdmi_pre_enable; if (HAS_PCH_CPT(dev)) intel_encoder->enable = cpt_enable_hdmi; + else if (HAS_PCH_IBX(dev)) + intel_encoder->enable = ibx_enable_hdmi; else - intel_encoder->enable = intel_enable_hdmi; + intel_encoder->enable = g4x_enable_hdmi; } intel_encoder->type = INTEL_OUTPUT_HDMI; -- cgit v1.3-6-gb490 From 0be6f0c835077bb4dc7346e8eb75329d131a445b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 5 May 2015 17:06:24 +0300 Subject: drm/i915: Disable all infoframes when turning off the HDMI port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we just disable the GCP infoframe when turning off the port. That means if the same transcoder is used on a DP port next, we might end up pushing infoframes over DP, which isn't intended. Just disable all the infoframes when turning off the port. Also protect against two ports stomping on each other on g4x due to the single video DIP instance. Now only the first port to enable gets to send infoframes. v2: Rebase Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 85 ++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 14a916437b24..ed0fce1e5953 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -514,7 +514,13 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return; - val &= ~VIDEO_DIP_ENABLE; + if (port != (val & VIDEO_DIP_PORT_MASK)) { + DRM_DEBUG_KMS("video DIP still enabled on port %c\n", + (val & VIDEO_DIP_PORT_MASK) >> 29); + return; + } + val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); I915_WRITE(reg, val); POSTING_READ(reg); return; @@ -522,16 +528,17 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, if (port != (val & VIDEO_DIP_PORT_MASK)) { if (val & VIDEO_DIP_ENABLE) { - val &= ~VIDEO_DIP_ENABLE; - I915_WRITE(reg, val); - POSTING_READ(reg); + DRM_DEBUG_KMS("video DIP already enabled on port %c\n", + (val & VIDEO_DIP_PORT_MASK) >> 29); + return; } val &= ~VIDEO_DIP_PORT_MASK; val |= port; } val |= VIDEO_DIP_ENABLE; - val &= ~VIDEO_DIP_ENABLE_VENDOR; + val &= ~(VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); I915_WRITE(reg, val); POSTING_READ(reg); @@ -632,23 +639,6 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder) return val != 0; } -static void intel_disable_gcp_infoframe(struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - u32 reg; - - if (HAS_DDI(dev_priv)) - reg = HSW_TVIDEO_DIP_CTL(crtc->config->cpu_transcoder); - else if (IS_VALLEYVIEW(dev_priv)) - reg = VLV_TVIDEO_DIP_CTL(crtc->pipe); - else if (HAS_PCH_SPLIT(dev_priv->dev)) - reg = TVIDEO_DIP_CTL(crtc->pipe); - else - return; - - I915_WRITE(reg, I915_READ(reg) & ~VIDEO_DIP_ENABLE_GCP); -} - static void ibx_set_infoframes(struct drm_encoder *encoder, bool enable, struct drm_display_mode *adjusted_mode) @@ -669,25 +659,26 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return; - val &= ~VIDEO_DIP_ENABLE; + val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); I915_WRITE(reg, val); POSTING_READ(reg); return; } if (port != (val & VIDEO_DIP_PORT_MASK)) { - if (val & VIDEO_DIP_ENABLE) { - val &= ~VIDEO_DIP_ENABLE; - I915_WRITE(reg, val); - POSTING_READ(reg); - } + WARN(val & VIDEO_DIP_ENABLE, + "DIP already enabled on port %c\n", + (val & VIDEO_DIP_PORT_MASK) >> 29); val &= ~VIDEO_DIP_PORT_MASK; val |= port; } val |= VIDEO_DIP_ENABLE; - val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | - VIDEO_DIP_ENABLE_GCP); + val &= ~(VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); if (intel_hdmi_set_gcp_infoframe(encoder)) val |= VIDEO_DIP_ENABLE_GCP; @@ -718,7 +709,9 @@ static void cpt_set_infoframes(struct drm_encoder *encoder, if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return; - val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI); + val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); I915_WRITE(reg, val); POSTING_READ(reg); return; @@ -727,7 +720,7 @@ static void cpt_set_infoframes(struct drm_encoder *encoder, /* Set both together, unset both together: see the spec. */ val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI; val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | - VIDEO_DIP_ENABLE_GCP); + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); if (intel_hdmi_set_gcp_infoframe(encoder)) val |= VIDEO_DIP_ENABLE_GCP; @@ -760,25 +753,26 @@ static void vlv_set_infoframes(struct drm_encoder *encoder, if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return; - val &= ~VIDEO_DIP_ENABLE; + val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); I915_WRITE(reg, val); POSTING_READ(reg); return; } if (port != (val & VIDEO_DIP_PORT_MASK)) { - if (val & VIDEO_DIP_ENABLE) { - val &= ~VIDEO_DIP_ENABLE; - I915_WRITE(reg, val); - POSTING_READ(reg); - } + WARN(val & VIDEO_DIP_ENABLE, + "DIP already enabled on port %c\n", + (val & VIDEO_DIP_PORT_MASK) >> 29); val &= ~VIDEO_DIP_PORT_MASK; val |= port; } val |= VIDEO_DIP_ENABLE; - val &= ~(VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_ENABLE_VENDOR | - VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP); + val &= ~(VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); if (intel_hdmi_set_gcp_infoframe(encoder)) val |= VIDEO_DIP_ENABLE_GCP; @@ -803,15 +797,16 @@ static void hsw_set_infoframes(struct drm_encoder *encoder, assert_hdmi_port_disabled(intel_hdmi); + val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW | + VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | + VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW); + if (!enable) { - I915_WRITE(reg, 0); + I915_WRITE(reg, val); POSTING_READ(reg); return; } - val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW | - VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW); - if (intel_hdmi_set_gcp_infoframe(encoder)) val |= VIDEO_DIP_ENABLE_GCP_HSW; @@ -1107,7 +1102,7 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) POSTING_READ(intel_hdmi->hdmi_reg); } - intel_disable_gcp_infoframe(to_intel_crtc(encoder->base.crtc)); + intel_hdmi->set_infoframes(&encoder->base, false, NULL); } static void g4x_disable_hdmi(struct intel_encoder *encoder) -- cgit v1.3-6-gb490 From ec1dc603c664364c9d6c9c8e774f2822edf7397b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 5 May 2015 17:06:25 +0300 Subject: drm/i915: Check infoframe state more diligently. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check that the DIP is enabled on the right port on IBX and VLV/CHV as we're doing on g4x, and also check for all the infoframe enable bits on all platforms. Eventually we should track each infoframe type independently, and also their contents. This is a small step in that direction as .infoframe_enabled() return value could be easily turned into a bitmask. Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 44 ++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ed0fce1e5953..1cde6c045da2 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -174,10 +174,14 @@ static bool g4x_infoframe_enabled(struct drm_encoder *encoder) struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); u32 val = I915_READ(VIDEO_DIP_CTL); - if (VIDEO_DIP_PORT(intel_dig_port->port) == (val & VIDEO_DIP_PORT_MASK)) - return val & VIDEO_DIP_ENABLE; + if ((val & VIDEO_DIP_ENABLE) == 0) + return false; - return false; + if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port)) + return false; + + return val & (VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); } static void ibx_write_infoframe(struct drm_encoder *encoder, @@ -227,10 +231,15 @@ static bool ibx_infoframe_enabled(struct drm_encoder *encoder) int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); - if (VIDEO_DIP_PORT(intel_dig_port->port) == (val & VIDEO_DIP_PORT_MASK)) - return val & VIDEO_DIP_ENABLE; + if ((val & VIDEO_DIP_ENABLE) == 0) + return false; - return false; + if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port)) + return false; + + return val & (VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); } static void cpt_write_infoframe(struct drm_encoder *encoder, @@ -282,7 +291,12 @@ static bool cpt_infoframe_enabled(struct drm_encoder *encoder) int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); - return val & VIDEO_DIP_ENABLE; + if ((val & VIDEO_DIP_ENABLE) == 0) + return false; + + return val & (VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); } static void vlv_write_infoframe(struct drm_encoder *encoder, @@ -332,10 +346,15 @@ static bool vlv_infoframe_enabled(struct drm_encoder *encoder) int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); - if (VIDEO_DIP_PORT(intel_dig_port->port) == (val & VIDEO_DIP_PORT_MASK)) - return val & VIDEO_DIP_ENABLE; + if ((val & VIDEO_DIP_ENABLE) == 0) + return false; - return false; + if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port)) + return false; + + return val & (VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); } static void hsw_write_infoframe(struct drm_encoder *encoder, @@ -383,8 +402,9 @@ static bool hsw_infoframe_enabled(struct drm_encoder *encoder) u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder); u32 val = I915_READ(ctl_reg); - return val & (VIDEO_DIP_ENABLE_AVI_HSW | VIDEO_DIP_ENABLE_SPD_HSW | - VIDEO_DIP_ENABLE_VS_HSW); + return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW | + VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | + VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW); } /* -- cgit v1.3-6-gb490 From be69a1335fceb706e19f7eaf8d34c9a721c5baf9 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 5 May 2015 17:06:26 +0300 Subject: drm/i915: Fix hdmi clock readout with pixel repeat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Account for the pixel multiplier when reading out the HDMI mode dotclock. Makes the state checked happier on my ILK when using double clocked modes. Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 1cde6c045da2..42fc50528190 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -943,6 +943,9 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, else dotclock = pipe_config->port_clock; + if (pipe_config->pixel_multiplier) + dotclock /= pipe_config->pixel_multiplier; + if (HAS_PCH_SPLIT(dev_priv->dev)) ironlake_check_encoder_dotclock(pipe_config, dotclock); -- cgit v1.3-6-gb490 From 3320e37f7ac1f4df90268f204fef490dacee7ca0 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 5 May 2015 17:06:27 +0300 Subject: drm/i915: Double the port clock when using double clocked modes with 12bpc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we're forgetting to double the port clock when using double clocked modes with 12bpc on HDMI. We're only accounting for the 1.5x factor due to the 12bpc. So further double the 1.5x port clock when we have a double clocked mode. Unfortunately I don't have any displays that support both 12bpc and double clocked modes, so I was unable to test this. Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 42fc50528190..00c4b40e0158 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1242,6 +1242,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) { pipe_config->pixel_multiplier = 2; + clock_12bpc *= 2; } if (intel_hdmi->color_range) -- cgit v1.3-6-gb490 From 66c826a1754c07012e29fbe9be7013e92a5acbac Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 1 Jun 2015 10:32:01 +0300 Subject: drm/i915/vlv: fix RC6 residency time calculation The divider value to convert from CZ clock rate to ms needs a +1 adjustment on VLV just like on CHV. This matches both the spec and the accuracy test by pm_rc6_residency. v2: - simplify logic checking for the CHV 320MHz special case (Rodrigo) Testcase: igt/pm_rc6_residency Signed-off-by: Imre Deak Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=76877 Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_sysfs.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 247626885f49..55bd04c6b939 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -64,24 +64,16 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) goto out; } - units = 0; - div = 1000000ULL; - - if (IS_CHERRYVIEW(dev)) { + if (IS_CHERRYVIEW(dev) && czcount_30ns == 1) { /* Special case for 320Mhz */ - if (czcount_30ns == 1) { - div = 10000000ULL; - units = 3125ULL; - } else { - /* chv counts are one less */ - czcount_30ns += 1; - } + div = 10000000ULL; + units = 3125ULL; + } else { + czcount_30ns += 1; + div = 1000000ULL; + units = DIV_ROUND_UP_ULL(30ULL * bias, czcount_30ns); } - if (units == 0) - units = DIV_ROUND_UP_ULL(30ULL * bias, - (u64)czcount_30ns); - if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH) units <<= 8; -- cgit v1.3-6-gb490 From ea3f5d261fb0b757f95c1657f71ac86eb1778fd1 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 22 May 2015 20:04:58 +0300 Subject: drm/i915/gtt: Don't leak scratch page on mapping error Free the scratch page if dma mapping fails. Signed-off-by: Mika Kuoppala Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 619dad1b2386..5e3bfa94221b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2143,8 +2143,10 @@ static int setup_scratch_page(struct drm_device *dev) #ifdef CONFIG_INTEL_IOMMU dma_addr = pci_map_page(dev->pdev, page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, dma_addr)) + if (pci_dma_mapping_error(dev->pdev, dma_addr)) { + __free_page(page); return -EINVAL; + } #else dma_addr = page_to_phys(page); #endif -- cgit v1.3-6-gb490 From 8a1ebd7480fe8e80119d12bef2906f9480c2916f Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 22 May 2015 20:04:59 +0300 Subject: drm/i915/gtt: Remove _single from page table allocator We are always allocating a single page. No need to be verbose so remove the suffix. Signed-off-by: Mika Kuoppala Reviewed-by: Joonas Lahtinen Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 5e3bfa94221b..d7ea81aa5ceb 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -369,7 +369,7 @@ static void gen8_initialize_pt(struct i915_address_space *vm, kunmap_atomic(pt_vaddr); } -static struct i915_page_table *alloc_pt_single(struct drm_device *dev) +static struct i915_page_table *alloc_pt(struct drm_device *dev) { struct i915_page_table *pt; const size_t count = INTEL_INFO(dev)->gen >= 8 ? @@ -417,7 +417,7 @@ static void unmap_and_free_pd(struct i915_page_directory *pd, } } -static struct i915_page_directory *alloc_pd_single(struct drm_device *dev) +static struct i915_page_directory *alloc_pd(struct drm_device *dev) { struct i915_page_directory *pd; int ret = -ENOMEM; @@ -702,7 +702,7 @@ static int gen8_ppgtt_alloc_pagetabs(struct i915_hw_ppgtt *ppgtt, continue; } - pt = alloc_pt_single(dev); + pt = alloc_pt(dev); if (IS_ERR(pt)) goto unwind_out; @@ -763,7 +763,7 @@ static int gen8_ppgtt_alloc_page_directories(struct i915_hw_ppgtt *ppgtt, if (pd) continue; - pd = alloc_pd_single(dev); + pd = alloc_pd(dev); if (IS_ERR(pd)) goto unwind_out; @@ -939,11 +939,11 @@ err_out: */ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) { - ppgtt->scratch_pt = alloc_pt_single(ppgtt->base.dev); + ppgtt->scratch_pt = alloc_pt(ppgtt->base.dev); if (IS_ERR(ppgtt->scratch_pt)) return PTR_ERR(ppgtt->scratch_pt); - ppgtt->scratch_pd = alloc_pd_single(ppgtt->base.dev); + ppgtt->scratch_pd = alloc_pd(ppgtt->base.dev); if (IS_ERR(ppgtt->scratch_pd)) return PTR_ERR(ppgtt->scratch_pd); @@ -1327,7 +1327,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, /* We've already allocated a page table */ WARN_ON(!bitmap_empty(pt->used_ptes, GEN6_PTES)); - pt = alloc_pt_single(dev); + pt = alloc_pt(dev); if (IS_ERR(pt)) { ret = PTR_ERR(pt); goto unwind_out; @@ -1413,7 +1413,7 @@ static int gen6_ppgtt_allocate_page_directories(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)); - ppgtt->scratch_pt = alloc_pt_single(ppgtt->base.dev); + ppgtt->scratch_pt = alloc_pt(ppgtt->base.dev); if (IS_ERR(ppgtt->scratch_pt)) return PTR_ERR(ppgtt->scratch_pt); -- cgit v1.3-6-gb490 From ac3f918d5a069f1c34c6e0d39cccb0e9c8ac9334 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Sat, 30 May 2015 20:25:53 +0200 Subject: Fix resume from suspend on IBM X30 This patch fixes the resume from suspend-to-ram on the IBM X30 laptop. The problem is caused by the Bios missing to re-initialize the iVCH registers, especially the PLL registers. This patch records the iVCH registers during initialization, and re-installs this register set when resuming. Signed-off-by: Thomas Richter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/dvo_ivch.c | 63 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c index 89b08a896d20..732ce8785945 100644 --- a/drivers/gpu/drm/i915/dvo_ivch.c +++ b/drivers/gpu/drm/i915/dvo_ivch.c @@ -22,6 +22,7 @@ * * Authors: * Eric Anholt + * Thomas Richter * * Minor modifications (Dithering enable): * Thomas Richter @@ -90,7 +91,7 @@ /* * LCD Vertical Display Size */ -#define VR21 0x20 +#define VR21 0x21 /* * Panel power down status @@ -155,16 +156,33 @@ # define VR8F_POWER_MASK (0x3c) # define VR8F_POWER_POS (2) +/* Some Bios implementations do not restore the DVO state upon + * resume from standby. Thus, this driver has to handle it + * instead. The following list contains all registers that + * require saving. + */ +static const uint16_t backup_addresses[] = { + 0x11, 0x12, + 0x18, 0x19, 0x1a, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x8e, 0x8f, + 0x10 /* this must come last */ +}; + struct ivch_priv { bool quiet; uint16_t width, height; + + /* Register backup */ + + uint16_t reg_backup[ARRAY_SIZE(backup_addresses)]; }; static void ivch_dump_regs(struct intel_dvo_device *dvo); - /** * Reads a register on the ivch. * @@ -246,6 +264,7 @@ static bool ivch_init(struct intel_dvo_device *dvo, { struct ivch_priv *priv; uint16_t temp; + int i; priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL); if (priv == NULL) @@ -273,6 +292,14 @@ static bool ivch_init(struct intel_dvo_device *dvo, ivch_read(dvo, VR20, &priv->width); ivch_read(dvo, VR21, &priv->height); + /* Make a backup of the registers to be able to restore them + * upon suspend. + */ + for (i = 0; i < ARRAY_SIZE(backup_addresses); i++) + ivch_read(dvo, backup_addresses[i], priv->reg_backup + i); + + ivch_dump_regs(dvo); + return true; out: @@ -294,12 +321,31 @@ static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo, return MODE_OK; } +/* Restore the DVO registers after a resume + * from RAM. Registers have been saved during + * the initialization. + */ +static void ivch_reset(struct intel_dvo_device *dvo) +{ + struct ivch_priv *priv = dvo->dev_priv; + int i; + + DRM_DEBUG_KMS("Resetting the IVCH registers\n"); + + ivch_write(dvo, VR10, 0x0000); + + for (i = 0; i < ARRAY_SIZE(backup_addresses); i++) + ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]); +} + /** Sets the power state of the panel connected to the ivch */ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable) { int i; uint16_t vr01, vr30, backlight; + ivch_reset(dvo); + /* Set the new power state of the panel. */ if (!ivch_read(dvo, VR01, &vr01)) return; @@ -308,6 +354,7 @@ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable) backlight = 1; else backlight = 0; + ivch_write(dvo, VR80, backlight); if (enable) @@ -334,6 +381,8 @@ static bool ivch_get_hw_state(struct intel_dvo_device *dvo) { uint16_t vr01; + ivch_reset(dvo); + /* Set the new power state of the panel. */ if (!ivch_read(dvo, VR01, &vr01)) return false; @@ -348,11 +397,15 @@ static void ivch_mode_set(struct intel_dvo_device *dvo, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct ivch_priv *priv = dvo->dev_priv; uint16_t vr40 = 0; uint16_t vr01 = 0; uint16_t vr10; - ivch_read(dvo, VR10, &vr10); + ivch_reset(dvo); + + vr10 = priv->reg_backup[ARRAY_SIZE(backup_addresses) - 1]; + /* Enable dithering for 18 bpp pipelines */ vr10 &= VR10_INTERFACE_DEPTH_MASK; if (vr10 == VR10_INTERFACE_2X18 || vr10 == VR10_INTERFACE_1X18) @@ -366,7 +419,7 @@ static void ivch_mode_set(struct intel_dvo_device *dvo, uint16_t x_ratio, y_ratio; vr01 |= VR01_PANEL_FIT_ENABLE; - vr40 |= VR40_CLOCK_GATING_ENABLE | VR40_ENHANCED_PANEL_FITTING; + vr40 |= VR40_CLOCK_GATING_ENABLE; x_ratio = (((mode->hdisplay - 1) << 16) / (adjusted_mode->hdisplay - 1)) >> 2; y_ratio = (((mode->vdisplay - 1) << 16) / @@ -381,8 +434,6 @@ static void ivch_mode_set(struct intel_dvo_device *dvo, ivch_write(dvo, VR01, vr01); ivch_write(dvo, VR40, vr40); - - ivch_dump_regs(dvo); } static void ivch_dump_regs(struct intel_dvo_device *dvo) -- cgit v1.3-6-gb490 From fcc0008fd02330f1c539a8dd831b00ca9b998cd8 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 26 May 2015 20:22:40 +0300 Subject: drm/i915: Bump CHV PFI credits to 63 when cdclk>=czclk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch from using 31 PFI credits to 63 PFI credits when cdclk>=czclk on CHV. The spec lists both 31 and 63 as "suggested" values, but based on feedback from hardware folks we should actually be using 63. Originally I picked the 31 basically by flipping a coin. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c4ccc376ae44..193ba79e5a41 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6055,7 +6055,7 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) if (DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 1000) >= dev_priv->rps.cz_freq) { /* CHV suggested value is 31 or 63 */ if (IS_CHERRYVIEW(dev_priv)) - credits = PFI_CREDIT_31; + credits = PFI_CREDIT_63; else credits = PFI_CREDIT(15); } else { -- cgit v1.3-6-gb490 From 6a65c5b9326c9dd391afb1b3df75cbedffbaccdb Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 29 May 2015 16:44:13 +0300 Subject: drm/i915: Fix command parser to validate multiple register access with the same command. Until now the software command checker assumed that commands could read or write at most a single register per packet. This is not necessarily the case, MI_LOAD_REGISTER_IMM expects a variable-length list of offset/value pairs and writes them in sequence. The previous code would only check whether the first entry was valid, effectively allowing userspace to write unrestricted registers of the MMIO space by sending a multi-register write with a legal first register, with potential security implications on Gen6 and 7 hardware. Fix it by extending the drm_i915_cmd_descriptor table to represent multi-register access and making validate_cmd() iterate for all register offsets present in the command packet. Signed-off-by: Francisco Jerez Reviewed-by: Zhigang Gong Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 74 ++++++++++++++++++++-------------- drivers/gpu/drm/i915/i915_drv.h | 5 +++ 2 files changed, 48 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 9605ff8f2fcd..5fc49bbcdb9d 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -123,7 +123,7 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, R ), CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, R ), CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W, - .reg = { .offset = 1, .mask = 0x007FFFFC } ), + .reg = { .offset = 1, .mask = 0x007FFFFC, .step = 2 } ), CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, .reg = { .offset = 1, .mask = 0x007FFFFC }, .bits = {{ @@ -934,7 +934,7 @@ bool i915_needs_cmd_parser(struct intel_engine_cs *ring) static bool check_cmd(const struct intel_engine_cs *ring, const struct drm_i915_cmd_descriptor *desc, - const u32 *cmd, + const u32 *cmd, u32 length, const bool is_master, bool *oacontrol_set) { @@ -950,38 +950,49 @@ static bool check_cmd(const struct intel_engine_cs *ring, } if (desc->flags & CMD_DESC_REGISTER) { - u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; - /* - * OACONTROL requires some special handling for writes. We - * want to make sure that any batch which enables OA also - * disables it before the end of the batch. The goal is to - * prevent one process from snooping on the perf data from - * another process. To do that, we need to check the value - * that will be written to the register. Hence, limit - * OACONTROL writes to only MI_LOAD_REGISTER_IMM commands. + * Get the distance between individual register offset + * fields if the command can perform more than one + * access at a time. */ - if (reg_addr == OACONTROL) { - if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { - DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); - return false; + const u32 step = desc->reg.step ? desc->reg.step : length; + u32 offset; + + for (offset = desc->reg.offset; offset < length; + offset += step) { + const u32 reg_addr = cmd[offset] & desc->reg.mask; + + /* + * OACONTROL requires some special handling for + * writes. We want to make sure that any batch which + * enables OA also disables it before the end of the + * batch. The goal is to prevent one process from + * snooping on the perf data from another process. To do + * that, we need to check the value that will be written + * to the register. Hence, limit OACONTROL writes to + * only MI_LOAD_REGISTER_IMM commands. + */ + if (reg_addr == OACONTROL) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { + DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); + return false; + } + + if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) + *oacontrol_set = (cmd[offset + 1] != 0); } - if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) - *oacontrol_set = (cmd[2] != 0); - } - - 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); - return false; + 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); + return false; + } } } } @@ -1105,7 +1116,8 @@ int i915_parse_cmds(struct intel_engine_cs *ring, break; } - if (!check_cmd(ring, desc, cmd, is_master, &oacontrol_set)) { + if (!check_cmd(ring, desc, cmd, length, is_master, + &oacontrol_set)) { ret = -EINVAL; break; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 46722f85ef76..971fc330cc35 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2312,10 +2312,15 @@ struct drm_i915_cmd_descriptor { * 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. + * + * A non-zero step value implies that the command may access multiple + * registers in sequence (e.g. LRI), in that case step gives the + * distance in dwords between individual offset fields. */ struct { u32 offset; u32 mask; + u32 step; } reg; #define MAX_CMD_DESC_BITMASKS 3 -- cgit v1.3-6-gb490 From 4e86f725cebc8164e5f6601707379dd51440269d Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 29 May 2015 16:44:14 +0300 Subject: drm/i915: Extend the parser to check register writes against a mask/value pair. In some cases it might be unnecessary or dangerous to give userspace the right to write arbitrary values to some register, even though it might be desirable to give it control of some of its bits. This patch extends the register whitelist entries to contain a mask/value pair in addition to the register offset. For registers with non-zero mask, any LRM writes and LRI writes where the bits of the immediate given by the mask don't match the specified value will be rejected. This will be used in my next patch to grant userspace partial write access to some sensitive registers. Signed-off-by: Francisco Jerez Reviewed-by: Zhigang Gong Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 138 +++++++++++++++++++++----------- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 +- 2 files changed, 96 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 5fc49bbcdb9d..cafa3e2f16fc 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -395,16 +395,38 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = { /* * Register whitelists, sorted by increasing register offset. + */ + +/* + * An individual whitelist entry granting access to register addr. If + * mask is non-zero the argument of immediate register writes will be + * AND-ed with mask, and the command will be rejected if the result + * doesn't match value. + * + * Registers with non-zero mask are only allowed to be written using + * LRI. + */ +struct drm_i915_reg_descriptor { + u32 addr; + u32 mask; + u32 value; +}; + +/* Convenience macro for adding 32-bit registers. */ +#define REG32(address, ...) \ + { .addr = address, __VA_ARGS__ } + +/* + * Convenience macro for adding 64-bit registers. * * Some registers that userspace accesses are 64 bits. The register * access commands only allow 32-bit accesses. Hence, we have to include * entries for both halves of the 64-bit registers. */ +#define REG64(addr) \ + REG32(addr), REG32(addr + sizeof(u32)) -/* Convenience macro for adding 64-bit registers */ -#define REG64(addr) (addr), (addr + sizeof(u32)) - -static const u32 gen7_render_regs[] = { +static const struct drm_i915_reg_descriptor gen7_render_regs[] = { REG64(GPGPU_THREADS_DISPATCHED), REG64(HS_INVOCATION_COUNT), REG64(DS_INVOCATION_COUNT), @@ -417,15 +439,15 @@ static const u32 gen7_render_regs[] = { REG64(CL_PRIMITIVES_COUNT), REG64(PS_INVOCATION_COUNT), REG64(PS_DEPTH_COUNT), - OACONTROL, /* Only allowed for LRI and SRM. See below. */ + REG32(OACONTROL), /* Only allowed for LRI and SRM. See below. */ REG64(MI_PREDICATE_SRC0), REG64(MI_PREDICATE_SRC1), - GEN7_3DPRIM_END_OFFSET, - GEN7_3DPRIM_START_VERTEX, - GEN7_3DPRIM_VERTEX_COUNT, - GEN7_3DPRIM_INSTANCE_COUNT, - GEN7_3DPRIM_START_INSTANCE, - GEN7_3DPRIM_BASE_VERTEX, + REG32(GEN7_3DPRIM_END_OFFSET), + REG32(GEN7_3DPRIM_START_VERTEX), + REG32(GEN7_3DPRIM_VERTEX_COUNT), + REG32(GEN7_3DPRIM_INSTANCE_COUNT), + REG32(GEN7_3DPRIM_START_INSTANCE), + REG32(GEN7_3DPRIM_BASE_VERTEX), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), @@ -434,33 +456,34 @@ static const u32 gen7_render_regs[] = { REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)), REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)), REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)), - GEN7_SO_WRITE_OFFSET(0), - GEN7_SO_WRITE_OFFSET(1), - GEN7_SO_WRITE_OFFSET(2), - GEN7_SO_WRITE_OFFSET(3), - GEN7_L3SQCREG1, - GEN7_L3CNTLREG2, - GEN7_L3CNTLREG3, + REG32(GEN7_SO_WRITE_OFFSET(0)), + REG32(GEN7_SO_WRITE_OFFSET(1)), + REG32(GEN7_SO_WRITE_OFFSET(2)), + REG32(GEN7_SO_WRITE_OFFSET(3)), + REG32(GEN7_L3SQCREG1), + REG32(GEN7_L3CNTLREG2), + REG32(GEN7_L3CNTLREG3), }; -static const u32 gen7_blt_regs[] = { - BCS_SWCTRL, +static const struct drm_i915_reg_descriptor gen7_blt_regs[] = { + REG32(BCS_SWCTRL), }; -static const u32 ivb_master_regs[] = { - FORCEWAKE_MT, - DERRMR, - GEN7_PIPE_DE_LOAD_SL(PIPE_A), - GEN7_PIPE_DE_LOAD_SL(PIPE_B), - GEN7_PIPE_DE_LOAD_SL(PIPE_C), +static const struct drm_i915_reg_descriptor ivb_master_regs[] = { + REG32(FORCEWAKE_MT), + REG32(DERRMR), + REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_A)), + REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_B)), + REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_C)), }; -static const u32 hsw_master_regs[] = { - FORCEWAKE_MT, - DERRMR, +static const struct drm_i915_reg_descriptor hsw_master_regs[] = { + REG32(FORCEWAKE_MT), + REG32(DERRMR), }; #undef REG64 +#undef REG32 static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) { @@ -550,14 +573,16 @@ static bool validate_cmds_sorted(struct intel_engine_cs *ring, return ret; } -static bool check_sorted(int ring_id, const u32 *reg_table, int reg_count) +static bool check_sorted(int ring_id, + const struct drm_i915_reg_descriptor *reg_table, + int reg_count) { int i; u32 previous = 0; bool ret = true; for (i = 0; i < reg_count; i++) { - u32 curr = reg_table[i]; + u32 curr = reg_table[i].addr; if (curr < previous) { DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n", @@ -804,18 +829,20 @@ find_cmd(struct intel_engine_cs *ring, return default_desc; } -static bool valid_reg(const u32 *table, int count, u32 addr) +static const struct drm_i915_reg_descriptor * +find_reg(const struct drm_i915_reg_descriptor *table, + int count, u32 addr) { - if (table && count != 0) { + if (table) { int i; for (i = 0; i < count; i++) { - if (table[i] == addr) - return true; + if (table[i].addr == addr) + return &table[i]; } } - return false; + return NULL; } static u32 *vmap_batch(struct drm_i915_gem_object *obj, @@ -961,6 +988,20 @@ static bool check_cmd(const struct intel_engine_cs *ring, for (offset = desc->reg.offset; offset < length; offset += step) { const u32 reg_addr = cmd[offset] & desc->reg.mask; + const struct drm_i915_reg_descriptor *reg = + find_reg(ring->reg_table, ring->reg_count, + reg_addr); + + if (!reg && is_master) + reg = find_reg(ring->master_reg_table, + ring->master_reg_count, + reg_addr); + + if (!reg) { + DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", + reg_addr, *cmd, ring->id); + return false; + } /* * OACONTROL requires some special handling for @@ -982,15 +1023,22 @@ static bool check_cmd(const struct intel_engine_cs *ring, *oacontrol_set = (cmd[offset + 1] != 0); } - 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); + /* + * Check the value written to the register against the + * allowed mask/value pair given in the whitelist entry. + */ + if (reg->mask) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { + DRM_DEBUG_DRIVER("CMD: Rejected LRM to masked register 0x%08X\n", + reg_addr); + return false; + } + + if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1) && + (offset + 2 > length || + (cmd[offset + 1] & reg->mask) != reg->value)) { + DRM_DEBUG_DRIVER("CMD: Rejected LRI to masked register 0x%08X\n", + reg_addr); return false; } } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 39f6dfc0ee54..e539314ae87e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -118,6 +118,7 @@ struct intel_ringbuffer { }; struct intel_context; +struct drm_i915_reg_descriptor; struct intel_engine_cs { const char *name; @@ -300,14 +301,14 @@ struct intel_engine_cs { /* * Table of registers allowed in commands that read/write registers. */ - const u32 *reg_table; + const struct drm_i915_reg_descriptor *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; + const struct drm_i915_reg_descriptor *master_reg_table; int master_reg_count; /* -- cgit v1.3-6-gb490 From d351f6d94893f3ba98b1b20c5ef44c35fc1da124 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 29 May 2015 16:44:15 +0300 Subject: drm/i915: Add SCRATCH1 and ROW_CHICKEN3 to the register whitelist. Only bit 27 of SCRATCH1 and bit 6 of ROW_CHICKEN3 are allowed to be set because of security-sensitive bits we don't want userspace to mess with. On HSW hardware the whitelisted bits control whether atomic read-modify-write operations are performed on L3 or on GTI, and when set to L3 (which can be 10x-30x better performing than on GTI, depending on the application) require great care to avoid a system hang, so we currently program them to be handled on GTI by default. Beignet can immediately start taking advantage of this change to enable L3 atomics. Mesa should eventually switch to L3 atomics too, but a number of non-trivial changes are still required so it will continue using GTI atomics for now. Signed-off-by: Francisco Jerez Reviewed-by: Zhigang Gong Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index cafa3e2f16fc..306d9e4e5cf3 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -463,6 +463,13 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = { REG32(GEN7_L3SQCREG1), REG32(GEN7_L3CNTLREG2), REG32(GEN7_L3CNTLREG3), + REG32(HSW_SCRATCH1, + .mask = ~HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE, + .value = 0), + REG32(HSW_ROW_CHICKEN3, + .mask = ~(HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE << 16 | + HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE), + .value = 0), }; static const struct drm_i915_reg_descriptor gen7_blt_regs[] = { -- cgit v1.3-6-gb490 From 78ace48cfe6ca226793e46b8c465507efd053bba Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 16:42:15 +0100 Subject: drm/i915: Remove unnecessary () used with WARN() In Linux, macros are usually well done and protect their arguments properly, even avoiding multiple evaluations of the parameters. Extra () are really not needed. Cc: Suketu Shah Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_csr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index 5cb8cc18994a..aae065280d1b 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -459,7 +459,8 @@ void intel_csr_ucode_fini(struct drm_device *dev) void assert_csr_loaded(struct drm_i915_private *dev_priv) { - WARN((intel_csr_load_status_get(dev_priv) != FW_LOADED), "CSR is not loaded.\n"); + WARN(intel_csr_load_status_get(dev_priv) != FW_LOADED, + "CSR is not loaded.\n"); WARN(!I915_READ(CSR_PROGRAM_BASE), "CSR program storage start is NULL\n"); WARN(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n"); -- cgit v1.3-6-gb490 From abd41dc93c37abc89fb0470a8195c58f37aa52ac Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 16:42:16 +0100 Subject: drm/i915/skl: Add debug messages at the start/end of DMC firmware loading It's handy to have debug message for the "big" events and this one qualifies IMHO. Also helpful to see what's happening while we're loading the firwmare and how much time it takes. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_csr.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index aae065280d1b..2cf25ee8a268 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -389,6 +389,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) intel_csr_load_program(dev); fw_loaded = true; + DRM_DEBUG_KMS("Finished loading %s\n", dev_priv->csr.fw_path); out: if (fw_loaded) intel_runtime_pm_put(dev_priv); @@ -422,6 +423,8 @@ void intel_csr_ucode_init(struct drm_device *dev) return; } + DRM_DEBUG_KMS("Loading %s\n", csr->fw_path); + /* * Obtain a runtime pm reference, until CSR is loaded, * to avoid entering runtime-suspend. -- cgit v1.3-6-gb490 From caf4e2527599a86f1b7d6c7e13546d80e7e50a7c Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 16:56:18 +0100 Subject: drm/i915: Make sure our labels start at column 0 I noticed one of those and it turned out we have a few lingering around. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_sprite.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 193ba79e5a41..9c07098d2e13 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7077,7 +7077,7 @@ static int i965gm_get_display_clock_speed(struct drm_device *dev) return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); - fail: +fail: DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%04x\n", vco, tmp); return 200000; } @@ -7118,7 +7118,7 @@ static int g33_get_display_clock_speed(struct drm_device *dev) return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); - fail: +fail: DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%08x\n", vco, tmp); return 190476; } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 8193a35388d7..f5965fb49008 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1189,6 +1189,6 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); - out: +out: return ret; } -- cgit v1.3-6-gb490 From 0d8041842644cff1183f3d0df429792764aecd3f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jun 2015 12:52:28 +0100 Subject: drm/i915: Fix build without CONFIG_PM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/gpu/drm/i915/i915_debugfs.c: In function ‘i915_runtime_pm_status’: drivers/gpu/drm/i915/i915_debugfs.c:2528:34: error: ‘struct dev_pm_info’ has no member named ‘usage_count’ atomic_read(&dev->dev->power.usage_count)); Regression from commit a6aaec8be22652a808d6e316d4a92e58cb75e986 Author: Damien Lespiau Date: Thu Jun 4 18:23:58 2015 +0100 drm/i915: Add runtime PM's usage_count in i915_runtime_pm_status Signed-off-by: Chris Wilson Cc: Damien Lespiau Cc: Paulo Zanoni Cc: Jani Nikula Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 47d9854434c5..2ad71ef86770 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2490,8 +2490,12 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused) seq_printf(m, "GPU idle: %s\n", yesno(!dev_priv->mm.busy)); seq_printf(m, "IRQs disabled: %s\n", yesno(!intel_irqs_enabled(dev_priv))); +#ifdef CONFIG_PM seq_printf(m, "Usage count: %d\n", atomic_read(&dev->dev->power.usage_count)); +#else + seq_printf(m, "Device Power Management (CONFIG_PM) disabled\n"); +#endif return 0; } -- cgit v1.3-6-gb490 From 49e4d842f0d0892c3d26c93a81b9f22c1467030e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jun 2015 12:23:48 +0100 Subject: drm/i915: Report to userspace if we have a (presumed) working GPU reset In igt, we want to test handling of GPU hangs, both for recovery purposes and for reporting. However, we don't want to inject a genuine GPU hang onto a machine that cannot recover and so be permenantly wedged. Rather than embed heuristics into igt, have the kernel report exactly when it expects the GPU reset to work. This can also be usefully extended in future to indicate different levels of fine-grained resets. Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Tim Gore Cc: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 5 +++++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_uncore.c | 28 ++++++++++++++++++++++------ include/uapi/drm/i915_drm.h | 1 + 4 files changed, 29 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 34248635c36c..88795d2f1819 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -163,6 +163,11 @@ static int i915_getparam(struct drm_device *dev, void *data, if (!value) return -ENODEV; break; + case I915_PARAM_HAS_GPU_RESET: + value = i915.enable_hangcheck && + i915.reset && + intel_has_gpu_reset(dev); + break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 971fc330cc35..44efb4deccb5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2594,6 +2594,7 @@ extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); #endif extern int intel_gpu_reset(struct drm_device *dev); +extern bool intel_has_gpu_reset(struct drm_device *dev); extern int i915_reset(struct drm_device *dev); extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index a6d8a3ee7750..4a86cf007aa0 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1455,20 +1455,36 @@ static int gen6_do_reset(struct drm_device *dev) return ret; } -int intel_gpu_reset(struct drm_device *dev) +static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *) { if (INTEL_INFO(dev)->gen >= 6) - return gen6_do_reset(dev); + return gen6_do_reset; else if (IS_GEN5(dev)) - return ironlake_do_reset(dev); + return ironlake_do_reset; else if (IS_G4X(dev)) - return g4x_do_reset(dev); + return g4x_do_reset; else if (IS_G33(dev)) - return g33_do_reset(dev); + return g33_do_reset; else if (INTEL_INFO(dev)->gen >= 3) - return i915_do_reset(dev); + return i915_do_reset; else + return NULL; +} + +int intel_gpu_reset(struct drm_device *dev) +{ + int (*reset)(struct drm_device *); + + reset = intel_get_gpu_reset(dev); + if (reset == NULL) return -ENODEV; + + return reset(dev); +} + +bool intel_has_gpu_reset(struct drm_device *dev) +{ + return intel_get_gpu_reset(dev) != NULL; } void intel_uncore_check_errors(struct drm_device *dev) diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 92d61a7c942a..f88cc1cac5d9 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -354,6 +354,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_REVISION 32 #define I915_PARAM_SUBSLICE_TOTAL 33 #define I915_PARAM_EU_TOTAL 34 +#define I915_PARAM_HAS_GPU_RESET 35 typedef struct drm_i915_getparam { int param; -- cgit v1.3-6-gb490 From 0ddfd20385f2e0b22cb19e7da4a235121755f192 Mon Sep 17 00:00:00 2001 From: Ramalingam C Date: Mon, 15 Jun 2015 20:50:05 +0530 Subject: drm/i915: Restarting the Idleness DRRS in drrs_flush Corrected the documentation on the intel_edp_drrs_flush and intel_edp_drrs_invalidate. And accordingly edp_drrs_flush function is modified to restart the idleness detection after upclocking. v2: Update kerneldoc Signed-off-by: Daniel Vetter (v1) Signed-off-by: Ramalingam C Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f73da99e66b8..f9e4fa842450 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5456,13 +5456,12 @@ unlock: } /** - * intel_edp_drrs_invalidate - Invalidate DRRS + * intel_edp_drrs_invalidate - Disable Idleness DRRS * @dev: DRM device * @frontbuffer_bits: frontbuffer plane tracking bits * - * When there is a disturbance on screen (due to cursor movement/time - * update etc), DRRS needs to be invalidated, i.e. need to switch to - * high RR. + * This function gets called everytime rendering on the given planes start. + * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR). * * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits. */ @@ -5487,6 +5486,7 @@ void intel_edp_drrs_invalidate(struct drm_device *dev, crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; + /* invalidate means busy screen hence upclock */ if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) { intel_dp_set_drrs_state(dev_priv->dev, dev_priv->drrs.dp->attached_connector->panel. @@ -5500,13 +5500,14 @@ void intel_edp_drrs_invalidate(struct drm_device *dev, } /** - * intel_edp_drrs_flush - Flush DRRS + * intel_edp_drrs_flush - Restart Idleness DRRS * @dev: DRM device * @frontbuffer_bits: frontbuffer plane tracking bits * - * When there is no movement on screen, DRRS work can be scheduled. - * This DRRS work is responsible for setting relevant registers after a - * timeout of 1 second. + * This function gets called every time rendering on the given planes has + * completed or flip on a crtc is completed. So DRRS should be upclocked + * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again, + * if no other planes are dirty. * * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits. */ @@ -5532,8 +5533,17 @@ void intel_edp_drrs_flush(struct drm_device *dev, pipe = to_intel_crtc(crtc)->pipe; dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; - if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR && - !dev_priv->drrs.busy_frontbuffer_bits) + /* flush means busy screen hence upclock */ + if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) + intel_dp_set_drrs_state(dev_priv->dev, + dev_priv->drrs.dp->attached_connector->panel. + fixed_mode->vrefresh); + + /* + * flush also means no more activity hence schedule downclock, if all + * other fbs are quiescent too + */ + if (!dev_priv->drrs.busy_frontbuffer_bits) schedule_delayed_work(&dev_priv->drrs.work, msecs_to_jiffies(1000)); mutex_unlock(&dev_priv->drrs.mutex); -- cgit v1.3-6-gb490 From 7cd35277b4b7af2121dbc5534fc112e2b3896ef4 Mon Sep 17 00:00:00 2001 From: Chandra Konduru Date: Wed, 10 Jun 2015 16:16:12 -0700 Subject: drm/i915: Delete duplicate #defines added for DCx Delete the duplicate #defines introduced by: commit 6b457d31ea0465fcadcf6d5044f5f71398954727 Author: A.Sunil Kamath Date: Thu Apr 16 14:22:09 2015 +0530 drm/i915/skl: Implement enable/disable for Display C5 state. Signed-off-by: Chandra Konduru Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c9f9d3d3adba..a66967fd0197 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7282,12 +7282,6 @@ enum skl_disp_power_wells { #define DC_STATE_EN 0x45504 #define DC_STATE_EN_UPTO_DC5 (1<<0) #define DC_STATE_EN_DC9 (1<<3) - -/* -* SKL DC -*/ -#define DC_STATE_EN 0x45504 -#define DC_STATE_EN_UPTO_DC5 (1<<0) #define DC_STATE_EN_UPTO_DC6 (2<<0) #define DC_STATE_EN_UPTO_DC5_DC6_MASK 0x3 -- cgit v1.3-6-gb490 From 4e9a86b6bd335925077dde1006da6838774537d9 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 11 Jun 2015 16:31:14 +0300 Subject: drm/i915: Actually respect DSPSURF alignment restrictions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently intel_gen4_compute_page_offset() simply picks the closest page boundary below the linear offset. That however may not be suitably aligned to satisfy any hardware specific restrictions. So let's make sure the page boundary we choose is properly aligned. Also to play it a bit safer lets split the remaining linear offset into x and y values instead of just x. This should make no difference for most platforms since we convert the x and y offsets back into a linear offset before feeding them to the hardware. HSW+ are different however and use x and y offsets even with linear buffers, so they might have trouble if either the x or y get too big. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 37 ++++++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_drv.h | 3 ++- drivers/gpu/drm/i915/intel_sprite.c | 9 ++++++--- 3 files changed, 31 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index df2383849fc3..1d440e7e0344 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2329,6 +2329,18 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb, return 0; } +static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv) +{ + if (INTEL_INFO(dev_priv)->gen >= 9) + return 256 * 1024; + else if (IS_BROADWATER(dev_priv) || IS_CRESTLINE(dev_priv)) + return 128 * 1024; + else if (INTEL_INFO(dev_priv)->gen >= 4) + return 4 * 1024; + else + return 64 * 1024; +} + int intel_pin_and_fence_fb_obj(struct drm_plane *plane, struct drm_framebuffer *fb, @@ -2346,14 +2358,7 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane, switch (fb->modifier[0]) { case DRM_FORMAT_MOD_NONE: - if (INTEL_INFO(dev)->gen >= 9) - alignment = 256 * 1024; - else if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) - alignment = 128 * 1024; - else if (INTEL_INFO(dev)->gen >= 4) - alignment = 4 * 1024; - else - alignment = 64 * 1024; + alignment = intel_linear_alignment(dev_priv); break; case I915_FORMAT_MOD_X_TILED: if (INTEL_INFO(dev)->gen >= 9) @@ -2443,7 +2448,8 @@ static void intel_unpin_fb_obj(struct drm_framebuffer *fb, /* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel * is assumed to be a power-of-two. */ -unsigned long intel_gen4_compute_page_offset(int *x, int *y, +unsigned long intel_gen4_compute_page_offset(struct drm_i915_private *dev_priv, + int *x, int *y, unsigned int tiling_mode, unsigned int cpp, unsigned int pitch) @@ -2459,12 +2465,13 @@ unsigned long intel_gen4_compute_page_offset(int *x, int *y, return tile_rows * pitch * 8 + tiles * 4096; } else { + unsigned int alignment = intel_linear_alignment(dev_priv) - 1; unsigned int offset; offset = *y * pitch + *x * cpp; - *y = 0; - *x = (offset & 4095) / cpp; - return offset & -4096; + *y = (offset & alignment) / pitch; + *x = ((offset & alignment) - *y * pitch) / cpp; + return offset & ~alignment; } } @@ -2733,7 +2740,8 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, if (INTEL_INFO(dev)->gen >= 4) { intel_crtc->dspaddr_offset = - intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; @@ -2834,7 +2842,8 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, linear_offset = y * fb->pitches[0] + x * pixel_size; intel_crtc->dspaddr_offset = - intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b28029a1c8f2..c28d1171ea80 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1113,7 +1113,8 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); #define assert_pipe_enabled(d, p) assert_pipe(d, p, true) #define assert_pipe_disabled(d, p) assert_pipe(d, p, false) -unsigned long intel_gen4_compute_page_offset(int *x, int *y, +unsigned long intel_gen4_compute_page_offset(struct drm_i915_private *dev_priv, + int *x, int *y, unsigned int tiling_mode, unsigned int bpp, unsigned int pitch); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index f5965fb49008..0434cbe1634b 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -411,7 +411,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, crtc_h--; linear_offset = y * fb->pitches[0] + x * pixel_size; - sprsurf_offset = intel_gen4_compute_page_offset(&x, &y, + sprsurf_offset = intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); @@ -546,7 +547,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, linear_offset = y * fb->pitches[0] + x * pixel_size; sprsurf_offset = - intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= sprsurf_offset; @@ -682,7 +684,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, linear_offset = y * fb->pitches[0] + x * pixel_size; dvssurf_offset = - intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= dvssurf_offset; -- cgit v1.3-6-gb490 From 985b8bb486e7dd924925898f86fffca546d698db Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 11 Jun 2015 16:31:15 +0300 Subject: drm/i915: Align DSPSURF to 128k on VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VLV/CHV have problems with 4k aligned linear scanout buffers. The VLV docs got updated at some point to say that we need to align them to 128k, just like we do on gen4. So far I've seen the problem manifest when the stride is an odd multiple of 512 bytes, and the surface address meets the following pattern '(addr & 0xf000) == 0x1000' (also == 0x2000 is problematic on VLV). The result is a starcase effect (so some pages get dropped maybe?), with a few pages here and there clearly getting scannout out at the wrong position. I've not actually been able to reproduce this problem on gen4, so it's not clear of the issue is any way related to the 128k restrictions supposedly inherited from gen4. But let's hope the 128k alignment is sufficient to hide it all. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Reviewed-by: Arun R Murthy Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1d440e7e0344..e94a9a0a6d91 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2333,7 +2333,8 @@ static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv) { if (INTEL_INFO(dev_priv)->gen >= 9) return 256 * 1024; - else if (IS_BROADWATER(dev_priv) || IS_CRESTLINE(dev_priv)) + else if (IS_BROADWATER(dev_priv) || IS_CRESTLINE(dev_priv) || + IS_VALLEYVIEW(dev_priv)) return 128 * 1024; else if (INTEL_INFO(dev_priv)->gen >= 4) return 4 * 1024; -- cgit v1.3-6-gb490 From 44c5905e8e977b1dd9bb99bcd5686464fa0aa247 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 11 Jun 2015 16:31:16 +0300 Subject: drm/i915: Drop the 64k linear scanout alignment on gen2/3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docs don't support the 64k linear scanout alignment we impose on gen2/3. And it really makes no sense since we have no DSPSURF register, so the only thing that the hardware will see is the linear offset which will be just pixel aligned anyway. There is one case where 64k comes into the picture, and that's FBC. The start of the line length buffer corresponds to a 64k aligned address of the uncompressed framebuffer. So if the uncompressed fb is not 64k aligned, the first actually used entry in the line length buffer will not be byte 0. There are 32 extra entries in the line length buffer to account for this extra alignment so we shouldn't have to worry about it when mapping the uncompressed fb to the GTT. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e94a9a0a6d91..a806f1598a46 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2339,7 +2339,7 @@ static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv) else if (INTEL_INFO(dev_priv)->gen >= 4) return 4 * 1024; else - return 64 * 1024; + return 0; } int -- cgit v1.3-6-gb490 From 31b9df1040a9ac1d4b88e382f16a50b9f0aff9be Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Jun 2015 14:36:18 -0300 Subject: drm/i915: print FBC compression status on debugfs We already had a few bugs in the past where FBC was compressing nothing when it was enabled, which makes the feature quite useless. Add this information to debugfs so the test suites can check for regressions in this piece of the code. Our igt/tests/kms_frontbuffer_tracking already has support for this message. v2: - Remove pointless VLV check (Ville). Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 5 +++++ drivers/gpu/drm/i915/i915_reg.h | 3 +++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 698c0a2db067..6c788e434255 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1638,6 +1638,11 @@ static int i915_fbc_status(struct seq_file *m, void *unused) seq_putc(m, '\n'); } + if (INTEL_INFO(dev_priv)->gen >= 7) + seq_printf(m, "Compressing: %s\n", + yesno(I915_READ(FBC_STATUS2) & + FBC_COMPRESSION_MASK)); + intel_runtime_pm_put(dev_priv); return 0; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a66967fd0197..2261609d1d75 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1951,6 +1951,9 @@ enum skl_disp_power_wells { #define FBC_FENCE_OFF 0x03218 /* BSpec typo has 321Bh */ #define FBC_TAG 0x03300 +#define FBC_STATUS2 0x43214 +#define FBC_COMPRESSION_MASK 0x7ff + #define FBC_LL_SIZE (1536) /* Framebuffer compression for GM45+ */ -- cgit v1.3-6-gb490 From 87f5ff0115eed248377f3474834caceca072b9ba Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Jun 2015 14:36:19 -0300 Subject: drm/i915: add FBC_ROTATION to enum no_fbc_reason Because we're currently using FBC_UNSUPPORTED_MODE for two different cases. This commit will also allow us to write the next one without hiding information from the user. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_fbc.c | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6c788e434255..985e860691b4 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1632,6 +1632,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused) case FBC_CHIP_DEFAULT: seq_puts(m, "disabled per chip default"); break; + case FBC_ROTATION: + seq_puts(m, "rotation not supported"); + break; default: seq_puts(m, "unknown reason"); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 617b01f56062..491ef0cfcb0b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -926,6 +926,7 @@ struct i915_fbc { FBC_MULTIPLE_PIPES, /* more than one pipe active */ FBC_MODULE_PARAM, FBC_CHIP_DEFAULT, /* disabled by default on this chip */ + FBC_ROTATION, /* rotation is not supported */ } no_fbc_reason; }; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 6abb83432d4d..43704a48f20c 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -587,7 +587,7 @@ void intel_fbc_update(struct drm_device *dev) } if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && crtc->primary->state->rotation != BIT(DRM_ROTATE_0)) { - if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE)) + if (set_no_fbc_reason(dev_priv, FBC_ROTATION)) DRM_DEBUG_KMS("Rotation unsupported, disabling\n"); goto out_disable; } -- cgit v1.3-6-gb490 From 2e8144a53db50cf3d5b32641346d116f778a9680 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Jun 2015 14:36:20 -0300 Subject: drm/i915: unify no_fbc_reason message printing This commit has two main advantages: simplify intel_fbc_update() and deduplicate the strings. v2: - Rebase due to changes on P1. - set_no_fbc_reason() can now return void (Chris). Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 49 +++----------------------- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_fbc.c | 70 ++++++++++++++++++++++++------------- 3 files changed, 51 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 985e860691b4..35a5defe7e29 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1594,52 +1594,11 @@ static int i915_fbc_status(struct seq_file *m, void *unused) intel_runtime_pm_get(dev_priv); - if (intel_fbc_enabled(dev)) { + if (intel_fbc_enabled(dev)) seq_puts(m, "FBC enabled\n"); - } else { - seq_puts(m, "FBC disabled: "); - switch (dev_priv->fbc.no_fbc_reason) { - case FBC_OK: - seq_puts(m, "FBC actived, but currently disabled in hardware"); - break; - case FBC_UNSUPPORTED: - seq_puts(m, "unsupported by this chipset"); - break; - case FBC_NO_OUTPUT: - seq_puts(m, "no outputs"); - break; - case FBC_STOLEN_TOO_SMALL: - seq_puts(m, "not enough stolen memory"); - break; - case FBC_UNSUPPORTED_MODE: - seq_puts(m, "mode not supported"); - break; - case FBC_MODE_TOO_LARGE: - seq_puts(m, "mode too large"); - break; - case FBC_BAD_PLANE: - seq_puts(m, "FBC unsupported on plane"); - break; - case FBC_NOT_TILED: - seq_puts(m, "scanout buffer not tiled"); - break; - case FBC_MULTIPLE_PIPES: - seq_puts(m, "multiple pipes are enabled"); - break; - case FBC_MODULE_PARAM: - seq_puts(m, "disabled per module param (default off)"); - break; - case FBC_CHIP_DEFAULT: - seq_puts(m, "disabled per chip default"); - break; - case FBC_ROTATION: - seq_puts(m, "rotation not supported"); - break; - default: - seq_puts(m, "unknown reason"); - } - seq_putc(m, '\n'); - } + else + seq_printf(m, "FBC disabled: %s\n", + intel_no_fbc_reason_str(dev_priv->fbc.no_fbc_reason)); if (INTEL_INFO(dev_priv)->gen >= 7) seq_printf(m, "Compressing: %s\n", diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c28d1171ea80..bcafefcf048b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1256,6 +1256,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, enum fb_op_origin origin); void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); +const char *intel_no_fbc_reason_str(enum no_fbc_reason reason); /* intel_hdmi.c */ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 43704a48f20c..1ff288ce84d8 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -432,14 +432,47 @@ void intel_fbc_disable(struct drm_device *dev) dev_priv->fbc.crtc = NULL; } -static bool set_no_fbc_reason(struct drm_i915_private *dev_priv, +const char *intel_no_fbc_reason_str(enum no_fbc_reason reason) +{ + switch (reason) { + case FBC_OK: + return "FBC enabled but currently disabled in hardware"; + case FBC_UNSUPPORTED: + return "unsupported by this chipset"; + case FBC_NO_OUTPUT: + return "no output"; + case FBC_STOLEN_TOO_SMALL: + return "not enough stolen memory"; + case FBC_UNSUPPORTED_MODE: + return "mode incompatible with compression"; + case FBC_MODE_TOO_LARGE: + return "mode too large for compression"; + case FBC_BAD_PLANE: + return "FBC unsupported on plane"; + case FBC_NOT_TILED: + return "framebuffer not tiled or fenced"; + case FBC_MULTIPLE_PIPES: + return "more than one pipe active"; + case FBC_MODULE_PARAM: + return "disabled per module param"; + case FBC_CHIP_DEFAULT: + return "disabled per chip default"; + case FBC_ROTATION: + return "rotation unsupported"; + default: + MISSING_CASE(reason); + return "unknown reason"; + } +} + +static void set_no_fbc_reason(struct drm_i915_private *dev_priv, enum no_fbc_reason reason) { if (dev_priv->fbc.no_fbc_reason == reason) - return false; + return; dev_priv->fbc.no_fbc_reason = reason; - return true; + DRM_DEBUG_KMS("Disabling FBC: %s\n", intel_no_fbc_reason_str(reason)); } static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) @@ -459,8 +492,7 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) if (intel_crtc_active(tmp_crtc) && to_intel_plane_state(tmp_crtc->primary->state)->visible) { if (one_pipe_only && crtc) { - if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES)) - DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); + set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES); return NULL; } crtc = tmp_crtc; @@ -471,8 +503,7 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) } if (!crtc || crtc->primary->fb == NULL) { - if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT)) - DRM_DEBUG_KMS("no output, disabling\n"); + set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT); return NULL; } @@ -516,14 +547,12 @@ void intel_fbc_update(struct drm_device *dev) i915.enable_fbc = 0; if (i915.enable_fbc < 0) { - if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT)) - DRM_DEBUG_KMS("disabled per chip default\n"); + set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT); goto out_disable; } if (!i915.enable_fbc) { - if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM)) - DRM_DEBUG_KMS("fbc disabled per module param\n"); + set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM); goto out_disable; } @@ -547,9 +576,7 @@ void intel_fbc_update(struct drm_device *dev) if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) || (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) { - if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE)) - DRM_DEBUG_KMS("mode incompatible with compression, " - "disabling\n"); + set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE); goto out_disable; } @@ -565,14 +592,12 @@ void intel_fbc_update(struct drm_device *dev) } if (intel_crtc->config->pipe_src_w > max_width || intel_crtc->config->pipe_src_h > max_height) { - if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE)) - DRM_DEBUG_KMS("mode too large for compression, disabling\n"); + set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE); goto out_disable; } 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"); + set_no_fbc_reason(dev_priv, FBC_BAD_PLANE); goto out_disable; } @@ -581,14 +606,12 @@ void intel_fbc_update(struct drm_device *dev) */ if (obj->tiling_mode != I915_TILING_X || obj->fence_reg == I915_FENCE_REG_NONE) { - if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED)) - DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n"); + set_no_fbc_reason(dev_priv, FBC_NOT_TILED); goto out_disable; } if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && crtc->primary->state->rotation != BIT(DRM_ROTATE_0)) { - if (set_no_fbc_reason(dev_priv, FBC_ROTATION)) - DRM_DEBUG_KMS("Rotation unsupported, disabling\n"); + set_no_fbc_reason(dev_priv, FBC_ROTATION); goto out_disable; } @@ -598,8 +621,7 @@ void intel_fbc_update(struct drm_device *dev) if (i915_gem_stolen_setup_compression(dev, obj->base.size, drm_format_plane_cpp(fb->pixel_format, 0))) { - if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL)) - DRM_DEBUG_KMS("framebuffer too large, disabling compression\n"); + set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL); goto out_disable; } -- cgit v1.3-6-gb490 From d8514d6306ea023f144ac922c4e6e6b283d5b78d Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Jun 2015 14:36:21 -0300 Subject: drm/i915: don't set the FBC plane select bits on HSW+ This commit is just to make the intentions explicit: on HSW+ these bits are MBZ, but since we only support plane A and the macro evaluates to zero when plane A is the parameter, we're not fixing any bug. v2: - Remove useless extra blank like (Chris). - Init dpfc_ctl in another place (Chris). Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 1ff288ce84d8..50ed3332def1 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -262,7 +262,10 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) dev_priv->fbc.enabled = true; - dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane); + dpfc_ctl = 0; + if (IS_IVYBRIDGE(dev)) + dpfc_ctl |= IVB_DPFC_CTL_PLANE(intel_crtc->plane); + if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) dev_priv->fbc.threshold++; -- cgit v1.3-6-gb490 From 0904deaf4e6bc1d854ed48255bdb170c7906c8fb Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Fri, 12 Jun 2015 10:11:32 +0300 Subject: drm/i915: Limit CHV max cdclk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Limit CHV maximum cdclk to 320MHz. v2: Rebase to the latest v3: Clean up of if-else tree Signed-off-by: Mika Kahola Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a806f1598a46..3f4891782cf6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5271,6 +5271,8 @@ static void intel_update_max_cdclk(struct drm_device *dev) dev_priv->max_cdclk_freq = 540000; else dev_priv->max_cdclk_freq = 675000; + } else if (IS_CHERRYVIEW(dev)) { + dev_priv->max_cdclk_freq = 320000; } else if (IS_VALLEYVIEW(dev)) { dev_priv->max_cdclk_freq = 400000; } else { -- cgit v1.3-6-gb490 From e7d66d89bc8bb44f9aab2f4749246214d15a159f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 15 Jun 2015 23:23:54 +0200 Subject: drm/i915: Remove more ilk rc6 remnants Leftover from the big purge commit a561165493e5fec2f74bd3ae0577ed659e44ab7f Author: John Harrison Date: Thu Mar 5 14:03:03 2015 +0000 drm/i915: Remove ironlake rc6 support Cc: John Harrison Cc: Rob Clark Reported-by: Rob Clark Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d091fec1e101..32ff034a0875 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4249,12 +4249,8 @@ static void intel_print_rc6_info(struct drm_device *dev, u32 mode) static int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6) { - /* No RC6 before Ironlake */ - if (INTEL_INFO(dev)->gen < 5) - return 0; - - /* RC6 is only on Ironlake mobile not on desktop */ - if (INTEL_INFO(dev)->gen == 5 && !IS_IRONLAKE_M(dev)) + /* No RC6 before Ironlake and code is gone for ilk. */ + if (INTEL_INFO(dev)->gen < 6) return 0; /* Respect the kernel parameter if it is set */ @@ -4274,10 +4270,6 @@ static int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6) return enable_rc6 & mask; } - /* Disable RC6 on Ironlake */ - if (INTEL_INFO(dev)->gen == 5) - return 0; - if (IS_IVYBRIDGE(dev)) return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE); -- cgit v1.3-6-gb490 From b27bc5a40f915671eda3ac255734a64153fc91f5 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 15 Jun 2015 14:46:40 +0300 Subject: ath10k: dump fw features during probing This should help when analysing problems from users and spot fw api blob problems easier. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 44 +++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/core.h | 3 +++ drivers/net/wireless/ath/ath10k/debug.c | 9 +++++-- 3 files changed, 54 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 59496a90ad5e..f5db43284b97 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -103,6 +103,50 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, }; +static const char *const ath10k_core_fw_feature_str[] = { + [ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX] = "wmi-mgmt-rx", + [ATH10K_FW_FEATURE_WMI_10X] = "wmi-10.x", + [ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX] = "has-wmi-mgmt-tx", + [ATH10K_FW_FEATURE_NO_P2P] = "no-p2p", + [ATH10K_FW_FEATURE_WMI_10_2] = "wmi-10.2", + [ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT] = "multi-vif-ps", + [ATH10K_FW_FEATURE_WOWLAN_SUPPORT] = "wowlan", + [ATH10K_FW_FEATURE_IGNORE_OTP_RESULT] = "ignore-otp", + [ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING] = "no-4addr-pad", + [ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init", +}; + +static unsigned int ath10k_core_get_fw_feature_str(char *buf, + size_t buf_len, + enum ath10k_fw_features feat) +{ + if (feat >= ARRAY_SIZE(ath10k_core_fw_feature_str) || + WARN_ON(!ath10k_core_fw_feature_str[feat])) { + return scnprintf(buf, buf_len, "bit%d", feat); + } + + return scnprintf(buf, buf_len, "%s", ath10k_core_fw_feature_str[feat]); +} + +void ath10k_core_get_fw_features_str(struct ath10k *ar, + char *buf, + size_t buf_len) +{ + unsigned int len = 0; + int i; + + for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) { + if (test_bit(i, ar->fw_features)) { + if (len > 0) + len += scnprintf(buf + len, buf_len - len, ","); + + len += ath10k_core_get_fw_feature_str(buf + len, + buf_len - len, + i); + } + } +} + static void ath10k_send_suspend_complete(struct ath10k *ar) { ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n"); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 78094f23c9dd..e9f93045fbd8 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -749,6 +749,9 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, enum ath10k_hw_rev hw_rev, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); +void ath10k_core_get_fw_features_str(struct ath10k *ar, + char *buf, + size_t max_len); int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode); int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 8fa606a9c4dd..8a4edfd36e47 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -124,7 +124,11 @@ EXPORT_SYMBOL(ath10k_info); void ath10k_print_driver_info(struct ath10k *ar) { - ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n", + char fw_features[128]; + + ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); + + ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d features %s\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -138,7 +142,8 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->htt.target_version_minor, ar->wmi.op_version, ath10k_cal_mode_str(ar->cal_mode), - ar->max_num_stations); + ar->max_num_stations, + fw_features); ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", config_enabled(CONFIG_ATH10K_DEBUG), config_enabled(CONFIG_ATH10K_DEBUGFS), -- cgit v1.3-6-gb490 From 67c81f5a06ed1474c4f16ad93f4502c760999515 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 15 Jun 2015 14:46:41 +0300 Subject: ath10k: print htt op_version upon driver boot HTT version itself isn't sufficient to know what HTT version given firmware blob uses. Hence print the recently introduced HTT op version code. While at it make the info string a bit more consistent and clear. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 8a4edfd36e47..edf6047997a7 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -128,7 +128,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); - ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d features %s\n", + ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d features %s\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -141,6 +141,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->htt.target_version_major, ar->htt.target_version_minor, ar->wmi.op_version, + ar->htt.op_version, ath10k_cal_mode_str(ar->cal_mode), ar->max_num_stations, fw_features); -- cgit v1.3-6-gb490 From c702534a23d61deaa0565ef0495ab866c06c4325 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Mon, 15 Jun 2015 14:46:41 +0300 Subject: ath10k: enable VHT for IBSS Enable VHT support for IBSS, while mac80211/cfg80211 and wpa_supplicant already support this. In my test env, qca988x 2x2 I get: (udp) ath10k-1 >>>> ath10k-2 (server) - speed: 419 Mbits/sec (tcp) ath10k-1 >>>> ath10k-2 (server) - speed: 404 Mbits/sec During tests I used wpa_supplicant (latest git version), which already support IBSS VHT, and choose highest available BW. Also tested with qca6174. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c48c744acbcc..c6255069e6e0 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6902,6 +6902,8 @@ int ath10k_mac_register(struct ath10k *ar) goto err_free; } + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + /* * on LL hardware queues are managed entirely by the FW * so we only advertise to mac we can do the queues thing -- cgit v1.3-6-gb490 From aeae5b4cd9185b0dc72f6d6102cf45073bfbc974 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 15 Jun 2015 14:46:42 +0300 Subject: ath10k: prevent debugfs mmio access crash kernel It was possible to force an out of bounds MMIO read/write via debugfs. E.g. on QCA988X this could be triggered with: echo 0x2080e0 | tee /sys/kernel/debug/ieee80211/*/ath10k/reg_addr cat /sys/kernel/debug/ieee80211/*/ath10k/reg_value BUG: unable to handle kernel paging request at ffffc90001e080e0 IP: [] ioread32+0x40/0x50 ... Call Trace: [] ? ath10k_pci_read32+0x4f/0x70 [ath10k_pci] [] ath10k_reg_value_read+0x90/0xf0 [ath10k_core] [] ? handle_mm_fault+0xa91/0x1050 [] __vfs_read+0x28/0xe0 [] ? security_file_permission+0x84/0xa0 [] ? rw_verify_area+0x53/0x100 [] vfs_read+0x8a/0x140 [] SyS_read+0x49/0xb0 [] ? trace_do_page_fault+0x3c/0xc0 [] system_call_fastpath+0x12/0x71 Reported-by: Ben Greear Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 13 +++++++++++++ drivers/net/wireless/ath/ath10k/pci.h | 1 + 2 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index ea656e011a96..41765172297c 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -479,6 +479,12 @@ void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; + if (unlikely(offset + sizeof(value) > ar_pci->mem_len)) { + ath10k_warn(ar, "refusing to write mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n", + offset, offset + sizeof(value), ar_pci->mem_len); + return; + } + ret = ath10k_pci_wake(ar); if (ret) { ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n", @@ -496,6 +502,12 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) u32 val; int ret; + if (unlikely(offset + sizeof(val) > ar_pci->mem_len)) { + ath10k_warn(ar, "refusing to read mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n", + offset, offset + sizeof(val), ar_pci->mem_len); + return 0; + } + ret = ath10k_pci_wake(ar); if (ret) { ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n", @@ -2679,6 +2691,7 @@ static int ath10k_pci_claim(struct ath10k *ar) pci_set_master(pdev); /* Arrange for access to Target SoC registers. */ + ar_pci->mem_len = pci_resource_len(pdev, BAR_NUM); ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0); if (!ar_pci->mem) { ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index d7696ddc03c4..eea0a0170b00 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -162,6 +162,7 @@ struct ath10k_pci { struct device *dev; struct ath10k *ar; void __iomem *mem; + size_t mem_len; /* * Number of MSI interrupts granted, 0 --> using legacy PCI line -- cgit v1.3-6-gb490 From 404d67ef2935c5e41d3d7a403c5fb1c278eff60e Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 15 Jun 2015 14:46:42 +0300 Subject: ath10k: remove unused variable hdr in ath10k_htt_rx_h_undecap() Just found this during code review. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 89eb16b30fc4..7399e45a016e 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1201,7 +1201,6 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar, { struct htt_rx_desc *rxd; enum rx_msdu_decap_format decap; - struct ieee80211_hdr *hdr; /* First msdu's decapped header: * [802.11 header] <-- padded to 4 bytes long @@ -1215,7 +1214,6 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar, */ rxd = (void *)msdu->data - sizeof(*rxd); - hdr = (void *)rxd->rx_hdr_status; decap = MS(__le32_to_cpu(rxd->msdu_start.info1), RX_MSDU_START_INFO1_DECAP_FORMAT); -- cgit v1.3-6-gb490 From d4298a3a8c92a18d375e55feecc60e4eefeb45e3 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 15 Jun 2015 14:46:43 +0300 Subject: ath10k: mac: remove unreachable negative return check wait_event_timeout(), introduced in 'commit 5e3dd157d7e7 ("ath10k: mac80211 driver for Qualcomm Atheros 802.11ac CQA98xx devices")' never returns < 0 so the only failure condition to be checked is ==0 (timeout). Further the return type is long not int - an appropriately named variable is added and the assignments fixed up. Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c6255069e6e0..e17eb75c508e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5566,7 +5566,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct ath10k *ar = hw->priv; bool skip; - int ret; + long time_left; /* mac80211 doesn't care if we really xmit queued frames or not * we'll collect those frames either way if we stop/delete vdevs */ @@ -5578,7 +5578,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (ar->state == ATH10K_STATE_WEDGED) goto skip; - ret = wait_event_timeout(ar->htt.empty_tx_wq, ({ + time_left = wait_event_timeout(ar->htt.empty_tx_wq, ({ bool empty; spin_lock_bh(&ar->htt.tx_lock); @@ -5592,9 +5592,9 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, (empty || skip); }), ATH10K_FLUSH_TIMEOUT_HZ); - if (ret <= 0 || skip) - ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n", - skip, ar->state, ret); + if (time_left == 0 || skip) + ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %ld\n", + skip, ar->state, time_left); skip: mutex_unlock(&ar->conf_mutex); -- cgit v1.3-6-gb490 From 71c47df4aa54ee3bfb113a5ae468c8bfb3a6fb7b Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 15 Jun 2015 14:46:43 +0300 Subject: ath10k: txrx: remove unreachable negative return check and fixup type wait_event_timeout(), introduced in 'commit 5e3dd157d7e7 ("ath10k: mac80211 driver for Qualcomm Atheros 802.11ac CQA98xx devices")' never returns < 0 so the only failure condition to be checked is == 0 (timeout). Further the return type is long not int - an appropriately named variable is added and the assignments fixed up. Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/txrx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 826500bb2b1b..6cf289158840 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -147,9 +147,9 @@ struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id) static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, const u8 *addr, bool expect_mapped) { - int ret; + long time_left; - ret = wait_event_timeout(ar->peer_mapping_wq, ({ + time_left = wait_event_timeout(ar->peer_mapping_wq, ({ bool mapped; spin_lock_bh(&ar->data_lock); @@ -160,7 +160,7 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)); }), 3*HZ); - if (ret <= 0) + if (time_left == 0) return -ETIMEDOUT; return 0; -- cgit v1.3-6-gb490 From ce52299ca6ac23222e040284913d1271edc96459 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 5 Jun 2015 15:08:24 -0700 Subject: drm/i915: Use helper to set CRTC state's mode We need to call drm_atomic_set_mode_for_crtc() rather than copying the mode in manually. As of commit commit 99cf4a29fa24461bbfe22125967188a18383eb5c Author: Daniel Stone Date: Mon May 25 19:11:51 2015 +0100 drm/atomic: Add current-mode blob to CRTC state the helper now also takes care of setting up the mode property blob for us; if we don't use the helper and never setup the mode blob, this will also trigger a failure in drm_atomic_crtc_check() when we have the DRIVER_ATOMIC flag set (i.e., when using the nuclear pageflip support via i915.nuclear_pageflip kernel command line parameter). Cc: Maarten Lankhorst Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3f4891782cf6..98bb15ac4c66 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13264,8 +13264,9 @@ intel_modeset_stage_output_state(struct drm_device *dev, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (set->mode) - drm_mode_copy(&crtc_state->mode, set->mode); + ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); + if (ret) + return ret; if (set->num_connectors) crtc_state->active = true; -- cgit v1.3-6-gb490 From b0a08bec96318be54db97c3f0b9e37b52561f9ea Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Thu, 18 Jun 2015 11:00:55 +0530 Subject: drm/i915/bxt: eDP Panel Power sequencing Changes for BXT - added a IS_BROXTON check to use the macro related to PPS registers for BXT. BXT does not have PP_DIV register. Making changes to handle this. Second set of PPS registers have been defined but will be used when VBT provides a selection between the 2 sets of registers. v2: [Jani] Added 2nd set of PPS registers and the macro Jani's review comments - remove reference in i915_suspend.c - Use BXT PP macro Squashing all PPS related patches into one. v3: Jani's review comments addressed - Use pp_ctl instead of pp - ironlake_get_pp_control() is not required for BXT - correct the use of && in the print statement - drop the shift in the print statement v4: Jani's comments - modify ironlake_get_pp_control() - dont set unlock key for bxt v5: Sonika's comments addressed - check alignment - move pp_ctrl_reg write (after ironlake_get_pp_control()) to !IS_BROXTON case. - check before subtracting 1 for t11_t12 Signed-off-by: Vandana Kannan Signed-off-by: A.Sunil Kamath Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 13 +++++++ drivers/gpu/drm/i915/intel_dp.c | 82 ++++++++++++++++++++++++++++++++--------- 2 files changed, 78 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2261609d1d75..c154a7b732cd 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6391,6 +6391,8 @@ enum skl_disp_power_wells { #define PCH_PP_CONTROL 0xc7204 #define PANEL_UNLOCK_REGS (0xabcd << 16) #define PANEL_UNLOCK_MASK (0xffff << 16) +#define BXT_POWER_CYCLE_DELAY_MASK (0x1f0) +#define BXT_POWER_CYCLE_DELAY_SHIFT 4 #define EDP_FORCE_VDD (1 << 3) #define EDP_BLC_ENABLE (1 << 2) #define PANEL_POWER_RESET (1 << 1) @@ -6419,6 +6421,17 @@ enum skl_disp_power_wells { #define PANEL_POWER_CYCLE_DELAY_MASK (0x1f) #define PANEL_POWER_CYCLE_DELAY_SHIFT 0 +/* BXT PPS changes - 2nd set of PPS registers */ +#define _BXT_PP_STATUS2 0xc7300 +#define _BXT_PP_CONTROL2 0xc7304 +#define _BXT_PP_ON_DELAYS2 0xc7308 +#define _BXT_PP_OFF_DELAYS2 0xc730c + +#define BXT_PP_STATUS(n) ((!n) ? PCH_PP_STATUS : _BXT_PP_STATUS2) +#define BXT_PP_CONTROL(n) ((!n) ? PCH_PP_CONTROL : _BXT_PP_CONTROL2) +#define BXT_PP_ON_DELAYS(n) ((!n) ? PCH_PP_ON_DELAYS : _BXT_PP_ON_DELAYS2) +#define BXT_PP_OFF_DELAYS(n) ((!n) ? PCH_PP_OFF_DELAYS : _BXT_PP_OFF_DELAYS2) + #define PCH_DP_B 0xe4100 #define PCH_DPB_AUX_CH_CTL 0xe4110 #define PCH_DPB_AUX_CH_DATA1 0xe4114 diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f9e4fa842450..2e6f23890dbf 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -567,7 +567,9 @@ static u32 _pp_ctrl_reg(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); - if (HAS_PCH_SPLIT(dev)) + if (IS_BROXTON(dev)) + return BXT_PP_CONTROL(0); + else if (HAS_PCH_SPLIT(dev)) return PCH_PP_CONTROL; else return VLV_PIPE_PP_CONTROL(vlv_power_sequencer_pipe(intel_dp)); @@ -577,7 +579,9 @@ static u32 _pp_stat_reg(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); - if (HAS_PCH_SPLIT(dev)) + if (IS_BROXTON(dev)) + return BXT_PP_STATUS(0); + else if (HAS_PCH_SPLIT(dev)) return PCH_PP_STATUS; else return VLV_PIPE_PP_STATUS(vlv_power_sequencer_pipe(intel_dp)); @@ -1703,8 +1707,10 @@ static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) lockdep_assert_held(&dev_priv->pps_mutex); control = I915_READ(_pp_ctrl_reg(intel_dp)); - control &= ~PANEL_UNLOCK_MASK; - control |= PANEL_UNLOCK_REGS; + if (!IS_BROXTON(dev)) { + control &= ~PANEL_UNLOCK_MASK; + control |= PANEL_UNLOCK_REGS; + } return control; } @@ -5093,8 +5099,8 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct edp_power_seq cur, vbt, spec, *final = &intel_dp->pps_delays; - u32 pp_on, pp_off, pp_div, pp; - int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg; + u32 pp_on, pp_off, pp_div = 0, pp_ctl = 0; + int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg = 0; lockdep_assert_held(&dev_priv->pps_mutex); @@ -5102,7 +5108,16 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, if (final->t11_t12 != 0) return; - if (HAS_PCH_SPLIT(dev)) { + if (IS_BROXTON(dev)) { + /* + * TODO: BXT has 2 sets of PPS registers. + * Correct Register for Broxton need to be identified + * using VBT. hardcoding for now + */ + pp_ctrl_reg = BXT_PP_CONTROL(0); + pp_on_reg = BXT_PP_ON_DELAYS(0); + pp_off_reg = BXT_PP_OFF_DELAYS(0); + } else if (HAS_PCH_SPLIT(dev)) { pp_ctrl_reg = PCH_PP_CONTROL; pp_on_reg = PCH_PP_ON_DELAYS; pp_off_reg = PCH_PP_OFF_DELAYS; @@ -5118,12 +5133,14 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, /* Workaround: Need to write PP_CONTROL with the unlock key as * the very first thing. */ - pp = ironlake_get_pp_control(intel_dp); - I915_WRITE(pp_ctrl_reg, pp); + pp_ctl = ironlake_get_pp_control(intel_dp); pp_on = I915_READ(pp_on_reg); pp_off = I915_READ(pp_off_reg); - pp_div = I915_READ(pp_div_reg); + if (!IS_BROXTON(dev)) { + I915_WRITE(pp_ctrl_reg, pp_ctl); + pp_div = I915_READ(pp_div_reg); + } /* Pull timing values out of registers */ cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> @@ -5138,8 +5155,17 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, cur.t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >> PANEL_POWER_DOWN_DELAY_SHIFT; - cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >> + if (IS_BROXTON(dev)) { + u16 tmp = (pp_ctl & BXT_POWER_CYCLE_DELAY_MASK) >> + BXT_POWER_CYCLE_DELAY_SHIFT; + if (tmp > 0) + cur.t11_t12 = (tmp - 1) * 1000; + else + cur.t11_t12 = 0; + } else { + cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >> PANEL_POWER_CYCLE_DELAY_SHIFT) * 1000; + } DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12); @@ -5196,13 +5222,23 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; u32 pp_on, pp_off, pp_div, port_sel = 0; int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev); - int pp_on_reg, pp_off_reg, pp_div_reg; + int pp_on_reg, pp_off_reg, pp_div_reg = 0, pp_ctrl_reg; enum port port = dp_to_dig_port(intel_dp)->port; const struct edp_power_seq *seq = &intel_dp->pps_delays; lockdep_assert_held(&dev_priv->pps_mutex); - if (HAS_PCH_SPLIT(dev)) { + if (IS_BROXTON(dev)) { + /* + * TODO: BXT has 2 sets of PPS registers. + * Correct Register for Broxton need to be identified + * using VBT. hardcoding for now + */ + pp_ctrl_reg = BXT_PP_CONTROL(0); + pp_on_reg = BXT_PP_ON_DELAYS(0); + pp_off_reg = BXT_PP_OFF_DELAYS(0); + + } else if (HAS_PCH_SPLIT(dev)) { pp_on_reg = PCH_PP_ON_DELAYS; pp_off_reg = PCH_PP_OFF_DELAYS; pp_div_reg = PCH_PP_DIVISOR; @@ -5228,9 +5264,16 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT); /* Compute the divisor for the pp clock, simply match the Bspec * formula. */ - pp_div = ((100 * div)/2 - 1) << PP_REFERENCE_DIVIDER_SHIFT; - pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000) - << PANEL_POWER_CYCLE_DELAY_SHIFT); + if (IS_BROXTON(dev)) { + pp_div = I915_READ(pp_ctrl_reg); + pp_div &= ~BXT_POWER_CYCLE_DELAY_MASK; + pp_div |= (DIV_ROUND_UP((seq->t11_t12 + 1), 1000) + << BXT_POWER_CYCLE_DELAY_SHIFT); + } else { + pp_div = ((100 * div)/2 - 1) << PP_REFERENCE_DIVIDER_SHIFT; + pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000) + << PANEL_POWER_CYCLE_DELAY_SHIFT); + } /* Haswell doesn't have any port selection bits for the panel * power sequencer any more. */ @@ -5247,11 +5290,16 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, I915_WRITE(pp_on_reg, pp_on); I915_WRITE(pp_off_reg, pp_off); - I915_WRITE(pp_div_reg, pp_div); + if (IS_BROXTON(dev)) + I915_WRITE(pp_ctrl_reg, pp_div); + else + I915_WRITE(pp_div_reg, pp_div); DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n", I915_READ(pp_on_reg), I915_READ(pp_off_reg), + IS_BROXTON(dev) ? + (I915_READ(pp_ctrl_reg) & BXT_POWER_CYCLE_DELAY_MASK) : I915_READ(pp_div_reg)); } -- cgit v1.3-6-gb490 From 7fd2d26921d1dd70732d8765d714ec3a023a3ca9 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 18 Jun 2015 12:51:40 +0300 Subject: drm/i915: Reset request handling for gen8+ In order for gen8+ hardware to guarantee that no context switch takes place during engine reset and that current context is properly saved, the driver needs to notify and query hw before commencing with reset. There are gpu hangs where the engine gets so stuck that it never will report to be ready for reset. We could proceed with reset anyway, but with some hangs with skl, the forced gpu reset will result in a system hang. By inspecting the unreadiness for reset seems to correlate with the probable system hang. We will only proceed with reset if all engines report that they are ready for reset. If root cause for system hang is found and can be worked around with another means, we can reconsider if we can reinstate full reset for unreadiness case. v2: -EIO, Recovery, gen8 (Chris, Tomas, Daniel) v3: updated commit msg v4: timeout_ms, simpler error path (Chris) References: https://bugs.freedesktop.org/show_bug.cgi?id=89959 References: https://bugs.freedesktop.org/show_bug.cgi?id=90854 Testcase: igt/gem_concurrent_blit/prw-blt-overwrite-source-read-rcs-forked Testcase: igt/gem_concurrent_blit/gtt-blt-overwrite-source-read-rcs-forked Cc: Chris Wilson Cc: Daniel Vetter Cc: Tomas Elf Reviewed-by: Chris Wilson Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_uncore.c | 43 ++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c154a7b732cd..64caa470f2c6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1461,6 +1461,9 @@ enum skl_disp_power_wells { #define RING_MAX_IDLE(base) ((base)+0x54) #define RING_HWS_PGA(base) ((base)+0x80) #define RING_HWS_PGA_GEN6(base) ((base)+0x2080) +#define RING_RESET_CTL(base) ((base)+0xd0) +#define RESET_CTL_REQUEST_RESET (1 << 0) +#define RESET_CTL_READY_TO_RESET (1 << 1) #define HSW_GTT_CACHE_EN 0x4024 #define GTT_CACHE_EN_ALL 0xF0007FFF diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 4a86cf007aa0..160a47a9bdd9 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1455,9 +1455,50 @@ static int gen6_do_reset(struct drm_device *dev) return ret; } +static int wait_for_register(struct drm_i915_private *dev_priv, + const u32 reg, + const u32 mask, + const u32 value, + const unsigned long timeout_ms) +{ + return wait_for((I915_READ(reg) & mask) == value, timeout_ms); +} + +static int gen8_do_reset(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_engine_cs *engine; + int i; + + for_each_ring(engine, dev_priv, i) { + I915_WRITE(RING_RESET_CTL(engine->mmio_base), + _MASKED_BIT_ENABLE(RESET_CTL_REQUEST_RESET)); + + if (wait_for_register(dev_priv, + RING_RESET_CTL(engine->mmio_base), + RESET_CTL_READY_TO_RESET, + RESET_CTL_READY_TO_RESET, + 700)) { + DRM_ERROR("%s: reset request timeout\n", engine->name); + goto not_ready; + } + } + + return gen6_do_reset(dev); + +not_ready: + for_each_ring(engine, dev_priv, i) + I915_WRITE(RING_RESET_CTL(engine->mmio_base), + _MASKED_BIT_DISABLE(RESET_CTL_REQUEST_RESET)); + + return -EIO; +} + static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *) { - if (INTEL_INFO(dev)->gen >= 6) + if (INTEL_INFO(dev)->gen >= 8) + return gen8_do_reset; + else if (INTEL_INFO(dev)->gen >= 6) return gen6_do_reset; else if (IS_GEN5(dev)) return ironlake_do_reset; -- cgit v1.3-6-gb490 From fbb35c1981012c72adff8f09f09005a8900a6dfd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Jun 2015 21:17:42 +0200 Subject: drm/i915: Update DRIVER_DATE to 20150619 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 491ef0cfcb0b..290017857c6d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -56,7 +56,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20150522" +#define DRIVER_DATE "20150619" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ -- cgit v1.3-6-gb490 From 4b8d80157e5d9074c5eac12aff8dad1742b52f1c Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 20 Jun 2015 23:52:30 +0200 Subject: iio: Add missing modifier names to core some are documented, others are in iio_event_monitor.c which was recently moved from staging Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 3524b0de8721..d8051cdcbdc2 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -81,6 +81,14 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_X] = "x", [IIO_MOD_Y] = "y", [IIO_MOD_Z] = "z", + [IIO_MOD_X_AND_Y] = "x&y", + [IIO_MOD_X_AND_Z] = "x&z", + [IIO_MOD_Y_AND_Z] = "y&z", + [IIO_MOD_X_AND_Y_AND_Z] = "x&y&z", + [IIO_MOD_X_OR_Y] = "x|y", + [IIO_MOD_X_OR_Z] = "x|z", + [IIO_MOD_Y_OR_Z] = "y|z", + [IIO_MOD_X_OR_Y_OR_Z] = "x|y|z", [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)", [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2", [IIO_MOD_LIGHT_BOTH] = "both", -- cgit v1.3-6-gb490 From 208335138001015fd7c5c986b39e05fffad1c528 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 20 Jun 2015 23:51:38 +0200 Subject: iio: light: isl29125: Add scale_available information Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/iio/light/isl29125.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index c82f4a6f8464..b3cbbe830141 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -197,9 +197,21 @@ done: return IRQ_HANDLED; } +static IIO_CONST_ATTR(scale_available, "0.005722 0.152590"); + +static struct attribute *isl29125_attributes[] = { + &iio_const_attr_scale_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group isl29125_attribute_group = { + .attrs = isl29125_attributes, +}; + static const struct iio_info isl29125_info = { .read_raw = isl29125_read_raw, .write_raw = isl29125_write_raw, + .attrs = &isl29125_attribute_group, .driver_module = THIS_MODULE, }; -- cgit v1.3-6-gb490 From db42a9be9f05516255e749a5ee4c1e5d07e0a73b Mon Sep 17 00:00:00 2001 From: Tiberiu Breana Date: Fri, 19 Jun 2015 17:56:37 +0300 Subject: iio: accel: STK8BA50: suspend sensor on init errors Put chip in 'suspend' mode in case something goes wrong during probe. Signed-off-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8ba50.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 92229bd8c82d..9836880cc2d1 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -265,7 +265,7 @@ static int stk8ba50_probe(struct i2c_client *client, STK8BA50_REG_SWRST, STK8BA50_RESET_CMD); if (ret < 0) { dev_err(&client->dev, "failed to reset sensor\n"); - return ret; + goto err_power_off; } /* The default range is +/-2g */ @@ -277,10 +277,14 @@ static int stk8ba50_probe(struct i2c_client *client, ret = iio_device_register(indio_dev); if (ret < 0) { dev_err(&client->dev, "device_register failed\n"); - stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND); + goto err_power_off; } return ret; + +err_power_off: + stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND); + return ret; } static int stk8ba50_remove(struct i2c_client *client) -- cgit v1.3-6-gb490 From 39b441bd30a9eff4b3d2cc039027037403ca5242 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Thu, 18 Jun 2015 00:32:00 +0200 Subject: iio:light:Kconfig: fix typo in description Fix the typo in the module description for the CM3323. Signed-off-by: Hartmut Knaack Reviewed-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index e6198b7c9cbf..554f8ee6d64a 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -86,7 +86,7 @@ config CM3323 depends on I2C tristate "Capella CM3323 color light sensor" help - Say Y here if you want to build a driver for Capela CM3323 + Say Y here if you want to build a driver for Capella CM3323 color sensor. To compile this driver as a module, choose M here: the module will -- cgit v1.3-6-gb490 From e5c97027449f235415990310e47071ec371fd46c Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Thu, 18 Jun 2015 00:32:01 +0200 Subject: iio:light:cm3323: pass up error value cm3323_get_it_bits() returns a valid error code, so pass it up in cm3323_read_raw(). Signed-off-by: Hartmut Knaack Reviewed-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/cm3323.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index 869033e48a1f..9c9136309ffe 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -175,7 +175,7 @@ static int cm3323_read_raw(struct iio_dev *indio_dev, i = cm3323_get_it_bits(data); if (i < 0) { mutex_unlock(&data->mutex); - return -EINVAL; + return i; } *val = cm3323_int_time[i].val; -- cgit v1.3-6-gb490 From 0ff8c78df8d7c32394b887de4d935962a7f373ce Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Thu, 18 Jun 2015 00:32:03 +0200 Subject: iio:light:cm3323: replace unneeded variable In cm3323_read_raw() i is used as return variable for the integration time index. The also existing return variable ret however is unused in this case, although appropriate. Replace i with ret and drop it. Signed-off-by: Hartmut Knaack Reviewed-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/cm3323.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index 9c9136309ffe..af1b1b025258 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -155,7 +155,7 @@ static int cm3323_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - int i, ret; + int ret; struct cm3323_data *data = iio_priv(indio_dev); switch (mask) { @@ -172,14 +172,14 @@ static int cm3323_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_INT_TIME: mutex_lock(&data->mutex); - i = cm3323_get_it_bits(data); - if (i < 0) { + ret = cm3323_get_it_bits(data); + if (ret < 0) { mutex_unlock(&data->mutex); - return i; + return ret; } - *val = cm3323_int_time[i].val; - *val2 = cm3323_int_time[i].val2; + *val = cm3323_int_time[ret].val; + *val2 = cm3323_int_time[ret].val2; mutex_unlock(&data->mutex); return IIO_VAL_INT_PLUS_MICRO; -- cgit v1.3-6-gb490 From 054101c186b9e41d2b57543070c4a520d38402da Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Thu, 18 Jun 2015 00:32:04 +0200 Subject: iio:light:cm3323: make use of GENMASK Use GENMASK to define the integration time bitmask. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/light/cm3323.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index af1b1b025258..57ff0a10890e 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -29,7 +29,7 @@ #define CM3323_CONF_SD_BIT BIT(0) /* sensor disable */ #define CM3323_CONF_AF_BIT BIT(1) /* auto/manual force mode */ -#define CM3323_CONF_IT_MASK (BIT(4) | BIT(5) | BIT(6)) +#define CM3323_CONF_IT_MASK GENMASK(6, 4) #define CM3323_CONF_IT_SHIFT 4 #define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28" -- cgit v1.3-6-gb490 From 8bf62ec83c89eda4114aae90c593f49649af76bd Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Thu, 18 Jun 2015 00:32:05 +0200 Subject: iio:light:cm3323: add empty lines for code structure Add some empty lines to visually separate logical structure blocks, as after if-blocks or before regular returns. Signed-off-by: Hartmut Knaack Reviewed-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/cm3323.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c index 57ff0a10890e..54c9e2df43f2 100644 --- a/drivers/iio/light/cm3323.c +++ b/drivers/iio/light/cm3323.c @@ -133,9 +133,11 @@ static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2) return ret; data->reg_conf = reg_conf; + return 0; } } + return -EINVAL; } @@ -148,6 +150,7 @@ static int cm3323_get_it_bits(struct cm3323_data *data) if (bits >= ARRAY_SIZE(cm3323_int_time)) return -EINVAL; + return bits; } @@ -243,11 +246,13 @@ static int cm3323_probe(struct i2c_client *client, dev_err(&client->dev, "cm3323 chip init failed\n"); return ret; } + ret = iio_device_register(indio_dev); if (ret < 0) { dev_err(&client->dev, "failed to register iio dev\n"); goto err_init; } + return 0; err_init: cm3323_disable(indio_dev); -- cgit v1.3-6-gb490 From 825c50dba0139b0322436ddda7d11f043955875e Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 16 Jun 2015 21:27:03 +0200 Subject: iio: pressure: Fix Measurement Specialties vendor name Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index fa6295041947..b13ea6fd939d 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -53,9 +53,9 @@ config MPL3115 will be called mpl3115. config MS5611 - tristate "Measurement Specialities MS5611 pressure sensor driver" + tristate "Measurement Specialties MS5611 pressure sensor driver" help - Say Y here to build support for the Measurement Specialities + Say Y here to build support for the Measurement Specialties MS5611 pressure and temperature sensor. To compile this driver as a module, choose M here: the module will -- cgit v1.3-6-gb490 From fdd15f6594f6bc466a01da28ddd2f11bb0e47a9f Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Mon, 15 Jun 2015 23:48:25 +0200 Subject: iio:accel:bmc150-accel: make use of mask definition BMC150_ACCEL_SLOPE_THRES_MASK was defined some time ago, but its 'magic' value got used instead in bmc150_accel_write_event(). Make use of it for improved readability. Signed-off-by: Hartmut Knaack Reviewed-by: Octavian Purdila Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 4e70f51c2370..b812728b438e 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -776,7 +776,7 @@ static int bmc150_accel_write_event(struct iio_dev *indio_dev, switch (info) { case IIO_EV_INFO_VALUE: - data->slope_thres = val & 0xFF; + data->slope_thres = val & BMC150_ACCEL_SLOPE_THRES_MASK; break; case IIO_EV_INFO_PERIOD: data->slope_dur = val & BMC150_ACCEL_SLOPE_DUR_MASK; -- cgit v1.3-6-gb490 From e20008ed931b9bdd90d1a3fd8c9ef9307547f4ed Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Mon, 15 Jun 2015 23:48:26 +0200 Subject: iio:accel:bmc150-accel: code style cleanup Apply the following coding style changes as indicated by checkpatch.pl in strict mode: - Please don't use multiple blank lines - braces {} should be used on all arms of this statement (if/else) - Alignment should match open parenthesis - Please don't use multiple blank lines - Blank lines aren't necessary after an open brace '{' - Missing a blank line after declarations - No space is necessary after a cast Also wrap/consolidate error messages to fit 80 characters per line and rework a comment. Signed-off-by: Hartmut Knaack Reviewed-by: Octavian Purdila Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 91 +++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index b812728b438e..47c6013ab376 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -241,7 +241,6 @@ static const struct { {500000, BMC150_ACCEL_SLEEP_500_MS}, {1000000, BMC150_ACCEL_SLEEP_1_SEC} }; - static int bmc150_accel_set_mode(struct bmc150_accel_data *data, enum bmc150_power_modes mode, int dur_us) @@ -259,8 +258,9 @@ static int bmc150_accel_set_mode(struct bmc150_accel_data *data, dur_val = bmc150_accel_sleep_value_table[i].reg_value; } - } else + } else { dur_val = 0; + } if (dur_val < 0) return -EINVAL; @@ -288,7 +288,7 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val, for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { if (bmc150_accel_samp_freq_table[i].val == val && - bmc150_accel_samp_freq_table[i].val2 == val2) { + bmc150_accel_samp_freq_table[i].val2 == val2) { ret = i2c_smbus_write_byte_data( data->client, BMC150_ACCEL_REG_PMU_BW, @@ -351,8 +351,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); if (ret < 0) { - dev_err(&data->client->dev, - "Error: Reading chip id\n"); + dev_err(&data->client->dev, "Error: Reading chip id\n"); return ret; } @@ -376,8 +375,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) BMC150_ACCEL_REG_PMU_RANGE, BMC150_ACCEL_DEF_RANGE_4G); if (ret < 0) { - dev_err(&data->client->dev, - "Error writing reg_pmu_range\n"); + dev_err(&data->client->dev, "Error writing reg_pmu_range\n"); return ret; } @@ -437,12 +435,13 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) { int ret; - if (on) + if (on) { ret = pm_runtime_get_sync(&data->client->dev); - else { + } else { pm_runtime_mark_last_busy(&data->client->dev); ret = pm_runtime_put_autosuspend(&data->client->dev); } + if (ret < 0) { dev_err(&data->client->dev, "Failed: bmc150_accel_set_power_state for %d\n", on); @@ -514,13 +513,13 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i, } /* - * We will expect the enable and disable to do operation in - * in reverse order. This will happen here anyway as our - * resume operation uses sync mode runtime pm calls, the - * suspend operation will be delayed by autosuspend delay - * So the disable operation will still happen in reverse of - * enable operation. When runtime pm is disabled the mode - * is always on so sequence doesn't matter + * We will expect the enable and disable to do operation in reverse + * order. This will happen here anyway, as our resume operation uses + * sync mode runtime pm calls. The suspend operation will be delayed + * by autosuspend delay. + * So the disable operation will still happen in reverse order of + * enable operation. When runtime pm is disabled the mode is always on, + * so sequence doesn't matter. */ ret = bmc150_accel_set_power_state(data, state); if (ret < 0) @@ -574,7 +573,6 @@ out_fix_power_state: return ret; } - static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) { int ret, i; @@ -674,8 +672,9 @@ static int bmc150_accel_read_raw(struct iio_dev *indio_dev, if (chan->type == IIO_TEMP) { *val = BMC150_ACCEL_TEMP_CENTER_VAL; return IIO_VAL_INT; - } else + } else { return -EINVAL; + } case IIO_CHAN_INFO_SCALE: *val = 0; switch (chan->type) { @@ -793,7 +792,6 @@ static int bmc150_accel_read_event_config(struct iio_dev *indio_dev, enum iio_event_type type, enum iio_event_direction dir) { - struct bmc150_accel_data *data = iio_priv(indio_dev); return data->ev_enable_state; @@ -827,7 +825,7 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev, } static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev, - struct iio_trigger *trig) + struct iio_trigger *trig) { struct bmc150_accel_data *data = iio_priv(indio_dev); int i; @@ -963,6 +961,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3]; int64_t tstamp; uint64_t sample_period; + ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_FIFO_STATUS); if (ret < 0) { @@ -1255,7 +1254,7 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig) } static int bmc150_accel_trigger_set_state(struct iio_trigger *trig, - bool state) + bool state) { struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig); struct bmc150_accel_data *data = t->data; @@ -1314,26 +1313,32 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev) dir = IIO_EV_DIR_RISING; if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X) - iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_X, - IIO_EV_TYPE_ROC, - dir), - data->timestamp); + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X, + IIO_EV_TYPE_ROC, + dir), + data->timestamp); + if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y) - iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Y, - IIO_EV_TYPE_ROC, - dir), - data->timestamp); + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Y, + IIO_EV_TYPE_ROC, + dir), + data->timestamp); + if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z) - iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Z, - IIO_EV_TYPE_ROC, - dir), - data->timestamp); + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Z, + IIO_EV_TYPE_ROC, + dir), + data->timestamp); + return ret; } @@ -1365,7 +1370,9 @@ static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private) BMC150_ACCEL_INT_MODE_LATCH_INT | BMC150_ACCEL_INT_MODE_LATCH_RESET); if (ret) - dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n"); + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + ret = IRQ_HANDLED; } else { ret = IRQ_NONE; @@ -1412,13 +1419,13 @@ static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data) if (!id) return NULL; - *data = (int) id->driver_data; + *data = (int)id->driver_data; return dev_name(dev); } static int bmc150_accel_gpio_probe(struct i2c_client *client, - struct bmc150_accel_data *data) + struct bmc150_accel_data *data) { struct device *dev; struct gpio_desc *gpio; -- cgit v1.3-6-gb490 From c6f67a1f55a7f8a8373068ca07553bd2b2731949 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 5 Jun 2015 15:56:47 +0300 Subject: iio: allow userspace to flush the hwfifo with non-blocking reads This patch changes the semantics of non-blocking reads so that a hardware fifo flush is triggered if the available data in the device buffer is less then the requested size. This allows userspace to accurately generate hardware fifo flushes, by doing a non-blocking read with a size greater then the sum of the device buffer and hardware fifo size. Signed-off-by: Octavian Purdila Reviewed-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 6eee1b044c60..f72be48e650c 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -71,8 +71,9 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, if (avail >= to_wait) { /* force a flush for non-blocking reads */ - if (!to_wait && !avail && to_flush) - iio_buffer_flush_hwfifo(indio_dev, buf, to_flush); + if (!to_wait && avail < to_flush) + iio_buffer_flush_hwfifo(indio_dev, buf, + to_flush - avail); return true; } @@ -100,8 +101,7 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, struct iio_dev *indio_dev = filp->private_data; struct iio_buffer *rb = indio_dev->buffer; size_t datum_size; - size_t to_wait = 0; - size_t to_read; + size_t to_wait; int ret; if (!indio_dev->info) @@ -119,14 +119,14 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, if (!datum_size) return 0; - to_read = min_t(size_t, n / datum_size, rb->watermark); - - if (!(filp->f_flags & O_NONBLOCK)) - to_wait = to_read; + if (filp->f_flags & O_NONBLOCK) + to_wait = 0; + else + to_wait = min_t(size_t, n / datum_size, rb->watermark); do { ret = wait_event_interruptible(rb->pollq, - iio_buffer_ready(indio_dev, rb, to_wait, to_read)); + iio_buffer_ready(indio_dev, rb, to_wait, n / datum_size)); if (ret) return ret; -- cgit v1.3-6-gb490 From 9d174b49ce05b63763e76f9f4373bc1b213ff584 Mon Sep 17 00:00:00 2001 From: Vlad Dogaru Date: Fri, 12 Jun 2015 11:31:38 +0300 Subject: iio: magn: bmc150: decouple buffer and trigger Signed-off-by: Vlad Dogaru Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 69 +++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index d4c178869991..a0e64f19f4c4 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -588,17 +588,6 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev, } } -static int bmc150_magn_validate_trigger(struct iio_dev *indio_dev, - struct iio_trigger *trig) -{ - struct bmc150_magn_data *data = iio_priv(indio_dev); - - if (data->dready_trig != trig) - return -EINVAL; - - return 0; -} - static ssize_t bmc150_magn_show_samp_freq_avail(struct device *dev, struct device_attribute *attr, char *buf) @@ -659,7 +648,6 @@ static const struct iio_info bmc150_magn_info = { .attrs = &bmc150_magn_attrs_group, .read_raw = bmc150_magn_read_raw, .write_raw = bmc150_magn_write_raw, - .validate_trigger = bmc150_magn_validate_trigger, .driver_module = THIS_MODULE, }; @@ -682,7 +670,7 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) pf->timestamp); err: - iio_trigger_notify_done(data->dready_trig); + iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; } @@ -827,6 +815,27 @@ static const struct iio_trigger_ops bmc150_magn_trigger_ops = { .owner = THIS_MODULE, }; +static int bmc150_magn_buffer_preenable(struct iio_dev *indio_dev) +{ + struct bmc150_magn_data *data = iio_priv(indio_dev); + + return bmc150_magn_set_power_state(data, true); +} + +static int bmc150_magn_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct bmc150_magn_data *data = iio_priv(indio_dev); + + return bmc150_magn_set_power_state(data, false); +} + +static const struct iio_buffer_setup_ops bmc150_magn_buffer_setup_ops = { + .preenable = bmc150_magn_buffer_preenable, + .postenable = iio_triggered_buffer_postenable, + .predisable = iio_triggered_buffer_predisable, + .postdisable = bmc150_magn_buffer_postdisable, +}; + static int bmc150_magn_gpio_probe(struct i2c_client *client) { struct device *dev; @@ -932,16 +941,6 @@ static int bmc150_magn_probe(struct i2c_client *client, goto err_poweroff; } - ret = iio_triggered_buffer_setup(indio_dev, - &iio_pollfunc_store_time, - bmc150_magn_trigger_handler, - NULL); - if (ret < 0) { - dev_err(&client->dev, - "iio triggered buffer setup failed\n"); - goto err_trigger_unregister; - } - ret = request_threaded_irq(client->irq, iio_trigger_generic_data_rdy_poll, NULL, @@ -951,14 +950,24 @@ static int bmc150_magn_probe(struct i2c_client *client, if (ret < 0) { dev_err(&client->dev, "request irq %d failed\n", client->irq); - goto err_buffer_cleanup; + goto err_trigger_unregister; } } + ret = iio_triggered_buffer_setup(indio_dev, + iio_pollfunc_store_time, + bmc150_magn_trigger_handler, + &bmc150_magn_buffer_setup_ops); + if (ret < 0) { + dev_err(&client->dev, + "iio triggered buffer setup failed\n"); + goto err_free_irq; + } + ret = iio_device_register(indio_dev); if (ret < 0) { dev_err(&client->dev, "unable to register iio device\n"); - goto err_free_irq; + goto err_buffer_cleanup; } ret = pm_runtime_set_active(&client->dev); @@ -976,12 +985,11 @@ static int bmc150_magn_probe(struct i2c_client *client, err_iio_unregister: iio_device_unregister(indio_dev); +err_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); err_free_irq: if (client->irq > 0) free_irq(client->irq, data->dready_trig); -err_buffer_cleanup: - if (data->dready_trig) - iio_triggered_buffer_cleanup(indio_dev); err_trigger_unregister: if (data->dready_trig) iio_trigger_unregister(data->dready_trig); @@ -1000,14 +1008,13 @@ static int bmc150_magn_remove(struct i2c_client *client) pm_runtime_put_noidle(&client->dev); iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); if (client->irq > 0) free_irq(data->client->irq, data->dready_trig); - if (data->dready_trig) { - iio_triggered_buffer_cleanup(indio_dev); + if (data->dready_trig) iio_trigger_unregister(data->dready_trig); - } mutex_lock(&data->mutex); bmc150_magn_set_power_mode(data, BMC150_MAGN_POWER_MODE_SUSPEND, true); -- cgit v1.3-6-gb490 From da8ef4e77d9dfe91d69033cfa05d9f3036fb8dfd Mon Sep 17 00:00:00 2001 From: Vlad Dogaru Date: Fri, 12 Jun 2015 11:31:39 +0300 Subject: iio: magn: bmc150: add support for bmc156 The BMC156 is a slightly less capable version of BMC150 which lacks support for magnetometer thresholds. Since this driver does not support those anyway, adding support is trivial. Datasheet is available at https://ae-bst.resource.bosch.com/media/products/dokumente/bmc156_1/BST-BMC156-DS000-01.pdf Signed-off-by: Vlad Dogaru Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index a0e64f19f4c4..cd002710dd02 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -1089,12 +1089,14 @@ static const struct dev_pm_ops bmc150_magn_pm_ops = { static const struct acpi_device_id bmc150_magn_acpi_match[] = { {"BMC150B", 0}, + {"BMC156B", 0}, {}, }; MODULE_DEVICE_TABLE(acpi, bmc150_magn_acpi_match); static const struct i2c_device_id bmc150_magn_id[] = { {"bmc150_magn", 0}, + {"bmc156_magn", 0}, {}, }; MODULE_DEVICE_TABLE(i2c, bmc150_magn_id); -- cgit v1.3-6-gb490 From efa86e9fa82eaeee76903f131bc326af48a7cbcf Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 17 Jun 2015 12:42:51 +0300 Subject: iio: light: Add support for ROHM RPR0521 sensor This patch adds support for ROHM RPR0521 ambient light and proximity sensor. It offers raw readings for intensity and proximity. Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 11 + drivers/iio/light/Makefile | 1 + drivers/iio/light/rpr0521.c | 615 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 627 insertions(+) create mode 100644 drivers/iio/light/rpr0521.c (limited to 'drivers') diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 554f8ee6d64a..730fa80c83ea 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -168,6 +168,17 @@ config JSA1212 To compile this driver as a module, choose M here: the module will be called jsa1212. +config RPR0521 + tristate "ROHM RPR0521 ALS and proximity sensor driver" + depends on I2C + select REGMAP_I2C + help + Say Y here if you want to build support for ROHM's RPR0521 + ambient light and proximity sensor device. + + To compile this driver as a module, choose M here: + the module will be called rpr0521. + config SENSORS_LM3533 tristate "LM3533 ambient light sensor" depends on MFD_LM3533 diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index e2d50fd59c66..adf97237db72 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_ISL29125) += isl29125.o obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_LTR501) += ltr501.o +obj-$(CONFIG_RPR0521) += rpr0521.o obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_STK3310) += stk3310.o obj-$(CONFIG_TCS3414) += tcs3414.o diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c new file mode 100644 index 000000000000..4b75bb0998b3 --- /dev/null +++ b/drivers/iio/light/rpr0521.c @@ -0,0 +1,615 @@ +/* + * RPR-0521 ROHM Ambient Light and Proximity Sensor + * + * Copyright (c) 2015, Intel Corporation. + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * IIO driver for RPR-0521RS (7-bit I2C slave address 0x38). + * + * TODO: illuminance channel, PM support, buffer + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define RPR0521_REG_SYSTEM_CTRL 0x40 +#define RPR0521_REG_MODE_CTRL 0x41 +#define RPR0521_REG_ALS_CTRL 0x42 +#define RPR0521_REG_PXS_CTRL 0x43 +#define RPR0521_REG_PXS_DATA 0x44 /* 16-bit, little endian */ +#define RPR0521_REG_ALS_DATA0 0x46 /* 16-bit, little endian */ +#define RPR0521_REG_ALS_DATA1 0x48 /* 16-bit, little endian */ +#define RPR0521_REG_ID 0x92 + +#define RPR0521_MODE_ALS_MASK BIT(7) +#define RPR0521_MODE_PXS_MASK BIT(6) +#define RPR0521_MODE_MEAS_TIME_MASK GENMASK(3, 0) +#define RPR0521_ALS_DATA0_GAIN_MASK GENMASK(5, 4) +#define RPR0521_ALS_DATA0_GAIN_SHIFT 4 +#define RPR0521_ALS_DATA1_GAIN_MASK GENMASK(3, 2) +#define RPR0521_ALS_DATA1_GAIN_SHIFT 2 +#define RPR0521_PXS_GAIN_MASK GENMASK(5, 4) +#define RPR0521_PXS_GAIN_SHIFT 4 + +#define RPR0521_MODE_ALS_ENABLE BIT(7) +#define RPR0521_MODE_ALS_DISABLE 0x00 +#define RPR0521_MODE_PXS_ENABLE BIT(6) +#define RPR0521_MODE_PXS_DISABLE 0x00 + +#define RPR0521_MANUFACT_ID 0xE0 +#define RPR0521_DEFAULT_MEAS_TIME 0x06 /* ALS - 100ms, PXS - 100ms */ + +#define RPR0521_DRV_NAME "RPR0521" +#define RPR0521_REGMAP_NAME "rpr0521_regmap" + +#define RPR0521_SLEEP_DELAY_MS 2000 + +#define RPR0521_ALS_SCALE_AVAIL "0.007812 0.015625 0.5 1" +#define RPR0521_PXS_SCALE_AVAIL "0.125 0.5 1" + +struct rpr0521_gain { + int scale; + int uscale; +}; + +static const struct rpr0521_gain rpr0521_als_gain[4] = { + {1, 0}, /* x1 */ + {0, 500000}, /* x2 */ + {0, 15625}, /* x64 */ + {0, 7812}, /* x128 */ +}; + +static const struct rpr0521_gain rpr0521_pxs_gain[3] = { + {1, 0}, /* x1 */ + {0, 500000}, /* x2 */ + {0, 125000}, /* x4 */ +}; + +enum rpr0521_channel { + RPR0521_CHAN_ALS_DATA0, + RPR0521_CHAN_ALS_DATA1, + RPR0521_CHAN_PXS, +}; + +struct rpr0521_reg_desc { + u8 address; + u8 device_mask; +}; + +static const struct rpr0521_reg_desc rpr0521_data_reg[] = { + [RPR0521_CHAN_ALS_DATA0] = { + .address = RPR0521_REG_ALS_DATA0, + .device_mask = RPR0521_MODE_ALS_MASK, + }, + [RPR0521_CHAN_ALS_DATA1] = { + .address = RPR0521_REG_ALS_DATA1, + .device_mask = RPR0521_MODE_ALS_MASK, + }, + [RPR0521_CHAN_PXS] = { + .address = RPR0521_REG_PXS_DATA, + .device_mask = RPR0521_MODE_PXS_MASK, + }, +}; + +static const struct rpr0521_gain_info { + u8 reg; + u8 mask; + u8 shift; + const struct rpr0521_gain *gain; + int size; +} rpr0521_gain[] = { + [RPR0521_CHAN_ALS_DATA0] = { + .reg = RPR0521_REG_ALS_CTRL, + .mask = RPR0521_ALS_DATA0_GAIN_MASK, + .shift = RPR0521_ALS_DATA0_GAIN_SHIFT, + .gain = rpr0521_als_gain, + .size = ARRAY_SIZE(rpr0521_als_gain), + }, + [RPR0521_CHAN_ALS_DATA1] = { + .reg = RPR0521_REG_ALS_CTRL, + .mask = RPR0521_ALS_DATA1_GAIN_MASK, + .shift = RPR0521_ALS_DATA1_GAIN_SHIFT, + .gain = rpr0521_als_gain, + .size = ARRAY_SIZE(rpr0521_als_gain), + }, + [RPR0521_CHAN_PXS] = { + .reg = RPR0521_REG_PXS_CTRL, + .mask = RPR0521_PXS_GAIN_MASK, + .shift = RPR0521_PXS_GAIN_SHIFT, + .gain = rpr0521_pxs_gain, + .size = ARRAY_SIZE(rpr0521_pxs_gain), + }, +}; + +struct rpr0521_data { + struct i2c_client *client; + + /* protect device params updates (e.g state, gain) */ + struct mutex lock; + + /* device active status */ + bool als_dev_en; + bool pxs_dev_en; + + /* optimize runtime pm ops - enable device only if needed */ + bool als_ps_need_en; + bool pxs_ps_need_en; + + struct regmap *regmap; +}; + +static IIO_CONST_ATTR(in_intensity_scale_available, RPR0521_ALS_SCALE_AVAIL); +static IIO_CONST_ATTR(in_proximity_scale_available, RPR0521_PXS_SCALE_AVAIL); + +static struct attribute *rpr0521_attributes[] = { + &iio_const_attr_in_intensity_scale_available.dev_attr.attr, + &iio_const_attr_in_proximity_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group rpr0521_attribute_group = { + .attrs = rpr0521_attributes, +}; + +static const struct iio_chan_spec rpr0521_channels[] = { + { + .type = IIO_INTENSITY, + .modified = 1, + .address = RPR0521_CHAN_ALS_DATA0, + .channel2 = IIO_MOD_LIGHT_BOTH, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_INTENSITY, + .modified = 1, + .address = RPR0521_CHAN_ALS_DATA1, + .channel2 = IIO_MOD_LIGHT_IR, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_PROXIMITY, + .address = RPR0521_CHAN_PXS, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + } +}; + +static int rpr0521_als_enable(struct rpr0521_data *data, u8 status) +{ + int ret; + + ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL, + RPR0521_MODE_ALS_MASK, + status); + if (ret < 0) + return ret; + + data->als_dev_en = true; + + return 0; +} + +static int rpr0521_pxs_enable(struct rpr0521_data *data, u8 status) +{ + int ret; + + ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL, + RPR0521_MODE_PXS_MASK, + status); + if (ret < 0) + return ret; + + data->pxs_dev_en = true; + + return 0; +} + +/** + * rpr0521_set_power_state - handles runtime PM state and sensors enabled status + * + * @data: rpr0521 device private data + * @on: state to be set for devices in @device_mask + * @device_mask: bitmask specifying for which device we need to update @on state + * + * We rely on rpr0521_runtime_resume to enable our @device_mask devices, but + * if (for example) PXS was enabled (pxs_dev_en = true) by a previous call to + * rpr0521_runtime_resume and we want to enable ALS we MUST set ALS enable + * bit of RPR0521_REG_MODE_CTRL here because rpr0521_runtime_resume will not + * be called twice. + */ +static int rpr0521_set_power_state(struct rpr0521_data *data, bool on, + u8 device_mask) +{ +#ifdef CONFIG_PM + int ret; + u8 update_mask = 0; + + if (device_mask & RPR0521_MODE_ALS_MASK) { + if (on && !data->als_ps_need_en && data->pxs_dev_en) + update_mask |= RPR0521_MODE_ALS_MASK; + else + data->als_ps_need_en = on; + } + + if (device_mask & RPR0521_MODE_PXS_MASK) { + if (on && !data->pxs_ps_need_en && data->als_dev_en) + update_mask |= RPR0521_MODE_PXS_MASK; + else + data->pxs_ps_need_en = on; + } + + if (update_mask) { + ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL, + update_mask, update_mask); + if (ret < 0) + return ret; + } + + if (on) { + ret = pm_runtime_get_sync(&data->client->dev); + } else { + pm_runtime_mark_last_busy(&data->client->dev); + ret = pm_runtime_put_autosuspend(&data->client->dev); + } + if (ret < 0) { + dev_err(&data->client->dev, + "Failed: rpr0521_set_power_state for %d, ret %d\n", + on, ret); + if (on) + pm_runtime_put_noidle(&data->client->dev); + + return ret; + } +#endif + return 0; +} + +static int rpr0521_get_gain(struct rpr0521_data *data, int chan, + int *val, int *val2) +{ + int ret, reg, idx; + + ret = regmap_read(data->regmap, rpr0521_gain[chan].reg, ®); + if (ret < 0) + return ret; + + idx = (rpr0521_gain[chan].mask & reg) >> rpr0521_gain[chan].shift; + *val = rpr0521_gain[chan].gain[idx].scale; + *val2 = rpr0521_gain[chan].gain[idx].uscale; + + return 0; +} + +static int rpr0521_set_gain(struct rpr0521_data *data, int chan, + int val, int val2) +{ + int i, idx = -EINVAL; + + /* get gain index */ + for (i = 0; i < rpr0521_gain[chan].size; i++) + if (val == rpr0521_gain[chan].gain[i].scale && + val2 == rpr0521_gain[chan].gain[i].uscale) { + idx = i; + break; + } + + if (idx < 0) + return idx; + + return regmap_update_bits(data->regmap, rpr0521_gain[chan].reg, + rpr0521_gain[chan].mask, + idx << rpr0521_gain[chan].shift); +} + +static int rpr0521_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct rpr0521_data *data = iio_priv(indio_dev); + int ret; + u8 device_mask; + __le16 raw_data; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type != IIO_INTENSITY && chan->type != IIO_PROXIMITY) + return -EINVAL; + + device_mask = rpr0521_data_reg[chan->address].device_mask; + + mutex_lock(&data->lock); + ret = rpr0521_set_power_state(data, true, device_mask); + if (ret < 0) { + mutex_unlock(&data->lock); + return ret; + } + + ret = regmap_bulk_read(data->regmap, + rpr0521_data_reg[chan->address].address, + &raw_data, 2); + if (ret < 0) { + rpr0521_set_power_state(data, false, device_mask); + mutex_unlock(&data->lock); + return ret; + } + + ret = rpr0521_set_power_state(data, false, device_mask); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + + *val = le16_to_cpu(raw_data); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + mutex_lock(&data->lock); + ret = rpr0521_get_gain(data, chan->address, val, val2); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int rpr0521_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct rpr0521_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + mutex_lock(&data->lock); + ret = rpr0521_set_gain(data, chan->address, val, val2); + mutex_unlock(&data->lock); + + return ret; + default: + return -EINVAL; + } +} + +static const struct iio_info rpr0521_info = { + .driver_module = THIS_MODULE, + .read_raw = rpr0521_read_raw, + .write_raw = rpr0521_write_raw, + .attrs = &rpr0521_attribute_group, +}; + +static int rpr0521_init(struct rpr0521_data *data) +{ + int ret; + int id; + + ret = regmap_read(data->regmap, RPR0521_REG_ID, &id); + if (ret < 0) { + dev_err(&data->client->dev, "Failed to read REG_ID register\n"); + return ret; + } + + if (id != RPR0521_MANUFACT_ID) { + dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n", + id, RPR0521_MANUFACT_ID); + return -ENODEV; + } + + /* set default measurement time - 100 ms for both ALS and PS */ + ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL, + RPR0521_MODE_MEAS_TIME_MASK, + RPR0521_DEFAULT_MEAS_TIME); + if (ret) { + pr_err("regmap_update_bits returned %d\n", ret); + return ret; + } + + ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE); + if (ret < 0) + return ret; + ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE); + if (ret < 0) + return ret; + + return 0; +} + +static int rpr0521_poweroff(struct rpr0521_data *data) +{ + int ret; + + ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL, + RPR0521_MODE_ALS_MASK | + RPR0521_MODE_PXS_MASK, + RPR0521_MODE_ALS_DISABLE | + RPR0521_MODE_PXS_DISABLE); + if (ret < 0) + return ret; + + data->als_dev_en = false; + data->pxs_dev_en = false; + + return 0; +} + +static bool rpr0521_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RPR0521_REG_MODE_CTRL: + case RPR0521_REG_ALS_CTRL: + case RPR0521_REG_PXS_CTRL: + return false; + default: + return true; + } +} + +static const struct regmap_config rpr0521_regmap_config = { + .name = RPR0521_REGMAP_NAME, + + .reg_bits = 8, + .val_bits = 8, + + .max_register = RPR0521_REG_ID, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = rpr0521_is_volatile_reg, +}; + +static int rpr0521_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rpr0521_data *data; + struct iio_dev *indio_dev; + struct regmap *regmap; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(client, &rpr0521_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "regmap_init failed!\n"); + return PTR_ERR(regmap); + } + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + data->regmap = regmap; + + mutex_init(&data->lock); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &rpr0521_info; + indio_dev->name = RPR0521_DRV_NAME; + indio_dev->channels = rpr0521_channels; + indio_dev->num_channels = ARRAY_SIZE(rpr0521_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = rpr0521_init(data); + if (ret < 0) { + dev_err(&client->dev, "rpr0521 chip init failed\n"); + return ret; + } + ret = iio_device_register(indio_dev); + if (ret < 0) + return ret; + + ret = pm_runtime_set_active(&client->dev); + if (ret < 0) + goto err_iio_unregister; + + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS); + pm_runtime_use_autosuspend(&client->dev); + + return 0; + +err_iio_unregister: + iio_device_unregister(indio_dev); + return ret; +} + +static int rpr0521_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + + iio_device_unregister(indio_dev); + rpr0521_poweroff(iio_priv(indio_dev)); + + return 0; +} + +#ifdef CONFIG_PM +static int rpr0521_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct rpr0521_data *data = iio_priv(indio_dev); + int ret; + + /* disable channels and sets {als,pxs}_dev_en to false */ + mutex_lock(&data->lock); + ret = rpr0521_poweroff(data); + mutex_unlock(&data->lock); + + return ret; +} + +static int rpr0521_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct rpr0521_data *data = iio_priv(indio_dev); + int ret; + + if (data->als_ps_need_en) { + ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE); + if (ret < 0) + return ret; + data->als_ps_need_en = false; + } + + if (data->pxs_ps_need_en) { + ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE); + if (ret < 0) + return ret; + data->pxs_ps_need_en = false; + } + + return 0; +} +#endif + +static const struct dev_pm_ops rpr0521_pm_ops = { + SET_RUNTIME_PM_OPS(rpr0521_runtime_suspend, + rpr0521_runtime_resume, NULL) +}; + +static const struct acpi_device_id rpr0521_acpi_match[] = { + {"RPR0521", 0}, + { } +}; +MODULE_DEVICE_TABLE(acpi, rpr0521_acpi_match); + +static const struct i2c_device_id rpr0521_id[] = { + {"rpr0521", 0}, + { } +}; + +MODULE_DEVICE_TABLE(i2c, rpr0521_id); + +static struct i2c_driver rpr0521_driver = { + .driver = { + .name = RPR0521_DRV_NAME, + .pm = &rpr0521_pm_ops, + .acpi_match_table = ACPI_PTR(rpr0521_acpi_match), + }, + .probe = rpr0521_probe, + .remove = rpr0521_remove, + .id_table = rpr0521_id, +}; + +module_i2c_driver(rpr0521_driver); + +MODULE_AUTHOR("Daniel Baluta "); +MODULE_DESCRIPTION("RPR0521 ROHM Ambient Light and Proximity Sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From b359283a035e44a6c760244e14af86cf1f62ef67 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:38 +0200 Subject: drm/i915: Use crtc state in intel_modeset_pipe_config Grabbing crtc state from atomic state is a lot more involved, and make sure connectors are added before calling this function. Move check_digital_port_conflicts to intel_modeset_checks, it's only useful to check it on a modeset. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 39 ++++++++++++++---------------------- 1 file changed, 15 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 98bb15ac4c66..a483a65f0757 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12056,10 +12056,9 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state) static int intel_modeset_pipe_config(struct drm_crtc *crtc, - struct drm_atomic_state *state) + struct intel_crtc_state *pipe_config) { - struct drm_crtc_state *crtc_state; - struct intel_crtc_state *pipe_config; + struct drm_atomic_state *state = pipe_config->base.state; struct intel_encoder *encoder; struct drm_connector *connector; struct drm_connector_state *connector_state; @@ -12072,26 +12071,6 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, return -EINVAL; } - if (!check_digital_port_conflicts(state)) { - DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n"); - return -EINVAL; - } - - crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); - if (WARN_ON(!crtc_state)) - return -EINVAL; - - pipe_config = to_intel_crtc_state(crtc_state); - - /* - * XXX: Add all connectors to make the crtc state match the encoders. - */ - if (!needs_modeset(&pipe_config->base)) { - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - return ret; - } - clear_intel_crtc_state(pipe_config); pipe_config->cpu_transcoder = @@ -12919,6 +12898,11 @@ static int intel_modeset_checks(struct drm_atomic_state *state) struct drm_device *dev = state->dev; int ret; + if (!check_digital_port_conflicts(state)) { + DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n"); + return -EINVAL; + } + /* * See if the config requires any additional preparation, e.g. * to adjust global state with pipes off. We need to do this @@ -12965,7 +12949,14 @@ intel_modeset_compute_config(struct drm_atomic_state *state) if (!crtc_state->enable) continue; - ret = intel_modeset_pipe_config(crtc, state); + if (!needs_modeset(crtc_state)) { + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + return ret; + } + + ret = intel_modeset_pipe_config(crtc, + to_intel_crtc_state(crtc_state)); if (ret) return ret; -- cgit v1.3-6-gb490 From 133b0d128be39e308ccd3b3d765c31ebdbf5380e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:39 +0200 Subject: drm/i915: Clean up intel_atomic_setup_scalers slightly. Get rid of a whole lot of ternary operators and assign the index in scaler_id, instead of the id. They're the same thing. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 21 +++++++++++---------- drivers/gpu/drm/i915/intel_display.c | 2 -- drivers/gpu/drm/i915/intel_drv.h | 1 - 3 files changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 4df6d2d7a9c8..041bff504629 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -309,15 +309,23 @@ int intel_atomic_setup_scalers(struct drm_device *dev, /* walkthrough scaler_users bits and start assigning scalers */ for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) { int *scaler_id; + const char *name; + int idx; /* skip if scaler not required */ if (!(scaler_state->scaler_users & (1 << i))) continue; if (i == SKL_CRTC_INDEX) { + name = "CRTC"; + idx = intel_crtc->base.base.id; + /* panel fitter case: assign as a crtc scaler */ scaler_id = &scaler_state->scaler_id; } else { + name = "PLANE"; + idx = plane->base.id; + if (!drm_state) continue; @@ -356,23 +364,16 @@ int intel_atomic_setup_scalers(struct drm_device *dev, for (j = 0; j < intel_crtc->num_scalers; j++) { if (!scaler_state->scalers[j].in_use) { scaler_state->scalers[j].in_use = 1; - *scaler_id = scaler_state->scalers[j].id; + *scaler_id = j; DRM_DEBUG_KMS("Attached scaler id %u.%u to %s:%d\n", - intel_crtc->pipe, - i == SKL_CRTC_INDEX ? scaler_state->scaler_id : - plane_state->scaler_id, - i == SKL_CRTC_INDEX ? "CRTC" : "PLANE", - i == SKL_CRTC_INDEX ? intel_crtc->base.base.id : - plane->base.id); + intel_crtc->pipe, *scaler_id, name, idx); break; } } } if (WARN_ON(*scaler_id < 0)) { - DRM_DEBUG_KMS("Cannot find scaler for %s:%d\n", - i == SKL_CRTC_INDEX ? "CRTC" : "PLANE", - i == SKL_CRTC_INDEX ? intel_crtc->base.base.id:plane->base.id); + DRM_DEBUG_KMS("Cannot find scaler for %s:%d\n", name, idx); continue; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a483a65f0757..df301cdb6a95 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14070,8 +14070,6 @@ static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_cr for (i = 0; i < intel_crtc->num_scalers; i++) { intel_scaler = &scaler_state->scalers[i]; intel_scaler->in_use = 0; - intel_scaler->id = i; - intel_scaler->mode = PS_SCALER_MODE_DYN; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bcafefcf048b..02b18a173472 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -293,7 +293,6 @@ struct intel_initial_plane_config { #define SKL_MAX_DST_H 4096 struct intel_scaler { - int id; int in_use; uint32_t mode; }; -- cgit v1.3-6-gb490 From 6d3a1ce7dc1a125a40d496e924e8e478560eb42f Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:40 +0200 Subject: drm/i915: Add a simple atomic crtc check function, v2. Move the check for encoder cloning here. Changes since v1: - Remove was/is crtc_disabled. (mattrope) - Rename function to intel_crtc_atomic_check. (mattrope) Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 5 +- drivers/gpu/drm/i915/intel_display.c | 126 ++++++++++++++++++++--------------- 2 files changed, 75 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 041bff504629..6ab71ea92819 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -100,7 +100,10 @@ int intel_atomic_check(struct drm_device *dev, if (ret) return ret; - /* FIXME: move to crtc atomic check function once it is ready */ + /* + * FIXME: move to crtc atomic check function once this is + * more atomic friendly. + */ ret = intel_atomic_setup_scalers(dev, nuclear_crtc, crtc_state); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index df301cdb6a95..df13769cf048 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11673,11 +11673,82 @@ retry: return ret; } +static bool encoders_cloneable(const struct intel_encoder *a, + const struct intel_encoder *b) +{ + /* 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 drm_atomic_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder) +{ + struct intel_encoder *source_encoder; + struct drm_connector *connector; + struct drm_connector_state *connector_state; + int i; + + for_each_connector_in_state(state, connector, connector_state, i) { + if (connector_state->crtc != &crtc->base) + continue; + + source_encoder = + to_intel_encoder(connector_state->best_encoder); + if (!encoders_cloneable(encoder, source_encoder)) + return false; + } + + return true; +} + +static bool check_encoder_cloning(struct drm_atomic_state *state, + struct intel_crtc *crtc) +{ + struct intel_encoder *encoder; + struct drm_connector *connector; + struct drm_connector_state *connector_state; + int i; + + for_each_connector_in_state(state, connector, connector_state, i) { + if (connector_state->crtc != &crtc->base) + continue; + + encoder = to_intel_encoder(connector_state->best_encoder); + if (!check_single_encoder_cloning(state, crtc, encoder)) + return false; + } + + return true; +} + +static int intel_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_atomic_state *state = crtc_state->state; + int idx = crtc->base.id; + bool mode_changed = needs_modeset(crtc_state); + + if (mode_changed && !check_encoder_cloning(state, intel_crtc)) { + DRM_DEBUG_KMS("rejecting invalid cloning configuration\n"); + return -EINVAL; + } + + I915_STATE_WARN(crtc->state->active != intel_crtc->active, + "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n", + idx, crtc->state->active, intel_crtc->active); + + return 0; +} + static const struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_set_base_atomic = intel_pipe_set_base_atomic, .load_lut = intel_crtc_load_lut, .atomic_begin = intel_begin_crtc_commit, .atomic_flush = intel_finish_crtc_commit, + .atomic_check = intel_crtc_atomic_check, }; /** @@ -11930,56 +12001,6 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, } } -static bool encoders_cloneable(const struct intel_encoder *a, - const struct intel_encoder *b) -{ - /* 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 drm_atomic_state *state, - struct intel_crtc *crtc, - struct intel_encoder *encoder) -{ - struct intel_encoder *source_encoder; - struct drm_connector *connector; - struct drm_connector_state *connector_state; - int i; - - for_each_connector_in_state(state, connector, connector_state, i) { - if (connector_state->crtc != &crtc->base) - continue; - - source_encoder = - to_intel_encoder(connector_state->best_encoder); - if (!encoders_cloneable(encoder, source_encoder)) - return false; - } - - return true; -} - -static bool check_encoder_cloning(struct drm_atomic_state *state, - struct intel_crtc *crtc) -{ - struct intel_encoder *encoder; - struct drm_connector *connector; - struct drm_connector_state *connector_state; - int i; - - for_each_connector_in_state(state, connector, connector_state, i) { - if (connector_state->crtc != &crtc->base) - continue; - - encoder = to_intel_encoder(connector_state->best_encoder); - if (!check_single_encoder_cloning(state, crtc, encoder)) - return false; - } - - return true; -} - static bool check_digital_port_conflicts(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; @@ -12066,11 +12087,6 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, int i; bool retry = true; - if (!check_encoder_cloning(state, to_intel_crtc(crtc))) { - DRM_DEBUG_KMS("rejecting invalid cloning configuration\n"); - return -EINVAL; - } - clear_intel_crtc_state(pipe_config); pipe_config->cpu_transcoder = -- cgit v1.3-6-gb490 From cf5a15befd90742128ca2bdc4409789e782fcc9d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:41 +0200 Subject: drm/i915: Move scaler setup to check crtc function, v2. The scaler setup may add planes, but since they're unchanged we only have to wait for primary flips. Also set planes_changed to indicate at least 1 plane is modified. Changes since v1: - Instead of removing planes, do minimal validation needed. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 17 +++++++++-------- drivers/gpu/drm/i915/intel_display.c | 15 +++++---------- 2 files changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 6ab71ea92819..d5afc2aa4ac7 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -100,14 +100,6 @@ int intel_atomic_check(struct drm_device *dev, if (ret) return ret; - /* - * FIXME: move to crtc atomic check function once this is - * more atomic friendly. - */ - ret = intel_atomic_setup_scalers(dev, nuclear_crtc, crtc_state); - if (ret) - return ret; - return ret; } @@ -349,6 +341,15 @@ int intel_atomic_setup_scalers(struct drm_device *dev, plane->base.id); return PTR_ERR(state); } + + /* + * the plane is added after plane checks are run, + * but since this plane is unchanged just do the + * minimum required validation. + */ + if (plane->type == DRM_PLANE_TYPE_PRIMARY) + intel_crtc->atomic.wait_for_flips = true; + crtc_state->base.planes_changed = true; } intel_plane = to_intel_plane(plane); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index df13769cf048..4b307ec173ef 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6586,7 +6586,6 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; - int ret; /* FIXME should check pixel clock limits on all platforms */ if (INTEL_INFO(dev)->gen < 4) { @@ -6632,14 +6631,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, if (pipe_config->has_pch_encoder) return ironlake_fdi_compute_config(crtc, pipe_config); - /* FIXME: remove below call once atomic mode set is place and all crtc - * related checks called from atomic_crtc_check function */ - ret = 0; - DRM_DEBUG_KMS("intel_crtc = %p drm_state (pipe_config->base.state) = %p\n", - crtc, pipe_config->base.state); - ret = intel_atomic_setup_scalers(dev, crtc, pipe_config); - - return ret; + return 0; } static int skylake_get_display_clock_speed(struct drm_device *dev) @@ -11726,7 +11718,10 @@ static bool check_encoder_cloning(struct drm_atomic_state *state, static int intel_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { + struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc_state); struct drm_atomic_state *state = crtc_state->state; int idx = crtc->base.id; bool mode_changed = needs_modeset(crtc_state); @@ -11740,7 +11735,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n", idx, crtc->state->active, intel_crtc->active); - return 0; + return intel_atomic_setup_scalers(dev, intel_crtc, pipe_config); } static const struct drm_crtc_helper_funcs intel_helper_funcs = { -- cgit v1.3-6-gb490 From ad421372a61a6104f21520845e85ba89d691e783 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:42 +0200 Subject: drm/i915: Assign a new pll from the crtc check function, v2. It saves another loop over all crtc's in the state, and computing clock is more of a per crtc thing. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 60 ++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4b307ec173ef..0576be36cd68 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11719,11 +11719,12 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); struct drm_atomic_state *state = crtc_state->state; - int idx = crtc->base.id; + int ret, idx = crtc->base.id; bool mode_changed = needs_modeset(crtc_state); if (mode_changed && !check_encoder_cloning(state, intel_crtc)) { @@ -11735,6 +11736,15 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n", idx, crtc->state->active, intel_crtc->active); + if (mode_changed && crtc_state->enable && + dev_priv->display.crtc_compute_clock && + !WARN_ON(pipe_config->shared_dpll != DPLL_ID_PRIVATE)) { + ret = dev_priv->display.crtc_compute_clock(intel_crtc, + pipe_config); + if (ret) + return ret; + } + return intel_atomic_setup_scalers(dev, intel_crtc, pipe_config); } @@ -12789,53 +12799,37 @@ static void update_scanline_offset(struct intel_crtc *crtc) crtc->scanline_offset = 1; } -static int intel_modeset_setup_plls(struct drm_atomic_state *state) +static void intel_modeset_clear_plls(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct drm_i915_private *dev_priv = to_i915(dev); - unsigned clear_pipes = 0; + struct intel_shared_dpll_config *shared_dpll = NULL; struct intel_crtc *intel_crtc; struct intel_crtc_state *intel_crtc_state; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; - int ret = 0; int i; if (!dev_priv->display.crtc_compute_clock) - return 0; + return; for_each_crtc_in_state(state, crtc, crtc_state, i) { + int dpll; + intel_crtc = to_intel_crtc(crtc); intel_crtc_state = to_intel_crtc_state(crtc_state); + dpll = intel_crtc_state->shared_dpll; - if (needs_modeset(crtc_state)) { - clear_pipes |= 1 << intel_crtc->pipe; - intel_crtc_state->shared_dpll = DPLL_ID_PRIVATE; - } - } - - if (clear_pipes) { - struct intel_shared_dpll_config *shared_dpll = - intel_atomic_get_shared_dpll_state(state); - - for (i = 0; i < dev_priv->num_shared_dpll; i++) - shared_dpll[i].crtc_mask &= ~clear_pipes; - } - - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc_state) || !crtc_state->enable) + if (!needs_modeset(crtc_state) || dpll == DPLL_ID_PRIVATE) continue; - intel_crtc = to_intel_crtc(crtc); - intel_crtc_state = to_intel_crtc_state(crtc_state); + intel_crtc_state->shared_dpll = DPLL_ID_PRIVATE; - ret = dev_priv->display.crtc_compute_clock(intel_crtc, - intel_crtc_state); - if (ret) - return ret; - } + if (!shared_dpll) + shared_dpll = intel_atomic_get_shared_dpll_state(state); - return ret; + shared_dpll[dpll].crtc_mask &= ~(1 << intel_crtc->pipe); + } } /* @@ -12931,14 +12925,12 @@ static int intel_modeset_checks(struct drm_atomic_state *state) return ret; } - ret = intel_modeset_setup_plls(state); - if (ret) - return ret; + intel_modeset_clear_plls(state); if (IS_HASWELL(dev)) - ret = haswell_mode_set_planes_workaround(state); + return haswell_mode_set_planes_workaround(state); - return ret; + return 0; } static int -- cgit v1.3-6-gb490 From 86adf9d7024a699d5195d44c30b7dcd866441f33 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 22 Jun 2015 09:50:32 +0200 Subject: drm/i915: Split skl_update_scaler, v4. commit 2c310b9d2859863826c3688c88218d607d5dd19a Author: Maarten Lankhorst Date: Mon May 18 12:28:52 2015 +0200 drm/i915: Split skl_update_scaler, v4. It's easier to read separate functions for crtc and plane scaler state. Changes since v1: - Update documentation. Changes since v2: - Get rid of parameters to skl_update_scaler only used for traces. This avoids needing to document the other parameters. Changes since v3: - Rename scaler_idx to scaler_user. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 211 +++++++++++++++++++---------------- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 12 +- drivers/gpu/drm/i915/intel_sprite.c | 3 +- 4 files changed, 121 insertions(+), 107 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0576be36cd68..29e1258fed06 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4313,62 +4313,16 @@ static void cpt_verify_modeset(struct drm_device *dev, int pipe) } } -/** - * skl_update_scaler_users - Stages update to crtc's scaler state - * @intel_crtc: crtc - * @crtc_state: crtc_state - * @plane: plane (NULL indicates crtc is requesting update) - * @plane_state: plane's state - * @force_detach: request unconditional detachment of scaler - * - * This function updates scaler state for requested plane or crtc. - * To request scaler usage update for a plane, caller shall pass plane pointer. - * To request scaler usage update for crtc, caller shall pass plane pointer - * as NULL. - * - * Return - * 0 - scaler_usage updated successfully - * error - requested scaling cannot be supported or other error condition - */ -int -skl_update_scaler_users( - struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state, - struct intel_plane *intel_plane, struct intel_plane_state *plane_state, - int force_detach) +static int +skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, + unsigned scaler_user, int *scaler_id, unsigned int rotation, + int src_w, int src_h, int dst_w, int dst_h) { + struct intel_crtc_scaler_state *scaler_state = + &crtc_state->scaler_state; + struct intel_crtc *intel_crtc = + to_intel_crtc(crtc_state->base.crtc); int need_scaling; - int idx; - int src_w, src_h, dst_w, dst_h; - int *scaler_id; - struct drm_framebuffer *fb; - struct intel_crtc_scaler_state *scaler_state; - unsigned int rotation; - - if (!intel_crtc || !crtc_state) - return 0; - - scaler_state = &crtc_state->scaler_state; - - idx = intel_plane ? drm_plane_index(&intel_plane->base) : SKL_CRTC_INDEX; - fb = intel_plane ? plane_state->base.fb : NULL; - - if (intel_plane) { - src_w = drm_rect_width(&plane_state->src) >> 16; - src_h = drm_rect_height(&plane_state->src) >> 16; - dst_w = drm_rect_width(&plane_state->dst); - dst_h = drm_rect_height(&plane_state->dst); - scaler_id = &plane_state->scaler_id; - rotation = plane_state->base.rotation; - } else { - struct drm_display_mode *adjusted_mode = - &crtc_state->base.adjusted_mode; - src_w = crtc_state->pipe_src_w; - src_h = crtc_state->pipe_src_h; - dst_w = adjusted_mode->hdisplay; - dst_h = adjusted_mode->vdisplay; - scaler_id = &scaler_state->scaler_id; - rotation = DRM_ROTATE_0; - } need_scaling = intel_rotation_90_or_270(rotation) ? (src_h != dst_w || src_w != dst_h): @@ -4384,17 +4338,14 @@ skl_update_scaler_users( * update to free the scaler is done in plane/panel-fit programming. * For this purpose crtc/plane_state->scaler_id isn't reset here. */ - if (force_detach || !need_scaling || (intel_plane && - (!fb || !plane_state->visible))) { + if (force_detach || !need_scaling) { if (*scaler_id >= 0) { - scaler_state->scaler_users &= ~(1 << idx); + scaler_state->scaler_users &= ~(1 << scaler_user); scaler_state->scalers[*scaler_id].in_use = 0; - DRM_DEBUG_KMS("Staged freeing scaler id %d.%d from %s:%d " - "crtc_state = %p scaler_users = 0x%x\n", - intel_crtc->pipe, *scaler_id, intel_plane ? "PLANE" : "CRTC", - intel_plane ? intel_plane->base.base.id : - intel_crtc->base.base.id, crtc_state, + DRM_DEBUG_KMS("scaler_user index %u.%u: " + "Staged freeing scaler id %d scaler_users = 0x%x\n", + intel_crtc->pipe, scaler_user, *scaler_id, scaler_state->scaler_users); *scaler_id = -1; } @@ -4407,51 +4358,112 @@ skl_update_scaler_users( src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H || dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H) { - DRM_DEBUG_KMS("%s:%d scaler_user index %u.%u: src %ux%u dst %ux%u " + DRM_DEBUG_KMS("scaler_user index %u.%u: src %ux%u dst %ux%u " "size is out of scaler range\n", - intel_plane ? "PLANE" : "CRTC", - intel_plane ? intel_plane->base.base.id : intel_crtc->base.base.id, - intel_crtc->pipe, idx, src_w, src_h, dst_w, dst_h); + intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h); return -EINVAL; } + /* mark this plane as a scaler user in crtc_state */ + scaler_state->scaler_users |= (1 << scaler_user); + DRM_DEBUG_KMS("scaler_user index %u.%u: " + "staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n", + intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h, + scaler_state->scaler_users); + + return 0; +} + +/** + * skl_update_scaler_crtc - Stages update to scaler state for a given crtc. + * + * @state: crtc's scaler state + * @force_detach: whether to forcibly disable scaler + * + * Return + * 0 - scaler_usage updated successfully + * error - requested scaling cannot be supported or other error condition + */ +int skl_update_scaler_crtc(struct intel_crtc_state *state, int force_detach) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); + struct drm_display_mode *adjusted_mode = + &state->base.adjusted_mode; + + DRM_DEBUG_KMS("Updating scaler for [CRTC:%i] scaler_user index %u.%u\n", + intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX); + + return skl_update_scaler(state, force_detach, SKL_CRTC_INDEX, + &state->scaler_state.scaler_id, DRM_ROTATE_0, + state->pipe_src_w, state->pipe_src_h, + adjusted_mode->hdisplay, adjusted_mode->hdisplay); +} + +/** + * skl_update_scaler_plane - Stages update to scaler state for a given plane. + * + * @state: crtc's scaler state + * @intel_plane: affected plane + * @plane_state: atomic plane state to update + * + * Return + * 0 - scaler_usage updated successfully + * error - requested scaling cannot be supported or other error condition + */ +int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, + struct intel_plane *intel_plane, + struct intel_plane_state *plane_state) +{ + + struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc); + struct drm_framebuffer *fb = plane_state->base.fb; + int ret; + + bool force_detach = !fb || !plane_state->visible; + + DRM_DEBUG_KMS("Updating scaler for [PLANE:%d] scaler_user index %u.%u\n", + intel_plane->base.base.id, intel_crtc->pipe, + drm_plane_index(&intel_plane->base)); + + ret = skl_update_scaler(crtc_state, force_detach, + drm_plane_index(&intel_plane->base), + &plane_state->scaler_id, + plane_state->base.rotation, + drm_rect_width(&plane_state->src) >> 16, + drm_rect_height(&plane_state->src) >> 16, + drm_rect_width(&plane_state->dst), + drm_rect_height(&plane_state->dst)); + + if (ret || plane_state->scaler_id < 0) + return ret; + /* check colorkey */ - if (WARN_ON(intel_plane && - intel_plane->ckey.flags != I915_SET_COLORKEY_NONE)) { - DRM_DEBUG_KMS("PLANE:%d scaling %ux%u->%ux%u not allowed with colorkey", - intel_plane->base.base.id, src_w, src_h, dst_w, dst_h); + if (WARN_ON(intel_plane->ckey.flags != I915_SET_COLORKEY_NONE)) { + DRM_DEBUG_KMS("[PLANE:%d] scaling with color key not allowed", + intel_plane->base.base.id); return -EINVAL; } /* Check src format */ - if (intel_plane) { - switch (fb->pixel_format) { - case DRM_FORMAT_RGB565: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - break; - default: - DRM_DEBUG_KMS("PLANE:%d FB:%d unsupported scaling format 0x%x\n", - intel_plane->base.base.id, fb->base.id, fb->pixel_format); - return -EINVAL; - } + switch (fb->pixel_format) { + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + break; + default: + DRM_DEBUG_KMS("[PLANE:%d] FB:%d unsupported scaling format 0x%x\n", + intel_plane->base.base.id, fb->base.id, fb->pixel_format); + return -EINVAL; } - /* mark this plane as a scaler user in crtc_state */ - scaler_state->scaler_users |= (1 << idx); - DRM_DEBUG_KMS("%s:%d staged scaling request for %ux%u->%ux%u " - "crtc_state = %p scaler_users = 0x%x\n", - intel_plane ? "PLANE" : "CRTC", - intel_plane ? intel_plane->base.base.id : intel_crtc->base.base.id, - src_w, src_h, dst_w, dst_h, crtc_state, scaler_state->scaler_users); return 0; } @@ -4466,7 +4478,7 @@ static void skylake_pfit_update(struct intel_crtc *crtc, int enable) DRM_DEBUG_KMS("for crtc_state = %p\n", crtc->config); /* To update pfit, first update scaler state */ - skl_update_scaler_users(crtc, crtc->config, NULL, NULL, !enable); + skl_update_scaler_crtc(crtc->config, !enable); intel_atomic_setup_scalers(crtc->base.dev, crtc, crtc->config); skl_detach_scalers(crtc); if (!enable) @@ -13660,8 +13672,9 @@ intel_check_primary_plane(struct drm_plane *plane, } if (INTEL_INFO(dev)->gen >= 9) { - ret = skl_update_scaler_users(intel_crtc, crtc_state, - to_intel_plane(plane), state, 0); + ret = skl_update_scaler_plane(crtc_state, + to_intel_plane(plane), + state); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 2e6f23890dbf..a1873b1498c9 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1382,7 +1382,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (INTEL_INFO(dev)->gen >= 9) { int ret; - ret = skl_update_scaler_users(intel_crtc, pipe_config, NULL, NULL, 0); + ret = skl_update_scaler_crtc(pipe_config, 0); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 02b18a173472..2436af9d2678 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -263,7 +263,7 @@ struct intel_plane_state { * plane requiring a scaler: * - During check_plane, its bit is set in * crtc_state->scaler_state.scaler_users by calling helper function - * update_scaler_users. + * update_scaler_plane. * - scaler_id indicates the scaler it got assigned. * * plane doesn't require a scaler: @@ -271,7 +271,7 @@ struct intel_plane_state { * got disabled. * - During check_plane, corresponding bit is reset in * crtc_state->scaler_state.scaler_users by calling helper function - * update_scaler_users. + * update_scaler_plane. */ int scaler_id; }; @@ -1148,9 +1148,11 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); void skl_detach_scalers(struct intel_crtc *intel_crtc); -int skl_update_scaler_users(struct intel_crtc *intel_crtc, - struct intel_crtc_state *crtc_state, struct intel_plane *intel_plane, - struct intel_plane_state *plane_state, int force_detach); +int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, + struct intel_plane *intel_plane, + struct intel_plane_state *plane_state); + +int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state, int force_detach); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 0434cbe1634b..f57268bde9aa 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -944,8 +944,7 @@ finish: } if (INTEL_INFO(dev)->gen >= 9) { - ret = skl_update_scaler_users(intel_crtc, crtc_state, intel_plane, - state, 0); + ret = skl_update_scaler_plane(crtc_state, intel_plane, state); if (ret) return ret; } -- cgit v1.3-6-gb490 From da20eabd2c69761f9dfd849985eb299e3335531f Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:44 +0200 Subject: drm/i915: Split plane updates of crtc->atomic into a helper, v2. This makes it easier to verify that no changes are done when calling this from crtc instead. Changes since v1: - Make intel_wm_need_update static and always check it. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic_plane.c | 21 +-- drivers/gpu/drm/i915/intel_display.c | 275 ++++++++++++++++++------------ drivers/gpu/drm/i915/intel_drv.h | 8 +- drivers/gpu/drm/i915/intel_sprite.c | 32 +--- 4 files changed, 176 insertions(+), 160 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 86ba4b2c3a65..aa2128369a0a 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -114,6 +114,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, struct intel_crtc_state *crtc_state; struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_plane_state *intel_state = to_intel_plane_state(state); + int ret; crtc = crtc ? crtc : plane->crtc; intel_crtc = to_intel_crtc(crtc); @@ -160,20 +161,6 @@ static int intel_plane_atomic_check(struct drm_plane *plane, intel_state->clip.y2 = crtc_state->base.active ? crtc_state->pipe_src_h : 0; - /* - * Disabling a plane is always okay; we just need to update - * fb tracking in a special way since cleanup_fb() won't - * get called by the plane helpers. - */ - if (state->fb == NULL && plane->state->fb != NULL) { - /* - * 'prepare' is never called when plane is being disabled, so - * we need to handle frontbuffer tracking as a special case - */ - intel_crtc->atomic.disabled_planes |= - (1 << drm_plane_index(plane)); - } - if (state->fb && intel_rotation_90_or_270(state->rotation)) { if (!(state->fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || state->fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)) { @@ -198,7 +185,11 @@ static int intel_plane_atomic_check(struct drm_plane *plane, } } - return intel_plane->check_plane(plane, intel_state); + ret = intel_plane->check_plane(plane, intel_state); + if (ret || !state->state) + return ret; + + return intel_plane_atomic_calc_changes(&crtc_state->base, state); } static void intel_plane_atomic_update(struct drm_plane *plane, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 29e1258fed06..39f6b80f990f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4403,19 +4403,19 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state, int force_detach) * skl_update_scaler_plane - Stages update to scaler state for a given plane. * * @state: crtc's scaler state - * @intel_plane: affected plane * @plane_state: atomic plane state to update * * Return * 0 - scaler_usage updated successfully * error - requested scaling cannot be supported or other error condition */ -int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, - struct intel_plane *intel_plane, - struct intel_plane_state *plane_state) +static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc); + struct intel_plane *intel_plane = + to_intel_plane(plane_state->base.plane); struct drm_framebuffer *fb = plane_state->base.fb; int ret; @@ -11677,6 +11677,161 @@ retry: return ret; } + +/** + * intel_wm_need_update - Check whether watermarks need updating + * @plane: drm plane + * @state: new plane state + * + * Check current plane state versus the new one to determine whether + * watermarks need to be recalculated. + * + * Returns true or false. + */ +static bool intel_wm_need_update(struct drm_plane *plane, + struct drm_plane_state *state) +{ + /* Update watermarks on tiling changes. */ + if (!plane->state->fb || !state->fb || + plane->state->fb->modifier[0] != state->fb->modifier[0] || + plane->state->rotation != state->rotation) + return true; + + if (plane->state->crtc_w != state->crtc_w) + return true; + + return false; +} + +int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) +{ + struct drm_crtc *crtc = crtc_state->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_plane *plane = plane_state->plane; + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_plane_state *old_plane_state = + to_intel_plane_state(plane->state); + int idx = intel_crtc->base.base.id, ret; + int i = drm_plane_index(plane); + bool mode_changed = needs_modeset(crtc_state); + bool was_crtc_enabled = crtc->state->active; + bool is_crtc_enabled = crtc_state->active; + + bool turn_off, turn_on, visible, was_visible; + struct drm_framebuffer *fb = plane_state->fb; + + if (crtc_state && INTEL_INFO(dev)->gen >= 9 && + plane->type != DRM_PLANE_TYPE_CURSOR) { + ret = skl_update_scaler_plane( + to_intel_crtc_state(crtc_state), + to_intel_plane_state(plane_state)); + if (ret) + return ret; + } + + /* + * Disabling a plane is always okay; we just need to update + * fb tracking in a special way since cleanup_fb() won't + * get called by the plane helpers. + */ + if (old_plane_state->base.fb && !fb) + intel_crtc->atomic.disabled_planes |= 1 << i; + + /* don't run rest during modeset yet */ + if (!intel_crtc->active || mode_changed) + return 0; + + was_visible = old_plane_state->visible; + visible = to_intel_plane_state(plane_state)->visible; + + if (!was_crtc_enabled && WARN_ON(was_visible)) + was_visible = false; + + if (!is_crtc_enabled && WARN_ON(visible)) + visible = false; + + if (!was_visible && !visible) + return 0; + + turn_off = was_visible && (!visible || mode_changed); + turn_on = visible && (!was_visible || mode_changed); + + DRM_DEBUG_ATOMIC("[CRTC:%i] has [PLANE:%i] with fb %i\n", idx, + plane->base.id, fb ? fb->base.id : -1); + + DRM_DEBUG_ATOMIC("[PLANE:%i] visible %i -> %i, off %i, on %i, ms %i\n", + plane->base.id, was_visible, visible, + turn_off, turn_on, mode_changed); + + if (intel_wm_need_update(plane, plane_state)) + intel_crtc->atomic.update_wm = true; + + switch (plane->type) { + case DRM_PLANE_TYPE_PRIMARY: + if (visible) + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); + + intel_crtc->atomic.wait_for_flips = true; + intel_crtc->atomic.pre_disable_primary = turn_off; + intel_crtc->atomic.post_enable_primary = turn_on; + + if (turn_off) + intel_crtc->atomic.disable_fbc = true; + + /* + * FBC does not work on some platforms for rotated + * planes, so disable it when rotation is not 0 and + * update it when rotation is set back to 0. + * + * FIXME: This is redundant with the fbc update done in + * the primary plane enable function except that that + * one is done too late. We eventually need to unify + * this. + */ + + if (visible && + INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && + dev_priv->fbc.crtc == intel_crtc && + plane_state->rotation != BIT(DRM_ROTATE_0)) + intel_crtc->atomic.disable_fbc = true; + + /* + * BDW signals flip done immediately if the plane + * is disabled, even if the plane enable is already + * armed to occur at the next vblank :( + */ + if (turn_on && IS_BROADWELL(dev)) + intel_crtc->atomic.wait_vblank = true; + + intel_crtc->atomic.update_fbc |= visible || mode_changed; + break; + case DRM_PLANE_TYPE_CURSOR: + if (visible) + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe); + break; + case DRM_PLANE_TYPE_OVERLAY: + /* + * 'prepare' is never called when plane is being disabled, so + * we need to handle frontbuffer tracking as a special case + */ + if (visible) + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); + + if (turn_off && is_crtc_enabled) { + intel_crtc->atomic.wait_vblank = true; + intel_crtc->atomic.update_sprite_watermarks |= + 1 << i; + } + break; + } + return 0; +} + static bool encoders_cloneable(const struct intel_encoder *a, const struct intel_encoder *b) { @@ -13443,28 +13598,6 @@ static void intel_shared_dpll_init(struct drm_device *dev) BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS); } -/** - * intel_wm_need_update - Check whether watermarks need updating - * @plane: drm plane - * @state: new plane state - * - * Check current plane state versus the new one to determine whether - * watermarks need to be recalculated. - * - * Returns true or false. - */ -bool intel_wm_need_update(struct drm_plane *plane, - struct drm_plane_state *state) -{ - /* Update watermarks on tiling changes. */ - if (!plane->state->fb || !state->fb || - plane->state->fb->modifier[0] != state->fb->modifier[0] || - plane->state->rotation != state->rotation) - return true; - - return false; -} - /** * intel_prepare_plane_fb - Prepare fb for usage on plane * @plane: drm plane to prepare for @@ -13586,7 +13719,6 @@ intel_check_primary_plane(struct drm_plane *plane, struct intel_plane_state *state) { struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = state->base.crtc; struct intel_crtc *intel_crtc; struct intel_crtc_state *crtc_state; @@ -13597,7 +13729,6 @@ intel_check_primary_plane(struct drm_plane *plane, bool can_position = false; int max_scale = DRM_PLANE_HELPER_NO_SCALING; int min_scale = DRM_PLANE_HELPER_NO_SCALING; - int ret; crtc = crtc ? crtc : plane->crtc; intel_crtc = to_intel_crtc(crtc); @@ -13613,73 +13744,11 @@ intel_check_primary_plane(struct drm_plane *plane, can_position = true; } - ret = drm_plane_helper_check_update(plane, crtc, fb, - src, dest, clip, - min_scale, - max_scale, - can_position, true, - &state->visible); - if (ret) - return ret; - - if (intel_crtc->active) { - struct intel_plane_state *old_state = - to_intel_plane_state(plane->state); - - intel_crtc->atomic.wait_for_flips = true; - - /* - * FBC does not work on some platforms for rotated - * planes, so disable it when rotation is not 0 and - * update it when rotation is set back to 0. - * - * FIXME: This is redundant with the fbc update done in - * the primary plane enable function except that that - * one is done too late. We eventually need to unify - * this. - */ - if (state->visible && - INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && - dev_priv->fbc.crtc == intel_crtc && - state->base.rotation != BIT(DRM_ROTATE_0)) { - intel_crtc->atomic.disable_fbc = true; - } - - if (state->visible && !old_state->visible) { - /* - * BDW signals flip done immediately if the plane - * is disabled, even if the plane enable is already - * armed to occur at the next vblank :( - */ - if (IS_BROADWELL(dev)) - intel_crtc->atomic.wait_vblank = true; - - if (crtc_state && !needs_modeset(&crtc_state->base)) - intel_crtc->atomic.post_enable_primary = true; - } - - if (!state->visible && old_state->visible && - crtc_state && !needs_modeset(&crtc_state->base)) - intel_crtc->atomic.pre_disable_primary = true; - - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); - - intel_crtc->atomic.update_fbc = true; - - if (intel_wm_need_update(plane, &state->base)) - intel_crtc->atomic.update_wm = true; - } - - if (INTEL_INFO(dev)->gen >= 9) { - ret = skl_update_scaler_plane(crtc_state, - to_intel_plane(plane), - state); - if (ret) - return ret; - } - - return 0; + return drm_plane_helper_check_update(plane, crtc, fb, + src, dest, clip, + min_scale, max_scale, + can_position, true, + &state->visible); } static void @@ -13939,10 +14008,9 @@ intel_check_cursor_plane(struct drm_plane *plane, if (ret) return ret; - /* if we want to turn off the cursor ignore width and height */ if (!obj) - goto finish; + return 0; /* Check for which cursor types we support */ if (!cursor_size_ok(dev, state->base.crtc_w, state->base.crtc_h)) { @@ -13959,19 +14027,10 @@ intel_check_cursor_plane(struct drm_plane *plane, if (fb->modifier[0] != DRM_FORMAT_MOD_NONE) { DRM_DEBUG_KMS("cursor cannot be tiled\n"); - ret = -EINVAL; - } - -finish: - if (intel_crtc->active) { - if (plane->state->crtc_w != state->base.crtc_w) - intel_crtc->atomic.update_wm = true; - - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe); + return -EINVAL; } - return ret; + return 0; } static void diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2436af9d2678..198cb20d9193 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1067,6 +1067,8 @@ int intel_plane_atomic_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val); +int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state); unsigned int intel_tile_height(struct drm_device *dev, uint32_t pixel_format, @@ -1081,9 +1083,6 @@ intel_rotation_90_or_270(unsigned int rotation) void intel_create_rotation_property(struct drm_device *dev, struct intel_plane *plane); -bool intel_wm_need_update(struct drm_plane *plane, - struct drm_plane_state *state); - /* shared dpll functions */ struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc); void assert_shared_dpll(struct drm_i915_private *dev_priv, @@ -1148,9 +1147,6 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); void skl_detach_scalers(struct intel_crtc *intel_crtc); -int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, - struct intel_plane *intel_plane, - struct intel_plane_state *plane_state); int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state, int force_detach); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index f57268bde9aa..e36bef805576 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -759,7 +759,6 @@ intel_check_sprite_plane(struct drm_plane *plane, int max_scale, min_scale; bool can_scale; int pixel_size; - int ret; intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc); crtc_state = state->base.state ? @@ -767,7 +766,7 @@ intel_check_sprite_plane(struct drm_plane *plane, if (!fb) { state->visible = false; - goto finish; + return 0; } /* Don't modify another pipe's plane */ @@ -920,35 +919,6 @@ intel_check_sprite_plane(struct drm_plane *plane, dst->y1 = crtc_y; dst->y2 = crtc_y + crtc_h; -finish: - /* - * If the sprite is completely covering the primary plane, - * we can disable the primary and save power. - */ - if (intel_crtc->active) { - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); - - if (intel_wm_need_update(plane, &state->base)) - intel_crtc->atomic.update_wm = true; - - if (!state->visible) { - /* - * Avoid underruns when disabling the sprite. - * FIXME remove once watermark updates are done properly. - */ - intel_crtc->atomic.wait_vblank = true; - intel_crtc->atomic.update_sprite_watermarks |= - (1 << drm_plane_index(plane)); - } - } - - if (INTEL_INFO(dev)->gen >= 9) { - ret = skl_update_scaler_plane(crtc_state, intel_plane, state); - if (ret) - return ret; - } - return 0; } -- cgit v1.3-6-gb490 From 302d19ac76ae5abacfcffcc76fb384d0b8d54c80 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:45 +0200 Subject: drm/i915: clean up plane commit functions No point in hiding behind big ifs. This will be true most of the time. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 ++++++++-------- drivers/gpu/drm/i915/intel_sprite.c | 33 ++++++++++++++------------------- 2 files changed, 22 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 39f6b80f990f..2f50c73653d9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13769,14 +13769,14 @@ intel_commit_primary_plane(struct drm_plane *plane, crtc->x = src->x1 >> 16; crtc->y = src->y1 >> 16; - if (intel_crtc->active) { - if (state->visible) - /* FIXME: kill this fastboot hack */ - intel_update_pipe_size(intel_crtc); + if (!intel_crtc->active) + return; - dev_priv->display.update_primary_plane(crtc, plane->fb, - crtc->x, crtc->y); - } + if (state->visible) + /* FIXME: kill this fastboot hack */ + intel_update_pipe_size(intel_crtc); + + dev_priv->display.update_primary_plane(crtc, fb, crtc->x, crtc->y); } static void @@ -14078,8 +14078,8 @@ intel_commit_cursor_plane(struct drm_plane *plane, intel_crtc->cursor_addr = addr; intel_crtc->cursor_bo = obj; -update: +update: if (intel_crtc->active) intel_crtc_update_cursor(crtc, state->visible); } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index e36bef805576..48353b34d0f5 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -930,31 +930,26 @@ intel_commit_sprite_plane(struct drm_plane *plane, struct intel_crtc *intel_crtc; struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_framebuffer *fb = state->base.fb; - int crtc_x, crtc_y; - unsigned int crtc_w, crtc_h; - uint32_t src_x, src_y, src_w, src_h; crtc = crtc ? crtc : plane->crtc; intel_crtc = to_intel_crtc(crtc); plane->fb = fb; - if (intel_crtc->active) { - if (state->visible) { - crtc_x = state->dst.x1; - crtc_y = state->dst.y1; - crtc_w = drm_rect_width(&state->dst); - crtc_h = drm_rect_height(&state->dst); - src_x = state->src.x1 >> 16; - src_y = state->src.y1 >> 16; - src_w = drm_rect_width(&state->src) >> 16; - src_h = drm_rect_height(&state->src) >> 16; - intel_plane->update_plane(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - } else { - intel_plane->disable_plane(plane, crtc, false); - } + if (!intel_crtc->active) + return; + + if (state->visible) { + intel_plane->update_plane(plane, crtc, fb, + state->dst.x1, state->dst.y1, + drm_rect_width(&state->dst), + drm_rect_height(&state->dst), + state->src.x1 >> 16, + state->src.y1 >> 16, + drm_rect_width(&state->src) >> 16, + drm_rect_height(&state->src) >> 16); + } else { + intel_plane->disable_plane(plane, crtc, false); } } -- cgit v1.3-6-gb490 From 061e4b8d650afd16ebe447d454431c717265b89f Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:46 +0200 Subject: drm/i915: clean up atomic plane check functions, v2. By passing crtc_state to the check_plane functions a lot of duplicated code can be removed. There are still some transitional helper calls, they will be removed later. Changes since v1: - Revert state->visible changes. - Use plane->state->crtc instead of plane->crtc. - Use drm_atomic_get_existing_crtc_state. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic_plane.c | 16 +++++++---- drivers/gpu/drm/i915/intel_display.c | 48 ++++++++++--------------------- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_sprite.c | 9 ++---- 4 files changed, 29 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index aa2128369a0a..91d53768df9d 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -116,7 +116,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, struct intel_plane_state *intel_state = to_intel_plane_state(state); int ret; - crtc = crtc ? crtc : plane->crtc; + crtc = crtc ? crtc : plane->state->crtc; intel_crtc = to_intel_crtc(crtc); /* @@ -131,10 +131,13 @@ static int intel_plane_atomic_check(struct drm_plane *plane, /* FIXME: temporary hack necessary while we still use the plane update * helper. */ if (state->state) { - crtc_state = - intel_atomic_get_crtc_state(state->state, intel_crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); + struct drm_crtc_state *drm_crtc_state = + drm_atomic_get_existing_crtc_state(state->state, crtc); + + if (WARN_ON(!drm_crtc_state)) + return -EINVAL; + + crtc_state = to_intel_crtc_state(drm_crtc_state); } else { crtc_state = intel_crtc->config; } @@ -185,7 +188,8 @@ static int intel_plane_atomic_check(struct drm_plane *plane, } } - ret = intel_plane->check_plane(plane, intel_state); + intel_state->visible = false; + ret = intel_plane->check_plane(plane, crtc_state, intel_state); if (ret || !state->state) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2f50c73653d9..d7ad8449a9e1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13716,36 +13716,25 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state static int intel_check_primary_plane(struct drm_plane *plane, + struct intel_crtc_state *crtc_state, struct intel_plane_state *state) { - struct drm_device *dev = plane->dev; struct drm_crtc *crtc = state->base.crtc; - struct intel_crtc *intel_crtc; - struct intel_crtc_state *crtc_state; struct drm_framebuffer *fb = state->base.fb; - struct drm_rect *dest = &state->dst; - struct drm_rect *src = &state->src; - const struct drm_rect *clip = &state->clip; - bool can_position = false; - int max_scale = DRM_PLANE_HELPER_NO_SCALING; int min_scale = DRM_PLANE_HELPER_NO_SCALING; + int max_scale = DRM_PLANE_HELPER_NO_SCALING; + bool can_position = false; - crtc = crtc ? crtc : plane->crtc; - intel_crtc = to_intel_crtc(crtc); - crtc_state = state->base.state ? - intel_atomic_get_crtc_state(state->base.state, intel_crtc) : NULL; - - if (INTEL_INFO(dev)->gen >= 9) { - /* use scaler when colorkey is not required */ - if (to_intel_plane(plane)->ckey.flags == I915_SET_COLORKEY_NONE) { - min_scale = 1; - max_scale = skl_max_scale(intel_crtc, crtc_state); - } + /* use scaler when colorkey is not required */ + if (INTEL_INFO(plane->dev)->gen >= 9 && + to_intel_plane(plane)->ckey.flags == I915_SET_COLORKEY_NONE) { + min_scale = 1; + max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state); can_position = true; } - return drm_plane_helper_check_update(plane, crtc, fb, - src, dest, clip, + return drm_plane_helper_check_update(plane, crtc, fb, &state->src, + &state->dst, &state->clip, min_scale, max_scale, can_position, true, &state->visible); @@ -13984,24 +13973,17 @@ void intel_create_rotation_property(struct drm_device *dev, struct intel_plane * static int intel_check_cursor_plane(struct drm_plane *plane, + struct intel_crtc_state *crtc_state, struct intel_plane_state *state) { - struct drm_crtc *crtc = state->base.crtc; - struct drm_device *dev = plane->dev; + struct drm_crtc *crtc = crtc_state->base.crtc; struct drm_framebuffer *fb = state->base.fb; - struct drm_rect *dest = &state->dst; - struct drm_rect *src = &state->src; - const struct drm_rect *clip = &state->clip; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc; unsigned stride; int ret; - crtc = crtc ? crtc : plane->crtc; - intel_crtc = to_intel_crtc(crtc); - - ret = drm_plane_helper_check_update(plane, crtc, fb, - src, dest, clip, + ret = drm_plane_helper_check_update(plane, crtc, fb, &state->src, + &state->dst, &state->clip, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, true, true, &state->visible); @@ -14013,7 +13995,7 @@ intel_check_cursor_plane(struct drm_plane *plane, return 0; /* Check for which cursor types we support */ - if (!cursor_size_ok(dev, state->base.crtc_w, state->base.crtc_h)) { + if (!cursor_size_ok(plane->dev, state->base.crtc_w, state->base.crtc_h)) { DRM_DEBUG("Cursor dimension %dx%d not supported\n", state->base.crtc_w, state->base.crtc_h); return -EINVAL; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 198cb20d9193..0145e0878be5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -613,6 +613,7 @@ struct intel_plane { void (*disable_plane)(struct drm_plane *plane, struct drm_crtc *crtc, bool force); int (*check_plane)(struct drm_plane *plane, + struct intel_crtc_state *crtc_state, struct intel_plane_state *state); void (*commit_plane)(struct drm_plane *plane, struct intel_plane_state *state); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 48353b34d0f5..cc18605ab7a8 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -742,11 +742,12 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc, bool force) static int intel_check_sprite_plane(struct drm_plane *plane, + struct intel_crtc_state *crtc_state, struct intel_plane_state *state) { struct drm_device *dev = plane->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); - struct intel_crtc_state *crtc_state; + struct drm_crtc *crtc = state->base.crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_framebuffer *fb = state->base.fb; int crtc_x, crtc_y; @@ -760,10 +761,6 @@ intel_check_sprite_plane(struct drm_plane *plane, bool can_scale; int pixel_size; - intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc); - crtc_state = state->base.state ? - intel_atomic_get_crtc_state(state->base.state, intel_crtc) : NULL; - if (!fb) { state->visible = false; return 0; -- cgit v1.3-6-gb490 From 7fabf5ef18ea76714ff04baaeeddb949faf486dd Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:47 +0200 Subject: drm/i915: remove force argument from disable_plane The idea was good, but planes can have a fb even though they're disabled. This makes the force argument useless and always true, because only the commit function updates state. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 +++------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_sprite.c | 10 +++++----- 3 files changed, 9 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d7ad8449a9e1..bc55221ffe65 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4804,7 +4804,7 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) struct drm_crtc *from = intel_plane->base.crtc; intel_plane->disable_plane(&intel_plane->base, - from ?: crtc, true); + from ?: crtc); } } @@ -13770,8 +13770,7 @@ intel_commit_primary_plane(struct drm_plane *plane, static void intel_disable_primary_plane(struct drm_plane *plane, - struct drm_crtc *crtc, - bool force) + struct drm_crtc *crtc) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -14017,17 +14016,8 @@ intel_check_cursor_plane(struct drm_plane *plane, static void intel_disable_cursor_plane(struct drm_plane *plane, - struct drm_crtc *crtc, - bool force) + struct drm_crtc *crtc) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - if (!force) { - plane->fb = NULL; - intel_crtc->cursor_bo = NULL; - intel_crtc->cursor_addr = 0; - } - intel_crtc_update_cursor(crtc, false); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0145e0878be5..eaf7eaf2ffac 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -611,7 +611,7 @@ struct intel_plane { uint32_t x, uint32_t y, uint32_t src_w, uint32_t src_h); void (*disable_plane)(struct drm_plane *plane, - struct drm_crtc *crtc, bool force); + struct drm_crtc *crtc); int (*check_plane)(struct drm_plane *plane, struct intel_crtc_state *crtc_state, struct intel_plane_state *state); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index cc18605ab7a8..699311a9bdfe 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -272,7 +272,7 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, } static void -skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc, bool force) +skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) { struct drm_device *dev = dplane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -456,7 +456,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, } static void -vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc, bool force) +vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) { struct drm_device *dev = dplane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -597,7 +597,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } static void -ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc, bool force) +ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -725,7 +725,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } static void -ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc, bool force) +ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -946,7 +946,7 @@ intel_commit_sprite_plane(struct drm_plane *plane, drm_rect_width(&state->src) >> 16, drm_rect_height(&state->src) >> 16); } else { - intel_plane->disable_plane(plane, crtc, false); + intel_plane->disable_plane(plane, crtc); } } -- cgit v1.3-6-gb490 From 0583236eaa8f8596c2adf5116020dba9bcf77806 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:48 +0200 Subject: drm/i915: move detaching scalers to begin_crtc_commit, v2. This is probably intended to be be done during vblank evasion. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 3 --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- drivers/gpu/drm/i915/intel_drv.h | 1 - 3 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index d5afc2aa4ac7..c1263be8c98b 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -144,9 +144,6 @@ int intel_atomic_commit(struct drm_device *dev, for_each_crtc_in_state(state, crtc, crtc_state, i) { to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); - if (INTEL_INFO(dev)->gen >= 9) - skl_detach_scalers(to_intel_crtc(crtc)); - drm_atomic_helper_commit_planes_on_crtc(crtc_state); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bc55221ffe65..449e07d29b3e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2925,16 +2925,13 @@ unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, /* * This function detaches (aka. unbinds) unused scalers in hardware */ -void skl_detach_scalers(struct intel_crtc *intel_crtc) +static void skl_detach_scalers(struct intel_crtc *intel_crtc) { struct drm_device *dev; struct drm_i915_private *dev_priv; struct intel_crtc_scaler_state *scaler_state; int i; - if (!intel_crtc || !intel_crtc->config) - return; - dev = intel_crtc->base.dev; dev_priv = dev->dev_private; scaler_state = &intel_crtc->config->scaler_state; @@ -13831,6 +13828,9 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) intel_crtc->atomic.evade = intel_pipe_update_start(intel_crtc, &intel_crtc->atomic.start_vbl_count); + + if (!needs_modeset(crtc->state) && INTEL_INFO(dev)->gen >= 9) + skl_detach_scalers(intel_crtc); } static void intel_finish_crtc_commit(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index eaf7eaf2ffac..49ec7142b9cc 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1147,7 +1147,6 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_state *pipe_config); void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); -void skl_detach_scalers(struct intel_crtc *intel_crtc); int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state, int force_detach); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); -- cgit v1.3-6-gb490 From ac21b225638a035449107dbbcc0c9f5bd4a24102 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:49 +0200 Subject: drm/i915: Move crtc commit updates to separate functions. To allow them to be used in intel_set_mode. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 127 +++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 449e07d29b3e..118c8acc2603 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4763,6 +4763,72 @@ intel_pre_disable_primary(struct drm_crtc *crtc) hsw_disable_ips(intel_crtc); } +static void intel_post_plane_update(struct intel_crtc *crtc) +{ + struct intel_crtc_atomic_commit *atomic = &crtc->atomic; + struct drm_device *dev = crtc->base.dev; + struct drm_plane *plane; + + if (atomic->wait_vblank) + intel_wait_for_vblank(dev, crtc->pipe); + + intel_frontbuffer_flip(dev, atomic->fb_bits); + + if (atomic->update_fbc) { + mutex_lock(&dev->struct_mutex); + intel_fbc_update(dev); + mutex_unlock(&dev->struct_mutex); + } + + if (atomic->post_enable_primary) + intel_post_enable_primary(&crtc->base); + + drm_for_each_plane_mask(plane, dev, atomic->update_sprite_watermarks) + intel_update_sprite_watermarks(plane, &crtc->base, + 0, 0, 0, false, false); + + memset(atomic, 0, sizeof(*atomic)); +} + +static void intel_pre_plane_update(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct intel_crtc_atomic_commit *atomic = &crtc->atomic; + struct drm_plane *p; + + /* Track fb's for any planes being disabled */ + + drm_for_each_plane_mask(p, dev, atomic->disabled_planes) { + struct intel_plane *plane = to_intel_plane(p); + unsigned fb_bits = 0; + + switch (p->type) { + case DRM_PLANE_TYPE_PRIMARY: + fb_bits = INTEL_FRONTBUFFER_PRIMARY(plane->pipe); + break; + case DRM_PLANE_TYPE_CURSOR: + fb_bits = INTEL_FRONTBUFFER_CURSOR(plane->pipe); + break; + case DRM_PLANE_TYPE_OVERLAY: + fb_bits = INTEL_FRONTBUFFER_SPRITE(plane->pipe); + break; + } + + mutex_lock(&dev->struct_mutex); + i915_gem_track_fb(intel_fb_obj(plane->base.fb), NULL, fb_bits); + mutex_unlock(&dev->struct_mutex); + } + + if (atomic->wait_for_flips) + intel_crtc_wait_for_pending_flips(&crtc->base); + + if (atomic->disable_fbc) + intel_fbc_disable(dev); + + if (atomic->pre_disable_primary) + intel_pre_disable_primary(&crtc->base); +} + static void intel_crtc_enable_planes(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -13780,43 +13846,8 @@ static void intel_begin_crtc_commit(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); - struct drm_crtc_state *crtc_state = intel_crtc->base.state; - struct intel_plane *intel_plane; - struct drm_plane *p; - unsigned fb_bits = 0; - - /* Track fb's for any planes being disabled */ - list_for_each_entry(p, &dev->mode_config.plane_list, head) { - intel_plane = to_intel_plane(p); - - if (intel_crtc->atomic.disabled_planes & - (1 << drm_plane_index(p))) { - switch (p->type) { - case DRM_PLANE_TYPE_PRIMARY: - fb_bits = INTEL_FRONTBUFFER_PRIMARY(intel_plane->pipe); - break; - case DRM_PLANE_TYPE_CURSOR: - fb_bits = INTEL_FRONTBUFFER_CURSOR(intel_plane->pipe); - break; - case DRM_PLANE_TYPE_OVERLAY: - fb_bits = INTEL_FRONTBUFFER_SPRITE(intel_plane->pipe); - break; - } - - mutex_lock(&dev->struct_mutex); - i915_gem_track_fb(intel_fb_obj(p->fb), NULL, fb_bits); - mutex_unlock(&dev->struct_mutex); - } - } - - if (intel_crtc->atomic.wait_for_flips) - intel_crtc_wait_for_pending_flips(crtc); - - if (intel_crtc->atomic.disable_fbc) - intel_fbc_disable(dev); - if (intel_crtc->atomic.pre_disable_primary) - intel_pre_disable_primary(crtc); + intel_pre_plane_update(intel_crtc); if (intel_crtc->atomic.update_wm) intel_update_watermarks(crtc); @@ -13824,7 +13855,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) intel_runtime_pm_get(dev_priv); /* Perform vblank evasion around commit operation */ - if (crtc_state->active && !needs_modeset(crtc_state)) + if (crtc->state->active && !needs_modeset(crtc->state)) intel_crtc->atomic.evade = intel_pipe_update_start(intel_crtc, &intel_crtc->atomic.start_vbl_count); @@ -13838,7 +13869,6 @@ static void intel_finish_crtc_commit(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); - struct drm_plane *p; if (intel_crtc->atomic.evade) intel_pipe_update_end(intel_crtc, @@ -13846,26 +13876,7 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc) intel_runtime_pm_put(dev_priv); - if (intel_crtc->atomic.wait_vblank && intel_crtc->active) - intel_wait_for_vblank(dev, intel_crtc->pipe); - - intel_frontbuffer_flip(dev, intel_crtc->atomic.fb_bits); - - if (intel_crtc->atomic.update_fbc) { - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); - } - - if (intel_crtc->atomic.post_enable_primary) - intel_post_enable_primary(crtc); - - drm_for_each_legacy_plane(p, &dev->mode_config.plane_list) - if (intel_crtc->atomic.update_sprite_watermarks & drm_plane_index(p)) - intel_update_sprite_watermarks(p, crtc, 0, 0, 0, - false, false); - - memset(&intel_crtc->atomic, 0, sizeof(intel_crtc->atomic)); + intel_post_plane_update(intel_crtc); } /** -- cgit v1.3-6-gb490 From 61333b6075bf3b48a31fb5623a4101ed6bf393bc Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:50 +0200 Subject: drm/i915: Do not run most checks when there's no modeset. All the checks in intel_modeset_checks are only useful when a modeset occurs, because there is nothing to update otherwise. Same for power/cdclk changes, if there is no modeset they are noops. Unfortunately intel_modeset_pipe_config still gets called without modeset, because atomic hw readout isn't done yet. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 118c8acc2603..57bc49039991 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13169,18 +13169,18 @@ intel_modeset_compute_config(struct drm_atomic_state *state) struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int ret, i; + bool any_ms = false; ret = drm_atomic_helper_check_modeset(state->dev, state); if (ret) return ret; for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!crtc_state->enable && - WARN_ON(crtc_state->active)) - crtc_state->active = false; - - if (!crtc_state->enable) + if (!crtc_state->enable) { + if (needs_modeset(crtc_state)) + any_ms = true; continue; + } if (!needs_modeset(crtc_state)) { ret = drm_atomic_add_affected_connectors(state, crtc); @@ -13193,14 +13193,20 @@ intel_modeset_compute_config(struct drm_atomic_state *state) if (ret) return ret; + if (needs_modeset(crtc_state)) + any_ms = true; + intel_dump_pipe_config(to_intel_crtc(crtc), to_intel_crtc_state(crtc_state), "[modeset]"); } - ret = intel_modeset_checks(state); - if (ret) - return ret; + if (any_ms) { + ret = intel_modeset_checks(state); + + if (ret) + return ret; + } return drm_atomic_helper_check_planes(state->dev, state); } @@ -13213,6 +13219,7 @@ static int __intel_set_mode(struct drm_atomic_state *state) struct drm_crtc_state *crtc_state; int ret = 0; int i; + bool any_ms = false; ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) @@ -13221,7 +13228,11 @@ static int __intel_set_mode(struct drm_atomic_state *state) drm_atomic_helper_swap_state(dev, state); for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc->state) || !crtc_state->active) + if (!needs_modeset(crtc->state)) + continue; + + any_ms = true; + if (!crtc_state->active) continue; intel_crtc_disable_planes(crtc); @@ -13234,8 +13245,8 @@ static int __intel_set_mode(struct drm_atomic_state *state) /* The state has been swaped above, so state actually contains the * old state now. */ - - modeset_update_crtc_power_domains(state); + if (any_ms) + modeset_update_crtc_power_domains(state); /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { -- cgit v1.3-6-gb490 From d032ffa04cf7c6f7187e53125e860597bf64b11c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:51 +0200 Subject: drm/i915: Handle disabling planes better, v2. Read out the initial state, and add a quirk to force add all planes to crtc_state->plane_mask during initial commit. This will disable all planes during the initial modeset. The initial plane quirk is temporary, and will go away when hardware readout is fully atomic, and the watermark updates in intel_sprite.c are removed. Changes since v1: - Unset state->visible on !primary planes. - Do not rely on the plane->crtc pointer in intel_atomic_plane, instead assume planes are invisible until modeset. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 7 ++ drivers/gpu/drm/i915/intel_display.c | 120 ++++++++++++++++++++++++++++------- drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 106 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index c1263be8c98b..060d98b10f83 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -96,6 +96,13 @@ int intel_atomic_check(struct drm_device *dev, return -EINVAL; } + if (crtc_state && + crtc_state->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) { + ret = drm_atomic_add_affected_planes(state, &nuclear_crtc->base); + if (ret) + return ret; + } + ret = drm_atomic_helper_check_planes(dev, state); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 57bc49039991..827c5a513f86 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -109,8 +109,6 @@ static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_cr struct intel_crtc_state *crtc_state); static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state, int num_connectors); -static void intel_crtc_enable_planes(struct drm_crtc *crtc); -static void intel_crtc_disable_planes(struct drm_crtc *crtc); static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) { @@ -4850,11 +4848,11 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc) intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe)); } -static void intel_crtc_disable_planes(struct drm_crtc *crtc) +static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask) { struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_plane *intel_plane; + struct drm_plane *p; int pipe = intel_crtc->pipe; intel_crtc_wait_for_pending_flips(crtc); @@ -4862,14 +4860,9 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) intel_pre_disable_primary(crtc); intel_crtc_dpms_overlay_disable(intel_crtc); - for_each_intel_plane(dev, intel_plane) { - if (intel_plane->pipe == pipe) { - struct drm_crtc *from = intel_plane->base.crtc; - intel_plane->disable_plane(&intel_plane->base, - from ?: crtc); - } - } + drm_for_each_plane_mask(p, dev, plane_mask) + to_intel_plane(p)->disable_plane(p, crtc); /* * FIXME: Once we grow proper nuclear flip support out of this we need @@ -6289,7 +6282,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) if (!intel_crtc->active) return; - intel_crtc_disable_planes(crtc); + intel_crtc_disable_planes(crtc, crtc->state->plane_mask); dev_priv->display.crtc_disable(crtc); domains = intel_crtc->enabled_power_domains; @@ -11885,7 +11878,7 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, intel_crtc->atomic.fb_bits |= INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); - if (turn_off && is_crtc_enabled) { + if (turn_off && !mode_changed) { intel_crtc->atomic.wait_vblank = true; intel_crtc->atomic.update_sprite_watermarks |= 1 << i; @@ -11945,6 +11938,34 @@ static bool check_encoder_cloning(struct drm_atomic_state *state, return true; } +static void intel_crtc_check_initial_planes(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state) +{ + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc_state); + struct drm_plane *p; + unsigned visible_mask = 0; + + drm_for_each_plane_mask(p, crtc->dev, crtc_state->plane_mask) { + struct drm_plane_state *plane_state = + drm_atomic_get_existing_plane_state(crtc_state->state, p); + + if (WARN_ON(!plane_state)) + continue; + + if (!plane_state->fb) + crtc_state->plane_mask &= + ~(1 << drm_plane_index(p)); + else if (to_intel_plane_state(plane_state)->visible) + visible_mask |= 1 << drm_plane_index(p); + } + + if (!visible_mask) + return; + + pipe_config->quirks &= ~PIPE_CONFIG_QUIRK_INITIAL_PLANES; +} + static int intel_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { @@ -11966,6 +11987,10 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n", idx, crtc->state->active, intel_crtc->active); + /* plane mask is fixed up after all initial planes are calculated */ + if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) + intel_crtc_check_initial_planes(crtc, crtc_state); + if (mode_changed && crtc_state->enable && dev_priv->display.crtc_compute_clock && !WARN_ON(pipe_config->shared_dpll != DPLL_ID_PRIVATE)) { @@ -13182,6 +13207,20 @@ intel_modeset_compute_config(struct drm_atomic_state *state) continue; } + if (to_intel_crtc_state(crtc_state)->quirks & + PIPE_CONFIG_QUIRK_INITIAL_PLANES) { + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + return ret; + + /* + * We ought to handle i915.fastboot here. + * If no modeset is required and the primary plane has + * a fb, update the members of crtc_state as needed, + * and run the necessary updates during vblank evasion. + */ + } + if (!needs_modeset(crtc_state)) { ret = drm_atomic_add_affected_connectors(state, crtc); if (ret) @@ -13235,7 +13274,7 @@ static int __intel_set_mode(struct drm_atomic_state *state) if (!crtc_state->active) continue; - intel_crtc_disable_planes(crtc); + intel_crtc_disable_planes(crtc, crtc_state->plane_mask); dev_priv->display.crtc_disable(crtc); } @@ -15403,10 +15442,51 @@ static bool primary_get_hw_state(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - if (!crtc->active) - return false; + return !!(I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE); +} + +static void readout_plane_state(struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state) +{ + struct intel_plane *p; + struct drm_plane_state *drm_plane_state; + bool active = crtc_state->base.active; + + if (active) { + crtc_state->quirks |= PIPE_CONFIG_QUIRK_INITIAL_PLANES; + + /* apply to previous sw state too */ + to_intel_crtc_state(crtc->base.state)->quirks |= + PIPE_CONFIG_QUIRK_INITIAL_PLANES; + } - return I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE; + for_each_intel_plane(crtc->base.dev, p) { + bool visible = active; + + if (crtc->pipe != p->pipe) + continue; + + drm_plane_state = p->base.state; + if (active && p->base.type == DRM_PLANE_TYPE_PRIMARY) { + visible = primary_get_hw_state(crtc); + to_intel_plane_state(drm_plane_state)->visible = visible; + } else { + /* + * unknown state, assume it's off to force a transition + * to on when calculating state changes. + */ + to_intel_plane_state(drm_plane_state)->visible = false; + } + + if (visible) { + crtc_state->base.plane_mask |= + 1 << drm_plane_index(&p->base); + } else if (crtc_state->base.state) { + /* Make this unconditional for atomic hw readout. */ + crtc_state->base.plane_mask &= + ~(1 << drm_plane_index(&p->base)); + } + } } static void intel_modeset_readout_hw_state(struct drm_device *dev) @@ -15419,9 +15499,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) int i; for_each_intel_crtc(dev, crtc) { - struct drm_plane *primary = crtc->base.primary; - struct intel_plane_state *plane_state; - memset(crtc->config, 0, sizeof(*crtc->config)); crtc->config->base.crtc = &crtc->base; @@ -15435,8 +15512,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) crtc->base.enabled = crtc->active; crtc->base.hwmode = crtc->config->base.adjusted_mode; - plane_state = to_intel_plane_state(primary->state); - plane_state->visible = primary_get_hw_state(crtc); + readout_plane_state(crtc, to_intel_crtc_state(crtc->base.state)); DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", crtc->base.base.id, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 49ec7142b9cc..3127c9ae4b42 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -338,6 +338,7 @@ struct intel_crtc_state { */ #define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ #define PIPE_CONFIG_QUIRK_INHERITED_MODE (1<<1) /* mode inherited from firmware */ +#define PIPE_CONFIG_QUIRK_INITIAL_PLANES (1<<2) /* planes are in unknown state */ unsigned long quirks; /* Pipe source size (ie. panel fitter input size) -- cgit v1.3-6-gb490 From a539205a1628e76cbaae35c8ba64d503c6aa619b Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:52 +0200 Subject: drm/i915: atomic plane updates in a nutshell Now that all planes are added during a modeset we can use the calculated changes before disabling a plane, and then either commit or force disable a plane before disabling the crtc. The code is shared with atomic_begin/flush, except watermark updating and vblank evasion are not used. This is needed for proper atomic suspend/resume support. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90868 Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 103 ++++++++--------------------------- drivers/gpu/drm/i915/intel_sprite.c | 4 +- 2 files changed, 23 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 827c5a513f86..32fac724a2f8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2217,28 +2217,6 @@ static void intel_disable_pipe(struct intel_crtc *crtc) intel_wait_for_pipe_off(crtc); } -/** - * intel_enable_primary_hw_plane - enable the primary plane on a given pipe - * @plane: plane to be enabled - * @crtc: crtc for the plane - * - * Enable @plane on @crtc, making sure that the pipe is running first. - */ -static void intel_enable_primary_hw_plane(struct drm_plane *plane, - struct drm_crtc *crtc) -{ - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - /* If the pipe isn't enabled, we can't pump pixels and may hang */ - assert_pipe_enabled(dev_priv, intel_crtc->pipe); - to_intel_plane_state(plane->state)->visible = true; - - dev_priv->display.update_primary_plane(crtc, plane->fb, - crtc->x, crtc->y); -} - static bool need_vtd_wa(struct drm_device *dev) { #ifdef CONFIG_INTEL_IOMMU @@ -4518,20 +4496,6 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc) } } -static void intel_enable_sprite_planes(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - enum pipe pipe = to_intel_crtc(crtc)->pipe; - struct drm_plane *plane; - struct intel_plane *intel_plane; - - drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { - intel_plane = to_intel_plane(plane); - if (intel_plane->pipe == pipe) - intel_plane_restore(&intel_plane->base); - } -} - void hsw_enable_ips(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; @@ -4827,27 +4791,6 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) intel_pre_disable_primary(&crtc->base); } -static void intel_crtc_enable_planes(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; - - intel_enable_primary_hw_plane(crtc->primary, crtc); - intel_enable_sprite_planes(crtc); - if (to_intel_plane_state(crtc->cursor->state)->visible) - intel_crtc_update_cursor(crtc, true); - - intel_post_enable_primary(crtc); - - /* - * FIXME: Once we grow proper nuclear flip support out of this we need - * to compute the mask of flip planes precisely. For the time being - * consider this a flip to a NULL plane. - */ - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe)); -} - static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask) { struct drm_device *dev = crtc->dev; @@ -4855,10 +4798,6 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask struct drm_plane *p; int pipe = intel_crtc->pipe; - intel_crtc_wait_for_pending_flips(crtc); - - intel_pre_disable_primary(crtc); - intel_crtc_dpms_overlay_disable(intel_crtc); drm_for_each_plane_mask(p, dev, plane_mask) @@ -6282,6 +6221,11 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) if (!intel_crtc->active) return; + if (to_intel_plane_state(crtc->primary->state)->visible) { + intel_crtc_wait_for_pending_flips(crtc); + intel_pre_disable_primary(crtc); + } + intel_crtc_disable_planes(crtc, crtc->state->plane_mask); dev_priv->display.crtc_disable(crtc); @@ -11795,10 +11739,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, if (old_plane_state->base.fb && !fb) intel_crtc->atomic.disabled_planes |= 1 << i; - /* don't run rest during modeset yet */ - if (!intel_crtc->active || mode_changed) - return 0; - was_visible = old_plane_state->visible; visible = to_intel_plane_state(plane_state)->visible; @@ -13267,15 +13207,18 @@ static int __intel_set_mode(struct drm_atomic_state *state) drm_atomic_helper_swap_state(dev, state); for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + if (!needs_modeset(crtc->state)) continue; any_ms = true; - if (!crtc_state->active) - continue; + intel_pre_plane_update(intel_crtc); - intel_crtc_disable_planes(crtc, crtc_state->plane_mask); - dev_priv->display.crtc_disable(crtc); + if (crtc_state->active) { + intel_crtc_disable_planes(crtc, crtc_state->plane_mask); + dev_priv->display.crtc_disable(crtc); + } } /* Only after disabling all output pipelines that will be changed can we @@ -13289,15 +13232,12 @@ static int __intel_set_mode(struct drm_atomic_state *state) /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { - drm_atomic_helper_commit_planes_on_crtc(crtc_state); - - if (!needs_modeset(crtc->state) || !crtc->state->active) - continue; - - update_scanline_offset(to_intel_crtc(crtc)); + if (needs_modeset(crtc->state) && crtc->state->active) { + update_scanline_offset(to_intel_crtc(crtc)); + dev_priv->display.crtc_enable(crtc); + } - dev_priv->display.crtc_enable(crtc); - intel_crtc_enable_planes(crtc); + drm_atomic_helper_commit_planes_on_crtc(crtc_state); } /* FIXME: add subpixel order */ @@ -13871,7 +13811,7 @@ intel_commit_primary_plane(struct drm_plane *plane, crtc->x = src->x1 >> 16; crtc->y = src->y1 >> 16; - if (!intel_crtc->active) + if (!crtc->state->active) return; if (state->visible) @@ -13897,7 +13837,8 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - intel_pre_plane_update(intel_crtc); + if (!needs_modeset(crtc->state)) + intel_pre_plane_update(intel_crtc); if (intel_crtc->atomic.update_wm) intel_update_watermarks(crtc); @@ -13905,7 +13846,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) intel_runtime_pm_get(dev_priv); /* Perform vblank evasion around commit operation */ - if (crtc->state->active && !needs_modeset(crtc->state)) + if (crtc->state->active) intel_crtc->atomic.evade = intel_pipe_update_start(intel_crtc, &intel_crtc->atomic.start_vbl_count); @@ -14113,7 +14054,7 @@ intel_commit_cursor_plane(struct drm_plane *plane, intel_crtc->cursor_bo = obj; update: - if (intel_crtc->active) + if (crtc->state->active) intel_crtc_update_cursor(crtc, state->visible); } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 699311a9bdfe..b605ad848b10 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -924,16 +924,14 @@ intel_commit_sprite_plane(struct drm_plane *plane, struct intel_plane_state *state) { struct drm_crtc *crtc = state->base.crtc; - struct intel_crtc *intel_crtc; struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_framebuffer *fb = state->base.fb; crtc = crtc ? crtc : plane->crtc; - intel_crtc = to_intel_crtc(crtc); plane->fb = fb; - if (!intel_crtc->active) + if (!crtc->state->active) return; if (state->visible) { -- cgit v1.3-6-gb490 From eddfcbcdc27fbecb33bff098967bbdd7ca75bfa6 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:53 +0200 Subject: drm/i915: Update less state during modeset. No need to repeatedly call update_watermarks, or update_fbc. Down to a single call to update_watermarks in .crtc_enable Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 66 +++++++++--------------------------- 1 file changed, 16 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 32fac724a2f8..b77ecaebeea7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1945,10 +1945,10 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) /* PCH only available on ILK+ */ BUG_ON(INTEL_INFO(dev)->gen < 5); - if (WARN_ON(pll == NULL)) - return; + if (pll == NULL) + return; - if (WARN_ON(pll->config.crtc_mask == 0)) + if (WARN_ON(!(pll->config.crtc_mask & (1 << drm_crtc_index(&crtc->base))))) return; DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n", @@ -4653,10 +4653,6 @@ intel_post_enable_primary(struct drm_crtc *crtc) */ hsw_enable_ips(intel_crtc); - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); - /* * Gen2 reports pipe underruns whenever all planes are disabled. * So don't enable underrun reporting before at least some planes @@ -4711,11 +4707,6 @@ intel_pre_disable_primary(struct drm_crtc *crtc) if (HAS_GMCH_DISPLAY(dev)) intel_set_memory_cxsr(dev_priv, false); - mutex_lock(&dev->struct_mutex); - if (dev_priv->fbc.crtc == intel_crtc) - intel_fbc_disable(dev); - mutex_unlock(&dev->struct_mutex); - /* * FIXME IPS should be fine as long as one plane is * enabled, but in practice it seems to have problems @@ -4755,6 +4746,7 @@ static void intel_post_plane_update(struct intel_crtc *crtc) static void intel_pre_plane_update(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc_atomic_commit *atomic = &crtc->atomic; struct drm_plane *p; @@ -4784,8 +4776,13 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) if (atomic->wait_for_flips) intel_crtc_wait_for_pending_flips(&crtc->base); - if (atomic->disable_fbc) - intel_fbc_disable(dev); + if (atomic->disable_fbc && + dev_priv->fbc.crtc == crtc) { + mutex_lock(&dev->struct_mutex); + if (dev_priv->fbc.crtc == crtc) + intel_fbc_disable(dev); + mutex_unlock(&dev->struct_mutex); + } if (atomic->pre_disable_primary) intel_pre_disable_primary(&crtc->base); @@ -5002,9 +4999,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; u32 reg, temp; - if (WARN_ON(!intel_crtc->active)) - return; - for_each_encoder_on_crtc(dev, crtc, encoder) encoder->disable(encoder); @@ -5043,18 +5037,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) I915_WRITE(PCH_DPLL_SEL, temp); } - /* disable PCH DPLL */ - intel_disable_shared_dpll(intel_crtc); - ironlake_fdi_pll_disable(intel_crtc); } - - intel_crtc->active = false; - intel_update_watermarks(crtc); - - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); } static void haswell_crtc_disable(struct drm_crtc *crtc) @@ -5065,9 +5049,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; - if (WARN_ON(!intel_crtc->active)) - return; - for_each_encoder_on_crtc(dev, crtc, encoder) { intel_opregion_notify_encoder(encoder, false); encoder->disable(encoder); @@ -5103,16 +5084,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->post_disable) encoder->post_disable(encoder); - - intel_crtc->active = false; - intel_update_watermarks(crtc); - - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); - - if (intel_crtc_to_shared_dpll(intel_crtc)) - intel_disable_shared_dpll(intel_crtc); } static void i9xx_pfit_enable(struct intel_crtc *crtc) @@ -6166,9 +6137,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - if (WARN_ON(!intel_crtc->active)) - return; - /* * On gen2 planes are double buffered but the pipe isn't, so we must * wait for planes to fully turn off before disabling the pipe. @@ -6202,13 +6170,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) if (!IS_GEN2(dev)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); - - intel_crtc->active = false; - intel_update_watermarks(crtc); - - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); } static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) @@ -11931,6 +11892,9 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) intel_crtc_check_initial_planes(crtc, crtc_state); + if (mode_changed) + intel_crtc->atomic.update_wm = !crtc_state->active; + if (mode_changed && crtc_state->enable && dev_priv->display.crtc_compute_clock && !WARN_ON(pipe_config->shared_dpll != DPLL_ID_PRIVATE)) { @@ -13218,6 +13182,8 @@ static int __intel_set_mode(struct drm_atomic_state *state) if (crtc_state->active) { intel_crtc_disable_planes(crtc, crtc_state->plane_mask); dev_priv->display.crtc_disable(crtc); + intel_crtc->active = false; + intel_disable_shared_dpll(intel_crtc); } } -- cgit v1.3-6-gb490 From 818ed961e6ee7988829918b5dc41da14a05f5bc5 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:54 +0200 Subject: drm/i915: Make setting color key atomic. By making color key atomic there are no more transitional helpers. The plane check function will reject the color key when a scaler is active. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic_plane.c | 1 + drivers/gpu/drm/i915/intel_display.c | 7 ++- drivers/gpu/drm/i915/intel_drv.h | 6 +-- drivers/gpu/drm/i915/intel_sprite.c | 85 +++++++++++++++---------------- 4 files changed, 46 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 91d53768df9d..10a8ecedc942 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -56,6 +56,7 @@ intel_create_plane_state(struct drm_plane *plane) state->base.plane = plane; state->base.rotation = BIT(DRM_ROTATE_0); + state->ckey.flags = I915_SET_COLORKEY_NONE; return state; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b77ecaebeea7..30ffca865e1d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4411,9 +4411,9 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, return ret; /* check colorkey */ - if (WARN_ON(intel_plane->ckey.flags != I915_SET_COLORKEY_NONE)) { + if (plane_state->ckey.flags != I915_SET_COLORKEY_NONE) { DRM_DEBUG_KMS("[PLANE:%d] scaling with color key not allowed", - intel_plane->base.base.id); + intel_plane->base.base.id); return -EINVAL; } @@ -13746,7 +13746,7 @@ intel_check_primary_plane(struct drm_plane *plane, /* use scaler when colorkey is not required */ if (INTEL_INFO(plane->dev)->gen >= 9 && - to_intel_plane(plane)->ckey.flags == I915_SET_COLORKEY_NONE) { + state->ckey.flags == I915_SET_COLORKEY_NONE) { min_scale = 1; max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state); can_position = true; @@ -13892,7 +13892,6 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, primary->check_plane = intel_check_primary_plane; primary->commit_plane = intel_commit_primary_plane; primary->disable_plane = intel_disable_primary_plane; - primary->ckey.flags = I915_SET_COLORKEY_NONE; if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4) primary->plane = !pipe; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3127c9ae4b42..d48b98014080 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -274,6 +274,8 @@ struct intel_plane_state { * update_scaler_plane. */ int scaler_id; + + struct drm_intel_sprite_colorkey ckey; }; struct intel_initial_plane_config { @@ -588,9 +590,6 @@ struct intel_plane { bool can_scale; int max_downscale; - /* FIXME convert to properties */ - struct drm_intel_sprite_colorkey ckey; - /* Since we need to change the watermarks before/after * enabling/disabling the planes, we need to store the parameters here * as the other pieces of the struct may not reflect the values we want @@ -1392,7 +1391,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); /* intel_sprite.c */ int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane); -int intel_plane_restore(struct drm_plane *plane); int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); bool intel_pipe_update_start(struct intel_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index b605ad848b10..e0045aa97bd2 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -182,7 +182,8 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, const int plane = intel_plane->plane + 1; u32 plane_ctl, stride_div, stride; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey; + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(drm_plane->state)->ckey; unsigned long surf_addr; u32 tile_height, plane_offset, plane_size; unsigned int rotation; @@ -344,7 +345,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, u32 sprctl; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey; + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(dplane->state)->ckey; sprctl = SP_ENABLE; @@ -488,7 +490,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, u32 sprctl, sprscale = 0; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey; + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(plane->state)->ckey; sprctl = SPRITE_ENABLE; @@ -629,7 +632,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, unsigned long dvssurf_offset, linear_offset; u32 dvscntr, dvsscale; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey; + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(plane->state)->ckey; dvscntr = DVS_ENABLE; @@ -781,7 +785,7 @@ intel_check_sprite_plane(struct drm_plane *plane, /* setup can_scale, min_scale, max_scale */ if (INTEL_INFO(dev)->gen >= 9) { /* use scaler when colorkey is not required */ - if (intel_plane->ckey.flags == I915_SET_COLORKEY_NONE) { + if (state->ckey.flags == I915_SET_COLORKEY_NONE) { can_scale = 1; min_scale = 1; max_scale = skl_max_scale(intel_crtc, crtc_state); @@ -801,7 +805,6 @@ intel_check_sprite_plane(struct drm_plane *plane, * coordinates and sizes. We probably need some way to decide whether * more strict checking should be done instead. */ - drm_rect_rotate(src, fb->width << 16, fb->height << 16, state->base.rotation); @@ -811,7 +814,7 @@ intel_check_sprite_plane(struct drm_plane *plane, vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale); BUG_ON(vscale < 0); - state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); + state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); crtc_x = dst->x1; crtc_y = dst->y1; @@ -953,7 +956,9 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, { struct drm_intel_sprite_colorkey *set = data; struct drm_plane *plane; - struct intel_plane *intel_plane; + struct drm_plane_state *plane_state; + struct drm_atomic_state *state; + struct drm_modeset_acquire_ctx ctx; int ret = 0; /* Make sure we don't try to enable both src & dest simultaneously */ @@ -964,50 +969,41 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, set->flags & I915_SET_COLORKEY_DESTINATION) return -EINVAL; - drm_modeset_lock_all(dev); - plane = drm_plane_find(dev, set->plane_id); - if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) { - ret = -ENOENT; - goto out_unlock; - } + if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) + return -ENOENT; - intel_plane = to_intel_plane(plane); + drm_modeset_acquire_init(&ctx, 0); - if (INTEL_INFO(dev)->gen >= 9) { - /* plane scaling and colorkey are mutually exclusive */ - if (to_intel_plane_state(plane->state)->scaler_id >= 0) { - DRM_ERROR("colorkey not allowed with scaler\n"); - ret = -EINVAL; - goto out_unlock; - } + state = drm_atomic_state_alloc(plane->dev); + if (!state) { + ret = -ENOMEM; + goto out; } + state->acquire_ctx = &ctx; + + while (1) { + plane_state = drm_atomic_get_plane_state(state, plane); + ret = PTR_ERR_OR_ZERO(plane_state); + if (!ret) { + to_intel_plane_state(plane_state)->ckey = *set; + ret = drm_atomic_commit(state); + } - intel_plane->ckey = *set; - - /* - * The only way this could fail would be due to - * the current plane state being unsupportable already, - * and we dont't consider that an error for the - * colorkey ioctl. So just ignore any error. - */ - intel_plane_restore(plane); + if (ret != -EDEADLK) + break; -out_unlock: - drm_modeset_unlock_all(dev); - return ret; -} + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + } -int intel_plane_restore(struct drm_plane *plane) -{ - if (!plane->crtc || !plane->state->fb) - return 0; + if (ret) + drm_atomic_state_free(state); - return drm_plane_helper_update(plane, plane->crtc, plane->state->fb, - plane->state->crtc_x, plane->state->crtc_y, - plane->state->crtc_w, plane->state->crtc_h, - plane->state->src_x, plane->state->src_y, - plane->state->src_w, plane->state->src_h); +out: + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return ret; } static const uint32_t ilk_plane_formats[] = { @@ -1136,7 +1132,6 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) intel_plane->plane = plane; intel_plane->check_plane = intel_check_sprite_plane; intel_plane->commit_plane = intel_commit_sprite_plane; - intel_plane->ckey.flags = I915_SET_COLORKEY_NONE; possible_crtcs = (1 << pipe); ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, &intel_plane_funcs, -- cgit v1.3-6-gb490 From c389c9c4d981e49185b1c89354c85608effefe50 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:55 +0200 Subject: drm/i915: Remove transitional references from intel_plane_atomic_check. All transitional plane helpers are gone, party! Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic_plane.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 10a8ecedc942..f1ab8e4b9c11 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -115,6 +115,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, struct intel_crtc_state *crtc_state; struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_plane_state *intel_state = to_intel_plane_state(state); + struct drm_crtc_state *drm_crtc_state; int ret; crtc = crtc ? crtc : plane->state->crtc; @@ -129,19 +130,11 @@ static int intel_plane_atomic_check(struct drm_plane *plane, if (!crtc) return 0; - /* FIXME: temporary hack necessary while we still use the plane update - * helper. */ - if (state->state) { - struct drm_crtc_state *drm_crtc_state = - drm_atomic_get_existing_crtc_state(state->state, crtc); + drm_crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); + if (WARN_ON(!drm_crtc_state)) + return -EINVAL; - if (WARN_ON(!drm_crtc_state)) - return -EINVAL; - - crtc_state = to_intel_crtc_state(drm_crtc_state); - } else { - crtc_state = intel_crtc->config; - } + crtc_state = to_intel_crtc_state(drm_crtc_state); /* * The original src/dest coordinates are stored in state->base, but @@ -191,7 +184,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, intel_state->visible = false; ret = intel_plane->check_plane(plane, crtc_state, intel_state); - if (ret || !state->state) + if (ret) return ret; return intel_plane_atomic_calc_changes(&crtc_state->base, state); -- cgit v1.3-6-gb490 From 27c329ed16ddf5540151dfa9d22c584b819e0718 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:56 +0200 Subject: drm/i915: Make cdclk part of the atomic state. The skylake scalers depend on the cdclk freq, but that frequency can change during a modeset. So when a modeset happens calculate the new cdclk in the atomic state. With the transitional helpers gone the cached value can be used in the scaler, and committed after all crtc's are disabled. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90874 Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_atomic.c | 2 + drivers/gpu/drm/i915/intel_display.c | 274 +++++++++++++++++------------------ drivers/gpu/drm/i915/intel_drv.h | 1 + 4 files changed, 135 insertions(+), 145 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 290017857c6d..3e36af90f943 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -619,7 +619,8 @@ struct drm_i915_display_funcs { struct drm_crtc *crtc, uint32_t sprite_width, uint32_t sprite_height, int pixel_size, bool enable, bool scaled); - void (*modeset_global_resources)(struct drm_atomic_state *state); + int (*modeset_calc_cdclk)(struct drm_atomic_state *state); + void (*modeset_commit_cdclk)(struct drm_atomic_state *state); /* Returns the active state of the crtc, and if the crtc is active, * fills out the pipe-config with the hw state. */ bool (*get_pipe_config)(struct intel_crtc *, diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 060d98b10f83..0aeced82201e 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -54,6 +54,8 @@ int intel_atomic_check(struct drm_device *dev, int i; bool not_nuclear = false; + to_intel_atomic_state(state)->cdclk = to_i915(dev)->cdclk_freq; + /* * FIXME: At the moment, we only support "nuclear pageflip" on a * single CRTC. Cross-crtc updates will be added later. diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 30ffca865e1d..64c6c38ec8af 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5204,8 +5204,13 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) intel_display_power_get(dev_priv, domain); } - if (dev_priv->display.modeset_global_resources) - dev_priv->display.modeset_global_resources(state); + if (dev_priv->display.modeset_commit_cdclk) { + unsigned int cdclk = to_intel_atomic_state(state)->cdclk; + + if (cdclk != dev_priv->cdclk_freq && + !WARN_ON(!state->allow_modeset)) + dev_priv->display.modeset_commit_cdclk(state); + } for_each_intel_crtc(dev, crtc) { enum intel_display_power_domain domain; @@ -5859,11 +5864,7 @@ static int intel_mode_max_pixclk(struct drm_device *dev, int max_pixclk = 0; for_each_intel_crtc(dev, intel_crtc) { - if (state) - crtc_state = - intel_atomic_get_crtc_state(state, intel_crtc); - else - crtc_state = intel_crtc->config; + crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); @@ -5877,46 +5878,34 @@ static int intel_mode_max_pixclk(struct drm_device *dev, return max_pixclk; } -static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) +static int valleyview_modeset_calc_cdclk(struct drm_atomic_state *state) { - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int max_pixclk = intel_mode_max_pixclk(state->dev, state); - int cdclk, ret = 0; + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixclk = intel_mode_max_pixclk(dev, state); if (max_pixclk < 0) return max_pixclk; - if (IS_VALLEYVIEW(dev_priv)) - cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); - else - cdclk = broxton_calc_cdclk(dev_priv, max_pixclk); - - if (cdclk == dev_priv->cdclk_freq) - return 0; - - /* add all active pipes to the state */ - for_each_crtc(state->dev, crtc) { - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); + to_intel_atomic_state(state)->cdclk = + valleyview_calc_cdclk(dev_priv, max_pixclk); - if (!crtc_state->active || needs_modeset(crtc_state)) - continue; + return 0; +} - crtc_state->mode_changed = true; +static int broxton_modeset_calc_cdclk(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixclk = intel_mode_max_pixclk(dev, state); - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - break; + if (max_pixclk < 0) + return max_pixclk; - ret = drm_atomic_add_affected_planes(state, crtc); - if (ret) - break; - } + to_intel_atomic_state(state)->cdclk = + broxton_calc_cdclk(dev_priv, max_pixclk); - return ret; + return 0; } static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) @@ -5955,41 +5944,31 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) WARN_ON(I915_READ(GCI_CONTROL) & PFI_CREDIT_RESEND); } -static void valleyview_modeset_global_resources(struct drm_atomic_state *old_state) +static void valleyview_modeset_commit_cdclk(struct drm_atomic_state *old_state) { struct drm_device *dev = old_state->dev; + unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk; struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixclk = intel_mode_max_pixclk(dev, NULL); - int req_cdclk; - - /* The path in intel_mode_max_pixclk() with a NULL atomic state should - * never fail. */ - if (WARN_ON(max_pixclk < 0)) - return; - - req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); - if (req_cdclk != dev_priv->cdclk_freq) { - /* - * FIXME: We can end up here with all power domains off, yet - * with a CDCLK frequency other than the minimum. To account - * for this take the PIPE-A power domain, which covers the HW - * blocks needed for the following programming. This can be - * removed once it's guaranteed that we get here either with - * the minimum CDCLK set, or the required power domains - * enabled. - */ - intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A); + /* + * FIXME: We can end up here with all power domains off, yet + * with a CDCLK frequency other than the minimum. To account + * for this take the PIPE-A power domain, which covers the HW + * blocks needed for the following programming. This can be + * removed once it's guaranteed that we get here either with + * the minimum CDCLK set, or the required power domains + * enabled. + */ + intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A); - if (IS_CHERRYVIEW(dev)) - cherryview_set_cdclk(dev, req_cdclk); - else - valleyview_set_cdclk(dev, req_cdclk); + if (IS_CHERRYVIEW(dev)) + cherryview_set_cdclk(dev, req_cdclk); + else + valleyview_set_cdclk(dev, req_cdclk); - vlv_program_pfi_credits(dev_priv); + vlv_program_pfi_credits(dev_priv); - intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A); - } + intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A); } static void valleyview_crtc_enable(struct drm_crtc *crtc) @@ -9490,41 +9469,35 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv) intel_prepare_ddi(dev); } -static void broxton_modeset_global_resources(struct drm_atomic_state *old_state) +static void broxton_modeset_commit_cdclk(struct drm_atomic_state *old_state) { struct drm_device *dev = old_state->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixclk = intel_mode_max_pixclk(dev, NULL); - int req_cdclk; - - /* see the comment in valleyview_modeset_global_resources */ - if (WARN_ON(max_pixclk < 0)) - return; + unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk; - req_cdclk = broxton_calc_cdclk(dev_priv, max_pixclk); - - if (req_cdclk != dev_priv->cdclk_freq) - broxton_set_cdclk(dev, req_cdclk); + broxton_set_cdclk(dev, req_cdclk); } /* compute the max rate for new configuration */ -static int ilk_max_pixel_rate(struct drm_i915_private *dev_priv) +static int ilk_max_pixel_rate(struct drm_atomic_state *state) { - struct drm_device *dev = dev_priv->dev; struct intel_crtc *intel_crtc; - struct drm_crtc *crtc; + struct intel_crtc_state *crtc_state; int max_pixel_rate = 0; - int pixel_rate; - for_each_crtc(dev, crtc) { - if (!crtc->state->enable) + for_each_intel_crtc(state->dev, intel_crtc) { + int pixel_rate; + + crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (!crtc_state->base.enable) continue; - intel_crtc = to_intel_crtc(crtc); - pixel_rate = ilk_pipe_pixel_rate(intel_crtc->config); + pixel_rate = ilk_pipe_pixel_rate(crtc_state); /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ - if (IS_BROADWELL(dev) && intel_crtc->config->ips_enabled) + if (IS_BROADWELL(state->dev) && crtc_state->ips_enabled) pixel_rate = DIV_ROUND_UP(pixel_rate * 100, 95); max_pixel_rate = max(max_pixel_rate, pixel_rate); @@ -9610,20 +9583,21 @@ static void broadwell_set_cdclk(struct drm_device *dev, int cdclk) cdclk, dev_priv->cdclk_freq); } -static int broadwell_calc_cdclk(struct drm_i915_private *dev_priv, - int max_pixel_rate) +static int broadwell_modeset_calc_cdclk(struct drm_atomic_state *state) { + struct drm_i915_private *dev_priv = to_i915(state->dev); + int max_pixclk = ilk_max_pixel_rate(state); int cdclk; /* * FIXME should also account for plane ratio * once 64bpp pixel formats are supported. */ - if (max_pixel_rate > 540000) + if (max_pixclk > 540000) cdclk = 675000; - else if (max_pixel_rate > 450000) + else if (max_pixclk > 450000) cdclk = 540000; - else if (max_pixel_rate > 337500) + else if (max_pixclk > 337500) cdclk = 450000; else cdclk = 337500; @@ -9638,49 +9612,17 @@ static int broadwell_calc_cdclk(struct drm_i915_private *dev_priv, cdclk = dev_priv->max_cdclk_freq; } - return cdclk; -} - -static int broadwell_modeset_global_pipes(struct drm_atomic_state *state) -{ - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int max_pixclk = ilk_max_pixel_rate(dev_priv); - int cdclk, i; - - cdclk = broadwell_calc_cdclk(dev_priv, max_pixclk); - - if (cdclk == dev_priv->cdclk_freq) - return 0; - - /* add all active pipes to the state */ - for_each_crtc(state->dev, crtc) { - if (!crtc->state->enable) - continue; - - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - } - - /* disable/enable all currently active pipes while we change cdclk */ - for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc_state->enable) - crtc_state->mode_changed = true; + to_intel_atomic_state(state)->cdclk = cdclk; return 0; } -static void broadwell_modeset_global_resources(struct drm_atomic_state *state) +static void broadwell_modeset_commit_cdclk(struct drm_atomic_state *old_state) { - struct drm_device *dev = state->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixel_rate = ilk_max_pixel_rate(dev_priv); - int req_cdclk = broadwell_calc_cdclk(dev_priv, max_pixel_rate); + struct drm_device *dev = old_state->dev; + unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk; - if (req_cdclk != dev_priv->cdclk_freq) - broadwell_set_cdclk(dev, req_cdclk); + broadwell_set_cdclk(dev, req_cdclk); } static int haswell_crtc_compute_clock(struct intel_crtc *crtc, @@ -13056,10 +12998,41 @@ static int haswell_mode_set_planes_workaround(struct drm_atomic_state *state) return 0; } +static int intel_modeset_all_pipes(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int ret = 0; + + /* add all active pipes to the state */ + for_each_crtc(state->dev, crtc) { + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (!crtc_state->active || needs_modeset(crtc_state)) + continue; + + crtc_state->mode_changed = true; + + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + break; + + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + break; + } + + return ret; +} + + /* Code that should eventually be part of atomic_check() */ static int intel_modeset_checks(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; if (!check_digital_port_conflicts(state)) { @@ -13074,15 +13047,19 @@ static int intel_modeset_checks(struct drm_atomic_state *state) * mode set on this crtc. For other crtcs we need to use the * adjusted_mode bits in the crtc directly. */ - if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev) || IS_BROADWELL(dev)) { - if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) - ret = valleyview_modeset_global_pipes(state); - else - ret = broadwell_modeset_global_pipes(state); + if (dev_priv->display.modeset_calc_cdclk) { + unsigned int cdclk; - if (ret) + ret = dev_priv->display.modeset_calc_cdclk(state); + + cdclk = to_intel_atomic_state(state)->cdclk; + if (!ret && cdclk != dev_priv->cdclk_freq) + ret = intel_modeset_all_pipes(state); + + if (ret < 0) return ret; - } + } else + to_intel_atomic_state(state)->cdclk = dev_priv->cdclk_freq; intel_modeset_clear_plls(state); @@ -13149,7 +13126,9 @@ intel_modeset_compute_config(struct drm_atomic_state *state) if (ret) return ret; - } + } else + to_intel_atomic_state(state)->cdclk = + to_i915(state->dev)->cdclk_freq; return drm_atomic_helper_check_planes(state->dev, state); } @@ -13717,7 +13696,7 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state dev = intel_crtc->base.dev; dev_priv = dev->dev_private; crtc_clock = crtc_state->base.adjusted_mode.crtc_clock; - cdclk = dev_priv->display.get_display_clock_speed(dev); + cdclk = to_intel_atomic_state(crtc_state->base.state)->cdclk; if (!crtc_clock || !cdclk) return DRM_PLANE_HELPER_NO_SCALING; @@ -14786,15 +14765,22 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; - if (IS_BROADWELL(dev)) - dev_priv->display.modeset_global_resources = - broadwell_modeset_global_resources; + if (IS_BROADWELL(dev)) { + dev_priv->display.modeset_commit_cdclk = + broadwell_modeset_commit_cdclk; + dev_priv->display.modeset_calc_cdclk = + broadwell_modeset_calc_cdclk; + } } else if (IS_VALLEYVIEW(dev)) { - dev_priv->display.modeset_global_resources = - valleyview_modeset_global_resources; + dev_priv->display.modeset_commit_cdclk = + valleyview_modeset_commit_cdclk; + dev_priv->display.modeset_calc_cdclk = + valleyview_modeset_calc_cdclk; } else if (IS_BROXTON(dev)) { - dev_priv->display.modeset_global_resources = - broxton_modeset_global_resources; + dev_priv->display.modeset_commit_cdclk = + broxton_modeset_commit_cdclk; + dev_priv->display.modeset_calc_cdclk = + broxton_modeset_calc_cdclk; } switch (INTEL_INFO(dev)->gen) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d48b98014080..853bfd98ef72 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -244,6 +244,7 @@ typedef struct dpll { struct intel_atomic_state { struct drm_atomic_state base; + unsigned int cdclk; bool dpll_set; struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS]; }; -- cgit v1.3-6-gb490 From a0049865ea53df19a3f14128fa080719e8f4bdba Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jun 2015 13:06:13 +0300 Subject: drm/i915/irq: move hotplug even debug print to second connector loop The hotplug work function has two loops iterating over connectors, the first for handling hotplug disabling due to irq storms and the second for actually handling the hotplug events. Move the debug printing into the second one, so we can abstract the storm handling better. This may change the output ordering slightly when there are multiple simultaneous hotplug events. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 56db9e747464..d64d6895a2e5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -917,10 +917,6 @@ static void i915_hotplug_work_func(struct work_struct *work) | DRM_CONNECTOR_POLL_DISCONNECT; hpd_disabled = true; } - if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { - DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", - connector->name, intel_encoder->hpd_pin); - } } /* if there were no outputs to poll, poll was disabled, * therefore make sure it's enabled when disabling HPD on @@ -939,6 +935,8 @@ static void i915_hotplug_work_func(struct work_struct *work) continue; intel_encoder = intel_connector->encoder; if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { + DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", + connector->name, intel_encoder->hpd_pin); if (intel_encoder->hot_plug) intel_encoder->hot_plug(intel_encoder); if (intel_hpd_irq_event(dev, connector)) -- cgit v1.3-6-gb490 From 70f71d5ff465965e2cfdb6f3f195a7b3fe2ab5cc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jun 2015 13:06:14 +0300 Subject: drm/i915/irq: abstract irq storm hotplug disabling Continue abstracting hotplug storm related functions to clarify the code. This time, abstract hotplug irq storm related hotplug disabling. While at it, clean up the loop iterating over connectors for readability. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 77 ++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d64d6895a2e5..bf4c15d0ea2b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -879,7 +879,7 @@ static void i915_digport_work_func(struct work_struct *work) /* * Handle hotplug events outside the interrupt handler proper. */ -#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) +static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv); static void i915_hotplug_work_func(struct work_struct *work) { @@ -890,7 +890,6 @@ static void i915_hotplug_work_func(struct work_struct *work) struct intel_connector *intel_connector; struct intel_encoder *intel_encoder; struct drm_connector *connector; - bool hpd_disabled = false; bool changed = false; u32 hpd_event_bits; @@ -901,31 +900,9 @@ static void i915_hotplug_work_func(struct work_struct *work) hpd_event_bits = dev_priv->hotplug.event_bits; dev_priv->hotplug.event_bits = 0; - list_for_each_entry(connector, &mode_config->connector_list, head) { - intel_connector = to_intel_connector(connector); - if (!intel_connector->encoder) - continue; - intel_encoder = intel_connector->encoder; - if (intel_encoder->hpd_pin > HPD_NONE && - dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_MARK_DISABLED && - connector->polled == DRM_CONNECTOR_POLL_HPD) { - DRM_INFO("HPD interrupt storm detected on connector %s: " - "switching from hotplug detection to polling\n", - connector->name); - dev_priv->hotplug.stats[intel_encoder->hpd_pin].state = HPD_DISABLED; - connector->polled = DRM_CONNECTOR_POLL_CONNECT - | DRM_CONNECTOR_POLL_DISCONNECT; - hpd_disabled = true; - } - } - /* if there were no outputs to poll, poll was disabled, - * therefore make sure it's enabled when disabling HPD on - * some connectors */ - if (hpd_disabled) { - drm_kms_helper_poll_enable(dev); - mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, - msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); - } + + /* Disable hotplug on connectors that hit an irq storm. */ + intel_hpd_irq_storm_disable(dev_priv); spin_unlock_irq(&dev_priv->irq_lock); @@ -1411,6 +1388,52 @@ static bool intel_hpd_irq_storm(struct drm_i915_private *dev_priv, return storm; } +#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) + +static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_connector *intel_connector; + struct intel_encoder *intel_encoder; + struct drm_connector *connector; + enum hpd_pin pin; + bool hpd_disabled = false; + + assert_spin_locked(&dev_priv->irq_lock); + + list_for_each_entry(connector, &mode_config->connector_list, head) { + if (connector->polled != DRM_CONNECTOR_POLL_HPD) + continue; + + intel_connector = to_intel_connector(connector); + intel_encoder = intel_connector->encoder; + if (!intel_encoder) + continue; + + pin = intel_encoder->hpd_pin; + if (pin == HPD_NONE || + dev_priv->hotplug.stats[pin].state != HPD_MARK_DISABLED) + continue; + + DRM_INFO("HPD interrupt storm detected on connector %s: " + "switching from hotplug detection to polling\n", + connector->name); + + dev_priv->hotplug.stats[pin].state = HPD_DISABLED; + connector->polled = DRM_CONNECTOR_POLL_CONNECT + | DRM_CONNECTOR_POLL_DISCONNECT; + hpd_disabled = true; + } + + /* Enable polling and queue hotplug re-enabling. */ + if (hpd_disabled) { + drm_kms_helper_poll_enable(dev); + mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); + } +} + static bool pch_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { -- cgit v1.3-6-gb490 From 10b0e9e904c409be8e2476058d9b19a6b37d619e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jun 2015 13:06:15 +0300 Subject: drm/i915/irq: clarify irq storm related function naming We'll have three functions: intel_hpd_irq_storm_detect for detecting irq storms, intel_hpd_irq_storm_disable for disabling hotplugs after detected storms, intel_hpd_irq_storm_reenable_work for re-enabling hotplug. No functional changes. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index bf4c15d0ea2b..ce9eef5f722c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1350,7 +1350,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, #define HPD_STORM_THRESHOLD 5 /** - * intel_hpd_irq_storm - gather stats and detect HPD irq storm on a pin + * intel_hpd_irq_storm_detect - gather stats and detect HPD irq storm on a pin * @dev_priv: private driver data pointer * @pin: the pin to gather stats on * @@ -1364,8 +1364,8 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, * * Return true if an irq storm was detected on @pin. */ -static bool intel_hpd_irq_storm(struct drm_i915_private *dev_priv, - enum hpd_pin pin) +static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, + enum hpd_pin pin) { unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies; unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); @@ -1603,7 +1603,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, queue_hp = true; } - if (intel_hpd_irq_storm(dev_priv, i)) { + if (intel_hpd_irq_storm_detect(dev_priv, i)) { dev_priv->hotplug.event_bits &= ~BIT(i); storm_detected = true; } @@ -4367,7 +4367,7 @@ static void i965_irq_uninstall(struct drm_device * dev) I915_WRITE(IIR, I915_READ(IIR)); } -static void intel_hpd_irq_reenable_work(struct work_struct *work) +static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) { struct drm_i915_private *dev_priv = container_of(work, typeof(*dev_priv), @@ -4433,7 +4433,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work, i915_hangcheck_elapsed); INIT_DELAYED_WORK(&dev_priv->hotplug.reenable_work, - intel_hpd_irq_reenable_work); + intel_hpd_irq_storm_reenable_work); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); -- cgit v1.3-6-gb490 From 77913b39addfaa836929815515ff55cea1142b66 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jun 2015 13:06:16 +0300 Subject: drm/i915: move generic hotplug code into new intel_hotplug.c file We have enough generic hotplug functions sprinkled all over i915_irq.c to warrant moving them to a file of their own. This should further underline the distinction between generic code in the new file and platform specific hotplug and irq code that remains in i915_irq.c. Add new intel_hpd_init_work to keep work functions static, and rename get_port_from_pin to intel_hpd_pin_to_port while increasing its visibility, but keep everything else the same. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.c | 15 -- drivers/gpu/drm/i915/i915_drv.h | 9 +- drivers/gpu/drm/i915/i915_irq.c | 409 +------------------------------ drivers/gpu/drm/i915/intel_hotplug.c | 452 +++++++++++++++++++++++++++++++++++ 5 files changed, 464 insertions(+), 422 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_hotplug.c (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index b7ddf48e1d75..de2196543367 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -34,6 +34,7 @@ i915-y += i915_cmd_parser.o \ i915_gpu_error.o \ i915_irq.o \ i915_trace_points.o \ + intel_hotplug.o \ intel_lrc.o \ intel_ringbuffer.o \ intel_uncore.o diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 78ef0bb53c36..0ec57bad454f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -541,21 +541,6 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) return true; } -void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) -{ - spin_lock_irq(&dev_priv->irq_lock); - - dev_priv->hotplug.long_port_mask = 0; - dev_priv->hotplug.short_port_mask = 0; - dev_priv->hotplug.event_bits = 0; - - spin_unlock_irq(&dev_priv->irq_lock); - - cancel_work_sync(&dev_priv->hotplug.dig_port_work); - cancel_work_sync(&dev_priv->hotplug.hotplug_work); - cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work); -} - void i915_firmware_load_error_print(const char *fw_path, int err) { DRM_ERROR("failed to load firmware %s (%d)\n", fw_path, err); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3e36af90f943..c3b9fcf301a0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2601,9 +2601,15 @@ extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on); -void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); void i915_firmware_load_error_print(const char *fw_path, int err); +/* intel_hotplug.c */ +void intel_hpd_irq_handler(struct drm_device *dev, u32 pin_mask, u32 long_mask); +void intel_hpd_init(struct drm_i915_private *dev_priv); +void intel_hpd_init_work(struct drm_i915_private *dev_priv); +void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); +enum port intel_hpd_pin_to_port(enum hpd_pin pin); + /* i915_irq.c */ void i915_queue_hangcheck(struct drm_device *dev); __printf(3, 4) @@ -2611,7 +2617,6 @@ void i915_handle_error(struct drm_device *dev, bool wedged, const char *fmt, ...); extern void intel_irq_init(struct drm_i915_private *dev_priv); -extern void intel_hpd_init(struct drm_i915_private *dev_priv); int intel_irq_install(struct drm_i915_private *dev_priv); void intel_irq_uninstall(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 ce9eef5f722c..2d3b2ccf9ce4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -807,125 +807,6 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, &crtc->hwmode); } -static bool intel_hpd_irq_event(struct drm_device *dev, - struct drm_connector *connector) -{ - enum drm_connector_status old_status; - - WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); - old_status = connector->status; - - connector->status = connector->funcs->detect(connector, false); - if (old_status == connector->status) - return false; - - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", - connector->base.id, - connector->name, - drm_get_connector_status_name(old_status), - drm_get_connector_status_name(connector->status)); - - return true; -} - -static void i915_digport_work_func(struct work_struct *work) -{ - struct drm_i915_private *dev_priv = - container_of(work, struct drm_i915_private, hotplug.dig_port_work); - u32 long_port_mask, short_port_mask; - struct intel_digital_port *intel_dig_port; - int i; - u32 old_bits = 0; - - spin_lock_irq(&dev_priv->irq_lock); - long_port_mask = dev_priv->hotplug.long_port_mask; - dev_priv->hotplug.long_port_mask = 0; - short_port_mask = dev_priv->hotplug.short_port_mask; - dev_priv->hotplug.short_port_mask = 0; - spin_unlock_irq(&dev_priv->irq_lock); - - for (i = 0; i < I915_MAX_PORTS; i++) { - bool valid = false; - bool long_hpd = false; - intel_dig_port = dev_priv->hotplug.irq_port[i]; - if (!intel_dig_port || !intel_dig_port->hpd_pulse) - continue; - - if (long_port_mask & (1 << i)) { - valid = true; - long_hpd = true; - } else if (short_port_mask & (1 << i)) - valid = true; - - if (valid) { - enum irqreturn ret; - - ret = intel_dig_port->hpd_pulse(intel_dig_port, long_hpd); - if (ret == IRQ_NONE) { - /* fall back to old school hpd */ - old_bits |= (1 << intel_dig_port->base.hpd_pin); - } - } - } - - if (old_bits) { - spin_lock_irq(&dev_priv->irq_lock); - dev_priv->hotplug.event_bits |= old_bits; - spin_unlock_irq(&dev_priv->irq_lock); - schedule_work(&dev_priv->hotplug.hotplug_work); - } -} - -/* - * Handle hotplug events outside the interrupt handler proper. - */ -static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv); - -static void i915_hotplug_work_func(struct work_struct *work) -{ - struct drm_i915_private *dev_priv = - container_of(work, struct drm_i915_private, hotplug.hotplug_work); - struct drm_device *dev = dev_priv->dev; - struct drm_mode_config *mode_config = &dev->mode_config; - struct intel_connector *intel_connector; - struct intel_encoder *intel_encoder; - struct drm_connector *connector; - bool changed = false; - u32 hpd_event_bits; - - mutex_lock(&mode_config->mutex); - DRM_DEBUG_KMS("running encoder hotplug functions\n"); - - spin_lock_irq(&dev_priv->irq_lock); - - hpd_event_bits = dev_priv->hotplug.event_bits; - dev_priv->hotplug.event_bits = 0; - - /* Disable hotplug on connectors that hit an irq storm. */ - intel_hpd_irq_storm_disable(dev_priv); - - spin_unlock_irq(&dev_priv->irq_lock); - - list_for_each_entry(connector, &mode_config->connector_list, head) { - intel_connector = to_intel_connector(connector); - if (!intel_connector->encoder) - continue; - intel_encoder = intel_connector->encoder; - if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { - DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", - connector->name, intel_encoder->hpd_pin); - if (intel_encoder->hot_plug) - intel_encoder->hot_plug(intel_encoder); - if (intel_hpd_irq_event(dev, connector)) - changed = true; - } - } - mutex_unlock(&mode_config->mutex); - - if (changed) - drm_kms_helper_hotplug_event(dev); -} - static void ironlake_rps_change_irq_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1346,94 +1227,6 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, return ret; } -#define HPD_STORM_DETECT_PERIOD 1000 -#define HPD_STORM_THRESHOLD 5 - -/** - * intel_hpd_irq_storm_detect - gather stats and detect HPD irq storm on a pin - * @dev_priv: private driver data pointer - * @pin: the pin to gather stats on - * - * Gather stats about HPD irqs from the specified @pin, and detect irq - * storms. Only the pin specific stats and state are changed, the caller is - * responsible for further action. - * - * @HPD_STORM_THRESHOLD irqs are allowed within @HPD_STORM_DETECT_PERIOD ms, - * otherwise it's considered an irq storm, and the irq state is set to - * @HPD_MARK_DISABLED. - * - * Return true if an irq storm was detected on @pin. - */ -static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, - enum hpd_pin pin) -{ - unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies; - unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); - bool storm = false; - - if (!time_in_range(jiffies, start, end)) { - dev_priv->hotplug.stats[pin].last_jiffies = jiffies; - dev_priv->hotplug.stats[pin].count = 0; - DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", pin); - } else if (dev_priv->hotplug.stats[pin].count > HPD_STORM_THRESHOLD) { - dev_priv->hotplug.stats[pin].state = HPD_MARK_DISABLED; - DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin); - storm = true; - } else { - dev_priv->hotplug.stats[pin].count++; - DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin, - dev_priv->hotplug.stats[pin].count); - } - - return storm; -} - -#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) - -static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv) -{ - struct drm_device *dev = dev_priv->dev; - struct drm_mode_config *mode_config = &dev->mode_config; - struct intel_connector *intel_connector; - struct intel_encoder *intel_encoder; - struct drm_connector *connector; - enum hpd_pin pin; - bool hpd_disabled = false; - - assert_spin_locked(&dev_priv->irq_lock); - - list_for_each_entry(connector, &mode_config->connector_list, head) { - if (connector->polled != DRM_CONNECTOR_POLL_HPD) - continue; - - intel_connector = to_intel_connector(connector); - intel_encoder = intel_connector->encoder; - if (!intel_encoder) - continue; - - pin = intel_encoder->hpd_pin; - if (pin == HPD_NONE || - dev_priv->hotplug.stats[pin].state != HPD_MARK_DISABLED) - continue; - - DRM_INFO("HPD interrupt storm detected on connector %s: " - "switching from hotplug detection to polling\n", - connector->name); - - dev_priv->hotplug.stats[pin].state = HPD_DISABLED; - connector->polled = DRM_CONNECTOR_POLL_CONNECT - | DRM_CONNECTOR_POLL_DISCONNECT; - hpd_disabled = true; - } - - /* Enable polling and queue hotplug re-enabling. */ - if (hpd_disabled) { - drm_kms_helper_poll_enable(dev); - mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, - msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); - } -} - static bool pch_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { @@ -1462,20 +1255,6 @@ static bool i9xx_port_hotplug_long_detect(enum port port, u32 val) } } -static enum port get_port_from_pin(enum hpd_pin pin) -{ - switch (pin) { - case HPD_PORT_B: - return PORT_B; - case HPD_PORT_C: - return PORT_C; - case HPD_PORT_D: - return PORT_D; - default: - return PORT_A; /* no hpd */ - } -} - /* Get a bit mask of pins that have triggered, and which ones may be long. */ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, u32 hotplug_trigger, u32 dig_hotplug_reg, const u32 hpd[HPD_NUM_PINS]) @@ -1492,7 +1271,7 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, if (hpd[i] & hotplug_trigger) { *pin_mask |= BIT(i); - if (pch_port_hotplug_long_detect(get_port_from_pin(i), dig_hotplug_reg)) + if (pch_port_hotplug_long_detect(intel_hpd_pin_to_port(i), dig_hotplug_reg)) *long_mask |= BIT(i); } } @@ -1518,7 +1297,7 @@ static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, if (hpd[i] & hotplug_trigger) { *pin_mask |= BIT(i); - if (i9xx_port_hotplug_long_detect(get_port_from_pin(i), hotplug_trigger)) + if (i9xx_port_hotplug_long_detect(intel_hpd_pin_to_port(i), hotplug_trigger)) *long_mask |= BIT(i); } } @@ -1527,104 +1306,6 @@ static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, hotplug_trigger, *pin_mask); } -/** - * intel_hpd_irq_handler - main hotplug irq handler - * @dev: drm device - * @pin_mask: a mask of hpd pins that have triggered the irq - * @long_mask: a mask of hpd pins that may be long hpd pulses - * - * This is the main hotplug irq handler for all platforms. The platform specific - * irq handlers call the platform specific hotplug irq handlers, which read and - * decode the appropriate registers into bitmasks about hpd pins that have - * triggered (@pin_mask), and which of those pins may be long pulses - * (@long_mask). The @long_mask is ignored if the port corresponding to the pin - * is not a digital port. - * - * Here, we do hotplug irq storm detection and mitigation, and pass further - * processing to appropriate bottom halves. - */ -static void intel_hpd_irq_handler(struct drm_device *dev, - u32 pin_mask, u32 long_mask) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - enum port port; - bool storm_detected = false; - bool queue_dig = false, queue_hp = false; - bool is_dig_port; - - if (!pin_mask) - return; - - spin_lock(&dev_priv->irq_lock); - for_each_hpd_pin(i) { - if (!(BIT(i) & pin_mask)) - continue; - - port = get_port_from_pin(i); - is_dig_port = port && dev_priv->hotplug.irq_port[port]; - - if (is_dig_port) { - bool long_hpd = long_mask & BIT(i); - - DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), - long_hpd ? "long" : "short"); - /* - * For long HPD pulses we want to have the digital queue happen, - * but we still want HPD storm detection to function. - */ - queue_dig = true; - if (long_hpd) { - dev_priv->hotplug.long_port_mask |= (1 << port); - } else { - /* for short HPD just trigger the digital queue */ - dev_priv->hotplug.short_port_mask |= (1 << port); - continue; - } - } - - if (dev_priv->hotplug.stats[i].state == HPD_DISABLED) { - /* - * On GMCH platforms the interrupt mask bits only - * prevent irq generation, not the setting of the - * hotplug bits itself. So only WARN about unexpected - * interrupts on saner platforms. - */ - WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev), - "Received HPD interrupt on pin %d although disabled\n", i); - continue; - } - - if (dev_priv->hotplug.stats[i].state != HPD_ENABLED) - continue; - - if (!is_dig_port) { - dev_priv->hotplug.event_bits |= BIT(i); - queue_hp = true; - } - - if (intel_hpd_irq_storm_detect(dev_priv, i)) { - dev_priv->hotplug.event_bits &= ~BIT(i); - storm_detected = true; - } - } - - if (storm_detected) - dev_priv->display.hpd_irq_setup(dev); - spin_unlock(&dev_priv->irq_lock); - - /* - * Our hotplug handler can grab modeset locks (by calling down into the - * fb helpers). Hence it must not be run on our own dev-priv->wq work - * queue for otherwise the flush_work in the pageflip code will - * deadlock. - */ - if (queue_dig) - queue_work(dev_priv->hotplug.dp_wq, &dev_priv->hotplug.dig_port_work); - if (queue_hp) - schedule_work(&dev_priv->hotplug.hotplug_work); -} - static void gmbus_irq_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -4367,46 +4048,6 @@ static void i965_irq_uninstall(struct drm_device * dev) I915_WRITE(IIR, I915_READ(IIR)); } -static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) -{ - struct drm_i915_private *dev_priv = - container_of(work, typeof(*dev_priv), - hotplug.reenable_work.work); - struct drm_device *dev = dev_priv->dev; - struct drm_mode_config *mode_config = &dev->mode_config; - int i; - - intel_runtime_pm_get(dev_priv); - - spin_lock_irq(&dev_priv->irq_lock); - for_each_hpd_pin(i) { - struct drm_connector *connector; - - if (dev_priv->hotplug.stats[i].state != HPD_DISABLED) - continue; - - dev_priv->hotplug.stats[i].state = HPD_ENABLED; - - list_for_each_entry(connector, &mode_config->connector_list, head) { - struct intel_connector *intel_connector = to_intel_connector(connector); - - if (intel_connector->encoder->hpd_pin == i) { - if (connector->polled != intel_connector->polled) - DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", - connector->name); - connector->polled = intel_connector->polled; - if (!connector->polled) - connector->polled = DRM_CONNECTOR_POLL_HPD; - } - } - } - if (dev_priv->display.hpd_irq_setup) - dev_priv->display.hpd_irq_setup(dev); - spin_unlock_irq(&dev_priv->irq_lock); - - intel_runtime_pm_put(dev_priv); -} - /** * intel_irq_init - initializes irq support * @dev_priv: i915 device instance @@ -4418,8 +4059,8 @@ void intel_irq_init(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; - INIT_WORK(&dev_priv->hotplug.hotplug_work, i915_hotplug_work_func); - INIT_WORK(&dev_priv->hotplug.dig_port_work, i915_digport_work_func); + intel_hpd_init_work(dev_priv); + INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); @@ -4432,8 +4073,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv) INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work, i915_hangcheck_elapsed); - INIT_DELAYED_WORK(&dev_priv->hotplug.reenable_work, - intel_hpd_irq_storm_reenable_work); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); @@ -4518,46 +4157,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv) } } -/** - * intel_hpd_init - initializes and enables hpd support - * @dev_priv: i915 device instance - * - * This function enables the hotplug support. It requires that interrupts have - * already been enabled with intel_irq_init_hw(). From this point on hotplug and - * poll request can run concurrently to other code, so locking rules must be - * obeyed. - * - * This is a separate step from interrupt enabling to simplify the locking rules - * in the driver load and resume code. - */ -void intel_hpd_init(struct drm_i915_private *dev_priv) -{ - struct drm_device *dev = dev_priv->dev; - struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_connector *connector; - int i; - - for_each_hpd_pin(i) { - dev_priv->hotplug.stats[i].count = 0; - dev_priv->hotplug.stats[i].state = HPD_ENABLED; - } - list_for_each_entry(connector, &mode_config->connector_list, head) { - struct intel_connector *intel_connector = to_intel_connector(connector); - connector->polled = intel_connector->polled; - if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) - connector->polled = DRM_CONNECTOR_POLL_HPD; - if (intel_connector->mst_port) - connector->polled = DRM_CONNECTOR_POLL_HPD; - } - - /* Interrupt setup is already guaranteed to be single-threaded, this is - * just to make the assert_spin_locked checks happy. */ - spin_lock_irq(&dev_priv->irq_lock); - if (dev_priv->display.hpd_irq_setup) - dev_priv->display.hpd_irq_setup(dev); - spin_unlock_irq(&dev_priv->irq_lock); -} - /** * intel_irq_install - enables the hardware interrupt * @dev_priv: i915 device instance diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c new file mode 100644 index 000000000000..3c53aac71d98 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -0,0 +1,452 @@ +/* + * Copyright © 2015 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. + */ + +#include + +#include +#include + +#include "i915_drv.h" +#include "intel_drv.h" + +enum port intel_hpd_pin_to_port(enum hpd_pin pin) +{ + switch (pin) { + case HPD_PORT_B: + return PORT_B; + case HPD_PORT_C: + return PORT_C; + case HPD_PORT_D: + return PORT_D; + default: + return PORT_A; /* no hpd */ + } +} + +#define HPD_STORM_DETECT_PERIOD 1000 +#define HPD_STORM_THRESHOLD 5 +#define HPD_STORM_REENABLE_DELAY (2 * 60 * 1000) + +/** + * intel_hpd_irq_storm_detect - gather stats and detect HPD irq storm on a pin + * @dev_priv: private driver data pointer + * @pin: the pin to gather stats on + * + * Gather stats about HPD irqs from the specified @pin, and detect irq + * storms. Only the pin specific stats and state are changed, the caller is + * responsible for further action. + * + * @HPD_STORM_THRESHOLD irqs are allowed within @HPD_STORM_DETECT_PERIOD ms, + * otherwise it's considered an irq storm, and the irq state is set to + * @HPD_MARK_DISABLED. + * + * Return true if an irq storm was detected on @pin. + */ +static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, + enum hpd_pin pin) +{ + unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies; + unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); + bool storm = false; + + if (!time_in_range(jiffies, start, end)) { + dev_priv->hotplug.stats[pin].last_jiffies = jiffies; + dev_priv->hotplug.stats[pin].count = 0; + DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", pin); + } else if (dev_priv->hotplug.stats[pin].count > HPD_STORM_THRESHOLD) { + dev_priv->hotplug.stats[pin].state = HPD_MARK_DISABLED; + DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin); + storm = true; + } else { + dev_priv->hotplug.stats[pin].count++; + DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin, + dev_priv->hotplug.stats[pin].count); + } + + return storm; +} + +static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_connector *intel_connector; + struct intel_encoder *intel_encoder; + struct drm_connector *connector; + enum hpd_pin pin; + bool hpd_disabled = false; + + assert_spin_locked(&dev_priv->irq_lock); + + list_for_each_entry(connector, &mode_config->connector_list, head) { + if (connector->polled != DRM_CONNECTOR_POLL_HPD) + continue; + + intel_connector = to_intel_connector(connector); + intel_encoder = intel_connector->encoder; + if (!intel_encoder) + continue; + + pin = intel_encoder->hpd_pin; + if (pin == HPD_NONE || + dev_priv->hotplug.stats[pin].state != HPD_MARK_DISABLED) + continue; + + DRM_INFO("HPD interrupt storm detected on connector %s: " + "switching from hotplug detection to polling\n", + connector->name); + + dev_priv->hotplug.stats[pin].state = HPD_DISABLED; + connector->polled = DRM_CONNECTOR_POLL_CONNECT + | DRM_CONNECTOR_POLL_DISCONNECT; + hpd_disabled = true; + } + + /* Enable polling and queue hotplug re-enabling. */ + if (hpd_disabled) { + drm_kms_helper_poll_enable(dev); + mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, + msecs_to_jiffies(HPD_STORM_REENABLE_DELAY)); + } +} + +static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, typeof(*dev_priv), + hotplug.reenable_work.work); + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + int i; + + intel_runtime_pm_get(dev_priv); + + spin_lock_irq(&dev_priv->irq_lock); + for_each_hpd_pin(i) { + struct drm_connector *connector; + + if (dev_priv->hotplug.stats[i].state != HPD_DISABLED) + continue; + + dev_priv->hotplug.stats[i].state = HPD_ENABLED; + + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_connector *intel_connector = to_intel_connector(connector); + + if (intel_connector->encoder->hpd_pin == i) { + if (connector->polled != intel_connector->polled) + DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", + connector->name); + connector->polled = intel_connector->polled; + if (!connector->polled) + connector->polled = DRM_CONNECTOR_POLL_HPD; + } + } + } + if (dev_priv->display.hpd_irq_setup) + dev_priv->display.hpd_irq_setup(dev); + spin_unlock_irq(&dev_priv->irq_lock); + + intel_runtime_pm_put(dev_priv); +} + +static bool intel_hpd_irq_event(struct drm_device *dev, + struct drm_connector *connector) +{ + enum drm_connector_status old_status; + + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + old_status = connector->status; + + connector->status = connector->funcs->detect(connector, false); + if (old_status == connector->status) + return false; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", + connector->base.id, + connector->name, + drm_get_connector_status_name(old_status), + drm_get_connector_status_name(connector->status)); + + return true; +} + +static void i915_digport_work_func(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, struct drm_i915_private, hotplug.dig_port_work); + u32 long_port_mask, short_port_mask; + struct intel_digital_port *intel_dig_port; + int i; + u32 old_bits = 0; + + spin_lock_irq(&dev_priv->irq_lock); + long_port_mask = dev_priv->hotplug.long_port_mask; + dev_priv->hotplug.long_port_mask = 0; + short_port_mask = dev_priv->hotplug.short_port_mask; + dev_priv->hotplug.short_port_mask = 0; + spin_unlock_irq(&dev_priv->irq_lock); + + for (i = 0; i < I915_MAX_PORTS; i++) { + bool valid = false; + bool long_hpd = false; + intel_dig_port = dev_priv->hotplug.irq_port[i]; + if (!intel_dig_port || !intel_dig_port->hpd_pulse) + continue; + + if (long_port_mask & (1 << i)) { + valid = true; + long_hpd = true; + } else if (short_port_mask & (1 << i)) + valid = true; + + if (valid) { + enum irqreturn ret; + + ret = intel_dig_port->hpd_pulse(intel_dig_port, long_hpd); + if (ret == IRQ_NONE) { + /* fall back to old school hpd */ + old_bits |= (1 << intel_dig_port->base.hpd_pin); + } + } + } + + if (old_bits) { + spin_lock_irq(&dev_priv->irq_lock); + dev_priv->hotplug.event_bits |= old_bits; + spin_unlock_irq(&dev_priv->irq_lock); + schedule_work(&dev_priv->hotplug.hotplug_work); + } +} + +/* + * Handle hotplug events outside the interrupt handler proper. + */ +static void i915_hotplug_work_func(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, struct drm_i915_private, hotplug.hotplug_work); + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_connector *intel_connector; + struct intel_encoder *intel_encoder; + struct drm_connector *connector; + bool changed = false; + u32 hpd_event_bits; + + mutex_lock(&mode_config->mutex); + DRM_DEBUG_KMS("running encoder hotplug functions\n"); + + spin_lock_irq(&dev_priv->irq_lock); + + hpd_event_bits = dev_priv->hotplug.event_bits; + dev_priv->hotplug.event_bits = 0; + + /* Disable hotplug on connectors that hit an irq storm. */ + intel_hpd_irq_storm_disable(dev_priv); + + spin_unlock_irq(&dev_priv->irq_lock); + + list_for_each_entry(connector, &mode_config->connector_list, head) { + intel_connector = to_intel_connector(connector); + if (!intel_connector->encoder) + continue; + intel_encoder = intel_connector->encoder; + if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { + DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", + connector->name, intel_encoder->hpd_pin); + if (intel_encoder->hot_plug) + intel_encoder->hot_plug(intel_encoder); + if (intel_hpd_irq_event(dev, connector)) + changed = true; + } + } + mutex_unlock(&mode_config->mutex); + + if (changed) + drm_kms_helper_hotplug_event(dev); +} + + +/** + * intel_hpd_irq_handler - main hotplug irq handler + * @dev: drm device + * @pin_mask: a mask of hpd pins that have triggered the irq + * @long_mask: a mask of hpd pins that may be long hpd pulses + * + * This is the main hotplug irq handler for all platforms. The platform specific + * irq handlers call the platform specific hotplug irq handlers, which read and + * decode the appropriate registers into bitmasks about hpd pins that have + * triggered (@pin_mask), and which of those pins may be long pulses + * (@long_mask). The @long_mask is ignored if the port corresponding to the pin + * is not a digital port. + * + * Here, we do hotplug irq storm detection and mitigation, and pass further + * processing to appropriate bottom halves. + */ +void intel_hpd_irq_handler(struct drm_device *dev, + u32 pin_mask, u32 long_mask) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + enum port port; + bool storm_detected = false; + bool queue_dig = false, queue_hp = false; + bool is_dig_port; + + if (!pin_mask) + return; + + spin_lock(&dev_priv->irq_lock); + for_each_hpd_pin(i) { + if (!(BIT(i) & pin_mask)) + continue; + + port = intel_hpd_pin_to_port(i); + is_dig_port = port && dev_priv->hotplug.irq_port[port]; + + if (is_dig_port) { + bool long_hpd = long_mask & BIT(i); + + DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), + long_hpd ? "long" : "short"); + /* + * For long HPD pulses we want to have the digital queue happen, + * but we still want HPD storm detection to function. + */ + queue_dig = true; + if (long_hpd) { + dev_priv->hotplug.long_port_mask |= (1 << port); + } else { + /* for short HPD just trigger the digital queue */ + dev_priv->hotplug.short_port_mask |= (1 << port); + continue; + } + } + + if (dev_priv->hotplug.stats[i].state == HPD_DISABLED) { + /* + * On GMCH platforms the interrupt mask bits only + * prevent irq generation, not the setting of the + * hotplug bits itself. So only WARN about unexpected + * interrupts on saner platforms. + */ + WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev), + "Received HPD interrupt on pin %d although disabled\n", i); + continue; + } + + if (dev_priv->hotplug.stats[i].state != HPD_ENABLED) + continue; + + if (!is_dig_port) { + dev_priv->hotplug.event_bits |= BIT(i); + queue_hp = true; + } + + if (intel_hpd_irq_storm_detect(dev_priv, i)) { + dev_priv->hotplug.event_bits &= ~BIT(i); + storm_detected = true; + } + } + + if (storm_detected) + dev_priv->display.hpd_irq_setup(dev); + spin_unlock(&dev_priv->irq_lock); + + /* + * Our hotplug handler can grab modeset locks (by calling down into the + * fb helpers). Hence it must not be run on our own dev-priv->wq work + * queue for otherwise the flush_work in the pageflip code will + * deadlock. + */ + if (queue_dig) + queue_work(dev_priv->hotplug.dp_wq, &dev_priv->hotplug.dig_port_work); + if (queue_hp) + schedule_work(&dev_priv->hotplug.hotplug_work); +} + +/** + * intel_hpd_init - initializes and enables hpd support + * @dev_priv: i915 device instance + * + * This function enables the hotplug support. It requires that interrupts have + * already been enabled with intel_irq_init_hw(). From this point on hotplug and + * poll request can run concurrently to other code, so locking rules must be + * obeyed. + * + * This is a separate step from interrupt enabling to simplify the locking rules + * in the driver load and resume code. + */ +void intel_hpd_init(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *connector; + int i; + + for_each_hpd_pin(i) { + dev_priv->hotplug.stats[i].count = 0; + dev_priv->hotplug.stats[i].state = HPD_ENABLED; + } + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_connector *intel_connector = to_intel_connector(connector); + connector->polled = intel_connector->polled; + if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) + connector->polled = DRM_CONNECTOR_POLL_HPD; + if (intel_connector->mst_port) + connector->polled = DRM_CONNECTOR_POLL_HPD; + } + + /* + * Interrupt setup is already guaranteed to be single-threaded, this is + * just to make the assert_spin_locked checks happy. + */ + spin_lock_irq(&dev_priv->irq_lock); + if (dev_priv->display.hpd_irq_setup) + dev_priv->display.hpd_irq_setup(dev); + spin_unlock_irq(&dev_priv->irq_lock); +} + +void intel_hpd_init_work(struct drm_i915_private *dev_priv) +{ + INIT_WORK(&dev_priv->hotplug.hotplug_work, i915_hotplug_work_func); + INIT_WORK(&dev_priv->hotplug.dig_port_work, i915_digport_work_func); + INIT_DELAYED_WORK(&dev_priv->hotplug.reenable_work, + intel_hpd_irq_storm_reenable_work); +} + +void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) +{ + spin_lock_irq(&dev_priv->irq_lock); + + dev_priv->hotplug.long_port_mask = 0; + dev_priv->hotplug.short_port_mask = 0; + dev_priv->hotplug.event_bits = 0; + + spin_unlock_irq(&dev_priv->irq_lock); + + cancel_work_sync(&dev_priv->hotplug.dig_port_work); + cancel_work_sync(&dev_priv->hotplug.hotplug_work); + cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work); +} -- cgit v1.3-6-gb490 From 8c841e57cadee2d0de7a1ea81c987088fb6a17fd Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jun 2015 13:06:17 +0300 Subject: drm/i915: reduce line width in {pch, i9xx}_get_hpd_pins() Make Paulo happier. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2d3b2ccf9ce4..a6fbe6443d63 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1257,8 +1257,10 @@ static bool i9xx_port_hotplug_long_detect(enum port port, u32 val) /* Get a bit mask of pins that have triggered, and which ones may be long. */ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, - u32 hotplug_trigger, u32 dig_hotplug_reg, const u32 hpd[HPD_NUM_PINS]) + u32 hotplug_trigger, u32 dig_hotplug_reg, + const u32 hpd[HPD_NUM_PINS]) { + enum port port; int i; *pin_mask = 0; @@ -1268,12 +1270,14 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, return; for_each_hpd_pin(i) { - if (hpd[i] & hotplug_trigger) { - *pin_mask |= BIT(i); + if ((hpd[i] & hotplug_trigger) == 0) + continue; - if (pch_port_hotplug_long_detect(intel_hpd_pin_to_port(i), dig_hotplug_reg)) - *long_mask |= BIT(i); - } + *pin_mask |= BIT(i); + + port = intel_hpd_pin_to_port(i); + if (pch_port_hotplug_long_detect(port, dig_hotplug_reg)) + *long_mask |= BIT(i); } DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x\n", @@ -1285,6 +1289,7 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, u32 hotplug_trigger, const u32 hpd[HPD_NUM_PINS]) { + enum port port; int i; *pin_mask = 0; @@ -1294,12 +1299,14 @@ static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, return; for_each_hpd_pin(i) { - if (hpd[i] & hotplug_trigger) { - *pin_mask |= BIT(i); + if ((hpd[i] & hotplug_trigger) == 0) + continue; - if (i9xx_port_hotplug_long_detect(intel_hpd_pin_to_port(i), hotplug_trigger)) - *long_mask |= BIT(i); - } + *pin_mask |= BIT(i); + + port = intel_hpd_pin_to_port(i); + if (i9xx_port_hotplug_long_detect(port, hotplug_trigger)) + *long_mask |= BIT(i); } DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, pins 0x%08x\n", -- cgit v1.3-6-gb490 From 3b1429d9458f5fc1abe57fb47b429290acb5d4d1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 18 Jun 2015 13:47:22 +0300 Subject: drm/i915: Factor out p2 divider selection for pre-ilk platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The same dpll p2 divider selection is repeated three times in the gen2-4 .find_dpll() functions. Factor it out. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 78 ++++++++++++++---------------------- 1 file changed, 30 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 64c6c38ec8af..df6f6adc7881 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -641,16 +641,12 @@ static bool intel_PLL_is_valid(struct drm_device *dev, return true; } -static bool -i9xx_find_best_dpll(const intel_limit_t *limit, - struct intel_crtc_state *crtc_state, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock) +static int +i9xx_select_p2_div(const intel_limit_t *limit, + const struct intel_crtc_state *crtc_state, + int target) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - struct drm_device *dev = crtc->base.dev; - intel_clock_t clock; - int err = target; + struct drm_device *dev = crtc_state->base.crtc->dev; if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) { /* @@ -659,18 +655,31 @@ i9xx_find_best_dpll(const intel_limit_t *limit, * single/dual channel state, if we even can. */ if (intel_is_dual_link_lvds(dev)) - clock.p2 = limit->p2.p2_fast; + return limit->p2.p2_fast; else - clock.p2 = limit->p2.p2_slow; + return limit->p2.p2_slow; } else { if (target < limit->p2.dot_limit) - clock.p2 = limit->p2.p2_slow; + return limit->p2.p2_slow; else - clock.p2 = limit->p2.p2_fast; + return limit->p2.p2_fast; } +} + +static bool +i9xx_find_best_dpll(const intel_limit_t *limit, + struct intel_crtc_state *crtc_state, + int target, int refclk, intel_clock_t *match_clock, + intel_clock_t *best_clock) +{ + struct drm_device *dev = crtc_state->base.crtc->dev; + intel_clock_t clock; + int err = target; memset(best_clock, 0, sizeof(*best_clock)); + clock.p2 = i9xx_select_p2_div(limit, crtc_state, target); + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { for (clock.m2 = limit->m2.min; @@ -710,30 +719,14 @@ pnv_find_best_dpll(const intel_limit_t *limit, int target, int refclk, intel_clock_t *match_clock, intel_clock_t *best_clock) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - struct drm_device *dev = crtc->base.dev; + struct drm_device *dev = crtc_state->base.crtc->dev; intel_clock_t clock; int err = target; - if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) { - /* - * For LVDS just rely on its current settings for dual-channel. - * We haven't figured out how to reliably set up different - * single/dual channel state, if we even can. - */ - if (intel_is_dual_link_lvds(dev)) - clock.p2 = limit->p2.p2_fast; - else - clock.p2 = limit->p2.p2_slow; - } else { - if (target < limit->p2.dot_limit) - clock.p2 = limit->p2.p2_slow; - else - clock.p2 = limit->p2.p2_fast; - } - memset(best_clock, 0, sizeof(*best_clock)); + clock.p2 = i9xx_select_p2_div(limit, crtc_state, target); + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { for (clock.m2 = limit->m2.min; @@ -771,28 +764,17 @@ g4x_find_best_dpll(const intel_limit_t *limit, int target, int refclk, intel_clock_t *match_clock, intel_clock_t *best_clock) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - struct drm_device *dev = crtc->base.dev; + struct drm_device *dev = crtc_state->base.crtc->dev; intel_clock_t clock; int max_n; - bool found; + bool found = false; /* approximately equals target * 0.00585 */ int err_most = (target >> 8) + (target >> 9); - found = false; - - if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) { - if (intel_is_dual_link_lvds(dev)) - clock.p2 = limit->p2.p2_fast; - else - clock.p2 = limit->p2.p2_slow; - } else { - if (target < limit->p2.dot_limit) - clock.p2 = limit->p2.p2_slow; - else - clock.p2 = limit->p2.p2_fast; - } memset(best_clock, 0, sizeof(*best_clock)); + + clock.p2 = i9xx_select_p2_div(limit, crtc_state, target); + max_n = limit->n.max; /* based on hardware requirement, prefer smaller n to precision */ for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { -- cgit v1.3-6-gb490 From 77a0d1cab489eb2b6ebd54234df4262f4840d498 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 18 Jun 2015 11:43:24 -0700 Subject: drm/i915: Remove unused ring argument from frontbuffer invalidate and busy functions. This patch doesn't have any functional change, but organize fruntbuffer invalidate and busy by removing unecesarry signature argument for ring. It was unsed on mark_fb_busy and only used on fb_obj_invalidate for the same ORIGIN_CS usage. So let's clean it a bit Cc: Daniel Vetter Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 10 +++++----- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_fbdev.c | 4 ++-- drivers/gpu/drm/i915/intel_frontbuffer.c | 14 +++++--------- 5 files changed, 13 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index be35f0486202..620e1b74cb03 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -350,7 +350,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj, if (ret) return ret; - intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU); + intel_fb_obj_invalidate(obj, ORIGIN_CPU); if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { unsigned long unwritten; @@ -804,7 +804,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, offset = i915_gem_obj_ggtt_offset(obj) + args->offset; - intel_fb_obj_invalidate(obj, NULL, ORIGIN_GTT); + intel_fb_obj_invalidate(obj, ORIGIN_GTT); while (remain > 0) { /* Operation in this page @@ -948,7 +948,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev, if (ret) return ret; - intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU); + intel_fb_obj_invalidate(obj, ORIGIN_CPU); i915_gem_object_pin_pages(obj); @@ -3942,7 +3942,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) } if (write) - intel_fb_obj_invalidate(obj, NULL, ORIGIN_GTT); + intel_fb_obj_invalidate(obj, ORIGIN_GTT); trace_i915_gem_object_change_domain(obj, old_read_domains, @@ -4215,7 +4215,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) } if (write) - intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU); + intel_fb_obj_invalidate(obj, ORIGIN_CPU); trace_i915_gem_object_change_domain(obj, old_read_domains, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3336e1c2c0a5..edb8c458cbe1 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1038,7 +1038,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, obj->dirty = 1; i915_gem_request_assign(&obj->last_write_req, req); - intel_fb_obj_invalidate(obj, ring, ORIGIN_CS); + intel_fb_obj_invalidate(obj, ORIGIN_CS); /* update for the implicit flush after a batch */ obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 853bfd98ef72..e2174fd3030b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -956,7 +956,6 @@ void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, /* intel_frontbuffer.c */ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, enum fb_op_origin origin); void intel_frontbuffer_flip_prepare(struct drm_device *dev, unsigned frontbuffer_bits); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 6372cfc7d053..838214666cc3 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -89,7 +89,7 @@ static int intel_fbdev_blank(int blank, struct fb_info *info) * now until we solve this for real. */ mutex_lock(&fb_helper->dev->struct_mutex); - intel_fb_obj_invalidate(ifbdev->fb->obj, NULL, ORIGIN_GTT); + intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT); mutex_unlock(&fb_helper->dev->struct_mutex); } @@ -115,7 +115,7 @@ static int intel_fbdev_pan_display(struct fb_var_screeninfo *var, * now until we solve this for real. */ mutex_lock(&fb_helper->dev->struct_mutex); - intel_fb_obj_invalidate(ifbdev->fb->obj, NULL, ORIGIN_GTT); + intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT); mutex_unlock(&fb_helper->dev->struct_mutex); } diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 57095f54c1f2..bdf0d57cad0f 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -98,14 +98,12 @@ static void intel_increase_pllclock(struct drm_device *dev, * intel_mark_fb_busy - mark given planes as busy * @dev: DRM device * @frontbuffer_bits: bits for the affected planes - * @ring: optional ring for asynchronous commands * * This function gets called every time the screen contents change. It can be * used to keep e.g. the update rate at the nominal refresh rate with DRRS. */ static void intel_mark_fb_busy(struct drm_device *dev, - unsigned frontbuffer_bits, - struct intel_engine_cs *ring) + unsigned frontbuffer_bits) { struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe; @@ -121,17 +119,15 @@ static void intel_mark_fb_busy(struct drm_device *dev, /** * intel_fb_obj_invalidate - invalidate frontbuffer object * @obj: GEM object to invalidate - * @ring: set for asynchronous rendering * @origin: which operation caused the invalidation * * This function gets called every time rendering on the given object starts and * frontbuffer caching (fbc, low refresh rate for DRRS, panel self refresh) must - * be invalidated. If @ring is non-NULL any subsequent invalidation will be delayed + * be invalidated. For ORIGIN_CS any subsequent invalidation will be delayed * until the rendering completes or a flip on this frontbuffer plane is * scheduled. */ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, enum fb_op_origin origin) { struct drm_device *dev = obj->base.dev; @@ -142,7 +138,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, if (!obj->frontbuffer_bits) return; - if (ring) { + if (origin == ORIGIN_CS) { mutex_lock(&dev_priv->fb_tracking.lock); dev_priv->fb_tracking.busy_bits |= obj->frontbuffer_bits; @@ -151,7 +147,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, mutex_unlock(&dev_priv->fb_tracking.lock); } - intel_mark_fb_busy(dev, obj->frontbuffer_bits, ring); + intel_mark_fb_busy(dev, obj->frontbuffer_bits); intel_psr_invalidate(dev, obj->frontbuffer_bits); intel_edp_drrs_invalidate(dev, obj->frontbuffer_bits); @@ -179,7 +175,7 @@ void intel_frontbuffer_flush(struct drm_device *dev, frontbuffer_bits &= ~dev_priv->fb_tracking.busy_bits; mutex_unlock(&dev_priv->fb_tracking.lock); - intel_mark_fb_busy(dev, frontbuffer_bits, NULL); + intel_mark_fb_busy(dev, frontbuffer_bits); intel_edp_drrs_flush(dev, frontbuffer_bits); intel_psr_flush(dev, frontbuffer_bits); -- cgit v1.3-6-gb490 From 55a9785d125a4dd33678795ccba0ed61a6e8540c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 19 Jun 2015 13:59:46 +0100 Subject: drm/i915: Enforce execobject.alignment to be a power-of-two Internal requirement for the alignment is that it must be a power-of-two, so enforce rejection at the user interface to execbuffer (which allows the caller to specify a stricter-than-expected alignment criterion). Signed-off-by: Chris Wilson Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index edb8c458cbe1..21f8eb659251 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -957,6 +957,9 @@ validate_exec_list(struct drm_device *dev, if (exec[i].flags & invalid_flags) return -EINVAL; + if (exec[i].alignment && !is_power_of_2(exec[i].alignment)) + return -EINVAL; + /* First check for malicious input causing overflow in * the worst case where we need to allocate the entire * relocation tree as a single array. -- cgit v1.3-6-gb490 From eebaed646ab263cabcd19485e606e51c0bb11c5c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 19 Jun 2015 13:57:43 +0100 Subject: drm/i915: Ignore LVDS presence in VBT flag if the LVDS is enabled by BIOS On older gen, pre-Ironlake, parts there is no hardwired pin to report the presence of an LVDS panel. Instead, we have to rely on the VBT to declare whether the machine has a panel or not. Though notoriously unreliable, so far we have erred on the side of false-positives and have required a list of machines which end up falsely reporting a panel as present. However, we now have reports of false-negatives, machines with an LVDS that are being ignored due to the VBT not declaring the panel. This patch ignores the VBT setting if the BIOS has already enabled the LVDS panel (and on Ironlake+ we also have the hardware presence pin). It fixes the Samsung NP680Z5E-X01FR in the bug report, but is likely to result in more false-positives, and since we rely on the BIOS to enable the panel, there are likely different circumstances where the BIOS will not enable that panel (and so we may see the same machine with and without a panel all on the whim of the BIOS). Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90979 Reported-and-tested-by: lysxia@gmail.com Signed-off-by: Chris Wilson Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lvds.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 161ab26f81fb..bf1702a6e33d 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -942,12 +942,6 @@ void intel_lvds_init(struct drm_device *dev) if (dmi_check_system(intel_no_lvds)) return; - pin = GMBUS_PIN_PANEL; - if (!lvds_is_present_in_vbt(dev, &pin)) { - DRM_DEBUG_KMS("LVDS is not present in VBT\n"); - return; - } - if (HAS_PCH_SPLIT(dev)) { if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) return; @@ -957,6 +951,16 @@ void intel_lvds_init(struct drm_device *dev) } } + pin = GMBUS_PIN_PANEL; + if (!lvds_is_present_in_vbt(dev, &pin)) { + u32 reg = HAS_PCH_SPLIT(dev) ? PCH_LVDS : LVDS; + if ((I915_READ(reg) & LVDS_PORT_EN) == 0) { + DRM_DEBUG_KMS("LVDS is not present in VBT\n"); + return; + } + DRM_DEBUG_KMS("LVDS is not present in VBT, but enabled anyway\n"); + } + lvds_encoder = kzalloc(sizeof(*lvds_encoder), GFP_KERNEL); if (!lvds_encoder) return; -- cgit v1.3-6-gb490 From fd930478fb797e4cbaa799d9ddd970e9a1fa1b4a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 19 Jun 2015 20:27:27 +0100 Subject: drm/i915: Remove KMS Kconfig option Since we only support modesetting by default (disabling modesetting on the command line prevents i915.ko from loading), having a parameter to disable modesstting by default is superfluous, i.e. saying CONFIG_DRM_I915_KMS=n is equivalent to CONFIG_DRM_I915=n. Signed-off-by: Chris Wilson Cc: Daniel Veter Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- arch/x86/configs/x86_64_defconfig | 1 - drivers/gpu/drm/i915/Kconfig | 9 --------- drivers/gpu/drm/i915/i915_drv.c | 20 +++++++------------- 3 files changed, 7 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig index 315b86106572..05630dfcb9f4 100644 --- a/arch/x86/configs/x86_64_defconfig +++ b/arch/x86/configs/x86_64_defconfig @@ -207,7 +207,6 @@ CONFIG_AGP_AMD64=y CONFIG_AGP_INTEL=y CONFIG_DRM=y CONFIG_DRM_I915=y -CONFIG_DRM_I915_KMS=y CONFIG_FB_MODE_HELPERS=y CONFIG_FB_TILEBLITTING=y CONFIG_FB_EFI=y diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 74acca9bcd9d..eb87e2538861 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -36,15 +36,6 @@ config DRM_I915 i810 driver instead, and the Atom z5xx series has an entirely different implementation. -config DRM_I915_KMS - bool "Enable modesetting on intel by default" - depends on DRM_I915 - default y - help - Choose this option if you want kernel modesetting enabled by default. - - If in doubt, say "Y". - config DRM_I915_FBDEV bool "Enable legacy fbdev support for the modesetting intel driver" depends on DRM_I915 diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0ec57bad454f..c69f19271e27 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1710,20 +1710,14 @@ static int __init i915_init(void) driver.num_ioctls = i915_max_ioctl; /* - * If CONFIG_DRM_I915_KMS is set, default to KMS unless - * explicitly disabled with the module pararmeter. - * - * Otherwise, just follow the parameter (defaulting to off). - * - * Allow optional vga_text_mode_force boot option to override - * the default behavior. + * Enable KMS by default, unless explicitly overriden by + * either the i915.modeset prarameter or by the + * vga_text_mode_force boot option. */ -#if defined(CONFIG_DRM_I915_KMS) - if (i915.modeset != 0) - driver.driver_features |= DRIVER_MODESET; -#endif - if (i915.modeset == 1) - driver.driver_features |= DRIVER_MODESET; + driver.driver_features |= DRIVER_MODESET; + + if (i915.modeset == 0) + driver.driver_features &= ~DRIVER_MODESET; #ifdef CONFIG_VGA_CONSOLE if (vgacon_text_force() && i915.modeset == -1) -- cgit v1.3-6-gb490 From bf13af56252b2b4f50eb6fc8638e8cb9e84ff475 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 23 Jun 2015 13:57:47 +0200 Subject: drm/i915: Fix up KMS Kconfig removal patch The module pciid list got lost, but somehow most distros seem to force-load drm drivers early and no one noticed for a while. Bug introduced in commit fd930478fb797e4cbaa799d9ddd970e9a1fa1b4a Author: Chris Wilson Date: Fri Jun 19 20:27:27 2015 +0100 drm/i915: Remove KMS Kconfig option Reported-by: Tvrtko Ursulin Cc: Tvrtko Ursulin Cc: Damien Lespiau Cc: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 -- drivers/gpu/drm/i915/i915_params.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c69f19271e27..b12a8218e35e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -440,9 +440,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */ {0, 0, 0} }; -#if defined(CONFIG_DRM_I915_KMS) MODULE_DEVICE_TABLE(pci, pciidlist); -#endif void intel_detect_pch(struct drm_device *dev) { diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 8ac5a1b29ac0..3f67e69185c8 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -58,7 +58,7 @@ struct i915_params i915 __read_mostly = { module_param_named(modeset, i915.modeset, int, 0400); MODULE_PARM_DESC(modeset, - "Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, " + "Use kernel modesetting [KMS] (0=disable, " "1=on, -1=force vga console preference [default])"); module_param_named(panel_ignore_lid, i915.panel_ignore_lid, int, 0600); -- cgit v1.3-6-gb490 From b1330fbb870467bbb90adb2e8868672af4ca88c7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 18 Jun 2015 11:42:08 +0100 Subject: drm/i915: Report an error when i915.reset prevents a reset If the user disables the GPU reset using the i915.reset parameter and one occurs, report that we failed to reset the GPU. If we return early, as we currently do, then we leave all state intact (with a hung GPU) and clients block forever waiting for their requests to complete. Testcase: igt/gem_eio Signed-off-by: Chris Wilson [danvet: Mark i915.reset as an unsafe modoption, as discussed with Chris.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 1 - drivers/gpu/drm/i915/i915_drv.c | 3 --- drivers/gpu/drm/i915/i915_params.c | 2 +- drivers/gpu/drm/i915/intel_uncore.c | 3 +++ 4 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 88795d2f1819..c5349fa3fcce 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -165,7 +165,6 @@ static int i915_getparam(struct drm_device *dev, void *data, break; case I915_PARAM_HAS_GPU_RESET: value = i915.enable_hangcheck && - i915.reset && intel_has_gpu_reset(dev); break; default: diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b12a8218e35e..e44dc0d6656f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -846,9 +846,6 @@ int i915_reset(struct drm_device *dev) bool simulated; int ret; - if (!i915.reset) - return 0; - intel_reset_gt_powersave(dev); mutex_lock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 3f67e69185c8..18f65595d60e 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -104,7 +104,7 @@ 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_param_named_unsafe(reset, i915.reset, bool, 0600); MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)"); module_param_named(enable_hangcheck, i915.enable_hangcheck, bool, 0644); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 160a47a9bdd9..45285a9178fe 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1496,6 +1496,9 @@ not_ready: static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *) { + if (!i915.reset) + return NULL; + if (INTEL_INFO(dev)->gen >= 8) return gen8_do_reset; else if (INTEL_INFO(dev)->gen >= 6) -- cgit v1.3-6-gb490 From 17ee950df38b649d8431e2f6f7f85282d89f5398 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 19 Jun 2015 19:07:01 +0100 Subject: drm/i915/gen8: Add infrastructure to initialize WA batch buffers Some of the WA are to be applied during context save but before restore and some at the end of context save/restore but before executing the instructions in the ring, WA batch buffers are created for this purpose and these WA cannot be applied using normal means. Each context has two registers to load the offsets of these batch buffers. If they are non-zero, HW understands that it need to execute these batches. v1: In this version two separate ring_buffer objects were used to load WA instructions for indirect and per context batch buffers and they were part of every context. v2: Chris suggested to include additional page in context and use it to load these WA instead of creating separate objects. This will simplify lot of things as we need not explicity pin/unpin them. Thomas Daniel further pointed that GuC is planning to use a similar setup to share data between GuC and driver and WA batch buffers can probably share that page. However after discussions with Dave who is implementing GuC changes, he suggested to use an independent page for the reasons - GuC area might grow and these WA are initialized only once and are not changed afterwards so we can share them share across all contexts. The page is updated with WA during render ring init. This has an advantage of not adding more special cases to default_context. We don't know upfront the number of WA we will applying using these batch buffers. For this reason the size was fixed earlier but it is not a good idea. To fix this, the functions that load instructions are modified to report the no of commands inserted and the size is now calculated after the batch is updated. A macro is introduced to add commands to these batch buffers which also checks for overflow and returns error. We have a full page dedicated for these WA so that should be sufficient for good number of WA, anything more means we have major issues. The list for Gen8 is small, same for Gen9 also, maybe few more gets added going forward but not close to filling entire page. Chris suggested a two-pass approach but we agreed to go with single page setup as it is a one-off routine and simpler code wins. One additional option is offset field which is helpful if we would like to have multiple batches at different offsets within the page and select them based on some criteria. This is not a requirement at this point but could help in future (Dave). Chris provided some helpful macros and suggestions which further simplified the code, they will also help in reducing code duplication when WA for other Gen are added. Add detailed comments explaining restrictions. Use do {} while(0) for wa_ctx_emit() macro. (Many thanks to Chris, Dave and Thomas for their reviews and inputs) Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Rafael Barbalho Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 223 +++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_ringbuffer.h | 21 +++ 2 files changed, 240 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9f5485ddcbe6..9b791a3d47dd 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -211,6 +211,7 @@ enum { FAULT_AND_CONTINUE /* Unsupported */ }; #define GEN8_CTX_ID_SHIFT 32 +#define CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x17 static int intel_lr_context_pin(struct intel_engine_cs *ring, struct intel_context *ctx); @@ -1077,6 +1078,191 @@ static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring, return 0; } +#define wa_ctx_emit(batch, cmd) \ + do { \ + if (WARN_ON(index >= (PAGE_SIZE / sizeof(uint32_t)))) { \ + return -ENOSPC; \ + } \ + batch[index++] = (cmd); \ + } while (0) + +static inline uint32_t wa_ctx_start(struct i915_wa_ctx_bb *wa_ctx, + uint32_t offset, + uint32_t start_alignment) +{ + return wa_ctx->offset = ALIGN(offset, start_alignment); +} + +static inline int wa_ctx_end(struct i915_wa_ctx_bb *wa_ctx, + uint32_t offset, + uint32_t size_alignment) +{ + wa_ctx->size = offset - wa_ctx->offset; + + WARN(wa_ctx->size % size_alignment, + "wa_ctx_bb failed sanity checks: size %d is not aligned to %d\n", + wa_ctx->size, size_alignment); + return 0; +} + +/** + * gen8_init_indirectctx_bb() - initialize indirect ctx batch with WA + * + * @ring: only applicable for RCS + * @wa_ctx: structure representing wa_ctx + * offset: specifies start of the batch, should be cache-aligned. This is updated + * with the offset value received as input. + * size: size of the batch in DWORDS but HW expects in terms of cachelines + * @batch: page in which WA are loaded + * @offset: This field specifies the start of the batch, it should be + * cache-aligned otherwise it is adjusted accordingly. + * Typically we only have one indirect_ctx and per_ctx batch buffer which are + * initialized at the beginning and shared across all contexts but this field + * helps us to have multiple batches at different offsets and select them based + * on a criteria. At the moment this batch always start at the beginning of the page + * and at this point we don't have multiple wa_ctx batch buffers. + * + * The number of WA applied are not known at the beginning; we use this field + * to return the no of DWORDS written. + + * It is to be noted that this batch does not contain MI_BATCH_BUFFER_END + * so it adds NOOPs as padding to make it cacheline aligned. + * MI_BATCH_BUFFER_END will be added to perctx batch and both of them together + * makes a complete batch buffer. + * + * Return: non-zero if we exceed the PAGE_SIZE limit. + */ + +static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, + struct i915_wa_ctx_bb *wa_ctx, + uint32_t *const batch, + uint32_t *offset) +{ + uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + + /* FIXME: Replace me with WA */ + wa_ctx_emit(batch, MI_NOOP); + + /* Pad to end of cacheline */ + while (index % CACHELINE_DWORDS) + wa_ctx_emit(batch, MI_NOOP); + + /* + * MI_BATCH_BUFFER_END is not required in Indirect ctx BB because + * execution depends on the length specified in terms of cache lines + * in the register CTX_RCS_INDIRECT_CTX + */ + + return wa_ctx_end(wa_ctx, *offset = index, CACHELINE_DWORDS); +} + +/** + * gen8_init_perctx_bb() - initialize per ctx batch with WA + * + * @ring: only applicable for RCS + * @wa_ctx: structure representing wa_ctx + * offset: specifies start of the batch, should be cache-aligned. + * size: size of the batch in DWORDS but HW expects in terms of cachelines + * @offset: This field specifies the start of this batch. + * This batch is started immediately after indirect_ctx batch. Since we ensure + * that indirect_ctx ends on a cacheline this batch is aligned automatically. + * + * The number of DWORDS written are returned using this field. + * + * This batch is terminated with MI_BATCH_BUFFER_END and so we need not add padding + * to align it with cacheline as padding after MI_BATCH_BUFFER_END is redundant. + */ +static int gen8_init_perctx_bb(struct intel_engine_cs *ring, + struct i915_wa_ctx_bb *wa_ctx, + uint32_t *const batch, + uint32_t *offset) +{ + uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + + wa_ctx_emit(batch, MI_BATCH_BUFFER_END); + + return wa_ctx_end(wa_ctx, *offset = index, 1); +} + +static int lrc_setup_wa_ctx_obj(struct intel_engine_cs *ring, u32 size) +{ + int ret; + + ring->wa_ctx.obj = i915_gem_alloc_object(ring->dev, PAGE_ALIGN(size)); + if (!ring->wa_ctx.obj) { + DRM_DEBUG_DRIVER("alloc LRC WA ctx backing obj failed.\n"); + return -ENOMEM; + } + + ret = i915_gem_obj_ggtt_pin(ring->wa_ctx.obj, PAGE_SIZE, 0); + if (ret) { + DRM_DEBUG_DRIVER("pin LRC WA ctx backing obj failed: %d\n", + ret); + drm_gem_object_unreference(&ring->wa_ctx.obj->base); + return ret; + } + + return 0; +} + +static void lrc_destroy_wa_ctx_obj(struct intel_engine_cs *ring) +{ + if (ring->wa_ctx.obj) { + i915_gem_object_ggtt_unpin(ring->wa_ctx.obj); + drm_gem_object_unreference(&ring->wa_ctx.obj->base); + ring->wa_ctx.obj = NULL; + } +} + +static int intel_init_workaround_bb(struct intel_engine_cs *ring) +{ + int ret; + uint32_t *batch; + uint32_t offset; + struct page *page; + struct i915_ctx_workarounds *wa_ctx = &ring->wa_ctx; + + WARN_ON(ring->id != RCS); + + ret = lrc_setup_wa_ctx_obj(ring, PAGE_SIZE); + if (ret) { + DRM_DEBUG_DRIVER("Failed to setup context WA page: %d\n", ret); + return ret; + } + + page = i915_gem_object_get_page(wa_ctx->obj, 0); + batch = kmap_atomic(page); + offset = 0; + + if (INTEL_INFO(ring->dev)->gen == 8) { + ret = gen8_init_indirectctx_bb(ring, + &wa_ctx->indirect_ctx, + batch, + &offset); + if (ret) + goto out; + + ret = gen8_init_perctx_bb(ring, + &wa_ctx->per_ctx, + batch, + &offset); + if (ret) + goto out; + } else { + WARN(INTEL_INFO(ring->dev)->gen >= 8, + "WA batch buffer is not initialized for Gen%d\n", + INTEL_INFO(ring->dev)->gen); + lrc_destroy_wa_ctx_obj(ring); + } + +out: + kunmap_atomic(batch); + if (ret) + lrc_destroy_wa_ctx_obj(ring); + + return ret; +} + static int gen8_init_common_ring(struct intel_engine_cs *ring) { struct drm_device *dev = ring->dev; @@ -1411,6 +1597,8 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring) kunmap(sg_page(ring->status_page.obj->pages->sgl)); ring->status_page.obj = NULL; } + + lrc_destroy_wa_ctx_obj(ring); } static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring) @@ -1474,7 +1662,22 @@ static int logical_render_ring_init(struct drm_device *dev) if (ret) return ret; - return intel_init_pipe_control(ring); + ret = intel_init_workaround_bb(ring); + if (ret) { + /* + * We continue even if we fail to initialize WA batch + * because we only expect rare glitches but nothing + * critical to prevent us from using GPU + */ + DRM_ERROR("WA batch buffer initialization failed: %d\n", + ret); + } + + ret = intel_init_pipe_control(ring); + if (ret) + lrc_destroy_wa_ctx_obj(ring); + + return ret; } static int logical_bsd_ring_init(struct drm_device *dev) @@ -1754,15 +1957,27 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o reg_state[CTX_SECOND_BB_STATE] = ring->mmio_base + 0x118; reg_state[CTX_SECOND_BB_STATE+1] = 0; if (ring->id == RCS) { - /* TODO: according to BSpec, the register state context - * for CHV does not have these. OTOH, these registers do - * exist in CHV. I'm waiting for a clarification */ reg_state[CTX_BB_PER_CTX_PTR] = ring->mmio_base + 0x1c0; reg_state[CTX_BB_PER_CTX_PTR+1] = 0; reg_state[CTX_RCS_INDIRECT_CTX] = ring->mmio_base + 0x1c4; reg_state[CTX_RCS_INDIRECT_CTX+1] = 0; reg_state[CTX_RCS_INDIRECT_CTX_OFFSET] = ring->mmio_base + 0x1c8; reg_state[CTX_RCS_INDIRECT_CTX_OFFSET+1] = 0; + if (ring->wa_ctx.obj) { + struct i915_ctx_workarounds *wa_ctx = &ring->wa_ctx; + uint32_t ggtt_offset = i915_gem_obj_ggtt_offset(wa_ctx->obj); + + reg_state[CTX_RCS_INDIRECT_CTX+1] = + (ggtt_offset + wa_ctx->indirect_ctx.offset * sizeof(uint32_t)) | + (wa_ctx->indirect_ctx.size / CACHELINE_DWORDS); + + reg_state[CTX_RCS_INDIRECT_CTX_OFFSET+1] = + CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT << 6; + + reg_state[CTX_BB_PER_CTX_PTR+1] = + (ggtt_offset + wa_ctx->per_ctx.offset * sizeof(uint32_t)) | + 0x01; + } } reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9); reg_state[CTX_LRI_HEADER_1] |= MI_LRI_FORCE_POSTED; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index e539314ae87e..64850293559c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -12,6 +12,7 @@ * workarounds! */ #define CACHELINE_BYTES 64 +#define CACHELINE_DWORDS (CACHELINE_BYTES / sizeof(uint32_t)) /* * Gen2 BSpec "1. Programming Environment" / 1.4.4.6 "Ring Buffer Use" @@ -120,6 +121,25 @@ struct intel_ringbuffer { struct intel_context; struct drm_i915_reg_descriptor; +/* + * we use a single page to load ctx workarounds so all of these + * values are referred in terms of dwords + * + * struct i915_wa_ctx_bb: + * offset: specifies batch starting position, also helpful in case + * if we want to have multiple batches at different offsets based on + * some criteria. It is not a requirement at the moment but provides + * an option for future use. + * size: size of the batch in DWORDS + */ +struct i915_ctx_workarounds { + struct i915_wa_ctx_bb { + u32 offset; + u32 size; + } indirect_ctx, per_ctx; + struct drm_i915_gem_object *obj; +}; + struct intel_engine_cs { const char *name; enum intel_ring_id { @@ -143,6 +163,7 @@ struct intel_engine_cs { struct i915_gem_batch_pool batch_pool; struct intel_hw_status_page status_page; + struct i915_ctx_workarounds wa_ctx; unsigned irq_refcount; /* protected by dev_priv->irq_lock */ u32 irq_enable_mask; /* bitmask to enable ring interrupt */ -- cgit v1.3-6-gb490 From c4db7599194248214b343d1ef1a1bc53d6cff187 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 19 Jun 2015 18:37:11 +0100 Subject: drm/i915/gen8: Re-order init pipe_control in lrc mode Some of the WA applied using WA batch buffers perform writes to scratch page. In the current flow WA are initialized before scratch obj is allocated. This patch reorders intel_init_pipe_control() to have a valid scratch obj before we initialize WA. v2: Check for valid scratch page before initializing WA as some of them perform writes to it. Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Michel Thierry Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9b791a3d47dd..f83d97ea4028 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1224,6 +1224,12 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring) WARN_ON(ring->id != RCS); + /* some WA perform writes to scratch page, ensure it is valid */ + if (ring->scratch.obj == NULL) { + DRM_ERROR("scratch page not allocated for %s\n", ring->name); + return -EINVAL; + } + ret = lrc_setup_wa_ctx_obj(ring, PAGE_SIZE); if (ret) { DRM_DEBUG_DRIVER("Failed to setup context WA page: %d\n", ret); @@ -1658,7 +1664,8 @@ static int logical_render_ring_init(struct drm_device *dev) ring->emit_bb_start = gen8_emit_bb_start; ring->dev = dev; - ret = logical_ring_init(dev, ring); + + ret = intel_init_pipe_control(ring); if (ret) return ret; @@ -1673,9 +1680,10 @@ static int logical_render_ring_init(struct drm_device *dev) ret); } - ret = intel_init_pipe_control(ring); - if (ret) + ret = logical_ring_init(dev, ring); + if (ret) { lrc_destroy_wa_ctx_obj(ring); + } return ret; } -- cgit v1.3-6-gb490 From 7ad00d1ac12bf461d0f0b69bf4e0e883b9e23c53 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 19 Jun 2015 18:37:12 +0100 Subject: drm/i915/gen8: Add WaDisableCtxRestoreArbitration workaround In Indirect and Per context w/a batch buffer, +WaDisableCtxRestoreArbitration Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Rafael Barbalho Signed-off-by: Arun Siluvery Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index f83d97ea4028..a1198baf34aa 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1140,8 +1140,8 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, { uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); - /* FIXME: Replace me with WA */ - wa_ctx_emit(batch, MI_NOOP); + /* WaDisableCtxRestoreArbitration:bdw,chv */ + wa_ctx_emit(batch, MI_ARB_ON_OFF | MI_ARB_DISABLE); /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) @@ -1179,6 +1179,9 @@ static int gen8_init_perctx_bb(struct intel_engine_cs *ring, { uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + /* WaDisableCtxRestoreArbitration:bdw,chv */ + wa_ctx_emit(batch, MI_ARB_ON_OFF | MI_ARB_ENABLE); + wa_ctx_emit(batch, MI_BATCH_BUFFER_END); return wa_ctx_end(wa_ctx, *offset = index, 1); -- cgit v1.3-6-gb490 From c82435bbe5aca62fc54615ff8ba78134bfa33866 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 19 Jun 2015 18:37:13 +0100 Subject: drm/i915/gen8: Add WaFlushCoherentL3CacheLinesAtContextSwitch workaround In Indirect context w/a batch buffer, +WaFlushCoherentL3CacheLinesAtContextSwitch:bdw v2: Add LRI commands to set/reset bit that invalidates coherent lines, update WA to include programming restrictions and exclude CHV as it is not required (Ville) v3: Avoid unnecessary read when it can be done by reading register once (Chris). Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Rafael Barbalho Signed-off-by: Arun Siluvery Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_lrc.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 64caa470f2c6..b8e2259fe9ee 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -431,6 +431,7 @@ #define PIPE_CONTROL_INDIRECT_STATE_DISABLE (1<<9) #define PIPE_CONTROL_NOTIFY (1<<8) #define PIPE_CONTROL_FLUSH_ENABLE (1<<7) /* gen7+ */ +#define PIPE_CONTROL_DC_FLUSH_ENABLE (1<<5) #define PIPE_CONTROL_VF_CACHE_INVALIDATE (1<<4) #define PIPE_CONTROL_CONST_CACHE_INVALIDATE (1<<3) #define PIPE_CONTROL_STATE_CACHE_INVALIDATE (1<<2) @@ -5811,6 +5812,7 @@ enum skl_disp_power_wells { #define GEN8_L3SQCREG4 0xb118 #define GEN8_LQSC_RO_PERF_DIS (1<<27) +#define GEN8_LQSC_FLUSH_COHERENT_LINES (1<<21) /* GEN8 chicken */ #define HDC_CHICKEN0 0x7300 diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a1198baf34aa..2b65d29c4801 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1143,6 +1143,29 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, /* WaDisableCtxRestoreArbitration:bdw,chv */ wa_ctx_emit(batch, MI_ARB_ON_OFF | MI_ARB_DISABLE); + /* WaFlushCoherentL3CacheLinesAtContextSwitch:bdw */ + if (IS_BROADWELL(ring->dev)) { + struct drm_i915_private *dev_priv = to_i915(ring->dev); + uint32_t l3sqc4_flush = (I915_READ(GEN8_L3SQCREG4) | + GEN8_LQSC_FLUSH_COHERENT_LINES); + + wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); + wa_ctx_emit(batch, GEN8_L3SQCREG4); + wa_ctx_emit(batch, l3sqc4_flush); + + wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); + wa_ctx_emit(batch, (PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_DC_FLUSH_ENABLE)); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + + wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); + wa_ctx_emit(batch, GEN8_L3SQCREG4); + wa_ctx_emit(batch, l3sqc4_flush & ~GEN8_LQSC_FLUSH_COHERENT_LINES); + } + /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) wa_ctx_emit(batch, MI_NOOP); -- cgit v1.3-6-gb490 From 29b1b415fcd95a2266ab58fc7825bccbffa5c142 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 18 Jun 2015 13:10:09 +0100 Subject: drm/i915: Reserve ring buffer space for i915_add_request() commands It is a bad idea for i915_add_request() to fail. The work will already have been send to the ring and will be processed, but there will not be any tracking or management of that work. The only way the add request call can fail is if it can't write its epilogue commands to the ring (cache flushing, seqno updates, interrupt signalling). The reasons for that are mostly down to running out of ring buffer space and the problems associated with trying to get some more. This patch prevents that situation from happening in the first place. When a request is created, it marks sufficient space as reserved for the epilogue commands. Thus guaranteeing that by the time the epilogue is written, there will be plenty of space for it. Note that a ring_begin() call is required to actually reserve the space (and do any potential waiting). However, that is not currently done at request creation time. This is because the ring_begin() code can allocate a request. Hence calling begin() from the request allocation code would lead to infinite recursion! Later patches in this series remove the need for begin() to do the allocate. At that point, it becomes safe for the allocate to call begin() and really reserve the space. Until then, there is a potential for insufficient space to be available at the point of calling i915_add_request(). However, that would only be in the case where the request was created and immediately submitted without ever calling ring_begin() and adding any work to that request. Which should never happen. And even if it does, and if that request happens to fall down the tiny window of opportunity for failing due to being out of ring space then does it really matter because the request wasn't doing anything in the first place? v2: Updated the 'reserved space too small' warning to include the offending sizes. Added a 'cancel' operation to clean up when a request is abandoned. Added re-initialisation of tracking state after a buffer wrap to keep the sanity checks accurate. v3: Incremented the reserved size to accommodate Ironlake (after finally managing to run on an ILK system). Also fixed missing wrap code in LRC mode. v4: Added extra comment and removed duplicate WARN (feedback from Tomas). For: VIZ-5115 CC: Tomas Elf Signed-off-by: John Harrison Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 37 +++++++++++++++++ drivers/gpu/drm/i915/intel_lrc.c | 21 ++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 71 ++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_ringbuffer.h | 25 ++++++++++++ 5 files changed, 153 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c3b9fcf301a0..6446911077d0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2200,6 +2200,7 @@ struct drm_i915_gem_request { int i915_gem_request_alloc(struct intel_engine_cs *ring, struct intel_context *ctx); +void i915_gem_request_cancel(struct drm_i915_gem_request *req); void i915_gem_request_free(struct kref *req_ref); static inline uint32_t diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 80b509bed6e0..b9e0989063b4 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2485,6 +2485,13 @@ int __i915_add_request(struct intel_engine_cs *ring, } else ringbuf = ring->buffer; + /* + * To ensure that this call will not fail, space for its emissions + * should already have been reserved in the ring buffer. Let the ring + * know that it is time to use that space up. + */ + intel_ring_reserved_space_use(ringbuf); + request_start = intel_ring_get_tail(ringbuf); /* * Emit any outstanding flushes - execbuf can fail to emit the flush @@ -2567,6 +2574,9 @@ int __i915_add_request(struct intel_engine_cs *ring, round_jiffies_up_relative(HZ)); intel_mark_busy(dev_priv->dev); + /* Sanity check that the reserved size was large enough. */ + intel_ring_reserved_space_end(ringbuf); + return 0; } @@ -2665,6 +2675,26 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, if (ret) goto err; + /* + * Reserve space in the ring buffer for all the commands required to + * eventually emit this request. This is to guarantee that the + * i915_add_request() call can't fail. Note that the reserve may need + * to be redone if the request is not actually submitted straight + * away, e.g. because a GPU scheduler has deferred it. + * + * Note further that this call merely notes the reserve request. A + * subsequent call to *_ring_begin() is required to actually ensure + * that the reservation is available. Without the begin, if the + * request creator immediately submitted the request without adding + * any commands to it then there might not actually be sufficient + * room for the submission commands. Unfortunately, the current + * *_ring_begin() implementations potentially call back here to + * i915_gem_request_alloc(). Thus calling _begin() here would lead to + * infinite recursion! Until that back call path is removed, it is + * necessary to do a manual _begin() outside. + */ + intel_ring_reserved_space_reserve(req->ringbuf, MIN_SPACE_FOR_ADD_REQUEST); + ring->outstanding_lazy_request = req; return 0; @@ -2673,6 +2703,13 @@ err: return ret; } +void i915_gem_request_cancel(struct drm_i915_gem_request *req) +{ + intel_ring_reserved_space_cancel(req->ringbuf); + + i915_gem_request_unreference(req); +} + struct drm_i915_gem_request * i915_gem_find_active_request(struct intel_engine_cs *ring) { diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 2b65d29c4801..7451f38b2ef8 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -686,6 +686,9 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, unsigned space; int ret; + /* The whole point of reserving space is to not wait! */ + WARN_ON(ringbuf->reserved_in_use); + if (intel_ring_space(ringbuf) >= bytes) return 0; @@ -746,6 +749,9 @@ static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf, uint32_t __iomem *virt; int rem = ringbuf->size - ringbuf->tail; + /* Can't wrap if space has already been reserved! */ + WARN_ON(ringbuf->reserved_in_use); + if (ringbuf->space < rem) { int ret = logical_ring_wait_for_space(ringbuf, ctx, rem); @@ -769,10 +775,25 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, { int ret; + /* + * Add on the reserved size to the request to make sure that after + * the intended commands have been emitted, there is guaranteed to + * still be enough free space to send them to the hardware. + */ + if (!ringbuf->reserved_in_use) + bytes += ringbuf->reserved_size; + if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) { ret = logical_ring_wrap_buffer(ringbuf, ctx); if (unlikely(ret)) return ret; + + if(ringbuf->reserved_size) { + uint32_t size = ringbuf->reserved_size; + + intel_ring_reserved_space_cancel(ringbuf); + intel_ring_reserved_space_reserve(ringbuf, size); + } } if (unlikely(ringbuf->space < bytes)) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b70d25bffb60..0c2bf0ed633d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2113,6 +2113,9 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n) unsigned space; int ret; + /* The whole point of reserving space is to not wait! */ + WARN_ON(ringbuf->reserved_in_use); + if (intel_ring_space(ringbuf) >= n) return 0; @@ -2140,6 +2143,9 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring) struct intel_ringbuffer *ringbuf = ring->buffer; int rem = ringbuf->size - ringbuf->tail; + /* Can't wrap if space has already been reserved! */ + WARN_ON(ringbuf->reserved_in_use); + if (ringbuf->space < rem) { int ret = ring_wait_for_space(ring, rem); if (ret) @@ -2190,16 +2196,77 @@ int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request) return 0; } -static int __intel_ring_prepare(struct intel_engine_cs *ring, - int bytes) +void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size) +{ + /* NB: Until request management is fully tidied up and the OLR is + * removed, there are too many ways for get false hits on this + * anti-recursion check! */ + /*WARN_ON(ringbuf->reserved_size);*/ + WARN_ON(ringbuf->reserved_in_use); + + ringbuf->reserved_size = size; + + /* + * Really need to call _begin() here but that currently leads to + * recursion problems! This will be fixed later but for now just + * return and hope for the best. Note that there is only a real + * problem if the create of the request never actually calls _begin() + * but if they are not submitting any work then why did they create + * the request in the first place? + */ +} + +void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf) +{ + WARN_ON(ringbuf->reserved_in_use); + + ringbuf->reserved_size = 0; + ringbuf->reserved_in_use = false; +} + +void intel_ring_reserved_space_use(struct intel_ringbuffer *ringbuf) +{ + WARN_ON(ringbuf->reserved_in_use); + + ringbuf->reserved_in_use = true; + ringbuf->reserved_tail = ringbuf->tail; +} + +void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf) +{ + WARN_ON(!ringbuf->reserved_in_use); + WARN(ringbuf->tail > ringbuf->reserved_tail + ringbuf->reserved_size, + "request reserved size too small: %d vs %d!\n", + ringbuf->tail - ringbuf->reserved_tail, ringbuf->reserved_size); + + ringbuf->reserved_size = 0; + ringbuf->reserved_in_use = false; +} + +static int __intel_ring_prepare(struct intel_engine_cs *ring, int bytes) { struct intel_ringbuffer *ringbuf = ring->buffer; int ret; + /* + * Add on the reserved size to the request to make sure that after + * the intended commands have been emitted, there is guaranteed to + * still be enough free space to send them to the hardware. + */ + if (!ringbuf->reserved_in_use) + bytes += ringbuf->reserved_size; + if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) { ret = intel_wrap_ring_buffer(ring); if (unlikely(ret)) return ret; + + if(ringbuf->reserved_size) { + uint32_t size = ringbuf->reserved_size; + + intel_ring_reserved_space_cancel(ringbuf); + intel_ring_reserved_space_reserve(ringbuf, size); + } } if (unlikely(ringbuf->space < bytes)) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 64850293559c..73db3ae8f237 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -106,6 +106,9 @@ struct intel_ringbuffer { int space; int size; int effective_size; + int reserved_size; + int reserved_tail; + bool reserved_in_use; /** We track the position of the requests in the ring buffer, and * when each is retired we increment last_retired_head as the GPU @@ -472,4 +475,26 @@ intel_ring_get_request(struct intel_engine_cs *ring) return ring->outstanding_lazy_request; } +/* + * Arbitrary size for largest possible 'add request' sequence. The code paths + * are complex and variable. Empirical measurement shows that the worst case + * is ILK at 136 words. Reserving too much is better than reserving too little + * as that allows for corner cases that might have been missed. So the figure + * has been rounded up to 160 words. + */ +#define MIN_SPACE_FOR_ADD_REQUEST 160 + +/* + * Reserve space in the ring to guarantee that the i915_add_request() call + * will always have sufficient room to do its stuff. The request creation + * code calls this automatically. + */ +void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size); +/* Cancel the reservation, e.g. because the request is being discarded. */ +void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf); +/* Use the reserved space - for use by i915_add_request() only. */ +void intel_ring_reserved_space_use(struct intel_ringbuffer *ringbuf); +/* Finish with the reserved space - for use by i915_add_request() only. */ +void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf); + #endif /* _INTEL_RINGBUFFER_H_ */ -- cgit v1.3-6-gb490 From bf7dc5b70952eb58c4fd57c9b964488650303a32 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:24 +0100 Subject: drm/i915: i915_add_request must not fail The i915_add_request() function is called to keep track of work that has been written to the ring buffer. It adds epilogue commands to track progress (seqno updates and such), moves the request structure onto the right list and other such house keeping tasks. However, the work itself has already been written to the ring and will get executed whether or not the add request call succeeds. So no matter what goes wrong, there isn't a whole lot of point in failing the call. At the moment, this is fine(ish). If the add request does bail early on and not do the housekeeping, the request will still float around in the ring->outstanding_lazy_request field and be picked up next time. It means multiple pieces of work will be tagged as the same request and driver can't actually wait for the first piece of work until something else has been submitted. But it all sort of hangs together. This patch series is all about removing the OLR and guaranteeing that each piece of work gets its own personal request. That means that there is no more 'hoovering up of forgotten requests'. If the request does not get tracked then it will be leaked. Thus the add request call _must_ not fail. The previous patch should have already ensured that it _will_ not fail by removing the potential for running out of ring space. This patch enforces the rule by actually removing the early exit paths and the return code. Note that if something does manage to fail and the epilogue commands don't get written to the ring, the driver will still hang together. The request will be added to the tracking lists. And as in the old case, any subsequent work will generate a new seqno which will suffice for marking the old one as complete. v2: Improved WARNings (Tomas Elf review request). For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 ++-- drivers/gpu/drm/i915/i915_gem.c | 43 ++++++++++++---------------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/i915_gem_render_state.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- drivers/gpu/drm/i915/intel_overlay.c | 8 +++--- drivers/gpu/drm/i915/intel_ringbuffer.c | 8 ++---- 7 files changed, 31 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6446911077d0..b687e9f4dcf9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2887,9 +2887,9 @@ void i915_gem_init_swizzling(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); -int __i915_add_request(struct intel_engine_cs *ring, - struct drm_file *file, - struct drm_i915_gem_object *batch_obj); +void __i915_add_request(struct intel_engine_cs *ring, + struct drm_file *file, + struct drm_i915_gem_object *batch_obj); #define i915_add_request(ring) \ __i915_add_request(ring, NULL, NULL) int __i915_wait_request(struct drm_i915_gem_request *req, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b9e0989063b4..23ee54dbc9c5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1155,15 +1155,12 @@ i915_gem_check_wedge(struct i915_gpu_error *error, int i915_gem_check_olr(struct drm_i915_gem_request *req) { - int ret; - WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex)); - ret = 0; if (req == req->ring->outstanding_lazy_request) - ret = i915_add_request(req->ring); + i915_add_request(req->ring); - return ret; + return 0; } static void fake_irq(unsigned long data) @@ -2466,9 +2463,14 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) return 0; } -int __i915_add_request(struct intel_engine_cs *ring, - struct drm_file *file, - struct drm_i915_gem_object *obj) +/* + * NB: This function is not allowed to fail. Doing so would mean the the + * request is not being tracked for completion but the work itself is + * going to happen on the hardware. This would be a Bad Thing(tm). + */ +void __i915_add_request(struct intel_engine_cs *ring, + struct drm_file *file, + struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = ring->dev->dev_private; struct drm_i915_gem_request *request; @@ -2478,7 +2480,7 @@ int __i915_add_request(struct intel_engine_cs *ring, request = ring->outstanding_lazy_request; if (WARN_ON(request == NULL)) - return -ENOMEM; + return; if (i915.enable_execlists) { ringbuf = request->ctx->engine[ring->id].ringbuf; @@ -2500,15 +2502,12 @@ int __i915_add_request(struct intel_engine_cs *ring, * is that the flush _must_ happen before the next request, no matter * what. */ - if (i915.enable_execlists) { + if (i915.enable_execlists) ret = logical_ring_flush_all_caches(ringbuf, request->ctx); - if (ret) - return ret; - } else { + else ret = intel_ring_flush_all_caches(ring); - if (ret) - return ret; - } + /* Not allowed to fail! */ + WARN(ret, "*_ring_flush_all_caches failed: %d!\n", ret); /* Record the position of the start of the request so that * should we detect the updated seqno part-way through the @@ -2517,17 +2516,15 @@ int __i915_add_request(struct intel_engine_cs *ring, */ request->postfix = intel_ring_get_tail(ringbuf); - if (i915.enable_execlists) { + if (i915.enable_execlists) ret = ring->emit_request(ringbuf, request); - if (ret) - return ret; - } else { + else { ret = ring->add_request(ring); - if (ret) - return ret; request->tail = intel_ring_get_tail(ringbuf); } + /* Not allowed to fail! */ + WARN(ret, "emit|add_request failed: %d!\n", ret); request->head = request_start; @@ -2576,8 +2573,6 @@ int __i915_add_request(struct intel_engine_cs *ring, /* Sanity check that the reserved size was large enough. */ intel_ring_reserved_space_end(ringbuf); - - return 0; } static bool i915_context_is_banned(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 21f8eb659251..8ebc10d0527d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1069,7 +1069,7 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev, ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - (void)__i915_add_request(ring, file, obj); + __i915_add_request(ring, file, obj); } static int diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index 521548a08578..ce4788ff3df5 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -173,7 +173,7 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring) i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - ret = __i915_add_request(ring, NULL, so.obj); + __i915_add_request(ring, NULL, so.obj); /* __i915_add_request moves object to inactive if it fails */ out: i915_gem_render_state_fini(&so); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7451f38b2ef8..5373b0d1068a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1601,7 +1601,7 @@ static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - ret = __i915_add_request(ring, file, so.obj); + __i915_add_request(ring, file, so.obj); /* intel_logical_ring_add_request moves object to inactive if it * fails */ out: diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 25c8ec697da1..e7534b946695 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -220,9 +220,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, WARN_ON(overlay->last_flip_req); i915_gem_request_assign(&overlay->last_flip_req, ring->outstanding_lazy_request); - ret = i915_add_request(ring); - if (ret) - return ret; + i915_add_request(ring); overlay->flip_tail = tail; ret = i915_wait_request(overlay->last_flip_req); @@ -291,7 +289,9 @@ static int intel_overlay_continue(struct intel_overlay *overlay, WARN_ON(overlay->last_flip_req); i915_gem_request_assign(&overlay->last_flip_req, ring->outstanding_lazy_request); - return i915_add_request(ring); + i915_add_request(ring); + + return 0; } static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 0c2bf0ed633d..b48aea12acc4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2166,14 +2166,10 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring) int intel_ring_idle(struct intel_engine_cs *ring) { struct drm_i915_gem_request *req; - int ret; /* We need to add any requests required to flush the objects and ring */ - if (ring->outstanding_lazy_request) { - ret = i915_add_request(ring); - if (ret) - return ret; - } + if (ring->outstanding_lazy_request) + i915_add_request(ring); /* Wait upon the last request to be completed */ if (list_empty(&ring->request_list)) -- cgit v1.3-6-gb490 From 0c8dac889539ab26382ba1636ec1159cae73f2b3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:25 +0100 Subject: drm/i915: Early alloc request in execbuff Start of explicit request management in the execbuffer code path. This patch adds a call to allocate a request structure before all the actual hardware work is done. Thus guaranteeing that all that work is tagged by a known request. At present, nothing further is done with the request, the rest comes later in the series. The only noticable change is that failure to get a request (e.g. due to lack of memory) will be caught earlier in the sequence. It now occurs right at the start before any un-undoable work has been done. v2: Simplified the error handling path. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 8ebc10d0527d..2e41f7281c84 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1611,10 +1611,16 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } else exec_start += i915_gem_obj_offset(batch_obj, vm); + /* Allocate a request for this batch buffer nice and early. */ + ret = i915_gem_request_alloc(ring, ctx); + if (ret) + goto err_batch_unpin; + ret = dev_priv->gt.execbuf_submit(dev, file, ring, ctx, args, &eb->vmas, batch_obj, exec_start, dispatch_flags); +err_batch_unpin: /* * FIXME: We crucially rely upon the active tracking for the (ppgtt) * batch vma for correctness. For less ugly and less fragility this @@ -1623,6 +1629,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, */ if (dispatch_flags & I915_DISPATCH_SECURE) i915_gem_object_ggtt_unpin(batch_obj); + err: /* the request owns the ref now */ i915_gem_context_unreference(ctx); -- cgit v1.3-6-gb490 From 40e895ceca40b9c3104b2abd0ed5c72650fb20a4 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:26 +0100 Subject: drm/i915: Set context in request from creation even in legacy mode In execlist mode, the context object pointer is written in to the request structure (and reference counted) at the point of request creation. In legacy mode, this only happens inside i915_add_request(). This patch updates the legacy code path to match the execlist version. This allows all the intermediate code between request creation and request submission to get at the context object given only a request structure. Thus negating the need to pass context pointers here, there and everywhere. v2: Moved the context reference so it does not need to be undone if the get_seqno() fails. v3: Fixed execlist mode always hitting a warning about invalid last_contexts (which don't exist in execlist mode). v4: Updated for new i915_gem_request_alloc() scheme. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 22 +++++++++------------- drivers/gpu/drm/i915/intel_lrc.c | 11 ++++------- drivers/gpu/drm/i915/intel_lrc.h | 3 +-- 3 files changed, 14 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 23ee54dbc9c5..80705dee92d6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2536,14 +2536,7 @@ void __i915_add_request(struct intel_engine_cs *ring, */ request->batch_obj = obj; - if (!i915.enable_execlists) { - /* Hold a reference to the current context so that we can inspect - * it later in case a hangcheck error event fires. - */ - request->ctx = ring->last_context; - if (request->ctx) - i915_gem_context_reference(request->ctx); - } + WARN_ON(!i915.enable_execlists && (request->ctx != ring->last_context)); request->emitted_jiffies = jiffies; list_add_tail(&request->list, &ring->request_list); @@ -2654,21 +2647,24 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, if (req == NULL) return -ENOMEM; - kref_init(&req->ref); - req->i915 = dev_priv; - ret = i915_gem_get_seqno(ring->dev, &req->seqno); if (ret) goto err; + kref_init(&req->ref); + req->i915 = dev_priv; req->ring = ring; + req->ctx = ctx; + i915_gem_context_reference(req->ctx); if (i915.enable_execlists) - ret = intel_logical_ring_alloc_request_extras(req, ctx); + ret = intel_logical_ring_alloc_request_extras(req); else ret = intel_ring_alloc_request_extras(req); - if (ret) + if (ret) { + i915_gem_context_unreference(req->ctx); goto err; + } /* * Reserve space in the ring buffer for all the commands required to diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 5373b0d1068a..6f3ec7197d89 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -659,20 +659,17 @@ static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf, return logical_ring_invalidate_all_caches(ringbuf, ctx); } -int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request, - struct intel_context *ctx) +int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request) { int ret; - if (ctx != request->ring->default_context) { - ret = intel_lr_context_pin(request->ring, ctx); + if (request->ctx != request->ring->default_context) { + ret = intel_lr_context_pin(request->ring, request->ctx); if (ret) return ret; } - request->ringbuf = ctx->engine[request->ring->id].ringbuf; - request->ctx = ctx; - i915_gem_context_reference(request->ctx); + request->ringbuf = request->ctx->engine[request->ring->id].ringbuf; return 0; } diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 04d3a6d8b207..4148de016931 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -36,8 +36,7 @@ #define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0) /* Logical Rings */ -int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request, - struct intel_context *ctx); +int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request); void intel_logical_ring_stop(struct intel_engine_cs *ring); void intel_logical_ring_cleanup(struct intel_engine_cs *ring); int intel_logical_rings_init(struct drm_device *dev); -- cgit v1.3-6-gb490 From 5f19e2bffa63a91cd4ac1adcec648e14a44277ce Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:27 +0100 Subject: drm/i915: Merged the many do_execbuf() parameters into a structure The do_execbuf() function takes quite a few parameters. The actual set of parameters is going to change with the conversion to passing requests around. Further, it is due to grow massively with the arrival of the GPU scheduler. This patch simplifies the prototype by passing a parameter structure instead. Changing the parameter set in the future is then simply a matter of adding/removing items to the structure. Note that the structure does not contain absolutely everything that is passed in. This is because the intention is to use this structure more extensively later in this patch series and more especially in the GPU scheduler that is coming soon. The latter requires hanging on to the structure as the final hardware submission can be delayed until long after the execbuf IOCTL has returned to user land. Thus it is unsafe to put anything in the structure that is local to the IOCTL call itself - such as the 'args' parameter. All entries must be copies of data or pointers to structures that are reference counted in some way and guaranteed to exist for the duration of the batch buffer's life. v2: Rebased to newer tree and updated for changes to the command parser. Specifically, a code shuffle has required saving the batch start address in the params structure. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 28 +++++++------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 59 +++++++++++++++++++----------- drivers/gpu/drm/i915/intel_lrc.c | 26 +++++++------ drivers/gpu/drm/i915/intel_lrc.h | 9 ++--- 4 files changed, 70 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b687e9f4dcf9..e2d0ed05c1e5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1648,6 +1648,17 @@ struct i915_virtual_gpu { bool active; }; +struct i915_execbuffer_params { + struct drm_device *dev; + struct drm_file *file; + uint32_t dispatch_flags; + uint32_t args_batch_start_offset; + uint32_t batch_obj_vm_offset; + struct intel_engine_cs *ring; + struct drm_i915_gem_object *batch_obj; + struct intel_context *ctx; +}; + struct drm_i915_private { struct drm_device *dev; struct kmem_cache *objects; @@ -1885,13 +1896,9 @@ struct drm_i915_private { /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */ struct { - int (*execbuf_submit)(struct drm_device *dev, struct drm_file *file, - struct intel_engine_cs *ring, - struct intel_context *ctx, + int (*execbuf_submit)(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, - struct list_head *vmas, - struct drm_i915_gem_object *batch_obj, - u64 exec_start, u32 flags); + struct list_head *vmas); int (*init_rings)(struct drm_device *dev); void (*cleanup_ring)(struct intel_engine_cs *ring); void (*stop_ring)(struct intel_engine_cs *ring); @@ -2689,14 +2696,9 @@ void i915_gem_execbuffer_retire_commands(struct drm_device *dev, struct drm_file *file, struct intel_engine_cs *ring, struct drm_i915_gem_object *obj); -int i915_gem_ringbuffer_submission(struct drm_device *dev, - struct drm_file *file, - struct intel_engine_cs *ring, - struct intel_context *ctx, +int i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, - struct list_head *vmas, - struct drm_i915_gem_object *batch_obj, - u64 exec_start, u32 flags); + struct list_head *vmas); int i915_gem_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_execbuffer2(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 2e41f7281c84..c5f879e594c4 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1193,17 +1193,15 @@ err: } int -i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, - struct intel_engine_cs *ring, - struct intel_context *ctx, +i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, - struct list_head *vmas, - struct drm_i915_gem_object *batch_obj, - u64 exec_start, u32 dispatch_flags) + struct list_head *vmas) { struct drm_clip_rect *cliprects = NULL; + struct drm_device *dev = params->dev; + struct intel_engine_cs *ring = params->ring; struct drm_i915_private *dev_priv = dev->dev_private; - u64 exec_len; + u64 exec_start, exec_len; int instp_mode; u32 instp_mask; int i, ret = 0; @@ -1255,11 +1253,11 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, if (ret) goto error; - ret = i915_switch_context(ring, ctx); + ret = i915_switch_context(ring, params->ctx); if (ret) goto error; - WARN(ctx->ppgtt && ctx->ppgtt->pd_dirty_rings & (1<id), + WARN(params->ctx->ppgtt && params->ctx->ppgtt->pd_dirty_rings & (1<id), "%s didn't clear reload\n", ring->name); instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK; @@ -1320,7 +1318,10 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, goto error; } - exec_len = args->batch_len; + exec_len = args->batch_len; + exec_start = params->batch_obj_vm_offset + + params->args_batch_start_offset; + if (cliprects) { for (i = 0; i < args->num_cliprects; i++) { ret = i915_emit_box(ring, &cliprects[i], @@ -1330,22 +1331,23 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, ret = ring->dispatch_execbuffer(ring, exec_start, exec_len, - dispatch_flags); + params->dispatch_flags); if (ret) goto error; } } else { ret = ring->dispatch_execbuffer(ring, exec_start, exec_len, - dispatch_flags); + params->dispatch_flags); if (ret) return ret; } - trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), dispatch_flags); + trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); - i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj); + i915_gem_execbuffer_retire_commands(params->dev, params->file, ring, + params->batch_obj); error: kfree(cliprects); @@ -1415,8 +1417,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct intel_engine_cs *ring; struct intel_context *ctx; struct i915_address_space *vm; + struct i915_execbuffer_params params_master; /* XXX: will be removed later */ + struct i915_execbuffer_params *params = ¶ms_master; const u32 ctx_id = i915_execbuffer2_get_context_id(*args); - u64 exec_start = args->batch_start_offset; u32 dispatch_flags; int ret; bool need_relocs; @@ -1509,6 +1512,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, else vm = &dev_priv->gtt.base; + memset(¶ms_master, 0x00, sizeof(params_master)); + eb = eb_create(args); if (eb == NULL) { i915_gem_context_unreference(ctx); @@ -1551,6 +1556,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } + params->args_batch_start_offset = args->batch_start_offset; if (i915_needs_cmd_parser(ring) && args->batch_len) { struct drm_i915_gem_object *parsed_batch_obj; @@ -1582,7 +1588,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * command parser has accepted. */ dispatch_flags |= I915_DISPATCH_SECURE; - exec_start = 0; + params->args_batch_start_offset = 0; batch_obj = parsed_batch_obj; } } @@ -1607,18 +1613,29 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err; - exec_start += i915_gem_obj_ggtt_offset(batch_obj); + params->batch_obj_vm_offset = i915_gem_obj_ggtt_offset(batch_obj); } else - exec_start += i915_gem_obj_offset(batch_obj, vm); + params->batch_obj_vm_offset = i915_gem_obj_offset(batch_obj, vm); /* Allocate a request for this batch buffer nice and early. */ ret = i915_gem_request_alloc(ring, ctx); if (ret) goto err_batch_unpin; - ret = dev_priv->gt.execbuf_submit(dev, file, ring, ctx, args, - &eb->vmas, batch_obj, exec_start, - dispatch_flags); + /* + * Save assorted stuff away to pass through to *_submission(). + * NB: This data should be 'persistent' and not local as it will + * kept around beyond the duration of the IOCTL once the GPU + * scheduler arrives. + */ + params->dev = dev; + params->file = file; + params->ring = ring; + params->dispatch_flags = dispatch_flags; + params->batch_obj = batch_obj; + params->ctx = ctx; + + ret = dev_priv->gt.execbuf_submit(params, args, &eb->vmas); err_batch_unpin: /* diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 6f3ec7197d89..eda3096a5b75 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -858,16 +858,15 @@ static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, * * Return: non-zero if the submission fails. */ -int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, - struct intel_engine_cs *ring, - struct intel_context *ctx, +int intel_execlists_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, - struct list_head *vmas, - struct drm_i915_gem_object *batch_obj, - u64 exec_start, u32 dispatch_flags) + struct list_head *vmas) { + struct drm_device *dev = params->dev; + struct intel_engine_cs *ring = params->ring; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; + struct intel_ringbuffer *ringbuf = params->ctx->engine[ring->id].ringbuf; + u64 exec_start; int instp_mode; u32 instp_mask; int ret; @@ -918,13 +917,13 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, return -EINVAL; } - ret = execlists_move_to_gpu(ringbuf, ctx, vmas); + ret = execlists_move_to_gpu(ringbuf, params->ctx, vmas); if (ret) return ret; if (ring == &dev_priv->ring[RCS] && instp_mode != dev_priv->relative_constants_mode) { - ret = intel_logical_ring_begin(ringbuf, ctx, 4); + ret = intel_logical_ring_begin(ringbuf, params->ctx, 4); if (ret) return ret; @@ -937,14 +936,17 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, dev_priv->relative_constants_mode = instp_mode; } - ret = ring->emit_bb_start(ringbuf, ctx, exec_start, dispatch_flags); + exec_start = params->batch_obj_vm_offset + + args->batch_start_offset; + + ret = ring->emit_bb_start(ringbuf, params->ctx, exec_start, params->dispatch_flags); if (ret) return ret; - trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), dispatch_flags); + trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); - i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj); + i915_gem_execbuffer_retire_commands(params->dev, params->file, ring, params->batch_obj); return 0; } diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 4148de016931..bf137c43e0a9 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -76,13 +76,10 @@ void intel_lr_context_reset(struct drm_device *dev, /* Execlists */ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists); -int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, - struct intel_engine_cs *ring, - struct intel_context *ctx, +struct i915_execbuffer_params; +int intel_execlists_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, - struct list_head *vmas, - struct drm_i915_gem_object *batch_obj, - u64 exec_start, u32 dispatch_flags); + struct list_head *vmas); u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj); void intel_lrc_irq_handler(struct intel_engine_cs *ring); -- cgit v1.3-6-gb490 From adeca76d8e2b34b5c739a36f4191aed63080da40 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:28 +0100 Subject: drm/i915: Simplify i915_gem_execbuffer_retire_commands() parameters Shrunk the parameter list of i915_gem_execbuffer_retire_commands() to a single structure as everything it requires is available in the execbuff_params object. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +---- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 12 ++++-------- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 3 files changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e2d0ed05c1e5..fdb185da2eef 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2692,10 +2692,7 @@ int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_execbuffer_move_to_active(struct list_head *vmas, struct intel_engine_cs *ring); -void i915_gem_execbuffer_retire_commands(struct drm_device *dev, - struct drm_file *file, - struct intel_engine_cs *ring, - struct drm_i915_gem_object *obj); +void i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params); int i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, struct list_head *vmas); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index c5f879e594c4..4bd10df1911c 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1060,16 +1060,13 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, } void -i915_gem_execbuffer_retire_commands(struct drm_device *dev, - struct drm_file *file, - struct intel_engine_cs *ring, - struct drm_i915_gem_object *obj) +i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params) { /* Unconditionally force add_request to emit a full flush. */ - ring->gpu_caches_dirty = true; + params->ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - __i915_add_request(ring, file, obj); + __i915_add_request(params->ring, params->file, params->batch_obj); } static int @@ -1346,8 +1343,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); - i915_gem_execbuffer_retire_commands(params->dev, params->file, ring, - params->batch_obj); + i915_gem_execbuffer_retire_commands(params); error: kfree(cliprects); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index eda3096a5b75..54654d25608a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -946,7 +946,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); - i915_gem_execbuffer_retire_commands(params->dev, params->file, ring, params->batch_obj); + i915_gem_execbuffer_retire_commands(params); return 0; } -- cgit v1.3-6-gb490 From 217e46b576ef0d5eed10ddfeb2b29bd3de289e95 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:29 +0100 Subject: drm/i915: Update alloc_request to return the allocated request The alloc_request() function does not actually return the newly allocated request. Instead, it must be pulled from ring->outstanding_lazy_request. This patch fixes this so that code can create a request and start using it knowing exactly which request it actually owns. v2: Updated for new i915_gem_request_alloc() scheme. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf 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_gem_execbuffer.c | 3 ++- drivers/gpu/drm/i915/intel_lrc.c | 3 ++- drivers/gpu/drm/i915/intel_ringbuffer.c | 3 ++- 5 files changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fdb185da2eef..c439461db9af 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2206,7 +2206,8 @@ struct drm_i915_gem_request { }; int i915_gem_request_alloc(struct intel_engine_cs *ring, - struct intel_context *ctx); + struct intel_context *ctx, + struct drm_i915_gem_request **req_out); void i915_gem_request_cancel(struct drm_i915_gem_request *req); void i915_gem_request_free(struct kref *req_ref); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 80705dee92d6..a0f51478581f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2634,13 +2634,17 @@ void i915_gem_request_free(struct kref *req_ref) } int i915_gem_request_alloc(struct intel_engine_cs *ring, - struct intel_context *ctx) + struct intel_context *ctx, + struct drm_i915_gem_request **req_out) { struct drm_i915_private *dev_priv = to_i915(ring->dev); struct drm_i915_gem_request *req; int ret; - if (ring->outstanding_lazy_request) + if (!req_out) + return -EINVAL; + + if ((*req_out = ring->outstanding_lazy_request) != NULL) return 0; req = kmem_cache_zalloc(dev_priv->requests, GFP_KERNEL); @@ -2686,7 +2690,7 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, */ intel_ring_reserved_space_reserve(req->ringbuf, MIN_SPACE_FOR_ADD_REQUEST); - ring->outstanding_lazy_request = req; + *req_out = ring->outstanding_lazy_request = req; return 0; err: diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 4bd10df1911c..9c9e20ace5e3 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1415,6 +1415,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct i915_address_space *vm; struct i915_execbuffer_params params_master; /* XXX: will be removed later */ struct i915_execbuffer_params *params = ¶ms_master; + struct drm_i915_gem_request *request; const u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 dispatch_flags; int ret; @@ -1614,7 +1615,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, params->batch_obj_vm_offset = i915_gem_obj_offset(batch_obj, vm); /* Allocate a request for this batch buffer nice and early. */ - ret = i915_gem_request_alloc(ring, ctx); + ret = i915_gem_request_alloc(ring, ctx, &request); if (ret) goto err_batch_unpin; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 54654d25608a..8af35889740b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -818,6 +818,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, struct intel_context *ctx, int num_dwords) { + struct drm_i915_gem_request *req; struct intel_engine_cs *ring = ringbuf->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -833,7 +834,7 @@ static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, return ret; /* Preallocate the olr before touching the ring */ - ret = i915_gem_request_alloc(ring, ctx); + ret = i915_gem_request_alloc(ring, ctx, &req); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b48aea12acc4..13eab1757972 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2277,6 +2277,7 @@ static int __intel_ring_prepare(struct intel_engine_cs *ring, int bytes) int intel_ring_begin(struct intel_engine_cs *ring, int num_dwords) { + struct drm_i915_gem_request *req; struct drm_i915_private *dev_priv = ring->dev->dev_private; int ret; @@ -2290,7 +2291,7 @@ int intel_ring_begin(struct intel_engine_cs *ring, return ret; /* Preallocate the olr before touching the ring */ - ret = i915_gem_request_alloc(ring, ring->default_context); + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; -- cgit v1.3-6-gb490 From 6a6ae79a761ddc95b67254e256f82f6d7c9c44d3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:30 +0100 Subject: drm/i915: Add request to execbuf params and add explicit cleanup Rather than just having a local request variable in the execbuff code, the request pointer is now stored in the execbuff params structure. Also added explicit cleanup of the request (plus wiping the OLR to match) in the error case. This means that the execbuff code is no longer dependent upon the OLR keeping track of the request so as to not leak it when things do go wrong. Note that in the success case, the i915_add_request() at the end of the submission function will tidy up the request and clear the OLR. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem_execbuffer.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c439461db9af..4364a209c6a5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1657,6 +1657,7 @@ struct i915_execbuffer_params { struct intel_engine_cs *ring; struct drm_i915_gem_object *batch_obj; struct intel_context *ctx; + struct drm_i915_gem_request *request; }; struct drm_i915_private { diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9c9e20ace5e3..9d53d787fcf6 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1415,7 +1415,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct i915_address_space *vm; struct i915_execbuffer_params params_master; /* XXX: will be removed later */ struct i915_execbuffer_params *params = ¶ms_master; - struct drm_i915_gem_request *request; const u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 dispatch_flags; int ret; @@ -1615,7 +1614,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, params->batch_obj_vm_offset = i915_gem_obj_offset(batch_obj, vm); /* Allocate a request for this batch buffer nice and early. */ - ret = i915_gem_request_alloc(ring, ctx, &request); + ret = i915_gem_request_alloc(ring, ctx, ¶ms->request); if (ret) goto err_batch_unpin; @@ -1649,6 +1648,16 @@ err: i915_gem_context_unreference(ctx); eb_destroy(eb); + /* + * If the request was created but not successfully submitted then it + * must be freed again. If it was submitted then it is being tracked + * on the active request list and no clean up is required here. + */ + if (ret && params->request) { + i915_gem_request_cancel(params->request); + ring->outstanding_lazy_request = NULL; + } + mutex_unlock(&dev->struct_mutex); pre_mutex_err: -- cgit v1.3-6-gb490 From 95c24161cd8561bd2f866a802a44b28fd0a867b7 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:31 +0100 Subject: drm/i915: Update the dispatch tracepoint to use params->request Updated a couple of trace points to use the now cached request pointer rather than extracting it from the ring. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9d53d787fcf6..610c3307a02a 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1340,7 +1340,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, return ret; } - trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); + trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); i915_gem_execbuffer_retire_commands(params); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8af35889740b..d94c01547304 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -944,7 +944,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, if (ret) return ret; - trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); + trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); i915_gem_execbuffer_retire_commands(params); -- cgit v1.3-6-gb490 From 535fbe8233d164e76bac515dd7efee699093cea9 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:32 +0100 Subject: drm/i915: Update move_to_gpu() to take a request structure The plan is to pass requests around as the basic submission tracking structure rather than rings and contexts. This patch updates the move_to_gpu() code paths. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 12 ++++++------ drivers/gpu/drm/i915/intel_lrc.c | 12 +++++------- 2 files changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 610c3307a02a..f6ce811a024a 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -891,10 +891,10 @@ err: } static int -i915_gem_execbuffer_move_to_gpu(struct intel_engine_cs *ring, +i915_gem_execbuffer_move_to_gpu(struct drm_i915_gem_request *req, struct list_head *vmas) { - const unsigned other_rings = ~intel_ring_flag(ring); + const unsigned other_rings = ~intel_ring_flag(req->ring); struct i915_vma *vma; uint32_t flush_domains = 0; bool flush_chipset = false; @@ -904,7 +904,7 @@ i915_gem_execbuffer_move_to_gpu(struct intel_engine_cs *ring, struct drm_i915_gem_object *obj = vma->obj; if (obj->active & other_rings) { - ret = i915_gem_object_sync(obj, ring); + ret = i915_gem_object_sync(obj, req->ring); if (ret) return ret; } @@ -916,7 +916,7 @@ i915_gem_execbuffer_move_to_gpu(struct intel_engine_cs *ring, } if (flush_chipset) - i915_gem_chipset_flush(ring->dev); + i915_gem_chipset_flush(req->ring->dev); if (flush_domains & I915_GEM_DOMAIN_GTT) wmb(); @@ -924,7 +924,7 @@ i915_gem_execbuffer_move_to_gpu(struct intel_engine_cs *ring, /* Unconditionally invalidate gpu caches and ensure that we do flush * any residual writes from the previous batch. */ - return intel_ring_invalidate_all_caches(ring); + return intel_ring_invalidate_all_caches(req->ring); } static bool @@ -1246,7 +1246,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, } } - ret = i915_gem_execbuffer_move_to_gpu(ring, vmas); + ret = i915_gem_execbuffer_move_to_gpu(params->request, vmas); if (ret) goto error; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d94c01547304..aa12a595a309 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -624,12 +624,10 @@ static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf, return 0; } -static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, +static int execlists_move_to_gpu(struct drm_i915_gem_request *req, struct list_head *vmas) { - struct intel_engine_cs *ring = ringbuf->ring; - const unsigned other_rings = ~intel_ring_flag(ring); + const unsigned other_rings = ~intel_ring_flag(req->ring); struct i915_vma *vma; uint32_t flush_domains = 0; bool flush_chipset = false; @@ -639,7 +637,7 @@ static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf, struct drm_i915_gem_object *obj = vma->obj; if (obj->active & other_rings) { - ret = i915_gem_object_sync(obj, ring); + ret = i915_gem_object_sync(obj, req->ring); if (ret) return ret; } @@ -656,7 +654,7 @@ static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf, /* Unconditionally invalidate gpu caches and ensure that we do flush * any residual writes from the previous batch. */ - return logical_ring_invalidate_all_caches(ringbuf, ctx); + return logical_ring_invalidate_all_caches(req->ringbuf, req->ctx); } int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request) @@ -918,7 +916,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, return -EINVAL; } - ret = execlists_move_to_gpu(ringbuf, params->ctx, vmas); + ret = execlists_move_to_gpu(params->request, vmas); if (ret) return ret; -- cgit v1.3-6-gb490 From 8a8edb59172983a7c4aa46ab35b5a23a49c729c5 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:33 +0100 Subject: drm/i915: Update execbuffer_move_to_active() to take a request structure The plan is to pass requests around as the basic submission tracking structure rather than rings and contexts. This patch updates the execbuffer_move_to_active() code path. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 6 +++--- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4364a209c6a5..14154c460762 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2693,7 +2693,7 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_execbuffer_move_to_active(struct list_head *vmas, - struct intel_engine_cs *ring); + struct drm_i915_gem_request *req); void i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params); int i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index f6ce811a024a..76bfc68d1a88 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1020,9 +1020,9 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, void i915_gem_execbuffer_move_to_active(struct list_head *vmas, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { - struct drm_i915_gem_request *req = intel_ring_get_request(ring); + struct intel_engine_cs *ring = i915_gem_request_get_ring(req); struct i915_vma *vma; list_for_each_entry(vma, vmas, exec_list) { @@ -1342,7 +1342,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags); - i915_gem_execbuffer_move_to_active(vmas, ring); + i915_gem_execbuffer_move_to_active(vmas, params->request); i915_gem_execbuffer_retire_commands(params); error: diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index aa12a595a309..754aa39eb12b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -944,7 +944,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags); - i915_gem_execbuffer_move_to_active(vmas, ring); + i915_gem_execbuffer_move_to_active(vmas, params->request); i915_gem_execbuffer_retire_commands(params); return 0; -- cgit v1.3-6-gb490 From 5b4a60c2768434a8c6d5f803a2410245334b8bf7 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:34 +0100 Subject: drm/i915: Add flag to i915_add_request() to skip the cache flush In order to explcitly track all GPU work (and completely remove the outstanding lazy request), it is necessary to add extra i915_add_request() calls to various places. Some of these do not need the implicit cache flush done as part of the standard batch buffer submission process. This patch adds a flag to _add_request() to specify whether the flush is required or not. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 +++++-- drivers/gpu/drm/i915/i915_gem.c | 17 ++++++++++------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/i915_gem_render_state.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 5 files changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 14154c460762..104893bea2f1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2890,9 +2890,12 @@ int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); void __i915_add_request(struct intel_engine_cs *ring, struct drm_file *file, - struct drm_i915_gem_object *batch_obj); + struct drm_i915_gem_object *batch_obj, + bool flush_caches); #define i915_add_request(ring) \ - __i915_add_request(ring, NULL, NULL) + __i915_add_request(ring, NULL, NULL, true) +#define i915_add_request_no_flush(ring) \ + __i915_add_request(ring, NULL, NULL, false) int __i915_wait_request(struct drm_i915_gem_request *req, unsigned reset_counter, bool interruptible, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a0f51478581f..74c319350876 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2470,7 +2470,8 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) */ void __i915_add_request(struct intel_engine_cs *ring, struct drm_file *file, - struct drm_i915_gem_object *obj) + struct drm_i915_gem_object *obj, + bool flush_caches) { struct drm_i915_private *dev_priv = ring->dev->dev_private; struct drm_i915_gem_request *request; @@ -2502,12 +2503,14 @@ void __i915_add_request(struct intel_engine_cs *ring, * is that the flush _must_ happen before the next request, no matter * what. */ - if (i915.enable_execlists) - ret = logical_ring_flush_all_caches(ringbuf, request->ctx); - else - ret = intel_ring_flush_all_caches(ring); - /* Not allowed to fail! */ - WARN(ret, "*_ring_flush_all_caches failed: %d!\n", ret); + if (flush_caches) { + if (i915.enable_execlists) + ret = logical_ring_flush_all_caches(ringbuf, request->ctx); + else + ret = intel_ring_flush_all_caches(ring); + /* Not allowed to fail! */ + WARN(ret, "*_ring_flush_all_caches failed: %d!\n", ret); + } /* Record the position of the start of the request so that * should we detect the updated seqno part-way through the diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 76bfc68d1a88..a15517249bb9 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1066,7 +1066,7 @@ i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params) params->ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - __i915_add_request(params->ring, params->file, params->batch_obj); + __i915_add_request(params->ring, params->file, params->batch_obj, true); } static int diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index ce4788ff3df5..4418616301e7 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -173,7 +173,7 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring) i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, NULL, so.obj); + __i915_add_request(ring, NULL, so.obj, true); /* __i915_add_request moves object to inactive if it fails */ out: i915_gem_render_state_fini(&so); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 754aa39eb12b..47443b9aa172 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1599,7 +1599,7 @@ static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, file, so.obj); + __i915_add_request(ring, file, so.obj, true); /* intel_logical_ring_add_request moves object to inactive if it * fails */ out: -- cgit v1.3-6-gb490 From 73cfa86512813807f39a51a21d14774a29714e15 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:35 +0100 Subject: drm/i915: Update i915_gpu_idle() to manage its own request Added explicit request creation and submission to the GPU idle code path. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 74c319350876..1a3a65d02238 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3305,11 +3305,23 @@ int i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ for_each_ring(ring, dev_priv, i) { if (!i915.enable_execlists) { - ret = i915_switch_context(ring, ring->default_context); + struct drm_i915_gem_request *req; + + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; + + ret = i915_switch_context(req->ring, ring->default_context); + if (ret) { + i915_gem_request_cancel(req); + return ret; + } + + i915_add_request_no_flush(req->ring); } + WARN_ON(ring->outstanding_lazy_request); + ret = intel_ring_idle(ring); if (ret) return ret; -- cgit v1.3-6-gb490 From 4ad2fd888bd3fa53e4bd36e5552bd784fb7ba241 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 18 Jun 2015 13:11:20 +0100 Subject: drm/i915: Split i915_ppgtt_init_hw() in half - generic and per ring The i915_gem_init_hw() function calls a bunch of smaller initialisation functions. Multiple of which have generic sections and per ring sections. This means multiple passes are done over the rings. Each pass writes data to the ring which floats around in that ring's OLR until some random point in the future when an add_request() is done by some random other piece of code. This patch breaks i915_ppgtt_init_hw() in two with the per ring initialisation now being done in i915_ppgtt_init_ring(). The ring looping is now done at the top level in i915_gem_init_hw(). v2: Fix dumb loop variable re-use. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 27 ++++++++++++++++++++------- drivers/gpu/drm/i915/i915_gem_gtt.c | 28 +++++++++++++++------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 1 + 3 files changed, 36 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1a3a65d02238..9522e861a733 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5015,7 +5015,7 @@ i915_gem_init_hw(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring; - int ret, i; + int ret, i, j; if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) return -EIO; @@ -5052,19 +5052,32 @@ i915_gem_init_hw(struct drm_device *dev) */ init_unused_rings(dev); + ret = i915_ppgtt_init_hw(dev); + if (ret) { + DRM_ERROR("PPGTT enable HW failed %d\n", ret); + goto out; + } + + /* Need to do basic initialisation of all rings first: */ for_each_ring(ring, dev_priv, i) { ret = ring->init_hw(ring); if (ret) goto out; } - for (i = 0; i < NUM_L3_SLICES(dev); i++) - i915_gem_l3_remap(&dev_priv->ring[RCS], i); + /* Now it is safe to go back round and do everything else: */ + for_each_ring(ring, dev_priv, i) { + if (ring->id == RCS) { + for (j = 0; j < NUM_L3_SLICES(dev); j++) + i915_gem_l3_remap(ring, j); + } - ret = i915_ppgtt_init_hw(dev); - if (ret && ret != -EIO) { - DRM_ERROR("PPGTT enable failed %d\n", ret); - i915_gem_cleanup_ringbuffer(dev); + ret = i915_ppgtt_init_ring(ring); + if (ret && ret != -EIO) { + DRM_ERROR("PPGTT enable ring #%d failed %d\n", i, ret); + i915_gem_cleanup_ringbuffer(dev); + goto out; + } } ret = i915_gem_context_enable(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index d7ea81aa5ceb..f8ecea22748a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1550,11 +1550,6 @@ int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) int i915_ppgtt_init_hw(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_engine_cs *ring; - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - int i, ret = 0; - /* In the case of execlists, PPGTT is enabled by the context descriptor * and the PDPs are contained within the context itself. We don't * need to do anything here. */ @@ -1573,16 +1568,23 @@ int i915_ppgtt_init_hw(struct drm_device *dev) else MISSING_CASE(INTEL_INFO(dev)->gen); - if (ppgtt) { - for_each_ring(ring, dev_priv, i) { - ret = ppgtt->switch_mm(ppgtt, ring); - if (ret != 0) - return ret; - } - } + return 0; +} - return ret; +int i915_ppgtt_init_ring(struct intel_engine_cs *ring) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; + + if (i915.enable_execlists) + return 0; + + if (!ppgtt) + return 0; + + return ppgtt->switch_mm(ppgtt, ring); } + struct i915_hw_ppgtt * i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 0d46dd20bf71..0caa9ebb615b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -475,6 +475,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev); int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); int i915_ppgtt_init_hw(struct drm_device *dev); +int i915_ppgtt_init_ring(struct intel_engine_cs *ring); void i915_ppgtt_release(struct kref *kref); struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv); -- cgit v1.3-6-gb490 From 90638cc1a4299acf19ed6fe253517a86d52a02ab Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:37 +0100 Subject: drm/i915: Moved the for_each_ring loop outside of i915_gem_context_enable() The start of day context initialisation code in i915_gem_context_enable() loops over each ring and calls the legacy switch context or the execlist init context code as appropriate. This patch moves the ring looping out of that function in to the top level caller i915_gem_init_hw(). This means the a single pass can be made over all rings doing the PPGTT, L3 remap and context initialisation of each ring altogether. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 17 ++++++++++------- drivers/gpu/drm/i915/i915_gem_context.c | 32 +++++++++++--------------------- 3 files changed, 22 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 104893bea2f1..198e681639b7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3039,7 +3039,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); +int i915_gem_context_enable(struct intel_engine_cs *ring); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_engine_cs *ring, struct intel_context *to); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9522e861a733..a580593f586e 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5052,6 +5052,8 @@ i915_gem_init_hw(struct drm_device *dev) */ init_unused_rings(dev); + BUG_ON(!dev_priv->ring[RCS].default_context); + ret = i915_ppgtt_init_hw(dev); if (ret) { DRM_ERROR("PPGTT enable HW failed %d\n", ret); @@ -5067,6 +5069,8 @@ i915_gem_init_hw(struct drm_device *dev) /* Now it is safe to go back round and do everything else: */ for_each_ring(ring, dev_priv, i) { + WARN_ON(!ring->default_context); + if (ring->id == RCS) { for (j = 0; j < NUM_L3_SLICES(dev); j++) i915_gem_l3_remap(ring, j); @@ -5078,14 +5082,13 @@ i915_gem_init_hw(struct drm_device *dev) i915_gem_cleanup_ringbuffer(dev); goto out; } - } - ret = i915_gem_context_enable(dev_priv); - if (ret && ret != -EIO) { - DRM_ERROR("Context enable failed %d\n", ret); - i915_gem_cleanup_ringbuffer(dev); - - goto out; + ret = i915_gem_context_enable(ring); + if (ret && ret != -EIO) { + DRM_ERROR("Context enable ring #%d failed %d\n", i, ret); + i915_gem_cleanup_ringbuffer(dev); + goto out; + } } out: diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 133afcf4d79e..9687d00c4b92 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -409,32 +409,22 @@ 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) +int i915_gem_context_enable(struct intel_engine_cs *ring) { - struct intel_engine_cs *ring; - int ret, i; - - BUG_ON(!dev_priv->ring[RCS].default_context); + int ret; if (i915.enable_execlists) { - for_each_ring(ring, dev_priv, i) { - if (ring->init_context) { - ret = ring->init_context(ring, - ring->default_context); - if (ret) { - DRM_ERROR("ring init context: %d\n", - ret); - return ret; - } - } - } + if (ring->init_context == NULL) + return 0; + ret = ring->init_context(ring, ring->default_context); } else - for_each_ring(ring, dev_priv, i) { - ret = i915_switch_context(ring, ring->default_context); - if (ret) - return ret; - } + ret = i915_switch_context(ring, ring->default_context); + + if (ret) { + DRM_ERROR("ring init context: %d\n", ret); + return ret; + } return 0; } -- cgit v1.3-6-gb490 From a3fbe05a611811ad8413130f63aaa79428b00377 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:38 +0100 Subject: drm/i915: Don't tag kernel batches as user batches The render state initialisation code does an explicit i915_add_request() call to commit the init commands. It was passing in the initialisation batch buffer to add_request() as the batch object parameter. However, the batch object entry in the request structure (which is all that parameter is used for) is meant for keeping track of user generated batch buffers for blame tagging during GPU hangs. This patch clears the batch object parameter so that kernel generated batch buffers are not tagged as being user generated. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_render_state.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index 4418616301e7..a32a4b9492b6 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -173,7 +173,7 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring) i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, NULL, so.obj, true); + __i915_add_request(ring, NULL, NULL, true); /* __i915_add_request moves object to inactive if it fails */ out: i915_gem_render_state_fini(&so); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 47443b9aa172..550e854a3509 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1599,7 +1599,7 @@ static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, file, so.obj, true); + __i915_add_request(ring, file, NULL, true); /* intel_logical_ring_add_request moves object to inactive if it * fails */ out: -- cgit v1.3-6-gb490 From dc4be6071a24f0d2da6af8ce16c19f276ac4d7a2 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:39 +0100 Subject: drm/i915: Add explicit request management to i915_gem_init_hw() Now that a single per ring loop is being done for all the different intialisation steps in i915_gem_init_hw(), it is possible to add proper request management as well. The last remaining issue is that the context enable call eventually ends up within *_render_state_init() and this does its own private _i915_add_request() call. This patch adds explicit request creation and submission to the top level loop and removes the add_request() from deep within the sub-functions. v2: Updated for removal of batch_obj from add_request call in previous patch. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/i915_gem.c | 12 ++++++++++++ drivers/gpu/drm/i915/i915_gem_render_state.c | 2 -- drivers/gpu/drm/i915/intel_lrc.c | 5 ----- 4 files changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 198e681639b7..75255392e1f4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2169,7 +2169,8 @@ struct drm_i915_gem_request { struct intel_context *ctx; struct intel_ringbuffer *ringbuf; - /** Batch buffer related to this request if any */ + /** Batch buffer related to this request if any (used for + error state dump only) */ struct drm_i915_gem_object *batch_obj; /** Time at which this request was emitted, in jiffies. */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a580593f586e..1872c985f8e5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5069,8 +5069,16 @@ i915_gem_init_hw(struct drm_device *dev) /* Now it is safe to go back round and do everything else: */ for_each_ring(ring, dev_priv, i) { + struct drm_i915_gem_request *req; + WARN_ON(!ring->default_context); + ret = i915_gem_request_alloc(ring, ring->default_context, &req); + if (ret) { + i915_gem_cleanup_ringbuffer(dev); + goto out; + } + if (ring->id == RCS) { for (j = 0; j < NUM_L3_SLICES(dev); j++) i915_gem_l3_remap(ring, j); @@ -5079,6 +5087,7 @@ i915_gem_init_hw(struct drm_device *dev) ret = i915_ppgtt_init_ring(ring); if (ret && ret != -EIO) { DRM_ERROR("PPGTT enable ring #%d failed %d\n", i, ret); + i915_gem_request_cancel(req); i915_gem_cleanup_ringbuffer(dev); goto out; } @@ -5086,9 +5095,12 @@ i915_gem_init_hw(struct drm_device *dev) ret = i915_gem_context_enable(ring); if (ret && ret != -EIO) { DRM_ERROR("Context enable ring #%d failed %d\n", i, ret); + i915_gem_request_cancel(req); i915_gem_cleanup_ringbuffer(dev); goto out; } + + i915_add_request_no_flush(ring); } out: diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index a32a4b9492b6..a07b4ee89fc2 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -173,8 +173,6 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring) i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, NULL, NULL, true); - /* __i915_add_request moves object to inactive if it fails */ out: i915_gem_render_state_fini(&so); return ret; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 550e854a3509..3549ba608e6e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1579,8 +1579,6 @@ static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, { struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; struct render_state so; - struct drm_i915_file_private *file_priv = ctx->file_priv; - struct drm_file *file = file_priv ? file_priv->file : NULL; int ret; ret = i915_gem_render_state_prepare(ring, &so); @@ -1599,9 +1597,6 @@ static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, file, NULL, true); - /* intel_logical_ring_add_request moves object to inactive if it - * fails */ out: i915_gem_render_state_fini(&so); return ret; -- cgit v1.3-6-gb490 From b3dd6b9681e4116bce4dd1145cb162a5a48bac8e Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:40 +0100 Subject: drm/i915: Update ppgtt_init_ring() & context_enable() to take requests The final step in removing the OLR from i915_gem_init_hw() is to pass the newly allocated request structure in to each step rather than passing a ring structure. This patch updates both i915_ppgtt_init_ring() and i915_gem_context_enable() to take request pointers. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_context.c | 3 ++- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 +++--- drivers/gpu/drm/i915/i915_gem_gtt.h | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 75255392e1f4..714caed86cdc 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3040,7 +3040,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 intel_engine_cs *ring); +int i915_gem_context_enable(struct drm_i915_gem_request *req); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_engine_cs *ring, struct intel_context *to); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1872c985f8e5..8fbdfc3e971c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5084,7 +5084,7 @@ i915_gem_init_hw(struct drm_device *dev) i915_gem_l3_remap(ring, j); } - ret = i915_ppgtt_init_ring(ring); + ret = i915_ppgtt_init_ring(req); if (ret && ret != -EIO) { DRM_ERROR("PPGTT enable ring #%d failed %d\n", i, ret); i915_gem_request_cancel(req); @@ -5092,7 +5092,7 @@ i915_gem_init_hw(struct drm_device *dev) goto out; } - ret = i915_gem_context_enable(ring); + ret = i915_gem_context_enable(req); if (ret && ret != -EIO) { DRM_ERROR("Context enable ring #%d failed %d\n", i, ret); i915_gem_request_cancel(req); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 9687d00c4b92..4514d5aa5a93 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -409,8 +409,9 @@ void i915_gem_context_fini(struct drm_device *dev) i915_gem_context_unreference(dctx); } -int i915_gem_context_enable(struct intel_engine_cs *ring) +int i915_gem_context_enable(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; if (i915.enable_execlists) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index f8ecea22748a..81ffd70c335e 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1571,9 +1571,9 @@ int i915_ppgtt_init_hw(struct drm_device *dev) return 0; } -int i915_ppgtt_init_ring(struct intel_engine_cs *ring) +int i915_ppgtt_init_ring(struct drm_i915_gem_request *req) { - struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct drm_i915_private *dev_priv = req->ring->dev->dev_private; struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; if (i915.enable_execlists) @@ -1582,7 +1582,7 @@ int i915_ppgtt_init_ring(struct intel_engine_cs *ring) if (!ppgtt) return 0; - return ppgtt->switch_mm(ppgtt, ring); + return ppgtt->switch_mm(ppgtt, req->ring); } struct i915_hw_ppgtt * diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 0caa9ebb615b..75dfa05d610d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -475,7 +475,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev); int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); int i915_ppgtt_init_hw(struct drm_device *dev); -int i915_ppgtt_init_ring(struct intel_engine_cs *ring); +int i915_ppgtt_init_ring(struct drm_i915_gem_request *req); void i915_ppgtt_release(struct kref *kref); struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv); -- cgit v1.3-6-gb490 From ba01cc9346bce45a8861f36bce2c4c5d44b800b2 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:41 +0100 Subject: drm/i915: Update i915_switch_context() to take a request structure Now that the request is guaranteed to specify the context, it is possible to update the context switch code to use requests rather than ring and context pairs. This patch updates i915_switch_context() accordingly. Also removed the warning that the request's context must match the last context switch's context. As the context switch now gets the context object from the request structure, there is no longer any scope for the two to become out of step. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf 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_context.c | 19 +++++++++---------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 4 files changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 714caed86cdc..b96d4b1a0978 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3042,8 +3042,7 @@ 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_gem_request *req); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); -int i915_switch_context(struct intel_engine_cs *ring, - struct intel_context *to); +int i915_switch_context(struct drm_i915_gem_request *req); struct intel_context * i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); void i915_gem_context_free(struct kref *ctx_ref); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8fbdfc3e971c..4625a2fdc180 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2539,8 +2539,6 @@ void __i915_add_request(struct intel_engine_cs *ring, */ request->batch_obj = obj; - WARN_ON(!i915.enable_execlists && (request->ctx != ring->last_context)); - request->emitted_jiffies = jiffies; list_add_tail(&request->list, &ring->request_list); request->file_priv = NULL; @@ -3311,7 +3309,7 @@ int i915_gpu_idle(struct drm_device *dev) if (ret) return ret; - ret = i915_switch_context(req->ring, ring->default_context); + ret = i915_switch_context(req); if (ret) { i915_gem_request_cancel(req); return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 4514d5aa5a93..f8902bcc3939 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -420,7 +420,7 @@ int i915_gem_context_enable(struct drm_i915_gem_request *req) ret = ring->init_context(ring, ring->default_context); } else - ret = i915_switch_context(ring, ring->default_context); + ret = i915_switch_context(req); if (ret) { DRM_ERROR("ring init context: %d\n", ret); @@ -775,8 +775,7 @@ unpin_out: /** * i915_switch_context() - perform a GPU context switch. - * @ring: ring for which we'll execute the context switch - * @to: the context to switch to + * @req: request for which we'll execute the context switch * * 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, @@ -787,25 +786,25 @@ unpin_out: * switched by writing to the ELSP and requests keep a reference to their * context. */ -int i915_switch_context(struct intel_engine_cs *ring, - struct intel_context *to) +int i915_switch_context(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = ring->dev->dev_private; WARN_ON(i915.enable_execlists); WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); - if (to->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake context */ - if (to != ring->last_context) { - i915_gem_context_reference(to); + if (req->ctx->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake context */ + if (req->ctx != ring->last_context) { + i915_gem_context_reference(req->ctx); if (ring->last_context) i915_gem_context_unreference(ring->last_context); - ring->last_context = to; + ring->last_context = req->ctx; } return 0; } - return do_switch(ring, to); + return do_switch(req->ring, req->ctx); } static bool contexts_enabled(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 a15517249bb9..d0ced5b04f4d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1250,7 +1250,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, if (ret) goto error; - ret = i915_switch_context(ring, params->ctx); + ret = i915_switch_context(params->request); if (ret) goto error; -- cgit v1.3-6-gb490 From abd68d9ed3fbd3280e8780150bd0e01099b02627 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:42 +0100 Subject: drm/i915: Update do_switch() to take a request structure Updated do_switch() to take a request pointer instead of a ring/context pair. v2: Removed some overzealous req-> dereferencing. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index f8902bcc3939..116c98394507 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -614,9 +614,10 @@ needs_pd_load_post(struct intel_engine_cs *ring, struct intel_context *to, return false; } -static int do_switch(struct intel_engine_cs *ring, - struct intel_context *to) +static int do_switch(struct drm_i915_gem_request *req) { + struct intel_context *to = req->ctx; + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = ring->dev->dev_private; struct intel_context *from = ring->last_context; u32 hw_flags = 0; @@ -804,7 +805,7 @@ int i915_switch_context(struct drm_i915_gem_request *req) return 0; } - return do_switch(req->ring, req->ctx); + return do_switch(req); } static bool contexts_enabled(struct drm_device *dev) -- cgit v1.3-6-gb490 From 76c3916887f1225db4b4960c59820db1a995f3cb Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:43 +0100 Subject: drm/i915: Update deferred context creation to do explicit request management In execlist mode, context initialisation is deferred until first use of the given context. This is because execlist mode has per ring context state and thus many more context storage objects than legacy mode and many are never actually used. Previously, the initialisation commands were written to the ring and tagged with some random request structure via the OLR. This seemed to be causing a null pointer deference bug under certain circumstances (BZ:88865). This patch adds explicit request creation and submission to the deferred initialisation code path. Thus removing any reliance on or randomness caused by the OLR. Note that it should be possible to move the deferred context creation until even later - when the context is actually switched to rather than when it is merely validated. This would allow the initialisation to be done within the request of the work that is wanting to use the context. Hence, the extra request that is created, used and retired just for the context init could be removed completely. However, this is left for a follow up patch. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 3549ba608e6e..3d60823e2c20 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2230,13 +2230,22 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, lrc_setup_hardware_status_page(ring, ctx_obj); else if (ring->id == RCS && !ctx->rcs_initialized) { if (ring->init_context) { - ret = ring->init_context(ring, ctx); + struct drm_i915_gem_request *req; + + ret = i915_gem_request_alloc(ring, ctx, &req); + if (ret) + return ret; + + ret = ring->init_context(req->ring, ctx); if (ret) { DRM_ERROR("ring init context: %d\n", ret); + i915_gem_request_cancel(req); ctx->engine[ring->id].ringbuf = NULL; ctx->engine[ring->id].state = NULL; goto error; } + + i915_add_request_no_flush(req->ring); } ctx->rcs_initialized = true; -- cgit v1.3-6-gb490 From 8753181e1006dcebc84127ce29b8f8166bb1ada3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:44 +0100 Subject: drm/i915: Update init_context() to take a request structure Now that everything above has been converted to use requests, it is possible to update init_context() to take a request pointer instead of a ring/context pair. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 4 ++-- drivers/gpu/drm/i915/intel_lrc.c | 9 ++++----- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 +++---- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 +-- 4 files changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 116c98394507..4969fc467ac0 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -418,7 +418,7 @@ int i915_gem_context_enable(struct drm_i915_gem_request *req) if (ring->init_context == NULL) return 0; - ret = ring->init_context(ring, ring->default_context); + ret = ring->init_context(req); } else ret = i915_switch_context(req); @@ -760,7 +760,7 @@ done: if (uninitialized) { if (ring->init_context) { - ret = ring->init_context(ring, to); + ret = ring->init_context(req); if (ret) DRM_ERROR("ring init context: %d\n", ret); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 3d60823e2c20..a8704f3571ff 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1602,16 +1602,15 @@ out: return ret; } -static int gen8_init_rcs_context(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int gen8_init_rcs_context(struct drm_i915_gem_request *req) { int ret; - ret = intel_logical_ring_workarounds_emit(ring, ctx); + ret = intel_logical_ring_workarounds_emit(req->ring, req->ctx); if (ret) return ret; - return intel_lr_context_render_state_init(ring, ctx); + return intel_lr_context_render_state_init(req->ring, req->ctx); } /** @@ -2236,7 +2235,7 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, if (ret) return ret; - ret = ring->init_context(req->ring, ctx); + ret = ring->init_context(req); if (ret) { DRM_ERROR("ring init context: %d\n", ret); i915_gem_request_cancel(req); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 13eab1757972..1b9b2c060533 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -742,16 +742,15 @@ static int intel_ring_workarounds_emit(struct intel_engine_cs *ring, return 0; } -static int intel_rcs_ctx_init(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int intel_rcs_ctx_init(struct drm_i915_gem_request *req) { int ret; - ret = intel_ring_workarounds_emit(ring, ctx); + ret = intel_ring_workarounds_emit(req->ring, req->ctx); if (ret != 0) return ret; - ret = i915_gem_render_state_init(ring); + ret = i915_gem_render_state_init(req->ring); if (ret) DRM_ERROR("init render state: %d\n", ret); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 73db3ae8f237..2bf58fa024ef 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -176,8 +176,7 @@ struct intel_engine_cs { int (*init_hw)(struct intel_engine_cs *ring); - int (*init_context)(struct intel_engine_cs *ring, - struct intel_context *ctx); + int (*init_context)(struct drm_i915_gem_request *req); void (*write_tail)(struct intel_engine_cs *ring, u32 value); -- cgit v1.3-6-gb490 From be01363f0a38c30828aca620e30f8c158910fca6 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:45 +0100 Subject: drm/i915: Update render_state_init() to take a request structure Updated the two render_state_init() functions to take a request pointer instead of a ring. This removes their reliance on the OLR. v2: Rebased to newer tree. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_render_state.c | 14 +++++++------- drivers/gpu/drm/i915/i915_gem_render_state.h | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 18 ++++++++---------- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 4 files changed, 17 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index a07b4ee89fc2..6598f9bc67e5 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -152,26 +152,26 @@ int i915_gem_render_state_prepare(struct intel_engine_cs *ring, return 0; } -int i915_gem_render_state_init(struct intel_engine_cs *ring) +int i915_gem_render_state_init(struct drm_i915_gem_request *req) { struct render_state so; int ret; - ret = i915_gem_render_state_prepare(ring, &so); + ret = i915_gem_render_state_prepare(req->ring, &so); if (ret) return ret; if (so.rodata == NULL) return 0; - ret = ring->dispatch_execbuffer(ring, - so.ggtt_offset, - so.rodata->batch_items * 4, - I915_DISPATCH_SECURE); + ret = req->ring->dispatch_execbuffer(req->ring, + so.ggtt_offset, + so.rodata->batch_items * 4, + I915_DISPATCH_SECURE); if (ret) goto out; - i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req->ring); out: i915_gem_render_state_fini(&so); diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.h b/drivers/gpu/drm/i915/i915_gem_render_state.h index c44961ed3fad..7aa73728178a 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.h +++ b/drivers/gpu/drm/i915/i915_gem_render_state.h @@ -39,7 +39,7 @@ struct render_state { int gen; }; -int i915_gem_render_state_init(struct intel_engine_cs *ring); +int i915_gem_render_state_init(struct drm_i915_gem_request *req); void i915_gem_render_state_fini(struct render_state *so); int i915_gem_render_state_prepare(struct intel_engine_cs *ring, struct render_state *so); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a8704f3571ff..78f3bac9403b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1574,28 +1574,26 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf, return 0; } -static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int intel_lr_context_render_state_init(struct drm_i915_gem_request *req) { - struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; struct render_state so; int ret; - ret = i915_gem_render_state_prepare(ring, &so); + ret = i915_gem_render_state_prepare(req->ring, &so); if (ret) return ret; if (so.rodata == NULL) return 0; - ret = ring->emit_bb_start(ringbuf, - ctx, - so.ggtt_offset, - I915_DISPATCH_SECURE); + ret = req->ring->emit_bb_start(req->ringbuf, + req->ctx, + so.ggtt_offset, + I915_DISPATCH_SECURE); if (ret) goto out; - i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req->ring); out: i915_gem_render_state_fini(&so); @@ -1610,7 +1608,7 @@ static int gen8_init_rcs_context(struct drm_i915_gem_request *req) if (ret) return ret; - return intel_lr_context_render_state_init(req->ring, req->ctx); + return intel_lr_context_render_state_init(req); } /** diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 1b9b2c060533..c5e42fcdecb3 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -750,7 +750,7 @@ static int intel_rcs_ctx_init(struct drm_i915_gem_request *req) if (ret != 0) return ret; - ret = i915_gem_render_state_init(req->ring); + ret = i915_gem_render_state_init(req); if (ret) DRM_ERROR("init render state: %d\n", ret); -- cgit v1.3-6-gb490 From 91af127fd7a2f069046b0b6740473e70e0051492 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 18 Jun 2015 13:14:56 +0100 Subject: drm/i915: Update i915_gem_object_sync() to take a request structure The plan is to pass requests around as the basic submission tracking structure rather than rings and contexts. This patch updates the i915_gem_object_sync() code path. v2: Much more complex patch to share a single request between the sync and the page flip. The _sync() function now supports lazy allocation of the request structure. That is, if one is passed in then that will be used. If one is not, then a request will be allocated and passed back out. Note that the _sync() code does not necessarily require a request. Thus one will only be created until certain situations. The reason the lazy allocation must be done within the _sync() code itself is because the decision to need one or not is not really something that code above can second guess (except in the case where one is definitely not required because no ring is passed in). The call chains above _sync() now support passing a request through which most callers passing in NULL and assuming that no request will be required (because they also pass in NULL for the ring and therefore can't be generating any ring code). The exeception is intel_crtc_page_flip() which now supports having a request returned from _sync(). If one is, then that request is shared by the page flip (if the page flip is of a type to need a request). If _sync() does not generate a request but the page flip does need one, then the page flip path will create its own request. v3: Updated comment description to be clearer about 'to_req' parameter (Tomas Elf review request). Rebased onto newer tree that significantly changed the synchronisation code. v4: Updated comments from review feedback (Tomas Elf) For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++- drivers/gpu/drm/i915/i915_gem.c | 48 ++++++++++++++++++++++-------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 17 +++++++---- drivers/gpu/drm/i915/intel_drv.h | 3 +- drivers/gpu/drm/i915/intel_fbdev.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- drivers/gpu/drm/i915/intel_overlay.c | 2 +- 8 files changed, 57 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b96d4b1a0978..6f2fd3de88e4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2805,7 +2805,8 @@ static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj) int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); int i915_gem_object_sync(struct drm_i915_gem_object *obj, - struct intel_engine_cs *to); + struct intel_engine_cs *to, + struct drm_i915_gem_request **to_req); void i915_vma_move_to_active(struct i915_vma *vma, struct intel_engine_cs *ring); int i915_gem_dumb_create(struct drm_file *file_priv, @@ -2916,6 +2917,7 @@ int __must_check i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, u32 alignment, struct intel_engine_cs *pipelined, + struct drm_i915_gem_request **pipelined_request, const struct i915_ggtt_view *view); void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj, const struct i915_ggtt_view *view); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4625a2fdc180..e80b08b864e7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3094,25 +3094,26 @@ out: static int __i915_gem_object_sync(struct drm_i915_gem_object *obj, struct intel_engine_cs *to, - struct drm_i915_gem_request *req) + struct drm_i915_gem_request *from_req, + struct drm_i915_gem_request **to_req) { struct intel_engine_cs *from; int ret; - from = i915_gem_request_get_ring(req); + from = i915_gem_request_get_ring(from_req); if (to == from) return 0; - if (i915_gem_request_completed(req, true)) + if (i915_gem_request_completed(from_req, true)) return 0; - ret = i915_gem_check_olr(req); + ret = i915_gem_check_olr(from_req); if (ret) return ret; if (!i915_semaphore_is_enabled(obj->base.dev)) { struct drm_i915_private *i915 = to_i915(obj->base.dev); - ret = __i915_wait_request(req, + ret = __i915_wait_request(from_req, atomic_read(&i915->gpu_error.reset_counter), i915->mm.interruptible, NULL, @@ -3120,15 +3121,23 @@ __i915_gem_object_sync(struct drm_i915_gem_object *obj, if (ret) return ret; - i915_gem_object_retire_request(obj, req); + i915_gem_object_retire_request(obj, from_req); } else { int idx = intel_ring_sync_index(from, to); - u32 seqno = i915_gem_request_get_seqno(req); + u32 seqno = i915_gem_request_get_seqno(from_req); + + WARN_ON(!to_req); if (seqno <= from->semaphore.sync_seqno[idx]) return 0; - trace_i915_gem_ring_sync_to(from, to, req); + if (*to_req == NULL) { + ret = i915_gem_request_alloc(to, to->default_context, to_req); + if (ret) + return ret; + } + + trace_i915_gem_ring_sync_to(from, to, from_req); ret = to->semaphore.sync_to(to, from, seqno); if (ret) return ret; @@ -3149,11 +3158,14 @@ __i915_gem_object_sync(struct drm_i915_gem_object *obj, * * @obj: object which may be in use on another ring. * @to: ring we wish to use the object on. May be NULL. + * @to_req: request we wish to use the object for. See below. + * This will be allocated and returned if a request is + * required but not passed in. * * This code is meant to abstract object synchronization with the GPU. * Calling with NULL implies synchronizing the object with the CPU * rather than a particular GPU ring. Conceptually we serialise writes - * between engines inside the GPU. We only allow on engine to write + * between engines inside the GPU. We only allow one engine to write * into a buffer at any time, but multiple readers. To ensure each has * a coherent view of memory, we must: * @@ -3164,11 +3176,22 @@ __i915_gem_object_sync(struct drm_i915_gem_object *obj, * - If we are a write request (pending_write_domain is set), the new * request must wait for outstanding read requests to complete. * + * For CPU synchronisation (NULL to) no request is required. For syncing with + * rings to_req must be non-NULL. However, a request does not have to be + * pre-allocated. If *to_req is NULL and sync commands will be emitted then a + * request will be allocated automatically and returned through *to_req. Note + * that it is not guaranteed that commands will be emitted (because the system + * might already be idle). Hence there is no need to create a request that + * might never have any work submitted. Note further that if a request is + * returned in *to_req, it is the responsibility of the caller to submit + * that request (after potentially adding more work to it). + * * Returns 0 if successful, else propagates up the lower layer error. */ int i915_gem_object_sync(struct drm_i915_gem_object *obj, - struct intel_engine_cs *to) + struct intel_engine_cs *to, + struct drm_i915_gem_request **to_req) { const bool readonly = obj->base.pending_write_domain == 0; struct drm_i915_gem_request *req[I915_NUM_RINGS]; @@ -3190,7 +3213,7 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, req[n++] = obj->last_read_req[i]; } for (i = 0; i < n; i++) { - ret = __i915_gem_object_sync(obj, to, req[i]); + ret = __i915_gem_object_sync(obj, to, req[i], to_req); if (ret) return ret; } @@ -4140,12 +4163,13 @@ int i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, u32 alignment, struct intel_engine_cs *pipelined, + struct drm_i915_gem_request **pipelined_request, const struct i915_ggtt_view *view) { u32 old_read_domains, old_write_domain; int ret; - ret = i915_gem_object_sync(obj, pipelined); + ret = i915_gem_object_sync(obj, pipelined, pipelined_request); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index d0ced5b04f4d..9968c02f76f3 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_execbuffer_move_to_gpu(struct drm_i915_gem_request *req, struct drm_i915_gem_object *obj = vma->obj; if (obj->active & other_rings) { - ret = i915_gem_object_sync(obj, req->ring); + ret = i915_gem_object_sync(obj, req->ring, &req); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index de6f8cc3c6d0..733308697094 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2304,7 +2304,8 @@ int intel_pin_and_fence_fb_obj(struct drm_plane *plane, struct drm_framebuffer *fb, const struct drm_plane_state *plane_state, - struct intel_engine_cs *pipelined) + struct intel_engine_cs *pipelined, + struct drm_i915_gem_request **pipelined_request) { struct drm_device *dev = fb->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2362,7 +2363,7 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane, dev_priv->mm.interruptible = false; ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined, - &view); + pipelined_request, &view); if (ret) goto err_interruptible; @@ -11352,6 +11353,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct intel_unpin_work *work; struct intel_engine_cs *ring; bool mmio_flip; + struct drm_i915_gem_request *request = NULL; int ret; /* @@ -11458,7 +11460,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, */ ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, crtc->primary->state, - mmio_flip ? i915_gem_request_get_ring(obj->last_write_req) : ring); + mmio_flip ? i915_gem_request_get_ring(obj->last_write_req) : ring, &request); if (ret) goto cleanup_pending; @@ -11489,6 +11491,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, intel_ring_get_request(ring)); } + if (request) + i915_add_request_no_flush(request->ring); + work->flip_queued_vblank = drm_crtc_vblank_count(crtc); work->enable_stall_check = true; @@ -11506,6 +11511,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, cleanup_unpin: intel_unpin_fb_obj(fb, crtc->primary->state); cleanup_pending: + if (request) + i915_gem_request_cancel(request); atomic_dec(&intel_crtc->unpin_work_count); mutex_unlock(&dev->struct_mutex); cleanup: @@ -13620,7 +13627,7 @@ intel_prepare_plane_fb(struct drm_plane *plane, if (ret) DRM_DEBUG_KMS("failed to attach phys object\n"); } else { - ret = intel_pin_and_fence_fb_obj(plane, fb, new_state, NULL); + ret = intel_pin_and_fence_fb_obj(plane, fb, new_state, NULL, NULL); } if (ret == 0) @@ -15560,7 +15567,7 @@ void intel_modeset_gem_init(struct drm_device *dev) ret = intel_pin_and_fence_fb_obj(c->primary, c->primary->fb, c->primary->state, - NULL); + NULL, NULL); mutex_unlock(&dev->struct_mutex); if (ret) { DRM_ERROR("failed to pin boot fb on pipe %d\n", diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e2174fd3030b..3529c9c9c420 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1045,7 +1045,8 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, int intel_pin_and_fence_fb_obj(struct drm_plane *plane, struct drm_framebuffer *fb, const struct drm_plane_state *plane_state, - struct intel_engine_cs *pipelined); + struct intel_engine_cs *pipelined, + struct drm_i915_gem_request **pipelined_request); struct drm_framebuffer * __intel_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 838214666cc3..2a1724e34a36 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -177,7 +177,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper, } /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL, NULL); + ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL, NULL, NULL); if (ret) { DRM_ERROR("failed to pin obj: %d\n", ret); goto out_fb; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 78f3bac9403b..7bcf1ec4d6aa 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -637,7 +637,7 @@ static int execlists_move_to_gpu(struct drm_i915_gem_request *req, struct drm_i915_gem_object *obj = vma->obj; if (obj->active & other_rings) { - ret = i915_gem_object_sync(obj, req->ring); + ret = i915_gem_object_sync(obj, req->ring, &req); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index e7534b946695..0f8187a12182 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -724,7 +724,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, if (ret != 0) return ret; - ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL, + ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL, NULL, &i915_ggtt_view_normal); if (ret != 0) return ret; -- cgit v1.3-6-gb490 From dad540ce02c5bc82569061c9562982e6f052ee42 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:47 +0100 Subject: drm/i915: Update overlay code to do explicit request management The overlay update code path to do explicit request creation and submission rather than relying on the OLR to do the right thing. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 57 ++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 0f8187a12182..3adb63eb0b99 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -210,17 +210,14 @@ static void intel_overlay_unmap_regs(struct intel_overlay *overlay, } static int intel_overlay_do_wait_request(struct intel_overlay *overlay, + struct drm_i915_gem_request *req, void (*tail)(struct intel_overlay *)) { - struct drm_device *dev = overlay->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_engine_cs *ring = &dev_priv->ring[RCS]; int ret; WARN_ON(overlay->last_flip_req); - i915_gem_request_assign(&overlay->last_flip_req, - ring->outstanding_lazy_request); - i915_add_request(ring); + i915_gem_request_assign(&overlay->last_flip_req, req); + i915_add_request(req->ring); overlay->flip_tail = tail; ret = i915_wait_request(overlay->last_flip_req); @@ -237,15 +234,22 @@ static int intel_overlay_on(struct intel_overlay *overlay) struct drm_device *dev = overlay->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring = &dev_priv->ring[RCS]; + struct drm_i915_gem_request *req; int ret; WARN_ON(overlay->active); WARN_ON(IS_I830(dev) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE)); - ret = intel_ring_begin(ring, 4); + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; + ret = intel_ring_begin(ring, 4); + if (ret) { + i915_gem_request_cancel(req); + return ret; + } + overlay->active = true; intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON); @@ -254,7 +258,7 @@ static int intel_overlay_on(struct intel_overlay *overlay) intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); - return intel_overlay_do_wait_request(overlay, NULL); + return intel_overlay_do_wait_request(overlay, req, NULL); } /* overlay needs to be enabled in OCMD reg */ @@ -264,6 +268,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, struct drm_device *dev = overlay->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring = &dev_priv->ring[RCS]; + struct drm_i915_gem_request *req; u32 flip_addr = overlay->flip_addr; u32 tmp; int ret; @@ -278,18 +283,23 @@ static int intel_overlay_continue(struct intel_overlay *overlay, if (tmp & (1 << 17)) DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp); - ret = intel_ring_begin(ring, 2); + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; + ret = intel_ring_begin(ring, 2); + if (ret) { + i915_gem_request_cancel(req); + return ret; + } + intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); intel_ring_emit(ring, flip_addr); intel_ring_advance(ring); WARN_ON(overlay->last_flip_req); - i915_gem_request_assign(&overlay->last_flip_req, - ring->outstanding_lazy_request); - i915_add_request(ring); + i915_gem_request_assign(&overlay->last_flip_req, req); + i915_add_request(req->ring); return 0; } @@ -327,6 +337,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) struct drm_device *dev = overlay->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring = &dev_priv->ring[RCS]; + struct drm_i915_gem_request *req; u32 flip_addr = overlay->flip_addr; int ret; @@ -338,10 +349,16 @@ static int intel_overlay_off(struct intel_overlay *overlay) * of the hw. Do it in both cases */ flip_addr |= OFC_UPDATE; - ret = intel_ring_begin(ring, 6); + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; + ret = intel_ring_begin(ring, 6); + if (ret) { + i915_gem_request_cancel(req); + return ret; + } + /* wait for overlay to go idle */ intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); intel_ring_emit(ring, flip_addr); @@ -360,7 +377,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) } intel_ring_advance(ring); - return intel_overlay_do_wait_request(overlay, intel_overlay_off_tail); + return intel_overlay_do_wait_request(overlay, req, intel_overlay_off_tail); } /* recover from an interruption due to a signal @@ -404,15 +421,23 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) { /* synchronous slowpath */ - ret = intel_ring_begin(ring, 2); + struct drm_i915_gem_request *req; + + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; + ret = intel_ring_begin(ring, 2); + if (ret) { + i915_gem_request_cancel(req); + return ret; + } + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); - ret = intel_overlay_do_wait_request(overlay, + ret = intel_overlay_do_wait_request(overlay, req, intel_overlay_release_old_vid_tail); if (ret) return ret; -- cgit v1.3-6-gb490 From 6258fbe23fe04da544261f48112a292bdb068c12 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:48 +0100 Subject: drm/i915: Update queue_flip() to take a request structure Updated the display page flip code to do explicit request creation and submission rather than relying on the OLR and just hoping that the request actually gets submitted at some random point. The sequence is now to create a request, queue the work to the ring, assign the known request to the flip queue work item then actually submit the work and post the request. Note that every single flip function used to finish with '__intel_ring_advance(ring);'. However, immediately after they return there is now an add request call which will do the advance anyway. Thus the many duplicate advance calls have been removed. v2: Updated commit message with comment about advance removal. v3: The request can now be allocated by the _sync() code earlier on. Thus the page flip path does not necessarily need to allocate a new request, it may be able to re-use one. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_display.c | 33 +++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 - 4 files changed, 21 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6f2fd3de88e4..0bb6a340d1c9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -640,7 +640,7 @@ struct drm_i915_display_funcs { int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags); void (*update_primary_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 733308697094..36d8cdeaed03 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10868,9 +10868,10 @@ static int intel_gen2_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { + struct intel_engine_cs *ring = req->ring; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 flip_mask; int ret; @@ -10895,7 +10896,6 @@ static int intel_gen2_queue_flip(struct drm_device *dev, intel_ring_emit(ring, 0); /* aux display base address, unused */ intel_mark_page_flip_active(intel_crtc); - __intel_ring_advance(ring); return 0; } @@ -10903,9 +10903,10 @@ static int intel_gen3_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { + struct intel_engine_cs *ring = req->ring; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 flip_mask; int ret; @@ -10927,7 +10928,6 @@ static int intel_gen3_queue_flip(struct drm_device *dev, intel_ring_emit(ring, MI_NOOP); intel_mark_page_flip_active(intel_crtc); - __intel_ring_advance(ring); return 0; } @@ -10935,9 +10935,10 @@ static int intel_gen4_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t pf, pipesrc; @@ -10966,7 +10967,6 @@ static int intel_gen4_queue_flip(struct drm_device *dev, intel_ring_emit(ring, pf | pipesrc); intel_mark_page_flip_active(intel_crtc); - __intel_ring_advance(ring); return 0; } @@ -10974,9 +10974,10 @@ static int intel_gen6_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t pf, pipesrc; @@ -11002,7 +11003,6 @@ static int intel_gen6_queue_flip(struct drm_device *dev, intel_ring_emit(ring, pf | pipesrc); intel_mark_page_flip_active(intel_crtc); - __intel_ring_advance(ring); return 0; } @@ -11010,9 +11010,10 @@ static int intel_gen7_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { + struct intel_engine_cs *ring = req->ring; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t plane_bit = 0; int len, ret; @@ -11097,7 +11098,6 @@ static int intel_gen7_queue_flip(struct drm_device *dev, intel_ring_emit(ring, (MI_NOOP)); intel_mark_page_flip_active(intel_crtc); - __intel_ring_advance(ring); return 0; } @@ -11267,7 +11267,7 @@ static int intel_default_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { return -ENODEV; @@ -11482,13 +11482,18 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, goto cleanup_unpin; } - ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring, + if (!request) { + ret = i915_gem_request_alloc(ring, ring->default_context, &request); + if (ret) + goto cleanup_unpin; + } + + ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request, page_flip_flags); if (ret) goto cleanup_unpin; - i915_gem_request_assign(&work->flip_queued_req, - intel_ring_get_request(ring)); + i915_gem_request_assign(&work->flip_queued_req, request); } if (request) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c5e42fcdecb3..38fa1fad594f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -81,7 +81,7 @@ bool intel_ring_stopped(struct intel_engine_cs *ring) return dev_priv->gpu_error.stop_rings & intel_ring_flag(ring); } -void __intel_ring_advance(struct intel_engine_cs *ring) +static void __intel_ring_advance(struct intel_engine_cs *ring) { struct intel_ringbuffer *ringbuf = ring->buffer; ringbuf->tail &= ringbuf->size - 1; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2bf58fa024ef..8713b0589859 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -442,7 +442,6 @@ int __intel_ring_space(int head, int tail, int size); void intel_ring_update_space(struct intel_ringbuffer *ringbuf); int intel_ring_space(struct intel_ringbuffer *ringbuf); bool intel_ring_stopped(struct intel_engine_cs *ring); -void __intel_ring_advance(struct intel_engine_cs *ring); int __must_check intel_ring_idle(struct intel_engine_cs *ring); void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno); -- cgit v1.3-6-gb490 From 75289874e4484cd4702b3341b654b45b4a09b9d3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:49 +0100 Subject: drm/i915: Update add_request() to take a request structure Now that all callers of i915_add_request() have a request pointer to hand, it is possible to update the add request function to take a request pointer rather than pulling it out of the OLR. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 10 +++++----- drivers/gpu/drm/i915/i915_gem.c | 22 +++++++++++----------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- drivers/gpu/drm/i915/intel_overlay.c | 4 ++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 3 ++- 7 files changed, 23 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0bb6a340d1c9..da7cb141a4d5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2890,14 +2890,14 @@ void i915_gem_init_swizzling(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); -void __i915_add_request(struct intel_engine_cs *ring, +void __i915_add_request(struct drm_i915_gem_request *req, struct drm_file *file, struct drm_i915_gem_object *batch_obj, bool flush_caches); -#define i915_add_request(ring) \ - __i915_add_request(ring, NULL, NULL, true) -#define i915_add_request_no_flush(ring) \ - __i915_add_request(ring, NULL, NULL, false) +#define i915_add_request(req) \ + __i915_add_request(req, NULL, NULL, true) +#define i915_add_request_no_flush(req) \ + __i915_add_request(req, NULL, NULL, false) int __i915_wait_request(struct drm_i915_gem_request *req, unsigned reset_counter, bool interruptible, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e80b08b864e7..c12bdd855be7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1158,7 +1158,7 @@ i915_gem_check_olr(struct drm_i915_gem_request *req) WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex)); if (req == req->ring->outstanding_lazy_request) - i915_add_request(req->ring); + i915_add_request(req); return 0; } @@ -2468,25 +2468,25 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) * request is not being tracked for completion but the work itself is * going to happen on the hardware. This would be a Bad Thing(tm). */ -void __i915_add_request(struct intel_engine_cs *ring, +void __i915_add_request(struct drm_i915_gem_request *request, struct drm_file *file, struct drm_i915_gem_object *obj, bool flush_caches) { - struct drm_i915_private *dev_priv = ring->dev->dev_private; - struct drm_i915_gem_request *request; + struct intel_engine_cs *ring; + struct drm_i915_private *dev_priv; struct intel_ringbuffer *ringbuf; u32 request_start; int ret; - request = ring->outstanding_lazy_request; if (WARN_ON(request == NULL)) return; - if (i915.enable_execlists) { - ringbuf = request->ctx->engine[ring->id].ringbuf; - } else - ringbuf = ring->buffer; + ring = request->ring; + dev_priv = ring->dev->dev_private; + ringbuf = request->ringbuf; + + WARN_ON(request != ring->outstanding_lazy_request); /* * To ensure that this call will not fail, space for its emissions @@ -3338,7 +3338,7 @@ int i915_gpu_idle(struct drm_device *dev) return ret; } - i915_add_request_no_flush(req->ring); + i915_add_request_no_flush(req); } WARN_ON(ring->outstanding_lazy_request); @@ -5122,7 +5122,7 @@ i915_gem_init_hw(struct drm_device *dev) goto out; } - i915_add_request_no_flush(ring); + i915_add_request_no_flush(req); } out: diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9968c02f76f3..896f7a117b99 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1066,7 +1066,7 @@ i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params) params->ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - __i915_add_request(params->ring, params->file, params->batch_obj, true); + __i915_add_request(params->request, params->file, params->batch_obj, true); } static int diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 36d8cdeaed03..7ec2421f0a97 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11497,7 +11497,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, } if (request) - i915_add_request_no_flush(request->ring); + i915_add_request_no_flush(request); work->flip_queued_vblank = drm_crtc_vblank_count(crtc); work->enable_stall_check = true; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7bcf1ec4d6aa..d142d284afd7 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2242,7 +2242,7 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, goto error; } - i915_add_request_no_flush(req->ring); + i915_add_request_no_flush(req); } ctx->rcs_initialized = true; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 3adb63eb0b99..3f709042b86c 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -217,7 +217,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, WARN_ON(overlay->last_flip_req); i915_gem_request_assign(&overlay->last_flip_req, req); - i915_add_request(req->ring); + i915_add_request(req); overlay->flip_tail = tail; ret = i915_wait_request(overlay->last_flip_req); @@ -299,7 +299,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, WARN_ON(overlay->last_flip_req); i915_gem_request_assign(&overlay->last_flip_req, req); - i915_add_request(req->ring); + i915_add_request(req); return 0; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 38fa1fad594f..049bc7fa3c42 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2167,8 +2167,9 @@ int intel_ring_idle(struct intel_engine_cs *ring) struct drm_i915_gem_request *req; /* We need to add any requests required to flush the objects and ring */ + WARN_ON(ring->outstanding_lazy_request); if (ring->outstanding_lazy_request) - i915_add_request(ring); + i915_add_request(ring->outstanding_lazy_request); /* Wait upon the last request to be completed */ if (list_empty(&ring->request_list)) -- cgit v1.3-6-gb490 From b2af03769301e986740c50bf72a47b9abd528290 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:50 +0100 Subject: drm/i915: Update [vma|object]_move_to_active() to take request structures Now that everything above has been converted to use request structures, it is possible to update the lower level move_to_active() functions to be request based as well. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 8 +++++--- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/i915_gem_render_state.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 6 files changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index da7cb141a4d5..74a437f0ae68 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2808,7 +2808,7 @@ int i915_gem_object_sync(struct drm_i915_gem_object *obj, struct intel_engine_cs *to, struct drm_i915_gem_request **to_req); void i915_vma_move_to_active(struct i915_vma *vma, - struct intel_engine_cs *ring); + struct drm_i915_gem_request *req); int i915_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c12bdd855be7..19a244151913 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2340,9 +2340,12 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj) } void i915_vma_move_to_active(struct i915_vma *vma, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { struct drm_i915_gem_object *obj = vma->obj; + struct intel_engine_cs *ring; + + ring = i915_gem_request_get_ring(req); /* Add a reference if we're newly entering the active list. */ if (obj->active == 0) @@ -2350,8 +2353,7 @@ void i915_vma_move_to_active(struct i915_vma *vma, obj->active |= intel_ring_flag(ring); list_move_tail(&obj->ring_list[ring->id], &ring->active_list); - i915_gem_request_assign(&obj->last_read_req[ring->id], - intel_ring_get_request(ring)); + i915_gem_request_assign(&obj->last_read_req[ring->id], req); list_move_tail(&vma->mm_list, &vma->vm->active_list); } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 4969fc467ac0..ea959abb8e2c 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -736,7 +736,7 @@ static int do_switch(struct drm_i915_gem_request *req) */ if (from != NULL) { from->legacy_hw_ctx.rcs_state->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION; - i915_vma_move_to_active(i915_gem_obj_to_ggtt(from->legacy_hw_ctx.rcs_state), ring); + i915_vma_move_to_active(i915_gem_obj_to_ggtt(from->legacy_hw_ctx.rcs_state), req); /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the * whole damn pipeline, we don't need to explicitly mark the * object dirty. The only exception is that the context must be diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 896f7a117b99..6bc86b8916e9 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1036,7 +1036,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, obj->base.pending_read_domains |= obj->base.read_domains; obj->base.read_domains = obj->base.pending_read_domains; - i915_vma_move_to_active(vma, ring); + i915_vma_move_to_active(vma, req); if (obj->base.write_domain) { obj->dirty = 1; i915_gem_request_assign(&obj->last_write_req, req); diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index 6598f9bc67e5..e04cda40df5e 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -171,7 +171,7 @@ int i915_gem_render_state_init(struct drm_i915_gem_request *req) if (ret) goto out; - i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req->ring); + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req); out: i915_gem_render_state_fini(&so); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d142d284afd7..18e2f5f06117 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1593,7 +1593,7 @@ static int intel_lr_context_render_state_init(struct drm_i915_gem_request *req) if (ret) goto out; - i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req->ring); + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req); out: i915_gem_render_state_fini(&so); -- cgit v1.3-6-gb490 From 6909a666466e4a83159df94c4e29cb9cd52fce9e Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:51 +0100 Subject: drm/i915: Update l3_remap to take a request structure Converted i915_gem_l3_remap() to take a request structure instead of a ring. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 5 +++-- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 74a437f0ae68..5aea6ddd5091 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2885,7 +2885,7 @@ bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force); int __must_check i915_gem_init(struct drm_device *dev); int i915_gem_init_rings(struct drm_device *dev); int __must_check i915_gem_init_hw(struct drm_device *dev); -int i915_gem_l3_remap(struct intel_engine_cs *ring, int slice); +int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice); void i915_gem_init_swizzling(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 19a244151913..79c4c328984d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4882,8 +4882,9 @@ err: return ret; } -int i915_gem_l3_remap(struct intel_engine_cs *ring, int slice) +int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice) { + struct intel_engine_cs *ring = req->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 reg_base = GEN7_L3LOG_BASE + (slice * 0x200); @@ -5105,7 +5106,7 @@ i915_gem_init_hw(struct drm_device *dev) if (ring->id == RCS) { for (j = 0; j < NUM_L3_SLICES(dev); j++) - i915_gem_l3_remap(ring, j); + i915_gem_l3_remap(req, j); } ret = i915_ppgtt_init_ring(req); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index ea959abb8e2c..8e52f3c58f61 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -720,7 +720,7 @@ static int do_switch(struct drm_i915_gem_request *req) if (!(to->remap_slice & (1< Date: Fri, 29 May 2015 17:43:52 +0100 Subject: drm/i915: Update mi_set_context() to take a request structure Updated mi_set_context() to take a request structure instead of a ring and context pair. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 8e52f3c58f61..a9dd7e96306e 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -478,10 +478,9 @@ i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id) } static inline int -mi_set_context(struct intel_engine_cs *ring, - struct intel_context *new_context, - u32 hw_flags) +mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) { + struct intel_engine_cs *ring = req->ring; u32 flags = hw_flags | MI_MM_SPACE_GTT; const int num_rings = /* Use an extended w/a on ivb+ if signalling from other rings */ @@ -533,7 +532,7 @@ mi_set_context(struct intel_engine_cs *ring, intel_ring_emit(ring, MI_NOOP); intel_ring_emit(ring, MI_SET_CONTEXT); - intel_ring_emit(ring, i915_gem_obj_ggtt_offset(new_context->legacy_hw_ctx.rcs_state) | + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(req->ctx->legacy_hw_ctx.rcs_state) | flags); /* * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP @@ -695,7 +694,7 @@ static int do_switch(struct drm_i915_gem_request *req) WARN_ON(needs_pd_load_pre(ring, to) && needs_pd_load_post(ring, to, hw_flags)); - ret = mi_set_context(ring, to, hw_flags); + ret = mi_set_context(req, hw_flags); if (ret) goto unpin_out; -- cgit v1.3-6-gb490 From 2f20055d360a2bb6863163d8b8b005ded1f6ba08 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:53 +0100 Subject: drm/i915: Update a bunch of execbuffer helpers to take request structures Updated *_ring_invalidate_all_caches(), i915_reset_gen7_sol_offsets() and i915_emit_box() to take request structures instead of ring or ringbuf/context pairs. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 12 +++++++----- drivers/gpu/drm/i915/intel_lrc.c | 9 ++++----- drivers/gpu/drm/i915/intel_ringbuffer.c | 3 ++- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6bc86b8916e9..1cbd6d65dae5 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -924,7 +924,7 @@ i915_gem_execbuffer_move_to_gpu(struct drm_i915_gem_request *req, /* Unconditionally invalidate gpu caches and ensure that we do flush * any residual writes from the previous batch. */ - return intel_ring_invalidate_all_caches(req->ring); + return intel_ring_invalidate_all_caches(req); } static bool @@ -1071,8 +1071,9 @@ i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params) static int i915_reset_gen7_sol_offsets(struct drm_device *dev, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = dev->dev_private; int ret, i; @@ -1097,10 +1098,11 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, } static int -i915_emit_box(struct intel_engine_cs *ring, +i915_emit_box(struct drm_i915_gem_request *req, struct drm_clip_rect *box, int DR1, int DR4) { + struct intel_engine_cs *ring = req->ring; int ret; if (box->y2 <= box->y1 || box->x2 <= box->x1 || @@ -1310,7 +1312,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, } if (args->flags & I915_EXEC_GEN7_SOL_RESET) { - ret = i915_reset_gen7_sol_offsets(dev, ring); + ret = i915_reset_gen7_sol_offsets(dev, params->request); if (ret) goto error; } @@ -1321,7 +1323,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, if (cliprects) { for (i = 0; i < args->num_cliprects; i++) { - ret = i915_emit_box(ring, &cliprects[i], + ret = i915_emit_box(params->request, &cliprects[i], args->DR1, args->DR4); if (ret) goto error; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 18e2f5f06117..284b48bdffb9 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -604,10 +604,9 @@ static int execlists_context_queue(struct intel_engine_cs *ring, return 0; } -static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx) +static int logical_ring_invalidate_all_caches(struct drm_i915_gem_request *req) { - struct intel_engine_cs *ring = ringbuf->ring; + struct intel_engine_cs *ring = req->ring; uint32_t flush_domains; int ret; @@ -615,7 +614,7 @@ static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf, if (ring->gpu_caches_dirty) flush_domains = I915_GEM_GPU_DOMAINS; - ret = ring->emit_flush(ringbuf, ctx, + ret = ring->emit_flush(req->ringbuf, req->ctx, I915_GEM_GPU_DOMAINS, flush_domains); if (ret) return ret; @@ -654,7 +653,7 @@ static int execlists_move_to_gpu(struct drm_i915_gem_request *req, /* Unconditionally invalidate gpu caches and ensure that we do flush * any residual writes from the previous batch. */ - return logical_ring_invalidate_all_caches(req->ringbuf, req->ctx); + return logical_ring_invalidate_all_caches(req); } int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 049bc7fa3c42..6bdb0ac1edf3 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2910,8 +2910,9 @@ intel_ring_flush_all_caches(struct intel_engine_cs *ring) } int -intel_ring_invalidate_all_caches(struct intel_engine_cs *ring) +intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; uint32_t flush_domains; int ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 8713b0589859..2eba35847946 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -446,7 +446,7 @@ bool intel_ring_stopped(struct intel_engine_cs *ring); int __must_check intel_ring_idle(struct intel_engine_cs *ring); void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno); int intel_ring_flush_all_caches(struct intel_engine_cs *ring); -int intel_ring_invalidate_all_caches(struct intel_engine_cs *ring); +int intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req); void intel_fini_pipe_control(struct intel_engine_cs *ring); int intel_init_pipe_control(struct intel_engine_cs *ring); -- cgit v1.3-6-gb490 From e2be4faf30d6cb0af77c0105837df25f925903c9 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:54 +0100 Subject: drm/i915: Update workarounds_emit() to take request structures Updated the *_ring_workarounds_emit() functions to take requests instead of ring/context pairs. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 14 +++++++------- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 284b48bdffb9..11f0c25c1020 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1058,11 +1058,11 @@ void intel_lr_context_unpin(struct intel_engine_cs *ring, } } -static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) { int ret, i; - struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; + struct intel_engine_cs *ring = req->ring; + struct intel_ringbuffer *ringbuf = req->ringbuf; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct i915_workarounds *w = &dev_priv->workarounds; @@ -1071,11 +1071,11 @@ static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring, return 0; ring->gpu_caches_dirty = true; - ret = logical_ring_flush_all_caches(ringbuf, ctx); + ret = logical_ring_flush_all_caches(ringbuf, req->ctx); if (ret) return ret; - ret = intel_logical_ring_begin(ringbuf, ctx, w->count * 2 + 2); + ret = intel_logical_ring_begin(ringbuf, req->ctx, w->count * 2 + 2); if (ret) return ret; @@ -1089,7 +1089,7 @@ static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring, intel_logical_ring_advance(ringbuf); ring->gpu_caches_dirty = true; - ret = logical_ring_flush_all_caches(ringbuf, ctx); + ret = logical_ring_flush_all_caches(ringbuf, req->ctx); if (ret) return ret; @@ -1603,7 +1603,7 @@ static int gen8_init_rcs_context(struct drm_i915_gem_request *req) { int ret; - ret = intel_logical_ring_workarounds_emit(req->ring, req->ctx); + ret = intel_logical_ring_workarounds_emit(req); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6bdb0ac1edf3..49869feb9e23 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -703,10 +703,10 @@ err: return ret; } -static int intel_ring_workarounds_emit(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req) { int ret, i; + struct intel_engine_cs *ring = req->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct i915_workarounds *w = &dev_priv->workarounds; @@ -746,7 +746,7 @@ static int intel_rcs_ctx_init(struct drm_i915_gem_request *req) { int ret; - ret = intel_ring_workarounds_emit(req->ring, req->ctx); + ret = intel_ring_workarounds_emit(req); if (ret != 0) return ret; -- cgit v1.3-6-gb490 From 4866d729ab3833b811b8972d773477d3e4a6f9c0 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:55 +0100 Subject: drm/i915: Update flush_all_caches() to take request structures Updated the *_ring_flush_all_caches() functions to take requests instead of rings or ringbuf/context pairs. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 4 ++-- drivers/gpu/drm/i915/intel_lrc.c | 11 +++++------ drivers/gpu/drm/i915/intel_lrc.h | 3 +-- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 ++++--- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 5 files changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 79c4c328984d..25fe1ef32eaa 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2507,9 +2507,9 @@ void __i915_add_request(struct drm_i915_gem_request *request, */ if (flush_caches) { if (i915.enable_execlists) - ret = logical_ring_flush_all_caches(ringbuf, request->ctx); + ret = logical_ring_flush_all_caches(request); else - ret = intel_ring_flush_all_caches(ring); + ret = intel_ring_flush_all_caches(request); /* Not allowed to fail! */ WARN(ret, "*_ring_flush_all_caches failed: %d!\n", ret); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 11f0c25c1020..7a18e83623b2 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -997,16 +997,15 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring) I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING)); } -int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx) +int logical_ring_flush_all_caches(struct drm_i915_gem_request *req) { - struct intel_engine_cs *ring = ringbuf->ring; + struct intel_engine_cs *ring = req->ring; int ret; if (!ring->gpu_caches_dirty) return 0; - ret = ring->emit_flush(ringbuf, ctx, 0, I915_GEM_GPU_DOMAINS); + ret = ring->emit_flush(req->ringbuf, req->ctx, 0, I915_GEM_GPU_DOMAINS); if (ret) return ret; @@ -1071,7 +1070,7 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) return 0; ring->gpu_caches_dirty = true; - ret = logical_ring_flush_all_caches(ringbuf, req->ctx); + ret = logical_ring_flush_all_caches(req); if (ret) return ret; @@ -1089,7 +1088,7 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) intel_logical_ring_advance(ringbuf); ring->gpu_caches_dirty = true; - ret = logical_ring_flush_all_caches(ringbuf, req->ctx); + ret = logical_ring_flush_all_caches(req); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index bf137c43e0a9..044c0e5c72e5 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -41,8 +41,7 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring); void intel_logical_ring_cleanup(struct intel_engine_cs *ring); int intel_logical_rings_init(struct drm_device *dev); -int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx); +int logical_ring_flush_all_caches(struct drm_i915_gem_request *req); /** * intel_logical_ring_advance() - advance the ringbuffer tail * @ringbuf: Ringbuffer to advance. diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 49869feb9e23..48ca73e7aaa6 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -715,7 +715,7 @@ static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req) return 0; ring->gpu_caches_dirty = true; - ret = intel_ring_flush_all_caches(ring); + ret = intel_ring_flush_all_caches(req); if (ret) return ret; @@ -733,7 +733,7 @@ static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req) intel_ring_advance(ring); ring->gpu_caches_dirty = true; - ret = intel_ring_flush_all_caches(ring); + ret = intel_ring_flush_all_caches(req); if (ret) return ret; @@ -2892,8 +2892,9 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev) } int -intel_ring_flush_all_caches(struct intel_engine_cs *ring) +intel_ring_flush_all_caches(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; if (!ring->gpu_caches_dirty) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2eba35847946..3f70687a2dc6 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -445,7 +445,7 @@ bool intel_ring_stopped(struct intel_engine_cs *ring); int __must_check intel_ring_idle(struct intel_engine_cs *ring); void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno); -int intel_ring_flush_all_caches(struct intel_engine_cs *ring); +int intel_ring_flush_all_caches(struct drm_i915_gem_request *req); int intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req); void intel_fini_pipe_control(struct intel_engine_cs *ring); -- cgit v1.3-6-gb490 From e85b26dc1ca5ecbf6456c61a131a986a755cbc69 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:56 +0100 Subject: drm/i915: Update switch_mm() to take a request structure Updated the switch_mm() code paths to take a request instead of a ring. This includes the myriad *_mm_switch functions themselves and a bunch of PDP related helper functions. v2: Rebased to newer tree. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 21 +++++++++++++-------- drivers/gpu/drm/i915/i915_gem_gtt.h | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index a9dd7e96306e..a223c9dd16fd 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -652,7 +652,7 @@ static int do_switch(struct drm_i915_gem_request *req) * Register Immediate commands in Ring Buffer before submitting * a context."*/ trace_switch_mm(ring, to); - ret = to->ppgtt->switch_mm(to->ppgtt, ring); + ret = to->ppgtt->switch_mm(to->ppgtt, req); if (ret) goto unpin_out; @@ -703,7 +703,7 @@ static int do_switch(struct drm_i915_gem_request *req) */ if (needs_pd_load_post(ring, to, hw_flags)) { trace_switch_mm(ring, to); - ret = to->ppgtt->switch_mm(to->ppgtt, ring); + ret = to->ppgtt->switch_mm(to->ppgtt, req); /* The hardware context switch is emitted, but we haven't * actually changed the state - so it's probably safe to bail * here. Still, let the user know something dangerous has diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 81ffd70c335e..5b0f512b1a40 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -452,10 +452,11 @@ free_pd: } /* Broadwell Page Directory Pointer Descriptors */ -static int gen8_write_pdp(struct intel_engine_cs *ring, +static int gen8_write_pdp(struct drm_i915_gem_request *req, unsigned entry, dma_addr_t addr) { + struct intel_engine_cs *ring = req->ring; int ret; BUG_ON(entry >= 4); @@ -476,7 +477,7 @@ static int gen8_write_pdp(struct intel_engine_cs *ring, } static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { int i, ret; @@ -485,7 +486,7 @@ static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt, dma_addr_t pd_daddr = pd ? pd->daddr : ppgtt->scratch_pd->daddr; /* The page directory might be NULL, but we need to clear out * whatever the previous context might have used. */ - ret = gen8_write_pdp(ring, i, pd_daddr); + ret = gen8_write_pdp(req, i, pd_daddr); if (ret) return ret; } @@ -1062,8 +1063,9 @@ static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt) } static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; /* NB: TLBs must be flushed and invalidated before a switch */ @@ -1087,8 +1089,9 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, } static int vgpu_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = to_i915(ppgtt->base.dev); I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); @@ -1097,8 +1100,9 @@ static int vgpu_mm_switch(struct i915_hw_ppgtt *ppgtt, } static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; /* NB: TLBs must be flushed and invalidated before a switch */ @@ -1129,8 +1133,9 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, } static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1582,7 +1587,7 @@ int i915_ppgtt_init_ring(struct drm_i915_gem_request *req) if (!ppgtt) return 0; - return ppgtt->switch_mm(ppgtt, req->ring); + return ppgtt->switch_mm(ppgtt, req); } struct i915_hw_ppgtt * diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 75dfa05d610d..735f11986ea6 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -338,7 +338,7 @@ struct i915_hw_ppgtt { int (*enable)(struct i915_hw_ppgtt *ppgtt); int (*switch_mm)(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring); + struct drm_i915_gem_request *req); void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m); }; -- cgit v1.3-6-gb490 From a84c3ae168837dbedd0bde76a536360e84ae863a Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:57 +0100 Subject: drm/i915: Update ring->flush() to take a requests structure Updated the various ring->flush() functions to take a request instead of a ring. Also updated the tracer to include the request id. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf [danvet: Rebase since I didn't merge the addition of req->uniq.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 +++--- drivers/gpu/drm/i915/i915_trace.h | 8 ++++---- drivers/gpu/drm/i915/intel_ringbuffer.c | 34 ++++++++++++++++++++------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 5 files changed, 30 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index a223c9dd16fd..c80b59db3c92 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -495,7 +495,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) * itlb_before_ctx_switch. */ if (IS_GEN6(ring->dev)) { - ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, 0); + ret = ring->flush(req, I915_GEM_GPU_DOMAINS, 0); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 5b0f512b1a40..037f86ed6a8a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1069,7 +1069,7 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, int ret; /* NB: TLBs must be flushed and invalidated before a switch */ - ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + ret = ring->flush(req, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); if (ret) return ret; @@ -1106,7 +1106,7 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, int ret; /* NB: TLBs must be flushed and invalidated before a switch */ - ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + ret = ring->flush(req, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); if (ret) return ret; @@ -1124,7 +1124,7 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, /* 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); + ret = ring->flush(req, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 497cba5deb1e..cf58eeb1c2c0 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -475,8 +475,8 @@ TRACE_EVENT(i915_gem_ring_dispatch, ); TRACE_EVENT(i915_gem_ring_flush, - TP_PROTO(struct intel_engine_cs *ring, u32 invalidate, u32 flush), - TP_ARGS(ring, invalidate, flush), + TP_PROTO(struct drm_i915_gem_request *req, u32 invalidate, u32 flush), + TP_ARGS(req, invalidate, flush), TP_STRUCT__entry( __field(u32, dev) @@ -486,8 +486,8 @@ TRACE_EVENT(i915_gem_ring_flush, ), TP_fast_assign( - __entry->dev = ring->dev->primary->index; - __entry->ring = ring->id; + __entry->dev = req->ring->dev->primary->index; + __entry->ring = req->ring->id; __entry->invalidate = invalidate; __entry->flush = flush; ), diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 48ca73e7aaa6..2425dc2db42c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -91,10 +91,11 @@ static void __intel_ring_advance(struct intel_engine_cs *ring) } static int -gen2_render_ring_flush(struct intel_engine_cs *ring, +gen2_render_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; u32 cmd; int ret; @@ -117,10 +118,11 @@ gen2_render_ring_flush(struct intel_engine_cs *ring, } static int -gen4_render_ring_flush(struct intel_engine_cs *ring, +gen4_render_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; struct drm_device *dev = ring->dev; u32 cmd; int ret; @@ -247,9 +249,10 @@ intel_emit_post_sync_nonzero_flush(struct intel_engine_cs *ring) } static int -gen6_render_ring_flush(struct intel_engine_cs *ring, - u32 invalidate_domains, u32 flush_domains) +gen6_render_ring_flush(struct drm_i915_gem_request *req, + u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; u32 flags = 0; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; @@ -318,9 +321,10 @@ gen7_render_ring_cs_stall_wa(struct intel_engine_cs *ring) } static int -gen7_render_ring_flush(struct intel_engine_cs *ring, +gen7_render_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; u32 flags = 0; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; @@ -400,9 +404,10 @@ gen8_emit_pipe_control(struct intel_engine_cs *ring, } static int -gen8_render_ring_flush(struct intel_engine_cs *ring, +gen8_render_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; u32 flags = 0; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; @@ -1594,10 +1599,11 @@ i8xx_ring_put_irq(struct intel_engine_cs *ring) } static int -bsd_ring_flush(struct intel_engine_cs *ring, +bsd_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 2); @@ -2372,9 +2378,10 @@ static void gen6_bsd_ring_write_tail(struct intel_engine_cs *ring, _MASKED_BIT_DISABLE(GEN6_BSD_SLEEP_MSG_DISABLE)); } -static int gen6_bsd_ring_flush(struct intel_engine_cs *ring, +static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req, u32 invalidate, u32 flush) { + struct intel_engine_cs *ring = req->ring; uint32_t cmd; int ret; @@ -2484,9 +2491,10 @@ gen6_ring_dispatch_execbuffer(struct intel_engine_cs *ring, /* Blitter support (SandyBridge+) */ -static int gen6_ring_flush(struct intel_engine_cs *ring, +static int gen6_ring_flush(struct drm_i915_gem_request *req, u32 invalidate, u32 flush) { + struct intel_engine_cs *ring = req->ring; struct drm_device *dev = ring->dev; uint32_t cmd; int ret; @@ -2900,11 +2908,11 @@ intel_ring_flush_all_caches(struct drm_i915_gem_request *req) if (!ring->gpu_caches_dirty) return 0; - ret = ring->flush(ring, 0, I915_GEM_GPU_DOMAINS); + ret = ring->flush(req, 0, I915_GEM_GPU_DOMAINS); if (ret) return ret; - trace_i915_gem_ring_flush(ring, 0, I915_GEM_GPU_DOMAINS); + trace_i915_gem_ring_flush(req, 0, I915_GEM_GPU_DOMAINS); ring->gpu_caches_dirty = false; return 0; @@ -2921,11 +2929,11 @@ intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req) if (ring->gpu_caches_dirty) flush_domains = I915_GEM_GPU_DOMAINS; - ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, flush_domains); + ret = ring->flush(req, I915_GEM_GPU_DOMAINS, flush_domains); if (ret) return ret; - trace_i915_gem_ring_flush(ring, I915_GEM_GPU_DOMAINS, flush_domains); + trace_i915_gem_ring_flush(req, I915_GEM_GPU_DOMAINS, flush_domains); ring->gpu_caches_dirty = false; return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 3f70687a2dc6..4c0d3296b78f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -180,7 +180,7 @@ struct intel_engine_cs { void (*write_tail)(struct intel_engine_cs *ring, u32 value); - int __must_check (*flush)(struct intel_engine_cs *ring, + int __must_check (*flush)(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains); int (*add_request)(struct intel_engine_cs *ring); -- cgit v1.3-6-gb490 From f2cf1fcc70d6577dce73f269609e0753e1a99802 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:58 +0100 Subject: drm/i915: Update some flush helpers to take request structures Updated intel_emit_post_sync_nonzero_flush(), gen7_render_ring_cs_stall_wa() and gen8_emit_pipe_control() to take requests instead of rings. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 2425dc2db42c..e0aa008f0555 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -214,8 +214,9 @@ gen4_render_ring_flush(struct drm_i915_gem_request *req, * really our business. That leaves only stall at scoreboard. */ static int -intel_emit_post_sync_nonzero_flush(struct intel_engine_cs *ring) +intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; @@ -258,7 +259,7 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req, int ret; /* Force SNB workarounds for PIPE_CONTROL flushes */ - ret = intel_emit_post_sync_nonzero_flush(ring); + ret = intel_emit_post_sync_nonzero_flush(req); if (ret) return ret; @@ -302,8 +303,9 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req, } static int -gen7_render_ring_cs_stall_wa(struct intel_engine_cs *ring) +gen7_render_ring_cs_stall_wa(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 4); @@ -366,7 +368,7 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req, /* Workaround: we must issue a pipe_control with CS-stall bit * set before a pipe_control command that has the state cache * invalidate bit set. */ - gen7_render_ring_cs_stall_wa(ring); + gen7_render_ring_cs_stall_wa(req); } ret = intel_ring_begin(ring, 4); @@ -383,9 +385,10 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req, } static int -gen8_emit_pipe_control(struct intel_engine_cs *ring, +gen8_emit_pipe_control(struct drm_i915_gem_request *req, u32 flags, u32 scratch_addr) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 6); @@ -407,9 +410,8 @@ static int gen8_render_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { - struct intel_engine_cs *ring = req->ring; u32 flags = 0; - u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; + u32 scratch_addr = req->ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; flags |= PIPE_CONTROL_CS_STALL; @@ -429,7 +431,7 @@ gen8_render_ring_flush(struct drm_i915_gem_request *req, flags |= PIPE_CONTROL_GLOBAL_GTT_IVB; /* WaCsStallBeforeStateCacheInvalidate:bdw,chv */ - ret = gen8_emit_pipe_control(ring, + ret = gen8_emit_pipe_control(req, PIPE_CONTROL_CS_STALL | PIPE_CONTROL_STALL_AT_SCOREBOARD, 0); @@ -437,7 +439,7 @@ gen8_render_ring_flush(struct drm_i915_gem_request *req, return ret; } - return gen8_emit_pipe_control(ring, flags, scratch_addr); + return gen8_emit_pipe_control(req, flags, scratch_addr); } static void ring_write_tail(struct intel_engine_cs *ring, -- cgit v1.3-6-gb490 From 7deb4d3980ea44ebb4097426f85d5f6c89b873a4 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:59 +0100 Subject: drm/i915: Update ring->emit_flush() to take a request structure Updated the various ring->emit_flush() implementations to take a request instead of a ringbuf/context pair. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 17 ++++++++--------- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 +-- 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7a18e83623b2..97390fa0684d 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -614,8 +614,7 @@ static int logical_ring_invalidate_all_caches(struct drm_i915_gem_request *req) if (ring->gpu_caches_dirty) flush_domains = I915_GEM_GPU_DOMAINS; - ret = ring->emit_flush(req->ringbuf, req->ctx, - I915_GEM_GPU_DOMAINS, flush_domains); + ret = ring->emit_flush(req, I915_GEM_GPU_DOMAINS, flush_domains); if (ret) return ret; @@ -1005,7 +1004,7 @@ int logical_ring_flush_all_caches(struct drm_i915_gem_request *req) if (!ring->gpu_caches_dirty) return 0; - ret = ring->emit_flush(req->ringbuf, req->ctx, 0, I915_GEM_GPU_DOMAINS); + ret = ring->emit_flush(req, 0, I915_GEM_GPU_DOMAINS); if (ret) return ret; @@ -1420,18 +1419,18 @@ static void gen8_logical_ring_put_irq(struct intel_engine_cs *ring) spin_unlock_irqrestore(&dev_priv->irq_lock, flags); } -static int gen8_emit_flush(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, +static int gen8_emit_flush(struct drm_i915_gem_request *request, u32 invalidate_domains, u32 unused) { + struct intel_ringbuffer *ringbuf = request->ringbuf; struct intel_engine_cs *ring = ringbuf->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t cmd; int ret; - ret = intel_logical_ring_begin(ringbuf, ctx, 4); + ret = intel_logical_ring_begin(ringbuf, request->ctx, 4); if (ret) return ret; @@ -1461,11 +1460,11 @@ static int gen8_emit_flush(struct intel_ringbuffer *ringbuf, return 0; } -static int gen8_emit_flush_render(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, +static int gen8_emit_flush_render(struct drm_i915_gem_request *request, u32 invalidate_domains, u32 flush_domains) { + struct intel_ringbuffer *ringbuf = request->ringbuf; struct intel_engine_cs *ring = ringbuf->ring; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; bool vf_flush_wa; @@ -1497,7 +1496,7 @@ static int gen8_emit_flush_render(struct intel_ringbuffer *ringbuf, vf_flush_wa = INTEL_INFO(ring->dev)->gen >= 9 && flags & PIPE_CONTROL_VF_CACHE_INVALIDATE; - ret = intel_logical_ring_begin(ringbuf, ctx, vf_flush_wa ? 12 : 6); + ret = intel_logical_ring_begin(ringbuf, request->ctx, vf_flush_wa ? 12 : 6); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 4c0d3296b78f..8c713f625755 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -268,8 +268,7 @@ struct intel_engine_cs { u32 irq_keep_mask; /* bitmask for interrupts that should not be masked */ int (*emit_request)(struct intel_ringbuffer *ringbuf, struct drm_i915_gem_request *request); - int (*emit_flush)(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, + int (*emit_flush)(struct drm_i915_gem_request *request, u32 invalidate_domains, u32 flush_domains); int (*emit_bb_start)(struct intel_ringbuffer *ringbuf, -- cgit v1.3-6-gb490 From ee044a8863de58044cb370c23f97b9b68b33e47b Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:00 +0100 Subject: drm/i915: Update ring->add_request() to take a request structure Updated the various ring->add_request() implementations to take a request instead of a ring. This removes their reliance on the OLR to obtain the seqno value that the request should be tagged with. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 26 ++++++++++++-------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 25fe1ef32eaa..6d511d32f72a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2524,7 +2524,7 @@ void __i915_add_request(struct drm_i915_gem_request *request, if (i915.enable_execlists) ret = ring->emit_request(ringbuf, request); else { - ret = ring->add_request(ring); + ret = ring->add_request(request); request->tail = intel_ring_get_tail(ringbuf); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e0aa008f0555..28d7801a8fa5 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1288,16 +1288,16 @@ static int gen6_signal(struct intel_engine_cs *signaller, /** * gen6_add_request - Update the semaphore mailbox registers - * - * @ring - ring that is adding a request - * @seqno - return seqno stuck into the ring + * + * @request - request to write to the ring * * Update the mailbox registers in the *other* rings with the current seqno. * This acts like a signal in the canonical semaphore. */ static int -gen6_add_request(struct intel_engine_cs *ring) +gen6_add_request(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; if (ring->semaphore.signal) @@ -1310,8 +1310,7 @@ gen6_add_request(struct intel_engine_cs *ring) intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, - i915_gem_request_get_seqno(ring->outstanding_lazy_request)); + intel_ring_emit(ring, i915_gem_request_get_seqno(req)); intel_ring_emit(ring, MI_USER_INTERRUPT); __intel_ring_advance(ring); @@ -1408,8 +1407,9 @@ do { \ } while (0) static int -pc_render_add_request(struct intel_engine_cs *ring) +pc_render_add_request(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; @@ -1429,8 +1429,7 @@ pc_render_add_request(struct intel_engine_cs *ring) PIPE_CONTROL_WRITE_FLUSH | PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE); intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, - i915_gem_request_get_seqno(ring->outstanding_lazy_request)); + intel_ring_emit(ring, i915_gem_request_get_seqno(req)); intel_ring_emit(ring, 0); PIPE_CONTROL_FLUSH(ring, scratch_addr); scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */ @@ -1449,8 +1448,7 @@ pc_render_add_request(struct intel_engine_cs *ring) PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE | PIPE_CONTROL_NOTIFY); intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, - i915_gem_request_get_seqno(ring->outstanding_lazy_request)); + intel_ring_emit(ring, i915_gem_request_get_seqno(req)); intel_ring_emit(ring, 0); __intel_ring_advance(ring); @@ -1619,8 +1617,9 @@ bsd_ring_flush(struct drm_i915_gem_request *req, } static int -i9xx_add_request(struct intel_engine_cs *ring) +i9xx_add_request(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 4); @@ -1629,8 +1628,7 @@ i9xx_add_request(struct intel_engine_cs *ring) intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, - i915_gem_request_get_seqno(ring->outstanding_lazy_request)); + intel_ring_emit(ring, i915_gem_request_get_seqno(req)); intel_ring_emit(ring, MI_USER_INTERRUPT); __intel_ring_advance(ring); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 8c713f625755..cb6d3d0b2530 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -183,7 +183,7 @@ struct intel_engine_cs { int __must_check (*flush)(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains); - int (*add_request)(struct intel_engine_cs *ring); + int (*add_request)(struct drm_i915_gem_request *req); /* Some chipsets are not quite as coherent as advertised and need * an expensive kick to force a true read of the up-to-date seqno. * However, the up-to-date seqno is not always required and the last -- cgit v1.3-6-gb490 From c4e766389e8b7ce3ceb7f2785d4bb94b82448ff0 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:01 +0100 Subject: drm/i915: Update ring->emit_request() to take a request structure Updated the ring->emit_request() implementation to take a request instead of a ringbuf/request pair. Also removed its use of the OLR for obtaining the request's seqno. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 7 +++---- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6d511d32f72a..339799c5aceb 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2522,7 +2522,7 @@ void __i915_add_request(struct drm_i915_gem_request *request, request->postfix = intel_ring_get_tail(ringbuf); if (i915.enable_execlists) - ret = ring->emit_request(ringbuf, request); + ret = ring->emit_request(request); else { ret = ring->add_request(request); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 97390fa0684d..9be732b40121 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1530,9 +1530,9 @@ static void gen8_set_seqno(struct intel_engine_cs *ring, u32 seqno) intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno); } -static int gen8_emit_request(struct intel_ringbuffer *ringbuf, - struct drm_i915_gem_request *request) +static int gen8_emit_request(struct drm_i915_gem_request *request) { + struct intel_ringbuffer *ringbuf = request->ringbuf; struct intel_engine_cs *ring = ringbuf->ring; u32 cmd; int ret; @@ -1554,8 +1554,7 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf, (ring->status_page.gfx_addr + (I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT))); intel_logical_ring_emit(ringbuf, 0); - intel_logical_ring_emit(ringbuf, - i915_gem_request_get_seqno(ring->outstanding_lazy_request)); + intel_logical_ring_emit(ringbuf, i915_gem_request_get_seqno(request)); intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT); intel_logical_ring_emit(ringbuf, MI_NOOP); intel_logical_ring_advance_and_submit(ringbuf, request->ctx, request); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index cb6d3d0b2530..96b8e353a1f0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -266,8 +266,7 @@ struct intel_engine_cs { struct list_head execlist_retired_req_list; u8 next_context_status_buffer; u32 irq_keep_mask; /* bitmask for interrupts that should not be masked */ - int (*emit_request)(struct intel_ringbuffer *ringbuf, - struct drm_i915_gem_request *request); + int (*emit_request)(struct drm_i915_gem_request *request); int (*emit_flush)(struct drm_i915_gem_request *request, u32 invalidate_domains, u32 flush_domains); -- cgit v1.3-6-gb490 From 53fddaf70d08aa6ff59a94ae0578ddc8743e920f Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:02 +0100 Subject: drm/i915: Update ring->dispatch_execbuffer() to take a request structure Updated the various ring->dispatch_execbuffer() implementations to take a request instead of a ring. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_render_state.c | 3 +-- drivers/gpu/drm/i915/intel_ringbuffer.c | 18 ++++++++++++------ drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 1cbd6d65dae5..9977c23ab47d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1328,14 +1328,14 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, if (ret) goto error; - ret = ring->dispatch_execbuffer(ring, + ret = ring->dispatch_execbuffer(params->request, exec_start, exec_len, params->dispatch_flags); if (ret) goto error; } } else { - ret = ring->dispatch_execbuffer(ring, + ret = ring->dispatch_execbuffer(params->request, exec_start, exec_len, params->dispatch_flags); if (ret) diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index e04cda40df5e..a0201fc94d25 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -164,8 +164,7 @@ int i915_gem_render_state_init(struct drm_i915_gem_request *req) if (so.rodata == NULL) return 0; - ret = req->ring->dispatch_execbuffer(req->ring, - so.ggtt_offset, + ret = req->ring->dispatch_execbuffer(req, so.ggtt_offset, so.rodata->batch_items * 4, I915_DISPATCH_SECURE); if (ret) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 28d7801a8fa5..44fdfd07d912 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1760,10 +1760,11 @@ gen8_ring_put_irq(struct intel_engine_cs *ring) } static int -i965_dispatch_execbuffer(struct intel_engine_cs *ring, +i965_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 length, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 2); @@ -1786,10 +1787,11 @@ i965_dispatch_execbuffer(struct intel_engine_cs *ring, #define I830_TLB_ENTRIES (2) #define I830_WA_SIZE max(I830_TLB_ENTRIES*4096, I830_BATCH_LIMIT) static int -i830_dispatch_execbuffer(struct intel_engine_cs *ring, +i830_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 len, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; u32 cs_offset = ring->scratch.gtt_offset; int ret; @@ -1848,10 +1850,11 @@ i830_dispatch_execbuffer(struct intel_engine_cs *ring, } static int -i915_dispatch_execbuffer(struct intel_engine_cs *ring, +i915_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 len, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 2); @@ -2423,10 +2426,11 @@ static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req, } static int -gen8_ring_dispatch_execbuffer(struct intel_engine_cs *ring, +gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 len, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; bool ppgtt = USES_PPGTT(ring->dev) && !(dispatch_flags & I915_DISPATCH_SECURE); int ret; @@ -2446,10 +2450,11 @@ gen8_ring_dispatch_execbuffer(struct intel_engine_cs *ring, } static int -hsw_ring_dispatch_execbuffer(struct intel_engine_cs *ring, +hsw_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 len, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 2); @@ -2468,10 +2473,11 @@ hsw_ring_dispatch_execbuffer(struct intel_engine_cs *ring, } static int -gen6_ring_dispatch_execbuffer(struct intel_engine_cs *ring, +gen6_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 len, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 2); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 96b8e353a1f0..bf679ae03aa1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -194,7 +194,7 @@ struct intel_engine_cs { bool lazy_coherency); void (*set_seqno)(struct intel_engine_cs *ring, u32 seqno); - int (*dispatch_execbuffer)(struct intel_engine_cs *ring, + int (*dispatch_execbuffer)(struct drm_i915_gem_request *req, u64 offset, u32 length, unsigned dispatch_flags); #define I915_DISPATCH_SECURE 0x1 -- cgit v1.3-6-gb490 From be795fc17bc9d42b0e5ec3e4442b59848137eb64 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:03 +0100 Subject: drm/i915: Update ring->emit_bb_start() to take a request structure Updated the ring->emit_bb_start() implementation to take a request instead of a ringbuf/context pair. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 12 +++++------- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 +-- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9be732b40121..9e99c6226b57 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -936,7 +936,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, exec_start = params->batch_obj_vm_offset + args->batch_start_offset; - ret = ring->emit_bb_start(ringbuf, params->ctx, exec_start, params->dispatch_flags); + ret = ring->emit_bb_start(params->request, exec_start, params->dispatch_flags); if (ret) return ret; @@ -1365,14 +1365,14 @@ static int gen9_init_render_ring(struct intel_engine_cs *ring) return init_workarounds_ring(ring); } -static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, +static int gen8_emit_bb_start(struct drm_i915_gem_request *req, u64 offset, unsigned dispatch_flags) { + struct intel_ringbuffer *ringbuf = req->ringbuf; bool ppgtt = !(dispatch_flags & I915_DISPATCH_SECURE); int ret; - ret = intel_logical_ring_begin(ringbuf, ctx, 4); + ret = intel_logical_ring_begin(ringbuf, req->ctx, 4); if (ret) return ret; @@ -1582,9 +1582,7 @@ static int intel_lr_context_render_state_init(struct drm_i915_gem_request *req) if (so.rodata == NULL) return 0; - ret = req->ring->emit_bb_start(req->ringbuf, - req->ctx, - so.ggtt_offset, + ret = req->ring->emit_bb_start(req, so.ggtt_offset, I915_DISPATCH_SECURE); if (ret) goto out; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index bf679ae03aa1..1f11c3236768 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -270,8 +270,7 @@ struct intel_engine_cs { int (*emit_flush)(struct drm_i915_gem_request *request, u32 invalidate_domains, u32 flush_domains); - int (*emit_bb_start)(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, + int (*emit_bb_start)(struct drm_i915_gem_request *req, u64 offset, unsigned dispatch_flags); /** -- cgit v1.3-6-gb490 From 599d924c6b01e89b53c7879e7d7d89baa8d677d2 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:04 +0100 Subject: drm/i915: Update ring->sync_to() to take a request structure Updated the ring->sync_to() implementations to take a request instead of a ring. Also updated the tracer to include the request id. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf [danvet: Rebase since I didn't merge the patch which added ->uniq.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 4 ++-- drivers/gpu/drm/i915/i915_trace.h | 8 ++++---- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 ++++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 339799c5aceb..ae9e5ecfe34c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3139,8 +3139,8 @@ __i915_gem_object_sync(struct drm_i915_gem_object *obj, return ret; } - trace_i915_gem_ring_sync_to(from, to, from_req); - ret = to->semaphore.sync_to(to, from, seqno); + trace_i915_gem_ring_sync_to(*to_req, from, from_req); + ret = to->semaphore.sync_to(*to_req, from, seqno); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index cf58eeb1c2c0..63328b6e8ea5 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -424,10 +424,10 @@ TRACE_EVENT(i915_gem_evict_vm, ); TRACE_EVENT(i915_gem_ring_sync_to, - TP_PROTO(struct intel_engine_cs *from, - struct intel_engine_cs *to, + TP_PROTO(struct drm_i915_gem_request *to_req, + struct intel_engine_cs *from, struct drm_i915_gem_request *req), - TP_ARGS(from, to, req), + TP_ARGS(to_req, from, req), TP_STRUCT__entry( __field(u32, dev) @@ -439,7 +439,7 @@ TRACE_EVENT(i915_gem_ring_sync_to, TP_fast_assign( __entry->dev = from->dev->primary->index; __entry->sync_from = from->id; - __entry->sync_to = to->id; + __entry->sync_to = to_req->ring->id; __entry->seqno = i915_gem_request_get_seqno(req); ), diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 44fdfd07d912..eb436a03fae9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1333,10 +1333,11 @@ static inline bool i915_gem_has_seqno_wrapped(struct drm_device *dev, */ static int -gen8_ring_sync(struct intel_engine_cs *waiter, +gen8_ring_sync(struct drm_i915_gem_request *waiter_req, struct intel_engine_cs *signaller, u32 seqno) { + struct intel_engine_cs *waiter = waiter_req->ring; struct drm_i915_private *dev_priv = waiter->dev->dev_private; int ret; @@ -1358,10 +1359,11 @@ gen8_ring_sync(struct intel_engine_cs *waiter, } static int -gen6_ring_sync(struct intel_engine_cs *waiter, +gen6_ring_sync(struct drm_i915_gem_request *waiter_req, struct intel_engine_cs *signaller, u32 seqno) { + struct intel_engine_cs *waiter = waiter_req->ring; u32 dw1 = MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 1f11c3236768..6853f8f0ee29 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -252,8 +252,8 @@ struct intel_engine_cs { }; /* AKA wait() */ - int (*sync_to)(struct intel_engine_cs *ring, - struct intel_engine_cs *to, + int (*sync_to)(struct drm_i915_gem_request *to_req, + struct intel_engine_cs *from, u32 seqno); int (*signal)(struct intel_engine_cs *signaller, /* num_dwords needed by caller */ -- cgit v1.3-6-gb490 From f71696876a16c3d68d27db71d93f389ae440171c Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:05 +0100 Subject: drm/i915: Update ring->signal() to take a request structure Updated the various ring->signal() implementations to take a request instead of a ring. This removes their reliance on the OLR to obtain the seqno value that should be used for the signal. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 20 ++++++++++---------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index eb436a03fae9..e6ef8d796311 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1171,10 +1171,11 @@ static void render_ring_cleanup(struct intel_engine_cs *ring) intel_fini_pipe_control(ring); } -static int gen8_rcs_signal(struct intel_engine_cs *signaller, +static int gen8_rcs_signal(struct drm_i915_gem_request *signaller_req, unsigned int num_dwords) { #define MBOX_UPDATE_DWORDS 8 + struct intel_engine_cs *signaller = signaller_req->ring; struct drm_device *dev = signaller->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *waiter; @@ -1194,8 +1195,7 @@ static int gen8_rcs_signal(struct intel_engine_cs *signaller, if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID) continue; - seqno = i915_gem_request_get_seqno( - signaller->outstanding_lazy_request); + seqno = i915_gem_request_get_seqno(signaller_req); intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6)); intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB | PIPE_CONTROL_QW_WRITE | @@ -1212,10 +1212,11 @@ static int gen8_rcs_signal(struct intel_engine_cs *signaller, return 0; } -static int gen8_xcs_signal(struct intel_engine_cs *signaller, +static int gen8_xcs_signal(struct drm_i915_gem_request *signaller_req, unsigned int num_dwords) { #define MBOX_UPDATE_DWORDS 6 + struct intel_engine_cs *signaller = signaller_req->ring; struct drm_device *dev = signaller->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *waiter; @@ -1235,8 +1236,7 @@ static int gen8_xcs_signal(struct intel_engine_cs *signaller, if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID) continue; - seqno = i915_gem_request_get_seqno( - signaller->outstanding_lazy_request); + seqno = i915_gem_request_get_seqno(signaller_req); intel_ring_emit(signaller, (MI_FLUSH_DW + 1) | MI_FLUSH_DW_OP_STOREDW); intel_ring_emit(signaller, lower_32_bits(gtt_offset) | @@ -1251,9 +1251,10 @@ static int gen8_xcs_signal(struct intel_engine_cs *signaller, return 0; } -static int gen6_signal(struct intel_engine_cs *signaller, +static int gen6_signal(struct drm_i915_gem_request *signaller_req, unsigned int num_dwords) { + struct intel_engine_cs *signaller = signaller_req->ring; struct drm_device *dev = signaller->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *useless; @@ -1271,8 +1272,7 @@ static int gen6_signal(struct intel_engine_cs *signaller, for_each_ring(useless, dev_priv, i) { u32 mbox_reg = signaller->semaphore.mbox.signal[i]; if (mbox_reg != GEN6_NOSYNC) { - u32 seqno = i915_gem_request_get_seqno( - signaller->outstanding_lazy_request); + u32 seqno = i915_gem_request_get_seqno(signaller_req); intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1)); intel_ring_emit(signaller, mbox_reg); intel_ring_emit(signaller, seqno); @@ -1301,7 +1301,7 @@ gen6_add_request(struct drm_i915_gem_request *req) int ret; if (ring->semaphore.signal) - ret = ring->semaphore.signal(ring, 4); + ret = ring->semaphore.signal(req, 4); else ret = intel_ring_begin(ring, 4); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 6853f8f0ee29..ca04f3f58757 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -255,7 +255,7 @@ struct intel_engine_cs { int (*sync_to)(struct drm_i915_gem_request *to_req, struct intel_engine_cs *from, u32 seqno); - int (*signal)(struct intel_engine_cs *signaller, + int (*signal)(struct drm_i915_gem_request *signaller_req, /* num_dwords needed by caller */ unsigned int num_dwords); } semaphore; -- cgit v1.3-6-gb490 From bba09b12b47b31b147206f5784691d2fb8888bf1 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:06 +0100 Subject: drm/i915: Update cacheline_align() to take a request structure Updated intel_ring_cacheline_align() to take a request instead of a ring. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 3 ++- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7ec2421f0a97..7882820b741a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11055,7 +11055,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, * then do the cacheline alignment, and finally emit the * MI_DISPLAY_FLIP. */ - ret = intel_ring_cacheline_align(ring); + ret = intel_ring_cacheline_align(req); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e6ef8d796311..6a77014e1d66 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2311,8 +2311,9 @@ int intel_ring_begin(struct intel_engine_cs *ring, } /* Align the ring tail to a cacheline boundary */ -int intel_ring_cacheline_align(struct intel_engine_cs *ring) +int intel_ring_cacheline_align(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int num_dwords = (ring->buffer->tail & (CACHELINE_BYTES - 1)) / sizeof(uint32_t); int ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index ca04f3f58757..8a5317bba112 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -422,7 +422,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring); int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request); int __must_check intel_ring_begin(struct intel_engine_cs *ring, int n); -int __must_check intel_ring_cacheline_align(struct intel_engine_cs *ring); +int __must_check intel_ring_cacheline_align(struct drm_i915_gem_request *req); static inline void intel_ring_emit(struct intel_engine_cs *ring, u32 data) { -- cgit v1.3-6-gb490 From 5fb9de1a2ea1968b57c906c6770794f1e7744828 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:07 +0100 Subject: drm/i915: Update intel_ring_begin() to take a request structure Now that everything above has been converted to use requests, intel_ring_begin() can be updated to take a request instead of a ring. This also means that it no longer needs to lazily allocate a request if no-one happens to have done it earlier. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 8 ++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 +-- drivers/gpu/drm/i915/intel_display.c | 10 ++-- drivers/gpu/drm/i915/intel_overlay.c | 8 ++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 74 +++++++++++++++--------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 8 files changed, 55 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ae9e5ecfe34c..e7a40f8712bc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4894,7 +4894,7 @@ int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice) if (!HAS_L3_DPF(dev) || !remap_info) return 0; - ret = intel_ring_begin(ring, GEN7_L3LOG_SIZE / 4 * 3); + ret = intel_ring_begin(req, GEN7_L3LOG_SIZE / 4 * 3); 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 c80b59db3c92..a7e58a8ae770 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -509,7 +509,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) if (INTEL_INFO(ring->dev)->gen >= 7) len += 2 + (num_rings ? 4*num_rings + 2 : 0); - ret = intel_ring_begin(ring, len); + ret = intel_ring_begin(req, len); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9977c23ab47d..6657bb9b2690 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1082,7 +1082,7 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, return -EINVAL; } - ret = intel_ring_begin(ring, 4 * 3); + ret = intel_ring_begin(req, 4 * 3); if (ret) return ret; @@ -1113,7 +1113,7 @@ i915_emit_box(struct drm_i915_gem_request *req, } if (INTEL_INFO(ring->dev)->gen >= 4) { - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -1122,7 +1122,7 @@ i915_emit_box(struct drm_i915_gem_request *req, intel_ring_emit(ring, ((box->x2 - 1) & 0xffff) | (box->y2 - 1) << 16); intel_ring_emit(ring, DR4); } else { - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -1298,7 +1298,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, if (ring == &dev_priv->ring[RCS] && instp_mode != dev_priv->relative_constants_mode) { - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(params->request, 4); if (ret) goto error; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 037f86ed6a8a..a8c33f7f922f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -461,7 +461,7 @@ static int gen8_write_pdp(struct drm_i915_gem_request *req, BUG_ON(entry >= 4); - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -1073,7 +1073,7 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, if (ret) return ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -1110,7 +1110,7 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, if (ret) return ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7882820b741a..bd121cd7ca1d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10876,7 +10876,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev, u32 flip_mask; int ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -10911,7 +10911,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev, u32 flip_mask; int ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -10944,7 +10944,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev, uint32_t pf, pipesrc; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -10983,7 +10983,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev, uint32_t pf, pipesrc; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -11059,7 +11059,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, if (ret) return ret; - ret = intel_ring_begin(ring, len); + ret = intel_ring_begin(req, len); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 3f709042b86c..444542696a2c 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -244,7 +244,7 @@ static int intel_overlay_on(struct intel_overlay *overlay) if (ret) return ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) { i915_gem_request_cancel(req); return ret; @@ -287,7 +287,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, if (ret) return ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) { i915_gem_request_cancel(req); return ret; @@ -353,7 +353,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) if (ret) return ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) { i915_gem_request_cancel(req); return ret; @@ -427,7 +427,7 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) if (ret) return ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) { i915_gem_request_cancel(req); return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6a77014e1d66..dfba3ee57382 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -106,7 +106,7 @@ gen2_render_ring_flush(struct drm_i915_gem_request *req, if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) cmd |= MI_READ_FLUSH; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -165,7 +165,7 @@ gen4_render_ring_flush(struct drm_i915_gem_request *req, (IS_G4X(dev) || IS_GEN5(dev))) cmd |= MI_INVALIDATE_ISP; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -220,8 +220,7 @@ intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req) u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; - - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -234,7 +233,7 @@ intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req) intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -289,7 +288,7 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req, flags |= PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_CS_STALL; } - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -308,7 +307,7 @@ gen7_render_ring_cs_stall_wa(struct drm_i915_gem_request *req) struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -371,7 +370,7 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req, gen7_render_ring_cs_stall_wa(req); } - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -391,7 +390,7 @@ gen8_emit_pipe_control(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -726,7 +725,7 @@ static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req) if (ret) return ret; - ret = intel_ring_begin(ring, (w->count * 2 + 2)); + ret = intel_ring_begin(req, (w->count * 2 + 2)); if (ret) return ret; @@ -1185,7 +1184,7 @@ static int gen8_rcs_signal(struct drm_i915_gem_request *signaller_req, num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS; #undef MBOX_UPDATE_DWORDS - ret = intel_ring_begin(signaller, num_dwords); + ret = intel_ring_begin(signaller_req, num_dwords); if (ret) return ret; @@ -1226,7 +1225,7 @@ static int gen8_xcs_signal(struct drm_i915_gem_request *signaller_req, num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS; #undef MBOX_UPDATE_DWORDS - ret = intel_ring_begin(signaller, num_dwords); + ret = intel_ring_begin(signaller_req, num_dwords); if (ret) return ret; @@ -1265,7 +1264,7 @@ static int gen6_signal(struct drm_i915_gem_request *signaller_req, num_dwords += round_up((num_rings-1) * MBOX_UPDATE_DWORDS, 2); #undef MBOX_UPDATE_DWORDS - ret = intel_ring_begin(signaller, num_dwords); + ret = intel_ring_begin(signaller_req, num_dwords); if (ret) return ret; @@ -1303,7 +1302,7 @@ gen6_add_request(struct drm_i915_gem_request *req) if (ring->semaphore.signal) ret = ring->semaphore.signal(req, 4); else - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -1341,7 +1340,7 @@ gen8_ring_sync(struct drm_i915_gem_request *waiter_req, struct drm_i915_private *dev_priv = waiter->dev->dev_private; int ret; - ret = intel_ring_begin(waiter, 4); + ret = intel_ring_begin(waiter_req, 4); if (ret) return ret; @@ -1378,7 +1377,7 @@ gen6_ring_sync(struct drm_i915_gem_request *waiter_req, WARN_ON(wait_mbox == MI_SEMAPHORE_SYNC_INVALID); - ret = intel_ring_begin(waiter, 4); + ret = intel_ring_begin(waiter_req, 4); if (ret) return ret; @@ -1423,7 +1422,7 @@ pc_render_add_request(struct drm_i915_gem_request *req) * incoherence by flushing the 6 PIPE_NOTIFY buffers out to * memory before requesting an interrupt. */ - ret = intel_ring_begin(ring, 32); + ret = intel_ring_begin(req, 32); if (ret) return ret; @@ -1608,7 +1607,7 @@ bsd_ring_flush(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -1624,7 +1623,7 @@ i9xx_add_request(struct drm_i915_gem_request *req) struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -1769,7 +1768,7 @@ i965_dispatch_execbuffer(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -1797,7 +1796,7 @@ i830_dispatch_execbuffer(struct drm_i915_gem_request *req, u32 cs_offset = ring->scratch.gtt_offset; int ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -1814,7 +1813,7 @@ i830_dispatch_execbuffer(struct drm_i915_gem_request *req, if (len > I830_BATCH_LIMIT) return -ENOSPC; - ret = intel_ring_begin(ring, 6 + 2); + ret = intel_ring_begin(req, 6 + 2); if (ret) return ret; @@ -1837,7 +1836,7 @@ i830_dispatch_execbuffer(struct drm_i915_gem_request *req, offset = cs_offset; } - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -1859,7 +1858,7 @@ i915_dispatch_execbuffer(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -2285,13 +2284,17 @@ static int __intel_ring_prepare(struct intel_engine_cs *ring, int bytes) return 0; } -int intel_ring_begin(struct intel_engine_cs *ring, +int intel_ring_begin(struct drm_i915_gem_request *req, int num_dwords) { - struct drm_i915_gem_request *req; - struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct intel_engine_cs *ring; + struct drm_i915_private *dev_priv; int ret; + WARN_ON(req == NULL); + ring = req->ring; + dev_priv = ring->dev->dev_private; + ret = i915_gem_check_wedge(&dev_priv->gpu_error, dev_priv->mm.interruptible); if (ret) @@ -2301,11 +2304,6 @@ int intel_ring_begin(struct intel_engine_cs *ring, if (ret) return ret; - /* Preallocate the olr before touching the ring */ - ret = i915_gem_request_alloc(ring, ring->default_context, &req); - if (ret) - return ret; - ring->buffer->space -= num_dwords * sizeof(uint32_t); return 0; } @@ -2321,7 +2319,7 @@ int intel_ring_cacheline_align(struct drm_i915_gem_request *req) return 0; num_dwords = CACHELINE_BYTES / sizeof(uint32_t) - num_dwords; - ret = intel_ring_begin(ring, num_dwords); + ret = intel_ring_begin(req, num_dwords); if (ret) return ret; @@ -2391,7 +2389,7 @@ static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req, uint32_t cmd; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -2438,7 +2436,7 @@ gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, !(dispatch_flags & I915_DISPATCH_SECURE); int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -2460,7 +2458,7 @@ hsw_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -2483,7 +2481,7 @@ gen6_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -2508,7 +2506,7 @@ static int gen6_ring_flush(struct drm_i915_gem_request *req, uint32_t cmd; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 8a5317bba112..00a4ff7593ce 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -421,7 +421,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring); int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request); -int __must_check intel_ring_begin(struct intel_engine_cs *ring, int n); +int __must_check intel_ring_begin(struct drm_i915_gem_request *req, int n); int __must_check intel_ring_cacheline_align(struct drm_i915_gem_request *req); static inline void intel_ring_emit(struct intel_engine_cs *ring, u32 data) -- cgit v1.3-6-gb490 From 4d616a293a1071d19066808abccb40930f0ae5a0 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:08 +0100 Subject: drm/i915: Update intel_logical_ring_begin() to take a request structure Now that everything above has been converted to use requests, intel_logical_ring_begin() can be updated to take a request instead of a ringbuf/context pair. This also means that it no longer needs to lazily allocate a request if no-one happens to have done it earlier. Note that this change makes the execlist signature the same as the legacy version. Thus the two functions could be merged into a ring->begin() wrapper if required. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9e99c6226b57..ad9db8a79d08 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -801,7 +801,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, /** * intel_logical_ring_begin() - prepare the logical ringbuffer to accept some commands * - * @ringbuf: Logical ringbuffer. + * @request: The request to start some new work for * @num_dwords: number of DWORDs that we plan to write to the ringbuffer. * * The ringbuffer might not be ready to accept the commands right away (maybe it needs to @@ -811,30 +811,26 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, * * Return: non-zero if the ringbuffer is not ready to be written to. */ -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, int num_dwords) +static int intel_logical_ring_begin(struct drm_i915_gem_request *req, + int num_dwords) { - struct drm_i915_gem_request *req; - struct intel_engine_cs *ring = ringbuf->ring; - struct drm_device *dev = ring->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv; int ret; + WARN_ON(req == NULL); + dev_priv = req->ring->dev->dev_private; + ret = i915_gem_check_wedge(&dev_priv->gpu_error, dev_priv->mm.interruptible); if (ret) return ret; - ret = logical_ring_prepare(ringbuf, ctx, num_dwords * sizeof(uint32_t)); - if (ret) - return ret; - - /* Preallocate the olr before touching the ring */ - ret = i915_gem_request_alloc(ring, ctx, &req); + ret = logical_ring_prepare(req->ringbuf, req->ctx, + num_dwords * sizeof(uint32_t)); if (ret) return ret; - ringbuf->space -= num_dwords * sizeof(uint32_t); + req->ringbuf->space -= num_dwords * sizeof(uint32_t); return 0; } @@ -920,7 +916,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, if (ring == &dev_priv->ring[RCS] && instp_mode != dev_priv->relative_constants_mode) { - ret = intel_logical_ring_begin(ringbuf, params->ctx, 4); + ret = intel_logical_ring_begin(params->request, 4); if (ret) return ret; @@ -1073,7 +1069,7 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) if (ret) return ret; - ret = intel_logical_ring_begin(ringbuf, req->ctx, w->count * 2 + 2); + ret = intel_logical_ring_begin(req, w->count * 2 + 2); if (ret) return ret; @@ -1372,7 +1368,7 @@ static int gen8_emit_bb_start(struct drm_i915_gem_request *req, bool ppgtt = !(dispatch_flags & I915_DISPATCH_SECURE); int ret; - ret = intel_logical_ring_begin(ringbuf, req->ctx, 4); + ret = intel_logical_ring_begin(req, 4); if (ret) return ret; @@ -1430,7 +1426,7 @@ static int gen8_emit_flush(struct drm_i915_gem_request *request, uint32_t cmd; int ret; - ret = intel_logical_ring_begin(ringbuf, request->ctx, 4); + ret = intel_logical_ring_begin(request, 4); if (ret) return ret; @@ -1496,7 +1492,7 @@ static int gen8_emit_flush_render(struct drm_i915_gem_request *request, vf_flush_wa = INTEL_INFO(ring->dev)->gen >= 9 && flags & PIPE_CONTROL_VF_CACHE_INVALIDATE; - ret = intel_logical_ring_begin(ringbuf, request->ctx, vf_flush_wa ? 12 : 6); + ret = intel_logical_ring_begin(request, vf_flush_wa ? 12 : 6); if (ret) return ret; @@ -1542,7 +1538,7 @@ static int gen8_emit_request(struct drm_i915_gem_request *request) * used as a workaround for not being allowed to do lite * restore with HEAD==TAIL (WaIdleLiteRestore). */ - ret = intel_logical_ring_begin(ringbuf, request->ctx, 8); + ret = intel_logical_ring_begin(request, 8); if (ret) return ret; -- cgit v1.3-6-gb490 From ccd98fe4996cd22094cde7b6a1f7c569f261b3e9 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:09 +0100 Subject: drm/i915: Add *_ring_begin() to request allocation Now that the *_ring_begin() functions no longer call the request allocation code, it is finally safe for the request allocation code to call *_ring_begin(). This is important to guarantee that the space reserved for the subsequent i915_add_request() call does actually get reserved. v2: Renamed functions according to review feedback (Tomas Elf). For: VIZ-5115 Signed-off-by: John Harrison Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 25 +++++++++++++------------ drivers/gpu/drm/i915/intel_lrc.c | 15 +++++++++++++++ drivers/gpu/drm/i915/intel_lrc.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 29 ++++++++++++++++------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 5 files changed, 46 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e7a40f8712bc..0af4960d141c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2679,19 +2679,20 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, * i915_add_request() call can't fail. Note that the reserve may need * to be redone if the request is not actually submitted straight * away, e.g. because a GPU scheduler has deferred it. - * - * Note further that this call merely notes the reserve request. A - * subsequent call to *_ring_begin() is required to actually ensure - * that the reservation is available. Without the begin, if the - * request creator immediately submitted the request without adding - * any commands to it then there might not actually be sufficient - * room for the submission commands. Unfortunately, the current - * *_ring_begin() implementations potentially call back here to - * i915_gem_request_alloc(). Thus calling _begin() here would lead to - * infinite recursion! Until that back call path is removed, it is - * necessary to do a manual _begin() outside. */ - intel_ring_reserved_space_reserve(req->ringbuf, MIN_SPACE_FOR_ADD_REQUEST); + if (i915.enable_execlists) + ret = intel_logical_ring_reserve_space(req); + else + ret = intel_ring_reserve_space(req); + if (ret) { + /* + * At this point, the request is fully allocated even if not + * fully prepared. Thus it can be cleaned up using the proper + * free code. + */ + i915_gem_request_cancel(req); + return ret; + } *req_out = ring->outstanding_lazy_request = req; return 0; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index ad9db8a79d08..75c3b9dfec9e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -834,6 +834,21 @@ static int intel_logical_ring_begin(struct drm_i915_gem_request *req, return 0; } +int intel_logical_ring_reserve_space(struct drm_i915_gem_request *request) +{ + /* + * The first call merely notes the reserve request and is common for + * all back ends. The subsequent localised _begin() call actually + * ensures that the reservation is available. Without the begin, if + * the request creator immediately submitted the request without + * adding any commands to it then there might not actually be + * sufficient room for the submission commands. + */ + intel_ring_reserved_space_reserve(request->ringbuf, MIN_SPACE_FOR_ADD_REQUEST); + + return intel_logical_ring_begin(request, 0); +} + /** * execlists_submission() - submit a batchbuffer for execution, Execlists style * @dev: DRM device. diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 044c0e5c72e5..f59940ac1cfc 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -37,6 +37,7 @@ /* Logical Rings */ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request); +int intel_logical_ring_reserve_space(struct drm_i915_gem_request *request); void intel_logical_ring_stop(struct intel_engine_cs *ring); void intel_logical_ring_cleanup(struct intel_engine_cs *ring); int intel_logical_rings_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index dfba3ee57382..a378360d0461 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2202,24 +2202,27 @@ int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request) return 0; } +int intel_ring_reserve_space(struct drm_i915_gem_request *request) +{ + /* + * The first call merely notes the reserve request and is common for + * all back ends. The subsequent localised _begin() call actually + * ensures that the reservation is available. Without the begin, if + * the request creator immediately submitted the request without + * adding any commands to it then there might not actually be + * sufficient room for the submission commands. + */ + intel_ring_reserved_space_reserve(request->ringbuf, MIN_SPACE_FOR_ADD_REQUEST); + + return intel_ring_begin(request, 0); +} + void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size) { - /* NB: Until request management is fully tidied up and the OLR is - * removed, there are too many ways for get false hits on this - * anti-recursion check! */ - /*WARN_ON(ringbuf->reserved_size);*/ + WARN_ON(ringbuf->reserved_size); WARN_ON(ringbuf->reserved_in_use); ringbuf->reserved_size = size; - - /* - * Really need to call _begin() here but that currently leads to - * recursion problems! This will be fixed later but for now just - * return and hope for the best. Note that there is only a real - * problem if the create of the request never actually calls _begin() - * but if they are not submitting any work then why did they create - * the request in the first place? - */ } void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 00a4ff7593ce..0f12020b54e9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -484,6 +484,7 @@ intel_ring_get_request(struct intel_engine_cs *ring) * will always have sufficient room to do its stuff. The request creation * code calls this automatically. */ +int intel_ring_reserve_space(struct drm_i915_gem_request *request); void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size); /* Cancel the reservation, e.g. because the request is being discarded. */ void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf); -- cgit v1.3-6-gb490 From 59c35a4d120ef5e34e91f2bccdfcf9e27a3b9397 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:10 +0100 Subject: drm/i915: Remove the now obsolete intel_ring_get_request() Much of the driver has now been converted to passing requests around instead of rings/ringbufs/contexts. Thus the function for retreiving the request from a ring (i.e. the OLR) is no longer used and can be removed. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 0f12020b54e9..d2cf4d92efc9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -463,13 +463,6 @@ static inline u32 intel_ring_get_tail(struct intel_ringbuffer *ringbuf) return ringbuf->tail; } -static inline struct drm_i915_gem_request * -intel_ring_get_request(struct intel_engine_cs *ring) -{ - BUG_ON(ring->outstanding_lazy_request == NULL); - return ring->outstanding_lazy_request; -} - /* * Arbitrary size for largest possible 'add request' sequence. The code paths * are complex and variable. Empirical measurement shows that the worst case -- cgit v1.3-6-gb490 From bccca494f75cbad4ea2d09e8205cab09ee610f6a Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:11 +0100 Subject: drm/i915: Remove the now obsolete 'outstanding_lazy_request' The outstanding_lazy_request is no longer used anywhere in the driver. Everything that was looking at it now has a request explicitly passed in from on high. Everything that was relying upon it behind the scenes is now explicitly creating/passing/submitting its own private request. Thus the OLR can be removed. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 16 ++-------------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 +--- drivers/gpu/drm/i915/intel_lrc.c | 1 - drivers/gpu/drm/i915/intel_ringbuffer.c | 8 -------- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 ---- 5 files changed, 3 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0af4960d141c..d1193dcb8729 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1157,9 +1157,6 @@ i915_gem_check_olr(struct drm_i915_gem_request *req) { WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex)); - if (req == req->ring->outstanding_lazy_request) - i915_add_request(req); - return 0; } @@ -2488,8 +2485,6 @@ void __i915_add_request(struct drm_i915_gem_request *request, dev_priv = ring->dev->dev_private; ringbuf = request->ringbuf; - WARN_ON(request != ring->outstanding_lazy_request); - /* * To ensure that this call will not fail, space for its emissions * should already have been reserved in the ring buffer. Let the ring @@ -2558,7 +2553,6 @@ void __i915_add_request(struct drm_i915_gem_request *request, } trace_i915_gem_request_add(request); - ring->outstanding_lazy_request = NULL; i915_queue_hangcheck(ring->dev); @@ -2647,8 +2641,7 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, if (!req_out) return -EINVAL; - if ((*req_out = ring->outstanding_lazy_request) != NULL) - return 0; + *req_out = NULL; req = kmem_cache_zalloc(dev_priv->requests, GFP_KERNEL); if (req == NULL) @@ -2694,7 +2687,7 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, return ret; } - *req_out = ring->outstanding_lazy_request = req; + *req_out = req; return 0; err: @@ -2791,9 +2784,6 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, i915_gem_request_retire(request); } - - /* This may not have been flushed before the reset, so clean it now */ - i915_gem_request_assign(&ring->outstanding_lazy_request, NULL); } void i915_gem_restore_fences(struct drm_device *dev) @@ -3344,8 +3334,6 @@ int i915_gpu_idle(struct drm_device *dev) i915_add_request_no_flush(req); } - WARN_ON(ring->outstanding_lazy_request); - ret = intel_ring_idle(ring); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6657bb9b2690..3aa2358c2b93 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1655,10 +1655,8 @@ err: * must be freed again. If it was submitted then it is being tracked * on the active request list and no clean up is required here. */ - if (ret && params->request) { + if (ret && params->request) i915_gem_request_cancel(params->request); - ring->outstanding_lazy_request = NULL; - } mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 75c3b9dfec9e..44568839103a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1633,7 +1633,6 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring) intel_logical_ring_stop(ring); WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0); - i915_gem_request_assign(&ring->outstanding_lazy_request, NULL); if (ring->cleanup) ring->cleanup(ring); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a378360d0461..af7c12ed0ba7 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2101,7 +2101,6 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring) intel_unpin_ringbuffer_obj(ringbuf); intel_destroy_ringbuffer_obj(ringbuf); - i915_gem_request_assign(&ring->outstanding_lazy_request, NULL); if (ring->cleanup) ring->cleanup(ring); @@ -2176,11 +2175,6 @@ int intel_ring_idle(struct intel_engine_cs *ring) { struct drm_i915_gem_request *req; - /* We need to add any requests required to flush the objects and ring */ - WARN_ON(ring->outstanding_lazy_request); - if (ring->outstanding_lazy_request) - i915_add_request(ring->outstanding_lazy_request); - /* Wait upon the last request to be completed */ if (list_empty(&ring->request_list)) return 0; @@ -2339,8 +2333,6 @@ void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - BUG_ON(ring->outstanding_lazy_request); - if (INTEL_INFO(dev)->gen == 6 || INTEL_INFO(dev)->gen == 7) { I915_WRITE(RING_SYNC_0(ring->mmio_base), 0); I915_WRITE(RING_SYNC_1(ring->mmio_base), 0); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index d2cf4d92efc9..0e2bbc6a3f8b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -291,10 +291,6 @@ struct intel_engine_cs { */ struct list_head request_list; - /** - * Do we have some not yet emitted requests outstanding? - */ - struct drm_i915_gem_request *outstanding_lazy_request; bool gpu_caches_dirty; wait_queue_head_t irq_queue; -- cgit v1.3-6-gb490 From fcfa423cbba268b1473e2d8c38fe6dbe65da88ea Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:12 +0100 Subject: drm/i915: Move the request/file and request/pid association to creation time In _i915_add_request(), the request is associated with a userland client. Specifically it is linked to the 'file' structure and the current user process is recorded. One problem here is that the current user process is not necessarily the same as when the request was submitted to the driver. This is especially true when the GPU scheduler arrives and decouples driver submission from hardware submission. Note also that it is only in the case where the add request comes from an execbuff call that there is a client to associate. Any other add request call is kernel only so does not need to do it. This patch moves the client association into a separate function. This is then called from the execbuffer code path itself at a sensible time. It also removes the now redundant 'file' pointer from the add request parameter list. An extra cleanup of the client association is also added to the request clean up code for the eventuality where the request is killed after association but before being submitted (e.g. due to out of memory error somewhere). Once the submission has happened, the request is on the request list and the regular request list removal will clear the association. Note that this still needs to happen at this point in time because the request might be kept floating around much longer (due to someone holding a reference count) and the client should not be worrying about this request after it has been retired. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 ++-- drivers/gpu/drm/i915/i915_gem.c | 56 +++++++++++++++++++++--------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 6 +++- 3 files changed, 49 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5aea6ddd5091..7d7339c8ec96 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2212,6 +2212,8 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, struct drm_i915_gem_request **req_out); void i915_gem_request_cancel(struct drm_i915_gem_request *req); void i915_gem_request_free(struct kref *req_ref); +int i915_gem_request_add_to_client(struct drm_i915_gem_request *req, + struct drm_file *file); static inline uint32_t i915_gem_request_get_seqno(struct drm_i915_gem_request *req) @@ -2891,13 +2893,12 @@ void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); void __i915_add_request(struct drm_i915_gem_request *req, - struct drm_file *file, struct drm_i915_gem_object *batch_obj, bool flush_caches); #define i915_add_request(req) \ - __i915_add_request(req, NULL, NULL, true) + __i915_add_request(req, NULL, true) #define i915_add_request_no_flush(req) \ - __i915_add_request(req, NULL, NULL, false) + __i915_add_request(req, NULL, false) int __i915_wait_request(struct drm_i915_gem_request *req, unsigned reset_counter, bool interruptible, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d1193dcb8729..10832c05e96d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1331,6 +1331,33 @@ out: return ret; } +int i915_gem_request_add_to_client(struct drm_i915_gem_request *req, + struct drm_file *file) +{ + struct drm_i915_private *dev_private; + struct drm_i915_file_private *file_priv; + + WARN_ON(!req || !file || req->file_priv); + + if (!req || !file) + return -EINVAL; + + if (req->file_priv) + return -EINVAL; + + dev_private = req->ring->dev->dev_private; + file_priv = file->driver_priv; + + spin_lock(&file_priv->mm.lock); + req->file_priv = file_priv; + list_add_tail(&req->client_list, &file_priv->mm.request_list); + spin_unlock(&file_priv->mm.lock); + + req->pid = get_pid(task_pid(current)); + + return 0; +} + static inline void i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) { @@ -1343,6 +1370,9 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) list_del(&request->client_list); request->file_priv = NULL; spin_unlock(&file_priv->mm.lock); + + put_pid(request->pid); + request->pid = NULL; } static void i915_gem_request_retire(struct drm_i915_gem_request *request) @@ -1362,8 +1392,6 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request) list_del_init(&request->list); i915_gem_request_remove_from_client(request); - put_pid(request->pid); - i915_gem_request_unreference(request); } @@ -2468,7 +2496,6 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) * going to happen on the hardware. This would be a Bad Thing(tm). */ void __i915_add_request(struct drm_i915_gem_request *request, - struct drm_file *file, struct drm_i915_gem_object *obj, bool flush_caches) { @@ -2538,19 +2565,6 @@ void __i915_add_request(struct drm_i915_gem_request *request, request->emitted_jiffies = jiffies; list_add_tail(&request->list, &ring->request_list); - request->file_priv = NULL; - - if (file) { - struct drm_i915_file_private *file_priv = file->driver_priv; - - spin_lock(&file_priv->mm.lock); - request->file_priv = file_priv; - list_add_tail(&request->client_list, - &file_priv->mm.request_list); - spin_unlock(&file_priv->mm.lock); - - request->pid = get_pid(task_pid(current)); - } trace_i915_gem_request_add(request); @@ -2616,6 +2630,9 @@ void i915_gem_request_free(struct kref *req_ref) typeof(*req), ref); struct intel_context *ctx = req->ctx; + if (req->file_priv) + i915_gem_request_remove_from_client(req); + if (ctx) { if (i915.enable_execlists) { struct intel_engine_cs *ring = req->ring; @@ -4314,6 +4331,13 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) if (time_after_eq(request->emitted_jiffies, recent_enough)) break; + /* + * Note that the request might not have been submitted yet. + * In which case emitted_jiffies will be zero. + */ + if (!request->emitted_jiffies) + continue; + target = request; } reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3aa2358c2b93..600db7441847 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1066,7 +1066,7 @@ i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params) params->ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - __i915_add_request(params->request, params->file, params->batch_obj, true); + __i915_add_request(params->request, params->batch_obj, true); } static int @@ -1620,6 +1620,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err_batch_unpin; + ret = i915_gem_request_add_to_client(params->request, file); + if (ret) + goto err_batch_unpin; + /* * Save assorted stuff away to pass through to *_submission(). * NB: This data should be 'persistent' and not local as it will -- cgit v1.3-6-gb490 From 9bb1af4406f475e6b68aa53c6227b98aed56d11d Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:13 +0100 Subject: drm/i915: Remove 'faked' request from LRC submission The LRC submission code requires a request for tracking purposes. It does not actually require that request to 'complete' it simply uses it for keeping hold of reference counts on contexts and such like. Previously, the fall back path of polling for space in the ring would start by submitting any outstanding work that was sat in the buffer. This submission was not done as part of the request that that work was owned by because that would lead to complications with the request being submitted twice. Instead, a null request structure was passed in to the submit call and a fake one was created. That fall back path has long since been obsoleted and has now been removed. Thus there is never any need to fake up a request structure. This patch removes that code. A couple of sanity check warnings are added as well, just in case. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 44568839103a..a40ca1f5965b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -555,22 +555,11 @@ static int execlists_context_queue(struct intel_engine_cs *ring, if (to != ring->default_context) intel_lr_context_pin(ring, to); - if (!request) { - /* - * If there isn't a request associated with this submission, - * create one as a temporary holder. - */ - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) - return -ENOMEM; - request->ring = ring; - request->ctx = to; - kref_init(&request->ref); - i915_gem_context_reference(request->ctx); - } else { - i915_gem_request_reference(request); - WARN_ON(to != request->ctx); - } + WARN_ON(!request); + WARN_ON(to != request->ctx); + + i915_gem_request_reference(request); + request->tail = tail; spin_lock_irq(&ring->execlist_lock); -- cgit v1.3-6-gb490 From ae70797d8d28d01e6354961e76f56112dae09052 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:14 +0100 Subject: drm/i915: Update a bunch of LRC functions to take requests A bunch of the low level LRC functions were passing around ringbuf and ctx pairs. In a few cases, they took the r/c pair and a request as well. This is all quite messy and unnecesary. The context_queue() call is especially bad since the fake request code got removed - it takes a request and three extra things that must be extracted from the request and then it checks them against what it finds in the request. Removing all the derivable data makes the code much simpler all round. This patch updates those functions to just take the request structure. Note that logical_ring_wait_for_space now takes a request structure but already had a local request pointer that it uses to scan for something to wait on. To avoid confusion the local variable has been renamed 'target' (it is searching for a target request to do something with) and the parameter has been called req (to guarantee anything accidentally missed gets a compiler error). v2: Updated commit message re wait_for_space (Tomas Elf review comment). For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 66 ++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a40ca1f5965b..045c99220184 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -544,23 +544,18 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) ((u32)ring->next_context_status_buffer & 0x07) << 8); } -static int execlists_context_queue(struct intel_engine_cs *ring, - struct intel_context *to, - u32 tail, - struct drm_i915_gem_request *request) +static int execlists_context_queue(struct drm_i915_gem_request *request) { + struct intel_engine_cs *ring = request->ring; struct drm_i915_gem_request *cursor; int num_elements = 0; - if (to != ring->default_context) - intel_lr_context_pin(ring, to); - - WARN_ON(!request); - WARN_ON(to != request->ctx); + if (request->ctx != ring->default_context) + intel_lr_context_pin(ring, request->ctx); i915_gem_request_reference(request); - request->tail = tail; + request->tail = request->ringbuf->tail; spin_lock_irq(&ring->execlist_lock); @@ -575,7 +570,7 @@ static int execlists_context_queue(struct intel_engine_cs *ring, struct drm_i915_gem_request, execlist_link); - if (to == tail_req->ctx) { + if (request->ctx == tail_req->ctx) { WARN(tail_req->elsp_submitted != 0, "More than 2 already-submitted reqs queued\n"); list_del(&tail_req->execlist_link); @@ -659,12 +654,12 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request return 0; } -static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, +static int logical_ring_wait_for_space(struct drm_i915_gem_request *req, int bytes) { - struct intel_engine_cs *ring = ringbuf->ring; - struct drm_i915_gem_request *request; + struct intel_ringbuffer *ringbuf = req->ringbuf; + struct intel_engine_cs *ring = req->ring; + struct drm_i915_gem_request *target; unsigned space; int ret; @@ -674,26 +669,26 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, if (intel_ring_space(ringbuf) >= bytes) return 0; - list_for_each_entry(request, &ring->request_list, list) { + list_for_each_entry(target, &ring->request_list, list) { /* * The request queue is per-engine, so can contain requests * from multiple ringbuffers. Here, we must ignore any that * aren't from the ringbuffer we're considering. */ - if (request->ringbuf != ringbuf) + if (target->ringbuf != ringbuf) continue; /* Would completion of this request free enough space? */ - space = __intel_ring_space(request->postfix, ringbuf->tail, + space = __intel_ring_space(target->postfix, ringbuf->tail, ringbuf->size); if (space >= bytes) break; } - if (WARN_ON(&request->list == &ring->request_list)) + if (WARN_ON(&target->list == &ring->request_list)) return -ENOSPC; - ret = i915_wait_request(request); + ret = i915_wait_request(target); if (ret) return ret; @@ -703,7 +698,7 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, /* * intel_logical_ring_advance_and_submit() - advance the tail and submit the workload - * @ringbuf: Logical Ringbuffer to advance. + * @request: Request to advance the logical ringbuffer of. * * The tail is updated in our logical ringbuffer struct, not in the actual context. What * really happens during submission is that the context and current tail will be placed @@ -711,23 +706,21 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, * point, the tail *inside* the context is updated and the ELSP written to. */ static void -intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, - struct drm_i915_gem_request *request) +intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request) { - struct intel_engine_cs *ring = ringbuf->ring; + struct intel_engine_cs *ring = request->ring; - intel_logical_ring_advance(ringbuf); + intel_logical_ring_advance(request->ringbuf); if (intel_ring_stopped(ring)) return; - execlists_context_queue(ring, ctx, ringbuf->tail, request); + execlists_context_queue(request); } -static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx) +static int logical_ring_wrap_buffer(struct drm_i915_gem_request *req) { + struct intel_ringbuffer *ringbuf = req->ringbuf; uint32_t __iomem *virt; int rem = ringbuf->size - ringbuf->tail; @@ -735,7 +728,7 @@ static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf, WARN_ON(ringbuf->reserved_in_use); if (ringbuf->space < rem) { - int ret = logical_ring_wait_for_space(ringbuf, ctx, rem); + int ret = logical_ring_wait_for_space(req, rem); if (ret) return ret; @@ -752,9 +745,9 @@ static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf, return 0; } -static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, int bytes) +static int logical_ring_prepare(struct drm_i915_gem_request *req, int bytes) { + struct intel_ringbuffer *ringbuf = req->ringbuf; int ret; /* @@ -766,7 +759,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, bytes += ringbuf->reserved_size; if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) { - ret = logical_ring_wrap_buffer(ringbuf, ctx); + ret = logical_ring_wrap_buffer(req); if (unlikely(ret)) return ret; @@ -779,7 +772,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, } if (unlikely(ringbuf->space < bytes)) { - ret = logical_ring_wait_for_space(ringbuf, ctx, bytes); + ret = logical_ring_wait_for_space(req, bytes); if (unlikely(ret)) return ret; } @@ -814,8 +807,7 @@ static int intel_logical_ring_begin(struct drm_i915_gem_request *req, if (ret) return ret; - ret = logical_ring_prepare(req->ringbuf, req->ctx, - num_dwords * sizeof(uint32_t)); + ret = logical_ring_prepare(req, num_dwords * sizeof(uint32_t)); if (ret) return ret; @@ -1557,7 +1549,7 @@ static int gen8_emit_request(struct drm_i915_gem_request *request) intel_logical_ring_emit(ringbuf, i915_gem_request_get_seqno(request)); intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT); intel_logical_ring_emit(ringbuf, MI_NOOP); - intel_logical_ring_advance_and_submit(ringbuf, request->ctx, request); + intel_logical_ring_advance_and_submit(request); /* * Here we add two extra NOOPs as padding to avoid -- cgit v1.3-6-gb490 From a5ac0f907d5b713a89c960605f36c0ccb436022c Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:15 +0100 Subject: drm/i915: Remove the now obsolete 'i915_gem_check_olr()' As there is no OLR to check, the check_olr() function is now a no-op and can be removed. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem.c | 34 +--------------------------------- drivers/gpu/drm/i915/intel_display.c | 6 ------ 3 files changed, 1 insertion(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7d7339c8ec96..92a38ff365e0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2852,7 +2852,6 @@ bool i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_requests_ring(struct intel_engine_cs *ring); int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible); -int __must_check i915_gem_check_olr(struct drm_i915_gem_request *req); 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 10832c05e96d..f79ce9f22312 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1149,17 +1149,6 @@ i915_gem_check_wedge(struct i915_gpu_error *error, return 0; } -/* - * Compare arbitrary request against outstanding lazy request. Emit on match. - */ -int -i915_gem_check_olr(struct drm_i915_gem_request *req) -{ - WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex)); - - return 0; -} - static void fake_irq(unsigned long data) { wake_up_process((struct task_struct *)data); @@ -1440,10 +1429,6 @@ i915_wait_request(struct drm_i915_gem_request *req) if (ret) return ret; - ret = i915_gem_check_olr(req); - if (ret) - return ret; - ret = __i915_wait_request(req, atomic_read(&dev_priv->gpu_error.reset_counter), interruptible, NULL, NULL); @@ -1543,10 +1528,6 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (req == NULL) return 0; - ret = i915_gem_check_olr(req); - if (ret) - goto err; - requests[n++] = i915_gem_request_reference(req); } else { for (i = 0; i < I915_NUM_RINGS; i++) { @@ -1556,10 +1537,6 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (req == NULL) continue; - ret = i915_gem_check_olr(req); - if (ret) - goto err; - requests[n++] = i915_gem_request_reference(req); } } @@ -1570,7 +1547,6 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, NULL, rps); mutex_lock(&dev->struct_mutex); -err: for (i = 0; i < n; i++) { if (ret == 0) i915_gem_object_retire_request(obj, requests[i]); @@ -2983,7 +2959,7 @@ i915_gem_idle_work_handler(struct work_struct *work) static int i915_gem_object_flush_active(struct drm_i915_gem_object *obj) { - int ret, i; + int i; if (!obj->active) return 0; @@ -2998,10 +2974,6 @@ i915_gem_object_flush_active(struct drm_i915_gem_object *obj) if (list_empty(&req->list)) goto retire; - ret = i915_gem_check_olr(req); - if (ret) - return ret; - if (i915_gem_request_completed(req, true)) { __i915_gem_request_retire__upto(req); retire: @@ -3117,10 +3089,6 @@ __i915_gem_object_sync(struct drm_i915_gem_object *obj, if (i915_gem_request_completed(from_req, true)) return 0; - ret = i915_gem_check_olr(from_req); - if (ret) - return ret; - if (!i915_semaphore_is_enabled(obj->base.dev)) { struct drm_i915_private *i915 = to_i915(obj->base.dev); ret = __i915_wait_request(from_req, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bd121cd7ca1d..1bc217ab3592 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11476,12 +11476,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, i915_gem_request_assign(&work->flip_queued_req, obj->last_write_req); } else { - if (obj->last_write_req) { - ret = i915_gem_check_olr(obj->last_write_req); - if (ret) - goto cleanup_unpin; - } - if (!request) { ret = i915_gem_request_alloc(ring, ring->default_context, &request); if (ret) -- cgit v1.3-6-gb490 From 4d78c8dcf9f856587fb7bf664021d9fb699012d9 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 23 Jun 2015 15:50:43 +0100 Subject: drm/i915: Fix warnings reported by 0-day Kernel 0-day framework reported warnings with WA batch patches, this patch fixes those warnings and an additional warning reported in intel_lrc.c file. Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 045c99220184..8d1c66debb2b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -784,6 +784,7 @@ static int logical_ring_prepare(struct drm_i915_gem_request *req, int bytes) * intel_logical_ring_begin() - prepare the logical ringbuffer to accept some commands * * @request: The request to start some new work for + * @ctx: Logical ring context whose ringbuffer is being prepared. * @num_dwords: number of DWORDs that we plan to write to the ringbuffer. * * The ringbuffer might not be ready to accept the commands right away (maybe it needs to @@ -1132,7 +1133,7 @@ static inline int wa_ctx_end(struct i915_wa_ctx_bb *wa_ctx, * * The number of WA applied are not known at the beginning; we use this field * to return the no of DWORDS written. - + * * It is to be noted that this batch does not contain MI_BATCH_BUFFER_END * so it adds NOOPs as padding to make it cacheline aligned. * MI_BATCH_BUFFER_END will be added to perctx batch and both of them together @@ -1194,6 +1195,7 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, * @wa_ctx: structure representing wa_ctx * offset: specifies start of the batch, should be cache-aligned. * size: size of the batch in DWORDS but HW expects in terms of cachelines + * @batch: page in which WA are loaded * @offset: This field specifies the start of this batch. * This batch is started immediately after indirect_ctx batch. Since we ensure * that indirect_ctx ends on a cacheline this batch is aligned automatically. -- cgit v1.3-6-gb490 From 5e60d790714bbda0402ddd715aee5e61b48682f4 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 23 Jun 2015 15:50:44 +0100 Subject: drm/i915: Bail out early if WA batch is not available for given Gen To initialize WA batch, at the moment we first allocate batch and then check whether we have any WA to be initialized for the given Gen; if we don't have any WA then we WARN the user, destroy the batch and return but this is causing another WARN in cleanup code complaining about sleeping in atomic context. Till we understand this better and to keep things simpler, bail out early if we don't have WA. Cc: Tvrtko Ursulin Cc: Chris Wilson Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8d1c66debb2b..500ae5139f51 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1260,6 +1260,12 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring) WARN_ON(ring->id != RCS); + /* update this when WA for higher Gen are added */ + if (WARN(INTEL_INFO(ring->dev)->gen > 8, + "WA batch buffer is not initialized for Gen%d\n", + INTEL_INFO(ring->dev)->gen)) + return 0; + /* some WA perform writes to scratch page, ensure it is valid */ if (ring->scratch.obj == NULL) { DRM_ERROR("scratch page not allocated for %s\n", ring->name); @@ -1290,11 +1296,6 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring) &offset); if (ret) goto out; - } else { - WARN(INTEL_INFO(ring->dev)->gen >= 8, - "WA batch buffer is not initialized for Gen%d\n", - INTEL_INFO(ring->dev)->gen); - lrc_destroy_wa_ctx_obj(ring); } out: -- cgit v1.3-6-gb490 From 392d39cfcaa9bcfa202fb0fd3bc65f3c20de318f Mon Sep 17 00:00:00 2001 From: Han Xu Date: Wed, 13 May 2015 14:40:57 -0500 Subject: mtd: fsl-quadspi: Access multiple chips simultaneously Add supports for simultaneous access to multiple chips. Need to lock the mutex before any quad spi operations and unlock the mutex after operations complete. Signed-off-by: Han Xu [Brian: reworked err path in fsl_qspi_prep()] Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 52a872fa1b6e..4fe13dd535f8 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -26,6 +26,7 @@ #include #include #include +#include /* The registers */ #define QUADSPI_MCR 0x00 @@ -233,6 +234,7 @@ struct fsl_qspi { u32 clk_rate; unsigned int chip_base_addr; /* We may support two chips. */ bool has_second_chip; + struct mutex lock; }; static inline int is_vybrid_qspi(struct fsl_qspi *q) @@ -761,18 +763,24 @@ static int fsl_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) struct fsl_qspi *q = nor->priv; int ret; + mutex_lock(&q->lock); ret = clk_enable(q->clk_en); if (ret) - return ret; + goto err_mutex; ret = clk_enable(q->clk); - if (ret) { - clk_disable(q->clk_en); - return ret; - } + if (ret) + goto err_clk; fsl_qspi_set_base_addr(q, nor); return 0; + +err_clk: + clk_disable(q->clk_en); +err_mutex: + mutex_unlock(&q->lock); + + return ret; } static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) @@ -781,6 +789,7 @@ static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) clk_disable(q->clk); clk_disable(q->clk_en); + mutex_unlock(&q->lock); } static int fsl_qspi_probe(struct platform_device *pdev) @@ -864,6 +873,8 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (of_get_property(np, "fsl,qspi-has-second-chip", NULL)) q->has_second_chip = true; + mutex_init(&q->lock); + /* iterate the subnodes. */ for_each_available_child_of_node(dev->of_node, np) { char modalias[40]; @@ -892,24 +903,24 @@ static int fsl_qspi_probe(struct platform_device *pdev) ret = of_modalias_node(np, modalias, sizeof(modalias)); if (ret < 0) - goto irq_failed; + goto mutex_failed; ret = of_property_read_u32(np, "spi-max-frequency", &q->clk_rate); if (ret < 0) - goto irq_failed; + goto mutex_failed; /* set the chip address for READID */ fsl_qspi_set_base_addr(q, nor); ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD); if (ret) - goto irq_failed; + goto mutex_failed; ppdata.of_node = np; ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); if (ret) - goto irq_failed; + goto mutex_failed; /* Set the correct NOR size now. */ if (q->nor_size == 0) { @@ -950,6 +961,8 @@ last_init_failed: i *= 2; mtd_device_unregister(&q->mtd[i]); } +mutex_failed: + mutex_destroy(&q->lock); irq_failed: clk_disable_unprepare(q->clk); clk_failed: @@ -973,6 +986,7 @@ static int fsl_qspi_remove(struct platform_device *pdev) writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); writel(0x0, q->iobase + QUADSPI_RSER); + mutex_destroy(&q->lock); clk_unprepare(q->clk); clk_unprepare(q->clk_en); return 0; -- cgit v1.3-6-gb490 From fdbff9282c0f5f61ffc87d57461b04d943250910 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 11:23:24 +0200 Subject: drm/i915: Clear fb_tracking.busy_bits also for synchronous flips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current/old frontbuffer might still have gpu frontbuffer rendering pending. But once flipped it won't have the corresponding frontbuffer bits any more and hence the request retire function won't ever clear the corresponding busy bits. The async flip tracking (with the flip_prepare and flip_complete functions) already does this, but somehow I've forgotten to do this for synchronous flips. Note that we don't track outstanding rendering of the new framebuffer with busy_bits since all our plane update code waits for previous rendering to complete before displaying a new buffer. Hence a new buffer will never be busy. v2: Drop the spurious inline Ville spotted. v3: Don't touch flip_bits in the synchronsou frontbuffer_flip function, noticed by Paulo. v4: Remove one more inline that slipped through (Paulo). Reported-by: Paulo Zanoni Cc: Paulo Zanoni Cc: Ville Syrjälä Testcase: igt/kms_frontbuffer_tracking/fbc-modesetfrombusy Tested-by: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 17 +---------------- drivers/gpu/drm/i915/intel_frontbuffer.c | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3529c9c9c420..e66ff7a3cb8a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -963,23 +963,8 @@ void intel_frontbuffer_flip_complete(struct drm_device *dev, unsigned frontbuffer_bits); void intel_frontbuffer_flush(struct drm_device *dev, unsigned frontbuffer_bits); -/** - * intel_frontbuffer_flip - synchronous frontbuffer flip - * @dev: DRM device - * @frontbuffer_bits: frontbuffer plane tracking bits - * - * This function gets called after scheduling a flip on @obj. This is for - * synchronous plane updates which will happen on the next vblank and which will - * not get delayed by pending gpu rendering. - * - * Can be called without any locks held. - */ -static inline void intel_frontbuffer_flip(struct drm_device *dev, - unsigned frontbuffer_bits) -{ - intel_frontbuffer_flush(dev, frontbuffer_bits); -} + unsigned frontbuffer_bits); unsigned int intel_fb_align_height(struct drm_device *dev, unsigned int height, diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index bdf0d57cad0f..3b0ac73ede8f 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -266,3 +266,28 @@ void intel_frontbuffer_flip_complete(struct drm_device *dev, intel_frontbuffer_flush(dev, frontbuffer_bits); } + +/** + * intel_frontbuffer_flip - synchronous frontbuffer flip + * @dev: DRM device + * @frontbuffer_bits: frontbuffer plane tracking bits + * + * This function gets called after scheduling a flip on @obj. This is for + * synchronous plane updates which will happen on the next vblank and which will + * not get delayed by pending gpu rendering. + * + * Can be called without any locks held. + */ + +void intel_frontbuffer_flip(struct drm_device *dev, + unsigned frontbuffer_bits) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev_priv->fb_tracking.lock); + /* Remove stale busy bits due to the old buffer. */ + dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits; + mutex_unlock(&dev_priv->fb_tracking.lock); + + intel_frontbuffer_flush(dev, frontbuffer_bits); +} -- cgit v1.3-6-gb490 From 27e78a2a1f92e79707b4fb18cff1276088ef9178 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:21 +0200 Subject: drm/i915: Filter out no-op frontbuffer tracking flushes Paulo noticed that the fbc frontbuffer tracking flush callback occasionally gets a call without any bit set. This can happen when we have to filter flush calls due to e.g. gpu rendering. Filter these out. Reported-by: Paulo Zanoni Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_frontbuffer.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 3b0ac73ede8f..6a70a51332e9 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -175,6 +175,9 @@ void intel_frontbuffer_flush(struct drm_device *dev, frontbuffer_bits &= ~dev_priv->fb_tracking.busy_bits; mutex_unlock(&dev_priv->fb_tracking.lock); + if (!frontbuffer_bits) + return; + intel_mark_fb_busy(dev, frontbuffer_bits); intel_edp_drrs_flush(dev, frontbuffer_bits); -- cgit v1.3-6-gb490 From 9a851789e8a0cf38f9c04705a8e01b572e61f05f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:22 +0200 Subject: drm/i915: debugfs for frontbuffer tracking Useful to figure out whether stuck bits are due to the frontbuffer tracking code as opposed to individual consumers (who have their own bitmask tracking). Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 35a5defe7e29..495a6376cf39 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1581,6 +1581,21 @@ static int i915_drpc_info(struct seq_file *m, void *unused) return ironlake_drpc_info(m); } +static int i915_frontbuffer_tracking(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + seq_printf(m, "FB tracking busy bits: 0x%08x\n", + dev_priv->fb_tracking.busy_bits); + + seq_printf(m, "FB tracking flip bits: 0x%08x\n", + dev_priv->fb_tracking.flip_bits); + + return 0; +} + static int i915_fbc_status(struct seq_file *m, void *unused) { struct drm_info_node *node = m->private; @@ -5021,6 +5036,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_drpc_info", i915_drpc_info, 0}, {"i915_emon_status", i915_emon_status, 0}, {"i915_ring_freq_table", i915_ring_freq_table, 0}, + {"i915_frontbuffer_tracking", i915_frontbuffer_tracking, 0}, {"i915_fbc_status", i915_fbc_status, 0}, {"i915_ips_status", i915_ips_status, 0}, {"i915_sr_status", i915_sr_status, 0}, -- cgit v1.3-6-gb490 From 251ac8621921d3936ea2eff6790fe35b25cf28a4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:24 +0200 Subject: drm/i915: s/update/compute/ for gmch dpll register functions I was momentarily confused until I've double-checked that these functions really only compute state and don't update the hardware state. They once did that, but since Ander's rework of the dpll computation flow that's no longer the case. Rename them to avoid further confusion. Note that the ilk code already follows the compute_dpll naming scheme for computing the actual register value. DDI code goes with _calc_, but that is close enough. Cc: Ander Conselvan de Oliveira Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1bc217ab3592..060e30be3e39 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7160,8 +7160,8 @@ void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n) intel_cpu_transcoder_set_m_n(crtc, dp_m_n, dp_m2_n2); } -static void vlv_update_pll(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) +static void vlv_compute_dpll(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config) { u32 dpll, dpll_md; @@ -7274,8 +7274,8 @@ static void vlv_prepare_pll(struct intel_crtc *crtc, mutex_unlock(&dev_priv->sb_lock); } -static void chv_update_pll(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) +static void chv_compute_dpll(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config) { pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV | DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS | @@ -7414,11 +7414,11 @@ void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe, }; if (IS_CHERRYVIEW(dev)) { - chv_update_pll(crtc, &pipe_config); + chv_compute_dpll(crtc, &pipe_config); chv_prepare_pll(crtc, &pipe_config); chv_enable_pll(crtc, &pipe_config); } else { - vlv_update_pll(crtc, &pipe_config); + vlv_compute_dpll(crtc, &pipe_config); vlv_prepare_pll(crtc, &pipe_config); vlv_enable_pll(crtc, &pipe_config); } @@ -7440,10 +7440,10 @@ void vlv_force_pll_off(struct drm_device *dev, enum pipe pipe) vlv_disable_pll(to_i915(dev), pipe); } -static void i9xx_update_pll(struct intel_crtc *crtc, - struct intel_crtc_state *crtc_state, - intel_clock_t *reduced_clock, - int num_connectors) +static void i9xx_compute_dpll(struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state, + intel_clock_t *reduced_clock, + int num_connectors) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -7517,10 +7517,10 @@ static void i9xx_update_pll(struct intel_crtc *crtc, } } -static void i8xx_update_pll(struct intel_crtc *crtc, - struct intel_crtc_state *crtc_state, - intel_clock_t *reduced_clock, - int num_connectors) +static void i8xx_compute_dpll(struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state, + intel_clock_t *reduced_clock, + int num_connectors) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -7830,17 +7830,17 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc, } if (IS_GEN2(dev)) { - i8xx_update_pll(crtc, crtc_state, + i8xx_compute_dpll(crtc, crtc_state, has_reduced_clock ? &reduced_clock : NULL, - num_connectors); + num_connectors); } else if (IS_CHERRYVIEW(dev)) { - chv_update_pll(crtc, crtc_state); + chv_compute_dpll(crtc, crtc_state); } else if (IS_VALLEYVIEW(dev)) { - vlv_update_pll(crtc, crtc_state); + vlv_compute_dpll(crtc, crtc_state); } else { - i9xx_update_pll(crtc, crtc_state, + i9xx_compute_dpll(crtc, crtc_state, has_reduced_clock ? &reduced_clock : NULL, - num_connectors); + num_connectors); } return 0; -- cgit v1.3-6-gb490 From c1d038c6e2fe1a07b23d8908bb2edfc95ca571cd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:25 +0200 Subject: drm/i915/drrs: Restrict buffer tracking to the DRRS pipe The current code tracks business across all pipes, but we're only really interested in the one pipe DRRS is enabled on. Fairly tiny optimization, but something I noticed while reading the code. But it might matter a bit when e.g. showing a video or something only on the external screen, while the panel is kept static. Also regroup the code slightly: First compute new bitmasks, then take appropriate actions. Cc: Ramalingam C Cc: Sivakumar Thulasimani Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a1873b1498c9..c43bff90c47a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5534,16 +5534,15 @@ void intel_edp_drrs_invalidate(struct drm_device *dev, crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; + frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); + dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits; + /* invalidate means busy screen hence upclock */ - if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) { + if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) intel_dp_set_drrs_state(dev_priv->dev, dev_priv->drrs.dp->attached_connector->panel. fixed_mode->vrefresh); - } - - frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); - dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits; mutex_unlock(&dev_priv->drrs.mutex); } @@ -5579,10 +5578,12 @@ void intel_edp_drrs_flush(struct drm_device *dev, crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; + + frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; /* flush means busy screen hence upclock */ - if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) + if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) intel_dp_set_drrs_state(dev_priv->dev, dev_priv->drrs.dp->attached_connector->panel. fixed_mode->vrefresh); -- cgit v1.3-6-gb490 From ec76d62999b73f818f7d777ce037157bd2d4af02 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:26 +0200 Subject: drm/i915/psr: Restrict buffer tracking to the PSR pipe The current code tracks business across all pipes, but we're only really interested in the one pipe DRRS is enabled on. Fairly tiny optimization, but something I noticed while reading the code. But it might matter a bit when e.g. showing a video or something only on the external screen, while the panel is kept static. Also regroup the code slightly: First compute new bitmasks, then take appropriate actions. Cc: Rodrigo Vivi Cc: Durgadoss R Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_psr.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 5ee0fa57ed19..e354ceacb628 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -663,11 +663,12 @@ void intel_psr_invalidate(struct drm_device *dev, crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; - intel_psr_exit(dev); - frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); - dev_priv->psr.busy_frontbuffer_bits |= frontbuffer_bits; + + if (frontbuffer_bits) + intel_psr_exit(dev); + mutex_unlock(&dev_priv->psr.lock); } @@ -698,6 +699,8 @@ void intel_psr_flush(struct drm_device *dev, crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; + + frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits; /* @@ -716,7 +719,7 @@ void intel_psr_flush(struct drm_device *dev, * invalidating. Which means we need to manually fake this in * software for all flushes, not just when we've seen a preceding * invalidation through frontbuffer rendering. */ - if (!HAS_DDI(dev)) + if (frontbuffer_bits && !HAS_DDI(dev)) intel_psr_exit(dev); if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) -- cgit v1.3-6-gb490 From 20c8838b0e3ba408a0ffe185b6124cdd0fcc3283 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:27 +0200 Subject: drm/i915/psr: Restrict single-shot updates to the PSR pipe The frontbuffer code gives us accurate information about activity, let's use it. Again this should avoid unecessary updates when multiple screens are on. Also realign function paramaters, I couldn't resist that bit of OCD. Cc: Rodrigo Vivi Cc: Durgadoss R Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 7 ++++--- drivers/gpu/drm/i915/intel_frontbuffer.c | 2 +- drivers/gpu/drm/i915/intel_psr.c | 22 +++++++++++++--------- 3 files changed, 18 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e66ff7a3cb8a..e90c7432bf4b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1307,11 +1307,12 @@ void intel_backlight_unregister(struct drm_device *dev); void intel_psr_enable(struct intel_dp *intel_dp); void intel_psr_disable(struct intel_dp *intel_dp); void intel_psr_invalidate(struct drm_device *dev, - unsigned frontbuffer_bits); + unsigned frontbuffer_bits); void intel_psr_flush(struct drm_device *dev, - unsigned frontbuffer_bits); + unsigned frontbuffer_bits); void intel_psr_init(struct drm_device *dev); -void intel_psr_single_frame_update(struct drm_device *dev); +void intel_psr_single_frame_update(struct drm_device *dev, + unsigned frontbuffer_bits); /* intel_runtime_pm.c */ int intel_power_domains_init(struct drm_i915_private *); diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 6a70a51332e9..89139c2ddd9e 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -243,7 +243,7 @@ void intel_frontbuffer_flip_prepare(struct drm_device *dev, dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits; mutex_unlock(&dev_priv->fb_tracking.lock); - intel_psr_single_frame_update(dev); + intel_psr_single_frame_update(dev, frontbuffer_bits); } /** diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index e354ceacb628..d79ba58637d7 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -596,13 +596,15 @@ static void intel_psr_exit(struct drm_device *dev) /** * intel_psr_single_frame_update - Single Frame Update * @dev: DRM device + * @frontbuffer_bits: frontbuffer plane tracking bits * * Some platforms support a single frame update feature that is used to * send and update only one frame on Remote Frame Buffer. * So far it is only implemented for Valleyview and Cherryview because * hardware requires this to be done before a page flip. */ -void intel_psr_single_frame_update(struct drm_device *dev) +void intel_psr_single_frame_update(struct drm_device *dev, + unsigned frontbuffer_bits) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -624,14 +626,16 @@ void intel_psr_single_frame_update(struct drm_device *dev) crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; - val = I915_READ(VLV_PSRCTL(pipe)); - /* - * We need to set this bit before writing registers for a flip. - * This bit will be self-clear when it gets to the PSR active state. - */ - I915_WRITE(VLV_PSRCTL(pipe), val | VLV_EDP_PSR_SINGLE_FRAME_UPDATE); + if (frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(pipe)) { + val = I915_READ(VLV_PSRCTL(pipe)); + /* + * We need to set this bit before writing registers for a flip. + * This bit will be self-clear when it gets to the PSR active state. + */ + I915_WRITE(VLV_PSRCTL(pipe), val | VLV_EDP_PSR_SINGLE_FRAME_UPDATE); + } mutex_unlock(&dev_priv->psr.lock); } @@ -648,7 +652,7 @@ void intel_psr_single_frame_update(struct drm_device *dev) * Dirty frontbuffers relevant to PSR are tracked in busy_frontbuffer_bits." */ void intel_psr_invalidate(struct drm_device *dev, - unsigned frontbuffer_bits) + unsigned frontbuffer_bits) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -685,7 +689,7 @@ void intel_psr_invalidate(struct drm_device *dev, * Dirty frontbuffers relevant to PSR are tracked in busy_frontbuffer_bits. */ void intel_psr_flush(struct drm_device *dev, - unsigned frontbuffer_bits) + unsigned frontbuffer_bits) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; -- cgit v1.3-6-gb490 From 9fb73863cc3eda7476e88a03e8b125b3d309b7b3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:28 +0200 Subject: drm/i915: Use to_i915 in intel_frontbuffer.c Must have missed the transition. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_frontbuffer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 89139c2ddd9e..16e699dac295 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -131,7 +131,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, enum fb_op_origin origin) { struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -168,7 +168,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, void intel_frontbuffer_flush(struct drm_device *dev, unsigned frontbuffer_bits) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); /* Delay flushing when rings are still busy.*/ mutex_lock(&dev_priv->fb_tracking.lock); @@ -198,7 +198,7 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire) { struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); unsigned frontbuffer_bits; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -235,7 +235,7 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, void intel_frontbuffer_flip_prepare(struct drm_device *dev, unsigned frontbuffer_bits) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); mutex_lock(&dev_priv->fb_tracking.lock); dev_priv->fb_tracking.flip_bits |= frontbuffer_bits; @@ -259,7 +259,7 @@ void intel_frontbuffer_flip_prepare(struct drm_device *dev, void intel_frontbuffer_flip_complete(struct drm_device *dev, unsigned frontbuffer_bits) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); mutex_lock(&dev_priv->fb_tracking.lock); /* Mask any cancelled flips. */ @@ -285,7 +285,7 @@ void intel_frontbuffer_flip_complete(struct drm_device *dev, void intel_frontbuffer_flip(struct drm_device *dev, unsigned frontbuffer_bits) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); mutex_lock(&dev_priv->fb_tracking.lock); /* Remove stale busy bits due to the old buffer. */ -- cgit v1.3-6-gb490 From 0160f055393f457f8f218377bc088207eb502c38 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 23 Jun 2015 15:46:57 +0100 Subject: drm/i915/gen8: Add WaClearSlmSpaceAtContextSwitch workaround In Indirect context w/a batch buffer, WaClearSlmSpaceAtContextSwitch This WA performs writes to scratch page so it must be valid, this check is performed before initializing the batch with this WA. v2: s/PIPE_CONTROL_FLUSH_RO_CACHES/PIPE_CONTROL_FLUSH_L3 (Ville) v3: GTT bit in scratch address should be mbz (Chris) Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Rafael Barbalho Signed-off-by: Arun Siluvery Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_lrc.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b8e2259fe9ee..c19067c843e8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -415,6 +415,7 @@ #define DISPLAY_PLANE_A (0<<20) #define DISPLAY_PLANE_B (1<<20) #define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|(len-2)) +#define PIPE_CONTROL_FLUSH_L3 (1<<27) #define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */ #define PIPE_CONTROL_MMIO_WRITE (1<<23) #define PIPE_CONTROL_STORE_DATA_INDEX (1<<21) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 500ae5139f51..90a02dc5245e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1147,6 +1147,7 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, uint32_t *const batch, uint32_t *offset) { + uint32_t scratch_addr; uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); /* WaDisableCtxRestoreArbitration:bdw,chv */ @@ -1175,6 +1176,20 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, wa_ctx_emit(batch, l3sqc4_flush & ~GEN8_LQSC_FLUSH_COHERENT_LINES); } + /* WaClearSlmSpaceAtContextSwitch:bdw,chv */ + /* Actual scratch location is at 128 bytes offset */ + scratch_addr = ring->scratch.gtt_offset + 2*CACHELINE_BYTES; + + wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); + wa_ctx_emit(batch, (PIPE_CONTROL_FLUSH_L3 | + PIPE_CONTROL_GLOBAL_GTT_IVB | + PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_QW_WRITE)); + wa_ctx_emit(batch, scratch_addr); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) wa_ctx_emit(batch, MI_NOOP); -- cgit v1.3-6-gb490 From 8c6cda29194c5891d52cbd9d7aac496b61bf9310 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 23 Jun 2015 20:40:27 +0300 Subject: drm/i915/gen9: fix typo when setting up the crtc scaler This typo lead to the crtc scaler getting enabled incorrectly and an evantual state checker mismatch about the scaler_id. Signed-off-by: Imre Deak Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 060e30be3e39..47c0501f052c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4352,7 +4352,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state, int force_detach) return skl_update_scaler(state, force_detach, SKL_CRTC_INDEX, &state->scaler_state.scaler_id, DRM_ROTATE_0, state->pipe_src_w, state->pipe_src_h, - adjusted_mode->hdisplay, adjusted_mode->hdisplay); + adjusted_mode->hdisplay, adjusted_mode->vdisplay); } /** -- cgit v1.3-6-gb490 From c329a4ec595e886300710271db24bc29b74a4205 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:23 +0200 Subject: drm/i915: Nuke lvds downclock support With the new DRRS code it kinda sticks out, and we never managed to get this to work well enough without causing issues. Time to wave goodbye. I've decided to keep the logic for programming the reduced clocks intact, but everything else is gone. If anyone ever wants to resurrect this we need to redo it all anyway on top of the frontbuffer tracking. Signed-off-by: Daniel Vetter Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 -- drivers/gpu/drm/i915/i915_params.c | 6 --- drivers/gpu/drm/i915/intel_bios.c | 62 +--------------------- drivers/gpu/drm/i915/intel_display.c | 90 +++----------------------------- drivers/gpu/drm/i915/intel_frontbuffer.c | 55 ------------------- drivers/gpu/drm/i915/intel_lvds.c | 18 +------ 6 files changed, 8 insertions(+), 227 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 92a38ff365e0..ea9caf22283f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1806,9 +1806,6 @@ struct drm_i915_private { /* Reclocking support */ bool render_reclock_avail; - bool lvds_downclock_avail; - /* indicates the reduced downclock for LVDS*/ - int lvds_downclock; struct i915_frontbuffer_tracking fb_tracking; @@ -2562,7 +2559,6 @@ struct i915_params { int modeset; int panel_ignore_lid; int semaphores; - unsigned int lvds_downclock; int lvds_channel_mode; int panel_use_ssc; int vbt_sdvo_panel_type; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 18f65595d60e..7983fe48a654 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -28,7 +28,6 @@ struct i915_params i915 __read_mostly = { .modeset = -1, .panel_ignore_lid = 1, .semaphores = -1, - .lvds_downclock = 0, .lvds_channel_mode = 0, .panel_use_ssc = -1, .vbt_sdvo_panel_type = -1, @@ -84,11 +83,6 @@ MODULE_PARM_DESC(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 " diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 198fc3c3291b..2ff9eb00fdec 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -122,42 +122,6 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, drm_mode_set_name(panel_fixed_mode); } -static bool -lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a, - const struct lvds_dvo_timing *b) -{ - if (a->hactive_hi != b->hactive_hi || - a->hactive_lo != b->hactive_lo) - return false; - - if (a->hsync_off_hi != b->hsync_off_hi || - a->hsync_off_lo != b->hsync_off_lo) - return false; - - if (a->hsync_pulse_width != b->hsync_pulse_width) - return false; - - if (a->hblank_hi != b->hblank_hi || - a->hblank_lo != b->hblank_lo) - return false; - - if (a->vactive_hi != b->vactive_hi || - a->vactive_lo != b->vactive_lo) - return false; - - if (a->vsync_off != b->vsync_off) - return false; - - if (a->vsync_pulse_width != b->vsync_pulse_width) - return false; - - if (a->vblank_hi != b->vblank_hi || - a->vblank_lo != b->vblank_lo) - return false; - - return true; -} - static const struct lvds_dvo_timing * get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, @@ -213,7 +177,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, const struct lvds_dvo_timing *panel_dvo_timing; const struct lvds_fp_timing *fp_timing; struct drm_display_mode *panel_fixed_mode; - int i, downclock, drrs_mode; + int drrs_mode; lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); if (!lvds_options) @@ -272,30 +236,6 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); drm_mode_debug_printmodeline(panel_fixed_mode); - /* - * Iterate over the LVDS panel timing info to find the lowest clock - * for the native resolution. - */ - downclock = panel_dvo_timing->clock; - for (i = 0; i < 16; i++) { - const struct lvds_dvo_timing *dvo_timing; - - dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, - lvds_lfp_data_ptrs, - i); - if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) && - dvo_timing->clock < downclock) - downclock = dvo_timing->clock; - } - - 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. " - "Normal Clock %dKHz, downclock %dKHz\n", - panel_fixed_mode->clock, 10*downclock); - } - fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data, lvds_lfp_data_ptrs, lvds_options->panel_type); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 47c0501f052c..6851943e50a8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7754,9 +7754,9 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; int refclk, num_connectors = 0; - intel_clock_t clock, reduced_clock; - bool ok, has_reduced_clock = false; - bool is_lvds = false, is_dsi = false; + intel_clock_t clock; + bool ok; + bool is_dsi = false; struct intel_encoder *encoder; const intel_limit_t *limit; struct drm_atomic_state *state = crtc_state->base.state; @@ -7774,9 +7774,6 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc, encoder = to_intel_encoder(connector_state->best_encoder); switch (encoder->type) { - case INTEL_OUTPUT_LVDS: - is_lvds = true; - break; case INTEL_OUTPUT_DSI: is_dsi = true; break; @@ -7808,19 +7805,6 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc, return -EINVAL; } - if (is_lvds && dev_priv->lvds_downclock_avail) { - /* - * Ensure we match the reduced clock's P to the target - * clock. If the clocks don't match, we can't switch - * the display clock by using the FP0/FP1. In such case - * we will disable the LVDS downclock feature. - */ - has_reduced_clock = - dev_priv->display.find_dpll(limit, crtc_state, - dev_priv->lvds_downclock, - refclk, &clock, - &reduced_clock); - } /* Compat-code for transition, will disappear. */ crtc_state->dpll.n = clock.n; crtc_state->dpll.m1 = clock.m1; @@ -7830,16 +7814,14 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc, } if (IS_GEN2(dev)) { - i8xx_compute_dpll(crtc, crtc_state, - has_reduced_clock ? &reduced_clock : NULL, + i8xx_compute_dpll(crtc, crtc_state, NULL, num_connectors); } else if (IS_CHERRYVIEW(dev)) { chv_compute_dpll(crtc, crtc_state); } else if (IS_VALLEYVIEW(dev)) { vlv_compute_dpll(crtc, crtc_state); } else { - i9xx_compute_dpll(crtc, crtc_state, - has_reduced_clock ? &reduced_clock : NULL, + i9xx_compute_dpll(crtc, crtc_state, NULL, num_connectors); } @@ -8651,9 +8633,7 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; int refclk; const intel_limit_t *limit; - bool ret, is_lvds = false; - - is_lvds = intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS); + bool ret; refclk = ironlake_get_refclk(crtc_state); @@ -8669,20 +8649,6 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, if (!ret) return false; - if (is_lvds && dev_priv->lvds_downclock_avail) { - /* - * Ensure we match the reduced clock's P to the target clock. - * If the clocks don't match, we can't switch the display clock - * by using the FP0/FP1. In such case we will disable the LVDS - * downclock feature. - */ - *has_reduced_clock = - dev_priv->display.find_dpll(limit, crtc_state, - dev_priv->lvds_downclock, - refclk, clock, - reduced_clock); - } - return true; } @@ -10620,42 +10586,6 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, return mode; } -static void intel_decrease_pllclock(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); - - if (!HAS_GMCH_DISPLAY(dev)) - return; - - if (!dev_priv->lvds_downclock_avail) - return; - - /* - * Since this is called by a timer, we should never get here in - * the manual case. - */ - if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) { - int pipe = intel_crtc->pipe; - int dpll_reg = DPLL(pipe); - int dpll; - - DRM_DEBUG_DRIVER("downclocking LVDS\n"); - - assert_panel_unlocked(dev_priv, pipe); - - dpll = I915_READ(dpll_reg); - dpll |= DISPLAY_RATE_SELECT_FPA1; - I915_WRITE(dpll_reg, dpll); - intel_wait_for_vblank(dev, pipe); - dpll = I915_READ(dpll_reg); - if (!(dpll & DISPLAY_RATE_SELECT_FPA1)) - DRM_DEBUG_DRIVER("failed to downclock LVDS!\n"); - } - -} - void intel_mark_busy(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -10673,20 +10603,12 @@ void intel_mark_busy(struct drm_device *dev) 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; - for_each_crtc(dev, crtc) { - if (!crtc->primary->fb) - continue; - - intel_decrease_pllclock(crtc); - } - if (INTEL_INFO(dev)->gen >= 6) gen6_rps_idle(dev->dev_private); diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 16e699dac295..6e90e2b0293d 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -65,57 +65,6 @@ #include "intel_drv.h" #include "i915_drv.h" -static void intel_increase_pllclock(struct drm_device *dev, - enum pipe pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int dpll_reg = DPLL(pipe); - int dpll; - - if (!HAS_GMCH_DISPLAY(dev)) - return; - - if (!dev_priv->lvds_downclock_avail) - return; - - dpll = I915_READ(dpll_reg); - if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) { - DRM_DEBUG_DRIVER("upclocking LVDS\n"); - - assert_panel_unlocked(dev_priv, pipe); - - dpll &= ~DISPLAY_RATE_SELECT_FPA1; - I915_WRITE(dpll_reg, dpll); - intel_wait_for_vblank(dev, pipe); - - dpll = I915_READ(dpll_reg); - if (dpll & DISPLAY_RATE_SELECT_FPA1) - DRM_DEBUG_DRIVER("failed to upclock LVDS!\n"); - } -} - -/** - * intel_mark_fb_busy - mark given planes as busy - * @dev: DRM device - * @frontbuffer_bits: bits for the affected planes - * - * This function gets called every time the screen contents change. It can be - * used to keep e.g. the update rate at the nominal refresh rate with DRRS. - */ -static void intel_mark_fb_busy(struct drm_device *dev, - unsigned frontbuffer_bits) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe pipe; - - for_each_pipe(dev_priv, pipe) { - if (!(frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(pipe))) - continue; - - intel_increase_pllclock(dev, pipe); - } -} - /** * intel_fb_obj_invalidate - invalidate frontbuffer object * @obj: GEM object to invalidate @@ -147,8 +96,6 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, mutex_unlock(&dev_priv->fb_tracking.lock); } - intel_mark_fb_busy(dev, obj->frontbuffer_bits); - intel_psr_invalidate(dev, obj->frontbuffer_bits); intel_edp_drrs_invalidate(dev, obj->frontbuffer_bits); intel_fbc_invalidate(dev_priv, obj->frontbuffer_bits, origin); @@ -178,8 +125,6 @@ void intel_frontbuffer_flush(struct drm_device *dev, if (!frontbuffer_bits) return; - intel_mark_fb_busy(dev, frontbuffer_bits); - intel_edp_drrs_flush(dev, frontbuffer_bits); intel_psr_flush(dev, frontbuffer_bits); intel_fbc_flush(dev_priv, frontbuffer_bits); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index bf1702a6e33d..ea85547611a5 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1072,24 +1072,8 @@ void intel_lvds_init(struct drm_device *dev) drm_mode_debug_printmodeline(scan); fixed_mode = drm_mode_duplicate(dev, scan); - if (fixed_mode) { - downclock_mode = - intel_find_panel_downclock(dev, - fixed_mode, connector); - if (downclock_mode != NULL && - i915.lvds_downclock) { - /* We found the downclock for LVDS. */ - dev_priv->lvds_downclock_avail = true; - dev_priv->lvds_downclock = - downclock_mode->clock; - DRM_DEBUG_KMS("LVDS downclock is found" - " in EDID. Normal clock %dKhz, " - "downclock %dKhz\n", - fixed_mode->clock, - dev_priv->lvds_downclock); - } + if (fixed_mode) goto out; - } } } -- cgit v1.3-6-gb490 From c9f8fd2d87eebb97b0ffdb3ff6cd90eb1c8e00bd Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 24 Jun 2015 09:55:20 +0100 Subject: drm/i915: Remove mostly unused variable in intel_rotate_fb_obj_pages It is only used in logging and it doesn't need to exist on its own. Also it was misleading to log view size as object size. v2: Improve commit message. (Joonas Lahtinen) Signed-off-by: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen [danvet: s/%lu/%zu/ where needed, reported by 0-day.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a8c33f7f922f..005b78b59aff 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2702,7 +2702,7 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, { struct drm_device *dev = obj->base.dev; struct intel_rotation_info *rot_info = &ggtt_view->rotation_info; - unsigned long size, pages, rot_pages; + unsigned long pages, rot_pages; struct sg_page_iter sg_iter; unsigned long i; dma_addr_t *page_addr_list; @@ -2720,7 +2720,6 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, width_pages = DIV_ROUND_UP(rot_info->pitch, tile_pitch); height_pages = DIV_ROUND_UP(rot_info->height, tile_height); rot_pages = width_pages * height_pages; - size = rot_pages * PAGE_SIZE; /* Allocate a temporary list of source pages for random access. */ page_addr_list = drm_malloc_ab(pages, sizeof(dma_addr_t)); @@ -2747,8 +2746,8 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, rotate_pages(page_addr_list, width_pages, height_pages, st); DRM_DEBUG_KMS( - "Created rotated page mapping for object size %lu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages).\n", - size, rot_info->pitch, rot_info->height, + "Created rotated page mapping for object size %zu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages).\n", + obj->base.size, rot_info->pitch, rot_info->height, rot_info->pixel_format, width_pages, height_pages, rot_pages); @@ -2762,8 +2761,8 @@ err_st_alloc: drm_free_large(page_addr_list); DRM_DEBUG_KMS( - "Failed to create rotated mapping for object size %lu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages)\n", - size, ret, rot_info->pitch, rot_info->height, + "Failed to create rotated mapping for object size %zu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages)\n", + obj->base.size, ret, rot_info->pitch, rot_info->height, rot_info->pixel_format, width_pages, height_pages, rot_pages); return ERR_PTR(ret); -- cgit v1.3-6-gb490 From 84fe03f7b2481b3a1cf4fb9db6e5df8d3698a4fe Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 23 Jun 2015 14:26:46 +0100 Subject: drm/i915: Move rotated geometry calculations into the fill helper This way data is available as soon as the view is passed into the call chain. v2: Store size in bytes instead of pages under the appropriate name. (Chris Wilson) v3: Use uint64_t instead of size_t. (Daniel Vetter) Signed-off-by: Tvrtko Ursulin Cc: Daniel Vetter Cc: Chris Wilson Reviewed-by: Joonas Lahtinen (v2) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 36 +++++++++++++----------------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 2 ++ drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 005b78b59aff..53a59b89462f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2700,29 +2700,17 @@ static struct sg_table * intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; struct intel_rotation_info *rot_info = &ggtt_view->rotation_info; - unsigned long pages, rot_pages; + unsigned int size_pages = rot_info->size >> PAGE_SHIFT; struct sg_page_iter sg_iter; unsigned long i; dma_addr_t *page_addr_list; struct sg_table *st; - unsigned int tile_pitch, tile_height; - unsigned int width_pages, height_pages; int ret = -ENOMEM; - pages = obj->base.size / PAGE_SIZE; - - /* Calculate tiling geometry. */ - tile_height = intel_tile_height(dev, rot_info->pixel_format, - rot_info->fb_modifier); - tile_pitch = PAGE_SIZE / tile_height; - width_pages = DIV_ROUND_UP(rot_info->pitch, tile_pitch); - height_pages = DIV_ROUND_UP(rot_info->height, tile_height); - rot_pages = width_pages * height_pages; - /* Allocate a temporary list of source pages for random access. */ - page_addr_list = drm_malloc_ab(pages, sizeof(dma_addr_t)); + page_addr_list = drm_malloc_ab(obj->base.size / PAGE_SIZE, + sizeof(dma_addr_t)); if (!page_addr_list) return ERR_PTR(ret); @@ -2731,7 +2719,7 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, if (!st) goto err_st_alloc; - ret = sg_alloc_table(st, rot_pages, GFP_KERNEL); + ret = sg_alloc_table(st, size_pages, GFP_KERNEL); if (ret) goto err_sg_alloc; @@ -2743,13 +2731,15 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, } /* Rotate the pages. */ - rotate_pages(page_addr_list, width_pages, height_pages, st); + rotate_pages(page_addr_list, + rot_info->width_pages, rot_info->height_pages, + st); DRM_DEBUG_KMS( - "Created rotated page mapping for object size %zu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages).\n", + "Created rotated page mapping for object size %zu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages).\n", obj->base.size, rot_info->pitch, rot_info->height, - rot_info->pixel_format, width_pages, height_pages, - rot_pages); + rot_info->pixel_format, rot_info->width_pages, + rot_info->height_pages, size_pages); drm_free_large(page_addr_list); @@ -2761,10 +2751,10 @@ err_st_alloc: drm_free_large(page_addr_list); DRM_DEBUG_KMS( - "Failed to create rotated mapping for object size %zu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages)\n", + "Failed to create rotated mapping for object size %zu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages)\n", obj->base.size, ret, rot_info->pitch, rot_info->height, - rot_info->pixel_format, width_pages, height_pages, - rot_pages); + rot_info->pixel_format, rot_info->width_pages, + rot_info->height_pages, size_pages); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 735f11986ea6..017ea308f8b4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -126,6 +126,8 @@ struct intel_rotation_info { unsigned int pitch; uint32_t pixel_format; uint64_t fb_modifier; + unsigned int width_pages, height_pages; + uint64_t size; }; struct i915_ggtt_view { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6851943e50a8..292d69e52cc5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2268,6 +2268,7 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb, const struct drm_plane_state *plane_state) { struct intel_rotation_info *info = &view->rotation_info; + unsigned int tile_height, tile_pitch; *view = i915_ggtt_view_normal; @@ -2284,6 +2285,13 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb, info->pitch = fb->pitches[0]; info->fb_modifier = fb->modifier[0]; + tile_height = intel_tile_height(fb->dev, fb->pixel_format, + fb->modifier[0]); + tile_pitch = PAGE_SIZE / tile_height; + info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_pitch); + info->height_pages = DIV_ROUND_UP(fb->height, tile_height); + info->size = info->width_pages * info->height_pages * PAGE_SIZE; + return 0; } -- cgit v1.3-6-gb490 From 9e759ff1f4a047c405034dfff1ee5c87abba41db Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 23 Jun 2015 12:57:43 +0100 Subject: drm/i915: Return correct size for rotated views Currently object size is returned for the rotated VMA size which can be bigger than the rotated view itself. Since the binding code pads all excess size with scratch pages the only minor issue with this is wasting some GGTT space, but still feels nicer to fix and report the real size. v2: Rebase for tracking size in bytes instead of pages. Signed-off-by: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 53a59b89462f..2279e030570c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2899,9 +2899,10 @@ size_t i915_ggtt_view_size(struct drm_i915_gem_object *obj, const struct i915_ggtt_view *view) { - if (view->type == I915_GGTT_VIEW_NORMAL || - view->type == I915_GGTT_VIEW_ROTATED) { + if (view->type == I915_GGTT_VIEW_NORMAL) { return obj->base.size; + } else if (view->type == I915_GGTT_VIEW_ROTATED) { + return view->rotation_info.size; } else if (view->type == I915_GGTT_VIEW_PARTIAL) { return view->params.partial.size << PAGE_SHIFT; } else { -- cgit v1.3-6-gb490 From acd3f3d3516838ebe001b7048fe59ab5b93bb645 Mon Sep 17 00:00:00 2001 From: Bob Paauwe Date: Tue, 23 Jun 2015 14:14:26 -0700 Subject: drm/i915: Add the ddi get cdclk code for BXT (v3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The registers and process differ from other platforms. If the hardware was programmed incorrectly, this will return invalid cdclk values, which should then cause reprogramming of the hardware. v2(Matt): Return 19.2 MHz when DE PLL is disabled (Ville) v3: Make less assumptions about the hardware state (Ville) Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Signed-off-by: Bob Paauwe Signed-off-by: Matt Roper Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 292d69e52cc5..cc68e4179a5a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6624,6 +6624,34 @@ static int skylake_get_display_clock_speed(struct drm_device *dev) return 24000; } +static int broxton_get_display_clock_speed(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + uint32_t cdctl = I915_READ(CDCLK_CTL); + uint32_t pll_ratio = I915_READ(BXT_DE_PLL_CTL) & BXT_DE_PLL_RATIO_MASK; + uint32_t pll_enab = I915_READ(BXT_DE_PLL_ENABLE); + int cdclk; + + if (!(pll_enab & BXT_DE_PLL_PLL_ENABLE)) + return 19200; + + cdclk = 19200 * pll_ratio / 2; + + switch (cdctl & BXT_CDCLK_CD2X_DIV_SEL_MASK) { + case BXT_CDCLK_CD2X_DIV_SEL_1: + return cdclk; /* 576MHz or 624MHz */ + case BXT_CDCLK_CD2X_DIV_SEL_1_5: + return cdclk * 2 / 3; /* 384MHz */ + case BXT_CDCLK_CD2X_DIV_SEL_2: + return cdclk / 2; /* 288MHz */ + case BXT_CDCLK_CD2X_DIV_SEL_4: + return cdclk / 4; /* 144MHz */ + } + + /* error case, do as if DE PLL isn't enabled */ + return 19200; +} + static int broadwell_get_display_clock_speed(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -14615,6 +14643,9 @@ static void intel_init_display(struct drm_device *dev) if (IS_SKYLAKE(dev)) dev_priv->display.get_display_clock_speed = skylake_get_display_clock_speed; + else if (IS_BROXTON(dev)) + dev_priv->display.get_display_clock_speed = + broxton_get_display_clock_speed; else if (IS_BROADWELL(dev)) dev_priv->display.get_display_clock_speed = broadwell_get_display_clock_speed; -- cgit v1.3-6-gb490 From a9ff8714d911b1f9417af75525eb29ac31e014fc Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 21:59:34 +0300 Subject: drm/i915: Store frontbuffer_bits in the plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid some 'switch (plane->type)' by storing the fronbuffer_bits in intel_plane. Signed-off-by: Ville Syrjälä [danvet: use singular frontbuffer_bits in intel_plane since a plan can only ever have one bit. Discussed with Ville on irc.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 75 ++++++++++-------------------------- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_sprite.c | 1 + 3 files changed, 22 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cc68e4179a5a..4882e43fd8a2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2613,7 +2613,7 @@ valid_fb: primary->crtc = primary->state->crtc = &intel_crtc->base; update_state_fb(primary); intel_crtc->base.state->plane_mask |= (1 << drm_plane_index(primary)); - obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); + obj->frontbuffer_bits |= to_intel_plane(primary)->frontbuffer_bit; } static void i9xx_update_primary_plane(struct drm_crtc *crtc, @@ -4742,25 +4742,12 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) struct drm_plane *p; /* Track fb's for any planes being disabled */ - drm_for_each_plane_mask(p, dev, atomic->disabled_planes) { struct intel_plane *plane = to_intel_plane(p); - unsigned fb_bits = 0; - - switch (p->type) { - case DRM_PLANE_TYPE_PRIMARY: - fb_bits = INTEL_FRONTBUFFER_PRIMARY(plane->pipe); - break; - case DRM_PLANE_TYPE_CURSOR: - fb_bits = INTEL_FRONTBUFFER_CURSOR(plane->pipe); - break; - case DRM_PLANE_TYPE_OVERLAY: - fb_bits = INTEL_FRONTBUFFER_SPRITE(plane->pipe); - break; - } mutex_lock(&dev->struct_mutex); - i915_gem_track_fb(intel_fb_obj(plane->base.fb), NULL, fb_bits); + i915_gem_track_fb(intel_fb_obj(plane->base.fb), NULL, + plane->frontbuffer_bit); mutex_unlock(&dev->struct_mutex); } @@ -10676,11 +10663,12 @@ static void intel_unpin_work_fn(struct work_struct *__work) { struct intel_unpin_work *work = container_of(__work, struct intel_unpin_work, work); - struct drm_device *dev = work->crtc->dev; - enum pipe pipe = to_intel_crtc(work->crtc)->pipe; + struct intel_crtc *crtc = to_intel_crtc(work->crtc); + struct drm_device *dev = crtc->base.dev; + struct drm_plane *primary = crtc->base.primary; mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(work->old_fb, work->crtc->primary->state); + intel_unpin_fb_obj(work->old_fb, primary->state); drm_gem_object_unreference(&work->pending_flip_obj->base); intel_fbc_update(dev); @@ -10689,11 +10677,11 @@ static void intel_unpin_work_fn(struct work_struct *__work) i915_gem_request_assign(&work->flip_queued_req, NULL); mutex_unlock(&dev->struct_mutex); - intel_frontbuffer_flip_complete(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); + intel_frontbuffer_flip_complete(dev, to_intel_plane(primary)->frontbuffer_bit); drm_framebuffer_unreference(work->old_fb); - BUG_ON(atomic_read(&to_intel_crtc(work->crtc)->unpin_work_count) == 0); - atomic_dec(&to_intel_crtc(work->crtc)->unpin_work_count); + BUG_ON(atomic_read(&crtc->unpin_work_count) == 0); + atomic_dec(&crtc->unpin_work_count); kfree(work); } @@ -11455,10 +11443,11 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->enable_stall_check = true; i915_gem_track_fb(intel_fb_obj(work->old_fb), obj, - INTEL_FRONTBUFFER_PRIMARY(pipe)); + to_intel_plane(primary)->frontbuffer_bit); intel_fbc_disable(dev); - intel_frontbuffer_flip_prepare(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); + intel_frontbuffer_flip_prepare(dev, + to_intel_plane(primary)->frontbuffer_bit); mutex_unlock(&dev->struct_mutex); trace_i915_flip_request(intel_crtc->plane, obj); @@ -11613,12 +11602,12 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, if (intel_wm_need_update(plane, plane_state)) intel_crtc->atomic.update_wm = true; + if (visible) + intel_crtc->atomic.fb_bits |= + to_intel_plane(plane)->frontbuffer_bit; + switch (plane->type) { case DRM_PLANE_TYPE_PRIMARY: - if (visible) - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); - intel_crtc->atomic.wait_for_flips = true; intel_crtc->atomic.pre_disable_primary = turn_off; intel_crtc->atomic.post_enable_primary = turn_on; @@ -11654,25 +11643,13 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, intel_crtc->atomic.update_fbc |= visible || mode_changed; break; case DRM_PLANE_TYPE_CURSOR: - if (visible) - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe); break; case DRM_PLANE_TYPE_OVERLAY: - /* - * 'prepare' is never called when plane is being disabled, so - * we need to handle frontbuffer tracking as a special case - */ - if (visible) - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); - if (turn_off && !mode_changed) { intel_crtc->atomic.wait_vblank = true; intel_crtc->atomic.update_sprite_watermarks |= 1 << i; } - break; } return 0; } @@ -13554,27 +13531,13 @@ intel_prepare_plane_fb(struct drm_plane *plane, { struct drm_device *dev = plane->dev; struct intel_plane *intel_plane = to_intel_plane(plane); - enum pipe pipe = intel_plane->pipe; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); - unsigned frontbuffer_bits = 0; int ret = 0; if (!obj) return 0; - switch (plane->type) { - case DRM_PLANE_TYPE_PRIMARY: - frontbuffer_bits = INTEL_FRONTBUFFER_PRIMARY(pipe); - break; - case DRM_PLANE_TYPE_CURSOR: - frontbuffer_bits = INTEL_FRONTBUFFER_CURSOR(pipe); - break; - case DRM_PLANE_TYPE_OVERLAY: - frontbuffer_bits = INTEL_FRONTBUFFER_SPRITE(pipe); - break; - } - mutex_lock(&dev->struct_mutex); if (plane->type == DRM_PLANE_TYPE_CURSOR && @@ -13588,7 +13551,7 @@ intel_prepare_plane_fb(struct drm_plane *plane, } if (ret == 0) - i915_gem_track_fb(old_obj, obj, frontbuffer_bits); + i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit); mutex_unlock(&dev->struct_mutex); @@ -13807,6 +13770,7 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, } primary->pipe = pipe; primary->plane = pipe; + primary->frontbuffer_bit = INTEL_FRONTBUFFER_PRIMARY(pipe); primary->check_plane = intel_check_primary_plane; primary->commit_plane = intel_commit_primary_plane; primary->disable_plane = intel_disable_primary_plane; @@ -13962,6 +13926,7 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev, cursor->max_downscale = 1; cursor->pipe = pipe; cursor->plane = pipe; + cursor->frontbuffer_bit = INTEL_FRONTBUFFER_CURSOR(pipe); cursor->check_plane = intel_check_cursor_plane; cursor->commit_plane = intel_commit_cursor_plane; cursor->disable_plane = intel_disable_cursor_plane; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e90c7432bf4b..e016d722cacb 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -590,6 +590,7 @@ struct intel_plane { enum pipe pipe; bool can_scale; int max_downscale; + uint32_t frontbuffer_bit; /* Since we need to change the watermarks before/after * enabling/disabling the planes, we need to store the parameters here diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index e0045aa97bd2..16be667cc5eb 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1130,6 +1130,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) intel_plane->pipe = pipe; intel_plane->plane = plane; + intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe); intel_plane->check_plane = intel_check_sprite_plane; intel_plane->commit_plane = intel_commit_sprite_plane; possible_crtcs = (1 << pipe); -- cgit v1.3-6-gb490 From 9e2ee2dd044e01e06e4a6389583f95bfa1058bf1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 21:59:35 +0300 Subject: drm/i915: Add debug messages for pipe enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we don't have any real indication when a pipe gets enabled/disabled. Add some. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4882e43fd8a2..01eaab8b6d40 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2110,6 +2110,8 @@ static void intel_enable_pipe(struct intel_crtc *crtc) int reg; u32 val; + DRM_DEBUG_KMS("enabling pipe %c\n", pipe_name(pipe)); + assert_planes_disabled(dev_priv, pipe); assert_cursor_disabled(dev_priv, pipe); assert_sprites_disabled(dev_priv, pipe); @@ -2169,6 +2171,8 @@ static void intel_disable_pipe(struct intel_crtc *crtc) int reg; u32 val; + DRM_DEBUG_KMS("disabling pipe %c\n", pipe_name(pipe)); + /* * Make sure planes won't keep trying to pump pixels to us, * or we might hang the display. -- cgit v1.3-6-gb490 From b503ed603ec9acc25dd31808fe87575bdaeab4e7 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 27 May 2015 22:20:46 +0300 Subject: iwlwifi: mvm: rs: report last tx rate based on RSSI and caps In scenarios where we haven't converged yet to a specific modulation and rate it could be better to report to userspace the last tx rate based on the STA capabilities and RSSI. This is important as sometimes userspace displays the last tx rate as the link speed. This avoids being presented with low legacy rates when rs just begins its search or after an idle period in which it resets itself. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 157 ++++++++++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/rs.h | 10 +++ 2 files changed, 160 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index daff1d0a8e4a..19a79262e0a0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2403,7 +2403,7 @@ struct rs_init_rate_info { u8 rate_idx; }; -static const struct rs_init_rate_info rs_init_rates_24ghz[] = { +static const struct rs_init_rate_info rs_optimal_rates_24ghz_legacy[] = { { -60, IWL_RATE_54M_INDEX }, { -64, IWL_RATE_48M_INDEX }, { -68, IWL_RATE_36M_INDEX }, @@ -2416,7 +2416,7 @@ static const struct rs_init_rate_info rs_init_rates_24ghz[] = { { S8_MIN, IWL_RATE_1M_INDEX }, }; -static const struct rs_init_rate_info rs_init_rates_5ghz[] = { +static const struct rs_init_rate_info rs_optimal_rates_5ghz_legacy[] = { { -60, IWL_RATE_54M_INDEX }, { -64, IWL_RATE_48M_INDEX }, { -72, IWL_RATE_36M_INDEX }, @@ -2427,6 +2427,124 @@ static const struct rs_init_rate_info rs_init_rates_5ghz[] = { { S8_MIN, IWL_RATE_6M_INDEX }, }; +static const struct rs_init_rate_info rs_optimal_rates_ht[] = { + { -60, IWL_RATE_MCS_7_INDEX }, + { -64, IWL_RATE_MCS_6_INDEX }, + { -68, IWL_RATE_MCS_5_INDEX }, + { -72, IWL_RATE_MCS_4_INDEX }, + { -80, IWL_RATE_MCS_3_INDEX }, + { -84, IWL_RATE_MCS_2_INDEX }, + { -85, IWL_RATE_MCS_1_INDEX }, + { S8_MIN, IWL_RATE_MCS_0_INDEX}, +}; + +static const struct rs_init_rate_info rs_optimal_rates_vht_20mhz[] = { + { -60, IWL_RATE_MCS_8_INDEX }, + { -64, IWL_RATE_MCS_7_INDEX }, + { -68, IWL_RATE_MCS_6_INDEX }, + { -72, IWL_RATE_MCS_5_INDEX }, + { -80, IWL_RATE_MCS_4_INDEX }, + { -84, IWL_RATE_MCS_3_INDEX }, + { -85, IWL_RATE_MCS_2_INDEX }, + { -87, IWL_RATE_MCS_1_INDEX }, + { S8_MIN, IWL_RATE_MCS_0_INDEX}, +}; + +static const struct rs_init_rate_info rs_optimal_rates_vht_40_80mhz[] = { + { -60, IWL_RATE_MCS_9_INDEX }, + { -64, IWL_RATE_MCS_8_INDEX }, + { -68, IWL_RATE_MCS_7_INDEX }, + { -72, IWL_RATE_MCS_6_INDEX }, + { -80, IWL_RATE_MCS_5_INDEX }, + { -84, IWL_RATE_MCS_4_INDEX }, + { -85, IWL_RATE_MCS_3_INDEX }, + { -87, IWL_RATE_MCS_2_INDEX }, + { -88, IWL_RATE_MCS_1_INDEX }, + { S8_MIN, IWL_RATE_MCS_0_INDEX }, +}; + +/* Init the optimal rate based on STA caps + * This combined with rssi is used to report the last tx rate + * to userspace when we haven't transmitted enough frames. + */ +static void rs_init_optimal_rate(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta) +{ + struct rs_rate *rate = &lq_sta->optimal_rate; + + if (lq_sta->max_mimo2_rate_idx != IWL_RATE_INVALID) + rate->type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; + else if (lq_sta->max_siso_rate_idx != IWL_RATE_INVALID) + rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; + else if (lq_sta->band == IEEE80211_BAND_5GHZ) + rate->type = LQ_LEGACY_A; + else + rate->type = LQ_LEGACY_G; + + rate->bw = rs_bw_from_sta_bw(sta); + rate->sgi = rs_sgi_allow(mvm, sta, rate, NULL); + + /* ANT/LDPC/STBC aren't relevant for the rate reported to userspace */ + + if (is_mimo(rate)) { + lq_sta->optimal_rate_mask = lq_sta->active_mimo2_rate; + } else if (is_siso(rate)) { + lq_sta->optimal_rate_mask = lq_sta->active_siso_rate; + } else { + lq_sta->optimal_rate_mask = lq_sta->active_legacy_rate; + + if (lq_sta->band == IEEE80211_BAND_5GHZ) { + lq_sta->optimal_rates = rs_optimal_rates_5ghz_legacy; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_5ghz_legacy); + } else { + lq_sta->optimal_rates = rs_optimal_rates_24ghz_legacy; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_24ghz_legacy); + } + } + + if (is_vht(rate)) { + if (rate->bw == RATE_MCS_CHAN_WIDTH_20) { + lq_sta->optimal_rates = rs_optimal_rates_vht_20mhz; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_vht_20mhz); + } else { + lq_sta->optimal_rates = rs_optimal_rates_vht_40_80mhz; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_vht_40_80mhz); + } + } else if (is_ht(rate)) { + lq_sta->optimal_rates = rs_optimal_rates_ht; + lq_sta->optimal_nentries = ARRAY_SIZE(rs_optimal_rates_ht); + } +} + +/* Compute the optimal rate index based on RSSI */ +static struct rs_rate *rs_get_optimal_rate(struct iwl_mvm *mvm, + struct iwl_lq_sta *lq_sta) +{ + struct rs_rate *rate = &lq_sta->optimal_rate; + int i; + + rate->index = find_first_bit(&lq_sta->optimal_rate_mask, + BITS_PER_LONG); + + for (i = 0; i < lq_sta->optimal_nentries; i++) { + int rate_idx = lq_sta->optimal_rates[i].rate_idx; + + if ((lq_sta->pers.last_rssi >= lq_sta->optimal_rates[i].rssi) && + (BIT(rate_idx) & lq_sta->optimal_rate_mask)) { + rate->index = rate_idx; + break; + } + } + + rs_dump_rate(mvm, rate, "OPTIMAL RATE"); + return rate; +} + /* Choose an initial legacy rate and antenna to use based on the RSSI * of last Rx */ @@ -2468,12 +2586,12 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, if (band == IEEE80211_BAND_5GHZ) { rate->type = LQ_LEGACY_A; - initial_rates = rs_init_rates_5ghz; - nentries = ARRAY_SIZE(rs_init_rates_5ghz); + initial_rates = rs_optimal_rates_5ghz_legacy; + nentries = ARRAY_SIZE(rs_optimal_rates_5ghz_legacy); } else { rate->type = LQ_LEGACY_G; - initial_rates = rs_init_rates_24ghz; - nentries = ARRAY_SIZE(rs_init_rates_24ghz); + initial_rates = rs_optimal_rates_24ghz_legacy; + nentries = ARRAY_SIZE(rs_optimal_rates_24ghz_legacy); } if (IWL_MVM_RS_RSSI_BASED_INIT_RATE) { @@ -2496,10 +2614,21 @@ void rs_update_last_rssi(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_sta, struct ieee80211_rx_status *rx_status) { + int i; + lq_sta->pers.chains = rx_status->chains; lq_sta->pers.chain_signal[0] = rx_status->chain_signal[0]; lq_sta->pers.chain_signal[1] = rx_status->chain_signal[1]; lq_sta->pers.chain_signal[2] = rx_status->chain_signal[2]; + lq_sta->pers.last_rssi = S8_MIN; + + for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) { + if (!(lq_sta->pers.chains & BIT(i))) + continue; + + if (lq_sta->pers.chain_signal[i] > lq_sta->pers.last_rssi) + lq_sta->pers.last_rssi = lq_sta->pers.chain_signal[i]; + } } /** @@ -2538,6 +2667,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rate = &tbl->rate; rs_get_initial_rate(mvm, lq_sta, band, rate); + rs_init_optimal_rate(mvm, sta, lq_sta); WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B); if (rate->ant == ANT_A) @@ -2560,6 +2690,8 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = mvm_sta; + struct rs_rate *optimal_rate; + u32 last_ucode_rate; if (sta && !iwl_mvm_sta_from_mac80211(sta)->vif) { /* if vif isn't initialized mvm doesn't know about @@ -2583,8 +2715,18 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, iwl_mvm_hwrate_to_tx_rate(lq_sta->last_rate_n_flags, info->band, &info->control.rates[0]); - info->control.rates[0].count = 1; + + /* Report the optimal rate based on rssi and STA caps if we haven't + * converged yet (too little traffic) or exploring other modulations + */ + if (lq_sta->rs_state != RS_STATE_STAY_IN_COLUMN) { + optimal_rate = rs_get_optimal_rate(mvm, lq_sta); + last_ucode_rate = ucode_rate_from_rs_rate(mvm, + optimal_rate); + iwl_mvm_hwrate_to_tx_rate(last_ucode_rate, info->band, + &txrc->reported_rate); + } } static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, @@ -2605,6 +2747,7 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, #endif lq_sta->pers.chains = 0; memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal)); + lq_sta->pers.last_rssi = S8_MIN; return &sta_priv->lq_sta; } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 2a3da314305a..81314ad9ebe0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Mobile Communications GmbH * * 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 @@ -316,6 +317,14 @@ struct iwl_lq_sta { u8 max_siso_rate_idx; u8 max_mimo2_rate_idx; + /* Optimal rate based on RSSI and STA caps. + * Used only to reflect link speed to userspace. + */ + struct rs_rate optimal_rate; + unsigned long optimal_rate_mask; + const struct rs_init_rate_info *optimal_rates; + int optimal_nentries; + u8 missed_rate_counter; struct iwl_lq_cmd lq; @@ -341,6 +350,7 @@ struct iwl_lq_sta { #endif u8 chains; s8 chain_signal[IEEE80211_MAX_CHAINS]; + s8 last_rssi; struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; struct iwl_mvm *drv; } pers; -- cgit v1.3-6-gb490 From 1738d60b31d7792516426d62521ec65bff8281f5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 May 2015 12:09:44 +0200 Subject: iwlwifi: mvm: handle RX MPDUs separately There's no need to forward RX MPDUs to notification wait tests, nor do we need to check them for firmware dump triggers, nor could they be asynchronous. It's thus more efficient to handle them separately, before going into the regular RX handlers. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index e4fa50075ffd..8f896cd1c9cd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -221,7 +221,6 @@ struct iwl_rx_handlers { * called from a worker with mvm->mutex held. */ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { - RX_HANDLER(REPLY_RX_MPDU_CMD, iwl_mvm_rx_rx_mpdu, false), RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false), RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false), RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), @@ -716,6 +715,9 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 i; + if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) + return iwl_mvm_rx_rx_mpdu(mvm, rxb, cmd); + iwl_mvm_rx_check_trigger(mvm, pkt); /* -- cgit v1.3-6-gb490 From 6c7d32cfdc622ef4b9f157592fc167513507270d Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 7 Jun 2015 09:34:57 +0300 Subject: iwlwifi: deprecate -10.ucode for 3160 / 7260 / 7265 This firmware is not supported anymore - stop loading this firmware. Remove code handling older versions. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-8000.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index cc35f796d406..fa35da4edda2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -76,7 +76,7 @@ #define IWL3165_UCODE_API_OK 13 /* Lowest firmware API version supported */ -#define IWL7260_UCODE_API_MIN 10 +#define IWL7260_UCODE_API_MIN 12 #define IWL3165_UCODE_API_MIN 13 /* NVM versions */ diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 72040cd0b979..0de575124fa2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -75,7 +75,7 @@ #define IWL8000_UCODE_API_OK 12 /* Lowest firmware API version supported */ -#define IWL8000_UCODE_API_MIN 10 +#define IWL8000_UCODE_API_MIN 12 /* NVM versions */ #define IWL8000_NVM_VERSION 0x0a1d diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index eb10c5ee4a14..a482ce692f5f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -676,8 +676,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } - if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) - iwl_mvm_get_shared_mem_conf(mvm); + iwl_mvm_get_shared_mem_conf(mvm); ret = iwl_mvm_sf_update(mvm, NULL, false); if (ret) -- cgit v1.3-6-gb490 From 012c02c15ac63b0b26c7f058c744e85cb563a737 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 16 Jun 2015 22:37:40 +0300 Subject: iwlwifi: dvm: start HW before running FW The new locking in PCIe transport requires to start_hw before start_fw. This uncovered a bug in dvm which failed to do so. Fix that. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 7acaa266b704..f603fb3122f7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -250,12 +250,24 @@ static int __iwl_up(struct iwl_priv *priv) } } + ret = iwl_trans_start_hw(priv->trans); + if (ret) { + IWL_ERR(priv, "Failed to start HW: %d\n", ret); + goto error; + } + ret = iwl_run_init_ucode(priv); if (ret) { IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret); goto error; } + ret = iwl_trans_start_hw(priv->trans); + if (ret) { + IWL_ERR(priv, "Failed to start HW: %d\n", ret); + goto error; + } + ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR); if (ret) { IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); -- cgit v1.3-6-gb490 From fa9f3281cbb1075545d4528c84059a3f4e117b44 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 11 Jun 2015 20:45:49 +0300 Subject: iwlwifi: pcie: lock start_hw / start_fw / stop_device This allows to ensure that we don't have races between them. A user reported that stop_device was called twice upon rfkill interrupt after suspend. When the interrupts are enabled, and right after when we directly check the rfkill state. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/drv.c | 4 ++ drivers/net/wireless/iwlwifi/pcie/internal.h | 3 + drivers/net/wireless/iwlwifi/pcie/rx.c | 2 + drivers/net/wireless/iwlwifi/pcie/trans.c | 82 ++++++++++++++++++++++++---- 4 files changed, 81 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 2ed1e4d2774d..dbd2a03a0f6d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -613,6 +613,7 @@ static int iwl_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct iwl_trans *trans = pci_get_drvdata(pdev); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill; /* Before you put code here, think about WoWLAN. You cannot check here @@ -643,7 +644,10 @@ static int iwl_pci_resume(struct device *device) } hw_rfkill = iwl_is_rfkill_set(trans); + + mutex_lock(&trans_pcie->mutex); iwl_trans_pcie_rf_kill(trans, hw_rfkill); + mutex_unlock(&trans_pcie->mutex); return 0; } diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 31f72a61cc3f..4f0640767d30 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -301,6 +301,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @scd_set_active: should the transport configure the SCD for HCMD queue * @rx_page_order: page order for receive buffer size * @reg_lock: protect hw register access + * @mutex: to protect stop_device / start_fw / start_hw * @cmd_in_flight: true when we have a host command in flight * @fw_mon_phys: physical address of the buffer for the firmware monitor * @fw_mon_page: points to the first page of the buffer for the firmware monitor @@ -320,9 +321,11 @@ struct iwl_trans_pcie { dma_addr_t ict_tbl_dma; int ict_index; bool use_ict; + bool is_down; struct isr_statistics isr_stats; spinlock_t irq_lock; + struct mutex mutex; u32 inta_mask; u32 scd_base_addr; struct iwl_dma_ptr scd_bc_tbls; diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index a3fbaa0ef5e0..93062f2e8f56 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1251,7 +1251,9 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) isr_stats->rfkill++; + mutex_lock(&trans_pcie->mutex); iwl_trans_pcie_rf_kill(trans, hw_rfkill); + mutex_unlock(&trans_pcie->mutex); 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 43ae658af6ec..23f2824e8d56 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -982,13 +982,25 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, const struct fw_img *fw, bool run_in_rfkill) { - int ret; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill; + int ret; + + mutex_lock(&trans_pcie->mutex); + + /* Someone called stop_device, don't try to start_fw */ + if (trans_pcie->is_down) { + IWL_WARN(trans, + "Can't start_fw since the HW hasn't been started\n"); + ret = EIO; + goto out; + } /* This may fail if AMT took ownership of the device */ if (iwl_pcie_prepare_card_hw(trans)) { IWL_WARN(trans, "Exit HW not ready\n"); - return -EIO; + ret = -EIO; + goto out; } iwl_enable_rfkill_int(trans); @@ -1000,15 +1012,17 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, else clear_bit(STATUS_RFKILL, &trans->status); iwl_trans_pcie_rf_kill(trans, hw_rfkill); - if (hw_rfkill && !run_in_rfkill) - return -ERFKILL; + if (hw_rfkill && !run_in_rfkill) { + ret = -ERFKILL; + goto out; + } iwl_write32(trans, CSR_INT, 0xFFFFFFFF); ret = iwl_pcie_nic_init(trans); if (ret) { IWL_ERR(trans, "Unable to init nic\n"); - return ret; + goto out; } /* make sure rfkill handshake bits are cleared */ @@ -1026,9 +1040,13 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, /* Load the given image to the HW */ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) - return iwl_pcie_load_given_ucode_8000(trans, fw); + ret = iwl_pcie_load_given_ucode_8000(trans, fw); else - return iwl_pcie_load_given_ucode(trans, fw); + ret = iwl_pcie_load_given_ucode(trans, fw); + +out: + mutex_unlock(&trans_pcie->mutex); + return ret; } static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) @@ -1037,11 +1055,18 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) iwl_pcie_tx_start(trans, scd_addr); } -static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) +static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill, was_hw_rfkill; + lockdep_assert_held(&trans_pcie->mutex); + + if (trans_pcie->is_down) + return; + + trans_pcie->is_down = true; + was_hw_rfkill = iwl_is_rfkill_set(trans); /* tell the device to stop sending interrupts */ @@ -1131,10 +1156,24 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) iwl_pcie_prepare_card_hw(trans); } +static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + mutex_lock(&trans_pcie->mutex); + _iwl_trans_pcie_stop_device(trans, low_power); + mutex_unlock(&trans_pcie->mutex); +} + void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) { + struct iwl_trans_pcie __maybe_unused *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + lockdep_assert_held(&trans_pcie->mutex); + if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) - iwl_trans_pcie_stop_device(trans, true); + _iwl_trans_pcie_stop_device(trans, true); } static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) @@ -1219,11 +1258,14 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, return 0; } -static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill; int err; + lockdep_assert_held(&trans_pcie->mutex); + err = iwl_pcie_prepare_card_hw(trans); if (err) { IWL_ERR(trans, "Error while preparing HW: %d\n", err); @@ -1240,20 +1282,38 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) /* From now on, the op_mode will be kept updated about RF kill state */ iwl_enable_rfkill_int(trans); + /* Set is_down to false here so that...*/ + trans_pcie->is_down = false; + hw_rfkill = iwl_is_rfkill_set(trans); if (hw_rfkill) set_bit(STATUS_RFKILL, &trans->status); else clear_bit(STATUS_RFKILL, &trans->status); + /* ... rfkill can call stop_device and set it false if needed */ iwl_trans_pcie_rf_kill(trans, hw_rfkill); return 0; } +static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; + + mutex_lock(&trans_pcie->mutex); + ret = _iwl_trans_pcie_start_hw(trans, low_power); + mutex_unlock(&trans_pcie->mutex); + + return ret; +} + static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + mutex_lock(&trans_pcie->mutex); + /* disable interrupts - don't enable HW RF kill interrupt */ spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); @@ -1266,6 +1326,7 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) spin_unlock(&trans_pcie->irq_lock); iwl_pcie_disable_ict(trans); + mutex_unlock(&trans_pcie->mutex); } static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) @@ -2472,6 +2533,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, spin_lock_init(&trans_pcie->irq_lock); spin_lock_init(&trans_pcie->reg_lock); spin_lock_init(&trans_pcie->ref_lock); + mutex_init(&trans_pcie->mutex); init_waitqueue_head(&trans_pcie->ucode_write_waitq); err = pci_enable_device(pdev); -- cgit v1.3-6-gb490 From 5b7e4c9ce19038f88828309a0a61f5d5c6686d37 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:03 +0300 Subject: drm/i915/gtt: Mark TLBS dirty for gen8+ When we touch gen8+ page maps, mark them dirty like we do with previous gens. v2: Update comment (Joonas) Signed-off-by: Mika Kuoppala Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 2279e030570c..bc4106375650 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -831,6 +831,16 @@ err_out: return -ENOMEM; } +/* PDE TLBs are a pain to invalidate on GEN8+. When we modify + * the page table structures, we mark them dirty so that + * context switching/execlist queuing code takes extra steps + * to ensure that tlbs are flushed. + */ +static void mark_tlbs_dirty(struct i915_hw_ppgtt *ppgtt) +{ + ppgtt->pd_dirty_rings = INTEL_INFO(ppgtt->base.dev)->ring_mask; +} + static int gen8_alloc_va_range(struct i915_address_space *vm, uint64_t start, uint64_t length) @@ -916,6 +926,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, } free_gen8_temp_bitmaps(new_page_dirs, new_page_tables); + mark_tlbs_dirty(ppgtt); return 0; err_out: @@ -928,6 +939,7 @@ err_out: unmap_and_free_pd(ppgtt->pdp.page_directory[pdpe], vm->dev); free_gen8_temp_bitmaps(new_page_dirs, new_page_tables); + mark_tlbs_dirty(ppgtt); return ret; } @@ -1272,16 +1284,6 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, kunmap_atomic(pt_vaddr); } -/* PDE TLBs are a pain invalidate pre GEN8. It requires a context reload. If we - * are switching between contexts with the same LRCA, we also must do a force - * restore. - */ -static void mark_tlbs_dirty(struct i915_hw_ppgtt *ppgtt) -{ - /* If current vm != vm, */ - ppgtt->pd_dirty_rings = INTEL_INFO(ppgtt->base.dev)->ring_mask; -} - static void gen6_initialize_pt(struct i915_address_space *vm, struct i915_page_table *pt) { -- cgit v1.3-6-gb490 From a05d80eec27460a2dca06676d489637e25f93caf Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:04 +0300 Subject: drm/i915/gtt: Check va range against vm size Check the allocation area against the known end of address space instead of against fixed value. v2: Return ENODEV on internal bugs (Chris) Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index bc4106375650..68705e381ada 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -757,9 +757,6 @@ static int gen8_ppgtt_alloc_page_directories(struct i915_hw_ppgtt *ppgtt, WARN_ON(!bitmap_empty(new_pds, GEN8_LEGACY_PDPES)); - /* FIXME: upper bound must not overflow 32 bits */ - WARN_ON((start + length) > (1ULL << 32)); - gen8_for_each_pdpe(pd, pdp, start, length, temp, pdpe) { if (pd) continue; @@ -859,7 +856,10 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, * actually use the other side of the canonical address space. */ if (WARN_ON(start + length < start)) - return -ERANGE; + return -ENODEV; + + if (WARN_ON(start + length > ppgtt->base.total)) + return -ENODEV; ret = alloc_gen8_temp_bitmaps(&new_page_dirs, &new_page_tables); if (ret) @@ -1304,7 +1304,7 @@ static void gen6_initialize_pt(struct i915_address_space *vm, } static int gen6_alloc_va_range(struct i915_address_space *vm, - uint64_t start, uint64_t length) + uint64_t start_in, uint64_t length_in) { DECLARE_BITMAP(new_page_tables, I915_PDES); struct drm_device *dev = vm->dev; @@ -1312,11 +1312,15 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, struct i915_hw_ppgtt *ppgtt = container_of(vm, struct i915_hw_ppgtt, base); struct i915_page_table *pt; - const uint32_t start_save = start, length_save = length; + uint32_t start, length, start_save, length_save; uint32_t pde, temp; int ret; - WARN_ON(upper_32_bits(start)); + if (WARN_ON(start_in + length_in > ppgtt->base.total)) + return -ENODEV; + + start = start_save = start_in; + length = length_save = length_in; bitmap_zero(new_page_tables, I915_PDES); -- cgit v1.3-6-gb490 From c44ef60e437019b8ca1dab8b4d2e8761fd4ce1e9 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:05 +0300 Subject: drm/i915/gtt: Allow >= 4GB sizes for vm. We can have exactly 4GB sized ppgtt with 32bit system. size_t is inadequate for this. v2: Convert a lot more places (Daniel) Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/char/agp/intel-gtt.c | 4 ++-- drivers/gpu/drm/i915/i915_debugfs.c | 42 ++++++++++++++++++------------------- drivers/gpu/drm/i915/i915_gem.c | 6 +++--- drivers/gpu/drm/i915/i915_gem_gtt.c | 22 +++++++++---------- drivers/gpu/drm/i915/i915_gem_gtt.h | 12 +++++------ include/drm/intel-gtt.h | 4 ++-- 6 files changed, 45 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 0b4188b9af7c..4734d02ca899 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1408,8 +1408,8 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, } EXPORT_SYMBOL(intel_gmch_probe); -void intel_gtt_get(size_t *gtt_total, size_t *stolen_size, - phys_addr_t *mappable_base, unsigned long *mappable_end) +void intel_gtt_get(u64 *gtt_total, size_t *stolen_size, + phys_addr_t *mappable_base, u64 *mappable_end) { *gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT; *stolen_size = intel_private.stolen_size; diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 495a6376cf39..bd0fbd6caac2 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -198,7 +198,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) struct drm_i915_private *dev_priv = dev->dev_private; struct i915_address_space *vm = &dev_priv->gtt.base; struct i915_vma *vma; - size_t total_obj_size, total_gtt_size; + u64 total_obj_size, total_gtt_size; int count, ret; ret = mutex_lock_interruptible(&dev->struct_mutex); @@ -231,7 +231,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) } mutex_unlock(&dev->struct_mutex); - seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n", + seq_printf(m, "Total %d objects, %llu bytes, %llu GTT size\n", count, total_obj_size, total_gtt_size); return 0; } @@ -253,7 +253,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; - size_t total_obj_size, total_gtt_size; + u64 total_obj_size, total_gtt_size; LIST_HEAD(stolen); int count, ret; @@ -292,7 +292,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) } mutex_unlock(&dev->struct_mutex); - seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n", + seq_printf(m, "Total %d objects, %llu bytes, %llu GTT size\n", count, total_obj_size, total_gtt_size); return 0; } @@ -310,10 +310,10 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) struct file_stats { struct drm_i915_file_private *file_priv; - int count; - size_t total, unbound; - size_t global, shared; - size_t active, inactive; + unsigned long count; + u64 total, unbound; + u64 global, shared; + u64 active, inactive; }; static int per_file_stats(int id, void *ptr, void *data) @@ -370,7 +370,7 @@ static int per_file_stats(int id, void *ptr, void *data) #define print_file_stats(m, name, stats) do { \ if (stats.count) \ - seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n", \ + seq_printf(m, "%s: %lu objects, %llu bytes (%llu active, %llu inactive, %llu global, %llu shared, %llu unbound)\n", \ name, \ stats.count, \ stats.total, \ @@ -420,7 +420,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 count, mappable_count, purgeable_count; - size_t size, mappable_size, purgeable_size; + u64 size, mappable_size, purgeable_size; struct drm_i915_gem_object *obj; struct i915_address_space *vm = &dev_priv->gtt.base; struct drm_file *file; @@ -437,17 +437,17 @@ static int i915_gem_object_info(struct seq_file *m, void* data) size = count = mappable_size = mappable_count = 0; count_objects(&dev_priv->mm.bound_list, global_list); - seq_printf(m, "%u [%u] objects, %zu [%zu] bytes in gtt\n", + seq_printf(m, "%u [%u] objects, %llu [%llu] bytes in gtt\n", count, mappable_count, size, mappable_size); size = count = mappable_size = mappable_count = 0; count_vmas(&vm->active_list, mm_list); - seq_printf(m, " %u [%u] active objects, %zu [%zu] bytes\n", + seq_printf(m, " %u [%u] active objects, %llu [%llu] bytes\n", count, mappable_count, size, mappable_size); size = count = mappable_size = mappable_count = 0; count_vmas(&vm->inactive_list, mm_list); - seq_printf(m, " %u [%u] inactive objects, %zu [%zu] bytes\n", + seq_printf(m, " %u [%u] inactive objects, %llu [%llu] bytes\n", count, mappable_count, size, mappable_size); size = count = purgeable_size = purgeable_count = 0; @@ -456,7 +456,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) if (obj->madv == I915_MADV_DONTNEED) purgeable_size += obj->base.size, ++purgeable_count; } - seq_printf(m, "%u unbound objects, %zu bytes\n", count, size); + seq_printf(m, "%u unbound objects, %llu bytes\n", count, size); size = count = mappable_size = mappable_count = 0; list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { @@ -473,16 +473,16 @@ static int i915_gem_object_info(struct seq_file *m, void* data) ++purgeable_count; } } - seq_printf(m, "%u purgeable objects, %zu bytes\n", + seq_printf(m, "%u purgeable objects, %llu bytes\n", purgeable_count, purgeable_size); - seq_printf(m, "%u pinned mappable objects, %zu bytes\n", + seq_printf(m, "%u pinned mappable objects, %llu bytes\n", mappable_count, mappable_size); - seq_printf(m, "%u fault mappable objects, %zu bytes\n", + seq_printf(m, "%u fault mappable objects, %llu bytes\n", count, size); - seq_printf(m, "%zu [%lu] gtt total\n", + seq_printf(m, "%llu [%llu] gtt total\n", dev_priv->gtt.base.total, - dev_priv->gtt.mappable_end - dev_priv->gtt.base.start); + (u64)dev_priv->gtt.mappable_end - dev_priv->gtt.base.start); seq_putc(m, '\n'); print_batch_pool_stats(m, dev_priv); @@ -519,7 +519,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data) uintptr_t list = (uintptr_t) node->info_ent->data; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; - size_t total_obj_size, total_gtt_size; + u64 total_obj_size, total_gtt_size; int count, ret; ret = mutex_lock_interruptible(&dev->struct_mutex); @@ -541,7 +541,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data) mutex_unlock(&dev->struct_mutex); - seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n", + seq_printf(m, "Total %d objects, %llu bytes, %llu GTT size\n", count, total_obj_size, total_gtt_size); return 0; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f79ce9f22312..db1955fad005 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3712,9 +3712,9 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 size, fence_size, fence_alignment, unfenced_alignment; - unsigned long start = + u64 start = flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0; - unsigned long end = + u64 end = flags & PIN_MAPPABLE ? dev_priv->gtt.mappable_end : vm->total; struct i915_vma *vma; int ret; @@ -3770,7 +3770,7 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, * attempt to find space. */ if (size > end) { - DRM_DEBUG("Attempting to bind an object (view type=%u) larger than the aperture: size=%u > %s aperture=%lu\n", + DRM_DEBUG("Attempting to bind an object (view type=%u) larger than the aperture: size=%u > %s aperture=%llu\n", ggtt_view ? ggtt_view->type : 0, size, flags & PIN_MAPPABLE ? "mappable" : "total", diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 68705e381ada..7a7789e18f38 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2112,7 +2112,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev, void i915_gem_init_global_gtt(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long gtt_size, mappable_size; + u64 gtt_size, mappable_size; gtt_size = dev_priv->gtt.base.total; mappable_size = dev_priv->gtt.mappable_end; @@ -2369,13 +2369,13 @@ static void chv_setup_private_ppat(struct drm_i915_private *dev_priv) } static int gen8_gmch_probe(struct drm_device *dev, - size_t *gtt_total, + u64 *gtt_total, size_t *stolen, phys_addr_t *mappable_base, - unsigned long *mappable_end) + u64 *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned int gtt_size; + u64 gtt_size; u16 snb_gmch_ctl; int ret; @@ -2417,10 +2417,10 @@ static int gen8_gmch_probe(struct drm_device *dev, } static int gen6_gmch_probe(struct drm_device *dev, - size_t *gtt_total, + u64 *gtt_total, size_t *stolen, phys_addr_t *mappable_base, - unsigned long *mappable_end) + u64 *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned int gtt_size; @@ -2434,7 +2434,7 @@ static int gen6_gmch_probe(struct drm_device *dev, * a coarse sanity check. */ if ((*mappable_end < (64<<20) || (*mappable_end > (512<<20)))) { - DRM_ERROR("Unknown GMADR size (%lx)\n", + DRM_ERROR("Unknown GMADR size (%llx)\n", dev_priv->gtt.mappable_end); return -ENXIO; } @@ -2468,10 +2468,10 @@ static void gen6_gmch_remove(struct i915_address_space *vm) } static int i915_gmch_probe(struct drm_device *dev, - size_t *gtt_total, + u64 *gtt_total, size_t *stolen, phys_addr_t *mappable_base, - unsigned long *mappable_end) + u64 *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; int ret; @@ -2536,9 +2536,9 @@ int i915_gem_gtt_init(struct drm_device *dev) gtt->base.dev = dev; /* GMADR is the PCI mmio aperture into the global GTT. */ - DRM_INFO("Memory usable by graphics device = %zdM\n", + DRM_INFO("Memory usable by graphics device = %lluM\n", gtt->base.total >> 20); - DRM_DEBUG_DRIVER("GMADR size = %ldM\n", gtt->mappable_end >> 20); + DRM_DEBUG_DRIVER("GMADR size = %lldM\n", gtt->mappable_end >> 20); DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", gtt->stolen_size >> 20); #ifdef CONFIG_INTEL_IOMMU if (intel_iommu_gfx_mapped) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 017ea308f8b4..600eec00a1f4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -235,8 +235,8 @@ struct i915_address_space { struct drm_mm mm; struct drm_device *dev; struct list_head global_link; - unsigned long start; /* Start offset always 0 for dri2 */ - size_t total; /* size addr space maps (ex. 2GB for ggtt) */ + u64 start; /* Start offset always 0 for dri2 */ + u64 total; /* size addr space maps (ex. 2GB for ggtt) */ struct { dma_addr_t addr; @@ -302,9 +302,9 @@ struct i915_address_space { */ struct i915_gtt { struct i915_address_space base; - size_t stolen_size; /* Total size of stolen memory */ - unsigned long mappable_end; /* End offset that we can CPU map */ + size_t stolen_size; /* Total size of stolen memory */ + u64 mappable_end; /* End offset that we can CPU map */ struct io_mapping *mappable; /* Mapping to our CPU mappable region */ phys_addr_t mappable_base; /* PA of our GMADR */ @@ -316,9 +316,9 @@ struct i915_gtt { int mtrr; /* global gtt ops */ - int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total, + int (*gtt_probe)(struct drm_device *dev, u64 *gtt_total, size_t *stolen, phys_addr_t *mappable_base, - unsigned long *mappable_end); + u64 *mappable_end); }; struct i915_hw_ppgtt { diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index b08bdade6002..9e9bddaa58a5 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -3,8 +3,8 @@ #ifndef _DRM_INTEL_GTT_H #define _DRM_INTEL_GTT_H -void intel_gtt_get(size_t *gtt_total, size_t *stolen_size, - phys_addr_t *mappable_base, unsigned long *mappable_end); +void intel_gtt_get(u64 *gtt_total, size_t *stolen_size, + phys_addr_t *mappable_base, u64 *mappable_end); int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, struct agp_bridge_data *bridge); -- cgit v1.3-6-gb490 From d852c7bf902aa36f37b6fd0bb1147c922e7bd0fb Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:06 +0300 Subject: drm/i915/gtt: Introduce i915_page_dir_dma_addr The legacy mode mm switch and the execlist context assignment needs dma address for the page directories. Introduce a function that encapsulates the scratch_pd dma fallback if no pd is found. v2: Rebase, s/ring/req Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 ++---- drivers/gpu/drm/i915/i915_gem_gtt.h | 8 ++++++++ drivers/gpu/drm/i915/intel_lrc.c | 4 +--- 3 files changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 7a7789e18f38..47e8e2eec26d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -482,10 +482,8 @@ static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt, int i, ret; for (i = GEN8_LEGACY_PDPES - 1; i >= 0; i--) { - struct i915_page_directory *pd = ppgtt->pdp.page_directory[i]; - dma_addr_t pd_daddr = pd ? pd->daddr : ppgtt->scratch_pd->daddr; - /* The page directory might be NULL, but we need to clear out - * whatever the previous context might have used. */ + const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i); + ret = gen8_write_pdp(req, i, pd_daddr); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 600eec00a1f4..f368c7155223 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -470,6 +470,14 @@ static inline size_t gen8_pte_count(uint64_t address, uint64_t length) return i915_pte_count(address, length, GEN8_PDE_SHIFT); } +static inline dma_addr_t +i915_page_dir_dma_addr(const struct i915_hw_ppgtt *ppgtt, const unsigned n) +{ + return test_bit(n, ppgtt->pdp.used_pdpes) ? + ppgtt->pdp.page_directory[n]->daddr : + ppgtt->scratch_pd->daddr; +} + int i915_gem_gtt_init(struct drm_device *dev); void i915_gem_init_global_gtt(struct drm_device *dev); void i915_global_gtt_cleanup(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 90a02dc5245e..fd25314fc913 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -190,9 +190,7 @@ #define GEN8_CTX_PRIVILEGE (1<<8) #define ASSIGN_CTX_PDP(ppgtt, reg_state, n) { \ - const u64 _addr = test_bit(n, ppgtt->pdp.used_pdpes) ? \ - ppgtt->pdp.page_directory[n]->daddr : \ - ppgtt->scratch_pd->daddr; \ + const u64 _addr = i915_page_dir_dma_addr((ppgtt), (n)); \ reg_state[CTX_PDP ## n ## _UDW+1] = upper_32_bits(_addr); \ reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \ } -- cgit v1.3-6-gb490 From 44159ddbeac3d34e5ca9037e151a242b7388df8e Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:07 +0300 Subject: drm/i915/gtt: Introduce struct i915_page_dma All our paging structures have struct page and dma address for that page. Add struct for page/dma address pairs and use it to make the setup and teardown for different paging structures identical. Include the page directory offset also in the struct for legacy gens. Rename it to clearly point out that it is offset into the ggtt. v2: Add comment about ggtt_offset (Michel) Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 120 ++++++++++++++---------------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 25 +++++--- 3 files changed, 64 insertions(+), 83 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index bd0fbd6caac2..b509844df0dd 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2227,7 +2227,7 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev) struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; seq_puts(m, "aliasing PPGTT:\n"); - seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd.pd_offset); + seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd.base.ggtt_offset); ppgtt->debug_dump(ppgtt, m); } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 47e8e2eec26d..a7bdbeb46904 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -301,52 +301,39 @@ static gen6_pte_t iris_pte_encode(dma_addr_t addr, return pte; } -#define i915_dma_unmap_single(px, dev) \ - __i915_dma_unmap_single((px)->daddr, dev) - -static void __i915_dma_unmap_single(dma_addr_t daddr, - struct drm_device *dev) +static int setup_page_dma(struct drm_device *dev, struct i915_page_dma *p) { struct device *device = &dev->pdev->dev; - dma_unmap_page(device, daddr, 4096, PCI_DMA_BIDIRECTIONAL); -} - -/** - * i915_dma_map_single() - Create a dma mapping for a page table/dir/etc. - * @px: Page table/dir/etc to get a DMA map for - * @dev: drm device - * - * Page table allocations are unified across all gens. They always require a - * single 4k allocation, as well as a DMA mapping. If we keep the structs - * symmetric here, the simple macro covers us for every page table type. - * - * Return: 0 if success. - */ -#define i915_dma_map_single(px, dev) \ - i915_dma_map_page_single((px)->page, (dev), &(px)->daddr) + p->page = alloc_page(GFP_KERNEL); + if (!p->page) + return -ENOMEM; -static int i915_dma_map_page_single(struct page *page, - struct drm_device *dev, - dma_addr_t *daddr) -{ - struct device *device = &dev->pdev->dev; + p->daddr = dma_map_page(device, + p->page, 0, 4096, PCI_DMA_BIDIRECTIONAL); - *daddr = dma_map_page(device, page, 0, 4096, PCI_DMA_BIDIRECTIONAL); - if (dma_mapping_error(device, *daddr)) - return -ENOMEM; + if (dma_mapping_error(device, p->daddr)) { + __free_page(p->page); + return -EINVAL; + } return 0; } -static void unmap_and_free_pt(struct i915_page_table *pt, - struct drm_device *dev) +static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p) { - if (WARN_ON(!pt->page)) + if (WARN_ON(!p->page)) return; - i915_dma_unmap_single(pt, dev); - __free_page(pt->page); + dma_unmap_page(&dev->pdev->dev, p->daddr, 4096, PCI_DMA_BIDIRECTIONAL); + __free_page(p->page); + memset(p, 0, sizeof(*p)); +} + +static void unmap_and_free_pt(struct i915_page_table *pt, + struct drm_device *dev) +{ + cleanup_page_dma(dev, &pt->base); kfree(pt->used_ptes); kfree(pt); } @@ -357,7 +344,7 @@ static void gen8_initialize_pt(struct i915_address_space *vm, gen8_pte_t *pt_vaddr, scratch_pte; int i; - pt_vaddr = kmap_atomic(pt->page); + pt_vaddr = kmap_atomic(pt->base.page); scratch_pte = gen8_pte_encode(vm->scratch.addr, I915_CACHE_LLC, true); @@ -386,19 +373,13 @@ static struct i915_page_table *alloc_pt(struct drm_device *dev) if (!pt->used_ptes) goto fail_bitmap; - pt->page = alloc_page(GFP_KERNEL); - if (!pt->page) - goto fail_page; - - ret = i915_dma_map_single(pt, dev); + ret = setup_page_dma(dev, &pt->base); if (ret) - goto fail_dma; + goto fail_page_m; return pt; -fail_dma: - __free_page(pt->page); -fail_page: +fail_page_m: kfree(pt->used_ptes); fail_bitmap: kfree(pt); @@ -409,9 +390,8 @@ fail_bitmap: static void unmap_and_free_pd(struct i915_page_directory *pd, struct drm_device *dev) { - if (pd->page) { - i915_dma_unmap_single(pd, dev); - __free_page(pd->page); + if (pd->base.page) { + cleanup_page_dma(dev, &pd->base); kfree(pd->used_pdes); kfree(pd); } @@ -431,18 +411,12 @@ static struct i915_page_directory *alloc_pd(struct drm_device *dev) if (!pd->used_pdes) goto free_pd; - pd->page = alloc_page(GFP_KERNEL); - if (!pd->page) - goto free_bitmap; - - ret = i915_dma_map_single(pd, dev); + ret = setup_page_dma(dev, &pd->base); if (ret) - goto free_page; + goto free_bitmap; return pd; -free_page: - __free_page(pd->page); free_bitmap: kfree(pd->used_pdes); free_pd: @@ -524,10 +498,10 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, pt = pd->page_table[pde]; - if (WARN_ON(!pt->page)) + if (WARN_ON(!pt->base.page)) continue; - page_table = pt->page; + page_table = pt->base.page; last_pte = pte + num_entries; if (last_pte > GEN8_PTES) @@ -574,7 +548,7 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, if (pt_vaddr == NULL) { struct i915_page_directory *pd = ppgtt->pdp.page_directory[pdpe]; struct i915_page_table *pt = pd->page_table[pde]; - struct page *page_table = pt->page; + struct page *page_table = pt->base.page; pt_vaddr = kmap_atomic(page_table); } @@ -606,7 +580,7 @@ static void __gen8_do_map_pt(gen8_pde_t * const pde, struct drm_device *dev) { gen8_pde_t entry = - gen8_pde_encode(dev, pt->daddr, I915_CACHE_LLC); + gen8_pde_encode(dev, pt->base.daddr, I915_CACHE_LLC); *pde = entry; } @@ -619,7 +593,7 @@ static void gen8_initialize_pd(struct i915_address_space *vm, struct i915_page_table *pt; int i; - page_directory = kmap_atomic(pd->page); + page_directory = kmap_atomic(pd->base.page); pt = ppgtt->scratch_pt; for (i = 0; i < I915_PDES; i++) /* Map the PDE to the page table */ @@ -634,7 +608,7 @@ static void gen8_free_page_tables(struct i915_page_directory *pd, struct drm_dev { int i; - if (!pd->page) + if (!pd->base.page) return; for_each_set_bit(i, pd->used_pdes, I915_PDES) { @@ -885,7 +859,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, /* Allocations have completed successfully, so set the bitmaps, and do * the mappings. */ gen8_for_each_pdpe(pd, &ppgtt->pdp, start, length, temp, pdpe) { - gen8_pde_t *const page_directory = kmap_atomic(pd->page); + gen8_pde_t *const page_directory = kmap_atomic(pd->base.page); struct i915_page_table *pt; uint64_t pd_len = gen8_clamp_pd(start, length); uint64_t pd_start = start; @@ -996,7 +970,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde) { u32 expected; gen6_pte_t *pt_vaddr; - dma_addr_t pt_addr = ppgtt->pd.page_table[pde]->daddr; + dma_addr_t pt_addr = ppgtt->pd.page_table[pde]->base.daddr; pd_entry = readl(ppgtt->pd_addr + pde); expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID); @@ -1007,7 +981,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) expected); seq_printf(m, "\tPDE: %x\n", pd_entry); - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[pde]->page); + pt_vaddr = kmap_atomic(ppgtt->pd.page_table[pde]->base.page); for (pte = 0; pte < GEN6_PTES; pte+=4) { unsigned long va = (pde * PAGE_SIZE * GEN6_PTES) + @@ -1042,7 +1016,7 @@ static void gen6_write_pde(struct i915_page_directory *pd, container_of(pd, struct i915_hw_ppgtt, pd); u32 pd_entry; - pd_entry = GEN6_PDE_ADDR_ENCODE(pt->daddr); + pd_entry = GEN6_PDE_ADDR_ENCODE(pt->base.daddr); pd_entry |= GEN6_PDE_VALID; writel(pd_entry, ppgtt->pd_addr + pde); @@ -1067,9 +1041,9 @@ static void gen6_write_page_range(struct drm_i915_private *dev_priv, static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt) { - BUG_ON(ppgtt->pd.pd_offset & 0x3f); + BUG_ON(ppgtt->pd.base.ggtt_offset & 0x3f); - return (ppgtt->pd.pd_offset / 64) << 16; + return (ppgtt->pd.base.ggtt_offset / 64) << 16; } static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, @@ -1236,7 +1210,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm, if (last_pte > GEN6_PTES) last_pte = GEN6_PTES; - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->page); + pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->base.page); for (i = first_pte; i < last_pte; i++) pt_vaddr[i] = scratch_pte; @@ -1265,7 +1239,7 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, pt_vaddr = NULL; for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { if (pt_vaddr == NULL) - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->page); + pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->base.page); pt_vaddr[act_pte] = vm->pte_encode(sg_page_iter_dma_address(&sg_iter), @@ -1293,7 +1267,7 @@ static void gen6_initialize_pt(struct i915_address_space *vm, scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); - pt_vaddr = kmap_atomic(pt->page); + pt_vaddr = kmap_atomic(pt->base.page); for (i = 0; i < GEN6_PTES; i++) pt_vaddr[i] = scratch_pte; @@ -1509,11 +1483,11 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.total = I915_PDES * GEN6_PTES * PAGE_SIZE; ppgtt->debug_dump = gen6_dump_ppgtt; - ppgtt->pd.pd_offset = + ppgtt->pd.base.ggtt_offset = ppgtt->node.start / PAGE_SIZE * sizeof(gen6_pte_t); ppgtt->pd_addr = (gen6_pte_t __iomem *)dev_priv->gtt.gsm + - ppgtt->pd.pd_offset / sizeof(gen6_pte_t); + ppgtt->pd.base.ggtt_offset / sizeof(gen6_pte_t); gen6_scratch_va_range(ppgtt, 0, ppgtt->base.total); @@ -1524,7 +1498,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->node.start / PAGE_SIZE); DRM_DEBUG("Adding PPGTT at offset %x\n", - ppgtt->pd.pd_offset << 10); + ppgtt->pd.base.ggtt_offset << 10); return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index f368c7155223..c681573b4005 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -207,19 +207,26 @@ struct i915_vma { #define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf }; -struct i915_page_table { +struct i915_page_dma { struct page *page; - dma_addr_t daddr; + union { + dma_addr_t daddr; + + /* For gen6/gen7 only. This is the offset in the GGTT + * where the page directory entries for PPGTT begin + */ + uint32_t ggtt_offset; + }; +}; + +struct i915_page_table { + struct i915_page_dma base; unsigned long *used_ptes; }; struct i915_page_directory { - struct page *page; /* NULL for GEN6-GEN7 */ - union { - uint32_t pd_offset; - dma_addr_t daddr; - }; + struct i915_page_dma base; unsigned long *used_pdes; struct i915_page_table *page_table[I915_PDES]; /* PDEs */ @@ -474,8 +481,8 @@ static inline dma_addr_t i915_page_dir_dma_addr(const struct i915_hw_ppgtt *ppgtt, const unsigned n) { return test_bit(n, ppgtt->pdp.used_pdpes) ? - ppgtt->pdp.page_directory[n]->daddr : - ppgtt->scratch_pd->daddr; + ppgtt->pdp.page_directory[n]->base.daddr : + ppgtt->scratch_pd->base.daddr; } int i915_gem_gtt_init(struct drm_device *dev); -- cgit v1.3-6-gb490 From a08e111a6cc88514155b087e0c307581064352b5 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:08 +0300 Subject: drm/i915/gtt: Rename unmap_and_free_px to free_px All the paging structures are now similar and mapped for dma. The unmapping is taken care of by common accessors, so don't overload the reader with such details. v2: Be consistent with goto labels (Michel) Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 40 ++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a7bdbeb46904..82ccc69a4a23 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -330,8 +330,7 @@ static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p) memset(p, 0, sizeof(*p)); } -static void unmap_and_free_pt(struct i915_page_table *pt, - struct drm_device *dev) +static void free_pt(struct drm_device *dev, struct i915_page_table *pt) { cleanup_page_dma(dev, &pt->base); kfree(pt->used_ptes); @@ -387,8 +386,7 @@ fail_bitmap: return ERR_PTR(ret); } -static void unmap_and_free_pd(struct i915_page_directory *pd, - struct drm_device *dev) +static void free_pd(struct drm_device *dev, struct i915_page_directory *pd) { if (pd->base.page) { cleanup_page_dma(dev, &pd->base); @@ -409,17 +407,17 @@ static struct i915_page_directory *alloc_pd(struct drm_device *dev) pd->used_pdes = kcalloc(BITS_TO_LONGS(I915_PDES), sizeof(*pd->used_pdes), GFP_KERNEL); if (!pd->used_pdes) - goto free_pd; + goto fail_bitmap; ret = setup_page_dma(dev, &pd->base); if (ret) - goto free_bitmap; + goto fail_page_m; return pd; -free_bitmap: +fail_page_m: kfree(pd->used_pdes); -free_pd: +fail_bitmap: kfree(pd); return ERR_PTR(ret); @@ -615,7 +613,7 @@ static void gen8_free_page_tables(struct i915_page_directory *pd, struct drm_dev if (WARN_ON(!pd->page_table[i])) continue; - unmap_and_free_pt(pd->page_table[i], dev); + free_pt(dev, pd->page_table[i]); pd->page_table[i] = NULL; } } @@ -631,11 +629,11 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) continue; gen8_free_page_tables(ppgtt->pdp.page_directory[i], ppgtt->base.dev); - unmap_and_free_pd(ppgtt->pdp.page_directory[i], ppgtt->base.dev); + free_pd(ppgtt->base.dev, ppgtt->pdp.page_directory[i]); } - unmap_and_free_pd(ppgtt->scratch_pd, ppgtt->base.dev); - unmap_and_free_pt(ppgtt->scratch_pt, ppgtt->base.dev); + free_pd(ppgtt->base.dev, ppgtt->scratch_pd); + free_pt(ppgtt->base.dev, ppgtt->scratch_pt); } /** @@ -688,7 +686,7 @@ static int gen8_ppgtt_alloc_pagetabs(struct i915_hw_ppgtt *ppgtt, unwind_out: for_each_set_bit(pde, new_pts, I915_PDES) - unmap_and_free_pt(pd->page_table[pde], dev); + free_pt(dev, pd->page_table[pde]); return -ENOMEM; } @@ -746,7 +744,7 @@ static int gen8_ppgtt_alloc_page_directories(struct i915_hw_ppgtt *ppgtt, unwind_out: for_each_set_bit(pdpe, new_pds, GEN8_LEGACY_PDPES) - unmap_and_free_pd(pdp->page_directory[pdpe], dev); + free_pd(dev, pdp->page_directory[pdpe]); return -ENOMEM; } @@ -904,11 +902,11 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, err_out: while (pdpe--) { for_each_set_bit(temp, new_page_tables[pdpe], I915_PDES) - unmap_and_free_pt(ppgtt->pdp.page_directory[pdpe]->page_table[temp], vm->dev); + free_pt(vm->dev, ppgtt->pdp.page_directory[pdpe]->page_table[temp]); } for_each_set_bit(pdpe, new_page_dirs, GEN8_LEGACY_PDPES) - unmap_and_free_pd(ppgtt->pdp.page_directory[pdpe], vm->dev); + free_pd(vm->dev, ppgtt->pdp.page_directory[pdpe]); free_gen8_temp_bitmaps(new_page_dirs, new_page_tables); mark_tlbs_dirty(ppgtt); @@ -1358,7 +1356,7 @@ unwind_out: struct i915_page_table *pt = ppgtt->pd.page_table[pde]; ppgtt->pd.page_table[pde] = ppgtt->scratch_pt; - unmap_and_free_pt(pt, vm->dev); + free_pt(vm->dev, pt); } mark_tlbs_dirty(ppgtt); @@ -1377,11 +1375,11 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) gen6_for_all_pdes(pt, ppgtt, pde) { if (pt != ppgtt->scratch_pt) - unmap_and_free_pt(pt, ppgtt->base.dev); + free_pt(ppgtt->base.dev, pt); } - unmap_and_free_pt(ppgtt->scratch_pt, ppgtt->base.dev); - unmap_and_free_pd(&ppgtt->pd, ppgtt->base.dev); + free_pt(ppgtt->base.dev, ppgtt->scratch_pt); + free_pd(ppgtt->base.dev, &ppgtt->pd); } static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) @@ -1431,7 +1429,7 @@ alloc: return 0; err_out: - unmap_and_free_pt(ppgtt->scratch_pt, ppgtt->base.dev); + free_pt(ppgtt->base.dev, ppgtt->scratch_pt); return ret; } -- cgit v1.3-6-gb490 From cee30c5439f5c9569ac9260b6e6968faf19cc575 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:09 +0300 Subject: drm/i915/gtt: Remove superfluous free_pd with gen6/7 This has slipped in somewhere but it was harmless as we check the page pointer before teardown. Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 82ccc69a4a23..21fba03dcd62 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1379,7 +1379,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) } free_pt(ppgtt->base.dev, ppgtt->scratch_pt); - free_pd(ppgtt->base.dev, &ppgtt->pd); } static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) -- cgit v1.3-6-gb490 From 73eeea537b1bb9c53c9e406a16354f6bc9b2be62 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:10 +0300 Subject: drm/i915/gtt: Introduce fill_page_dma() When we setup page directories and tables, we point the entries to a to the next level scratch structure. Make this generic by introducing a fill_page_dma which maps and flushes. We also need 32 bit variant for legacy gens. v2: Fix flushes and handle valleyview (Ville) v3: Now really fix flushes (Michel, Ville) Reviewed-by: Michel Thierry Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 74 ++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 21fba03dcd62..734ffd240cd6 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -330,6 +330,34 @@ static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p) memset(p, 0, sizeof(*p)); } +static void fill_page_dma(struct drm_device *dev, struct i915_page_dma *p, + const uint64_t val) +{ + int i; + uint64_t * const vaddr = kmap_atomic(p->page); + + for (i = 0; i < 512; i++) + vaddr[i] = val; + + /* There are only few exceptions for gen >=6. chv and bxt. + * And we are not sure about the latter so play safe for now. + */ + if (IS_CHERRYVIEW(dev) || IS_BROXTON(dev)) + drm_clflush_virt_range(vaddr, PAGE_SIZE); + + kunmap_atomic(vaddr); +} + +static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p, + const uint32_t val32) +{ + uint64_t v = val32; + + v = v << 32 | val32; + + fill_page_dma(dev, p, v); +} + static void free_pt(struct drm_device *dev, struct i915_page_table *pt) { cleanup_page_dma(dev, &pt->base); @@ -340,19 +368,11 @@ static void free_pt(struct drm_device *dev, struct i915_page_table *pt) static void gen8_initialize_pt(struct i915_address_space *vm, struct i915_page_table *pt) { - gen8_pte_t *pt_vaddr, scratch_pte; - int i; - - pt_vaddr = kmap_atomic(pt->base.page); - scratch_pte = gen8_pte_encode(vm->scratch.addr, - I915_CACHE_LLC, true); + gen8_pte_t scratch_pte; - for (i = 0; i < GEN8_PTES; i++) - pt_vaddr[i] = scratch_pte; + scratch_pte = gen8_pte_encode(vm->scratch.addr, I915_CACHE_LLC, true); - if (!HAS_LLC(vm->dev)) - drm_clflush_virt_range(pt_vaddr, PAGE_SIZE); - kunmap_atomic(pt_vaddr); + fill_page_dma(vm->dev, &pt->base, scratch_pte); } static struct i915_page_table *alloc_pt(struct drm_device *dev) @@ -586,20 +606,13 @@ static void gen8_initialize_pd(struct i915_address_space *vm, struct i915_page_directory *pd) { struct i915_hw_ppgtt *ppgtt = - container_of(vm, struct i915_hw_ppgtt, base); - gen8_pde_t *page_directory; - struct i915_page_table *pt; - int i; + container_of(vm, struct i915_hw_ppgtt, base); + gen8_pde_t scratch_pde; - page_directory = kmap_atomic(pd->base.page); - pt = ppgtt->scratch_pt; - for (i = 0; i < I915_PDES; i++) - /* Map the PDE to the page table */ - __gen8_do_map_pt(page_directory + i, pt, vm->dev); + scratch_pde = gen8_pde_encode(vm->dev, ppgtt->scratch_pt->base.daddr, + I915_CACHE_LLC); - if (!HAS_LLC(vm->dev)) - drm_clflush_virt_range(page_directory, PAGE_SIZE); - kunmap_atomic(page_directory); + fill_page_dma(vm->dev, &pd->base, scratch_pde); } static void gen8_free_page_tables(struct i915_page_directory *pd, struct drm_device *dev) @@ -1255,22 +1268,15 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, } static void gen6_initialize_pt(struct i915_address_space *vm, - struct i915_page_table *pt) + struct i915_page_table *pt) { - gen6_pte_t *pt_vaddr, scratch_pte; - int i; + gen6_pte_t scratch_pte; WARN_ON(vm->scratch.addr == 0); - scratch_pte = vm->pte_encode(vm->scratch.addr, - I915_CACHE_LLC, true, 0); - - pt_vaddr = kmap_atomic(pt->base.page); - - for (i = 0; i < GEN6_PTES; i++) - pt_vaddr[i] = scratch_pte; + scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); - kunmap_atomic(pt_vaddr); + fill_page_dma_32(vm->dev, &pt->base, scratch_pte); } static int gen6_alloc_va_range(struct i915_address_space *vm, -- cgit v1.3-6-gb490 From d1c54acd67dc6518629224b68cac17cd5cff1dc3 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:11 +0300 Subject: drm/i915/gtt: Introduce kmap|kunmap for dma page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As there is flushing involved when we have done the cpu write, make functions for mapping for cpu space. Make macros to map any type of paging structure. v2: Make it clear tha flushing kunmap is only for ppgtt (Ville) v3: Flushing fixed (Ville, Michel). Removed superfluous semicolon Cc: Ville Syrjälä Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 77 +++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 734ffd240cd6..6abcf326b649 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -330,15 +330,16 @@ static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p) memset(p, 0, sizeof(*p)); } -static void fill_page_dma(struct drm_device *dev, struct i915_page_dma *p, - const uint64_t val) +static void *kmap_page_dma(struct i915_page_dma *p) { - int i; - uint64_t * const vaddr = kmap_atomic(p->page); - - for (i = 0; i < 512; i++) - vaddr[i] = val; + return kmap_atomic(p->page); +} +/* We use the flushing unmap only with ppgtt structures: + * page directories, page tables and scratch pages. + */ +static void kunmap_page_dma(struct drm_device *dev, void *vaddr) +{ /* There are only few exceptions for gen >=6. chv and bxt. * And we are not sure about the latter so play safe for now. */ @@ -348,6 +349,21 @@ static void fill_page_dma(struct drm_device *dev, struct i915_page_dma *p, kunmap_atomic(vaddr); } +#define kmap_px(px) kmap_page_dma(&(px)->base) +#define kunmap_px(ppgtt, vaddr) kunmap_page_dma((ppgtt)->base.dev, (vaddr)) + +static void fill_page_dma(struct drm_device *dev, struct i915_page_dma *p, + const uint64_t val) +{ + int i; + uint64_t * const vaddr = kmap_page_dma(p); + + for (i = 0; i < 512; i++) + vaddr[i] = val; + + kunmap_page_dma(dev, vaddr); +} + static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p, const uint32_t val32) { @@ -504,7 +520,6 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, while (num_entries) { struct i915_page_directory *pd; struct i915_page_table *pt; - struct page *page_table; if (WARN_ON(!ppgtt->pdp.page_directory[pdpe])) continue; @@ -519,22 +534,18 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, if (WARN_ON(!pt->base.page)) continue; - page_table = pt->base.page; - last_pte = pte + num_entries; if (last_pte > GEN8_PTES) last_pte = GEN8_PTES; - pt_vaddr = kmap_atomic(page_table); + pt_vaddr = kmap_px(pt); for (i = pte; i < last_pte; i++) { pt_vaddr[i] = scratch_pte; num_entries--; } - if (!HAS_LLC(ppgtt->base.dev)) - drm_clflush_virt_range(pt_vaddr, PAGE_SIZE); - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt); pte = 0; if (++pde == I915_PDES) { @@ -566,18 +577,14 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, if (pt_vaddr == NULL) { struct i915_page_directory *pd = ppgtt->pdp.page_directory[pdpe]; struct i915_page_table *pt = pd->page_table[pde]; - struct page *page_table = pt->base.page; - - pt_vaddr = kmap_atomic(page_table); + pt_vaddr = kmap_px(pt); } pt_vaddr[pte] = gen8_pte_encode(sg_page_iter_dma_address(&sg_iter), cache_level, true); if (++pte == GEN8_PTES) { - if (!HAS_LLC(ppgtt->base.dev)) - drm_clflush_virt_range(pt_vaddr, PAGE_SIZE); - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt_vaddr); pt_vaddr = NULL; if (++pde == I915_PDES) { pdpe++; @@ -586,11 +593,9 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, pte = 0; } } - if (pt_vaddr) { - if (!HAS_LLC(ppgtt->base.dev)) - drm_clflush_virt_range(pt_vaddr, PAGE_SIZE); - kunmap_atomic(pt_vaddr); - } + + if (pt_vaddr) + kunmap_px(ppgtt, pt_vaddr); } static void __gen8_do_map_pt(gen8_pde_t * const pde, @@ -870,7 +875,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, /* Allocations have completed successfully, so set the bitmaps, and do * the mappings. */ gen8_for_each_pdpe(pd, &ppgtt->pdp, start, length, temp, pdpe) { - gen8_pde_t *const page_directory = kmap_atomic(pd->base.page); + gen8_pde_t *const page_directory = kmap_px(pd); struct i915_page_table *pt; uint64_t pd_len = gen8_clamp_pd(start, length); uint64_t pd_start = start; @@ -900,10 +905,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, * point we're still relying on insert_entries() */ } - if (!HAS_LLC(vm->dev)) - drm_clflush_virt_range(page_directory, PAGE_SIZE); - - kunmap_atomic(page_directory); + kunmap_px(ppgtt, page_directory); set_bit(pdpe, ppgtt->pdp.used_pdpes); } @@ -992,7 +994,8 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) expected); seq_printf(m, "\tPDE: %x\n", pd_entry); - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[pde]->base.page); + pt_vaddr = kmap_px(ppgtt->pd.page_table[pde]); + for (pte = 0; pte < GEN6_PTES; pte+=4) { unsigned long va = (pde * PAGE_SIZE * GEN6_PTES) + @@ -1014,7 +1017,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) } seq_puts(m, "\n"); } - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt_vaddr); } } @@ -1221,12 +1224,12 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm, if (last_pte > GEN6_PTES) last_pte = GEN6_PTES; - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->base.page); + pt_vaddr = kmap_px(ppgtt->pd.page_table[act_pt]); for (i = first_pte; i < last_pte; i++) pt_vaddr[i] = scratch_pte; - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt_vaddr); num_entries -= last_pte - first_pte; first_pte = 0; @@ -1250,21 +1253,21 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, pt_vaddr = NULL; for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { if (pt_vaddr == NULL) - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->base.page); + pt_vaddr = kmap_px(ppgtt->pd.page_table[act_pt]); pt_vaddr[act_pte] = vm->pte_encode(sg_page_iter_dma_address(&sg_iter), cache_level, true, flags); if (++act_pte == GEN6_PTES) { - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt_vaddr); pt_vaddr = NULL; act_pt++; act_pte = 0; } } if (pt_vaddr) - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt_vaddr); } static void gen6_initialize_pt(struct i915_address_space *vm, -- cgit v1.3-6-gb490 From 567047be2a7ede082d29f45524c287b87bd75e53 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:12 +0300 Subject: drm/i915/gtt: Use macros to access dma mapped pages Make paging structure type agnostic *_px macros to access page dma struct, the backing page and the dma address. This makes the code less cluttered on internals of i915_page_dma. v2: Superfluous const -> nonconst removed v3: Rebased Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry (v2) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 35 ++++++++++++++++++++--------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 8 ++++++-- 2 files changed, 26 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 6abcf326b649..e85676e2352a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -349,9 +349,14 @@ static void kunmap_page_dma(struct drm_device *dev, void *vaddr) kunmap_atomic(vaddr); } -#define kmap_px(px) kmap_page_dma(&(px)->base) +#define kmap_px(px) kmap_page_dma(px_base(px)) #define kunmap_px(ppgtt, vaddr) kunmap_page_dma((ppgtt)->base.dev, (vaddr)) +#define setup_px(dev, px) setup_page_dma((dev), px_base(px)) +#define cleanup_px(dev, px) cleanup_page_dma((dev), px_base(px)) +#define fill_px(dev, px, v) fill_page_dma((dev), px_base(px), (v)) +#define fill32_px(dev, px, v) fill_page_dma_32((dev), px_base(px), (v)) + static void fill_page_dma(struct drm_device *dev, struct i915_page_dma *p, const uint64_t val) { @@ -376,7 +381,7 @@ static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p, static void free_pt(struct drm_device *dev, struct i915_page_table *pt) { - cleanup_page_dma(dev, &pt->base); + cleanup_px(dev, pt); kfree(pt->used_ptes); kfree(pt); } @@ -388,7 +393,7 @@ static void gen8_initialize_pt(struct i915_address_space *vm, scratch_pte = gen8_pte_encode(vm->scratch.addr, I915_CACHE_LLC, true); - fill_page_dma(vm->dev, &pt->base, scratch_pte); + fill_px(vm->dev, pt, scratch_pte); } static struct i915_page_table *alloc_pt(struct drm_device *dev) @@ -408,7 +413,7 @@ static struct i915_page_table *alloc_pt(struct drm_device *dev) if (!pt->used_ptes) goto fail_bitmap; - ret = setup_page_dma(dev, &pt->base); + ret = setup_px(dev, pt); if (ret) goto fail_page_m; @@ -424,8 +429,8 @@ fail_bitmap: static void free_pd(struct drm_device *dev, struct i915_page_directory *pd) { - if (pd->base.page) { - cleanup_page_dma(dev, &pd->base); + if (px_page(pd)) { + cleanup_px(dev, pd); kfree(pd->used_pdes); kfree(pd); } @@ -445,7 +450,7 @@ static struct i915_page_directory *alloc_pd(struct drm_device *dev) if (!pd->used_pdes) goto fail_bitmap; - ret = setup_page_dma(dev, &pd->base); + ret = setup_px(dev, pd); if (ret) goto fail_page_m; @@ -531,7 +536,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, pt = pd->page_table[pde]; - if (WARN_ON(!pt->base.page)) + if (WARN_ON(!px_page(pt))) continue; last_pte = pte + num_entries; @@ -603,7 +608,7 @@ static void __gen8_do_map_pt(gen8_pde_t * const pde, struct drm_device *dev) { gen8_pde_t entry = - gen8_pde_encode(dev, pt->base.daddr, I915_CACHE_LLC); + gen8_pde_encode(dev, px_dma(pt), I915_CACHE_LLC); *pde = entry; } @@ -614,17 +619,17 @@ static void gen8_initialize_pd(struct i915_address_space *vm, container_of(vm, struct i915_hw_ppgtt, base); gen8_pde_t scratch_pde; - scratch_pde = gen8_pde_encode(vm->dev, ppgtt->scratch_pt->base.daddr, + scratch_pde = gen8_pde_encode(vm->dev, px_dma(ppgtt->scratch_pt), I915_CACHE_LLC); - fill_page_dma(vm->dev, &pd->base, scratch_pde); + fill_px(vm->dev, pd, scratch_pde); } static void gen8_free_page_tables(struct i915_page_directory *pd, struct drm_device *dev) { int i; - if (!pd->base.page) + if (!px_page(pd)) return; for_each_set_bit(i, pd->used_pdes, I915_PDES) { @@ -983,7 +988,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde) { u32 expected; gen6_pte_t *pt_vaddr; - dma_addr_t pt_addr = ppgtt->pd.page_table[pde]->base.daddr; + const dma_addr_t pt_addr = px_dma(ppgtt->pd.page_table[pde]); pd_entry = readl(ppgtt->pd_addr + pde); expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID); @@ -1030,7 +1035,7 @@ static void gen6_write_pde(struct i915_page_directory *pd, container_of(pd, struct i915_hw_ppgtt, pd); u32 pd_entry; - pd_entry = GEN6_PDE_ADDR_ENCODE(pt->base.daddr); + pd_entry = GEN6_PDE_ADDR_ENCODE(px_dma(pt)); pd_entry |= GEN6_PDE_VALID; writel(pd_entry, ppgtt->pd_addr + pde); @@ -1279,7 +1284,7 @@ static void gen6_initialize_pt(struct i915_address_space *vm, scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); - fill_page_dma_32(vm->dev, &pt->base, scratch_pte); + fill32_px(vm->dev, pt, scratch_pte); } static int gen6_alloc_va_range(struct i915_address_space *vm, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index c681573b4005..f4bcec2b389a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -219,6 +219,10 @@ struct i915_page_dma { }; }; +#define px_base(px) (&(px)->base) +#define px_page(px) (px_base(px)->page) +#define px_dma(px) (px_base(px)->daddr) + struct i915_page_table { struct i915_page_dma base; @@ -481,8 +485,8 @@ static inline dma_addr_t i915_page_dir_dma_addr(const struct i915_hw_ppgtt *ppgtt, const unsigned n) { return test_bit(n, ppgtt->pdp.used_pdpes) ? - ppgtt->pdp.page_directory[n]->base.daddr : - ppgtt->scratch_pd->base.daddr; + px_dma(ppgtt->pdp.page_directory[n]) : + px_dma(ppgtt->scratch_pd); } int i915_gem_gtt_init(struct drm_device *dev); -- cgit v1.3-6-gb490 From c114f76a0a76eeffa1c1be392d98182c2cc30291 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:13 +0300 Subject: drm/i915/gtt: Make scratch page i915_page_dma compatible Lay out scratch page structure in similar manner than other paging structures. This allows us to use the same tools for setup and teardown. Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 89 ++++++++++++++++++++----------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 9 ++-- 2 files changed, 54 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index e85676e2352a..0cc0cf4362ea 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -301,11 +301,12 @@ static gen6_pte_t iris_pte_encode(dma_addr_t addr, return pte; } -static int setup_page_dma(struct drm_device *dev, struct i915_page_dma *p) +static int __setup_page_dma(struct drm_device *dev, + struct i915_page_dma *p, gfp_t flags) { struct device *device = &dev->pdev->dev; - p->page = alloc_page(GFP_KERNEL); + p->page = alloc_page(flags); if (!p->page) return -ENOMEM; @@ -320,6 +321,11 @@ static int setup_page_dma(struct drm_device *dev, struct i915_page_dma *p) return 0; } +static int setup_page_dma(struct drm_device *dev, struct i915_page_dma *p) +{ + return __setup_page_dma(dev, p, GFP_KERNEL); +} + static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p) { if (WARN_ON(!p->page)) @@ -391,7 +397,8 @@ static void gen8_initialize_pt(struct i915_address_space *vm, { gen8_pte_t scratch_pte; - scratch_pte = gen8_pte_encode(vm->scratch.addr, I915_CACHE_LLC, true); + scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true); fill_px(vm->dev, pt, scratch_pte); } @@ -519,7 +526,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, unsigned num_entries = length >> PAGE_SHIFT; unsigned last_pte, i; - scratch_pte = gen8_pte_encode(ppgtt->base.scratch.addr, + scratch_pte = gen8_pte_encode(px_dma(ppgtt->base.scratch_page), I915_CACHE_LLC, use_scratch); while (num_entries) { @@ -983,7 +990,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) uint32_t pte, pde, temp; uint32_t start = ppgtt->base.start, length = ppgtt->base.total; - scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), I915_CACHE_LLC, true, 0); gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde) { u32 expected; @@ -1222,7 +1229,8 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm, unsigned first_pte = first_entry % GEN6_PTES; unsigned last_pte, i; - scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true, 0); while (num_entries) { last_pte = first_pte + num_entries; @@ -1280,9 +1288,10 @@ static void gen6_initialize_pt(struct i915_address_space *vm, { gen6_pte_t scratch_pte; - WARN_ON(vm->scratch.addr == 0); + WARN_ON(px_dma(vm->scratch_page) == 0); - scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true, 0); fill32_px(vm->dev, pt, scratch_pte); } @@ -1519,13 +1528,14 @@ static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) struct drm_i915_private *dev_priv = dev->dev_private; ppgtt->base.dev = dev; - ppgtt->base.scratch = dev_priv->gtt.base.scratch; + ppgtt->base.scratch_page = dev_priv->gtt.base.scratch_page; if (INTEL_INFO(dev)->gen < 8) return gen6_ppgtt_init(ppgtt); else return gen8_ppgtt_init(ppgtt); } + int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1842,7 +1852,7 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm, first_entry, num_entries, max_entries)) num_entries = max_entries; - scratch_pte = gen8_pte_encode(vm->scratch.addr, + scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), I915_CACHE_LLC, use_scratch); for (i = 0; i < num_entries; i++) @@ -1868,7 +1878,8 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm, first_entry, num_entries, max_entries)) num_entries = max_entries; - scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, use_scratch, 0); + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, use_scratch, 0); for (i = 0; i < num_entries; i++) iowrite32(scratch_pte, >t_base[i]); @@ -2125,42 +2136,40 @@ void i915_global_gtt_cleanup(struct drm_device *dev) vm->cleanup(vm); } -static int setup_scratch_page(struct drm_device *dev) +static int alloc_scratch_page(struct i915_address_space *vm) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct page *page; - dma_addr_t dma_addr; + struct i915_page_scratch *sp; + int ret; + + WARN_ON(vm->scratch_page); - page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); - if (page == NULL) + sp = kzalloc(sizeof(*sp), GFP_KERNEL); + if (sp == NULL) return -ENOMEM; - set_pages_uc(page, 1); -#ifdef CONFIG_INTEL_IOMMU - dma_addr = pci_map_page(dev->pdev, page, 0, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, dma_addr)) { - __free_page(page); - return -EINVAL; + ret = __setup_page_dma(vm->dev, px_base(sp), GFP_DMA32 | __GFP_ZERO); + if (ret) { + kfree(sp); + return ret; } -#else - dma_addr = page_to_phys(page); -#endif - dev_priv->gtt.base.scratch.page = page; - dev_priv->gtt.base.scratch.addr = dma_addr; + + set_pages_uc(px_page(sp), 1); + + vm->scratch_page = sp; return 0; } -static void teardown_scratch_page(struct drm_device *dev) +static void free_scratch_page(struct i915_address_space *vm) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct page *page = dev_priv->gtt.base.scratch.page; + struct i915_page_scratch *sp = vm->scratch_page; - set_pages_wb(page, 1); - pci_unmap_page(dev->pdev, dev_priv->gtt.base.scratch.addr, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - __free_page(page); + set_pages_wb(px_page(sp), 1); + + cleanup_px(vm->dev, sp); + kfree(sp); + + vm->scratch_page = NULL; } static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) @@ -2268,7 +2277,7 @@ static int ggtt_probe_common(struct drm_device *dev, return -ENOMEM; } - ret = setup_scratch_page(dev); + ret = alloc_scratch_page(&dev_priv->gtt.base); if (ret) { DRM_ERROR("Scratch setup failed\n"); /* iounmap will also get called at remove, but meh */ @@ -2447,7 +2456,7 @@ static void gen6_gmch_remove(struct i915_address_space *vm) struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base); iounmap(gtt->gsm); - teardown_scratch_page(vm->dev); + free_scratch_page(vm); } static int i915_gmch_probe(struct drm_device *dev, @@ -2511,13 +2520,13 @@ int i915_gem_gtt_init(struct drm_device *dev) dev_priv->gtt.base.cleanup = gen6_gmch_remove; } + gtt->base.dev = dev; + ret = gtt->gtt_probe(dev, >t->base.total, >t->stolen_size, >t->mappable_base, >t->mappable_end); if (ret) return ret; - gtt->base.dev = dev; - /* GMADR is the PCI mmio aperture into the global GTT. */ DRM_INFO("Memory usable by graphics device = %lluM\n", gtt->base.total >> 20); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index f4bcec2b389a..216d949507af 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -223,6 +223,10 @@ struct i915_page_dma { #define px_page(px) (px_base(px)->page) #define px_dma(px) (px_base(px)->daddr) +struct i915_page_scratch { + struct i915_page_dma base; +}; + struct i915_page_table { struct i915_page_dma base; @@ -249,10 +253,7 @@ struct i915_address_space { u64 start; /* Start offset always 0 for dri2 */ u64 total; /* size addr space maps (ex. 2GB for ggtt) */ - struct { - dma_addr_t addr; - struct page *page; - } scratch; + struct i915_page_scratch *scratch_page; /** * List of objects currently involved in rendering. -- cgit v1.3-6-gb490 From b2dd45111e0fb4b36dcc972c7ae4e69ff1df4f88 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:15 +0300 Subject: drm/i915/gtt: Pin vma during virtual address allocation Dynamic page table allocation might wake the shrinker when memory is requested for page table structures. As this happens when we try to allocate the virtual address during binding, our vma might be among the targets for eviction. We should do i915_vma_pin() and do pin early in there like Chris suggests but this is interim solution. Shield our vma from shrinker by incrementing pin count before the virtual address is allocated. The proper place to fix this would be in gem, inside of i915_vma_pin(). But we don't have that yet so take the short cut as a intermediate solution. Testcase: igt/gem_ctx_thrash Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 0cc0cf4362ea..29d76b06e7de 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2870,9 +2870,12 @@ int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level, vma->node.size, VM_TO_TRACE_NAME(vma->vm)); + /* XXX: i915_vma_pin() will fix this +- hack */ + vma->pin_count++; ret = vma->vm->allocate_va_range(vma->vm, vma->node.start, vma->node.size); + vma->pin_count--; if (ret) return ret; } -- cgit v1.3-6-gb490 From fe36f55d4d4447679923fc74564786ae423ca4bd Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:16 +0300 Subject: drm/i915/gtt: Cleanup page directory encoding Write page directory entry without using superfluous indirect function. Also remove unused device parameter from the encode function. Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 29d76b06e7de..6817b072fac4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -192,9 +192,8 @@ static gen8_pte_t gen8_pte_encode(dma_addr_t addr, return pte; } -static gen8_pde_t gen8_pde_encode(struct drm_device *dev, - dma_addr_t addr, - enum i915_cache_level level) +static gen8_pde_t gen8_pde_encode(const dma_addr_t addr, + const enum i915_cache_level level) { gen8_pde_t pde = _PAGE_PRESENT | _PAGE_RW; pde |= addr; @@ -610,15 +609,6 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, kunmap_px(ppgtt, pt_vaddr); } -static void __gen8_do_map_pt(gen8_pde_t * const pde, - struct i915_page_table *pt, - struct drm_device *dev) -{ - gen8_pde_t entry = - gen8_pde_encode(dev, px_dma(pt), I915_CACHE_LLC); - *pde = entry; -} - static void gen8_initialize_pd(struct i915_address_space *vm, struct i915_page_directory *pd) { @@ -626,7 +616,7 @@ static void gen8_initialize_pd(struct i915_address_space *vm, container_of(vm, struct i915_hw_ppgtt, base); gen8_pde_t scratch_pde; - scratch_pde = gen8_pde_encode(vm->dev, px_dma(ppgtt->scratch_pt), + scratch_pde = gen8_pde_encode(px_dma(ppgtt->scratch_pt), I915_CACHE_LLC); fill_px(vm->dev, pd, scratch_pde); @@ -911,7 +901,8 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, set_bit(pde, pd->used_pdes); /* Map the PDE to the page table */ - __gen8_do_map_pt(page_directory + pde, pt, vm->dev); + page_directory[pde] = gen8_pde_encode(px_dma(pt), + I915_CACHE_LLC); /* NB: We haven't yet mapped ptes to pages. At this * point we're still relying on insert_entries() */ -- cgit v1.3-6-gb490 From 79ab93705464982b9f7e9b5dfabfacde634338aa Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:17 +0300 Subject: drm/i915/gtt: Move scratch_pd and scratch_pt into vm struct Scratch page is part of struct i915_address_space. Move other scratch entities into the same struct. This is a preparatory patch for having only one instance of each scratch_pt/pd. v2: make commit msg more readable Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry (v1) [danvet: Bikeshed summary to avoid confusion with vmas.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 51 +++++++++++++++++-------------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 7 +++-- 2 files changed, 27 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 6817b072fac4..2c8201e06e27 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -612,12 +612,9 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, static void gen8_initialize_pd(struct i915_address_space *vm, struct i915_page_directory *pd) { - struct i915_hw_ppgtt *ppgtt = - container_of(vm, struct i915_hw_ppgtt, base); gen8_pde_t scratch_pde; - scratch_pde = gen8_pde_encode(px_dma(ppgtt->scratch_pt), - I915_CACHE_LLC); + scratch_pde = gen8_pde_encode(px_dma(vm->scratch_pt), I915_CACHE_LLC); fill_px(vm->dev, pd, scratch_pde); } @@ -652,8 +649,8 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) free_pd(ppgtt->base.dev, ppgtt->pdp.page_directory[i]); } - free_pd(ppgtt->base.dev, ppgtt->scratch_pd); - free_pt(ppgtt->base.dev, ppgtt->scratch_pt); + free_pd(vm->dev, vm->scratch_pd); + free_pt(vm->dev, vm->scratch_pt); } /** @@ -689,7 +686,7 @@ static int gen8_ppgtt_alloc_pagetabs(struct i915_hw_ppgtt *ppgtt, /* Don't reallocate page tables */ if (pt) { /* Scratch is never allocated this way */ - WARN_ON(pt == ppgtt->scratch_pt); + WARN_ON(pt == ppgtt->base.scratch_pt); continue; } @@ -940,16 +937,16 @@ err_out: */ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) { - ppgtt->scratch_pt = alloc_pt(ppgtt->base.dev); - if (IS_ERR(ppgtt->scratch_pt)) - return PTR_ERR(ppgtt->scratch_pt); + ppgtt->base.scratch_pt = alloc_pt(ppgtt->base.dev); + if (IS_ERR(ppgtt->base.scratch_pt)) + return PTR_ERR(ppgtt->base.scratch_pt); - ppgtt->scratch_pd = alloc_pd(ppgtt->base.dev); - if (IS_ERR(ppgtt->scratch_pd)) - return PTR_ERR(ppgtt->scratch_pd); + ppgtt->base.scratch_pd = alloc_pd(ppgtt->base.dev); + if (IS_ERR(ppgtt->base.scratch_pd)) + return PTR_ERR(ppgtt->base.scratch_pd); - gen8_initialize_pt(&ppgtt->base, ppgtt->scratch_pt); - gen8_initialize_pd(&ppgtt->base, ppgtt->scratch_pd); + gen8_initialize_pt(&ppgtt->base, ppgtt->base.scratch_pt); + gen8_initialize_pd(&ppgtt->base, ppgtt->base.scratch_pd); ppgtt->base.start = 0; ppgtt->base.total = 1ULL << 32; @@ -981,7 +978,8 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) uint32_t pte, pde, temp; uint32_t start = ppgtt->base.start, length = ppgtt->base.total; - scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), I915_CACHE_LLC, true, 0); + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true, 0); gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde) { u32 expected; @@ -1314,7 +1312,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, * tables. */ gen6_for_each_pde(pt, &ppgtt->pd, start, length, temp, pde) { - if (pt != ppgtt->scratch_pt) { + if (pt != vm->scratch_pt) { WARN_ON(bitmap_empty(pt->used_ptes, GEN6_PTES)); continue; } @@ -1369,7 +1367,7 @@ unwind_out: for_each_set_bit(pde, new_page_tables, I915_PDES) { struct i915_page_table *pt = ppgtt->pd.page_table[pde]; - ppgtt->pd.page_table[pde] = ppgtt->scratch_pt; + ppgtt->pd.page_table[pde] = vm->scratch_pt; free_pt(vm->dev, pt); } @@ -1384,15 +1382,14 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) struct i915_page_table *pt; uint32_t pde; - drm_mm_remove_node(&ppgtt->node); gen6_for_all_pdes(pt, ppgtt, pde) { - if (pt != ppgtt->scratch_pt) + if (pt != vm->scratch_pt) free_pt(ppgtt->base.dev, pt); } - free_pt(ppgtt->base.dev, ppgtt->scratch_pt); + free_pt(vm->dev, vm->scratch_pt); } static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) @@ -1407,11 +1404,11 @@ static int gen6_ppgtt_allocate_page_directories(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)); - ppgtt->scratch_pt = alloc_pt(ppgtt->base.dev); - if (IS_ERR(ppgtt->scratch_pt)) - return PTR_ERR(ppgtt->scratch_pt); + ppgtt->base.scratch_pt = alloc_pt(ppgtt->base.dev); + if (IS_ERR(ppgtt->base.scratch_pt)) + return PTR_ERR(ppgtt->base.scratch_pt); - gen6_initialize_pt(&ppgtt->base, ppgtt->scratch_pt); + gen6_initialize_pt(&ppgtt->base, ppgtt->base.scratch_pt); alloc: ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm, @@ -1442,7 +1439,7 @@ alloc: return 0; err_out: - free_pt(ppgtt->base.dev, ppgtt->scratch_pt); + free_pt(ppgtt->base.dev, ppgtt->base.scratch_pt); return ret; } @@ -1458,7 +1455,7 @@ static void gen6_scratch_va_range(struct i915_hw_ppgtt *ppgtt, uint32_t pde, temp; gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde) - ppgtt->pd.page_table[pde] = ppgtt->scratch_pt; + ppgtt->pd.page_table[pde] = ppgtt->base.scratch_pt; } static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 216d949507af..e1cfa292f9ad 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -254,6 +254,8 @@ struct i915_address_space { u64 total; /* size addr space maps (ex. 2GB for ggtt) */ struct i915_page_scratch *scratch_page; + struct i915_page_table *scratch_pt; + struct i915_page_directory *scratch_pd; /** * List of objects currently involved in rendering. @@ -343,9 +345,6 @@ struct i915_hw_ppgtt { struct i915_page_directory pd; }; - struct i915_page_table *scratch_pt; - struct i915_page_directory *scratch_pd; - struct drm_i915_file_private *file_priv; gen6_pte_t __iomem *pd_addr; @@ -487,7 +486,7 @@ i915_page_dir_dma_addr(const struct i915_hw_ppgtt *ppgtt, const unsigned n) { return test_bit(n, ppgtt->pdp.used_pdpes) ? px_dma(ppgtt->pdp.page_directory[n]) : - px_dma(ppgtt->scratch_pd); + px_dma(ppgtt->base.scratch_pd); } int i915_gem_gtt_init(struct drm_device *dev); -- cgit v1.3-6-gb490 From 966082c93273f4fd52f4a068b4b55c47e3ba72cc Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:19 +0300 Subject: drm/i915/gtt: Use nonatomic bitmap ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need for atomicity here. Convert all bitmap operations to nonatomic variants. Cc: Ville Syrjälä Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 2c8201e06e27..e7e0a049995f 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -696,7 +696,7 @@ static int gen8_ppgtt_alloc_pagetabs(struct i915_hw_ppgtt *ppgtt, gen8_initialize_pt(&ppgtt->base, pt); pd->page_table[pde] = pt; - set_bit(pde, new_pts); + __set_bit(pde, new_pts); } return 0; @@ -754,7 +754,7 @@ static int gen8_ppgtt_alloc_page_directories(struct i915_hw_ppgtt *ppgtt, gen8_initialize_pd(&ppgtt->base, pd); pdp->page_directory[pdpe] = pd; - set_bit(pdpe, new_pds); + __set_bit(pdpe, new_pds); } return 0; @@ -895,7 +895,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, gen8_pte_count(pd_start, pd_len)); /* Our pde is now pointing to the pagetable, pt */ - set_bit(pde, pd->used_pdes); + __set_bit(pde, pd->used_pdes); /* Map the PDE to the page table */ page_directory[pde] = gen8_pde_encode(px_dma(pt), @@ -907,7 +907,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, kunmap_px(ppgtt, page_directory); - set_bit(pdpe, ppgtt->pdp.used_pdpes); + __set_bit(pdpe, ppgtt->pdp.used_pdpes); } free_gen8_temp_bitmaps(new_page_dirs, new_page_tables); @@ -1329,7 +1329,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, gen6_initialize_pt(vm, pt); ppgtt->pd.page_table[pde] = pt; - set_bit(pde, new_page_tables); + __set_bit(pde, new_page_tables); trace_i915_page_table_entry_alloc(vm, pde, start, GEN6_PDE_SHIFT); } @@ -1343,7 +1343,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, bitmap_set(tmp_bitmap, gen6_pte_index(start), gen6_pte_count(start, length)); - if (test_and_clear_bit(pde, new_page_tables)) + if (__test_and_clear_bit(pde, new_page_tables)) gen6_write_pde(&ppgtt->pd, pde, pt); trace_i915_page_table_entry_map(vm, pde, pt, -- cgit v1.3-6-gb490 From 7a01a0a292c25a85cd36efcd5920d2f1caccbb2b Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Fri, 26 Jun 2015 13:46:14 +0100 Subject: drm/i915/lrc: Update PDPx registers with lri commands A safer way to update the PDPx registers is sending lri commands, added in the ring before the batchbuffer start. Otherwise, the ctx must be idle before trying to change anything (but the ring-tail) in the ctx image. An example where the ctx won't be idle is lite-restore. This patch depends on 5b7e4c9ce ("drm/i915/gtt: Mark TLBS dirty for gen8+"). v2: Combine lri writes (and save 8 commands). (Mika) v3: Rebase after ring/req changes, and removed references to deprecated patches. Cc: Dave Gordon Cc: Mika Kuoppala Signed-off-by: Michel Thierry Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index fd25314fc913..8cac4cab1666 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1373,6 +1373,34 @@ static int gen9_init_render_ring(struct intel_engine_cs *ring) return init_workarounds_ring(ring); } +static int intel_logical_ring_emit_pdps(struct drm_i915_gem_request *req) +{ + struct i915_hw_ppgtt *ppgtt = req->ctx->ppgtt; + struct intel_engine_cs *ring = req->ring; + struct intel_ringbuffer *ringbuf = req->ringbuf; + const int num_lri_cmds = GEN8_LEGACY_PDPES * 2; + int i, ret; + + ret = intel_logical_ring_begin(req, num_lri_cmds * 2 + 2); + if (ret) + return ret; + + intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(num_lri_cmds)); + for (i = GEN8_LEGACY_PDPES - 1; i >= 0; i--) { + const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i); + + intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_UDW(ring, i)); + intel_logical_ring_emit(ringbuf, upper_32_bits(pd_daddr)); + intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_LDW(ring, i)); + intel_logical_ring_emit(ringbuf, lower_32_bits(pd_daddr)); + } + + intel_logical_ring_emit(ringbuf, MI_NOOP); + intel_logical_ring_advance(ringbuf); + + return 0; +} + static int gen8_emit_bb_start(struct drm_i915_gem_request *req, u64 offset, unsigned dispatch_flags) { @@ -1380,6 +1408,20 @@ static int gen8_emit_bb_start(struct drm_i915_gem_request *req, bool ppgtt = !(dispatch_flags & I915_DISPATCH_SECURE); int ret; + /* Don't rely in hw updating PDPs, specially in lite-restore. + * Ideally, we should set Force PD Restore in ctx descriptor, + * but we can't. Force Restore would be a second option, but + * it is unsafe in case of lite-restore (because the ctx is + * not idle). */ + if (req->ctx->ppgtt && + (intel_ring_flag(req->ring) & req->ctx->ppgtt->pd_dirty_rings)) { + ret = intel_logical_ring_emit_pdps(req); + if (ret) + return ret; + + req->ctx->ppgtt->pd_dirty_rings &= ~intel_ring_flag(req->ring); + } + ret = intel_logical_ring_begin(req, 4); if (ret) return ret; -- cgit v1.3-6-gb490 From f37c05052ff6430767f3bff60efc0e92f690495b Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Wed, 10 Jun 2015 17:46:39 +0100 Subject: drm/i915/gtt: Switch gen8_free_page_tables params After Mika's ppgtt cleanup series, all the other free functions have drm_device as the first parameter, except this one. No functional changes. Signed-off-by: Michel Thierry Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index e7e0a049995f..b94eebe81fd8 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -619,7 +619,8 @@ static void gen8_initialize_pd(struct i915_address_space *vm, fill_px(vm->dev, pd, scratch_pde); } -static void gen8_free_page_tables(struct i915_page_directory *pd, struct drm_device *dev) +static void gen8_free_page_tables(struct drm_device *dev, + struct i915_page_directory *pd) { int i; @@ -645,7 +646,8 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) if (WARN_ON(!ppgtt->pdp.page_directory[i])) continue; - gen8_free_page_tables(ppgtt->pdp.page_directory[i], ppgtt->base.dev); + gen8_free_page_tables(ppgtt->base.dev, + ppgtt->pdp.page_directory[i]); free_pd(ppgtt->base.dev, ppgtt->pdp.page_directory[i]); } -- cgit v1.3-6-gb490 From dc2538139277089e218b1b1d0d01454ecf39e944 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 25 Jun 2015 16:15:06 +0100 Subject: drm/i915/skl: Replace the HDMI DPLL divider computation algorithm The HW validation team came back from further testing with a slightly changed constraint on the deviation between the DCO frequency and the central frequency. Instead of +-4%, it's now +1%/-6%. Unfortunately, the previous algorithm didn't quite cope with these new constraints, the reason being that it wasn't thorough enough looking at the possible divider candidates. The new algorithm looks at all dividers, which is definitely a hammer approach (we could reduce further the set of dividers to good ones as a follow up, at the cost of a bit more complicated code). But, at least, we can now satisfy the +1%/+6% rule for all the "Well known" HDMI frequencies of my test set (373 entries). On that subject, the new code is quite extensively tested in intel-gpu-tools (tools/skl_compute_wrpll). v2: Fix cycling between central frequencies and dividers (Paulo) Properly choose the minimal deviation between postive and negative candidates (Paulo). On the 373 test frequencies, v2 computes better dividers than v1 (ie more even dividers and lower deviation on average): v1: average deviation: 206.52 v2: average deviation: 194.47 Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 211 +++++++++++++++++++++++++-------------- 1 file changed, 137 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 31b29e8781ac..6e964ef7dfda 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1104,6 +1104,103 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc, return true; } +struct skl_wrpll_context { + uint64_t min_deviation; /* current minimal deviation */ + uint64_t central_freq; /* chosen central freq */ + uint64_t dco_freq; /* chosen dco freq */ + unsigned int p; /* chosen divider */ +}; + +static void skl_wrpll_context_init(struct skl_wrpll_context *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + + ctx->min_deviation = U64_MAX; +} + +/* DCO freq must be within +1%/-6% of the DCO central freq */ +#define SKL_DCO_MAX_PDEVIATION 100 +#define SKL_DCO_MAX_NDEVIATION 600 + +static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx, + uint64_t central_freq, + uint64_t dco_freq, + unsigned int divider) +{ + uint64_t deviation; + + deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq), + central_freq); + + /* positive deviation */ + if (dco_freq >= central_freq) { + if (deviation < SKL_DCO_MAX_PDEVIATION && + deviation < ctx->min_deviation) { + ctx->min_deviation = deviation; + ctx->central_freq = central_freq; + ctx->dco_freq = dco_freq; + ctx->p = divider; + } + /* negative deviation */ + } else if (deviation < SKL_DCO_MAX_NDEVIATION && + deviation < ctx->min_deviation) { + ctx->min_deviation = deviation; + ctx->central_freq = central_freq; + ctx->dco_freq = dco_freq; + ctx->p = divider; + } + +} + +static void skl_wrpll_get_multipliers(unsigned int p, + unsigned int *p0 /* out */, + unsigned int *p1 /* out */, + unsigned int *p2 /* out */) +{ + /* even dividers */ + if (p % 2 == 0) { + unsigned int half = p / 2; + + if (half == 1 || half == 2 || half == 3 || half == 5) { + *p0 = 2; + *p1 = 1; + *p2 = half; + } else if (half % 2 == 0) { + *p0 = 2; + *p1 = half / 2; + *p2 = 2; + } else if (half % 3 == 0) { + *p0 = 3; + *p1 = half / 3; + *p2 = 2; + } else if (half % 7 == 0) { + *p0 = 7; + *p1 = half / 7; + *p2 = 2; + } + } else if (p == 3 || p == 9) { /* 3, 5, 7, 9, 15, 21, 35 */ + *p0 = 3; + *p1 = 1; + *p2 = p / 3; + } else if (p == 5 || p == 7) { + *p0 = p; + *p1 = 1; + *p2 = 1; + } else if (p == 15) { + *p0 = 3; + *p1 = 1; + *p2 = 5; + } else if (p == 21) { + *p0 = 7; + *p1 = 1; + *p2 = 3; + } else if (p == 35) { + *p0 = 7; + *p1 = 1; + *p2 = 5; + } +} + struct skl_wrpll_params { uint32_t dco_fraction; uint32_t dco_integer; @@ -1189,90 +1286,56 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */, uint64_t dco_central_freq[3] = {8400000000ULL, 9000000000ULL, 9600000000ULL}; - uint32_t min_dco_deviation = 400; - uint32_t min_dco_index = 3; - uint32_t P0[4] = {1, 2, 3, 7}; - uint32_t P2[4] = {1, 2, 3, 5}; - bool found = false; - uint32_t candidate_p = 0; - uint32_t candidate_p0[3] = {0}, candidate_p1[3] = {0}; - uint32_t candidate_p2[3] = {0}; - uint32_t dco_central_freq_deviation[3]; - uint32_t i, P1, k, dco_count; - bool retry_with_odd = false; - - /* Determine P0, P1 or P2 */ - for (dco_count = 0; dco_count < 3; dco_count++) { - found = false; - candidate_p = - div64_u64(dco_central_freq[dco_count], afe_clock); - if (retry_with_odd == false) - candidate_p = (candidate_p % 2 == 0 ? - candidate_p : candidate_p + 1); - - for (P1 = 1; P1 < candidate_p; P1++) { - for (i = 0; i < 4; i++) { - if (!(P0[i] != 1 || P1 == 1)) - continue; - - for (k = 0; k < 4; k++) { - if (P1 != 1 && P2[k] != 2) - continue; - - if (candidate_p == P0[i] * P1 * P2[k]) { - /* Found possible P0, P1, P2 */ - found = true; - candidate_p0[dco_count] = P0[i]; - candidate_p1[dco_count] = P1; - candidate_p2[dco_count] = P2[k]; - goto found; - } - - } - } - } - -found: - if (found) { - dco_central_freq_deviation[dco_count] = - div64_u64(10000 * - abs_diff(candidate_p * afe_clock, - dco_central_freq[dco_count]), - dco_central_freq[dco_count]); - - if (dco_central_freq_deviation[dco_count] < - min_dco_deviation) { - min_dco_deviation = - dco_central_freq_deviation[dco_count]; - min_dco_index = dco_count; + static const int even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, + 24, 28, 30, 32, 36, 40, 42, 44, + 48, 52, 54, 56, 60, 64, 66, 68, + 70, 72, 76, 78, 80, 84, 88, 90, + 92, 96, 98 }; + static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 }; + static const struct { + const int *list; + int n_dividers; + } dividers[] = { + { even_dividers, ARRAY_SIZE(even_dividers) }, + { odd_dividers, ARRAY_SIZE(odd_dividers) }, + }; + struct skl_wrpll_context ctx; + unsigned int dco, d, i; + unsigned int p0, p1, p2; + + skl_wrpll_context_init(&ctx); + + for (d = 0; d < ARRAY_SIZE(dividers); d++) { + for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) { + for (i = 0; i < dividers[d].n_dividers; i++) { + unsigned int p = dividers[d].list[i]; + uint64_t dco_freq = p * afe_clock; + + skl_wrpll_try_divider(&ctx, + dco_central_freq[dco], + dco_freq, + p); } } - - if (min_dco_index > 2 && dco_count == 2) { - /* oh well, we tried... */ - if (retry_with_odd) - break; - - retry_with_odd = true; - dco_count = 0; - } } - if (WARN(min_dco_index > 2, - "No valid parameters found for pixel clock: %dHz\n", clock)) + if (!ctx.p) { + DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock); return false; + } - skl_wrpll_params_populate(wrpll_params, - afe_clock, - dco_central_freq[min_dco_index], - candidate_p0[min_dco_index], - candidate_p1[min_dco_index], - candidate_p2[min_dco_index]); + /* + * gcc incorrectly analyses that these can be used without being + * initialized. To be fair, it's hard to guess. + */ + p0 = p1 = p2 = 0; + skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2); + skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq, + p0, p1, p2); return true; } - static bool skl_ddi_pll_select(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state, -- cgit v1.3-6-gb490 From 267db663458a8077a087674fb85ea95f540d8671 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 25 Jun 2015 16:19:24 +0100 Subject: drm/i915/skl: Prefer even dividers for SKL DPLLs Currently, if an odd divider improves the deviation (minimizes it), we take that divider. The recommendation is to prefer even dividers. v2: Move the check at the right place after having inverted the two for loops in the previous patch. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 6e964ef7dfda..f6b3ccc4ab66 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1317,6 +1317,13 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */, p); } } + + /* + * If a solution is found with an even divider, prefer + * this one. + */ + if (d == 0 && ctx.p) + break; } if (!ctx.p) { -- cgit v1.3-6-gb490 From 350405623ff3f447813eaef2035272bf05281671 Mon Sep 17 00:00:00 2001 From: Bob Paauwe Date: Thu, 25 Jun 2015 14:54:07 -0700 Subject: drm/i915: Update rps frequencies for BXT Broxton is using a different register and different bit ordering for rps status capabilities. Also GT perf freqency register is different for Broxton so update that. Signed-off-by: Bob Paauwe Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 21 ++++++++++++++++----- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 16 ++++++++++++---- 3 files changed, 30 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index b509844df0dd..7d303e721a77 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1132,9 +1132,9 @@ static int i915_frequency_info(struct seq_file *m, void *unused) (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); } else if (IS_GEN6(dev) || (IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) || IS_BROADWELL(dev) || IS_GEN9(dev)) { - u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); - u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); - u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + u32 rp_state_limits; + u32 gt_perf_status; + u32 rp_state_cap; u32 rpmodectl, rpinclimit, rpdeclimit; u32 rpstat, cagf, reqf; u32 rpupei, rpcurup, rpprevup; @@ -1142,6 +1142,15 @@ static int i915_frequency_info(struct seq_file *m, void *unused) u32 pm_ier, pm_imr, pm_isr, pm_iir, pm_mask; int max_freq; + rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); + if (IS_BROXTON(dev)) { + rp_state_cap = I915_READ(BXT_RP_STATE_CAP); + gt_perf_status = I915_READ(BXT_GT_PERF_STATUS); + } else { + rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); + } + /* RPSTAT1 is in the GT power well */ ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) @@ -1229,7 +1238,8 @@ static int i915_frequency_info(struct seq_file *m, void *unused) seq_printf(m, "Down threshold: %d%%\n", dev_priv->rps.down_threshold); - max_freq = (rp_state_cap & 0xff0000) >> 16; + max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 0 : + rp_state_cap >> 16) & 0xff; max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1); seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); @@ -1239,7 +1249,8 @@ static int i915_frequency_info(struct seq_file *m, void *unused) seq_printf(m, "Nominal (RP1) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); - max_freq = rp_state_cap & 0xff; + max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 16 : + rp_state_cap >> 0) & 0xff; max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1); seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c19067c843e8..b6c8037a9e54 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2734,8 +2734,10 @@ enum skl_disp_power_wells { #define GEN6_GT_THREAD_STATUS_CORE_MASK 0x7 #define GEN6_GT_PERF_STATUS (MCHBAR_MIRROR_BASE_SNB + 0x5948) +#define BXT_GT_PERF_STATUS (MCHBAR_MIRROR_BASE_SNB + 0x7070) #define GEN6_RP_STATE_LIMITS (MCHBAR_MIRROR_BASE_SNB + 0x5994) #define GEN6_RP_STATE_CAP (MCHBAR_MIRROR_BASE_SNB + 0x5998) +#define BXT_RP_STATE_CAP 0x138170 #define INTERVAL_1_28_US(us) (((us) * 100) >> 7) #define INTERVAL_1_33_US(us) (((us) * 3) >> 2) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 32ff034a0875..213da42d6c24 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4288,13 +4288,21 @@ static void gen6_init_rps_frequencies(struct drm_device *dev) u32 ddcc_status = 0; int ret; - rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); /* All of these values are in units of 50MHz */ dev_priv->rps.cur_freq = 0; /* static values from HW: RP0 > RP1 > RPn (min_freq) */ - dev_priv->rps.rp0_freq = (rp_state_cap >> 0) & 0xff; - dev_priv->rps.rp1_freq = (rp_state_cap >> 8) & 0xff; - dev_priv->rps.min_freq = (rp_state_cap >> 16) & 0xff; + if (IS_BROXTON(dev)) { + rp_state_cap = I915_READ(BXT_RP_STATE_CAP); + dev_priv->rps.rp0_freq = (rp_state_cap >> 16) & 0xff; + dev_priv->rps.rp1_freq = (rp_state_cap >> 8) & 0xff; + dev_priv->rps.min_freq = (rp_state_cap >> 0) & 0xff; + } else { + rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + dev_priv->rps.rp0_freq = (rp_state_cap >> 0) & 0xff; + dev_priv->rps.rp1_freq = (rp_state_cap >> 8) & 0xff; + dev_priv->rps.min_freq = (rp_state_cap >> 16) & 0xff; + } + if (IS_SKYLAKE(dev)) { /* Store the frequency values in 16.66 MHZ units, which is the natural hardware unit for SKL */ -- cgit v1.3-6-gb490 From e7ad987832637701fc723ac2c1580c30c191bca6 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 26 Jun 2015 18:34:29 +0100 Subject: drm/i915/skl: Skip remaining dividers when deviation is 0 We can't improve a 0 deviation, so when we find such a divider, skip the remaining ones they won't be better. This short-circuit the search for 34 of the 373 test frequencies in the corresponding i-g-t test (tools/skl_compute_wrpll) v2: Place the short-circuiting code in skl_compute_wrpll() (Paulo) (I'm sure nobody will notice the spurious removal of a blank line) Reviewed-by: Paulo Zanoni Suggested-by: Paulo Zanoni Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index f6b3ccc4ab66..42c14870ef43 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1149,7 +1149,6 @@ static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx, ctx->dco_freq = dco_freq; ctx->p = divider; } - } static void skl_wrpll_get_multipliers(unsigned int p, @@ -1315,9 +1314,17 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */, dco_central_freq[dco], dco_freq, p); + /* + * Skip the remaining dividers if we're sure to + * have found the definitive divider, we can't + * improve a 0 deviation. + */ + if (ctx.min_deviation == 0) + goto skip_remaining_dividers; } } +skip_remaining_dividers: /* * If a solution is found with an even divider, prefer * this one. -- cgit v1.3-6-gb490 From 12ebb05246338aa9cdee51da50f57237352b3f64 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 21 Jun 2015 12:18:09 +0200 Subject: iio:adc:Kconfig: rework help descriptions Rework the help text of several ADCs to make sure that: - the module name is mentioned, if the driver can be built as a module - "If unsure, say N" messages are dropped - right indentation is maintained Signed-off-by: Hartmut Knaack Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7c5565891cb8..dace593b158b 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -20,6 +20,9 @@ config AD7266 Say yes here to build support for Analog Devices AD7265 and AD7266 ADCs. + To compile this driver as a module, choose M here: the module will be + called ad7266. + config AD7291 tristate "Analog Devices AD7291 ADC driver" depends on I2C @@ -52,8 +55,6 @@ config AD7476 AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC). - If unsure, say N (but it's safe to say "Y"). - To compile this driver as a module, choose M here: the module will be called ad7476. @@ -63,8 +64,7 @@ config AD7791 select AD_SIGMA_DELTA help Say yes here to build support for Analog Devices AD7787, AD7788, AD7789, - AD7790 and AD7791 SPI analog to digital converters (ADC). If unsure, say - N (but it is safe to say "Y"). + AD7790 and AD7791 SPI analog to digital converters (ADC). To compile this driver as a module, choose M here: the module will be called ad7791. @@ -76,7 +76,6 @@ config AD7793 help Say yes here to build support for Analog Devices AD7785, AD7792, AD7793, AD7794 and AD7795 SPI analog to digital converters (ADC). - If unsure, say N (but it's safe to say "Y"). To compile this driver as a module, choose M here: the module will be called AD7793. @@ -89,7 +88,6 @@ config AD7887 help Say yes here to build support for Analog Devices AD7887 SPI analog to digital converter (ADC). - If unsure, say N (but it's safe to say "Y"). To compile this driver as a module, choose M here: the module will be called ad7887. @@ -117,6 +115,9 @@ config AD799X i2c analog to digital converters (ADC). Provides direct access via sysfs. + To compile this driver as a module, choose M here: the module will be + called ad799x. + config AT91_ADC tristate "Atmel AT91 ADC" depends on ARCH_AT91 @@ -127,6 +128,9 @@ config AT91_ADC help Say yes here to build support for Atmel AT91 ADC. + To compile this driver as a module, choose M here: the module will be + called at91_adc. + config AXP288_ADC tristate "X-Powers AXP288 ADC driver" depends on MFD_AXP20X @@ -135,6 +139,9 @@ config AXP288_ADC device. Depending on platform configuration, this general purpose ADC can be used for sampling sensors such as thermal resistors. + To compile this driver as a module, choose M here: the module will be + called axp288_adc. + config BERLIN2_ADC tristate "Marvell Berlin2 ADC driver" depends on ARCH_BERLIN @@ -151,6 +158,9 @@ config DA9150_GPADC This driver can also be built as a module. If chosen, the module name will be da9150-gpadc. + To compile this driver as a module, choose M here: the module will be + called berlin2-adc. + config CC10001_ADC tristate "Cosmic Circuits 10001 ADC driver" depends on HAVE_CLK || REGULATOR @@ -171,12 +181,18 @@ config EXYNOS_ADC of SoCs for drivers such as the touchscreen and hwmon to use to share this resource. + To compile this driver as a module, choose M here: the module will be + called exynos_adc. + config LP8788_ADC tristate "LP8788 ADC driver" depends on MFD_LP8788 help Say yes here to build support for TI LP8788 ADC. + To compile this driver as a module, choose M here: the module will be + called lp8788_adc. + config MAX1027 tristate "Maxim max1027 ADC driver" depends on SPI @@ -186,6 +202,9 @@ config MAX1027 Say yes here to build support for Maxim SPI ADC models max1027, max1029 and max1031. + To compile this driver as a module, choose M here: the module will be + called max1027. + config MAX1363 tristate "Maxim max1363 ADC driver" depends on I2C @@ -202,6 +221,9 @@ config MAX1363 max11646, max11647) Provides direct access via sysfs and buffered data via the iio dev interface. + To compile this driver as a module, choose M here: the module will be + called max1363. + config MCP320X tristate "Microchip Technology MCP3x01/02/04/08" depends on SPI @@ -310,15 +332,18 @@ config TI_AM335X_ADC Say yes here to build support for Texas Instruments ADC driver which is also a MFD client. + To compile this driver as a module, choose M here: the module will be + called ti_am335x_adc. + 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 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. + 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" @@ -351,6 +376,9 @@ config VIPERBOARD_ADC Say yes here to access the ADC part of the Nano River Technologies Viperboard. + To compile this driver as a module, choose M here: the module will be + called viperboard_adc. + config XILINX_XADC tristate "Xilinx XADC driver" depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST -- cgit v1.3-6-gb490 From 066cf55b9ce35f1f90dde9fcec01431a9243a949 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 26 Jun 2015 13:55:54 -0700 Subject: drm/i915: Fix IPS related flicker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We cannot let IPS enabled with no plane on the pipe: BSpec: "IPS cannot be enabled until after at least one plane has been enabled for at least one vertical blank." and "IPS must be disabled while there is still at least one plane enabled on the same pipe as IPS." This restriction apply to HSW and BDW. However a shortcut path on update primary plane function to make primary plane invisible by setting DSPCTRL to 0 was leting IPS enabled while there was no other plane enabled on the pipe causing flickerings that we were believing that it was caused by that other restriction where ips cannot be used when pixel rate is greater than 95% of cdclok. v2: Don't mess with Atomic path as pointed out by Ville. v3: Rebase after a long time and atomic path changes. Accept Ville suggestion of not check !fb v4: Re-factore on dinq Reference: https://bugs.freedesktop.org/show_bug.cgi?id=85583 Cc: Paulo Zanoni Cc: Jani Nikula Cc: Daniel Vetter Reviewed-by: Ville Syrjälä Tested-by: Kenneth Graunke [danvet: Make it compile] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 +++++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 01eaab8b6d40..eb665d7ffda7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4766,6 +4766,9 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) mutex_unlock(&dev->struct_mutex); } + if (crtc->atomic.disable_ips) + hsw_disable_ips(crtc); + if (atomic->pre_disable_primary) intel_pre_disable_primary(&crtc->base); } @@ -11616,8 +11619,19 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, intel_crtc->atomic.pre_disable_primary = turn_off; intel_crtc->atomic.post_enable_primary = turn_on; - if (turn_off) + if (turn_off) { + /* + * FIXME: Actually if we will still have any other + * plane enabled on the pipe we could let IPS enabled + * still, but for now lets consider that when we make + * primary invisible by setting DSPCNTR to 0 on + * update_primary_plane function IPS needs to be + * disable. + */ + intel_crtc->atomic.disable_ips = true; + intel_crtc->atomic.disable_fbc = true; + } /* * FBC does not work on some platforms for rotated diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e016d722cacb..33cff9d9a7a1 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -498,6 +498,7 @@ struct intel_crtc_atomic_commit { /* Sleepable operations to perform before commit */ bool wait_for_flips; bool disable_fbc; + bool disable_ips; bool pre_disable_primary; bool update_wm; unsigned disabled_planes; -- cgit v1.3-6-gb490 From 031b698a77a70a6c394568034437b5486a44e868 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 26 Jun 2015 19:35:16 +0200 Subject: drm/i915: Unconditionally do fb tracking invalidate in set_domain We can't elide the fb tracking invalidate if the buffer is already in the right domain since that would lead to missed screen updates. I'm pretty sure I've written this already before but must have gotten lost unfortunately :( v2: Chris observed that all internal set_domain users already correctly do the fb invalidate on their own, hence we can move this just into the set_domain ioctl instead. v3: I screwed up setting the invalidate ORIGIN_* correctly (Chris). Cc: Chris Wilson Reported-by: Paulo Zanoni Cc: Paulo Zanoni Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Tested-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index db1955fad005..37cd901c9d75 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1614,6 +1614,11 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, else ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); + if (write_domain != 0) + intel_fb_obj_invalidate(obj, + write_domain == I915_GEM_DOMAIN_GTT ? + ORIGIN_GTT : ORIGIN_CPU); + unref: drm_gem_object_unreference(&obj->base); unlock: @@ -3982,9 +3987,6 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) obj->dirty = 1; } - if (write) - intel_fb_obj_invalidate(obj, ORIGIN_GTT); - trace_i915_gem_object_change_domain(obj, old_read_domains, old_write_domain); @@ -4256,9 +4258,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) obj->base.write_domain = I915_GEM_DOMAIN_CPU; } - if (write) - intel_fb_obj_invalidate(obj, ORIGIN_CPU); - trace_i915_gem_object_change_domain(obj, old_read_domains, old_write_domain); -- cgit v1.3-6-gb490 From a7a6c498927ea42c9a3b26e0caa5c854a980d58c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 22:00:01 +0300 Subject: drm/i915: POSTING_READ() in intel_set_memory_cxsr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want cxsr exit to happen ASAP, so toss in some POSTING_READ()s to make sure things are really kicked off. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 213da42d6c24..66a70966ed43 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -334,22 +334,27 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable) if (IS_VALLEYVIEW(dev)) { I915_WRITE(FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0); + POSTING_READ(FW_BLC_SELF_VLV); if (IS_CHERRYVIEW(dev)) chv_set_memory_pm5(dev_priv, enable); } else if (IS_G4X(dev) || IS_CRESTLINE(dev)) { I915_WRITE(FW_BLC_SELF, enable ? FW_BLC_SELF_EN : 0); + POSTING_READ(FW_BLC_SELF); } else if (IS_PINEVIEW(dev)) { val = I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN; val |= enable ? PINEVIEW_SELF_REFRESH_EN : 0; I915_WRITE(DSPFW3, val); + POSTING_READ(DSPFW3); } else if (IS_I945G(dev) || IS_I945GM(dev)) { val = enable ? _MASKED_BIT_ENABLE(FW_BLC_SELF_EN) : _MASKED_BIT_DISABLE(FW_BLC_SELF_EN); I915_WRITE(FW_BLC_SELF, val); + POSTING_READ(FW_BLC_SELF); } else if (IS_I915GM(dev)) { val = enable ? _MASKED_BIT_ENABLE(INSTPM_SELF_EN) : _MASKED_BIT_DISABLE(INSTPM_SELF_EN); I915_WRITE(INSTPM, val); + POSTING_READ(INSTPM); } else { return; } -- cgit v1.3-6-gb490 From f015c5518879fb3e578caaa63806617468a24045 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 22:00:02 +0300 Subject: drm/i915: Split atomic wm update to pre and post variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Try to update the watermarks on the right side of the plane update. This is just a temporary hack until we get the proper two part update into place. However in the meantime this might have some chance of at least working. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 15 +++++++++++---- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index eb665d7ffda7..8024e7a30eed 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4722,6 +4722,9 @@ static void intel_post_plane_update(struct intel_crtc *crtc) intel_frontbuffer_flip(dev, atomic->fb_bits); + if (crtc->atomic.update_wm_post) + intel_update_watermarks(&crtc->base); + if (atomic->update_fbc) { mutex_lock(&dev->struct_mutex); intel_fbc_update(dev); @@ -11606,8 +11609,12 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, plane->base.id, was_visible, visible, turn_off, turn_on, mode_changed); - if (intel_wm_need_update(plane, plane_state)) - intel_crtc->atomic.update_wm = true; + if (turn_on) + intel_crtc->atomic.update_wm_pre = true; + else if (turn_off) + intel_crtc->atomic.update_wm_post = true; + else if (intel_wm_need_update(plane, plane_state)) + intel_crtc->atomic.update_wm_pre = true; if (visible) intel_crtc->atomic.fb_bits |= @@ -11776,7 +11783,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, intel_crtc_check_initial_planes(crtc, crtc_state); if (mode_changed) - intel_crtc->atomic.update_wm = !crtc_state->active; + intel_crtc->atomic.update_wm_post = !crtc_state->active; if (mode_changed && crtc_state->enable && dev_priv->display.crtc_compute_clock && @@ -13705,7 +13712,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) if (!needs_modeset(crtc->state)) intel_pre_plane_update(intel_crtc); - if (intel_crtc->atomic.update_wm) + if (intel_crtc->atomic.update_wm_pre) intel_update_watermarks(crtc); intel_runtime_pm_get(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 33cff9d9a7a1..a02bdfbc6acc 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -500,7 +500,7 @@ struct intel_crtc_atomic_commit { bool disable_fbc; bool disable_ips; bool pre_disable_primary; - bool update_wm; + bool update_wm_pre, update_wm_post; unsigned disabled_planes; /* Sleepable operations to perform after commit */ -- cgit v1.3-6-gb490 From 6eb1a6817246f1a67de4d6959a84d09efead5329 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 22:00:03 +0300 Subject: drm/i915: Read wm values from hardware at init on CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read out the current watermark settings from the hardware at driver init time. This will allow us to compare the newly calculated values against the currrent ones and potentially avoid needless WM updates. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_display.c | 4 +- drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_pm.c | 141 +++++++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ea9caf22283f..2009ba516334 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1515,6 +1515,8 @@ struct vlv_wm_values { uint8_t sprite[2]; uint8_t primary; } ddl[3]; + uint8_t level; + bool cxsr; }; struct skl_ddb_entry { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8024e7a30eed..2295f08ac0b6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15453,7 +15453,9 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, pll->on = false; } - if (IS_GEN9(dev)) + if (IS_CHERRYVIEW(dev)) + vlv_wm_get_hw_state(dev); + else if (IS_GEN9(dev)) skl_wm_get_hw_state(dev); else if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a02bdfbc6acc..e7a82dcfda24 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -583,6 +583,7 @@ struct intel_plane_wm_parameters { bool scaled; u64 tiling; unsigned int rotation; + uint16_t fifo_size; }; struct intel_plane { @@ -1368,6 +1369,7 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv, unsigned long submitted); void intel_queue_rps_boost_for_request(struct drm_device *dev, struct drm_i915_gem_request *req); +void vlv_wm_get_hw_state(struct drm_device *dev); void ilk_wm_get_hw_state(struct drm_device *dev); void skl_wm_get_hw_state(struct drm_device *dev); void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 66a70966ed43..8ea4768dcf10 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1006,6 +1006,14 @@ static int vlv_compute_wm(struct intel_crtc *crtc, return fifo_size - clamp(DIV_ROUND_UP(256 * entries, 64), 0, fifo_size - 8); } +enum vlv_wm_level { + VLV_WM_LEVEL_PM2, + VLV_WM_LEVEL_PM5, + VLV_WM_LEVEL_DDR_DVFS, + CHV_WM_NUM_LEVELS, + VLV_WM_NUM_LEVELS = 1, +}; + static bool vlv_compute_sr_wm(struct drm_device *dev, struct vlv_wm_values *wm) { @@ -3689,6 +3697,139 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) } } +#define _FW_WM(value, plane) \ + (((value) & DSPFW_ ## plane ## _MASK) >> DSPFW_ ## plane ## _SHIFT) +#define _FW_WM_VLV(value, plane) \ + (((value) & DSPFW_ ## plane ## _MASK_VLV) >> DSPFW_ ## plane ## _SHIFT) + +static void vlv_read_wm_values(struct drm_i915_private *dev_priv, + struct vlv_wm_values *wm) +{ + enum pipe pipe; + uint32_t tmp; + + for_each_pipe(dev_priv, pipe) { + tmp = I915_READ(VLV_DDL(pipe)); + + wm->ddl[pipe].primary = + (tmp >> DDL_PLANE_SHIFT) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK); + wm->ddl[pipe].cursor = + (tmp >> DDL_CURSOR_SHIFT) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK); + wm->ddl[pipe].sprite[0] = + (tmp >> DDL_SPRITE_SHIFT(0)) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK); + wm->ddl[pipe].sprite[1] = + (tmp >> DDL_SPRITE_SHIFT(1)) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK); + } + + tmp = I915_READ(DSPFW1); + wm->sr.plane = _FW_WM(tmp, SR); + wm->pipe[PIPE_B].cursor = _FW_WM(tmp, CURSORB); + wm->pipe[PIPE_B].primary = _FW_WM_VLV(tmp, PLANEB); + wm->pipe[PIPE_A].primary = _FW_WM_VLV(tmp, PLANEA); + + tmp = I915_READ(DSPFW2); + wm->pipe[PIPE_A].sprite[1] = _FW_WM_VLV(tmp, SPRITEB); + wm->pipe[PIPE_A].cursor = _FW_WM(tmp, CURSORA); + wm->pipe[PIPE_A].sprite[0] = _FW_WM_VLV(tmp, SPRITEA); + + tmp = I915_READ(DSPFW3); + wm->sr.cursor = _FW_WM(tmp, CURSOR_SR); + + if (IS_CHERRYVIEW(dev_priv)) { + tmp = I915_READ(DSPFW7_CHV); + wm->pipe[PIPE_B].sprite[1] = _FW_WM_VLV(tmp, SPRITED); + wm->pipe[PIPE_B].sprite[0] = _FW_WM_VLV(tmp, SPRITEC); + + tmp = I915_READ(DSPFW8_CHV); + wm->pipe[PIPE_C].sprite[1] = _FW_WM_VLV(tmp, SPRITEF); + wm->pipe[PIPE_C].sprite[0] = _FW_WM_VLV(tmp, SPRITEE); + + tmp = I915_READ(DSPFW9_CHV); + wm->pipe[PIPE_C].primary = _FW_WM_VLV(tmp, PLANEC); + wm->pipe[PIPE_C].cursor = _FW_WM(tmp, CURSORC); + + tmp = I915_READ(DSPHOWM); + wm->sr.plane |= _FW_WM(tmp, SR_HI) << 9; + wm->pipe[PIPE_C].sprite[1] |= _FW_WM(tmp, SPRITEF_HI) << 8; + wm->pipe[PIPE_C].sprite[0] |= _FW_WM(tmp, SPRITEE_HI) << 8; + wm->pipe[PIPE_C].primary |= _FW_WM(tmp, PLANEC_HI) << 8; + wm->pipe[PIPE_B].sprite[1] |= _FW_WM(tmp, SPRITED_HI) << 8; + wm->pipe[PIPE_B].sprite[0] |= _FW_WM(tmp, SPRITEC_HI) << 8; + wm->pipe[PIPE_B].primary |= _FW_WM(tmp, PLANEB_HI) << 8; + wm->pipe[PIPE_A].sprite[1] |= _FW_WM(tmp, SPRITEB_HI) << 8; + wm->pipe[PIPE_A].sprite[0] |= _FW_WM(tmp, SPRITEA_HI) << 8; + wm->pipe[PIPE_A].primary |= _FW_WM(tmp, PLANEA_HI) << 8; + } else { + tmp = I915_READ(DSPFW7); + wm->pipe[PIPE_B].sprite[1] = _FW_WM_VLV(tmp, SPRITED); + wm->pipe[PIPE_B].sprite[0] = _FW_WM_VLV(tmp, SPRITEC); + + tmp = I915_READ(DSPHOWM); + wm->sr.plane |= _FW_WM(tmp, SR_HI) << 9; + wm->pipe[PIPE_B].sprite[1] |= _FW_WM(tmp, SPRITED_HI) << 8; + wm->pipe[PIPE_B].sprite[0] |= _FW_WM(tmp, SPRITEC_HI) << 8; + wm->pipe[PIPE_B].primary |= _FW_WM(tmp, PLANEB_HI) << 8; + wm->pipe[PIPE_A].sprite[1] |= _FW_WM(tmp, SPRITEB_HI) << 8; + wm->pipe[PIPE_A].sprite[0] |= _FW_WM(tmp, SPRITEA_HI) << 8; + wm->pipe[PIPE_A].primary |= _FW_WM(tmp, PLANEA_HI) << 8; + } +} + +#undef _FW_WM +#undef _FW_WM_VLV + +void vlv_wm_get_hw_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + struct vlv_wm_values *wm = &dev_priv->wm.vlv; + struct intel_plane *plane; + enum pipe pipe; + u32 val; + + vlv_read_wm_values(dev_priv, wm); + + for_each_intel_plane(dev, plane) { + switch (plane->base.type) { + int sprite; + case DRM_PLANE_TYPE_CURSOR: + plane->wm.fifo_size = 63; + break; + case DRM_PLANE_TYPE_PRIMARY: + plane->wm.fifo_size = vlv_get_fifo_size(dev, plane->pipe, 0); + break; + case DRM_PLANE_TYPE_OVERLAY: + sprite = plane->plane; + plane->wm.fifo_size = vlv_get_fifo_size(dev, plane->pipe, sprite + 1); + break; + } + } + + wm->cxsr = I915_READ(FW_BLC_SELF_VLV) & FW_CSPWRDWNEN; + wm->level = VLV_WM_LEVEL_PM2; + + if (IS_CHERRYVIEW(dev_priv)) { + mutex_lock(&dev_priv->rps.hw_lock); + + val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ); + if (val & DSP_MAXFIFO_PM5_ENABLE) + wm->level = VLV_WM_LEVEL_PM5; + + val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2); + if ((val & FORCE_DDR_HIGH_FREQ) == 0) + wm->level = VLV_WM_LEVEL_DDR_DVFS; + + mutex_unlock(&dev_priv->rps.hw_lock); + } + + for_each_pipe(dev_priv, pipe) + DRM_DEBUG_KMS("Initial watermarks: pipe %c, plane=%d, cursor=%d, sprite0=%d, sprite1=%d\n", + pipe_name(pipe), wm->pipe[pipe].primary, wm->pipe[pipe].cursor, + wm->pipe[pipe].sprite[0], wm->pipe[pipe].sprite[1]); + + DRM_DEBUG_KMS("Initial watermarks: SR plane=%d, SR cursor=%d level=%d cxsr=%d\n", + wm->sr.plane, wm->sr.cursor, wm->level, wm->cxsr); +} + void ilk_wm_get_hw_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; -- cgit v1.3-6-gb490 From 262cd2e154c29dc3a235f68cc91e13d8f48e8002 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 22:00:04 +0300 Subject: drm/i915: CHV DDR DVFS support and another watermark rewrite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turns out the VLV/CHV system agent doesn't understand memory latencies, so trying to rely on the PND deadline mechanism is not going to fly especially when DDR DVFS is enabled. Currently we try to avoid the problems by lying to the system agent about the deadlines and setting the FIFO watermarks to 8 cachelines. This however leads to bad memory self refresh residency. So in order to satosfy everyone we'll just give up on the deadline scheme and program the watermarks old school based on the worst case memory latency. I've modelled this a bit on the ILK+ approach where we compute multiple sets of watermarks for each pipe (PM2,PM5,DDR DVFS) and when merge thet appropriate one later with the watermarks from other pipes. There isn't too much to merge actually since each pipe has a totally independent FIFO (well apart from the mess with the partially shared DSPARB registers), but still decopuling the pipes from each other seems like a good idea. Eventually we'll want to perform the watermark update in two phases around the plane update to avoid underruns due to the single buffered watermark registers. But that's still in limbo for ILK+ too, so I've not gone that far yet for VLV/CHV either. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 28 +-- drivers/gpu/drm/i915/intel_display.c | 6 +- drivers/gpu/drm/i915/intel_drv.h | 11 ++ drivers/gpu/drm/i915/intel_pm.c | 318 ++++++++++++++++++++++++++++++++++- 4 files changed, 345 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2009ba516334..6acc6504863b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -276,6 +276,12 @@ struct i915_hotplug { &dev->mode_config.plane_list, \ base.head) +#define for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) \ + list_for_each_entry(intel_plane, \ + &(dev)->mode_config.plane_list, \ + base.head) \ + if ((intel_plane)->pipe == (intel_crtc)->pipe) + #define for_each_intel_crtc(dev, intel_crtc) \ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) @@ -1498,18 +1504,20 @@ struct ilk_wm_values { enum intel_ddb_partitioning partitioning; }; -struct vlv_wm_values { - struct { - uint16_t primary; - uint16_t sprite[2]; - uint8_t cursor; - } pipe[3]; +struct vlv_pipe_wm { + uint16_t primary; + uint16_t sprite[2]; + uint8_t cursor; +}; - struct { - uint16_t plane; - uint8_t cursor; - } sr; +struct vlv_sr_wm { + uint16_t plane; + uint8_t cursor; +}; +struct vlv_wm_values { + struct vlv_pipe_wm pipe[3]; + struct vlv_sr_wm sr; struct { uint8_t cursor; uint8_t sprite[2]; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2295f08ac0b6..7baa45db9756 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4699,8 +4699,11 @@ intel_pre_disable_primary(struct drm_crtc *crtc) * event which is after the vblank start event, so we need to have a * wait-for-vblank between disabling the plane and the pipe. */ - if (HAS_GMCH_DISPLAY(dev)) + if (HAS_GMCH_DISPLAY(dev)) { intel_set_memory_cxsr(dev_priv, false); + dev_priv->wm.vlv.cxsr = false; + intel_wait_for_vblank(dev, pipe); + } /* * FIXME IPS should be fine as long as one plane is @@ -6017,7 +6020,6 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) intel_crtc_load_lut(crtc); - intel_update_watermarks(crtc); intel_enable_pipe(intel_crtc); assert_vblank_disabled(crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e7a82dcfda24..8397d1c9005b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -462,6 +462,15 @@ struct intel_crtc_state { enum pipe hsw_workaround_pipe; }; +struct vlv_wm_state { + struct vlv_pipe_wm wm[3]; + struct vlv_sr_wm sr[3]; + uint8_t num_active_planes; + uint8_t num_levels; + uint8_t level; + bool cxsr; +}; + struct intel_pipe_wm { struct intel_wm_level wm[5]; uint32_t linetime; @@ -565,6 +574,8 @@ struct intel_crtc { /* scalers available on this crtc */ int num_scalers; + + struct vlv_wm_state wm_state; }; struct intel_plane_wm_parameters { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8ea4768dcf10..23e5be9887a3 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -335,8 +335,6 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable) if (IS_VALLEYVIEW(dev)) { I915_WRITE(FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0); POSTING_READ(FW_BLC_SELF_VLV); - if (IS_CHERRYVIEW(dev)) - chv_set_memory_pm5(dev_priv, enable); } else if (IS_G4X(dev) || IS_CRESTLINE(dev)) { I915_WRITE(FW_BLC_SELF, enable ? FW_BLC_SELF_EN : 0); POSTING_READ(FW_BLC_SELF); @@ -929,8 +927,6 @@ static void vlv_write_wm_values(struct intel_crtc *crtc, } POSTING_READ(DSPFW1); - - dev_priv->wm.vlv = *wm; } #undef FW_WM_VLV @@ -1014,6 +1010,72 @@ enum vlv_wm_level { VLV_WM_NUM_LEVELS = 1, }; +/* latency must be in 0.1us units. */ +static unsigned int vlv_wm_method2(unsigned int pixel_rate, + unsigned int pipe_htotal, + unsigned int horiz_pixels, + unsigned int bytes_per_pixel, + unsigned int latency) +{ + unsigned int ret; + + ret = (latency * pixel_rate) / (pipe_htotal * 10000); + ret = (ret + 1) * horiz_pixels * bytes_per_pixel; + ret = DIV_ROUND_UP(ret, 64); + + return ret; +} + +static void vlv_setup_wm_latency(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* all latencies in usec */ + dev_priv->wm.pri_latency[VLV_WM_LEVEL_PM2] = 3; + + if (IS_CHERRYVIEW(dev_priv)) { + dev_priv->wm.pri_latency[VLV_WM_LEVEL_PM5] = 12; + dev_priv->wm.pri_latency[VLV_WM_LEVEL_DDR_DVFS] = 33; + } +} + +static uint16_t vlv_compute_wm_level(struct intel_plane *plane, + struct intel_crtc *crtc, + const struct intel_plane_state *state, + int level) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + int clock, htotal, pixel_size, width, wm; + + if (dev_priv->wm.pri_latency[level] == 0) + return USHRT_MAX; + + if (!state->visible) + return 0; + + pixel_size = drm_format_plane_cpp(state->base.fb->pixel_format, 0); + clock = crtc->config->base.adjusted_mode.crtc_clock; + htotal = crtc->config->base.adjusted_mode.crtc_htotal; + width = crtc->config->pipe_src_w; + if (WARN_ON(htotal == 0)) + htotal = 1; + + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) { + /* + * FIXME the formula gives values that are + * too big for the cursor FIFO, and hence we + * would never be able to use cursors. For + * now just hardcode the watermark. + */ + wm = 63; + } else { + wm = vlv_wm_method2(clock, htotal, width, pixel_size, + dev_priv->wm.pri_latency[level] * 10); + } + + return min_t(int, wm, USHRT_MAX); +} + static bool vlv_compute_sr_wm(struct drm_device *dev, struct vlv_wm_values *wm) { @@ -1105,6 +1167,249 @@ static void valleyview_update_wm(struct drm_crtc *crtc) if (cxsr_enabled) intel_set_memory_cxsr(dev_priv, true); + + dev_priv->wm.vlv = wm; +} + +static void vlv_invert_wms(struct intel_crtc *crtc) +{ + struct vlv_wm_state *wm_state = &crtc->wm_state; + int level; + + for (level = 0; level < wm_state->num_levels; level++) { + struct drm_device *dev = crtc->base.dev; + const int sr_fifo_size = INTEL_INFO(dev)->num_pipes * 512 - 1; + struct intel_plane *plane; + + wm_state->sr[level].plane = sr_fifo_size - wm_state->sr[level].plane; + wm_state->sr[level].cursor = 63 - wm_state->sr[level].cursor; + + for_each_intel_plane_on_crtc(dev, crtc, plane) { + switch (plane->base.type) { + int sprite; + case DRM_PLANE_TYPE_CURSOR: + wm_state->wm[level].cursor = plane->wm.fifo_size - + wm_state->wm[level].cursor; + break; + case DRM_PLANE_TYPE_PRIMARY: + wm_state->wm[level].primary = plane->wm.fifo_size - + wm_state->wm[level].primary; + break; + case DRM_PLANE_TYPE_OVERLAY: + sprite = plane->plane; + wm_state->wm[level].sprite[sprite] = plane->wm.fifo_size - + wm_state->wm[level].sprite[sprite]; + break; + } + } + } +} + +static void _vlv_compute_wm(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct vlv_wm_state *wm_state = &crtc->wm_state; + struct intel_plane *plane; + int sr_fifo_size = INTEL_INFO(dev)->num_pipes * 512 - 1; + int level; + + memset(wm_state, 0, sizeof(*wm_state)); + + wm_state->cxsr = crtc->pipe != PIPE_C; + if (IS_CHERRYVIEW(dev)) + wm_state->num_levels = CHV_WM_NUM_LEVELS; + else + wm_state->num_levels = VLV_WM_NUM_LEVELS; + + wm_state->num_active_planes = 0; + for_each_intel_plane_on_crtc(dev, crtc, plane) { + struct intel_plane_state *state = + to_intel_plane_state(plane->base.state); + + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) + continue; + + if (state->visible) + wm_state->num_active_planes++; + } + + if (wm_state->num_active_planes != 1) + wm_state->cxsr = false; + + if (wm_state->cxsr) { + for (level = 0; level < wm_state->num_levels; level++) { + wm_state->sr[level].plane = sr_fifo_size; + wm_state->sr[level].cursor = 63; + } + } + + for_each_intel_plane_on_crtc(dev, crtc, plane) { + struct intel_plane_state *state = + to_intel_plane_state(plane->base.state); + + if (!state->visible) + continue; + + /* normal watermarks */ + for (level = 0; level < wm_state->num_levels; level++) { + int wm = vlv_compute_wm_level(plane, crtc, state, level); + int max_wm = plane->base.type == DRM_PLANE_TYPE_CURSOR ? 63 : 511; + + /* hack */ + if (WARN_ON(level == 0 && wm > max_wm)) + wm = max_wm; + + if (wm > plane->wm.fifo_size) + break; + + switch (plane->base.type) { + int sprite; + case DRM_PLANE_TYPE_CURSOR: + wm_state->wm[level].cursor = wm; + break; + case DRM_PLANE_TYPE_PRIMARY: + wm_state->wm[level].primary = wm; + break; + case DRM_PLANE_TYPE_OVERLAY: + sprite = plane->plane; + wm_state->wm[level].sprite[sprite] = wm; + break; + } + } + + wm_state->num_levels = level; + + if (!wm_state->cxsr) + continue; + + /* maxfifo watermarks */ + switch (plane->base.type) { + int sprite, level; + case DRM_PLANE_TYPE_CURSOR: + for (level = 0; level < wm_state->num_levels; level++) + wm_state->sr[level].cursor = + wm_state->sr[level].cursor; + break; + case DRM_PLANE_TYPE_PRIMARY: + for (level = 0; level < wm_state->num_levels; level++) + wm_state->sr[level].plane = + min(wm_state->sr[level].plane, + wm_state->wm[level].primary); + break; + case DRM_PLANE_TYPE_OVERLAY: + sprite = plane->plane; + for (level = 0; level < wm_state->num_levels; level++) + wm_state->sr[level].plane = + min(wm_state->sr[level].plane, + wm_state->wm[level].sprite[sprite]); + break; + } + } + + /* clear any (partially) filled invalid levels */ + for (level = wm_state->num_levels; level < CHV_WM_NUM_LEVELS; level++) { + memset(&wm_state->wm[level], 0, sizeof(wm_state->wm[level])); + memset(&wm_state->sr[level], 0, sizeof(wm_state->sr[level])); + } + + vlv_invert_wms(crtc); +} + +static void vlv_merge_wm(struct drm_device *dev, + struct vlv_wm_values *wm) +{ + struct intel_crtc *crtc; + int num_active_crtcs = 0; + + if (IS_CHERRYVIEW(dev)) + wm->level = VLV_WM_LEVEL_DDR_DVFS; + else + wm->level = VLV_WM_LEVEL_PM2; + wm->cxsr = true; + + for_each_intel_crtc(dev, crtc) { + const struct vlv_wm_state *wm_state = &crtc->wm_state; + + if (!crtc->active) + continue; + + if (!wm_state->cxsr) + wm->cxsr = false; + + num_active_crtcs++; + wm->level = min_t(int, wm->level, wm_state->num_levels - 1); + } + + if (num_active_crtcs != 1) + wm->cxsr = false; + + for_each_intel_crtc(dev, crtc) { + struct vlv_wm_state *wm_state = &crtc->wm_state; + enum pipe pipe = crtc->pipe; + + if (!crtc->active) + continue; + + wm->pipe[pipe] = wm_state->wm[wm->level]; + if (wm->cxsr) + wm->sr = wm_state->sr[wm->level]; + + wm->ddl[pipe].primary = DDL_PRECISION_HIGH | 2; + wm->ddl[pipe].sprite[0] = DDL_PRECISION_HIGH | 2; + wm->ddl[pipe].sprite[1] = DDL_PRECISION_HIGH | 2; + wm->ddl[pipe].cursor = DDL_PRECISION_HIGH | 2; + } +} + +static void vlv_update_wm(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); + enum pipe pipe = intel_crtc->pipe; + struct vlv_wm_values wm = {}; + + _vlv_compute_wm(intel_crtc); + vlv_merge_wm(dev, &wm); + + if (memcmp(&dev_priv->wm.vlv, &wm, sizeof(wm)) == 0) + return; + + if (wm.level < VLV_WM_LEVEL_DDR_DVFS && + dev_priv->wm.vlv.level >= VLV_WM_LEVEL_DDR_DVFS) + chv_set_memory_dvfs(dev_priv, false); + + if (wm.level < VLV_WM_LEVEL_PM5 && + dev_priv->wm.vlv.level >= VLV_WM_LEVEL_PM5) + chv_set_memory_pm5(dev_priv, false); + + if (!wm.cxsr && dev_priv->wm.vlv.cxsr) { + intel_set_memory_cxsr(dev_priv, false); + intel_wait_for_vblank(dev, pipe); + } + + vlv_write_wm_values(intel_crtc, &wm); + + DRM_DEBUG_KMS("Setting FIFO watermarks - %c: plane=%d, cursor=%d, " + "sprite0=%d, sprite1=%d, SR: plane=%d, cursor=%d level=%d cxsr=%d\n", + pipe_name(pipe), wm.pipe[pipe].primary, wm.pipe[pipe].cursor, + wm.pipe[pipe].sprite[0], wm.pipe[pipe].sprite[1], + wm.sr.plane, wm.sr.cursor, wm.level, wm.cxsr); + + if (wm.cxsr && !dev_priv->wm.vlv.cxsr) { + intel_wait_for_vblank(dev, pipe); + intel_set_memory_cxsr(dev_priv, true); + } + + if (wm.level >= VLV_WM_LEVEL_PM5 && + dev_priv->wm.vlv.level < VLV_WM_LEVEL_PM5) + chv_set_memory_pm5(dev_priv, true); + + if (wm.level >= VLV_WM_LEVEL_DDR_DVFS && + dev_priv->wm.vlv.level < VLV_WM_LEVEL_DDR_DVFS) + chv_set_memory_dvfs(dev_priv, true); + + dev_priv->wm.vlv = wm; } static void valleyview_update_sprite_wm(struct drm_plane *plane, @@ -6831,8 +7136,9 @@ void intel_init_pm(struct drm_device *dev) else if (INTEL_INFO(dev)->gen == 8) dev_priv->display.init_clock_gating = broadwell_init_clock_gating; } else if (IS_CHERRYVIEW(dev)) { - dev_priv->display.update_wm = valleyview_update_wm; - dev_priv->display.update_sprite_wm = valleyview_update_sprite_wm; + vlv_setup_wm_latency(dev); + + dev_priv->display.update_wm = vlv_update_wm; dev_priv->display.init_clock_gating = cherryview_init_clock_gating; } else if (IS_VALLEYVIEW(dev)) { -- cgit v1.3-6-gb490 From 54f1b6e15db87722aa21035169ce811af9d971fd Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 22:00:05 +0300 Subject: drm/i915: Compute display FIFO split dynamically for CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consider which planes are active and compute the FIFO split based on the relative data rates. Since we only consider the pipe src width rather than the plane width when computing watermarks it seems best to do the same when computing the FIFO split as well. This means the only thing we actually have to consider for the FIFO splut is the bpp, and we can ignore the rest. I've just stuffed the logic into the watermark code for now. Eventually it'll need to move into the atomic update for the crtc. There's also one extra complication I've not yet considered; Some of the DSPARB registers contain bits related to multiple pipes. The registers are double buffered but apparently they update on the vblank of any active pipe. So doing the FIFO reconfiguration properly when multiple pipes are active is not going to be fun. But let's ignore that mess for now. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 25 +++++- drivers/gpu/drm/i915/intel_pm.c | 175 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 189 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b6c8037a9e54..50e6279d7d56 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4415,9 +4415,32 @@ enum skl_disp_power_wells { #define DSPARB_BSTART_SHIFT 0 #define DSPARB_BEND_SHIFT 9 /* on 855 */ #define DSPARB_AEND_SHIFT 0 - +#define DSPARB_SPRITEA_SHIFT_VLV 0 +#define DSPARB_SPRITEA_MASK_VLV (0xff << 0) +#define DSPARB_SPRITEB_SHIFT_VLV 8 +#define DSPARB_SPRITEB_MASK_VLV (0xff << 8) +#define DSPARB_SPRITEC_SHIFT_VLV 16 +#define DSPARB_SPRITEC_MASK_VLV (0xff << 16) +#define DSPARB_SPRITED_SHIFT_VLV 24 +#define DSPARB_SPRITED_MASK_VLV (0xff << 24) #define DSPARB2 (VLV_DISPLAY_BASE + 0x70060) /* vlv/chv */ +#define DSPARB_SPRITEA_HI_SHIFT_VLV 0 +#define DSPARB_SPRITEA_HI_MASK_VLV (0x1 << 0) +#define DSPARB_SPRITEB_HI_SHIFT_VLV 4 +#define DSPARB_SPRITEB_HI_MASK_VLV (0x1 << 4) +#define DSPARB_SPRITEC_HI_SHIFT_VLV 8 +#define DSPARB_SPRITEC_HI_MASK_VLV (0x1 << 8) +#define DSPARB_SPRITED_HI_SHIFT_VLV 12 +#define DSPARB_SPRITED_HI_MASK_VLV (0x1 << 12) +#define DSPARB_SPRITEE_HI_SHIFT_VLV 16 +#define DSPARB_SPRITEE_HI_MASK_VLV (0x1 << 16) +#define DSPARB_SPRITEF_HI_SHIFT_VLV 20 +#define DSPARB_SPRITEF_HI_MASK_VLV (0x1 << 20) #define DSPARB3 (VLV_DISPLAY_BASE + 0x7006c) /* chv */ +#define DSPARB_SPRITEE_SHIFT_VLV 0 +#define DSPARB_SPRITEE_MASK_VLV (0xff << 0) +#define DSPARB_SPRITEF_SHIFT_VLV 8 +#define DSPARB_SPRITEF_MASK_VLV (0xff << 8) /* pnv/gen4/g4x/vlv/chv */ #define DSPFW1 (dev_priv->info.display_mmio_offset + 0x70034) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 23e5be9887a3..49cca0b16cc6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1171,6 +1171,73 @@ static void valleyview_update_wm(struct drm_crtc *crtc) dev_priv->wm.vlv = wm; } +static void vlv_compute_fifo(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct vlv_wm_state *wm_state = &crtc->wm_state; + struct intel_plane *plane; + unsigned int total_rate = 0; + const int fifo_size = 512 - 1; + int fifo_extra, fifo_left = fifo_size; + + for_each_intel_plane_on_crtc(dev, crtc, plane) { + struct intel_plane_state *state = + to_intel_plane_state(plane->base.state); + + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) + continue; + + if (state->visible) { + wm_state->num_active_planes++; + total_rate += drm_format_plane_cpp(state->base.fb->pixel_format, 0); + } + } + + for_each_intel_plane_on_crtc(dev, crtc, plane) { + struct intel_plane_state *state = + to_intel_plane_state(plane->base.state); + unsigned int rate; + + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) { + plane->wm.fifo_size = 63; + continue; + } + + if (!state->visible) { + plane->wm.fifo_size = 0; + continue; + } + + rate = drm_format_plane_cpp(state->base.fb->pixel_format, 0); + plane->wm.fifo_size = fifo_size * rate / total_rate; + fifo_left -= plane->wm.fifo_size; + } + + fifo_extra = DIV_ROUND_UP(fifo_left, wm_state->num_active_planes ?: 1); + + /* spread the remainder evenly */ + for_each_intel_plane_on_crtc(dev, crtc, plane) { + int plane_extra; + + if (fifo_left == 0) + break; + + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) + continue; + + /* give it all to the first plane if none are active */ + if (plane->wm.fifo_size == 0 && + wm_state->num_active_planes) + continue; + + plane_extra = min(fifo_extra, fifo_left); + plane->wm.fifo_size += plane_extra; + fifo_left -= plane_extra; + } + + WARN_ON(fifo_left != 0); +} + static void vlv_invert_wms(struct intel_crtc *crtc) { struct vlv_wm_state *wm_state = &crtc->wm_state; @@ -1222,16 +1289,8 @@ static void _vlv_compute_wm(struct intel_crtc *crtc) wm_state->num_levels = VLV_WM_NUM_LEVELS; wm_state->num_active_planes = 0; - for_each_intel_plane_on_crtc(dev, crtc, plane) { - struct intel_plane_state *state = - to_intel_plane_state(plane->base.state); - - if (plane->base.type == DRM_PLANE_TYPE_CURSOR) - continue; - if (state->visible) - wm_state->num_active_planes++; - } + vlv_compute_fifo(crtc); if (wm_state->num_active_planes != 1) wm_state->cxsr = false; @@ -1315,6 +1374,96 @@ static void _vlv_compute_wm(struct intel_crtc *crtc) vlv_invert_wms(crtc); } +#define VLV_FIFO(plane, value) \ + (((value) << DSPARB_ ## plane ## _SHIFT_VLV) & DSPARB_ ## plane ## _MASK_VLV) + +static void vlv_pipe_set_fifo_size(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_plane *plane; + int sprite0_start = 0, sprite1_start = 0, fifo_size = 0; + + for_each_intel_plane_on_crtc(dev, crtc, plane) { + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) { + WARN_ON(plane->wm.fifo_size != 63); + continue; + } + + if (plane->base.type == DRM_PLANE_TYPE_PRIMARY) + sprite0_start = plane->wm.fifo_size; + else if (plane->plane == 0) + sprite1_start = sprite0_start + plane->wm.fifo_size; + else + fifo_size = sprite1_start + plane->wm.fifo_size; + } + + WARN_ON(fifo_size != 512 - 1); + + DRM_DEBUG_KMS("Pipe %c FIFO split %d / %d / %d\n", + pipe_name(crtc->pipe), sprite0_start, + sprite1_start, fifo_size); + + switch (crtc->pipe) { + uint32_t dsparb, dsparb2, dsparb3; + case PIPE_A: + dsparb = I915_READ(DSPARB); + dsparb2 = I915_READ(DSPARB2); + + dsparb &= ~(VLV_FIFO(SPRITEA, 0xff) | + VLV_FIFO(SPRITEB, 0xff)); + dsparb |= (VLV_FIFO(SPRITEA, sprite0_start) | + VLV_FIFO(SPRITEB, sprite1_start)); + + dsparb2 &= ~(VLV_FIFO(SPRITEA_HI, 0x1) | + VLV_FIFO(SPRITEB_HI, 0x1)); + dsparb2 |= (VLV_FIFO(SPRITEA_HI, sprite0_start >> 8) | + VLV_FIFO(SPRITEB_HI, sprite1_start >> 8)); + + I915_WRITE(DSPARB, dsparb); + I915_WRITE(DSPARB2, dsparb2); + break; + case PIPE_B: + dsparb = I915_READ(DSPARB); + dsparb2 = I915_READ(DSPARB2); + + dsparb &= ~(VLV_FIFO(SPRITEC, 0xff) | + VLV_FIFO(SPRITED, 0xff)); + dsparb |= (VLV_FIFO(SPRITEC, sprite0_start) | + VLV_FIFO(SPRITED, sprite1_start)); + + dsparb2 &= ~(VLV_FIFO(SPRITEC_HI, 0xff) | + VLV_FIFO(SPRITED_HI, 0xff)); + dsparb2 |= (VLV_FIFO(SPRITEC_HI, sprite0_start >> 8) | + VLV_FIFO(SPRITED_HI, sprite1_start >> 8)); + + I915_WRITE(DSPARB, dsparb); + I915_WRITE(DSPARB2, dsparb2); + break; + case PIPE_C: + dsparb3 = I915_READ(DSPARB3); + dsparb2 = I915_READ(DSPARB2); + + dsparb3 &= ~(VLV_FIFO(SPRITEE, 0xff) | + VLV_FIFO(SPRITEF, 0xff)); + dsparb3 |= (VLV_FIFO(SPRITEE, sprite0_start) | + VLV_FIFO(SPRITEF, sprite1_start)); + + dsparb2 &= ~(VLV_FIFO(SPRITEE_HI, 0xff) | + VLV_FIFO(SPRITEF_HI, 0xff)); + dsparb2 |= (VLV_FIFO(SPRITEE_HI, sprite0_start >> 8) | + VLV_FIFO(SPRITEF_HI, sprite1_start >> 8)); + + I915_WRITE(DSPARB3, dsparb3); + I915_WRITE(DSPARB2, dsparb2); + break; + default: + break; + } +} + +#undef VLV_FIFO + static void vlv_merge_wm(struct drm_device *dev, struct vlv_wm_values *wm) { @@ -1372,8 +1521,11 @@ static void vlv_update_wm(struct drm_crtc *crtc) _vlv_compute_wm(intel_crtc); vlv_merge_wm(dev, &wm); - if (memcmp(&dev_priv->wm.vlv, &wm, sizeof(wm)) == 0) + if (memcmp(&dev_priv->wm.vlv, &wm, sizeof(wm)) == 0) { + /* FIXME should be part of crtc atomic commit */ + vlv_pipe_set_fifo_size(intel_crtc); return; + } if (wm.level < VLV_WM_LEVEL_DDR_DVFS && dev_priv->wm.vlv.level >= VLV_WM_LEVEL_DDR_DVFS) @@ -1388,6 +1540,9 @@ static void vlv_update_wm(struct drm_crtc *crtc) intel_wait_for_vblank(dev, pipe); } + /* FIXME should be part of crtc atomic commit */ + vlv_pipe_set_fifo_size(intel_crtc); + vlv_write_wm_values(intel_crtc, &wm); DRM_DEBUG_KMS("Setting FIFO watermarks - %c: plane=%d, cursor=%d, " -- cgit v1.3-6-gb490 From 26e1fe4fbd4c15919f8cfa9440d70eca5a457ba3 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 22:00:06 +0300 Subject: drm/i915: Use the memory latency based WM computation on VLV too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to get decnet memory self refresh residency on VLV, flip it over to the new CHV way of doing things. VLV doesn't do PM5 or DDR DVFS so it's a bit simpler. I'm not sure the currently memory latency used for CHV is really appropriate for VLV. Some further testing will probably be needed to figure that out. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 223 +---------------------------------- drivers/gpu/drm/i915/intel_sprite.c | 6 - 3 files changed, 6 insertions(+), 225 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7baa45db9756..649c5dba5463 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15455,7 +15455,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, pll->on = false; } - if (IS_CHERRYVIEW(dev)) + if (IS_VALLEYVIEW(dev)) vlv_wm_get_hw_state(dev); else if (IS_GEN9(dev)) skl_wm_get_hw_state(dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 49cca0b16cc6..0cccc44e1828 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -931,77 +931,6 @@ static void vlv_write_wm_values(struct intel_crtc *crtc, #undef FW_WM_VLV -static uint8_t vlv_compute_drain_latency(struct drm_crtc *crtc, - struct drm_plane *plane) -{ - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int entries, prec_mult, drain_latency, pixel_size; - int clock = intel_crtc->config->base.adjusted_mode.crtc_clock; - const int high_precision = IS_CHERRYVIEW(dev) ? 16 : 64; - - /* - * FIXME the plane might have an fb - * but be invisible (eg. due to clipping) - */ - if (!intel_crtc->active || !plane->state->fb) - return 0; - - if (WARN(clock == 0, "Pixel clock is zero!\n")) - return 0; - - pixel_size = drm_format_plane_cpp(plane->state->fb->pixel_format, 0); - - if (WARN(pixel_size == 0, "Pixel size is zero!\n")) - return 0; - - entries = DIV_ROUND_UP(clock, 1000) * pixel_size; - - prec_mult = high_precision; - drain_latency = 64 * prec_mult * 4 / entries; - - if (drain_latency > DRAIN_LATENCY_MASK) { - prec_mult /= 2; - drain_latency = 64 * prec_mult * 4 / entries; - } - - if (drain_latency > DRAIN_LATENCY_MASK) - drain_latency = DRAIN_LATENCY_MASK; - - return drain_latency | (prec_mult == high_precision ? - DDL_PRECISION_HIGH : DDL_PRECISION_LOW); -} - -static int vlv_compute_wm(struct intel_crtc *crtc, - struct intel_plane *plane, - int fifo_size) -{ - int clock, entries, pixel_size; - - /* - * FIXME the plane might have an fb - * but be invisible (eg. due to clipping) - */ - if (!crtc->active || !plane->base.state->fb) - return 0; - - pixel_size = drm_format_plane_cpp(plane->base.state->fb->pixel_format, 0); - clock = crtc->config->base.adjusted_mode.crtc_clock; - - entries = DIV_ROUND_UP(clock, 1000) * pixel_size; - - /* - * Set up the watermark such that we don't start issuing memory - * requests until we are within PND's max deadline value (256us). - * Idea being to be idle as long as possible while still taking - * advatange of PND's deadline scheduling. The limit of 8 - * cachelines (used when the FIFO will anyway drain in less time - * than 256us) should match what we would be done if trickle - * feed were enabled. - */ - return fifo_size - clamp(DIV_ROUND_UP(256 * entries, 64), 0, fifo_size - 8); -} - enum vlv_wm_level { VLV_WM_LEVEL_PM2, VLV_WM_LEVEL_PM5, @@ -1076,101 +1005,6 @@ static uint16_t vlv_compute_wm_level(struct intel_plane *plane, return min_t(int, wm, USHRT_MAX); } -static bool vlv_compute_sr_wm(struct drm_device *dev, - struct vlv_wm_values *wm) -{ - struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_crtc *crtc; - enum pipe pipe = INVALID_PIPE; - int num_planes = 0; - int fifo_size = 0; - struct intel_plane *plane; - - wm->sr.cursor = wm->sr.plane = 0; - - crtc = single_enabled_crtc(dev); - /* maxfifo not supported on pipe C */ - if (crtc && to_intel_crtc(crtc)->pipe != PIPE_C) { - pipe = to_intel_crtc(crtc)->pipe; - num_planes = !!wm->pipe[pipe].primary + - !!wm->pipe[pipe].sprite[0] + - !!wm->pipe[pipe].sprite[1]; - fifo_size = INTEL_INFO(dev_priv)->num_pipes * 512 - 1; - } - - if (fifo_size == 0 || num_planes > 1) - return false; - - wm->sr.cursor = vlv_compute_wm(to_intel_crtc(crtc), - to_intel_plane(crtc->cursor), 0x3f); - - list_for_each_entry(plane, &dev->mode_config.plane_list, base.head) { - if (plane->base.type == DRM_PLANE_TYPE_CURSOR) - continue; - - if (plane->pipe != pipe) - continue; - - wm->sr.plane = vlv_compute_wm(to_intel_crtc(crtc), - plane, fifo_size); - if (wm->sr.plane != 0) - break; - } - - return true; -} - -static void valleyview_update_wm(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); - enum pipe pipe = intel_crtc->pipe; - bool cxsr_enabled; - struct vlv_wm_values wm = dev_priv->wm.vlv; - - wm.ddl[pipe].primary = vlv_compute_drain_latency(crtc, crtc->primary); - wm.pipe[pipe].primary = vlv_compute_wm(intel_crtc, - to_intel_plane(crtc->primary), - vlv_get_fifo_size(dev, pipe, 0)); - - wm.ddl[pipe].cursor = vlv_compute_drain_latency(crtc, crtc->cursor); - wm.pipe[pipe].cursor = vlv_compute_wm(intel_crtc, - to_intel_plane(crtc->cursor), - 0x3f); - - cxsr_enabled = vlv_compute_sr_wm(dev, &wm); - - if (memcmp(&wm, &dev_priv->wm.vlv, sizeof(wm)) == 0) - return; - - DRM_DEBUG_KMS("Setting FIFO watermarks - %c: plane=%d, cursor=%d, " - "SR: plane=%d, cursor=%d\n", pipe_name(pipe), - wm.pipe[pipe].primary, wm.pipe[pipe].cursor, - wm.sr.plane, wm.sr.cursor); - - /* - * FIXME DDR DVFS introduces massive memory latencies which - * are not known to system agent so any deadline specified - * by the display may not be respected. To support DDR DVFS - * the watermark code needs to be rewritten to essentially - * bypass deadline mechanism and rely solely on the - * watermarks. For now disable DDR DVFS. - */ - if (IS_CHERRYVIEW(dev_priv)) - chv_set_memory_dvfs(dev_priv, false); - - if (!cxsr_enabled) - intel_set_memory_cxsr(dev_priv, false); - - vlv_write_wm_values(intel_crtc, &wm); - - if (cxsr_enabled) - intel_set_memory_cxsr(dev_priv, true); - - dev_priv->wm.vlv = wm; -} - static void vlv_compute_fifo(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; @@ -1272,7 +1106,7 @@ static void vlv_invert_wms(struct intel_crtc *crtc) } } -static void _vlv_compute_wm(struct intel_crtc *crtc) +static void vlv_compute_wm(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct vlv_wm_state *wm_state = &crtc->wm_state; @@ -1518,7 +1352,7 @@ static void vlv_update_wm(struct drm_crtc *crtc) enum pipe pipe = intel_crtc->pipe; struct vlv_wm_values wm = {}; - _vlv_compute_wm(intel_crtc); + vlv_compute_wm(intel_crtc); vlv_merge_wm(dev, &wm); if (memcmp(&dev_priv->wm.vlv, &wm, sizeof(wm)) == 0) { @@ -1567,54 +1401,6 @@ static void vlv_update_wm(struct drm_crtc *crtc) dev_priv->wm.vlv = wm; } -static void valleyview_update_sprite_wm(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, - uint32_t sprite_height, - int pixel_size, - bool enabled, bool scaled) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; - int sprite = to_intel_plane(plane)->plane; - bool cxsr_enabled; - struct vlv_wm_values wm = dev_priv->wm.vlv; - - if (enabled) { - wm.ddl[pipe].sprite[sprite] = - vlv_compute_drain_latency(crtc, plane); - - wm.pipe[pipe].sprite[sprite] = - vlv_compute_wm(intel_crtc, - to_intel_plane(plane), - vlv_get_fifo_size(dev, pipe, sprite+1)); - } else { - wm.ddl[pipe].sprite[sprite] = 0; - wm.pipe[pipe].sprite[sprite] = 0; - } - - cxsr_enabled = vlv_compute_sr_wm(dev, &wm); - - if (memcmp(&wm, &dev_priv->wm.vlv, sizeof(wm)) == 0) - return; - - DRM_DEBUG_KMS("Setting FIFO watermarks - %c: sprite %c=%d, " - "SR: plane=%d, cursor=%d\n", pipe_name(pipe), - sprite_name(pipe, sprite), - wm.pipe[pipe].sprite[sprite], - wm.sr.plane, wm.sr.cursor); - - if (!cxsr_enabled) - intel_set_memory_cxsr(dev_priv, false); - - vlv_write_wm_values(intel_crtc, &wm); - - if (cxsr_enabled) - intel_set_memory_cxsr(dev_priv, true); -} - #define single_plane_enabled(mask) is_power_of_2(mask) static void g4x_update_wm(struct drm_crtc *crtc) @@ -7297,8 +7083,9 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.init_clock_gating = cherryview_init_clock_gating; } else if (IS_VALLEYVIEW(dev)) { - dev_priv->display.update_wm = valleyview_update_wm; - dev_priv->display.update_sprite_wm = valleyview_update_sprite_wm; + vlv_setup_wm_latency(dev); + + dev_priv->display.update_wm = vlv_update_wm; dev_priv->display.init_clock_gating = valleyview_init_clock_gating; } else if (IS_PINEVIEW(dev)) { diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 16be667cc5eb..cd21525df352 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -402,10 +402,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, if (obj->tiling_mode != I915_TILING_NONE) sprctl |= SP_TILED; - intel_update_sprite_watermarks(dplane, crtc, src_w, src_h, - pixel_size, true, - src_w != crtc_w || src_h != crtc_h); - /* Sizes are 0 based */ src_w--; src_h--; @@ -470,8 +466,6 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) I915_WRITE(SPSURF(pipe, plane), 0); POSTING_READ(SPSURF(pipe, plane)); - - intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false); } static void -- cgit v1.3-6-gb490 From 852eb00dc44ea2b8896e2fa27c6a36a1f697ba5a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 22:00:07 +0300 Subject: drm/i915: Try to make sure cxsr is disabled around plane enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CxSR (or maxfifo on VLV/CHV) blocks somne changes to the plane control register (enable bit at least, not quite sure about the rest). So in order to have the plane enable/disable when we want we need to first kick the hardware out of cxsr. Unfortunateloy this requires some extra vblank waits. For the CxSR enable after the plane update we should eventually use an async vblank worker, but since we don't have that just do sync vblank waits. For the disable case we have no choice but to do it synchronously. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 36 +++++++++++++++++++++++++++++++----- drivers/gpu/drm/i915/intel_drv.h | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 11 ++++------- 3 files changed, 38 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 649c5dba5463..b7d42e6aac10 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4725,6 +4725,9 @@ static void intel_post_plane_update(struct intel_crtc *crtc) intel_frontbuffer_flip(dev, atomic->fb_bits); + if (atomic->disable_cxsr) + crtc->wm.cxsr_allowed = true; + if (crtc->atomic.update_wm_post) intel_update_watermarks(&crtc->base); @@ -4777,6 +4780,11 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) if (atomic->pre_disable_primary) intel_pre_disable_primary(&crtc->base); + + if (atomic->disable_cxsr) { + crtc->wm.cxsr_allowed = false; + intel_set_memory_cxsr(dev_priv, false); + } } static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask) @@ -11611,12 +11619,26 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, plane->base.id, was_visible, visible, turn_off, turn_on, mode_changed); - if (turn_on) + if (turn_on) { intel_crtc->atomic.update_wm_pre = true; - else if (turn_off) + /* must disable cxsr around plane enable/disable */ + if (plane->type != DRM_PLANE_TYPE_CURSOR) { + intel_crtc->atomic.disable_cxsr = true; + /* to potentially re-enable cxsr */ + intel_crtc->atomic.wait_vblank = true; + intel_crtc->atomic.update_wm_post = true; + } + } else if (turn_off) { intel_crtc->atomic.update_wm_post = true; - else if (intel_wm_need_update(plane, plane_state)) + /* must disable cxsr around plane enable/disable */ + if (plane->type != DRM_PLANE_TYPE_CURSOR) { + if (is_crtc_enabled) + intel_crtc->atomic.wait_vblank = true; + intel_crtc->atomic.disable_cxsr = true; + } + } else if (intel_wm_need_update(plane, plane_state)) { intel_crtc->atomic.update_wm_pre = true; + } if (visible) intel_crtc->atomic.fb_bits |= @@ -11784,8 +11806,8 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) intel_crtc_check_initial_planes(crtc, crtc_state); - if (mode_changed) - intel_crtc->atomic.update_wm_post = !crtc_state->active; + if (mode_changed && !crtc_state->active) + intel_crtc->atomic.update_wm_post = true; if (mode_changed && crtc_state->enable && dev_priv->display.crtc_compute_clock && @@ -13105,6 +13127,8 @@ static int __intel_set_mode(struct drm_atomic_state *state) if (!needs_modeset(crtc->state)) continue; + intel_pre_plane_update(intel_crtc); + any_ms = true; intel_pre_plane_update(intel_crtc); @@ -14065,6 +14089,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->cursor_cntl = ~0; intel_crtc->cursor_size = ~0; + intel_crtc->wm.cxsr_allowed = true; + BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL); dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8397d1c9005b..7f2e204b9fb5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -508,6 +508,7 @@ struct intel_crtc_atomic_commit { bool wait_for_flips; bool disable_fbc; bool disable_ips; + bool disable_cxsr; bool pre_disable_primary; bool update_wm_pre, update_wm_post; unsigned disabled_planes; @@ -566,6 +567,8 @@ struct intel_crtc { struct intel_pipe_wm active; /* SKL wm values currently in use */ struct skl_pipe_wm skl_active; + /* allow CxSR on this pipe */ + bool cxsr_allowed; } wm; int scanline_offset; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0cccc44e1828..a023b40c046b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -335,6 +335,7 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable) if (IS_VALLEYVIEW(dev)) { I915_WRITE(FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0); POSTING_READ(FW_BLC_SELF_VLV); + dev_priv->wm.vlv.cxsr = enable; } else if (IS_G4X(dev) || IS_CRESTLINE(dev)) { I915_WRITE(FW_BLC_SELF, enable ? FW_BLC_SELF_EN : 0); POSTING_READ(FW_BLC_SELF); @@ -1116,7 +1117,7 @@ static void vlv_compute_wm(struct intel_crtc *crtc) memset(wm_state, 0, sizeof(*wm_state)); - wm_state->cxsr = crtc->pipe != PIPE_C; + wm_state->cxsr = crtc->pipe != PIPE_C && crtc->wm.cxsr_allowed; if (IS_CHERRYVIEW(dev)) wm_state->num_levels = CHV_WM_NUM_LEVELS; else @@ -1369,10 +1370,8 @@ static void vlv_update_wm(struct drm_crtc *crtc) dev_priv->wm.vlv.level >= VLV_WM_LEVEL_PM5) chv_set_memory_pm5(dev_priv, false); - if (!wm.cxsr && dev_priv->wm.vlv.cxsr) { + if (!wm.cxsr && dev_priv->wm.vlv.cxsr) intel_set_memory_cxsr(dev_priv, false); - intel_wait_for_vblank(dev, pipe); - } /* FIXME should be part of crtc atomic commit */ vlv_pipe_set_fifo_size(intel_crtc); @@ -1385,10 +1384,8 @@ static void vlv_update_wm(struct drm_crtc *crtc) wm.pipe[pipe].sprite[0], wm.pipe[pipe].sprite[1], wm.sr.plane, wm.sr.cursor, wm.level, wm.cxsr); - if (wm.cxsr && !dev_priv->wm.vlv.cxsr) { - intel_wait_for_vblank(dev, pipe); + if (wm.cxsr && !dev_priv->wm.vlv.cxsr) intel_set_memory_cxsr(dev_priv, true); - } if (wm.level >= VLV_WM_LEVEL_PM5 && dev_priv->wm.vlv.level < VLV_WM_LEVEL_PM5) -- cgit v1.3-6-gb490 From 6f9c784b7ec2cc9fc9fd7c5a8634b70aadd76015 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 22:00:08 +0300 Subject: drm/i915: Don't do PM5/DDR DVFS with multiple pipes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling PM5/DDR DVFS with multiple active pipes isn't a validated configuration. It does seem to work most of the time at least, but there is clearly an additional risk of underruns, so let's not play with fire. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a023b40c046b..16ca34fb5380 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1327,6 +1327,9 @@ static void vlv_merge_wm(struct drm_device *dev, if (num_active_crtcs != 1) wm->cxsr = false; + if (num_active_crtcs > 1) + wm->level = VLV_WM_LEVEL_PM2; + for_each_intel_crtc(dev, crtc) { struct vlv_wm_state *wm_state = &crtc->wm_state; enum pipe pipe = crtc->pipe; -- cgit v1.3-6-gb490 From de38b95cbb2a92ea037c22d41fc1476c0825c0d7 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 22:00:09 +0300 Subject: drm/i915: Add debugfs knobs for VLVCHV memory latency values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow tweaking the VLV/CHV memory latencies thorugh sysfs, like we do for ILK+. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7d303e721a77..68a5e868f90b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4203,8 +4203,15 @@ static const struct file_operations i915_displayport_test_type_fops = { static void wm_latency_show(struct seq_file *m, const uint16_t wm[8]) { struct drm_device *dev = m->private; - int num_levels = ilk_wm_max_level(dev) + 1; int level; + int num_levels; + + if (IS_CHERRYVIEW(dev)) + num_levels = 3; + else if (IS_VALLEYVIEW(dev)) + num_levels = 1; + else + num_levels = ilk_wm_max_level(dev) + 1; drm_modeset_lock_all(dev); @@ -4213,9 +4220,9 @@ static void wm_latency_show(struct seq_file *m, const uint16_t wm[8]) /* * - WM1+ latency values in 0.5us units - * - latencies are in us on gen9 + * - latencies are in us on gen9/vlv/chv */ - if (INTEL_INFO(dev)->gen >= 9) + if (INTEL_INFO(dev)->gen >= 9 || IS_VALLEYVIEW(dev)) latency *= 10; else if (level > 0) latency *= 5; @@ -4279,7 +4286,7 @@ static int pri_wm_latency_open(struct inode *inode, struct file *file) { struct drm_device *dev = inode->i_private; - if (HAS_GMCH_DISPLAY(dev)) + if (INTEL_INFO(dev)->gen < 5) return -ENODEV; return single_open(file, pri_wm_latency_show, dev); @@ -4311,11 +4318,18 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, struct seq_file *m = file->private_data; struct drm_device *dev = m->private; uint16_t new[8] = { 0 }; - int num_levels = ilk_wm_max_level(dev) + 1; + int num_levels; int level; int ret; char tmp[32]; + if (IS_CHERRYVIEW(dev)) + num_levels = 3; + else if (IS_VALLEYVIEW(dev)) + num_levels = 1; + else + num_levels = ilk_wm_max_level(dev) + 1; + if (len >= sizeof(tmp)) return -EINVAL; -- cgit v1.3-6-gb490 From 2cb389b7e4966151d44c505d49ea31a8d6969372 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 24 Jun 2015 22:00:10 +0300 Subject: drm/i915: Zero unused WM1 watermarks on VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hardware supposedly ignores the WM1 watermarks while the PND deadline mode is enabled, but clear out the register just in case. This is what the other OS does, and it does make register dumps look more consistent when we don't have partial WM1 values lingering in the registers (some WM1 watermarks already get zeroed when the actually used DSPFW registers get written). Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 16ca34fb5380..6eb5d76e6912 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -927,6 +927,12 @@ static void vlv_write_wm_values(struct intel_crtc *crtc, FW_WM(wm->pipe[PIPE_A].primary >> 8, PLANEA_HI)); } + /* zero (unused) WM1 watermarks */ + I915_WRITE(DSPFW4, 0); + I915_WRITE(DSPFW5, 0); + I915_WRITE(DSPFW6, 0); + I915_WRITE(DSPHOWM1, 0); + POSTING_READ(DSPFW1); } -- cgit v1.3-6-gb490 From 4b8a8262086ece4b7eb34bd2e40cce3b3c9c7079 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 19 Nov 2014 18:30:22 +0100 Subject: HID: picoLCD: Deletion of unnecessary checks before three function calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functions backlight_device_unregister(), lcd_device_unregister() and rc_unregister_device() test whether their argument is NULL and then return immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Reviewed-by: Bruno Prémont Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd_backlight.c | 3 +-- drivers/hid/hid-picolcd_cir.c | 3 +-- drivers/hid/hid-picolcd_lcd.c | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-picolcd_backlight.c b/drivers/hid/hid-picolcd_backlight.c index a32c5f86b0b3..808807ad388f 100644 --- a/drivers/hid/hid-picolcd_backlight.c +++ b/drivers/hid/hid-picolcd_backlight.c @@ -94,8 +94,7 @@ void picolcd_exit_backlight(struct picolcd_data *data) struct backlight_device *bdev = data->backlight; data->backlight = NULL; - if (bdev) - backlight_device_unregister(bdev); + backlight_device_unregister(bdev); } int picolcd_resume_backlight(struct picolcd_data *data) diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c index 045f8ebf16b5..96286510f42e 100644 --- a/drivers/hid/hid-picolcd_cir.c +++ b/drivers/hid/hid-picolcd_cir.c @@ -145,7 +145,6 @@ void picolcd_exit_cir(struct picolcd_data *data) struct rc_dev *rdev = data->rc_dev; data->rc_dev = NULL; - if (rdev) - rc_unregister_device(rdev); + rc_unregister_device(rdev); } diff --git a/drivers/hid/hid-picolcd_lcd.c b/drivers/hid/hid-picolcd_lcd.c index 89821c2da6d7..22dcbe13da89 100644 --- a/drivers/hid/hid-picolcd_lcd.c +++ b/drivers/hid/hid-picolcd_lcd.c @@ -92,8 +92,7 @@ void picolcd_exit_lcd(struct picolcd_data *data) struct lcd_device *ldev = data->lcd; data->lcd = NULL; - if (ldev) - lcd_device_unregister(ldev); + lcd_device_unregister(ldev); } int picolcd_resume_lcd(struct picolcd_data *data) -- cgit v1.3-6-gb490 From f8896f5d58e64bfd3c2b5f7c5ba5c3f3967e93c7 Mon Sep 17 00:00:00 2001 From: David Weinehall Date: Thu, 25 Jun 2015 11:11:03 +0300 Subject: drm/i915/skl: Buffer translation improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for 0.85V VccIO on Skylake Y, separate buffer translation tables for Skylake U, and support for I_boost for the entries that needs this. Changes in v2: * Refactored the code a bit to move all DDI signal level setup to intel_ddi.c Issue: VIZ-5677 Signed-off-by: David Weinehall Reviewed-by: Antti Koskipää [danvet: Apply style polish checkpatch suggested.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 8 + drivers/gpu/drm/i915/i915_reg.h | 12 + drivers/gpu/drm/i915/intel_ddi.c | 509 ++++++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_dp.c | 104 +------- drivers/gpu/drm/i915/intel_drv.h | 3 +- 5 files changed, 423 insertions(+), 213 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6acc6504863b..64041e788a1c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2436,6 +2436,14 @@ struct drm_i915_cmd_table { /* ULX machines are also considered ULT. */ #define IS_HSW_ULX(dev) (INTEL_DEVID(dev) == 0x0A0E || \ INTEL_DEVID(dev) == 0x0A1E) +#define IS_SKL_ULT(dev) (INTEL_DEVID(dev) == 0x1906 || \ + INTEL_DEVID(dev) == 0x1913 || \ + INTEL_DEVID(dev) == 0x1916 || \ + INTEL_DEVID(dev) == 0x1921 || \ + INTEL_DEVID(dev) == 0x1926) +#define IS_SKL_ULX(dev) (INTEL_DEVID(dev) == 0x190E || \ + INTEL_DEVID(dev) == 0x1915 || \ + INTEL_DEVID(dev) == 0x191E) #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary) #define SKL_REVID_A0 (0x0) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 50e6279d7d56..bdef9f7b629e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1384,6 +1384,18 @@ enum skl_disp_power_wells { _PORT_TX_DW14_LN0_C) + \ _BXT_LANE_OFFSET(lane)) +/* UAIMI scratch pad register 1 */ +#define UAIMI_SPR1 0x4F074 +/* SKL VccIO mask */ +#define SKL_VCCIO_MASK 0x1 +/* SKL balance leg register */ +#define DISPIO_CR_TX_BMU_CR0 0x6C00C +/* I_boost values */ +#define BALANCE_LEG_SHIFT(port) (8+3*(port)) +#define BALANCE_LEG_MASK(port) (7<<(8+3*(port))) +/* Balance leg disable bits */ +#define BALANCE_LEG_DISABLE_SHIFT 23 + /* * Fence registers */ diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 42c14870ef43..b29d103bd706 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -31,6 +31,7 @@ struct ddi_buf_trans { u32 trans1; /* balance leg enable, de-emph level */ u32 trans2; /* vref sel, vswing */ + u8 i_boost; /* SKL: I_boost; valid: 0x0, 0x1, 0x3, 0x7 */ }; /* HDMI/DVI modes ignore everything but the last 2 items. So we share @@ -38,134 +39,213 @@ struct ddi_buf_trans { * automatically adapt to HDMI connections as well */ static const struct ddi_buf_trans hsw_ddi_translations_dp[] = { - { 0x00FFFFFF, 0x0006000E }, - { 0x00D75FFF, 0x0005000A }, - { 0x00C30FFF, 0x00040006 }, - { 0x80AAAFFF, 0x000B0000 }, - { 0x00FFFFFF, 0x0005000A }, - { 0x00D75FFF, 0x000C0004 }, - { 0x80C30FFF, 0x000B0000 }, - { 0x00FFFFFF, 0x00040006 }, - { 0x80D75FFF, 0x000B0000 }, + { 0x00FFFFFF, 0x0006000E, 0x0 }, + { 0x00D75FFF, 0x0005000A, 0x0 }, + { 0x00C30FFF, 0x00040006, 0x0 }, + { 0x80AAAFFF, 0x000B0000, 0x0 }, + { 0x00FFFFFF, 0x0005000A, 0x0 }, + { 0x00D75FFF, 0x000C0004, 0x0 }, + { 0x80C30FFF, 0x000B0000, 0x0 }, + { 0x00FFFFFF, 0x00040006, 0x0 }, + { 0x80D75FFF, 0x000B0000, 0x0 }, }; static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = { - { 0x00FFFFFF, 0x0007000E }, - { 0x00D75FFF, 0x000F000A }, - { 0x00C30FFF, 0x00060006 }, - { 0x00AAAFFF, 0x001E0000 }, - { 0x00FFFFFF, 0x000F000A }, - { 0x00D75FFF, 0x00160004 }, - { 0x00C30FFF, 0x001E0000 }, - { 0x00FFFFFF, 0x00060006 }, - { 0x00D75FFF, 0x001E0000 }, + { 0x00FFFFFF, 0x0007000E, 0x0 }, + { 0x00D75FFF, 0x000F000A, 0x0 }, + { 0x00C30FFF, 0x00060006, 0x0 }, + { 0x00AAAFFF, 0x001E0000, 0x0 }, + { 0x00FFFFFF, 0x000F000A, 0x0 }, + { 0x00D75FFF, 0x00160004, 0x0 }, + { 0x00C30FFF, 0x001E0000, 0x0 }, + { 0x00FFFFFF, 0x00060006, 0x0 }, + { 0x00D75FFF, 0x001E0000, 0x0 }, }; static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = { /* Idx NT mV d T mV d db */ - { 0x00FFFFFF, 0x0006000E }, /* 0: 400 400 0 */ - { 0x00E79FFF, 0x000E000C }, /* 1: 400 500 2 */ - { 0x00D75FFF, 0x0005000A }, /* 2: 400 600 3.5 */ - { 0x00FFFFFF, 0x0005000A }, /* 3: 600 600 0 */ - { 0x00E79FFF, 0x001D0007 }, /* 4: 600 750 2 */ - { 0x00D75FFF, 0x000C0004 }, /* 5: 600 900 3.5 */ - { 0x00FFFFFF, 0x00040006 }, /* 6: 800 800 0 */ - { 0x80E79FFF, 0x00030002 }, /* 7: 800 1000 2 */ - { 0x00FFFFFF, 0x00140005 }, /* 8: 850 850 0 */ - { 0x00FFFFFF, 0x000C0004 }, /* 9: 900 900 0 */ - { 0x00FFFFFF, 0x001C0003 }, /* 10: 950 950 0 */ - { 0x80FFFFFF, 0x00030002 }, /* 11: 1000 1000 0 */ + { 0x00FFFFFF, 0x0006000E, 0x0 },/* 0: 400 400 0 */ + { 0x00E79FFF, 0x000E000C, 0x0 },/* 1: 400 500 2 */ + { 0x00D75FFF, 0x0005000A, 0x0 },/* 2: 400 600 3.5 */ + { 0x00FFFFFF, 0x0005000A, 0x0 },/* 3: 600 600 0 */ + { 0x00E79FFF, 0x001D0007, 0x0 },/* 4: 600 750 2 */ + { 0x00D75FFF, 0x000C0004, 0x0 },/* 5: 600 900 3.5 */ + { 0x00FFFFFF, 0x00040006, 0x0 },/* 6: 800 800 0 */ + { 0x80E79FFF, 0x00030002, 0x0 },/* 7: 800 1000 2 */ + { 0x00FFFFFF, 0x00140005, 0x0 },/* 8: 850 850 0 */ + { 0x00FFFFFF, 0x000C0004, 0x0 },/* 9: 900 900 0 */ + { 0x00FFFFFF, 0x001C0003, 0x0 },/* 10: 950 950 0 */ + { 0x80FFFFFF, 0x00030002, 0x0 },/* 11: 1000 1000 0 */ }; static const struct ddi_buf_trans bdw_ddi_translations_edp[] = { - { 0x00FFFFFF, 0x00000012 }, - { 0x00EBAFFF, 0x00020011 }, - { 0x00C71FFF, 0x0006000F }, - { 0x00AAAFFF, 0x000E000A }, - { 0x00FFFFFF, 0x00020011 }, - { 0x00DB6FFF, 0x0005000F }, - { 0x00BEEFFF, 0x000A000C }, - { 0x00FFFFFF, 0x0005000F }, - { 0x00DB6FFF, 0x000A000C }, + { 0x00FFFFFF, 0x00000012, 0x0 }, + { 0x00EBAFFF, 0x00020011, 0x0 }, + { 0x00C71FFF, 0x0006000F, 0x0 }, + { 0x00AAAFFF, 0x000E000A, 0x0 }, + { 0x00FFFFFF, 0x00020011, 0x0 }, + { 0x00DB6FFF, 0x0005000F, 0x0 }, + { 0x00BEEFFF, 0x000A000C, 0x0 }, + { 0x00FFFFFF, 0x0005000F, 0x0 }, + { 0x00DB6FFF, 0x000A000C, 0x0 }, }; static const struct ddi_buf_trans bdw_ddi_translations_dp[] = { - { 0x00FFFFFF, 0x0007000E }, - { 0x00D75FFF, 0x000E000A }, - { 0x00BEFFFF, 0x00140006 }, - { 0x80B2CFFF, 0x001B0002 }, - { 0x00FFFFFF, 0x000E000A }, - { 0x00DB6FFF, 0x00160005 }, - { 0x80C71FFF, 0x001A0002 }, - { 0x00F7DFFF, 0x00180004 }, - { 0x80D75FFF, 0x001B0002 }, + { 0x00FFFFFF, 0x0007000E, 0x0 }, + { 0x00D75FFF, 0x000E000A, 0x0 }, + { 0x00BEFFFF, 0x00140006, 0x0 }, + { 0x80B2CFFF, 0x001B0002, 0x0 }, + { 0x00FFFFFF, 0x000E000A, 0x0 }, + { 0x00DB6FFF, 0x00160005, 0x0 }, + { 0x80C71FFF, 0x001A0002, 0x0 }, + { 0x00F7DFFF, 0x00180004, 0x0 }, + { 0x80D75FFF, 0x001B0002, 0x0 }, }; static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = { - { 0x00FFFFFF, 0x0001000E }, - { 0x00D75FFF, 0x0004000A }, - { 0x00C30FFF, 0x00070006 }, - { 0x00AAAFFF, 0x000C0000 }, - { 0x00FFFFFF, 0x0004000A }, - { 0x00D75FFF, 0x00090004 }, - { 0x00C30FFF, 0x000C0000 }, - { 0x00FFFFFF, 0x00070006 }, - { 0x00D75FFF, 0x000C0000 }, + { 0x00FFFFFF, 0x0001000E, 0x0 }, + { 0x00D75FFF, 0x0004000A, 0x0 }, + { 0x00C30FFF, 0x00070006, 0x0 }, + { 0x00AAAFFF, 0x000C0000, 0x0 }, + { 0x00FFFFFF, 0x0004000A, 0x0 }, + { 0x00D75FFF, 0x00090004, 0x0 }, + { 0x00C30FFF, 0x000C0000, 0x0 }, + { 0x00FFFFFF, 0x00070006, 0x0 }, + { 0x00D75FFF, 0x000C0000, 0x0 }, }; static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = { /* Idx NT mV d T mV df db */ - { 0x00FFFFFF, 0x0007000E }, /* 0: 400 400 0 */ - { 0x00D75FFF, 0x000E000A }, /* 1: 400 600 3.5 */ - { 0x00BEFFFF, 0x00140006 }, /* 2: 400 800 6 */ - { 0x00FFFFFF, 0x0009000D }, /* 3: 450 450 0 */ - { 0x00FFFFFF, 0x000E000A }, /* 4: 600 600 0 */ - { 0x00D7FFFF, 0x00140006 }, /* 5: 600 800 2.5 */ - { 0x80CB2FFF, 0x001B0002 }, /* 6: 600 1000 4.5 */ - { 0x00FFFFFF, 0x00140006 }, /* 7: 800 800 0 */ - { 0x80E79FFF, 0x001B0002 }, /* 8: 800 1000 2 */ - { 0x80FFFFFF, 0x001B0002 }, /* 9: 1000 1000 0 */ + { 0x00FFFFFF, 0x0007000E, 0x0 },/* 0: 400 400 0 */ + { 0x00D75FFF, 0x000E000A, 0x0 },/* 1: 400 600 3.5 */ + { 0x00BEFFFF, 0x00140006, 0x0 },/* 2: 400 800 6 */ + { 0x00FFFFFF, 0x0009000D, 0x0 },/* 3: 450 450 0 */ + { 0x00FFFFFF, 0x000E000A, 0x0 },/* 4: 600 600 0 */ + { 0x00D7FFFF, 0x00140006, 0x0 },/* 5: 600 800 2.5 */ + { 0x80CB2FFF, 0x001B0002, 0x0 },/* 6: 600 1000 4.5 */ + { 0x00FFFFFF, 0x00140006, 0x0 },/* 7: 800 800 0 */ + { 0x80E79FFF, 0x001B0002, 0x0 },/* 8: 800 1000 2 */ + { 0x80FFFFFF, 0x001B0002, 0x0 },/* 9: 1000 1000 0 */ }; +/* Skylake H, S, and Skylake Y with 0.95V VccIO */ static const struct ddi_buf_trans skl_ddi_translations_dp[] = { - { 0x00000018, 0x000000a2 }, - { 0x00004014, 0x0000009B }, - { 0x00006012, 0x00000088 }, - { 0x00008010, 0x00000087 }, - { 0x00000018, 0x0000009B }, - { 0x00004014, 0x00000088 }, - { 0x00006012, 0x00000087 }, - { 0x00000018, 0x00000088 }, - { 0x00004014, 0x00000087 }, + { 0x00002016, 0x000000A0, 0x0 }, + { 0x00005012, 0x0000009B, 0x0 }, + { 0x00007011, 0x00000088, 0x0 }, + { 0x00009010, 0x000000C7, 0x0 }, + { 0x00002016, 0x0000009B, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x00007011, 0x000000C7, 0x0 }, + { 0x00002016, 0x000000DF, 0x0 }, + { 0x00005012, 0x000000C7, 0x0 }, }; -/* eDP 1.4 low vswing translation parameters */ +/* Skylake U */ +static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = { + { 0x00002016, 0x000000A2, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x00007011, 0x00000087, 0x0 }, + { 0x80009010, 0x000000C7, 0x1 }, /* Uses I_boost */ + { 0x00002016, 0x0000009D, 0x0 }, + { 0x00005012, 0x000000C7, 0x0 }, + { 0x00007011, 0x000000C7, 0x0 }, + { 0x00002016, 0x00000088, 0x0 }, + { 0x00005012, 0x000000C7, 0x0 }, +}; + +/* Skylake Y with 0.85V VccIO */ +static const struct ddi_buf_trans skl_y_085v_ddi_translations_dp[] = { + { 0x00000018, 0x000000A2, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x00007011, 0x00000087, 0x0 }, + { 0x80009010, 0x000000C7, 0x1 }, /* Uses I_boost */ + { 0x00000018, 0x0000009D, 0x0 }, + { 0x00005012, 0x000000C7, 0x0 }, + { 0x00007011, 0x000000C7, 0x0 }, + { 0x00000018, 0x00000088, 0x0 }, + { 0x00005012, 0x000000C7, 0x0 }, +}; + +/* + * Skylake H and S, and Skylake Y with 0.95V VccIO + * eDP 1.4 low vswing translation parameters + */ static const struct ddi_buf_trans skl_ddi_translations_edp[] = { - { 0x00000018, 0x000000a8 }, - { 0x00002016, 0x000000ab }, - { 0x00006012, 0x000000a2 }, - { 0x00008010, 0x00000088 }, - { 0x00000018, 0x000000ab }, - { 0x00004014, 0x000000a2 }, - { 0x00006012, 0x000000a6 }, - { 0x00000018, 0x000000a2 }, - { 0x00005013, 0x0000009c }, - { 0x00000018, 0x00000088 }, + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000A9, 0x0 }, + { 0x00007011, 0x000000A2, 0x0 }, + { 0x00009010, 0x0000009C, 0x0 }, + { 0x00000018, 0x000000A9, 0x0 }, + { 0x00006013, 0x000000A2, 0x0 }, + { 0x00007011, 0x000000A6, 0x0 }, + { 0x00000018, 0x000000AB, 0x0 }, + { 0x00007013, 0x0000009F, 0x0 }, + { 0x00000018, 0x000000DF, 0x0 }, }; +/* + * Skylake U + * eDP 1.4 low vswing translation parameters + */ +static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = { + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000A9, 0x0 }, + { 0x00007011, 0x000000A2, 0x0 }, + { 0x00009010, 0x0000009C, 0x0 }, + { 0x00000018, 0x000000A9, 0x0 }, + { 0x00006013, 0x000000A2, 0x0 }, + { 0x00007011, 0x000000A6, 0x0 }, + { 0x00002016, 0x000000AB, 0x0 }, + { 0x00005013, 0x0000009F, 0x0 }, + { 0x00000018, 0x000000DF, 0x0 }, +}; +/* + * Skylake Y with 0.95V VccIO + * eDP 1.4 low vswing translation parameters + */ +static const struct ddi_buf_trans skl_y_085v_ddi_translations_edp[] = { + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000AB, 0x0 }, + { 0x00007011, 0x000000A4, 0x0 }, + { 0x00009010, 0x000000DF, 0x0 }, + { 0x00000018, 0x000000AA, 0x0 }, + { 0x00006013, 0x000000A4, 0x0 }, + { 0x00007011, 0x0000009D, 0x0 }, + { 0x00000018, 0x000000A0, 0x0 }, + { 0x00006012, 0x000000DF, 0x0 }, + { 0x00000018, 0x0000008A, 0x0 }, +}; + +/* Skylake H, S and U, and Skylake Y with 0.95V VccIO */ static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { - { 0x00000018, 0x000000ac }, - { 0x00005012, 0x0000009d }, - { 0x00007011, 0x00000088 }, - { 0x00000018, 0x000000a1 }, - { 0x00000018, 0x00000098 }, - { 0x00004013, 0x00000088 }, - { 0x00006012, 0x00000087 }, - { 0x00000018, 0x000000df }, - { 0x00003015, 0x00000087 }, - { 0x00003015, 0x000000c7 }, - { 0x00000018, 0x000000c7 }, + { 0x00000018, 0x000000AC, 0x0 }, + { 0x00005012, 0x0000009D, 0x0 }, + { 0x00007011, 0x00000088, 0x0 }, + { 0x00000018, 0x000000A1, 0x0 }, + { 0x00000018, 0x00000098, 0x0 }, + { 0x00004013, 0x00000088, 0x0 }, + { 0x00006012, 0x00000087, 0x0 }, + { 0x00000018, 0x000000DF, 0x0 }, + { 0x00003015, 0x00000087, 0x0 }, /* Default */ + { 0x00003015, 0x000000C7, 0x0 }, + { 0x00000018, 0x000000C7, 0x0 }, +}; + +/* Skylake Y with 0.85V VccIO */ +static const struct ddi_buf_trans skl_y_085v_ddi_translations_hdmi[] = { + { 0x00000018, 0x000000A1, 0x0 }, + { 0x00005012, 0x000000DF, 0x0 }, + { 0x00007011, 0x00000084, 0x0 }, + { 0x00000018, 0x000000A4, 0x0 }, + { 0x00000018, 0x0000009D, 0x0 }, + { 0x00004013, 0x00000080, 0x0 }, + { 0x00006013, 0x000000C7, 0x0 }, + { 0x00000018, 0x0000008A, 0x0 }, + { 0x00003015, 0x000000C7, 0x0 }, /* Default */ + { 0x80003015, 0x000000C7, 0x7 }, /* Uses I_boost */ + { 0x00000018, 0x000000C7, 0x0 }, }; struct bxt_ddi_buf_trans { @@ -190,7 +270,7 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { { 154, 0x9A, 0, 64, false }, /* 6: 600 6 */ { 102, 0x9A, 0, 128, false }, /* 7: 800 0 */ { 154, 0x9A, 0, 85, false }, /* 8: 800 3.5 */ - { 154, 0x9A, 1, 128, false }, /* 9: 1200 0 */ + { 154, 0x9A, 1, 128, false }, /* 9: 1200 0 */ }; /* BSpec has 2 recommended values - entries 0 and 8. @@ -210,6 +290,9 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = { { 154, 0x9A, 1, 128, true }, /* 9: 1200 0 */ }; +static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, + enum port port, int type); + static void ddi_get_encoder_port(struct intel_encoder *intel_encoder, struct intel_digital_port **dig_port, enum port *port) @@ -249,6 +332,102 @@ intel_dig_port_supports_hdmi(const struct intel_digital_port *intel_dig_port) return intel_dig_port->hdmi.hdmi_reg; } +static const struct ddi_buf_trans *skl_get_buf_trans_dp(struct drm_device *dev, + int *n_entries) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + const struct ddi_buf_trans *ddi_translations; + static int is_095v = -1; + + if (is_095v == -1) { + u32 spr1 = I915_READ(UAIMI_SPR1); + + is_095v = spr1 & SKL_VCCIO_MASK; + } + + if (IS_SKL_ULX(dev) && !is_095v) { + ddi_translations = skl_y_085v_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_y_085v_ddi_translations_dp); + } else if (IS_SKL_ULT(dev)) { + ddi_translations = skl_u_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp); + } else { + ddi_translations = skl_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_ddi_translations_dp); + } + + return ddi_translations; +} + +static const struct ddi_buf_trans *skl_get_buf_trans_edp(struct drm_device *dev, + int *n_entries) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + const struct ddi_buf_trans *ddi_translations; + static int is_095v = -1; + + if (is_095v == -1) { + u32 spr1 = I915_READ(UAIMI_SPR1); + + is_095v = spr1 & SKL_VCCIO_MASK; + } + + if (IS_SKL_ULX(dev) && !is_095v) { + if (dev_priv->edp_low_vswing) { + ddi_translations = skl_y_085v_ddi_translations_edp; + *n_entries = + ARRAY_SIZE(skl_y_085v_ddi_translations_edp); + } else { + ddi_translations = skl_y_085v_ddi_translations_dp; + *n_entries = + ARRAY_SIZE(skl_y_085v_ddi_translations_dp); + } + } else if (IS_SKL_ULT(dev)) { + if (dev_priv->edp_low_vswing) { + ddi_translations = skl_u_ddi_translations_edp; + *n_entries = ARRAY_SIZE(skl_u_ddi_translations_edp); + } else { + ddi_translations = skl_u_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp); + } + } else { + if (dev_priv->edp_low_vswing) { + ddi_translations = skl_ddi_translations_edp; + *n_entries = ARRAY_SIZE(skl_ddi_translations_edp); + } else { + ddi_translations = skl_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_ddi_translations_dp); + } + } + + return ddi_translations; +} + +static const struct ddi_buf_trans * +skl_get_buf_trans_hdmi(struct drm_device *dev, + int *n_entries) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + const struct ddi_buf_trans *ddi_translations; + static int is_095v = -1; + + if (is_095v == -1) { + u32 spr1 = I915_READ(UAIMI_SPR1); + + is_095v = spr1 & SKL_VCCIO_MASK; + } + + if (IS_SKL_ULX(dev) && !is_095v) { + ddi_translations = skl_y_085v_ddi_translations_hdmi; + *n_entries = ARRAY_SIZE(skl_y_085v_ddi_translations_hdmi); + } else { + ddi_translations = skl_ddi_translations_hdmi; + *n_entries = ARRAY_SIZE(skl_ddi_translations_hdmi); + } + + return ddi_translations; +} + /* * Starting with Haswell, DDI port buffers must be programmed with correct * values in advance. The buffer values are different for FDI and DP modes, @@ -279,20 +458,13 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, INTEL_OUTPUT_HDMI); return; } else if (IS_SKYLAKE(dev)) { - ddi_translations_fdi = NULL; - ddi_translations_dp = skl_ddi_translations_dp; - n_dp_entries = ARRAY_SIZE(skl_ddi_translations_dp); - if (dev_priv->edp_low_vswing) { - ddi_translations_edp = skl_ddi_translations_edp; - n_edp_entries = ARRAY_SIZE(skl_ddi_translations_edp); - } else { - ddi_translations_edp = skl_ddi_translations_dp; - n_edp_entries = ARRAY_SIZE(skl_ddi_translations_dp); - } - - ddi_translations_hdmi = skl_ddi_translations_hdmi; - n_hdmi_entries = ARRAY_SIZE(skl_ddi_translations_hdmi); - hdmi_default_entry = 7; + ddi_translations_dp = + skl_get_buf_trans_dp(dev, &n_dp_entries); + ddi_translations_edp = + skl_get_buf_trans_edp(dev, &n_edp_entries); + ddi_translations_hdmi = + skl_get_buf_trans_hdmi(dev, &n_hdmi_entries); + hdmi_default_entry = 8; } else if (IS_BROADWELL(dev)) { ddi_translations_fdi = bdw_ddi_translations_fdi; ddi_translations_dp = bdw_ddi_translations_dp; @@ -1883,8 +2055,48 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) TRANS_CLK_SEL_DISABLED); } -void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, - enum port port, int type) +static void skl_ddi_set_iboost(struct drm_device *dev, u32 level, + enum port port, int type) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + const struct ddi_buf_trans *ddi_translations; + uint8_t iboost; + int n_entries; + u32 reg; + + if (type == INTEL_OUTPUT_DISPLAYPORT) { + ddi_translations = skl_get_buf_trans_dp(dev, &n_entries); + iboost = ddi_translations[port].i_boost; + } else if (type == INTEL_OUTPUT_EDP) { + ddi_translations = skl_get_buf_trans_edp(dev, &n_entries); + iboost = ddi_translations[port].i_boost; + } else if (type == INTEL_OUTPUT_HDMI) { + ddi_translations = skl_get_buf_trans_hdmi(dev, &n_entries); + iboost = ddi_translations[port].i_boost; + } else { + return; + } + + /* Make sure that the requested I_boost is valid */ + if (iboost && iboost != 0x1 && iboost != 0x3 && iboost != 0x7) { + DRM_ERROR("Invalid I_boost value %u\n", iboost); + return; + } + + reg = I915_READ(DISPIO_CR_TX_BMU_CR0); + reg &= ~BALANCE_LEG_MASK(port); + reg &= ~(1 << (BALANCE_LEG_DISABLE_SHIFT + port)); + + if (iboost) + reg |= iboost << BALANCE_LEG_SHIFT(port); + else + reg |= 1 << (BALANCE_LEG_DISABLE_SHIFT + port); + + I915_WRITE(DISPIO_CR_TX_BMU_CR0, reg); +} + +static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, + enum port port, int type) { struct drm_i915_private *dev_priv = dev->dev_private; const struct bxt_ddi_buf_trans *ddi_translations; @@ -1944,6 +2156,73 @@ void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, I915_WRITE(BXT_PORT_PCS_DW10_GRP(port), val); } +static uint32_t translate_signal_level(int signal_levels) +{ + uint32_t level; + + switch (signal_levels) { + default: + DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level: 0x%x\n", + signal_levels); + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0: + level = 0; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1: + level = 1; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2: + level = 2; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3: + level = 3; + break; + + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0: + level = 4; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1: + level = 5; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2: + level = 6; + break; + + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0: + level = 7; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1: + level = 8; + break; + + case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0: + level = 9; + break; + } + + return level; +} + +uint32_t ddi_signal_levels(struct intel_dp *intel_dp) +{ + struct intel_digital_port *dport = dp_to_dig_port(intel_dp); + struct drm_device *dev = dport->base.base.dev; + struct intel_encoder *encoder = &dport->base; + uint8_t train_set = intel_dp->train_set[0]; + int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | + DP_TRAIN_PRE_EMPHASIS_MASK); + enum port port = dport->port; + uint32_t level; + + level = translate_signal_level(signal_levels); + + if (IS_SKYLAKE(dev)) + skl_ddi_set_iboost(dev, level, port, encoder->type); + else if (IS_BROXTON(dev)) + bxt_ddi_vswing_sequence(dev, level, port, encoder->type); + + return DDI_BUF_TRANS_SELECT(level); +} + static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c43bff90c47a..367f71224c96 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3424,92 +3424,6 @@ gen7_edp_signal_levels(uint8_t train_set) } } -/* Gen7.5's (HSW) DP voltage swing and pre-emphasis control */ -static uint32_t -hsw_signal_levels(uint8_t train_set) -{ - int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | - DP_TRAIN_PRE_EMPHASIS_MASK); - switch (signal_levels) { - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0: - return DDI_BUF_TRANS_SELECT(0); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1: - return DDI_BUF_TRANS_SELECT(1); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2: - return DDI_BUF_TRANS_SELECT(2); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3: - return DDI_BUF_TRANS_SELECT(3); - - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0: - return DDI_BUF_TRANS_SELECT(4); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1: - return DDI_BUF_TRANS_SELECT(5); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2: - return DDI_BUF_TRANS_SELECT(6); - - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0: - return DDI_BUF_TRANS_SELECT(7); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1: - return DDI_BUF_TRANS_SELECT(8); - - case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0: - return DDI_BUF_TRANS_SELECT(9); - default: - DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:" - "0x%x\n", signal_levels); - return DDI_BUF_TRANS_SELECT(0); - } -} - -static void bxt_signal_levels(struct intel_dp *intel_dp) -{ - struct intel_digital_port *dport = dp_to_dig_port(intel_dp); - enum port port = dport->port; - struct drm_device *dev = dport->base.base.dev; - struct intel_encoder *encoder = &dport->base; - uint8_t train_set = intel_dp->train_set[0]; - uint32_t level = 0; - - int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | - DP_TRAIN_PRE_EMPHASIS_MASK); - switch (signal_levels) { - default: - DRM_DEBUG_KMS("Unsupported voltage swing/pre-emph level\n"); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0: - level = 0; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1: - level = 1; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2: - level = 2; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3: - level = 3; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0: - level = 4; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1: - level = 5; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2: - level = 6; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0: - level = 7; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1: - level = 8; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0: - level = 9; - break; - } - - bxt_ddi_vswing_sequence(dev, level, port, encoder->type); -} - /* Properly updates "DP" with the correct signal levels. */ static void intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) @@ -3517,22 +3431,20 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum port port = intel_dig_port->port; struct drm_device *dev = intel_dig_port->base.base.dev; - uint32_t signal_levels, mask; + uint32_t signal_levels, mask = 0; uint8_t train_set = intel_dp->train_set[0]; - if (IS_BROXTON(dev)) { - signal_levels = 0; - bxt_signal_levels(intel_dp); - mask = 0; - } else if (HAS_DDI(dev)) { - signal_levels = hsw_signal_levels(train_set); - mask = DDI_BUF_EMP_MASK; + if (HAS_DDI(dev)) { + signal_levels = ddi_signal_levels(intel_dp); + + if (IS_BROXTON(dev)) + signal_levels = 0; + else + mask = DDI_BUF_EMP_MASK; } else if (IS_CHERRYVIEW(dev)) { signal_levels = chv_signal_levels(intel_dp); - mask = 0; } else if (IS_VALLEYVIEW(dev)) { signal_levels = vlv_signal_levels(intel_dp); - mask = 0; } else if (IS_GEN7(dev) && port == PORT_A) { signal_levels = gen7_edp_signal_levels(train_set); mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7f2e204b9fb5..bb52620a3ce8 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -968,8 +968,7 @@ void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder); void intel_ddi_clock_get(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config); void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state); -void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, - enum port port, int type); +uint32_t ddi_signal_levels(struct intel_dp *intel_dp); /* intel_frontbuffer.c */ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, -- cgit v1.3-6-gb490 From 05712c1561041d102d3cac7d7e79548b1446caa4 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 18 Jun 2015 17:25:54 +0300 Subject: drm/i915/bxt: add missing DDI PLL registers to the state checking Although we have a fixed setting for the PLL9 and EBB4 registers, it still makes sense to check them together with the rest of PLL registers. While at it also remove a redundant comment about 10 bit clock enabling. Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/i915_reg.h | 3 ++- drivers/gpu/drm/i915/intel_ddi.c | 16 +++++++++++++--- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 4 files changed, 21 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 64041e788a1c..1dbd95710bf4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -372,7 +372,8 @@ struct intel_dpll_hw_state { uint32_t cfgcr1, cfgcr2; /* bxt */ - uint32_t ebb0, pll0, pll1, pll2, pll3, pll6, pll8, pll10, pcsdw12; + uint32_t ebb0, ebb4, pll0, pll1, pll2, pll3, pll6, pll8, pll9, pll10, + pcsdw12; }; struct intel_shared_dpll_config { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index bdef9f7b629e..4d8ef2de4374 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1208,7 +1208,8 @@ enum skl_disp_power_wells { /* PORT_PLL_8_A */ #define PORT_PLL_TARGET_CNT_MASK 0x3FF /* PORT_PLL_9_A */ -#define PORT_PLL_LOCK_THRESHOLD_MASK 0xe +#define PORT_PLL_LOCK_THRESHOLD_SHIFT 1 +#define PORT_PLL_LOCK_THRESHOLD_MASK (0x7 << PORT_PLL_LOCK_THRESHOLD_SHIFT) /* PORT_PLL_10_A */ #define PORT_PLL_DCO_AMP_OVR_EN_H (1<<27) #define PORT_PLL_DCO_AMP_MASK 0x3c00 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b29d103bd706..cf2896da8ad8 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1722,11 +1722,15 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, crtc_state->dpll_hw_state.pll8 = targ_cnt; + crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT; + if (dcoampovr_en_h) crtc_state->dpll_hw_state.pll10 = PORT_PLL_DCO_AMP_OVR_EN_H; crtc_state->dpll_hw_state.pll10 |= PORT_PLL_DCO_AMP(dco_amp); + crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE; + crtc_state->dpll_hw_state.pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger; @@ -2767,7 +2771,7 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, temp = I915_READ(BXT_PORT_PLL(port, 9)); temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK; - temp |= (5 << 1); + temp |= pll->config.hw_state.pll9; I915_WRITE(BXT_PORT_PLL(port, 9), temp); temp = I915_READ(BXT_PORT_PLL(port, 10)); @@ -2780,8 +2784,8 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, temp = I915_READ(BXT_PORT_PLL_EBB_4(port)); temp |= PORT_PLL_RECALIBRATE; I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp); - /* Enable 10 bit clock */ - temp |= PORT_PLL_10BIT_CLK_ENABLE; + temp &= ~PORT_PLL_10BIT_CLK_ENABLE; + temp |= pll->config.hw_state.ebb4; I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp); /* Enable PLL */ @@ -2832,12 +2836,18 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, return false; hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port)); + hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(port)); + hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE; + hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0)); hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1)); hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2)); hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3)); hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6)); hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8)); + hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9)); + hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK; + hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10)); /* * While we write to the group register to program all lanes at once we diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b7d42e6aac10..6be876845931 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12012,17 +12012,19 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide); if (IS_BROXTON(dev)) { - DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: ebb0: 0x%x, " + DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x," "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, " - "pll6: 0x%x, pll8: 0x%x, pcsdw12: 0x%x\n", + "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pcsdw12: 0x%x\n", pipe_config->ddi_pll_sel, pipe_config->dpll_hw_state.ebb0, + pipe_config->dpll_hw_state.ebb4, pipe_config->dpll_hw_state.pll0, pipe_config->dpll_hw_state.pll1, pipe_config->dpll_hw_state.pll2, pipe_config->dpll_hw_state.pll3, pipe_config->dpll_hw_state.pll6, pipe_config->dpll_hw_state.pll8, + pipe_config->dpll_hw_state.pll9, pipe_config->dpll_hw_state.pcsdw12); } else if (IS_SKYLAKE(dev)) { DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: " -- cgit v1.3-6-gb490 From c8453338b8218b42b70cc256badeaca52021a42c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 18 Jun 2015 17:25:55 +0300 Subject: drm/i915/bxt: add PLL10 to the PLL state dumper Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6be876845931..dd430ce1f37e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12014,7 +12014,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, if (IS_BROXTON(dev)) { DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x," "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, " - "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pcsdw12: 0x%x\n", + "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pll10: 0x%x, pcsdw12: 0x%x\n", pipe_config->ddi_pll_sel, pipe_config->dpll_hw_state.ebb0, pipe_config->dpll_hw_state.ebb4, @@ -12025,6 +12025,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, pipe_config->dpll_hw_state.pll6, pipe_config->dpll_hw_state.pll8, pipe_config->dpll_hw_state.pll9, + pipe_config->dpll_hw_state.pll10, pipe_config->dpll_hw_state.pcsdw12); } else if (IS_SKYLAKE(dev)) { DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: " -- cgit v1.3-6-gb490 From 589eca678a0348687fbfc3194a0d87467a3f6c3f Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 22 Jun 2015 23:35:50 +0300 Subject: drm/i915/vlv: move the vlv PLL helper next to its platform counterparts Move the helper next to the PLL helpers of the other platforms for clarity. No functional change. Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dd430ce1f37e..8ec0f30f0847 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -418,16 +418,6 @@ static const intel_limit_t intel_limits_bxt = { .p2 = { .p2_slow = 1, .p2_fast = 20 }, }; -static void vlv_clock(int refclk, intel_clock_t *clock) -{ - clock->m = clock->m1 * clock->m2; - clock->p = clock->p1 * clock->p2; - if (WARN_ON(clock->n == 0 || clock->p == 0)) - return; - clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); - clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); -} - static bool needs_modeset(struct drm_crtc_state *state) { @@ -589,6 +579,16 @@ static void i9xx_clock(int refclk, intel_clock_t *clock) clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } +static void vlv_clock(int refclk, intel_clock_t *clock) +{ + clock->m = clock->m1 * clock->m2; + clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n == 0 || clock->p == 0)) + return; + clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); + clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); +} + static void chv_clock(int refclk, intel_clock_t *clock) { clock->m = clock->m1 * clock->m2; -- cgit v1.3-6-gb490 From dccbea3b0704c77c5bbd9e5e9240d6eb253d2565 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 22 Jun 2015 23:35:51 +0300 Subject: drm/i915: calculate the port clock rate along with other PLL params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Depending on the platform the port clock fed to the pipe can be the PLL's post-divided fast clock rate or a /5 divided version of it. To make this more obvious across the platforms calculate this port clock along with the rest of the PLL parameters. This is also needed by the next patch where we can reuse the CHV helper for the BXT PLL HW readout code; so export the corresponding helper. While at it also add a more descriptive name to the helpers and a comment explaining what's being calculated. No functional change. Suggested-by: Ville Syrjälä Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 61 +++++++++++++++++++++--------------- drivers/gpu/drm/i915/intel_drv.h | 2 ++ 2 files changed, 38 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8ec0f30f0847..724b0e3a5d37 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -553,15 +553,25 @@ intel_limit(struct intel_crtc_state *crtc_state, int refclk) return limit; } +/* + * Platform specific helpers to calculate the port PLL loopback- (clock.m), + * and post-divider (clock.p) values, pre- (clock.vco) and post-divided fast + * (clock.dot) clock rates. This fast dot clock is fed to the port's IO logic. + * The helpers' return value is the rate of the clock that is fed to the + * display engine's pipe which can be the above fast dot clock rate or a + * divided-down version of it. + */ /* m1 is reserved as 0 in Pineview, n is a ring counter */ -static void pineview_clock(int refclk, intel_clock_t *clock) +static int pnv_calc_dpll_params(int refclk, intel_clock_t *clock) { clock->m = clock->m2 + 2; clock->p = clock->p1 * clock->p2; if (WARN_ON(clock->n == 0 || clock->p == 0)) - return; + return 0; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + return clock->dot; } static uint32_t i9xx_dpll_compute_m(struct dpll *dpll) @@ -569,35 +579,41 @@ static uint32_t i9xx_dpll_compute_m(struct dpll *dpll) return 5 * (dpll->m1 + 2) + (dpll->m2 + 2); } -static void i9xx_clock(int refclk, intel_clock_t *clock) +static int i9xx_calc_dpll_params(int refclk, intel_clock_t *clock) { clock->m = i9xx_dpll_compute_m(clock); clock->p = clock->p1 * clock->p2; if (WARN_ON(clock->n + 2 == 0 || clock->p == 0)) - return; + return 0; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + return clock->dot; } -static void vlv_clock(int refclk, intel_clock_t *clock) +static int vlv_calc_dpll_params(int refclk, intel_clock_t *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2; if (WARN_ON(clock->n == 0 || clock->p == 0)) - return; + return 0; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + return clock->dot / 5; } -static void chv_clock(int refclk, intel_clock_t *clock) +int chv_calc_dpll_params(int refclk, intel_clock_t *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2; if (WARN_ON(clock->n == 0 || clock->p == 0)) - return; + return 0; clock->vco = DIV_ROUND_CLOSEST_ULL((uint64_t)refclk * clock->m, clock->n << 22); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + return clock->dot / 5; } #define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0) @@ -692,7 +708,7 @@ i9xx_find_best_dpll(const intel_limit_t *limit, clock.p1 <= limit->p1.max; clock.p1++) { int this_err; - i9xx_clock(refclk, &clock); + i9xx_calc_dpll_params(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) continue; @@ -737,7 +753,7 @@ pnv_find_best_dpll(const intel_limit_t *limit, clock.p1 <= limit->p1.max; clock.p1++) { int this_err; - pineview_clock(refclk, &clock); + pnv_calc_dpll_params(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) continue; @@ -787,7 +803,7 @@ g4x_find_best_dpll(const intel_limit_t *limit, clock.p1 >= limit->p1.min; clock.p1--) { int this_err; - i9xx_clock(refclk, &clock); + i9xx_calc_dpll_params(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) continue; @@ -877,7 +893,7 @@ vlv_find_best_dpll(const intel_limit_t *limit, clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n, refclk * clock.m1); - vlv_clock(refclk, &clock); + vlv_calc_dpll_params(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) @@ -940,7 +956,7 @@ chv_find_best_dpll(const intel_limit_t *limit, clock.m2 = m2; - chv_clock(refclk, &clock); + chv_calc_dpll_params(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) continue; @@ -7925,10 +7941,7 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc, clock.p1 = (mdiv >> DPIO_P1_SHIFT) & 7; clock.p2 = (mdiv >> DPIO_P2_SHIFT) & 0x1f; - vlv_clock(refclk, &clock); - - /* clock.dot is the fast clock */ - pipe_config->port_clock = clock.dot / 5; + pipe_config->port_clock = vlv_calc_dpll_params(refclk, &clock); } static void @@ -8024,10 +8037,7 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc, clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7; clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f; - chv_clock(refclk, &clock); - - /* clock.dot is the fast clock */ - pipe_config->port_clock = clock.dot / 5; + pipe_config->port_clock = chv_calc_dpll_params(refclk, &clock); } static bool i9xx_get_pipe_config(struct intel_crtc *crtc, @@ -10464,6 +10474,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, u32 dpll = pipe_config->dpll_hw_state.dpll; u32 fp; intel_clock_t clock; + int port_clock; int refclk = i9xx_pll_refclk(dev, pipe_config); if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) @@ -10504,9 +10515,9 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, } if (IS_PINEVIEW(dev)) - pineview_clock(refclk, &clock); + port_clock = pnv_calc_dpll_params(refclk, &clock); else - i9xx_clock(refclk, &clock); + port_clock = i9xx_calc_dpll_params(refclk, &clock); } else { u32 lvds = IS_I830(dev) ? 0 : I915_READ(LVDS); bool is_lvds = (pipe == 1) && (lvds & LVDS_PORT_EN); @@ -10532,7 +10543,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, clock.p2 = 2; } - i9xx_clock(refclk, &clock); + port_clock = i9xx_calc_dpll_params(refclk, &clock); } /* @@ -10540,7 +10551,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, * port_clock to compute adjusted_mode.crtc_clock in the * encoder's get_config() function. */ - pipe_config->port_clock = clock.dot; + pipe_config->port_clock = port_clock; } int intel_dotclock_calculate(int link_freq, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bb52620a3ce8..3f0a89060820 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1140,6 +1140,8 @@ ironlake_check_encoder_dotclock(const struct intel_crtc_state *pipe_config, int dotclock); bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, int target_clock, intel_clock_t *best_clock); +int chv_calc_dpll_params(int refclk, intel_clock_t *pll_clock); + bool intel_crtc_active(struct drm_crtc *crtc); void hsw_enable_ips(struct intel_crtc *crtc); void hsw_disable_ips(struct intel_crtc *crtc); -- cgit v1.3-6-gb490 From aa610dcb7c1999fe3353562340a72196d9a54ae0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 22 Jun 2015 23:35:52 +0300 Subject: drm/i915/bxt: add DDI port HW readout support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for reading out the HW state for DDI ports. Since the actual programming is very similar to the CHV/VLV DPIO PLL programming we can reuse much of the logic from there. This fixes the state checker failures I saw on my BXT with HDMI output. v2: - rebased on v2 of patch 4/5 Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 15 +++++++++------ drivers/gpu/drm/i915/intel_ddi.c | 22 ++++++++++++++++++++-- 2 files changed, 29 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4d8ef2de4374..42ba1ef641d8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1170,10 +1170,12 @@ enum skl_disp_power_wells { #define _PORT_PLL_EBB_0_A 0x162034 #define _PORT_PLL_EBB_0_B 0x6C034 #define _PORT_PLL_EBB_0_C 0x6C340 -#define PORT_PLL_P1_MASK (0x07 << 13) -#define PORT_PLL_P1(x) ((x) << 13) -#define PORT_PLL_P2_MASK (0x1f << 8) -#define PORT_PLL_P2(x) ((x) << 8) +#define PORT_PLL_P1_SHIFT 13 +#define PORT_PLL_P1_MASK (0x07 << PORT_PLL_P1_SHIFT) +#define PORT_PLL_P1(x) ((x) << PORT_PLL_P1_SHIFT) +#define PORT_PLL_P2_SHIFT 8 +#define PORT_PLL_P2_MASK (0x1f << PORT_PLL_P2_SHIFT) +#define PORT_PLL_P2(x) ((x) << PORT_PLL_P2_SHIFT) #define BXT_PORT_PLL_EBB_0(port) _PORT3(port, _PORT_PLL_EBB_0_A, \ _PORT_PLL_EBB_0_B, \ _PORT_PLL_EBB_0_C) @@ -1193,8 +1195,9 @@ enum skl_disp_power_wells { /* PORT_PLL_0_A */ #define PORT_PLL_M2_MASK 0xFF /* PORT_PLL_1_A */ -#define PORT_PLL_N_MASK (0x0F << 8) -#define PORT_PLL_N(x) ((x) << 8) +#define PORT_PLL_N_SHIFT 8 +#define PORT_PLL_N_MASK (0x0F << PORT_PLL_N_SHIFT) +#define PORT_PLL_N(x) ((x) << PORT_PLL_N_SHIFT) /* PORT_PLL_2_A */ #define PORT_PLL_M2_FRAC_MASK 0x3FFFFF /* PORT_PLL_3_A */ diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index cf2896da8ad8..cef9709fa2ba 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1140,8 +1140,26 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder, static int bxt_calc_pll_link(struct drm_i915_private *dev_priv, enum intel_dpll_id dpll) { - /* FIXME formula not available in bspec */ - return 0; + struct intel_shared_dpll *pll; + struct intel_dpll_hw_state *state; + intel_clock_t clock; + + /* For DDI ports we always use a shared PLL. */ + if (WARN_ON(dpll == DPLL_ID_PRIVATE)) + return 0; + + pll = &dev_priv->shared_dplls[dpll]; + state = &pll->config.hw_state; + + clock.m1 = 2; + clock.m2 = (state->pll0 & PORT_PLL_M2_MASK) << 22; + if (state->pll3 & PORT_PLL_M2_FRAC_ENABLE) + clock.m2 |= state->pll2 & PORT_PLL_M2_FRAC_MASK; + clock.n = (state->pll1 & PORT_PLL_N_MASK) >> PORT_PLL_N_SHIFT; + clock.p1 = (state->ebb0 & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT; + clock.p2 = (state->ebb0 & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT; + + return chv_calc_dpll_params(100000, &clock); } static void bxt_ddi_clock_get(struct intel_encoder *encoder, -- cgit v1.3-6-gb490 From 2f2cfc4a9a5b7be65d61382b58cfb206f13966df Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:01 +0530 Subject: ath10k: Add a table to store hw specific values This is to prepare ath10k to support newer chip set. Values like CE_COUNT, MSI_ASSIGN_CE_MAX and RTC_STATE_V_ON can be different for different chips. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 2 ++ drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/hw.c | 14 ++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 18 +++++++++++++++--- 4 files changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f5db43284b97..b17541b74aaf 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1514,9 +1514,11 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, switch (hw_rev) { case ATH10K_HW_QCA988X: ar->regs = &qca988x_regs; + ar->hw_values = &qca988x_values; break; case ATH10K_HW_QCA6174: ar->regs = &qca6174_regs; + ar->hw_values = &qca6174_values; break; default: ath10k_err(ar, "unsupported core hardware revision %d\n", diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index e9f93045fbd8..993cd362fb0a 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -560,6 +560,7 @@ struct ath10k { struct completion target_suspend; const struct ath10k_hw_regs *regs; + const struct ath10k_hw_values *hw_values; struct ath10k_bmi bmi; struct ath10k_wmi wmi; struct ath10k_htc htc; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 5997f00afe3b..48bcd2cfad00 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -58,6 +58,20 @@ const struct ath10k_hw_regs qca6174_regs = { .scratch_3_address = 0x0028, }; +const struct ath10k_hw_values qca988x_values = { + .rtc_state_val_on = 3, + .ce_count = 8, + .msi_assign_ce_max = 7, + .num_target_ce_config_wlan = 7, +}; + +const struct ath10k_hw_values qca6174_values = { + .rtc_state_val_on = 3, + .ce_count = 8, + .msi_assign_ce_max = 7, + .num_target_ce_config_wlan = 7, +}; + void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 85cca29375fe..b218388131ca 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -169,6 +169,16 @@ struct ath10k_hw_regs { extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; +struct ath10k_hw_values { + u32 rtc_state_val_on; + u8 ce_count; + u8 msi_assign_ce_max; + u8 num_target_ce_config_wlan; +}; + +extern const struct ath10k_hw_values qca988x_values; +extern const struct ath10k_hw_values qca6174_values; + void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); @@ -310,8 +320,10 @@ enum ath10k_hw_rate_cck { #define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) #define TARGET_TLV_NUM_WOW_PATTERNS 22 +#define NUM_TARGET_CE_CONFIG_WLAN ar->hw_values->num_target_ce_config_wlan + /* Number of Copy Engines supported */ -#define CE_COUNT 8 +#define CE_COUNT ar->hw_values->ce_count /* * Total number of PCIe MSI interrupts requested for all interrupt sources. @@ -335,10 +347,10 @@ enum ath10k_hw_rate_cck { /* MSIs for Copy Engines */ #define MSI_ASSIGN_CE_INITIAL 1 -#define MSI_ASSIGN_CE_MAX 7 +#define MSI_ASSIGN_CE_MAX ar->hw_values->msi_assign_ce_max /* as of IP3.7.1 */ -#define RTC_STATE_V_ON 3 +#define RTC_STATE_V_ON ar->hw_values->rtc_state_val_on #define RTC_STATE_COLD_RESET_MASK ar->regs->rtc_state_cold_reset_mask #define RTC_STATE_V_LSB 0 -- cgit v1.3-6-gb490 From a521ee983d312db76e6c275c32475cb20bdc7d39 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:02 +0530 Subject: ath10k: Add new reg_address/mask to hw register table Add more register address and mask which can be different for newer chip to hw_reg table. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.h | 6 ++++-- drivers/net/wireless/ath/ath10k/hw.c | 22 ++++++++++++++++++---- drivers/net/wireless/ath/ath10k/hw.h | 17 ++++++++++++----- 3 files changed, 34 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 0eddb204d85b..93939de2be19 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -423,8 +423,10 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) #define CE_RING_IDX_INCR(nentries_mask, idx) (((idx) + 1) & (nentries_mask)) -#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB 8 -#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK 0x0000ff00 +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB \ + ar->regs->ce_wrap_intr_sum_host_msi_lsb +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK \ + ar->regs->ce_wrap_intr_sum_host_msi_mask #define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(x) \ (((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \ CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 48bcd2cfad00..cb09867b5533 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -34,8 +34,15 @@ const struct ath10k_hw_regs qca988x_regs = { .ce7_base_address = 0x00059000, .soc_reset_control_si0_rst_mask = 0x00000001, .soc_reset_control_ce_rst_mask = 0x00040000, - .soc_chip_id_address = 0x00ec, - .scratch_3_address = 0x0030, + .soc_chip_id_address = 0x000000ec, + .scratch_3_address = 0x00000030, + .fw_indicator_address = 0x00009030, + .pcie_local_base_address = 0x00080000, + .ce_wrap_intr_sum_host_msi_lsb = 0x00000008, + .ce_wrap_intr_sum_host_msi_mask = 0x0000ff00, + .pcie_intr_fw_mask = 0x00000400, + .pcie_intr_ce_mask_all = 0x0007f800, + .pcie_intr_clr_address = 0x00000014, }; const struct ath10k_hw_regs qca6174_regs = { @@ -54,8 +61,15 @@ const struct ath10k_hw_regs qca6174_regs = { .ce7_base_address = 0x00036000, .soc_reset_control_si0_rst_mask = 0x00000000, .soc_reset_control_ce_rst_mask = 0x00000001, - .soc_chip_id_address = 0x000f0, - .scratch_3_address = 0x0028, + .soc_chip_id_address = 0x000000f0, + .scratch_3_address = 0x00000028, + .fw_indicator_address = 0x00009028, + .pcie_local_base_address = 0x00080000, + .ce_wrap_intr_sum_host_msi_lsb = 0x00000008, + .ce_wrap_intr_sum_host_msi_mask = 0x0000ff00, + .pcie_intr_fw_mask = 0x00000400, + .pcie_intr_ce_mask_all = 0x0007f800, + .pcie_intr_clr_address = 0x00000014, }; const struct ath10k_hw_values qca988x_values = { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index b218388131ca..5d04317cb3dc 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -164,6 +164,13 @@ struct ath10k_hw_regs { u32 soc_reset_control_ce_rst_mask; u32 soc_chip_id_address; u32 scratch_3_address; + u32 fw_indicator_address; + u32 pcie_local_base_address; + u32 ce_wrap_intr_sum_host_msi_lsb; + u32 ce_wrap_intr_sum_host_msi_mask; + u32 pcie_intr_fw_mask; + u32 pcie_intr_ce_mask_all; + u32 pcie_intr_clr_address; }; extern const struct ath10k_hw_regs qca988x_regs; @@ -386,7 +393,7 @@ enum ath10k_hw_rate_cck { #define CE7_BASE_ADDRESS ar->regs->ce7_base_address #define DBI_BASE_ADDRESS 0x00060000 #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 -#define PCIE_LOCAL_BASE_ADDRESS 0x00080000 +#define PCIE_LOCAL_BASE_ADDRESS ar->regs->pcie_local_base_address #define SOC_RESET_CONTROL_ADDRESS 0x00000000 #define SOC_RESET_CONTROL_OFFSET 0x00000000 @@ -460,7 +467,7 @@ enum ath10k_hw_rate_cck { #define CORE_CTRL_ADDRESS 0x0000 #define PCIE_INTR_ENABLE_ADDRESS 0x0008 #define PCIE_INTR_CAUSE_ADDRESS 0x000c -#define PCIE_INTR_CLR_ADDRESS 0x0014 +#define PCIE_INTR_CLR_ADDRESS ar->regs->pcie_intr_clr_address #define SCRATCH_3_ADDRESS ar->regs->scratch_3_address #define CPU_INTR_ADDRESS 0x0010 @@ -468,13 +475,13 @@ enum ath10k_hw_rate_cck { #define CCNT_TO_MSEC(x) ((x) / 88000) /* Firmware indications to the Host via SCRATCH_3 register. */ -#define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) +#define FW_INDICATOR_ADDRESS ar->regs->fw_indicator_address #define FW_IND_EVENT_PENDING 1 #define FW_IND_INITIALIZED 2 /* HOST_REG interrupt from firmware */ -#define PCIE_INTR_FIRMWARE_MASK 0x00000400 -#define PCIE_INTR_CE_MASK_ALL 0x0007f800 +#define PCIE_INTR_FIRMWARE_MASK ar->regs->pcie_intr_fw_mask +#define PCIE_INTR_CE_MASK_ALL ar->regs->pcie_intr_ce_mask_all #define DRAM_BASE_ADDRESS 0x00400000 -- cgit v1.3-6-gb490 From 8bd4702103dca2b06446f85c04222faa8eb553b5 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:03 +0530 Subject: ath10k: Add hw register/values for QCA99X0 chip This is to prepare the driver for QCA99X0 chip support. This commit adds hw_params, hw register table and hw_values table for QCA99X0 chip. Please note this is only a partial patch adding support for QCA99X0, so the device id is not yet added to pci device table. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 18 ++++++++++++ drivers/net/wireless/ath/ath10k/hw.c | 44 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 18 ++++++++++++ drivers/net/wireless/ath/ath10k/pci.c | 5 ++++ drivers/net/wireless/ath/ath10k/targaddrs.h | 3 ++ 5 files changed, 88 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index b17541b74aaf..f239e9690831 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -101,6 +101,20 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, }, }, + { + .id = QCA99X0_HW_2_0_DEV_VERSION, + .name = "qca99x0 hw2.0", + .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .fw = { + .dir = QCA99X0_HW_2_0_FW_DIR, + .fw = QCA99X0_HW_2_0_FW_FILE, + .otp = QCA99X0_HW_2_0_OTP_FILE, + .board = QCA99X0_HW_2_0_BOARD_DATA_FILE, + .board_size = QCA99X0_BOARD_DATA_SZ, + .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, + }, + }, }; static const char *const ath10k_core_fw_feature_str[] = { @@ -1520,6 +1534,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ar->regs = &qca6174_regs; ar->hw_values = &qca6174_values; break; + case ATH10K_HW_QCA99X0: + ar->regs = &qca99x0_regs; + ar->hw_values = &qca99x0_values; + break; default: ath10k_err(ar, "unsupported core hardware revision %d\n", hw_rev); diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index cb09867b5533..e5fe33d9ca43 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -72,6 +72,43 @@ const struct ath10k_hw_regs qca6174_regs = { .pcie_intr_clr_address = 0x00000014, }; +const struct ath10k_hw_regs qca99x0_regs = { + .rtc_state_cold_reset_mask = 0x00000400, + .rtc_soc_base_address = 0x00080000, + .rtc_wmac_base_address = 0x00000000, + .soc_core_base_address = 0x00082000, + .ce_wrapper_base_address = 0x0004d000, + .ce0_base_address = 0x0004a000, + .ce1_base_address = 0x0004a400, + .ce2_base_address = 0x0004a800, + .ce3_base_address = 0x0004ac00, + .ce4_base_address = 0x0004b000, + .ce5_base_address = 0x0004b400, + .ce6_base_address = 0x0004b800, + .ce7_base_address = 0x0004bc00, + /* Note: qca99x0 supports upto 12 Copy Engines. Other than address of + * CE0 and CE1 no other copy engine is directly referred in the code. + * It is not really neccessary to assign address for newly supported + * CEs in this address table. + * Copy Engine Address + * CE8 0x0004c000 + * CE9 0x0004c400 + * CE10 0x0004c800 + * CE11 0x0004cc00 + */ + .soc_reset_control_si0_rst_mask = 0x00000001, + .soc_reset_control_ce_rst_mask = 0x00000100, + .soc_chip_id_address = 0x000000ec, + .scratch_3_address = 0x00040050, + .fw_indicator_address = 0x00040050, + .pcie_local_base_address = 0x00000000, + .ce_wrap_intr_sum_host_msi_lsb = 0x0000000c, + .ce_wrap_intr_sum_host_msi_mask = 0x00fff000, + .pcie_intr_fw_mask = 0x00100000, + .pcie_intr_ce_mask_all = 0x000fff00, + .pcie_intr_clr_address = 0x00000010, +}; + const struct ath10k_hw_values qca988x_values = { .rtc_state_val_on = 3, .ce_count = 8, @@ -86,6 +123,13 @@ const struct ath10k_hw_values qca6174_values = { .num_target_ce_config_wlan = 7, }; +const struct ath10k_hw_values qca99x0_values = { + .rtc_state_val_on = 5, + .ce_count = 12, + .msi_assign_ce_max = 12, + .num_target_ce_config_wlan = 10, +}; + void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 5d04317cb3dc..76caeab5c7d3 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -72,6 +72,18 @@ enum qca6174_chip_id_rev { #define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin" #define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234 +/* QCA99X0 1.0 definitions (unsupported) */ +#define QCA99X0_HW_1_0_CHIP_ID_REV 0x0 + +/* QCA99X0 2.0 definitions */ +#define QCA99X0_HW_2_0_DEV_VERSION 0x01000000 +#define QCA99X0_HW_2_0_CHIP_ID_REV 0x1 +#define QCA99X0_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA99X0/hw2.0" +#define QCA99X0_HW_2_0_FW_FILE "firmware.bin" +#define QCA99X0_HW_2_0_OTP_FILE "otp.bin" +#define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin" +#define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234 + #define ATH10K_FW_API2_FILE "firmware-2.bin" #define ATH10K_FW_API3_FILE "firmware-3.bin" @@ -144,6 +156,7 @@ enum ath10k_fw_htt_op_version { enum ath10k_hw_rev { ATH10K_HW_QCA988X, ATH10K_HW_QCA6174, + ATH10K_HW_QCA99X0, }; struct ath10k_hw_regs { @@ -175,6 +188,7 @@ struct ath10k_hw_regs { extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; +extern const struct ath10k_hw_regs qca99x0_regs; struct ath10k_hw_values { u32 rtc_state_val_on; @@ -185,12 +199,14 @@ struct ath10k_hw_values { extern const struct ath10k_hw_values qca988x_values; extern const struct ath10k_hw_values qca6174_values; +extern const struct ath10k_hw_values qca99x0_values; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); #define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X) #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) +#define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0) /* Known pecularities: * - current FW doesn't support raw rx mode (last tested v599) @@ -485,6 +501,8 @@ enum ath10k_hw_rate_cck { #define DRAM_BASE_ADDRESS 0x00400000 +#define PCIE_BAR_REG_ADDRESS 0x40030 + #define MISSING 0 #define SYSTEM_SLEEP_OFFSET SOC_SYSTEM_SLEEP_OFFSET diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 41765172297c..0007e7077f9c 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -59,6 +59,7 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); #define QCA988X_2_0_DEVICE_ID (0x003c) #define QCA6174_2_1_DEVICE_ID (0x003e) +#define QCA99X0_2_0_DEVICE_ID (0x0040) static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ @@ -1699,6 +1700,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) switch (ar_pci->pdev->device) { case QCA988X_2_0_DEVICE_ID: + case QCA99X0_2_0_DEVICE_ID: return 1; case QCA6174_2_1_DEVICE_ID: switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) { @@ -2758,6 +2760,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev, case QCA6174_2_1_DEVICE_ID: hw_rev = ATH10K_HW_QCA6174; break; + case QCA99X0_2_0_DEVICE_ID: + hw_rev = ATH10K_HW_QCA99X0; + break; default: WARN_ON(1); return -ENOTSUPP; diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index a417aae52623..768bef629099 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -450,4 +450,7 @@ Fw Mode/SubMode Mask #define QCA6174_BOARD_DATA_SZ 8192 #define QCA6174_BOARD_EXT_DATA_SZ 0 +#define QCA99X0_BOARD_DATA_SZ 12288 +#define QCA99X0_BOARD_EXT_DATA_SZ 0 + #endif /* __TARGADDRS_H__ */ -- cgit v1.3-6-gb490 From 050af069de03489947023544bfed1977952b8215 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:04 +0530 Subject: ath10k: Copy Engine related changes for QCA99X0 QCA99X0 supports upto 12 Copy engines. Host and target CE configuration table is updated to support new copy engine pipes. This also fixes the assumption of diagnostic CE by making CE_7 as the one instead of CE_COUNT - 1. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.h | 2 +- drivers/net/wireless/ath/ath10k/hw.h | 3 ++ drivers/net/wireless/ath/ath10k/pci.c | 69 ++++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 93939de2be19..bb4b8f3e7c5c 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -21,7 +21,7 @@ #include "hif.h" /* Maximum number of Copy Engine's supported */ -#define CE_COUNT_MAX 8 +#define CE_COUNT_MAX 12 #define CE_HTT_H2T_MSG_SRC_NENTRIES 4096 /* Descriptor rings must be aligned to this boundary */ diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 76caeab5c7d3..581965947594 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -343,6 +343,9 @@ enum ath10k_hw_rate_cck { #define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) #define TARGET_TLV_NUM_WOW_PATTERNS 22 +/* Diagnostic Window */ +#define CE_DIAG_PIPE 7 + #define NUM_TARGET_CE_CONFIG_WLAN ar->hw_values->num_target_ce_config_wlan /* Number of Copy Engines supported */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 0007e7077f9c..c2aecfe76544 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -156,6 +156,38 @@ static const struct ce_attr host_ce_config_wlan[] = { .src_sz_max = DIAG_TRANSFER_LIMIT, .dest_nentries = 2, }, + + /* CE8: target->host pktlog */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 128, + }, + + /* CE9 target autonomous qcache memcpy */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, + + /* CE10: target autonomous hif memcpy */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, + + /* CE11: target autonomous hif memcpy */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, }; /* Target firmware's Copy Engine configuration. */ @@ -233,6 +265,38 @@ static const struct ce_pipe_config target_ce_config_wlan[] = { }, /* CE7 used only by Host */ + { + .pipenum = __cpu_to_le32(7), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(0), + .nbytes_max = __cpu_to_le32(0), + .flags = __cpu_to_le32(0), + .reserved = __cpu_to_le32(0), + }, + + /* CE8 target->host packtlog */ + { + .pipenum = __cpu_to_le32(8), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(64), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE9 target autonomous qcache memcpy */ + { + .pipenum = __cpu_to_le32(9), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* It not necessary to send target wlan configuration for CE10 & CE11 + * as these CEs are not actively used in target. + */ }; /* @@ -1771,7 +1835,8 @@ static int ath10k_pci_init_config(struct ath10k *ar) ret = ath10k_pci_diag_write_mem(ar, pipe_cfg_targ_addr, target_ce_config_wlan, - sizeof(target_ce_config_wlan)); + sizeof(struct ce_pipe_config) * + NUM_TARGET_CE_CONFIG_WLAN); if (ret != 0) { ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret); @@ -1885,7 +1950,7 @@ static int ath10k_pci_alloc_pipes(struct ath10k *ar) } /* Last CE is Diagnostic Window */ - if (i == CE_COUNT - 1) { + if (i == CE_DIAG_PIPE) { ar_pci->ce_diag = pipe->ce_hdl; continue; } -- cgit v1.3-6-gb490 From 418ca5992e2f91050e0673b3a3a78197f0122bf8 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:05 +0530 Subject: ath10k: Make target cpu address to CE address conversion chip specific Make the helper converting target virtual address space to CE address space a target type specific to support QCA99X0. Also make this as function instead of macro. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 25 ++++++++++++++++++++++--- drivers/net/wireless/ath/ath10k/pci.h | 12 ------------ 2 files changed, 22 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index c2aecfe76544..df7d74e75149 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -755,6 +755,26 @@ static void ath10k_pci_rx_replenish_retry(unsigned long ptr) ath10k_pci_rx_post(ar); } +static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) +{ + u32 val = 0; + + switch (ar->hw_rev) { + case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA6174: + val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS) & + 0x7fff) << 21; + break; + case ATH10K_HW_QCA99X0: + val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS); + break; + } + + val |= 0x100000 | (addr & 0xfffff); + return val; +} + /* * Diagnostic read/write access is provided for startup/config/debug usage. * Caller must guarantee proper alignment, when applicable, and single user @@ -817,8 +837,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, * convert it from Target CPU virtual address space * to CE address space */ - address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, - address); + address = ath10k_pci_targ_cpu_to_ce_addr(ar, address); ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0, 0); @@ -976,7 +995,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, * to * CE address space */ - address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address); + address = ath10k_pci_targ_cpu_to_ce_addr(ar, address); remaining_bytes = orig_nbytes; ce_data = ce_data_base; diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index eea0a0170b00..8d364fb8f743 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -237,18 +237,6 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) #define CDC_WAR_MAGIC_STR 0xceef0000 #define CDC_WAR_DATA_CE 4 -/* - * TODO: Should be a function call specific to each Target-type. - * This convoluted macro converts from Target CPU Virtual Address Space to CE - * Address Space. As part of this process, we conservatively fetch the current - * PCIE_BAR. MOST of the time, this should match the upper bits of PCI space - * for this device; but that's not guaranteed. - */ -#define TARG_CPU_SPACE_TO_CE_SPACE(ar, pci_addr, addr) \ - (((ath10k_pci_read32(ar, (SOC_CORE_BASE_ADDRESS | \ - CORE_CTRL_ADDRESS)) & 0x7ff) << 21) | \ - 0x100000 | ((addr) & 0xfffff)) - /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */ #define DIAG_ACCESS_CE_TIMEOUT_MS 10 -- cgit v1.3-6-gb490 From 6e4202c3ed301dea62885a3ead6506534fcf8db3 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:06 +0530 Subject: ath10k: Add chip reset sequence for QCA99X0 QCA99X0 supports only cold reset. Also, made ath10k_pci_irq_msi_fw_mask() and ath10k_pci_irq_msi_fw_unmask() non-99X0 specific till we get proper register configuration to mask/unmask irq/MSI. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 81 ++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index df7d74e75149..1b4634a6374d 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -82,7 +82,7 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { static void ath10k_pci_buffer_cleanup(struct ath10k *ar); static int ath10k_pci_cold_reset(struct ath10k *ar); -static int ath10k_pci_warm_reset(struct ath10k *ar); +static int ath10k_pci_safe_chip_reset(struct ath10k *ar); static int ath10k_pci_wait_for_target_init(struct ath10k *ar); static int ath10k_pci_init_irq(struct ath10k *ar); static int ath10k_pci_deinit_irq(struct ath10k *ar); @@ -91,6 +91,7 @@ static void ath10k_pci_free_irq(struct ath10k *ar); static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, struct ath10k_ce_pipe *rx_pipe, struct bmi_xfer *xfer); +static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar); static const struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ @@ -1427,20 +1428,42 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) { u32 val; - val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); - val &= ~CORE_CTRL_PCIE_REG_31_MASK; - - ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); + switch (ar->hw_rev) { + case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA6174: + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS); + val &= ~CORE_CTRL_PCIE_REG_31_MASK; + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS, val); + break; + case ATH10K_HW_QCA99X0: + /* TODO: Find appropriate register configuration for QCA99X0 + * to mask irq/MSI. + */ + break; + } } static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) { u32 val; - val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); - val |= CORE_CTRL_PCIE_REG_31_MASK; - - ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); + switch (ar->hw_rev) { + case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA6174: + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS); + val |= CORE_CTRL_PCIE_REG_31_MASK; + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS, val); + break; + case ATH10K_HW_QCA99X0: + /* TODO: Find appropriate register configuration for QCA99X0 + * to unmask irq/MSI. + */ + break; + } } static void ath10k_pci_irq_disable(struct ath10k *ar) @@ -1602,7 +1625,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) * masked. To prevent the device from asserting the interrupt reset it * before proceeding with cleanup. */ - ath10k_pci_warm_reset(ar); + ath10k_pci_safe_chip_reset(ar); ath10k_pci_irq_disable(ar); ath10k_pci_irq_sync(ar); @@ -2114,6 +2137,18 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) return 0; } +static int ath10k_pci_safe_chip_reset(struct ath10k *ar) +{ + if (QCA_REV_988X(ar) || QCA_REV_6174(ar)) { + return ath10k_pci_warm_reset(ar); + } else if (QCA_REV_99X0(ar)) { + ath10k_pci_irq_disable(ar); + return ath10k_pci_qca99x0_chip_reset(ar); + } else { + return -ENOTSUPP; + } +} + static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar) { int i, ret; @@ -2220,12 +2255,38 @@ static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar) return 0; } +static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset\n"); + + ret = ath10k_pci_cold_reset(ar); + if (ret) { + ath10k_warn(ar, "failed to cold reset: %d\n", ret); + return ret; + } + + ret = ath10k_pci_wait_for_target_init(ar); + if (ret) { + ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", + ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset complete (cold)\n"); + + return 0; +} + static int ath10k_pci_chip_reset(struct ath10k *ar) { if (QCA_REV_988X(ar)) return ath10k_pci_qca988x_chip_reset(ar); else if (QCA_REV_6174(ar)) return ath10k_pci_qca6174_chip_reset(ar); + else if (QCA_REV_99X0(ar)) + return ath10k_pci_qca99x0_chip_reset(ar); else return -ENOTSUPP; } -- cgit v1.3-6-gb490 From 2adf99ca33ca75c8a702797f77a1652e26f18a6e Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:07 +0530 Subject: ath10k: Extend CE src desc flags for interrupt indication QCA99X0 uses two new copy engine src desc flags for interrupt indication. Bit_2 is to mark if host interrupt is disabled after processing the current desc and bit_3 is to mark if target interrupt is diabled after the processing of current descriptor. CE_DESC_FLAGS_META_DATA_MASK and CE_DESC_FLAGS_META_DATA_LSB are based on the target type. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 1 + drivers/net/wireless/ath/ath10k/ce.h | 9 +++++++-- drivers/net/wireless/ath/ath10k/hw.c | 6 ++++++ drivers/net/wireless/ath/ath10k/hw.h | 2 ++ 4 files changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index e508c65b6ba8..cf28fbebaedc 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -452,6 +452,7 @@ int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, { struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; + struct ath10k *ar = ce_state->ar; unsigned int sw_index = dest_ring->sw_index; struct ce_desc *base = dest_ring->base_addr_owner_space; diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index bb4b8f3e7c5c..5c903e15dd65 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -38,8 +38,13 @@ struct ath10k_ce_pipe; #define CE_DESC_FLAGS_GATHER (1 << 0) #define CE_DESC_FLAGS_BYTE_SWAP (1 << 1) -#define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC -#define CE_DESC_FLAGS_META_DATA_LSB 2 + +/* Following desc flags are used in QCA99X0 */ +#define CE_DESC_FLAGS_HOST_INT_DIS (1 << 2) +#define CE_DESC_FLAGS_TGT_INT_DIS (1 << 3) + +#define CE_DESC_FLAGS_META_DATA_MASK ar->hw_values->ce_desc_meta_data_mask +#define CE_DESC_FLAGS_META_DATA_LSB ar->hw_values->ce_desc_meta_data_lsb struct ce_desc { __le32 addr; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index e5fe33d9ca43..1414e1f3c7ac 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -114,6 +114,8 @@ const struct ath10k_hw_values qca988x_values = { .ce_count = 8, .msi_assign_ce_max = 7, .num_target_ce_config_wlan = 7, + .ce_desc_meta_data_mask = 0xFFFC, + .ce_desc_meta_data_lsb = 2, }; const struct ath10k_hw_values qca6174_values = { @@ -121,6 +123,8 @@ const struct ath10k_hw_values qca6174_values = { .ce_count = 8, .msi_assign_ce_max = 7, .num_target_ce_config_wlan = 7, + .ce_desc_meta_data_mask = 0xFFFC, + .ce_desc_meta_data_lsb = 2, }; const struct ath10k_hw_values qca99x0_values = { @@ -128,6 +132,8 @@ const struct ath10k_hw_values qca99x0_values = { .ce_count = 12, .msi_assign_ce_max = 12, .num_target_ce_config_wlan = 10, + .ce_desc_meta_data_mask = 0xFFF0, + .ce_desc_meta_data_lsb = 4, }; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 581965947594..35cd8caaf738 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -195,6 +195,8 @@ struct ath10k_hw_values { u8 ce_count; u8 msi_assign_ce_max; u8 num_target_ce_config_wlan; + u16 ce_desc_meta_data_mask; + u8 ce_desc_meta_data_lsb; }; extern const struct ath10k_hw_values qca988x_values; -- cgit v1.3-6-gb490 From fd3d6ffbd035d24b2baff0b5b39751183c289b33 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:08 +0530 Subject: ath10k: Fix BMI communication timeout for QCA99X0 There is more than 1 sec delay in getting response from target through BMI in QCA99X0. Increase the BMI communication timeout to 2*HZ to fix BMI failures. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 31a990635490..df7c7616533b 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -178,7 +178,7 @@ struct bmi_target_info { }; /* in msec */ -#define BMI_COMMUNICATION_TIMEOUT_HZ (1*HZ) +#define BMI_COMMUNICATION_TIMEOUT_HZ (2 * HZ) #define BMI_CE_NUM_TO_TARG 0 #define BMI_CE_NUM_TO_HOST 1 -- cgit v1.3-6-gb490 From dcb02db1068b78bd1b4d2bf64317021c2531a7b0 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:09 +0530 Subject: ath10k: Add support for code swap Code swap is a mechanism to use host memory to store some fw binary code segment. Ath10k host driver allocates and loads the code swap binary into the host memory and configures the target with the host allocated memory information at the address taken from code swap binary. This patch adds code swap support for firmware binary. Code swap binary for firmware bin is available in ATH10K_FW_IE_FW_CODE_SWAP_IMAGE. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Makefile | 3 +- drivers/net/wireless/ath/ath10k/core.c | 24 ++++ drivers/net/wireless/ath/ath10k/core.h | 7 ++ drivers/net/wireless/ath/ath10k/hw.h | 3 + drivers/net/wireless/ath/ath10k/swap.c | 208 +++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/swap.h | 72 +++++++++++ 6 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/ath10k/swap.c create mode 100644 drivers/net/wireless/ath/ath10k/swap.h (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 9729e6941635..c04fb00e7930 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -11,7 +11,8 @@ ath10k_core-y += mac.o \ wmi-tlv.o \ bmi.o \ hw.o \ - p2p.o + p2p.o \ + swap.o ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f239e9690831..c5f5d160deb7 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -470,6 +470,13 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode) data = ar->firmware_data; data_len = ar->firmware_len; mode_name = "normal"; + ret = ath10k_swap_code_seg_configure(ar, + ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW); + if (ret) { + ath10k_err(ar, "failed to configure fw code swap: %d\n", + ret); + return ret; + } break; case ATH10K_FIRMWARE_MODE_UTF: data = ar->testmode.utf->data; @@ -509,6 +516,8 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) if (!IS_ERR(ar->cal_file)) release_firmware(ar->cal_file); + ath10k_swap_code_seg_release(ar); + ar->board = NULL; ar->board_data = NULL; ar->board_len = 0; @@ -522,6 +531,7 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) ar->firmware_len = 0; ar->cal_file = NULL; + } static int ath10k_fetch_cal_file(struct ath10k *ar) @@ -795,6 +805,13 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n", ar->htt.op_version); break; + case ATH10K_FW_IE_FW_CODE_SWAP_IMAGE: + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "found fw code swap image ie (%zd B)\n", + ie_len); + ar->swap.firmware_codeswap_data = data; + ar->swap.firmware_codeswap_len = ie_len; + break; default: ath10k_warn(ar, "Unknown FW IE: %u\n", le32_to_cpu(hdr->id)); @@ -1388,6 +1405,13 @@ static int ath10k_core_probe_fw(struct ath10k *ar) goto err_free_firmware_files; } + ret = ath10k_swap_code_seg_init(ar); + if (ret) { + ath10k_err(ar, "failed to initialize code swap segment: %d\n", + ret); + goto err_free_firmware_files; + } + mutex_lock(&ar->conf_mutex); ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 993cd362fb0a..b9145f539aa9 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -36,6 +36,7 @@ #include "spectral.h" #include "thermal.h" #include "wow.h" +#include "swap.h" #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -603,6 +604,12 @@ struct ath10k { const struct firmware *cal_file; + struct { + const void *firmware_codeswap_data; + size_t firmware_codeswap_len; + struct ath10k_swap_code_seg_info *firmware_swap_code_seg_info; + } swap; + char spec_board_id[100]; bool spec_board_loaded; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 35cd8caaf738..3e277814ce93 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -124,6 +124,9 @@ enum ath10k_fw_ie_type { * FW API 5 and above. */ ATH10K_FW_IE_HTT_OP_VERSION = 6, + + /* Code swap image for firmware binary */ + ATH10K_FW_IE_FW_CODE_SWAP_IMAGE = 7, }; enum ath10k_fw_wmi_op_version { diff --git a/drivers/net/wireless/ath/ath10k/swap.c b/drivers/net/wireless/ath/ath10k/swap.c new file mode 100644 index 000000000000..3ca3fae408a7 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/swap.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, 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. + */ + +/* This file has implementation for code swap logic. With code swap feature, + * target can run the fw binary with even smaller IRAM size by using host + * memory to store some of the code segments. + */ + +#include "core.h" +#include "bmi.h" +#include "debug.h" + +static int ath10k_swap_code_seg_fill(struct ath10k *ar, + struct ath10k_swap_code_seg_info *seg_info, + const void *data, size_t data_len) +{ + u8 *virt_addr = seg_info->virt_address[0]; + u8 swap_magic[ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ] = {}; + const u8 *fw_data = data; + union ath10k_swap_code_seg_item *swap_item; + u32 length = 0; + u32 payload_len; + u32 total_payload_len = 0; + u32 size_left = data_len; + + /* Parse swap bin and copy the content to host allocated memory. + * The format is Address, length and value. The last 4-bytes is + * target write address. Currently address field is not used. + */ + seg_info->target_addr = -1; + while (size_left >= sizeof(*swap_item)) { + swap_item = (union ath10k_swap_code_seg_item *)fw_data; + payload_len = __le32_to_cpu(swap_item->tlv.length); + if ((payload_len > size_left) || + (payload_len == 0 && + size_left != sizeof(struct ath10k_swap_code_seg_tail))) { + ath10k_err(ar, "refusing to parse invalid tlv length %d\n", + payload_len); + return -EINVAL; + } + + if (payload_len == 0) { + if (memcmp(swap_item->tail.magic_signature, swap_magic, + ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ)) { + ath10k_err(ar, "refusing an invalid swap file\n"); + return -EINVAL; + } + seg_info->target_addr = + __le32_to_cpu(swap_item->tail.bmi_write_addr); + break; + } + + memcpy(virt_addr, swap_item->tlv.data, payload_len); + virt_addr += payload_len; + length = payload_len + sizeof(struct ath10k_swap_code_seg_tlv); + size_left -= length; + fw_data += length; + total_payload_len += payload_len; + } + + if (seg_info->target_addr == -1) { + ath10k_err(ar, "failed to parse invalid swap file\n"); + return -EINVAL; + } + seg_info->seg_hw_info.swap_size = __cpu_to_le32(total_payload_len); + + return 0; +} + +static void +ath10k_swap_code_seg_free(struct ath10k *ar, + struct ath10k_swap_code_seg_info *seg_info) +{ + u32 seg_size; + + if (!seg_info) + return; + + if (!seg_info->virt_address[0]) + return; + + seg_size = __le32_to_cpu(seg_info->seg_hw_info.size); + dma_free_coherent(ar->dev, seg_size, seg_info->virt_address[0], + seg_info->paddr[0]); +} + +static struct ath10k_swap_code_seg_info * +ath10k_swap_code_seg_alloc(struct ath10k *ar, size_t swap_bin_len) +{ + struct ath10k_swap_code_seg_info *seg_info; + void *virt_addr; + dma_addr_t paddr; + + swap_bin_len = roundup(swap_bin_len, 2); + if (swap_bin_len > ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX) { + ath10k_err(ar, "refusing code swap bin because it is too big %zu > %d\n", + swap_bin_len, ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX); + return NULL; + } + + seg_info = devm_kzalloc(ar->dev, sizeof(*seg_info), GFP_KERNEL); + if (!seg_info) + return NULL; + + virt_addr = dma_alloc_coherent(ar->dev, swap_bin_len, &paddr, + GFP_KERNEL); + if (!virt_addr) { + ath10k_err(ar, "failed to allocate dma coherent memory\n"); + return NULL; + } + + seg_info->seg_hw_info.bus_addr[0] = __cpu_to_le32(paddr); + seg_info->seg_hw_info.size = __cpu_to_le32(swap_bin_len); + seg_info->seg_hw_info.swap_size = __cpu_to_le32(swap_bin_len); + seg_info->seg_hw_info.num_segs = + __cpu_to_le32(ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED); + seg_info->seg_hw_info.size_log2 = __cpu_to_le32(ilog2(swap_bin_len)); + seg_info->virt_address[0] = virt_addr; + seg_info->paddr[0] = paddr; + + return seg_info; +} + +int ath10k_swap_code_seg_configure(struct ath10k *ar, + enum ath10k_swap_code_seg_bin_type type) +{ + int ret; + struct ath10k_swap_code_seg_info *seg_info = NULL; + + switch (type) { + case ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW: + if (!ar->swap.firmware_swap_code_seg_info) + return 0; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot found firmware code swap binary\n"); + seg_info = ar->swap.firmware_swap_code_seg_info; + break; + default: + case ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP: + case ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF: + ath10k_warn(ar, "ignoring unknown code swap binary type %d\n", + type); + return 0; + } + + ret = ath10k_bmi_write_memory(ar, seg_info->target_addr, + &seg_info->seg_hw_info, + sizeof(seg_info->seg_hw_info)); + if (ret) { + ath10k_err(ar, "failed to write Code swap segment information (%d)\n", + ret); + return ret; + } + + return 0; +} + +void ath10k_swap_code_seg_release(struct ath10k *ar) +{ + ath10k_swap_code_seg_free(ar, ar->swap.firmware_swap_code_seg_info); + ar->swap.firmware_codeswap_data = NULL; + ar->swap.firmware_codeswap_len = 0; + ar->swap.firmware_swap_code_seg_info = NULL; +} + +int ath10k_swap_code_seg_init(struct ath10k *ar) +{ + int ret; + struct ath10k_swap_code_seg_info *seg_info; + + if (!ar->swap.firmware_codeswap_len || !ar->swap.firmware_codeswap_data) + return 0; + + seg_info = ath10k_swap_code_seg_alloc(ar, + ar->swap.firmware_codeswap_len); + if (!seg_info) { + ath10k_err(ar, "failed to allocate fw code swap segment\n"); + return -ENOMEM; + } + + ret = ath10k_swap_code_seg_fill(ar, seg_info, + ar->swap.firmware_codeswap_data, + ar->swap.firmware_codeswap_len); + + if (ret) { + ath10k_warn(ar, "failed to initialize fw code swap segment: %d\n", + ret); + ath10k_swap_code_seg_free(ar, seg_info); + return ret; + } + + ar->swap.firmware_swap_code_seg_info = seg_info; + + return 0; +} diff --git a/drivers/net/wireless/ath/ath10k/swap.h b/drivers/net/wireless/ath/ath10k/swap.h new file mode 100644 index 000000000000..5c89952dd20f --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/swap.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, 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 _SWAP_H_ +#define _SWAP_H_ + +#define ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX (512 * 1024) +#define ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ 12 +#define ATH10K_SWAP_CODE_SEG_NUM_MAX 16 +/* Currently only one swap segment is supported */ +#define ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED 1 + +struct ath10k_swap_code_seg_tlv { + __le32 address; + __le32 length; + u8 data[0]; +} __packed; + +struct ath10k_swap_code_seg_tail { + u8 magic_signature[ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ]; + __le32 bmi_write_addr; +} __packed; + +union ath10k_swap_code_seg_item { + struct ath10k_swap_code_seg_tlv tlv; + struct ath10k_swap_code_seg_tail tail; +} __packed; + +enum ath10k_swap_code_seg_bin_type { + ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP, + ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW, + ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF, +}; + +struct ath10k_swap_code_seg_hw_info { + /* Swap binary image size */ + __le32 swap_size; + __le32 num_segs; + + /* Swap data size */ + __le32 size; + __le32 size_log2; + __le32 bus_addr[ATH10K_SWAP_CODE_SEG_NUM_MAX]; + __le64 reserved[ATH10K_SWAP_CODE_SEG_NUM_MAX]; +} __packed; + +struct ath10k_swap_code_seg_info { + struct ath10k_swap_code_seg_hw_info seg_hw_info; + void *virt_address[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED]; + u32 target_addr; + dma_addr_t paddr[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED]; +}; + +int ath10k_swap_code_seg_configure(struct ath10k *ar, + enum ath10k_swap_code_seg_bin_type type); +void ath10k_swap_code_seg_release(struct ath10k *ar); +int ath10k_swap_code_seg_init(struct ath10k *ar); + +#endif -- cgit v1.3-6-gb490 From d772703e705961dc4bd280373e3679c8c4f95df7 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:10 +0530 Subject: ath10k: Add BMI param value to execute otp to hw_param BMI parameter value to execute downloaded otp binary is different for QCA99X0. Have a member in hw_params to hold hw specific BMI param. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 8 +++++++- drivers/net/wireless/ath/ath10k/core.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c5f5d160deb7..80f38b50296b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -49,6 +49,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .has_shifted_cc_wraparound = true, + .otp_exe_param = 0, .fw = { .dir = QCA988X_HW_2_0_FW_DIR, .fw = QCA988X_HW_2_0_FW_FILE, @@ -63,6 +64,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw2.1", .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, .uart_pin = 6, + .otp_exe_param = 0, .fw = { .dir = QCA6174_HW_2_1_FW_DIR, .fw = QCA6174_HW_2_1_FW_FILE, @@ -77,6 +79,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw3.0", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, + .otp_exe_param = 0, .fw = { .dir = QCA6174_HW_3_0_FW_DIR, .fw = QCA6174_HW_3_0_FW_FILE, @@ -91,6 +94,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw3.2", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, + .otp_exe_param = 0, .fw = { /* uses same binaries as hw3.0 */ .dir = QCA6174_HW_3_0_FW_DIR, @@ -106,6 +110,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca99x0 hw2.0", .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, + .otp_exe_param = 0x00000700, .fw = { .dir = QCA99X0_HW_2_0_FW_DIR, .fw = QCA99X0_HW_2_0_FW_FILE, @@ -413,6 +418,7 @@ out: static int ath10k_download_and_run_otp(struct ath10k *ar) { u32 result, address = ar->hw_params.patch_load_addr; + u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param; int ret; ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len); @@ -438,7 +444,7 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) return ret; } - ret = ath10k_bmi_execute(ar, address, 0, &result); + ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); if (ret) { ath10k_err(ar, "could not execute otp (%d)\n", ret); return ret; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index b9145f539aa9..afd21d5b25ae 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -572,6 +572,7 @@ struct ath10k { const char *name; u32 patch_load_addr; int uart_pin; + u32 otp_exe_param; /* This is true if given HW chip has a quirky Cycle Counter * wraparound which resets to 0x7fffffff instead of 0. All -- cgit v1.3-6-gb490 From 9bd213224654b8c13af8bffcf9bd07ee0baae5ef Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:09 +0530 Subject: ath10k: include new wmi op version for 10.4 fw qca99X0 chip uses firmware version 10.4. Define a new macro ATH10K_FW_WMI_OP_VERSION_10_4 for 10.4 firmware and include in switch cases where ATH10K_FW_WMI_OP_VERSION_* is used to avoid compilation error. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 2 ++ drivers/net/wireless/ath/ath10k/hw.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 2 ++ drivers/net/wireless/ath/ath10k/wmi.c | 2 ++ 4 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 80f38b50296b..5e8d8af5d0d0 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1115,6 +1115,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | WMI_STAT_PEER; break; + case ATH10K_FW_WMI_OP_VERSION_10_4: case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); @@ -1137,6 +1138,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_TLV: ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_TLV; break; + case ATH10K_FW_WMI_OP_VERSION_10_4: case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 3e277814ce93..b0c89b48092d 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -137,6 +137,7 @@ enum ath10k_fw_wmi_op_version { ATH10K_FW_WMI_OP_VERSION_10_2 = 3, ATH10K_FW_WMI_OP_VERSION_TLV = 4, ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5, + ATH10K_FW_WMI_OP_VERSION_10_4 = 6, /* keep last */ ATH10K_FW_WMI_OP_VERSION_MAX, diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e17eb75c508e..a8561d1f26e3 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6943,6 +6943,8 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_10x_if_comb); break; + case ATH10K_FW_WMI_OP_VERSION_10_4: + break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6c046c244705..b32bb6825f3c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5415,6 +5415,8 @@ static const struct wmi_ops wmi_10_2_4_ops = { int ath10k_wmi_attach(struct ath10k *ar) { switch (ar->wmi.op_version) { + case ATH10K_FW_WMI_OP_VERSION_10_4: + break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; ar->wmi.ops = &wmi_10_2_4_ops; -- cgit v1.3-6-gb490 From 840357ccc365b650d2321a5690cb5374192619ca Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:10 +0530 Subject: ath10k: add 10.4 fw wmi service bitmap definition Include new enum to define wmi service bitmap definitions for 10.4 firmware and a function wmi_10_4_svc_map() to remap 10.4 firmware wmi service bitmap definitions to ath10k generic wmi services. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 5 ++ drivers/net/wireless/ath/ath10k/wmi.h | 146 ++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b32bb6825f3c..52493d14c9b0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5412,10 +5412,15 @@ static const struct wmi_ops wmi_10_2_4_ops = { /* .gen_adaptive_qcs not implemented */ }; +static const struct wmi_ops wmi_10_4_ops = { + .map_svc = wmi_10_4_svc_map, +}; + int ath10k_wmi_attach(struct ath10k *ar) { switch (ar->wmi.op_version) { case ATH10K_FW_WMI_OP_VERSION_10_4: + ar->wmi.ops = &wmi_10_4_ops; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index cf44a3d080a3..b54d14b00819 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -150,6 +150,12 @@ enum wmi_service { WMI_SERVICE_SAP_AUTH_OFFLOAD, WMI_SERVICE_ATF, WMI_SERVICE_COEX_GPIO, + WMI_SERVICE_ENHANCED_PROXY_STA, + WMI_SERVICE_TT, + WMI_SERVICE_PEER_CACHING, + WMI_SERVICE_AUX_SPECTRAL_INTF, + WMI_SERVICE_AUX_CHAN_LOAD_INTF, + WMI_SERVICE_BSS_CHANNEL_INFO_64, /* keep last */ WMI_SERVICE_MAX, @@ -218,6 +224,51 @@ enum wmi_main_service { WMI_MAIN_SERVICE_TX_ENCAP, }; +enum wmi_10_4_service { + WMI_10_4_SERVICE_BEACON_OFFLOAD = 0, + WMI_10_4_SERVICE_SCAN_OFFLOAD, + WMI_10_4_SERVICE_ROAM_OFFLOAD, + WMI_10_4_SERVICE_BCN_MISS_OFFLOAD, + WMI_10_4_SERVICE_STA_PWRSAVE, + WMI_10_4_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_10_4_SERVICE_AP_UAPSD, + WMI_10_4_SERVICE_AP_DFS, + WMI_10_4_SERVICE_11AC, + WMI_10_4_SERVICE_BLOCKACK, + WMI_10_4_SERVICE_PHYERR, + WMI_10_4_SERVICE_BCN_FILTER, + WMI_10_4_SERVICE_RTT, + WMI_10_4_SERVICE_RATECTRL, + WMI_10_4_SERVICE_WOW, + WMI_10_4_SERVICE_RATECTRL_CACHE, + WMI_10_4_SERVICE_IRAM_TIDS, + WMI_10_4_SERVICE_BURST, + WMI_10_4_SERVICE_SMART_ANTENNA_SW_SUPPORT, + WMI_10_4_SERVICE_GTK_OFFLOAD, + WMI_10_4_SERVICE_SCAN_SCH, + WMI_10_4_SERVICE_CSA_OFFLOAD, + WMI_10_4_SERVICE_CHATTER, + WMI_10_4_SERVICE_COEX_FREQAVOID, + WMI_10_4_SERVICE_PACKET_POWER_SAVE, + WMI_10_4_SERVICE_FORCE_FW_HANG, + WMI_10_4_SERVICE_SMART_ANTENNA_HW_SUPPORT, + WMI_10_4_SERVICE_GPIO, + WMI_10_4_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_10_4_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_10_4_SERVICE_STA_KEEP_ALIVE, + WMI_10_4_SERVICE_TX_ENCAP, + WMI_10_4_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_10_4_SERVICE_EARLY_RX, + WMI_10_4_SERVICE_ENHANCED_PROXY_STA, + WMI_10_4_SERVICE_TT, + WMI_10_4_SERVICE_ATF, + WMI_10_4_SERVICE_PEER_CACHING, + WMI_10_4_SERVICE_COEX_GPIO, + WMI_10_4_SERVICE_AUX_SPECTRAL_INTF, + WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF, + WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, +}; + static inline char *wmi_service_name(int service_id) { #define SVCSTR(x) case x: return #x @@ -299,6 +350,12 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_SAP_AUTH_OFFLOAD); SVCSTR(WMI_SERVICE_ATF); SVCSTR(WMI_SERVICE_COEX_GPIO); + SVCSTR(WMI_SERVICE_ENHANCED_PROXY_STA); + SVCSTR(WMI_SERVICE_TT); + SVCSTR(WMI_SERVICE_PEER_CACHING); + SVCSTR(WMI_SERVICE_AUX_SPECTRAL_INTF); + SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF); + SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64); default: return NULL; } @@ -437,6 +494,95 @@ static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_TX_ENCAP, len); } +static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, + size_t len) +{ + SVCMAP(WMI_10_4_SERVICE_BEACON_OFFLOAD, + WMI_SERVICE_BEACON_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_SCAN_OFFLOAD, + WMI_SERVICE_SCAN_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_ROAM_OFFLOAD, + WMI_SERVICE_ROAM_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_BCN_MISS_OFFLOAD, + WMI_SERVICE_BCN_MISS_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_STA_PWRSAVE, + WMI_SERVICE_STA_PWRSAVE, len); + SVCMAP(WMI_10_4_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); + SVCMAP(WMI_10_4_SERVICE_AP_UAPSD, + WMI_SERVICE_AP_UAPSD, len); + SVCMAP(WMI_10_4_SERVICE_AP_DFS, + WMI_SERVICE_AP_DFS, len); + SVCMAP(WMI_10_4_SERVICE_11AC, + WMI_SERVICE_11AC, len); + SVCMAP(WMI_10_4_SERVICE_BLOCKACK, + WMI_SERVICE_BLOCKACK, len); + SVCMAP(WMI_10_4_SERVICE_PHYERR, + WMI_SERVICE_PHYERR, len); + SVCMAP(WMI_10_4_SERVICE_BCN_FILTER, + WMI_SERVICE_BCN_FILTER, len); + SVCMAP(WMI_10_4_SERVICE_RTT, + WMI_SERVICE_RTT, len); + SVCMAP(WMI_10_4_SERVICE_RATECTRL, + WMI_SERVICE_RATECTRL, len); + SVCMAP(WMI_10_4_SERVICE_WOW, + WMI_SERVICE_WOW, len); + SVCMAP(WMI_10_4_SERVICE_RATECTRL_CACHE, + WMI_SERVICE_RATECTRL_CACHE, len); + SVCMAP(WMI_10_4_SERVICE_IRAM_TIDS, + WMI_SERVICE_IRAM_TIDS, len); + SVCMAP(WMI_10_4_SERVICE_BURST, + WMI_SERVICE_BURST, len); + SVCMAP(WMI_10_4_SERVICE_SMART_ANTENNA_SW_SUPPORT, + WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_GTK_OFFLOAD, + WMI_SERVICE_GTK_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_SCAN_SCH, + WMI_SERVICE_SCAN_SCH, len); + SVCMAP(WMI_10_4_SERVICE_CSA_OFFLOAD, + WMI_SERVICE_CSA_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_CHATTER, + WMI_SERVICE_CHATTER, len); + SVCMAP(WMI_10_4_SERVICE_COEX_FREQAVOID, + WMI_SERVICE_COEX_FREQAVOID, len); + SVCMAP(WMI_10_4_SERVICE_PACKET_POWER_SAVE, + WMI_SERVICE_PACKET_POWER_SAVE, len); + SVCMAP(WMI_10_4_SERVICE_FORCE_FW_HANG, + WMI_SERVICE_FORCE_FW_HANG, len); + SVCMAP(WMI_10_4_SERVICE_SMART_ANTENNA_HW_SUPPORT, + WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_GPIO, + WMI_SERVICE_GPIO, len); + SVCMAP(WMI_10_4_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len); + SVCMAP(WMI_10_4_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len); + SVCMAP(WMI_10_4_SERVICE_STA_KEEP_ALIVE, + WMI_SERVICE_STA_KEEP_ALIVE, len); + SVCMAP(WMI_10_4_SERVICE_TX_ENCAP, + WMI_SERVICE_TX_ENCAP, len); + SVCMAP(WMI_10_4_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, len); + SVCMAP(WMI_10_4_SERVICE_EARLY_RX, + WMI_SERVICE_EARLY_RX, len); + SVCMAP(WMI_10_4_SERVICE_ENHANCED_PROXY_STA, + WMI_SERVICE_ENHANCED_PROXY_STA, len); + SVCMAP(WMI_10_4_SERVICE_TT, + WMI_SERVICE_TT, len); + SVCMAP(WMI_10_4_SERVICE_ATF, + WMI_SERVICE_ATF, len); + SVCMAP(WMI_10_4_SERVICE_PEER_CACHING, + WMI_SERVICE_PEER_CACHING, len); + SVCMAP(WMI_10_4_SERVICE_COEX_GPIO, + WMI_SERVICE_COEX_GPIO, len); + SVCMAP(WMI_10_4_SERVICE_AUX_SPECTRAL_INTF, + WMI_SERVICE_AUX_SPECTRAL_INTF, len); + SVCMAP(WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF, + WMI_SERVICE_AUX_CHAN_LOAD_INTF, len); + SVCMAP(WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, + WMI_SERVICE_BSS_CHANNEL_INFO_64, len); +} + #undef SVCMAP /* 2 word representation of MAC addr */ -- cgit v1.3-6-gb490 From 2d491e69962a94bbeb0449a060cca2d156f943e9 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:11 +0530 Subject: ath10k: include 10.4 fw specific wmi cmd and event ids 10.4 firmware wmi cmd and event id values are not exactly aligned with previous firmware versions (main, 10.x, 10.2, etc). Add new enum to define wmi cmd & event definitions for 10.4 firmware and prepare wmi_10_4_cmd_map based on 10.4 firmware wmi cmd definitions. wmi_cmd_map is extended to accommodate new wmi commands which are exclusively available in 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 184 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 252 ++++++++++++++++++++++++++++++++++ 2 files changed, 436 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 52493d14c9b0..8dc937de98ab 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -395,6 +395,189 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { .pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, }; +/* 10.4 WMI cmd track */ +static struct wmi_cmd_map wmi_10_4_cmd_map = { + .init_cmdid = WMI_10_4_INIT_CMDID, + .start_scan_cmdid = WMI_10_4_START_SCAN_CMDID, + .stop_scan_cmdid = WMI_10_4_STOP_SCAN_CMDID, + .scan_chan_list_cmdid = WMI_10_4_SCAN_CHAN_LIST_CMDID, + .scan_sch_prio_tbl_cmdid = WMI_10_4_SCAN_SCH_PRIO_TBL_CMDID, + .pdev_set_regdomain_cmdid = WMI_10_4_PDEV_SET_REGDOMAIN_CMDID, + .pdev_set_channel_cmdid = WMI_10_4_PDEV_SET_CHANNEL_CMDID, + .pdev_set_param_cmdid = WMI_10_4_PDEV_SET_PARAM_CMDID, + .pdev_pktlog_enable_cmdid = WMI_10_4_PDEV_PKTLOG_ENABLE_CMDID, + .pdev_pktlog_disable_cmdid = WMI_10_4_PDEV_PKTLOG_DISABLE_CMDID, + .pdev_set_wmm_params_cmdid = WMI_10_4_PDEV_SET_WMM_PARAMS_CMDID, + .pdev_set_ht_cap_ie_cmdid = WMI_10_4_PDEV_SET_HT_CAP_IE_CMDID, + .pdev_set_vht_cap_ie_cmdid = WMI_10_4_PDEV_SET_VHT_CAP_IE_CMDID, + .pdev_set_dscp_tid_map_cmdid = WMI_10_4_PDEV_SET_DSCP_TID_MAP_CMDID, + .pdev_set_quiet_mode_cmdid = WMI_10_4_PDEV_SET_QUIET_MODE_CMDID, + .pdev_green_ap_ps_enable_cmdid = WMI_10_4_PDEV_GREEN_AP_PS_ENABLE_CMDID, + .pdev_get_tpc_config_cmdid = WMI_10_4_PDEV_GET_TPC_CONFIG_CMDID, + .pdev_set_base_macaddr_cmdid = WMI_10_4_PDEV_SET_BASE_MACADDR_CMDID, + .vdev_create_cmdid = WMI_10_4_VDEV_CREATE_CMDID, + .vdev_delete_cmdid = WMI_10_4_VDEV_DELETE_CMDID, + .vdev_start_request_cmdid = WMI_10_4_VDEV_START_REQUEST_CMDID, + .vdev_restart_request_cmdid = WMI_10_4_VDEV_RESTART_REQUEST_CMDID, + .vdev_up_cmdid = WMI_10_4_VDEV_UP_CMDID, + .vdev_stop_cmdid = WMI_10_4_VDEV_STOP_CMDID, + .vdev_down_cmdid = WMI_10_4_VDEV_DOWN_CMDID, + .vdev_set_param_cmdid = WMI_10_4_VDEV_SET_PARAM_CMDID, + .vdev_install_key_cmdid = WMI_10_4_VDEV_INSTALL_KEY_CMDID, + .peer_create_cmdid = WMI_10_4_PEER_CREATE_CMDID, + .peer_delete_cmdid = WMI_10_4_PEER_DELETE_CMDID, + .peer_flush_tids_cmdid = WMI_10_4_PEER_FLUSH_TIDS_CMDID, + .peer_set_param_cmdid = WMI_10_4_PEER_SET_PARAM_CMDID, + .peer_assoc_cmdid = WMI_10_4_PEER_ASSOC_CMDID, + .peer_add_wds_entry_cmdid = WMI_10_4_PEER_ADD_WDS_ENTRY_CMDID, + .peer_remove_wds_entry_cmdid = WMI_10_4_PEER_REMOVE_WDS_ENTRY_CMDID, + .peer_mcast_group_cmdid = WMI_10_4_PEER_MCAST_GROUP_CMDID, + .bcn_tx_cmdid = WMI_10_4_BCN_TX_CMDID, + .pdev_send_bcn_cmdid = WMI_10_4_PDEV_SEND_BCN_CMDID, + .bcn_tmpl_cmdid = WMI_10_4_BCN_PRB_TMPL_CMDID, + .bcn_filter_rx_cmdid = WMI_10_4_BCN_FILTER_RX_CMDID, + .prb_req_filter_rx_cmdid = WMI_10_4_PRB_REQ_FILTER_RX_CMDID, + .mgmt_tx_cmdid = WMI_10_4_MGMT_TX_CMDID, + .prb_tmpl_cmdid = WMI_10_4_PRB_TMPL_CMDID, + .addba_clear_resp_cmdid = WMI_10_4_ADDBA_CLEAR_RESP_CMDID, + .addba_send_cmdid = WMI_10_4_ADDBA_SEND_CMDID, + .addba_status_cmdid = WMI_10_4_ADDBA_STATUS_CMDID, + .delba_send_cmdid = WMI_10_4_DELBA_SEND_CMDID, + .addba_set_resp_cmdid = WMI_10_4_ADDBA_SET_RESP_CMDID, + .send_singleamsdu_cmdid = WMI_10_4_SEND_SINGLEAMSDU_CMDID, + .sta_powersave_mode_cmdid = WMI_10_4_STA_POWERSAVE_MODE_CMDID, + .sta_powersave_param_cmdid = WMI_10_4_STA_POWERSAVE_PARAM_CMDID, + .sta_mimo_ps_mode_cmdid = WMI_10_4_STA_MIMO_PS_MODE_CMDID, + .pdev_dfs_enable_cmdid = WMI_10_4_PDEV_DFS_ENABLE_CMDID, + .pdev_dfs_disable_cmdid = WMI_10_4_PDEV_DFS_DISABLE_CMDID, + .roam_scan_mode = WMI_10_4_ROAM_SCAN_MODE, + .roam_scan_rssi_threshold = WMI_10_4_ROAM_SCAN_RSSI_THRESHOLD, + .roam_scan_period = WMI_10_4_ROAM_SCAN_PERIOD, + .roam_scan_rssi_change_threshold = + WMI_10_4_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + .roam_ap_profile = WMI_10_4_ROAM_AP_PROFILE, + .ofl_scan_add_ap_profile = WMI_10_4_OFL_SCAN_ADD_AP_PROFILE, + .ofl_scan_remove_ap_profile = WMI_10_4_OFL_SCAN_REMOVE_AP_PROFILE, + .ofl_scan_period = WMI_10_4_OFL_SCAN_PERIOD, + .p2p_dev_set_device_info = WMI_10_4_P2P_DEV_SET_DEVICE_INFO, + .p2p_dev_set_discoverability = WMI_10_4_P2P_DEV_SET_DISCOVERABILITY, + .p2p_go_set_beacon_ie = WMI_10_4_P2P_GO_SET_BEACON_IE, + .p2p_go_set_probe_resp_ie = WMI_10_4_P2P_GO_SET_PROBE_RESP_IE, + .p2p_set_vendor_ie_data_cmdid = WMI_10_4_P2P_SET_VENDOR_IE_DATA_CMDID, + .ap_ps_peer_param_cmdid = WMI_10_4_AP_PS_PEER_PARAM_CMDID, + .ap_ps_peer_uapsd_coex_cmdid = WMI_10_4_AP_PS_PEER_UAPSD_COEX_CMDID, + .peer_rate_retry_sched_cmdid = WMI_10_4_PEER_RATE_RETRY_SCHED_CMDID, + .wlan_profile_trigger_cmdid = WMI_10_4_WLAN_PROFILE_TRIGGER_CMDID, + .wlan_profile_set_hist_intvl_cmdid = + WMI_10_4_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + .wlan_profile_get_profile_data_cmdid = + WMI_10_4_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + .wlan_profile_enable_profile_id_cmdid = + WMI_10_4_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + .wlan_profile_list_profile_id_cmdid = + WMI_10_4_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + .pdev_suspend_cmdid = WMI_10_4_PDEV_SUSPEND_CMDID, + .pdev_resume_cmdid = WMI_10_4_PDEV_RESUME_CMDID, + .add_bcn_filter_cmdid = WMI_10_4_ADD_BCN_FILTER_CMDID, + .rmv_bcn_filter_cmdid = WMI_10_4_RMV_BCN_FILTER_CMDID, + .wow_add_wake_pattern_cmdid = WMI_10_4_WOW_ADD_WAKE_PATTERN_CMDID, + .wow_del_wake_pattern_cmdid = WMI_10_4_WOW_DEL_WAKE_PATTERN_CMDID, + .wow_enable_disable_wake_event_cmdid = + WMI_10_4_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + .wow_enable_cmdid = WMI_10_4_WOW_ENABLE_CMDID, + .wow_hostwakeup_from_sleep_cmdid = + WMI_10_4_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + .rtt_measreq_cmdid = WMI_10_4_RTT_MEASREQ_CMDID, + .rtt_tsf_cmdid = WMI_10_4_RTT_TSF_CMDID, + .vdev_spectral_scan_configure_cmdid = + WMI_10_4_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, + .vdev_spectral_scan_enable_cmdid = + WMI_10_4_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + .request_stats_cmdid = WMI_10_4_REQUEST_STATS_CMDID, + .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED, + .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED, + .gtk_offload_cmdid = WMI_10_4_GTK_OFFLOAD_CMDID, + .csa_offload_enable_cmdid = WMI_10_4_CSA_OFFLOAD_ENABLE_CMDID, + .csa_offload_chanswitch_cmdid = WMI_10_4_CSA_OFFLOAD_CHANSWITCH_CMDID, + .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED, + .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED, + .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED, + .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED, + .echo_cmdid = WMI_10_4_ECHO_CMDID, + .pdev_utf_cmdid = WMI_10_4_PDEV_UTF_CMDID, + .dbglog_cfg_cmdid = WMI_10_4_DBGLOG_CFG_CMDID, + .pdev_qvit_cmdid = WMI_10_4_PDEV_QVIT_CMDID, + .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_keepalive_cmdid = WMI_10_4_VDEV_SET_KEEPALIVE_CMDID, + .vdev_get_keepalive_cmdid = WMI_10_4_VDEV_GET_KEEPALIVE_CMDID, + .force_fw_hang_cmdid = WMI_10_4_FORCE_FW_HANG_CMDID, + .gpio_config_cmdid = WMI_10_4_GPIO_CONFIG_CMDID, + .gpio_output_cmdid = WMI_10_4_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_10_4_PDEV_GET_TEMPERATURE_CMDID, + .vdev_set_wmm_params_cmdid = WMI_CMD_UNSUPPORTED, + .tdls_set_state_cmdid = WMI_CMD_UNSUPPORTED, + .tdls_peer_update_cmdid = WMI_CMD_UNSUPPORTED, + .adaptive_qcs_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_10_4_SCAN_UPDATE_REQUEST_CMDID, + .vdev_standby_response_cmdid = WMI_10_4_VDEV_STANDBY_RESPONSE_CMDID, + .vdev_resume_response_cmdid = WMI_10_4_VDEV_RESUME_RESPONSE_CMDID, + .wlan_peer_caching_add_peer_cmdid = + WMI_10_4_WLAN_PEER_CACHING_ADD_PEER_CMDID, + .wlan_peer_caching_evict_peer_cmdid = + WMI_10_4_WLAN_PEER_CACHING_EVICT_PEER_CMDID, + .wlan_peer_caching_restore_peer_cmdid = + WMI_10_4_WLAN_PEER_CACHING_RESTORE_PEER_CMDID, + .wlan_peer_caching_print_all_peers_info_cmdid = + WMI_10_4_WLAN_PEER_CACHING_PRINT_ALL_PEERS_INFO_CMDID, + .peer_update_wds_entry_cmdid = WMI_10_4_PEER_UPDATE_WDS_ENTRY_CMDID, + .peer_add_proxy_sta_entry_cmdid = + WMI_10_4_PEER_ADD_PROXY_STA_ENTRY_CMDID, + .rtt_keepalive_cmdid = WMI_10_4_RTT_KEEPALIVE_CMDID, + .oem_req_cmdid = WMI_10_4_OEM_REQ_CMDID, + .nan_cmdid = WMI_10_4_NAN_CMDID, + .vdev_ratemask_cmdid = WMI_10_4_VDEV_RATEMASK_CMDID, + .qboost_cfg_cmdid = WMI_10_4_QBOOST_CFG_CMDID, + .pdev_smart_ant_enable_cmdid = WMI_10_4_PDEV_SMART_ANT_ENABLE_CMDID, + .pdev_smart_ant_set_rx_antenna_cmdid = + WMI_10_4_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID, + .peer_smart_ant_set_tx_antenna_cmdid = + WMI_10_4_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID, + .peer_smart_ant_set_train_info_cmdid = + WMI_10_4_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID, + .peer_smart_ant_set_node_config_ops_cmdid = + WMI_10_4_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, + .pdev_set_antenna_switch_table_cmdid = + WMI_10_4_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID, + .pdev_set_ctl_table_cmdid = WMI_10_4_PDEV_SET_CTL_TABLE_CMDID, + .pdev_set_mimogain_table_cmdid = WMI_10_4_PDEV_SET_MIMOGAIN_TABLE_CMDID, + .pdev_ratepwr_table_cmdid = WMI_10_4_PDEV_RATEPWR_TABLE_CMDID, + .pdev_ratepwr_chainmsk_table_cmdid = + WMI_10_4_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, + .pdev_fips_cmdid = WMI_10_4_PDEV_FIPS_CMDID, + .tt_set_conf_cmdid = WMI_10_4_TT_SET_CONF_CMDID, + .fwtest_cmdid = WMI_10_4_FWTEST_CMDID, + .vdev_atf_request_cmdid = WMI_10_4_VDEV_ATF_REQUEST_CMDID, + .peer_atf_request_cmdid = WMI_10_4_PEER_ATF_REQUEST_CMDID, + .pdev_get_ani_cck_config_cmdid = WMI_10_4_PDEV_GET_ANI_CCK_CONFIG_CMDID, + .pdev_get_ani_ofdm_config_cmdid = + WMI_10_4_PDEV_GET_ANI_OFDM_CONFIG_CMDID, + .pdev_reserve_ast_entry_cmdid = WMI_10_4_PDEV_RESERVE_AST_ENTRY_CMDID, + .pdev_get_nfcal_power_cmdid = WMI_10_4_PDEV_GET_NFCAL_POWER_CMDID, + .pdev_get_tpc_cmdid = WMI_10_4_PDEV_GET_TPC_CMDID, + .pdev_get_ast_info_cmdid = WMI_10_4_PDEV_GET_AST_INFO_CMDID, + .vdev_set_dscp_tid_map_cmdid = WMI_10_4_VDEV_SET_DSCP_TID_MAP_CMDID, + .pdev_get_info_cmdid = WMI_10_4_PDEV_GET_INFO_CMDID, + .vdev_get_info_cmdid = WMI_10_4_VDEV_GET_INFO_CMDID, + .vdev_filter_neighbor_rx_packets_cmdid = + WMI_10_4_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID, + .mu_cal_start_cmdid = WMI_10_4_MU_CAL_START_CMDID, + .set_cca_params_cmdid = WMI_10_4_SET_CCA_PARAMS_CMDID, + .pdev_bss_chan_info_request_cmdid = + WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, +}; + /* MAIN WMI VDEV param map */ static struct wmi_vdev_param_map wmi_vdev_param_map = { .rts_threshold = WMI_VDEV_PARAM_RTS_THRESHOLD, @@ -5421,6 +5604,7 @@ int ath10k_wmi_attach(struct ath10k *ar) switch (ar->wmi.op_version) { case ATH10K_FW_WMI_OP_VERSION_10_4: ar->wmi.ops = &wmi_10_4_ops; + ar->wmi.cmd = &wmi_10_4_cmd_map; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b54d14b00819..c3a05a9a05ae 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -711,6 +711,48 @@ struct wmi_cmd_map { u32 tdls_set_state_cmdid; u32 tdls_peer_update_cmdid; u32 adaptive_qcs_cmdid; + u32 scan_update_request_cmdid; + u32 vdev_standby_response_cmdid; + u32 vdev_resume_response_cmdid; + u32 wlan_peer_caching_add_peer_cmdid; + u32 wlan_peer_caching_evict_peer_cmdid; + u32 wlan_peer_caching_restore_peer_cmdid; + u32 wlan_peer_caching_print_all_peers_info_cmdid; + u32 peer_update_wds_entry_cmdid; + u32 peer_add_proxy_sta_entry_cmdid; + u32 rtt_keepalive_cmdid; + u32 oem_req_cmdid; + u32 nan_cmdid; + u32 vdev_ratemask_cmdid; + u32 qboost_cfg_cmdid; + u32 pdev_smart_ant_enable_cmdid; + u32 pdev_smart_ant_set_rx_antenna_cmdid; + u32 peer_smart_ant_set_tx_antenna_cmdid; + u32 peer_smart_ant_set_train_info_cmdid; + u32 peer_smart_ant_set_node_config_ops_cmdid; + u32 pdev_set_antenna_switch_table_cmdid; + u32 pdev_set_ctl_table_cmdid; + u32 pdev_set_mimogain_table_cmdid; + u32 pdev_ratepwr_table_cmdid; + u32 pdev_ratepwr_chainmsk_table_cmdid; + u32 pdev_fips_cmdid; + u32 tt_set_conf_cmdid; + u32 fwtest_cmdid; + u32 vdev_atf_request_cmdid; + u32 peer_atf_request_cmdid; + u32 pdev_get_ani_cck_config_cmdid; + u32 pdev_get_ani_ofdm_config_cmdid; + u32 pdev_reserve_ast_entry_cmdid; + u32 pdev_get_nfcal_power_cmdid; + u32 pdev_get_tpc_cmdid; + u32 pdev_get_ast_info_cmdid; + u32 vdev_set_dscp_tid_map_cmdid; + u32 pdev_get_info_cmdid; + u32 vdev_get_info_cmdid; + u32 vdev_filter_neighbor_rx_packets_cmdid; + u32 mu_cal_start_cmdid; + u32 set_cca_params_cmdid; + u32 pdev_bss_chan_info_request_cmdid; }; /* @@ -1366,6 +1408,216 @@ enum wmi_10_2_event_id { WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1, }; +enum wmi_10_4_cmd_id { + WMI_10_4_START_CMDID = 0x9000, + WMI_10_4_END_CMDID = 0x9FFF, + WMI_10_4_INIT_CMDID, + WMI_10_4_START_SCAN_CMDID = WMI_10_4_START_CMDID, + WMI_10_4_STOP_SCAN_CMDID, + WMI_10_4_SCAN_CHAN_LIST_CMDID, + WMI_10_4_SCAN_SCH_PRIO_TBL_CMDID, + WMI_10_4_SCAN_UPDATE_REQUEST_CMDID, + WMI_10_4_ECHO_CMDID, + WMI_10_4_PDEV_SET_REGDOMAIN_CMDID, + WMI_10_4_PDEV_SET_CHANNEL_CMDID, + WMI_10_4_PDEV_SET_PARAM_CMDID, + WMI_10_4_PDEV_PKTLOG_ENABLE_CMDID, + WMI_10_4_PDEV_PKTLOG_DISABLE_CMDID, + WMI_10_4_PDEV_SET_WMM_PARAMS_CMDID, + WMI_10_4_PDEV_SET_HT_CAP_IE_CMDID, + WMI_10_4_PDEV_SET_VHT_CAP_IE_CMDID, + WMI_10_4_PDEV_SET_BASE_MACADDR_CMDID, + WMI_10_4_PDEV_SET_DSCP_TID_MAP_CMDID, + WMI_10_4_PDEV_SET_QUIET_MODE_CMDID, + WMI_10_4_PDEV_GREEN_AP_PS_ENABLE_CMDID, + WMI_10_4_PDEV_GET_TPC_CONFIG_CMDID, + WMI_10_4_VDEV_CREATE_CMDID, + WMI_10_4_VDEV_DELETE_CMDID, + WMI_10_4_VDEV_START_REQUEST_CMDID, + WMI_10_4_VDEV_RESTART_REQUEST_CMDID, + WMI_10_4_VDEV_UP_CMDID, + WMI_10_4_VDEV_STOP_CMDID, + WMI_10_4_VDEV_DOWN_CMDID, + WMI_10_4_VDEV_STANDBY_RESPONSE_CMDID, + WMI_10_4_VDEV_RESUME_RESPONSE_CMDID, + WMI_10_4_VDEV_SET_PARAM_CMDID, + WMI_10_4_VDEV_INSTALL_KEY_CMDID, + WMI_10_4_WLAN_PEER_CACHING_ADD_PEER_CMDID, + WMI_10_4_WLAN_PEER_CACHING_EVICT_PEER_CMDID, + WMI_10_4_WLAN_PEER_CACHING_RESTORE_PEER_CMDID, + WMI_10_4_WLAN_PEER_CACHING_PRINT_ALL_PEERS_INFO_CMDID, + WMI_10_4_PEER_CREATE_CMDID, + WMI_10_4_PEER_DELETE_CMDID, + WMI_10_4_PEER_FLUSH_TIDS_CMDID, + WMI_10_4_PEER_SET_PARAM_CMDID, + WMI_10_4_PEER_ASSOC_CMDID, + WMI_10_4_PEER_ADD_WDS_ENTRY_CMDID, + WMI_10_4_PEER_UPDATE_WDS_ENTRY_CMDID, + WMI_10_4_PEER_REMOVE_WDS_ENTRY_CMDID, + WMI_10_4_PEER_ADD_PROXY_STA_ENTRY_CMDID, + WMI_10_4_PEER_MCAST_GROUP_CMDID, + WMI_10_4_BCN_TX_CMDID, + WMI_10_4_PDEV_SEND_BCN_CMDID, + WMI_10_4_BCN_PRB_TMPL_CMDID, + WMI_10_4_BCN_FILTER_RX_CMDID, + WMI_10_4_PRB_REQ_FILTER_RX_CMDID, + WMI_10_4_MGMT_TX_CMDID, + WMI_10_4_PRB_TMPL_CMDID, + WMI_10_4_ADDBA_CLEAR_RESP_CMDID, + WMI_10_4_ADDBA_SEND_CMDID, + WMI_10_4_ADDBA_STATUS_CMDID, + WMI_10_4_DELBA_SEND_CMDID, + WMI_10_4_ADDBA_SET_RESP_CMDID, + WMI_10_4_SEND_SINGLEAMSDU_CMDID, + WMI_10_4_STA_POWERSAVE_MODE_CMDID, + WMI_10_4_STA_POWERSAVE_PARAM_CMDID, + WMI_10_4_STA_MIMO_PS_MODE_CMDID, + WMI_10_4_DBGLOG_CFG_CMDID, + WMI_10_4_PDEV_DFS_ENABLE_CMDID, + WMI_10_4_PDEV_DFS_DISABLE_CMDID, + WMI_10_4_PDEV_QVIT_CMDID, + WMI_10_4_ROAM_SCAN_MODE, + WMI_10_4_ROAM_SCAN_RSSI_THRESHOLD, + WMI_10_4_ROAM_SCAN_PERIOD, + WMI_10_4_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + WMI_10_4_ROAM_AP_PROFILE, + WMI_10_4_OFL_SCAN_ADD_AP_PROFILE, + WMI_10_4_OFL_SCAN_REMOVE_AP_PROFILE, + WMI_10_4_OFL_SCAN_PERIOD, + WMI_10_4_P2P_DEV_SET_DEVICE_INFO, + WMI_10_4_P2P_DEV_SET_DISCOVERABILITY, + WMI_10_4_P2P_GO_SET_BEACON_IE, + WMI_10_4_P2P_GO_SET_PROBE_RESP_IE, + WMI_10_4_P2P_SET_VENDOR_IE_DATA_CMDID, + WMI_10_4_AP_PS_PEER_PARAM_CMDID, + WMI_10_4_AP_PS_PEER_UAPSD_COEX_CMDID, + WMI_10_4_PEER_RATE_RETRY_SCHED_CMDID, + WMI_10_4_WLAN_PROFILE_TRIGGER_CMDID, + WMI_10_4_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + WMI_10_4_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + WMI_10_4_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + WMI_10_4_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + WMI_10_4_PDEV_SUSPEND_CMDID, + WMI_10_4_PDEV_RESUME_CMDID, + WMI_10_4_ADD_BCN_FILTER_CMDID, + WMI_10_4_RMV_BCN_FILTER_CMDID, + WMI_10_4_WOW_ADD_WAKE_PATTERN_CMDID, + WMI_10_4_WOW_DEL_WAKE_PATTERN_CMDID, + WMI_10_4_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + WMI_10_4_WOW_ENABLE_CMDID, + WMI_10_4_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + WMI_10_4_RTT_MEASREQ_CMDID, + WMI_10_4_RTT_TSF_CMDID, + WMI_10_4_RTT_KEEPALIVE_CMDID, + WMI_10_4_OEM_REQ_CMDID, + WMI_10_4_NAN_CMDID, + WMI_10_4_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, + WMI_10_4_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + WMI_10_4_REQUEST_STATS_CMDID, + WMI_10_4_GPIO_CONFIG_CMDID, + WMI_10_4_GPIO_OUTPUT_CMDID, + WMI_10_4_VDEV_RATEMASK_CMDID, + WMI_10_4_CSA_OFFLOAD_ENABLE_CMDID, + WMI_10_4_GTK_OFFLOAD_CMDID, + WMI_10_4_QBOOST_CFG_CMDID, + WMI_10_4_CSA_OFFLOAD_CHANSWITCH_CMDID, + WMI_10_4_PDEV_SMART_ANT_ENABLE_CMDID, + WMI_10_4_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID, + WMI_10_4_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID, + WMI_10_4_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID, + WMI_10_4_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, + WMI_10_4_VDEV_SET_KEEPALIVE_CMDID, + WMI_10_4_VDEV_GET_KEEPALIVE_CMDID, + WMI_10_4_FORCE_FW_HANG_CMDID, + WMI_10_4_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID, + WMI_10_4_PDEV_SET_CTL_TABLE_CMDID, + WMI_10_4_PDEV_SET_MIMOGAIN_TABLE_CMDID, + WMI_10_4_PDEV_RATEPWR_TABLE_CMDID, + WMI_10_4_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, + WMI_10_4_PDEV_FIPS_CMDID, + WMI_10_4_TT_SET_CONF_CMDID, + WMI_10_4_FWTEST_CMDID, + WMI_10_4_VDEV_ATF_REQUEST_CMDID, + WMI_10_4_PEER_ATF_REQUEST_CMDID, + WMI_10_4_PDEV_GET_ANI_CCK_CONFIG_CMDID, + WMI_10_4_PDEV_GET_ANI_OFDM_CONFIG_CMDID, + WMI_10_4_PDEV_RESERVE_AST_ENTRY_CMDID, + WMI_10_4_PDEV_GET_NFCAL_POWER_CMDID, + WMI_10_4_PDEV_GET_TPC_CMDID, + WMI_10_4_PDEV_GET_AST_INFO_CMDID, + WMI_10_4_VDEV_SET_DSCP_TID_MAP_CMDID, + WMI_10_4_PDEV_GET_TEMPERATURE_CMDID, + WMI_10_4_PDEV_GET_INFO_CMDID, + WMI_10_4_VDEV_GET_INFO_CMDID, + WMI_10_4_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID, + WMI_10_4_MU_CAL_START_CMDID, + WMI_10_4_SET_CCA_PARAMS_CMDID, + WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, + WMI_10_4_PDEV_UTF_CMDID = WMI_10_4_END_CMDID - 1, +}; + +enum wmi_10_4_event_id { + WMI_10_4_SERVICE_READY_EVENTID = 0x8000, + WMI_10_4_READY_EVENTID, + WMI_10_4_DEBUG_MESG_EVENTID, + WMI_10_4_START_EVENTID = 0x9000, + WMI_10_4_END_EVENTID = 0x9FFF, + WMI_10_4_SCAN_EVENTID = WMI_10_4_START_EVENTID, + WMI_10_4_ECHO_EVENTID, + WMI_10_4_UPDATE_STATS_EVENTID, + WMI_10_4_INST_RSSI_STATS_EVENTID, + WMI_10_4_VDEV_START_RESP_EVENTID, + WMI_10_4_VDEV_STANDBY_REQ_EVENTID, + WMI_10_4_VDEV_RESUME_REQ_EVENTID, + WMI_10_4_VDEV_STOPPED_EVENTID, + WMI_10_4_PEER_STA_KICKOUT_EVENTID, + WMI_10_4_HOST_SWBA_EVENTID, + WMI_10_4_TBTTOFFSET_UPDATE_EVENTID, + WMI_10_4_MGMT_RX_EVENTID, + WMI_10_4_CHAN_INFO_EVENTID, + WMI_10_4_PHYERR_EVENTID, + WMI_10_4_ROAM_EVENTID, + WMI_10_4_PROFILE_MATCH, + WMI_10_4_DEBUG_PRINT_EVENTID, + WMI_10_4_PDEV_QVIT_EVENTID, + WMI_10_4_WLAN_PROFILE_DATA_EVENTID, + WMI_10_4_RTT_MEASUREMENT_REPORT_EVENTID, + WMI_10_4_TSF_MEASUREMENT_REPORT_EVENTID, + WMI_10_4_RTT_ERROR_REPORT_EVENTID, + WMI_10_4_RTT_KEEPALIVE_EVENTID, + WMI_10_4_OEM_CAPABILITY_EVENTID, + WMI_10_4_OEM_MEASUREMENT_REPORT_EVENTID, + WMI_10_4_OEM_ERROR_REPORT_EVENTID, + WMI_10_4_NAN_EVENTID, + WMI_10_4_WOW_WAKEUP_HOST_EVENTID, + WMI_10_4_GTK_OFFLOAD_STATUS_EVENTID, + WMI_10_4_GTK_REKEY_FAIL_EVENTID, + WMI_10_4_DCS_INTERFERENCE_EVENTID, + WMI_10_4_PDEV_TPC_CONFIG_EVENTID, + WMI_10_4_CSA_HANDLING_EVENTID, + WMI_10_4_GPIO_INPUT_EVENTID, + WMI_10_4_PEER_RATECODE_LIST_EVENTID, + WMI_10_4_GENERIC_BUFFER_EVENTID, + WMI_10_4_MCAST_BUF_RELEASE_EVENTID, + WMI_10_4_MCAST_LIST_AGEOUT_EVENTID, + WMI_10_4_VDEV_GET_KEEPALIVE_EVENTID, + WMI_10_4_WDS_PEER_EVENTID, + WMI_10_4_PEER_STA_PS_STATECHG_EVENTID, + WMI_10_4_PDEV_FIPS_EVENTID, + WMI_10_4_TT_STATS_EVENTID, + WMI_10_4_PDEV_CHANNEL_HOPPING_EVENTID, + WMI_10_4_PDEV_ANI_CCK_LEVEL_EVENTID, + WMI_10_4_PDEV_ANI_OFDM_LEVEL_EVENTID, + WMI_10_4_PDEV_RESERVE_AST_ENTRY_EVENTID, + WMI_10_4_PDEV_NFCAL_POWER_EVENTID, + WMI_10_4_PDEV_TPC_EVENTID, + WMI_10_4_PDEV_GET_AST_INFO_EVENTID, + WMI_10_4_PDEV_TEMPERATURE_EVENTID, + WMI_10_4_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID, + WMI_10_4_PDEV_BSS_CHAN_INFO_EVENTID, + WMI_10_4_PDEV_UTF_EVENTID = WMI_10_4_END_EVENTID - 1, +}; + enum wmi_phy_mode { MODE_11A = 0, /* 11a Mode */ MODE_11G = 1, /* 11b/g Mode */ -- cgit v1.3-6-gb490 From 772b4aeee51a851132abf799de8c07cfbe95ac00 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:12 +0530 Subject: ath10k: set 10.4 fw exclusive wmi cmd as unsupported for other fw versions In fact, explicit assigned to ZERO for unsupported wmi commands are not really needed. Global static variable will have ZERO by default. However, just for better readability setting all wmi cmds in non 10.4 firmware wmi mapping table as unsupported for wmi cmd which are exclusively available only in 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 32 ++++++ drivers/net/wireless/ath/ath10k/wmi.c | 158 ++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 8fdba3865c96..7e75dec5b4fb 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3151,6 +3151,38 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = { .tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID, .tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID, .adaptive_qcs_cmdid = WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 8dc937de98ab..a58ddb74ac3b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -148,6 +148,48 @@ static struct wmi_cmd_map wmi_cmd_map = { .gpio_config_cmdid = WMI_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, + .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, + .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.X WMI cmd track */ @@ -271,6 +313,48 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, + .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, + .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.2.4 WMI cmd track */ @@ -393,6 +477,48 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, + .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, + .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.4 WMI cmd track */ @@ -1032,6 +1158,38 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, }; void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, -- cgit v1.3-6-gb490 From 93841a15cce206450cdb31fe9b3f6b00342afe2b Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:13 +0530 Subject: ath10k: add 10.4 fw wmi vdev cmd ids Include 10.4 firmware wmi vdev cmd id and make up wmi vdev map table wmi_10_4_vdev_param_map and also update non 10.4 firmware vdev cmd map table with newly added vdev cmd id specifically for 10.4 firmware as unsupported. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 16 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 124 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 85 ++++++++++++++++++++ 3 files changed, 225 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 7e75dec5b4fb..b2a8e327a551 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3294,6 +3294,22 @@ static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { .tx_encap_type = WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_TLV_VDEV_PARAM_UNSUPPORTED, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, }; static const struct wmi_ops wmi_tlv_ops = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a58ddb74ac3b..087dea85ef7c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -761,6 +761,22 @@ static struct wmi_vdev_param_map wmi_vdev_param_map = { .tx_encap_type = WMI_VDEV_PARAM_TX_ENCAP_TYPE, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_VDEV_PARAM_UNSUPPORTED, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, }; /* 10.X WMI VDEV param map */ @@ -820,6 +836,22 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = { .tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, }; static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { @@ -878,6 +910,97 @@ static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { .tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, +}; + +static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = { + .rts_threshold = WMI_10_4_VDEV_PARAM_RTS_THRESHOLD, + .fragmentation_threshold = WMI_10_4_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + .beacon_interval = WMI_10_4_VDEV_PARAM_BEACON_INTERVAL, + .listen_interval = WMI_10_4_VDEV_PARAM_LISTEN_INTERVAL, + .multicast_rate = WMI_10_4_VDEV_PARAM_MULTICAST_RATE, + .mgmt_tx_rate = WMI_10_4_VDEV_PARAM_MGMT_TX_RATE, + .slot_time = WMI_10_4_VDEV_PARAM_SLOT_TIME, + .preamble = WMI_10_4_VDEV_PARAM_PREAMBLE, + .swba_time = WMI_10_4_VDEV_PARAM_SWBA_TIME, + .wmi_vdev_stats_update_period = WMI_10_4_VDEV_STATS_UPDATE_PERIOD, + .wmi_vdev_pwrsave_ageout_time = WMI_10_4_VDEV_PWRSAVE_AGEOUT_TIME, + .wmi_vdev_host_swba_interval = WMI_10_4_VDEV_HOST_SWBA_INTERVAL, + .dtim_period = WMI_10_4_VDEV_PARAM_DTIM_PERIOD, + .wmi_vdev_oc_scheduler_air_time_limit = + WMI_10_4_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + .wds = WMI_10_4_VDEV_PARAM_WDS, + .atim_window = WMI_10_4_VDEV_PARAM_ATIM_WINDOW, + .bmiss_count_max = WMI_10_4_VDEV_PARAM_BMISS_COUNT_MAX, + .bmiss_first_bcnt = WMI_10_4_VDEV_PARAM_BMISS_FIRST_BCNT, + .bmiss_final_bcnt = WMI_10_4_VDEV_PARAM_BMISS_FINAL_BCNT, + .feature_wmm = WMI_10_4_VDEV_PARAM_FEATURE_WMM, + .chwidth = WMI_10_4_VDEV_PARAM_CHWIDTH, + .chextoffset = WMI_10_4_VDEV_PARAM_CHEXTOFFSET, + .disable_htprotection = WMI_10_4_VDEV_PARAM_DISABLE_HTPROTECTION, + .sta_quickkickout = WMI_10_4_VDEV_PARAM_STA_QUICKKICKOUT, + .mgmt_rate = WMI_10_4_VDEV_PARAM_MGMT_RATE, + .protection_mode = WMI_10_4_VDEV_PARAM_PROTECTION_MODE, + .fixed_rate = WMI_10_4_VDEV_PARAM_FIXED_RATE, + .sgi = WMI_10_4_VDEV_PARAM_SGI, + .ldpc = WMI_10_4_VDEV_PARAM_LDPC, + .tx_stbc = WMI_10_4_VDEV_PARAM_TX_STBC, + .rx_stbc = WMI_10_4_VDEV_PARAM_RX_STBC, + .intra_bss_fwd = WMI_10_4_VDEV_PARAM_INTRA_BSS_FWD, + .def_keyid = WMI_10_4_VDEV_PARAM_DEF_KEYID, + .nss = WMI_10_4_VDEV_PARAM_NSS, + .bcast_data_rate = WMI_10_4_VDEV_PARAM_BCAST_DATA_RATE, + .mcast_data_rate = WMI_10_4_VDEV_PARAM_MCAST_DATA_RATE, + .mcast_indicate = WMI_10_4_VDEV_PARAM_MCAST_INDICATE, + .dhcp_indicate = WMI_10_4_VDEV_PARAM_DHCP_INDICATE, + .unknown_dest_indicate = WMI_10_4_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + .ap_keepalive_min_idle_inactive_time_secs = + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_idle_inactive_time_secs = + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_unresponsive_time_secs = + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + .ap_enable_nawds = WMI_10_4_VDEV_PARAM_AP_ENABLE_NAWDS, + .mcast2ucast_set = WMI_10_4_VDEV_PARAM_MCAST2UCAST_SET, + .enable_rtscts = WMI_10_4_VDEV_PARAM_ENABLE_RTSCTS, + .txbf = WMI_10_4_VDEV_PARAM_TXBF, + .packet_powersave = WMI_10_4_VDEV_PARAM_PACKET_POWERSAVE, + .drop_unencry = WMI_10_4_VDEV_PARAM_DROP_UNENCRY, + .tx_encap_type = WMI_10_4_VDEV_PARAM_TX_ENCAP_TYPE, + .ap_detect_out_of_sync_sleeping_sta_time_secs = + WMI_10_4_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + .rc_num_retries = WMI_10_4_VDEV_PARAM_RC_NUM_RETRIES, + .cabq_maxdur = WMI_10_4_VDEV_PARAM_CABQ_MAXDUR, + .mfptest_set = WMI_10_4_VDEV_PARAM_MFPTEST_SET, + .rts_fixed_rate = WMI_10_4_VDEV_PARAM_RTS_FIXED_RATE, + .vht_sgimask = WMI_10_4_VDEV_PARAM_VHT_SGIMASK, + .vht80_ratemask = WMI_10_4_VDEV_PARAM_VHT80_RATEMASK, + .early_rx_adjust_enable = WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + .early_rx_tgt_bmiss_num = WMI_10_4_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + .early_rx_bmiss_sample_cycle = + WMI_10_4_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + .early_rx_slop_step = WMI_10_4_VDEV_PARAM_EARLY_RX_SLOP_STEP, + .early_rx_init_slop = WMI_10_4_VDEV_PARAM_EARLY_RX_INIT_SLOP, + .early_rx_adjust_pause = WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + .proxy_sta = WMI_10_4_VDEV_PARAM_PROXY_STA, + .meru_vc = WMI_10_4_VDEV_PARAM_MERU_VC, + .rx_decap_type = WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE, + .bw_nss_ratemask = WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK, }; static struct wmi_pdev_param_map wmi_pdev_param_map = { @@ -5763,6 +5886,7 @@ int ath10k_wmi_attach(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_10_4: ar->wmi.ops = &wmi_10_4_ops; ar->wmi.cmd = &wmi_10_4_cmd_map; + ar->wmi.vdev_param = &wmi_10_4_vdev_param_map; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index c3a05a9a05ae..ecc7288ff119 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3904,6 +3904,22 @@ struct wmi_vdev_param_map { u32 drop_unencry; u32 tx_encap_type; u32 ap_detect_out_of_sync_sleeping_sta_time_secs; + u32 rc_num_retries; + u32 cabq_maxdur; + u32 mfptest_set; + u32 rts_fixed_rate; + u32 vht_sgimask; + u32 vht80_ratemask; + u32 early_rx_adjust_enable; + u32 early_rx_tgt_bmiss_num; + u32 early_rx_bmiss_sample_cycle; + u32 early_rx_slop_step; + u32 early_rx_init_slop; + u32 early_rx_adjust_pause; + u32 proxy_sta; + u32 meru_vc; + u32 rx_decap_type; + u32 bw_nss_ratemask; }; #define WMI_VDEV_PARAM_UNSUPPORTED 0 @@ -4162,6 +4178,75 @@ enum wmi_10x_vdev_param { WMI_10X_VDEV_PARAM_VHT80_RATEMASK, }; +enum wmi_10_4_vdev_param { + WMI_10_4_VDEV_PARAM_RTS_THRESHOLD = 0x1, + WMI_10_4_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + WMI_10_4_VDEV_PARAM_BEACON_INTERVAL, + WMI_10_4_VDEV_PARAM_LISTEN_INTERVAL, + WMI_10_4_VDEV_PARAM_MULTICAST_RATE, + WMI_10_4_VDEV_PARAM_MGMT_TX_RATE, + WMI_10_4_VDEV_PARAM_SLOT_TIME, + WMI_10_4_VDEV_PARAM_PREAMBLE, + WMI_10_4_VDEV_PARAM_SWBA_TIME, + WMI_10_4_VDEV_STATS_UPDATE_PERIOD, + WMI_10_4_VDEV_PWRSAVE_AGEOUT_TIME, + WMI_10_4_VDEV_HOST_SWBA_INTERVAL, + WMI_10_4_VDEV_PARAM_DTIM_PERIOD, + WMI_10_4_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + WMI_10_4_VDEV_PARAM_WDS, + WMI_10_4_VDEV_PARAM_ATIM_WINDOW, + WMI_10_4_VDEV_PARAM_BMISS_COUNT_MAX, + WMI_10_4_VDEV_PARAM_BMISS_FIRST_BCNT, + WMI_10_4_VDEV_PARAM_BMISS_FINAL_BCNT, + WMI_10_4_VDEV_PARAM_FEATURE_WMM, + WMI_10_4_VDEV_PARAM_CHWIDTH, + WMI_10_4_VDEV_PARAM_CHEXTOFFSET, + WMI_10_4_VDEV_PARAM_DISABLE_HTPROTECTION, + WMI_10_4_VDEV_PARAM_STA_QUICKKICKOUT, + WMI_10_4_VDEV_PARAM_MGMT_RATE, + WMI_10_4_VDEV_PARAM_PROTECTION_MODE, + WMI_10_4_VDEV_PARAM_FIXED_RATE, + WMI_10_4_VDEV_PARAM_SGI, + WMI_10_4_VDEV_PARAM_LDPC, + WMI_10_4_VDEV_PARAM_TX_STBC, + WMI_10_4_VDEV_PARAM_RX_STBC, + WMI_10_4_VDEV_PARAM_INTRA_BSS_FWD, + WMI_10_4_VDEV_PARAM_DEF_KEYID, + WMI_10_4_VDEV_PARAM_NSS, + WMI_10_4_VDEV_PARAM_BCAST_DATA_RATE, + WMI_10_4_VDEV_PARAM_MCAST_DATA_RATE, + WMI_10_4_VDEV_PARAM_MCAST_INDICATE, + WMI_10_4_VDEV_PARAM_DHCP_INDICATE, + WMI_10_4_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + WMI_10_4_VDEV_PARAM_AP_ENABLE_NAWDS, + WMI_10_4_VDEV_PARAM_MCAST2UCAST_SET, + WMI_10_4_VDEV_PARAM_ENABLE_RTSCTS, + WMI_10_4_VDEV_PARAM_RC_NUM_RETRIES, + WMI_10_4_VDEV_PARAM_TXBF, + WMI_10_4_VDEV_PARAM_PACKET_POWERSAVE, + WMI_10_4_VDEV_PARAM_DROP_UNENCRY, + WMI_10_4_VDEV_PARAM_TX_ENCAP_TYPE, + WMI_10_4_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + WMI_10_4_VDEV_PARAM_CABQ_MAXDUR, + WMI_10_4_VDEV_PARAM_MFPTEST_SET, + WMI_10_4_VDEV_PARAM_RTS_FIXED_RATE, + WMI_10_4_VDEV_PARAM_VHT_SGIMASK, + WMI_10_4_VDEV_PARAM_VHT80_RATEMASK, + WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + WMI_10_4_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + WMI_10_4_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + WMI_10_4_VDEV_PARAM_EARLY_RX_SLOP_STEP, + WMI_10_4_VDEV_PARAM_EARLY_RX_INIT_SLOP, + WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + WMI_10_4_VDEV_PARAM_PROXY_STA, + WMI_10_4_VDEV_PARAM_MERU_VC, + WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE, + WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK, +}; + #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0) #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1) #define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2) -- cgit v1.3-6-gb490 From d86561ff677b312424ba53389be80b507941973b Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:14 +0530 Subject: ath10k: add 10.4 fw wmi pdev cmd ids Include 10.4 firmware wmi pdev cmd id and prepare wmi vdev map table wmi_10_4_pdev_param_map and update non 10.4 firmware pdev cmd map table with newly added vdev cmd id specifically for 10.4 firmware as unsupported. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 42 ++++++ drivers/net/wireless/ath/ath10k/wmi.c | 228 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 136 ++++++++++++++++++ 3 files changed, 406 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index b2a8e327a551..620b37b59784 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3236,6 +3236,48 @@ static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { .burst_dur = WMI_TLV_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_TLV_PDEV_PARAM_BURST_ENABLE, .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 087dea85ef7c..3f29886dc880 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1053,6 +1053,48 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = { .burst_dur = WMI_PDEV_PARAM_UNSUPPORTED, .burst_enable = WMI_PDEV_PARAM_UNSUPPORTED, .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { @@ -1106,6 +1148,48 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { @@ -1159,6 +1243,48 @@ static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; /* firmware 10.2 specific mappings */ @@ -1315,6 +1441,107 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, }; +static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = { + .tx_chain_mask = WMI_10_4_PDEV_PARAM_TX_CHAIN_MASK, + .rx_chain_mask = WMI_10_4_PDEV_PARAM_RX_CHAIN_MASK, + .txpower_limit2g = WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT2G, + .txpower_limit5g = WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT5G, + .txpower_scale = WMI_10_4_PDEV_PARAM_TXPOWER_SCALE, + .beacon_gen_mode = WMI_10_4_PDEV_PARAM_BEACON_GEN_MODE, + .beacon_tx_mode = WMI_10_4_PDEV_PARAM_BEACON_TX_MODE, + .resmgr_offchan_mode = WMI_10_4_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + .protection_mode = WMI_10_4_PDEV_PARAM_PROTECTION_MODE, + .dynamic_bw = WMI_10_4_PDEV_PARAM_DYNAMIC_BW, + .non_agg_sw_retry_th = WMI_10_4_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + .agg_sw_retry_th = WMI_10_4_PDEV_PARAM_AGG_SW_RETRY_TH, + .sta_kickout_th = WMI_10_4_PDEV_PARAM_STA_KICKOUT_TH, + .ac_aggrsize_scaling = WMI_10_4_PDEV_PARAM_AC_AGGRSIZE_SCALING, + .ltr_enable = WMI_10_4_PDEV_PARAM_LTR_ENABLE, + .ltr_ac_latency_be = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BE, + .ltr_ac_latency_bk = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BK, + .ltr_ac_latency_vi = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VI, + .ltr_ac_latency_vo = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VO, + .ltr_ac_latency_timeout = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + .ltr_sleep_override = WMI_10_4_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + .ltr_rx_override = WMI_10_4_PDEV_PARAM_LTR_RX_OVERRIDE, + .ltr_tx_activity_timeout = WMI_10_4_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + .l1ss_enable = WMI_10_4_PDEV_PARAM_L1SS_ENABLE, + .dsleep_enable = WMI_10_4_PDEV_PARAM_DSLEEP_ENABLE, + .pcielp_txbuf_flush = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + .pcielp_txbuf_watermark = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, + .pcielp_txbuf_tmo_en = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + .pcielp_txbuf_tmo_value = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + .pdev_stats_update_period = + WMI_10_4_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + .vdev_stats_update_period = + WMI_10_4_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + .peer_stats_update_period = + WMI_10_4_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + .bcnflt_stats_update_period = + WMI_10_4_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + .pmf_qos = WMI_10_4_PDEV_PARAM_PMF_QOS, + .arp_ac_override = WMI_10_4_PDEV_PARAM_ARP_AC_OVERRIDE, + .dcs = WMI_10_4_PDEV_PARAM_DCS, + .ani_enable = WMI_10_4_PDEV_PARAM_ANI_ENABLE, + .ani_poll_period = WMI_10_4_PDEV_PARAM_ANI_POLL_PERIOD, + .ani_listen_period = WMI_10_4_PDEV_PARAM_ANI_LISTEN_PERIOD, + .ani_ofdm_level = WMI_10_4_PDEV_PARAM_ANI_OFDM_LEVEL, + .ani_cck_level = WMI_10_4_PDEV_PARAM_ANI_CCK_LEVEL, + .dyntxchain = WMI_10_4_PDEV_PARAM_DYNTXCHAIN, + .proxy_sta = WMI_10_4_PDEV_PARAM_PROXY_STA, + .idle_ps_config = WMI_10_4_PDEV_PARAM_IDLE_PS_CONFIG, + .power_gating_sleep = WMI_10_4_PDEV_PARAM_POWER_GATING_SLEEP, + .fast_channel_reset = WMI_10_4_PDEV_PARAM_FAST_CHANNEL_RESET, + .burst_dur = WMI_10_4_PDEV_PARAM_BURST_DUR, + .burst_enable = WMI_10_4_PDEV_PARAM_BURST_ENABLE, + .cal_period = WMI_10_4_PDEV_PARAM_CAL_PERIOD, + .aggr_burst = WMI_10_4_PDEV_PARAM_AGGR_BURST, + .rx_decap_mode = WMI_10_4_PDEV_PARAM_RX_DECAP_MODE, + .smart_antenna_default_antenna = + WMI_10_4_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA, + .igmpmld_override = WMI_10_4_PDEV_PARAM_IGMPMLD_OVERRIDE, + .igmpmld_tid = WMI_10_4_PDEV_PARAM_IGMPMLD_TID, + .antenna_gain = WMI_10_4_PDEV_PARAM_ANTENNA_GAIN, + .rx_filter = WMI_10_4_PDEV_PARAM_RX_FILTER, + .set_mcast_to_ucast_tid = WMI_10_4_PDEV_SET_MCAST_TO_UCAST_TID, + .proxy_sta_mode = WMI_10_4_PDEV_PARAM_PROXY_STA_MODE, + .set_mcast2ucast_mode = WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_MODE, + .set_mcast2ucast_buffer = WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, + .remove_mcast2ucast_buffer = + WMI_10_4_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, + .peer_sta_ps_statechg_enable = + WMI_10_4_PDEV_PEER_STA_PS_STATECHG_ENABLE, + .igmpmld_ac_override = WMI_10_4_PDEV_PARAM_IGMPMLD_AC_OVERRIDE, + .block_interbss = WMI_10_4_PDEV_PARAM_BLOCK_INTERBSS, + .set_disable_reset_cmdid = WMI_10_4_PDEV_PARAM_SET_DISABLE_RESET_CMDID, + .set_msdu_ttl_cmdid = WMI_10_4_PDEV_PARAM_SET_MSDU_TTL_CMDID, + .set_ppdu_duration_cmdid = WMI_10_4_PDEV_PARAM_SET_PPDU_DURATION_CMDID, + .txbf_sound_period_cmdid = WMI_10_4_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID, + .set_promisc_mode_cmdid = WMI_10_4_PDEV_PARAM_SET_PROMISC_MODE_CMDID, + .set_burst_mode_cmdid = WMI_10_4_PDEV_PARAM_SET_BURST_MODE_CMDID, + .en_stats = WMI_10_4_PDEV_PARAM_EN_STATS, + .mu_group_policy = WMI_10_4_PDEV_PARAM_MU_GROUP_POLICY, + .noise_detection = WMI_10_4_PDEV_PARAM_NOISE_DETECTION, + .noise_threshold = WMI_10_4_PDEV_PARAM_NOISE_THRESHOLD, + .dpd_enable = WMI_10_4_PDEV_PARAM_DPD_ENABLE, + .set_mcast_bcast_echo = WMI_10_4_PDEV_PARAM_SET_MCAST_BCAST_ECHO, + .atf_strict_sch = WMI_10_4_PDEV_PARAM_ATF_STRICT_SCH, + .atf_sched_duration = WMI_10_4_PDEV_PARAM_ATF_SCHED_DURATION, + .ant_plzn = WMI_10_4_PDEV_PARAM_ANT_PLZN, + .mgmt_retry_limit = WMI_10_4_PDEV_PARAM_MGMT_RETRY_LIMIT, + .sensitivity_level = WMI_10_4_PDEV_PARAM_SENSITIVITY_LEVEL, + .signed_txpower_2g = WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_2G, + .signed_txpower_5g = WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_5G, + .enable_per_tid_amsdu = WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMSDU, + .enable_per_tid_ampdu = WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMPDU, + .cca_threshold = WMI_10_4_PDEV_PARAM_CCA_THRESHOLD, + .rts_fixed_rate = WMI_10_4_PDEV_PARAM_RTS_FIXED_RATE, + .pdev_reset = WMI_10_4_PDEV_PARAM_PDEV_RESET, + .wapi_mbssid_offset = WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET, + .arp_srcaddr = WMI_10_4_PDEV_PARAM_ARP_SRCADDR, + .arp_dstaddr = WMI_10_4_PDEV_PARAM_ARP_DSTADDR, +}; + void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, const struct wmi_channel_arg *arg) { @@ -5887,6 +6114,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.ops = &wmi_10_4_ops; ar->wmi.cmd = &wmi_10_4_cmd_map; ar->wmi.vdev_param = &wmi_10_4_vdev_param_map; + ar->wmi.pdev_param = &wmi_10_4_pdev_param_map; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index ecc7288ff119..f6ee163259f6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3011,6 +3011,48 @@ struct wmi_pdev_param_map { u32 burst_dur; u32 burst_enable; u32 cal_period; + u32 aggr_burst; + u32 rx_decap_mode; + u32 smart_antenna_default_antenna; + u32 igmpmld_override; + u32 igmpmld_tid; + u32 antenna_gain; + u32 rx_filter; + u32 set_mcast_to_ucast_tid; + u32 proxy_sta_mode; + u32 set_mcast2ucast_mode; + u32 set_mcast2ucast_buffer; + u32 remove_mcast2ucast_buffer; + u32 peer_sta_ps_statechg_enable; + u32 igmpmld_ac_override; + u32 block_interbss; + u32 set_disable_reset_cmdid; + u32 set_msdu_ttl_cmdid; + u32 set_ppdu_duration_cmdid; + u32 txbf_sound_period_cmdid; + u32 set_promisc_mode_cmdid; + u32 set_burst_mode_cmdid; + u32 en_stats; + u32 mu_group_policy; + u32 noise_detection; + u32 noise_threshold; + u32 dpd_enable; + u32 set_mcast_bcast_echo; + u32 atf_strict_sch; + u32 atf_sched_duration; + u32 ant_plzn; + u32 mgmt_retry_limit; + u32 sensitivity_level; + u32 signed_txpower_2g; + u32 signed_txpower_5g; + u32 enable_per_tid_amsdu; + u32 enable_per_tid_ampdu; + u32 cca_threshold; + u32 rts_fixed_rate; + u32 pdev_reset; + u32 wapi_mbssid_offset; + u32 arp_srcaddr; + u32 arp_dstaddr; }; #define WMI_PDEV_PARAM_UNSUPPORTED 0 @@ -3226,6 +3268,100 @@ enum wmi_10x_pdev_param { WMI_10X_PDEV_PARAM_CAL_PERIOD }; +enum wmi_10_4_pdev_param { + WMI_10_4_PDEV_PARAM_TX_CHAIN_MASK = 0x1, + WMI_10_4_PDEV_PARAM_RX_CHAIN_MASK, + WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT2G, + WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT5G, + WMI_10_4_PDEV_PARAM_TXPOWER_SCALE, + WMI_10_4_PDEV_PARAM_BEACON_GEN_MODE, + WMI_10_4_PDEV_PARAM_BEACON_TX_MODE, + WMI_10_4_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + WMI_10_4_PDEV_PARAM_PROTECTION_MODE, + WMI_10_4_PDEV_PARAM_DYNAMIC_BW, + WMI_10_4_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + WMI_10_4_PDEV_PARAM_AGG_SW_RETRY_TH, + WMI_10_4_PDEV_PARAM_STA_KICKOUT_TH, + WMI_10_4_PDEV_PARAM_AC_AGGRSIZE_SCALING, + WMI_10_4_PDEV_PARAM_LTR_ENABLE, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BE, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BK, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VI, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VO, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + WMI_10_4_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + WMI_10_4_PDEV_PARAM_LTR_RX_OVERRIDE, + WMI_10_4_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + WMI_10_4_PDEV_PARAM_L1SS_ENABLE, + WMI_10_4_PDEV_PARAM_DSLEEP_ENABLE, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + WMI_10_4_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_PMF_QOS, + WMI_10_4_PDEV_PARAM_ARP_AC_OVERRIDE, + WMI_10_4_PDEV_PARAM_DCS, + WMI_10_4_PDEV_PARAM_ANI_ENABLE, + WMI_10_4_PDEV_PARAM_ANI_POLL_PERIOD, + WMI_10_4_PDEV_PARAM_ANI_LISTEN_PERIOD, + WMI_10_4_PDEV_PARAM_ANI_OFDM_LEVEL, + WMI_10_4_PDEV_PARAM_ANI_CCK_LEVEL, + WMI_10_4_PDEV_PARAM_DYNTXCHAIN, + WMI_10_4_PDEV_PARAM_PROXY_STA, + WMI_10_4_PDEV_PARAM_IDLE_PS_CONFIG, + WMI_10_4_PDEV_PARAM_POWER_GATING_SLEEP, + WMI_10_4_PDEV_PARAM_AGGR_BURST, + WMI_10_4_PDEV_PARAM_RX_DECAP_MODE, + WMI_10_4_PDEV_PARAM_FAST_CHANNEL_RESET, + WMI_10_4_PDEV_PARAM_BURST_DUR, + WMI_10_4_PDEV_PARAM_BURST_ENABLE, + WMI_10_4_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA, + WMI_10_4_PDEV_PARAM_IGMPMLD_OVERRIDE, + WMI_10_4_PDEV_PARAM_IGMPMLD_TID, + WMI_10_4_PDEV_PARAM_ANTENNA_GAIN, + WMI_10_4_PDEV_PARAM_RX_FILTER, + WMI_10_4_PDEV_SET_MCAST_TO_UCAST_TID, + WMI_10_4_PDEV_PARAM_PROXY_STA_MODE, + WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_MODE, + WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, + WMI_10_4_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, + WMI_10_4_PDEV_PEER_STA_PS_STATECHG_ENABLE, + WMI_10_4_PDEV_PARAM_IGMPMLD_AC_OVERRIDE, + WMI_10_4_PDEV_PARAM_BLOCK_INTERBSS, + WMI_10_4_PDEV_PARAM_SET_DISABLE_RESET_CMDID, + WMI_10_4_PDEV_PARAM_SET_MSDU_TTL_CMDID, + WMI_10_4_PDEV_PARAM_SET_PPDU_DURATION_CMDID, + WMI_10_4_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID, + WMI_10_4_PDEV_PARAM_SET_PROMISC_MODE_CMDID, + WMI_10_4_PDEV_PARAM_SET_BURST_MODE_CMDID, + WMI_10_4_PDEV_PARAM_EN_STATS, + WMI_10_4_PDEV_PARAM_MU_GROUP_POLICY, + WMI_10_4_PDEV_PARAM_NOISE_DETECTION, + WMI_10_4_PDEV_PARAM_NOISE_THRESHOLD, + WMI_10_4_PDEV_PARAM_DPD_ENABLE, + WMI_10_4_PDEV_PARAM_SET_MCAST_BCAST_ECHO, + WMI_10_4_PDEV_PARAM_ATF_STRICT_SCH, + WMI_10_4_PDEV_PARAM_ATF_SCHED_DURATION, + WMI_10_4_PDEV_PARAM_ANT_PLZN, + WMI_10_4_PDEV_PARAM_MGMT_RETRY_LIMIT, + WMI_10_4_PDEV_PARAM_SENSITIVITY_LEVEL, + WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_2G, + WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_5G, + WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMSDU, + WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMPDU, + WMI_10_4_PDEV_PARAM_CCA_THRESHOLD, + WMI_10_4_PDEV_PARAM_RTS_FIXED_RATE, + WMI_10_4_PDEV_PARAM_CAL_PERIOD, + WMI_10_4_PDEV_PARAM_PDEV_RESET, + WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET, + WMI_10_4_PDEV_PARAM_ARP_SRCADDR, + WMI_10_4_PDEV_PARAM_ARP_DSTADDR, +}; + struct wmi_pdev_set_param_cmd { __le32 param_id; __le32 param_value; -- cgit v1.3-6-gb490 From d1e52a8ed2bf34ed5b839c190209deb80828d189 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:15 +0530 Subject: ath10k: fill 10.4 fw wmi init cmd default values Define 10.4 wmi init command structure and introduce new function ath10k_wmi_10_4_op_gen_init() to fill default values for each field which goes as part of wmi init cmd to 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 7 ++ drivers/net/wireless/ath/ath10k/core.h | 2 + drivers/net/wireless/ath/ath10k/hw.h | 54 ++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 83 +++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 220 +++++++++++++++++++++++++++++++++ 5 files changed, 366 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 5e8d8af5d0d0..020ac9f10168 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1116,6 +1116,13 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) WMI_STAT_PEER; break; case ATH10K_FW_WMI_OP_VERSION_10_4: + ar->max_num_peers = TARGET_10_4_NUM_PEERS; + ar->max_num_stations = TARGET_10_4_NUM_STATIONS; + ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS; + ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; + ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; + ar->fw_stats_req_mask = WMI_STAT_PEER; + break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index afd21d5b25ae..58b02ae81706 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -684,6 +684,8 @@ struct ath10k { int max_num_stations; int max_num_vdevs; int max_num_tdls_vdevs; + int num_active_peers; + int num_tids; struct work_struct offchan_tx_work; struct sk_buff_head offchan_tx_queue; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index b0c89b48092d..52fc0249378b 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -354,6 +354,60 @@ enum ath10k_hw_rate_cck { #define NUM_TARGET_CE_CONFIG_WLAN ar->hw_values->num_target_ce_config_wlan +/* Target specific defines for 10.4 firmware */ +#define TARGET_10_4_NUM_VDEVS 16 +#define TARGET_10_4_NUM_STATIONS 32 +#define TARGET_10_4_NUM_PEERS ((TARGET_10_4_NUM_STATIONS) + \ + (TARGET_10_4_NUM_VDEVS)) +#define TARGET_10_4_ACTIVE_PEERS 0 +#define TARGET_10_4_NUM_OFFLOAD_PEERS 0 +#define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0 +#define TARGET_10_4_NUM_PEER_KEYS 2 +#define TARGET_10_4_TGT_NUM_TIDS ((TARGET_10_4_NUM_PEERS) * 2) +#define TARGET_10_4_AST_SKID_LIMIT 32 +#define TARGET_10_4_TX_CHAIN_MASK (BIT(0) | BIT(1) | \ + BIT(2) | BIT(3)) +#define TARGET_10_4_RX_CHAIN_MASK (BIT(0) | BIT(1) | \ + BIT(2) | BIT(3)) + +/* 100 ms for video, best-effort, and background */ +#define TARGET_10_4_RX_TIMEOUT_LO_PRI 100 + +/* 40 ms for voice */ +#define TARGET_10_4_RX_TIMEOUT_HI_PRI 40 + +#define TARGET_10_4_RX_DECAP_MODE ATH10K_HW_TXRX_NATIVE_WIFI +#define TARGET_10_4_SCAN_MAX_REQS 4 +#define TARGET_10_4_BMISS_OFFLOAD_MAX_VDEV 3 +#define TARGET_10_4_ROAM_OFFLOAD_MAX_VDEV 3 +#define TARGET_10_4_ROAM_OFFLOAD_MAX_PROFILES 8 + +/* Note: mcast to ucast is disabled by default */ +#define TARGET_10_4_NUM_MCAST_GROUPS 0 +#define TARGET_10_4_NUM_MCAST_TABLE_ELEMS 0 +#define TARGET_10_4_MCAST2UCAST_MODE 0 + +#define TARGET_10_4_TX_DBG_LOG_SIZE 1024 +#define TARGET_10_4_NUM_WDS_ENTRIES 32 +#define TARGET_10_4_DMA_BURST_SIZE 1 +#define TARGET_10_4_MAC_AGGR_DELIM 0 +#define TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1 +#define TARGET_10_4_VOW_CONFIG 0 +#define TARGET_10_4_GTK_OFFLOAD_MAX_VDEV 3 +#define TARGET_10_4_NUM_MSDU_DESC (1024 + 400) +#define TARGET_10_4_11AC_TX_MAX_FRAGS 2 +#define TARGET_10_4_MAX_PEER_EXT_STATS 16 +#define TARGET_10_4_SMART_ANT_CAP 0 +#define TARGET_10_4_BK_MIN_FREE 0 +#define TARGET_10_4_BE_MIN_FREE 0 +#define TARGET_10_4_VI_MIN_FREE 0 +#define TARGET_10_4_VO_MIN_FREE 0 +#define TARGET_10_4_RX_BATCH_MODE 1 +#define TARGET_10_4_THERMAL_THROTTLING_CONFIG 0 +#define TARGET_10_4_ATF_CONFIG 0 +#define TARGET_10_4_IPHDR_PAD_CONFIG 1 +#define TARGET_10_4_QWRAP_CONFIG 0 + /* Number of Copy Engines supported */ #define CE_COUNT ar->hw_values->ce_count diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 3f29886dc880..6c51b20dc8c5 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4641,6 +4641,88 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) return buf; } +static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) +{ + struct wmi_init_cmd_10_4 *cmd; + struct sk_buff *buf; + struct wmi_resource_config_10_4 config = {}; + u32 len; + + config.num_vdevs = __cpu_to_le32(ar->max_num_vdevs); + config.num_peers = __cpu_to_le32(ar->max_num_peers); + config.num_active_peers = __cpu_to_le32(ar->num_active_peers); + config.num_tids = __cpu_to_le32(ar->num_tids); + + config.num_offload_peers = __cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_PEERS); + config.num_offload_reorder_buffs = + __cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS); + config.num_peer_keys = __cpu_to_le32(TARGET_10_4_NUM_PEER_KEYS); + config.ast_skid_limit = __cpu_to_le32(TARGET_10_4_AST_SKID_LIMIT); + config.tx_chain_mask = __cpu_to_le32(TARGET_10_4_TX_CHAIN_MASK); + config.rx_chain_mask = __cpu_to_le32(TARGET_10_4_RX_CHAIN_MASK); + + config.rx_timeout_pri[0] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri[1] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri[2] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri[3] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_HI_PRI); + + config.rx_decap_mode = __cpu_to_le32(TARGET_10_4_RX_DECAP_MODE); + config.scan_max_pending_req = __cpu_to_le32(TARGET_10_4_SCAN_MAX_REQS); + config.bmiss_offload_max_vdev = + __cpu_to_le32(TARGET_10_4_BMISS_OFFLOAD_MAX_VDEV); + config.roam_offload_max_vdev = + __cpu_to_le32(TARGET_10_4_ROAM_OFFLOAD_MAX_VDEV); + config.roam_offload_max_ap_profiles = + __cpu_to_le32(TARGET_10_4_ROAM_OFFLOAD_MAX_PROFILES); + config.num_mcast_groups = __cpu_to_le32(TARGET_10_4_NUM_MCAST_GROUPS); + config.num_mcast_table_elems = + __cpu_to_le32(TARGET_10_4_NUM_MCAST_TABLE_ELEMS); + + config.mcast2ucast_mode = __cpu_to_le32(TARGET_10_4_MCAST2UCAST_MODE); + config.tx_dbg_log_size = __cpu_to_le32(TARGET_10_4_TX_DBG_LOG_SIZE); + config.num_wds_entries = __cpu_to_le32(TARGET_10_4_NUM_WDS_ENTRIES); + config.dma_burst_size = __cpu_to_le32(TARGET_10_4_DMA_BURST_SIZE); + config.mac_aggr_delim = __cpu_to_le32(TARGET_10_4_MAC_AGGR_DELIM); + + config.rx_skip_defrag_timeout_dup_detection_check = + __cpu_to_le32(TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK); + + config.vow_config = __cpu_to_le32(TARGET_10_4_VOW_CONFIG); + config.gtk_offload_max_vdev = + __cpu_to_le32(TARGET_10_4_GTK_OFFLOAD_MAX_VDEV); + config.num_msdu_desc = __cpu_to_le32(TARGET_10_4_NUM_MSDU_DESC); + config.max_frag_entries = __cpu_to_le32(TARGET_10_4_11AC_TX_MAX_FRAGS); + config.max_peer_ext_stats = + __cpu_to_le32(TARGET_10_4_MAX_PEER_EXT_STATS); + config.smart_ant_cap = __cpu_to_le32(TARGET_10_4_SMART_ANT_CAP); + + config.bk_minfree = __cpu_to_le32(TARGET_10_4_BK_MIN_FREE); + config.be_minfree = __cpu_to_le32(TARGET_10_4_BE_MIN_FREE); + config.vi_minfree = __cpu_to_le32(TARGET_10_4_VI_MIN_FREE); + config.vo_minfree = __cpu_to_le32(TARGET_10_4_VO_MIN_FREE); + + config.rx_batchmode = __cpu_to_le32(TARGET_10_4_RX_BATCH_MODE); + config.tt_support = + __cpu_to_le32(TARGET_10_4_THERMAL_THROTTLING_CONFIG); + config.atf_config = __cpu_to_le32(TARGET_10_4_ATF_CONFIG); + config.iphdr_pad_config = __cpu_to_le32(TARGET_10_4_IPHDR_PAD_CONFIG); + config.qwrap_config = __cpu_to_le32(TARGET_10_4_QWRAP_CONFIG); + + len = sizeof(*cmd) + + (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); + + buf = ath10k_wmi_alloc_skb(ar, len); + if (!buf) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_init_cmd_10_4 *)buf->data; + memcpy(&cmd->resource_config, &config, sizeof(config)); + ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.4\n"); + return buf; +} + int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) { if (arg->ie_len && !arg->ie) @@ -6105,6 +6187,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { static const struct wmi_ops wmi_10_4_ops = { .map_svc = wmi_10_4_svc_map, + .gen_init = ath10k_wmi_10_4_op_gen_init, }; int ath10k_wmi_attach(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index f6ee163259f6..dbb9f1c8c917 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2380,6 +2380,221 @@ struct wmi_resource_config_10_2 { #define NUM_UNITS_IS_NUM_VDEVS 0x1 #define NUM_UNITS_IS_NUM_PEERS 0x2 +struct wmi_resource_config_10_4 { + /* Number of virtual devices (VAPs) to support */ + __le32 num_vdevs; + + /* Number of peer nodes to support */ + __le32 num_peers; + + /* Number of active peer nodes to support */ + __le32 num_active_peers; + + /* In offload mode, target supports features like WOW, chatter and other + * protocol offloads. In order to support them some functionalities like + * reorder buffering, PN checking need to be done in target. + * This determines maximum number of peers supported by target in + * offload mode. + */ + __le32 num_offload_peers; + + /* Number of reorder buffers available for doing target based reorder + * Rx reorder buffering + */ + __le32 num_offload_reorder_buffs; + + /* Number of keys per peer */ + __le32 num_peer_keys; + + /* Total number of TX/RX data TIDs */ + __le32 num_tids; + + /* Max skid for resolving hash collisions. + * The address search table is sparse, so that if two MAC addresses + * result in the same hash value, the second of these conflicting + * entries can slide to the next index in the address search table, + * and use it, if it is unoccupied. This ast_skid_limit parameter + * specifies the upper bound on how many subsequent indices to search + * over to find an unoccupied space. + */ + __le32 ast_skid_limit; + + /* The nominal chain mask for transmit. + * The chain mask may be modified dynamically, e.g. to operate AP tx + * with a reduced number of chains if no clients are associated. + * This configuration parameter specifies the nominal chain-mask that + * should be used when not operating with a reduced set of tx chains. + */ + __le32 tx_chain_mask; + + /* The nominal chain mask for receive. + * The chain mask may be modified dynamically, e.g. for a client to use + * a reduced number of chains for receive if the traffic to the client + * is low enough that it doesn't require downlink MIMO or antenna + * diversity. This configuration parameter specifies the nominal + * chain-mask that should be used when not operating with a reduced + * set of rx chains. + */ + __le32 rx_chain_mask; + + /* What rx reorder timeout (ms) to use for the AC. + * Each WMM access class (voice, video, best-effort, background) will + * have its own timeout value to dictate how long to wait for missing + * rx MPDUs to arrive before flushing subsequent MPDUs that have already + * been received. This parameter specifies the timeout in milliseconds + * for each class. + */ + __le32 rx_timeout_pri[4]; + + /* What mode the rx should decap packets to. + * MAC can decap to RAW (no decap), native wifi or Ethernet types. + * This setting also determines the default TX behavior, however TX + * behavior can be modified on a per VAP basis during VAP init + */ + __le32 rx_decap_mode; + + __le32 scan_max_pending_req; + + __le32 bmiss_offload_max_vdev; + + __le32 roam_offload_max_vdev; + + __le32 roam_offload_max_ap_profiles; + + /* How many groups to use for mcast->ucast conversion. + * The target's WAL maintains a table to hold information regarding + * which peers belong to a given multicast group, so that if + * multicast->unicast conversion is enabled, the target can convert + * multicast tx frames to a series of unicast tx frames, to each peer + * within the multicast group. This num_mcast_groups configuration + * parameter tells the target how many multicast groups to provide + * storage for within its multicast group membership table. + */ + __le32 num_mcast_groups; + + /* Size to alloc for the mcast membership table. + * This num_mcast_table_elems configuration parameter tells the target + * how many peer elements it needs to provide storage for in its + * multicast group membership table. These multicast group membership + * table elements are shared by the multicast groups stored within + * the table. + */ + __le32 num_mcast_table_elems; + + /* Whether/how to do multicast->unicast conversion. + * This configuration parameter specifies whether the target should + * perform multicast --> unicast conversion on transmit, and if so, + * what to do if it finds no entries in its multicast group membership + * table for the multicast IP address in the tx frame. + * Configuration value: + * 0 -> Do not perform multicast to unicast conversion. + * 1 -> Convert multicast frames to unicast, if the IP multicast address + * from the tx frame is found in the multicast group membership + * table. If the IP multicast address is not found, drop the frame + * 2 -> Convert multicast frames to unicast, if the IP multicast address + * from the tx frame is found in the multicast group membership + * table. If the IP multicast address is not found, transmit the + * frame as multicast. + */ + __le32 mcast2ucast_mode; + + /* How much memory to allocate for a tx PPDU dbg log. + * This parameter controls how much memory the target will allocate to + * store a log of tx PPDU meta-information (how large the PPDU was, + * when it was sent, whether it was successful, etc.) + */ + __le32 tx_dbg_log_size; + + /* How many AST entries to be allocated for WDS */ + __le32 num_wds_entries; + + /* MAC DMA burst size. 0 -default, 1 -256B */ + __le32 dma_burst_size; + + /* Fixed delimiters to be inserted after every MPDU to account for + * interface latency to avoid underrun. + */ + __le32 mac_aggr_delim; + + /* Determine whether target is responsible for detecting duplicate + * non-aggregate MPDU and timing out stale fragments. A-MPDU reordering + * is always performed on the target. + * + * 0: target responsible for frag timeout and dup checking + * 1: host responsible for frag timeout and dup checking + */ + __le32 rx_skip_defrag_timeout_dup_detection_check; + + /* Configuration for VoW : No of Video nodes to be supported and max + * no of descriptors for each video link (node). + */ + __le32 vow_config; + + /* Maximum vdev that could use gtk offload */ + __le32 gtk_offload_max_vdev; + + /* Number of msdu descriptors target should use */ + __le32 num_msdu_desc; + + /* Max number of tx fragments per MSDU. + * This parameter controls the max number of tx fragments per MSDU. + * This will passed by target as part of the WMI_SERVICE_READY event + * and is overridden by the OS shim as required. + */ + __le32 max_frag_entries; + + /* Max number of extended peer stats. + * This parameter controls the max number of peers for which extended + * statistics are supported by target + */ + __le32 max_peer_ext_stats; + + /* Smart antenna capabilities information. + * 1 - Smart antenna is enabled + * 0 - Smart antenna is disabled + * In future this can contain smart antenna specific capabilities. + */ + __le32 smart_ant_cap; + + /* User can configure the buffers allocated for each AC (BE, BK, VI, VO) + * during init. + */ + __le32 bk_minfree; + __le32 be_minfree; + __le32 vi_minfree; + __le32 vo_minfree; + + /* Rx batch mode capability. + * 1 - Rx batch mode enabled + * 0 - Rx batch mode disabled + */ + __le32 rx_batchmode; + + /* Thermal throttling capability. + * 1 - Capable of thermal throttling + * 0 - Not capable of thermal throttling + */ + __le32 tt_support; + + /* ATF configuration. + * 1 - Enable ATF + * 0 - Disable ATF + */ + __le32 atf_config; + + /* Configure padding to manage IP header un-alignment + * 1 - Enable padding + * 0 - Disable padding + */ + __le32 iphdr_pad_config; + + /* qwrap configuration + * 1 - This is qwrap configuration + * 0 - This is not qwrap + */ + __le32 qwrap_config; +} __packed; + /* strucutre describing host memory chunk. */ struct host_memory_chunk { /* id of the request that is passed up in service ready */ @@ -2412,6 +2627,11 @@ struct wmi_init_cmd_10_2 { struct wmi_host_mem_chunks mem_chunks; } __packed; +struct wmi_init_cmd_10_4 { + struct wmi_resource_config_10_4 resource_config; + struct wmi_host_mem_chunks mem_chunks; +} __packed; + struct wmi_chan_list_entry { __le16 freq; u8 phy_mode; /* valid for 10.2 only */ -- cgit v1.3-6-gb490 From 1c0929614ac429a32509307e790e813325562dc1 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:16 +0530 Subject: ath10k: handle 10.4 fw wmi mgmt rx event 10.4 firmware wmi mgmt rx event format differs from non 10.4 firmware and changing existing wmi mgmt rx event parsing function ath10k_wmi_op_pull_mgmt_rx_ev() for 10.4 would add more complex. This patch adds new function to receive any wmi rx event from 10.4 firmware and also introduce new function to parse wmi mgmt rx event. In addition, fw main branch service rdy event parsing function is linked in wmi ops table. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 64 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 15 ++++++++ 2 files changed, 79 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6c51b20dc8c5..9502032f46dc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2124,6 +2124,40 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } +static int ath10k_wmi_10_4_op_pull_mgmt_rx_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg) +{ + struct wmi_10_4_mgmt_rx_event *ev; + struct wmi_10_4_mgmt_rx_hdr *ev_hdr; + size_t pull_len; + u32 msdu_len; + + ev = (struct wmi_10_4_mgmt_rx_event *)skb->data; + ev_hdr = &ev->hdr; + pull_len = sizeof(*ev); + + if (skb->len < pull_len) + return -EPROTO; + + skb_pull(skb, pull_len); + arg->channel = ev_hdr->channel; + arg->buf_len = ev_hdr->buf_len; + arg->status = ev_hdr->status; + arg->snr = ev_hdr->snr; + arg->phy_mode = ev_hdr->phy_mode; + arg->rate = ev_hdr->rate; + + msdu_len = __le32_to_cpu(arg->buf_len); + if (skb->len < msdu_len) + return -EPROTO; + + /* Make sure bytes added for padding are removed. */ + skb_trim(skb, msdu_len); + + return 0; +} + int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_mgmt_rx_ev_arg arg = {}; @@ -4267,6 +4301,33 @@ out: dev_kfree_skb(skb); } +static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_cmd_hdr *cmd_hdr; + enum wmi_10_4_event_id id; + + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; + id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); + + if (!skb_pull(skb, sizeof(struct wmi_cmd_hdr))) + goto out; + + trace_ath10k_wmi_event(ar, id, skb->data, skb->len); + + switch (id) { + case WMI_10_4_MGMT_RX_EVENTID: + ath10k_wmi_event_mgmt_rx(ar, skb); + /* mgmt_rx() owns the skb now! */ + return; + default: + ath10k_warn(ar, "Unknown eventid: %d\n", id); + break; + } + +out: + dev_kfree_skb(skb); +} + static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) { int ret; @@ -6186,7 +6247,10 @@ static const struct wmi_ops wmi_10_2_4_ops = { }; static const struct wmi_ops wmi_10_4_ops = { + .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, + .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .gen_init = ath10k_wmi_10_4_op_gen_init, }; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index dbb9f1c8c917..b1bec031c111 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2947,6 +2947,21 @@ struct wmi_mgmt_rx_event_v2 { u8 buf[0]; } __packed; +struct wmi_10_4_mgmt_rx_hdr { + __le32 channel; + __le32 snr; + u8 rssi_ctl[4]; + __le32 rate; + __le32 phy_mode; + __le32 buf_len; + __le32 status; +} __packed; + +struct wmi_10_4_mgmt_rx_event { + struct wmi_10_4_mgmt_rx_hdr hdr; + u8 buf[0]; +} __packed; + #define WMI_RX_STATUS_OK 0x00 #define WMI_RX_STATUS_ERR_CRC 0x01 #define WMI_RX_STATUS_ERR_DECRYPT 0x08 -- cgit v1.3-6-gb490 From b039941704452d8f89e83cba352b5c89a6ebf2ab Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:17 +0530 Subject: ath10k: adjust default peer limits if qcache enabled in 10.4 fw 10.4 firmware supports upto 512 clients when qcache feature is enabled. Make adjustment on default max peer count, active peers, number of tid in such case to meet qcache requirement. 10.4 fw has extra unit info flag NUM_UNITS_IS_NUM_ACTIVE_PEERS which is also handled in this patch. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.h | 6 ++++++ drivers/net/wireless/ath/ath10k/wmi.c | 27 +++++++++++++++++++++++---- drivers/net/wireless/ath/ath10k/wmi.h | 5 +++-- 3 files changed, 32 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 52fc0249378b..568c5ea5561f 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -360,6 +360,12 @@ enum ath10k_hw_rate_cck { #define TARGET_10_4_NUM_PEERS ((TARGET_10_4_NUM_STATIONS) + \ (TARGET_10_4_NUM_VDEVS)) #define TARGET_10_4_ACTIVE_PEERS 0 + +/* TODO: increase qcache max client limit to 512 after + * testing with 512 client. + */ +#define TARGET_10_4_NUM_QCACHE_PEERS_MAX 256 +#define TARGET_10_4_QCACHE_ACTIVE_PEERS 50 #define TARGET_10_4_NUM_OFFLOAD_PEERS 0 #define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0 #define TARGET_10_4_NUM_PEER_KEYS 2 diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 9502032f46dc..62ea0bca03e1 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3826,20 +3826,39 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) return; } + if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) { + ar->max_num_peers = TARGET_10_4_NUM_QCACHE_PEERS_MAX + + TARGET_10_4_NUM_VDEVS; + ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS + + TARGET_10_4_NUM_VDEVS; + ar->num_tids = ar->num_active_peers * 2; + ar->max_num_stations = TARGET_10_4_NUM_QCACHE_PEERS_MAX; + } + + /* TODO: Adjust max peer count for cases like WMI_SERVICE_RATECTRL_CACHE + * and WMI_SERVICE_IRAM_TIDS, etc. + */ + for (i = 0; i < num_mem_reqs; ++i) { req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id); num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units); unit_size = __le32_to_cpu(arg.mem_reqs[i]->unit_size); num_unit_info = __le32_to_cpu(arg.mem_reqs[i]->num_unit_info); - if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) + if (num_unit_info & NUM_UNITS_IS_NUM_ACTIVE_PEERS) { + if (ar->num_active_peers) + num_units = ar->num_active_peers + 1; + else + num_units = ar->max_num_peers + 1; + } else if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) { /* number of units to allocate is number of * peers, 1 extra for self peer on target */ /* this needs to be tied, host and target * can get out of sync */ - num_units = TARGET_10X_NUM_PEERS + 1; - else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) - num_units = TARGET_10X_NUM_VDEVS + 1; + num_units = ar->max_num_peers + 1; + } else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) { + num_units = ar->max_num_vdevs + 1; + } ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n", diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b1bec031c111..b1e4932f97f9 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2377,8 +2377,9 @@ struct wmi_resource_config_10_2 { __le32 feature_mask; } __packed; -#define NUM_UNITS_IS_NUM_VDEVS 0x1 -#define NUM_UNITS_IS_NUM_PEERS 0x2 +#define NUM_UNITS_IS_NUM_VDEVS BIT(0) +#define NUM_UNITS_IS_NUM_PEERS BIT(1) +#define NUM_UNITS_IS_NUM_ACTIVE_PEERS BIT(2) struct wmi_resource_config_10_4 { /* Number of virtual devices (VAPs) to support */ -- cgit v1.3-6-gb490 From d02e752f732a91e2a6de9a3547c682914ae0bbe7 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:18 +0530 Subject: ath10k: handle 10.4 fw wmi ready event Reuse existing function ath10k_wmi_op_pull_rdy_ev() to parse WMI_10_4_READY_EVENTID and handle the same event in ath10k_wmi_10_4_op_rx(). Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 62ea0bca03e1..271ad2f86d24 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4338,6 +4338,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_mgmt_rx(ar, skb); /* mgmt_rx() owns the skb now! */ return; + case WMI_10_4_READY_EVENTID: + ath10k_wmi_event_ready(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -6270,6 +6273,7 @@ static const struct wmi_ops wmi_10_4_ops = { .map_svc = wmi_10_4_svc_map, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, + .pull_rdy = ath10k_wmi_op_pull_rdy_ev, .gen_init = ath10k_wmi_10_4_op_gen_init, }; -- cgit v1.3-6-gb490 From b24fc6fc7c0f6425793fd46ccc4ea48f49447617 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 16 Jun 2015 10:34:03 +0200 Subject: ath: DFS - limit number of potential PRI sequences In the PRI detector, after the current radar pulse has been checked agains existing PRI sequences, it is considered as part of a new potential sequence. Previously, the condition to accept a new sequence was to have at least the same number of pulses as the longest matching sequence. This was wrong, since it led to duplicates of PRI sequences. This patch changes the acceptance criteria for new potential sequences from 'at least' to 'more than' the longest existing. Detection performance remains unaffected, while the number of PRI sequences accounted at runtime (and with it CPU load) is reduced by up to 50%. Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/dfs_pri_detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c index 1b5ad1965607..cc5c592fc4c0 100644 --- a/drivers/net/wireless/ath/dfs_pri_detector.c +++ b/drivers/net/wireless/ath/dfs_pri_detector.c @@ -273,7 +273,7 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde, tmp_false_count++; } } - if (ps.count < min_count) + if (ps.count <= min_count) /* did not reach minimum count, drop sequence */ continue; -- cgit v1.3-6-gb490 From 33190ebfb1e846f97366a334e45b03caf4a65c84 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 15 Jun 2015 17:42:32 +0300 Subject: wil6210: restart AP upon change in privacy settings privacy settings might change while AP is running. Inside wil_cfg80211_change_beacon(), detect change in privacy settings and handle it by stopping and re-starting the AP. Firmware cannot handle on-the-fly privacy settings change and so AP restart is required. Signed-off-by: Dedy Lansky Signed-off-by: Hamad Kadmany Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 217 +++++++++++++++++----------- drivers/net/wireless/ath/wil6210/wil6210.h | 2 + 2 files changed, 135 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index c79cfe02ec80..e4be2d9bbac4 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -736,6 +736,92 @@ static int wil_fix_bcon(struct wil6210_priv *wil, return rc; } +/* internal functions for device reset and starting AP */ +static int _wil_cfg80211_set_ies(struct wiphy *wiphy, + size_t probe_ies_len, const u8 *probe_ies, + size_t assoc_ies_len, const u8 *assoc_ies) + +{ + int rc; + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + /* FW do not form regular beacon, so bcon IE's are not set + * For the DMG bcon, when it will be supported, bcon IE's will + * be reused; add something like: + * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, + * bcon->beacon_ies); + */ + rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, probe_ies_len, probe_ies); + if (rc) { + wil_err(wil, "set_ie(PROBE_RESP) failed\n"); + return rc; + } + + rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, assoc_ies_len, assoc_ies); + if (rc) { + wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); + return rc; + } + + return 0; +} + +static int _wil_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *ssid, size_t ssid_len, u32 privacy, + int bi, u8 chan, + size_t probe_ies_len, const u8 *probe_ies, + size_t assoc_ies_len, const u8 *assoc_ies, + u8 hidden_ssid) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + struct wireless_dev *wdev = ndev->ieee80211_ptr; + u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); + + wil_set_recovery_state(wil, fw_recovery_idle); + + mutex_lock(&wil->mutex); + + __wil_down(wil); + rc = __wil_up(wil); + if (rc) + goto out; + + rc = wmi_set_ssid(wil, ssid_len, ssid); + if (rc) + goto out; + + rc = _wil_cfg80211_set_ies(wiphy, probe_ies_len, probe_ies, + assoc_ies_len, assoc_ies); + if (rc) + goto out; + + wil->privacy = privacy; + wil->channel = chan; + wil->hidden_ssid = hidden_ssid; + + netif_carrier_on(ndev); + + rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid); + if (rc) + goto err_pcp_start; + + rc = wil_bcast_init(wil); + if (rc) + goto err_bcast; + + goto out; /* success */ + +err_bcast: + wmi_pcp_stop(wil); +err_pcp_start: + netif_carrier_off(ndev); +out: + mutex_unlock(&wil->mutex); + return rc; +} + static int wil_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_beacon_data *bcon) @@ -746,6 +832,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, const u8 *pr_ies = NULL; size_t pr_ies_len = 0; int rc; + u32 privacy = 0; wil_dbg_misc(wil, "%s()\n", __func__); wil_print_bcon_data(bcon); @@ -760,40 +847,41 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, wil_print_bcon_data(bcon); } - /* FW do not form regular beacon, so bcon IE's are not set - * For the DMG bcon, when it will be supported, bcon IE's will - * be reused; add something like: - * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, - * bcon->beacon_ies); - */ - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); - if (rc) { - wil_err(wil, "set_ie(PROBE_RESP) failed\n"); - return rc; - } + if (pr_ies && cfg80211_find_ie(WLAN_EID_RSN, pr_ies, pr_ies_len)) + privacy = 1; - rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, - bcon->assocresp_ies_len, - bcon->assocresp_ies); - if (rc) { - wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); - return rc; + /* in case privacy has changed, need to restart the AP */ + if (wil->privacy != privacy) { + struct wireless_dev *wdev = ndev->ieee80211_ptr; + + wil_dbg_misc(wil, "privacy changed %d=>%d. Restarting AP\n", + wil->privacy, privacy); + + rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid, + wdev->ssid_len, privacy, + wdev->beacon_interval, + wil->channel, pr_ies_len, pr_ies, + bcon->assocresp_ies_len, + bcon->assocresp_ies, + wil->hidden_ssid); + } else { + rc = _wil_cfg80211_set_ies(wiphy, pr_ies_len, pr_ies, + bcon->assocresp_ies_len, + bcon->assocresp_ies); } - return 0; + return rc; } static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *info) { - int rc = 0; + int rc; struct wil6210_priv *wil = wiphy_to_wil(wiphy); - struct wireless_dev *wdev = ndev->ieee80211_ptr; struct ieee80211_channel *channel = info->chandef.chan; struct cfg80211_beacon_data *bcon = &info->beacon; struct cfg80211_crypto_settings *crypto = &info->crypto; - u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); const u8 *pr_ies = NULL; @@ -807,6 +895,23 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } + switch (info->hidden_ssid) { + case NL80211_HIDDEN_SSID_NOT_IN_USE: + hidden_ssid = WMI_HIDDEN_SSID_DISABLED; + break; + + case NL80211_HIDDEN_SSID_ZERO_LEN: + hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY; + break; + + case NL80211_HIDDEN_SSID_ZERO_CONTENTS: + hidden_ssid = WMI_HIDDEN_SSID_CLEAR; + break; + + default: + wil_err(wil, "AP: Invalid hidden SSID %d\n", info->hidden_ssid); + return -EOPNOTSUPP; + } wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, channel->center_freq, info->privacy ? "secure" : "open"); wil_dbg_misc(wil, "Privacy: %d auth_type %d\n", @@ -830,70 +935,14 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_print_bcon_data(bcon); } - wil_set_recovery_state(wil, fw_recovery_idle); - - mutex_lock(&wil->mutex); - - __wil_down(wil); - rc = __wil_up(wil); - if (rc) - goto out; - - rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); - if (rc) - goto out; - - /* IE's */ - /* bcon 'head IE's are not relevant for 60g band */ - /* - * FW do not form regular beacon, so bcon IE's are not set - * For the DMG bcon, when it will be supported, bcon IE's will - * be reused; add something like: - * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, - * bcon->beacon_ies); - */ - wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); - wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, - bcon->assocresp_ies); - - wil->privacy = info->privacy; - - switch (info->hidden_ssid) { - case NL80211_HIDDEN_SSID_NOT_IN_USE: - hidden_ssid = WMI_HIDDEN_SSID_DISABLED; - break; - - case NL80211_HIDDEN_SSID_ZERO_LEN: - hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY; - break; - - case NL80211_HIDDEN_SSID_ZERO_CONTENTS: - hidden_ssid = WMI_HIDDEN_SSID_CLEAR; - break; - - default: - rc = -EOPNOTSUPP; - goto out; - } - - netif_carrier_on(ndev); - - rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, - channel->hw_value, hidden_ssid); - if (rc) - goto err_pcp_start; + rc = _wil_cfg80211_start_ap(wiphy, ndev, + info->ssid, info->ssid_len, info->privacy, + info->beacon_interval, channel->hw_value, + pr_ies_len, pr_ies, + bcon->assocresp_ies_len, + bcon->assocresp_ies, + hidden_ssid); - rc = wil_bcast_init(wil); - if (rc) - goto err_bcast; - - goto out; /* success */ -err_bcast: - wmi_pcp_stop(wil); -err_pcp_start: - netif_carrier_off(ndev); -out: - mutex_unlock(&wil->mutex); return rc; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 275355d46a36..c63e4a35eaa0 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -559,6 +559,8 @@ struct wil6210_priv { /* profile */ u32 monitor_flags; u32 privacy; /* secure connection? */ + u8 hidden_ssid; /* relevant in AP mode */ + u16 channel; /* relevant in AP mode */ int sinfo_gen; u32 ap_isolate; /* no intra-BSS communication */ /* interrupt moderation */ -- cgit v1.3-6-gb490 From a03fee347cdcbf101820b2984366a37043ffc62b Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:20 +0530 Subject: ath10k: enhance swba event handler to adapt different size tim bitmap Due to 512 client support in 10.4 firmware, size of tim ie is going to be slightly higher than non 10.4 firmware. So, size of tim_bitmap what is carried in swba event from 10.4 firmware is bit higher. The only bottle neck to reuse existing swba handler ath10k_wmi_event_host_swba() for 10.4 is that code designed to deal with fixed size tim bitmap(ie, tim_info[].tim_bitmap in wmi_swba_ev_arg). This patch removes such size limitation and makes it more suitable to handle swba event which has different size tim bitmap. All existing swba event parsing functions are changed to adapt this change. Actual support to handle 10.4 swba event is added in next patch. Only preparation is made in this patch. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 18 ++++++++++- drivers/net/wireless/ath/ath10k/wmi.c | 53 +++++++++++++++++++++++-------- drivers/net/wireless/ath/ath10k/wmi.h | 10 +++++- 3 files changed, 66 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 620b37b59784..ced35a1e0675 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -709,6 +709,8 @@ static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len, const void *ptr, void *data) { struct wmi_tlv_swba_parse *swba = data; + struct wmi_tim_info_arg *tim_info_arg; + const struct wmi_tim_info *tim_info_ev = ptr; if (tag != WMI_TLV_TAG_STRUCT_TIM_INFO) return -EPROTO; @@ -716,7 +718,21 @@ static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len, if (swba->n_tim >= ARRAY_SIZE(swba->arg->tim_info)) return -ENOBUFS; - swba->arg->tim_info[swba->n_tim++] = ptr; + if (__le32_to_cpu(tim_info_ev->tim_len) > + sizeof(tim_info_ev->tim_bitmap)) { + ath10k_warn(ar, "refusing to parse invalid swba structure\n"); + return -EPROTO; + } + + tim_info_arg = &swba->arg->tim_info[swba->n_tim]; + tim_info_arg->tim_len = tim_info_ev->tim_len; + tim_info_arg->tim_mcast = tim_info_ev->tim_mcast; + tim_info_arg->tim_bitmap = tim_info_ev->tim_bitmap; + tim_info_arg->tim_changed = tim_info_ev->tim_changed; + tim_info_arg->tim_num_ps_pending = tim_info_ev->tim_num_ps_pending; + + swba->n_tim++; + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 271ad2f86d24..228c3dd6713a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2874,33 +2874,42 @@ exit: static void ath10k_wmi_update_tim(struct ath10k *ar, struct ath10k_vif *arvif, struct sk_buff *bcn, - const struct wmi_tim_info *tim_info) + const struct wmi_tim_info_arg *tim_info) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data; struct ieee80211_tim_ie *tim; u8 *ies, *ie; u8 ie_len, pvm_len; __le32 t; - u32 v; + u32 v, tim_len; + + /* When FW reports 0 in tim_len, ensure atleast first byte + * in tim_bitmap is considered for pvm calculation. + */ + tim_len = tim_info->tim_len ? __le32_to_cpu(tim_info->tim_len) : 1; /* if next SWBA has no tim_changed the tim_bitmap is garbage. * we must copy the bitmap upon change and reuse it later */ if (__le32_to_cpu(tim_info->tim_changed)) { int i; - BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) != - sizeof(tim_info->tim_bitmap)); + if (sizeof(arvif->u.ap.tim_bitmap) < tim_len) { + ath10k_warn(ar, "SWBA TIM field is too big (%u), truncated it to %zu", + tim_len, sizeof(arvif->u.ap.tim_bitmap)); + tim_len = sizeof(arvif->u.ap.tim_bitmap); + } - for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) { + for (i = 0; i < tim_len; i++) { t = tim_info->tim_bitmap[i / 4]; v = __le32_to_cpu(t); arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF; } - /* FW reports either length 0 or 16 - * so we calculate this on our own */ + /* FW reports either length 0 or length based on max supported + * station. so we calculate this on our own + */ arvif->u.ap.tim_len = 0; - for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) + for (i = 0; i < tim_len; i++) if (arvif->u.ap.tim_bitmap[i]) arvif->u.ap.tim_len = i; @@ -2924,7 +2933,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, pvm_len = ie_len - 3; /* exclude dtim count, dtim period, bmap ctl */ if (pvm_len < arvif->u.ap.tim_len) { - int expand_size = sizeof(arvif->u.ap.tim_bitmap) - pvm_len; + int expand_size = tim_len - pvm_len; int move_size = skb_tail_pointer(bcn) - (ie + 2 + ie_len); void *next_ie = ie + 2 + ie_len; @@ -2939,7 +2948,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, } } - if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) { + if (pvm_len > tim_len) { ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len); return; } @@ -3003,7 +3012,21 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info))) break; - arg->tim_info[i] = &ev->bcn_info[i].tim_info; + if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) > + sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) { + ath10k_warn(ar, "refusing to parse invalid swba structure\n"); + return -EPROTO; + } + + arg->tim_info[i].tim_len = ev->bcn_info[i].tim_info.tim_len; + arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast; + arg->tim_info[i].tim_bitmap = + ev->bcn_info[i].tim_info.tim_bitmap; + arg->tim_info[i].tim_changed = + ev->bcn_info[i].tim_info.tim_changed; + arg->tim_info[i].tim_num_ps_pending = + ev->bcn_info[i].tim_info.tim_num_ps_pending; + arg->noa_info[i] = &ev->bcn_info[i].p2p_noa_info; i++; } @@ -3016,7 +3039,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) struct wmi_swba_ev_arg arg = {}; u32 map; int i = -1; - const struct wmi_tim_info *tim_info; + const struct wmi_tim_info_arg *tim_info; const struct wmi_p2p_noa_info *noa_info; struct ath10k_vif *arvif; struct sk_buff *bcn; @@ -3045,7 +3068,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) break; } - tim_info = arg.tim_info[i]; + tim_info = &arg.tim_info[i]; noa_info = arg.noa_info[i]; ath10k_dbg(ar, ATH10K_DBG_MGMT, @@ -3060,6 +3083,10 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) __le32_to_cpu(tim_info->tim_bitmap[1]), __le32_to_cpu(tim_info->tim_bitmap[0])); + /* TODO: Only first 4 word from tim_bitmap is dumped. + * Extend debug code to dump full tim_bitmap. + */ + arvif = ath10k_get_arvif(ar, vdev_id); if (arvif == NULL) { ath10k_warn(ar, "no vif for vdev_id %d found\n", diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b1e4932f97f9..7c4a15f1ae77 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5160,6 +5160,14 @@ struct wmi_tim_info { __le32 tim_num_ps_pending; } __packed; +struct wmi_tim_info_arg { + __le32 tim_len; + __le32 tim_mcast; + const __le32 *tim_bitmap; + __le32 tim_changed; + __le32 tim_num_ps_pending; +} __packed; + /* Maximum number of NOA Descriptors supported */ #define WMI_P2P_MAX_NOA_DESCRIPTORS 4 #define WMI_P2P_OPPPS_ENABLE_BIT BIT(0) @@ -5710,7 +5718,7 @@ struct wmi_peer_kick_ev_arg { struct wmi_swba_ev_arg { __le32 vdev_map; - const struct wmi_tim_info *tim_info[WMI_MAX_AP_VDEV]; + struct wmi_tim_info_arg tim_info[WMI_MAX_AP_VDEV]; const struct wmi_p2p_noa_info *noa_info[WMI_MAX_AP_VDEV]; }; -- cgit v1.3-6-gb490 From 3cec3be3d101bfec7136841cbb9b32ca49ac0328 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:21 +0530 Subject: ath10k: handle 10.4 firmware wmi swba event 10.4 firmware swba event payload has space to accommodate upto 512 client traffic indication info & one p2p noa descriptor. It's is not matching with exiting swba event format defined for non 10.4 firmware. Non 10.4 firmware swba event format is designed to support only upto only 128 client and four p2p notice of absence descriptor. following changes are done in this patch to enable ath10k to handle 10.4 firmware swba event, - link generic ath10k_wmi_event_host_swba() to handle 10.4 swba event in 10.4 wmi rx handler. - add 10.4 specific swba event structure wmi_10_4_host_swba_event. - new function ath10k_wmi_10_4_op_pull_swba_ev() to parse 10.4 swba event. - increase tim_bitmap[] size in ath10k_vif to 64 to hold 512 station power save state. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 4 +-- drivers/net/wireless/ath/ath10k/wmi.c | 61 ++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 41 +++++++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 58b02ae81706..86c4015270e9 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -328,8 +328,8 @@ struct ath10k_vif { u32 uapsd; } sta; struct { - /* 127 stations; wmi limit */ - u8 tim_bitmap[16]; + /* 512 stations */ + u8 tim_bitmap[64]; u8 tim_len; u32 ssid_len; u8 ssid[IEEE80211_MAX_SSID_LEN]; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 228c3dd6713a..7f9800ac15ec 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3034,6 +3034,63 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } +static int ath10k_wmi_10_4_op_pull_swba_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_swba_ev_arg *arg) +{ + struct wmi_10_4_host_swba_event *ev = (void *)skb->data; + u32 map, tim_len; + size_t i; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->vdev_map = ev->vdev_map; + + for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) { + if (!(map & BIT(0))) + continue; + + /* If this happens there were some changes in firmware and + * ath10k should update the max size of tim_info array. + */ + if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info))) + break; + + if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) > + sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) { + ath10k_warn(ar, "refusing to parse invalid swba structure\n"); + return -EPROTO; + } + + tim_len = __le32_to_cpu(ev->bcn_info[i].tim_info.tim_len); + if (tim_len) { + /* Exclude 4 byte guard length */ + tim_len -= 4; + arg->tim_info[i].tim_len = __cpu_to_le32(tim_len); + } else { + arg->tim_info[i].tim_len = 0; + } + + arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast; + arg->tim_info[i].tim_bitmap = + ev->bcn_info[i].tim_info.tim_bitmap; + arg->tim_info[i].tim_changed = + ev->bcn_info[i].tim_info.tim_changed; + arg->tim_info[i].tim_num_ps_pending = + ev->bcn_info[i].tim_info.tim_num_ps_pending; + + /* 10.4 firmware doesn't have p2p support. notice of absence + * info can be ignored for now. + */ + + i++; + } + + return 0; +} + void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) { struct wmi_swba_ev_arg arg = {}; @@ -4368,6 +4425,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; + case WMI_10_4_HOST_SWBA_EVENTID: + ath10k_wmi_event_host_swba(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -6299,6 +6359,7 @@ static const struct wmi_ops wmi_10_4_ops = { .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, .gen_init = ath10k_wmi_10_4_op_gen_init, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 7c4a15f1ae77..395742d3ff61 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5199,6 +5199,47 @@ struct wmi_host_swba_event { struct wmi_bcn_info bcn_info[0]; } __packed; +/* 16 words = 512 client + 1 word = for guard */ +#define WMI_10_4_TIM_BITMAP_ARRAY_SIZE 17 + +struct wmi_10_4_tim_info { + __le32 tim_len; + __le32 tim_mcast; + __le32 tim_bitmap[WMI_10_4_TIM_BITMAP_ARRAY_SIZE]; + __le32 tim_changed; + __le32 tim_num_ps_pending; +} __packed; + +#define WMI_10_4_P2P_MAX_NOA_DESCRIPTORS 1 + +struct wmi_10_4_p2p_noa_info { + /* Bit 0 - Flag to indicate an update in NOA schedule + * Bits 7-1 - Reserved + */ + u8 changed; + /* NOA index */ + u8 index; + /* Bit 0 - Opp PS state of the AP + * Bits 1-7 - Ctwindow in TUs + */ + u8 ctwindow_oppps; + /* Number of NOA descriptors */ + u8 num_descriptors; + + struct wmi_p2p_noa_descriptor + noa_descriptors[WMI_10_4_P2P_MAX_NOA_DESCRIPTORS]; +} __packed; + +struct wmi_10_4_bcn_info { + struct wmi_10_4_tim_info tim_info; + struct wmi_10_4_p2p_noa_info p2p_noa_info; +} __packed; + +struct wmi_10_4_host_swba_event { + __le32 vdev_map; + struct wmi_10_4_bcn_info bcn_info[0]; +} __packed; + #define WMI_MAX_AP_VDEV 16 struct wmi_tbtt_offset_event { -- cgit v1.3-6-gb490 From 373b48cfe77ff8c0ff94564a280dbfea56e769d4 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:22 +0530 Subject: ath10k: enable vdev and peer related operations for 10.4 fw Most of existing vdev and peer related functions (vdev create, vdev delete, vdev start, peer create, peer delete, peer flush, etc) are reusable for 10.4 firmware. Link those general vdev and peer functions to 10.4 wmi function table. Existing general pktlog enable/disable, dbglog configuration functions are reusable for 10.4 and add them also in wmi function table. Also handle few wmi events (sevice rdy, echo, dbg msg, tbtt offset update, dbg print) in ath10k_wmi_10_4_op_rx(). wow event is not applicable in 10.4 firmware, have it under not implemented print. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 7f9800ac15ec..a83a3636842b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4422,12 +4422,40 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_mgmt_rx(ar, skb); /* mgmt_rx() owns the skb now! */ return; + case WMI_10_4_ECHO_EVENTID: + ath10k_wmi_event_echo(ar, skb); + break; + case WMI_10_4_DEBUG_MESG_EVENTID: + ath10k_wmi_event_debug_mesg(ar, skb); + break; + case WMI_10_4_SERVICE_READY_EVENTID: + ath10k_wmi_event_service_ready(ar, skb); + break; case WMI_10_4_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; + case WMI_10_4_PEER_STA_KICKOUT_EVENTID: + ath10k_wmi_event_peer_sta_kickout(ar, skb); + break; case WMI_10_4_HOST_SWBA_EVENTID: ath10k_wmi_event_host_swba(ar, skb); break; + case WMI_10_4_TBTTOFFSET_UPDATE_EVENTID: + ath10k_wmi_event_tbttoffset_update(ar, skb); + break; + case WMI_10_4_DEBUG_PRINT_EVENTID: + ath10k_wmi_event_debug_print(ar, skb); + break; + case WMI_10_4_VDEV_START_RESP_EVENTID: + ath10k_wmi_event_vdev_start_resp(ar, skb); + break; + case WMI_10_4_VDEV_STOPPED_EVENTID: + ath10k_wmi_event_vdev_stopped(ar, skb); + break; + case WMI_10_4_WOW_WAKEUP_HOST_EVENTID: + ath10k_dbg(ar, ATH10K_DBG_WMI, + "received event id %d not implemented\n", id); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -6359,10 +6387,44 @@ static const struct wmi_ops wmi_10_4_ops = { .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + + .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, + .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, + .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, .gen_init = ath10k_wmi_10_4_op_gen_init, + .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_peer_create = ath10k_wmi_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, + .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, + .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, + .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, + .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, + .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + + /* shared with 10.2 */ + .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, }; int ath10k_wmi_attach(struct ath10k *ar) -- cgit v1.3-6-gb490 From b2297baa273b2a73d7408a97d0163c5a0dfccf8c Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:23 +0530 Subject: ath10k: add scan support for 10.4 fw Existing non 10.4 firmware scan related events and commands are matching with 10.4 firmware (except chan info event). Link general start scan,stop scan, scan channel list configuration functions to 10.4 wmi function table and add a new handler to parse 10.4 specific chan info event. 10.4 firmware has extra scan completion reason WMI_SCAN_REASON_INTERNAL_FAILURE and new scan event WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT compared to previous firmware versions. These things are added in respective enum. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 42 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 36 ++++++++++++++++++++++-------- 2 files changed, 69 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a83a3636842b..9f73c5784f45 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1923,6 +1923,8 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, return "completed [preempted]"; case WMI_SCAN_REASON_TIMEDOUT: return "completed [timedout]"; + case WMI_SCAN_REASON_INTERNAL_FAILURE: + return "completed [internal err]"; case WMI_SCAN_REASON_MAX: break; } @@ -1937,6 +1939,10 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, return "preempted"; case WMI_SCAN_EVENT_START_FAILED: return "start failed"; + case WMI_SCAN_EVENT_RESTARTED: + return "restarted"; + case WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT: + return "foreign channel exit"; default: return "unknown"; } @@ -2012,6 +2018,8 @@ int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) break; case WMI_SCAN_EVENT_DEQUEUED: case WMI_SCAN_EVENT_PREEMPTED: + case WMI_SCAN_EVENT_RESTARTED: + case WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT: default: break; } @@ -2318,6 +2326,29 @@ static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } +static int ath10k_wmi_10_4_op_pull_ch_info_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg) +{ + struct wmi_10_4_chan_info_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->err_code = ev->err_code; + arg->freq = ev->freq; + arg->cmd_flags = ev->cmd_flags; + arg->noise_floor = ev->noise_floor; + arg->rx_clear_count = ev->rx_clear_count; + arg->cycle_count = ev->cycle_count; + arg->chan_tx_pwr_range = ev->chan_tx_pwr_range; + arg->chan_tx_pwr_tp = ev->chan_tx_pwr_tp; + arg->rx_frame_count = ev->rx_frame_count; + + return 0; +} + void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) { struct wmi_ch_info_ev_arg arg = {}; @@ -4431,6 +4462,12 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); break; + case WMI_10_4_SCAN_EVENTID: + ath10k_wmi_event_scan(ar, skb); + break; + case WMI_10_4_CHAN_INFO_EVENTID: + ath10k_wmi_event_chan_info(ar, skb); + break; case WMI_10_4_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; @@ -6386,7 +6423,10 @@ static const struct wmi_ops wmi_10_2_4_ops = { static const struct wmi_ops wmi_10_4_ops = { .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, + + .pull_scan = ath10k_wmi_op_pull_scan_ev, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_10_4_op_pull_ch_info_ev, .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, @@ -6398,6 +6438,8 @@ static const struct wmi_ops wmi_10_4_ops = { .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, .gen_init = ath10k_wmi_10_4_op_gen_init, + .gen_start_scan = ath10k_wmi_op_gen_start_scan, + .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 395742d3ff61..6e806cb7ebe2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2879,15 +2879,17 @@ enum wmi_bss_filter { }; enum wmi_scan_event_type { - WMI_SCAN_EVENT_STARTED = 0x1, - WMI_SCAN_EVENT_COMPLETED = 0x2, - WMI_SCAN_EVENT_BSS_CHANNEL = 0x4, - WMI_SCAN_EVENT_FOREIGN_CHANNEL = 0x8, - WMI_SCAN_EVENT_DEQUEUED = 0x10, - WMI_SCAN_EVENT_PREEMPTED = 0x20, /* possibly by high-prio scan */ - WMI_SCAN_EVENT_START_FAILED = 0x40, - WMI_SCAN_EVENT_RESTARTED = 0x80, - WMI_SCAN_EVENT_MAX = 0x8000 + WMI_SCAN_EVENT_STARTED = BIT(0), + WMI_SCAN_EVENT_COMPLETED = BIT(1), + WMI_SCAN_EVENT_BSS_CHANNEL = BIT(2), + WMI_SCAN_EVENT_FOREIGN_CHANNEL = BIT(3), + WMI_SCAN_EVENT_DEQUEUED = BIT(4), + /* possibly by high-prio scan */ + WMI_SCAN_EVENT_PREEMPTED = BIT(5), + WMI_SCAN_EVENT_START_FAILED = BIT(6), + WMI_SCAN_EVENT_RESTARTED = BIT(7), + WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT = BIT(8), + WMI_SCAN_EVENT_MAX = BIT(15), }; enum wmi_scan_completion_reason { @@ -2895,6 +2897,7 @@ enum wmi_scan_completion_reason { WMI_SCAN_REASON_CANCELLED, WMI_SCAN_REASON_PREEMPTED, WMI_SCAN_REASON_TIMEDOUT, + WMI_SCAN_REASON_INTERNAL_FAILURE, WMI_SCAN_REASON_MAX, }; @@ -5564,6 +5567,18 @@ struct wmi_chan_info_event { __le32 cycle_count; } __packed; +struct wmi_10_4_chan_info_event { + __le32 err_code; + __le32 freq; + __le32 cmd_flags; + __le32 noise_floor; + __le32 rx_clear_count; + __le32 cycle_count; + __le32 chan_tx_pwr_range; + __le32 chan_tx_pwr_tp; + __le32 rx_frame_count; +} __packed; + struct wmi_peer_sta_kickout_event { struct wmi_mac_addr peer_macaddr; } __packed; @@ -5744,6 +5759,9 @@ struct wmi_ch_info_ev_arg { __le32 noise_floor; __le32 rx_clear_count; __le32 cycle_count; + __le32 chan_tx_pwr_range; + __le32 chan_tx_pwr_tp; + __le32 rx_frame_count; }; struct wmi_vdev_start_ev_arg { -- cgit v1.3-6-gb490 From 721ad3ca7956ce66e11fdcb187769130486feb28 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:24 +0530 Subject: ath10k: add 10.4 fw specific htt msg definitions New htt event table is added for 10.4 firmware. Following new htt events are available only 10.4. adding this to generic htt event table, HTT_T2H_MSG_TYPE_EN_STATS, HTT_T2H_MSG_TYPE_TX_FETCH_IND, HTT_T2H_MSG_TYPE_TX_FETCH_CONF, HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/htt.c | 41 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/htt.h | 36 ++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/htt_rx.c | 4 ++++ drivers/net/wireless/ath/ath10k/hw.h | 2 ++ 5 files changed, 84 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 020ac9f10168..7ef960792dbc 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1121,6 +1121,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS; ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; + ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PEER; break; case ATH10K_FW_WMI_OP_VERSION_UNSET: diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 6da6ef26143a..6f71f94939fa 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -102,6 +102,43 @@ static const enum htt_t2h_msg_type htt_tlv_t2h_msg_types[] = { [HTT_TLV_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST, }; +static const enum htt_t2h_msg_type htt_10_4_t2h_msg_types[] = { + [HTT_10_4_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF, + [HTT_10_4_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND, + [HTT_10_4_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH, + [HTT_10_4_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP, + [HTT_10_4_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP, + [HTT_10_4_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA, + [HTT_10_4_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA, + [HTT_10_4_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND, + [HTT_10_4_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG, + [HTT_10_4_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF, + [HTT_10_4_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND, + [HTT_10_4_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND, + [HTT_10_4_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND, + [HTT_10_4_T2H_MSG_TYPE_TX_INSPECT_IND] = + HTT_T2H_MSG_TYPE_TX_INSPECT_IND, + [HTT_10_4_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] = + HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION, + [HTT_10_4_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE, + [HTT_10_4_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] = + HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND, + [HTT_10_4_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND, + [HTT_10_4_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] = + HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND, + [HTT_10_4_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST, + [HTT_10_4_T2H_MSG_TYPE_EN_STATS] = HTT_T2H_MSG_TYPE_EN_STATS, + [HTT_10_4_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF, + [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND] = + HTT_T2H_MSG_TYPE_TX_FETCH_IND, + [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF] = + HTT_T2H_MSG_TYPE_TX_FETCH_CONF, + [HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD] = + HTT_T2H_MSG_TYPE_STATS_NOUPLOAD, + [HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND] = + HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND, +}; + int ath10k_htt_connect(struct ath10k_htt *htt) { struct ath10k_htc_svc_conn_req conn_req; @@ -147,6 +184,10 @@ int ath10k_htt_init(struct ath10k *ar) 2; /* ip4 dscp or ip6 priority */ switch (ar->htt.op_version) { + case ATH10K_FW_HTT_OP_VERSION_10_4: + ar->htt.t2h_msg_types = htt_10_4_t2h_msg_types; + ar->htt.t2h_msg_types_max = HTT_10_4_T2H_NUM_MSGS; + break; case ATH10K_FW_HTT_OP_VERSION_10_1: ar->htt.t2h_msg_types = htt_10x_t2h_msg_types; ar->htt.t2h_msg_types_max = HTT_10X_T2H_NUM_MSGS; diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 7e8a0d835663..8e64ace0119b 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -349,6 +349,38 @@ enum htt_tlv_t2h_msg_type { HTT_TLV_T2H_NUM_MSGS }; +enum htt_10_4_t2h_msg_type { + HTT_10_4_T2H_MSG_TYPE_VERSION_CONF = 0x0, + HTT_10_4_T2H_MSG_TYPE_RX_IND = 0x1, + HTT_10_4_T2H_MSG_TYPE_RX_FLUSH = 0x2, + HTT_10_4_T2H_MSG_TYPE_PEER_MAP = 0x3, + HTT_10_4_T2H_MSG_TYPE_PEER_UNMAP = 0x4, + HTT_10_4_T2H_MSG_TYPE_RX_ADDBA = 0x5, + HTT_10_4_T2H_MSG_TYPE_RX_DELBA = 0x6, + HTT_10_4_T2H_MSG_TYPE_TX_COMPL_IND = 0x7, + HTT_10_4_T2H_MSG_TYPE_PKTLOG = 0x8, + HTT_10_4_T2H_MSG_TYPE_STATS_CONF = 0x9, + HTT_10_4_T2H_MSG_TYPE_RX_FRAG_IND = 0xa, + HTT_10_4_T2H_MSG_TYPE_SEC_IND = 0xb, + HTT_10_4_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc, + HTT_10_4_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd, + HTT_10_4_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe, + HTT_10_4_T2H_MSG_TYPE_CHAN_CHANGE = 0xf, + HTT_10_4_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0x10, + HTT_10_4_T2H_MSG_TYPE_RX_PN_IND = 0x11, + HTT_10_4_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x12, + HTT_10_4_T2H_MSG_TYPE_TEST = 0x13, + HTT_10_4_T2H_MSG_TYPE_EN_STATS = 0x14, + HTT_10_4_T2H_MSG_TYPE_AGGR_CONF = 0x15, + HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND = 0x16, + HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF = 0x17, + HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x18, + /* 0x19 to 0x2f are reserved */ + HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND = 0x30, + /* keep this last */ + HTT_10_4_T2H_NUM_MSGS +}; + enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_VERSION_CONF, HTT_T2H_MSG_TYPE_RX_IND, @@ -375,6 +407,10 @@ enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_AGGR_CONF, HTT_T2H_MSG_TYPE_STATS_NOUPLOAD, HTT_T2H_MSG_TYPE_TEST, + HTT_T2H_MSG_TYPE_EN_STATS, + HTT_T2H_MSG_TYPE_TX_FETCH_IND, + HTT_T2H_MSG_TYPE_TX_FETCH_CONF, + HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND, /* keep this last */ HTT_T2H_NUM_MSGS }; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 7399e45a016e..d7d118328f31 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2072,6 +2072,10 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; case HTT_T2H_MSG_TYPE_CHAN_CHANGE: break; + case HTT_T2H_MSG_TYPE_EN_STATS: + case HTT_T2H_MSG_TYPE_TX_FETCH_IND: + case HTT_T2H_MSG_TYPE_TX_FETCH_CONF: + case HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND: default: ath10k_warn(ar, "htt event (%d) not handled\n", resp->hdr.msg_type); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 568c5ea5561f..917228517546 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -153,6 +153,8 @@ enum ath10k_fw_htt_op_version { ATH10K_FW_HTT_OP_VERSION_TLV = 3, + ATH10K_FW_HTT_OP_VERSION_10_4 = 4, + /* keep last */ ATH10K_FW_HTT_OP_VERSION_MAX, }; -- cgit v1.3-6-gb490 From cf36fef08a85c815d9358e1571d3d83da02474f7 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:25 +0530 Subject: ath10k: advertise 10.4 fw ap and sta iface combination to mac80211 10.4 fw supports upto 16 interface in ap mode and 1 interface in station mode, overall total interfaces supported are 16 interfaces. Populate this limit in wiphy->iface_combinations. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a8561d1f26e3..0f3c17c0c8f8 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6620,6 +6620,33 @@ static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = { }, }; +static const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 16, + .types = BIT(NL80211_IFTYPE_AP) + }, +}; + +static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = { + { + .limits = ath10k_10_4_if_limits, + .n_limits = ARRAY_SIZE(ath10k_10_4_if_limits), + .max_interfaces = 16, + .num_different_channels = 1, + .beacon_int_infra_match = true, +#ifdef CONFIG_ATH10K_DFS_CERTIFIED + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), +#endif + }, +}; + static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) { struct ieee80211_sta_vht_cap vht_cap = {0}; @@ -6944,6 +6971,9 @@ int ath10k_mac_register(struct ath10k *ar) ARRAY_SIZE(ath10k_10x_if_comb); break; case ATH10K_FW_WMI_OP_VERSION_10_4: + ar->hw->wiphy->iface_combinations = ath10k_10_4_if_comb; + ar->hw->wiphy->n_iface_combinations = + ARRAY_SIZE(ath10k_10_4_if_comb); break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: -- cgit v1.3-6-gb490 From 5c8726eca3e4080615f09328d1f28013b6e5c837 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:26 +0530 Subject: ath10k: set max spatial stream to 4 for 10.4 fw 10.4 fw supports upto 4 spatial stream. Limit max spatial stream to 4 for 10.4 firmware and to 3 for non 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 4 ++++ drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 6 +++--- drivers/net/wireless/ath/ath10k/wmi.h | 3 ++- 4 files changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7ef960792dbc..79d40d904296 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1095,6 +1095,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | WMI_STAT_PEER; + ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_10_1: case ATH10K_FW_WMI_OP_VERSION_10_2: @@ -1104,6 +1105,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->max_num_vdevs = TARGET_10X_NUM_VDEVS; ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PEER; + ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_TLV: ar->max_num_peers = TARGET_TLV_NUM_PEERS; @@ -1114,6 +1116,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS; ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | WMI_STAT_PEER; + ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_10_4: ar->max_num_peers = TARGET_10_4_NUM_PEERS; @@ -1123,6 +1126,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PEER; + ar->max_spatial_stream = WMI_10_4_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 86c4015270e9..f0811d0a8a7c 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -546,6 +546,7 @@ struct ath10k { u32 ht_cap_info; u32 vht_cap_info; u32 num_rf_chains; + u32 max_spatial_stream; /* protected by conf_mutex */ bool ani_enabled; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 9f73c5784f45..638332e96931 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3915,10 +3915,10 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) if (ar->fw_api == 1 && ar->fw_version_build > 636) set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features); - if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { + if (ar->num_rf_chains > ar->max_spatial_stream) { ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n", - ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); - ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; + ar->num_rf_chains, ar->max_spatial_stream); + ar->num_rf_chains = ar->max_spatial_stream; } ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 6e806cb7ebe2..0d4efc9c5796 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -1747,7 +1747,8 @@ enum wmi_channel_change_cause { /* Indicate reason for channel switch */ #define WMI_CHANNEL_CHANGE_CAUSE_CSA (1 << 13) -#define WMI_MAX_SPATIAL_STREAM 3 +#define WMI_MAX_SPATIAL_STREAM 3 /* default max ss */ +#define WMI_10_4_MAX_SPATIAL_STREAM 4 /* HT Capabilities*/ #define WMI_HT_CAP_ENABLED 0x0001 /* HT Enabled/ disabled */ -- cgit v1.3-6-gb490 From d9156b5f6849a1b1185ac62790f36df013b1ade6 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:27 +0530 Subject: ath10k: configure frag desc memory to target for qca99X0 Pre qca99X0 chipsets follows the model where dynamically allocate memory for frag desc on getting new skb for TX. But, this is not going to be the case in qca99X0. It expects frag desc memory to be allocated at boot time and let the driver to reuse allocated memory after every TX completion. So there won't be any dynamic frag memory memory allocation in qca99X0 during data transmission. qca99X0 hardware doesn't need fragment desc address to be programmed in msdu descriptor for every data transaction. It needs to know only starting address of fragment descriptor at the time of the boot. During data transmission, qca99X0 hardware can retrieve corresponding frag addr by adding programmed frag desc base addr + msdu id. Allocate continuous fragment descriptor memory (same size as number of descriptor) at the time of target initialization and configure allocated dma address to the target via HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG. How this is allocated continuous memory is going to be used is not covered in this patch. It just allocates memory and hand over to firmware. If we don't do it at init time, qca99X0 will stall when firmware tries to do TX. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/core.h | 6 +++ drivers/net/wireless/ath/ath10k/htt.c | 4 ++ drivers/net/wireless/ath/ath10k/htt.h | 11 +++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 76 +++++++++++++++++++++++++++++++- 5 files changed, 96 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 79d40d904296..f79fa6c67ebc 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -111,6 +111,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .otp_exe_param = 0x00000700, + .continuous_frag_desc = true, .fw = { .dir = QCA99X0_HW_2_0_FW_DIR, .fw = QCA99X0_HW_2_0_FW_FILE, diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index f0811d0a8a7c..2e5c935579c4 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -582,6 +582,12 @@ struct ath10k { */ bool has_shifted_cc_wraparound; + /* Some of chip expects fragment descriptor to be continuous + * memory for any TX operation. Set continuous_frag_desc flag + * for the hardware which have such requirement. + */ + bool continuous_frag_desc; + struct ath10k_hw_params_fw { const char *dir; const char *fw; diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 6f71f94939fa..4474c3e839db 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -249,5 +249,9 @@ int ath10k_htt_setup(struct ath10k_htt *htt) if (status) return status; + status = ath10k_htt_send_frag_desc_bank_cfg(htt); + if (status) + return status; + return ath10k_htt_send_rx_ring_cfg_ll(htt); } diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 8e64ace0119b..8bdf1e7dd171 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -87,6 +87,11 @@ struct htt_data_tx_desc_frag { __le32 len; } __packed; +struct htt_msdu_ext_desc { + __le32 tso_flag[4]; + struct htt_data_tx_desc_frag frags[6]; +}; + enum htt_data_tx_desc_flags0 { HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT = 1 << 0, HTT_DATA_TX_DESC_FLAGS0_NO_AGGR = 1 << 1, @@ -1466,6 +1471,11 @@ struct ath10k_htt { /* rx_status template */ struct ieee80211_rx_status rx_status; + + struct { + dma_addr_t paddr; + struct htt_msdu_ext_desc *vaddr; + } frag_desc; }; #define RX_HTT_HDR_STATUS_LEN 64 @@ -1533,6 +1543,7 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb); void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb); int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt); int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie); +int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt); int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt); int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, u8 max_subfrms_ampdu, diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index a60ef7d1d5fc..148d5b607c3c 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -84,6 +84,7 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) int ath10k_htt_tx_alloc(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; + int ret, size; ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", htt->max_num_pending_tx); @@ -94,11 +95,31 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev, sizeof(struct ath10k_htt_txbuf), 4, 0); if (!htt->tx_pool) { - idr_destroy(&htt->pending_tx); - return -ENOMEM; + ret = -ENOMEM; + goto free_idr_pending_tx; + } + + if (!ar->hw_params.continuous_frag_desc) + goto skip_frag_desc_alloc; + + size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc); + htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size, + &htt->frag_desc.paddr, + GFP_DMA); + if (!htt->frag_desc.vaddr) { + ath10k_warn(ar, "failed to alloc fragment desc memory\n"); + ret = -ENOMEM; + goto free_tx_pool; } +skip_frag_desc_alloc: return 0; + +free_tx_pool: + dma_pool_destroy(htt->tx_pool); +free_idr_pending_tx: + idr_destroy(&htt->pending_tx); + return ret; } static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) @@ -121,9 +142,18 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) void ath10k_htt_tx_free(struct ath10k_htt *htt) { + int size; + idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); idr_destroy(&htt->pending_tx); dma_pool_destroy(htt->tx_pool); + + if (htt->frag_desc.vaddr) { + size = htt->max_num_pending_tx * + sizeof(struct htt_msdu_ext_desc); + dma_free_coherent(htt->ar->dev, size, htt->frag_desc.vaddr, + htt->frag_desc.paddr); + } } void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) @@ -201,6 +231,48 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie) return 0; } +int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt) +{ + struct ath10k *ar = htt->ar; + struct sk_buff *skb; + struct htt_cmd *cmd; + int ret, size; + + if (!ar->hw_params.continuous_frag_desc) + return 0; + + if (!htt->frag_desc.paddr) { + ath10k_warn(ar, "invalid frag desc memory\n"); + return -EINVAL; + } + + size = sizeof(cmd->hdr) + sizeof(cmd->frag_desc_bank_cfg); + skb = ath10k_htc_alloc_skb(ar, size); + if (!skb) + return -ENOMEM; + + skb_put(skb, size); + cmd = (struct htt_cmd *)skb->data; + cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG; + cmd->frag_desc_bank_cfg.info = 0; + cmd->frag_desc_bank_cfg.num_banks = 1; + cmd->frag_desc_bank_cfg.desc_size = sizeof(struct htt_msdu_ext_desc); + cmd->frag_desc_bank_cfg.bank_base_addrs[0] = + __cpu_to_le32(htt->frag_desc.paddr); + cmd->frag_desc_bank_cfg.bank_id[0].bank_max_id = + __cpu_to_le16(htt->max_num_pending_tx - 1); + + ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); + if (ret) { + ath10k_warn(ar, "failed to send frag desc bank cfg request: %d\n", + ret); + dev_kfree_skb_any(skb); + return ret; + } + + return 0; +} + int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; -- cgit v1.3-6-gb490 From 0e975980d435d58df2d430d688b8c18778b42218 Mon Sep 17 00:00:00 2001 From: Peter Antoine Date: Tue, 23 Jun 2015 08:18:49 +0100 Subject: drm: Turn off Legacy Context Functions The context functions are not used by the i915 driver and should not be used by modeset drivers. These driver functions contain several bugs and security holes. This change makes these functions optional can be turned on by a setting, they are turned off by default for modeset driver with the exception of the nouvea driver that may require them with an old version of libdrm. The previous attempt was commit 7c510133d93dd6f15ca040733ba7b2891ed61fd1 Author: Daniel Vetter Date: Thu Aug 8 15:41:21 2013 +0200 drm: mark context support as a legacy subsystem but this had to be reverted commit c21eb21cb50d58e7cbdcb8b9e7ff68b85cfa5095 Author: Dave Airlie Date: Fri Sep 20 08:32:59 2013 +1000 Revert "drm: mark context support as a legacy subsystem" v2: remove returns from void function, and formatting (Daniel Vetter) v3: - s/Nova/nouveau/ in the commit message, and add references to the previous attempts - drop the part touching the drm hw lock, that should be a separate patch. Signed-off-by: Peter Antoine (v2) Cc: Peter Antoine (v2) Reviewed-by: Peter Antoine Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_context.c | 48 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_drv.c | 13 ++++++---- drivers/gpu/drm/nouveau/nouveau_drm.c | 3 ++- include/drm/drmP.h | 23 +++++++++-------- 4 files changed, 70 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c index 9b23525c0ed0..32958dabd7b0 100644 --- a/drivers/gpu/drm/drm_context.c +++ b/drivers/gpu/drm/drm_context.c @@ -53,6 +53,10 @@ struct drm_ctx_list { */ void drm_legacy_ctxbitmap_free(struct drm_device * dev, int ctx_handle) { + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return; + mutex_lock(&dev->struct_mutex); idr_remove(&dev->ctx_idr, ctx_handle); mutex_unlock(&dev->struct_mutex); @@ -87,6 +91,10 @@ static int drm_legacy_ctxbitmap_next(struct drm_device * dev) */ int drm_legacy_ctxbitmap_init(struct drm_device * dev) { + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + idr_init(&dev->ctx_idr); return 0; } @@ -101,6 +109,10 @@ int drm_legacy_ctxbitmap_init(struct drm_device * dev) */ void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev) { + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return; + mutex_lock(&dev->struct_mutex); idr_destroy(&dev->ctx_idr); mutex_unlock(&dev->struct_mutex); @@ -119,6 +131,10 @@ void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file) { struct drm_ctx_list *pos, *tmp; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return; + mutex_lock(&dev->ctxlist_mutex); list_for_each_entry_safe(pos, tmp, &dev->ctxlist, head) { @@ -161,6 +177,10 @@ int drm_legacy_getsareactx(struct drm_device *dev, void *data, struct drm_local_map *map; struct drm_map_list *_entry; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->struct_mutex); map = idr_find(&dev->ctx_idr, request->ctx_id); @@ -205,6 +225,10 @@ int drm_legacy_setsareactx(struct drm_device *dev, void *data, struct drm_local_map *map = NULL; struct drm_map_list *r_list = NULL; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->struct_mutex); list_for_each_entry(r_list, &dev->maplist, head) { if (r_list->map @@ -305,6 +329,10 @@ int drm_legacy_resctx(struct drm_device *dev, void *data, struct drm_ctx ctx; int i; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + if (res->count >= DRM_RESERVED_CONTEXTS) { memset(&ctx, 0, sizeof(ctx)); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { @@ -335,6 +363,10 @@ int drm_legacy_addctx(struct drm_device *dev, void *data, struct drm_ctx_list *ctx_entry; struct drm_ctx *ctx = data; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + ctx->handle = drm_legacy_ctxbitmap_next(dev); if (ctx->handle == DRM_KERNEL_CONTEXT) { /* Skip kernel's context and get a new one. */ @@ -378,6 +410,10 @@ int drm_legacy_getctx(struct drm_device *dev, void *data, { struct drm_ctx *ctx = data; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + /* This is 0, because we don't handle any context flags */ ctx->flags = 0; @@ -400,6 +436,10 @@ int drm_legacy_switchctx(struct drm_device *dev, void *data, { struct drm_ctx *ctx = data; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + DRM_DEBUG("%d\n", ctx->handle); return drm_context_switch(dev, dev->last_context, ctx->handle); } @@ -420,6 +460,10 @@ int drm_legacy_newctx(struct drm_device *dev, void *data, { struct drm_ctx *ctx = data; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + DRM_DEBUG("%d\n", ctx->handle); drm_context_switch_complete(dev, file_priv, ctx->handle); @@ -442,6 +486,10 @@ int drm_legacy_rmctx(struct drm_device *dev, void *data, { struct drm_ctx *ctx = data; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + DRM_DEBUG("%d\n", ctx->handle); if (ctx->handle != DRM_KERNEL_CONTEXT) { if (dev->driver->context_dtor) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index b7bf4ce8c012..838657503113 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -582,11 +582,14 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, if (drm_ht_create(&dev->map_hash, 12)) goto err_minors; - ret = drm_legacy_ctxbitmap_init(dev); - if (ret) { - DRM_ERROR("Cannot allocate memory for context bitmap.\n"); - goto err_ht; - } + if (drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) || + !drm_core_check_feature(dev, DRIVER_MODESET)) + ret = drm_legacy_ctxbitmap_init(dev); + if (ret) { + DRM_ERROR( + "Cannot allocate memory for context bitmap.\n"); + goto err_ht; + } if (drm_core_check_feature(dev, DRIVER_GEM)) { ret = drm_gem_init(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 89049335b738..9624b3827c34 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -941,7 +941,8 @@ static struct drm_driver driver_stub = { .driver_features = DRIVER_USE_AGP | - DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER, + DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER | + DRIVER_KMS_LEGACY_CONTEXT, .load = nouveau_drm_load, .unload = nouveau_drm_unload, diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 48db6a56975f..3dc7c16c18f2 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -137,17 +137,18 @@ void drm_err(const char *format, ...); /*@{*/ /* driver capabilities and requirements mask */ -#define DRIVER_USE_AGP 0x1 -#define DRIVER_PCI_DMA 0x8 -#define DRIVER_SG 0x10 -#define DRIVER_HAVE_DMA 0x20 -#define DRIVER_HAVE_IRQ 0x40 -#define DRIVER_IRQ_SHARED 0x80 -#define DRIVER_GEM 0x1000 -#define DRIVER_MODESET 0x2000 -#define DRIVER_PRIME 0x4000 -#define DRIVER_RENDER 0x8000 -#define DRIVER_ATOMIC 0x10000 +#define DRIVER_USE_AGP 0x1 +#define DRIVER_PCI_DMA 0x8 +#define DRIVER_SG 0x10 +#define DRIVER_HAVE_DMA 0x20 +#define DRIVER_HAVE_IRQ 0x40 +#define DRIVER_IRQ_SHARED 0x80 +#define DRIVER_GEM 0x1000 +#define DRIVER_MODESET 0x2000 +#define DRIVER_PRIME 0x4000 +#define DRIVER_RENDER 0x8000 +#define DRIVER_ATOMIC 0x10000 +#define DRIVER_KMS_LEGACY_CONTEXT 0x20000 /***********************************************************************/ /** \name Macros to make printk easier */ -- cgit v1.3-6-gb490 From ba6976c129a571464fccbbcf866f4f93d91113c0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 23 Jun 2015 11:22:36 +0200 Subject: drm: Convert drm_legacy_ctxbitmap_init to void return type It can't fail really. Also remove the redundant kms check Peter added. Cc: Peter Antoine Reviewed-by: Peter Antoine Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_context.c | 5 ++--- drivers/gpu/drm/drm_drv.c | 10 +--------- drivers/gpu/drm/drm_legacy.h | 2 +- 3 files changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c index 32958dabd7b0..192a5f9eeb74 100644 --- a/drivers/gpu/drm/drm_context.c +++ b/drivers/gpu/drm/drm_context.c @@ -89,14 +89,13 @@ static int drm_legacy_ctxbitmap_next(struct drm_device * dev) * * Initialise the drm_device::ctx_idr */ -int drm_legacy_ctxbitmap_init(struct drm_device * dev) +void drm_legacy_ctxbitmap_init(struct drm_device * dev) { if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; + return; idr_init(&dev->ctx_idr); - return 0; } /** diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 838657503113..9b51fe11ff19 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -582,14 +582,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, if (drm_ht_create(&dev->map_hash, 12)) goto err_minors; - if (drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) || - !drm_core_check_feature(dev, DRIVER_MODESET)) - ret = drm_legacy_ctxbitmap_init(dev); - if (ret) { - DRM_ERROR( - "Cannot allocate memory for context bitmap.\n"); - goto err_ht; - } + drm_legacy_ctxbitmap_init(dev); if (drm_core_check_feature(dev, DRIVER_GEM)) { ret = drm_gem_init(dev); @@ -603,7 +596,6 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, err_ctxbitmap: drm_legacy_ctxbitmap_cleanup(dev); -err_ht: drm_ht_remove(&dev->map_hash); err_minors: drm_minor_free(dev, DRM_MINOR_LEGACY); diff --git a/drivers/gpu/drm/drm_legacy.h b/drivers/gpu/drm/drm_legacy.h index c1dc61473db5..9b731786e4db 100644 --- a/drivers/gpu/drm/drm_legacy.h +++ b/drivers/gpu/drm/drm_legacy.h @@ -42,7 +42,7 @@ struct drm_file; #define DRM_KERNEL_CONTEXT 0 #define DRM_RESERVED_CONTEXTS 1 -int drm_legacy_ctxbitmap_init(struct drm_device *dev); +void drm_legacy_ctxbitmap_init(struct drm_device *dev); void drm_legacy_ctxbitmap_cleanup(struct drm_device *dev); void drm_legacy_ctxbitmap_free(struct drm_device *dev, int ctx_handle); void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file); -- cgit v1.3-6-gb490 From da168d81b44898404d281d5dbe70154ab5f117c1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 23 Jun 2015 11:34:21 +0200 Subject: drm: Reject DRI1 hw lock ioctl functions for kms drivers I've done some extensive history digging across libdrm, mesa and xf86-video-{intel,nouveau,ati}. The only potential user of this with kms drivers I could find was ttmtest, which once used drmGetLock still. But that mistake was quickly fixed up. Even the intel xvmc library (which otherwise was really good with using dri1 stuff in kms mode) managed to never take the hw lock for dri2 (and hence kms). Hence it should be save to unconditionally disallow this. Cc: Peter Antoine Reviewed-by: Peter Antoine Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_lock.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index f861361a635e..4924d381b664 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c @@ -61,6 +61,9 @@ int drm_legacy_lock(struct drm_device *dev, void *data, struct drm_master *master = file_priv->master; int ret = 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + ++file_priv->lock_count; if (lock->context == DRM_KERNEL_CONTEXT) { @@ -153,6 +156,9 @@ int drm_legacy_unlock(struct drm_device *dev, void *data, struct drm_file *file_ struct drm_lock *lock = data; struct drm_master *master = file_priv->master; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + if (lock->context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", task_pid_nr(current), lock->context); -- cgit v1.3-6-gb490 From 0d0b49c51e0c1b5f4facbf7191db82b39ac99b96 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 1 Jul 2015 14:05:09 +0200 Subject: drm: Remove useless blank line Blank lines at the end of a function definition are not useful, so get rid of it. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index b69ed97d447c..0bf46d5ee221 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4298,7 +4298,6 @@ void drm_property_unreference_blob(struct drm_property_blob *blob) mutex_unlock(&dev->mode_config.blob_lock); else might_lock(&dev->mode_config.blob_lock); - } EXPORT_SYMBOL(drm_property_unreference_blob); -- cgit v1.3-6-gb490 From a9cc54eeba635d2feb2ed4bf43d4ea4e08e7e0a9 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 24 Jun 2015 08:59:24 +0200 Subject: drm/atomic: Update old_fb after setting a property. This change updates the old_fb pointer only after acquiring the plane lock, if there are no properties the fb cannot have been changed either, so this works out correctly. Found in a discussion with Rob Clark. Cc: Rob Clark Signed-off-by: Maarten Lankhorst Reviewed-by: Rob Clark Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f6f2fb58eb37..bd7f723c708e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1472,12 +1472,6 @@ retry: goto fail; } - if (obj->type == DRM_MODE_OBJECT_PLANE) { - plane = obj_to_plane(obj); - plane_mask |= (1 << drm_plane_index(plane)); - plane->old_fb = plane->fb; - } - if (get_user(count_props, count_props_ptr + copied_objs)) { ret = -EFAULT; goto fail; @@ -1514,6 +1508,12 @@ retry: copied_props++; } + + if (obj->type == DRM_MODE_OBJECT_PLANE && count_props) { + plane = obj_to_plane(obj); + plane_mask |= (1 << drm_plane_index(plane)); + plane->old_fb = plane->fb; + } } if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { -- cgit v1.3-6-gb490 From 793dfa59bcfde9d642295480674926827e9adcfc Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 18 Jun 2015 17:25:53 +0300 Subject: drm/i915/bxt: mask off the DPLL state checker bits we don't program For the purpose of state checking we only care about the DPLL HW flags that we actually program, so mask off the ones that we don't. This fixes one set of DPLL state check failures. Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index cef9709fa2ba..15fc66a8da78 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2854,19 +2854,38 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, return false; hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port)); + hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK; + hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(port)); hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE; hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0)); + hw_state->pll0 &= PORT_PLL_M2_MASK; + hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1)); + hw_state->pll1 &= PORT_PLL_N_MASK; + hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2)); + hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK; + hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3)); + hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE; + hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6)); + hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK | + PORT_PLL_INT_COEFF_MASK | + PORT_PLL_GAIN_CTL_MASK; + hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8)); + hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK; + hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9)); hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK; hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10)); + hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H | + PORT_PLL_DCO_AMP_MASK; + /* * While we write to the group register to program all lanes at once we * can read only lane registers. We configure all lanes the same way, so @@ -2877,6 +2896,7 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n", hw_state->pcsdw12, I915_READ(BXT_PORT_PCS_DW12_LN23(port))); + hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD; return true; } -- cgit v1.3-6-gb490 From 79bbcc299fca92ba3558c4966e6ad52ee1052d89 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Tue, 30 Jun 2015 12:40:55 +0100 Subject: drm/i915: Reserve space improvements An earlier patch was added to reserve space in the ring buffer for the commands issued during 'add_request()'. The initial version was pessimistic in the way it handled buffer wrapping and would cause premature wraps and thus waste ring space. This patch updates the code to better handle the wrap case. It no longer enforces that the space being asked for and the reserved space are a single contiguous block. Instead, it allows the reserve to be on the far end of a wrap operation. It still guarantees that the space is available so when the wrap occurs, no wait will happen. Thus the wrap cannot fail which is the whole point of the exercise. Also fixed a merge failure with some comments from the original patch. v2: Incorporated suggestion by David Gordon to move the wrap code inside the prepare function and thus allow a single combined wait_for_space() call rather than doing one before the wrap and another after. This also makes the prepare code much simpler and easier to follow. v3: Fix for 'effective_size' vs 'size' during ring buffer remainder calculations (spotted by Tomas Elf). For: VIZ-5115 CC: Daniel Vetter Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 73 +++++++++++++------------- drivers/gpu/drm/i915/intel_ringbuffer.c | 90 +++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +- 3 files changed, 90 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8cac4cab1666..22e9f85f40e4 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -661,12 +661,12 @@ static int logical_ring_wait_for_space(struct drm_i915_gem_request *req, unsigned space; int ret; - /* The whole point of reserving space is to not wait! */ - WARN_ON(ringbuf->reserved_in_use); - if (intel_ring_space(ringbuf) >= bytes) return 0; + /* The whole point of reserving space is to not wait! */ + WARN_ON(ringbuf->reserved_in_use); + list_for_each_entry(target, &ring->request_list, list) { /* * The request queue is per-engine, so can contain requests @@ -716,22 +716,11 @@ intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request) execlists_context_queue(request); } -static int logical_ring_wrap_buffer(struct drm_i915_gem_request *req) +static void __wrap_ring_buffer(struct intel_ringbuffer *ringbuf) { - struct intel_ringbuffer *ringbuf = req->ringbuf; uint32_t __iomem *virt; int rem = ringbuf->size - ringbuf->tail; - /* Can't wrap if space has already been reserved! */ - WARN_ON(ringbuf->reserved_in_use); - - if (ringbuf->space < rem) { - int ret = logical_ring_wait_for_space(req, rem); - - if (ret) - return ret; - } - virt = ringbuf->virtual_start + ringbuf->tail; rem /= 4; while (rem--) @@ -739,40 +728,50 @@ static int logical_ring_wrap_buffer(struct drm_i915_gem_request *req) ringbuf->tail = 0; intel_ring_update_space(ringbuf); - - return 0; } static int logical_ring_prepare(struct drm_i915_gem_request *req, int bytes) { struct intel_ringbuffer *ringbuf = req->ringbuf; - int ret; - - /* - * Add on the reserved size to the request to make sure that after - * the intended commands have been emitted, there is guaranteed to - * still be enough free space to send them to the hardware. - */ - if (!ringbuf->reserved_in_use) - bytes += ringbuf->reserved_size; - - if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) { - ret = logical_ring_wrap_buffer(req); - if (unlikely(ret)) - return ret; + int remain_usable = ringbuf->effective_size - ringbuf->tail; + int remain_actual = ringbuf->size - ringbuf->tail; + int ret, total_bytes, wait_bytes = 0; + bool need_wrap = false; - if(ringbuf->reserved_size) { - uint32_t size = ringbuf->reserved_size; + if (ringbuf->reserved_in_use) + total_bytes = bytes; + else + total_bytes = bytes + ringbuf->reserved_size; - intel_ring_reserved_space_cancel(ringbuf); - intel_ring_reserved_space_reserve(ringbuf, size); + if (unlikely(bytes > remain_usable)) { + /* + * Not enough space for the basic request. So need to flush + * out the remainder and then wait for base + reserved. + */ + wait_bytes = remain_actual + total_bytes; + need_wrap = true; + } else { + if (unlikely(total_bytes > remain_usable)) { + /* + * The base request will fit but the reserved space + * falls off the end. So only need to to wait for the + * reserved size after flushing out the remainder. + */ + wait_bytes = remain_actual + ringbuf->reserved_size; + need_wrap = true; + } else if (total_bytes > ringbuf->space) { + /* No wrapping required, just waiting. */ + wait_bytes = total_bytes; } } - if (unlikely(ringbuf->space < bytes)) { - ret = logical_ring_wait_for_space(req, bytes); + if (wait_bytes) { + ret = logical_ring_wait_for_space(req, wait_bytes); if (unlikely(ret)) return ret; + + if (need_wrap) + __wrap_ring_buffer(ringbuf); } return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index af7c12ed0ba7..e39c8912f673 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2121,12 +2121,12 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n) unsigned space; int ret; - /* The whole point of reserving space is to not wait! */ - WARN_ON(ringbuf->reserved_in_use); - if (intel_ring_space(ringbuf) >= n) return 0; + /* The whole point of reserving space is to not wait! */ + WARN_ON(ringbuf->reserved_in_use); + list_for_each_entry(request, &ring->request_list, list) { space = __intel_ring_space(request->postfix, ringbuf->tail, ringbuf->size); @@ -2145,21 +2145,11 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n) return 0; } -static int intel_wrap_ring_buffer(struct intel_engine_cs *ring) +static void __wrap_ring_buffer(struct intel_ringbuffer *ringbuf) { uint32_t __iomem *virt; - struct intel_ringbuffer *ringbuf = ring->buffer; int rem = ringbuf->size - ringbuf->tail; - /* Can't wrap if space has already been reserved! */ - WARN_ON(ringbuf->reserved_in_use); - - if (ringbuf->space < rem) { - int ret = ring_wait_for_space(ring, rem); - if (ret) - return ret; - } - virt = ringbuf->virtual_start + ringbuf->tail; rem /= 4; while (rem--) @@ -2167,8 +2157,6 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring) ringbuf->tail = 0; intel_ring_update_space(ringbuf); - - return 0; } int intel_ring_idle(struct intel_engine_cs *ring) @@ -2238,9 +2226,21 @@ void intel_ring_reserved_space_use(struct intel_ringbuffer *ringbuf) void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf) { WARN_ON(!ringbuf->reserved_in_use); - WARN(ringbuf->tail > ringbuf->reserved_tail + ringbuf->reserved_size, - "request reserved size too small: %d vs %d!\n", - ringbuf->tail - ringbuf->reserved_tail, ringbuf->reserved_size); + if (ringbuf->tail > ringbuf->reserved_tail) { + WARN(ringbuf->tail > ringbuf->reserved_tail + ringbuf->reserved_size, + "request reserved size too small: %d vs %d!\n", + ringbuf->tail - ringbuf->reserved_tail, ringbuf->reserved_size); + } else { + /* + * The ring was wrapped while the reserved space was in use. + * That means that some unknown amount of the ring tail was + * no-op filled and skipped. Thus simply adding the ring size + * to the tail and doing the above space check will not work. + * Rather than attempt to track how much tail was skipped, + * it is much simpler to say that also skipping the sanity + * check every once in a while is not a big issue. + */ + } ringbuf->reserved_size = 0; ringbuf->reserved_in_use = false; @@ -2249,33 +2249,45 @@ void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf) static int __intel_ring_prepare(struct intel_engine_cs *ring, int bytes) { struct intel_ringbuffer *ringbuf = ring->buffer; - int ret; - - /* - * Add on the reserved size to the request to make sure that after - * the intended commands have been emitted, there is guaranteed to - * still be enough free space to send them to the hardware. - */ - if (!ringbuf->reserved_in_use) - bytes += ringbuf->reserved_size; - - if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) { - ret = intel_wrap_ring_buffer(ring); - if (unlikely(ret)) - return ret; + int remain_usable = ringbuf->effective_size - ringbuf->tail; + int remain_actual = ringbuf->size - ringbuf->tail; + int ret, total_bytes, wait_bytes = 0; + bool need_wrap = false; - if(ringbuf->reserved_size) { - uint32_t size = ringbuf->reserved_size; + if (ringbuf->reserved_in_use) + total_bytes = bytes; + else + total_bytes = bytes + ringbuf->reserved_size; - intel_ring_reserved_space_cancel(ringbuf); - intel_ring_reserved_space_reserve(ringbuf, size); + if (unlikely(bytes > remain_usable)) { + /* + * Not enough space for the basic request. So need to flush + * out the remainder and then wait for base + reserved. + */ + wait_bytes = remain_actual + total_bytes; + need_wrap = true; + } else { + if (unlikely(total_bytes > remain_usable)) { + /* + * The base request will fit but the reserved space + * falls off the end. So only need to to wait for the + * reserved size after flushing out the remainder. + */ + wait_bytes = remain_actual + ringbuf->reserved_size; + need_wrap = true; + } else if (total_bytes > ringbuf->space) { + /* No wrapping required, just waiting. */ + wait_bytes = total_bytes; } } - if (unlikely(ringbuf->space < bytes)) { - ret = ring_wait_for_space(ring, bytes); + if (wait_bytes) { + ret = ring_wait_for_space(ring, wait_bytes); if (unlikely(ret)) return ret; + + if (need_wrap) + __wrap_ring_buffer(ringbuf); } return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 0e2bbc6a3f8b..304cac4caf1c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -473,7 +473,6 @@ static inline u32 intel_ring_get_tail(struct intel_ringbuffer *ringbuf) * will always have sufficient room to do its stuff. The request creation * code calls this automatically. */ -int intel_ring_reserve_space(struct drm_i915_gem_request *request); void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size); /* Cancel the reservation, e.g. because the request is being discarded. */ void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf); @@ -482,4 +481,7 @@ void intel_ring_reserved_space_use(struct intel_ringbuffer *ringbuf); /* Finish with the reserved space - for use by i915_add_request() only. */ void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf); +/* Legacy ringbuffer specific portion of reservation code: */ +int intel_ring_reserve_space(struct drm_i915_gem_request *request); + #endif /* _INTEL_RINGBUFFER_H_ */ -- cgit v1.3-6-gb490 From 2e906beac6be0116c557f96d1c07cb7a955f8059 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 30 Jun 2015 18:16:37 +0300 Subject: drm/i915/gtt: Reorder page alloc/free/init functions Maintain base page handling functions in order of alloc, free, init. No functional changes. v2: s/Introduce/Maintain (Michel) v3: Rebase Cc: Michel Thierry Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 166 ++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 83 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b94eebe81fd8..ef3019c88eb7 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -384,24 +384,6 @@ static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p, fill_page_dma(dev, p, v); } -static void free_pt(struct drm_device *dev, struct i915_page_table *pt) -{ - cleanup_px(dev, pt); - kfree(pt->used_ptes); - kfree(pt); -} - -static void gen8_initialize_pt(struct i915_address_space *vm, - struct i915_page_table *pt) -{ - gen8_pte_t scratch_pte; - - scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), - I915_CACHE_LLC, true); - - fill_px(vm->dev, pt, scratch_pte); -} - static struct i915_page_table *alloc_pt(struct drm_device *dev) { struct i915_page_table *pt; @@ -433,13 +415,35 @@ fail_bitmap: return ERR_PTR(ret); } -static void free_pd(struct drm_device *dev, struct i915_page_directory *pd) +static void free_pt(struct drm_device *dev, struct i915_page_table *pt) { - if (px_page(pd)) { - cleanup_px(dev, pd); - kfree(pd->used_pdes); - kfree(pd); - } + cleanup_px(dev, pt); + kfree(pt->used_ptes); + kfree(pt); +} + +static void gen8_initialize_pt(struct i915_address_space *vm, + struct i915_page_table *pt) +{ + gen8_pte_t scratch_pte; + + scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true); + + fill_px(vm->dev, pt, scratch_pte); +} + +static void gen6_initialize_pt(struct i915_address_space *vm, + struct i915_page_table *pt) +{ + gen6_pte_t scratch_pte; + + WARN_ON(px_dma(vm->scratch_page) == 0); + + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true, 0); + + fill32_px(vm->dev, pt, scratch_pte); } static struct i915_page_directory *alloc_pd(struct drm_device *dev) @@ -470,6 +474,61 @@ fail_bitmap: return ERR_PTR(ret); } +static void free_pd(struct drm_device *dev, struct i915_page_directory *pd) +{ + if (px_page(pd)) { + cleanup_px(dev, pd); + kfree(pd->used_pdes); + kfree(pd); + } +} + +static void gen8_initialize_pd(struct i915_address_space *vm, + struct i915_page_directory *pd) +{ + gen8_pde_t scratch_pde; + + scratch_pde = gen8_pde_encode(px_dma(vm->scratch_pt), I915_CACHE_LLC); + + fill_px(vm->dev, pd, scratch_pde); +} + +static int alloc_scratch_page(struct i915_address_space *vm) +{ + struct i915_page_scratch *sp; + int ret; + + WARN_ON(vm->scratch_page); + + sp = kzalloc(sizeof(*sp), GFP_KERNEL); + if (sp == NULL) + return -ENOMEM; + + ret = __setup_page_dma(vm->dev, px_base(sp), GFP_DMA32 | __GFP_ZERO); + if (ret) { + kfree(sp); + return ret; + } + + set_pages_uc(px_page(sp), 1); + + vm->scratch_page = sp; + + return 0; +} + +static void free_scratch_page(struct i915_address_space *vm) +{ + struct i915_page_scratch *sp = vm->scratch_page; + + set_pages_wb(px_page(sp), 1); + + cleanup_px(vm->dev, sp); + kfree(sp); + + vm->scratch_page = NULL; +} + /* Broadwell Page Directory Pointer Descriptors */ static int gen8_write_pdp(struct drm_i915_gem_request *req, unsigned entry, @@ -609,16 +668,6 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, kunmap_px(ppgtt, pt_vaddr); } -static void gen8_initialize_pd(struct i915_address_space *vm, - struct i915_page_directory *pd) -{ - gen8_pde_t scratch_pde; - - scratch_pde = gen8_pde_encode(px_dma(vm->scratch_pt), I915_CACHE_LLC); - - fill_px(vm->dev, pd, scratch_pde); -} - static void gen8_free_page_tables(struct drm_device *dev, struct i915_page_directory *pd) { @@ -1274,19 +1323,6 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, kunmap_px(ppgtt, pt_vaddr); } -static void gen6_initialize_pt(struct i915_address_space *vm, - struct i915_page_table *pt) -{ - gen6_pte_t scratch_pte; - - WARN_ON(px_dma(vm->scratch_page) == 0); - - scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), - I915_CACHE_LLC, true, 0); - - fill32_px(vm->dev, pt, scratch_pte); -} - static int gen6_alloc_va_range(struct i915_address_space *vm, uint64_t start_in, uint64_t length_in) { @@ -2126,42 +2162,6 @@ void i915_global_gtt_cleanup(struct drm_device *dev) vm->cleanup(vm); } -static int alloc_scratch_page(struct i915_address_space *vm) -{ - struct i915_page_scratch *sp; - int ret; - - WARN_ON(vm->scratch_page); - - sp = kzalloc(sizeof(*sp), GFP_KERNEL); - if (sp == NULL) - return -ENOMEM; - - ret = __setup_page_dma(vm->dev, px_base(sp), GFP_DMA32 | __GFP_ZERO); - if (ret) { - kfree(sp); - return ret; - } - - set_pages_uc(px_page(sp), 1); - - vm->scratch_page = sp; - - return 0; -} - -static void free_scratch_page(struct i915_address_space *vm) -{ - struct i915_page_scratch *sp = vm->scratch_page; - - set_pages_wb(px_page(sp), 1); - - cleanup_px(vm->dev, sp); - kfree(sp); - - vm->scratch_page = NULL; -} - static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) { snb_gmch_ctl >>= SNB_GMCH_GGMS_SHIFT; -- cgit v1.3-6-gb490 From 4ad2af1ed1e972704e1dbc8e7716cd3394a27385 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 30 Jun 2015 18:16:39 +0300 Subject: drm/i915/gtt: Return struct i915_scratch_page from alloc_scratch Every other alloc_* function return the pointer to the page they alloc. Follow the convention with scratch page also. Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 78 ++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ef3019c88eb7..a4ec1c6f5652 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -384,6 +384,35 @@ static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p, fill_page_dma(dev, p, v); } +static struct i915_page_scratch *alloc_scratch_page(struct drm_device *dev) +{ + struct i915_page_scratch *sp; + int ret; + + sp = kzalloc(sizeof(*sp), GFP_KERNEL); + if (sp == NULL) + return ERR_PTR(-ENOMEM); + + ret = __setup_page_dma(dev, px_base(sp), GFP_DMA32 | __GFP_ZERO); + if (ret) { + kfree(sp); + return ERR_PTR(ret); + } + + set_pages_uc(px_page(sp), 1); + + return sp; +} + +static void free_scratch_page(struct drm_device *dev, + struct i915_page_scratch *sp) +{ + set_pages_wb(px_page(sp), 1); + + cleanup_px(dev, sp); + kfree(sp); +} + static struct i915_page_table *alloc_pt(struct drm_device *dev) { struct i915_page_table *pt; @@ -493,42 +522,6 @@ static void gen8_initialize_pd(struct i915_address_space *vm, fill_px(vm->dev, pd, scratch_pde); } -static int alloc_scratch_page(struct i915_address_space *vm) -{ - struct i915_page_scratch *sp; - int ret; - - WARN_ON(vm->scratch_page); - - sp = kzalloc(sizeof(*sp), GFP_KERNEL); - if (sp == NULL) - return -ENOMEM; - - ret = __setup_page_dma(vm->dev, px_base(sp), GFP_DMA32 | __GFP_ZERO); - if (ret) { - kfree(sp); - return ret; - } - - set_pages_uc(px_page(sp), 1); - - vm->scratch_page = sp; - - return 0; -} - -static void free_scratch_page(struct i915_address_space *vm) -{ - struct i915_page_scratch *sp = vm->scratch_page; - - set_pages_wb(px_page(sp), 1); - - cleanup_px(vm->dev, sp); - kfree(sp); - - vm->scratch_page = NULL; -} - /* Broadwell Page Directory Pointer Descriptors */ static int gen8_write_pdp(struct drm_i915_gem_request *req, unsigned entry, @@ -2244,8 +2237,8 @@ static int ggtt_probe_common(struct drm_device *dev, size_t gtt_size) { struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_page_scratch *scratch_page; phys_addr_t gtt_phys_addr; - int ret; /* For Modern GENs the PTEs and register space are split in the BAR */ gtt_phys_addr = pci_resource_start(dev->pdev, 0) + @@ -2267,14 +2260,17 @@ static int ggtt_probe_common(struct drm_device *dev, return -ENOMEM; } - ret = alloc_scratch_page(&dev_priv->gtt.base); - if (ret) { + scratch_page = alloc_scratch_page(dev); + if (IS_ERR(scratch_page)) { DRM_ERROR("Scratch setup failed\n"); /* iounmap will also get called at remove, but meh */ iounmap(dev_priv->gtt.gsm); + return PTR_ERR(scratch_page); } - return ret; + dev_priv->gtt.base.scratch_page = scratch_page; + + return 0; } /* The GGTT and PPGTT need a private PPAT setup in order to handle cacheability @@ -2446,7 +2442,7 @@ static void gen6_gmch_remove(struct i915_address_space *vm) struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base); iounmap(gtt->gsm); - free_scratch_page(vm); + free_scratch_page(vm->dev, vm->scratch_page); } static int i915_gmch_probe(struct drm_device *dev, -- cgit v1.3-6-gb490 From ca1543be2c4233fbc266bf66f4320806e61e05dd Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 1 Jul 2015 11:51:10 +0100 Subject: drm/i915: Report correct GGTT space usage Currently only normal views were accounted which under-accounts the usage as reported in debugfs. Introduce new helper, i915_gem_obj_total_ggtt_size, and use it from call sites which want to know how much GGTT space are objects using. v2: Single loop in i915_gem_get_aperture_ioctl. (Chris Wilson) v3: Walk GGTT active/inactive lists in i915_gem_get_aperture_ioctl for better efficiency. (Chris Wilson, Daniel Vetter) v4: Make i915_gem_obj_total_ggtt_size private to debugfs. (Chris Wilson) v5: Change unsigned long to u64. (Chris Wilson) Signed-off-by: Tvrtko Ursulin Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 22 ++++++++++++++++++---- drivers/gpu/drm/i915/i915_gem.c | 13 ++++++++----- 2 files changed, 26 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 68a5e868f90b..6a8de04c6a2b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -117,6 +117,20 @@ static inline const char *get_global_flag(struct drm_i915_gem_object *obj) return i915_gem_obj_to_ggtt(obj) ? "g" : " "; } +static u64 i915_gem_obj_total_ggtt_size(struct drm_i915_gem_object *obj) +{ + u64 size = 0; + struct i915_vma *vma; + + list_for_each_entry(vma, &obj->vma_list, vma_link) { + if (i915_is_ggtt(vma->vm) && + drm_mm_node_allocated(&vma->node)) + size += vma->node.size; + } + + return size; +} + static void describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) { @@ -269,7 +283,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) list_add(&obj->obj_exec_link, &stolen); total_obj_size += obj->base.size; - total_gtt_size += i915_gem_obj_ggtt_size(obj); + total_gtt_size += i915_gem_obj_total_ggtt_size(obj); count++; } list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) { @@ -299,7 +313,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) #define count_objects(list, member) do { \ list_for_each_entry(obj, list, member) { \ - size += i915_gem_obj_ggtt_size(obj); \ + size += i915_gem_obj_total_ggtt_size(obj); \ ++count; \ if (obj->map_and_fenceable) { \ mappable_size += i915_gem_obj_ggtt_size(obj); \ @@ -405,7 +419,7 @@ static void print_batch_pool_stats(struct seq_file *m, #define count_vmas(list, member) do { \ list_for_each_entry(vma, list, member) { \ - size += i915_gem_obj_ggtt_size(vma->obj); \ + size += i915_gem_obj_total_ggtt_size(vma->obj); \ ++count; \ if (vma->obj->map_and_fenceable) { \ mappable_size += i915_gem_obj_ggtt_size(vma->obj); \ @@ -535,7 +549,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data) describe_obj(m, obj); seq_putc(m, '\n'); total_obj_size += obj->base.size; - total_gtt_size += i915_gem_obj_ggtt_size(obj); + total_gtt_size += i915_gem_obj_total_ggtt_size(obj); count++; } diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 37cd901c9d75..c8ee13f466c8 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -149,14 +149,18 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_get_aperture *args = data; - struct drm_i915_gem_object *obj; + struct i915_gtt *ggtt = &dev_priv->gtt; + struct i915_vma *vma; size_t pinned; pinned = 0; mutex_lock(&dev->struct_mutex); - list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) - if (i915_gem_obj_is_pinned(obj)) - pinned += i915_gem_obj_ggtt_size(obj); + list_for_each_entry(vma, &ggtt->base.active_list, mm_list) + if (vma->pin_count) + pinned += vma->node.size; + list_for_each_entry(vma, &ggtt->base.inactive_list, mm_list) + if (vma->pin_count) + pinned += vma->node.size; mutex_unlock(&dev->struct_mutex); args->aper_size = dev_priv->gtt.base.total; @@ -5468,4 +5472,3 @@ bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) return false; } - -- cgit v1.3-6-gb490 From ce65e47b78789b4f78be1fd7e4c884df74a9f075 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 30 Jun 2015 10:53:05 -0300 Subject: drm/i915: don't increment the FBC threshold at fbc_enable We first set the threshold value when we're allocating the CFB, and then later at {ilk,gen7}_fbc_enable() we increment it in case we're using 16bpp. While that is correct, it is dangerous: if we rework the code a little bit in a way that allows us to call intel_fbc_enable() without necessarily calling i915_gem_stolen_setup_compression() first, we might end up incrementing threshold more than once. To prevent that, increment a temporary variable instead. v2: Rebase. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 50ed3332def1..9e55b9badb4b 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -188,14 +188,15 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; + int threshold = dev_priv->fbc.threshold; dev_priv->fbc.enabled = true; dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane); if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) - dev_priv->fbc.threshold++; + threshold++; - switch (dev_priv->fbc.threshold) { + switch (threshold) { case 4: case 3: dpfc_ctl |= DPFC_CTL_LIMIT_4X; @@ -259,6 +260,7 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; + int threshold = dev_priv->fbc.threshold; dev_priv->fbc.enabled = true; @@ -267,9 +269,9 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) dpfc_ctl |= IVB_DPFC_CTL_PLANE(intel_crtc->plane); if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) - dev_priv->fbc.threshold++; + threshold++; - switch (dev_priv->fbc.threshold) { + switch (threshold) { case 4: case 3: dpfc_ctl |= DPFC_CTL_LIMIT_4X; -- cgit v1.3-6-gb490 From 260c1ad1993d3f17e25c5d848d6d2525ff38913c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 1 Jul 2015 15:58:50 +0300 Subject: drm/i915/dsi: abstract dsi bpp derivation from pixel format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nuke three copies of the same switch case. Hopefully we can switch to a drm generic function later on, but that will require us to swich to enum mipi_dsi_pixel_format first. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi_pll.c | 67 +++++++++++++----------------------- 1 file changed, 24 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index d20cf37b6901..49ae821e82d8 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -38,6 +38,27 @@ #define DSI_HFP_PACKET_EXTRA_SIZE 6 #define DSI_EOTP_PACKET_SIZE 4 +static int dsi_pixel_format_bpp(int pixel_format) +{ + int bpp; + + switch (pixel_format) { + default: + case VID_MODE_FORMAT_RGB888: + case VID_MODE_FORMAT_RGB666_LOOSE: + bpp = 24; + break; + case VID_MODE_FORMAT_RGB666: + bpp = 18; + break; + case VID_MODE_FORMAT_RGB565: + bpp = 16; + break; + } + + return bpp; +} + struct dsi_mnp { u32 dsi_pll_ctrl; u32 dsi_pll_div; @@ -65,19 +86,7 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode, u32 dsi_bit_clock_hz; u32 dsi_clk; - switch (pixel_format) { - default: - case VID_MODE_FORMAT_RGB888: - case VID_MODE_FORMAT_RGB666_LOOSE: - bpp = 24; - break; - case VID_MODE_FORMAT_RGB666: - bpp = 18; - break; - case VID_MODE_FORMAT_RGB565: - bpp = 16; - break; - } + bpp = dsi_pixel_format_bpp(pixel_format); hactive = mode->hdisplay; vactive = mode->vdisplay; @@ -137,21 +146,7 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode, static u32 dsi_clk_from_pclk(u32 pclk, int pixel_format, int lane_count) { u32 dsi_clk_khz; - u32 bpp; - - switch (pixel_format) { - default: - case VID_MODE_FORMAT_RGB888: - case VID_MODE_FORMAT_RGB666_LOOSE: - bpp = 24; - break; - case VID_MODE_FORMAT_RGB666: - bpp = 18; - break; - case VID_MODE_FORMAT_RGB565: - bpp = 16; - break; - } + u32 bpp = dsi_pixel_format_bpp(pixel_format); /* DSI data rate = pixel clock * bits per pixel / lane count pixel clock is converted from KHz to Hz */ @@ -286,21 +281,7 @@ void vlv_disable_dsi_pll(struct intel_encoder *encoder) static void assert_bpp_mismatch(int pixel_format, int pipe_bpp) { - int bpp; - - switch (pixel_format) { - default: - case VID_MODE_FORMAT_RGB888: - case VID_MODE_FORMAT_RGB666_LOOSE: - bpp = 24; - break; - case VID_MODE_FORMAT_RGB666: - bpp = 18; - break; - case VID_MODE_FORMAT_RGB565: - bpp = 16; - break; - } + int bpp = dsi_pixel_format_bpp(pixel_format); WARN(bpp != pipe_bpp, "bpp match assertion failure (expected %d, current %d)\n", -- cgit v1.3-6-gb490 From 3c5c6d88855baf9c3b9aa6243a37bb179f5a737e Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Wed, 1 Jul 2015 15:58:51 +0300 Subject: drm/i915: Support for higher DSI clk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For MIPI panels requiring higher DSI clk, values needs to be added in lfsr_converts table for getting the correct values of pll ctrl and dividor values which gets programmed in cck regs, otherwise DSI PLL does not get locked leading to no display on the MIPI panel. Signed-off-by: Gaurav K Singh Signed-off-by: Rodrigo Vivi Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi_pll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index 49ae821e82d8..be0c1e230c48 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -67,8 +67,8 @@ struct dsi_mnp { static const u32 lfsr_converts[] = { 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 62 - 70 */ 461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */ - 106, 53, 282, 397, 354, 227, 113, 56, 284, 142, /* 81 - 90 */ - 71, 35 /* 91 - 92 */ + 106, 53, 282, 397, 454, 227, 113, 56, 284, 142, /* 81 - 90 */ + 71, 35, 273, 136, 324, 418, 465, 488, 500, 506 /* 91 - 100 */ }; #ifdef DSI_CLK_FROM_RR -- cgit v1.3-6-gb490 From 20dbe1a1cbf3f1f0a6a07581e5b95ae027c9bea0 Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Wed, 1 Jul 2015 15:58:52 +0300 Subject: drm/i915: Changes required to enable DSI Video Mode on CHT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On CHT, changes are required for calculating the correct m,n & p with minimal error +/- for the required DSI clock, so that the correct dividor & ctrl values are written in cck regs for DSI. This patch has been tested on CHT RVP with 1200 x 1920 panel. v2 by Jani, rebased on earlier refactoring, original at [1]. [1] http://mid.gmane.org/1431368400-1942-5-git-send-email-rodrigo.vivi@intel.com Signed-off-by: Gaurav K Singh Signed-off-by: Rodrigo Vivi Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi_pll.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index be0c1e230c48..c6a8975b128f 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -157,11 +157,13 @@ static u32 dsi_clk_from_pclk(u32 pclk, int pixel_format, int lane_count) #endif -static int dsi_calc_mnp(int target_dsi_clk, struct dsi_mnp *dsi_mnp) +static int dsi_calc_mnp(struct drm_i915_private *dev_priv, + struct dsi_mnp *dsi_mnp, int target_dsi_clk) { unsigned int calc_m = 0, calc_p = 0; - unsigned int m, n = 1, p; - int ref_clk = 25000; + unsigned int m_min, m_max, p_min = 2, p_max = 6; + unsigned int m, n, p; + int ref_clk; int delta = target_dsi_clk; u32 m_seed; @@ -171,8 +173,20 @@ static int dsi_calc_mnp(int target_dsi_clk, struct dsi_mnp *dsi_mnp) return -ECHRNG; } - for (m = 62; m <= 92 && delta; m++) { - for (p = 2; p <= 6 && delta; p++) { + if (IS_CHERRYVIEW(dev_priv)) { + ref_clk = 100000; + n = 4; + m_min = 70; + m_max = 96; + } else { + ref_clk = 25000; + n = 1; + m_min = 62; + m_max = 92; + } + + for (m = m_min; m <= m_max && delta; m++) { + for (p = p_min; p <= p_max && delta; p++) { /* * Find the optimal m and p divisors with minimal delta * +/- the required clock @@ -212,7 +226,7 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder) dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format, intel_dsi->lane_count); - ret = dsi_calc_mnp(dsi_clk, &dsi_mnp); + ret = dsi_calc_mnp(dev_priv, &dsi_mnp, dsi_clk); if (ret) { DRM_DEBUG_KMS("dsi_calc_mnp failed\n"); return; -- cgit v1.3-6-gb490 From 8776f02b7c77f17dcf1dfab9954648874f264c89 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 30 Jun 2015 18:16:40 +0300 Subject: drm/i915/gtt: Per ppgtt scratch page Previously we have pointed the page where the individual ppgtt scratch structures refer to, to be the instance which GGTT setup have allocated. So it has been shared. To achieve full isolation between ppgtts also in this regard, allocate per ppgtt scratch page. Cc: Michel Thierry Cc: Daniel Vetter Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 94 +++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a4ec1c6f5652..ed65f24867b4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -678,6 +678,42 @@ static void gen8_free_page_tables(struct drm_device *dev, } } +static int gen8_init_scratch(struct i915_address_space *vm) +{ + struct drm_device *dev = vm->dev; + + vm->scratch_page = alloc_scratch_page(dev); + if (IS_ERR(vm->scratch_page)) + return PTR_ERR(vm->scratch_page); + + vm->scratch_pt = alloc_pt(dev); + if (IS_ERR(vm->scratch_pt)) { + free_scratch_page(dev, vm->scratch_page); + return PTR_ERR(vm->scratch_pt); + } + + vm->scratch_pd = alloc_pd(dev); + if (IS_ERR(vm->scratch_pd)) { + free_pt(dev, vm->scratch_pt); + free_scratch_page(dev, vm->scratch_page); + return PTR_ERR(vm->scratch_pd); + } + + gen8_initialize_pt(vm, vm->scratch_pt); + gen8_initialize_pd(vm, vm->scratch_pd); + + return 0; +} + +static void gen8_free_scratch(struct i915_address_space *vm) +{ + struct drm_device *dev = vm->dev; + + free_pd(dev, vm->scratch_pd); + free_pt(dev, vm->scratch_pt); + free_scratch_page(dev, vm->scratch_page); +} + static void gen8_ppgtt_cleanup(struct i915_address_space *vm) { struct i915_hw_ppgtt *ppgtt = @@ -693,8 +729,7 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) free_pd(ppgtt->base.dev, ppgtt->pdp.page_directory[i]); } - free_pd(vm->dev, vm->scratch_pd); - free_pt(vm->dev, vm->scratch_pt); + gen8_free_scratch(vm); } /** @@ -981,16 +1016,11 @@ err_out: */ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) { - ppgtt->base.scratch_pt = alloc_pt(ppgtt->base.dev); - if (IS_ERR(ppgtt->base.scratch_pt)) - return PTR_ERR(ppgtt->base.scratch_pt); - - ppgtt->base.scratch_pd = alloc_pd(ppgtt->base.dev); - if (IS_ERR(ppgtt->base.scratch_pd)) - return PTR_ERR(ppgtt->base.scratch_pd); + int ret; - gen8_initialize_pt(&ppgtt->base, ppgtt->base.scratch_pt); - gen8_initialize_pd(&ppgtt->base, ppgtt->base.scratch_pd); + ret = gen8_init_scratch(&ppgtt->base); + if (ret) + return ret; ppgtt->base.start = 0; ppgtt->base.total = 1ULL << 32; @@ -1406,6 +1436,33 @@ unwind_out: return ret; } +static int gen6_init_scratch(struct i915_address_space *vm) +{ + struct drm_device *dev = vm->dev; + + vm->scratch_page = alloc_scratch_page(dev); + if (IS_ERR(vm->scratch_page)) + return PTR_ERR(vm->scratch_page); + + vm->scratch_pt = alloc_pt(dev); + if (IS_ERR(vm->scratch_pt)) { + free_scratch_page(dev, vm->scratch_page); + return PTR_ERR(vm->scratch_pt); + } + + gen6_initialize_pt(vm, vm->scratch_pt); + + return 0; +} + +static void gen6_free_scratch(struct i915_address_space *vm) +{ + struct drm_device *dev = vm->dev; + + free_pt(dev, vm->scratch_pt); + free_scratch_page(dev, vm->scratch_page); +} + static void gen6_ppgtt_cleanup(struct i915_address_space *vm) { struct i915_hw_ppgtt *ppgtt = @@ -1420,11 +1477,12 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) free_pt(ppgtt->base.dev, pt); } - free_pt(vm->dev, vm->scratch_pt); + gen6_free_scratch(vm); } static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) { + struct i915_address_space *vm = &ppgtt->base; struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; bool retried = false; @@ -1435,11 +1493,10 @@ static int gen6_ppgtt_allocate_page_directories(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)); - ppgtt->base.scratch_pt = alloc_pt(ppgtt->base.dev); - if (IS_ERR(ppgtt->base.scratch_pt)) - return PTR_ERR(ppgtt->base.scratch_pt); - gen6_initialize_pt(&ppgtt->base, ppgtt->base.scratch_pt); + ret = gen6_init_scratch(vm); + if (ret) + return ret; alloc: ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm, @@ -1470,7 +1527,7 @@ alloc: return 0; err_out: - free_pt(ppgtt->base.dev, ppgtt->base.scratch_pt); + gen6_free_scratch(vm); return ret; } @@ -1544,10 +1601,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) { - struct drm_i915_private *dev_priv = dev->dev_private; - ppgtt->base.dev = dev; - ppgtt->base.scratch_page = dev_priv->gtt.base.scratch_page; if (INTEL_INFO(dev)->gen < 8) return gen6_ppgtt_init(ppgtt); -- cgit v1.3-6-gb490 From ce14ec20a1ffcd356f578036617d657be8429c00 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 2 Jul 2015 15:16:39 +0200 Subject: drm/crtc-helper: Fixup error handling in drm_helper_crtc_mode_set In commit 9f658b7b62e7aefc1ee067136126eca3f58cabfd Author: Daniel Stone Date: Fri May 22 13:34:45 2015 +0100 drm/crtc_helper: Replace open-coded CRTC state helpers error handling code was broken, resulting in the first path not being checked correctly. Fix this by using the same pattern as in the transitional plane helper function drm_plane_helper_update. v2: Simplify the cleanup code while at it too. v3: After some debugging with John we realized that the above patch from Daniel also accidentally removed the if (crtc_state) check. This is legal when transitioning to atomic, when the initial state reset isn't all wired up yet properly. Reinstate that check to fix the bug John has hit. Cc: Daniel Stone CC: Sean Paul Cc: John Hunter Signed-off-by: Daniel Vetter Reviewed-by: Daniel Stone Reported-and-tested-by: John Hunter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc_helper.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 393114df88a3..93104f3555f5 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -927,15 +927,13 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod if (crtc->funcs->atomic_duplicate_state) crtc_state = crtc->funcs->atomic_duplicate_state(crtc); - else { + else if (crtc->state) + crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc); + else crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL); - if (!crtc_state) - return -ENOMEM; - if (crtc->state) - __drm_atomic_helper_crtc_duplicate_state(crtc, crtc_state); - else - crtc_state->crtc = crtc; - } + + if (!crtc_state) + return -ENOMEM; crtc_state->planes_changed = true; crtc_state->mode_changed = true; @@ -957,11 +955,11 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod ret = drm_helper_crtc_mode_set_base(crtc, x, y, old_fb); out: - if (crtc->funcs->atomic_destroy_state) - crtc->funcs->atomic_destroy_state(crtc, crtc_state); - else { - __drm_atomic_helper_crtc_destroy_state(crtc, crtc_state); - kfree(crtc_state); + if (crtc_state) { + if (crtc->funcs->atomic_destroy_state) + crtc->funcs->atomic_destroy_state(crtc, crtc_state); + else + drm_atomic_helper_crtc_destroy_state(crtc, crtc_state); } return ret; -- cgit v1.3-6-gb490 From e4f31ad2b7138db449310c9b63d402a29dc0e1c9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 2 Jul 2015 16:33:53 +0200 Subject: drm: reset empty state in transitional helpers Transitional drivers might not have all the state frobbing lined up yet. But since the initial code has been merged a lot more state was added, so we really need this. Cc: Daniel Stone Signed-off-by: Daniel Vetter Reviewed-by: Daniel Stone Reported-and-tested-by: John Hunter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc_helper.c | 8 +++++--- drivers/gpu/drm/drm_plane_helper.c | 16 ++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 93104f3555f5..d3dfb0ebbeb2 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -927,10 +927,12 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod if (crtc->funcs->atomic_duplicate_state) crtc_state = crtc->funcs->atomic_duplicate_state(crtc); - else if (crtc->state) + else { + if (!crtc->state) + drm_atomic_helper_crtc_reset(crtc); + crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc); - else - crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL); + } if (!crtc_state) return -ENOMEM; diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 2f0ed11024eb..b07a213f5655 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -525,10 +525,12 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, if (plane->funcs->atomic_duplicate_state) plane_state = plane->funcs->atomic_duplicate_state(plane); - else if (plane->state) + else { + if (!plane->state) + drm_atomic_helper_plane_reset(plane); + plane_state = drm_atomic_helper_plane_duplicate_state(plane); - else - plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); + } if (!plane_state) return -ENOMEM; plane_state->plane = plane; @@ -572,10 +574,12 @@ int drm_plane_helper_disable(struct drm_plane *plane) if (plane->funcs->atomic_duplicate_state) plane_state = plane->funcs->atomic_duplicate_state(plane); - else if (plane->state) + else { + if (!plane->state) + drm_atomic_helper_plane_reset(plane); + plane_state = drm_atomic_helper_plane_duplicate_state(plane); - else - plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); + } if (!plane_state) return -ENOMEM; plane_state->plane = plane; -- cgit v1.3-6-gb490 From 1f96beec7a44f46bf277e2050a7a5a0308831d61 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 3 Jul 2015 14:17:29 +0300 Subject: drm: remove redundant code form drm_ioc32.c The compat ioctl handler ends up calling access_ok() twice: first indirectly inside compat_alloc_user_space() and then after returning from that function. This patch fixes issue. v2: there were three invalid removals of access_ok() that I've fixed. Also went through all the changes couple of times and verified that access_ok() is only removed when the buffer is allocated with compat_alloc_user_space(). My deepest apologies for this kind of sloppiness! Signed-off-by: Jarkko Sakkinen Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_ioc32.c | 55 +++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index aa8bbb460c57..8dcfa76b09e6 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -93,7 +93,7 @@ static int compat_drm_version(struct file *file, unsigned int cmd, return -EFAULT; version = compat_alloc_user_space(sizeof(*version)); - if (!access_ok(VERIFY_WRITE, version, sizeof(*version))) + if (!version) return -EFAULT; if (__put_user(v32.name_len, &version->name_len) || __put_user((void __user *)(unsigned long)v32.name, @@ -140,7 +140,7 @@ static int compat_drm_getunique(struct file *file, unsigned int cmd, return -EFAULT; u = compat_alloc_user_space(sizeof(*u)); - if (!access_ok(VERIFY_WRITE, u, sizeof(*u))) + if (!u) return -EFAULT; if (__put_user(uq32.unique_len, &u->unique_len) || __put_user((void __user *)(unsigned long)uq32.unique, @@ -168,7 +168,7 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd, return -EFAULT; u = compat_alloc_user_space(sizeof(*u)); - if (!access_ok(VERIFY_WRITE, u, sizeof(*u))) + if (!u) return -EFAULT; if (__put_user(uq32.unique_len, &u->unique_len) || __put_user((void __user *)(unsigned long)uq32.unique, @@ -200,7 +200,7 @@ static int compat_drm_getmap(struct file *file, unsigned int cmd, return -EFAULT; map = compat_alloc_user_space(sizeof(*map)); - if (!access_ok(VERIFY_WRITE, map, sizeof(*map))) + if (!map) return -EFAULT; if (__put_user(idx, &map->offset)) return -EFAULT; @@ -237,7 +237,7 @@ static int compat_drm_addmap(struct file *file, unsigned int cmd, return -EFAULT; map = compat_alloc_user_space(sizeof(*map)); - if (!access_ok(VERIFY_WRITE, map, sizeof(*map))) + if (!map) return -EFAULT; if (__put_user(m32.offset, &map->offset) || __put_user(m32.size, &map->size) @@ -277,7 +277,7 @@ static int compat_drm_rmmap(struct file *file, unsigned int cmd, return -EFAULT; map = compat_alloc_user_space(sizeof(*map)); - if (!access_ok(VERIFY_WRITE, map, sizeof(*map))) + if (!map) return -EFAULT; if (__put_user((void *)(unsigned long)handle, &map->handle)) return -EFAULT; @@ -306,7 +306,7 @@ static int compat_drm_getclient(struct file *file, unsigned int cmd, return -EFAULT; client = compat_alloc_user_space(sizeof(*client)); - if (!access_ok(VERIFY_WRITE, client, sizeof(*client))) + if (!client) return -EFAULT; if (__put_user(idx, &client->idx)) return -EFAULT; @@ -345,7 +345,7 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd, int i, err; stats = compat_alloc_user_space(sizeof(*stats)); - if (!access_ok(VERIFY_WRITE, stats, sizeof(*stats))) + if (!stats) return -EFAULT; err = drm_ioctl(file, DRM_IOCTL_GET_STATS, (unsigned long)stats); @@ -382,8 +382,7 @@ static int compat_drm_addbufs(struct file *file, unsigned int cmd, unsigned long agp_start; buf = compat_alloc_user_space(sizeof(*buf)); - if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf)) - || !access_ok(VERIFY_WRITE, argp, sizeof(*argp))) + if (!buf || !access_ok(VERIFY_WRITE, argp, sizeof(*argp))) return -EFAULT; if (__copy_in_user(buf, argp, offsetof(drm_buf_desc32_t, agp_start)) @@ -414,7 +413,7 @@ static int compat_drm_markbufs(struct file *file, unsigned int cmd, return -EFAULT; buf = compat_alloc_user_space(sizeof(*buf)); - if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf))) + if (!buf) return -EFAULT; if (__put_user(b32.size, &buf->size) @@ -455,7 +454,7 @@ static int compat_drm_infobufs(struct file *file, unsigned int cmd, nbytes = sizeof(*request) + count * sizeof(struct drm_buf_desc); request = compat_alloc_user_space(nbytes); - if (!access_ok(VERIFY_WRITE, request, nbytes)) + if (!request) return -EFAULT; list = (struct drm_buf_desc *) (request + 1); @@ -516,7 +515,7 @@ static int compat_drm_mapbufs(struct file *file, unsigned int cmd, return -EINVAL; nbytes = sizeof(*request) + count * sizeof(struct drm_buf_pub); request = compat_alloc_user_space(nbytes); - if (!access_ok(VERIFY_WRITE, request, nbytes)) + if (!request) return -EFAULT; list = (struct drm_buf_pub *) (request + 1); @@ -563,7 +562,7 @@ static int compat_drm_freebufs(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request))) + if (!request) return -EFAULT; if (__put_user(req32.count, &request->count) || __put_user((int __user *)(unsigned long)req32.list, @@ -589,7 +588,7 @@ static int compat_drm_setsareactx(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request))) + if (!request) return -EFAULT; if (__put_user(req32.ctx_id, &request->ctx_id) || __put_user((void *)(unsigned long)req32.handle, @@ -613,7 +612,7 @@ static int compat_drm_getsareactx(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request))) + if (!request) return -EFAULT; if (__put_user(ctx_id, &request->ctx_id)) return -EFAULT; @@ -646,7 +645,7 @@ static int compat_drm_resctx(struct file *file, unsigned int cmd, return -EFAULT; res = compat_alloc_user_space(sizeof(*res)); - if (!access_ok(VERIFY_WRITE, res, sizeof(*res))) + if (!res) return -EFAULT; if (__put_user(res32.count, &res->count) || __put_user((struct drm_ctx __user *) (unsigned long)res32.contexts, @@ -689,7 +688,7 @@ static int compat_drm_dma(struct file *file, unsigned int cmd, return -EFAULT; d = compat_alloc_user_space(sizeof(*d)); - if (!access_ok(VERIFY_WRITE, d, sizeof(*d))) + if (!d) return -EFAULT; if (__put_user(d32.context, &d->context) @@ -764,7 +763,7 @@ static int compat_drm_agp_info(struct file *file, unsigned int cmd, int err; info = compat_alloc_user_space(sizeof(*info)); - if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) + if (!info) return -EFAULT; err = drm_ioctl(file, DRM_IOCTL_AGP_INFO, (unsigned long)info); @@ -807,7 +806,7 @@ static int compat_drm_agp_alloc(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + if (!request || __put_user(req32.size, &request->size) || __put_user(req32.type, &request->type)) return -EFAULT; @@ -834,7 +833,7 @@ static int compat_drm_agp_free(struct file *file, unsigned int cmd, u32 handle; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + if (!request || get_user(handle, &argp->handle) || __put_user(handle, &request->handle)) return -EFAULT; @@ -858,7 +857,7 @@ static int compat_drm_agp_bind(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + if (!request || __put_user(req32.handle, &request->handle) || __put_user(req32.offset, &request->offset)) return -EFAULT; @@ -874,7 +873,7 @@ static int compat_drm_agp_unbind(struct file *file, unsigned int cmd, u32 handle; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + if (!request || get_user(handle, &argp->handle) || __put_user(handle, &request->handle)) return -EFAULT; @@ -897,8 +896,7 @@ static int compat_drm_sg_alloc(struct file *file, unsigned int cmd, unsigned long x; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)) + if (!request || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)) || __get_user(x, &argp->size) || __put_user(x, &request->size)) return -EFAULT; @@ -923,8 +921,7 @@ static int compat_drm_sg_free(struct file *file, unsigned int cmd, unsigned long x; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)) + if (!request || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)) || __get_user(x, &argp->handle) || __put_user(x << PAGE_SHIFT, &request->handle)) return -EFAULT; @@ -952,7 +949,7 @@ static int compat_drm_update_draw(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) || + if (!request || __put_user(update32.handle, &request->handle) || __put_user(update32.type, &request->type) || __put_user(update32.num, &request->num) || @@ -994,7 +991,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + if (!request || __put_user(req32.request.type, &request->request.type) || __put_user(req32.request.sequence, &request->request.sequence) || __put_user(req32.request.signal, &request->request.signal)) -- cgit v1.3-6-gb490 From 5d4db691ed978080435f4e5aad2ce707294a75b4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Jun 2015 15:04:28 +0200 Subject: spi: rspi: Drop variable "error" in qspi_trigger_transfer_out_in() Just use "ret" instead, for consistency with other similar functions. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index f9189a0c8cec..9a71fa2e53a9 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -725,24 +725,23 @@ static int qspi_trigger_transfer_out_in(struct rspi_data *rspi, const u8 *tx, u8 *rx, unsigned int len) { int i, n, ret; - int error; while (len > 0) { n = qspi_set_send_trigger(rspi, len); qspi_set_receive_trigger(rspi, len); if (n == QSPI_BUFFER_SIZE) { - error = rspi_wait_for_tx_empty(rspi); - if (error < 0) { + ret = rspi_wait_for_tx_empty(rspi); + if (ret < 0) { dev_err(&rspi->master->dev, "transmit timeout\n"); - return error; + return ret; } for (i = 0; i < n; i++) rspi_write_data(rspi, *tx++); - error = rspi_wait_for_rx_full(rspi); - if (error < 0) { + ret = rspi_wait_for_rx_full(rspi); + if (ret < 0) { dev_err(&rspi->master->dev, "receive timeout\n"); - return error; + return ret; } for (i = 0; i < n; i++) *rx++ = rspi_read_data(rspi); -- cgit v1.3-6-gb490 From cb76b1ca9174aa29d4c7c0f4aef113be203b600c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Jun 2015 15:04:29 +0200 Subject: spi: rspi: Make qspi_set_send_trigger() return "unsigned int" qspi_set_send_trigger() returns an unsigned value, so make it return "unsigned int". Update the loop variables qspi_trigger_transfer_out_int() to match the above. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 9a71fa2e53a9..818843336932 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -383,7 +383,8 @@ static void qspi_update(const struct rspi_data *rspi, u8 mask, u8 val, u8 reg) rspi_write8(rspi, data, reg); } -static int qspi_set_send_trigger(struct rspi_data *rspi, unsigned int len) +static unsigned int qspi_set_send_trigger(struct rspi_data *rspi, + unsigned int len) { unsigned int n; @@ -724,7 +725,8 @@ static int rspi_rz_transfer_one(struct spi_master *master, static int qspi_trigger_transfer_out_in(struct rspi_data *rspi, const u8 *tx, u8 *rx, unsigned int len) { - int i, n, ret; + unsigned int i, n; + int ret; while (len > 0) { n = qspi_set_send_trigger(rspi, len); -- cgit v1.3-6-gb490 From a3d1d001c9c583c79b1d9ab20f0a24333e35a3f8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 3 Jul 2015 15:53:23 +0200 Subject: drm/i915: Update DRIVER_DATE to 20150703 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1dbd95710bf4..950a9811a16f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -56,7 +56,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20150619" +#define DRIVER_DATE "20150703" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ -- cgit v1.3-6-gb490 From 4acaf96f747d0cfd6030bde362c1189d248dacff Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 23 Jun 2015 22:52:28 +0800 Subject: iio: ssp_sensors: Remove redundant spi driver bus initialization In ancient times it was necessary to manually initialize the bus field of an spi_driver to spi_bus_type. These days this is done in spi_register_driver(), so we can drop the manual assignment. Signed-off-by: Antonio Borneo To: Jonathan Cameron To: Lars-Peter Clausen To: Karol Wrona To: linux-iio@vger.kernel.org Cc: linux-kernel@vger.kernel.org Acked-by: Karol Wrona Signed-off-by: Jonathan Cameron --- drivers/iio/common/ssp_sensors/ssp_dev.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c index 9a40097e7cf8..d338bb595db3 100644 --- a/drivers/iio/common/ssp_sensors/ssp_dev.c +++ b/drivers/iio/common/ssp_sensors/ssp_dev.c @@ -700,7 +700,6 @@ static struct spi_driver ssp_driver = { .remove = ssp_remove, .driver = { .pm = &ssp_pm_ops, - .bus = &spi_bus_type, .owner = THIS_MODULE, .of_match_table = of_match_ptr(ssp_of_match), .name = "sensorhub" -- cgit v1.3-6-gb490 From 57f7d509c8f60e66d69ac216a03ef39c5ea1ddb8 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sun, 21 Jun 2015 23:50:22 +0200 Subject: iio: tmp006: Use GENMASK Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/tmp006.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index fcc49f89b946..ecdb6191951e 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -36,9 +36,9 @@ #define TMP006_CONFIG_DRDY_EN BIT(8) #define TMP006_CONFIG_DRDY BIT(7) -#define TMP006_CONFIG_MOD_MASK 0x7000 +#define TMP006_CONFIG_MOD_MASK GENMASK(14, 12) -#define TMP006_CONFIG_CR_MASK 0x0e00 +#define TMP006_CONFIG_CR_MASK GENMASK(11, 9) #define TMP006_CONFIG_CR_SHIFT 9 #define TMP006_MANUFACTURER_MAGIC 0x5449 -- cgit v1.3-6-gb490 From 7cb46c2a0666547493132327ccfc0698d90e52f7 Mon Sep 17 00:00:00 2001 From: Tomasz Duszynski Date: Tue, 23 Jun 2015 20:45:47 +0200 Subject: iio: pressure: ms5611: remove IIO_CHAN_INFO_SCALE from mask IIO_CHAN_INFO_SCALE is useful whenever conversion to standard units is done in userspace. In this case conversion is handled by driver so this bit is unnecessary. Signed-off-by: Tomasz Duszynski Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/ms5611_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index e42c8531d9b3..1109513cdda9 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -163,13 +163,11 @@ static int ms5611_read_raw(struct iio_dev *indio_dev, static const struct iio_chan_spec ms5611_channels[] = { { .type = IIO_PRESSURE, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | - BIT(IIO_CHAN_INFO_SCALE) + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }, { .type = IIO_TEMP, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | - BIT(IIO_CHAN_INFO_SCALE) + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), } }; -- cgit v1.3-6-gb490 From 9690d81a02dc4eea78de1686c3bf23a8dd4c0f28 Mon Sep 17 00:00:00 2001 From: Tomasz Duszynski Date: Tue, 23 Jun 2015 20:45:48 +0200 Subject: iio: pressure: ms5611: add support for MS5607 temperature and pressure sensor MS5607 is temperature and pressure sensor which hardware is similar to MS5611. Both sensors share command protocol and support both I2C and SPI serial protocols. They only differ in compensation algorithms. Signed-off-by: Tomasz Duszynski Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/Kconfig | 2 +- drivers/iio/pressure/ms5611.h | 16 +++++++- drivers/iio/pressure/ms5611_core.c | 76 +++++++++++++++++++++++++++++++++----- drivers/iio/pressure/ms5611_i2c.c | 5 ++- drivers/iio/pressure/ms5611_spi.c | 6 ++- 5 files changed, 88 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index b13ea6fd939d..4745179ff64b 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -56,7 +56,7 @@ config MS5611 tristate "Measurement Specialties MS5611 pressure sensor driver" help Say Y here to build support for the Measurement Specialties - MS5611 pressure and temperature sensor. + MS5611, MS5607 pressure and temperature sensors. To compile this driver as a module, choose M here: the module will be called ms5611_core. diff --git a/drivers/iio/pressure/ms5611.h b/drivers/iio/pressure/ms5611.h index 099c6cdea43f..23b93c797dba 100644 --- a/drivers/iio/pressure/ms5611.h +++ b/drivers/iio/pressure/ms5611.h @@ -27,6 +27,18 @@ #define MS5611_PROM_WORDS_NB 8 +enum { + MS5611, + MS5607, +}; + +struct ms5611_chip_info { + u16 prom[MS5611_PROM_WORDS_NB]; + + int (*temp_and_pressure_compensate)(struct ms5611_chip_info *chip_info, + s32 *temp, s32 *pressure); +}; + struct ms5611_state { void *client; struct mutex lock; @@ -36,9 +48,9 @@ struct ms5611_state { int (*read_adc_temp_and_pressure)(struct device *dev, s32 *temp, s32 *pressure); - u16 prom[MS5611_PROM_WORDS_NB]; + struct ms5611_chip_info *chip_info; }; -int ms5611_probe(struct iio_dev *indio_dev, struct device *dev); +int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, int type); #endif /* _MS5611_H */ diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index 1109513cdda9..2f3d9b4aca4e 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -9,6 +9,7 @@ * * Data sheet: * http://www.meas-spec.com/downloads/MS5611-01BA03.pdf + * http://www.meas-spec.com/downloads/MS5607-02BA03.pdf * */ @@ -50,7 +51,8 @@ static int ms5611_read_prom(struct iio_dev *indio_dev) struct ms5611_state *st = iio_priv(indio_dev); for (i = 0; i < MS5611_PROM_WORDS_NB; i++) { - ret = st->read_prom_word(&indio_dev->dev, i, &st->prom[i]); + ret = st->read_prom_word(&indio_dev->dev, + i, &st->chip_info->prom[i]); if (ret < 0) { dev_err(&indio_dev->dev, "failed to read prom at %d\n", i); @@ -58,7 +60,7 @@ static int ms5611_read_prom(struct iio_dev *indio_dev) } } - if (!ms5611_prom_is_valid(st->prom, MS5611_PROM_WORDS_NB)) { + if (!ms5611_prom_is_valid(st->chip_info->prom, MS5611_PROM_WORDS_NB)) { dev_err(&indio_dev->dev, "PROM integrity check failed\n"); return -ENODEV; } @@ -70,22 +72,30 @@ static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev, s32 *temp, s32 *pressure) { int ret; - s32 t, p; - s64 off, sens, dt; struct ms5611_state *st = iio_priv(indio_dev); - ret = st->read_adc_temp_and_pressure(&indio_dev->dev, &t, &p); + ret = st->read_adc_temp_and_pressure(&indio_dev->dev, temp, pressure); if (ret < 0) { dev_err(&indio_dev->dev, "failed to read temperature and pressure\n"); return ret; } - dt = t - (st->prom[5] << 8); - off = ((s64)st->prom[2] << 16) + ((st->prom[4] * dt) >> 7); - sens = ((s64)st->prom[1] << 15) + ((st->prom[3] * dt) >> 8); + return st->chip_info->temp_and_pressure_compensate(st->chip_info, + temp, pressure); +} + +static int ms5611_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info, + s32 *temp, s32 *pressure) +{ + s32 t = *temp, p = *pressure; + s64 off, sens, dt; - t = 2000 + ((st->prom[6] * dt) >> 23); + dt = t - (chip_info->prom[5] << 8); + off = ((s64)chip_info->prom[2] << 16) + ((chip_info->prom[4] * dt) >> 7); + sens = ((s64)chip_info->prom[1] << 15) + ((chip_info->prom[3] * dt) >> 8); + + t = 2000 + ((chip_info->prom[6] * dt) >> 23); if (t < 2000) { s64 off2, sens2, t2; @@ -111,6 +121,42 @@ static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev, return 0; } +static int ms5607_temp_and_pressure_compensate(struct ms5611_chip_info *chip_info, + s32 *temp, s32 *pressure) +{ + s32 t = *temp, p = *pressure; + s64 off, sens, dt; + + dt = t - (chip_info->prom[5] << 8); + off = ((s64)chip_info->prom[2] << 17) + ((chip_info->prom[4] * dt) >> 6); + sens = ((s64)chip_info->prom[1] << 16) + ((chip_info->prom[3] * dt) >> 7); + + t = 2000 + ((chip_info->prom[6] * dt) >> 23); + if (t < 2000) { + s64 off2, sens2, t2; + + t2 = (dt * dt) >> 31; + off2 = (61 * (t - 2000) * (t - 2000)) >> 4; + sens2 = off2 << 1; + + if (t < -1500) { + s64 tmp = (t + 1500) * (t + 1500); + + off2 += 15 * tmp; + sens2 += (8 * tmp); + } + + t -= t2; + off -= off2; + sens -= sens2; + } + + *temp = t; + *pressure = (((p * sens) >> 21) - off) >> 15; + + return 0; +} + static int ms5611_reset(struct iio_dev *indio_dev) { int ret; @@ -160,6 +206,15 @@ static int ms5611_read_raw(struct iio_dev *indio_dev, return -EINVAL; } +static struct ms5611_chip_info chip_info_tbl[] = { + [MS5611] = { + .temp_and_pressure_compensate = ms5611_temp_and_pressure_compensate, + }, + [MS5607] = { + .temp_and_pressure_compensate = ms5607_temp_and_pressure_compensate, + } +}; + static const struct iio_chan_spec ms5611_channels[] = { { .type = IIO_PRESSURE, @@ -187,12 +242,13 @@ static int ms5611_init(struct iio_dev *indio_dev) return ms5611_read_prom(indio_dev); } -int ms5611_probe(struct iio_dev *indio_dev, struct device *dev) +int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, int type) { int ret; struct ms5611_state *st = iio_priv(indio_dev); mutex_init(&st->lock); + st->chip_info = &chip_info_tbl[type]; indio_dev->dev.parent = dev; indio_dev->name = dev->driver->name; indio_dev->info = &ms5611_info; diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c index 748fd9acaad8..9d504f17669b 100644 --- a/drivers/iio/pressure/ms5611_i2c.c +++ b/drivers/iio/pressure/ms5611_i2c.c @@ -104,11 +104,12 @@ static int ms5611_i2c_probe(struct i2c_client *client, st->read_adc_temp_and_pressure = ms5611_i2c_read_adc_temp_and_pressure; st->client = client; - return ms5611_probe(indio_dev, &client->dev); + return ms5611_probe(indio_dev, &client->dev, id->driver_data); } static const struct i2c_device_id ms5611_id[] = { - { "ms5611", 0 }, + { "ms5611", MS5611 }, + { "ms5607", MS5607 }, { } }; MODULE_DEVICE_TABLE(i2c, ms5611_id); diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c index 976726fd4e6c..08ee6e88c79f 100644 --- a/drivers/iio/pressure/ms5611_spi.c +++ b/drivers/iio/pressure/ms5611_spi.c @@ -103,11 +103,13 @@ static int ms5611_spi_probe(struct spi_device *spi) st->read_adc_temp_and_pressure = ms5611_spi_read_adc_temp_and_pressure; st->client = spi; - return ms5611_probe(indio_dev, &spi->dev); + return ms5611_probe(indio_dev, &spi->dev, + spi_get_device_id(spi)->driver_data); } static const struct spi_device_id ms5611_id[] = { - { "ms5611", 0 }, + { "ms5611", MS5611 }, + { "ms5607", MS5607 }, { } }; MODULE_DEVICE_TABLE(spi, ms5611_id); -- cgit v1.3-6-gb490 From db6a19b8251f089afcd40ed116ffdc2326f704a8 Mon Sep 17 00:00:00 2001 From: Tiberiu Breana Date: Wed, 24 Jun 2015 16:54:46 +0300 Subject: iio: accel: Add trigger support for STK8BA50 Add data-ready interrupts and trigger support for STK8BA50. Additional changes: - read_accel now returns raw acceleration data instead of the sign_extend32 value - read_raw will now enable/disable the sensor with each reading Change-Id: I9c2d7be4256b2dcc5546e4432308ea54f8004333 Signed-off-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8ba50.c | 296 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 271 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 9836880cc2d1..16cee637109b 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -11,11 +11,17 @@ */ #include +#include #include +#include #include #include +#include #include #include +#include +#include +#include #define STK8BA50_REG_XOUT 0x02 #define STK8BA50_REG_YOUT 0x04 @@ -24,6 +30,8 @@ #define STK8BA50_REG_BWSEL 0x10 #define STK8BA50_REG_POWMODE 0x11 #define STK8BA50_REG_SWRST 0x14 +#define STK8BA50_REG_INTEN2 0x17 +#define STK8BA50_REG_INTMAP2 0x1A #define STK8BA50_MODE_NORMAL 0 #define STK8BA50_MODE_SUSPEND 1 @@ -31,8 +39,14 @@ #define STK8BA50_DATA_SHIFT 6 #define STK8BA50_RESET_CMD 0xB6 #define STK8BA50_SR_1792HZ_IDX 7 +#define STK8BA50_DREADY_INT_MASK 0x10 +#define STK8BA50_DREADY_INT_MAP 0x81 +#define STK8BA50_ALL_CHANNEL_MASK 7 +#define STK8BA50_ALL_CHANNEL_SIZE 6 #define STK8BA50_DRIVER_NAME "stk8ba50" +#define STK8BA50_GPIO "stk8ba50_gpio" +#define STK8BA50_IRQ_NAME "stk8ba50_event" #define STK8BA50_SCALE_AVAIL "0.0384 0.0767 0.1534 0.3069" @@ -68,14 +82,29 @@ static const struct { {0x0C, 224}, {0x0D, 448}, {0x0E, 896}, {0x0F, 1792} }; +/* Used to map scan mask bits to their corresponding channel register. */ +static const int stk8ba50_channel_table[] = { + STK8BA50_REG_XOUT, + STK8BA50_REG_YOUT, + STK8BA50_REG_ZOUT +}; + struct stk8ba50_data { struct i2c_client *client; struct mutex lock; int range; u8 sample_rate_idx; + struct iio_trigger *dready_trig; + bool dready_trigger_on; + /* + * 3 x 16-bit channels (10-bit data, 6-bit padding) + + * 1 x 16 padding + + * 4 x 16 64-bit timestamp + */ + s16 buffer[8]; }; -#define STK8BA50_ACCEL_CHANNEL(reg, axis) { \ +#define STK8BA50_ACCEL_CHANNEL(index, reg, axis) { \ .type = IIO_ACCEL, \ .address = reg, \ .modified = 1, \ @@ -83,12 +112,21 @@ struct stk8ba50_data { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 10, \ + .storagebits = 16, \ + .shift = STK8BA50_DATA_SHIFT, \ + .endianness = IIO_CPU, \ + }, \ } static const struct iio_chan_spec stk8ba50_channels[] = { - STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_XOUT, X), - STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_YOUT, Y), - STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_ZOUT, Z), + STK8BA50_ACCEL_CHANNEL(0, STK8BA50_REG_XOUT, X), + STK8BA50_ACCEL_CHANNEL(1, STK8BA50_REG_YOUT, Y), + STK8BA50_ACCEL_CHANNEL(2, STK8BA50_REG_ZOUT, Z), + IIO_CHAN_SOFT_TIMESTAMP(3), }; static IIO_CONST_ATTR(in_accel_scale_available, STK8BA50_SCALE_AVAIL); @@ -116,7 +154,61 @@ static int stk8ba50_read_accel(struct stk8ba50_data *data, u8 reg) return ret; } - return sign_extend32(ret >> STK8BA50_DATA_SHIFT, 9); + return ret; +} + +static int stk8ba50_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct stk8ba50_data *data = iio_priv(indio_dev); + int ret; + + if (state) + ret = i2c_smbus_write_byte_data(data->client, + STK8BA50_REG_INTEN2, STK8BA50_DREADY_INT_MASK); + else + ret = i2c_smbus_write_byte_data(data->client, + STK8BA50_REG_INTEN2, 0x00); + + if (ret < 0) + dev_err(&data->client->dev, "failed to set trigger state\n"); + else + data->dready_trigger_on = state; + + return ret; +} + +static const struct iio_trigger_ops stk8ba50_trigger_ops = { + .set_trigger_state = stk8ba50_data_rdy_trigger_set_state, + .owner = THIS_MODULE, +}; + +static int stk8ba50_set_power(struct stk8ba50_data *data, bool mode) +{ + int ret; + u8 masked_reg; + struct i2c_client *client = data->client; + + ret = i2c_smbus_read_byte_data(client, STK8BA50_REG_POWMODE); + if (ret < 0) + goto exit_err; + + if (mode) + masked_reg = ret | STK8BA50_MODE_POWERBIT; + else + masked_reg = ret & (~STK8BA50_MODE_POWERBIT); + + ret = i2c_smbus_write_byte_data(client, STK8BA50_REG_POWMODE, + masked_reg); + if (ret < 0) + goto exit_err; + + return ret; + +exit_err: + dev_err(&client->dev, "failed to change sensor mode\n"); + return ret; } static int stk8ba50_read_raw(struct iio_dev *indio_dev, @@ -124,11 +216,26 @@ static int stk8ba50_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct stk8ba50_data *data = iio_priv(indio_dev); + int ret; switch (mask) { case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; mutex_lock(&data->lock); - *val = stk8ba50_read_accel(data, chan->address); + ret = stk8ba50_set_power(data, STK8BA50_MODE_NORMAL); + if (ret < 0) { + mutex_unlock(&data->lock); + return -EINVAL; + } + ret = stk8ba50_read_accel(data, chan->address); + if (ret < 0) { + stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND); + mutex_unlock(&data->lock); + return -EINVAL; + } + *val = sign_extend32(ret >> STK8BA50_DATA_SHIFT, 9); + stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND); mutex_unlock(&data->lock); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: @@ -208,30 +315,100 @@ static const struct iio_info stk8ba50_info = { .attrs = &stk8ba50_attribute_group, }; -static int stk8ba50_set_power(struct stk8ba50_data *data, bool mode) +static irqreturn_t stk8ba50_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct stk8ba50_data *data = iio_priv(indio_dev); + int bit, ret, i = 0; + + mutex_lock(&data->lock); + /* + * Do a bulk read if all channels are requested, + * from 0x02 (XOUT1) to 0x07 (ZOUT2) + */ + if (*(indio_dev->active_scan_mask) == STK8BA50_ALL_CHANNEL_MASK) { + ret = i2c_smbus_read_i2c_block_data(data->client, + STK8BA50_REG_XOUT, + STK8BA50_ALL_CHANNEL_SIZE, + (u8 *)data->buffer); + if (ret < STK8BA50_ALL_CHANNEL_SIZE) { + dev_err(&data->client->dev, "register read failed\n"); + goto err; + } + } else { + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->masklength) { + ret = stk8ba50_read_accel(data, + stk8ba50_channel_table[bit]); + if (ret < 0) + goto err; + + data->buffer[i++] = ret; + } + } + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + pf->timestamp); +err: + mutex_unlock(&data->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static irqreturn_t stk8ba50_data_rdy_trig_poll(int irq, void *private) { + struct iio_dev *indio_dev = private; + struct stk8ba50_data *data = iio_priv(indio_dev); + + if (data->dready_trigger_on) + iio_trigger_poll(data->dready_trig); + + return IRQ_HANDLED; +} + +static int stk8ba50_buffer_preenable(struct iio_dev *indio_dev) +{ + struct stk8ba50_data *data = iio_priv(indio_dev); + + return stk8ba50_set_power(data, STK8BA50_MODE_NORMAL); +} + +static int stk8ba50_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct stk8ba50_data *data = iio_priv(indio_dev); + + return stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND); +} + +static const struct iio_buffer_setup_ops stk8ba50_buffer_setup_ops = { + .preenable = stk8ba50_buffer_preenable, + .postenable = iio_triggered_buffer_postenable, + .predisable = iio_triggered_buffer_predisable, + .postdisable = stk8ba50_buffer_postdisable, +}; + +static int stk8ba50_gpio_probe(struct i2c_client *client) +{ + struct device *dev; + struct gpio_desc *gpio; int ret; - u8 masked_reg; - struct i2c_client *client = data->client; - ret = i2c_smbus_read_byte_data(client, STK8BA50_REG_POWMODE); - if (ret < 0) - goto exit_err; + if (!client) + return -EINVAL; - if (mode) - masked_reg = ret | STK8BA50_MODE_POWERBIT; - else - masked_reg = ret & (~STK8BA50_MODE_POWERBIT); + dev = &client->dev; - ret = i2c_smbus_write_byte_data(client, STK8BA50_REG_POWMODE, - masked_reg); - if (ret < 0) - goto exit_err; + /* data ready gpio interrupt pin */ + gpio = devm_gpiod_get_index(dev, STK8BA50_GPIO, 0, GPIOD_IN); + if (IS_ERR(gpio)) { + dev_err(dev, "acpi gpio get index failed\n"); + return PTR_ERR(gpio); + } - return ret; + ret = gpiod_to_irq(gpio); + dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); -exit_err: - dev_err(&client->dev, "failed to change sensor mode\n"); return ret; } @@ -274,14 +451,78 @@ static int stk8ba50_probe(struct i2c_client *client, /* The default sampling rate is 1792 Hz (maximum) */ data->sample_rate_idx = STK8BA50_SR_1792HZ_IDX; + /* Set up interrupts */ + ret = i2c_smbus_write_byte_data(client, + STK8BA50_REG_INTEN2, STK8BA50_DREADY_INT_MASK); + if (ret < 0) { + dev_err(&client->dev, "failed to set up interrupts\n"); + goto err_power_off; + } + ret = i2c_smbus_write_byte_data(client, + STK8BA50_REG_INTMAP2, STK8BA50_DREADY_INT_MAP); + if (ret < 0) { + dev_err(&client->dev, "failed to set up interrupts\n"); + goto err_power_off; + } + + if (client->irq < 0) + client->irq = stk8ba50_gpio_probe(client); + + if (client->irq >= 0) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + stk8ba50_data_rdy_trig_poll, + NULL, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, + STK8BA50_IRQ_NAME, + indio_dev); + if (ret < 0) { + dev_err(&client->dev, "request irq %d failed\n", + client->irq); + goto err_power_off; + } + + data->dready_trig = devm_iio_trigger_alloc(&client->dev, + "%s-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->dready_trig) { + ret = -ENOMEM; + goto err_power_off; + } + + data->dready_trig->dev.parent = &client->dev; + data->dready_trig->ops = &stk8ba50_trigger_ops; + iio_trigger_set_drvdata(data->dready_trig, indio_dev); + ret = iio_trigger_register(data->dready_trig); + if (ret) { + dev_err(&client->dev, "iio trigger register failed\n"); + goto err_power_off; + } + } + + ret = iio_triggered_buffer_setup(indio_dev, + iio_pollfunc_store_time, + stk8ba50_trigger_handler, + &stk8ba50_buffer_setup_ops); + if (ret < 0) { + dev_err(&client->dev, "iio triggered buffer setup failed\n"); + goto err_trigger_unregister; + } + ret = iio_device_register(indio_dev); if (ret < 0) { dev_err(&client->dev, "device_register failed\n"); - goto err_power_off; + goto err_buffer_cleanup; } return ret; +err_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); +err_trigger_unregister: + if (data->dready_trig) + iio_trigger_unregister(data->dready_trig); err_power_off: stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND); return ret; @@ -290,10 +531,15 @@ err_power_off: static int stk8ba50_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct stk8ba50_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + + if (data->dready_trig) + iio_trigger_unregister(data->dready_trig); - return stk8ba50_set_power(iio_priv(indio_dev), STK8BA50_MODE_SUSPEND); + return stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND); } #ifdef CONFIG_PM_SLEEP -- cgit v1.3-6-gb490 From 95c12bba51c37359073b34f1a56fe396bd33d3cf Mon Sep 17 00:00:00 2001 From: Tiberiu Breana Date: Wed, 24 Jun 2015 17:01:48 +0300 Subject: iio: accel: Add buffer mode for Sensortek STK8312 Added triggered buffer mode support for the STK8312 accelerometer. Additional changes: - set_mode now sets operation mode directly, no longer masking the register's previous value - read_accel now returns raw acceleration data instead of the sign_extend32 value - read_raw will now enable/disable the sensor with each reading Signed-off-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 300 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 265 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index d211d9f3975b..be58d66d5d33 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -11,16 +11,23 @@ */ #include +#include #include +#include #include #include #include +#include #include #include +#include +#include +#include #define STK8312_REG_XOUT 0x00 #define STK8312_REG_YOUT 0x01 #define STK8312_REG_ZOUT 0x02 +#define STK8312_REG_INTSU 0x06 #define STK8312_REG_MODE 0x07 #define STK8312_REG_STH 0x13 #define STK8312_REG_RESET 0x20 @@ -29,14 +36,19 @@ #define STK8312_REG_OTPDATA 0x3E #define STK8312_REG_OTPCTRL 0x3F -#define STK8312_MODE_ACTIVE 1 -#define STK8312_MODE_STANDBY 0 -#define STK8312_MODE_MASK 0x01 +#define STK8312_MODE_ACTIVE 0x01 +#define STK8312_MODE_STANDBY 0x00 +#define STK8312_DREADY_BIT 0x10 +#define STK8312_INT_MODE 0xC0 #define STK8312_RNG_MASK 0xC0 #define STK8312_RNG_SHIFT 6 #define STK8312_READ_RETRIES 16 +#define STK8312_ALL_CHANNEL_MASK 7 +#define STK8312_ALL_CHANNEL_SIZE 3 #define STK8312_DRIVER_NAME "stk8312" +#define STK8312_GPIO "stk8312_gpio" +#define STK8312_IRQ_NAME "stk8312_event" /* * The accelerometer has two measurement ranges: @@ -53,19 +65,27 @@ static const int stk8312_scale_table[][2] = { {0, 461600}, {1, 231100} }; -#define STK8312_ACCEL_CHANNEL(reg, axis) { \ +#define STK8312_ACCEL_CHANNEL(index, reg, axis) { \ .type = IIO_ACCEL, \ .address = reg, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 8, \ + .storagebits = 8, \ + .endianness = IIO_CPU, \ + }, \ } static const struct iio_chan_spec stk8312_channels[] = { - STK8312_ACCEL_CHANNEL(STK8312_REG_XOUT, X), - STK8312_ACCEL_CHANNEL(STK8312_REG_YOUT, Y), - STK8312_ACCEL_CHANNEL(STK8312_REG_ZOUT, Z), + STK8312_ACCEL_CHANNEL(0, STK8312_REG_XOUT, X), + STK8312_ACCEL_CHANNEL(1, STK8312_REG_YOUT, Y), + STK8312_ACCEL_CHANNEL(2, STK8312_REG_ZOUT, Z), + IIO_CHAN_SOFT_TIMESTAMP(3), }; struct stk8312_data { @@ -73,6 +93,9 @@ struct stk8312_data { struct mutex lock; int range; u8 mode; + struct iio_trigger *dready_trig; + bool dready_trigger_on; + s8 buffer[16]; /* 3x8-bit channels + 5x8 padding + 64-bit timestamp */ }; static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL); @@ -130,31 +153,19 @@ exit_err: static int stk8312_set_mode(struct stk8312_data *data, u8 mode) { int ret; - u8 masked_reg; struct i2c_client *client = data->client; - if (mode > 1) - return -EINVAL; - else if (mode == data->mode) + if (mode == data->mode) return 0; - ret = i2c_smbus_read_byte_data(client, STK8312_REG_MODE); - if (ret < 0) { - dev_err(&client->dev, "failed to change sensor mode\n"); - return ret; - } - masked_reg = ret & (~STK8312_MODE_MASK); - masked_reg |= mode; - - ret = i2c_smbus_write_byte_data(client, - STK8312_REG_MODE, masked_reg); + ret = i2c_smbus_write_byte_data(client, STK8312_REG_MODE, mode); if (ret < 0) { dev_err(&client->dev, "failed to change sensor mode\n"); return ret; } data->mode = mode; - if (mode == STK8312_MODE_ACTIVE) { + if (mode & STK8312_MODE_ACTIVE) { /* Need to run OTP sequence before entering active mode */ usleep_range(1000, 5000); ret = stk8312_otp_init(data); @@ -163,6 +174,52 @@ static int stk8312_set_mode(struct stk8312_data *data, u8 mode) return ret; } +static int stk8312_set_interrupts(struct stk8312_data *data, u8 int_mask) +{ + int ret; + u8 mode; + struct i2c_client *client = data->client; + + mode = data->mode; + /* We need to go in standby mode to modify registers */ + ret = stk8312_set_mode(data, STK8312_MODE_STANDBY); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU, int_mask); + if (ret < 0) + dev_err(&client->dev, "failed to set interrupts\n"); + + return stk8312_set_mode(data, mode); +} + +static int stk8312_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct stk8312_data *data = iio_priv(indio_dev); + int ret; + + if (state) + ret = stk8312_set_interrupts(data, STK8312_DREADY_BIT); + else + ret = stk8312_set_interrupts(data, 0x00); + + if (ret < 0) { + dev_err(&data->client->dev, "failed to set trigger state\n"); + return ret; + } + + data->dready_trigger_on = state; + + return ret; +} + +static const struct iio_trigger_ops stk8312_trigger_ops = { + .set_trigger_state = stk8312_data_rdy_trigger_set_state, + .owner = THIS_MODULE, +}; + static int stk8312_set_range(struct stk8312_data *data, u8 range) { int ret; @@ -208,12 +265,10 @@ static int stk8312_read_accel(struct stk8312_data *data, u8 address) return -EINVAL; ret = i2c_smbus_read_byte_data(client, address); - if (ret < 0) { + if (ret < 0) dev_err(&client->dev, "register read failed\n"); - return ret; - } - return sign_extend32(ret, 7); + return ret; } static int stk8312_read_raw(struct iio_dev *indio_dev, @@ -221,14 +276,27 @@ static int stk8312_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct stk8312_data *data = iio_priv(indio_dev); - - if (chan->type != IIO_ACCEL) - return -EINVAL; + int ret; switch (mask) { case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; mutex_lock(&data->lock); - *val = stk8312_read_accel(data, chan->address); + ret = stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE); + if (ret < 0) { + mutex_unlock(&data->lock); + return -EINVAL; + } + ret = stk8312_read_accel(data, chan->address); + if (ret < 0) { + stk8312_set_mode(data, + data->mode & (~STK8312_MODE_ACTIVE)); + mutex_unlock(&data->lock); + return -EINVAL; + } + *val = sign_extend32(ret, 7); + stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE)); mutex_unlock(&data->lock); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: @@ -277,6 +345,109 @@ static const struct iio_info stk8312_info = { .attrs = &stk8312_attribute_group, }; +static irqreturn_t stk8312_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct stk8312_data *data = iio_priv(indio_dev); + int bit, ret, i = 0; + u8 buffer[STK8312_ALL_CHANNEL_SIZE]; + + mutex_lock(&data->lock); + /* + * Do a bulk read if all channels are requested, + * from 0x00 (XOUT) to 0x02 (ZOUT) + */ + if (*(indio_dev->active_scan_mask) == STK8312_ALL_CHANNEL_MASK) { + ret = i2c_smbus_read_i2c_block_data(data->client, + STK8312_REG_XOUT, + STK8312_ALL_CHANNEL_SIZE, + buffer); + if (ret < STK8312_ALL_CHANNEL_SIZE) { + dev_err(&data->client->dev, "register read failed\n"); + mutex_unlock(&data->lock); + goto err; + } + data->buffer[0] = buffer[0]; + data->buffer[1] = buffer[1]; + data->buffer[2] = buffer[2]; + } else { + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->masklength) { + ret = stk8312_read_accel(data, bit); + if (ret < 0) { + mutex_unlock(&data->lock); + goto err; + } + data->buffer[i++] = ret; + } + } + mutex_unlock(&data->lock); + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + pf->timestamp); +err: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static irqreturn_t stk8312_data_rdy_trig_poll(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct stk8312_data *data = iio_priv(indio_dev); + + if (data->dready_trigger_on) + iio_trigger_poll(data->dready_trig); + + return IRQ_HANDLED; +} + +static int stk8312_buffer_preenable(struct iio_dev *indio_dev) +{ + struct stk8312_data *data = iio_priv(indio_dev); + + return stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE); +} + +static int stk8312_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct stk8312_data *data = iio_priv(indio_dev); + + return stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE)); +} + +static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = { + .preenable = stk8312_buffer_preenable, + .postenable = iio_triggered_buffer_postenable, + .predisable = iio_triggered_buffer_predisable, + .postdisable = stk8312_buffer_postdisable, +}; + +static int stk8312_gpio_probe(struct i2c_client *client) +{ + struct device *dev; + struct gpio_desc *gpio; + int ret; + + if (!client) + return -EINVAL; + + dev = &client->dev; + + /* data ready gpio interrupt pin */ + gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0, GPIOD_IN); + if (IS_ERR(gpio)) { + dev_err(dev, "acpi gpio get index failed\n"); + return PTR_ERR(gpio); + } + + ret = gpiod_to_irq(gpio); + dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); + + return ret; +} + static int stk8312_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -312,26 +483,85 @@ static int stk8312_probe(struct i2c_client *client, if (ret < 0) return ret; - ret = stk8312_set_mode(data, STK8312_MODE_ACTIVE); + ret = stk8312_set_mode(data, STK8312_INT_MODE | STK8312_MODE_ACTIVE); if (ret < 0) return ret; + if (client->irq < 0) + client->irq = stk8312_gpio_probe(client); + + if (client->irq >= 0) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + stk8312_data_rdy_trig_poll, + NULL, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, + STK8312_IRQ_NAME, + indio_dev); + if (ret < 0) { + dev_err(&client->dev, "request irq %d failed\n", + client->irq); + goto err_power_off; + } + + data->dready_trig = devm_iio_trigger_alloc(&client->dev, + "%s-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->dready_trig) { + ret = -ENOMEM; + goto err_power_off; + } + + data->dready_trig->dev.parent = &client->dev; + data->dready_trig->ops = &stk8312_trigger_ops; + iio_trigger_set_drvdata(data->dready_trig, indio_dev); + ret = iio_trigger_register(data->dready_trig); + if (ret) { + dev_err(&client->dev, "iio trigger register failed\n"); + goto err_power_off; + } + } + + ret = iio_triggered_buffer_setup(indio_dev, + iio_pollfunc_store_time, + stk8312_trigger_handler, + &stk8312_buffer_setup_ops); + if (ret < 0) { + dev_err(&client->dev, "iio triggered buffer setup failed\n"); + goto err_trigger_unregister; + } + ret = iio_device_register(indio_dev); if (ret < 0) { dev_err(&client->dev, "device_register failed\n"); - stk8312_set_mode(data, STK8312_MODE_STANDBY); + goto err_buffer_cleanup; } return ret; + +err_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); +err_trigger_unregister: + if (data->dready_trig) + iio_trigger_unregister(data->dready_trig); +err_power_off: + stk8312_set_mode(data, STK8312_MODE_STANDBY); + return ret; } static int stk8312_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct stk8312_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); - return stk8312_set_mode(iio_priv(indio_dev), STK8312_MODE_STANDBY); + if (data->dready_trig) + iio_trigger_unregister(data->dready_trig); + + return stk8312_set_mode(data, STK8312_MODE_STANDBY); } #ifdef CONFIG_PM_SLEEP @@ -341,7 +571,7 @@ static int stk8312_suspend(struct device *dev) data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); - return stk8312_set_mode(data, STK8312_MODE_STANDBY); + return stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE)); } static int stk8312_resume(struct device *dev) @@ -350,7 +580,7 @@ static int stk8312_resume(struct device *dev) data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); - return stk8312_set_mode(data, STK8312_MODE_ACTIVE); + return stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE); } static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume); -- cgit v1.3-6-gb490 From 5e913d27f91aa15e1311399385579bef5238e2cd Mon Sep 17 00:00:00 2001 From: Tiberiu Breana Date: Wed, 24 Jun 2015 17:01:49 +0300 Subject: iio: accel: Add sampling rate support for STK8312 Added support for setting the STK8312 accelerometer's sampling rate. Signed-off-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 96 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index be58d66d5d33..c2bd1444d6da 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -29,6 +29,7 @@ #define STK8312_REG_ZOUT 0x02 #define STK8312_REG_INTSU 0x06 #define STK8312_REG_MODE 0x07 +#define STK8312_REG_SR 0x08 #define STK8312_REG_STH 0x13 #define STK8312_REG_RESET 0x20 #define STK8312_REG_AFECTRL 0x24 @@ -41,6 +42,8 @@ #define STK8312_DREADY_BIT 0x10 #define STK8312_INT_MODE 0xC0 #define STK8312_RNG_MASK 0xC0 +#define STK8312_SR_MASK 0x07 +#define STK8312_SR_400HZ_IDX 0 #define STK8312_RNG_SHIFT 6 #define STK8312_READ_RETRIES 16 #define STK8312_ALL_CHANNEL_MASK 7 @@ -65,20 +68,29 @@ static const int stk8312_scale_table[][2] = { {0, 461600}, {1, 231100} }; -#define STK8312_ACCEL_CHANNEL(index, reg, axis) { \ - .type = IIO_ACCEL, \ - .address = reg, \ - .modified = 1, \ - .channel2 = IIO_MOD_##axis, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .scan_index = index, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 8, \ - .storagebits = 8, \ - .endianness = IIO_CPU, \ - }, \ +static const struct { + u16 val; + u32 val2; +} stk8312_samp_freq_table[] = { + {400, 0}, {200, 0}, {100, 0}, {50, 0}, {25, 0}, + {12, 500000}, {6, 250000}, {3, 125000} +}; + +#define STK8312_ACCEL_CHANNEL(index, reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 8, \ + .storagebits = 8, \ + .endianness = IIO_CPU, \ + }, \ } static const struct iio_chan_spec stk8312_channels[] = { @@ -92,6 +104,7 @@ struct stk8312_data { struct i2c_client *client; struct mutex lock; int range; + u8 sample_rate_idx; u8 mode; struct iio_trigger *dready_trig; bool dready_trigger_on; @@ -100,8 +113,11 @@ struct stk8312_data { static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("3.125 6.25 12.5 25 50 100 200 400"); + static struct attribute *stk8312_attributes[] = { &iio_const_attr_in_accel_scale_available.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, NULL, }; @@ -220,6 +236,39 @@ static const struct iio_trigger_ops stk8312_trigger_ops = { .owner = THIS_MODULE, }; +static int stk8312_set_sample_rate(struct stk8312_data *data, int rate) +{ + int ret; + u8 masked_reg; + u8 mode; + struct i2c_client *client = data->client; + + if (rate == data->sample_rate_idx) + return 0; + + mode = data->mode; + /* We need to go in standby mode to modify registers */ + ret = stk8312_set_mode(data, STK8312_MODE_STANDBY); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_byte_data(client, STK8312_REG_SR); + if (ret < 0) { + dev_err(&client->dev, "failed to set sampling rate\n"); + return ret; + } + + masked_reg = (ret & (~STK8312_SR_MASK)) | rate; + + ret = i2c_smbus_write_byte_data(client, STK8312_REG_SR, masked_reg); + if (ret < 0) + dev_err(&client->dev, "failed to set sampling rate\n"); + else + data->sample_rate_idx = rate; + + return stk8312_set_mode(data, mode); +} + static int stk8312_set_range(struct stk8312_data *data, u8 range) { int ret; @@ -303,6 +352,10 @@ static int stk8312_read_raw(struct iio_dev *indio_dev, *val = stk8312_scale_table[data->range - 1][0]; *val2 = stk8312_scale_table[data->range - 1][1]; return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = stk8312_samp_freq_table[data->sample_rate_idx].val; + *val2 = stk8312_samp_freq_table[data->sample_rate_idx].val2; + return IIO_VAL_INT_PLUS_MICRO; } return -EINVAL; @@ -332,6 +385,20 @@ static int stk8312_write_raw(struct iio_dev *indio_dev, ret = stk8312_set_range(data, index); mutex_unlock(&data->lock); + return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + for (i = 0; i < ARRAY_SIZE(stk8312_samp_freq_table); i++) + if (val == stk8312_samp_freq_table[i].val && + val2 == stk8312_samp_freq_table[i].val2) { + index = i; + break; + } + if (index < 0) + return -EINVAL; + mutex_lock(&data->lock); + ret = stk8312_set_sample_rate(data, index); + mutex_unlock(&data->lock); + return ret; } @@ -479,6 +546,7 @@ static int stk8312_probe(struct i2c_client *client, dev_err(&client->dev, "failed to reset sensor\n"); return ret; } + data->sample_rate_idx = STK8312_SR_400HZ_IDX; ret = stk8312_set_range(data, 1); if (ret < 0) return ret; -- cgit v1.3-6-gb490 From fcc577dd55db193926537e0e4de98492d665446b Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Tue, 23 Jun 2015 16:34:19 +0300 Subject: iio: Fix parameters in iio_triggered_buffer_setup This patch renames the top half handler and the bottom half handler of iio_triggered_buffer_setup() in accordance with their usage. The bottom half has been renamed to reflect the fact that it is a thread based call, compliant with iio_alloc_pollfunc(). The names of the parameters were swapped, thus creating confusion. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-triggered-buffer.c | 12 ++++++------ include/linux/iio/triggered_buffer.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/industrialio-triggered-buffer.c b/drivers/iio/industrialio-triggered-buffer.c index 15a5341b5e7b..4b2858ba1fd6 100644 --- a/drivers/iio/industrialio-triggered-buffer.c +++ b/drivers/iio/industrialio-triggered-buffer.c @@ -24,8 +24,8 @@ static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { /** * iio_triggered_buffer_setup() - Setup triggered buffer and pollfunc * @indio_dev: IIO device structure - * @pollfunc_bh: Function which will be used as pollfunc bottom half - * @pollfunc_th: Function which will be used as pollfunc top half + * @h: Function which will be used as pollfunc top half + * @thread: Function which will be used as pollfunc bottom half * @setup_ops: Buffer setup functions to use for this device. * If NULL the default setup functions for triggered * buffers will be used. @@ -42,8 +42,8 @@ static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { * iio_triggered_buffer_cleanup(). */ int iio_triggered_buffer_setup(struct iio_dev *indio_dev, - irqreturn_t (*pollfunc_bh)(int irq, void *p), - irqreturn_t (*pollfunc_th)(int irq, void *p), + irqreturn_t (*h)(int irq, void *p), + irqreturn_t (*thread)(int irq, void *p), const struct iio_buffer_setup_ops *setup_ops) { struct iio_buffer *buffer; @@ -57,8 +57,8 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev, iio_device_attach_buffer(indio_dev, buffer); - indio_dev->pollfunc = iio_alloc_pollfunc(pollfunc_bh, - pollfunc_th, + indio_dev->pollfunc = iio_alloc_pollfunc(h, + thread, IRQF_ONESHOT, indio_dev, "%s_consumer%d", diff --git a/include/linux/iio/triggered_buffer.h b/include/linux/iio/triggered_buffer.h index c378ebec605e..f72f70d5a97b 100644 --- a/include/linux/iio/triggered_buffer.h +++ b/include/linux/iio/triggered_buffer.h @@ -7,8 +7,8 @@ struct iio_dev; struct iio_buffer_setup_ops; int iio_triggered_buffer_setup(struct iio_dev *indio_dev, - irqreturn_t (*pollfunc_bh)(int irq, void *p), - irqreturn_t (*pollfunc_th)(int irq, void *p), + irqreturn_t (*h)(int irq, void *p), + irqreturn_t (*thread)(int irq, void *p), const struct iio_buffer_setup_ops *setup_ops); void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev); -- cgit v1.3-6-gb490 From ec530829ed064bc63d260f309e3ef88e0764132b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 5 Jul 2015 21:55:10 +0200 Subject: GPU-DRM: Delete an unnecessary check before drm_property_unreference_blob() The drm_property_unreference_blob() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Reviewed-by: Zhao Junwang Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index b69ed97d447c..79fe31e5851e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4469,9 +4469,7 @@ static int drm_property_replace_global_blob(struct drm_device *dev, goto err_created; } - if (old_blob) - drm_property_unreference_blob(old_blob); - + drm_property_unreference_blob(old_blob); *replace = new_blob; return 0; -- cgit v1.3-6-gb490 From 398a017e91d1518e303886398b15b1851c3d902c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 30 Jun 2015 15:33:51 +0300 Subject: drm/i915: Fix HDMI 12bpc and pixel repeat clock readout for DDI platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take the HDMI 12bpc mode and pixel repeat into account when extracting the dotclock from the hardware on DDI platforms. Tested on HSW only. Signed-off-by: Ville Syrjälä Reviewed-and-tested-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 49 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 15fc66a8da78..e7f0379453e8 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1027,6 +1027,26 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv, return dco_freq / (p0 * p1 * p2 * 5); } +static void ddi_dotclock_get(struct intel_crtc_state *pipe_config) +{ + int dotclock; + + if (pipe_config->has_pch_encoder) + dotclock = intel_dotclock_calculate(pipe_config->port_clock, + &pipe_config->fdi_m_n); + else if (pipe_config->has_dp_encoder) + dotclock = intel_dotclock_calculate(pipe_config->port_clock, + &pipe_config->dp_m_n); + else if (pipe_config->has_hdmi_sink && pipe_config->pipe_bpp == 36) + dotclock = pipe_config->port_clock * 2 / 3; + else + dotclock = pipe_config->port_clock; + + if (pipe_config->pixel_multiplier) + dotclock /= pipe_config->pixel_multiplier; + + pipe_config->base.adjusted_mode.crtc_clock = dotclock; +} static void skl_ddi_clock_get(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) @@ -1073,12 +1093,7 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder, pipe_config->port_clock = link_clock; - if (pipe_config->has_dp_encoder) - pipe_config->base.adjusted_mode.crtc_clock = - intel_dotclock_calculate(pipe_config->port_clock, - &pipe_config->dp_m_n); - else - pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; + ddi_dotclock_get(pipe_config); } static void hsw_ddi_clock_get(struct intel_encoder *encoder, @@ -1125,16 +1140,7 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder, pipe_config->port_clock = link_clock * 2; - if (pipe_config->has_pch_encoder) - pipe_config->base.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->base.adjusted_mode.crtc_clock = - intel_dotclock_calculate(pipe_config->port_clock, - &pipe_config->dp_m_n); - else - pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; + ddi_dotclock_get(pipe_config); } static int bxt_calc_pll_link(struct drm_i915_private *dev_priv, @@ -1169,16 +1175,9 @@ static void bxt_ddi_clock_get(struct intel_encoder *encoder, enum port port = intel_ddi_get_encoder_port(encoder); uint32_t dpll = port; - pipe_config->port_clock = - bxt_calc_pll_link(dev_priv, dpll); + pipe_config->port_clock = bxt_calc_pll_link(dev_priv, dpll); - if (pipe_config->has_dp_encoder) - pipe_config->base.adjusted_mode.crtc_clock = - intel_dotclock_calculate(pipe_config->port_clock, - &pipe_config->dp_m_n); - else - pipe_config->base.adjusted_mode.crtc_clock = - pipe_config->port_clock; + ddi_dotclock_get(pipe_config); } void intel_ddi_clock_get(struct intel_encoder *encoder, -- cgit v1.3-6-gb490 From 6fd765d0591a79934b268137fc7c0fbfa0e2e3b4 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 30 Jun 2015 15:33:52 +0300 Subject: drm/i915: Bump HDMI min port clock to 25 MHz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increase the HDMI port minimum port clock from 20 to 25 MHz. This is is the minimum listed in the DVI/HDMI specs, and it's also the documented minimum DPLL frequency for most of our platforms. Signed-off-by: Ville Syrjälä Reviewed-and-tested-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 00c4b40e0158..69244ed2c352 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1175,7 +1175,7 @@ intel_hdmi_mode_valid(struct drm_connector *connector, if (clock > hdmi_portclock_limit(intel_attached_hdmi(connector), true)) return MODE_CLOCK_HIGH; - if (clock < 20000) + if (clock < 25000) return MODE_CLOCK_LOW; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) -- cgit v1.3-6-gb490 From e64e739ed6e5409b86ab5896cad4edb4570bf8ec Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 30 Jun 2015 19:23:59 +0300 Subject: drm/i915: Account for CHV/BXT DPLL clock limitations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHV/BXT DPLL can't generate frequencies in the 216-240 MHz range. Account for that when checking whether the HDMI port clock is valid. This is particularly important for BXT since it can otherwise do 12bpc, and standard 1920x1080p60 CEA modes land right in the middle of that range when the clock gets multiplied to account for 12bpc. With the extra checks we will now filter out any mode where both 8bpc and 12bpc clock are within the gap. During modeset we then pick whichever mode works, favoring 12bpc if both are possible. 12bpc isn't supported on CHV so we simply end up filtering out any mode where the 8bpc port clock is in the gap. v2: Fix crtc_clock vs. port_clock fumble in compute_config() (Imre) Signed-off-by: Ville Syrjälä Reviewed-and-tested-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 58 +++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 69244ed2c352..f5c60d6febee 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1151,7 +1151,7 @@ static void pch_post_disable_hdmi(struct intel_encoder *encoder) intel_disable_hdmi(encoder); } -static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) +static int hdmi_port_clock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) { struct drm_device *dev = intel_hdmi_to_dev(hdmi); @@ -1163,25 +1163,49 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) return 225000; } +static enum drm_mode_status +hdmi_port_clock_valid(struct intel_hdmi *hdmi, + int clock, bool respect_dvi_limit) +{ + struct drm_device *dev = intel_hdmi_to_dev(hdmi); + + if (clock < 25000) + return MODE_CLOCK_LOW; + if (clock > hdmi_port_clock_limit(hdmi, respect_dvi_limit)) + return MODE_CLOCK_HIGH; + + /* CHV/BXT DPLL can't generate 216-240 MHz */ + if ((IS_CHERRYVIEW(dev) || IS_BROXTON(dev)) && + clock > 216000 && clock < 240000) + return MODE_CLOCK_RANGE; + + return MODE_OK; +} + static enum drm_mode_status intel_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - int clock = mode->clock; + struct intel_hdmi *hdmi = intel_attached_hdmi(connector); + struct drm_device *dev = intel_hdmi_to_dev(hdmi); + enum drm_mode_status status; + int clock; + + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + clock = mode->clock; if (mode->flags & DRM_MODE_FLAG_DBLCLK) clock *= 2; - if (clock > hdmi_portclock_limit(intel_attached_hdmi(connector), - true)) - return MODE_CLOCK_HIGH; - if (clock < 25000) - return MODE_CLOCK_LOW; + /* check if we can do 8bpc */ + status = hdmi_port_clock_valid(hdmi, clock, true); - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) - return MODE_NO_DBLESCAN; + /* if we can't do 8bpc we may still be able to do 12bpc */ + if (!HAS_GMCH_DISPLAY(dev) && status != MODE_OK) + status = hdmi_port_clock_valid(hdmi, clock * 3 / 2, true); - return MODE_OK; + return status; } static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state) @@ -1222,8 +1246,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct drm_device *dev = encoder->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; - int clock_12bpc = pipe_config->base.adjusted_mode.crtc_clock * 3 / 2; - int portclock_limit = hdmi_portclock_limit(intel_hdmi, false); + int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock; + int clock_12bpc = clock_8bpc * 3 / 2; int desired_bpp; pipe_config->has_hdmi_sink = intel_hdmi->has_hdmi_sink; @@ -1242,6 +1266,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) { pipe_config->pixel_multiplier = 2; + clock_8bpc *= 2; clock_12bpc *= 2; } @@ -1261,7 +1286,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, * within limits. */ if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink && - clock_12bpc <= portclock_limit && + hdmi_port_clock_valid(intel_hdmi, clock_12bpc, false) == MODE_OK && hdmi_12bpc_possible(pipe_config) && 0 /* FIXME 12bpc support totally broken */) { DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); @@ -1272,6 +1297,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, } else { DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); desired_bpp = 8*3; + + pipe_config->port_clock = clock_8bpc; } if (!pipe_config->bw_constrained) { @@ -1279,8 +1306,9 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, pipe_config->pipe_bpp = desired_bpp; } - if (adjusted_mode->crtc_clock > portclock_limit) { - DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n"); + if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock, + false) != MODE_OK) { + DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n"); return false; } -- cgit v1.3-6-gb490 From 7a0baa6234468aa387f9b8a1a79dc2a4b4821f67 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 30 Jun 2015 15:33:54 +0300 Subject: Revert "drm/i915: Disable 12bpc hdmi for now" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HDMI 12bpc should be working fine now. Let it loose. This reverts commit 5e3daaca09f5158eff9c92290faa1d2001ecc6e4. v2: Rebased due to CHV/BXT port clock check improvemnts Signed-off-by: Ville Syrjälä Reviewed-and-tested-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f5c60d6febee..c7e912bafb87 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1287,8 +1287,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, */ if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink && hdmi_port_clock_valid(intel_hdmi, clock_12bpc, false) == MODE_OK && - hdmi_12bpc_possible(pipe_config) && - 0 /* FIXME 12bpc support totally broken */) { + hdmi_12bpc_possible(pipe_config)) { DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); desired_bpp = 12*3; -- cgit v1.3-6-gb490 From 89ae3d3b9a384e75158f71ea9b878c8a45f3d582 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 9 Jun 2015 11:35:25 +0200 Subject: drm/msm/dp: use flags argument of devm_gpiod_get to set direction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Use this to simplify the driver. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Acked-by: Alexandre Courbot Acked-by: Linus Walleij Signed-off-by: Uwe Kleine-König --- drivers/gpu/drm/msm/edp/edp_ctrl.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 7991069dd492..81200e9be382 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -373,7 +373,7 @@ static int edp_gpio_config(struct edp_ctrl *ctrl) struct device *dev = &ctrl->pdev->dev; int ret; - ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd"); + ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd", GPIOD_IN); if (IS_ERR(ctrl->panel_hpd_gpio)) { ret = PTR_ERR(ctrl->panel_hpd_gpio); ctrl->panel_hpd_gpio = NULL; @@ -381,13 +381,7 @@ static int edp_gpio_config(struct edp_ctrl *ctrl) return ret; } - ret = gpiod_direction_input(ctrl->panel_hpd_gpio); - if (ret) { - pr_err("%s: Set direction for hpd failed, %d\n", __func__, ret); - return ret; - } - - ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en"); + ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en", GPIOD_OUT_LOW); if (IS_ERR(ctrl->panel_en_gpio)) { ret = PTR_ERR(ctrl->panel_en_gpio); ctrl->panel_en_gpio = NULL; @@ -395,13 +389,6 @@ static int edp_gpio_config(struct edp_ctrl *ctrl) return ret; } - ret = gpiod_direction_output(ctrl->panel_en_gpio, 0); - if (ret) { - pr_err("%s: Set direction for panel_en failed, %d\n", - __func__, ret); - return ret; - } - DBG("gpio on"); return 0; -- cgit v1.3-6-gb490 From 26a5bd26499fba331ecaa1e8ce8cc2b8c6fac569 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 11 Feb 2015 17:32:53 +0100 Subject: drm/tilcdc: panel: make better use of gpiod API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Furthermore there is devm_gpiod_get_optional which is designed to get optional gpios. Simplify driver accordingly. Acked-by: Alexandre Courbot Acked-by: Linus Walleij Signed-off-by: Uwe Kleine-König --- drivers/gpu/drm/tilcdc/tilcdc_panel.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index 7a0315855e90..0af8bed7ce1e 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c @@ -375,25 +375,17 @@ static int panel_probe(struct platform_device *pdev) dev_info(&pdev->dev, "found backlight\n"); } - panel_mod->enable_gpio = devm_gpiod_get(&pdev->dev, "enable"); + panel_mod->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", + GPIOD_OUT_LOW); if (IS_ERR(panel_mod->enable_gpio)) { ret = PTR_ERR(panel_mod->enable_gpio); - if (ret != -ENOENT) { - dev_err(&pdev->dev, "failed to request enable GPIO\n"); - goto fail_backlight; - } - - /* Optional GPIO is not here, continue silently. */ - panel_mod->enable_gpio = NULL; - } else { - ret = gpiod_direction_output(panel_mod->enable_gpio, 0); - if (ret < 0) { - dev_err(&pdev->dev, "failed to setup GPIO\n"); - goto fail_backlight; - } - dev_info(&pdev->dev, "found enable GPIO\n"); + dev_err(&pdev->dev, "failed to request enable GPIO\n"); + goto fail_backlight; } + if (panel_mod->enable_gpio) + dev_info(&pdev->dev, "found enable GPIO\n"); + mod = &panel_mod->base; pdev->dev.platform_data = mod; -- cgit v1.3-6-gb490 From 7d4eb6f2110d9a9f9fe8d39eabddadbd35eb12b2 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 Jun 2015 09:04:55 +0200 Subject: iio: light: stk3310: use flags argument of devm_gpiod_get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Simplify driver accordingly. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Acked-by: Jonathan Cameron Signed-off-by: Uwe Kleine-König --- drivers/iio/light/stk3310.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index fee4297d7c8f..84c77d42a2c6 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -488,16 +488,12 @@ static int stk3310_gpio_probe(struct i2c_client *client) dev = &client->dev; /* gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0); + gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0, GPIOD_IN); if (IS_ERR(gpio)) { dev_err(dev, "acpi gpio get index failed\n"); return PTR_ERR(gpio); } - ret = gpiod_direction_input(gpio); - if (ret) - return ret; - ret = gpiod_to_irq(gpio); dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); -- cgit v1.3-6-gb490 From 7d891dbee52e0a843ee7724ad4100675cf2fe24c Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 Jun 2015 09:04:55 +0200 Subject: iio: magn: bmc150: use flags argument of devm_gpiod_get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Simplify driver accordingly. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Acked-by: Jonathan Cameron Signed-off-by: Uwe Kleine-König --- drivers/iio/magnetometer/bmc150_magn.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index d4c178869991..187a31fdc35a 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -839,16 +839,12 @@ static int bmc150_magn_gpio_probe(struct i2c_client *client) dev = &client->dev; /* data ready GPIO interrupt pin */ - gpio = devm_gpiod_get_index(dev, BMC150_MAGN_GPIO_INT, 0); + gpio = devm_gpiod_get_index(dev, BMC150_MAGN_GPIO_INT, 0, GPIOD_IN); if (IS_ERR(gpio)) { dev_err(dev, "ACPI GPIO get index failed\n"); return PTR_ERR(gpio); } - ret = gpiod_direction_input(gpio); - if (ret) - return ret; - ret = gpiod_to_irq(gpio); dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); -- cgit v1.3-6-gb490 From a33c380ef59353e550e852c82395306cf83cc7c0 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 Jun 2015 09:04:55 +0200 Subject: media: i2c/adp1653: set enable gpio to output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without setting the direction of a gpio to output a call to gpiod_set_value doesn't have a defined outcome. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Acked-by: Sakari Ailus Acked-by: Pavel Machek Signed-off-by: Uwe Kleine-König --- drivers/media/i2c/adp1653.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index c70ababce954..5dd39775d6ca 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c @@ -465,7 +465,7 @@ static int adp1653_of_init(struct i2c_client *client, of_node_put(child); - pd->enable_gpio = devm_gpiod_get(&client->dev, "enable"); + pd->enable_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_LOW); if (!pd->enable_gpio) { dev_err(&client->dev, "Error getting GPIO\n"); return -EINVAL; -- cgit v1.3-6-gb490 From 3bfe76806f705a24b82bc43c84c8506f3a44f77b Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 Jun 2015 09:04:55 +0200 Subject: NFC: nxp-nci_i2c: use flags argument of devm_gpiod_get_index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Simplify driver accordingly which even makes error checking more correct because gpiod_direction_{in,out}put might fail. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Acked-by: Oleg Zhurakivskyy Signed-off-by: Uwe Kleine-König --- drivers/nfc/nxp-nci/i2c.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c index 2f77f1d03638..fac80c691914 100644 --- a/drivers/nfc/nxp-nci/i2c.c +++ b/drivers/nfc/nxp-nci/i2c.c @@ -318,19 +318,15 @@ static int nxp_nci_i2c_acpi_config(struct nxp_nci_i2c_phy *phy) struct i2c_client *client = phy->i2c_dev; struct gpio_desc *gpiod_en, *gpiod_fw, *gpiod_irq; - gpiod_en = devm_gpiod_get_index(&client->dev, NULL, 2); - gpiod_fw = devm_gpiod_get_index(&client->dev, NULL, 1); - gpiod_irq = devm_gpiod_get_index(&client->dev, NULL, 0); + gpiod_en = devm_gpiod_get_index(&client->dev, NULL, 2, GPIOD_OUT_LOW); + gpiod_fw = devm_gpiod_get_index(&client->dev, NULL, 1, GPIOD_OUT_LOW); + gpiod_irq = devm_gpiod_get_index(&client->dev, NULL, 0, GPIOD_IN); if (IS_ERR(gpiod_en) || IS_ERR(gpiod_fw) || IS_ERR(gpiod_irq)) { nfc_err(&client->dev, "No GPIOs\n"); return -EINVAL; } - gpiod_direction_output(gpiod_en, 0); - gpiod_direction_output(gpiod_fw, 0); - gpiod_direction_input(gpiod_irq); - client->irq = gpiod_to_irq(gpiod_irq); if (client->irq < 0) { nfc_err(&client->dev, "No IRQ\n"); -- cgit v1.3-6-gb490 From 8e71c68074ff37348d586c87b0ee530e7440b094 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 Jun 2015 08:55:30 +0200 Subject: phy: tusb1210: make better use of gpiod API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Furthermore there is devm_gpiod_get_optional which is designed to get optional gpios. Simplify driver accordingly. Signed-off-by: Uwe Kleine-König --- drivers/phy/phy-tusb1210.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-tusb1210.c b/drivers/phy/phy-tusb1210.c index 07efdd318bdc..93dd45f2f26e 100644 --- a/drivers/phy/phy-tusb1210.c +++ b/drivers/phy/phy-tusb1210.c @@ -61,32 +61,26 @@ static struct phy_ops phy_ops = { static int tusb1210_probe(struct ulpi *ulpi) { - struct gpio_desc *gpio; struct tusb1210 *tusb; u8 val, reg; - int ret; tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL); if (!tusb) return -ENOMEM; - gpio = devm_gpiod_get(&ulpi->dev, "reset"); - if (!IS_ERR(gpio)) { - ret = gpiod_direction_output(gpio, 0); - if (ret) - return ret; - gpiod_set_value_cansleep(gpio, 1); - tusb->gpio_reset = gpio; - } + tusb->gpio_reset = devm_gpiod_get_optional(&ulpi->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(tusb->gpio_reset)) + return PTR_ERR(tusb->gpio_reset); - gpio = devm_gpiod_get(&ulpi->dev, "cs"); - if (!IS_ERR(gpio)) { - ret = gpiod_direction_output(gpio, 0); - if (ret) - return ret; - gpiod_set_value_cansleep(gpio, 1); - tusb->gpio_cs = gpio; - } + gpiod_set_value_cansleep(tusb->gpio_reset, 1); + + tusb->gpio_cs = devm_gpiod_get_optional(&ulpi->dev, "cs", + GPIOD_OUT_LOW); + if (IS_ERR(tusb->gpio_cs)) + return PTR_ERR(tusb->gpio_cs); + + gpiod_set_value_cansleep(tusb->gpio_cs, 1); /* * VENDOR_SPECIFIC2 register in TUSB1210 can be used for configuring eye -- cgit v1.3-6-gb490 From 75da3b1c24389fe78680269176de0332d35f7fad Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 12 Jun 2015 09:04:55 +0200 Subject: usb: dwc3: pci: make better use of gpiod API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Use this additional parameter and the _optional variant to simplify the driver and improve error handling. Also expand the comment to explain why it's not sensible to switch to devm_gpiod_get and why the gpiod_put is also necessary. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Tested-by: Heikki Krogerus Signed-off-by: Uwe Kleine-König --- drivers/usb/dwc3/dwc3-pci.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 27e4fc896e9d..f62617999f3c 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -83,17 +83,23 @@ static int dwc3_pci_quirks(struct pci_dev *pdev) acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev), acpi_dwc3_byt_gpios); - /* These GPIOs will turn on the USB2 PHY */ - gpio = gpiod_get(&pdev->dev, "cs"); - if (!IS_ERR(gpio)) { - gpiod_direction_output(gpio, 0); - gpiod_set_value_cansleep(gpio, 1); - gpiod_put(gpio); - } + /* + * These GPIOs will turn on the USB2 PHY. Note that we have to + * put the gpio descriptors again here because the phy driver + * might want to grab them, too. + */ + gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + + gpiod_set_value_cansleep(gpio, 1); + gpiod_put(gpio); + + gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); - gpio = gpiod_get(&pdev->dev, "reset"); - if (!IS_ERR(gpio)) { - gpiod_direction_output(gpio, 0); + if (gpio) { gpiod_set_value_cansleep(gpio, 1); gpiod_put(gpio); usleep_range(10000, 11000); -- cgit v1.3-6-gb490 From eac477801924cac38a273338487cce9f460434bb Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 5 Mar 2015 09:36:19 +0100 Subject: usb: pass flags parameter to gpiod_get functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Currently this parameter is made optional with the help of a cpp trick. To allow dropping this hack convert callers to explictly pass a value for flags. Acked-by: Felipe Balbi Acked-by: Robert Jarzmik Signed-off-by: Uwe Kleine-König --- drivers/usb/gadget/udc/pxa27x_udc.c | 2 +- drivers/usb/phy/phy-generic.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index b51226abade6..042f06b52677 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -2422,7 +2422,7 @@ static int pxa_udc_probe(struct platform_device *pdev) } udc->udc_command = mach->udc_command; } else { - udc->gpiod = devm_gpiod_get(&pdev->dev, NULL); + udc->gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_ASIS); } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index deee68eafb72..ec6ecd03269c 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -218,11 +218,13 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, clk_rate = 0; needs_vcc = of_property_read_bool(node, "vcc-supply"); - nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset"); + nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset", + GPIOD_ASIS); err = PTR_ERR_OR_ZERO(nop->gpiod_reset); if (!err) { nop->gpiod_vbus = devm_gpiod_get_optional(dev, - "vbus-detect"); + "vbus-detect", + GPIOD_ASIS); err = PTR_ERR_OR_ZERO(nop->gpiod_vbus); } } else if (pdata) { -- cgit v1.3-6-gb490 From e62925567c7926e78bc8ca976cde5c28ea265a49 Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Wed, 1 Jul 2015 17:02:57 +0530 Subject: drm/i915/bxt: BUNs related to port PLL This patch contains changes based on 2 updates to the spec: Port PLL VCO restriction raised up to 6700. Port PLL now needs DCO amp override enable for all VCO frequencies. v2: Sonika's review comment addressed - dcoampovr_en_h variable not required Based on a discussion with Siva, the following changes have been made. - replace dco_amp var with #define BXT_DCO_AMPLITUDE - set pll10 in a single assignment v3: Move DCO amplitude default value to i915_reg.h. Suggested by Siva. Signed-off-by: Vandana Kannan Reviewed-by: Sonika Jindal [v2] [danvet: Spell out BUN since not everyone knows what this means.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ddi.c | 15 +++++---------- drivers/gpu/drm/i915/intel_display.c | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 42ba1ef641d8..ac8436fc6ced 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1215,6 +1215,7 @@ enum skl_disp_power_wells { #define PORT_PLL_LOCK_THRESHOLD_MASK (0x7 << PORT_PLL_LOCK_THRESHOLD_SHIFT) /* PORT_PLL_10_A */ #define PORT_PLL_DCO_AMP_OVR_EN_H (1<<27) +#define PORT_PLL_DCO_AMP_DEFAULT 15 #define PORT_PLL_DCO_AMP_MASK 0x3c00 #define PORT_PLL_DCO_AMP(x) (x<<10) #define _PORT_PLL_BASE(port) _PORT3(port, _PORT_PLL_0_A, \ diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index e7f0379453e8..db22f0173027 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1644,7 +1644,7 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, struct bxt_clk_div clk_div = {0}; int vco = 0; uint32_t prop_coef, int_coef, gain_ctl, targ_cnt; - uint32_t dcoampovr_en_h, dco_amp, lanestagger; + uint32_t lanestagger; if (intel_encoder->type == INTEL_OUTPUT_HDMI) { intel_clock_t best_clock; @@ -1683,9 +1683,7 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2; } - dco_amp = 15; - dcoampovr_en_h = 0; - if (vco >= 6200000 && vco <= 6480000) { + if (vco >= 6200000 && vco <= 6700000) { prop_coef = 4; int_coef = 9; gain_ctl = 3; @@ -1696,8 +1694,6 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, int_coef = 11; gain_ctl = 3; targ_cnt = 9; - if (vco >= 4800000 && vco < 5400000) - dcoampovr_en_h = 1; } else if (vco == 5400000) { prop_coef = 3; int_coef = 8; @@ -1741,10 +1737,9 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT; - if (dcoampovr_en_h) - crtc_state->dpll_hw_state.pll10 = PORT_PLL_DCO_AMP_OVR_EN_H; - - crtc_state->dpll_hw_state.pll10 |= PORT_PLL_DCO_AMP(dco_amp); + crtc_state->dpll_hw_state.pll10 = + PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT) + | PORT_PLL_DCO_AMP_OVR_EN_H; crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 724b0e3a5d37..5ba35bb8e1a5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -409,7 +409,7 @@ static const intel_limit_t intel_limits_chv = { static const intel_limit_t intel_limits_bxt = { /* FIXME: find real dot limits */ .dot = { .min = 0, .max = INT_MAX }, - .vco = { .min = 4800000, .max = 6480000 }, + .vco = { .min = 4800000, .max = 6700000 }, .n = { .min = 1, .max = 1 }, .m1 = { .min = 2, .max = 2 }, /* FIXME: find real m2 limits */ -- cgit v1.3-6-gb490 From 919032ec7c758fd4d65f2a141d1e0a10152198c9 Mon Sep 17 00:00:00 2001 From: Abdiel Janulgue Date: Tue, 16 Jun 2015 13:39:40 +0300 Subject: drm/i915: Enable resource streamer bits on MI_BATCH_BUFFER_START Adds support for enabling the resource streamer on the legacy ringbuffer for HSW and GEN8. Reviewed-by: Chris Wilson Signed-off-by: Abdiel Janulgue Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 8 ++++++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ac8436fc6ced..b932e170c977 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -361,6 +361,7 @@ #define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) #define MI_BATCH_GTT (2<<6) /* aliased with (1<<7) on gen4 */ #define MI_BATCH_BUFFER_START_GEN8 MI_INSTR(0x31, 1) +#define MI_BATCH_RESOURCE_STREAMER (1<<10) #define MI_PREDICATE_SRC0 (0x2400) #define MI_PREDICATE_SRC1 (0x2408) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e39c8912f673..bddc9032e17e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2448,7 +2448,9 @@ gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, return ret; /* FIXME(BDW): Address space and security selectors. */ - intel_ring_emit(ring, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8)); + intel_ring_emit(ring, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8) | + (dispatch_flags & I915_DISPATCH_RS ? + MI_BATCH_RESOURCE_STREAMER : 0)); intel_ring_emit(ring, lower_32_bits(offset)); intel_ring_emit(ring, upper_32_bits(offset)); intel_ring_emit(ring, MI_NOOP); @@ -2472,7 +2474,9 @@ hsw_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, intel_ring_emit(ring, MI_BATCH_BUFFER_START | (dispatch_flags & I915_DISPATCH_SECURE ? - 0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW)); + 0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW) | + (dispatch_flags & I915_DISPATCH_RS ? + MI_BATCH_RESOURCE_STREAMER : 0)); /* bit0-7 is the length on GEN6+ */ intel_ring_emit(ring, offset); intel_ring_advance(ring); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 304cac4caf1c..0ea89ea30182 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -199,6 +199,7 @@ struct intel_engine_cs { unsigned dispatch_flags); #define I915_DISPATCH_SECURE 0x1 #define I915_DISPATCH_PINNED 0x2 +#define I915_DISPATCH_RS 0x4 void (*cleanup)(struct intel_engine_cs *ring); /* GEN8 signal/wait table - never trust comments! -- cgit v1.3-6-gb490 From 4c436d55b279bbc6b02aac02e7dc683fc09f884e Mon Sep 17 00:00:00 2001 From: Abdiel Janulgue Date: Tue, 16 Jun 2015 13:39:41 +0300 Subject: drm/i915: Enable Resource Streamer state save/restore on MI_SET_CONTEXT Also clarify comments on context size that the extra state for Resource Streamer is included. v2: Don't remove the extended save/restore enabled for older platforms. (Ville) Use new MI_SET_CONTEXT defines for HSW RS save/restore state instead of extended save/restore. (Daniel) Suggested-by: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Abdiel Janulgue Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 4 +++- drivers/gpu/drm/i915/i915_reg.h | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index a7e58a8ae770..4256b8e97e40 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -501,7 +501,9 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) } /* These flags are for resource streamer on HSW+ */ - if (!IS_HASWELL(ring->dev) && INTEL_INFO(ring->dev)->gen < 8) + if (IS_HASWELL(ring->dev) || INTEL_INFO(ring->dev)->gen >= 8) + flags |= (HSW_MI_RS_SAVE_STATE_EN | HSW_MI_RS_RESTORE_STATE_EN); + else if (INTEL_INFO(ring->dev)->gen < 8) flags |= (MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b932e170c977..45ff3d3e79c8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -321,6 +321,8 @@ #define MI_RESTORE_EXT_STATE_EN (1<<2) #define MI_FORCE_RESTORE (1<<1) #define MI_RESTORE_INHIBIT (1<<0) +#define HSW_MI_RS_SAVE_STATE_EN (1<<3) +#define HSW_MI_RS_RESTORE_STATE_EN (1<<2) #define MI_SEMAPHORE_SIGNAL MI_INSTR(0x1b, 0) /* GEN8+ */ #define MI_SEMAPHORE_TARGET(engine) ((engine)<<15) #define MI_SEMAPHORE_WAIT MI_INSTR(0x1c, 2) /* GEN8+ */ @@ -2803,7 +2805,8 @@ enum skl_disp_power_wells { * valid. Now, docs explain in dwords what is in the context object. The full * size is 70720 bytes, however, the power context and execlist context will * never be saved (power context is stored elsewhere, and execlists don't work - * on HSW) - so the final size is 66944 bytes, which rounds to 17 pages. + * on HSW) - so the final size, including the extra state required for the + * Resource Streamer, is 66944 bytes, which rounds to 17 pages. */ #define HSW_CXT_TOTAL_SIZE (17 * PAGE_SIZE) /* Same as Haswell, but 72064 bytes now. */ -- cgit v1.3-6-gb490 From 6922528a04a810b2889e82a4dc17eab920379117 Mon Sep 17 00:00:00 2001 From: Abdiel Janulgue Date: Tue, 16 Jun 2015 13:39:42 +0300 Subject: drm/i915: Enable resource streamer on Execlists GEN8 and above uses Execlists by default instead of the legacy ringbuffer for batch execution. This patch enables the resource streamer bits when required. Patch is based on the initial work by Minu Mathai This version also adds the required bits to enable GEN8 Resource Streamer context save and restore for Execlists. Cc: ville.syrjala@linux.intel.com Signed-off-by: Abdiel Janulgue Reviewed-by: Arun Siluvery Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 8 ++++++-- drivers/gpu/drm/i915/intel_lrc.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 22e9f85f40e4..0160bec1e7ba 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1426,7 +1426,10 @@ static int gen8_emit_bb_start(struct drm_i915_gem_request *req, return ret; /* FIXME(BDW): Address space and security selectors. */ - intel_logical_ring_emit(ringbuf, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8)); + intel_logical_ring_emit(ringbuf, MI_BATCH_BUFFER_START_GEN8 | + (ppgtt<<8) | + (dispatch_flags & I915_DISPATCH_RS ? + MI_BATCH_RESOURCE_STREAMER : 0)); intel_logical_ring_emit(ringbuf, lower_32_bits(offset)); intel_logical_ring_emit(ringbuf, upper_32_bits(offset)); intel_logical_ring_emit(ringbuf, MI_NOOP); @@ -2019,7 +2022,8 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o reg_state[CTX_CONTEXT_CONTROL] = RING_CONTEXT_CONTROL(ring); reg_state[CTX_CONTEXT_CONTROL+1] = _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH | - CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT); + CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | + CTX_CTRL_RS_CTX_ENABLE); reg_state[CTX_RING_HEAD] = RING_HEAD(ring->mmio_base); reg_state[CTX_RING_HEAD+1] = 0; reg_state[CTX_RING_TAIL] = RING_TAIL(ring->mmio_base); diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index f59940ac1cfc..d3dd3ac33aef 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -32,6 +32,7 @@ #define RING_CONTEXT_CONTROL(ring) ((ring)->mmio_base+0x244) #define CTX_CTRL_INHIBIT_SYN_CTX_SWITCH (1 << 3) #define CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT (1 << 0) +#define CTX_CTRL_RS_CTX_ENABLE (1 << 1) #define RING_CONTEXT_STATUS_BUF(ring) ((ring)->mmio_base+0x370) #define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0) -- cgit v1.3-6-gb490 From 6170511a917679f8a1324f031a0a40f851ae91e9 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Tue, 30 Jun 2015 12:57:14 -0500 Subject: crypto: ccp - Provide support to autoload CCP driver Add the necessary module device tables to the platform support to allow for autoloading of the CCP driver. This will allow for the CCP's hwrng support to be available without having to manually load the driver. The module device table entry for the pci support is already present. Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-platform.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/crypto/ccp/ccp-platform.c b/drivers/crypto/ccp/ccp-platform.c index f2e6de361fd1..bb241c3ab6b9 100644 --- a/drivers/crypto/ccp/ccp-platform.c +++ b/drivers/crypto/ccp/ccp-platform.c @@ -216,6 +216,7 @@ static const struct acpi_device_id ccp_acpi_match[] = { { "AMDI0C00", 0 }, { }, }; +MODULE_DEVICE_TABLE(acpi, ccp_acpi_match); #endif #ifdef CONFIG_OF @@ -223,6 +224,7 @@ static const struct of_device_id ccp_of_match[] = { { .compatible = "amd,ccp-seattle-v1a" }, { }, }; +MODULE_DEVICE_TABLE(of, ccp_of_match); #endif static struct platform_driver ccp_platform_driver = { -- cgit v1.3-6-gb490 From fa9a9a084a2153095d0433188be232b0127ab23c Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Thu, 2 Jul 2015 15:38:48 -0700 Subject: crypto: nx - nx842_OF_upd_status should return ENODEV if device is not 'okay' The current documention mentions explicitly that EINVAL should be returned if the device is not available, but nx842_OF_upd_status() always returns 0. However, nx842_probe() specifically checks for non-ENODEV returns from nx842_of_upd() (which in turn calls nx842_OF_upd_status()) and emits an extra error in that case. It seems like the proper return code of a disabled device is ENODEV. Signed-off-by: Nishanth Aravamudan Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-pseries.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index 3040a6091bf2..819c23c546e3 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c @@ -556,7 +556,7 @@ static int nx842_OF_set_defaults(struct nx842_devdata *devdata) * * Returns: * 0 - Device is available - * -EINVAL - Device is not available + * -ENODEV - Device is not available */ static int nx842_OF_upd_status(struct nx842_devdata *devdata, struct property *prop) { @@ -569,6 +569,7 @@ static int nx842_OF_upd_status(struct nx842_devdata *devdata, dev_info(devdata->dev, "%s: status '%s' is not 'okay'\n", __func__, status); devdata->status = UNAVAILABLE; + ret = -ENODEV; } return ret; -- cgit v1.3-6-gb490 From ec13bcbe07a202c32ea74927e27479aa4d19d1b1 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Thu, 2 Jul 2015 15:39:21 -0700 Subject: crypto: nx - rename nx842_{init, exit} to nx842_pseries_{init, exit} While there is no technical reason that both nx-842.c and nx-842-pseries.c can have the same name for the init/exit functions, it is a bit confusing with initcall_debug. Rename the pseries specific functions appropriately Signed-off-by: Nishanth Aravamudan Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-pseries.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index 819c23c546e3..e17f4d2e96e0 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c @@ -1080,7 +1080,7 @@ static struct vio_driver nx842_vio_driver = { .id_table = nx842_vio_driver_ids, }; -static int __init nx842_init(void) +static int __init nx842_pseries_init(void) { struct nx842_devdata *new_devdata; int ret; @@ -1116,9 +1116,9 @@ static int __init nx842_init(void) return 0; } -module_init(nx842_init); +module_init(nx842_pseries_init); -static void __exit nx842_exit(void) +static void __exit nx842_pseries_exit(void) { struct nx842_devdata *old_devdata; unsigned long flags; @@ -1137,5 +1137,5 @@ static void __exit nx842_exit(void) vio_unregister_driver(&nx842_vio_driver); } -module_exit(nx842_exit); +module_exit(nx842_pseries_exit); -- cgit v1.3-6-gb490 From 7abd75bf7ac6d04e0389472cf2cd3a8bf53e4894 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Thu, 2 Jul 2015 15:40:09 -0700 Subject: crypto: nx - do not emit extra output if status is disabled If the device-tree indicates the nx-842 device's status is 'disabled', we emit two messages: nx_compress_pseries ibm,compression-v1: nx842_OF_upd_status: status 'disabled' is not 'okay'. nx_compress_pseries ibm,compression-v1: nx842_OF_upd: device disabled Given that 'disabled' is a valid state, and we are going to emit that the device is disabled, only print out a non-'okay' status if it is not 'disabled'. Signed-off-by: Nishanth Aravamudan Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-pseries.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index e17f4d2e96e0..b84b0ceeb46e 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c @@ -566,8 +566,14 @@ static int nx842_OF_upd_status(struct nx842_devdata *devdata, if (!strncmp(status, "okay", (size_t)prop->length)) { devdata->status = AVAILABLE; } else { - dev_info(devdata->dev, "%s: status '%s' is not 'okay'\n", + /* + * Caller will log that the device is disabled, so only + * output if there is an unexpected status. + */ + if (strncmp(status, "disabled", (size_t)prop->length)) { + dev_info(devdata->dev, "%s: status '%s' is not 'okay'\n", __func__, status); + } devdata->status = UNAVAILABLE; ret = -ENODEV; } -- cgit v1.3-6-gb490 From a9ed33ca075f712cc7fd96eb84e3d322012fcaaf Mon Sep 17 00:00:00 2001 From: Abdiel Janulgue Date: Wed, 1 Jul 2015 10:12:23 +0300 Subject: drm/i915: Expose I915_EXEC_RESOURCE_STREAMER flag and getparam Ensures that the batch buffer is executed by the resource streamer. And will let userspace know whether Resource Streamer is supported in the kernel. v2: Don't skip 1<<15 for the exec flags (Jani Nikula) v3: Use HAS_RESOURCE_STREAMER macro for execbuf validation (Chris Wilson) (from getparam patch) v2: Update I915_PARAM_HAS_RESOURCE_STREAMER so it's after I915_PARAM_HAS_GPU_RESET. v3: Only advertise RS support for hardware that supports it. v4: Add HAS_RESOURCE_STREAMER() macro (Chris) Testcase: igt/gem_exec_params Cc: Jani Nikula Cc: Kenneth Graunke Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Abdiel Janulgue [danvet: squash in getparam patch since it'd break bisect, suggested by Chris.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 14 ++++++++++++++ include/uapi/drm/i915_drm.h | 8 +++++++- 4 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index c5349fa3fcce..a42f16592433 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -167,6 +167,9 @@ static int i915_getparam(struct drm_device *dev, void *data, value = i915.enable_hangcheck && intel_has_gpu_reset(dev); break; + case I915_PARAM_HAS_RESOURCE_STREAMER: + value = HAS_RESOURCE_STREAMER(dev); + break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 950a9811a16f..63daf4cd2477 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2539,6 +2539,9 @@ struct drm_i915_cmd_table { #define HAS_CSR(dev) (IS_SKYLAKE(dev)) +#define HAS_RESOURCE_STREAMER(dev) (IS_HASWELL(dev) || \ + INTEL_INFO(dev)->gen >= 8) + #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 600db7441847..83577c615962 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1490,6 +1490,20 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, return -EINVAL; } + if (args->flags & I915_EXEC_RESOURCE_STREAMER) { + if (!HAS_RESOURCE_STREAMER(dev)) { + DRM_DEBUG("RS is only allowed for Haswell, Gen8 and above\n"); + return -EINVAL; + } + if (ring->id != RCS) { + DRM_DEBUG("RS is not available on %s\n", + ring->name); + return -EINVAL; + } + + dispatch_flags |= I915_DISPATCH_RS; + } + intel_runtime_pm_get(dev_priv); ret = i915_mutex_lock_interruptible(dev); diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index f88cc1cac5d9..e7c29f1659ad 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -355,6 +355,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_SUBSLICE_TOTAL 33 #define I915_PARAM_EU_TOTAL 34 #define I915_PARAM_HAS_GPU_RESET 35 +#define I915_PARAM_HAS_RESOURCE_STREAMER 36 typedef struct drm_i915_getparam { int param; @@ -765,7 +766,12 @@ struct drm_i915_gem_execbuffer2 { #define I915_EXEC_BSD_RING1 (1<<13) #define I915_EXEC_BSD_RING2 (2<<13) -#define __I915_EXEC_UNKNOWN_FLAGS -(1<<15) +/** Tell the kernel that the batchbuffer is processed by + * the resource streamer. + */ +#define I915_EXEC_RESOURCE_STREAMER (1<<15) + +#define __I915_EXEC_UNKNOWN_FLAGS -(I915_EXEC_RESOURCE_STREAMER<<1) #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define i915_execbuffer2_set_context_id(eb2, context) \ -- cgit v1.3-6-gb490 From b17d1bf16cc72a374a48d748940f700009d40ff4 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 11 Feb 2015 11:52:37 +0100 Subject: gpio: make flags mandatory for gpiod_get functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that all[1] users of the gpiod_get functions are converted to make use of the up to now optional flags parameter, make it mandatory which allows to remove some cpp magic. [1] all but etraxfs-uart which is broken anyhow and I'm allowed to ignore it by Jesper Nilsson :-) Acked-by: Alexandre Courbot Signed-off-by: Uwe Kleine-König --- drivers/gpio/devres.c | 18 +++++----- drivers/gpio/gpiolib.c | 16 ++++----- include/linux/gpio/consumer.h | 82 ++++++++++++------------------------------- 3 files changed, 40 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 07ba82317ece..903fcf4d04a0 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -59,13 +59,13 @@ static int devm_gpiod_match_array(struct device *dev, void *res, void *data) * automatically disposed on driver detach. See gpiod_get() for detailed * information about behavior and return values. */ -struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags) { return devm_gpiod_get_index(dev, con_id, 0, flags); } -EXPORT_SYMBOL(__devm_gpiod_get); +EXPORT_SYMBOL(devm_gpiod_get); /** * devm_gpiod_get_optional - Resource-managed gpiod_get_optional() @@ -77,13 +77,13 @@ EXPORT_SYMBOL(__devm_gpiod_get); * are automatically disposed on driver detach. See gpiod_get_optional() for * detailed information about behavior and return values. */ -struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags) { return devm_gpiod_get_index_optional(dev, con_id, 0, flags); } -EXPORT_SYMBOL(__devm_gpiod_get_optional); +EXPORT_SYMBOL(devm_gpiod_get_optional); /** * devm_gpiod_get_index - Resource-managed gpiod_get_index() @@ -96,7 +96,7 @@ EXPORT_SYMBOL(__devm_gpiod_get_optional); * automatically disposed on driver detach. See gpiod_get_index() for detailed * information about behavior and return values. */ -struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags) @@ -120,7 +120,7 @@ struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev, return desc; } -EXPORT_SYMBOL(__devm_gpiod_get_index); +EXPORT_SYMBOL(devm_gpiod_get_index); /** * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node @@ -182,10 +182,10 @@ EXPORT_SYMBOL(devm_get_gpiod_from_child); * gpiod_get_index_optional() for detailed information about behavior and * return values. */ -struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, - enum gpiod_flags flags) + enum gpiod_flags flags) { struct gpio_desc *desc; @@ -197,7 +197,7 @@ struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *de return desc; } -EXPORT_SYMBOL(__devm_gpiod_get_index_optional); +EXPORT_SYMBOL(devm_gpiod_get_index_optional); /** * devm_gpiod_get_array - Resource-managed gpiod_get_array() diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bf4bd1d120c3..4b2f98168225 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1894,12 +1894,12 @@ EXPORT_SYMBOL_GPL(gpiod_count); * dev, -ENOENT if no GPIO has been assigned to the requested function, or * another IS_ERR() code if an error occurred while trying to acquire the GPIO. */ -struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id, +struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags) { return gpiod_get_index(dev, con_id, 0, flags); } -EXPORT_SYMBOL_GPL(__gpiod_get); +EXPORT_SYMBOL_GPL(gpiod_get); /** * gpiod_get_optional - obtain an optional GPIO for a given GPIO function @@ -1911,13 +1911,13 @@ EXPORT_SYMBOL_GPL(__gpiod_get); * the requested function it will return NULL. This is convenient for drivers * that need to handle optional GPIOs. */ -struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev, +struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags) { return gpiod_get_index_optional(dev, con_id, 0, flags); } -EXPORT_SYMBOL_GPL(__gpiod_get_optional); +EXPORT_SYMBOL_GPL(gpiod_get_optional); /** @@ -1974,7 +1974,7 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, * requested function and/or index, or another IS_ERR() code if an error * occurred while trying to acquire the GPIO. */ -struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags) @@ -2023,7 +2023,7 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, return desc; } -EXPORT_SYMBOL_GPL(__gpiod_get_index); +EXPORT_SYMBOL_GPL(gpiod_get_index); /** * fwnode_get_named_gpiod - obtain a GPIO from firmware node @@ -2092,7 +2092,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod); * specified index was assigned to the requested function it will return NULL. * This is convenient for drivers that need to handle optional GPIOs. */ -struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, +struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags) @@ -2107,7 +2107,7 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, return desc; } -EXPORT_SYMBOL_GPL(__gpiod_get_index_optional); +EXPORT_SYMBOL_GPL(gpiod_get_index_optional); /** * gpiod_hog - Hog the specified GPIO desc given the provided flags diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index adac255aee86..14cac67c2012 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -47,17 +47,17 @@ enum gpiod_flags { int gpiod_count(struct device *dev, const char *con_id); /* Acquire and dispose GPIOs */ -struct gpio_desc *__must_check __gpiod_get(struct device *dev, +struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags); -struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags); -struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev, +struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags); -struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, +struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags); @@ -70,18 +70,18 @@ struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev, void gpiod_put(struct gpio_desc *desc); void gpiod_put_array(struct gpio_descs *descs); -struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags); -struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags); -struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags); struct gpio_desc *__must_check -__devm_gpiod_get_index_optional(struct device *dev, const char *con_id, +devm_gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags); struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, const char *con_id, @@ -146,31 +146,31 @@ static inline int gpiod_count(struct device *dev, const char *con_id) return 0; } -static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev, - const char *con_id, - enum gpiod_flags flags) +static inline struct gpio_desc *__must_check gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); } static inline struct gpio_desc *__must_check -__gpiod_get_index(struct device *dev, - const char *con_id, - unsigned int idx, - enum gpiod_flags flags) +gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); } static inline struct gpio_desc *__must_check -__gpiod_get_optional(struct device *dev, const char *con_id, - enum gpiod_flags flags) +gpiod_get_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); } static inline struct gpio_desc *__must_check -__gpiod_get_index_optional(struct device *dev, const char *con_id, - unsigned int index, enum gpiod_flags flags) +gpiod_get_index_optional(struct device *dev, const char *con_id, + unsigned int index, enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); } @@ -206,7 +206,7 @@ static inline void gpiod_put_array(struct gpio_descs *descs) } static inline struct gpio_desc *__must_check -__devm_gpiod_get(struct device *dev, +devm_gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags) { @@ -214,7 +214,7 @@ __devm_gpiod_get(struct device *dev, } static inline struct gpio_desc *__must_check -__devm_gpiod_get_index(struct device *dev, +devm_gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags) @@ -223,14 +223,14 @@ __devm_gpiod_get_index(struct device *dev, } static inline struct gpio_desc *__must_check -__devm_gpiod_get_optional(struct device *dev, const char *con_id, +devm_gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); } static inline struct gpio_desc *__must_check -__devm_gpiod_get_index_optional(struct device *dev, const char *con_id, +devm_gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); @@ -424,42 +424,6 @@ static inline struct gpio_desc *devm_get_gpiod_from_child( #endif /* CONFIG_GPIOLIB */ -/* - * Vararg-hacks! This is done to transition the kernel to always pass - * the options flags argument to the below functions. During a transition - * phase these vararg macros make both old-and-newstyle code compile, - * but when all calls to the elder API are removed, these should go away - * and the __gpiod_get() etc functions above be renamed just gpiod_get() - * etc. - */ -#define __gpiod_get(dev, con_id, flags, ...) __gpiod_get(dev, con_id, flags) -#define gpiod_get(varargs...) __gpiod_get(varargs, GPIOD_ASIS) -#define __gpiod_get_index(dev, con_id, index, flags, ...) \ - __gpiod_get_index(dev, con_id, index, flags) -#define gpiod_get_index(varargs...) __gpiod_get_index(varargs, GPIOD_ASIS) -#define __gpiod_get_optional(dev, con_id, flags, ...) \ - __gpiod_get_optional(dev, con_id, flags) -#define gpiod_get_optional(varargs...) __gpiod_get_optional(varargs, GPIOD_ASIS) -#define __gpiod_get_index_optional(dev, con_id, index, flags, ...) \ - __gpiod_get_index_optional(dev, con_id, index, flags) -#define gpiod_get_index_optional(varargs...) \ - __gpiod_get_index_optional(varargs, GPIOD_ASIS) -#define __devm_gpiod_get(dev, con_id, flags, ...) \ - __devm_gpiod_get(dev, con_id, flags) -#define devm_gpiod_get(varargs...) __devm_gpiod_get(varargs, GPIOD_ASIS) -#define __devm_gpiod_get_index(dev, con_id, index, flags, ...) \ - __devm_gpiod_get_index(dev, con_id, index, flags) -#define devm_gpiod_get_index(varargs...) \ - __devm_gpiod_get_index(varargs, GPIOD_ASIS) -#define __devm_gpiod_get_optional(dev, con_id, flags, ...) \ - __devm_gpiod_get_optional(dev, con_id, flags) -#define devm_gpiod_get_optional(varargs...) \ - __devm_gpiod_get_optional(varargs, GPIOD_ASIS) -#define __devm_gpiod_get_index_optional(dev, con_id, index, flags, ...) \ - __devm_gpiod_get_index_optional(dev, con_id, index, flags) -#define devm_gpiod_get_index_optional(varargs...) \ - __devm_gpiod_get_index_optional(varargs, GPIOD_ASIS) - #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) int gpiod_export(struct gpio_desc *desc, bool direction_may_change); -- cgit v1.3-6-gb490 From c30400fcffb70d17bbf33eaff5020b83111bd66c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 Jul 2015 12:31:30 -0300 Subject: drm/i915: set FDI translations to NULL on SKL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/gpu/drm/i915/intel_ddi.c: In function ‘intel_prepare_ddi’: drivers/gpu/drm/i915/intel_ddi.c:517:6: warning: ‘ddi_translations_fdi’ may be used uninitialized in this function [-Wmaybe-uninitialized] if (ddi_translations_fdi) ^ drivers/gpu/drm/i915/intel_ddi.c:446:30: note: ‘ddi_translations_fdi’ was declared here const struct ddi_buf_trans *ddi_translations_fdi; ^ This line used to be there, but was removed by: commit f8896f5d58e64bfd3c2b5f7c5ba5c3f3967e93c7 Author: David Weinehall Date: Thu Jun 25 11:11:03 2015 +030 drm/i915/skl: Buffer translation improvements Cc: David Weinehall Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index db22f0173027..9a40bfb20e0c 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -458,6 +458,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, INTEL_OUTPUT_HDMI); return; } else if (IS_SKYLAKE(dev)) { + ddi_translations_fdi = NULL; ddi_translations_dp = skl_get_buf_trans_dp(dev, &n_dp_entries); ddi_translations_edp = -- cgit v1.3-6-gb490 From 3e6da4a9d9005fbc83420686fb897bd8ad749e91 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 16:05:27 +0300 Subject: drm/i915/audio: clarify HD audio documentation wrt modeset Clarify that audio enable/disable sequences are part of the modeset sequence. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index c4312177b0ee..c4397c1e7e4f 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -41,7 +41,8 @@ * * The disable sequences must be performed before disabling the transcoder or * port. The enable sequences may only be performed after enabling the - * transcoder and port, and after completed link training. + * transcoder and port, and after completed link training. Therefore the audio + * enable/disable sequences are part of the modeset sequence. * * The codec and controller sequences could be done either parallel or serial, * but generally the ELDV/PD change in the codec sequence indicates to the audio -- cgit v1.3-6-gb490 From 856974a401bacf4fee1f3e3b2f601b7abfd5fa2a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 16:05:28 +0300 Subject: drm/i915/hotplug: document the hotplug handling in the driver Add an overview of the drm/i915 hotplug handling. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 5 +++++ drivers/gpu/drm/i915/intel_hotplug.c | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) (limited to 'drivers') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index c0312cbd023d..e82205ee3d5f 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4044,6 +4044,11 @@ int num_ioctls; probing, so those sections fully apply. + + Hotplug +!Pdrivers/gpu/drm/i915/intel_hotplug.c Hotplug +!Idrivers/gpu/drm/i915/intel_hotplug.c + High Definition Audio !Pdrivers/gpu/drm/i915/intel_audio.c High Definition Audio over HDMI and Display Port diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 3c53aac71d98..bac91a158ca2 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -29,6 +29,45 @@ #include "i915_drv.h" #include "intel_drv.h" +/** + * DOC: Hotplug + * + * Simply put, hotplug occurs when a display is connected to or disconnected + * from the system. However, there may be adapters and docking stations and + * Display Port short pulses and MST devices involved, complicating matters. + * + * Hotplug in i915 is handled in many different levels of abstraction. + * + * The platform dependent interrupt handling code in i915_irq.c enables, + * disables, and does preliminary handling of the interrupts. The interrupt + * handlers gather the hotplug detect (HPD) information from relevant registers + * into a platform independent mask of hotplug pins that have fired. + * + * The platform independent interrupt handler intel_hpd_irq_handler() in + * intel_hotplug.c does hotplug irq storm detection and mitigation, and passes + * further processing to appropriate bottom halves (Display Port specific and + * regular hotplug). + * + * The Display Port work function i915_digport_work_func() calls into + * intel_dp_hpd_pulse() via hooks, which handles DP short pulses and DP MST long + * pulses, with failures and non-MST long pulses triggering regular hotplug + * processing on the connector. + * + * The regular hotplug work function i915_hotplug_work_func() calls connector + * detect hooks, and, if connector status changes, triggers sending of hotplug + * uevent to userspace via drm_kms_helper_hotplug_event(). + * + * Finally, the userspace is responsible for triggering a modeset upon receiving + * the hotplug uevent, disabling or enabling the crtc as needed. + * + * The hotplug interrupt storm detection and mitigation code keeps track of the + * number of interrupts per hotplug pin per a period of time, and if the number + * of interrupts exceeds a certain threshold, the interrupt is disabled for a + * while before being re-enabled. The intention is to mitigate issues raising + * from broken hardware triggering massive amounts of interrupts and grinding + * the system to a halt. + */ + enum port intel_hpd_pin_to_port(enum hpd_pin pin) { switch (pin) { -- cgit v1.3-6-gb490 From 2d80391d36e698e8dabc3b3ff0969fc6fde156c4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 17:43:21 +0300 Subject: drm/i915/opregion: use BUILD_BUG_ON to verify mailbox struct sizes Signed-off-by: Jani Nikula Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 71e87abdcae7..c4756a2d77bb 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -862,6 +862,11 @@ int intel_opregion_setup(struct drm_device *dev) char buf[sizeof(OPREGION_SIGNATURE)]; int err = 0; + BUILD_BUG_ON(sizeof(struct opregion_header) != 0x100); + BUILD_BUG_ON(sizeof(struct opregion_acpi) != 0x100); + BUILD_BUG_ON(sizeof(struct opregion_swsci) != 0x100); + BUILD_BUG_ON(sizeof(struct opregion_asle) != 0x100); + pci_read_config_dword(dev->pdev, PCI_ASLS, &asls); DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls); if (asls == 0) { -- cgit v1.3-6-gb490 From f6a430d8ee8dba13807b75845478a1920187840b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 17:43:22 +0300 Subject: drm/i915/opregion: add new opregion stuff Inluding extended didl and cpdl fields Present since opregion version 3.0. Signed-off-by: Jani Nikula Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index c4756a2d77bb..d05a504fd176 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -53,6 +53,7 @@ #define MBOX_ACPI (1<<0) #define MBOX_SWSCI (1<<1) #define MBOX_ASLE (1<<2) +#define MBOX_ASLE_EXT (1<<4) struct opregion_header { u8 signature[16]; @@ -62,7 +63,10 @@ struct opregion_header { u8 vbios_ver[16]; u8 driver_ver[16]; u32 mboxes; - u8 reserved[164]; + u32 driver_model; + u32 pcon; + u8 dver[32]; + u8 rsvd[124]; } __packed; /* OpRegion mailbox #1: public ACPI methods */ @@ -84,7 +88,9 @@ struct opregion_acpi { u32 evts; /* ASL supported events */ u32 cnot; /* current OS notification */ u32 nrdy; /* driver status */ - u8 rsvd2[60]; + u32 did2[7]; /* extended supported display devices ID list */ + u32 cpd2[7]; /* extended attached display devices list */ + u8 rsvd2[4]; } __packed; /* OpRegion mailbox #2: SWSCI */ @@ -113,7 +119,10 @@ struct opregion_asle { u32 pcft; /* power conservation features */ u32 srot; /* supported rotation angles */ u32 iuer; /* IUER events */ - u8 rsvd[86]; + u64 fdss; + u32 fdsp; + u32 stat; + u8 rsvd[70]; } __packed; /* Driver readiness indicator */ -- cgit v1.3-6-gb490 From b4fe8156a72da0030f18fd16ce7ded3747f932bb Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 17:43:23 +0300 Subject: drm/i915/opregion: prefer DRM logging functions over pr_warn and dev_dbg Conform to same style as the rest of the driver. Signed-off-by: Jani Nikula Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index d05a504fd176..5ab75a6a4131 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -25,8 +25,6 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include @@ -658,14 +656,13 @@ static void intel_didl_outputs(struct drm_device *dev) } if (!acpi_video_bus) { - pr_warn("No ACPI video bus found\n"); + DRM_ERROR("No ACPI video bus found\n"); return; } list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { if (i >= 8) { - dev_dbg(&dev->pdev->dev, - "More than 8 outputs detected via ACPI\n"); + DRM_DEBUG_KMS("More than 8 outputs detected via ACPI\n"); return; } status = @@ -691,8 +688,7 @@ blind_set: list_for_each_entry(connector, &dev->mode_config.connector_list, head) { int output_type = ACPI_OTHER_OUTPUT; if (i >= 8) { - dev_dbg(&dev->pdev->dev, - "More than 8 outputs in connector list\n"); + DRM_DEBUG_KMS("More than 8 outputs in connector list\n"); return; } switch (connector->connector_type) { -- cgit v1.3-6-gb490 From d5cbb22fcd0685944bbac80935b59df83e33e28e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 17:43:24 +0300 Subject: drm/i915/opregion: abstract didl and did2 getter and setter Make it easier to handle the extended didl. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 50 +++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 5ab75a6a4131..6235d9acce45 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -628,6 +628,38 @@ static struct notifier_block intel_opregion_notifier = { * (version 3) */ +static u32 get_did(struct intel_opregion *opregion, int i) +{ + u32 did; + + if (i < ARRAY_SIZE(opregion->acpi->didl)) { + did = ioread32(&opregion->acpi->didl[i]); + } else { + i -= ARRAY_SIZE(opregion->acpi->didl); + + if (WARN_ON(i >= ARRAY_SIZE(opregion->acpi->did2))) + return 0; + + did = ioread32(&opregion->acpi->did2[i]); + } + + return did; +} + +static void set_did(struct intel_opregion *opregion, int i, u32 val) +{ + if (i < ARRAY_SIZE(opregion->acpi->didl)) { + iowrite32(val, &opregion->acpi->didl[i]); + } else { + i -= ARRAY_SIZE(opregion->acpi->didl); + + if (WARN_ON(i >= ARRAY_SIZE(opregion->acpi->did2))) + return; + + iowrite32(val, &opregion->acpi->did2[i]); + } +} + static void intel_didl_outputs(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -665,22 +697,19 @@ static void intel_didl_outputs(struct drm_device *dev) DRM_DEBUG_KMS("More than 8 outputs detected via ACPI\n"); return; } - status = - acpi_evaluate_integer(acpi_cdev->handle, "_ADR", - NULL, &device_id); + status = acpi_evaluate_integer(acpi_cdev->handle, "_ADR", + NULL, &device_id); if (ACPI_SUCCESS(status)) { if (!device_id) goto blind_set; - iowrite32((u32)(device_id & 0x0f0f), - &opregion->acpi->didl[i]); - i++; + set_did(opregion, i++, (u32)(device_id & 0x0f0f)); } } end: /* If fewer than 8 outputs, the list must be null terminated */ if (i < 8) - iowrite32(0, &opregion->acpi->didl[i]); + set_did(opregion, i, 0); return; blind_set: @@ -713,9 +742,8 @@ blind_set: output_type = ACPI_LVDS_OUTPUT; break; } - temp = ioread32(&opregion->acpi->didl[i]); - iowrite32(temp | (1<<31) | output_type | i, - &opregion->acpi->didl[i]); + temp = get_did(opregion, i); + set_did(opregion, i, temp | (1 << 31) | output_type | i); i++; } goto end; @@ -735,7 +763,7 @@ static void intel_setup_cadls(struct drm_device *dev) * display switching hotkeys. Just like DIDL, CADL is NULL-terminated if * there are less than eight devices. */ do { - disp_id = ioread32(&opregion->acpi->didl[i]); + disp_id = get_did(opregion, i); iowrite32(disp_id, &opregion->acpi->cadl[i]); } while (++i < 8 && disp_id != 0); } -- cgit v1.3-6-gb490 From dfc2066d8f8f2d87c1d8d00024478403c04d4e50 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 17:43:25 +0300 Subject: drm/i915/opregion: start using extended didl Adding support for did2, or the extended support display devices ID list, increases the total to 15. Signed-off-by: Jani Nikula Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 6235d9acce45..7df916e914a4 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -669,7 +669,7 @@ static void intel_didl_outputs(struct drm_device *dev) struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL; unsigned long long device_id; acpi_status status; - u32 temp; + u32 temp, max_outputs; int i = 0; handle = ACPI_HANDLE(&dev->pdev->dev); @@ -692,9 +692,20 @@ static void intel_didl_outputs(struct drm_device *dev) return; } + /* + * In theory, did2, the extended didl, gets added at opregion version + * 3.0. In practice, however, we're supposed to set it for earlier + * versions as well, since a BIOS that doesn't understand did2 should + * not look at it anyway. Use a variable so we can tweak this if a need + * arises later. + */ + max_outputs = ARRAY_SIZE(opregion->acpi->didl) + + ARRAY_SIZE(opregion->acpi->did2); + list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { - if (i >= 8) { - DRM_DEBUG_KMS("More than 8 outputs detected via ACPI\n"); + if (i >= max_outputs) { + DRM_DEBUG_KMS("More than %u outputs detected via ACPI\n", + max_outputs); return; } status = acpi_evaluate_integer(acpi_cdev->handle, "_ADR", @@ -707,8 +718,10 @@ static void intel_didl_outputs(struct drm_device *dev) } end: - /* If fewer than 8 outputs, the list must be null terminated */ - if (i < 8) + DRM_DEBUG_KMS("%d outputs detected\n", i); + + /* If fewer than max outputs, the list must be null terminated */ + if (i < max_outputs) set_did(opregion, i, 0); return; @@ -716,8 +729,9 @@ blind_set: i = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { int output_type = ACPI_OTHER_OUTPUT; - if (i >= 8) { - DRM_DEBUG_KMS("More than 8 outputs in connector list\n"); + if (i >= max_outputs) { + DRM_DEBUG_KMS("More than %u outputs in connector list\n", + max_outputs); return; } switch (connector->connector_type) { -- cgit v1.3-6-gb490 From e72072b6d7a49ea09dd833c3bdaa300e86ab0671 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 3 Jul 2015 11:22:27 +0300 Subject: drm/i915: Drop a spurious intel_pre_plane_update() call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kill the extra intel_pre_plane_update() I accidentally added in commit 852eb00dc44ea2b8896e2fa27c6a36a1f697ba5a Author: Ville Syrjälä Date: Wed Jun 24 22:00:07 2015 +0300 drm/i915: Try to make sure cxsr is disabled around plane enable/disable This fixes a load of warnings from the frontbuffer tracking. Testcase: igt/kms_frontbuffer_tracking/fbc-1p-rte Tested-by: Paulo Zanoni Tested-by: Matt Roper 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, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5ba35bb8e1a5..136b53371878 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13141,8 +13141,6 @@ static int __intel_set_mode(struct drm_atomic_state *state) if (!needs_modeset(crtc->state)) continue; - intel_pre_plane_update(intel_crtc); - any_ms = true; intel_pre_plane_update(intel_crtc); -- cgit v1.3-6-gb490 From e3e30f63389a319ca45161b07eb74e60f1e7ea20 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Jun 2015 06:53:59 -0300 Subject: [media] stk1160: fix sequence handling Fix the sequence counter: we're counting frames, not fields. Also remove the unused 'field' field. That would only be needed if this driver would support V4L2_FIELD_ALTERNATE. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stk1160/stk1160-v4l.c | 2 ++ drivers/media/usb/stk1160/stk1160-video.c | 4 +--- drivers/media/usb/stk1160/stk1160.h | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 4d313ed4c32e..7291cca58704 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -194,6 +194,8 @@ static int stk1160_start_streaming(struct stk1160 *dev) /* Start saa711x */ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); + dev->sequence = 0; + /* Start stk1160 */ stk1160_write_reg(dev, STK1160_DCTRL, 0xb3); stk1160_write_reg(dev, STK1160_DCTRL+3, 0x00); diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 39f1aae209bc..940c3eaea507 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -96,9 +96,7 @@ void stk1160_buffer_done(struct stk1160 *dev) { struct stk1160_buffer *buf = dev->isoc_ctl.buf; - dev->field_count++; - - buf->vb.v4l2_buf.sequence = dev->field_count >> 1; + buf->vb.v4l2_buf.sequence = dev->sequence++; buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; buf->vb.v4l2_buf.bytesused = buf->bytesused; v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index abdea484c998..3922a6cabde2 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -151,8 +151,7 @@ struct stk1160 { v4l2_std_id norm; /* current norm */ struct stk1160_fmt *fmt; /* selected format */ - unsigned int field_count; /* not sure ??? */ - enum v4l2_field field; /* also not sure :/ */ + unsigned int sequence; /* i2c i/o */ struct i2c_adapter i2c_adap; -- cgit v1.3-6-gb490 From 9d1b1f61a49c66145ebbf2844124987118e65632 Mon Sep 17 00:00:00 2001 From: Krzysztof Hałasa Date: Mon, 8 Jun 2015 10:35:05 -0300 Subject: [media] SOLO6x10: Fix G.723 minimum audio period count The period count is fixed, don't confuse ALSA. Signed-off-by: Krzysztof Ha?asa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-g723.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 7ddc76709caa..4a37a1c51c48 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -48,10 +48,8 @@ /* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page * is broken down to 20 * 48 byte regions (one for each channel possible) * with the rest of the page being dummy data. */ -#define G723_MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX) +#define PERIODS G723_FDMA_PAGES #define G723_INTR_ORDER 4 /* 0 - 4 */ -#define PERIODS_MIN (1 << G723_INTR_ORDER) -#define PERIODS_MAX G723_FDMA_PAGES struct solo_snd_pcm { int on; @@ -130,11 +128,11 @@ static const struct snd_pcm_hardware snd_solo_pcm_hw = { .rate_max = SAMPLERATE, .channels_min = 1, .channels_max = 1, - .buffer_bytes_max = G723_MAX_BUFFER, + .buffer_bytes_max = G723_PERIOD_BYTES * PERIODS, .period_bytes_min = G723_PERIOD_BYTES, .period_bytes_max = G723_PERIOD_BYTES, - .periods_min = PERIODS_MIN, - .periods_max = PERIODS_MAX, + .periods_min = PERIODS, + .periods_max = PERIODS, }; static int snd_solo_pcm_open(struct snd_pcm_substream *ss) @@ -340,7 +338,8 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev) ret = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), - G723_MAX_BUFFER, G723_MAX_BUFFER); + G723_PERIOD_BYTES * PERIODS, + G723_PERIOD_BYTES * PERIODS); if (ret < 0) return ret; -- cgit v1.3-6-gb490 From dd43a6278a9dbda46f56782b54a7a59216a87d23 Mon Sep 17 00:00:00 2001 From: Krzysztof Hałasa Date: Mon, 8 Jun 2015 10:37:15 -0300 Subject: [media] SOLO6x10: unmap registers only after free_irq() Fixes a panic on ARM. Diagnosis by Russell King. Signed-off-by: Krzysztof Ha?asa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index 570d119ea18b..84627e6f7377 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -164,9 +164,9 @@ static void free_solo_dev(struct solo_dev *solo_dev) /* Now cleanup the PCI device */ solo_irq_off(solo_dev, ~0); - pci_iounmap(pdev, solo_dev->reg_base); if (pdev->irq) free_irq(pdev->irq, solo_dev); + pci_iounmap(pdev, solo_dev->reg_base); } pci_release_regions(pdev); -- cgit v1.3-6-gb490 From e1ceb25a1569ce5b61b9c496dd32d038ba8cb936 Mon Sep 17 00:00:00 2001 From: Krzysztof Hałasa Date: Mon, 8 Jun 2015 10:42:24 -0300 Subject: [media] SOLO6x10: remove unneeded register locking and barriers readl() and writel() are atomic, we don't need the spin lock. Also, flushing posted write buffer isn't required. Especially on read :-) Signed-off-by: Krzysztof Ha?asa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-core.c | 1 - drivers/media/pci/solo6x10/solo6x10.h | 26 +------------------------- 2 files changed, 1 insertion(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index 84627e6f7377..9c948b1fc1d8 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -483,7 +483,6 @@ static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) solo_dev->type = id->driver_data; solo_dev->pdev = pdev; - spin_lock_init(&solo_dev->reg_io_lock); ret = v4l2_device_register(&pdev->dev, &solo_dev->v4l2_dev); if (ret) goto fail_probe; diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h index 1ca54b08b3aa..27423d7f5410 100644 --- a/drivers/media/pci/solo6x10/solo6x10.h +++ b/drivers/media/pci/solo6x10/solo6x10.h @@ -199,7 +199,6 @@ struct solo_dev { int nr_ext; u32 irq_mask; u32 motion_mask; - spinlock_t reg_io_lock; struct v4l2_device v4l2_dev; /* tw28xx accounting */ @@ -281,36 +280,13 @@ struct solo_dev { static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg) { - unsigned long flags; - u32 ret; - u16 val; - - spin_lock_irqsave(&solo_dev->reg_io_lock, flags); - - ret = readl(solo_dev->reg_base + reg); - rmb(); - pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val); - rmb(); - - spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags); - - return ret; + return readl(solo_dev->reg_base + reg); } static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data) { - unsigned long flags; - u16 val; - - spin_lock_irqsave(&solo_dev->reg_io_lock, flags); - writel(data, solo_dev->reg_base + reg); - wmb(); - pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val); - rmb(); - - spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags); } static inline void solo_irq_on(struct solo_dev *dev, u32 mask) -- cgit v1.3-6-gb490 From d9b8252202a4cc60a6c5d4fb237d2bd99680e00f Mon Sep 17 00:00:00 2001 From: Krzysztof Hałasa Date: Mon, 8 Jun 2015 10:50:22 -0300 Subject: [media] SOLO6x10: Remove dead code solo_dev and pdev cannot be NULL here. It doesn't matter if we initialized the PCI device or not. Signed-off-by: Krzysztof Ha?asa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-core.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index 9c948b1fc1d8..f50d07229236 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -134,23 +134,11 @@ static irqreturn_t solo_isr(int irq, void *data) static void free_solo_dev(struct solo_dev *solo_dev) { - struct pci_dev *pdev; - - if (!solo_dev) - return; + struct pci_dev *pdev = solo_dev->pdev; if (solo_dev->dev.parent) device_unregister(&solo_dev->dev); - pdev = solo_dev->pdev; - - /* If we never initialized the PCI device, then nothing else - * below here needs cleanup */ - if (!pdev) { - kfree(solo_dev); - return; - } - if (solo_dev->reg_base) { /* Bring down the sub-devices first */ solo_g723_exit(solo_dev); @@ -164,8 +152,7 @@ static void free_solo_dev(struct solo_dev *solo_dev) /* Now cleanup the PCI device */ solo_irq_off(solo_dev, ~0); - if (pdev->irq) - free_irq(pdev->irq, solo_dev); + free_irq(pdev->irq, solo_dev); pci_iounmap(pdev, solo_dev->reg_base); } -- cgit v1.3-6-gb490 From e6cf0c409b40349f46427f9fc56f6ce4ec640a5d Mon Sep 17 00:00:00 2001 From: Jan Roemisch Date: Tue, 9 Jun 2015 08:44:33 -0300 Subject: [media] radio-bcm2048: Fix region selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes region selection for lower bottom_frequency in BCM2048 FM receiver. It also removes "Japan wide band" region since this is impossible to do just like that. Signed-off-by: Jan Roemisch Acked-by: Pali Rohár Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/bcm2048/radio-bcm2048.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index 8bc68e2b4052..fb55e5941445 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -342,14 +342,6 @@ static struct region_info region_configs[] = { .deemphasis = 50, .region = 3, }, - /* Japan wide band */ - { - .channel_spacing = 10, - .bottom_frequency = 76000, - .top_frequency = 108000, - .deemphasis = 50, - .region = 4, - }, }; /* @@ -741,6 +733,18 @@ static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region) mutex_lock(&bdev->mutex); bdev->region_info = region_configs[region]; + + if (region_configs[region].bottom_frequency < 87500) + bdev->cache_fm_ctrl |= BCM2048_BAND_SELECT; + else + bdev->cache_fm_ctrl &= ~BCM2048_BAND_SELECT; + + err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL, + bdev->cache_fm_ctrl); + if (err) { + mutex_unlock(&bdev->mutex); + goto done; + } mutex_unlock(&bdev->mutex); if (bdev->frequency < region_configs[region].bottom_frequency || -- cgit v1.3-6-gb490 From cfcffe397fae05d6193bbb0dc87a7148323bf3fb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 9 Jun 2015 10:54:53 -0300 Subject: [media] rc/Kconfig: fix indentation problem The RC_ST and IR_SUNXI entries have weird indentation, and the RC_ST entry is actually malformed. Fix it. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index ddfab256b9a5..b6e13116c6f5 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -371,21 +371,21 @@ config RC_ST tristate "ST remote control receiver" depends on RC_CORE depends on ARCH_STI || COMPILE_TEST - help - Say Y here if you want support for ST remote control driver - which allows both IR and UHF RX. - The driver passes raw pulse and space information to the LIRC decoder. + ---help--- + Say Y here if you want support for ST remote control driver + which allows both IR and UHF RX. + The driver passes raw pulse and space information to the LIRC decoder. - If you're not sure, select N here. + If you're not sure, select N here. config IR_SUNXI - tristate "SUNXI IR remote control" - depends on RC_CORE - depends on ARCH_SUNXI || COMPILE_TEST - ---help--- - Say Y if you want to use sunXi internal IR Controller - - To compile this driver as a module, choose M here: the module will - be called sunxi-ir. + tristate "SUNXI IR remote control" + depends on RC_CORE + depends on ARCH_SUNXI || COMPILE_TEST + ---help--- + Say Y if you want to use sunXi internal IR Controller + + To compile this driver as a module, choose M here: the module will + be called sunxi-ir. endif #RC_DEVICES -- cgit v1.3-6-gb490 From fd7524294ccaa6168593042121e3bbd26a529fd5 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:32:33 -0300 Subject: [media] v4l2-dv-timings: use swap() in v4l2_calc_aspect_ratio() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dv-timings.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 04dc71e3ebf0..eefad4f17497 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -665,7 +665,6 @@ EXPORT_SYMBOL_GPL(v4l2_detect_gtf); struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait) { struct v4l2_fract aspect = { 16, 9 }; - u32 tmp; u8 ratio; /* Nothing filled in, fallback to 16:9 */ @@ -697,9 +696,7 @@ struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait) if (hor_landscape) return aspect; /* The aspect ratio is for portrait, so swap numerator and denominator */ - tmp = aspect.denominator; - aspect.denominator = aspect.numerator; - aspect.numerator = tmp; + swap(aspect.denominator, aspect.numerator); return aspect; } EXPORT_SYMBOL_GPL(v4l2_calc_aspect_ratio); -- cgit v1.3-6-gb490 From 453f847ef2e445a7b1fe6cbe35d36a06c60f58a5 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:32:39 -0300 Subject: [media] wl128x: use swap() in fm_rdsparse_swapbytes() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_common.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 704397f3c106..ebc73b034249 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -689,7 +689,6 @@ static void fm_rx_update_af_cache(struct fmdev *fmdev, u8 af) static void fm_rdsparse_swapbytes(struct fmdev *fmdev, struct fm_rdsdata_format *rds_format) { - u8 byte1; u8 index = 0; u8 *rds_buff; @@ -701,9 +700,7 @@ static void fm_rdsparse_swapbytes(struct fmdev *fmdev, if (fmdev->asci_id != 0x6350) { rds_buff = &rds_format->data.groupdatabuff.buff[0]; while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) { - byte1 = rds_buff[index]; - rds_buff[index] = rds_buff[index + 1]; - rds_buff[index + 1] = byte1; + swap(rds_buff[index], rds_buff[index + 1]); index += 2; } } -- cgit v1.3-6-gb490 From 2bb00da1484073342a1f3e9f846ac0ad8dc6314d Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:32:41 -0300 Subject: [media] saa7146: use swap() in sort_and_eliminate() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_hlp.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/saa7146/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c index be746d1aee9a..3dc6a838ca6f 100644 --- a/drivers/media/common/saa7146/saa7146_hlp.c +++ b/drivers/media/common/saa7146/saa7146_hlp.c @@ -307,7 +307,7 @@ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field /* simple bubble-sort algorithm with duplicate elimination */ static int sort_and_eliminate(u32* values, int* count) { - int low = 0, high = 0, top = 0, temp = 0; + int low = 0, high = 0, top = 0; int cur = 0, next = 0; /* sanity checks */ @@ -318,11 +318,8 @@ static int sort_and_eliminate(u32* values, int* count) /* bubble sort the first @count items of the array @values */ for( top = *count; top > 0; top--) { for( low = 0, high = 1; high < top; low++, high++) { - if( values[low] > values[high] ) { - temp = values[low]; - values[low] = values[high]; - values[high] = temp; - } + if( values[low] > values[high] ) + swap(values[low], values[high]); } } -- cgit v1.3-6-gb490 From f47c183c20d845af9d747fc1e5b7dbd9c3871e05 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:32:50 -0300 Subject: [media] saa6588: use swap() in saa6588_i2c_poll() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/saa6588.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c index 2960b5a8362a..2240e0a67db1 100644 --- a/drivers/media/i2c/saa6588.c +++ b/drivers/media/i2c/saa6588.c @@ -301,9 +301,7 @@ static void saa6588_i2c_poll(struct saa6588 *s) first and the last of the 3 bytes block. */ - tmp = tmpbuf[2]; - tmpbuf[2] = tmpbuf[0]; - tmpbuf[0] = tmp; + swap(tmpbuf[2], tmpbuf[0]); /* Map 'Invalid block E' to 'Invalid Block' */ if (blocknum == 6) -- cgit v1.3-6-gb490 From 30533ad10b7c3d7c05b757382aee28458167ab75 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:33:45 -0300 Subject: [media] btcx-risc: use swap() in btcx_sort_clips() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/btcx-risc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/bt8xx/btcx-risc.c b/drivers/media/pci/bt8xx/btcx-risc.c index 00f0880b6d66..57c7f58c3af2 100644 --- a/drivers/media/pci/bt8xx/btcx-risc.c +++ b/drivers/media/pci/bt8xx/btcx-risc.c @@ -160,7 +160,6 @@ btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int m void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) { - struct v4l2_clip swap; int i,j,n; if (nclips < 2) @@ -168,9 +167,7 @@ btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) for (i = nclips-2; i >= 0; i--) { for (n = 0, j = 0; j <= i; j++) { if (clips[j].c.left > clips[j+1].c.left) { - swap = clips[j]; - clips[j] = clips[j+1]; - clips[j+1] = swap; + swap(clips[j], clips[j + 1]); n++; } } -- cgit v1.3-6-gb490 From 5fea1bb703c360f323c62f6d34b5e947d0590e80 Mon Sep 17 00:00:00 2001 From: Prashant Laddha Date: Wed, 10 Jun 2015 13:51:42 -0300 Subject: [media] v4l2-dv-timings: add support for reduced blanking v2 Added support for reduced blanking version 2 (RB v2) in cvt timings. Standard specifies a fixed vsync pulse of 8 lines to indicate RB v2 timings. Vertical back porch is fixed at 6 lines and vertical front porch is remainder of vertical blanking time. For RB v2, horizontal blanking is fixed at 80 pixels. Horizontal sync is fixed at 32. All horizontal timing counts (active pixels, front, back porches) can be specified upto a precision of 1. RB v2 allows for non standard aspect ratios. In RB v2 vsync does not indicate aspect ratio. In absence of aspect ratio v4l2_detect_cvt() cannot calculate image width from image height. Hence extending the v4l2_detect_cvt() to pass image width in case of RB v2. Signed-off-by: Prashant Laddha Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 2 +- drivers/media/i2c/adv7842.c | 2 +- drivers/media/platform/vivid/vivid-vid-cap.c | 2 +- drivers/media/v4l2-core/v4l2-dv-timings.c | 80 ++++++++++++++++++++-------- include/media/v4l2-dv-timings.h | 6 ++- 5 files changed, 67 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 808360fd6539..60630d62e663 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1328,7 +1328,7 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, } } - if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, + if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), false, timings)) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 4cf79b2422d4..aa0d1a04543b 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1442,7 +1442,7 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, } } - if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, + if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), false, timings)) diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index c4268d1b2f82..ed0b8788a66f 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1627,7 +1627,7 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) h_freq = (u32)bt->pixelclock / total_h_pixel; if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { - if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, + if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, bt->width, bt->polarities, bt->interlaced, timings)) return true; } diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index eefad4f17497..ddaad3d7f1dd 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -316,6 +316,7 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); */ #define CVT_PXL_CLK_GRAN 250000 /* pixel clock granularity */ +#define CVT_PXL_CLK_GRAN_RB_V2 1000 /* granularity for reduced blanking v2*/ /* Normal blanking */ #define CVT_MIN_V_BPORCH 7 /* lines */ @@ -335,15 +336,22 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); /* Reduced Blanking */ #define CVT_RB_MIN_V_BPORCH 7 /* lines */ #define CVT_RB_V_FPORCH 3 /* lines */ -#define CVT_RB_MIN_V_BLANK 460 /* us */ +#define CVT_RB_MIN_V_BLANK 460 /* us */ #define CVT_RB_H_SYNC 32 /* pixels */ -#define CVT_RB_H_BPORCH 80 /* pixels */ #define CVT_RB_H_BLANK 160 /* pixels */ +/* Reduce blanking Version 2 */ +#define CVT_RB_V2_H_BLANK 80 /* pixels */ +#define CVT_RB_MIN_V_FPORCH 3 /* lines */ +#define CVT_RB_V2_MIN_V_FPORCH 1 /* lines */ +#define CVT_RB_V_BPORCH 6 /* lines */ /** v4l2_detect_cvt - detect if the given timings follow the CVT standard * @frame_height - the total height of the frame (including blanking) in lines. * @hfreq - the horizontal frequency in Hz. * @vsync - the height of the vertical sync in lines. + * @active_width - active width of image (does not include blanking). This + * information is needed only in case of version 2 of reduced blanking. + * In other cases, this parameter does not have any effect on timings. * @polarities - the horizontal and vertical polarities (same as struct * v4l2_bt_timings polarities). * @interlaced - if this flag is true, it indicates interlaced format @@ -352,20 +360,22 @@ 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, bool interlaced, struct v4l2_dv_timings *fmt) +bool v4l2_detect_cvt(unsigned frame_height, + unsigned hfreq, + unsigned vsync, + unsigned active_width, + u32 polarities, + bool interlaced, + struct v4l2_dv_timings *fmt) { int v_fp, v_bp, h_fp, h_bp, hsync; int frame_width, image_height, image_width; bool reduced_blanking; + bool rb_v2 = false; unsigned pix_clk; - if (vsync < 4 || vsync > 7) + if (vsync < 4 || vsync > 8) return false; if (polarities == V4L2_DV_VSYNC_POS_POL) @@ -375,17 +385,35 @@ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, else return false; + if (reduced_blanking && vsync == 8) + rb_v2 = true; + + if (rb_v2 && active_width == 0) + return false; + + if (!rb_v2 && vsync > 7) + return false; + if (hfreq == 0) return false; /* Vertical */ if (reduced_blanking) { - v_fp = CVT_RB_V_FPORCH; - v_bp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1; - v_bp -= vsync + v_fp; - - if (v_bp < CVT_RB_MIN_V_BPORCH) - v_bp = CVT_RB_MIN_V_BPORCH; + if (rb_v2) { + v_bp = CVT_RB_V_BPORCH; + v_fp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1; + v_fp -= vsync + v_bp; + + if (v_fp < CVT_RB_V2_MIN_V_FPORCH) + v_fp = CVT_RB_V2_MIN_V_FPORCH; + } else { + v_fp = CVT_RB_V_FPORCH; + v_bp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1; + v_bp -= vsync + v_fp; + + if (v_bp < CVT_RB_MIN_V_BPORCH) + v_bp = CVT_RB_MIN_V_BPORCH; + } } else { v_fp = CVT_MIN_V_PORCH_RND; v_bp = (CVT_MIN_VSYNC_BP * hfreq) / 1000000 + 1 - vsync; @@ -422,22 +450,32 @@ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, else return false; break; + case 8: + image_width = active_width; + break; default: return false; } - image_width = image_width & ~7; + if (!rb_v2) + image_width = image_width & ~7; /* Horizontal */ if (reduced_blanking) { - pix_clk = (image_width + CVT_RB_H_BLANK) * hfreq; - pix_clk = (pix_clk / CVT_PXL_CLK_GRAN) * CVT_PXL_CLK_GRAN; + int h_blank; + int clk_gran; + + h_blank = rb_v2 ? CVT_RB_V2_H_BLANK : CVT_RB_H_BLANK; + clk_gran = rb_v2 ? CVT_PXL_CLK_GRAN_RB_V2 : CVT_PXL_CLK_GRAN; - h_bp = CVT_RB_H_BPORCH; + pix_clk = (image_width + h_blank) * hfreq; + pix_clk = (pix_clk / clk_gran) * clk_gran; + + h_bp = h_blank / 2; hsync = CVT_RB_H_SYNC; - h_fp = CVT_RB_H_BLANK - h_bp - hsync; + h_fp = h_blank - h_bp - hsync; - frame_width = image_width + CVT_RB_H_BLANK; + frame_width = image_width + h_blank; } else { unsigned ideal_duty_cycle_per_myriad = 100 * CVT_C_PRIME - (CVT_M_PRIME * 100000) / hfreq; diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h index eecd3102a618..e18a653549cd 100644 --- a/include/media/v4l2-dv-timings.h +++ b/include/media/v4l2-dv-timings.h @@ -115,6 +115,9 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, * @frame_height - the total height of the frame (including blanking) in lines. * @hfreq - the horizontal frequency in Hz. * @vsync - the height of the vertical sync in lines. + * @active_width - active width of image (does not include blanking). This + * information is needed only in case of version 2 of reduced blanking. + * In other cases, this parameter does not have any effect on timings. * @polarities - the horizontal and vertical polarities (same as struct * v4l2_bt_timings polarities). * @interlaced - if this flag is true, it indicates interlaced format @@ -125,7 +128,8 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, * in with the found CVT timings. */ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, - u32 polarities, bool interlaced, struct v4l2_dv_timings *fmt); + unsigned active_width, u32 polarities, bool interlaced, + struct v4l2_dv_timings *fmt); /** v4l2_detect_gtf - detect if the given timings follow the GTF standard * @frame_height - the total height of the frame (including blanking) in lines. -- cgit v1.3-6-gb490 From 1b3b384177b2de010833fefffac6af3d6ffbdfed Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 12 Jun 2015 03:52:54 -0300 Subject: [media] v4l2-dv-timings: log if the timing is reduced blanking V2 The last CVT standard introduced reduced blanking version 2 which is signaled by a vsync of 8. Log this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dv-timings.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index ddaad3d7f1dd..2c7b9fdfa0af 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -290,9 +290,11 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-", bt->il_vsync, bt->il_vbackporch); pr_info("%s: pixelclock: %llu\n", dev_prefix, bt->pixelclock); - pr_info("%s: flags (0x%x):%s%s%s%s%s\n", dev_prefix, bt->flags, + pr_info("%s: flags (0x%x):%s%s%s%s%s%s\n", dev_prefix, bt->flags, (bt->flags & V4L2_DV_FL_REDUCED_BLANKING) ? " REDUCED_BLANKING" : "", + ((bt->flags & V4L2_DV_FL_REDUCED_BLANKING) && + bt->vsync == 8) ? " (V2)" : "", (bt->flags & V4L2_DV_FL_CAN_REDUCE_FPS) ? " CAN_REDUCE_FPS" : "", (bt->flags & V4L2_DV_FL_REDUCED_FPS) ? -- cgit v1.3-6-gb490 From 5d479386983c5f1bb1aff4f88a027b6143f88a39 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 19 May 2015 20:08:05 -0300 Subject: [media] v4l: omap3isp: Fix async notifier registration order The async notifier was registered before the v4l2_device was registered and before the notifier callbacks were set. This could lead to missing the bound() and complete() callbacks and to attempting to spin_lock() and uninitialised spin lock. Also fix unregistering the async notifier in the case of an error --- the function may not fail anymore after the notifier is registered. Fixes: da7f3843d2c7 ("[media] omap3isp: Add support for the Device Tree") Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 18d0a871747f..d1334bb1fe37 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2000,10 +2000,8 @@ static int isp_register_entities(struct isp_device *isp) ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); done: - if (ret < 0) { + if (ret < 0) isp_unregister_entities(isp); - v4l2_async_notifier_unregister(&isp->notifier); - } return ret; } @@ -2423,10 +2421,6 @@ static int isp_probe(struct platform_device *pdev) ret = isp_of_parse_nodes(&pdev->dev, &isp->notifier); if (ret < 0) return ret; - ret = v4l2_async_notifier_register(&isp->v4l2_dev, - &isp->notifier); - if (ret) - return ret; } else { isp->pdata = pdev->dev.platform_data; isp->syscon = syscon_regmap_lookup_by_pdevname("syscon.0"); @@ -2557,18 +2551,27 @@ static int isp_probe(struct platform_device *pdev) if (ret < 0) goto error_iommu; - isp->notifier.bound = isp_subdev_notifier_bound; - isp->notifier.complete = isp_subdev_notifier_complete; - ret = isp_register_entities(isp); if (ret < 0) goto error_modules; + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { + isp->notifier.bound = isp_subdev_notifier_bound; + isp->notifier.complete = isp_subdev_notifier_complete; + + ret = v4l2_async_notifier_register(&isp->v4l2_dev, + &isp->notifier); + if (ret) + goto error_register_entities; + } + isp_core_init(isp, 1); omap3isp_put(isp); return 0; +error_register_entities: + isp_unregister_entities(isp); error_modules: isp_cleanup_modules(isp); error_iommu: -- cgit v1.3-6-gb490 From 9d39f05490115bf145e5ea03c0b7ec9d3d015b01 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 12 Jun 2015 20:06:23 -0300 Subject: [media] v4l: omap3isp: Fix sub-device power management code Commit 813f5c0ac5cc ("media: Change media device link_notify behaviour") modified the media controller link setup notification API and updated the OMAP3 ISP driver accordingly. As a side effect it introduced a bug by turning power on after setting the link instead of before. This results in sub-devices not being powered down in some cases when they should be. Fix it. Fixes: 813f5c0ac5cc [media] media: Change media device link_notify behaviour Signed-off-by: Sakari Ailus Cc: stable@vger.kernel.org # since v3.10 Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index d1334bb1fe37..12be830d704f 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -829,14 +829,14 @@ static int isp_pipeline_link_notify(struct media_link *link, u32 flags, int ret; if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && - !(link->flags & MEDIA_LNK_FL_ENABLED)) { + !(flags & MEDIA_LNK_FL_ENABLED)) { /* Powering off entities is assumed to never fail. */ isp_pipeline_pm_power(source, -sink_use); isp_pipeline_pm_power(sink, -source_use); return 0; } - if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && + if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH && (flags & MEDIA_LNK_FL_ENABLED)) { ret = isp_pipeline_pm_power(source, sink_use); -- cgit v1.3-6-gb490 From 44f4294d5ee58ba3f9dcc0da4cc545c21328eb10 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 12 Apr 2015 09:09:05 -0300 Subject: [media] v4l: omap4iss: Enable driver compilation as a module Now that the driver doesn't use the non-exported omap4_ctrl_pad_readl and omap4_ctrl_pad_writel functions nothing prevents it from being compiled as a module anymore. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/omap4iss/Kconfig | 2 +- drivers/staging/media/omap4iss/TODO | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig index 072dac04a750..8d4e3bd1bfe1 100644 --- a/drivers/staging/media/omap4iss/Kconfig +++ b/drivers/staging/media/omap4iss/Kconfig @@ -1,5 +1,5 @@ config VIDEO_OMAP4 - bool "OMAP 4 Camera support" + tristate "OMAP 4 Camera support" depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4 depends on HAS_DMA select MFD_SYSCON diff --git a/drivers/staging/media/omap4iss/TODO b/drivers/staging/media/omap4iss/TODO index fcde88860a2c..4d220ef82653 100644 --- a/drivers/staging/media/omap4iss/TODO +++ b/drivers/staging/media/omap4iss/TODO @@ -1,4 +1,3 @@ -* Make the driver compile as a module * Fix FIFO/buffer overflows and underflows * Replace dummy resizer code with a real implementation * Fix checkpatch errors and warnings -- cgit v1.3-6-gb490 From 408131b85509902b100f7045484c7377a40be99d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 12 Apr 2015 09:09:05 -0300 Subject: [media] v4l: omap4iss: Remove video node crop support Cropping should be configured on the pipeline subdev nodes, not through the video nodes. Remove crop support on all video nodes. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/omap4iss/iss_video.c | 73 ------------------------------ 1 file changed, 73 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 85c54fedddda..40405d8710a6 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -639,76 +639,6 @@ iss_video_try_format(struct file *file, void *fh, struct v4l2_format *format) return 0; } -static int -iss_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev *subdev; - int ret; - - subdev = iss_video_remote_subdev(video, NULL); - if (subdev == NULL) - return -EINVAL; - - mutex_lock(&video->mutex); - ret = v4l2_subdev_call(subdev, video, cropcap, cropcap); - mutex_unlock(&video->mutex); - - return ret == -ENOIOCTLCMD ? -ENOTTY : ret; -} - -static int -iss_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev_format format; - struct v4l2_subdev *subdev; - u32 pad; - int ret; - - subdev = iss_video_remote_subdev(video, &pad); - if (subdev == NULL) - return -EINVAL; - - /* Try the get crop operation first and fallback to get format if not - * implemented. - */ - ret = v4l2_subdev_call(subdev, video, g_crop, crop); - if (ret != -ENOIOCTLCMD) - return ret; - - format.pad = pad; - format.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format); - if (ret < 0) - return ret == -ENOIOCTLCMD ? -ENOTTY : ret; - - crop->c.left = 0; - crop->c.top = 0; - crop->c.width = format.format.width; - crop->c.height = format.format.height; - - return 0; -} - -static int -iss_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev *subdev; - int ret; - - subdev = iss_video_remote_subdev(video, NULL); - if (subdev == NULL) - return -EINVAL; - - mutex_lock(&video->mutex); - ret = v4l2_subdev_call(subdev, video, s_crop, crop); - mutex_unlock(&video->mutex); - - return ret == -ENOIOCTLCMD ? -ENOTTY : ret; -} - static int iss_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) { @@ -1018,9 +948,6 @@ static const struct v4l2_ioctl_ops iss_video_ioctl_ops = { .vidioc_g_fmt_vid_out = iss_video_get_format, .vidioc_s_fmt_vid_out = iss_video_set_format, .vidioc_try_fmt_vid_out = iss_video_try_format, - .vidioc_cropcap = iss_video_cropcap, - .vidioc_g_crop = iss_video_get_crop, - .vidioc_s_crop = iss_video_set_crop, .vidioc_g_parm = iss_video_get_param, .vidioc_s_parm = iss_video_set_param, .vidioc_reqbufs = iss_video_reqbufs, -- cgit v1.3-6-gb490 From 8c0378354709058bba3319bb58fd04bd09e1eaa6 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 26 May 2015 06:54:45 -0300 Subject: [media] atmel-isi: disable ISI even if it has codec request In current code, stop_streaming() will just return if ISI is still working in the codec. But this is incorrect, we need to disable ISI even it is working on the codec, otherwise stop_streaming() will not work as we expected. Signed-off-by: Josh Wu Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 287902681164..22270225b202 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -431,11 +431,9 @@ static void stop_streaming(struct vb2_queue *vq) time_before(jiffies, timeout)) msleep(1); - if (time_after(jiffies, timeout)) { + if (time_after(jiffies, timeout)) dev_err(icd->parent, "Timeout waiting for finishing codec request\n"); - return; - } /* Disable interrupts */ isi_writel(isi, ISI_INTDIS, -- cgit v1.3-6-gb490 From f3745a3af521d403d4c174e4bad0986e11f4d2f1 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 26 May 2015 06:54:46 -0300 Subject: [media] atmel-isi: add runtime pm support The runtime pm resume/suspend will enable/disable pclk (ISI peripheral clock). We have to call runtime_pm_get_sync()/runtime_pm_put() when we need to access ISI registers. In atmel_isi_probe(), remove the isi disable code as at that moment ISI peripheral clock is not enable yet. Besides, clock_start()/clock_stop() is used to control the mclk, not the ISI peripheral clock. So move this to start[stop]_streaming() function. Signed-off-by: Josh Wu Acked-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 55 +++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 22270225b202..0ea360acea81 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -386,10 +387,13 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) struct atmel_isi *isi = ici->priv; int ret; + pm_runtime_get_sync(ici->v4l2_dev.dev); + /* Reset ISI */ ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); if (ret < 0) { dev_err(icd->parent, "Reset ISI timed out\n"); + pm_runtime_put(ici->v4l2_dev.dev); return ret; } /* Disable all interrupts */ @@ -443,6 +447,8 @@ static void stop_streaming(struct vb2_queue *vq) ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE); if (ret < 0) dev_err(icd->parent, "Disable ISI timed out\n"); + + pm_runtime_put(ici->v4l2_dev.dev); } static struct vb2_ops isi_video_qops = { @@ -514,7 +520,13 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, if (mf->code != xlate->code) return -EINVAL; + /* Enable PM and peripheral clock before operate isi registers */ + pm_runtime_get_sync(ici->v4l2_dev.dev); + ret = configure_geometry(isi, pix->width, pix->height, xlate->code); + + pm_runtime_put(ici->v4l2_dev.dev); + if (ret < 0) return ret; @@ -734,14 +746,9 @@ static int isi_camera_clock_start(struct soc_camera_host *ici) struct atmel_isi *isi = ici->priv; int ret; - ret = clk_prepare_enable(isi->pclk); - if (ret) - return ret; - if (!IS_ERR(isi->mck)) { ret = clk_prepare_enable(isi->mck); if (ret) { - clk_disable_unprepare(isi->pclk); return ret; } } @@ -756,7 +763,6 @@ static void isi_camera_clock_stop(struct soc_camera_host *ici) if (!IS_ERR(isi->mck)) clk_disable_unprepare(isi->mck); - clk_disable_unprepare(isi->pclk); } static unsigned int isi_camera_poll(struct file *file, poll_table *pt) @@ -853,9 +859,14 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) cfg1 |= ISI_CFG1_THMASK_BEATS_16; + /* Enable PM and peripheral clock before operate isi registers */ + pm_runtime_get_sync(ici->v4l2_dev.dev); + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); isi_writel(isi, ISI_CFG1, cfg1); + pm_runtime_put(ici->v4l2_dev.dev); + return 0; } @@ -887,6 +898,7 @@ static int atmel_isi_remove(struct platform_device *pdev) sizeof(struct fbd) * MAX_BUFFER_NUM, isi->p_fb_descriptors, isi->fb_descriptors_phys); + pm_runtime_disable(&pdev->dev); return 0; } @@ -1025,8 +1037,6 @@ static int atmel_isi_probe(struct platform_device *pdev) if (isi->pdata.data_width_flags & ISI_DATAWIDTH_10) isi->width_flags |= 1 << 9; - isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); - irq = platform_get_irq(pdev, 0); if (IS_ERR_VALUE(irq)) { ret = irq; @@ -1047,6 +1057,9 @@ static int atmel_isi_probe(struct platform_device *pdev) soc_host->v4l2_dev.dev = &pdev->dev; soc_host->nr = pdev->id; + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + if (isi->pdata.asd_sizes) { soc_host->asd = isi->pdata.asd; soc_host->asd_sizes = isi->pdata.asd_sizes; @@ -1060,6 +1073,7 @@ static int atmel_isi_probe(struct platform_device *pdev) return 0; err_register_soc_camera_host: + pm_runtime_disable(&pdev->dev); err_req_irq: err_ioremap: vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); @@ -1072,6 +1086,30 @@ err_alloc_ctx: return ret; } +static int atmel_isi_runtime_suspend(struct device *dev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(dev); + struct atmel_isi *isi = container_of(soc_host, + struct atmel_isi, soc_host); + + clk_disable_unprepare(isi->pclk); + + return 0; +} +static int atmel_isi_runtime_resume(struct device *dev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(dev); + struct atmel_isi *isi = container_of(soc_host, + struct atmel_isi, soc_host); + + return clk_prepare_enable(isi->pclk); +} + +static const struct dev_pm_ops atmel_isi_dev_pm_ops = { + SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend, + atmel_isi_runtime_resume, NULL) +}; + static const struct of_device_id atmel_isi_of_match[] = { { .compatible = "atmel,at91sam9g45-isi" }, { } @@ -1083,6 +1121,7 @@ static struct platform_driver atmel_isi_driver = { .driver = { .name = "atmel_isi", .of_match_table = of_match_ptr(atmel_isi_of_match), + .pm = &atmel_isi_dev_pm_ops, }, }; -- cgit v1.3-6-gb490 From 4a99362da734dfdcca5035dfa15b9f3708f1f8a4 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 26 May 2015 06:54:47 -0300 Subject: [media] atmel-isi: remove mck backward compatibility code The master clock should be handled by sensor itself. Signed-off-by: Josh Wu Acked-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 46 --------------------------- 1 file changed, 46 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 0ea360acea81..90701726a06a 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -35,7 +35,6 @@ #define VID_LIMIT_BYTES (16 * 1024 * 1024) #define MIN_FRAME_RATE 15 #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) -#define ISI_DEFAULT_MCLK_FREQ 25000000 /* Frame buffer descriptor */ struct fbd { @@ -83,8 +82,6 @@ struct atmel_isi { struct completion complete; /* ISI peripherial clock */ struct clk *pclk; - /* ISI_MCK, feed to camera sensor to generate pixel clock */ - struct clk *mck; unsigned int irq; struct isi_platform_data pdata; @@ -740,31 +737,6 @@ static void isi_camera_remove_device(struct soc_camera_device *icd) icd->devnum); } -/* Called with .host_lock held */ -static int isi_camera_clock_start(struct soc_camera_host *ici) -{ - struct atmel_isi *isi = ici->priv; - int ret; - - if (!IS_ERR(isi->mck)) { - ret = clk_prepare_enable(isi->mck); - if (ret) { - return ret; - } - } - - return 0; -} - -/* Called with .host_lock held */ -static void isi_camera_clock_stop(struct soc_camera_host *ici) -{ - struct atmel_isi *isi = ici->priv; - - if (!IS_ERR(isi->mck)) - clk_disable_unprepare(isi->mck); -} - static unsigned int isi_camera_poll(struct file *file, poll_table *pt) { struct soc_camera_device *icd = file->private_data; @@ -874,8 +846,6 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = { .owner = THIS_MODULE, .add = isi_camera_add_device, .remove = isi_camera_remove_device, - .clock_start = isi_camera_clock_start, - .clock_stop = isi_camera_clock_stop, .set_fmt = isi_camera_set_fmt, .try_fmt = isi_camera_try_fmt, .get_formats = isi_camera_get_formats, @@ -912,7 +882,6 @@ static int atmel_isi_probe_dt(struct atmel_isi *isi, /* Default settings for ISI */ isi->pdata.full_mode = 1; - isi->pdata.mck_hz = ISI_DEFAULT_MCLK_FREQ; isi->pdata.frate = ISI_CFG1_FRATE_CAPTURE_ALL; np = of_graph_get_next_endpoint(np, NULL); @@ -988,21 +957,6 @@ static int atmel_isi_probe(struct platform_device *pdev) INIT_LIST_HEAD(&isi->video_buffer_list); INIT_LIST_HEAD(&isi->dma_desc_head); - /* ISI_MCK is the sensor master clock. It should be handled by the - * sensor driver directly, as the ISI has no use for that clock. Make - * the clock optional here while platforms transition to the correct - * model. - */ - isi->mck = devm_clk_get(dev, "isi_mck"); - if (!IS_ERR(isi->mck)) { - /* Set ISI_MCK's frequency, it should be faster than pixel - * clock. - */ - ret = clk_set_rate(isi->mck, isi->pdata.mck_hz); - if (ret < 0) - return ret; - } - isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, sizeof(struct fbd) * MAX_BUFFER_NUM, &isi->fb_descriptors_phys, -- cgit v1.3-6-gb490 From 4366dfef377034e97d5b35677b7a1ebb1f1ce6dc Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Wed, 10 Jun 2015 10:38:29 -0300 Subject: [media] media/v4l2-ctrls: Code cleanout validate_new() We can simplify the code removing the if(). v4l2_ctr_new sets ctrls->elems to 1 when !ctrl->is_ptr. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index e3a3468002e6..b6b7dcc1b77d 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1678,21 +1678,6 @@ static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) unsigned idx; int err = 0; - if (!ctrl->is_ptr) { - switch (ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER: - case V4L2_CTRL_TYPE_INTEGER_MENU: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_BITMASK: - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_BUTTON: - case V4L2_CTRL_TYPE_CTRL_CLASS: - case V4L2_CTRL_TYPE_INTEGER64: - return ctrl->type_ops->validate(ctrl, 0, p_new); - default: - break; - } - } for (idx = 0; !err && idx < ctrl->elems; idx++) err = ctrl->type_ops->validate(ctrl, idx, p_new); return err; -- cgit v1.3-6-gb490 From 227da85e775065c81e222f443e8379aba4d3f668 Mon Sep 17 00:00:00 2001 From: Prashant Laddha Date: Fri, 12 Jun 2015 08:48:10 -0300 Subject: [media] v4l2-dv-timings: print refresh rate with better precision In many cases, refresh rate is not exact integer. In such cases, fraction was lost and it used to print, say, 59 in case of 59.94. Now, capturing the fraction up to 2 decimal places. Signed-off-by: Prashant Laddha Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dv-timings.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 2c7b9fdfa0af..6a83d6191684 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -256,6 +256,7 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, { const struct v4l2_bt_timings *bt = &t->bt; u32 htot, vtot; + u32 fps; if (t->type != V4L2_DV_BT_656_1120) return; @@ -265,13 +266,15 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, if (bt->interlaced) vtot /= 2; + fps = (htot * vtot) > 0 ? div_u64((100 * (u64)bt->pixelclock), + (htot * vtot)) : 0; + if (prefix == NULL) prefix = ""; - pr_info("%s: %s%ux%u%s%u (%ux%u)\n", dev_prefix, prefix, + pr_info("%s: %s%ux%u%s%u.%u (%ux%u)\n", dev_prefix, prefix, bt->width, bt->height, bt->interlaced ? "i" : "p", - (htot * vtot) > 0 ? ((u32)bt->pixelclock / (htot * vtot)) : 0, - htot, vtot); + fps / 100, fps % 100, htot, vtot); if (!detailed) return; -- cgit v1.3-6-gb490 From 747d481df3b9b6ef46ccb233d74c8d93ec4819e6 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:07 -0300 Subject: [media] media/i2c/adv7343: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7343.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index 7c50833e7d17..d27283135490 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c @@ -319,13 +319,6 @@ static const struct v4l2_ctrl_ops adv7343_ctrl_ops = { static const struct v4l2_subdev_core_ops adv7343_core_ops = { .log_status = adv7343_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -- cgit v1.3-6-gb490 From 260faaa490d29cd2ad3cad54fbda0ede406c818e Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:08 -0300 Subject: [media] media/i2c/adv7393: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7393.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7393.c b/drivers/media/i2c/adv7393.c index 558f19154eb9..0215f95c2245 100644 --- a/drivers/media/i2c/adv7393.c +++ b/drivers/media/i2c/adv7393.c @@ -306,13 +306,6 @@ static const struct v4l2_ctrl_ops adv7393_ctrl_ops = { static const struct v4l2_subdev_core_ops adv7393_core_ops = { .log_status = adv7393_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static int adv7393_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -- cgit v1.3-6-gb490 From 6ceea1f7d021492ed13609fa1cf401484dae0e0d Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:09 -0300 Subject: [media] media/i2c/cs5345: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cs5345.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/cs5345.c b/drivers/media/i2c/cs5345.c index 34b76a9e7515..8cebf9cc8007 100644 --- a/drivers/media/i2c/cs5345.c +++ b/drivers/media/i2c/cs5345.c @@ -132,13 +132,6 @@ static const struct v4l2_ctrl_ops cs5345_ctrl_ops = { static const struct v4l2_subdev_core_ops cs5345_core_ops = { .log_status = cs5345_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = cs5345_g_register, .s_register = cs5345_s_register, -- cgit v1.3-6-gb490 From 3cfa008e3cafa90684f84abbfb995cec437a61ea Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:10 -0300 Subject: [media] media/i2c/saa717x: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/saa717x.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index 7d517361e419..c6ba19cf1aa5 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -1204,13 +1204,6 @@ static const struct v4l2_subdev_core_ops saa717x_core_ops = { .g_register = saa717x_g_register, .s_register = saa717x_s_register, #endif - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, .log_status = saa717x_log_status, }; -- cgit v1.3-6-gb490 From fc1a33fed0274efefbfc5f463a69efbaee4d989f Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:12 -0300 Subject: [media] media/i2c/tda7432: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda7432.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index cf93021a6500..d3834a4c48da 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c @@ -331,13 +331,6 @@ static const struct v4l2_ctrl_ops tda7432_ctrl_ops = { static const struct v4l2_subdev_core_ops tda7432_core_ops = { .log_status = tda7432_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_ops tda7432_ops = { -- cgit v1.3-6-gb490 From 8b198c6b8b65ef39c3652972c36a43e04b4482dd Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:13 -0300 Subject: [media] media/i2c/tlv320aic23: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tlv320aic23b.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tlv320aic23b.c b/drivers/media/i2c/tlv320aic23b.c index ef87f7b09ea2..0370dd89f1fc 100644 --- a/drivers/media/i2c/tlv320aic23b.c +++ b/drivers/media/i2c/tlv320aic23b.c @@ -122,13 +122,6 @@ static const struct v4l2_ctrl_ops tlv320aic23b_ctrl_ops = { static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = { .log_status = tlv320aic23b_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = { -- cgit v1.3-6-gb490 From e5b40d2e11c3e2ed60ecb70313765d48c7786448 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:14 -0300 Subject: [media] media/i2c/tvp514x: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp514x.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 24e47279e30c..a93985a9b070 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -957,16 +957,6 @@ static int tvp514x_set_pad_format(struct v4l2_subdev *sd, return 0; } -static const struct v4l2_subdev_core_ops tvp514x_core_ops = { - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - static const struct v4l2_subdev_video_ops tvp514x_video_ops = { .s_std = tvp514x_s_std, .s_routing = tvp514x_s_routing, @@ -983,7 +973,6 @@ static const struct v4l2_subdev_pad_ops tvp514x_pad_ops = { }; static const struct v4l2_subdev_ops tvp514x_ops = { - .core = &tvp514x_core_ops, .video = &tvp514x_video_ops, .pad = &tvp514x_pad_ops, }; -- cgit v1.3-6-gb490 From f5f24bc3267b3651e8bb026a5669dfe6855ffe63 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:15 -0300 Subject: [media] media/i2c/tvp7002: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp7002.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 05077cffd235..f617d8b745ee 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -861,13 +861,6 @@ tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cf /* V4L2 core operation handlers */ static const struct v4l2_subdev_core_ops tvp7002_core_ops = { .log_status = tvp7002_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = tvp7002_g_register, .s_register = tvp7002_s_register, -- cgit v1.3-6-gb490 From c2527967c5795815d3422f147af767293b3806eb Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:16 -0300 Subject: [media] i2c/wm8739: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/wm8739.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/wm8739.c b/drivers/media/i2c/wm8739.c index 3be73f6a40e9..534b0e560317 100644 --- a/drivers/media/i2c/wm8739.c +++ b/drivers/media/i2c/wm8739.c @@ -176,13 +176,6 @@ static const struct v4l2_ctrl_ops wm8739_ctrl_ops = { static const struct v4l2_subdev_core_ops wm8739_core_ops = { .log_status = wm8739_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_audio_ops wm8739_audio_ops = { -- cgit v1.3-6-gb490 From 59617e74e20dac9523e34f5461162b19347dacf8 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:17 -0300 Subject: [media] pci/ivtv/ivtv-gpio: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtv-gpio.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/ivtv/ivtv-gpio.c b/drivers/media/pci/ivtv/ivtv-gpio.c index af52def700cc..f752f3993687 100644 --- a/drivers/media/pci/ivtv/ivtv-gpio.c +++ b/drivers/media/pci/ivtv/ivtv-gpio.c @@ -313,13 +313,6 @@ static const struct v4l2_ctrl_ops gpio_ctrl_ops = { static const struct v4l2_subdev_core_ops subdev_core_ops = { .log_status = subdev_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = { -- cgit v1.3-6-gb490 From 387a69243890a51be023aef12d0fdcae343f43f2 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:18 -0300 Subject: [media] media/radio/saa7706h: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/saa7706h.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c index ec805b09c608..183e92719140 100644 --- a/drivers/media/radio/saa7706h.c +++ b/drivers/media/radio/saa7706h.c @@ -336,19 +336,7 @@ static const struct v4l2_ctrl_ops saa7706h_ctrl_ops = { .s_ctrl = saa7706h_s_ctrl, }; -static const struct v4l2_subdev_core_ops saa7706h_core_ops = { - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - -static const struct v4l2_subdev_ops saa7706h_ops = { - .core = &saa7706h_core_ops, -}; +static const struct v4l2_subdev_ops empty_ops = {}; /* * Generic i2c probe @@ -373,7 +361,7 @@ static int saa7706h_probe(struct i2c_client *client, if (state == NULL) return -ENOMEM; sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &saa7706h_ops); + v4l2_i2c_subdev_init(sd, client, &empty_ops); v4l2_ctrl_handler_init(&state->hdl, 4); v4l2_ctrl_new_std(&state->hdl, &saa7706h_ctrl_ops, -- cgit v1.3-6-gb490 From 0a2a89c4acbf2ede9cdcc51d7113091978079b7b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 4 Jun 2015 05:52:26 -0300 Subject: [media] gspca: sn9c2028: remove an unneeded condition We already know status is negative because of the earlier check so there is no need to check again. Signed-off-by: Dan Carpenter Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/sn9c2028.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c index c75b7388a85c..4f2050a5ec94 100644 --- a/drivers/media/usb/gspca/sn9c2028.c +++ b/drivers/media/usb/gspca/sn9c2028.c @@ -140,7 +140,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command) status = sn9c2028_read1(gspca_dev); if (status < 0) { pr_err("long command status read error %d\n", status); - return (status < 0) ? status : -EIO; + return status; } memset(reading, 0, 4); -- cgit v1.3-6-gb490 From 63f2f417526fc54191f2b813f72dc1d5322bede8 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 7 Jun 2015 11:34:40 -0300 Subject: [media] gscpa_m5602: use msecs_to_jiffies for conversions API compliance scanning with coccinelle flagged: ./drivers/media/usb/gspca/m5602/m5602_s5k83a.c:180:9-25: WARNING: timeout (100) seems HZ dependent Numeric constants passed to schedule_timeout() make the effective timeout HZ dependent which makes little sense in a polling loop for the cameras rotation state. Fixed up by converting the constant to jiffies with msecs_to_jiffies() Signed-off-by: Nicholas Mc Guire Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/m5602/m5602_s5k83a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c index 7cbc3a00bda8..bf6b215438e3 100644 --- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c +++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c @@ -177,7 +177,7 @@ static int rotation_thread_function(void *data) __s32 vflip, hflip; set_current_state(TASK_INTERRUPTIBLE); - while (!schedule_timeout(100)) { + while (!schedule_timeout(msecs_to_jiffies(100))) { if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock)) break; -- cgit v1.3-6-gb490 From 03b36e4dcf422a10da8b67bce2ed00b34ec58aac Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Wed, 28 Jan 2015 22:53:53 -0200 Subject: [media] v4l: vsp1: Fix VI6_WPF_SZCLIP_SIZE_MASK macro Clipping size bit of VI6_WPFn _HSZCLIP and VI6_WPFn _VSZCLIP register are from 0 bit to 11 bit. But VI6_WPF_SZCLIP_SIZE_MASK is set to 0x1FFF, this will mask until the reserve bits. This fixes size for VI6_WPF_SZCLIP_SIZE_MASK. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index da3c573e1efc..f61e1096f9fc 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -238,7 +238,7 @@ #define VI6_WPF_SZCLIP_EN (1 << 28) #define VI6_WPF_SZCLIP_OFST_MASK (0xff << 16) #define VI6_WPF_SZCLIP_OFST_SHIFT 16 -#define VI6_WPF_SZCLIP_SIZE_MASK (0x1fff << 0) +#define VI6_WPF_SZCLIP_SIZE_MASK (0xfff << 0) #define VI6_WPF_SZCLIP_SIZE_SHIFT 0 #define VI6_WPF_OUTFMT 0x100c -- cgit v1.3-6-gb490 From 1aa7890324b497f96f07c20673fae58f26fabfe7 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Wed, 28 Jan 2015 22:53:54 -0200 Subject: [media] v4l: vsp1: Fix VI6_DPR_ROUTE_FP_MASK macro FP bit of VI6_DPR_mod_ROUTE register is 6bit. But VI6_DPR_ROUTE_FP_MASK is set to 0xFF, this will mask until the reserve bit. This fixes size for VI6_DPR_ROUTE_FP_MASK. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index f61e1096f9fc..4177f98968d6 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -306,7 +306,7 @@ #define VI6_DPR_BRU_ROUTE 0x204c #define VI6_DPR_ROUTE_FXA_MASK (0xff << 8) #define VI6_DPR_ROUTE_FXA_SHIFT 16 -#define VI6_DPR_ROUTE_FP_MASK (0xff << 8) +#define VI6_DPR_ROUTE_FP_MASK (0x3f << 8) #define VI6_DPR_ROUTE_FP_SHIFT 8 #define VI6_DPR_ROUTE_RT_MASK (0x3f << 0) #define VI6_DPR_ROUTE_RT_SHIFT 0 -- cgit v1.3-6-gb490 From 45008ee9295b3ae96d7413ab91871907a671ca82 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Wed, 28 Jan 2015 22:53:55 -0200 Subject: [media] v4l: vsp1: Fix VI6_DPR_ROUTE_FXA_MASK macro FXA bit of VI6_DPR_mod_ROUTE register starts from 16bit. But VI6_DPR_ROUTE_FXA_MASK is set to become start from 8bit. This fixes shift size for VI6_DPR_ROUTE_FXA_MASK. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 4177f98968d6..25b48738b147 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -304,7 +304,7 @@ #define VI6_DPR_HST_ROUTE 0x2044 #define VI6_DPR_HSI_ROUTE 0x2048 #define VI6_DPR_BRU_ROUTE 0x204c -#define VI6_DPR_ROUTE_FXA_MASK (0xff << 8) +#define VI6_DPR_ROUTE_FXA_MASK (0xff << 16) #define VI6_DPR_ROUTE_FXA_SHIFT 16 #define VI6_DPR_ROUTE_FP_MASK (0x3f << 8) #define VI6_DPR_ROUTE_FP_SHIFT 8 -- cgit v1.3-6-gb490 From 139c92866e34bfa4897e644b36147fc86cc7a7a1 Mon Sep 17 00:00:00 2001 From: Sei Fumizono Date: Sun, 15 Mar 2015 11:33:07 -0300 Subject: [media] v4l: vsp1: Fix Suspend-to-RAM Fix Suspend-to-RAM so that VSP1 driver continues to work after resuming. In detail, - Fix the judgment of ref count in resuming. - Add stopping VSP1 during suspend. [Refactor the suspend and resume code to lower suspend delay] Signed-off-by: Sei Fumizono Signed-off-by: Yoshifumi Hosoya Signed-off-by: Yoshihiro Kaneko Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drv.c | 13 ++++-- drivers/media/platform/vsp1/vsp1_video.c | 70 +++++++++++++++++++++++++++++++- drivers/media/platform/vsp1/vsp1_video.h | 5 ++- 3 files changed, 83 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 913485a90e97..4e61886384e3 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-2014 Renesas Electronics Corporation + * Copyright (C) 2013-2015 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * @@ -403,7 +403,10 @@ static int vsp1_pm_suspend(struct device *dev) if (vsp1->ref_count == 0) return 0; + vsp1_pipelines_suspend(vsp1); + clk_disable_unprepare(vsp1->clock); + return 0; } @@ -413,10 +416,14 @@ static int vsp1_pm_resume(struct device *dev) WARN_ON(mutex_is_locked(&vsp1->lock)); - if (vsp1->ref_count) + if (vsp1->ref_count == 0) return 0; - return clk_prepare_enable(vsp1->clock); + clk_prepare_enable(vsp1->clock); + + vsp1_pipelines_resume(vsp1); + + return 0; } #endif diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index d91f19a9e1c1..c4b06214b6c1 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-2014 Renesas Electronics Corporation + * Copyright (C) 2013-2015 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * @@ -703,6 +703,74 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, } } +void vsp1_pipelines_suspend(struct vsp1_device *vsp1) +{ + unsigned long flags; + unsigned int i; + int ret; + + /* To avoid increasing the system suspend time needlessly, loop over the + * pipelines twice, first to set them all to the stopping state, and then + * to wait for the stop to complete. + */ + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + spin_lock_irqsave(&pipe->irqlock, flags); + if (pipe->state == VSP1_PIPELINE_RUNNING) + pipe->state = VSP1_PIPELINE_STOPPING; + spin_unlock_irqrestore(&pipe->irqlock, flags); + } + + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + ret = wait_event_timeout(pipe->wq, + pipe->state == VSP1_PIPELINE_STOPPED, + msecs_to_jiffies(500)); + if (ret == 0) + dev_warn(vsp1->dev, "pipeline %u stop timeout\n", + wpf->entity.index); + } +} + +void vsp1_pipelines_resume(struct vsp1_device *vsp1) +{ + unsigned int i; + + /* Resume pipeline all running pipelines. */ + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + if (vsp1_pipeline_ready(pipe)) + vsp1_pipeline_run(pipe); + } +} + /* ----------------------------------------------------------------------------- * videobuf2 Queue Operations */ diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h index fd2851a82e00..0887a4d2742c 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-2014 Renesas Electronics Corporation + * Copyright (C) 2013-2015 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * @@ -149,4 +149,7 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, struct vsp1_entity *input, unsigned int alpha); +void vsp1_pipelines_suspend(struct vsp1_device *vsp1); +void vsp1_pipelines_resume(struct vsp1_device *vsp1); + #endif /* __VSP1_VIDEO_H__ */ -- cgit v1.3-6-gb490 From 1c991fee30c72ff49bb96558d5f1c14a60230677 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 29 Apr 2015 16:54:39 -0300 Subject: [media] v4l: vsp1: Fix race condition when stopping pipeline When stopping the pipeline the driver waits for the pipeline state to be set to VSP1_PIPELINE_STOPPED but fails to lock the pipe irqlock to read the state variable protected by the lock. Fix it. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_video.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index c4b06214b6c1..c1b5a09b8331 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -514,6 +514,18 @@ static void vsp1_pipeline_run(struct vsp1_pipeline *pipe) pipe->buffers_ready = 0; } +bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) +{ + unsigned long flags; + bool stopped; + + spin_lock_irqsave(&pipe->irqlock, flags); + stopped = pipe->state == VSP1_PIPELINE_STOPPED, + spin_unlock_irqrestore(&pipe->irqlock, flags); + + return stopped; +} + static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) { struct vsp1_entity *entity; @@ -525,7 +537,7 @@ static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) pipe->state = VSP1_PIPELINE_STOPPING; spin_unlock_irqrestore(&pipe->irqlock, flags); - ret = wait_event_timeout(pipe->wq, pipe->state == VSP1_PIPELINE_STOPPED, + ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe), msecs_to_jiffies(500)); ret = ret == 0 ? -ETIMEDOUT : 0; @@ -741,8 +753,7 @@ void vsp1_pipelines_suspend(struct vsp1_device *vsp1) if (pipe == NULL) continue; - ret = wait_event_timeout(pipe->wq, - pipe->state == VSP1_PIPELINE_STOPPED, + ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe), msecs_to_jiffies(500)); if (ret == 0) dev_warn(vsp1->dev, "pipeline %u stop timeout\n", -- cgit v1.3-6-gb490 From 85a0638b7855dfb00dc9b66bc2fdd4276d7dc87c Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Thu, 28 May 2015 09:59:39 -0300 Subject: [media] v4l: vsp1: Align crop rectangle to even boundary for YUV formats Make sure that there are valid values in the crop rectangle to ensure that the color plane doesn't get shifted when cropping. Since there is no distinction between 12bit and 16bit YUV formats in at the subdev level, use the more restrictive 12bit limits for all YUV formats. Signed-off-by: Damian Hobson-Garcia Signed-off-by: Yoshihiro Kaneko Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_rwpf.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index fa71f4695e16..9688c219b30e 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c @@ -197,6 +197,17 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, */ format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, sel->which); + + /* Restrict the crop rectangle coordinates to multiples of 2 to avoid + * shifting the color plane. + */ + if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { + sel->r.left = ALIGN(sel->r.left, 2); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = round_down(sel->r.width, 2); + sel->r.height = round_down(sel->r.height, 2); + } + sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); if (rwpf->entity.type == VSP1_ENTITY_WPF) { -- cgit v1.3-6-gb490 From 41bdc3cf81c4d0f0dfe09f06ff203dd59d422f37 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 3 Jul 2015 08:35:51 -0300 Subject: [media] vsp1: declar vsp1_pipeline_stopped() as static drivers/media/platform/vsp1/vsp1_video.c:517:6: warning: no previous prototype for 'vsp1_pipeline_stopped' [-Wmissing-prototypes] bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index c1b5a09b8331..770e08dc03f1 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -514,7 +514,7 @@ static void vsp1_pipeline_run(struct vsp1_pipeline *pipe) pipe->buffers_ready = 0; } -bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) +static bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) { unsigned long flags; bool stopped; -- cgit v1.3-6-gb490 From 4690271ce14cd4cf4796e0b6631978d151abe8e4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:57:56 -0300 Subject: [media] sh-vou: use resource managed calls Simplify the sh-vou clean up by using devm_* were possible. Signed-off-by: Hans Verkuil Cc: Magnus Damm Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 43 ++++++++--------------------------------- 1 file changed, 8 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 8b799bae01b8..801d5ef4dc28 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -1300,7 +1300,7 @@ static int sh_vou_probe(struct platform_device *pdev) struct i2c_adapter *i2c_adap; struct video_device *vdev; struct sh_vou_device *vou_dev; - struct resource *reg_res, *region; + struct resource *reg_res; struct v4l2_subdev *subdev; int irq, ret; @@ -1312,7 +1312,7 @@ static int sh_vou_probe(struct platform_device *pdev) return -ENODEV; } - vou_dev = kzalloc(sizeof(*vou_dev), GFP_KERNEL); + vou_dev = devm_kzalloc(&pdev->dev, sizeof(*vou_dev), GFP_KERNEL); if (!vou_dev) return -ENOMEM; @@ -1340,28 +1340,18 @@ static int sh_vou_probe(struct platform_device *pdev) pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - region = request_mem_region(reg_res->start, resource_size(reg_res), - pdev->name); - if (!region) { - dev_err(&pdev->dev, "VOU region already claimed\n"); - ret = -EBUSY; - goto ereqmemreg; - } - - vou_dev->base = ioremap(reg_res->start, resource_size(reg_res)); - if (!vou_dev->base) { - ret = -ENOMEM; - goto emap; - } + vou_dev->base = devm_ioremap_resource(&pdev->dev, reg_res); + if (IS_ERR(vou_dev->base)) + return PTR_ERR(vou_dev->base); - ret = request_irq(irq, sh_vou_isr, 0, "vou", vou_dev); + ret = devm_request_irq(&pdev->dev, irq, sh_vou_isr, 0, "vou", vou_dev); if (ret < 0) - goto ereqirq; + return ret; ret = v4l2_device_register(&pdev->dev, &vou_dev->v4l2_dev); if (ret < 0) { dev_err(&pdev->dev, "Error registering v4l2 device\n"); - goto ev4l2devreg; + return ret; } vdev = &vou_dev->vdev; @@ -1407,39 +1397,22 @@ ereset: ei2cgadap: pm_runtime_disable(&pdev->dev); v4l2_device_unregister(&vou_dev->v4l2_dev); -ev4l2devreg: - free_irq(irq, vou_dev); -ereqirq: - iounmap(vou_dev->base); -emap: - release_mem_region(reg_res->start, resource_size(reg_res)); -ereqmemreg: - kfree(vou_dev); return ret; } static int sh_vou_remove(struct platform_device *pdev) { - int irq = platform_get_irq(pdev, 0); struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); struct sh_vou_device *vou_dev = container_of(v4l2_dev, struct sh_vou_device, v4l2_dev); struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next, struct v4l2_subdev, list); struct i2c_client *client = v4l2_get_subdevdata(sd); - struct resource *reg_res; - if (irq > 0) - free_irq(irq, vou_dev); pm_runtime_disable(&pdev->dev); video_unregister_device(&vou_dev->vdev); i2c_put_adapter(client->adapter); v4l2_device_unregister(&vou_dev->v4l2_dev); - iounmap(vou_dev->base); - reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (reg_res) - release_mem_region(reg_res->start, resource_size(reg_res)); - kfree(vou_dev); return 0; } -- cgit v1.3-6-gb490 From d8046ee09f843cb314a660f589a334bce84a7efa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:57:57 -0300 Subject: [media] sh-vou: fix querycap support Fix v4l2-compliance errors due to empty driver and bus_info fields. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 801d5ef4dc28..d7a72a9ba90b 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -396,6 +396,8 @@ static int sh_vou_querycap(struct file *file, void *priv, dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); strlcpy(cap->card, "SuperH VOU", sizeof(cap->card)); + strlcpy(cap->driver, "sh-vou", sizeof(cap->driver)); + strlcpy(cap->bus_info, "platform:sh-vou", sizeof(cap->bus_info)); cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; -- cgit v1.3-6-gb490 From c5f98085bf3f1d645aaf76eac7c9ca0e2ab684c6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:57:58 -0300 Subject: [media] sh-vou: use v4l2_fh This allows us to drop the use_count and you get free G/S_PRIORITY support. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index d7a72a9ba90b..4994b7ba9236 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -63,7 +63,6 @@ enum sh_vou_status { struct sh_vou_device { struct v4l2_device v4l2_dev; struct video_device vdev; - atomic_t use_count; struct sh_vou_pdata *pdata; spinlock_t lock; void __iomem *base; @@ -79,6 +78,7 @@ struct sh_vou_device { }; struct sh_vou_file { + struct v4l2_fh fh; struct videobuf_queue vbq; }; @@ -1173,20 +1173,24 @@ static int sh_vou_open(struct file *file) dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + v4l2_fh_init(&vou_file->fh, &vou_dev->vdev); if (mutex_lock_interruptible(&vou_dev->fop_lock)) { kfree(vou_file); return -ERESTARTSYS; } - if (atomic_inc_return(&vou_dev->use_count) == 1) { + v4l2_fh_add(&vou_file->fh); + if (v4l2_fh_is_singular(&vou_file->fh)) { int ret; + /* First open */ vou_dev->status = SH_VOU_INITIALISING; pm_runtime_get_sync(vou_dev->v4l2_dev.dev); ret = sh_vou_hw_init(vou_dev); if (ret < 0) { - atomic_dec(&vou_dev->use_count); pm_runtime_put(vou_dev->v4l2_dev.dev); vou_dev->status = SH_VOU_IDLE; + v4l2_fh_del(&vou_file->fh); + v4l2_fh_exit(&vou_file->fh); mutex_unlock(&vou_dev->fop_lock); kfree(vou_file); return ret; @@ -1213,14 +1217,16 @@ static int sh_vou_release(struct file *file) dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - if (!atomic_dec_return(&vou_dev->use_count)) { - mutex_lock(&vou_dev->fop_lock); + mutex_lock(&vou_dev->fop_lock); + if (v4l2_fh_is_singular(&vou_file->fh)) { /* Last close */ vou_dev->status = SH_VOU_IDLE; sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101); pm_runtime_put(vou_dev->v4l2_dev.dev); - mutex_unlock(&vou_dev->fop_lock); } + v4l2_fh_del(&vou_file->fh); + v4l2_fh_exit(&vou_file->fh); + mutex_unlock(&vou_dev->fop_lock); file->private_data = NULL; kfree(vou_file); @@ -1321,7 +1327,6 @@ static int sh_vou_probe(struct platform_device *pdev) INIT_LIST_HEAD(&vou_dev->queue); spin_lock_init(&vou_dev->lock); mutex_init(&vou_dev->fop_lock); - atomic_set(&vou_dev->use_count, 0); vou_dev->pdata = vou_pdata; vou_dev->status = SH_VOU_IDLE; -- cgit v1.3-6-gb490 From 4de00d0efe0a7af8e2ef591effa2a559b7cc38a3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:57:59 -0300 Subject: [media] sh-vou: support compulsory G/S/ENUM_OUTPUT ioctls Video output drivers must support these ioctls. Otherwise applications cannot deduce that these outputs exist and what capabilities they have. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 4994b7ba9236..d9a4502b4a58 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -872,6 +872,30 @@ static int sh_vou_streamoff(struct file *file, void *priv, return 0; } +static int sh_vou_enum_output(struct file *file, void *fh, + struct v4l2_output *a) +{ + struct sh_vou_device *vou_dev = video_drvdata(file); + + if (a->index) + return -EINVAL; + strlcpy(a->name, "Video Out", sizeof(a->name)); + a->type = V4L2_OUTPUT_TYPE_ANALOG; + a->std = vou_dev->vdev.tvnorms; + return 0; +} + +int sh_vou_g_output(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; + return 0; +} + +int sh_vou_s_output(struct file *file, void *fh, unsigned int i) +{ + return i ? -EINVAL : 0; +} + static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt) { switch (bus_fmt) { @@ -1276,6 +1300,9 @@ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { .vidioc_dqbuf = sh_vou_dqbuf, .vidioc_streamon = sh_vou_streamon, .vidioc_streamoff = sh_vou_streamoff, + .vidioc_g_output = sh_vou_g_output, + .vidioc_s_output = sh_vou_s_output, + .vidioc_enum_output = sh_vou_enum_output, .vidioc_s_std = sh_vou_s_std, .vidioc_g_std = sh_vou_g_std, .vidioc_cropcap = sh_vou_cropcap, -- cgit v1.3-6-gb490 From 22df2e7a390f6cb31c6a5b0d8051d0ec83769ed1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:58:00 -0300 Subject: [media] sh-vou: fix incorrect initial pixelformat It was set to a format that wasn't supported. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index d9a4502b4a58..262c244fcc39 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -1368,7 +1368,7 @@ static int sh_vou_probe(struct platform_device *pdev) rect->height = 480; pix->width = VOU_MAX_IMAGE_WIDTH; pix->height = 480; - pix->pixelformat = V4L2_PIX_FMT_YVYU; + pix->pixelformat = V4L2_PIX_FMT_NV16; pix->field = V4L2_FIELD_NONE; pix->bytesperline = VOU_MAX_IMAGE_WIDTH * 2; pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480; -- cgit v1.3-6-gb490 From 61fbacc115731d2b0435f959f94ff7eb8c3c1059 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:58:01 -0300 Subject: [media] sh-vou: replace g/s_crop/cropcap by g/s_selection Implement g/s_selection. The v4l2 core will emulate g/s_crop and cropcap on top of g/s_selection. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 71 +++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 262c244fcc39..9479c4429e97 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -949,24 +949,36 @@ static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } -static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a) +static int sh_vou_g_selection(struct file *file, void *fh, + struct v4l2_selection *sel) { struct sh_vou_device *vou_dev = video_drvdata(file); - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - a->c = vou_dev->rect; - + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + switch (sel->target) { + case V4L2_SEL_TGT_COMPOSE: + sel->r = vou_dev->rect; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = VOU_MAX_IMAGE_WIDTH; + sel->r.height = VOU_MAX_IMAGE_HEIGHT; + break; + default: + return -EINVAL; + } return 0; } /* Assume a dull encoder, do all the work ourselves. */ -static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) +static int sh_vou_s_selection(struct file *file, void *fh, + struct v4l2_selection *sel) { - struct v4l2_crop a_writable = *a; + struct v4l2_rect *rect = &sel->r; struct sh_vou_device *vou_dev = video_drvdata(file); - struct v4l2_rect *rect = &a_writable.c; struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT}; struct v4l2_pix_format *pix = &vou_dev->pix; struct sh_vou_geometry geo; @@ -980,10 +992,8 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) unsigned int img_height_max; int ret; - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__, - rect->width, rect->height, rect->left, rect->top); - - if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || + sel->target != V4L2_SEL_TGT_COMPOSE) return -EINVAL; if (vou_dev->std & V4L2_STD_525_60) @@ -1047,36 +1057,6 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) return 0; } -/* - * Total field: NTSC 858 x 2 * 262/263, PAL 864 x 2 * 312/313, default rectangle - * is the initial register values, height takes the interlaced format into - * account. The actual image can only go up to 720 x 2 * 240, So, VOUVPR can - * actually only meaningfully contain values <= 720 and <= 240 respectively, and - * not <= 864 and <= 312. - */ -static int sh_vou_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *a) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = VOU_MAX_IMAGE_WIDTH; - a->bounds.height = VOU_MAX_IMAGE_HEIGHT; - /* Default = max, set VOUDPR = 0, which is not hardware default */ - a->defrect.left = 0; - a->defrect.top = 0; - a->defrect.width = VOU_MAX_IMAGE_WIDTH; - a->defrect.height = VOU_MAX_IMAGE_HEIGHT; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - static irqreturn_t sh_vou_isr(int irq, void *dev_id) { struct sh_vou_device *vou_dev = dev_id; @@ -1305,9 +1285,8 @@ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { .vidioc_enum_output = sh_vou_enum_output, .vidioc_s_std = sh_vou_s_std, .vidioc_g_std = sh_vou_g_std, - .vidioc_cropcap = sh_vou_cropcap, - .vidioc_g_crop = sh_vou_g_crop, - .vidioc_s_crop = sh_vou_s_crop, + .vidioc_g_selection = sh_vou_g_selection, + .vidioc_s_selection = sh_vou_s_selection, }; static const struct v4l2_file_operations sh_vou_fops = { -- cgit v1.3-6-gb490 From 66853ec4e1d096efe406383adc219285e5516af4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:58:03 -0300 Subject: [media] sh-vou: let sh_vou_s_fmt_vid_out call sh_vou_try_fmt_vid_out This ensures that both do the same checks, and simplifies s_fmt_vid_out a bit. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 86 +++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 9479c4429e97..079910d7062f 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -673,34 +673,19 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std) vou_scale_v_num[idx_v], vou_scale_v_den[idx_v], best); } -static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) +static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) { struct sh_vou_device *vou_dev = video_drvdata(file); struct v4l2_pix_format *pix = &fmt->fmt.pix; unsigned int img_height_max; int pix_idx; - struct sh_vou_geometry geo; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - /* Revisit: is this the correct code? */ - .format.code = MEDIA_BUS_FMT_YUYV8_2X8, - .format.field = V4L2_FIELD_INTERLACED, - .format.colorspace = V4L2_COLORSPACE_SMPTE170M, - }; - struct v4l2_mbus_framefmt *mbfmt = &format.format; - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, - vou_dev->rect.width, vou_dev->rect.height, - pix->width, pix->height); - if (pix->field == V4L2_FIELD_ANY) - pix->field = V4L2_FIELD_NONE; + dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - if (fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || - pix->field != V4L2_FIELD_NONE) - return -EINVAL; + pix->field = V4L2_FIELD_INTERLACED; + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + pix->ycbcr_enc = pix->quantization = 0; for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++) if (vou_fmt[pix_idx].pfmt == pix->pixelformat) @@ -714,9 +699,37 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, else img_height_max = 576; - /* Image width must be a multiple of 4 */ v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2, &pix->height, 0, img_height_max, 1, 0); + pix->bytesperline = pix->width * 2; + + return 0; +} + +static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct sh_vou_device *vou_dev = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + unsigned int img_height_max; + struct sh_vou_geometry geo; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + /* Revisit: is this the correct code? */ + .format.code = MEDIA_BUS_FMT_YUYV8_2X8, + .format.field = V4L2_FIELD_INTERLACED, + .format.colorspace = V4L2_COLORSPACE_SMPTE170M, + }; + struct v4l2_mbus_framefmt *mbfmt = &format.format; + int ret = sh_vou_try_fmt_vid_out(file, priv, fmt); + int pix_idx; + + if (ret) + return ret; + + for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++) + if (vou_fmt[pix_idx].pfmt == pix->pixelformat) + break; geo.in_width = pix->width; geo.in_height = pix->height; @@ -735,6 +748,11 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, geo.output.width, geo.output.height, mbfmt->width, mbfmt->height); + if (vou_dev->std & V4L2_STD_525_60) + img_height_max = 480; + else + img_height_max = 576; + /* Sanity checks */ if ((unsigned)mbfmt->width > VOU_MAX_IMAGE_WIDTH || (unsigned)mbfmt->height > img_height_max || @@ -767,30 +785,6 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, return 0; } -static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int i; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - pix->field = V4L2_FIELD_NONE; - - v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1, - &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0); - - for (i = 0; i < ARRAY_SIZE(vou_fmt); i++) - if (vou_fmt[i].pfmt == pix->pixelformat) - return 0; - - pix->pixelformat = vou_fmt[0].pfmt; - - return 0; -} - static int sh_vou_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *req) { -- cgit v1.3-6-gb490 From 5c3edcb225d6690000c2563c573984042747b28d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:58:04 -0300 Subject: [media] sh-vou: fix bytesperline The bytesperline values were wrong for planar formats where bytesperline is the line length for the first plane. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 079910d7062f..6cf80835e8ba 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -133,6 +133,7 @@ struct sh_vou_fmt { u32 pfmt; char *desc; unsigned char bpp; + unsigned char bpl; unsigned char rgb; unsigned char yf; unsigned char pkf; @@ -143,6 +144,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_NV12, .bpp = 12, + .bpl = 1, .desc = "YVU420 planar", .yf = 0, .rgb = 0, @@ -150,6 +152,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_NV16, .bpp = 16, + .bpl = 1, .desc = "YVYU planar", .yf = 1, .rgb = 0, @@ -157,6 +160,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_RGB24, .bpp = 24, + .bpl = 3, .desc = "RGB24", .pkf = 2, .rgb = 1, @@ -164,6 +168,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_RGB565, .bpp = 16, + .bpl = 2, .desc = "RGB565", .pkf = 3, .rgb = 1, @@ -171,6 +176,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_RGB565X, .bpp = 16, + .bpl = 2, .desc = "RGB565 byteswapped", .pkf = 3, .rgb = 1, @@ -701,7 +707,8 @@ static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2, &pix->height, 0, img_height_max, 1, 0); - pix->bytesperline = pix->width * 2; + pix->bytesperline = pix->width * vou_fmt[pix_idx].bpl; + pix->sizeimage = pix->height * ((pix->width * vou_fmt[pix_idx].bpp) >> 3); return 0; } @@ -1343,7 +1350,7 @@ static int sh_vou_probe(struct platform_device *pdev) pix->height = 480; pix->pixelformat = V4L2_PIX_FMT_NV16; pix->field = V4L2_FIELD_NONE; - pix->bytesperline = VOU_MAX_IMAGE_WIDTH * 2; + pix->bytesperline = VOU_MAX_IMAGE_WIDTH; pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; -- cgit v1.3-6-gb490 From 57af3ad59d953f300a1fcb143e72d024aff73550 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:58:05 -0300 Subject: [media] sh-vou: convert to vb2 This converts this driver to videobuf2. As usual it is a big and hard to review patch, but this is always a big-bang change. It has been tested with my Renesas board. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 590 +++++++++++++++++----------------------- 1 file changed, 250 insertions(+), 340 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 6cf80835e8ba..da8ea6a76327 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include /* Mirror addresses are not available for all registers */ #define VOUER 0 @@ -57,8 +57,19 @@ enum sh_vou_status { SH_VOU_RUNNING, }; +#define VOU_MIN_IMAGE_WIDTH 16 #define VOU_MAX_IMAGE_WIDTH 720 -#define VOU_MAX_IMAGE_HEIGHT 576 +#define VOU_MIN_IMAGE_HEIGHT 16 + +struct sh_vou_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + +static inline struct sh_vou_buffer *to_sh_vou_buffer(struct vb2_buffer *vb2) +{ + return container_of(vb2, struct sh_vou_buffer, vb); +} struct sh_vou_device { struct v4l2_device v4l2_dev; @@ -69,19 +80,17 @@ struct sh_vou_device { /* State information */ struct v4l2_pix_format pix; struct v4l2_rect rect; - struct list_head queue; + struct list_head buf_list; v4l2_std_id std; int pix_idx; - struct videobuf_buffer *active; + struct vb2_queue queue; + struct vb2_alloc_ctx *alloc_ctx; + struct sh_vou_buffer *active; enum sh_vou_status status; + unsigned sequence; struct mutex fop_lock; }; -struct sh_vou_file { - struct v4l2_fh fh; - struct videobuf_queue vbq; -}; - /* Register access routines for sides A, B and mirror addresses */ static void sh_vou_reg_a_write(struct sh_vou_device *vou_dev, unsigned int reg, u32 value) @@ -184,11 +193,11 @@ static struct sh_vou_fmt vou_fmt[] = { }; static void sh_vou_schedule_next(struct sh_vou_device *vou_dev, - struct videobuf_buffer *vb) + struct vb2_buffer *vb) { dma_addr_t addr1, addr2; - addr1 = videobuf_to_dma_contig(vb); + addr1 = vb2_dma_contig_plane_dma_addr(vb, 0); switch (vou_dev->pix.pixelformat) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: @@ -202,8 +211,7 @@ static void sh_vou_schedule_next(struct sh_vou_device *vou_dev, sh_vou_reg_m_write(vou_dev, VOUAD2R, addr2); } -static void sh_vou_stream_start(struct sh_vou_device *vou_dev, - struct videobuf_buffer *vb) +static void sh_vou_stream_config(struct sh_vou_device *vou_dev) { unsigned int row_coeff; #ifdef __LITTLE_ENDIAN @@ -230,167 +238,136 @@ static void sh_vou_stream_start(struct sh_vou_device *vou_dev, sh_vou_reg_a_write(vou_dev, VOUSWR, dataswap); sh_vou_reg_ab_write(vou_dev, VOUAIR, vou_dev->pix.width * row_coeff); - sh_vou_schedule_next(vou_dev, vb); -} - -static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - BUG_ON(in_interrupt()); - - /* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */ - videobuf_waiton(vq, vb, 0, 0); - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; } /* Locking: caller holds fop_lock mutex */ -static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) +static int sh_vou_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - - *size = vou_fmt[vou_dev->pix_idx].bpp * vou_dev->pix.width * - vou_dev->pix.height / 8; - - if (*count < 2) - *count = 2; - - /* Taking into account maximum frame size, *count will stay >= 2 */ - if (PAGE_ALIGN(*size) * *count > 4 * 1024 * 1024) - *count = 4 * 1024 * 1024 / PAGE_ALIGN(*size); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); + struct v4l2_pix_format *pix = &vou_dev->pix; + int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): count=%d, size=%d\n", __func__, - *count, *size); + dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + if (fmt && fmt->fmt.pix.sizeimage < pix->height * bytes_per_line) + return -EINVAL; + *nplanes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : pix->height * bytes_per_line; + alloc_ctxs[0] = vou_dev->alloc_ctx; return 0; } -/* Locking: caller holds fop_lock mutex */ -static int sh_vou_buf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) +static int sh_vou_buf_prepare(struct vb2_buffer *vb) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vb->vb2_queue); struct v4l2_pix_format *pix = &vou_dev->pix; - int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; - int ret; + unsigned bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; + unsigned size = pix->height * bytes_per_line; dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - if (vb->width != pix->width || - vb->height != pix->height || - vb->field != pix->field) { - vb->width = pix->width; - vb->height = pix->height; - vb->field = field; - if (vb->state != VIDEOBUF_NEEDS_INIT) - free_buffer(vq, vb); - } - - vb->size = vb->height * bytes_per_line; - if (vb->baddr && vb->bsize < vb->size) { + if (vb2_plane_size(vb, 0) < size) { /* User buffer too small */ - dev_warn(vq->dev, "User buffer too small: [%zu] @ %lx\n", - vb->bsize, vb->baddr); + dev_warn(vou_dev->v4l2_dev.dev, "buffer too small (%lu < %u)\n", + vb2_plane_size(vb, 0), size); return -EINVAL; } - if (vb->state == VIDEOBUF_NEEDS_INIT) { - ret = videobuf_iolock(vq, vb, NULL); - if (ret < 0) { - dev_warn(vq->dev, "IOLOCK buf-type %d: %d\n", - vb->memory, ret); - return ret; - } - vb->state = VIDEOBUF_PREPARED; - } - - dev_dbg(vou_dev->v4l2_dev.dev, - "%s(): fmt #%d, %u bytes per line, phys %pad, type %d, state %d\n", - __func__, vou_dev->pix_idx, bytes_per_line, - ({ dma_addr_t addr = videobuf_to_dma_contig(vb); &addr; }), - vb->memory, vb->state); - + vb2_set_plane_payload(vb, 0, size); return 0; } /* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */ -static void sh_vou_buf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void sh_vou_buf_queue(struct vb2_buffer *vb) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vb->vb2_queue); + struct sh_vou_buffer *shbuf = to_sh_vou_buffer(vb); + unsigned long flags; - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + spin_lock_irqsave(&vou_dev->lock, flags); + list_add_tail(&shbuf->list, &vou_dev->buf_list); + spin_unlock_irqrestore(&vou_dev->lock, flags); +} - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &vou_dev->queue); - - if (vou_dev->status == SH_VOU_RUNNING) { - return; - } else if (!vou_dev->active) { - vou_dev->active = vb; - /* Start from side A: we use mirror addresses, so, set B */ - sh_vou_reg_a_write(vou_dev, VOURPR, 1); - dev_dbg(vou_dev->v4l2_dev.dev, "%s: first buffer status 0x%x\n", - __func__, sh_vou_reg_a_read(vou_dev, VOUSTR)); - sh_vou_schedule_next(vou_dev, vb); - /* Only activate VOU after the second buffer */ - } else if (vou_dev->active->queue.next == &vb->queue) { - /* Second buffer - initialise register side B */ - sh_vou_reg_a_write(vou_dev, VOURPR, 0); - sh_vou_stream_start(vou_dev, vb); - - /* Register side switching with frame VSYNC */ - sh_vou_reg_a_write(vou_dev, VOURCR, 5); - dev_dbg(vou_dev->v4l2_dev.dev, "%s: second buffer status 0x%x\n", - __func__, sh_vou_reg_a_read(vou_dev, VOUSTR)); - - /* Enable End-of-Frame (VSYNC) interrupts */ - sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004); - /* Two buffers on the queue - activate the hardware */ - - vou_dev->status = SH_VOU_RUNNING; - sh_vou_reg_a_write(vou_dev, VOUER, 0x107); +static int sh_vou_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); + struct sh_vou_buffer *buf, *node; + int ret; + + vou_dev->sequence = 0; + ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, + video, s_stream, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) { + list_for_each_entry_safe(buf, node, &vou_dev->buf_list, list) { + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + list_del(&buf->list); + } + vou_dev->active = NULL; + return ret; } + + buf = list_entry(vou_dev->buf_list.next, struct sh_vou_buffer, list); + + vou_dev->active = buf; + + /* Start from side A: we use mirror addresses, so, set B */ + sh_vou_reg_a_write(vou_dev, VOURPR, 1); + dev_dbg(vou_dev->v4l2_dev.dev, "%s: first buffer status 0x%x\n", + __func__, sh_vou_reg_a_read(vou_dev, VOUSTR)); + sh_vou_schedule_next(vou_dev, &buf->vb); + + buf = list_entry(buf->list.next, struct sh_vou_buffer, list); + + /* Second buffer - initialise register side B */ + sh_vou_reg_a_write(vou_dev, VOURPR, 0); + sh_vou_schedule_next(vou_dev, &buf->vb); + + /* Register side switching with frame VSYNC */ + sh_vou_reg_a_write(vou_dev, VOURCR, 5); + + sh_vou_stream_config(vou_dev); + /* Enable End-of-Frame (VSYNC) interrupts */ + sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004); + + /* Two buffers on the queue - activate the hardware */ + vou_dev->status = SH_VOU_RUNNING; + sh_vou_reg_a_write(vou_dev, VOUER, 0x107); + return 0; } -static void sh_vou_buf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void sh_vou_stop_streaming(struct vb2_queue *vq) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); + struct sh_vou_buffer *buf, *node; unsigned long flags; - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - + v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, + video, s_stream, 0); + /* disable output */ + sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); + /* ...but the current frame will complete */ + sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); + msleep(50); spin_lock_irqsave(&vou_dev->lock, flags); - - if (vou_dev->active == vb) { - /* disable output */ - sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); - /* ...but the current frame will complete */ - sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); - vou_dev->active = NULL; + list_for_each_entry_safe(buf, node, &vou_dev->buf_list, list) { + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + list_del(&buf->list); } - - if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED)) { - vb->state = VIDEOBUF_ERROR; - list_del(&vb->queue); - } - + vou_dev->active = NULL; spin_unlock_irqrestore(&vou_dev->lock, flags); - - free_buffer(vq, vb); } -static struct videobuf_queue_ops sh_vou_video_qops = { - .buf_setup = sh_vou_buf_setup, - .buf_prepare = sh_vou_buf_prepare, - .buf_queue = sh_vou_buf_queue, - .buf_release = sh_vou_buf_release, +static struct vb2_ops sh_vou_qops = { + .queue_setup = sh_vou_queue_setup, + .buf_prepare = sh_vou_buf_prepare, + .buf_queue = sh_vou_buf_queue, + .start_streaming = sh_vou_start_streaming, + .stop_streaming = sh_vou_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; /* Video IOCTLs */ @@ -404,7 +381,8 @@ static int sh_vou_querycap(struct file *file, void *priv, strlcpy(cap->card, "SuperH VOU", sizeof(cap->card)); strlcpy(cap->driver, "sh-vou", sizeof(cap->driver)); strlcpy(cap->bus_info, "platform:sh-vou", sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -548,8 +526,10 @@ static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std) img_height_max = 576; /* Image width must be a multiple of 4 */ - v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2, - &geo->in_height, 0, img_height_max, 1, 0); + v4l_bound_align_image(&geo->in_width, + VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 2, + &geo->in_height, + VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); /* Select scales to come as close as possible to the output image */ for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) { @@ -705,19 +685,19 @@ static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, else img_height_max = 576; - v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2, - &pix->height, 0, img_height_max, 1, 0); + v4l_bound_align_image(&pix->width, + VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 2, + &pix->height, + VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); pix->bytesperline = pix->width * vou_fmt[pix_idx].bpl; pix->sizeimage = pix->height * ((pix->width * vou_fmt[pix_idx].bpp) >> 3); return 0; } -static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) +static int sh_vou_set_fmt_vid_out(struct sh_vou_device *vou_dev, + struct v4l2_pix_format *pix) { - struct sh_vou_device *vou_dev = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; unsigned int img_height_max; struct sh_vou_geometry geo; struct v4l2_subdev_format format = { @@ -728,11 +708,11 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, .format.colorspace = V4L2_COLORSPACE_SMPTE170M, }; struct v4l2_mbus_framefmt *mbfmt = &format.format; - int ret = sh_vou_try_fmt_vid_out(file, priv, fmt); int pix_idx; + int ret; - if (ret) - return ret; + if (vb2_is_busy(&vou_dev->queue)) + return -EBUSY; for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++) if (vou_fmt[pix_idx].pfmt == pix->pixelformat) @@ -792,85 +772,15 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, return 0; } -static int sh_vou_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - return videobuf_reqbufs(&vou_file->vbq, req); -} - -static int sh_vou_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - return videobuf_querybuf(&vou_file->vbq, b); -} - -static int sh_vou_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - return videobuf_qbuf(&vou_file->vbq, b); -} - -static int sh_vou_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - return videobuf_dqbuf(&vou_file->vbq, b, file->f_flags & O_NONBLOCK); -} - -static int sh_vou_streamon(struct file *file, void *priv, - enum v4l2_buf_type buftype) +static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) { struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + int ret = sh_vou_try_fmt_vid_out(file, priv, fmt); - ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, - video, s_stream, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) + if (ret) return ret; - - /* This calls our .buf_queue() (== sh_vou_buf_queue) */ - return videobuf_streamon(&vou_file->vbq); -} - -static int sh_vou_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - /* - * This calls buf_release from host driver's videobuf_queue_ops for all - * remaining buffers. When the last buffer is freed, stop streaming - */ - videobuf_streamoff(&vou_file->vbq); - v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_stream, 0); - - return 0; + return sh_vou_set_fmt_vid_out(vou_dev, &fmt->fmt.pix); } static int sh_vou_enum_output(struct file *file, void *fh, @@ -919,8 +829,11 @@ static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id) dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id); - if (std_id & ~vou_dev->vdev.tvnorms) - return -EINVAL; + if (std_id == vou_dev->std) + return 0; + + if (vb2_is_busy(&vou_dev->queue)) + return -EBUSY; ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_std_output, std_id); @@ -928,13 +841,25 @@ static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id) if (ret < 0 && ret != -ENOIOCTLCMD) return ret; - if (std_id & V4L2_STD_525_60) + vou_dev->rect.top = vou_dev->rect.left = 0; + vou_dev->rect.width = VOU_MAX_IMAGE_WIDTH; + if (std_id & V4L2_STD_525_60) { sh_vou_reg_ab_set(vou_dev, VOUCR, sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29); - else + vou_dev->rect.height = 480; + } else { sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29); + vou_dev->rect.height = 576; + } + vou_dev->pix.width = vou_dev->rect.width; + vou_dev->pix.height = vou_dev->rect.height; + vou_dev->pix.bytesperline = + vou_dev->pix.width * vou_fmt[vou_dev->pix_idx].bpl; + vou_dev->pix.sizeimage = vou_dev->pix.height * + ((vou_dev->pix.width * vou_fmt[vou_dev->pix_idx].bpp) >> 3); vou_dev->std = std_id; + sh_vou_set_fmt_vid_out(vou_dev, &vou_dev->pix); return 0; } @@ -966,7 +891,10 @@ static int sh_vou_g_selection(struct file *file, void *fh, sel->r.left = 0; sel->r.top = 0; sel->r.width = VOU_MAX_IMAGE_WIDTH; - sel->r.height = VOU_MAX_IMAGE_HEIGHT; + if (vou_dev->std & V4L2_STD_525_60) + sel->r.height = 480; + else + sel->r.height = 576; break; default: return -EINVAL; @@ -997,13 +925,18 @@ static int sh_vou_s_selection(struct file *file, void *fh, sel->target != V4L2_SEL_TGT_COMPOSE) return -EINVAL; + if (vb2_is_busy(&vou_dev->queue)) + return -EBUSY; + if (vou_dev->std & V4L2_STD_525_60) img_height_max = 480; else img_height_max = 576; - v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1, - &rect->height, 0, img_height_max, 1, 0); + v4l_bound_align_image(&rect->width, + VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 1, + &rect->height, + VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH) rect->left = VOU_MAX_IMAGE_WIDTH - rect->width; @@ -1062,7 +995,7 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id) { struct sh_vou_device *vou_dev = dev_id; static unsigned long j; - struct videobuf_buffer *vb; + struct sh_vou_buffer *vb; static int cnt; u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked; u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR); @@ -1075,7 +1008,7 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id) } spin_lock(&vou_dev->lock); - if (!vou_dev->active || list_empty(&vou_dev->queue)) { + if (!vou_dev->active || list_empty(&vou_dev->buf_list)) { if (printk_timed_ratelimit(&j, 500)) dev_warn(vou_dev->v4l2_dev.dev, "IRQ without active buffer: %x!\n", irq_status); @@ -1097,33 +1030,30 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id) sh_vou_reg_a_write(vou_dev, VOUIR, masked); vb = vou_dev->active; - list_del(&vb->queue); - - vb->state = VIDEOBUF_DONE; - v4l2_get_timestamp(&vb->ts); - vb->field_count++; - wake_up(&vb->done); - - if (list_empty(&vou_dev->queue)) { - /* Stop VOU */ - dev_dbg(vou_dev->v4l2_dev.dev, "%s: queue empty after %d\n", - __func__, cnt); - sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); - vou_dev->active = NULL; - vou_dev->status = SH_VOU_INITIALISING; - /* Disable End-of-Frame (VSYNC) interrupts */ - sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); + if (list_is_singular(&vb->list)) { + /* Keep cycling while no next buffer is available */ + sh_vou_schedule_next(vou_dev, &vb->vb); spin_unlock(&vou_dev->lock); return IRQ_HANDLED; } - vou_dev->active = list_entry(vou_dev->queue.next, - struct videobuf_buffer, queue); + list_del(&vb->list); + + v4l2_get_timestamp(&vb->vb.v4l2_buf.timestamp); + vb->vb.v4l2_buf.sequence = vou_dev->sequence++; + vb->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; + vb2_buffer_done(&vb->vb, VB2_BUF_STATE_DONE); + + vou_dev->active = list_entry(vou_dev->buf_list.next, + struct sh_vou_buffer, list); - if (vou_dev->active->queue.next != &vou_dev->queue) { - struct videobuf_buffer *new = list_entry(vou_dev->active->queue.next, - struct videobuf_buffer, queue); - sh_vou_schedule_next(vou_dev, new); + if (list_is_singular(&vou_dev->buf_list)) { + /* Keep cycling while no next buffer is available */ + sh_vou_schedule_next(vou_dev, &vou_dev->active->vb); + } else { + struct sh_vou_buffer *new = list_entry(vou_dev->active->list.next, + struct sh_vou_buffer, list); + sh_vou_schedule_next(vou_dev, &new->vb); } spin_unlock(&vou_dev->lock); @@ -1163,6 +1093,8 @@ static int sh_vou_hw_init(struct sh_vou_device *vou_dev) /* Default - fixed HSYNC length, can be made configurable is required */ sh_vou_reg_ab_write(vou_dev, VOUMSR, 0x800000); + sh_vou_set_fmt_vid_out(vou_dev, &vou_dev->pix); + return 0; } @@ -1170,104 +1102,49 @@ static int sh_vou_hw_init(struct sh_vou_device *vou_dev) static int sh_vou_open(struct file *file) { struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = kzalloc(sizeof(struct sh_vou_file), - GFP_KERNEL); - - if (!vou_file) - return -ENOMEM; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + int err; - v4l2_fh_init(&vou_file->fh, &vou_dev->vdev); - if (mutex_lock_interruptible(&vou_dev->fop_lock)) { - kfree(vou_file); + if (mutex_lock_interruptible(&vou_dev->fop_lock)) return -ERESTARTSYS; - } - v4l2_fh_add(&vou_file->fh); - if (v4l2_fh_is_singular(&vou_file->fh)) { - int ret; + err = v4l2_fh_open(file); + if (err) + goto done_open; + if (v4l2_fh_is_singular_file(file) && + vou_dev->status == SH_VOU_INITIALISING) { /* First open */ - vou_dev->status = SH_VOU_INITIALISING; pm_runtime_get_sync(vou_dev->v4l2_dev.dev); - ret = sh_vou_hw_init(vou_dev); - if (ret < 0) { + err = sh_vou_hw_init(vou_dev); + if (err < 0) { pm_runtime_put(vou_dev->v4l2_dev.dev); + v4l2_fh_release(file); + } else { vou_dev->status = SH_VOU_IDLE; - v4l2_fh_del(&vou_file->fh); - v4l2_fh_exit(&vou_file->fh); - mutex_unlock(&vou_dev->fop_lock); - kfree(vou_file); - return ret; } } - - videobuf_queue_dma_contig_init(&vou_file->vbq, &sh_vou_video_qops, - vou_dev->v4l2_dev.dev, &vou_dev->lock, - V4L2_BUF_TYPE_VIDEO_OUTPUT, - V4L2_FIELD_NONE, - sizeof(struct videobuf_buffer), - &vou_dev->vdev, &vou_dev->fop_lock); +done_open: mutex_unlock(&vou_dev->fop_lock); - - file->private_data = vou_file; - - return 0; + return err; } static int sh_vou_release(struct file *file) { struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = file->private_data; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + bool is_last; mutex_lock(&vou_dev->fop_lock); - if (v4l2_fh_is_singular(&vou_file->fh)) { + is_last = v4l2_fh_is_singular_file(file); + _vb2_fop_release(file, NULL); + if (is_last) { /* Last close */ - vou_dev->status = SH_VOU_IDLE; + vou_dev->status = SH_VOU_INITIALISING; sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101); pm_runtime_put(vou_dev->v4l2_dev.dev); } - v4l2_fh_del(&vou_file->fh); - v4l2_fh_exit(&vou_file->fh); mutex_unlock(&vou_dev->fop_lock); - - file->private_data = NULL; - kfree(vou_file); - return 0; } -static int sh_vou_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = file->private_data; - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - if (mutex_lock_interruptible(&vou_dev->fop_lock)) - return -ERESTARTSYS; - ret = videobuf_mmap_mapper(&vou_file->vbq, vma); - mutex_unlock(&vou_dev->fop_lock); - return ret; -} - -static unsigned int sh_vou_poll(struct file *file, poll_table *wait) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = file->private_data; - unsigned int res; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - mutex_lock(&vou_dev->fop_lock); - res = videobuf_poll_stream(file, &vou_file->vbq, wait); - mutex_unlock(&vou_dev->fop_lock); - return res; -} - /* sh_vou display ioctl operations */ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { .vidioc_querycap = sh_vou_querycap, @@ -1275,12 +1152,15 @@ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { .vidioc_g_fmt_vid_out = sh_vou_g_fmt_vid_out, .vidioc_s_fmt_vid_out = sh_vou_s_fmt_vid_out, .vidioc_try_fmt_vid_out = sh_vou_try_fmt_vid_out, - .vidioc_reqbufs = sh_vou_reqbufs, - .vidioc_querybuf = sh_vou_querybuf, - .vidioc_qbuf = sh_vou_qbuf, - .vidioc_dqbuf = sh_vou_dqbuf, - .vidioc_streamon = sh_vou_streamon, - .vidioc_streamoff = sh_vou_streamoff, + .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_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_expbuf = vb2_ioctl_expbuf, .vidioc_g_output = sh_vou_g_output, .vidioc_s_output = sh_vou_s_output, .vidioc_enum_output = sh_vou_enum_output, @@ -1295,8 +1175,9 @@ static const struct v4l2_file_operations sh_vou_fops = { .open = sh_vou_open, .release = sh_vou_release, .unlocked_ioctl = video_ioctl2, - .mmap = sh_vou_mmap, - .poll = sh_vou_poll, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, + .write = vb2_fop_write, }; static const struct video_device sh_vou_video_template = { @@ -1317,6 +1198,7 @@ static int sh_vou_probe(struct platform_device *pdev) struct sh_vou_device *vou_dev; struct resource *reg_res; struct v4l2_subdev *subdev; + struct vb2_queue *q; int irq, ret; reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1331,11 +1213,12 @@ static int sh_vou_probe(struct platform_device *pdev) if (!vou_dev) return -ENOMEM; - INIT_LIST_HEAD(&vou_dev->queue); + INIT_LIST_HEAD(&vou_dev->buf_list); spin_lock_init(&vou_dev->lock); mutex_init(&vou_dev->fop_lock); vou_dev->pdata = vou_pdata; - vou_dev->status = SH_VOU_IDLE; + vou_dev->status = SH_VOU_INITIALISING; + vou_dev->pix_idx = 1; rect = &vou_dev->rect; pix = &vou_dev->pix; @@ -1349,7 +1232,7 @@ static int sh_vou_probe(struct platform_device *pdev) pix->width = VOU_MAX_IMAGE_WIDTH; pix->height = 480; pix->pixelformat = V4L2_PIX_FMT_NV16; - pix->field = V4L2_FIELD_NONE; + pix->field = V4L2_FIELD_INTERLACED; pix->bytesperline = VOU_MAX_IMAGE_WIDTH; pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; @@ -1378,6 +1261,30 @@ static int sh_vou_probe(struct platform_device *pdev) video_set_drvdata(vdev, vou_dev); + /* Initialize the vb2 queue */ + q = &vou_dev->queue; + q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; + q->drv_priv = vou_dev; + q->buf_struct_size = sizeof(struct sh_vou_buffer); + q->ops = &sh_vou_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + q->lock = &vou_dev->fop_lock; + ret = vb2_queue_init(q); + if (ret) + goto einitctx; + + vou_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(vou_dev->alloc_ctx)) { + dev_err(&pdev->dev, "Can't allocate buffer context"); + ret = PTR_ERR(vou_dev->alloc_ctx); + goto einitctx; + } + vdev->queue = q; + INIT_LIST_HEAD(&vou_dev->buf_list); + pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); @@ -1409,6 +1316,8 @@ ei2cnd: ereset: i2c_put_adapter(i2c_adap); ei2cgadap: + vb2_dma_contig_cleanup_ctx(vou_dev->alloc_ctx); +einitctx: pm_runtime_disable(&pdev->dev); v4l2_device_unregister(&vou_dev->v4l2_dev); return ret; @@ -1426,6 +1335,7 @@ static int sh_vou_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); video_unregister_device(&vou_dev->vdev); i2c_put_adapter(client->adapter); + vb2_dma_contig_cleanup_ctx(vou_dev->alloc_ctx); v4l2_device_unregister(&vou_dev->v4l2_dev); return 0; } -- cgit v1.3-6-gb490 From 0b3474f0f61b21fc7f4d2a203cbcc2599a4d3aef Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Jun 2015 03:20:15 -0300 Subject: [media] sh-vou: add support for log_status Dump the VOU registers in log_status. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index da8ea6a76327..e2b2afa0a73d 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -875,6 +875,33 @@ static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } +static int sh_vou_log_status(struct file *file, void *priv) +{ + struct sh_vou_device *vou_dev = video_drvdata(file); + + pr_info("VOUER: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUER)); + pr_info("VOUCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUCR)); + pr_info("VOUSTR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSTR)); + pr_info("VOUVCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUVCR)); + pr_info("VOUISR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUISR)); + pr_info("VOUBCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUBCR)); + pr_info("VOUDPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDPR)); + pr_info("VOUDSR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDSR)); + pr_info("VOUVPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUVPR)); + pr_info("VOUIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUIR)); + pr_info("VOUSRR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSRR)); + pr_info("VOUMSR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUMSR)); + pr_info("VOUHIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUHIR)); + pr_info("VOUDFR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDFR)); + pr_info("VOUAD1R: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAD1R)); + pr_info("VOUAD2R: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAD2R)); + pr_info("VOUAIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAIR)); + pr_info("VOUSWR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSWR)); + pr_info("VOURCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOURCR)); + pr_info("VOURPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOURPR)); + return 0; +} + static int sh_vou_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) { @@ -1168,6 +1195,7 @@ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { .vidioc_g_std = sh_vou_g_std, .vidioc_g_selection = sh_vou_g_selection, .vidioc_s_selection = sh_vou_s_selection, + .vidioc_log_status = sh_vou_log_status, }; static const struct v4l2_file_operations sh_vou_fops = { -- cgit v1.3-6-gb490 From 4c34cc5e0f99ced4c7a11d49007bf7a90e2fae7a Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:11 -0300 Subject: [media] media/i2c/sr030pc30: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Acked-by: Sylwester Nawrocki Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/sr030pc30.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c index b62b6ddc4356..229dc76c44a5 100644 --- a/drivers/media/i2c/sr030pc30.c +++ b/drivers/media/i2c/sr030pc30.c @@ -636,13 +636,6 @@ static const struct v4l2_ctrl_ops sr030pc30_ctrl_ops = { static const struct v4l2_subdev_core_ops sr030pc30_core_ops = { .s_power = sr030pc30_s_power, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_pad_ops sr030pc30_pad_ops = { -- cgit v1.3-6-gb490 From 250121d348645675f5ade7e7ebe3fc6b46a9a2c0 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 3 Jun 2015 10:59:50 -0300 Subject: [media] media: adv7180: add of match table Add a proper of match id for use when the device is being bound via device tree, to avoid having to use the i2c old-style binding of the device. Signed-off-by: Ben Dooks Signed-off-by: William.Towle Reviewed-by: Rob Taylor Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index a493c0b0b5fe..09a96df170d1 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1324,11 +1325,21 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); #define ADV7180_PM_OPS NULL #endif +#ifdef CONFIG_OF +static const struct of_device_id adv7180_of_id[] = { + { .compatible = "adi,adv7180", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, adv7180_of_id); +#endif + static struct i2c_driver adv7180_driver = { .driver = { .owner = THIS_MODULE, .name = KBUILD_MODNAME, .pm = ADV7180_PM_OPS, + .of_match_table = of_match_ptr(adv7180_of_id), }, .probe = adv7180_probe, .remove = adv7180_remove, -- cgit v1.3-6-gb490 From f862f57dae5f0555552256b67f5bfd523f97a736 Mon Sep 17 00:00:00 2001 From: Pablo Anton Date: Fri, 19 Jun 2015 10:23:06 -0300 Subject: [media] media: i2c: ADV7604: Migrate to regmap This is a preliminary patch in order to add support for ALSA. It replaces all current i2c access with regmap. Signed-off-by: Pablo Anton Signed-off-by: Jean-Michel Hautbois Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 351 ++++++++++++++++++++++++++++++++------------ 1 file changed, 256 insertions(+), 95 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 60630d62e663..8e39bf60cb16 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -188,6 +189,9 @@ struct adv76xx_state { /* i2c clients */ struct i2c_client *i2c_clients[ADV76XX_PAGE_MAX]; + /* Regmaps */ + struct regmap *regmap[ADV76XX_PAGE_MAX]; + /* controls */ struct v4l2_ctrl *detect_tx_5v_ctrl; struct v4l2_ctrl *analog_sampling_phase_ctrl; @@ -373,66 +377,39 @@ static inline unsigned vtotal(const struct v4l2_bt_timings *t) /* ----------------------------------------------------------------------- */ -static s32 adv_smbus_read_byte_data_check(struct i2c_client *client, - u8 command, bool check) -{ - union i2c_smbus_data data; - - if (!i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_READ, command, - I2C_SMBUS_BYTE_DATA, &data)) - return data.byte; - if (check) - v4l_err(client, "error reading %02x, %02x\n", - client->addr, command); - return -EIO; -} - -static s32 adv_smbus_read_byte_data(struct adv76xx_state *state, - enum adv76xx_page page, u8 command) +static int adv76xx_read_check(struct adv76xx_state *state, + int client_page, u8 reg) { - return adv_smbus_read_byte_data_check(state->i2c_clients[page], - command, true); -} - -static s32 adv_smbus_write_byte_data(struct adv76xx_state *state, - enum adv76xx_page page, u8 command, - u8 value) -{ - struct i2c_client *client = state->i2c_clients[page]; - union i2c_smbus_data data; + struct i2c_client *client = state->i2c_clients[client_page]; int err; - int i; + unsigned int val; - data.byte = value; - for (i = 0; i < 3; i++) { - err = i2c_smbus_xfer(client->adapter, client->addr, - client->flags, - I2C_SMBUS_WRITE, command, - I2C_SMBUS_BYTE_DATA, &data); - if (!err) - break; + err = regmap_read(state->regmap[client_page], reg, &val); + + if (err) { + v4l_err(client, "error reading %02x, %02x\n", + client->addr, reg); + return err; } - if (err < 0) - v4l_err(client, "error writing %02x, %02x, %02x\n", - client->addr, command, value); - return err; + return val; } -static s32 adv_smbus_write_i2c_block_data(struct adv76xx_state *state, - enum adv76xx_page page, u8 command, - unsigned length, const u8 *values) +/* adv76xx_write_block(): Write raw data with a maximum of I2C_SMBUS_BLOCK_MAX + * size to one or more registers. + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +static int adv76xx_write_block(struct adv76xx_state *state, int client_page, + unsigned int init_reg, const void *val, + size_t val_len) { - struct i2c_client *client = state->i2c_clients[page]; - union i2c_smbus_data data; + struct regmap *regmap = state->regmap[client_page]; + + if (val_len > I2C_SMBUS_BLOCK_MAX) + val_len = I2C_SMBUS_BLOCK_MAX; - if (length > I2C_SMBUS_BLOCK_MAX) - length = I2C_SMBUS_BLOCK_MAX; - data.block[0] = length; - memcpy(data.block + 1, values, length); - return i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_WRITE, command, - I2C_SMBUS_I2C_BLOCK_DATA, &data); + return regmap_raw_write(regmap, init_reg, val, val_len); } /* ----------------------------------------------------------------------- */ @@ -441,14 +418,14 @@ static inline int io_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_IO, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_IO, reg); } static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_IO, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_IO], reg, val); } static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -460,71 +437,70 @@ static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_AVLINK, reg); + return adv76xx_read_check(state, ADV7604_PAGE_AVLINK, reg); } static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_AVLINK, reg, val); + return regmap_write(state->regmap[ADV7604_PAGE_AVLINK], reg, val); } static inline int cec_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CEC, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_CEC, reg); } static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CEC, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_CEC], reg, val); } static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_INFOFRAME, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_INFOFRAME, reg); } static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_INFOFRAME, - reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_INFOFRAME], reg, val); } static inline int afe_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_AFE, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_AFE, reg); } static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_AFE, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_AFE], reg, val); } static inline int rep_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_REP, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_REP, reg); } static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_REP, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_REP], reg, val); } static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -536,28 +512,37 @@ static inline int edid_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_EDID, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_EDID, reg); } static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_EDID, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_EDID], reg, val); } static inline int edid_write_block(struct v4l2_subdev *sd, - unsigned len, const u8 *val) + unsigned int total_len, const u8 *val) { struct adv76xx_state *state = to_state(sd); int err = 0; - int i; + int i = 0; + int len = 0; - v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); + v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", + __func__, total_len); + + while (!err && i < total_len) { + len = (total_len - i) > I2C_SMBUS_BLOCK_MAX ? + I2C_SMBUS_BLOCK_MAX : + (total_len - i); + + err = adv76xx_write_block(state, ADV76XX_PAGE_EDID, + i, val + i, len); + i += len; + } - for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) - err = adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_EDID, - i, I2C_SMBUS_BLOCK_MAX, val + i); return err; } @@ -587,7 +572,7 @@ static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_HDMI, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_HDMI, reg); } static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) @@ -599,7 +584,7 @@ static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_HDMI, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_HDMI], reg, val); } static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -611,14 +596,14 @@ static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_TEST, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_TEST], reg, val); } static inline int cp_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CP, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_CP, reg); } static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) @@ -630,7 +615,7 @@ static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CP, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_CP], reg, val); } static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -642,14 +627,14 @@ static inline int vdp_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_VDP, reg); + return adv76xx_read_check(state, ADV7604_PAGE_VDP, reg); } static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_VDP, reg, val); + return regmap_write(state->regmap[ADV7604_PAGE_VDP], reg, val); } #define ADV76XX_REG(page, offset) (((page) << 8) | (offset)) @@ -660,13 +645,16 @@ static int adv76xx_read_reg(struct v4l2_subdev *sd, unsigned int reg) { struct adv76xx_state *state = to_state(sd); unsigned int page = reg >> 8; + unsigned int val; + int err; if (!(BIT(page) & state->info->page_mask)) return -EINVAL; reg &= 0xff; + err = regmap_read(state->regmap[page], reg, &val); - return adv_smbus_read_byte_data(state, page, reg); + return err ? err : val; } #endif @@ -680,7 +668,7 @@ static int adv76xx_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) reg &= 0xff; - return adv_smbus_write_byte_data(state, page, reg, val); + return regmap_write(state->regmap[page], reg, val); } static void adv76xx_write_reg_seq(struct v4l2_subdev *sd, @@ -976,8 +964,8 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ /* IO-map reg. 0x16 and 0x17 should be written in sequence */ - if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_IO, - 0x16, 2, pll)) + if (regmap_raw_write(state->regmap[ADV76XX_PAGE_IO], + 0x16, pll, 2)) v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); /* active video - horizontal timing */ @@ -1028,8 +1016,8 @@ static void adv76xx_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 off 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, ADV76XX_PAGE_CP, - 0x77, 4, offset_buf)) + if (regmap_raw_write(state->regmap[ADV76XX_PAGE_CP], + 0x77, offset_buf, 4)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); } @@ -1058,8 +1046,8 @@ static void adv76xx_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, 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, ADV76XX_PAGE_CP, - 0x73, 4, gain_buf)) + if (regmap_raw_write(state->regmap[ADV76XX_PAGE_CP], + 0x73, gain_buf, 4)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); } @@ -2762,6 +2750,148 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) return 0; } +static const struct regmap_config adv76xx_regmap_cnf[] = { + { + .name = "io", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "avlink", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "cec", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "infoframe", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "esdp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "epp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "afe", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "rep", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "edid", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + + { + .name = "hdmi", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "test", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "cp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "vdp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, +}; + +static int configure_regmap(struct adv76xx_state *state, int region) +{ + int err; + + if (!state->i2c_clients[region]) + return -ENODEV; + + state->regmap[region] = + devm_regmap_init_i2c(state->i2c_clients[region], + &adv76xx_regmap_cnf[region]); + + if (IS_ERR(state->regmap[region])) { + err = PTR_ERR(state->regmap[region]); + v4l_err(state->i2c_clients[region], + "Error initializing regmap %d with error %d\n", + region, err); + return -EINVAL; + } + + return 0; +} + +static int configure_regmaps(struct adv76xx_state *state) +{ + int i, err; + + for (i = ADV7604_PAGE_AVLINK ; i < ADV76XX_PAGE_MAX; i++) { + err = configure_regmap(state, i); + if (err && (err != -ENODEV)) + return err; + } + return 0; +} + static int adv76xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -2771,7 +2901,7 @@ static int adv76xx_probe(struct i2c_client *client, struct v4l2_ctrl_handler *hdl; struct v4l2_subdev *sd; unsigned int i; - u16 val; + unsigned int val, val2; int err; /* Check if the adapter supports the needed features */ @@ -2835,23 +2965,49 @@ static int adv76xx_probe(struct i2c_client *client, client->addr); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + /* Configure IO Regmap region */ + err = configure_regmap(state, ADV76XX_PAGE_IO); + + if (err) { + v4l2_err(sd, "Error configuring IO regmap region\n"); + return -ENODEV; + } + /* * Verify that the chip is present. On ADV7604 the RD_INFO register only * identifies the revision, while on ADV7611 it identifies the model as * well. Use the HDMI slave address on ADV7604 and RD_INFO on ADV7611. */ if (state->info->type == ADV7604) { - val = adv_smbus_read_byte_data_check(client, 0xfb, false); + err = regmap_read(state->regmap[ADV76XX_PAGE_IO], 0xfb, &val); + if (err) { + v4l2_err(sd, "Error %d reading IO Regmap\n", err); + return -ENODEV; + } if (val != 0x68) { - v4l2_info(sd, "not an adv7604 on address 0x%x\n", + v4l2_err(sd, "not an adv7604 on address 0x%x\n", client->addr << 1); return -ENODEV; } } else { - val = (adv_smbus_read_byte_data_check(client, 0xea, false) << 8) - | (adv_smbus_read_byte_data_check(client, 0xeb, false) << 0); - if (val != 0x2051) { - v4l2_info(sd, "not an adv7611 on address 0x%x\n", + err = regmap_read(state->regmap[ADV76XX_PAGE_IO], + 0xea, + &val); + if (err) { + v4l2_err(sd, "Error %d reading IO Regmap\n", err); + return -ENODEV; + } + val2 = val << 8; + err = regmap_read(state->regmap[ADV76XX_PAGE_IO], + 0xeb, + &val); + if (err) { + v4l2_err(sd, "Error %d reading IO Regmap\n", err); + return -ENODEV; + } + val2 |= val; + if (val2 != 0x2051) { + v4l2_err(sd, "not an adv7611 on address 0x%x\n", client->addr << 1); return -ENODEV; } @@ -2941,6 +3097,11 @@ static int adv76xx_probe(struct i2c_client *client, if (err) goto err_work_queues; + /* Configure regmaps */ + err = configure_regmaps(state); + if (err) + goto err_entity; + err = adv76xx_core_init(sd); if (err) goto err_entity; -- cgit v1.3-6-gb490 From 8331d30bf0ccf179c3d03d968c9ae1c8f06eafc4 Mon Sep 17 00:00:00 2001 From: William Towle Date: Wed, 3 Jun 2015 10:59:51 -0300 Subject: [media] media: adv7604: chip info and formats for ADV7612 Add support for the ADV7612 chip as implemented on Renesas' Lager board to adv7604.c, including lists for formats/colourspace/timing selection and an IRQ handler. Signed-off-by: William Towle Signed-off-by: Hans Verkuil [hans.verkuil@cisco.com: fix merge conflicts due to regmap patch] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 91 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 8e39bf60cb16..c8fefeab0513 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); enum adv76xx_type { ADV7604, ADV7611, + ADV7612, }; struct adv76xx_reg_seq { @@ -754,6 +755,23 @@ static const struct adv76xx_format_info adv7611_formats[] = { ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, }; +static const struct adv76xx_format_info adv7612_formats[] = { + { MEDIA_BUS_FMT_RGB888_1X24, ADV76XX_OP_CH_SEL_RGB, true, false, + ADV76XX_OP_MODE_SEL_SDR_444 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_2X8, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_2X8, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_UYVY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_VYUY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_1X16, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_1X16, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, +}; + static const struct adv76xx_format_info * adv76xx_format_info(struct adv76xx_state *state, u32 code) { @@ -2498,6 +2516,11 @@ static void adv7611_setup_irqs(struct v4l2_subdev *sd) io_write(sd, 0x41, 0xd0); /* STDI irq for any change, disable INT2 */ } +static void adv7612_setup_irqs(struct v4l2_subdev *sd) +{ + io_write(sd, 0x41, 0xd0); /* disable INT2 */ +} + static void adv76xx_unregister_clients(struct adv76xx_state *state) { unsigned int i; @@ -2585,6 +2608,19 @@ static const struct adv76xx_reg_seq adv7611_recommended_settings_hdmi[] = { { ADV76XX_REG_SEQ_TERM, 0 }, }; +static const struct adv76xx_reg_seq adv7612_recommended_settings_hdmi[] = { + { ADV76XX_REG(ADV76XX_PAGE_CP, 0x6c), 0x00 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x9b), 0x03 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x6f), 0x08 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x85), 0x1f }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x87), 0x70 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0xda }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x01 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x03), 0x98 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4c), 0x44 }, + { ADV76XX_REG_SEQ_TERM, 0 }, +}; + static const struct adv76xx_chip_info adv76xx_chip_info[] = { [ADV7604] = { .type = ADV7604, @@ -2673,17 +2709,59 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = { .field1_vsync_mask = 0x3fff, .field1_vbackporch_mask = 0x3fff, }, + [ADV7612] = { + .type = ADV7612, + .has_afe = false, + .max_port = ADV7604_PAD_HDMI_PORT_B, + .num_dv_ports = 2, + .edid_enable_reg = 0x74, + .edid_status_reg = 0x76, + .lcf_reg = 0xa3, + .tdms_lock_mask = 0x43, + .cable_det_mask = 0x01, + .fmt_change_digital_mask = 0x03, + .formats = adv7612_formats, + .nformats = ARRAY_SIZE(adv7612_formats), + .set_termination = adv7611_set_termination, + .setup_irqs = adv7612_setup_irqs, + .read_hdmi_pixelclock = adv7611_read_hdmi_pixelclock, + .read_cable_det = adv7611_read_cable_det, + .recommended_settings = { + [1] = adv7612_recommended_settings_hdmi, + }, + .num_recommended_settings = { + [1] = ARRAY_SIZE(adv7612_recommended_settings_hdmi), + }, + .page_mask = BIT(ADV76XX_PAGE_IO) | BIT(ADV76XX_PAGE_CEC) | + BIT(ADV76XX_PAGE_INFOFRAME) | BIT(ADV76XX_PAGE_AFE) | + BIT(ADV76XX_PAGE_REP) | BIT(ADV76XX_PAGE_EDID) | + BIT(ADV76XX_PAGE_HDMI) | BIT(ADV76XX_PAGE_CP), + .linewidth_mask = 0x1fff, + .field0_height_mask = 0x1fff, + .field1_height_mask = 0x1fff, + .hfrontporch_mask = 0x1fff, + .hsync_mask = 0x1fff, + .hbackporch_mask = 0x1fff, + .field0_vfrontporch_mask = 0x3fff, + .field0_vsync_mask = 0x3fff, + .field0_vbackporch_mask = 0x3fff, + .field1_vfrontporch_mask = 0x3fff, + .field1_vsync_mask = 0x3fff, + .field1_vbackporch_mask = 0x3fff, + }, }; static const struct i2c_device_id adv76xx_i2c_id[] = { { "adv7604", (kernel_ulong_t)&adv76xx_chip_info[ADV7604] }, { "adv7611", (kernel_ulong_t)&adv76xx_chip_info[ADV7611] }, + { "adv7612", (kernel_ulong_t)&adv76xx_chip_info[ADV7612] }, { } }; MODULE_DEVICE_TABLE(i2c, adv76xx_i2c_id); static const struct of_device_id adv76xx_of_id[] __maybe_unused = { { .compatible = "adi,adv7611", .data = &adv76xx_chip_info[ADV7611] }, + { .compatible = "adi,adv7612", .data = &adv76xx_chip_info[ADV7612] }, { } }; MODULE_DEVICE_TABLE(of, adv76xx_of_id); @@ -2978,7 +3056,8 @@ static int adv76xx_probe(struct i2c_client *client, * identifies the revision, while on ADV7611 it identifies the model as * well. Use the HDMI slave address on ADV7604 and RD_INFO on ADV7611. */ - if (state->info->type == ADV7604) { + switch (state->info->type) { + case ADV7604: err = regmap_read(state->regmap[ADV76XX_PAGE_IO], 0xfb, &val); if (err) { v4l2_err(sd, "Error %d reading IO Regmap\n", err); @@ -2989,7 +3068,9 @@ static int adv76xx_probe(struct i2c_client *client, client->addr << 1); return -ENODEV; } - } else { + break; + case ADV7611: + case ADV7612: err = regmap_read(state->regmap[ADV76XX_PAGE_IO], 0xea, &val); @@ -3006,11 +3087,13 @@ static int adv76xx_probe(struct i2c_client *client, return -ENODEV; } val2 |= val; - if (val2 != 0x2051) { - v4l2_err(sd, "not an adv7611 on address 0x%x\n", + if ((state->info->type == ADV7611 && val != 0x2051) || + (state->info->type == ADV7612 && val != 0x2041)) { + v4l2_err(sd, "not an adv761x on address 0x%x\n", client->addr << 1); return -ENODEV; } + break; } /* control handlers */ -- cgit v1.3-6-gb490 From bf9c82278c348eb6b72496de6a3e5269aadb6b34 Mon Sep 17 00:00:00 2001 From: Ian Molton Date: Wed, 3 Jun 2015 10:59:53 -0300 Subject: [media] media: adv7604: ability to read default input port from DT Adds support to the adv7604 driver for specifying the default input port in the Device tree. If no value is provided, the driver will be unable to select an input without help from userspace. Tested-by: William Towle Signed-off-by: Ian Molton Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/adv7604.txt | 3 +++ drivers/media/i2c/adv7604.c | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.txt b/Documentation/devicetree/bindings/media/i2c/adv7604.txt index 7eafdbc055f9..8337f75c75da 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7604.txt +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.txt @@ -47,6 +47,7 @@ Optional Endpoint Properties: If none of hsync-active, vsync-active and pclk-sample is specified the endpoint will use embedded BT.656 synchronization. + - default-input: Select which input is selected after reset. Example: @@ -60,6 +61,8 @@ Example: #address-cells = <1>; #size-cells = <0>; + default-input = <0>; + port@0 { reg = <0>; }; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index c8fefeab0513..21b549a8dc74 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2772,6 +2772,7 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) struct device_node *endpoint; struct device_node *np; unsigned int flags; + u32 v; np = state->i2c_clients[ADV76XX_PAGE_IO]->dev.of_node; @@ -2781,6 +2782,12 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) return -EINVAL; v4l2_of_parse_endpoint(endpoint, &bus_cfg); + + if (!of_property_read_u32(endpoint, "default-input", &v)) + state->pdata.default_input = v; + else + state->pdata.default_input = -1; + of_node_put(endpoint); flags = bus_cfg.bus.parallel.flags; @@ -2819,7 +2826,6 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) /* Hardcode the remaining platform data fields. */ state->pdata.disable_pwrdnb = 0; state->pdata.disable_cable_det_rst = 0; - state->pdata.default_input = -1; state->pdata.blank_data = 1; state->pdata.alt_data_sat = 1; state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0; -- cgit v1.3-6-gb490 From 2a1e91a1595f4dec14ab16d63c6348d8fa159911 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 3 Jul 2015 09:12:54 -0300 Subject: [media] sh_vou: declare static functions as such drivers/media/platform/sh_vou.c:799:5: warning: no previous prototype for 'sh_vou_g_output' [-Wmissing-prototypes] int sh_vou_g_output(struct file *file, void *fh, unsigned int *i) ^ drivers/media/platform/sh_vou.c:805:5: warning: no previous prototype for 'sh_vou_s_output' [-Wmissing-prototypes] int sh_vou_s_output(struct file *file, void *fh, unsigned int i) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index e2b2afa0a73d..fe5c8ab06bd5 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -796,13 +796,13 @@ static int sh_vou_enum_output(struct file *file, void *fh, return 0; } -int sh_vou_g_output(struct file *file, void *fh, unsigned int *i) +static int sh_vou_g_output(struct file *file, void *fh, unsigned int *i) { *i = 0; return 0; } -int sh_vou_s_output(struct file *file, void *fh, unsigned int i) +static int sh_vou_s_output(struct file *file, void *fh, unsigned int i) { return i ? -EINVAL : 0; } -- cgit v1.3-6-gb490 From a66b0c41ad277ae62a3ae6ac430a71882f899557 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Tue, 19 May 2015 19:03:12 -0300 Subject: [media] rc-core: fix remove uevent generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The input_dev is already gone when the rc device is being unregistered so checking for its presence only means that no remove uevent will be generated. Cc: stable@kernel.org Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 9d015db65280..84d142bdb7a2 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1193,9 +1193,6 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct rc_dev *dev = to_rc_dev(device); - if (!dev || !dev->input_dev) - return -ENODEV; - if (dev->rc_map.name) ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); if (dev->driver_name) -- cgit v1.3-6-gb490 From fcb13097867757d360d5226d36ed3ffe849dc3ae Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Tue, 19 May 2015 19:03:17 -0300 Subject: [media] rc-core: use an IDA rather than a bitmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch changes rc-core to use the kernel facilities that are already available for handling unique numbers instead of rolling its own bitmap stuff. Signed-off-by: David Härdeman Tested-by: Stefan Lippers-Hollmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-ir-raw.c | 2 +- drivers/media/rc/rc-main.c | 40 ++++++++++++++++++++-------------------- include/media/rc-core.h | 4 ++-- 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index b9e4645c731c..1068f2ba56c6 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -406,7 +406,7 @@ int ir_raw_event_register(struct rc_dev *dev) spin_lock_init(&dev->raw->lock); dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, - "rc%ld", dev->devno); + "rc%u", dev->minor); if (IS_ERR(dev->raw->thread)) { rc = PTR_ERR(dev->raw->thread); diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 84d142bdb7a2..20914edd5a10 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -18,17 +18,15 @@ #include #include #include +#include #include #include #include "rc-core-priv.h" -/* Bitmap to store allocated device numbers from 0 to IRRCV_NUM_DEVICES - 1 */ -#define IRRCV_NUM_DEVICES 256 -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 #define IR_TAB_MAX_SIZE 8192 +#define RC_DEV_MAX 256 /* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */ #define IR_KEYPRESS_TIMEOUT 250 @@ -38,6 +36,9 @@ static LIST_HEAD(rc_map_list); static DEFINE_SPINLOCK(rc_map_lock); static struct led_trigger *led_feedback; +/* Used to keep track of rc devices */ +static DEFINE_IDA(rc_ida); + static struct rc_map_list *seek_rc_map(const char *name) { struct rc_map_list *map = NULL; @@ -1311,7 +1312,9 @@ int rc_register_device(struct rc_dev *dev) static bool raw_init = false; /* raw decoders loaded? */ struct rc_map *rc_map; const char *path; - int rc, devno, attr = 0; + int attr = 0; + int minor; + int rc; if (!dev || !dev->map_name) return -EINVAL; @@ -1331,13 +1334,13 @@ int rc_register_device(struct rc_dev *dev) if (dev->close) dev->input_dev->close = ir_close; - do { - devno = find_first_zero_bit(ir_core_dev_number, - IRRCV_NUM_DEVICES); - /* No free device slots */ - if (devno >= IRRCV_NUM_DEVICES) - return -ENOMEM; - } while (test_and_set_bit(devno, ir_core_dev_number)); + minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL); + if (minor < 0) + return minor; + + dev->minor = minor; + dev_set_name(&dev->dev, "rc%u", dev->minor); + dev_set_drvdata(&dev->dev, dev); dev->dev.groups = dev->sysfs_groups; dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp; @@ -1357,9 +1360,6 @@ int rc_register_device(struct rc_dev *dev) */ mutex_lock(&dev->lock); - dev->devno = devno; - dev_set_name(&dev->dev, "rc%ld", dev->devno); - dev_set_drvdata(&dev->dev, dev); rc = device_add(&dev->dev); if (rc) goto out_unlock; @@ -1435,8 +1435,8 @@ int rc_register_device(struct rc_dev *dev) mutex_unlock(&dev->lock); - IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n", - dev->devno, + IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n", + dev->minor, dev->driver_name ? dev->driver_name : "unknown", rc_map->name ? rc_map->name : "unknown", dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked"); @@ -1455,7 +1455,7 @@ out_dev: device_del(&dev->dev); out_unlock: mutex_unlock(&dev->lock); - clear_bit(dev->devno, ir_core_dev_number); + ida_simple_remove(&rc_ida, minor); return rc; } EXPORT_SYMBOL_GPL(rc_register_device); @@ -1467,8 +1467,6 @@ void rc_unregister_device(struct rc_dev *dev) del_timer_sync(&dev->timer_keyup); - clear_bit(dev->devno, ir_core_dev_number); - if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); @@ -1481,6 +1479,8 @@ void rc_unregister_device(struct rc_dev *dev) device_del(&dev->dev); + ida_simple_remove(&rc_ida, dev->minor); + rc_free_device(dev); } diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 45534da57759..5642fbea886e 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -69,7 +69,7 @@ enum rc_filter_type { * @rc_map: current scan/key table * @lock: used to ensure we've filled in all protocol details before * anyone can call show_protocols or store_protocols - * @devno: unique remote control device number + * @minor: unique minor remote control device number * @raw: additional data for raw pulse/space devices * @input_dev: the input child device used to communicate events to userspace * @driver_type: specifies if protocol decoding is done in hardware or software @@ -131,7 +131,7 @@ struct rc_dev { const char *map_name; struct rc_map rc_map; struct mutex lock; - unsigned long devno; + unsigned int minor; struct ir_raw_event_ctrl *raw; struct input_dev *input_dev; enum rc_driver_type driver_type; -- cgit v1.3-6-gb490 From 275ddb40bcf686d210d86c6718e42425a6a0bc76 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Tue, 19 May 2015 19:03:22 -0300 Subject: [media] rc-core: remove the LIRC "protocol" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LIRC protocol was always a bad fit and if we're ever going to expose protocol numbers in a user-space API, it'd be better to get rid of the LIRC "protocol" first. The sysfs API is kept backwards compatible by always listing the lirc protocol as present and enabled. Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 5 +---- drivers/media/rc/keymaps/rc-lirc.c | 2 +- drivers/media/rc/rc-main.c | 14 +++++++++----- include/media/rc-map.h | 38 ++++++++++++++++++-------------------- 4 files changed, 29 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 98893a8332c7..a32659fcd266 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -35,9 +35,6 @@ 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)) - return 0; - if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) return -EINVAL; @@ -424,7 +421,7 @@ static int ir_lirc_unregister(struct rc_dev *dev) } static struct ir_raw_handler lirc_handler = { - .protocols = RC_BIT_LIRC, + .protocols = 0, .decode = ir_lirc_decode, .raw_register = ir_lirc_register, .raw_unregister = ir_lirc_unregister, diff --git a/drivers/media/rc/keymaps/rc-lirc.c b/drivers/media/rc/keymaps/rc-lirc.c index fbf08fa6f46e..e172f5db5803 100644 --- a/drivers/media/rc/keymaps/rc-lirc.c +++ b/drivers/media/rc/keymaps/rc-lirc.c @@ -20,7 +20,7 @@ static struct rc_map_list lirc_map = { .map = { .scan = lirc, .size = ARRAY_SIZE(lirc), - .rc_type = RC_TYPE_LIRC, + .rc_type = RC_TYPE_OTHER, .name = RC_MAP_LIRC, } }; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 20914edd5a10..c80816561181 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -800,7 +800,6 @@ static struct { { RC_BIT_SANYO, "sanyo" }, { RC_BIT_SHARP, "sharp" }, { RC_BIT_MCE_KBD, "mce_kbd" }, - { RC_BIT_LIRC, "lirc" }, { RC_BIT_XMP, "xmp" }, }; @@ -885,6 +884,9 @@ static ssize_t show_protocols(struct device *device, allowed &= ~proto_names[i].type; } + if (dev->driver_type == RC_DRIVER_IR_RAW) + tmp += sprintf(tmp, "[lirc] "); + if (tmp != buf) tmp--; *tmp = '\n'; @@ -936,8 +938,12 @@ static int parse_protocol_change(u64 *protocols, const char *buf) } if (i == ARRAY_SIZE(proto_names)) { - IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); - return -EINVAL; + if (!strcasecmp(tmp, "lirc")) + mask = 0; + else { + IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); + return -EINVAL; + } } count++; @@ -1425,8 +1431,6 @@ int rc_register_device(struct rc_dev *dev) if (dev->change_protocol) { u64 rc_type = (1ll << rc_map->rc_type); - if (dev->driver_type == RC_DRIVER_IR_RAW) - rc_type |= RC_BIT_LIRC; rc = dev->change_protocol(dev, &rc_type); if (rc < 0) goto out_raw; diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 27763d5bd261..7c4bbc4dfab4 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -14,30 +14,28 @@ enum rc_type { RC_TYPE_UNKNOWN = 0, /* Protocol not known */ RC_TYPE_OTHER = 1, /* Protocol known but proprietary */ - RC_TYPE_LIRC = 2, /* Pass raw IR to lirc userspace */ - RC_TYPE_RC5 = 3, /* Philips RC5 protocol */ - RC_TYPE_RC5X = 4, /* Philips RC5x protocol */ - RC_TYPE_RC5_SZ = 5, /* StreamZap variant of RC5 */ - RC_TYPE_JVC = 6, /* JVC protocol */ - RC_TYPE_SONY12 = 7, /* Sony 12 bit protocol */ - RC_TYPE_SONY15 = 8, /* Sony 15 bit protocol */ - RC_TYPE_SONY20 = 9, /* Sony 20 bit protocol */ - RC_TYPE_NEC = 10, /* NEC protocol */ - RC_TYPE_SANYO = 11, /* Sanyo protocol */ - RC_TYPE_MCE_KBD = 12, /* RC6-ish MCE keyboard/mouse */ - RC_TYPE_RC6_0 = 13, /* Philips RC6-0-16 protocol */ - RC_TYPE_RC6_6A_20 = 14, /* Philips RC6-6A-20 protocol */ - 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 */ - RC_TYPE_XMP = 19, /* XMP protocol */ + RC_TYPE_RC5 = 2, /* Philips RC5 protocol */ + RC_TYPE_RC5X = 3, /* Philips RC5x protocol */ + RC_TYPE_RC5_SZ = 4, /* StreamZap variant of RC5 */ + RC_TYPE_JVC = 5, /* JVC protocol */ + RC_TYPE_SONY12 = 6, /* Sony 12 bit protocol */ + RC_TYPE_SONY15 = 7, /* Sony 15 bit protocol */ + RC_TYPE_SONY20 = 8, /* Sony 20 bit protocol */ + RC_TYPE_NEC = 9, /* NEC protocol */ + RC_TYPE_SANYO = 10, /* Sanyo protocol */ + RC_TYPE_MCE_KBD = 11, /* RC6-ish MCE keyboard/mouse */ + RC_TYPE_RC6_0 = 12, /* Philips RC6-0-16 protocol */ + RC_TYPE_RC6_6A_20 = 13, /* Philips RC6-6A-20 protocol */ + RC_TYPE_RC6_6A_24 = 14, /* Philips RC6-6A-24 protocol */ + RC_TYPE_RC6_6A_32 = 15, /* Philips RC6-6A-32 protocol */ + RC_TYPE_RC6_MCE = 16, /* MCE (Philips RC6-6A-32 subtype) protocol */ + RC_TYPE_SHARP = 17, /* Sharp protocol */ + RC_TYPE_XMP = 18, /* XMP protocol */ }; #define RC_BIT_NONE 0 #define RC_BIT_UNKNOWN (1 << RC_TYPE_UNKNOWN) #define RC_BIT_OTHER (1 << RC_TYPE_OTHER) -#define RC_BIT_LIRC (1 << RC_TYPE_LIRC) #define RC_BIT_RC5 (1 << RC_TYPE_RC5) #define RC_BIT_RC5X (1 << RC_TYPE_RC5X) #define RC_BIT_RC5_SZ (1 << RC_TYPE_RC5_SZ) @@ -56,7 +54,7 @@ enum rc_type { #define RC_BIT_SHARP (1 << RC_TYPE_SHARP) #define RC_BIT_XMP (1 << RC_TYPE_XMP) -#define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | RC_BIT_LIRC | \ +#define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | \ RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \ RC_BIT_JVC | \ RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \ -- cgit v1.3-6-gb490 From f459aec2bc81a46b674901424295f8ffe5e29ad0 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Tue, 19 May 2015 19:03:27 -0300 Subject: [media] lmedm04: NEC scancode cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes the keymap back to the state before commit 616a4b83 and changes the driver to use full NEC32 scancodes following the instructions provided by Malcolm Priestley . Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/rc-lme2510.c | 132 ++++++++++++++++----------------- drivers/media/usb/dvb-usb-v2/lmedm04.c | 21 +++--- 2 files changed, 77 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index 51f18bb50a37..2b0027c41332 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c @@ -15,74 +15,74 @@ static struct rc_map_table lme2510_rc[] = { /* Type 1 - 26 buttons */ - { 0x10ed45, KEY_0 }, - { 0x10ed5f, KEY_1 }, - { 0x10ed50, KEY_2 }, - { 0x10ed5d, KEY_3 }, - { 0x10ed41, KEY_4 }, - { 0x10ed0a, KEY_5 }, - { 0x10ed42, KEY_6 }, - { 0x10ed47, KEY_7 }, - { 0x10ed49, KEY_8 }, - { 0x10ed05, KEY_9 }, - { 0x10ed43, KEY_POWER }, - { 0x10ed46, KEY_SUBTITLE }, - { 0x10ed06, KEY_PAUSE }, - { 0x10ed03, KEY_MEDIA_REPEAT}, - { 0x10ed02, KEY_PAUSE }, - { 0x10ed5e, KEY_VOLUMEUP }, - { 0x10ed5c, KEY_VOLUMEDOWN }, - { 0x10ed09, KEY_CHANNELUP }, - { 0x10ed1a, KEY_CHANNELDOWN }, - { 0x10ed1e, KEY_PLAY }, - { 0x10ed1b, KEY_ZOOM }, - { 0x10ed59, KEY_MUTE }, - { 0x10ed5a, KEY_TV }, - { 0x10ed18, KEY_RECORD }, - { 0x10ed07, KEY_EPG }, - { 0x10ed01, KEY_STOP }, + { 0xef12ba45, KEY_0 }, + { 0xef12a05f, KEY_1 }, + { 0xef12af50, KEY_2 }, + { 0xef12a25d, KEY_3 }, + { 0xef12be41, KEY_4 }, + { 0xef12f50a, KEY_5 }, + { 0xef12bd42, KEY_6 }, + { 0xef12b847, KEY_7 }, + { 0xef12b649, KEY_8 }, + { 0xef12fa05, KEY_9 }, + { 0xef12bc43, KEY_POWER }, + { 0xef12b946, KEY_SUBTITLE }, + { 0xef12f906, KEY_PAUSE }, + { 0xef12fc03, KEY_MEDIA_REPEAT}, + { 0xef12fd02, KEY_PAUSE }, + { 0xef12a15e, KEY_VOLUMEUP }, + { 0xef12a35c, KEY_VOLUMEDOWN }, + { 0xef12f609, KEY_CHANNELUP }, + { 0xef12e51a, KEY_CHANNELDOWN }, + { 0xef12e11e, KEY_PLAY }, + { 0xef12e41b, KEY_ZOOM }, + { 0xef12a659, KEY_MUTE }, + { 0xef12a55a, KEY_TV }, + { 0xef12e718, KEY_RECORD }, + { 0xef12f807, KEY_EPG }, + { 0xef12fe01, KEY_STOP }, /* Type 2 - 20 buttons */ - { 0xbf15, KEY_0 }, - { 0xbf08, KEY_1 }, - { 0xbf09, KEY_2 }, - { 0xbf0a, KEY_3 }, - { 0xbf0c, KEY_4 }, - { 0xbf0d, KEY_5 }, - { 0xbf0e, KEY_6 }, - { 0xbf10, KEY_7 }, - { 0xbf11, KEY_8 }, - { 0xbf12, KEY_9 }, - { 0xbf00, KEY_POWER }, - { 0xbf04, KEY_MEDIA_REPEAT}, /* Recall */ - { 0xbf1a, KEY_PAUSE }, /* Timeshift */ - { 0xbf02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ - { 0xbf06, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ - { 0xbf01, KEY_CHANNELUP }, - { 0xbf05, KEY_CHANNELDOWN }, - { 0xbf14, KEY_ZOOM }, - { 0xbf18, KEY_RECORD }, - { 0xbf16, KEY_STOP }, + { 0xff40ea15, KEY_0 }, + { 0xff40f708, KEY_1 }, + { 0xff40f609, KEY_2 }, + { 0xff40f50a, KEY_3 }, + { 0xff40f30c, KEY_4 }, + { 0xff40f20d, KEY_5 }, + { 0xff40f10e, KEY_6 }, + { 0xff40ef10, KEY_7 }, + { 0xff40ee11, KEY_8 }, + { 0xff40ed12, KEY_9 }, + { 0xff40ff00, KEY_POWER }, + { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */ + { 0xff40e51a, KEY_PAUSE }, /* Timeshift */ + { 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ + { 0xff40f906, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ + { 0xff40fe01, KEY_CHANNELUP }, + { 0xff40fa05, KEY_CHANNELDOWN }, + { 0xff40eb14, KEY_ZOOM }, + { 0xff40e718, KEY_RECORD }, + { 0xff40e916, KEY_STOP }, /* Type 3 - 20 buttons */ - { 0x1c, KEY_0 }, - { 0x07, KEY_1 }, - { 0x15, KEY_2 }, - { 0x09, KEY_3 }, - { 0x16, KEY_4 }, - { 0x19, KEY_5 }, - { 0x0d, KEY_6 }, - { 0x0c, KEY_7 }, - { 0x18, KEY_8 }, - { 0x5e, KEY_9 }, - { 0x45, KEY_POWER }, - { 0x44, KEY_MEDIA_REPEAT}, /* Recall */ - { 0x4a, KEY_PAUSE }, /* Timeshift */ - { 0x47, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ - { 0x43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ - { 0x46, KEY_CHANNELUP }, - { 0x40, KEY_CHANNELDOWN }, - { 0x08, KEY_ZOOM }, - { 0x42, KEY_RECORD }, - { 0x5a, KEY_STOP }, + { 0xff00e31c, KEY_0 }, + { 0xff00f807, KEY_1 }, + { 0xff00ea15, KEY_2 }, + { 0xff00f609, KEY_3 }, + { 0xff00e916, KEY_4 }, + { 0xff00e619, KEY_5 }, + { 0xff00f20d, KEY_6 }, + { 0xff00f30c, KEY_7 }, + { 0xff00e718, KEY_8 }, + { 0xff00a15e, KEY_9 }, + { 0xff00ba45, KEY_POWER }, + { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */ + { 0xff00b54a, KEY_PAUSE }, /* Timeshift */ + { 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ + { 0xff00bc43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ + { 0xff00b946, KEY_CHANNELUP }, + { 0xff00bf40, KEY_CHANNELDOWN }, + { 0xff00f708, KEY_ZOOM }, + { 0xff00bd42, KEY_RECORD }, + { 0xff00a55a, KEY_STOP }, }; static struct rc_map_list lme2510_map = { diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 4cc55b3a0558..3721ee63b8fb 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -348,15 +348,16 @@ static void lme2510_int_response(struct urb *lme_urb) switch (ibuf[0]) { case 0xaa: debug_data_snipet(1, "INT Remote data snipet", ibuf); - if ((ibuf[4] + ibuf[5]) == 0xff) { - key = RC_SCANCODE_NECX((ibuf[2] ^ 0xff) << 8 | - (ibuf[3] > 0) ? (ibuf[3] ^ 0xff) : 0, - ibuf[5]); - deb_info(1, "INT Key =%08x", key); - if (adap_to_d(adap)->rc_dev != NULL) - rc_keydown(adap_to_d(adap)->rc_dev, - RC_TYPE_NEC, key, 0); - } + if (!adap_to_d(adap)->rc_dev) + break; + + key = RC_SCANCODE_NEC32(ibuf[2] << 24 | + ibuf[3] << 16 | + ibuf[4] << 8 | + ibuf[5]); + + deb_info(1, "INT Key = 0x%08x", key); + rc_keydown(adap_to_d(adap)->rc_dev, RC_TYPE_NEC, key, 0); break; case 0xbb: switch (st->tuner_config) { @@ -1344,7 +1345,7 @@ module_usb_driver(lme2510_driver); MODULE_AUTHOR("Malcolm Priestley "); MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_VERSION("2.06"); +MODULE_VERSION("2.07"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(LME2510_C_S7395); MODULE_FIRMWARE(LME2510_C_LG); -- cgit v1.3-6-gb490 From 8783b9c50400c6279d7c3b716637b98e83d3c933 Mon Sep 17 00:00:00 2001 From: Nibble Max Date: Mon, 29 Jun 2015 11:09:42 -0300 Subject: [media] SMI PCIe IR driver for DVBSky cards Ported from the manufacturer's source tree, available from http://dvbsky.net/download/linux/media_build-bst-150211.tar.gz This is the second patch after a public review. [mchehab@osg.samsung.com: fix inconsistent identing warning] Signed-off-by: Dirk Nehring Reviewd-by: Nibble Max Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/smipcie/Kconfig | 1 + drivers/media/pci/smipcie/Makefile | 3 + drivers/media/pci/smipcie/smipcie-ir.c | 232 +++++++ drivers/media/pci/smipcie/smipcie-main.c | 1114 ++++++++++++++++++++++++++++++ drivers/media/pci/smipcie/smipcie.c | 1102 ----------------------------- drivers/media/pci/smipcie/smipcie.h | 19 + 6 files changed, 1369 insertions(+), 1102 deletions(-) create mode 100644 drivers/media/pci/smipcie/smipcie-ir.c create mode 100644 drivers/media/pci/smipcie/smipcie-main.c delete mode 100644 drivers/media/pci/smipcie/smipcie.c (limited to 'drivers') diff --git a/drivers/media/pci/smipcie/Kconfig b/drivers/media/pci/smipcie/Kconfig index 21a1583dbd8f..c11c772830c9 100644 --- a/drivers/media/pci/smipcie/Kconfig +++ b/drivers/media/pci/smipcie/Kconfig @@ -7,6 +7,7 @@ config DVB_SMIPCIE select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT + depends on RC_CORE help Support for cards with SMI PCIe bridge: - DVBSky S950 V3 diff --git a/drivers/media/pci/smipcie/Makefile b/drivers/media/pci/smipcie/Makefile index be55481a6e95..013bc3fe4294 100644 --- a/drivers/media/pci/smipcie/Makefile +++ b/drivers/media/pci/smipcie/Makefile @@ -1,3 +1,6 @@ + +smipcie-objs := smipcie-main.o smipcie-ir.o + obj-$(CONFIG_DVB_SMIPCIE) += smipcie.o ccflags-y += -Idrivers/media/tuners diff --git a/drivers/media/pci/smipcie/smipcie-ir.c b/drivers/media/pci/smipcie/smipcie-ir.c new file mode 100644 index 000000000000..d018673c71f6 --- /dev/null +++ b/drivers/media/pci/smipcie/smipcie-ir.c @@ -0,0 +1,232 @@ +/* + * SMI PCIe driver for DVBSky cards. + * + * Copyright (C) 2014 Max nibble + * + * 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 "smipcie.h" + +static void smi_ir_enableInterrupt(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(MSI_INT_ENA_SET, IR_X_INT); +} + +static void smi_ir_disableInterrupt(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(MSI_INT_ENA_CLR, IR_X_INT); +} + +static void smi_ir_clearInterrupt(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(MSI_INT_STATUS_CLR, IR_X_INT); +} + +static void smi_ir_stop(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_ir_disableInterrupt(ir); + smi_clear(IR_Init_Reg, 0x80); +} + +#define BITS_PER_COMMAND 14 +#define GROUPS_PER_BIT 2 +#define IR_RC5_MIN_BIT 36 +#define IR_RC5_MAX_BIT 52 +static u32 smi_decode_rc5(u8 *pData, u8 size) +{ + u8 index, current_bit, bit_count; + u8 group_array[BITS_PER_COMMAND * GROUPS_PER_BIT + 4]; + u8 group_index = 0; + u32 command = 0xFFFFFFFF; + + group_array[group_index++] = 1; + + for (index = 0; index < size; index++) { + + current_bit = (pData[index] & 0x80) ? 1 : 0; + bit_count = pData[index] & 0x7f; + + if ((current_bit == 1) && (bit_count >= 2*IR_RC5_MAX_BIT + 1)) { + goto process_code; + } else if ((bit_count >= IR_RC5_MIN_BIT) && + (bit_count <= IR_RC5_MAX_BIT)) { + group_array[group_index++] = current_bit; + } else if ((bit_count > IR_RC5_MAX_BIT) && + (bit_count <= 2*IR_RC5_MAX_BIT)) { + group_array[group_index++] = current_bit; + group_array[group_index++] = current_bit; + } else { + goto invalid_timing; + } + if (group_index >= BITS_PER_COMMAND*GROUPS_PER_BIT) + goto process_code; + + if ((group_index == BITS_PER_COMMAND*GROUPS_PER_BIT - 1) + && (group_array[group_index-1] == 0)) { + group_array[group_index++] = 1; + goto process_code; + } + } + +process_code: + if (group_index == (BITS_PER_COMMAND*GROUPS_PER_BIT-1)) + group_array[group_index++] = 1; + + if (group_index == BITS_PER_COMMAND*GROUPS_PER_BIT) { + command = 0; + for (index = 0; index < (BITS_PER_COMMAND*GROUPS_PER_BIT); + index = index + 2) { + if ((group_array[index] == 1) && + (group_array[index+1] == 0)) { + command |= (1 << (BITS_PER_COMMAND - + (index/2) - 1)); + } else if ((group_array[index] == 0) && + (group_array[index+1] == 1)) { + /* */ + } else { + command = 0xFFFFFFFF; + goto invalid_timing; + } + } + } + +invalid_timing: + return command; +} + +static void smi_ir_decode(struct work_struct *work) +{ + struct smi_rc *ir = container_of(work, struct smi_rc, work); + struct smi_dev *dev = ir->dev; + struct rc_dev *rc_dev = ir->rc_dev; + u32 dwIRControl, dwIRData, dwIRCode, scancode; + u8 index, ucIRCount, readLoop, rc5_command, rc5_system, toggle; + + dwIRControl = smi_read(IR_Init_Reg); + if (dwIRControl & rbIRVld) { + ucIRCount = (u8) smi_read(IR_Data_Cnt); + + if (ucIRCount < 4) + goto end_ir_decode; + + readLoop = ucIRCount/4; + if (ucIRCount % 4) + readLoop += 1; + for (index = 0; index < readLoop; index++) { + dwIRData = smi_read(IR_DATA_BUFFER_BASE + (index*4)); + + ir->irData[index*4 + 0] = (u8)(dwIRData); + ir->irData[index*4 + 1] = (u8)(dwIRData >> 8); + ir->irData[index*4 + 2] = (u8)(dwIRData >> 16); + ir->irData[index*4 + 3] = (u8)(dwIRData >> 24); + } + dwIRCode = smi_decode_rc5(ir->irData, ucIRCount); + + if (dwIRCode != 0xFFFFFFFF) { + rc5_command = dwIRCode & 0x3F; + rc5_system = (dwIRCode & 0x7C0) >> 6; + toggle = (dwIRCode & 0x800) ? 1 : 0; + scancode = rc5_system << 8 | rc5_command; + rc_keydown(rc_dev, RC_TYPE_RC5, scancode, toggle); + } + } +end_ir_decode: + smi_set(IR_Init_Reg, 0x04); + smi_ir_enableInterrupt(ir); +} + +/* ir functions call by main driver.*/ +int smi_ir_irq(struct smi_rc *ir, u32 int_status) +{ + int handled = 0; + + if (int_status & IR_X_INT) { + smi_ir_disableInterrupt(ir); + smi_ir_clearInterrupt(ir); + schedule_work(&ir->work); + handled = 1; + } + return handled; +} + +void smi_ir_start(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(IR_Idle_Cnt_Low, 0x00140070); + msleep(20); + smi_set(IR_Init_Reg, 0x90); + + smi_ir_enableInterrupt(ir); +} + +int smi_ir_init(struct smi_dev *dev) +{ + int ret; + struct rc_dev *rc_dev; + struct smi_rc *ir = &dev->ir; + + rc_dev = rc_allocate_device(); + if (!rc_dev) + return -ENOMEM; + + /* init input device */ + snprintf(ir->input_name, sizeof(ir->input_name), "IR (%s)", + dev->info->name); + snprintf(ir->input_phys, sizeof(ir->input_phys), "pci-%s/ir0", + pci_name(dev->pci_dev)); + + rc_dev->driver_name = "SMI_PCIe"; + rc_dev->input_phys = ir->input_phys; + rc_dev->input_name = ir->input_name; + rc_dev->input_id.bustype = BUS_PCI; + rc_dev->input_id.version = 1; + rc_dev->input_id.vendor = dev->pci_dev->subsystem_vendor; + rc_dev->input_id.product = dev->pci_dev->subsystem_device; + rc_dev->dev.parent = &dev->pci_dev->dev; + + rc_dev->driver_type = RC_DRIVER_SCANCODE; + rc_dev->map_name = RC_MAP_DVBSKY; + + ir->rc_dev = rc_dev; + ir->dev = dev; + + INIT_WORK(&ir->work, smi_ir_decode); + smi_ir_disableInterrupt(ir); + + ret = rc_register_device(rc_dev); + if (ret) + goto ir_err; + + return 0; +ir_err: + rc_free_device(rc_dev); + return ret; +} + +void smi_ir_exit(struct smi_dev *dev) +{ + struct smi_rc *ir = &dev->ir; + struct rc_dev *rc_dev = ir->rc_dev; + + smi_ir_stop(ir); + rc_unregister_device(rc_dev); + ir->rc_dev = NULL; +} diff --git a/drivers/media/pci/smipcie/smipcie-main.c b/drivers/media/pci/smipcie/smipcie-main.c new file mode 100644 index 000000000000..b039a229b7d2 --- /dev/null +++ b/drivers/media/pci/smipcie/smipcie-main.c @@ -0,0 +1,1114 @@ +/* + * SMI PCIe driver for DVBSky cards. + * + * Copyright (C) 2014 Max nibble + * + * 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 "smipcie.h" +#include "m88ds3103.h" +#include "ts2020.h" +#include "m88rs6000t.h" +#include "si2168.h" +#include "si2157.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int smi_hw_init(struct smi_dev *dev) +{ + u32 port_mux, port_ctrl, int_stat; + + /* set port mux.*/ + port_mux = smi_read(MUX_MODE_CTRL); + port_mux &= ~(rbPaMSMask); + port_mux |= rbPaMSDtvNoGpio; + port_mux &= ~(rbPbMSMask); + port_mux |= rbPbMSDtvNoGpio; + port_mux &= ~(0x0f0000); + port_mux |= 0x50000; + smi_write(MUX_MODE_CTRL, port_mux); + + /* set DTV register.*/ + /* Port A */ + port_ctrl = smi_read(VIDEO_CTRL_STATUS_A); + port_ctrl &= ~0x01; + smi_write(VIDEO_CTRL_STATUS_A, port_ctrl); + port_ctrl = smi_read(MPEG2_CTRL_A); + port_ctrl &= ~0x40; + port_ctrl |= 0x80; + smi_write(MPEG2_CTRL_A, port_ctrl); + /* Port B */ + port_ctrl = smi_read(VIDEO_CTRL_STATUS_B); + port_ctrl &= ~0x01; + smi_write(VIDEO_CTRL_STATUS_B, port_ctrl); + port_ctrl = smi_read(MPEG2_CTRL_B); + port_ctrl &= ~0x40; + port_ctrl |= 0x80; + smi_write(MPEG2_CTRL_B, port_ctrl); + + /* disable and clear interrupt.*/ + smi_write(MSI_INT_ENA_CLR, ALL_INT); + int_stat = smi_read(MSI_INT_STATUS); + smi_write(MSI_INT_STATUS_CLR, int_stat); + + /* reset demod.*/ + smi_clear(PERIPHERAL_CTRL, 0x0303); + msleep(50); + smi_set(PERIPHERAL_CTRL, 0x0101); + return 0; +} + +/* i2c bit bus.*/ +static void smi_i2c_cfg(struct smi_dev *dev, u32 sw_ctl) +{ + u32 dwCtrl; + + dwCtrl = smi_read(sw_ctl); + dwCtrl &= ~0x18; /* disable output.*/ + dwCtrl |= 0x21; /* reset and software mode.*/ + dwCtrl &= ~0xff00; + dwCtrl |= 0x6400; + smi_write(sw_ctl, dwCtrl); + msleep(20); + dwCtrl = smi_read(sw_ctl); + dwCtrl &= ~0x20; + smi_write(sw_ctl, dwCtrl); +} + +static void smi_i2c_setsda(struct smi_dev *dev, int state, u32 sw_ctl) +{ + if (state) { + /* set as input.*/ + smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN); + } else { + smi_clear(sw_ctl, SW_I2C_MSK_DAT_OUT); + /* set as output.*/ + smi_set(sw_ctl, SW_I2C_MSK_DAT_EN); + } +} + +static void smi_i2c_setscl(void *data, int state, u32 sw_ctl) +{ + struct smi_dev *dev = data; + + if (state) { + /* set as input.*/ + smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN); + } else { + smi_clear(sw_ctl, SW_I2C_MSK_CLK_OUT); + /* set as output.*/ + smi_set(sw_ctl, SW_I2C_MSK_CLK_EN); + } +} + +static int smi_i2c_getsda(void *data, u32 sw_ctl) +{ + struct smi_dev *dev = data; + /* set as input.*/ + smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN); + udelay(1); + return (smi_read(sw_ctl) & SW_I2C_MSK_DAT_IN) ? 1 : 0; +} + +static int smi_i2c_getscl(void *data, u32 sw_ctl) +{ + struct smi_dev *dev = data; + /* set as input.*/ + smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN); + udelay(1); + return (smi_read(sw_ctl) & SW_I2C_MSK_CLK_IN) ? 1 : 0; +} +/* i2c 0.*/ +static void smi_i2c0_setsda(void *data, int state) +{ + struct smi_dev *dev = data; + + smi_i2c_setsda(dev, state, I2C_A_SW_CTL); +} + +static void smi_i2c0_setscl(void *data, int state) +{ + struct smi_dev *dev = data; + + smi_i2c_setscl(dev, state, I2C_A_SW_CTL); +} + +static int smi_i2c0_getsda(void *data) +{ + struct smi_dev *dev = data; + + return smi_i2c_getsda(dev, I2C_A_SW_CTL); +} + +static int smi_i2c0_getscl(void *data) +{ + struct smi_dev *dev = data; + + return smi_i2c_getscl(dev, I2C_A_SW_CTL); +} +/* i2c 1.*/ +static void smi_i2c1_setsda(void *data, int state) +{ + struct smi_dev *dev = data; + + smi_i2c_setsda(dev, state, I2C_B_SW_CTL); +} + +static void smi_i2c1_setscl(void *data, int state) +{ + struct smi_dev *dev = data; + + smi_i2c_setscl(dev, state, I2C_B_SW_CTL); +} + +static int smi_i2c1_getsda(void *data) +{ + struct smi_dev *dev = data; + + return smi_i2c_getsda(dev, I2C_B_SW_CTL); +} + +static int smi_i2c1_getscl(void *data) +{ + struct smi_dev *dev = data; + + return smi_i2c_getscl(dev, I2C_B_SW_CTL); +} + +static int smi_i2c_init(struct smi_dev *dev) +{ + int ret; + + /* i2c bus 0 */ + smi_i2c_cfg(dev, I2C_A_SW_CTL); + i2c_set_adapdata(&dev->i2c_bus[0], dev); + strcpy(dev->i2c_bus[0].name, "SMI-I2C0"); + dev->i2c_bus[0].owner = THIS_MODULE; + dev->i2c_bus[0].dev.parent = &dev->pci_dev->dev; + dev->i2c_bus[0].algo_data = &dev->i2c_bit[0]; + dev->i2c_bit[0].data = dev; + dev->i2c_bit[0].setsda = smi_i2c0_setsda; + dev->i2c_bit[0].setscl = smi_i2c0_setscl; + dev->i2c_bit[0].getsda = smi_i2c0_getsda; + dev->i2c_bit[0].getscl = smi_i2c0_getscl; + dev->i2c_bit[0].udelay = 12; + dev->i2c_bit[0].timeout = 10; + /* Raise SCL and SDA */ + smi_i2c0_setsda(dev, 1); + smi_i2c0_setscl(dev, 1); + + ret = i2c_bit_add_bus(&dev->i2c_bus[0]); + if (ret < 0) + return ret; + + /* i2c bus 1 */ + smi_i2c_cfg(dev, I2C_B_SW_CTL); + i2c_set_adapdata(&dev->i2c_bus[1], dev); + strcpy(dev->i2c_bus[1].name, "SMI-I2C1"); + dev->i2c_bus[1].owner = THIS_MODULE; + dev->i2c_bus[1].dev.parent = &dev->pci_dev->dev; + dev->i2c_bus[1].algo_data = &dev->i2c_bit[1]; + dev->i2c_bit[1].data = dev; + dev->i2c_bit[1].setsda = smi_i2c1_setsda; + dev->i2c_bit[1].setscl = smi_i2c1_setscl; + dev->i2c_bit[1].getsda = smi_i2c1_getsda; + dev->i2c_bit[1].getscl = smi_i2c1_getscl; + dev->i2c_bit[1].udelay = 12; + dev->i2c_bit[1].timeout = 10; + /* Raise SCL and SDA */ + smi_i2c1_setsda(dev, 1); + smi_i2c1_setscl(dev, 1); + + ret = i2c_bit_add_bus(&dev->i2c_bus[1]); + if (ret < 0) + i2c_del_adapter(&dev->i2c_bus[0]); + + return ret; +} + +static void smi_i2c_exit(struct smi_dev *dev) +{ + i2c_del_adapter(&dev->i2c_bus[0]); + i2c_del_adapter(&dev->i2c_bus[1]); +} + +static int smi_read_eeprom(struct i2c_adapter *i2c, u16 reg, u8 *data, u16 size) +{ + int ret; + u8 b0[2] = { (reg >> 8) & 0xff, reg & 0xff }; + + struct i2c_msg msg[] = { + { .addr = 0x50, .flags = 0, + .buf = b0, .len = 2 }, + { .addr = 0x50, .flags = I2C_M_RD, + .buf = data, .len = size } + }; + + ret = i2c_transfer(i2c, msg, 2); + + if (ret != 2) { + dev_err(&i2c->dev, "%s: reg=0x%x (error=%d)\n", + __func__, reg, ret); + return ret; + } + return ret; +} + +/* ts port interrupt operations */ +static void smi_port_disableInterrupt(struct smi_port *port) +{ + struct smi_dev *dev = port->dev; + + smi_write(MSI_INT_ENA_CLR, + (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); +} + +static void smi_port_enableInterrupt(struct smi_port *port) +{ + struct smi_dev *dev = port->dev; + + smi_write(MSI_INT_ENA_SET, + (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); +} + +static void smi_port_clearInterrupt(struct smi_port *port) +{ + struct smi_dev *dev = port->dev; + + smi_write(MSI_INT_STATUS_CLR, + (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); +} + +/* tasklet handler: DMA data to dmx.*/ +static void smi_dma_xfer(unsigned long data) +{ + struct smi_port *port = (struct smi_port *) data; + struct smi_dev *dev = port->dev; + u32 intr_status, finishedData, dmaManagement; + u8 dmaChan0State, dmaChan1State; + + intr_status = port->_int_status; + dmaManagement = smi_read(port->DMA_MANAGEMENT); + dmaChan0State = (u8)((dmaManagement & 0x00000030) >> 4); + dmaChan1State = (u8)((dmaManagement & 0x00300000) >> 20); + + /* CH-0 DMA interrupt.*/ + if ((intr_status & port->_dmaInterruptCH0) && (dmaChan0State == 0x01)) { + dev_dbg(&dev->pci_dev->dev, + "Port[%d]-DMA CH0 engine complete successful !\n", + port->idx); + finishedData = smi_read(port->DMA_CHAN0_TRANS_STATE); + finishedData &= 0x003FFFFF; + /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0] + * indicate dma total transfer length and + * zero of [21:0] indicate dma total transfer length + * equal to 0x400000 (4MB)*/ + if (finishedData == 0) + finishedData = 0x00400000; + if (finishedData != SMI_TS_DMA_BUF_SIZE) { + dev_dbg(&dev->pci_dev->dev, + "DMA CH0 engine complete length mismatched, finish data=%d !\n", + finishedData); + } + dvb_dmx_swfilter_packets(&port->demux, + port->cpu_addr[0], (finishedData / 188)); + /*dvb_dmx_swfilter(&port->demux, + port->cpu_addr[0], finishedData);*/ + } + /* CH-1 DMA interrupt.*/ + if ((intr_status & port->_dmaInterruptCH1) && (dmaChan1State == 0x01)) { + dev_dbg(&dev->pci_dev->dev, + "Port[%d]-DMA CH1 engine complete successful !\n", + port->idx); + finishedData = smi_read(port->DMA_CHAN1_TRANS_STATE); + finishedData &= 0x003FFFFF; + /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0] + * indicate dma total transfer length and + * zero of [21:0] indicate dma total transfer length + * equal to 0x400000 (4MB)*/ + if (finishedData == 0) + finishedData = 0x00400000; + if (finishedData != SMI_TS_DMA_BUF_SIZE) { + dev_dbg(&dev->pci_dev->dev, + "DMA CH1 engine complete length mismatched, finish data=%d !\n", + finishedData); + } + dvb_dmx_swfilter_packets(&port->demux, + port->cpu_addr[1], (finishedData / 188)); + /*dvb_dmx_swfilter(&port->demux, + port->cpu_addr[1], finishedData);*/ + } + /* restart DMA.*/ + if (intr_status & port->_dmaInterruptCH0) + dmaManagement |= 0x00000002; + if (intr_status & port->_dmaInterruptCH1) + dmaManagement |= 0x00020000; + smi_write(port->DMA_MANAGEMENT, dmaManagement); + /* Re-enable interrupts */ + smi_port_enableInterrupt(port); +} + +static void smi_port_dma_free(struct smi_port *port) +{ + if (port->cpu_addr[0]) { + pci_free_consistent(port->dev->pci_dev, SMI_TS_DMA_BUF_SIZE, + port->cpu_addr[0], port->dma_addr[0]); + port->cpu_addr[0] = NULL; + } + if (port->cpu_addr[1]) { + pci_free_consistent(port->dev->pci_dev, SMI_TS_DMA_BUF_SIZE, + port->cpu_addr[1], port->dma_addr[1]); + port->cpu_addr[1] = NULL; + } +} + +static int smi_port_init(struct smi_port *port, int dmaChanUsed) +{ + dev_dbg(&port->dev->pci_dev->dev, + "%s, port %d, dmaused %d\n", __func__, port->idx, dmaChanUsed); + port->enable = 0; + if (port->idx == 0) { + /* Port A */ + port->_dmaInterruptCH0 = dmaChanUsed & 0x01; + port->_dmaInterruptCH1 = dmaChanUsed & 0x02; + + port->DMA_CHAN0_ADDR_LOW = DMA_PORTA_CHAN0_ADDR_LOW; + port->DMA_CHAN0_ADDR_HI = DMA_PORTA_CHAN0_ADDR_HI; + port->DMA_CHAN0_TRANS_STATE = DMA_PORTA_CHAN0_TRANS_STATE; + port->DMA_CHAN0_CONTROL = DMA_PORTA_CHAN0_CONTROL; + port->DMA_CHAN1_ADDR_LOW = DMA_PORTA_CHAN1_ADDR_LOW; + port->DMA_CHAN1_ADDR_HI = DMA_PORTA_CHAN1_ADDR_HI; + port->DMA_CHAN1_TRANS_STATE = DMA_PORTA_CHAN1_TRANS_STATE; + port->DMA_CHAN1_CONTROL = DMA_PORTA_CHAN1_CONTROL; + port->DMA_MANAGEMENT = DMA_PORTA_MANAGEMENT; + } else { + /* Port B */ + port->_dmaInterruptCH0 = (dmaChanUsed << 2) & 0x04; + port->_dmaInterruptCH1 = (dmaChanUsed << 2) & 0x08; + + port->DMA_CHAN0_ADDR_LOW = DMA_PORTB_CHAN0_ADDR_LOW; + port->DMA_CHAN0_ADDR_HI = DMA_PORTB_CHAN0_ADDR_HI; + port->DMA_CHAN0_TRANS_STATE = DMA_PORTB_CHAN0_TRANS_STATE; + port->DMA_CHAN0_CONTROL = DMA_PORTB_CHAN0_CONTROL; + port->DMA_CHAN1_ADDR_LOW = DMA_PORTB_CHAN1_ADDR_LOW; + port->DMA_CHAN1_ADDR_HI = DMA_PORTB_CHAN1_ADDR_HI; + port->DMA_CHAN1_TRANS_STATE = DMA_PORTB_CHAN1_TRANS_STATE; + port->DMA_CHAN1_CONTROL = DMA_PORTB_CHAN1_CONTROL; + port->DMA_MANAGEMENT = DMA_PORTB_MANAGEMENT; + } + + if (port->_dmaInterruptCH0) { + port->cpu_addr[0] = pci_alloc_consistent(port->dev->pci_dev, + SMI_TS_DMA_BUF_SIZE, + &port->dma_addr[0]); + if (!port->cpu_addr[0]) { + dev_err(&port->dev->pci_dev->dev, + "Port[%d] DMA CH0 memory allocation failed!\n", + port->idx); + goto err; + } + } + + if (port->_dmaInterruptCH1) { + port->cpu_addr[1] = pci_alloc_consistent(port->dev->pci_dev, + SMI_TS_DMA_BUF_SIZE, + &port->dma_addr[1]); + if (!port->cpu_addr[1]) { + dev_err(&port->dev->pci_dev->dev, + "Port[%d] DMA CH1 memory allocation failed!\n", + port->idx); + goto err; + } + } + + smi_port_disableInterrupt(port); + tasklet_init(&port->tasklet, smi_dma_xfer, (unsigned long)port); + tasklet_disable(&port->tasklet); + port->enable = 1; + return 0; +err: + smi_port_dma_free(port); + return -ENOMEM; +} + +static void smi_port_exit(struct smi_port *port) +{ + smi_port_disableInterrupt(port); + tasklet_kill(&port->tasklet); + smi_port_dma_free(port); + port->enable = 0; +} + +static int smi_port_irq(struct smi_port *port, u32 int_status) +{ + u32 port_req_irq = port->_dmaInterruptCH0 | port->_dmaInterruptCH1; + int handled = 0; + + if (int_status & port_req_irq) { + smi_port_disableInterrupt(port); + port->_int_status = int_status; + smi_port_clearInterrupt(port); + tasklet_schedule(&port->tasklet); + handled = 1; + } + return handled; +} + +static irqreturn_t smi_irq_handler(int irq, void *dev_id) +{ + struct smi_dev *dev = dev_id; + struct smi_port *port0 = &dev->ts_port[0]; + struct smi_port *port1 = &dev->ts_port[1]; + struct smi_rc *ir = &dev->ir; + int handled = 0; + + u32 intr_status = smi_read(MSI_INT_STATUS); + + /* ts0 interrupt.*/ + if (dev->info->ts_0) + handled += smi_port_irq(port0, intr_status); + + /* ts1 interrupt.*/ + if (dev->info->ts_1) + handled += smi_port_irq(port1, intr_status); + + /* ir interrupt.*/ + handled += smi_ir_irq(ir, intr_status); + + return IRQ_RETVAL(handled); +} + +static struct i2c_client *smi_add_i2c_client(struct i2c_adapter *adapter, + struct i2c_board_info *info) +{ + struct i2c_client *client; + + request_module(info->type); + client = i2c_new_device(adapter, info); + if (client == NULL || client->dev.driver == NULL) + goto err_add_i2c_client; + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + goto err_add_i2c_client; + } + return client; + +err_add_i2c_client: + client = NULL; + return client; +} + +static void smi_del_i2c_client(struct i2c_client *client) +{ + module_put(client->dev.driver->owner); + i2c_unregister_device(client); +} + +static const struct m88ds3103_config smi_dvbsky_m88ds3103_cfg = { + .i2c_addr = 0x68, + .clock = 27000000, + .i2c_wr_max = 33, + .clock_out = 0, + .ts_mode = M88DS3103_TS_PARALLEL, + .ts_clk = 16000, + .ts_clk_pol = 1, + .agc = 0x99, + .lnb_hv_pol = 0, + .lnb_en_pol = 1, +}; + +static int smi_dvbsky_m88ds3103_fe_attach(struct smi_port *port) +{ + int ret = 0; + struct smi_dev *dev = port->dev; + struct i2c_adapter *i2c; + /* tuner I2C module */ + struct i2c_adapter *tuner_i2c_adapter; + struct i2c_client *tuner_client; + struct i2c_board_info tuner_info; + struct ts2020_config ts2020_config = {}; + memset(&tuner_info, 0, sizeof(struct i2c_board_info)); + i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; + + /* attach demod */ + port->fe = dvb_attach(m88ds3103_attach, + &smi_dvbsky_m88ds3103_cfg, i2c, &tuner_i2c_adapter); + if (!port->fe) { + ret = -ENODEV; + return ret; + } + /* attach tuner */ + ts2020_config.fe = port->fe; + strlcpy(tuner_info.type, "ts2020", I2C_NAME_SIZE); + tuner_info.addr = 0x60; + tuner_info.platform_data = &ts2020_config; + tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info); + if (!tuner_client) { + ret = -ENODEV; + goto err_tuner_i2c_device; + } + + /* delegate signal strength measurement to tuner */ + port->fe->ops.read_signal_strength = + port->fe->ops.tuner_ops.get_rf_strength; + + port->i2c_client_tuner = tuner_client; + return ret; + +err_tuner_i2c_device: + dvb_frontend_detach(port->fe); + return ret; +} + +static const struct m88ds3103_config smi_dvbsky_m88rs6000_cfg = { + .i2c_addr = 0x69, + .clock = 27000000, + .i2c_wr_max = 33, + .ts_mode = M88DS3103_TS_PARALLEL, + .ts_clk = 16000, + .ts_clk_pol = 1, + .agc = 0x99, + .lnb_hv_pol = 0, + .lnb_en_pol = 1, +}; + +static int smi_dvbsky_m88rs6000_fe_attach(struct smi_port *port) +{ + int ret = 0; + struct smi_dev *dev = port->dev; + struct i2c_adapter *i2c; + /* tuner I2C module */ + struct i2c_adapter *tuner_i2c_adapter; + struct i2c_client *tuner_client; + struct i2c_board_info tuner_info; + struct m88rs6000t_config m88rs6000t_config; + + memset(&tuner_info, 0, sizeof(struct i2c_board_info)); + i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; + + /* attach demod */ + port->fe = dvb_attach(m88ds3103_attach, + &smi_dvbsky_m88rs6000_cfg, i2c, &tuner_i2c_adapter); + if (!port->fe) { + ret = -ENODEV; + return ret; + } + /* attach tuner */ + m88rs6000t_config.fe = port->fe; + strlcpy(tuner_info.type, "m88rs6000t", I2C_NAME_SIZE); + tuner_info.addr = 0x21; + tuner_info.platform_data = &m88rs6000t_config; + tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info); + if (!tuner_client) { + ret = -ENODEV; + goto err_tuner_i2c_device; + } + + /* delegate signal strength measurement to tuner */ + port->fe->ops.read_signal_strength = + port->fe->ops.tuner_ops.get_rf_strength; + + port->i2c_client_tuner = tuner_client; + return ret; + +err_tuner_i2c_device: + dvb_frontend_detach(port->fe); + return ret; +} + +static int smi_dvbsky_sit2_fe_attach(struct smi_port *port) +{ + int ret = 0; + struct smi_dev *dev = port->dev; + struct i2c_adapter *i2c; + struct i2c_adapter *tuner_i2c_adapter; + struct i2c_client *client_tuner, *client_demod; + struct i2c_board_info client_info; + struct si2168_config si2168_config; + struct si2157_config si2157_config; + + /* select i2c bus */ + i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; + + /* attach demod */ + memset(&si2168_config, 0, sizeof(si2168_config)); + si2168_config.i2c_adapter = &tuner_i2c_adapter; + si2168_config.fe = &port->fe; + si2168_config.ts_mode = SI2168_TS_PARALLEL; + + memset(&client_info, 0, sizeof(struct i2c_board_info)); + strlcpy(client_info.type, "si2168", I2C_NAME_SIZE); + client_info.addr = 0x64; + client_info.platform_data = &si2168_config; + + client_demod = smi_add_i2c_client(i2c, &client_info); + if (!client_demod) { + ret = -ENODEV; + return ret; + } + port->i2c_client_demod = client_demod; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = port->fe; + si2157_config.if_port = 1; + + memset(&client_info, 0, sizeof(struct i2c_board_info)); + strlcpy(client_info.type, "si2157", I2C_NAME_SIZE); + client_info.addr = 0x60; + client_info.platform_data = &si2157_config; + + client_tuner = smi_add_i2c_client(tuner_i2c_adapter, &client_info); + if (!client_tuner) { + smi_del_i2c_client(port->i2c_client_demod); + port->i2c_client_demod = NULL; + ret = -ENODEV; + return ret; + } + port->i2c_client_tuner = client_tuner; + return ret; +} + +static int smi_fe_init(struct smi_port *port) +{ + int ret = 0; + struct smi_dev *dev = port->dev; + struct dvb_adapter *adap = &port->dvb_adapter; + u8 mac_ee[16]; + + dev_dbg(&port->dev->pci_dev->dev, + "%s: port %d, fe_type = %d\n", + __func__, port->idx, port->fe_type); + switch (port->fe_type) { + case DVBSKY_FE_M88DS3103: + ret = smi_dvbsky_m88ds3103_fe_attach(port); + break; + case DVBSKY_FE_M88RS6000: + ret = smi_dvbsky_m88rs6000_fe_attach(port); + break; + case DVBSKY_FE_SIT2: + ret = smi_dvbsky_sit2_fe_attach(port); + break; + } + if (ret < 0) + return ret; + + /* register dvb frontend */ + ret = dvb_register_frontend(adap, port->fe); + if (ret < 0) { + if (port->i2c_client_tuner) + smi_del_i2c_client(port->i2c_client_tuner); + if (port->i2c_client_demod) + smi_del_i2c_client(port->i2c_client_demod); + dvb_frontend_detach(port->fe); + return ret; + } + /* init MAC.*/ + ret = smi_read_eeprom(&dev->i2c_bus[0], 0xc0, mac_ee, 16); + dev_info(&port->dev->pci_dev->dev, + "DVBSky SMI PCIe MAC= %pM\n", mac_ee + (port->idx)*8); + memcpy(adap->proposed_mac, mac_ee + (port->idx)*8, 6); + return ret; +} + +static void smi_fe_exit(struct smi_port *port) +{ + dvb_unregister_frontend(port->fe); + /* remove I2C demod and tuner */ + if (port->i2c_client_tuner) + smi_del_i2c_client(port->i2c_client_tuner); + if (port->i2c_client_demod) + smi_del_i2c_client(port->i2c_client_demod); + dvb_frontend_detach(port->fe); +} + +static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, + int (*start_feed)(struct dvb_demux_feed *), + int (*stop_feed)(struct dvb_demux_feed *), + void *priv) +{ + dvbdemux->priv = priv; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = start_feed; + dvbdemux->stop_feed = stop_feed; + dvbdemux->write_to_decoder = NULL; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + return dvb_dmx_init(dvbdemux); +} + +static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, + struct dvb_demux *dvbdemux, + struct dmx_frontend *hw_frontend, + struct dmx_frontend *mem_frontend, + struct dvb_adapter *dvb_adapter) +{ + int ret; + + dmxdev->filternum = 256; + dmxdev->demux = &dvbdemux->dmx; + dmxdev->capabilities = 0; + ret = dvb_dmxdev_init(dmxdev, dvb_adapter); + if (ret < 0) + return ret; + + hw_frontend->source = DMX_FRONTEND_0; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); + mem_frontend->source = DMX_MEMORY_FE; + dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); + return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); +} + +static u32 smi_config_DMA(struct smi_port *port) +{ + struct smi_dev *dev = port->dev; + u32 totalLength = 0, dmaMemPtrLow, dmaMemPtrHi, dmaCtlReg; + u8 chanLatencyTimer = 0, dmaChanEnable = 1, dmaTransStart = 1; + u32 dmaManagement = 0, tlpTransUnit = DMA_TRANS_UNIT_188; + u8 tlpTc = 0, tlpTd = 1, tlpEp = 0, tlpAttr = 0; + u64 mem; + + dmaManagement = smi_read(port->DMA_MANAGEMENT); + /* Setup Channel-0 */ + if (port->_dmaInterruptCH0) { + totalLength = SMI_TS_DMA_BUF_SIZE; + mem = port->dma_addr[0]; + dmaMemPtrLow = mem & 0xffffffff; + dmaMemPtrHi = mem >> 32; + dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25) + | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30); + dmaManagement |= dmaChanEnable | (dmaTransStart << 1) + | (chanLatencyTimer << 8); + /* write DMA register, start DMA engine */ + smi_write(port->DMA_CHAN0_ADDR_LOW, dmaMemPtrLow); + smi_write(port->DMA_CHAN0_ADDR_HI, dmaMemPtrHi); + smi_write(port->DMA_CHAN0_CONTROL, dmaCtlReg); + } + /* Setup Channel-1 */ + if (port->_dmaInterruptCH1) { + totalLength = SMI_TS_DMA_BUF_SIZE; + mem = port->dma_addr[1]; + dmaMemPtrLow = mem & 0xffffffff; + dmaMemPtrHi = mem >> 32; + dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25) + | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30); + dmaManagement |= (dmaChanEnable << 16) | (dmaTransStart << 17) + | (chanLatencyTimer << 24); + /* write DMA register, start DMA engine */ + smi_write(port->DMA_CHAN1_ADDR_LOW, dmaMemPtrLow); + smi_write(port->DMA_CHAN1_ADDR_HI, dmaMemPtrHi); + smi_write(port->DMA_CHAN1_CONTROL, dmaCtlReg); + } + return dmaManagement; +} + +static int smi_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct smi_port *port = dvbdmx->priv; + struct smi_dev *dev = port->dev; + u32 dmaManagement; + + if (port->users++ == 0) { + dmaManagement = smi_config_DMA(port); + smi_port_clearInterrupt(port); + smi_port_enableInterrupt(port); + smi_write(port->DMA_MANAGEMENT, dmaManagement); + tasklet_enable(&port->tasklet); + } + return port->users; +} + +static int smi_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct smi_port *port = dvbdmx->priv; + struct smi_dev *dev = port->dev; + + if (--port->users) + return port->users; + + tasklet_disable(&port->tasklet); + smi_port_disableInterrupt(port); + smi_clear(port->DMA_MANAGEMENT, 0x30003); + return 0; +} + +static int smi_dvb_init(struct smi_port *port) +{ + int ret; + struct dvb_adapter *adap = &port->dvb_adapter; + struct dvb_demux *dvbdemux = &port->demux; + + dev_dbg(&port->dev->pci_dev->dev, + "%s, port %d\n", __func__, port->idx); + + ret = dvb_register_adapter(adap, "SMI_DVB", THIS_MODULE, + &port->dev->pci_dev->dev, + adapter_nr); + if (ret < 0) { + dev_err(&port->dev->pci_dev->dev, "Fail to register DVB adapter.\n"); + return ret; + } + ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", + smi_start_feed, + smi_stop_feed, port); + if (ret < 0) + goto err_del_dvb_register_adapter; + + ret = my_dvb_dmxdev_ts_card_init(&port->dmxdev, &port->demux, + &port->hw_frontend, + &port->mem_frontend, adap); + if (ret < 0) + goto err_del_dvb_dmx; + + ret = dvb_net_init(adap, &port->dvbnet, port->dmxdev.demux); + if (ret < 0) + goto err_del_dvb_dmxdev; + return 0; +err_del_dvb_dmxdev: + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend); + dvb_dmxdev_release(&port->dmxdev); +err_del_dvb_dmx: + dvb_dmx_release(&port->demux); +err_del_dvb_register_adapter: + dvb_unregister_adapter(&port->dvb_adapter); + return ret; +} + +static void smi_dvb_exit(struct smi_port *port) +{ + struct dvb_demux *dvbdemux = &port->demux; + + dvb_net_release(&port->dvbnet); + + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend); + dvb_dmxdev_release(&port->dmxdev); + dvb_dmx_release(&port->demux); + + dvb_unregister_adapter(&port->dvb_adapter); +} + +static int smi_port_attach(struct smi_dev *dev, + struct smi_port *port, int index) +{ + int ret, dmachs; + + port->dev = dev; + port->idx = index; + port->fe_type = (index == 0) ? dev->info->fe_0 : dev->info->fe_1; + dmachs = (index == 0) ? dev->info->ts_0 : dev->info->ts_1; + /* port init.*/ + ret = smi_port_init(port, dmachs); + if (ret < 0) + return ret; + /* dvb init.*/ + ret = smi_dvb_init(port); + if (ret < 0) + goto err_del_port_init; + /* fe init.*/ + ret = smi_fe_init(port); + if (ret < 0) + goto err_del_dvb_init; + return 0; +err_del_dvb_init: + smi_dvb_exit(port); +err_del_port_init: + smi_port_exit(port); + return ret; +} + +static void smi_port_detach(struct smi_port *port) +{ + smi_fe_exit(port); + smi_dvb_exit(port); + smi_port_exit(port); +} + +static int smi_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct smi_dev *dev; + int ret = -ENOMEM; + + if (pci_enable_device(pdev) < 0) + return -ENODEV; + + dev = kzalloc(sizeof(struct smi_dev), GFP_KERNEL); + if (!dev) { + ret = -ENOMEM; + goto err_pci_disable_device; + } + + dev->pci_dev = pdev; + pci_set_drvdata(pdev, dev); + dev->info = (struct smi_cfg_info *) id->driver_data; + dev_info(&dev->pci_dev->dev, + "card detected: %s\n", dev->info->name); + + dev->nr = dev->info->type; + dev->lmmio = ioremap(pci_resource_start(dev->pci_dev, 0), + pci_resource_len(dev->pci_dev, 0)); + if (!dev->lmmio) { + ret = -ENOMEM; + goto err_kfree; + } + + /* should we set to 32bit DMA? */ + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret < 0) + goto err_pci_iounmap; + + pci_set_master(pdev); + + ret = smi_hw_init(dev); + if (ret < 0) + goto err_pci_iounmap; + + ret = smi_i2c_init(dev); + if (ret < 0) + goto err_pci_iounmap; + + if (dev->info->ts_0) { + ret = smi_port_attach(dev, &dev->ts_port[0], 0); + if (ret < 0) + goto err_del_i2c_adaptor; + } + + if (dev->info->ts_1) { + ret = smi_port_attach(dev, &dev->ts_port[1], 1); + if (ret < 0) + goto err_del_port0_attach; + } + + ret = smi_ir_init(dev); + if (ret < 0) + goto err_del_port1_attach; + +#ifdef CONFIG_PCI_MSI /* to do msi interrupt.???*/ + if (pci_msi_enabled()) + ret = pci_enable_msi(dev->pci_dev); + if (ret) + dev_info(&dev->pci_dev->dev, "MSI not available.\n"); +#endif + + ret = request_irq(dev->pci_dev->irq, smi_irq_handler, + IRQF_SHARED, "SMI_PCIE", dev); + if (ret < 0) + goto err_del_ir; + + smi_ir_start(&dev->ir); + return 0; + +err_del_ir: + smi_ir_exit(dev); +err_del_port1_attach: + if (dev->info->ts_1) + smi_port_detach(&dev->ts_port[1]); +err_del_port0_attach: + if (dev->info->ts_0) + smi_port_detach(&dev->ts_port[0]); +err_del_i2c_adaptor: + smi_i2c_exit(dev); +err_pci_iounmap: + iounmap(dev->lmmio); +err_kfree: + pci_set_drvdata(pdev, NULL); + kfree(dev); +err_pci_disable_device: + pci_disable_device(pdev); + return ret; +} + +static void smi_remove(struct pci_dev *pdev) +{ + struct smi_dev *dev = pci_get_drvdata(pdev); + + smi_write(MSI_INT_ENA_CLR, ALL_INT); + free_irq(dev->pci_dev->irq, dev); +#ifdef CONFIG_PCI_MSI + pci_disable_msi(dev->pci_dev); +#endif + if (dev->info->ts_1) + smi_port_detach(&dev->ts_port[1]); + if (dev->info->ts_0) + smi_port_detach(&dev->ts_port[0]); + + smi_ir_exit(dev); + smi_i2c_exit(dev); + iounmap(dev->lmmio); + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); + kfree(dev); +} + +/* DVBSky cards */ +static struct smi_cfg_info dvbsky_s950_cfg = { + .type = SMI_DVBSKY_S950, + .name = "DVBSky S950 V3", + .ts_0 = SMI_TS_NULL, + .ts_1 = SMI_TS_DMA_BOTH, + .fe_0 = DVBSKY_FE_NULL, + .fe_1 = DVBSKY_FE_M88DS3103, +}; + +static struct smi_cfg_info dvbsky_s952_cfg = { + .type = SMI_DVBSKY_S952, + .name = "DVBSky S952 V3", + .ts_0 = SMI_TS_DMA_BOTH, + .ts_1 = SMI_TS_DMA_BOTH, + .fe_0 = DVBSKY_FE_M88RS6000, + .fe_1 = DVBSKY_FE_M88RS6000, +}; + +static struct smi_cfg_info dvbsky_t9580_cfg = { + .type = SMI_DVBSKY_T9580, + .name = "DVBSky T9580 V3", + .ts_0 = SMI_TS_DMA_BOTH, + .ts_1 = SMI_TS_DMA_BOTH, + .fe_0 = DVBSKY_FE_SIT2, + .fe_1 = DVBSKY_FE_M88DS3103, +}; + +/* PCI IDs */ +#define SMI_ID(_subvend, _subdev, _driverdata) { \ + .vendor = SMI_VID, .device = SMI_PID, \ + .subvendor = _subvend, .subdevice = _subdev, \ + .driver_data = (unsigned long)&_driverdata } + +static const struct pci_device_id smi_id_table[] = { + SMI_ID(0x4254, 0x0550, dvbsky_s950_cfg), + SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg), + SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg), + {0} +}; +MODULE_DEVICE_TABLE(pci, smi_id_table); + +static struct pci_driver smipcie_driver = { + .name = "SMI PCIe driver", + .id_table = smi_id_table, + .probe = smi_probe, + .remove = smi_remove, +}; + +module_pci_driver(smipcie_driver); + +MODULE_AUTHOR("Max nibble "); +MODULE_DESCRIPTION("SMI PCIe driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/smipcie/smipcie.c b/drivers/media/pci/smipcie/smipcie.c deleted file mode 100644 index 143fd7899ecd..000000000000 --- a/drivers/media/pci/smipcie/smipcie.c +++ /dev/null @@ -1,1102 +0,0 @@ -/* - * SMI PCIe driver for DVBSky cards. - * - * Copyright (C) 2014 Max nibble - * - * 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 "smipcie.h" -#include "m88ds3103.h" -#include "ts2020.h" -#include "m88rs6000t.h" -#include "si2168.h" -#include "si2157.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static int smi_hw_init(struct smi_dev *dev) -{ - u32 port_mux, port_ctrl, int_stat; - - /* set port mux.*/ - port_mux = smi_read(MUX_MODE_CTRL); - port_mux &= ~(rbPaMSMask); - port_mux |= rbPaMSDtvNoGpio; - port_mux &= ~(rbPbMSMask); - port_mux |= rbPbMSDtvNoGpio; - port_mux &= ~(0x0f0000); - port_mux |= 0x50000; - smi_write(MUX_MODE_CTRL, port_mux); - - /* set DTV register.*/ - /* Port A */ - port_ctrl = smi_read(VIDEO_CTRL_STATUS_A); - port_ctrl &= ~0x01; - smi_write(VIDEO_CTRL_STATUS_A, port_ctrl); - port_ctrl = smi_read(MPEG2_CTRL_A); - port_ctrl &= ~0x40; - port_ctrl |= 0x80; - smi_write(MPEG2_CTRL_A, port_ctrl); - /* Port B */ - port_ctrl = smi_read(VIDEO_CTRL_STATUS_B); - port_ctrl &= ~0x01; - smi_write(VIDEO_CTRL_STATUS_B, port_ctrl); - port_ctrl = smi_read(MPEG2_CTRL_B); - port_ctrl &= ~0x40; - port_ctrl |= 0x80; - smi_write(MPEG2_CTRL_B, port_ctrl); - - /* disable and clear interrupt.*/ - smi_write(MSI_INT_ENA_CLR, ALL_INT); - int_stat = smi_read(MSI_INT_STATUS); - smi_write(MSI_INT_STATUS_CLR, int_stat); - - /* reset demod.*/ - smi_clear(PERIPHERAL_CTRL, 0x0303); - msleep(50); - smi_set(PERIPHERAL_CTRL, 0x0101); - return 0; -} - -/* i2c bit bus.*/ -static void smi_i2c_cfg(struct smi_dev *dev, u32 sw_ctl) -{ - u32 dwCtrl; - - dwCtrl = smi_read(sw_ctl); - dwCtrl &= ~0x18; /* disable output.*/ - dwCtrl |= 0x21; /* reset and software mode.*/ - dwCtrl &= ~0xff00; - dwCtrl |= 0x6400; - smi_write(sw_ctl, dwCtrl); - msleep(20); - dwCtrl = smi_read(sw_ctl); - dwCtrl &= ~0x20; - smi_write(sw_ctl, dwCtrl); -} - -static void smi_i2c_setsda(struct smi_dev *dev, int state, u32 sw_ctl) -{ - if (state) { - /* set as input.*/ - smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN); - } else { - smi_clear(sw_ctl, SW_I2C_MSK_DAT_OUT); - /* set as output.*/ - smi_set(sw_ctl, SW_I2C_MSK_DAT_EN); - } -} - -static void smi_i2c_setscl(void *data, int state, u32 sw_ctl) -{ - struct smi_dev *dev = data; - - if (state) { - /* set as input.*/ - smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN); - } else { - smi_clear(sw_ctl, SW_I2C_MSK_CLK_OUT); - /* set as output.*/ - smi_set(sw_ctl, SW_I2C_MSK_CLK_EN); - } -} - -static int smi_i2c_getsda(void *data, u32 sw_ctl) -{ - struct smi_dev *dev = data; - /* set as input.*/ - smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN); - udelay(1); - return (smi_read(sw_ctl) & SW_I2C_MSK_DAT_IN) ? 1 : 0; -} - -static int smi_i2c_getscl(void *data, u32 sw_ctl) -{ - struct smi_dev *dev = data; - /* set as input.*/ - smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN); - udelay(1); - return (smi_read(sw_ctl) & SW_I2C_MSK_CLK_IN) ? 1 : 0; -} -/* i2c 0.*/ -static void smi_i2c0_setsda(void *data, int state) -{ - struct smi_dev *dev = data; - - smi_i2c_setsda(dev, state, I2C_A_SW_CTL); -} - -static void smi_i2c0_setscl(void *data, int state) -{ - struct smi_dev *dev = data; - - smi_i2c_setscl(dev, state, I2C_A_SW_CTL); -} - -static int smi_i2c0_getsda(void *data) -{ - struct smi_dev *dev = data; - - return smi_i2c_getsda(dev, I2C_A_SW_CTL); -} - -static int smi_i2c0_getscl(void *data) -{ - struct smi_dev *dev = data; - - return smi_i2c_getscl(dev, I2C_A_SW_CTL); -} -/* i2c 1.*/ -static void smi_i2c1_setsda(void *data, int state) -{ - struct smi_dev *dev = data; - - smi_i2c_setsda(dev, state, I2C_B_SW_CTL); -} - -static void smi_i2c1_setscl(void *data, int state) -{ - struct smi_dev *dev = data; - - smi_i2c_setscl(dev, state, I2C_B_SW_CTL); -} - -static int smi_i2c1_getsda(void *data) -{ - struct smi_dev *dev = data; - - return smi_i2c_getsda(dev, I2C_B_SW_CTL); -} - -static int smi_i2c1_getscl(void *data) -{ - struct smi_dev *dev = data; - - return smi_i2c_getscl(dev, I2C_B_SW_CTL); -} - -static int smi_i2c_init(struct smi_dev *dev) -{ - int ret; - - /* i2c bus 0 */ - smi_i2c_cfg(dev, I2C_A_SW_CTL); - i2c_set_adapdata(&dev->i2c_bus[0], dev); - strcpy(dev->i2c_bus[0].name, "SMI-I2C0"); - dev->i2c_bus[0].owner = THIS_MODULE; - dev->i2c_bus[0].dev.parent = &dev->pci_dev->dev; - dev->i2c_bus[0].algo_data = &dev->i2c_bit[0]; - dev->i2c_bit[0].data = dev; - dev->i2c_bit[0].setsda = smi_i2c0_setsda; - dev->i2c_bit[0].setscl = smi_i2c0_setscl; - dev->i2c_bit[0].getsda = smi_i2c0_getsda; - dev->i2c_bit[0].getscl = smi_i2c0_getscl; - dev->i2c_bit[0].udelay = 12; - dev->i2c_bit[0].timeout = 10; - /* Raise SCL and SDA */ - smi_i2c0_setsda(dev, 1); - smi_i2c0_setscl(dev, 1); - - ret = i2c_bit_add_bus(&dev->i2c_bus[0]); - if (ret < 0) - return ret; - - /* i2c bus 1 */ - smi_i2c_cfg(dev, I2C_B_SW_CTL); - i2c_set_adapdata(&dev->i2c_bus[1], dev); - strcpy(dev->i2c_bus[1].name, "SMI-I2C1"); - dev->i2c_bus[1].owner = THIS_MODULE; - dev->i2c_bus[1].dev.parent = &dev->pci_dev->dev; - dev->i2c_bus[1].algo_data = &dev->i2c_bit[1]; - dev->i2c_bit[1].data = dev; - dev->i2c_bit[1].setsda = smi_i2c1_setsda; - dev->i2c_bit[1].setscl = smi_i2c1_setscl; - dev->i2c_bit[1].getsda = smi_i2c1_getsda; - dev->i2c_bit[1].getscl = smi_i2c1_getscl; - dev->i2c_bit[1].udelay = 12; - dev->i2c_bit[1].timeout = 10; - /* Raise SCL and SDA */ - smi_i2c1_setsda(dev, 1); - smi_i2c1_setscl(dev, 1); - - ret = i2c_bit_add_bus(&dev->i2c_bus[1]); - if (ret < 0) - i2c_del_adapter(&dev->i2c_bus[0]); - - return ret; -} - -static void smi_i2c_exit(struct smi_dev *dev) -{ - i2c_del_adapter(&dev->i2c_bus[0]); - i2c_del_adapter(&dev->i2c_bus[1]); -} - -static int smi_read_eeprom(struct i2c_adapter *i2c, u16 reg, u8 *data, u16 size) -{ - int ret; - u8 b0[2] = { (reg >> 8) & 0xff, reg & 0xff }; - - struct i2c_msg msg[] = { - { .addr = 0x50, .flags = 0, - .buf = b0, .len = 2 }, - { .addr = 0x50, .flags = I2C_M_RD, - .buf = data, .len = size } - }; - - ret = i2c_transfer(i2c, msg, 2); - - if (ret != 2) { - dev_err(&i2c->dev, "%s: reg=0x%x (error=%d)\n", - __func__, reg, ret); - return ret; - } - return ret; -} - -/* ts port interrupt operations */ -static void smi_port_disableInterrupt(struct smi_port *port) -{ - struct smi_dev *dev = port->dev; - - smi_write(MSI_INT_ENA_CLR, - (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); -} - -static void smi_port_enableInterrupt(struct smi_port *port) -{ - struct smi_dev *dev = port->dev; - - smi_write(MSI_INT_ENA_SET, - (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); -} - -static void smi_port_clearInterrupt(struct smi_port *port) -{ - struct smi_dev *dev = port->dev; - - smi_write(MSI_INT_STATUS_CLR, - (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); -} - -/* tasklet handler: DMA data to dmx.*/ -static void smi_dma_xfer(unsigned long data) -{ - struct smi_port *port = (struct smi_port *) data; - struct smi_dev *dev = port->dev; - u32 intr_status, finishedData, dmaManagement; - u8 dmaChan0State, dmaChan1State; - - intr_status = port->_int_status; - dmaManagement = smi_read(port->DMA_MANAGEMENT); - dmaChan0State = (u8)((dmaManagement & 0x00000030) >> 4); - dmaChan1State = (u8)((dmaManagement & 0x00300000) >> 20); - - /* CH-0 DMA interrupt.*/ - if ((intr_status & port->_dmaInterruptCH0) && (dmaChan0State == 0x01)) { - dev_dbg(&dev->pci_dev->dev, - "Port[%d]-DMA CH0 engine complete successful !\n", - port->idx); - finishedData = smi_read(port->DMA_CHAN0_TRANS_STATE); - finishedData &= 0x003FFFFF; - /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0] - * indicate dma total transfer length and - * zero of [21:0] indicate dma total transfer length - * equal to 0x400000 (4MB)*/ - if (finishedData == 0) - finishedData = 0x00400000; - if (finishedData != SMI_TS_DMA_BUF_SIZE) { - dev_dbg(&dev->pci_dev->dev, - "DMA CH0 engine complete length mismatched, finish data=%d !\n", - finishedData); - } - dvb_dmx_swfilter_packets(&port->demux, - port->cpu_addr[0], (finishedData / 188)); - /*dvb_dmx_swfilter(&port->demux, - port->cpu_addr[0], finishedData);*/ - } - /* CH-1 DMA interrupt.*/ - if ((intr_status & port->_dmaInterruptCH1) && (dmaChan1State == 0x01)) { - dev_dbg(&dev->pci_dev->dev, - "Port[%d]-DMA CH1 engine complete successful !\n", - port->idx); - finishedData = smi_read(port->DMA_CHAN1_TRANS_STATE); - finishedData &= 0x003FFFFF; - /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0] - * indicate dma total transfer length and - * zero of [21:0] indicate dma total transfer length - * equal to 0x400000 (4MB)*/ - if (finishedData == 0) - finishedData = 0x00400000; - if (finishedData != SMI_TS_DMA_BUF_SIZE) { - dev_dbg(&dev->pci_dev->dev, - "DMA CH1 engine complete length mismatched, finish data=%d !\n", - finishedData); - } - dvb_dmx_swfilter_packets(&port->demux, - port->cpu_addr[1], (finishedData / 188)); - /*dvb_dmx_swfilter(&port->demux, - port->cpu_addr[1], finishedData);*/ - } - /* restart DMA.*/ - if (intr_status & port->_dmaInterruptCH0) - dmaManagement |= 0x00000002; - if (intr_status & port->_dmaInterruptCH1) - dmaManagement |= 0x00020000; - smi_write(port->DMA_MANAGEMENT, dmaManagement); - /* Re-enable interrupts */ - smi_port_enableInterrupt(port); -} - -static void smi_port_dma_free(struct smi_port *port) -{ - if (port->cpu_addr[0]) { - pci_free_consistent(port->dev->pci_dev, SMI_TS_DMA_BUF_SIZE, - port->cpu_addr[0], port->dma_addr[0]); - port->cpu_addr[0] = NULL; - } - if (port->cpu_addr[1]) { - pci_free_consistent(port->dev->pci_dev, SMI_TS_DMA_BUF_SIZE, - port->cpu_addr[1], port->dma_addr[1]); - port->cpu_addr[1] = NULL; - } -} - -static int smi_port_init(struct smi_port *port, int dmaChanUsed) -{ - dev_dbg(&port->dev->pci_dev->dev, - "%s, port %d, dmaused %d\n", __func__, port->idx, dmaChanUsed); - port->enable = 0; - if (port->idx == 0) { - /* Port A */ - port->_dmaInterruptCH0 = dmaChanUsed & 0x01; - port->_dmaInterruptCH1 = dmaChanUsed & 0x02; - - port->DMA_CHAN0_ADDR_LOW = DMA_PORTA_CHAN0_ADDR_LOW; - port->DMA_CHAN0_ADDR_HI = DMA_PORTA_CHAN0_ADDR_HI; - port->DMA_CHAN0_TRANS_STATE = DMA_PORTA_CHAN0_TRANS_STATE; - port->DMA_CHAN0_CONTROL = DMA_PORTA_CHAN0_CONTROL; - port->DMA_CHAN1_ADDR_LOW = DMA_PORTA_CHAN1_ADDR_LOW; - port->DMA_CHAN1_ADDR_HI = DMA_PORTA_CHAN1_ADDR_HI; - port->DMA_CHAN1_TRANS_STATE = DMA_PORTA_CHAN1_TRANS_STATE; - port->DMA_CHAN1_CONTROL = DMA_PORTA_CHAN1_CONTROL; - port->DMA_MANAGEMENT = DMA_PORTA_MANAGEMENT; - } else { - /* Port B */ - port->_dmaInterruptCH0 = (dmaChanUsed << 2) & 0x04; - port->_dmaInterruptCH1 = (dmaChanUsed << 2) & 0x08; - - port->DMA_CHAN0_ADDR_LOW = DMA_PORTB_CHAN0_ADDR_LOW; - port->DMA_CHAN0_ADDR_HI = DMA_PORTB_CHAN0_ADDR_HI; - port->DMA_CHAN0_TRANS_STATE = DMA_PORTB_CHAN0_TRANS_STATE; - port->DMA_CHAN0_CONTROL = DMA_PORTB_CHAN0_CONTROL; - port->DMA_CHAN1_ADDR_LOW = DMA_PORTB_CHAN1_ADDR_LOW; - port->DMA_CHAN1_ADDR_HI = DMA_PORTB_CHAN1_ADDR_HI; - port->DMA_CHAN1_TRANS_STATE = DMA_PORTB_CHAN1_TRANS_STATE; - port->DMA_CHAN1_CONTROL = DMA_PORTB_CHAN1_CONTROL; - port->DMA_MANAGEMENT = DMA_PORTB_MANAGEMENT; - } - - if (port->_dmaInterruptCH0) { - port->cpu_addr[0] = pci_alloc_consistent(port->dev->pci_dev, - SMI_TS_DMA_BUF_SIZE, - &port->dma_addr[0]); - if (!port->cpu_addr[0]) { - dev_err(&port->dev->pci_dev->dev, - "Port[%d] DMA CH0 memory allocation failed!\n", - port->idx); - goto err; - } - } - - if (port->_dmaInterruptCH1) { - port->cpu_addr[1] = pci_alloc_consistent(port->dev->pci_dev, - SMI_TS_DMA_BUF_SIZE, - &port->dma_addr[1]); - if (!port->cpu_addr[1]) { - dev_err(&port->dev->pci_dev->dev, - "Port[%d] DMA CH1 memory allocation failed!\n", - port->idx); - goto err; - } - } - - smi_port_disableInterrupt(port); - tasklet_init(&port->tasklet, smi_dma_xfer, (unsigned long)port); - tasklet_disable(&port->tasklet); - port->enable = 1; - return 0; -err: - smi_port_dma_free(port); - return -ENOMEM; -} - -static void smi_port_exit(struct smi_port *port) -{ - smi_port_disableInterrupt(port); - tasklet_kill(&port->tasklet); - smi_port_dma_free(port); - port->enable = 0; -} - -static int smi_port_irq(struct smi_port *port, u32 int_status) -{ - u32 port_req_irq = port->_dmaInterruptCH0 | port->_dmaInterruptCH1; - int handled = 0; - - if (int_status & port_req_irq) { - smi_port_disableInterrupt(port); - port->_int_status = int_status; - smi_port_clearInterrupt(port); - tasklet_schedule(&port->tasklet); - handled = 1; - } - return handled; -} - -static irqreturn_t smi_irq_handler(int irq, void *dev_id) -{ - struct smi_dev *dev = dev_id; - struct smi_port *port0 = &dev->ts_port[0]; - struct smi_port *port1 = &dev->ts_port[1]; - int handled = 0; - - u32 intr_status = smi_read(MSI_INT_STATUS); - - /* ts0 interrupt.*/ - if (dev->info->ts_0) - handled += smi_port_irq(port0, intr_status); - - /* ts1 interrupt.*/ - if (dev->info->ts_1) - handled += smi_port_irq(port1, intr_status); - - return IRQ_RETVAL(handled); -} - -static struct i2c_client *smi_add_i2c_client(struct i2c_adapter *adapter, - struct i2c_board_info *info) -{ - struct i2c_client *client; - - request_module(info->type); - client = i2c_new_device(adapter, info); - if (client == NULL || client->dev.driver == NULL) - goto err_add_i2c_client; - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - goto err_add_i2c_client; - } - return client; - -err_add_i2c_client: - client = NULL; - return client; -} - -static void smi_del_i2c_client(struct i2c_client *client) -{ - module_put(client->dev.driver->owner); - i2c_unregister_device(client); -} - -static const struct m88ds3103_config smi_dvbsky_m88ds3103_cfg = { - .i2c_addr = 0x68, - .clock = 27000000, - .i2c_wr_max = 33, - .clock_out = 0, - .ts_mode = M88DS3103_TS_PARALLEL, - .ts_clk = 16000, - .ts_clk_pol = 1, - .agc = 0x99, - .lnb_hv_pol = 0, - .lnb_en_pol = 1, -}; - -static int smi_dvbsky_m88ds3103_fe_attach(struct smi_port *port) -{ - int ret = 0; - struct smi_dev *dev = port->dev; - struct i2c_adapter *i2c; - /* tuner I2C module */ - struct i2c_adapter *tuner_i2c_adapter; - struct i2c_client *tuner_client; - struct i2c_board_info tuner_info; - struct ts2020_config ts2020_config = {}; - memset(&tuner_info, 0, sizeof(struct i2c_board_info)); - i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; - - /* attach demod */ - port->fe = dvb_attach(m88ds3103_attach, - &smi_dvbsky_m88ds3103_cfg, i2c, &tuner_i2c_adapter); - if (!port->fe) { - ret = -ENODEV; - return ret; - } - /* attach tuner */ - ts2020_config.fe = port->fe; - strlcpy(tuner_info.type, "ts2020", I2C_NAME_SIZE); - tuner_info.addr = 0x60; - tuner_info.platform_data = &ts2020_config; - tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info); - if (!tuner_client) { - ret = -ENODEV; - goto err_tuner_i2c_device; - } - - /* delegate signal strength measurement to tuner */ - port->fe->ops.read_signal_strength = - port->fe->ops.tuner_ops.get_rf_strength; - - port->i2c_client_tuner = tuner_client; - return ret; - -err_tuner_i2c_device: - dvb_frontend_detach(port->fe); - return ret; -} - -static const struct m88ds3103_config smi_dvbsky_m88rs6000_cfg = { - .i2c_addr = 0x69, - .clock = 27000000, - .i2c_wr_max = 33, - .ts_mode = M88DS3103_TS_PARALLEL, - .ts_clk = 16000, - .ts_clk_pol = 1, - .agc = 0x99, - .lnb_hv_pol = 0, - .lnb_en_pol = 1, -}; - -static int smi_dvbsky_m88rs6000_fe_attach(struct smi_port *port) -{ - int ret = 0; - struct smi_dev *dev = port->dev; - struct i2c_adapter *i2c; - /* tuner I2C module */ - struct i2c_adapter *tuner_i2c_adapter; - struct i2c_client *tuner_client; - struct i2c_board_info tuner_info; - struct m88rs6000t_config m88rs6000t_config; - - memset(&tuner_info, 0, sizeof(struct i2c_board_info)); - i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; - - /* attach demod */ - port->fe = dvb_attach(m88ds3103_attach, - &smi_dvbsky_m88rs6000_cfg, i2c, &tuner_i2c_adapter); - if (!port->fe) { - ret = -ENODEV; - return ret; - } - /* attach tuner */ - m88rs6000t_config.fe = port->fe; - strlcpy(tuner_info.type, "m88rs6000t", I2C_NAME_SIZE); - tuner_info.addr = 0x21; - tuner_info.platform_data = &m88rs6000t_config; - tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info); - if (!tuner_client) { - ret = -ENODEV; - goto err_tuner_i2c_device; - } - - /* delegate signal strength measurement to tuner */ - port->fe->ops.read_signal_strength = - port->fe->ops.tuner_ops.get_rf_strength; - - port->i2c_client_tuner = tuner_client; - return ret; - -err_tuner_i2c_device: - dvb_frontend_detach(port->fe); - return ret; -} - -static int smi_dvbsky_sit2_fe_attach(struct smi_port *port) -{ - int ret = 0; - struct smi_dev *dev = port->dev; - struct i2c_adapter *i2c; - struct i2c_adapter *tuner_i2c_adapter; - struct i2c_client *client_tuner, *client_demod; - struct i2c_board_info client_info; - struct si2168_config si2168_config; - struct si2157_config si2157_config; - - /* select i2c bus */ - i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; - - /* attach demod */ - memset(&si2168_config, 0, sizeof(si2168_config)); - si2168_config.i2c_adapter = &tuner_i2c_adapter; - si2168_config.fe = &port->fe; - si2168_config.ts_mode = SI2168_TS_PARALLEL; - - memset(&client_info, 0, sizeof(struct i2c_board_info)); - strlcpy(client_info.type, "si2168", I2C_NAME_SIZE); - client_info.addr = 0x64; - client_info.platform_data = &si2168_config; - - client_demod = smi_add_i2c_client(i2c, &client_info); - if (!client_demod) { - ret = -ENODEV; - return ret; - } - port->i2c_client_demod = client_demod; - - /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = port->fe; - si2157_config.if_port = 1; - - memset(&client_info, 0, sizeof(struct i2c_board_info)); - strlcpy(client_info.type, "si2157", I2C_NAME_SIZE); - client_info.addr = 0x60; - client_info.platform_data = &si2157_config; - - client_tuner = smi_add_i2c_client(tuner_i2c_adapter, &client_info); - if (!client_tuner) { - smi_del_i2c_client(port->i2c_client_demod); - port->i2c_client_demod = NULL; - ret = -ENODEV; - return ret; - } - port->i2c_client_tuner = client_tuner; - return ret; -} - -static int smi_fe_init(struct smi_port *port) -{ - int ret = 0; - struct smi_dev *dev = port->dev; - struct dvb_adapter *adap = &port->dvb_adapter; - u8 mac_ee[16]; - - dev_dbg(&port->dev->pci_dev->dev, - "%s: port %d, fe_type = %d\n", - __func__, port->idx, port->fe_type); - switch (port->fe_type) { - case DVBSKY_FE_M88DS3103: - ret = smi_dvbsky_m88ds3103_fe_attach(port); - break; - case DVBSKY_FE_M88RS6000: - ret = smi_dvbsky_m88rs6000_fe_attach(port); - break; - case DVBSKY_FE_SIT2: - ret = smi_dvbsky_sit2_fe_attach(port); - break; - } - if (ret < 0) - return ret; - - /* register dvb frontend */ - ret = dvb_register_frontend(adap, port->fe); - if (ret < 0) { - if (port->i2c_client_tuner) - smi_del_i2c_client(port->i2c_client_tuner); - if (port->i2c_client_demod) - smi_del_i2c_client(port->i2c_client_demod); - dvb_frontend_detach(port->fe); - return ret; - } - /* init MAC.*/ - ret = smi_read_eeprom(&dev->i2c_bus[0], 0xc0, mac_ee, 16); - dev_info(&port->dev->pci_dev->dev, - "DVBSky SMI PCIe MAC= %pM\n", mac_ee + (port->idx)*8); - memcpy(adap->proposed_mac, mac_ee + (port->idx)*8, 6); - return ret; -} - -static void smi_fe_exit(struct smi_port *port) -{ - dvb_unregister_frontend(port->fe); - /* remove I2C demod and tuner */ - if (port->i2c_client_tuner) - smi_del_i2c_client(port->i2c_client_tuner); - if (port->i2c_client_demod) - smi_del_i2c_client(port->i2c_client_demod); - dvb_frontend_detach(port->fe); -} - -static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id, - int (*start_feed)(struct dvb_demux_feed *), - int (*stop_feed)(struct dvb_demux_feed *), - void *priv) -{ - dvbdemux->priv = priv; - - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = start_feed; - dvbdemux->stop_feed = stop_feed; - dvbdemux->write_to_decoder = NULL; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - return dvb_dmx_init(dvbdemux); -} - -static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev, - struct dvb_demux *dvbdemux, - struct dmx_frontend *hw_frontend, - struct dmx_frontend *mem_frontend, - struct dvb_adapter *dvb_adapter) -{ - int ret; - - dmxdev->filternum = 256; - dmxdev->demux = &dvbdemux->dmx; - dmxdev->capabilities = 0; - ret = dvb_dmxdev_init(dmxdev, dvb_adapter); - if (ret < 0) - return ret; - - hw_frontend->source = DMX_FRONTEND_0; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend); - mem_frontend->source = DMX_MEMORY_FE; - dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend); - return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend); -} - -static u32 smi_config_DMA(struct smi_port *port) -{ - struct smi_dev *dev = port->dev; - u32 totalLength = 0, dmaMemPtrLow, dmaMemPtrHi, dmaCtlReg; - u8 chanLatencyTimer = 0, dmaChanEnable = 1, dmaTransStart = 1; - u32 dmaManagement = 0, tlpTransUnit = DMA_TRANS_UNIT_188; - u8 tlpTc = 0, tlpTd = 1, tlpEp = 0, tlpAttr = 0; - u64 mem; - - dmaManagement = smi_read(port->DMA_MANAGEMENT); - /* Setup Channel-0 */ - if (port->_dmaInterruptCH0) { - totalLength = SMI_TS_DMA_BUF_SIZE; - mem = port->dma_addr[0]; - dmaMemPtrLow = mem & 0xffffffff; - dmaMemPtrHi = mem >> 32; - dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25) - | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30); - dmaManagement |= dmaChanEnable | (dmaTransStart << 1) - | (chanLatencyTimer << 8); - /* write DMA register, start DMA engine */ - smi_write(port->DMA_CHAN0_ADDR_LOW, dmaMemPtrLow); - smi_write(port->DMA_CHAN0_ADDR_HI, dmaMemPtrHi); - smi_write(port->DMA_CHAN0_CONTROL, dmaCtlReg); - } - /* Setup Channel-1 */ - if (port->_dmaInterruptCH1) { - totalLength = SMI_TS_DMA_BUF_SIZE; - mem = port->dma_addr[1]; - dmaMemPtrLow = mem & 0xffffffff; - dmaMemPtrHi = mem >> 32; - dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25) - | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30); - dmaManagement |= (dmaChanEnable << 16) | (dmaTransStart << 17) - | (chanLatencyTimer << 24); - /* write DMA register, start DMA engine */ - smi_write(port->DMA_CHAN1_ADDR_LOW, dmaMemPtrLow); - smi_write(port->DMA_CHAN1_ADDR_HI, dmaMemPtrHi); - smi_write(port->DMA_CHAN1_CONTROL, dmaCtlReg); - } - return dmaManagement; -} - -static int smi_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct smi_port *port = dvbdmx->priv; - struct smi_dev *dev = port->dev; - u32 dmaManagement; - - if (port->users++ == 0) { - dmaManagement = smi_config_DMA(port); - smi_port_clearInterrupt(port); - smi_port_enableInterrupt(port); - smi_write(port->DMA_MANAGEMENT, dmaManagement); - tasklet_enable(&port->tasklet); - } - return port->users; -} - -static int smi_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct smi_port *port = dvbdmx->priv; - struct smi_dev *dev = port->dev; - - if (--port->users) - return port->users; - - tasklet_disable(&port->tasklet); - smi_port_disableInterrupt(port); - smi_clear(port->DMA_MANAGEMENT, 0x30003); - return 0; -} - -static int smi_dvb_init(struct smi_port *port) -{ - int ret; - struct dvb_adapter *adap = &port->dvb_adapter; - struct dvb_demux *dvbdemux = &port->demux; - - dev_dbg(&port->dev->pci_dev->dev, - "%s, port %d\n", __func__, port->idx); - - ret = dvb_register_adapter(adap, "SMI_DVB", THIS_MODULE, - &port->dev->pci_dev->dev, - adapter_nr); - if (ret < 0) { - dev_err(&port->dev->pci_dev->dev, "Fail to register DVB adapter.\n"); - return ret; - } - ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", - smi_start_feed, - smi_stop_feed, port); - if (ret < 0) - goto err_del_dvb_register_adapter; - - ret = my_dvb_dmxdev_ts_card_init(&port->dmxdev, &port->demux, - &port->hw_frontend, - &port->mem_frontend, adap); - if (ret < 0) - goto err_del_dvb_dmx; - - ret = dvb_net_init(adap, &port->dvbnet, port->dmxdev.demux); - if (ret < 0) - goto err_del_dvb_dmxdev; - return 0; -err_del_dvb_dmxdev: - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend); - dvb_dmxdev_release(&port->dmxdev); -err_del_dvb_dmx: - dvb_dmx_release(&port->demux); -err_del_dvb_register_adapter: - dvb_unregister_adapter(&port->dvb_adapter); - return ret; -} - -static void smi_dvb_exit(struct smi_port *port) -{ - struct dvb_demux *dvbdemux = &port->demux; - - dvb_net_release(&port->dvbnet); - - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend); - dvb_dmxdev_release(&port->dmxdev); - dvb_dmx_release(&port->demux); - - dvb_unregister_adapter(&port->dvb_adapter); -} - -static int smi_port_attach(struct smi_dev *dev, - struct smi_port *port, int index) -{ - int ret, dmachs; - - port->dev = dev; - port->idx = index; - port->fe_type = (index == 0) ? dev->info->fe_0 : dev->info->fe_1; - dmachs = (index == 0) ? dev->info->ts_0 : dev->info->ts_1; - /* port init.*/ - ret = smi_port_init(port, dmachs); - if (ret < 0) - return ret; - /* dvb init.*/ - ret = smi_dvb_init(port); - if (ret < 0) - goto err_del_port_init; - /* fe init.*/ - ret = smi_fe_init(port); - if (ret < 0) - goto err_del_dvb_init; - return 0; -err_del_dvb_init: - smi_dvb_exit(port); -err_del_port_init: - smi_port_exit(port); - return ret; -} - -static void smi_port_detach(struct smi_port *port) -{ - smi_fe_exit(port); - smi_dvb_exit(port); - smi_port_exit(port); -} - -static int smi_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct smi_dev *dev; - int ret = -ENOMEM; - - if (pci_enable_device(pdev) < 0) - return -ENODEV; - - dev = kzalloc(sizeof(struct smi_dev), GFP_KERNEL); - if (!dev) { - ret = -ENOMEM; - goto err_pci_disable_device; - } - - dev->pci_dev = pdev; - pci_set_drvdata(pdev, dev); - dev->info = (struct smi_cfg_info *) id->driver_data; - dev_info(&dev->pci_dev->dev, - "card detected: %s\n", dev->info->name); - - dev->nr = dev->info->type; - dev->lmmio = ioremap(pci_resource_start(dev->pci_dev, 0), - pci_resource_len(dev->pci_dev, 0)); - if (!dev->lmmio) { - ret = -ENOMEM; - goto err_kfree; - } - - /* should we set to 32bit DMA? */ - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret < 0) - goto err_pci_iounmap; - - pci_set_master(pdev); - - ret = smi_hw_init(dev); - if (ret < 0) - goto err_pci_iounmap; - - ret = smi_i2c_init(dev); - if (ret < 0) - goto err_pci_iounmap; - - if (dev->info->ts_0) { - ret = smi_port_attach(dev, &dev->ts_port[0], 0); - if (ret < 0) - goto err_del_i2c_adaptor; - } - - if (dev->info->ts_1) { - ret = smi_port_attach(dev, &dev->ts_port[1], 1); - if (ret < 0) - goto err_del_port0_attach; - } - -#ifdef CONFIG_PCI_MSI /* to do msi interrupt.???*/ - if (pci_msi_enabled()) - ret = pci_enable_msi(dev->pci_dev); - if (ret) - dev_info(&dev->pci_dev->dev, "MSI not available.\n"); -#endif - - ret = request_irq(dev->pci_dev->irq, smi_irq_handler, - IRQF_SHARED, "SMI_PCIE", dev); - if (ret < 0) - goto err_del_port1_attach; - - return 0; - -err_del_port1_attach: - if (dev->info->ts_1) - smi_port_detach(&dev->ts_port[1]); -err_del_port0_attach: - if (dev->info->ts_0) - smi_port_detach(&dev->ts_port[0]); -err_del_i2c_adaptor: - smi_i2c_exit(dev); -err_pci_iounmap: - iounmap(dev->lmmio); -err_kfree: - pci_set_drvdata(pdev, NULL); - kfree(dev); -err_pci_disable_device: - pci_disable_device(pdev); - return ret; -} - -static void smi_remove(struct pci_dev *pdev) -{ - struct smi_dev *dev = pci_get_drvdata(pdev); - - smi_write(MSI_INT_ENA_CLR, ALL_INT); - free_irq(dev->pci_dev->irq, dev); -#ifdef CONFIG_PCI_MSI - pci_disable_msi(dev->pci_dev); -#endif - if (dev->info->ts_1) - smi_port_detach(&dev->ts_port[1]); - if (dev->info->ts_0) - smi_port_detach(&dev->ts_port[0]); - - smi_i2c_exit(dev); - iounmap(dev->lmmio); - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); - kfree(dev); -} - -/* DVBSky cards */ -static struct smi_cfg_info dvbsky_s950_cfg = { - .type = SMI_DVBSKY_S950, - .name = "DVBSky S950 V3", - .ts_0 = SMI_TS_NULL, - .ts_1 = SMI_TS_DMA_BOTH, - .fe_0 = DVBSKY_FE_NULL, - .fe_1 = DVBSKY_FE_M88DS3103, -}; - -static struct smi_cfg_info dvbsky_s952_cfg = { - .type = SMI_DVBSKY_S952, - .name = "DVBSky S952 V3", - .ts_0 = SMI_TS_DMA_BOTH, - .ts_1 = SMI_TS_DMA_BOTH, - .fe_0 = DVBSKY_FE_M88RS6000, - .fe_1 = DVBSKY_FE_M88RS6000, -}; - -static struct smi_cfg_info dvbsky_t9580_cfg = { - .type = SMI_DVBSKY_T9580, - .name = "DVBSky T9580 V3", - .ts_0 = SMI_TS_DMA_BOTH, - .ts_1 = SMI_TS_DMA_BOTH, - .fe_0 = DVBSKY_FE_SIT2, - .fe_1 = DVBSKY_FE_M88DS3103, -}; - -/* PCI IDs */ -#define SMI_ID(_subvend, _subdev, _driverdata) { \ - .vendor = SMI_VID, .device = SMI_PID, \ - .subvendor = _subvend, .subdevice = _subdev, \ - .driver_data = (unsigned long)&_driverdata } - -static const struct pci_device_id smi_id_table[] = { - SMI_ID(0x4254, 0x0550, dvbsky_s950_cfg), - SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg), - SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg), - {0} -}; -MODULE_DEVICE_TABLE(pci, smi_id_table); - -static struct pci_driver smipcie_driver = { - .name = "SMI PCIe driver", - .id_table = smi_id_table, - .probe = smi_probe, - .remove = smi_remove, -}; - -module_pci_driver(smipcie_driver); - -MODULE_AUTHOR("Max nibble "); -MODULE_DESCRIPTION("SMI PCIe driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/smipcie/smipcie.h b/drivers/media/pci/smipcie/smipcie.h index 10cdf20f4839..68cdda28fd98 100644 --- a/drivers/media/pci/smipcie/smipcie.h +++ b/drivers/media/pci/smipcie/smipcie.h @@ -234,6 +234,17 @@ struct smi_cfg_info { int fe_1; }; +struct smi_rc { + struct smi_dev *dev; + struct rc_dev *rc_dev; + char input_phys[64]; + char input_name[64]; + struct work_struct work; + u8 irData[256]; + + int users; +}; + struct smi_port { struct smi_dev *dev; int idx; @@ -284,6 +295,9 @@ struct smi_dev { /* i2c */ struct i2c_adapter i2c_bus[2]; struct i2c_algo_bit_data i2c_bit[2]; + + /* ir */ + struct smi_rc ir; }; #define smi_read(reg) readl(dev->lmmio + ((reg)>>2)) @@ -296,4 +310,9 @@ struct smi_dev { #define smi_set(reg, bit) smi_andor((reg), (bit), (bit)) #define smi_clear(reg, bit) smi_andor((reg), (bit), 0) +int smi_ir_irq(struct smi_rc *ir, u32 int_status); +void smi_ir_start(struct smi_rc *ir); +void smi_ir_exit(struct smi_dev *dev); +int smi_ir_init(struct smi_dev *dev); + #endif /* #ifndef _SMI_PCIE_H_ */ -- cgit v1.3-6-gb490 From d713fd4976f2838ca2ebccdc187256edb46bd48e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:07 -0300 Subject: drm/i915: add simple wrappers for stolen node insertion/removal We want to move the FBC code out of i915_gem_stolen.c, but that code directly adds/removes stolen memory nodes. Let's create this abstraction, so i915_gme_stolen.c is still in control of all the stolen memory handling. The abstraction will also allow us to add locking assertions later. v2: - Add dev_priv as remove_node() argument since we'll need it later (Chris). Requested-by: Chris Wilson Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 ++++ drivers/gpu/drm/i915/i915_gem_stolen.c | 48 ++++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 63daf4cd2477..3e746ccf17ff 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3112,6 +3112,11 @@ static inline void i915_gem_chipset_flush(struct drm_device *dev) } /* i915_gem_stolen.c */ +int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv, + struct drm_mm_node *node, u64 size, + unsigned alignment); +void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv, + struct drm_mm_node *node); int i915_gem_init_stolen(struct drm_device *dev); int i915_gem_stolen_setup_compression(struct drm_device *dev, int size, int fb_cpp); void i915_gem_stolen_cleanup_compression(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 348ed5abcdbf..d811b148817f 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -42,6 +42,23 @@ * for is a boon. */ +int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv, + struct drm_mm_node *node, u64 size, + unsigned alignment) +{ + if (!drm_mm_initialized(&dev_priv->mm.stolen)) + return -ENODEV; + + return drm_mm_insert_node(&dev_priv->mm.stolen, node, size, alignment, + DRM_MM_SEARCH_DEFAULT); +} + +void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv, + struct drm_mm_node *node) +{ + drm_mm_remove_node(node); +} + static unsigned long i915_stolen_to_physical(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -168,8 +185,7 @@ static int find_compression_threshold(struct drm_device *dev, */ /* Try to over-allocate to reduce reallocations and fragmentation. */ - ret = drm_mm_insert_node(&dev_priv->mm.stolen, node, - size <<= 1, 4096, DRM_MM_SEARCH_DEFAULT); + ret = i915_gem_stolen_insert_node(dev_priv, node, size <<= 1, 4096); if (ret == 0) return compression_threshold; @@ -179,9 +195,7 @@ again: (fb_cpp == 2 && compression_threshold == 2)) return 0; - ret = drm_mm_insert_node(&dev_priv->mm.stolen, node, - size >>= 1, 4096, - DRM_MM_SEARCH_DEFAULT); + ret = i915_gem_stolen_insert_node(dev_priv, node, size >>= 1, 4096); if (ret && INTEL_INFO(dev)->gen <= 4) { return 0; } else if (ret) { @@ -218,8 +232,8 @@ static int i915_setup_compression(struct drm_device *dev, int size, int fb_cpp) if (!compressed_llb) goto err_fb; - ret = drm_mm_insert_node(&dev_priv->mm.stolen, compressed_llb, - 4096, 4096, DRM_MM_SEARCH_DEFAULT); + ret = i915_gem_stolen_insert_node(dev_priv, compressed_llb, + 4096, 4096); if (ret) goto err_fb; @@ -240,7 +254,7 @@ static int i915_setup_compression(struct drm_device *dev, int size, int fb_cpp) err_fb: kfree(compressed_llb); - drm_mm_remove_node(&dev_priv->fbc.compressed_fb); + i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); err_llb: pr_info_once("drm: not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size); return -ENOSPC; @@ -269,10 +283,11 @@ void i915_gem_stolen_cleanup_compression(struct drm_device *dev) if (dev_priv->fbc.uncompressed_size == 0) return; - drm_mm_remove_node(&dev_priv->fbc.compressed_fb); + i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); if (dev_priv->fbc.compressed_llb) { - drm_mm_remove_node(dev_priv->fbc.compressed_llb); + i915_gem_stolen_remove_node(dev_priv, + dev_priv->fbc.compressed_llb); kfree(dev_priv->fbc.compressed_llb); } @@ -386,8 +401,10 @@ static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj) static void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + if (obj->stolen) { - drm_mm_remove_node(obj->stolen); + i915_gem_stolen_remove_node(dev_priv, obj->stolen); kfree(obj->stolen); obj->stolen = NULL; } @@ -449,8 +466,7 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size) if (!stolen) return NULL; - ret = drm_mm_insert_node(&dev_priv->mm.stolen, stolen, size, - 4096, DRM_MM_SEARCH_DEFAULT); + ret = i915_gem_stolen_insert_node(dev_priv, stolen, size, 4096); if (ret) { kfree(stolen); return NULL; @@ -460,7 +476,7 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size) if (obj) return obj; - drm_mm_remove_node(stolen); + i915_gem_stolen_remove_node(dev_priv, stolen); kfree(stolen); return NULL; } @@ -505,7 +521,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, obj = _i915_gem_object_create_stolen(dev, stolen); if (obj == NULL) { DRM_DEBUG_KMS("failed to allocate stolen object\n"); - drm_mm_remove_node(stolen); + i915_gem_stolen_remove_node(dev_priv, stolen); kfree(stolen); return NULL; } @@ -546,7 +562,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, err_vma: i915_gem_vma_destroy(vma); err_out: - drm_mm_remove_node(stolen); + i915_gem_stolen_remove_node(dev_priv, stolen); kfree(stolen); drm_gem_object_unreference(&obj->base); return NULL; -- cgit v1.3-6-gb490 From fc786728ee8acc76e22769af3b2df67b94cd49b6 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:08 -0300 Subject: drm/i915: move FBC code out of i915_gem_stolen.c With the abstractions created by the last patch, we can move this code and the only thing inside intel_fbc.c that knows about dev_priv->mm is the code that reads stolen_base. We also had to move a call to i915_gem_stolen_cleanup_compression() - now called intel_fbc_cleanup_cfb() - outside i915_gem_stolen.c. v2: - Rebase after the remove_node() changes on the previous patch. Requested-by: Chris Wilson Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson 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_gem_stolen.c | 127 -------------------------------- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_fbc.c | 129 ++++++++++++++++++++++++++++++++- 5 files changed, 128 insertions(+), 132 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a42f16592433..066c34c3298a 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1123,6 +1123,7 @@ int i915_driver_unload(struct drm_device *dev) i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); + intel_fbc_cleanup_cfb(dev); i915_gem_cleanup_stolen(dev); intel_csr_ucode_fini(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3e746ccf17ff..2b78686e23d9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3118,8 +3118,6 @@ int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv, void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv, struct drm_mm_node *node); int i915_gem_init_stolen(struct drm_device *dev); -int i915_gem_stolen_setup_compression(struct drm_device *dev, int size, int fb_cpp); -void i915_gem_stolen_cleanup_compression(struct drm_device *dev); void i915_gem_cleanup_stolen(struct drm_device *dev); struct drm_i915_gem_object * i915_gem_object_create_stolen(struct drm_device *dev, u32 size); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index d811b148817f..d2d556c69175 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -168,132 +168,6 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev) return base; } -static int find_compression_threshold(struct drm_device *dev, - struct drm_mm_node *node, - int size, - int fb_cpp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int compression_threshold = 1; - int ret; - - /* HACK: This code depends on what we will do in *_enable_fbc. If that - * code changes, this code needs to change as well. - * - * The enable_fbc code will attempt to use one of our 2 compression - * thresholds, therefore, in that case, we only have 1 resort. - */ - - /* Try to over-allocate to reduce reallocations and fragmentation. */ - ret = i915_gem_stolen_insert_node(dev_priv, node, size <<= 1, 4096); - if (ret == 0) - return compression_threshold; - -again: - /* HW's ability to limit the CFB is 1:4 */ - if (compression_threshold > 4 || - (fb_cpp == 2 && compression_threshold == 2)) - return 0; - - ret = i915_gem_stolen_insert_node(dev_priv, node, size >>= 1, 4096); - if (ret && INTEL_INFO(dev)->gen <= 4) { - return 0; - } else if (ret) { - compression_threshold <<= 1; - goto again; - } else { - return compression_threshold; - } -} - -static int i915_setup_compression(struct drm_device *dev, int size, int fb_cpp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_mm_node *uninitialized_var(compressed_llb); - int ret; - - ret = find_compression_threshold(dev, &dev_priv->fbc.compressed_fb, - size, fb_cpp); - if (!ret) - goto err_llb; - else if (ret > 1) { - DRM_INFO("Reducing the compressed framebuffer size. This may lead to less power savings than a non-reduced-size. Try to increase stolen memory size if available in BIOS.\n"); - - } - - dev_priv->fbc.threshold = ret; - - if (INTEL_INFO(dev_priv)->gen >= 5) - I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); - else if (IS_GM45(dev)) { - I915_WRITE(DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); - } else { - compressed_llb = kzalloc(sizeof(*compressed_llb), GFP_KERNEL); - if (!compressed_llb) - goto err_fb; - - ret = i915_gem_stolen_insert_node(dev_priv, compressed_llb, - 4096, 4096); - if (ret) - goto err_fb; - - dev_priv->fbc.compressed_llb = compressed_llb; - - I915_WRITE(FBC_CFB_BASE, - dev_priv->mm.stolen_base + dev_priv->fbc.compressed_fb.start); - I915_WRITE(FBC_LL_BASE, - dev_priv->mm.stolen_base + compressed_llb->start); - } - - dev_priv->fbc.uncompressed_size = size; - - DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n", - size); - - return 0; - -err_fb: - kfree(compressed_llb); - i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); -err_llb: - pr_info_once("drm: not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size); - return -ENOSPC; -} - -int i915_gem_stolen_setup_compression(struct drm_device *dev, int size, int fb_cpp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!drm_mm_initialized(&dev_priv->mm.stolen)) - return -ENODEV; - - if (size <= dev_priv->fbc.uncompressed_size) - return 0; - - /* Release any current block */ - i915_gem_stolen_cleanup_compression(dev); - - return i915_setup_compression(dev, size, fb_cpp); -} - -void i915_gem_stolen_cleanup_compression(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->fbc.uncompressed_size == 0) - return; - - i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); - - if (dev_priv->fbc.compressed_llb) { - i915_gem_stolen_remove_node(dev_priv, - dev_priv->fbc.compressed_llb); - kfree(dev_priv->fbc.compressed_llb); - } - - dev_priv->fbc.uncompressed_size = 0; -} - void i915_gem_cleanup_stolen(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -301,7 +175,6 @@ void i915_gem_cleanup_stolen(struct drm_device *dev) if (!drm_mm_initialized(&dev_priv->mm.stolen)) return; - i915_gem_stolen_cleanup_compression(dev); drm_mm_takedown(&dev_priv->mm.stolen); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3f0a89060820..82abbfae4e23 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1258,6 +1258,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); const char *intel_no_fbc_reason_str(enum no_fbc_reason reason); +void intel_fbc_cleanup_cfb(struct drm_device *dev); /* intel_hdmi.c */ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 9e55b9badb4b..55711b452fbf 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -515,6 +515,129 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) return crtc; } +static int find_compression_threshold(struct drm_device *dev, + struct drm_mm_node *node, + int size, + int fb_cpp) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int compression_threshold = 1; + int ret; + + /* HACK: This code depends on what we will do in *_enable_fbc. If that + * code changes, this code needs to change as well. + * + * The enable_fbc code will attempt to use one of our 2 compression + * thresholds, therefore, in that case, we only have 1 resort. + */ + + /* Try to over-allocate to reduce reallocations and fragmentation. */ + ret = i915_gem_stolen_insert_node(dev_priv, node, size <<= 1, 4096); + if (ret == 0) + return compression_threshold; + +again: + /* HW's ability to limit the CFB is 1:4 */ + if (compression_threshold > 4 || + (fb_cpp == 2 && compression_threshold == 2)) + return 0; + + ret = i915_gem_stolen_insert_node(dev_priv, node, size >>= 1, 4096); + if (ret && INTEL_INFO(dev)->gen <= 4) { + return 0; + } else if (ret) { + compression_threshold <<= 1; + goto again; + } else { + return compression_threshold; + } +} + +static int intel_fbc_alloc_cfb(struct drm_device *dev, int size, int fb_cpp) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_mm_node *uninitialized_var(compressed_llb); + int ret; + + ret = find_compression_threshold(dev, &dev_priv->fbc.compressed_fb, + size, fb_cpp); + if (!ret) + goto err_llb; + else if (ret > 1) { + DRM_INFO("Reducing the compressed framebuffer size. This may lead to less power savings than a non-reduced-size. Try to increase stolen memory size if available in BIOS.\n"); + + } + + dev_priv->fbc.threshold = ret; + + if (INTEL_INFO(dev_priv)->gen >= 5) + I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); + else if (IS_GM45(dev)) { + I915_WRITE(DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); + } else { + compressed_llb = kzalloc(sizeof(*compressed_llb), GFP_KERNEL); + if (!compressed_llb) + goto err_fb; + + ret = i915_gem_stolen_insert_node(dev_priv, compressed_llb, + 4096, 4096); + if (ret) + goto err_fb; + + dev_priv->fbc.compressed_llb = compressed_llb; + + I915_WRITE(FBC_CFB_BASE, + dev_priv->mm.stolen_base + dev_priv->fbc.compressed_fb.start); + I915_WRITE(FBC_LL_BASE, + dev_priv->mm.stolen_base + compressed_llb->start); + } + + dev_priv->fbc.uncompressed_size = size; + + DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n", + size); + + return 0; + +err_fb: + kfree(compressed_llb); + i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); +err_llb: + pr_info_once("drm: not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size); + return -ENOSPC; +} + +void intel_fbc_cleanup_cfb(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->fbc.uncompressed_size == 0) + return; + + i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); + + if (dev_priv->fbc.compressed_llb) { + i915_gem_stolen_remove_node(dev_priv, + dev_priv->fbc.compressed_llb); + kfree(dev_priv->fbc.compressed_llb); + } + + dev_priv->fbc.uncompressed_size = 0; +} + +static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (size <= dev_priv->fbc.uncompressed_size) + return 0; + + /* Release any current block */ + intel_fbc_cleanup_cfb(dev); + + return intel_fbc_alloc_cfb(dev, size, fb_cpp); +} + /** * intel_fbc_update - enable/disable FBC as needed * @dev: the drm_device @@ -624,8 +747,8 @@ void intel_fbc_update(struct drm_device *dev) if (in_dbg_master()) goto out_disable; - if (i915_gem_stolen_setup_compression(dev, obj->base.size, - drm_format_plane_cpp(fb->pixel_format, 0))) { + if (intel_fbc_setup_cfb(dev, obj->base.size, + drm_format_plane_cpp(fb->pixel_format, 0))) { set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL); goto out_disable; } @@ -678,7 +801,7 @@ out_disable: DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); intel_fbc_disable(dev); } - i915_gem_stolen_cleanup_compression(dev); + intel_fbc_cleanup_cfb(dev); } void intel_fbc_invalidate(struct drm_i915_private *dev_priv, -- cgit v1.3-6-gb490 From 92e97d2f47616b144feb86db489e134935b021b8 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:09 -0300 Subject: drm/i915: add dev_priv->mm.stolen_lock Which should protect dev_priv->mm.stolen usage. This will allow us to simplify the relationship between stolen memory, FBC and struct_mutex. v2: - Rebase after the stolen_remove_node() dev_priv patch move. - I realized that after we fixed a few things related to the FBC CFB size checks, we're not reallocating the CFB anymore with FBC enabled, so we can just move all the locking to i915_gem_stolen.c and stop worrying about freezing all the stolen alocations while freeing/rellocating the CFB. This allows us to fix the "Too coarse" observation from Chris. Suggested-by: Chris Wilson Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++++ drivers/gpu/drm/i915/i915_gem_stolen.c | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2b78686e23d9..eb10c1624006 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1245,6 +1245,10 @@ struct intel_l3_parity { struct i915_gem_mm { /** Memory allocator for GTT stolen memory */ struct drm_mm stolen; + /** Protects the usage of the GTT stolen memory allocator. This is + * always the inner lock when overlapping with struct_mutex. */ + struct mutex stolen_lock; + /** List of all objects in gtt_space. Used to restore gtt * mappings on resume */ struct list_head bound_list; diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index d2d556c69175..de76d886cd1d 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -46,17 +46,25 @@ int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv, struct drm_mm_node *node, u64 size, unsigned alignment) { + int ret; + if (!drm_mm_initialized(&dev_priv->mm.stolen)) return -ENODEV; - return drm_mm_insert_node(&dev_priv->mm.stolen, node, size, alignment, - DRM_MM_SEARCH_DEFAULT); + mutex_lock(&dev_priv->mm.stolen_lock); + ret = drm_mm_insert_node(&dev_priv->mm.stolen, node, size, alignment, + DRM_MM_SEARCH_DEFAULT); + mutex_unlock(&dev_priv->mm.stolen_lock); + + return ret; } void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv, struct drm_mm_node *node) { + mutex_lock(&dev_priv->mm.stolen_lock); drm_mm_remove_node(node); + mutex_unlock(&dev_priv->mm.stolen_lock); } static unsigned long i915_stolen_to_physical(struct drm_device *dev) @@ -184,6 +192,8 @@ int i915_gem_init_stolen(struct drm_device *dev) u32 tmp; int bios_reserved = 0; + mutex_init(&dev_priv->mm.stolen_lock); + #ifdef CONFIG_INTEL_IOMMU if (intel_iommu_gfx_mapped && INTEL_INFO(dev)->gen < 8) { DRM_INFO("DMAR active, disabling use of stolen memory\n"); @@ -384,7 +394,9 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, stolen->start = stolen_offset; stolen->size = size; + mutex_lock(&dev_priv->mm.stolen_lock); ret = drm_mm_reserve_node(&dev_priv->mm.stolen, stolen); + mutex_unlock(&dev_priv->mm.stolen_lock); if (ret) { DRM_DEBUG_KMS("failed to allocate stolen space\n"); kfree(stolen); -- cgit v1.3-6-gb490 From 25ad93fd9f0513df41f70327cca19d51369f1674 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:10 -0300 Subject: drm/i915: add the FBC mutex Make sure we're not going to have weird races in really weird cases where a lot of different CRTCs are doing rendering and modesets at the same time. With this change and the stolen_lock from the previous patch, we can start removing the struct_mutex locking we have around FBC in the next patches. v2: - Rebase (6 months later) - Also lock debugfs and stolen. v3: - Don't lock a single value read (Chris). - Replace lockdep assertions with WARNs (Daniel). - Improve commit message. - Don't forget intel_pre_plane_update() locking. v4: - Don't remove struct_mutex at intel_pre_plane_update() (Chris). - Add comment regarding locking dependencies (Chris). - Rebase after the stolen code rework. - Rebase again after drm-intel-nightly changes. v5: - Rebase after the new stolen_lock patch. Reviewed-by: Chris Wilson (v4) Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++ drivers/gpu/drm/i915/i915_drv.h | 3 ++ drivers/gpu/drm/i915/intel_display.c | 6 +-- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_fbc.c | 101 +++++++++++++++++++++++++++++------ 5 files changed, 96 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6a8de04c6a2b..cc74a92dd346 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1633,6 +1633,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused) } intel_runtime_pm_get(dev_priv); + mutex_lock(&dev_priv->fbc.lock); if (intel_fbc_enabled(dev)) seq_puts(m, "FBC enabled\n"); @@ -1645,6 +1646,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused) yesno(I915_READ(FBC_STATUS2) & FBC_COMPRESSION_MASK)); + mutex_unlock(&dev_priv->fbc.lock); intel_runtime_pm_put(dev_priv); return 0; @@ -1675,6 +1677,7 @@ static int i915_fbc_fc_set(void *data, u64 val) return -ENODEV; drm_modeset_lock_all(dev); + mutex_lock(&dev_priv->fbc.lock); reg = I915_READ(ILK_DPFC_CONTROL); dev_priv->fbc.false_color = val; @@ -1683,6 +1686,7 @@ static int i915_fbc_fc_set(void *data, u64 val) (reg | FBC_CTL_FALSE_COLOR) : (reg & ~FBC_CTL_FALSE_COLOR)); + mutex_unlock(&dev_priv->fbc.lock); drm_modeset_unlock_all(dev); return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index eb10c1624006..093d6421dddf 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -899,6 +899,9 @@ enum fb_op_origin { }; struct i915_fbc { + /* This is always the inner lock when overlapping with struct_mutex and + * it's the outer lock when overlapping with stolen_lock. */ + struct mutex lock; unsigned long uncompressed_size; unsigned threshold; unsigned int fb_id; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 136b53371878..93d3bdf242a9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4783,11 +4783,9 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) if (atomic->wait_for_flips) intel_crtc_wait_for_pending_flips(&crtc->base); - if (atomic->disable_fbc && - dev_priv->fbc.crtc == crtc) { + if (atomic->disable_fbc) { mutex_lock(&dev->struct_mutex); - if (dev_priv->fbc.crtc == crtc) - intel_fbc_disable(dev); + intel_fbc_disable_crtc(crtc); mutex_unlock(&dev->struct_mutex); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 82abbfae4e23..63d7d32e6123 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1252,6 +1252,7 @@ bool intel_fbc_enabled(struct drm_device *dev); void intel_fbc_update(struct drm_device *dev); void intel_fbc_init(struct drm_i915_private *dev_priv); void intel_fbc_disable(struct drm_device *dev); +void intel_fbc_disable_crtc(struct intel_crtc *crtc); void intel_fbc_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 55711b452fbf..a076c7a25062 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -336,6 +336,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) struct drm_i915_private *dev_priv = dev->dev_private; mutex_lock(&dev->struct_mutex); + mutex_lock(&dev_priv->fbc.lock); if (work == dev_priv->fbc.fbc_work) { /* Double check that we haven't switched fb without cancelling * the prior work. @@ -350,6 +351,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) dev_priv->fbc.fbc_work = NULL; } + mutex_unlock(&dev_priv->fbc.lock); mutex_unlock(&dev->struct_mutex); kfree(work); @@ -357,6 +359,8 @@ static void intel_fbc_work_fn(struct work_struct *__work) static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv) { + WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + if (dev_priv->fbc.fbc_work == NULL) return; @@ -384,6 +388,8 @@ static void intel_fbc_enable(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; + WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + if (!dev_priv->display.enable_fbc) return; @@ -418,6 +424,21 @@ static void intel_fbc_enable(struct drm_crtc *crtc) schedule_delayed_work(&work->work, msecs_to_jiffies(50)); } +static void __intel_fbc_disable(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + + intel_fbc_cancel_work(dev_priv); + + if (!dev_priv->display.disable_fbc) + return; + + dev_priv->display.disable_fbc(dev); + dev_priv->fbc.crtc = NULL; +} + /** * intel_fbc_disable - disable FBC * @dev: the drm_device @@ -428,13 +449,26 @@ void intel_fbc_disable(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - intel_fbc_cancel_work(dev_priv); + mutex_lock(&dev_priv->fbc.lock); + __intel_fbc_disable(dev); + mutex_unlock(&dev_priv->fbc.lock); +} - if (!dev_priv->display.disable_fbc) - return; +/* + * intel_fbc_disable_crtc - disable FBC if it's associated with crtc + * @crtc: the CRTC + * + * This function disables FBC if it's associated with the provided CRTC. + */ +void intel_fbc_disable_crtc(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; - dev_priv->display.disable_fbc(dev); - dev_priv->fbc.crtc = NULL; + mutex_lock(&dev_priv->fbc.lock); + if (dev_priv->fbc.crtc == crtc) + __intel_fbc_disable(dev); + mutex_unlock(&dev_priv->fbc.lock); } const char *intel_no_fbc_reason_str(enum no_fbc_reason reason) @@ -607,7 +641,7 @@ err_llb: return -ENOSPC; } -void intel_fbc_cleanup_cfb(struct drm_device *dev) +static void __intel_fbc_cleanup_cfb(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -625,6 +659,15 @@ void intel_fbc_cleanup_cfb(struct drm_device *dev) dev_priv->fbc.uncompressed_size = 0; } +void intel_fbc_cleanup_cfb(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev_priv->fbc.lock); + __intel_fbc_cleanup_cfb(dev); + mutex_unlock(&dev_priv->fbc.lock); +} + static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -633,13 +676,13 @@ static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) return 0; /* Release any current block */ - intel_fbc_cleanup_cfb(dev); + __intel_fbc_cleanup_cfb(dev); return intel_fbc_alloc_cfb(dev, size, fb_cpp); } /** - * intel_fbc_update - enable/disable FBC as needed + * __intel_fbc_update - enable/disable FBC as needed, unlocked * @dev: the drm_device * * Set up the framebuffer compression hardware at mode set time. We @@ -657,7 +700,7 @@ static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) * * We need to enable/disable FBC on a global basis. */ -void intel_fbc_update(struct drm_device *dev) +static void __intel_fbc_update(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = NULL; @@ -670,6 +713,8 @@ void intel_fbc_update(struct drm_device *dev) if (!HAS_FBC(dev)) return; + WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + /* disable framebuffer compression in vGPU */ if (intel_vgpu_active(dev)) i915.enable_fbc = 0; @@ -788,7 +833,7 @@ void intel_fbc_update(struct drm_device *dev) * some point. And we wait before enabling FBC anyway. */ DRM_DEBUG_KMS("disabling active FBC for update\n"); - intel_fbc_disable(dev); + __intel_fbc_disable(dev); } intel_fbc_enable(crtc); @@ -799,9 +844,24 @@ out_disable: /* Multiple disables should be harmless */ if (intel_fbc_enabled(dev)) { DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); - intel_fbc_disable(dev); + __intel_fbc_disable(dev); } - intel_fbc_cleanup_cfb(dev); + __intel_fbc_cleanup_cfb(dev); +} + +/* + * intel_fbc_update - enable/disable FBC as needed + * @dev: the drm_device + * + * This function reevaluates the overall state and enables or disables FBC. + */ +void intel_fbc_update(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev_priv->fbc.lock); + __intel_fbc_update(dev); + mutex_unlock(&dev_priv->fbc.lock); } void intel_fbc_invalidate(struct drm_i915_private *dev_priv, @@ -814,6 +874,8 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, if (origin == ORIGIN_GTT) return; + mutex_lock(&dev_priv->fbc.lock); + if (dev_priv->fbc.enabled) fbc_bits = INTEL_FRONTBUFFER_PRIMARY(dev_priv->fbc.crtc->pipe); else if (dev_priv->fbc.fbc_work) @@ -825,7 +887,9 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, dev_priv->fbc.busy_bits |= (fbc_bits & frontbuffer_bits); if (dev_priv->fbc.busy_bits) - intel_fbc_disable(dev); + __intel_fbc_disable(dev); + + mutex_unlock(&dev_priv->fbc.lock); } void intel_fbc_flush(struct drm_i915_private *dev_priv, @@ -833,13 +897,18 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, { struct drm_device *dev = dev_priv->dev; + mutex_lock(&dev_priv->fbc.lock); + if (!dev_priv->fbc.busy_bits) - return; + goto out; dev_priv->fbc.busy_bits &= ~frontbuffer_bits; if (!dev_priv->fbc.busy_bits) - intel_fbc_update(dev); + __intel_fbc_update(dev); + +out: + mutex_unlock(&dev_priv->fbc.lock); } /** @@ -852,6 +921,8 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) { enum pipe pipe; + mutex_init(&dev_priv->fbc.lock); + if (!HAS_FBC(dev_priv)) { dev_priv->fbc.enabled = false; dev_priv->fbc.no_fbc_reason = FBC_UNSUPPORTED; -- cgit v1.3-6-gb490 From 5abeca4ec5d425538b73af58076990823a744e2a Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:11 -0300 Subject: drm/i915: intel_frontbuffer_flip_prepare() doesn't need struct_mutex So release the lock earlier. Reviewed-by: Chris wilson Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 93d3bdf242a9..e1f9ae69a13a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11475,9 +11475,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, to_intel_plane(primary)->frontbuffer_bit); intel_fbc_disable(dev); + mutex_unlock(&dev->struct_mutex); intel_frontbuffer_flip_prepare(dev, to_intel_plane(primary)->frontbuffer_bit); - mutex_unlock(&dev->struct_mutex); trace_i915_flip_request(intel_crtc->plane, obj); -- cgit v1.3-6-gb490 From b5e4b84d9f12b093780a4e90e51604c3b4706cde Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:12 -0300 Subject: drm/i915: intel_unregister_dsm_handler() doesn't need struct_mutex So don't grab the lock before calling the function. Reviewed-by: Chris wilson Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e1f9ae69a13a..8ddeb294f1eb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15603,12 +15603,10 @@ void intel_modeset_cleanup(struct drm_device *dev) */ drm_kms_helper_poll_fini(dev); - mutex_lock(&dev->struct_mutex); - intel_unregister_dsm_handler(); + mutex_lock(&dev->struct_mutex); intel_fbc_disable(dev); - mutex_unlock(&dev->struct_mutex); /* flush any delayed tasks or pending work */ -- cgit v1.3-6-gb490 From c80ac8548d167dfb7affdb997d99d875bb1a28a3 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:13 -0300 Subject: drm/i915: FBC doesn't need struct_mutex anymore Everything is covered either by fbc.lock or mm.stolen_lock, and intel_fbc.c is already responsible for grabbing the appropriate locks when it needs them. Reviewed-by: Chris wilson Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ---- drivers/gpu/drm/i915/intel_display.c | 14 +++----------- drivers/gpu/drm/i915/intel_fbc.c | 2 -- 3 files changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index cc74a92dd346..5b89130eb366 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1660,9 +1660,7 @@ static int i915_fbc_fc_get(void *data, u64 *val) if (INTEL_INFO(dev)->gen < 7 || !HAS_FBC(dev)) return -ENODEV; - drm_modeset_lock_all(dev); *val = dev_priv->fbc.false_color; - drm_modeset_unlock_all(dev); return 0; } @@ -1676,7 +1674,6 @@ static int i915_fbc_fc_set(void *data, u64 val) if (INTEL_INFO(dev)->gen < 7 || !HAS_FBC(dev)) return -ENODEV; - drm_modeset_lock_all(dev); mutex_lock(&dev_priv->fbc.lock); reg = I915_READ(ILK_DPFC_CONTROL); @@ -1687,7 +1684,6 @@ static int i915_fbc_fc_set(void *data, u64 val) (reg & ~FBC_CTL_FALSE_COLOR)); mutex_unlock(&dev_priv->fbc.lock); - drm_modeset_unlock_all(dev); return 0; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8ddeb294f1eb..eb50f59d7840 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4747,11 +4747,8 @@ static void intel_post_plane_update(struct intel_crtc *crtc) if (crtc->atomic.update_wm_post) intel_update_watermarks(&crtc->base); - if (atomic->update_fbc) { - mutex_lock(&dev->struct_mutex); + if (atomic->update_fbc) intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); - } if (atomic->post_enable_primary) intel_post_enable_primary(&crtc->base); @@ -4783,11 +4780,8 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) if (atomic->wait_for_flips) intel_crtc_wait_for_pending_flips(&crtc->base); - if (atomic->disable_fbc) { - mutex_lock(&dev->struct_mutex); + if (atomic->disable_fbc) intel_fbc_disable_crtc(crtc); - mutex_unlock(&dev->struct_mutex); - } if (crtc->atomic.disable_ips) hsw_disable_ips(crtc); @@ -11473,9 +11467,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, i915_gem_track_fb(intel_fb_obj(work->old_fb), obj, to_intel_plane(primary)->frontbuffer_bit); + mutex_unlock(&dev->struct_mutex); intel_fbc_disable(dev); - mutex_unlock(&dev->struct_mutex); intel_frontbuffer_flip_prepare(dev, to_intel_plane(primary)->frontbuffer_bit); @@ -15605,9 +15599,7 @@ void intel_modeset_cleanup(struct drm_device *dev) intel_unregister_dsm_handler(); - mutex_lock(&dev->struct_mutex); intel_fbc_disable(dev); - mutex_unlock(&dev->struct_mutex); /* flush any delayed tasks or pending work */ flush_scheduled_work(); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index a076c7a25062..cc9b7effec40 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -335,7 +335,6 @@ static void intel_fbc_work_fn(struct work_struct *__work) struct drm_device *dev = work->crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - mutex_lock(&dev->struct_mutex); mutex_lock(&dev_priv->fbc.lock); if (work == dev_priv->fbc.fbc_work) { /* Double check that we haven't switched fb without cancelling @@ -352,7 +351,6 @@ static void intel_fbc_work_fn(struct work_struct *__work) dev_priv->fbc.fbc_work = NULL; } mutex_unlock(&dev_priv->fbc.lock); - mutex_unlock(&dev->struct_mutex); kfree(work); } -- cgit v1.3-6-gb490 From 0bf73c361f986a04af332600bf06476c8f481c5b Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 Jul 2015 15:40:54 -0300 Subject: drm/i915: protect FBC functions with FBC checks Now all the functions called by other files check whether FBC has been initialized. This allows us to drop the checks on the static functions. v2: - s/HAS_FBC/dev_priv->display.enable_fbc/ everywhere but the init function (Chris). Suggested-by: Chris Wilson Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index cc9b7effec40..65f08e330dc1 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -388,9 +388,6 @@ static void intel_fbc_enable(struct drm_crtc *crtc) WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); - if (!dev_priv->display.enable_fbc) - return; - intel_fbc_cancel_work(dev_priv); work = kzalloc(sizeof(*work), GFP_KERNEL); @@ -430,9 +427,6 @@ static void __intel_fbc_disable(struct drm_device *dev) intel_fbc_cancel_work(dev_priv); - if (!dev_priv->display.disable_fbc) - return; - dev_priv->display.disable_fbc(dev); dev_priv->fbc.crtc = NULL; } @@ -447,6 +441,9 @@ void intel_fbc_disable(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (!dev_priv->display.enable_fbc) + return; + mutex_lock(&dev_priv->fbc.lock); __intel_fbc_disable(dev); mutex_unlock(&dev_priv->fbc.lock); @@ -463,6 +460,9 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc) struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + if (!dev_priv->display.enable_fbc) + return; + mutex_lock(&dev_priv->fbc.lock); if (dev_priv->fbc.crtc == crtc) __intel_fbc_disable(dev); @@ -661,6 +661,9 @@ void intel_fbc_cleanup_cfb(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (!dev_priv->display.enable_fbc) + return; + mutex_lock(&dev_priv->fbc.lock); __intel_fbc_cleanup_cfb(dev); mutex_unlock(&dev_priv->fbc.lock); @@ -708,9 +711,6 @@ static void __intel_fbc_update(struct drm_device *dev) const struct drm_display_mode *adjusted_mode; unsigned int max_width, max_height; - if (!HAS_FBC(dev)) - return; - WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); /* disable framebuffer compression in vGPU */ @@ -857,6 +857,9 @@ void intel_fbc_update(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (!dev_priv->display.enable_fbc) + return; + mutex_lock(&dev_priv->fbc.lock); __intel_fbc_update(dev); mutex_unlock(&dev_priv->fbc.lock); @@ -869,6 +872,9 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, struct drm_device *dev = dev_priv->dev; unsigned int fbc_bits; + if (!dev_priv->display.enable_fbc) + return; + if (origin == ORIGIN_GTT) return; @@ -895,6 +901,9 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, { struct drm_device *dev = dev_priv->dev; + if (!dev_priv->display.enable_fbc) + return; + mutex_lock(&dev_priv->fbc.lock); if (!dev_priv->fbc.busy_bits) -- cgit v1.3-6-gb490 From 9e00084750c0f0603ec8a6ff15e0bcf78b8202bd Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 3 Jul 2015 14:27:31 +0100 Subject: drm/i915: Update WaFlushCoherentL3CacheLinesAtContextSwitch In this WA we need to set GEN8_L3SQCREG4[21:21] and reset it after PIPE_CONTROL instruction but there is a slight complication as this is applied in WA batch where the values are only initialized once. Dave identified an issue with the current implementation where the register value is read once at the beginning and it is reused; this patch corrects this by saving the register value to memory, update register with the bit of our interest and restore it back with original value. This implementation uses MI_LOAD_REGISTER_MEM which is currently only used by command parser and was using a default length of 0. This is now updated with correct length and moved to appropriate place. Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 6 +-- drivers/gpu/drm/i915/i915_reg.h | 3 +- drivers/gpu/drm/i915/intel_lrc.c | 72 +++++++++++++++++++++++++--------- 3 files changed, 58 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 306d9e4e5cf3..430571b977db 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -131,7 +131,7 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { .mask = MI_GLOBAL_GTT, .expected = 0, }}, ), - CMD( MI_LOAD_REGISTER_MEM, SMI, !F, 0xFF, W | B, + CMD( MI_LOAD_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, .reg = { .offset = 1, .mask = 0x007FFFFC }, .bits = {{ .offset = 0, @@ -1021,7 +1021,7 @@ static bool check_cmd(const struct intel_engine_cs *ring, * only MI_LOAD_REGISTER_IMM commands. */ if (reg_addr == OACONTROL) { - if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM(1)) { DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); return false; } @@ -1035,7 +1035,7 @@ static bool check_cmd(const struct intel_engine_cs *ring, * allowed mask/value pair given in the whitelist entry. */ if (reg->mask) { - if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM(1)) { DRM_DEBUG_DRIVER("CMD: Rejected LRM to masked register 0x%08X\n", reg_addr); return false; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 45ff3d3e79c8..1c4d7894b429 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -354,6 +354,8 @@ #define MI_INVALIDATE_BSD (1<<7) #define MI_FLUSH_DW_USE_GTT (1<<2) #define MI_FLUSH_DW_USE_PPGTT (0<<2) +#define MI_LOAD_REGISTER_MEM(x) MI_INSTR(0x29, 2*(x)-1) +#define MI_LOAD_REGISTER_MEM_GEN8(x) MI_INSTR(0x29, 3*(x)-1) #define MI_BATCH_BUFFER MI_INSTR(0x30, 1) #define MI_BATCH_NON_SECURE (1) /* for snb/ivb/vlv this also means "batch in ppgtt" when ppgtt is enabled. */ @@ -459,7 +461,6 @@ #define MI_CLFLUSH MI_INSTR(0x27, 0) #define MI_REPORT_PERF_COUNT MI_INSTR(0x28, 0) #define MI_REPORT_PERF_COUNT_GGTT (1<<0) -#define MI_LOAD_REGISTER_MEM MI_INSTR(0x29, 0) #define MI_LOAD_REGISTER_REG MI_INSTR(0x2A, 0) #define MI_RS_STORE_DATA_IMM MI_INSTR(0x2B, 0) #define MI_LOAD_URB_MEM MI_INSTR(0x2C, 0) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 0160bec1e7ba..a499f16db194 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1092,6 +1092,56 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) batch[index++] = (cmd); \ } while (0) + +/* + * In this WA we need to set GEN8_L3SQCREG4[21:21] and reset it after + * PIPE_CONTROL instruction. This is required for the flush to happen correctly + * but there is a slight complication as this is applied in WA batch where the + * values are only initialized once so we cannot take register value at the + * beginning and reuse it further; hence we save its value to memory, upload a + * constant value with bit21 set and then we restore it back with the saved value. + * To simplify the WA, a constant value is formed by using the default value + * of this register. This shouldn't be a problem because we are only modifying + * it for a short period and this batch in non-premptible. We can ofcourse + * use additional instructions that read the actual value of the register + * at that time and set our bit of interest but it makes the WA complicated. + * + * This WA is also required for Gen9 so extracting as a function avoids + * code duplication. + */ +static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring, + uint32_t *const batch, + uint32_t index) +{ + uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); + + wa_ctx_emit(batch, (MI_STORE_REGISTER_MEM_GEN8(1) | + MI_SRM_LRM_GLOBAL_GTT)); + wa_ctx_emit(batch, GEN8_L3SQCREG4); + wa_ctx_emit(batch, ring->scratch.gtt_offset + 256); + wa_ctx_emit(batch, 0); + + wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); + wa_ctx_emit(batch, GEN8_L3SQCREG4); + wa_ctx_emit(batch, l3sqc4_flush); + + wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); + wa_ctx_emit(batch, (PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_DC_FLUSH_ENABLE)); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + + wa_ctx_emit(batch, (MI_LOAD_REGISTER_MEM_GEN8(1) | + MI_SRM_LRM_GLOBAL_GTT)); + wa_ctx_emit(batch, GEN8_L3SQCREG4); + wa_ctx_emit(batch, ring->scratch.gtt_offset + 256); + wa_ctx_emit(batch, 0); + + return index; +} + static inline uint32_t wa_ctx_start(struct i915_wa_ctx_bb *wa_ctx, uint32_t offset, uint32_t start_alignment) @@ -1152,25 +1202,9 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, /* WaFlushCoherentL3CacheLinesAtContextSwitch:bdw */ if (IS_BROADWELL(ring->dev)) { - struct drm_i915_private *dev_priv = to_i915(ring->dev); - uint32_t l3sqc4_flush = (I915_READ(GEN8_L3SQCREG4) | - GEN8_LQSC_FLUSH_COHERENT_LINES); - - wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); - wa_ctx_emit(batch, GEN8_L3SQCREG4); - wa_ctx_emit(batch, l3sqc4_flush); - - wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); - wa_ctx_emit(batch, (PIPE_CONTROL_CS_STALL | - PIPE_CONTROL_DC_FLUSH_ENABLE)); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - - wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); - wa_ctx_emit(batch, GEN8_L3SQCREG4); - wa_ctx_emit(batch, l3sqc4_flush & ~GEN8_LQSC_FLUSH_COHERENT_LINES); + index = gen8_emit_flush_coherentl3_wa(ring, batch, index); + if (index < 0) + return index; } /* WaClearSlmSpaceAtContextSwitch:bdw,chv */ -- cgit v1.3-6-gb490 From a647828afc7d7d352aeb076dbc03bd952b09b1e3 Mon Sep 17 00:00:00 2001 From: "Niu,Bing" Date: Sat, 4 Jul 2015 00:27:34 +0800 Subject: drm/i915: Also perform gpu reset under execlist mode. It is found that i915 will not reset gpu under execlist mode when unload module. that will lead to some issues when unload/load module with different submission mode. e.g. from execlist mode to ring buffer mode via loading/unloading i915. Because HW is not in a reset state and registers are not clean under such condition. Signed-off-by: Niu,Bing Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c8ee13f466c8..672c803a0a27 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5196,6 +5196,14 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) for_each_ring(ring, dev_priv, i) dev_priv->gt.cleanup_ring(ring); + + if (i915.enable_execlists) + /* + * Neither the BIOS, ourselves or any other kernel + * expects the system to be in execlists mode on startup, + * so we need to reset the GPU back to legacy mode. + */ + intel_gpu_reset(dev); } static void -- cgit v1.3-6-gb490 From 35ca0ee49d2973976f89f07eb842782a39d20a14 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 8 Jun 2015 10:33:16 +0200 Subject: dmaengine: at_xdmac: fix indentation Fix indentation. Signed-off-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index cf1213de7865..86d56058021c 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -624,12 +624,12 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags, void *context) { - struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); - struct at_xdmac_desc *first = NULL, *prev = NULL; - struct scatterlist *sg; - int i; - unsigned int xfer_size = 0; - unsigned long irqflags; + struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); + struct at_xdmac_desc *first = NULL, *prev = NULL; + struct scatterlist *sg; + int i; + unsigned int xfer_size = 0; + unsigned long irqflags; struct dma_async_tx_descriptor *ret = NULL; if (!sgl) -- cgit v1.3-6-gb490 From 87be28aaf1458445d5f648688c2eec0f13b8f3b9 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 25 Jun 2015 18:43:58 +0200 Subject: x86/asm/tsc: Replace rdtscll() with native_read_tsc() Now that the ->read_tsc() paravirt hook is gone, rdtscll() is just a wrapper around native_read_tsc(). Unwrap it. Signed-off-by: Andy Lutomirski Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Huang Rui Cc: John Stultz Cc: Len Brown Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Thomas Gleixner Cc: kvm ML Link: http://lkml.kernel.org/r/d2449ae62c1b1fb90195bcfb19ef4a35883a04dc.1434501121.git.luto@kernel.org Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/aslr.c | 2 +- arch/x86/include/asm/msr.h | 3 --- arch/x86/include/asm/tsc.h | 5 +---- arch/x86/kernel/apb_timer.c | 4 ++-- arch/x86/kernel/apic/apic.c | 8 ++++---- arch/x86/kernel/cpu/mcheck/mce.c | 4 ++-- arch/x86/kernel/espfix_64.c | 2 +- arch/x86/kernel/hpet.c | 4 ++-- arch/x86/kernel/trace_clock.c | 2 +- arch/x86/kernel/tsc.c | 4 ++-- arch/x86/kvm/vmx.c | 2 +- arch/x86/lib/delay.c | 2 +- drivers/thermal/intel_powerclamp.c | 4 ++-- tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c | 4 ++-- 14 files changed, 22 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c index d7b1f655b3ef..ea33236190b1 100644 --- a/arch/x86/boot/compressed/aslr.c +++ b/arch/x86/boot/compressed/aslr.c @@ -82,7 +82,7 @@ static unsigned long get_random_long(void) if (has_cpuflag(X86_FEATURE_TSC)) { debug_putstr(" RDTSC"); - rdtscll(raw); + raw = native_read_tsc(); random ^= raw; use_i8254 = false; diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index d1afac7df484..7273b74e0f99 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -192,9 +192,6 @@ do { \ #define rdtscl(low) \ ((low) = (u32)native_read_tsc()) -#define rdtscll(val) \ - ((val) = native_read_tsc()) - #define rdtscp(low, high, aux) \ do { \ unsigned long long _val = native_read_tscp(&(aux)); \ diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h index 3da1cc1218ac..b4883902948b 100644 --- a/arch/x86/include/asm/tsc.h +++ b/arch/x86/include/asm/tsc.h @@ -21,15 +21,12 @@ extern void disable_TSC(void); static inline cycles_t get_cycles(void) { - unsigned long long ret = 0; - #ifndef CONFIG_X86_TSC if (!cpu_has_tsc) return 0; #endif - rdtscll(ret); - return ret; + return native_read_tsc(); } extern void tsc_init(void); diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index 9fe111cc50f8..25efa534c4e4 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c @@ -263,7 +263,7 @@ static int apbt_clocksource_register(void) /* Verify whether apbt counter works */ t1 = dw_apb_clocksource_read(clocksource_apbt); - rdtscll(start); + start = native_read_tsc(); /* * We don't know the TSC frequency yet, but waiting for @@ -273,7 +273,7 @@ static int apbt_clocksource_register(void) */ do { rep_nop(); - rdtscll(now); + now = native_read_tsc(); } while ((now - start) < 200000UL); /* APBT is the only always on clocksource, it has to work! */ diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index dcb52850a28f..51af1ed1ae2e 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -457,7 +457,7 @@ static int lapic_next_deadline(unsigned long delta, { u64 tsc; - rdtscll(tsc); + tsc = native_read_tsc(); wrmsrl(MSR_IA32_TSC_DEADLINE, tsc + (((u64) delta) * TSC_DIVISOR)); return 0; } @@ -592,7 +592,7 @@ static void __init lapic_cal_handler(struct clock_event_device *dev) unsigned long pm = acpi_pm_read_early(); if (cpu_has_tsc) - rdtscll(tsc); + tsc = native_read_tsc(); switch (lapic_cal_loops++) { case 0: @@ -1209,7 +1209,7 @@ void setup_local_APIC(void) long long max_loops = cpu_khz ? cpu_khz : 1000000; if (cpu_has_tsc) - rdtscll(tsc); + tsc = native_read_tsc(); if (disable_apic) { disable_ioapic_support(); @@ -1293,7 +1293,7 @@ void setup_local_APIC(void) } if (queued) { if (cpu_has_tsc && cpu_khz) { - rdtscll(ntsc); + ntsc = native_read_tsc(); max_loops = (cpu_khz << 10) - (ntsc - tsc); } else max_loops--; diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index df919ff103c3..a5283d2d0094 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -125,7 +125,7 @@ void mce_setup(struct mce *m) { memset(m, 0, sizeof(struct mce)); m->cpu = m->extcpu = smp_processor_id(); - rdtscll(m->tsc); + m->tsc = native_read_tsc(); /* We hope get_seconds stays lockless */ m->time = get_seconds(); m->cpuvendor = boot_cpu_data.x86_vendor; @@ -1784,7 +1784,7 @@ static void collect_tscs(void *data) { unsigned long *cpu_tsc = (unsigned long *)data; - rdtscll(cpu_tsc[smp_processor_id()]); + cpu_tsc[smp_processor_id()] = native_read_tsc(); } static int mce_apei_read_done; diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c index f5d0730e7b08..334a2a9c034d 100644 --- a/arch/x86/kernel/espfix_64.c +++ b/arch/x86/kernel/espfix_64.c @@ -110,7 +110,7 @@ static void init_espfix_random(void) */ if (!arch_get_random_long(&rand)) { /* The constant is an arbitrary large prime */ - rdtscll(rand); + rand = native_read_tsc(); rand *= 0xc345c6b72fd16123UL; } diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 10757d0a3fcf..cc390fe69b71 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -735,7 +735,7 @@ static int hpet_clocksource_register(void) /* Verify whether hpet counter works */ t1 = hpet_readl(HPET_COUNTER); - rdtscll(start); + start = native_read_tsc(); /* * We don't know the TSC frequency yet, but waiting for @@ -745,7 +745,7 @@ static int hpet_clocksource_register(void) */ do { rep_nop(); - rdtscll(now); + now = native_read_tsc(); } while ((now - start) < 200000UL); if (t1 == hpet_readl(HPET_COUNTER)) { diff --git a/arch/x86/kernel/trace_clock.c b/arch/x86/kernel/trace_clock.c index 25b993729f9b..bd8f4d41bd56 100644 --- a/arch/x86/kernel/trace_clock.c +++ b/arch/x86/kernel/trace_clock.c @@ -15,7 +15,7 @@ u64 notrace trace_clock_x86_tsc(void) u64 ret; rdtsc_barrier(); - rdtscll(ret); + ret = native_read_tsc(); return ret; } diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index e7710cd7ba00..e66f5dcaeb63 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -248,7 +248,7 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) data = cyc2ns_write_begin(cpu); - rdtscll(tsc_now); + tsc_now = native_read_tsc(); ns_now = cycles_2_ns(tsc_now); /* @@ -290,7 +290,7 @@ u64 native_sched_clock(void) } /* read the Time Stamp Counter: */ - rdtscll(tsc_now); + tsc_now = native_read_tsc(); /* return the value in ns */ return cycles_2_ns(tsc_now); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index e856dd566f4c..4fa1ccad7beb 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2236,7 +2236,7 @@ static u64 guest_read_tsc(void) { u64 host_tsc, tsc_offset; - rdtscll(host_tsc); + host_tsc = native_read_tsc(); tsc_offset = vmcs_read64(TSC_OFFSET); return host_tsc + tsc_offset; } diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c index 39d6a3db0b96..9a52ad0c0758 100644 --- a/arch/x86/lib/delay.c +++ b/arch/x86/lib/delay.c @@ -100,7 +100,7 @@ void use_tsc_delay(void) int read_current_timer(unsigned long *timer_val) { if (delay_fn == delay_tsc) { - rdtscll(*timer_val); + *timer_val = native_read_tsc(); return 0; } return -1; diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index 5820e8513927..ab13448defcf 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -340,7 +340,7 @@ static bool powerclamp_adjust_controls(unsigned int target_ratio, /* check result for the last window */ msr_now = pkg_state_counter(); - rdtscll(tsc_now); + tsc_now = native_read_tsc(); /* calculate pkg cstate vs tsc ratio */ if (!msr_last || !tsc_last) @@ -482,7 +482,7 @@ static void poll_pkg_cstate(struct work_struct *dummy) u64 val64; msr_now = pkg_state_counter(); - rdtscll(tsc_now); + tsc_now = native_read_tsc(); jiffies_now = jiffies; /* calculate pkg cstate vs tsc ratio */ diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c index 5224ee5b392d..f02b0c0bff9b 100644 --- a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c +++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c @@ -81,11 +81,11 @@ static int __init cpufreq_test_tsc(void) printk(KERN_DEBUG "start--> \n"); then = read_pmtmr(); - rdtscll(then_tsc); + then_tsc = native_read_tsc(); for (i=0;i<20;i++) { mdelay(100); now = read_pmtmr(); - rdtscll(now_tsc); + now_tsc = native_read_tsc(); diff = (now - then) & 0xFFFFFF; diff_tsc = now_tsc - then_tsc; printk(KERN_DEBUG "t1: %08u t2: %08u diff_pmtmr: %08u diff_tsc: %016llu\n", then, now, diff, diff_tsc); -- cgit v1.3-6-gb490 From e18d1f8df176527332761ac29ee3097f8584c478 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 25 Jun 2015 18:44:02 +0200 Subject: x86/asm/tsc, drivers/net/hamradio/baycom_epp: Replace rdtscl() with native_read_tsc() This is only used if BAYCOM_DEBUG is defined. Signed-off-by: Andy Lutomirski Signed-off-by: Borislav Petkov Acked-by: Thomas Sailer Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Huang Rui Cc: John Stultz Cc: Len Brown Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Thomas Gleixner Cc: kvm ML Cc: linux-hams@vger.kernel.org Link: http://lkml.kernel.org/r/1195ce0c7f34169ff3006341b77806184a46b9bf.1434501121.git.luto@kernel.org Signed-off-by: Ingo Molnar --- drivers/net/hamradio/baycom_epp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 83c7cce0d172..44e5c3b5e0af 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -638,7 +638,7 @@ static int receive(struct net_device *dev, int cnt) #define GETTICK(x) \ ({ \ if (cpu_has_tsc) \ - rdtscl(x); \ + x = (unsigned int)native_read_tsc(); \ }) #else /* __i386__ */ #define GETTICK(x) -- cgit v1.3-6-gb490 From 3a2c16c8489d967de10b3b7f5cc0f7cab4337770 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 25 Jun 2015 18:44:03 +0200 Subject: x86/asm/tsc, staging/lirc_serial: Remove TSC-based timing It wasn't compiled in by default. I suspect that the driver was and still is broken, though -- it's calling udelay with a parameter that's derived from loops_per_jiffy. Signed-off-by: Andy Lutomirski Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Greg Kroah-Hartman Cc: H. Peter Anvin Cc: Huang Rui Cc: Jarod Wilson Cc: John Stultz Cc: Len Brown Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Thomas Gleixner Cc: devel@driverdev.osuosl.org Cc: kvm ML Link: http://lkml.kernel.org/r/c95df47c5405b494d19d20b2852a9378c9f661f3.1434501121.git.luto@kernel.org Signed-off-by: Ingo Molnar --- drivers/staging/media/lirc/lirc_serial.c | 63 ++------------------------------ 1 file changed, 4 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index dc7984455c3a..465796a686c4 100644 --- a/drivers/staging/media/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c @@ -327,9 +327,6 @@ static void safe_udelay(unsigned long usecs) * time */ -/* So send_pulse can quickly convert microseconds to clocks */ -static unsigned long conv_us_to_clocks; - static int init_timing_params(unsigned int new_duty_cycle, unsigned int new_freq) { @@ -344,7 +341,6 @@ static int init_timing_params(unsigned int new_duty_cycle, /* How many clocks in a microsecond?, avoiding long long divide */ work = loops_per_sec; work *= 4295; /* 4295 = 2^32 / 1e6 */ - conv_us_to_clocks = work >> 32; /* * Carrier period in clocks, approach good up to 32GHz clock, @@ -357,10 +353,9 @@ static int init_timing_params(unsigned int new_duty_cycle, pulse_width = period * duty_cycle / 100; space_width = period - pulse_width; dprintk("in init_timing_params, freq=%d, duty_cycle=%d, " - "clk/jiffy=%ld, pulse=%ld, space=%ld, " - "conv_us_to_clocks=%ld\n", + "clk/jiffy=%ld, pulse=%ld, space=%ld\n", freq, duty_cycle, __this_cpu_read(cpu_info.loops_per_jiffy), - pulse_width, space_width, conv_us_to_clocks); + pulse_width, space_width); return 0; } #else /* ! USE_RDTSC */ @@ -431,63 +426,14 @@ static long send_pulse_irdeo(unsigned long length) return ret; } -#ifdef USE_RDTSC -/* Version that uses Pentium rdtsc instruction to measure clocks */ - -/* - * This version does sub-microsecond timing using rdtsc instruction, - * and does away with the fudged LIRC_SERIAL_TRANSMITTER_LATENCY - * Implicitly i586 architecture... - Steve - */ - -static long send_pulse_homebrew_softcarrier(unsigned long length) -{ - int flag; - unsigned long target, start, now; - - /* Get going quick as we can */ - rdtscl(start); - on(); - /* Convert length from microseconds to clocks */ - length *= conv_us_to_clocks; - /* And loop till time is up - flipping at right intervals */ - now = start; - target = pulse_width; - flag = 1; - /* - * FIXME: This looks like a hard busy wait, without even an occasional, - * polite, cpu_relax() call. There's got to be a better way? - * - * The i2c code has the result of a lot of bit-banging work, I wonder if - * there's something there which could be helpful here. - */ - while ((now - start) < length) { - /* Delay till flip time */ - do { - rdtscl(now); - } while ((now - start) < target); - - /* flip */ - if (flag) { - rdtscl(now); - off(); - target += space_width; - } else { - rdtscl(now); on(); - target += pulse_width; - } - flag = !flag; - } - rdtscl(now); - return ((now - start) - length) / conv_us_to_clocks; -} -#else /* ! USE_RDTSC */ /* Version using udelay() */ /* * here we use fixed point arithmetic, with 8 * fractional bits. that gets us within 0.1% or so of the right average * frequency, albeit with some jitter in pulse length - Steve + * + * This should use ndelay instead. */ /* To match 8 fractional bits used for pulse/space length */ @@ -520,7 +466,6 @@ static long send_pulse_homebrew_softcarrier(unsigned long length) } return (actual-length) >> 8; } -#endif /* USE_RDTSC */ static long send_pulse_homebrew(unsigned long length) { -- cgit v1.3-6-gb490 From 016bfc449a88c833e949414a41748b359843dbb1 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 25 Jun 2015 18:44:04 +0200 Subject: x86/asm/tsc, input/joystick/analog: Switch from rdtscl() to native_read_tsc() This timing code is hideous, and this doesn't help. It gets rid of one of the last users of rdtscl(), though. Signed-off-by: Andy Lutomirski Signed-off-by: Borislav Petkov Acked-by: Dmitry Torokhov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Huang Rui Cc: John Stultz Cc: Len Brown Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Thomas Gleixner Cc: kvm ML Cc: linux-input@vger.kernel.org Link: http://lkml.kernel.org/r/90d19b3cea0e05ca6f333d1598daa38afb993260.1434501121.git.luto@kernel.org Signed-off-by: Ingo Molnar --- drivers/input/joystick/analog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 4284080e481d..f871b4f00056 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -143,7 +143,7 @@ struct analog_port { #include -#define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0) +#define GET_TIME(x) do { if (cpu_has_tsc) x = (unsigned int)native_read_tsc(); else x = get_time_pit(); } while (0) #define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? PIT_TICK_RATE / HZ : 0))) #define TIME_NAME (cpu_has_tsc?"TSC":"PIT") static unsigned int get_time_pit(void) @@ -160,7 +160,7 @@ static unsigned int get_time_pit(void) return count; } #elif defined(__x86_64__) -#define GET_TIME(x) rdtscl(x) +#define GET_TIME(x) do { x = (unsigned int)native_read_tsc(); } while (0) #define DELTA(x,y) ((y)-(x)) #define TIME_NAME "TSC" #elif defined(__alpha__) || defined(CONFIG_MN10300) || defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_TILE) -- cgit v1.3-6-gb490 From 732f374ba50b64150bf954c2d4e9f6fae583cccf Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 25 Jun 2015 18:44:05 +0200 Subject: x86/asm/tsc, drivers/input/gameport: Replace rdtscl() with native_read_tsc() It's unclear to me why this code exists in the first place. Signed-off-by: Andy Lutomirski Signed-off-by: Borislav Petkov Acked-by: Dmitry Torokhov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Huang Rui Cc: John Stultz Cc: Len Brown Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Thomas Gleixner Cc: kvm ML Cc: linux-input@vger.kernel.org Link: http://lkml.kernel.org/r/9e058e72f4cf1f13c6483c1360b39c3d188a2c2a.1434501121.git.luto@kernel.org Signed-off-by: Ingo Molnar --- drivers/input/gameport/gameport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index e853a2134680..abc0cb22e750 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -149,9 +149,9 @@ static int old_gameport_measure_speed(struct gameport *gameport) for(i = 0; i < 50; i++) { local_irq_save(flags); - rdtscl(t1); + t1 = native_read_tsc(); for (t = 0; t < 50; t++) gameport_read(gameport); - rdtscl(t2); + t2 = native_read_tsc(); local_irq_restore(flags); udelay(i * 10); if (t2 - t1 < tx) tx = t2 - t1; -- cgit v1.3-6-gb490 From 4ea1636b04dbd66536fa387bae2eea463efc705b Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 25 Jun 2015 18:44:07 +0200 Subject: x86/asm/tsc: Rename native_read_tsc() to rdtsc() Now that there is no paravirt TSC, the "native" is inappropriate. The function does RDTSC, so give it the obvious name: rdtsc(). Suggested-by: Borislav Petkov Signed-off-by: Andy Lutomirski Signed-off-by: Borislav Petkov Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Huang Rui Cc: John Stultz Cc: Len Brown Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ralf Baechle Cc: Thomas Gleixner Cc: kvm ML Link: http://lkml.kernel.org/r/fd43e16281991f096c1e4d21574d9e1402c62d39.1434501121.git.luto@kernel.org [ Ported it to v4.2-rc1. ] Signed-off-by: Ingo Molnar --- arch/x86/boot/compressed/aslr.c | 2 +- arch/x86/entry/vdso/vclock_gettime.c | 2 +- arch/x86/include/asm/msr.h | 11 ++++++++++- arch/x86/include/asm/pvclock.h | 2 +- arch/x86/include/asm/stackprotector.h | 2 +- arch/x86/include/asm/tsc.h | 2 +- arch/x86/kernel/apb_timer.c | 8 ++++---- arch/x86/kernel/apic/apic.c | 8 ++++---- arch/x86/kernel/cpu/amd.c | 4 ++-- arch/x86/kernel/cpu/mcheck/mce.c | 4 ++-- arch/x86/kernel/espfix_64.c | 2 +- arch/x86/kernel/hpet.c | 4 ++-- arch/x86/kernel/trace_clock.c | 2 +- arch/x86/kernel/tsc.c | 4 ++-- arch/x86/kvm/lapic.c | 4 ++-- arch/x86/kvm/svm.c | 4 ++-- arch/x86/kvm/vmx.c | 4 ++-- arch/x86/kvm/x86.c | 12 ++++++------ arch/x86/lib/delay.c | 8 ++++---- drivers/cpufreq/intel_pstate.c | 2 +- drivers/input/gameport/gameport.c | 4 ++-- drivers/input/joystick/analog.c | 4 ++-- drivers/net/hamradio/baycom_epp.c | 2 +- drivers/thermal/intel_powerclamp.c | 4 ++-- tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c | 4 ++-- 25 files changed, 59 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c index ea33236190b1..6a9b96b4624d 100644 --- a/arch/x86/boot/compressed/aslr.c +++ b/arch/x86/boot/compressed/aslr.c @@ -82,7 +82,7 @@ static unsigned long get_random_long(void) if (has_cpuflag(X86_FEATURE_TSC)) { debug_putstr(" RDTSC"); - raw = native_read_tsc(); + raw = rdtsc(); random ^= raw; use_i8254 = false; diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c index 972b488ac16a..0340d93c18ca 100644 --- a/arch/x86/entry/vdso/vclock_gettime.c +++ b/arch/x86/entry/vdso/vclock_gettime.c @@ -186,7 +186,7 @@ notrace static cycle_t vread_tsc(void) * but no one has ever seen it happen. */ rdtsc_barrier(); - ret = (cycle_t)native_read_tsc(); + ret = (cycle_t)rdtsc(); last = gtod->cycle_last; diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index c89ed6ceed02..ff0c120dafe5 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -109,7 +109,16 @@ notrace static inline int native_write_msr_safe(unsigned int msr, extern int rdmsr_safe_regs(u32 regs[8]); extern int wrmsr_safe_regs(u32 regs[8]); -static __always_inline unsigned long long native_read_tsc(void) +/** + * rdtsc() - returns the current TSC without ordering constraints + * + * rdtsc() returns the result of RDTSC as a 64-bit integer. The + * only ordering constraint it supplies is the ordering implied by + * "asm volatile": it will put the RDTSC in the place you expect. The + * CPU can and will speculatively execute that RDTSC, though, so the + * results can be non-monotonic if compared on different CPUs. + */ +static __always_inline unsigned long long rdtsc(void) { DECLARE_ARGS(val, low, high); diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h index 2bd69d62c623..5c490db62e32 100644 --- a/arch/x86/include/asm/pvclock.h +++ b/arch/x86/include/asm/pvclock.h @@ -62,7 +62,7 @@ static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift) static __always_inline u64 pvclock_get_nsec_offset(const struct pvclock_vcpu_time_info *src) { - u64 delta = native_read_tsc() - src->tsc_timestamp; + u64 delta = rdtsc() - src->tsc_timestamp; return pvclock_scale_delta(delta, src->tsc_to_system_mul, src->tsc_shift); } diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h index bc5fa2af112e..58505f01962f 100644 --- a/arch/x86/include/asm/stackprotector.h +++ b/arch/x86/include/asm/stackprotector.h @@ -72,7 +72,7 @@ static __always_inline void boot_init_stack_canary(void) * on during the bootup the random pool has true entropy too. */ get_random_bytes(&canary, sizeof(canary)); - tsc = native_read_tsc(); + tsc = rdtsc(); canary += tsc + (tsc << 32UL); current->stack_canary = canary; diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h index b4883902948b..3df7675debcf 100644 --- a/arch/x86/include/asm/tsc.h +++ b/arch/x86/include/asm/tsc.h @@ -26,7 +26,7 @@ static inline cycles_t get_cycles(void) return 0; #endif - return native_read_tsc(); + return rdtsc(); } extern void tsc_init(void); diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index 25efa534c4e4..222a57076039 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c @@ -263,7 +263,7 @@ static int apbt_clocksource_register(void) /* Verify whether apbt counter works */ t1 = dw_apb_clocksource_read(clocksource_apbt); - start = native_read_tsc(); + start = rdtsc(); /* * We don't know the TSC frequency yet, but waiting for @@ -273,7 +273,7 @@ static int apbt_clocksource_register(void) */ do { rep_nop(); - now = native_read_tsc(); + now = rdtsc(); } while ((now - start) < 200000UL); /* APBT is the only always on clocksource, it has to work! */ @@ -390,13 +390,13 @@ unsigned long apbt_quick_calibrate(void) old = dw_apb_clocksource_read(clocksource_apbt); old += loop; - t1 = native_read_tsc(); + t1 = rdtsc(); do { new = dw_apb_clocksource_read(clocksource_apbt); } while (new < old); - t2 = native_read_tsc(); + t2 = rdtsc(); shift = 5; if (unlikely(loop >> shift == 0)) { diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 51af1ed1ae2e..0d71cd9b4a50 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -457,7 +457,7 @@ static int lapic_next_deadline(unsigned long delta, { u64 tsc; - tsc = native_read_tsc(); + tsc = rdtsc(); wrmsrl(MSR_IA32_TSC_DEADLINE, tsc + (((u64) delta) * TSC_DIVISOR)); return 0; } @@ -592,7 +592,7 @@ static void __init lapic_cal_handler(struct clock_event_device *dev) unsigned long pm = acpi_pm_read_early(); if (cpu_has_tsc) - tsc = native_read_tsc(); + tsc = rdtsc(); switch (lapic_cal_loops++) { case 0: @@ -1209,7 +1209,7 @@ void setup_local_APIC(void) long long max_loops = cpu_khz ? cpu_khz : 1000000; if (cpu_has_tsc) - tsc = native_read_tsc(); + tsc = rdtsc(); if (disable_apic) { disable_ioapic_support(); @@ -1293,7 +1293,7 @@ void setup_local_APIC(void) } if (queued) { if (cpu_has_tsc && cpu_khz) { - ntsc = native_read_tsc(); + ntsc = rdtsc(); max_loops = (cpu_khz << 10) - (ntsc - tsc); } else max_loops--; diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index a69710db6112..51ad2af84a72 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -125,10 +125,10 @@ static void init_amd_k6(struct cpuinfo_x86 *c) n = K6_BUG_LOOP; f_vide = vide; - d = native_read_tsc(); + d = rdtsc(); while (n--) f_vide(); - d2 = native_read_tsc(); + d2 = rdtsc(); d = d2-d; if (d > 20*K6_BUG_LOOP) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index a5283d2d0094..96cceccd11b4 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -125,7 +125,7 @@ void mce_setup(struct mce *m) { memset(m, 0, sizeof(struct mce)); m->cpu = m->extcpu = smp_processor_id(); - m->tsc = native_read_tsc(); + m->tsc = rdtsc(); /* We hope get_seconds stays lockless */ m->time = get_seconds(); m->cpuvendor = boot_cpu_data.x86_vendor; @@ -1784,7 +1784,7 @@ static void collect_tscs(void *data) { unsigned long *cpu_tsc = (unsigned long *)data; - cpu_tsc[smp_processor_id()] = native_read_tsc(); + cpu_tsc[smp_processor_id()] = rdtsc(); } static int mce_apei_read_done; diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c index 334a2a9c034d..67315cd0132c 100644 --- a/arch/x86/kernel/espfix_64.c +++ b/arch/x86/kernel/espfix_64.c @@ -110,7 +110,7 @@ static void init_espfix_random(void) */ if (!arch_get_random_long(&rand)) { /* The constant is an arbitrary large prime */ - rand = native_read_tsc(); + rand = rdtsc(); rand *= 0xc345c6b72fd16123UL; } diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index cc390fe69b71..f75c5908c7a6 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -735,7 +735,7 @@ static int hpet_clocksource_register(void) /* Verify whether hpet counter works */ t1 = hpet_readl(HPET_COUNTER); - start = native_read_tsc(); + start = rdtsc(); /* * We don't know the TSC frequency yet, but waiting for @@ -745,7 +745,7 @@ static int hpet_clocksource_register(void) */ do { rep_nop(); - now = native_read_tsc(); + now = rdtsc(); } while ((now - start) < 200000UL); if (t1 == hpet_readl(HPET_COUNTER)) { diff --git a/arch/x86/kernel/trace_clock.c b/arch/x86/kernel/trace_clock.c index bd8f4d41bd56..67efb8c96fc4 100644 --- a/arch/x86/kernel/trace_clock.c +++ b/arch/x86/kernel/trace_clock.c @@ -15,7 +15,7 @@ u64 notrace trace_clock_x86_tsc(void) u64 ret; rdtsc_barrier(); - ret = native_read_tsc(); + ret = rdtsc(); return ret; } diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index e66f5dcaeb63..21d6e04e3e82 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -248,7 +248,7 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) data = cyc2ns_write_begin(cpu); - tsc_now = native_read_tsc(); + tsc_now = rdtsc(); ns_now = cycles_2_ns(tsc_now); /* @@ -290,7 +290,7 @@ u64 native_sched_clock(void) } /* read the Time Stamp Counter: */ - tsc_now = native_read_tsc(); + tsc_now = rdtsc(); /* return the value in ns */ return cycles_2_ns(tsc_now); diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 954e98a8c2e3..2f0ade48614f 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1172,7 +1172,7 @@ void wait_lapic_expire(struct kvm_vcpu *vcpu) tsc_deadline = apic->lapic_timer.expired_tscdeadline; apic->lapic_timer.expired_tscdeadline = 0; - guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu, native_read_tsc()); + guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu, rdtsc()); trace_kvm_wait_lapic_expire(vcpu->vcpu_id, guest_tsc - tsc_deadline); /* __delay is delay_tsc whenever the hardware has TSC, thus always. */ @@ -1240,7 +1240,7 @@ static void start_apic_timer(struct kvm_lapic *apic) local_irq_save(flags); now = apic->lapic_timer.timer.base->get_time(); - guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu, native_read_tsc()); + guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu, rdtsc()); if (likely(tscdeadline > guest_tsc)) { ns = (tscdeadline - guest_tsc) * 1000000ULL; do_div(ns, this_tsc_khz); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 602b974a60a6..8dfbad7a2c44 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1080,7 +1080,7 @@ static u64 svm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc) { u64 tsc; - tsc = svm_scale_tsc(vcpu, native_read_tsc()); + tsc = svm_scale_tsc(vcpu, rdtsc()); return target_tsc - tsc; } @@ -3079,7 +3079,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) switch (msr_info->index) { case MSR_IA32_TSC: { msr_info->data = svm->vmcb->control.tsc_offset + - svm_scale_tsc(vcpu, native_read_tsc()); + svm_scale_tsc(vcpu, rdtsc()); break; } diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 4fa1ccad7beb..10d69a6df14f 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2236,7 +2236,7 @@ static u64 guest_read_tsc(void) { u64 host_tsc, tsc_offset; - host_tsc = native_read_tsc(); + host_tsc = rdtsc(); tsc_offset = vmcs_read64(TSC_OFFSET); return host_tsc + tsc_offset; } @@ -2317,7 +2317,7 @@ static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool ho static u64 vmx_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc) { - return target_tsc - native_read_tsc(); + return target_tsc - rdtsc(); } static bool guest_cpuid_has_vmx(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f771058cfb5c..dfa97139282d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1455,7 +1455,7 @@ static cycle_t read_tsc(void) * but no one has ever seen it happen. */ rdtsc_barrier(); - ret = (cycle_t)native_read_tsc(); + ret = (cycle_t)rdtsc(); last = pvclock_gtod_data.clock.cycle_last; @@ -1646,7 +1646,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) return 1; } if (!use_master_clock) { - host_tsc = native_read_tsc(); + host_tsc = rdtsc(); kernel_ns = get_kernel_ns(); } @@ -2810,7 +2810,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (unlikely(vcpu->cpu != cpu) || check_tsc_unstable()) { s64 tsc_delta = !vcpu->arch.last_host_tsc ? 0 : - native_read_tsc() - vcpu->arch.last_host_tsc; + rdtsc() - vcpu->arch.last_host_tsc; if (tsc_delta < 0) mark_tsc_unstable("KVM discovered backwards TSC"); if (check_tsc_unstable()) { @@ -2838,7 +2838,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) { kvm_x86_ops->vcpu_put(vcpu); kvm_put_guest_fpu(vcpu); - vcpu->arch.last_host_tsc = native_read_tsc(); + vcpu->arch.last_host_tsc = rdtsc(); } static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, @@ -6623,7 +6623,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) hw_breakpoint_restore(); vcpu->arch.last_guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu, - native_read_tsc()); + rdtsc()); vcpu->mode = OUTSIDE_GUEST_MODE; smp_wmb(); @@ -7437,7 +7437,7 @@ int kvm_arch_hardware_enable(void) if (ret != 0) return ret; - local_tsc = native_read_tsc(); + local_tsc = rdtsc(); stable = !check_tsc_unstable(); list_for_each_entry(kvm, &vm_list, vm_list) { kvm_for_each_vcpu(i, vcpu, kvm) { diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c index 35115f3786a9..f24bc59ab0a0 100644 --- a/arch/x86/lib/delay.c +++ b/arch/x86/lib/delay.c @@ -55,10 +55,10 @@ static void delay_tsc(unsigned long __loops) preempt_disable(); cpu = smp_processor_id(); rdtsc_barrier(); - bclock = native_read_tsc(); + bclock = rdtsc(); for (;;) { rdtsc_barrier(); - now = native_read_tsc(); + now = rdtsc(); if ((now - bclock) >= loops) break; @@ -80,7 +80,7 @@ static void delay_tsc(unsigned long __loops) loops -= (now - bclock); cpu = smp_processor_id(); rdtsc_barrier(); - bclock = native_read_tsc(); + bclock = rdtsc(); } } preempt_enable(); @@ -100,7 +100,7 @@ void use_tsc_delay(void) int read_current_timer(unsigned long *timer_val) { if (delay_fn == delay_tsc) { - *timer_val = native_read_tsc(); + *timer_val = rdtsc(); return 0; } return -1; diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 15ada47bb720..7c56d7eaa671 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -765,7 +765,7 @@ static inline void intel_pstate_sample(struct cpudata *cpu) local_irq_save(flags); rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_MPERF, mperf); - tsc = native_read_tsc(); + tsc = rdtsc(); local_irq_restore(flags); cpu->last_sample_time = cpu->sample.time; diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index abc0cb22e750..4a2a9e370be7 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -149,9 +149,9 @@ static int old_gameport_measure_speed(struct gameport *gameport) for(i = 0; i < 50; i++) { local_irq_save(flags); - t1 = native_read_tsc(); + t1 = rdtsc(); for (t = 0; t < 50; t++) gameport_read(gameport); - t2 = native_read_tsc(); + t2 = rdtsc(); local_irq_restore(flags); udelay(i * 10); if (t2 - t1 < tx) tx = t2 - t1; diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index f871b4f00056..6f8b084e13d0 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -143,7 +143,7 @@ struct analog_port { #include -#define GET_TIME(x) do { if (cpu_has_tsc) x = (unsigned int)native_read_tsc(); else x = get_time_pit(); } while (0) +#define GET_TIME(x) do { if (cpu_has_tsc) x = (unsigned int)rdtsc(); else x = get_time_pit(); } while (0) #define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? PIT_TICK_RATE / HZ : 0))) #define TIME_NAME (cpu_has_tsc?"TSC":"PIT") static unsigned int get_time_pit(void) @@ -160,7 +160,7 @@ static unsigned int get_time_pit(void) return count; } #elif defined(__x86_64__) -#define GET_TIME(x) do { x = (unsigned int)native_read_tsc(); } while (0) +#define GET_TIME(x) do { x = (unsigned int)rdtsc(); } while (0) #define DELTA(x,y) ((y)-(x)) #define TIME_NAME "TSC" #elif defined(__alpha__) || defined(CONFIG_MN10300) || defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_TILE) diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 44e5c3b5e0af..72c9f1f352b4 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -638,7 +638,7 @@ static int receive(struct net_device *dev, int cnt) #define GETTICK(x) \ ({ \ if (cpu_has_tsc) \ - x = (unsigned int)native_read_tsc(); \ + x = (unsigned int)rdtsc(); \ }) #else /* __i386__ */ #define GETTICK(x) diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index ab13448defcf..2ac0c704bcb8 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -340,7 +340,7 @@ static bool powerclamp_adjust_controls(unsigned int target_ratio, /* check result for the last window */ msr_now = pkg_state_counter(); - tsc_now = native_read_tsc(); + tsc_now = rdtsc(); /* calculate pkg cstate vs tsc ratio */ if (!msr_last || !tsc_last) @@ -482,7 +482,7 @@ static void poll_pkg_cstate(struct work_struct *dummy) u64 val64; msr_now = pkg_state_counter(); - tsc_now = native_read_tsc(); + tsc_now = rdtsc(); jiffies_now = jiffies; /* calculate pkg cstate vs tsc ratio */ diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c index f02b0c0bff9b..6ff8383f2941 100644 --- a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c +++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c @@ -81,11 +81,11 @@ static int __init cpufreq_test_tsc(void) printk(KERN_DEBUG "start--> \n"); then = read_pmtmr(); - then_tsc = native_read_tsc(); + then_tsc = rdtsc(); for (i=0;i<20;i++) { mdelay(100); now = read_pmtmr(); - now_tsc = native_read_tsc(); + now_tsc = rdtsc(); diff = (now - then) & 0xFFFFFF; diff_tsc = now_tsc - then_tsc; printk(KERN_DEBUG "t1: %08u t2: %08u diff_pmtmr: %08u diff_tsc: %016llu\n", then, now, diff, diff_tsc); -- cgit v1.3-6-gb490 From d264b48687fab995fe970451ed11f4259d68aee1 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 26 Jun 2015 13:17:42 +0300 Subject: dmaengine: Remove remaining FSF mailing addresses Commit 3b62286d0ef7 ("dmaengine: Remove FSF mailing addresses") left Free Software Foundation mailing address still in two files. Remove it now. Signed-off-by: Jarkko Nikula Signed-off-by: Vinod Koul --- drivers/dma/pch_dma.c | 4 ---- drivers/dma/timb_dma.c | 4 ---- 2 files changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index b859792dde95..113605f6fe20 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -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. */ #include diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index c4c3d93fdd1b..559cd4073698 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -10,10 +10,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: -- cgit v1.3-6-gb490 From d8cb8875ac60e2832614a2c48af236b5899cf209 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 3 Jul 2015 17:09:32 +0300 Subject: drm/i915: Convert execlist_submit_contexts() for requests Pass around requests to carry context deeper in callchain. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a499f16db194..7282466ee567 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -358,29 +358,29 @@ static int execlists_update_context(struct drm_i915_gem_object *ctx_obj, return 0; } -static void execlists_submit_contexts(struct intel_engine_cs *ring, - struct intel_context *to0, u32 tail0, - struct intel_context *to1, u32 tail1) +static void execlists_submit_requests(struct drm_i915_gem_request *rq0, + struct drm_i915_gem_request *rq1) { - struct drm_i915_gem_object *ctx_obj0 = to0->engine[ring->id].state; - struct intel_ringbuffer *ringbuf0 = to0->engine[ring->id].ringbuf; + struct intel_engine_cs *ring = rq0->ring; + struct drm_i915_gem_object *ctx_obj0 = rq0->ctx->engine[ring->id].state; struct drm_i915_gem_object *ctx_obj1 = NULL; - struct intel_ringbuffer *ringbuf1 = NULL; BUG_ON(!ctx_obj0); WARN_ON(!i915_gem_obj_is_pinned(ctx_obj0)); - WARN_ON(!i915_gem_obj_is_pinned(ringbuf0->obj)); + WARN_ON(!i915_gem_obj_is_pinned(rq0->ringbuf->obj)); - execlists_update_context(ctx_obj0, ringbuf0->obj, to0->ppgtt, tail0); + execlists_update_context(ctx_obj1, rq0->ringbuf->obj, + rq0->ctx->ppgtt, rq0->tail); + + if (rq1) { + ctx_obj1 = rq1->ctx->engine[ring->id].state; - if (to1) { - ringbuf1 = to1->engine[ring->id].ringbuf; - ctx_obj1 = to1->engine[ring->id].state; BUG_ON(!ctx_obj1); WARN_ON(!i915_gem_obj_is_pinned(ctx_obj1)); - WARN_ON(!i915_gem_obj_is_pinned(ringbuf1->obj)); + WARN_ON(!i915_gem_obj_is_pinned(rq1->ringbuf->obj)); - execlists_update_context(ctx_obj1, ringbuf1->obj, to1->ppgtt, tail1); + execlists_update_context(ctx_obj1, rq1->ringbuf->obj, + rq1->ctx->ppgtt, rq1->tail); } execlists_elsp_write(ring, ctx_obj0, ctx_obj1); @@ -443,9 +443,7 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring) WARN_ON(req1 && req1->elsp_submitted); - execlists_submit_contexts(ring, req0->ctx, req0->tail, - req1 ? req1->ctx : NULL, - req1 ? req1->tail : 0); + execlists_submit_requests(req0, req1); req0->elsp_submitted++; if (req1) -- cgit v1.3-6-gb490 From 05d9824bfb40e211c8804fee65af1fbb736925a2 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 3 Jul 2015 17:09:33 +0300 Subject: drm/i915: Convert execlists_update_context() for requests Pass around requests to carry context deeper in callchain. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7282466ee567..8e1619a06f3b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -329,19 +329,24 @@ static void execlists_elsp_write(struct intel_engine_cs *ring, spin_unlock(&dev_priv->uncore.lock); } -static int execlists_update_context(struct drm_i915_gem_object *ctx_obj, - struct drm_i915_gem_object *ring_obj, - struct i915_hw_ppgtt *ppgtt, - u32 tail) +static int execlists_update_context(struct drm_i915_gem_request *rq) { + struct intel_engine_cs *ring = rq->ring; + struct i915_hw_ppgtt *ppgtt = rq->ctx->ppgtt; + struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state; + struct drm_i915_gem_object *rb_obj = rq->ringbuf->obj; struct page *page; uint32_t *reg_state; + BUG_ON(!ctx_obj); + WARN_ON(!i915_gem_obj_is_pinned(ctx_obj)); + WARN_ON(!i915_gem_obj_is_pinned(rb_obj)); + page = i915_gem_object_get_page(ctx_obj, 1); reg_state = kmap_atomic(page); - reg_state[CTX_RING_TAIL+1] = tail; - reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(ring_obj); + reg_state[CTX_RING_TAIL+1] = rq->tail; + reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(rb_obj); /* True PPGTT with dynamic page allocation: update PDP registers and * point the unallocated PDPs to the scratch page @@ -365,22 +370,11 @@ static void execlists_submit_requests(struct drm_i915_gem_request *rq0, struct drm_i915_gem_object *ctx_obj0 = rq0->ctx->engine[ring->id].state; struct drm_i915_gem_object *ctx_obj1 = NULL; - BUG_ON(!ctx_obj0); - WARN_ON(!i915_gem_obj_is_pinned(ctx_obj0)); - WARN_ON(!i915_gem_obj_is_pinned(rq0->ringbuf->obj)); - - execlists_update_context(ctx_obj1, rq0->ringbuf->obj, - rq0->ctx->ppgtt, rq0->tail); + execlists_update_context(rq0); if (rq1) { + execlists_update_context(rq1); ctx_obj1 = rq1->ctx->engine[ring->id].state; - - BUG_ON(!ctx_obj1); - WARN_ON(!i915_gem_obj_is_pinned(ctx_obj1)); - WARN_ON(!i915_gem_obj_is_pinned(rq1->ringbuf->obj)); - - execlists_update_context(ctx_obj1, rq1->ringbuf->obj, - rq1->ctx->ppgtt, rq1->tail); } execlists_elsp_write(ring, ctx_obj0, ctx_obj1); -- cgit v1.3-6-gb490 From f3cc01f0948c1deb12cfb1da2959f391229c9d4b Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Mon, 6 Jul 2015 11:08:30 +0300 Subject: drm/i915: Assign request ringbuf before pin In preparation to make intel_lr_context_pin|unpin to accept requests, assign ringbuf into request before we call the pinning. v2: No need to unset ringbuf on error path (Chris) Cc: Chris Wilson Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8e1619a06f3b..fd285d32f62a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -633,14 +633,14 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request { int ret; + request->ringbuf = request->ctx->engine[request->ring->id].ringbuf; + if (request->ctx != request->ring->default_context) { ret = intel_lr_context_pin(request->ring, request->ctx); if (ret) return ret; } - request->ringbuf = request->ctx->engine[request->ring->id].ringbuf; - return 0; } -- cgit v1.3-6-gb490 From 8ba319da898fcecdac158cb46ca69e38b2b08da3 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 3 Jul 2015 17:09:35 +0300 Subject: drm/i915: Convert intel_lr_context_pin() for requests Pass around requests to carry context deeper in callchain. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 8 +++----- drivers/gpu/drm/i915/intel_lrc.c | 31 +++++++++++++++---------------- drivers/gpu/drm/i915/intel_lrc.h | 3 +-- 3 files changed, 19 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 672c803a0a27..82c05b80b7ef 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2620,10 +2620,8 @@ void i915_gem_request_free(struct kref *req_ref) if (ctx) { if (i915.enable_execlists) { - struct intel_engine_cs *ring = req->ring; - - if (ctx != ring->default_context) - intel_lr_context_unpin(ring, ctx); + if (ctx != req->ring->default_context) + intel_lr_context_unpin(req); } i915_gem_context_unreference(ctx); @@ -2765,7 +2763,7 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, list_del(&submit_req->execlist_link); if (submit_req->ctx != ring->default_context) - intel_lr_context_unpin(ring, submit_req->ctx); + intel_lr_context_unpin(submit_req); i915_gem_request_unreference(submit_req); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index fd285d32f62a..5ae68215e6fb 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -211,8 +211,7 @@ enum { #define GEN8_CTX_ID_SHIFT 32 #define CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x17 -static int intel_lr_context_pin(struct intel_engine_cs *ring, - struct intel_context *ctx); +static int intel_lr_context_pin(struct drm_i915_gem_request *rq); /** * intel_sanitize_enable_execlists() - sanitize i915.enable_execlists @@ -541,7 +540,7 @@ static int execlists_context_queue(struct drm_i915_gem_request *request) int num_elements = 0; if (request->ctx != ring->default_context) - intel_lr_context_pin(ring, request->ctx); + intel_lr_context_pin(request); i915_gem_request_reference(request); @@ -636,7 +635,7 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request request->ringbuf = request->ctx->engine[request->ring->id].ringbuf; if (request->ctx != request->ring->default_context) { - ret = intel_lr_context_pin(request->ring, request->ctx); + ret = intel_lr_context_pin(request); if (ret) return ret; } @@ -950,7 +949,7 @@ void intel_execlists_retire_requests(struct intel_engine_cs *ring) ctx->engine[ring->id].state; if (ctx_obj && (ctx != ring->default_context)) - intel_lr_context_unpin(ring, ctx); + intel_lr_context_unpin(req); list_del(&req->execlist_link); i915_gem_request_unreference(req); } @@ -994,15 +993,15 @@ int logical_ring_flush_all_caches(struct drm_i915_gem_request *req) return 0; } -static int intel_lr_context_pin(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int intel_lr_context_pin(struct drm_i915_gem_request *rq) { - struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state; - struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; + struct intel_engine_cs *ring = rq->ring; + struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state; + struct intel_ringbuffer *ringbuf = rq->ringbuf; int ret = 0; WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex)); - if (ctx->engine[ring->id].pin_count++ == 0) { + if (rq->ctx->engine[ring->id].pin_count++ == 0) { ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 0); if (ret) @@ -1018,20 +1017,20 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring, unpin_ctx_obj: i915_gem_object_ggtt_unpin(ctx_obj); reset_pin_count: - ctx->engine[ring->id].pin_count = 0; + rq->ctx->engine[ring->id].pin_count = 0; return ret; } -void intel_lr_context_unpin(struct intel_engine_cs *ring, - struct intel_context *ctx) +void intel_lr_context_unpin(struct drm_i915_gem_request *rq) { - struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state; - struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; + struct intel_engine_cs *ring = rq->ring; + struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state; + struct intel_ringbuffer *ringbuf = rq->ringbuf; if (ctx_obj) { WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex)); - if (--ctx->engine[ring->id].pin_count == 0) { + if (--rq->ctx->engine[ring->id].pin_count == 0) { intel_unpin_ringbuffer_obj(ringbuf); i915_gem_object_ggtt_unpin(ctx_obj); } diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index d3dd3ac33aef..e0299fbb1728 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -70,8 +70,7 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf, void intel_lr_context_free(struct intel_context *ctx); int intel_lr_context_deferred_create(struct intel_context *ctx, struct intel_engine_cs *ring); -void intel_lr_context_unpin(struct intel_engine_cs *ring, - struct intel_context *ctx); +void intel_lr_context_unpin(struct drm_i915_gem_request *req); void intel_lr_context_reset(struct drm_device *dev, struct intel_context *ctx); -- cgit v1.3-6-gb490 From cc3c42532c312c60f8499e22bbdb895ed5ce1d73 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 3 Jul 2015 17:09:36 +0300 Subject: drm/i915: Convert execlists_elsp_writ() for requests Pass around requests to carry context deeper in callchain. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 5ae68215e6fb..a07284adc317 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -292,12 +292,16 @@ static uint64_t execlists_ctx_descriptor(struct intel_engine_cs *ring, return desc; } -static void execlists_elsp_write(struct intel_engine_cs *ring, - struct drm_i915_gem_object *ctx_obj0, - struct drm_i915_gem_object *ctx_obj1) +static void execlists_elsp_write(struct drm_i915_gem_request *rq0, + struct drm_i915_gem_request *rq1) { + + struct intel_engine_cs *ring = rq0->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *ctx_obj0 = rq0->ctx->engine[ring->id].state; + struct drm_i915_gem_object *ctx_obj1 = rq1 ? + rq1->ctx->engine[ring->id].state : NULL; uint64_t temp = 0; uint32_t desc[4]; @@ -365,18 +369,12 @@ static int execlists_update_context(struct drm_i915_gem_request *rq) static void execlists_submit_requests(struct drm_i915_gem_request *rq0, struct drm_i915_gem_request *rq1) { - struct intel_engine_cs *ring = rq0->ring; - struct drm_i915_gem_object *ctx_obj0 = rq0->ctx->engine[ring->id].state; - struct drm_i915_gem_object *ctx_obj1 = NULL; - execlists_update_context(rq0); - if (rq1) { + if (rq1) execlists_update_context(rq1); - ctx_obj1 = rq1->ctx->engine[ring->id].state; - } - execlists_elsp_write(ring, ctx_obj0, ctx_obj1); + execlists_elsp_write(rq0, rq1); } static void execlists_context_unqueue(struct intel_engine_cs *ring) -- cgit v1.3-6-gb490 From 8ee36152cfb087af22680ee394dcde262565fd73 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 3 Jul 2015 17:09:37 +0300 Subject: drm/i915: Convert execlists_ctx_descriptor() for requests Pass around requests to carry context deeper in callchain. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a07284adc317..2c39ce0458b2 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -261,10 +261,11 @@ u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj) return lrca >> 12; } -static uint64_t execlists_ctx_descriptor(struct intel_engine_cs *ring, - struct drm_i915_gem_object *ctx_obj) +static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_request *rq) { + struct intel_engine_cs *ring = rq->ring; struct drm_device *dev = ring->dev; + struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state; uint64_t desc; uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj); @@ -299,21 +300,18 @@ static void execlists_elsp_write(struct drm_i915_gem_request *rq0, struct intel_engine_cs *ring = rq0->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *ctx_obj0 = rq0->ctx->engine[ring->id].state; - struct drm_i915_gem_object *ctx_obj1 = rq1 ? - rq1->ctx->engine[ring->id].state : NULL; uint64_t temp = 0; uint32_t desc[4]; /* XXX: You must always write both descriptors in the order below. */ - if (ctx_obj1) - temp = execlists_ctx_descriptor(ring, ctx_obj1); + if (rq1) + temp = execlists_ctx_descriptor(rq1); else temp = 0; desc[1] = (u32)(temp >> 32); desc[0] = (u32)temp; - temp = execlists_ctx_descriptor(ring, ctx_obj0); + temp = execlists_ctx_descriptor(rq0); desc[3] = (u32)(temp >> 32); desc[2] = (u32)temp; -- cgit v1.3-6-gb490 From 1cff8cc35bd310419cd2545ddcb65b329bdc1053 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Mon, 6 Jul 2015 11:09:25 +0300 Subject: drm/i915: Mark elsps submitted when they are pushed to hw Now when we have requests this deep on call chain, we can mark the elsp being submitted when it actually is. Remove temp variable and readjust commenting to more closely fit to the code. v2: Avoid tmp variable and reduce number of writes (Chris) Cc: Chris Wilson Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 2c39ce0458b2..4c47a64a974f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -300,31 +300,29 @@ static void execlists_elsp_write(struct drm_i915_gem_request *rq0, struct intel_engine_cs *ring = rq0->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint64_t temp = 0; - uint32_t desc[4]; + uint64_t desc[2]; - /* XXX: You must always write both descriptors in the order below. */ - if (rq1) - temp = execlists_ctx_descriptor(rq1); - else - temp = 0; - desc[1] = (u32)(temp >> 32); - desc[0] = (u32)temp; + if (rq1) { + desc[1] = execlists_ctx_descriptor(rq1); + rq1->elsp_submitted++; + } else { + desc[1] = 0; + } - temp = execlists_ctx_descriptor(rq0); - desc[3] = (u32)(temp >> 32); - desc[2] = (u32)temp; + desc[0] = execlists_ctx_descriptor(rq0); + rq0->elsp_submitted++; + /* You must always write both descriptors in the order below. */ spin_lock(&dev_priv->uncore.lock); intel_uncore_forcewake_get__locked(dev_priv, FORCEWAKE_ALL); - I915_WRITE_FW(RING_ELSP(ring), desc[1]); - I915_WRITE_FW(RING_ELSP(ring), desc[0]); - I915_WRITE_FW(RING_ELSP(ring), desc[3]); + I915_WRITE_FW(RING_ELSP(ring), upper_32_bits(desc[1])); + I915_WRITE_FW(RING_ELSP(ring), lower_32_bits(desc[1])); + I915_WRITE_FW(RING_ELSP(ring), upper_32_bits(desc[0])); /* The context is automatically loaded after the following */ - I915_WRITE_FW(RING_ELSP(ring), desc[2]); + I915_WRITE_FW(RING_ELSP(ring), lower_32_bits(desc[0])); - /* ELSP is a wo register, so use another nearby reg for posting instead */ + /* ELSP is a wo register, use another nearby reg for posting */ POSTING_READ_FW(RING_EXECLIST_STATUS(ring)); intel_uncore_forcewake_put__locked(dev_priv, FORCEWAKE_ALL); spin_unlock(&dev_priv->uncore.lock); @@ -433,10 +431,6 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring) WARN_ON(req1 && req1->elsp_submitted); execlists_submit_requests(req0, req1); - - req0->elsp_submitted++; - if (req1) - req1->elsp_submitted++; } static bool execlists_check_remove_request(struct intel_engine_cs *ring, -- cgit v1.3-6-gb490 From 16a624a9c81814cc2f1353eff2e502430c3fa79a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 24 Jun 2015 08:17:02 +0200 Subject: soc: mediatek: Add infracfg misc driver support This adds support for some miscellaneous bits of the infracfg controller. The mtk_infracfg_set/clear_bus_protection functions are necessary for the scpsys power domain driver to handle the bus protection bits which are contained in the infacfg register space. Signed-off-by: Sascha Hauer Reviewed-by: Daniel Kurtz Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/Kconfig | 9 ++++ drivers/soc/mediatek/Makefile | 1 + drivers/soc/mediatek/mtk-infracfg.c | 91 +++++++++++++++++++++++++++++++++++ include/linux/soc/mediatek/infracfg.h | 26 ++++++++++ 4 files changed, 127 insertions(+) create mode 100644 drivers/soc/mediatek/mtk-infracfg.c create mode 100644 include/linux/soc/mediatek/infracfg.h (limited to 'drivers') diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index 3c1850332a90..e609a6f5e2eb 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -1,6 +1,15 @@ # # MediaTek SoC drivers # +config MTK_INFRACFG + bool "MediaTek INFRACFG Support" + depends on ARCH_MEDIATEK || COMPILE_TEST + select REGMAP + help + Say yes here to add support for the MediaTek INFRACFG controller. The + INFRACFG controller contains various infrastructure registers not + directly associated to any device. + config MTK_PMIC_WRAP tristate "MediaTek PMIC Wrapper Support" depends on ARCH_MEDIATEK diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile index ecaf4defd7f6..3fa940fb4eab 100644 --- a/drivers/soc/mediatek/Makefile +++ b/drivers/soc/mediatek/Makefile @@ -1 +1,2 @@ +obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o diff --git a/drivers/soc/mediatek/mtk-infracfg.c b/drivers/soc/mediatek/mtk-infracfg.c new file mode 100644 index 000000000000..dba3055a9493 --- /dev/null +++ b/drivers/soc/mediatek/mtk-infracfg.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015 Pengutronix, Sascha Hauer + * + * 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 + +#define INFRA_TOPAXI_PROTECTEN 0x0220 +#define INFRA_TOPAXI_PROTECTSTA1 0x0228 + +/** + * mtk_infracfg_set_bus_protection - enable bus protection + * @regmap: The infracfg regmap + * @mask: The mask containing the protection bits to be enabled. + * + * This function enables the bus protection bits for disabled power + * domains so that the system does not hang when some unit accesses the + * bus while in power down. + */ +int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask) +{ + unsigned long expired; + u32 val; + int ret; + + regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, mask); + + expired = jiffies + HZ; + + while (1) { + ret = regmap_read(infracfg, INFRA_TOPAXI_PROTECTSTA1, &val); + if (ret) + return ret; + + if ((val & mask) == mask) + break; + + cpu_relax(); + if (time_after(jiffies, expired)) + return -EIO; + } + + return 0; +} + +/** + * mtk_infracfg_clear_bus_protection - disable bus protection + * @regmap: The infracfg regmap + * @mask: The mask containing the protection bits to be disabled. + * + * This function disables the bus protection bits previously enabled with + * mtk_infracfg_set_bus_protection. + */ +int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask) +{ + unsigned long expired; + int ret; + + regmap_update_bits(infracfg, INFRA_TOPAXI_PROTECTEN, mask, 0); + + expired = jiffies + HZ; + + while (1) { + u32 val; + + ret = regmap_read(infracfg, INFRA_TOPAXI_PROTECTSTA1, &val); + if (ret) + return ret; + + if (!(val & mask)) + break; + + cpu_relax(); + if (time_after(jiffies, expired)) + return -EIO; + } + + return 0; +} diff --git a/include/linux/soc/mediatek/infracfg.h b/include/linux/soc/mediatek/infracfg.h new file mode 100644 index 000000000000..a5714e93fb34 --- /dev/null +++ b/include/linux/soc/mediatek/infracfg.h @@ -0,0 +1,26 @@ +#ifndef __SOC_MEDIATEK_INFRACFG_H +#define __SOC_MEDIATEK_INFRACFG_H + +#define MT8173_TOP_AXI_PROT_EN_MCI_M2 BIT(0) +#define MT8173_TOP_AXI_PROT_EN_MM_M0 BIT(1) +#define MT8173_TOP_AXI_PROT_EN_MM_M1 BIT(2) +#define MT8173_TOP_AXI_PROT_EN_MMAPB_S BIT(6) +#define MT8173_TOP_AXI_PROT_EN_L2C_M2 BIT(9) +#define MT8173_TOP_AXI_PROT_EN_L2SS_SMI BIT(11) +#define MT8173_TOP_AXI_PROT_EN_L2SS_ADD BIT(12) +#define MT8173_TOP_AXI_PROT_EN_CCI_M2 BIT(13) +#define MT8173_TOP_AXI_PROT_EN_MFG_S BIT(14) +#define MT8173_TOP_AXI_PROT_EN_PERI_M0 BIT(15) +#define MT8173_TOP_AXI_PROT_EN_PERI_M1 BIT(16) +#define MT8173_TOP_AXI_PROT_EN_DEBUGSYS BIT(17) +#define MT8173_TOP_AXI_PROT_EN_CQ_DMA BIT(18) +#define MT8173_TOP_AXI_PROT_EN_GCPU BIT(19) +#define MT8173_TOP_AXI_PROT_EN_IOMMU BIT(20) +#define MT8173_TOP_AXI_PROT_EN_MFG_M0 BIT(21) +#define MT8173_TOP_AXI_PROT_EN_MFG_M1 BIT(22) +#define MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT BIT(23) + +int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask); +int mtk_infracfg_clear_bus_protection(struct regmap *infracfg, u32 mask); + +#endif /* __SOC_MEDIATEK_INFRACFG_H */ -- cgit v1.3-6-gb490 From c84e358718a66f76ac0de1681d15d8d0c68fcdab Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 24 Jun 2015 08:17:04 +0200 Subject: soc: Mediatek: Add SCPSYS power domain driver This adds a power domain driver for the Mediatek SCPSYS unit. The System Control Processor System (SCPSYS) has several power management related tasks in the system. The tasks include thermal measurement, dynamic voltage frequency scaling (DVFS), interrupt filter and lowlevel sleep control. The System Power Manager (SPM) inside the SCPSYS is for the MTCMOS power domain control. For now this driver only adds power domain support, the more advanced features are not yet supported. The driver implements the generic PM domain device tree bindings, the first user will most likely be the Mediatek AFE audio driver. Signed-off-by: Sascha Hauer Reviewed-by: Daniel Kurtz Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/Kconfig | 10 + drivers/soc/mediatek/Makefile | 1 + drivers/soc/mediatek/mtk-scpsys.c | 487 +++++++++++++++++++++++++++++++ include/dt-bindings/power/mt8173-power.h | 15 + 4 files changed, 513 insertions(+) create mode 100644 drivers/soc/mediatek/mtk-scpsys.c create mode 100644 include/dt-bindings/power/mt8173-power.h (limited to 'drivers') diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index e609a6f5e2eb..9d5068248aa0 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -19,3 +19,13 @@ config MTK_PMIC_WRAP Say yes here to add support for MediaTek PMIC Wrapper found on different MediaTek SoCs. The PMIC wrapper is a proprietary hardware to connect the PMIC. + +config MTK_SCPSYS + bool "MediaTek SCPSYS Support" + depends on ARCH_MEDIATEK || COMPILE_TEST + select REGMAP + select MTK_INFRACFG + select PM_GENERIC_DOMAINS if PM + help + Say yes here to add support for the MediaTek SCPSYS power domain + driver. diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile index 3fa940fb4eab..12998b08819e 100644 --- a/drivers/soc/mediatek/Makefile +++ b/drivers/soc/mediatek/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o +obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c new file mode 100644 index 000000000000..43a79ed761c4 --- /dev/null +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2015 Pengutronix, Sascha Hauer + * + * 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 +#include +#include +#include +#include +#include + +#define SPM_VDE_PWR_CON 0x0210 +#define SPM_MFG_PWR_CON 0x0214 +#define SPM_VEN_PWR_CON 0x0230 +#define SPM_ISP_PWR_CON 0x0238 +#define SPM_DIS_PWR_CON 0x023c +#define SPM_VEN2_PWR_CON 0x0298 +#define SPM_AUDIO_PWR_CON 0x029c +#define SPM_MFG_2D_PWR_CON 0x02c0 +#define SPM_MFG_ASYNC_PWR_CON 0x02c4 +#define SPM_USB_PWR_CON 0x02cc +#define SPM_PWR_STATUS 0x060c +#define SPM_PWR_STATUS_2ND 0x0610 + +#define PWR_RST_B_BIT BIT(0) +#define PWR_ISO_BIT BIT(1) +#define PWR_ON_BIT BIT(2) +#define PWR_ON_2ND_BIT BIT(3) +#define PWR_CLK_DIS_BIT BIT(4) + +#define PWR_STATUS_DISP BIT(3) +#define PWR_STATUS_MFG BIT(4) +#define PWR_STATUS_ISP BIT(5) +#define PWR_STATUS_VDEC BIT(7) +#define PWR_STATUS_VENC_LT BIT(20) +#define PWR_STATUS_VENC BIT(21) +#define PWR_STATUS_MFG_2D BIT(22) +#define PWR_STATUS_MFG_ASYNC BIT(23) +#define PWR_STATUS_AUDIO BIT(24) +#define PWR_STATUS_USB BIT(25) + +enum clk_id { + MT8173_CLK_MM, + MT8173_CLK_MFG, + MT8173_CLK_NONE, + MT8173_CLK_MAX = MT8173_CLK_NONE, +}; + +struct scp_domain_data { + const char *name; + u32 sta_mask; + int ctl_offs; + u32 sram_pdn_bits; + u32 sram_pdn_ack_bits; + u32 bus_prot_mask; + enum clk_id clk_id; +}; + +static const struct scp_domain_data scp_domain_data[] __initconst = { + [MT8173_POWER_DOMAIN_VDEC] = { + .name = "vdec", + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = MT8173_CLK_MM, + }, + [MT8173_POWER_DOMAIN_VENC] = { + .name = "venc", + .sta_mask = PWR_STATUS_VENC, + .ctl_offs = SPM_VEN_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = MT8173_CLK_MM, + }, + [MT8173_POWER_DOMAIN_ISP] = { + .name = "isp", + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = MT8173_CLK_MM, + }, + [MT8173_POWER_DOMAIN_MM] = { + .name = "mm", + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = MT8173_CLK_MM, + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | + MT8173_TOP_AXI_PROT_EN_MM_M1, + }, + [MT8173_POWER_DOMAIN_VENC_LT] = { + .name = "venc_lt", + .sta_mask = PWR_STATUS_VENC_LT, + .ctl_offs = SPM_VEN2_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = MT8173_CLK_MM, + }, + [MT8173_POWER_DOMAIN_AUDIO] = { + .name = "audio", + .sta_mask = PWR_STATUS_AUDIO, + .ctl_offs = SPM_AUDIO_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = MT8173_CLK_NONE, + }, + [MT8173_POWER_DOMAIN_USB] = { + .name = "usb", + .sta_mask = PWR_STATUS_USB, + .ctl_offs = SPM_USB_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = MT8173_CLK_NONE, + }, + [MT8173_POWER_DOMAIN_MFG_ASYNC] = { + .name = "mfg_async", + .sta_mask = PWR_STATUS_MFG_ASYNC, + .ctl_offs = SPM_MFG_ASYNC_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = 0, + .clk_id = MT8173_CLK_MFG, + }, + [MT8173_POWER_DOMAIN_MFG_2D] = { + .name = "mfg_2d", + .sta_mask = PWR_STATUS_MFG_2D, + .ctl_offs = SPM_MFG_2D_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = MT8173_CLK_NONE, + }, + [MT8173_POWER_DOMAIN_MFG] = { + .name = "mfg", + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(13, 8), + .sram_pdn_ack_bits = GENMASK(21, 16), + .clk_id = MT8173_CLK_NONE, + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | + MT8173_TOP_AXI_PROT_EN_MFG_M0 | + MT8173_TOP_AXI_PROT_EN_MFG_M1 | + MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, + }, +}; + +#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data) + +struct scp; + +struct scp_domain { + struct generic_pm_domain genpd; + struct scp *scp; + struct clk *clk; + u32 sta_mask; + void __iomem *ctl_addr; + u32 sram_pdn_bits; + u32 sram_pdn_ack_bits; + u32 bus_prot_mask; +}; + +struct scp { + struct scp_domain domains[NUM_DOMAINS]; + struct genpd_onecell_data pd_data; + struct device *dev; + void __iomem *base; + struct regmap *infracfg; +}; + +static int scpsys_domain_is_on(struct scp_domain *scpd) +{ + struct scp *scp = scpd->scp; + + u32 status = readl(scp->base + SPM_PWR_STATUS) & scpd->sta_mask; + u32 status2 = readl(scp->base + SPM_PWR_STATUS_2ND) & scpd->sta_mask; + + /* + * A domain is on when both status bits are set. If only one is set + * return an error. This happens while powering up a domain + */ + + if (status && status2) + return true; + if (!status && !status2) + return false; + + return -EINVAL; +} + +static int scpsys_power_on(struct generic_pm_domain *genpd) +{ + struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); + struct scp *scp = scpd->scp; + unsigned long timeout; + bool expired; + void __iomem *ctl_addr = scpd->ctl_addr; + u32 sram_pdn_ack = scpd->sram_pdn_ack_bits; + u32 val; + int ret; + + if (scpd->clk) { + ret = clk_prepare_enable(scpd->clk); + if (ret) + goto err_clk; + } + + val = readl(ctl_addr); + val |= PWR_ON_BIT; + writel(val, ctl_addr); + val |= PWR_ON_2ND_BIT; + writel(val, ctl_addr); + + /* wait until PWR_ACK = 1 */ + timeout = jiffies + HZ; + expired = false; + while (1) { + ret = scpsys_domain_is_on(scpd); + if (ret > 0) + break; + + if (expired) { + ret = -ETIMEDOUT; + goto err_pwr_ack; + } + + cpu_relax(); + + if (time_after(jiffies, timeout)) + expired = true; + } + + val &= ~PWR_CLK_DIS_BIT; + writel(val, ctl_addr); + + val &= ~PWR_ISO_BIT; + writel(val, ctl_addr); + + val |= PWR_RST_B_BIT; + writel(val, ctl_addr); + + val &= ~scpd->sram_pdn_bits; + writel(val, ctl_addr); + + /* wait until SRAM_PDN_ACK all 0 */ + timeout = jiffies + HZ; + expired = false; + while (sram_pdn_ack && (readl(ctl_addr) & sram_pdn_ack)) { + + if (expired) { + ret = -ETIMEDOUT; + goto err_pwr_ack; + } + + cpu_relax(); + + if (time_after(jiffies, timeout)) + expired = true; + } + + if (scpd->bus_prot_mask) { + ret = mtk_infracfg_clear_bus_protection(scp->infracfg, + scpd->bus_prot_mask); + if (ret) + goto err_pwr_ack; + } + + return 0; + +err_pwr_ack: + clk_disable_unprepare(scpd->clk); +err_clk: + dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name); + + return ret; +} + +static int scpsys_power_off(struct generic_pm_domain *genpd) +{ + struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); + struct scp *scp = scpd->scp; + unsigned long timeout; + bool expired; + void __iomem *ctl_addr = scpd->ctl_addr; + u32 pdn_ack = scpd->sram_pdn_ack_bits; + u32 val; + int ret; + + if (scpd->bus_prot_mask) { + ret = mtk_infracfg_set_bus_protection(scp->infracfg, + scpd->bus_prot_mask); + if (ret) + goto out; + } + + val = readl(ctl_addr); + val |= scpd->sram_pdn_bits; + writel(val, ctl_addr); + + /* wait until SRAM_PDN_ACK all 1 */ + timeout = jiffies + HZ; + expired = false; + while (pdn_ack && (readl(ctl_addr) & pdn_ack) != pdn_ack) { + if (expired) { + ret = -ETIMEDOUT; + goto out; + } + + cpu_relax(); + + if (time_after(jiffies, timeout)) + expired = true; + } + + val |= PWR_ISO_BIT; + writel(val, ctl_addr); + + val &= ~PWR_RST_B_BIT; + writel(val, ctl_addr); + + val |= PWR_CLK_DIS_BIT; + writel(val, ctl_addr); + + val &= ~PWR_ON_BIT; + writel(val, ctl_addr); + + val &= ~PWR_ON_2ND_BIT; + writel(val, ctl_addr); + + /* wait until PWR_ACK = 0 */ + timeout = jiffies + HZ; + expired = false; + while (1) { + ret = scpsys_domain_is_on(scpd); + if (ret == 0) + break; + + if (expired) { + ret = -ETIMEDOUT; + goto out; + } + + cpu_relax(); + + if (time_after(jiffies, timeout)) + expired = true; + } + + if (scpd->clk) + clk_disable_unprepare(scpd->clk); + + return 0; + +out: + dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name); + + return ret; +} + +static int __init scpsys_probe(struct platform_device *pdev) +{ + struct genpd_onecell_data *pd_data; + struct resource *res; + int i, ret; + struct scp *scp; + struct clk *clk[MT8173_CLK_MAX]; + + scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL); + if (!scp) + return -ENOMEM; + + scp->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + scp->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(scp->base)) + return PTR_ERR(scp->base); + + pd_data = &scp->pd_data; + + pd_data->domains = devm_kzalloc(&pdev->dev, + sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL); + if (!pd_data->domains) + return -ENOMEM; + + clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm"); + if (IS_ERR(clk[MT8173_CLK_MM])) + return PTR_ERR(clk[MT8173_CLK_MM]); + + clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg"); + if (IS_ERR(clk[MT8173_CLK_MFG])) + return PTR_ERR(clk[MT8173_CLK_MFG]); + + scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "infracfg"); + if (IS_ERR(scp->infracfg)) { + dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n", + PTR_ERR(scp->infracfg)); + return PTR_ERR(scp->infracfg); + } + + pd_data->num_domains = NUM_DOMAINS; + + for (i = 0; i < NUM_DOMAINS; i++) { + struct scp_domain *scpd = &scp->domains[i]; + struct generic_pm_domain *genpd = &scpd->genpd; + const struct scp_domain_data *data = &scp_domain_data[i]; + + pd_data->domains[i] = genpd; + scpd->scp = scp; + + scpd->sta_mask = data->sta_mask; + scpd->ctl_addr = scp->base + data->ctl_offs; + scpd->sram_pdn_bits = data->sram_pdn_bits; + scpd->sram_pdn_ack_bits = data->sram_pdn_ack_bits; + scpd->bus_prot_mask = data->bus_prot_mask; + if (data->clk_id != MT8173_CLK_NONE) + scpd->clk = clk[data->clk_id]; + + genpd->name = data->name; + genpd->power_off = scpsys_power_off; + genpd->power_on = scpsys_power_on; + + /* + * Initially turn on all domains to make the domains usable + * with !CONFIG_PM and to get the hardware in sync with the + * software. The unused domains will be switched off during + * late_init time. + */ + genpd->power_on(genpd); + + pm_genpd_init(genpd, NULL, false); + } + + /* + * We are not allowed to fail here since there is no way to unregister + * a power domain. Once registered above we have to keep the domains + * valid. + */ + + ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC], + pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]); + if (ret && IS_ENABLED(CONFIG_PM)) + dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret); + + ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D], + pd_data->domains[MT8173_POWER_DOMAIN_MFG]); + if (ret && IS_ENABLED(CONFIG_PM)) + dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret); + + ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); + if (ret) + dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); + + return 0; +} + +static const struct of_device_id of_scpsys_match_tbl[] = { + { + .compatible = "mediatek,mt8173-scpsys", + }, { + /* sentinel */ + } +}; + +static struct platform_driver scpsys_drv = { + .driver = { + .name = "mtk-scpsys", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_scpsys_match_tbl), + }, +}; + +module_platform_driver_probe(scpsys_drv, scpsys_probe); diff --git a/include/dt-bindings/power/mt8173-power.h b/include/dt-bindings/power/mt8173-power.h new file mode 100644 index 000000000000..b34cee95aa89 --- /dev/null +++ b/include/dt-bindings/power/mt8173-power.h @@ -0,0 +1,15 @@ +#ifndef _DT_BINDINGS_POWER_MT8183_POWER_H +#define _DT_BINDINGS_POWER_MT8183_POWER_H + +#define MT8173_POWER_DOMAIN_VDEC 0 +#define MT8173_POWER_DOMAIN_VENC 1 +#define MT8173_POWER_DOMAIN_ISP 2 +#define MT8173_POWER_DOMAIN_MM 3 +#define MT8173_POWER_DOMAIN_VENC_LT 4 +#define MT8173_POWER_DOMAIN_AUDIO 5 +#define MT8173_POWER_DOMAIN_USB 6 +#define MT8173_POWER_DOMAIN_MFG_ASYNC 7 +#define MT8173_POWER_DOMAIN_MFG_2D 8 +#define MT8173_POWER_DOMAIN_MFG 9 + +#endif /* _DT_BINDINGS_POWER_MT8183_POWER_H */ -- cgit v1.3-6-gb490 From c07a2d1194fc694785771643c413c44adf7635d3 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 6 Jul 2015 09:19:24 -0700 Subject: drm/i915: Don't dereference NULL plane while setting up scalers intel_atomic_setup_scalers() dereferences 'plane' before the plane has been assigned. The plane ID assignment doing this dereference is only needed for debugging messages later in the function, so just move the assignment farther down the function to a point where plane will no longer be NULL. This was introduced in: commit 133b0d128be39e308ccd3b3d765c31ebdbf5380e Author: Maarten Lankhorst Date: Mon Jun 15 12:33:39 2015 +0200 drm/i915: Clean up intel_atomic_setup_scalers slightly. Cc: Maarten Lankhorst Cc: Bob Paauwe Reported-by: Bob Paauwe Signed-off-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 0aeced82201e..5c79a31603af 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -325,7 +325,6 @@ int intel_atomic_setup_scalers(struct drm_device *dev, scaler_id = &scaler_state->scaler_id; } else { name = "PLANE"; - idx = plane->base.id; if (!drm_state) continue; @@ -359,6 +358,7 @@ int intel_atomic_setup_scalers(struct drm_device *dev, } intel_plane = to_intel_plane(plane); + idx = plane->base.id; /* plane on different crtc cannot be a scaler user of this crtc */ if (WARN_ON(intel_plane->pipe != intel_crtc->pipe)) { -- cgit v1.3-6-gb490 From d26a5b6e80c87fd8fd136eb0a334fc7960ac9699 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 2 Jul 2015 17:42:46 +0300 Subject: drm/i915: Disable LVDS port after the pipe on PCH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the correct pipe vs port disable sequence for the PCH LVDS ports, ie. disable the port after the pipe. Other PCH port were already converted in the following commits: 1ea56e269e136544c0a76dc831c5edc27c47cb3c drm/i915: Disable CRT port after pipe on PCH platforms 3c65d1d1bb92ea959e8bce3eeae90fe5c3daa58a drm/i915: Disable SDVO port after the pipe on PCH platforms a4790cec3adf5eec91f397b1884706a71c70730f drm/i915: Disable HDMI port after the pipe on PCH platforms 08aff3fe26ae7a0d6f302ac2e1b7e2eb9933cd42 drm/i915: Move DP port disable to post_disable for pch platforms but LVDS was forgotten. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lvds.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index ea85547611a5..937e8216e9d6 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -239,8 +239,6 @@ static void intel_disable_lvds(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); - struct intel_connector *intel_connector = - &lvds_encoder->attached_connector->base; struct drm_i915_private *dev_priv = dev->dev_private; u32 ctl_reg, stat_reg; @@ -252,8 +250,6 @@ static void intel_disable_lvds(struct intel_encoder *encoder) stat_reg = PP_STATUS; } - intel_panel_disable_backlight(intel_connector); - I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000)) DRM_ERROR("timed out waiting for panel to power off\n"); @@ -262,6 +258,31 @@ static void intel_disable_lvds(struct intel_encoder *encoder) POSTING_READ(lvds_encoder->reg); } +static void gmch_disable_lvds(struct intel_encoder *encoder) +{ + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + struct intel_connector *intel_connector = + &lvds_encoder->attached_connector->base; + + intel_panel_disable_backlight(intel_connector); + + intel_disable_lvds(encoder); +} + +static void pch_disable_lvds(struct intel_encoder *encoder) +{ + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + struct intel_connector *intel_connector = + &lvds_encoder->attached_connector->base; + + intel_panel_disable_backlight(intel_connector); +} + +static void pch_post_disable_lvds(struct intel_encoder *encoder) +{ + intel_disable_lvds(encoder); +} + static enum drm_mode_status intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) @@ -992,7 +1013,12 @@ void intel_lvds_init(struct drm_device *dev) intel_encoder->enable = intel_enable_lvds; intel_encoder->pre_enable = intel_pre_enable_lvds; intel_encoder->compute_config = intel_lvds_compute_config; - intel_encoder->disable = intel_disable_lvds; + if (HAS_PCH_SPLIT(dev_priv)) { + intel_encoder->disable = pch_disable_lvds; + intel_encoder->post_disable = pch_post_disable_lvds; + } else { + intel_encoder->disable = gmch_disable_lvds; + } intel_encoder->get_hw_state = intel_lvds_get_hw_state; intel_encoder->get_config = intel_lvds_get_config; intel_connector->get_hw_state = intel_connector_get_hw_state; -- cgit v1.3-6-gb490 From 70cfef26267474f94ff4a988fb45ff78442b1cf4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 29 Jun 2015 09:04:43 +0900 Subject: regulator: Add lockdep asserts to help detecting locking misuse Add lockdep_assert_held_once() to functions explicitly mentioning that rdev or regulator_list mutex must be held. Using WARN_ONCE shouldn't pollute the dmesg to much. The patch (if CONFIG_LOCKDEP enabled) will show warnings in certain regulators calling regulator_notifier_call_chain() without rdev->mutex held. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c9f72019bd68..68b616580533 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -640,6 +640,8 @@ static int drms_uA_update(struct regulator_dev *rdev) int current_uA = 0, output_uV, input_uV, err; unsigned int mode; + lockdep_assert_held_once(&rdev->mutex); + /* * first check to see if we can set modes at all, otherwise just * tell the consumer everything is OK. @@ -760,6 +762,8 @@ static int suspend_set_state(struct regulator_dev *rdev, /* locks held by caller */ static int suspend_prepare(struct regulator_dev *rdev, suspend_state_t state) { + lockdep_assert_held_once(&rdev->mutex); + if (!rdev->constraints) return -EINVAL; @@ -1587,6 +1591,8 @@ static void _regulator_put(struct regulator *regulator) if (regulator == NULL || IS_ERR(regulator)) return; + lockdep_assert_held_once(®ulator_list_mutex); + rdev = regulator->rdev; debugfs_remove_recursive(regulator->debugfs); @@ -1965,6 +1971,8 @@ static int _regulator_enable(struct regulator_dev *rdev) { int ret; + lockdep_assert_held_once(&rdev->mutex); + /* check voltage and requested load before enabling */ if (rdev->constraints && (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) @@ -2065,6 +2073,8 @@ static int _regulator_disable(struct regulator_dev *rdev) { int ret = 0; + lockdep_assert_held_once(&rdev->mutex); + if (WARN(rdev->use_count <= 0, "unbalanced disables for %s\n", rdev_get_name(rdev))) return -EIO; @@ -2143,6 +2153,8 @@ static int _regulator_force_disable(struct regulator_dev *rdev) { int ret = 0; + lockdep_assert_held_once(&rdev->mutex); + ret = _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | REGULATOR_EVENT_PRE_DISABLE, NULL); if (ret & NOTIFY_STOP_MASK) @@ -3439,6 +3451,8 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free); int regulator_notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data) { + lockdep_assert_held_once(&rdev->mutex); + _notifier_call_chain(rdev, event, data); return NOTIFY_DONE; -- cgit v1.3-6-gb490 From fe052a1810ec4687ee7d606290561af504047707 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 29 Jun 2015 13:08:19 +0300 Subject: target: Use struct t10_pi_tuple Its not a good idea to keep target specific definition of the same t10-pi tuple. (Fix v4.2-rc1 patch fuzz - nab) Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 2 +- drivers/target/target_core_sbc.c | 10 +++++----- include/target/target_core_base.h | 7 +------ 3 files changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 09e682b1c549..db7034292053 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -754,7 +754,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) dev->dev_link_magic = SE_DEV_LINK_MAGIC; dev->se_hba = hba; dev->transport = hba->backend->ops; - dev->prot_length = sizeof(struct se_dif_v1_tuple); + dev->prot_length = sizeof(struct t10_pi_tuple); dev->hba_index = hba->hba_index; INIT_LIST_HEAD(&dev->dev_list); diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index e318ddbe15da..ac7215039e5a 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1191,7 +1191,7 @@ void sbc_dif_generate(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_dif_v1_tuple *sdt; + struct t10_pi_tuple *sdt; struct scatterlist *dsg = cmd->t_data_sg, *psg; sector_t sector = cmd->t_task_lba; void *daddr, *paddr; @@ -1203,7 +1203,7 @@ sbc_dif_generate(struct se_cmd *cmd) daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; for (j = 0; j < psg->length; - j += sizeof(struct se_dif_v1_tuple)) { + j += sizeof(*sdt)) { __u16 crc; unsigned int avail; @@ -1256,7 +1256,7 @@ sbc_dif_generate(struct se_cmd *cmd) } static sense_reason_t -sbc_dif_v1_verify(struct se_cmd *cmd, struct se_dif_v1_tuple *sdt, +sbc_dif_v1_verify(struct se_cmd *cmd, struct t10_pi_tuple *sdt, __u16 crc, sector_t sector, unsigned int ei_lba) { __be16 csum; @@ -1346,7 +1346,7 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, unsigned int ei_lba, struct scatterlist *psg, int psg_off) { struct se_device *dev = cmd->se_dev; - struct se_dif_v1_tuple *sdt; + struct t10_pi_tuple *sdt; struct scatterlist *dsg = cmd->t_data_sg; sector_t sector = start; void *daddr, *paddr; @@ -1361,7 +1361,7 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, for (i = psg_off; i < psg->length && sector < start + sectors; - i += sizeof(struct se_dif_v1_tuple)) { + i += sizeof(*sdt)) { __u16 crc; unsigned int avail; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 17ae2d6a4891..a6816444d81b 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -426,12 +427,6 @@ enum target_core_dif_check { TARGET_DIF_CHECK_REFTAG = 0x1 << 2, }; -struct se_dif_v1_tuple { - __be16 guard_tag; - __be16 app_tag; - __be32 ref_tag; -}; - /* for sam_task_attr */ #define TCM_SIMPLE_TAG 0x20 #define TCM_HEAD_TAG 0x21 -- cgit v1.3-6-gb490 From 4791eb61dbe8100ccac59fecfac9d93a15db1447 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 18 Jun 2015 16:18:28 +0200 Subject: clk: rockchip: rk3288: add CLK_SET_RATE_PARENT to sclk_mac The dwmac ethernet controller on the rk3288 supports phys connected via rgmii and rmii. With rgmii phys it is expected that the mac clock is provided externally while with rmii phys the clock can be external but also generated from the plls. In the later case it of course needs be at 50MHz, which gets set from the dwmac_rk driver. As most devices use a rgmii phy it never surfaced so far that the mac clk mux, doesn't go up one lever to the pll clock in the rmii case with internal clock generation, as it is missing the CLK_SET_RATE_PARENT flag, and thus will not set the correct frequency in most cases. Fixes: b9e4ba541607 ("clk: rockchip: add clock controller for rk3288") Cc: stable@vger.kernel.org Signed-off-by: Heiko Stuebner Signed-off-by: Stephen Boyd --- drivers/clk/rockchip/clk-rk3288.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 4f817ed9e6ee..0211162ee879 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -578,7 +578,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0, RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS, RK3288_CLKGATE_CON(2), 5, GFLAGS), - MUX(SCLK_MAC, "mac_clk", mux_mac_p, 0, + MUX(SCLK_MAC, "mac_clk", mux_mac_p, CLK_SET_RATE_PARENT, RK3288_CLKSEL_CON(21), 4, 1, MFLAGS), GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0, RK3288_CLKGATE_CON(5), 3, GFLAGS), -- cgit v1.3-6-gb490 From 101762976b8d7038934f31ffb4e19fbac9b5e1d4 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 18 Jun 2015 16:18:29 +0200 Subject: clk: rockchip: fix faulty vip parent name on rk3288 The video input processor (vip) was called camera interface (cif) on older socs which seems to have resulted in a copy'n'paste error when creating the rk3288 camera clocks. Signed-off-by: Heiko Stuebner Signed-off-by: Stephen Boyd --- drivers/clk/rockchip/clk-rk3288.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 0211162ee879..df9dc9630e6c 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -189,7 +189,7 @@ PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" }; PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" }; PNAME(mux_uart3_p) = { "uart3_src", "uart3_frac", "xin24m" }; PNAME(mux_uart4_p) = { "uart4_src", "uart4_frac", "xin24m" }; -PNAME(mux_cif_out_p) = { "cif_src", "xin24m" }; +PNAME(mux_vip_out_p) = { "vip_src", "xin24m" }; PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" }; PNAME(mux_hsadcout_p) = { "hsadc_src", "ext_hsadc" }; PNAME(mux_edp_24m_p) = { "ext_edp_24m", "xin24m" }; @@ -434,7 +434,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE_NODIV(0, "vip_src", mux_pll_src_cpll_gpll_p, 0, RK3288_CLKSEL_CON(26), 8, 1, MFLAGS, RK3288_CLKGATE_CON(3), 7, GFLAGS), - COMPOSITE_NOGATE(0, "sclk_vip_out", mux_cif_out_p, 0, + COMPOSITE_NOGATE(0, "sclk_vip_out", mux_vip_out_p, 0, RK3288_CLKSEL_CON(26), 15, 1, MFLAGS, 9, 5, DFLAGS), DIV(0, "pclk_pd_alive", "gpll", 0, -- cgit v1.3-6-gb490 From 2d7884a7d0e70f9509881c40eaee3f5a5c201b07 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 18 Jun 2015 16:18:30 +0200 Subject: clk: rockchip: protect register macros against multipart values The macros calculate the correct offset from the id in the parameter. If this parameter does not consist of a single number, the calculation will return wrong registers in the best case or create unaligned accesses in the worst case. So protect the calculations against such values. Signed-off-by: Heiko Stuebner Signed-off-by: Stephen Boyd --- drivers/clk/rockchip/clk.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 6b092673048a..92edb5f9e7e8 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -31,22 +31,22 @@ ((val) << (shift) | (mask) << ((shift) + 16)) /* register positions shared by RK2928, RK3066 and RK3188 */ -#define RK2928_PLL_CON(x) (x * 0x4) +#define RK2928_PLL_CON(x) ((x) * 0x4) #define RK2928_MODE_CON 0x40 -#define RK2928_CLKSEL_CON(x) (x * 0x4 + 0x44) -#define RK2928_CLKGATE_CON(x) (x * 0x4 + 0xd0) +#define RK2928_CLKSEL_CON(x) ((x) * 0x4 + 0x44) +#define RK2928_CLKGATE_CON(x) ((x) * 0x4 + 0xd0) #define RK2928_GLB_SRST_FST 0x100 #define RK2928_GLB_SRST_SND 0x104 -#define RK2928_SOFTRST_CON(x) (x * 0x4 + 0x110) +#define RK2928_SOFTRST_CON(x) ((x) * 0x4 + 0x110) #define RK2928_MISC_CON 0x134 #define RK3288_PLL_CON(x) RK2928_PLL_CON(x) #define RK3288_MODE_CON 0x50 -#define RK3288_CLKSEL_CON(x) (x * 0x4 + 0x60) -#define RK3288_CLKGATE_CON(x) (x * 0x4 + 0x160) +#define RK3288_CLKSEL_CON(x) ((x) * 0x4 + 0x60) +#define RK3288_CLKGATE_CON(x) ((x) * 0x4 + 0x160) #define RK3288_GLB_SRST_FST 0x1b0 #define RK3288_GLB_SRST_SND 0x1b4 -#define RK3288_SOFTRST_CON(x) (x * 0x4 + 0x1b8) +#define RK3288_SOFTRST_CON(x) ((x) * 0x4 + 0x1b8) #define RK3288_MISC_CON 0x1e8 #define RK3288_SDMMC_CON0 0x200 #define RK3288_SDMMC_CON1 0x204 @@ -67,7 +67,7 @@ enum rockchip_pll_type { .nr = _nr, \ .nf = _nf, \ .no = _no, \ - .bwadj = (_nf >> 1), \ + .bwadj = ((_nf) >> 1), \ } #define RK3066_PLL_RATE_BWADJ(_rate, _nr, _nf, _no, _bw) \ -- cgit v1.3-6-gb490 From 6f085072534363b68c705d54b9dbbed0474ff357 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Thu, 18 Jun 2015 16:18:31 +0200 Subject: clk: rockchip: add COMPOSITE_NOGATE_DIVTBL variant A clock branch consisting of a mux and divider with non-standard divider values. Signed-off-by: Heiko Stuebner Signed-off-by: Stephen Boyd --- drivers/clk/rockchip/clk.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 92edb5f9e7e8..501f02ea9d4b 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -308,6 +308,26 @@ struct rockchip_clk_branch { .gate_offset = -1, \ } +#define COMPOSITE_NOGATE_DIVTBL(_id, cname, pnames, f, mo, ms, \ + mw, mf, ds, dw, df, dt) \ + { \ + .id = _id, \ + .branch_type = branch_composite, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .flags = f, \ + .muxdiv_offset = mo, \ + .mux_shift = ms, \ + .mux_width = mw, \ + .mux_flags = mf, \ + .div_shift = ds, \ + .div_width = dw, \ + .div_flags = df, \ + .div_table = dt, \ + .gate_offset = -1, \ + } + #define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf)\ { \ .id = _id, \ -- cgit v1.3-6-gb490 From 8a76f443a9ea6f7f72ede9f95fe0ca5b90f09a43 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sun, 5 Jul 2015 11:00:14 +0200 Subject: clk: rockchip: add support for phase inverters Most Rockchip socs have optional phase inverters connected to some clocks that move the clock-phase by 180 degrees. Signed-off-by: Heiko Stuebner [sboyd@codeaurora.org: Dropped lazy part of commit text] Signed-off-by: Stephen Boyd --- drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-inverter.c | 116 ++++++++++++++++++++++++++++++++++++ drivers/clk/rockchip/clk.c | 7 +++ drivers/clk/rockchip/clk.h | 20 +++++++ 4 files changed, 144 insertions(+) create mode 100644 drivers/clk/rockchip/clk-inverter.c (limited to 'drivers') diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 2714097f90db..fd71c7df03d1 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -6,6 +6,7 @@ obj-y += clk-rockchip.o obj-y += clk.o obj-y += clk-pll.o obj-y += clk-cpu.o +obj-y += clk-inverter.o obj-y += clk-mmc-phase.o obj-$(CONFIG_RESET_CONTROLLER) += softrst.o diff --git a/drivers/clk/rockchip/clk-inverter.c b/drivers/clk/rockchip/clk-inverter.c new file mode 100644 index 000000000000..8054fdb5effb --- /dev/null +++ b/drivers/clk/rockchip/clk-inverter.c @@ -0,0 +1,116 @@ +/* + * Copyright 2015 Heiko Stuebner + * + * 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 +#include +#include "clk.h" + +struct rockchip_inv_clock { + struct clk_hw hw; + void __iomem *reg; + int shift; + int flags; + spinlock_t *lock; +}; + +#define to_inv_clock(_hw) container_of(_hw, struct rockchip_inv_clock, hw) + +#define INVERTER_MASK 0x1 + +static int rockchip_inv_get_phase(struct clk_hw *hw) +{ + struct rockchip_inv_clock *inv_clock = to_inv_clock(hw); + u32 val; + + val = readl(inv_clock->reg) >> inv_clock->shift; + val &= INVERTER_MASK; + return val ? 180 : 0; +} + +static int rockchip_inv_set_phase(struct clk_hw *hw, int degrees) +{ + struct rockchip_inv_clock *inv_clock = to_inv_clock(hw); + u32 val; + + if (degrees % 180 == 0) { + val = !!degrees; + } else { + pr_err("%s: unsupported phase %d for %s\n", + __func__, degrees, __clk_get_name(hw->clk)); + return -EINVAL; + } + + if (inv_clock->flags & ROCKCHIP_INVERTER_HIWORD_MASK) { + writel(HIWORD_UPDATE(val, INVERTER_MASK, inv_clock->shift), + inv_clock->reg); + } else { + unsigned long flags; + u32 reg; + + spin_lock_irqsave(inv_clock->lock, flags); + + reg = readl(inv_clock->reg); + reg &= ~BIT(inv_clock->shift); + reg |= val; + writel(reg, inv_clock->reg); + + spin_unlock_irqrestore(inv_clock->lock, flags); + } + + return 0; +} + +static const struct clk_ops rockchip_inv_clk_ops = { + .get_phase = rockchip_inv_get_phase, + .set_phase = rockchip_inv_set_phase, +}; + +struct clk *rockchip_clk_register_inverter(const char *name, + const char *const *parent_names, u8 num_parents, + void __iomem *reg, int shift, int flags, + spinlock_t *lock) +{ + struct clk_init_data init; + struct rockchip_inv_clock *inv_clock; + struct clk *clk; + + inv_clock = kmalloc(sizeof(*inv_clock), GFP_KERNEL); + if (!inv_clock) + return NULL; + + init.name = name; + init.num_parents = num_parents; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = parent_names; + init.ops = &rockchip_inv_clk_ops; + + inv_clock->hw.init = &init; + inv_clock->reg = reg; + inv_clock->shift = shift; + inv_clock->flags = flags; + inv_clock->lock = lock; + + clk = clk_register(NULL, &inv_clock->hw); + if (IS_ERR(clk)) + goto err_free; + + return clk; + +err_free: + kfree(inv_clock); + return NULL; +} diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 052b94db0ff9..24938815655f 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -277,6 +277,13 @@ void __init rockchip_clk_register_branches( list->div_shift ); break; + case branch_inverter: + clk = rockchip_clk_register_inverter( + list->name, list->parent_names, + list->num_parents, + reg_base + list->muxdiv_offset, + list->div_shift, list->div_flags, &clk_lock); + break; } /* none of the cases above matched */ diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 501f02ea9d4b..b72dad074a75 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -182,6 +182,13 @@ struct clk *rockchip_clk_register_mmc(const char *name, const char *const *parent_names, u8 num_parents, void __iomem *reg, int shift); +#define ROCKCHIP_INVERTER_HIWORD_MASK BIT(0) + +struct clk *rockchip_clk_register_inverter(const char *name, + const char *const *parent_names, u8 num_parents, + void __iomem *reg, int shift, int flags, + spinlock_t *lock); + #define PNAME(x) static const char *const x[] __initconst enum rockchip_clk_branch_type { @@ -191,6 +198,7 @@ enum rockchip_clk_branch_type { branch_fraction_divider, branch_gate, branch_mmc, + branch_inverter, }; struct rockchip_clk_branch { @@ -414,6 +422,18 @@ struct rockchip_clk_branch { .div_shift = shift, \ } +#define INVERTER(_id, cname, pname, io, is, if) \ + { \ + .id = _id, \ + .branch_type = branch_inverter, \ + .name = cname, \ + .parent_names = (const char *[]){ pname }, \ + .num_parents = 1, \ + .muxdiv_offset = io, \ + .div_shift = is, \ + .div_flags = if, \ + } + void rockchip_clk_init(struct device_node *np, void __iomem *base, unsigned long nr_clks); struct regmap *rockchip_clk_get_grf(void); -- cgit v1.3-6-gb490 From 7c494ad0581a31b20d2e8c397e0a28a6ffcabf8a Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sun, 5 Jul 2015 11:00:15 +0200 Subject: clk: rockchip: fix issues in the mmc-phase clock The review for the new inverter clock type uncovered some issues (missing headers and name handling) that are also present in the mmc-phase clock type, I got (to much) inspiration from. Fix these there too. Signed-off-by: Heiko Stuebner Signed-off-by: Stephen Boyd --- drivers/clk/rockchip/clk-mmc-phase.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index e9f8df324e7c..f2c6889f289c 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -15,6 +15,8 @@ #include #include +#include +#include #include "clk.h" struct rockchip_mmc_clock { @@ -131,6 +133,7 @@ struct clk *rockchip_clk_register_mmc(const char *name, if (!mmc_clock) return NULL; + init.name = name; init.num_parents = num_parents; init.parent_names = parent_names; init.ops = &rockchip_mmc_clk_ops; @@ -139,9 +142,6 @@ struct clk *rockchip_clk_register_mmc(const char *name, mmc_clock->reg = reg; mmc_clock->shift = shift; - if (name) - init.name = name; - clk = clk_register(NULL, &mmc_clock->hw); if (IS_ERR(clk)) goto err_free; -- cgit v1.3-6-gb490 From 4534b1113e4a4c649caac03f7787fbf4c4595718 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sun, 5 Jul 2015 11:00:16 +0200 Subject: clk: rockchip: define the inverters of rk3066/rk3188 and rk3288 Both soc series' have inverters on the hsadc and camera interface clock paths. So define them using the newly added inverter type. Signed-off-by: Heiko Stuebner Signed-off-by: Stephen Boyd --- drivers/clk/rockchip/clk-rk3188.c | 9 ++++++++- drivers/clk/rockchip/clk-rk3288.c | 7 ++++++- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index e4f9d472f1ff..a9ab4f9c1305 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -235,6 +235,7 @@ static struct rockchip_pll_clock rk3188_pll_clks[] __initdata = { #define MFLAGS CLK_MUX_HIWORD_MASK #define DFLAGS CLK_DIVIDER_HIWORD_MASK #define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE) +#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK /* 2 ^ (val + 1) */ static struct clk_div_table div_core_peri_t[] = { @@ -310,6 +311,8 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { GATE(0, "pclkin_cif0", "ext_cif0", 0, RK2928_CLKGATE_CON(3), 3, GFLAGS), + INVERTER(0, "pclk_cif0", "pclkin_cif0", + RK2928_CLKSEL_CON(30), 8, IFLAGS), /* * the 480m are generated inside the usb block from these clocks, @@ -334,8 +337,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { COMPOSITE_FRAC(0, "hsadc_frac", "hsadc_src", 0, RK2928_CLKSEL_CON(23), 0, RK2928_CLKGATE_CON(2), 7, GFLAGS), - MUX(SCLK_HSADC, "sclk_hsadc", mux_sclk_hsadc_p, 0, + MUX(0, "sclk_hsadc_out", mux_sclk_hsadc_p, 0, RK2928_CLKSEL_CON(22), 4, 2, MFLAGS), + INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out", + RK2928_CLKSEL_CON(22), 7, IFLAGS), COMPOSITE_NOMUX(SCLK_SARADC, "sclk_saradc", "xin24m", 0, RK2928_CLKSEL_CON(24), 8, 8, DFLAGS, @@ -557,6 +562,8 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { GATE(0, "pclkin_cif1", "ext_cif1", 0, RK2928_CLKGATE_CON(3), 4, GFLAGS), + INVERTER(0, "pclk_cif1", "pclkin_cif1", + RK2928_CLKSEL_CON(30), 12, IFLAGS), COMPOSITE(0, "aclk_gpu_src", mux_pll_src_cpll_gpll_p, 0, RK2928_CLKSEL_CON(33), 8, 1, MFLAGS, 0, 5, DFLAGS, diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index df9dc9630e6c..a8bad7d3a487 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -223,6 +223,7 @@ static struct clk_div_table div_hclk_cpu_t[] = { #define MFLAGS CLK_MUX_HIWORD_MASK #define DFLAGS CLK_DIVIDER_HIWORD_MASK #define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE) +#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { /* @@ -592,8 +593,10 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0, RK3288_CLKSEL_CON(22), 0, 1, MFLAGS, 8, 8, DFLAGS, RK3288_CLKGATE_CON(2), 6, GFLAGS), - MUX(SCLK_HSADC, "sclk_hsadc_out", mux_hsadcout_p, 0, + MUX(0, "sclk_hsadc_out", mux_hsadcout_p, 0, RK3288_CLKSEL_CON(22), 4, 1, MFLAGS), + INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out", + RK3288_CLKSEL_CON(22), 7, IFLAGS), GATE(0, "jtag", "ext_jtag", 0, RK3288_CLKGATE_CON(4), 14, GFLAGS), @@ -768,7 +771,9 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { */ GATE(0, "pclk_vip_in", "ext_vip", 0, RK3288_CLKGATE_CON(16), 0, GFLAGS), + INVERTER(0, "pclk_vip", "pclk_vip_in", RK3288_CLKSEL_CON(29), 4, IFLAGS), GATE(0, "pclk_isp_in", "ext_isp", 0, RK3288_CLKGATE_CON(16), 3, GFLAGS), + INVERTER(0, "pclk_isp", "pclk_isp_in", RK3288_CLKSEL_CON(29), 3, IFLAGS), }; static const char *const rk3288_critical_clocks[] __initconst = { -- cgit v1.3-6-gb490 From 3536c97a52db2848d13512878c65affd98fd29db Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Sun, 5 Jul 2015 11:00:20 +0200 Subject: clk: rockchip: add rk3368 clock controller Describe the clock tree and software resets of the rk3368 ARM64 SoC Signed-off-by: Heiko Stuebner Signed-off-by: Stephen Boyd --- drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk-rk3368.c | 881 ++++++++++++++++++++++++++++++++++++++ drivers/clk/rockchip/clk.h | 16 + 3 files changed, 898 insertions(+) create mode 100644 drivers/clk/rockchip/clk-rk3368.c (limited to 'drivers') diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index fd71c7df03d1..b27edd6c8183 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_RESET_CONTROLLER) += softrst.o obj-y += clk-rk3188.o obj-y += clk-rk3288.o +obj-y += clk-rk3368.o diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c new file mode 100644 index 000000000000..9c5d61e698ef --- /dev/null +++ b/drivers/clk/rockchip/clk-rk3368.c @@ -0,0 +1,881 @@ +/* + * Copyright (c) 2015 Heiko Stuebner + * + * 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 +#include +#include "clk.h" + +#define RK3368_GRF_SOC_STATUS0 0x480 + +enum rk3368_plls { + apllb, aplll, dpll, cpll, gpll, npll, +}; + +static struct rockchip_pll_rate_table rk3368_pll_rates[] = { + RK3066_PLL_RATE(2208000000, 1, 92, 1), + RK3066_PLL_RATE(2184000000, 1, 91, 1), + RK3066_PLL_RATE(2160000000, 1, 90, 1), + RK3066_PLL_RATE(2136000000, 1, 89, 1), + RK3066_PLL_RATE(2112000000, 1, 88, 1), + RK3066_PLL_RATE(2088000000, 1, 87, 1), + RK3066_PLL_RATE(2064000000, 1, 86, 1), + RK3066_PLL_RATE(2040000000, 1, 85, 1), + RK3066_PLL_RATE(2016000000, 1, 84, 1), + RK3066_PLL_RATE(1992000000, 1, 83, 1), + RK3066_PLL_RATE(1968000000, 1, 82, 1), + RK3066_PLL_RATE(1944000000, 1, 81, 1), + RK3066_PLL_RATE(1920000000, 1, 80, 1), + RK3066_PLL_RATE(1896000000, 1, 79, 1), + RK3066_PLL_RATE(1872000000, 1, 78, 1), + RK3066_PLL_RATE(1848000000, 1, 77, 1), + RK3066_PLL_RATE(1824000000, 1, 76, 1), + RK3066_PLL_RATE(1800000000, 1, 75, 1), + RK3066_PLL_RATE(1776000000, 1, 74, 1), + RK3066_PLL_RATE(1752000000, 1, 73, 1), + RK3066_PLL_RATE(1728000000, 1, 72, 1), + RK3066_PLL_RATE(1704000000, 1, 71, 1), + RK3066_PLL_RATE(1680000000, 1, 70, 1), + RK3066_PLL_RATE(1656000000, 1, 69, 1), + RK3066_PLL_RATE(1632000000, 1, 68, 1), + RK3066_PLL_RATE(1608000000, 1, 67, 1), + RK3066_PLL_RATE(1560000000, 1, 65, 1), + RK3066_PLL_RATE(1512000000, 1, 63, 1), + RK3066_PLL_RATE(1488000000, 1, 62, 1), + RK3066_PLL_RATE(1464000000, 1, 61, 1), + RK3066_PLL_RATE(1440000000, 1, 60, 1), + RK3066_PLL_RATE(1416000000, 1, 59, 1), + RK3066_PLL_RATE(1392000000, 1, 58, 1), + RK3066_PLL_RATE(1368000000, 1, 57, 1), + RK3066_PLL_RATE(1344000000, 1, 56, 1), + RK3066_PLL_RATE(1320000000, 1, 55, 1), + RK3066_PLL_RATE(1296000000, 1, 54, 1), + RK3066_PLL_RATE(1272000000, 1, 53, 1), + RK3066_PLL_RATE(1248000000, 1, 52, 1), + RK3066_PLL_RATE(1224000000, 1, 51, 1), + RK3066_PLL_RATE(1200000000, 1, 50, 1), + RK3066_PLL_RATE(1176000000, 1, 49, 1), + RK3066_PLL_RATE(1128000000, 1, 47, 1), + RK3066_PLL_RATE(1104000000, 1, 46, 1), + RK3066_PLL_RATE(1008000000, 1, 84, 2), + RK3066_PLL_RATE( 912000000, 1, 76, 2), + RK3066_PLL_RATE( 888000000, 1, 74, 2), + RK3066_PLL_RATE( 816000000, 1, 68, 2), + RK3066_PLL_RATE( 792000000, 1, 66, 2), + RK3066_PLL_RATE( 696000000, 1, 58, 2), + RK3066_PLL_RATE( 672000000, 1, 56, 2), + RK3066_PLL_RATE( 648000000, 1, 54, 2), + RK3066_PLL_RATE( 624000000, 1, 52, 2), + RK3066_PLL_RATE( 600000000, 1, 50, 2), + RK3066_PLL_RATE( 576000000, 1, 48, 2), + RK3066_PLL_RATE( 552000000, 1, 46, 2), + RK3066_PLL_RATE( 528000000, 1, 88, 4), + RK3066_PLL_RATE( 504000000, 1, 84, 4), + RK3066_PLL_RATE( 480000000, 1, 80, 4), + RK3066_PLL_RATE( 456000000, 1, 76, 4), + RK3066_PLL_RATE( 408000000, 1, 68, 4), + RK3066_PLL_RATE( 312000000, 1, 52, 4), + RK3066_PLL_RATE( 252000000, 1, 84, 8), + RK3066_PLL_RATE( 216000000, 1, 72, 8), + RK3066_PLL_RATE( 126000000, 2, 84, 8), + RK3066_PLL_RATE( 48000000, 2, 32, 8), + { /* sentinel */ }, +}; + +PNAME(mux_pll_p) = { "xin24m", "xin32k" }; +PNAME(mux_armclkb_p) = { "apllb_core", "gpllb_core" }; +PNAME(mux_armclkl_p) = { "aplll_core", "gplll_core" }; +PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; +PNAME(mux_cs_src_p) = { "apllb_cs", "aplll_cs", "gpll_cs"}; +PNAME(mux_aclk_bus_src_p) = { "cpll_aclk_bus", "gpll_aclk_bus" }; + +PNAME(mux_pll_src_cpll_gpll_p) = { "cpll", "gpll" }; +PNAME(mux_pll_src_cpll_gpll_npll_p) = { "cpll", "gpll", "npll" }; +PNAME(mux_pll_src_npll_cpll_gpll_p) = { "npll", "cpll", "gpll" }; +PNAME(mux_pll_src_cpll_gpll_usb_p) = { "cpll", "gpll", "usbphy_480m" }; +PNAME(mux_pll_src_cpll_gpll_usb_usb_p) = { "cpll", "gpll", "usbphy_480m", + "usbphy_480m" }; +PNAME(mux_pll_src_cpll_gpll_usb_npll_p) = { "cpll", "gpll", "usbphy_480m", + "npll" }; +PNAME(mux_pll_src_cpll_gpll_npll_npll_p) = { "cpll", "gpll", "npll", "npll" }; +PNAME(mux_pll_src_cpll_gpll_npll_usb_p) = { "cpll", "gpll", "npll", + "usbphy_480m" }; + +PNAME(mux_i2s_8ch_pre_p) = { "i2s_8ch_src", "i2s_8ch_frac", + "ext_i2s", "xin12m" }; +PNAME(mux_i2s_8ch_clkout_p) = { "i2s_8ch_pre", "xin12m" }; +PNAME(mux_i2s_2ch_p) = { "i2s_2ch_src", "i2s_2ch_frac", + "dummy", "xin12m" }; +PNAME(mux_spdif_8ch_p) = { "spdif_8ch_pre", "spdif_8ch_frac", + "ext_i2s", "xin12m" }; +PNAME(mux_edp_24m_p) = { "dummy", "xin24m" }; +PNAME(mux_vip_out_p) = { "vip_src", "xin24m" }; +PNAME(mux_usbphy480m_p) = { "usbotg_out", "xin24m" }; +PNAME(mux_hsic_usbphy480m_p) = { "usbotg_out", "dummy" }; +PNAME(mux_hsicphy480m_p) = { "cpll", "gpll", "usbphy_480m" }; +PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" }; +PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" }; +PNAME(mux_uart2_p) = { "uart2_src", "xin24m" }; +PNAME(mux_uart3_p) = { "uart3_src", "uart3_frac", "xin24m" }; +PNAME(mux_uart4_p) = { "uart4_src", "uart4_frac", "xin24m" }; +PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" }; +PNAME(mux_mmc_src_p) = { "cpll", "gpll", "usbphy_480m", "xin24m" }; + +static struct rockchip_pll_clock rk3368_pll_clks[] __initdata = { + [apllb] = PLL(pll_rk3066, PLL_APLLB, "apllb", mux_pll_p, 0, RK3368_PLL_CON(0), + RK3368_PLL_CON(3), 8, 1, 0, rk3368_pll_rates), + [aplll] = PLL(pll_rk3066, PLL_APLLL, "aplll", mux_pll_p, 0, RK3368_PLL_CON(4), + RK3368_PLL_CON(7), 8, 0, 0, rk3368_pll_rates), + [dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK3368_PLL_CON(8), + RK3368_PLL_CON(11), 8, 2, 0, NULL), + [cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK3368_PLL_CON(12), + RK3368_PLL_CON(15), 8, 3, ROCKCHIP_PLL_SYNC_RATE, rk3368_pll_rates), + [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK3368_PLL_CON(16), + RK3368_PLL_CON(19), 8, 4, ROCKCHIP_PLL_SYNC_RATE, rk3368_pll_rates), + [npll] = PLL(pll_rk3066, PLL_NPLL, "npll", mux_pll_p, 0, RK3368_PLL_CON(20), + RK3368_PLL_CON(23), 8, 5, ROCKCHIP_PLL_SYNC_RATE, rk3368_pll_rates), +}; + +static struct clk_div_table div_ddrphy_t[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 3, .div = 4 }, + { /* sentinel */ }, +}; + +#define MFLAGS CLK_MUX_HIWORD_MASK +#define DFLAGS CLK_DIVIDER_HIWORD_MASK +#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE) +#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK + +static const struct rockchip_cpuclk_reg_data rk3368_cpuclkb_data = { + .core_reg = RK3368_CLKSEL_CON(0), + .div_core_shift = 0, + .div_core_mask = 0x1f, + .mux_core_shift = 15, +}; + +static const struct rockchip_cpuclk_reg_data rk3368_cpuclkl_data = { + .core_reg = RK3368_CLKSEL_CON(2), + .div_core_shift = 0, + .div_core_mask = 0x1f, + .mux_core_shift = 7, +}; + +#define RK3368_DIV_ACLKM_MASK 0x1f +#define RK3368_DIV_ACLKM_SHIFT 8 +#define RK3368_DIV_ATCLK_MASK 0x1f +#define RK3368_DIV_ATCLK_SHIFT 0 +#define RK3368_DIV_PCLK_DBG_MASK 0x1f +#define RK3368_DIV_PCLK_DBG_SHIFT 8 + +#define RK3368_CLKSEL0(_offs, _aclkm) \ + { \ + .reg = RK3288_CLKSEL_CON(0 + _offs), \ + .val = HIWORD_UPDATE(_aclkm, RK3368_DIV_ACLKM_MASK, \ + RK3368_DIV_ACLKM_SHIFT), \ + } +#define RK3368_CLKSEL1(_offs, _atclk, _pdbg) \ + { \ + .reg = RK3288_CLKSEL_CON(1 + _offs), \ + .val = HIWORD_UPDATE(_atclk, RK3368_DIV_ATCLK_MASK, \ + RK3368_DIV_ATCLK_SHIFT) | \ + HIWORD_UPDATE(_pdbg, RK3368_DIV_PCLK_DBG_MASK, \ + RK3368_DIV_PCLK_DBG_SHIFT), \ + } + +/* cluster_b: aclkm in clksel0, rest in clksel1 */ +#define RK3368_CPUCLKB_RATE(_prate, _aclkm, _atclk, _pdbg) \ + { \ + .prate = _prate, \ + .divs = { \ + RK3368_CLKSEL0(0, _aclkm), \ + RK3368_CLKSEL1(0, _atclk, _pdbg), \ + }, \ + } + +/* cluster_l: aclkm in clksel2, rest in clksel3 */ +#define RK3368_CPUCLKL_RATE(_prate, _aclkm, _atclk, _pdbg) \ + { \ + .prate = _prate, \ + .divs = { \ + RK3368_CLKSEL0(2, _aclkm), \ + RK3368_CLKSEL1(2, _atclk, _pdbg), \ + }, \ + } + +static struct rockchip_cpuclk_rate_table rk3368_cpuclkb_rates[] __initdata = { + RK3368_CPUCLKB_RATE(1512000000, 2, 6, 6), + RK3368_CPUCLKB_RATE(1488000000, 2, 5, 5), + RK3368_CPUCLKB_RATE(1416000000, 2, 5, 5), + RK3368_CPUCLKB_RATE(1200000000, 2, 4, 4), + RK3368_CPUCLKB_RATE(1008000000, 2, 4, 4), + RK3368_CPUCLKB_RATE( 816000000, 2, 3, 3), + RK3368_CPUCLKB_RATE( 696000000, 2, 3, 3), + RK3368_CPUCLKB_RATE( 600000000, 2, 2, 2), + RK3368_CPUCLKB_RATE( 408000000, 2, 2, 2), + RK3368_CPUCLKB_RATE( 312000000, 2, 2, 2), +}; + +static struct rockchip_cpuclk_rate_table rk3368_cpuclkl_rates[] __initdata = { + RK3368_CPUCLKL_RATE(1512000000, 2, 7, 7), + RK3368_CPUCLKL_RATE(1488000000, 2, 6, 6), + RK3368_CPUCLKL_RATE(1416000000, 2, 6, 6), + RK3368_CPUCLKL_RATE(1200000000, 2, 5, 5), + RK3368_CPUCLKL_RATE(1008000000, 2, 5, 5), + RK3368_CPUCLKL_RATE( 816000000, 2, 4, 4), + RK3368_CPUCLKL_RATE( 696000000, 2, 3, 3), + RK3368_CPUCLKL_RATE( 600000000, 2, 3, 3), + RK3368_CPUCLKL_RATE( 408000000, 2, 2, 2), + RK3368_CPUCLKL_RATE( 312000000, 2, 2, 2), +}; + +static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { + /* + * Clock-Architecture Diagram 2 + */ + + MUX(SCLK_USBPHY480M, "usbphy_480m", mux_usbphy480m_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(13), 8, 1, MFLAGS), + + GATE(0, "apllb_core", "apllb", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 0, GFLAGS), + GATE(0, "gpllb_core", "gpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 1, GFLAGS), + + GATE(0, "aplll_core", "aplll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 4, GFLAGS), + GATE(0, "gplll_core", "gpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 5, GFLAGS), + + DIV(0, "aclkm_core_b", "armclkb", 0, + RK3368_CLKSEL_CON(0), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + DIV(0, "atclk_core_b", "armclkb", 0, + RK3368_CLKSEL_CON(1), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + DIV(0, "pclk_dbg_b", "armclkb", 0, + RK3368_CLKSEL_CON(1), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + + DIV(0, "aclkm_core_l", "armclkl", 0, + RK3368_CLKSEL_CON(2), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + DIV(0, "atclk_core_l", "armclkl", 0, + RK3368_CLKSEL_CON(3), 0, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + DIV(0, "pclk_dbg_l", "armclkl", 0, + RK3368_CLKSEL_CON(3), 8, 5, DFLAGS | CLK_DIVIDER_READ_ONLY), + + GATE(0, "apllb_cs", "apllb", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 9, GFLAGS), + GATE(0, "aplll_cs", "aplll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 10, GFLAGS), + GATE(0, "gpll_cs", "gpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(0), 8, GFLAGS), + COMPOSITE_NOGATE(0, "sclk_cs_pre", mux_cs_src_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(4), 6, 2, MFLAGS, 0, 5, DFLAGS), + COMPOSITE_NOMUX(0, "clkin_trace", "sclk_cs_pre", CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(4), 8, 5, DFLAGS, + RK3368_CLKGATE_CON(0), 13, GFLAGS), + + COMPOSITE(0, "aclk_cci_pre", mux_pll_src_cpll_gpll_usb_npll_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(5), 6, 2, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(0), 12, GFLAGS), + GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3368_CLKGATE_CON(7), 10, GFLAGS), + + GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(1), 8, GFLAGS), + GATE(0, "gpll_ddr", "gpll", 0, + RK3368_CLKGATE_CON(1), 9, GFLAGS), + COMPOSITE_NOGATE_DIVTBL(0, "ddrphy_src", mux_ddrphy_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(13), 4, 1, MFLAGS, 0, 2, DFLAGS, div_ddrphy_t), + + GATE(0, "sclk_ddr", "ddrphy_div4", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(6), 14, GFLAGS), + GATE(0, "sclk_ddr4x", "ddrphy_src", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(6), 15, GFLAGS), + + GATE(0, "gpll_aclk_bus", "gpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(1), 10, GFLAGS), + GATE(0, "cpll_aclk_bus", "cpll", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(1), 11, GFLAGS), + COMPOSITE_NOGATE(0, "aclk_bus_src", mux_aclk_bus_src_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(8), 7, 1, MFLAGS, 0, 5, DFLAGS), + + GATE(ACLK_BUS, "aclk_bus", "aclk_bus_src", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(1), 0, GFLAGS), + COMPOSITE_NOMUX(PCLK_BUS, "pclk_bus", "aclk_bus_src", CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(8), 12, 3, DFLAGS, + RK3368_CLKGATE_CON(1), 2, GFLAGS), + COMPOSITE_NOMUX(HCLK_BUS, "hclk_bus", "aclk_bus_src", CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(8), 8, 2, DFLAGS, + RK3368_CLKGATE_CON(1), 1, GFLAGS), + COMPOSITE_NOMUX(0, "sclk_crypto", "aclk_bus_src", 0, + RK3368_CLKSEL_CON(10), 14, 2, DFLAGS, + RK3368_CLKGATE_CON(7), 2, GFLAGS), + + COMPOSITE(0, "fclk_mcu_src", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(12), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(1), 3, GFLAGS), + /* + * stclk_mcu is listed as child of fclk_mcu_src in diagram 5, + * but stclk_mcu has an additional own divider in diagram 2 + */ + COMPOSITE_NOMUX(0, "stclk_mcu", "fclk_mcu_src", 0, + RK3368_CLKSEL_CON(12), 8, 3, DFLAGS, + RK3368_CLKGATE_CON(13), 13, GFLAGS), + + COMPOSITE(0, "i2s_8ch_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(27), 12, 1, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(6), 1, GFLAGS), + COMPOSITE_FRAC(0, "i2s_8ch_frac", "i2s_8ch_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(28), 0, + RK3368_CLKGATE_CON(6), 2, GFLAGS), + MUX(0, "i2s_8ch_pre", mux_i2s_8ch_pre_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(27), 8, 2, MFLAGS), + COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "i2s_8ch_clkout", mux_i2s_8ch_clkout_p, 0, + RK3368_CLKSEL_CON(27), 15, 1, MFLAGS, + RK3368_CLKGATE_CON(6), 0, GFLAGS), + GATE(SCLK_I2S_8CH, "sclk_i2s_8ch", "i2s_8ch_pre", CLK_SET_RATE_PARENT, + RK3368_CLKGATE_CON(6), 3, GFLAGS), + COMPOSITE(0, "spdif_8ch_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(31), 12, 1, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(6), 4, GFLAGS), + COMPOSITE_FRAC(0, "spdif_8ch_frac", "spdif_8ch_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(32), 0, + RK3368_CLKGATE_CON(6), 5, GFLAGS), + COMPOSITE_NODIV(SCLK_SPDIF_8CH, "sclk_spdif_8ch", mux_spdif_8ch_p, 0, + RK3368_CLKSEL_CON(31), 8, 2, MFLAGS, + RK3368_CLKGATE_CON(6), 6, GFLAGS), + COMPOSITE(0, "i2s_2ch_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(53), 12, 1, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(5), 13, GFLAGS), + COMPOSITE_FRAC(0, "i2s_2ch_frac", "i2s_2ch_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(54), 0, + RK3368_CLKGATE_CON(5), 14, GFLAGS), + COMPOSITE_NODIV(SCLK_I2S_2CH, "sclk_i2s_2ch", mux_i2s_2ch_p, 0, + RK3368_CLKSEL_CON(53), 8, 2, MFLAGS, + RK3368_CLKGATE_CON(5), 15, GFLAGS), + + COMPOSITE(0, "sclk_tsp", mux_pll_src_cpll_gpll_npll_p, 0, + RK3368_CLKSEL_CON(46), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(6), 12, GFLAGS), + GATE(0, "sclk_hsadc_tsp", "ext_hsadc_tsp", 0, + RK3368_CLKGATE_CON(13), 7, GFLAGS), + + MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(35), 12, 1, MFLAGS), + COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0, + RK3368_CLKSEL_CON(37), 0, 7, DFLAGS, + RK3368_CLKGATE_CON(2), 4, GFLAGS), + MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(37), 8, 1, MFLAGS), + + /* + * Clock-Architecture Diagram 3 + */ + + COMPOSITE(0, "aclk_vepu", mux_pll_src_cpll_gpll_usb_p, 0, + RK3368_CLKSEL_CON(15), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 6, GFLAGS), + COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_usb_p, 0, + RK3368_CLKSEL_CON(15), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 7, GFLAGS), + + /* + * We introduce a virtual node of hclk_vodec_pre_v to split one clock + * struct with a gate and a fix divider into two node in software. + */ + GATE(0, "hclk_video_pre_v", "aclk_vdpu", 0, + RK3368_CLKGATE_CON(4), 8, GFLAGS), + + COMPOSITE(0, "sclk_hevc_cabac_src", mux_pll_src_cpll_gpll_npll_usb_p, 0, + RK3368_CLKSEL_CON(17), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(5), 1, GFLAGS), + COMPOSITE(0, "sclk_hevc_core_src", mux_pll_src_cpll_gpll_npll_usb_p, 0, + RK3368_CLKSEL_CON(17), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3368_CLKGATE_CON(5), 2, GFLAGS), + + COMPOSITE(0, "aclk_vio0", mux_pll_src_cpll_gpll_usb_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(19), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 0, GFLAGS), + DIV(0, "hclk_vio", "aclk_vio0", 0, + RK3368_CLKSEL_CON(21), 0, 5, DFLAGS), + + COMPOSITE(0, "aclk_rga_pre", mux_pll_src_cpll_gpll_usb_p, 0, + RK3368_CLKSEL_CON(18), 14, 2, MFLAGS, 8, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 3, GFLAGS), + COMPOSITE(SCLK_RGA, "sclk_rga", mux_pll_src_cpll_gpll_usb_p, 0, + RK3368_CLKSEL_CON(18), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 4, GFLAGS), + + COMPOSITE(DCLK_VOP, "dclk_vop", mux_pll_src_cpll_gpll_npll_p, 0, + RK3368_CLKSEL_CON(20), 8, 2, MFLAGS, 0, 8, DFLAGS, + RK3368_CLKGATE_CON(4), 1, GFLAGS), + + GATE(SCLK_VOP0_PWM, "sclk_vop0_pwm", "xin24m", 0, + RK3368_CLKGATE_CON(4), 2, GFLAGS), + + COMPOSITE(SCLK_ISP, "sclk_isp", mux_pll_src_cpll_gpll_npll_npll_p, 0, + RK3368_CLKSEL_CON(22), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3368_CLKGATE_CON(4), 9, GFLAGS), + + GATE(0, "pclk_isp_in", "ext_isp", 0, + RK3368_CLKGATE_CON(17), 2, GFLAGS), + INVERTER(PCLK_ISP, "pclk_isp", "pclk_isp_in", + RK3368_CLKSEL_CON(21), 6, IFLAGS), + + GATE(0, "pclk_vip_in", "ext_vip", 0, + RK3368_CLKGATE_CON(16), 13, GFLAGS), + INVERTER(PCLK_VIP, "pclk_vip", "pclk_vip_in", + RK3368_CLKSEL_CON(21), 13, IFLAGS), + + GATE(SCLK_HDMI_HDCP, "sclk_hdmi_hdcp", "xin24m", 0, + RK3368_CLKGATE_CON(4), 13, GFLAGS), + GATE(SCLK_HDMI_CEC, "sclk_hdmi_cec", "xin32k", 0, + RK3368_CLKGATE_CON(5), 12, GFLAGS), + + COMPOSITE_NODIV(0, "vip_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(21), 15, 1, MFLAGS, + RK3368_CLKGATE_CON(4), 5, GFLAGS), + COMPOSITE_NOGATE(0, "sclk_vip_out", mux_vip_out_p, 0, + RK3368_CLKSEL_CON(21), 14, 1, MFLAGS, 8, 5, DFLAGS), + + COMPOSITE_NODIV(SCLK_EDP_24M, "sclk_edp_24m", mux_edp_24m_p, 0, + RK3368_CLKSEL_CON(23), 8, 1, MFLAGS, + RK3368_CLKGATE_CON(5), 4, GFLAGS), + COMPOSITE(SCLK_EDP, "sclk_edp", mux_pll_src_cpll_gpll_npll_npll_p, 0, + RK3368_CLKSEL_CON(23), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3368_CLKGATE_CON(5), 3, GFLAGS), + + COMPOSITE(SCLK_HDCP, "sclk_hdcp", mux_pll_src_cpll_gpll_npll_npll_p, 0, + RK3368_CLKSEL_CON(55), 6, 2, MFLAGS, 0, 6, DFLAGS, + RK3368_CLKGATE_CON(5), 5, GFLAGS), + + DIV(0, "pclk_pd_alive", "gpll", 0, + RK3368_CLKSEL_CON(10), 8, 5, DFLAGS), + + /* sclk_timer has a gate in the sgrf */ + + COMPOSITE_NOMUX(0, "pclk_pd_pmu", "gpll", CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(10), 0, 5, DFLAGS, + RK3368_CLKGATE_CON(7), 9, GFLAGS), + GATE(SCLK_PVTM_PMU, "sclk_pvtm_pmu", "xin24m", 0, + RK3368_CLKGATE_CON(7), 3, GFLAGS), + COMPOSITE(0, "sclk_gpu_core_src", mux_pll_src_cpll_gpll_usb_npll_p, 0, + RK3368_CLKSEL_CON(14), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(4), 11, GFLAGS), + MUX(0, "aclk_gpu_src", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(14), 14, 1, MFLAGS), + COMPOSITE_NOMUX(0, "aclk_gpu_mem_pre", "aclk_gpu_src", 0, + RK3368_CLKSEL_CON(14), 8, 5, DFLAGS, + RK3368_CLKGATE_CON(5), 8, GFLAGS), + COMPOSITE_NOMUX(0, "aclk_gpu_cfg_pre", "aclk_gpu_src", 0, + RK3368_CLKSEL_CON(16), 8, 5, DFLAGS, + RK3368_CLKGATE_CON(5), 9, GFLAGS), + GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, + RK3368_CLKGATE_CON(7), 11, GFLAGS), + + COMPOSITE(0, "aclk_peri_src", mux_pll_src_cpll_gpll_p, CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(9), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(3), 0, GFLAGS), + COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0, + RK3368_CLKSEL_CON(9), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK3368_CLKGATE_CON(3), 3, GFLAGS), + COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_src", CLK_IGNORE_UNUSED, + RK3368_CLKSEL_CON(9), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK3368_CLKGATE_CON(3), 2, GFLAGS), + GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(3), 1, GFLAGS), + + GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3368_CLKGATE_CON(4), 14, GFLAGS), + + /* + * Clock-Architecture Diagram 4 + */ + + COMPOSITE(SCLK_SPI0, "sclk_spi0", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(45), 7, 1, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(3), 7, GFLAGS), + COMPOSITE(SCLK_SPI1, "sclk_spi1", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(45), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3368_CLKGATE_CON(3), 8, GFLAGS), + COMPOSITE(SCLK_SPI2, "sclk_spi2", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(46), 15, 1, MFLAGS, 8, 7, DFLAGS, + RK3368_CLKGATE_CON(3), 9, GFLAGS), + + + COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0, + RK3368_CLKSEL_CON(50), 8, 2, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(7), 12, GFLAGS), + COMPOSITE(SCLK_SDIO0, "sclk_sdio0", mux_mmc_src_p, 0, + RK3368_CLKSEL_CON(48), 8, 2, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(7), 13, GFLAGS), + COMPOSITE(SCLK_EMMC, "sclk_emmc", mux_mmc_src_p, 0, + RK3368_CLKSEL_CON(51), 8, 2, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(7), 15, GFLAGS), + + MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3368_SDMMC_CON0, 1), + MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3368_SDMMC_CON1, 0), + + MMC(SCLK_SDIO0_DRV, "sdio0_drv", "sclk_sdio0", RK3368_SDIO0_CON0, 1), + MMC(SCLK_SDIO0_SAMPLE, "sdio0_sample", "sclk_sdio0", RK3368_SDIO0_CON1, 0), + + MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3368_EMMC_CON0, 1), + MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3368_EMMC_CON1, 0), + + GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin24m", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(8), 1, GFLAGS), + + /* pmu_grf_soc_con0[6] allows to select between xin32k and pvtm_pmu */ + GATE(SCLK_OTG_ADP, "sclk_otg_adp", "xin32k", CLK_IGNORE_UNUSED, + RK3368_CLKGATE_CON(8), 4, GFLAGS), + + /* pmu_grf_soc_con0[6] allows to select between xin32k and pvtm_pmu */ + COMPOSITE_NOMUX(SCLK_TSADC, "sclk_tsadc", "xin32k", 0, + RK3368_CLKSEL_CON(25), 0, 6, DFLAGS, + RK3368_CLKGATE_CON(3), 5, GFLAGS), + + COMPOSITE_NOMUX(SCLK_SARADC, "sclk_saradc", "xin24m", 0, + RK3368_CLKSEL_CON(25), 8, 8, DFLAGS, + RK3368_CLKGATE_CON(3), 6, GFLAGS), + + COMPOSITE(SCLK_NANDC0, "sclk_nandc0", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(47), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(7), 8, GFLAGS), + + COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(52), 7, 1, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(6), 7, GFLAGS), + + COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gpll_usb_usb_p, 0, + RK3368_CLKSEL_CON(33), 12, 2, MFLAGS, 0, 7, DFLAGS, + RK3368_CLKGATE_CON(2), 0, GFLAGS), + COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(34), 0, + RK3368_CLKGATE_CON(2), 1, GFLAGS), + MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(33), 8, 2, MFLAGS), + + COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0, + RK3368_CLKSEL_CON(35), 0, 7, DFLAGS, + RK3368_CLKGATE_CON(2), 2, GFLAGS), + COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(36), 0, + RK3368_CLKGATE_CON(2), 3, GFLAGS), + MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(35), 8, 2, MFLAGS), + + COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0, + RK3368_CLKSEL_CON(39), 0, 7, DFLAGS, + RK3368_CLKGATE_CON(2), 6, GFLAGS), + COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(40), 0, + RK3368_CLKGATE_CON(2), 7, GFLAGS), + MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(39), 8, 2, MFLAGS), + + COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0, + RK3368_CLKSEL_CON(41), 0, 7, DFLAGS, + RK3368_CLKGATE_CON(2), 8, GFLAGS), + COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(42), 0, + RK3368_CLKGATE_CON(2), 9, GFLAGS), + MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(41), 8, 2, MFLAGS), + + COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0, + RK3368_CLKSEL_CON(43), 6, 2, MFLAGS, 0, 5, DFLAGS, + RK3368_CLKGATE_CON(3), 4, GFLAGS), + MUX(SCLK_MAC, "mac_clk", mux_mac_p, CLK_SET_RATE_PARENT, + RK3368_CLKSEL_CON(43), 8, 1, MFLAGS), + GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0, + RK3368_CLKGATE_CON(7), 7, GFLAGS), + GATE(SCLK_MACREF, "sclk_macref", "mac_clk", 0, + RK3368_CLKGATE_CON(7), 6, GFLAGS), + GATE(SCLK_MAC_RX, "sclk_mac_rx", "mac_clk", 0, + RK3368_CLKGATE_CON(7), 4, GFLAGS), + GATE(SCLK_MAC_TX, "sclk_mac_tx", "mac_clk", 0, + RK3368_CLKGATE_CON(7), 5, GFLAGS), + + GATE(0, "jtag", "ext_jtag", 0, + RK3368_CLKGATE_CON(7), 0, GFLAGS), + + COMPOSITE_NODIV(0, "hsic_usbphy_480m", mux_hsic_usbphy480m_p, 0, + RK3368_CLKSEL_CON(26), 8, 2, MFLAGS, + RK3368_CLKGATE_CON(8), 0, GFLAGS), + COMPOSITE_NODIV(SCLK_HSICPHY480M, "sclk_hsicphy480m", mux_hsicphy480m_p, 0, + RK3368_CLKSEL_CON(26), 12, 2, MFLAGS, + RK3368_CLKGATE_CON(8), 7, GFLAGS), + GATE(SCLK_HSICPHY12M, "sclk_hsicphy12m", "xin12m", 0, + RK3368_CLKGATE_CON(8), 6, GFLAGS), + + /* + * Clock-Architecture Diagram 5 + */ + + /* aclk_cci_pre gates */ + GATE(0, "aclk_core_niu_cpup", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 4, GFLAGS), + GATE(0, "aclk_core_niu_cci", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 3, GFLAGS), + GATE(0, "aclk_cci400", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 2, GFLAGS), + GATE(0, "aclk_adb400m_pd_core_b", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 1, GFLAGS), + GATE(0, "aclk_adb400m_pd_core_l", "aclk_cci_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 0, GFLAGS), + + /* aclkm_core_* gates */ + GATE(0, "aclk_adb400s_pd_core_b", "aclkm_core_b", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(10), 0, GFLAGS), + GATE(0, "aclk_adb400s_pd_core_l", "aclkm_core_l", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(9), 0, GFLAGS), + + /* armclk* gates */ + GATE(0, "sclk_dbg_pd_core_b", "armclkb", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(10), 1, GFLAGS), + GATE(0, "sclk_dbg_pd_core_l", "armclkl", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(9), 1, GFLAGS), + + /* sclk_cs_pre gates */ + GATE(0, "sclk_dbg", "sclk_cs_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 7, GFLAGS), + GATE(0, "pclk_core_niu_sdbg", "sclk_cs_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 6, GFLAGS), + GATE(0, "hclk_core_niu_dbg", "sclk_cs_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(11), 5, GFLAGS), + + /* aclk_bus gates */ + GATE(0, "aclk_strc_sys", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 12, GFLAGS), + GATE(ACLK_DMAC_BUS, "aclk_dmac_bus", "aclk_bus", 0, RK3368_CLKGATE_CON(12), 11, GFLAGS), + GATE(0, "sclk_intmem1", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 6, GFLAGS), + GATE(0, "sclk_intmem0", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 5, GFLAGS), + GATE(0, "aclk_intmem", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 4, GFLAGS), + GATE(0, "aclk_gic400", "aclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(13), 9, GFLAGS), + + /* sclk_ddr gates */ + GATE(0, "nclk_ddrupctl", "sclk_ddr", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(13), 2, GFLAGS), + + /* clk_hsadc_tsp is part of diagram2 */ + + /* fclk_mcu_src gates */ + GATE(0, "hclk_noc_mcu", "fclk_mcu_src", 0, RK3368_CLKGATE_CON(13), 14, GFLAGS), + GATE(0, "fclk_mcu", "fclk_mcu_src", 0, RK3368_CLKGATE_CON(13), 12, GFLAGS), + GATE(0, "hclk_mcu", "fclk_mcu_src", 0, RK3368_CLKGATE_CON(13), 11, GFLAGS), + + /* hclk_cpu gates */ + GATE(HCLK_SPDIF, "hclk_spdif", "hclk_bus", 0, RK3368_CLKGATE_CON(12), 10, GFLAGS), + GATE(HCLK_ROM, "hclk_rom", "hclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 9, GFLAGS), + GATE(HCLK_I2S_2CH, "hclk_i2s_2ch", "hclk_bus", 0, RK3368_CLKGATE_CON(12), 8, GFLAGS), + GATE(HCLK_I2S_8CH, "hclk_i2s_8ch", "hclk_bus", 0, RK3368_CLKGATE_CON(12), 7, GFLAGS), + GATE(HCLK_TSP, "hclk_tsp", "hclk_bus", 0, RK3368_CLKGATE_CON(13), 10, GFLAGS), + GATE(HCLK_CRYPTO, "hclk_crypto", "hclk_bus", 0, RK3368_CLKGATE_CON(13), 4, GFLAGS), + GATE(MCLK_CRYPTO, "mclk_crypto", "hclk_bus", 0, RK3368_CLKGATE_CON(13), 3, GFLAGS), + + /* pclk_cpu gates */ + GATE(PCLK_DDRPHY, "pclk_ddrphy", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 14, GFLAGS), + GATE(PCLK_DDRUPCTL, "pclk_ddrupctl", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 13, GFLAGS), + GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 3, GFLAGS), + GATE(PCLK_I2C0, "pclk_i2c0", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 2, GFLAGS), + GATE(PCLK_MAILBOX, "pclk_mailbox", "pclk_bus", 0, RK3368_CLKGATE_CON(12), 1, GFLAGS), + GATE(PCLK_PWM0, "pclk_pwm0", "pclk_bus", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(12), 0, GFLAGS), + GATE(PCLK_SIM, "pclk_sim", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 8, GFLAGS), + GATE(PCLK_PWM1, "pclk_pwm1", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 6, GFLAGS), + GATE(PCLK_UART2, "pclk_uart2", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 5, GFLAGS), + GATE(0, "pclk_efuse_256", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 1, GFLAGS), + GATE(0, "pclk_efuse_1024", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 0, GFLAGS), + + /* + * video clk gates + * aclk_video(_pre) can actually select between parents of aclk_vdpu + * and aclk_vepu by setting bit GRF_SOC_CON0[7]. + */ + GATE(ACLK_VIDEO, "aclk_video", "aclk_vdpu", 0, RK3368_CLKGATE_CON(15), 0, GFLAGS), + GATE(SCLK_HEVC_CABAC, "sclk_hevc_cabac", "sclk_hevc_cabac_src", 0, RK3368_CLKGATE_CON(15), 3, GFLAGS), + GATE(SCLK_HEVC_CORE, "sclk_hevc_core", "sclk_hevc_core_src", 0, RK3368_CLKGATE_CON(15), 2, GFLAGS), + GATE(HCLK_VIDEO, "hclk_video", "hclk_video_pre", 0, RK3368_CLKGATE_CON(15), 1, GFLAGS), + + /* aclk_rga_pre gates */ + GATE(ACLK_VIO1_NOC, "aclk_vio1_noc", "aclk_rga_pre", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 10, GFLAGS), + GATE(ACLK_RGA, "aclk_rga", "aclk_rga_pre", 0, RK3368_CLKGATE_CON(16), 0, GFLAGS), + GATE(ACLK_HDCP, "aclk_hdcp", "aclk_rga_pre", 0, RK3368_CLKGATE_CON(17), 10, GFLAGS), + + /* aclk_vio0 gates */ + GATE(ACLK_VIP, "aclk_vip", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 11, GFLAGS), + GATE(ACLK_VIO0_NOC, "aclk_vio0_noc", "aclk_vio0", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 9, GFLAGS), + GATE(ACLK_VOP, "aclk_vop", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 5, GFLAGS), + GATE(ACLK_VOP_IEP, "aclk_vop_iep", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 4, GFLAGS), + GATE(ACLK_IEP, "aclk_iep", "aclk_vio0", 0, RK3368_CLKGATE_CON(16), 2, GFLAGS), + + /* sclk_isp gates */ + GATE(HCLK_ISP, "hclk_isp", "sclk_isp", 0, RK3368_CLKGATE_CON(16), 14, GFLAGS), + GATE(ACLK_ISP, "aclk_isp", "sclk_isp", 0, RK3368_CLKGATE_CON(17), 0, GFLAGS), + + /* hclk_vio gates */ + GATE(HCLK_VIP, "hclk_vip", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 12, GFLAGS), + GATE(HCLK_VIO_NOC, "hclk_vio_noc", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 8, GFLAGS), + GATE(HCLK_VIO_AHB_ARBI, "hclk_vio_ahb_arbi", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(16), 7, GFLAGS), + GATE(HCLK_VOP, "hclk_vop", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 6, GFLAGS), + GATE(HCLK_IEP, "hclk_iep", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 3, GFLAGS), + GATE(HCLK_RGA, "hclk_rga", "hclk_vio", 0, RK3368_CLKGATE_CON(16), 1, GFLAGS), + GATE(HCLK_VIO_HDCPMMU, "hclk_hdcpmmu", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 12, GFLAGS), + GATE(HCLK_VIO_H2P, "hclk_vio_h2p", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 7, GFLAGS), + + /* + * pclk_vio gates + * pclk_vio comes from the exactly same source as hclk_vio + */ + GATE(PCLK_HDCP, "pclk_hdcp", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 11, GFLAGS), + GATE(PCLK_EDP_CTRL, "pclk_edp_ctrl", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 9, GFLAGS), + GATE(PCLK_VIO_H2P, "pclk_vio_h2p", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 8, GFLAGS), + GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 6, GFLAGS), + GATE(PCLK_MIPI_CSI, "pclk_mipi_csi", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 4, GFLAGS), + GATE(PCLK_MIPI_DSI0, "pclk_mipi_dsi0", "hclk_vio", 0, RK3368_CLKGATE_CON(17), 3, GFLAGS), + + /* ext_vip gates in diagram3 */ + + /* gpu gates */ + GATE(SCLK_GPU_CORE, "sclk_gpu_core", "sclk_gpu_core_src", 0, RK3368_CLKGATE_CON(18), 2, GFLAGS), + GATE(ACLK_GPU_MEM, "aclk_gpu_mem", "aclk_gpu_mem_pre", 0, RK3368_CLKGATE_CON(18), 1, GFLAGS), + GATE(ACLK_GPU_CFG, "aclk_gpu_cfg", "aclk_gpu_cfg_pre", 0, RK3368_CLKGATE_CON(18), 0, GFLAGS), + + /* aclk_peri gates */ + GATE(ACLK_DMAC_PERI, "aclk_dmac_peri", "aclk_peri", 0, RK3368_CLKGATE_CON(19), 3, GFLAGS), + GATE(0, "aclk_peri_axi_matrix", "aclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(19), 2, GFLAGS), + GATE(HCLK_SFC, "hclk_sfc", "aclk_peri", 0, RK3368_CLKGATE_CON(20), 15, GFLAGS), + GATE(ACLK_GMAC, "aclk_gmac", "aclk_peri", 0, RK3368_CLKGATE_CON(20), 13, GFLAGS), + GATE(0, "aclk_peri_niu", "aclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 8, GFLAGS), + GATE(ACLK_PERI_MMU, "aclk_peri_mmu", "aclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(21), 4, GFLAGS), + + /* hclk_peri gates */ + GATE(0, "hclk_peri_axi_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(19), 0, GFLAGS), + GATE(HCLK_NANDC0, "hclk_nandc0", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 11, GFLAGS), + GATE(0, "hclk_mmc_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 10, GFLAGS), + GATE(0, "hclk_emem_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 9, GFLAGS), + GATE(0, "hclk_peri_ahb_arbi", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 7, GFLAGS), + GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 6, GFLAGS), + GATE(HCLK_HSIC, "hclk_hsic", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 5, GFLAGS), + GATE(HCLK_HOST1, "hclk_host1", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 4, GFLAGS), + GATE(HCLK_HOST0, "hclk_host0", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 3, GFLAGS), + GATE(0, "pmu_hclk_otg0", "hclk_peri", 0, RK3368_CLKGATE_CON(20), 2, GFLAGS), + GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(20), 1, GFLAGS), + GATE(HCLK_HSADC, "hclk_hsadc", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 3, GFLAGS), + GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 2, GFLAGS), + GATE(HCLK_SDIO0, "hclk_sdio0", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 1, GFLAGS), + GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK3368_CLKGATE_CON(21), 0, GFLAGS), + + /* pclk_peri gates */ + GATE(PCLK_SARADC, "pclk_saradc", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 15, GFLAGS), + GATE(PCLK_I2C5, "pclk_i2c5", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 14, GFLAGS), + GATE(PCLK_I2C4, "pclk_i2c4", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 13, GFLAGS), + GATE(PCLK_I2C3, "pclk_i2c3", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 12, GFLAGS), + GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 11, GFLAGS), + GATE(PCLK_UART4, "pclk_uart4", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 10, GFLAGS), + GATE(PCLK_UART3, "pclk_uart3", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 9, GFLAGS), + GATE(PCLK_UART1, "pclk_uart1", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 8, GFLAGS), + GATE(PCLK_UART0, "pclk_uart0", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 7, GFLAGS), + GATE(PCLK_SPI2, "pclk_spi2", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 6, GFLAGS), + GATE(PCLK_SPI1, "pclk_spi1", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 5, GFLAGS), + GATE(PCLK_SPI0, "pclk_spi0", "pclk_peri", 0, RK3368_CLKGATE_CON(19), 4, GFLAGS), + GATE(0, "pclk_peri_axi_matrix", "pclk_peri", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(19), 1, GFLAGS), + GATE(PCLK_GMAC, "pclk_gmac", "pclk_peri", 0, RK3368_CLKGATE_CON(20), 14, GFLAGS), + GATE(PCLK_TSADC, "pclk_tsadc", "pclk_peri", 0, RK3368_CLKGATE_CON(20), 0, GFLAGS), + + /* pclk_pd_alive gates */ + GATE(PCLK_TIMER1, "pclk_timer1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 8, GFLAGS), + GATE(PCLK_TIMER0, "pclk_timer0", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 7, GFLAGS), + GATE(0, "pclk_alive_niu", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 12, GFLAGS), + GATE(PCLK_GRF, "pclk_grf", "pclk_pd_alive", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 11, GFLAGS), + GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 3, GFLAGS), + GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 2, GFLAGS), + GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_pd_alive", 0, RK3368_CLKGATE_CON(14), 1, GFLAGS), + + /* + * pclk_vio gates + * pclk_vio comes from the exactly same source as hclk_vio + */ + GATE(0, "pclk_dphyrx", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 8, GFLAGS), + GATE(0, "pclk_dphytx", "hclk_vio", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(14), 8, GFLAGS), + + /* pclk_pd_pmu gates */ + GATE(PCLK_PMUGRF, "pclk_pmugrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 0, GFLAGS), + GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_pd_pmu", 0, RK3368_CLKGATE_CON(17), 4, GFLAGS), + GATE(PCLK_SGRF, "pclk_sgrf", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 3, GFLAGS), + GATE(0, "pclk_pmu_noc", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS), + GATE(0, "pclk_intmem1", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 1, GFLAGS), + GATE(PCLK_PMU, "pclk_pmu", "pclk_pd_pmu", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(17), 2, GFLAGS), + + /* timer gates */ + GATE(0, "sclk_timer15", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 11, GFLAGS), + GATE(0, "sclk_timer14", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 10, GFLAGS), + GATE(0, "sclk_timer13", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 9, GFLAGS), + GATE(0, "sclk_timer12", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 8, GFLAGS), + GATE(0, "sclk_timer11", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 7, GFLAGS), + GATE(0, "sclk_timer10", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 6, GFLAGS), + GATE(0, "sclk_timer05", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 5, GFLAGS), + GATE(0, "sclk_timer04", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 4, GFLAGS), + GATE(0, "sclk_timer03", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 3, GFLAGS), + GATE(0, "sclk_timer02", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 2, GFLAGS), + GATE(0, "sclk_timer01", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 1, GFLAGS), + GATE(0, "sclk_timer00", "xin24m", CLK_IGNORE_UNUSED, RK3368_CLKGATE_CON(24), 0, GFLAGS), +}; + +static void __init rk3368_clk_init(struct device_node *np) +{ + void __iomem *reg_base; + struct clk *clk; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("%s: could not map cru region\n", __func__); + return; + } + + rockchip_clk_init(np, reg_base, CLK_NR_CLKS); + + /* xin12m is created by a cru-internal divider */ + clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock xin12m: %ld\n", + __func__, PTR_ERR(clk)); + + /* ddrphy_div4 is created by a cru-internal divider */ + clk = clk_register_fixed_factor(NULL, "ddrphy_div4", "ddrphy_src", 0, 1, 4); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock xin12m: %ld\n", + __func__, PTR_ERR(clk)); + + clk = clk_register_fixed_factor(NULL, "hclk_video_pre", + "hclk_video_pre_v", 0, 1, 4); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n", + __func__, PTR_ERR(clk)); + + /* Watchdog pclk is controlled by sgrf_soc_con3[7]. */ + clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1); + if (IS_ERR(clk)) + pr_warn("%s: could not register clock pclk_wdt: %ld\n", + __func__, PTR_ERR(clk)); + else + rockchip_clk_add_lookup(clk, PCLK_WDT); + + rockchip_clk_register_plls(rk3368_pll_clks, + ARRAY_SIZE(rk3368_pll_clks), + RK3368_GRF_SOC_STATUS0); + rockchip_clk_register_branches(rk3368_clk_branches, + ARRAY_SIZE(rk3368_clk_branches)); + + rockchip_clk_register_armclk(ARMCLKB, "armclkb", + mux_armclkb_p, ARRAY_SIZE(mux_armclkb_p), + &rk3368_cpuclkb_data, rk3368_cpuclkb_rates, + ARRAY_SIZE(rk3368_cpuclkb_rates)); + + rockchip_clk_register_armclk(ARMCLKL, "armclkl", + mux_armclkl_p, ARRAY_SIZE(mux_armclkl_p), + &rk3368_cpuclkl_data, rk3368_cpuclkl_rates, + ARRAY_SIZE(rk3368_cpuclkl_rates)); + + rockchip_register_softrst(np, 15, reg_base + RK3368_SOFTRST_CON(0), + ROCKCHIP_SOFTRST_HIWORD_MASK); + + rockchip_register_restart_notifier(RK3368_GLB_SRST_FST); +} +CLK_OF_DECLARE(rk3368_cru, "rockchip,rk3368-cru", rk3368_clk_init); diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index b72dad074a75..f506df85e543 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -57,6 +57,22 @@ #define RK3288_EMMC_CON0 0x218 #define RK3288_EMMC_CON1 0x21c +#define RK3368_PLL_CON(x) RK2928_PLL_CON(x) +#define RK3368_CLKSEL_CON(x) ((x) * 0x4 + 0x100) +#define RK3368_CLKGATE_CON(x) ((x) * 0x4 + 0x200) +#define RK3368_GLB_SRST_FST 0x280 +#define RK3368_GLB_SRST_SND 0x284 +#define RK3368_SOFTRST_CON(x) ((x) * 0x4 + 0x300) +#define RK3368_MISC_CON 0x380 +#define RK3368_SDMMC_CON0 0x400 +#define RK3368_SDMMC_CON1 0x404 +#define RK3368_SDIO0_CON0 0x408 +#define RK3368_SDIO0_CON1 0x40c +#define RK3368_SDIO1_CON0 0x410 +#define RK3368_SDIO1_CON1 0x414 +#define RK3368_EMMC_CON0 0x418 +#define RK3368_EMMC_CON1 0x41c + enum rockchip_pll_type { pll_rk3066, }; -- cgit v1.3-6-gb490 From ec7478fa173f65e5ee5fd2ba42c59ca3e700027b Mon Sep 17 00:00:00 2001 From: shengyong Date: Thu, 25 Jun 2015 02:23:13 +0000 Subject: mtd: nandsim: fix free of NULL pointer If allocating ns->nand_pages_slab fails, do not try to destroy it when cleaning up nandsim resources. Signed-off-by: Sheng Yong Signed-off-by: Brian Norris --- drivers/mtd/nand/nandsim.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 52c0c1a3899c..6a74f62a0033 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -649,7 +649,8 @@ static void free_device(struct nandsim *ns) kmem_cache_free(ns->nand_pages_slab, ns->pages[i].byte); } - kmem_cache_destroy(ns->nand_pages_slab); + if (ns->nand_pages_slab) + kmem_cache_destroy(ns->nand_pages_slab); vfree(ns->pages); } } -- cgit v1.3-6-gb490 From 5891a8d11f79b9a45a7334a63d0fa731875bc308 Mon Sep 17 00:00:00 2001 From: shengyong Date: Thu, 25 Jun 2015 02:23:14 +0000 Subject: mtd: nandsim: fix double free Do not call free_device() in init_nandsim, the caller - ns_init_module - will take care of that if something goes wrong. Signed-off-by: Sheng Yong Signed-off-by: Brian Norris --- drivers/mtd/nand/nandsim.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 6a74f62a0033..95d0cc49cfc2 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -730,8 +730,7 @@ static int init_nandsim(struct mtd_info *mtd) /* Fill the partition_info structure */ if (parts_num > ARRAY_SIZE(ns->partitions)) { NS_ERR("too many partitions.\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } remains = ns->geom.totsz; next_offset = 0; @@ -740,14 +739,12 @@ static int init_nandsim(struct mtd_info *mtd) if (!part_sz || part_sz > remains) { NS_ERR("bad partition size.\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } ns->partitions[i].name = get_partition_name(i); if (!ns->partitions[i].name) { NS_ERR("unable to allocate memory.\n"); - ret = -ENOMEM; - goto error; + return -ENOMEM; } ns->partitions[i].offset = next_offset; ns->partitions[i].size = part_sz; @@ -758,14 +755,12 @@ static int init_nandsim(struct mtd_info *mtd) if (remains) { if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) { NS_ERR("too many partitions.\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } ns->partitions[i].name = get_partition_name(i); if (!ns->partitions[i].name) { NS_ERR("unable to allocate memory.\n"); - ret = -ENOMEM; - goto error; + return -ENOMEM; } ns->partitions[i].offset = next_offset; ns->partitions[i].size = remains; @@ -793,24 +788,18 @@ static int init_nandsim(struct mtd_info *mtd) printk("options: %#x\n", ns->options); if ((ret = alloc_device(ns)) != 0) - goto error; + return ret; /* Allocate / initialize the internal buffer */ ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); if (!ns->buf.byte) { NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", ns->geom.pgszoob); - ret = -ENOMEM; - goto error; + return -ENOMEM; } memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); return 0; - -error: - free_device(ns); - - return ret; } /* -- cgit v1.3-6-gb490 From e21b08e2f3e1ebb13d5930bd994cfaada22ed58b Mon Sep 17 00:00:00 2001 From: Sergej Sawazki Date: Sun, 28 Jun 2015 16:24:53 +0200 Subject: clk: gpio-gate: Include export.h instead of module.h Include export.h for EXPORT_SYMBOL_GPL, no need to include module.h. Cc: Jyri Sarha Signed-off-by: Sergej Sawazki Signed-off-by: Stephen Boyd --- drivers/clk/clk-gpio-gate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c index f564e624fb93..a377f8848f0a 100644 --- a/drivers/clk/clk-gpio-gate.c +++ b/drivers/clk/clk-gpio-gate.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include #include #include -- cgit v1.3-6-gb490 From 281cbb007612814183d79b1f72d0395303fcfb6f Mon Sep 17 00:00:00 2001 From: Sergej Sawazki Date: Sun, 28 Jun 2015 16:24:54 +0200 Subject: clk: gpio-gate: Stay silent on EPROBE_DEFER Do not output an error message if requesting gpio failes with EPROBE_DEFER. Cc: Jyri Sarha Signed-off-by: Sergej Sawazki Signed-off-by: Stephen Boyd --- drivers/clk/clk-gpio-gate.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c index a377f8848f0a..ef942daa955a 100644 --- a/drivers/clk/clk-gpio-gate.c +++ b/drivers/clk/clk-gpio-gate.c @@ -90,8 +90,9 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, err = gpio_request_one(gpio, gpio_flags, name); if (err) { - pr_err("%s: %s: Error requesting clock control gpio %u\n", - __func__, name, gpio); + if (err != -EPROBE_DEFER) + pr_err("%s: %s: Error requesting clock control gpio %u\n", + __func__, name, gpio); return ERR_PTR(err); } -- cgit v1.3-6-gb490 From 80eeb1f0f757c790b020d9f425bb0e824973d49c Mon Sep 17 00:00:00 2001 From: Sergej Sawazki Date: Sun, 28 Jun 2015 16:24:55 +0200 Subject: clk: add gpio controlled clock multiplexer Add a common clock driver for basic gpio controlled clock multiplexers. This driver can be used for devices like 5V41068A or 831721I from IDT or for discrete multiplexer circuits. The 'select' pin selects one of two parent clocks. Cc: Jyri Sarha Signed-off-by: Sergej Sawazki [sboyd@codeaurora.org: Fix error paths to free memory and do it in the correct order] Signed-off-by: Stephen Boyd --- .../devicetree/bindings/clock/gpio-mux-clock.txt | 19 ++ drivers/clk/clk-gpio-gate.c | 242 +++++++++++++++------ include/linux/clk-provider.h | 17 ++ 3 files changed, 214 insertions(+), 64 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/gpio-mux-clock.txt (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/clock/gpio-mux-clock.txt b/Documentation/devicetree/bindings/clock/gpio-mux-clock.txt new file mode 100644 index 000000000000..2be1e038ca62 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/gpio-mux-clock.txt @@ -0,0 +1,19 @@ +Binding for simple gpio clock multiplexer. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "gpio-mux-clock". +- clocks: list of two references to parent clocks. +- #clock-cells : from common clock binding; shall be set to 0. +- select-gpios : GPIO reference for selecting the parent clock. + +Example: + clock { + compatible = "gpio-mux-clock"; + clocks = <&parentclk1>, <&parentclk2>; + #clock-cells = <0>; + select-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; + }; diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c index ef942daa955a..c0d202c24a97 100644 --- a/drivers/clk/clk-gpio-gate.c +++ b/drivers/clk/clk-gpio-gate.c @@ -1,12 +1,15 @@ /* * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com - * Author: Jyri Sarha + * + * Authors: + * Jyri Sarha + * Sergej Sawazki * * 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. * - * Gpio gated clock implementation + * Gpio controlled clock implementation */ #include @@ -61,24 +64,55 @@ const struct clk_ops clk_gpio_gate_ops = { EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); /** - * clk_register_gpio - register a gpip clock with the clock framework - * @dev: device that is registering this clock - * @name: name of this clock - * @parent_name: name of this clock's parent - * @gpio: gpio number to gate this clock - * @active_low: true if gpio should be set to 0 to enable clock - * @flags: clock flags + * DOC: basic clock multiplexer which can be controlled with a gpio output + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * rate - rate is only affected by parent switching. No clk_set_rate support + * parent - parent is adjustable through clk_set_parent */ -struct clk *clk_register_gpio_gate(struct device *dev, const char *name, - const char *parent_name, unsigned gpio, bool active_low, - unsigned long flags) + +static u8 clk_gpio_mux_get_parent(struct clk_hw *hw) { - struct clk_gpio *clk_gpio = NULL; - struct clk *clk = ERR_PTR(-EINVAL); - struct clk_init_data init = { NULL }; + struct clk_gpio *clk = to_clk_gpio(hw); + + return gpiod_get_value(clk->gpiod); +} + +static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value(clk->gpiod, index); + + return 0; +} + +const struct clk_ops clk_gpio_mux_ops = { + .get_parent = clk_gpio_mux_get_parent, + .set_parent = clk_gpio_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_gpio_mux_ops); + +static struct clk *clk_register_gpio(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags, + const struct clk_ops *clk_gpio_ops) +{ + struct clk_gpio *clk_gpio; + struct clk *clk; + struct clk_init_data init = {}; unsigned long gpio_flags; int err; + if (dev) + clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL); + else + clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL); + + if (!clk_gpio) + return ERR_PTR(-ENOMEM); + if (active_low) gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH; else @@ -88,70 +122,108 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, err = devm_gpio_request_one(dev, gpio, gpio_flags, name); else err = gpio_request_one(gpio, gpio_flags, name); - if (err) { if (err != -EPROBE_DEFER) pr_err("%s: %s: Error requesting clock control gpio %u\n", __func__, name, gpio); - return ERR_PTR(err); - } - - if (dev) - clk_gpio = devm_kzalloc(dev, sizeof(struct clk_gpio), - GFP_KERNEL); - else - clk_gpio = kzalloc(sizeof(struct clk_gpio), GFP_KERNEL); + if (!dev) + kfree(clk_gpio); - if (!clk_gpio) { - clk = ERR_PTR(-ENOMEM); - goto clk_register_gpio_gate_err; + return ERR_PTR(err); } init.name = name; - init.ops = &clk_gpio_gate_ops; + init.ops = clk_gpio_ops; init.flags = flags | CLK_IS_BASIC; - init.parent_names = (parent_name ? &parent_name : NULL); - init.num_parents = (parent_name ? 1 : 0); + init.parent_names = parent_names; + init.num_parents = num_parents; clk_gpio->gpiod = gpio_to_desc(gpio); clk_gpio->hw.init = &init; - clk = clk_register(dev, &clk_gpio->hw); + if (dev) + clk = devm_clk_register(dev, &clk_gpio->hw); + else + clk = clk_register(NULL, &clk_gpio->hw); if (!IS_ERR(clk)) return clk; - if (!dev) + if (!dev) { + gpiod_put(clk_gpio->gpiod); kfree(clk_gpio); - -clk_register_gpio_gate_err: - if (!dev) - gpio_free(gpio); + } return clk; } + +/** + * clk_register_gpio_gate - register a gpio clock gate with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_name: name of this clock's parent + * @gpio: gpio number to gate this clock + * @active_low: true if gpio should be set to 0 to enable clock + * @flags: clock flags + */ +struct clk *clk_register_gpio_gate(struct device *dev, const char *name, + const char *parent_name, unsigned gpio, bool active_low, + unsigned long flags) +{ + return clk_register_gpio(dev, name, + (parent_name ? &parent_name : NULL), + (parent_name ? 1 : 0), gpio, active_low, flags, + &clk_gpio_gate_ops); +} EXPORT_SYMBOL_GPL(clk_register_gpio_gate); +/** + * clk_register_gpio_mux - register a gpio clock mux with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_names: names of this clock's parents + * @num_parents: number of parents listed in @parent_names + * @gpio: gpio number to gate this clock + * @active_low: true if gpio should be set to 0 to enable clock + * @flags: clock flags + */ +struct clk *clk_register_gpio_mux(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags) +{ + if (num_parents != 2) { + pr_err("mux-clock %s must have 2 parents\n", name); + return ERR_PTR(-EINVAL); + } + + return clk_register_gpio(dev, name, parent_names, num_parents, + gpio, active_low, flags, &clk_gpio_mux_ops); +} +EXPORT_SYMBOL_GPL(clk_register_gpio_mux); + #ifdef CONFIG_OF /** - * The clk_register_gpio_gate has to be delayed, because the EPROBE_DEFER + * clk_register_get() has to be delayed, because -EPROBE_DEFER * can not be handled properly at of_clk_init() call time. */ -struct clk_gpio_gate_delayed_register_data { +struct clk_gpio_delayed_register_data { + const char *gpio_name; struct device_node *node; struct mutex lock; struct clk *clk; + struct clk *(*clk_register_get)(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low); }; -static struct clk *of_clk_gpio_gate_delayed_register_get( - struct of_phandle_args *clkspec, - void *_data) +static struct clk *of_clk_gpio_delayed_register_get( + struct of_phandle_args *clkspec, void *_data) { - struct clk_gpio_gate_delayed_register_data *data = _data; + struct clk_gpio_delayed_register_data *data = _data; struct clk *clk; - const char *clk_name = data->node->name; - const char *parent_name; + const char **parent_names; + int i, num_parents; int gpio; enum of_gpio_flags of_flags; @@ -162,47 +234,89 @@ static struct clk *of_clk_gpio_gate_delayed_register_get( return data->clk; } - gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0, - &of_flags); + gpio = of_get_named_gpio_flags(data->node, data->gpio_name, 0, + &of_flags); if (gpio < 0) { mutex_unlock(&data->lock); - if (gpio != -EPROBE_DEFER) - pr_err("%s: %s: Can't get 'enable-gpios' DT property\n", - __func__, clk_name); + if (gpio == -EPROBE_DEFER) + pr_debug("%s: %s: GPIOs not yet available, retry later\n", + data->node->name, __func__); + else + pr_err("%s: %s: Can't get '%s' DT property\n", + data->node->name, __func__, + data->gpio_name); return ERR_PTR(gpio); } - parent_name = of_clk_get_parent_name(data->node, 0); + num_parents = of_clk_get_parent_count(data->node); - clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpio, - of_flags & OF_GPIO_ACTIVE_LOW, 0); - if (IS_ERR(clk)) { - mutex_unlock(&data->lock); - return clk; - } + parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); + if (!parent_names) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(data->node, i); + + clk = data->clk_register_get(data->node->name, parent_names, + num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); + if (IS_ERR(clk)) + goto out; data->clk = clk; +out: mutex_unlock(&data->lock); + kfree(parent_names); return clk; } -/** - * of_gpio_gate_clk_setup() - Setup function for gpio controlled clock - */ -static void __init of_gpio_gate_clk_setup(struct device_node *node) +static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low) +{ + return clk_register_gpio_gate(NULL, name, parent_names[0], + gpio, active_low, 0); +} + +static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low) +{ + return clk_register_gpio_mux(NULL, name, parent_names, num_parents, + gpio, active_low, 0); +} + +static void __init of_gpio_clk_setup(struct device_node *node, + const char *gpio_name, + struct clk *(*clk_register_get)(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low)) { - struct clk_gpio_gate_delayed_register_data *data; + struct clk_gpio_delayed_register_data *data; - data = kzalloc(sizeof(struct clk_gpio_gate_delayed_register_data), - GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return; data->node = node; + data->gpio_name = gpio_name; + data->clk_register_get = clk_register_get; mutex_init(&data->lock); - of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data); + of_clk_add_provider(node, of_clk_gpio_delayed_register_get, data); +} + +static void __init of_gpio_gate_clk_setup(struct device_node *node) +{ + of_gpio_clk_setup(node, "enable-gpios", + of_clk_gpio_gate_delayed_register_get); } CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup); + +void __init of_gpio_mux_clk_setup(struct device_node *node) +{ + of_gpio_clk_setup(node, "select-gpios", + of_clk_gpio_mux_delayed_register_get); +} +CLK_OF_DECLARE(gpio_mux_clk, "gpio-mux-clock", of_gpio_mux_clk_setup); #endif diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 78842f46f152..823d7f70878e 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -549,6 +549,23 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, void of_gpio_clk_gate_setup(struct device_node *node); +/** + * struct clk_gpio_mux - gpio controlled clock multiplexer + * + * @hw: see struct clk_gpio + * @gpiod: gpio descriptor to select the parent of this clock multiplexer + * + * Clock with a gpio control for selecting the parent clock. + * Implements .get_parent, .set_parent and .determine_rate + */ + +extern const struct clk_ops clk_gpio_mux_ops; +struct clk *clk_register_gpio_mux(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags); + +void of_gpio_mux_clk_setup(struct device_node *node); + /** * clk_register - allocate a new clock, register it and return an opaque cookie * @dev: device that is registering this clock -- cgit v1.3-6-gb490 From bb68a4f1e5ef7f2cebe84c57e465afa68a6ab911 Mon Sep 17 00:00:00 2001 From: Sergej Sawazki Date: Sun, 28 Jun 2015 16:24:56 +0200 Subject: clk: Rename clk-gpio-gate.c to clk-gpio.c The file clk-gpio-gate.c does not only contain the gate clock, but also the mux clock. Rename the file to clk-gpio.c. Cc: Jyri Sarha Signed-off-by: Sergej Sawazki Signed-off-by: Stephen Boyd --- drivers/clk/Makefile | 2 +- drivers/clk/clk-gpio-gate.c | 322 -------------------------------------------- drivers/clk/clk-gpio.c | 322 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 323 insertions(+), 323 deletions(-) delete mode 100644 drivers/clk/clk-gpio-gate.c create mode 100644 drivers/clk/clk-gpio.c (limited to 'drivers') diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index c4cf075a2320..d08b3e5985be 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-gate.o obj-$(CONFIG_COMMON_CLK) += clk-mux.o obj-$(CONFIG_COMMON_CLK) += clk-composite.o obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o -obj-$(CONFIG_COMMON_CLK) += clk-gpio-gate.o +obj-$(CONFIG_COMMON_CLK) += clk-gpio.o ifeq ($(CONFIG_OF), y) obj-$(CONFIG_COMMON_CLK) += clk-conf.o endif diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c deleted file mode 100644 index c0d202c24a97..000000000000 --- a/drivers/clk/clk-gpio-gate.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: - * Jyri Sarha - * Sergej Sawazki - * - * 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. - * - * Gpio controlled clock implementation - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * DOC: basic gpio gated clock which can be enabled and disabled - * with gpio output - * Traits of this clock: - * prepare - clk_(un)prepare only ensures parent is (un)prepared - * enable - clk_enable and clk_disable are functional & control gpio - * rate - inherits rate from parent. No clk_set_rate support - * parent - fixed parent. No clk_set_parent support - */ - -#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw) - -static int clk_gpio_gate_enable(struct clk_hw *hw) -{ - struct clk_gpio *clk = to_clk_gpio(hw); - - gpiod_set_value(clk->gpiod, 1); - - return 0; -} - -static void clk_gpio_gate_disable(struct clk_hw *hw) -{ - struct clk_gpio *clk = to_clk_gpio(hw); - - gpiod_set_value(clk->gpiod, 0); -} - -static int clk_gpio_gate_is_enabled(struct clk_hw *hw) -{ - struct clk_gpio *clk = to_clk_gpio(hw); - - return gpiod_get_value(clk->gpiod); -} - -const struct clk_ops clk_gpio_gate_ops = { - .enable = clk_gpio_gate_enable, - .disable = clk_gpio_gate_disable, - .is_enabled = clk_gpio_gate_is_enabled, -}; -EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); - -/** - * DOC: basic clock multiplexer which can be controlled with a gpio output - * Traits of this clock: - * prepare - clk_prepare only ensures that parents are prepared - * rate - rate is only affected by parent switching. No clk_set_rate support - * parent - parent is adjustable through clk_set_parent - */ - -static u8 clk_gpio_mux_get_parent(struct clk_hw *hw) -{ - struct clk_gpio *clk = to_clk_gpio(hw); - - return gpiod_get_value(clk->gpiod); -} - -static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_gpio *clk = to_clk_gpio(hw); - - gpiod_set_value(clk->gpiod, index); - - return 0; -} - -const struct clk_ops clk_gpio_mux_ops = { - .get_parent = clk_gpio_mux_get_parent, - .set_parent = clk_gpio_mux_set_parent, - .determine_rate = __clk_mux_determine_rate, -}; -EXPORT_SYMBOL_GPL(clk_gpio_mux_ops); - -static struct clk *clk_register_gpio(struct device *dev, const char *name, - const char **parent_names, u8 num_parents, unsigned gpio, - bool active_low, unsigned long flags, - const struct clk_ops *clk_gpio_ops) -{ - struct clk_gpio *clk_gpio; - struct clk *clk; - struct clk_init_data init = {}; - unsigned long gpio_flags; - int err; - - if (dev) - clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL); - else - clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL); - - if (!clk_gpio) - return ERR_PTR(-ENOMEM); - - if (active_low) - gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH; - else - gpio_flags = GPIOF_OUT_INIT_LOW; - - if (dev) - err = devm_gpio_request_one(dev, gpio, gpio_flags, name); - else - err = gpio_request_one(gpio, gpio_flags, name); - if (err) { - if (err != -EPROBE_DEFER) - pr_err("%s: %s: Error requesting clock control gpio %u\n", - __func__, name, gpio); - if (!dev) - kfree(clk_gpio); - - return ERR_PTR(err); - } - - init.name = name; - init.ops = clk_gpio_ops; - init.flags = flags | CLK_IS_BASIC; - init.parent_names = parent_names; - init.num_parents = num_parents; - - clk_gpio->gpiod = gpio_to_desc(gpio); - clk_gpio->hw.init = &init; - - if (dev) - clk = devm_clk_register(dev, &clk_gpio->hw); - else - clk = clk_register(NULL, &clk_gpio->hw); - - if (!IS_ERR(clk)) - return clk; - - if (!dev) { - gpiod_put(clk_gpio->gpiod); - kfree(clk_gpio); - } - - return clk; -} - -/** - * clk_register_gpio_gate - register a gpio clock gate with the clock framework - * @dev: device that is registering this clock - * @name: name of this clock - * @parent_name: name of this clock's parent - * @gpio: gpio number to gate this clock - * @active_low: true if gpio should be set to 0 to enable clock - * @flags: clock flags - */ -struct clk *clk_register_gpio_gate(struct device *dev, const char *name, - const char *parent_name, unsigned gpio, bool active_low, - unsigned long flags) -{ - return clk_register_gpio(dev, name, - (parent_name ? &parent_name : NULL), - (parent_name ? 1 : 0), gpio, active_low, flags, - &clk_gpio_gate_ops); -} -EXPORT_SYMBOL_GPL(clk_register_gpio_gate); - -/** - * clk_register_gpio_mux - register a gpio clock mux with the clock framework - * @dev: device that is registering this clock - * @name: name of this clock - * @parent_names: names of this clock's parents - * @num_parents: number of parents listed in @parent_names - * @gpio: gpio number to gate this clock - * @active_low: true if gpio should be set to 0 to enable clock - * @flags: clock flags - */ -struct clk *clk_register_gpio_mux(struct device *dev, const char *name, - const char **parent_names, u8 num_parents, unsigned gpio, - bool active_low, unsigned long flags) -{ - if (num_parents != 2) { - pr_err("mux-clock %s must have 2 parents\n", name); - return ERR_PTR(-EINVAL); - } - - return clk_register_gpio(dev, name, parent_names, num_parents, - gpio, active_low, flags, &clk_gpio_mux_ops); -} -EXPORT_SYMBOL_GPL(clk_register_gpio_mux); - -#ifdef CONFIG_OF -/** - * clk_register_get() has to be delayed, because -EPROBE_DEFER - * can not be handled properly at of_clk_init() call time. - */ - -struct clk_gpio_delayed_register_data { - const char *gpio_name; - struct device_node *node; - struct mutex lock; - struct clk *clk; - struct clk *(*clk_register_get)(const char *name, - const char **parent_names, u8 num_parents, - unsigned gpio, bool active_low); -}; - -static struct clk *of_clk_gpio_delayed_register_get( - struct of_phandle_args *clkspec, void *_data) -{ - struct clk_gpio_delayed_register_data *data = _data; - struct clk *clk; - const char **parent_names; - int i, num_parents; - int gpio; - enum of_gpio_flags of_flags; - - mutex_lock(&data->lock); - - if (data->clk) { - mutex_unlock(&data->lock); - return data->clk; - } - - gpio = of_get_named_gpio_flags(data->node, data->gpio_name, 0, - &of_flags); - if (gpio < 0) { - mutex_unlock(&data->lock); - if (gpio == -EPROBE_DEFER) - pr_debug("%s: %s: GPIOs not yet available, retry later\n", - data->node->name, __func__); - else - pr_err("%s: %s: Can't get '%s' DT property\n", - data->node->name, __func__, - data->gpio_name); - return ERR_PTR(gpio); - } - - num_parents = of_clk_get_parent_count(data->node); - - parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); - if (!parent_names) - return ERR_PTR(-ENOMEM); - - for (i = 0; i < num_parents; i++) - parent_names[i] = of_clk_get_parent_name(data->node, i); - - clk = data->clk_register_get(data->node->name, parent_names, - num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); - if (IS_ERR(clk)) - goto out; - - data->clk = clk; -out: - mutex_unlock(&data->lock); - kfree(parent_names); - - return clk; -} - -static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name, - const char **parent_names, u8 num_parents, - unsigned gpio, bool active_low) -{ - return clk_register_gpio_gate(NULL, name, parent_names[0], - gpio, active_low, 0); -} - -static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name, - const char **parent_names, u8 num_parents, unsigned gpio, - bool active_low) -{ - return clk_register_gpio_mux(NULL, name, parent_names, num_parents, - gpio, active_low, 0); -} - -static void __init of_gpio_clk_setup(struct device_node *node, - const char *gpio_name, - struct clk *(*clk_register_get)(const char *name, - const char **parent_names, u8 num_parents, - unsigned gpio, bool active_low)) -{ - struct clk_gpio_delayed_register_data *data; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return; - - data->node = node; - data->gpio_name = gpio_name; - data->clk_register_get = clk_register_get; - mutex_init(&data->lock); - - of_clk_add_provider(node, of_clk_gpio_delayed_register_get, data); -} - -static void __init of_gpio_gate_clk_setup(struct device_node *node) -{ - of_gpio_clk_setup(node, "enable-gpios", - of_clk_gpio_gate_delayed_register_get); -} -CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup); - -void __init of_gpio_mux_clk_setup(struct device_node *node) -{ - of_gpio_clk_setup(node, "select-gpios", - of_clk_gpio_mux_delayed_register_get); -} -CLK_OF_DECLARE(gpio_mux_clk, "gpio-mux-clock", of_gpio_mux_clk_setup); -#endif diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c new file mode 100644 index 000000000000..c0d202c24a97 --- /dev/null +++ b/drivers/clk/clk-gpio.c @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com + * + * Authors: + * Jyri Sarha + * Sergej Sawazki + * + * 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. + * + * Gpio controlled clock implementation + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * DOC: basic gpio gated clock which can be enabled and disabled + * with gpio output + * Traits of this clock: + * prepare - clk_(un)prepare only ensures parent is (un)prepared + * enable - clk_enable and clk_disable are functional & control gpio + * rate - inherits rate from parent. No clk_set_rate support + * parent - fixed parent. No clk_set_parent support + */ + +#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw) + +static int clk_gpio_gate_enable(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value(clk->gpiod, 1); + + return 0; +} + +static void clk_gpio_gate_disable(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value(clk->gpiod, 0); +} + +static int clk_gpio_gate_is_enabled(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + return gpiod_get_value(clk->gpiod); +} + +const struct clk_ops clk_gpio_gate_ops = { + .enable = clk_gpio_gate_enable, + .disable = clk_gpio_gate_disable, + .is_enabled = clk_gpio_gate_is_enabled, +}; +EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); + +/** + * DOC: basic clock multiplexer which can be controlled with a gpio output + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * rate - rate is only affected by parent switching. No clk_set_rate support + * parent - parent is adjustable through clk_set_parent + */ + +static u8 clk_gpio_mux_get_parent(struct clk_hw *hw) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + return gpiod_get_value(clk->gpiod); +} + +static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_gpio *clk = to_clk_gpio(hw); + + gpiod_set_value(clk->gpiod, index); + + return 0; +} + +const struct clk_ops clk_gpio_mux_ops = { + .get_parent = clk_gpio_mux_get_parent, + .set_parent = clk_gpio_mux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_gpio_mux_ops); + +static struct clk *clk_register_gpio(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags, + const struct clk_ops *clk_gpio_ops) +{ + struct clk_gpio *clk_gpio; + struct clk *clk; + struct clk_init_data init = {}; + unsigned long gpio_flags; + int err; + + if (dev) + clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL); + else + clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL); + + if (!clk_gpio) + return ERR_PTR(-ENOMEM); + + if (active_low) + gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH; + else + gpio_flags = GPIOF_OUT_INIT_LOW; + + if (dev) + err = devm_gpio_request_one(dev, gpio, gpio_flags, name); + else + err = gpio_request_one(gpio, gpio_flags, name); + if (err) { + if (err != -EPROBE_DEFER) + pr_err("%s: %s: Error requesting clock control gpio %u\n", + __func__, name, gpio); + if (!dev) + kfree(clk_gpio); + + return ERR_PTR(err); + } + + init.name = name; + init.ops = clk_gpio_ops; + init.flags = flags | CLK_IS_BASIC; + init.parent_names = parent_names; + init.num_parents = num_parents; + + clk_gpio->gpiod = gpio_to_desc(gpio); + clk_gpio->hw.init = &init; + + if (dev) + clk = devm_clk_register(dev, &clk_gpio->hw); + else + clk = clk_register(NULL, &clk_gpio->hw); + + if (!IS_ERR(clk)) + return clk; + + if (!dev) { + gpiod_put(clk_gpio->gpiod); + kfree(clk_gpio); + } + + return clk; +} + +/** + * clk_register_gpio_gate - register a gpio clock gate with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_name: name of this clock's parent + * @gpio: gpio number to gate this clock + * @active_low: true if gpio should be set to 0 to enable clock + * @flags: clock flags + */ +struct clk *clk_register_gpio_gate(struct device *dev, const char *name, + const char *parent_name, unsigned gpio, bool active_low, + unsigned long flags) +{ + return clk_register_gpio(dev, name, + (parent_name ? &parent_name : NULL), + (parent_name ? 1 : 0), gpio, active_low, flags, + &clk_gpio_gate_ops); +} +EXPORT_SYMBOL_GPL(clk_register_gpio_gate); + +/** + * clk_register_gpio_mux - register a gpio clock mux with the clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @parent_names: names of this clock's parents + * @num_parents: number of parents listed in @parent_names + * @gpio: gpio number to gate this clock + * @active_low: true if gpio should be set to 0 to enable clock + * @flags: clock flags + */ +struct clk *clk_register_gpio_mux(struct device *dev, const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low, unsigned long flags) +{ + if (num_parents != 2) { + pr_err("mux-clock %s must have 2 parents\n", name); + return ERR_PTR(-EINVAL); + } + + return clk_register_gpio(dev, name, parent_names, num_parents, + gpio, active_low, flags, &clk_gpio_mux_ops); +} +EXPORT_SYMBOL_GPL(clk_register_gpio_mux); + +#ifdef CONFIG_OF +/** + * clk_register_get() has to be delayed, because -EPROBE_DEFER + * can not be handled properly at of_clk_init() call time. + */ + +struct clk_gpio_delayed_register_data { + const char *gpio_name; + struct device_node *node; + struct mutex lock; + struct clk *clk; + struct clk *(*clk_register_get)(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low); +}; + +static struct clk *of_clk_gpio_delayed_register_get( + struct of_phandle_args *clkspec, void *_data) +{ + struct clk_gpio_delayed_register_data *data = _data; + struct clk *clk; + const char **parent_names; + int i, num_parents; + int gpio; + enum of_gpio_flags of_flags; + + mutex_lock(&data->lock); + + if (data->clk) { + mutex_unlock(&data->lock); + return data->clk; + } + + gpio = of_get_named_gpio_flags(data->node, data->gpio_name, 0, + &of_flags); + if (gpio < 0) { + mutex_unlock(&data->lock); + if (gpio == -EPROBE_DEFER) + pr_debug("%s: %s: GPIOs not yet available, retry later\n", + data->node->name, __func__); + else + pr_err("%s: %s: Can't get '%s' DT property\n", + data->node->name, __func__, + data->gpio_name); + return ERR_PTR(gpio); + } + + num_parents = of_clk_get_parent_count(data->node); + + parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); + if (!parent_names) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < num_parents; i++) + parent_names[i] = of_clk_get_parent_name(data->node, i); + + clk = data->clk_register_get(data->node->name, parent_names, + num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW); + if (IS_ERR(clk)) + goto out; + + data->clk = clk; +out: + mutex_unlock(&data->lock); + kfree(parent_names); + + return clk; +} + +static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low) +{ + return clk_register_gpio_gate(NULL, name, parent_names[0], + gpio, active_low, 0); +} + +static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name, + const char **parent_names, u8 num_parents, unsigned gpio, + bool active_low) +{ + return clk_register_gpio_mux(NULL, name, parent_names, num_parents, + gpio, active_low, 0); +} + +static void __init of_gpio_clk_setup(struct device_node *node, + const char *gpio_name, + struct clk *(*clk_register_get)(const char *name, + const char **parent_names, u8 num_parents, + unsigned gpio, bool active_low)) +{ + struct clk_gpio_delayed_register_data *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return; + + data->node = node; + data->gpio_name = gpio_name; + data->clk_register_get = clk_register_get; + mutex_init(&data->lock); + + of_clk_add_provider(node, of_clk_gpio_delayed_register_get, data); +} + +static void __init of_gpio_gate_clk_setup(struct device_node *node) +{ + of_gpio_clk_setup(node, "enable-gpios", + of_clk_gpio_gate_delayed_register_get); +} +CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup); + +void __init of_gpio_mux_clk_setup(struct device_node *node) +{ + of_gpio_clk_setup(node, "select-gpios", + of_clk_gpio_mux_delayed_register_get); +} +CLK_OF_DECLARE(gpio_mux_clk, "gpio-mux-clock", of_gpio_mux_clk_setup); +#endif -- cgit v1.3-6-gb490 From 78e50c6def9cca448dbb028b57ec92a1589edc07 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Wed, 17 Jun 2015 23:28:49 +0200 Subject: clk: xgene: Delete duplicated name field X-Gene clocks implement it's name in the clock private struct. This is a duplication of the name field. We can delete the field and rely on the common implementation to retrieve the name. Signed-off-by: Matthias Brugger Signed-off-by: Stephen Boyd --- drivers/clk/clk-xgene.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index f26b3ac36b27..4caee9356407 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -60,7 +60,6 @@ enum xgene_pll_type { struct xgene_clk_pll { struct clk_hw hw; - const char *name; void __iomem *reg; spinlock_t *lock; u32 pll_offset; @@ -75,7 +74,7 @@ static int xgene_clk_pll_is_enabled(struct clk_hw *hw) u32 data; data = xgene_clk_read(pllclk->reg + pllclk->pll_offset); - pr_debug("%s pll %s\n", pllclk->name, + pr_debug("%s pll %s\n", __clk_get_name(hw->clk), data & REGSPEC_RESET_F1_MASK ? "disabled" : "enabled"); return data & REGSPEC_RESET_F1_MASK ? 0 : 1; @@ -113,7 +112,7 @@ static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw, fref = parent_rate / nref; fvco = fref * nfb; } - pr_debug("%s pll recalc rate %ld parent %ld\n", pllclk->name, + pr_debug("%s pll recalc rate %ld parent %ld\n", __clk_get_name(hw->clk), fvco / nout, parent_rate); return fvco / nout; @@ -146,7 +145,6 @@ static struct clk *xgene_register_clk_pll(struct device *dev, init.parent_names = parent_name ? &parent_name : NULL; init.num_parents = parent_name ? 1 : 0; - apmclk->name = name; apmclk->reg = reg; apmclk->lock = lock; apmclk->pll_offset = pll_offset; @@ -210,7 +208,6 @@ struct xgene_dev_parameters { struct xgene_clk { struct clk_hw hw; - const char *name; spinlock_t *lock; struct xgene_dev_parameters param; }; @@ -228,7 +225,7 @@ static int xgene_clk_enable(struct clk_hw *hw) spin_lock_irqsave(pclk->lock, flags); if (pclk->param.csr_reg != NULL) { - pr_debug("%s clock enabled\n", pclk->name); + pr_debug("%s clock enabled\n", __clk_get_name(hw->clk)); reg = __pa(pclk->param.csr_reg); /* First enable the clock */ data = xgene_clk_read(pclk->param.csr_reg + @@ -237,7 +234,7 @@ static int xgene_clk_enable(struct clk_hw *hw) xgene_clk_write(data, pclk->param.csr_reg + pclk->param.reg_clk_offset); pr_debug("%s clock PADDR base %pa clk offset 0x%08X mask 0x%08X value 0x%08X\n", - pclk->name, ®, + __clk_get_name(hw->clk), ®, pclk->param.reg_clk_offset, pclk->param.reg_clk_mask, data); @@ -248,7 +245,7 @@ static int xgene_clk_enable(struct clk_hw *hw) xgene_clk_write(data, pclk->param.csr_reg + pclk->param.reg_csr_offset); pr_debug("%s CSR RESET PADDR base %pa csr offset 0x%08X mask 0x%08X value 0x%08X\n", - pclk->name, ®, + __clk_get_name(hw->clk), ®, pclk->param.reg_csr_offset, pclk->param.reg_csr_mask, data); } @@ -269,7 +266,7 @@ static void xgene_clk_disable(struct clk_hw *hw) spin_lock_irqsave(pclk->lock, flags); if (pclk->param.csr_reg != NULL) { - pr_debug("%s clock disabled\n", pclk->name); + pr_debug("%s clock disabled\n", __clk_get_name(hw->clk)); /* First put the CSR in reset */ data = xgene_clk_read(pclk->param.csr_reg + pclk->param.reg_csr_offset); @@ -295,10 +292,10 @@ static int xgene_clk_is_enabled(struct clk_hw *hw) u32 data = 0; if (pclk->param.csr_reg != NULL) { - pr_debug("%s clock checking\n", pclk->name); + pr_debug("%s clock checking\n", __clk_get_name(hw->clk)); data = xgene_clk_read(pclk->param.csr_reg + pclk->param.reg_clk_offset); - pr_debug("%s clock is %s\n", pclk->name, + pr_debug("%s clock is %s\n", __clk_get_name(hw->clk), data & pclk->param.reg_clk_mask ? "enabled" : "disabled"); } @@ -321,11 +318,13 @@ static unsigned long xgene_clk_recalc_rate(struct clk_hw *hw, data &= (1 << pclk->param.reg_divider_width) - 1; pr_debug("%s clock recalc rate %ld parent %ld\n", - pclk->name, parent_rate / data, parent_rate); + __clk_get_name(hw->clk), + parent_rate / data, parent_rate); + return parent_rate / data; } else { pr_debug("%s clock recalc rate %ld parent %ld\n", - pclk->name, parent_rate, parent_rate); + __clk_get_name(hw->clk), parent_rate, parent_rate); return parent_rate; } } @@ -357,7 +356,7 @@ static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate, data |= divider; xgene_clk_write(data, pclk->param.divider_reg + pclk->param.reg_divider_offset); - pr_debug("%s clock set rate %ld\n", pclk->name, + pr_debug("%s clock set rate %ld\n", __clk_get_name(hw->clk), parent_rate / divider_save); } else { divider_save = 1; @@ -419,7 +418,6 @@ static struct clk *xgene_register_clk(struct device *dev, init.parent_names = parent_name ? &parent_name : NULL; init.num_parents = parent_name ? 1 : 0; - apmclk->name = name; apmclk->lock = lock; apmclk->hw.init = &init; apmclk->param = *parameters; -- cgit v1.3-6-gb490 From adb11a40a3ac5225ce3746a62c2a7ebde42ec04e Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Mon, 6 Jul 2015 16:51:30 +0300 Subject: clk: qcom: Constify the parent names arrays Make const both the array and the strings, so they can be moved to .rodata section. Signed-off-by: Georgi Djakov Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-apq8084.c | 12 ++++++------ drivers/clk/qcom/gcc-ipq806x.c | 10 +++++----- drivers/clk/qcom/gcc-msm8660.c | 8 ++++---- drivers/clk/qcom/gcc-msm8916.c | 24 ++++++++++++------------ drivers/clk/qcom/gcc-msm8960.c | 12 ++++++------ drivers/clk/qcom/gcc-msm8974.c | 4 ++-- drivers/clk/qcom/lcc-ipq806x.c | 6 +++--- drivers/clk/qcom/lcc-msm8960.c | 8 ++++---- drivers/clk/qcom/mmcc-apq8084.c | 20 ++++++++++---------- drivers/clk/qcom/mmcc-msm8960.c | 14 +++++++------- drivers/clk/qcom/mmcc-msm8974.c | 16 ++++++++-------- 11 files changed, 67 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c index 54a756b90a37..05b7a25b80e8 100644 --- a/drivers/clk/qcom/gcc-apq8084.c +++ b/drivers/clk/qcom/gcc-apq8084.c @@ -48,7 +48,7 @@ static const struct parent_map gcc_xo_gpll0_map[] = { { P_GPLL0, 1 } }; -static const char *gcc_xo_gpll0[] = { +static const char * const gcc_xo_gpll0[] = { "xo", "gpll0_vote", }; @@ -59,7 +59,7 @@ static const struct parent_map gcc_xo_gpll0_gpll4_map[] = { { P_GPLL4, 5 } }; -static const char *gcc_xo_gpll0_gpll4[] = { +static const char * const gcc_xo_gpll0_gpll4[] = { "xo", "gpll0_vote", "gpll4_vote", @@ -70,7 +70,7 @@ static const struct parent_map gcc_xo_sata_asic0_map[] = { { P_SATA_ASIC0_CLK, 2 } }; -static const char *gcc_xo_sata_asic0[] = { +static const char * const gcc_xo_sata_asic0[] = { "xo", "sata_asic0_clk", }; @@ -80,7 +80,7 @@ static const struct parent_map gcc_xo_sata_rx_map[] = { { P_SATA_RX_CLK, 2} }; -static const char *gcc_xo_sata_rx[] = { +static const char * const gcc_xo_sata_rx[] = { "xo", "sata_rx_clk", }; @@ -90,7 +90,7 @@ static const struct parent_map gcc_xo_pcie_map[] = { { P_PCIE_0_1_PIPE_CLK, 2 } }; -static const char *gcc_xo_pcie[] = { +static const char * const gcc_xo_pcie[] = { "xo", "pcie_pipe", }; @@ -100,7 +100,7 @@ static const struct parent_map gcc_xo_pcie_sleep_map[] = { { P_SLEEP_CLK, 6 } }; -static const char *gcc_xo_pcie_sleep[] = { +static const char * const gcc_xo_pcie_sleep[] = { "xo", "sleep_clk_src", }; diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index 563969942a1d..40e480220cd3 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -188,7 +188,7 @@ static const struct parent_map gcc_pxo_pll8_map[] = { { P_PLL8, 3 } }; -static const char *gcc_pxo_pll8[] = { +static const char * const gcc_pxo_pll8[] = { "pxo", "pll8_vote", }; @@ -199,7 +199,7 @@ static const struct parent_map gcc_pxo_pll8_cxo_map[] = { { P_CXO, 5 } }; -static const char *gcc_pxo_pll8_cxo[] = { +static const char * const gcc_pxo_pll8_cxo[] = { "pxo", "pll8_vote", "cxo", @@ -215,7 +215,7 @@ static const struct parent_map gcc_pxo_pll3_sata_map[] = { { P_PLL3, 6 } }; -static const char *gcc_pxo_pll3[] = { +static const char * const gcc_pxo_pll3[] = { "pxo", "pll3", }; @@ -226,7 +226,7 @@ static const struct parent_map gcc_pxo_pll8_pll0[] = { { P_PLL0, 2 } }; -static const char *gcc_pxo_pll8_pll0_map[] = { +static const char * const gcc_pxo_pll8_pll0_map[] = { "pxo", "pll8_vote", "pll0_vote", @@ -240,7 +240,7 @@ static const struct parent_map gcc_pxo_pll8_pll14_pll18_pll0_map[] = { { P_PLL18, 1 } }; -static const char *gcc_pxo_pll8_pll14_pll18_pll0[] = { +static const char * const gcc_pxo_pll8_pll14_pll18_pll0[] = { "pxo", "pll8_vote", "pll0_vote", diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c index fc6b12da5b30..b02826ed770a 100644 --- a/drivers/clk/qcom/gcc-msm8660.c +++ b/drivers/clk/qcom/gcc-msm8660.c @@ -70,7 +70,7 @@ static const struct parent_map gcc_pxo_pll8_map[] = { { P_PLL8, 3 } }; -static const char *gcc_pxo_pll8[] = { +static const char * const gcc_pxo_pll8[] = { "pxo", "pll8_vote", }; @@ -81,7 +81,7 @@ static const struct parent_map gcc_pxo_pll8_cxo_map[] = { { P_CXO, 5 } }; -static const char *gcc_pxo_pll8_cxo[] = { +static const char * const gcc_pxo_pll8_cxo[] = { "pxo", "pll8_vote", "cxo", @@ -1917,7 +1917,7 @@ static struct clk_rcg usb_fs1_xcvr_fs_src = { } }; -static const char *usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" }; +static const char * const usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" }; static struct clk_branch usb_fs1_xcvr_fs_clk = { .halt_reg = 0x2fcc, @@ -1984,7 +1984,7 @@ static struct clk_rcg usb_fs2_xcvr_fs_src = { } }; -static const char *usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" }; +static const char * const usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" }; static struct clk_branch usb_fs2_xcvr_fs_clk = { .halt_reg = 0x2fcc, diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c index c66f7bc2ae87..3bf4fb3deef6 100644 --- a/drivers/clk/qcom/gcc-msm8916.c +++ b/drivers/clk/qcom/gcc-msm8916.c @@ -51,7 +51,7 @@ static const struct parent_map gcc_xo_gpll0_map[] = { { P_GPLL0, 1 }, }; -static const char *gcc_xo_gpll0[] = { +static const char * const gcc_xo_gpll0[] = { "xo", "gpll0_vote", }; @@ -62,7 +62,7 @@ static const struct parent_map gcc_xo_gpll0_bimc_map[] = { { P_BIMC, 2 }, }; -static const char *gcc_xo_gpll0_bimc[] = { +static const char * const gcc_xo_gpll0_bimc[] = { "xo", "gpll0_vote", "bimc_pll_vote", @@ -75,7 +75,7 @@ static const struct parent_map gcc_xo_gpll0a_gpll1_gpll2a_map[] = { { P_GPLL2_AUX, 2 }, }; -static const char *gcc_xo_gpll0a_gpll1_gpll2a[] = { +static const char * const gcc_xo_gpll0a_gpll1_gpll2a[] = { "xo", "gpll0_vote", "gpll1_vote", @@ -88,7 +88,7 @@ static const struct parent_map gcc_xo_gpll0_gpll2_map[] = { { P_GPLL2, 2 }, }; -static const char *gcc_xo_gpll0_gpll2[] = { +static const char * const gcc_xo_gpll0_gpll2[] = { "xo", "gpll0_vote", "gpll2_vote", @@ -99,7 +99,7 @@ static const struct parent_map gcc_xo_gpll0a_map[] = { { P_GPLL0_AUX, 2 }, }; -static const char *gcc_xo_gpll0a[] = { +static const char * const gcc_xo_gpll0a[] = { "xo", "gpll0_vote", }; @@ -111,7 +111,7 @@ static const struct parent_map gcc_xo_gpll0_gpll1a_sleep_map[] = { { P_SLEEP_CLK, 6 }, }; -static const char *gcc_xo_gpll0_gpll1a_sleep[] = { +static const char * const gcc_xo_gpll0_gpll1a_sleep[] = { "xo", "gpll0_vote", "gpll1_vote", @@ -124,7 +124,7 @@ static const struct parent_map gcc_xo_gpll0_gpll1a_map[] = { { P_GPLL1_AUX, 2 }, }; -static const char *gcc_xo_gpll0_gpll1a[] = { +static const char * const gcc_xo_gpll0_gpll1a[] = { "xo", "gpll0_vote", "gpll1_vote", @@ -135,7 +135,7 @@ static const struct parent_map gcc_xo_dsibyte_map[] = { { P_DSI0_PHYPLL_BYTE, 2 }, }; -static const char *gcc_xo_dsibyte[] = { +static const char * const gcc_xo_dsibyte[] = { "xo", "dsi0pllbyte", }; @@ -146,7 +146,7 @@ static const struct parent_map gcc_xo_gpll0a_dsibyte_map[] = { { P_DSI0_PHYPLL_BYTE, 1 }, }; -static const char *gcc_xo_gpll0a_dsibyte[] = { +static const char * const gcc_xo_gpll0a_dsibyte[] = { "xo", "gpll0_vote", "dsi0pllbyte", @@ -158,7 +158,7 @@ static const struct parent_map gcc_xo_gpll0_dsiphy_map[] = { { P_DSI0_PHYPLL_DSI, 2 }, }; -static const char *gcc_xo_gpll0_dsiphy[] = { +static const char * const gcc_xo_gpll0_dsiphy[] = { "xo", "gpll0_vote", "dsi0pll", @@ -170,7 +170,7 @@ static const struct parent_map gcc_xo_gpll0a_dsiphy_map[] = { { P_DSI0_PHYPLL_DSI, 1 }, }; -static const char *gcc_xo_gpll0a_dsiphy[] = { +static const char * const gcc_xo_gpll0a_dsiphy[] = { "xo", "gpll0_vote", "dsi0pll", @@ -183,7 +183,7 @@ static const struct parent_map gcc_xo_gpll0a_gpll1_gpll2_map[] = { { P_GPLL2, 2 }, }; -static const char *gcc_xo_gpll0a_gpll1_gpll2[] = { +static const char * const gcc_xo_gpll0a_gpll1_gpll2[] = { "xo", "gpll0_vote", "gpll1_vote", diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index eb6a4f9fa107..aa294b1bad34 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -125,7 +125,7 @@ static const struct parent_map gcc_pxo_pll8_map[] = { { P_PLL8, 3 } }; -static const char *gcc_pxo_pll8[] = { +static const char * const gcc_pxo_pll8[] = { "pxo", "pll8_vote", }; @@ -136,7 +136,7 @@ static const struct parent_map gcc_pxo_pll8_cxo_map[] = { { P_CXO, 5 } }; -static const char *gcc_pxo_pll8_cxo[] = { +static const char * const gcc_pxo_pll8_cxo[] = { "pxo", "pll8_vote", "cxo", @@ -148,7 +148,7 @@ static const struct parent_map gcc_pxo_pll8_pll3_map[] = { { P_PLL3, 6 } }; -static const char *gcc_pxo_pll8_pll3[] = { +static const char * const gcc_pxo_pll8_pll3[] = { "pxo", "pll8_vote", "pll3", @@ -2085,7 +2085,7 @@ static struct clk_rcg usb_hsic_xcvr_fs_src = { } }; -static const char *usb_hsic_xcvr_fs_src_p[] = { "usb_hsic_xcvr_fs_src" }; +static const char * const usb_hsic_xcvr_fs_src_p[] = { "usb_hsic_xcvr_fs_src" }; static struct clk_branch usb_hsic_xcvr_fs_clk = { .halt_reg = 0x2fc8, @@ -2181,7 +2181,7 @@ static struct clk_rcg usb_fs1_xcvr_fs_src = { } }; -static const char *usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" }; +static const char * const usb_fs1_xcvr_fs_src_p[] = { "usb_fs1_xcvr_fs_src" }; static struct clk_branch usb_fs1_xcvr_fs_clk = { .halt_reg = 0x2fcc, @@ -2248,7 +2248,7 @@ static struct clk_rcg usb_fs2_xcvr_fs_src = { } }; -static const char *usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" }; +static const char * const usb_fs2_xcvr_fs_src_p[] = { "usb_fs2_xcvr_fs_src" }; static struct clk_branch usb_fs2_xcvr_fs_clk = { .halt_reg = 0x2fcc, diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c index c39d09874e74..2c289702119f 100644 --- a/drivers/clk/qcom/gcc-msm8974.c +++ b/drivers/clk/qcom/gcc-msm8974.c @@ -44,7 +44,7 @@ static const struct parent_map gcc_xo_gpll0_map[] = { { P_GPLL0, 1 } }; -static const char *gcc_xo_gpll0[] = { +static const char * const gcc_xo_gpll0[] = { "xo", "gpll0_vote", }; @@ -55,7 +55,7 @@ static const struct parent_map gcc_xo_gpll0_gpll4_map[] = { { P_GPLL4, 5 } }; -static const char *gcc_xo_gpll0_gpll4[] = { +static const char * const gcc_xo_gpll0_gpll4[] = { "xo", "gpll0_vote", "gpll4_vote", diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c index 47f0ac16d149..93ad42b14366 100644 --- a/drivers/clk/qcom/lcc-ipq806x.c +++ b/drivers/clk/qcom/lcc-ipq806x.c @@ -71,7 +71,7 @@ static const struct parent_map lcc_pxo_pll4_map[] = { { P_PLL4, 2 } }; -static const char *lcc_pxo_pll4[] = { +static const char * const lcc_pxo_pll4[] = { "pxo", "pll4_vote", }; @@ -146,7 +146,7 @@ static struct clk_rcg mi2s_osr_src = { }, }; -static const char *lcc_mi2s_parents[] = { +static const char * const lcc_mi2s_parents[] = { "mi2s_osr_src", }; @@ -340,7 +340,7 @@ static struct clk_rcg spdif_src = { }, }; -static const char *lcc_spdif_parents[] = { +static const char * const lcc_spdif_parents[] = { "spdif_src", }; diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c index d0df9d5fc3af..ecb96c284675 100644 --- a/drivers/clk/qcom/lcc-msm8960.c +++ b/drivers/clk/qcom/lcc-msm8960.c @@ -57,7 +57,7 @@ static const struct parent_map lcc_pxo_pll4_map[] = { { P_PLL4, 2 } }; -static const char *lcc_pxo_pll4[] = { +static const char * const lcc_pxo_pll4[] = { "pxo", "pll4_vote", }; @@ -127,7 +127,7 @@ static struct clk_rcg mi2s_osr_src = { }, }; -static const char *lcc_mi2s_parents[] = { +static const char * const lcc_mi2s_parents[] = { "mi2s_osr_src", }; @@ -233,7 +233,7 @@ static struct clk_rcg prefix##_osr_src = { \ }, \ }; \ \ -static const char *lcc_##prefix##_parents[] = { \ +static const char * const lcc_##prefix##_parents[] = { \ #prefix "_osr_src", \ }; \ \ @@ -445,7 +445,7 @@ static struct clk_rcg slimbus_src = { }, }; -static const char *lcc_slimbus_parents[] = { +static const char * const lcc_slimbus_parents[] = { "slimbus_src", }; diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c index 1b17df2cb0af..f0ee6bde11af 100644 --- a/drivers/clk/qcom/mmcc-apq8084.c +++ b/drivers/clk/qcom/mmcc-apq8084.c @@ -53,7 +53,7 @@ static const struct parent_map mmcc_xo_mmpll0_mmpll1_gpll0_map[] = { { P_GPLL0, 5 } }; -static const char *mmcc_xo_mmpll0_mmpll1_gpll0[] = { +static const char * const mmcc_xo_mmpll0_mmpll1_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -69,7 +69,7 @@ static const struct parent_map mmcc_xo_mmpll0_dsi_hdmi_gpll0_map[] = { { P_DSI1PLL, 3 } }; -static const char *mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = { +static const char * const mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = { "xo", "mmpll0_vote", "hdmipll", @@ -86,7 +86,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_2_gpll0_map[] = { { P_MMPLL2, 3 } }; -static const char *mmcc_xo_mmpll0_1_2_gpll0[] = { +static const char * const mmcc_xo_mmpll0_1_2_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -102,7 +102,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_3_gpll0_map[] = { { P_MMPLL3, 3 } }; -static const char *mmcc_xo_mmpll0_1_3_gpll0[] = { +static const char * const mmcc_xo_mmpll0_1_3_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -119,7 +119,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_map[] = { { P_DSI1PLL, 2 } }; -static const char *mmcc_xo_dsi_hdmi_edp[] = { +static const char * const mmcc_xo_dsi_hdmi_edp[] = { "xo", "edp_link_clk", "hdmipll", @@ -137,7 +137,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_gpll0_map[] = { { P_DSI1PLL, 2 } }; -static const char *mmcc_xo_dsi_hdmi_edp_gpll0[] = { +static const char * const mmcc_xo_dsi_hdmi_edp_gpll0[] = { "xo", "edp_link_clk", "hdmipll", @@ -155,7 +155,7 @@ static const struct parent_map mmcc_xo_dsibyte_hdmi_edp_gpll0_map[] = { { P_DSI1PLL_BYTE, 2 } }; -static const char *mmcc_xo_dsibyte_hdmi_edp_gpll0[] = { +static const char * const mmcc_xo_dsibyte_hdmi_edp_gpll0[] = { "xo", "edp_link_clk", "hdmipll", @@ -172,7 +172,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll0_map[] = { { P_MMPLL4, 3 } }; -static const char *mmcc_xo_mmpll0_1_4_gpll0[] = { +static const char * const mmcc_xo_mmpll0_1_4_gpll0[] = { "xo", "mmpll0", "mmpll1", @@ -189,7 +189,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll1_0_map[] = { { P_GPLL1, 4 } }; -static const char *mmcc_xo_mmpll0_1_4_gpll1_0[] = { +static const char * const mmcc_xo_mmpll0_1_4_gpll1_0[] = { "xo", "mmpll0", "mmpll1", @@ -208,7 +208,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_4_gpll1_0_sleep_map[] = { { P_MMSLEEP, 6 } }; -static const char *mmcc_xo_mmpll0_1_4_gpll1_0_sleep[] = { +static const char * const mmcc_xo_mmpll0_1_4_gpll1_0_sleep[] = { "xo", "mmpll0", "mmpll1", diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index 9711bca9cc06..54aadbcda61a 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c @@ -50,7 +50,7 @@ static const struct parent_map mmcc_pxo_pll8_pll2_map[] = { { P_PLL2, 1 } }; -static const char *mmcc_pxo_pll8_pll2[] = { +static const char * const mmcc_pxo_pll8_pll2[] = { "pxo", "pll8_vote", "pll2", @@ -63,7 +63,7 @@ static const struct parent_map mmcc_pxo_pll8_pll2_pll3_map[] = { { P_PLL3, 3 } }; -static const char *mmcc_pxo_pll8_pll2_pll15[] = { +static const char * const mmcc_pxo_pll8_pll2_pll15[] = { "pxo", "pll8_vote", "pll2", @@ -77,7 +77,7 @@ static const struct parent_map mmcc_pxo_pll8_pll2_pll15_map[] = { { P_PLL15, 3 } }; -static const char *mmcc_pxo_pll8_pll2_pll3[] = { +static const char * const mmcc_pxo_pll8_pll2_pll3[] = { "pxo", "pll8_vote", "pll2", @@ -579,7 +579,7 @@ static const struct clk_ops clk_ops_pix_rdi = { .determine_rate = __clk_mux_determine_rate, }; -static const char *pix_rdi_parents[] = { +static const char * const pix_rdi_parents[] = { "csi0_clk", "csi1_clk", "csi2_clk", @@ -709,7 +709,7 @@ static struct clk_rcg csiphytimer_src = { }, }; -static const char *csixphy_timer_src[] = { "csiphytimer_src" }; +static const char * const csixphy_timer_src[] = { "csiphytimer_src" }; static struct clk_branch csiphy0_timer_clk = { .halt_reg = 0x01e8, @@ -1385,7 +1385,7 @@ static const struct parent_map mmcc_pxo_hdmi_map[] = { { P_HDMI_PLL, 3 } }; -static const char *mmcc_pxo_hdmi[] = { +static const char * const mmcc_pxo_hdmi[] = { "pxo", "hdmi_pll", }; @@ -1428,7 +1428,7 @@ static struct clk_rcg tv_src = { }, }; -static const char *tv_src_name[] = { "tv_src" }; +static const char * const tv_src_name[] = { "tv_src" }; static struct clk_branch tv_enc_clk = { .halt_reg = 0x01d4, diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index 07f4cc159ad3..0987bf443e1f 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c @@ -56,7 +56,7 @@ static const struct parent_map mmcc_xo_mmpll0_mmpll1_gpll0_map[] = { { P_GPLL0, 5 } }; -static const char *mmcc_xo_mmpll0_mmpll1_gpll0[] = { +static const char * const mmcc_xo_mmpll0_mmpll1_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -72,7 +72,7 @@ static const struct parent_map mmcc_xo_mmpll0_dsi_hdmi_gpll0_map[] = { { P_DSI1PLL, 3 } }; -static const char *mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = { +static const char * const mmcc_xo_mmpll0_dsi_hdmi_gpll0[] = { "xo", "mmpll0_vote", "hdmipll", @@ -89,7 +89,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_2_gpll0_map[] = { { P_MMPLL2, 3 } }; -static const char *mmcc_xo_mmpll0_1_2_gpll0[] = { +static const char * const mmcc_xo_mmpll0_1_2_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -105,7 +105,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_3_gpll0_map[] = { { P_MMPLL3, 3 } }; -static const char *mmcc_xo_mmpll0_1_3_gpll0[] = { +static const char * const mmcc_xo_mmpll0_1_3_gpll0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -121,7 +121,7 @@ static const struct parent_map mmcc_xo_mmpll0_1_gpll1_0_map[] = { { P_GPLL1, 4 } }; -static const char *mmcc_xo_mmpll0_1_gpll1_0[] = { +static const char * const mmcc_xo_mmpll0_1_gpll1_0[] = { "xo", "mmpll0_vote", "mmpll1_vote", @@ -138,7 +138,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_map[] = { { P_DSI1PLL, 2 } }; -static const char *mmcc_xo_dsi_hdmi_edp[] = { +static const char * const mmcc_xo_dsi_hdmi_edp[] = { "xo", "edp_link_clk", "hdmipll", @@ -156,7 +156,7 @@ static const struct parent_map mmcc_xo_dsi_hdmi_edp_gpll0_map[] = { { P_DSI1PLL, 2 } }; -static const char *mmcc_xo_dsi_hdmi_edp_gpll0[] = { +static const char * const mmcc_xo_dsi_hdmi_edp_gpll0[] = { "xo", "edp_link_clk", "hdmipll", @@ -174,7 +174,7 @@ static const struct parent_map mmcc_xo_dsibyte_hdmi_edp_gpll0_map[] = { { P_DSI1PLL_BYTE, 2 } }; -static const char *mmcc_xo_dsibyte_hdmi_edp_gpll0[] = { +static const char * const mmcc_xo_dsibyte_hdmi_edp_gpll0[] = { "xo", "edp_link_clk", "hdmipll", -- cgit v1.3-6-gb490 From e26bb71da9cf3c54cd8b1c1341a9c9b89e704ca6 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 30 Jun 2015 13:51:51 +0530 Subject: staging: wilc1000: fix build failure commit 80279fb7ba5b ("cfg80211: properly send NL80211_ATTR_DISCONNECTED_BY_AP in disconnect") has changed the api of cfg80211_disconnected() and caused a build failure. Add the extra argument as false since it appears from the code that the disconnection is not locally generated. And incase of doubt we can use false as that is the default behaviour. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 92064db9eb05..f7f5fafe49fe 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -675,7 +675,8 @@ static void CfgConnectResult(tenuConnDisconnEvent enuConnDisconnEvent, pstrDisconnectNotifInfo->u16reason = 1; } cfg80211_disconnected(dev, pstrDisconnectNotifInfo->u16reason, pstrDisconnectNotifInfo->ie, - pstrDisconnectNotifInfo->ie_len, GFP_KERNEL); + pstrDisconnectNotifInfo->ie_len, false, + GFP_KERNEL); } -- cgit v1.3-6-gb490 From 8ca1b55a49f3b8e139fb4567b966f03a734e744f Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Sun, 21 Jun 2015 10:56:21 +0530 Subject: Staging: wilc1000: Replace memset with eth_zero_addr Use eth_zero_addr to assign the zero address to the given address array instead of memset when second argument is address of zero. The Coccinelle semantic patch that makes this change is as follows: // @eth_zero_addr@ expression e; @@ -memset(e,0x00,ETH_ALEN); +eth_zero_addr(e); // Signed-off-by: Vaishali Thakkar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/linux_mon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/linux_mon.c b/drivers/staging/wilc1000/linux_mon.c index f5296f53a3d2..2a3d875d14f8 100644 --- a/drivers/staging/wilc1000/linux_mon.c +++ b/drivers/staging/wilc1000/linux_mon.c @@ -495,7 +495,7 @@ static void WILC_WFI_mon_setup(struct net_device *dev) ether_setup(dev); dev->tx_queue_len = 0; dev->type = ARPHRD_IEEE80211_RADIOTAP; - memset(dev->dev_addr, 0, ETH_ALEN); + eth_zero_addr(dev->dev_addr); #ifdef USE_WIRELESS { -- cgit v1.3-6-gb490 From a241a78952af31fcf4d33db2308fefb27c91703f Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 22 Jun 2015 13:08:11 +0900 Subject: staging: wilc1000: wilc_wfi_netdevice.c: remove prohibited space before semicolon Fix checkpatch warning found by checkpatch.pl WARNING: space prohibited before semicolon Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.c b/drivers/staging/wilc1000/wilc_wfi_netdevice.c index ab66ce4bd790..01542f439376 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.c +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.c @@ -31,7 +31,7 @@ module_param(timeout, int, 0); /* * Do we run in NAPI mode? */ -static int use_napi ; +static int use_napi; module_param(use_napi, int, 0); -- cgit v1.3-6-gb490 From e8b369ea2bf80b5813ee760de4454deb2c10ee87 Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 22 Jun 2015 13:08:12 +0900 Subject: staging: wilc1000: wilc_wfi_netdevice.c: remove prohibited space Fix checkpatch warning found by checkpatch.pl WARNING: space prohibited between function name and open parenthesis '(' Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.c b/drivers/staging/wilc1000/wilc_wfi_netdevice.c index 01542f439376..9da7674602e1 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.c +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.c @@ -71,7 +71,7 @@ void WILC_WFI_SetupPool(struct net_device *dev) priv->ppool = NULL; for (i = 0; i < pool_size; i++) { - pkt = kmalloc (sizeof (struct WILC_WFI_packet), GFP_KERNEL); + pkt = kmalloc(sizeof(struct WILC_WFI_packet), GFP_KERNEL); if (pkt == NULL) { PRINT_D(RX_DBG, "Ran out of memory allocating packet pool\n"); return; @@ -99,7 +99,7 @@ void WILC_WFI_TearDownPool(struct net_device *dev) while ((pkt = priv->ppool)) { priv->ppool = pkt->next; - kfree (pkt); + kfree(pkt); /* FIXME - in-flight packets ? */ } } -- cgit v1.3-6-gb490 From 55229a56bb9e6f7f9dce36099b1045deb73409f1 Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 22 Jun 2015 13:08:13 +0900 Subject: staging: wilc1000: wilc_wfi_netdevice.c: remove braces for single statement block Fix checkpatch warning found by checkpatch.pl WARNING: braces {} are not necessary for single statement blocks Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.c b/drivers/staging/wilc1000/wilc_wfi_netdevice.c index 9da7674602e1..039e21f6caf6 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.c +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.c @@ -931,10 +931,8 @@ int WILC_WFI_InitModule(void) /* ret = host_int_init(&priv[0]->hWILCWFIDrv); */ /*copy handle to the other driver*/ /* priv[1]->hWILCWFIDrv = priv[0]->hWILCWFIDrv; */ - if (ret) { + if (ret) PRINT_ER("Error Init Driver\n"); - } - out: if (ret) -- cgit v1.3-6-gb490 From df493fe8fa7ed73d73e08c768ed057b0e61b813d Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 22 Jun 2015 13:08:14 +0900 Subject: staging: wilc1000: wilc_wfi_netdevice.c: Insert blank line after declarations Fix checkpatch warning found by checkpatch.pl WARNING: Missing a blank line after declarations Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.c b/drivers/staging/wilc1000/wilc_wfi_netdevice.c index 039e21f6caf6..31a796b5ff29 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.c +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.c @@ -207,6 +207,7 @@ struct WILC_WFI_packet *WILC_WFI_DequeueBuf(struct net_device *dev) static void WILC_WFI_RxInts(struct net_device *dev, int enable) { struct WILC_WFI_priv *priv = netdev_priv(dev); + priv->rx_int_enabled = enable; } @@ -522,6 +523,7 @@ void WILC_WFI_HwTx(char *buf, int len, struct net_device *dev) if (0) { /* enable this conditional to look at the data */ int i; + PRINT_D(RX_DBG, "len is %i", len); for (i = 14; i < len; i++) PRINT_D(RX_DBG, "TXdata[%d] %02x\n", i, buf[i] & 0xff); @@ -677,6 +679,7 @@ int WILC_WFI_Ioctl(struct net_device *dev, struct ifreq *rq, int cmd) struct net_device_stats *WILC_WFI_Stats(struct net_device *dev) { struct WILC_WFI_priv *priv = netdev_priv(dev); + return &priv->stats; } -- cgit v1.3-6-gb490 From decc286c7dac701fc545d4a23cb2f9cf19a09a2c Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 22 Jun 2015 13:08:15 +0900 Subject: staging: wilc1000: wilc_wfi_netdevice.c: move statement after declarations Fix checkpatch warning found by checkpatch.pl WARNING: Missing a blank line after declarations Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.c b/drivers/staging/wilc1000/wilc_wfi_netdevice.c index 31a796b5ff29..170ca65cd135 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.c +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.c @@ -886,9 +886,10 @@ int WILC_WFI_InitModule(void) int result, i, ret = -ENOMEM; struct WILC_WFI_priv *priv[2], *netpriv; struct wireless_dev *wdev; - WILC_WFI_Interrupt = use_napi ? WILC_WFI_NapiInterrupt : WILC_WFI_RegularInterrupt; char buf[IFNAMSIZ]; + WILC_WFI_Interrupt = use_napi ? WILC_WFI_NapiInterrupt : WILC_WFI_RegularInterrupt; + for (i = 0; i < 2; i++) { /* Allocate the net devices */ -- cgit v1.3-6-gb490 From 6608a38c66dfc0b14e77b92cbbf2457d18c42cd7 Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Mon, 22 Jun 2015 07:02:46 +0000 Subject: staging: wilc1000: remove ununsed variable and associated line This patch removes a unused variable 'u16RespLen' that is assigned a value that is never used. The line that does the assignment is also removed. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/coreconfigurator.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c index ed6ac45c0385..67cffc3c9b94 100644 --- a/drivers/staging/wilc1000/coreconfigurator.c +++ b/drivers/staging/wilc1000/coreconfigurator.c @@ -1739,7 +1739,6 @@ s32 ParseResponse(u8 *resp, tstrWID *pstrWIDcfgResult) s32 ParseWriteResponse(u8 *pu8RespBuffer) { s32 s32Error = WILC_FAIL; - u16 u16RespLen = 0; u16 u16WIDtype = (u16)WID_NIL; /* Check whether the received frame is a valid response */ @@ -1748,9 +1747,6 @@ s32 ParseWriteResponse(u8 *pu8RespBuffer) return WILC_FAIL; } - /* Extract Response Length */ - u16RespLen = MAKE_WORD16(pu8RespBuffer[2], pu8RespBuffer[3]); - u16WIDtype = MAKE_WORD16(pu8RespBuffer[4], pu8RespBuffer[5]); /* Check for WID_STATUS ID and then check the length and status value */ -- cgit v1.3-6-gb490 From ab6ebe3a4b1ff9e37c2b7d12da7f985125dfab55 Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Mon, 22 Jun 2015 07:03:06 +0000 Subject: staging: wilc1000: remove redundant initialization of variable This patch removes the redundant initialization of the variable 'st' as it is reassigned a new value before its being used anywhere else. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/coreconfigurator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c index 67cffc3c9b94..eb685fea2cd2 100644 --- a/drivers/staging/wilc1000/coreconfigurator.c +++ b/drivers/staging/wilc1000/coreconfigurator.c @@ -605,7 +605,7 @@ INLINE u16 get_cap_info(u8 *data) { u16 cap_info = 0; u16 index = MAC_HDR_LEN; - tenuFrmSubtype st = BEACON; + tenuFrmSubtype st; st = get_sub_type(data); -- cgit v1.3-6-gb490 From 04f2a50d41950ba60a56d2f884be05893ac61b6b Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Mon, 22 Jun 2015 07:03:27 +0000 Subject: staging: wilc1000: remove ununsed if..else.. code blocks This patch removes ununsed if..else... code blocks. Its actually some dead code. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/coreconfigurator.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c index eb685fea2cd2..b0696141e10f 100644 --- a/drivers/staging/wilc1000/coreconfigurator.c +++ b/drivers/staging/wilc1000/coreconfigurator.c @@ -1568,14 +1568,6 @@ s32 further_process_response(u8 *resp, case WID_STR: WILC_memcpy(cfg_str, resp + idx, cfg_len); /* cfg_str[cfg_len] = '\0'; //mostafa: no need currently for NULL termination */ - if (process_wid_num) { - /*fprintf(out_file,"0x%4.4x = %s\n",g_wid_num, - * cfg_str);*/ - } else { - /*fprintf(out_file,"%s = %s\n",gastrWIDs[cnt].cfg_switch, - * cfg_str);*/ - } - if (pstrWIDresult->s32ValueSize >= cfg_len) { WILC_memcpy(pstrWIDresult->ps8WidVal, cfg_str, cfg_len); /* mostafa: no need currently for the extra NULL byte */ pstrWIDresult->s32ValueSize = cfg_len; @@ -1591,13 +1583,6 @@ s32 further_process_response(u8 *resp, WILC_strncpy(pstrWIDresult->ps8WidVal, cfg_str, WILC_strlen(cfg_str)); pstrWIDresult->ps8WidVal[WILC_strlen(cfg_str)] = '\0'; - if (process_wid_num) { - /*fprintf(out_file,"0x%4.4x = %s\n",g_wid_num, - * cfg_str);*/ - } else { - /*fprintf(out_file,"%s = %s\n",gastrWIDs[cnt].cfg_switch, - * cfg_str);*/ - } break; case WID_IP: @@ -1606,13 +1591,6 @@ s32 further_process_response(u8 *resp, MAKE_WORD16(resp[idx + 2], resp[idx + 3]) ); conv_int_to_ip(cfg_str, cfg_int); - if (process_wid_num) { - /*fprintf(out_file,"0x%4.4x = %s\n",g_wid_num, - * cfg_str);*/ - } else { - /*fprintf(out_file,"%s = %s\n",gastrWIDs[cnt].cfg_switch, - * cfg_str);*/ - } break; case WID_BIN_DATA: -- cgit v1.3-6-gb490 From 53e1096fea95f196377baac5e005b2de8c730631 Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Mon, 22 Jun 2015 07:03:53 +0000 Subject: staging: wilc1000: remove ununsed variable & corresponding lines This patch removes a couple of ununsed variable.The lines in which these variables are assigned are also removed as they are not necessary. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/linux_mon.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/linux_mon.c b/drivers/staging/wilc1000/linux_mon.c index 2a3d875d14f8..d812a3b194f3 100644 --- a/drivers/staging/wilc1000/linux_mon.c +++ b/drivers/staging/wilc1000/linux_mon.c @@ -237,14 +237,12 @@ static void mgmt_tx_complete(void *priv, int status) } static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len) { - linux_wlan_t *nic; struct tx_complete_mon_data *mgmt_tx = NULL; if (dev == NULL) { PRINT_D(HOSTAPD_DBG, "ERROR: dev == NULL\n"); return WILC_FAIL; } - nic = netdev_priv(dev); netif_stop_queue(dev); mgmt_tx = kmalloc(sizeof(struct tx_complete_mon_data), GFP_ATOMIC); @@ -298,7 +296,6 @@ static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len) static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ieee80211_radiotap_header *rtap_hdr; u32 rtap_len, i, ret = 0; struct WILC_WFI_mon_priv *mon_priv; @@ -318,7 +315,6 @@ static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb, return WILC_FAIL; } - rtap_hdr = (struct ieee80211_radiotap_header *)skb->data; rtap_len = ieee80211_get_radiotap_len(skb->data); if (skb->len < rtap_len) { -- cgit v1.3-6-gb490 From 773116ea0b78c0aa8315bb64690d6a82c3f44b64 Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Mon, 22 Jun 2015 07:04:20 +0000 Subject: staging: wilc1000: remove unused variable This patch removes a unused variable timeout and the associated code. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/linux_wlan.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index b352c504a77d..5a794df0da4d 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -868,7 +868,6 @@ static int linux_wlan_txq_task(void *vp) #define TX_BACKOFF_WEIGHT_MIN (0) #define TX_BACKOFF_WEIGHT_UNIT_MS (10) int backoff_weight = TX_BACKOFF_WEIGHT_MIN; - signed long timeout; #endif /* inform wilc1000_wlan_init that TXQ task is started. */ @@ -906,7 +905,6 @@ static int linux_wlan_txq_task(void *vp) } if (ret == WILC_TX_ERR_NO_BUF) { /* failed to allocate buffers in chip. */ - timeout = msecs_to_jiffies(TX_BACKOFF_WEIGHT_UNIT_MS << backoff_weight); do { /* Back off from sending packets for some time. */ /* schedule_timeout will allow RX task to run and free buffers.*/ -- cgit v1.3-6-gb490 From 369f190a70d1972eed3888bd255dca711c8f58f3 Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Mon, 22 Jun 2015 07:04:39 +0000 Subject: staging: wilc1000: remove redundant assignment of variable This patch the removes the redundant assignement of the variable ret as its being overwritren before being used anywhere. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index 3af91f770485..d28c410ba249 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -1782,7 +1782,7 @@ static int wilc_wlan_stop(void) /******************************************************************************/ reg = ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 8) | (1 << 9) | (1 << 26) | (1 << 29) | (1 << 30) | (1 << 31)); /**/ /**/ - ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); /**/ + p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); /**/ reg = ~(1 << 10); /**/ /**/ ret = p->hif_func.hif_write_reg(WILC_GLB_RESET_0, reg); /**/ -- cgit v1.3-6-gb490 From 810532227a431d5f13e732a37119a94d73819949 Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Mon, 22 Jun 2015 13:13:58 +0000 Subject: staging: wilc1000: remove ununsed variable This patch removes ununsed variable 'len' Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wlan.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index d28c410ba249..def72fd1236d 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -118,11 +118,10 @@ static void wilc_debug(uint32_t flag, char *fmt, ...) { char buf[256]; va_list args; - int len; if (flag & dbgflag) { va_start(args, fmt); - len = vsprintf(buf, fmt, args); + vsprintf(buf, fmt, args); va_end(args); if (g_wlan.os_func.os_debug) -- cgit v1.3-6-gb490 From 690910c0cf350a96590c6795f2d0f26e5f8ec59f Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Mon, 22 Jun 2015 07:05:22 +0000 Subject: staging: wilc1000: remove ununsed variable & associated code This patch removes the ununsed variable 'priv' at multiple instances and all its associated code where its assigned a value. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index f7f5fafe49fe..1d0b7f87b100 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -144,9 +144,7 @@ bool g_wep_keys_saved = false; void clear_shadow_scan(void *pUserVoid) { - struct WILC_WFI_priv *priv; int i; - priv = (struct WILC_WFI_priv *)pUserVoid; if (op_ifcs == 0) { WILC_TimerDestroy(&hAgingTimer, NULL); PRINT_INFO(CORECONFIG_DBG, "destroy aging timer\n"); @@ -219,9 +217,7 @@ void refresh_scan(void *pUserVoid, uint8_t all, bool bDirectScan) void reset_shadow_found(void *pUserVoid) { - struct WILC_WFI_priv *priv; int i; - priv = (struct WILC_WFI_priv *)pUserVoid; for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { astrLastScannedNtwrksShadow[i].u8Found = 0; @@ -230,9 +226,7 @@ void reset_shadow_found(void *pUserVoid) void update_scan_time(void *pUserVoid) { - struct WILC_WFI_priv *priv; int i; - priv = (struct WILC_WFI_priv *)pUserVoid; for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan = jiffies; } @@ -240,11 +234,9 @@ void update_scan_time(void *pUserVoid) void remove_network_from_shadow(void *pUserVoid) { - struct WILC_WFI_priv *priv; unsigned long now = jiffies; int i, j; - priv = (struct WILC_WFI_priv *)pUserVoid; for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { if (time_after(now, astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan + (unsigned long)(SCAN_RESULT_EXPIRE))) { @@ -281,11 +273,9 @@ void clear_duringIP(void *pUserVoid) int8_t is_network_in_shadow(tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid) { - struct WILC_WFI_priv *priv; int8_t state = -1; int i; - priv = (struct WILC_WFI_priv *)pUserVoid; if (u32LastScannedNtwrksCountShadow == 0) { PRINT_D(CFG80211_DBG, "Starting Aging timer\n"); WILC_TimerStart(&(hAgingTimer), AGING_TIME, pUserVoid, NULL); @@ -305,11 +295,9 @@ int8_t is_network_in_shadow(tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid) void add_network_to_shadow(tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid, void *pJoinParams) { - struct WILC_WFI_priv *priv; int8_t ap_found = is_network_in_shadow(pstrNetworkInfo, pUserVoid); uint32_t ap_index = 0; uint8_t rssi_index = 0; - priv = (struct WILC_WFI_priv *)pUserVoid; if (u32LastScannedNtwrksCountShadow >= MAX_NUM_SCANNED_NETWORKS_SHADOW) { PRINT_D(CFG80211_DBG, "Shadow network reached its maximum limit\n"); -- cgit v1.3-6-gb490 From ba8f5e6642958c73cd558a2d9503720e35951b06 Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Mon, 22 Jun 2015 07:05:42 +0000 Subject: staging: wilc1000: remove unused variable msg_len This patch removes a ununsed variable msg_len and its associated code. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wlan_cfg.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wilc_wlan_cfg.c index 3cffe55b3a93..04d032783dae 100644 --- a/drivers/staging/wilc1000/wilc_wlan_cfg.c +++ b/drivers/staging/wilc1000/wilc_wlan_cfg.c @@ -513,7 +513,6 @@ static int wilc_wlan_cfg_indicate_rx(uint8_t *frame, int size, wilc_cfg_rsp_t *r int ret = 1; uint8_t msg_type; uint8_t msg_id; - uint16_t msg_len; #ifdef WILC_FULLY_HOSTING_AP u32 *ptru32Frame; bool bStatus = frame[2]; @@ -528,11 +527,6 @@ static int wilc_wlan_cfg_indicate_rx(uint8_t *frame, int size, wilc_cfg_rsp_t *r msg_type = frame[0]; msg_id = frame[1]; /* seq no */ -#ifdef BIG_ENDIAN - msg_len = (frame[2] << 8) | frame[3]; -#else - msg_len = (frame[3] << 8) | frame[2]; -#endif frame += 4; size -= 4; -- cgit v1.3-6-gb490 From 2d33ff126bd6f4597189af7348aff9721d4b8080 Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Mon, 22 Jun 2015 07:06:01 +0000 Subject: staging: wilc1000: use BIT macro This patch addresses the checkpatch warning advising the usage of the BIT macro for Bit shift operation. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wlan_if.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wlan_if.h b/drivers/staging/wilc1000/wilc_wlan_if.h index 8ed51e385118..8735a6a64d89 100644 --- a/drivers/staging/wilc1000/wilc_wlan_if.h +++ b/drivers/staging/wilc1000/wilc_wlan_if.h @@ -43,8 +43,8 @@ ********************************************/ #define HIF_SDIO (0) -#define HIF_SPI (1 << 0) -#define HIF_SDIO_GPIO_IRQ (1 << 2) +#define HIF_SPI BIT(0) +#define HIF_SDIO_GPIO_IRQ BIT(2) /******************************************** -- cgit v1.3-6-gb490 From bf903c1e0784f668bcb325494a38cc359c1b5de6 Mon Sep 17 00:00:00 2001 From: Sunil Shahu Date: Mon, 22 Jun 2015 19:23:01 +0530 Subject: staging: wilc1000: host_interface: add spaces around '=' Fix coding style error by placing spaces around '=' as suggested by checkpatch.pl script. Signed-off-by: Sunil Shahu Reviewed-by: Luis de Bethencourt Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 6b10bbbe6ab2..d1fe73df807d 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -7945,8 +7945,8 @@ s32 host_int_get_ipaddress(WILC_WFIDrvHandle hWFIDrv, u8 *u16ipadd, u8 idx) strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_IPADDRESS; strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.au8IPAddr = u16ipadd; - strHostIFmsg.drvHandler=hWFIDrv; - strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.idx= idx; + strHostIFmsg.drvHandler = hWFIDrv; + strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.idx = idx; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); if (s32Error) { -- cgit v1.3-6-gb490 From 66f1a77ec182847b3334edeb37eb4d10b2e8043e Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Tue, 23 Jun 2015 09:17:44 +0900 Subject: staging: wilc1000: wilc_wfi_netdevice.c: remove commented codes Remove commented codes. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.c b/drivers/staging/wilc1000/wilc_wfi_netdevice.c index 170ca65cd135..478cd2bcfea0 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.c +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.c @@ -325,7 +325,6 @@ void WILC_WFI_Rx(struct net_device *dev, struct WILC_WFI_packet *pkt) PRINT_INFO(RX_DBG, "In monitor device name %s\n", dev->name); priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); PRINT_D(RX_DBG, "VALUE PASSED IN OF HRWD %p\n", priv->hWILCWFIDrv); - /* host_int_get_rssi(priv->hWILCWFIDrv, &(rssi)); */ if (INFO) { for (i = 14; i < skb->len; i++) PRINT_INFO(RX_DBG, "RXdata[%d] %02x\n", i, skb->data[i]); @@ -600,12 +599,6 @@ int WILC_WFI_Tx(struct sk_buff *skb, struct net_device *dev) char *data, shortpkt[ETH_ZLEN]; struct WILC_WFI_priv *priv = netdev_priv(dev); - /* priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); */ - - /* if(priv->monitor_flag) */ - /* mac80211_hwsim_monitor_rx(skb); */ - - data = skb->data; len = skb->len; @@ -836,12 +829,6 @@ void WILC_WFI_Cleanup(void) int i; struct WILC_WFI_priv *priv[2]; - /*if(hwsim_mon!=NULL) - * { - * PRINT_D(RX_DBG, "Freeing monitor interface\n"); - * unregister_netdev(hwsim_mon); - * free_netdev(hwsim_mon); - * }*/ for (i = 0; i < 2; i++) { priv[i] = netdev_priv(WILC_WFI_devs[i]); @@ -897,7 +884,6 @@ int WILC_WFI_InitModule(void) WILC_WFI_Init); if (WILC_WFI_devs[i] == NULL) goto out; - /* priv[i] = netdev_priv(WILC_WFI_devs[i]); */ wdev = WILC_WFI_WiphyRegister(WILC_WFI_devs[i]); WILC_WFI_devs[i]->ieee80211_ptr = wdev; @@ -921,9 +907,6 @@ int WILC_WFI_InitModule(void) priv[1] = netdev_priv(WILC_WFI_devs[1]); if (priv[1]->dev->ieee80211_ptr->wiphy->interface_modes && BIT(NL80211_IFTYPE_MONITOR)) { - /* snprintf(buf, IFNAMSIZ, "mon.%s", priv[1]->dev->name); */ - /* WILC_WFI_init_mon_interface(); */ - /* priv[1]->monitor_flag = 1; */ } priv[0]->bCfgScanning = false; @@ -931,10 +914,6 @@ int WILC_WFI_InitModule(void) WILC_memset(priv[0]->au8AssociatedBss, 0xFF, ETH_ALEN); - - /* ret = host_int_init(&priv[0]->hWILCWFIDrv); */ - /*copy handle to the other driver*/ - /* priv[1]->hWILCWFIDrv = priv[0]->hWILCWFIDrv; */ if (ret) PRINT_ER("Error Init Driver\n"); -- cgit v1.3-6-gb490 From 5927139ab52ef90232bd2578836ce36e5798920d Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Tue, 23 Jun 2015 09:17:45 +0900 Subject: staging: wilc1000: wilc_wfi_netdevice.c: remove unused codes Remove if statement that has no any codes. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.c b/drivers/staging/wilc1000/wilc_wfi_netdevice.c index 478cd2bcfea0..d5facb4e55d9 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.c +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.c @@ -906,9 +906,6 @@ int WILC_WFI_InitModule(void) priv[0] = netdev_priv(WILC_WFI_devs[0]); priv[1] = netdev_priv(WILC_WFI_devs[1]); - if (priv[1]->dev->ieee80211_ptr->wiphy->interface_modes && BIT(NL80211_IFTYPE_MONITOR)) { - - } priv[0]->bCfgScanning = false; priv[0]->u32RcvdChCount = 0; -- cgit v1.3-6-gb490 From 70fb5aa8a5f67275b5c2ebe23190777213d010df Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Tue, 23 Jun 2015 09:17:46 +0900 Subject: staging: wilc1000: wilc_wfi_netdevice.c: remove unused variable Remove variable that is defined but never used. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.c b/drivers/staging/wilc1000/wilc_wfi_netdevice.c index d5facb4e55d9..c2e92c0dd4bd 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.c +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.c @@ -873,7 +873,6 @@ int WILC_WFI_InitModule(void) int result, i, ret = -ENOMEM; struct WILC_WFI_priv *priv[2], *netpriv; struct wireless_dev *wdev; - char buf[IFNAMSIZ]; WILC_WFI_Interrupt = use_napi ? WILC_WFI_NapiInterrupt : WILC_WFI_RegularInterrupt; -- cgit v1.3-6-gb490 From 9295e2d7341cb66ab8bbca029eabbe85b38bc376 Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Tue, 23 Jun 2015 09:17:47 +0900 Subject: staging: wilc1000: wilc_wfi_netdevice.c: remove blank lines Remove multiple blank lines. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.c b/drivers/staging/wilc1000/wilc_wfi_netdevice.c index c2e92c0dd4bd..af9b85822ced 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.c +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.c @@ -12,11 +12,9 @@ #include "wilc_wfi_cfgoperations.h" #include "host_interface.h" - MODULE_AUTHOR("Mai Daftedar"); MODULE_LICENSE("Dual BSD/GPL"); - struct net_device *WILC_WFI_devs[2]; /* @@ -34,7 +32,6 @@ module_param(timeout, int, 0); static int use_napi; module_param(use_napi, int, 0); - /* * A structure representing an in-flight packet. */ @@ -45,12 +42,9 @@ struct WILC_WFI_packet { u8 data[ETH_DATA_LEN]; }; - - int pool_size = 8; module_param(pool_size, int, 0); - static void WILC_WFI_TxTimeout(struct net_device *dev); static void (*WILC_WFI_Interrupt)(int, void *, struct pt_regs *); @@ -252,7 +246,6 @@ int WILC_WFI_Open(struct net_device *dev) int WILC_WFI_Release(struct net_device *dev) { /* release ports, irq and such -- like fops->close */ - netif_stop_queue(dev); /* can't transmit any more */ return 0; @@ -512,7 +505,6 @@ void WILC_WFI_HwTx(char *buf, int len, struct net_device *dev) u32 *saddr, *daddr; struct WILC_WFI_packet *tx_buffer; - /* I am paranoid. Ain't I? */ if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { PRINT_D(RX_DBG, "WILC_WFI: Hmm... packet too short (%i octets)\n", @@ -580,7 +572,6 @@ void WILC_WFI_HwTx(char *buf, int len, struct net_device *dev) (unsigned long) priv->stats.tx_packets); } else WILC_WFI_Interrupt(0, dev, NULL); - } /** @@ -785,7 +776,6 @@ void WILC_WFI_Init(struct net_device *dev) { struct WILC_WFI_priv *priv; - /* * Then, assign other fields in dev, using ether_setup() and some * hand assignments @@ -851,12 +841,6 @@ void WILC_WFI_Cleanup(void) void StartConfigSim(void); - - - - - - /** * @brief WILC_WFI_Stat * @details Return statistics to the caller @@ -877,7 +861,6 @@ int WILC_WFI_InitModule(void) WILC_WFI_Interrupt = use_napi ? WILC_WFI_NapiInterrupt : WILC_WFI_RegularInterrupt; for (i = 0; i < 2; i++) { - /* Allocate the net devices */ WILC_WFI_devs[i] = alloc_netdev(sizeof(struct WILC_WFI_priv), "wlan%d", WILC_WFI_Init); @@ -900,7 +883,6 @@ int WILC_WFI_InitModule(void) ret = 0; } - /*init atmel driver */ priv[0] = netdev_priv(WILC_WFI_devs[0]); priv[1] = netdev_priv(WILC_WFI_devs[1]); @@ -921,7 +903,6 @@ out: } - module_init(WILC_WFI_InitModule); module_exit(WILC_WFI_Cleanup); -- cgit v1.3-6-gb490 From 69176e1cbd62d1660c082fc2dfc3ae7aece525ff Mon Sep 17 00:00:00 2001 From: Sunghoon Cho Date: Fri, 26 Jun 2015 15:48:14 +0900 Subject: staging: wilc1000: remove the warnings on the prohibited spaces This patch removes the warnings reported by checkpatch.pl regarding prohibited spaces between function name and open parenthesis. Signed-off-by: Sunghoon Cho Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h index d413fa3861c0..22d7b85f43c3 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -80,9 +80,9 @@ struct WILC_WFI_stats { * LPC3131 which is important to get the MAC start status when you are blocked inside * linux_wlan_firmware_download() which blocks mac_open(). */ -#if defined (NM73131_0_BOARD) +#if defined(NM73131_0_BOARD) #define RX_BH_TYPE RX_BH_KTHREAD -#elif defined (PANDA_BOARD) +#elif defined(PANDA_BOARD) #define RX_BH_TYPE RX_BH_THREADED_IRQ #else #define RX_BH_TYPE RX_BH_KTHREAD -- cgit v1.3-6-gb490 From 36901b690d5d83e0330a33bd6c1771c21c46c450 Mon Sep 17 00:00:00 2001 From: Sunghoon Cho Date: Fri, 26 Jun 2015 15:48:15 +0900 Subject: staging: wilc1000: add a blank line after struct declaration This patch adds a blank line right after a struct declaration. Signed-off-by: Sunghoon Cho Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h index 22d7b85f43c3..8102ef0bb70e 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -95,6 +95,7 @@ struct wilc_wfi_key { int seq_len; u32 cipher; }; + struct wilc_wfi_wep_key { u8 *key; u8 key_len; -- cgit v1.3-6-gb490 From 70e59d92256221640b8122ef258e886b1b1aa33d Mon Sep 17 00:00:00 2001 From: Sunghoon Cho Date: Fri, 26 Jun 2015 15:48:16 +0900 Subject: staging: wilc1000: remove the warnings on the line over 80 characters This patch removes the warnings reported by checkpatch.pl on the line over 80 characters. Signed-off-by: Sunghoon Cho Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_netdevice.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/wilc_wfi_netdevice.h index 8102ef0bb70e..0dfe108e7cf8 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/wilc_wfi_netdevice.h @@ -77,8 +77,8 @@ struct WILC_WFI_stats { #define num_reg_frame 2 /* * If you use RX_BH_WORK_QUEUE on LPC3131: You may lose the first interrupt on - * LPC3131 which is important to get the MAC start status when you are blocked inside - * linux_wlan_firmware_download() which blocks mac_open(). + * LPC3131 which is important to get the MAC start status when you are blocked + * inside linux_wlan_firmware_download() which blocks mac_open(). */ #if defined(NM73131_0_BOARD) #define RX_BH_TYPE RX_BH_KTHREAD @@ -151,7 +151,8 @@ struct WILC_WFI_priv { u8 WILC_WFI_wep_default; u8 WILC_WFI_wep_key[4][WLAN_KEY_LEN_WEP104]; u8 WILC_WFI_wep_key_len[4]; - struct net_device *real_ndev; /* The real interface that the monitor is on */ + /* The real interface that the monitor is on */ + struct net_device *real_ndev; struct wilc_wfi_key *wilc_gtk[MAX_NUM_STA]; struct wilc_wfi_key *wilc_ptk[MAX_NUM_STA]; u8 wilc_groupkey; -- cgit v1.3-6-gb490 From 2b9d5b483784c588b1ecb658cac83cd8100a74aa Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 26 Jun 2015 16:44:24 +0200 Subject: staging: wilc1000: remove unnecessary braces Removing all checkpatch.pl warnings: WARNING: braces {} are not necessary for single statement blocks Signed-off-by: Luis de Bethencourt Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 276 ++++++++++-------------------- 1 file changed, 92 insertions(+), 184 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index d1fe73df807d..bf183b2f39f4 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -659,9 +659,8 @@ static s32 Handle_SetWfiDrvHandler(tstrHostIfSetDrvHandler *pstrHostIfSetDrvHand s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); - if ((pstrHostIfSetDrvHandler->u32Address) == (u32)NULL) { + if ((pstrHostIfSetDrvHandler->u32Address) == (u32)NULL) up(&hSemDeinitDrvHandle); - } if (s32Error) { @@ -705,9 +704,8 @@ static s32 Handle_SetOperationMode(void *drvHandler, tstrHostIfSetOperationMode s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); - if ((pstrHostIfSetOperationMode->u32Mode) == (u32)NULL) { + if ((pstrHostIfSetOperationMode->u32Mode) == (u32)NULL) up(&hSemDeinitDrvHandle); - } if (s32Error) { @@ -1204,10 +1202,9 @@ static s32 Handle_CfgParam(void *drvHandler, tstrHostIFCfgParamAttr *strHostIFCf } s32Error = SendConfigPkt(SET_CFG, strWIDList, u8WidCnt, false, (u32)pstrWFIDrv); - if (s32Error) { + if (s32Error) PRINT_ER("Error in setting CFG params\n"); - } WILC_CATCH(s32Error) { } @@ -1284,9 +1281,8 @@ static s32 Handle_Scan(void *drvHandler, tstrHostIFscanAttr *pstrHostIFscanAttr) strWIDList[u32WidsCount].u16WIDid = (u16)WID_SSID_PROBE_REQ; strWIDList[u32WidsCount].enuWIDtype = WID_STR; - for (i = 0; i < pstrHostIFscanAttr->strHiddenNetwork.u8ssidnum; i++) { + for (i = 0; i < pstrHostIFscanAttr->strHiddenNetwork.u8ssidnum; i++) valuesize += ((pstrHostIFscanAttr->strHiddenNetwork.pstrHiddenNetworkInfo[i].u8ssidlen) + 1); - } pu8HdnNtwrksWidVal = WILC_MALLOC(valuesize + 1); strWIDList[u32WidsCount].ps8WidVal = pu8HdnNtwrksWidVal; if (strWIDList[u32WidsCount].ps8WidVal != NULL) { @@ -1336,9 +1332,8 @@ static s32 Handle_Scan(void *drvHandler, tstrHostIFscanAttr *pstrHostIFscanAttr) int i; for (i = 0; i < pstrHostIFscanAttr->u8ChnlListLen; i++) { - if (pstrHostIFscanAttr->pu8ChnlFreqList[i] > 0) { + if (pstrHostIFscanAttr->pu8ChnlFreqList[i] > 0) pstrHostIFscanAttr->pu8ChnlFreqList[i] = pstrHostIFscanAttr->pu8ChnlFreqList[i] - 1; - } } } @@ -1400,9 +1395,8 @@ static s32 Handle_Scan(void *drvHandler, tstrHostIFscanAttr *pstrHostIFscanAttr) pstrHostIFscanAttr->pu8ChnlFreqList = NULL; } - if (pu8HdnNtwrksWidVal != NULL) { + if (pu8HdnNtwrksWidVal != NULL) WILC_FREE(pu8HdnNtwrksWidVal); - } return s32Error; } @@ -1778,9 +1772,8 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon strWIDList[u32WidsCount].s32ValueSize = MAX_SSID_LEN + 7; strWIDList[u32WidsCount].ps8WidVal = WILC_MALLOC(strWIDList[u32WidsCount].s32ValueSize); - if (strWIDList[u32WidsCount].ps8WidVal == NULL) { + if (strWIDList[u32WidsCount].ps8WidVal == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } pu8CurrByte = strWIDList[u32WidsCount].ps8WidVal; @@ -1795,9 +1788,8 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon PRINT_ER("Channel out of range\n"); *(pu8CurrByte++) = 0xFF; } - if (pstrHostIFconnectAttr->pu8bssid != NULL) { + if (pstrHostIFconnectAttr->pu8bssid != NULL) WILC_memcpy(pu8CurrByte, pstrHostIFconnectAttr->pu8bssid, 6); - } pu8CurrByte += 6; /* keep the buffer at the start of the allocated pointer to use it with the free*/ @@ -1817,9 +1809,8 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon gu32FlushedJoinReqSize = strWIDList[u32WidsCount].s32ValueSize; gu8FlushedJoinReq = WILC_MALLOC(gu32FlushedJoinReqSize); } - if (strWIDList[u32WidsCount].ps8WidVal == NULL) { + if (strWIDList[u32WidsCount].ps8WidVal == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } pu8CurrByte = strWIDList[u32WidsCount].ps8WidVal; @@ -1845,15 +1836,13 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon PRINT_D(HOSTINF_DBG, "* Cap Info %0x*\n", (*(pu8CurrByte - 2) | ((*(pu8CurrByte - 1)) << 8))); /* sa*/ - if (pstrHostIFconnectAttr->pu8bssid != NULL) { + if (pstrHostIFconnectAttr->pu8bssid != NULL) WILC_memcpy(pu8CurrByte, pstrHostIFconnectAttr->pu8bssid, 6); - } pu8CurrByte += 6; /* bssid*/ - if (pstrHostIFconnectAttr->pu8bssid != NULL) { + if (pstrHostIFconnectAttr->pu8bssid != NULL) WILC_memcpy(pu8CurrByte, pstrHostIFconnectAttr->pu8bssid, 6); - } pu8CurrByte += 6; /* Beacon Period*/ @@ -1990,9 +1979,8 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon WILC_memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); if (pstrHostIFconnectAttr->pfConnectResult != NULL) { - if (pstrHostIFconnectAttr->pu8bssid != NULL) { + if (pstrHostIFconnectAttr->pu8bssid != NULL) WILC_memcpy(strConnectInfo.au8bssid, pstrHostIFconnectAttr->pu8bssid, 6); - } if (pstrHostIFconnectAttr->pu8IEs != NULL) { strConnectInfo.ReqIEsLen = pstrHostIFconnectAttr->IEsLen; @@ -2039,9 +2027,8 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon pstrHostIFconnectAttr->pu8IEs = NULL; } - if (pu8CurrByte != NULL) { + if (pu8CurrByte != NULL) WILC_FREE(pu8CurrByte); - } return s32Error; } @@ -2186,9 +2173,8 @@ static s32 Handle_ConnectTimeout(void *drvHandler) PRINT_D(HOSTINF_DBG, "Sending disconnect request\n"); s32Error = SendConfigPkt(SET_CFG, &strWID, 1, false, (u32)pstrWFIDrv); - if (s32Error) { + if (s32Error) PRINT_ER("Failed to send dissconect config packet\n"); - } /* Deallocation of the Saved Connect Request in the global Handle */ pstrWFIDrv->strWILC_UsrConnReq.ssidLen = 0; @@ -2371,9 +2357,8 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst tstrDisconnectNotifInfo strDisconnectNotifInfo; s32 s32Err = WILC_SUCCESS; tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *) drvHandler; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) PRINT_ER("Driver handler is NULL\n"); - } PRINT_D(GENERIC_DBG, "Current State = %d,Received state = %d\n", pstrWFIDrv->enuHostIFstate, pstrRcvdGnrlAsyncInfo->pu8Buffer[7]); @@ -2654,10 +2639,9 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running Scan >> \n\n"); /*Abort the running scan*/ WILC_TimerStop(&(pstrWFIDrv->hScanTimer), NULL); - if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { + if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) Handle_ScanDone((void *)pstrWFIDrv, SCAN_EVENT_ABORTED); - } } } @@ -3463,9 +3447,8 @@ static void Handle_AddBeacon(void *drvHandler, tstrHostIFSetBeacon *pstrSetBeaco strWID.enuWIDtype = WID_BIN; strWID.s32ValueSize = pstrSetBeaconParam->u32HeadLen + pstrSetBeaconParam->u32TailLen + 16; strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); - if (strWID.ps8WidVal == NULL) { + if (strWID.ps8WidVal == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } pu8CurrByte = strWID.ps8WidVal; *pu8CurrByte++ = (pstrSetBeaconParam->u32Interval & 0xFF); @@ -3534,9 +3517,8 @@ static void Handle_DelBeacon(void *drvHandler, tstrHostIFDelBeacon *pstrDelBeaco strWID.s32ValueSize = sizeof(char); strWID.ps8WidVal = &gu8DelBcn; - if (strWID.ps8WidVal == NULL) { + if (strWID.ps8WidVal == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } pu8CurrByte = strWID.ps8WidVal; @@ -3580,9 +3562,8 @@ static u32 WILC_HostIf_PackStaParam(u8 *pu8Buffer, tstrWILC_AddStaParam *pstrSta *pu8CurrByte++ = (pstrStationParam->u16AssocID >> 8) & 0xFF; *pu8CurrByte++ = pstrStationParam->u8NumRates; - if (pstrStationParam->u8NumRates > 0) { + if (pstrStationParam->u8NumRates > 0) WILC_memcpy(pu8CurrByte, pstrStationParam->pu8Rates, pstrStationParam->u8NumRates); - } pu8CurrByte += pstrStationParam->u8NumRates; *pu8CurrByte++ = pstrStationParam->bIsHTSupported; @@ -3633,9 +3614,8 @@ static void Handle_AddStation(void *drvHandler, tstrWILC_AddStaParam *pstrStatio strWID.s32ValueSize = WILC_ADD_STA_LENGTH + pstrStationParam->u8NumRates; strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); - if (strWID.ps8WidVal == NULL) { + if (strWID.ps8WidVal == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } pu8CurrByte = strWID.ps8WidVal; pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam); @@ -3679,9 +3659,8 @@ static void Handle_DelAllSta(void *drvHandler, tstrHostIFDelAllSta *pstrDelAllSt PRINT_D(HOSTINF_DBG, "Handling delete station \n"); strWID.ps8WidVal = WILC_MALLOC((pstrDelAllStaParam->u8Num_AssocSta * ETH_ALEN) + 1); - if (strWID.ps8WidVal == NULL) { + if (strWID.ps8WidVal == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } pu8CurrByte = strWID.ps8WidVal; @@ -3736,9 +3715,8 @@ static void Handle_DelStation(void *drvHandler, tstrHostIFDelSta *pstrDelStaPara PRINT_D(HOSTINF_DBG, "Handling delete station \n"); strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); - if (strWID.ps8WidVal == NULL) { + if (strWID.ps8WidVal == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } pu8CurrByte = strWID.ps8WidVal; @@ -3781,9 +3759,8 @@ static void Handle_EditStation(void *drvHandler, tstrWILC_AddStaParam *pstrStati PRINT_D(HOSTINF_DBG, "Handling edit station\n"); strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); - if (strWID.ps8WidVal == NULL) { + if (strWID.ps8WidVal == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } pu8CurrByte = strWID.ps8WidVal; pu8CurrByte += WILC_HostIf_PackStaParam(pu8CurrByte, pstrStationParam); @@ -3858,18 +3835,16 @@ static int Handle_RemainOnChan(void *drvHandler, tstrHostIfRemainOnChan *pstrHos strWID.s32ValueSize = 2; strWID.ps8WidVal = (s8 *)WILC_MALLOC(strWID.s32ValueSize); - if (strWID.ps8WidVal == NULL) { + if (strWID.ps8WidVal == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } strWID.ps8WidVal[0] = u8remain_on_chan_flag; strWID.ps8WidVal[1] = (s8)pstrHostIfRemainOnChan->u16Channel; /*Sending Cfg*/ s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); - if (s32Error != WILC_SUCCESS) { + if (s32Error != WILC_SUCCESS) PRINT_ER("Failed to set remain on channel\n"); - } WILC_CATCH(-1) { @@ -3877,9 +3852,8 @@ static int Handle_RemainOnChan(void *drvHandler, tstrHostIfRemainOnChan *pstrHos WILC_TimerStart(&(pstrWFIDrv->hRemainOnChannel), pstrHostIfRemainOnChan->u32duration, (void *)pstrWFIDrv, NULL); /*Calling CFG ready_on_channel*/ - if (pstrWFIDrv->strHostIfRemainOnChan.pRemainOnChanReady) { + if (pstrWFIDrv->strHostIfRemainOnChan.pRemainOnChanReady) pstrWFIDrv->strHostIfRemainOnChan.pRemainOnChanReady(pstrWFIDrv->strHostIfRemainOnChan.pVoid); - } if (pstrWFIDrv->u8RemainOnChan_pendingreq) pstrWFIDrv->u8RemainOnChan_pendingreq = 0; @@ -3909,9 +3883,8 @@ static int Handle_RegisterFrame(void *drvHandler, tstrHostIfRegisterFrame *pstrH strWID.u16WIDid = (u16)WID_REGISTER_FRAME; strWID.enuWIDtype = WID_STR; strWID.ps8WidVal = WILC_MALLOC(sizeof(u16) + 2); - if (strWID.ps8WidVal == NULL) { + if (strWID.ps8WidVal == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } pu8CurrByte = strWID.ps8WidVal; @@ -3968,9 +3941,8 @@ static u32 Handle_ListenStateExpired(void *drvHandler, tstrHostIfRemainOnChan *p strWID.s32ValueSize = 2; strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); - if (strWID.ps8WidVal == NULL) { + if (strWID.ps8WidVal == NULL) PRINT_ER("Failed to allocate memory\n"); - } strWID.ps8WidVal[0] = u8remain_on_chan_flag; strWID.ps8WidVal[1] = FALSE_FRMWR_CHANNEL; @@ -4022,9 +3994,8 @@ static void ListenTimerCB(void *pvArg) /* send the message */ s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -4095,9 +4066,8 @@ static void Handle_SetMulticastFilter(void *drvHandler, tstrHostIFSetMulti *strH strWID.enuWIDtype = WID_BIN; strWID.s32ValueSize = sizeof(tstrHostIFSetMulti) + ((strHostIfSetMulti->u32count) * ETH_ALEN); strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); - if (strWID.ps8WidVal == NULL) { + if (strWID.ps8WidVal == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } pu8CurrByte = strWID.ps8WidVal; *pu8CurrByte++ = (strHostIfSetMulti->bIsEnabled & 0xFF); @@ -4430,9 +4400,8 @@ static int hostIFthread(void *pvArg) /*BugID_5213*/ /*Allow chip sleep, only if both interfaces are not connected*/ - if (!linux_wlan_get_num_conn_ifcs()) { + if (!linux_wlan_get_num_conn_ifcs()) chip_sleep_manually(INFINITE_SLEEP_TIME); - } Handle_ScanDone(strHostIFmsg.drvHandler, SCAN_EVENT_DONE); @@ -4649,9 +4618,8 @@ s32 host_int_remove_wep_key(WILC_WFIDrvHandle hWFIDrv, u8 u8keyIdx) tstrHostIFmsg strHostIFmsg; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /* prepare the Remove Wep Key Message */ WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -4699,9 +4667,8 @@ s32 host_int_set_WEPDefaultKeyID(WILC_WFIDrvHandle hWFIDrv, u8 u8Index) tstrHostIFmsg strHostIFmsg; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /* prepare the Key Message */ WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -4756,10 +4723,9 @@ s32 host_int_add_wep_key_bss_sta(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8WepKey, tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; tstrHostIFmsg strHostIFmsg; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /* prepare the Key Message */ WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -4823,10 +4789,9 @@ s32 host_int_add_wep_key_bss_ap(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8WepKey, tstrHostIFmsg strHostIFmsg; u8 i; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /* prepare the Key Message */ WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -4899,15 +4864,12 @@ s32 host_int_add_ptk(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8Ptk, u8 u8PtkKeylen tstrHostIFmsg strHostIFmsg; u8 u8KeyLen = u8PtkKeylen; u32 i; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } - if (pu8RxMic != NULL) { + if (pu8RxMic != NULL) u8KeyLen += RX_MIC_KEY_LEN; - } - if (pu8TxMic != NULL) { + if (pu8TxMic != NULL) u8KeyLen += TX_MIC_KEY_LEN; - } /* prepare the Key Message */ WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -5002,19 +4964,16 @@ s32 host_int_add_rx_gtk(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8RxGtk, u8 u8GtkK tstrHostIFmsg strHostIFmsg; u8 u8KeyLen = u8GtkKeylen; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /* prepare the Key Message */ WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); - if (pu8RxMic != NULL) { + if (pu8RxMic != NULL) u8KeyLen += RX_MIC_KEY_LEN; - } - if (pu8TxMic != NULL) { + if (pu8TxMic != NULL) u8KeyLen += TX_MIC_KEY_LEN; - } if (KeyRSC != NULL) { strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr. uniHostIFkeyAttr.strHostIFwpaAttr.pu8seq = (u8 *)WILC_MALLOC(u32KeyRSClen); @@ -5111,9 +5070,8 @@ s32 host_int_set_pmkid_info(WILC_WFIDrvHandle hWFIDrv, tstrHostIFpmkidAttr *pu8P u32 i; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /* prepare the Key Message */ WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -5464,9 +5422,8 @@ s32 host_int_set_join_req(WILC_WFIDrvHandle hWFIDrv, u8 *pu8bssid, tstrHostIFmsg strHostIFmsg; tenuScanConnTimer enuScanConnTimer; - if (pstrWFIDrv == NULL || pfConnectResult == NULL) { + if (pstrWFIDrv == NULL || pfConnectResult == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } if (hWFIDrv == NULL) { PRINT_ER("Driver not initialized: gWFiDrvHandle = NULL\n"); @@ -5564,9 +5521,8 @@ s32 host_int_flush_join_req(WILC_WFIDrvHandle hWFIDrv) } - if (hWFIDrv == NULL) { + if (hWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } strHostIFmsg.u16MsgId = HOST_IF_MSG_FLUSH_CONNECT; @@ -5800,9 +5756,8 @@ s32 host_int_set_mac_chnl_num(WILC_WFIDrvHandle hWFIDrv, u8 u8ChNum) tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; tstrHostIFmsg strHostIFmsg; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /* prepare the set channel message */ WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -5811,9 +5766,8 @@ s32 host_int_set_mac_chnl_num(WILC_WFIDrvHandle hWFIDrv, u8 u8ChNum) strHostIFmsg.drvHandler = hWFIDrv; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -5834,9 +5788,8 @@ s32 host_int_wait_msg_queue_idle(void) WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_Q_IDLE; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -5864,9 +5817,8 @@ s32 host_int_set_wfi_drv_handler(u32 u32address) /* strHostIFmsg.drvHandler=hWFIDrv; */ s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -5892,9 +5844,8 @@ s32 host_int_set_operation_mode(WILC_WFIDrvHandle hWFIDrv, u32 u32mode) strHostIFmsg.drvHandler = hWFIDrv; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -6229,9 +6180,8 @@ s32 host_int_scan(WILC_WFIDrvHandle hWFIDrv, u8 u8ScanSource, tstrHostIFmsg strHostIFmsg; tenuScanConnTimer enuScanConnTimer; - if (pstrWFIDrv == NULL || ScanResult == NULL) { + if (pstrWFIDrv == NULL || ScanResult == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /* prepare the Scan Message */ @@ -6301,9 +6251,8 @@ s32 hif_set_cfg(WILC_WFIDrvHandle hWFIDrv, tstrCfgParamVal *pstrCfgParamVal) tstrHostIFmsg strHostIFmsg; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /* prepare the WiphyParams Message */ WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_CFG_PARAMS; @@ -6794,9 +6743,8 @@ s32 host_int_deinit(WILC_WFIDrvHandle hWFIDrv) s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error != WILC_SUCCESS) { + if (s32Error != WILC_SUCCESS) PRINT_ER("Error in sending deinit's message queue message function: Error(%d)\n", s32Error); - } down(&hSemHostIFthrdEnd); @@ -6866,9 +6814,8 @@ void NetworkInfoReceived(u8 *pu8Buffer, u32 u32Length) /* send the message */ s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) PRINT_ER("Error in sending network info message queue message parameters: Error(%d)\n", s32Error); - } return; @@ -6930,9 +6877,8 @@ void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length) /* send the message */ s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) PRINT_ER("Error in sending message queue asynchronous message info: Error(%d)\n", s32Error); - } /*BugID_5348*/ up(&hSemHostIntDeinit); @@ -6960,9 +6906,8 @@ void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length) PRINT_D(GENERIC_DBG, "Scan notification received %p\n", pstrWFIDrv); - if (pstrWFIDrv == NULL || pstrWFIDrv == terminated_handle) { + if (pstrWFIDrv == NULL || pstrWFIDrv == terminated_handle) return; - } /*if there is an ongoing scan request*/ if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { @@ -6983,9 +6928,8 @@ void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length) /* send the message */ s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) PRINT_ER("Error in sending message queue scan complete parameters: Error(%d)\n", s32Error); - } } @@ -7014,9 +6958,8 @@ s32 host_int_remain_on_channel(WILC_WFIDrvHandle hWFIDrv, u32 u32SessionID, u32 tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; tstrHostIFmsg strHostIFmsg; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /* prepare the remainonchan Message */ WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -7032,9 +6975,8 @@ s32 host_int_remain_on_channel(WILC_WFIDrvHandle hWFIDrv, u32 u32SessionID, u32 strHostIFmsg.drvHandler = hWFIDrv; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -7063,9 +7005,8 @@ s32 host_int_ListenStateExpired(WILC_WFIDrvHandle hWFIDrv, u32 u32SessionID) tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; tstrHostIFmsg strHostIFmsg; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /*Stopping remain-on-channel timer*/ WILC_TimerStop(&(pstrWFIDrv->hRemainOnChannel), NULL); @@ -7077,9 +7018,8 @@ s32 host_int_ListenStateExpired(WILC_WFIDrvHandle hWFIDrv, u32 u32SessionID) strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan.u32ListenSessionID = u32SessionID; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -7101,9 +7041,8 @@ s32 host_int_frame_register(WILC_WFIDrvHandle hWFIDrv, u16 u16FrameType, bool bR tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; tstrHostIFmsg strHostIFmsg; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -7129,9 +7068,8 @@ s32 host_int_frame_register(WILC_WFIDrvHandle hWFIDrv, u16 u16FrameType, bool bR strHostIFmsg.drvHandler = hWFIDrv; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -7165,9 +7103,8 @@ s32 host_int_add_beacon(WILC_WFIDrvHandle hWFIDrv, u32 u32Interval, tstrHostIFmsg strHostIFmsg; tstrHostIFSetBeacon *pstrSetBeaconParam = &strHostIFmsg.uniHostIFmsgBody.strHostIFSetBeacon; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -7181,37 +7118,32 @@ s32 host_int_add_beacon(WILC_WFIDrvHandle hWFIDrv, u32 u32Interval, pstrSetBeaconParam->u32DTIMPeriod = u32DTIMPeriod; pstrSetBeaconParam->u32HeadLen = u32HeadLen; pstrSetBeaconParam->pu8Head = (u8 *)WILC_MALLOC(u32HeadLen); - if (pstrSetBeaconParam->pu8Head == NULL) { + if (pstrSetBeaconParam->pu8Head == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } WILC_memcpy(pstrSetBeaconParam->pu8Head, pu8Head, u32HeadLen); pstrSetBeaconParam->u32TailLen = u32TailLen; /* Bug 4599 : if tail length = 0 skip allocating & copying */ if (u32TailLen > 0) { pstrSetBeaconParam->pu8Tail = (u8 *)WILC_MALLOC(u32TailLen); - if (pstrSetBeaconParam->pu8Tail == NULL) { + if (pstrSetBeaconParam->pu8Tail == NULL) WILC_ERRORREPORT(s32Error, WILC_NO_MEM); - } WILC_memcpy(pstrSetBeaconParam->pu8Tail, pu8Tail, u32TailLen); } else { pstrSetBeaconParam->pu8Tail = NULL; } s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { - if (pstrSetBeaconParam->pu8Head != NULL) { + if (pstrSetBeaconParam->pu8Head != NULL) WILC_FREE(pstrSetBeaconParam->pu8Head); - } - if (pstrSetBeaconParam->pu8Tail != NULL) { + if (pstrSetBeaconParam->pu8Tail != NULL) WILC_FREE(pstrSetBeaconParam->pu8Tail); - } } return s32Error; @@ -7234,9 +7166,8 @@ s32 host_int_del_beacon(WILC_WFIDrvHandle hWFIDrv) tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; tstrHostIFmsg strHostIFmsg; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } /* prepare the WiphyParams Message */ strHostIFmsg.u16MsgId = HOST_IF_MSG_DEL_BEACON; @@ -7270,9 +7201,8 @@ s32 host_int_add_station(WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam *pstrSt tstrWILC_AddStaParam *pstrAddStationMsg = &strHostIFmsg.uniHostIFmsgBody.strAddStaParam; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -7294,9 +7224,8 @@ s32 host_int_add_station(WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam *pstrSt s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -7320,9 +7249,8 @@ s32 host_int_del_station(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8MacAddr) tstrHostIFmsg strHostIFmsg; tstrHostIFDelSta *pstrDelStationMsg = &strHostIFmsg.uniHostIFmsgBody.strDelStaParam; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -7341,9 +7269,8 @@ s32 host_int_del_station(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8MacAddr) WILC_memcpy(pstrDelStationMsg->au8MacAddr, pu8MacAddr, ETH_ALEN); s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -7370,9 +7297,8 @@ s32 host_int_del_allstation(WILC_WFIDrvHandle hWFIDrv, u8 pu8MacAddr[][ETH_ALEN] u8 u8AssocNumb = 0; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -7400,10 +7326,9 @@ s32 host_int_del_allstation(WILC_WFIDrvHandle hWFIDrv, u8 pu8MacAddr[][ETH_ALEN] s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -7430,9 +7355,8 @@ s32 host_int_edit_station(WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam *pstrS tstrHostIFmsg strHostIFmsg; tstrWILC_AddStaParam *pstrAddStationMsg = &strHostIFmsg.uniHostIFmsgBody.strAddStaParam; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } PRINT_D(HOSTINF_DBG, "Setting editing station message queue params\n"); @@ -7452,9 +7376,8 @@ s32 host_int_edit_station(WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam *pstrS } s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { } @@ -7472,9 +7395,8 @@ s32 host_int_set_power_mgmt(WILC_WFIDrvHandle hWFIDrv, bool bIsEnabled, u32 u32T PRINT_INFO(HOSTINF_DBG, "\n\n>> Setting PS to %d << \n\n", bIsEnabled); - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } PRINT_D(HOSTINF_DBG, "Setting Power management message queue params\n"); @@ -7490,9 +7412,8 @@ s32 host_int_set_power_mgmt(WILC_WFIDrvHandle hWFIDrv, bool bIsEnabled, u32 u32T s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { } @@ -7508,9 +7429,8 @@ s32 host_int_setup_multicast_filter(WILC_WFIDrvHandle hWFIDrv, bool bIsEnabled, tstrHostIFSetMulti *pstrMulticastFilterParam = &strHostIFmsg.uniHostIFmsgBody.strHostIfSetMulti; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } PRINT_D(HOSTINF_DBG, "Setting Multicast Filter params\n"); @@ -7525,9 +7445,8 @@ s32 host_int_setup_multicast_filter(WILC_WFIDrvHandle hWFIDrv, bool bIsEnabled, pstrMulticastFilterParam->u32count = u32count; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { } @@ -7633,9 +7552,8 @@ static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo) pNewJoinBssParam->wmm_cap = true; /* Check if Bit 7 is set indicating U-APSD capability */ - if (pu8IEs[index + 8] & (1 << 7)) { + if (pu8IEs[index + 8] & (1 << 7)) pNewJoinBssParam->uapsd_cap = true; - } index += pu8IEs[index + 1] + 2; continue; } @@ -7779,9 +7697,8 @@ static int host_int_addBASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char T tstrHostIFmsg strHostIFmsg; tstrHostIfBASessionInfo *pBASessionInfo = &strHostIFmsg.uniHostIFmsgBody.strHostIfBASessionInfo; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -7795,9 +7712,8 @@ static int host_int_addBASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char T strHostIFmsg.drvHandler = hWFIDrv; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -7814,9 +7730,8 @@ s32 host_int_delBASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char TID) tstrHostIFmsg strHostIFmsg; tstrHostIfBASessionInfo *pBASessionInfo = &strHostIFmsg.uniHostIFmsgBody.strHostIfBASessionInfo; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -7828,9 +7743,8 @@ s32 host_int_delBASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char TID) strHostIFmsg.drvHandler = hWFIDrv; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -7849,9 +7763,8 @@ s32 host_int_del_All_Rx_BASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char tstrHostIFmsg strHostIFmsg; tstrHostIfBASessionInfo *pBASessionInfo = &strHostIFmsg.uniHostIFmsgBody.strHostIfBASessionInfo; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -7863,9 +7776,8 @@ s32 host_int_del_All_Rx_BASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char strHostIFmsg.drvHandler = hWFIDrv; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -7894,9 +7806,8 @@ s32 host_int_setup_ipaddress(WILC_WFIDrvHandle hWFIDrv, u8 *u16ipadd, u8 idx) /* TODO: Enable This feature on softap firmware */ return 0; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -7908,9 +7819,8 @@ s32 host_int_setup_ipaddress(WILC_WFIDrvHandle hWFIDrv, u8 *u16ipadd, u8 idx) strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.idx = idx; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { @@ -7935,9 +7845,8 @@ s32 host_int_get_ipaddress(WILC_WFIDrvHandle hWFIDrv, u8 *u16ipadd, u8 idx) tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; tstrHostIFmsg strHostIFmsg; - if (pstrWFIDrv == NULL) { + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - } WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); @@ -7949,9 +7858,8 @@ s32 host_int_get_ipaddress(WILC_WFIDrvHandle hWFIDrv, u8 *u16ipadd, u8 idx) strHostIFmsg.uniHostIFmsgBody.strHostIfSetIP.idx = idx; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); - if (s32Error) { + if (s32Error) WILC_ERRORREPORT(s32Error, s32Error); - } WILC_CATCH(s32Error) { -- cgit v1.3-6-gb490 From 78c87591d4d50e0cb3e670a909e63db92409c4c5 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 26 Jun 2015 16:45:14 +0200 Subject: staging: wilc1000: add blank lines after declarations Fix all checkpatch.pl warnings: WARNING: Missing a blank line after declarations Signed-off-by: Luis de Bethencourt Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index bf183b2f39f4..e13074fb5c22 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -841,6 +841,7 @@ static s32 Handle_SetMacAddress(void *drvHandler, tstrHostIfSetMacAddress *pstrH tstrWID strWID; tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; u8 *mac_buf = (u8 *)WILC_MALLOC(ETH_ALEN); + if (mac_buf == NULL) { PRINT_ER("No buffer to send mac address\n"); return WILC_FAIL; @@ -1225,6 +1226,7 @@ static s32 Handle_CfgParam(void *drvHandler, tstrHostIFCfgParamAttr *strHostIFCf static s32 Handle_wait_msg_q_empty(void) { s32 s32Error = WILC_SUCCESS; + g_wilc_initialized = 0; up(&hWaitResponse); return s32Error; @@ -2357,6 +2359,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst tstrDisconnectNotifInfo strDisconnectNotifInfo; s32 s32Err = WILC_SUCCESS; tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *) drvHandler; + if (pstrWFIDrv == NULL) PRINT_ER("Driver handler is NULL\n"); PRINT_D(GENERIC_DBG, "Current State = %d,Received state = %d\n", pstrWFIDrv->enuHostIFstate, @@ -3208,6 +3211,7 @@ static s32 Handle_GetChnl(void *drvHandler) tstrWID strWID; /* tstrWILC_WFIDrv * pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; */ tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + strWID.u16WIDid = (u16)WID_CURRENT_CHANNEL; strWID.enuWIDtype = WID_CHAR; strWID.ps8WidVal = (s8 *)&gu8Chnl; @@ -3441,6 +3445,7 @@ static void Handle_AddBeacon(void *drvHandler, tstrHostIFSetBeacon *pstrSetBeaco tstrWID strWID; u8 *pu8CurrByte; tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + PRINT_D(HOSTINF_DBG, "Adding BEACON\n"); strWID.u16WIDid = (u16)WID_ADD_BEACON; @@ -3512,6 +3517,7 @@ static void Handle_DelBeacon(void *drvHandler, tstrHostIFDelBeacon *pstrDelBeaco tstrWID strWID; u8 *pu8CurrByte; tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + strWID.u16WIDid = (u16)WID_DEL_BEACON; strWID.enuWIDtype = WID_CHAR; strWID.s32ValueSize = sizeof(char); @@ -3608,6 +3614,7 @@ static void Handle_AddStation(void *drvHandler, tstrWILC_AddStaParam *pstrStatio tstrWID strWID; u8 *pu8CurrByte; tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + PRINT_D(HOSTINF_DBG, "Handling add station\n"); strWID.u16WIDid = (u16)WID_ADD_STA; strWID.enuWIDtype = WID_BIN; @@ -3647,11 +3654,13 @@ static void Handle_AddStation(void *drvHandler, tstrWILC_AddStaParam *pstrStatio static void Handle_DelAllSta(void *drvHandler, tstrHostIFDelAllSta *pstrDelAllStaParam) { s32 s32Error = WILC_SUCCESS; + tstrWID strWID; u8 *pu8CurrByte; tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; u8 i; u8 au8Zero_Buff[6] = {0}; + strWID.u16WIDid = (u16)WID_DEL_ALL_STA; strWID.enuWIDtype = WID_STR; strWID.s32ValueSize = (pstrDelAllStaParam->u8Num_AssocSta * ETH_ALEN) + 1; @@ -4019,6 +4028,7 @@ static void Handle_PowerManagement(void *drvHandler, tstrHostIfPowerMgmtParam *s tstrWID strWID; s8 s8PowerMode; tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; + strWID.u16WIDid = (u16)WID_POWER_MANAGEMENT; if (strPowerMgmtParam->bIsEnabled == true) { @@ -4864,6 +4874,7 @@ s32 host_int_add_ptk(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8Ptk, u8 u8PtkKeylen tstrHostIFmsg strHostIFmsg; u8 u8KeyLen = u8PtkKeylen; u32 i; + if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); if (pu8RxMic != NULL) @@ -6421,6 +6432,7 @@ void host_int_send_join_leave_info_to_host void GetPeriodicRSSI(void *pvArg) { tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)pvArg; + if (pstrWFIDrv == NULL) { PRINT_ER("Driver handler is NULL\n"); return; @@ -6900,6 +6912,7 @@ void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length) tstrHostIFmsg strHostIFmsg; u32 drvHandler; tstrWILC_WFIDrv *pstrWFIDrv = NULL; + drvHandler = ((pu8Buffer[u32Length - 4]) | (pu8Buffer[u32Length - 3] << 8) | (pu8Buffer[u32Length - 2] << 16) | (pu8Buffer[u32Length - 1] << 24)); pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; @@ -7216,6 +7229,7 @@ s32 host_int_add_station(WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam *pstrSt WILC_memcpy(pstrAddStationMsg, pstrStaParams, sizeof(tstrWILC_AddStaParam)); if (pstrAddStationMsg->u8NumRates > 0) { u8 *rates = WILC_MALLOC(pstrAddStationMsg->u8NumRates); + WILC_NULLCHECK(s32Error, rates); WILC_memcpy(rates, pstrStaParams->pu8Rates, pstrAddStationMsg->u8NumRates); @@ -7370,6 +7384,7 @@ s32 host_int_edit_station(WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam *pstrS WILC_memcpy(pstrAddStationMsg, pstrStaParams, sizeof(tstrWILC_AddStaParam)); if (pstrAddStationMsg->u8NumRates > 0) { u8 *rates = WILC_MALLOC(pstrAddStationMsg->u8NumRates); + WILC_NULLCHECK(s32Error, rates); WILC_memcpy(rates, pstrStaParams->pu8Rates, pstrAddStationMsg->u8NumRates); pstrAddStationMsg->pu8Rates = rates; @@ -7563,6 +7578,7 @@ static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo) (pu8IEs[index + 4] == 0x9a) && /* OUI */ (pu8IEs[index + 5] == 0x09) && (pu8IEs[index + 6] == 0x0c)) { /* OUI Type */ u16 u16P2P_count; + pNewJoinBssParam->tsf = ptstrNetworkInfo->u32Tsf; pNewJoinBssParam->u8NoaEnbaled = 1; pNewJoinBssParam->u8Index = pu8IEs[index + 9]; -- cgit v1.3-6-gb490 From 03b2d5e75088564c35297bd6192d1a5b504e7298 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 26 Jun 2015 16:45:58 +0200 Subject: staging: wilc1000: remove whitespaces before quoted newlines Fix all checkpatch.pl warnings: WARNING: unnecessary whitespace before a quoted newline Signed-off-by: Luis de Bethencourt Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 84 +++++++++++++++---------------- 1 file changed, 42 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index e13074fb5c22..79b7c2ab03b2 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -699,7 +699,7 @@ static s32 Handle_SetOperationMode(void *drvHandler, tstrHostIfSetOperationMode strWID.s32ValueSize = sizeof(u32); /*Sending Cfg*/ - PRINT_INFO(HOSTINF_DBG, "pstrWFIDrv= %p \n", pstrWFIDrv); + PRINT_INFO(HOSTINF_DBG, "pstrWFIDrv= %p\n", pstrWFIDrv); s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); @@ -740,7 +740,7 @@ s32 Handle_set_IPAddress(void *drvHandler, u8 *pu8IPAddr, u8 idx) if (pu8IPAddr[0] < 192) pu8IPAddr[0] = 0; - PRINT_INFO(HOSTINF_DBG, "Indx = %d, Handling set IP = %d.%d.%d.%d \n", idx, pu8IPAddr[0], pu8IPAddr[1], pu8IPAddr[2], pu8IPAddr[3]); + PRINT_INFO(HOSTINF_DBG, "Indx = %d, Handling set IP = %d.%d.%d.%d\n", idx, pu8IPAddr[0], pu8IPAddr[1], pu8IPAddr[2], pu8IPAddr[3]); WILC_memcpy(gs8SetIP[idx], pu8IPAddr, IP_ALEN); @@ -810,7 +810,7 @@ s32 Handle_get_IPAddress(void *drvHandler, u8 *pu8IPAddr, u8 idx) PRINT_ER("Failed to get IP address\n"); WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); } else { - PRINT_INFO(HOSTINF_DBG, "IP address retrieved:: u8IfIdx = %d \n", idx); + PRINT_INFO(HOSTINF_DBG, "IP address retrieved:: u8IfIdx = %d\n", idx); PRINT_INFO(HOSTINF_DBG, "%d.%d.%d.%d\n", gs8GetIP[idx][0], gs8GetIP[idx][1], gs8GetIP[idx][2], gs8GetIP[idx][3]); PRINT_INFO(HOSTINF_DBG, "\n"); } @@ -1253,7 +1253,7 @@ static s32 Handle_Scan(void *drvHandler, tstrHostIFscanAttr *pstrHostIFscanAttr) tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *) drvHandler; PRINT_D(HOSTINF_DBG, "Setting SCAN params\n"); - PRINT_D(HOSTINF_DBG, "Scanning: In [%d] state \n", pstrWFIDrv->enuHostIFstate); + PRINT_D(HOSTINF_DBG, "Scanning: In [%d] state\n", pstrWFIDrv->enuHostIFstate); pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult = pstrHostIFscanAttr->pfScanResult; pstrWFIDrv->strWILC_UsrScanReq.u32UserScanPvoid = pstrHostIFscanAttr->pvUserArg; @@ -1524,7 +1524,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon DeallocateSurveyResults(pstrSurveyResults); } else { WILC_ERRORREPORT(s32Error, WILC_FAIL); - PRINT_ER("ParseSurveyResults() Error(%d) \n", s32Err); + PRINT_ER("ParseSurveyResults() Error(%d)\n", s32Err); } @@ -1555,7 +1555,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon if (i < pstrWFIDrv->u32SurveyResultsCount) { u8bssDscListIndex = i; - PRINT_INFO(HOSTINF_DBG, "Connecting to network of Bss Idx %d and SSID %s and channel %d \n", + PRINT_INFO(HOSTINF_DBG, "Connecting to network of Bss Idx%d and SSID %s and channel%d\n", u8bssDscListIndex, pstrWFIDrv->astrSurveyResults[u8bssDscListIndex].SSID, pstrWFIDrv->astrSurveyResults[u8bssDscListIndex].Channel); @@ -2006,7 +2006,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon } } else { - PRINT_ER("Connect callback function pointer is NULL \n"); + PRINT_ER("Connect callback function pointer is NULL\n"); } } @@ -2162,7 +2162,7 @@ static s32 Handle_ConnectTimeout(void *drvHandler) strConnectInfo.pu8ReqIEs = NULL; } } else { - PRINT_ER("Connect callback function pointer is NULL \n"); + PRINT_ER("Connect callback function pointer is NULL\n"); } /* Here we will notify our firmware also with the Connection failure {through sending to it Cfg packet carrying @@ -2301,7 +2301,7 @@ static s32 Handle_RcvdNtwrkInfo(void *drvHandler, tstrRcvdNetworkInfo *pstrRcvdN } } else { - PRINT_WRN(HOSTINF_DBG, "Discovered networks exceeded max. limit \n"); + PRINT_WRN(HOSTINF_DBG, "Discovered networks exceeded max. limit\n"); } } else { pstrNetworkInfo->bNewNetwork = false; @@ -2423,7 +2423,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst s32Err = ParseAssocRespInfo(gapu8RcvdAssocResp, u32RcvdAssocRespInfoLen, &pstrConnectRespInfo); if (s32Err) { - PRINT_ER("ParseAssocRespInfo() returned error %d \n", s32Err); + PRINT_ER("ParseAssocRespInfo() returned error %d\n", s32Err); } else { /* use the necessary parsed Info from the Received Association Response */ strConnectInfo.u16ConnectStatus = pstrConnectRespInfo->u16ConnectStatus; @@ -2454,7 +2454,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst * So check first the matching between the received mac status and the received status code in Asoc Resp */ if ((u8MacStatus == MAC_CONNECTED) && (strConnectInfo.u16ConnectStatus != SUCCESSFUL_STATUSCODE)) { - PRINT_ER("Received MAC status is MAC_CONNECTED while the received status code in Asoc Resp is not SUCCESSFUL_STATUSCODE \n"); + PRINT_ER("Received MAC status is MAC_CONNECTED while the received status code in Asoc Resp is not SUCCESSFUL_STATUSCODE\n"); WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); } else if (u8MacStatus == MAC_DISCONNECTED) { @@ -2563,7 +2563,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst WILC_memset(&strDisconnectNotifInfo, 0, sizeof(tstrDisconnectNotifInfo)); if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { - PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running OBSS Scan >> \n\n"); + PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running OBSS Scan >>\n\n"); WILC_TimerStop(&(pstrWFIDrv->hScanTimer), NULL); Handle_ScanDone((void *)pstrWFIDrv, SCAN_EVENT_ABORTED); } @@ -2586,7 +2586,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst pstrWFIDrv->strWILC_UsrConnReq.u32UserConnectPvoid); } else { - PRINT_ER("Connect result callback function is NULL \n"); + PRINT_ER("Connect result callback function is NULL\n"); } WILC_memset(pstrWFIDrv->au8AssociatedBSSID, 0, ETH_ALEN); @@ -2639,7 +2639,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst } else if ((u8MacStatus == MAC_DISCONNECTED) && (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult != NULL)) { PRINT_D(HOSTINF_DBG, "Received MAC_DISCONNECTED from the FW while scanning\n"); - PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running Scan >> \n\n"); + PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running Scan >>\n\n"); /*Abort the running scan*/ WILC_TimerStop(&(pstrWFIDrv->hScanTimer), NULL); if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) @@ -2859,7 +2859,7 @@ static int Handle_Key(void *drvHandler, tstrHostIFkeyAttr *pstrHostIFkeyAttr) if (pstrWFIDrv->enuHostIFstate == HOST_IF_CONNECTED) { WILC_memcpy(pu8keybuf, pstrWFIDrv->au8AssociatedBSSID, ETH_ALEN); } else { - PRINT_ER("Couldn't handle WPARxGtk while enuHostIFstate is not HOST_IF_CONNECTED \n"); + PRINT_ER("Couldn't handle WPARxGtk while enuHostIFstate is not HOST_IF_CONNECTED\n"); } WILC_memcpy(pu8keybuf + 6, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8seq, 8); @@ -3095,7 +3095,7 @@ static void Handle_Disconnect(void *drvHandler) pstrWFIDrv->strWILC_UsrConnReq.pfUserConnectResult(CONN_DISCONN_EVENT_DISCONN_NOTIF, NULL, 0, &strDisconnectNotifInfo, pstrWFIDrv->strWILC_UsrConnReq.u32UserConnectPvoid); } else { - PRINT_ER("strWILC_UsrConnReq.pfUserConnectResult = NULL \n"); + PRINT_ER("strWILC_UsrConnReq.pfUserConnectResult = NULL\n"); } gbScanWhileConnected = false; @@ -3181,7 +3181,7 @@ static s32 Switch_Log_Terminal(void *drvHandler) PRINT_D(HOSTINF_DBG, "Failed to switch log terminal\n"); WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); } else { - PRINT_INFO(HOSTINF_DBG, "MAC address set :: \n"); + PRINT_INFO(HOSTINF_DBG, "MAC address set ::\n"); } @@ -3665,7 +3665,7 @@ static void Handle_DelAllSta(void *drvHandler, tstrHostIFDelAllSta *pstrDelAllSt strWID.enuWIDtype = WID_STR; strWID.s32ValueSize = (pstrDelAllStaParam->u8Num_AssocSta * ETH_ALEN) + 1; - PRINT_D(HOSTINF_DBG, "Handling delete station \n"); + PRINT_D(HOSTINF_DBG, "Handling delete station\n"); strWID.ps8WidVal = WILC_MALLOC((pstrDelAllStaParam->u8Num_AssocSta * ETH_ALEN) + 1); if (strWID.ps8WidVal == NULL) @@ -3721,7 +3721,7 @@ static void Handle_DelStation(void *drvHandler, tstrHostIFDelSta *pstrDelStaPara strWID.enuWIDtype = WID_BIN; strWID.s32ValueSize = ETH_ALEN; - PRINT_D(HOSTINF_DBG, "Handling delete station \n"); + PRINT_D(HOSTINF_DBG, "Handling delete station\n"); strWID.ps8WidVal = WILC_MALLOC(strWID.s32ValueSize); if (strWID.ps8WidVal == NULL) @@ -4126,7 +4126,7 @@ static s32 Handle_AddBASession(void *drvHandler, tstrHostIfBASessionInfo *strHos char *ptr = NULL; tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; - PRINT_D(HOSTINF_DBG, "Opening Block Ack session with\nBSSID = %.2x:%.2x:%.2x \nTID=%d \nBufferSize == %d \nSessionTimeOut = %d\n", + PRINT_D(HOSTINF_DBG, "Opening Block Ack session with\nBSSID = %.2x:%.2x:%.2x\nTID=%d\nBufferSize == %d\nSessionTimeOut = %d\n", strHostIfBASessionInfo->au8Bssid[0], strHostIfBASessionInfo->au8Bssid[1], strHostIfBASessionInfo->au8Bssid[2], @@ -4213,7 +4213,7 @@ static s32 Handle_DelBASession(void *drvHandler, tstrHostIfBASessionInfo *strHos char *ptr = NULL; tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; - PRINT_D(GENERIC_DBG, "Delete Block Ack session with\nBSSID = %.2x:%.2x:%.2x \nTID=%d\n", + PRINT_D(GENERIC_DBG, "Delete Block Ack session with\nBSSID = %.2x:%.2x:%.2x\nTID=%d\n", strHostIfBASessionInfo->au8Bssid[0], strHostIfBASessionInfo->au8Bssid[1], strHostIfBASessionInfo->au8Bssid[2], @@ -4283,7 +4283,7 @@ static s32 Handle_DelAllRxBASessions(void *drvHandler, tstrHostIfBASessionInfo * char *ptr = NULL; tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; - PRINT_D(GENERIC_DBG, "Delete Block Ack session with\nBSSID = %.2x:%.2x:%.2x \nTID=%d\n", + PRINT_D(GENERIC_DBG, "Delete Block Ack session with\nBSSID = %.2x:%.2x:%.2x\nTID=%d\n", strHostIfBASessionInfo->au8Bssid[0], strHostIfBASessionInfo->au8Bssid[1], strHostIfBASessionInfo->au8Bssid[2], @@ -4471,7 +4471,7 @@ static int hostIFthread(void *pvArg) break; case HOST_IF_MSG_CONNECT_TIMER_FIRED: - PRINT_D(HOSTINF_DBG, "Connect Timeout \n"); + PRINT_D(HOSTINF_DBG, "Connect Timeout\n"); Handle_ConnectTimeout(strHostIFmsg.drvHandler); break; @@ -4542,7 +4542,7 @@ static int hostIFthread(void *pvArg) break; default: - PRINT_ER("[Host Interface] undefined Received Msg ID \n"); + PRINT_ER("[Host Interface] undefined Received Msg ID\n"); break; } } @@ -4648,7 +4648,7 @@ s32 host_int_remove_wep_key(WILC_WFIDrvHandle hWFIDrv, u8 u8keyIdx) /* send the message */ s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); if (s32Error) - PRINT_ER("Error in sending message queue : Request to remove WEP key \n"); + PRINT_ER("Error in sending message queue : Request to remove WEP key\n"); down(&(pstrWFIDrv->hSemTestKeyBlock)); WILC_CATCH(s32Error) @@ -5571,7 +5571,7 @@ s32 host_int_disconnect(WILC_WFIDrvHandle hWFIDrv, u16 u16ReasonCode) tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; if (pstrWFIDrv == NULL) { - PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL\n"); WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); } @@ -5688,7 +5688,7 @@ s32 host_int_get_assoc_res_info(WILC_WFIDrvHandle hWFIDrv, u8 *pu8AssocRespInfo, tstrWILC_WFIDrv *pstrWFIDrv = (tstrWILC_WFIDrv *)hWFIDrv; if (pstrWFIDrv == NULL) { - PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL\n"); WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); } @@ -5887,7 +5887,7 @@ s32 host_int_get_host_chnl_num(WILC_WFIDrvHandle hWFIDrv, u8 *pu8ChNo) tstrHostIFmsg strHostIFmsg; if (pstrWFIDrv == NULL) { - PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL\n"); WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); } @@ -5934,7 +5934,7 @@ s32 host_int_test_set_int_wid(WILC_WFIDrvHandle hWFIDrv, u32 u32TestMemAddr) if (pstrWFIDrv == NULL) { - PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL\n"); WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); } @@ -5980,7 +5980,7 @@ s32 host_int_get_inactive_time(WILC_WFIDrvHandle hWFIDrv, const u8 *mac, u32 *pu tstrHostIFmsg strHostIFmsg; if (pstrWFIDrv == NULL) { - PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL\n"); WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); } @@ -6028,7 +6028,7 @@ s32 host_int_test_get_int_wid(WILC_WFIDrvHandle hWFIDrv, u32 *pu32TestMemAddr) if (pstrWFIDrv == NULL) { - PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL\n"); WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); } @@ -6302,7 +6302,7 @@ s32 hif_get_cfg(WILC_WFIDrvHandle hWFIDrv, u16 u16WID, u16 *pu16WID_Value) down(&(pstrWFIDrv->gtOsCfgValuesSem)); if (pstrWFIDrv == NULL) { - PRINT_ER("Driver not initialized: pstrWFIDrv = NULL \n"); + PRINT_ER("Driver not initialized: pstrWFIDrv = NULL\n"); WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); } PRINT_D(HOSTINF_DBG, "Getting configuration parameters\n"); @@ -6699,18 +6699,18 @@ s32 host_int_deinit(WILC_WFIDrvHandle hWFIDrv) /*Destroy all timers before acquiring hSemDeinitDrvHandle*/ /*to guarantee handling all messages befor proceeding*/ if (WILC_TimerDestroy(&(pstrWFIDrv->hScanTimer), NULL)) { - PRINT_D(HOSTINF_DBG, ">> Scan timer is active \n"); + PRINT_D(HOSTINF_DBG, ">> Scan timer is active\n"); /* msleep(HOST_IF_SCAN_TIMEOUT+1000); */ } if (WILC_TimerDestroy(&(pstrWFIDrv->hConnectTimer), NULL)) { - PRINT_D(HOSTINF_DBG, ">> Connect timer is active \n"); + PRINT_D(HOSTINF_DBG, ">> Connect timer is active\n"); /* msleep(HOST_IF_CONNECT_TIMEOUT+1000); */ } if (WILC_TimerDestroy(&(g_hPeriodicRSSI), NULL)) { - PRINT_D(HOSTINF_DBG, ">> Connect timer is active \n"); + PRINT_D(HOSTINF_DBG, ">> Connect timer is active\n"); /* msleep(HOST_IF_CONNECT_TIMEOUT+1000); */ } @@ -6747,7 +6747,7 @@ s32 host_int_deinit(WILC_WFIDrvHandle hWFIDrv) if (clients_count == 1) { if (WILC_TimerDestroy(&g_hPeriodicRSSI, NULL)) { - PRINT_D(HOSTINF_DBG, ">> Connect timer is active \n"); + PRINT_D(HOSTINF_DBG, ">> Connect timer is active\n"); /* msleep(HOST_IF_CONNECT_TIMEOUT+1000); */ } strHostIFmsg.u16MsgId = HOST_IF_MSG_EXIT; @@ -6856,7 +6856,7 @@ void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length) drvHandler = ((pu8Buffer[u32Length - 4]) | (pu8Buffer[u32Length - 3] << 8) | (pu8Buffer[u32Length - 2] << 16) | (pu8Buffer[u32Length - 1] << 24)); pstrWFIDrv = (tstrWILC_WFIDrv *)drvHandler; - PRINT_D(HOSTINF_DBG, "General asynchronous info packet received \n"); + PRINT_D(HOSTINF_DBG, "General asynchronous info packet received\n"); if (pstrWFIDrv == NULL || pstrWFIDrv == terminated_handle) { @@ -7408,7 +7408,7 @@ s32 host_int_set_power_mgmt(WILC_WFIDrvHandle hWFIDrv, bool bIsEnabled, u32 u32T tstrHostIFmsg strHostIFmsg; tstrHostIfPowerMgmtParam *pstrPowerMgmtParam = &strHostIFmsg.uniHostIFmsgBody.strPowerMgmtparam; - PRINT_INFO(HOSTINF_DBG, "\n\n>> Setting PS to %d << \n\n", bIsEnabled); + PRINT_INFO(HOSTINF_DBG, "\n\n>> Setting PS to %d <<\n\n", bIsEnabled); if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); @@ -7590,9 +7590,9 @@ static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo) } else pNewJoinBssParam->u8OppEnable = 0; /* HOSTINF_DBG */ - PRINT_D(GENERIC_DBG, "P2P Dump \n"); + PRINT_D(GENERIC_DBG, "P2P Dump\n"); for (i = 0; i < pu8IEs[index + 7]; i++) - PRINT_D(GENERIC_DBG, " %x \n", pu8IEs[index + 9 + i]); + PRINT_D(GENERIC_DBG, " %x\n", pu8IEs[index + 9 + i]); pNewJoinBssParam->u8Count = pu8IEs[index + 11]; u16P2P_count = index + 12; @@ -7632,7 +7632,7 @@ static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo) rsnIndex += 7; /* skipping id, length, version(2B) and first 3 bytes of gcipher */ pNewJoinBssParam->rsn_grp_policy = pu8IEs[rsnIndex]; rsnIndex++; - /* PRINT_D(HOSTINF_DBG,"Group Policy: %0x \n",pNewJoinBssParam->rsn_grp_policy); */ + /* PRINT_D(HOSTINF_DBG,"Group Policy: %0x\n",pNewJoinBssParam->rsn_grp_policy); */ /* initialize policies with invalid values */ jumpOffset = pu8IEs[rsnIndex] * 4; /* total no.of bytes of pcipher field (count*4) */ @@ -7643,7 +7643,7 @@ static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo) pcipherCount = (pu8IEs[rsnIndex] > 3) ? 3 : pu8IEs[rsnIndex]; rsnIndex += 2; /* jump 2 bytes of pcipher count */ - /* PRINT_D(HOSTINF_DBG,"\npcipher:%d \n",pcipherCount); */ + /* PRINT_D(HOSTINF_DBG,"\npcipher:%d\n",pcipherCount); */ for (i = pcipherTotalCount, j = 0; i < pcipherCount + pcipherTotalCount && i < 3; i++, j++) { /* each count corresponds to 4 bytes, only last byte is saved */ pNewJoinBssParam->rsn_pcip_policy[i] = pu8IEs[rsnIndex + ((j + 1) * 4) - 1]; -- cgit v1.3-6-gb490 From 83cc9be5ebef180efb7df74c0518149a749e7c42 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 26 Jun 2015 16:47:28 +0200 Subject: staging: wilc1000: fix typos in PRINT_ERR() Fix typo "packe" to "packet". Signed-off-by: Luis de Bethencourt Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 79b7c2ab03b2..1915fc6b5176 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -3688,7 +3688,7 @@ static void Handle_DelAllSta(void *drvHandler, tstrHostIFDelAllSta *pstrDelAllSt s32Error = SendConfigPkt(SET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); if (s32Error) { - PRINT_ER("Failed to send add station config packe\n"); + PRINT_ER("Failed to send add station config packet\n"); WILC_ERRORREPORT(s32Error, WILC_FAIL); } @@ -3735,7 +3735,7 @@ static void Handle_DelStation(void *drvHandler, tstrHostIFDelSta *pstrDelStaPara s32Error = SendConfigPkt(SET_CFG, &strWID, 1, false, (u32)pstrWFIDrv); if (s32Error) { - PRINT_ER("Failed to send add station config packe\n"); + PRINT_ER("Failed to send add station config packet\n"); WILC_ERRORREPORT(s32Error, WILC_FAIL); } -- cgit v1.3-6-gb490 From b3a02832e47629c08b27589688c788d6af87e738 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 26 Jun 2015 17:40:25 +0200 Subject: staging: wilc1000: switch printks to vsprintf IPv4 extension Switch printks with IP addresses to use vsprintf extension %pI4. Suggested-by: Joe Perches Signed-off-by: Luis de Bethencourt Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 1915fc6b5176..483926f28436 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -740,7 +740,7 @@ s32 Handle_set_IPAddress(void *drvHandler, u8 *pu8IPAddr, u8 idx) if (pu8IPAddr[0] < 192) pu8IPAddr[0] = 0; - PRINT_INFO(HOSTINF_DBG, "Indx = %d, Handling set IP = %d.%d.%d.%d\n", idx, pu8IPAddr[0], pu8IPAddr[1], pu8IPAddr[2], pu8IPAddr[3]); + PRINT_INFO(HOSTINF_DBG, "Indx = %d, Handling set IP = %pI4\n", idx, pu8IPAddr); WILC_memcpy(gs8SetIP[idx], pu8IPAddr, IP_ALEN); @@ -796,7 +796,7 @@ s32 Handle_get_IPAddress(void *drvHandler, u8 *pu8IPAddr, u8 idx) s32Error = SendConfigPkt(GET_CFG, &strWID, 1, true, (u32)pstrWFIDrv); - PRINT_INFO(HOSTINF_DBG, "%d.%d.%d.%d\n", (u8)(strWID.ps8WidVal[0]), (u8)(strWID.ps8WidVal[1]), (u8)(strWID.ps8WidVal[2]), (u8)(strWID.ps8WidVal[3])); + PRINT_INFO(HOSTINF_DBG, "%pI4\n", strWID.ps8WidVal); WILC_memcpy(gs8GetIP[idx], strWID.ps8WidVal, IP_ALEN); @@ -811,7 +811,7 @@ s32 Handle_get_IPAddress(void *drvHandler, u8 *pu8IPAddr, u8 idx) WILC_ERRORREPORT(s32Error, WILC_INVALID_STATE); } else { PRINT_INFO(HOSTINF_DBG, "IP address retrieved:: u8IfIdx = %d\n", idx); - PRINT_INFO(HOSTINF_DBG, "%d.%d.%d.%d\n", gs8GetIP[idx][0], gs8GetIP[idx][1], gs8GetIP[idx][2], gs8GetIP[idx][3]); + PRINT_INFO(HOSTINF_DBG, "%pI4\n", gs8GetIP[idx]); PRINT_INFO(HOSTINF_DBG, "\n"); } -- cgit v1.3-6-gb490 From 137b9938849901f8e402da15736125b0a0bd2477 Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Mon, 29 Jun 2015 12:43:32 +0000 Subject: staging:wilc1000: code cleanup Fix reported by coccinelle Removed {} for single statement if block Signed-off-by: Prasanna Karthik Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/fifo_buffer.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/fifo_buffer.c b/drivers/staging/wilc1000/fifo_buffer.c index b6c07cfc43d2..86eb82e36be0 100644 --- a/drivers/staging/wilc1000/fifo_buffer.c +++ b/drivers/staging/wilc1000/fifo_buffer.c @@ -31,11 +31,10 @@ u32 FIFO_DeInit(tHANDLE hFifo) u32 u32Error = 0; tstrFifoHandler *pstrFifoHandler = (tstrFifoHandler *) hFifo; if (pstrFifoHandler) { - if (pstrFifoHandler->pu8Buffer) { + if (pstrFifoHandler->pu8Buffer) WILC_FREE (pstrFifoHandler->pu8Buffer); - } else { + else u32Error = 1; - } WILC_FREE (pstrFifoHandler); } else { @@ -52,11 +51,11 @@ u32 FIFO_ReadBytes(tHANDLE hFifo, u8 *pu8Buffer, u32 u32BytesToRead, u32 *pu32By if (pstrFifoHandler->u32TotalBytes) { down(&pstrFifoHandler->SemBuffer); - if (u32BytesToRead > pstrFifoHandler->u32TotalBytes) { + if (u32BytesToRead > pstrFifoHandler->u32TotalBytes) *pu32BytesRead = pstrFifoHandler->u32TotalBytes; - } else { + else *pu32BytesRead = u32BytesToRead; - } + if ((pstrFifoHandler->u32ReadOffset + u32BytesToRead) <= pstrFifoHandler->u32BufferLength) { WILC_memcpy(pu8Buffer, pstrFifoHandler->pu8Buffer + pstrFifoHandler->u32ReadOffset, *pu32BytesRead); -- cgit v1.3-6-gb490 From 6fdb302c1d996d2e0c1c527aa6f54a04ee80a0d8 Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Mon, 6 Jul 2015 19:48:04 +0200 Subject: wilc1000: host_interface.c: global variables do not need to be explicitly initialized to 0 or NULL. Fixed explicit initialization of global pointer variable. GCC takes care of this implicitly. Signed-off-by: Daniel Machon Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 483926f28436..c089e739465a 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -534,8 +534,8 @@ typedef enum { /*****************************************************************************/ -tstrWILC_WFIDrv *terminated_handle = NULL; -tstrWILC_WFIDrv *gWFiDrvHandle = NULL; +tstrWILC_WFIDrv *terminated_handle; +tstrWILC_WFIDrv *gWFiDrvHandle; #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP bool g_obtainingIP = false; #endif -- cgit v1.3-6-gb490 From fce9a74ba46fb545ad81cf244f3a1af4a877606c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 18:43:44 -0300 Subject: dmaengine: imx-dma: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. While at it, change the label 'err' to a more descriptive naming. Signed-off-by: Fabio Estevam Signed-off-by: Vinod Koul --- drivers/dma/imx-dma.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 865501fcc67d..139c5676cd74 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -1083,8 +1083,12 @@ static int __init imxdma_probe(struct platform_device *pdev) if (IS_ERR(imxdma->dma_ahb)) return PTR_ERR(imxdma->dma_ahb); - clk_prepare_enable(imxdma->dma_ipg); - clk_prepare_enable(imxdma->dma_ahb); + ret = clk_prepare_enable(imxdma->dma_ipg); + if (ret) + return ret; + ret = clk_prepare_enable(imxdma->dma_ahb); + if (ret) + goto disable_dma_ipg_clk; /* reset DMA module */ imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR); @@ -1094,20 +1098,20 @@ static int __init imxdma_probe(struct platform_device *pdev) dma_irq_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register IRQ for DMA\n"); - goto err; + goto disable_dma_ahb_clk; } irq_err = platform_get_irq(pdev, 1); if (irq_err < 0) { ret = irq_err; - goto err; + goto disable_dma_ahb_clk; } ret = devm_request_irq(&pdev->dev, irq_err, imxdma_err_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n"); - goto err; + goto disable_dma_ahb_clk; } } @@ -1144,7 +1148,7 @@ static int __init imxdma_probe(struct platform_device *pdev) dev_warn(imxdma->dev, "Can't register IRQ %d " "for DMA channel %d\n", irq + i, i); - goto err; + goto disable_dma_ahb_clk; } init_timer(&imxdmac->watchdog); imxdmac->watchdog.function = &imxdma_watchdog; @@ -1190,7 +1194,7 @@ static int __init imxdma_probe(struct platform_device *pdev) ret = dma_async_device_register(&imxdma->dma_device); if (ret) { dev_err(&pdev->dev, "unable to register\n"); - goto err; + goto disable_dma_ahb_clk; } if (pdev->dev.of_node) { @@ -1206,9 +1210,10 @@ static int __init imxdma_probe(struct platform_device *pdev) err_of_dma_controller: dma_async_device_unregister(&imxdma->dma_device); -err: - clk_disable_unprepare(imxdma->dma_ipg); +disable_dma_ahb_clk: clk_disable_unprepare(imxdma->dma_ahb); +disable_dma_ipg_clk: + clk_disable_unprepare(imxdma->dma_ipg); return ret; } -- cgit v1.3-6-gb490 From 4483320e241c5f6b63caa912343eb73c8b1dfd18 Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Fri, 26 Jun 2015 16:04:48 +0530 Subject: dmaengine: Use Pointer xt after NULL check. Removing static analysis error:- Possible null pointer dereference: xt Because currently xt is dereferenced before NULL check, Thus Use it after NULL Check. Signed-off-by: Maninder Singh Reviewed-by: Vaneet Narang Acked-by: Nicolas Ferre Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 59892126d175..d313acbb50e0 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -659,14 +659,14 @@ atc_prep_dma_interleaved(struct dma_chan *chan, size_t len = 0; int i; + if (unlikely(!xt || xt->numf != 1 || !xt->frame_size)) + return NULL; + dev_info(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n", __func__, xt->src_start, xt->dst_start, xt->numf, xt->frame_size, flags); - if (unlikely(!xt || xt->numf != 1 || !xt->frame_size)) - return NULL; - /* * The controller can only "skip" X bytes every Y bytes, so we * need to make sure we are given a template that fit that -- cgit v1.3-6-gb490 From 7618d0359c167d89d7e904a00487be4945c10a65 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 24 Jun 2015 10:49:59 -0700 Subject: dmaengine: ioatdma: Set non RAID channels to be private capable This allows claiming of non-RAID channels as a private channel. This prevents breakage of MDRAID using the IOATDMA channels via async_tx but also allows agents such as NTB to claim channels exclusively for its usages. Signed-off-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/dma_v3.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index 64790a45ef5d..8fbffd038113 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -1694,6 +1694,9 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca) } } + if (!(device->cap & (IOAT_CAP_XOR | IOAT_CAP_PQ))) + dma_cap_set(DMA_PRIVATE, dma->cap_mask); + err = ioat_probe(device); if (err) return err; -- cgit v1.3-6-gb490 From 3cb43cc0b408c4672ba94fe28406a90a94b1edfe Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Jul 2015 08:43:03 +0200 Subject: drm: Update plane->fb also for page_flip The legacy page_flip driver entry point is the only one left which requires drivers to update plane->fb themselves. All the other entry hooks will patch things up for the driver as needed since no one seems to reliable get this right, see e.g. drm_mode_set_config_internal or the plane->fb/old_fb handling in drm_mode_atomic_ioctl. Therefore unify things, which allows us to ditch a TODO from drm_atomic_helper_page_flip. This should also help the atomic transition in i915 since we keep a bit of legacy cruft only around because of this special behaviour in ->page_flip. Cc: Maarten Lankhorst Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 4 ---- drivers/gpu/drm/drm_crtc.c | 8 +------- 2 files changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 5b59d5ad7d1c..0898afbc9e23 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1915,10 +1915,6 @@ retry: if (ret != 0) goto fail; - /* TODO: ->page_flip is the only driver callback where the core - * doesn't update plane->fb. For now patch it up here. */ - plane->fb = plane->state->fb; - /* Driver takes ownership of state on successful async commit. */ return 0; fail: diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 0bf46d5ee221..2bbb232e80d7 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -5345,13 +5345,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, /* Keep the old fb, don't unref it. */ crtc->primary->old_fb = NULL; } else { - /* - * Warn if the driver hasn't properly updated the crtc->fb - * field to reflect that the new framebuffer is now used. - * Failing to do so will screw with the reference counting - * on framebuffers. - */ - WARN_ON(crtc->primary->fb != fb); + crtc->primary->fb = fb; /* Unref only the old framebuffer. */ fb = NULL; } -- cgit v1.3-6-gb490 From ec9f932ed41622d120de52a5b525e4d77b9ef17e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 24 Jun 2015 08:59:25 +0200 Subject: drm/atomic: Cleanup on error properly in the atomic ioctl. It's probably allowed to leave old_fb set to garbage when unlocking, but to prevent undefined behavior unset it just in case. Also crtc_state->event could be NULL on memory allocation failure, in which case event_space is increased for no reason. Note: Contains some general simplification of the cleanup code too. Signed-off-by: Maarten Lankhorst [danvet: Add note about the other changes in here. And fix long line while at it.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 64 +++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index bd7f723c708e..acebd1617264 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1463,18 +1463,18 @@ retry: if (get_user(obj_id, objs_ptr + copied_objs)) { ret = -EFAULT; - goto fail; + goto out; } obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY); if (!obj || !obj->properties) { ret = -ENOENT; - goto fail; + goto out; } if (get_user(count_props, count_props_ptr + copied_objs)) { ret = -EFAULT; - goto fail; + goto out; } copied_objs++; @@ -1486,25 +1486,25 @@ retry: if (get_user(prop_id, props_ptr + copied_props)) { ret = -EFAULT; - goto fail; + goto out; } prop = drm_property_find(dev, prop_id); if (!prop) { ret = -ENOENT; - goto fail; + goto out; } if (copy_from_user(&prop_value, prop_values_ptr + copied_props, sizeof(prop_value))) { ret = -EFAULT; - goto fail; + goto out; } ret = atomic_set_prop(state, obj, prop, prop_value); if (ret) - goto fail; + goto out; copied_props++; } @@ -1523,7 +1523,7 @@ retry: e = create_vblank_event(dev, file_priv, arg->user_data); if (!e) { ret = -ENOMEM; - goto fail; + goto out; } crtc_state->event = e; @@ -1533,13 +1533,15 @@ retry: if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { ret = drm_atomic_check_only(state); /* _check_only() does not free state, unlike _commit() */ - drm_atomic_state_free(state); + if (!ret) + drm_atomic_state_free(state); } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { ret = drm_atomic_async_commit(state); } else { ret = drm_atomic_commit(state); } +out: /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping * locks (ie. while it is still safe to deref plane->state). We * need to do this here because the driver entry points cannot @@ -1552,41 +1554,35 @@ retry: drm_framebuffer_reference(new_fb); plane->fb = new_fb; plane->crtc = plane->state->crtc; - } else { - plane->old_fb = NULL; - } - if (plane->old_fb) { - drm_framebuffer_unreference(plane->old_fb); - plane->old_fb = NULL; + + if (plane->old_fb) + drm_framebuffer_unreference(plane->old_fb); } + plane->old_fb = NULL; } - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - - return ret; + if (ret == -EDEADLK) { + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + goto retry; + } -fail: - if (ret == -EDEADLK) - goto backoff; + if (ret) { + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (!crtc_state->event) + continue; - if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { - for_each_crtc_in_state(state, crtc, crtc_state, i) { - destroy_vblank_event(dev, file_priv, crtc_state->event); - crtc_state->event = NULL; + destroy_vblank_event(dev, file_priv, + crtc_state->event); + } } - } - drm_atomic_state_free(state); + drm_atomic_state_free(state); + } drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_modeset_backoff(&ctx); - - goto retry; } -- cgit v1.3-6-gb490 From 3fec3d2f0a54d7c57c386c430bee2d6e5425ebfb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Jul 2015 09:10:07 +0200 Subject: drm/i915: Ditch SUPPORTS_INTEGRATED_HDMI|DP and use IS_G4X instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since that's really what we want to test for. Note remove the gen5 case doesn't change anything: In intel_setup_outputs ilk is handled already in the HAS_PCH_SPLIT case, and the register save/restore code touches registers which simply doesn't exist anymore at all. v2: Drop UMS parts. v3: Update commit message to reflect that the reg save/restore code is gone (Ville). Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/intel_display.c | 10 +++++----- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 093d6421dddf..952e242a6e71 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2519,8 +2519,6 @@ struct drm_i915_cmd_table { #define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \ IS_I915GM(dev))) #define SUPPORTS_DIGITAL_OUTPUTS(dev) (!IS_GEN2(dev) && !IS_PINEVIEW(dev)) -#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_GEN5(dev)) -#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_GEN5(dev)) #define SUPPORTS_TV(dev) (INTEL_INFO(dev)->supports_tv) #define I915_HAS_HOTPLUG(dev) (INTEL_INFO(dev)->has_hotplug) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index eb50f59d7840..99bf147b2f68 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14312,12 +14312,12 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { DRM_DEBUG_KMS("probing SDVOB\n"); found = intel_sdvo_init(dev, GEN3_SDVOB, true); - if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) { + if (!found && IS_G4X(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); intel_hdmi_init(dev, GEN4_HDMIB, PORT_B); } - if (!found && SUPPORTS_INTEGRATED_DP(dev)) + if (!found && IS_G4X(dev)) intel_dp_init(dev, DP_B, PORT_B); } @@ -14330,15 +14330,15 @@ static void intel_setup_outputs(struct drm_device *dev) if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) { - if (SUPPORTS_INTEGRATED_HDMI(dev)) { + if (IS_G4X(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOC\n"); intel_hdmi_init(dev, GEN4_HDMIC, PORT_C); } - if (SUPPORTS_INTEGRATED_DP(dev)) + if (IS_G4X(dev)) intel_dp_init(dev, DP_C, PORT_C); } - if (SUPPORTS_INTEGRATED_DP(dev) && + if (IS_G4X(dev) && (I915_READ(DP_D) & DP_DETECTED)) intel_dp_init(dev, DP_D, PORT_D); } else if (IS_GEN2(dev)) -- cgit v1.3-6-gb490 From 6adfb1ef106bfe4b5ecb8bd75c4d037741d28a48 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Jul 2015 09:10:40 +0200 Subject: drm/i915: s/mdelay/msleep/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Burning cpu cycles isn't awesome, so use sleeps instead. Signed-off-by: Daniel Vetter Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 99bf147b2f68..737e939cf0f4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1026,7 +1026,7 @@ static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe) line_mask = DSL_LINEMASK_GEN3; line1 = I915_READ(reg) & line_mask; - mdelay(5); + msleep(5); line2 = I915_READ(reg) & line_mask; return line1 == line2; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6eb5d76e6912..1efac89cb738 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4255,7 +4255,7 @@ static void ironlake_enable_drps(struct drm_device *dev) if (wait_for_atomic((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10)) DRM_ERROR("stuck trying to change perf mode\n"); - mdelay(1); + msleep(1); ironlake_set_drps(dev, fstart); @@ -4286,10 +4286,10 @@ static void ironlake_disable_drps(struct drm_device *dev) /* Go back to the starting frequency */ ironlake_set_drps(dev, dev_priv->ips.fstart); - mdelay(1); + msleep(1); rgvswctl |= MEMCTL_CMD_STS; I915_WRITE(MEMSWCTL, rgvswctl); - mdelay(1); + msleep(1); spin_unlock_irq(&mchdev_lock); } -- cgit v1.3-6-gb490 From 09da55dc84782b9b3fd8291719460da2d13bd27c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Jul 2015 11:44:32 +0200 Subject: drm/i915: Inline SUPPORTS_DIGITAL_OUTPUTS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the register save/restore code is gone there's just one user left and it just obfuscates that one. Remove it. Cc: Ville Syrjälä Suggested-by: Ville Syrjälä Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_display.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 952e242a6e71..464b28d5e678 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2518,7 +2518,6 @@ struct drm_i915_cmd_table { */ #define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \ IS_I915GM(dev))) -#define SUPPORTS_DIGITAL_OUTPUTS(dev) (!IS_GEN2(dev) && !IS_PINEVIEW(dev)) #define SUPPORTS_TV(dev) (INTEL_INFO(dev)->supports_tv) #define I915_HAS_HOTPLUG(dev) (INTEL_INFO(dev)->has_hotplug) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 737e939cf0f4..3c2425f5366d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14306,7 +14306,7 @@ static void intel_setup_outputs(struct drm_device *dev) } intel_dsi_init(dev); - } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { + } else if (!IS_GEN2(dev) && !IS_PINEVIEW(dev)) { bool found = false; if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { -- cgit v1.3-6-gb490 From 93e3a9e9993ef018522b7005d97d8124b7e73385 Mon Sep 17 00:00:00 2001 From: Sifan Naeem Date: Thu, 18 Jun 2015 13:27:12 +0100 Subject: spi: img-spfi: check for max speed supported by the spfi block Maximum speed supported by spfi is limited to 1/4 of the spfi clock. But in some SoCs the maximum speed supported by the spfi block can be limited to less than 1/4 of the spfi clock. In such cases we have to define the limit in the device tree so that the driver can pick it up. Signed-off-by: Sifan Naeem Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-img-spfi.txt | 1 + drivers/spi/spi-img-spfi.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/spi/spi-img-spfi.txt b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt index e02fbf18c82c..494db6012d02 100644 --- a/Documentation/devicetree/bindings/spi/spi-img-spfi.txt +++ b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt @@ -21,6 +21,7 @@ Required properties: Optional properties: - img,supports-quad-mode: Should be set if the interface supports quad mode SPI transfers. +- spfi-max-frequency: Maximum speed supported by the spfi block. Example: diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index 788e2b176a4f..f31d792a4662 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -546,6 +546,7 @@ static int img_spfi_probe(struct platform_device *pdev) struct img_spfi *spfi; struct resource *res; int ret; + u32 max_speed_hz; master = spi_alloc_master(&pdev->dev, sizeof(*spfi)); if (!master) @@ -610,6 +611,19 @@ static int img_spfi_probe(struct platform_device *pdev) master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4; master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512; + /* + * Maximum speed supported by spfi is limited to the lower value + * between 1/4 of the SPFI clock or to "spfi-max-frequency" + * defined in the device tree. + * If no value is defined in the device tree assume the maximum + * speed supported to be 1/4 of the SPFI clock. + */ + if (!of_property_read_u32(spfi->dev->of_node, "spfi-max-frequency", + &max_speed_hz)) { + if (master->max_speed_hz > max_speed_hz) + master->max_speed_hz = max_speed_hz; + } + master->setup = img_spfi_setup; master->cleanup = img_spfi_cleanup; master->transfer_one = img_spfi_transfer_one; -- cgit v1.3-6-gb490 From 65598c13fd66c3b5eac16d5b8eacc704aa17ce40 Mon Sep 17 00:00:00 2001 From: Andrew Gabbasov Date: Tue, 30 Jun 2015 10:48:37 -0500 Subject: spi: Fix per-page mapping of unaligned vmalloc-ed buffer spi_map_buf() processes mapping of vmalloc-ed buffers in a special way, making mapping of every page separately. However, if the buffer is not aligned to page boundary (e.g. sub-array in a vmalloc-ed array), it fills the scatter table with page-size unaligned pieces, that cross page boundaries. This is incorrect and can, for example, cause memory corruption and various crashes when working with ubifs on spi-nor chips (though those drivers are themselves buggy in that they should be providing DMAable memory to the SPI framework). Fix this by using proper scatter table size and intra-page buffer lengths, so that the whole buffer splits into separate scatter table entries on page boundaries. Signed-off-by: Andrew Gabbasov Signed-off-by: Mark Brown --- drivers/spi/spi.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index cf8b91b23a76..27e4f1f116ee 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -476,21 +476,30 @@ static int spi_map_buf(struct spi_master *master, struct device *dev, enum dma_data_direction dir) { const bool vmalloced_buf = is_vmalloc_addr(buf); - const int desc_len = vmalloced_buf ? PAGE_SIZE : master->max_dma_len; - const int sgs = DIV_ROUND_UP(len, desc_len); + int desc_len; + int sgs; struct page *vm_page; void *sg_buf; size_t min; int i, ret; + if (vmalloced_buf) { + desc_len = PAGE_SIZE; + sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len); + } else { + desc_len = master->max_dma_len; + sgs = DIV_ROUND_UP(len, desc_len); + } + ret = sg_alloc_table(sgt, sgs, GFP_KERNEL); if (ret != 0) return ret; for (i = 0; i < sgs; i++) { - min = min_t(size_t, len, desc_len); if (vmalloced_buf) { + min = min_t(size_t, + len, desc_len - offset_in_page(buf)); vm_page = vmalloc_to_page(buf); if (!vm_page) { sg_free_table(sgt); @@ -499,6 +508,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev, sg_set_page(&sgt->sgl[i], vm_page, min, offset_in_page(buf)); } else { + min = min_t(size_t, len, desc_len); sg_buf = buf; sg_set_buf(&sgt->sgl[i], sg_buf, min); } -- cgit v1.3-6-gb490 From 385a9c8fccc0308dbd8182c57b29a95e01e29688 Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Tue, 30 Jun 2015 21:03:58 +0300 Subject: spi/s3c24xx: remove unnecessary memset of s3c24xx_spi Memory for this struct is allocated by spi_alloc_master() using kzalloc() so it doesn't need to be set to 0 one more time. Signed-off-by: Alexey Klimov Reviewed-by: Daniel Kurtz Signed-off-by: Mark Brown --- drivers/spi/spi-s3c24xx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index f747ca269986..f36bc320a807 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -501,7 +501,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) } hw = spi_master_get_devdata(master); - memset(hw, 0, sizeof(struct s3c24xx_spi)); hw->master = master; hw->pdata = pdata = dev_get_platdata(&pdev->dev); -- cgit v1.3-6-gb490 From 99622f56110ee8cbfe8ecf2dd5e666f67cf4bb97 Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Tue, 30 Jun 2015 21:04:07 +0300 Subject: spi/rockchip: remove unnecessary memset of rockchip_spi Memory for struct rockchip_spi is allocated by spi_alloc_master() using kzalloc() so it doesn't need to be set to 0 one more time. Signed-off-by: Alexey Klimov Signed-off-by: Mark Brown --- drivers/spi/spi-rockchip.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 68e7efeb9a27..79a8bc4f6cec 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -645,7 +645,6 @@ static int rockchip_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); rs = spi_master_get_devdata(master); - memset(rs, 0, sizeof(struct rockchip_spi)); /* Get basic io resource and map it */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.3-6-gb490 From f6d1b3e20a840a7201ae400a970f42cca96aa17b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Jun 2015 15:02:44 +0200 Subject: spi: sh-msiof: Remove obsolete spi_r8a779x_msiof platform_device_id entries Since commit a483dcbfa21f919c ("ARM: shmobile: lager: Remove legacy board support"), R-Car Gen2 SoCs are only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the corresponding platform_device_id entry. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index d3370a612d84..118c652d88b5 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -1265,11 +1265,6 @@ static int sh_msiof_spi_remove(struct platform_device *pdev) static const struct platform_device_id spi_driver_ids[] = { { "spi_sh_msiof", (kernel_ulong_t)&sh_data }, - { "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data }, - { "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data }, - { "spi_r8a7792_msiof", (kernel_ulong_t)&r8a779x_data }, - { "spi_r8a7793_msiof", (kernel_ulong_t)&r8a779x_data }, - { "spi_r8a7794_msiof", (kernel_ulong_t)&r8a779x_data }, {}, }; MODULE_DEVICE_TABLE(platform, spi_driver_ids); -- cgit v1.3-6-gb490 From eca2ebc7e007c9e2b8f5ecfcfc74b53fbe68e42b Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Mon, 22 Jun 2015 13:00:36 +0000 Subject: spi: expose spi_master and spi_device statistics via sysfs per spi-master statistics accessible as: /sys/class/spi_master/spi*/statistics/* per spi-device statistics accessible via: /sys/class/spi_master/spi*/spi*.*/statistics/* The following statistics are exposed as separate "files" inside these directories: * messages number of spi_messages * transfers number of spi_transfers * bytes number of bytes transferred * bytes_rx number of bytes transmitted * bytes_tx number of bytes received * errors number of errors encounterd * timedout number of messages that have timed out * spi_async number of spi_messages submitted using spi_async * spi_sync number of spi_messages submitted using spi_sync * spi_sync_immediate number of spi_messages submitted using spi_sync, that are handled immediately without a context switch to the spi_pump worker-thread Signed-off-by: Martin Sperl Signed-off-by: Mark Brown --- drivers/spi/spi.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++- include/linux/spi/spi.h | 64 ++++++++++++++++++ 2 files changed, 229 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index cf8b91b23a76..07476ca083a0 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -67,11 +67,141 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf) } static DEVICE_ATTR_RO(modalias); +#define SPI_STATISTICS_ATTRS(field, file) \ +static ssize_t spi_master_##field##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct spi_master *master = container_of(dev, \ + struct spi_master, dev); \ + return spi_statistics_##field##_show(&master->statistics, buf); \ +} \ +static struct device_attribute dev_attr_spi_master_##field = { \ + .attr = { .name = file, .mode = S_IRUGO }, \ + .show = spi_master_##field##_show, \ +}; \ +static ssize_t spi_device_##field##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct spi_device *spi = container_of(dev, \ + struct spi_device, dev); \ + return spi_statistics_##field##_show(&spi->statistics, buf); \ +} \ +static struct device_attribute dev_attr_spi_device_##field = { \ + .attr = { .name = file, .mode = S_IRUGO }, \ + .show = spi_device_##field##_show, \ +} + +#define SPI_STATISTICS_SHOW_NAME(name, file, field, format_string) \ +static ssize_t spi_statistics_##name##_show(struct spi_statistics *stat, \ + char *buf) \ +{ \ + unsigned long flags; \ + ssize_t len; \ + spin_lock_irqsave(&stat->lock, flags); \ + len = sprintf(buf, format_string, stat->field); \ + spin_unlock_irqrestore(&stat->lock, flags); \ + return len; \ +} \ +SPI_STATISTICS_ATTRS(name, file) + +#define SPI_STATISTICS_SHOW(field, format_string) \ + SPI_STATISTICS_SHOW_NAME(field, __stringify(field), \ + field, format_string) + +SPI_STATISTICS_SHOW(messages, "%lu"); +SPI_STATISTICS_SHOW(transfers, "%lu"); +SPI_STATISTICS_SHOW(errors, "%lu"); +SPI_STATISTICS_SHOW(timedout, "%lu"); + +SPI_STATISTICS_SHOW(spi_sync, "%lu"); +SPI_STATISTICS_SHOW(spi_sync_immediate, "%lu"); +SPI_STATISTICS_SHOW(spi_async, "%lu"); + +SPI_STATISTICS_SHOW(bytes, "%llu"); +SPI_STATISTICS_SHOW(bytes_rx, "%llu"); +SPI_STATISTICS_SHOW(bytes_tx, "%llu"); + static struct attribute *spi_dev_attrs[] = { &dev_attr_modalias.attr, NULL, }; -ATTRIBUTE_GROUPS(spi_dev); + +static const struct attribute_group spi_dev_group = { + .attrs = spi_dev_attrs, +}; + +static struct attribute *spi_device_statistics_attrs[] = { + &dev_attr_spi_device_messages.attr, + &dev_attr_spi_device_transfers.attr, + &dev_attr_spi_device_errors.attr, + &dev_attr_spi_device_timedout.attr, + &dev_attr_spi_device_spi_sync.attr, + &dev_attr_spi_device_spi_sync_immediate.attr, + &dev_attr_spi_device_spi_async.attr, + &dev_attr_spi_device_bytes.attr, + &dev_attr_spi_device_bytes_rx.attr, + &dev_attr_spi_device_bytes_tx.attr, + NULL, +}; + +static const struct attribute_group spi_device_statistics_group = { + .name = "statistics", + .attrs = spi_device_statistics_attrs, +}; + +static const struct attribute_group *spi_dev_groups[] = { + &spi_dev_group, + &spi_device_statistics_group, + NULL, +}; + +static struct attribute *spi_master_statistics_attrs[] = { + &dev_attr_spi_master_messages.attr, + &dev_attr_spi_master_transfers.attr, + &dev_attr_spi_master_errors.attr, + &dev_attr_spi_master_timedout.attr, + &dev_attr_spi_master_spi_sync.attr, + &dev_attr_spi_master_spi_sync_immediate.attr, + &dev_attr_spi_master_spi_async.attr, + &dev_attr_spi_master_bytes.attr, + &dev_attr_spi_master_bytes_rx.attr, + &dev_attr_spi_master_bytes_tx.attr, + NULL, +}; + +static const struct attribute_group spi_master_statistics_group = { + .name = "statistics", + .attrs = spi_master_statistics_attrs, +}; + +static const struct attribute_group *spi_master_groups[] = { + &spi_master_statistics_group, + NULL, +}; + +void spi_statistics_add_transfer_stats(struct spi_statistics *stats, + struct spi_transfer *xfer, + struct spi_master *master) +{ + unsigned long flags; + + spin_lock_irqsave(&stats->lock, flags); + + stats->transfers++; + + stats->bytes += xfer->len; + if ((xfer->tx_buf) && + (xfer->tx_buf != master->dummy_tx)) + stats->bytes_tx += xfer->len; + if ((xfer->rx_buf) && + (xfer->rx_buf != master->dummy_rx)) + stats->bytes_rx += xfer->len; + + spin_unlock_irqrestore(&stats->lock, flags); +} +EXPORT_SYMBOL_GPL(spi_statistics_add_transfer_stats); /* modalias support makes "modprobe $MODALIAS" new-style hotplug work, * and the sysfs version makes coldplug work too. @@ -249,6 +379,9 @@ struct spi_device *spi_alloc_device(struct spi_master *master) spi->dev.bus = &spi_bus_type; spi->dev.release = spidev_release; spi->cs_gpio = -ENOENT; + + spin_lock_init(&spi->statistics.lock); + device_initialize(&spi->dev); return spi; } @@ -689,17 +822,29 @@ static int spi_transfer_one_message(struct spi_master *master, bool keep_cs = false; int ret = 0; unsigned long ms = 1; + struct spi_statistics *statm = &master->statistics; + struct spi_statistics *stats = &msg->spi->statistics; spi_set_cs(msg->spi, true); + SPI_STATISTICS_INCREMENT_FIELD(statm, messages); + SPI_STATISTICS_INCREMENT_FIELD(stats, messages); + list_for_each_entry(xfer, &msg->transfers, transfer_list) { trace_spi_transfer_start(msg, xfer); + spi_statistics_add_transfer_stats(statm, xfer, master); + spi_statistics_add_transfer_stats(stats, xfer, master); + if (xfer->tx_buf || xfer->rx_buf) { reinit_completion(&master->xfer_completion); ret = master->transfer_one(master, msg->spi, xfer); if (ret < 0) { + SPI_STATISTICS_INCREMENT_FIELD(statm, + errors); + SPI_STATISTICS_INCREMENT_FIELD(stats, + errors); dev_err(&msg->spi->dev, "SPI transfer failed: %d\n", ret); goto out; @@ -715,6 +860,10 @@ static int spi_transfer_one_message(struct spi_master *master, } if (ms == 0) { + SPI_STATISTICS_INCREMENT_FIELD(statm, + timedout); + SPI_STATISTICS_INCREMENT_FIELD(stats, + timedout); dev_err(&msg->spi->dev, "SPI transfer timed out\n"); msg->status = -ETIMEDOUT; @@ -1416,10 +1565,10 @@ static struct class spi_master_class = { .name = "spi_master", .owner = THIS_MODULE, .dev_release = spi_master_release, + .dev_groups = spi_master_groups, }; - /** * spi_alloc_master - allocate SPI master controller * @dev: the controller, possibly using the platform_bus @@ -1585,6 +1734,8 @@ int spi_register_master(struct spi_master *master) goto done; } } + /* add statistics */ + spin_lock_init(&master->statistics.lock); mutex_lock(&board_lock); list_add_tail(&master->list, &spi_master_list); @@ -1939,6 +2090,9 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) message->spi = spi; + SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_async); + SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_async); + trace_spi_message_submit(message); return master->transfer(spi, message); @@ -2075,6 +2229,9 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, message->context = &done; message->spi = spi; + SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, spi_sync); + SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync); + if (!bus_locked) mutex_lock(&master->bus_lock_mutex); @@ -2102,8 +2259,13 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message, /* Push out the messages in the calling context if we * can. */ - if (master->transfer == spi_queued_transfer) + if (master->transfer == spi_queued_transfer) { + SPI_STATISTICS_INCREMENT_FIELD(&master->statistics, + spi_sync_immediate); + SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, + spi_sync_immediate); __spi_pump_messages(master, false); + } wait_for_completion(&done); status = message->status; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index d673072346f2..269e8afd3e2a 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -23,6 +23,8 @@ #include struct dma_chan; +struct spi_master; +struct spi_transfer; /* * INTERFACES between SPI master-side drivers and SPI infrastructure. @@ -30,6 +32,59 @@ struct dma_chan; */ extern struct bus_type spi_bus_type; +/** + * struct spi_statistics - statistics for spi transfers + * @clock: lock protecting this structure + * + * @messages: number of spi-messages handled + * @transfers: number of spi_transfers handled + * @errors: number of errors during spi_transfer + * @timedout: number of timeouts during spi_transfer + * + * @spi_sync: number of times spi_sync is used + * @spi_sync_immediate: + * number of times spi_sync is executed immediately + * in calling context without queuing and scheduling + * @spi_async: number of times spi_async is used + * + * @bytes: number of bytes transferred to/from device + * @bytes_tx: number of bytes sent to device + * @bytes_rx: number of bytes received from device + * + */ +struct spi_statistics { + spinlock_t lock; /* lock for the whole structure */ + + unsigned long messages; + unsigned long transfers; + unsigned long errors; + unsigned long timedout; + + unsigned long spi_sync; + unsigned long spi_sync_immediate; + unsigned long spi_async; + + unsigned long long bytes; + unsigned long long bytes_rx; + unsigned long long bytes_tx; + +}; + +void spi_statistics_add_transfer_stats(struct spi_statistics *stats, + struct spi_transfer *xfer, + struct spi_master *master); + +#define SPI_STATISTICS_ADD_TO_FIELD(stats, field, count) \ + do { \ + unsigned long flags; \ + spin_lock_irqsave(&(stats)->lock, flags); \ + (stats)->field += count; \ + spin_unlock_irqrestore(&(stats)->lock, flags); \ + } while (0) + +#define SPI_STATISTICS_INCREMENT_FIELD(stats, field) \ + SPI_STATISTICS_ADD_TO_FIELD(stats, field, 1) + /** * struct spi_device - Master side proxy for an SPI slave device * @dev: Driver model representation of the device. @@ -60,6 +115,8 @@ extern struct bus_type spi_bus_type; * @cs_gpio: gpio number of the chipselect line (optional, -ENOENT when * when not using a GPIO line) * + * @statistics: statistics for the spi_device + * * A @spi_device is used to interchange data between an SPI slave * (usually a discrete chip) and CPU memory. * @@ -98,6 +155,9 @@ struct spi_device { char modalias[SPI_NAME_SIZE]; int cs_gpio; /* chip select gpio */ + /* the statistics */ + struct spi_statistics statistics; + /* * likely need more hooks for more protocol options affecting how * the controller talks to each chip, like: @@ -296,6 +356,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS * number. Any individual value may be -ENOENT for CS lines that * are not GPIOs (driven by the SPI controller itself). + * @statistics: statistics for the spi_master * @dma_tx: DMA transmit channel * @dma_rx: DMA receive channel * @dummy_rx: dummy receive buffer for full-duplex devices @@ -452,6 +513,9 @@ struct spi_master { /* gpio chip select */ int *cs_gpios; + /* statistics */ + struct spi_statistics statistics; + /* DMA channels for use with core dmaengine helpers */ struct dma_chan *dma_tx; struct dma_chan *dma_rx; -- cgit v1.3-6-gb490 From ec8677267f4ef126275b2e0a429211b256f1a94a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 7 Jul 2015 19:21:44 +0800 Subject: regulator: ltc3589: Constify ltc3589_reg_defaults ltc3589_reg_defaults[] is not modified after initialized, so make it const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/ltc3589.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 0ce8e4e0fa73..c31dfa8805d9 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -378,7 +378,7 @@ static bool ltc3589_volatile_reg(struct device *dev, unsigned int reg) return false; } -static struct reg_default ltc3589_reg_defaults[] = { +static const struct reg_default ltc3589_reg_defaults[] = { { LTC3589_SCR1, 0x00 }, { LTC3589_OVEN, 0x00 }, { LTC3589_SCR2, 0x00 }, -- cgit v1.3-6-gb490 From f9178dad67952673b653315f92620b7a981466e5 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 6 Jul 2015 09:58:29 +0100 Subject: regulator: pwm-regulator: Separate voltage-table initialisation Take this out of the main .probe() routine in order to facilitate the introduction of different ways to obtain 'duty cycle' information. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 77 +++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index ffa96124a5e7..25560fc519b7 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -78,8 +78,7 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev, return drvdata->duty_cycle_table[selector].uV; } - -static struct regulator_ops pwm_regulator_voltage_ops = { +static struct regulator_ops pwm_regulator_voltage_table_ops = { .set_voltage_sel = pwm_regulator_set_voltage_sel, .get_voltage_sel = pwm_regulator_get_voltage_sel, .list_voltage = pwm_regulator_list_voltage, @@ -88,20 +87,55 @@ static struct regulator_ops pwm_regulator_voltage_ops = { static struct regulator_desc pwm_regulator_desc = { .name = "pwm-regulator", - .ops = &pwm_regulator_voltage_ops, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, .supply_name = "pwm", }; +static int pwm_regulator_init_table(struct platform_device *pdev, + struct pwm_regulator_data *drvdata) +{ + struct device_node *np = pdev->dev.of_node; + struct pwm_voltages *duty_cycle_table; + int length; + int ret; + + of_find_property(np, "voltage-table", &length); + + if ((length < sizeof(*duty_cycle_table)) || + (length % sizeof(*duty_cycle_table))) { + dev_err(&pdev->dev, + "voltage-table length(%d) is invalid\n", + length); + return -EINVAL; + } + + duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); + if (!duty_cycle_table) + return -ENOMEM; + + ret = of_property_read_u32_array(np, "voltage-table", + (u32 *)duty_cycle_table, + length / sizeof(u32)); + if (ret) { + dev_err(&pdev->dev, "Failed to read voltage-table\n"); + return ret; + } + + drvdata->duty_cycle_table = duty_cycle_table; + pwm_regulator_desc.ops = &pwm_regulator_voltage_table_ops; + pwm_regulator_desc.n_voltages = length / sizeof(*duty_cycle_table); + + return 0; +} + static int pwm_regulator_probe(struct platform_device *pdev) { struct pwm_regulator_data *drvdata; - struct property *prop; struct regulator_dev *regulator; struct regulator_config config = { }; struct device_node *np = pdev->dev.of_node; - int length, ret; + int ret; if (!np) { dev_err(&pdev->dev, "Device Tree node missing\n"); @@ -112,36 +146,15 @@ static int pwm_regulator_probe(struct platform_device *pdev) if (!drvdata) return -ENOMEM; - /* determine the number of voltage-table */ - prop = of_find_property(np, "voltage-table", &length); - if (!prop) { - dev_err(&pdev->dev, "No voltage-table\n"); - return -EINVAL; - } - - if ((length < sizeof(*drvdata->duty_cycle_table)) || - (length % sizeof(*drvdata->duty_cycle_table))) { - dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n", - length); + if (of_find_property(np, "voltage-table", NULL)) { + ret = pwm_regulator_init_table(pdev, drvdata); + if (ret) + return ret; + } else { + dev_err(&pdev->dev, "No \"voltage-table\" supplied\n"); return -EINVAL; } - pwm_regulator_desc.n_voltages = length / sizeof(*drvdata->duty_cycle_table); - - drvdata->duty_cycle_table = devm_kzalloc(&pdev->dev, - length, GFP_KERNEL); - if (!drvdata->duty_cycle_table) - return -ENOMEM; - - /* read voltage table from DT property */ - ret = of_property_read_u32_array(np, "voltage-table", - (u32 *)drvdata->duty_cycle_table, - length / sizeof(u32)); - if (ret < 0) { - dev_err(&pdev->dev, "read voltage-table failed\n"); - return ret; - } - config.init_data = of_get_regulator_init_data(&pdev->dev, np, &pwm_regulator_desc); if (!config.init_data) -- cgit v1.3-6-gb490 From 3692db3a904800445f8af249e1ac0f2b6496f31d Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 1 Jul 2015 18:31:43 +0530 Subject: regulator: max8973: add support to configure ETR from DT The MAX8973/MAX77621 feature an Enhanced Transient Response(ETR) circuit that is enabled through software. The enhanced transient response reduces the voltage droop during large load steps by temporarily allowing all three phases to fire in unison, slewing total inductor current faster than would normally be possible if all three phases continued to operate 120deg out of phase. The enhanced transient response detector features two selectable sensitivity settings, which select the output voltage slew rate during load transients that triggers the ETR circuit. The sensitivity of the ETR detector is set by the CKADV[1:0] bits in the CONTROL2 register. Add support to configure the ETR through platform data from DT. Update the DT binding document accordingly. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown --- .../bindings/regulator/max8973-regulator.txt | 6 ++++++ drivers/regulator/max8973-regulator.c | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/regulator/max8973-regulator.txt b/Documentation/devicetree/bindings/regulator/max8973-regulator.txt index 55efb24e5683..f80ea2fe27e6 100644 --- a/Documentation/devicetree/bindings/regulator/max8973-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/max8973-regulator.txt @@ -25,6 +25,12 @@ Optional properties: -maxim,enable-frequency-shift: boolean, enable 9% frequency shift. -maxim,enable-bias-control: boolean, enable bias control. By enabling this startup delay can be reduce to 20us from 220us. +-maxim,enable-etr: boolean, enable Enhanced Transient Response. +-maxim,enable-high-etr-sensitivity: boolean, Enhanced transient response + circuit is enabled and set for high sensitivity. If this + property is available then etr will be enable default. + +Enhanced transient response (ETR) will affect the configuration of CKADV. Example: diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index e94ddcf97722..a8fd7f4dd8d8 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -421,6 +421,8 @@ static struct max8973_regulator_platform_data *max8973_parse_dt( struct device_node *np = dev->of_node; int ret; u32 pval; + bool etr_enable; + bool etr_sensitivity_high; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -452,6 +454,23 @@ static struct max8973_regulator_platform_data *max8973_parse_dt( if (of_property_read_bool(np, "maxim,enable-bias-control")) pdata->control_flags |= MAX8973_CONTROL_BIAS_ENABLE; + etr_enable = of_property_read_bool(np, "maxim,enable-etr"); + etr_sensitivity_high = of_property_read_bool(np, + "maxim,enable-high-etr-sensitivity"); + if (etr_sensitivity_high) + etr_enable = true; + + if (etr_enable) { + if (etr_sensitivity_high) + pdata->control_flags |= + MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US; + else + pdata->control_flags |= + MAX8973_CONTROL_CLKADV_TRIP_150mV_PER_US; + } else { + pdata->control_flags |= MAX8973_CONTROL_CLKADV_TRIP_DISABLED; + } + return pdata; } -- cgit v1.3-6-gb490 From ffaab99184a2c8b592bba85d8e4da708c65b4cc1 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 1 Jul 2015 18:31:44 +0530 Subject: regulator: max8973: add support to configure ETR based on rail load Add support to configure Enhanced Transient Response Enable (ETR) and Sensitivity Selection based on maximum current i.e. expected load on that rail. Maxim recommended as: - Enable ETR with high sensitivity (75mV/us) for 0 to 9A expected loads, - Enable ETR with low sensitivity (150mV/us) for 9A to 12A expected loads. - Disable ETR for expected load > 12A. These recommendation will be configured for MAX77621 when maximum load is provided through regulator constraint for maximum current from platform. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown --- drivers/regulator/max8973-regulator.c | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index a8fd7f4dd8d8..f67365962b67 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -75,6 +75,7 @@ #define MAX8973_DISCH_ENBABLE BIT(5) #define MAX8973_FT_ENABLE BIT(4) +#define MAX8973_CKKADV_TRIP_MASK 0xC #define MAX8973_CKKADV_TRIP_DISABLE 0xC #define MAX8973_CKKADV_TRIP_75mV_PER_US 0x0 #define MAX8973_CKKADV_TRIP_150mV_PER_US 0x4 @@ -282,6 +283,55 @@ static int max8973_set_ramp_delay(struct regulator_dev *rdev, return ret; } +static int max8973_set_current_limit(struct regulator_dev *rdev, + int min_ua, int max_ua) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + unsigned int val; + int ret; + + if (max_ua <= 9000000) + val = MAX8973_CKKADV_TRIP_75mV_PER_US; + else if (max_ua <= 12000000) + val = MAX8973_CKKADV_TRIP_150mV_PER_US; + else + val = MAX8973_CKKADV_TRIP_DISABLE; + + ret = regmap_update_bits(max->regmap, MAX8973_CONTROL2, + MAX8973_CKKADV_TRIP_MASK, val); + if (ret < 0) { + dev_err(max->dev, "register %d update failed: %d\n", + MAX8973_CONTROL2, ret); + return ret; + } + return 0; +} + +static int max8973_get_current_limit(struct regulator_dev *rdev) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + unsigned int control2; + int ret; + + ret = regmap_read(max->regmap, MAX8973_CONTROL2, &control2); + if (ret < 0) { + dev_err(max->dev, "register %d read failed: %d\n", + MAX8973_CONTROL2, ret); + return ret; + } + switch (control2 & MAX8973_CKKADV_TRIP_MASK) { + case MAX8973_CKKADV_TRIP_DISABLE: + return 15000000; + case MAX8973_CKKADV_TRIP_150mV_PER_US: + return 12000000; + case MAX8973_CKKADV_TRIP_75mV_PER_US: + return 9000000; + default: + break; + } + return 9000000; +} + static const struct regulator_ops max8973_dcdc_ops = { .get_voltage_sel = max8973_dcdc_get_voltage_sel, .set_voltage_sel = max8973_dcdc_set_voltage_sel, @@ -632,6 +682,8 @@ static int max8973_probe(struct i2c_client *client, max->ops.enable = regulator_enable_regmap; max->ops.disable = regulator_disable_regmap; max->ops.is_enabled = regulator_is_enabled_regmap; + max->ops.set_current_limit = max8973_set_current_limit; + max->ops.get_current_limit = max8973_get_current_limit; break; default: break; -- cgit v1.3-6-gb490 From 2b93f7ee0836d1dbcfcf8560dd2a34cd51b3ff21 Mon Sep 17 00:00:00 2001 From: Nishanth Aravamudan Date: Mon, 6 Jul 2015 10:06:21 -0700 Subject: crypto: nx - reduce chattiness of platform drivers While we never would successfully load on the wrong machine type, there is extra output by default regardless of machine type. For instance, on a PowerVM LPAR, we see the following: nx_compress_powernv: loading nx_compress_powernv: no coprocessors found even though those coprocessors could never be found. Signed-off-by: Nishanth Aravamudan Cc: Dan Streetman Cc: Herbert Xu Cc: "David S. Miller" Cc: linux-crypto@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org Acked-by: Michael Ellerman Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-powernv.c | 10 +--------- drivers/crypto/nx/nx-842-pseries.c | 3 --- 2 files changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c index 33b3b0abf4ae..7e474562058d 100644 --- a/drivers/crypto/nx/nx-842-powernv.c +++ b/drivers/crypto/nx/nx-842-powernv.c @@ -594,15 +594,11 @@ static __init int nx842_powernv_init(void) BUILD_BUG_ON(DDE_BUFFER_ALIGN % DDE_BUFFER_SIZE_MULT); BUILD_BUG_ON(DDE_BUFFER_SIZE_MULT % DDE_BUFFER_LAST_MULT); - pr_info("loading\n"); - for_each_compatible_node(dn, NULL, "ibm,power-nx") nx842_powernv_probe(dn); - if (!nx842_ct) { - pr_err("no coprocessors found\n"); + if (!nx842_ct) return -ENODEV; - } if (!nx842_platform_driver_set(&nx842_powernv_driver)) { struct nx842_coproc *coproc, *n; @@ -615,8 +611,6 @@ static __init int nx842_powernv_init(void) return -EEXIST; } - pr_info("loaded\n"); - return 0; } module_init(nx842_powernv_init); @@ -631,7 +625,5 @@ static void __exit nx842_powernv_exit(void) list_del(&coproc->list); kfree(coproc); } - - pr_info("unloaded\n"); } module_exit(nx842_powernv_exit); diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index b84b0ceeb46e..d44524da6589 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c @@ -1091,8 +1091,6 @@ static int __init nx842_pseries_init(void) struct nx842_devdata *new_devdata; int ret; - pr_info("Registering IBM Power 842 compression driver\n"); - if (!of_find_compatible_node(NULL, NULL, "ibm,compression")) return -ENODEV; @@ -1129,7 +1127,6 @@ static void __exit nx842_pseries_exit(void) struct nx842_devdata *old_devdata; unsigned long flags; - pr_info("Exiting IBM Power 842 compression driver\n"); nx842_platform_driver_unset(&nx842_pseries_driver); spin_lock_irqsave(&devdata_mutex, flags); old_devdata = rcu_dereference_check(devdata, -- cgit v1.3-6-gb490 From 4773be185a0f7c1c09d8966e100c76f4fa9a3227 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 7 Jul 2015 16:06:51 +0100 Subject: regulator: pwm-regulator: Add support for continuous-voltage The current version of PWM regulator only supports a static table approach, where pre-calculated values are supplied by the vendor and obtained via DT. The continuous-voltage method takes min_uV and max_uV, and divides the difference between them up into a number of slices. The number of slices depend on how large the duty cycle register is. This information is provided by a DT property. As the name alludes, this provides values for a continuous voltage range between min_uV and max_uV, which has obvious benefits over either limited voltage possibilities, or the requirement to provide a large voltage-table. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 114 +++++++++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 25560fc519b7..dac145db305c 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -21,9 +22,16 @@ #include struct pwm_regulator_data { - struct pwm_voltages *duty_cycle_table; + /* Shared */ struct pwm_device *pwm; + + /* Voltage table */ + struct pwm_voltages *duty_cycle_table; int state; + + /* Continuous voltage */ + u32 max_duty_cycle; + int volt_uV; }; struct pwm_voltages { @@ -31,6 +39,9 @@ struct pwm_voltages { unsigned int dutycycle; }; +/** + * Voltage table call-backs + */ static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); @@ -78,6 +89,71 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev, return drvdata->duty_cycle_table[selector].uV; } + +/** + * Continuous voltage call-backs + */ +static int pwm_voltage_to_duty_cycle(struct regulator_dev *rdev, + int volt_mV) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + int min_mV = rdev->constraints->min_uV / 1000; + int max_mV = rdev->constraints->max_uV / 1000; + int max_duty_cycle = drvdata->max_duty_cycle; + int vdiff = min_mV - max_mV; + int pwm_code; + int tmp; + + tmp = ((max_duty_cycle - min_mV) * max_duty_cycle) / vdiff; + pwm_code = ((tmp + max_duty_cycle) * volt_mV) / vdiff; + + if (pwm_code < 0) + pwm_code = 0; + if (pwm_code > max_duty_cycle) + pwm_code = max_duty_cycle; + + return pwm_code * 100 / max_duty_cycle; +} + +static int pwm_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + + return drvdata->volt_uV; +} + +static int pwm_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, + unsigned *selector) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + unsigned int ramp_delay = rdev->constraints->ramp_delay; + int duty_cycle; + int ret; + + duty_cycle = pwm_voltage_to_duty_cycle(rdev, min_uV / 1000); + + ret = pwm_config(drvdata->pwm, + (drvdata->pwm->period / 100) * duty_cycle, + drvdata->pwm->period); + if (ret) { + dev_err(&rdev->dev, "Failed to configure PWM\n"); + return ret; + } + + ret = pwm_enable(drvdata->pwm); + if (ret) { + dev_err(&rdev->dev, "Failed to enable PWM\n"); + return ret; + } + drvdata->volt_uV = min_uV; + + /* Delay required by PWM regulator to settle to the new voltage */ + usleep_range(ramp_delay, ramp_delay + 1000); + + return 0; +} + static struct regulator_ops pwm_regulator_voltage_table_ops = { .set_voltage_sel = pwm_regulator_set_voltage_sel, .get_voltage_sel = pwm_regulator_get_voltage_sel, @@ -85,6 +161,11 @@ static struct regulator_ops pwm_regulator_voltage_table_ops = { .map_voltage = regulator_map_voltage_iterate, }; +static struct regulator_ops pwm_regulator_voltage_continuous_ops = { + .get_voltage = pwm_regulator_get_voltage, + .set_voltage = pwm_regulator_set_voltage, +}; + static struct regulator_desc pwm_regulator_desc = { .name = "pwm-regulator", .type = REGULATOR_VOLTAGE, @@ -129,6 +210,25 @@ static int pwm_regulator_init_table(struct platform_device *pdev, return 0; } +static int pwm_regulator_init_continuous(struct platform_device *pdev, + struct pwm_regulator_data *drvdata) +{ + struct device_node *np = pdev->dev.of_node; + int ret; + + ret = of_property_read_u32(np, "max-duty-cycle", + &drvdata->max_duty_cycle); + if (ret) { + dev_err(&pdev->dev, "Failed to read \"pwm-max-value\"\n"); + return ret; + } + + pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops; + pwm_regulator_desc.continuous_voltage_range = true; + + return 0; +} + static int pwm_regulator_probe(struct platform_device *pdev) { struct pwm_regulator_data *drvdata; @@ -146,14 +246,12 @@ static int pwm_regulator_probe(struct platform_device *pdev) if (!drvdata) return -ENOMEM; - if (of_find_property(np, "voltage-table", NULL)) { + if (of_find_property(np, "voltage-table", NULL)) ret = pwm_regulator_init_table(pdev, drvdata); - if (ret) - return ret; - } else { - dev_err(&pdev->dev, "No \"voltage-table\" supplied\n"); - return -EINVAL; - } + else + ret = pwm_regulator_init_continuous(pdev, drvdata); + if (ret) + return ret; config.init_data = of_get_regulator_init_data(&pdev->dev, np, &pwm_regulator_desc); -- cgit v1.3-6-gb490 From cae897dec26a9d81dcb5182b13b08450f38d6bde Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 7 Jul 2015 16:06:52 +0100 Subject: regulator: pwm-regulator: Simplify voltage to duty-cycle call If we reverse some of the logic and change the formula used, we can simplify the function greatly. It is intentional that this function is supplied and then re-worked within the same patch-set. The submission in the previous patch is the tried and tested (i.e. in real releases) method written by ST. This patch contains a simplification provided later. It looks and performs better, but doesn't have the same time-under-test that the original method does. The idea is that we keep some history in order to provide an easy way back i.e. revert. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index dac145db305c..d5cb267fa192 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -93,26 +93,13 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev, /** * Continuous voltage call-backs */ -static int pwm_voltage_to_duty_cycle(struct regulator_dev *rdev, - int volt_mV) +static int pwm_voltage_to_duty_cycle(struct regulator_dev *rdev, int req_uV) { - struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); - int min_mV = rdev->constraints->min_uV / 1000; - int max_mV = rdev->constraints->max_uV / 1000; - int max_duty_cycle = drvdata->max_duty_cycle; - int vdiff = min_mV - max_mV; - int pwm_code; - int tmp; - - tmp = ((max_duty_cycle - min_mV) * max_duty_cycle) / vdiff; - pwm_code = ((tmp + max_duty_cycle) * volt_mV) / vdiff; - - if (pwm_code < 0) - pwm_code = 0; - if (pwm_code > max_duty_cycle) - pwm_code = max_duty_cycle; - - return pwm_code * 100 / max_duty_cycle; + int min_uV = rdev->constraints->min_uV; + int max_uV = rdev->constraints->max_uV; + int diff = max_uV - min_uV; + + return 100 - ((((req_uV * 100) - (min_uV * 100)) / diff)); } static int pwm_regulator_get_voltage(struct regulator_dev *rdev) @@ -131,7 +118,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, int duty_cycle; int ret; - duty_cycle = pwm_voltage_to_duty_cycle(rdev, min_uV / 1000); + duty_cycle = pwm_voltage_to_duty_cycle(rdev, min_uV); ret = pwm_config(drvdata->pwm, (drvdata->pwm->period / 100) * duty_cycle, -- cgit v1.3-6-gb490 From 5ad2cb14f5b8f3cb3d8688115037751b1ff45455 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 7 Jul 2015 16:06:53 +0100 Subject: regulator: pwm-regulator: Don't assign structure attributes right away Perhaps this is just personal preference, but ... This patch introduces a new local variable to receive and test regulator initialisation data. It simplifies and cleans up the code making it that little bit easier to read and maintain. The local value is assigned to the structure attribute when all the others are. This is the way we usually do things. Prevents this kind of nonsense: this->is->just.silly = fetch_silly_value(&pointer); if (!this->is->just.silly) { printk("Silly value failed: %d\n", this->is->just.silly); return this->is->just.silly; } Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index d5cb267fa192..cb482089050b 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -218,6 +218,7 @@ static int pwm_regulator_init_continuous(struct platform_device *pdev, static int pwm_regulator_probe(struct platform_device *pdev) { + const struct regulator_init_data *init_data; struct pwm_regulator_data *drvdata; struct regulator_dev *regulator; struct regulator_config config = { }; @@ -240,14 +241,15 @@ static int pwm_regulator_probe(struct platform_device *pdev) if (ret) return ret; - config.init_data = of_get_regulator_init_data(&pdev->dev, np, - &pwm_regulator_desc); - if (!config.init_data) + init_data = of_get_regulator_init_data(&pdev->dev, np, + &pwm_regulator_desc); + if (!init_data) return -ENOMEM; config.of_node = np; config.dev = &pdev->dev; config.driver_data = drvdata; + config.init_data = init_data; drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); if (IS_ERR(drvdata->pwm)) { -- cgit v1.3-6-gb490 From b7e79329c4e34d63cd374e603ece91f2b2c3331e Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 6 Jul 2015 15:52:21 -0700 Subject: Input: bma150 - use sign_extend32() for sign extending Despite it's name, sign_extend32() is used for 16 bit values aswell. Signed-off-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/misc/bma150.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index b36831c828d3..c2780493b0ed 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -333,10 +333,9 @@ static void bma150_report_xyz(struct bma150_data *bma150) y = ((0xc0 & data[2]) >> 6) | (data[3] << 2); z = ((0xc0 & data[4]) >> 6) | (data[5] << 2); - /* sign extension */ - x = (s16) (x << 6) >> 6; - y = (s16) (y << 6) >> 6; - z = (s16) (z << 6) >> 6; + x = sign_extend32(x, 9); + y = sign_extend32(y, 9); + z = sign_extend32(z, 9); input_report_abs(bma150->input, ABS_X, x); input_report_abs(bma150->input, ABS_Y, y); -- cgit v1.3-6-gb490 From a8a8db47990d9b3789a30f4ab6744ce83f733c85 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 6 Jul 2015 12:10:51 -0700 Subject: clk: at91: Silence warnings and cleanup __init/extern usage Remove useless ifdefs around function prototypes to silence the following sparse warnings when the configs aren't enabled. drivers/clk/at91/clk-h32mx.c:95:13: warning: symbol 'of_sama5d4_clk_h32mx_setup' was not declared. Should it be static? drivers/clk/at91/clk-utmi.c:159:13: warning: symbol 'of_at91sam9x5_clk_utmi_setup' was not declared. Should it be static? Plus, using __init and extern in function prototypes doesn't do anything, so just drop it throughout this file. Acked-by: Boris BREZILLON Acked-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/pmc.h | 124 +++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index eb8e5dc9076d..8b87771c69b2 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -59,71 +59,63 @@ static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value) int of_at91_get_clk_range(struct device_node *np, const char *propname, struct clk_range *range); -extern void __init of_at91sam9260_clk_slow_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91rm9200_clk_main_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_main_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9g45_clk_pll_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_sama5d3_clk_pll_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_master_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_master_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_sys_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_periph_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_periph_setup(struct device_node *np, - struct at91_pmc *pmc); - -extern void __init of_at91rm9200_clk_prog_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9g45_clk_prog_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np, - struct at91_pmc *pmc); - -#if defined(CONFIG_HAVE_AT91_UTMI) -extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np, - struct at91_pmc *pmc); -#endif - -#if defined(CONFIG_HAVE_AT91_USB_CLK) -extern void __init of_at91rm9200_clk_usb_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, - struct at91_pmc *pmc); -extern void __init of_at91sam9n12_clk_usb_setup(struct device_node *np, - struct at91_pmc *pmc); -#endif - -#if defined(CONFIG_HAVE_AT91_SMD) -extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, - struct at91_pmc *pmc); -#endif - -#if defined(CONFIG_HAVE_AT91_H32MX) -extern void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, - struct at91_pmc *pmc); -#endif +void of_at91sam9260_clk_slow_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_main_osc_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91rm9200_clk_main_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_main_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9g45_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9g20_clk_pllb_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_sama5d3_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_plldiv_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_master_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_master_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_sys_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_periph_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_periph_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9g45_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_prog_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91sam9x5_clk_utmi_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91rm9200_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9x5_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc); +void of_at91sam9n12_clk_usb_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_at91sam9x5_clk_smd_setup(struct device_node *np, + struct at91_pmc *pmc); + +void of_sama5d4_clk_h32mx_setup(struct device_node *np, + struct at91_pmc *pmc); #endif /* __PMC_H_ */ -- cgit v1.3-6-gb490 From d4f76de37458bc613f9465d8fafc2b5fea0cdea1 Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Fri, 12 Jun 2015 11:41:55 +0300 Subject: clk: qcom: Add support for SR2 PLLs Add support for SR2 type pll operations. SR2 is optimized for Time Interval Error (TIE) or absolute jitter. Signed-off-by: Georgi Djakov Signed-off-by: Stephen Boyd --- drivers/clk/qcom/clk-pll.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-pll.h | 1 + 2 files changed, 76 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c index 245d5063a385..017eede87237 100644 --- a/drivers/clk/qcom/clk-pll.c +++ b/drivers/clk/qcom/clk-pll.c @@ -292,3 +292,78 @@ void clk_pll_configure_sr_hpm_lp(struct clk_pll *pll, struct regmap *regmap, clk_pll_set_fsm_mode(pll, regmap, 0); } EXPORT_SYMBOL_GPL(clk_pll_configure_sr_hpm_lp); + +static int clk_pll_sr2_enable(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + int ret; + u32 mode; + + ret = regmap_read(pll->clkr.regmap, pll->mode_reg, &mode); + if (ret) + return ret; + + /* Disable PLL bypass mode. */ + ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_BYPASSNL, + PLL_BYPASSNL); + if (ret) + return ret; + + /* + * H/W requires a 5us delay between disabling the bypass and + * de-asserting the reset. Delay 10us just to be safe. + */ + udelay(10); + + /* De-assert active-low PLL reset. */ + ret = regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_RESET_N, + PLL_RESET_N); + if (ret) + return ret; + + ret = wait_for_pll(pll); + if (ret) + return ret; + + /* Enable PLL output. */ + return regmap_update_bits(pll->clkr.regmap, pll->mode_reg, PLL_OUTCTRL, + PLL_OUTCTRL); +} + +static int +clk_pll_sr2_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) +{ + struct clk_pll *pll = to_clk_pll(hw); + const struct pll_freq_tbl *f; + bool enabled; + u32 mode; + u32 enable_mask = PLL_OUTCTRL | PLL_BYPASSNL | PLL_RESET_N; + + f = find_freq(pll->freq_tbl, rate); + if (!f) + return -EINVAL; + + regmap_read(pll->clkr.regmap, pll->mode_reg, &mode); + enabled = (mode & enable_mask) == enable_mask; + + if (enabled) + clk_pll_disable(hw); + + regmap_update_bits(pll->clkr.regmap, pll->l_reg, 0x3ff, f->l); + regmap_update_bits(pll->clkr.regmap, pll->m_reg, 0x7ffff, f->m); + regmap_update_bits(pll->clkr.regmap, pll->n_reg, 0x7ffff, f->n); + + if (enabled) + clk_pll_sr2_enable(hw); + + return 0; +} + +const struct clk_ops clk_pll_sr2_ops = { + .enable = clk_pll_sr2_enable, + .disable = clk_pll_disable, + .set_rate = clk_pll_sr2_set_rate, + .recalc_rate = clk_pll_recalc_rate, + .determine_rate = clk_pll_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_pll_sr2_ops); diff --git a/drivers/clk/qcom/clk-pll.h b/drivers/clk/qcom/clk-pll.h index c9c0cda306d0..ffd0c63bddbc 100644 --- a/drivers/clk/qcom/clk-pll.h +++ b/drivers/clk/qcom/clk-pll.h @@ -62,6 +62,7 @@ struct clk_pll { extern const struct clk_ops clk_pll_ops; extern const struct clk_ops clk_pll_vote_ops; +extern const struct clk_ops clk_pll_sr2_ops; #define to_clk_pll(_hw) container_of(to_clk_regmap(_hw), struct clk_pll, clkr) -- cgit v1.3-6-gb490 From 2e3b19f137f31290979999ff7ac67ce52e02be0e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 6 Jul 2015 16:48:19 -0700 Subject: clk: Check for allocation errors in of_clk_init() Dan Carpenter reports that we don't check the allocation here for failure. Add a failure check and free any previously allocated providers from the clk_provider_list. Reported-by: Dan Carpenter Cc: Gregory CLEMENT Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ddb4b541016f..705156828a7a 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3112,8 +3112,17 @@ void __init of_clk_init(const struct of_device_id *matches) /* First prepare the list of the clocks providers */ for_each_matching_node_and_match(np, matches, &match) { - struct clock_provider *parent = - kzalloc(sizeof(struct clock_provider), GFP_KERNEL); + struct clock_provider *parent; + + parent = kzalloc(sizeof(*parent), GFP_KERNEL); + if (!parent) { + list_for_each_entry_safe(clk_provider, next, + &clk_provider_list, node) { + list_del(&clk_provider->node); + kfree(clk_provider); + } + return; + } parent->clk_init_cb = match->data; parent->np = np; -- cgit v1.3-6-gb490 From 2573a02aa5c882fdcab82bba953241f2fa3181a3 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 6 Jul 2015 16:50:00 -0700 Subject: clk: Move clk_provider_list to scope of function using it The list isn't used after of_clk_init() is called, so we don't need to keep an empty list around after init. Put the list on the stack. Cc: Gregory CLEMENT Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 705156828a7a..7873151a7ff8 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3054,8 +3054,6 @@ struct clock_provider { struct list_head node; }; -static LIST_HEAD(clk_provider_list); - /* * This function looks for a parent clock. If there is one, then it * checks that the provider for this parent clock was initialized, in @@ -3106,6 +3104,7 @@ void __init of_clk_init(const struct of_device_id *matches) struct clock_provider *clk_provider, *next; bool is_init_done; bool force = false; + LIST_HEAD(clk_provider_list); if (!matches) matches = &__clk_of_table; -- cgit v1.3-6-gb490 From 4c62dbbce902cf2afa88cac89ec67c828160f431 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 26 Jun 2015 11:27:41 +0300 Subject: ACPI: Remove FSF mailing addresses There is no need to carry potentially outdated Free Software Foundation mailing address in file headers since the COPYING file includes it. Signed-off-by: Jarkko Nikula Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ac.c | 4 ---- drivers/acpi/acpi_ipmi.c | 4 ---- drivers/acpi/acpi_memhotplug.c | 5 ----- drivers/acpi/acpi_pad.c | 4 ---- drivers/acpi/acpi_video.c | 4 ---- drivers/acpi/apei/apei-base.c | 4 ---- drivers/acpi/apei/einj.c | 4 ---- drivers/acpi/apei/erst-dbg.c | 4 ---- drivers/acpi/apei/erst.c | 4 ---- drivers/acpi/apei/ghes.c | 4 ---- drivers/acpi/apei/hest.c | 4 ---- drivers/acpi/battery.c | 4 ---- drivers/acpi/blacklist.c | 4 ---- drivers/acpi/bus.c | 4 ---- drivers/acpi/button.c | 4 ---- drivers/acpi/cm_sbs.c | 4 ---- drivers/acpi/container.c | 4 ---- drivers/acpi/device_pm.c | 4 ---- drivers/acpi/dock.c | 4 ---- drivers/acpi/ec.c | 4 ---- drivers/acpi/fan.c | 4 ---- drivers/acpi/hed.c | 4 ---- drivers/acpi/internal.h | 3 --- drivers/acpi/numa.c | 4 ---- drivers/acpi/osl.c | 4 ---- drivers/acpi/pci_irq.c | 4 ---- drivers/acpi/pci_link.c | 4 ---- drivers/acpi/pci_root.c | 4 ---- drivers/acpi/pci_slot.c | 4 ---- drivers/acpi/power.c | 4 ---- drivers/acpi/processor_driver.c | 4 ---- drivers/acpi/processor_idle.c | 4 ---- drivers/acpi/processor_perflib.c | 4 ---- drivers/acpi/processor_thermal.c | 4 ---- drivers/acpi/processor_throttling.c | 4 ---- drivers/acpi/resource.c | 4 ---- drivers/acpi/sbs.c | 4 ---- drivers/acpi/tables.c | 4 ---- drivers/acpi/thermal.c | 4 ---- drivers/acpi/utils.c | 4 ---- include/acpi/acpi_bus.h | 4 ---- include/acpi/acpi_drivers.h | 4 ---- include/linux/acpi.h | 4 ---- 43 files changed, 172 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 9b5354a2cd08..f71b756b05c4 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -16,10 +16,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c index ac0f52f6df2b..f77956c3fd45 100644 --- a/drivers/acpi/acpi_ipmi.c +++ b/drivers/acpi/acpi_ipmi.c @@ -17,10 +17,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index ee28f4d15625..6b0d3ef7309c 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -16,11 +16,6 @@ * NON INFRINGEMENT. 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. - * - * * ACPI based HotPlug driver that supports Memory Hotplug * This driver fields notifications from firmware for memory add * and remove operations and alerts the VM of the affected memory diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 00b39802d7ec..ae307ff36acb 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -12,10 +12,6 @@ * 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 diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 8c2fe2f2f9fd..5778e8e4313a 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -17,10 +17,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index a85ac07f3da3..a2c8d7adb6eb 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -24,10 +24,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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index a095d4f858da..0431883653be 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -18,10 +18,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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/apei/erst-dbg.c b/drivers/acpi/apei/erst-dbg.c index 04ab5c9d3ced..6330f557a2c8 100644 --- a/drivers/acpi/apei/erst-dbg.c +++ b/drivers/acpi/apei/erst-dbg.c @@ -17,10 +17,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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 3670bbab57a3..6682c5daf742 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -18,10 +18,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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 2bfd53cbfe80..23981ac1c6c2 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -23,10 +23,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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 06e9b411a0a2..20b3fcf4007c 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -21,10 +21,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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index b3628cc01a53..b719ab3090bb 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -18,10 +18,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 278dc4be992a..96809cd99ace 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -20,10 +20,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 513e7230e3d0..c8356eb79911 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -15,10 +15,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 6d5d1832a588..5c3b0918d5fd 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -16,10 +16,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index 6c9ee68e46fb..d0918d421f90 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -11,10 +11,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index c8ead9f97375..12c240903c18 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -20,10 +20,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 717afcdb5f4a..d06cd59b5906 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -15,10 +15,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index a688aa243f6c..e8e128dede29 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -17,10 +17,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 9d4761d2f6b7..990446629935 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -22,10 +22,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index bea0bbaafa97..e297a480e135 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -16,10 +16,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index a322710b5ba4..5c67a6d8f803 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -15,10 +15,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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 4683a96932b9..8c71cb8335c0 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -13,9 +13,6 @@ * 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. */ #ifndef _ACPI_INTERNAL_H_ diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index acaa3b4ea504..72b6e9ef0ae9 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -15,10 +15,6 @@ * 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 - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c262e4acd68d..5e1f1bc5421e 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -19,10 +19,6 @@ * 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 - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * */ diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 304eccb0ae5c..25fff35df82c 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -19,10 +19,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index cfd7581cc19f..2f5f84ced85f 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -17,10 +17,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * TBD: diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1b5569c092c6..393706a5261b 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -16,10 +16,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 139d9e479370..7188e53b6b7c 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -20,10 +20,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 diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 93eac53b5110..45b47f2c9f03 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -16,10 +16,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index d9f71581b79b..3af8dc30f129 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -21,10 +21,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d540f42c9232..175c86bee3a9 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -21,10 +21,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index cfc8aba72f86..53cfe8ba9799 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -20,10 +20,6 @@ * 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. - * */ #include diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index e003663b2f8e..1fed84a092c2 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -19,10 +19,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 84243c32e29c..f170d746336d 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -19,10 +19,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 10561ce16ed1..64ea0d10b788 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -15,10 +15,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 01504c819e8f..cb3dedb1beae 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -17,10 +17,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 2e19189da0ee..17a6fa01a338 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -15,10 +15,6 @@ * 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 - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * */ diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 6d4e44ea74ac..fc28b9f5aa84 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -16,10 +16,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This driver fully implements the ACPI thermal policy as described in the diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 67c548ad3764..475c9079bf85 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -16,10 +16,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 83061cac719b..5ba8fb64f664 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -16,10 +16,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index ea6428b7dacb..29c691265b49 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -16,10 +16,6 @@ * 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. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c471dfc93b71..1c116ee53b1e 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -15,10 +15,6 @@ * 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 - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -- cgit v1.3-6-gb490 From 310b0d55f0301908461191db392ecee01735b3ec Mon Sep 17 00:00:00 2001 From: "Vutla, Lokesh" Date: Tue, 7 Jul 2015 21:01:43 +0530 Subject: crypto: omap-aes - Fix CTR mode Algo self tests are failing for CTR mode with omap-aes driver, giving the following error: [ 150.053644] omap_aes_crypt: request size is not exact amount of AES blocks [ 150.061262] alg: skcipher: encryption failed on test 5 for ctr-aes-omap: ret=22 This is because the input length is not aligned with AES_BLOCK_SIZE. Adding support for omap-aes driver for inputs with length not aligned with AES_BLOCK_SIZE. Signed-off-by: Lokesh Vutla Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 9a28b7e07c71..4a0e808b4fba 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -558,6 +558,9 @@ static int omap_aes_check_aligned(struct scatterlist *sg, int total) { int len = 0; + if (!IS_ALIGNED(total, AES_BLOCK_SIZE)) + return -EINVAL; + while (sg) { if (!IS_ALIGNED(sg->offset, 4)) return -1; @@ -577,9 +580,10 @@ static int omap_aes_check_aligned(struct scatterlist *sg, int total) static int omap_aes_copy_sgs(struct omap_aes_dev *dd) { void *buf_in, *buf_out; - int pages; + int pages, total; - pages = get_order(dd->total); + total = ALIGN(dd->total, AES_BLOCK_SIZE); + pages = get_order(total); buf_in = (void *)__get_free_pages(GFP_ATOMIC, pages); buf_out = (void *)__get_free_pages(GFP_ATOMIC, pages); @@ -594,11 +598,11 @@ static int omap_aes_copy_sgs(struct omap_aes_dev *dd) sg_copy_buf(buf_in, dd->in_sg, 0, dd->total, 0); sg_init_table(&dd->in_sgl, 1); - sg_set_buf(&dd->in_sgl, buf_in, dd->total); + sg_set_buf(&dd->in_sgl, buf_in, total); dd->in_sg = &dd->in_sgl; sg_init_table(&dd->out_sgl, 1); - sg_set_buf(&dd->out_sgl, buf_out, dd->total); + sg_set_buf(&dd->out_sgl, buf_out, total); dd->out_sg = &dd->out_sgl; return 0; @@ -611,7 +615,7 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd, struct omap_aes_ctx *ctx; struct omap_aes_reqctx *rctx; unsigned long flags; - int err, ret = 0; + int err, ret = 0, len; spin_lock_irqsave(&dd->lock, flags); if (req) @@ -650,8 +654,9 @@ static int omap_aes_handle_queue(struct omap_aes_dev *dd, dd->sgs_copied = 0; } - dd->in_sg_len = scatterwalk_bytes_sglen(dd->in_sg, dd->total); - dd->out_sg_len = scatterwalk_bytes_sglen(dd->out_sg, dd->total); + len = ALIGN(dd->total, AES_BLOCK_SIZE); + dd->in_sg_len = scatterwalk_bytes_sglen(dd->in_sg, len); + dd->out_sg_len = scatterwalk_bytes_sglen(dd->out_sg, len); BUG_ON(dd->in_sg_len < 0 || dd->out_sg_len < 0); rctx = ablkcipher_request_ctx(req); @@ -678,7 +683,7 @@ static void omap_aes_done_task(unsigned long data) { struct omap_aes_dev *dd = (struct omap_aes_dev *)data; void *buf_in, *buf_out; - int pages; + int pages, len; pr_debug("enter done_task\n"); @@ -697,7 +702,8 @@ static void omap_aes_done_task(unsigned long data) sg_copy_buf(buf_out, dd->orig_out, 0, dd->total_save, 1); - pages = get_order(dd->total_save); + len = ALIGN(dd->total_save, AES_BLOCK_SIZE); + pages = get_order(len); free_pages((unsigned long)buf_in, pages); free_pages((unsigned long)buf_out, pages); } @@ -726,11 +732,6 @@ static int omap_aes_crypt(struct ablkcipher_request *req, unsigned long mode) !!(mode & FLAGS_ENCRYPT), !!(mode & FLAGS_CBC)); - if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) { - pr_err("request size is not exact amount of AES blocks\n"); - return -EINVAL; - } - dd = omap_aes_find_dev(ctx); if (!dd) return -ENODEV; @@ -1046,9 +1047,7 @@ static irqreturn_t omap_aes_irq(int irq, void *dev_id) } } - dd->total -= AES_BLOCK_SIZE; - - BUG_ON(dd->total < 0); + dd->total -= min_t(size_t, AES_BLOCK_SIZE, dd->total); /* Clear IRQ status */ status &= ~AES_REG_IRQ_DATA_OUT; -- cgit v1.3-6-gb490 From 6e2e3d1de45214fe5538318a208f2f7ccc617e4c Mon Sep 17 00:00:00 2001 From: "Vutla, Lokesh" Date: Tue, 7 Jul 2015 21:01:44 +0530 Subject: crypto: omap-aes - Increase priority of hw accelerator Increasing the priority of omap-aes hw algos, in order to take precedence over sw algos. Signed-off-by: Lokesh Vutla Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 4a0e808b4fba..54925d98b12f 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -834,7 +834,7 @@ static struct crypto_alg algs_ecb_cbc[] = { { .cra_name = "ecb(aes)", .cra_driver_name = "ecb-aes-omap", - .cra_priority = 100, + .cra_priority = 300, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC, @@ -856,7 +856,7 @@ static struct crypto_alg algs_ecb_cbc[] = { { .cra_name = "cbc(aes)", .cra_driver_name = "cbc-aes-omap", - .cra_priority = 100, + .cra_priority = 300, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC, @@ -882,7 +882,7 @@ static struct crypto_alg algs_ctr[] = { { .cra_name = "ctr(aes)", .cra_driver_name = "ctr-aes-omap", - .cra_priority = 100, + .cra_priority = 300, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC, -- cgit v1.3-6-gb490 From 5396c6c0741317a54f8032ac50346f123e664a52 Mon Sep 17 00:00:00 2001 From: "Vutla, Lokesh" Date: Tue, 7 Jul 2015 21:01:45 +0530 Subject: crypto: omap-aes - Fix configuring of AES mode AES_CTRL_REG is used to configure AES mode. Before configuring any mode we need to make sure all other modes are reset or else driver will misbehave. So mask all modes before configuring any AES mode. Signed-off-by: Lokesh Vutla Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 54925d98b12f..35521b8b6886 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -63,6 +63,7 @@ #define AES_REG_CTRL_DIRECTION (1 << 2) #define AES_REG_CTRL_INPUT_READY (1 << 1) #define AES_REG_CTRL_OUTPUT_READY (1 << 0) +#define AES_REG_CTRL_MASK GENMASK(24, 2) #define AES_REG_DATA_N(dd, x) ((dd)->pdata->data_ofs + ((x) * 0x04)) @@ -254,7 +255,7 @@ static int omap_aes_write_ctrl(struct omap_aes_dev *dd) { unsigned int key32; int i, err; - u32 val, mask = 0; + u32 val; err = omap_aes_hw_init(dd); if (err) @@ -274,17 +275,13 @@ static int omap_aes_write_ctrl(struct omap_aes_dev *dd) val = FLD_VAL(((dd->ctx->keylen >> 3) - 1), 4, 3); if (dd->flags & FLAGS_CBC) val |= AES_REG_CTRL_CBC; - if (dd->flags & FLAGS_CTR) { + if (dd->flags & FLAGS_CTR) val |= AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_128; - mask = AES_REG_CTRL_CTR | AES_REG_CTRL_CTR_WIDTH_MASK; - } + if (dd->flags & FLAGS_ENCRYPT) val |= AES_REG_CTRL_DIRECTION; - mask |= AES_REG_CTRL_CBC | AES_REG_CTRL_DIRECTION | - AES_REG_CTRL_KEY_SIZE; - - omap_aes_write_mask(dd, AES_REG_CTRL(dd), val, mask); + omap_aes_write_mask(dd, AES_REG_CTRL(dd), val, AES_REG_CTRL_MASK); return 0; } -- cgit v1.3-6-gb490 From 340d9d317eb93039754004621c6c5cb1a5e9735c Mon Sep 17 00:00:00 2001 From: "Vutla, Lokesh" Date: Tue, 7 Jul 2015 21:01:46 +0530 Subject: crypto: omap-aes - Use BIT() macro Use BIT()/GENMASK() macros for all register definitions instead of hand-writing bit masks. Signed-off-by: Lokesh Vutla Signed-off-by: Herbert Xu --- drivers/crypto/omap-aes.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 35521b8b6886..eba23147c0ee 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -52,17 +52,17 @@ #define AES_REG_IV(dd, x) ((dd)->pdata->iv_ofs + ((x) * 0x04)) #define AES_REG_CTRL(dd) ((dd)->pdata->ctrl_ofs) -#define AES_REG_CTRL_CTR_WIDTH_MASK (3 << 7) -#define AES_REG_CTRL_CTR_WIDTH_32 (0 << 7) -#define AES_REG_CTRL_CTR_WIDTH_64 (1 << 7) -#define AES_REG_CTRL_CTR_WIDTH_96 (2 << 7) -#define AES_REG_CTRL_CTR_WIDTH_128 (3 << 7) -#define AES_REG_CTRL_CTR (1 << 6) -#define AES_REG_CTRL_CBC (1 << 5) -#define AES_REG_CTRL_KEY_SIZE (3 << 3) -#define AES_REG_CTRL_DIRECTION (1 << 2) -#define AES_REG_CTRL_INPUT_READY (1 << 1) -#define AES_REG_CTRL_OUTPUT_READY (1 << 0) +#define AES_REG_CTRL_CTR_WIDTH_MASK GENMASK(8, 7) +#define AES_REG_CTRL_CTR_WIDTH_32 0 +#define AES_REG_CTRL_CTR_WIDTH_64 BIT(7) +#define AES_REG_CTRL_CTR_WIDTH_96 BIT(8) +#define AES_REG_CTRL_CTR_WIDTH_128 GENMASK(8, 7) +#define AES_REG_CTRL_CTR BIT(6) +#define AES_REG_CTRL_CBC BIT(5) +#define AES_REG_CTRL_KEY_SIZE GENMASK(4, 3) +#define AES_REG_CTRL_DIRECTION BIT(2) +#define AES_REG_CTRL_INPUT_READY BIT(1) +#define AES_REG_CTRL_OUTPUT_READY BIT(0) #define AES_REG_CTRL_MASK GENMASK(24, 2) #define AES_REG_DATA_N(dd, x) ((dd)->pdata->data_ofs + ((x) * 0x04)) @@ -70,12 +70,12 @@ #define AES_REG_REV(dd) ((dd)->pdata->rev_ofs) #define AES_REG_MASK(dd) ((dd)->pdata->mask_ofs) -#define AES_REG_MASK_SIDLE (1 << 6) -#define AES_REG_MASK_START (1 << 5) -#define AES_REG_MASK_DMA_OUT_EN (1 << 3) -#define AES_REG_MASK_DMA_IN_EN (1 << 2) -#define AES_REG_MASK_SOFTRESET (1 << 1) -#define AES_REG_AUTOIDLE (1 << 0) +#define AES_REG_MASK_SIDLE BIT(6) +#define AES_REG_MASK_START BIT(5) +#define AES_REG_MASK_DMA_OUT_EN BIT(3) +#define AES_REG_MASK_DMA_IN_EN BIT(2) +#define AES_REG_MASK_SOFTRESET BIT(1) +#define AES_REG_AUTOIDLE BIT(0) #define AES_REG_LENGTH_N(x) (0x54 + ((x) * 0x04)) -- cgit v1.3-6-gb490 From 21589ebda68172baeb03f35533ee2ec34543bf55 Mon Sep 17 00:00:00 2001 From: Guilhem Lettron Date: Sat, 27 Jun 2015 17:02:23 +0200 Subject: HID: sensor-hub: Add in quirk for Lenovo Yogas with ITE Like yogas with TEXAS_INSTRUMENTS, yogas with ITE chips needs to be initialized with enumeration quirks. Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-sensor-hub.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b04b0820d816..9a59810a0b21 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -497,6 +497,9 @@ #define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070 +#define USB_VENDOR_ID_ITE 0x048d +#define USB_DEVICE_ID_ITE_LENOVO_YOGA 0x8386 + #define USB_VENDOR_ID_JABRA 0x0b0e #define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412 #define USB_DEVICE_ID_JABRA_SPEAK_510 0x0420 diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 090a1ba0abb6..a76eb2a0a987 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -774,6 +774,9 @@ static const struct hid_device_id sensor_hub_devices[] = { { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_TEXAS_INSTRUMENTS, USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA), .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE, + USB_DEVICE_ID_ITE_LENOVO_YOGA), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID, HID_ANY_ID) }, { } -- cgit v1.3-6-gb490 From 615322f6ac358f9c94b483d0a16f3f46fcb27b1c Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 29 Jun 2015 11:10:41 +0200 Subject: HID: usbhid: no flushing if device is already polled During open() it is unnecessary to wait for the device to flush stale inputs if the device is polled while closed due to a quirk or opening fails. Signed-off-by: Oliver Neukum Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index bfbe1bedda7f..1a23d78fe5e7 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -710,7 +710,8 @@ int usbhid_open(struct hid_device *hid) * Wait 50 msec for the queue to empty before allowing events * to go through hid. */ - msleep(50); + if (res == 0 && !(hid->quirks & HID_QUIRK_ALWAYS_POLL)) + msleep(50); clear_bit(HID_RESUME_RUNNING, &usbhid->iofl); } done: -- cgit v1.3-6-gb490 From ff2a31171016771829fd1689af65752175de1940 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:03 -0300 Subject: drm/i915: move FBC vfuncs to struct i915_fbc Because it makes more sense there, IMHO. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 +++--- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_fbc.c | 44 ++++++++++++++++++------------------ 3 files changed, 28 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 464b28d5e678..79d7ecec1bbf 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -598,9 +598,6 @@ struct intel_limit; struct dpll; struct drm_i915_display_funcs { - bool (*fbc_enabled)(struct drm_device *dev); - void (*enable_fbc)(struct drm_crtc *crtc); - void (*disable_fbc)(struct drm_device *dev); int (*get_display_clock_speed)(struct drm_device *dev); int (*get_fifo_size)(struct drm_device *dev, int plane); /** @@ -939,6 +936,10 @@ struct i915_fbc { FBC_CHIP_DEFAULT, /* disabled by default on this chip */ FBC_ROTATION, /* rotation is not supported */ } no_fbc_reason; + + bool (*fbc_enabled)(struct drm_device *dev); + void (*enable_fbc)(struct drm_crtc *crtc); + void (*disable_fbc)(struct drm_device *dev); }; /** diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3c2425f5366d..aefcf028fd92 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3134,8 +3134,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->display.disable_fbc) - dev_priv->display.disable_fbc(dev); + if (dev_priv->fbc.disable_fbc) + dev_priv->fbc.disable_fbc(dev); dev_priv->display.update_primary_plane(crtc, fb, x, y); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 65f08e330dc1..07ea5b311d27 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -341,7 +341,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) * the prior work. */ if (work->crtc->primary->fb == work->fb) { - dev_priv->display.enable_fbc(work->crtc); + dev_priv->fbc.enable_fbc(work->crtc); dev_priv->fbc.crtc = to_intel_crtc(work->crtc); dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id; @@ -393,7 +393,7 @@ static void intel_fbc_enable(struct drm_crtc *crtc) work = kzalloc(sizeof(*work), GFP_KERNEL); if (work == NULL) { DRM_ERROR("Failed to allocate FBC work structure\n"); - dev_priv->display.enable_fbc(crtc); + dev_priv->fbc.enable_fbc(crtc); return; } @@ -427,7 +427,7 @@ static void __intel_fbc_disable(struct drm_device *dev) intel_fbc_cancel_work(dev_priv); - dev_priv->display.disable_fbc(dev); + dev_priv->fbc.disable_fbc(dev); dev_priv->fbc.crtc = NULL; } @@ -441,7 +441,7 @@ void intel_fbc_disable(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); @@ -460,7 +460,7 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc) struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); @@ -661,7 +661,7 @@ void intel_fbc_cleanup_cfb(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); @@ -857,7 +857,7 @@ void intel_fbc_update(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); @@ -872,7 +872,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, struct drm_device *dev = dev_priv->dev; unsigned int fbc_bits; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; if (origin == ORIGIN_GTT) @@ -901,7 +901,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, { struct drm_device *dev = dev_priv->dev; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); @@ -945,25 +945,25 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) } if (INTEL_INFO(dev_priv)->gen >= 7) { - dev_priv->display.fbc_enabled = ilk_fbc_enabled; - dev_priv->display.enable_fbc = gen7_fbc_enable; - dev_priv->display.disable_fbc = ilk_fbc_disable; + dev_priv->fbc.fbc_enabled = ilk_fbc_enabled; + dev_priv->fbc.enable_fbc = gen7_fbc_enable; + dev_priv->fbc.disable_fbc = ilk_fbc_disable; } else if (INTEL_INFO(dev_priv)->gen >= 5) { - dev_priv->display.fbc_enabled = ilk_fbc_enabled; - dev_priv->display.enable_fbc = ilk_fbc_enable; - dev_priv->display.disable_fbc = ilk_fbc_disable; + dev_priv->fbc.fbc_enabled = ilk_fbc_enabled; + dev_priv->fbc.enable_fbc = ilk_fbc_enable; + dev_priv->fbc.disable_fbc = ilk_fbc_disable; } else if (IS_GM45(dev_priv)) { - dev_priv->display.fbc_enabled = g4x_fbc_enabled; - dev_priv->display.enable_fbc = g4x_fbc_enable; - dev_priv->display.disable_fbc = g4x_fbc_disable; + dev_priv->fbc.fbc_enabled = g4x_fbc_enabled; + dev_priv->fbc.enable_fbc = g4x_fbc_enable; + dev_priv->fbc.disable_fbc = g4x_fbc_disable; } else { - dev_priv->display.fbc_enabled = i8xx_fbc_enabled; - dev_priv->display.enable_fbc = i8xx_fbc_enable; - dev_priv->display.disable_fbc = i8xx_fbc_disable; + dev_priv->fbc.fbc_enabled = i8xx_fbc_enabled; + dev_priv->fbc.enable_fbc = i8xx_fbc_enable; + dev_priv->fbc.disable_fbc = i8xx_fbc_disable; /* This value was pulled out of someone's hat */ I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); } - dev_priv->fbc.enabled = dev_priv->display.fbc_enabled(dev_priv->dev); + dev_priv->fbc.enabled = dev_priv->fbc.fbc_enabled(dev_priv->dev); } -- cgit v1.3-6-gb490 From 7733b49bb03ee10b8889f8f5edf11d755115b230 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:04 -0300 Subject: drm/i915: use dev_priv for the FBC functions Because the cool kids use dev_priv and FBC wants to be cool too. We've been historically using struct drm_device on the FBC function arguments, but we only really need it for intel_vgpu_active(): we can use dev_priv everywhere else. So let's fully switch to dev_priv since I'm getting tired of adding "struct drm_device *dev = dev_priv->dev" everywhere. If I get a NACK here I'll propose the opposite: convert all the functions that currently take dev_priv to take dev. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 4 +- drivers/gpu/drm/i915/i915_suspend.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 14 ++-- drivers/gpu/drm/i915/intel_drv.h | 8 +- drivers/gpu/drm/i915/intel_fbc.c | 154 ++++++++++++++--------------------- drivers/gpu/drm/i915/intel_pm.c | 4 +- 8 files changed, 80 insertions(+), 110 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5b89130eb366..73aaea22bbef 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1635,7 +1635,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused) intel_runtime_pm_get(dev_priv); mutex_lock(&dev_priv->fbc.lock); - if (intel_fbc_enabled(dev)) + if (intel_fbc_enabled(dev_priv)) seq_puts(m, "FBC enabled\n"); else seq_printf(m, "FBC disabled: %s\n", diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 066c34c3298a..5e63076cc769 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1123,7 +1123,7 @@ int i915_driver_unload(struct drm_device *dev) i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); - intel_fbc_cleanup_cfb(dev); + intel_fbc_cleanup_cfb(dev_priv); i915_gem_cleanup_stolen(dev); intel_csr_ucode_fini(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 79d7ecec1bbf..7f75ff36245b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -937,9 +937,9 @@ struct i915_fbc { FBC_ROTATION, /* rotation is not supported */ } no_fbc_reason; - bool (*fbc_enabled)(struct drm_device *dev); + bool (*fbc_enabled)(struct drm_i915_private *dev_priv); void (*enable_fbc)(struct drm_crtc *crtc); - void (*disable_fbc)(struct drm_device *dev); + void (*disable_fbc)(struct drm_i915_private *dev_priv); }; /** diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index cf67f82f7b7f..1ccac618468e 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -92,7 +92,7 @@ static void i915_restore_display(struct drm_device *dev) } /* only restore FBC info on the platform that supports FBC*/ - intel_fbc_disable(dev); + intel_fbc_disable(dev_priv); /* restore FBC interval */ if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev)) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aefcf028fd92..4bcbff9793d4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3135,7 +3135,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->fbc.disable_fbc) - dev_priv->fbc.disable_fbc(dev); + dev_priv->fbc.disable_fbc(dev_priv); dev_priv->display.update_primary_plane(crtc, fb, x, y); @@ -4734,6 +4734,7 @@ static void intel_post_plane_update(struct intel_crtc *crtc) { struct intel_crtc_atomic_commit *atomic = &crtc->atomic; struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_plane *plane; if (atomic->wait_vblank) @@ -4748,7 +4749,7 @@ static void intel_post_plane_update(struct intel_crtc *crtc) intel_update_watermarks(&crtc->base); if (atomic->update_fbc) - intel_fbc_update(dev); + intel_fbc_update(dev_priv); if (atomic->post_enable_primary) intel_post_enable_primary(&crtc->base); @@ -10688,13 +10689,14 @@ static void intel_unpin_work_fn(struct work_struct *__work) container_of(__work, struct intel_unpin_work, work); struct intel_crtc *crtc = to_intel_crtc(work->crtc); struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_plane *primary = crtc->base.primary; mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(work->old_fb, primary->state); drm_gem_object_unreference(&work->pending_flip_obj->base); - intel_fbc_update(dev); + intel_fbc_update(dev_priv); if (work->flip_queued_req) i915_gem_request_assign(&work->flip_queued_req, NULL); @@ -11469,7 +11471,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, to_intel_plane(primary)->frontbuffer_bit); mutex_unlock(&dev->struct_mutex); - intel_fbc_disable(dev); + intel_fbc_disable(dev_priv); intel_frontbuffer_flip_prepare(dev, to_intel_plane(primary)->frontbuffer_bit); @@ -15045,7 +15047,7 @@ void intel_modeset_init(struct drm_device *dev) intel_setup_outputs(dev); /* Just in case the BIOS is doing something questionable. */ - intel_fbc_disable(dev); + intel_fbc_disable(dev_priv); drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(dev, false); @@ -15599,7 +15601,7 @@ void intel_modeset_cleanup(struct drm_device *dev) intel_unregister_dsm_handler(); - intel_fbc_disable(dev); + intel_fbc_disable(dev_priv); /* flush any delayed tasks or pending work */ flush_scheduled_work(); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 63d7d32e6123..082d0e7dfb14 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1248,10 +1248,10 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev) #endif /* intel_fbc.c */ -bool intel_fbc_enabled(struct drm_device *dev); -void intel_fbc_update(struct drm_device *dev); +bool intel_fbc_enabled(struct drm_i915_private *dev_priv); +void intel_fbc_update(struct drm_i915_private *dev_priv); void intel_fbc_init(struct drm_i915_private *dev_priv); -void intel_fbc_disable(struct drm_device *dev); +void intel_fbc_disable(struct drm_i915_private *dev_priv); void intel_fbc_disable_crtc(struct intel_crtc *crtc); void intel_fbc_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, @@ -1259,7 +1259,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); const char *intel_no_fbc_reason_str(enum no_fbc_reason reason); -void intel_fbc_cleanup_cfb(struct drm_device *dev); +void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv); /* intel_hdmi.c */ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 07ea5b311d27..449dbe42569f 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -41,9 +41,8 @@ #include "intel_drv.h" #include "i915_drv.h" -static void i8xx_fbc_disable(struct drm_device *dev) +static void i8xx_fbc_disable(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; u32 fbc_ctl; dev_priv->fbc.enabled = false; @@ -67,8 +66,7 @@ static void i8xx_fbc_disable(struct drm_device *dev) static void i8xx_fbc_enable(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct drm_framebuffer *fb = crtc->primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -84,7 +82,7 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) cfb_pitch = fb->pitches[0]; /* FBC_CTL wants 32B or 64B units */ - if (IS_GEN2(dev)) + if (IS_GEN2(dev_priv)) cfb_pitch = (cfb_pitch / 32) - 1; else cfb_pitch = (cfb_pitch / 64) - 1; @@ -93,7 +91,7 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) I915_WRITE(FBC_TAG + (i * 4), 0); - if (IS_GEN4(dev)) { + if (IS_GEN4(dev_priv)) { u32 fbc_ctl2; /* Set it up... */ @@ -107,7 +105,7 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) fbc_ctl = I915_READ(FBC_CONTROL); fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT; fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC; - if (IS_I945GM(dev)) + if (IS_I945GM(dev_priv)) fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; fbc_ctl |= obj->fence_reg; @@ -117,17 +115,14 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) cfb_pitch, crtc->y, plane_name(intel_crtc->plane)); } -static bool i8xx_fbc_enabled(struct drm_device *dev) +static bool i8xx_fbc_enabled(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - return I915_READ(FBC_CONTROL) & FBC_CTL_EN; } static void g4x_fbc_enable(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct drm_framebuffer *fb = crtc->primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -150,9 +145,8 @@ static void g4x_fbc_enable(struct drm_crtc *crtc) DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); } -static void g4x_fbc_disable(struct drm_device *dev) +static void g4x_fbc_disable(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; u32 dpfc_ctl; dev_priv->fbc.enabled = false; @@ -167,10 +161,8 @@ static void g4x_fbc_disable(struct drm_device *dev) } } -static bool g4x_fbc_enabled(struct drm_device *dev) +static bool g4x_fbc_enabled(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN; } @@ -182,8 +174,7 @@ static void intel_fbc_nuke(struct drm_i915_private *dev_priv) static void ilk_fbc_enable(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct drm_framebuffer *fb = crtc->primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -209,7 +200,7 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) break; } dpfc_ctl |= DPFC_CTL_FENCE_EN; - if (IS_GEN5(dev)) + if (IS_GEN5(dev_priv)) dpfc_ctl |= obj->fence_reg; I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); @@ -217,7 +208,7 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) /* enable it... */ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); - if (IS_GEN6(dev)) { + if (IS_GEN6(dev_priv)) { I915_WRITE(SNB_DPFC_CTL_SA, SNB_CPU_FENCE_ENABLE | obj->fence_reg); I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); @@ -228,9 +219,8 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); } -static void ilk_fbc_disable(struct drm_device *dev) +static void ilk_fbc_disable(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; u32 dpfc_ctl; dev_priv->fbc.enabled = false; @@ -245,17 +235,14 @@ static void ilk_fbc_disable(struct drm_device *dev) } } -static bool ilk_fbc_enabled(struct drm_device *dev) +static bool ilk_fbc_enabled(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; } static void gen7_fbc_enable(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct drm_framebuffer *fb = crtc->primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -265,7 +252,7 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) dev_priv->fbc.enabled = true; dpfc_ctl = 0; - if (IS_IVYBRIDGE(dev)) + if (IS_IVYBRIDGE(dev_priv)) dpfc_ctl |= IVB_DPFC_CTL_PLANE(intel_crtc->plane); if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) @@ -291,7 +278,7 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); - if (IS_IVYBRIDGE(dev)) { + if (IS_IVYBRIDGE(dev_priv)) { /* WaFbcAsynchFlipDisableFbcQueue:ivb */ I915_WRITE(ILK_DISPLAY_CHICKEN1, I915_READ(ILK_DISPLAY_CHICKEN1) | @@ -314,16 +301,14 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) /** * intel_fbc_enabled - Is FBC enabled? - * @dev: the drm_device + * @dev_priv: i915 device instance * * This function is used to verify the current state of FBC. * FIXME: This should be tracked in the plane config eventually * instead of queried at runtime for most callers. */ -bool intel_fbc_enabled(struct drm_device *dev) +bool intel_fbc_enabled(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - return dev_priv->fbc.enabled; } @@ -332,8 +317,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) struct intel_fbc_work *work = container_of(to_delayed_work(__work), struct intel_fbc_work, work); - struct drm_device *dev = work->crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = work->crtc->dev->dev_private; mutex_lock(&dev_priv->fbc.lock); if (work == dev_priv->fbc.fbc_work) { @@ -383,8 +367,7 @@ static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv) static void intel_fbc_enable(struct drm_crtc *crtc) { struct intel_fbc_work *work; - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); @@ -419,33 +402,29 @@ static void intel_fbc_enable(struct drm_crtc *crtc) schedule_delayed_work(&work->work, msecs_to_jiffies(50)); } -static void __intel_fbc_disable(struct drm_device *dev) +static void __intel_fbc_disable(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); intel_fbc_cancel_work(dev_priv); - dev_priv->fbc.disable_fbc(dev); + dev_priv->fbc.disable_fbc(dev_priv); dev_priv->fbc.crtc = NULL; } /** * intel_fbc_disable - disable FBC - * @dev: the drm_device + * @dev_priv: i915 device instance * * This function disables FBC. */ -void intel_fbc_disable(struct drm_device *dev) +void intel_fbc_disable(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); - __intel_fbc_disable(dev); + __intel_fbc_disable(dev_priv); mutex_unlock(&dev_priv->fbc.lock); } @@ -457,15 +436,14 @@ void intel_fbc_disable(struct drm_device *dev) */ void intel_fbc_disable_crtc(struct intel_crtc *crtc) { - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); if (dev_priv->fbc.crtc == crtc) - __intel_fbc_disable(dev); + __intel_fbc_disable(dev_priv); mutex_unlock(&dev_priv->fbc.lock); } @@ -547,12 +525,11 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) return crtc; } -static int find_compression_threshold(struct drm_device *dev, +static int find_compression_threshold(struct drm_i915_private *dev_priv, struct drm_mm_node *node, int size, int fb_cpp) { - struct drm_i915_private *dev_priv = dev->dev_private; int compression_threshold = 1; int ret; @@ -575,7 +552,7 @@ again: return 0; ret = i915_gem_stolen_insert_node(dev_priv, node, size >>= 1, 4096); - if (ret && INTEL_INFO(dev)->gen <= 4) { + if (ret && INTEL_INFO(dev_priv)->gen <= 4) { return 0; } else if (ret) { compression_threshold <<= 1; @@ -585,13 +562,13 @@ again: } } -static int intel_fbc_alloc_cfb(struct drm_device *dev, int size, int fb_cpp) +static int intel_fbc_alloc_cfb(struct drm_i915_private *dev_priv, int size, + int fb_cpp) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_mm_node *uninitialized_var(compressed_llb); int ret; - ret = find_compression_threshold(dev, &dev_priv->fbc.compressed_fb, + ret = find_compression_threshold(dev_priv, &dev_priv->fbc.compressed_fb, size, fb_cpp); if (!ret) goto err_llb; @@ -604,7 +581,7 @@ static int intel_fbc_alloc_cfb(struct drm_device *dev, int size, int fb_cpp) if (INTEL_INFO(dev_priv)->gen >= 5) I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); - else if (IS_GM45(dev)) { + else if (IS_GM45(dev_priv)) { I915_WRITE(DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); } else { compressed_llb = kzalloc(sizeof(*compressed_llb), GFP_KERNEL); @@ -639,10 +616,8 @@ err_llb: return -ENOSPC; } -static void __intel_fbc_cleanup_cfb(struct drm_device *dev) +static void __intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->fbc.uncompressed_size == 0) return; @@ -657,34 +632,31 @@ static void __intel_fbc_cleanup_cfb(struct drm_device *dev) dev_priv->fbc.uncompressed_size = 0; } -void intel_fbc_cleanup_cfb(struct drm_device *dev) +void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); - __intel_fbc_cleanup_cfb(dev); + __intel_fbc_cleanup_cfb(dev_priv); mutex_unlock(&dev_priv->fbc.lock); } -static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) +static int intel_fbc_setup_cfb(struct drm_i915_private *dev_priv, int size, + int fb_cpp) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (size <= dev_priv->fbc.uncompressed_size) return 0; /* Release any current block */ - __intel_fbc_cleanup_cfb(dev); + __intel_fbc_cleanup_cfb(dev_priv); - return intel_fbc_alloc_cfb(dev, size, fb_cpp); + return intel_fbc_alloc_cfb(dev_priv, size, fb_cpp); } /** * __intel_fbc_update - enable/disable FBC as needed, unlocked - * @dev: the drm_device + * @dev_priv: i915 device instance * * Set up the framebuffer compression hardware at mode set time. We * enable it if possible: @@ -701,9 +673,8 @@ static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) * * We need to enable/disable FBC on a global basis. */ -static void __intel_fbc_update(struct drm_device *dev) +static void __intel_fbc_update(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = NULL; struct intel_crtc *intel_crtc; struct drm_framebuffer *fb; @@ -714,7 +685,7 @@ static void __intel_fbc_update(struct drm_device *dev) WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); /* disable framebuffer compression in vGPU */ - if (intel_vgpu_active(dev)) + if (intel_vgpu_active(dev_priv->dev)) i915.enable_fbc = 0; if (i915.enable_fbc < 0) { @@ -751,10 +722,10 @@ static void __intel_fbc_update(struct drm_device *dev) goto out_disable; } - if (INTEL_INFO(dev)->gen >= 8 || IS_HASWELL(dev)) { + if (INTEL_INFO(dev_priv)->gen >= 8 || IS_HASWELL(dev_priv)) { max_width = 4096; max_height = 4096; - } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) { max_width = 4096; max_height = 2048; } else { @@ -766,7 +737,7 @@ static void __intel_fbc_update(struct drm_device *dev) set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE); goto out_disable; } - if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) && + if ((INTEL_INFO(dev_priv)->gen < 4 || HAS_DDI(dev_priv)) && intel_crtc->plane != PLANE_A) { set_no_fbc_reason(dev_priv, FBC_BAD_PLANE); goto out_disable; @@ -780,7 +751,7 @@ static void __intel_fbc_update(struct drm_device *dev) set_no_fbc_reason(dev_priv, FBC_NOT_TILED); goto out_disable; } - if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && + if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_G4X(dev_priv) && crtc->primary->state->rotation != BIT(DRM_ROTATE_0)) { set_no_fbc_reason(dev_priv, FBC_ROTATION); goto out_disable; @@ -790,7 +761,7 @@ static void __intel_fbc_update(struct drm_device *dev) if (in_dbg_master()) goto out_disable; - if (intel_fbc_setup_cfb(dev, obj->base.size, + if (intel_fbc_setup_cfb(dev_priv, obj->base.size, drm_format_plane_cpp(fb->pixel_format, 0))) { set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL); goto out_disable; @@ -806,7 +777,7 @@ static void __intel_fbc_update(struct drm_device *dev) dev_priv->fbc.y == crtc->y) return; - if (intel_fbc_enabled(dev)) { + if (intel_fbc_enabled(dev_priv)) { /* We update FBC along two paths, after changing fb/crtc * configuration (modeswitching) and after page-flipping * finishes. For the latter, we know that not only did @@ -831,7 +802,7 @@ static void __intel_fbc_update(struct drm_device *dev) * some point. And we wait before enabling FBC anyway. */ DRM_DEBUG_KMS("disabling active FBC for update\n"); - __intel_fbc_disable(dev); + __intel_fbc_disable(dev_priv); } intel_fbc_enable(crtc); @@ -840,28 +811,26 @@ static void __intel_fbc_update(struct drm_device *dev) out_disable: /* Multiple disables should be harmless */ - if (intel_fbc_enabled(dev)) { + if (intel_fbc_enabled(dev_priv)) { DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); - __intel_fbc_disable(dev); + __intel_fbc_disable(dev_priv); } - __intel_fbc_cleanup_cfb(dev); + __intel_fbc_cleanup_cfb(dev_priv); } /* * intel_fbc_update - enable/disable FBC as needed - * @dev: the drm_device + * @dev_priv: i915 device instance * * This function reevaluates the overall state and enables or disables FBC. */ -void intel_fbc_update(struct drm_device *dev) +void intel_fbc_update(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); - __intel_fbc_update(dev); + __intel_fbc_update(dev_priv); mutex_unlock(&dev_priv->fbc.lock); } @@ -869,7 +838,6 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin) { - struct drm_device *dev = dev_priv->dev; unsigned int fbc_bits; if (!dev_priv->fbc.enable_fbc) @@ -891,7 +859,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, dev_priv->fbc.busy_bits |= (fbc_bits & frontbuffer_bits); if (dev_priv->fbc.busy_bits) - __intel_fbc_disable(dev); + __intel_fbc_disable(dev_priv); mutex_unlock(&dev_priv->fbc.lock); } @@ -899,8 +867,6 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits) { - struct drm_device *dev = dev_priv->dev; - if (!dev_priv->fbc.enable_fbc) return; @@ -912,7 +878,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, dev_priv->fbc.busy_bits &= ~frontbuffer_bits; if (!dev_priv->fbc.busy_bits) - __intel_fbc_update(dev); + __intel_fbc_update(dev_priv); out: mutex_unlock(&dev_priv->fbc.lock); @@ -965,5 +931,5 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); } - dev_priv->fbc.enabled = dev_priv->fbc.fbc_enabled(dev_priv->dev); + dev_priv->fbc.enabled = dev_priv->fbc.fbc_enabled(dev_priv); } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1efac89cb738..4e24d2b13e4c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2479,6 +2479,7 @@ static void ilk_wm_merge(struct drm_device *dev, const struct ilk_wm_maximums *max, struct intel_pipe_wm *merged) { + struct drm_i915_private *dev_priv = dev->dev_private; int level, max_level = ilk_wm_max_level(dev); int last_enabled_level = max_level; @@ -2519,7 +2520,8 @@ static void ilk_wm_merge(struct drm_device *dev, * What we should check here is whether FBC can be * enabled sometime later. */ - if (IS_GEN5(dev) && !merged->fbc_wm_enabled && intel_fbc_enabled(dev)) { + if (IS_GEN5(dev) && !merged->fbc_wm_enabled && + intel_fbc_enabled(dev_priv)) { for (level = 2; level <= max_level; level++) { struct intel_wm_level *wm = &merged->wm[level]; -- cgit v1.3-6-gb490 From 220285f2281515f4e8a9ec7892f7de40d857c290 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:05 -0300 Subject: drm/i915: use intel_crtc for the FBC functions This is all internal i915.ko work, let's start using intel_crtc for everything. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 +- drivers/gpu/drm/i915/intel_fbc.c | 79 +++++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7f75ff36245b..4ef1764aa8a5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -918,7 +918,7 @@ struct i915_fbc { struct intel_fbc_work { struct delayed_work work; - struct drm_crtc *crtc; + struct intel_crtc *crtc; struct drm_framebuffer *fb; } *fbc_work; @@ -938,7 +938,7 @@ struct i915_fbc { } no_fbc_reason; bool (*fbc_enabled)(struct drm_i915_private *dev_priv); - void (*enable_fbc)(struct drm_crtc *crtc); + void (*enable_fbc)(struct intel_crtc *crtc); void (*disable_fbc)(struct drm_i915_private *dev_priv); }; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 449dbe42569f..9ef5b6ca5db7 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -64,12 +64,11 @@ static void i8xx_fbc_disable(struct drm_i915_private *dev_priv) DRM_DEBUG_KMS("disabled FBC\n"); } -static void i8xx_fbc_enable(struct drm_crtc *crtc) +static void i8xx_fbc_enable(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = crtc->dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_framebuffer *fb = crtc->base.primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int cfb_pitch; int i; u32 fbc_ctl; @@ -96,9 +95,9 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) /* Set it up... */ fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; - fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane); + fbc_ctl2 |= FBC_CTL_PLANE(crtc->plane); I915_WRITE(FBC_CONTROL2, fbc_ctl2); - I915_WRITE(FBC_FENCE_OFF, crtc->y); + I915_WRITE(FBC_FENCE_OFF, crtc->base.y); } /* enable it... */ @@ -112,7 +111,7 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) I915_WRITE(FBC_CONTROL, fbc_ctl); DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n", - cfb_pitch, crtc->y, plane_name(intel_crtc->plane)); + cfb_pitch, crtc->base.y, plane_name(crtc->plane)); } static bool i8xx_fbc_enabled(struct drm_i915_private *dev_priv) @@ -120,29 +119,28 @@ static bool i8xx_fbc_enabled(struct drm_i915_private *dev_priv) return I915_READ(FBC_CONTROL) & FBC_CTL_EN; } -static void g4x_fbc_enable(struct drm_crtc *crtc) +static void g4x_fbc_enable(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = crtc->dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_framebuffer *fb = crtc->base.primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; dev_priv->fbc.enabled = true; - dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN; + dpfc_ctl = DPFC_CTL_PLANE(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); + I915_WRITE(DPFC_FENCE_YOFF, crtc->base.y); /* enable it... */ I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); - DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane)); } static void g4x_fbc_disable(struct drm_i915_private *dev_priv) @@ -172,18 +170,17 @@ static void intel_fbc_nuke(struct drm_i915_private *dev_priv) POSTING_READ(MSG_FBC_REND_STATE); } -static void ilk_fbc_enable(struct drm_crtc *crtc) +static void ilk_fbc_enable(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = crtc->dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_framebuffer *fb = crtc->base.primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; int threshold = dev_priv->fbc.threshold; dev_priv->fbc.enabled = true; - dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane); + dpfc_ctl = DPFC_CTL_PLANE(crtc->plane); if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) threshold++; @@ -203,7 +200,7 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) if (IS_GEN5(dev_priv)) dpfc_ctl |= obj->fence_reg; - I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); + I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->base.y); I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID); /* enable it... */ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); @@ -211,12 +208,12 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) if (IS_GEN6(dev_priv)) { I915_WRITE(SNB_DPFC_CTL_SA, SNB_CPU_FENCE_ENABLE | obj->fence_reg); - I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->base.y); } intel_fbc_nuke(dev_priv); - DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane)); } static void ilk_fbc_disable(struct drm_i915_private *dev_priv) @@ -240,12 +237,11 @@ static bool ilk_fbc_enabled(struct drm_i915_private *dev_priv) return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; } -static void gen7_fbc_enable(struct drm_crtc *crtc) +static void gen7_fbc_enable(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = crtc->dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_framebuffer *fb = crtc->base.primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; int threshold = dev_priv->fbc.threshold; @@ -253,7 +249,7 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) dpfc_ctl = 0; if (IS_IVYBRIDGE(dev_priv)) - dpfc_ctl |= IVB_DPFC_CTL_PLANE(intel_crtc->plane); + dpfc_ctl |= IVB_DPFC_CTL_PLANE(crtc->plane); if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) threshold++; @@ -285,18 +281,18 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) ILK_FBCQ_DIS); } else { /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ - I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe), - I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) | + I915_WRITE(CHICKEN_PIPESL_1(crtc->pipe), + I915_READ(CHICKEN_PIPESL_1(crtc->pipe)) | HSW_FBCQ_DIS); } I915_WRITE(SNB_DPFC_CTL_SA, SNB_CPU_FENCE_ENABLE | obj->fence_reg); - I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->base.y); intel_fbc_nuke(dev_priv); - DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane)); } /** @@ -317,19 +313,20 @@ static void intel_fbc_work_fn(struct work_struct *__work) struct intel_fbc_work *work = container_of(to_delayed_work(__work), struct intel_fbc_work, work); - struct drm_i915_private *dev_priv = work->crtc->dev->dev_private; + struct drm_i915_private *dev_priv = work->crtc->base.dev->dev_private; + struct drm_framebuffer *crtc_fb = work->crtc->base.primary->fb; mutex_lock(&dev_priv->fbc.lock); if (work == dev_priv->fbc.fbc_work) { /* Double check that we haven't switched fb without cancelling * the prior work. */ - if (work->crtc->primary->fb == work->fb) { + if (crtc_fb == work->fb) { dev_priv->fbc.enable_fbc(work->crtc); - dev_priv->fbc.crtc = to_intel_crtc(work->crtc); - dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id; - dev_priv->fbc.y = work->crtc->y; + dev_priv->fbc.crtc = work->crtc; + dev_priv->fbc.fb_id = crtc_fb->base.id; + dev_priv->fbc.y = work->crtc->base.y; } dev_priv->fbc.fbc_work = NULL; @@ -364,10 +361,10 @@ static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv) dev_priv->fbc.fbc_work = NULL; } -static void intel_fbc_enable(struct drm_crtc *crtc) +static void intel_fbc_enable(struct intel_crtc *crtc) { struct intel_fbc_work *work; - struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); @@ -381,7 +378,7 @@ static void intel_fbc_enable(struct drm_crtc *crtc) } work->crtc = crtc; - work->fb = crtc->primary->fb; + work->fb = crtc->base.primary->fb; INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn); dev_priv->fbc.fbc_work = work; @@ -805,7 +802,7 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) __intel_fbc_disable(dev_priv); } - intel_fbc_enable(crtc); + intel_fbc_enable(intel_crtc); dev_priv->fbc.no_fbc_reason = FBC_OK; return; @@ -852,7 +849,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, fbc_bits = INTEL_FRONTBUFFER_PRIMARY(dev_priv->fbc.crtc->pipe); else if (dev_priv->fbc.fbc_work) fbc_bits = INTEL_FRONTBUFFER_PRIMARY( - to_intel_crtc(dev_priv->fbc.fbc_work->crtc)->pipe); + dev_priv->fbc.fbc_work->crtc->pipe); else fbc_bits = dev_priv->fbc.possible_framebuffer_bits; -- cgit v1.3-6-gb490 From 8935108528194918966757fa00ac986176fe9497 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:06 -0300 Subject: drm/i915: add FBC_IN_DBG_MASTER no_fbc_reason The poor in_dbg_master() check was the only one without a reason string. Give it a reason string so it won't feel excluded. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_fbc.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4ef1764aa8a5..52d07fbd9cc8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -935,6 +935,7 @@ struct i915_fbc { FBC_MODULE_PARAM, FBC_CHIP_DEFAULT, /* disabled by default on this chip */ FBC_ROTATION, /* rotation is not supported */ + FBC_IN_DBG_MASTER, /* kernel debugger is active */ } no_fbc_reason; bool (*fbc_enabled)(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 9ef5b6ca5db7..8d39893b7550 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -471,6 +471,8 @@ const char *intel_no_fbc_reason_str(enum no_fbc_reason reason) return "disabled per chip default"; case FBC_ROTATION: return "rotation unsupported"; + case FBC_IN_DBG_MASTER: + return "Kernel debugger is active"; default: MISSING_CASE(reason); return "unknown reason"; @@ -755,8 +757,10 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) } /* If the kernel debugger is active, always disable compression */ - if (in_dbg_master()) + if (in_dbg_master()) { + set_no_fbc_reason(dev_priv, FBC_IN_DBG_MASTER); goto out_disable; + } if (intel_fbc_setup_cfb(dev_priv, obj->base.size, drm_format_plane_cpp(fb->pixel_format, 0))) { -- cgit v1.3-6-gb490 From 232fd934a4b458e5a0dacdd17efc1faffb9df615 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:07 -0300 Subject: drm/i915: extract FBC_MULTIPLE_PIPES check I have two separate refactor ideas that require extracting this to a separate function. I'm not sure which idea I'll end choosing, but since both will require extracting this function, let's do this now. Notice that this is just code moving. Any possible problems with the current multiple pipes check should be fixed in later commits. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 8d39893b7550..790edb3a2f39 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -493,24 +493,17 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) { struct drm_crtc *crtc = NULL, *tmp_crtc; enum pipe pipe; - bool pipe_a_only = false, one_pipe_only = false; + bool pipe_a_only = false; if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8) pipe_a_only = true; - else if (INTEL_INFO(dev_priv)->gen <= 4) - one_pipe_only = true; for_each_pipe(dev_priv, pipe) { tmp_crtc = dev_priv->pipe_to_crtc_mapping[pipe]; if (intel_crtc_active(tmp_crtc) && - to_intel_plane_state(tmp_crtc->primary->state)->visible) { - if (one_pipe_only && crtc) { - set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES); - return NULL; - } + to_intel_plane_state(tmp_crtc->primary->state)->visible) crtc = tmp_crtc; - } if (pipe_a_only) break; @@ -524,6 +517,26 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) return crtc; } +static bool multiple_pipes_ok(struct drm_i915_private *dev_priv) +{ + enum pipe pipe; + int n_pipes = 0; + struct drm_crtc *crtc; + + if (INTEL_INFO(dev_priv)->gen > 4) + return true; + + for_each_pipe(dev_priv, pipe) { + crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + + if (intel_crtc_active(crtc) && + to_intel_plane_state(crtc->primary->state)->visible) + n_pipes++; + } + + return (n_pipes < 2); +} + static int find_compression_threshold(struct drm_i915_private *dev_priv, struct drm_mm_node *node, int size, @@ -710,6 +723,11 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) if (!crtc) goto out_disable; + if (!multiple_pipes_ok(dev_priv)) { + set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES); + goto out_disable; + } + intel_crtc = to_intel_crtc(crtc); fb = crtc->primary->fb; obj = intel_fb_obj(fb); -- cgit v1.3-6-gb490 From 8df5dd57fd2f4e7f02793457a3bd61e5d4a644d5 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:08 -0300 Subject: drm/i915: move set_no_fbc_reason() call out of intel_fbc_find_crtc() So now all the calls are inside __intel_fbc_update(). Consistency! Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 790edb3a2f39..c271af767981 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -509,10 +509,8 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) break; } - if (!crtc || crtc->primary->fb == NULL) { - set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT); + if (!crtc || crtc->primary->fb == NULL) return NULL; - } return crtc; } @@ -720,8 +718,10 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) * - going to an unsupported config (interlace, pixel multiply, etc.) */ crtc = intel_fbc_find_crtc(dev_priv); - if (!crtc) + if (!crtc) { + set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT); goto out_disable; + } if (!multiple_pipes_ok(dev_priv)) { set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES); -- cgit v1.3-6-gb490 From 72010aca55264cfe6516a955066c846d3885b0c6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Mar 2015 10:22:20 +0000 Subject: pcmcia: sa11x0: fix missing clk_put() in sa11x0 socket drivers Fix the lack of clk_put() in sa11xx_base.c's error cleanup paths by converting the driver to the devm_* API. Fixes: 86d88bfca475 ("ARM: 8247/2: pcmcia: sa1100: make use of device clock") Signed-off-by: Russell King --- drivers/pcmcia/sa1100_generic.c | 1 - drivers/pcmcia/sa11xx_base.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 803945259da8..42861cc70158 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -93,7 +93,6 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev) for (i = 0; i < sinfo->nskt; i++) soc_pcmcia_remove_one(&sinfo->skt[i]); - clk_put(sinfo->clk); kfree(sinfo); return 0; } diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index cf6de2c2b329..553d70a67f80 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -222,7 +222,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int i, ret = 0; struct clk *clk; - clk = clk_get(dev, NULL); + clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) return PTR_ERR(clk); @@ -251,7 +251,6 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, if (ret) { while (--i >= 0) soc_pcmcia_remove_one(&sinfo->skt[i]); - clk_put(clk); kfree(sinfo); } else { dev_set_drvdata(dev, sinfo); -- cgit v1.3-6-gb490 From e33e640ad0b76151534a2b9387b98eb02d6ddda7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Mar 2015 10:33:16 +0000 Subject: pcmcia: sa11x0: convert memory allocation to devm_* API Convert the sa11x0 socket driver memory allocation to use devm_kzalloc() to simplify the cleanup path. Signed-off-by: Russell King --- drivers/pcmcia/sa1100_generic.c | 1 - drivers/pcmcia/sa11xx_base.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 42861cc70158..66acdc85727c 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -93,7 +93,6 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev) for (i = 0; i < sinfo->nskt; i++) soc_pcmcia_remove_one(&sinfo->skt[i]); - kfree(sinfo); return 0; } diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index 553d70a67f80..6e6336d47d4a 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -228,7 +228,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, sa11xx_drv_pcmcia_ops(ops); - sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); + sinfo = devm_kzalloc(dev, SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); if (!sinfo) return -ENOMEM; @@ -251,7 +251,6 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, if (ret) { while (--i >= 0) soc_pcmcia_remove_one(&sinfo->skt[i]); - kfree(sinfo); } else { dev_set_drvdata(dev, sinfo); } -- cgit v1.3-6-gb490 From af4739c281621017a8a84dd6ba3471bba2dd6c6a Mon Sep 17 00:00:00 2001 From: Gabriele Mazzotta Date: Tue, 7 Jul 2015 21:58:02 +0200 Subject: HID: i2c-hid: Call device suspend callback before disabling irq i2c-hid takes care of requesting and handling IRQs for HID devices which in turns might expect them to be always active when working in normal conditions. Hence, disabling IRQs before calling the suspend callbacks can potentially cause problems since device drivers might try to perform operations needing them. Fix this by disabling IRQs only after the suspend callbacks had been executed. Signed-off-by: Gabriele Mazzotta Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index f77469d4edfb..9ed69b5121f7 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -1092,13 +1092,13 @@ static int i2c_hid_suspend(struct device *dev) struct hid_device *hid = ihid->hid; int ret = 0; + if (hid->driver && hid->driver->suspend) + ret = hid->driver->suspend(hid, PMSG_SUSPEND); + disable_irq(ihid->irq); if (device_may_wakeup(&client->dev)) enable_irq_wake(ihid->irq); - if (hid->driver && hid->driver->suspend) - ret = hid->driver->suspend(hid, PMSG_SUSPEND); - /* Save some power */ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); -- cgit v1.3-6-gb490 From aaf5ec2e51ab1d9c5e962b4728a1107ed3ff7a3e Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Wed, 8 Jul 2015 17:07:47 +0530 Subject: drm/i915: Handle HPD when it has actually occurred MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Writing to PCH_PORT_HOTPLUG for each interrupt is not required. Handle it only if hpd has actually occurred like we handle other interrupts. v2: Make few variables local to if block (Ville) v3: Add check for ibx/cpt both (Ville). While at it, remove the redundant check for hotplug_trigger from pch_get_hpd_pins v4: Indentation (Ville) Reviewed-by: Ville Syrjälä Signed-off-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a6fbe6443d63..a897f68485c2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1266,9 +1266,6 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, *pin_mask = 0; *long_mask = 0; - if (!hotplug_trigger) - return; - for_each_hpd_pin(i) { if ((hpd[i] & hotplug_trigger) == 0) continue; @@ -1658,14 +1655,17 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) struct drm_i915_private *dev_priv = dev->dev_private; int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; - u32 dig_hotplug_reg; - u32 pin_mask, long_mask; - dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); - I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); + if (hotplug_trigger) { + u32 dig_hotplug_reg, pin_mask, long_mask; - pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd_ibx); - intel_hpd_irq_handler(dev, pin_mask, long_mask); + dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); + I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); + + pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + dig_hotplug_reg, hpd_ibx); + intel_hpd_irq_handler(dev, pin_mask, long_mask); + } if (pch_iir & SDE_AUDIO_POWER_MASK) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> @@ -1757,14 +1757,16 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) struct drm_i915_private *dev_priv = dev->dev_private; int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; - u32 dig_hotplug_reg; - u32 pin_mask, long_mask; - dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); - I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); + if (hotplug_trigger) { + u32 dig_hotplug_reg, pin_mask, long_mask; - pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd_cpt); - intel_hpd_irq_handler(dev, pin_mask, long_mask); + dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); + I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); + pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + dig_hotplug_reg, hpd_cpt); + intel_hpd_irq_handler(dev, pin_mask, long_mask); + } if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> -- cgit v1.3-6-gb490 From 83b8a982b101c48fc025066a7b08beaf6fa756f0 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Wed, 8 Jul 2015 10:27:05 +0100 Subject: drm/i915: Update wa_ctx_emit() macro as per kernel coding guidelines wa_ctx_emit() depends on the name of a local variable; if the name of that variable is changed then we get compile errors. In this case it is unlikely to be changed as this macro is only used in this set of functions but Kernel coding guidelines doesn't recommend doing this. It was my mistake as I should have corrected it at the beginning but missed so correct this before there are more usages of this macro (Bob Beckett). https://www.kernel.org/doc/Documentation/CodingStyle, Chapter 12, "Things to avoid when using macros", point 2): " 2) macros that depend on having a local variable with a magic name: #define FOO(val) bar(index, val) might look like a good thing, but it's confusing as hell when one reads the code and it's prone to breakage from seemingly innocent changes. " v2: Optimization to avoid multiple evaluation of 'index' in the macro. Since we invoke it multiple times, compiler, if it can, should be able to coalesce them into a single condition and remove multiple WARN_ON checks (Chris). Suggested-by: Robert Beckett Cc: Robert Beckett Cc: Chris Wilson Cc: Imre Deak Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 79 ++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 4c47a64a974f..971d7b0ae017 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1065,12 +1065,13 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) return 0; } -#define wa_ctx_emit(batch, cmd) \ +#define wa_ctx_emit(batch, index, cmd) \ do { \ - if (WARN_ON(index >= (PAGE_SIZE / sizeof(uint32_t)))) { \ + int __index = (index)++; \ + if (WARN_ON(__index >= (PAGE_SIZE / sizeof(uint32_t)))) { \ return -ENOSPC; \ } \ - batch[index++] = (cmd); \ + batch[__index] = (cmd); \ } while (0) @@ -1096,29 +1097,29 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring, { uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); - wa_ctx_emit(batch, (MI_STORE_REGISTER_MEM_GEN8(1) | - MI_SRM_LRM_GLOBAL_GTT)); - wa_ctx_emit(batch, GEN8_L3SQCREG4); - wa_ctx_emit(batch, ring->scratch.gtt_offset + 256); - wa_ctx_emit(batch, 0); - - wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); - wa_ctx_emit(batch, GEN8_L3SQCREG4); - wa_ctx_emit(batch, l3sqc4_flush); - - wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); - wa_ctx_emit(batch, (PIPE_CONTROL_CS_STALL | - PIPE_CONTROL_DC_FLUSH_ENABLE)); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - - wa_ctx_emit(batch, (MI_LOAD_REGISTER_MEM_GEN8(1) | - MI_SRM_LRM_GLOBAL_GTT)); - wa_ctx_emit(batch, GEN8_L3SQCREG4); - wa_ctx_emit(batch, ring->scratch.gtt_offset + 256); - wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8(1) | + MI_SRM_LRM_GLOBAL_GTT)); + wa_ctx_emit(batch, index, GEN8_L3SQCREG4); + wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256); + wa_ctx_emit(batch, index, 0); + + wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1)); + wa_ctx_emit(batch, index, GEN8_L3SQCREG4); + wa_ctx_emit(batch, index, l3sqc4_flush); + + wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6)); + wa_ctx_emit(batch, index, (PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_DC_FLUSH_ENABLE)); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); + + wa_ctx_emit(batch, index, (MI_LOAD_REGISTER_MEM_GEN8(1) | + MI_SRM_LRM_GLOBAL_GTT)); + wa_ctx_emit(batch, index, GEN8_L3SQCREG4); + wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256); + wa_ctx_emit(batch, index, 0); return index; } @@ -1179,7 +1180,7 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); /* WaDisableCtxRestoreArbitration:bdw,chv */ - wa_ctx_emit(batch, MI_ARB_ON_OFF | MI_ARB_DISABLE); + wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE); /* WaFlushCoherentL3CacheLinesAtContextSwitch:bdw */ if (IS_BROADWELL(ring->dev)) { @@ -1192,19 +1193,19 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, /* Actual scratch location is at 128 bytes offset */ scratch_addr = ring->scratch.gtt_offset + 2*CACHELINE_BYTES; - wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); - wa_ctx_emit(batch, (PIPE_CONTROL_FLUSH_L3 | - PIPE_CONTROL_GLOBAL_GTT_IVB | - PIPE_CONTROL_CS_STALL | - PIPE_CONTROL_QW_WRITE)); - wa_ctx_emit(batch, scratch_addr); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6)); + wa_ctx_emit(batch, index, (PIPE_CONTROL_FLUSH_L3 | + PIPE_CONTROL_GLOBAL_GTT_IVB | + PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_QW_WRITE)); + wa_ctx_emit(batch, index, scratch_addr); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) - wa_ctx_emit(batch, MI_NOOP); + wa_ctx_emit(batch, index, MI_NOOP); /* * MI_BATCH_BUFFER_END is not required in Indirect ctx BB because @@ -1240,9 +1241,9 @@ static int gen8_init_perctx_bb(struct intel_engine_cs *ring, uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); /* WaDisableCtxRestoreArbitration:bdw,chv */ - wa_ctx_emit(batch, MI_ARB_ON_OFF | MI_ARB_ENABLE); + wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE); - wa_ctx_emit(batch, MI_BATCH_BUFFER_END); + wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END); return wa_ctx_end(wa_ctx, *offset = index, 1); } -- cgit v1.3-6-gb490 From de152b627eb3018de91ec5c5a50b38e17d80a88b Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 7 Jul 2015 16:28:51 -0700 Subject: drm/i915: Add origin to frontbuffer tracking flush This will be useful to PSR and FBC once we start making dirty fb calls to also flush frontbuffer. Cc: Daniel Vetter Cc: Paulo Zanoni Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 12 ++++++------ drivers/gpu/drm/i915/intel_drv.h | 8 ++++---- drivers/gpu/drm/i915/intel_frontbuffer.c | 12 +++++++----- 3 files changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 82c05b80b7ef..aaabf3c259d5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -375,7 +375,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj, i915_gem_chipset_flush(dev); out: - intel_fb_obj_flush(obj, false); + intel_fb_obj_flush(obj, false, ORIGIN_CPU); return ret; } @@ -839,7 +839,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, } out_flush: - intel_fb_obj_flush(obj, false); + intel_fb_obj_flush(obj, false, ORIGIN_GTT); out_unpin: i915_gem_object_ggtt_unpin(obj); out: @@ -1032,7 +1032,7 @@ out: if (needs_clflush_after) i915_gem_chipset_flush(dev); - intel_fb_obj_flush(obj, false); + intel_fb_obj_flush(obj, false, ORIGIN_CPU); return ret; } @@ -2375,7 +2375,7 @@ i915_gem_object_retire__write(struct drm_i915_gem_object *obj) RQ_BUG_ON(!(obj->active & intel_ring_flag(obj->last_write_req->ring))); i915_gem_request_assign(&obj->last_write_req, NULL); - intel_fb_obj_flush(obj, true); + intel_fb_obj_flush(obj, true, ORIGIN_CS); } static void @@ -3905,7 +3905,7 @@ i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj) old_write_domain = obj->base.write_domain; obj->base.write_domain = 0; - intel_fb_obj_flush(obj, false); + intel_fb_obj_flush(obj, false, ORIGIN_GTT); trace_i915_gem_object_change_domain(obj, obj->base.read_domains, @@ -3927,7 +3927,7 @@ i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj) old_write_domain = obj->base.write_domain; obj->base.write_domain = 0; - intel_fb_obj_flush(obj, false); + intel_fb_obj_flush(obj, false, ORIGIN_CPU); trace_i915_gem_object_change_domain(obj, obj->base.read_domains, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 082d0e7dfb14..beeb4d326cbe 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -978,16 +978,16 @@ void intel_frontbuffer_flip_prepare(struct drm_device *dev, void intel_frontbuffer_flip_complete(struct drm_device *dev, unsigned frontbuffer_bits); void intel_frontbuffer_flush(struct drm_device *dev, - unsigned frontbuffer_bits); + unsigned frontbuffer_bits, + enum fb_op_origin origin); void intel_frontbuffer_flip(struct drm_device *dev, unsigned frontbuffer_bits); - unsigned int intel_fb_align_height(struct drm_device *dev, unsigned int height, uint32_t pixel_format, uint64_t fb_format_modifier); -void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire); - +void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire, + enum fb_op_origin origin); u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier, uint32_t pixel_format); diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 6e90e2b0293d..cb5a6f0447e7 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -105,6 +105,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, * intel_frontbuffer_flush - flush frontbuffer * @dev: DRM device * @frontbuffer_bits: frontbuffer plane tracking bits + * @origin: which operation caused the flush * * This function gets called every time rendering on the given planes has * completed and frontbuffer caching can be started again. Flushes will get @@ -113,7 +114,8 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, * Can be called without any locks held. */ void intel_frontbuffer_flush(struct drm_device *dev, - unsigned frontbuffer_bits) + unsigned frontbuffer_bits, + enum fb_op_origin origin) { struct drm_i915_private *dev_priv = to_i915(dev); @@ -140,7 +142,7 @@ void intel_frontbuffer_flush(struct drm_device *dev, * then any delayed flushes will be unblocked. */ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, - bool retire) + bool retire, enum fb_op_origin origin) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); @@ -162,7 +164,7 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, mutex_unlock(&dev_priv->fb_tracking.lock); } - intel_frontbuffer_flush(dev, frontbuffer_bits); + intel_frontbuffer_flush(dev, frontbuffer_bits, origin); } /** @@ -212,7 +214,7 @@ void intel_frontbuffer_flip_complete(struct drm_device *dev, dev_priv->fb_tracking.flip_bits &= ~frontbuffer_bits; mutex_unlock(&dev_priv->fb_tracking.lock); - intel_frontbuffer_flush(dev, frontbuffer_bits); + intel_frontbuffer_flush(dev, frontbuffer_bits, ORIGIN_FLIP); } /** @@ -237,5 +239,5 @@ void intel_frontbuffer_flip(struct drm_device *dev, dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits; mutex_unlock(&dev_priv->fb_tracking.lock); - intel_frontbuffer_flush(dev, frontbuffer_bits); + intel_frontbuffer_flush(dev, frontbuffer_bits, ORIGIN_FLIP); } -- cgit v1.3-6-gb490 From f089d4d20fcbcf16a62ef3b4b57f41ecf59a5d83 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 7 Jul 2015 15:28:12 +0100 Subject: mfd: wm5110: Add registers for custom write sequence triggers This register will be needed as part of some additional support for the headphone path on wm5110, so this patch adds the register and sets up its regmap config. Signed-off-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/mfd/wm5110-tables.c | 2 ++ include/linux/mfd/arizona/registers.h | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 12cad94b4035..62a4aa13cb98 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -676,6 +676,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */ { 0x00000040, 0x0000 }, /* R64 - Wake control */ { 0x00000041, 0x0000 }, /* R65 - Sequence control */ + { 0x00000042, 0x0000 }, /* R66 - Spare Triggers */ { 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */ { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */ { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */ @@ -1716,6 +1717,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_PWM_DRIVE_3: case ARIZONA_WAKE_CONTROL: case ARIZONA_SEQUENCE_CONTROL: + case ARIZONA_SPARE_TRIGGERS: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3: diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 3499d36e6067..11affb3c2768 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -39,6 +39,7 @@ #define ARIZONA_PWM_DRIVE_3 0x32 #define ARIZONA_WAKE_CONTROL 0x40 #define ARIZONA_SEQUENCE_CONTROL 0x41 +#define ARIZONA_SPARE_TRIGGERS 0x42 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1 0x61 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2 0x62 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3 0x63 @@ -1430,6 +1431,42 @@ #define ARIZONA_WSEQ_ENA_JD2_RISE_SHIFT 0 /* WSEQ_ENA_JD2_RISE */ #define ARIZONA_WSEQ_ENA_JD2_RISE_WIDTH 1 /* WSEQ_ENA_JD2_RISE */ +/* + * R66 (0x42) - Spare Triggers + */ +#define ARIZONA_WS_TRG8 0x0080 /* WS_TRG8 */ +#define ARIZONA_WS_TRG8_MASK 0x0080 /* WS_TRG8 */ +#define ARIZONA_WS_TRG8_SHIFT 7 /* WS_TRG8 */ +#define ARIZONA_WS_TRG8_WIDTH 1 /* WS_TRG8 */ +#define ARIZONA_WS_TRG7 0x0040 /* WS_TRG7 */ +#define ARIZONA_WS_TRG7_MASK 0x0040 /* WS_TRG7 */ +#define ARIZONA_WS_TRG7_SHIFT 6 /* WS_TRG7 */ +#define ARIZONA_WS_TRG7_WIDTH 1 /* WS_TRG7 */ +#define ARIZONA_WS_TRG6 0x0020 /* WS_TRG6 */ +#define ARIZONA_WS_TRG6_MASK 0x0020 /* WS_TRG6 */ +#define ARIZONA_WS_TRG6_SHIFT 5 /* WS_TRG6 */ +#define ARIZONA_WS_TRG6_WIDTH 1 /* WS_TRG6 */ +#define ARIZONA_WS_TRG5 0x0010 /* WS_TRG5 */ +#define ARIZONA_WS_TRG5_MASK 0x0010 /* WS_TRG5 */ +#define ARIZONA_WS_TRG5_SHIFT 4 /* WS_TRG5 */ +#define ARIZONA_WS_TRG5_WIDTH 1 /* WS_TRG5 */ +#define ARIZONA_WS_TRG4 0x0008 /* WS_TRG4 */ +#define ARIZONA_WS_TRG4_MASK 0x0008 /* WS_TRG4 */ +#define ARIZONA_WS_TRG4_SHIFT 3 /* WS_TRG4 */ +#define ARIZONA_WS_TRG4_WIDTH 1 /* WS_TRG4 */ +#define ARIZONA_WS_TRG3 0x0004 /* WS_TRG3 */ +#define ARIZONA_WS_TRG3_MASK 0x0004 /* WS_TRG3 */ +#define ARIZONA_WS_TRG3_SHIFT 2 /* WS_TRG3 */ +#define ARIZONA_WS_TRG3_WIDTH 1 /* WS_TRG3 */ +#define ARIZONA_WS_TRG2 0x0002 /* WS_TRG2 */ +#define ARIZONA_WS_TRG2_MASK 0x0002 /* WS_TRG2 */ +#define ARIZONA_WS_TRG2_SHIFT 1 /* WS_TRG2 */ +#define ARIZONA_WS_TRG2_WIDTH 1 /* WS_TRG2 */ +#define ARIZONA_WS_TRG1 0x0001 /* WS_TRG1 */ +#define ARIZONA_WS_TRG1_MASK 0x0001 /* WS_TRG1 */ +#define ARIZONA_WS_TRG1_SHIFT 0 /* WS_TRG1 */ +#define ARIZONA_WS_TRG1_WIDTH 1 /* WS_TRG1 */ + /* * R97 (0x61) - Sample Rate Sequence Select 1 */ -- cgit v1.3-6-gb490 From 81207880cef207cd89db863f9aa1d65f22b4f2a2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 7 Jul 2015 15:28:13 +0100 Subject: mfd: wm5110: Add register patch for rev E and above Add a register patch for rev E and above that configures the location of some write sequences to assist with the headphone enables. Signed-off-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/mfd/wm5110-tables.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 62a4aa13cb98..e08924261fef 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -249,6 +249,16 @@ static const struct reg_default wm5110_revd_patch[] = { { 0x80, 0x0 }, }; +/* Add extra headphone write sequence locations */ +static const struct reg_default wm5110_reve_patch[] = { + { 0x80, 0x3 }, + { 0x80, 0x3 }, + { 0x4b, 0x138 }, + { 0x4c, 0x13d }, + { 0x80, 0x0 }, + { 0x80, 0x0 }, +}; + /* We use a function so we can use ARRAY_SIZE() */ int wm5110_patch(struct arizona *arizona) { @@ -266,7 +276,9 @@ int wm5110_patch(struct arizona *arizona) wm5110_revd_patch, ARRAY_SIZE(wm5110_revd_patch)); default: - return 0; + return regmap_register_patch(arizona->regmap, + wm5110_reve_patch, + ARRAY_SIZE(wm5110_reve_patch)); } } EXPORT_SYMBOL_GPL(wm5110_patch); -- cgit v1.3-6-gb490 From 0a6d4245691173eb953c440b8c6fc0b1688e6b25 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 2 Jul 2015 13:24:44 +0200 Subject: mlx4: TCP/UDP packets have L4 hash Mellanox driver has the knowledge if rxhash is a L4 hash, if it receives a non fragmented TCP or UDP frame and NETIF_F_RXCSUM is enabled on netdev. ip_summed value is CHECKSUM_UNNECESSARY in this case. Signed-off-by: Eric Dumazet Cc: Amir Vadai Cc: Ido Shamay Acked-by: Ido Shamay Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 7a4f20bb7fcb..12c65e1ad6a9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -917,7 +917,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud if (dev->features & NETIF_F_RXHASH) skb_set_hash(gro_skb, be32_to_cpu(cqe->immed_rss_invalid), - PKT_HASH_TYPE_L3); + (ip_summed == CHECKSUM_UNNECESSARY) ? + PKT_HASH_TYPE_L4 : + PKT_HASH_TYPE_L3); skb_record_rx_queue(gro_skb, cq->ring); skb_mark_napi_id(gro_skb, &cq->napi); @@ -963,7 +965,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud if (dev->features & NETIF_F_RXHASH) skb_set_hash(skb, be32_to_cpu(cqe->immed_rss_invalid), - PKT_HASH_TYPE_L3); + (ip_summed == CHECKSUM_UNNECESSARY) ? + PKT_HASH_TYPE_L4 : + PKT_HASH_TYPE_L3); if ((be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_VLAN_PRESENT_MASK) && -- cgit v1.3-6-gb490 From 6ab13b27699e5a71cca20d301c3c424653bd0841 Mon Sep 17 00:00:00 2001 From: "Li, Liang Z" Date: Mon, 6 Jul 2015 08:42:56 +0800 Subject: xen-netback: remove duplicated function definition There are two duplicated xenvif_zerocopy_callback() definitions. Remove one of them. Signed-off-by: Liang Li Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 8a495b318b6f..c6cb85a85c89 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -325,9 +325,6 @@ static inline pending_ring_idx_t nr_pending_reqs(struct xenvif_queue *queue) queue->pending_prod + queue->pending_cons; } -/* Callback from stack when TX packet can be released */ -void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success); - irqreturn_t xenvif_interrupt(int irq, void *dev_id); extern bool separate_tx_rx_irq; -- cgit v1.3-6-gb490 From 7baaa9092dedad5f670a7b1716b2ce9e1175ba02 Mon Sep 17 00:00:00 2001 From: Punnaiah Choudary Kalluri Date: Mon, 6 Jul 2015 10:02:53 +0530 Subject: net: macb: Add SG support for Zynq SOC family Enable SG support for Zynq SOC family devices. Signed-off-by: Punnaiah Choudary Kalluri Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index caeb39561567..a4e3f8655cb8 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2741,8 +2741,7 @@ static const struct macb_config emac_config = { static const struct macb_config zynqmp_config = { - .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE | - MACB_CAPS_JUMBO, + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, @@ -2750,8 +2749,7 @@ static const struct macb_config zynqmp_config = { }; static const struct macb_config zynq_config = { - .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE | - MACB_CAPS_NO_GIGABIT_HALF, + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_NO_GIGABIT_HALF, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, -- cgit v1.3-6-gb490 From 0beb44b0653978c0f180f902fb93a1b0b61833b8 Mon Sep 17 00:00:00 2001 From: Carol Soto Date: Mon, 6 Jul 2015 09:20:19 -0500 Subject: net/mlx4_core: Add extra check for total vfs for SRIOV Add extra check for total vfs for SRIOV to check if that value is bigger than total vfs in pci SRIOV capabalities. Fix a check and print of the number of maximum vfs that hw can handle. Fix a check and print of the number of maximum vfs per port that driver can handle. Signed-off-by: Carol L Soto Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 12fbfcb44d8a..d76f4257e305 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2907,6 +2907,8 @@ static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev, { u64 dev_flags = dev->flags; int err = 0; + int fw_enabled_sriov_vfs = min(pci_sriov_get_totalvfs(pdev), + MLX4_MAX_NUM_VF); if (reset_flow) { dev->dev_vfs = kcalloc(total_vfs, sizeof(*dev->dev_vfs), @@ -2932,6 +2934,12 @@ static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev, } if (!(dev->flags & MLX4_FLAG_SRIOV)) { + if (total_vfs > fw_enabled_sriov_vfs) { + mlx4_err(dev, "requested vfs (%d) > available vfs (%d). Continuing without SR_IOV\n", + total_vfs, fw_enabled_sriov_vfs); + err = -ENOMEM; + goto disable_sriov; + } mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", total_vfs); err = pci_enable_sriov(pdev, total_vfs); } @@ -3413,20 +3421,20 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data, goto err_disable_pdev; } } - if (total_vfs >= MLX4_MAX_NUM_VF) { + if (total_vfs > MLX4_MAX_NUM_VF) { dev_err(&pdev->dev, - "Requested more VF's (%d) than allowed (%d)\n", - total_vfs, MLX4_MAX_NUM_VF - 1); + "Requested more VF's (%d) than allowed by hw (%d)\n", + total_vfs, MLX4_MAX_NUM_VF); err = -EINVAL; goto err_disable_pdev; } for (i = 0; i < MLX4_MAX_PORTS; i++) { - if (nvfs[i] + nvfs[2] >= MLX4_MAX_NUM_VF_P_PORT) { + if (nvfs[i] + nvfs[2] > MLX4_MAX_NUM_VF_P_PORT) { dev_err(&pdev->dev, - "Requested more VF's (%d) for port (%d) than allowed (%d)\n", + "Requested more VF's (%d) for port (%d) than allowed by driver (%d)\n", nvfs[i] + nvfs[2], i + 1, - MLX4_MAX_NUM_VF_P_PORT - 1); + MLX4_MAX_NUM_VF_P_PORT); err = -EINVAL; goto err_disable_pdev; } -- cgit v1.3-6-gb490 From 81aa507981bd785da84ac8bbed942495257dcaa3 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 6 Jul 2015 22:38:34 +0530 Subject: cxgb4: Add PCI device ids for few more T5 and T6 adapters Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h index d7ca106927b0..8353a6cbfcc2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h @@ -142,6 +142,8 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN CH_PCI_ID_TABLE_FENTRY(0x5013), /* T580-chr */ CH_PCI_ID_TABLE_FENTRY(0x5014), /* T580-so */ CH_PCI_ID_TABLE_FENTRY(0x5015), /* T502-bt */ + CH_PCI_ID_TABLE_FENTRY(0x5016), /* T580-OCP-SO */ + CH_PCI_ID_TABLE_FENTRY(0x5017), /* T520-OCP-SO */ CH_PCI_ID_TABLE_FENTRY(0x5080), /* Custom T540-cr */ CH_PCI_ID_TABLE_FENTRY(0x5081), /* Custom T540-LL-cr */ CH_PCI_ID_TABLE_FENTRY(0x5082), /* Custom T504-cr */ @@ -155,6 +157,22 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN CH_PCI_ID_TABLE_FENTRY(0x5090), /* Custom T540-CR */ CH_PCI_ID_TABLE_FENTRY(0x5091), /* Custom T522-CR */ CH_PCI_ID_TABLE_FENTRY(0x5092), /* Custom T520-CR */ + + /* T6 adapters: + */ + CH_PCI_ID_TABLE_FENTRY(0x6001), + CH_PCI_ID_TABLE_FENTRY(0x6002), + CH_PCI_ID_TABLE_FENTRY(0x6003), + CH_PCI_ID_TABLE_FENTRY(0x6004), + CH_PCI_ID_TABLE_FENTRY(0x6005), + CH_PCI_ID_TABLE_FENTRY(0x6006), + CH_PCI_ID_TABLE_FENTRY(0x6007), + CH_PCI_ID_TABLE_FENTRY(0x6009), + CH_PCI_ID_TABLE_FENTRY(0x600d), + CH_PCI_ID_TABLE_FENTRY(0x6010), + CH_PCI_ID_TABLE_FENTRY(0x6011), + CH_PCI_ID_TABLE_FENTRY(0x6014), + CH_PCI_ID_TABLE_FENTRY(0x6015), CH_PCI_DEVICE_ID_TABLE_DEFINE_END; #endif /* __T4_PCI_ID_TBL_H__ */ -- cgit v1.3-6-gb490 From 9e29e21a9bbfb2204bab875f0ef6dbaed66592e7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jul 2015 22:05:28 +0200 Subject: ifb: add multiqueue operation Add multiqueue capabilities to ifb netdevice. This removes last bottleneck for ingress when mq qdisc can be used to shard load from multiple RX queues on physical device. Tested: # netem based setup, installed at receiver side ETH=eth0 IFB=ifb10 EST="est 1sec 4sec" # Optional rate estimator RTT_HALF=2ms #REORDER=20us #LOSS="loss 1" TXQ=8 ip link add ifb10 numtxqueues $TXQ type ifb ip link set dev $IFB up tc qdisc add dev $ETH ingress 2>/dev/null tc filter add dev $ETH parent ffff: \ protocol ip u32 match u32 0 0 flowid 1:1 \ action mirred egress redirect dev $IFB tc qdisc del dev $IFB root 2>/dev/null tc qdisc add dev $IFB root handle 1: mq for i in `seq 1 $TXQ` do slot=$( printf %x $(( i )) ) tc qd add dev $IFB parent 1:$slot $EST netem \ limit 100000 delay $RTT_HALF $REORDER $LOSS done lpaa24:~# tc -s -d qd sh dev ifb10 qdisc mq 1: root Sent 316544766 bytes 5265927 pkt (dropped 0, overlimits 0 requeues 0) backlog 98880b 1648p requeues 0 qdisc netem 8002: parent 1:1 limit 100000 delay 2.0ms Sent 39601416 bytes 658721 pkt (dropped 0, overlimits 0 requeues 0) rate 38235Kbit 79657pps backlog 12240b 204p requeues 0 qdisc netem 8003: parent 1:2 limit 100000 delay 2.0ms Sent 39472866 bytes 657227 pkt (dropped 0, overlimits 0 requeues 0) rate 38234Kbit 79655pps backlog 10620b 176p requeues 0 qdisc netem 8004: parent 1:3 limit 100000 delay 2.0ms Sent 39703417 bytes 659699 pkt (dropped 0, overlimits 0 requeues 0) rate 38320Kbit 79831pps backlog 12780b 213p requeues 0 qdisc netem 8005: parent 1:4 limit 100000 delay 2.0ms Sent 39565149 bytes 658011 pkt (dropped 0, overlimits 0 requeues 0) rate 38174Kbit 79530pps backlog 11880b 198p requeues 0 qdisc netem 8006: parent 1:5 limit 100000 delay 2.0ms Sent 39506078 bytes 657354 pkt (dropped 0, overlimits 0 requeues 0) rate 38195Kbit 79571pps backlog 12480b 208p requeues 0 qdisc netem 8007: parent 1:6 limit 100000 delay 2.0ms Sent 39675994 bytes 658849 pkt (dropped 0, overlimits 0 requeues 0) rate 38323Kbit 79838pps backlog 12600b 210p requeues 0 qdisc netem 8008: parent 1:7 limit 100000 delay 2.0ms Sent 39532042 bytes 658367 pkt (dropped 0, overlimits 0 requeues 0) rate 38177Kbit 79536pps backlog 13140b 219p requeues 0 qdisc netem 8009: parent 1:8 limit 100000 delay 2.0ms Sent 39488164 bytes 657705 pkt (dropped 0, overlimits 0 requeues 0) rate 38192Kbit 79568pps backlog 13Kb 222p requeues 0 Signed-off-by: Eric Dumazet Cc: Alexei Starovoitov Cc: Jamal Hadi Salim Cc: John Fastabend Acked-by: Alexei Starovoitov Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- drivers/net/ifb.c | 207 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 120 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 94570aace241..cc56fac3c3f8 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -38,69 +38,68 @@ #include #define TX_Q_LIMIT 32 -struct ifb_private { +struct ifb_q_private { + struct net_device *dev; struct tasklet_struct ifb_tasklet; - int tasklet_pending; - - struct u64_stats_sync rsync; + int tasklet_pending; + int txqnum; struct sk_buff_head rq; - u64 rx_packets; - u64 rx_bytes; + u64 rx_packets; + u64 rx_bytes; + struct u64_stats_sync rsync; struct u64_stats_sync tsync; + u64 tx_packets; + u64 tx_bytes; struct sk_buff_head tq; - u64 tx_packets; - u64 tx_bytes; -}; +} ____cacheline_aligned_in_smp; -static int numifbs = 2; +struct ifb_dev_private { + struct ifb_q_private *tx_private; +}; -static void ri_tasklet(unsigned long dev); static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev); static int ifb_open(struct net_device *dev); static int ifb_close(struct net_device *dev); -static void ri_tasklet(unsigned long dev) +static void ifb_ri_tasklet(unsigned long _txp) { - struct net_device *_dev = (struct net_device *)dev; - struct ifb_private *dp = netdev_priv(_dev); + struct ifb_q_private *txp = (struct ifb_q_private *)_txp; struct netdev_queue *txq; struct sk_buff *skb; - txq = netdev_get_tx_queue(_dev, 0); - if ((skb = skb_peek(&dp->tq)) == NULL) { - if (__netif_tx_trylock(txq)) { - skb_queue_splice_tail_init(&dp->rq, &dp->tq); - __netif_tx_unlock(txq); - } else { - /* reschedule */ + txq = netdev_get_tx_queue(txp->dev, txp->txqnum); + skb = skb_peek(&txp->tq); + if (!skb) { + if (!__netif_tx_trylock(txq)) goto resched; - } + skb_queue_splice_tail_init(&txp->rq, &txp->tq); + __netif_tx_unlock(txq); } - while ((skb = __skb_dequeue(&dp->tq)) != NULL) { + while ((skb = __skb_dequeue(&txp->tq)) != NULL) { u32 from = G_TC_FROM(skb->tc_verd); skb->tc_verd = 0; skb->tc_verd = SET_TC_NCLS(skb->tc_verd); - u64_stats_update_begin(&dp->tsync); - dp->tx_packets++; - dp->tx_bytes += skb->len; - u64_stats_update_end(&dp->tsync); + u64_stats_update_begin(&txp->tsync); + txp->tx_packets++; + txp->tx_bytes += skb->len; + u64_stats_update_end(&txp->tsync); rcu_read_lock(); - skb->dev = dev_get_by_index_rcu(dev_net(_dev), skb->skb_iif); + skb->dev = dev_get_by_index_rcu(dev_net(txp->dev), skb->skb_iif); if (!skb->dev) { rcu_read_unlock(); dev_kfree_skb(skb); - _dev->stats.tx_dropped++; - if (skb_queue_len(&dp->tq) != 0) + txp->dev->stats.tx_dropped++; + if (skb_queue_len(&txp->tq) != 0) goto resched; break; } rcu_read_unlock(); - skb->skb_iif = _dev->ifindex; + skb->skb_iif = txp->dev->ifindex; if (from & AT_EGRESS) { dev_queue_xmit(skb); @@ -112,10 +111,11 @@ static void ri_tasklet(unsigned long dev) } if (__netif_tx_trylock(txq)) { - if ((skb = skb_peek(&dp->rq)) == NULL) { - dp->tasklet_pending = 0; - if (netif_queue_stopped(_dev)) - netif_wake_queue(_dev); + skb = skb_peek(&txp->rq); + if (!skb) { + txp->tasklet_pending = 0; + if (netif_tx_queue_stopped(txq)) + netif_tx_wake_queue(txq); } else { __netif_tx_unlock(txq); goto resched; @@ -123,8 +123,8 @@ static void ri_tasklet(unsigned long dev) __netif_tx_unlock(txq); } else { resched: - dp->tasklet_pending = 1; - tasklet_schedule(&dp->ifb_tasklet); + txp->tasklet_pending = 1; + tasklet_schedule(&txp->ifb_tasklet); } } @@ -132,29 +132,58 @@ resched: static struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { - struct ifb_private *dp = netdev_priv(dev); + struct ifb_dev_private *dp = netdev_priv(dev); + struct ifb_q_private *txp = dp->tx_private; unsigned int start; - - do { - 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_irq(&dp->rsync, start)); - - do { - 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_irq(&dp->tsync, start)); - + u64 packets, bytes; + int i; + + for (i = 0; i < dev->num_tx_queues; i++,txp++) { + do { + start = u64_stats_fetch_begin_irq(&txp->rsync); + packets = txp->rx_packets; + bytes = txp->rx_bytes; + } while (u64_stats_fetch_retry_irq(&txp->rsync, start)); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + + do { + start = u64_stats_fetch_begin_irq(&txp->tsync); + packets = txp->tx_packets; + bytes = txp->tx_bytes; + } while (u64_stats_fetch_retry_irq(&txp->tsync, start)); + stats->tx_packets += packets; + stats->tx_bytes += bytes; + } stats->rx_dropped = dev->stats.rx_dropped; stats->tx_dropped = dev->stats.tx_dropped; return stats; } +static int ifb_dev_init(struct net_device *dev) +{ + struct ifb_dev_private *dp = netdev_priv(dev); + struct ifb_q_private *txp; + int i; + + txp = kcalloc(dev->num_tx_queues, sizeof(*txp), GFP_KERNEL); + if (!txp) + return -ENOMEM; + dp->tx_private = txp; + for (i = 0; i < dev->num_tx_queues; i++,txp++) { + txp->txqnum = i; + txp->dev = dev; + __skb_queue_head_init(&txp->rq); + __skb_queue_head_init(&txp->tq); + u64_stats_init(&txp->rsync); + u64_stats_init(&txp->tsync); + tasklet_init(&txp->ifb_tasklet, ifb_ri_tasklet, + (unsigned long)txp); + netif_tx_start_queue(netdev_get_tx_queue(dev, i)); + } + return 0; +} static const struct net_device_ops ifb_netdev_ops = { .ndo_open = ifb_open, @@ -162,6 +191,7 @@ static const struct net_device_ops ifb_netdev_ops = { .ndo_get_stats64 = ifb_stats64, .ndo_start_xmit = ifb_xmit, .ndo_validate_addr = eth_validate_addr, + .ndo_init = ifb_dev_init, }; #define IFB_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_FRAGLIST | \ @@ -169,10 +199,24 @@ static const struct net_device_ops ifb_netdev_ops = { NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_CTAG_TX | \ NETIF_F_HW_VLAN_STAG_TX) +static void ifb_dev_free(struct net_device *dev) +{ + struct ifb_dev_private *dp = netdev_priv(dev); + struct ifb_q_private *txp = dp->tx_private; + int i; + + for (i = 0; i < dev->num_tx_queues; i++,txp++) { + tasklet_kill(&txp->ifb_tasklet); + __skb_queue_purge(&txp->rq); + __skb_queue_purge(&txp->tq); + } + kfree(dp->tx_private); + free_netdev(dev); +} + static void ifb_setup(struct net_device *dev) { /* Initialize the device structure. */ - dev->destructor = free_netdev; dev->netdev_ops = &ifb_netdev_ops; /* Fill in device structure with ethernet-generic values. */ @@ -188,17 +232,19 @@ static void ifb_setup(struct net_device *dev) dev->priv_flags &= ~IFF_TX_SKB_SHARING; netif_keep_dst(dev); eth_hw_addr_random(dev); + dev->destructor = ifb_dev_free; } static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ifb_private *dp = netdev_priv(dev); + struct ifb_dev_private *dp = netdev_priv(dev); u32 from = G_TC_FROM(skb->tc_verd); + struct ifb_q_private *txp = dp->tx_private + skb_get_queue_mapping(skb); - u64_stats_update_begin(&dp->rsync); - dp->rx_packets++; - dp->rx_bytes += skb->len; - u64_stats_update_end(&dp->rsync); + u64_stats_update_begin(&txp->rsync); + txp->rx_packets++; + txp->rx_bytes += skb->len; + u64_stats_update_end(&txp->rsync); if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->skb_iif) { dev_kfree_skb(skb); @@ -206,14 +252,13 @@ static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) { - netif_stop_queue(dev); - } + if (skb_queue_len(&txp->rq) >= dev->tx_queue_len) + netif_tx_stop_queue(netdev_get_tx_queue(dev, txp->txqnum)); - __skb_queue_tail(&dp->rq, skb); - if (!dp->tasklet_pending) { - dp->tasklet_pending = 1; - tasklet_schedule(&dp->ifb_tasklet); + __skb_queue_tail(&txp->rq, skb); + if (!txp->tasklet_pending) { + txp->tasklet_pending = 1; + tasklet_schedule(&txp->ifb_tasklet); } return NETDEV_TX_OK; @@ -221,24 +266,13 @@ static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) static int ifb_close(struct net_device *dev) { - struct ifb_private *dp = netdev_priv(dev); - - tasklet_kill(&dp->ifb_tasklet); - netif_stop_queue(dev); - __skb_queue_purge(&dp->rq); - __skb_queue_purge(&dp->tq); + netif_tx_stop_all_queues(dev); return 0; } static int ifb_open(struct net_device *dev) { - struct ifb_private *dp = netdev_priv(dev); - - tasklet_init(&dp->ifb_tasklet, ri_tasklet, (unsigned long)dev); - __skb_queue_head_init(&dp->rq); - __skb_queue_head_init(&dp->tq); - netif_start_queue(dev); - + netif_tx_start_all_queues(dev); return 0; } @@ -255,31 +289,30 @@ static int ifb_validate(struct nlattr *tb[], struct nlattr *data[]) static struct rtnl_link_ops ifb_link_ops __read_mostly = { .kind = "ifb", - .priv_size = sizeof(struct ifb_private), + .priv_size = sizeof(struct ifb_dev_private), .setup = ifb_setup, .validate = ifb_validate, }; -/* Number of ifb devices to be set up by this module. */ +/* Number of ifb devices to be set up by this module. + * Note that these legacy devices have one queue. + * Prefer something like : ip link add ifb10 numtxqueues 8 type ifb + */ +static int numifbs = 2; module_param(numifbs, int, 0); MODULE_PARM_DESC(numifbs, "Number of ifb devices"); static int __init ifb_init_one(int index) { struct net_device *dev_ifb; - struct ifb_private *dp; int err; - dev_ifb = alloc_netdev(sizeof(struct ifb_private), "ifb%d", + dev_ifb = alloc_netdev(sizeof(struct ifb_dev_private), "ifb%d", NET_NAME_UNKNOWN, ifb_setup); if (!dev_ifb) return -ENOMEM; - dp = netdev_priv(dev_ifb); - u64_stats_init(&dp->rsync); - u64_stats_init(&dp->tsync); - dev_ifb->rtnl_link_ops = &ifb_link_ops; err = register_netdevice(dev_ifb); if (err < 0) -- cgit v1.3-6-gb490 From f9cbce34c34bcc05ea0dd78c8999bfe88b5b6b86 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 6 Jul 2015 14:11:37 -0700 Subject: hv_netvsc: Add support to set MTU reservation from guest side When packet encapsulation is in use, the MTU needs to be reduced for headroom reservation. The existing code takes the updated MTU value only from the host side. But vSwitch extensions, such as Open vSwitch, require the flexibility to change the MTU to different values from within a guest during the lifecycle of a vNIC, when the encapsulation protocol is changed. The patch supports this kind of MTU changes. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 1 + drivers/net/hyperv/netvsc_drv.c | 3 +-- drivers/net/hyperv/rndis_filter.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index dd4544085db3..26cd14ccf4d5 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -589,6 +589,7 @@ struct nvsp_message { #define NETVSC_MTU 65536 +#define NETVSC_MTU_MIN 68 #define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ #define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */ diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 358475ed9b59..b855ba9a507d 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -743,8 +743,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2) limit = NETVSC_MTU - ETH_HLEN; - /* Hyper-V hosts don't support MTU < ETH_DATA_LEN (1500) */ - if (mtu < ETH_DATA_LEN || mtu > limit) + if (mtu < NETVSC_MTU_MIN || mtu > limit) return -EINVAL; nvdev->start_remove = true; diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 236aeb76ef22..2e40417a8087 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1054,7 +1054,7 @@ int rndis_filter_device_add(struct hv_device *dev, ret = rndis_filter_query_device(rndis_device, RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE, &mtu, &size); - if (ret == 0 && size == sizeof(u32)) + if (ret == 0 && size == sizeof(u32) && mtu < net_device->ndev->mtu) net_device->ndev->mtu = mtu; /* Get the mac address */ -- cgit v1.3-6-gb490 From b11b6ed0f97f900f5c4bba9b3abcd2d2dab73ca7 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Tue, 7 Jul 2015 12:32:54 +0530 Subject: net: ec_bhf: Use module_pci_driver Use module_pci_driver for drivers whose init and exit functions only register and unregister, respectively. A simplified version of the Coccinelle semantic patch that performs this transformation is as follows: @a@ identifier f, x; @@ -static f(...) { return pci_register_driver(&x); } @b depends on a@ identifier e, a.x; @@ -static e(...) { pci_unregister_driver(&x); } @c depends on a && b@ identifier a.f; declarer name module_init; @@ -module_init(f); @d depends on a && b && c@ identifier b.e, a.x; declarer name module_exit; declarer name module_pci_driver; @@ -module_exit(e); +module_pci_driver(x); Signed-off-by: Vaishali Thakkar Signed-off-by: David S. Miller --- drivers/net/ethernet/ec_bhf.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ec_bhf.c b/drivers/net/ethernet/ec_bhf.c index d1017509b08a..f7b42483921c 100644 --- a/drivers/net/ethernet/ec_bhf.c +++ b/drivers/net/ethernet/ec_bhf.c @@ -604,19 +604,7 @@ static struct pci_driver pci_driver = { .probe = ec_bhf_probe, .remove = ec_bhf_remove, }; - -static int __init ec_bhf_init(void) -{ - return pci_register_driver(&pci_driver); -} - -static void __exit ec_bhf_exit(void) -{ - pci_unregister_driver(&pci_driver); -} - -module_init(ec_bhf_init); -module_exit(ec_bhf_exit); +module_pci_driver(pci_driver); module_param(polling_frequency, long, S_IRUGO); MODULE_PARM_DESC(polling_frequency, "Polling timer frequency in ns"); -- cgit v1.3-6-gb490 From 5be9ed8d49754c22fffd8ddd9cb751d591f31a08 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 7 Jul 2015 21:49:18 +0530 Subject: cxgb4: Don't use entire L2T table, use only its slice The driver was retrieving the parameters for the bounds of its slice of the L2T from the firmware and then throwing those away and using the entire table. This corrects that problem. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/l2t.c | 94 ++++++++++++++----------- drivers/net/ethernet/chelsio/cxgb4/l2t.h | 18 ++++- drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 1 - 4 files changed, 71 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 351f3b1bf800..d582e175dfb6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4757,7 +4757,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) */ cfg_queues(adapter); - adapter->l2t = t4_init_l2t(); + adapter->l2t = t4_init_l2t(adapter->l2t_start, adapter->l2t_end); if (!adapter->l2t) { /* We tolerate a lack of L2T, giving up some functionality */ dev_warn(&pdev->dev, "could not allocate L2T, continuing\n"); diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 252efc29321f..ac27898c6ab0 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -51,24 +51,17 @@ #define VLAN_NONE 0xfff /* identifies sync vs async L2T_WRITE_REQs */ -#define F_SYNC_WR (1 << 12) - -enum { - L2T_STATE_VALID, /* entry is up to date */ - L2T_STATE_STALE, /* entry may be used but needs revalidation */ - L2T_STATE_RESOLVING, /* entry needs address resolution */ - L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */ - - /* when state is one of the below the entry is not hashed */ - L2T_STATE_SWITCHING, /* entry is being used by a switching filter */ - L2T_STATE_UNUSED /* entry not in use */ -}; +#define SYNC_WR_S 12 +#define SYNC_WR_V(x) ((x) << SYNC_WR_S) +#define SYNC_WR_F SYNC_WR_V(1) struct l2t_data { + unsigned int l2t_start; /* start index of our piece of the L2T */ + unsigned int l2t_size; /* number of entries in l2tab */ rwlock_t lock; atomic_t nfree; /* number of free entries */ struct l2t_entry *rover; /* starting point for next allocation */ - struct l2t_entry l2tab[L2T_SIZE]; + struct l2t_entry l2tab[0]; /* MUST BE LAST */ }; static inline unsigned int vlan_prio(const struct l2t_entry *e) @@ -85,29 +78,36 @@ static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e) /* * To avoid having to check address families we do not allow v4 and v6 * neighbors to be on the same hash chain. We keep v4 entries in the first - * half of available hash buckets and v6 in the second. + * half of available hash buckets and v6 in the second. We need at least two + * entries in our L2T for this scheme to work. */ enum { - L2T_SZ_HALF = L2T_SIZE / 2, - L2T_HASH_MASK = L2T_SZ_HALF - 1 + L2T_MIN_HASH_BUCKETS = 2, }; -static inline unsigned int arp_hash(const u32 *key, int ifindex) +static inline unsigned int arp_hash(struct l2t_data *d, const u32 *key, + int ifindex) { - return jhash_2words(*key, ifindex, 0) & L2T_HASH_MASK; + unsigned int l2t_size_half = d->l2t_size / 2; + + return jhash_2words(*key, ifindex, 0) % l2t_size_half; } -static inline unsigned int ipv6_hash(const u32 *key, int ifindex) +static inline unsigned int ipv6_hash(struct l2t_data *d, const u32 *key, + int ifindex) { + unsigned int l2t_size_half = d->l2t_size / 2; u32 xor = key[0] ^ key[1] ^ key[2] ^ key[3]; - return L2T_SZ_HALF + (jhash_2words(xor, ifindex, 0) & L2T_HASH_MASK); + return (l2t_size_half + + (jhash_2words(xor, ifindex, 0) % l2t_size_half)); } -static unsigned int addr_hash(const u32 *addr, int addr_len, int ifindex) +static unsigned int addr_hash(struct l2t_data *d, const u32 *addr, + int addr_len, int ifindex) { - return addr_len == 4 ? arp_hash(addr, ifindex) : - ipv6_hash(addr, ifindex); + return addr_len == 4 ? arp_hash(d, addr, ifindex) : + ipv6_hash(d, addr, ifindex); } /* @@ -139,6 +139,8 @@ static void neigh_replace(struct l2t_entry *e, struct neighbour *n) */ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) { + struct l2t_data *d = adap->l2t; + unsigned int l2t_idx = e->idx + d->l2t_start; struct sk_buff *skb; struct cpl_l2t_write_req *req; @@ -150,10 +152,10 @@ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) INIT_TP_WR(req, 0); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, - e->idx | (sync ? F_SYNC_WR : 0) | + l2t_idx | (sync ? SYNC_WR_F : 0) | TID_QID_V(adap->sge.fw_evtq.abs_id))); req->params = htons(L2T_W_PORT_V(e->lport) | L2T_W_NOREPLY_V(!sync)); - req->l2t_idx = htons(e->idx); + req->l2t_idx = htons(l2t_idx); req->vlan = htons(e->vlan); if (e->neigh && !(e->neigh->dev->flags & IFF_LOOPBACK)) memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); @@ -190,18 +192,19 @@ static void send_pending(struct adapter *adap, struct l2t_entry *e) */ void do_l2t_write_rpl(struct adapter *adap, const struct cpl_l2t_write_rpl *rpl) { + struct l2t_data *d = adap->l2t; unsigned int tid = GET_TID(rpl); - unsigned int idx = tid & (L2T_SIZE - 1); + unsigned int l2t_idx = tid % L2T_SIZE; if (unlikely(rpl->status != CPL_ERR_NONE)) { dev_err(adap->pdev_dev, "Unexpected L2T_WRITE_RPL status %u for entry %u\n", - rpl->status, idx); + rpl->status, l2t_idx); return; } - if (tid & F_SYNC_WR) { - struct l2t_entry *e = &adap->l2t->l2tab[idx]; + if (tid & SYNC_WR_F) { + struct l2t_entry *e = &d->l2tab[l2t_idx - d->l2t_start]; spin_lock(&e->lock); if (e->state != L2T_STATE_SWITCHING) { @@ -276,7 +279,7 @@ static struct l2t_entry *alloc_l2e(struct l2t_data *d) return NULL; /* there's definitely a free entry */ - for (e = d->rover, end = &d->l2tab[L2T_SIZE]; e != end; ++e) + for (e = d->rover, end = &d->l2tab[d->l2t_size]; e != end; ++e) if (atomic_read(&e->refcnt) == 0) goto found; @@ -368,7 +371,7 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, int addr_len = neigh->tbl->key_len; u32 *addr = (u32 *)neigh->primary_key; int ifidx = neigh->dev->ifindex; - int hash = addr_hash(addr, addr_len, ifidx); + int hash = addr_hash(d, addr, addr_len, ifidx); if (neigh->dev->flags & IFF_LOOPBACK) lport = netdev2pinfo(physdev)->tx_chan + 4; @@ -481,7 +484,7 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh) int addr_len = neigh->tbl->key_len; u32 *addr = (u32 *) neigh->primary_key; int ifidx = neigh->dev->ifindex; - int hash = addr_hash(addr, addr_len, ifidx); + int hash = addr_hash(d, addr, addr_len, ifidx); read_lock_bh(&d->lock); for (e = d->l2tab[hash].first; e; e = e->next) @@ -554,20 +557,30 @@ int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan, return write_l2e(adap, e, 0); } -struct l2t_data *t4_init_l2t(void) +struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end) { + unsigned int l2t_size; int i; struct l2t_data *d; - d = t4_alloc_mem(sizeof(*d)); + if (l2t_start >= l2t_end || l2t_end >= L2T_SIZE) + return NULL; + l2t_size = l2t_end - l2t_start + 1; + if (l2t_size < L2T_MIN_HASH_BUCKETS) + return NULL; + + d = t4_alloc_mem(sizeof(*d) + l2t_size * sizeof(struct l2t_entry)); if (!d) return NULL; + d->l2t_start = l2t_start; + d->l2t_size = l2t_size; + d->rover = d->l2tab; - atomic_set(&d->nfree, L2T_SIZE); + atomic_set(&d->nfree, l2t_size); rwlock_init(&d->lock); - for (i = 0; i < L2T_SIZE; ++i) { + for (i = 0; i < d->l2t_size; ++i) { d->l2tab[i].idx = i; d->l2tab[i].state = L2T_STATE_UNUSED; spin_lock_init(&d->l2tab[i].lock); @@ -578,9 +591,9 @@ struct l2t_data *t4_init_l2t(void) static inline void *l2t_get_idx(struct seq_file *seq, loff_t pos) { - struct l2t_entry *l2tab = seq->private; + struct l2t_data *d = seq->private; - return pos >= L2T_SIZE ? NULL : &l2tab[pos]; + return pos >= d->l2t_size ? NULL : &d->l2tab[pos]; } static void *l2t_seq_start(struct seq_file *seq, loff_t *pos) @@ -620,6 +633,7 @@ static int l2t_seq_show(struct seq_file *seq, void *v) "Ethernet address VLAN/P LP State Users Port\n"); else { char ip[60]; + struct l2t_data *d = seq->private; struct l2t_entry *e = v; spin_lock_bh(&e->lock); @@ -628,7 +642,7 @@ static int l2t_seq_show(struct seq_file *seq, void *v) else sprintf(ip, e->v6 ? "%pI6c" : "%pI4", e->addr); seq_printf(seq, "%4u %-25s %17pM %4d %u %2u %c %5u %s\n", - e->idx, ip, e->dmac, + e->idx + d->l2t_start, ip, e->dmac, e->vlan & VLAN_VID_MASK, vlan_prio(e), e->lport, l2e_state(e), atomic_read(&e->refcnt), e->neigh ? e->neigh->dev->name : ""); @@ -652,7 +666,7 @@ static int l2t_seq_open(struct inode *inode, struct file *file) struct adapter *adap = inode->i_private; struct seq_file *seq = file->private_data; - seq->private = adap->l2t->l2tab; + seq->private = adap->l2t; } return rc; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.h b/drivers/net/ethernet/chelsio/cxgb4/l2t.h index a30126ce90cb..b38dc526aad5 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.h +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.h @@ -39,6 +39,20 @@ #include #include +enum { L2T_SIZE = 4096 }; /* # of L2T entries */ + +enum { + L2T_STATE_VALID, /* entry is up to date */ + L2T_STATE_STALE, /* entry may be used but needs revalidation */ + L2T_STATE_RESOLVING, /* entry needs address resolution */ + L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */ + L2T_STATE_NOARP, /* Netdev down or removed*/ + + /* when state is one of the below the entry is not hashed */ + L2T_STATE_SWITCHING, /* entry is being used by a switching filter */ + L2T_STATE_UNUSED /* entry not in use */ +}; + struct adapter; struct l2t_data; struct neighbour; @@ -56,7 +70,7 @@ struct cpl_l2t_write_rpl; */ struct l2t_entry { u16 state; /* entry state */ - u16 idx; /* entry index */ + u16 idx; /* entry index within in-memory table */ u32 addr[4]; /* next hop IP or IPv6 address */ int ifindex; /* neighbor's net_device's ifindex */ struct neighbour *neigh; /* associated neighbour */ @@ -104,7 +118,7 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh); struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *d); int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan, u8 port, u8 *eth_addr); -struct l2t_data *t4_init_l2t(void); +struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end); void do_l2t_write_rpl(struct adapter *p, const struct cpl_l2t_write_rpl *rpl); extern const struct file_operations t4_l2t_fops; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index c8488f430d19..640369df8b3a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -47,7 +47,6 @@ enum { TCB_SIZE = 128, /* TCB size */ NMTUS = 16, /* size of MTU table */ NCCTRL_WIN = 32, /* # of congestion control windows */ - L2T_SIZE = 4096, /* # of L2T entries */ PM_NSTATS = 5, /* # of PM stats */ MBOX_LEN = 64, /* mailbox size in bytes */ TRACE_LEN = 112, /* length of trace data and mask */ -- cgit v1.3-6-gb490 From 5b4e83e133c7e610fdb6063f64bd404fc0836fe0 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 7 Jul 2015 21:49:19 +0530 Subject: cxgb4: Update register ranges for T6 adapter Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 2b52aae7ec86..ba2be1e93ec3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -1345,9 +1345,9 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0x5a80, 0x5a9c, 0x5b94, 0x5bfc, 0x5c10, 0x5ec0, - 0x5ec8, 0x5ec8, + 0x5ec8, 0x5ecc, 0x6000, 0x6040, - 0x6058, 0x6154, + 0x6058, 0x615c, 0x7700, 0x7798, 0x77c0, 0x7880, 0x78cc, 0x78fc, @@ -1371,20 +1371,22 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0x9f00, 0x9f6c, 0x9f80, 0xa020, 0xd004, 0xd03c, + 0xd100, 0xd118, + 0xd200, 0xd31c, 0xdfc0, 0xdfe0, 0xe000, 0xf008, 0x11000, 0x11014, 0x11048, 0x11110, 0x11118, 0x1117c, - 0x11190, 0x11260, + 0x11190, 0x11264, 0x11300, 0x1130c, - 0x12000, 0x1205c, + 0x12000, 0x1206c, 0x19040, 0x1906c, 0x19078, 0x19080, 0x1908c, 0x19124, 0x19150, 0x191b0, 0x191d0, 0x191e8, - 0x19238, 0x192b8, + 0x19238, 0x192bc, 0x193f8, 0x19474, 0x19490, 0x194cc, 0x194f0, 0x194f8, @@ -1466,7 +1468,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0x30200, 0x30318, 0x30400, 0x3052c, 0x30540, 0x3061c, - 0x30800, 0x3088c, + 0x30800, 0x30890, 0x308c0, 0x30908, 0x30910, 0x309b8, 0x30a00, 0x30a04, @@ -1544,7 +1546,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0x34200, 0x34318, 0x34400, 0x3452c, 0x34540, 0x3461c, - 0x34800, 0x3488c, + 0x34800, 0x34890, 0x348c0, 0x34908, 0x34910, 0x349b8, 0x34a00, 0x34a04, -- cgit v1.3-6-gb490 From df459ebc33324e6e2932b0236a7e1a53a14182b2 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 7 Jul 2015 21:49:20 +0530 Subject: cxgb4: Read stats for only available channels Updating the driver to read the stats of only available channels. T6 and later has only 2 channels Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 73 +++++++++++------------------- 1 file changed, 26 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index ba2be1e93ec3..1e6597dc8736 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3926,43 +3926,25 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, */ void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st) { - /* T6 and later has 2 channels */ - if (adap->params.arch.nchan == NCHAN) { - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->mac_in_errs, 12, TP_MIB_MAC_IN_ERR_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tnl_cong_drops, 8, - TP_MIB_TNL_CNG_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tnl_tx_drops, 4, - TP_MIB_TNL_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->ofld_vlan_drops, 4, - TP_MIB_OFD_VLN_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tcp6_in_errs, 4, - TP_MIB_TCP_V6IN_ERR_0_A); - } else { - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->mac_in_errs, 2, TP_MIB_MAC_IN_ERR_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->hdr_in_errs, 2, TP_MIB_HDR_IN_ERR_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tcp_in_errs, 2, TP_MIB_TCP_IN_ERR_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tnl_cong_drops, 2, - TP_MIB_TNL_CNG_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->ofld_chan_drops, 2, - TP_MIB_OFD_CHN_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tnl_tx_drops, 2, TP_MIB_TNL_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->ofld_vlan_drops, 2, - TP_MIB_OFD_VLN_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tcp6_in_errs, 2, TP_MIB_TCP_V6IN_ERR_0_A); - } + int nchan = adap->params.arch.nchan; + + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->mac_in_errs, nchan, TP_MIB_MAC_IN_ERR_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->hdr_in_errs, nchan, TP_MIB_HDR_IN_ERR_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->tcp_in_errs, nchan, TP_MIB_TCP_IN_ERR_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->tnl_cong_drops, nchan, TP_MIB_TNL_CNG_DROP_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->ofld_chan_drops, nchan, TP_MIB_OFD_CHN_DROP_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->tnl_tx_drops, nchan, TP_MIB_TNL_DROP_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->ofld_vlan_drops, nchan, TP_MIB_OFD_VLN_DROP_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->tcp6_in_errs, nchan, TP_MIB_TCP_V6IN_ERR_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, &st->ofld_no_neigh, 2, TP_MIB_OFD_ARP_DROP_A); } @@ -3976,16 +3958,13 @@ void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st) */ void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st) { - /* T6 and later has 2 channels */ - if (adap->params.arch.nchan == NCHAN) { - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req, - 8, TP_MIB_CPL_IN_REQ_0_A); - } else { - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req, - 2, TP_MIB_CPL_IN_REQ_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->rsp, - 2, TP_MIB_CPL_OUT_RSP_0_A); - } + int nchan = adap->params.arch.nchan; + + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req, + nchan, TP_MIB_CPL_IN_REQ_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->rsp, + nchan, TP_MIB_CPL_OUT_RSP_0_A); + } /** -- cgit v1.3-6-gb490 From b7660642b77b6aa7fae6c0f832d0290af331bd7e Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 7 Jul 2015 21:49:21 +0530 Subject: cxgb4: Enable cim_la dump to support T6 Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 54 ++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index a11485fbb33f..b135d05c9984 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -151,6 +151,45 @@ static int cim_la_show_3in1(struct seq_file *seq, void *v, int idx) return 0; } +static int cim_la_show_t6(struct seq_file *seq, void *v, int idx) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "Status Inst Data PC LS0Stat " + "LS0Addr LS0Data LS1Stat LS1Addr LS1Data\n"); + } else { + const u32 *p = v; + + seq_printf(seq, " %02x %04x%04x %04x%04x %04x%04x %08x %08x %08x %08x %08x %08x\n", + (p[9] >> 16) & 0xff, /* Status */ + p[9] & 0xffff, p[8] >> 16, /* Inst */ + p[8] & 0xffff, p[7] >> 16, /* Data */ + p[7] & 0xffff, p[6] >> 16, /* PC */ + p[2], p[1], p[0], /* LS0 Stat, Addr and Data */ + p[5], p[4], p[3]); /* LS1 Stat, Addr and Data */ + } + return 0; +} + +static int cim_la_show_pc_t6(struct seq_file *seq, void *v, int idx) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "Status Inst Data PC\n"); + } else { + const u32 *p = v; + + seq_printf(seq, " %02x %08x %08x %08x\n", + p[3] & 0xff, p[2], p[1], p[0]); + seq_printf(seq, " %02x %02x%06x %02x%06x %02x%06x\n", + (p[6] >> 8) & 0xff, p[6] & 0xff, p[5] >> 8, + p[5] & 0xff, p[4] >> 8, p[4] & 0xff, p[3] >> 8); + seq_printf(seq, " %02x %04x%04x %04x%04x %04x%04x\n", + (p[9] >> 16) & 0xff, p[9] & 0xffff, p[8] >> 16, + p[8] & 0xffff, p[7] >> 16, p[7] & 0xffff, + p[6] >> 16); + } + return 0; +} + static int cim_la_open(struct inode *inode, struct file *file) { int ret; @@ -162,9 +201,18 @@ static int cim_la_open(struct inode *inode, struct file *file) if (ret) return ret; - p = seq_open_tab(file, adap->params.cim_la_size / 8, 8 * sizeof(u32), 1, - cfg & UPDBGLACAPTPCONLY_F ? - cim_la_show_3in1 : cim_la_show); + if (is_t6(adap->params.chip)) { + /* +1 to account for integer division of CIMLA_SIZE/10 */ + p = seq_open_tab(file, (adap->params.cim_la_size / 10) + 1, + 10 * sizeof(u32), 1, + cfg & UPDBGLACAPTPCONLY_F ? + cim_la_show_pc_t6 : cim_la_show_t6); + } else { + p = seq_open_tab(file, adap->params.cim_la_size / 8, + 8 * sizeof(u32), 1, + cfg & UPDBGLACAPTPCONLY_F ? cim_la_show_3in1 : + cim_la_show); + } if (!p) return -ENOMEM; -- cgit v1.3-6-gb490 From f5bbc91c88c18a4c518f066cc4e784d7b5fb9735 Mon Sep 17 00:00:00 2001 From: Anda-Maria Nicolae Date: Tue, 7 Jul 2015 15:25:53 +0300 Subject: power_supply: rt9455_charger: Properly notify userspace about charging events Charging events this patch refers to are: - charger is connected to/disconnected from the power source - battery is reconnected to the charger, after it was absent. When the charger is connected to/disconnected from the power source, CHRVPI interrupt occurs and PWR_RDY bit is either set or cleared. PWR_RDY bit is updated after 1-2 seconds CHRVPI interrupt has occurred. power_supply_changed() should be called after PWR_RDY bit is updated. /sys/class/power_supply/rt9455-charger/online file displays the value of PWR_RDY bit. This way, if the userspace is notified that a charging event has occurred and the userspace reads /sys/class/power_supply/rt9455-charger/online file, this file is properly updated when the userspace reads it. This is the reason why power_supply_changed() is called in rt9455_pwr_rdy_work_callback(), instead of being called in interrupt handler. Since no interrupt is triggered when the battery is reconnected to the charger, the userspace is never notified that the battery is reconnected. This is why power_supply_changed() is called in rt9455_max_charging_time_work_callback(), so that the userspace is notified that the battery is reconnected. Signed-off-by: Anda-Maria Nicolae Reviewed-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/rt9455_charger.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/rt9455_charger.c b/drivers/power/rt9455_charger.c index 08baac6e3ada..a49a9d44bdda 100644 --- a/drivers/power/rt9455_charger.c +++ b/drivers/power/rt9455_charger.c @@ -973,7 +973,6 @@ static int rt9455_irq_handler_check_irq2_register(struct rt9455_info *info, if (irq2 & GET_MASK(F_CHRVPI)) { dev_dbg(dev, "Charger fault occurred\n"); - alert_userspace = true; /* * CHRVPI bit is set in 2 cases: * 1. when the power source is connected to the charger. @@ -981,6 +980,9 @@ static int rt9455_irq_handler_check_irq2_register(struct rt9455_info *info, * To identify the case, PWR_RDY bit is checked. Because * PWR_RDY bit is set / cleared after CHRVPI interrupt is * triggered, it is used delayed_work to later read PWR_RDY bit. + * Also, do not set to true alert_userspace, because there is no + * need to notify userspace when CHRVPI interrupt has occurred. + * Userspace will be notified after PWR_RDY bit is read. */ queue_delayed_work(system_power_efficient_wq, &info->pwr_rdy_work, @@ -1178,7 +1180,7 @@ static irqreturn_t rt9455_irq_handler_thread(int irq, void *data) /* * Sometimes, an interrupt occurs while rt9455_probe() function * is executing and power_supply_register() is not yet called. - * Do not call power_supply_charged() in this case. + * Do not call power_supply_changed() in this case. */ if (info->charger) power_supply_changed(info->charger); @@ -1478,6 +1480,11 @@ static void rt9455_pwr_rdy_work_callback(struct work_struct *work) RT9455_MAX_CHARGING_TIME * HZ); break; } + /* + * Notify userspace that the charger has been either connected to or + * disconnected from the power source. + */ + power_supply_changed(info->charger); } static void rt9455_max_charging_time_work_callback(struct work_struct *work) @@ -1533,6 +1540,11 @@ static void rt9455_batt_presence_work_callback(struct work_struct *work) if (ret) dev_err(dev, "Failed to unmask BATAB interrupt\n"); } + /* + * Notify userspace that the battery is now connected to the + * charger. + */ + power_supply_changed(info->charger); } } -- cgit v1.3-6-gb490 From 2d53809594afaf2ae66a90a3142c1b702fd3bcea Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Mon, 6 Jul 2015 15:57:44 -0700 Subject: Input: zforce_ts - convert to use the gpiod interface Use the new GPIO descriptor interface to handle the zForce GPIOs. This simplifies the code and allows transparently handle GPIO polarity, as specified in device tree data. Also switch to using gpio_{set|get}_value_cansleep() since none of the callers is in atomic context and cansleep variant allows more GPIO controllers to be used with the touchscreen. Signed-off-by: Dirk Behme Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zforce_ts.c | 58 +++++++++++++++++---------------- include/linux/platform_data/zforce_ts.h | 3 -- 2 files changed, 30 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index f58a196521a9..c4cffcfb03d3 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -24,14 +24,13 @@ #include #include #include -#include +#include #include #include #include #include #include #include -#include #define WAIT_TIMEOUT msecs_to_jiffies(1000) @@ -120,6 +119,9 @@ struct zforce_ts { struct regulator *reg_vdd; + struct gpio_desc *gpio_int; + struct gpio_desc *gpio_rst; + bool suspending; bool suspended; bool boot_complete; @@ -161,6 +163,16 @@ static int zforce_command(struct zforce_ts *ts, u8 cmd) return 0; } +static void zforce_reset_assert(struct zforce_ts *ts) +{ + gpiod_set_value_cansleep(ts->gpio_rst, 1); +} + +static void zforce_reset_deassert(struct zforce_ts *ts) +{ + gpiod_set_value_cansleep(ts->gpio_rst, 0); +} + static int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len) { struct i2c_client *client = ts->client; @@ -479,7 +491,6 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) { struct zforce_ts *ts = dev_id; struct i2c_client *client = ts->client; - const struct zforce_ts_platdata *pdata = ts->pdata; int ret; u8 payload_buffer[FRAME_MAXSIZE]; u8 *payload; @@ -499,7 +510,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) if (!ts->suspending && device_may_wakeup(&client->dev)) pm_stay_awake(&client->dev); - while (!gpio_get_value(pdata->gpio_int)) { + while (!gpiod_get_value_cansleep(ts->gpio_int)) { ret = zforce_read_packet(ts, payload_buffer); if (ret < 0) { dev_err(&client->dev, @@ -690,7 +701,7 @@ static void zforce_reset(void *data) { struct zforce_ts *ts = data; - gpio_set_value(ts->pdata->gpio_rst, 0); + zforce_reset_assert(ts); udelay(10); @@ -712,18 +723,6 @@ static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev) 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); @@ -755,19 +754,22 @@ static int zforce_probe(struct i2c_client *client, if (!ts) return -ENOMEM; - ret = devm_gpio_request_one(&client->dev, pdata->gpio_int, GPIOF_IN, - "zforce_ts_int"); - if (ret) { - dev_err(&client->dev, "request of gpio %d failed, %d\n", - pdata->gpio_int, ret); + /* INT GPIO */ + ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0, GPIOD_IN); + if (IS_ERR(ts->gpio_int)) { + ret = PTR_ERR(ts->gpio_int); + dev_err(&client->dev, + "failed to request interrupt GPIO: %d\n", ret); return ret; } - ret = devm_gpio_request_one(&client->dev, pdata->gpio_rst, - GPIOF_OUT_INIT_LOW, "zforce_ts_rst"); - if (ret) { - dev_err(&client->dev, "request of gpio %d failed, %d\n", - pdata->gpio_rst, ret); + /* RST GPIO */ + ts->gpio_rst = devm_gpiod_get_index(&client->dev, NULL, 1, + GPIOD_OUT_HIGH); + if (IS_ERR(ts->gpio_rst)) { + ret = PTR_ERR(ts->gpio_rst); + dev_err(&client->dev, + "failed to request reset GPIO: %d\n", ret); return ret; } @@ -863,7 +865,7 @@ static int zforce_probe(struct i2c_client *client, i2c_set_clientdata(client, ts); /* let the controller boot */ - gpio_set_value(pdata->gpio_rst, 1); + zforce_reset_deassert(ts); ts->command_waiting = NOTIFICATION_BOOTCOMPLETE; if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) diff --git a/include/linux/platform_data/zforce_ts.h b/include/linux/platform_data/zforce_ts.h index 0472ab2f6ede..7bdece8ef33e 100644 --- a/include/linux/platform_data/zforce_ts.h +++ b/include/linux/platform_data/zforce_ts.h @@ -16,9 +16,6 @@ #define _LINUX_INPUT_ZFORCE_TS_H struct zforce_ts_platdata { - int gpio_int; - int gpio_rst; - unsigned int x_max; unsigned int y_max; }; -- cgit v1.3-6-gb490 From ec0843fabe29ad44bdaaa16c8d6cda4537716de5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 8 Jul 2015 08:25:50 -0700 Subject: Input: drv260x/drv2665/drv2667 - constify reg_default tables These reg_default tables are not modified after initialized, so make them const. Signed-off-by: Axel Lin Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv260x.c | 2 +- drivers/input/misc/drv2665.c | 2 +- drivers/input/misc/drv2667.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index e5d60ecd29a4..0e3af55d9e25 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -204,7 +204,7 @@ struct drv260x_data { int overdrive_voltage; }; -static struct reg_default drv260x_reg_defs[] = { +static const struct reg_default drv260x_reg_defs[] = { { DRV260X_STATUS, 0xe0 }, { DRV260X_MODE, 0x40 }, { DRV260X_RT_PB_IN, 0x00 }, diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index 0afaa33de07d..e9501fdca5ef 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -74,7 +74,7 @@ static const u8 drv2665_sine_wave_form[] = { 0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00, }; -static struct reg_default drv2665_reg_defs[] = { +static const struct reg_default drv2665_reg_defs[] = { { DRV2665_STATUS, 0x02 }, { DRV2665_CTRL_1, 0x28 }, { DRV2665_CTRL_2, 0x40 }, diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index fc0fddf0896a..a231342207f9 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -116,7 +116,7 @@ struct drv2667_data { u32 frequency; }; -static struct reg_default drv2667_reg_defs[] = { +static const struct reg_default drv2667_reg_defs[] = { { DRV2667_STATUS, 0x02 }, { DRV2667_CTRL_1, 0x28 }, { DRV2667_CTRL_2, 0x40 }, -- cgit v1.3-6-gb490 From f23487cdbe3bd002e99f41250143014e522c34de Mon Sep 17 00:00:00 2001 From: Anshul Garg Date: Wed, 8 Jul 2015 16:41:39 -0700 Subject: Input: joydev - use for_each_set_bit where appropriate Use for_each_set_bit to check for set bits in bitmap as it is more efficient than checking individual bits. Signed-off-by: Anshul Garg Signed-off-by: Dmitry Torokhov --- drivers/input/joydev.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index f362883c94e3..46862602a5f7 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -798,12 +798,11 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, joydev->handle.handler = handler; joydev->handle.private = joydev; - for (i = 0; i < ABS_CNT; i++) - if (test_bit(i, dev->absbit)) { - joydev->absmap[i] = joydev->nabs; - joydev->abspam[joydev->nabs] = i; - joydev->nabs++; - } + for_each_set_bit(i, dev->absbit, ABS_CNT) { + joydev->absmap[i] = joydev->nabs; + joydev->abspam[joydev->nabs] = i; + joydev->nabs++; + } for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC + 1; i++) if (test_bit(i + BTN_MISC, dev->keybit)) { -- cgit v1.3-6-gb490 From 948cea14487af7d6e8b8007dc24a5361869f410b Mon Sep 17 00:00:00 2001 From: Anshul Garg Date: Wed, 8 Jul 2015 16:43:20 -0700 Subject: Input: ff-core - use for_each_set_bit where appropriate Use for_each_set_bit to check for set bits in bitmap as it is more efficient than checking individual bits. Signed-off-by: Anshul Garg Signed-off-by: Dmitry Torokhov --- drivers/input/ff-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index 8f4a30fccbb6..c64208267198 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -343,9 +343,8 @@ int input_ff_create(struct input_dev *dev, unsigned int max_effects) __set_bit(EV_FF, dev->evbit); /* Copy "true" bits into ff device bitmap */ - for (i = 0; i <= FF_MAX; i++) - if (test_bit(i, dev->ffbit)) - __set_bit(i, ff->ffbit); + for_each_set_bit(i, dev->ffbit, FF_CNT) + __set_bit(i, ff->ffbit); /* we can emulate RUMBLE with periodic effects */ if (test_bit(FF_PERIODIC, ff->ffbit)) -- cgit v1.3-6-gb490 From 71d3c0b49a72fd092b7490b923d1721ceced8170 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 9 Jul 2015 14:55:46 +0530 Subject: cxgb4vf: Fix check to use new User Doorbell mechanism If we don't have access to the new User GTS (T5+), use the old doorbell mechanism; otherwise use the new BAR2 mechanism. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index ad53e5ad2acd..1d5e77a566e1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -1898,7 +1898,10 @@ static int napi_rx_handler(struct napi_struct *napi, int budget) rspq->unhandled_irqs++; val = CIDXINC_V(work_done) | SEINTARM_V(intr_params); - if (is_t4(rspq->adapter->params.chip)) { + /* If we don't have access to the new User GTS (T5+), use the old + * doorbell mechanism; otherwise use the new BAR2 mechanism. + */ + if (unlikely(!rspq->bar2_addr)) { t4_write_reg(rspq->adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, val | INGRESSQID_V((u32)rspq->cntxt_id)); @@ -1998,10 +2001,13 @@ static unsigned int process_intrq(struct adapter *adapter) } val = CIDXINC_V(work_done) | SEINTARM_V(intrq->intr_params); - if (is_t4(adapter->params.chip)) + /* If we don't have access to the new User GTS (T5+), use the old + * doorbell mechanism; otherwise use the new BAR2 mechanism. + */ + if (unlikely(!intrq->bar2_addr)) { t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, val | INGRESSQID_V(intrq->cntxt_id)); - else { + } else { writel(val | INGRESSQID_V(intrq->bar2_qid), intrq->bar2_addr + SGE_UDB_GTS); wmb(); -- cgit v1.3-6-gb490 From 910be1abbec9cac102fde8ab6dd68a9b410ca441 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Thu, 9 Jul 2015 10:25:39 +0530 Subject: neterion: s2io: Use module_pci_driver Use module_pci_driver for drivers whose init and exit functions only register and unregister, respectively. A simplified version of the Coccinelle semantic patch that performs this transformation is as follows: @a@ identifier f, x; @@ -static f(...) { return pci_register_driver(&x); } @b depends on a@ identifier e, a.x; statement S; @@ -static e(...) { -pci_unregister_driver(&x); -DBG_PRINT(INIT_DBG,"S"); - } @c depends on a && b@ identifier a.f; declarer name module_init; @@ -module_init(f); @d depends on a && b && c@ identifier b.e, a.x; declarer name module_exit; declarer name module_pci_driver; @@ -module_exit(e); +module_pci_driver(x); Signed-off-by: Vaishali Thakkar Signed-off-by: David S. Miller --- drivers/net/ethernet/neterion/s2io.c | 26 +------------------------- drivers/net/ethernet/neterion/s2io.h | 2 -- 2 files changed, 1 insertion(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index c28111749e1f..2d1b94274079 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -8226,31 +8226,7 @@ static void s2io_rem_nic(struct pci_dev *pdev) pci_disable_device(pdev); } -/** - * s2io_starter - Entry point for the driver - * Description: This function is the entry point for the driver. It verifies - * the module loadable parameters and initializes PCI configuration space. - */ - -static int __init s2io_starter(void) -{ - return pci_register_driver(&s2io_driver); -} - -/** - * s2io_closer - Cleanup routine for the driver - * Description: This function is the cleanup routine for the driver. It - * unregisters the driver. - */ - -static __exit void s2io_closer(void) -{ - pci_unregister_driver(&s2io_driver); - DBG_PRINT(INIT_DBG, "cleanup done\n"); -} - -module_init(s2io_starter); -module_exit(s2io_closer); +module_pci_driver(s2io_driver); static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, struct tcphdr **tcp, struct RxD_t *rxdp, diff --git a/drivers/net/ethernet/neterion/s2io.h b/drivers/net/ethernet/neterion/s2io.h index d89b6ed82c51..6c5997dc8afc 100644 --- a/drivers/net/ethernet/neterion/s2io.h +++ b/drivers/net/ethernet/neterion/s2io.h @@ -1085,8 +1085,6 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp); static void tx_intr_handler(struct fifo_info *fifo_data); static void s2io_handle_errors(void * dev_id); -static int s2io_starter(void); -static void s2io_closer(void); static void s2io_tx_watchdog(struct net_device *dev); static void s2io_set_multicast(struct net_device *dev); static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp); -- cgit v1.3-6-gb490 From 77a58c741df1b91258cc4df3e6893ff61e8293a4 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 8 Jul 2015 16:06:47 -0700 Subject: rocker: add change MTU support Implement ndo_change_mtu: on MTU change, reallocate Rx ring bufs and signal HW of new port MTU value. Signed-off-by: Scott Feldman Reviewed-by: Simon Horman Tested-by: Simon Horman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 61 ++++++++++++++++++++++++++++++++++++ drivers/net/ethernet/rocker/rocker.h | 1 + 2 files changed, 62 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 2d8578cade03..c0051673c9fa 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -1817,6 +1817,30 @@ rocker_cmd_set_port_settings_macaddr_prep(const struct rocker_port *rocker_port, return 0; } +static int +rocker_cmd_set_port_settings_mtu_prep(const struct rocker_port *rocker_port, + struct rocker_desc_info *desc_info, + void *priv) +{ + int mtu = *(int *)priv; + struct rocker_tlv *cmd_info; + + if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, + ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS)) + return -EMSGSIZE; + cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO); + if (!cmd_info) + return -EMSGSIZE; + if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT, + rocker_port->pport)) + return -EMSGSIZE; + if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_MTU, + mtu)) + return -EMSGSIZE; + rocker_tlv_nest_end(desc_info, cmd_info); + return 0; +} + static int rocker_cmd_set_port_learning_prep(const struct rocker_port *rocker_port, struct rocker_desc_info *desc_info, @@ -1874,6 +1898,14 @@ static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port, macaddr, NULL, NULL); } +static int rocker_cmd_set_port_settings_mtu(struct rocker_port *rocker_port, + int mtu) +{ + return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, + rocker_cmd_set_port_settings_mtu_prep, + &mtu, NULL, NULL); +} + static int rocker_port_set_learning(struct rocker_port *rocker_port, enum switchdev_trans trans) { @@ -4152,6 +4184,34 @@ static int rocker_port_set_mac_address(struct net_device *dev, void *p) return 0; } +static int rocker_port_change_mtu(struct net_device *dev, int new_mtu) +{ + struct rocker_port *rocker_port = netdev_priv(dev); + int running = netif_running(dev); + int err; + +#define ROCKER_PORT_MIN_MTU 68 +#define ROCKER_PORT_MAX_MTU 9000 + + if (new_mtu < ROCKER_PORT_MIN_MTU || new_mtu > ROCKER_PORT_MAX_MTU) + return -EINVAL; + + if (running) + rocker_port_stop(dev); + + netdev_info(dev, "MTU change from %d to %d\n", dev->mtu, new_mtu); + dev->mtu = new_mtu; + + err = rocker_cmd_set_port_settings_mtu(rocker_port, new_mtu); + if (err) + return err; + + if (running) + err = rocker_port_open(dev); + + return err; +} + static int rocker_port_get_phys_port_name(struct net_device *dev, char *buf, size_t len) { @@ -4172,6 +4232,7 @@ static const struct net_device_ops rocker_port_netdev_ops = { .ndo_stop = rocker_port_stop, .ndo_start_xmit = rocker_port_xmit, .ndo_set_mac_address = rocker_port_set_mac_address, + .ndo_change_mtu = rocker_port_change_mtu, .ndo_bridge_getlink = switchdev_port_bridge_getlink, .ndo_bridge_setlink = switchdev_port_bridge_setlink, .ndo_bridge_dellink = switchdev_port_bridge_dellink, diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h index c61fbf968036..08b2c3d96188 100644 --- a/drivers/net/ethernet/rocker/rocker.h +++ b/drivers/net/ethernet/rocker/rocker.h @@ -159,6 +159,7 @@ enum { ROCKER_TLV_CMD_PORT_SETTINGS_MODE, /* u8 */ ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, /* u8 */ ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, /* binary */ + ROCKER_TLV_CMD_PORT_SETTINGS_MTU, /* u16 */ __ROCKER_TLV_CMD_PORT_SETTINGS_MAX, ROCKER_TLV_CMD_PORT_SETTINGS_MAX = -- cgit v1.3-6-gb490 From 5ddfb12e90c73cf86881345be422e09c367f6981 Mon Sep 17 00:00:00 2001 From: Ellen Wang Date: Wed, 8 Jul 2015 11:17:39 -0700 Subject: HID: cp2112: support large i2c transfers cp2112_i2c_xfer() only reads up to 61 bytes, returning EIO on longers reads. The fix is to wrap a loop around cp2112_read() to pick up all the returned data. Signed-off-by: Ellen Wang Signed-off-by: Jiri Kosina --- drivers/hid/hid-cp2112.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index a2dbbbe0d8d7..75398cb84fde 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -511,13 +511,30 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, if (!(msgs->flags & I2C_M_RD)) goto finish; - ret = cp2112_read(dev, msgs->buf, msgs->len); - if (ret < 0) - goto power_normal; - if (ret != msgs->len) { - hid_warn(hdev, "short read: %d < %d\n", ret, msgs->len); - ret = -EIO; - goto power_normal; + for (count = 0; count < msgs->len;) { + ret = cp2112_read(dev, msgs->buf + count, msgs->len - count); + if (ret < 0) + goto power_normal; + if (ret == 0) { + hid_err(hdev, "read returned 0\n"); + ret = -EIO; + goto power_normal; + } + count += ret; + if (count > msgs->len) { + /* + * The hardware returned too much data. + * This is mostly harmless because cp2112_read() + * has a limit check so didn't overrun our + * buffer. Nevertheless, we return an error + * because something is seriously wrong and + * it shouldn't go unnoticed. + */ + hid_err(hdev, "long read: %d > %zd\n", + ret, msgs->len - count + ret); + ret = -EIO; + goto power_normal; + } } finish: -- cgit v1.3-6-gb490 From 0925636042170e0b6716cd86635899c5f4258f69 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Mon, 6 Jul 2015 16:48:31 -0700 Subject: HID: rmi: Disable scanning if the device is not a wake source Some touchpads are configured with firmware which continues to scan for fingers at a minimal scan rate even after receiving the HID power sleep command. This allows a finger touching the touchpad to genrate a wake event. This patch ensures that scanning is disabled if the touchpad is not a wake source and ensures scanning is enabled on resume. Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina --- drivers/hid/hid-rmi.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 4cf80bb276dc..af191a265b80 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -33,6 +33,9 @@ #define RMI_READ_DATA_PENDING 1 #define RMI_STARTED 2 +#define RMI_SLEEP_NORMAL 0x0 +#define RMI_SLEEP_DEEP_SLEEP 0x1 + /* device flags */ #define RMI_DEVICE BIT(0) #define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) @@ -126,6 +129,8 @@ struct rmi_data { unsigned long device_flags; unsigned long firmware_id; + + u8 f01_ctrl0; }; #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) @@ -532,9 +537,51 @@ static int rmi_event(struct hid_device *hdev, struct hid_field *field, } #ifdef CONFIG_PM +static int rmi_set_sleep_mode(struct hid_device *hdev, int sleep_mode) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + u8 f01_ctrl0; + + f01_ctrl0 = (data->f01_ctrl0 & ~0x3) | sleep_mode; + + ret = rmi_write(hdev, data->f01.control_base_addr, + &f01_ctrl0); + if (ret) { + hid_err(hdev, "can not write sleep mode\n"); + return ret; + } + + return 0; +} + +static int rmi_suspend(struct hid_device *hdev, pm_message_t message) +{ + if (!device_may_wakeup(hdev->dev.parent)) + return rmi_set_sleep_mode(hdev, RMI_SLEEP_DEEP_SLEEP); + + return 0; +} + static int rmi_post_reset(struct hid_device *hdev) { - return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + int ret; + + ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + if (ret) { + hid_err(hdev, "can not set rmi mode\n"); + return ret; + } + + if (!device_may_wakeup(hdev->dev.parent)) { + ret = rmi_set_sleep_mode(hdev, RMI_SLEEP_NORMAL); + if (ret) { + hid_err(hdev, "can not write sleep mode\n"); + return ret; + } + } + + return ret; } static int rmi_post_resume(struct hid_device *hdev) @@ -732,6 +779,12 @@ static int rmi_populate_f01(struct hid_device *hdev) data->firmware_id += info[2] * 65536; } + ret = rmi_read(hdev, data->f01.control_base_addr, &data->f01_ctrl0); + + if (ret) { + hid_err(hdev, "can not read f01 ctrl0\n"); + return ret; + } return 0; } @@ -1273,6 +1326,7 @@ static struct hid_driver rmi_driver = { .input_mapping = rmi_input_mapping, .input_configured = rmi_input_configured, #ifdef CONFIG_PM + .suspend = rmi_suspend, .resume = rmi_post_resume, .reset_resume = rmi_post_reset, #endif -- cgit v1.3-6-gb490 From 67e123ff0e9a71fcf19f83827d59f73076f5bd1a Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 9 Jul 2015 08:08:15 +0200 Subject: HID: wacom: Delete unnecessary checks before the function call "input_free_device" The input_free_device() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 4c0ffca97bef..936ad7770ec3 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1149,12 +1149,9 @@ static void wacom_free_inputs(struct wacom *wacom) { struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - if (wacom_wac->pen_input) - input_free_device(wacom_wac->pen_input); - if (wacom_wac->touch_input) - input_free_device(wacom_wac->touch_input); - if (wacom_wac->pad_input) - input_free_device(wacom_wac->pad_input); + input_free_device(wacom_wac->pen_input); + input_free_device(wacom_wac->touch_input); + input_free_device(wacom_wac->pad_input); wacom_wac->pen_input = NULL; wacom_wac->touch_input = NULL; wacom_wac->pad_input = NULL; -- cgit v1.3-6-gb490 From 169de1316c1e69ad169d81c60549479640461630 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 8 Jul 2015 16:21:31 -0700 Subject: drm/i915: PSR: Flush means invalidate + flush Since flush actually means invalidate + flush we need to force psr exit on PSR flush. On Core platforms there is no way to disable hw tracking and do the pure sw tracking so we simulate it by fully disable psr and reschedule a enable back. So a good idea is to minimize sequential disable/enable in cases we know that HW tracking like when flush has been originated by a flip. Also flip had just invalidated it already. It also uses origin to minimize the a bit the amount of disable/enabled, mainly when flip already had invalidated. With this patch in place it is possible to do a flush on dirty areas properly in a following patch. v2: Remove duplicated exit on HSW+Sprites as pointed out by Paulo. Cc: Paulo Zanoni Cc: Daniel Vetter Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 3 ++- drivers/gpu/drm/i915/intel_frontbuffer.c | 2 +- drivers/gpu/drm/i915/intel_psr.c | 40 +++++++++++++++++--------------- 3 files changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index beeb4d326cbe..c8635110a96d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1329,7 +1329,8 @@ void intel_psr_disable(struct intel_dp *intel_dp); void intel_psr_invalidate(struct drm_device *dev, unsigned frontbuffer_bits); void intel_psr_flush(struct drm_device *dev, - unsigned frontbuffer_bits); + unsigned frontbuffer_bits, + enum fb_op_origin origin); void intel_psr_init(struct drm_device *dev); void intel_psr_single_frame_update(struct drm_device *dev, unsigned frontbuffer_bits); diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index cb5a6f0447e7..e73d2ff0d9b8 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -128,7 +128,7 @@ void intel_frontbuffer_flush(struct drm_device *dev, return; intel_edp_drrs_flush(dev, frontbuffer_bits); - intel_psr_flush(dev, frontbuffer_bits); + intel_psr_flush(dev, frontbuffer_bits, origin); intel_fbc_flush(dev_priv, frontbuffer_bits); } diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index d79ba58637d7..6db043f3c1ad 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -680,6 +680,7 @@ void intel_psr_invalidate(struct drm_device *dev, * intel_psr_flush - Flush PSR * @dev: DRM device * @frontbuffer_bits: frontbuffer plane tracking bits + * @origin: which operation caused the flush * * Since the hardware frontbuffer tracking has gaps we need to integrate * with the software frontbuffer tracking. This function gets called every @@ -689,7 +690,7 @@ void intel_psr_invalidate(struct drm_device *dev, * Dirty frontbuffers relevant to PSR are tracked in busy_frontbuffer_bits. */ void intel_psr_flush(struct drm_device *dev, - unsigned frontbuffer_bits) + unsigned frontbuffer_bits, enum fb_op_origin origin) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -707,24 +708,25 @@ void intel_psr_flush(struct drm_device *dev, frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits; - /* - * On Haswell sprite plane updates don't result in a psr invalidating - * signal in the hardware. Which means we need to manually fake this in - * software for all flushes, not just when we've seen a preceding - * invalidation through frontbuffer rendering. - */ - if (IS_HASWELL(dev) && - (frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe))) - intel_psr_exit(dev); - - /* - * On Valleyview and Cherryview we don't use hardware tracking so - * any plane updates or cursor moves don't result in a PSR - * invalidating. Which means we need to manually fake this in - * software for all flushes, not just when we've seen a preceding - * invalidation through frontbuffer rendering. */ - if (frontbuffer_bits && !HAS_DDI(dev)) - intel_psr_exit(dev); + if (HAS_DDI(dev)) { + /* + * By definition every flush should mean invalidate + flush, + * however on core platforms let's minimize the + * disable/re-enable so we can avoid the invalidate when flip + * originated the flush. + */ + if (frontbuffer_bits && origin != ORIGIN_FLIP) + intel_psr_exit(dev); + } else { + /* + * On Valleyview and Cherryview we don't use hardware tracking + * so any plane updates or cursor moves don't result in a PSR + * invalidating. Which means we need to manually fake this in + * software for all flushes. + */ + if (frontbuffer_bits) + intel_psr_exit(dev); + } if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) schedule_delayed_work(&dev_priv->psr.work, -- cgit v1.3-6-gb490 From 86c985883edeba570c9b6679827556bed2c6ecdc Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 8 Jul 2015 16:22:45 -0700 Subject: drm/i915: dirty fb operation flushsing frontbuffer Let's do a frontbuffer flush on dirty fb. To be used for DIRTYFB drm ioctl. This patch solves the biggest PSR known issue, that is missed screen updates during boot, mainly when there is a splash screen involved like Plymouth. Previously PSR was being invalidated by fbdev and Plymounth was taking control with PSR yet invalidated and could get screen updates normally. However with some atomic modeset changes Pymouth modeset over ioctl was now causing frontbuffer flushes making PSR gets back to work while it cannot track the screen updates and exit properly. By adding this flush on dirtyfb we properly track frontbuffer writes and properly exit PSR. Actually all mmap_wc users should call this dirty callback in order to have a proper frontbuffer tracking. In the future it can be extended to return 0 if the whole screen has being flushed or the number of rects flushed as Chris suggested. v2: Remove ORIGIN_FB_DIRTY and use ORIGIN_GTT instead since dirty callback is just called after few screen updates and not on everyone as pointed by Daniel. v3: Use flush instead of invalidate since flush means invalidate + flush and dirty means drawn had finished and it can be flushed. v4: Remove PSR from subject since it is purely frontbuffer tracking change and that can be useful for FBC as well. Cc: Chris Wilson Cc: Paulo Zanoni Cc: Daniel Vetter Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni [danvet: Fix alignment as spotted by Paulo.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4bcbff9793d4..c465a52a38bc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14385,9 +14385,27 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, return drm_gem_handle_create(file, &obj->base, handle); } +static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, + struct drm_file *file, + unsigned flags, unsigned color, + struct drm_clip_rect *clips, + unsigned num_clips) +{ + struct drm_device *dev = fb->dev; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + + mutex_lock(&dev->struct_mutex); + intel_fb_obj_flush(obj, false, ORIGIN_GTT); + mutex_unlock(&dev->struct_mutex); + + return 0; +} + static const struct drm_framebuffer_funcs intel_fb_funcs = { .destroy = intel_user_framebuffer_destroy, .create_handle = intel_user_framebuffer_create_handle, + .dirty = intel_user_framebuffer_dirty, }; static -- cgit v1.3-6-gb490 From 76f2e13d5597d72c4f88509d0d183e4a8512b01f Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 8 Jul 2015 18:08:38 -0300 Subject: drm/i915: fix intel_fb_obj_flush documentation Reported by the kbuild test robot. Regression introduced by: commit de152b627eb3018de91ec5c5a50b38e17d80a88b Author: Rodrigo Vivi Date: Tue Jul 7 16:28:51 2015 -0700 drm/i915: Add origin to frontbuffer tracking flush (I reviewed this commit, so it's also my fault) Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_frontbuffer.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index e73d2ff0d9b8..e22d0b142392 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -136,6 +136,7 @@ void intel_frontbuffer_flush(struct drm_device *dev, * intel_fb_obj_flush - flush frontbuffer object * @obj: GEM object to flush * @retire: set when retiring asynchronous rendering + * @origin: which operation caused the flush * * This function gets called every time rendering on the given object has * completed and frontbuffer caching can be started again. If @retire is true -- cgit v1.3-6-gb490 From b6c2aa5187ac59c8c6728ae09934390c3757f2bf Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 8 Jul 2015 18:08:37 -0300 Subject: drm/i915: intel_frontbuffer_flush can now be static So make it static. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 3 --- drivers/gpu/drm/i915/intel_frontbuffer.c | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c8635110a96d..b9c01c5b881f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -977,9 +977,6 @@ void intel_frontbuffer_flip_prepare(struct drm_device *dev, unsigned frontbuffer_bits); void intel_frontbuffer_flip_complete(struct drm_device *dev, unsigned frontbuffer_bits); -void intel_frontbuffer_flush(struct drm_device *dev, - unsigned frontbuffer_bits, - enum fb_op_origin origin); void intel_frontbuffer_flip(struct drm_device *dev, unsigned frontbuffer_bits); unsigned int intel_fb_align_height(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index e22d0b142392..c405c2deb8bf 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -113,9 +113,9 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, * * Can be called without any locks held. */ -void intel_frontbuffer_flush(struct drm_device *dev, - unsigned frontbuffer_bits, - enum fb_op_origin origin) +static void intel_frontbuffer_flush(struct drm_device *dev, + unsigned frontbuffer_bits, + enum fb_op_origin origin) { struct drm_i915_private *dev_priv = to_i915(dev); -- cgit v1.3-6-gb490 From cc2e26a7c57924b31e9c5ac7b3d0d814253c9285 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 8 Jul 2015 18:08:39 -0300 Subject: drm/i915: fix intel_frontbuffer_flip documentation Reported by the kbuild test robot. Regression introduced by: commit fdbff9282c0f5f61ffc87d57461b04d943250910 Author: Daniel Vetter Date: Thu Jun 18 11:23:24 2015 +0200 drm/i915: Clear fb_tracking.busy_bits also for synchronous flips (I reviewed this commit, so it's also my fault) Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 1 - drivers/gpu/drm/i915/intel_frontbuffer.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index e82205ee3d5f..1ca1171b16e5 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4012,7 +4012,6 @@ int num_ioctls; Frontbuffer Tracking !Pdrivers/gpu/drm/i915/intel_frontbuffer.c frontbuffer tracking !Idrivers/gpu/drm/i915/intel_frontbuffer.c -!Fdrivers/gpu/drm/i915/intel_drv.h intel_frontbuffer_flip !Fdrivers/gpu/drm/i915/i915_gem.c i915_gem_track_fb diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index c405c2deb8bf..777b1d3ccd41 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -229,7 +229,6 @@ void intel_frontbuffer_flip_complete(struct drm_device *dev, * * Can be called without any locks held. */ - void intel_frontbuffer_flip(struct drm_device *dev, unsigned frontbuffer_bits) { -- cgit v1.3-6-gb490 From f747a1fe7848453957dbdf362a42d7a6735c6ff0 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 9 Jul 2015 16:35:27 +0100 Subject: regulator: pwm-regulator: Remove obsoleted property In "[3d7ef30] regulator: pwm-regulator: Simplify voltage to duty-cycle call" we stopped using max_duty_cycle, so we can retire it from device data and DT. There is no need to deprecate this property, as it hasn't hit Mainline yet. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/pwm-regulator.txt | 11 ++++------- drivers/regulator/pwm-regulator.c | 9 --------- 2 files changed, 4 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt index 23b47720b2e4..ed936f0f34f2 100644 --- a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt @@ -29,15 +29,14 @@ Required properties: - pwms: PWM specification (See: ../pwm/pwm.txt) -One of these must be provided: +Only required for Voltage Table Mode: - voltage-table: Voltage and Duty-Cycle table consisting of 2 cells First cell is voltage in microvolts (uV) Second cell is duty-cycle in percent (%) -- max-duty-cycle: Maximum Duty-Cycle value -- this will normally be - 255 (0xff) for an 8 bit PWM device - -If both are provided, the current default is voltage-table mode. +NB: To be clear, if voltage-table is provided, then the device will be used +in Voltage Table Mode. If no voltage-table is provided, then the device will +be used in Continuous Voltage Mode. Any property defined as part of the core regulator binding can also be used. (See: ../regulator/regulator.txt) @@ -49,8 +48,6 @@ Continuous Voltage Example: regulator-min-microvolt = <1016000>; regulator-max-microvolt = <1114000>; regulator-name = "vdd_logic"; - - max-duty-cycle = <255>; /* 8bit PWM */ }; Voltage Table Example: diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index cb482089050b..d92e66772ec0 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -30,7 +30,6 @@ struct pwm_regulator_data { int state; /* Continuous voltage */ - u32 max_duty_cycle; int volt_uV; }; @@ -201,14 +200,6 @@ static int pwm_regulator_init_continuous(struct platform_device *pdev, struct pwm_regulator_data *drvdata) { struct device_node *np = pdev->dev.of_node; - int ret; - - ret = of_property_read_u32(np, "max-duty-cycle", - &drvdata->max_duty_cycle); - if (ret) { - dev_err(&pdev->dev, "Failed to read \"pwm-max-value\"\n"); - return ret; - } pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops; pwm_regulator_desc.continuous_voltage_range = true; -- cgit v1.3-6-gb490 From f3f6439d8635d783f145b321db3049369e745799 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 9 Jul 2015 16:35:28 +0100 Subject: regulator: pwm-regulator: Small clean-ups Remove over-bracketing, use framework API to fetch PWM period and be more forthcoming that pwm_voltage_to_duty_cycle() actually returns duty cycle as a percentage, rather than a register value. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index d92e66772ec0..936e387cc532 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -92,13 +92,13 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev, /** * Continuous voltage call-backs */ -static int pwm_voltage_to_duty_cycle(struct regulator_dev *rdev, int req_uV) +static int pwm_voltage_to_duty_cycle_percentage(struct regulator_dev *rdev, int req_uV) { int min_uV = rdev->constraints->min_uV; int max_uV = rdev->constraints->max_uV; int diff = max_uV - min_uV; - return 100 - ((((req_uV * 100) - (min_uV * 100)) / diff)); + return 100 - (((req_uV * 100) - (min_uV * 100)) / diff); } static int pwm_regulator_get_voltage(struct regulator_dev *rdev) @@ -114,14 +114,13 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); unsigned int ramp_delay = rdev->constraints->ramp_delay; + unsigned int period = pwm_get_period(drvdata->pwm); int duty_cycle; int ret; - duty_cycle = pwm_voltage_to_duty_cycle(rdev, min_uV); + duty_cycle = pwm_voltage_to_duty_cycle_percentage(rdev, min_uV); - ret = pwm_config(drvdata->pwm, - (drvdata->pwm->period / 100) * duty_cycle, - drvdata->pwm->period); + ret = pwm_config(drvdata->pwm, (period / 100) * duty_cycle, period); if (ret) { dev_err(&rdev->dev, "Failed to configure PWM\n"); return ret; -- cgit v1.3-6-gb490 From 5d506a5ad4155e813d254d2f02ce17b58045423c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 9 Jul 2015 16:48:50 +0800 Subject: regulator: qcom_spmi-regulator: Use DIV_ROUND_UP instead of open-coded Signed-off-by: Axel Lin Reviewed-by: Andy Gross Signed-off-by: Mark Brown --- drivers/regulator/qcom_spmi-regulator.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 850a30a95b5b..9ef0e2f28ec4 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -504,8 +504,7 @@ static int spmi_regulator_select_voltage(struct spmi_regulator *vreg, * Force uV to be an allowed set point by applying a ceiling function to * the uV value. */ - *voltage_sel = (uV - range->min_uV + range->step_uV - 1) - / range->step_uV; + *voltage_sel = DIV_ROUND_UP(uV - range->min_uV, range->step_uV); uV = *voltage_sel * range->step_uV + range->min_uV; if (uV > max_uV) { -- cgit v1.3-6-gb490 From b6d30968d86c45a7bb599eaca13ff048d3fa576c Mon Sep 17 00:00:00 2001 From: Anshul Garg Date: Thu, 9 Jul 2015 10:18:22 -0700 Subject: Input: uinput - switch to using for_each_set_bit() Use for_each_set_bit to check for set bits in bitmap as it is more efficient and compact. Signed-off-by: Anshul Garg Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 421e29e4cd81..345df9b03aed 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -320,10 +320,8 @@ static int uinput_validate_absbits(struct input_dev *dev) * Check if absmin/absmax/absfuzz/absflat are sane. */ - for (cnt = 0; cnt < ABS_CNT; cnt++) { + for_each_set_bit(cnt, dev->absbit, ABS_CNT) { int min, max; - if (!test_bit(cnt, dev->absbit)) - continue; min = input_abs_get_min(dev, cnt); max = input_abs_get_max(dev, cnt); @@ -416,7 +414,7 @@ static int uinput_setup_device(struct uinput_device *udev, dev->id.product = user_dev->id.product; dev->id.version = user_dev->id.version; - for (i = 0; i < ABS_CNT; i++) { + for_each_set_bit(i, dev->absbit, ABS_CNT) { input_abs_set_max(dev, i, user_dev->absmax[i]); input_abs_set_min(dev, i, user_dev->absmin[i]); input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]); -- cgit v1.3-6-gb490 From 09108b90f0404587b7afac64023ec11a7f1b1406 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 7 Jul 2015 16:28:54 -0700 Subject: drm/i915: PSR: Remove Low Power HW tracking mask. By Spec we should only mask memup and hotplug detection for hardware tracking cases. However we always masked LPSP because with power well always enabled on audio PSR was never being activated and residency was always zeroed. Apparently audio driver is tying power well management and runtime PM for some reason. But with audio runtime PM working or with audio completely out of picture we should remove this mask, otherwise we have a high risk of miss screen updates as faced by Matthew. WARNING: With this patch if snd_intel_hda driver is running and not releasing power well properly PSR will constant Exit and Performance Counter will be 0. But the best thing of this patch is that with one more HW tracking working the risks of missed blank screen are minimized at most. This affects just core platforms where PSR exit are also helped by HW tracking: Haswell, Broadwell and Skylake for now. v2: Fix commit message explanation. It has nothing to do with runtime PM on i915 as previously advertised. Cc: Daniel Vetter Cc: Matthew Garrett Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_psr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 6db043f3c1ad..24fa3c7e947f 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -400,7 +400,7 @@ void intel_psr_enable(struct intel_dp *intel_dp) /* Avoid continuous PSR exit by masking memup and hpd */ I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP | - EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP); + EDP_PSR_DEBUG_MASK_HPD); /* Enable PSR on the panel */ hsw_psr_enable_sink(intel_dp); -- cgit v1.3-6-gb490 From 97173eaf5f33b1e85efdb06d593d333480b60bf3 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 7 Jul 2015 16:28:55 -0700 Subject: drm/i915: PSR: Increase idle_frames Idle frames the number of identical frames needed before panel can enter PSR. There are some panels that requires up to minimum of 4 idle frames available on the market. For these cases usually VBT should be used to configure the number of idle frames, but unfortunately this isn't always true and VBT isn't being set at all. Let's trust VBT when it is set + 1 and use minimum of 4 + 1 when VBT isn't set. "+1" covers the "of-by-one" case. Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_psr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 24fa3c7e947f..acd8ec859f71 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -254,10 +254,13 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp) uint32_t max_sleep_time = 0x1f; /* Lately it was identified that depending on panel idle frame count * calculated at HW can be off by 1. So let's use what came - * from VBT + 1 and at minimum 2 to be on the safe side. + * from VBT + 1. + * There are also other cases where panel demands at least 4 + * but VBT is not being set. To cover these 2 cases lets use + * at least 5 when VBT isn't set to be on the safest side. */ uint32_t idle_frames = dev_priv->vbt.psr.idle_frames ? - dev_priv->vbt.psr.idle_frames + 1 : 2; + dev_priv->vbt.psr.idle_frames + 1 : 5; uint32_t val = 0x0; const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; -- cgit v1.3-6-gb490 From aba6da3e61779186a7bd45e2206d88524f422e5b Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 9 Jul 2015 09:56:41 -0700 Subject: drm/i915: fbdev_set_par reliably invalidating frontbuffer fbdev_set_par is called when fbcon is taking over control. In the past frontbuffer was being invalidated on set_to_gtt_domain, but it moved to set_domain fixing that case, but left this behind and broken in commit 031b698a77a70a6c394568034437b5486a44e868 Author: Daniel Vetter Date: Fri Jun 26 19:35:16 2015 +0200 drm/i915: Unconditionally do fb tracking invalidate in set_domain Note that even before this commit it wasn't perfect since the invalidate was omitted if the fbcon was already in the GTT domain, which it usually was. Since we are also invalidating in other fbdev cases this one was masked here. At least until now that I found this corner case: On boot with plymouth doing a splash screen when returning to the console frontbuffer wans't being invalidated causing missed screen updates with PSR enabled. So this patch fixes this issue. v2: Make invalidate directly and unconditionally and fix commit message indicating the set_domain fix as pointed out by Daniel. v3: Remove unecessary if(obj) added by mistake Cc: Paulo Zanoni Cc: Daniel Vetter Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni [danvet: Try to clarify commit message a bit and make it clear the referenced commit made this worse.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 2a1724e34a36..25ce7b62d4d5 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -63,8 +63,7 @@ static int intel_fbdev_set_par(struct fb_info *info) * now until we solve this for real. */ mutex_lock(&fb_helper->dev->struct_mutex); - ret = i915_gem_object_set_to_gtt_domain(ifbdev->fb->obj, - true); + intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT); mutex_unlock(&fb_helper->dev->struct_mutex); } -- cgit v1.3-6-gb490 From d04df7325ac9def8c4a68b49822c1d0a0c5379c6 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 8 Jul 2015 16:25:21 -0700 Subject: drm/i915: fbdev restore mode needs to invalidate frontbuffer This fbdev restore mode was another corner case that was now calling frontbuffer flip and flush and making we miss screen updates with PSR enabled. So let's also add the invalidate hack here while we don't have a reliable dirty fbdev op. v2: As pointed by Paulo: removed seg fault risk, used fb_helper when possible and put brackets on if. Cc: Paulo Zanoni Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Testcase: igt/kms_fbcon_fbt/psr Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 25ce7b62d4d5..33b3c9233eac 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -824,11 +824,20 @@ void intel_fbdev_restore_mode(struct drm_device *dev) { int ret; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_fbdev *ifbdev = dev_priv->fbdev; + struct drm_fb_helper *fb_helper; - if (!dev_priv->fbdev) + if (!ifbdev) return; - ret = drm_fb_helper_restore_fbdev_mode_unlocked(&dev_priv->fbdev->helper); - if (ret) + fb_helper = &ifbdev->helper; + + ret = drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); + if (ret) { DRM_DEBUG("failed to restore crtc mode\n"); + } else { + mutex_lock(&fb_helper->dev->struct_mutex); + intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT); + mutex_unlock(&fb_helper->dev->struct_mutex); + } } -- cgit v1.3-6-gb490 From 7c3d0d67d5ddb2aeb3fdae540a567a56c2831d2a Mon Sep 17 00:00:00 2001 From: "Aleksey S. Kazantsev" Date: Tue, 7 Jul 2015 20:38:15 -0700 Subject: dsa: mv88e6352/mv88e6xxx: Add support for Marvell 88E6320 and 88E6321 MV88E6320 and MV88E6321 are largely compatible to MV886352, but are members of a different chip family. Signed-off-by: Aleksey S. Kazantsev Signed-off-by: Guenter Roeck Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/Kconfig | 6 +++--- drivers/net/dsa/mv88e6352.c | 31 +++++++++++++++++++++++++------ drivers/net/dsa/mv88e6xxx.c | 42 ++++++++++++++++++++++++++++++------------ drivers/net/dsa/mv88e6xxx.h | 8 +++++++- 4 files changed, 65 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 7ad0a4d8e475..4c483d937481 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -46,13 +46,13 @@ config NET_DSA_MV88E6171 ethernet switches chips. config NET_DSA_MV88E6352 - tristate "Marvell 88E6172/88E6176/88E6352 ethernet switch chip support" + tristate "Marvell 88E6172/6176/6320/6321/6352 ethernet switch chip support" depends on NET_DSA select NET_DSA_MV88E6XXX select NET_DSA_TAG_EDSA ---help--- - This enables support for the Marvell 88E6172, 88E6176 and 88E6352 - ethernet switch chips. + This enables support for the Marvell 88E6172, 88E6176, 88E6320, + 88E6321 and 88E6352 ethernet switch chips. config NET_DSA_BCM_SF2 tristate "Broadcom Starfighter 2 Ethernet switch support" diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 632815c10a40..cfece5ae9d5f 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -36,6 +36,18 @@ static char *mv88e6352_probe(struct device *host_dev, int sw_addr) return "Marvell 88E6172"; if ((ret & 0xfff0) == PORT_SWITCH_ID_6176) return "Marvell 88E6176"; + if (ret == PORT_SWITCH_ID_6320_A1) + return "Marvell 88E6320 (A1)"; + if (ret == PORT_SWITCH_ID_6320_A2) + return "Marvell 88e6320 (A2)"; + if ((ret & 0xfff0) == PORT_SWITCH_ID_6320) + return "Marvell 88E6320"; + if (ret == PORT_SWITCH_ID_6321_A1) + return "Marvell 88E6321 (A1)"; + if (ret == PORT_SWITCH_ID_6321_A2) + return "Marvell 88e6321 (A2)"; + if ((ret & 0xfff0) == PORT_SWITCH_ID_6321) + return "Marvell 88E6321"; if (ret == PORT_SWITCH_ID_6352_A0) return "Marvell 88E6352 (A0)"; if (ret == PORT_SWITCH_ID_6352_A1) @@ -84,11 +96,12 @@ static int mv88e6352_setup_global(struct dsa_switch *ds) static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp) { + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; int ret; *temp = 0; - ret = mv88e6xxx_phy_page_read(ds, 0, 6, 27); + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 27); if (ret < 0) return ret; @@ -99,11 +112,12 @@ static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp) static int mv88e6352_get_temp_limit(struct dsa_switch *ds, int *temp) { + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; int ret; *temp = 0; - ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); if (ret < 0) return ret; @@ -114,23 +128,25 @@ static int mv88e6352_get_temp_limit(struct dsa_switch *ds, int *temp) static int mv88e6352_set_temp_limit(struct dsa_switch *ds, int temp) { + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; int ret; - ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); if (ret < 0) return ret; temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); - return mv88e6xxx_phy_page_write(ds, 0, 6, 26, + return mv88e6xxx_phy_page_write(ds, phy, 6, 26, (ret & 0xe0ff) | (temp << 8)); } static int mv88e6352_get_temp_alarm(struct dsa_switch *ds, bool *alarm) { + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; int ret; *alarm = false; - ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); if (ret < 0) return ret; @@ -394,5 +410,8 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .fdb_getnext = mv88e6xxx_port_fdb_getnext, }; -MODULE_ALIAS("platform:mv88e6352"); MODULE_ALIAS("platform:mv88e6172"); +MODULE_ALIAS("platform:mv88e6176"); +MODULE_ALIAS("platform:mv88e6320"); +MODULE_ALIAS("platform:mv88e6321"); +MODULE_ALIAS("platform:mv88e6352"); diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index fd8547c2b79d..f394e4d4d9e0 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -517,6 +517,18 @@ static bool mv88e6xxx_6185_family(struct dsa_switch *ds) return false; } +bool mv88e6xxx_6320_family(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + switch (ps->id) { + case PORT_SWITCH_ID_6320: + case PORT_SWITCH_ID_6321: + return true; + } + return false; +} + static bool mv88e6xxx_6351_family(struct dsa_switch *ds) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); @@ -565,7 +577,7 @@ static int _mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port) { int ret; - if (mv88e6xxx_6352_family(ds)) + if (mv88e6xxx_6320_family(ds) || mv88e6xxx_6352_family(ds)) port = (port + 1) << 5; /* Snapshot the hardware statistics counters for this port. */ @@ -1377,7 +1389,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) || - mv88e6xxx_6065_family(ds)) { + mv88e6xxx_6065_family(ds) || mv88e6xxx_6320_family(ds)) { /* MAC Forcing register: don't force link, speed, * duplex or flow control state to any particular * values on physical ports, but force the CPU port @@ -1423,7 +1435,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || - mv88e6xxx_6185_family(ds)) + mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds)) reg = PORT_CONTROL_IGMP_MLD_SNOOP | PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP | PORT_CONTROL_STATE_FORWARDING; @@ -1431,7 +1443,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) reg |= PORT_CONTROL_DSA_TAG; if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || - mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6320_family(ds)) { if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA) reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA; else @@ -1441,14 +1454,15 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || - mv88e6xxx_6185_family(ds)) { + mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds)) { if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA) reg |= PORT_CONTROL_EGRESS_ADD_TAG; } } if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || - mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds)) { + mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || + mv88e6xxx_6320_family(ds)) { if (ds->dsa_port_mask & (1 << port)) reg |= PORT_CONTROL_FRAME_MODE_DSA; if (port == dsa_upstream_port(ds)) @@ -1473,11 +1487,11 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) reg = 0; if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || - mv88e6xxx_6095_family(ds)) + mv88e6xxx_6095_family(ds) || mv88e6xxx_6320_family(ds)) reg = PORT_CONTROL_2_MAP_DA; if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || - mv88e6xxx_6165_family(ds)) + mv88e6xxx_6165_family(ds) || mv88e6xxx_6320_family(ds)) reg |= PORT_CONTROL_2_JUMBO_10240; if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) { @@ -1514,7 +1528,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) goto abort; if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || - mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6320_family(ds)) { /* Do not limit the period of time that this port can * be paused for by the remote end or the period of * time that this port can pause the remote end. @@ -1564,7 +1579,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || - mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) { + mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) || + mv88e6xxx_6320_family(ds)) { /* Rate Control: disable ingress rate limiting. */ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_RATE_CONTROL, 0x0001); @@ -1976,7 +1992,8 @@ int mv88e6xxx_setup_global(struct dsa_switch *ds) (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT)); if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || - mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6320_family(ds)) { /* Send all frames with destination addresses matching * 01:80:c2:00:00:2x to the CPU port. */ @@ -1995,7 +2012,8 @@ int mv88e6xxx_setup_global(struct dsa_switch *ds) if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || - mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) { + mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) || + mv88e6xxx_6320_family(ds)) { /* Disable ingress rate limiting by resetting all * ingress rate limit registers to their initial * state. diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index a650b2656de9..64786cb89a93 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -89,7 +89,12 @@ #define PORT_SWITCH_ID_6182 0x1a60 #define PORT_SWITCH_ID_6185 0x1a70 #define PORT_SWITCH_ID_6240 0x2400 -#define PORT_SWITCH_ID_6320 0x1250 +#define PORT_SWITCH_ID_6320 0x1150 +#define PORT_SWITCH_ID_6320_A1 0x1151 +#define PORT_SWITCH_ID_6320_A2 0x1152 +#define PORT_SWITCH_ID_6321 0x3100 +#define PORT_SWITCH_ID_6321_A1 0x3101 +#define PORT_SWITCH_ID_6321_A2 0x3102 #define PORT_SWITCH_ID_6350 0x3710 #define PORT_SWITCH_ID_6351 0x3750 #define PORT_SWITCH_ID_6352 0x3520 @@ -410,6 +415,7 @@ int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg); int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, int reg, int val); +bool mv88e6xxx_6320_family(struct dsa_switch *ds); extern struct dsa_switch_driver mv88e6131_switch_driver; extern struct dsa_switch_driver mv88e6123_61_65_switch_driver; extern struct dsa_switch_driver mv88e6352_switch_driver; -- cgit v1.3-6-gb490 From 44eda784a2229d25e2724ef1734fe67453716231 Mon Sep 17 00:00:00 2001 From: Ellen Wang Date: Thu, 9 Jul 2015 21:55:06 -0700 Subject: HID: cp2112: support i2c write-read transfers in hid-cp2112 cp2112_i2c_xfer() only supports a single i2c_msg. More than one message at a time just returns EIO. This breaks certain important cases. For example, the at24 eeprom driver generates paired write and read messages (for eeprom address and data). Since the device doesn't support i2c repeated starts in general, but does support a single write-repeated-start-read pair (since hardware rev 1), we recognize the latter case and implement only that. Signed-off-by: Ellen Wang Signed-off-by: Jiri Kosina --- drivers/hid/hid-cp2112.c | 74 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 75398cb84fde..1d24a65b4295 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -156,6 +156,7 @@ struct cp2112_device { wait_queue_head_t wait; u8 read_data[61]; u8 read_length; + u8 hwversion; int xfer_status; atomic_t read_avail; atomic_t xfer_avail; @@ -446,6 +447,24 @@ static int cp2112_i2c_write_req(void *buf, u8 slave_address, u8 *data, return data_length + 3; } +static int cp2112_i2c_write_read_req(void *buf, u8 slave_address, + u8 *addr, int addr_length, + int read_length) +{ + struct cp2112_write_read_req_report *report = buf; + + if (read_length < 1 || read_length > 512 || + addr_length > sizeof(report->target_address)) + return -EINVAL; + + report->report = CP2112_DATA_WRITE_READ_REQUEST; + report->slave_address = slave_address << 1; + report->length = cpu_to_be16(read_length); + report->target_address_length = addr_length; + memcpy(report->target_address, addr, addr_length); + return addr_length + 5; +} + static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { @@ -453,26 +472,46 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, struct hid_device *hdev = dev->hdev; u8 buf[64]; ssize_t count; + ssize_t read_length = 0; + u8 *read_buf = NULL; unsigned int retries; int ret; hid_dbg(hdev, "I2C %d messages\n", num); - if (num != 1) { + if (num == 1) { + if (msgs->flags & I2C_M_RD) { + hid_dbg(hdev, "I2C read %#04x len %d\n", + msgs->addr, msgs->len); + read_length = msgs->len; + read_buf = msgs->buf; + count = cp2112_read_req(buf, msgs->addr, msgs->len); + } else { + hid_dbg(hdev, "I2C write %#04x len %d\n", + msgs->addr, msgs->len); + count = cp2112_i2c_write_req(buf, msgs->addr, + msgs->buf, msgs->len); + } + if (count < 0) + return count; + } else if (dev->hwversion > 1 && /* no repeated start in rev 1 */ + num == 2 && + msgs[0].addr == msgs[1].addr && + !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) { + hid_dbg(hdev, "I2C write-read %#04x wlen %d rlen %d\n", + msgs[0].addr, msgs[0].len, msgs[1].len); + read_length = msgs[1].len; + read_buf = msgs[1].buf; + count = cp2112_i2c_write_read_req(buf, msgs[0].addr, + msgs[0].buf, msgs[0].len, msgs[1].len); + if (count < 0) + return count; + } else { hid_err(hdev, "Multi-message I2C transactions not supported\n"); return -EOPNOTSUPP; } - if (msgs->flags & I2C_M_RD) - count = cp2112_read_req(buf, msgs->addr, msgs->len); - else - count = cp2112_i2c_write_req(buf, msgs->addr, msgs->buf, - msgs->len); - - if (count < 0) - return count; - ret = hid_hw_power(hdev, PM_HINT_FULLON); if (ret < 0) { hid_err(hdev, "power management error: %d\n", ret); @@ -508,11 +547,8 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, goto power_normal; } - if (!(msgs->flags & I2C_M_RD)) - goto finish; - - for (count = 0; count < msgs->len;) { - ret = cp2112_read(dev, msgs->buf + count, msgs->len - count); + for (count = 0; count < read_length;) { + ret = cp2112_read(dev, read_buf + count, read_length - count); if (ret < 0) goto power_normal; if (ret == 0) { @@ -521,7 +557,7 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, goto power_normal; } count += ret; - if (count > msgs->len) { + if (count > read_length) { /* * The hardware returned too much data. * This is mostly harmless because cp2112_read() @@ -531,15 +567,14 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, * it shouldn't go unnoticed. */ hid_err(hdev, "long read: %d > %zd\n", - ret, msgs->len - count + ret); + ret, read_length - count + ret); ret = -EIO; goto power_normal; } } -finish: /* return the number of transferred messages */ - ret = 1; + ret = num; power_normal: hid_hw_power(hdev, PM_HINT_NORMAL); @@ -1047,6 +1082,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) dev->adap.dev.parent = &hdev->dev; snprintf(dev->adap.name, sizeof(dev->adap.name), "CP2112 SMBus Bridge on hiddev%d", hdev->minor); + dev->hwversion = buf[2]; init_waitqueue_head(&dev->wait); hid_device_io_start(hdev); -- cgit v1.3-6-gb490 From 3eb4351af42bd8b6de20daab07b204a85c35248f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 9 Jul 2015 14:33:21 -0700 Subject: HID: input: call input_sync() when automatically releasing a key We need to emit EV_SYN/SYN_REPORT between key press and release, otherwise userspace is allowed to "swallow" the event. [jkosina@suse.com: Dmitry says that he's observing this behavior with Plantronics headset] Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 3511bbaba505..14aebe483219 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1163,8 +1163,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct input_event(input, usage->type, usage->code, value); - if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) + if ((field->flags & HID_MAIN_ITEM_RELATIVE) && + usage->type == EV_KEY && value) { + input_sync(input); input_event(input, usage->type, usage->code, 0); + } } void hidinput_report_event(struct hid_device *hid, struct hid_report *report) -- cgit v1.3-6-gb490 From 7ff0589c7bff4ca31b255ac2028f633f14047762 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:22 +0000 Subject: regmap: add force_write option on _regmap_update_bits() Sometimes we want to write data even though it doesn't change value. Then, force_write option on _regmap_update_bits() helps this purpose. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7111d04f2621..69ec411ce722 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -34,7 +34,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, - bool *change); + bool *change, bool force_write); static int _regmap_bus_reg_read(void *context, unsigned int reg, unsigned int *val); @@ -1178,7 +1178,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, ret = _regmap_update_bits(map, range->selector_reg, range->selector_mask, win_page << range->selector_shift, - &page_chg); + &page_chg, false); map->work_buf = orig_work_buf; @@ -2327,7 +2327,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_read); static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, - bool *change) + bool *change, bool force_write) { int ret; unsigned int tmp, orig; @@ -2339,7 +2339,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, tmp = orig & ~mask; tmp |= val & mask; - if (tmp != orig) { + if (force_write || (tmp != orig)) { ret = _regmap_write(map, reg, tmp); if (change) *change = true; @@ -2367,7 +2367,7 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, int ret; map->lock(map->lock_arg); - ret = _regmap_update_bits(map, reg, mask, val, NULL); + ret = _regmap_update_bits(map, reg, mask, val, NULL, false); map->unlock(map->lock_arg); return ret; @@ -2398,7 +2398,7 @@ int regmap_update_bits_async(struct regmap *map, unsigned int reg, map->async = true; - ret = _regmap_update_bits(map, reg, mask, val, NULL); + ret = _regmap_update_bits(map, reg, mask, val, NULL, false); map->async = false; @@ -2427,7 +2427,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, int ret; map->lock(map->lock_arg); - ret = _regmap_update_bits(map, reg, mask, val, change); + ret = _regmap_update_bits(map, reg, mask, val, change, false); map->unlock(map->lock_arg); return ret; } @@ -2460,7 +2460,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, map->async = true; - ret = _regmap_update_bits(map, reg, mask, val, change); + ret = _regmap_update_bits(map, reg, mask, val, change, false); map->async = false; -- cgit v1.3-6-gb490 From fd4b7286ccc469bf5dde22db6b8fcc455c3c4a66 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:39 +0000 Subject: regmap: add regmap_write_bits() regmap_write_bits() is similar to regmap_update_bits(), but regmap_write_bits() write data to register even though it is same value. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 23 +++++++++++++++++++++++ include/linux/regmap.h | 9 +++++++++ 2 files changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 69ec411ce722..d93bb9a8ab98 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2374,6 +2374,29 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, } EXPORT_SYMBOL_GPL(regmap_update_bits); +/** + * regmap_write_bits: Perform a read/modify/write cycle on the register map + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * + * Returns zero for success, a negative number on error. + */ +int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + int ret; + + map->lock(map->lock_arg); + ret = _regmap_update_bits(map, reg, mask, val, NULL, true); + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_write_bits); + /** * regmap_update_bits_async: Perform a read/modify/write cycle on the register * map asynchronously diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 59c55ea0f0b5..e4b9ad4f05ef 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -424,6 +424,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, size_t val_count); int regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); +int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val); int regmap_update_bits_async(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); int regmap_update_bits_check(struct regmap *map, unsigned int reg, @@ -645,6 +647,13 @@ static inline int regmap_update_bits(struct regmap *map, unsigned int reg, return -EINVAL; } +static inline int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_update_bits_async(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val) -- cgit v1.3-6-gb490 From e874e6c7edc43436f73cf84157d9221f8b807c36 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:55 +0000 Subject: regmap: add regmap_fields_force_write() regmap_fields_force_write() is similar to regmap_fields_write(), but regmap_fields_force_write() write data to register even though it is same value. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 12 ++++++++++++ include/linux/regmap.h | 2 ++ 2 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index d93bb9a8ab98..dd63bcbbf8a5 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1624,6 +1624,18 @@ int regmap_fields_write(struct regmap_field *field, unsigned int id, } EXPORT_SYMBOL_GPL(regmap_fields_write); +int regmap_fields_force_write(struct regmap_field *field, unsigned int id, + unsigned int val) +{ + if (id >= field->id_size) + return -EINVAL; + + return regmap_write_bits(field->regmap, + field->reg + (field->id_offset * id), + field->mask, val << field->shift); +} +EXPORT_SYMBOL_GPL(regmap_fields_force_write); + /** * regmap_fields_update_bits(): Perform a read/modify/write cycle * on the register field diff --git a/include/linux/regmap.h b/include/linux/regmap.h index e4b9ad4f05ef..519c96231a91 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -505,6 +505,8 @@ int regmap_field_update_bits(struct regmap_field *field, int regmap_fields_write(struct regmap_field *field, unsigned int id, unsigned int val); +int regmap_fields_force_write(struct regmap_field *field, unsigned int id, + unsigned int val); int regmap_fields_read(struct regmap_field *field, unsigned int id, unsigned int *val); int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, -- cgit v1.3-6-gb490 From ca12bb14fee138603d17b1d68906abeebaa09b30 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:47:23 +0900 Subject: EDAC, xgene: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Cc: linux-edac Cc: Loc Ho Cc: Mauro Carvalho Chehab Link: http://lkml.kernel.org/r/1436507243-11159-1-git-send-email-k.kozlowski@samsung.com Signed-off-by: Borislav Petkov --- drivers/edac/xgene_edac.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c index 14636e4b6a08..ba06904af2e1 100644 --- a/drivers/edac/xgene_edac.c +++ b/drivers/edac/xgene_edac.c @@ -1168,7 +1168,6 @@ static struct platform_driver xgene_edac_driver = { .remove = xgene_edac_remove, .driver = { .name = "xgene-edac", - .owner = THIS_MODULE, .of_match_table = xgene_edac_of_match, }, }; -- cgit v1.3-6-gb490 From 3fd4079fe295b91cd1f4330e3c8f1e6e4618a27d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:29:45 +0900 Subject: soc: mediatek: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Acked-by: Sascha Hauer Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index f432291feee9..8bc7b41b09fd 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -926,7 +926,6 @@ err_out1: static struct platform_driver pwrap_drv = { .driver = { .name = "mt-pmic-pwrap", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(of_pwrap_match_tbl), }, .probe = pwrap_probe, -- cgit v1.3-6-gb490 From f293634b5a9e9acbcc1cac29fac7609bd999f868 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 10 Jul 2015 08:45:34 +0100 Subject: regulator: pwm-regulator: Fix 'unused-variable' warning drivers/regulator/pwm-regulator.c: In function 'pwm_regulator_init_continuous': drivers/regulator/pwm-regulator.c:202:22: warning: unused variable 'np' [-Wunused-variable] struct device_node *np = pdev->dev.of_node; ^ Reported-by: kbuild test robot Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 936e387cc532..a4c2ce92d41f 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -198,8 +198,6 @@ static int pwm_regulator_init_table(struct platform_device *pdev, static int pwm_regulator_init_continuous(struct platform_device *pdev, struct pwm_regulator_data *drvdata) { - struct device_node *np = pdev->dev.of_node; - pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops; pwm_regulator_desc.continuous_voltage_range = true; -- cgit v1.3-6-gb490 From b343e08f3c5623d12829ad4965dd4c4e50f86fa2 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 10 Jul 2015 08:45:35 +0100 Subject: regulator: pwm-regulator: Fix 'used uninitialized' warning drivers/regulator/pwm-regulator.c: In function 'pwm_regulator_init_table': drivers/regulator/pwm-regulator.c:172:14: warning: 'length' is used uninitialized in this function [-Wuninitialized] if ((length < sizeof(*duty_cycle_table)) || ^ Reported-by: kbuild test robot Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index a4c2ce92d41f..331b85148680 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -163,7 +163,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev, { struct device_node *np = pdev->dev.of_node; struct pwm_voltages *duty_cycle_table; - int length; + int length = 0; int ret; of_find_property(np, "voltage-table", &length); -- cgit v1.3-6-gb490 From 60cb65ebf49e6db114c3efeb3971064a6ddbea0e Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 10 Jul 2015 08:45:36 +0100 Subject: regulator: pwm-regulator: Fix ' comparison between signed and unsigned integer' warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/regulator/pwm-regulator.c: In function ‘pwm_regulator_init_table’: drivers/regulator/pwm-regulator.c:171:14: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 331b85148680..fc3166dfcbfa 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -163,7 +163,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev, { struct device_node *np = pdev->dev.of_node; struct pwm_voltages *duty_cycle_table; - int length = 0; + unsigned int length = 0; int ret; of_find_property(np, "voltage-table", &length); -- cgit v1.3-6-gb490 From 634ec36cc0ab9d8dda0f2c101fa28d2e2a61b9eb Mon Sep 17 00:00:00 2001 From: David Thomson Date: Fri, 10 Jul 2015 13:56:54 +1200 Subject: net: phy: Pass mdix ethtool setting through to phy driver Pass the mdix setting from ethtool down to the phy driver, to allow driver specific implementations of manually setting the polarity. Signed-off-by: David Thomson Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 2 ++ include/linux/phy.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index b2197b506acb..47693a9ebd3a 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -353,6 +353,8 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) phydev->duplex = cmd->duplex; + phydev->mdix = cmd->eth_tp_mdix_ctrl; + /* Restart the PHY */ phy_start_aneg(phydev); diff --git a/include/linux/phy.h b/include/linux/phy.h index a26c3f84b8dd..e5fb1d415961 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -424,6 +424,8 @@ struct phy_device { struct net_device *attached_dev; + u8 mdix; + void (*adjust_link)(struct net_device *dev); }; #define to_phy_device(d) container_of(d, struct phy_device, dev) -- cgit v1.3-6-gb490 From 239aa55b9496144f89670b545b5698e6c989f710 Mon Sep 17 00:00:00 2001 From: David Thomson Date: Fri, 10 Jul 2015 16:28:25 +1200 Subject: net: phy: Support setting polarity in marvell phy driver Support manually setting the polarity to mdi or mdix Signed-off-by: David Thomson Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 42 ++++++++++++++++++++++++++++++++++++++++-- drivers/net/phy/phy.c | 1 + 2 files changed, 41 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index f721444c2b0a..3320a179ee36 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -48,6 +48,8 @@ #define MII_M1011_IMASK_CLEAR 0x0000 #define MII_M1011_PHY_SCR 0x10 +#define MII_M1011_PHY_SCR_MDI 0x0000 +#define MII_M1011_PHY_SCR_MDI_X 0x0020 #define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 #define MII_M1145_PHY_EXT_SR 0x1b @@ -159,6 +161,43 @@ static int marvell_config_intr(struct phy_device *phydev) return err; } +static int marvell_set_polarity(struct phy_device *phydev, int polarity) +{ + int reg; + int err; + int val; + + /* get the current settings */ + reg = phy_read(phydev, MII_M1011_PHY_SCR); + if (reg < 0) + return reg; + + val = reg; + val &= ~MII_M1011_PHY_SCR_AUTO_CROSS; + switch (polarity) { + case ETH_TP_MDI: + val |= MII_M1011_PHY_SCR_MDI; + break; + case ETH_TP_MDI_X: + val |= MII_M1011_PHY_SCR_MDI_X; + break; + case ETH_TP_MDI_AUTO: + case ETH_TP_MDI_INVALID: + default: + val |= MII_M1011_PHY_SCR_AUTO_CROSS; + break; + } + + if (val != reg) { + /* Set the new polarity value in the register */ + err = phy_write(phydev, MII_M1011_PHY_SCR, val); + if (err) + return err; + } + + return 0; +} + static int marvell_config_aneg(struct phy_device *phydev) { int err; @@ -191,8 +230,7 @@ static int marvell_config_aneg(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_M1011_PHY_SCR, - MII_M1011_PHY_SCR_AUTO_CROSS); + err = marvell_set_polarity(phydev, phydev->mdix); if (err < 0) return err; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 47693a9ebd3a..84b1fba58ac3 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -379,6 +379,7 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) cmd->transceiver = phy_is_internal(phydev) ? XCVR_INTERNAL : XCVR_EXTERNAL; cmd->autoneg = phydev->autoneg; + cmd->eth_tp_mdix_ctrl = phydev->mdix; return 0; } -- cgit v1.3-6-gb490 From 6979b9cf58c86d14ceb1702b5b3fa4f63c98c013 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:29:23 +0900 Subject: net: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hip04_eth.c | 1 - drivers/net/ethernet/hisilicon/hip04_mdio.c | 1 - drivers/net/ethernet/ti/netcp_core.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index d49bee38cd31..cc2d8b4b18e3 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -965,7 +965,6 @@ static struct platform_driver hip04_mac_driver = { .remove = hip04_remove, .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .of_match_table = hip04_mac_match, }, }; diff --git a/drivers/net/ethernet/hisilicon/hip04_mdio.c b/drivers/net/ethernet/hisilicon/hip04_mdio.c index b3bac25db99c..fca0a5be1f0f 100644 --- a/drivers/net/ethernet/hisilicon/hip04_mdio.c +++ b/drivers/net/ethernet/hisilicon/hip04_mdio.c @@ -174,7 +174,6 @@ static struct platform_driver hip04_mdio_driver = { .remove = hip04_mdio_remove, .driver = { .name = "hip04-mdio", - .owner = THIS_MODULE, .of_match_table = hip04_mdio_match, }, }; diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c index 5ec4ed3f6c8d..3e47202b9010 100644 --- a/drivers/net/ethernet/ti/netcp_core.c +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -2142,7 +2142,6 @@ MODULE_DEVICE_TABLE(of, of_match); static struct platform_driver netcp_driver = { .driver = { .name = "netcp-1.0", - .owner = THIS_MODULE, .of_match_table = of_match, }, .probe = netcp_probe, -- cgit v1.3-6-gb490 From 145155e786ccee898f6ed665f6dd3bce7c14830f Mon Sep 17 00:00:00 2001 From: Kalesh Purayil Date: Fri, 10 Jul 2015 05:32:43 -0400 Subject: be2net: remove duplicate code in be_setup_wol() This change will make be_setup_wol() routine more compact and readable by removing some duplicate code. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 6f642426308c..635c62fa319c 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3529,15 +3529,15 @@ err: static int be_setup_wol(struct be_adapter *adapter, bool enable) { + struct device *dev = &adapter->pdev->dev; struct be_dma_mem cmd; - int status = 0; u8 mac[ETH_ALEN]; + int status; eth_zero_addr(mac); cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config); - cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, - GFP_KERNEL); + cmd.va = dma_zalloc_coherent(dev, cmd.size, &cmd.dma, GFP_KERNEL); if (!cmd.va) return -ENOMEM; @@ -3546,24 +3546,18 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) PCICFG_PM_CONTROL_OFFSET, PCICFG_PM_CONTROL_MASK); if (status) { - dev_err(&adapter->pdev->dev, - "Could not enable Wake-on-lan\n"); - dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, - cmd.dma); - return status; + dev_err(dev, "Could not enable Wake-on-lan\n"); + goto err; } - status = be_cmd_enable_magic_wol(adapter, - adapter->netdev->dev_addr, - &cmd); - pci_enable_wake(adapter->pdev, PCI_D3hot, 1); - pci_enable_wake(adapter->pdev, PCI_D3cold, 1); } else { - status = be_cmd_enable_magic_wol(adapter, mac, &cmd); - pci_enable_wake(adapter->pdev, PCI_D3hot, 0); - pci_enable_wake(adapter->pdev, PCI_D3cold, 0); + ether_addr_copy(mac, adapter->netdev->dev_addr); } - dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma); + status = be_cmd_enable_magic_wol(adapter, mac, &cmd); + pci_enable_wake(adapter->pdev, PCI_D3hot, enable); + pci_enable_wake(adapter->pdev, PCI_D3cold, enable); +err: + dma_free_coherent(dev, cmd.size, cmd.va, cmd.dma); return status; } -- cgit v1.3-6-gb490 From ff9ed19d263d9678394b6ac079abd68efb3c55c0 Mon Sep 17 00:00:00 2001 From: Kalesh Purayil Date: Fri, 10 Jul 2015 05:32:44 -0400 Subject: be2net: query FW to check if EVB is enabled The current code assumes that bridge functionality (EVB) in the adapter is enabled only when SR-IOV is enabled. This is not always true. This patch uses the GET_HSW_CONFIG FW cmd to query this from the FW. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.h | 1 + drivers/net/ethernet/emulex/benet/be_main.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 2716e6f30d9a..f0a92b7e4e7d 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1758,6 +1758,7 @@ struct be_cmd_req_set_mac_list { /*********************** HSW Config ***********************/ #define PORT_FWD_TYPE_VEPA 0x3 #define PORT_FWD_TYPE_VEB 0x2 +#define PORT_FWD_TYPE_PASSTHRU 0x1 #define ENABLE_MAC_SPOOFCHK 0x2 #define DISABLE_MAC_SPOOFCHK 0x3 diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 635c62fa319c..f21c56abd5c2 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -5073,9 +5073,6 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, int status = 0; u8 hsw_mode; - if (!sriov_enabled(adapter)) - return 0; - /* BE and Lancer chips support VEB mode only */ if (BEx_chip(adapter) || lancer_chip(adapter)) { hsw_mode = PORT_FWD_TYPE_VEB; @@ -5085,6 +5082,9 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, NULL); if (status) return 0; + + if (hsw_mode == PORT_FWD_TYPE_PASSTHRU) + return 0; } return ndo_dflt_bridge_getlink(skb, pid, seq, dev, -- cgit v1.3-6-gb490 From bc23d6b7ab051106b700869e7ee09e8aec6864f2 Mon Sep 17 00:00:00 2001 From: Kalesh Purayil Date: Fri, 10 Jul 2015 05:32:45 -0400 Subject: be2net: remove redundant D0 power state set pci_enable_device() call sets device power state to D0; there is no need doing it again. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index f21c56abd5c2..8b81e23ae9ba 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -5807,7 +5807,6 @@ static int be_pci_resume(struct pci_dev *pdev) if (status) return status; - pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); status = be_resume(adapter); @@ -5887,7 +5886,6 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_DISCONNECT; pci_set_master(pdev); - pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); /* Check if card is ok and fw is ready */ -- cgit v1.3-6-gb490 From 887a65c4ab1511a9afc8a20e5507bec3d074f867 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Fri, 10 Jul 2015 05:32:46 -0400 Subject: be2net: fix wrong return value in be_check_ufi_compatibility() In the commit a6e6ff6eee12f3e ("be2net: simplify UFI compatibility checking"), a return value of "-1" was incorrectly used in place of "false". This patch fixes it. Fixes: a6e6ff6eee12f3e ("be2net: simplify UFI compatibility checking") Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 8b81e23ae9ba..8ef7ea5d8f4a 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4918,7 +4918,7 @@ static bool be_check_ufi_compatibility(struct be_adapter *adapter, { if (!fhdr) { dev_err(&adapter->pdev->dev, "Invalid FW UFI file"); - return -1; + return false; } /* First letter of the build version is used to identify -- cgit v1.3-6-gb490 From 1645d99768e00d3148ebded5d8c4ab55cdb19a5c Mon Sep 17 00:00:00 2001 From: Venkat Duvvuru Date: Fri, 10 Jul 2015 05:32:47 -0400 Subject: be2net: convert dest field in udp-hdr to host-endian The "dest" field in the UDP-hdr of a TX skb is in network endian format. Convert it to host endian before accessing it. The os2bmc patch, mentioned below introduced this code. Fixes: 760c295e0e8d ("be2net: Support for OS2BMC") Signed-off-by: Venkat Duvvuru Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 8ef7ea5d8f4a..c996dd76f546 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1254,7 +1254,7 @@ static bool be_send_pkt_to_bmc(struct be_adapter *adapter, if (is_udp_pkt((*skb))) { struct udphdr *udp = udp_hdr((*skb)); - switch (udp->dest) { + switch (ntohs(udp->dest)) { case DHCP_CLIENT_PORT: os2bmc = is_dhcp_client_filt_enabled(adapter); goto done; -- cgit v1.3-6-gb490 From efaa408e964012225897e87d9aad97a4d0ebc1d5 Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Fri, 10 Jul 2015 05:32:48 -0400 Subject: be2net: return error status from be_mcc_notify() When the adapter is in error state, return error from be_mcc_notify() so that the caller routines need not sleep waiting for a response. Signed-off-by: Suresh Reddy Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 39 +++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 9eac3227d2ca..a299f7bca7ba 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -88,19 +88,21 @@ static inline void *embedded_payload(struct be_mcc_wrb *wrb) return wrb->payload.embedded_payload; } -static void be_mcc_notify(struct be_adapter *adapter) +static int be_mcc_notify(struct be_adapter *adapter) { struct be_queue_info *mccq = &adapter->mcc_obj.q; u32 val = 0; if (be_check_error(adapter, BE_ERROR_ANY)) - return; + return -EIO; val |= mccq->id & DB_MCCQ_RING_ID_MASK; val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; wmb(); iowrite32(val, adapter->db + DB_MCCQ_OFFSET); + + return 0; } /* To check if valid bit is set, check the entire word as we don't know @@ -541,7 +543,9 @@ static int be_mcc_notify_wait(struct be_adapter *adapter) resp = be_decode_resp_hdr(wrb->tag0, wrb->tag1); - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto out; status = be_mcc_wait_compl(adapter); if (status == -EIO) @@ -1547,7 +1551,10 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) else hdr->version = 2; - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto err; + adapter->stats_cmd_sent = true; err: @@ -1583,7 +1590,10 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter, req->cmd_params.params.pport_num = cpu_to_le16(adapter->hba_port_num); req->cmd_params.params.reset_stats = 0; - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto err; + adapter->stats_cmd_sent = true; err: @@ -1687,8 +1697,7 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter) OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req), wrb, NULL); - be_mcc_notify(adapter); - + status = be_mcc_notify(adapter); err: spin_unlock_bh(&adapter->mcc_lock); return status; @@ -1860,7 +1869,7 @@ static int __be_cmd_modify_eqd(struct be_adapter *adapter, cpu_to_le32(set_eqd[i].delay_multiplier); } - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); err: spin_unlock_bh(&adapter->mcc_lock); return status; @@ -2320,7 +2329,10 @@ int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma + sizeof(struct lancer_cmd_req_write_object))); - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto err_unlock; + spin_unlock_bh(&adapter->mcc_lock); if (!wait_for_completion_timeout(&adapter->et_cmd_compl, @@ -2491,7 +2503,10 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, req->params.op_code = cpu_to_le32(flash_opcode); req->params.data_buf_size = cpu_to_le32(buf_size); - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto err_unlock; + spin_unlock_bh(&adapter->mcc_lock); if (!wait_for_completion_timeout(&adapter->et_cmd_compl, @@ -2636,7 +2651,9 @@ int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, req->num_pkts = cpu_to_le32(num_pkts); req->loopback_type = cpu_to_le32(loopback_type); - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto err; spin_unlock_bh(&adapter->mcc_lock); -- cgit v1.3-6-gb490 From 8af65c2f4deeb02a128c5cf29fa351b70bf16424 Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Fri, 10 Jul 2015 05:32:49 -0400 Subject: be2net: make the RX_FILTER command asynchronous This fix makes the RX_FILTER cmd asynchronous, i.e., the caller issues this cmd and doesn't wait for a completion from the FW. If the FW/adapter is in an error state, this change helps in not holding up the rtnl_lock and keeping bottom halves disabled while the driver timesout waiting for a response from the FW. Signed-off-by: Suresh Reddy Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index a299f7bca7ba..93934d347a23 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1962,7 +1962,7 @@ static int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN); } - status = be_mcc_notify_wait(adapter); + status = be_mcc_notify(adapter); err: spin_unlock_bh(&adapter->mcc_lock); return status; -- cgit v1.3-6-gb490 From 9c8559750cd7b7936dd38810fc2110fc91d7d527 Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Fri, 10 Jul 2015 05:32:50 -0400 Subject: be2net: make SET_LOOPBACK_MODE cmd asynchrounous The SET_LOOPBACK_MODE command is always issued from ethtool only in a process context. So, while waiting for the cmd to complete, the driver can sleep instead of holding spin_lock_bh() on the mcc_lock. This is done by calling be_mcc_notify() instead of be_mcc_notify_wait() (that returns only after the cmd completes while the MCCQ is locked). Signed-off-by: Suresh Reddy Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 23 ++++++++++++++++++++--- drivers/net/ethernet/emulex/benet/be_cmds.h | 2 ++ drivers/net/ethernet/emulex/benet/be_ethtool.c | 15 +++++++++++++-- 3 files changed, 35 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 93934d347a23..ecad46f79653 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -172,6 +172,12 @@ static void be_async_cmd_process(struct be_adapter *adapter, return; } + if (opcode == OPCODE_LOWLEVEL_SET_LOOPBACK_MODE && + subsystem == CMD_SUBSYSTEM_LOWLEVEL) { + complete(&adapter->et_cmd_compl); + return; + } + if ((opcode == OPCODE_COMMON_WRITE_FLASHROM || opcode == OPCODE_COMMON_WRITE_OBJECT) && subsystem == CMD_SUBSYSTEM_COMMON) { @@ -2600,7 +2606,7 @@ int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, wrb = wrb_from_mccq(adapter); if (!wrb) { status = -EBUSY; - goto err; + goto err_unlock; } req = embedded_payload(wrb); @@ -2614,8 +2620,19 @@ int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, req->loopback_type = loopback_type; req->loopback_state = enable; - status = be_mcc_notify_wait(adapter); -err: + status = be_mcc_notify(adapter); + if (status) + goto err_unlock; + + spin_unlock_bh(&adapter->mcc_lock); + + if (!wait_for_completion_timeout(&adapter->et_cmd_compl, + msecs_to_jiffies(SET_LB_MODE_TIMEOUT))) + status = -ETIMEDOUT; + + return status; + +err_unlock: spin_unlock_bh(&adapter->mcc_lock); return status; } diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index f0a92b7e4e7d..a4479f7488d3 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1495,6 +1495,8 @@ struct be_cmd_resp_acpi_wol_magic_config_v1 { #define BE_PME_D3COLD_CAP 0x80 /********************** LoopBack test *********************/ +#define SET_LB_MODE_TIMEOUT 12000 + struct be_cmd_req_loopback_test { struct be_cmd_req_hdr hdr; u32 loopback_type; diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index b2476dbfd103..d20ff054c1f7 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -847,10 +847,21 @@ err: static u64 be_loopback_test(struct be_adapter *adapter, u8 loopback_type, u64 *status) { - be_cmd_set_loopback(adapter, adapter->hba_port_num, loopback_type, 1); + int ret; + + ret = be_cmd_set_loopback(adapter, adapter->hba_port_num, + loopback_type, 1); + if (ret) + return ret; + *status = be_cmd_loopback_test(adapter, adapter->hba_port_num, loopback_type, 1500, 2, 0xabc); - be_cmd_set_loopback(adapter, adapter->hba_port_num, BE_NO_LOOPBACK, 1); + + ret = be_cmd_set_loopback(adapter, adapter->hba_port_num, + BE_NO_LOOPBACK, 1); + if (ret) + return ret; + return *status; } -- cgit v1.3-6-gb490 From a78dfcb38492ccc127023e9ee3a35d214009b02f Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Fri, 10 Jul 2015 05:32:51 -0400 Subject: be2net: bump up the driver version to 10.6.0.3 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(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 8d12b41b3b19..cb5777bb7429 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -37,7 +37,7 @@ #include "be_hw.h" #include "be_roce.h" -#define DRV_VER "10.6.0.2" +#define DRV_VER "10.6.0.3" #define DRV_NAME "be2net" #define BE_NAME "Emulex BladeEngine2" #define BE3_NAME "Emulex BladeEngine3" -- cgit v1.3-6-gb490 From a052158aa981ca470673f49c636b289ee16894ea Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Fri, 3 Jul 2015 15:33:49 +0200 Subject: ath10k: fix QCA61X4 boot up commit a521ee983d312db7 ("ath10k: Add new reg_address/mask to hw register table") broke QCA61x4 support by providing wrong fw_indicator_address, which should have been 0x0003a028 instead of 0x00009028. User experience was a failing boot up sequence (crashing device during initialization): [ 181.663874] ath10k_pci 0000:02:00.0: enabling device (0000 -> 0002) [ 181.664787] ath10k_pci 0000:02:00.0: pci irq msi-x interrupts 8 irq_mode 0 reset_mode 0 [ 181.688886] ath10k_pci 0000:02:00.0: device has crashed during init [ 181.688897] ath10k_pci 0000:02:00.0: failed to wait for target after cold reset: -70 [ 181.688902] ath10k_pci 0000:02:00.0: failed to reset chip: -70 [ 181.689774] ath10k_pci: probe of 0000:02:00.0 failed with error -70 Fix it by updating the address with correct value. Fixes: a521ee983d31 ("ath10k: Add new reg_address/mask to hw register table") Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 1414e1f3c7ac..fef7ccf6e185 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -63,7 +63,7 @@ const struct ath10k_hw_regs qca6174_regs = { .soc_reset_control_ce_rst_mask = 0x00000001, .soc_chip_id_address = 0x000000f0, .scratch_3_address = 0x00000028, - .fw_indicator_address = 0x00009028, + .fw_indicator_address = 0x0003a028, .pcie_local_base_address = 0x00080000, .ce_wrap_intr_sum_host_msi_lsb = 0x00000008, .ce_wrap_intr_sum_host_msi_mask = 0x0000ff00, -- cgit v1.3-6-gb490 From 3c7e256a6de378e01098147527082abae05b146e Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 3 Jul 2015 19:25:27 +0530 Subject: ath10k: Fix target to cpu address conversion logic In commit 418ca5992e2f ("ath10k: Make target cpu address to CE address conversion chip specific") mask 0x7fff is added by mistake instead of 0x7ff. Fix this regression. Fixes: 418ca5992e2f ("ath10k: Make target cpu address to CE address conversion chip specific") Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 1b4634a6374d..5778e5277823 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -765,7 +765,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) case ATH10K_HW_QCA6174: val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS) & - 0x7fff) << 21; + 0x7ff) << 21; break; case ATH10K_HW_QCA99X0: val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS); -- cgit v1.3-6-gb490 From 835d56a10c1fcfb0fee28bb6aceb722e1a6f643a Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:34 +0200 Subject: ath10k: don't set cck/ofdm scan flags mac80211 already does provide complete IEs for Probe Requests for hw scan and ath10k firmware was appending duplicate Supported Rates IEs unnecessarily. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 --- drivers/net/wireless/ath/ath10k/wmi.c | 1 - 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0f3c17c0c8f8..1a3368dc98a1 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4641,9 +4641,6 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, arg.vdev_id = arvif->vdev_id; arg.scan_id = ATH10K_SCAN_ID; - if (!req->no_cck) - arg.scan_ctrl_flags |= WMI_SCAN_ADD_CCK_RATES; - if (req->ie_len) { arg.ie_len = req->ie_len; memcpy(arg.ie, req->ie, arg.ie_len); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 638332e96931..0791a4336e80 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5180,7 +5180,6 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar, | WMI_SCAN_EVENT_BSS_CHANNEL | WMI_SCAN_EVENT_FOREIGN_CHANNEL | WMI_SCAN_EVENT_DEQUEUED; - arg->scan_ctrl_flags |= WMI_SCAN_ADD_OFDM_RATES; arg->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT; arg->n_bssids = 1; arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF"; -- cgit v1.3-6-gb490 From 424f26301467daf241a4afe4b6fe82750d4ac624 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:35 +0200 Subject: ath10k: limit multi-vif ps more aggresivelly Further testing proved that multi-channel AP+STA on QCA6174 with RM.2.0-00088 should have powersave force-disabled to avoid beacon misses/skipping on either side which in turn could disrupt communication. Since AP never has arvif->ps don't even bother checking it. Other combinations may be broken as well so disallow powersave with multivif outright unless firmware advertises otherwise. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1a3368dc98a1..c08ad1d994cd 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1668,7 +1668,7 @@ static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif) return 0; } -static int ath10k_mac_ps_vif_count(struct ath10k *ar) +static int ath10k_mac_num_vifs_started(struct ath10k *ar) { struct ath10k_vif *arvif; int num = 0; @@ -1676,7 +1676,7 @@ static int ath10k_mac_ps_vif_count(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); list_for_each_entry(arvif, &ar->arvifs, list) - if (arvif->ps) + if (arvif->is_started) num++; return num; @@ -1700,7 +1700,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) enable_ps = arvif->ps; - if (enable_ps && ath10k_mac_ps_vif_count(ar) > 1 && + if (enable_ps && ath10k_mac_num_vifs_started(ar) > 1 && !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT, ar->fw_features)) { ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n", -- cgit v1.3-6-gb490 From d710e75d1050cb66fbf6e906addb4a661e444729 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:36 +0200 Subject: ath10k: fix hw roc expiration notifcation The expiration function must not be called when roc is explicitly cancelled by mac80211. However since fcf9844636be ("ath10k: fix hw roc expiration") the notification was never sent when roc actually expired. This fixes some P2P connection setup issues. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 2e5c935579c4..78e07051b897 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -633,6 +633,7 @@ struct ath10k { bool is_roc; int vdev_id; int roc_freq; + bool roc_notify; } scan; struct { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c08ad1d994cd..b842612e0b61 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3449,14 +3449,13 @@ void __ath10k_scan_finish(struct ath10k *ar) case ATH10K_SCAN_IDLE: break; case ATH10K_SCAN_RUNNING: - if (ar->scan.is_roc) - ieee80211_remain_on_channel_expired(ar->hw); - /* fall through */ case ATH10K_SCAN_ABORTING: if (!ar->scan.is_roc) ieee80211_scan_completed(ar->hw, (ar->scan.state == ATH10K_SCAN_ABORTING)); + else if (ar->scan.roc_notify) + ieee80211_remain_on_channel_expired(ar->hw); /* fall through */ case ATH10K_SCAN_STARTING: ar->scan.state = ATH10K_SCAN_IDLE; @@ -5459,6 +5458,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ar->scan.is_roc = true; ar->scan.vdev_id = arvif->vdev_id; ar->scan.roc_freq = chan->center_freq; + ar->scan.roc_notify = true; ret = 0; break; case ATH10K_SCAN_STARTING: @@ -5522,7 +5522,13 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; mutex_lock(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + ar->scan.roc_notify = false; + spin_unlock_bh(&ar->data_lock); + ath10k_scan_abort(ar); + mutex_unlock(&ar->conf_mutex); cancel_delayed_work_sync(&ar->scan.timeout); -- cgit v1.3-6-gb490 From f23e587e55f3607741e29a789efa61ea999f13f8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:37 +0200 Subject: ath10k: update vdev ps state on start Psmode can be forcefully enabled when vdev isn't started. It isn't guaranteed that mac80211 will re-issue psmode setting after vdev is started unless actual bss_conf.ps value has changed. Even if this doesn't fix any problems now it may prevent future breakage. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b842612e0b61..8049d77cfc35 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6222,6 +6222,13 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, arvif->is_started = true; + ret = ath10k_mac_vif_setup_ps(arvif); + if (ret) { + ath10k_warn(ar, "failed to update vdev %i ps: %d\n", + arvif->vdev_id, ret); + goto err_stop; + } + if (vif->type == NL80211_IFTYPE_MONITOR) { ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, 0, vif->addr); if (ret) { @@ -6239,6 +6246,7 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, err_stop: ath10k_vdev_stop(arvif); arvif->is_started = false; + ath10k_mac_vif_setup_ps(arvif); err: mutex_unlock(&ar->conf_mutex); -- cgit v1.3-6-gb490 From acd0b27bb13a09dd0a56d4562d3eb4137a7318b2 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:38 +0200 Subject: ath10k: fix per-vif queue locking Whenever any vdev was supposed to be paused all Tx queues were stopped (except offchannel) instead of only these associated with the given vdev. This caused subtle issues with multi-channel/multi-vif scenarios, e.g. authentication of station vif could sometimes fail depending on fw tx pause request timing. Fixes: b4aa539dd8f2 ("ath10k: implement tx pause wmi event") Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 47 +++++++++---------------------- drivers/net/wireless/ath/ath10k/mac.h | 6 ++-- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 34 ++++++++++++++++++---- 3 files changed, 45 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 8049d77cfc35..b2e3fe9a9cae 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3034,38 +3034,16 @@ static void ath10k_mac_vif_handle_tx_pause(struct ath10k_vif *arvif, lockdep_assert_held(&ar->htt.tx_lock); - switch (pause_id) { - case WMI_TLV_TX_PAUSE_ID_MCC: - case WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA: - case WMI_TLV_TX_PAUSE_ID_P2P_GO_PS: - case WMI_TLV_TX_PAUSE_ID_AP_PS: - case WMI_TLV_TX_PAUSE_ID_IBSS_PS: - switch (action) { - case WMI_TLV_TX_PAUSE_ACTION_STOP: - ath10k_mac_vif_tx_lock(arvif, pause_id); - break; - case WMI_TLV_TX_PAUSE_ACTION_WAKE: - ath10k_mac_vif_tx_unlock(arvif, pause_id); - break; - default: - ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n", - action, arvif->vdev_id); - break; - } + switch (action) { + case WMI_TLV_TX_PAUSE_ACTION_STOP: + ath10k_mac_vif_tx_lock(arvif, pause_id); + break; + case WMI_TLV_TX_PAUSE_ACTION_WAKE: + ath10k_mac_vif_tx_unlock(arvif, pause_id); break; - case WMI_TLV_TX_PAUSE_ID_AP_PEER_PS: - case WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD: - case WMI_TLV_TX_PAUSE_ID_STA_ADD_BA: - case WMI_TLV_TX_PAUSE_ID_HOST: default: - /* FIXME: Some pause_ids aren't vdev specific. Instead they - * target peer_id and tid. Implementing these could improve - * traffic scheduling fairness across multiple connected - * stations in AP/IBSS modes. - */ - ath10k_dbg(ar, ATH10K_DBG_MAC, - "mac ignoring unsupported tx pause vdev %i id %d\n", - arvif->vdev_id, pause_id); + ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n", + action, arvif->vdev_id); break; } } @@ -3082,12 +3060,15 @@ static void ath10k_mac_handle_tx_pause_iter(void *data, u8 *mac, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_mac_tx_pause *arg = data; + if (arvif->vdev_id != arg->vdev_id) + return; + ath10k_mac_vif_handle_tx_pause(arvif, arg->pause_id, arg->action); } -void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id, - enum wmi_tlv_tx_pause_id pause_id, - enum wmi_tlv_tx_pause_action action) +void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, + enum wmi_tlv_tx_pause_id pause_id, + enum wmi_tlv_tx_pause_action action) { struct ath10k_mac_tx_pause arg = { .vdev_id = vdev_id, diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index b291f063705c..e3cefe4c7cfd 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -61,9 +61,9 @@ int ath10k_mac_vif_chan(struct ieee80211_vif *vif, void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb); void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id); -void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id, - enum wmi_tlv_tx_pause_id pause_id, - enum wmi_tlv_tx_pause_action action); +void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, + enum wmi_tlv_tx_pause_id pause_id, + enum wmi_tlv_tx_pause_action action); u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband, u8 hw_rate); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index ced35a1e0675..4189d4a90ce0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -377,12 +377,34 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar, "wmi tlv tx pause pause_id %u action %u vdev_map 0x%08x peer_id %u tid_map 0x%08x\n", pause_id, action, vdev_map, peer_id, tid_map); - for (vdev_id = 0; vdev_map; vdev_id++) { - if (!(vdev_map & BIT(vdev_id))) - continue; - - vdev_map &= ~BIT(vdev_id); - ath10k_mac_handle_tx_pause(ar, vdev_id, pause_id, action); + switch (pause_id) { + case WMI_TLV_TX_PAUSE_ID_MCC: + case WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA: + case WMI_TLV_TX_PAUSE_ID_P2P_GO_PS: + case WMI_TLV_TX_PAUSE_ID_AP_PS: + case WMI_TLV_TX_PAUSE_ID_IBSS_PS: + for (vdev_id = 0; vdev_map; vdev_id++) { + if (!(vdev_map & BIT(vdev_id))) + continue; + + vdev_map &= ~BIT(vdev_id); + ath10k_mac_handle_tx_pause_vdev(ar, vdev_id, pause_id, + action); + } + break; + case WMI_TLV_TX_PAUSE_ID_AP_PEER_PS: + case WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD: + case WMI_TLV_TX_PAUSE_ID_STA_ADD_BA: + case WMI_TLV_TX_PAUSE_ID_HOST: + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac ignoring unsupported tx pause id %d\n", + pause_id); + break; + default: + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac ignoring unknown tx pause vdev %d\n", + pause_id); + break; } kfree(tb); -- cgit v1.3-6-gb490 From ed25b113a955e62aeaba49a3ec71faea4f25bf34 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:39 +0200 Subject: ath10k: tweak interface combinations Concurrent AP/GO operation on different channels isn't really supported well by the firmware so it's better to remove it from being advertised. Also tune the way station and p2p client interface limits are expressed to allow station + 2x p2p client or station + p2p client + p2p go. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 39 ++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b2e3fe9a9cae..caa56ce5d907 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6557,8 +6557,11 @@ static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = { static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = { { .max = 2, - .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO), }, @@ -6568,6 +6571,26 @@ static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = { }, }; +static const struct ieee80211_iface_limit ath10k_tlv_qcs_if_limit[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + static const struct ieee80211_iface_limit ath10k_tlv_if_limit_ibss[] = { { .max = 1, @@ -6586,7 +6609,7 @@ static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = { { .limits = ath10k_tlv_if_limit, .num_different_channels = 1, - .max_interfaces = 3, + .max_interfaces = 4, .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit), }, { @@ -6600,10 +6623,16 @@ static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = { static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = { { .limits = ath10k_tlv_if_limit, - .num_different_channels = 2, - .max_interfaces = 3, + .num_different_channels = 1, + .max_interfaces = 4, .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit), }, + { + .limits = ath10k_tlv_qcs_if_limit, + .num_different_channels = 2, + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(ath10k_tlv_qcs_if_limit), + }, { .limits = ath10k_tlv_if_limit_ibss, .num_different_channels = 1, -- cgit v1.3-6-gb490 From 00798c38f49eb028b0c5fac01293783206af29fb Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 15 Jun 2015 19:24:35 +0200 Subject: ipw2100: fix timeout bug - always evaluated to 0 commit 2c86c275015c ("Add ipw2100 wireless driver.") introduced HW_PHY_OFF_LOOP_DELAY (HZ / 5000) which always evaluated to 0. Clarified by Stanislav Yakovlev that it should be 50 milliseconds thus fixed up to msecs_to_jiffies(50). Signed-off-by: Nicholas Mc Guire Acked-by: Stanislav Yakovlev Signed-off-by: Kalle Valo --- drivers/net/wireless/ipw2x00/ipw2100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 08eb229e7816..36818c7f30b9 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -1410,7 +1410,7 @@ static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv) static int ipw2100_hw_phy_off(struct ipw2100_priv *priv) { -#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000) +#define HW_PHY_OFF_LOOP_DELAY (msecs_to_jiffies(50)) struct host_command cmd = { .host_command = CARD_DISABLE_PHY_OFF, -- cgit v1.3-6-gb490 From 8f010d9ca88f9023650b2e54b74c84ab63a19d02 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 16 Jun 2015 11:46:42 +0200 Subject: ath9k: DFS - consider ext_channel pulses only in HT40 mode The chip reports radar pulses on extension channel even if operating in HT20 mode. This patch adds a sanity check for HT40 mode before it feeds pulses on extension channel to the pattern detector. Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/dfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index e98a9eaba7ff..5025a4e91a8b 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -198,7 +198,8 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, sc->dfs_prev_pulse_ts = pe.ts; if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND) ath9k_dfs_process_radar_pulse(sc, &pe); - if (ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { + if (IS_CHAN_HT40(ah->curchan) && + ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20; ath9k_dfs_process_radar_pulse(sc, &pe); } -- cgit v1.3-6-gb490 From 8fc2b61a36fe17f744b445a26599a6cac9e6c1c0 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 16 Jun 2015 12:52:16 +0200 Subject: ath9k: DFS - add pulse chirp detection for FCC FCC long pulse radar (type 5) requires pulses to be checked for chirping. This patch implements chirp detection based on the FFT data provided for long pulses. A chirp is detected when a set of criteria defined by FCC pulse characteristics is met, including * have at least 4 FFT samples * max_bin index moves equidistantly between samples * the gradient is within defined range The chirp detection has been tested with reference radar generating devices and proved to work reliably. Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/dfs.c | 167 +++++++++++++++++++++++++++++++++-- 1 file changed, 161 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index 5025a4e91a8b..1ece42c2443d 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -30,6 +30,157 @@ struct ath_radar_data { u8 pulse_length_pri; }; +/**** begin: CHIRP ************************************************************/ + +/* min and max gradients for defined FCC chirping pulses, given by + * - 20MHz chirp width over a pulse width of 50us + * - 5MHz chirp width over a pulse width of 100us + */ +static const int BIN_DELTA_MIN = 1; +static const int BIN_DELTA_MAX = 10; + +/* we need at least 3 deltas / 4 samples for a reliable chirp detection */ +#define NUM_DIFFS 3 +static const int FFT_NUM_SAMPLES = (NUM_DIFFS + 1); + +/* Threshold for difference of delta peaks */ +static const int MAX_DIFF = 2; + +/* width range to be checked for chirping */ +static const int MIN_CHIRP_PULSE_WIDTH = 20; +static const int MAX_CHIRP_PULSE_WIDTH = 110; + +struct ath9k_dfs_fft_20 { + u8 bin[28]; + u8 lower_bins[3]; +} __packed; +struct ath9k_dfs_fft_40 { + u8 bin[64]; + u8 lower_bins[3]; + u8 upper_bins[3]; +} __packed; + +static inline int fft_max_index(u8 *bins) +{ + return (bins[2] & 0xfc) >> 2; +} +static inline int fft_max_magnitude(u8 *bins) +{ + return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10; +} +static inline u8 fft_bitmap_weight(u8 *bins) +{ + return bins[0] & 0x3f; +} + +static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft, + bool is_ctl, bool is_ext) +{ + const int DFS_UPPER_BIN_OFFSET = 64; + /* if detected radar on both channels, select the significant one */ + if (is_ctl && is_ext) { + /* first check wether channels have 'strong' bins */ + is_ctl = fft_bitmap_weight(fft->lower_bins) != 0; + is_ext = fft_bitmap_weight(fft->upper_bins) != 0; + + /* if still unclear, take higher magnitude */ + if (is_ctl && is_ext) { + int mag_lower = fft_max_magnitude(fft->lower_bins); + int mag_upper = fft_max_magnitude(fft->upper_bins); + if (mag_upper > mag_lower) + is_ctl = false; + else + is_ext = false; + } + } + if (is_ctl) + return fft_max_index(fft->lower_bins); + return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET; +} +static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data, + int datalen, bool is_ctl, bool is_ext) +{ + int i; + int max_bin[FFT_NUM_SAMPLES]; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + int prev_delta; + + if (IS_CHAN_HT40(ah->curchan)) { + struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data; + int num_fft_packets = datalen / sizeof(*fft); + if (num_fft_packets == 0) + return false; + + ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n", + datalen, num_fft_packets); + if (num_fft_packets < (FFT_NUM_SAMPLES)) { + ath_dbg(common, DFS, "not enough packets for chirp\n"); + return false; + } + /* HW sometimes adds 2 garbage bytes in front of FFT samples */ + if ((datalen % sizeof(*fft)) == 2) { + fft = (struct ath9k_dfs_fft_40 *) (data + 2); + ath_dbg(common, DFS, "fixing datalen by 2\n"); + } + if (IS_CHAN_HT40MINUS(ah->curchan)) { + int temp = is_ctl; + is_ctl = is_ext; + is_ext = temp; + } + for (i = 0; i < FFT_NUM_SAMPLES; i++) + max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl, + is_ext); + } else { + struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data; + int num_fft_packets = datalen / sizeof(*fft); + if (num_fft_packets == 0) + return false; + ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n", + datalen, num_fft_packets); + if (num_fft_packets < (FFT_NUM_SAMPLES)) { + ath_dbg(common, DFS, "not enough packets for chirp\n"); + return false; + } + /* in ht20, this is a 6-bit signed number => shift it to 0 */ + for (i = 0; i < FFT_NUM_SAMPLES; i++) + max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20; + } + ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n", + max_bin[0], max_bin[1], max_bin[2], max_bin[3]); + + /* Check for chirp attributes within specs + * a) delta of adjacent max_bins is within range + * b) delta of adjacent deltas are within tolerance + */ + prev_delta = 0; + for (i = 0; i < NUM_DIFFS; i++) { + int ddelta = -1; + int delta = max_bin[i + 1] - max_bin[i]; + + /* ensure gradient is within valid range */ + if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) { + ath_dbg(common, DFS, "CHIRP: invalid delta %d " + "in sample %d\n", delta, i); + return false; + } + if (i == 0) + goto done; + ddelta = delta - prev_delta; + if (abs(ddelta) > MAX_DIFF) { + ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n", + ddelta); + return false; + } +done: + ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n", + i, delta, ddelta); + prev_delta = delta; + } + return true; +} +/**** end: CHIRP **************************************************************/ + /* convert pulse duration to usecs, considering clock mode */ static u32 dur_to_usecs(struct ath_hw *ah, u32 dur) { @@ -113,12 +264,6 @@ ath9k_postprocess_radar_event(struct ath_softc *sc, return false; } - /* - * TODO: check chirping pulses - * checks for chirping are dependent on the DFS regulatory domain - * used, which is yet TBD - */ - /* convert duration to usecs */ pe->width = dur_to_usecs(sc->sc_ah, dur); pe->rssi = rssi; @@ -190,6 +335,16 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, if (!ath9k_postprocess_radar_event(sc, &ard, &pe)) return; + if (pe.width > MIN_CHIRP_PULSE_WIDTH && + pe.width < MAX_CHIRP_PULSE_WIDTH) { + bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND); + bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND); + int clen = datalen - 3; + pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext); + } else { + pe.chirp = false; + } + ath_dbg(common, DFS, "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, " "width=%d, rssi=%d, delta_ts=%llu\n", -- cgit v1.3-6-gb490 From e23fd9812fe729612e778ba9bd9530ce5c234f23 Mon Sep 17 00:00:00 2001 From: Ana Calinov Date: Wed, 8 Jul 2015 05:44:42 -0700 Subject: iio: accel: kxcjk-1013: Remove blank lines This patch fixes the the following errors given by checkpatch.pl with --strict: Please don't use multiple blank lines. Blank lines aren't necessary after an open brace '{'. Signed-off-by: Ana Calinov Reviewed-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kxcjk-1013.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 0d9bd35ff258..8128579bff79 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -658,10 +658,8 @@ static int kxcjk1013_set_scale(struct kxcjk1013_data *data, int val) int ret, i; enum kxcjk1013_mode store_mode; - for (i = 0; i < ARRAY_SIZE(KXCJK1013_scale_table); ++i) { if (KXCJK1013_scale_table[i].scale == val) { - ret = kxcjk1013_get_mode(data, &store_mode); if (ret < 0) return ret; @@ -820,7 +818,6 @@ static int kxcjk1013_read_event_config(struct iio_dev *indio_dev, enum iio_event_type type, enum iio_event_direction dir) { - struct kxcjk1013_data *data = iio_priv(indio_dev); return data->ev_enable_state; -- cgit v1.3-6-gb490 From 1ce96bd366b87d3896a450b3ac26a8a0916573b4 Mon Sep 17 00:00:00 2001 From: Ana Calinov Date: Wed, 8 Jul 2015 07:04:31 -0700 Subject: iio: frequency: adf4350: Delete blank line This patch removes an unnecessary blank line found by checkpatch.pl --strict: Blank lines aren't necessary after an open brace '{'. Signed-off-by: Ana Calinov Signed-off-by: Jonathan Cameron --- drivers/iio/frequency/adf4350.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 10a0dfc3b01f..9890c81c027d 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -72,7 +72,6 @@ static int adf4350_sync_config(struct adf4350_state *st) for (i = ADF4350_REG5; i >= ADF4350_REG0; i--) { if ((st->regs_hw[i] != st->regs[i]) || ((i == ADF4350_REG0) && doublebuf)) { - switch (i) { case ADF4350_REG1: case ADF4350_REG4: -- cgit v1.3-6-gb490 From 862cb6ce58029c478aca573ee7bff0081249a6d3 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Fri, 10 Jul 2015 17:10:21 +0300 Subject: Staging: iio: dummy: Fix blank line warnings Multiple blank lines should not be used as indicated by checkpatch.pl. Also, a line should be used after a function/structure declaration. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- drivers/staging/iio/iio_dummy_evgen.c | 1 + drivers/staging/iio/iio_simple_dummy.c | 2 -- drivers/staging/iio/iio_simple_dummy.h | 1 + drivers/staging/iio/iio_simple_dummy_buffer.c | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/staging/iio/iio_dummy_evgen.c index c54d5b5443a6..6d38854c38c8 100644 --- a/drivers/staging/iio/iio_dummy_evgen.c +++ b/drivers/staging/iio/iio_dummy_evgen.c @@ -214,6 +214,7 @@ static struct device iio_evgen_dev = { .groups = iio_evgen_groups, .release = &iio_evgen_release, }; + static __init int iio_dummy_evgen_init(void) { int ret = iio_dummy_evgen_create(); diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c index 1629a8a6bf26..381f90ff468a 100644 --- a/drivers/staging/iio/iio_simple_dummy.c +++ b/drivers/staging/iio/iio_simple_dummy.c @@ -611,7 +611,6 @@ static int iio_dummy_probe(int index) */ iio_dummy_devs[index] = indio_dev; - /* * Set the device name. * @@ -675,7 +674,6 @@ static void iio_dummy_remove(int index) */ struct iio_dev *indio_dev = iio_dummy_devs[index]; - /* Unregister the device */ iio_device_unregister(indio_dev); diff --git a/drivers/staging/iio/iio_simple_dummy.h b/drivers/staging/iio/iio_simple_dummy.h index e877a99540ab..8d00224e6fad 100644 --- a/drivers/staging/iio/iio_simple_dummy.h +++ b/drivers/staging/iio/iio_simple_dummy.h @@ -119,6 +119,7 @@ static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) { return 0; }; + static inline void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev) {}; diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c index a651b8922d0a..00ed7745f3c5 100644 --- a/drivers/staging/iio/iio_simple_dummy_buffer.c +++ b/drivers/staging/iio/iio_simple_dummy_buffer.c @@ -32,6 +32,7 @@ static const s16 fakedata[] = { [diffvoltage3m4] = -2, [accelx] = 344, }; + /** * iio_simple_dummy_trigger_h() - the trigger handler function * @irq: the interrupt number @@ -178,7 +179,6 @@ error_free_buffer: iio_kfifo_free(indio_dev->buffer); error_ret: return ret; - } /** -- cgit v1.3-6-gb490 From 071667a0fae08ed8c9dcdb9ff526dc66888cac4b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:34:26 +0900 Subject: staging: iio: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Jonathan Cameron --- drivers/staging/iio/addac/adt7316-i2c.c | 1 - drivers/staging/iio/light/isl29018.c | 1 - drivers/staging/iio/light/isl29028.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c index 75ddd4f801a3..78fe0b557280 100644 --- a/drivers/staging/iio/addac/adt7316-i2c.c +++ b/drivers/staging/iio/addac/adt7316-i2c.c @@ -124,7 +124,6 @@ static struct i2c_driver adt7316_driver = { .driver = { .name = "adt7316", .pm = ADT7316_PM_OPS, - .owner = THIS_MODULE, }, .probe = adt7316_i2c_probe, .id_table = adt7316_i2c_id, diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index e646c5d24004..019ba5245c23 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -838,7 +838,6 @@ static struct i2c_driver isl29018_driver = { .name = "isl29018", .acpi_match_table = ACPI_PTR(isl29018_acpi_match), .pm = ISL29018_PM_OPS, - .owner = THIS_MODULE, .of_match_table = isl29018_of_match, }, .probe = isl29018_probe, diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c index e5b2fdc2334b..cd6f2727aa58 100644 --- a/drivers/staging/iio/light/isl29028.c +++ b/drivers/staging/iio/light/isl29028.c @@ -547,7 +547,6 @@ static struct i2c_driver isl29028_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "isl29028", - .owner = THIS_MODULE, .of_match_table = isl29028_of_match, }, .probe = isl29028_probe, -- cgit v1.3-6-gb490 From 2155971a66f89924edb37c213251c4fe9f7776c0 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:54:14 +0900 Subject: iio: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 1 - drivers/iio/accel/st_accel_i2c.c | 1 - drivers/iio/adc/mcp3422.c | 1 - drivers/iio/adc/ti-adc081c.c | 1 - drivers/iio/dac/ad5064.c | 1 - drivers/iio/dac/ad5380.c | 1 - drivers/iio/dac/ad5446.c | 1 - drivers/iio/dac/max5821.c | 1 - drivers/iio/gyro/itg3200_core.c | 1 - drivers/iio/gyro/st_gyro_i2c.c | 1 - drivers/iio/humidity/si7005.c | 1 - drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 1 - drivers/iio/light/apds9300.c | 1 - drivers/iio/light/bh1750.c | 1 - drivers/iio/light/cm32181.c | 1 - drivers/iio/light/cm3232.c | 1 - drivers/iio/light/cm36651.c | 1 - drivers/iio/light/gp2ap020a00f.c | 1 - drivers/iio/light/isl29125.c | 1 - drivers/iio/light/jsa1212.c | 1 - drivers/iio/light/ltr501.c | 1 - drivers/iio/light/tcs3414.c | 1 - drivers/iio/light/tcs3472.c | 1 - drivers/iio/light/tsl4531.c | 1 - drivers/iio/light/vcnl4000.c | 1 - drivers/iio/magnetometer/st_magn_i2c.c | 1 - drivers/iio/pressure/ms5611_i2c.c | 1 - drivers/iio/pressure/st_pressure_i2c.c | 1 - drivers/iio/temperature/mlx90614.c | 1 - drivers/iio/temperature/tmp006.c | 1 - 30 files changed, 30 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 75c6d2103e07..f04b88406995 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -846,7 +846,6 @@ MODULE_DEVICE_TABLE(i2c, bma180_ids); static struct i2c_driver bma180_driver = { .driver = { .name = "bma180", - .owner = THIS_MODULE, .pm = BMA180_PM_OPS, }, .probe = bma180_probe, diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index d4ad72ca4a3d..a2f1c20319eb 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -122,7 +122,6 @@ MODULE_DEVICE_TABLE(i2c, st_accel_id_table); static struct i2c_driver st_accel_driver = { .driver = { - .owner = THIS_MODULE, .name = "st-accel-i2c", .of_match_table = of_match_ptr(st_accel_of_match), }, diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index b96c636470ef..3555122008b4 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -404,7 +404,6 @@ MODULE_DEVICE_TABLE(of, mcp3422_of_match); static struct i2c_driver mcp3422_driver = { .driver = { .name = "mcp3422", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(mcp3422_of_match), }, .probe = mcp3422_probe, diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index b3a82b4d1a75..2c8374f86252 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -140,7 +140,6 @@ MODULE_DEVICE_TABLE(of, adc081c_of_match); static struct i2c_driver adc081c_driver = { .driver = { .name = "adc081c", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(adc081c_of_match), }, .probe = adc081c_probe, diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index f03b92fd3803..c067e6821496 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -630,7 +630,6 @@ MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids); static struct i2c_driver ad5064_i2c_driver = { .driver = { .name = "ad5064", - .owner = THIS_MODULE, }, .probe = ad5064_i2c_probe, .remove = ad5064_i2c_remove, diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 9de4c4d38280..130de9b3e0bf 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -593,7 +593,6 @@ MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids); static struct i2c_driver ad5380_i2c_driver = { .driver = { .name = "ad5380", - .owner = THIS_MODULE, }, .probe = ad5380_i2c_probe, .remove = ad5380_i2c_remove, diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 46bb62a5c1d4..07e17d72a3f3 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -569,7 +569,6 @@ MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids); static struct i2c_driver ad5446_i2c_driver = { .driver = { .name = "ad5446", - .owner = THIS_MODULE, }, .probe = ad5446_i2c_probe, .remove = ad5446_i2c_remove, diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c index 6e914495b346..28b8748ea824 100644 --- a/drivers/iio/dac/max5821.c +++ b/drivers/iio/dac/max5821.c @@ -392,7 +392,6 @@ static struct i2c_driver max5821_driver = { .driver = { .name = "max5821", .pm = MAX5821_PM_OPS, - .owner = THIS_MODULE, }, .probe = max5821_probe, .remove = max5821_remove, diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index f0fd94055d88..c102a6325bb0 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -379,7 +379,6 @@ MODULE_DEVICE_TABLE(i2c, itg3200_id); static struct i2c_driver itg3200_driver = { .driver = { - .owner = THIS_MODULE, .name = "itg3200", .pm = &itg3200_pm_ops, }, diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index 64480b16c689..6848451f817a 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -99,7 +99,6 @@ MODULE_DEVICE_TABLE(i2c, st_gyro_id_table); static struct i2c_driver st_gyro_driver = { .driver = { - .owner = THIS_MODULE, .name = "st-gyro-i2c", .of_match_table = of_match_ptr(st_gyro_of_match), }, diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c index bdd586e6d955..91972ccd8aaf 100644 --- a/drivers/iio/humidity/si7005.c +++ b/drivers/iio/humidity/si7005.c @@ -177,7 +177,6 @@ MODULE_DEVICE_TABLE(i2c, si7005_id); static struct i2c_driver si7005_driver = { .driver = { .name = "si7005", - .owner = THIS_MODULE, }, .probe = si7005_probe, .id_table = si7005_id, diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 096e545538b8..ca6de8e2d0f9 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -909,7 +909,6 @@ static struct i2c_driver inv_mpu_driver = { .remove = inv_mpu_remove, .id_table = inv_mpu_id, .driver = { - .owner = THIS_MODULE, .name = "inv-mpu6050", .pm = INV_MPU6050_PMOPS, .acpi_match_table = ACPI_PTR(inv_acpi_match), diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 9ddde0ca9c34..e1b9fa5a7e91 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -515,7 +515,6 @@ MODULE_DEVICE_TABLE(i2c, apds9300_id); static struct i2c_driver apds9300_driver = { .driver = { .name = APDS9300_DRV_NAME, - .owner = THIS_MODULE, .pm = APDS9300_PM_OPS, }, .probe = apds9300_probe, diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c index 564c2b3c1a83..8b4164343f20 100644 --- a/drivers/iio/light/bh1750.c +++ b/drivers/iio/light/bh1750.c @@ -319,7 +319,6 @@ MODULE_DEVICE_TABLE(i2c, bh1750_id); static struct i2c_driver bh1750_driver = { .driver = { .name = "bh1750", - .owner = THIS_MODULE, .pm = BH1750_PM_OPS, }, .probe = bh1750_probe, diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index 5d12ae54d088..1c0de2f8885d 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -358,7 +358,6 @@ static struct i2c_driver cm32181_driver = { .driver = { .name = "cm32181", .of_match_table = of_match_ptr(cm32181_of_match), - .owner = THIS_MODULE, }, .id_table = cm32181_id, .probe = cm32181_probe, diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 39c8d99cc48e..1b508c65877c 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -421,7 +421,6 @@ static const struct of_device_id cm3232_of_match[] = { static struct i2c_driver cm3232_driver = { .driver = { .name = "cm3232", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(cm3232_of_match), #ifdef CONFIG_PM_SLEEP .pm = &cm3232_pm_ops, diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 39fc67e82138..2a39e141e90c 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -736,7 +736,6 @@ static struct i2c_driver cm36651_driver = { .driver = { .name = "cm36651", .of_match_table = cm36651_of_match, - .owner = THIS_MODULE, }, .probe = cm36651_probe, .remove = cm36651_remove, diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 32b6449833fa..0334a814b5eb 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1640,7 +1640,6 @@ static struct i2c_driver gp2ap020a00f_driver = { .driver = { .name = GP2A_I2C_NAME, .of_match_table = of_match_ptr(gp2ap020a00f_of_match), - .owner = THIS_MODULE, }, .probe = gp2ap020a00f_probe, .remove = gp2ap020a00f_remove, diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index b3cbbe830141..e2945a20e5f6 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -346,7 +346,6 @@ static struct i2c_driver isl29125_driver = { .driver = { .name = ISL29125_DRV_NAME, .pm = &isl29125_pm_ops, - .owner = THIS_MODULE, }, .probe = isl29125_probe, .remove = isl29125_remove, diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index 3a3af89beaf9..c4e8c6b6c3c3 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -457,7 +457,6 @@ static struct i2c_driver jsa1212_driver = { .driver = { .name = JSA1212_DRIVER_NAME, .pm = JSA1212_PM_OPS, - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(jsa1212_acpi_match), }, .probe = jsa1212_probe, diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 1ef7d3773ab9..f4c9a5cdfed6 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -1551,7 +1551,6 @@ static struct i2c_driver ltr501_driver = { .name = LTR501_DRV_NAME, .pm = <r501_pm_ops, .acpi_match_table = ACPI_PTR(ltr_acpi_match), - .owner = THIS_MODULE, }, .probe = ltr501_probe, .remove = ltr501_remove, diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index 71c2bde275aa..8075388aa672 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -392,7 +392,6 @@ static struct i2c_driver tcs3414_driver = { .driver = { .name = TCS3414_DRV_NAME, .pm = &tcs3414_pm_ops, - .owner = THIS_MODULE, }, .probe = tcs3414_probe, .remove = tcs3414_remove, diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 752569985d1d..1b530bf04c89 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -366,7 +366,6 @@ static struct i2c_driver tcs3472_driver = { .driver = { .name = TCS3472_DRV_NAME, .pm = &tcs3472_pm_ops, - .owner = THIS_MODULE, }, .probe = tcs3472_probe, .remove = tcs3472_remove, diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c index 63c26e2d5d97..26979183d27c 100644 --- a/drivers/iio/light/tsl4531.c +++ b/drivers/iio/light/tsl4531.c @@ -247,7 +247,6 @@ static struct i2c_driver tsl4531_driver = { .driver = { .name = TSL4531_DRV_NAME, .pm = TSL4531_PM_OPS, - .owner = THIS_MODULE, }, .probe = tsl4531_probe, .remove = tsl4531_remove, diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index d948c4778ba6..c9d85bbc9230 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -185,7 +185,6 @@ static int vcnl4000_probe(struct i2c_client *client, static struct i2c_driver vcnl4000_driver = { .driver = { .name = VCNL4000_DRV_NAME, - .owner = THIS_MODULE, }, .probe = vcnl4000_probe, .id_table = vcnl4000_id, diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 5311d8aea8cc..28aa80731cea 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -85,7 +85,6 @@ MODULE_DEVICE_TABLE(i2c, st_magn_id_table); static struct i2c_driver st_magn_driver = { .driver = { - .owner = THIS_MODULE, .name = "st-magn-i2c", .of_match_table = of_match_ptr(st_magn_of_match), }, diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c index 9d504f17669b..245797d1ecf0 100644 --- a/drivers/iio/pressure/ms5611_i2c.c +++ b/drivers/iio/pressure/ms5611_i2c.c @@ -117,7 +117,6 @@ MODULE_DEVICE_TABLE(i2c, ms5611_id); static struct i2c_driver ms5611_driver = { .driver = { .name = "ms5611", - .owner = THIS_MODULE, }, .id_table = ms5611_id, .probe = ms5611_i2c_probe, diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 137788bba4a3..8fcf9766eaec 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -79,7 +79,6 @@ MODULE_DEVICE_TABLE(i2c, st_press_id_table); static struct i2c_driver st_press_driver = { .driver = { - .owner = THIS_MODULE, .name = "st-press-i2c", .of_match_table = of_match_ptr(st_press_of_match), }, diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index cb2e8ad8bfdc..90f70b461567 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -551,7 +551,6 @@ static const struct dev_pm_ops mlx90614_pm_ops = { static struct i2c_driver mlx90614_driver = { .driver = { .name = "mlx90614", - .owner = THIS_MODULE, .pm = &mlx90614_pm_ops, }, .probe = mlx90614_probe, diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index ecdb6191951e..395df23d7c8c 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -277,7 +277,6 @@ static struct i2c_driver tmp006_driver = { .driver = { .name = "tmp006", .pm = &tmp006_pm_ops, - .owner = THIS_MODULE, }, .probe = tmp006_probe, .remove = tmp006_remove, -- cgit v1.3-6-gb490 From b66231183a8542de1414e42326dd1c6bc4af75f4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 6 Jul 2015 15:32:25 +0200 Subject: irqchip/dw-apb-ictl: Fix generic domain chip wreckage The num_ct argument of irq_alloc_domain_generic_chips() tells the core code how many chip types (for different control flows, e.g. edge/level) should be allocated. It does not control how many generic chip instances are created because that's determined from the irq domain size and the number of interrupts per chip. The dw-apb init abuses the num_ct argument for allocating one or two chip types depending on the number of interrupts. That's completely wrong because the alternate type is never used. This code was obviously never tested on a system which has more than 32 interrupts as that would have never worked due to the unitialized second generic chip instance. Hand in the proper num_ct=1 and fixup the chip initialization along with the interrupt handler. Signed-off-by: Thomas Gleixner Tested-by: Jisheng Zhang Cc: Sebastian Hesselbarth Cc: Mark Rutland Cc: Jason Cooper Link: http://lkml.kernel.org/r/20150706101543.373582262@linutronix.de --- drivers/irqchip/irq-dw-apb-ictl.c | 53 ++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-dw-apb-ictl.c b/drivers/irqchip/irq-dw-apb-ictl.c index 53bb7326a60a..ca22f4e73944 100644 --- a/drivers/irqchip/irq-dw-apb-ictl.c +++ b/drivers/irqchip/irq-dw-apb-ictl.c @@ -25,24 +25,25 @@ #define APB_INT_MASK_H 0x0c #define APB_INT_FINALSTATUS_L 0x30 #define APB_INT_FINALSTATUS_H 0x34 +#define APB_INT_BASE_OFFSET 0x04 static void dw_apb_ictl_handler(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct irq_chip_generic *gc = irq_get_handler_data(irq); - struct irq_domain *d = gc->private; - u32 stat; + struct irq_domain *d = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); int n; chained_irq_enter(chip, desc); - for (n = 0; n < gc->num_ct; n++) { - stat = readl_relaxed(gc->reg_base + - APB_INT_FINALSTATUS_L + 4 * n); + for (n = 0; n < d->revmap_size; n += 32) { + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, n); + u32 stat = readl_relaxed(gc->reg_base + APB_INT_FINALSTATUS_L); + while (stat) { u32 hwirq = ffs(stat) - 1; - generic_handle_irq(irq_find_mapping(d, - gc->irq_base + hwirq + 32 * n)); + u32 virq = irq_find_mapping(d, gc->irq_base + hwirq); + + generic_handle_irq(virq); stat &= ~(1 << hwirq); } } @@ -73,7 +74,7 @@ static int __init dw_apb_ictl_init(struct device_node *np, struct irq_domain *domain; struct irq_chip_generic *gc; void __iomem *iobase; - int ret, nrirqs, irq; + int ret, nrirqs, irq, i; u32 reg; /* Map the parent interrupt for the chained handler */ @@ -128,35 +129,25 @@ static int __init dw_apb_ictl_init(struct device_node *np, goto err_unmap; } - ret = irq_alloc_domain_generic_chips(domain, 32, (nrirqs > 32) ? 2 : 1, - np->name, handle_level_irq, clr, 0, - IRQ_GC_MASK_CACHE_PER_TYPE | + ret = irq_alloc_domain_generic_chips(domain, 32, 1, np->name, + handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); if (ret) { pr_err("%s: unable to alloc irq domain gc\n", np->full_name); goto err_unmap; } - gc = irq_get_domain_generic_chip(domain, 0); - gc->private = domain; - gc->reg_base = iobase; - - gc->chip_types[0].regs.mask = APB_INT_MASK_L; - gc->chip_types[0].regs.enable = APB_INT_ENABLE_L; - gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; - gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit; - gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume; - - if (nrirqs > 32) { - gc->chip_types[1].regs.mask = APB_INT_MASK_H; - gc->chip_types[1].regs.enable = APB_INT_ENABLE_H; - gc->chip_types[1].chip.irq_mask = irq_gc_mask_set_bit; - gc->chip_types[1].chip.irq_unmask = irq_gc_mask_clr_bit; - gc->chip_types[1].chip.irq_resume = dw_apb_ictl_resume; + for (i = 0; i < DIV_ROUND_UP(nrirqs, 32); i++) { + gc = irq_get_domain_generic_chip(domain, i * 32); + gc->reg_base = iobase + i * APB_INT_BASE_OFFSET; + gc->chip_types[0].regs.mask = APB_INT_MASK_L; + gc->chip_types[0].regs.enable = APB_INT_ENABLE_L; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit; + gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume; } - irq_set_handler_data(irq, gc); - irq_set_chained_handler(irq, dw_apb_ictl_handler); + irq_set_chained_handler_and_data(irq, dw_apb_ictl_handler, domain); return 0; -- cgit v1.3-6-gb490 From d452bca82d9ff4f220afa4234418912623db4fe6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 6 Jul 2015 10:18:29 +0000 Subject: irqchip/sirfsoc: Fix generic chip allocation wreckage irq_alloc_domain_generic_chips() can only be called once for an irqdomain. The sirfsoc init calls it twice and because the return value is not checked it does not notice the wreckage. The code works by chance because the first call already allocates two chips and therefor the second call to sirfsoc_alloc_gc() operates on the proper generic chip instance. Use a single call and setup the two chips in the obvious correct way. Signed-off-by: Thomas Gleixner Cc: Jason Cooper Cc: Barry Song Cc: linux-arm-kernel@lists.infradead.org Cc: Olof Johansson Link: http://lkml.kernel.org/r/20150706101543.470696950@linutronix.de --- drivers/irqchip/irq-sirfsoc.c | 48 ++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c index a469355df352..b93006955b85 100644 --- a/drivers/irqchip/irq-sirfsoc.c +++ b/drivers/irqchip/irq-sirfsoc.c @@ -17,34 +17,38 @@ #include #include "irqchip.h" -#define SIRFSOC_INT_RISC_MASK0 0x0018 -#define SIRFSOC_INT_RISC_MASK1 0x001C -#define SIRFSOC_INT_RISC_LEVEL0 0x0020 -#define SIRFSOC_INT_RISC_LEVEL1 0x0024 +#define SIRFSOC_INT_RISC_MASK0 0x0018 +#define SIRFSOC_INT_RISC_MASK1 0x001C +#define SIRFSOC_INT_RISC_LEVEL0 0x0020 +#define SIRFSOC_INT_RISC_LEVEL1 0x0024 #define SIRFSOC_INIT_IRQ_ID 0x0038 +#define SIRFSOC_INT_BASE_OFFSET 0x0004 #define SIRFSOC_NUM_IRQS 64 +#define SIRFSOC_NUM_BANKS (SIRFSOC_NUM_IRQS / 32) static struct irq_domain *sirfsoc_irqdomain; -static __init void -sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num) +static __init void sirfsoc_alloc_gc(void __iomem *base) { - struct irq_chip_generic *gc; - struct irq_chip_type *ct; - int ret; unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; unsigned int set = IRQ_LEVEL; - - ret = irq_alloc_domain_generic_chips(sirfsoc_irqdomain, num, 1, "irq_sirfsoc", - handle_level_irq, clr, set, IRQ_GC_INIT_MASK_CACHE); - - gc = irq_get_domain_generic_chip(sirfsoc_irqdomain, irq_start); - gc->reg_base = base; - ct = gc->chip_types; - ct->chip.irq_mask = irq_gc_mask_clr_bit; - ct->chip.irq_unmask = irq_gc_mask_set_bit; - ct->regs.mask = SIRFSOC_INT_RISC_MASK0; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + int i; + + irq_alloc_domain_generic_chips(sirfsoc_irqdomain, 32, 1, "irq_sirfsoc", + handle_level_irq, clr, set, + IRQ_GC_INIT_MASK_CACHE); + + for (i = 0; i < SIRFSOC_NUM_BANKS; i++) { + gc = irq_get_domain_generic_chip(sirfsoc_irqdomain, i * 32); + gc->reg_base = base + i * SIRFSOC_INT_BASE_OFFSET; + ct = gc->chip_types; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->regs.mask = SIRFSOC_INT_RISC_MASK0; + } } static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs) @@ -64,10 +68,8 @@ static int __init sirfsoc_irq_init(struct device_node *np, panic("unable to map intc cpu registers\n"); sirfsoc_irqdomain = irq_domain_add_linear(np, SIRFSOC_NUM_IRQS, - &irq_generic_chip_ops, base); - - sirfsoc_alloc_gc(base, 0, 32); - sirfsoc_alloc_gc(base + 4, 32, SIRFSOC_NUM_IRQS - 32); + &irq_generic_chip_ops, base); + sirfsoc_alloc_gc(base); writel_relaxed(0, base + SIRFSOC_INT_RISC_LEVEL0); writel_relaxed(0, base + SIRFSOC_INT_RISC_LEVEL1); -- cgit v1.3-6-gb490 From 41a83e06e2bb9ac46731681fd44d1e6ab184dac5 Mon Sep 17 00:00:00 2001 From: Joel Porquet Date: Tue, 7 Jul 2015 17:11:46 -0400 Subject: irqchip: Prepare for local stub header removal The IRQCHIP_DECLARE macro moved to to 'include/linux/irqchip.h', so the local irqchip.h became an empty shell, which solely includes include/linux/irqchip.h Include the global header in all irqchip drivers instead of the local header, so we can remove it. Signed-off-by: Joel Porquet Cc: vgupta@synopsys.com Cc: monstr@monstr.eu Cc: ralf@linux-mips.org Cc: jason@lakedaemon.net Link: http://lkml.kernel.org/r/1882096.X39jVG8e0D@joel-zenbook Signed-off-by: Thomas Gleixner --- drivers/irqchip/exynos-combiner.c | 3 +-- drivers/irqchip/irq-armada-370-xp.c | 3 +-- drivers/irqchip/irq-atmel-aic.c | 2 +- drivers/irqchip/irq-atmel-aic5.c | 2 +- drivers/irqchip/irq-bcm2835.c | 3 +-- drivers/irqchip/irq-bcm7038-l1.c | 3 +-- drivers/irqchip/irq-bcm7120-l2.c | 3 +-- drivers/irqchip/irq-brcmstb-l2.c | 2 -- drivers/irqchip/irq-clps711x.c | 3 +-- drivers/irqchip/irq-crossbar.c | 3 +-- drivers/irqchip/irq-digicolor.c | 3 +-- drivers/irqchip/irq-dw-apb-ictl.c | 3 +-- drivers/irqchip/irq-gic-v3-its.c | 3 +-- drivers/irqchip/irq-gic-v3.c | 2 +- drivers/irqchip/irq-gic.c | 2 +- drivers/irqchip/irq-hip04.c | 2 +- drivers/irqchip/irq-ingenic.c | 3 +-- drivers/irqchip/irq-keystone.c | 3 +-- drivers/irqchip/irq-mips-cpu.c | 3 +-- drivers/irqchip/irq-mips-gic.c | 3 +-- drivers/irqchip/irq-mmp.c | 3 +-- drivers/irqchip/irq-moxart.c | 3 +-- drivers/irqchip/irq-mtk-sysirq.c | 3 +-- drivers/irqchip/irq-mxs.c | 3 +-- drivers/irqchip/irq-nvic.c | 3 +-- drivers/irqchip/irq-omap-intc.c | 3 +-- drivers/irqchip/irq-or1k-pic.c | 3 +-- drivers/irqchip/irq-orion.c | 3 +-- drivers/irqchip/irq-renesas-h8300h.c | 2 -- drivers/irqchip/irq-renesas-h8s.c | 2 +- drivers/irqchip/irq-s3c24xx.c | 3 +-- drivers/irqchip/irq-sirfsoc.c | 2 +- drivers/irqchip/irq-sun4i.c | 3 +-- drivers/irqchip/irq-sunxi-nmi.c | 2 +- drivers/irqchip/irq-tb10x.c | 2 +- drivers/irqchip/irq-tegra.c | 3 +-- drivers/irqchip/irq-versatile-fpga.c | 3 +-- drivers/irqchip/irq-vf610-mscm-ir.c | 3 +-- drivers/irqchip/irq-vic.c | 3 +-- drivers/irqchip/irq-vt8500.c | 3 +-- drivers/irqchip/irq-xtensa-mx.c | 3 +-- drivers/irqchip/irq-xtensa-pic.c | 3 +-- drivers/irqchip/irq-zevio.c | 3 +-- drivers/irqchip/spear-shirq.c | 3 +-- 44 files changed, 42 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 5c82e3bdafdf..05cdccc3d5e0 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -15,13 +15,12 @@ #include #include #include +#include #include #include #include #include -#include "irqchip.h" - #define COMBINER_ENABLE_SET 0x0 #define COMBINER_ENABLE_CLEAR 0x4 #define COMBINER_INT_STATUS 0xC diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 0d3b0fe2f175..73b73ac04ce7 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -33,8 +34,6 @@ #include #include -#include "irqchip.h" - /* Interrupt Controller Registers Map */ #define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) #define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C) diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c index dae3604b32a9..dbbf30aee278 100644 --- a/drivers/irqchip/irq-atmel-aic.c +++ b/drivers/irqchip/irq-atmel-aic.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,6 @@ #include #include "irq-atmel-aic-common.h" -#include "irqchip.h" /* Number of irq lines managed by AIC */ #define NR_AIC_IRQS 32 diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index 459bf4429d36..ff2e832af10d 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,6 @@ #include #include "irq-atmel-aic-common.h" -#include "irqchip.h" /* Number of irq lines managed by AIC */ #define NR_AIC5_IRQS 128 diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index e68c3b60a681..a36ba96e1448 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -48,13 +48,12 @@ #include #include #include +#include #include #include #include -#include "irqchip.h" - /* Put the bank and irq (32 bits) into the hwirq */ #define MAKE_HWIRQ(b, n) ((b << 5) | (n)) #define HWIRQ_BANK(i) (i >> 5) diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index d3b8c8be15f6..66850aa203ce 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -29,10 +29,9 @@ #include #include #include +#include #include -#include "irqchip.h" - #define IRQS_PER_WORD 32 #define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 4) #define MAX_WORDS 8 diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 3ba5cc780fcb..7de378e98cf2 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -26,10 +26,9 @@ #include #include #include +#include #include -#include "irqchip.h" - /* Register offset in the L2 interrupt controller */ #define IRQEN 0x00 #define IRQSTAT 0x04 diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index d6bcc6be0777..4e60b88ec33f 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -32,8 +32,6 @@ #include #include -#include "irqchip.h" - /* Register offsets in the L2 interrupt controller */ #define CPU_STATUS 0x00 #define CPU_SET 0x04 diff --git a/drivers/irqchip/irq-clps711x.c b/drivers/irqchip/irq-clps711x.c index 33127f131d78..2dd929eed9e0 100644 --- a/drivers/irqchip/irq-clps711x.c +++ b/drivers/irqchip/irq-clps711x.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -19,8 +20,6 @@ #include #include -#include "irqchip.h" - #define CLPS711X_INTSR1 (0x0240) #define CLPS711X_INTMR1 (0x0280) #define CLPS711X_BLEOI (0x0600) diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c index 692fe2bc8197..1240c4deda75 100644 --- a/drivers/irqchip/irq-crossbar.c +++ b/drivers/irqchip/irq-crossbar.c @@ -11,13 +11,12 @@ */ #include #include +#include #include #include #include #include -#include "irqchip.h" - #define IRQ_FREE -1 #define IRQ_RESERVED -2 #define IRQ_SKIP -3 diff --git a/drivers/irqchip/irq-digicolor.c b/drivers/irqchip/irq-digicolor.c index 3cbc658afe27..dad85e74c37c 100644 --- a/drivers/irqchip/irq-digicolor.c +++ b/drivers/irqchip/irq-digicolor.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -20,8 +21,6 @@ #include -#include "irqchip.h" - #define UC_IRQ_CONTROL 0x04 #define IC_FLAG_CLEAR_LO 0x00 diff --git a/drivers/irqchip/irq-dw-apb-ictl.c b/drivers/irqchip/irq-dw-apb-ictl.c index ca22f4e73944..efd95d9955e7 100644 --- a/drivers/irqchip/irq-dw-apb-ictl.c +++ b/drivers/irqchip/irq-dw-apb-ictl.c @@ -13,12 +13,11 @@ #include #include +#include #include #include #include -#include "irqchip.h" - #define APB_INT_ENABLE_L 0x00 #define APB_INT_ENABLE_H 0x04 #define APB_INT_MASK_L 0x08 diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 1b7e155869f6..63dbdec2f05b 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -30,14 +30,13 @@ #include #include +#include #include #include #include #include -#include "irqchip.h" - #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1 << 0) #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index c52f7ba205b4..e406bc5f13e4 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -32,7 +33,6 @@ #include #include "irq-gic-common.h" -#include "irqchip.h" struct redist_region { void __iomem *redist_base; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 8d7e1c8b6d56..9be84bd3cd55 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -48,7 +49,6 @@ #include #include "irq-gic-common.h" -#include "irqchip.h" union gic_base { void __iomem *common_base; diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index 0cae45d10695..55c2c1074e15 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -48,7 +49,6 @@ #include #include "irq-gic-common.h" -#include "irqchip.h" #define HIP04_MAX_IRQS 510 diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c index 005de3f932ae..fc5953dea509 100644 --- a/drivers/irqchip/irq-ingenic.c +++ b/drivers/irqchip/irq-ingenic.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -28,8 +29,6 @@ #include #include -#include "irqchip.h" - struct ingenic_intc_data { void __iomem *base; unsigned num_chips; diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index 81e3cf5b9a1f..d10244fa743a 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -20,13 +20,12 @@ #include #include #include +#include #include #include #include #include #include -#include "irqchip.h" - /* The source ID bits start from 4 to 31 (total 28 bits)*/ #define BIT_OFS 4 diff --git a/drivers/irqchip/irq-mips-cpu.c b/drivers/irqchip/irq-mips-cpu.c index a43c41988009..8c504f562e9d 100644 --- a/drivers/irqchip/irq-mips-cpu.c +++ b/drivers/irqchip/irq-mips-cpu.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -38,8 +39,6 @@ #include #include -#include "irqchip.h" - static inline void unmask_mips_irq(struct irq_data *d) { set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 4400edd1a6c7..42dbebc55e32 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -22,8 +23,6 @@ #include -#include "irqchip.h" - unsigned int gic_present; struct gic_pcpu_mask { diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c index c0da57bdb89d..c9c03a264632 100644 --- a/drivers/irqchip/irq-mmp.c +++ b/drivers/irqchip/irq-mmp.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -24,8 +25,6 @@ #include #include -#include "irqchip.h" - #define MAX_ICU_NR 16 #define PJ1_INT_SEL 0x10c diff --git a/drivers/irqchip/irq-moxart.c b/drivers/irqchip/irq-moxart.c index 00b3cc908f76..a24b06a1718b 100644 --- a/drivers/irqchip/irq-moxart.c +++ b/drivers/irqchip/irq-moxart.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -19,8 +20,6 @@ #include -#include "irqchip.h" - #define IRQ_SOURCE_REG 0 #define IRQ_MASK_REG 0x04 #define IRQ_CLEAR_REG 0x08 diff --git a/drivers/irqchip/irq-mtk-sysirq.c b/drivers/irqchip/irq-mtk-sysirq.c index 15c13039bba2..c8753da4c156 100644 --- a/drivers/irqchip/irq-mtk-sysirq.c +++ b/drivers/irqchip/irq-mtk-sysirq.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -21,8 +22,6 @@ #include #include -#include "irqchip.h" - struct mtk_sysirq_chip_data { spinlock_t lock; void __iomem *intpol_base; diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c index 04bf97b289cf..1faf812f3dc8 100644 --- a/drivers/irqchip/irq-mxs.c +++ b/drivers/irqchip/irq-mxs.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -27,8 +28,6 @@ #include #include -#include "irqchip.h" - #define HW_ICOLL_VECTOR 0x0000 #define HW_ICOLL_LEVELACK 0x0010 #define HW_ICOLL_CTRL 0x0020 diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c index 5fac9100f6cb..a878b8d03868 100644 --- a/drivers/irqchip/irq-nvic.c +++ b/drivers/irqchip/irq-nvic.c @@ -21,13 +21,12 @@ #include #include #include +#include #include #include #include -#include "irqchip.h" - #define NVIC_ISER 0x000 #define NVIC_ICER 0x080 #define NVIC_IPR 0x300 diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c index a569c6dbd1d1..6cc0ad57ffab 100644 --- a/drivers/irqchip/irq-omap-intc.c +++ b/drivers/irqchip/irq-omap-intc.c @@ -17,13 +17,12 @@ #include #include +#include #include #include #include #include -#include "irqchip.h" - /* Define these here for now until we drop all board-files */ #define OMAP24XX_IC_BASE 0x480fe000 #define OMAP34XX_IC_BASE 0x48200000 diff --git a/drivers/irqchip/irq-or1k-pic.c b/drivers/irqchip/irq-or1k-pic.c index e93d079fe069..6a9a3e79218b 100644 --- a/drivers/irqchip/irq-or1k-pic.c +++ b/drivers/irqchip/irq-or1k-pic.c @@ -9,12 +9,11 @@ */ #include +#include #include #include #include -#include "irqchip.h" - /* OR1K PIC implementation */ struct or1k_pic_dev { diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c index ad0c0f6f1d65..995f66b8616e 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -10,14 +10,13 @@ #include #include +#include #include #include #include #include #include -#include "irqchip.h" - /* * Orion SoC main interrupt controller */ diff --git a/drivers/irqchip/irq-renesas-h8300h.c b/drivers/irqchip/irq-renesas-h8300h.c index 1870e6bd3dd9..6fd30d5ee14d 100644 --- a/drivers/irqchip/irq-renesas-h8300h.c +++ b/drivers/irqchip/irq-renesas-h8300h.c @@ -11,8 +11,6 @@ #include #include -#include "irqchip.h" - static const char ipr_bit[] = { 7, 6, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, diff --git a/drivers/irqchip/irq-renesas-h8s.c b/drivers/irqchip/irq-renesas-h8s.c index 64425f4de7d9..8098ead1eb22 100644 --- a/drivers/irqchip/irq-renesas-h8s.c +++ b/drivers/irqchip/irq-renesas-h8s.c @@ -5,10 +5,10 @@ */ #include +#include #include #include #include -#include "irqchip.h" static void *intc_baseaddr; #define IPRA ((unsigned long)intc_baseaddr) diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c index e96717f45ea1..aee4266f27f7 100644 --- a/drivers/irqchip/irq-s3c24xx.c +++ b/drivers/irqchip/irq-s3c24xx.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -40,8 +41,6 @@ #include #include -#include "irqchip.h" - #define S3C_IRQTYPE_NONE 0 #define S3C_IRQTYPE_EINT 1 #define S3C_IRQTYPE_EDGE 2 diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c index b93006955b85..10cb21b9ba3d 100644 --- a/drivers/irqchip/irq-sirfsoc.c +++ b/drivers/irqchip/irq-sirfsoc.c @@ -11,11 +11,11 @@ #include #include #include +#include #include #include #include #include -#include "irqchip.h" #define SIRFSOC_INT_RISC_MASK0 0x0018 #define SIRFSOC_INT_RISC_MASK1 0x001C diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 83d6aa6464ee..4ad3e7c69aa7 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -23,8 +24,6 @@ #include #include -#include "irqchip.h" - #define SUN4I_IRQ_VECTOR_REG 0x00 #define SUN4I_IRQ_PROTECTION_REG 0x08 #define SUN4I_IRQ_NMI_CTRL_REG 0x0c diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c index 6b2b582433bd..2fb8c0e6f02b 100644 --- a/drivers/irqchip/irq-sunxi-nmi.c +++ b/drivers/irqchip/irq-sunxi-nmi.c @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include "irqchip.h" #define SUNXI_NMI_SRC_TYPE_MASK 0x00000003 diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c index accc20036a3c..55dea554d955 100644 --- a/drivers/irqchip/irq-tb10x.c +++ b/drivers/irqchip/irq-tb10x.c @@ -22,13 +22,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include "irqchip.h" #define AB_IRQCTL_INT_ENABLE 0x00 #define AB_IRQCTL_INT_STATUS 0x04 diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c index f67bbd80433e..2fd89eb88f3a 100644 --- a/drivers/irqchip/irq-tegra.c +++ b/drivers/irqchip/irq-tegra.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -31,8 +32,6 @@ #include -#include "irqchip.h" - #define ICTLR_CPU_IEP_VFIQ 0x08 #define ICTLR_CPU_IEP_FIR 0x14 #define ICTLR_CPU_IEP_FIR_SET 0x18 diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 888111b76ea0..4ba480b92844 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -14,8 +15,6 @@ #include #include -#include "irqchip.h" - #define IRQ_STATUS 0x00 #define IRQ_RAW_STATUS 0x04 #define IRQ_ENABLE_SET 0x08 diff --git a/drivers/irqchip/irq-vf610-mscm-ir.c b/drivers/irqchip/irq-vf610-mscm-ir.c index f5c01cbcc73a..2c2255886401 100644 --- a/drivers/irqchip/irq-vf610-mscm-ir.c +++ b/drivers/irqchip/irq-vf610-mscm-ir.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,8 +35,6 @@ #include #include -#include "irqchip.h" - #define MSCM_CPxNUM 0x4 #define MSCM_IRSPRC(n) (0x80 + 2 * (n)) diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index d4ce331ea4a0..4cd65c19c1ee 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -37,8 +38,6 @@ #include #include -#include "irqchip.h" - #define VIC_IRQ_STATUS 0x00 #define VIC_FIQ_STATUS 0x04 #define VIC_INT_SELECT 0x0c /* 1 = FIQ, 0 = IRQ */ diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c index 0b297009b856..52c280004c56 100644 --- a/drivers/irqchip/irq-vt8500.c +++ b/drivers/irqchip/irq-vt8500.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -39,8 +40,6 @@ #include #include -#include "irqchip.h" - #define VT8500_ICPC_IRQ 0x20 #define VT8500_ICPC_FIQ 0x24 #define VT8500_ICDC 0x40 /* Destination Control 64*u32 */ diff --git a/drivers/irqchip/irq-xtensa-mx.c b/drivers/irqchip/irq-xtensa-mx.c index e1c2f9632893..bb3ac5fe5846 100644 --- a/drivers/irqchip/irq-xtensa-mx.c +++ b/drivers/irqchip/irq-xtensa-mx.c @@ -11,12 +11,11 @@ #include #include #include +#include #include #include -#include "irqchip.h" - #define HW_IRQ_IPI_COUNT 2 #define HW_IRQ_MX_BASE 2 #define HW_IRQ_EXTERN_BASE 3 diff --git a/drivers/irqchip/irq-xtensa-pic.c b/drivers/irqchip/irq-xtensa-pic.c index 7d71126d1ce5..472ae1770964 100644 --- a/drivers/irqchip/irq-xtensa-pic.c +++ b/drivers/irqchip/irq-xtensa-pic.c @@ -15,10 +15,9 @@ #include #include #include +#include #include -#include "irqchip.h" - unsigned int cached_irq_mask; /* diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c index e4ef74ed454a..4c48fa88a03d 100644 --- a/drivers/irqchip/irq-zevio.c +++ b/drivers/irqchip/irq-zevio.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -18,8 +19,6 @@ #include #include -#include "irqchip.h" - #define IO_STATUS 0x000 #define IO_RAW_STATUS 0x004 #define IO_ENABLE 0x008 diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c index a45121546caf..3df144f0f79b 100644 --- a/drivers/irqchip/spear-shirq.c +++ b/drivers/irqchip/spear-shirq.c @@ -18,14 +18,13 @@ #include #include #include +#include #include #include #include #include #include -#include "irqchip.h" - /* * struct spear_shirq: shared irq structure * -- cgit v1.3-6-gb490 From 741ff9661337231233cd675df7726ffafe13c960 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:49 +0200 Subject: irqchip/exynos-combiner: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: linux-arm-kernel@lists.infradead.org Cc: linux-samsung-soc@vger.kernel.org --- drivers/irqchip/exynos-combiner.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 05cdccc3d5e0..6ad04acbd51e 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -121,9 +121,8 @@ static struct irq_chip combiner_chip = { static void __init combiner_cascade_irq(struct combiner_chip_data *combiner_data, unsigned int irq) { - if (irq_set_handler_data(irq, combiner_data) != 0) - BUG(); - irq_set_chained_handler(irq, combiner_handle_cascade_irq); + irq_set_chained_handler_and_data(irq, combiner_handle_cascade_irq, + combiner_data); } static void __init combiner_init_one(struct combiner_chip_data *combiner_data, -- cgit v1.3-6-gb490 From 3a7946eed85a1031120d2c946d6e8e8520b32827 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:50 +0200 Subject: irqchip/bcm7038-l1: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Kevin Cernekee Cc: Florian Fainelli Cc: Thomas Gleixner Cc: Jason Cooper Cc: linux-mips@linux-mips.org --- drivers/irqchip/irq-bcm7038-l1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index 66850aa203ce..409bdc6366c2 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -256,8 +256,8 @@ static int __init bcm7038_l1_init_one(struct device_node *dn, pr_err("failed to map parent interrupt %d\n", parent_irq); return -EINVAL; } - irq_set_handler_data(parent_irq, intc); - irq_set_chained_handler(parent_irq, bcm7038_l1_irq_handle); + irq_set_chained_handler_and_data(parent_irq, bcm7038_l1_irq_handle, + intc); return 0; } -- cgit v1.3-6-gb490 From 99e32ab1732e8e66c775087f5361fca235bbee0e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:51 +0200 Subject: irqchip/bcm7120-l2: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Kevin Cernekee Cc: Florian Fainelli Cc: Thomas Gleixner Cc: Jason Cooper Cc: linux-mips@linux-mips.org --- drivers/irqchip/irq-bcm7120-l2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 7de378e98cf2..88c9719e5d33 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -130,8 +130,8 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, } } - irq_set_handler_data(parent_irq, data); - irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle); + irq_set_chained_handler_and_data(parent_irq, + bcm7120_l2_intc_irq_handle, data); return 0; } -- cgit v1.3-6-gb490 From f286c173593245d443e592edea2ec35ef4a7c7e8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:52 +0200 Subject: irqchip/brcmstb-l2: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Kevin Cernekee Cc: Florian Fainelli Cc: Thomas Gleixner Cc: Jason Cooper Cc: linux-mips@linux-mips.org --- drivers/irqchip/irq-brcmstb-l2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index 4e60b88ec33f..cef15189aa5b 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -170,8 +170,8 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np, } /* Set the IRQ chaining logic */ - irq_set_handler_data(data->parent_irq, data); - irq_set_chained_handler(data->parent_irq, brcmstb_l2_intc_irq_handle); + irq_set_chained_handler_and_data(data->parent_irq, + brcmstb_l2_intc_irq_handle, data); gc = irq_get_domain_generic_chip(data->domain, 0); gc->reg_base = data->base; -- cgit v1.3-6-gb490 From 4d83fcf8d615e44ca3ce1ac5766ae121ce08161b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:53 +0200 Subject: irqchip/gic: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper --- drivers/irqchip/irq-gic.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 9be84bd3cd55..2eaae9c2a5d4 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -331,9 +331,8 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) { if (gic_nr >= MAX_GIC_NR) BUG(); - if (irq_set_handler_data(irq, &gic_data[gic_nr]) != 0) - BUG(); - irq_set_chained_handler(irq, gic_handle_cascade_irq); + irq_set_chained_handler_and_data(irq, gic_handle_cascade_irq, + &gic_data[gic_nr]); } static u8 gic_get_cpumask(struct gic_chip_data *gic) -- cgit v1.3-6-gb490 From bc4d2c074ac1b55a95a2011bffe1c5ebb590e886 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:54 +0200 Subject: irqchip/imgpdc: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper --- drivers/irqchip/irq-imgpdc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index 8071c2eb0248..03d91cbfc45e 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -451,13 +451,13 @@ static int pdc_intc_probe(struct platform_device *pdev) /* Setup chained handlers for the peripheral IRQs */ for (i = 0; i < priv->nr_perips; ++i) { irq = priv->perip_irqs[i]; - irq_set_handler_data(irq, priv); - irq_set_chained_handler(irq, pdc_intc_perip_isr); + irq_set_chained_handler_and_data(irq, pdc_intc_perip_isr, + priv); } /* Setup chained handler for the syswake IRQ */ - irq_set_handler_data(priv->syswake_irq, priv); - irq_set_chained_handler(priv->syswake_irq, pdc_intc_syswake_isr); + irq_set_chained_handler_and_data(priv->syswake_irq, + pdc_intc_syswake_isr, priv); dev_info(&pdev->dev, "PDC IRQ controller initialised (%u perip IRQs, %u syswake IRQs)\n", -- cgit v1.3-6-gb490 From 832b404ea0f48a57f1099327cd3137e9a6a51f88 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:55 +0200 Subject: irqchip/metag: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: James Hogan Cc: Thomas Gleixner Cc: Jason Cooper Cc: linux-metag@vger.kernel.org --- drivers/irqchip/irq-metag.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-metag.c b/drivers/irqchip/irq-metag.c index c16c186d97d3..3d23ce3edb5c 100644 --- a/drivers/irqchip/irq-metag.c +++ b/drivers/irqchip/irq-metag.c @@ -286,8 +286,7 @@ static void metag_internal_irq_init_cpu(struct metag_internal_irq_priv *priv, int irq = tbisig_map(signum); /* Register the multiplexed IRQ handler */ - irq_set_handler_data(irq, priv); - irq_set_chained_handler(irq, metag_internal_irq_demux); + irq_set_chained_handler_and_data(irq, metag_internal_irq_demux, priv); irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); } -- cgit v1.3-6-gb490 From 07d22c23d63a3dc08083fec7ce26562b05e7d24b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:57 +0200 Subject: irqchip/orion: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper --- drivers/irqchip/irq-orion.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c index 995f66b8616e..7fbae56b802c 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -197,8 +197,8 @@ static int __init orion_bridge_irq_init(struct device_node *np, writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK); writel(0, gc->reg_base + ORION_BRIDGE_IRQ_CAUSE); - irq_set_handler_data(irq, domain); - irq_set_chained_handler(irq, orion_bridge_irq_handler); + irq_set_chained_handler_and_data(irq, orion_bridge_irq_handler, + domain); return 0; } -- cgit v1.3-6-gb490 From 3200a71207c7d4ec4e961c0ef7ac50361de30e9a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:58 +0200 Subject: irqchip/sunxi-nmi: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper Cc: Maxime Ripard Cc: linux-arm-kernel@lists.infradead.org --- drivers/irqchip/irq-sunxi-nmi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c index 2fb8c0e6f02b..9186a113ed1b 100644 --- a/drivers/irqchip/irq-sunxi-nmi.c +++ b/drivers/irqchip/irq-sunxi-nmi.c @@ -182,8 +182,7 @@ static int __init sunxi_sc_nmi_irq_init(struct device_node *node, sunxi_sc_nmi_write(gc, reg_offs->enable, 0); sunxi_sc_nmi_write(gc, reg_offs->pend, 0x1); - irq_set_handler_data(irq, domain); - irq_set_chained_handler(irq, sunxi_sc_nmi_handle_irq); + irq_set_chained_handler_and_data(irq, sunxi_sc_nmi_handle_irq, domain); return 0; -- cgit v1.3-6-gb490 From 22890b0dbe233fa460d25762ab6a2f5c90f84d9c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:58 +0200 Subject: irqchip/tb10x: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper --- drivers/irqchip/irq-tb10x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c index 55dea554d955..c7e1407c2b40 100644 --- a/drivers/irqchip/irq-tb10x.c +++ b/drivers/irqchip/irq-tb10x.c @@ -173,8 +173,8 @@ static int __init of_tb10x_init_irq(struct device_node *ictl, for (i = 0; i < nrirqs; i++) { unsigned int irq = irq_of_parse_and_map(ictl, i); - irq_set_handler_data(irq, domain); - irq_set_chained_handler(irq, tb10x_irq_cascade); + irq_set_chained_handler_and_data(irq, tb10x_irq_cascade, + domain); } ab_irqctl_writereg(gc, AB_IRQCTL_INT_ENABLE, 0); -- cgit v1.3-6-gb490 From fcd3c5bee16a2c3c9cd6c4cb8e3e093d458d9f86 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:00 +0200 Subject: irqchip/versatile: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper --- drivers/irqchip/irq-versatile-fpga.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 4ba480b92844..70088bb3fb53 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -155,8 +155,8 @@ void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, f->valid = valid; if (parent_irq != -1) { - irq_set_handler_data(parent_irq, f); - irq_set_chained_handler(parent_irq, fpga_irq_handle); + irq_set_chained_handler_and_data(parent_irq, fpga_irq_handle, + f); } /* This will also allocate irq descriptors */ -- cgit v1.3-6-gb490 From 9f2135419ffb7601b6642147ae0e6ccc19a7d5be Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:00 +0200 Subject: irqchip/vic: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper --- drivers/irqchip/irq-vic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index 4cd65c19c1ee..03846dff4212 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -296,8 +296,8 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq, vic_id++; if (parent_irq) { - irq_set_handler_data(parent_irq, v); - irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded); + irq_set_chained_handler_and_data(parent_irq, + vic_handle_irq_cascaded, v); } v->domain = irq_domain_add_simple(node, fls(valid_sources), irq, -- cgit v1.3-6-gb490 From 72f86db4dd5eafbadd45c9092df73c49f320f638 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:38 +0800 Subject: irqchip/mips-gic: Use access helper irq_data_get_affinity_mask() Use access helper irq_data_get_affinity_mask() to hide implementation details of struct irq_desc. [ tglx: Verified with coccinelle ] Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: Jason Cooper Link: http://lkml.kernel.org/r/1433145945-789-30-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-mips-gic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 42dbebc55e32..e6c2df99662a 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -405,7 +405,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, clear_bit(irq, pcpu_masks[i].pcpu_mask); set_bit(irq, pcpu_masks[cpumask_first(&tmp)].pcpu_mask); - cpumask_copy(d->affinity, cpumask); + cpumask_copy(irq_data_get_affinity_mask(d), cpumask); spin_unlock_irqrestore(&gic_lock, flags); return IRQ_SET_MASK_OK_NOCOPY; -- cgit v1.3-6-gb490 From 5b29264c659c31bada65582005d99adb3bb41fea Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:20 +0800 Subject: irqchip: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: Jason Cooper Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: Maxime Ripard Link: http://lkml.kernel.org/r/1433391238-19471-11-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/exynos-combiner.c | 4 ++-- drivers/irqchip/irq-armada-370-xp.c | 2 +- drivers/irqchip/irq-gic.c | 4 ++-- drivers/irqchip/irq-orion.c | 2 +- drivers/irqchip/irq-sunxi-nmi.c | 2 +- drivers/irqchip/spear-shirq.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 6ad04acbd51e..1a4a1b09394c 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -67,8 +67,8 @@ static void combiner_unmask_irq(struct irq_data *data) static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) { - struct combiner_chip_data *chip_data = irq_get_handler_data(irq); - struct irq_chip *chip = irq_get_chip(irq); + struct combiner_chip_data *chip_data = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int cascade_irq, combiner_irq; unsigned long status; diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 73b73ac04ce7..39b72da0c143 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -450,7 +450,7 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {} static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned long irqmap, irqn, irqsrc, cpuid; unsigned int cascade_irq; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 2eaae9c2a5d4..cadd8628fb40 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -288,8 +288,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) { - struct gic_chip_data *chip_data = irq_get_handler_data(irq); - struct irq_chip *chip = irq_get_chip(irq); + struct gic_chip_data *chip_data = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int cascade_irq, gic_irq; unsigned long status; diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c index 7fbae56b802c..5ea999a724b5 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -108,7 +108,7 @@ IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init); static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct irq_domain *d = irq_get_handler_data(irq); + struct irq_domain *d = irq_desc_get_handler_data(desc); struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0); u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) & diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c index 9186a113ed1b..772a82cacbf7 100644 --- a/drivers/irqchip/irq-sunxi-nmi.c +++ b/drivers/irqchip/irq-sunxi-nmi.c @@ -61,7 +61,7 @@ static inline u32 sunxi_sc_nmi_read(struct irq_chip_generic *gc, u32 off) static void sunxi_sc_nmi_handle_irq(unsigned int irq, struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int virq = irq_find_mapping(domain, 0); chained_irq_enter(chip, desc); diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c index 3df144f0f79b..61718550a064 100644 --- a/drivers/irqchip/spear-shirq.c +++ b/drivers/irqchip/spear-shirq.c @@ -184,7 +184,7 @@ static struct spear_shirq *spear320_shirq_blocks[] = { static void shirq_handler(unsigned irq, struct irq_desc *desc) { - struct spear_shirq *shirq = irq_get_handler_data(irq); + struct spear_shirq *shirq = irq_desc_get_handler_data(desc); u32 pend; pend = readl(shirq->base + shirq->status_reg) & shirq->mask; -- cgit v1.3-6-gb490 From f61fd21dea1b9b40edfab07bdcd60d6a3bd95ba1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 14:45:25 -0700 Subject: Input: of_touchscreen - always issue warning if axis is not set up Do issue warning about axis that is present in device tree but not specified by the driver even in case of multi-touch axis as callers now tell us if they expect multi-touch data or not. Reviewed-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/of_touchscreen.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c index 806cd0ad160f..759cf4b8ba09 100644 --- a/drivers/input/touchscreen/of_touchscreen.c +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -39,13 +39,9 @@ static void touchscreen_set_params(struct input_dev *dev, struct input_absinfo *absinfo; if (!test_bit(axis, dev->absbit)) { - /* - * Emit a warning only if the axis is not a multitouch - * axis, which might not be set by the driver. - */ - if (!input_is_mt_axis(axis)) - dev_warn(&dev->dev, - "DT specifies parameters but the axis is not set up\n"); + dev_warn(&dev->dev, + "DT specifies parameters but the axis %lu is not set up\n", + axis); return; } -- cgit v1.3-6-gb490 From 517178692ccd730a95b278bd8cd67e11498a9a84 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 14:57:54 -0700 Subject: Input: of_touchscreen - fix setting max values on X/Y axis The binding specification says that "touchscreen-size-x" and "-y" specify horizontal and vertical resolution of the touchscreen and therefore maximum absolute coordinates should be reduced by 1 since we are starting with 0. Reviewed-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/of_touchscreen.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c index 759cf4b8ba09..50bc0f219547 100644 --- a/drivers/input/touchscreen/of_touchscreen.c +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -71,23 +71,25 @@ void touchscreen_parse_of_params(struct input_dev *dev, bool multitouch) axis = multitouch ? ABS_MT_POSITION_X : ABS_X; data_present = touchscreen_get_prop_u32(np, "touchscreen-size-x", - input_abs_get_max(dev, axis), + input_abs_get_max(dev, + axis) + 1, &maximum) | touchscreen_get_prop_u32(np, "touchscreen-fuzz-x", input_abs_get_fuzz(dev, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum, fuzz); + touchscreen_set_params(dev, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y; data_present = touchscreen_get_prop_u32(np, "touchscreen-size-y", - input_abs_get_max(dev, axis), + input_abs_get_max(dev, + axis) + 1, &maximum) | touchscreen_get_prop_u32(np, "touchscreen-fuzz-y", input_abs_get_fuzz(dev, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum, fuzz); + touchscreen_set_params(dev, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; data_present = touchscreen_get_prop_u32(np, "touchscreen-max-pressure", -- cgit v1.3-6-gb490 From 4200e831e4a8fd09fa4e78de2e571ab270c12d06 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 15:18:24 -0700 Subject: Input: of_touchscreen - switch to using device properties Let's switch form OF to device properties so that common parsing code could work not only on device tree but also on ACPI-based platforms. Reviewed-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 4 +-- drivers/input/touchscreen/Makefile | 2 +- drivers/input/touchscreen/edt-ft5x06.c | 2 +- drivers/input/touchscreen/of_touchscreen.c | 56 ++++++++++++++++-------------- drivers/input/touchscreen/tsc2005.c | 2 +- include/linux/input/touchscreen.h | 11 ++---- 6 files changed, 37 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index aa2b5f21b89b..27035ecbd4f5 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -11,9 +11,9 @@ menuconfig INPUT_TOUCHSCREEN if INPUT_TOUCHSCREEN -config OF_TOUCHSCREEN +config TOUCHSCREEN_PROPERTIES def_tristate INPUT - depends on INPUT && OF + depends on INPUT config TOUCHSCREEN_88PM860X tristate "Marvell 88PM860x touchscreen" diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index fa3d33bac7fc..c85aae23e7f8 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -6,7 +6,7 @@ wm97xx-ts-y := wm97xx-core.o -obj-$(CONFIG_OF_TOUCHSCREEN) += of_touchscreen.o +obj-$(CONFIG_TOUCHSCREEN_PROPERTIES) += of_touchscreen.o obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 394b1de9a2a3..8f8f3199be39 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1041,7 +1041,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, 0, tsdata->num_y * 64 - 1, 0, 0); if (!pdata) - touchscreen_parse_of_params(input, true); + touchscreen_parse_properties(input, true); error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, INPUT_MT_DIRECT); if (error) { diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c index 50bc0f219547..bb6f2fe14667 100644 --- a/drivers/input/touchscreen/of_touchscreen.c +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -9,12 +9,12 @@ * */ -#include +#include #include #include #include -static bool touchscreen_get_prop_u32(struct device_node *np, +static bool touchscreen_get_prop_u32(struct device *dev, const char *property, unsigned int default_value, unsigned int *value) @@ -22,7 +22,7 @@ static bool touchscreen_get_prop_u32(struct device_node *np, u32 val; int error; - error = of_property_read_u32(np, property, &val); + error = device_property_read_u32(dev, property, &val); if (error) { *value = default_value; return false; @@ -51,54 +51,58 @@ static void touchscreen_set_params(struct input_dev *dev, } /** - * touchscreen_parse_of_params - parse common touchscreen DT properties - * @dev: device that should be parsed + * touchscreen_parse_properties - parse common touchscreen DT properties + * @input: input device that should be parsed + * @multitouch: specifies whether parsed properties should be applied to + * single-touch or multi-touch axes * * This function parses common DT properties for touchscreens and setups the - * input device accordingly. The function keeps previously setuped default + * input device accordingly. The function keeps previously set up default * values if no value is specified via DT. */ -void touchscreen_parse_of_params(struct input_dev *dev, bool multitouch) +void touchscreen_parse_properties(struct input_dev *input, bool multitouch) { - struct device_node *np = dev->dev.parent->of_node; + struct device *dev = input->dev.parent; unsigned int axis; unsigned int maximum, fuzz; bool data_present; - input_alloc_absinfo(dev); - if (!dev->absinfo) + input_alloc_absinfo(input); + if (!input->absinfo) return; axis = multitouch ? ABS_MT_POSITION_X : ABS_X; - data_present = touchscreen_get_prop_u32(np, "touchscreen-size-x", - input_abs_get_max(dev, + data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-x", + input_abs_get_max(input, axis) + 1, &maximum) | - touchscreen_get_prop_u32(np, "touchscreen-fuzz-x", - input_abs_get_fuzz(dev, axis), + touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x", + input_abs_get_fuzz(input, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum - 1, fuzz); + touchscreen_set_params(input, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y; - data_present = touchscreen_get_prop_u32(np, "touchscreen-size-y", - input_abs_get_max(dev, + data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-y", + input_abs_get_max(input, axis) + 1, &maximum) | - touchscreen_get_prop_u32(np, "touchscreen-fuzz-y", - input_abs_get_fuzz(dev, axis), + touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y", + input_abs_get_fuzz(input, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum - 1, fuzz); + touchscreen_set_params(input, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; - data_present = touchscreen_get_prop_u32(np, "touchscreen-max-pressure", - input_abs_get_max(dev, axis), + data_present = touchscreen_get_prop_u32(dev, + "touchscreen-max-pressure", + input_abs_get_max(input, axis), &maximum) | - touchscreen_get_prop_u32(np, "touchscreen-fuzz-pressure", - input_abs_get_fuzz(dev, axis), + touchscreen_get_prop_u32(dev, + "touchscreen-fuzz-pressure", + input_abs_get_fuzz(input, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum, fuzz); + touchscreen_set_params(input, axis, maximum, fuzz); } -EXPORT_SYMBOL(touchscreen_parse_of_params); +EXPORT_SYMBOL(touchscreen_parse_properties); diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index d8c025b0f88c..aaf947525cd9 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -709,7 +709,7 @@ static int tsc2005_probe(struct spi_device *spi) input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); if (np) - touchscreen_parse_of_params(input_dev, false); + touchscreen_parse_properties(input_dev, false); input_dev->open = tsc2005_open; input_dev->close = tsc2005_close; diff --git a/include/linux/input/touchscreen.h b/include/linux/input/touchscreen.h index eecc9ea6cd58..c91e1376132b 100644 --- a/include/linux/input/touchscreen.h +++ b/include/linux/input/touchscreen.h @@ -9,15 +9,8 @@ #ifndef _TOUCHSCREEN_H #define _TOUCHSCREEN_H -#include +struct input_dev; -#ifdef CONFIG_OF -void touchscreen_parse_of_params(struct input_dev *dev, bool multitouch); -#else -static inline void touchscreen_parse_of_params(struct input_dev *dev, - bool multitouch) -{ -} -#endif +void touchscreen_parse_properties(struct input_dev *dev, bool multitouch); #endif -- cgit v1.3-6-gb490 From 28a74c050060c17b1edaee2d60470a33be476941 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 11:48:47 -0700 Subject: Input: pixcir_i2c_ts - move platform data Let's move driver's platform data definitions from include/linux/input/ into include/linux/platform_data/ so that it stays with the rest of platform data definitions. Acked-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 2 +- include/linux/input/pixcir_ts.h | 64 ----------------------------- include/linux/platform_data/pixcir_i2c_ts.h | 64 +++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 65 deletions(-) delete mode 100644 include/linux/input/pixcir_ts.h create mode 100644 include/linux/platform_data/pixcir_i2c_ts.h (limited to 'drivers') diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 2c2107147319..f7d90997a786 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -24,11 +24,11 @@ #include #include #include -#include #include #include #include #include +#include #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h deleted file mode 100644 index 7bae83b7c396..000000000000 --- a/include/linux/input/pixcir_ts.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef _PIXCIR_I2C_TS_H -#define _PIXCIR_I2C_TS_H - -/* - * Register map - */ -#define PIXCIR_REG_POWER_MODE 51 -#define PIXCIR_REG_INT_MODE 52 - -/* - * Power modes: - * active: max scan speed - * idle: lower scan speed with automatic transition to active on touch - * halt: datasheet says sleep but this is more like halt as the chip - * clocks are cut and it can only be brought out of this mode - * using the RESET pin. - */ -enum pixcir_power_mode { - PIXCIR_POWER_ACTIVE, - PIXCIR_POWER_IDLE, - PIXCIR_POWER_HALT, -}; - -#define PIXCIR_POWER_MODE_MASK 0x03 -#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2) - -/* - * Interrupt modes: - * periodical: interrupt is asserted periodicaly - * diff coordinates: interrupt is asserted when coordinates change - * level on touch: interrupt level asserted during touch - * pulse on touch: interrupt pulse asserted druing touch - * - */ -enum pixcir_int_mode { - PIXCIR_INT_PERIODICAL, - PIXCIR_INT_DIFF_COORD, - PIXCIR_INT_LEVEL_TOUCH, - PIXCIR_INT_PULSE_TOUCH, -}; - -#define PIXCIR_INT_MODE_MASK 0x03 -#define PIXCIR_INT_ENABLE (1UL << 3) -#define PIXCIR_INT_POL_HIGH (1UL << 2) - -/** - * struct pixcir_irc_chip_data - chip related data - * @max_fingers: Max number of fingers reported simultaneously by h/w - * @has_hw_ids: Hardware supports finger tracking IDs - * - */ -struct pixcir_i2c_chip_data { - u8 max_fingers; - bool has_hw_ids; -}; - -struct pixcir_ts_platform_data { - int x_max; - int y_max; - int gpio_attb; /* GPIO connected to ATTB line */ - struct pixcir_i2c_chip_data chip; -}; - -#endif diff --git a/include/linux/platform_data/pixcir_i2c_ts.h b/include/linux/platform_data/pixcir_i2c_ts.h new file mode 100644 index 000000000000..7bae83b7c396 --- /dev/null +++ b/include/linux/platform_data/pixcir_i2c_ts.h @@ -0,0 +1,64 @@ +#ifndef _PIXCIR_I2C_TS_H +#define _PIXCIR_I2C_TS_H + +/* + * Register map + */ +#define PIXCIR_REG_POWER_MODE 51 +#define PIXCIR_REG_INT_MODE 52 + +/* + * Power modes: + * active: max scan speed + * idle: lower scan speed with automatic transition to active on touch + * halt: datasheet says sleep but this is more like halt as the chip + * clocks are cut and it can only be brought out of this mode + * using the RESET pin. + */ +enum pixcir_power_mode { + PIXCIR_POWER_ACTIVE, + PIXCIR_POWER_IDLE, + PIXCIR_POWER_HALT, +}; + +#define PIXCIR_POWER_MODE_MASK 0x03 +#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2) + +/* + * Interrupt modes: + * periodical: interrupt is asserted periodicaly + * diff coordinates: interrupt is asserted when coordinates change + * level on touch: interrupt level asserted during touch + * pulse on touch: interrupt pulse asserted druing touch + * + */ +enum pixcir_int_mode { + PIXCIR_INT_PERIODICAL, + PIXCIR_INT_DIFF_COORD, + PIXCIR_INT_LEVEL_TOUCH, + PIXCIR_INT_PULSE_TOUCH, +}; + +#define PIXCIR_INT_MODE_MASK 0x03 +#define PIXCIR_INT_ENABLE (1UL << 3) +#define PIXCIR_INT_POL_HIGH (1UL << 2) + +/** + * struct pixcir_irc_chip_data - chip related data + * @max_fingers: Max number of fingers reported simultaneously by h/w + * @has_hw_ids: Hardware supports finger tracking IDs + * + */ +struct pixcir_i2c_chip_data { + u8 max_fingers; + bool has_hw_ids; +}; + +struct pixcir_ts_platform_data { + int x_max; + int y_max; + int gpio_attb; /* GPIO connected to ATTB line */ + struct pixcir_i2c_chip_data chip; +}; + +#endif -- cgit v1.3-6-gb490 From cb4a5f068096c0cea954f363e70020aabb3555f4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 11:56:21 -0700 Subject: Input: pixcir_i2c_ts - switch the device over to gpiod This allows uniform parsing on legacy, DT and ACPI systems. Acked-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 26 +++++++++----------------- include/linux/platform_data/pixcir_i2c_ts.h | 1 - 2 files changed, 9 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index f7d90997a786..19732b573227 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -25,8 +25,8 @@ #include #include #include +#include #include -#include #include #include @@ -35,6 +35,7 @@ struct pixcir_i2c_ts_data { struct i2c_client *client; struct input_dev *input; + struct gpio_desc *gpio_attb; const struct pixcir_ts_platform_data *pdata; bool running; int max_fingers; /* Max fingers supported in this instance */ @@ -161,7 +162,6 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) { struct pixcir_i2c_ts_data *tsdata = dev_id; - const struct pixcir_ts_platform_data *pdata = tsdata->pdata; struct pixcir_report_data report; while (tsdata->running) { @@ -171,7 +171,7 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) /* report it */ pixcir_ts_report(tsdata, &report); - if (gpio_get_value(pdata->gpio_attb)) { + if (gpiod_get_value(tsdata->gpio_attb)) { if (report.num_touches) { /* * Last report with no finger up? @@ -427,9 +427,6 @@ static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data; - pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0); - /* gpio_attb validity is checked in probe */ - if (of_property_read_u32(np, "touchscreen-size-x", &pdata->x_max)) { dev_err(dev, "Failed to get touchscreen-size-x property\n"); return ERR_PTR(-EINVAL); @@ -442,8 +439,8 @@ static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) } pdata->y_max -= 1; - dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__, - pdata->x_max + 1, pdata->y_max + 1, pdata->gpio_attb); + dev_dbg(dev, "%s: x %d, y %d\n", __func__, + pdata->x_max + 1, pdata->y_max + 1); return pdata; } @@ -476,11 +473,6 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return -EINVAL; } - if (!gpio_is_valid(pdata->gpio_attb)) { - dev_err(dev, "Invalid gpio_attb in pdata\n"); - return -EINVAL; - } - if (!pdata->chip.max_fingers) { dev_err(dev, "Invalid max_fingers in pdata\n"); return -EINVAL; @@ -530,10 +522,10 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input_set_drvdata(input, tsdata); - error = devm_gpio_request_one(dev, pdata->gpio_attb, - GPIOF_DIR_IN, "pixcir_i2c_attb"); - if (error) { - dev_err(dev, "Failed to request ATTB gpio\n"); + tsdata->gpio_attb = devm_gpiod_get(dev, "attb", GPIOD_IN); + if (IS_ERR(tsdata->gpio_attb)) { + error = PTR_ERR(tsdata->gpio_attb); + dev_err(dev, "Failed to request ATTB gpio: %d\n", error); return error; } diff --git a/include/linux/platform_data/pixcir_i2c_ts.h b/include/linux/platform_data/pixcir_i2c_ts.h index 7bae83b7c396..646af6f8b838 100644 --- a/include/linux/platform_data/pixcir_i2c_ts.h +++ b/include/linux/platform_data/pixcir_i2c_ts.h @@ -57,7 +57,6 @@ struct pixcir_i2c_chip_data { struct pixcir_ts_platform_data { int x_max; int y_max; - int gpio_attb; /* GPIO connected to ATTB line */ struct pixcir_i2c_chip_data chip; }; -- cgit v1.3-6-gb490 From 127520caebd9ae1b77c7026bf538a81b8fcd19a8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 13:27:00 -0700 Subject: Input: pixcir_i2c_ts - allow using with GPIO expanders We are using threaded interrupt handler and thus are allowed to sleep. Let's switch over to gpiod_get_value_cansleep() so that we do not get ugly warnings in case GPIO controller might sleep when accessing GPIO. Acked-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 19732b573227..5330c0446540 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -171,7 +171,7 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) /* report it */ pixcir_ts_report(tsdata, &report); - if (gpiod_get_value(tsdata->gpio_attb)) { + if (gpiod_get_value_cansleep(tsdata->gpio_attb)) { if (report.num_touches) { /* * Last report with no finger up? -- cgit v1.3-6-gb490 From 40929167e6e8450a06501d292c5e5c81455d1c47 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 6 Jul 2015 13:27:43 -0700 Subject: Input: pixcir_i2c_ts - add RESET gpio The controller has a RESET pin which is usually controlled over a GPIO line. If such a GPIO is provided, perform a RESET during probe. Signed-off-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/pixcir_i2c_ts.txt | 3 +++ drivers/input/touchscreen/pixcir_i2c_ts.c | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt index 6e551090f465..8eb240a287c8 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt @@ -8,6 +8,9 @@ Required properties: - touchscreen-size-x: horizontal resolution of touchscreen (in pixels) - touchscreen-size-y: vertical resolution of touchscreen (in pixels) +Optional properties: +- reset-gpio: GPIO connected to the RESET line of the chip + Example: i2c@00000000 { diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 5330c0446540..a5a83139aad0 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -36,6 +36,7 @@ struct pixcir_i2c_ts_data { struct i2c_client *client; struct input_dev *input; struct gpio_desc *gpio_attb; + struct gpio_desc *gpio_reset; const struct pixcir_ts_platform_data *pdata; bool running; int max_fingers; /* Max fingers supported in this instance */ @@ -189,6 +190,17 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static void pixcir_reset(struct pixcir_i2c_ts_data *tsdata) +{ + if (!IS_ERR_OR_NULL(tsdata->gpio_reset)) { + gpiod_set_value_cansleep(tsdata->gpio_reset, 1); + ndelay(100); /* datasheet section 1.2.3 says 80ns min. */ + gpiod_set_value_cansleep(tsdata->gpio_reset, 0); + /* wait for controller ready. 100ms guess. */ + msleep(100); + } +} + static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, enum pixcir_power_mode mode) { @@ -529,6 +541,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return error; } + tsdata->gpio_reset = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(tsdata->gpio_reset)) { + error = PTR_ERR(tsdata->gpio_reset); + dev_err(dev, "Failed to request RESET gpio: %d\n", error); + return error; + } + error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, tsdata); @@ -537,6 +557,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return error; } + pixcir_reset(tsdata); + /* Always be in IDLE mode to save power, device supports auto wake */ error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE); if (error) { -- cgit v1.3-6-gb490 From 69b8c2a50c59a3b1c70666059a85c646f897eb96 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 13:43:31 -0700 Subject: Input: pixcir_i2c_ts - simplify input device initialization input_mt_init_slots() will perform necessary settings for performing multi-touch to single-touch emulation, we do not need to do that ourselves. Acked-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index a5a83139aad0..f47480e8dff8 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -510,11 +510,6 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input->close = pixcir_input_close; input->dev.parent = &client->dev; - __set_bit(EV_KEY, input->evbit); - __set_bit(EV_ABS, input->evbit); - __set_bit(BTN_TOUCH, input->keybit); - input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0); - input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); -- cgit v1.3-6-gb490 From d48259a0d2c6820d26ea2077c8d330cf1b33877d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 14:29:29 -0700 Subject: Input: pixcir_i2c_ts - use standard OF touchscreen parsing code Let's switch to using standard touchscreen device properties parsing module instead of doing it by hand in the driver. Acked-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 95 ++++++++++++++----------------- 1 file changed, 44 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index f47480e8dff8..68d0d549797c 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -24,9 +24,10 @@ #include #include #include +#include #include #include -#include +/*#include */ #include #include @@ -37,9 +38,9 @@ struct pixcir_i2c_ts_data { struct input_dev *input; struct gpio_desc *gpio_attb; struct gpio_desc *gpio_reset; - const struct pixcir_ts_platform_data *pdata; - bool running; + const struct pixcir_i2c_chip_data *chip; int max_fingers; /* Max fingers supported in this instance */ + bool running; }; struct pixcir_touch { @@ -62,7 +63,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, u8 touch; int ret, i; int readsize; - const struct pixcir_i2c_chip_data *chip = &tsdata->pdata->chip; + const struct pixcir_i2c_chip_data *chip = tsdata->chip; memset(report, 0, sizeof(struct pixcir_report_data)); @@ -115,13 +116,13 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, struct pixcir_touch *touch; int n, i, slot; struct device *dev = &ts->client->dev; - const struct pixcir_i2c_chip_data *chip = &ts->pdata->chip; + const struct pixcir_i2c_chip_data *chip = ts->chip; n = report->num_touches; if (n > PIXCIR_MAX_SLOTS) n = PIXCIR_MAX_SLOTS; - if (!chip->has_hw_ids) { + if (!ts->chip->has_hw_ids) { for (i = 0; i < n; i++) { touch = &report->touches[i]; pos[i].x = touch->x; @@ -423,77 +424,59 @@ static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, #ifdef CONFIG_OF static const struct of_device_id pixcir_of_match[]; -static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) +static int pixcir_parse_dt(struct device *dev, + struct pixcir_i2c_ts_data *tsdata) { - struct pixcir_ts_platform_data *pdata; - struct device_node *np = dev->of_node; const struct of_device_id *match; match = of_match_device(of_match_ptr(pixcir_of_match), dev); if (!match) - return ERR_PTR(-EINVAL); - - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return ERR_PTR(-ENOMEM); - - pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data; - - if (of_property_read_u32(np, "touchscreen-size-x", &pdata->x_max)) { - dev_err(dev, "Failed to get touchscreen-size-x property\n"); - return ERR_PTR(-EINVAL); - } - pdata->x_max -= 1; - - if (of_property_read_u32(np, "touchscreen-size-y", &pdata->y_max)) { - dev_err(dev, "Failed to get touchscreen-size-y property\n"); - return ERR_PTR(-EINVAL); - } - pdata->y_max -= 1; + return -EINVAL; - dev_dbg(dev, "%s: x %d, y %d\n", __func__, - pdata->x_max + 1, pdata->y_max + 1); + tsdata->chip = (const struct pixcir_i2c_chip_data *)match->data; + if (!tsdata->chip) + return -EINVAL; - return pdata; + return 0; } #else -static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) +static int pixcir_parse_dt(struct device *dev, + struct pixcir_i2c_ts_data *tsdata) { - return ERR_PTR(-EINVAL); + return -EINVAL; } #endif static int pixcir_i2c_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { const struct pixcir_ts_platform_data *pdata = dev_get_platdata(&client->dev); struct device *dev = &client->dev; - struct device_node *np = dev->of_node; struct pixcir_i2c_ts_data *tsdata; struct input_dev *input; int error; - if (np && !pdata) { - pdata = pixcir_parse_dt(dev); - if (IS_ERR(pdata)) - return PTR_ERR(pdata); - } + tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); + if (!tsdata) + return -ENOMEM; - if (!pdata) { + if (pdata) { + tsdata->chip = &pdata->chip; + } else if (dev->of_node) { + error = pixcir_parse_dt(dev, tsdata); + if (error) + return error; + } else { dev_err(&client->dev, "platform data not defined\n"); return -EINVAL; } - if (!pdata->chip.max_fingers) { - dev_err(dev, "Invalid max_fingers in pdata\n"); + if (!tsdata->chip->max_fingers) { + dev_err(dev, "Invalid max_fingers in chip data\n"); return -EINVAL; } - tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); - if (!tsdata) - return -ENOMEM; - input = devm_input_allocate_device(dev); if (!input) { dev_err(dev, "Failed to allocate input device\n"); @@ -502,7 +485,6 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, tsdata->client = client; tsdata->input = input; - tsdata->pdata = pdata; input->name = client->name; input->id.bustype = BUS_I2C; @@ -510,10 +492,21 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input->close = pixcir_input_close; input->dev.parent = &client->dev; - input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); + if (pdata) { + input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); + } else { + input_set_capability(input, EV_ABS, ABS_MT_POSITION_X); + input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); + touchscreen_parse_properties(input, true); + if (!input_abs_get_max(input, ABS_MT_POSITION_X) || + !input_abs_get_max(input, ABS_MT_POSITION_Y)) { + dev_err(dev, "Touchscreen size is not specified\n"); + return -EINVAL; + } + } - tsdata->max_fingers = tsdata->pdata->chip.max_fingers; + tsdata->max_fingers = tsdata->chip->max_fingers; if (tsdata->max_fingers > PIXCIR_MAX_SLOTS) { tsdata->max_fingers = PIXCIR_MAX_SLOTS; dev_info(dev, "Limiting maximum fingers to %d\n", -- cgit v1.3-6-gb490 From d5ebe37e8cded781bb91ac63dda2da180ecb90b6 Mon Sep 17 00:00:00 2001 From: HungNien Chen Date: Thu, 9 Jul 2015 10:27:02 -0700 Subject: Input: wdt87xx_i2c - populate vendor and product in input device These attributes can be used to identify controllers present in the system. Signed-off-by: HungNien Chen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wdt87xx_i2c.c | 46 ++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index fb92ae1c5fae..764d8f28203c 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -23,7 +23,7 @@ #include #define WDT87XX_NAME "wdt87xx_i2c" -#define WDT87XX_DRV_VER "0.9.6" +#define WDT87XX_DRV_VER "0.9.7" #define WDT87XX_FW_NAME "wdt87xx_fw.bin" #define WDT87XX_CFG_NAME "wdt87xx_cfg.bin" @@ -85,6 +85,11 @@ #define CTL_PARAM_OFFSET_PHY_H 24 #define CTL_PARAM_OFFSET_FACTOR 32 +/* The definition of the device descriptor */ +#define WDT_GD_DEVICE 1 +#define DEV_DESC_OFFSET_VID 8 +#define DEV_DESC_OFFSET_PID 10 + /* Communication commands */ #define PACKET_SIZE 56 #define VND_REQ_READ 0x06 @@ -165,6 +170,8 @@ struct wdt87xx_sys_param { u16 scaling_factor; u32 max_x; u32 max_y; + u16 vendor_id; + u16 product_id; }; struct wdt87xx_data { @@ -208,6 +215,32 @@ static int wdt87xx_i2c_xfer(struct i2c_client *client, return 0; } +static int wdt87xx_get_desc(struct i2c_client *client, u8 desc_idx, + u8 *buf, size_t len) +{ + u8 tx_buf[] = { 0x22, 0x00, 0x10, 0x0E, 0x23, 0x00 }; + int error; + + tx_buf[2] |= desc_idx & 0xF; + + error = wdt87xx_i2c_xfer(client, tx_buf, sizeof(tx_buf), + buf, len); + if (error) { + dev_err(&client->dev, "get desc failed: %d\n", error); + return error; + } + + if (buf[0] != len) { + dev_err(&client->dev, "unexpected response to get desc: %d\n", + buf[0]); + return -EINVAL; + } + + mdelay(WDT_COMMAND_DELAY_MS); + + return 0; +} + static int wdt87xx_get_string(struct i2c_client *client, u8 str_idx, u8 *buf, size_t len) { @@ -403,6 +436,15 @@ static int wdt87xx_get_sysparam(struct i2c_client *client, u8 buf[PKT_READ_SIZE]; int error; + error = wdt87xx_get_desc(client, WDT_GD_DEVICE, buf, 18); + if (error) { + dev_err(&client->dev, "failed to get device desc\n"); + return error; + } + + param->vendor_id = get_unaligned_le16(buf + DEV_DESC_OFFSET_VID); + param->product_id = get_unaligned_le16(buf + DEV_DESC_OFFSET_PID); + error = wdt87xx_get_string(client, STRIDX_PARAMETERS, buf, 34); if (error) { dev_err(&client->dev, "failed to get parameters\n"); @@ -994,6 +1036,8 @@ static int wdt87xx_ts_create_input_device(struct wdt87xx_data *wdt) input->name = "WDT87xx Touchscreen"; input->id.bustype = BUS_I2C; + input->id.vendor = wdt->param.vendor_id; + input->id.product = wdt->param.product_id; input->phys = wdt->phys; input_set_abs_params(input, ABS_MT_POSITION_X, 0, -- cgit v1.3-6-gb490 From 339d6b88e872f8369495a7224916a4d1d8376ca3 Mon Sep 17 00:00:00 2001 From: HungNien Chen Date: Sat, 11 Jul 2015 17:30:19 -0700 Subject: Input: wdt87xx_i2c - change the sleep time to 2500ms after the sw reset The original wait time was 200ms which was enough for the firmware to finish loading and boot. After that the firmware will perform initialization and touch calibration, which will take about 1.1 second. The touch calibration will change controller frequency to scan at the most optimal frequency and during calibration/frequency switching process we may run into i2c data errors. To avoid them we extend the sleep to 2500ms after issuing the sw reset. Signed-off-by: HungNien Chen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wdt87xx_i2c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index 764d8f28203c..515c20a6e10f 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -157,6 +157,7 @@ /* Controller requires minimum 300us between commands */ #define WDT_COMMAND_DELAY_MS 2 #define WDT_FLASH_WRITE_DELAY_MS 4 +#define WDT_FW_RESET_TIME 2500 struct wdt87xx_sys_param { u16 fw_id; @@ -406,7 +407,7 @@ static int wdt87xx_sw_reset(struct i2c_client *client) } /* Wait the device to be ready */ - msleep(200); + msleep(WDT_FW_RESET_TIME); return 0; } -- cgit v1.3-6-gb490 From d2aa914d27f1fb9b7d4e4767c1698ed6a665cb1d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:41 +0200 Subject: irqchip/vt8500: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: @@ struct irq_data *d; expression E1; @@ -__irq_set_handler_locked(d->irq, E1); +irq_set_handler_locked(d, E1); Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper --- drivers/irqchip/irq-vt8500.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c index 52c280004c56..8371d9978d31 100644 --- a/drivers/irqchip/irq-vt8500.c +++ b/drivers/irqchip/irq-vt8500.c @@ -126,15 +126,15 @@ static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type) return -EINVAL; case IRQF_TRIGGER_HIGH: dctr |= VT8500_TRIGGER_HIGH; - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); break; case IRQF_TRIGGER_FALLING: dctr |= VT8500_TRIGGER_FALLING; - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); break; case IRQF_TRIGGER_RISING: dctr |= VT8500_TRIGGER_RISING; - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); break; } writeb(dctr, base + VT8500_ICDC + d->hwirq); -- cgit v1.3-6-gb490 From 0a2b64979ab7f8d5325879bd552dcb85974b2980 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 14:39:45 +0200 Subject: irqchip/metag-ext: Use irq_set_chip_handler_name_locked() Hand in irq_data and avoid the redundant lookup of irq_desc. Originally-from: Jiang Liu Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-metag-ext.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-metag-ext.c b/drivers/irqchip/irq-metag-ext.c index 2cb474ad8809..5f4c52928d16 100644 --- a/drivers/irqchip/irq-metag-ext.c +++ b/drivers/irqchip/irq-metag-ext.c @@ -404,7 +404,6 @@ static int meta_intc_irq_set_type(struct irq_data *data, unsigned int flow_type) #ifdef CONFIG_METAG_SUSPEND_MEM struct meta_intc_priv *priv = &meta_intc_priv; #endif - unsigned int irq = data->irq; irq_hw_number_t hw = data->hwirq; unsigned int bit = 1 << meta_intc_offset(hw); void __iomem *level_addr = meta_intc_level_addr(hw); @@ -413,11 +412,11 @@ static int meta_intc_irq_set_type(struct irq_data *data, unsigned int flow_type) /* update the chip/handler */ if (flow_type & IRQ_TYPE_LEVEL_MASK) - __irq_set_chip_handler_name_locked(irq, &meta_intc_level_chip, - handle_level_irq, NULL); + irq_set_chip_handler_name_locked(data, &meta_intc_level_chip, + handle_level_irq, NULL); else - __irq_set_chip_handler_name_locked(irq, &meta_intc_edge_chip, - handle_edge_irq, NULL); + irq_set_chip_handler_name_locked(data, &meta_intc_edge_chip, + handle_edge_irq, NULL); /* and clear/set the bit in HWLEVELEXT */ __global_lock2(flags); -- cgit v1.3-6-gb490 From a595fc51a3417274acc1eee63967e9b9e657cc89 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 14:41:25 +0200 Subject: irqchip/mips-gic: Use irq_set_chip_handler_name_locked Use irq_set_handler_name_locked() as it avoids a redundant lookup of the irq descriptor. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Jason Cooper --- drivers/irqchip/irq-mips-gic.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index e6c2df99662a..e670f651166d 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -367,15 +367,12 @@ static int gic_set_type(struct irq_data *d, unsigned int type) break; } - if (is_edge) { - __irq_set_chip_handler_name_locked(d->irq, - &gic_edge_irq_controller, - handle_edge_irq, NULL); - } else { - __irq_set_chip_handler_name_locked(d->irq, - &gic_level_irq_controller, - handle_level_irq, NULL); - } + if (is_edge) + irq_set_chip_handler_name_locked(d, &gic_edge_irq_controller, + handle_edge_irq, NULL); + else + irq_set_chip_handler_name_locked(d, &gic_level_irq_controller, + handle_level_irq, NULL); spin_unlock_irqrestore(&gic_lock, flags); return 0; -- cgit v1.3-6-gb490 From 80c394fab89649585089f5bd5013f2d99e5756ef Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 11 Jun 2015 13:27:51 +0200 Subject: cxl: Add explicit precision specifiers C99 says that a precision given as simply '.' with no following digits or * should be interpreted as 0. The kernel's printf implementation, however, treats this case as if the precision was omitted. C99 also says that if both the precision and value are 0, no digits should be printed. Even if the kernel followed C99 to the letter, I don't think that would be particularly useful in these cases. For consistency with most other format strings in the file, use an explicit precision of 16 and add a 0x prefix. Signed-off-by: Rasmus Villemoes Signed-off-by: Michael Ellerman --- drivers/misc/cxl/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c index 680cd263436d..2b64bb43b304 100644 --- a/drivers/misc/cxl/irq.c +++ b/drivers/misc/cxl/irq.c @@ -147,7 +147,7 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info) if (dsisr & CXL_PSL_DSISR_An_PE) return handle_psl_slice_error(ctx, dsisr, irq_info->errstat); if (dsisr & CXL_PSL_DSISR_An_AE) { - pr_devel("CXL interrupt: AFU Error %.llx\n", irq_info->afu_err); + pr_devel("CXL interrupt: AFU Error 0x%.16llx\n", irq_info->afu_err); if (ctx->pending_afu_err) { /* @@ -158,7 +158,7 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info) * probably best that we log them somewhere: */ dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error " - "undelivered to pe %i: %.llx\n", + "undelivered to pe %i: 0x%.16llx\n", ctx->pe, irq_info->afu_err); } else { spin_lock(&ctx->lock); -- cgit v1.3-6-gb490 From de369538436ae0caf784c69187ad0e53152b7ddf Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 11 Jun 2015 13:27:52 +0200 Subject: cxl: use more common format specifier A precision of 16 (%.16llx) has the same effect as a field width of 16 along with passing the 0 flag (%016llx), but the latter is much more common in the kernel tree. Update cxl to use that. Signed-off-by: Rasmus Villemoes Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/irq.c | 32 ++++++++++++++++---------------- drivers/misc/cxl/native.c | 10 +++++----- drivers/misc/cxl/pci.c | 10 +++++----- drivers/misc/cxl/trace.h | 10 +++++----- 4 files changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c index 2b64bb43b304..abfce494ca6b 100644 --- a/drivers/misc/cxl/irq.c +++ b/drivers/misc/cxl/irq.c @@ -30,12 +30,12 @@ static irqreturn_t handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr, u6 serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An); afu_debug = cxl_p1n_read(ctx->afu, CXL_AFU_DEBUG_An); - dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%.16llx\n", errstat); - dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%.16llx\n", fir1); - dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%.16llx\n", fir2); - dev_crit(&ctx->afu->dev, "PSL_SERR_An: 0x%.16llx\n", serr); - dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%.16llx\n", fir_slice); - dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%.16llx\n", afu_debug); + dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%016llx\n", errstat); + dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%016llx\n", fir1); + dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%016llx\n", fir2); + dev_crit(&ctx->afu->dev, "PSL_SERR_An: 0x%016llx\n", serr); + dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice); + dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug); dev_crit(&ctx->afu->dev, "STOPPING CXL TRACE\n"); cxl_stop_trace(ctx->afu->adapter); @@ -54,10 +54,10 @@ irqreturn_t cxl_slice_irq_err(int irq, void *data) fir_slice = cxl_p1n_read(afu, CXL_PSL_FIR_SLICE_An); errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An); afu_debug = cxl_p1n_read(afu, CXL_AFU_DEBUG_An); - dev_crit(&afu->dev, "PSL_SERR_An: 0x%.16llx\n", serr); - dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%.16llx\n", fir_slice); - dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%.16llx\n", errstat); - dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%.16llx\n", afu_debug); + dev_crit(&afu->dev, "PSL_SERR_An: 0x%016llx\n", serr); + dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice); + dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%016llx\n", errstat); + dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug); cxl_p1n_write(afu, CXL_PSL_SERR_An, serr); @@ -72,7 +72,7 @@ static irqreturn_t cxl_irq_err(int irq, void *data) WARN(1, "CXL ERROR interrupt %i\n", irq); err_ivte = cxl_p1_read(adapter, CXL_PSL_ErrIVTE); - dev_crit(&adapter->dev, "PSL_ErrIVTE: 0x%.16llx\n", err_ivte); + dev_crit(&adapter->dev, "PSL_ErrIVTE: 0x%016llx\n", err_ivte); dev_crit(&adapter->dev, "STOPPING CXL TRACE\n"); cxl_stop_trace(adapter); @@ -80,7 +80,7 @@ static irqreturn_t cxl_irq_err(int irq, void *data) fir1 = cxl_p1_read(adapter, CXL_PSL_FIR1); fir2 = cxl_p1_read(adapter, CXL_PSL_FIR2); - dev_crit(&adapter->dev, "PSL_FIR1: 0x%.16llx\nPSL_FIR2: 0x%.16llx\n", fir1, fir2); + dev_crit(&adapter->dev, "PSL_FIR1: 0x%016llx\nPSL_FIR2: 0x%016llx\n", fir1, fir2); return IRQ_HANDLED; } @@ -147,7 +147,7 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info) if (dsisr & CXL_PSL_DSISR_An_PE) return handle_psl_slice_error(ctx, dsisr, irq_info->errstat); if (dsisr & CXL_PSL_DSISR_An_AE) { - pr_devel("CXL interrupt: AFU Error 0x%.16llx\n", irq_info->afu_err); + pr_devel("CXL interrupt: AFU Error 0x%016llx\n", irq_info->afu_err); if (ctx->pending_afu_err) { /* @@ -158,7 +158,7 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info) * probably best that we log them somewhere: */ dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error " - "undelivered to pe %i: 0x%.16llx\n", + "undelivered to pe %i: 0x%016llx\n", ctx->pe, irq_info->afu_err); } else { spin_lock(&ctx->lock); @@ -211,8 +211,8 @@ static irqreturn_t cxl_irq_multiplexed(int irq, void *data) } rcu_read_unlock(); - WARN(1, "Unable to demultiplex CXL PSL IRQ for PE %i DSISR %.16llx DAR" - " %.16llx\n(Possible AFU HW issue - was a term/remove acked" + WARN(1, "Unable to demultiplex CXL PSL IRQ for PE %i DSISR %016llx DAR" + " %016llx\n(Possible AFU HW issue - was a term/remove acked" " with outstanding transactions?)\n", ph, irq_info.dsisr, irq_info.dar); return fail_psl_irq(afu, &irq_info); diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index 10567f245818..fc9310dd2367 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -41,7 +41,7 @@ static int afu_control(struct cxl_afu *afu, u64 command, rc = -EBUSY; goto out; } - pr_devel_ratelimited("AFU control... (0x%.16llx)\n", + pr_devel_ratelimited("AFU control... (0x%016llx)\n", AFU_Cntl | command); cpu_relax(); AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); @@ -120,13 +120,13 @@ int cxl_psl_purge(struct cxl_afu *afu) goto out; } dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An); - pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%.16llx PSL_DSISR: 0x%.16llx\n", PSL_CNTL, dsisr); + pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%016llx PSL_DSISR: 0x%016llx\n", PSL_CNTL, dsisr); if (dsisr & CXL_PSL_DSISR_TRANS) { dar = cxl_p2n_read(afu, CXL_PSL_DAR_An); - dev_notice(&afu->dev, "PSL purge terminating pending translation, DSISR: 0x%.16llx, DAR: 0x%.16llx\n", dsisr, dar); + dev_notice(&afu->dev, "PSL purge terminating pending translation, DSISR: 0x%016llx, DAR: 0x%016llx\n", dsisr, dar); cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); } else if (dsisr) { - dev_notice(&afu->dev, "PSL purge acknowledging pending non-translation fault, DSISR: 0x%.16llx\n", dsisr); + dev_notice(&afu->dev, "PSL purge acknowledging pending non-translation fault, DSISR: 0x%016llx\n", dsisr); cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); } else { cpu_relax(); @@ -684,7 +684,7 @@ static void recover_psl_err(struct cxl_afu *afu, u64 errstat) { u64 dsisr; - pr_devel("RECOVERING FROM PSL ERROR... (0x%.16llx)\n", errstat); + pr_devel("RECOVERING FROM PSL ERROR... (0x%016llx)\n", errstat); /* Clear PSL_DSISR[PE] */ dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An); diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 32ad09705949..eb05efb74eed 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -656,7 +656,7 @@ static int sanitise_afu_regs(struct cxl_afu *afu) */ reg = cxl_p2n_read(afu, CXL_AFU_Cntl_An); if ((reg & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) { - dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#.16llx\n", reg); + dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#016llx\n", reg); if (__cxl_afu_reset(afu)) return -EIO; if (cxl_afu_disable(afu)) @@ -677,7 +677,7 @@ static int sanitise_afu_regs(struct cxl_afu *afu) cxl_p2n_write(afu, CXL_SSTP0_An, 0x0000000000000000); reg = cxl_p2n_read(afu, CXL_PSL_DSISR_An); if (reg) { - dev_warn(&afu->dev, "AFU had pending DSISR: %#.16llx\n", reg); + dev_warn(&afu->dev, "AFU had pending DSISR: %#016llx\n", reg); if (reg & CXL_PSL_DSISR_TRANS) cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); else @@ -686,12 +686,12 @@ static int sanitise_afu_regs(struct cxl_afu *afu) reg = cxl_p1n_read(afu, CXL_PSL_SERR_An); if (reg) { if (reg & ~0xffff) - dev_warn(&afu->dev, "AFU had pending SERR: %#.16llx\n", reg); + dev_warn(&afu->dev, "AFU had pending SERR: %#016llx\n", reg); cxl_p1n_write(afu, CXL_PSL_SERR_An, reg & ~0xffff); } reg = cxl_p2n_read(afu, CXL_PSL_ErrStat_An); if (reg) { - dev_warn(&afu->dev, "AFU had pending error status: %#.16llx\n", reg); + dev_warn(&afu->dev, "AFU had pending error status: %#016llx\n", reg); cxl_p2n_write(afu, CXL_PSL_ErrStat_An, reg); } @@ -893,7 +893,7 @@ static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev) if (pci_request_region(dev, 0, "priv 1 regs")) goto err2; - pr_devel("cxl_map_adapter_regs: p1: %#.16llx %#llx, p2: %#.16llx %#llx", + pr_devel("cxl_map_adapter_regs: p1: %#016llx %#llx, p2: %#016llx %#llx", p1_base(dev), p1_size(dev), p2_base(dev), p2_size(dev)); if (!(adapter->p1_mmio = ioremap(p1_base(dev), p1_size(dev)))) diff --git a/drivers/misc/cxl/trace.h b/drivers/misc/cxl/trace.h index ae434d87887e..6e1e2adfba8e 100644 --- a/drivers/misc/cxl/trace.h +++ b/drivers/misc/cxl/trace.h @@ -105,7 +105,7 @@ TRACE_EVENT(cxl_attach, __entry->num_interrupts = num_interrupts; ), - TP_printk("afu%i.%i pid=%i pe=%i wed=0x%.16llx irqs=%i amr=0x%llx", + TP_printk("afu%i.%i pid=%i pe=%i wed=0x%016llx irqs=%i amr=0x%llx", __entry->card, __entry->afu, __entry->pid, @@ -177,7 +177,7 @@ TRACE_EVENT(cxl_psl_irq, __entry->dar = dar; ), - TP_printk("afu%i.%i pe=%i irq=%i dsisr=%s dar=0x%.16llx", + TP_printk("afu%i.%i pe=%i irq=%i dsisr=%s dar=0x%016llx", __entry->card, __entry->afu, __entry->pe, @@ -233,7 +233,7 @@ TRACE_EVENT(cxl_ste_miss, __entry->dar = dar; ), - TP_printk("afu%i.%i pe=%i dar=0x%.16llx", + TP_printk("afu%i.%i pe=%i dar=0x%016llx", __entry->card, __entry->afu, __entry->pe, @@ -264,7 +264,7 @@ TRACE_EVENT(cxl_ste_write, __entry->v = v; ), - TP_printk("afu%i.%i pe=%i SSTE[%i] E=0x%.16llx V=0x%.16llx", + TP_printk("afu%i.%i pe=%i SSTE[%i] E=0x%016llx V=0x%016llx", __entry->card, __entry->afu, __entry->pe, @@ -295,7 +295,7 @@ TRACE_EVENT(cxl_pte_miss, __entry->dar = dar; ), - TP_printk("afu%i.%i pe=%i dsisr=%s dar=0x%.16llx", + TP_printk("afu%i.%i pe=%i dsisr=%s dar=0x%016llx", __entry->card, __entry->afu, __entry->pe, -- cgit v1.3-6-gb490 From 05e062f92c917b14ffa944e4a98e5348b53b1390 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 26 Jun 2015 14:10:54 -0300 Subject: clk: imx: clk-imx6q: Provide initial IPU clock settings for mx6dl Currently it is not possible to use HDMI and LVDS at the same time on a imx6dl-sabresd board. Fix this usecase by setting IMX6QDL_CLK_PLL3_PFD1_540M to 540MHz and also by setting it as the parent of IMX6QDL_CLK_IPU1_SEL. Based on the configuration done in the FSL kernel. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx6q.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index d046f8e43de8..c507bcad2c37 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -494,6 +494,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk_set_parent(clk[IMX6QDL_CLK_LDB_DI1_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); } + clk_set_rate(clk[IMX6QDL_CLK_PLL3_PFD1_540M], 540000000); + if (clk_on_imx6dl()) + clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]); + clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]); -- cgit v1.3-6-gb490 From c5e0688cc75e46b0e9be39224d8e4646593ef375 Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:19 +0530 Subject: drm/i915/skl: Retrieve the Rpe value from Pcode Read the efficient frequency (aka RPe) value through the the mailbox command (0x1A) from the pcode, as done on Haswell and Broadwell. The turbo minimum frequency softlimit is not revised as per the efficient frequency value. v2: Replaced the conditional expression operator with 'if' statement (Tom) v3: Corrected the derivation of efficient frequency & shifted the GEN9_FREQ_SCALER multiplications downwards (Ville) Issue: VIZ-5143 Signed-off-by: Akash Goel Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4e24d2b13e4c..ca82ad23e3f8 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4703,18 +4703,11 @@ static void gen6_init_rps_frequencies(struct drm_device *dev) dev_priv->rps.min_freq = (rp_state_cap >> 16) & 0xff; } - if (IS_SKYLAKE(dev)) { - /* Store the frequency values in 16.66 MHZ units, which is - the natural hardware unit for SKL */ - dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER; - dev_priv->rps.rp1_freq *= GEN9_FREQ_SCALER; - dev_priv->rps.min_freq *= GEN9_FREQ_SCALER; - } /* hw_max = RP0 until we check for overclocking */ dev_priv->rps.max_freq = dev_priv->rps.rp0_freq; dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq; - if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + if (IS_HASWELL(dev) || IS_BROADWELL(dev) || IS_SKYLAKE(dev)) { ret = sandybridge_pcode_read(dev_priv, HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL, &ddcc_status); @@ -4726,6 +4719,16 @@ static void gen6_init_rps_frequencies(struct drm_device *dev) dev_priv->rps.max_freq); } + if (IS_SKYLAKE(dev)) { + /* Store the frequency values in 16.66 MHZ units, which is + the natural hardware unit for SKL */ + dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER; + dev_priv->rps.rp1_freq *= GEN9_FREQ_SCALER; + dev_priv->rps.min_freq *= GEN9_FREQ_SCALER; + dev_priv->rps.max_freq *= GEN9_FREQ_SCALER; + dev_priv->rps.efficient_freq *= GEN9_FREQ_SCALER; + } + dev_priv->rps.idle_freq = dev_priv->rps.min_freq; /* Preserve min/max settings in case of re-init */ -- cgit v1.3-6-gb490 From 4c8c7743b53fb169ef2cb07a9eaa80c1b6c1d04e Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:20 +0530 Subject: drm/i915/skl: Ring frequency table programming changes Ring frequency table programming changes for SKL. No need for a floor on ring frequency, as the issue of performance impact with ring running below DDR frequency, is believed to be fixed on SKL v2: Removed the check for avoiding ring frequency programming for BXT (Rodrigo) Issue: VIZ-5144 Signed-off-by: Akash Goel Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ca82ad23e3f8..9d98f4074eae 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5021,6 +5021,7 @@ static void __gen6_update_ring_freq(struct drm_device *dev) int min_freq = 15; unsigned int gpu_freq; unsigned int max_ia_freq, min_ring_freq; + unsigned int max_gpu_freq, min_gpu_freq; int scaling_factor = 180; struct cpufreq_policy *policy; @@ -5045,17 +5046,31 @@ static void __gen6_update_ring_freq(struct drm_device *dev) /* convert DDR frequency from units of 266.6MHz to bandwidth */ min_ring_freq = mult_frac(min_ring_freq, 8, 3); + if (IS_SKYLAKE(dev)) { + /* Convert GT frequency to 50 HZ units */ + min_gpu_freq = dev_priv->rps.min_freq / GEN9_FREQ_SCALER; + max_gpu_freq = dev_priv->rps.max_freq / GEN9_FREQ_SCALER; + } else { + min_gpu_freq = dev_priv->rps.min_freq; + max_gpu_freq = dev_priv->rps.max_freq; + } + /* * For each potential GPU frequency, load a ring frequency we'd like * to use for memory access. We do this by specifying the IA frequency * the PCU should use as a reference to determine the ring frequency. */ - for (gpu_freq = dev_priv->rps.max_freq; gpu_freq >= dev_priv->rps.min_freq; - gpu_freq--) { - int diff = dev_priv->rps.max_freq - gpu_freq; + for (gpu_freq = max_gpu_freq; gpu_freq >= min_gpu_freq; gpu_freq--) { + int diff = max_gpu_freq - gpu_freq; unsigned int ia_freq = 0, ring_freq = 0; - if (INTEL_INFO(dev)->gen >= 8) { + if (IS_SKYLAKE(dev)) { + /* + * ring_freq = 2 * GT. ring_freq is in 100MHz units + * No floor required for ring frequency on SKL. + */ + ring_freq = gpu_freq; + } else if (INTEL_INFO(dev)->gen >= 8) { /* max(2 * GT, DDR). NB: GT is 50MHz units */ ring_freq = max(min_ring_freq, gpu_freq); } else if (IS_HASWELL(dev)) { -- cgit v1.3-6-gb490 From f936ec34dea8da6f38340c1ae2cb35207d8d78cb Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:22 +0530 Subject: drm/i915/skl: Updated the i915_ring_freq_table debugfs function Updated the i915_ring_freq_table debugfs function to support the read of ring frequency table, through Punit interface, for SKL also. Issue: VIZ-5144 Signed-off-by: Akash Goel Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 73aaea22bbef..27f0a0d98e3a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1782,6 +1782,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) struct drm_i915_private *dev_priv = dev->dev_private; int ret = 0; int gpu_freq, ia_freq; + unsigned int max_gpu_freq, min_gpu_freq; if (!(IS_GEN6(dev) || IS_GEN7(dev))) { seq_puts(m, "unsupported on this chipset\n"); @@ -1796,17 +1797,27 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) if (ret) goto out; + if (IS_SKYLAKE(dev)) { + /* Convert GT frequency to 50 HZ units */ + min_gpu_freq = + dev_priv->rps.min_freq_softlimit / GEN9_FREQ_SCALER; + max_gpu_freq = + dev_priv->rps.max_freq_softlimit / GEN9_FREQ_SCALER; + } else { + min_gpu_freq = dev_priv->rps.min_freq_softlimit; + max_gpu_freq = dev_priv->rps.max_freq_softlimit; + } + seq_puts(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n"); - for (gpu_freq = dev_priv->rps.min_freq_softlimit; - gpu_freq <= dev_priv->rps.max_freq_softlimit; - gpu_freq++) { + for (gpu_freq = min_gpu_freq; gpu_freq <= max_gpu_freq; gpu_freq++) { ia_freq = gpu_freq; sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_MIN_FREQ_TABLE, &ia_freq); seq_printf(m, "%d\t\t%d\t\t\t\t%d\n", - intel_gpu_freq(dev_priv, gpu_freq), + intel_gpu_freq(dev_priv, (gpu_freq * + (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1))), ((ia_freq >> 0) & 0xff) * 100, ((ia_freq >> 8) & 0xff) * 100); } -- cgit v1.3-6-gb490 From b8afb9113c519a8bd742f7df8c424b0af69a75cd Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 29 Jun 2015 15:25:48 +0300 Subject: drm/i915: Keep GMCH DPLL VGA mode always disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We disable the DPLL VGA mode when enabling the DPLL, but we enaable it again when disabling the DPLL. Having VGA mode enabled even in unused DPLLs can cause problems for CHV, so it seems wiser to always keep it disabled. And let's just do that on all GMCH platforms to keep things as similar as possible between them. Signed-off-by: Ville Syrjälä Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 +++++--- drivers/gpu/drm/i915/intel_dsi.c | 2 +- drivers/gpu/drm/i915/intel_runtime_pm.c | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c465a52a38bc..59986377ba8a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1790,13 +1790,13 @@ static void i9xx_disable_pll(struct intel_crtc *crtc) /* Make sure the pipe isn't still relying on us */ assert_pipe_disabled(dev_priv, pipe); - I915_WRITE(DPLL(pipe), 0); + I915_WRITE(DPLL(pipe), DPLL_VGA_MODE_DIS); POSTING_READ(DPLL(pipe)); } static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) { - u32 val = 0; + u32 val; /* Make sure the pipe isn't still relying on us */ assert_pipe_disabled(dev_priv, pipe); @@ -1805,6 +1805,7 @@ static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) * Leave integrated clock source and reference clock enabled for pipe B. * The latter is needed for VGA hotplug / manual detection. */ + val = DPLL_VGA_MODE_DIS; if (pipe == PIPE_B) val = DPLL_INTEGRATED_CRI_CLK_VLV | DPLL_REFA_CLK_ENABLE_VLV; I915_WRITE(DPLL(pipe), val); @@ -1821,7 +1822,8 @@ static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) assert_pipe_disabled(dev_priv, pipe); /* Set PLL en = 0 */ - val = DPLL_SSC_REF_CLOCK_CHV | DPLL_REFA_CLK_ENABLE_VLV; + val = DPLL_SSC_REF_CLOCK_CHV | + DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; if (pipe != PIPE_A) val |= DPLL_INTEGRATED_CRI_CLK_VLV; I915_WRITE(DPLL(pipe), val); diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 98998e976dbb..5381ddcc2a79 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -418,7 +418,7 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) /* update the hw state for DPLL */ intel_crtc->config->dpll_hw_state.dpll = DPLL_INTEGRATED_CLOCK_VLV | - DPLL_REFA_CLK_ENABLE_VLV; + DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; tmp = I915_READ(DSPCLK_GATE_D); tmp |= DPOUNIT_CLOCK_GATE_DISABLE; diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 1a45385f4d66..f0e6f49ee33a 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -882,7 +882,7 @@ static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, * display and the reference clock for VGA * hotplug / manual detection. */ - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ @@ -933,13 +933,13 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, */ if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) { phy = DPIO_PHY0; - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | DPLL_REFA_CLK_ENABLE_VLV); - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); } else { phy = DPIO_PHY1; - I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) | + I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) | DPLL_VGA_MODE_DIS | DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); } udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ -- cgit v1.3-6-gb490 From 60bfe44f83c0a9d7293e821c4ddae3770d60acf9 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 29 Jun 2015 15:25:49 +0300 Subject: drm/i915: Apply OCD to VLV/CHV DPLL defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the spurious 'A' from the VLV/CHV ref clock enable define, and add the "REF" to the VLV ref clock selection bit. Also s/CLOCK/CLK/ for extra consistency. Signed-off-by: Ville Syrjälä Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- drivers/gpu/drm/i915/intel_display.c | 14 +++++++------- drivers/gpu/drm/i915/intel_dsi.c | 6 +++--- drivers/gpu/drm/i915/intel_runtime_pm.c | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1c4d7894b429..0650a3d8a40f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2150,7 +2150,7 @@ enum skl_disp_power_wells { #define DPLL_DVO_2X_MODE (1 << 30) #define DPLL_EXT_BUFFER_ENABLE_VLV (1 << 30) #define DPLL_SYNCLOCK_ENABLE (1 << 29) -#define DPLL_REFA_CLK_ENABLE_VLV (1 << 29) +#define DPLL_REF_CLK_ENABLE_VLV (1 << 29) #define DPLL_VGA_MODE_DIS (1 << 28) #define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ #define DPLLB_MODE_LVDS (2 << 26) /* i915 */ @@ -2164,8 +2164,8 @@ enum skl_disp_power_wells { #define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */ #define DPLL_LOCK_VLV (1<<15) #define DPLL_INTEGRATED_CRI_CLK_VLV (1<<14) -#define DPLL_INTEGRATED_CLOCK_VLV (1<<13) -#define DPLL_SSC_REF_CLOCK_CHV (1<<13) +#define DPLL_INTEGRATED_REF_CLK_VLV (1<<13) +#define DPLL_SSC_REF_CLK_CHV (1<<13) #define DPLL_PORTC_READY_MASK (0xf << 4) #define DPLL_PORTB_READY_MASK (0xf) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 59986377ba8a..a7482ab140e1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1807,7 +1807,7 @@ static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) */ val = DPLL_VGA_MODE_DIS; if (pipe == PIPE_B) - val = DPLL_INTEGRATED_CRI_CLK_VLV | DPLL_REFA_CLK_ENABLE_VLV; + val = DPLL_INTEGRATED_CRI_CLK_VLV | DPLL_REF_CLK_ENABLE_VLV; I915_WRITE(DPLL(pipe), val); POSTING_READ(DPLL(pipe)); @@ -1822,8 +1822,8 @@ static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) assert_pipe_disabled(dev_priv, pipe); /* Set PLL en = 0 */ - val = DPLL_SSC_REF_CLOCK_CHV | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; + val = DPLL_SSC_REF_CLK_CHV | + DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; if (pipe != PIPE_A) val |= DPLL_INTEGRATED_CRI_CLK_VLV; I915_WRITE(DPLL(pipe), val); @@ -7224,8 +7224,8 @@ static void vlv_compute_dpll(struct intel_crtc *crtc, * clock for pipe B, since VGA hotplug / manual detection depends * on it. */ - dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV | - DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV; + dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REF_CLK_ENABLE_VLV | + DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_REF_CLK_VLV; /* We should never disable this, set it here for state tracking */ if (crtc->pipe == PIPE_B) dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; @@ -7331,8 +7331,8 @@ static void vlv_prepare_pll(struct intel_crtc *crtc, static void chv_compute_dpll(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { - pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS | + pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLK_CHV | + DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS | DPLL_VCO_ENABLE; if (crtc->pipe != PIPE_A) pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 5381ddcc2a79..f4438eb5b458 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -413,12 +413,12 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) /* Disable DPOunit clock gating, can stall pipe * and we need DPLL REFA always enabled */ tmp = I915_READ(DPLL(pipe)); - tmp |= DPLL_REFA_CLK_ENABLE_VLV; + tmp |= DPLL_REF_CLK_ENABLE_VLV; I915_WRITE(DPLL(pipe), tmp); /* update the hw state for DPLL */ - intel_crtc->config->dpll_hw_state.dpll = DPLL_INTEGRATED_CLOCK_VLV | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; + intel_crtc->config->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV | + DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; tmp = I915_READ(DSPCLK_GATE_D); tmp |= DPOUNIT_CLOCK_GATE_DISABLE; diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index f0e6f49ee33a..932d96332eca 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -883,7 +883,7 @@ static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, * hotplug / manual detection. */ I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); + DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ vlv_set_power_well(dev_priv, power_well, true); @@ -934,13 +934,13 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) { phy = DPIO_PHY0; I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | - DPLL_REFA_CLK_ENABLE_VLV); + DPLL_REF_CLK_ENABLE_VLV); I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); + DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); } else { phy = DPIO_PHY1; I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) | DPLL_VGA_MODE_DIS | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); + DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); } udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ vlv_set_power_well(dev_priv, power_well, true); -- cgit v1.3-6-gb490 From 8fcd5cd8b3cb29019937ab4b773da27a37e8e79b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 29 Jun 2015 15:25:50 +0300 Subject: drm/i915: Simplify CHV pipe A power well code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pipe A power well is the "disp2d" well on CHV and pipe B and C wells don't even exist. Thereforce we can remove the checks for pipe A vs. others and just assume it's always pipe A. Signed-off-by: Ville Syrjälä Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 47 ++++++++++++++------------------- 1 file changed, 20 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 932d96332eca..1bd947ad2163 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1042,53 +1042,46 @@ out: static void chv_pipe_power_well_sync_hw(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { + WARN_ON_ONCE(power_well->data != PIPE_A); + chv_set_pipe_power_well(dev_priv, power_well, power_well->count > 0); } static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - WARN_ON_ONCE(power_well->data != PIPE_A && - power_well->data != PIPE_B && - power_well->data != PIPE_C); + WARN_ON_ONCE(power_well->data != PIPE_A); chv_set_pipe_power_well(dev_priv, power_well, true); - if (power_well->data == PIPE_A) { - spin_lock_irq(&dev_priv->irq_lock); - valleyview_enable_display_irqs(dev_priv); - spin_unlock_irq(&dev_priv->irq_lock); + spin_lock_irq(&dev_priv->irq_lock); + valleyview_enable_display_irqs(dev_priv); + spin_unlock_irq(&dev_priv->irq_lock); - /* - * During driver initialization/resume we can avoid restoring the - * part of the HW/SW state that will be inited anyway explicitly. - */ - if (dev_priv->power_domains.initializing) - return; + /* + * During driver initialization/resume we can avoid restoring the + * part of the HW/SW state that will be inited anyway explicitly. + */ + if (dev_priv->power_domains.initializing) + return; - intel_hpd_init(dev_priv); + intel_hpd_init(dev_priv); - i915_redisable_vga_power_on(dev_priv->dev); - } + i915_redisable_vga_power_on(dev_priv->dev); } static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - WARN_ON_ONCE(power_well->data != PIPE_A && - power_well->data != PIPE_B && - power_well->data != PIPE_C); - - if (power_well->data == PIPE_A) { - spin_lock_irq(&dev_priv->irq_lock); - valleyview_disable_display_irqs(dev_priv); - spin_unlock_irq(&dev_priv->irq_lock); - } + WARN_ON_ONCE(power_well->data != PIPE_A); + + spin_lock_irq(&dev_priv->irq_lock); + valleyview_disable_display_irqs(dev_priv); + spin_unlock_irq(&dev_priv->irq_lock); chv_set_pipe_power_well(dev_priv, power_well, false); - if (power_well->data == PIPE_A) - vlv_power_sequencer_reset(dev_priv); + vlv_power_sequencer_reset(dev_priv); } /** -- cgit v1.3-6-gb490 From 2be7d540fde3f82e404cbddeeb2fdf05cf33af3c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 29 Jun 2015 15:25:51 +0300 Subject: drm/i915: Refactor VLV display power well init/deinit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do the exact same steps around the disp2d/pipe A power well enable/disable on VLV and CHV. Refactor the shared code into some helpers. Note that this means we now call vlv_power_sequencer_reset() before turning off the power well, whereas before we did it after. That doesn't matter though since vlv_power_sequencer_reset() just resets the power sequencer software tracking and doesn't touch the hardware at all. Signed-off-by: Ville Syrjälä Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 52 +++++++++++++++------------------ 1 file changed, 23 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 1bd947ad2163..6393b76f87ff 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -835,12 +835,8 @@ static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv, return enabled; } -static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well) +static void vlv_display_power_well_init(struct drm_i915_private *dev_priv) { - 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); @@ -858,18 +854,33 @@ static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv, i915_redisable_vga_power_on(dev_priv->dev); } +static void vlv_display_power_well_deinit(struct drm_i915_private *dev_priv) +{ + spin_lock_irq(&dev_priv->irq_lock); + valleyview_disable_display_irqs(dev_priv); + spin_unlock_irq(&dev_priv->irq_lock); + + vlv_power_sequencer_reset(dev_priv); +} + +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); + + vlv_display_power_well_init(dev_priv); +} + static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D); - spin_lock_irq(&dev_priv->irq_lock); - valleyview_disable_display_irqs(dev_priv); - spin_unlock_irq(&dev_priv->irq_lock); + vlv_display_power_well_deinit(dev_priv); vlv_set_power_well(dev_priv, power_well, false); - - vlv_power_sequencer_reset(dev_priv); } static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, @@ -1054,20 +1065,7 @@ static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv, chv_set_pipe_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/resume we can avoid restoring the - * part of the HW/SW state that will be inited anyway explicitly. - */ - if (dev_priv->power_domains.initializing) - return; - - intel_hpd_init(dev_priv); - - i915_redisable_vga_power_on(dev_priv->dev); + vlv_display_power_well_init(dev_priv); } static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv, @@ -1075,13 +1073,9 @@ static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv, { WARN_ON_ONCE(power_well->data != PIPE_A); - spin_lock_irq(&dev_priv->irq_lock); - valleyview_disable_display_irqs(dev_priv); - spin_unlock_irq(&dev_priv->irq_lock); + vlv_display_power_well_deinit(dev_priv); chv_set_pipe_power_well(dev_priv, power_well, false); - - vlv_power_sequencer_reset(dev_priv); } /** -- cgit v1.3-6-gb490 From 5e6ccc0b3d16725028caccceb2460fc3473d7d55 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Mon, 6 Jul 2015 14:44:11 +0300 Subject: drm/i915: Adjust BXT HDMI port clock limits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit e62925567c7926e78bc8ca976cde5c28ea265a49 Author: Vandana Kannan Date: Wed Jul 1 17:02:57 2015 +0530 drm/i915/bxt: BUNs related to port PLL BXT DPLL can now generate frequencies in the 216-223 MHz range. Adjust the HDMI port clock checks to account for the reduced range of invalid frequencies. Cc: Vandana Kannan Cc: Imre Deak Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index c7e912bafb87..70bad5bf1d48 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1174,9 +1174,12 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi, if (clock > hdmi_port_clock_limit(hdmi, respect_dvi_limit)) return MODE_CLOCK_HIGH; - /* CHV/BXT DPLL can't generate 216-240 MHz */ - if ((IS_CHERRYVIEW(dev) || IS_BROXTON(dev)) && - clock > 216000 && clock < 240000) + /* BXT DPLL can't generate 223-240 MHz */ + if (IS_BROXTON(dev) && clock > 223333 && clock < 240000) + return MODE_CLOCK_RANGE; + + /* CHV DPLL can't generate 216-240 MHz */ + if (IS_CHERRYVIEW(dev) && clock > 216000 && clock < 240000) return MODE_CLOCK_RANGE; return MODE_OK; -- cgit v1.3-6-gb490 From feecb691007831263e6285a25a323f175a081f42 Mon Sep 17 00:00:00 2001 From: "Thulasimani,Sivakumar" Date: Fri, 10 Jul 2015 12:30:43 +0530 Subject: drm/i915: storm detection documentation update Update the hotplug documentation to explain that hotplug storm is not expected for Display port panels and hence is not handled in current code. v2: update the statements as recommended by Daniel Signed-off-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hotplug.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index bac91a158ca2..3c9171f11531 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -66,6 +66,14 @@ * while before being re-enabled. The intention is to mitigate issues raising * from broken hardware triggering massive amounts of interrupts and grinding * the system to a halt. + * + * Current implementation expects that hotplug interrupt storm will not be + * seen when display port sink is connected, hence on platforms whose DP + * callback is handled by i915_digport_work_func reenabling of hpd is not + * performed (it was never expected to be disabled in the first place ;) ) + * this is specific to DP sinks handled by this routine and any other display + * such as HDMI or DVI enabled on the same port will have proper logic since + * it will use i915_hotplug_work_func where this logic is handled. */ enum port intel_hpd_pin_to_port(enum hpd_pin pin) -- cgit v1.3-6-gb490 From cd25dd5b766858b730af00d5b2bbaf6ad2b80c27 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Fri, 10 Jul 2015 18:31:40 +0530 Subject: drm/i915: Update PM interrupts before updating the freq Currently we update the freq before masking the interrupts, which can allow new interrupts to occur before the frequency has changed. These extra interrupts might waste some cpu cycles. This patch corrects this by masking interrupts prior to updating the frequency. Note from Chris: "Well it won't waste CPU cycles as the interrupt is also masked by the threshold limits, but there should be no harm at all in reordering the patch so, and it does make a certain amount of sense." Signed-off-by: Deepak S Signed-off-by: Praveen Paneri Reviewed-by: Chris Wilson [danvet: Add note from Chris.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9d98f4074eae..135fb974dfff 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4482,14 +4482,14 @@ static void valleyview_set_rps(struct drm_device *dev, u8 val) "Odd GPU freq value\n")) val &= ~1; + I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val)); + if (val != dev_priv->rps.cur_freq) { vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val); if (!IS_CHERRYVIEW(dev_priv)) gen6_set_rps_thresholds(dev_priv, val); } - I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val)); - dev_priv->rps.cur_freq = val; trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val)); } -- cgit v1.3-6-gb490 From 4245746037e379dc9f1388e422d52001cd431921 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 24 Jun 2015 14:14:21 +0200 Subject: regulator: da9210: Add optional interrupt support Add optional interrupt support to the da9210 regulator driver, to handle over-current, under- and over-voltage, and over-temperature events. Only the interrupt sources for which we handle events are unmasked, to avoid interrupts we cannot handle. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/da9210.txt | 4 ++ drivers/regulator/da9210-regulator.c | 75 ++++++++++++++++++++++ 2 files changed, 79 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/regulator/da9210.txt b/Documentation/devicetree/bindings/regulator/da9210.txt index 3297c53cb915..7aa9b1fa6b21 100644 --- a/Documentation/devicetree/bindings/regulator/da9210.txt +++ b/Documentation/devicetree/bindings/regulator/da9210.txt @@ -5,6 +5,10 @@ Required properties: - compatible: must be "dlg,da9210" - reg: the i2c slave address of the regulator. It should be 0x68. +Optional properties: + +- interrupts: a reference to the DA9210 interrupt, if available. + Any standard regulator properties can be used to configure the single da9210 DCDC. diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index f0489cb9018b..8e39f7457bc3 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include #include @@ -120,6 +122,55 @@ static int da9210_get_current_limit(struct regulator_dev *rdev) return da9210_buck_limits[sel]; } +static irqreturn_t da9210_irq_handler(int irq, void *data) +{ + struct da9210 *chip = data; + unsigned int val, handled = 0; + int error, ret = IRQ_NONE; + + error = regmap_read(chip->regmap, DA9210_REG_EVENT_B, &val); + if (error < 0) + goto error_i2c; + + if (val & DA9210_E_OVCURR) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_OVER_CURRENT, + NULL); + handled |= DA9210_E_OVCURR; + } + if (val & DA9210_E_NPWRGOOD) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_UNDER_VOLTAGE, + NULL); + handled |= DA9210_E_NPWRGOOD; + } + if (val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT)) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_OVER_TEMP, NULL); + handled |= val & (DA9210_E_TEMP_WARN | DA9210_E_TEMP_CRIT); + } + if (val & DA9210_E_VMAX) { + regulator_notifier_call_chain(chip->rdev, + REGULATOR_EVENT_REGULATION_OUT, + NULL); + handled |= DA9210_E_VMAX; + } + if (handled) { + /* Clear handled events */ + error = regmap_write(chip->regmap, DA9210_REG_EVENT_B, handled); + if (error < 0) + goto error_i2c; + + ret = IRQ_HANDLED; + } + + return ret; + +error_i2c: + dev_err(regmap_get_device(chip->regmap), "I2C error : %d\n", error); + return ret; +} + /* * I2C driver interface functions */ @@ -168,6 +219,30 @@ static int da9210_i2c_probe(struct i2c_client *i2c, } chip->rdev = rdev; + if (i2c->irq) { + error = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, + da9210_irq_handler, + IRQF_TRIGGER_LOW | + IRQF_ONESHOT | IRQF_SHARED, + "da9210", chip); + if (error) { + dev_err(&i2c->dev, "Failed to request IRQ%u: %d\n", + i2c->irq, error); + return error; + } + + error = regmap_update_bits(chip->regmap, DA9210_REG_MASK_B, + DA9210_M_OVCURR | DA9210_M_NPWRGOOD | + DA9210_M_TEMP_WARN | + DA9210_M_TEMP_CRIT | DA9210_M_VMAX, 0); + if (error < 0) { + dev_err(&i2c->dev, "Failed to update mask reg: %d\n", + error); + return error; + } + } else { + dev_warn(&i2c->dev, "No IRQ configured\n"); + } i2c_set_clientdata(i2c, chip); -- cgit v1.3-6-gb490 From 04dc91ce2cca5927159c689aa1f47663f8c51530 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 12:26:44 +0200 Subject: regmap: Add better support for devices without readback support Currently regmap requires that a reg_read callback is supplied, otherwise a warning is emitted each time regmap_read() is called. This means a device or bus without readback support needs to supply dummy reg_read callback. Apart from that regmap_read() will still work fine if a cache is used. Remove the warning and let regmap_readable() return false if not reg_read callback is supplied. This means a device no longer has to supply a dummy callback if it does not support readback and it also doesn't have to have a readable_reg callback that always returns false since this is now implicit. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7111d04f2621..8894b992043e 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -93,6 +93,9 @@ bool regmap_writeable(struct regmap *map, unsigned int reg) bool regmap_readable(struct regmap *map, unsigned int reg) { + if (!map->reg_read) + return false; + if (map->max_register && reg > map->max_register) return false; @@ -2097,8 +2100,6 @@ static int _regmap_read(struct regmap *map, unsigned int reg, int ret; void *context = _regmap_map_get_context(map); - WARN_ON(!map->reg_read); - if (!map->cache_bypass) { ret = regcache_read(map, reg, val); if (ret == 0) -- cgit v1.3-6-gb490 From 7035f3a4e2444490d461f8b17c2275d61fefd980 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Fri, 10 Jul 2015 12:48:21 -0700 Subject: HID: rmi: Write updated F11 control registers after reset When a device is reset the values of control registers will be reset to the defaults. This patch reapplies the control register values set for F11 by the driver. Signed-off-by: Andrew Duggan Tested-by: Gabriele Mazzotta Signed-off-by: Jiri Kosina --- drivers/hid/hid-rmi.c | 56 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index af191a265b80..9a792e725ea3 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -40,6 +40,14 @@ #define RMI_DEVICE BIT(0) #define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) +/* + * retrieve the ctrl registers + * the ctrl register has a size of 20 but a fw bug split it into 16 + 4, + * and there is no way to know if the first 20 bytes are here or not. + * We use only the first 12 bytes, so get only them. + */ +#define RMI_F11_CTRL_REG_COUNT 12 + enum rmi_mode_type { RMI_MODE_OFF = 0, RMI_MODE_ATTN_REPORTS = 1, @@ -116,6 +124,8 @@ struct rmi_data { unsigned int max_y; unsigned int x_size_mm; unsigned int y_size_mm; + bool read_f11_ctrl_regs; + u8 f11_ctrl_regs[RMI_F11_CTRL_REG_COUNT]; unsigned int gpio_led_count; unsigned int button_count; @@ -557,6 +567,18 @@ static int rmi_set_sleep_mode(struct hid_device *hdev, int sleep_mode) static int rmi_suspend(struct hid_device *hdev, pm_message_t message) { + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + u8 buf[RMI_F11_CTRL_REG_COUNT]; + + ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, + RMI_F11_CTRL_REG_COUNT); + if (ret) + hid_warn(hdev, "can not read F11 control registers\n"); + else + memcpy(data->f11_ctrl_regs, buf, RMI_F11_CTRL_REG_COUNT); + + if (!device_may_wakeup(hdev->dev.parent)) return rmi_set_sleep_mode(hdev, RMI_SLEEP_DEEP_SLEEP); @@ -565,6 +587,7 @@ static int rmi_suspend(struct hid_device *hdev, pm_message_t message) static int rmi_post_reset(struct hid_device *hdev) { + struct rmi_data *data = hid_get_drvdata(hdev); int ret; ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); @@ -573,6 +596,14 @@ static int rmi_post_reset(struct hid_device *hdev) return ret; } + if (data->read_f11_ctrl_regs) { + ret = rmi_write_block(hdev, data->f11.control_base_addr, + data->f11_ctrl_regs, RMI_F11_CTRL_REG_COUNT); + if (ret) + hid_warn(hdev, + "can not write F11 control registers after reset\n"); + } + if (!device_may_wakeup(hdev->dev.parent)) { ret = rmi_set_sleep_mode(hdev, RMI_SLEEP_NORMAL); if (ret) { @@ -957,24 +988,23 @@ static int rmi_populate_f11(struct hid_device *hdev) if (has_data40) data->f11.report_size += data->max_fingers * 2; - /* - * retrieve the ctrl registers - * the ctrl register has a size of 20 but a fw bug split it into 16 + 4, - * and there is no way to know if the first 20 bytes are here or not. - * We use only the first 12 bytes, so get only them. - */ - ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 12); + ret = rmi_read_block(hdev, data->f11.control_base_addr, + data->f11_ctrl_regs, RMI_F11_CTRL_REG_COUNT); if (ret) { hid_err(hdev, "can not read ctrl block of size 11: %d.\n", ret); return ret; } - data->max_x = buf[6] | (buf[7] << 8); - data->max_y = buf[8] | (buf[9] << 8); + /* data->f11_ctrl_regs now contains valid register data */ + data->read_f11_ctrl_regs = true; + + data->max_x = data->f11_ctrl_regs[6] | (data->f11_ctrl_regs[7] << 8); + data->max_y = data->f11_ctrl_regs[8] | (data->f11_ctrl_regs[9] << 8); if (has_dribble) { - buf[0] = buf[0] & ~BIT(6); - ret = rmi_write(hdev, data->f11.control_base_addr, buf); + data->f11_ctrl_regs[0] = data->f11_ctrl_regs[0] & ~BIT(6); + ret = rmi_write(hdev, data->f11.control_base_addr, + data->f11_ctrl_regs); if (ret) { hid_err(hdev, "can not write to control reg 0: %d.\n", ret); @@ -983,9 +1013,9 @@ static int rmi_populate_f11(struct hid_device *hdev) } if (has_palm_detect) { - buf[11] = buf[11] & ~BIT(0); + data->f11_ctrl_regs[11] = data->f11_ctrl_regs[11] & ~BIT(0); ret = rmi_write(hdev, data->f11.control_base_addr + 11, - &buf[11]); + &data->f11_ctrl_regs[11]); if (ret) { hid_err(hdev, "can not write to control reg 11: %d.\n", ret); -- cgit v1.3-6-gb490 From 70caee0a3721956a98cb4bfbfa0eaa38c9182e44 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 9 Jul 2015 14:11:51 -0400 Subject: HID: wacom: remove the extra Pen interface for Wacom Bamboo PAD As mentioned in the comment in the code, both the pen and touch data come from the interface tagged as BAMBOO_PAD. The driver re-routes the events for the Pen to the generic HID interface and keeps the ones for the touch through this current interface. Clearing the WACOM_DEVICETYPE_PEN bit removes the extra unused interface added in 2a6cdbd ("HID: wacom: Introduce new 'touch_input' device") and makes the Bamboo PAD to behave like in 4.1. Reviewed-by: Jason Gerecke Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 232da89f4e88..f5a0d3c64520 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2220,10 +2220,10 @@ void wacom_setup_device_quirks(struct wacom *wacom) * 0, whose HID descriptor has an application usage of 0xFF0D * (i.e., WACOM_VENDORDEFINED_PEN). We route pen packets back * out through the HID_GENERIC device created for interface 1, - * so rewrite this one to be of type BTN_TOOL_FINGER. + * so rewrite this one to be of type WACOM_DEVICETYPE_TOUCH. */ if (features->type == BAMBOO_PAD) - features->device_type |= WACOM_DEVICETYPE_TOUCH; + features->device_type = WACOM_DEVICETYPE_TOUCH; if (wacom->hdev->bus == BUS_BLUETOOTH) features->quirks |= WACOM_QUIRK_BATTERY; -- cgit v1.3-6-gb490 From 2259b5bbaac847f9f322659953966ebb53cfd9bc Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Fri, 10 Jul 2015 00:10:21 -0600 Subject: HID: sony: Navigator Axis for L1 button Patch HID report descriptor to add joystick axis for the L1 button (previously missing). Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index ed2f008f8403..69586b316409 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -296,7 +296,14 @@ static __u8 navigation_rdesc[] = { 0x09, 0x01, /* Usage (Pointer), */ 0x81, 0x02, /* Input (Variable), */ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x95, 0x20, /* Report Count (26), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x95, 0x01, /* Report Count (1), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x95, 0x1E, /* Report Count (24), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x30, /* Report Count (48), */ -- cgit v1.3-6-gb490 From b1a55af2773d5e4d30b748517fedfac26fc5fd81 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:39:22 +0900 Subject: power_supply: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sebastian Reichel --- drivers/power/bq24190_charger.c | 1 - drivers/power/bq24735-charger.c | 1 - drivers/power/pm2301_charger.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c index 052db78c3736..703ebecaf38b 100644 --- a/drivers/power/bq24190_charger.c +++ b/drivers/power/bq24190_charger.c @@ -1534,7 +1534,6 @@ static struct i2c_driver bq24190_driver = { .id_table = bq24190_i2c_ids, .driver = { .name = "bq24190-charger", - .owner = THIS_MODULE, .pm = &bq24190_pm_ops, .of_match_table = of_match_ptr(bq24190_of_match), }, diff --git a/drivers/power/bq24735-charger.c b/drivers/power/bq24735-charger.c index 961a18930027..b0174379713c 100644 --- a/drivers/power/bq24735-charger.c +++ b/drivers/power/bq24735-charger.c @@ -409,7 +409,6 @@ MODULE_DEVICE_TABLE(of, bq24735_match_ids); static struct i2c_driver bq24735_charger_driver = { .driver = { .name = "bq24735-charger", - .owner = THIS_MODULE, .of_match_table = bq24735_match_ids, }, .probe = bq24735_charger_probe, diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c index cc0893ffbf7e..3a45cc0c4dce 100644 --- a/drivers/power/pm2301_charger.c +++ b/drivers/power/pm2301_charger.c @@ -1244,7 +1244,6 @@ static struct i2c_driver pm2xxx_charger_driver = { .remove = pm2xxx_wall_charger_remove, .driver = { .name = "pm2xxx-wall_charger", - .owner = THIS_MODULE, .pm = PM2XXX_PM_OPS, }, .id_table = pm2xxx_id, -- cgit v1.3-6-gb490 From e4ca061275ec6a48b66c6edebe08644e666994c0 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 8 Jul 2015 15:31:52 +0200 Subject: drm/i915: Don't forget to mark crtc as inactive after disable Watermark calculations depend on the intel_crtc->active flag to be set properly. Suspend/resume is broken on SKL and we also get DDB mismatches without this patch. The regression was introduced in: commit eddfcbcdc27fbecb33bff098967bbdd7ca75bfa6 Author: Maarten Lankhorst Date: Mon Jun 15 12:33:53 2015 +0200 drm/i915: Update less state during modeset. No need to repeatedly call update_watermarks, or update_fbc. Down to a single call to update_watermarks in .crtc_enable Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter v2: Don't touch disable_shared_dpll() Signed-off-by: Patrik Jakobsson Reviewed-by: Maarten Lankhorst Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91203 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a7482ab140e1..00c60c1c5162 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5049,6 +5049,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) ironlake_fdi_pll_disable(intel_crtc); } + + intel_crtc->active = false; + intel_update_watermarks(crtc); } static void haswell_crtc_disable(struct drm_crtc *crtc) @@ -5094,6 +5097,9 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->post_disable) encoder->post_disable(encoder); + + intel_crtc->active = false; + intel_update_watermarks(crtc); } static void i9xx_pfit_enable(struct intel_crtc *crtc) @@ -6158,6 +6164,9 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) if (!IS_GEN2(dev)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); + + intel_crtc->active = false; + intel_update_watermarks(crtc); } static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) -- cgit v1.3-6-gb490 From 7bd393543287b921f964a350166bf2866527a1b5 Mon Sep 17 00:00:00 2001 From: James Ban Date: Tue, 30 Jun 2015 13:39:39 +0900 Subject: regulator: da9211: support da9215 This is a patch for supporting da9215 buck converter. Signed-off-by: James Ban Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/da9211.txt | 32 +++++++++++++++-- drivers/regulator/Kconfig | 6 ++-- drivers/regulator/da9211-regulator.c | 40 ++++++++++++++++------ drivers/regulator/da9211-regulator.h | 18 +++++----- include/linux/regulator/da9211.h | 19 +++++----- 5 files changed, 81 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/regulator/da9211.txt b/Documentation/devicetree/bindings/regulator/da9211.txt index eb618907c7de..c620493e8dbe 100644 --- a/Documentation/devicetree/bindings/regulator/da9211.txt +++ b/Documentation/devicetree/bindings/regulator/da9211.txt @@ -1,7 +1,7 @@ -* Dialog Semiconductor DA9211/DA9213 Voltage Regulator +* Dialog Semiconductor DA9211/DA9213/DA9215 Voltage Regulator Required properties: -- compatible: "dlg,da9211" or "dlg,da9213". +- compatible: "dlg,da9211" or "dlg,da9213" or "dlg,da9215" - reg: I2C slave address, usually 0x68. - interrupts: the interrupt outputs of the controller - regulators: A node that houses a sub-node for each regulator within the @@ -66,3 +66,31 @@ Example 2) DA9213 }; }; }; + + +Example 3) DA9215 + pmic: da9215@68 { + compatible = "dlg,da9215"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <4000000>; + regulator-max-microamp = <7000000>; + enable-gpios = <&gpio 27 0>; + }; + BUCKB { + regulator-name = "VBUCKB"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <4000000>; + regulator-max-microamp = <7000000>; + enable-gpios = <&gpio 17 0>; + }; + }; + }; + diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index bef3bde6971b..23496da101de 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -209,13 +209,13 @@ config REGULATOR_DA9210 interface. config REGULATOR_DA9211 - tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214 regulator" + tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214/DA9215 regulator" depends on I2C select REGMAP_I2C help Say y here to support for the Dialog Semiconductor DA9211/DA9212 - /DA9213/DA9214. - The DA9211/DA9212/DA9213/DA9214 is a multi-phase synchronous + /DA9213/DA9214/DA9215. + The DA9211/DA9212/DA9213/DA9214/DA9215 is a multi-phase synchronous step down converter 12A or 16A DC-DC Buck controlled through an I2C interface. diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index df79e4b1946e..0858100d2d03 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -1,6 +1,6 @@ /* - * da9211-regulator.c - Regulator device driver for DA9211/DA9213 - * Copyright (C) 2014 Dialog Semiconductor Ltd. + * da9211-regulator.c - Regulator device driver for DA9211/DA9213/DA9215 + * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -32,6 +32,7 @@ /* DEVICE IDs */ #define DA9211_DEVICE_ID 0x22 #define DA9213_DEVICE_ID 0x23 +#define DA9215_DEVICE_ID 0x24 #define DA9211_BUCK_MODE_SLEEP 1 #define DA9211_BUCK_MODE_SYNC 2 @@ -90,6 +91,13 @@ static const int da9213_current_limits[] = { 3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000, 4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000 }; +/* Current limits for DA9215 buck (uA) indices + * corresponds with register values + */ +static const int da9215_current_limits[] = { + 4000000, 4200000, 4400000, 4600000, 4800000, 5000000, 5200000, 5400000, + 5600000, 5800000, 6000000, 6200000, 6400000, 6600000, 6800000, 7000000 +}; static unsigned int da9211_buck_get_mode(struct regulator_dev *rdev) { @@ -157,6 +165,10 @@ static int da9211_set_current_limit(struct regulator_dev *rdev, int min, current_limits = da9213_current_limits; max_size = ARRAY_SIZE(da9213_current_limits)-1; break; + case DA9215: + current_limits = da9215_current_limits; + max_size = ARRAY_SIZE(da9215_current_limits)-1; + break; default: return -EINVAL; } @@ -189,6 +201,9 @@ static int da9211_get_current_limit(struct regulator_dev *rdev) case DA9213: current_limits = da9213_current_limits; break; + case DA9215: + current_limits = da9215_current_limits; + break; default: return -EINVAL; } @@ -350,13 +365,11 @@ static int da9211_regulator_init(struct da9211 *chip) /* If configuration for 1/2 bucks is different between platform data * and the register, driver should exit. */ - if ((chip->pdata->num_buck == 2 && data == 0x40) - || (chip->pdata->num_buck == 1 && data == 0x00)) { - if (data == 0) - chip->num_regulator = 1; - else - chip->num_regulator = 2; - } else { + if (chip->pdata->num_buck == 1 && data == 0x00) + chip->num_regulator = 1; + else if (chip->pdata->num_buck == 2 && data != 0x00) + chip->num_regulator = 2; + else { dev_err(chip->dev, "Configuration is mismatched\n"); return -EINVAL; } @@ -438,6 +451,9 @@ static int da9211_i2c_probe(struct i2c_client *i2c, case DA9213_DEVICE_ID: chip->chip_id = DA9213; break; + case DA9215_DEVICE_ID: + chip->chip_id = DA9215; + break; default: dev_err(chip->dev, "Unsupported device id = 0x%x.\n", data); return -ENODEV; @@ -478,6 +494,7 @@ static int da9211_i2c_probe(struct i2c_client *i2c, static const struct i2c_device_id da9211_i2c_id[] = { {"da9211", DA9211}, {"da9213", DA9213}, + {"da9215", DA9215}, {}, }; MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); @@ -486,6 +503,7 @@ MODULE_DEVICE_TABLE(i2c, da9211_i2c_id); static const struct of_device_id da9211_dt_ids[] = { { .compatible = "dlg,da9211", .data = &da9211_i2c_id[0] }, { .compatible = "dlg,da9213", .data = &da9211_i2c_id[1] }, + { .compatible = "dlg,da9215", .data = &da9211_i2c_id[2] }, {}, }; MODULE_DEVICE_TABLE(of, da9211_dt_ids); @@ -504,5 +522,5 @@ static struct i2c_driver da9211_regulator_driver = { module_i2c_driver(da9211_regulator_driver); MODULE_AUTHOR("James Ban "); -MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213"); -MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Regulator device driver for Dialog DA9211/DA9213/DA9215"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/da9211-regulator.h b/drivers/regulator/da9211-regulator.h index 93fa9df2721c..d6ad96fc64d3 100644 --- a/drivers/regulator/da9211-regulator.h +++ b/drivers/regulator/da9211-regulator.h @@ -1,16 +1,16 @@ /* - * da9211-regulator.h - Regulator definitions for DA9211/DA9213 - * Copyright (C) 2014 Dialog Semiconductor Ltd. + * da9211-regulator.h - Regulator definitions for DA9211/DA9213/DA9215 + * Copyright (C) 2015 Dialog Semiconductor Ltd. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library 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 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 library is distributed in the hope that it will be useful, + * 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 - * Library General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef __DA9211_REGISTERS_H__ diff --git a/include/linux/regulator/da9211.h b/include/linux/regulator/da9211.h index 5dd65acc2a69..a43a5ca1167b 100644 --- a/include/linux/regulator/da9211.h +++ b/include/linux/regulator/da9211.h @@ -1,16 +1,16 @@ /* - * da9211.h - Regulator device driver for DA9211/DA9213 - * Copyright (C) 2014 Dialog Semiconductor Ltd. + * da9211.h - Regulator device driver for DA9211/DA9213/DA9215 + * Copyright (C) 2015 Dialog Semiconductor Ltd. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library 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 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 library is distributed in the hope that it will be useful, + * 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 - * Library General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #ifndef __LINUX_REGULATOR_DA9211_H @@ -23,6 +23,7 @@ enum da9211_chip_id { DA9211, DA9213, + DA9215, }; struct da9211_pdata { -- cgit v1.3-6-gb490 From c149e4cd08ba01f4d2d0104f469d5f5419294e06 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 3 Jun 2015 11:46:22 +0800 Subject: x86/irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner --- arch/x86/kernel/apic/io_apic.c | 2 +- arch/x86/kernel/apic/vector.c | 3 ++- arch/x86/kernel/irq.c | 5 +++-- drivers/xen/events/events_base.c | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 845dc0df2002..09921de4210f 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2541,7 +2541,7 @@ void __init setup_ioapic_dest(void) * Honour affinities which have been set in early boot */ if (!irqd_can_balance(idata) || irqd_affinity_was_set(idata)) - mask = idata->affinity; + mask = irq_data_get_affinity_mask(idata); else mask = apic->target_cpus(); diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 9b62f690b0ff..7ad911ea4f56 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -496,7 +496,8 @@ static int apic_set_affinity(struct irq_data *irq_data, if (err) { struct irq_data *top = irq_get_irq_data(irq); - if (assign_irq_vector(irq, data, top->affinity)) + if (assign_irq_vector(irq, data, + irq_data_get_affinity_mask(top))) pr_err("Failed to recover vector for irq %d\n", irq); return err; } diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index 88b366487b0e..7ed9cba27637 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -348,7 +348,8 @@ int check_irq_vectors_for_cpu_disable(void) continue; data = irq_desc_get_irq_data(desc); - cpumask_copy(&affinity_new, data->affinity); + cpumask_copy(&affinity_new, + irq_data_get_affinity_mask(data)); cpumask_clear_cpu(this_cpu, &affinity_new); /* Do not count inactive or per-cpu irqs. */ @@ -426,7 +427,7 @@ void fixup_irqs(void) raw_spin_lock(&desc->lock); data = irq_desc_get_irq_data(desc); - affinity = data->affinity; + affinity = irq_data_get_affinity_mask(data); if (!irq_has_action(irq) || irqd_is_per_cpu(data) || cpumask_subset(affinity, cpu_online_mask)) { raw_spin_unlock(&desc->lock); diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 96093ae369a5..ed8bf1067a97 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -336,7 +336,7 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) BUG_ON(irq == -1); #ifdef CONFIG_SMP - cpumask_copy(irq_get_irq_data(irq)->affinity, cpumask_of(cpu)); + cpumask_copy(irq_get_affinity_mask(irq), cpumask_of(cpu)); #endif xen_evtchn_port_bind_to_cpu(info, cpu); @@ -373,7 +373,7 @@ static void xen_irq_init(unsigned irq) struct irq_info *info; #ifdef CONFIG_SMP /* By default all event channels notify CPU#0. */ - cpumask_copy(irq_get_irq_data(irq)->affinity, cpumask_of(0)); + cpumask_copy(irq_get_affinity_mask(irq), cpumask_of(0)); #endif info = kzalloc(sizeof(*info), GFP_KERNEL); -- cgit v1.3-6-gb490 From 86665d2897209429a7e4a003764b9fc5034dbfa1 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 7 Jul 2015 18:30:05 -0700 Subject: clk: st: Fix error paths and allocation style The error paths in this file leak memory and mappings and test for pointers being valid after dereferencing them. Fix these problems and properly free resources on errors. Fix some stylistic things too like using sizeof(*ptr) and fitting more code on a single line. Note that we don't unregister clocks here. That needs a clk_composite_unregister() API that we don't have right now. Acked-by: Gabriel Fernandez Cc: Pankaj Dev Signed-off-by: Stephen Boyd --- drivers/clk/st/clkgen-mux.c | 83 ++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c index 717c4a91a17b..ab9298395264 100644 --- a/drivers/clk/st/clkgen-mux.c +++ b/drivers/clk/st/clkgen-mux.c @@ -30,7 +30,7 @@ static const char ** __init clkgen_mux_get_parents(struct device_node *np, if (WARN_ON(nparents <= 0)) return ERR_PTR(-EINVAL); - parents = kzalloc(nparents * sizeof(const char *), GFP_KERNEL); + parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL); if (!parents) return ERR_PTR(-ENOMEM); @@ -215,7 +215,7 @@ static const struct clk_ops clkgena_divmux_ops = { /** * clk_register_genamux - register a genamux clock with the clock framework */ -static struct clk *clk_register_genamux(const char *name, +static struct clk * __init clk_register_genamux(const char *name, const char **parent_names, u8 num_parents, void __iomem *reg, const struct clkgena_divmux_data *muxdata, @@ -369,11 +369,10 @@ static const struct of_device_id clkgena_divmux_of_match[] = { {} }; -static void __iomem * __init clkgen_get_register_base( - struct device_node *np) +static void __iomem * __init clkgen_get_register_base(struct device_node *np) { struct device_node *pnode; - void __iomem *reg = NULL; + void __iomem *reg; pnode = of_get_parent(np); if (!pnode) @@ -398,7 +397,7 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np) if (WARN_ON(!match)) return; - data = (struct clkgena_divmux_data *)match->data; + data = match->data; reg = clkgen_get_register_base(np); if (!reg) @@ -406,18 +405,18 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np) parents = clkgen_mux_get_parents(np, &num_parents); if (IS_ERR(parents)) - return; + goto err_parents; clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); if (!clk_data) - goto err; + goto err_alloc; clk_data->clk_num = data->num_outputs; - clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), + clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *), GFP_KERNEL); if (!clk_data->clks) - goto err; + goto err_alloc_clks; for (i = 0; i < clk_data->clk_num; i++) { struct clk *clk; @@ -447,11 +446,13 @@ static void __init st_of_clkgena_divmux_setup(struct device_node *np) of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); return; err: - if (clk_data) - kfree(clk_data->clks); - + kfree(clk_data->clks); +err_alloc_clks: kfree(clk_data); +err_alloc: kfree(parents); +err_parents: + iounmap(reg); } CLK_OF_DECLARE(clkgenadivmux, "st,clkgena-divmux", st_of_clkgena_divmux_setup); @@ -491,7 +492,7 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np) void __iomem *reg; const char *parent_name, *clk_name; struct clk *clk; - struct clkgena_prediv_data *data; + const struct clkgena_prediv_data *data; match = of_match_node(clkgena_prediv_of_match, np); if (!match) { @@ -499,7 +500,7 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np) return; } - data = (struct clkgena_prediv_data *)match->data; + data = match->data; reg = clkgen_get_register_base(np); if (!reg) @@ -507,18 +508,18 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np) parent_name = of_clk_get_parent_name(np, 0); if (!parent_name) - return; + goto err; if (of_property_read_string_index(np, "clock-output-names", 0, &clk_name)) - return; + goto err; clk = clk_register_divider_table(NULL, clk_name, parent_name, CLK_GET_RATE_NOCACHE, reg + data->offset, data->shift, 1, 0, data->table, NULL); if (IS_ERR(clk)) - return; + goto err; of_clk_add_provider(np, of_clk_src_simple_get, clk); pr_debug("%s: parent %s rate %u\n", @@ -527,6 +528,8 @@ static void __init st_of_clkgena_prediv_setup(struct device_node *np) (unsigned int)clk_get_rate(clk)); return; +err: + iounmap(reg); } CLK_OF_DECLARE(clkgenaprediv, "st,clkgena-prediv", st_of_clkgena_prediv_setup); @@ -630,7 +633,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np) void __iomem *reg; const char **parents; int num_parents; - struct clkgen_mux_data *data; + const struct clkgen_mux_data *data; match = of_match_node(mux_of_match, np); if (!match) { @@ -638,7 +641,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np) return; } - data = (struct clkgen_mux_data *)match->data; + data = match->data; reg = of_iomap(np, 0); if (!reg) { @@ -650,7 +653,7 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np) if (IS_ERR(parents)) { pr_err("%s: Failed to get parents (%ld)\n", __func__, PTR_ERR(parents)); - return; + goto err_parents; } clk = clk_register_mux(NULL, np->name, parents, num_parents, @@ -666,12 +669,14 @@ static void __init st_of_clkgen_mux_setup(struct device_node *np) __clk_get_name(clk_get_parent(clk)), (unsigned int)clk_get_rate(clk)); + kfree(parents); of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; err: kfree(parents); - - return; +err_parents: + iounmap(reg); } CLK_OF_DECLARE(clkgen_mux, "st,clkgen-mux", st_of_clkgen_mux_setup); @@ -707,12 +712,12 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np) const char **parents; int num_parents, i; struct clk_onecell_data *clk_data; - struct clkgen_vcc_data *data; + const struct clkgen_vcc_data *data; match = of_match_node(vcc_of_match, np); if (WARN_ON(!match)) return; - data = (struct clkgen_vcc_data *)match->data; + data = match->data; reg = of_iomap(np, 0); if (!reg) @@ -720,18 +725,18 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np) parents = clkgen_mux_get_parents(np, &num_parents); if (IS_ERR(parents)) - return; + goto err_parents; clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); if (!clk_data) - goto err; + goto err_alloc; clk_data->clk_num = VCC_MAX_CHANNELS; - clk_data->clks = kzalloc(clk_data->clk_num * sizeof(struct clk *), + clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *), GFP_KERNEL); if (!clk_data->clks) - goto err; + goto err_alloc_clks; for (i = 0; i < clk_data->clk_num; i++) { struct clk *clk; @@ -750,21 +755,21 @@ static void __init st_of_clkgen_vcc_setup(struct device_node *np) if (*clk_name == '\0') continue; - gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); + gate = kzalloc(sizeof(*gate), GFP_KERNEL); if (!gate) - break; + goto err; - div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); + div = kzalloc(sizeof(*div), GFP_KERNEL); if (!div) { kfree(gate); - break; + goto err; } - mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); + mux = kzalloc(sizeof(*mux), GFP_KERNEL); if (!mux) { kfree(gate); kfree(div); - break; + goto err; } gate->reg = reg + VCC_GATE_OFFSET; @@ -823,10 +828,12 @@ err: kfree(container_of(composite->mux_hw, struct clk_mux, hw)); } - if (clk_data) - kfree(clk_data->clks); - + kfree(clk_data->clks); +err_alloc_clks: kfree(clk_data); +err_alloc: kfree(parents); +err_parents: + iounmap(reg); } CLK_OF_DECLARE(clkgen_vcc, "st,clkgen-vcc", st_of_clkgen_vcc_setup); -- cgit v1.3-6-gb490 From 6c7c65538632f0961df8f02e3be446eb03f687e4 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:58:59 +0200 Subject: staging: lustre: fid: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/fid/fid_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c index 1362783b7eab..a16d577c6cb1 100644 --- a/drivers/staging/lustre/lustre/fid/fid_request.c +++ b/drivers/staging/lustre/lustre/fid/fid_request.c @@ -498,11 +498,11 @@ int client_fid_init(struct obd_device *obd, int rc; cli->cl_seq = kzalloc(sizeof(*cli->cl_seq), GFP_NOFS); - if (cli->cl_seq == NULL) + if (!cli->cl_seq) return -ENOMEM; prefix = kzalloc(MAX_OBD_NAME + 5, GFP_NOFS); - if (prefix == NULL) { + if (!prefix) { rc = -ENOMEM; goto out_free_seq; } -- cgit v1.3-6-gb490 From 812f205962e20f4e4052e42d0009b05988760ef2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:59:00 +0200 Subject: staging: lustre: fld: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/fld/fld_cache.c | 2 +- drivers/staging/lustre/lustre/fld/fld_request.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c index ec2fc4339a2e..1b1066b2461c 100644 --- a/drivers/staging/lustre/lustre/fld/fld_cache.c +++ b/drivers/staging/lustre/lustre/fld/fld_cache.c @@ -70,7 +70,7 @@ struct fld_cache *fld_cache_init(const char *name, LASSERT(cache_threshold < cache_size); cache = kzalloc(sizeof(*cache), GFP_NOFS); - if (cache == NULL) + if (!cache) return ERR_PTR(-ENOMEM); INIT_LIST_HEAD(&cache->fci_entries_head); diff --git a/drivers/staging/lustre/lustre/fld/fld_request.c b/drivers/staging/lustre/lustre/fld/fld_request.c index c3b47f2346df..1e450bf95383 100644 --- a/drivers/staging/lustre/lustre/fld/fld_request.c +++ b/drivers/staging/lustre/lustre/fld/fld_request.c @@ -222,7 +222,7 @@ int fld_client_add_target(struct lu_client_fld *fld, fld->lcf_name, name, tar->ft_idx); target = kzalloc(sizeof(*target), GFP_NOFS); - if (target == NULL) + if (!target) return -ENOMEM; spin_lock(&fld->lcf_lock); -- cgit v1.3-6-gb490 From c38ce3548e0c5df27b63f9b591f11a9c34416576 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:59:01 +0200 Subject: staging: lustre: lclient: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/lclient/lcommon_cl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c index e0c1ccafbd63..9053f8116298 100644 --- a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c +++ b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c @@ -203,7 +203,7 @@ struct lu_device *ccc_device_alloc(const struct lu_env *env, int rc; vdv = kzalloc(sizeof(*vdv), GFP_NOFS); - if (vdv == NULL) + if (!vdv) return ERR_PTR(-ENOMEM); lud = &vdv->cdv_cl.cd_lu_dev; -- cgit v1.3-6-gb490 From 94e67761bd05150976342516180508d93a0a7c07 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:59:02 +0200 Subject: staging: lustre: ldlm: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ldlm/ldlm_lock.c | 4 ++-- drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c | 8 ++++---- drivers/staging/lustre/lustre/ldlm/ldlm_pool.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index bb2246d3b22b..cd340fc8ceab 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -1528,7 +1528,7 @@ struct ldlm_lock *ldlm_lock_create(struct ldlm_namespace *ns, if (lvb_len) { lock->l_lvb_len = lvb_len; lock->l_lvb_data = kzalloc(lvb_len, GFP_NOFS); - if (lock->l_lvb_data == NULL) + if (!lock->l_lvb_data) goto out; } @@ -1813,7 +1813,7 @@ int ldlm_run_ast_work(struct ldlm_namespace *ns, struct list_head *rpc_list, return 0; arg = kzalloc(sizeof(*arg), GFP_NOFS); - if (arg == NULL) + if (!arg) return -ENOMEM; atomic_set(&arg->restart, 0); diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c index b7b6ca1196b7..941eb4e72039 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c @@ -225,7 +225,7 @@ static void ldlm_handle_cp_callback(struct ptlrpc_request *req, void *lvb_data; lvb_data = kzalloc(lvb_len, GFP_NOFS); - if (lvb_data == NULL) { + if (!lvb_data) { LDLM_ERROR(lock, "No memory: %d.\n", lvb_len); rc = -ENOMEM; goto out; @@ -453,7 +453,7 @@ static int ldlm_bl_to_thread(struct ldlm_namespace *ns, struct ldlm_bl_work_item *blwi; blwi = kzalloc(sizeof(*blwi), GFP_NOFS); - if (blwi == NULL) + if (!blwi) return -ENOMEM; init_blwi(blwi, ns, ld, cancels, count, lock, cancel_flags); @@ -1053,7 +1053,7 @@ static int ldlm_setup(void) return -EALREADY; ldlm_state = kzalloc(sizeof(*ldlm_state), GFP_NOFS); - if (ldlm_state == NULL) + if (!ldlm_state) return -ENOMEM; ldlm_kobj = kobject_create_and_add("ldlm", lustre_kobj); @@ -1123,7 +1123,7 @@ static int ldlm_setup(void) blp = kzalloc(sizeof(*blp), GFP_NOFS); - if (blp == NULL) { + if (!blp) { rc = -ENOMEM; goto out; } diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c index 1605b9c69271..4519d779a0ef 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c @@ -1422,7 +1422,7 @@ static int ldlm_pools_thread_start(void) return -EALREADY; ldlm_pools_thread = kzalloc(sizeof(*ldlm_pools_thread), GFP_NOFS); - if (ldlm_pools_thread == NULL) + if (!ldlm_pools_thread) return -ENOMEM; init_completion(&ldlm_pools_comp); -- cgit v1.3-6-gb490 From 76e4290ccc428fddd9052d12ceb5b806ae982a26 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:59:03 +0200 Subject: staging: lustre: lmv: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/lmv/lmv_intent.c | 2 +- drivers/staging/lustre/lustre/lmv/lmv_obd.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/lmv/lmv_intent.c b/drivers/staging/lustre/lustre/lmv/lmv_intent.c index cb35f6341fb2..eebe45bdceb6 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_intent.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_intent.c @@ -100,7 +100,7 @@ static int lmv_intent_remote(struct obd_export *exp, void *lmm, } op_data = kzalloc(sizeof(*op_data), GFP_NOFS); - if (op_data == NULL) { + if (!op_data) { rc = -ENOMEM; goto out; } diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index ac5053cd5da5..5c058d0802dc 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -716,7 +716,7 @@ repeat_fid2path: if (remote_gf == NULL) { remote_gf_size = sizeof(*remote_gf) + PATH_MAX; remote_gf = kzalloc(remote_gf_size, GFP_NOFS); - if (remote_gf == NULL) { + if (!remote_gf) { rc = -ENOMEM; goto out_fid2path; } @@ -1398,7 +1398,7 @@ static int lmv_statfs(const struct lu_env *env, struct obd_export *exp, return rc; temp = kzalloc(sizeof(*temp), GFP_NOFS); - if (temp == NULL) + if (!temp) return -ENOMEM; for (i = 0; i < lmv->desc.ld_tgt_count; i++) { @@ -1730,7 +1730,7 @@ lmv_enqueue_remote(struct obd_export *exp, struct ldlm_enqueue_info *einfo, } rdata = kzalloc(sizeof(*rdata), GFP_NOFS); - if (rdata == NULL) { + if (!rdata) { rc = -ENOMEM; goto out; } -- cgit v1.3-6-gb490 From 36a86fe68f875d2b3fc8a61d4a80494e57333f1f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:59:04 +0200 Subject: staging: lustre: lov: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/lov/lov_dev.c | 2 +- drivers/staging/lustre/lustre/lov/lov_io.c | 2 +- drivers/staging/lustre/lustre/lov/lov_obd.c | 2 +- drivers/staging/lustre/lustre/lov/lov_pool.c | 2 +- drivers/staging/lustre/lustre/lov/lov_request.c | 18 +++++++++--------- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/lov/lov_dev.c b/drivers/staging/lustre/lustre/lov/lov_dev.c index 504b24a468fc..8c3bbe574723 100644 --- a/drivers/staging/lustre/lustre/lov/lov_dev.c +++ b/drivers/staging/lustre/lustre/lov/lov_dev.c @@ -478,7 +478,7 @@ static struct lu_device *lov_device_alloc(const struct lu_env *env, int rc; ld = kzalloc(sizeof(*ld), GFP_NOFS); - if (ld == NULL) + if (!ld) return ERR_PTR(-ENOMEM); cl_device_init(&ld->ld_cl, t); diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c index 11c1081b1d3d..bf3629151d68 100644 --- a/drivers/staging/lustre/lustre/lov/lov_io.c +++ b/drivers/staging/lustre/lustre/lov/lov_io.c @@ -181,7 +181,7 @@ static int lov_io_sub_init(const struct lu_env *env, struct lov_io *lio, } else { sub->sub_io = kzalloc(sizeof(*sub->sub_io), GFP_NOFS); - if (sub->sub_io == NULL) + if (!sub->sub_io) result = -ENOMEM; } } diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c index 96c55acd52ae..cd6ed580c48b 100644 --- a/drivers/staging/lustre/lustre/lov/lov_obd.c +++ b/drivers/staging/lustre/lustre/lov/lov_obd.c @@ -976,7 +976,7 @@ static int lov_recreate(struct obd_export *exp, struct obdo *src_oa, src_oa->o_flags & OBD_FL_RECREATE_OBJS); obj_mdp = kzalloc(sizeof(*obj_mdp), GFP_NOFS); - if (obj_mdp == NULL) + if (!obj_mdp) return -ENOMEM; ost_idx = src_oa->o_nlink; diff --git a/drivers/staging/lustre/lustre/lov/lov_pool.c b/drivers/staging/lustre/lustre/lov/lov_pool.c index 1e4d3fbee323..c59b1402616e 100644 --- a/drivers/staging/lustre/lustre/lov/lov_pool.c +++ b/drivers/staging/lustre/lustre/lov/lov_pool.c @@ -431,7 +431,7 @@ int lov_pool_new(struct obd_device *obd, char *poolname) return -ENAMETOOLONG; new_pool = kzalloc(sizeof(*new_pool), GFP_NOFS); - if (new_pool == NULL) + if (!new_pool) return -ENOMEM; strncpy(new_pool->pool_name, poolname, LOV_MAXPOOLNAME); diff --git a/drivers/staging/lustre/lustre/lov/lov_request.c b/drivers/staging/lustre/lustre/lov/lov_request.c index f4de8b84c5c2..416e42ed7792 100644 --- a/drivers/staging/lustre/lustre/lov/lov_request.c +++ b/drivers/staging/lustre/lustre/lov/lov_request.c @@ -275,7 +275,7 @@ int lov_prep_getattr_set(struct obd_export *exp, struct obd_info *oinfo, int rc = 0, i; set = kzalloc(sizeof(*set), GFP_NOFS); - if (set == NULL) + if (!set) return -ENOMEM; lov_init_set(set); @@ -301,7 +301,7 @@ int lov_prep_getattr_set(struct obd_export *exp, struct obd_info *oinfo, } req = kzalloc(sizeof(*req), GFP_NOFS); - if (req == NULL) { + if (!req) { rc = -ENOMEM; goto out_set; } @@ -358,7 +358,7 @@ int lov_prep_destroy_set(struct obd_export *exp, struct obd_info *oinfo, int rc = 0, i; set = kzalloc(sizeof(*set), GFP_NOFS); - if (set == NULL) + if (!set) return -ENOMEM; lov_init_set(set); @@ -384,7 +384,7 @@ int lov_prep_destroy_set(struct obd_export *exp, struct obd_info *oinfo, } req = kzalloc(sizeof(*req), GFP_NOFS); - if (req == NULL) { + if (!req) { rc = -ENOMEM; goto out_set; } @@ -477,7 +477,7 @@ int lov_prep_setattr_set(struct obd_export *exp, struct obd_info *oinfo, int rc = 0, i; set = kzalloc(sizeof(*set), GFP_NOFS); - if (set == NULL) + if (!set) return -ENOMEM; lov_init_set(set); @@ -500,7 +500,7 @@ int lov_prep_setattr_set(struct obd_export *exp, struct obd_info *oinfo, } req = kzalloc(sizeof(*req), GFP_NOFS); - if (req == NULL) { + if (!req) { rc = -ENOMEM; goto out_set; } @@ -704,7 +704,7 @@ int lov_prep_statfs_set(struct obd_device *obd, struct obd_info *oinfo, int rc = 0, i; set = kzalloc(sizeof(*set), GFP_NOFS); - if (set == NULL) + if (!set) return -ENOMEM; lov_init_set(set); @@ -730,14 +730,14 @@ int lov_prep_statfs_set(struct obd_device *obd, struct obd_info *oinfo, } req = kzalloc(sizeof(*req), GFP_NOFS); - if (req == NULL) { + if (!req) { rc = -ENOMEM; goto out_set; } req->rq_oi.oi_osfs = kzalloc(sizeof(*req->rq_oi.oi_osfs), GFP_NOFS); - if (req->rq_oi.oi_osfs == NULL) { + if (!req->rq_oi.oi_osfs) { kfree(req); rc = -ENOMEM; goto out_set; -- cgit v1.3-6-gb490 From bb144d09a95c6016528ec869b4398ae679cc4df7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:59:05 +0200 Subject: staging: lustre: mdc: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/mdc/mdc_request.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index 7f208a6621e6..204d51262560 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -1202,7 +1202,7 @@ static int mdc_ioc_fid2path(struct obd_export *exp, struct getinfo_fid2path *gf) /* Key is KEY_FID2PATH + getinfo_fid2path description */ keylen = cfs_size_round(sizeof(KEY_FID2PATH)) + sizeof(*gf); key = kzalloc(keylen, GFP_NOFS); - if (key == NULL) + if (!key) return -ENOMEM; memcpy(key, KEY_FID2PATH, sizeof(KEY_FID2PATH)); memcpy(key + cfs_size_round(sizeof(KEY_FID2PATH)), gf, sizeof(*gf)); @@ -1605,7 +1605,7 @@ static int mdc_changelog_send_thread(void *csdata) cs->cs_fp, cs->cs_startrec); cs->cs_buf = kzalloc(KUC_CHANGELOG_MSG_MAXSIZE, GFP_NOFS); - if (cs->cs_buf == NULL) { + if (!cs->cs_buf) { rc = -ENOMEM; goto out; } @@ -1934,7 +1934,7 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len, struct obd_quotactl *oqctl; oqctl = kzalloc(sizeof(*oqctl), GFP_NOFS); - if (oqctl == NULL) { + if (!oqctl) { rc = -ENOMEM; goto out; } -- cgit v1.3-6-gb490 From c829be817600694bb99bb978943a6ef966874160 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:59:06 +0200 Subject: staging: lustre: mgc: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/mgc/mgc_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c index 174dfc32876b..562bd95bdcb9 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_request.c +++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c @@ -1128,7 +1128,7 @@ static int mgc_apply_recover_logs(struct obd_device *mgc, LASSERT(cfg->cfg_sb == cfg->cfg_instance); inst = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS); - if (inst == NULL) + if (!inst) return -ENOMEM; if (!IS_SERVER(lsi)) { @@ -1493,7 +1493,7 @@ static int mgc_process_cfg_log(struct obd_device *mgc, lsi = s2lsi(cld->cld_cfg.cfg_sb); env = kzalloc(sizeof(*env), GFP_NOFS); - if (env == NULL) + if (!env) return -ENOMEM; rc = lu_env_init(env, LCT_MG_THREAD); -- cgit v1.3-6-gb490 From 485640b536adc451330815a75f433be15c655243 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:59:07 +0200 Subject: staging: lustre: obdclass: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/class_obd.c | 2 +- drivers/staging/lustre/lustre/obdclass/genops.c | 6 +++--- drivers/staging/lustre/lustre/obdclass/llog.c | 6 +++--- drivers/staging/lustre/lustre/obdclass/lprocfs_status.c | 2 +- drivers/staging/lustre/lustre/obdclass/lustre_peer.c | 2 +- drivers/staging/lustre/lustre/obdclass/obd_config.c | 10 +++++----- drivers/staging/lustre/lustre/obdclass/obd_mount.c | 12 ++++++------ 7 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index 1bc37566b3a5..8ebe2e6c1696 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -232,7 +232,7 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg) goto out; } lcfg = kzalloc(data->ioc_plen1, GFP_NOFS); - if (lcfg == NULL) { + if (!lcfg) { err = -ENOMEM; goto out; } diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c index 978c3c5c460a..a42c9f9209c5 100644 --- a/drivers/staging/lustre/lustre/obdclass/genops.c +++ b/drivers/staging/lustre/lustre/obdclass/genops.c @@ -172,7 +172,7 @@ int class_register_type(struct obd_ops *dt_ops, struct md_ops *md_ops, rc = -ENOMEM; type = kzalloc(sizeof(*type), GFP_NOFS); - if (type == NULL) + if (!type) return rc; type->typ_dt_ops = kzalloc(sizeof(*type->typ_dt_ops), GFP_NOFS); @@ -1016,7 +1016,7 @@ struct obd_import *class_new_import(struct obd_device *obd) struct obd_import *imp; imp = kzalloc(sizeof(*imp), GFP_NOFS); - if (imp == NULL) + if (!imp) return NULL; INIT_LIST_HEAD(&imp->imp_pinger_chain); @@ -1819,7 +1819,7 @@ void *kuc_alloc(int payload_len, int transport, int type) int len = kuc_len(payload_len); lh = kzalloc(len, GFP_NOFS); - if (lh == NULL) + if (!lh) return ERR_PTR(-ENOMEM); lh->kuc_magic = KUC_MAGIC; diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c index 4fa52d1b79d1..9af2da618a4d 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog.c +++ b/drivers/staging/lustre/lustre/obdclass/llog.c @@ -61,7 +61,7 @@ static struct llog_handle *llog_alloc_handle(void) struct llog_handle *loghandle; loghandle = kzalloc(sizeof(*loghandle), GFP_NOFS); - if (loghandle == NULL) + if (!loghandle) return NULL; init_rwsem(&loghandle->lgh_lock); @@ -208,7 +208,7 @@ int llog_init_handle(const struct lu_env *env, struct llog_handle *handle, LASSERT(handle->lgh_hdr == NULL); llh = kzalloc(sizeof(*llh), GFP_NOFS); - if (llh == NULL) + if (!llh) return -ENOMEM; handle->lgh_hdr = llh; /* first assign flags to use llog_client_ops */ @@ -435,7 +435,7 @@ int llog_process_or_fork(const struct lu_env *env, int rc; lpi = kzalloc(sizeof(*lpi), GFP_NOFS); - if (lpi == NULL) { + if (!lpi) { CERROR("cannot alloc pointer\n"); return -ENOMEM; } diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c index 17e7c1807863..c761dbf88278 100644 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c @@ -275,7 +275,7 @@ struct dentry *ldebugfs_add_symlink(const char *name, struct dentry *parent, return NULL; dest = kzalloc(MAX_STRING_SIZE + 1, GFP_KERNEL); - if (dest == NULL) + if (!dest) return NULL; va_start(ap, format); diff --git a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c index 5cc6435cc47a..d6184f821cd0 100644 --- a/drivers/staging/lustre/lustre/obdclass/lustre_peer.c +++ b/drivers/staging/lustre/lustre/obdclass/lustre_peer.c @@ -105,7 +105,7 @@ int class_add_uuid(const char *uuid, __u64 nid) return -EOVERFLOW; data = kzalloc(sizeof(*data), GFP_NOFS); - if (data == NULL) + if (!data) return -ENOMEM; obd_str2uuid(&data->un_uuid, uuid); diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c index fbdb748a36b9..3435720c96bb 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_config.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c @@ -835,7 +835,7 @@ int class_add_profile(int proflen, char *prof, int osclen, char *osc, CDEBUG(D_CONFIG, "Add profile %s\n", prof); lprof = kzalloc(sizeof(*lprof), GFP_NOFS); - if (lprof == NULL) + if (!lprof) return -ENOMEM; INIT_LIST_HEAD(&lprof->lp_list); @@ -979,7 +979,7 @@ struct lustre_cfg *lustre_cfg_rename(struct lustre_cfg *cfg, new_len = LUSTRE_CFG_BUFLEN(cfg, 1) + strlen(new_name) - name_len; new_param = kzalloc(new_len, GFP_NOFS); - if (new_param == NULL) + if (!new_param) return ERR_PTR(-ENOMEM); strcpy(new_param, new_name); @@ -987,7 +987,7 @@ struct lustre_cfg *lustre_cfg_rename(struct lustre_cfg *cfg, strcat(new_param, value); bufs = kzalloc(sizeof(*bufs), GFP_NOFS); - if (bufs == NULL) { + if (!bufs) { kfree(new_param); return ERR_PTR(-ENOMEM); } @@ -1461,7 +1461,7 @@ int class_config_llog_handler(const struct lu_env *env, inst_len = LUSTRE_CFG_BUFLEN(lcfg, 0) + sizeof(clli->cfg_instance) * 2 + 4; inst_name = kzalloc(inst_len, GFP_NOFS); - if (inst_name == NULL) { + if (!inst_name) { rc = -ENOMEM; goto out; } @@ -1639,7 +1639,7 @@ int class_config_dump_handler(const struct lu_env *env, int rc = 0; outstr = kzalloc(256, GFP_NOFS); - if (outstr == NULL) + if (!outstr) return -ENOMEM; if (rec->lrh_type == OBD_CFG_REC) { diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c index ce4a71f7171a..3e0b8a4b6486 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c @@ -85,7 +85,7 @@ int lustre_process_log(struct super_block *sb, char *logname, LASSERT(cfg); bufs = kzalloc(sizeof(*bufs), GFP_NOFS); - if (bufs == NULL) + if (!bufs) return -ENOMEM; /* mgc_process_config */ @@ -258,7 +258,7 @@ int lustre_start_mgc(struct super_block *sb) mgssec = lsi->lsi_lmd->lmd_mgssec ? lsi->lsi_lmd->lmd_mgssec : ""; data = kzalloc(sizeof(*data), GFP_NOFS); - if (data == NULL) { + if (!data) { rc = -ENOMEM; goto out_free; } @@ -885,7 +885,7 @@ static int lmd_parse_mgssec(struct lustre_mount_data *lmd, char *ptr) length = tail - ptr; lmd->lmd_mgssec = kzalloc(length + 1, GFP_NOFS); - if (lmd->lmd_mgssec == NULL) + if (!lmd->lmd_mgssec) return -ENOMEM; memcpy(lmd->lmd_mgssec, ptr, length); @@ -911,7 +911,7 @@ static int lmd_parse_string(char **handle, char *ptr) length = tail - ptr; *handle = kzalloc(length + 1, GFP_NOFS); - if (*handle == NULL) + if (!*handle) return -ENOMEM; memcpy(*handle, ptr, length); @@ -941,7 +941,7 @@ static int lmd_parse_mgs(struct lustre_mount_data *lmd, char **ptr) oldlen = strlen(lmd->lmd_mgs) + 1; mgsnid = kzalloc(oldlen + length + 1, GFP_NOFS); - if (mgsnid == NULL) + if (!mgsnid) return -ENOMEM; if (lmd->lmd_mgs != NULL) { @@ -983,7 +983,7 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd) lmd->lmd_magic = LMD_MAGIC; lmd->lmd_params = kzalloc(4096, GFP_NOFS); - if (lmd->lmd_params == NULL) + if (!lmd->lmd_params) return -ENOMEM; lmd->lmd_params[0] = '\0'; -- cgit v1.3-6-gb490 From efeb257dcf1c84fa05eff06cb829906576ae21b8 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:59:08 +0200 Subject: staging: lustre: obdecho: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdecho/echo_client.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c index 0222fd2e4757..de6f795e05d1 100644 --- a/drivers/staging/lustre/lustre/obdecho/echo_client.c +++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c @@ -480,11 +480,11 @@ static int echo_alloc_memmd(struct echo_device *ed, LASSERT(*lsmp == NULL); *lsmp = kzalloc(lsm_size, GFP_NOFS); - if (*lsmp == NULL) + if (!*lsmp) return -ENOMEM; (*lsmp)->lsm_oinfo[0] = kzalloc(sizeof(struct lov_oinfo), GFP_NOFS); - if ((*lsmp)->lsm_oinfo[0] == NULL) { + if (!(*lsmp)->lsm_oinfo[0]) { kfree(*lsmp); return -ENOMEM; } @@ -701,7 +701,7 @@ static struct lu_device *echo_device_alloc(const struct lu_env *env, int cleanup = 0; ed = kzalloc(sizeof(*ed), GFP_NOFS); - if (ed == NULL) { + if (!ed) { rc = -ENOMEM; goto out; } @@ -1878,7 +1878,7 @@ echo_client_iocontrol(unsigned int cmd, struct obd_export *exp, int len, return rc; env = kzalloc(sizeof(*env), GFP_NOFS); - if (env == NULL) + if (!env) return -ENOMEM; rc = lu_env_init(env, LCT_DT_THREAD); @@ -2049,7 +2049,7 @@ static int echo_client_setup(const struct lu_env *env, ec->ec_nstripes = 0; ocd = kzalloc(sizeof(*ocd), GFP_NOFS); - if (ocd == NULL) { + if (!ocd) { CERROR("Can't alloc ocd connecting to %s\n", lustre_cfg_string(lcfg, 1)); return -ENOMEM; -- cgit v1.3-6-gb490 From 3408e9aeee5fedd0eab223502074cad3120324b0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:59:09 +0200 Subject: staging: lustre: osc: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/osc/osc_dev.c | 2 +- drivers/staging/lustre/lustre/osc/osc_request.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/osc/osc_dev.c b/drivers/staging/lustre/lustre/osc/osc_dev.c index 9222c9f4faae..91fdec44792b 100644 --- a/drivers/staging/lustre/lustre/osc/osc_dev.c +++ b/drivers/staging/lustre/lustre/osc/osc_dev.c @@ -218,7 +218,7 @@ static struct lu_device *osc_device_alloc(const struct lu_env *env, int rc; od = kzalloc(sizeof(*od), GFP_NOFS); - if (od == NULL) + if (!od) return ERR_PTR(-ENOMEM); cl_device_init(&od->od_cl, t); diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index f84b4c78a8a0..96c80e9bf92d 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -119,7 +119,7 @@ static int osc_packmd(struct obd_export *exp, struct lov_mds_md **lmmp, if (*lmmp == NULL) { *lmmp = kzalloc(lmm_size, GFP_NOFS); - if (*lmmp == NULL) + if (!*lmmp) return -ENOMEM; } @@ -1909,7 +1909,7 @@ int osc_build_rpc(const struct lu_env *env, struct client_obd *cli, mpflag = cfs_memory_pressure_get_and_set(); crattr = kzalloc(sizeof(*crattr), GFP_NOFS); - if (crattr == NULL) { + if (!crattr) { rc = -ENOMEM; goto out; } -- cgit v1.3-6-gb490 From 597851ac2ae4e3857f2ab410adb0775951a09fa0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 18:59:10 +0200 Subject: staging: lustre: ptlrpc: Use !x to check for kzalloc failure !x is more normal for kzalloc failure in the kernel. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; statement S1, S2; @@ x = kzalloc(...); if ( - x == NULL + !x ) S1 else S2 // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ptlrpc/client.c | 2 +- drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c | 8 ++++---- drivers/staging/lustre/lustre/ptlrpc/nrs.c | 2 +- drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c | 2 +- drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c | 2 +- drivers/staging/lustre/lustre/ptlrpc/sec_config.c | 2 +- drivers/staging/lustre/lustre/ptlrpc/sec_plain.c | 2 +- drivers/staging/lustre/lustre/ptlrpc/service.c | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index a12cd66b2365..c83a34a01e65 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -971,7 +971,7 @@ int ptlrpc_set_add_cb(struct ptlrpc_request_set *set, struct ptlrpc_set_cbdata *cbdata; cbdata = kzalloc(sizeof(*cbdata), GFP_NOFS); - if (cbdata == NULL) + if (!cbdata) return -ENOMEM; cbdata->psc_interpret = fn; diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c index aaaabbf5f1b9..53f9af1f2f3e 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c +++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c @@ -652,7 +652,7 @@ static ssize_t ptlrpc_lprocfs_nrs_seq_write(struct file *file, return -EINVAL; cmd = kzalloc(LPROCFS_NRS_WR_MAX_CMD, GFP_NOFS); - if (cmd == NULL) + if (!cmd) return -ENOMEM; /** * strsep() modifies its argument, so keep a copy @@ -819,7 +819,7 @@ ptlrpc_lprocfs_svc_req_history_start(struct seq_file *s, loff_t *pos) } srhi = kzalloc(sizeof(*srhi), GFP_NOFS); - if (srhi == NULL) + if (!srhi) return NULL; srhi->srhi_seq = 0; @@ -1219,7 +1219,7 @@ int lprocfs_wr_evict_client(struct file *file, const char __user *buffer, char *tmpbuf; kbuf = kzalloc(BUFLEN, GFP_NOFS); - if (kbuf == NULL) + if (!kbuf) return -ENOMEM; /* @@ -1303,7 +1303,7 @@ int lprocfs_wr_import(struct file *file, const char __user *buffer, return -EINVAL; kbuf = kzalloc(count + 1, GFP_NOFS); - if (kbuf == NULL) + if (!kbuf) return -ENOMEM; if (copy_from_user(kbuf, buffer, count)) { diff --git a/drivers/staging/lustre/lustre/ptlrpc/nrs.c b/drivers/staging/lustre/lustre/ptlrpc/nrs.c index 9516acadb7a1..d37cdd5ac580 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/nrs.c +++ b/drivers/staging/lustre/lustre/ptlrpc/nrs.c @@ -1156,7 +1156,7 @@ int ptlrpc_nrs_policy_register(struct ptlrpc_nrs_pol_conf *conf) } desc = kzalloc(sizeof(*desc), GFP_NOFS); - if (desc == NULL) { + if (!desc) { rc = -ENOMEM; goto fail; } diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c index e591cff323ec..17cc81d5074f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c @@ -739,7 +739,7 @@ static int ptlrpcd_init(void) size = offsetof(struct ptlrpcd, pd_threads[nthreads]); ptlrpcds = kzalloc(size, GFP_NOFS); - if (ptlrpcds == NULL) { + if (!ptlrpcds) { rc = -ENOMEM; goto out; } diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c index 69d73c430696..2ee3e8b2e879 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c @@ -415,7 +415,7 @@ static int enc_pools_add_pages(int npages) for (i = 0; i < npools; i++) { pools[i] = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS); - if (pools[i] == NULL) + if (!pools[i]) goto out_pools; for (j = 0; j < PAGES_PER_POOL && alloced < npages; j++) { diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c index 31da43e8b3c6..e7f2f333257d 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_config.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_config.c @@ -564,7 +564,7 @@ struct sptlrpc_conf *sptlrpc_conf_get(const char *fsname, return NULL; conf = kzalloc(sizeof(*conf), GFP_NOFS); - if (conf == NULL) + if (!conf) return NULL; strcpy(conf->sc_fsname, fsname); diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c index 53ce0d14bd46..a243db60f697 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_plain.c @@ -444,7 +444,7 @@ struct ptlrpc_sec *plain_create_sec(struct obd_import *imp, LASSERT(SPTLRPC_FLVR_POLICY(sf->sf_rpc) == SPTLRPC_POLICY_PLAIN); plsec = kzalloc(sizeof(*plsec), GFP_NOFS); - if (plsec == NULL) + if (!plsec) return NULL; /* diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c index 9117f1c15a8e..56a86317ded7 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/service.c +++ b/drivers/staging/lustre/lustre/ptlrpc/service.c @@ -732,7 +732,7 @@ ptlrpc_register_service(struct ptlrpc_service_conf *conf, service = kzalloc(offsetof(struct ptlrpc_service, srv_parts[ncpts]), GFP_NOFS); - if (service == NULL) { + if (!service) { kfree(cpts); return ERR_PTR(-ENOMEM); } @@ -2298,7 +2298,7 @@ static int ptlrpc_main(void *arg) } env = kzalloc(sizeof(*env), GFP_NOFS); - if (env == NULL) { + if (!env) { rc = -ENOMEM; goto out_srv_fini; } -- cgit v1.3-6-gb490 From f82ced5d6bce6cd0719e95f744bfeb8f81677790 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 21:07:50 +0200 Subject: staging: lustre: llite: drop trivially useless initialization Remove initialization of a variable that is immediately reassigned. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ type T; identifier x; constant C; expression e; @@ T x - = C ; x = e; // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/llite/file.c | 2 +- drivers/staging/lustre/lustre/llite/xattr_cache.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 3075db211106..e01a47c0b80a 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -3005,7 +3005,7 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) struct inode *inode = d_inode(de); struct ll_sb_info *sbi = ll_i2sbi(inode); struct ll_inode_info *lli = ll_i2info(inode); - int res = 0; + int res; res = ll_inode_revalidate(de, MDS_INODELOCK_UPDATE | MDS_INODELOCK_LOOKUP); diff --git a/drivers/staging/lustre/lustre/llite/xattr_cache.c b/drivers/staging/lustre/lustre/llite/xattr_cache.c index 6956dec53fcc..9e763ce244e3 100644 --- a/drivers/staging/lustre/lustre/llite/xattr_cache.c +++ b/drivers/staging/lustre/lustre/llite/xattr_cache.c @@ -357,7 +357,7 @@ static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit) struct ll_inode_info *lli = ll_i2info(inode); struct mdt_body *body; __u32 *xsizes; - int rc = 0, i; + int rc, i; -- cgit v1.3-6-gb490 From 53a0d4868703c5d5d5dc0d0eaf9166d6bba9a697 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 21:07:53 +0200 Subject: staging: lustre: osc: drop trivially useless initialization Remove initialization of a variable that is immediately reassigned. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ type T; identifier x; constant C; expression e; @@ T x - = C ; x = e; // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/osc/osc_page.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/osc/osc_page.c b/drivers/staging/lustre/lustre/osc/osc_page.c index 43dfa73dd3a6..f9cf5cea643d 100644 --- a/drivers/staging/lustre/lustre/osc/osc_page.c +++ b/drivers/staging/lustre/lustre/osc/osc_page.c @@ -471,7 +471,7 @@ static int osc_page_flush(const struct lu_env *env, struct cl_io *io) { struct osc_page *opg = cl2osc_page(slice); - int rc = 0; + int rc; rc = osc_flush_async_page(env, io, opg); return rc; -- cgit v1.3-6-gb490 From a84b7fd5f7539a1eca943a17ba9d7cafc10f3f90 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 21:07:51 +0200 Subject: staging: lustre: lmv: drop trivially useless initialization Remove initialization of a variable that is immediately reassigned. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ type T; identifier x; constant C; expression e; @@ T x - = C ; x = e; // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/lmv/lmv_obd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index 5c058d0802dc..c9e0536e9f2a 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -1993,7 +1993,7 @@ static int lmv_setattr(struct obd_export *exp, struct md_op_data *op_data, struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; struct lmv_tgt_desc *tgt; - int rc = 0; + int rc; rc = lmv_check_connect(obd); if (rc) -- cgit v1.3-6-gb490 From 0d0c8b75713491cdb3f6e7792b68ccaae9e7518e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 21:07:52 +0200 Subject: staging: lustre: obdclass: llog: drop trivially useless initialization Remove initialization of a variable that is immediately reassigned. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ type T; identifier x; constant C; expression e; @@ T x - = C ; x = e; // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/llog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/llog.c b/drivers/staging/lustre/lustre/obdclass/llog.c index 9af2da618a4d..facc8351fcea 100644 --- a/drivers/staging/lustre/lustre/obdclass/llog.c +++ b/drivers/staging/lustre/lustre/obdclass/llog.c @@ -907,7 +907,7 @@ int llog_is_empty(const struct lu_env *env, struct llog_ctxt *ctxt, char *name) { struct llog_handle *llh; - int rc = 0; + int rc; rc = llog_open(env, ctxt, &llh, NULL, name, LLOG_OPEN_EXISTS); if (rc < 0) { -- cgit v1.3-6-gb490 From fad22d71bbba464bfb30ea5e5c18c52cc8e35168 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 20 Jun 2015 21:07:49 +0200 Subject: staging: lustre: libcfs: drop trivially useless initialization Remove initialization of a variable that is immediately reassigned. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ type T; identifier x; constant C; expression e; @@ T x - = C ; x = e; // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/fail.c | 2 +- drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/fail.c b/drivers/staging/lustre/lustre/libcfs/fail.c index 7b7fc215e633..42d615fbd664 100644 --- a/drivers/staging/lustre/lustre/libcfs/fail.c +++ b/drivers/staging/lustre/lustre/libcfs/fail.c @@ -123,7 +123,7 @@ EXPORT_SYMBOL(__cfs_fail_check_set); int __cfs_fail_timeout_set(__u32 id, __u32 value, int ms, int set) { - int ret = 0; + int ret; ret = __cfs_fail_check_set(id, value, set); if (ret) { diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c b/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c index 31a558115a96..933525c73da1 100644 --- a/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c +++ b/drivers/staging/lustre/lustre/libcfs/libcfs_cpu.c @@ -78,7 +78,7 @@ EXPORT_SYMBOL(cfs_cpt_table_free); int cfs_cpt_table_print(struct cfs_cpt_table *cptab, char *buf, int len) { - int rc = 0; + int rc; rc = snprintf(buf, len, "%d\t: %d\n", 0, 0); len -= rc; -- cgit v1.3-6-gb490 From a82de7ea52e74b39b9e13ec0d6372378181dcfd0 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Wed, 24 Jun 2015 10:07:45 -0400 Subject: staging/lustre/lnet: Move asm/irq.h include after linux includes Apparently m86k cannot build if you include asm/irq.h before linux/* includes and fixing it there is hard. So just move asm/irq.h include to where it does not cause any problems. Thanks to Geert Uytterhoeven for getting to the root of it. Signed-off-by: Oleg Drokin Compile-Tested-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h index 7125eb955ae5..cb91e68919d0 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h @@ -31,7 +31,6 @@ #define DEBUG_PORTAL_ALLOC #define DEBUG_SUBSYSTEM S_LND -#include #include #include #include @@ -47,6 +46,7 @@ #include #include #include +#include #include #include -- cgit v1.3-6-gb490 From 3c150f0081647c0b96ce0d61d541b9b470433676 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Wed, 24 Jun 2015 10:09:24 -0400 Subject: staging/lustre/lov: Move target sysfs symlink removal to LOV freeing This helps to avoid use after free on unmount. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/lov/lov_obd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c index cd6ed580c48b..5f4c115f4ff4 100644 --- a/drivers/staging/lustre/lustre/lov/lov_obd.c +++ b/drivers/staging/lustre/lustre/lov/lov_obd.c @@ -107,6 +107,10 @@ static void lov_putref(struct obd_device *obd) /* Disconnect */ __lov_del_obd(obd, tgt); } + + if (lov->lov_tgts_kobj) + kobject_put(lov->lov_tgts_kobj); + } else { mutex_unlock(&lov->lov_lock); } @@ -322,9 +326,6 @@ static int lov_disconnect(struct obd_export *exp) } } - if (lov->lov_tgts_kobj) - kobject_put(lov->lov_tgts_kobj); - obd_putref(obd); out: -- cgit v1.3-6-gb490 From 6a491f2b80f2806221ba3a5a3e26fbe945f82d83 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:40 -0400 Subject: staging/lustre: make ldebugfs_remove recursive ldebugfs_remove is usually called on directories with files passed in as attributes, so simple debugfs_remove failes on them as not empty Switch to debugfs_remove_recursive. This fixes a number of problems where a new filesystem is mounted after being unmounted first. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/lprocfs_status.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c index c761dbf88278..08d1f0edf98d 100644 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c @@ -329,7 +329,7 @@ EXPORT_SYMBOL(ldebugfs_add_vars); void ldebugfs_remove(struct dentry **entryp) { - debugfs_remove(*entryp); + debugfs_remove_recursive(*entryp); *entryp = NULL; } EXPORT_SYMBOL(ldebugfs_remove); -- cgit v1.3-6-gb490 From faa7a4e3e03889267f66a98d85434b4ff7dd0087 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:41 -0400 Subject: staging/lustre/ldlm: In ldlm_pools_fini make sure there was init first. It turns out if you call ldlm_pools_fini without completing the ldlm_pools_init, then attempt to unregister not yet registered shrinkers makes the kernel very unhappy. So make sure we have them registered first. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ldlm/ldlm_pool.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c index 4519d779a0ef..c234acb85f10 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c @@ -1486,8 +1486,10 @@ EXPORT_SYMBOL(ldlm_pools_init); void ldlm_pools_fini(void) { - unregister_shrinker(&ldlm_pools_srv_shrinker); - unregister_shrinker(&ldlm_pools_cli_shrinker); + if (ldlm_pools_thread) { + unregister_shrinker(&ldlm_pools_srv_shrinker); + unregister_shrinker(&ldlm_pools_cli_shrinker); + } ldlm_pools_thread_stop(); } EXPORT_SYMBOL(ldlm_pools_fini); -- cgit v1.3-6-gb490 From 3c4872f94359ed38a1392c0a9238c48a9aee6f8f Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:42 -0400 Subject: staging/lustre/obdclass: fix class_procfs_init error return value Dan Carpenter noticed that procfs conversion patches introduced a bug where should kobject_create_and_add, an error is not returned from class_procfs_init. Reported-by: Dan Carpenter Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/linux/linux-module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c index 84f75dce0d4c..b618c0bd7e09 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c @@ -423,7 +423,7 @@ static struct attribute_group lustre_attr_group = { int class_procfs_init(void) { - int rc = 0; + int rc = -ENOMEM; struct dentry *file; lustre_kobj = kobject_create_and_add("lustre", fs_kobj); -- cgit v1.3-6-gb490 From 80595b7498a1c4c7bb4f3db3bd8b7998196c8719 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:43 -0400 Subject: staging/lustre: remove alloc_fail_rate sysctl It was used to control allocation failure rate, but there is in-kernel way of doing that that's more versatile too. This is going to remove just the sysctl, the underlying variable will be removed once all OBD_ALLOC* macros removal patchseries land. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- .../lustre/lustre/obdclass/linux/linux-sysctl.c | 38 ---------------------- 1 file changed, 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c index 54f0a81f7b51..b9a7d2faf049 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c @@ -203,37 +203,6 @@ static int proc_max_dirty_pages_in_mb(struct ctl_table *table, int write, return rc; } -static int proc_alloc_fail_rate(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int rc = 0; - - if (!table->data || !table->maxlen || !*lenp || (*ppos && !write)) { - *lenp = 0; - return 0; - } - if (write) { - rc = lprocfs_write_frac_helper(buffer, *lenp, - (unsigned int *)table->data, - OBD_ALLOC_FAIL_MULT); - } else { - char buf[21]; - int len; - - len = lprocfs_read_frac_helper(buf, 21, - *(unsigned int *)table->data, - OBD_ALLOC_FAIL_MULT); - if (len > *lenp) - len = *lenp; - buf[len] = '\0'; - if (copy_to_user(buffer, buf, len)) - return -EFAULT; - *lenp = len; - } - *ppos += *lenp; - return rc; -} - static struct ctl_table obd_table[] = { { .procname = "timeout", @@ -298,13 +267,6 @@ static struct ctl_table obd_table[] = { .mode = 0644, .proc_handler = &proc_set_timeout }, - { - .procname = "alloc_fail_rate", - .data = &obd_alloc_fail_rate, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_alloc_fail_rate - }, { .procname = "max_dirty_mb", .data = &obd_max_dirty_pages, -- cgit v1.3-6-gb490 From 2836cd81a9ca8d3fc7c86fe4167b8053d784e725 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:44 -0400 Subject: staging/lustre: Remove now obsolete memory tracking sysctls In the past when Lustre did its own allocation amounts tracking the results were shown in sysctl as current and overall max number of bytes and pages allocated. Now that we don't track these, remove the sysctls. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- .../lustre/lustre/obdclass/linux/linux-sysctl.c | 124 --------------------- 1 file changed, 124 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c index b9a7d2faf049..e800bd6c5491 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c @@ -66,102 +66,6 @@ static int proc_set_timeout(struct ctl_table *table, int write, return rc; } -static int proc_memory_alloc(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - char buf[22]; - int len; - - if (!*lenp || (*ppos && !write)) { - *lenp = 0; - return 0; - } - if (write) - return -EINVAL; - - len = snprintf(buf, sizeof(buf), "%llu\n", obd_memory_sum()); - if (len > *lenp) - len = *lenp; - buf[len] = '\0'; - if (copy_to_user(buffer, buf, len)) - return -EFAULT; - *lenp = len; - *ppos += *lenp; - return 0; -} - -static int proc_pages_alloc(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - char buf[22]; - int len; - - if (!*lenp || (*ppos && !write)) { - *lenp = 0; - return 0; - } - if (write) - return -EINVAL; - - len = snprintf(buf, sizeof(buf), "%llu\n", obd_pages_sum()); - if (len > *lenp) - len = *lenp; - buf[len] = '\0'; - if (copy_to_user(buffer, buf, len)) - return -EFAULT; - *lenp = len; - *ppos += *lenp; - return 0; -} - -static int proc_mem_max(struct ctl_table *table, int write, void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - char buf[22]; - int len; - - if (!*lenp || (*ppos && !write)) { - *lenp = 0; - return 0; - } - if (write) - return -EINVAL; - - len = snprintf(buf, sizeof(buf), "%llu\n", obd_memory_max()); - if (len > *lenp) - len = *lenp; - buf[len] = '\0'; - if (copy_to_user(buffer, buf, len)) - return -EFAULT; - *lenp = len; - *ppos += *lenp; - return 0; -} - -static int proc_pages_max(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - char buf[22]; - int len; - - if (!*lenp || (*ppos && !write)) { - *lenp = 0; - return 0; - } - if (write) - return -EINVAL; - - len = snprintf(buf, sizeof(buf), "%llu\n", obd_pages_max()); - if (len > *lenp) - len = *lenp; - buf[len] = '\0'; - if (copy_to_user(buffer, buf, len)) - return -EFAULT; - *lenp = len; - *ppos += *lenp; - return 0; -} - static int proc_max_dirty_pages_in_mb(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -232,34 +136,6 @@ static struct ctl_table obd_table[] = { .mode = 0644, .proc_handler = &proc_dointvec }, - { - .procname = "memused", - .data = NULL, - .maxlen = 0, - .mode = 0444, - .proc_handler = &proc_memory_alloc - }, - { - .procname = "pagesused", - .data = NULL, - .maxlen = 0, - .mode = 0444, - .proc_handler = &proc_pages_alloc - }, - { - .procname = "memused_max", - .data = NULL, - .maxlen = 0, - .mode = 0444, - .proc_handler = &proc_mem_max - }, - { - .procname = "pagesused_max", - .data = NULL, - .maxlen = 0, - .mode = 0444, - .proc_handler = &proc_pages_max - }, { .procname = "ldlm_timeout", .data = &ldlm_timeout, -- cgit v1.3-6-gb490 From 082a33441f5e0f8b59b6a7297fdfca064d55fb26 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:45 -0400 Subject: staging/lustre: Remove unneeded ldlm_timeout control ldlm_timeout is used server-side to determine AST timeouts, so it makes no sense on the client, esp. since it's not really used anywhere. Remove all traces of it except from the config where make it a noop. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/obd_support.h | 4 ---- drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c | 9 --------- drivers/staging/lustre/lustre/obdclass/class_obd.c | 4 ---- drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c | 9 --------- drivers/staging/lustre/lustre/obdclass/obd_config.c | 7 +------ 5 files changed, 1 insertion(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h index 73e2d4880b9b..f6b369206ace 100644 --- a/drivers/staging/lustre/lustre/include/obd_support.h +++ b/drivers/staging/lustre/lustre/include/obd_support.h @@ -56,9 +56,7 @@ extern unsigned int obd_dump_on_eviction; /* obd_timeout should only be used for recovery, not for networking / disk / timings affected by load (use Adaptive Timeouts) */ extern unsigned int obd_timeout; /* seconds */ -extern unsigned int ldlm_timeout; /* seconds */ extern unsigned int obd_timeout_set; -extern unsigned int ldlm_timeout_set; extern unsigned int at_min; extern unsigned int at_max; extern unsigned int at_history; @@ -105,8 +103,6 @@ int obd_alloc_fail(const void *ptr, const char *name, const char *type, /* Timeout definitions */ #define OBD_TIMEOUT_DEFAULT 100 -#define LDLM_TIMEOUT_DEFAULT 20 -#define MDS_LDLM_TIMEOUT_DEFAULT 6 /* Time to wait for all clients to reconnect during recovery (hard limit) */ #define OBD_RECOVERY_TIME_HARD (obd_timeout * 9) /* Time to wait for all clients to reconnect during recovery (soft limit) */ diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c index 941eb4e72039..ac79db952da7 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c @@ -76,15 +76,6 @@ inline unsigned long round_timeout(unsigned long timeout) return cfs_time_seconds((int)cfs_duration_sec(cfs_time_sub(timeout, 0)) + 1); } -/* timeout for initial callback (AST) reply (bz10399) */ -static inline unsigned int ldlm_get_rq_timeout(void) -{ - /* Non-AT value */ - unsigned int timeout = min(ldlm_timeout, obd_timeout / 3); - - return timeout < 1 ? 1 : timeout; -} - #define ELT_STOPPED 0 #define ELT_READY 1 #define ELT_TERMINATE 2 diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index 8ebe2e6c1696..34b16c044df8 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -78,12 +78,8 @@ atomic_t obd_dirty_pages; EXPORT_SYMBOL(obd_dirty_pages); unsigned int obd_timeout = OBD_TIMEOUT_DEFAULT; /* seconds */ EXPORT_SYMBOL(obd_timeout); -unsigned int ldlm_timeout = LDLM_TIMEOUT_DEFAULT; /* seconds */ -EXPORT_SYMBOL(ldlm_timeout); unsigned int obd_timeout_set; EXPORT_SYMBOL(obd_timeout_set); -unsigned int ldlm_timeout_set; -EXPORT_SYMBOL(ldlm_timeout_set); /* Adaptive timeout defs here instead of ptlrpc module for /proc/sys/ access */ unsigned int at_min = 0; EXPORT_SYMBOL(at_min); diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c index e800bd6c5491..eda5f30e8f30 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c @@ -61,8 +61,6 @@ static int proc_set_timeout(struct ctl_table *table, int write, int rc; rc = proc_dointvec(table, write, buffer, lenp, ppos); - if (ldlm_timeout >= obd_timeout) - ldlm_timeout = max(obd_timeout / 3, 1U); return rc; } @@ -136,13 +134,6 @@ static struct ctl_table obd_table[] = { .mode = 0644, .proc_handler = &proc_dointvec }, - { - .procname = "ldlm_timeout", - .data = &ldlm_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_set_timeout - }, { .procname = "max_dirty_mb", .data = &obd_max_dirty_pages, diff --git a/drivers/staging/lustre/lustre/obdclass/obd_config.c b/drivers/staging/lustre/lustre/obdclass/obd_config.c index 3435720c96bb..93805ac93c5a 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_config.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_config.c @@ -1123,12 +1123,7 @@ int class_process_config(struct lustre_cfg *lcfg) goto out; } case LCFG_SET_LDLM_TIMEOUT: { - CDEBUG(D_IOCTL, "changing lustre ldlm_timeout from %d to %d\n", - ldlm_timeout, lcfg->lcfg_num); - ldlm_timeout = max(lcfg->lcfg_num, 1U); - if (ldlm_timeout >= obd_timeout) - ldlm_timeout = max(obd_timeout / 3, 1U); - ldlm_timeout_set = 1; + /* ldlm_timeout is not used on the client */ err = 0; goto out; } -- cgit v1.3-6-gb490 From e2424a1265f2772b66f068c205256e2aef5f74a0 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:46 -0400 Subject: staging/lustre/obdclass: move sysctl timeout to sysfs This is the first step of moving lustre sysctls from /proc/sys/lustre to /sys/fs/lustre Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/obd_class.h | 4 +- drivers/staging/lustre/lustre/obdclass/class_obd.c | 6 +- .../lustre/lustre/obdclass/linux/linux-sysctl.c | 66 +++++++++++++++++----- drivers/staging/lustre/sysfs-fs-lustre | 12 ++++ 4 files changed, 71 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h index 36ed78127830..7dce4eea8575 100644 --- a/drivers/staging/lustre/lustre/include/obd_class.h +++ b/drivers/staging/lustre/lustre/include/obd_class.h @@ -1869,8 +1869,8 @@ extern int (*ptlrpc_put_connection_superhack)(struct ptlrpc_connection *c); /* obd_mount.c */ /* sysctl.c */ -extern void obd_sysctl_init (void); -extern void obd_sysctl_clean (void); +extern int obd_sysctl_init(void); +extern void obd_sysctl_clean(void); /* uuid.c */ typedef __u8 class_uuid_t[16]; diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index 34b16c044df8..2e42d1a637f1 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -567,12 +567,14 @@ static int __init init_obdclass(void) if (err) return err; - obd_sysctl_init(); - err = class_procfs_init(); if (err) return err; + err = obd_sysctl_init(); + if (err) + return err; + err = lu_global_init(); if (err) return err; diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c index eda5f30e8f30..3c8087b5cf4b 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c @@ -54,16 +54,53 @@ static struct ctl_table_header *obd_table_header; #endif -#ifdef CONFIG_SYSCTL -static int proc_set_timeout(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) +struct static_lustre_uintvalue_attr { + struct { + struct attribute attr; + ssize_t (*show)(struct kobject *kobj, struct attribute *attr, + char *buf); + ssize_t (*store)(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len); + } u; + int *value; +}; + +static ssize_t static_uintvalue_show(struct kobject *kobj, + struct attribute *attr, + char *buf) { + struct static_lustre_uintvalue_attr *lattr = (void *)attr; + + return sprintf(buf, "%d\n", *lattr->value); +} + +static ssize_t static_uintvalue_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, size_t count) +{ + struct static_lustre_uintvalue_attr *lattr = (void *)attr; int rc; + unsigned int val; - rc = proc_dointvec(table, write, buffer, lenp, ppos); - return rc; + rc = kstrtouint(buffer, 10, &val); + if (rc) + return rc; + + *lattr->value = val; + + return count; } +#define LUSTRE_STATIC_UINT_ATTR(name, value) \ +static struct static_lustre_uintvalue_attr lustre_sattr_##name = \ + {__ATTR(name, 0644, \ + static_uintvalue_show, \ + static_uintvalue_store),\ + value } + +LUSTRE_STATIC_UINT_ATTR(timeout, &obd_timeout); + +#ifdef CONFIG_SYSCTL static int proc_max_dirty_pages_in_mb(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -106,13 +143,6 @@ static int proc_max_dirty_pages_in_mb(struct ctl_table *table, int write, } static struct ctl_table obd_table[] = { - { - .procname = "timeout", - .data = &obd_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_set_timeout - }, { .procname = "debug_peer_on_timeout", .data = &obd_debug_peer_on_timeout, @@ -191,12 +221,22 @@ static struct ctl_table parent_table[] = { }; #endif -void obd_sysctl_init(void) +static struct attribute *lustre_attrs[] = { + &lustre_sattr_timeout.u.attr, + NULL, +}; + +static struct attribute_group lustre_attr_group = { + .attrs = lustre_attrs, +}; + +int obd_sysctl_init(void) { #ifdef CONFIG_SYSCTL if (!obd_table_header) obd_table_header = register_sysctl_table(parent_table); #endif + return sysfs_create_group(lustre_kobj, &lustre_attr_group); } void obd_sysctl_clean(void) diff --git a/drivers/staging/lustre/sysfs-fs-lustre b/drivers/staging/lustre/sysfs-fs-lustre index 1e302e8516ce..6dbad260fa7d 100644 --- a/drivers/staging/lustre/sysfs-fs-lustre +++ b/drivers/staging/lustre/sysfs-fs-lustre @@ -40,6 +40,18 @@ Description: e.g. dd.1253 nodelocal - use jobid_name value from above. +What: /sys/fs/lustre/timeout +Date: June 2015 +Contact: "Oleg Drokin" +Description: + Controls "lustre timeout" variable, also known as obd_timeout + in some old manual. In the past obd_timeout was of paramount + importance as the timeout value used everywhere and where + other timeouts were derived from. These days it's much less + important as network timeouts are mostly determined by + AT (adaptive timeouts). + Unit: seconds, default: 100 + What: /sys/fs/lustre/llite/-/blocksize Date: May 2015 Contact: "Oleg Drokin" -- cgit v1.3-6-gb490 From df476a4d5de09d9324b108fc9c5ff2c00a0850d0 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:47 -0400 Subject: staging/lustre/obdclass: move max_dirty_mb from sysctl to sysfs max_dirty_mb is now a parameter in /sys/fs/lustre/ Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- .../lustre/lustre/obdclass/linux/linux-sysctl.c | 74 +++++++++------------- drivers/staging/lustre/sysfs-fs-lustre | 12 ++++ 2 files changed, 43 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c index 3c8087b5cf4b..bb55a07b6c51 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c @@ -100,48 +100,42 @@ static struct static_lustre_uintvalue_attr lustre_sattr_##name = \ LUSTRE_STATIC_UINT_ATTR(timeout, &obd_timeout); -#ifdef CONFIG_SYSCTL -static int proc_max_dirty_pages_in_mb(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) +static ssize_t max_dirty_mb_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - int rc = 0; + return sprintf(buf, "%ul\n", + obd_max_dirty_pages / (1 << (20 - PAGE_CACHE_SHIFT))); +} + +static ssize_t max_dirty_mb_store(struct kobject *kobj, struct attribute *attr, + const char *buffer, size_t count) +{ + int rc; + unsigned long val; + + rc = kstrtoul(buffer, 10, &val); + if (rc) + return rc; + + val *= 1 << (20 - PAGE_CACHE_SHIFT); /* convert to pages */ - if (!table->data || !table->maxlen || !*lenp || (*ppos && !write)) { - *lenp = 0; - return 0; + if (val > ((totalram_pages / 10) * 9)) { + /* Somebody wants to assign too much memory to dirty pages */ + return -EINVAL; } - if (write) { - rc = lprocfs_write_frac_helper(buffer, *lenp, - (unsigned int *)table->data, - 1 << (20 - PAGE_CACHE_SHIFT)); - /* Don't allow them to let dirty pages exceed 90% of system - * memory and set a hard minimum of 4MB. */ - if (obd_max_dirty_pages > ((totalram_pages / 10) * 9)) { - CERROR("Refusing to set max dirty pages to %u, which is more than 90%% of available RAM; setting to %lu\n", - obd_max_dirty_pages, - ((totalram_pages / 10) * 9)); - obd_max_dirty_pages = (totalram_pages / 10) * 9; - } else if (obd_max_dirty_pages < 4 << (20 - PAGE_CACHE_SHIFT)) { - obd_max_dirty_pages = 4 << (20 - PAGE_CACHE_SHIFT); - } - } else { - char buf[21]; - int len; - - len = lprocfs_read_frac_helper(buf, sizeof(buf), - *(unsigned int *)table->data, - 1 << (20 - PAGE_CACHE_SHIFT)); - if (len > *lenp) - len = *lenp; - buf[len] = '\0'; - if (copy_to_user(buffer, buf, len)) - return -EFAULT; - *lenp = len; + + if (val < 4 << (20 - PAGE_CACHE_SHIFT)) { + /* Less than 4 Mb for dirty cache is also bad */ + return -EINVAL; } - *ppos += *lenp; - return rc; + + obd_max_dirty_pages = val; + + return count; } +LUSTRE_RW_ATTR(max_dirty_mb); +#ifdef CONFIG_SYSCTL static struct ctl_table obd_table[] = { { .procname = "debug_peer_on_timeout", @@ -164,13 +158,6 @@ static struct ctl_table obd_table[] = { .mode = 0644, .proc_handler = &proc_dointvec }, - { - .procname = "max_dirty_mb", - .data = &obd_max_dirty_pages, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_max_dirty_pages_in_mb - }, { .procname = "at_min", .data = &at_min, @@ -223,6 +210,7 @@ static struct ctl_table parent_table[] = { static struct attribute *lustre_attrs[] = { &lustre_sattr_timeout.u.attr, + &lustre_attr_max_dirty_mb.attr, NULL, }; diff --git a/drivers/staging/lustre/sysfs-fs-lustre b/drivers/staging/lustre/sysfs-fs-lustre index 6dbad260fa7d..38d1adcd2335 100644 --- a/drivers/staging/lustre/sysfs-fs-lustre +++ b/drivers/staging/lustre/sysfs-fs-lustre @@ -52,6 +52,18 @@ Description: AT (adaptive timeouts). Unit: seconds, default: 100 +What: /sys/fs/lustre/max_dirty_mb +Date: June 2015 +Contact: "Oleg Drokin" +Description: + Controls total number of dirty cache (in megabytes) allowed + across all mounted lustre filesystems. + Since writeout of dirty pages in Lustre is somewhat expensive, + when you allow to many dirty pages, this might lead to + performance degradations as kernel tries to desperately + find some pages to free/writeout. + Default 1/2 RAM. Min value 4, max value 9/10 of RAM. + What: /sys/fs/lustre/llite/-/blocksize Date: May 2015 Contact: "Oleg Drokin" -- cgit v1.3-6-gb490 From 9e7fa14935901bcd09576b2866d5dd15f69caf83 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:48 -0400 Subject: staging/lustre/obdclass: move debug controls to sysfs debug_peer_on_timeout, dump_on_timeout and dump_on_eviction controls from /proc/sys/lustre to /sys/fs/lustre Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- .../lustre/lustre/obdclass/linux/linux-sysctl.c | 28 ++++++---------------- drivers/staging/lustre/sysfs-fs-lustre | 26 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c index bb55a07b6c51..6af1cb2cb386 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c @@ -135,29 +135,12 @@ static ssize_t max_dirty_mb_store(struct kobject *kobj, struct attribute *attr, } LUSTRE_RW_ATTR(max_dirty_mb); +LUSTRE_STATIC_UINT_ATTR(debug_peer_on_timeout, &obd_debug_peer_on_timeout); +LUSTRE_STATIC_UINT_ATTR(dump_on_timeout, &obd_dump_on_timeout); +LUSTRE_STATIC_UINT_ATTR(dump_on_eviction, &obd_dump_on_eviction); + #ifdef CONFIG_SYSCTL static struct ctl_table obd_table[] = { - { - .procname = "debug_peer_on_timeout", - .data = &obd_debug_peer_on_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .procname = "dump_on_timeout", - .data = &obd_dump_on_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .procname = "dump_on_eviction", - .data = &obd_dump_on_eviction, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, { .procname = "at_min", .data = &at_min, @@ -211,6 +194,9 @@ static struct ctl_table parent_table[] = { static struct attribute *lustre_attrs[] = { &lustre_sattr_timeout.u.attr, &lustre_attr_max_dirty_mb.attr, + &lustre_sattr_debug_peer_on_timeout.u.attr, + &lustre_sattr_dump_on_timeout.u.attr, + &lustre_sattr_dump_on_eviction.u.attr, NULL, }; diff --git a/drivers/staging/lustre/sysfs-fs-lustre b/drivers/staging/lustre/sysfs-fs-lustre index 38d1adcd2335..ea9982bae85d 100644 --- a/drivers/staging/lustre/sysfs-fs-lustre +++ b/drivers/staging/lustre/sysfs-fs-lustre @@ -64,6 +64,32 @@ Description: find some pages to free/writeout. Default 1/2 RAM. Min value 4, max value 9/10 of RAM. +What: /sys/fs/lustre/debug_peer_on_timeout +Date: June 2015 +Contact: "Oleg Drokin" +Description: + Control if lnet debug information should be printed when + an RPC timeout occurs. + 0 disabled (default) + 1 enabled + +What: /sys/fs/lustre/dump_on_timeout +Date: June 2015 +Contact: "Oleg Drokin" +Description: + Controls if Lustre debug log should be dumped when an RPC + timeout occurs. This is useful if yout debug buffer typically + rolls over by the time you notice RPC timeouts. + +What: /sys/fs/lustre/dump_on_eviction +Date: June 2015 +Contact: "Oleg Drokin" +Description: + Controls if Lustre debug log should be dumped when an this + client is evicted from one of the servers. + This is useful if yout debug buffer typically rolls over + by the time you notice the eviction event. + What: /sys/fs/lustre/llite/-/blocksize Date: May 2015 Contact: "Oleg Drokin" -- cgit v1.3-6-gb490 From bcef118e7ed67e28edcaab9be9ca11412176c540 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:49 -0400 Subject: staging/lustre/obdclass: Move AT controls from sysctl to sysfs Adaptive Timeouts controls are being moved from /proc/sys/lustre to /sys/fs/lustre Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- .../lustre/lustre/obdclass/linux/linux-sysctl.c | 45 ++++-------------- drivers/staging/lustre/sysfs-fs-lustre | 53 ++++++++++++++++++++++ 2 files changed, 63 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c index 6af1cb2cb386..82b3c39214b0 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c @@ -138,44 +138,14 @@ LUSTRE_RW_ATTR(max_dirty_mb); LUSTRE_STATIC_UINT_ATTR(debug_peer_on_timeout, &obd_debug_peer_on_timeout); LUSTRE_STATIC_UINT_ATTR(dump_on_timeout, &obd_dump_on_timeout); LUSTRE_STATIC_UINT_ATTR(dump_on_eviction, &obd_dump_on_eviction); +LUSTRE_STATIC_UINT_ATTR(at_min, &at_min); +LUSTRE_STATIC_UINT_ATTR(at_max, &at_max); +LUSTRE_STATIC_UINT_ATTR(at_extra, &at_extra); +LUSTRE_STATIC_UINT_ATTR(at_early_margin, &at_early_margin); +LUSTRE_STATIC_UINT_ATTR(at_history, &at_history); #ifdef CONFIG_SYSCTL static struct ctl_table obd_table[] = { - { - .procname = "at_min", - .data = &at_min, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, - { - .procname = "at_max", - .data = &at_max, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, - { - .procname = "at_extra", - .data = &at_extra, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, - { - .procname = "at_early_margin", - .data = &at_early_margin, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, - { - .procname = "at_history", - .data = &at_history, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, {} }; @@ -197,6 +167,11 @@ static struct attribute *lustre_attrs[] = { &lustre_sattr_debug_peer_on_timeout.u.attr, &lustre_sattr_dump_on_timeout.u.attr, &lustre_sattr_dump_on_eviction.u.attr, + &lustre_sattr_at_min.u.attr, + &lustre_sattr_at_max.u.attr, + &lustre_sattr_at_extra.u.attr, + &lustre_sattr_at_early_margin.u.attr, + &lustre_sattr_at_history.u.attr, NULL, }; diff --git a/drivers/staging/lustre/sysfs-fs-lustre b/drivers/staging/lustre/sysfs-fs-lustre index ea9982bae85d..873e2cf31217 100644 --- a/drivers/staging/lustre/sysfs-fs-lustre +++ b/drivers/staging/lustre/sysfs-fs-lustre @@ -90,6 +90,59 @@ Description: This is useful if yout debug buffer typically rolls over by the time you notice the eviction event. +What: /sys/fs/lustre/at_min +Date: July 2015 +Contact: "Oleg Drokin" +Description: + Controls minimum adaptive timeout in seconds. If you encounter + a case where clients timeout due to server-reported processing + time being too short, you might consider increasing this value. + One common case of this if the underlying network has + unpredictable long delays. + Default: 0 + +What: /sys/fs/lustre/at_max +Date: July 2015 +Contact: "Oleg Drokin" +Description: + Controls maximum adaptive timeout in seconds. If at_max timeout + is reached for an RPC, the RPC will time out. + Some genuinuely slow network hardware might warrant increasing + this value. + Setting this value to 0 disables Adaptive Timeouts + functionality and old-style obd_timeout value is then used. + Default: 600 + +What: /sys/fs/lustre/at_extra +Date: July 2015 +Contact: "Oleg Drokin" +Description: + Controls how much extra time to request for unfinished requests + in processing in seconds. Normally a server-side parameter, it + is also used on the client for responses to various LDLM ASTs + that are handled with a special server thread on the client. + This is a way for the servers to ask the clients not to time + out the request that reached current servicing time estimate + yet and give it some more time. + Default: 30 + +What: /sys/fs/lustre/at_early_margin +Date: July 2015 +Contact: "Oleg Drokin" +Description: + Controls when to send the early reply for requests that are + about to timeout as an offset to the estimated service time in + seconds.. + Default: 5 + +What: /sys/fs/lustre/at_history +Date: July 2015 +Contact: "Oleg Drokin" +Description: + Controls for how many seconds to remember slowest events + encountered by adaptive timeouts code. + Default: 600 + What: /sys/fs/lustre/llite/-/blocksize Date: May 2015 Contact: "Oleg Drokin" -- cgit v1.3-6-gb490 From 8952aad1cfc178cae5205546be62f0e22a056f0b Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:50 -0400 Subject: staging/lustre: Get rid of remaining /proc/sys/lustre plumbing Since all of the variables from /proc/sys/lustre were moved to /sys/fs/lustre, get rid of the remaining infrastructure. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/obd_class.h | 1 - drivers/staging/lustre/lustre/obdclass/class_obd.c | 1 - .../lustre/lustre/obdclass/linux/linux-sysctl.c | 30 ---------------------- 3 files changed, 32 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h index 7dce4eea8575..e1f8b15753f9 100644 --- a/drivers/staging/lustre/lustre/include/obd_class.h +++ b/drivers/staging/lustre/lustre/include/obd_class.h @@ -1870,7 +1870,6 @@ extern int (*ptlrpc_put_connection_superhack)(struct ptlrpc_connection *c); /* sysctl.c */ extern int obd_sysctl_init(void); -extern void obd_sysctl_clean(void); /* uuid.c */ typedef __u8 class_uuid_t[16]; diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index 2e42d1a637f1..edb2c7d525db 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -659,7 +659,6 @@ static void cleanup_obdclass(void) lu_global_fini(); obd_cleanup_caches(); - obd_sysctl_clean(); class_procfs_clean(); diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c index 82b3c39214b0..1515163a81a5 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-sysctl.c @@ -50,10 +50,6 @@ #include "../../include/obd_support.h" #include "../../include/lprocfs_status.h" -#ifdef CONFIG_SYSCTL -static struct ctl_table_header *obd_table_header; -#endif - struct static_lustre_uintvalue_attr { struct { struct attribute attr; @@ -144,23 +140,6 @@ LUSTRE_STATIC_UINT_ATTR(at_extra, &at_extra); LUSTRE_STATIC_UINT_ATTR(at_early_margin, &at_early_margin); LUSTRE_STATIC_UINT_ATTR(at_history, &at_history); -#ifdef CONFIG_SYSCTL -static struct ctl_table obd_table[] = { - {} -}; - -static struct ctl_table parent_table[] = { - { - .procname = "lustre", - .data = NULL, - .maxlen = 0, - .mode = 0555, - .child = obd_table - }, - {} -}; -#endif - static struct attribute *lustre_attrs[] = { &lustre_sattr_timeout.u.attr, &lustre_attr_max_dirty_mb.attr, @@ -181,18 +160,9 @@ static struct attribute_group lustre_attr_group = { int obd_sysctl_init(void) { -#ifdef CONFIG_SYSCTL - if (!obd_table_header) - obd_table_header = register_sysctl_table(parent_table); -#endif return sysfs_create_group(lustre_kobj, &lustre_attr_group); } void obd_sysctl_clean(void) { -#ifdef CONFIG_SYSCTL - if (obd_table_header) - unregister_sysctl_table(obd_table_header); - obd_table_header = NULL; -#endif } -- cgit v1.3-6-gb490 From 0871d551af37c72c308397c16c31bae945e6a79d Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:51 -0400 Subject: staging/lustre/libcfs: move /proc/sys/lnet to debugfs Parameters in lnet sysctl are of debug quantity, so let's move them to debugfs instead. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/module.c | 86 +++++++++++++++++---------- 1 file changed, 56 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index e60b2e9b9194..bffde77d089d 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -50,6 +50,7 @@ #include #include +#include # define DEBUG_SUBSYSTEM S_LNET @@ -69,10 +70,10 @@ extern struct miscdevice libcfs_dev; extern struct cfs_wi_sched *cfs_sched_rehash; extern void libcfs_init_nidstrings(void); -static int insert_proc(void); -static void remove_proc(void); +static void insert_debugfs(void); +static void remove_debugfs(void); -static struct ctl_table_header *lnet_table_header; +static struct dentry *lnet_debugfs_root; extern char lnet_upcall[1024]; /** * The path of debug log dump upcall script. @@ -428,17 +429,10 @@ static int init_libcfs_module(void) goto cleanup_wi; } - - rc = insert_proc(); - if (rc) { - CERROR("insert_proc: error %d\n", rc); - goto cleanup_crypto; - } + insert_debugfs(); CDEBUG (D_OTHER, "portals setup OK\n"); return 0; - cleanup_crypto: - cfs_crypto_unregister(); cleanup_wi: cfs_wi_shutdown(); cleanup_deregister: @@ -454,7 +448,7 @@ static void exit_libcfs_module(void) { int rc; - remove_proc(); + remove_debugfs(); CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n", atomic_read(&libcfs_kmemory)); @@ -935,31 +929,63 @@ static struct ctl_table lnet_table[] = { } }; -static struct ctl_table top_table[] = { - { - .procname = "lnet", - .mode = 0555, - .data = NULL, - .maxlen = 0, - .child = lnet_table, - }, - { - } +static ssize_t lnet_debugfs_read(struct file *filp, char __user *buf, + size_t count, loff_t *ppos) +{ + struct ctl_table *table = filp->private_data; + int error; + + error = table->proc_handler(table, 0, (void __user *)buf, &count, ppos); + if (!error) + error = count; + + return error; +} + +static ssize_t lnet_debugfs_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct ctl_table *table = filp->private_data; + int error; + + error = table->proc_handler(table, 1, (void __user *)buf, &count, ppos); + if (!error) + error = count; + + return error; +} + +static const struct file_operations lnet_debugfs_file_operations = { + .open = simple_open, + .read = lnet_debugfs_read, + .write = lnet_debugfs_write, + .llseek = default_llseek, }; -static int insert_proc(void) +static void insert_debugfs(void) { - if (lnet_table_header == NULL) - lnet_table_header = register_sysctl_table(top_table); - return 0; + struct ctl_table *table; + struct dentry *entry; + + if (lnet_debugfs_root == NULL) + lnet_debugfs_root = debugfs_create_dir("lnet", NULL); + + /* Even if we cannot create, just ignore it altogether) */ + if (IS_ERR_OR_NULL(lnet_debugfs_root)) + return; + + for (table = lnet_table; table->procname; table++) + entry = debugfs_create_file(table->procname, table->mode, + lnet_debugfs_root, table, + &lnet_debugfs_file_operations); } -static void remove_proc(void) +static void remove_debugfs(void) { - if (lnet_table_header != NULL) - unregister_sysctl_table(lnet_table_header); + if (lnet_debugfs_root != NULL) + debugfs_remove_recursive(lnet_debugfs_root); - lnet_table_header = NULL; + lnet_debugfs_root = NULL; } MODULE_VERSION("1.0.0"); -- cgit v1.3-6-gb490 From 1b4d97b6c6ca05446ff33843a7b174cdd765df5a Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:52 -0400 Subject: staging/lustre/libcfs: Remove redundant lnet debugfs variables /proc/sys/lnet/console_ratelimit, debug_path and panic_on_lbug are module parameters with no special magic accessible via /sys/module/libcfs/parameters/libcfs_console_ratelimit, /sys/module/libcfs/parameters/libcfs_debug_file_path and /sys/module/libcfs/parameters/libcfs_panic_on_lbug respectively. As such just replace them with corresponding symlinks Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/module.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index bffde77d089d..8a2644600d3e 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -802,13 +802,6 @@ static struct ctl_table lnet_table[] = { .mode = 0644, .proc_handler = &proc_dobitmasks, }, - { - .procname = "console_ratelimit", - .data = &libcfs_console_ratelimit, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, { .procname = "console_max_delay_centisecs", .maxlen = sizeof(int), @@ -828,14 +821,6 @@ static struct ctl_table lnet_table[] = { .proc_handler = &proc_console_backoff }, - { - .procname = "debug_path", - .data = libcfs_debug_file_path_arr, - .maxlen = sizeof(libcfs_debug_file_path_arr), - .mode = 0644, - .proc_handler = &proc_dostring, - }, - { .procname = "cpu_partition_table", .maxlen = 128, @@ -871,13 +856,6 @@ static struct ctl_table lnet_table[] = { .mode = 0444, .proc_handler = &proc_dointvec, }, - { - .procname = "panic_on_lbug", - .data = &libcfs_panic_on_lbug, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, { .procname = "dump_kernel", .maxlen = 256, -- cgit v1.3-6-gb490 From 8710427dd68f4dff8976d221e220317cea20ecec Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 6 Jul 2015 12:48:53 -0400 Subject: staging/lustre/libcfs: get rid of debugfs/lnet/console_backoff module parameter libcfs_console_backoff accessible through /sys/module/libcfs/parameters/libcfs_console_backoff would do the same thing, just add a special "uintpos" parameter type to disallow 0 values too. Also add a symlink to the module parameter variable for backwards compatibility Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/debug.c | 31 +++++++++++++- drivers/staging/lustre/lustre/libcfs/module.c | 59 +++++++++++---------------- 2 files changed, 54 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c index 021c92fa0333..147004cef391 100644 --- a/drivers/staging/lustre/lustre/libcfs/debug.c +++ b/drivers/staging/lustre/lustre/libcfs/debug.c @@ -82,8 +82,37 @@ module_param(libcfs_console_min_delay, uint, 0644); MODULE_PARM_DESC(libcfs_console_min_delay, "Lustre kernel debug console min delay (jiffies)"); EXPORT_SYMBOL(libcfs_console_min_delay); +static int param_set_uint_minmax(const char *val, + const struct kernel_param *kp, + unsigned int min, unsigned int max) +{ + unsigned int num; + int ret; + + if (!val) + return -EINVAL; + ret = kstrtouint(val, 0, &num); + if (ret == -EINVAL || num < min || num > max) + return -EINVAL; + *((unsigned int *)kp->arg) = num; + return 0; +} + +static int param_set_uintpos(const char *val, const struct kernel_param *kp) +{ + return param_set_uint_minmax(val, kp, 1, -1); +} + +static struct kernel_param_ops param_ops_uintpos = { + .set = param_set_uintpos, + .get = param_get_uint, +}; + +#define param_check_uintpos(name, p) \ + __param_check(name, p, unsigned int) + unsigned int libcfs_console_backoff = CDEBUG_DEFAULT_BACKOFF; -module_param(libcfs_console_backoff, uint, 0644); +module_param(libcfs_console_backoff, uintpos, 0644); MODULE_PARM_DESC(libcfs_console_backoff, "Lustre kernel debug console backoff factor"); EXPORT_SYMBOL(libcfs_console_backoff); diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index 8a2644600d3e..8b9ce223fc6f 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -678,34 +678,6 @@ static int proc_console_min_delay_cs(struct ctl_table *table, int write, return rc; } -static int proc_console_backoff(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int rc, backoff; - struct ctl_table dummy = *table; - - dummy.data = &backoff; - dummy.proc_handler = &proc_dointvec; - - if (!write) { /* read */ - backoff = libcfs_console_backoff; - rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); - return rc; - } - - /* write */ - backoff = 0; - rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); - if (rc < 0) - return rc; - if (backoff <= 0) - return -EINVAL; - - libcfs_console_backoff = backoff; - - return rc; -} - static int libcfs_force_lbug(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) @@ -814,13 +786,6 @@ static struct ctl_table lnet_table[] = { .mode = 0644, .proc_handler = &proc_console_min_delay_cs }, - { - .procname = "console_backoff", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_console_backoff - }, - { .procname = "cpu_partition_table", .maxlen = 128, @@ -907,6 +872,23 @@ static struct ctl_table lnet_table[] = { } }; +struct lnet_debugfs_symlink_def { + char *name; + char *target; +}; + +struct lnet_debugfs_symlink_def lnet_debugfs_symlinks[] = { + { "console_ratelimit", + "/sys/module/libcfs/parameters/libcfs_console_ratelimit"}, + { "debug_path", + "/sys/module/libcfs/parameters/libcfs_debug_file_path"}, + { "panic_on_lbug", + "/sys/module/libcfs/parameters/libcfs_panic_on_lbug"}, + { "libcfs_console_backoff", + "/sys/module/libcfs/parameters/libcfs_console_backoff"}, + {}, +}; + static ssize_t lnet_debugfs_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { @@ -944,6 +926,7 @@ static void insert_debugfs(void) { struct ctl_table *table; struct dentry *entry; + struct lnet_debugfs_symlink_def *symlinks; if (lnet_debugfs_root == NULL) lnet_debugfs_root = debugfs_create_dir("lnet", NULL); @@ -956,6 +939,12 @@ static void insert_debugfs(void) entry = debugfs_create_file(table->procname, table->mode, lnet_debugfs_root, table, &lnet_debugfs_file_operations); + + for (symlinks = lnet_debugfs_symlinks; symlinks->name; symlinks++) + entry = debugfs_create_symlink(symlinks->name, + lnet_debugfs_root, + symlinks->target); + } static void remove_debugfs(void) -- cgit v1.3-6-gb490 From 323b0b2c1e57d3c089473d755ff9a001d1a6bc8f Mon Sep 17 00:00:00 2001 From: Dmitry Eremin Date: Mon, 6 Jul 2015 12:48:54 -0400 Subject: staging/lustre/libcfs: Remove redundant enums and sysctl moduleparams /proc/sys/lnet/lnet_memused Remove memory tracking for LNet. Remove redundant enums definition. Signed-off-by: Dmitry Eremin Signed-off-by: Greg Kroah-Hartman --- .../lustre/include/linux/libcfs/libcfs_private.h | 28 +-------------- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 12 ------- .../staging/lustre/lnet/klnds/socklnd/socklnd.c | 5 --- .../staging/lustre/lnet/klnds/socklnd/socklnd_cb.c | 3 +- drivers/staging/lustre/lnet/lnet/router_proc.c | 11 ------ .../staging/lustre/lustre/include/obd_support.h | 12 +++---- drivers/staging/lustre/lustre/libcfs/debug.c | 3 -- drivers/staging/lustre/lustre/libcfs/module.c | 41 ---------------------- drivers/staging/lustre/lustre/obdclass/class_obd.c | 6 ++-- 9 files changed, 9 insertions(+), 112 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h index ed37d26eb20d..9544860e3292 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h @@ -87,24 +87,6 @@ do { \ lbug_with_loc(&msgdata); \ } while (0) -extern atomic_t libcfs_kmemory; -/* - * Memory - */ - -# define libcfs_kmem_inc(ptr, size) \ -do { \ - atomic_add(size, &libcfs_kmemory); \ -} while (0) - -# define libcfs_kmem_dec(ptr, size) \ -do { \ - atomic_sub(size, &libcfs_kmemory); \ -} while (0) - -# define libcfs_kmem_read() \ - atomic_read(&libcfs_kmemory) - #ifndef LIBCFS_VMALLOC_SIZE #define LIBCFS_VMALLOC_SIZE (2 << PAGE_CACHE_SHIFT) /* 2 pages */ #endif @@ -121,14 +103,9 @@ do { \ if (unlikely((ptr) == NULL)) { \ CERROR("LNET: out of memory at %s:%d (tried to alloc '" \ #ptr "' = %d)\n", __FILE__, __LINE__, (int)(size)); \ - CERROR("LNET: %d total bytes allocated by lnet\n", \ - libcfs_kmem_read()); \ } else { \ memset((ptr), 0, (size)); \ - libcfs_kmem_inc((ptr), (size)); \ - CDEBUG(D_MALLOC, "alloc '" #ptr "': %d at %p (tot %d).\n", \ - (int)(size), (ptr), libcfs_kmem_read()); \ - } \ + } \ } while (0) /** @@ -180,9 +157,6 @@ do { \ "%s:%d\n", s, __FILE__, __LINE__); \ break; \ } \ - libcfs_kmem_dec((ptr), s); \ - CDEBUG(D_MALLOC, "kfreed '" #ptr "': %d at %p (tot %d).\n", \ - s, (ptr), libcfs_kmem_read()); \ if (unlikely(s > LIBCFS_VMALLOC_SIZE)) \ vfree(ptr); \ else \ diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 4eb24a11b02a..f429d25306c1 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -2667,9 +2667,6 @@ static void kiblnd_base_shutdown(void) LASSERT(list_empty(&kiblnd_data.kib_devs)); - CDEBUG(D_MALLOC, "before LND base cleanup: kmem %d\n", - atomic_read(&libcfs_kmemory)); - switch (kiblnd_data.kib_init) { default: LBUG(); @@ -2720,9 +2717,6 @@ static void kiblnd_base_shutdown(void) if (kiblnd_data.kib_scheds != NULL) cfs_percpt_free(kiblnd_data.kib_scheds); - CDEBUG(D_MALLOC, "after LND base cleanup: kmem %d\n", - atomic_read(&libcfs_kmemory)); - kiblnd_data.kib_init = IBLND_INIT_NOTHING; module_put(THIS_MODULE); } @@ -2739,9 +2733,6 @@ void kiblnd_shutdown(lnet_ni_t *ni) if (net == NULL) goto out; - CDEBUG(D_MALLOC, "before LND net cleanup: kmem %d\n", - atomic_read(&libcfs_kmemory)); - write_lock_irqsave(g_lock, flags); net->ibn_shutdown = 1; write_unlock_irqrestore(g_lock, flags); @@ -2786,9 +2777,6 @@ void kiblnd_shutdown(lnet_ni_t *ni) break; } - CDEBUG(D_MALLOC, "after LND net cleanup: kmem %d\n", - atomic_read(&libcfs_kmemory)); - net->ibn_init = IBLND_INIT_NOTHING; ni->ni_data = NULL; diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c index 4128a92218a9..d8bfcadd184a 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c @@ -2252,8 +2252,6 @@ ksocknal_base_shutdown(void) int i; int j; - CDEBUG(D_MALLOC, "before NAL cleanup: kmem %d\n", - atomic_read(&libcfs_kmemory)); LASSERT(ksocknal_data.ksnd_nnets == 0); switch (ksocknal_data.ksnd_init) { @@ -2331,9 +2329,6 @@ ksocknal_base_shutdown(void) break; } - CDEBUG(D_MALLOC, "after NAL cleanup: kmem %d\n", - atomic_read(&libcfs_kmemory)); - module_put(THIS_MODULE); } diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c index fe2a83a540cd..0d5aac6a2bb3 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c @@ -526,8 +526,7 @@ ksocknal_process_transmit (ksock_conn_t *conn, ksock_tx_t *tx) counter++; /* exponential backoff warnings */ if ((counter & (-counter)) == counter) - CWARN("%u ENOMEM tx %p (%u allocated)\n", - counter, conn, atomic_read(&libcfs_kmemory)); + CWARN("%u ENOMEM tx %p\n", counter, conn); /* Queue on ksnd_enomem_conns for retry after a timeout */ spin_lock_bh(&ksocknal_data.ksnd_reaper_lock); diff --git a/drivers/staging/lustre/lnet/lnet/router_proc.c b/drivers/staging/lustre/lnet/lnet/router_proc.c index ee902dc43823..40f418b82960 100644 --- a/drivers/staging/lustre/lnet/lnet/router_proc.c +++ b/drivers/staging/lustre/lnet/lnet/router_proc.c @@ -32,17 +32,6 @@ static struct ctl_table_header *lnet_table_header; -#define CTL_LNET (0x100) -enum { - PSDEV_LNET_STATS = 100, - PSDEV_LNET_ROUTES, - PSDEV_LNET_ROUTERS, - PSDEV_LNET_PEERS, - PSDEV_LNET_BUFFERS, - PSDEV_LNET_NIS, - PSDEV_LNET_PTL_ROTOR, -}; - #define LNET_LOFFT_BITS (sizeof(loff_t) * 8) /* * NB: max allowed LNET_CPT_BITS is 8 on 64-bit system and 2 on 32-bit system diff --git a/drivers/staging/lustre/lustre/include/obd_support.h b/drivers/staging/lustre/lustre/include/obd_support.h index f6b369206ace..88e16717e854 100644 --- a/drivers/staging/lustre/lustre/include/obd_support.h +++ b/drivers/staging/lustre/lustre/include/obd_support.h @@ -501,8 +501,6 @@ int obd_alloc_fail(const void *ptr, const char *name, const char *type, #define OBD_FAIL_ONCE CFS_FAIL_ONCE #define OBD_FAILED CFS_FAILED -extern atomic_t libcfs_kmemory; - extern void obd_update_maxusage(void); #define obd_memory_add(size) \ @@ -618,8 +616,8 @@ do { \ if (unlikely((ptr) == NULL)) { \ CERROR("vmalloc of '" #ptr "' (%d bytes) failed\n", \ (int)(size)); \ - CERROR("%llu total bytes allocated by Lustre, %d by LNET\n", \ - obd_memory_sum(), atomic_read(&libcfs_kmemory)); \ + CERROR("%llu total bytes allocated by Lustre\n", \ + obd_memory_sum()); \ } else { \ OBD_ALLOC_POST(ptr, size, "vmalloced"); \ } \ @@ -765,12 +763,10 @@ do { \ "failed\n", (int)1, \ (__u64)(1 << PAGE_CACHE_SHIFT)); \ CERROR("%llu total bytes and %llu total pages " \ - "(%llu bytes) allocated by Lustre, " \ - "%d total bytes by LNET\n", \ + "(%llu bytes) allocated by Lustre\n", \ obd_memory_sum(), \ obd_pages_sum() << PAGE_CACHE_SHIFT, \ - obd_pages_sum(), \ - atomic_read(&libcfs_kmemory)); \ + obd_pages_sum()); \ } else { \ obd_pages_add(0); \ CDEBUG(D_MALLOC, "alloc_pages '" #ptr "': %d page(s) / " \ diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c index 147004cef391..98075529cc53 100644 --- a/drivers/staging/lustre/lustre/libcfs/debug.c +++ b/drivers/staging/lustre/lustre/libcfs/debug.c @@ -136,9 +136,6 @@ module_param(libcfs_panic_on_lbug, uint, 0644); MODULE_PARM_DESC(libcfs_panic_on_lbug, "Lustre kernel panic on LBUG"); EXPORT_SYMBOL(libcfs_panic_on_lbug); -atomic_t libcfs_kmemory = ATOMIC_INIT(0); -EXPORT_SYMBOL(libcfs_kmemory); - static wait_queue_head_t debug_ctlwq; char libcfs_debug_file_path_arr[PATH_MAX] = LIBCFS_DEBUG_FILE_PATH_DEFAULT; diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index 8b9ce223fc6f..95fa846095ee 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -80,33 +80,6 @@ extern char lnet_upcall[1024]; */ extern char lnet_debug_log_upcall[1024]; -#define CTL_LNET (0x100) - -enum { - PSDEV_DEBUG = 1, /* control debugging */ - PSDEV_SUBSYSTEM_DEBUG, /* control debugging */ - PSDEV_PRINTK, /* force all messages to console */ - PSDEV_CONSOLE_RATELIMIT, /* ratelimit console messages */ - PSDEV_CONSOLE_MAX_DELAY_CS, /* maximum delay over which we skip messages */ - PSDEV_CONSOLE_MIN_DELAY_CS, /* initial delay over which we skip messages */ - PSDEV_CONSOLE_BACKOFF, /* delay increase factor */ - PSDEV_DEBUG_PATH, /* crashdump log location */ - PSDEV_DEBUG_DUMP_PATH, /* crashdump tracelog location */ - PSDEV_CPT_TABLE, /* information about cpu partitions */ - PSDEV_LNET_UPCALL, /* User mode upcall script */ - PSDEV_LNET_MEMUSED, /* bytes currently PORTAL_ALLOCated */ - PSDEV_LNET_CATASTROPHE, /* if we have LBUGged or panic'd */ - PSDEV_LNET_PANIC_ON_LBUG, /* flag to panic on LBUG */ - PSDEV_LNET_DUMP_KERNEL, /* snapshot kernel debug buffer to file */ - PSDEV_LNET_DAEMON_FILE, /* spool kernel debug buffer to file */ - PSDEV_LNET_DEBUG_MB, /* size of debug buffer */ - PSDEV_LNET_DEBUG_LOG_UPCALL, /* debug log upcall script */ - PSDEV_LNET_WATCHDOG_RATELIMIT, /* ratelimit watchdog messages */ - PSDEV_LNET_FORCE_LBUG, /* hook to force an LBUG */ - PSDEV_LNET_FAIL_LOC, /* control test failures instrumentation */ - PSDEV_LNET_FAIL_VAL, /* userdata for fail loc */ -}; - static void kportal_memhog_free (struct libcfs_device_userstate *ldu) { struct page **level0p = &ldu->ldu_memhog_root_page; @@ -450,9 +423,6 @@ static void exit_libcfs_module(void) remove_debugfs(); - CDEBUG(D_MALLOC, "before Portals cleanup: kmem %d\n", - atomic_read(&libcfs_kmemory)); - if (cfs_sched_rehash != NULL) { cfs_wi_sched_destroy(cfs_sched_rehash); cfs_sched_rehash = NULL; @@ -467,10 +437,6 @@ static void exit_libcfs_module(void) cfs_cpu_fini(); - if (atomic_read(&libcfs_kmemory) != 0) - CERROR("Portals memory leaked: %d bytes\n", - atomic_read(&libcfs_kmemory)); - rc = libcfs_debug_cleanup(); if (rc) pr_err("LustreError: libcfs_debug_cleanup: %d\n", rc); @@ -807,13 +773,6 @@ static struct ctl_table lnet_table[] = { .mode = 0644, .proc_handler = &proc_dostring, }, - { - .procname = "lnet_memused", - .data = (int *)&libcfs_kmemory.counter, - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = &proc_dointvec, - }, { .procname = "catastrophe", .data = &libcfs_catastrophe, diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index edb2c7d525db..2c705d76211f 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -140,11 +140,11 @@ int obd_alloc_fail(const void *ptr, const char *name, const char *type, CERROR("%s%salloc of %s (%llu bytes) failed at %s:%d\n", ptr ? "force " :"", type, name, (__u64)size, file, line); - CERROR("%llu total bytes and %llu total pages (%llu bytes) allocated by Lustre, %d total bytes by LNET\n", + CERROR("%llu total bytes and %llu total pages" + " (%llu bytes) allocated by Lustre\n", obd_memory_sum(), obd_pages_sum() << PAGE_CACHE_SHIFT, - obd_pages_sum(), - atomic_read(&libcfs_kmemory)); + obd_pages_sum()); return 1; } return 0; -- cgit v1.3-6-gb490 From 90c94b564265474cffe55888ce25f45ce0ce4bb5 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin Date: Mon, 6 Jul 2015 12:48:55 -0400 Subject: staging/lustre/libcfs: Remove unneeded lnet watchdog_ratelimit sysctl It is no longer used anywhere. Signed-off-by: Dmitry Eremin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h | 1 - drivers/staging/lustre/lustre/libcfs/debug.c | 3 --- drivers/staging/lustre/lustre/libcfs/module.c | 12 ------------ 3 files changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h index 8251ac932e37..a3aa644154e2 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_debug.h @@ -50,7 +50,6 @@ extern unsigned int libcfs_stack; extern unsigned int libcfs_debug; extern unsigned int libcfs_printk; extern unsigned int libcfs_console_ratelimit; -extern unsigned int libcfs_watchdog_ratelimit; extern unsigned int libcfs_console_max_delay; extern unsigned int libcfs_console_min_delay; extern unsigned int libcfs_console_backoff; diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c index 98075529cc53..5ae7b6515189 100644 --- a/drivers/staging/lustre/lustre/libcfs/debug.c +++ b/drivers/staging/lustre/lustre/libcfs/debug.c @@ -128,9 +128,6 @@ EXPORT_SYMBOL(portal_enter_debugger); unsigned int libcfs_catastrophe; EXPORT_SYMBOL(libcfs_catastrophe); -unsigned int libcfs_watchdog_ratelimit = 300; -EXPORT_SYMBOL(libcfs_watchdog_ratelimit); - unsigned int libcfs_panic_on_lbug = 1; module_param(libcfs_panic_on_lbug, uint, 0644); MODULE_PARM_DESC(libcfs_panic_on_lbug, "Lustre kernel panic on LBUG"); diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index 95fa846095ee..8e228ae2c745 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -511,9 +511,6 @@ static int proc_dobitmasks(struct ctl_table *table, int write, __proc_dobitmasks); } -static int min_watchdog_ratelimit; /* disable ratelimiting */ -static int max_watchdog_ratelimit = (24*60*60); /* limit to once per day */ - static int __proc_dump_kernel(void *data, int write, loff_t pos, void __user *buffer, int nob) { @@ -797,15 +794,6 @@ static struct ctl_table lnet_table[] = { .mode = 0644, .proc_handler = &proc_debug_mb, }, - { - .procname = "watchdog_ratelimit", - .data = &libcfs_watchdog_ratelimit, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .extra1 = &min_watchdog_ratelimit, - .extra2 = &max_watchdog_ratelimit, - }, { .procname = "force_lbug", .data = NULL, -- cgit v1.3-6-gb490 From db07a4c968fb5045c382be493bd2bd3ba8412b3e Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Wed, 8 Jul 2015 13:34:36 +0000 Subject: staging: lustre: remove dead code This patch removes commented code. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/osc/osc_cache.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index 5592d32a1a95..c72035e048aa 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -1837,12 +1837,6 @@ static int try_to_add_extent_for_io(struct client_obd *cli, oap2 = list_first_entry(&tmp->oe_pages, struct osc_async_page, oap_pending_item); EASSERT(tmp->oe_owner == current, tmp); -#if 0 - if (overlapped(tmp, ext)) { - OSC_EXTENT_DUMP(D_ERROR, tmp, "overlapped %p.\n", ext); - EASSERT(0, ext); - } -#endif if (oap2cl_page(oap)->cp_type != oap2cl_page(oap2)->cp_type) { CDEBUG(D_CACHE, "Do not permit different type of IO" " for a same RPC\n"); -- cgit v1.3-6-gb490 From 9e0e332a7a4ac8a00ba06b536ecda8582b5a0814 Mon Sep 17 00:00:00 2001 From: Matt Mooney Date: Wed, 8 Jul 2015 09:21:11 -0700 Subject: staging: lustre: make ptlrpc_init static fix sparse warning in lustre/ptlrpc/ptlrpc_module.c:54:12: warning: symbol 'ptlrpc_init' was not declared. Should it be static? The __init macro is moved before the function name to match standard usage. Signed-off-by: Matt Mooney Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c index 5268887ca6b3..ae99180d6036 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpc_module.c @@ -51,7 +51,7 @@ extern spinlock_t ptlrpc_rs_debug_lock; extern struct mutex pinger_mutex; extern struct mutex ptlrpcd_mutex; -__init int ptlrpc_init(void) +static int __init ptlrpc_init(void) { int rc, cleanup_phase = 0; -- cgit v1.3-6-gb490 From 574150f0d275c4caf04156ecda6f9f988d6f5ffd Mon Sep 17 00:00:00 2001 From: Anders Fridlund Date: Thu, 9 Jul 2015 11:02:09 +0200 Subject: staging:lustre: fix "space required after that ', '" error in cl_page.c This is a patch to the cl_page.c file that fixes a "space required after that ','" error found by the checkpatch.pl tool. Signed-off-by: Anders Fridlund Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/cl_page.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index a7f3032f34dd..282ae734fba2 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -1425,7 +1425,7 @@ void cl_page_clip(const struct lu_env *env, struct cl_page *pg, CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", from, to); CL_PAGE_INVOID(env, pg, CL_PAGE_OP(cpo_clip), (const struct lu_env *, - const struct cl_page_slice *,int, int), + const struct cl_page_slice *, int, int), from, to); } EXPORT_SYMBOL(cl_page_clip); -- cgit v1.3-6-gb490 From 5d3d44729775998ad9efb47f2946378c764854a4 Mon Sep 17 00:00:00 2001 From: Kris Baumann Date: Thu, 9 Jul 2015 22:12:48 +0200 Subject: Staging: lustre: lustre: obdclass: genops: fixed brace coding style issues Fixed several brace coding style issues. Signed-off-by: Kris Baumann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/genops.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c index a42c9f9209c5..d36697d2c47f 100644 --- a/drivers/staging/lustre/lustre/obdclass/genops.c +++ b/drivers/staging/lustre/lustre/obdclass/genops.c @@ -71,9 +71,8 @@ static struct obd_device *obd_device_alloc(void) struct obd_device *obd; OBD_SLAB_ALLOC_PTR_GFP(obd, obd_device_cachep, GFP_NOFS); - if (obd != NULL) { + if (obd != NULL) obd->obd_magic = OBD_DEVICE_MAGIC; - } return obd; } @@ -294,7 +293,7 @@ struct obd_device *class_newdev(const char *type_name, const char *name) } type = class_get_type(type_name); - if (type == NULL){ + if (type == NULL) { CERROR("OBD: unknown type: %s\n", type_name); return ERR_PTR(-ENODEV); } @@ -999,7 +998,8 @@ void class_import_put(struct obd_import *imp) } EXPORT_SYMBOL(class_import_put); -static void init_imp_at(struct imp_at *at) { +static void init_imp_at(struct imp_at *at) +{ int i; at_init(&at->iat_net_latency, 0, 0); for (i = 0; i < IMP_AT_MAX_PORTALS; i++) { @@ -1642,7 +1642,8 @@ static int obd_zombie_impexp_check(void *arg) /** * Add export to the obd_zombie thread and notify it. */ -static void obd_zombie_export_add(struct obd_export *exp) { +static void obd_zombie_export_add(struct obd_export *exp) +{ spin_lock(&exp->exp_obd->obd_dev_lock); LASSERT(!list_empty(&exp->exp_obd_chain)); list_del_init(&exp->exp_obd_chain); @@ -1658,7 +1659,8 @@ static void obd_zombie_export_add(struct obd_export *exp) { /** * Add import to the obd_zombie thread and notify it. */ -static void obd_zombie_import_add(struct obd_import *imp) { +static void obd_zombie_import_add(struct obd_import *imp) +{ LASSERT(imp->imp_sec == NULL); LASSERT(imp->imp_rq_pool == NULL); spin_lock(&obd_zombie_impexp_lock); -- cgit v1.3-6-gb490 From 1b2d5577c507d35cc2ea205eba0b101003cc2fe9 Mon Sep 17 00:00:00 2001 From: Ronit Halder Date: Fri, 10 Jul 2015 23:05:39 +0530 Subject: Staging: lustre: fixed a blank line after declarations coding style issue Fixed a blank line after declarations coding style issue Signed-off-by: Ronit Halder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/lov/lov_merge.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/lov/lov_merge.c b/drivers/staging/lustre/lustre/lov/lov_merge.c index b7e7bfabe382..dd1cf3d2d039 100644 --- a/drivers/staging/lustre/lustre/lov/lov_merge.c +++ b/drivers/staging/lustre/lustre/lov/lov_merge.c @@ -123,6 +123,7 @@ int lov_adjust_kms(struct obd_export *exp, struct lov_stripe_md *lsm, if (shrink) { for (; stripe < lsm->lsm_stripe_count; stripe++) { struct lov_oinfo *loi = lsm->lsm_oinfo[stripe]; + kms = lov_size_to_stripe(lsm, size, stripe); CDEBUG(D_INODE, "stripe %d KMS %sing %llu->%llu\n", -- cgit v1.3-6-gb490 From 3e9f88e68801fe7f862d7ab57041a68f91ce9b5a Mon Sep 17 00:00:00 2001 From: Perry Hooker Date: Mon, 13 Jul 2015 17:33:47 -0600 Subject: staging: lustre: libcfs: move assignment out of conditional Found by checkpatch.pl Signed-off-by: Perry Hooker Signed-off-by: Greg Kroah-Hartman --- .../staging/lustre/include/linux/libcfs/libcfs_fail.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_fail.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_fail.h index eea55d94e6be..aa69c6a33d19 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_fail.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_fail.h @@ -79,14 +79,16 @@ static inline int cfs_fail_check_set(__u32 id, __u32 value, { int ret = 0; - if (unlikely(CFS_FAIL_PRECHECK(id) && - (ret = __cfs_fail_check_set(id, value, set)))) { - if (quiet) { - CDEBUG(D_INFO, "*** cfs_fail_loc=%x, val=%u***\n", - id, value); - } else { - LCONSOLE_INFO("*** cfs_fail_loc=%x, val=%u***\n", - id, value); + if (unlikely(CFS_FAIL_PRECHECK(id))) { + ret = __cfs_fail_check_set(id, value, set); + if (ret) { + if (quiet) { + CDEBUG(D_INFO, "*** cfs_fail_loc=%x, val=%u***\n", + id, value); + } else { + LCONSOLE_INFO("*** cfs_fail_loc=%x, val=%u***\n", + id, value); + } } } -- cgit v1.3-6-gb490 From 8dc08446d0671709bdec9e037845b014e33663b1 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 13 Jul 2015 23:17:54 -0400 Subject: staging/lustre/libcfs: get rid of debugfs/lnet/debug_mb It's just a fancy libcfs_debug_mb module parameter wrapper, so just add debug buffer size check and resizing and the same functionality now would be accessible via /sys/module/libcfs/parameters/libcfs_debug_mb Also add a symlink for backwards compatibility. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/debug.c | 40 ++++++++++++++++++++++-- drivers/staging/lustre/lustre/libcfs/module.c | 32 ++----------------- drivers/staging/lustre/lustre/libcfs/tracefile.c | 12 ------- drivers/staging/lustre/lustre/libcfs/tracefile.h | 1 - 4 files changed, 40 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c index 5ae7b6515189..995a1e3353ad 100644 --- a/drivers/staging/lustre/lustre/libcfs/debug.c +++ b/drivers/staging/lustre/lustre/libcfs/debug.c @@ -57,8 +57,42 @@ module_param(libcfs_debug, int, 0644); MODULE_PARM_DESC(libcfs_debug, "Lustre kernel debug mask"); EXPORT_SYMBOL(libcfs_debug); +static int libcfs_param_debug_mb_set(const char *val, + const struct kernel_param *kp) +{ + int rc; + unsigned num; + + rc = kstrtouint(val, 0, &num); + if (rc < 0) + return rc; + + if (!*((unsigned int *)kp->arg)) { + *((unsigned int *)kp->arg) = num; + return 0; + } + + rc = cfs_trace_set_debug_mb(num); + + if (!rc) + *((unsigned int *)kp->arg) = cfs_trace_get_debug_mb(); + + return rc; +} + +/* While debug_mb setting look like unsigned int, in fact + * it needs quite a bunch of extra processing, so we define special + * debugmb parameter type with corresponding methods to handle this case */ +static struct kernel_param_ops param_ops_debugmb = { + .set = libcfs_param_debug_mb_set, + .get = param_get_uint, +}; + +#define param_check_debugmb(name, p) \ + __param_check(name, p, unsigned int) + static unsigned int libcfs_debug_mb; -module_param(libcfs_debug_mb, uint, 0644); +module_param(libcfs_debug_mb, debugmb, 0644); MODULE_PARM_DESC(libcfs_debug_mb, "Total debug buffer size."); EXPORT_SYMBOL(libcfs_debug_mb); @@ -437,8 +471,10 @@ int libcfs_debug_init(unsigned long bufsize) } rc = cfs_tracefile_init(max); - if (rc == 0) + if (rc == 0) { libcfs_register_panic_notifier(); + libcfs_debug_mb = cfs_trace_get_debug_mb(); + } return rc; } diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index 8e228ae2c745..acfe7780ede8 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -550,31 +550,6 @@ static int proc_daemon_file(struct ctl_table *table, int write, __proc_daemon_file); } -static int __proc_debug_mb(void *data, int write, - loff_t pos, void __user *buffer, int nob) -{ - if (!write) { - char tmpstr[32]; - int len = snprintf(tmpstr, sizeof(tmpstr), "%d", - cfs_trace_get_debug_mb()); - - if (pos >= len) - return 0; - - return cfs_trace_copyout_string(buffer, nob, tmpstr + pos, - "\n"); - } - - return cfs_trace_set_debug_mb_usrstr(buffer, nob); -} - -static int proc_debug_mb(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return proc_call_handler(table->data, write, ppos, buffer, lenp, - __proc_debug_mb); -} - static int proc_console_max_delay_cs(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) @@ -789,11 +764,6 @@ static struct ctl_table lnet_table[] = { .maxlen = 256, .proc_handler = &proc_daemon_file, }, - { - .procname = "debug_mb", - .mode = 0644, - .proc_handler = &proc_debug_mb, - }, { .procname = "force_lbug", .data = NULL, @@ -833,6 +803,8 @@ struct lnet_debugfs_symlink_def lnet_debugfs_symlinks[] = { "/sys/module/libcfs/parameters/libcfs_panic_on_lbug"}, { "libcfs_console_backoff", "/sys/module/libcfs/parameters/libcfs_console_backoff"}, + { "debug_mb", + "/sys/module/libcfs/parameters/libcfs_debug_mb"}, {}, }; diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.c b/drivers/staging/lustre/lustre/libcfs/tracefile.c index 6ee2adcf8890..effa2af58c13 100644 --- a/drivers/staging/lustre/lustre/libcfs/tracefile.c +++ b/drivers/staging/lustre/lustre/libcfs/tracefile.c @@ -937,18 +937,6 @@ int cfs_trace_set_debug_mb(int mb) return 0; } -int cfs_trace_set_debug_mb_usrstr(void __user *usr_str, int usr_str_nob) -{ - char str[32]; - int rc; - - rc = cfs_trace_copyin_string(str, sizeof(str), usr_str, usr_str_nob); - if (rc < 0) - return rc; - - return cfs_trace_set_debug_mb(simple_strtoul(str, NULL, 0)); -} - int cfs_trace_get_debug_mb(void) { int i; diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.h b/drivers/staging/lustre/lustre/libcfs/tracefile.h index 0601476e1dc3..8d993f4d24c8 100644 --- a/drivers/staging/lustre/lustre/libcfs/tracefile.h +++ b/drivers/staging/lustre/lustre/libcfs/tracefile.h @@ -77,7 +77,6 @@ int cfs_trace_dump_debug_buffer_usrstr(void __user *usr_str, int usr_str_nob); int cfs_trace_daemon_command(char *str); int cfs_trace_daemon_command_usrstr(void __user *usr_str, int usr_str_nob); int cfs_trace_set_debug_mb(int mb); -int cfs_trace_set_debug_mb_usrstr(void __user *usr_str, int usr_str_nob); int cfs_trace_get_debug_mb(void); extern void libcfs_debug_dumplog_internal(void *arg); -- cgit v1.3-6-gb490 From 35ca907d245e8c218f39b6ed8bd6a1c656d056cc Mon Sep 17 00:00:00 2001 From: Dmitry Eremin Date: Mon, 13 Jul 2015 23:17:55 -0400 Subject: staging/lustre/libcfs: get rid of debugfs/lnet/console_{min, max}_delay_centisecs They are just fancy module parameters wrappers, so just the same functionality now would be accessible via /sys/module/libcfs/parameters/libcfs_console_{min,max}_delay Also install compatibility symlinks Signed-off-by: Dmitry Eremin Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/debug.c | 69 ++++++++++++++++++++-- drivers/staging/lustre/lustre/libcfs/module.c | 82 ++------------------------- 2 files changed, 68 insertions(+), 83 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c index 995a1e3353ad..1cc714caaba1 100644 --- a/drivers/staging/lustre/lustre/libcfs/debug.c +++ b/drivers/staging/lustre/lustre/libcfs/debug.c @@ -106,16 +106,75 @@ module_param(libcfs_console_ratelimit, uint, 0644); MODULE_PARM_DESC(libcfs_console_ratelimit, "Lustre kernel debug console ratelimit (0 to disable)"); EXPORT_SYMBOL(libcfs_console_ratelimit); +static int param_set_delay_minmax(const char *val, + const struct kernel_param *kp, + long min, long max) +{ + long d; + int sec; + int rc; + + rc = kstrtoint(val, 0, &sec); + if (rc) + return -EINVAL; + + d = cfs_time_seconds(sec) / 100; + if (d < min || d > max) + return -EINVAL; + + *((unsigned int *)kp->arg) = d; + + return 0; +} + +static int param_get_delay(char *buffer, const struct kernel_param *kp) +{ + unsigned int d = *(unsigned int *)kp->arg; + + return sprintf(buffer, "%u", (unsigned int)cfs_duration_sec(d * 100)); +} + unsigned int libcfs_console_max_delay; -module_param(libcfs_console_max_delay, uint, 0644); -MODULE_PARM_DESC(libcfs_console_max_delay, "Lustre kernel debug console max delay (jiffies)"); EXPORT_SYMBOL(libcfs_console_max_delay); - unsigned int libcfs_console_min_delay; -module_param(libcfs_console_min_delay, uint, 0644); -MODULE_PARM_DESC(libcfs_console_min_delay, "Lustre kernel debug console min delay (jiffies)"); EXPORT_SYMBOL(libcfs_console_min_delay); +static int param_set_console_max_delay(const char *val, + const struct kernel_param *kp) +{ + return param_set_delay_minmax(val, kp, + libcfs_console_min_delay, INT_MAX); +} + +static struct kernel_param_ops param_ops_console_max_delay = { + .set = param_set_console_max_delay, + .get = param_get_delay, +}; + +#define param_check_console_max_delay(name, p) \ + __param_check(name, p, unsigned int) + +module_param(libcfs_console_max_delay, console_max_delay, 0644); +MODULE_PARM_DESC(libcfs_console_max_delay, "Lustre kernel debug console max delay (jiffies)"); + +static int param_set_console_min_delay(const char *val, + const struct kernel_param *kp) +{ + return param_set_delay_minmax(val, kp, + 1, libcfs_console_max_delay); +} + +static struct kernel_param_ops param_ops_console_min_delay = { + .set = param_set_console_min_delay, + .get = param_get_delay, +}; + +#define param_check_console_min_delay(name, p) \ + __param_check(name, p, unsigned int) + +module_param(libcfs_console_min_delay, console_min_delay, 0644); +MODULE_PARM_DESC(libcfs_console_min_delay, "Lustre kernel debug console min delay (jiffies)"); + static int param_set_uint_minmax(const char *val, const struct kernel_param *kp, unsigned int min, unsigned int max) diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index acfe7780ede8..0ed26580f5ea 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -550,72 +550,6 @@ static int proc_daemon_file(struct ctl_table *table, int write, __proc_daemon_file); } -static int proc_console_max_delay_cs(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int rc, max_delay_cs; - struct ctl_table dummy = *table; - long d; - - dummy.data = &max_delay_cs; - dummy.proc_handler = &proc_dointvec; - - if (!write) { /* read */ - max_delay_cs = cfs_duration_sec(libcfs_console_max_delay * 100); - rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); - return rc; - } - - /* write */ - max_delay_cs = 0; - rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); - if (rc < 0) - return rc; - if (max_delay_cs <= 0) - return -EINVAL; - - d = cfs_time_seconds(max_delay_cs) / 100; - if (d == 0 || d < libcfs_console_min_delay) - return -EINVAL; - libcfs_console_max_delay = d; - - return rc; -} - -static int proc_console_min_delay_cs(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int rc, min_delay_cs; - struct ctl_table dummy = *table; - long d; - - dummy.data = &min_delay_cs; - dummy.proc_handler = &proc_dointvec; - - if (!write) { /* read */ - min_delay_cs = cfs_duration_sec(libcfs_console_min_delay * 100); - rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); - return rc; - } - - /* write */ - min_delay_cs = 0; - rc = proc_dointvec(&dummy, write, buffer, lenp, ppos); - if (rc < 0) - return rc; - if (min_delay_cs <= 0) - return -EINVAL; - - d = cfs_time_seconds(min_delay_cs) / 100; - if (d == 0 || d > libcfs_console_max_delay) - return -EINVAL; - libcfs_console_min_delay = d; - - return rc; -} - static int libcfs_force_lbug(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) @@ -712,18 +646,6 @@ static struct ctl_table lnet_table[] = { .mode = 0644, .proc_handler = &proc_dobitmasks, }, - { - .procname = "console_max_delay_centisecs", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_console_max_delay_cs - }, - { - .procname = "console_min_delay_centisecs", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_console_min_delay_cs - }, { .procname = "cpu_partition_table", .maxlen = 128, @@ -805,6 +727,10 @@ struct lnet_debugfs_symlink_def lnet_debugfs_symlinks[] = { "/sys/module/libcfs/parameters/libcfs_console_backoff"}, { "debug_mb", "/sys/module/libcfs/parameters/libcfs_debug_mb"}, + { "console_min_delay_centisecs", + "/sys/module/libcfs/parameters/libcfs_console_min_delay"}, + { "console_max_delay_centisecs", + "/sys/module/libcfs/parameters/libcfs_console_max_delay"}, {}, }; -- cgit v1.3-6-gb490 From 96d1865d344a966ab534fb16c55e8dd4601efb71 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin Date: Mon, 13 Jul 2015 23:17:56 -0400 Subject: staging/lustre/libcfs: remove unused portal_enter_debugger variable Remove portal_enter_debugger because it's not used any more. Signed-off-by: Dmitry Eremin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/debug.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c index 1cc714caaba1..63468870f230 100644 --- a/drivers/staging/lustre/lustre/libcfs/debug.c +++ b/drivers/staging/lustre/lustre/libcfs/debug.c @@ -215,9 +215,6 @@ EXPORT_SYMBOL(libcfs_debug_binary); unsigned int libcfs_stack = 3 * THREAD_SIZE / 4; EXPORT_SYMBOL(libcfs_stack); -static unsigned int portal_enter_debugger; -EXPORT_SYMBOL(portal_enter_debugger); - unsigned int libcfs_catastrophe; EXPORT_SYMBOL(libcfs_catastrophe); -- cgit v1.3-6-gb490 From aa66d6f87f300b15ac2efdcde9e198bf5a9020ce Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 13 Jul 2015 23:17:57 -0400 Subject: staging/lustre/libcfs: Fix kstrtouint return value check fix Apparently kstrtouint could return not just -EINVAL, but also -ERANGE, so make sure we just check the return value for something negative. Noticed by Dan Carpenter Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c index 63468870f230..e93f556fac0d 100644 --- a/drivers/staging/lustre/lustre/libcfs/debug.c +++ b/drivers/staging/lustre/lustre/libcfs/debug.c @@ -185,7 +185,7 @@ static int param_set_uint_minmax(const char *val, if (!val) return -EINVAL; ret = kstrtouint(val, 0, &num); - if (ret == -EINVAL || num < min || num > max) + if (ret < 0 || num < min || num > max) return -EINVAL; *((unsigned int *)kp->arg) = num; return 0; -- cgit v1.3-6-gb490 From 99e1dfb7d2094d9afc1dca57d525f7b36aa18079 Mon Sep 17 00:00:00 2001 From: Aravind Gopalakrishnan Date: Mon, 13 Jul 2015 06:53:02 -0500 Subject: EDAC, mce_amd: Don't emit 'CE' for Deferred error Currently, when decoding an MCE, we display 'CE' for a Deferred error, like this: [Hardware Error]: CPU:0 (15:2:0) MC4_STATUS[Over|CE|MiscV|-|AddrV|Deferred|-|UECC]: 0xdc04b00095080813 When the 'UC' bit in the MCx_STATUS register is clear, the error status is either a Corrected error or Deferred error as determined by the 'Deferred' bit. So do not print 'CE' on a deferred error. Refer to AMD Error Scope Hierarchy table in a newer BKDG (example: 49125_15h_Models_30h-3Fh_BKDG.pdf, section "RAS Features"). Signed-off-by: Aravind Gopalakrishnan Cc: Mauro Carvalho Chehab Cc: linux-edac Link: http://lkml.kernel.org/r/1436788382-6463-1-git-send-email-aravind.gopalakrishnan@amd.com Signed-off-by: Borislav Petkov --- drivers/edac/mce_amd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 58586d59bf8e..e3a945ce374b 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -763,7 +763,8 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) c->x86, c->x86_model, c->x86_mask, m->bank, ((m->status & MCI_STATUS_OVER) ? "Over" : "-"), - ((m->status & MCI_STATUS_UC) ? "UE" : "CE"), + ((m->status & MCI_STATUS_UC) ? "UE" : + (m->status & MCI_STATUS_DEFERRED) ? "-" : "CE"), ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"), ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"), ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-")); -- cgit v1.3-6-gb490 From 23ad69aafec5d3815fdbe59aea56ec4b59dcae60 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 8 Jul 2015 21:40:39 +0800 Subject: crypto: nx/842 - Fix context corruption The transform context is shared memory and must not be written to without locking. This patch adds locking to nx-842 to prevent context corruption. Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-crypto.c | 48 ++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-crypto.c b/drivers/crypto/nx/nx-842-crypto.c index d53a1dcd7b4e..3288a701c91b 100644 --- a/drivers/crypto/nx/nx-842-crypto.c +++ b/drivers/crypto/nx/nx-842-crypto.c @@ -60,6 +60,7 @@ #include #include #include +#include #include "nx-842.h" @@ -125,6 +126,8 @@ static int update_param(struct nx842_crypto_param *p, } struct nx842_crypto_ctx { + spinlock_t lock; + u8 *wmem; u8 *sbounce, *dbounce; @@ -136,6 +139,7 @@ static int nx842_crypto_init(struct crypto_tfm *tfm) { struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); + spin_lock_init(&ctx->lock); ctx->wmem = kmalloc(nx842_workmem_size(), GFP_KERNEL); ctx->sbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); @@ -315,6 +319,8 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm, DIV_ROUND_UP(p.iremain, c.maximum)); hdrsize = NX842_CRYPTO_HEADER_SIZE(groups); + spin_lock_bh(&ctx->lock); + /* skip adding header if the buffers meet all constraints */ add_header = (p.iremain % c.multiple || p.iremain < c.minimum || @@ -331,8 +337,9 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm, while (p.iremain > 0) { n = hdr->groups++; + ret = -ENOSPC; if (hdr->groups > NX842_CRYPTO_GROUP_MAX) - return -ENOSPC; + goto unlock; /* header goes before first group */ h = !n && add_header ? hdrsize : 0; @@ -342,12 +349,13 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm, ret = compress(ctx, &p, &hdr->group[n], &c, &ignore, h); if (ret) - return ret; + goto unlock; } if (!add_header && hdr->groups > 1) { pr_err("Internal error: No header but multiple groups\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } /* ignore indicates the input stream needed to be padded */ @@ -358,13 +366,15 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm, if (add_header) ret = nx842_crypto_add_header(hdr, dst); if (ret) - return ret; + goto unlock; *dlen = p.ototal; pr_debug("compress total slen %x dlen %x\n", slen, *dlen); - return 0; +unlock: + spin_unlock_bh(&ctx->lock); + return ret; } static int decompress(struct nx842_crypto_ctx *ctx, @@ -494,6 +504,8 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, hdr = (struct nx842_crypto_header *)src; + spin_lock_bh(&ctx->lock); + /* If it doesn't start with our header magic number, assume it's a raw * 842 compressed buffer and pass it directly to the hardware driver */ @@ -506,26 +518,31 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, ret = decompress(ctx, &p, &g, &c, 0, usehw); if (ret) - return ret; + goto unlock; *dlen = p.ototal; - return 0; + ret = 0; + goto unlock; } if (!hdr->groups) { pr_err("header has no groups\n"); - return -EINVAL; + ret = -EINVAL; + goto unlock; } if (hdr->groups > NX842_CRYPTO_GROUP_MAX) { pr_err("header has too many groups %x, max %x\n", hdr->groups, NX842_CRYPTO_GROUP_MAX); - return -EINVAL; + ret = -EINVAL; + goto unlock; } hdr_len = NX842_CRYPTO_HEADER_SIZE(hdr->groups); - if (hdr_len > slen) - return -EOVERFLOW; + if (hdr_len > slen) { + ret = -EOVERFLOW; + goto unlock; + } memcpy(&ctx->header, src, hdr_len); hdr = &ctx->header; @@ -537,14 +554,19 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, ret = decompress(ctx, &p, &hdr->group[n], &c, ignore, usehw); if (ret) - return ret; + goto unlock; } *dlen = p.ototal; pr_debug("decompress total slen %x dlen %x\n", slen, *dlen); - return 0; + ret = 0; + +unlock: + spin_unlock_bh(&ctx->lock); + + return ret; } static struct crypto_alg alg = { -- cgit v1.3-6-gb490 From c3d219495ed583a03ea10b5b30bccec398299cb7 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 9 Jul 2015 07:17:31 +0800 Subject: crypto: nx - Use new IV convention This patch converts rfc4106 to the new calling convention where the IV is now part of the AD and needs to be skipped. This patch also makes use of type-safe AEAD functions where possible. Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-aes-gcm.c | 66 +++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c index 92c993f08213..5719638b8642 100644 --- a/drivers/crypto/nx/nx-aes-gcm.c +++ b/drivers/crypto/nx/nx-aes-gcm.c @@ -21,11 +21,9 @@ #include #include -#include #include #include #include -#include #include #include "nx_csbcpb.h" @@ -36,7 +34,7 @@ static int gcm_aes_nx_set_key(struct crypto_aead *tfm, const u8 *in_key, unsigned int key_len) { - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base); + struct nx_crypto_ctx *nx_ctx = crypto_aead_ctx(tfm); struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead; @@ -75,7 +73,7 @@ static int gcm4106_aes_nx_set_key(struct crypto_aead *tfm, const u8 *in_key, unsigned int key_len) { - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base); + struct nx_crypto_ctx *nx_ctx = crypto_aead_ctx(tfm); char *nonce = nx_ctx->priv.gcm.nonce; int rc; @@ -110,13 +108,14 @@ static int gcm4106_aes_nx_setauthsize(struct crypto_aead *tfm, static int nx_gca(struct nx_crypto_ctx *nx_ctx, struct aead_request *req, - u8 *out) + u8 *out, + unsigned int assoclen) { int rc; struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead; struct scatter_walk walk; struct nx_sg *nx_sg = nx_ctx->in_sg; - unsigned int nbytes = req->assoclen; + unsigned int nbytes = assoclen; unsigned int processed = 0, to_process; unsigned int max_sg_len; @@ -167,7 +166,7 @@ static int nx_gca(struct nx_crypto_ctx *nx_ctx, NX_CPB_FDM(csbcpb_aead) |= NX_FDM_CONTINUATION; atomic_inc(&(nx_ctx->stats->aes_ops)); - atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes)); + atomic64_add(assoclen, &(nx_ctx->stats->aes_bytes)); processed += to_process; } while (processed < nbytes); @@ -177,13 +176,15 @@ static int nx_gca(struct nx_crypto_ctx *nx_ctx, return rc; } -static int gmac(struct aead_request *req, struct blkcipher_desc *desc) +static int gmac(struct aead_request *req, struct blkcipher_desc *desc, + unsigned int assoclen) { int rc; - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); + struct nx_crypto_ctx *nx_ctx = + crypto_aead_ctx(crypto_aead_reqtfm(req)); struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; struct nx_sg *nx_sg; - unsigned int nbytes = req->assoclen; + unsigned int nbytes = assoclen; unsigned int processed = 0, to_process; unsigned int max_sg_len; @@ -238,7 +239,7 @@ static int gmac(struct aead_request *req, struct blkcipher_desc *desc) NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION; atomic_inc(&(nx_ctx->stats->aes_ops)); - atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes)); + atomic64_add(assoclen, &(nx_ctx->stats->aes_bytes)); processed += to_process; } while (processed < nbytes); @@ -253,7 +254,8 @@ static int gcm_empty(struct aead_request *req, struct blkcipher_desc *desc, int enc) { int rc; - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); + struct nx_crypto_ctx *nx_ctx = + crypto_aead_ctx(crypto_aead_reqtfm(req)); struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; char out[AES_BLOCK_SIZE]; struct nx_sg *in_sg, *out_sg; @@ -314,9 +316,11 @@ out: return rc; } -static int gcm_aes_nx_crypt(struct aead_request *req, int enc) +static int gcm_aes_nx_crypt(struct aead_request *req, int enc, + unsigned int assoclen) { - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); + struct nx_crypto_ctx *nx_ctx = + crypto_aead_ctx(crypto_aead_reqtfm(req)); struct nx_gcm_rctx *rctx = aead_request_ctx(req); struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; struct blkcipher_desc desc; @@ -332,10 +336,10 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc) *(u32 *)(desc.info + NX_GCM_CTR_OFFSET) = 1; if (nbytes == 0) { - if (req->assoclen == 0) + if (assoclen == 0) rc = gcm_empty(req, &desc, enc); else - rc = gmac(req, &desc); + rc = gmac(req, &desc, assoclen); if (rc) goto out; else @@ -343,9 +347,10 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc) } /* Process associated data */ - csbcpb->cpb.aes_gcm.bit_length_aad = req->assoclen * 8; - if (req->assoclen) { - rc = nx_gca(nx_ctx, req, csbcpb->cpb.aes_gcm.in_pat_or_aad); + csbcpb->cpb.aes_gcm.bit_length_aad = assoclen * 8; + if (assoclen) { + rc = nx_gca(nx_ctx, req, csbcpb->cpb.aes_gcm.in_pat_or_aad, + assoclen); if (rc) goto out; } @@ -363,7 +368,6 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc) to_process = nbytes - processed; csbcpb->cpb.aes_gcm.bit_length_data = nbytes * 8; - desc.tfm = (struct crypto_blkcipher *) req->base.tfm; rc = nx_build_sg_lists(nx_ctx, &desc, req->dst, req->src, &to_process, processed + req->assoclen, @@ -430,7 +434,7 @@ static int gcm_aes_nx_encrypt(struct aead_request *req) memcpy(iv, req->iv, 12); - return gcm_aes_nx_crypt(req, 1); + return gcm_aes_nx_crypt(req, 1, req->assoclen); } static int gcm_aes_nx_decrypt(struct aead_request *req) @@ -440,12 +444,13 @@ static int gcm_aes_nx_decrypt(struct aead_request *req) memcpy(iv, req->iv, 12); - return gcm_aes_nx_crypt(req, 0); + return gcm_aes_nx_crypt(req, 0, req->assoclen); } static int gcm4106_aes_nx_encrypt(struct aead_request *req) { - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); + struct nx_crypto_ctx *nx_ctx = + crypto_aead_ctx(crypto_aead_reqtfm(req)); struct nx_gcm_rctx *rctx = aead_request_ctx(req); char *iv = rctx->iv; char *nonce = nx_ctx->priv.gcm.nonce; @@ -453,12 +458,16 @@ static int gcm4106_aes_nx_encrypt(struct aead_request *req) memcpy(iv, nonce, NX_GCM4106_NONCE_LEN); memcpy(iv + NX_GCM4106_NONCE_LEN, req->iv, 8); - return gcm_aes_nx_crypt(req, 1); + if (req->assoclen < 8) + return -EINVAL; + + return gcm_aes_nx_crypt(req, 1, req->assoclen - 8); } static int gcm4106_aes_nx_decrypt(struct aead_request *req) { - struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); + struct nx_crypto_ctx *nx_ctx = + crypto_aead_ctx(crypto_aead_reqtfm(req)); struct nx_gcm_rctx *rctx = aead_request_ctx(req); char *iv = rctx->iv; char *nonce = nx_ctx->priv.gcm.nonce; @@ -466,7 +475,10 @@ static int gcm4106_aes_nx_decrypt(struct aead_request *req) memcpy(iv, nonce, NX_GCM4106_NONCE_LEN); memcpy(iv + NX_GCM4106_NONCE_LEN, req->iv, 8); - return gcm_aes_nx_crypt(req, 0); + if (req->assoclen < 8) + return -EINVAL; + + return gcm_aes_nx_crypt(req, 0, req->assoclen - 8); } /* tell the block cipher walk routines that this is a stream cipher by @@ -478,6 +490,7 @@ struct aead_alg nx_gcm_aes_alg = { .base = { .cra_name = "gcm(aes)", .cra_driver_name = "gcm-aes-nx", + .cra_flags = CRYPTO_ALG_AEAD_NEW, .cra_priority = 300, .cra_blocksize = 1, .cra_ctxsize = sizeof(struct nx_crypto_ctx), @@ -496,6 +509,7 @@ struct aead_alg nx_gcm4106_aes_alg = { .base = { .cra_name = "rfc4106(gcm(aes))", .cra_driver_name = "rfc4106-gcm-aes-nx", + .cra_flags = CRYPTO_ALG_AEAD_NEW, .cra_priority = 300, .cra_blocksize = 1, .cra_ctxsize = sizeof(struct nx_crypto_ctx), -- cgit v1.3-6-gb490 From 46218750d5230abd86c2b054aa9b8cb74b23413e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 9 Jul 2015 07:17:33 +0800 Subject: crypto: caam - Use new IV convention This patch converts rfc4106 to the new calling convention where the IV is now part of the AD and needs to be skipped. Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 75 ++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index daca933a82ec..3c50a5082127 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -87,8 +87,8 @@ #define DESC_GCM_DEC_LEN (DESC_GCM_BASE + 12 * CAAM_CMD_SZ) #define DESC_RFC4106_BASE (3 * CAAM_CMD_SZ) -#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 10 * CAAM_CMD_SZ) -#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 10 * CAAM_CMD_SZ) +#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 12 * CAAM_CMD_SZ) +#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 12 * CAAM_CMD_SZ) #define DESC_RFC4543_BASE (3 * CAAM_CMD_SZ) #define DESC_RFC4543_ENC_LEN (DESC_RFC4543_BASE + 11 * CAAM_CMD_SZ) @@ -976,29 +976,32 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) append_operation(desc, ctx->class1_alg_type | OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8); append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - /* Skip assoc data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); - /* Read assoc data */ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - /* cryptlen = seqoutlen - assoclen */ - append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + /* Skip IV */ + append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); /* Will read cryptlen bytes */ append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - /* Write encrypted data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); - /* Read payload data */ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); + /* Skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); + + /* cryptlen = seqoutlen - assoclen */ + append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* Write encrypted data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); + /* Write ICV */ append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); @@ -1044,29 +1047,32 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) append_operation(desc, ctx->class1_alg_type | OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8); append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - /* Skip assoc data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); - /* Read assoc data */ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - /* Will write cryptlen bytes */ - append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); + /* Skip IV */ + append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); /* Will read cryptlen bytes */ - append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); - - /* Store payload data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); + append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG3, CAAM_CMD_SZ); /* Read encrypted data */ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); + /* Skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); + + /* Will write cryptlen bytes */ + append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); + + /* Store payload data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); + /* Read ICV */ append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); @@ -2685,6 +2691,14 @@ static int gcm_encrypt(struct aead_request *req) return ret; } +static int ipsec_gcm_encrypt(struct aead_request *req) +{ + if (req->assoclen < 8) + return -EINVAL; + + return gcm_encrypt(req); +} + static int old_aead_encrypt(struct aead_request *req) { struct aead_edesc *edesc; @@ -2757,6 +2771,14 @@ static int gcm_decrypt(struct aead_request *req) return ret; } +static int ipsec_gcm_decrypt(struct aead_request *req) +{ + if (req->assoclen < 8) + return -EINVAL; + + return gcm_decrypt(req); +} + static int old_aead_decrypt(struct aead_request *req) { struct aead_edesc *edesc; @@ -4058,8 +4080,8 @@ static struct caam_aead_alg driver_aeads[] = { }, .setkey = rfc4106_setkey, .setauthsize = rfc4106_setauthsize, - .encrypt = gcm_encrypt, - .decrypt = gcm_decrypt, + .encrypt = ipsec_gcm_encrypt, + .decrypt = ipsec_gcm_decrypt, .ivsize = 8, .maxauthsize = AES_BLOCK_SIZE, }, @@ -4076,8 +4098,8 @@ static struct caam_aead_alg driver_aeads[] = { }, .setkey = rfc4543_setkey, .setauthsize = rfc4543_setauthsize, - .encrypt = gcm_encrypt, - .decrypt = gcm_decrypt, + .encrypt = ipsec_gcm_encrypt, + .decrypt = ipsec_gcm_decrypt, .ivsize = 8, .maxauthsize = AES_BLOCK_SIZE, }, @@ -4260,7 +4282,8 @@ static void caam_aead_alg_init(struct caam_aead_alg *t_alg) alg->base.cra_module = THIS_MODULE; alg->base.cra_priority = CAAM_CRA_PRIORITY; alg->base.cra_ctxsize = sizeof(struct caam_ctx); - alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY; + alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_AEAD_NEW; alg->init = caam_aead_init; alg->exit = caam_aead_exit; -- cgit v1.3-6-gb490 From 1f644a7c7cd6a2c310312936d51cb56e6ac56f10 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:46:16 +0900 Subject: crypto: marvell/cesa - Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Acked-by: Boris Brezillon Signed-off-by: Herbert Xu --- drivers/crypto/marvell/cesa.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c index 1c6f98dd88f4..0643e3366e33 100644 --- a/drivers/crypto/marvell/cesa.c +++ b/drivers/crypto/marvell/cesa.c @@ -533,7 +533,6 @@ static struct platform_driver marvell_cesa = { .probe = mv_cesa_probe, .remove = mv_cesa_remove, .driver = { - .owner = THIS_MODULE, .name = "marvell-cesa", .of_match_table = mv_cesa_of_match_table, }, -- cgit v1.3-6-gb490 From 2d6f0600b2cd755959527230ef5a6fba97bb762a Mon Sep 17 00:00:00 2001 From: Leonidas Da Silva Barbosa Date: Mon, 13 Jul 2015 13:51:39 -0300 Subject: crypto: vmx - Adding enable_kernel_vsx() to access VSX instructions vmx-crypto driver make use of some VSX instructions which are only available if VSX is enabled. Running in cases where VSX are not enabled vmx-crypto fails in a VSX exception. In order to fix this enable_kernel_vsx() was added to turn on VSX instructions for vmx-crypto. Signed-off-by: Leonidas S. Barbosa Signed-off-by: Herbert Xu --- drivers/crypto/vmx/aes.c | 3 +++ drivers/crypto/vmx/aes_cbc.c | 3 +++ drivers/crypto/vmx/aes_ctr.c | 3 +++ drivers/crypto/vmx/ghash.c | 4 ++++ 4 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/crypto/vmx/aes.c b/drivers/crypto/vmx/aes.c index e79e567e43aa..263af709e536 100644 --- a/drivers/crypto/vmx/aes.c +++ b/drivers/crypto/vmx/aes.c @@ -84,6 +84,7 @@ static int p8_aes_setkey(struct crypto_tfm *tfm, const u8 *key, preempt_disable(); pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key); ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key); pagefault_enable(); @@ -103,6 +104,7 @@ static void p8_aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) preempt_disable(); pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); aes_p8_encrypt(src, dst, &ctx->enc_key); pagefault_enable(); preempt_enable(); @@ -119,6 +121,7 @@ static void p8_aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) preempt_disable(); pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); aes_p8_decrypt(src, dst, &ctx->dec_key); pagefault_enable(); preempt_enable(); diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index 7299995c78ec..0b8fe2ec5315 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c @@ -85,6 +85,7 @@ static int p8_aes_cbc_setkey(struct crypto_tfm *tfm, const u8 *key, preempt_disable(); pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key); ret += aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key); pagefault_enable(); @@ -115,6 +116,7 @@ static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc, preempt_disable(); pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); blkcipher_walk_init(&walk, dst, src, nbytes); ret = blkcipher_walk_virt(desc, &walk); @@ -155,6 +157,7 @@ static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc, preempt_disable(); pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); blkcipher_walk_init(&walk, dst, src, nbytes); ret = blkcipher_walk_virt(desc, &walk); diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c index 7adae42a7b79..1e754ae4e850 100644 --- a/drivers/crypto/vmx/aes_ctr.c +++ b/drivers/crypto/vmx/aes_ctr.c @@ -82,6 +82,7 @@ static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key, pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key); pagefault_enable(); @@ -100,6 +101,7 @@ static void p8_aes_ctr_final(struct p8_aes_ctr_ctx *ctx, pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); aes_p8_encrypt(ctrblk, keystream, &ctx->enc_key); pagefault_enable(); @@ -131,6 +133,7 @@ static int p8_aes_ctr_crypt(struct blkcipher_desc *desc, while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) { pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); aes_p8_ctr32_encrypt_blocks(walk.src.virt.addr, walk.dst.virt.addr, (nbytes & diff --git a/drivers/crypto/vmx/ghash.c b/drivers/crypto/vmx/ghash.c index b5e29002b666..2183a2e77641 100644 --- a/drivers/crypto/vmx/ghash.c +++ b/drivers/crypto/vmx/ghash.c @@ -119,6 +119,7 @@ static int p8_ghash_setkey(struct crypto_shash *tfm, const u8 *key, preempt_disable(); pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); enable_kernel_fp(); gcm_init_p8(ctx->htable, (const u64 *) key); pagefault_enable(); @@ -149,6 +150,7 @@ static int p8_ghash_update(struct shash_desc *desc, preempt_disable(); pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); enable_kernel_fp(); gcm_ghash_p8(dctx->shash, ctx->htable, dctx->buffer, GHASH_DIGEST_SIZE); @@ -163,6 +165,7 @@ static int p8_ghash_update(struct shash_desc *desc, preempt_disable(); pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); enable_kernel_fp(); gcm_ghash_p8(dctx->shash, ctx->htable, src, len); pagefault_enable(); @@ -193,6 +196,7 @@ static int p8_ghash_final(struct shash_desc *desc, u8 *out) preempt_disable(); pagefault_disable(); enable_kernel_altivec(); + enable_kernel_vsx(); enable_kernel_fp(); gcm_ghash_p8(dctx->shash, ctx->htable, dctx->buffer, GHASH_DIGEST_SIZE); -- cgit v1.3-6-gb490 From 787b4271a6a0c09775241770782b22762f40bd6e Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 10 Jul 2015 02:09:42 +0800 Subject: clk: imx: add imx6ul clk tree support Add imx6ul clock driver support. Signed-off-by: Anson Huang Signed-off-by: Bai Ping Signed-off-by: Fugang Duan Signed-off-by: Frank Li Signed-off-by: Shawn Guo --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx6ul.c | 432 +++++++++++++++++++++++++++++++ include/dt-bindings/clock/imx6ul-clock.h | 240 +++++++++++++++++ 3 files changed, 673 insertions(+) create mode 100644 drivers/clk/imx/clk-imx6ul.c create mode 100644 include/dt-bindings/clock/imx6ul-clock.h (limited to 'drivers') diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 75fae169ce8f..1ada68abb158 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -22,5 +22,6 @@ obj-$(CONFIG_SOC_IMX5) += clk-imx51-imx53.o obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o +obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c new file mode 100644 index 000000000000..aaa36650695f --- /dev/null +++ b/drivers/clk/imx/clk-imx6ul.c @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16) +#define CCDR 0x4 + +static const char *pll_bypass_src_sels[] = { "osc", "dummy", }; +static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", }; +static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", }; +static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", }; +static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", }; +static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", }; +static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", }; +static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", }; +static const char *ca7_secondary_sels[] = { "pll2_pfd2_396m", "pll2_bus", }; +static const char *step_sels[] = { "osc", "ca7_secondary_sel", }; +static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; +static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", }; +static const char *axi_sels[] = {"periph", "axi_alt_sel", }; +static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", }; +static const char *periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll4_audio_div", }; +static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", }; +static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", }; +static const char *periph_sels[] = { "periph_pre", "periph_clk2", }; +static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", }; +static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *bch_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *gpmi_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *eim_slow_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd0_720m", }; +static const char *spdif_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", }; +static const char *sai_sels[] = { "pll3_pfd2_508m", "pll5_video_div", "pll4_audio_div", }; +static const char *lcdif_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", }; +static const char *sim_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", }; +static const char *ldb_di0_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_pfd3_594m", "pll2_pfd1_594m", "pll3_pfd3_454m", }; +static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", }; +static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", }; +static const char *qspi1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", }; +static const char *enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", "pll3_pfd3_454m", "dummy", "dummy", "dummy", }; +static const char *can_sels[] = { "pll3_60m", "osc", "pll3_80m", "dummy", }; +static const char *ecspi_sels[] = { "pll3_60m", "osc", }; +static const char *uart_sels[] = { "pll3_80m", "osc", }; +static const char *perclk_sels[] = { "ipg", "osc", }; +static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; +static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; +static const char *sim_sels[] = { "sim_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", }; + +static struct clk *clks[IMX6UL_CLK_END]; +static struct clk_onecell_data clk_data; + +static int const clks_init_on[] __initconst = { + IMX6UL_CLK_AIPSTZ1, IMX6UL_CLK_AIPSTZ2, IMX6UL_CLK_AIPSTZ3, + IMX6UL_CLK_AXI, IMX6UL_CLK_ARM, IMX6UL_CLK_ROM, + IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG, +}; + +static struct clk_div_table clk_enet_ref_table[] = { + { .val = 0, .div = 20, }, + { .val = 1, .div = 10, }, + { .val = 2, .div = 5, }, + { .val = 3, .div = 4, }, + { } +}; + +static struct clk_div_table post_div_table[] = { + { .val = 2, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 4, }, + { } +}; + +static struct clk_div_table video_div_table[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 1, }, + { .val = 3, .div = 4, }, + { } +}; + +static u32 share_count_asrc; +static u32 share_count_audio; +static u32 share_count_sai1; +static u32 share_count_sai2; +static u32 share_count_sai3; + +static void __init imx6ul_clocks_init(struct device_node *ccm_node) +{ + struct device_node *np; + void __iomem *base; + int i; + + clks[IMX6UL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); + + clks[IMX6UL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil"); + clks[IMX6UL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc"); + + /* ipp_di clock is external input */ + clks[IMX6UL_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0"); + clks[IMX6UL_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1"); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop"); + base = of_iomap(np, 0); + WARN_ON(!base); + + clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + clks[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); + + clks[IMX6UL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f); + clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1); + clks[IMX6UL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3); + clks[IMX6UL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f); + clks[IMX6UL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f); + clks[IMX6UL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3); + clks[IMX6UL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3); + + clks[IMX6UL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6UL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6UL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6UL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6UL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6UL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6UL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT); + clks[IMX6UL_CLK_CSI_SEL] = imx_clk_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT); + + /* Do not bypass PLLs initially */ + clk_set_parent(clks[IMX6UL_PLL1_BYPASS], clks[IMX6UL_CLK_PLL1]); + clk_set_parent(clks[IMX6UL_PLL2_BYPASS], clks[IMX6UL_CLK_PLL2]); + clk_set_parent(clks[IMX6UL_PLL3_BYPASS], clks[IMX6UL_CLK_PLL3]); + clk_set_parent(clks[IMX6UL_PLL4_BYPASS], clks[IMX6UL_CLK_PLL4]); + clk_set_parent(clks[IMX6UL_PLL5_BYPASS], clks[IMX6UL_CLK_PLL5]); + clk_set_parent(clks[IMX6UL_PLL6_BYPASS], clks[IMX6UL_CLK_PLL6]); + clk_set_parent(clks[IMX6UL_PLL7_BYPASS], clks[IMX6UL_CLK_PLL7]); + + clks[IMX6UL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1); + clks[IMX6UL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13); + clks[IMX6UL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13); + clks[IMX6UL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13); + clks[IMX6UL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13); + clks[IMX6UL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13); + clks[IMX6UL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13); + + /* + * Bit 20 is the reserved and read-only bit, we do this only for: + * - Do nothing for usbphy clk_enable/disable + * - Keep refcount when do usbphy clk_enable/disable, in that case, + * the clk framework many need to enable/disable usbphy's parent + */ + clks[IMX6UL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20); + clks[IMX6UL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20); + + /* + * usbphy*_gate needs to be on after system boots up, and software + * never needs to control it anymore. + */ + clks[IMX6UL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6); + clks[IMX6UL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6); + + /* name parent_name reg idx */ + clks[IMX6UL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); + clks[IMX6UL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); + clks[IMX6UL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2); + clks[IMX6UL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3); + clks[IMX6UL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0); + clks[IMX6UL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1); + clks[IMX6UL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2); + clks[IMX6UL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3); + + clks[IMX6UL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0, + base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock); + clks[IMX6UL_CLK_ENET2_REF] = clk_register_divider_table(NULL, "enet2_ref", "pll6_enet", 0, + base + 0xe0, 2, 2, 0, clk_enet_ref_table, &imx_ccm_lock); + + clks[IMX6UL_CLK_ENET2_REF_125M] = imx_clk_gate("enet_ref_125m", "enet2_ref", base + 0xe0, 20); + clks[IMX6UL_CLK_ENET_PTP_REF] = imx_clk_fixed_factor("enet_ptp_ref", "pll6_enet", 1, 20); + clks[IMX6UL_CLK_ENET_PTP] = imx_clk_gate("enet_ptp", "enet_ptp_ref", base + 0xe0, 21); + + clks[IMX6UL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); + clks[IMX6UL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock); + clks[IMX6UL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); + clks[IMX6UL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); + + /* name parent_name mult div */ + clks[IMX6UL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2); + clks[IMX6UL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); + clks[IMX6UL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); + clks[IMX6UL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); + + np = ccm_node; + base = of_iomap(np, 0); + WARN_ON(!base); + + clks[IMX6UL_CA7_SECONDARY_SEL] = imx_clk_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels)); + clks[IMX6UL_CLK_STEP] = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels)); + clks[IMX6UL_CLK_PLL1_SW] = imx_clk_mux_flags("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0); + clks[IMX6UL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels)); + clks[IMX6UL_CLK_AXI_SEL] = imx_clk_mux_flags("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels), 0); + clks[IMX6UL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels)); + clks[IMX6UL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels)); + clks[IMX6UL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); + clks[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); + clks[IMX6UL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels)); + clks[IMX6UL_CLK_GPMI_SEL] = imx_clk_mux("gpmi_sel", base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels)); + clks[IMX6UL_CLK_BCH_SEL] = imx_clk_mux("bch_sel", base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels)); + clks[IMX6UL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6UL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); + clks[IMX6UL_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", base + 0x1c, 14, 2, sai_sels, ARRAY_SIZE(sai_sels)); + clks[IMX6UL_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", base + 0x1c, 12, 2, sai_sels, ARRAY_SIZE(sai_sels)); + clks[IMX6UL_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", base + 0x1c, 10, 2, sai_sels, ARRAY_SIZE(sai_sels)); + clks[IMX6UL_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels)); + clks[IMX6UL_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels)); + clks[IMX6UL_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels)); + clks[IMX6UL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); + clks[IMX6UL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels)); + clks[IMX6UL_CLK_LDB_DI0_SEL] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels)); + clks[IMX6UL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels)); + clks[IMX6UL_CLK_SIM_PRE_SEL] = imx_clk_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels)); + clks[IMX6UL_CLK_SIM_SEL] = imx_clk_mux("sim_sel", base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels)); + clks[IMX6UL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels)); + clks[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels)); + clks[IMX6UL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels)); + + clks[IMX6UL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels)); + clks[IMX6UL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels)); + + clks[IMX6UL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); + clks[IMX6UL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7); + clks[IMX6UL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "qspi1_sel", 2, 7); + clks[IMX6UL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "qspi1_sel", 1, 7); + + clks[IMX6UL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); + clks[IMX6UL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); + + clks[IMX6UL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); + clks[IMX6UL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); + clks[IMX6UL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); + clks[IMX6UL_CLK_LCDIF_PODF] = imx_clk_divider("lcdif_podf", "lcdif_pred", base + 0x18, 23, 3); + clks[IMX6UL_CLK_QSPI1_PDOF] = imx_clk_divider("qspi1_podf", "qspi1_sel", base + 0x1c, 26, 3); + clks[IMX6UL_CLK_EIM_SLOW_PODF] = imx_clk_divider("eim_slow_podf", "eim_slow_sel", base + 0x1c, 23, 3); + clks[IMX6UL_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6); + clks[IMX6UL_CLK_CAN_PODF] = imx_clk_divider("can_podf", "can_sel", base + 0x20, 2, 6); + clks[IMX6UL_CLK_GPMI_PODF] = imx_clk_divider("gpmi_podf", "gpmi_sel", base + 0x24, 22, 3); + clks[IMX6UL_CLK_BCH_PODF] = imx_clk_divider("bch_podf", "bch_sel", base + 0x24, 19, 3); + clks[IMX6UL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); + clks[IMX6UL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); + clks[IMX6UL_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6); + clks[IMX6UL_CLK_SAI3_PRED] = imx_clk_divider("sai3_pred", "sai3_sel", base + 0x28, 22, 3); + clks[IMX6UL_CLK_SAI3_PODF] = imx_clk_divider("sai3_podf", "sai3_pred", base + 0x28, 16, 6); + clks[IMX6UL_CLK_SAI1_PRED] = imx_clk_divider("sai1_pred", "sai1_sel", base + 0x28, 6, 3); + clks[IMX6UL_CLK_SAI1_PODF] = imx_clk_divider("sai1_podf", "sai1_pred", base + 0x28, 0, 6); + clks[IMX6UL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3); + clks[IMX6UL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6); + clks[IMX6UL_CLK_SAI2_PRED] = imx_clk_divider("sai2_pred", "sai2_sel", base + 0x2c, 6, 3); + clks[IMX6UL_CLK_SAI2_PODF] = imx_clk_divider("sai2_podf", "sai2_pred", base + 0x2c, 0, 6); + clks[IMX6UL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3); + clks[IMX6UL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3); + clks[IMX6UL_CLK_SIM_PODF] = imx_clk_divider("sim_podf", "sim_pre_sel", base + 0x34, 12, 3); + clks[IMX6UL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6); + clks[IMX6UL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3); + clks[IMX6UL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3); + + clks[IMX6UL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); + clks[IMX6UL_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2); + clks[IMX6UL_CLK_AXI_PODF] = imx_clk_busy_divider("axi_podf", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0); + clks[IMX6UL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); + + /* CCGR0 */ + clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0); + clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2); + clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4); + clks[IMX6UL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc); + clks[IMX6UL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc); + clks[IMX6UL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); + clks[IMX6UL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); + clks[IMX6UL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); + clks[IMX6UL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14); + clks[IMX6UL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16); + clks[IMX6UL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18); + clks[IMX6UL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20); + clks[IMX6UL_CLK_GPT2_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x68, 24); + clks[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x68, 26); + clks[IMX6UL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28); + clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28); + clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30); + + /* CCGR1 */ + clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); + clks[IMX6UL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2); + clks[IMX6UL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4); + clks[IMX6UL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6); + clks[IMX6UL_CLK_ADC2] = imx_clk_gate2("adc2", "ipg", base + 0x6c, 8); + clks[IMX6UL_CLK_UART3_IPG] = imx_clk_gate2("uart3_ipg", "ipg", base + 0x6c, 10); + clks[IMX6UL_CLK_UART3_SERIAL] = imx_clk_gate2("uart3_serial", "uart_podf", base + 0x6c, 10); + clks[IMX6UL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12); + clks[IMX6UL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14); + clks[IMX6UL_CLK_ADC1] = imx_clk_gate2("adc1", "ipg", base + 0x6c, 16); + clks[IMX6UL_CLK_GPT1_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20); + clks[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22); + clks[IMX6UL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24); + clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24); + + /* CCGR2 */ + clks[IMX6UL_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2); + clks[IMX6UL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6); + clks[IMX6UL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8); + clks[IMX6UL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); + clks[IMX6UL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); + clks[IMX6UL_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif_podf", base + 0x70, 14); + clks[IMX6UL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28); + clks[IMX6UL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30); + + /* CCGR3 */ + clks[IMX6UL_CLK_UART5_IPG] = imx_clk_gate2("uart5_ipg", "ipg", base + 0x74, 2); + clks[IMX6UL_CLK_UART5_SERIAL] = imx_clk_gate2("uart5_serial", "uart_podf", base + 0x74, 2); + clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4); + clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x74, 4); + clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6); + clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6); + clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10); + clks[IMX6UL_CLK_QSPI] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14); + clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); + clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20); + clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24); + clks[IMX6UL_CLK_AXI] = imx_clk_gate("axi", "axi_podf", base + 0x74, 28); + + /* CCGR4 */ + clks[IMX6UL_CLK_PER_BCH] = imx_clk_gate2("per_bch", "bch_podf", base + 0x78, 12); + clks[IMX6UL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16); + clks[IMX6UL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18); + clks[IMX6UL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20); + clks[IMX6UL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22); + clks[IMX6UL_CLK_GPMI_BCH_APB] = imx_clk_gate2("gpmi_bch_apb", "bch_podf", base + 0x78, 24); + clks[IMX6UL_CLK_GPMI_BCH] = imx_clk_gate2("gpmi_bch", "gpmi_podf", base + 0x78, 26); + clks[IMX6UL_CLK_GPMI_IO] = imx_clk_gate2("gpmi_io", "enfc_podf", base + 0x78, 28); + clks[IMX6UL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "bch_podf", base + 0x78, 30); + + /* CCGR5 */ + clks[IMX6UL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); + clks[IMX6UL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); + clks[IMX6UL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10); + clks[IMX6UL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); + clks[IMX6UL_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio); + clks[IMX6UL_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio); + clks[IMX6UL_CLK_SAI3] = imx_clk_gate2_shared("sai3", "sai3_podf", base + 0x7c, 22, &share_count_sai3); + clks[IMX6UL_CLK_SAI3_IPG] = imx_clk_gate2_shared("sai3_ipg", "ipg", base + 0x7c, 22, &share_count_sai3); + clks[IMX6UL_CLK_UART1_IPG] = imx_clk_gate2("uart1_ipg", "ipg", base + 0x7c, 24); + clks[IMX6UL_CLK_UART1_SERIAL] = imx_clk_gate2("uart1_serial", "uart_podf", base + 0x7c, 24); + clks[IMX6UL_CLK_UART7_IPG] = imx_clk_gate2("uart7_ipg", "ipg", base + 0x7c, 26); + clks[IMX6UL_CLK_UART7_SERIAL] = imx_clk_gate2("uart7_serial", "uart_podf", base + 0x7c, 26); + clks[IMX6UL_CLK_SAI1] = imx_clk_gate2_shared("sai1", "sai1_podf", base + 0x7c, 28, &share_count_sai1); + clks[IMX6UL_CLK_SAI1_IPG] = imx_clk_gate2_shared("sai1_ipg", "ipg", base + 0x7c, 28, &share_count_sai1); + clks[IMX6UL_CLK_SAI2] = imx_clk_gate2_shared("sai2", "sai2_podf", base + 0x7c, 30, &share_count_sai2); + clks[IMX6UL_CLK_SAI2_IPG] = imx_clk_gate2_shared("sai2_ipg", "ipg", base + 0x7c, 30, &share_count_sai2); + + /* CCGR6 */ + clks[IMX6UL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); + clks[IMX6UL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); + clks[IMX6UL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); + clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1", "sim_sel", base + 0x80, 6); + clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2", "sim_sel", base + 0x80, 8); + clks[IMX6UL_CLK_EIM] = imx_clk_gate2("eim", "eim_slow_podf", base + 0x80, 10); + clks[IMX6UL_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16); + clks[IMX6UL_CLK_UART8_IPG] = imx_clk_gate2("uart8_ipg", "ipg", base + 0x80, 14); + clks[IMX6UL_CLK_UART8_SERIAL] = imx_clk_gate2("uart8_serial", "uart_podf", base + 0x80, 14); + clks[IMX6UL_CLK_WDOG3] = imx_clk_gate2("wdog3", "ipg", base + 0x80, 20); + clks[IMX6UL_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24); + clks[IMX6UL_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26); + clks[IMX6UL_CLK_PWM6] = imx_clk_gate2("pwm6", "perclk", base + 0x80, 28); + clks[IMX6UL_CLK_PWM7] = imx_clk_gate2("Pwm7", "perclk", base + 0x80, 30); + + /* mask handshake of mmdc */ + writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR); + + for (i = 0; i < ARRAY_SIZE(clks); i++) + if (IS_ERR(clks[i])) + pr_err("i.MX6UL clk %d: register failed with %ld\n", i, PTR_ERR(clks[i])); + + clk_data.clks = clks; + clk_data.clk_num = ARRAY_SIZE(clks); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + /* set perclk to from OSC */ + clk_set_parent(clks[IMX6UL_CLK_PERCLK_SEL], clks[IMX6UL_CLK_OSC]); + + clk_set_rate(clks[IMX6UL_CLK_ENET_REF], 50000000); + clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000); + clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000); + + /* keep all the clks on just for bringup */ + for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) + clk_prepare_enable(clks[clks_init_on[i]]); + + if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { + clk_prepare_enable(clks[IMX6UL_CLK_USBPHY1_GATE]); + clk_prepare_enable(clks[IMX6UL_CLK_USBPHY2_GATE]); + } + + clk_set_parent(clks[IMX6UL_CLK_CAN_SEL], clks[IMX6UL_CLK_PLL3_60M]); + clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]); + + clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]); +} + +CLK_OF_DECLARE(imx6ul, "fsl,imx6ul-ccm", imx6ul_clocks_init); diff --git a/include/dt-bindings/clock/imx6ul-clock.h b/include/dt-bindings/clock/imx6ul-clock.h new file mode 100644 index 000000000000..c343894ce603 --- /dev/null +++ b/include/dt-bindings/clock/imx6ul-clock.h @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2015 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 __DT_BINDINGS_CLOCK_IMX6UL_H +#define __DT_BINDINGS_CLOCK_IMX6UL_H + +#define IMX6UL_CLK_DUMMY 0 +#define IMX6UL_CLK_CKIL 1 +#define IMX6UL_CLK_CKIH 2 +#define IMX6UL_CLK_OSC 3 +#define IMX6UL_PLL1_BYPASS_SRC 4 +#define IMX6UL_PLL2_BYPASS_SRC 5 +#define IMX6UL_PLL3_BYPASS_SRC 6 +#define IMX6UL_PLL4_BYPASS_SRC 7 +#define IMX6UL_PLL5_BYPASS_SRC 8 +#define IMX6UL_PLL6_BYPASS_SRC 9 +#define IMX6UL_PLL7_BYPASS_SRC 10 +#define IMX6UL_CLK_PLL1 11 +#define IMX6UL_CLK_PLL2 12 +#define IMX6UL_CLK_PLL3 13 +#define IMX6UL_CLK_PLL4 14 +#define IMX6UL_CLK_PLL5 15 +#define IMX6UL_CLK_PLL6 16 +#define IMX6UL_CLK_PLL7 17 +#define IMX6UL_PLL1_BYPASS 18 +#define IMX6UL_PLL2_BYPASS 19 +#define IMX6UL_PLL3_BYPASS 20 +#define IMX6UL_PLL4_BYPASS 21 +#define IMX6UL_PLL5_BYPASS 22 +#define IMX6UL_PLL6_BYPASS 23 +#define IMX6UL_PLL7_BYPASS 24 +#define IMX6UL_CLK_PLL1_SYS 25 +#define IMX6UL_CLK_PLL2_BUS 26 +#define IMX6UL_CLK_PLL3_USB_OTG 27 +#define IMX6UL_CLK_PLL4_AUDIO 28 +#define IMX6UL_CLK_PLL5_VIDEO 29 +#define IMX6UL_CLK_PLL6_ENET 30 +#define IMX6UL_CLK_PLL7_USB_HOST 31 +#define IMX6UL_CLK_USBPHY1 32 +#define IMX6UL_CLK_USBPHY2 33 +#define IMX6UL_CLK_USBPHY1_GATE 34 +#define IMX6UL_CLK_USBPHY2_GATE 35 +#define IMX6UL_CLK_PLL2_PFD0 36 +#define IMX6UL_CLK_PLL2_PFD1 37 +#define IMX6UL_CLK_PLL2_PFD2 38 +#define IMX6UL_CLK_PLL2_PFD3 39 +#define IMX6UL_CLK_PLL3_PFD0 40 +#define IMX6UL_CLK_PLL3_PFD1 41 +#define IMX6UL_CLK_PLL3_PFD2 42 +#define IMX6UL_CLK_PLL3_PFD3 43 +#define IMX6UL_CLK_ENET_REF 44 +#define IMX6UL_CLK_ENET2_REF 45 +#define IMX6UL_CLK_ENET2_REF_125M 46 +#define IMX6UL_CLK_ENET_PTP_REF 47 +#define IMX6UL_CLK_ENET_PTP 48 +#define IMX6UL_CLK_PLL4_POST_DIV 49 +#define IMX6UL_CLK_PLL4_AUDIO_DIV 50 +#define IMX6UL_CLK_PLL5_POST_DIV 51 +#define IMX6UL_CLK_PLL5_VIDEO_DIV 52 +#define IMX6UL_CLK_PLL2_198M 53 +#define IMX6UL_CLK_PLL3_80M 54 +#define IMX6UL_CLK_PLL3_60M 55 +#define IMX6UL_CLK_STEP 56 +#define IMX6UL_CLK_PLL1_SW 57 +#define IMX6UL_CLK_AXI_ALT_SEL 58 +#define IMX6UL_CLK_AXI_SEL 59 +#define IMX6UL_CLK_PERIPH_PRE 60 +#define IMX6UL_CLK_PERIPH2_PRE 61 +#define IMX6UL_CLK_PERIPH_CLK2_SEL 62 +#define IMX6UL_CLK_PERIPH2_CLK2_SEL 63 +#define IMX6UL_CLK_USDHC1_SEL 64 +#define IMX6UL_CLK_USDHC2_SEL 65 +#define IMX6UL_CLK_BCH_SEL 66 +#define IMX6UL_CLK_GPMI_SEL 67 +#define IMX6UL_CLK_EIM_SLOW_SEL 68 +#define IMX6UL_CLK_SPDIF_SEL 69 +#define IMX6UL_CLK_SAI1_SEL 70 +#define IMX6UL_CLK_SAI2_SEL 71 +#define IMX6UL_CLK_SAI3_SEL 72 +#define IMX6UL_CLK_LCDIF_PRE_SEL 73 +#define IMX6UL_CLK_SIM_PRE_SEL 74 +#define IMX6UL_CLK_LDB_DI0_SEL 75 +#define IMX6UL_CLK_LDB_DI1_SEL 76 +#define IMX6UL_CLK_ENFC_SEL 77 +#define IMX6UL_CLK_CAN_SEL 78 +#define IMX6UL_CLK_ECSPI_SEL 79 +#define IMX6UL_CLK_UART_SEL 80 +#define IMX6UL_CLK_QSPI1_SEL 81 +#define IMX6UL_CLK_PERCLK_SEL 82 +#define IMX6UL_CLK_LCDIF_SEL 83 +#define IMX6UL_CLK_SIM_SEL 84 +#define IMX6UL_CLK_PERIPH 85 +#define IMX6UL_CLK_PERIPH2 86 +#define IMX6UL_CLK_LDB_DI0_DIV_3_5 87 +#define IMX6UL_CLK_LDB_DI0_DIV_7 88 +#define IMX6UL_CLK_LDB_DI1_DIV_3_5 89 +#define IMX6UL_CLK_LDB_DI1_DIV_7 90 +#define IMX6UL_CLK_LDB_DI0_DIV_SEL 91 +#define IMX6UL_CLK_LDB_DI1_DIV_SEL 92 +#define IMX6UL_CLK_ARM 93 +#define IMX6UL_CLK_PERIPH_CLK2 94 +#define IMX6UL_CLK_PERIPH2_CLK2 95 +#define IMX6UL_CLK_AHB 96 +#define IMX6UL_CLK_MMDC_PODF 97 +#define IMX6UL_CLK_AXI_PODF 98 +#define IMX6UL_CLK_PERCLK 99 +#define IMX6UL_CLK_IPG 100 +#define IMX6UL_CLK_USDHC1_PODF 101 +#define IMX6UL_CLK_USDHC2_PODF 102 +#define IMX6UL_CLK_BCH_PODF 103 +#define IMX6UL_CLK_GPMI_PODF 104 +#define IMX6UL_CLK_EIM_SLOW_PODF 105 +#define IMX6UL_CLK_SPDIF_PRED 106 +#define IMX6UL_CLK_SPDIF_PODF 107 +#define IMX6UL_CLK_SAI1_PRED 108 +#define IMX6UL_CLK_SAI1_PODF 109 +#define IMX6UL_CLK_SAI2_PRED 110 +#define IMX6UL_CLK_SAI2_PODF 111 +#define IMX6UL_CLK_SAI3_PRED 112 +#define IMX6UL_CLK_SAI3_PODF 113 +#define IMX6UL_CLK_LCDIF_PRED 114 +#define IMX6UL_CLK_LCDIF_PODF 115 +#define IMX6UL_CLK_SIM_PODF 116 +#define IMX6UL_CLK_QSPI1_PDOF 117 +#define IMX6UL_CLK_ENFC_PRED 118 +#define IMX6UL_CLK_ENFC_PODF 119 +#define IMX6UL_CLK_CAN_PODF 120 +#define IMX6UL_CLK_ECSPI_PODF 121 +#define IMX6UL_CLK_UART_PODF 122 +#define IMX6UL_CLK_ADC1 123 +#define IMX6UL_CLK_ADC2 124 +#define IMX6UL_CLK_AIPSTZ1 125 +#define IMX6UL_CLK_AIPSTZ2 126 +#define IMX6UL_CLK_AIPSTZ3 127 +#define IMX6UL_CLK_APBHDMA 128 +#define IMX6UL_CLK_ASRC_IPG 129 +#define IMX6UL_CLK_ASRC_MEM 130 +#define IMX6UL_CLK_GPMI_BCH_APB 131 +#define IMX6UL_CLK_GPMI_BCH 132 +#define IMX6UL_CLK_GPMI_IO 133 +#define IMX6UL_CLK_GPMI_APB 134 +#define IMX6UL_CLK_CAAM_MEM 135 +#define IMX6UL_CLK_CAAM_ACLK 136 +#define IMX6UL_CLK_CAAM_IPG 137 +#define IMX6UL_CLK_CSI 138 +#define IMX6UL_CLK_ECSPI1 139 +#define IMX6UL_CLK_ECSPI2 140 +#define IMX6UL_CLK_ECSPI3 141 +#define IMX6UL_CLK_ECSPI4 142 +#define IMX6UL_CLK_EIM 143 +#define IMX6UL_CLK_ENET 144 +#define IMX6UL_CLK_ENET_AHB 145 +#define IMX6UL_CLK_EPIT1 146 +#define IMX6UL_CLK_EPIT2 147 +#define IMX6UL_CLK_CAN1_IPG 148 +#define IMX6UL_CLK_CAN1_SERIAL 149 +#define IMX6UL_CLK_CAN2_IPG 150 +#define IMX6UL_CLK_CAN2_SERIAL 151 +#define IMX6UL_CLK_GPT1_BUS 152 +#define IMX6UL_CLK_GPT1_SERIAL 153 +#define IMX6UL_CLK_GPT2_BUS 154 +#define IMX6UL_CLK_GPT2_SERIAL 155 +#define IMX6UL_CLK_I2C1 156 +#define IMX6UL_CLK_I2C2 157 +#define IMX6UL_CLK_I2C3 158 +#define IMX6UL_CLK_I2C4 159 +#define IMX6UL_CLK_IOMUXC 160 +#define IMX6UL_CLK_LCDIF_APB 161 +#define IMX6UL_CLK_LCDIF_PIX 162 +#define IMX6UL_CLK_MMDC_P0_FAST 163 +#define IMX6UL_CLK_MMDC_P0_IPG 164 +#define IMX6UL_CLK_OCOTP 165 +#define IMX6UL_CLK_OCRAM 166 +#define IMX6UL_CLK_PWM1 167 +#define IMX6UL_CLK_PWM2 168 +#define IMX6UL_CLK_PWM3 169 +#define IMX6UL_CLK_PWM4 170 +#define IMX6UL_CLK_PWM5 171 +#define IMX6UL_CLK_PWM6 172 +#define IMX6UL_CLK_PWM7 173 +#define IMX6UL_CLK_PWM8 174 +#define IMX6UL_CLK_PXP 175 +#define IMX6UL_CLK_QSPI 176 +#define IMX6UL_CLK_ROM 177 +#define IMX6UL_CLK_SAI1 178 +#define IMX6UL_CLK_SAI1_IPG 179 +#define IMX6UL_CLK_SAI2 180 +#define IMX6UL_CLK_SAI2_IPG 181 +#define IMX6UL_CLK_SAI3 182 +#define IMX6UL_CLK_SAI3_IPG 183 +#define IMX6UL_CLK_SDMA 184 +#define IMX6UL_CLK_SIM 185 +#define IMX6UL_CLK_SIM_S 186 +#define IMX6UL_CLK_SPBA 187 +#define IMX6UL_CLK_SPDIF 188 +#define IMX6UL_CLK_UART1_IPG 189 +#define IMX6UL_CLK_UART1_SERIAL 190 +#define IMX6UL_CLK_UART2_IPG 191 +#define IMX6UL_CLK_UART2_SERIAL 192 +#define IMX6UL_CLK_UART3_IPG 193 +#define IMX6UL_CLK_UART3_SERIAL 194 +#define IMX6UL_CLK_UART4_IPG 195 +#define IMX6UL_CLK_UART4_SERIAL 196 +#define IMX6UL_CLK_UART5_IPG 197 +#define IMX6UL_CLK_UART5_SERIAL 198 +#define IMX6UL_CLK_UART6_IPG 199 +#define IMX6UL_CLK_UART6_SERIAL 200 +#define IMX6UL_CLK_UART7_IPG 201 +#define IMX6UL_CLK_UART7_SERIAL 202 +#define IMX6UL_CLK_UART8_IPG 203 +#define IMX6UL_CLK_UART8_SERIAL 204 +#define IMX6UL_CLK_USBOH3 205 +#define IMX6UL_CLK_USDHC1 206 +#define IMX6UL_CLK_USDHC2 207 +#define IMX6UL_CLK_WDOG1 208 +#define IMX6UL_CLK_WDOG2 209 +#define IMX6UL_CLK_WDOG3 210 +#define IMX6UL_CLK_LDB_DI0 211 +#define IMX6UL_CLK_AXI 212 +#define IMX6UL_CLK_SPDIF_GCLK 213 +#define IMX6UL_CLK_GPT_3M 214 +#define IMX6UL_CLK_SIM2 215 +#define IMX6UL_CLK_SIM1 216 +#define IMX6UL_CLK_IPP_DI0 217 +#define IMX6UL_CLK_IPP_DI1 218 +#define IMX6UL_CA7_SECONDARY_SEL 219 +#define IMX6UL_CLK_PER_BCH 220 +#define IMX6UL_CLK_CSI_SEL 221 +#define IMX6UL_CLK_CSI_PODF 222 +#define IMX6UL_CLK_PLL3_120M 223 + +#define IMX6UL_CLK_END 224 + +#endif /* __DT_BINDINGS_CLOCK_IMX6UL_H */ -- cgit v1.3-6-gb490 From cc017fb4d7a3308725afc02af9fd84a171e6e028 Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:21 +0530 Subject: drm/i915/skl: Restrict the ring frequency table programming to SKL Ring frequency table programming is not required on BXT. Added separate checks to enable the programming only for SKL & skip for BXT. v2: Removed the BXT check from gen6_update_ring_freq function Issue: VIZ-5144 Signed-off-by: Akash Goel Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 135fb974dfff..f2be1cedb52f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6219,7 +6219,8 @@ static void intel_gen6_powersave_work(struct work_struct *work) } else if (INTEL_INFO(dev)->gen >= 9) { gen9_enable_rc6(dev); gen9_enable_rps(dev); - __gen6_update_ring_freq(dev); + if (IS_SKYLAKE(dev)) + __gen6_update_ring_freq(dev); } else if (IS_BROADWELL(dev)) { gen8_enable_rps(dev); __gen6_update_ring_freq(dev); -- cgit v1.3-6-gb490 From 05379818e489bd9fec892f79f202b2ff41fd6ff8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:46 +0200 Subject: gpio/mpc8xxx: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-mpc8xxx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 20aa66f34f6e..da8e89205f37 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -396,8 +396,8 @@ static int mpc8xxx_probe(struct platform_device *pdev) out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); out_be32(mm_gc->regs + GPIO_IMR, 0); - irq_set_handler_data(mpc8xxx_gc->irqn, mpc8xxx_gc); - irq_set_chained_handler(mpc8xxx_gc->irqn, mpc8xxx_gpio_irq_cascade); + irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, + mpc8xxx_gpio_irq_cascade, mpc8xxx_gc); return 0; } @@ -407,8 +407,7 @@ static int mpc8xxx_remove(struct platform_device *pdev) struct mpc8xxx_gpio_chip *mpc8xxx_gc = platform_get_drvdata(pdev); if (mpc8xxx_gc->irq) { - irq_set_handler_data(mpc8xxx_gc->irqn, NULL); - irq_set_chained_handler(mpc8xxx_gc->irqn, NULL); + irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, NULL, NULL); irq_domain_remove(mpc8xxx_gc->irq); } -- cgit v1.3-6-gb490 From d68cd06ce40d7227598912bb1a0c75980d2b5a4b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:47 +0200 Subject: gpio/mvebu: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-mvebu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 1a54205860f5..ab660e44a672 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -787,8 +787,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) if (irq < 0) continue; - irq_set_handler_data(irq, mvchip); - irq_set_chained_handler(irq, mvebu_gpio_irq_handler); + irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler, + mvchip); } mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1); -- cgit v1.3-6-gb490 From 8a52211ad8d8c97fede3707c938126002e11ec79 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:47 +0200 Subject: gpio/timberdale: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-timberdale.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index e8f97e03c9bb..fd1970ed15e6 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -299,8 +299,7 @@ static int timbgpio_probe(struct platform_device *pdev) #endif } - irq_set_handler_data(irq, tgpio); - irq_set_chained_handler(irq, timbgpio_irq); + irq_set_chained_handler_and_data(irq, timbgpio_irq, tgpio); return 0; } -- cgit v1.3-6-gb490 From 77c77e3f074f576a39534bb9b10b6f1b4d91a8db Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:48 +0200 Subject: gpio/tz1090: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-tz1090.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index 445660adc898..bbac92ae4c32 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -510,8 +510,8 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND; /* Setup chained handler for this GPIO bank */ - irq_set_handler_data(bank->irq, bank); - irq_set_chained_handler(bank->irq, tz1090_gpio_irq_handler); + irq_set_chained_handler_and_data(bank->irq, tz1090_gpio_irq_handler, + bank); return 0; } -- cgit v1.3-6-gb490 From f7f877533c11029e4b4caf8aae9968c5fd561625 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:48 +0200 Subject: gpiolib: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpiolib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bf4bd1d120c3..78a738bca53f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -443,8 +443,8 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, * The parent irqchip is already using the chip_data for this * irqchip, so our callbacks simply use the handler_data. */ - irq_set_handler_data(parent_irq, gpiochip); - irq_set_chained_handler(parent_irq, parent_handler); + irq_set_chained_handler_and_data(parent_irq, parent_handler, + gpiochip); gpiochip->irq_parent = parent_irq; } -- cgit v1.3-6-gb490 From 47c08462921f17de890c2574b2893ecae44cfd76 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 14:37:42 +0200 Subject: gpio/zynq: Use irq_set_chip_handler_name_locked() Hand in irq_data and avoid the redundant lookup of irq_desc. Originally-from: Jiang Liu Signed-off-by: Thomas Gleixner --- drivers/gpio/gpio-zynq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 2e87c4b8da26..53b297473724 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -441,10 +441,10 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); if (type & IRQ_TYPE_LEVEL_MASK) { - __irq_set_chip_handler_name_locked(irq_data->irq, + irq_set_chip_handler_name_locked(irq_data, &zynq_gpio_level_irqchip, handle_fasteoi_irq, NULL); } else { - __irq_set_chip_handler_name_locked(irq_data->irq, + irq_set_chip_handler_name_locked(irq_data, &zynq_gpio_edge_irqchip, handle_level_irq, NULL); } -- cgit v1.3-6-gb490 From 72b2a9ef9c5fffe274cca0be63a4f3998fa0b641 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:38 +0200 Subject: gpio/ep93xx: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: @@ struct irq_data *d; expression E1; @@ -__irq_set_handler_locked(d->irq, E1); +irq_set_handler_locked(d, E1); Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-ep93xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 45684f36ddb1..8664cf041b1f 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -208,7 +208,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) return -EINVAL; } - __irq_set_handler_locked(d->irq, handler); + irq_set_handler_locked(d, handler); gpio_int_enabled[port] |= port_mask; -- cgit v1.3-6-gb490 From b11b7af97883da01082e318abac51cec7162a347 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:38 +0200 Subject: gpio/msm-v2: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-msm-v2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index 52ff18229fdc..cbf383f7270d 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -281,14 +281,14 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) if (flow_type & IRQ_TYPE_EDGE_BOTH) { bits |= BIT(INTR_DECT_CTL); - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) __set_bit(gpio, msm_gpio.dual_edge_irqs); else __clear_bit(gpio, msm_gpio.dual_edge_irqs); } else { bits &= ~BIT(INTR_DECT_CTL); - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); __clear_bit(gpio, msm_gpio.dual_edge_irqs); } -- cgit v1.3-6-gb490 From 43ec2e4316047e9eecf7df86768708395888eb96 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:39 +0200 Subject: gpio/omap: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Kevin Hilman Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-omap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index b0c57d505be7..1a7c2ded9d6f 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -511,9 +511,9 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); return 0; -- cgit v1.3-6-gb490 From 2456d869c45eeaefa7c5c96d30d1e884a12709e3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:40 +0200 Subject: gpio/pch: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-pch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 2d9a950ca2d4..34ed176df15a 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -281,9 +281,9 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) /* And the handler */ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); unlock: spin_unlock_irqrestore(&chip->spinlock, flags); -- cgit v1.3-6-gb490 From f170d71eb2eb5de968dbedfd74bc53944a080391 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:40 +0200 Subject: gpio/gpio-tegra: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: Stephen Warren Cc: Thierry Reding Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 9b25c90f725c..271c4cf5e0cc 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -252,9 +252,9 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) tegra_gpio_enable(gpio); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); return 0; } -- cgit v1.3-6-gb490 From c16edb8b3a070be758a97bc6cd00855c7bbccec4 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:19 +0800 Subject: gpio/davinci: Use accessor function irq_data_get_irq_handler_data() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Cc: Linus Walleij Cc: Alexandre Courbot Signed-off-by: Thomas Gleixner --- drivers/gpio/gpio-davinci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index c5e05c82d67c..477d5b8616ab 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -396,7 +396,7 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) struct davinci_gpio_regs __iomem *g; u32 mask; - d = (struct davinci_gpio_controller *)data->handler_data; + d = (struct davinci_gpio_controller *)irq_data_get_irq_handler_data(data); g = (struct davinci_gpio_regs __iomem *)d->regs; mask = __gpio_mask(data->irq - d->gpio_irq); -- cgit v1.3-6-gb490 From 476f8b4c94a90d1167961d90a5ed68dbe87c62da Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:15 +0800 Subject: gpio: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. Preparatory patch for the removal of the 'irq' argument from irq flow handlers. Signed-off-by: Jiang Liu Acked-by: Linus Walleij Cc: Alexandre Courbot Signed-off-by: Thomas Gleixner --- drivers/gpio/gpio-bcm-kona.c | 2 +- drivers/gpio/gpio-dwapb.c | 2 +- drivers/gpio/gpio-mvebu.c | 2 +- drivers/gpio/gpio-mxc.c | 6 +++--- drivers/gpio/gpio-mxs.c | 2 +- drivers/gpio/gpio-omap.c | 2 +- drivers/gpio/gpio-tegra.c | 4 +--- drivers/gpio/gpio-timberdale.c | 5 +++-- drivers/gpio/gpio-vf610.c | 2 +- drivers/gpio/gpio-zynq.c | 2 +- 10 files changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 40343fa92c7b..109083f65248 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -438,7 +438,7 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) void __iomem *reg_base; int bit, bank_id; unsigned long sta; - struct bcm_kona_gpio_bank *bank = irq_get_handler_data(irq); + struct bcm_kona_gpio_bank *bank = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 55fa9853a7f2..c5be4b9b8baf 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -149,7 +149,7 @@ static u32 dwapb_do_irq(struct dwapb_gpio *gpio) static void dwapb_irq_handler(u32 irq, struct irq_desc *desc) { - struct dwapb_gpio *gpio = irq_get_handler_data(irq); + struct dwapb_gpio *gpio = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); dwapb_do_irq(gpio); diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index ab660e44a672..b65d2b8d3b95 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -460,7 +460,7 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct mvebu_gpio_chip *mvchip = irq_get_handler_data(irq); + struct mvebu_gpio_chip *mvchip = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); u32 cause, type; int i; diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index ec1eb1b7250f..0f740276ed2b 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -275,8 +275,8 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_stat; - struct mxc_gpio_port *port = irq_get_handler_data(irq); - struct irq_chip *chip = irq_get_chip(irq); + struct mxc_gpio_port *port = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); @@ -292,7 +292,7 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_msk, irq_stat; struct mxc_gpio_port *port; - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 551d15d7c369..b7f383eb18d9 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -157,7 +157,7 @@ static void mxs_flip_edge(struct mxs_gpio_port *port, u32 gpio) static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_stat; - struct mxs_gpio_port *port = irq_get_handler_data(irq); + struct mxs_gpio_port *port = irq_desc_get_handler_data(desc); desc->irq_data.chip->irq_ack(&desc->irq_data); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 1a7c2ded9d6f..04ea23ba37cc 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -714,7 +714,7 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) struct gpio_bank *bank; int unmasked = 0; struct irq_chip *irqchip = irq_desc_get_chip(desc); - struct gpio_chip *chip = irq_get_handler_data(irq); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); chained_irq_enter(irqchip, desc); diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 271c4cf5e0cc..530b27f9d66f 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -268,16 +268,14 @@ static void tegra_gpio_irq_shutdown(struct irq_data *d) static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct tegra_gpio_bank *bank; int port; int pin; int unmasked = 0; struct irq_chip *chip = irq_desc_get_chip(desc); + struct tegra_gpio_bank *bank = irq_desc_get_handler_data(desc); chained_irq_enter(chip, desc); - bank = irq_get_handler_data(irq); - for (port = 0; port < 4; port++) { int gpio = tegra_gpio_compose(bank->bank, port, 0); unsigned long sta = tegra_gpio_readl(GPIO_INT_STA(gpio)) & diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index fd1970ed15e6..ac53ff0a8086 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -194,11 +194,12 @@ out: static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) { - struct timbgpio *tgpio = irq_get_handler_data(irq); + struct timbgpio *tgpio = irq_desc_get_handler_data(desc); + struct irq_data *data = irq_desc_get_irq_data(desc); unsigned long ipr; int offset; - desc->irq_data.chip->irq_ack(irq_get_irq_data(irq)); + data->chip->irq_ack(data); ipr = ioread32(tgpio->membase + TGPIO_IPR); iowrite32(ipr, tgpio->membase + TGPIO_ICR); diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 7bd9f209ffa8..fa344388f4da 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -120,7 +120,7 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, static void vf610_gpio_irq_handler(u32 irq, struct irq_desc *desc) { - struct vf610_gpio_port *port = irq_get_handler_data(irq); + struct vf610_gpio_port *port = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); int pin; unsigned long irq_isfr; diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 53b297473724..db8a61b8ca0c 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -518,7 +518,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc) { u32 int_sts, int_enb; unsigned int bank_num; - struct zynq_gpio *gpio = irq_get_handler_data(irq); + struct zynq_gpio *gpio = irq_desc_get_handler_data(desc); struct irq_chip *irqchip = irq_desc_get_chip(desc); chained_irq_enter(irqchip, desc); -- cgit v1.3-6-gb490 From c3ca1e6f1849a6bce3a4a57e483d13ab7a544dd4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 12 Jul 2015 23:47:32 +0200 Subject: gpio/davinci: Prepare gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-davinci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 477d5b8616ab..9a738f5d409b 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -327,8 +327,9 @@ static struct irq_chip gpio_irqchip = { }; static void -gpio_irq_handler(unsigned irq, struct irq_desc *desc) +gpio_irq_handler(unsigned __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct davinci_gpio_regs __iomem *g; u32 mask = 0xffff; struct davinci_gpio_controller *d; -- cgit v1.3-6-gb490 From e43ea7a7736bb29fd088e83a7b66195eb2854814 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 00:06:41 +0200 Subject: gpio/ep93xx: Prepare ep93xx_gpio_f_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-ep93xx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 8664cf041b1f..dc0c40935940 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -100,13 +100,15 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) } } -static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc) +static void ep93xx_gpio_f_irq_handler(unsigned int __irq, + struct irq_desc *desc) { /* * map discontiguous hw irq range to continuous sw irq range: * * IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7}) */ + unsigned int irq = irq_desc_get_irq(desc); int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */ int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx; -- cgit v1.3-6-gb490 From 364ea44b24deec90c1ba88dc427d5bc4864096f5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 00:09:04 +0200 Subject: gpio/mvebu: Prepare mvebu_gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-mvebu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index b65d2b8d3b95..b396bf3bf294 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -458,7 +458,7 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) return 0; } -static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void mvebu_gpio_irq_handler(unsigned int __irq, struct irq_desc *desc) { struct mvebu_gpio_chip *mvchip = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); -- cgit v1.3-6-gb490 From 2951a7990c4aac3bfa05ea8474eb2948ca73eaba Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 00:11:27 +0200 Subject: gpio/sa1100: Prepare sa1100_gpio_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-sa1100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index 3fa22dade243..e847a4cf9326 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -173,9 +173,9 @@ static struct irq_domain *sa1100_gpio_irqdomain; * and call the handler. */ static void -sa1100_gpio_handler(unsigned int irq, struct irq_desc *desc) +sa1100_gpio_handler(unsigned int __irq, struct irq_desc *desc) { - unsigned int mask; + unsigned int irq, mask; mask = GEDR; do { -- cgit v1.3-6-gb490 From 789f9dabfe44c1f7056aa0a7c9a9205de4d5261f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:07:01 +0200 Subject: gpio/msm-v2: Avoid redundant lookup of irq_data It's pretty silly to do irq_data *d = irq_get_irq_data(irq_data->irq); because that results in d = irq_data, but goes through a lookup of the irq_data. Use irq_data directly. Signed-off-by: Thomas Gleixner Cc: Linus Walleij Cc: Alexandre Courbot Cc: Jiang Liu Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-msm-v2.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index cbf383f7270d..1f0fb19209bf 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -187,14 +187,6 @@ static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return irq_create_mapping(domain, offset); } -static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq) -{ - struct irq_data *irq_data = irq_get_irq_data(irq); - - return irq_data->hwirq; -} - - /* For dual-edge interrupts in software, since the hardware has no * such support: * @@ -238,7 +230,7 @@ static void msm_gpio_update_dual_edge_pos(unsigned gpio) static void msm_gpio_irq_ack(struct irq_data *d) { - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); + int gpio = d->hwirq; writel(BIT(INTR_STATUS), GPIO_INTR_STATUS(gpio)); if (test_bit(gpio, msm_gpio.dual_edge_irqs)) @@ -247,8 +239,8 @@ static void msm_gpio_irq_ack(struct irq_data *d) static void msm_gpio_irq_mask(struct irq_data *d) { - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); unsigned long irq_flags; + int gpio = d->hwirq; spin_lock_irqsave(&tlmm_lock, irq_flags); writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio)); @@ -259,8 +251,8 @@ static void msm_gpio_irq_mask(struct irq_data *d) static void msm_gpio_irq_unmask(struct irq_data *d) { - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); unsigned long irq_flags; + int gpio = d->hwirq; spin_lock_irqsave(&tlmm_lock, irq_flags); __set_bit(gpio, msm_gpio.enabled_irqs); @@ -271,8 +263,8 @@ static void msm_gpio_irq_unmask(struct irq_data *d) static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) { - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); unsigned long irq_flags; + int gpio = d->hwirq; uint32_t bits; spin_lock_irqsave(&tlmm_lock, irq_flags); @@ -331,7 +323,7 @@ static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc) static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) { - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); + int gpio = d->hwirq; if (on) { if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO)) -- cgit v1.3-6-gb490 From 1765d671b18e58fdd6341edac9c22e57d90ef6a8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:18:56 +0200 Subject: gpio/davinci: Avoid redundant lookup of irq_data It's pretty silly to do void *cd = irq_get_chip_data(irq_data->irq); because that results in cd = irq_data->chip_data, but goes through a redundant lookup of the irq_data. Use irq_data directly. Signed-off-by: Thomas Gleixner Cc: Linus Walleij Cc: Alexandre Courbot Cc: Jiang Liu Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-davinci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 9a738f5d409b..d885d98fe161 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -65,11 +65,11 @@ static struct davinci_gpio_regs __iomem *gpio2regs(unsigned gpio) return ptr; } -static inline struct davinci_gpio_regs __iomem *irq2regs(int irq) +static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d) { struct davinci_gpio_regs __iomem *g; - g = (__force struct davinci_gpio_regs __iomem *)irq_get_chip_data(irq); + g = (__force struct davinci_gpio_regs __iomem *)irq_data_get_irq_chip_data(d); return g; } @@ -287,7 +287,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) static void gpio_irq_disable(struct irq_data *d) { - struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); + struct davinci_gpio_regs __iomem *g = irq2regs(d); u32 mask = (u32) irq_data_get_irq_handler_data(d); writel_relaxed(mask, &g->clr_falling); @@ -296,7 +296,7 @@ static void gpio_irq_disable(struct irq_data *d) static void gpio_irq_enable(struct irq_data *d) { - struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); + struct davinci_gpio_regs __iomem *g = irq2regs(d); u32 mask = (u32) irq_data_get_irq_handler_data(d); unsigned status = irqd_get_trigger_type(d); -- cgit v1.3-6-gb490 From bdac2b6dc7392668a8530d67a5f762366f57f9b4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 23:22:44 +0200 Subject: gpio/davinci: Fix race in installing chained irq handler Fix a race where a pending interrupt could be received and the handler called before the handler's data has been setup, by converting to irq_set_chained_handler_and_data(). Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot --- drivers/gpio/gpio-davinci.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index d885d98fe161..b23cbcea2d98 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -579,15 +579,13 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) writel_relaxed(~0, &g->clr_falling); writel_relaxed(~0, &g->clr_rising); - /* set up all irqs in this bank */ - irq_set_chained_handler(bank_irq, gpio_irq_handler); - /* * Each chip handles 32 gpios, and each irq bank consists of 16 * gpio irqs. Pass the irq bank's corresponding controller to * the chained irq handler. */ - irq_set_handler_data(bank_irq, &chips[gpio / 32]); + irq_set_chained_handler_and_data(bank_irq, gpio_irq_handler, + &chips[gpio / 32]); binten |= BIT(bank); } -- cgit v1.3-6-gb490 From 131e663bd6f1055caaff128f9aa5071d227eeb72 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:32:33 +0200 Subject: drm/gem: rip out drm vma accounting for gem mmaps Doesn't really add anything which can't be figured out through proc files. And more clearly separates the new gem mmap handling code from the old drm maps mmap handling code, which is surely a good thing. Cc: Martin Peres Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_gem.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 16a164770713..27a4228b4343 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -778,22 +778,14 @@ void drm_gem_vm_open(struct vm_area_struct *vma) struct drm_gem_object *obj = vma->vm_private_data; drm_gem_object_reference(obj); - - mutex_lock(&obj->dev->struct_mutex); - drm_vm_open_locked(obj->dev, vma); - mutex_unlock(&obj->dev->struct_mutex); } EXPORT_SYMBOL(drm_gem_vm_open); void drm_gem_vm_close(struct vm_area_struct *vma) { struct drm_gem_object *obj = vma->vm_private_data; - struct drm_device *dev = obj->dev; - mutex_lock(&dev->struct_mutex); - drm_vm_close_locked(obj->dev, vma); - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); + drm_gem_object_unreference_unlocked(obj); } EXPORT_SYMBOL(drm_gem_vm_close); @@ -850,7 +842,6 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, */ drm_gem_object_reference(obj); - drm_vm_open_locked(dev, vma); return 0; } EXPORT_SYMBOL(drm_gem_mmap_obj); -- cgit v1.3-6-gb490 From fa3eec7791b0fe27e3112804a71ba445ff336a6b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 1 Jul 2015 23:51:43 +0100 Subject: regmap: Silence warning on invalid zero length read Zero length reads make no sense in a regmap context and are likely to trigger bugs further down the stack so insert an error check, also silencing compiler warnings about use of ret in cases where we iterate per register. Reported-by: Russell King Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 8894b992043e..9c1f856842a3 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2180,6 +2180,8 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, return -EINVAL; if (reg % map->reg_stride) return -EINVAL; + if (val_count == 0) + return -EINVAL; map->lock(map->lock_arg); -- cgit v1.3-6-gb490 From 8a75d157ccddc2c1fb5aeefe6a1a45a9eb0c0176 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:14 +0200 Subject: drm/i915: Only update state on crtc's that are part of the atomic state. This is probably hard to hit right now because in most cases all atomic locks are taken, but after conversion to atomic this will make it more likely to corrupt the crtc->config pointer, resulting in hard to find bugs. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 00c60c1c5162..9995df578fa8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12312,6 +12312,7 @@ intel_modeset_update_state(struct drm_atomic_state *state) struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; struct drm_connector *connector; + int i; intel_shared_dpll_commit(state); @@ -12331,7 +12332,7 @@ intel_modeset_update_state(struct drm_atomic_state *state) intel_modeset_update_staged_output_state(state->dev); /* Double check state. */ - for_each_crtc(dev, crtc) { + for_each_crtc_in_state(state, crtc, crtc_state, i) { WARN_ON(crtc->state->enable != intel_crtc_in_use(crtc)); to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); -- cgit v1.3-6-gb490 From e435d6e52b164c041d3b0f88be3f7b8c5a14462a Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:15 +0200 Subject: drm/i915: Do not update pfit state when toggling crtc enabled. There's not much point for calculating the changes for the old state. Instead just disable all scalers when disabling. It's probably good enough to just disable the crtc_scaler, but just in case there's a bug disable all scalers. This means intel_atomic_setup_scalers is only called in the crtc check function now, so all the transitional code can be removed. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 14 ++------ drivers/gpu/drm/i915/intel_display.c | 68 +++++++++++++++++++++++------------- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 2 +- 4 files changed, 48 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 5c79a31603af..b92b8581efc2 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -272,17 +272,12 @@ int intel_atomic_setup_scalers(struct drm_device *dev, struct drm_plane *plane = NULL; struct intel_plane *intel_plane; struct intel_plane_state *plane_state = NULL; - struct intel_crtc_scaler_state *scaler_state; - struct drm_atomic_state *drm_state; + struct intel_crtc_scaler_state *scaler_state = + &crtc_state->scaler_state; + struct drm_atomic_state *drm_state = crtc_state->base.state; int num_scalers_need; int i, j; - if (INTEL_INFO(dev)->gen < 9 || !intel_crtc || !crtc_state) - return 0; - - scaler_state = &crtc_state->scaler_state; - drm_state = crtc_state->base.state; - num_scalers_need = hweight32(scaler_state->scaler_users); DRM_DEBUG_KMS("crtc_state = %p need = %d avail = %d scaler_users = 0x%x\n", crtc_state, num_scalers_need, intel_crtc->num_scalers, @@ -326,9 +321,6 @@ int intel_atomic_setup_scalers(struct drm_device *dev, } else { name = "PLANE"; - if (!drm_state) - continue; - /* plane scaler case: assign as a plane scaler */ /* find the plane that set the bit as scaler_user */ plane = drm_state->planes[i]; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9995df578fa8..99897b152091 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2911,29 +2911,32 @@ unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, return i915_gem_obj_ggtt_offset_view(obj, view); } +static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(SKL_PS_CTRL(intel_crtc->pipe, id), 0); + I915_WRITE(SKL_PS_WIN_POS(intel_crtc->pipe, id), 0); + I915_WRITE(SKL_PS_WIN_SZ(intel_crtc->pipe, id), 0); + DRM_DEBUG_KMS("CRTC:%d Disabled scaler id %u.%u\n", + intel_crtc->base.base.id, intel_crtc->pipe, id); +} + /* * This function detaches (aka. unbinds) unused scalers in hardware */ static void skl_detach_scalers(struct intel_crtc *intel_crtc) { - struct drm_device *dev; - struct drm_i915_private *dev_priv; struct intel_crtc_scaler_state *scaler_state; int i; - dev = intel_crtc->base.dev; - dev_priv = dev->dev_private; scaler_state = &intel_crtc->config->scaler_state; /* loop through and disable scalers that aren't in use */ for (i = 0; i < intel_crtc->num_scalers; i++) { - if (!scaler_state->scalers[i].in_use) { - I915_WRITE(SKL_PS_CTRL(intel_crtc->pipe, i), 0); - I915_WRITE(SKL_PS_WIN_POS(intel_crtc->pipe, i), 0); - I915_WRITE(SKL_PS_WIN_SZ(intel_crtc->pipe, i), 0); - DRM_DEBUG_KMS("CRTC:%d Disabled scaler id %u.%u\n", - intel_crtc->base.base.id, intel_crtc->pipe, i); - } + if (!scaler_state->scalers[i].in_use) + skl_detach_scaler(intel_crtc, i); } } @@ -4364,13 +4367,12 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, * skl_update_scaler_crtc - Stages update to scaler state for a given crtc. * * @state: crtc's scaler state - * @force_detach: whether to forcibly disable scaler * * Return * 0 - scaler_usage updated successfully * error - requested scaling cannot be supported or other error condition */ -int skl_update_scaler_crtc(struct intel_crtc_state *state, int force_detach) +int skl_update_scaler_crtc(struct intel_crtc_state *state) { struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); struct drm_display_mode *adjusted_mode = @@ -4379,7 +4381,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state, int force_detach) DRM_DEBUG_KMS("Updating scaler for [CRTC:%i] scaler_user index %u.%u\n", intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX); - return skl_update_scaler(state, force_detach, SKL_CRTC_INDEX, + return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX, &state->scaler_state.scaler_id, DRM_ROTATE_0, state->pipe_src_w, state->pipe_src_h, adjusted_mode->hdisplay, adjusted_mode->vdisplay); @@ -4453,7 +4455,15 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, return 0; } -static void skylake_pfit_update(struct intel_crtc *crtc, int enable) +static void skylake_scaler_disable(struct intel_crtc *crtc) +{ + int i; + + for (i = 0; i < crtc->num_scalers; i++) + skl_detach_scaler(crtc, i); +} + +static void skylake_pfit_enable(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4463,13 +4473,6 @@ static void skylake_pfit_update(struct intel_crtc *crtc, int enable) DRM_DEBUG_KMS("for crtc_state = %p\n", crtc->config); - /* To update pfit, first update scaler state */ - skl_update_scaler_crtc(crtc->config, !enable); - intel_atomic_setup_scalers(crtc->base.dev, crtc, crtc->config); - skl_detach_scalers(crtc); - if (!enable) - return; - if (crtc->config->pch_pfit.enabled) { int id; @@ -4944,7 +4947,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_ddi_enable_pipe_clock(intel_crtc); if (INTEL_INFO(dev)->gen == 9) - skylake_pfit_update(intel_crtc, 1); + skylake_pfit_enable(intel_crtc); else if (INTEL_INFO(dev)->gen < 9) ironlake_pfit_enable(intel_crtc); else @@ -5081,7 +5084,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); if (INTEL_INFO(dev)->gen == 9) - skylake_pfit_update(intel_crtc, 0); + skylake_scaler_disable(intel_crtc); else if (INTEL_INFO(dev)->gen < 9) ironlake_pfit_disable(intel_crtc); else @@ -11834,7 +11837,17 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, return ret; } - return intel_atomic_setup_scalers(dev, intel_crtc, pipe_config); + ret = 0; + if (INTEL_INFO(dev)->gen >= 9) { + if (mode_changed) + ret = skl_update_scaler_crtc(pipe_config); + + if (!ret) + ret = intel_atomic_setup_scalers(dev, intel_crtc, + pipe_config); + } + + return ret; } static const struct drm_crtc_helper_funcs intel_helper_funcs = { @@ -15355,6 +15368,11 @@ static void readout_plane_state(struct intel_crtc *crtc, continue; drm_plane_state = p->base.state; + + /* Plane scaler state is not touched here. The first atomic + * commit will restore all plane scalers to its old state. + */ + if (active && p->base.type == DRM_PLANE_TYPE_PRIMARY) { visible = primary_get_hw_state(crtc); to_intel_plane_state(drm_plane_state)->visible = visible; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 367f71224c96..085d84156008 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1382,7 +1382,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (INTEL_INFO(dev)->gen >= 9) { int ret; - ret = skl_update_scaler_crtc(pipe_config, 0); + ret = skl_update_scaler_crtc(pipe_config); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b9c01c5b881f..09a0a9222a3a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1149,7 +1149,7 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); -int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state, int force_detach); +int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, -- cgit v1.3-6-gb490 From 8e9ba31a0f6c217e05f84efe9c569f9010a8ad26 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:16 +0200 Subject: drm/i915: Do not use plane_config in intel_fbdev.c Use the atomic state instead, this allows removing plane_config from the crtc after the full hw readout is completed. The size can be found in the fb, no need for the plane_config. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 33b3c9233eac..b791f2374f3b 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -581,7 +581,6 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, struct intel_framebuffer *fb = NULL; struct drm_crtc *crtc; struct intel_crtc *intel_crtc; - struct intel_initial_plane_config *plane_config = NULL; unsigned int max_size = 0; if (!i915.fastboot) @@ -589,20 +588,21 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, /* Find the largest fb */ for_each_crtc(dev, crtc) { + struct drm_i915_gem_object *obj = + intel_fb_obj(crtc->primary->state->fb); intel_crtc = to_intel_crtc(crtc); - if (!intel_crtc->active || !crtc->primary->fb) { + if (!intel_crtc->active || !obj) { 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) { + if (obj->base.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 = to_intel_framebuffer(crtc->primary->fb); - max_size = plane_config->size; + fb = to_intel_framebuffer(crtc->primary->state->fb); + max_size = obj->base.size; } } @@ -637,7 +637,6 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n", pipe_name(intel_crtc->pipe), cur_size, fb->base.pitches[0]); - plane_config = NULL; fb = NULL; break; } @@ -658,7 +657,6 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, 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; } -- cgit v1.3-6-gb490 From cfb23ed622d040619abb91e625fcba74d356b8a8 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 12:17:40 +0200 Subject: drm/i915: Allow fuzzy matching in pipe_config_compare, v2. Instead of doing ad-hoc checks we already have a way of checking if the state is compatible or not. Use this to force a modeset. Only during modesets, or with PIPE_CONFIG_QUIRK_INHERITED_MODE we should check if a full modeset is really needed. Fastboot will allow the adjust parameter to ignore some stuff too, and it will fix up differences in state that are ignored by the compare function. Changes since v1: - Increase the value of the lowest m/n to prevent truncation. - Dump pipe config when fastboot's used, without a modeset. - Add adjust parameter to intel_compare_link_m_n, which is used to adjust m2_n2 if it's a multiple of m_n. - Add exact parameter intel_compare_m_n. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 218 +++++++++++++++++++++++++---------- 1 file changed, 157 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 99897b152091..541d2a841279 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12288,19 +12288,6 @@ encoder_retry: DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n", base_bpp, pipe_config->pipe_bpp, pipe_config->dither); - /* Check if we need to force a modeset */ - if (pipe_config->has_audio != - to_intel_crtc_state(crtc->state)->has_audio) { - pipe_config->base.mode_changed = true; - ret = drm_atomic_add_affected_planes(state, crtc); - } - - /* - * Note we have an issue here with infoframes: current code - * only updates them on the full mode set path per hw - * requirements. So here we should be checking for any - * required changes and forcing a mode set. - */ fail: return ret; } @@ -12404,27 +12391,133 @@ static bool intel_fuzzy_clock_check(int clock1, int clock2) base.head) \ if (mask & (1 <<(intel_crtc)->pipe)) + +static bool +intel_compare_m_n(unsigned int m, unsigned int n, + unsigned int m2, unsigned int n2, + bool exact) +{ + if (m == m2 && n == n2) + return true; + + if (exact || !m || !n || !m2 || !n2) + return false; + + BUILD_BUG_ON(DATA_LINK_M_N_MASK > INT_MAX); + + if (m > m2) { + while (m > m2) { + m2 <<= 1; + n2 <<= 1; + } + } else if (m < m2) { + while (m < m2) { + m <<= 1; + n <<= 1; + } + } + + return m == m2 && n == n2; +} + +static bool +intel_compare_link_m_n(const struct intel_link_m_n *m_n, + struct intel_link_m_n *m2_n2, + bool adjust) +{ + if (m_n->tu == m2_n2->tu && + intel_compare_m_n(m_n->gmch_m, m_n->gmch_n, + m2_n2->gmch_m, m2_n2->gmch_n, !adjust) && + intel_compare_m_n(m_n->link_m, m_n->link_n, + m2_n2->link_m, m2_n2->link_n, !adjust)) { + if (adjust) + *m2_n2 = *m_n; + + return true; + } + + return false; +} + static bool intel_pipe_config_compare(struct drm_device *dev, struct intel_crtc_state *current_config, - struct intel_crtc_state *pipe_config) + struct intel_crtc_state *pipe_config, + bool adjust) { + bool ret = true; + +#define INTEL_ERR_OR_DBG_KMS(fmt, ...) \ + do { \ + if (!adjust) \ + DRM_ERROR(fmt, ##__VA_ARGS__); \ + else \ + DRM_DEBUG_KMS(fmt, ##__VA_ARGS__); \ + } while (0) + #define PIPE_CONF_CHECK_X(name) \ if (current_config->name != pipe_config->name) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected 0x%08x, found 0x%08x)\n", \ current_config->name, \ pipe_config->name); \ - return false; \ + ret = false; \ } #define PIPE_CONF_CHECK_I(name) \ if (current_config->name != pipe_config->name) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected %i, found %i)\n", \ current_config->name, \ pipe_config->name); \ - return false; \ + ret = false; \ + } + +#define PIPE_CONF_CHECK_M_N(name) \ + if (!intel_compare_link_m_n(¤t_config->name, \ + &pipe_config->name,\ + adjust)) { \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ + "(expected tu %i gmch %i/%i link %i/%i, " \ + "found tu %i, gmch %i/%i link %i/%i)\n", \ + current_config->name.tu, \ + current_config->name.gmch_m, \ + current_config->name.gmch_n, \ + current_config->name.link_m, \ + current_config->name.link_n, \ + pipe_config->name.tu, \ + pipe_config->name.gmch_m, \ + pipe_config->name.gmch_n, \ + pipe_config->name.link_m, \ + pipe_config->name.link_n); \ + ret = false; \ + } + +#define PIPE_CONF_CHECK_M_N_ALT(name, alt_name) \ + if (!intel_compare_link_m_n(¤t_config->name, \ + &pipe_config->name, adjust) && \ + !intel_compare_link_m_n(¤t_config->alt_name, \ + &pipe_config->name, adjust)) { \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ + "(expected tu %i gmch %i/%i link %i/%i, " \ + "or tu %i gmch %i/%i link %i/%i, " \ + "found tu %i, gmch %i/%i link %i/%i)\n", \ + current_config->name.tu, \ + current_config->name.gmch_m, \ + current_config->name.gmch_n, \ + current_config->name.link_m, \ + current_config->name.link_n, \ + current_config->alt_name.tu, \ + current_config->alt_name.gmch_m, \ + current_config->alt_name.gmch_n, \ + current_config->alt_name.link_m, \ + current_config->alt_name.link_n, \ + pipe_config->name.tu, \ + pipe_config->name.gmch_m, \ + pipe_config->name.gmch_n, \ + pipe_config->name.link_m, \ + pipe_config->name.link_n); \ + ret = false; \ } /* This is required for BDW+ where there is only one set of registers for @@ -12435,30 +12528,30 @@ intel_pipe_config_compare(struct drm_device *dev, #define PIPE_CONF_CHECK_I_ALT(name, alt_name) \ if ((current_config->name != pipe_config->name) && \ (current_config->alt_name != pipe_config->name)) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected %i or %i, found %i)\n", \ current_config->name, \ current_config->alt_name, \ pipe_config->name); \ - return false; \ + ret = false; \ } #define PIPE_CONF_CHECK_FLAGS(name, mask) \ if ((current_config->name ^ pipe_config->name) & (mask)) { \ - DRM_ERROR("mismatch in " #name "(" #mask ") " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name "(" #mask ") " \ "(expected %i, found %i)\n", \ current_config->name & (mask), \ pipe_config->name & (mask)); \ - return false; \ + ret = false; \ } #define PIPE_CONF_CHECK_CLOCK_FUZZY(name) \ if (!intel_fuzzy_clock_check(current_config->name, pipe_config->name)) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected %i, found %i)\n", \ current_config->name, \ pipe_config->name); \ - return false; \ + ret = false; \ } #define PIPE_CONF_QUIRK(quirk) \ @@ -12468,35 +12561,18 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(has_pch_encoder); PIPE_CONF_CHECK_I(fdi_lanes); - PIPE_CONF_CHECK_I(fdi_m_n.gmch_m); - PIPE_CONF_CHECK_I(fdi_m_n.gmch_n); - PIPE_CONF_CHECK_I(fdi_m_n.link_m); - PIPE_CONF_CHECK_I(fdi_m_n.link_n); - PIPE_CONF_CHECK_I(fdi_m_n.tu); + PIPE_CONF_CHECK_M_N(fdi_m_n); PIPE_CONF_CHECK_I(has_dp_encoder); if (INTEL_INFO(dev)->gen < 8) { - PIPE_CONF_CHECK_I(dp_m_n.gmch_m); - PIPE_CONF_CHECK_I(dp_m_n.gmch_n); - PIPE_CONF_CHECK_I(dp_m_n.link_m); - PIPE_CONF_CHECK_I(dp_m_n.link_n); - PIPE_CONF_CHECK_I(dp_m_n.tu); - - if (current_config->has_drrs) { - PIPE_CONF_CHECK_I(dp_m2_n2.gmch_m); - PIPE_CONF_CHECK_I(dp_m2_n2.gmch_n); - PIPE_CONF_CHECK_I(dp_m2_n2.link_m); - PIPE_CONF_CHECK_I(dp_m2_n2.link_n); - PIPE_CONF_CHECK_I(dp_m2_n2.tu); - } - } else { - PIPE_CONF_CHECK_I_ALT(dp_m_n.gmch_m, dp_m2_n2.gmch_m); - PIPE_CONF_CHECK_I_ALT(dp_m_n.gmch_n, dp_m2_n2.gmch_n); - PIPE_CONF_CHECK_I_ALT(dp_m_n.link_m, dp_m2_n2.link_m); - PIPE_CONF_CHECK_I_ALT(dp_m_n.link_n, dp_m2_n2.link_n); - PIPE_CONF_CHECK_I_ALT(dp_m_n.tu, dp_m2_n2.tu); - } + PIPE_CONF_CHECK_M_N(dp_m_n); + + PIPE_CONF_CHECK_I(has_drrs); + if (current_config->has_drrs) + PIPE_CONF_CHECK_M_N(dp_m2_n2); + } else + PIPE_CONF_CHECK_M_N_ALT(dp_m_n, dp_m2_n2); PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hdisplay); PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_htotal); @@ -12592,8 +12668,9 @@ intel_pipe_config_compare(struct drm_device *dev, #undef PIPE_CONF_CHECK_FLAGS #undef PIPE_CONF_CHECK_CLOCK_FUZZY #undef PIPE_CONF_QUIRK +#undef INTEL_ERR_OR_DBG_KMS - return true; + return ret; } static void check_wm_state(struct drm_device *dev) @@ -12785,8 +12862,11 @@ check_crtc_state(struct drm_device *dev) "transitional active state does not match atomic hw state " "(expected %i, found %i)\n", crtc->base.state->active, crtc->active); - if (active && - !intel_pipe_config_compare(dev, crtc->config, &pipe_config)) { + if (!active) + continue; + + if (!intel_pipe_config_compare(dev, crtc->config, + &pipe_config, false)) { I915_STATE_WARN(1, "pipe state doesn't match!\n"); intel_dump_pipe_config(crtc, &pipe_config, "[hw state]"); @@ -13087,14 +13167,17 @@ intel_modeset_compute_config(struct drm_atomic_state *state) return ret; for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc_state); + bool modeset, recalc; + if (!crtc_state->enable) { if (needs_modeset(crtc_state)) any_ms = true; continue; } - if (to_intel_crtc_state(crtc_state)->quirks & - PIPE_CONFIG_QUIRK_INITIAL_PLANES) { + if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) { ret = drm_atomic_add_affected_planes(state, crtc); if (ret) return ret; @@ -13107,23 +13190,36 @@ intel_modeset_compute_config(struct drm_atomic_state *state) */ } - if (!needs_modeset(crtc_state)) { + modeset = needs_modeset(crtc_state); + recalc = pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE; + + if (!modeset && !recalc) + continue; + + if (recalc) { ret = drm_atomic_add_affected_connectors(state, crtc); if (ret) return ret; } - ret = intel_modeset_pipe_config(crtc, - to_intel_crtc_state(crtc_state)); + ret = intel_modeset_pipe_config(crtc, pipe_config); if (ret) return ret; - if (needs_modeset(crtc_state)) - any_ms = true; + if (recalc && !intel_pipe_config_compare(state->dev, + to_intel_crtc_state(crtc->state), + pipe_config, true)) { + modeset = crtc_state->mode_changed = true; + + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + return ret; + } + any_ms = modeset; intel_dump_pipe_config(to_intel_crtc(crtc), - to_intel_crtc_state(crtc_state), - "[modeset]"); + pipe_config, + modeset ? "[modeset]" : "[fastboot]"); } if (any_ms) { -- cgit v1.3-6-gb490 From be5651f2d5814cefbe89b17c187309ad4c1d3967 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:18 +0200 Subject: drm/i915: Update missing properties in find_initial_plane_obj The src and crtc rectangles were never set, resulting in the primary plane being made invisible on first atomic update. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 541d2a841279..d013a34dde7f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2588,6 +2588,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, struct intel_crtc *i; struct drm_i915_gem_object *obj; struct drm_plane *primary = intel_crtc->base.primary; + struct drm_plane_state *plane_state = primary->state; struct drm_framebuffer *fb; if (!plane_config->fb) @@ -2627,13 +2628,21 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, return; valid_fb: + plane_state->src_x = plane_state->src_y = 0; + plane_state->src_w = fb->width << 16; + plane_state->src_h = fb->height << 16; + + plane_state->crtc_x = plane_state->src_y = 0; + plane_state->crtc_w = fb->width; + plane_state->crtc_h = fb->height; + obj = intel_fb_obj(fb); if (obj->tiling_mode != I915_TILING_NONE) dev_priv->preserve_bios_swizzle = true; - primary->fb = fb; + drm_framebuffer_reference(fb); + primary->fb = primary->state->fb = fb; primary->crtc = primary->state->crtc = &intel_crtc->base; - update_state_fb(primary); intel_crtc->base.state->plane_mask |= (1 << drm_plane_index(primary)); obj->frontbuffer_bits |= to_intel_plane(primary)->frontbuffer_bit; } -- cgit v1.3-6-gb490 From eeebeac5e476800991ea1d10827307c41650ba11 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 12:33:29 +0200 Subject: drm/i915: Remove plane_config from struct intel_crtc, v2. Nothing depends on this outside initial hw readout, so keep this struct on the stack instead. Changes since v1: - Remove unrelated changes. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 19 ++++++++++--------- drivers/gpu/drm/i915/intel_drv.h | 1 - 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d013a34dde7f..b0a3120c6da1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15202,6 +15202,8 @@ void intel_modeset_init(struct drm_device *dev) drm_modeset_unlock_all(dev); for_each_intel_crtc(dev, crtc) { + struct intel_initial_plane_config plane_config = {}; + if (!crtc->active) continue; @@ -15212,15 +15214,14 @@ void intel_modeset_init(struct drm_device *dev) * can even allow for smooth boot transitions if the BIOS * fb is large enough for the active pipe configuration. */ - if (dev_priv->display.get_initial_plane_config) { - dev_priv->display.get_initial_plane_config(crtc, - &crtc->plane_config); - /* - * If the fb is shared between multiple heads, we'll - * just get the first one. - */ - intel_find_initial_plane_obj(crtc, &crtc->plane_config); - } + dev_priv->display.get_initial_plane_config(crtc, + &plane_config); + + /* + * If the fb is shared between multiple heads, we'll + * just get the first one. + */ + intel_find_initial_plane_obj(crtc, &plane_config); } } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 09a0a9222a3a..09e3581c8441 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -550,7 +550,6 @@ struct intel_crtc { uint32_t cursor_size; uint32_t cursor_base; - struct intel_initial_plane_config plane_config; struct intel_crtc_state *config; bool new_enabled; -- cgit v1.3-6-gb490 From 6d00d153f00097d259f86304e11858a50a1b8ad1 Mon Sep 17 00:00:00 2001 From: Ellen Wang Date: Mon, 13 Jul 2015 15:23:54 -0700 Subject: HID: cp2112: fix I2C_SMBUS_BYTE write When doing an I2C_SMBUS_BYTE write (one byte write, no address), the data to be written is in "command" not "data->byte". Signed-off-by: Ellen Wang Acked-by: Wolfram Sang Reviewed-by: Antonio Borneo Cc: stable@vger.kernel.org Signed-off-by: Jiri Kosina --- drivers/hid/hid-cp2112.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 1d24a65b4295..a84d3700e740 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -606,7 +606,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, if (I2C_SMBUS_READ == read_write) count = cp2112_read_req(buf, addr, read_length); else - count = cp2112_write_req(buf, addr, data->byte, NULL, + count = cp2112_write_req(buf, addr, command, NULL, 0); break; case I2C_SMBUS_BYTE_DATA: -- cgit v1.3-6-gb490 From faf4ffe031df41c067f3b89632ce3d3667bb64ad Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 14 Jul 2015 10:59:30 +0200 Subject: drm/i915: Remove unused compat32 code Totatlly forgotten that we have these when nuking all the UMS code. Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_ioc32.c | 125 -------------------------------------- 1 file changed, 125 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_ioc32.c b/drivers/gpu/drm/i915/i915_ioc32.c index 176de6322e4d..6eec2221b44e 100644 --- a/drivers/gpu/drm/i915/i915_ioc32.c +++ b/drivers/gpu/drm/i915/i915_ioc32.c @@ -35,98 +35,6 @@ #include #include "i915_drv.h" -typedef struct _drm_i915_batchbuffer32 { - int start; /* agp offset */ - int used; /* nr bytes in use */ - int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ - int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ - int num_cliprects; /* mulitpass with multiple cliprects? */ - u32 cliprects; /* pointer to userspace cliprects */ -} drm_i915_batchbuffer32_t; - -static int compat_i915_batchbuffer(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_i915_batchbuffer32_t batchbuffer32; - drm_i915_batchbuffer_t __user *batchbuffer; - - if (copy_from_user - (&batchbuffer32, (void __user *)arg, sizeof(batchbuffer32))) - return -EFAULT; - - batchbuffer = compat_alloc_user_space(sizeof(*batchbuffer)); - if (!access_ok(VERIFY_WRITE, batchbuffer, sizeof(*batchbuffer)) - || __put_user(batchbuffer32.start, &batchbuffer->start) - || __put_user(batchbuffer32.used, &batchbuffer->used) - || __put_user(batchbuffer32.DR1, &batchbuffer->DR1) - || __put_user(batchbuffer32.DR4, &batchbuffer->DR4) - || __put_user(batchbuffer32.num_cliprects, - &batchbuffer->num_cliprects) - || __put_user((int __user *)(unsigned long)batchbuffer32.cliprects, - &batchbuffer->cliprects)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_I915_BATCHBUFFER, - (unsigned long)batchbuffer); -} - -typedef struct _drm_i915_cmdbuffer32 { - u32 buf; /* pointer to userspace command buffer */ - int sz; /* nr bytes in buf */ - int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ - int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ - int num_cliprects; /* mulitpass with multiple cliprects? */ - u32 cliprects; /* pointer to userspace cliprects */ -} drm_i915_cmdbuffer32_t; - -static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_i915_cmdbuffer32_t cmdbuffer32; - drm_i915_cmdbuffer_t __user *cmdbuffer; - - if (copy_from_user - (&cmdbuffer32, (void __user *)arg, sizeof(cmdbuffer32))) - return -EFAULT; - - cmdbuffer = compat_alloc_user_space(sizeof(*cmdbuffer)); - if (!access_ok(VERIFY_WRITE, cmdbuffer, sizeof(*cmdbuffer)) - || __put_user((int __user *)(unsigned long)cmdbuffer32.buf, - &cmdbuffer->buf) - || __put_user(cmdbuffer32.sz, &cmdbuffer->sz) - || __put_user(cmdbuffer32.DR1, &cmdbuffer->DR1) - || __put_user(cmdbuffer32.DR4, &cmdbuffer->DR4) - || __put_user(cmdbuffer32.num_cliprects, &cmdbuffer->num_cliprects) - || __put_user((int __user *)(unsigned long)cmdbuffer32.cliprects, - &cmdbuffer->cliprects)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_I915_CMDBUFFER, - (unsigned long)cmdbuffer); -} - -typedef struct drm_i915_irq_emit32 { - u32 irq_seq; -} drm_i915_irq_emit32_t; - -static int compat_i915_irq_emit(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_i915_irq_emit32_t req32; - drm_i915_irq_emit_t __user *request; - - if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) - return -EFAULT; - - request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user((int __user *)(unsigned long)req32.irq_seq, - &request->irq_seq)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_I915_IRQ_EMIT, - (unsigned long)request); -} typedef struct drm_i915_getparam32 { int param; u32 value; @@ -152,41 +60,8 @@ static int compat_i915_getparam(struct file *file, unsigned int cmd, (unsigned long)request); } -typedef struct drm_i915_mem_alloc32 { - int region; - int alignment; - int size; - u32 region_offset; /* offset from start of fb or agp */ -} drm_i915_mem_alloc32_t; - -static int compat_i915_alloc(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_i915_mem_alloc32_t req32; - drm_i915_mem_alloc_t __user *request; - - if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) - return -EFAULT; - - request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user(req32.region, &request->region) - || __put_user(req32.alignment, &request->alignment) - || __put_user(req32.size, &request->size) - || __put_user((void __user *)(unsigned long)req32.region_offset, - &request->region_offset)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_I915_ALLOC, - (unsigned long)request); -} - static drm_ioctl_compat_t *i915_compat_ioctls[] = { - [DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer, - [DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer, [DRM_I915_GETPARAM] = compat_i915_getparam, - [DRM_I915_IRQ_EMIT] = compat_i915_irq_emit, - [DRM_I915_ALLOC] = compat_i915_alloc }; /** -- cgit v1.3-6-gb490 From 3bbaba0ceaa254c9ee261e329bfd92e4ba4fe32a Mon Sep 17 00:00:00 2001 From: Peter Antoine Date: Fri, 10 Jul 2015 20:13:11 +0300 Subject: drm/i915: Added Programming of the MOCS This change adds the programming of the MOCS registers to the gen 9+ platforms. The set of MOCS configuration entries introduced by this patch is intended to be minimal but sufficient to cover the needs of current userspace - i.e. a good set of defaults. It is expected to be extended in the future to provide further default values or to allow userspace to redefine its private MOCS tables based on its demand for additional caching configurations. In this setup, userspace should only utilize the first N entries, higher entries are reserved for future use. It creates a fixed register set that is programmed across the different engines so that all engines have the same table. This is done as the main RCS context only holds the registers for itself and the shared L3 values. By trying to keep the registers consistent across the different engines it should make the programming for the registers consistent. v2: -'static const' for private data structures and style changes.(Matt Turner) v3: - Make the tables "slightly" more readable. (Damien Lespiau) - Updated tables fix performance regression. v4: - Code formatting. (Chris Wilson) - re-privatised mocs code. (Daniel Vetter) v5: - Changed the name of a function. (Chris Wilson) v6: - re-based - Added Mesa table entry (skylake & broxton) (Francisco Jerez) - Tidied up the readability defines (Francisco Jerez) - NUMBER of entries defines wrong. (Jim Bish) - Added comments to clear up the meaning of the tables (Jim Bish) Signed-off-by: Peter Antoine v7 (Francisco Jerez): - Don't write L3-specific MOCS_ESC/SCC values into the e/LLC control tables. Prefix L3-specific defines consistently with L3_ and e/LLC-specific defines with LE_ to avoid this kind of confusion in the future. - Change L3CC WT define back to RESERVED (matches my hardware documentation and the original patch, probably a misunderstanding of my own previous comment). - Drop Android tables, define new minimal tables more suitable for the open source stack. - Add comment that the MOCS tables are part of the kernel ABI. - Move intel_logical_ring_begin() and _advance() calls one level down (Chris Wilson). - Minor formatting and style fixes. v8 (Francisco Jerez): - Add table size sanity check to emit_mocs_control/l3cc_table() (Chris Wilson). - Add comment about undefined entries being implicitly set to uncached for forwards compatibility. v9 (Francisco Jerez): - Minor style fixes. Signed-off-by: Francisco Jerez Acked-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_reg.h | 9 + drivers/gpu/drm/i915/intel_lrc.c | 12 +- drivers/gpu/drm/i915/intel_lrc.h | 1 + drivers/gpu/drm/i915/intel_mocs.c | 335 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_mocs.h | 57 +++++++ 6 files changed, 413 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_mocs.c create mode 100644 drivers/gpu/drm/i915/intel_mocs.h (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index de2196543367..e52e01251644 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -36,6 +36,7 @@ i915-y += i915_cmd_parser.o \ i915_trace_points.o \ intel_hotplug.o \ intel_lrc.o \ + intel_mocs.o \ intel_ringbuffer.o \ intel_uncore.o diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0650a3d8a40f..97794bc753f2 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7902,4 +7902,13 @@ enum skl_disp_power_wells { #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000) #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800) +/* MOCS (Memory Object Control State) registers */ +#define GEN9_LNCFCMOCS0 0xb020 /* L3 Cache Control base */ + +#define GEN9_GFX_MOCS_0 0xc800 /* Graphics MOCS base register*/ +#define GEN9_MFX0_MOCS_0 0xc900 /* Media 0 MOCS base register*/ +#define GEN9_MFX1_MOCS_0 0xca00 /* Media 1 MOCS base register*/ +#define GEN9_VEBOX_MOCS_0 0xcb00 /* Video MOCS base register*/ +#define GEN9_BLT_MOCS_0 0xcc00 /* Blitter MOCS base register*/ + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 971d7b0ae017..d7f66d289970 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -135,6 +135,7 @@ #include #include #include "i915_drv.h" +#include "intel_mocs.h" #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE) #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE) @@ -772,8 +773,7 @@ static int logical_ring_prepare(struct drm_i915_gem_request *req, int bytes) * * Return: non-zero if the ringbuffer is not ready to be written to. */ -static int intel_logical_ring_begin(struct drm_i915_gem_request *req, - int num_dwords) +int intel_logical_ring_begin(struct drm_i915_gem_request *req, int num_dwords) { struct drm_i915_private *dev_priv; int ret; @@ -1670,6 +1670,14 @@ static int gen8_init_rcs_context(struct drm_i915_gem_request *req) if (ret) return ret; + ret = intel_rcs_context_init_mocs(req); + /* + * Failing to program the MOCS is non-fatal.The system will not + * run at peak performance. So generate an error and carry on. + */ + if (ret) + DRM_ERROR("MOCS failed to program: expect performance issues.\n"); + return intel_lr_context_render_state_init(req); } diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index e0299fbb1728..64f89f9982a2 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -42,6 +42,7 @@ int intel_logical_ring_reserve_space(struct drm_i915_gem_request *request); void intel_logical_ring_stop(struct intel_engine_cs *ring); void intel_logical_ring_cleanup(struct intel_engine_cs *ring); int intel_logical_rings_init(struct drm_device *dev); +int intel_logical_ring_begin(struct drm_i915_gem_request *req, int num_dwords); int logical_ring_flush_all_caches(struct drm_i915_gem_request *req); /** diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c new file mode 100644 index 000000000000..6d3c6c0a5c62 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_mocs.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2015 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. + */ + +#include "intel_mocs.h" +#include "intel_lrc.h" +#include "intel_ringbuffer.h" + +/* structures required */ +struct drm_i915_mocs_entry { + u32 control_value; + u16 l3cc_value; +}; + +struct drm_i915_mocs_table { + u32 size; + const struct drm_i915_mocs_entry *table; +}; + +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */ +#define LE_CACHEABILITY(value) ((value) << 0) +#define LE_TGT_CACHE(value) ((value) << 2) +#define LE_LRUM(value) ((value) << 4) +#define LE_AOM(value) ((value) << 6) +#define LE_RSC(value) ((value) << 7) +#define LE_SCC(value) ((value) << 8) +#define LE_PFM(value) ((value) << 11) +#define LE_SCF(value) ((value) << 14) + +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */ +#define L3_ESC(value) ((value) << 0) +#define L3_SCC(value) ((value) << 1) +#define L3_CACHEABILITY(value) ((value) << 4) + +/* Helper defines */ +#define GEN9_NUM_MOCS_ENTRIES 62 /* 62 out of 64 - 63 & 64 are reserved. */ + +/* (e)LLC caching options */ +#define LE_PAGETABLE 0 +#define LE_UC 1 +#define LE_WT 2 +#define LE_WB 3 + +/* L3 caching options */ +#define L3_DIRECT 0 +#define L3_UC 1 +#define L3_RESERVED 2 +#define L3_WB 3 + +/* Target cache */ +#define ELLC 0 +#define LLC 1 +#define LLC_ELLC 2 + +/* + * MOCS tables + * + * These are the MOCS tables that are programmed across all the rings. + * The control value is programmed to all the rings that support the + * MOCS registers. While the l3cc_values are only programmed to the + * LNCFCMOCS0 - LNCFCMOCS32 registers. + * + * These tables are intended to be kept reasonably consistent across + * platforms. However some of the fields are not applicable to all of + * them. + * + * Entries not part of the following tables are undefined as far as + * userspace is concerned and shouldn't be relied upon. For the time + * being they will be implicitly initialized to the strictest caching + * configuration (uncached) to guarantee forwards compatibility with + * userspace programs written against more recent kernels providing + * additional MOCS entries. + * + * NOTE: These tables MUST start with being uncached and the length + * MUST be less than 63 as the last two registers are reserved + * by the hardware. These tables are part of the kernel ABI and + * may only be updated incrementally by adding entries at the + * end. + */ +static const struct drm_i915_mocs_entry skylake_mocs_table[] = { + /* { 0x00000009, 0x0010 } */ + { (LE_CACHEABILITY(LE_UC) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(0) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_UC)) }, + /* { 0x00000038, 0x0030 } */ + { (LE_CACHEABILITY(LE_PAGETABLE) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) }, + /* { 0x0000003b, 0x0030 } */ + { (LE_CACHEABILITY(LE_WB) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) } +}; + +/* NOTE: the LE_TGT_CACHE is not used on Broxton */ +static const struct drm_i915_mocs_entry broxton_mocs_table[] = { + /* { 0x00000009, 0x0010 } */ + { (LE_CACHEABILITY(LE_UC) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(0) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_UC)) }, + /* { 0x00000038, 0x0030 } */ + { (LE_CACHEABILITY(LE_PAGETABLE) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) }, + /* { 0x0000003b, 0x0030 } */ + { (LE_CACHEABILITY(LE_WB) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) } +}; + +/** + * get_mocs_settings() + * @dev: DRM device. + * @table: Output table that will be made to point at appropriate + * MOCS values for the device. + * + * This function will return the values of the MOCS table that needs to + * be programmed for the platform. It will return the values that need + * to be programmed and if they need to be programmed. + * + * Return: true if there are applicable MOCS settings for the device. + */ +static bool get_mocs_settings(struct drm_device *dev, + struct drm_i915_mocs_table *table) +{ + bool result = false; + + if (IS_SKYLAKE(dev)) { + table->size = ARRAY_SIZE(skylake_mocs_table); + table->table = skylake_mocs_table; + result = true; + } else if (IS_BROXTON(dev)) { + table->size = ARRAY_SIZE(broxton_mocs_table); + table->table = broxton_mocs_table; + result = true; + } else { + WARN_ONCE(INTEL_INFO(dev)->gen >= 9, + "Platform that should have a MOCS table does not.\n"); + } + + return result; +} + +/** + * emit_mocs_control_table() - emit the mocs control table + * @req: Request to set up the MOCS table for. + * @table: The values to program into the control regs. + * @reg_base: The base for the engine that needs to be programmed. + * + * This function simply emits a MI_LOAD_REGISTER_IMM command for the + * given table starting at the given address. + * + * Return: 0 on success, otherwise the error status. + */ +static int emit_mocs_control_table(struct drm_i915_gem_request *req, + const struct drm_i915_mocs_table *table, + u32 reg_base) +{ + struct intel_ringbuffer *ringbuf = req->ringbuf; + unsigned int index; + int ret; + + if (WARN_ON(table->size > GEN9_NUM_MOCS_ENTRIES)) + return -ENODEV; + + ret = intel_logical_ring_begin(req, 2 + 2 * GEN9_NUM_MOCS_ENTRIES); + if (ret) { + DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret); + return ret; + } + + intel_logical_ring_emit(ringbuf, + MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES)); + + for (index = 0; index < table->size; index++) { + intel_logical_ring_emit(ringbuf, reg_base + index * 4); + intel_logical_ring_emit(ringbuf, + table->table[index].control_value); + } + + /* + * Ok, now set the unused entries to uncached. These entries + * are officially undefined and no contract for the contents + * and settings is given for these entries. + * + * Entry 0 in the table is uncached - so we are just writing + * that value to all the used entries. + */ + for (; index < GEN9_NUM_MOCS_ENTRIES; index++) { + intel_logical_ring_emit(ringbuf, reg_base + index * 4); + intel_logical_ring_emit(ringbuf, table->table[0].control_value); + } + + intel_logical_ring_emit(ringbuf, MI_NOOP); + intel_logical_ring_advance(ringbuf); + + return 0; +} + +/** + * emit_mocs_l3cc_table() - emit the mocs control table + * @req: Request to set up the MOCS table for. + * @table: The values to program into the control regs. + * + * This function simply emits a MI_LOAD_REGISTER_IMM command for the + * given table starting at the given address. This register set is + * programmed in pairs. + * + * Return: 0 on success, otherwise the error status. + */ +static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req, + const struct drm_i915_mocs_table *table) +{ + struct intel_ringbuffer *ringbuf = req->ringbuf; + unsigned int count; + unsigned int i; + u32 value; + u32 filler = (table->table[0].l3cc_value & 0xffff) | + ((table->table[0].l3cc_value & 0xffff) << 16); + int ret; + + if (WARN_ON(table->size > GEN9_NUM_MOCS_ENTRIES)) + return -ENODEV; + + ret = intel_logical_ring_begin(req, 2 + GEN9_NUM_MOCS_ENTRIES); + if (ret) { + DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret); + return ret; + } + + intel_logical_ring_emit(ringbuf, + MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2)); + + for (i = 0, count = 0; i < table->size / 2; i++, count += 2) { + value = (table->table[count].l3cc_value & 0xffff) | + ((table->table[count + 1].l3cc_value & 0xffff) << 16); + + intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4); + intel_logical_ring_emit(ringbuf, value); + } + + if (table->size & 0x01) { + /* Odd table size - 1 left over */ + value = (table->table[count].l3cc_value & 0xffff) | + ((table->table[0].l3cc_value & 0xffff) << 16); + } else + value = filler; + + /* + * Now set the rest of the table to uncached - use entry 0 as + * this will be uncached. Leave the last pair uninitialised as + * they are reserved by the hardware. + */ + for (; i < GEN9_NUM_MOCS_ENTRIES / 2; i++) { + intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4); + intel_logical_ring_emit(ringbuf, value); + + value = filler; + } + + intel_logical_ring_emit(ringbuf, MI_NOOP); + intel_logical_ring_advance(ringbuf); + + return 0; +} + +/** + * intel_rcs_context_init_mocs() - program the MOCS register. + * @req: Request to set up the MOCS tables for. + * + * This function will emit a batch buffer with the values required for + * programming the MOCS register values for all the currently supported + * rings. + * + * These registers are partially stored in the RCS context, so they are + * emitted at the same time so that when a context is created these registers + * are set up. These registers have to be emitted into the start of the + * context as setting the ELSP will re-init some of these registers back + * to the hw values. + * + * Return: 0 on success, otherwise the error status. + */ +int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req) +{ + struct drm_i915_mocs_table t; + int ret; + + if (get_mocs_settings(req->ring->dev, &t)) { + /* Program the control registers */ + ret = emit_mocs_control_table(req, &t, GEN9_GFX_MOCS_0); + if (ret) + return ret; + + ret = emit_mocs_control_table(req, &t, GEN9_MFX0_MOCS_0); + if (ret) + return ret; + + ret = emit_mocs_control_table(req, &t, GEN9_MFX1_MOCS_0); + if (ret) + return ret; + + ret = emit_mocs_control_table(req, &t, GEN9_VEBOX_MOCS_0); + if (ret) + return ret; + + ret = emit_mocs_control_table(req, &t, GEN9_BLT_MOCS_0); + if (ret) + return ret; + + /* Now program the l3cc registers */ + ret = emit_mocs_l3cc_table(req, &t); + if (ret) + return ret; + } + + return 0; +} diff --git a/drivers/gpu/drm/i915/intel_mocs.h b/drivers/gpu/drm/i915/intel_mocs.h new file mode 100644 index 000000000000..76e45b1748b3 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_mocs.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015 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. + */ + +#ifndef INTEL_MOCS_H +#define INTEL_MOCS_H + +/** + * DOC: Memory Objects Control State (MOCS) + * + * Motivation: + * In previous Gens the MOCS settings was a value that was set by user land as + * part of the batch. In Gen9 this has changed to be a single table (per ring) + * that all batches now reference by index instead of programming the MOCS + * directly. + * + * The one wrinkle in this is that only PART of the MOCS tables are included + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 - LNCFCMOCS32 + * registers). The rest are not (the settings for the other rings). + * + * This table needs to be set at system start-up because the way the table + * interacts with the contexts and the GmmLib interface. + * + * + * Implementation: + * + * The tables (one per supported platform) are defined in intel_mocs.c + * and are programmed in the first batch after the context is loaded + * (with the hardware workarounds). This will then let the usual + * context handling keep the MOCS in step. + */ + +#include +#include "i915_drv.h" + +int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req); + +#endif -- cgit v1.3-6-gb490 From 4cf0ebbd4fafbdf8e6431dbb315e5511c3efdc3b Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:20 +0200 Subject: drm/i915: Rework plane readout. All non-primary planes get disabled during hw readout, this reduces complexity and means not having to do some plane visibility checks during the first commit. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 7 --- drivers/gpu/drm/i915/intel_display.c | 86 ++++-------------------------------- drivers/gpu/drm/i915/intel_drv.h | 1 - 3 files changed, 8 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index b92b8581efc2..dcf4fb458649 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -98,13 +98,6 @@ int intel_atomic_check(struct drm_device *dev, return -EINVAL; } - if (crtc_state && - crtc_state->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) { - ret = drm_atomic_add_affected_planes(state, &nuclear_crtc->base); - if (ret) - return ret; - } - ret = drm_atomic_helper_check_planes(dev, state); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b0a3120c6da1..ba2c933fcea2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11781,34 +11781,6 @@ static bool check_encoder_cloning(struct drm_atomic_state *state, return true; } -static void intel_crtc_check_initial_planes(struct drm_crtc *crtc, - struct drm_crtc_state *crtc_state) -{ - struct intel_crtc_state *pipe_config = - to_intel_crtc_state(crtc_state); - struct drm_plane *p; - unsigned visible_mask = 0; - - drm_for_each_plane_mask(p, crtc->dev, crtc_state->plane_mask) { - struct drm_plane_state *plane_state = - drm_atomic_get_existing_plane_state(crtc_state->state, p); - - if (WARN_ON(!plane_state)) - continue; - - if (!plane_state->fb) - crtc_state->plane_mask &= - ~(1 << drm_plane_index(p)); - else if (to_intel_plane_state(plane_state)->visible) - visible_mask |= 1 << drm_plane_index(p); - } - - if (!visible_mask) - return; - - pipe_config->quirks &= ~PIPE_CONFIG_QUIRK_INITIAL_PLANES; -} - static int intel_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { @@ -11830,10 +11802,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n", idx, crtc->state->active, intel_crtc->active); - /* plane mask is fixed up after all initial planes are calculated */ - if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) - intel_crtc_check_initial_planes(crtc, crtc_state); - if (mode_changed && !crtc_state->active) intel_crtc->atomic.update_wm_post = true; @@ -13186,19 +13154,6 @@ intel_modeset_compute_config(struct drm_atomic_state *state) continue; } - if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) { - ret = drm_atomic_add_affected_planes(state, crtc); - if (ret) - return ret; - - /* - * We ought to handle i915.fastboot here. - * If no modeset is required and the primary plane has - * a fb, update the members of crtc_state as needed, - * and run the necessary updates during vblank evasion. - */ - } - modeset = needs_modeset(crtc_state); recalc = pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE; @@ -15456,47 +15411,22 @@ static void readout_plane_state(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state) { struct intel_plane *p; - struct drm_plane_state *drm_plane_state; + struct intel_plane_state *plane_state; bool active = crtc_state->base.active; - if (active) { - crtc_state->quirks |= PIPE_CONFIG_QUIRK_INITIAL_PLANES; - - /* apply to previous sw state too */ - to_intel_crtc_state(crtc->base.state)->quirks |= - PIPE_CONFIG_QUIRK_INITIAL_PLANES; - } - for_each_intel_plane(crtc->base.dev, p) { - bool visible = active; - if (crtc->pipe != p->pipe) continue; - drm_plane_state = p->base.state; - - /* Plane scaler state is not touched here. The first atomic - * commit will restore all plane scalers to its old state. - */ + plane_state = to_intel_plane_state(p->base.state); - if (active && p->base.type == DRM_PLANE_TYPE_PRIMARY) { - visible = primary_get_hw_state(crtc); - to_intel_plane_state(drm_plane_state)->visible = visible; - } else { - /* - * unknown state, assume it's off to force a transition - * to on when calculating state changes. - */ - to_intel_plane_state(drm_plane_state)->visible = false; - } + if (p->base.type == DRM_PLANE_TYPE_PRIMARY) + plane_state->visible = primary_get_hw_state(crtc); + else { + if (active) + p->disable_plane(&p->base, &crtc->base); - if (visible) { - crtc_state->base.plane_mask |= - 1 << drm_plane_index(&p->base); - } else if (crtc_state->base.state) { - /* Make this unconditional for atomic hw readout. */ - crtc_state->base.plane_mask &= - ~(1 << drm_plane_index(&p->base)); + plane_state->visible = false; } } } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 09e3581c8441..2c23900b491f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -341,7 +341,6 @@ struct intel_crtc_state { */ #define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ #define PIPE_CONFIG_QUIRK_INHERITED_MODE (1<<1) /* mode inherited from firmware */ -#define PIPE_CONFIG_QUIRK_INITIAL_PLANES (1<<2) /* planes are in unknown state */ unsigned long quirks; /* Pipe source size (ie. panel fitter input size) -- cgit v1.3-6-gb490 From b06f8b0df73dea39337e394805827491d0b1585c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 13:42:49 +0200 Subject: drm/i915: Fix reference leak in intel_modeset_readout_hw_state. Unreference the old mode_blob by calling the crtc_destroy_state helper before zeroing the crtc_state. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ba2c933fcea2..4325d00a4598 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15441,6 +15441,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) int i; for_each_intel_crtc(dev, crtc) { + __drm_atomic_helper_crtc_destroy_state(&crtc->base, crtc->base.state); memset(crtc->config, 0, sizeof(*crtc->config)); crtc->config->base.crtc = &crtc->base; -- cgit v1.3-6-gb490 From 4be40c987aa0867a8fa77c12d5ed6fa2f8853dbc Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 13:45:32 +0200 Subject: drm/i915: Zero the mode in intel_sanitize_crtc when force disabling. There is a WARN_ON in drm_atomic_crtc_check for this when exposing the atomic property. If the mode_blob still exists, but enable = false then all updates are rejected with -EINVAL. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4325d00a4598..5254a3a5a268 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15291,7 +15291,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) crtc->base.state->enable ? "enabled" : "disabled", crtc->active ? "enabled" : "disabled"); - crtc->base.state->enable = crtc->active; + WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, NULL) < 0); crtc->base.state->active = crtc->active; crtc->base.enabled = crtc->active; -- cgit v1.3-6-gb490 From 3a03dfb057d0ee5f3146ffe40179af3ed7e48213 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 13:46:40 +0200 Subject: drm/i915: Calculate vblank timestamping constants before enabling vblank. This is required to properly initialize vblanks on the active crtc. Without it drm_calc_vbltimestamp_from_scanoutpos can fail with crtc 0: Noop due to uninitialized mode. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5254a3a5a268..1b8a17c67ff5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15239,6 +15239,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) /* restore vblank interrupts to correct state */ drm_crtc_vblank_reset(&crtc->base); if (crtc->active) { + drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode); update_scanline_offset(crtc); drm_crtc_vblank_on(&crtc->base); } -- cgit v1.3-6-gb490 From 5c1e34261907736dc3b3a7219b2f48f353f10a93 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 15:58:28 +0200 Subject: drm/i915: Readout initial hw mode. drm/i915: Readout initial hw mode, v2. Atomic requires a mode blob when crtc_state->enable is true, or you get a huge warn_on. With a few tweaks the mode we read out from hardware could be used as the real mode without a modeset, but this requires too much testing, so for now force a modeset the first time the mode blob's updated. This preserves the old behavior, because previously we never set the initial mode, which always meant that a modeset happened when the mode was first set. Changes since v1: - Add a description in intel_modeset_readout_hw_state of how the recalculation is done. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 62 ++++++++++++++++++++++++------------ drivers/gpu/drm/i915/intel_fbdev.c | 11 ++----- 2 files changed, 44 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1b8a17c67ff5..a1341cbd40e0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13146,7 +13146,7 @@ intel_modeset_compute_config(struct drm_atomic_state *state) for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); - bool modeset, recalc; + bool modeset, recalc = false; if (!crtc_state->enable) { if (needs_modeset(crtc_state)) @@ -13155,7 +13155,10 @@ intel_modeset_compute_config(struct drm_atomic_state *state) } modeset = needs_modeset(crtc_state); - recalc = pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE; + /* see comment in intel_modeset_readout_hw_state */ + if (!modeset && crtc_state->mode_blob != crtc->state->mode_blob && + pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE) + recalc = true; if (!modeset && !recalc) continue; @@ -13170,9 +13173,10 @@ intel_modeset_compute_config(struct drm_atomic_state *state) if (ret) return ret; - if (recalc && !intel_pipe_config_compare(state->dev, + if (recalc && (!i915.fastboot || + !intel_pipe_config_compare(state->dev, to_intel_crtc_state(crtc->state), - pipe_config, true)) { + pipe_config, true))) { modeset = crtc_state->mode_changed = true; ret = drm_atomic_add_affected_planes(state, crtc); @@ -15451,11 +15455,42 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) crtc->active = dev_priv->display.get_pipe_config(crtc, crtc->config); - crtc->base.state->enable = crtc->active; crtc->base.state->active = crtc->active; crtc->base.enabled = crtc->active; - crtc->base.hwmode = crtc->config->base.adjusted_mode; + memset(&crtc->base.mode, 0, sizeof(crtc->base.mode)); + if (crtc->base.state->active) { + intel_mode_from_pipe_config(&crtc->base.mode, crtc->config); + intel_mode_from_pipe_config(&crtc->base.state->adjusted_mode, crtc->config); + WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, &crtc->base.mode)); + + /* + * The initial mode needs to be set in order to keep + * the atomic core happy. It wants a valid mode if the + * crtc's enabled, so we do the above call. + * + * At this point some state updated by the connectors + * in their ->detect() callback has not run yet, so + * no recalculation can be done yet. + * + * Even if we could do a recalculation and modeset + * right now it would cause a double modeset if + * fbdev or userspace chooses a different initial mode. + * + * So to prevent the double modeset, fail the memcmp + * test in drm_atomic_set_mode_for_crtc to get a new + * mode blob, and compare if the mode blob changed + * when the PIPE_CONFIG_QUIRK_INHERITED_MODE quirk is + * set. + * + * If that happens, someone indicated they wanted a + * mode change, which means it's safe to do a full + * recalculation. + */ + crtc->base.state->mode.private_flags = ~0; + } + + crtc->base.hwmode = crtc->config->base.adjusted_mode; readout_plane_state(crtc, to_intel_crtc_state(crtc->base.state)); DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", @@ -15532,21 +15567,6 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, intel_modeset_readout_hw_state(dev); - /* - * Now that we have the config, copy it to each CRTC struct - * Note that this could go away if we move to using crtc_config - * checking everywhere. - */ - for_each_intel_crtc(dev, crtc) { - if (crtc->active && i915.fastboot) { - intel_mode_from_pipe_config(&crtc->base.mode, - crtc->config); - DRM_DEBUG_KMS("[CRTC:%d] found active mode: ", - crtc->base.base.id); - drm_mode_debug_printmodeline(&crtc->base.mode); - } - } - /* HW state is read out, now we need to sanitize this mess. */ for_each_intel_encoder(dev, encoder) { intel_sanitize_encoder(encoder); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index b791f2374f3b..7eff33ff84f6 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -483,18 +483,13 @@ retry: * IMPORTANT: We want to use the adjusted mode (i.e. * after the panel fitter upscaling) as the initial * config, not the input mode, which is what crtc->mode - * usually contains. But since our current fastboot + * usually contains. But since our current * code puts a mode derived from the post-pfit timings - * into crtc->mode this works out correctly. We don't - * use hwmode anywhere right now, so use it for this - * since the fb helper layer wants a pointer to - * something we own. + * into crtc->mode this works out correctly. */ DRM_DEBUG_KMS("looking for current mode on connector %s\n", connector->name); - intel_mode_from_pipe_config(&encoder->crtc->hwmode, - to_intel_crtc(encoder->crtc)->config); - modes[i] = &encoder->crtc->hwmode; + modes[i] = &encoder->crtc->mode; } crtcs[i] = new_crtc; -- cgit v1.3-6-gb490 From 043e9bda6b7bf6ff83576c65a40becc5054e827d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:25 +0200 Subject: drm/i915: Convert resume to atomic. Instead of all the ad-hoc updating, duplicate the old state first before reading out the hw state, then restore it. intel_display_resume is a new function that duplicates the sw state, then reads out the hw state, and commits the old state. intel_display_setup_hw_state now only reads out the atomic state. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90396 Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone 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/intel_display.c | 77 ++++++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_lvds.c | 2 +- 4 files changed, 60 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e44dc0d6656f..db48aee7f140 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -741,7 +741,7 @@ static int i915_drm_resume(struct drm_device *dev) spin_unlock_irq(&dev_priv->irq_lock); drm_modeset_lock_all(dev); - intel_modeset_setup_hw_state(dev, true); + intel_display_resume(dev); drm_modeset_unlock_all(dev); intel_dp_mst_resume(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 52d07fbd9cc8..45bbc19883f1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3277,8 +3277,7 @@ extern void intel_modeset_gem_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); extern void intel_connector_unregister(struct intel_connector *); 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 intel_display_resume(struct drm_device *dev); extern void i915_redisable_vga(struct drm_device *dev); extern void i915_redisable_vga_power_on(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 a1341cbd40e0..b7f17e8a556e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -109,6 +109,7 @@ static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_cr struct intel_crtc_state *crtc_state); static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state, int num_connectors); +static void intel_modeset_setup_hw_state(struct drm_device *dev); static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) { @@ -3251,7 +3252,7 @@ void intel_finish_reset(struct drm_device *dev) dev_priv->display.hpd_irq_setup(dev); spin_unlock_irq(&dev_priv->irq_lock); - intel_modeset_setup_hw_state(dev, true); + intel_display_resume(dev); intel_hpd_init(dev_priv); @@ -15157,7 +15158,7 @@ void intel_modeset_init(struct drm_device *dev) intel_fbc_disable(dev_priv); drm_modeset_lock_all(dev); - intel_modeset_setup_hw_state(dev, false); + intel_modeset_setup_hw_state(dev); drm_modeset_unlock_all(dev); for_each_intel_crtc(dev, crtc) { @@ -15554,10 +15555,11 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) } } -/* Scan out the current hw modeset state, sanitizes it and maps it into the drm - * and i915 state tracking structures. */ -void intel_modeset_setup_hw_state(struct drm_device *dev, - bool force_restore) +/* Scan out the current hw modeset state, + * and sanitizes it to the current state + */ +static void +intel_modeset_setup_hw_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe; @@ -15600,24 +15602,59 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, else if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); - if (force_restore) { - i915_redisable_vga(dev); + intel_modeset_update_staged_output_state(dev); +} - /* - * We need to use raw interfaces for restoring state to avoid - * checking (bogus) intermediate states. - */ - for_each_pipe(dev_priv, pipe) { - struct drm_crtc *crtc = - dev_priv->pipe_to_crtc_mapping[pipe]; +void intel_display_resume(struct drm_device *dev) +{ + struct drm_atomic_state *state = drm_atomic_state_alloc(dev); + struct intel_connector *conn; + struct intel_plane *plane; + struct drm_crtc *crtc; + int ret; - intel_crtc_restore_mode(crtc); - } - } else { - intel_modeset_update_staged_output_state(dev); + if (!state) + return; + + state->acquire_ctx = dev->mode_config.acquire_ctx; + + /* preserve complete old state, including dpll */ + intel_atomic_get_shared_dpll_state(state); + + for_each_crtc(dev, crtc) { + struct drm_crtc_state *crtc_state = + drm_atomic_get_crtc_state(state, crtc); + + ret = PTR_ERR_OR_ZERO(crtc_state); + if (ret) + goto err; + + /* force a restore */ + crtc_state->mode_changed = true; } - intel_modeset_check_state(dev); + for_each_intel_plane(dev, plane) { + ret = PTR_ERR_OR_ZERO(drm_atomic_get_plane_state(state, &plane->base)); + if (ret) + goto err; + } + + for_each_intel_connector(dev, conn) { + ret = PTR_ERR_OR_ZERO(drm_atomic_get_connector_state(state, &conn->base)); + if (ret) + goto err; + } + + intel_modeset_setup_hw_state(dev); + + i915_redisable_vga(dev); + ret = intel_set_mode(state); + if (!ret) + return; + +err: + DRM_ERROR("Restoring old state failed with %i\n", ret); + drm_atomic_state_free(state); } void intel_modeset_gem_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 937e8216e9d6..cb634f48e7d9 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -473,7 +473,7 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, */ if (!HAS_PCH_SPLIT(dev)) { drm_modeset_lock_all(dev); - intel_modeset_setup_hw_state(dev, true); + intel_display_resume(dev); drm_modeset_unlock_all(dev); } -- cgit v1.3-6-gb490 From ad3c558fb92f725858494f6b3f0befcd89cbb41c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:26 +0200 Subject: drm/i915: Get rid of unused transitional members. The previous commit converted hw readout to atomic, all the new_* members were used for restoring the old state, but with the conversion of suspend to atomic there's no use left for them. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 80 ++++++++---------------------------- drivers/gpu/drm/i915/intel_drv.h | 12 ------ 2 files changed, 18 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b7f17e8a556e..bb9edd049e90 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10247,7 +10247,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, retry: ret = drm_modeset_lock(&config->connection_mutex, ctx); if (ret) - goto fail_unlock; + goto fail; /* * Algorithm gets a little messy: @@ -10265,10 +10265,10 @@ retry: ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; old->dpms_mode = connector->dpms; old->load_detect_temp = false; @@ -10287,9 +10287,6 @@ retry: continue; if (possible_crtc->state->enable) continue; - /* This can occur when applying the pipe A quirk on resume. */ - if (to_intel_crtc(possible_crtc)->new_enabled) - continue; crtc = possible_crtc; break; @@ -10300,20 +10297,17 @@ retry: */ if (!crtc) { DRM_DEBUG_KMS("no pipe available for load-detect\n"); - goto fail_unlock; + goto fail; } ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail_unlock; - intel_encoder->new_crtc = to_intel_crtc(crtc); - to_intel_connector(connector)->new_encoder = intel_encoder; + goto fail; intel_crtc = to_intel_crtc(crtc); - intel_crtc->new_enabled = true; old->dpms_mode = connector->dpms; old->load_detect_temp = true; old->release_fb = NULL; @@ -10381,9 +10375,7 @@ retry: intel_wait_for_vblank(dev, intel_crtc->pipe); return true; - fail: - intel_crtc->new_enabled = crtc->state->enable; -fail_unlock: +fail: drm_atomic_state_free(state); state = NULL; @@ -10429,10 +10421,6 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (IS_ERR(crtc_state)) goto fail; - to_intel_connector(connector)->new_encoder = NULL; - intel_encoder->new_crtc = NULL; - intel_crtc->new_enabled = false; - connector_state->best_encoder = NULL; connector_state->crtc = NULL; @@ -11836,37 +11824,6 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = { .atomic_check = intel_crtc_atomic_check, }; -/** - * intel_modeset_update_staged_output_state - * - * Updates the staged output configuration state, e.g. after we've read out the - * current hw state. - */ -static void intel_modeset_update_staged_output_state(struct drm_device *dev) -{ - struct intel_crtc *crtc; - struct intel_encoder *encoder; - struct intel_connector *connector; - - for_each_intel_connector(dev, connector) { - connector->new_encoder = - to_intel_encoder(connector->base.encoder); - } - - for_each_intel_encoder(dev, encoder) { - encoder->new_crtc = - to_intel_crtc(encoder->base.crtc); - } - - for_each_intel_crtc(dev, crtc) { - crtc->new_enabled = crtc->base.state->enable; - } -} - -/* Transitional helper to copy current connector/encoder state to - * connector->state. This is needed so that code that is partially - * converted to atomic does the right thing. - */ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev) { struct intel_connector *connector; @@ -12307,7 +12264,6 @@ intel_modeset_update_state(struct drm_atomic_state *state) } drm_atomic_helper_update_legacy_modeset_state(state->dev, state); - intel_modeset_update_staged_output_state(state->dev); /* Double check state. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { @@ -12707,11 +12663,14 @@ check_connector_state(struct drm_device *dev) struct intel_connector *connector; for_each_intel_connector(dev, connector) { + struct drm_encoder *encoder = connector->base.encoder; + struct drm_connector_state *state = connector->base.state; + /* This also checks the encoder/connector hw state with the * ->get_hw_state callbacks. */ intel_connector_check_state(connector); - I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder, + I915_STATE_WARN(state->best_encoder != encoder, "connector's staged encoder doesn't match current encoder\n"); } } @@ -12731,8 +12690,6 @@ check_encoder_state(struct drm_device *dev) encoder->base.base.id, encoder->base.name); - I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc, - "encoder's stage crtc doesn't match current crtc\n"); I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc, "encoder's active_connectors set, but no crtc\n"); @@ -12742,6 +12699,10 @@ check_encoder_state(struct drm_device *dev) enabled = true; if (connector->base.dpms != DRM_MODE_DPMS_OFF) active = true; + + I915_STATE_WARN(connector->base.state->crtc != + encoder->base.crtc, + "connector's crtc doesn't match encoder crtc\n"); } /* * for MST connectors if we unplug the connector is gone @@ -13312,11 +13273,12 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) * need to copy the staged config to the atomic state, otherwise the * mode set will just reapply the state the HW is already in. */ for_each_intel_encoder(dev, encoder) { - if (&encoder->new_crtc->base != crtc) + if (encoder->base.crtc != crtc) continue; for_each_intel_connector(dev, connector) { - if (connector->new_encoder != encoder) + if (connector->base.state->best_encoder != + &encoder->base) continue; connector_state = drm_atomic_get_connector_state(state, &connector->base); @@ -13329,7 +13291,6 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) } connector_state->crtc = crtc; - connector_state->best_encoder = &encoder->base; } } @@ -13341,9 +13302,6 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) return; } - crtc_state->base.active = crtc_state->base.enable = - to_intel_crtc(crtc)->new_enabled; - drm_mode_copy(&crtc_state->base.mode, &crtc->mode); intel_modeset_setup_plane_state(state, crtc, &crtc->mode, @@ -15601,8 +15559,6 @@ intel_modeset_setup_hw_state(struct drm_device *dev) skl_wm_get_hw_state(dev); else if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); - - intel_modeset_update_staged_output_state(dev); } void intel_display_resume(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2c23900b491f..217b773e0673 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -130,11 +130,6 @@ struct intel_fbdev { struct intel_encoder { struct drm_encoder base; - /* - * The new crtc this encoder will be driven from. Only differs from - * base->crtc while a modeset is in progress. - */ - struct intel_crtc *new_crtc; enum intel_output_type type; unsigned int cloneable; @@ -195,12 +190,6 @@ struct intel_connector { */ struct intel_encoder *encoder; - /* - * The new encoder this connector will be driven. Only differs from - * encoder while a modeset is in progress. - */ - struct intel_encoder *new_encoder; - /* Reads out the current hw, returning true if the connector is enabled * and active (i.e. dpms ON state). */ bool (*get_hw_state)(struct intel_connector *); @@ -550,7 +539,6 @@ struct intel_crtc { uint32_t cursor_base; struct intel_crtc_state *config; - bool new_enabled; /* reset counter value when the last flip was submitted */ unsigned int reset_counter; -- cgit v1.3-6-gb490 From 292b990e86abc42cba683fda1a56dc5f253a1d3e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:27 +0200 Subject: drm/i915: Update power domains on readout. This allows us to get rid of the set_init_power in modeset_update_crtc_domains. The state should be sanitized enough after setup_hw_state to not need the init power. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 76 ++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bb9edd049e90..ee1124813af9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5196,6 +5196,9 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc) unsigned long mask; enum transcoder transcoder; + if (!crtc->state->active) + return 0; + transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe); mask = BIT(POWER_DOMAIN_PIPE(pipe)); @@ -5210,27 +5213,46 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc) return mask; } -static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) +static unsigned long modeset_get_crtc_power_domains(struct drm_crtc *crtc) { - struct drm_device *dev = state->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long pipe_domains[I915_MAX_PIPES] = { 0, }; - struct intel_crtc *crtc; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum intel_display_power_domain domain; + unsigned long domains, new_domains, old_domains; - /* - * First get all needed power domains, then put all unneeded, to avoid - * any unnecessary toggling of the power wells. - */ - for_each_intel_crtc(dev, crtc) { - enum intel_display_power_domain domain; + old_domains = intel_crtc->enabled_power_domains; + intel_crtc->enabled_power_domains = new_domains = get_crtc_power_domains(crtc); - if (!crtc->base.state->enable) - continue; + domains = new_domains & ~old_domains; + + for_each_power_domain(domain, domains) + intel_display_power_get(dev_priv, domain); + + return old_domains & ~new_domains; +} + +static void modeset_put_power_domains(struct drm_i915_private *dev_priv, + unsigned long domains) +{ + enum intel_display_power_domain domain; + + for_each_power_domain(domain, domains) + intel_display_power_put(dev_priv, domain); +} - pipe_domains[crtc->pipe] = get_crtc_power_domains(&crtc->base); +static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long put_domains[I915_MAX_PIPES] = {}; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + int i; - for_each_power_domain(domain, pipe_domains[crtc->pipe]) - intel_display_power_get(dev_priv, domain); + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (needs_modeset(crtc->state)) + put_domains[to_intel_crtc(crtc)->pipe] = + modeset_get_crtc_power_domains(crtc); } if (dev_priv->display.modeset_commit_cdclk) { @@ -5241,16 +5263,9 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) dev_priv->display.modeset_commit_cdclk(state); } - for_each_intel_crtc(dev, crtc) { - 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); + for (i = 0; i < I915_MAX_PIPES; i++) + if (put_domains[i]) + modeset_put_power_domains(dev_priv, put_domains[i]); } static void intel_update_max_cdclk(struct drm_device *dev) @@ -15559,6 +15574,15 @@ intel_modeset_setup_hw_state(struct drm_device *dev) skl_wm_get_hw_state(dev); else if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); + + for_each_intel_crtc(dev, crtc) { + unsigned long put_domains; + + put_domains = modeset_get_crtc_power_domains(&crtc->base); + if (WARN_ON(put_domains)) + modeset_put_power_domains(dev_priv, put_domains); + } + intel_display_set_init_power(dev_priv, false); } void intel_display_resume(struct drm_device *dev) -- cgit v1.3-6-gb490 From e694eb020f12949a3eb12d4bb4957f0237961b2d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 16:19:12 +0200 Subject: drm/i915: Always force a modeset in intel_crtc_restore_mode, v2. And get rid of things that are no longer true. This function is only used for forcing a modeset when encoder properties are changed. Because this is not yet done atomically, assume a full modeset is needed and force a modeset on the crtc. Changes since v1: - s/reset/force modeset/ Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 58 ++++++++++-------------------------- 1 file changed, 16 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ee1124813af9..f9ed3732f95f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13267,63 +13267,37 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_atomic_state *state; - struct intel_encoder *encoder; - struct intel_connector *connector; - struct drm_connector_state *connector_state; - struct intel_crtc_state *crtc_state; + struct drm_crtc_state *crtc_state; int ret; state = drm_atomic_state_alloc(dev); if (!state) { - DRM_DEBUG_KMS("[CRTC:%d] mode restore failed, out of memory", + DRM_DEBUG_KMS("[CRTC:%d] crtc restore failed, out of memory", crtc->base.id); return; } - state->acquire_ctx = dev->mode_config.acquire_ctx; - - /* The force restore path in the HW readout code relies on the staged - * config still keeping the user requested config while the actual - * state has been overwritten by the configuration read from HW. We - * need to copy the staged config to the atomic state, otherwise the - * mode set will just reapply the state the HW is already in. */ - for_each_intel_encoder(dev, encoder) { - if (encoder->base.crtc != crtc) - continue; + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); - for_each_intel_connector(dev, connector) { - if (connector->base.state->best_encoder != - &encoder->base) - continue; - - connector_state = drm_atomic_get_connector_state(state, &connector->base); - if (IS_ERR(connector_state)) { - DRM_DEBUG_KMS("Failed to add [CONNECTOR:%d:%s] to state: %ld\n", - connector->base.base.id, - connector->base.name, - PTR_ERR(connector_state)); - continue; - } +retry: + crtc_state = drm_atomic_get_crtc_state(state, crtc); + ret = PTR_ERR_OR_ZERO(crtc_state); + if (!ret) { + if (!crtc_state->active) + goto out; - connector_state->crtc = crtc; - } + crtc_state->mode_changed = true; + ret = intel_set_mode(state); } - crtc_state = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc)); - if (IS_ERR(crtc_state)) { - DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n", - crtc->base.id, PTR_ERR(crtc_state)); - drm_atomic_state_free(state); - return; + if (ret == -EDEADLK) { + drm_atomic_state_clear(state); + drm_modeset_backoff(state->acquire_ctx); + goto retry; } - drm_mode_copy(&crtc_state->base.mode, &crtc->mode); - - intel_modeset_setup_plane_state(state, crtc, &crtc->mode, - crtc->primary->fb, crtc->x, crtc->y); - - ret = intel_set_mode(state); if (ret) +out: drm_atomic_state_free(state); } -- cgit v1.3-6-gb490 From 70e0bd74b9a22ecaa25793bf4f461cf84a1f348a Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:29 +0200 Subject: drm/i915: Make intel_display_suspend atomic, try 2. Calculate all state using a normal transition, but afterwards fudge crtc->state->active back to its old value. This should still allow state restore in setup_hw_state to work properly. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 52 +++++++++++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 50 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f9ed3732f95f..4e64dae78360 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6225,12 +6225,58 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) * turn all crtc's off, but do not adjust state * This has to be paired with a call to intel_modeset_setup_hw_state. */ -void intel_display_suspend(struct drm_device *dev) +int intel_display_suspend(struct drm_device *dev) { + struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; + struct drm_atomic_state *state; struct drm_crtc *crtc; + unsigned crtc_mask = 0; + int ret = 0; + + if (WARN_ON(!ctx)) + return 0; + + lockdep_assert_held(&ctx->ww_ctx); + state = drm_atomic_state_alloc(dev); + if (WARN_ON(!state)) + return -ENOMEM; + + state->acquire_ctx = ctx; + state->allow_modeset = true; + + for_each_crtc(dev, crtc) { + struct drm_crtc_state *crtc_state = + drm_atomic_get_crtc_state(state, crtc); - for_each_crtc(dev, crtc) - intel_crtc_disable_noatomic(crtc); + ret = PTR_ERR_OR_ZERO(crtc_state); + if (ret) + goto free; + + if (!crtc_state->active) + continue; + + crtc_state->active = false; + crtc_mask |= 1 << drm_crtc_index(crtc); + } + + if (crtc_mask) { + ret = intel_set_mode(state); + + if (!ret) { + for_each_crtc(dev, crtc) + if (crtc_mask & (1 << drm_crtc_index(crtc))) + crtc->state->active = true; + + return ret; + } + } + +free: + if (ret) + DRM_ERROR("Suspending crtc's failed with %i\n", ret); + drm_atomic_state_free(state); + return ret; } /* Master function to enable/disable CRTC and corresponding power wells */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 217b773e0673..f4abce103221 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -988,7 +988,7 @@ int intel_pch_rawclk(struct drm_device *dev); void intel_mark_busy(struct drm_device *dev); void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); -void intel_display_suspend(struct drm_device *dev); +int intel_display_suspend(struct drm_device *dev); int intel_crtc_control(struct drm_crtc *crtc, bool enable); void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); -- cgit v1.3-6-gb490 From 97d3308ab245c51ae237b3444afa7ae87aa9bcd4 Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:23 +0530 Subject: drm/i915: Add HAS_CORE_RING_FREQ macro Added a new HAS_CORE_RING_FREQ macro, currently used in gen6_update_ring_freq & i915_ring_freq_table debugfs function. The programming & read of ring frequency table is needed for newer GEN(>=6) platforms, except VLV/CHV. Issue: VIZ-5144 Suggested-by: Daniel Vetter Signed-off-by: Akash Goel 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/intel_pm.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 27f0a0d98e3a..f3f014df61a3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1784,7 +1784,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) int gpu_freq, ia_freq; unsigned int max_gpu_freq, min_gpu_freq; - if (!(IS_GEN6(dev) || IS_GEN7(dev))) { + if (!HAS_CORE_RING_FREQ(dev)) { seq_puts(m, "unsupported on this chipset\n"); return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 45bbc19883f1..661135691d6b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2548,6 +2548,9 @@ struct drm_i915_cmd_table { #define HAS_RESOURCE_STREAMER(dev) (IS_HASWELL(dev) || \ INTEL_INFO(dev)->gen >= 8) +#define HAS_CORE_RING_FREQ(dev) (INTEL_INFO(dev)->gen >= 6 && \ + !IS_VALLEYVIEW(dev)) + #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f2be1cedb52f..025978548fb6 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5104,7 +5104,7 @@ void gen6_update_ring_freq(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (INTEL_INFO(dev)->gen < 6 || IS_VALLEYVIEW(dev)) + if (!HAS_CORE_RING_FREQ(dev)) return; mutex_lock(&dev_priv->rps.hw_lock); -- cgit v1.3-6-gb490 From 430b7ad5d3d07e9869085d777264a37ae2dd5c26 Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:24 +0530 Subject: drm/i915: Added BXT check in HAS_CORE_RING_FREQ macro Updated the HAS_CORE_RING_FREQ macro to add the broxton check, so as to disallow the programming & read of ring frequency table for it. Issue: VIZ-5144 Suggested-by: Daniel Vetter Signed-off-by: Akash Goel Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 661135691d6b..2714228e3456 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2549,7 +2549,7 @@ struct drm_i915_cmd_table { INTEL_INFO(dev)->gen >= 8) #define HAS_CORE_RING_FREQ(dev) (INTEL_INFO(dev)->gen >= 6 && \ - !IS_VALLEYVIEW(dev)) + !IS_VALLEYVIEW(dev) && !IS_BROXTON(dev)) #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 -- cgit v1.3-6-gb490 From f5e9fdaeb3ba48d9a5a6882614f42d0303355fae Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:30:46 +0900 Subject: spi: xcomm: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/spi/spi-xcomm.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index bb478dccf1d8..d0561a8d9f16 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -241,7 +241,6 @@ static const struct i2c_device_id spi_xcomm_ids[] = { static struct i2c_driver spi_xcomm_driver = { .driver = { .name = "spi-xcomm", - .owner = THIS_MODULE, }, .id_table = spi_xcomm_ids, .probe = spi_xcomm_probe, -- cgit v1.3-6-gb490 From 736050c4c11a4907d381672d5396485045d78bab Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:44:01 +0900 Subject: regulator: da9062: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/da9062-regulator.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/da9062-regulator.c b/drivers/regulator/da9062-regulator.c index dd76da09b3c7..5638fe8d759d 100644 --- a/drivers/regulator/da9062-regulator.c +++ b/drivers/regulator/da9062-regulator.c @@ -818,7 +818,6 @@ static int da9062_regulator_probe(struct platform_device *pdev) static struct platform_driver da9062_regulator_driver = { .driver = { .name = "da9062-regulators", - .owner = THIS_MODULE, }, .probe = da9062_regulator_probe, }; -- cgit v1.3-6-gb490 From a807a6cc29115a9a43c168fc0d4540b3d9284815 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:44:00 +0900 Subject: regulator: drivers: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/act8865-regulator.c | 1 - drivers/regulator/da9210-regulator.c | 1 - drivers/regulator/da9211-regulator.c | 1 - drivers/regulator/isl6271a-regulator.c | 1 - drivers/regulator/isl9305.c | 1 - drivers/regulator/lp3971.c | 1 - drivers/regulator/lp3972.c | 1 - drivers/regulator/lp872x.c | 1 - drivers/regulator/ltc3589.c | 1 - drivers/regulator/max1586.c | 1 - drivers/regulator/max8660.c | 1 - drivers/regulator/max8973-regulator.c | 1 - drivers/regulator/pfuze100-regulator.c | 1 - drivers/regulator/tps51632-regulator.c | 1 - drivers/regulator/tps62360-regulator.c | 1 - drivers/regulator/tps65023-regulator.c | 1 - 16 files changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 2ff73d72ca34..896db168e4bd 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -530,7 +530,6 @@ MODULE_DEVICE_TABLE(i2c, act8865_ids); static struct i2c_driver act8865_pmic_driver = { .driver = { .name = "act8865", - .owner = THIS_MODULE, }, .probe = act8865_pmic_probe, .id_table = act8865_ids, diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index f0489cb9018b..143a6621b44f 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -184,7 +184,6 @@ MODULE_DEVICE_TABLE(i2c, da9210_i2c_id); static struct i2c_driver da9210_regulator_driver = { .driver = { .name = "da9210", - .owner = THIS_MODULE, }, .probe = da9210_i2c_probe, .id_table = da9210_i2c_id, diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index df79e4b1946e..ab8914f280c7 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -494,7 +494,6 @@ MODULE_DEVICE_TABLE(of, da9211_dt_ids); static struct i2c_driver da9211_regulator_driver = { .driver = { .name = "da9211", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(da9211_dt_ids), }, .probe = da9211_i2c_probe, diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 6e5da95fa025..4abd8e9c81e5 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -156,7 +156,6 @@ MODULE_DEVICE_TABLE(i2c, isl6271a_id); static struct i2c_driver isl6271a_i2c_driver = { .driver = { .name = "isl6271a", - .owner = THIS_MODULE, }, .probe = isl6271a_probe, .id_table = isl6271a_id, diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c index 6e3a15fe00f1..eae9d1ffe641 100644 --- a/drivers/regulator/isl9305.c +++ b/drivers/regulator/isl9305.c @@ -195,7 +195,6 @@ MODULE_DEVICE_TABLE(i2c, isl9305_i2c_id); static struct i2c_driver isl9305_regulator_driver = { .driver = { .name = "isl9305", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(isl9305_dt_ids), }, .probe = isl9305_i2c_probe, diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 66fd2330dca0..15c25c622edf 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -452,7 +452,6 @@ MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id); static struct i2c_driver lp3971_i2c_driver = { .driver = { .name = "LP3971", - .owner = THIS_MODULE, }, .probe = lp3971_i2c_probe, .id_table = lp3971_i2c_id, diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index aea485afcc1a..3a7e96e2c7b3 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -550,7 +550,6 @@ MODULE_DEVICE_TABLE(i2c, lp3972_i2c_id); static struct i2c_driver lp3972_i2c_driver = { .driver = { .name = "lp3972", - .owner = THIS_MODULE, }, .probe = lp3972_i2c_probe, .id_table = lp3972_i2c_id, diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 3de328ab41f3..171c7625dd67 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -955,7 +955,6 @@ MODULE_DEVICE_TABLE(i2c, lp872x_ids); static struct i2c_driver lp872x_driver = { .driver = { .name = "lp872x", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(lp872x_dt_ids), }, .probe = lp872x_probe, diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 0ce8e4e0fa73..6e79d2e8963d 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -542,7 +542,6 @@ MODULE_DEVICE_TABLE(i2c, ltc3589_i2c_id); static struct i2c_driver ltc3589_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, }, .probe = ltc3589_probe, .id_table = ltc3589_i2c_id, diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index d2a8c64cae42..2c1228d5796a 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -304,7 +304,6 @@ static struct i2c_driver max1586_pmic_driver = { .probe = max1586_pmic_probe, .driver = { .name = "max1586", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(max1586_of_match), }, .id_table = max1586_id, diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 4071d74fa828..b87f62dd484e 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -518,7 +518,6 @@ static struct i2c_driver max8660_driver = { .probe = max8660_probe, .driver = { .name = "max8660", - .owner = THIS_MODULE, }, .id_table = max8660_id, }; diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 6f2bdad8b4d8..399a85bc907e 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -652,7 +652,6 @@ static struct i2c_driver max8973_i2c_driver = { .driver = { .name = "max8973", .of_match_table = of_max8973_match_tbl, - .owner = THIS_MODULE, }, .probe = max8973_probe, .id_table = max8973_id, diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 8cc8d1877c44..2f66821d53cb 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -643,7 +643,6 @@ static struct i2c_driver pfuze_driver = { .id_table = pfuze_device_id, .driver = { .name = "pfuze100-regulator", - .owner = THIS_MODULE, .of_match_table = pfuze_dt_ids, }, .probe = pfuze100_regulator_probe, diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index c213e37eb69e..572816e30095 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -362,7 +362,6 @@ MODULE_DEVICE_TABLE(i2c, tps51632_id); static struct i2c_driver tps51632_i2c_driver = { .driver = { .name = "tps51632", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tps51632_of_match), }, .probe = tps51632_probe, diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index a1fd626c6c96..f6a6d36a6533 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -515,7 +515,6 @@ MODULE_DEVICE_TABLE(i2c, tps62360_id); static struct i2c_driver tps62360_i2c_driver = { .driver = { .name = "tps62360", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tps62360_of_match), }, .probe = tps62360_probe, diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index b941e564b3f3..5cc19b44974a 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -410,7 +410,6 @@ MODULE_DEVICE_TABLE(i2c, tps_65023_id); static struct i2c_driver tps_65023_i2c_driver = { .driver = { .name = "tps65023", - .owner = THIS_MODULE, }, .probe = tps_65023_probe, .id_table = tps_65023_id, -- cgit v1.3-6-gb490 From 4a118753d411d3e22a463361bb867c51d63ebe14 Mon Sep 17 00:00:00 2001 From: Srinidhi Kasagar Date: Fri, 19 Jun 2015 11:52:46 +0530 Subject: PCI: Remove Intel Cherrytrail D3 delays Just like Haswell, Intel Atom Cherrytrail does not need the default 10ms d3_delay imposed by the PCI specification. Expand quirk_remove_d3_delay() to apply to Cherrytrail devices, so we can ignore the 10ms delay before entering or exiting D3 suspend. [bhelgaas: changelog, comment] Signed-off-by: Srinidhi Kasagar Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e9fd0e90fa3b..1fd0ce8208d0 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3028,7 +3028,16 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c26, quirk_remove_d3_delay); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c4e, quirk_remove_d3_delay); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c02, quirk_remove_d3_delay); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c22, quirk_remove_d3_delay); - +/* Intel Cherrytrail devices do not need 10ms d3_delay */ +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2280, quirk_remove_d3_delay); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b0, quirk_remove_d3_delay); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b8, quirk_remove_d3_delay); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22d8, quirk_remove_d3_delay); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22dc, quirk_remove_d3_delay); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b5, quirk_remove_d3_delay); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b7, quirk_remove_d3_delay); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2298, quirk_remove_d3_delay); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x229c, quirk_remove_d3_delay); /* * Some devices may pass our check in pci_intx_mask_supported if * PCI_COMMAND_INTX_DISABLE works though they actually do not properly -- cgit v1.3-6-gb490 From 3657cebda5eb9dc1c4c6a0ea5b38bfef70aea50a Mon Sep 17 00:00:00 2001 From: Krzysztof =?utf-8?Q?Ha=C5=82asa?= Date: Fri, 19 Jun 2015 10:00:15 +0200 Subject: PCI: Add quirk for Intersil/Techwell TW686[4589] AV capture cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero) class code. Fix it. Signed-off-by: Krzysztof Hałasa Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 1fd0ce8208d0..1b9fc4ed39a3 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3663,6 +3663,28 @@ DECLARE_PCI_FIXUP_HEADER(0x1283, 0x8892, quirk_use_pcie_bridge_dma_alias); /* Intel 82801, https://bugzilla.kernel.org/show_bug.cgi?id=44881#c49 */ DECLARE_PCI_FIXUP_HEADER(0x8086, 0x244e, quirk_use_pcie_bridge_dma_alias); +/* + * Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero) + * class code. Fix it. + */ +static void quirk_tw686x_class(struct pci_dev *pdev) +{ + u32 class = pdev->class; + + /* Use "Multimedia controller" class */ + pdev->class = (PCI_CLASS_MULTIMEDIA_OTHER << 8) | 0x01; + dev_info(&pdev->dev, "TW686x PCI class overridden (%#08x -> %#08x)\n", + class, pdev->class); +} +DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6864, PCI_CLASS_NOT_DEFINED, 0, + quirk_tw686x_class); +DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6865, PCI_CLASS_NOT_DEFINED, 0, + quirk_tw686x_class); +DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6868, PCI_CLASS_NOT_DEFINED, 0, + quirk_tw686x_class); +DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6869, PCI_CLASS_NOT_DEFINED, 0, + quirk_tw686x_class); + /* * AMD has indicated that the devices below do not support peer-to-peer * in any system where they are found in the southbridge with an AMD -- cgit v1.3-6-gb490 From cd76d10b78ab21a7adc4562e016213dd4891b6e5 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 19 Jun 2015 15:28:31 -0500 Subject: PCI: Use PCI_CLASS_SERIAL_USB instead of bare number be6646bfbaec ("PCI: Prevent xHCI driver from claiming AMD Nolan USB3 DRD device") added a quirk to override the PCI class code of the AMD Nolan device. Use PCI_CLASS_SERIAL_USB instead of a bare number to improve greppability. Also add a log message about what we're doing. No functional change except the new message. Signed-off-by: Bjorn Helgaas Acked-by: Huang Rui CC: Jason Chang CC: Felipe Balbi --- drivers/pci/quirks.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 1b9fc4ed39a3..ecaad8f39681 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -424,10 +424,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_ */ static void quirk_amd_nl_class(struct pci_dev *pdev) { - /* - * Use 'USB Device' (0x0c03fe) instead of PCI header provided - */ - pdev->class = 0x0c03fe; + u32 class = pdev->class; + + /* Use "USB Device (not host controller)" class */ + pdev->class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe; + dev_info(&pdev->dev, "PCI class overridden (%#08x -> %#08x) so dwc3 driver can claim this instead of xhci\n", + class, pdev->class); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB, quirk_amd_nl_class); -- cgit v1.3-6-gb490 From e6323e3c51601e5ccda24024ece3d7cd542378ea Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 19 Jun 2015 15:36:45 -0500 Subject: PCI: Fix generic NCR 53c810 class code quirk In the generic quirk fixup_rev1_53c810(), added by a5312e28c195 ("[PATCH] PCI: NCR 53c810 quirk"), we assigned "class = PCI_CLASS_STORAGE_SCSI". But PCI_CLASS_STORAGE_SCSI is only the two-byte base class/sub-class and needs to be shifted to make space for the low-order interface byte. Furthermore, we had a similar quirk, pci_fixup_ncr53c810(), for arch/x86, which assigned class correctly. The arch code is linked before the PCI core, so arch quirks run before generic quirks. Therefore, on x86, the x86 arch quirk ran first, and the generic quirk did nothing because it saw that dev->class was already set. But on other arches, the generic quirk set the wrong class code. Fix the generic quirk to set the correct class code and remove the now-unnecessary x86-specific quirk. Signed-off-by: Bjorn Helgaas CC: Matthew Wilcox --- arch/x86/pci/fixup.c | 13 ------------- drivers/pci/quirks.c | 14 +++++++++----- 2 files changed, 9 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index 9a2b7101ae8a..e58565556703 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -62,19 +62,6 @@ static void pci_fixup_umc_ide(struct pci_dev *d) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide); -static void pci_fixup_ncr53c810(struct pci_dev *d) -{ - /* - * NCR 53C810 returns class code 0 (at least on some systems). - * Fix class to be PCI_CLASS_STORAGE_SCSI - */ - if (!d->class) { - dev_warn(&d->dev, "Fixing NCR 53C810 class code\n"); - d->class = PCI_CLASS_STORAGE_SCSI << 8; - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810); - static void pci_fixup_latency(struct pci_dev *d) { /* diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ecaad8f39681..afc8151f4ca5 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1988,14 +1988,18 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1508, quirk_disable_aspm_l0s); static void fixup_rev1_53c810(struct pci_dev *dev) { - /* rev 1 ncr53c810 chips don't set the class at all which means + u32 class = dev->class; + + /* + * rev 1 ncr53c810 chips don't set the class at all which means * they don't get their resources remapped. Fix that here. */ + if (class) + return; - if (dev->class == PCI_CLASS_NOT_DEFINED) { - dev_info(&dev->dev, "NCR 53c810 rev 1 detected; setting PCI class\n"); - dev->class = PCI_CLASS_STORAGE_SCSI; - } + dev->class = PCI_CLASS_STORAGE_SCSI << 8; + dev_info(&dev->dev, "NCR 53c810 rev 1 PCI class overridden (%#08x -> %#08x)\n", + class, dev->class); } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810); -- cgit v1.3-6-gb490 From d1541dc977d376406f4584d8eb055488655c98ec Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 19 Jun 2015 15:58:24 -0500 Subject: PCI: Fix TI816X class code quirk In fixup_ti816x_class(), we assigned "class = PCI_CLASS_MULTIMEDIA_VIDEO". But PCI_CLASS_MULTIMEDIA_VIDEO is only the two-byte base class/sub-class and needs to be shifted to make space for the low-order interface byte. Shift PCI_CLASS_MULTIMEDIA_VIDEO to set the correct class code. Fixes: 63c4408074cb ("PCI: Add quirk for setting valid class for TI816X Endpoint") Signed-off-by: Bjorn Helgaas CC: Hemant Pedanekar --- drivers/pci/quirks.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index afc8151f4ca5..9734b4234d5c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2835,12 +2835,15 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x3c28, vtd_mask_spec_errors); static void fixup_ti816x_class(struct pci_dev *dev) { + u32 class = dev->class; + /* TI 816x devices do not have class code set when in PCIe boot mode */ - dev_info(&dev->dev, "Setting PCI class for 816x PCIe device\n"); - dev->class = PCI_CLASS_MULTIMEDIA_VIDEO; + dev->class = PCI_CLASS_MULTIMEDIA_VIDEO << 8; + dev_info(&dev->dev, "PCI class overridden (%#08x -> %#08x)\n", + class, dev->class); } DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_TI, 0xb800, - PCI_CLASS_NOT_DEFINED, 0, fixup_ti816x_class); + PCI_CLASS_NOT_DEFINED, 0, fixup_ti816x_class); /* Some PCIe devices do not work reliably with the claimed maximum * payload size supported. -- cgit v1.3-6-gb490 From eefaf338820ecd3fb14da496f8a740612257a341 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 24 Jun 2015 15:46:38 -0500 Subject: PCI: Revert aeb30016fec3 ("PCI: add Intel USB specific reset method") Revert aeb30016fec3 ("PCI: add Intel USB specific reset method"). We checked for "dev->class == PCI_CLASS_SERIAL_USB", but dev->class contains the entire three-byte base class/sub-class/interface, while PCI_CLASS_SERIAL_USB is only the two-byte base class/sub-class. This error meant that we used the Intel device-specific reset on devices with class code 0x000c03 instead of those with class code 0x0c03xx. 0x000c03 is a reserved value in the 0x00 backwards compatibility base class and shouldn't match any devices, so I think reset_intel_generic_dev() always failed. I considered adding a shift, but I can't test it, so it's as likely to break something as to fix something. Signed-off-by: Bjorn Helgaas CC: Yu Zhao CC: Mathias Nyman --- drivers/pci/quirks.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 9734b4234d5c..35f8d409ad71 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3344,28 +3344,6 @@ fs_initcall_sync(pci_apply_final_quirks); * reset a single function if other methods (e.g. FLR, PM D0->D3) are * not available. */ -static int reset_intel_generic_dev(struct pci_dev *dev, int probe) -{ - int pos; - - /* only implement PCI_CLASS_SERIAL_USB at present */ - if (dev->class == PCI_CLASS_SERIAL_USB) { - pos = pci_find_capability(dev, PCI_CAP_ID_VNDR); - if (!pos) - return -ENOTTY; - - if (probe) - return 0; - - pci_write_config_byte(dev, pos + 0x4, 1); - msleep(100); - - return 0; - } else { - return -ENOTTY; - } -} - static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe) { /* @@ -3524,8 +3502,6 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = { reset_ivb_igd }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_M2_VGA, reset_ivb_igd }, - { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, - reset_intel_generic_dev }, { PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID, reset_chelsio_generic_dev }, { 0 } -- cgit v1.3-6-gb490 From 2b4aed1d1f119634d80d8c701873c2be01480aa9 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 19 Jun 2015 16:20:58 -0500 Subject: PCI: Shift PCI_CLASS_NOT_DEFINED consistently with other classes The PCI class in dev->class is a three-byte value comprising a base class, sub-class, and interface type. PCI_CLASS_NOT_DEFINED includes the base class and sub-class, but not the interface type, so it should be shifted to make space for the interface. It happens that PCI_CLASS_NOT_DEFINED is zero, so it doesn't matter in the end, but we should still use it consistently with other class definitions. Treat PCI_CLASS_NOT_DEFINED as a base class/sub-class value that should appear in bits 8-23 of dev->class. Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 2 +- drivers/pci/quirks.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cefd636681b6..71bd520e8ff7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1268,7 +1268,7 @@ int pci_setup_device(struct pci_dev *dev) bad: dev_err(&dev->dev, "ignoring class %#08x (doesn't match header type %02x)\n", dev->class, dev->hdr_type); - dev->class = PCI_CLASS_NOT_DEFINED; + dev->class = PCI_CLASS_NOT_DEFINED << 8; } /* We found a fine healthy device, go go go... */ diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 35f8d409ad71..32cc9c802b47 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2843,7 +2843,7 @@ static void fixup_ti816x_class(struct pci_dev *dev) class, dev->class); } DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_TI, 0xb800, - PCI_CLASS_NOT_DEFINED, 0, fixup_ti816x_class); + PCI_CLASS_NOT_DEFINED, 8, fixup_ti816x_class); /* Some PCIe devices do not work reliably with the claimed maximum * payload size supported. @@ -3661,13 +3661,13 @@ static void quirk_tw686x_class(struct pci_dev *pdev) dev_info(&pdev->dev, "TW686x PCI class overridden (%#08x -> %#08x)\n", class, pdev->class); } -DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6864, PCI_CLASS_NOT_DEFINED, 0, +DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6864, PCI_CLASS_NOT_DEFINED, 8, quirk_tw686x_class); -DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6865, PCI_CLASS_NOT_DEFINED, 0, +DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6865, PCI_CLASS_NOT_DEFINED, 8, quirk_tw686x_class); -DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6868, PCI_CLASS_NOT_DEFINED, 0, +DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6868, PCI_CLASS_NOT_DEFINED, 8, quirk_tw686x_class); -DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6869, PCI_CLASS_NOT_DEFINED, 0, +DECLARE_PCI_FIXUP_CLASS_EARLY(0x1797, 0x6869, PCI_CLASS_NOT_DEFINED, 8, quirk_tw686x_class); /* -- cgit v1.3-6-gb490 From e7f6c6d02cc3fa7f78153919900561bd1dce02a3 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 24 Jun 2015 16:03:23 -0500 Subject: PCI: Fix pcie_port_device_resume() comment The function comment claimed this was pcie_port_device_suspend(), but it's really pcie_port_device_resume(). Perils of cut and paste. Use the correct function name in the comment. Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/pci/pcie/portdrv_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 2f0ce668a775..88122dc2e1b1 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -448,7 +448,7 @@ static int resume_iter(struct device *dev, void *data) } /** - * pcie_port_device_suspend - resume port services associated with a PCIe port + * pcie_port_device_resume - resume port services associated with a PCIe port * @dev: PCI Express port to handle */ int pcie_port_device_resume(struct device *dev) -- cgit v1.3-6-gb490 From 93972d18bbaba6f34e21742400b6e7461edc4837 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 28 Jun 2015 16:42:04 +0200 Subject: PCI: iproc: Delete unnecessary checks before phy calls The functions phy_exit() and phy_power_off() test whether their argument is NULL and then return immediately. Thus the test around the calls is not needed. This issue was detected by using the Coccinelle software. [bhelgaas: also phy_init() and phy_power_on(), as Ray Jui suggested] [bhelgaas: also remove tests in iproc_pcie_remove()] Signed-off-by: Markus Elfring Signed-off-by: Bjorn Helgaas Reviewed-by: Ray Jui --- drivers/pci/host/pcie-iproc.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index d77481ea553e..9a00dca5e453 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -191,19 +191,16 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) if (!pcie || !pcie->dev || !pcie->base) return -EINVAL; - if (pcie->phy) { - ret = phy_init(pcie->phy); - if (ret) { - dev_err(pcie->dev, "unable to initialize PCIe PHY\n"); - return ret; - } - - ret = phy_power_on(pcie->phy); - if (ret) { - dev_err(pcie->dev, "unable to power on PCIe PHY\n"); - goto err_exit_phy; - } + ret = phy_init(pcie->phy); + if (ret) { + dev_err(pcie->dev, "unable to initialize PCIe PHY\n"); + return ret; + } + ret = phy_power_on(pcie->phy); + if (ret) { + dev_err(pcie->dev, "unable to power on PCIe PHY\n"); + goto err_exit_phy; } iproc_pcie_reset(pcie); @@ -239,12 +236,9 @@ err_rm_root_bus: pci_remove_root_bus(bus); err_power_off_phy: - if (pcie->phy) - phy_power_off(pcie->phy); + phy_power_off(pcie->phy); err_exit_phy: - if (pcie->phy) - phy_exit(pcie->phy); - + phy_exit(pcie->phy); return ret; } EXPORT_SYMBOL(iproc_pcie_setup); @@ -254,10 +248,8 @@ int iproc_pcie_remove(struct iproc_pcie *pcie) pci_stop_root_bus(pcie->root_bus); pci_remove_root_bus(pcie->root_bus); - if (pcie->phy) { - phy_power_off(pcie->phy); - phy_exit(pcie->phy); - } + phy_power_off(pcie->phy); + phy_exit(pcie->phy); return 0; } -- cgit v1.3-6-gb490 From 29e2d6d1f6f61ba2b5cc9d9867e01d8c31a6c4f7 Mon Sep 17 00:00:00 2001 From: Ellen Wang Date: Thu, 9 Jul 2015 22:04:31 -0700 Subject: HID: cp2112: fix byte order in SMBUS operations Change all occurrences of be16 to le16 in cp2112_xfer(), because SMBUS words are little endian, not big endian. Signed-off-by: Ellen Wang Cc: stable@vger.kernel.org Signed-off-by: Jiri Kosina --- drivers/hid/hid-cp2112.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index a84d3700e740..7afc3fcc122c 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -589,7 +589,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data; struct hid_device *hdev = dev->hdev; u8 buf[64]; - __be16 word; + __le16 word; ssize_t count; size_t read_length = 0; unsigned int retries; @@ -621,7 +621,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, break; case I2C_SMBUS_WORD_DATA: read_length = 2; - word = cpu_to_be16(data->word); + word = cpu_to_le16(data->word); if (I2C_SMBUS_READ == read_write) count = cp2112_write_read_req(buf, addr, read_length, @@ -634,7 +634,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, size = I2C_SMBUS_WORD_DATA; read_write = I2C_SMBUS_READ; read_length = 2; - word = cpu_to_be16(data->word); + word = cpu_to_le16(data->word); count = cp2112_write_read_req(buf, addr, read_length, command, (u8 *)&word, 2); @@ -727,7 +727,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, data->byte = buf[0]; break; case I2C_SMBUS_WORD_DATA: - data->word = be16_to_cpup((__be16 *)buf); + data->word = le16_to_cpup((__le16 *)buf); break; case I2C_SMBUS_BLOCK_DATA: if (read_length > I2C_SMBUS_BLOCK_MAX) { -- cgit v1.3-6-gb490 From 5f37ac9343db1d0d3a9028d963eafe834053a0fb Mon Sep 17 00:00:00 2001 From: Lukasz Janyst Date: Tue, 14 Jul 2015 17:22:21 +0200 Subject: staging: lustre: fix whitespace coding style issues in libcfs/module.c This is a patch to the libcfs/module.c file fixing whitespace warnings found by checkpatch.pl. Signed-off-by: Lukasz Janyst Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/module.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index 0ed26580f5ea..1ab4232e0705 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -80,7 +80,7 @@ extern char lnet_upcall[1024]; */ extern char lnet_debug_log_upcall[1024]; -static void kportal_memhog_free (struct libcfs_device_userstate *ldu) +static void kportal_memhog_free(struct libcfs_device_userstate *ldu) { struct page **level0p = &ldu->ldu_memhog_root_page; struct page **level1p; @@ -120,7 +120,7 @@ static void kportal_memhog_free (struct libcfs_device_userstate *ldu) *level0p = NULL; } - LASSERT (ldu->ldu_memhog_pages == 0); + LASSERT(ldu->ldu_memhog_pages == 0); } static int kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages, @@ -132,8 +132,8 @@ static int kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages, int count1; int count2; - LASSERT (ldu->ldu_memhog_pages == 0); - LASSERT (ldu->ldu_memhog_root_page == NULL); + LASSERT(ldu->ldu_memhog_pages == 0); + LASSERT(ldu->ldu_memhog_root_page == NULL); if (npages < 0) return -EINVAL; @@ -312,7 +312,7 @@ static int libcfs_ioctl_int(struct cfs_psdev_file *pfile, unsigned long cmd, if (err != -EINVAL) { if (err == 0) err = libcfs_ioctl_popdata(arg, - data, sizeof (*data)); + data, sizeof(*data)); break; } } @@ -404,7 +404,7 @@ static int init_libcfs_module(void) insert_debugfs(); - CDEBUG (D_OTHER, "portals setup OK\n"); + CDEBUG(D_OTHER, "portals setup OK\n"); return 0; cleanup_wi: cfs_wi_shutdown(); -- cgit v1.3-6-gb490 From a5cb88804d51b9d272d1d15ea348a244ba4d26c3 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 14 Jul 2015 09:35:42 +0200 Subject: staging: lustre: Deletion of unnecessary checks before three function calls The following functions test whether their argument is NULL and then return immediately. * kfree * ll_file_data_put * ptlrpc_connection_put Thus the test around such calls is not needed. This issue was detected by using the Coccinelle software. See also a previous update suggestion: "remove unneeded null test before free" by Julia Lawall https://lkml.org/lkml/2015/5/1/498 https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg878600.html Signed-off-by: Markus Elfring Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/llite/file.c | 3 +-- drivers/staging/lustre/lustre/llite/llite_lib.c | 2 +- drivers/staging/lustre/lustre/ptlrpc/import.c | 6 ++---- drivers/staging/lustre/lustre/ptlrpc/service.c | 4 +--- 4 files changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index e01a47c0b80a..dcd0c6d65efb 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -702,8 +702,7 @@ out_och_free: out_openerr: if (opendir_set != 0) ll_stop_statahead(inode, lli->lli_opendir_key); - if (fd != NULL) - ll_file_data_put(fd); + ll_file_data_put(fd); } else { ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_OPEN, 1); } diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 25139885b5a7..ab4839cad939 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -1114,7 +1114,7 @@ void ll_clear_inode(struct inode *inode) if (lli->lli_mds_read_och) ll_md_real_close(inode, FMODE_READ); - if (S_ISLNK(inode->i_mode) && lli->lli_symlink_name) { + if (S_ISLNK(inode->i_mode)) { kfree(lli->lli_symlink_name); lli->lli_symlink_name = NULL; } diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c index c9b8481dd384..1eae3896c037 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/import.c +++ b/drivers/staging/lustre/lustre/ptlrpc/import.c @@ -555,14 +555,12 @@ static int import_select_connection(struct obd_import *imp) imp_conn->oic_last_attempt = cfs_time_current_64(); /* switch connection, don't mind if it's same as the current one */ - if (imp->imp_connection) - ptlrpc_connection_put(imp->imp_connection); + ptlrpc_connection_put(imp->imp_connection); imp->imp_connection = ptlrpc_connection_addref(imp_conn->oic_conn); dlmexp = class_conn2export(&imp->imp_dlm_handle); LASSERT(dlmexp != NULL); - if (dlmexp->exp_connection) - ptlrpc_connection_put(dlmexp->exp_connection); + ptlrpc_connection_put(dlmexp->exp_connection); dlmexp->exp_connection = ptlrpc_connection_addref(imp_conn->oic_conn); class_export_put(dlmexp); diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c index 56a86317ded7..cf9477d4749b 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/service.c +++ b/drivers/staging/lustre/lustre/ptlrpc/service.c @@ -2826,9 +2826,7 @@ void ptlrpc_hr_fini(void) ptlrpc_stop_hr_threads(); cfs_percpt_for_each(hrp, i, ptlrpc_hr.hr_partitions) { - if (hrp->hrp_thrs != NULL) { - kfree(hrp->hrp_thrs); - } + kfree(hrp->hrp_thrs); } cfs_percpt_free(ptlrpc_hr.hr_partitions); -- cgit v1.3-6-gb490 From 5dbc247c2a11f6b9febb854a55be5ae6be720df6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Jun 2015 14:55:13 +0200 Subject: ata: sata_rcar: Remove obsolete sata-r8a779* platform_device_id entries Since commit a483dcbfa21f919c ("ARM: shmobile: lager: Remove legacy board support"), R-Car Gen2 SoCs are only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the corresponding platform_device_id entry. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Tejun Heo --- drivers/ata/sata_rcar.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index d49a5193b7de..8804127b108c 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -861,10 +861,6 @@ MODULE_DEVICE_TABLE(of, sata_rcar_match); static const struct platform_device_id sata_rcar_id_table[] = { { "sata_rcar", RCAR_GEN1_SATA }, /* Deprecated by "sata-r8a7779" */ { "sata-r8a7779", RCAR_GEN1_SATA }, - { "sata-r8a7790", RCAR_GEN2_SATA }, - { "sata-r8a7790-es1", RCAR_R8A7790_ES1_SATA }, - { "sata-r8a7791", RCAR_GEN2_SATA }, - { "sata-r8a7793", RCAR_GEN2_SATA }, { }, }; MODULE_DEVICE_TABLE(platform, sata_rcar_id_table); -- cgit v1.3-6-gb490 From aad0d51e933f8656880592020319d2dbd09532a2 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 10 Jul 2015 21:10:10 +0300 Subject: ravb: kill useless initializers Some of the local variable intializers in the driver turned out to be pointless, kill them. Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index fd9745714d90..47287c1cc7e0 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -223,9 +223,9 @@ static void ravb_ring_free(struct net_device *ndev, int q) static void ravb_ring_format(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); - struct ravb_ex_rx_desc *rx_desc = NULL; - struct ravb_tx_desc *tx_desc = NULL; - struct ravb_desc *desc = NULL; + struct ravb_ex_rx_desc *rx_desc; + struct ravb_tx_desc *tx_desc; + struct ravb_desc *desc; int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q]; int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q]; struct sk_buff *skb; @@ -435,7 +435,7 @@ static int ravb_tx_free(struct net_device *ndev, int q) struct net_device_stats *stats = &priv->stats[q]; struct ravb_tx_desc *desc; int free_num = 0; - int entry = 0; + int entry; u32 size; for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) { @@ -508,8 +508,8 @@ static bool ravb_rx(struct net_device *ndev, int *quota, int q) struct sk_buff *skb; dma_addr_t dma_addr; struct timespec64 ts; - u16 pkt_len = 0; u8 desc_status; + u16 pkt_len; int limit; boguscnt = min(boguscnt, *quota); @@ -1272,8 +1272,8 @@ static void ravb_tx_timeout_work(struct work_struct *work) static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); - struct ravb_tstamp_skb *ts_skb = NULL; u16 q = skb_get_queue_mapping(skb); + struct ravb_tstamp_skb *ts_skb; struct ravb_tx_desc *desc; unsigned long flags; u32 dma_addr; -- cgit v1.3-6-gb490 From ffb4d602623aef9eb813a35b87b20854c030a2ec Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 24 Jun 2015 16:05:54 -0500 Subject: PCI: Add pcie_downstream_port() (true for Root and Switch Downstream Ports) As used in the PCIe spec, "Downstream Port" includes both Root Ports and Switch Downstream Ports. We sometimes checked for PCI_EXP_TYPE_DOWNSTREAM when we should have checked for PCI_EXP_TYPE_ROOT_PORT or PCI_EXP_TYPE_DOWNSTREAM. For a Root Port without a slot, the effect of this was that using pcie_capability_read_word() to read PCI_EXP_SLTSTA returned zero instead of showing the Presence Detect State bit hardwired to one as the PCIe Spec, r3.0, sec 7.8, requires. (This read is completed in software because previous PCIe spec versions didn't require PCI_EXP_SLTSTA to exist at all.) Nothing in the kernel currently depends on this (pciehp only reads PCI_EXP_SLTSTA on ports with slots), so this is a cleanup and not a functional change. Add a pcie_downstream_port() helper function and use it. Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/pci/access.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/access.c b/drivers/pci/access.c index d9b64a175990..5465b005220c 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -531,6 +531,14 @@ static inline int pcie_cap_version(const struct pci_dev *dev) return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS; } +static bool pcie_downstream_port(const struct pci_dev *dev) +{ + int type = pci_pcie_type(dev); + + return type == PCI_EXP_TYPE_ROOT_PORT || + type == PCI_EXP_TYPE_DOWNSTREAM; +} + bool pcie_cap_has_lnkctl(const struct pci_dev *dev) { int type = pci_pcie_type(dev); @@ -546,10 +554,7 @@ bool pcie_cap_has_lnkctl(const struct pci_dev *dev) static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev) { - int type = pci_pcie_type(dev); - - return (type == PCI_EXP_TYPE_ROOT_PORT || - type == PCI_EXP_TYPE_DOWNSTREAM) && + return pcie_downstream_port(dev) && pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT; } @@ -628,10 +633,9 @@ int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val) * State bit in the Slot Status register of Downstream Ports, * which must be hardwired to 1b. (PCIe Base Spec 3.0, sec 7.8) */ - if (pci_is_pcie(dev) && pos == PCI_EXP_SLTSTA && - pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) { + if (pci_is_pcie(dev) && pcie_downstream_port(dev) && + pos == PCI_EXP_SLTSTA) *val = PCI_EXP_SLTSTA_PDS; - } return 0; } @@ -657,10 +661,9 @@ int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val) return ret; } - if (pci_is_pcie(dev) && pos == PCI_EXP_SLTCTL && - pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) { + if (pci_is_pcie(dev) && pcie_downstream_port(dev) && + pos == PCI_EXP_SLTSTA) *val = PCI_EXP_SLTSTA_PDS; - } return 0; } -- cgit v1.3-6-gb490 From 5605b188833fc60c297e0a3927e274349a172f59 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Mon, 13 Jul 2015 15:50:30 +0300 Subject: staging: android: ion: reorder variable definitions Prevents false positive "missing empty line after a definition" checkpatch warning. Signed-off-by: Dmitry Kalinkin Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 6f4811263557..6c922c7817f9 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1103,10 +1103,10 @@ static struct dma_buf_ops dma_buf_ops = { struct dma_buf *ion_share_dma_buf(struct ion_client *client, struct ion_handle *handle) { + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); struct ion_buffer *buffer; struct dma_buf *dmabuf; bool valid_handle; - DEFINE_DMA_BUF_EXPORT_INFO(exp_info); mutex_lock(&client->lock); valid_handle = ion_handle_validate(client, handle); -- cgit v1.3-6-gb490 From cef853810edcfffb9203b59637eebb916cfaa759 Mon Sep 17 00:00:00 2001 From: "Guillermo O. Freschi" Date: Sun, 21 Jun 2015 05:28:55 -0300 Subject: staging: android: ion_chunk_heap.c: Fixed line over 80 characters Simple style fix. Signed-off-by: Guillermo O. Freschi Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion_chunk_heap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c index 54746157d799..0813163f962f 100644 --- a/drivers/staging/android/ion/ion_chunk_heap.c +++ b/drivers/staging/android/ion/ion_chunk_heap.c @@ -173,8 +173,8 @@ struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data) chunk_heap->heap.ops = &chunk_heap_ops; chunk_heap->heap.type = ION_HEAP_TYPE_CHUNK; chunk_heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE; - pr_debug("%s: base %lu size %zu align %ld\n", __func__, chunk_heap->base, - heap_data->size, heap_data->align); + pr_debug("%s: base %lu size %zu align %ld\n", __func__, + chunk_heap->base, heap_data->size, heap_data->align); return &chunk_heap->heap; -- cgit v1.3-6-gb490 From 4ef299d7dd51f4081618446a420f500e7f7e5d1b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:38:26 +0900 Subject: PCI: xgene: Drop owner assignment from platform_driver platform_driver_register() automatically supplies THIS_MODULE, so we don't need to set it in the platform_driver struct. Remove the xgene_msi_driver.owner assignment. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pci-xgene-msi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-xgene-msi.c b/drivers/pci/host/pci-xgene-msi.c index 2d31d4d6fd08..9e1889e6aec7 100644 --- a/drivers/pci/host/pci-xgene-msi.c +++ b/drivers/pci/host/pci-xgene-msi.c @@ -582,7 +582,6 @@ error: static struct platform_driver xgene_msi_driver = { .driver = { .name = "xgene-msi", - .owner = THIS_MODULE, .of_match_table = xgene_msi_match_table, }, .probe = xgene_msi_probe, -- cgit v1.3-6-gb490 From 55ff2c6972e96acc3fd12be33ac7ac2fa17f1b0d Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 22 Jun 2015 14:14:35 +0200 Subject: staging: comedi: das08_cs: don't split Author string fixes checkpatch.pl WARNING: quoted string split across lines +MODULE_AUTHOR("David A. Schleef , " + "Frank Mori Hess "); Modules with multiple authors have a MODULE_AUTHOR line for each one. Signed-off-by: Luis de Bethencourt Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/das08_cs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index 93fab6890161..9c02b17a2834 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -108,7 +108,7 @@ static struct pcmcia_driver das08_cs_driver = { }; module_comedi_pcmcia_driver(driver_das08_cs, das08_cs_driver); -MODULE_AUTHOR("David A. Schleef , " - "Frank Mori Hess "); +MODULE_AUTHOR("David A. Schleef "); +MODULE_AUTHOR("Frank Mori Hess "); MODULE_DESCRIPTION("Comedi driver for ComputerBoards DAS-08 PCMCIA boards"); MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From fa4c586e17dc1f5402235e4a78399ebc2026c435 Mon Sep 17 00:00:00 2001 From: Abdul Hussain Date: Mon, 22 Jun 2015 06:10:56 +0000 Subject: Staging: comedi: dmm32at: Simplify a trivial if-return sequence This patch simplify a trivial if-return sequence. Possibly combine with a preceding function call. Signed-off-by: Abdul Hussain Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/dmm32at.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index bb2883c83afa..958c0d4aae5c 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -607,11 +607,7 @@ static int dmm32at_attach(struct comedi_device *dev, /* Digital I/O subdevice */ s = &dev->subdevices[2]; - ret = subdev_8255_init(dev, s, dmm32at_8255_io, DMM32AT_8255_IOBASE); - if (ret) - return ret; - - return 0; + return subdev_8255_init(dev, s, dmm32at_8255_io, DMM32AT_8255_IOBASE); } static struct comedi_driver dmm32at_driver = { -- cgit v1.3-6-gb490 From 11b22e1465e25dbbf29c7df30ba20497d91c63f2 Mon Sep 17 00:00:00 2001 From: Abdul Hussain Date: Mon, 22 Jun 2015 06:10:59 +0000 Subject: Staging: comedi: fl512: Simplify a trivial if-return sequence This patch simplify a trivial if-return sequence. Possibly combine with a preceding function call. Signed-off-by: Abdul Hussain Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/fl512.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index e1f493241cd6..55cae61458cb 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -136,11 +136,7 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_fl512; s->insn_write = fl512_ao_insn_write; - ret = comedi_alloc_subdev_readback(s); - if (ret) - return ret; - - return 0; + return comedi_alloc_subdev_readback(s); } static struct comedi_driver fl512_driver = { -- cgit v1.3-6-gb490 From 2b2dae3da36dd2bcbf6c2171dba8a51a7b42673a Mon Sep 17 00:00:00 2001 From: Abdul Hussain Date: Mon, 22 Jun 2015 06:11:06 +0000 Subject: Staging: comedi: dac02: Simplify a trivial if-return sequence This patch simplify a trivial if-return sequence. Possibly combine with a preceding function call. Signed-off-by: Abdul Hussain Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/dac02.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c index a6798ad8fa7f..a562df498b01 100644 --- a/drivers/staging/comedi/drivers/dac02.c +++ b/drivers/staging/comedi/drivers/dac02.c @@ -130,11 +130,7 @@ static int dac02_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &das02_ao_ranges; s->insn_write = dac02_ao_insn_write; - ret = comedi_alloc_subdev_readback(s); - if (ret) - return ret; - - return 0; + return comedi_alloc_subdev_readback(s); } static struct comedi_driver dac02_driver = { -- cgit v1.3-6-gb490 From ac7e62914cf5d31d31948d3f2b085e80e515a7cc Mon Sep 17 00:00:00 2001 From: Abdul Hussain Date: Mon, 22 Jun 2015 06:11:09 +0000 Subject: Staging: comedi: ni_daq_dio24: Simplify a trivial if-return sequence This patch simplify a trivial if-return sequence. Possibly combine with a preceding function call. Signed-off-by: Abdul Hussain Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/ni_daq_dio24.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index a208cb348437..d9de83ab0267 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -55,11 +55,7 @@ static int dio24_auto_attach(struct comedi_device *dev, /* 8255 dio */ s = &dev->subdevices[0]; - ret = subdev_8255_init(dev, s, NULL, 0x00); - if (ret) - return ret; - - return 0; + return subdev_8255_init(dev, s, NULL, 0x00); } static struct comedi_driver driver_dio24 = { -- cgit v1.3-6-gb490 From 71b9f42eac9722d8dc39a5b2771255e2a6214eee Mon Sep 17 00:00:00 2001 From: Abdul Hussain Date: Mon, 22 Jun 2015 06:11:13 +0000 Subject: Staging: comedi: s626: Simplify a trivial if-return sequence This patch simplify a trivial if-return sequence. Possibly combine with a preceding function call. Signed-off-by: Abdul Hussain Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/s626.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 781918d8d85f..35f0f676eb28 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -2852,11 +2852,7 @@ static int s626_auto_attach(struct comedi_device *dev, s->insn_read = s626_enc_insn_read; s->insn_write = s626_enc_insn_write; - ret = s626_initialize(dev); - if (ret) - return ret; - - return 0; + return s626_initialize(dev); } static void s626_detach(struct comedi_device *dev) -- cgit v1.3-6-gb490 From 21eaa3c23ac49c6a2b8f842412177a956711169a Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 22 Jun 2015 15:02:36 +0200 Subject: staging: comedi: das16m1: no space before tabs Warning found by checkpatch.pl WARNING: please, no space before tabs /drivers/staging/comedi/drivers/das16m1.c:83 + 404-407 ^I8254$ Signed-off-by: Luis de Bethencourt Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/das16m1.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index a18a8878bdb8..25f4da5d3f14 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -69,18 +69,18 @@ irq can be omitted, although the cmd interface will not work without it. "cio-das16/m1" - 0 a/d bits 0-3, mux start 12 bit - 1 a/d bits 4-11 unused - 2 status control - 3 di 4 bit do 4 bit - 4 unused clear interrupt - 5 interrupt, pacer - 6 channel/gain queue address - 7 channel/gain queue data - 89ab 8254 - cdef 8254 - 400 8255 - 404-407 8254 + 0 a/d bits 0-3, mux start 12 bit + 1 a/d bits 4-11 unused + 2 status control + 3 di 4 bit do 4 bit + 4 unused clear interrupt + 5 interrupt, pacer + 6 channel/gain queue address + 7 channel/gain queue data + 89ab 8254 + cdef 8254 + 400 8255 + 404-407 8254 */ -- cgit v1.3-6-gb490 From 58a06a2a64930ad11cc398b0b00ae9817b9a821a Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 22 Jun 2015 15:03:15 +0200 Subject: staging: comedi: das16m1: fix lines over 80 characters Warnings found by checkpatch.pl WARNING: line over 80 characters /drivers/staging/comedi/drivers/das16m1.c:414 + if (devpriv->adc_count == 0 && hw_counter == devpriv->initial_hw_count) { /drivers/staging/comedi/drivers/das16m1.c:417 /drivers/staging/comedi/drivers/das16m1.c:418 /drivers/staging/comedi/drivers/das16m1.c:419 /drivers/staging/comedi/drivers/das16m1.c:420 /drivers/staging/comedi/drivers/das16m1.c:421 Signed-off-by: Luis de Bethencourt Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/das16m1.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 25f4da5d3f14..3a37373fbb6f 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -411,15 +411,18 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) hw_counter = comedi_8254_read(devpriv->counter, 1); /* make sure hardware counter reading is not bogus due to initial value * not having been loaded yet */ - if (devpriv->adc_count == 0 && hw_counter == devpriv->initial_hw_count) { + if (devpriv->adc_count == 0 && + hw_counter == devpriv->initial_hw_count) { num_samples = 0; } else { - /* The calculation of num_samples looks odd, but it uses the following facts. - * 16 bit hardware counter is initialized with value of zero (which really - * means 0x1000). The counter decrements by one on each conversion - * (when the counter decrements from zero it goes to 0xffff). num_samples - * is a 16 bit variable, so it will roll over in a similar fashion to the - * hardware counter. Work it out, and this is what you get. */ + /* The calculation of num_samples looks odd, but it uses the + * following facts. 16 bit hardware counter is initialized with + * value of zero (which really means 0x1000). The counter + * decrements by one on each conversion (when the counter + * decrements from zero it goes to 0xffff). num_samples is a + * 16 bit variable, so it will roll over in a similar fashion + * to the hardware counter. Work it out, and this is what you + * get. */ num_samples = -hw_counter - devpriv->adc_count; } /* check if we only need some of the points */ -- cgit v1.3-6-gb490 From 0f73490e20261dbf543744bb3dc1ae6d6af0d80f Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 22 Jun 2015 23:33:42 +0800 Subject: staging: comedi: fix cast warning in comedi_compat32.c This patch fixes the following sparse warning: drivers/staging/comedi/comedi_compat32.c:205:16: warning: cast removes address space of expression Signed-off-by: Geliang Tang Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_compat32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c index 25848244c4b1..f356386d833a 100644 --- a/drivers/staging/comedi/comedi_compat32.c +++ b/drivers/staging/comedi/comedi_compat32.c @@ -202,7 +202,8 @@ static int get_compat_cmd(struct comedi_cmd __user *cmd, err |= __get_user(temp.uint, &cmd32->stop_arg); err |= __put_user(temp.uint, &cmd->stop_arg); err |= __get_user(temp.uptr, &cmd32->chanlist); - err |= __put_user(compat_ptr(temp.uptr), &cmd->chanlist); + err |= __put_user((unsigned int __force *)compat_ptr(temp.uptr), + &cmd->chanlist); err |= __get_user(temp.uint, &cmd32->chanlist_len); err |= __put_user(temp.uint, &cmd->chanlist_len); err |= __get_user(temp.uptr, &cmd32->data); -- cgit v1.3-6-gb490 From 50f058a1900aa02fea93c6d47584eefc74fdd4ac Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 6 Jul 2015 15:41:18 +0200 Subject: staging: comedi: Grammar s/Enable support a/Enable support for a/ Signed-off-by: Geert Uytterhoeven Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 7dee73dfbf88..57e71f9f14a2 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -2,7 +2,7 @@ config COMEDI tristate "Data acquisition support (comedi)" depends on m ---help--- - Enable support a wide range of data acquisition devices + Enable support for a wide range of data acquisition devices for Linux. if COMEDI -- cgit v1.3-6-gb490 From 4fff0fea6d8821b1e521b7d38ea6d69c47e21efc Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Tue, 7 Jul 2015 18:06:07 +0100 Subject: staging: comedi: cb_pcimdas: add external analog output ranges The analog output range is not programmable, but the ranges for each of the two analog output channels are settable via jumpers. These jumper settings are not readable by the driver. The driver provides a range table containing all the possible internal ranges (+/-10V, +/-5V, 0-10V, 0-5V) to provide information to the user application (although any range selected by the application that differs from the jumper settings will not produce the expected voltage output). The range table does not cover all possible ranges of the analog output channels. The jumpers also allow an external reference voltage between 0 and 10V to be used as bipolar or unipolar output range. Add a couple more ranges to the end of the range table to define these two external ranges. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/cb_pcimdas.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index 4ebf5aae5019..47e38398921e 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -141,11 +141,13 @@ static const struct comedi_lrange cb_pcimdas_ai_uni_range = { * jumper-settable on the board. The settings are not software-readable. */ static const struct comedi_lrange cb_pcimdas_ao_range = { - 4, { + 6, { BIP_RANGE(10), BIP_RANGE(5), UNI_RANGE(10), - UNI_RANGE(5) + UNI_RANGE(5), + RANGE_ext(-1, 1), + RANGE_ext(0, 1) } }; -- cgit v1.3-6-gb490 From 0e0d311ebd589e65b8e5559e067d0dd109ac3434 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Tue, 7 Jul 2015 17:06:52 +0100 Subject: staging: comedi: use CAP_SYS_ADMIN instead of CAP_NET_ADMIN If the "comedi" module has been loaded with the "comedi_num_legacy_minors" module parameter set to a non-zero value, some reserved comedi devices get created. These can be attached to a low-level comedi driver using the `COMEDI_DEVCONFIG` ioctl command, which checks for the `CAP_SYS_ADMIN` capability. Of course, the comedi device needs to be opened before the ioctl command can be sent. If the comedi device is unattached, `comedi_open()` currently requires the `CAP_NET_ADMIN` capability. It makes more sense to just require the `CAP_SYS_ADMIN` capability here, so change it. For the curious, commit a8f80e8ff94e ("Networking: use CAP_NET_ADMIN when deciding to call request_module") changed this capability from `CAP_SYS_MODULE` to `CAP_NET_ADMIN`, even though it doesn't seem relevant here. The original `CAP_SYS_MODULE` capability was due to the function having some code to request a module using a "char-major-%i-%i" alias, but that was never compiled in and was removed by commit f30f2c2d417b ("staging: comedi: remove check for CONFIG_KMOD"). Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 985d94b6cbfd..1679bfba25a9 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -2599,8 +2599,8 @@ static int comedi_open(struct inode *inode, struct file *file) cfp->dev = dev; mutex_lock(&dev->mutex); - if (!dev->attached && !capable(CAP_NET_ADMIN)) { - dev_dbg(dev->class_dev, "not attached and not CAP_NET_ADMIN\n"); + if (!dev->attached && !capable(CAP_SYS_ADMIN)) { + dev_dbg(dev->class_dev, "not attached and not CAP_SYS_ADMIN\n"); rc = -ENODEV; goto out; } -- cgit v1.3-6-gb490 From 90e6f51da718fc982eafd3dd7d6c78b378f67136 Mon Sep 17 00:00:00 2001 From: Santhosh Pai Date: Mon, 29 Jun 2015 10:44:03 +0100 Subject: staging: Comedi: comedi_fops: Fixed the return error code This patch fixes the checkpatch.pl warning: WARNING: ENOSYS means 'invalid syscall nr' and nothing else try_module_get fails when the reference count of the module is not allowed to be incremented ,and hence -ENXIO is returned indicating no device or address. [IA - combined two of santhosh's changes to the error return value!] Signed-off-by: santhosh pai Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 1679bfba25a9..4820ab6d0aa8 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -2606,7 +2606,7 @@ static int comedi_open(struct inode *inode, struct file *file) } if (dev->attached && dev->use_count == 0) { if (!try_module_get(dev->driver->module)) { - rc = -ENOSYS; + rc = -ENXIO; goto out; } if (dev->open) { -- cgit v1.3-6-gb490 From f44a75e27d5eb4b1788f59c2bc185baaaf732f75 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 14 Apr 2015 17:09:14 -0700 Subject: i40e: Implement ndo_features_check() i40e supports UDP tunnel headers up to 80 bytes in length, so this adds a check to ensure that it doesn't try to offload packets that exceed that. Signed-off-by: Joe Stringer Signed-off-by: Jesse Gross Acked-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 48a52b35b614..b44eb357cff7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8099,6 +8099,25 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, } #endif /* HAVE_BRIDGE_ATTRIBS */ +#define I40E_MAX_TUNNEL_HDR_LEN 80 +/** + * i40e_features_check - Validate encapsulated packet conforms to limits + * @skb: skb buff + * @netdev: This physical port's netdev + * @features: Offload features that the stack believes apply + **/ +static netdev_features_t i40e_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) +{ + if (skb->encapsulation && + (skb_inner_mac_header(skb) - skb_transport_header(skb) > + I40E_MAX_TUNNEL_HDR_LEN)) + return features & ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK); + + return features; +} + static const struct net_device_ops i40e_netdev_ops = { .ndo_open = i40e_open, .ndo_stop = i40e_close, @@ -8133,6 +8152,7 @@ static const struct net_device_ops i40e_netdev_ops = { #endif .ndo_get_phys_port_id = i40e_get_phys_port_id, .ndo_fdb_add = i40e_ndo_fdb_add, + .ndo_features_check = i40e_features_check, #ifdef HAVE_BRIDGE_ATTRIBS .ndo_bridge_getlink = i40e_ndo_bridge_getlink, .ndo_bridge_setlink = i40e_ndo_bridge_setlink, -- cgit v1.3-6-gb490 From d0389e51fc9b3c74e7935ded5d22eab4ea004589 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 22 Apr 2015 19:34:05 -0400 Subject: i40e/i40evf: Add stats to track FD ATR and SB dynamic enable state Since the driver can dynamically enable/disable FD ATR and SB features, these stats help keep track of the current state and along with fd_flush count provide a means to debug what could be going on with the flow director filters. This will take away the need for being verbose in our debug logs with respect to FD. Change-ID: I29224f750fe6602391043655d18996570720377d Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 2 ++ drivers/net/ethernet/intel/i40e/i40e_main.c | 12 ++++++++++++ drivers/net/ethernet/intel/i40e/i40e_type.h | 2 ++ drivers/net/ethernet/intel/i40evf/i40e_type.h | 2 ++ 4 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 9a68c65b17ea..0b68f61eeb0c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -148,7 +148,9 @@ static struct i40e_stats i40e_gstrings_stats[] = { I40E_PF_STAT("fdir_flush_cnt", fd_flush_cnt), I40E_PF_STAT("fdir_atr_match", stats.fd_atr_match), I40E_PF_STAT("fdir_atr_tunnel_match", stats.fd_atr_tunnel_match), + I40E_PF_STAT("fdir_atr_status", stats.fd_atr_status), I40E_PF_STAT("fdir_sb_match", stats.fd_sb_match), + I40E_PF_STAT("fdir_sb_status", stats.fd_sb_status), /* LPI stats */ I40E_PF_STAT("tx_lpi_status", stats.tx_lpi_status), diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b44eb357cff7..b5fc6544fb69 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1123,6 +1123,18 @@ static void i40e_update_pf_stats(struct i40e_pf *pf) pf->stat_offsets_loaded, &osd->rx_lpi_count, &nsd->rx_lpi_count); + if (pf->flags & I40E_FLAG_FD_SB_ENABLED && + !(pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) + nsd->fd_sb_status = true; + else + nsd->fd_sb_status = false; + + if (pf->flags & I40E_FLAG_FD_ATR_ENABLED && + !(pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) + nsd->fd_atr_status = true; + else + nsd->fd_atr_status = false; + pf->stat_offsets_loaded = true; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 9a5a75b1e2bc..350c5ee85ec3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -1134,6 +1134,8 @@ struct i40e_hw_port_stats { u64 fd_atr_match; u64 fd_sb_match; u64 fd_atr_tunnel_match; + u32 fd_atr_status; + u32 fd_sb_status; /* EEE LPI */ u32 tx_lpi_status; u32 rx_lpi_status; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index c463ec41579c..068813d3c7a3 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -1109,6 +1109,8 @@ struct i40e_hw_port_stats { u64 fd_atr_match; u64 fd_sb_match; u64 fd_atr_tunnel_match; + u32 fd_atr_status; + u32 fd_sb_status; /* EEE LPI */ u32 tx_lpi_status; u32 rx_lpi_status; -- cgit v1.3-6-gb490 From c78b953e0f189824f5eaa2d60123cfd12ea6db0d Mon Sep 17 00:00:00 2001 From: Pawel Orlowski Date: Wed, 22 Apr 2015 19:34:06 -0400 Subject: i40e/i40evf: Update Flex-10 related device/function capabilities The Flex10 device/function capability has been upgraded to include information needed to support Flex-10 configurations. This patch adds new fields to the i40e_hw_capabilities structure and updates i40e_parse_discover_capabilities functions to extract them from the AQ response. Naming convention has changed to use flex10 mode instead of existing mfp_mode_1. Change-ID: I305dd888866985a30293acb3fb14fa43ca6b79ea Signed-off-by: Pawel Orlowski Signed-off-by: Akeem G Abodunrin Signed-off-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 24 +++++++++++++++++++----- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_type.h | 12 +++++++++++- drivers/net/ethernet/intel/i40evf/i40e_type.h | 12 +++++++++++- 4 files changed, 42 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 0bae22da014d..07032229ee60 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -2391,7 +2391,7 @@ i40e_aq_erase_nvm_exit: #define I40E_DEV_FUNC_CAP_MSIX_VF 0x44 #define I40E_DEV_FUNC_CAP_FLOW_DIRECTOR 0x45 #define I40E_DEV_FUNC_CAP_IEEE_1588 0x46 -#define I40E_DEV_FUNC_CAP_MFP_MODE_1 0xF1 +#define I40E_DEV_FUNC_CAP_FLEX10 0xF1 #define I40E_DEV_FUNC_CAP_CEM 0xF2 #define I40E_DEV_FUNC_CAP_IWARP 0x51 #define I40E_DEV_FUNC_CAP_LED 0x61 @@ -2416,6 +2416,7 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, u32 valid_functions, num_functions; u32 number, logical_id, phys_id; struct i40e_hw_capabilities *p; + u8 major_rev; u32 i = 0; u16 id; @@ -2433,6 +2434,7 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, number = le32_to_cpu(cap->number); logical_id = le32_to_cpu(cap->logical_id); phys_id = le32_to_cpu(cap->phys_id); + major_rev = cap->major_rev; switch (id) { case I40E_DEV_FUNC_CAP_SWITCH_MODE: @@ -2507,9 +2509,21 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, case I40E_DEV_FUNC_CAP_MSIX_VF: p->num_msix_vectors_vf = number; break; - case I40E_DEV_FUNC_CAP_MFP_MODE_1: - if (number == 1) - p->mfp_mode_1 = true; + case I40E_DEV_FUNC_CAP_FLEX10: + if (major_rev == 1) { + if (number == 1) { + p->flex10_enable = true; + p->flex10_capable = true; + } + } else { + /* Capability revision >= 2 */ + if (number & 1) + p->flex10_enable = true; + if (number & 2) + p->flex10_capable = true; + } + p->flex10_mode = logical_id; + p->flex10_status = phys_id; break; case I40E_DEV_FUNC_CAP_CEM: if (number == 1) @@ -2557,7 +2571,7 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, /* Software override ensuring FCoE is disabled if npar or mfp * mode because it is not supported in these modes. */ - if (p->npar_enable || p->mfp_mode_1) + if (p->npar_enable || p->flex10_enable) p->fcoe = false; /* count the enabled ports (aka the "not disabled" ports) */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b5fc6544fb69..ed6fc52362af 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7685,7 +7685,7 @@ static int i40e_sw_init(struct i40e_pf *pf) } /* MFP mode enabled */ - if (pf->hw.func_caps.npar_enable || pf->hw.func_caps.mfp_mode_1) { + if (pf->hw.func_caps.npar_enable || pf->hw.func_caps.flex10_enable) { pf->flags |= I40E_FLAG_MFP_ENABLED; dev_info(&pf->pdev->dev, "MFP mode Enabled\n"); if (i40e_get_npar_bw_setting(pf)) diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 350c5ee85ec3..220371ece7c4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -213,7 +213,17 @@ struct i40e_hw_capabilities { bool dcb; bool fcoe; bool iscsi; /* Indicates iSCSI enabled */ - bool mfp_mode_1; + bool flex10_enable; + bool flex10_capable; + u32 flex10_mode; +#define I40E_FLEX10_MODE_UNKNOWN 0x0 +#define I40E_FLEX10_MODE_DCC 0x1 +#define I40E_FLEX10_MODE_DCI 0x2 + + u32 flex10_status; +#define I40E_FLEX10_STATUS_DCC_ERROR 0x1 +#define I40E_FLEX10_STATUS_VC_MODE 0x2 + bool mgmt_cem; bool ieee_1588; bool iwarp; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 068813d3c7a3..3969c6548af0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -213,7 +213,17 @@ struct i40e_hw_capabilities { bool dcb; bool fcoe; bool iscsi; /* Indicates iSCSI enabled */ - bool mfp_mode_1; + bool flex10_enable; + bool flex10_capable; + u32 flex10_mode; +#define I40E_FLEX10_MODE_UNKNOWN 0x0 +#define I40E_FLEX10_MODE_DCC 0x1 +#define I40E_FLEX10_MODE_DCI 0x2 + + u32 flex10_status; +#define I40E_FLEX10_STATUS_DCC_ERROR 0x1 +#define I40E_FLEX10_STATUS_VC_MODE 0x2 + bool mgmt_cem; bool ieee_1588; bool iwarp; -- cgit v1.3-6-gb490 From 489ce7a46306052ab4ef26c6305051c5f1b24bb4 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 27 Apr 2015 14:57:08 -0400 Subject: i40e/i40evf: improve Tx performance with a small tweak Add a prefetch for the next Tx descriptor to be used when we know there are more coming. Change-ID: Ibb9acab11d508eec2db7da795df74debc16eeacb Signed-off-by: Jesse Brandeburg Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 ++ drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 9a4f2bc70cd2..1fe230d2be5d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2616,6 +2616,8 @@ static inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, netif_xmit_stopped(netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index))) writel(i, tx_ring->tail); + else + prefetchw(tx_desc + 1); return; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 395f32f226c0..0f0e185b5c66 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1841,6 +1841,8 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, netif_xmit_stopped(netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index))) writel(i, tx_ring->tail); + else + prefetchw(tx_desc + 1); return; -- cgit v1.3-6-gb490 From 973371da4d66b96736143bd3f2b2ff2331faae8f Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:09 -0400 Subject: i40evf: Allow for an abundance of vectors The driver currently only maps TX and RX queues to a single MSI-X vector per queue pair if there are exactly enough vectors for this. Unfortunately, if we have too many vectors it will fail and allocate queues to vectors in a suboptimal manner. Change the condition check to allow for excess vectors. In this case, the extras just won't be used. Change-ID: I23e1e2955c64739c86612db88a25583e6a7e0b17 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 4ab4ebba07a1..94eff4a269e6 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -406,7 +406,7 @@ static int i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter) /* The ideal configuration... * We have enough vectors to map one per queue. */ - if (q_vectors == (rxr_remaining * 2)) { + if (q_vectors >= (rxr_remaining * 2)) { for (; rxr_idx < rxr_remaining; v_start++, rxr_idx++) i40evf_map_vector_to_rxq(adapter, v_start, rxr_idx); -- cgit v1.3-6-gb490 From 85927ec1b369c880407aa82eba70d49c04c35062 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:10 -0400 Subject: i40e: ignore duplicate port VLAN requests If user attempts to set a port VLAN on a VF that already has the same port VLAN configured, the driver will go through a completely unnecessary flurry of filter removals and filter adds. Just check for this condition and return success instead of doing a bunch of busywork. Change-ID: Ia1a9e83e6ed48b3f4658bc20dfc6af0cf525d54a Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 23f95cdbdfcc..433e80320eea 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2088,6 +2088,10 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, goto error_pvid; } + if (vsi->info.pvid == (vlan_id | (qos << I40E_VLAN_PRIORITY_SHIFT))) + /* duplicate request, so just return success */ + goto error_pvid; + if (vsi->info.pvid == 0 && i40e_is_vsi_in_vlan(vsi)) { dev_err(&pf->pdev->dev, "VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n", -- cgit v1.3-6-gb490 From 9df70b66418e284dc1e7f272ac445c1d1e990b97 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Mon, 27 Apr 2015 14:57:11 -0400 Subject: i40e: Remove incorrect #ifdef's This patch removes some #ifdef's that should not be there. They were stopping code that is needed from being compiled in. With these #ifdef's removed, changes are needed in the driver to fix some compile errors: adding missing parameters to the definition of ndo_bridge_setlink and a ndo_dflt_brige_getlink call. Change-ID: I5516614e1bc50b6bca0647cef971bc96161ba2de Signed-off-by: Carolyn Wyborny Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ed6fc52362af..c7f2a0a74dcf 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7993,7 +7993,6 @@ static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], return err; } -#ifdef HAVE_BRIDGE_ATTRIBS /** * i40e_ndo_bridge_setlink - Set the hardware bridge mode * @dev: the netdev being configured @@ -8007,7 +8006,8 @@ static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], * bridge mode enabled. **/ static int i40e_ndo_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh) + struct nlmsghdr *nlh, + u16 flags) { struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_vsi *vsi = np->vsi; @@ -8078,14 +8078,9 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev, * Return the mode in which the hardware bridge is operating in * i.e VEB or VEPA. **/ -#ifdef HAVE_BRIDGE_FILTER static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, u32 filter_mask, int nlflags) -#else -static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, - struct net_device *dev, int nlflags) -#endif /* HAVE_BRIDGE_FILTER */ { struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_vsi *vsi = np->vsi; @@ -8109,7 +8104,6 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode, nlflags, 0, 0, filter_mask, NULL); } -#endif /* HAVE_BRIDGE_ATTRIBS */ #define I40E_MAX_TUNNEL_HDR_LEN 80 /** @@ -8165,10 +8159,8 @@ static const struct net_device_ops i40e_netdev_ops = { .ndo_get_phys_port_id = i40e_get_phys_port_id, .ndo_fdb_add = i40e_ndo_fdb_add, .ndo_features_check = i40e_features_check, -#ifdef HAVE_BRIDGE_ATTRIBS .ndo_bridge_getlink = i40e_ndo_bridge_getlink, .ndo_bridge_setlink = i40e_ndo_bridge_setlink, -#endif /* HAVE_BRIDGE_ATTRIBS */ }; /** -- cgit v1.3-6-gb490 From cb2f65bc0c64015e8fa45fe1065ad241bf31a994 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Mon, 27 Apr 2015 14:57:12 -0400 Subject: i40e/i40evf: Update the admin queue command header Make the necessary updates to i40e_adminq_cmd.h. Change-ID: Ib031c86cc6cab78e5aa44c64d8ce5474be8d7e42 Signed-off-by: Greg Rose Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 24 ++++++++++++---------- .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 18 +++++++--------- 2 files changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 929e3d72a01e..9101f5c00f37 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -34,7 +34,7 @@ */ #define I40E_FW_API_VERSION_MAJOR 0x0001 -#define I40E_FW_API_VERSION_MINOR 0x0002 +#define I40E_FW_API_VERSION_MINOR 0x0004 struct i40e_aq_desc { __le16 flags; @@ -132,12 +132,7 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_list_func_capabilities = 0x000A, i40e_aqc_opc_list_dev_capabilities = 0x000B, - i40e_aqc_opc_set_cppm_configuration = 0x0103, - i40e_aqc_opc_set_arp_proxy_entry = 0x0104, - i40e_aqc_opc_set_ns_proxy_entry = 0x0105, - /* LAA */ - i40e_aqc_opc_mng_laa = 0x0106, /* AQ obsolete */ i40e_aqc_opc_mac_address_read = 0x0107, i40e_aqc_opc_mac_address_write = 0x0108, @@ -262,7 +257,6 @@ enum i40e_admin_queue_opc { /* Tunnel commands */ i40e_aqc_opc_add_udp_tunnel = 0x0B00, i40e_aqc_opc_del_udp_tunnel = 0x0B01, - i40e_aqc_opc_tunnel_key_structure = 0x0B10, /* Async Events */ i40e_aqc_opc_event_lan_overflow = 0x1001, @@ -274,8 +268,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_oem_ocbb_initialize = 0xFE03, /* debug commands */ - i40e_aqc_opc_debug_get_deviceid = 0xFF00, - i40e_aqc_opc_debug_set_mode = 0xFF01, i40e_aqc_opc_debug_read_reg = 0xFF03, i40e_aqc_opc_debug_write_reg = 0xFF04, i40e_aqc_opc_debug_modify_reg = 0xFF07, @@ -509,7 +501,8 @@ struct i40e_aqc_mac_address_read { #define I40E_AQC_SAN_ADDR_VALID 0x20 #define I40E_AQC_PORT_ADDR_VALID 0x40 #define I40E_AQC_WOL_ADDR_VALID 0x80 -#define I40E_AQC_ADDR_VALID_MASK 0xf0 +#define I40E_AQC_MC_MAG_EN_VALID 0x100 +#define I40E_AQC_ADDR_VALID_MASK 0x1F0 u8 reserved[6]; __le32 addr_high; __le32 addr_low; @@ -532,7 +525,9 @@ struct i40e_aqc_mac_address_write { #define I40E_AQC_WRITE_TYPE_LAA_ONLY 0x0000 #define I40E_AQC_WRITE_TYPE_LAA_WOL 0x4000 #define I40E_AQC_WRITE_TYPE_PORT 0x8000 -#define I40E_AQC_WRITE_TYPE_MASK 0xc000 +#define I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG 0xC000 +#define I40E_AQC_WRITE_TYPE_MASK 0xC000 + __le16 mac_sah; __le32 mac_sal; u8 reserved[8]; @@ -1068,6 +1063,7 @@ struct i40e_aqc_set_vsi_promiscuous_modes { __le16 seid; #define I40E_AQC_VSI_PROM_CMD_SEID_MASK 0x3FF __le16 vlan_tag; +#define I40E_AQC_SET_VSI_VLAN_MASK 0x0FFF #define I40E_AQC_SET_VSI_VLAN_VALID 0x8000 u8 reserved[8]; }; @@ -2064,6 +2060,12 @@ I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_start); #define I40E_AQC_CEE_PFC_STATUS_MASK (0x7 << I40E_AQC_CEE_PFC_STATUS_SHIFT) #define I40E_AQC_CEE_APP_STATUS_SHIFT 0x8 #define I40E_AQC_CEE_APP_STATUS_MASK (0x7 << I40E_AQC_CEE_APP_STATUS_SHIFT) +#define I40E_AQC_CEE_FCOE_STATUS_SHIFT 0x8 +#define I40E_AQC_CEE_FCOE_STATUS_MASK (0x7 << I40E_AQC_CEE_FCOE_STATUS_SHIFT) +#define I40E_AQC_CEE_ISCSI_STATUS_SHIFT 0xA +#define I40E_AQC_CEE_ISCSI_STATUS_MASK (0x7 << I40E_AQC_CEE_ISCSI_STATUS_SHIFT) +#define I40E_AQC_CEE_FIP_STATUS_SHIFT 0x10 +#define I40E_AQC_CEE_FIP_STATUS_MASK (0x7 << I40E_AQC_CEE_FIP_STATUS_SHIFT) struct i40e_aqc_get_cee_dcb_cfg_v1_resp { u8 reserved1; u8 oper_num_tc; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index e715bccfb5d2..d5bd6f066921 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -34,7 +34,7 @@ */ #define I40E_FW_API_VERSION_MAJOR 0x0001 -#define I40E_FW_API_VERSION_MINOR 0x0002 +#define I40E_FW_API_VERSION_MINOR 0x0004 #define I40E_FW_API_VERSION_A0_MINOR 0x0000 struct i40e_aq_desc { @@ -133,12 +133,7 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_list_func_capabilities = 0x000A, i40e_aqc_opc_list_dev_capabilities = 0x000B, - i40e_aqc_opc_set_cppm_configuration = 0x0103, - i40e_aqc_opc_set_arp_proxy_entry = 0x0104, - i40e_aqc_opc_set_ns_proxy_entry = 0x0105, - /* LAA */ - i40e_aqc_opc_mng_laa = 0x0106, /* AQ obsolete */ i40e_aqc_opc_mac_address_read = 0x0107, i40e_aqc_opc_mac_address_write = 0x0108, @@ -260,7 +255,6 @@ enum i40e_admin_queue_opc { /* Tunnel commands */ i40e_aqc_opc_add_udp_tunnel = 0x0B00, i40e_aqc_opc_del_udp_tunnel = 0x0B01, - i40e_aqc_opc_tunnel_key_structure = 0x0B10, /* Async Events */ i40e_aqc_opc_event_lan_overflow = 0x1001, @@ -272,8 +266,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_oem_ocbb_initialize = 0xFE03, /* debug commands */ - i40e_aqc_opc_debug_get_deviceid = 0xFF00, - i40e_aqc_opc_debug_set_mode = 0xFF01, i40e_aqc_opc_debug_read_reg = 0xFF03, i40e_aqc_opc_debug_write_reg = 0xFF04, i40e_aqc_opc_debug_modify_reg = 0xFF07, @@ -507,7 +499,8 @@ struct i40e_aqc_mac_address_read { #define I40E_AQC_SAN_ADDR_VALID 0x20 #define I40E_AQC_PORT_ADDR_VALID 0x40 #define I40E_AQC_WOL_ADDR_VALID 0x80 -#define I40E_AQC_ADDR_VALID_MASK 0xf0 +#define I40E_AQC_MC_MAG_EN_VALID 0x100 +#define I40E_AQC_ADDR_VALID_MASK 0x1F0 u8 reserved[6]; __le32 addr_high; __le32 addr_low; @@ -530,7 +523,9 @@ struct i40e_aqc_mac_address_write { #define I40E_AQC_WRITE_TYPE_LAA_ONLY 0x0000 #define I40E_AQC_WRITE_TYPE_LAA_WOL 0x4000 #define I40E_AQC_WRITE_TYPE_PORT 0x8000 -#define I40E_AQC_WRITE_TYPE_MASK 0xc000 +#define I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG 0xC000 +#define I40E_AQC_WRITE_TYPE_MASK 0xC000 + __le16 mac_sah; __le32 mac_sal; u8 reserved[8]; @@ -1066,6 +1061,7 @@ struct i40e_aqc_set_vsi_promiscuous_modes { __le16 seid; #define I40E_AQC_VSI_PROM_CMD_SEID_MASK 0x3FF __le16 vlan_tag; +#define I40E_AQC_SET_VSI_VLAN_MASK 0x0FFF #define I40E_AQC_SET_VSI_VLAN_VALID 0x8000 u8 reserved[8]; }; -- cgit v1.3-6-gb490 From e995163cdcf9b70c7840a8d6a7ea7c0ce81c761b Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:13 -0400 Subject: i40e: correctly program filters for VFs MAC filters for VFs were being programmed with 0 for the VLAN value when there was no VLAN assigned. This is incorrect and actually assigns the VF to VLAN 0. Instead, we must use -1 to indicate that no VLAN is in use. This change programs the filters correctly and gets rid of a bogus error message when setting a port VLAN on an active VF. Change-ID: Ica9a9906d768405377ff3308e27f7d0b5b2ea96e Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 433e80320eea..4070a22f16c8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -542,11 +542,13 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) if (vf->port_vlan_id) i40e_vsi_add_pvid(vsi, vf->port_vlan_id); f = i40e_add_filter(vsi, vf->default_lan_addr.addr, - vf->port_vlan_id, true, false); + vf->port_vlan_id ? vf->port_vlan_id : -1, + true, false); if (!f) dev_info(&pf->pdev->dev, "Could not allocate VF MAC addr\n"); - f = i40e_add_filter(vsi, brdcast, vf->port_vlan_id, + f = i40e_add_filter(vsi, brdcast, + vf->port_vlan_id ? vf->port_vlan_id : -1, true, false); if (!f) dev_info(&pf->pdev->dev, @@ -2023,7 +2025,8 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) } /* delete the temporary mac address */ - i40e_del_filter(vsi, vf->default_lan_addr.addr, vf->port_vlan_id, + i40e_del_filter(vsi, vf->default_lan_addr.addr, + vf->port_vlan_id ? vf->port_vlan_id : -1, true, false); /* Delete all the filters for this VSI - we're going to kill it -- cgit v1.3-6-gb490 From 54f455eeb56c0ab92db87bed6bd767d206d9e743 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:14 -0400 Subject: i40e: do a proper reset when disabling a VF The VF disable code was just whanging on the reset bit without properly cleaning up the VF, which would leave the VF in an indeterminate state from which it could not recover. Fix this by notifying the VF and then by calling the normal VF reset routine. Change-ID: I862b9dfa919368773cbdc212b805b520db2f7430 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 4070a22f16c8..55b19f5e436a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -160,13 +160,8 @@ void i40e_vc_notify_vf_reset(struct i40e_vf *vf) **/ static inline void i40e_vc_disable_vf(struct i40e_pf *pf, struct i40e_vf *vf) { - struct i40e_hw *hw = &pf->hw; - u32 reg; - - reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id)); - reg |= I40E_VPGEN_VFRTRIG_VFSWR_MASK; - wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg); - i40e_flush(hw); + i40e_vc_notify_vf_reset(vf); + i40e_reset_vf(vf, false); } /** -- cgit v1.3-6-gb490 From 5b8f8505d37c63d492391e5fafcd43332671b36b Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:15 -0400 Subject: i40e: un-disable VF after reset When a VF is disabled, there is no way for it to recover until either the PF driver is reloaded or SR-IOV is disabled and enabled. To correct this, enable the VF after a successful reset. Change-ID: I9e0788476c4d53d5407961b503febdfff2b8a7c6 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 55b19f5e436a..fdd7f5e3a66b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -832,6 +832,7 @@ complete_reset: i40e_alloc_vf_res(vf); i40e_enable_vf_mappings(vf); set_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states); + clear_bit(I40E_VF_STAT_DISABLED, &vf->vf_states); /* tell the VF the reset is done */ wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE); -- cgit v1.3-6-gb490 From 68ef169204e3a88ea4823645038d5496f66200f6 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:16 -0400 Subject: i40evf: don't delete all the filters Due to an inverted conditional, the driver was marking all of its MAC filters for deletion every time set_rx_mode was called. Depending upon the timing of the calls to set_rx_mode and the processing of the admin queue, the driver would (accidentally) end up with a varying number of functional filters. Correct this logic so that MAC filters are added and removed correctly. Add a check for the driver's "hardware" MAC address so that this filter doesn't get removed incorrectly. Change-ID: Ib3e7c4a5b53df6835f164fe44cb778cb71f8aff8 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 94eff4a269e6..1c2ee97d1844 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -892,8 +892,10 @@ static void i40evf_set_rx_mode(struct net_device *netdev) break; } } + if (ether_addr_equal(f->macaddr, adapter->hw.mac.addr)) + found = true; } - if (found) { + if (!found) { f->remove = true; adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; } -- cgit v1.3-6-gb490 From 44151cd32deb1074530f3beba51d535fa0887d9a Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:17 -0400 Subject: i40evf: add MAC address filter in open, not init During close, all of the MAC filters are cleared, so the driver would be unable to receive unicast packets after being closed and reopened. Add the adapter's "hardware" MAC address filter in open, not init. This ensures that the correct filter is present each time. Change-ID: I51a11e9c1200139dab6f66a5353bd38c7d26f875 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 1c2ee97d1844..802e158ea981 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1858,6 +1858,7 @@ static int i40evf_open(struct net_device *netdev) if (err) goto err_req_irq; + i40evf_add_filter(adapter, adapter->hw.mac.addr); i40evf_configure(adapter); err = i40evf_up_complete(adapter); @@ -1998,7 +1999,6 @@ static void i40evf_init_task(struct work_struct *work) struct i40evf_adapter, init_task.work); struct net_device *netdev = adapter->netdev; - struct i40evf_mac_filter *f; struct i40e_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; int i, err, bufsz; @@ -2132,16 +2132,6 @@ static void i40evf_init_task(struct work_struct *work) ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr); ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr); - f = kzalloc(sizeof(*f), GFP_ATOMIC); - if (!f) - goto err_sw_init; - - ether_addr_copy(f->macaddr, adapter->hw.mac.addr); - f->add = true; - adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; - - list_add(&f->list, &adapter->mac_filter_list); - init_timer(&adapter->watchdog_timer); adapter->watchdog_timer.function = &i40evf_watchdog_timer; adapter->watchdog_timer.data = (unsigned long)adapter; -- cgit v1.3-6-gb490 From 3bbf0faa90cb8d541d8b2ce01610dcec6828bd00 Mon Sep 17 00:00:00 2001 From: Faisal Latif Date: Mon, 27 Apr 2015 14:57:19 -0400 Subject: i40e/i40evf: Add support for pre-allocated pages for PD The i40e_add_pd_table_entry() routine is being modified to handle both cases where a backing page is passed and where backing page is allocated in i40e_add_pd_table_entry(). For PBLE resource management, it is more efficient for it to manage its backing pages. For VF, PBLE backing page addresses will be send to PF driver for PBLE resource. The i40e_remove_pd_bp() is also modified to not free pre-allocated pages and free only ones which were allocated in i40e_add_pd_table_entry(). Change-ID: Ie673f0403f22979e9406f5a94048dceb91bcf9a8 Signed-off-by: Faisal Latif Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_hmc.c | 30 +++++++++++++++++--------- drivers/net/ethernet/intel/i40e/i40e_hmc.h | 4 +++- drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c | 2 +- drivers/net/ethernet/intel/i40evf/i40e_hmc.h | 4 +++- 4 files changed, 27 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_hmc.c index 9b987ccc9e82..b89856a5e313 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.c @@ -116,6 +116,7 @@ exit: * @hw: pointer to our HW structure * @hmc_info: pointer to the HMC configuration information structure * @pd_index: which page descriptor index to manipulate + * @rsrc_pg: if not NULL, use preallocated page instead of allocating new one. * * This function: * 1. Initializes the pd entry @@ -129,12 +130,14 @@ exit: **/ i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, - u32 pd_index) + u32 pd_index, + struct i40e_dma_mem *rsrc_pg) { i40e_status ret_code = 0; struct i40e_hmc_pd_table *pd_table; struct i40e_hmc_pd_entry *pd_entry; struct i40e_dma_mem mem; + struct i40e_dma_mem *page = &mem; u32 sd_idx, rel_pd_idx; u64 *pd_addr; u64 page_desc; @@ -155,18 +158,24 @@ i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; pd_entry = &pd_table->pd_entry[rel_pd_idx]; if (!pd_entry->valid) { - /* allocate a 4K backing page */ - ret_code = i40e_allocate_dma_mem(hw, &mem, i40e_mem_bp, - I40E_HMC_PAGED_BP_SIZE, - I40E_HMC_PD_BP_BUF_ALIGNMENT); - if (ret_code) - goto exit; + if (rsrc_pg) { + pd_entry->rsrc_pg = true; + page = rsrc_pg; + } else { + /* allocate a 4K backing page */ + ret_code = i40e_allocate_dma_mem(hw, page, i40e_mem_bp, + I40E_HMC_PAGED_BP_SIZE, + I40E_HMC_PD_BP_BUF_ALIGNMENT); + if (ret_code) + goto exit; + pd_entry->rsrc_pg = false; + } - pd_entry->bp.addr = mem; + pd_entry->bp.addr = *page; pd_entry->bp.sd_pd_index = pd_index; pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED; /* Set page address and valid bit */ - page_desc = mem.pa | 0x1; + page_desc = page->pa | 0x1; pd_addr = (u64 *)pd_table->pd_page_addr.va; pd_addr += rel_pd_idx; @@ -240,7 +249,8 @@ i40e_status i40e_remove_pd_bp(struct i40e_hw *hw, I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx); /* free memory here */ - ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr)); + if (!pd_entry->rsrc_pg) + ret_code = i40e_free_dma_mem(hw, &pd_entry->bp.addr); if (ret_code) goto exit; if (!pd_table->ref_cnt) diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_hmc.h index 732a02660330..386416bf7267 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.h @@ -62,6 +62,7 @@ struct i40e_hmc_bp { struct i40e_hmc_pd_entry { struct i40e_hmc_bp bp; u32 sd_index; + bool rsrc_pg; bool valid; }; @@ -218,7 +219,8 @@ i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw, i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, - u32 pd_index); + u32 pd_index, + struct i40e_dma_mem *rsrc_pg); i40e_status i40e_remove_pd_bp(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, u32 idx); diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c index 0079ad7bcd0e..d399eaf5aad5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c @@ -387,7 +387,7 @@ static i40e_status i40e_create_lan_hmc_object(struct i40e_hw *hw, /* update the pd table entry */ ret_code = i40e_add_pd_table_entry(hw, info->hmc_info, - i); + i, NULL); if (ret_code) { pd_error = true; break; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h index 931c88044300..adc6f71f40a8 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h @@ -62,6 +62,7 @@ struct i40e_hmc_bp { struct i40e_hmc_pd_entry { struct i40e_hmc_bp bp; u32 sd_index; + bool rsrc_pg; bool valid; }; @@ -218,7 +219,8 @@ i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw, i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, - u32 pd_index); + u32 pd_index, + struct i40e_dma_mem *rsrc_pg); i40e_status i40e_remove_pd_bp(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, u32 idx); -- cgit v1.3-6-gb490 From b2a75c5819ec910f430a2ff12fec6cce202899a0 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Mon, 27 Apr 2015 14:57:20 -0400 Subject: i40e: Refine an error message to avoid confusion Change a warning message to indicate what may have really happened when the init_shared_code call fails. Change-ID: I616ace40fed120d0dec86dfc91ab2d7cde466904 Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c7f2a0a74dcf..9ec6fa292b20 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -9767,7 +9767,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = i40e_init_shared_code(hw); if (err) { - dev_info(&pdev->dev, "init_shared_code failed: %d\n", err); + dev_warn(&pdev->dev, "unidentified MAC or BLANK NVM: %d\n", + err); goto err_pf_reset; } -- cgit v1.3-6-gb490 From 76945bf9ff8a2433f1efb777ec64475c1eec08ab Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Mon, 27 Apr 2015 14:57:22 -0400 Subject: i40e/i40evf: Bump version to 1.3.6 for i40e and 1.3.2 for i40evf Bump. Change-ID: I84573d9fa51effc5b29bf5b8c74e3cc8b2673f48 Signed-off-by: Catherine Sullivan Tested-by: Jim Young 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(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 9ec6fa292b20..6ce9086e558a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 1 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 4 +#define DRV_VERSION_BUILD 6 #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 802e158ea981..c698523923e4 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -34,7 +34,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710/X710 Virtual Function Network Driver"; -#define DRV_VERSION "1.2.25" +#define DRV_VERSION "1.3.2" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; -- cgit v1.3-6-gb490 From 7211f6f72f6a7d0c0aaefe03f8c404f5e4704bec Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Wed, 24 Jun 2015 16:51:21 +0000 Subject: staging: sm750fb: remove redundant __func__ in debug statement This patch removes the redundant __func__ from dynamic debug prints as the pr_xxx set of functions can be dynamically controlled to include function name.Also fix a typo in debug statement. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_accel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index 6eee4cd582d1..8ea3a61ba37c 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -100,7 +100,7 @@ int hw_fillrect(struct lynx_accel *accel, { /* int time wait and always busy,seems hardware * got something error */ - pr_debug("%s:De engine always bussy\n", __func__); + pr_debug("De engine always busy\n"); return -1; } -- cgit v1.3-6-gb490 From 202add2a04f6371ee493ff325ae466578c3bb2c5 Mon Sep 17 00:00:00 2001 From: Anatoly Stepanov Date: Mon, 29 Jun 2015 02:43:54 +0300 Subject: staging: sm750fb: replace spaces with tabs Replace spaces with tabs according to checkpatch.pl error message: "ERROR: code indent should use tabs where possible" Signed-off-by: Anatoly Stepanov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_hw.c | 70 +++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 84381bc414e7..3b3089ce3189 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -171,23 +171,23 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) /* Set up GPIO for software I2C to program DVI chip in the Xilinx SP605 board, in order to have video signal. */ - swI2CInit(0, 1); + swI2CInit(0, 1); - /* Customer may NOT use CH7301 DVI chip, which has to be - initialized differently. - */ - if (swI2CReadReg(0xec, 0x4a) == 0x95) - { - /* The following register values for CH7301 are from - Chrontel app note and our experiment. - */ + /* Customer may NOT use CH7301 DVI chip, which has to be + initialized differently. + */ + if (swI2CReadReg(0xec, 0x4a) == 0x95) + { + /* The following register values for CH7301 are from + Chrontel app note and our experiment. + */ pr_info("yes,CH7301 DVI chip found\n"); - swI2CWriteReg(0xec, 0x1d, 0x16); - swI2CWriteReg(0xec, 0x21, 0x9); - swI2CWriteReg(0xec, 0x49, 0xC0); + swI2CWriteReg(0xec, 0x1d, 0x16); + swI2CWriteReg(0xec, 0x21, 0x9); + swI2CWriteReg(0xec, 0x49, 0xC0); pr_info("okay,CH7301 DVI chip setup done\n"); - } + } } /* init 2d engine */ @@ -612,28 +612,28 @@ int hw_sm750_deWait(void) } int hw_sm750_pan_display(struct lynxfb_crtc *crtc, - const struct fb_var_screeninfo *var, - const struct fb_info *info) + const struct fb_var_screeninfo *var, + const struct fb_info *info) { - uint32_t total; - /* check params */ - if ((var->xoffset + var->xres > var->xres_virtual) || - (var->yoffset + var->yres > var->yres_virtual)) { - return -EINVAL; - } - - total = var->yoffset * info->fix.line_length + - ((var->xoffset * var->bits_per_pixel) >> 3); - total += crtc->oScreen; - if (crtc->channel == sm750_primary) { - POKE32(PANEL_FB_ADDRESS, - FIELD_VALUE(PEEK32(PANEL_FB_ADDRESS), - PANEL_FB_ADDRESS, ADDRESS, total)); - } else { - POKE32(CRT_FB_ADDRESS, - FIELD_VALUE(PEEK32(CRT_FB_ADDRESS), - CRT_FB_ADDRESS, ADDRESS, total)); - } - return 0; + uint32_t total; + /* check params */ + if ((var->xoffset + var->xres > var->xres_virtual) || + (var->yoffset + var->yres > var->yres_virtual)) { + return -EINVAL; + } + + total = var->yoffset * info->fix.line_length + + ((var->xoffset * var->bits_per_pixel) >> 3); + total += crtc->oScreen; + if (crtc->channel == sm750_primary) { + POKE32(PANEL_FB_ADDRESS, + FIELD_VALUE(PEEK32(PANEL_FB_ADDRESS), + PANEL_FB_ADDRESS, ADDRESS, total)); + } else { + POKE32(CRT_FB_ADDRESS, + FIELD_VALUE(PEEK32(CRT_FB_ADDRESS), + CRT_FB_ADDRESS, ADDRESS, total)); + } + return 0; } -- cgit v1.3-6-gb490 From 29d87336d4fea45d53a14d33f2fc5d174a4bfd59 Mon Sep 17 00:00:00 2001 From: Anatoly Stepanov Date: Mon, 29 Jun 2015 02:43:55 +0300 Subject: staging: sm750fb: remove trailing whitespaces Remove trailing whitespaces according to checkpatch.pl error message: "ERROR: trailing whitespace" Signed-off-by: Anatoly Stepanov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_hw.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 3b3089ce3189..1dd20beea831 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -28,7 +28,7 @@ int hw_sm750_map(struct lynx_share* share, struct pci_dev* pdev) { int ret; struct sm750_share *spec_share; - + spec_share = container_of(share, struct sm750_share, share); ret = 0; @@ -60,7 +60,7 @@ int hw_sm750_map(struct lynx_share* share, struct pci_dev* pdev) pr_info("mmio virtual addr = %p\n", share->pvReg); } - + share->accel.dprBase = share->pvReg + DE_BASE_ADDR_TYPE1; share->accel.dpPortBase = share->pvReg + DE_PORT_ADDR_TYPE1; @@ -104,7 +104,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) { struct sm750_share *spec_share; struct init_status *parm; - + spec_share = container_of(share, struct sm750_share, share); parm = &spec_share->state.initParm; if(parm->chip_clk == 0) @@ -202,7 +202,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) resource_size_t hw_sm750_getVMSize(struct lynx_share *share) { resource_size_t ret; - + ret = ddk750_getVMSize(); return ret; } @@ -211,7 +211,7 @@ resource_size_t hw_sm750_getVMSize(struct lynx_share *share) int hw_sm750_output_checkMode(struct lynxfb_output* output, struct fb_var_screeninfo* var) { - + return 0; } @@ -222,7 +222,7 @@ int hw_sm750_output_setMode(struct lynxfb_output* output, int ret; disp_output_t dispSet; int channel; - + ret = 0; dispSet = 0; channel = *output->channel; @@ -259,14 +259,14 @@ int hw_sm750_output_setMode(struct lynxfb_output* output, void hw_sm750_output_clear(struct lynxfb_output* output) { - + return; } int hw_sm750_crtc_checkMode(struct lynxfb_crtc* crtc, struct fb_var_screeninfo* var) { struct lynx_share *share; - + share = container_of(crtc, struct lynxfb_par, crtc)->share; @@ -303,7 +303,7 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc* crtc, struct lynx_share *share; struct lynxfb_par *par; - + ret = 0; par = container_of(crtc, struct lynxfb_par, crtc); share = par->share; @@ -414,7 +414,7 @@ exit: void hw_sm750_crtc_clear(struct lynxfb_crtc* crtc) { - + return; } @@ -428,7 +428,7 @@ int hw_sm750_setColReg(struct lynxfb_crtc* crtc, ushort index, int hw_sm750le_setBLANK(struct lynxfb_output * output, int blank){ int dpms, crtdb; - + switch(blank) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) @@ -483,7 +483,7 @@ int hw_sm750le_setBLANK(struct lynxfb_output * output, int blank){ int hw_sm750_setBLANK(struct lynxfb_output* output, int blank) { unsigned int dpms, pps, crtdb; - + dpms = pps = crtdb = 0; switch (blank) @@ -636,4 +636,3 @@ int hw_sm750_pan_display(struct lynxfb_crtc *crtc, } return 0; } - -- cgit v1.3-6-gb490 From e0ded448d0b70e76a8d1111ae33ffeb68524fd91 Mon Sep 17 00:00:00 2001 From: Anatoly Stepanov Date: Mon, 29 Jun 2015 02:43:56 +0300 Subject: staging: sm750fb: insert space between ')' and '{' Insert spaces according to checkpatch.pl message: "ERROR: space required before the open brace '{'" Signed-off-by: Anatoly Stepanov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_hw.c | 40 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 1dd20beea831..dcb5927581d8 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -52,7 +52,7 @@ int hw_sm750_map(struct lynx_share* share, struct pci_dev* pdev) /* now map mmio and vidmem*/ share->pvReg = ioremap_nocache(share->vidreg_start, share->vidreg_size); - if(!share->pvReg){ + if(!share->pvReg) { pr_err("mmio failed\n"); ret = -EFAULT; goto exit; @@ -87,7 +87,7 @@ int hw_sm750_map(struct lynx_share* share, struct pci_dev* pdev) share->pvMem = ioremap_wc(share->vidmem_start, share->vidmem_size); - if(!share->pvMem){ + if(!share->pvMem) { pr_err("Map video memory failed\n"); ret = -EFAULT; goto exit; @@ -119,7 +119,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) ddk750_initHw((initchip_param_t *)&spec_share->state.initParm); /* for sm718,open pci burst */ - if(share->devid == 0x718){ + if(share->devid == 0x718) { POKE32(SYSTEM_CTRL, FIELD_SET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, PCI_BURST, ON)); } @@ -133,7 +133,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) if(getChipType() != SM750LE) { /* does user need CRT ?*/ - if(spec_share->state.nocrt){ + if(spec_share->state.nocrt) { POKE32(MISC_CTRL, FIELD_SET(PEEK32(MISC_CTRL), MISC_CTRL, @@ -155,7 +155,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) DPMS, VPHP)); } - switch (spec_share->state.pnltype){ + switch (spec_share->state.pnltype) { case sm750_doubleTFT: case sm750_24TFT: case sm750_dualTFT: @@ -191,7 +191,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) } /* init 2d engine */ - if(!share->accel_off){ + if(!share->accel_off) { hw_sm750_initAccel(share); } @@ -228,8 +228,8 @@ int hw_sm750_output_setMode(struct lynxfb_output* output, channel = *output->channel; - if(getChipType() != SM750LE){ - if(channel == sm750_primary){ + if(getChipType() != SM750LE) { + if(channel == sm750_primary) { pr_info("primary channel\n"); if(output->paths & sm750_panel) dispSet |= do_LCD1_PRI; @@ -270,7 +270,7 @@ int hw_sm750_crtc_checkMode(struct lynxfb_crtc* crtc, struct fb_var_screeninfo* share = container_of(crtc, struct lynxfb_par, crtc)->share; - switch (var->bits_per_pixel){ + switch (var->bits_per_pixel) { case 8: case 16: break; @@ -308,9 +308,9 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc* crtc, par = container_of(crtc, struct lynxfb_par, crtc); share = par->share; #if 1 - if(!share->accel_off){ + if(!share->accel_off) { /* set 2d engine pixel format according to mode bpp */ - switch(var->bits_per_pixel){ + switch(var->bits_per_pixel) { case 8: fmt = 0; break; @@ -348,12 +348,12 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc* crtc, pr_debug("Request pixel clock = %lu\n", modparm.pixel_clock); ret = ddk750_setModeTiming(&modparm, clock); - if(ret){ + if(ret) { pr_err("Set mode timing failed\n"); goto exit; } - if(crtc->channel != sm750_secondary){ + if(crtc->channel != sm750_secondary) { /* set pitch, offset ,width,start address ,etc... */ POKE32(PANEL_FB_ADDRESS, FIELD_SET(0, PANEL_FB_ADDRESS, STATUS, CURRENT)| @@ -426,7 +426,7 @@ int hw_sm750_setColReg(struct lynxfb_crtc* crtc, ushort index, return 0; } -int hw_sm750le_setBLANK(struct lynxfb_output * output, int blank){ +int hw_sm750le_setBLANK(struct lynxfb_output * output, int blank) { int dpms, crtdb; switch(blank) @@ -473,7 +473,7 @@ int hw_sm750le_setBLANK(struct lynxfb_output * output, int blank){ return -EINVAL; } - if(output->paths & sm750_crt){ + if(output->paths & sm750_crt) { POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, DPMS, dpms)); POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, BLANK, crtdb)); } @@ -535,13 +535,13 @@ int hw_sm750_setBLANK(struct lynxfb_output* output, int blank) break; } - if(output->paths & sm750_crt){ + if(output->paths & sm750_crt) { POKE32(SYSTEM_CTRL, FIELD_VALUE(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, DPMS, dpms)); POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, BLANK, crtdb)); } - if(output->paths & sm750_panel){ + if(output->paths & sm750_panel) { POKE32(PANEL_DISPLAY_CTRL, FIELD_VALUE(PEEK32(PANEL_DISPLAY_CTRL), PANEL_DISPLAY_CTRL, DATA, pps)); } @@ -554,7 +554,7 @@ void hw_sm750_initAccel(struct lynx_share *share) u32 reg; enable2DEngine(1); - if(getChipType() == SM750LE){ + if(getChipType() == SM750LE) { reg = PEEK32(DE_STATE1); reg = FIELD_SET(reg, DE_STATE1, DE_ABORT, ON); POKE32(DE_STATE1, reg); @@ -581,7 +581,7 @@ void hw_sm750_initAccel(struct lynx_share *share) int hw_sm750le_deWait(void) { int i=0x10000000; - while(i--){ + while(i--) { unsigned int dwVal = PEEK32(DE_STATE2); if((FIELD_GET(dwVal, DE_STATE2, DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) && (FIELD_GET(dwVal, DE_STATE2, DE_FIFO) == DE_STATE2_DE_FIFO_EMPTY) && @@ -598,7 +598,7 @@ int hw_sm750le_deWait(void) int hw_sm750_deWait(void) { int i=0x10000000; - while(i--){ + while(i--) { unsigned int dwVal = PEEK32(SYSTEM_CTRL); if((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS) == SYSTEM_CTRL_DE_STATUS_IDLE) && (FIELD_GET(dwVal, SYSTEM_CTRL, DE_FIFO) == SYSTEM_CTRL_DE_FIFO_EMPTY) && -- cgit v1.3-6-gb490 From 6d1b3d64cdc5f22452784ade42ebbc2382a7010e Mon Sep 17 00:00:00 2001 From: Anatoly Stepanov Date: Mon, 29 Jun 2015 02:43:57 +0300 Subject: staging: sm750fb: insert space before open parenthesis Insert spaces before '(' according to checkpatch.pl message: "ERROR: space required before the open parenthesis" Signed-off-by: Anatoly Stepanov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_hw.c | 62 +++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index dcb5927581d8..0e98cd374616 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -44,7 +44,7 @@ int hw_sm750_map(struct lynx_share* share, struct pci_dev* pdev) * successfully * */ - if((ret = pci_request_region(pdev, 1, "sm750fb"))) + if ((ret = pci_request_region(pdev, 1, "sm750fb"))) { pr_err("Can not request PCI regions.\n"); goto exit; @@ -52,7 +52,7 @@ int hw_sm750_map(struct lynx_share* share, struct pci_dev* pdev) /* now map mmio and vidmem*/ share->pvReg = ioremap_nocache(share->vidreg_start, share->vidreg_size); - if(!share->pvReg) { + if (!share->pvReg) { pr_err("mmio failed\n"); ret = -EFAULT; goto exit; @@ -78,7 +78,7 @@ int hw_sm750_map(struct lynx_share* share, struct pci_dev* pdev) /* reserve the vidmem space of smi adaptor */ #if 0 - if((ret = pci_request_region(pdev, 0, _moduleName_))) + if ((ret = pci_request_region(pdev, 0, _moduleName_))) { pr_err("Can not request PCI regions.\n"); goto exit; @@ -87,7 +87,7 @@ int hw_sm750_map(struct lynx_share* share, struct pci_dev* pdev) share->pvMem = ioremap_wc(share->vidmem_start, share->vidmem_size); - if(!share->pvMem) { + if (!share->pvMem) { pr_err("Map video memory failed\n"); ret = -EFAULT; goto exit; @@ -107,19 +107,19 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) spec_share = container_of(share, struct sm750_share, share); parm = &spec_share->state.initParm; - if(parm->chip_clk == 0) + if (parm->chip_clk == 0) parm->chip_clk = (getChipType() == SM750LE)? DEFAULT_SM750LE_CHIP_CLOCK : DEFAULT_SM750_CHIP_CLOCK; - if(parm->mem_clk == 0) + if (parm->mem_clk == 0) parm->mem_clk = parm->chip_clk; - if(parm->master_clk == 0) + if (parm->master_clk == 0) parm->master_clk = parm->chip_clk/3; ddk750_initHw((initchip_param_t *)&spec_share->state.initParm); /* for sm718,open pci burst */ - if(share->devid == 0x718) { + if (share->devid == 0x718) { POKE32(SYSTEM_CTRL, FIELD_SET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, PCI_BURST, ON)); } @@ -130,10 +130,10 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) ddk750_initDVIDisp(); #endif - if(getChipType() != SM750LE) + if (getChipType() != SM750LE) { /* does user need CRT ?*/ - if(spec_share->state.nocrt) { + if (spec_share->state.nocrt) { POKE32(MISC_CTRL, FIELD_SET(PEEK32(MISC_CTRL), MISC_CTRL, @@ -191,7 +191,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) } /* init 2d engine */ - if(!share->accel_off) { + if (!share->accel_off) { hw_sm750_initAccel(share); } @@ -228,19 +228,19 @@ int hw_sm750_output_setMode(struct lynxfb_output* output, channel = *output->channel; - if(getChipType() != SM750LE) { - if(channel == sm750_primary) { + if (getChipType() != SM750LE) { + if (channel == sm750_primary) { pr_info("primary channel\n"); - if(output->paths & sm750_panel) + if (output->paths & sm750_panel) dispSet |= do_LCD1_PRI; - if(output->paths & sm750_crt) + if (output->paths & sm750_crt) dispSet |= do_CRT_PRI; }else{ pr_info("secondary channel\n"); - if(output->paths & sm750_panel) + if (output->paths & sm750_panel) dispSet |= do_LCD1_SEC; - if(output->paths & sm750_crt) + if (output->paths & sm750_crt) dispSet |= do_CRT_SEC; } @@ -308,9 +308,9 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc* crtc, par = container_of(crtc, struct lynxfb_par, crtc); share = par->share; #if 1 - if(!share->accel_off) { + if (!share->accel_off) { /* set 2d engine pixel format according to mode bpp */ - switch(var->bits_per_pixel) { + switch (var->bits_per_pixel) { case 8: fmt = 0; break; @@ -341,19 +341,19 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc* crtc, modparm.vertical_total = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; /* choose pll */ - if(crtc->channel != sm750_secondary) + if (crtc->channel != sm750_secondary) clock = PRIMARY_PLL; else clock = SECONDARY_PLL; pr_debug("Request pixel clock = %lu\n", modparm.pixel_clock); ret = ddk750_setModeTiming(&modparm, clock); - if(ret) { + if (ret) { pr_err("Set mode timing failed\n"); goto exit; } - if(crtc->channel != sm750_secondary) { + if (crtc->channel != sm750_secondary) { /* set pitch, offset ,width,start address ,etc... */ POKE32(PANEL_FB_ADDRESS, FIELD_SET(0, PANEL_FB_ADDRESS, STATUS, CURRENT)| @@ -429,7 +429,7 @@ int hw_sm750_setColReg(struct lynxfb_crtc* crtc, ushort index, int hw_sm750le_setBLANK(struct lynxfb_output * output, int blank) { int dpms, crtdb; - switch(blank) + switch (blank) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) case FB_BLANK_UNBLANK: @@ -473,7 +473,7 @@ int hw_sm750le_setBLANK(struct lynxfb_output * output, int blank) { return -EINVAL; } - if(output->paths & sm750_crt) { + if (output->paths & sm750_crt) { POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, DPMS, dpms)); POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, BLANK, crtdb)); } @@ -535,13 +535,13 @@ int hw_sm750_setBLANK(struct lynxfb_output* output, int blank) break; } - if(output->paths & sm750_crt) { + if (output->paths & sm750_crt) { POKE32(SYSTEM_CTRL, FIELD_VALUE(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, DPMS, dpms)); POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, BLANK, crtdb)); } - if(output->paths & sm750_panel) { + if (output->paths & sm750_panel) { POKE32(PANEL_DISPLAY_CTRL, FIELD_VALUE(PEEK32(PANEL_DISPLAY_CTRL), PANEL_DISPLAY_CTRL, DATA, pps)); } @@ -554,7 +554,7 @@ void hw_sm750_initAccel(struct lynx_share *share) u32 reg; enable2DEngine(1); - if(getChipType() == SM750LE) { + if (getChipType() == SM750LE) { reg = PEEK32(DE_STATE1); reg = FIELD_SET(reg, DE_STATE1, DE_ABORT, ON); POKE32(DE_STATE1, reg); @@ -581,9 +581,9 @@ void hw_sm750_initAccel(struct lynx_share *share) int hw_sm750le_deWait(void) { int i=0x10000000; - while(i--) { + while (i--) { unsigned int dwVal = PEEK32(DE_STATE2); - if((FIELD_GET(dwVal, DE_STATE2, DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) && + if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) && (FIELD_GET(dwVal, DE_STATE2, DE_FIFO) == DE_STATE2_DE_FIFO_EMPTY) && (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO) == DE_STATE2_DE_MEM_FIFO_EMPTY)) { @@ -598,9 +598,9 @@ int hw_sm750le_deWait(void) int hw_sm750_deWait(void) { int i=0x10000000; - while(i--) { + while (i--) { unsigned int dwVal = PEEK32(SYSTEM_CTRL); - if((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS) == SYSTEM_CTRL_DE_STATUS_IDLE) && + if ((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS) == SYSTEM_CTRL_DE_STATUS_IDLE) && (FIELD_GET(dwVal, SYSTEM_CTRL, DE_FIFO) == SYSTEM_CTRL_DE_FIFO_EMPTY) && (FIELD_GET(dwVal, SYSTEM_CTRL, DE_MEM_FIFO) == SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) { -- cgit v1.3-6-gb490 From e188ea325d2419164691d6347b4ff7a4128f64b6 Mon Sep 17 00:00:00 2001 From: Anatoly Stepanov Date: Mon, 29 Jun 2015 02:43:58 +0300 Subject: staging: sm750fb: fix indentation of pointer operator Fix indentation of pointer operator '*' according to checkpatch.pl message: "ERROR: 'foo* bar' should be 'foo *bar' " Signed-off-by: Anatoly Stepanov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_hw.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 0e98cd374616..4f4ec93f098c 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -24,7 +24,7 @@ #include "ddk750.h" #include "sm750_accel.h" -int hw_sm750_map(struct lynx_share* share, struct pci_dev* pdev) +int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev) { int ret; struct sm750_share *spec_share; @@ -209,15 +209,15 @@ resource_size_t hw_sm750_getVMSize(struct lynx_share *share) -int hw_sm750_output_checkMode(struct lynxfb_output* output, struct fb_var_screeninfo* var) +int hw_sm750_output_checkMode(struct lynxfb_output *output, struct fb_var_screeninfo *var) { return 0; } -int hw_sm750_output_setMode(struct lynxfb_output* output, - struct fb_var_screeninfo* var, struct fb_fix_screeninfo* fix) +int hw_sm750_output_setMode(struct lynxfb_output *output, + struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix) { int ret; disp_output_t dispSet; @@ -257,13 +257,13 @@ int hw_sm750_output_setMode(struct lynxfb_output* output, return ret; } -void hw_sm750_output_clear(struct lynxfb_output* output) +void hw_sm750_output_clear(struct lynxfb_output *output) { return; } -int hw_sm750_crtc_checkMode(struct lynxfb_crtc* crtc, struct fb_var_screeninfo* var) +int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc, struct fb_var_screeninfo *var) { struct lynx_share *share; @@ -292,9 +292,9 @@ int hw_sm750_crtc_checkMode(struct lynxfb_crtc* crtc, struct fb_var_screeninfo* /* set the controller's mode for @crtc charged with @var and @fix parameters */ -int hw_sm750_crtc_setMode(struct lynxfb_crtc* crtc, - struct fb_var_screeninfo* var, - struct fb_fix_screeninfo* fix) +int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc, + struct fb_var_screeninfo *var, + struct fb_fix_screeninfo *fix) { int ret, fmt; u32 reg; @@ -412,13 +412,13 @@ exit: return ret; } -void hw_sm750_crtc_clear(struct lynxfb_crtc* crtc) +void hw_sm750_crtc_clear(struct lynxfb_crtc *crtc) { return; } -int hw_sm750_setColReg(struct lynxfb_crtc* crtc, ushort index, +int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, ushort red, ushort green, ushort blue) { static unsigned int add[]={PANEL_PALETTE_RAM, CRT_PALETTE_RAM}; @@ -426,7 +426,7 @@ int hw_sm750_setColReg(struct lynxfb_crtc* crtc, ushort index, return 0; } -int hw_sm750le_setBLANK(struct lynxfb_output * output, int blank) { +int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank) { int dpms, crtdb; switch (blank) @@ -480,7 +480,7 @@ int hw_sm750le_setBLANK(struct lynxfb_output * output, int blank) { return 0; } -int hw_sm750_setBLANK(struct lynxfb_output* output, int blank) +int hw_sm750_setBLANK(struct lynxfb_output *output, int blank) { unsigned int dpms, pps, crtdb; -- cgit v1.3-6-gb490 From 4bcdffee2d9b9fddb617431bbd9231576eb4054b Mon Sep 17 00:00:00 2001 From: Anatoly Stepanov Date: Mon, 29 Jun 2015 02:43:59 +0300 Subject: staging: sm750fb: put open brace on the previous line Fix open braces according to checkpatch.pl message: "ERROR: that open brace { should be on the previous line" Signed-off-by: Anatoly Stepanov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_hw.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 4f4ec93f098c..4dded626023d 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -44,8 +44,7 @@ int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev) * successfully * */ - if ((ret = pci_request_region(pdev, 1, "sm750fb"))) - { + if ((ret = pci_request_region(pdev, 1, "sm750fb"))) { pr_err("Can not request PCI regions.\n"); goto exit; } @@ -78,8 +77,7 @@ int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev) /* reserve the vidmem space of smi adaptor */ #if 0 - if ((ret = pci_request_region(pdev, 0, _moduleName_))) - { + if ((ret = pci_request_region(pdev, 0, _moduleName_))) { pr_err("Can not request PCI regions.\n"); goto exit; } @@ -130,8 +128,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) ddk750_initDVIDisp(); #endif - if (getChipType() != SM750LE) - { + if (getChipType() != SM750LE) { /* does user need CRT ?*/ if (spec_share->state.nocrt) { POKE32(MISC_CTRL, @@ -177,8 +174,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) /* Customer may NOT use CH7301 DVI chip, which has to be initialized differently. */ - if (swI2CReadReg(0xec, 0x4a) == 0x95) - { + if (swI2CReadReg(0xec, 0x4a) == 0x95) { /* The following register values for CH7301 are from Chrontel app note and our experiment. */ @@ -429,8 +425,7 @@ int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank) { int dpms, crtdb; - switch (blank) - { + switch (blank) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) case FB_BLANK_UNBLANK: #else @@ -486,8 +481,7 @@ int hw_sm750_setBLANK(struct lynxfb_output *output, int blank) dpms = pps = crtdb = 0; - switch (blank) - { + switch (blank) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) case FB_BLANK_UNBLANK: #else @@ -585,8 +579,7 @@ int hw_sm750le_deWait(void) unsigned int dwVal = PEEK32(DE_STATE2); if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) && (FIELD_GET(dwVal, DE_STATE2, DE_FIFO) == DE_STATE2_DE_FIFO_EMPTY) && - (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO) == DE_STATE2_DE_MEM_FIFO_EMPTY)) - { + (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO) == DE_STATE2_DE_MEM_FIFO_EMPTY)) { return 0; } } @@ -602,8 +595,7 @@ int hw_sm750_deWait(void) unsigned int dwVal = PEEK32(SYSTEM_CTRL); if ((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS) == SYSTEM_CTRL_DE_STATUS_IDLE) && (FIELD_GET(dwVal, SYSTEM_CTRL, DE_FIFO) == SYSTEM_CTRL_DE_FIFO_EMPTY) && - (FIELD_GET(dwVal, SYSTEM_CTRL, DE_MEM_FIFO) == SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) - { + (FIELD_GET(dwVal, SYSTEM_CTRL, DE_MEM_FIFO) == SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) { return 0; } } -- cgit v1.3-6-gb490 From 5e83e2832b86e76a273e197aae580b81541af352 Mon Sep 17 00:00:00 2001 From: Anatoly Stepanov Date: Mon, 29 Jun 2015 02:44:00 +0300 Subject: staging: sm750fb: fix indentation in 'else' statements Fix indentation according to checkpatch.pl message: "ERROR: space required after that close brace '}'" Signed-off-by: Anatoly Stepanov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_hw.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 4dded626023d..9de253209536 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -55,7 +55,7 @@ int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev) pr_err("mmio failed\n"); ret = -EFAULT; goto exit; - }else{ + } else { pr_info("mmio virtual addr = %p\n", share->pvReg); } @@ -89,7 +89,7 @@ int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev) pr_err("Map video memory failed\n"); ret = -EFAULT; goto exit; - }else{ + } else { pr_info("video memory vaddr = %p\n", share->pvMem); } exit: @@ -140,7 +140,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) FIELD_SET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, DPMS, VNHN)); - }else{ + } else { POKE32(MISC_CTRL, FIELD_SET(PEEK32(MISC_CTRL), MISC_CTRL, @@ -163,7 +163,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) spec_share->state.pnltype)); break; } - }else{ + } else { /* for 750LE ,no DVI chip initilization makes Monitor no signal */ /* Set up GPIO for software I2C to program DVI chip in the Xilinx SP605 board, in order to have video signal. @@ -232,7 +232,7 @@ int hw_sm750_output_setMode(struct lynxfb_output *output, if (output->paths & sm750_crt) dispSet |= do_CRT_PRI; - }else{ + } else { pr_info("secondary channel\n"); if (output->paths & sm750_panel) dispSet |= do_LCD1_SEC; @@ -241,7 +241,7 @@ int hw_sm750_output_setMode(struct lynxfb_output *output, } ddk750_setLogicalDispOut(dispSet); - }else{ + } else { /* just open DISPLAY_CONTROL_750LE register bit 3:0*/ u32 reg; reg = PEEK32(DISPLAY_CONTROL_750LE); @@ -385,7 +385,7 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc, PANEL_DISPLAY_CTRL, FORMAT, (var->bits_per_pixel >> 4) )); - }else{ + } else { /* not implemented now */ POKE32(CRT_FB_ADDRESS, crtc->oScreen); reg = var->xres * (var->bits_per_pixel >> 3); @@ -557,7 +557,7 @@ void hw_sm750_initAccel(struct lynx_share *share) reg = FIELD_SET(reg, DE_STATE1, DE_ABORT, OFF); POKE32(DE_STATE1, reg); - }else{ + } else { /* engine reset */ reg = PEEK32(SYSTEM_CTRL); reg = FIELD_SET(reg, SYSTEM_CTRL, DE_ABORT, ON); -- cgit v1.3-6-gb490 From 990e56663bc6012512fd32fc5e92c54bd58ed688 Mon Sep 17 00:00:00 2001 From: Anatoly Stepanov Date: Mon, 29 Jun 2015 02:44:01 +0300 Subject: staging: sm750fb: fix 'switch and case' indentation Fix according to checkpatch.pl message: "ERROR: switch and case should be at the same indent" Signed-off-by: Anatoly Stepanov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_hw.c | 172 ++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 9de253209536..3093c2540bda 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -153,15 +153,15 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) } switch (spec_share->state.pnltype) { - case sm750_doubleTFT: - case sm750_24TFT: - case sm750_dualTFT: - POKE32(PANEL_DISPLAY_CTRL, - FIELD_VALUE(PEEK32(PANEL_DISPLAY_CTRL), - PANEL_DISPLAY_CTRL, - TFT_DISP, - spec_share->state.pnltype)); - break; + case sm750_doubleTFT: + case sm750_24TFT: + case sm750_dualTFT: + POKE32(PANEL_DISPLAY_CTRL, + FIELD_VALUE(PEEK32(PANEL_DISPLAY_CTRL), + PANEL_DISPLAY_CTRL, + TFT_DISP, + spec_share->state.pnltype)); + break; } } else { /* for 750LE ,no DVI chip initilization makes Monitor no signal */ @@ -267,17 +267,17 @@ int hw_sm750_crtc_checkMode(struct lynxfb_crtc *crtc, struct fb_var_screeninfo * share = container_of(crtc, struct lynxfb_par, crtc)->share; switch (var->bits_per_pixel) { - case 8: - case 16: - break; - case 32: - if (share->revid == SM750LE_REVISION_ID) { - pr_debug("750le do not support 32bpp\n"); - return -EINVAL; - } - break; - default: + case 8: + case 16: + break; + case 32: + if (share->revid == SM750LE_REVISION_ID) { + pr_debug("750le do not support 32bpp\n"); return -EINVAL; + } + break; + default: + return -EINVAL; } @@ -307,16 +307,16 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc, if (!share->accel_off) { /* set 2d engine pixel format according to mode bpp */ switch (var->bits_per_pixel) { - case 8: - fmt = 0; - break; - case 16: - fmt = 1; - break; - case 32: - default: - fmt = 2; - break; + case 8: + fmt = 0; + break; + case 16: + fmt = 1; + break; + case 32: + default: + fmt = 2; + break; } hw_set2dformat(&share->accel, fmt); } @@ -427,45 +427,45 @@ int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank) { switch (blank) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) - case FB_BLANK_UNBLANK: + case FB_BLANK_UNBLANK: #else - case VESA_NO_BLANKING: + case VESA_NO_BLANKING: #endif - dpms = CRT_DISPLAY_CTRL_DPMS_0; - crtdb = CRT_DISPLAY_CTRL_BLANK_OFF; - break; + dpms = CRT_DISPLAY_CTRL_DPMS_0; + crtdb = CRT_DISPLAY_CTRL_BLANK_OFF; + break; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) - case FB_BLANK_NORMAL: - dpms = CRT_DISPLAY_CTRL_DPMS_0; - crtdb = CRT_DISPLAY_CTRL_BLANK_ON; - break; + case FB_BLANK_NORMAL: + dpms = CRT_DISPLAY_CTRL_DPMS_0; + crtdb = CRT_DISPLAY_CTRL_BLANK_ON; + break; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) - case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: #else - case VESA_VSYNC_SUSPEND: + case VESA_VSYNC_SUSPEND: #endif - dpms = CRT_DISPLAY_CTRL_DPMS_2; - crtdb = CRT_DISPLAY_CTRL_BLANK_ON; - break; + dpms = CRT_DISPLAY_CTRL_DPMS_2; + crtdb = CRT_DISPLAY_CTRL_BLANK_ON; + break; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) - case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: #else - case VESA_HSYNC_SUSPEND: + case VESA_HSYNC_SUSPEND: #endif - dpms = CRT_DISPLAY_CTRL_DPMS_1; - crtdb = CRT_DISPLAY_CTRL_BLANK_ON; - break; + dpms = CRT_DISPLAY_CTRL_DPMS_1; + crtdb = CRT_DISPLAY_CTRL_BLANK_ON; + break; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) - case FB_BLANK_POWERDOWN: + case FB_BLANK_POWERDOWN: #else - case VESA_POWERDOWN: + case VESA_POWERDOWN: #endif - dpms = CRT_DISPLAY_CTRL_DPMS_3; - crtdb = CRT_DISPLAY_CTRL_BLANK_ON; - break; - default: - return -EINVAL; + dpms = CRT_DISPLAY_CTRL_DPMS_3; + crtdb = CRT_DISPLAY_CTRL_BLANK_ON; + break; + default: + return -EINVAL; } if (output->paths & sm750_crt) { @@ -483,50 +483,50 @@ int hw_sm750_setBLANK(struct lynxfb_output *output, int blank) switch (blank) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) - case FB_BLANK_UNBLANK: + case FB_BLANK_UNBLANK: #else - case VESA_NO_BLANKING: + case VESA_NO_BLANKING: #endif - pr_info("flag = FB_BLANK_UNBLANK \n"); - dpms = SYSTEM_CTRL_DPMS_VPHP; - pps = PANEL_DISPLAY_CTRL_DATA_ENABLE; - crtdb = CRT_DISPLAY_CTRL_BLANK_OFF; - break; + pr_info("flag = FB_BLANK_UNBLANK \n"); + dpms = SYSTEM_CTRL_DPMS_VPHP; + pps = PANEL_DISPLAY_CTRL_DATA_ENABLE; + crtdb = CRT_DISPLAY_CTRL_BLANK_OFF; + break; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) - case FB_BLANK_NORMAL: - pr_info("flag = FB_BLANK_NORMAL \n"); - dpms = SYSTEM_CTRL_DPMS_VPHP; - pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; - crtdb = CRT_DISPLAY_CTRL_BLANK_ON; - break; + case FB_BLANK_NORMAL: + pr_info("flag = FB_BLANK_NORMAL \n"); + dpms = SYSTEM_CTRL_DPMS_VPHP; + pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; + crtdb = CRT_DISPLAY_CTRL_BLANK_ON; + break; #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) - case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: #else - case VESA_VSYNC_SUSPEND: + case VESA_VSYNC_SUSPEND: #endif - dpms = SYSTEM_CTRL_DPMS_VNHP; - pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; - crtdb = CRT_DISPLAY_CTRL_BLANK_ON; - break; + dpms = SYSTEM_CTRL_DPMS_VNHP; + pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; + crtdb = CRT_DISPLAY_CTRL_BLANK_ON; + break; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) - case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: #else - case VESA_HSYNC_SUSPEND: + case VESA_HSYNC_SUSPEND: #endif - dpms = SYSTEM_CTRL_DPMS_VPHN; - pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; - crtdb = CRT_DISPLAY_CTRL_BLANK_ON; - break; + dpms = SYSTEM_CTRL_DPMS_VPHN; + pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; + crtdb = CRT_DISPLAY_CTRL_BLANK_ON; + break; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) - case FB_BLANK_POWERDOWN: + case FB_BLANK_POWERDOWN: #else - case VESA_POWERDOWN: + case VESA_POWERDOWN: #endif - dpms = SYSTEM_CTRL_DPMS_VNHN; - pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; - crtdb = CRT_DISPLAY_CTRL_BLANK_ON; - break; + dpms = SYSTEM_CTRL_DPMS_VNHN; + pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; + crtdb = CRT_DISPLAY_CTRL_BLANK_ON; + break; } if (output->paths & sm750_crt) { -- cgit v1.3-6-gb490 From 9a52ae2dd8c24a3ab53bb68ea2b5f94c11e3f5a8 Mon Sep 17 00:00:00 2001 From: Anatoly Stepanov Date: Mon, 29 Jun 2015 02:44:02 +0300 Subject: staging: sm750fb: remove assignment from if condition Remove assignment from if condition according to checkpatch.pl message: "ERROR: do not use assignment in if condition" Signed-off-by: Anatoly Stepanov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_hw.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 3093c2540bda..987da9e2aa2f 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -43,8 +43,8 @@ int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev) * in lynxfb_remove, or memory will not be mapped again * successfully * */ - - if ((ret = pci_request_region(pdev, 1, "sm750fb"))) { + ret = pci_request_region(pdev, 1, "sm750fb"); + if (ret) { pr_err("Can not request PCI regions.\n"); goto exit; } @@ -77,7 +77,8 @@ int hw_sm750_map(struct lynx_share *share, struct pci_dev *pdev) /* reserve the vidmem space of smi adaptor */ #if 0 - if ((ret = pci_request_region(pdev, 0, _moduleName_))) { + ret = pci_request_region(pdev, 0, _moduleName_); + if (ret) { pr_err("Can not request PCI regions.\n"); goto exit; } -- cgit v1.3-6-gb490 From 14a974c567aa30070f87ec6652c1727a0e03f11a Mon Sep 17 00:00:00 2001 From: Anatoly Stepanov Date: Mon, 29 Jun 2015 02:44:03 +0300 Subject: staging: sm750fb: fix open brace in function declaration Fix according to checkpatch.pl message: "ERROR: open brace '{' following function declarations go on the next line" Signed-off-by: Anatoly Stepanov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 987da9e2aa2f..a4f0cd06e74c 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -423,7 +423,8 @@ int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, return 0; } -int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank) { +int hw_sm750le_setBLANK(struct lynxfb_output *output, int blank) +{ int dpms, crtdb; switch (blank) { -- cgit v1.3-6-gb490 From d5fca4035a59eb4b120b2ffd645f12508dfb2ed6 Mon Sep 17 00:00:00 2001 From: Anatoly Stepanov Date: Mon, 29 Jun 2015 02:44:04 +0300 Subject: staging: sm750fb: add required spaces around C operators Add spaces according to checkpatch.pl messages: "ERROR: spaces required around that '=' (ctx:VxV)" "ERROR: need consistent spacing around '-' (ctx:WxV)" "ERROR: spaces required around that '?' (ctx:VxE)" "ERROR: need consistent spacing around '&' (ctx:VxW)" Signed-off-by: Anatoly Stepanov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_hw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index a4f0cd06e74c..359165d523d0 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -107,7 +107,7 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) spec_share = container_of(share, struct sm750_share, share); parm = &spec_share->state.initParm; if (parm->chip_clk == 0) - parm->chip_clk = (getChipType() == SM750LE)? + parm->chip_clk = (getChipType() == SM750LE) ? DEFAULT_SM750LE_CHIP_CLOCK : DEFAULT_SM750_CHIP_CLOCK; @@ -327,7 +327,7 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc, modparm.pixel_clock = ps_to_hz(var->pixclock); modparm.vertical_sync_polarity = (var->sync & FB_SYNC_HOR_HIGH_ACT) ? POS:NEG; modparm.horizontal_sync_polarity = (var->sync & FB_SYNC_VERT_HIGH_ACT) ? POS:NEG; - modparm.clock_phase_polarity = (var->sync& FB_SYNC_COMP_HIGH_ACT) ? POS:NEG; + modparm.clock_phase_polarity = (var->sync & FB_SYNC_COMP_HIGH_ACT) ? POS:NEG; modparm.horizontal_display_end = var->xres; modparm.horizontal_sync_width = var->hsync_len; modparm.horizontal_sync_start = var->xres + var->right_margin; @@ -366,7 +366,7 @@ int hw_sm750_crtc_setMode(struct lynxfb_crtc *crtc, FIELD_VALUE(0, PANEL_FB_WIDTH, OFFSET, fix->line_length)); POKE32(PANEL_WINDOW_WIDTH, - FIELD_VALUE(0, PANEL_WINDOW_WIDTH, WIDTH, var->xres -1)| + FIELD_VALUE(0, PANEL_WINDOW_WIDTH, WIDTH, var->xres - 1)| FIELD_VALUE(0, PANEL_WINDOW_WIDTH, X, var->xoffset)); POKE32(PANEL_WINDOW_HEIGHT, @@ -418,7 +418,7 @@ void hw_sm750_crtc_clear(struct lynxfb_crtc *crtc) int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, ushort red, ushort green, ushort blue) { - static unsigned int add[]={PANEL_PALETTE_RAM, CRT_PALETTE_RAM}; + static unsigned int add[] = {PANEL_PALETTE_RAM, CRT_PALETTE_RAM}; POKE32(add[crtc->channel] + index*4, (red<<16)|(green<<8)|blue); return 0; } @@ -576,7 +576,7 @@ void hw_sm750_initAccel(struct lynx_share *share) int hw_sm750le_deWait(void) { - int i=0x10000000; + int i = 0x10000000; while (i--) { unsigned int dwVal = PEEK32(DE_STATE2); if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) && @@ -592,7 +592,7 @@ int hw_sm750le_deWait(void) int hw_sm750_deWait(void) { - int i=0x10000000; + int i = 0x10000000; while (i--) { unsigned int dwVal = PEEK32(SYSTEM_CTRL); if ((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS) == SYSTEM_CTRL_DE_STATUS_IDLE) && -- cgit v1.3-6-gb490 From df525686865a79a44b39f7032cf94e625e894865 Mon Sep 17 00:00:00 2001 From: Vinay Simha BN Date: Tue, 14 Jul 2015 19:15:28 +0530 Subject: staging: sm750fb: coding style global ERROR fixes kernel coding style fixes for below messages from scripts/checkpatch.pl ERROR: do not initialise globals to 0 or NULL Signed-off-by: Vinay Simha BN Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_help.c | 6 +++--- drivers/staging/sm750fb/sm750.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_help.c b/drivers/staging/sm750fb/ddk750_help.c index 1adcafcc5133..f027df58fc11 100644 --- a/drivers/staging/sm750fb/ddk750_help.c +++ b/drivers/staging/sm750fb/ddk750_help.c @@ -1,8 +1,8 @@ #include "ddk750_help.h" -void __iomem *mmio750 = NULL; -char revId750 = 0; -unsigned short devId750 = 0; +void __iomem *mmio750; +char revId750; +unsigned short devId750; /* after driver mapped io registers, use this function first */ void ddk750_set_mmio(void __iomem *addr, unsigned short devId, char revId) diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index 8e201f19cc0d..4d165ca3baad 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -24,7 +24,7 @@ #include "modedb.h" -int smi_indent = 0; +int smi_indent; /* @@ -47,9 +47,9 @@ static int g_noaccel; static int g_nomtrr; static const char *g_fbmode[] = {NULL, NULL}; static const char *g_def_fbmode = "800x600-16@60"; -static char *g_settings = NULL; +static char *g_settings; static int g_dualview; -static char *g_option = NULL; +static char *g_option; static const struct fb_videomode lynx750_ext[] = { -- cgit v1.3-6-gb490 From a43abee7de3967b7a211ae17563e2e2db40c4f5d Mon Sep 17 00:00:00 2001 From: Anders Fridlund Date: Thu, 9 Jul 2015 14:45:22 +0200 Subject: Staging: sm750fb: ddk750_dvi.h: Fix brace coding style issue This is a patch to the ddk750_dvi.h file that fixes up a brace error found by the checkpatch.pl tool Signed-off-by: Anders Fridlund Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_dvi.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_dvi.h b/drivers/staging/sm750fb/ddk750_dvi.h index 83bbd6d62061..e1d4c9a2d50a 100644 --- a/drivers/staging/sm750fb/ddk750_dvi.h +++ b/drivers/staging/sm750fb/ddk750_dvi.h @@ -26,8 +26,7 @@ typedef unsigned char (*PFN_DVICTRL_CHECKINTERRUPT)(void); typedef void (*PFN_DVICTRL_CLEARINTERRUPT)(void); /* Structure to hold all the function pointer to the DVI Controller. */ -typedef struct _dvi_ctrl_device_t -{ +typedef struct _dvi_ctrl_device_t { PFN_DVICTRL_INIT pfnInit; PFN_DVICTRL_RESETCHIP pfnResetChip; PFN_DVICTRL_GETCHIPSTRING pfnGetChipString; -- cgit v1.3-6-gb490 From addce19f58c52a03314e2d8a1e30708dabf9bf30 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:41 -0400 Subject: staging: unisys: respond to msgs post device_create Fix problem that prevents us from responding to any device message after device_create. By neglecting to NULL out pending_msg_hdr after the device_create response, we were effectively preventing any subsequent messages to the device from working, because device_epilog() will correctly bail out early if it sees that pending_msg_hdr is still set non-NULL, as that is an indicator to mean that an unanswered message is still outstanding. This problem was discovered as part of testing IOVM service partition recovery, because device_epilog() was in fact bailing out when it was called from my_device_changestate(), which of course prevented us from transitioning the device to the paused state. However, the incorrect behavior would occur for ANY subsequent command directed at the device, not just for changestate. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorbus/visorchipset.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorbus/visorchipset.c b/drivers/staging/unisys/visorbus/visorchipset.c index bb8087e70127..d47ec24e2dc5 100644 --- a/drivers/staging/unisys/visorbus/visorchipset.c +++ b/drivers/staging/unisys/visorbus/visorchipset.c @@ -2047,6 +2047,7 @@ device_create_response(struct visor_device *dev_info, int response) response); kfree(dev_info->pending_msg_hdr); + dev_info->pending_msg_hdr = NULL; } static void -- cgit v1.3-6-gb490 From d15a65be5542ab0c4792a54cf90419fbaf741791 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:42 -0400 Subject: staging: unisys: prevent faults processing messages Prevent faults processing messages for devices that no driver has yet registered to handle. Previously, code of the form: drv = to_visor_driver(dev->device.driver); if (!drv) goto away; was not having the desired intent, because to_visor_driver() was essentially returning garbage if its argument was NULL. The only existing case of this is in initiate_chipset_device_pause_resume(), which is called during IOVM service partition recovery. We were thus faulting when IOVM service partition recovery was initiated on a bus that had at least one device for which no function driver had registered (visorbus_register_visor_driver). Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/include/visorbus.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/include/visorbus.h b/drivers/staging/unisys/include/visorbus.h index e4a21e42e868..a0144c6a8ad1 100644 --- a/drivers/staging/unisys/include/visorbus.h +++ b/drivers/staging/unisys/include/visorbus.h @@ -113,7 +113,8 @@ struct visor_driver { struct driver_attribute version_attr; }; -#define to_visor_driver(x) container_of(x, struct visor_driver, driver) +#define to_visor_driver(x) ((x) ? \ + (container_of(x, struct visor_driver, driver)) : (NULL)) /** A device type for things "plugged" into the visorbus bus */ -- cgit v1.3-6-gb490 From d01da5eac098c4676dd5d296b5be5b0f988fc3c8 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:43 -0400 Subject: staging: unisys: visornic: correct visornic_pause Correct visornic_pause() to indicate completion asynchronously rather than in-line Previously, visornic_pause() (called to stop the device due to IOVM service partition recovery) was calling the passed complete_func() in-line, rather than delaying the calling until after the device had actually been stopped. The behavior has been corrected so that the calling of the complete_func() is now delayed until after the stopping of the device has been completed in visornic_serverdown_complete(), which runs asynchronously via the workqueue visornic_serverdown_workqueue. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 710074437737..fa52e0fa5cbc 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -151,6 +151,7 @@ struct visornic_devdata { * sent to the IOPART end */ struct work_struct serverdown_completion; + visorbus_state_complete_func server_down_complete_func; struct work_struct timeout_reset; struct uiscmdrsp *cmdrsp_rcv; /* cmdrsp_rcv is used for * posting/unposting rcv buffers @@ -545,8 +546,12 @@ visornic_serverdown_complete(struct work_struct *work) atomic_set(&devdata->num_rcvbuf_in_iovm, 0); spin_unlock_irqrestore(&devdata->priv_lock, flags); + if (devdata->server_down_complete_func) + (*devdata->server_down_complete_func)(devdata->dev, 0); + devdata->server_down = true; devdata->server_change_state = false; + devdata->server_down_complete_func = NULL; } /** @@ -558,10 +563,12 @@ visornic_serverdown_complete(struct work_struct *work) * Returns 0 if we scheduled the work, -EINVAL on error. */ static int -visornic_serverdown(struct visornic_devdata *devdata) +visornic_serverdown(struct visornic_devdata *devdata, + visorbus_state_complete_func complete_func) { if (!devdata->server_down && !devdata->server_change_state) { devdata->server_change_state = true; + devdata->server_down_complete_func = complete_func; queue_work(visornic_serverdown_workqueue, &devdata->serverdown_completion); } else if (devdata->server_change_state) { @@ -895,7 +902,7 @@ visornic_timeout_reset(struct work_struct *work) return; call_serverdown: - visornic_serverdown(devdata); + visornic_serverdown(devdata, NULL); } /** @@ -1980,8 +1987,7 @@ static int visornic_pause(struct visor_device *dev, { struct visornic_devdata *devdata = dev_get_drvdata(&dev->device); - visornic_serverdown(devdata); - complete_func(dev, 0); + visornic_serverdown(devdata, complete_func); return 0; } -- cgit v1.3-6-gb490 From 5deeea3379b2fc34d07cfb909b2905e9e1116615 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:44 -0400 Subject: staging: unisys: prevent faults in visornic_pause Prevent faults in visornic_pause, visornic_resume(), and visornic_remove() Prior to this patch, any call to visornic_pause(), visornic_resume(), or visornic_remove() would fault, due to dev_set_drvdata() never having been called to stash our struct visornic_devdata * into the device's drvdata. I.e., all calls to dev_get_drvdata() were returning NULL, meaning a fault was soon to follow. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index fa52e0fa5cbc..72253a07c255 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1831,6 +1831,7 @@ static int visornic_probe(struct visor_device *dev) } devdata->netdev = netdev; + dev_set_drvdata(&dev->device, devdata); init_waitqueue_head(&devdata->rsp_queue); spin_lock_init(&devdata->priv_lock); devdata->enabled = 0; /* not yet */ -- cgit v1.3-6-gb490 From 46dfa3d83464c7ee694ff32761645c3e27fcfc48 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:45 -0400 Subject: staging: unisys: neglect to NULL rcvbuf pointer Neglect to NULL rcvbuf pointer array could result in faults later This problem would exhibit itself as a fault when when attempting to stop any visornic device (i.e., in visornic_disable_with_timeout() or visornic_serverdown_complete()) that had never been started (i.e., for which init_rcv_bufs() had never been called). Because the array of rcvbuf was never cleared to NULLs, we would mistakenly attempt to call kfree_skb() on garbage memory. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 72253a07c255..915c9132a5c4 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1845,7 +1845,7 @@ static int visornic_probe(struct visor_device *dev) if (err) goto cleanup_netdev; - devdata->rcvbuf = kmalloc(sizeof(struct sk_buff *) * + devdata->rcvbuf = kzalloc(sizeof(struct sk_buff *) * devdata->num_rcv_bufs, GFP_KERNEL); if (!devdata->rcvbuf) { err = -ENOMEM; -- cgit v1.3-6-gb490 From 00748b0c69becb3fc4e520a3f9047b46d3bffe2c Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:46 -0400 Subject: staging: unisys: add error messages to visornic Add error message to genuine rare error paths, and debug messages to enable relatively non-verbose tracing of code paths You can enable debug messages by including this on the kernel command line: visornic.dyndbg=+p or by this from the command line: echo "module visornic +p" > /dynamic_debug/control Refer to Documentation/dynamic-debug-howto.txt for more details. In addition to the new debug and error messages, a message like the following will be logged every time a visornic device is probed, which will enable you to map back-and-forth between visorbus device names (e.g., "vbus2:dev0") and netdev names (e.g., "eth0"): visornic vbus2:dev0: visornic_probe success netdev=eth0 With this patch and visornic debugging enabled, you should expect to see messages like the following in the most-common scenarios: * driver loaded: visornic_init * device probed: visornic vbus2:dev0: visornic_probe visor_thread_start visor_thread_start success * network interface configured (ifconfig): net eth0: visornic_open net eth0: visornic_enable_with_timeout net eth0: visornic_enable_with_timeout success net eth0: visornic_open success Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 91 ++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 915c9132a5c4..de05ac79662a 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -299,6 +299,8 @@ static int visor_thread_start(struct visor_thread_info *thrinfo, init_completion(&thrinfo->has_stopped); thrinfo->task = kthread_run(threadfn, thrcontext, name); if (IS_ERR(thrinfo->task)) { + pr_debug("%s failed (%ld)\n", + __func__, PTR_ERR(thrinfo->task)); thrinfo->id = 0; return -EINVAL; } @@ -572,6 +574,8 @@ visornic_serverdown(struct visornic_devdata *devdata, queue_work(visornic_serverdown_workqueue, &devdata->serverdown_completion); } else if (devdata->server_change_state) { + dev_dbg(&devdata->dev->device, "%s changing state\n", + __func__); return -EINVAL; } return 0; @@ -708,6 +712,8 @@ visornic_disable_with_timeout(struct net_device *netdev, const int timeout) break; if (devdata->server_down || devdata->server_change_state) { spin_unlock_irqrestore(&devdata->priv_lock, flags); + dev_dbg(&netdev->dev, "%s server went away\n", + __func__); return -EIO; } set_current_state(TASK_INTERRUPTIBLE); @@ -821,8 +827,11 @@ visornic_enable_with_timeout(struct net_device *netdev, const int timeout) * gets a disable. */ i = init_rcv_bufs(netdev, devdata); - if (i < 0) + if (i < 0) { + dev_err(&netdev->dev, + "%s failed to init rcv bufs (%d)\n", __func__, i); return i; + } spin_lock_irqsave(&devdata->priv_lock, flags); devdata->enabled = 1; @@ -845,6 +854,8 @@ visornic_enable_with_timeout(struct net_device *netdev, const int timeout) break; if (devdata->server_down || devdata->server_change_state) { spin_unlock_irqrestore(&devdata->priv_lock, flags); + dev_dbg(&netdev->dev, "%s server went away\n", + __func__); return -EIO; } set_current_state(TASK_INTERRUPTIBLE); @@ -855,8 +866,10 @@ visornic_enable_with_timeout(struct net_device *netdev, const int timeout) spin_unlock_irqrestore(&devdata->priv_lock, flags); - if (!devdata->enab_dis_acked) + if (!devdata->enab_dis_acked) { + dev_err(&netdev->dev, "%s missing ACK\n", __func__); return -EIO; + } /* find an open slot in the array to save off VisorNic references * for debug @@ -968,6 +981,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) devdata->server_change_state) { spin_unlock_irqrestore(&devdata->priv_lock, flags); devdata->busy_cnt++; + dev_dbg(&netdev->dev, + "%s busy - queue stopped\n", __func__); return NETDEV_TX_BUSY; } @@ -986,6 +1001,9 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) if (firstfraglen < ETH_HEADER_SIZE) { spin_unlock_irqrestore(&devdata->priv_lock, flags); devdata->busy_cnt++; + dev_err(&netdev->dev, + "%s busy - first frag too small (%d)\n", + __func__, firstfraglen); return NETDEV_TX_BUSY; } @@ -1025,6 +1043,9 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) netif_stop_queue(netdev); spin_unlock_irqrestore(&devdata->priv_lock, flags); devdata->busy_cnt++; + dev_dbg(&netdev->dev, + "%s busy - waiting for iovm to catch up\n", + __func__); return NETDEV_TX_BUSY; } if (devdata->queuefullmsg_logged) @@ -1065,6 +1086,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) if (cmdrsp->net.xmt.num_frags == -1) { spin_unlock_irqrestore(&devdata->priv_lock, flags); devdata->busy_cnt++; + dev_err(&netdev->dev, + "%s busy - copy frags failed\n", __func__); return NETDEV_TX_BUSY; } @@ -1073,6 +1096,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) netif_stop_queue(netdev); spin_unlock_irqrestore(&devdata->priv_lock, flags); devdata->busy_cnt++; + dev_dbg(&netdev->dev, + "%s busy - signalinsert failed\n", __func__); return NETDEV_TX_BUSY; } @@ -1105,6 +1130,9 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) * netif_wake_queue() after lower * threshold */ + dev_dbg(&netdev->dev, + "%s busy - invoking iovm flow control\n", + __func__); devdata->flow_control_upper_hits++; } spin_unlock_irqrestore(&devdata->priv_lock, flags); @@ -1211,6 +1239,8 @@ visornic_xmit_timeout(struct net_device *netdev) /* Ensure that a ServerDown message hasn't been received */ if (!devdata->enabled || (devdata->server_down && !devdata->server_change_state)) { + dev_dbg(&netdev->dev, "%s no processing\n", + __func__); spin_unlock_irqrestore(&devdata->priv_lock, flags); return; } @@ -1808,8 +1838,11 @@ static int visornic_probe(struct visor_device *dev) u64 features; netdev = alloc_etherdev(sizeof(struct visornic_devdata)); - if (!netdev) + if (!netdev) { + dev_err(&dev->device, + "%s alloc_etherdev failed\n", __func__); return -ENOMEM; + } netdev->netdev_ops = &visornic_dev_ops; netdev->watchdog_timeo = (5 * HZ); @@ -1821,11 +1854,17 @@ static int visornic_probe(struct visor_device *dev) vnic.macaddr); err = visorbus_read_channel(dev, channel_offset, netdev->dev_addr, ETH_ALEN); - if (err < 0) + if (err < 0) { + dev_err(&dev->device, + "%s failed to get mac addr from chan (%d)\n", + __func__, err); goto cleanup_netdev; + } devdata = devdata_initialize(netdev_priv(netdev), dev); if (!devdata) { + dev_err(&dev->device, + "%s devdata_initialize failed\n", __func__); err = -ENOMEM; goto cleanup_netdev; } @@ -1842,8 +1881,12 @@ static int visornic_probe(struct visor_device *dev) vnic.num_rcv_bufs); err = visorbus_read_channel(dev, channel_offset, &devdata->num_rcv_bufs, 4); - if (err) + if (err) { + dev_err(&dev->device, + "%s failed to get #rcv bufs from chan (%d)\n", + __func__, err); goto cleanup_netdev; + } devdata->rcvbuf = kzalloc(sizeof(struct sk_buff *) * devdata->num_rcv_bufs, GFP_KERNEL); @@ -1884,38 +1927,58 @@ static int visornic_probe(struct visor_device *dev) channel_offset = offsetof(struct spar_io_channel_protocol, vnic.mtu); err = visorbus_read_channel(dev, channel_offset, &netdev->mtu, 4); - if (err) + if (err) { + dev_err(&dev->device, + "%s failed to get mtu from chan (%d)\n", + __func__, err); goto cleanup_xmit_cmdrsp; + } /* TODO: Setup Interrupt information */ /* Let's start our threads to get responses */ channel_offset = offsetof(struct spar_io_channel_protocol, channel_header.features); err = visorbus_read_channel(dev, channel_offset, &features, 8); - if (err) + if (err) { + dev_err(&dev->device, + "%s failed to get features from chan (%d)\n", + __func__, err); goto cleanup_xmit_cmdrsp; + } features |= ULTRA_IO_CHANNEL_IS_POLLING; err = visorbus_write_channel(dev, channel_offset, &features, 8); - if (err) + if (err) { + dev_err(&dev->device, + "%s failed to set features in chan (%d)\n", + __func__, err); goto cleanup_xmit_cmdrsp; + } devdata->thread_wait_ms = 2; visor_thread_start(&devdata->threadinfo, process_incoming_rsps, devdata, "vnic_incoming"); err = register_netdev(netdev); - if (err) + if (err) { + dev_err(&dev->device, + "%s register_netdev failed (%d)\n", __func__, err); goto cleanup_thread_stop; + } /* create debgug/sysfs directories */ devdata->eth_debugfs_dir = debugfs_create_dir(netdev->name, visornic_debugfs_dir); if (!devdata->eth_debugfs_dir) { + dev_err(&dev->device, + "%s debugfs_create_dir %s failed\n", + __func__, netdev->name); err = -ENOMEM; goto cleanup_thread_stop; } + dev_info(&dev->device, "%s success netdev=%s\n", + __func__, netdev->name); return 0; cleanup_thread_stop: @@ -1963,8 +2026,10 @@ static void visornic_remove(struct visor_device *dev) { struct visornic_devdata *devdata = dev_get_drvdata(&dev->device); - if (!devdata) + if (!devdata) { + dev_err(&dev->device, "%s no devdata\n", __func__); return; + } dev_set_drvdata(&dev->device, NULL); host_side_disappeared(devdata); kref_put(&devdata->kref, devdata_release); @@ -2010,8 +2075,10 @@ static int visornic_resume(struct visor_device *dev, unsigned long flags; devdata = dev_get_drvdata(&dev->device); - if (!devdata) + if (!devdata) { + dev_err(&dev->device, "%s no devdata\n", __func__); return -EINVAL; + } netdev = devdata->netdev; @@ -2039,6 +2106,8 @@ static int visornic_resume(struct visor_device *dev, */ send_enbdis(netdev, 1, devdata); } else if (devdata->server_change_state) { + dev_err(&dev->device, "%s server_change_state\n", + __func__); return -EIO; } -- cgit v1.3-6-gb490 From fa15d6d3466390faae884dca45c7c21255c30f3c Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:47 -0400 Subject: staging: unisys: visornic: correct obvious double-allocation of workqueues Looks like an errant patch fitting caused us to redundantly allocate the workqueues at both the beginning and end of visornic_init(). This was corrected by removing the allocations at the beginning. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Fixes: 68905a14e49c ('staging: unisys: Add s-Par visornic ethernet driver') Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index de05ac79662a..2ff7f2f30660 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -2127,18 +2127,6 @@ static int visornic_init(void) struct dentry *ret; int err = -ENOMEM; - /* create workqueue for serverdown completion */ - visornic_serverdown_workqueue = - create_singlethread_workqueue("visornic_serverdown"); - if (!visornic_serverdown_workqueue) - return -ENOMEM; - - /* create workqueue for tx timeout reset */ - visornic_timeout_reset_workqueue = - create_singlethread_workqueue("visornic_timeout_reset"); - if (!visornic_timeout_reset_workqueue) - return -ENOMEM; - visornic_debugfs_dir = debugfs_create_dir("visornic", NULL); if (!visornic_debugfs_dir) return err; -- cgit v1.3-6-gb490 From 46df82267eb26f4f6859e1564dbc9580f57dc542 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:48 -0400 Subject: staging: unisys: visornic: correctly clean up device on removal visornic_remove() is called to logically detach the visornic driver from a visorbus-supplied device, which can happen either just prior to a visorbus-supplied device disappearing, or as a result of an rmmod of visornic. Prior to this patch, logic was missing to properly clean up for this removal, which was fixed via the following changes: * A going_away flag is now used to interlock between device destruction and workqueue operations, protected by priv_lock. I.e., setting going_away=true under lock guarantees that no new work items can get queued to the work queues. going_away=true also short-circuits other operations to enable device destruction to proceed. * Missing clean-up operations for the workqueues, netdev, debugfs entries, and the worker thread were added. * Memory referenced from the visornic private devdata struct is now freed as part of devdata destruction. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 65 ++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 2ff7f2f30660..ba460539adb6 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -162,6 +162,7 @@ struct visornic_devdata { */ bool server_down; /* IOPART is down */ bool server_change_state; /* Processing SERVER_CHANGESTATE msg */ + bool going_away; /* device is being torn down */ struct dentry *eth_debugfs_dir; struct visor_thread_info threadinfo; u64 interrupts_rcvd; @@ -568,7 +569,17 @@ static int visornic_serverdown(struct visornic_devdata *devdata, visorbus_state_complete_func complete_func) { + unsigned long flags; + + spin_lock_irqsave(&devdata->priv_lock, flags); if (!devdata->server_down && !devdata->server_change_state) { + if (devdata->going_away) { + spin_unlock_irqrestore(&devdata->priv_lock, flags); + dev_dbg(&devdata->dev->device, + "%s aborting because device removal pending\n", + __func__); + return -ENODEV; + } devdata->server_change_state = true; devdata->server_down_complete_func = complete_func; queue_work(visornic_serverdown_workqueue, @@ -576,8 +587,10 @@ visornic_serverdown(struct visornic_devdata *devdata, } else if (devdata->server_change_state) { dev_dbg(&devdata->dev->device, "%s changing state\n", __func__); + spin_unlock_irqrestore(&devdata->priv_lock, flags); return -EINVAL; } + spin_unlock_irqrestore(&devdata->priv_lock, flags); return 0; } @@ -1236,6 +1249,14 @@ visornic_xmit_timeout(struct net_device *netdev) unsigned long flags; spin_lock_irqsave(&devdata->priv_lock, flags); + if (devdata->going_away) { + spin_unlock_irqrestore(&devdata->priv_lock, flags); + dev_dbg(&devdata->dev->device, + "%s aborting because device removal pending\n", + __func__); + return; + } + /* Ensure that a ServerDown message hasn't been received */ if (!devdata->enabled || (devdata->server_down && !devdata->server_change_state)) { @@ -1244,9 +1265,8 @@ visornic_xmit_timeout(struct net_device *netdev) spin_unlock_irqrestore(&devdata->priv_lock, flags); return; } - spin_unlock_irqrestore(&devdata->priv_lock, flags); - queue_work(visornic_timeout_reset_workqueue, &devdata->timeout_reset); + spin_unlock_irqrestore(&devdata->priv_lock, flags); } /** @@ -1614,6 +1634,9 @@ static void devdata_release(struct kref *mykref) spin_lock(&lock_all_devices); list_del(&devdata->list_all); spin_unlock(&lock_all_devices); + kfree(devdata->rcvbuf); + kfree(devdata->cmdrsp_rcv); + kfree(devdata->xmit_cmdrsp); kfree(devdata); } @@ -2025,13 +2048,51 @@ static void host_side_disappeared(struct visornic_devdata *devdata) static void visornic_remove(struct visor_device *dev) { struct visornic_devdata *devdata = dev_get_drvdata(&dev->device); + struct net_device *netdev; + unsigned long flags; if (!devdata) { dev_err(&dev->device, "%s no devdata\n", __func__); return; } + spin_lock_irqsave(&devdata->priv_lock, flags); + if (devdata->going_away) { + spin_unlock_irqrestore(&devdata->priv_lock, flags); + dev_err(&dev->device, "%s already being removed\n", __func__); + return; + } + devdata->going_away = true; + spin_unlock_irqrestore(&devdata->priv_lock, flags); + netdev = devdata->netdev; + if (!netdev) { + dev_err(&dev->device, "%s not net device\n", __func__); + return; + } + + /* going_away prevents new items being added to the workqueues */ + flush_workqueue(visornic_serverdown_workqueue); + flush_workqueue(visornic_timeout_reset_workqueue); + + debugfs_remove_recursive(devdata->eth_debugfs_dir); + + unregister_netdev(netdev); /* this will call visornic_close() */ + + /* this had to wait until last because visornic_close() / + * visornic_disable_with_timeout() polls waiting for state that is + * only updated by the thread + */ + if (devdata->threadinfo.id) { + visor_thread_stop(&devdata->threadinfo); + if (devdata->threadinfo.id) { + dev_err(&dev->device, "%s cannot stop worker thread\n", + __func__); + return; + } + } + dev_set_drvdata(&dev->device, NULL); host_side_disappeared(devdata); + free_netdev(netdev); kref_put(&devdata->kref, devdata_release); } -- cgit v1.3-6-gb490 From 3798ff31d1fb1ee33de619ffc81a6a56c3ccb973 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:49 -0400 Subject: staging: unisys: visornic: don't destroy global workqueues until devs destroyed visornic_cleanup() was previously incorrectly destroying its global workqueues prior to cleaning up the devices which used them. This patch corrects the order of these operations. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index ba460539adb6..14977ad356cf 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -2241,6 +2241,8 @@ cleanup_debugfs: */ static void visornic_cleanup(void) { + visorbus_unregister_visor_driver(&visornic_driver); + if (visornic_serverdown_workqueue) { flush_workqueue(visornic_serverdown_workqueue); destroy_workqueue(visornic_serverdown_workqueue); @@ -2251,7 +2253,6 @@ static void visornic_cleanup(void) } debugfs_remove_recursive(visornic_debugfs_dir); - visorbus_unregister_visor_driver(&visornic_driver); kfree(dev_num_pool); dev_num_pool = NULL; } -- cgit v1.3-6-gb490 From 1a2e3e3d0992ced8eeb4cfbf228f617ad08afbf1 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:50 -0400 Subject: staging: unisys: visornic: delay start of worker thread until netdev created This only makes sense, since the worker thread depends upon the netdev existing. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 14977ad356cf..07e89ad92a66 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1978,15 +1978,11 @@ static int visornic_probe(struct visor_device *dev) goto cleanup_xmit_cmdrsp; } - devdata->thread_wait_ms = 2; - visor_thread_start(&devdata->threadinfo, process_incoming_rsps, - devdata, "vnic_incoming"); - err = register_netdev(netdev); if (err) { dev_err(&dev->device, "%s register_netdev failed (%d)\n", __func__, err); - goto cleanup_thread_stop; + goto cleanup_xmit_cmdrsp; } /* create debgug/sysfs directories */ @@ -1997,16 +1993,17 @@ static int visornic_probe(struct visor_device *dev) "%s debugfs_create_dir %s failed\n", __func__, netdev->name); err = -ENOMEM; - goto cleanup_thread_stop; + goto cleanup_xmit_cmdrsp; } + devdata->thread_wait_ms = 2; + visor_thread_start(&devdata->threadinfo, process_incoming_rsps, + devdata, "vnic_incoming"); + dev_info(&dev->device, "%s success netdev=%s\n", __func__, netdev->name); return 0; -cleanup_thread_stop: - visor_thread_stop(&devdata->threadinfo); - cleanup_xmit_cmdrsp: kfree(devdata->xmit_cmdrsp); -- cgit v1.3-6-gb490 From 051e9fbbba1594331a9b3b2b157b5a0ce54b9a43 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:51 -0400 Subject: staging: unisys: visornic: use preferred interface for setting netdev's parent Just switch this line so it uses the correct function call. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 07e89ad92a66..9b3c5d876b86 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1869,7 +1869,7 @@ static int visornic_probe(struct visor_device *dev) netdev->netdev_ops = &visornic_dev_ops; netdev->watchdog_timeo = (5 * HZ); - netdev->dev.parent = &dev->device; + SET_NETDEV_DEV(netdev, &dev->device); /* Get MAC adddress from channel and read it into the device. */ netdev->addr_len = ETH_ALEN; -- cgit v1.3-6-gb490 From 8d0119d8e81f93cf3c1bc2b6e7a39e28620cda1a Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Thu, 9 Jul 2015 13:27:52 -0400 Subject: staging: unisys: visornic: prevent erroneous kfree of devdata pointer A struct visornic_devdata for each visornic device is actually allocated as part of alloc_etherdev(), here in visornic_probe(): netdev = alloc_etherdev(sizeof(struct visornic_devdata)); But code in devdata_release() was treating devdata as a pointer that needed to be kfree()d! This was causing all sorts of weird behavior after doing an rmmod of visornic, both because free_netdev() was actually freeing the memory used for devdata, and because devdata wasn't pointing to dynamically-allocated memory in the first place. The kfree(devdata) and the kref that tracked devdata's usage have been appropriately deleted. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 9b3c5d876b86..9350473a732b 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -119,7 +119,6 @@ struct visornic_devdata { struct visor_device *dev; char name[99]; struct list_head list_all; /* < link within list_all_devices list */ - struct kref kref; struct net_device *netdev; struct net_device_stats net_stats; atomic_t interrupt_rcvd; @@ -1602,14 +1601,11 @@ devdata_initialize(struct visornic_devdata *devdata, struct visor_device *dev) spin_unlock(&dev_num_pool_lock); if (devnum == MAXDEVICES) devnum = -1; - if (devnum < 0) { - kfree(devdata); + if (devnum < 0) return NULL; - } devdata->devnum = devnum; devdata->dev = dev; strncpy(devdata->name, dev_name(&dev->device), sizeof(devdata->name)); - kref_init(&devdata->kref); spin_lock(&lock_all_devices); list_add_tail(&devdata->list_all, &list_all_devices); spin_unlock(&lock_all_devices); @@ -1617,17 +1613,14 @@ devdata_initialize(struct visornic_devdata *devdata, struct visor_device *dev) } /** - * devdata_release - Frees up a devdata - * @mykref: kref to the devdata + * devdata_release - Frees up references in devdata + * @devdata: struct to clean up * - * Frees up a devdata. + * Frees up references in devdata. * Returns void */ -static void devdata_release(struct kref *mykref) +static void devdata_release(struct visornic_devdata *devdata) { - struct visornic_devdata *devdata = - container_of(mykref, struct visornic_devdata, kref); - spin_lock(&dev_num_pool_lock); clear_bit(devdata->devnum, dev_num_pool); spin_unlock(&dev_num_pool_lock); @@ -1637,7 +1630,6 @@ static void devdata_release(struct kref *mykref) kfree(devdata->rcvbuf); kfree(devdata->cmdrsp_rcv); kfree(devdata->xmit_cmdrsp); - kfree(devdata); } static const struct net_device_ops visornic_dev_ops = { @@ -2089,8 +2081,8 @@ static void visornic_remove(struct visor_device *dev) dev_set_drvdata(&dev->device, NULL); host_side_disappeared(devdata); + devdata_release(devdata); free_netdev(netdev); - kref_put(&devdata->kref, devdata_release); } /** -- cgit v1.3-6-gb490 From 1fc07f99134ba0b8d4099322ea0753137ea7ed3b Mon Sep 17 00:00:00 2001 From: David Kershner Date: Thu, 9 Jul 2015 13:27:53 -0400 Subject: staging: unisys: Allow visorbus to autoload We inadvertently remove the MODULE_DEVICE_TABLE line for visorbus, this patch adds it back in. Signed-off-by: David Kershner Signed-off-by: Benjamin Romer Fixes: d5b3f1dccee4 ('staging: unisys: move timskmod.h functionality') Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorbus/visorchipset.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorbus/visorchipset.c b/drivers/staging/unisys/visorbus/visorchipset.c index d47ec24e2dc5..4be931844052 100644 --- a/drivers/staging/unisys/visorbus/visorchipset.c +++ b/drivers/staging/unisys/visorbus/visorchipset.c @@ -2382,6 +2382,9 @@ static struct acpi_driver unisys_acpi_driver = { .remove = visorchipset_exit, }, }; + +MODULE_DEVICE_TABLE(acpi, unisys_device_ids); + static __init uint32_t visorutil_spar_detect(void) { unsigned int eax, ebx, ecx, edx; -- cgit v1.3-6-gb490 From 2164be191e3d627dd7744b7224daf9ad9495c9af Mon Sep 17 00:00:00 2001 From: Ken Cox Date: Thu, 9 Jul 2015 13:28:56 -0400 Subject: staging: unisys: Fix broken build when ARCH=um When building with ARCH=um you get the following error: arch/x86/include/asm/cpufeature.h:252:42: error: 'REQUIRED_MASK0' undeclared The Unisys drivers should not be compiled for UML, so this patch addresses that by adding a dependency to kconfig for !UML. Reported-by: kbuild test robot Tested-by: Ken Cox Signed-off-by: Ken Cox Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig index 778f9d05f98a..624abe66c20c 100644 --- a/drivers/staging/unisys/Kconfig +++ b/drivers/staging/unisys/Kconfig @@ -3,7 +3,7 @@ # menuconfig UNISYSSPAR bool "Unisys SPAR driver support" - depends on X86_64 + depends on X86_64 && !UML select PCI select ACPI ---help--- -- cgit v1.3-6-gb490 From fd012d0def470d6c2e1a441421d00404240e7fec Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Mon, 13 Jul 2015 14:51:23 -0400 Subject: staging: unisys: correctly NULL-terminate visorbus sysfs attribute array I'm not sure what adverse runtime effects the previously-omitted NULL-termination would cause, but the code was definitely wrong. Fixes: 795731627c ('staging: unisys: Clean up device sysfs attributes') Signed-off-by: Tim Sell Acked-by: Don Zickus Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorbus/visorbus_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorbus/visorbus_main.c b/drivers/staging/unisys/visorbus/visorbus_main.c index 6db47196c189..0f66f239dff0 100644 --- a/drivers/staging/unisys/visorbus/visorbus_main.c +++ b/drivers/staging/unisys/visorbus/visorbus_main.c @@ -471,6 +471,7 @@ static struct attribute *channel_attrs[] = { &dev_attr_typeguid.attr, &dev_attr_zoneguid.attr, &dev_attr_typename.attr, + NULL }; static struct attribute_group channel_attr_grp = { -- cgit v1.3-6-gb490 From d253058f490febdfdbe0a0f09a25166c71afd2b3 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Mon, 13 Jul 2015 14:51:24 -0400 Subject: staging: unisys: fix random memory corruption in visorchannel_write() visorchannel_write() and it's user visorbus_write_channel() are exported, so all visorbus function drivers (i.e., drivers that call visorbus_register_visor_driver()) are potentially affected by the bug. Because of pointer-arithmetic rules, the address being written to in the affected code was actually at byte offset: sizeof(struct channel_header) * offset instead of just bytes as intended. The bug could cause some very difficult-to-diagnose symptoms. The particular problem that led me on this chase was a kernel fault that would occur during 'insmod visornic' after a previous 'rmmod visornic', where we would fault during netdev_register_kobject() within pm_runtime_set_memalloc_noio() while traversing a device list, which occurred because dev->parent for the visorbus device had become corrupted. Fixes: 0abb60c1c ('staging: unisys: visorchannel_write(): Handle...') Signed-off-by: Tim Sell Acked-by: Don Zickus Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorbus/visorchannel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorbus/visorchannel.c b/drivers/staging/unisys/visorbus/visorchannel.c index 20b63496e9f2..af349c8a3693 100644 --- a/drivers/staging/unisys/visorbus/visorchannel.c +++ b/drivers/staging/unisys/visorbus/visorchannel.c @@ -259,7 +259,8 @@ visorchannel_write(struct visorchannel *channel, ulong offset, if (offset < chdr_size) { copy_size = min(chdr_size - offset, nbytes); - memcpy(&channel->chan_hdr + offset, local, copy_size); + memcpy(((char *)(&channel->chan_hdr)) + offset, + local, copy_size); } memcpy_toio(channel->mapped + offset, local, nbytes); -- cgit v1.3-6-gb490 From 0aa5ae1e2eed3f57ff1dfd7cd057aaff5d9c1d9f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 13 Jul 2015 20:51:32 +0200 Subject: staging: unisys: Use kzalloc instead of kmalloc/memset This patch turns a kmalloc/memset into an equivalent kzalloc. Signed-off-by: Christophe JAILLET Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorbus/visorbus_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorbus/visorbus_main.c b/drivers/staging/unisys/visorbus/visorbus_main.c index 0f66f239dff0..2c46745f156a 100644 --- a/drivers/staging/unisys/visorbus/visorbus_main.c +++ b/drivers/staging/unisys/visorbus/visorbus_main.c @@ -281,12 +281,11 @@ devmajorminor_create_file(struct visor_device *dev, const char *name, rc = -ENOMEM; goto away; } - myattr = kmalloc(sizeof(*myattr), GFP_KERNEL); + myattr = kzalloc(sizeof(*myattr), GFP_KERNEL); if (!myattr) { rc = -ENOMEM; goto away; } - memset(myattr, 0, sizeof(struct devmajorminor_attribute)); myattr->show = DEVMAJORMINOR_ATTR; myattr->store = NULL; myattr->slot = slot; -- cgit v1.3-6-gb490 From 216c3e2c135e69dc8cc93ca9bd2c03300910f44f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 13 Jul 2015 20:52:26 +0200 Subject: staging: unisys: Reduce indent Remove some extra tabs in order to improve readalibility. Signed-off-by: Christophe JAILLET Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorbus/visorbus_main.c | 49 ++++++++++++------------- 1 file changed, 24 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorbus/visorbus_main.c b/drivers/staging/unisys/visorbus/visorbus_main.c index 2c46745f156a..3e33e3629682 100644 --- a/drivers/staging/unisys/visorbus/visorbus_main.c +++ b/drivers/staging/unisys/visorbus/visorbus_main.c @@ -218,9 +218,9 @@ visorbus_release_device(struct device *xdev) struct devmajorminor_attribute { struct attribute attr; int slot; - ssize_t (*show)(struct visor_device *, int slot, char *buf); - ssize_t (*store)(struct visor_device *, int slot, const char *buf, - size_t count); + ssize_t (*show)(struct visor_device *, int slot, char *buf); + ssize_t (*store)(struct visor_device *, int slot, const char *buf, + size_t count); }; static ssize_t DEVMAJORMINOR_ATTR(struct visor_device *dev, int slot, char *buf) @@ -1043,10 +1043,10 @@ write_vbus_chp_info(struct visorchannel *chan, int off = sizeof(struct channel_header) + hdr_info->chp_info_offset; if (hdr_info->chp_info_offset == 0) - return -1; + return -1; if (visorchannel_write(chan, off, info, sizeof(*info)) < 0) - return -1; + return -1; return 0; } @@ -1061,10 +1061,10 @@ write_vbus_bus_info(struct visorchannel *chan, int off = sizeof(struct channel_header) + hdr_info->bus_info_offset; if (hdr_info->bus_info_offset == 0) - return -1; + return -1; if (visorchannel_write(chan, off, info, sizeof(*info)) < 0) - return -1; + return -1; return 0; } @@ -1081,10 +1081,10 @@ write_vbus_dev_info(struct visorchannel *chan, (hdr_info->device_info_struct_bytes * devix); if (hdr_info->dev_info_offset == 0) - return -1; + return -1; if (visorchannel_write(chan, off, info, sizeof(*info)) < 0) - return -1; + return -1; return 0; } @@ -1106,7 +1106,7 @@ fix_vbus_dev_info(struct visor_device *visordev) struct spar_vbus_headerinfo *hdr_info; if (!visordev->device.driver) - return; + return; hdr_info = (struct spar_vbus_headerinfo *)visordev->vbus_hdr_info; if (!hdr_info) @@ -1319,11 +1319,11 @@ static void pause_state_change_complete(struct visor_device *dev, int status) { if (!dev->pausing) - return; + return; dev->pausing = false; if (!chipset_responders.device_pause) /* this can never happen! */ - return; + return; /* Notify the chipset driver that the pause is complete, which * will presumably want to send some sort of response to the @@ -1339,11 +1339,11 @@ static void resume_state_change_complete(struct visor_device *dev, int status) { if (!dev->resuming) - return; + return; dev->resuming = false; if (!chipset_responders.device_resume) /* this can never happen! */ - return; + return; /* Notify the chipset driver that the resume is complete, * which will presumably want to send some sort of response to @@ -1367,14 +1367,14 @@ initiate_chipset_device_pause_resume(struct visor_device *dev, bool is_pause) else notify_func = chipset_responders.device_resume; if (!notify_func) - goto away; + goto away; drv = to_visor_driver(dev->device.driver); if (!drv) - goto away; + goto away; if (dev->pausing || dev->resuming) - goto away; + goto away; /* Note that even though both drv->pause() and drv->resume * specify a callback function, it is NOT necessary for us to @@ -1385,7 +1385,7 @@ initiate_chipset_device_pause_resume(struct visor_device *dev, bool is_pause) */ if (is_pause) { if (!drv->pause) - goto away; + goto away; dev->pausing = true; x = drv->pause(dev, pause_state_change_complete); @@ -1397,7 +1397,7 @@ initiate_chipset_device_pause_resume(struct visor_device *dev, bool is_pause) * would never even get here in that case. */ fix_vbus_dev_info(dev); if (!drv->resume) - goto away; + goto away; dev->resuming = true; x = drv->resume(dev, resume_state_change_complete); @@ -1413,7 +1413,7 @@ initiate_chipset_device_pause_resume(struct visor_device *dev, bool is_pause) away: if (rc < 0) { if (notify_func) - (*notify_func)(dev, rc); + (*notify_func)(dev, rc); } } @@ -1469,8 +1469,8 @@ visorbus_init(void) away: if (rc) - POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, rc, - POSTCODE_SEVERITY_ERR); + POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, rc, + POSTCODE_SEVERITY_ERR); return rc; } @@ -1495,9 +1495,8 @@ visorbus_exit(void) list_for_each_safe(listentry, listtmp, &list_all_bus_instances) { struct visor_device *dev = list_entry(listentry, - struct - visor_device, - list_all); + struct visor_device, + list_all); remove_bus_instance(dev); } remove_bus_type(); -- cgit v1.3-6-gb490 From a3ef1a8e93912396f3bd46d579c9241c399de530 Mon Sep 17 00:00:00 2001 From: David Kershner Date: Tue, 14 Jul 2015 14:43:29 -0400 Subject: staging: unisys: Lock visorchannels associated with devices A visorchannel associated with a device should have its writing to the channel protected by a lock. Fixes: b32c4997c ('staging: unisys: Move channel creation up the stack') Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorbus/visorchipset.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorbus/visorchipset.c b/drivers/staging/unisys/visorbus/visorchipset.c index 4be931844052..fb08f9523ab3 100644 --- a/drivers/staging/unisys/visorbus/visorchipset.c +++ b/drivers/staging/unisys/visorbus/visorchipset.c @@ -1247,10 +1247,11 @@ my_device_create(struct controlvm_message *inmsg) POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, dev_no, bus_no, POSTCODE_SEVERITY_INFO); - visorchannel = visorchannel_create(cmd->create_device.channel_addr, - cmd->create_device.channel_bytes, - GFP_KERNEL, - cmd->create_device.data_type_uuid); + visorchannel = + visorchannel_create_with_lock(cmd->create_device.channel_addr, + cmd->create_device.channel_bytes, + GFP_KERNEL, + cmd->create_device.data_type_uuid); if (!visorchannel) { POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no, -- cgit v1.3-6-gb490 From 24ac1074c1dad1bdc455f8f6df5c5316fae53eb7 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Tue, 14 Jul 2015 14:43:30 -0400 Subject: staging: unisys: fix random hangs with network stress in visornic We learned that it was possible for the core networking code to call visornic_xmit() within ISR context, resulting in the need for us to use spin_lock_irqsave() / spin_lock_irqrestore() to lock accesses to our virtual device channels. Without the correct locking added in this patch, random hangs would occur on typical kernels while stressing the netork. When using a kernel with CONFIG_DEBUG_SPINLOCK=y, a stackdump would occur at the time of the hang reporting: BUG: spinlock recursion on CPU#0, vnic_incoming/ (see below for more details) We considered the possibility of adding a protocol between a visordriver and visorbus where the visordriver could specify which type of locking it required for its virtual device channels (essentially indicating whether or not it was possible for the channel to be accessed in ISR context), but decided this extra complexity was NOT needed, and that channel queues should always be accessed with the most-stringent locking. So that is what is implemented in this commit. Below is an example stackdump illustrating the spinlock recursion that is fixed by this commit. Note that we are first in virtnic_rx() writing to the device channel when an APIC timer interrupt occurs. Within the core networking code, net_rx_action() calls process_backlog(), which eventually lands up back up in virtnic_xmit() in the code attempting to also write to the device channel. BUG: spinlock recursion on CPU#0, vnic_incoming/262 lock: 0xffff88002db810c0, .magic: dead4ead, .owner: vnic_incoming/262, .owner_cpu: 0 CPU: 0 PID: 262 Comm: vnic_incoming Tainted: G C 4.2.0-rc1-ARCH+ #56 Hardware name: Dell Inc. PowerEdge T110/ , BIOS 1.23 12/15/2009 ffff8800216ac200 ffff88002c803388 ffffffff81476364 0000000000000106 ffff88002db810c0 ffff88002c8033a8 ffffffff8109e2bc ffff88002db810c0 ffffffff817631d4 ffff88002c8033c8 ffffffff8109e330 ffff88002db810c0 Call Trace: [] dump_stack+0x4f/0x73 [] spin_dump+0x7c/0xc0 [] spin_bug+0x30/0x40 [] do_raw_spin_lock+0x127/0x140 [] _raw_spin_lock+0x40/0x50 [] ? visorchannel_signalinsert+0x46/0x70 [visorbus] [] visorchannel_signalinsert+0x46/0x70 [visorbus] [] visornic_xmit+0x302/0x5d0 [visornic] [] dev_hard_start_xmit+0x2e0/0x510 [] ? validate_xmit_skb+0x235/0x310 [] sch_direct_xmit+0xf7/0x1d0 [] __dev_queue_xmit+0x203/0x640 [] ? __dev_queue_xmit+0x50/0x640 [] ? ip_finish_output+0x1df/0x310 [] dev_queue_xmit_sk+0x13/0x20 [] ip_finish_output2+0x22c/0x470 [] ? ip_finish_output+0x1df/0x310 [] ? __lock_is_held+0x50/0x70 [] ip_finish_output+0x1df/0x310 [] ip_output+0xb1/0x100 [] ip_local_out_sk+0x3e/0x80 [] ip_queue_xmit+0x188/0x4a0 [] ? ip_local_out_sk+0x80/0x80 [] ? __alloc_skb+0x86/0x1e0 [] tcp_transmit_skb+0x4cb/0x9c0 [] ? __kmalloc_reserve+0x3c/0x90 [] ? __alloc_skb+0x9a/0x1e0 [] tcp_send_ack+0x10d/0x150 [] __tcp_ack_snd_check+0x5e/0x90 [] tcp_rcv_established+0x354/0x710 [] tcp_v4_do_rcv+0x162/0x3f0 [] tcp_v4_rcv+0xb22/0xb50 [] ? ip_local_deliver_finish+0x4c/0x2d0 [] ip_local_deliver_finish+0xe0/0x2d0 [] ? ip_local_deliver_finish+0x4c/0x2d0 [] ip_local_deliver+0xae/0xc0 [] ip_rcv_finish+0x14f/0x510 [] ? __netif_receive_skb_core+0x9d/0xb70 [] ip_rcv+0x2d3/0x3b0 [] ? cpuacct_css_alloc+0xb0/0xb0 [] __netif_receive_skb_core+0x663/0xb70 [] ? __netif_receive_skb_core+0x9d/0xb70 [] ? cpuacct_charge+0x99/0xb0 [] ? cpuacct_css_alloc+0xb0/0xb0 [] ? __lock_is_held+0x50/0x70 [] ? process_backlog+0xbc/0x150 [] ? process_backlog+0x11b/0x150 [] __netif_receive_skb+0x27/0x70 [] process_backlog+0x92/0x150 [] net_rx_action+0x13d/0x350 [] ? lapic_next_event+0x1d/0x30 [] __do_softirq+0x104/0x320 [] ? hrtimer_interrupt+0xc8/0x1a0 [] ? blocking_notifier_chain_cond_register+0x70/0x70 [] irq_exit+0x79/0xa0 [] smp_apic_timer_interrupt+0x4a/0x60 [] apic_timer_interrupt+0x68/0x70 [] ? __memcpy+0x12/0x20 [] ? visorchannel_write+0x4a/0x80 [visorbus] [] signalinsert_inner+0x88/0x130 [visorbus] [] visorchannel_signalinsert+0x55/0x70 [visorbus] [] visornic_rx+0x12e7/0x19d0 [visornic] [] process_incoming_rsps+0x289/0x690 [visornic] [] ? preempt_schedule+0x25/0x30 [] ? ___preempt_schedule+0x12/0x14 [] ? wait_woken+0x90/0x90 [] ? visornic_rx+0x19d0/0x19d0 [visornic] [] ? visornic_rx+0x19d0/0x19d0 [visornic] [] kthread+0xe9/0x110 [] ? __init_kthread_worker+0x70/0x70 [] ret_from_fork+0x3f/0x70 [] ? __init_kthread_worker+0x70/0x70 Fixes: b12fdf7da ('staging: unisys: rework signal remove/insert to avoid sparse lock warnings') Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorbus/visorchannel.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorbus/visorchannel.c b/drivers/staging/unisys/visorbus/visorchannel.c index af349c8a3693..c6452c3908e6 100644 --- a/drivers/staging/unisys/visorbus/visorchannel.c +++ b/drivers/staging/unisys/visorbus/visorchannel.c @@ -417,11 +417,12 @@ bool visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg) { bool rc; + unsigned long flags; if (channel->needs_lock) { - spin_lock(&channel->remove_lock); + spin_lock_irqsave(&channel->remove_lock, flags); rc = signalremove_inner(channel, queue, msg); - spin_unlock(&channel->remove_lock); + spin_unlock_irqrestore(&channel->remove_lock, flags); } else { rc = signalremove_inner(channel, queue, msg); } @@ -471,11 +472,12 @@ bool visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg) { bool rc; + unsigned long flags; if (channel->needs_lock) { - spin_lock(&channel->insert_lock); + spin_lock_irqsave(&channel->insert_lock, flags); rc = signalinsert_inner(channel, queue, msg); - spin_unlock(&channel->insert_lock); + spin_unlock_irqrestore(&channel->insert_lock, flags); } else { rc = signalinsert_inner(channel, queue, msg); } -- cgit v1.3-6-gb490 From d482893b1caa5345b066c9721bab6636059e2a61 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 27 May 2015 00:25:57 +0800 Subject: rtc: snvs: use syscon to access register snvs included rtc, on/off key, power-off module change to syscon to access register Signed-off-by: Frank Li Acked-by: Alexandre Belloni Signed-off-by: Shawn Guo --- drivers/rtc/rtc-snvs.c | 132 +++++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index d87a85cefb66..950c5d0b6dca 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -18,6 +18,10 @@ #include #include #include +#include +#include + +#define SNVS_LPREGISTER_OFFSET 0x34 /* These register offsets are relative to LP (Low Power) range */ #define SNVS_LPCR 0x04 @@ -37,31 +41,36 @@ struct snvs_rtc_data { struct rtc_device *rtc; - void __iomem *ioaddr; + struct regmap *regmap; + int offset; int irq; - spinlock_t lock; struct clk *clk; }; -static u32 rtc_read_lp_counter(void __iomem *ioaddr) +static u32 rtc_read_lp_counter(struct snvs_rtc_data *data) { u64 read1, read2; + u32 val; do { - read1 = readl(ioaddr + SNVS_LPSRTCMR); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val); + read1 = val; read1 <<= 32; - read1 |= readl(ioaddr + SNVS_LPSRTCLR); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val); + read1 |= val; - read2 = readl(ioaddr + SNVS_LPSRTCMR); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCMR, &val); + read2 = val; read2 <<= 32; - read2 |= readl(ioaddr + SNVS_LPSRTCLR); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val); + read2 |= val; } while (read1 != read2); /* Convert 47-bit counter to 32-bit raw second count */ return (u32) (read1 >> CNTR_TO_SECS_SH); } -static void rtc_write_sync_lp(void __iomem *ioaddr) +static void rtc_write_sync_lp(struct snvs_rtc_data *data) { u32 count1, count2, count3; int i; @@ -69,15 +78,15 @@ static void rtc_write_sync_lp(void __iomem *ioaddr) /* Wait for 3 CKIL cycles */ for (i = 0; i < 3; i++) { do { - count1 = readl(ioaddr + SNVS_LPSRTCLR); - count2 = readl(ioaddr + SNVS_LPSRTCLR); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count1); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2); } while (count1 != count2); /* Now wait until counter value changes */ do { do { - count2 = readl(ioaddr + SNVS_LPSRTCLR); - count3 = readl(ioaddr + SNVS_LPSRTCLR); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count2); + regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &count3); } while (count2 != count3); } while (count3 == count1); } @@ -85,23 +94,14 @@ static void rtc_write_sync_lp(void __iomem *ioaddr) static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable) { - unsigned long flags; int timeout = 1000; u32 lpcr; - spin_lock_irqsave(&data->lock, flags); - - lpcr = readl(data->ioaddr + SNVS_LPCR); - if (enable) - lpcr |= SNVS_LPCR_SRTC_ENV; - else - lpcr &= ~SNVS_LPCR_SRTC_ENV; - writel(lpcr, data->ioaddr + SNVS_LPCR); - - spin_unlock_irqrestore(&data->lock, flags); + regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_SRTC_ENV, + enable ? SNVS_LPCR_SRTC_ENV : 0); while (--timeout) { - lpcr = readl(data->ioaddr + SNVS_LPCR); + regmap_read(data->regmap, data->offset + SNVS_LPCR, &lpcr); if (enable) { if (lpcr & SNVS_LPCR_SRTC_ENV) @@ -121,7 +121,7 @@ static int snvs_rtc_enable(struct snvs_rtc_data *data, bool enable) static int snvs_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct snvs_rtc_data *data = dev_get_drvdata(dev); - unsigned long time = rtc_read_lp_counter(data->ioaddr); + unsigned long time = rtc_read_lp_counter(data); rtc_time_to_tm(time, tm); @@ -139,8 +139,8 @@ static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm) snvs_rtc_enable(data, false); /* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */ - writel(time << CNTR_TO_SECS_SH, data->ioaddr + SNVS_LPSRTCLR); - writel(time >> (32 - CNTR_TO_SECS_SH), data->ioaddr + SNVS_LPSRTCMR); + regmap_write(data->regmap, data->offset + SNVS_LPSRTCLR, time << CNTR_TO_SECS_SH); + regmap_write(data->regmap, data->offset + SNVS_LPSRTCMR, time >> (32 - CNTR_TO_SECS_SH)); /* Enable RTC again */ snvs_rtc_enable(data, true); @@ -153,10 +153,10 @@ static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct snvs_rtc_data *data = dev_get_drvdata(dev); u32 lptar, lpsr; - lptar = readl(data->ioaddr + SNVS_LPTAR); + regmap_read(data->regmap, data->offset + SNVS_LPTAR, &lptar); rtc_time_to_tm(lptar, &alrm->time); - lpsr = readl(data->ioaddr + SNVS_LPSR); + regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr); alrm->pending = (lpsr & SNVS_LPSR_LPTA) ? 1 : 0; return 0; @@ -165,21 +165,12 @@ static int snvs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int snvs_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) { struct snvs_rtc_data *data = dev_get_drvdata(dev); - u32 lpcr; - unsigned long flags; - - spin_lock_irqsave(&data->lock, flags); - lpcr = readl(data->ioaddr + SNVS_LPCR); - if (enable) - lpcr |= (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN); - else - lpcr &= ~(SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN); - writel(lpcr, data->ioaddr + SNVS_LPCR); + regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, + (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN), + enable ? (SNVS_LPCR_LPTA_EN | SNVS_LPCR_LPWUI_EN) : 0); - spin_unlock_irqrestore(&data->lock, flags); - - rtc_write_sync_lp(data->ioaddr); + rtc_write_sync_lp(data); return 0; } @@ -189,24 +180,14 @@ static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) struct snvs_rtc_data *data = dev_get_drvdata(dev); struct rtc_time *alrm_tm = &alrm->time; unsigned long time; - unsigned long flags; - u32 lpcr; rtc_tm_to_time(alrm_tm, &time); - spin_lock_irqsave(&data->lock, flags); - - /* Have to clear LPTA_EN before programming new alarm time in LPTAR */ - lpcr = readl(data->ioaddr + SNVS_LPCR); - lpcr &= ~SNVS_LPCR_LPTA_EN; - writel(lpcr, data->ioaddr + SNVS_LPCR); - - spin_unlock_irqrestore(&data->lock, flags); - - writel(time, data->ioaddr + SNVS_LPTAR); + regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0); + regmap_write(data->regmap, data->offset + SNVS_LPTAR, time); /* Clear alarm interrupt status bit */ - writel(SNVS_LPSR_LPTA, data->ioaddr + SNVS_LPSR); + regmap_write(data->regmap, data->offset + SNVS_LPSR, SNVS_LPSR_LPTA); return snvs_rtc_alarm_irq_enable(dev, alrm->enabled); } @@ -226,7 +207,7 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id) u32 lpsr; u32 events = 0; - lpsr = readl(data->ioaddr + SNVS_LPSR); + regmap_read(data->regmap, data->offset + SNVS_LPSR, &lpsr); if (lpsr & SNVS_LPSR_LPTA) { events |= (RTC_AF | RTC_IRQF); @@ -238,25 +219,48 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id) } /* clear interrupt status */ - writel(lpsr, data->ioaddr + SNVS_LPSR); + regmap_write(data->regmap, data->offset + SNVS_LPSR, lpsr); return events ? IRQ_HANDLED : IRQ_NONE; } +static const struct regmap_config snvs_rtc_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + static int snvs_rtc_probe(struct platform_device *pdev) { struct snvs_rtc_data *data; struct resource *res; int ret; + void __iomem *mmio; data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->ioaddr = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(data->ioaddr)) - return PTR_ERR(data->ioaddr); + data->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap"); + + if (IS_ERR(data->regmap)) { + dev_warn(&pdev->dev, "snvs rtc: you use old dts file, please update it\n"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + mmio = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mmio)) + return PTR_ERR(mmio); + + data->regmap = devm_regmap_init_mmio(&pdev->dev, mmio, &snvs_rtc_config); + } else { + data->offset = SNVS_LPREGISTER_OFFSET; + of_property_read_u32(pdev->dev.of_node, "offset", &data->offset); + } + + if (!data->regmap) { + dev_err(&pdev->dev, "Can't find snvs syscon\n"); + return -ENODEV; + } data->irq = platform_get_irq(pdev, 0); if (data->irq < 0) @@ -276,13 +280,11 @@ static int snvs_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); - spin_lock_init(&data->lock); - /* Initialize glitch detect */ - writel(SNVS_LPPGDR_INIT, data->ioaddr + SNVS_LPPGDR); + regmap_write(data->regmap, data->offset + SNVS_LPPGDR, SNVS_LPPGDR_INIT); /* Clear interrupt status */ - writel(0xffffffff, data->ioaddr + SNVS_LPSR); + regmap_write(data->regmap, data->offset + SNVS_LPSR, 0xffffffff); /* Enable RTC */ snvs_rtc_enable(data, true); -- cgit v1.3-6-gb490 From f0a2db08e31071946c421a0ba0bb99e8273d2808 Mon Sep 17 00:00:00 2001 From: Fabio Falzoi Date: Tue, 30 Jun 2015 08:43:08 +0200 Subject: Staging: fbtft: Remove paragraph about writing to FSF Remove paragraph about writing to the Free Software Foundation's mailing address from GPL notice. This patch fixes the following checkpatch error: CHECK:FSF_MAILING_ADDRESS at line 17. Signed-off-by: Fabio Falzoi Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/flexfb.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c index 2c4ce07f5106..80b66204f705 100644 --- a/drivers/staging/fbtft/flexfb.c +++ b/drivers/staging/fbtft/flexfb.c @@ -12,10 +12,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. */ #include -- cgit v1.3-6-gb490 From df127f13c2342eef93298874713947adce8168ad Mon Sep 17 00:00:00 2001 From: Fabio Falzoi Date: Tue, 30 Jun 2015 08:43:09 +0200 Subject: Staging: fbtft: Remove unnecessary multiple blank lines This patch removes some unnecessary multiple blank lines to fix the following checkpatch errors: CHECK:LINE_SPACING at lines 29, 67, 131, 287, 299, 312, 326, 351 and 364. Signed-off-by: Fabio Falzoi Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/flexfb.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c index 80b66204f705..ed867e7055d6 100644 --- a/drivers/staging/fbtft/flexfb.c +++ b/drivers/staging/fbtft/flexfb.c @@ -26,7 +26,6 @@ #define DRVNAME "flexfb" - static char *chip; module_param(chip, charp, 0); MODULE_PARM_DESC(chip, "LCD controller"); @@ -64,7 +63,6 @@ static bool latched; module_param(latched, bool, 0); MODULE_PARM_DESC(latched, "Use with latched 16-bit databus"); - static int *initp; static int initp_num; @@ -128,7 +126,6 @@ static int ssd1351_init[] = { -1, 0xfd, 0x12, -1, 0xfd, 0xb1, -1, 0xae, -1, 0xb3 -1, 0xab, 0x01, -1, 0xb1, 0x32, -1, 0xb4, 0xa0, 0xb5, 0x55, -1, 0xbb, 0x17, -1, 0xbe, 0x05, -1, 0xc1, 0xc8, 0x80, 0xc8, -1, 0xc7, 0x0f, -1, 0xb6, 0x01, -1, 0xa6, -1, 0xaf, -3 }; - /* ili9320, ili9325 */ static void flexfb_set_addr_win_1(struct fbtft_par *par, int xs, int ys, int xe, int ye) @@ -284,7 +281,6 @@ static int flexfb_probe_common(struct spi_device *sdev, initp_num = ARRAY_SIZE(st7735r_init); } - } else if (!strcmp(chip, "hx8340bn")) { if (!width) width = 176; @@ -296,7 +292,6 @@ static int flexfb_probe_common(struct spi_device *sdev, initp_num = ARRAY_SIZE(hx8340bn_init); } - } else if (!strcmp(chip, "ili9225")) { if (!width) width = 176; @@ -309,8 +304,6 @@ static int flexfb_probe_common(struct spi_device *sdev, initp_num = ARRAY_SIZE(ili9225_init); } - - } else if (!strcmp(chip, "ili9320")) { if (!width) width = 240; @@ -323,7 +316,6 @@ static int flexfb_probe_common(struct spi_device *sdev, initp_num = ARRAY_SIZE(ili9320_init); } - } else if (!strcmp(chip, "ili9325")) { if (!width) width = 240; @@ -348,7 +340,6 @@ static int flexfb_probe_common(struct spi_device *sdev, initp_num = ARRAY_SIZE(ili9341_init); } - } else if (!strcmp(chip, "ssd1289")) { if (!width) width = 240; @@ -361,8 +352,6 @@ static int flexfb_probe_common(struct spi_device *sdev, initp_num = ARRAY_SIZE(ssd1289_init); } - - } else if (!strcmp(chip, "ssd1351")) { if (!width) width = 128; -- cgit v1.3-6-gb490 From 4906c43a342f864ca93f85aecab0d2f5d6689668 Mon Sep 17 00:00:00 2001 From: Fabio Falzoi Date: Tue, 30 Jun 2015 08:43:16 +0200 Subject: Staging: fbtft: Fix parenthesis alignment coding style issue This patch fixes the following checkpatch.pl error: CHECK:PARENTHESIS_ALIGNMENT at line 217. Signed-off-by: Fabio Falzoi Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/flexfb.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c index ed867e7055d6..13d173e1822a 100644 --- a/drivers/staging/fbtft/flexfb.c +++ b/drivers/staging/fbtft/flexfb.c @@ -130,9 +130,8 @@ static int ssd1351_init[] = { -1, 0xfd, 0x12, -1, 0xfd, 0xb1, -1, 0xae, -1, 0xb3 static void flexfb_set_addr_win_1(struct fbtft_par *par, int xs, int ys, int xe, int ye) { - fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, - "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", - __func__, xs, ys, xe, ye); + fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", + __func__, xs, ys, xe, ye); switch (par->info->var.rotate) { /* R20h = Horizontal GRAM Start Address */ /* R21h = Vertical GRAM Start Address */ @@ -512,8 +511,8 @@ static int flexfb_remove_common(struct device *dev, struct fb_info *info) return -EINVAL; par = info->par; if (par) - fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par, - "%s()\n", __func__); + fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par, "%s()\n", + __func__); fbtft_unregister_framebuffer(info); fbtft_framebuffer_release(info); -- cgit v1.3-6-gb490 From a1bf5205b2f013134ac55b02b3384502f21daa5e Mon Sep 17 00:00:00 2001 From: Fabio Falzoi Date: Tue, 30 Jun 2015 08:43:17 +0200 Subject: Staging: fbtft: Fix spacing coding style issue This patch fixes the following checkpatch.pl error: CHECK:SPACING at line 318. Signed-off-by: Fabio Falzoi Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/flexfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c index 13d173e1822a..ce6e3ae30a2e 100644 --- a/drivers/staging/fbtft/flexfb.c +++ b/drivers/staging/fbtft/flexfb.c @@ -234,7 +234,7 @@ static int flexfb_verify_gpios_db(struct fbtft_par *par) return -EINVAL; } if (latched) - num_db = buswidth/2; + num_db = buswidth / 2; for (i = 0; i < num_db; i++) { if (par->gpio.db[i] < 0) { dev_err(par->info->device, -- cgit v1.3-6-gb490 From dc4b2068934d6562048393d4531b9983df41b14e Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Sat, 11 Jul 2015 18:57:04 +0200 Subject: staging: fbtft: Add reset to fbtft_init_display_dt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an init sequence is present in the Device Tree, fbtft_init_display_dt() is used to initialize the display. Add missing reset function call and activation of chip select for parallel bus. Signed-off-by: Noralf Trønnes Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/fbtft-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 9cc81412be69..f04128fb0693 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -1076,6 +1076,11 @@ static int fbtft_init_display_dt(struct fbtft_par *par) p = of_prop_next_u32(prop, NULL, &val); if (!p) return -EINVAL; + + par->fbtftops.reset(par); + if (par->gpio.cs != -1) + gpio_set_value(par->gpio.cs, 0); /* Activate chip */ + while (p) { if (val & FBTFT_OF_INIT_CMD) { val &= 0xFFFF; -- cgit v1.3-6-gb490 From d3dc6e2322155087c19a1d6a71818be534de0602 Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Wed, 27 May 2015 00:26:00 +0800 Subject: input: keyboard: imx: add snvs power key driver add snvs power key driver. It work in imx chips after i.mx6sx ON/OFF key used power on/off whole system. This driver make it wakeup from suspend state when short press ON/OFF key. Long time press will trig SNVS power off chip without software intervention. Signed-off-by: Robin Gong Signed-off-by: Frank Li Acked-by: Dmitry Torokhov Signed-off-by: Shawn Guo --- drivers/input/keyboard/Kconfig | 11 ++ drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/snvs_pwrkey.c | 227 +++++++++++++++++++++++++++++++++++ 3 files changed, 239 insertions(+) create mode 100644 drivers/input/keyboard/snvs_pwrkey.c (limited to 'drivers') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 4cd94fd6cbad..82a8fb50afac 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -401,6 +401,17 @@ config KEYBOARD_MPR121 To compile this driver as a module, choose M here: the module will be called mpr121_touchkey. +config KEYBOARD_SNVS_PWRKEY + tristate "IMX SNVS Power Key Driver" + depends on SOC_IMX6SX + depends on OF + help + This is the snvs powerkey driver for the Freescale i.MX application + processors that are newer than i.MX6 SX. + + To compile this driver as a module, choose M here; the + module will be called snvs_pwrkey. + config KEYBOARD_IMX tristate "IMX keypad support" depends on ARCH_MXC diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index df28d5553c05..1d416ddf84e4 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o +obj-$(CONFIG_KEYBOARD_SNVS_PWRKEY) += snvs_pwrkey.o obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c new file mode 100644 index 000000000000..512a1fc2a864 --- /dev/null +++ b/drivers/input/keyboard/snvs_pwrkey.c @@ -0,0 +1,227 @@ +/* + * Driver for the IMX SNVS ON/OFF Power Key + * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SNVS_LPSR_REG 0x4C /* LP Status Register */ +#define SNVS_LPCR_REG 0x38 /* LP Control Register */ +#define SNVS_HPSR_REG 0x14 +#define SNVS_HPSR_BTN BIT(6) +#define SNVS_LPSR_SPO BIT(18) +#define SNVS_LPCR_DEP_EN BIT(5) + +#define DEBOUNCE_TIME 30 +#define REPEAT_INTERVAL 60 + +struct pwrkey_drv_data { + struct regmap *snvs; + int irq; + int keycode; + int keystate; /* 1:pressed */ + int wakeup; + struct timer_list check_timer; + struct input_dev *input; +}; + +static void imx_imx_snvs_check_for_events(unsigned long data) +{ + struct pwrkey_drv_data *pdata = (struct pwrkey_drv_data *) data; + struct input_dev *input = pdata->input; + u32 state; + + regmap_read(pdata->snvs, SNVS_HPSR_REG, &state); + state = state & SNVS_HPSR_BTN ? 1 : 0; + + /* only report new event if status changed */ + if (state ^ pdata->keystate) { + pdata->keystate = state; + input_event(input, EV_KEY, pdata->keycode, state); + input_sync(input); + pm_relax(pdata->input->dev.parent); + } + + /* repeat check if pressed long */ + if (state) { + mod_timer(&pdata->check_timer, + jiffies + msecs_to_jiffies(REPEAT_INTERVAL)); + } +} + +static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); + u32 lp_status; + + pm_wakeup_event(pdata->input->dev.parent, 0); + + regmap_read(pdata->snvs, SNVS_LPSR_REG, &lp_status); + if (lp_status & SNVS_LPSR_SPO) + mod_timer(&pdata->check_timer, jiffies + msecs_to_jiffies(DEBOUNCE_TIME)); + + /* clear SPO status */ + regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO); + + return IRQ_HANDLED; +} + +static void imx_snvs_pwrkey_act(void *pdata) +{ + struct pwrkey_drv_data *pd = pdata; + + del_timer_sync(&pd->check_timer); +} + +static int imx_snvs_pwrkey_probe(struct platform_device *pdev) +{ + struct pwrkey_drv_data *pdata = NULL; + struct input_dev *input = NULL; + struct device_node *np; + int error; + + /* Get SNVS register Page */ + np = pdev->dev.of_node; + if (!np) + return -ENODEV; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");; + + if (!pdata->snvs) { + dev_err(&pdev->dev, "Can't get snvs syscon\n"); + return -ENODEV; + } + + if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) { + pdata->keycode = KEY_POWER; + dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n"); + } + + pdata->wakeup = of_property_read_bool(np, "wakeup"); + + pdata->irq = platform_get_irq(pdev, 0); + if (pdata->irq < 0) { + dev_err(&pdev->dev, "no irq defined in platform data\n"); + return -EINVAL; + } + + regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_DEP_EN, SNVS_LPCR_DEP_EN); + + /* clear the unexpected interrupt before driver ready */ + regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO); + + setup_timer(&pdata->check_timer, + imx_imx_snvs_check_for_events, (unsigned long) pdata); + + input = devm_input_allocate_device(&pdev->dev); + if (!input) { + dev_err(&pdev->dev, "failed to allocate the input device\n"); + return -ENOMEM; + } + + input->name = pdev->name; + input->phys = "snvs-pwrkey/input0"; + input->id.bustype = BUS_HOST; + + input_set_capability(input, EV_KEY, pdata->keycode); + + /* input customer action to cancel release timer */ + error = devm_add_action(&pdev->dev, imx_snvs_pwrkey_act, pdata); + if (error) { + dev_err(&pdev->dev, "failed to register remove action\n"); + return error; + } + + error = devm_request_irq(&pdev->dev, pdata->irq, + imx_snvs_pwrkey_interrupt, + 0, pdev->name, pdev); + + if (error) { + dev_err(&pdev->dev, "interrupt not available.\n"); + return error; + } + + error = input_register_device(input); + if (error < 0) { + dev_err(&pdev->dev, "failed to register input device\n"); + input_free_device(input); + return error; + } + + pdata->input = input; + platform_set_drvdata(pdev, pdata); + + device_init_wakeup(&pdev->dev, pdata->wakeup); + + return 0; +} + +static int imx_snvs_pwrkey_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(pdata->irq); + + return 0; +} + +static int imx_snvs_pwrkey_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(pdata->irq); + + return 0; +} + +static const struct of_device_id imx_snvs_pwrkey_ids[] = { + { .compatible = "fsl,sec-v4.0-pwrkey" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_snvs_pwrkey_ids); + +static SIMPLE_DEV_PM_OPS(imx_snvs_pwrkey_pm_ops, imx_snvs_pwrkey_suspend, + imx_snvs_pwrkey_resume); + +static struct platform_driver imx_snvs_pwrkey_driver = { + .driver = { + .name = "snvs_pwrkey", + .pm = &imx_snvs_pwrkey_pm_ops, + .of_match_table = imx_snvs_pwrkey_ids, + }, + .probe = imx_snvs_pwrkey_probe, +}; +module_platform_driver(imx_snvs_pwrkey_driver); + +MODULE_AUTHOR("Freescale Semiconductor"); +MODULE_DESCRIPTION("i.MX snvs power key Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From a1560f9bec8b9275a751bd39a1db791d2c73d6e5 Mon Sep 17 00:00:00 2001 From: Henri Chain Date: Tue, 14 Jul 2015 14:59:39 +0200 Subject: Staging: fbtft: Add support for the Ultrachip UC1611 LCD controller This is a driver chip for 240x160 4-bit greyscale LCDs. It is capable of 4-wire (8 bit) or 3-wire (9 bit) SPI that have both been tested. (It also has a 6800 or 8080-style parallel interface, but I have not included support for it.) Signed-off-by: Henri Chain Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/Kconfig | 6 + drivers/staging/fbtft/Makefile | 1 + drivers/staging/fbtft/fb_uc1611.c | 350 +++++++++++++++++++++++++++++++++++ drivers/staging/fbtft/fbtft_device.c | 31 ++++ 4 files changed, 388 insertions(+) create mode 100644 drivers/staging/fbtft/fb_uc1611.c (limited to 'drivers') diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig index d4018780ce58..f7e68fdd9904 100644 --- a/drivers/staging/fbtft/Kconfig +++ b/drivers/staging/fbtft/Kconfig @@ -152,6 +152,12 @@ config FB_TFT_TLS8204 help Generic Framebuffer support for TLS8204 +config FB_TFT_UC1611 + tristate "FB driver for the UC1611 LCD controller" + depends on FB_TFT + help + Generic Framebuffer support for UC1611 + config FB_TFT_UC1701 tristate "FB driver for the UC1701 LCD Controller" depends on FB_TFT diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile index 554b5260b0ee..b26efdc87775 100644 --- a/drivers/staging/fbtft/Makefile +++ b/drivers/staging/fbtft/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_FB_TFT_SSD1351) += fb_ssd1351.o obj-$(CONFIG_FB_TFT_ST7735R) += fb_st7735r.o obj-$(CONFIG_FB_TFT_TINYLCD) += fb_tinylcd.o obj-$(CONFIG_FB_TFT_TLS8204) += fb_tls8204.o +obj-$(CONFIG_FB_TFT_UC1611) += fb_uc1611.o obj-$(CONFIG_FB_TFT_UC1701) += fb_uc1701.o obj-$(CONFIG_FB_TFT_UPD161704) += fb_upd161704.o obj-$(CONFIG_FB_TFT_WATTEROTT) += fb_watterott.o diff --git a/drivers/staging/fbtft/fb_uc1611.c b/drivers/staging/fbtft/fb_uc1611.c new file mode 100644 index 000000000000..32f3a9d921d6 --- /dev/null +++ b/drivers/staging/fbtft/fb_uc1611.c @@ -0,0 +1,350 @@ +/* + * FB driver for the UltraChip UC1611 LCD controller + * + * The display is 4-bit grayscale (16 shades) 240x160. + * + * Copyright (C) 2015 Henri Chain + * + * 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 +#include +#include + +#include "fbtft.h" + +#define DRVNAME "fb_uc1611" +#define WIDTH 240 +#define HEIGHT 160 +#define BPP 8 +#define FPS 40 + +/* + * LCD voltage is a combination of ratio, gain, pot and temp + * + * V_LCD = V_BIAS * ratio + * V_LCD = (C_V0 + C_PM × pot) * (1 + (T - 25) * temp) + * C_V0 and C_PM depend on ratio and gain + * T is ambient temperature + */ + +/* BR -> actual ratio: 0-3 -> 5, 10, 11, 13 */ +static unsigned ratio = 2; +module_param(ratio, uint, 0); +MODULE_PARM_DESC(ratio, "BR[1:0] Bias voltage ratio: 0-3 (default: 2)"); + +static unsigned gain = 3; +module_param(gain, uint, 0); +MODULE_PARM_DESC(gain, "GN[1:0] Bias voltage gain: 0-3 (default: 3)"); + +static unsigned pot = 16; +module_param(pot, uint, 0); +MODULE_PARM_DESC(pot, "PM[6:0] Bias voltage pot.: 0-63 (default: 16)"); + +/* TC -> % compensation per deg C: 0-3 -> -.05, -.10, -.015, -.20 */ +static unsigned temp; +module_param(temp, uint, 0); +MODULE_PARM_DESC(temp, "TC[1:0] Temperature compensation: 0-3 (default: 0)"); + +/* PC[1:0] -> LCD capacitance: 0-3 -> <20nF, 20-28 nF, 29-40 nF, 40-56 nF */ +static unsigned load = 1; +module_param(load, uint, 0); +MODULE_PARM_DESC(load, "PC[1:0] Panel Loading: 0-3 (default: 1)"); + +/* PC[3:2] -> V_LCD: 0, 1, 3 -> ext., int. with ratio = 5, int. standard */ +static unsigned pump = 3; +module_param(pump, uint, 0); +MODULE_PARM_DESC(pump, "PC[3:2] Pump control: 0,1,3 (default: 3)"); + +static int init_display(struct fbtft_par *par) +{ + int ret; + + fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); + + /* Set CS active high */ + par->spi->mode |= SPI_CS_HIGH; + ret = par->spi->master->setup(par->spi); + if (ret) { + dev_err(par->info->device, "Could not set SPI_CS_HIGH\n"); + return ret; + } + + /* Reset controller */ + write_reg(par, 0xE2); + + /* Set bias ratio */ + write_reg(par, 0xE8 | (ratio & 0x03)); + + /* Set bias gain and potentiometer */ + write_reg(par, 0x81); + write_reg(par, (gain & 0x03) << 6 | (pot & 0x3F)); + + /* Set temperature compensation */ + write_reg(par, 0x24 | (temp & 0x03)); + + /* Set panel loading */ + write_reg(par, 0x28 | (load & 0x03)); + + /* Set pump control */ + write_reg(par, 0x2C | (pump & 0x03)); + + /* Set inverse display */ + write_reg(par, 0xA6 | (0x01 & 0x01)); + + /* Set 4-bit grayscale mode */ + write_reg(par, 0xD0 | (0x02 & 0x03)); + + /* Set Display enable */ + write_reg(par, 0xA8 | 0x07); + + return 0; +} + +static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) +{ + fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, + "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", + __func__, xs, ys, xe, ye); + + switch (par->info->var.rotate) { + case 90: + case 270: + /* Set column address */ + write_reg(par, ys & 0x0F); + write_reg(par, 0x10 | (ys >> 4)); + + /* Set page address (divide xs by 2) (not used by driver) */ + write_reg(par, 0x60 | ((xs >> 1) & 0x0F)); + write_reg(par, 0x70 | (xs >> 5)); + break; + default: + /* Set column address (not used by driver) */ + write_reg(par, xs & 0x0F); + write_reg(par, 0x10 | (xs >> 4)); + + /* Set page address (divide ys by 2) */ + write_reg(par, 0x60 | ((ys >> 1) & 0x0F)); + write_reg(par, 0x70 | (ys >> 5)); + break; + } +} + +static int blank(struct fbtft_par *par, bool on) +{ + fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n", + __func__, on ? "true" : "false"); + + if (on) + write_reg(par, 0xA8 | 0x00); + else + write_reg(par, 0xA8 | 0x07); + return 0; +} + +static int set_var(struct fbtft_par *par) +{ + fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__); + + /* par->info->fix.visual = FB_VISUAL_PSEUDOCOLOR; */ + par->info->var.grayscale = 1; + par->info->var.red.offset = 0; + par->info->var.red.length = 8; + par->info->var.green.offset = 0; + par->info->var.green.length = 8; + par->info->var.blue.offset = 0; + par->info->var.blue.length = 8; + par->info->var.transp.offset = 0; + par->info->var.transp.length = 0; + + switch (par->info->var.rotate) { + case 90: + /* Set RAM address control */ + write_reg(par, 0x88 + | (0x0 & 0x1) << 2 /* Increment positively */ + | (0x1 & 0x1) << 1 /* Increment page first */ + | (0x1 & 0x1)); /* Wrap around (default) */ + + /* Set LCD mapping */ + write_reg(par, 0xC0 + | (0x0 & 0x1) << 2 /* Mirror Y OFF */ + | (0x0 & 0x1) << 1 /* Mirror X OFF */ + | (0x0 & 0x1)); /* MS nibble last (default) */ + break; + case 180: + /* Set RAM address control */ + write_reg(par, 0x88 + | (0x0 & 0x1) << 2 /* Increment positively */ + | (0x0 & 0x1) << 1 /* Increment column first */ + | (0x1 & 0x1)); /* Wrap around (default) */ + + /* Set LCD mapping */ + write_reg(par, 0xC0 + | (0x1 & 0x1) << 2 /* Mirror Y ON */ + | (0x0 & 0x1) << 1 /* Mirror X OFF */ + | (0x0 & 0x1)); /* MS nibble last (default) */ + break; + case 270: + /* Set RAM address control */ + write_reg(par, 0x88 + | (0x0 & 0x1) << 2 /* Increment positively */ + | (0x1 & 0x1) << 1 /* Increment page first */ + | (0x1 & 0x1)); /* Wrap around (default) */ + + /* Set LCD mapping */ + write_reg(par, 0xC0 + | (0x1 & 0x1) << 2 /* Mirror Y ON */ + | (0x1 & 0x1) << 1 /* Mirror X ON */ + | (0x0 & 0x1)); /* MS nibble last (default) */ + break; + default: + /* Set RAM address control */ + write_reg(par, 0x88 + | (0x0 & 0x1) << 2 /* Increment positively */ + | (0x0 & 0x1) << 1 /* Increment column first */ + | (0x1 & 0x1)); /* Wrap around (default) */ + + /* Set LCD mapping */ + write_reg(par, 0xC0 + | (0x0 & 0x1) << 2 /* Mirror Y OFF */ + | (0x1 & 0x1) << 1 /* Mirror X ON */ + | (0x0 & 0x1)); /* MS nibble last (default) */ + break; + } + + return 0; +} + +static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) +{ + u8 *vmem8 = (u8 *)(par->info->screen_base); + u8 *buf8 = (u8 *)(par->txbuf.buf); + u16 *buf16 = (u16 *)(par->txbuf.buf); + int line_length = par->info->fix.line_length; + int y_start = (offset / line_length); + int y_end = (offset + len - 1) / line_length; + int x, y, i; + int ret = 0; + + fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__); + + switch (par->pdata->display.buswidth) { + case 8: + switch (par->info->var.rotate) { + case 90: + case 270: + i = y_start * line_length; + for (y = y_start; y <= y_end; y++) { + for (x = 0; x < line_length; x += 2) { + *buf8 = vmem8[i] >> 4; + *buf8 |= vmem8[i + 1] & 0xF0; + buf8++; + i += 2; + } + } + break; + default: + /* Must be even because pages are two lines */ + y_start &= 0xFE; + i = y_start * line_length; + for (y = y_start; y <= y_end; y += 2) { + for (x = 0; x < line_length; x++) { + *buf8 = vmem8[i] >> 4; + *buf8 |= vmem8[i + line_length] & 0xF0; + buf8++; + i++; + } + i += line_length; + } + break; + } + gpio_set_value(par->gpio.dc, 1); + + /* Write data */ + ret = par->fbtftops.write(par, par->txbuf.buf, len / 2); + break; + case 9: + switch (par->info->var.rotate) { + case 90: + case 270: + i = y_start * line_length; + for (y = y_start; y <= y_end; y++) { + for (x = 0; x < line_length; x += 2) { + *buf16 = 0x100; + *buf16 |= vmem8[i] >> 4; + *buf16 |= vmem8[i + 1] & 0xF0; + buf16++; + i += 2; + } + } + break; + default: + /* Must be even because pages are two lines */ + y_start &= 0xFE; + i = y_start * line_length; + for (y = y_start; y <= y_end; y += 2) { + for (x = 0; x < line_length; x++) { + *buf16 = 0x100; + *buf16 |= vmem8[i] >> 4; + *buf16 |= vmem8[i + line_length] & 0xF0; + buf16++; + i++; + } + i += line_length; + } + break; + } + + /* Write data */ + ret = par->fbtftops.write(par, par->txbuf.buf, len); + break; + default: + dev_err(par->info->device, "unsupported buswidth %d\n", + par->pdata->display.buswidth); + } + + if (ret < 0) + dev_err(par->info->device, "write failed and returned: %d\n", + ret); + + return ret; +} + +static struct fbtft_display display = { + .txbuflen = -1, + .regwidth = 8, + .width = WIDTH, + .height = HEIGHT, + .bpp = BPP, + .fps = FPS, + .fbtftops = { + .write_vmem = write_vmem, + .init_display = init_display, + .set_addr_win = set_addr_win, + .set_var = set_var, + .blank = blank, + }, +}; + +FBTFT_REGISTER_DRIVER(DRVNAME, "ultrachip,uc1611", &display); + +MODULE_ALIAS("spi:" DRVNAME); +MODULE_ALIAS("platform:" DRVNAME); +MODULE_ALIAS("spi:uc1611"); +MODULE_ALIAS("platform:uc1611"); + +MODULE_DESCRIPTION("FB driver for the UC1611 LCD controller"); +MODULE_AUTHOR("Henri Chain"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/fbtft/fbtft_device.c b/drivers/staging/fbtft/fbtft_device.c index 211d504901f2..fa916e88d549 100644 --- a/drivers/staging/fbtft/fbtft_device.c +++ b/drivers/staging/fbtft/fbtft_device.c @@ -396,6 +396,37 @@ static struct fbtft_device_display displays[] = { }, } } + }, { + .name = "ew24ha0", + .spi = &(struct spi_board_info) { + .modalias = "fb_uc1611", + .max_speed_hz = 32000000, + .mode = SPI_MODE_3, + .platform_data = &(struct fbtft_platform_data) { + .display = { + .buswidth = 8, + }, + .gpios = (const struct fbtft_gpio []) { + { "dc", 24 }, + {}, + }, + } + } + }, { + .name = "ew24ha0_9bit", + .spi = &(struct spi_board_info) { + .modalias = "fb_uc1611", + .max_speed_hz = 32000000, + .mode = SPI_MODE_3, + .platform_data = &(struct fbtft_platform_data) { + .display = { + .buswidth = 9, + }, + .gpios = (const struct fbtft_gpio []) { + {}, + }, + } + } }, { .name = "flexfb", .spi = &(struct spi_board_info) { -- cgit v1.3-6-gb490 From 943304b3fb54adc5f2ec85d1679c7b2b8d908346 Mon Sep 17 00:00:00 2001 From: Arjun Krishna Babu Date: Sat, 20 Jun 2015 12:46:50 +0800 Subject: staging: vt6656: Fixed two lines over 80 characters long The presence of comments originally caused the two lines to be over 80 characters long. The issue is fixed by moving the comments into a separate line. Signed-off-by: Arjun Krishna Babu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/rxtx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index 8116791f4f06..da075f485298 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -45,8 +45,11 @@ #include "usbpipe.h" static const u16 vnt_time_stampoff[2][MAX_RATE] = { - {384, 288, 226, 209, 54, 43, 37, 31, 28, 25, 24, 23},/* Long Preamble */ - {384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23},/* Short Preamble */ + /* Long Preamble */ + {384, 288, 226, 209, 54, 43, 37, 31, 28, 25, 24, 23}, + + /* Short Preamble */ + {384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23}, }; static const u16 vnt_fb_opt0[2][5] = { -- cgit v1.3-6-gb490 From 4fdae0d9fee32c1cbffffb1a246fcc10ed5b1085 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 21 Jun 2015 11:05:54 +0100 Subject: staging: vt6655: vnt_tx_packet don't wakeup from power saving. mac80211 changes the wake state before attempting to tx data Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index ed040fbb7df8..0176456d15e2 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1211,9 +1211,6 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) vnt_generate_fifo_header(priv, dma_idx, head_td, skb); - if (MACbIsRegBitsOn(priv->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) - MACbPSWakeup(priv->PortOffset); - spin_lock_irqsave(&priv->lock, flags); priv->bPWBitOn = false; -- cgit v1.3-6-gb490 From 3e7921a09407743c52498c188adfa56156d60fc3 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 21 Jun 2015 11:05:55 +0100 Subject: staging: vt6655: Correct listen interval TBTT wake up PSbIsNextTBTTWakeUp is called at beacon intervals. The should listen to next beacon on count down of wake_up_count == 1. This restores this back to vendors code but modified for mac80211. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device.h | 1 + drivers/staging/vt6655/power.c | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/device.h b/drivers/staging/vt6655/device.h index 5cf1b337cba7..6aebb495fa8d 100644 --- a/drivers/staging/vt6655/device.h +++ b/drivers/staging/vt6655/device.h @@ -403,6 +403,7 @@ struct vnt_private { unsigned char abyEEPROM[EEP_MAX_CONTEXT_SIZE]; /* unsigned long alignment */ unsigned short wBeaconInterval; + u16 wake_up_count; struct work_struct interrupt_work; diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c index be3c4e949b6a..06e6b9d871c4 100644 --- a/drivers/staging/vt6655/power.c +++ b/drivers/staging/vt6655/power.c @@ -157,10 +157,18 @@ PSbIsNextTBTTWakeUp( struct ieee80211_conf *conf = &hw->conf; bool bWakeUp = false; - if (conf->listen_interval == 1) { - /* Turn on wake up to listen next beacon */ - MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN); - bWakeUp = true; + if (conf->listen_interval > 1) { + if (!pDevice->wake_up_count) + pDevice->wake_up_count = conf->listen_interval; + + --pDevice->wake_up_count; + + if (pDevice->wake_up_count == 1) { + /* Turn on wake up to listen next beacon */ + MACvRegBitsOn(pDevice->PortOffset, + MAC_REG_PSCTL, PSCTL_LNBCN); + bWakeUp = true; + } } return bWakeUp; -- cgit v1.3-6-gb490 From eda01f6161e0f0d156f7fd24080d3a788ebbb911 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Thu, 9 Jul 2015 17:01:25 +0100 Subject: staging: vt6655: Fix missing power saving support Add IEEE80211_HW_SUPPORTS_PS to ieee80211_hw flags enabling this feature. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 0176456d15e2..4f55d5e9a9c5 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1808,6 +1808,7 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent) ieee80211_hw_set(priv->hw, SIGNAL_DBM); ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS); ieee80211_hw_set(priv->hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(priv->hw, SUPPORTS_PS); priv->hw->max_signal = 100; -- cgit v1.3-6-gb490 From 353710ce90b74d711d6d30f1219e0c9634c6fc82 Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Sun, 12 Jul 2015 09:20:31 -0400 Subject: Staging: vt6655: Replace C99 comments in rf.h and rf.c. This patch replaces C99 comments in rf.h and rf.c, with C89 comments, fixing the checkpatch.pl errors. Signed-off-by: Nicholas Parkanyi Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/rf.c | 532 ++++++++++++++++++++++---------------------- drivers/staging/vt6655/rf.h | 24 +- 2 files changed, 278 insertions(+), 278 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c index 7626f635f160..c537321444be 100644 --- a/drivers/staging/vt6655/rf.c +++ b/drivers/staging/vt6655/rf.c @@ -39,66 +39,66 @@ #include "rf.h" #include "baseband.h" -#define BY_AL2230_REG_LEN 23 //24bit +#define BY_AL2230_REG_LEN 23 /* 24bit */ #define CB_AL2230_INIT_SEQ 15 -#define SWITCH_CHANNEL_DELAY_AL2230 200 //us +#define SWITCH_CHANNEL_DELAY_AL2230 200 /* us */ #define AL2230_PWR_IDX_LEN 64 -#define BY_AL7230_REG_LEN 23 //24bit +#define BY_AL7230_REG_LEN 23 /* 24bit */ #define CB_AL7230_INIT_SEQ 16 -#define SWITCH_CHANNEL_DELAY_AL7230 200 //us +#define SWITCH_CHANNEL_DELAY_AL7230 200 /* us */ #define AL7230_PWR_IDX_LEN 64 static const unsigned long dwAL2230InitTable[CB_AL2230_INIT_SEQ] = { - 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // - 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // - 0x01A00200+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // - 0x00FFF300+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // - 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // - 0x0F4DC500+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // - 0x0805B600+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // - 0x0146C700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // - 0x00068800+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // - 0x0403B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // - 0x00DBBA00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // - 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // + 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x01A00200+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x00FFF300+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0F4DC500+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0805B600+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0146C700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x00068800+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x0403B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x00DBBA00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, + 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, 0x0BDFFC00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, 0x00000D00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, 0x00580F00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW }; static const unsigned long dwAL2230ChannelTable0[CB_MAX_CHANNEL] = { - 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz - 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz - 0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz - 0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz - 0x03F7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz - 0x03F7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz - 0x03E7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz - 0x03E7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz - 0x03F7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz - 0x03F7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz - 0x03E7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz - 0x03E7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz - 0x03F7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz - 0x03E7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M + 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 1, Tf = 2412MHz */ + 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 2, Tf = 2417MHz */ + 0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 3, Tf = 2422MHz */ + 0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 4, Tf = 2427MHz */ + 0x03F7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 5, Tf = 2432MHz */ + 0x03F7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 6, Tf = 2437MHz */ + 0x03E7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 7, Tf = 2442MHz */ + 0x03E7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 8, Tf = 2447MHz */ + 0x03F7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 9, Tf = 2452MHz */ + 0x03F7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 10, Tf = 2457MHz */ + 0x03E7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 11, Tf = 2462MHz */ + 0x03E7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 12, Tf = 2467MHz */ + 0x03F7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 13, Tf = 2472MHz */ + 0x03E7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW /* channel = 14, Tf = 2412M */ }; static const unsigned long dwAL2230ChannelTable1[CB_MAX_CHANNEL] = { - 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz - 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz - 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz - 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz - 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz - 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz - 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz - 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz - 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz - 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz - 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz - 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz - 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz - 0x06666100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 1, Tf = 2412MHz */ + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 2, Tf = 2417MHz */ + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 3, Tf = 2422MHz */ + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 4, Tf = 2427MHz */ + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 5, Tf = 2432MHz */ + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 6, Tf = 2437MHz */ + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 7, Tf = 2442MHz */ + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 8, Tf = 2447MHz */ + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 9, Tf = 2452MHz */ + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 10, Tf = 2457MHz */ + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 11, Tf = 2462MHz */ + 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 12, Tf = 2467MHz */ + 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 13, Tf = 2472MHz */ + 0x06666100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW /* channel = 14, Tf = 2412M */ }; static unsigned long dwAL2230PowerTable[AL2230_PWR_IDX_LEN] = { @@ -168,240 +168,240 @@ static unsigned long dwAL2230PowerTable[AL2230_PWR_IDX_LEN] = { 0x0407F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW }; -// 40MHz reference frequency -// Need to Pull PLLON(PE3) low when writing channel registers through 3-wire. +/* 40MHz reference frequency + * Need to Pull PLLON(PE3) low when writing channel registers through 3-wire.*/ static const unsigned long dwAL7230InitTable[CB_AL7230_INIT_SEQ] = { - 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a - 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a - 0x841FF200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 451FE2 - 0x3FDFA300+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 5FDFA3 - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // 11b/g // Need modify for 11a - // RoberYu:20050113, Rev0.47 Regsiter Setting Guide - 0x802B5500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 8D1B55 + 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Channel1 // Need modify for 11a */ + 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Channel1 // Need modify for 11a */ + 0x841FF200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11a: 451FE2 */ + 0x3FDFA300+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11a: 5FDFA3 */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* 11b/g // Need modify for 11a */ + /* RoberYu:20050113, Rev0.47 Regsiter Setting Guide */ + 0x802B5500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11a: 8D1B55 */ 0x56AF3600+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, - 0xCE020700+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 860207 + 0xCE020700+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11a: 860207 */ 0x6EBC0800+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, - 0xE0000A00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: E0600A - 0x08031B00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // init 0x080B1B00 => 0x080F1B00 for 3 wire control TxGain(D10) - // RoberYu:20050113, Rev0.47 Regsiter Setting Guide - 0x000A3C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 00143C + 0xE0000A00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11a: E0600A */ + 0x08031B00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* init 0x080B1B00 => 0x080F1B00 for 3 wire control TxGain(D10) */ + /* RoberYu:20050113, Rev0.47 Regsiter Setting Guide */ + 0x000A3C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11a: 00143C */ 0xFFFFFD00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, 0x00000E00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, - 0x1ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // Need modify for 11a: 12BACF + 0x1ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW /* Need modify for 11a: 12BACF */ }; static const unsigned long dwAL7230InitTableAMode[CB_AL7230_INIT_SEQ] = { - 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g - 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g - 0x451FE200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g - 0x5FDFA300+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g - 0x67F78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // 11a // Need modify for 11b/g - 0x853F5500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g, RoberYu:20050113 + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Channel184 // Need modify for 11b/g */ + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Channel184 // Need modify for 11b/g */ + 0x451FE200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11b/g */ + 0x5FDFA300+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11b/g */ + 0x67F78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* 11a // Need modify for 11b/g */ + 0x853F5500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11b/g, RoberYu:20050113 */ 0x56AF3600+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, - 0xCE020700+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g + 0xCE020700+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11b/g */ 0x6EBC0800+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, - 0xE0600A00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g - 0x08031B00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // init 0x080B1B00 => 0x080F1B00 for 3 wire control TxGain(D10) - 0x00147C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g + 0xE0600A00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11b/g */ + 0x08031B00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* init 0x080B1B00 => 0x080F1B00 for 3 wire control TxGain(D10) */ + 0x00147C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* Need modify for 11b/g */ 0xFFFFFD00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, 0x00000E00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, - 0x12BACF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // Need modify for 11b/g + 0x12BACF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW /* Need modify for 11b/g */ }; static const unsigned long dwAL7230ChannelTable0[CB_MAX_CHANNEL] = { - 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz - 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz - 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz - 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz - 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz - 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz - 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz - 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz //RobertYu: 20050218, update for APNode 0.49 - 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz //RobertYu: 20050218, update for APNode 0.49 - 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz //RobertYu: 20050218, update for APNode 0.49 - 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz //RobertYu: 20050218, update for APNode 0.49 - 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz //RobertYu: 20050218, update for APNode 0.49 - 0x0037C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz //RobertYu: 20050218, update for APNode 0.49 - 0x0037C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz - - // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22) - 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15) - 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16) - 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17) - 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18) - 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19) - 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20) - 0x0FF53000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21) - 0x0FF53000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22) - - // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, - // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56) - - 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23) - 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24) - 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25) - 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26) - 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27) - 0x0FF55000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28) - 0x0FF56000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29) - 0x0FF56000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30) - 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31) //RobertYu: 20050218, update for APNode 0.49 - 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32) - 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33) - 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34) - 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35) - 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36) - 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37) - 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38) - 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39) - 0x0FF59000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40) - - 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41) - 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42) - 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43) - 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44) - 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45) - 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46) - 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47) - 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48) - 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49) - 0x0FF5F000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50) - 0x0FF5F000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51) - 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52) - 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53) - 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54) - 0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55) - 0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56) + 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 1, Tf = 2412MHz */ + 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 2, Tf = 2417MHz */ + 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 3, Tf = 2422MHz */ + 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 4, Tf = 2427MHz */ + 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 5, Tf = 2432MHz */ + 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 6, Tf = 2437MHz */ + 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 7, Tf = 2442MHz */ + 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 8, Tf = 2447MHz //RobertYu: 20050218, update for APNode 0.49 */ + 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 9, Tf = 2452MHz //RobertYu: 20050218, update for APNode 0.49 */ + 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 10, Tf = 2457MHz //RobertYu: 20050218, update for APNode 0.49 */ + 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 11, Tf = 2462MHz //RobertYu: 20050218, update for APNode 0.49 */ + 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 12, Tf = 2467MHz //RobertYu: 20050218, update for APNode 0.49 */ + 0x0037C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 13, Tf = 2472MHz //RobertYu: 20050218, update for APNode 0.49 */ + 0x0037C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 14, Tf = 2484MHz */ + + /* 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22) */ + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 183, Tf = 4915MHz (15) */ + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 184, Tf = 4920MHz (16) */ + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 185, Tf = 4925MHz (17) */ + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 187, Tf = 4935MHz (18) */ + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 188, Tf = 4940MHz (19) */ + 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 189, Tf = 4945MHz (20) */ + 0x0FF53000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 192, Tf = 4960MHz (21) */ + 0x0FF53000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 196, Tf = 4980MHz (22) */ + + /* 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, + * 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56) */ + + 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 7, Tf = 5035MHz (23) */ + 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 8, Tf = 5040MHz (24) */ + 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 9, Tf = 5045MHz (25) */ + 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 11, Tf = 5055MHz (26) */ + 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 12, Tf = 5060MHz (27) */ + 0x0FF55000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 16, Tf = 5080MHz (28) */ + 0x0FF56000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 34, Tf = 5170MHz (29) */ + 0x0FF56000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 36, Tf = 5180MHz (30) */ + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 38, Tf = 5190MHz (31) //RobertYu: 20050218, update for APNode 0.49 */ + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 40, Tf = 5200MHz (32) */ + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 42, Tf = 5210MHz (33) */ + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 44, Tf = 5220MHz (34) */ + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 46, Tf = 5230MHz (35) */ + 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 48, Tf = 5240MHz (36) */ + 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 52, Tf = 5260MHz (37) */ + 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 56, Tf = 5280MHz (38) */ + 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 60, Tf = 5300MHz (39) */ + 0x0FF59000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 64, Tf = 5320MHz (40) */ + + 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 100, Tf = 5500MHz (41) */ + 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 104, Tf = 5520MHz (42) */ + 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 108, Tf = 5540MHz (43) */ + 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 112, Tf = 5560MHz (44) */ + 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 116, Tf = 5580MHz (45) */ + 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 120, Tf = 5600MHz (46) */ + 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 124, Tf = 5620MHz (47) */ + 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 128, Tf = 5640MHz (48) */ + 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 132, Tf = 5660MHz (49) */ + 0x0FF5F000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 136, Tf = 5680MHz (50) */ + 0x0FF5F000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 140, Tf = 5700MHz (51) */ + 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 149, Tf = 5745MHz (52) */ + 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 153, Tf = 5765MHz (53) */ + 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 157, Tf = 5785MHz (54) */ + 0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 161, Tf = 5805MHz (55) */ + 0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW /* channel = 165, Tf = 5825MHz (56) */ }; static const unsigned long dwAL7230ChannelTable1[CB_MAX_CHANNEL] = { - 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz - 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz - 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz - 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz - 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz - 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz - 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz - 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz - 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz - 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz - 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz - 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz - 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz - 0x06666100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz - - // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22) - 0x1D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15) - 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16) - 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17) - 0x08000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18) - 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19) - 0x0D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20) - 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21) - 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22) - - // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, - // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56) - 0x1D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23) - 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24) - 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25) - 0x08000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26) - 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27) - 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28) - 0x05555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29) - 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30) - 0x10000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31) - 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32) - 0x1AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33) - 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34) - 0x05555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35) - 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36) - 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37) - 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38) - 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39) - 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40) - 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41) - 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42) - 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43) - 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44) - 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45) - 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46) - 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47) - 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48) - 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49) - 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50) - 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51) - 0x18000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52) - 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53) - 0x0D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54) - 0x18000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55) - 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56) + 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 1, Tf = 2412MHz */ + 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 2, Tf = 2417MHz */ + 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 3, Tf = 2422MHz */ + 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 4, Tf = 2427MHz */ + 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 5, Tf = 2432MHz */ + 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 6, Tf = 2437MHz */ + 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 7, Tf = 2442MHz */ + 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 8, Tf = 2447MHz */ + 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 9, Tf = 2452MHz */ + 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 10, Tf = 2457MHz */ + 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 11, Tf = 2462MHz */ + 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 12, Tf = 2467MHz */ + 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 13, Tf = 2472MHz */ + 0x06666100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 14, Tf = 2484MHz */ + + /* 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22) */ + 0x1D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 183, Tf = 4915MHz (15) */ + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 184, Tf = 4920MHz (16) */ + 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 185, Tf = 4925MHz (17) */ + 0x08000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 187, Tf = 4935MHz (18) */ + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 188, Tf = 4940MHz (19) */ + 0x0D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 189, Tf = 4945MHz (20) */ + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 192, Tf = 4960MHz (21) */ + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 196, Tf = 4980MHz (22) */ + + /* 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, + * 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56) */ + 0x1D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 7, Tf = 5035MHz (23) */ + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 8, Tf = 5040MHz (24) */ + 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 9, Tf = 5045MHz (25) */ + 0x08000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 11, Tf = 5055MHz (26) */ + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 12, Tf = 5060MHz (27) */ + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 16, Tf = 5080MHz (28) */ + 0x05555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 34, Tf = 5170MHz (29) */ + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 36, Tf = 5180MHz (30) */ + 0x10000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 38, Tf = 5190MHz (31) */ + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 40, Tf = 5200MHz (32) */ + 0x1AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 42, Tf = 5210MHz (33) */ + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 44, Tf = 5220MHz (34) */ + 0x05555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 46, Tf = 5230MHz (35) */ + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 48, Tf = 5240MHz (36) */ + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 52, Tf = 5260MHz (37) */ + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 56, Tf = 5280MHz (38) */ + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 60, Tf = 5300MHz (39) */ + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 64, Tf = 5320MHz (40) */ + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 100, Tf = 5500MHz (41) */ + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 104, Tf = 5520MHz (42) */ + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 108, Tf = 5540MHz (43) */ + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 112, Tf = 5560MHz (44) */ + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 116, Tf = 5580MHz (45) */ + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 120, Tf = 5600MHz (46) */ + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 124, Tf = 5620MHz (47) */ + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 128, Tf = 5640MHz (48) */ + 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 132, Tf = 5660MHz (49) */ + 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 136, Tf = 5680MHz (50) */ + 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 140, Tf = 5700MHz (51) */ + 0x18000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 149, Tf = 5745MHz (52) */ + 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 153, Tf = 5765MHz (53) */ + 0x0D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 157, Tf = 5785MHz (54) */ + 0x18000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 161, Tf = 5805MHz (55) */ + 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW /* channel = 165, Tf = 5825MHz (56) */ }; static const unsigned long dwAL7230ChannelTable2[CB_MAX_CHANNEL] = { - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz - 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz - - // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15) - 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21) - 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22) - - // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, - // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23) - 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33) - 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37) - 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41) - 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44) - 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47) - 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50) - 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55) - 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56) + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 1, Tf = 2412MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 2, Tf = 2417MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 3, Tf = 2422MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 4, Tf = 2427MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 5, Tf = 2432MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 6, Tf = 2437MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 7, Tf = 2442MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 8, Tf = 2447MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 9, Tf = 2452MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 10, Tf = 2457MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 11, Tf = 2462MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 12, Tf = 2467MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 13, Tf = 2472MHz */ + 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 14, Tf = 2484MHz */ + + /* 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 183, Tf = 4915MHz (15) */ + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 184, Tf = 4920MHz (16) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 185, Tf = 4925MHz (17) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 187, Tf = 4935MHz (18) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 188, Tf = 4940MHz (19) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 189, Tf = 4945MHz (20) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 192, Tf = 4960MHz (21) */ + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 196, Tf = 4980MHz (22) */ + + /* 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, + * 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 7, Tf = 5035MHz (23) */ + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 8, Tf = 5040MHz (24) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 9, Tf = 5045MHz (25) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 11, Tf = 5055MHz (26) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 12, Tf = 5060MHz (27) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 16, Tf = 5080MHz (28) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 34, Tf = 5170MHz (29) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 36, Tf = 5180MHz (30) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 38, Tf = 5190MHz (31) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 40, Tf = 5200MHz (32) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 42, Tf = 5210MHz (33) */ + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 44, Tf = 5220MHz (34) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 46, Tf = 5230MHz (35) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 48, Tf = 5240MHz (36) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 52, Tf = 5260MHz (37) */ + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 56, Tf = 5280MHz (38) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 60, Tf = 5300MHz (39) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 64, Tf = 5320MHz (40) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 100, Tf = 5500MHz (41) */ + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 104, Tf = 5520MHz (42) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 108, Tf = 5540MHz (43) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 112, Tf = 5560MHz (44) */ + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 116, Tf = 5580MHz (45) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 120, Tf = 5600MHz (46) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 124, Tf = 5620MHz (47) */ + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 128, Tf = 5640MHz (48) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 132, Tf = 5660MHz (49) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 136, Tf = 5680MHz (50) */ + 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 140, Tf = 5700MHz (51) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 149, Tf = 5745MHz (52) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 153, Tf = 5765MHz (53) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 157, Tf = 5785MHz (54) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, /* channel = 161, Tf = 5805MHz (55) */ + 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW /* channel = 165, Tf = 5825MHz (56) */ }; /* @@ -438,13 +438,13 @@ static bool s_bAL7230Init(struct vnt_private *priv) MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); /* Calibration */ - MACvTimer0MicroSDelay(dwIoBase, 150);//150us + MACvTimer0MicroSDelay(dwIoBase, 150);/* 150us */ /* TXDCOC:active, RCK:disable */ bResult &= IFRFbWriteEmbedded(priv, (0x9ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); - MACvTimer0MicroSDelay(dwIoBase, 30);//30us + MACvTimer0MicroSDelay(dwIoBase, 30);/* 30us */ /* TXDCOC:disable, RCK:active */ bResult &= IFRFbWriteEmbedded(priv, (0x3ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); - MACvTimer0MicroSDelay(dwIoBase, 30);//30us + MACvTimer0MicroSDelay(dwIoBase, 30);/* 30us */ /* TXDCOC:disable, RCK:disable */ bResult &= IFRFbWriteEmbedded(priv, dwAL7230InitTable[CB_AL7230_INIT_SEQ-1]); @@ -457,7 +457,7 @@ static bool s_bAL7230Init(struct vnt_private *priv) /* PE1: TX_ON, PE2: RX_ON, PE3: PLLON */ /* 3-wire control for power saving mode */ - VNSvOutPortB(dwIoBase + MAC_REG_PSPWRSIG, (PSSIG_WPE3 | PSSIG_WPE2)); //1100 0000 + VNSvOutPortB(dwIoBase + MAC_REG_PSPWRSIG, (PSSIG_WPE3 | PSSIG_WPE2)); /* 1100 0000 */ return bResult; } @@ -557,16 +557,16 @@ static bool RFbAL2230Init(struct vnt_private *priv) for (ii = 0; ii < CB_AL2230_INIT_SEQ; ii++) bResult &= IFRFbWriteEmbedded(priv, dwAL2230InitTable[ii]); - MACvTimer0MicroSDelay(dwIoBase, 30); //delay 30 us + MACvTimer0MicroSDelay(dwIoBase, 30); /* delay 30 us */ /* PLL On */ MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); - MACvTimer0MicroSDelay(dwIoBase, 150);//150us + MACvTimer0MicroSDelay(dwIoBase, 150);/* 150us */ bResult &= IFRFbWriteEmbedded(priv, (0x00d80f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW)); - MACvTimer0MicroSDelay(dwIoBase, 30);//30us + MACvTimer0MicroSDelay(dwIoBase, 30);/* 30us */ bResult &= IFRFbWriteEmbedded(priv, (0x00780f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW)); - MACvTimer0MicroSDelay(dwIoBase, 30);//30us + MACvTimer0MicroSDelay(dwIoBase, 30);/* 30us */ bResult &= IFRFbWriteEmbedded(priv, dwAL2230InitTable[CB_AL2230_INIT_SEQ-1]); MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 | @@ -575,7 +575,7 @@ static bool RFbAL2230Init(struct vnt_private *priv) SOFTPWRCTL_TXPEINV)); /* 3-wire control for power saving mode */ - VNSvOutPortB(dwIoBase + MAC_REG_PSPWRSIG, (PSSIG_WPE3 | PSSIG_WPE2)); //1100 0000 + VNSvOutPortB(dwIoBase + MAC_REG_PSPWRSIG, (PSSIG_WPE3 | PSSIG_WPE2)); /* 1100 0000 */ return bResult; } @@ -661,11 +661,11 @@ bool RFbSelectChannel(struct vnt_private *priv, unsigned char byRFType, case RF_AL2230S: bResult = RFbAL2230SelectChannel(priv, byChannel); break; - //{{ RobertYu: 20050104 + /*{{ RobertYu: 20050104 */ case RF_AIROHA7230: bResult = s_bAL7230SelectChannel(priv, byChannel); break; - //}} RobertYu + /*}} RobertYu */ case RF_NOTHING: bResult = true; break; diff --git a/drivers/staging/vt6655/rf.h b/drivers/staging/vt6655/rf.h index 2ea21e2b00f2..b5fc3eed06fb 100644 --- a/drivers/staging/vt6655/rf.h +++ b/drivers/staging/vt6655/rf.h @@ -33,18 +33,18 @@ #include "device.h" /*--------------------- Export Definitions -------------------------*/ -// -// Baseband RF pair definition in eeprom (Bits 6..0) -// +/* + * Baseband RF pair definition in eeprom (Bits 6..0) +*/ #define RF_RFMD2959 0x01 #define RF_MAXIMAG 0x02 #define RF_AIROHA 0x03 #define RF_UW2451 0x05 #define RF_MAXIMG 0x06 -#define RF_MAXIM2829 0x07 // RobertYu: 20041118 -#define RF_UW2452 0x08 // RobertYu: 20041210 -#define RF_AIROHA7230 0x0a // RobertYu: 20050104 +#define RF_MAXIM2829 0x07 /* RobertYu: 20041118 */ +#define RF_UW2452 0x08 /* RobertYu: 20041210 */ +#define RF_AIROHA7230 0x0a /* RobertYu: 20050104 */ #define RF_UW2453 0x0b #define RF_VT3226 0x09 @@ -63,9 +63,9 @@ #define ZONE_MKK 6 #define ZONE_ISRAEL 7 -//[20050104] CB_MAXIM2829_CHANNEL_5G_HIGH, CB_UW2452_CHANNEL_5G_HIGH: 40==>41 -#define CB_MAXIM2829_CHANNEL_5G_HIGH 41 //Index41: channel = 100, Tf = 5500MHz, set the (A3:A0=0101) D6=1 -#define CB_UW2452_CHANNEL_5G_HIGH 41 //[20041210] Index41: channel = 100, Tf = 5500MHz, change VCO2->VCO3 +/* [20050104] CB_MAXIM2829_CHANNEL_5G_HIGH, CB_UW2452_CHANNEL_5G_HIGH: 40==>41 */ +#define CB_MAXIM2829_CHANNEL_5G_HIGH 41 /* Index41: channel = 100, Tf = 5500MHz, set the (A3:A0=0101) D6=1 */ +#define CB_UW2452_CHANNEL_5G_HIGH 41 /* [20041210] Index41: channel = 100, Tf = 5500MHz, change VCO2->VCO3 */ /*--------------------- Export Classes ----------------------------*/ @@ -93,8 +93,8 @@ RFvRSSITodBm( long *pldBm ); -//{{ RobertYu: 20050104 +/* {{ RobertYu: 20050104 */ bool RFbAL7230SelectChannelPostProcess(struct vnt_private *, u16, u16); -//}} RobertYu +/* }} RobertYu */ -#endif // __RF_H__ +#endif /* __RF_H__ */ -- cgit v1.3-6-gb490 From 11208b0b3a9ddc462795bdb3aadfc0eda8ef2e4b Mon Sep 17 00:00:00 2001 From: Nicholas Parkanyi Date: Sun, 12 Jul 2015 08:17:52 -0400 Subject: Staging: vt6655: Remove do { } while (0) from single-statement macros in upc.h. This patch fixes checkpatch.pl warnings in upc.h regarding single-statement macros embedded within do { } while (0) blocks. Signed-off-by: Nicholas Parkanyi Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/upc.h | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/upc.h b/drivers/staging/vt6655/upc.h index cc63dc8d47f7..85fe0464cfb3 100644 --- a/drivers/staging/vt6655/upc.h +++ b/drivers/staging/vt6655/upc.h @@ -37,35 +37,23 @@ /* For memory mapped IO */ -#define VNSvInPortB(dwIOAddress, pbyData) \ -do { \ - *(pbyData) = ioread8(dwIOAddress); \ -} while (0) +#define VNSvInPortB(dwIOAddress, pbyData) \ + (*(pbyData) = ioread8(dwIOAddress)) -#define VNSvInPortW(dwIOAddress, pwData) \ -do { \ - *(pwData) = ioread16(dwIOAddress); \ -} while (0) +#define VNSvInPortW(dwIOAddress, pwData) \ + (*(pwData) = ioread16(dwIOAddress)) -#define VNSvInPortD(dwIOAddress, pdwData) \ -do { \ - *(pdwData) = ioread32(dwIOAddress); \ -} while (0) +#define VNSvInPortD(dwIOAddress, pdwData) \ + (*(pdwData) = ioread32(dwIOAddress)) -#define VNSvOutPortB(dwIOAddress, byData) \ -do { \ - iowrite8((u8)byData, dwIOAddress); \ -} while (0) +#define VNSvOutPortB(dwIOAddress, byData) \ + iowrite8((u8)(byData), dwIOAddress) -#define VNSvOutPortW(dwIOAddress, wData) \ -do { \ - iowrite16((u16)wData, dwIOAddress); \ -} while (0) +#define VNSvOutPortW(dwIOAddress, wData) \ + iowrite16((u16)(wData), dwIOAddress) -#define VNSvOutPortD(dwIOAddress, dwData) \ -do { \ - iowrite32((u32)dwData, dwIOAddress); \ -} while (0) +#define VNSvOutPortD(dwIOAddress, dwData) \ + iowrite32((u32)(dwData), dwIOAddress) #define PCAvDelayByIO(uDelayUnit) \ do { \ -- cgit v1.3-6-gb490 From edeafb979666e28cbd4699716a1e5533791ea916 Mon Sep 17 00:00:00 2001 From: Joglekar Tejas Date: Sat, 20 Jun 2015 12:46:16 +0000 Subject: staging:rtl8723au:odm.c:Removing trailing whitespaces This patch removes the trailing whitespace error given by checkpatch.pl Signed-off-by: Joglekar Tejas Acked-by: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/hal/odm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/hal/odm.c b/drivers/staging/rtl8723au/hal/odm.c index f354f5e11a30..6b9dbeffafcb 100644 --- a/drivers/staging/rtl8723au/hal/odm.c +++ b/drivers/staging/rtl8723au/hal/odm.c @@ -985,7 +985,7 @@ void ODM_RF_Saving23a(struct dm_odm_t *pDM_Odm, u8 bForceInNormal) val32 = rtl8723au_read32(adapter, 0x874); val32 |= pDM_PSTable->Reg874; rtl8723au_write32(adapter, 0x874, val32); - + val32 = rtl8723au_read32(adapter, 0xc70); val32 |= pDM_PSTable->RegC70; rtl8723au_write32(adapter, 0xc70, val32); -- cgit v1.3-6-gb490 From e60b6538342ec047ae2e49335f65b7f92585fab9 Mon Sep 17 00:00:00 2001 From: Greg Donald Date: Sat, 20 Jun 2015 11:06:48 -0500 Subject: drivers: staging: rtl8192u: Fix "space required after that ','" errors Fix checkpatch.pl "space required after that ','" errors Signed-off-by: Greg Donald Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c | 4 ++-- drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c | 2 +- drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c | 2 +- drivers/staging/rtl8192u/r819xU_firmware.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index 1b11acb96233..a1f9d42833e0 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -1177,7 +1177,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco tag = skb_put(skb, ht_cap_len); *tag++ = MFIE_TYPE_HT_CAP; *tag++ = ht_cap_len - 2; - memcpy(tag, ht_cap_buf,ht_cap_len -2); + memcpy(tag, ht_cap_buf, ht_cap_len - 2); tag += ht_cap_len -2; } } @@ -1214,7 +1214,7 @@ inline struct sk_buff *ieee80211_association_req(struct ieee80211_network *beaco tag = skb_put(skb, realtek_ie_len); *tag++ = MFIE_TYPE_GENERIC; *tag++ = realtek_ie_len - 2; - memcpy(tag, realtek_ie_buf,realtek_ie_len -2 ); + memcpy(tag, realtek_ie_buf, realtek_ie_len - 2); } } // printk("<=====%s(), %p, %p\n", __func__, ieee->dev, ieee->dev->dev_addr); diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c index 714fbcace72b..3e502520648e 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c @@ -391,7 +391,7 @@ int ieee80211_wx_set_essid(struct ieee80211_device *ieee, union iwreq_data *wrqu, char *extra) { - int ret=0,len; + int ret = 0, len; short proto_started; unsigned long flags; diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c index c2588f80625b..80411c93d8fa 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c @@ -956,7 +956,7 @@ void HTOnAssocRsp(struct ieee80211_device *ieee) // HTDebugHTCapability(pHTInfo->PeerHTCapBuf,"HTOnAssocRsp_wq"); // HTDebugHTInfo(pHTInfo->PeerHTInfoBuf,"HTOnAssocRsp_wq"); // - if(!memcmp(pHTInfo->PeerHTCapBuf,EWC11NHTCap, sizeof(EWC11NHTCap))) + if (!memcmp(pHTInfo->PeerHTCapBuf, EWC11NHTCap, sizeof(EWC11NHTCap))) pPeerHTCap = (PHT_CAPABILITY_ELE)(&pHTInfo->PeerHTCapBuf[4]); else pPeerHTCap = (PHT_CAPABILITY_ELE)(pHTInfo->PeerHTCapBuf); diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c index d27b1e24ca4a..742725e9bfc1 100644 --- a/drivers/staging/rtl8192u/r819xU_firmware.c +++ b/drivers/staging/rtl8192u/r819xU_firmware.c @@ -66,7 +66,7 @@ static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, skb = dev_alloc_skb(USB_HWDESC_HEADER_LEN + frag_length + 4); if (!skb) return false; - memcpy((unsigned char *)(skb->cb),&dev,sizeof(dev)); + memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); tcb_desc->queue_index = TXCMD_QUEUE; tcb_desc->bCmdOrInit = DESC_PACKET_TYPE_INIT; -- cgit v1.3-6-gb490 From 7ee8095bfe1d61ab4a59f5eff14d833ff90c0b38 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Fri, 26 Jun 2015 09:54:00 +0530 Subject: Staging: rtl8192u: Replace memset with eth_zero_addr Use eth_zero_addr to assign the zero address to the given address array instead of memset when second argument is address of zero. Note that the 6 in the third argument of memset appears to represent an ethernet address size (ETH_ALEN). The Coccinelle semantic patch that makes this change is as follows: // @eth_zero_addr@ expression e; @@ -memset(e,0x00,6); +eth_zero_addr(e); // Signed-off-by: Vaishali Thakkar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c index ea92fdebe5a7..b89105dbcbba 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c @@ -112,7 +112,7 @@ static void TsAddBaProcess(unsigned long data) static void ResetTsCommonInfo(PTS_COMMON_INFO pTsCommonInfo) { - memset(pTsCommonInfo->Addr, 0, 6); + eth_zero_addr(pTsCommonInfo->Addr); memset(&pTsCommonInfo->TSpec, 0, sizeof(TSPEC_BODY)); memset(&pTsCommonInfo->TClass, 0, sizeof(QOS_TCLAS)*TCLAS_NUM); pTsCommonInfo->TClasProc = 0; -- cgit v1.3-6-gb490 From 0ccd8ebb0e17ddeb2d56cf644da089adc4aa3bc0 Mon Sep 17 00:00:00 2001 From: Peter Karlsson Date: Sun, 21 Jun 2015 13:29:50 +0200 Subject: staging: ft1000-usb: fixed table alignment Fixed alignment to 8 bytes per line. Signed-off-by: Peter Karlsson Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_debug.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c index 409266b1a886..90942e02a583 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c @@ -415,12 +415,19 @@ static long ft1000_ioctl(struct file *file, unsigned int command, struct timeval tv; struct IOCTL_GET_VER get_ver_data; struct IOCTL_GET_DSP_STAT get_stat_data; - u8 ConnectionMsg[] = {0x00, 0x44, 0x10, 0x20, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x93, 0x64, - 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0a, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x37, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7f, 0x00, - 0x00, 0x01, 0x00, 0x00}; + u8 ConnectionMsg[] = { + 0x00, 0x44, 0x10, 0x20, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x93, 0x64, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x37, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7f, 0x00, + 0x00, 0x01, 0x00, 0x00 + }; unsigned short ledStat = 0; unsigned short conStat = 0; -- cgit v1.3-6-gb490 From d4216b30bdd56fb823c1d32b5e46687ae87601f6 Mon Sep 17 00:00:00 2001 From: Peter Karlsson Date: Sun, 21 Jun 2015 13:29:51 +0200 Subject: staging: ft1000-usb: shorten lines to under 80 characters Wrap function arguments to shorten lines to under 80 characters. Signed-off-by: Peter Karlsson Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_debug.c | 12 ++++++++---- drivers/staging/ft1000/ft1000-usb/ft1000_download.c | 21 ++++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c index 90942e02a583..f241a3a5a684 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_debug.c @@ -260,7 +260,8 @@ void ft1000_destroy_dev(struct net_device *netdev) /* Make sure we free any memory reserve for slow Queue */ for (i = 0; i < MAX_NUM_APP; i++) { while (list_empty(&dev->app_info[i].app_sqlist) == 0) { - pdpram_blk = list_entry(dev->app_info[i].app_sqlist.next, struct dpram_blk, list); + pdpram_blk = list_entry(dev->app_info[i].app_sqlist.next, + struct dpram_blk, list); list_del(&pdpram_blk->list); ft1000_free_buffer(pdpram_blk, &freercvpool); @@ -502,10 +503,12 @@ static long ft1000_ioctl(struct file *file, unsigned int command, memcpy(get_stat_data.eui64, info->eui64, EUISZ); if (info->ProgConStat != 0xFF) { - ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX); + ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, + (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX); get_stat_data.LedStat = ntohs(ledStat); pr_debug("LedStat = 0x%x\n", get_stat_data.LedStat); - ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX); + ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, + (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX); get_stat_data.ConStat = ntohs(conStat); pr_debug("ConStat = 0x%x\n", get_stat_data.ConStat); } else { @@ -696,7 +699,8 @@ static long ft1000_ioctl(struct file *file, unsigned int command, if (list_empty(&ft1000dev->app_info[i].app_sqlist) == 0) { /* pr_debug("Message detected in slow queue\n"); */ spin_lock_irqsave(&free_buff_lock, flags); - pdpram_blk = list_entry(ft1000dev->app_info[i].app_sqlist.next, struct dpram_blk, list); + pdpram_blk = list_entry(ft1000dev->app_info[i].app_sqlist.next, + struct dpram_blk, list); list_del(&pdpram_blk->list); ft1000dev->app_info[i].NumOfMsg--; /* pr_debug("NumOfMsg for app %d = %d\n", i, ft1000dev->app_info[i].NumOfMsg); */ diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index 5def347beb08..a72511c21200 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -180,7 +180,8 @@ static u16 get_handshake(struct ft1000_usb *ft1000dev, u16 expected_value) } status = ft1000_read_dpram16(ft1000dev, - DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1); + DWNLD_MAG1_HANDSHAKE_LOC, + (u8 *)&handshake, 1); handshake = ntohs(handshake); if (status) @@ -281,12 +282,14 @@ static u16 get_request_type(struct ft1000_usb *ft1000dev) if (ft1000dev->bootmode == 1) { status = fix_ft1000_read_dpram32(ft1000dev, - DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx); + DWNLD_MAG1_TYPE_LOC, + (u8 *)&tempx); tempx = ntohl(tempx); } else { tempx = 0; status = ft1000_read_dpram16(ft1000dev, - DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1); + DWNLD_MAG1_TYPE_LOC, + (u8 *)&tempword, 1); tempx |= (tempword << 16); tempx = ntohl(tempx); } @@ -304,7 +307,8 @@ static u16 get_request_type_usb(struct ft1000_usb *ft1000dev) if (ft1000dev->bootmode == 1) { status = fix_ft1000_read_dpram32(ft1000dev, - DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx); + DWNLD_MAG1_TYPE_LOC, + (u8 *)&tempx); tempx = ntohl(tempx); } else { if (ft1000dev->usbboot == 2) { @@ -332,14 +336,17 @@ static long get_request_value(struct ft1000_usb *ft1000dev) if (ft1000dev->bootmode == 1) { status = fix_ft1000_read_dpram32(ft1000dev, - DWNLD_MAG1_SIZE_LOC, (u8 *)&value); + DWNLD_MAG1_SIZE_LOC, + (u8 *)&value); value = ntohl(value); } else { status = ft1000_read_dpram16(ft1000dev, - DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 0); + DWNLD_MAG1_SIZE_LOC, + (u8 *)&tempword, 0); value = tempword; status = ft1000_read_dpram16(ft1000dev, - DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1); + DWNLD_MAG1_SIZE_LOC, + (u8 *)&tempword, 1); value |= (tempword << 16); value = ntohl(value); } -- cgit v1.3-6-gb490 From f4bf6b343073e32d5cf8fdb0f38192493fcad5c2 Mon Sep 17 00:00:00 2001 From: Giedrius Statkevičius Date: Thu, 25 Jun 2015 20:34:43 +0300 Subject: staging: ft1000: convert pack pragma to __packed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert a Microsoft compiler specific directive "#pragma pack(1)" to a GCC equivalent __packed. Also, by doing this we save ourselves from trouble if any other struct definitions are added after the #pragma because it will be applied to all of the definitions following it. Signed-off-by: Giedrius Statkevičius Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_download.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index a72511c21200..297b7aece506 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -95,7 +95,6 @@ struct dsp_file_hdr { long nDspImages; /* Number of DSP images in file. */ }; -#pragma pack(1) struct dsp_image_info { long coff_date; /* Date/time when DSP Coff image was built. */ long begin_offset; /* Offset in file where image begins. */ @@ -105,7 +104,7 @@ struct dsp_image_info { long version; /* Embedded version # of DSP code. */ unsigned short checksum; /* DSP File checksum */ unsigned short pad1; -}; +} __packed; /* checks if the doorbell register is cleared */ -- cgit v1.3-6-gb490 From 8027b3332142268a1cf988fd62946a4afe49b986 Mon Sep 17 00:00:00 2001 From: Sunil Shahu Date: Mon, 22 Jun 2015 16:58:41 +0530 Subject: drivers: staging: rtl8712: remove unnecessary else statement "else" statement after "if" is unnecessary, hence removed. Signed-off-by: Sunil Shahu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl871x_security.c | 35 ++++++++++++++---------------- 1 file changed, 16 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c index bcd1a5128868..21465c9c898f 100644 --- a/drivers/staging/rtl8712/rtl871x_security.c +++ b/drivers/staging/rtl8712/rtl871x_security.c @@ -124,28 +124,25 @@ static u8 crc32_reverseBit(u8 data) static void crc32_init(void) { + sint i, j; + u32 c = 0x12340000; + u8 *p = (u8 *)&c, *p1; + u8 k; + if (bcrc32initialized == 1) return; - else { - sint i, j; - u32 c; - u8 *p = (u8 *)&c, *p1; - u8 k; - - c = 0x12340000; - for (i = 0; i < 256; ++i) { - k = crc32_reverseBit((u8)i); - for (c = ((u32)k) << 24, j = 8; j > 0; --j) - c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : - (c << 1); - p1 = (u8 *)&crc32_table[i]; - p1[0] = crc32_reverseBit(p[3]); - p1[1] = crc32_reverseBit(p[2]); - p1[2] = crc32_reverseBit(p[1]); - p1[3] = crc32_reverseBit(p[0]); - } - bcrc32initialized = 1; + + for (i = 0; i < 256; ++i) { + k = crc32_reverseBit((u8)i); + for (c = ((u32)k) << 24, j = 8; j > 0; --j) + c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1); + p1 = (u8 *)&crc32_table[i]; + p1[0] = crc32_reverseBit(p[3]); + p1[1] = crc32_reverseBit(p[2]); + p1[2] = crc32_reverseBit(p[1]); + p1[3] = crc32_reverseBit(p[0]); } + bcrc32initialized = 1; } static u32 getcrc32(u8 *buf, u32 len) -- cgit v1.3-6-gb490 From a732152c76ee194274299905c700125bef1fc0c8 Mon Sep 17 00:00:00 2001 From: Sunil Shahu Date: Fri, 26 Jun 2015 19:42:24 +0530 Subject: staging: rtl8712: rtl871x_security.c: remove unnecessary variable initialization Variable "u32 c" always re-initialize in for loop. Initialized value of "u32 c" is not used in function and is redundant, hence removed. Suggested-by: Dan Carpenter Signed-off-by: Sunil Shahu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl871x_security.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c index 21465c9c898f..862792826dc5 100644 --- a/drivers/staging/rtl8712/rtl871x_security.c +++ b/drivers/staging/rtl8712/rtl871x_security.c @@ -125,7 +125,7 @@ static u8 crc32_reverseBit(u8 data) static void crc32_init(void) { sint i, j; - u32 c = 0x12340000; + u32 c; u8 *p = (u8 *)&c, *p1; u8 k; -- cgit v1.3-6-gb490 From 5eafbb0c529c5765fcfd57cb073982ad1cd06cc7 Mon Sep 17 00:00:00 2001 From: Ravi Teja Darbha Date: Tue, 30 Jun 2015 02:18:56 +0530 Subject: rtl8712:Fix checkpatch warning Fix line over 80 characters warning. Signed-off-by: Ravi Teja Darbha Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl8712_recv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c index fcb8c61b2884..4fa2540a6c34 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.c +++ b/drivers/staging/rtl8712/rtl8712_recv.c @@ -58,8 +58,8 @@ int r8712_init_recv_priv(struct recv_priv *precvpriv, struct _adapter *padapter) /*init recv_buf*/ _init_queue(&precvpriv->free_recv_buf_queue); - precvpriv->pallocated_recv_buf = kzalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4, - GFP_ATOMIC); + precvpriv->pallocated_recv_buf = + kzalloc(NR_RECVBUFF * sizeof(struct recv_buf) + 4, GFP_ATOMIC); if (precvpriv->pallocated_recv_buf == NULL) return _FAIL; precvpriv->precv_buf = precvpriv->pallocated_recv_buf + 4 - -- cgit v1.3-6-gb490 From d5a3a945fdf2584f3191e8cc958234057ef691da Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Thu, 9 Jul 2015 06:05:09 +0000 Subject: staging: xgifb: prefer using the BIT macro This patch uses the BIT macro for bit shift operation. Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Greg Kroah-Hartman --- drivers/staging/xgifb/XGI_main_26.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c index 943d463cf193..5bfe151ea328 100644 --- a/drivers/staging/xgifb/XGI_main_26.c +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -18,8 +18,8 @@ #define Index_CR_GPIO_Reg1 0x48 #define Index_CR_GPIO_Reg3 0x4a -#define GPIOG_EN (1<<6) -#define GPIOG_READ (1<<1) +#define GPIOG_EN BIT(6) +#define GPIOG_READ BIT(1) static char *forcecrt2type; static char *mode; -- cgit v1.3-6-gb490 From fb44d9a507305ab05945d8a781a0a1255a3d9868 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Tue, 14 Jul 2015 00:44:09 +0200 Subject: staging/xgifb: Move register helper functions to header and mark them as static inline. This shrinks the compiled module from 137442 to 117732 bytes and we also get rid of vb_util.c Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/staging/xgifb/Makefile | 2 +- drivers/staging/xgifb/vb_util.c | 42 --------------------------------------- drivers/staging/xgifb/vb_util.h | 44 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 40 insertions(+), 48 deletions(-) delete mode 100644 drivers/staging/xgifb/vb_util.c (limited to 'drivers') diff --git a/drivers/staging/xgifb/Makefile b/drivers/staging/xgifb/Makefile index 55e519905346..964a843c4521 100644 --- a/drivers/staging/xgifb/Makefile +++ b/drivers/staging/xgifb/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_FB_XGI) += xgifb.o -xgifb-y := XGI_main_26.o vb_init.o vb_setmode.o vb_util.o +xgifb-y := XGI_main_26.o vb_init.o vb_setmode.o diff --git a/drivers/staging/xgifb/vb_util.c b/drivers/staging/xgifb/vb_util.c deleted file mode 100644 index be3437ca339e..000000000000 --- a/drivers/staging/xgifb/vb_util.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "vgatypes.h" -#include "vb_util.h" - -void xgifb_reg_set(unsigned long port, u8 index, u8 data) -{ - outb(index, port); - outb(data, port + 1); -} - -u8 xgifb_reg_get(unsigned long port, u8 index) -{ - outb(index, port); - return inb(port + 1); -} - -void xgifb_reg_and_or(unsigned long port, u8 index, - unsigned data_and, unsigned data_or) -{ - u8 temp; - - temp = xgifb_reg_get(port, index); /* XGINew_Part1Port index 02 */ - temp = (temp & data_and) | data_or; - xgifb_reg_set(port, index, temp); -} - -void xgifb_reg_and(unsigned long port, u8 index, unsigned data_and) -{ - u8 temp; - - temp = xgifb_reg_get(port, index); /* XGINew_Part1Port index 02 */ - temp &= data_and; - xgifb_reg_set(port, index, temp); -} - -void xgifb_reg_or(unsigned long port, u8 index, unsigned data_or) -{ - u8 temp; - - temp = xgifb_reg_get(port, index); /* XGINew_Part1Port index 02 */ - temp |= data_or; - xgifb_reg_set(port, index, temp); -} diff --git a/drivers/staging/xgifb/vb_util.h b/drivers/staging/xgifb/vb_util.h index 9161de1d37dd..7bd395fb31b2 100644 --- a/drivers/staging/xgifb/vb_util.h +++ b/drivers/staging/xgifb/vb_util.h @@ -1,9 +1,43 @@ #ifndef _VBUTIL_ #define _VBUTIL_ -extern void xgifb_reg_set(unsigned long, u8, u8); -extern u8 xgifb_reg_get(unsigned long, u8); -extern void xgifb_reg_or(unsigned long, u8, unsigned); -extern void xgifb_reg_and(unsigned long, u8, unsigned); -extern void xgifb_reg_and_or(unsigned long, u8, unsigned, unsigned); +static inline void xgifb_reg_set(unsigned long port, u8 index, u8 data) +{ + outb(index, port); + outb(data, port + 1); +} + +static inline u8 xgifb_reg_get(unsigned long port, u8 index) +{ + outb(index, port); + return inb(port + 1); +} + +static inline void xgifb_reg_and_or(unsigned long port, u8 index, + unsigned data_and, unsigned data_or) +{ + u8 temp; + + temp = xgifb_reg_get(port, index); + temp = (temp & data_and) | data_or; + xgifb_reg_set(port, index, temp); +} + +static inline void xgifb_reg_and(unsigned long port, u8 index, unsigned data_and) +{ + u8 temp; + + temp = xgifb_reg_get(port, index); + temp &= data_and; + xgifb_reg_set(port, index, temp); +} + +static inline void xgifb_reg_or(unsigned long port, u8 index, unsigned data_or) +{ + u8 temp; + + temp = xgifb_reg_get(port, index); + temp |= data_or; + xgifb_reg_set(port, index, temp); +} #endif -- cgit v1.3-6-gb490 From 4f920c1f1778193338925ee3665844e08b4a6997 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 23 Jun 2015 22:52:39 +0800 Subject: staging: mt29f_spinand: Remove redundant spi driver bus initialization In ancient times it was necessary to manually initialize the bus field of an spi_driver to spi_bus_type. These days this is done in spi_register_driver(), so we can drop the manual assignment. Signed-off-by: Antonio Borneo To: Greg Kroah-Hartman To: devel@driverdev.osuosl.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/mt29f_spinand/mt29f_spinand.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c index 7285c64bac24..ad30ce4206ef 100644 --- a/drivers/staging/mt29f_spinand/mt29f_spinand.c +++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c @@ -948,7 +948,6 @@ static const struct of_device_id spinand_dt[] = { static struct spi_driver spinand_driver = { .driver = { .name = "mt29f", - .bus = &spi_bus_type, .owner = THIS_MODULE, .of_match_table = spinand_dt, }, -- cgit v1.3-6-gb490 From 304e08845126d949eacb2d95a5d15d4d022d555b Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Thu, 25 Jun 2015 14:56:13 +0200 Subject: staging: speakup: fix indentation Signed-off-by: Luis de Bethencourt Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/keyhelp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/speakup/keyhelp.c b/drivers/staging/speakup/keyhelp.c index 94756742136f..02d5c706aee7 100644 --- a/drivers/staging/speakup/keyhelp.c +++ b/drivers/staging/speakup/keyhelp.c @@ -165,7 +165,7 @@ int spk_handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key) synth_printf("\n"); return 1; } - cur_item = letter_offsets[ch-'a']; + cur_item = letter_offsets[ch-'a']; } else if (type == KT_CUR) { if (ch == 0 && (MSG_FUNCNAMES_START + cur_item + 1) <= -- cgit v1.3-6-gb490 From d6cb68d51e7123a66c78ec4c48b2686509f290b6 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 7 Jul 2015 13:44:33 +0530 Subject: staging: sm7xxfb: remove unused macros These macros were only defined but not used anywhere. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm7xxfb/sm7xx.h | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm7xxfb/sm7xx.h b/drivers/staging/sm7xxfb/sm7xx.h index 4bed0946c1b1..31a21bd85dae 100644 --- a/drivers/staging/sm7xxfb/sm7xx.h +++ b/drivers/staging/sm7xxfb/sm7xx.h @@ -13,8 +13,6 @@ * more details. */ -#define NR_PALETTE 256 - #define FB_ACCEL_SMI_LYNX 88 #define SCREEN_X_RES 1024 @@ -31,12 +29,8 @@ extern void __iomem *smtc_regbaseaddress; #define smtc_mmiowb(dat, reg) writeb(dat, smtc_regbaseaddress + reg) -#define smtc_mmioww(dat, reg) writew(dat, smtc_regbaseaddress + reg) -#define smtc_mmiowl(dat, reg) writel(dat, smtc_regbaseaddress + reg) #define smtc_mmiorb(reg) readb(smtc_regbaseaddress + reg) -#define smtc_mmiorw(reg) readw(smtc_regbaseaddress + reg) -#define smtc_mmiorl(reg) readl(smtc_regbaseaddress + reg) #define SIZE_SR00_SR04 (0x04 - 0x00 + 1) #define SIZE_SR10_SR24 (0x24 - 0x10 + 1) @@ -48,8 +42,6 @@ extern void __iomem *smtc_regbaseaddress; #define SIZE_CR00_CR18 (0x18 - 0x00 + 1) #define SIZE_CR30_CR4D (0x4D - 0x30 + 1) #define SIZE_CR90_CRA7 (0xA7 - 0x90 + 1) -#define SIZE_VPR (0x6C + 1) -#define SIZE_DPR (0x44 + 1) static inline void smtc_crtcw(int reg, int val) { @@ -57,24 +49,12 @@ static inline void smtc_crtcw(int reg, int val) smtc_mmiowb(val, 0x3d5); } -static inline unsigned int smtc_crtcr(int reg) -{ - smtc_mmiowb(reg, 0x3d4); - return smtc_mmiorb(0x3d5); -} - static inline void smtc_grphw(int reg, int val) { smtc_mmiowb(reg, 0x3ce); smtc_mmiowb(val, 0x3cf); } -static inline unsigned int smtc_grphr(int reg) -{ - smtc_mmiowb(reg, 0x3ce); - return smtc_mmiorb(0x3cf); -} - static inline void smtc_attrw(int reg, int val) { smtc_mmiorb(0x3da); -- cgit v1.3-6-gb490 From 4a012d30508ed09063e35eeee95e34ecc8534716 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 7 Jul 2015 13:44:34 +0530 Subject: staging: sm7xxfb: fix error handling We were checking smtc_regbaseaddress and that too at a place where it can never be NULL. Real check should be on sfb->lfb immediately after we do ioremap. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm7xxfb/sm7xxfb.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c index 2ff4fe73d148..8fb62af8f97d 100644 --- a/drivers/staging/sm7xxfb/sm7xxfb.c +++ b/drivers/staging/sm7xxfb/sm7xxfb.c @@ -1456,6 +1456,14 @@ static int smtcfb_pci_probe(struct pci_dev *pdev, #else sfb->lfb = ioremap(mmio_base, 0x00800000); #endif + if (!sfb->lfb) { + dev_err(&pdev->dev, + "%s: unable to map memory mapped IO!\n", + sfb->fb->fix.id); + err = -ENOMEM; + goto failed_fb; + } + sfb->mmio = (smtc_regbaseaddress = sfb->lfb + 0x00700000); sfb->dp_regs = sfb->lfb + 0x00408000; @@ -1466,13 +1474,6 @@ static int smtcfb_pci_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb); } #endif - if (!smtc_regbaseaddress) { - dev_err(&pdev->dev, - "%s: unable to map memory mapped IO!\n", - sfb->fb->fix.id); - err = -ENOMEM; - goto failed_fb; - } /* set MCLK = 14.31818 * (0x16 / 0x2) */ smtc_seqw(0x6a, 0x16); -- cgit v1.3-6-gb490 From eb90d44de7e6c7498a21e8de2935123395bbc31b Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 7 Jul 2015 13:44:35 +0530 Subject: staging: sm7xxfb: use kernel commandline We were only using the kernel commandline to set the mode if this driver is builtin, but when it is built as a module we were not having any way to set the mode. Start using commandline even if it is built as a module. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm7xxfb/sm7xxfb.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c index 8fb62af8f97d..4dc9d5f32517 100644 --- a/drivers/staging/sm7xxfb/sm7xxfb.c +++ b/drivers/staging/sm7xxfb/sm7xxfb.c @@ -1660,14 +1660,12 @@ static struct pci_driver smtcfb_driver = { static int __init sm712fb_init(void) { -#ifndef MODULE char *option = NULL; if (fb_get_options("sm712fb", &option)) return -ENODEV; if (option && *option) mode_option = option; -#endif sm7xx_vga_setup(mode_option); return pci_register_driver(&smtcfb_driver); -- cgit v1.3-6-gb490 From 027d3efd933d87ca3d9a28365cae795c14e7a563 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Fri, 26 Jun 2015 07:50:34 +0200 Subject: staging: rtl8188eu: don't duplicate ieee80211 WLAN_CAPABILITY_* constants linux/ieee80211.h already defines constants for capability bits. Include it where needed, resolve discrepancies in naming, and remove the duplicated definitions. Also, make use of WLAN_CAPABILITY_IS_STA_BSS() macro to check if neither ESS nor IBSS capability bits are set. Signed-off-by: Jakub Sitnicki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_ap.c | 2 +- drivers/staging/rtl8188eu/core/rtw_ieee80211.c | 2 ++ drivers/staging/rtl8188eu/core/rtw_mlme.c | 5 +++-- drivers/staging/rtl8188eu/core/rtw_wlan_util.c | 2 ++ drivers/staging/rtl8188eu/include/ieee80211.h | 10 ---------- drivers/staging/rtl8188eu/os_dep/ioctl_linux.c | 4 ++-- 6 files changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c index 581af88e3024..9d484cf81184 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ap.c +++ b/drivers/staging/rtl8188eu/core/rtw_ap.c @@ -1584,7 +1584,7 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) } } - if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT)) { + if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)) { if (!psta->no_short_slot_time_set) { psta->no_short_slot_time_set = 1; diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c index 11b780d6c4ab..d43e8672d86e 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c @@ -19,6 +19,8 @@ ******************************************************************************/ #define _IEEE80211_C +#include + #include #include #include diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index 05584515c5b4..a1ed741fc804 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -19,6 +19,7 @@ ******************************************************************************/ #define _RTW_MLME_C_ +#include #include #include @@ -352,8 +353,8 @@ int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst) ((!memcmp(src->Ssid.Ssid, dst->Ssid.Ssid, src->Ssid.SsidLength)) == true) && ((s_cap & WLAN_CAPABILITY_IBSS) == (d_cap & WLAN_CAPABILITY_IBSS)) && - ((s_cap & WLAN_CAPABILITY_BSS) == - (d_cap & WLAN_CAPABILITY_BSS))); + ((s_cap & WLAN_CAPABILITY_ESS) == + (d_cap & WLAN_CAPABILITY_ESS))); } struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue) diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c index 32300df7b996..077b39a41c60 100644 --- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c @@ -19,6 +19,8 @@ ******************************************************************************/ #define _RTW_WLAN_UTIL_C_ +#include + #include #include #include diff --git a/drivers/staging/rtl8188eu/include/ieee80211.h b/drivers/staging/rtl8188eu/include/ieee80211.h index b129ad148b47..fabb95917e8b 100644 --- a/drivers/staging/rtl8188eu/include/ieee80211.h +++ b/drivers/staging/rtl8188eu/include/ieee80211.h @@ -483,16 +483,6 @@ struct ieee80211_snap_hdr { #define WLAN_AUTH_CHALLENGE_LEN 128 -#define WLAN_CAPABILITY_BSS (1<<0) -#define WLAN_CAPABILITY_IBSS (1<<1) -#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) -#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) -#define WLAN_CAPABILITY_PRIVACY (1<<4) -#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) -#define WLAN_CAPABILITY_PBCC (1<<6) -#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) -#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) - /* Non standard? Not in */ #define WLAN_REASON_EXPIRATION_CHK 65535 diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index 38dba1435c1e..ce756cdb817b 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -179,8 +179,8 @@ static char *translate_scan(struct adapter *padapter, cap = le16_to_cpu(le_tmp); - if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_BSS)) { - if (cap & WLAN_CAPABILITY_BSS) + if (!WLAN_CAPABILITY_IS_STA_BSS(cap)) { + if (cap & WLAN_CAPABILITY_ESS) iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; -- cgit v1.3-6-gb490 From 9e7e78d8298bd487f7a0d2b0c62033b3841d03ca Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Mon, 29 Jun 2015 12:57:35 +0000 Subject: staging:rtl8188eu: Code cleanup fix reported by coccinelle bool check modified Signed-off-by: Prasanna Karthik Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/hal/rf_cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/hal/rf_cfg.c b/drivers/staging/rtl8188eu/hal/rf_cfg.c index 455ecdc8d9fa..954cade478db 100644 --- a/drivers/staging/rtl8188eu/hal/rf_cfg.c +++ b/drivers/staging/rtl8188eu/hal/rf_cfg.c @@ -295,7 +295,7 @@ static bool rf6052_conf_para(struct adapter *adapt) break; } - if (rtstatus != true) + if (!rtstatus) return false; } -- cgit v1.3-6-gb490 From e1d0bcedfb6da518422472fcbab03999fc312ab1 Mon Sep 17 00:00:00 2001 From: Sunil Shahu Date: Tue, 7 Jul 2015 14:55:44 +0530 Subject: staging: rtl8188eu: core: rtw_mlme: remove space before ',' Fix coding style error by removing spaces before ',' as suggested by checkpatch.pl script. Signed-off-by: Sunil Shahu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_mlme.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index a1ed741fc804..2b599e3c0785 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -161,7 +161,7 @@ exit: return pnetwork; } -static void _rtw_free_network(struct mlme_priv *pmlmepriv , struct wlan_network *pnetwork, u8 isfreeall) +static void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork, u8 isfreeall) { u32 curr_time, delta_time; u32 lifetime = SCANQUEUE_LIFETIME; @@ -582,7 +582,7 @@ static int rtw_is_desired_network(struct adapter *adapter, struct wlan_network * } /* TODO: Perry: For Power Management */ -void rtw_atimdone_event_callback(struct adapter *adapter , u8 *pbuf) +void rtw_atimdone_event_callback(struct adapter *adapter, u8 *pbuf) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("receive atimdone_evet\n")); return; @@ -615,7 +615,7 @@ void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); ibss_wlan = rtw_find_network(&pmlmepriv->scanned_queue, pnetwork->MacAddress); if (ibss_wlan) { - memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8); + memcpy(ibss_wlan->network.IEs, pnetwork->IEs, 8); spin_unlock_bh(&pmlmepriv->scanned_queue.lock); goto exit; } @@ -1383,7 +1383,7 @@ void _rtw_join_timeout_handler (unsigned long data) DBG_88E("%s try another roaming\n", __func__); do_join_r = rtw_do_join(adapter); if (_SUCCESS != do_join_r) { - DBG_88E("%s roaming do_join return %d\n", __func__ , do_join_r); + DBG_88E("%s roaming do_join return %d\n", __func__, do_join_r); continue; } break; @@ -1998,7 +1998,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ p = rtw_get_ie(in_ie+12, _HT_ADD_INFO_IE_, &ielen, in_len-12); if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) { out_len = *pout_len; - rtw_set_ie(out_ie+out_len, _HT_ADD_INFO_IE_, ielen, p+2 , pout_len); + rtw_set_ie(out_ie+out_len, _HT_ADD_INFO_IE_, ielen, p+2, pout_len); } } return phtpriv->ht_option; -- cgit v1.3-6-gb490 From 249472588cf0b5fa18063783dd1d4f4a62c8ddb3 Mon Sep 17 00:00:00 2001 From: Sreenath Madasu Date: Wed, 8 Jul 2015 18:43:00 -0400 Subject: staging: rtl8188eu: core: Fixed 80 character length warning When the checkpatch.pl script was run, it showed lines with length more than 80 characters in rtw_ap.c file. Fixed line number 382 by breaking it up into two lines within 80 characters. Signed-off-by: Sreenath Madasu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_ap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c index 9d484cf81184..5c45f8a8c2cf 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ap.c +++ b/drivers/staging/rtl8188eu/core/rtw_ap.c @@ -379,7 +379,8 @@ void expire_timeout_chk(struct adapter *padapter) if (pmlmeext->active_keep_alive_check) { int stainfo_offset; - stainfo_offset = rtw_stainfo_offset(pstapriv, psta); + stainfo_offset = + rtw_stainfo_offset(pstapriv, psta); if (stainfo_offset_valid(stainfo_offset)) chk_alive_list[chk_alive_num++] = stainfo_offset; continue; -- cgit v1.3-6-gb490 From 3738408cc802025a1ecf4a059a0c8ab048cb7e72 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Fri, 10 Jul 2015 18:52:17 +0200 Subject: staging: rtl8188eu: remove RegulatorMode from struct hal_data_8188e This field is not used anywhere. Also, kill the rt_regulator_mode enum which exists just for this field. Signed-off-by: Jakub Sitnicki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c | 3 --- drivers/staging/rtl8188eu/include/rtl8188e_hal.h | 7 ------- 2 files changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c index 7904d2260f2c..f6c1591e66c3 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c @@ -144,9 +144,6 @@ static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter) ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC); ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK)>>CHIP_VER_RTL_SHIFT; /* IC version (CUT) */ - /* For regulator mode. by tynli. 2011.01.14 */ - pHalData->RegulatorMode = ((value32 & TRP_BT_EN) ? RT_LDO_REGULATOR : RT_SWITCHING_REGULATOR); - ChipVersion.ROMVer = 0; /* ROM code version. */ dump_chip_info(ChipVersion); diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h index 7d8e022925e0..5aa2adc1f013 100644 --- a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h +++ b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h @@ -188,15 +188,8 @@ struct txpowerinfo24g { #define EFUSE_PROTECT_BYTES_BANK 16 -/* For RTL8723 regulator mode. */ -enum rt_regulator_mode { - RT_SWITCHING_REGULATOR = 0, - RT_LDO_REGULATOR = 1, -}; - struct hal_data_8188e { struct HAL_VERSION VersionID; - enum rt_regulator_mode RegulatorMode; /* switching regulator or LDO */ u16 CustomerID; u8 *pfirmware; u32 fwsize; -- cgit v1.3-6-gb490 From e827aeedd0e14dcb67eb29afbaa875ab1a0f7b26 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Fri, 10 Jul 2015 18:52:18 +0200 Subject: staging: rtl8188eu: remove ICtype from struct HAL_VERSION IC type on RTL8188EU is always 8188E. Remove it and all the macros that check it. Signed-off-by: Jakub Sitnicki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/hal/hal_com.c | 13 +---- drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c | 1 - drivers/staging/rtl8188eu/hal/usb_halinit.c | 2 +- drivers/staging/rtl8188eu/include/HalVerDef.h | 61 ----------------------- 4 files changed, 2 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/hal/hal_com.c b/drivers/staging/rtl8188eu/hal/hal_com.c index 170e3de5eab4..62ffa7c73c89 100644 --- a/drivers/staging/rtl8188eu/hal/hal_com.c +++ b/drivers/staging/rtl8188eu/hal/hal_com.c @@ -31,18 +31,7 @@ void dump_chip_info(struct HAL_VERSION chip_vers) uint cnt = 0; char buf[128]; - if (IS_81XXC(chip_vers)) { - cnt += sprintf((buf+cnt), "Chip Version Info: %s_", - IS_92C_SERIAL(chip_vers) ? - "CHIP_8192C" : "CHIP_8188C"); - } else if (IS_92D(chip_vers)) { - cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8192D_"); - } else if (IS_8723_SERIES(chip_vers)) { - cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8723A_"); - } else if (IS_8188E(chip_vers)) { - cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8188E_"); - } - + cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8188E_"); cnt += sprintf((buf+cnt), "%s_", IS_NORMAL_CHIP(chip_vers) ? "Normal_Chip" : "Test_Chip"); cnt += sprintf((buf+cnt), "%s_", IS_CHIP_VENDOR_TSMC(chip_vers) ? diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c index f6c1591e66c3..af757ffd535f 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c @@ -137,7 +137,6 @@ static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter) pHalData = GET_HAL_DATA(padapter); value32 = usb_read32(padapter, REG_SYS_CFG); - ChipVersion.ICType = CHIP_8188E; ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP); ChipVersion.RFType = RF_TYPE_1T1R; diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c index 872622214264..ffcca6b03fe2 100644 --- a/drivers/staging/rtl8188eu/hal/usb_halinit.c +++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c @@ -1703,7 +1703,7 @@ static void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) /* Forece leave RF low power mode for 1T1R to prevent conficting setting in Fw power */ /* saving sequence. 2010.06.07. Added by tynli. Suggested by SD3 yschang. */ - if ((psmode != PS_MODE_ACTIVE) && (!IS_92C_SERIAL(haldata->VersionID))) + if (psmode != PS_MODE_ACTIVE) ODM_RF_Saving(podmpriv, true); rtl8188e_set_FwPwrMode_cmd(Adapter, psmode); } diff --git a/drivers/staging/rtl8188eu/include/HalVerDef.h b/drivers/staging/rtl8188eu/include/HalVerDef.h index 97047cf06780..c542f7e04f5b 100644 --- a/drivers/staging/rtl8188eu/include/HalVerDef.h +++ b/drivers/staging/rtl8188eu/include/HalVerDef.h @@ -20,20 +20,6 @@ #ifndef __HAL_VERSION_DEF_H__ #define __HAL_VERSION_DEF_H__ -enum HAL_IC_TYPE { - CHIP_8192S = 0, - CHIP_8188C = 1, - CHIP_8192C = 2, - CHIP_8192D = 3, - CHIP_8723A = 4, - CHIP_8188E = 5, - CHIP_8881A = 6, - CHIP_8812A = 7, - CHIP_8821A = 8, - CHIP_8723B = 9, - CHIP_8192E = 10, -}; - enum HAL_CHIP_TYPE { TEST_CHIP = 0, NORMAL_CHIP = 1, @@ -67,7 +53,6 @@ enum HAL_RF_TYPE { }; struct HAL_VERSION { - enum HAL_IC_TYPE ICType; enum HAL_CHIP_TYPE ChipType; enum HAL_CUT_VERSION CUTVersion; enum HAL_VENDOR VendorType; @@ -76,7 +61,6 @@ struct HAL_VERSION { }; /* Get element */ -#define GET_CVID_IC_TYPE(version) (((version).ICType)) #define GET_CVID_CHIP_TYPE(version) (((version).ChipType)) #define GET_CVID_RF_TYPE(version) (((version).RFType)) #define GET_CVID_MANUFACTUER(version) (((version).VendorType)) @@ -86,17 +70,6 @@ struct HAL_VERSION { /* Common Macro. -- */ /* HAL_VERSION VersionID */ -/* HAL_IC_TYPE_E */ -#define IS_81XXC(version) \ - (((GET_CVID_IC_TYPE(version) == CHIP_8192C) || \ - (GET_CVID_IC_TYPE(version) == CHIP_8188C)) ? true : false) -#define IS_8723_SERIES(version) \ - ((GET_CVID_IC_TYPE(version) == CHIP_8723A) ? true : false) -#define IS_92D(version) \ - ((GET_CVID_IC_TYPE(version) == CHIP_8192D) ? true : false) -#define IS_8188E(version) \ - ((GET_CVID_IC_TYPE(version) == CHIP_8188E) ? true : false) - /* HAL_CHIP_TYPE_E */ #define IS_TEST_CHIP(version) \ ((GET_CVID_CHIP_TYPE(version) == TEST_CHIP) ? true : false) @@ -130,38 +103,4 @@ struct HAL_VERSION { #define IS_2T2R(version) \ ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? true : false) -/* Chip version Macro. -- */ -#define IS_81XXC_TEST_CHIP(version) \ - ((IS_81XXC(version) && (!IS_NORMAL_CHIP(version))) ? true : false) - -#define IS_92C_SERIAL(version) \ - ((IS_81XXC(version) && IS_2T2R(version)) ? true : false) -#define IS_81xxC_VENDOR_UMC_A_CUT(version) \ - (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? \ - (IS_A_CUT(version) ? true : false) : false) : false) -#define IS_81xxC_VENDOR_UMC_B_CUT(version) \ - (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? \ - (IS_B_CUT(version) ? true : false) : false) : false) -#define IS_81xxC_VENDOR_UMC_C_CUT(version) \ - (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? \ - (IS_C_CUT(version) ? true : false) : false) : false) - -#define IS_NORMAL_CHIP92D(version) \ - ((IS_92D(version)) ? \ - ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? true : false) : false) - -#define IS_92D_SINGLEPHY(version) \ - ((IS_92D(version)) ? (IS_2T2R(version) ? true : false) : false) -#define IS_92D_C_CUT(version) \ - ((IS_92D(version)) ? (IS_C_CUT(version) ? true : false) : false) -#define IS_92D_D_CUT(version) \ - ((IS_92D(version)) ? (IS_D_CUT(version) ? true : false) : false) -#define IS_92D_E_CUT(version) \ - ((IS_92D(version)) ? (IS_E_CUT(version) ? true : false) : false) - -#define IS_8723A_A_CUT(version) \ - ((IS_8723_SERIES(version)) ? (IS_A_CUT(version) ? true : false) : false) -#define IS_8723A_B_CUT(version) \ - ((IS_8723_SERIES(version)) ? (IS_B_CUT(version) ? true : false) : false) - #endif -- cgit v1.3-6-gb490 From 3c71dd6c5609285b122a50ebc2d59ebafdac595f Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Fri, 10 Jul 2015 18:52:19 +0200 Subject: staging: rtl8188eu: remove RFtype from struct HAL_VERSION RFtype in struct HAL_VERSION duplicates rf_type in struct hal_data_8188e, and does not change. Remove it and the macros that test it. Signed-off-by: Jakub Sitnicki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/hal/hal_com.c | 12 +----------- drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c | 15 ++------------- drivers/staging/rtl8188eu/include/HalVerDef.h | 21 --------------------- 3 files changed, 3 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/hal/hal_com.c b/drivers/staging/rtl8188eu/hal/hal_com.c index 62ffa7c73c89..a296648a4dd1 100644 --- a/drivers/staging/rtl8188eu/hal/hal_com.c +++ b/drivers/staging/rtl8188eu/hal/hal_com.c @@ -49,17 +49,7 @@ void dump_chip_info(struct HAL_VERSION chip_vers) else cnt += sprintf((buf+cnt), "UNKNOWN_CUT(%d)_", chip_vers.CUTVersion); - - if (IS_1T1R(chip_vers)) - cnt += sprintf((buf+cnt), "1T1R_"); - else if (IS_1T2R(chip_vers)) - cnt += sprintf((buf+cnt), "1T2R_"); - else if (IS_2T2R(chip_vers)) - cnt += sprintf((buf+cnt), "2T2R_"); - else - cnt += sprintf((buf+cnt), "UNKNOWN_RFTYPE(%d)_", - chip_vers.RFType); - + cnt += sprintf((buf+cnt), "1T1R_"); cnt += sprintf((buf+cnt), "RomVer(%d)\n", chip_vers.ROMVer); pr_info("%s", buf); diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c index af757ffd535f..ea9703095196 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c @@ -138,8 +138,6 @@ static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter) value32 = usb_read32(padapter, REG_SYS_CFG); ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP); - - ChipVersion.RFType = RF_TYPE_1T1R; ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC); ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK)>>CHIP_VER_RTL_SHIFT; /* IC version (CUT) */ @@ -148,17 +146,8 @@ static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter) dump_chip_info(ChipVersion); pHalData->VersionID = ChipVersion; - - if (IS_1T2R(ChipVersion)) { - pHalData->rf_type = RF_1T2R; - pHalData->NumTotalRFPath = 2; - } else if (IS_2T2R(ChipVersion)) { - pHalData->rf_type = RF_2T2R; - pHalData->NumTotalRFPath = 2; - } else{ - pHalData->rf_type = RF_1T1R; - pHalData->NumTotalRFPath = 1; - } + pHalData->rf_type = RF_1T1R; + pHalData->NumTotalRFPath = 1; MSG_88E("RF_Type is %x!!\n", pHalData->rf_type); diff --git a/drivers/staging/rtl8188eu/include/HalVerDef.h b/drivers/staging/rtl8188eu/include/HalVerDef.h index c542f7e04f5b..2c24814d9793 100644 --- a/drivers/staging/rtl8188eu/include/HalVerDef.h +++ b/drivers/staging/rtl8188eu/include/HalVerDef.h @@ -41,28 +41,15 @@ enum HAL_VENDOR { CHIP_VENDOR_UMC = 1, }; -enum HAL_RF_TYPE { - RF_TYPE_1T1R = 0, - RF_TYPE_1T2R = 1, - RF_TYPE_2T2R = 2, - RF_TYPE_2T3R = 3, - RF_TYPE_2T4R = 4, - RF_TYPE_3T3R = 5, - RF_TYPE_3T4R = 6, - RF_TYPE_4T4R = 7, -}; - struct HAL_VERSION { enum HAL_CHIP_TYPE ChipType; enum HAL_CUT_VERSION CUTVersion; enum HAL_VENDOR VendorType; - enum HAL_RF_TYPE RFType; u8 ROMVer; }; /* Get element */ #define GET_CVID_CHIP_TYPE(version) (((version).ChipType)) -#define GET_CVID_RF_TYPE(version) (((version).RFType)) #define GET_CVID_MANUFACTUER(version) (((version).VendorType)) #define GET_CVID_CUT_VERSION(version) (((version).CUTVersion)) #define GET_CVID_ROM_VERSION(version) (((version).ROMVer) & ROM_VERSION_MASK) @@ -95,12 +82,4 @@ struct HAL_VERSION { #define IS_CHIP_VENDOR_UMC(version) \ ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC) ? true : false) -/* HAL_RF_TYPE_E */ -#define IS_1T1R(version) \ - ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R) ? true : false) -#define IS_1T2R(version) \ - ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R) ? true : false) -#define IS_2T2R(version) \ - ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? true : false) - #endif -- cgit v1.3-6-gb490 From a51d13037b1e5149bcbe65cc5a47af1d35affdaa Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Fri, 10 Jul 2015 18:52:20 +0200 Subject: staging: rtl8188eu: remove ROMVer from struct HAL_VERSION ROM version on RTL8188EU is always 0. Signed-off-by: Jakub Sitnicki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/hal/hal_com.c | 2 +- drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c | 2 -- drivers/staging/rtl8188eu/include/HalVerDef.h | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/hal/hal_com.c b/drivers/staging/rtl8188eu/hal/hal_com.c index a296648a4dd1..38e9fdc312d3 100644 --- a/drivers/staging/rtl8188eu/hal/hal_com.c +++ b/drivers/staging/rtl8188eu/hal/hal_com.c @@ -50,7 +50,7 @@ void dump_chip_info(struct HAL_VERSION chip_vers) cnt += sprintf((buf+cnt), "UNKNOWN_CUT(%d)_", chip_vers.CUTVersion); cnt += sprintf((buf+cnt), "1T1R_"); - cnt += sprintf((buf+cnt), "RomVer(%d)\n", chip_vers.ROMVer); + cnt += sprintf((buf+cnt), "RomVer(0)\n"); pr_info("%s", buf); } diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c index ea9703095196..49b6b9cdf778 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c @@ -141,8 +141,6 @@ static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter) ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC); ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK)>>CHIP_VER_RTL_SHIFT; /* IC version (CUT) */ - ChipVersion.ROMVer = 0; /* ROM code version. */ - dump_chip_info(ChipVersion); pHalData->VersionID = ChipVersion; diff --git a/drivers/staging/rtl8188eu/include/HalVerDef.h b/drivers/staging/rtl8188eu/include/HalVerDef.h index 2c24814d9793..56b4ff08e509 100644 --- a/drivers/staging/rtl8188eu/include/HalVerDef.h +++ b/drivers/staging/rtl8188eu/include/HalVerDef.h @@ -45,14 +45,12 @@ struct HAL_VERSION { enum HAL_CHIP_TYPE ChipType; enum HAL_CUT_VERSION CUTVersion; enum HAL_VENDOR VendorType; - u8 ROMVer; }; /* Get element */ #define GET_CVID_CHIP_TYPE(version) (((version).ChipType)) #define GET_CVID_MANUFACTUER(version) (((version).VendorType)) #define GET_CVID_CUT_VERSION(version) (((version).CUTVersion)) -#define GET_CVID_ROM_VERSION(version) (((version).ROMVer) & ROM_VERSION_MASK) /* Common Macro. -- */ /* HAL_VERSION VersionID */ -- cgit v1.3-6-gb490 From 4221844a627aaebf28732d6e891de2aa4db38aa0 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Fri, 10 Jul 2015 18:52:21 +0200 Subject: staging: rtl8188eu: fold rtl8188e_read_chip_version() into rtl8188e_SetHalODMVar() Both rtl8188e_read_chip_version() and ReadChipVersion8188E() are used only in one place. Make ReadChipVersion8188E() a void function and eliminate its wrapper - rtl8188e_read_chip_version(). Signed-off-by: Jakub Sitnicki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c index 49b6b9cdf778..b05da9d6b693 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c @@ -128,7 +128,7 @@ static void rtl8188e_free_hal_data(struct adapter *padapter) padapter->HalData = NULL; } -static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter) +static void ReadChipVersion8188E(struct adapter *padapter) { u32 value32; struct HAL_VERSION ChipVersion; @@ -148,13 +148,6 @@ static struct HAL_VERSION ReadChipVersion8188E(struct adapter *padapter) pHalData->NumTotalRFPath = 1; MSG_88E("RF_Type is %x!!\n", pHalData->rf_type); - - return ChipVersion; -} - -static void rtl8188e_read_chip_version(struct adapter *padapter) -{ - ReadChipVersion8188E(padapter); } static void rtl8188e_SetHalODMVar(struct adapter *Adapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet) @@ -203,7 +196,7 @@ void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc) pHalFunc->dm_init = &rtl8188e_init_dm_priv; - pHalFunc->read_chip_version = &rtl8188e_read_chip_version; + pHalFunc->read_chip_version = &ReadChipVersion8188E; pHalFunc->set_bwmode_handler = &phy_set_bw_mode; pHalFunc->set_channel_handler = &phy_sw_chnl; -- cgit v1.3-6-gb490 From 9fccffbfd9505116c0ab847742aafaa7da55d413 Mon Sep 17 00:00:00 2001 From: Johannes Postma Date: Wed, 8 Jul 2015 13:41:46 +0100 Subject: Staging: ozwpan: ozusbsvc1.c: Fix missing blank line after declarations This patch fixes a missing line after declarations issue. Signed-off-by: Johannes Postma Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ozwpan/ozusbsvc1.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/ozwpan/ozusbsvc1.c b/drivers/staging/ozwpan/ozusbsvc1.c index 301fee8625ed..b6cfecbeabf7 100644 --- a/drivers/staging/ozwpan/ozusbsvc1.c +++ b/drivers/staging/ozwpan/ozusbsvc1.c @@ -327,6 +327,7 @@ static void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx, (struct oz_multiple_fixed *)data_hdr; u8 *data = body->data; unsigned int n; + if (!body->unit_size || len < sizeof(struct oz_multiple_fixed) - 1) break; -- cgit v1.3-6-gb490 From 364b91be262aaf0afc1726be391fbeb7f2b59c52 Mon Sep 17 00:00:00 2001 From: Leung Timothy Chi King Date: Wed, 1 Jul 2015 09:44:13 -0700 Subject: Staging: rts5208: Fix checkpatch warning: else is not generally useful The following checkpatch warning was fixed: WARNING: else is not generally useful after a break or return Signed-off-by: Leung Timothy Chi King Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rts5208/sd.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rts5208/sd.c b/drivers/staging/rts5208/sd.c index a8d657bb5c1b..cb4157960fad 100644 --- a/drivers/staging/rts5208/sd.c +++ b/drivers/staging/rts5208/sd.c @@ -3520,12 +3520,11 @@ int reset_sd_card(struct rtsx_chip *chip) if (chip->sd_io) { rtsx_trace(chip); return STATUS_FAIL; - } else { - retval = reset_mmc(chip); - if (retval != STATUS_SUCCESS) { - rtsx_trace(chip); - return STATUS_FAIL; - } + } + retval = reset_mmc(chip); + if (retval != STATUS_SUCCESS) { + rtsx_trace(chip); + return STATUS_FAIL; } } } -- cgit v1.3-6-gb490 From 861e82d5b5a42d2eda34f3123b46162eaae9af80 Mon Sep 17 00:00:00 2001 From: Jacob Kiefer Date: Fri, 10 Jul 2015 01:26:30 -0400 Subject: staging: style fix for octeon/ethernet-tx.c Broke line with greater than 80 characters into two lines and improved logical operator readability in hardware checksum if statement. Signed-off-by: Jacob Kiefer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/octeon/ethernet-tx.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index 7c1c1b052b7d..e2df041ca82d 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -396,10 +396,12 @@ dont_put_skbuff_in_hw: /* Check if we can use the hardware checksumming */ if ((skb->protocol == htons(ETH_P_IP)) && - (ip_hdr(skb)->version == 4) && (ip_hdr(skb)->ihl == 5) && - ((ip_hdr(skb)->frag_off == 0) || (ip_hdr(skb)->frag_off == htons(1 << 14))) - && ((ip_hdr(skb)->protocol == IPPROTO_TCP) - || (ip_hdr(skb)->protocol == IPPROTO_UDP))) { + (ip_hdr(skb)->version == 4) && + (ip_hdr(skb)->ihl == 5) && + ((ip_hdr(skb)->frag_off == 0) || + (ip_hdr(skb)->frag_off == htons(1 << 14))) && + ((ip_hdr(skb)->protocol == IPPROTO_TCP) || + (ip_hdr(skb)->protocol == IPPROTO_UDP))) { /* Use hardware checksum calc */ pko_command.s.ipoffp1 = sizeof(struct ethhdr) + 1; } -- cgit v1.3-6-gb490 From bd1fb5388da0a37c053649ec4aa8e588ef39f958 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:34:28 +0900 Subject: staging: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c index 0f524bb7b41d..1f9ba8beb061 100644 --- a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c +++ b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c @@ -1126,7 +1126,6 @@ MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table); static struct i2c_driver synaptics_rmi4_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .pm = &synaptics_rmi4_dev_pm_ops, }, .probe = synaptics_rmi4_probe, -- cgit v1.3-6-gb490 From fff905f32966109d513ae17afc6fe39f1c76bb67 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Tue, 30 Jun 2015 09:16:41 +0800 Subject: PCI: Move PCI_FIND_CAP_TTL to pci.h and use it in quirks Some quirks search for a HyperTransport capability and use a hard-coded TTL value of 48 to avoid an infinite loop. Move the definition of PCI_FIND_CAP_TTL to pci.h and use it instead of the hard-coded TTL values. [bhelgaas: changelog] Signed-off-by: Wei Yang Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 1 - drivers/pci/pci.h | 2 ++ drivers/pci/quirks.c | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0008c950452c..66bd80e7ec12 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -140,7 +140,6 @@ void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar) EXPORT_SYMBOL_GPL(pci_ioremap_bar); #endif -#define PCI_FIND_CAP_TTL 48 static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap, int *ttl) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 4ff0ff1c4088..24ba9dc8910a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -4,6 +4,8 @@ #define PCI_CFG_SPACE_SIZE 256 #define PCI_CFG_SPACE_EXP_SIZE 4096 +#define PCI_FIND_CAP_TTL 48 + extern const unsigned char pcie_link_speed[]; bool pcie_cap_has_lnkctl(const struct pci_dev *dev); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 32cc9c802b47..683393710bef 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2247,7 +2247,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x9601, quirk_amd_780_apc_msi); * return 1 if a HT MSI capability is found and enabled */ static int msi_ht_cap_enabled(struct pci_dev *dev) { - int pos, ttl = 48; + int pos, ttl = PCI_FIND_CAP_TTL; pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); while (pos && ttl--) { @@ -2306,7 +2306,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, /* Force enable MSI mapping capability on HT bridges */ static void ht_enable_msi_mapping(struct pci_dev *dev) { - int pos, ttl = 48; + int pos, ttl = PCI_FIND_CAP_TTL; pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); while (pos && ttl--) { @@ -2385,7 +2385,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, static int ht_check_msi_mapping(struct pci_dev *dev) { - int pos, ttl = 48; + int pos, ttl = PCI_FIND_CAP_TTL; int found = 0; /* check if there is HT MSI cap or enabled on this device */ @@ -2510,7 +2510,7 @@ out: static void ht_disable_msi_mapping(struct pci_dev *dev) { - int pos, ttl = 48; + int pos, ttl = PCI_FIND_CAP_TTL; pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); while (pos && ttl--) { -- cgit v1.3-6-gb490 From 0a1a9b49427f13b6e12366eb8f06b8094ab61447 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Tue, 30 Jun 2015 09:16:44 +0800 Subject: PCI: Simplify pci_find_(ext_)capability() return value checks The return value of the pci_find_(ext_)capability() is either zero or the position of a capability. It is never negative. This patch consolidates the form of check from (pos <= 0) to (!pos). Signed-off-by: Wei Yang Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 66bd80e7ec12..29b560591d54 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -971,7 +971,7 @@ static int pci_save_pcix_state(struct pci_dev *dev) struct pci_cap_saved_state *save_state; pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); - if (pos <= 0) + if (!pos) return 0; save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX); @@ -994,7 +994,7 @@ static void pci_restore_pcix_state(struct pci_dev *dev) save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX); pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); - if (!save_state || pos <= 0) + if (!save_state || !pos) return; cap = (u16 *)&save_state->cap.data[0]; @@ -2158,7 +2158,7 @@ static int _pci_add_cap_save_buffer(struct pci_dev *dev, u16 cap, else pos = pci_find_capability(dev, cap); - if (pos <= 0) + if (!pos) return 0; save_state = kzalloc(sizeof(*save_state) + size, GFP_KERNEL); -- cgit v1.3-6-gb490 From aaed816fde8501ed86bb62c4d7f7b137969afc7e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 14 Jul 2015 16:41:19 -0500 Subject: PCI: Remove useless redundant code Remove redundant code from __pci_bus_find_cap_start(). No functional change. Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 29b560591d54..359b954670e6 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -195,8 +195,6 @@ static int __pci_bus_find_cap_start(struct pci_bus *bus, return PCI_CAPABILITY_LIST; case PCI_HEADER_TYPE_CARDBUS: return PCI_CB_CAPABILITY_LIST; - default: - return 0; } return 0; -- cgit v1.3-6-gb490 From 46fd96251f66421b178b4ff7f0b26b2e4cb94092 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Wed, 1 Jul 2015 17:37:10 +0300 Subject: PCI: Remove a broken link in quirks.c Remove a broken link in drivers/pci/quirks.c. Signed-off-by: Rami Rosen Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 683393710bef..96b354814cb7 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -163,7 +163,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quirk_ * VIA Apollo KT133 needs PCI latency patch * Made according to a windows driver based patch by George E. Breese * see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm - * and http://www.georgebreese.com/net/software/#PCI * Also see http://www.au-ja.org/review-kt133a-1-en.phtml for * the info on which Mr Breese based his work. * -- cgit v1.3-6-gb490 From 04ed5f3d4ea9981e31219fc2514b5505445dd92c Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:04 +0200 Subject: staging: rtl8192e: Remove ToLegalChannel() Function is not used. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/dot11d.c | 24 ------------------------ drivers/staging/rtl8192e/dot11d.h | 1 - 2 files changed, 25 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/dot11d.c b/drivers/staging/rtl8192e/dot11d.c index ef9da863c335..7f48845e7125 100644 --- a/drivers/staging/rtl8192e/dot11d.c +++ b/drivers/staging/rtl8192e/dot11d.c @@ -190,27 +190,3 @@ void DOT11D_ScanComplete(struct rtllib_device *dev) break; } } - -int ToLegalChannel(struct rtllib_device *dev, u8 channel) -{ - struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev); - u8 default_chn = 0; - u32 i; - - for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) { - if (pDot11dInfo->channel_map[i] > 0) { - default_chn = i; - break; - } - } - - if (MAX_CHANNEL_NUMBER < channel) { - netdev_err(dev->dev, "%s(): Invalid Channel\n", __func__); - return default_chn; - } - - if (pDot11dInfo->channel_map[channel] > 0) - return channel; - - return default_chn; -} diff --git a/drivers/staging/rtl8192e/dot11d.h b/drivers/staging/rtl8192e/dot11d.h index 69e0f8f7e3f8..e1c1888e282b 100644 --- a/drivers/staging/rtl8192e/dot11d.h +++ b/drivers/staging/rtl8192e/dot11d.h @@ -98,6 +98,5 @@ void Dot11d_UpdateCountryIe(struct rtllib_device *dev, u8 *pTaddr, u16 CoutryIeLen, u8 *pCoutryIe); u8 DOT11D_GetMaxTxPwrInDbm(struct rtllib_device *dev, u8 Channel); void DOT11D_ScanComplete(struct rtllib_device *dev); -int ToLegalChannel(struct rtllib_device *dev, u8 channel); #endif -- cgit v1.3-6-gb490 From 9efe891d01c3734ab05fdbd53dead3451fa03e29 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:05 +0200 Subject: staging: rtl8192e: Remove unused defines Remove most of unused defines (excluding phyreg/hw registers). Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/dot11d.h | 4 -- drivers/staging/rtl8192e/rtl8192e/r8190P_def.h | 46 ---------------------- .../staging/rtl8192e/rtl8192e/r8192E_firmware.h | 2 - drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 3 -- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 19 --------- drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 1 - drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 3 -- drivers/staging/rtl8192e/rtl819x_BA.h | 5 --- drivers/staging/rtl8192e/rtl819x_HT.h | 2 - drivers/staging/rtl8192e/rtl819x_TS.h | 2 - drivers/staging/rtl8192e/rtllib.h | 40 ------------------- drivers/staging/rtl8192e/rtllib_softmac.c | 1 - 12 files changed, 128 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/dot11d.h b/drivers/staging/rtl8192e/dot11d.h index e1c1888e282b..127af823ae96 100644 --- a/drivers/staging/rtl8192e/dot11d.h +++ b/drivers/staging/rtl8192e/dot11d.h @@ -79,7 +79,6 @@ static inline void cpMacAddr(unsigned char *des, unsigned char *src) #define UPDATE_CIE_SRC(__pIeeeDev, __pTa) \ cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) -#define CIE_WATCHDOG_TH 1 #define GET_CIE_WATCHDOG(__pIeeeDev) \ (GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog) static inline void RESET_CIE_WATCHDOG(struct rtllib_device *__pIeeeDev) @@ -88,9 +87,6 @@ static inline void RESET_CIE_WATCHDOG(struct rtllib_device *__pIeeeDev) } #define UPDATE_CIE_WATCHDOG(__pIeeeDev) (++GET_CIE_WATCHDOG(__pIeeeDev)) -#define IS_DOT11D_STATE_DONE(__pIeeeDev) \ - (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) - void dot11d_init(struct rtllib_device *dev); void Dot11d_Channelmap(u8 channel_plan, struct rtllib_device *ieee); void Dot11d_Reset(struct rtllib_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h index d0b08301b88f..dba4584c7006 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_def.h @@ -26,8 +26,6 @@ #define MAX_SILENT_RESET_RX_SLOT_NUM 10 #define RX_MPDU_QUEUE 0 -#define RX_CMD_QUEUE 1 - enum rtl819x_loopback { RTL819X_NO_LOOPBACK = 0, @@ -36,11 +34,6 @@ enum rtl819x_loopback { RTL819X_CCK_LOOPBACK = 3, }; - -#define RESET_DELAY_8185 20 - -#define RT_IBSS_INT_MASKS (IMR_BcnInt | IMR_BcnInt | IMR_TBDOK | IMR_TBDER) - #define DESC90_RATE1M 0x00 #define DESC90_RATE2M 0x01 #define DESC90_RATE5_5M 0x02 @@ -74,17 +67,6 @@ enum rtl819x_loopback { #define SHORT_SLOT_TIME 9 #define NON_SHORT_SLOT_TIME 20 - -#define MAX_LINES_HWCONFIG_TXT 1000 -#define MAX_BYTES_LINE_HWCONFIG_TXT 128 - -#define SW_THREE_WIRE 0 -#define HW_THREE_WIRE 2 - -#define BT_DEMO_BOARD 0 -#define BT_QA_BOARD 1 -#define BT_FPGA 2 - #define RX_SMOOTH 20 #define QSLT_BK 0x1 @@ -96,25 +78,14 @@ enum rtl819x_loopback { #define QSLT_MGNT 0x12 #define QSLT_CMD 0x13 -#define NUM_OF_FIRMWARE_QUEUE 10 -#define NUM_OF_PAGES_IN_FW 0x100 #define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x007 #define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x0aa #define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x024 #define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x007 -#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0 -#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x2 #define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x10 -#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0 #define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x4 #define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xd -#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM 0x026 -#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM 0x048 -#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM 0x048 -#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM 0x026 -#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM 0x00 - #define APPLIED_RESERVED_QUEUE_IN_FW 0x80000000 #define RSVD_FW_QUEUE_PAGE_BK_SHIFT 0x00 #define RSVD_FW_QUEUE_PAGE_BE_SHIFT 0x08 @@ -197,23 +168,6 @@ struct tx_fwinfo_8190pci { }; - -#define TX_DESC_SIZE 32 - -#define TX_DESC_CMD_SIZE 32 - - -#define TX_STATUS_DESC_SIZE 32 - -#define TX_FWINFO_SIZE 8 - - -#define RX_DESC_SIZE 16 - -#define RX_STATUS_DESC_SIZE 16 - -#define RX_DRIVER_INFO_SIZE 8 - struct log_int_8190 { u32 nIMR_COMDOK; u32 nIMR_MGNTDOK; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h index d79e54203199..ef232d2c34e6 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h @@ -19,8 +19,6 @@ #ifndef __INC_FIRMWARE_H #define __INC_FIRMWARE_H -#define RTL8190_CPU_START_OFFSET 0x80 - #define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4*(v/4) - 8) #define RTL8192E_BOOT_IMG_FW "RTL8192E/boot.img" diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 3de7cc549794..bce960d884e2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -58,9 +58,6 @@ static u32 edca_setting_UL[HT_IOT_PEER_MAX] = { 0x5e4332 }; -#define RTK_UL_EDCA 0xa44f -#define RTK_DL_EDCA 0x5e4322 - const u32 dm_tx_bb_gain[TxBBGainTableLength] = { 0x7f8001fe, /* 12 dB */ 0x788001e2, /* 11 dB */ diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index b037451c3ada..ac95d8f80995 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -27,26 +27,17 @@ #define DM_DIG_THRESH_HIGH 40 #define DM_DIG_THRESH_LOW 35 -#define DM_FALSEALARM_THRESH_LOW 40 -#define DM_FALSEALARM_THRESH_HIGH 1000 - #define DM_DIG_HIGH_PWR_THRESH_HIGH 75 #define DM_DIG_HIGH_PWR_THRESH_LOW 70 #define BW_AUTO_SWITCH_HIGH_LOW 25 #define BW_AUTO_SWITCH_LOW_HIGH 30 -#define DM_check_fsync_time_interval 500 - - #define DM_DIG_BACKOFF 12 #define DM_DIG_MAX 0x36 #define DM_DIG_MIN 0x1c #define DM_DIG_MIN_Netcore 0x12 -#define DM_DIG_BACKOFF_MAX 12 -#define DM_DIG_BACKOFF_MIN -4 - #define RxPathSelection_SS_TH_low 30 #define RxPathSelection_diff_TH 18 @@ -55,8 +46,6 @@ #define RateAdaptiveTH_Low_40M 10 #define VeryLowRSSI 15 -#define CTSToSelfTHVal 35 - #define WAIotTHVal 25 #define E_FOR_TX_POWER_TRACK 300 @@ -70,14 +59,6 @@ #define Tx_Retry_Count_Reg 0x1ac #define RegC38_TH 20 -#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74 -#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67 - -#define TxHighPwrLevel_Normal 0 -#define TxHighPwrLevel_Level1 1 -#define TxHighPwrLevel_Level2 2 - -#define DM_Type_ByFW 0 #define DM_Type_ByDriver 1 /*--------------------------Define Parameters-------------------------------*/ diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index 962f2e5b8bf8..d23c0f1d76f5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -30,7 +30,6 @@ struct net_device; #define RT_CHECK_FOR_HANG_PERIOD 2 -#define INIT_DEFAULT_CHAN 1 void rtl8192_hw_wakeup(struct net_device *dev); void rtl8192_hw_to_sleep(struct net_device *dev, u64 time); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index f5e4961677d2..3d7758592490 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -729,9 +729,6 @@ static int r8192_wx_set_enc(struct net_device *dev, hwkey[i] |= (key[4 * i + 3] & mask) << 24; } - #define CONF_WEP40 0x4 - #define CONF_WEP104 0x14 - switch (wrqu->encoding.flags & IW_ENCODE_INDEX) { case 0: key_idx = ieee->crypt_info.tx_keyidx; diff --git a/drivers/staging/rtl8192e/rtl819x_BA.h b/drivers/staging/rtl8192e/rtl819x_BA.h index 613e14c12df3..894666465152 100644 --- a/drivers/staging/rtl8192e/rtl819x_BA.h +++ b/drivers/staging/rtl8192e/rtl819x_BA.h @@ -19,11 +19,7 @@ #ifndef _BATYPE_H_ #define _BATYPE_H_ -#define TOTAL_TXBA_NUM 16 -#define TOTAL_RXBA_NUM 16 - #define BA_SETUP_TIMEOUT 200 -#define BA_INACT_TIMEOUT 60000 #define BA_POLICY_DELAYED 0 #define BA_POLICY_IMMEDIATE 1 @@ -32,7 +28,6 @@ #define ADDBA_STATUS_REFUSED 37 #define ADDBA_STATUS_INVALID_PARAM 38 -#define DELBA_REASON_QSTA_LEAVING 36 #define DELBA_REASON_END_BA 37 #define DELBA_REASON_UNKNOWN_BA 38 #define DELBA_REASON_TIMEOUT 39 diff --git a/drivers/staging/rtl8192e/rtl819x_HT.h b/drivers/staging/rtl8192e/rtl819x_HT.h index 0c263d9f7246..51711dcdc8ef 100644 --- a/drivers/staging/rtl8192e/rtl819x_HT.h +++ b/drivers/staging/rtl8192e/rtl819x_HT.h @@ -20,8 +20,6 @@ #define _RTL819XU_HTTYPE_H_ #define MIMO_PS_STATIC 0 -#define MIMO_PS_DYNAMIC 1 -#define MIMO_PS_NOLIMIT 3 #define sHTCLng 4 diff --git a/drivers/staging/rtl8192e/rtl819x_TS.h b/drivers/staging/rtl8192e/rtl819x_TS.h index b8fed556928c..a93348c37f17 100644 --- a/drivers/staging/rtl8192e/rtl819x_TS.h +++ b/drivers/staging/rtl8192e/rtl819x_TS.h @@ -19,8 +19,6 @@ #ifndef _TSTYPE_H_ #define _TSTYPE_H_ #include "rtl819x_Qos.h" -#define TS_SETUP_TIMEOUT 60 -#define TS_INACT_TIMEOUT 60 #define TS_ADDBA_DELAY 60 #define TOTAL_TS_NUM 16 diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index fd38c6dd146b..8ba92ed5cd09 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -84,9 +84,6 @@ #define iwe_stream_add_point_rsl(info, start, stop, iwe, p) \ iwe_stream_add_point(info, start, stop, iwe, p) -#define usb_alloc_urb_rsl(x, y) usb_alloc_urb(x, y) -#define usb_submit_urb_rsl(x, y) usb_submit_urb(x, y) - static inline void *netdev_priv_rsl(struct net_device *dev) { return netdev_priv(dev); @@ -110,27 +107,14 @@ static inline void *netdev_priv_rsl(struct net_device *dev) #define HIGH_QUEUE 7 #define BEACON_QUEUE 8 -#define LOW_QUEUE BE_QUEUE -#define NORMAL_QUEUE MGNT_QUEUE - #ifndef IW_MODE_MESH #define IW_MODE_MESH 7 #endif -#define AMSDU_SUBHEADER_LEN 14 -#define SWRF_TIMEOUT 50 #define IE_CISCO_FLAG_POSITION 0x08 #define SUPPORT_CKIP_MIC 0x08 #define SUPPORT_CKIP_PK 0x10 -#define RT_RF_OFF_LEVL_ASPM BIT0 -#define RT_RF_OFF_LEVL_CLK_REQ BIT1 -#define RT_RF_OFF_LEVL_PCI_D3 BIT2 #define RT_RF_OFF_LEVL_HALT_NIC BIT3 -#define RT_RF_OFF_LEVL_FREE_FW BIT4 -#define RT_RF_OFF_LEVL_FW_32K BIT5 -#define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT6 -#define RT_RF_LPS_DISALBE_2R BIT30 -#define RT_RF_LPS_LEVEL_ASPM BIT31 #define RT_IN_PS_LEVEL(pPSC, _PS_FLAG) \ ((pPSC->CurPsLevel & _PS_FLAG) ? true : false) #define RT_CLEAR_PS_LEVEL(pPSC, _PS_FLAG) \ @@ -244,22 +228,6 @@ struct sw_chnl_cmd { #define MGN_MCS13 0x8d #define MGN_MCS14 0x8e #define MGN_MCS15 0x8f -#define MGN_MCS0_SG 0x90 -#define MGN_MCS1_SG 0x91 -#define MGN_MCS2_SG 0x92 -#define MGN_MCS3_SG 0x93 -#define MGN_MCS4_SG 0x94 -#define MGN_MCS5_SG 0x95 -#define MGN_MCS6_SG 0x96 -#define MGN_MCS7_SG 0x97 -#define MGN_MCS8_SG 0x98 -#define MGN_MCS9_SG 0x99 -#define MGN_MCS10_SG 0x9a -#define MGN_MCS11_SG 0x9b -#define MGN_MCS12_SG 0x9c -#define MGN_MCS13_SG 0x9d -#define MGN_MCS14_SG 0x9e -#define MGN_MCS15_SG 0x9f enum hw_variables { HW_VAR_ETHER_ADDR, @@ -748,16 +716,11 @@ struct rtllib_stats { struct rtllib_device; -#define SEC_KEY_1 (1<<0) -#define SEC_KEY_2 (1<<1) -#define SEC_KEY_3 (1<<2) -#define SEC_KEY_4 (1<<3) #define SEC_ACTIVE_KEY (1<<4) #define SEC_AUTH_MODE (1<<5) #define SEC_UNICAST_GROUP (1<<6) #define SEC_LEVEL (1<<7) #define SEC_ENABLED (1<<8) -#define SEC_ENCRYPT (1<<9) #define SEC_LEVEL_0 0 /* None */ #define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ @@ -772,7 +735,6 @@ struct rtllib_device; #define WEP_KEY_LEN 13 #define SCM_KEY_LEN 32 -#define SCM_TEMPORAL_KEY_LENGTH 16 struct rtllib_security { u16 active_key:2, @@ -1187,8 +1149,6 @@ enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; #define WME_AC_BE 0x01 #define WME_AC_VI 0x02 #define WME_AC_VO 0x03 -#define WME_ACI_MASK 0x03 -#define WME_AIFSN_MASK 0x03 #define WME_AC_PRAM_LEN 16 #define MAX_RECEIVE_BUFFER_SIZE 9100 diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index d320c31732f2..eac7f289d354 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -1511,7 +1511,6 @@ static void rtllib_associate_step2(struct rtllib_device *ieee) } } -#define CANCELLED 2 static void rtllib_associate_complete_wq(void *data) { struct rtllib_device *ieee = (struct rtllib_device *) -- cgit v1.3-6-gb490 From 5e6f1c7145342ad0320b06ebd05d260c48275ae7 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:06 +0200 Subject: staging: rtl8192e: Remove undefs They relate to macros that are not used in the driver. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index c6cdb43b864c..32bf4754f612 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -22,25 +22,6 @@ * Contact Information: * wlanfae ******************************************************************************/ -#undef RX_DONT_PASS_UL -#undef DEBUG_EPROM -#undef DEBUG_RX_VERBOSE -#undef DUMMY_RX -#undef DEBUG_ZERO_RX -#undef DEBUG_RX_SKB -#undef DEBUG_TX_FRAG -#undef DEBUG_RX_FRAG -#undef DEBUG_TX_FILLDESC -#undef DEBUG_TX -#undef DEBUG_IRQ -#undef DEBUG_RX -#undef DEBUG_RXALLOC -#undef DEBUG_REGISTERS -#undef DEBUG_RING -#undef DEBUG_IRQ_TASKLET -#undef DEBUG_TX_ALLOC -#undef DEBUG_TX_DESC - #include #include #include -- cgit v1.3-6-gb490 From adc7623c86064d1578b406f9625ac25088ce05c1 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:07 +0200 Subject: staging: rtl8192e: Remove unused enums Remove ack_policy enum and some unused RTL_DEBUG enums. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl819x_Qos.h | 5 ----- drivers/staging/rtl8192e/rtllib_debug.h | 6 ------ 2 files changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl819x_Qos.h b/drivers/staging/rtl8192e/rtl819x_Qos.h index 3aa35ced2b8b..fcc8fabbebb7 100644 --- a/drivers/staging/rtl8192e/rtl819x_Qos.h +++ b/drivers/staging/rtl8192e/rtl819x_Qos.h @@ -96,11 +96,6 @@ struct octet_string { u16 Length; }; -enum ack_policy { - eAckPlc0_ACK = 0x00, - eAckPlc1_NoACK = 0x01, -}; - #define AC0_BE 0 #define AC1_BK 1 #define AC2_VI 2 diff --git a/drivers/staging/rtl8192e/rtllib_debug.h b/drivers/staging/rtl8192e/rtllib_debug.h index 42e88d69ae63..2f47a7cd23ab 100644 --- a/drivers/staging/rtl8192e/rtllib_debug.h +++ b/drivers/staging/rtl8192e/rtllib_debug.h @@ -40,10 +40,7 @@ enum RTL_DEBUG { COMP_DBG = (1 << 1), COMP_INIT = (1 << 2), COMP_RECV = (1 << 3), - COMP_SEND = (1 << 4), - COMP_CMD = (1 << 5), COMP_POWER = (1 << 6), - COMP_EPROM = (1 << 7), COMP_SWBW = (1 << 8), COMP_SEC = (1 << 9), COMP_LPS = (1 << 10), @@ -58,15 +55,12 @@ enum RTL_DEBUG { COMP_CH = (1 << 19), COMP_RF = (1 << 20), COMP_FIRMWARE = (1 << 21), - COMP_HT = (1 << 22), COMP_RESET = (1 << 23), COMP_CMDPKT = (1 << 24), COMP_SCAN = (1 << 25), COMP_PS = (1 << 26), COMP_DOWN = (1 << 27), COMP_INTR = (1 << 28), - COMP_LED = (1 << 29), - COMP_MLME = (1 << 30), COMP_ERR = (1 << 31) }; -- cgit v1.3-6-gb490 From 1184b4ade8182945ae063e584081368387a3b725 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:08 +0200 Subject: staging: rtl8192e: Remove unused fields from rtllib_stats None of them are used in the driver. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib.h | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 8ba92ed5cd09..dc0653a3ad45 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -691,27 +691,8 @@ struct rtllib_frag_entry { }; struct rtllib_stats { - unsigned int tx_unicast_frames; - unsigned int tx_multicast_frames; - unsigned int tx_fragments; - unsigned int tx_unicast_octets; - unsigned int tx_multicast_octets; - unsigned int tx_deferred_transmissions; - unsigned int tx_single_retry_frames; - unsigned int tx_multiple_retry_frames; - unsigned int tx_retry_limit_exceeded; unsigned int tx_discards; - unsigned int rx_unicast_frames; - unsigned int rx_multicast_frames; - unsigned int rx_fragments; - unsigned int rx_unicast_octets; - unsigned int rx_multicast_octets; - unsigned int rx_fcs_errors; - unsigned int rx_discards_no_buffer; - unsigned int tx_discards_wrong_sa; unsigned int rx_discards_undecryptable; - unsigned int rx_message_in_msg_fragments; - unsigned int rx_message_in_bad_msg_fragments; }; struct rtllib_device; -- cgit v1.3-6-gb490 From e93c18c7236f3fb90e87c6239ed78ad2c2552dfd Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:09 +0200 Subject: staging: rtl8192e: Remove rtllib_stats structure Two remaining fields of rtllib_stats are only incremented, but never read. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib.h | 6 ------ drivers/staging/rtl8192e/rtllib_rx.c | 2 -- drivers/staging/rtl8192e/rtllib_tx.c | 1 - 3 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index dc0653a3ad45..c44c8686e6bc 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -690,11 +690,6 @@ struct rtllib_frag_entry { u8 dst_addr[ETH_ALEN]; }; -struct rtllib_stats { - unsigned int tx_discards; - unsigned int rx_discards_undecryptable; -}; - struct rtllib_device; #define SEC_ACTIVE_KEY (1<<4) @@ -1532,7 +1527,6 @@ struct rtllib_device { /* Bookkeeping structures */ struct net_device_stats stats; - struct rtllib_stats ieee_stats; struct rtllib_softmac_stats softmac_stats; /* Probe / Beacon management */ diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index da862c3da4ce..0698a0d1f466 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -317,7 +317,6 @@ rtllib_rx_frame_decrypt(struct rtllib_device *ieee, struct sk_buff *skb, netdev_dbg(ieee->dev, "Decryption failed ICV mismatch (key %d)\n", skb->data[hdrlen + 3] >> 6); - ieee->ieee_stats.rx_discards_undecryptable++; return -1; } @@ -1077,7 +1076,6 @@ static int rtllib_rx_get_crypt(struct rtllib_device *ieee, struct sk_buff *skb, netdev_dbg(ieee->dev, "Decryption failed (not set) (SA= %pM)\n", hdr->addr2); - ieee->ieee_stats.rx_discards_undecryptable++; return -1; } } diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c index e99ea5e67ef9..517500c83d3e 100644 --- a/drivers/staging/rtl8192e/rtllib_tx.c +++ b/drivers/staging/rtl8192e/rtllib_tx.c @@ -205,7 +205,6 @@ int rtllib_encrypt_fragment(struct rtllib_device *ieee, struct sk_buff *frag, if (res < 0) { netdev_info(ieee->dev, "%s: Encryption failed: len=%d.\n", ieee->dev->name, frag->len); - ieee->ieee_stats.tx_discards++; return -1; } -- cgit v1.3-6-gb490 From 9b3fcf2bbf9374ade7f9dcac1c58c4af6fcc0694 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:10 +0200 Subject: staging: rtl8192e: Remove unused ether_header structure Structure is not used in the driver. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index c44c8686e6bc..81a3b9348379 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -1140,12 +1140,6 @@ enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; #define ETHERNET_HEADER_SIZE 14 /* length of two Ethernet address * plus ether type*/ -struct ether_header { - u8 ether_dhost[ETHER_ADDR_LEN]; - u8 ether_shost[ETHER_ADDR_LEN]; - u16 ether_type; -} __packed; - enum erp_t { ERP_NonERPpresent = 0x01, ERP_UseProtection = 0x02, -- cgit v1.3-6-gb490 From 18e2daa85847a555c3fc9b8e2b2b90a60cab0830 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:11 +0200 Subject: staging: rtl8192e: Remove unused rtllib_device::freq_band Member is never referenced. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 81a3b9348379..65c22dba5017 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -1602,7 +1602,6 @@ struct rtllib_device { int short_slot; int mode; /* A, B, G */ int modulation; /* CCK, OFDM */ - int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ /* used for forcing the ibss workqueue to terminate * without wait for the syncro scan to terminate -- cgit v1.3-6-gb490 From 632751b5290a70c094bdcabf5f9266f7f0a8fadd Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:12 +0200 Subject: staging: rtl8192e: Remove DOT11D_GetMaxTxPwrInDbm() Function is not used. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/dot11d.c | 15 --------------- drivers/staging/rtl8192e/dot11d.h | 1 - 2 files changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/dot11d.c b/drivers/staging/rtl8192e/dot11d.c index 7f48845e7125..fcf9b3bcf76a 100644 --- a/drivers/staging/rtl8192e/dot11d.c +++ b/drivers/staging/rtl8192e/dot11d.c @@ -160,21 +160,6 @@ void Dot11d_UpdateCountryIe(struct rtllib_device *dev, u8 *pTaddr, pDot11dInfo->State = DOT11D_STATE_LEARNED; } -u8 DOT11D_GetMaxTxPwrInDbm(struct rtllib_device *dev, u8 Channel) -{ - struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev); - u8 MaxTxPwrInDbm = 255; - - if (MAX_CHANNEL_NUMBER < Channel) { - netdev_info(dev->dev, "DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n"); - return MaxTxPwrInDbm; - } - if (pDot11dInfo->channel_map[Channel]) - MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel]; - - return MaxTxPwrInDbm; -} - void DOT11D_ScanComplete(struct rtllib_device *dev) { struct rt_dot11d_info *pDot11dInfo = GET_DOT11D_INFO(dev); diff --git a/drivers/staging/rtl8192e/dot11d.h b/drivers/staging/rtl8192e/dot11d.h index 127af823ae96..129ebed2e3cc 100644 --- a/drivers/staging/rtl8192e/dot11d.h +++ b/drivers/staging/rtl8192e/dot11d.h @@ -92,7 +92,6 @@ void Dot11d_Channelmap(u8 channel_plan, struct rtllib_device *ieee); void Dot11d_Reset(struct rtllib_device *dev); void Dot11d_UpdateCountryIe(struct rtllib_device *dev, u8 *pTaddr, u16 CoutryIeLen, u8 *pCoutryIe); -u8 DOT11D_GetMaxTxPwrInDbm(struct rtllib_device *dev, u8 Channel); void DOT11D_ScanComplete(struct rtllib_device *dev); #endif -- cgit v1.3-6-gb490 From 1e16cb17d59c9aafe8cc3dfc912050b1c4dddca7 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:13 +0200 Subject: staging: rtl8192e: Remove read|write_nic_io_(d)word|byte() None of this functions was used. Also remove PlatformIOCheckPageLegalAndGetRegMask() used by them. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 158 --------------------------- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 7 -- 2 files changed, 165 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 32bf4754f612..813435988db5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -90,164 +90,6 @@ static struct pci_driver rtl8192_pci_driver = { /**************************************************************************** -----------------------------IO STUFF------------------------- *****************************************************************************/ -static bool PlatformIOCheckPageLegalAndGetRegMask(u32 u4bPage, u8 *pu1bPageMask) -{ - bool bReturn = false; - - *pu1bPageMask = 0xfe; - - switch (u4bPage) { - case 1: case 2: case 3: case 4: - case 8: case 9: case 10: case 12: case 13: - bReturn = true; - *pu1bPageMask = 0xf0; - break; - - default: - bReturn = false; - break; - } - - return bReturn; -} - -void write_nic_io_byte(struct net_device *dev, int x, u8 y) -{ - u32 u4bPage = x >> 8; - u8 u1PageMask = 0; - bool bIsLegalPage = false; - - if (u4bPage == 0) { - outb(y&0xff, dev->base_addr + x); - - } else { - bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, - &u1PageMask); - if (bIsLegalPage) { - u8 u1bPsr = read_nic_io_byte(dev, PSR); - - write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | - (u8)u4bPage)); - write_nic_io_byte(dev, (x & 0xff), y); - write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); - } - } -} - -void write_nic_io_word(struct net_device *dev, int x, u16 y) -{ - u32 u4bPage = x >> 8; - u8 u1PageMask = 0; - bool bIsLegalPage = false; - - if (u4bPage == 0) { - outw(y, dev->base_addr + x); - } else { - bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, - &u1PageMask); - if (bIsLegalPage) { - u8 u1bPsr = read_nic_io_byte(dev, PSR); - - write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | - (u8)u4bPage)); - write_nic_io_word(dev, (x & 0xff), y); - write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); - - } - } -} - -void write_nic_io_dword(struct net_device *dev, int x, u32 y) -{ - u32 u4bPage = x >> 8; - u8 u1PageMask = 0; - bool bIsLegalPage = false; - - if (u4bPage == 0) { - outl(y, dev->base_addr + x); - } else { - bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, - &u1PageMask); - if (bIsLegalPage) { - u8 u1bPsr = read_nic_io_byte(dev, PSR); - - write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | - (u8)u4bPage)); - write_nic_io_dword(dev, (x & 0xff), y); - write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); - } - } -} - -u8 read_nic_io_byte(struct net_device *dev, int x) -{ - u32 u4bPage = x >> 8; - u8 u1PageMask = 0; - bool bIsLegalPage = false; - u8 Data = 0; - - if (u4bPage == 0) - return 0xff&inb(dev->base_addr + x); - - bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, - &u1PageMask); - if (bIsLegalPage) { - u8 u1bPsr = read_nic_io_byte(dev, PSR); - - write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | - (u8)u4bPage)); - Data = read_nic_io_byte(dev, (x & 0xff)); - write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); - } - - return Data; -} - -u16 read_nic_io_word(struct net_device *dev, int x) -{ - u32 u4bPage = x >> 8; - u8 u1PageMask = 0; - bool bIsLegalPage = false; - u16 Data = 0; - - if (u4bPage == 0) - return inw(dev->base_addr + x); - bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, - &u1PageMask); - if (bIsLegalPage) { - u8 u1bPsr = read_nic_io_byte(dev, PSR); - - write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | - (u8)u4bPage)); - Data = read_nic_io_word(dev, (x & 0xff)); - write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); - } - - return Data; -} - -u32 read_nic_io_dword(struct net_device *dev, int x) -{ - u32 u4bPage = x >> 8; - u8 u1PageMask = 0; - bool bIsLegalPage = false; - u32 Data = 0; - - if (u4bPage == 0) - return inl(dev->base_addr + x); - bIsLegalPage = PlatformIOCheckPageLegalAndGetRegMask(u4bPage, - &u1PageMask); - if (bIsLegalPage) { - u8 u1bPsr = read_nic_io_byte(dev, PSR); - - write_nic_io_byte(dev, PSR, ((u1bPsr & u1PageMask) | - (u8)u4bPage)); - Data = read_nic_io_dword(dev, (x & 0xff)); - write_nic_io_byte(dev, PSR, (u1bPsr & u1PageMask)); - } - - return Data; -} u8 read_nic_byte(struct net_device *dev, int x) { diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 776d950655cb..cb7af04f4db1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -581,13 +581,6 @@ extern const struct ethtool_ops rtl819x_ethtool_ops; void rtl8192_tx_cmd(struct net_device *dev, struct sk_buff *skb); short rtl8192_tx(struct net_device *dev, struct sk_buff *skb); -u8 read_nic_io_byte(struct net_device *dev, int x); -u32 read_nic_io_dword(struct net_device *dev, int x); -u16 read_nic_io_word(struct net_device *dev, int x); -void write_nic_io_byte(struct net_device *dev, int x, u8 y); -void write_nic_io_word(struct net_device *dev, int x, u16 y); -void write_nic_io_dword(struct net_device *dev, int x, u32 y); - u8 read_nic_byte(struct net_device *dev, int x); u32 read_nic_dword(struct net_device *dev, int x); u16 read_nic_word(struct net_device *dev, int x); -- cgit v1.3-6-gb490 From 9d9d0e369859fe16fe2b7154c64fb65c32136b95 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:14 +0200 Subject: staging: rtl8192e: Remove DMESG macro It is used in several places, but expands to nothing. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 1 - drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 3 --- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 4 ---- drivers/staging/rtl8192e/rtllib_debug.h | 2 -- 4 files changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index f6661bbae7a8..459ce659d090 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -41,7 +41,6 @@ void rtl8192e_start_beacon(struct net_device *dev) u16 BcnCW = 6; u16 BcnIFS = 0xf; - DMESG("Enabling beacon TX"); rtl8192_irq_disable(dev); write_nic_word(dev, ATIMWND, 2); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 813435988db5..1652da66338d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2723,8 +2723,6 @@ err_rel_mem: release_mem_region(pmem_start, pmem_len); err_rel_rtllib: free_rtllib(dev); - - DMESG("wlan driver load failed\n"); err_pci_disable: pci_disable_device(pdev); return err; @@ -2830,7 +2828,6 @@ static int __init rtl8192_pci_module_init(void) pr_info("Copyright (c) 2007-2008, Realsil Wlan Driver\n"); if (0 != pci_register_driver(&rtl8192_pci_driver)) { - DMESG("No device found"); /*pci_unregister_driver (&rtl8192_pci_driver);*/ return -ENODEV; } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index 3d7758592490..15fc48440cdc 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -818,13 +818,9 @@ static int r8192_wx_set_retry(struct net_device *dev, } if (wrqu->retry.flags & IW_RETRY_MAX) { priv->retry_rts = wrqu->retry.value; - DMESG("Setting retry for RTS/CTS data to %d", - wrqu->retry.value); } else { priv->retry_data = wrqu->retry.value; - DMESG("Setting retry for non RTS/CTS data to %d", - wrqu->retry.value); } diff --git a/drivers/staging/rtl8192e/rtllib_debug.h b/drivers/staging/rtl8192e/rtllib_debug.h index 2f47a7cd23ab..17c276d71058 100644 --- a/drivers/staging/rtl8192e/rtllib_debug.h +++ b/drivers/staging/rtl8192e/rtllib_debug.h @@ -30,8 +30,6 @@ #define DRV_NAME "rtllib_92e" #endif -#define DMESG(x, a...) - extern u32 rt_global_debug_component; /* These are the defines for rt_global_debug_component */ -- cgit v1.3-6-gb490 From 59eda5eecda9dc8566d9bc70a7e4dde0a5256aa0 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:15 +0200 Subject: staging: rtl8192e: Remove rtl819x_process_cck_rxpathsel() Function is empty. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 -- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 6 ------ drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 -- 3 files changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 459ce659d090..f28676bc8a8d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1731,8 +1731,6 @@ static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer, if (!bcheck) return; - rtl819x_process_cck_rxpathsel(priv, prev_st); - priv->stats.num_process_phyinfo++; if (!prev_st->bIsCCK && prev_st->bPacketToSelf) { for (rfpath = RF90_PATH_A; rfpath < RF90_PATH_C; rfpath++) { diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 1652da66338d..57eb43e2f5bb 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2012,12 +2012,6 @@ rtl819x_update_rxsignalstatistics8190pci( weighting) / 6; } -void rtl819x_process_cck_rxpathsel(struct r8192_priv *priv, - struct rtllib_rx_stats *pprevious_stats) -{ -} - - u8 rtl819x_query_rxpwrpercentage(char antpower) { if ((antpower <= -100) || (antpower >= 20)) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index cb7af04f4db1..6497918cd35d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -635,8 +635,6 @@ long rtl819x_translate_todbm(struct r8192_priv *priv, u8 signal_strength_index); void rtl819x_update_rxsignalstatistics8190pci(struct r8192_priv *priv, struct rtllib_rx_stats *pprevious_stats); u8 rtl819x_evm_dbtopercentage(char value); -void rtl819x_process_cck_rxpathsel(struct r8192_priv *priv, - struct rtllib_rx_stats *pprevious_stats); u8 rtl819x_query_rxpwrpercentage(char antpower); void rtl8192_record_rxdesc_forlateruse(struct rtllib_rx_stats *psrc_stats, struct rtllib_rx_stats *ptarget_stats); -- cgit v1.3-6-gb490 From 84b2ce69f952ce84b0b7ce926d497327e38767b6 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:16 +0200 Subject: staging: rtl8192e: probe: Remove bdma64 check It is always false. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 57eb43e2f5bb..1dc119eab5f1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2599,7 +2599,6 @@ static int rtl8192_pci_probe(struct pci_dev *pdev, struct rtl819x_ops *ops = (struct rtl819x_ops *)(id->driver_data); unsigned long pmem_start, pmem_len, pmem_flags; int err = -ENOMEM; - bool bdma64 = false; u8 revision_id; RT_TRACE(COMP_INIT, "Configuring chip resources"); @@ -2623,8 +2622,6 @@ static int rtl8192_pci_probe(struct pci_dev *pdev, goto err_pci_disable; err = -ENODEV; - if (bdma64) - dev->features |= NETIF_F_HIGHDMA; pci_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); -- cgit v1.3-6-gb490 From 3a82a2fe2c165a3d1deb251b19550e5e863e95be Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:17 +0200 Subject: staging: rtl8192e: Remove rtl8192_rx_cmd() Function is empty. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 1dc119eab5f1..a550634d857e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2161,11 +2161,6 @@ done: } -static void rtl8192_rx_cmd(struct net_device *dev) -{ -} - - static void rtl8192_tx_resume(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); @@ -2192,9 +2187,6 @@ void rtl8192_irq_rx_tasklet(struct r8192_priv *priv) { rtl8192_rx_normal(priv->rtllib->dev); - if (MAX_RX_QUEUE > 1) - rtl8192_rx_cmd(priv->rtllib->dev); - write_nic_dword(priv->rtllib->dev, INTA_MASK, read_nic_dword(priv->rtllib->dev, INTA_MASK) | IMR_RDU); } -- cgit v1.3-6-gb490 From 735b78615ace8f2c3527baccce0ee2d3ed0fb145 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:18 +0200 Subject: staging: rtl8192e: rtl_dm: Make functions static Make as many functions as possible static in rtllib_dm.c. The following functions were affected: - dm_check_fsync - dm_CheckRfCtrlGPIO - dm_fsync_timer_callback Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 9 ++++++--- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 3 --- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index bce960d884e2..c2367128c594 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -210,6 +210,9 @@ static void dm_deInit_fsync(struct net_device *dev); static void dm_check_txrateandretrycount(struct net_device *dev); static void dm_check_ac_dc_power(struct net_device *dev); +static void dm_check_fsync(struct net_device *dev); +static void dm_CheckRfCtrlGPIO(void *data); +static void dm_fsync_timer_callback(unsigned long data); /*---------------------Define local function prototype-----------------------*/ @@ -1851,7 +1854,7 @@ static void dm_check_pbc_gpio(struct net_device *dev) { } -void dm_CheckRfCtrlGPIO(void *data) +static void dm_CheckRfCtrlGPIO(void *data) { struct r8192_priv *priv = container_of_dwork_rsl(data, struct r8192_priv, gpio_change_rf_wq); @@ -2188,7 +2191,7 @@ static void dm_deInit_fsync(struct net_device *dev) del_timer_sync(&priv->fsync_timer); } -void dm_fsync_timer_callback(unsigned long data) +static void dm_fsync_timer_callback(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct r8192_priv *priv = rtllib_priv((struct net_device *)data); @@ -2372,7 +2375,7 @@ static void dm_StartSWFsync(struct net_device *dev) } -void dm_check_fsync(struct net_device *dev) +static void dm_check_fsync(struct net_device *dev) { #define RegC38_Default 0 #define RegC38_NonFsync_Other_AP 1 diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index ac95d8f80995..95b8a8fd0556 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -203,8 +203,5 @@ extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); extern void dm_backup_dynamic_mechanism_state(struct net_device *dev); extern void dm_init_edca_turbo(struct net_device *dev); extern void dm_rf_pathcheck_workitemcallback(void *data); -extern void dm_fsync_timer_callback(unsigned long data); -extern void dm_check_fsync(struct net_device *dev); extern void dm_initialize_txpower_tracking(struct net_device *dev); -extern void dm_CheckRfCtrlGPIO(void *data); #endif /*__R8192UDM_H__ */ -- cgit v1.3-6-gb490 From e0c84c1c1f0b6335184ab6ea0cdecfbf4abe173a Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:19 +0200 Subject: staging: rtl8192e: rtllib_HTProc: Make functions static Make as many functions as possible static in rtllib_HTProc.c. The following functions were affected: - HTMcsToDataRate - HTFilterMCSRate Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl819x_HTProc.c | 5 +++-- drivers/staging/rtl8192e/rtllib.h | 3 --- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c index b5c3647b0f80..555745b2a75e 100644 --- a/drivers/staging/rtl8192e/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192e/rtl819x_HTProc.c @@ -117,7 +117,7 @@ void HTUpdateDefaultSetting(struct rtllib_device *ieee) pHTInfo->RxReorderPendingTime = 30; } -u16 HTMcsToDataRate(struct rtllib_device *ieee, u8 nMcsRate) +static u16 HTMcsToDataRate(struct rtllib_device *ieee, u8 nMcsRate) { struct rt_hi_throughput *pHTInfo = ieee->pHTInfo; @@ -502,7 +502,8 @@ u8 HTGetHighestMCSRate(struct rtllib_device *ieee, u8 *pMCSRateSet, return mcsRate | 0x80; } -u8 HTFilterMCSRate(struct rtllib_device *ieee, u8 *pSupportMCS, u8 *pOperateMCS) +static u8 HTFilterMCSRate(struct rtllib_device *ieee, u8 *pSupportMCS, + u8 *pOperateMCS) { u8 i; diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 65c22dba5017..98f7db00cbca 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -2194,7 +2194,6 @@ extern u16 MCS_DATA_RATE[2][2][77]; extern u8 HTCCheck(struct rtllib_device *ieee, u8 *pFrame); extern void HTResetIOTSetting(struct rt_hi_throughput *pHTInfo); extern bool IsHTHalfNmodeAPs(struct rtllib_device *ieee); -extern u16 HTMcsToDataRate(struct rtllib_device *ieee, u8 nMcsRate); extern u16 TxCountToDataRate(struct rtllib_device *ieee, u8 nDataRate); extern int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb); extern int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb); @@ -2256,8 +2255,6 @@ extern int rtllib_parse_info_param(struct rtllib_device *ieee, void rtllib_indicate_packets(struct rtllib_device *ieee, struct rtllib_rxb **prxbIndicateArray, u8 index); -extern u8 HTFilterMCSRate(struct rtllib_device *ieee, u8 *pSupportMCS, - u8 *pOperateMCS); extern void HTUseDefaultSetting(struct rtllib_device *ieee); #define RT_ASOC_RETRY_LIMIT 5 u8 MgntQuery_TxRateExcludeCCKRates(struct rtllib_device *ieee); -- cgit v1.3-6-gb490 From 3ebfc4180586ee138af643513e6f75ad61f4db74 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:20 +0200 Subject: staging: rtl8192e: Make phy_RF8256_Config_ParaFile() static Relocate function in driver to avoid adding unnecessary fw decl. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 18 +++++++++--------- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h | 1 - 2 files changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index facc6f1f302b..f3eb1dc3da73 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -81,15 +81,7 @@ void PHY_SetRF8256Bandwidth(struct net_device *dev, } } -bool PHY_RF8256_Config(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - priv->NumTotalRFPath = RTL819X_TOTAL_RF_PATH; - return phy_RF8256_Config_ParaFile(dev); -} - -bool phy_RF8256_Config_ParaFile(struct net_device *dev) +static bool phy_RF8256_Config_ParaFile(struct net_device *dev) { u32 u4RegValue = 0; u8 eRFPath; @@ -240,6 +232,14 @@ phy_RF8256_Config_ParaFile_Fail: return false; } +bool PHY_RF8256_Config(struct net_device *dev) +{ + struct r8192_priv *priv = rtllib_priv(dev); + + priv->NumTotalRFPath = RTL819X_TOTAL_RF_PATH; + return phy_RF8256_Config_ParaFile(dev); +} + void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel) { u32 TxAGC = 0; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h index 64e831d2f4e5..d9348d92af26 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h @@ -24,7 +24,6 @@ extern void PHY_SetRF8256Bandwidth(struct net_device *dev, enum ht_channel_width Bandwidth); extern bool PHY_RF8256_Config(struct net_device *dev); -extern bool phy_RF8256_Config_ParaFile(struct net_device *dev); extern void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel); extern void PHY_SetRF8256OFDMTxPower(struct net_device *dev, u8 powerlevel); -- cgit v1.3-6-gb490 From 235a86c3ec8e5343dd153889ecc42a6fc66c09ce Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:21 +0200 Subject: staging: rtl8192e: rtl_core: Make functions static Make as many functions as possible static in rtl_core.c. If needed - move fw declaration from header. The following functions were affected: - rtl8192_is_tx_queue_empty - rtl819x_watchdog_wqcallback - watch_dog_timer_callback - rtl8192_data_hard_stop - rtl8192_data_hard_resume - rtl8192_hard_data_xmit - rtl8192_hard_start_xmit - rtl8192_tx_cmd - rtl8192_tx - rtl8192_pci_initdescring - rtl8192_irq_tx_tasklet - rtl8192_irq_rx_tasklet - rtl8192_cancel_deferred_work - _rtl8192_up - rtl8192_up - rtl8192_down - rtl8192_restart - rtl8192_update_cap Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 64 +++++++++++++++++----------- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 24 ----------- 2 files changed, 39 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index a550634d857e..ca8406bba26d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -87,6 +87,25 @@ static struct pci_driver rtl8192_pci_driver = { .resume = rtl8192E_resume, /* PM resume fn */ }; +static short rtl8192_is_tx_queue_empty(struct net_device *dev); +static void rtl819x_watchdog_wqcallback(void *data); +static void watch_dog_timer_callback(unsigned long data); +static void rtl8192_data_hard_stop(struct net_device *dev); +static void rtl8192_data_hard_resume(struct net_device *dev); +static void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, + int rate); +static int rtl8192_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void rtl8192_tx_cmd(struct net_device *dev, struct sk_buff *skb); +static short rtl8192_tx(struct net_device *dev, struct sk_buff *skb); +static short rtl8192_pci_initdescring(struct net_device *dev); +static void rtl8192_irq_tx_tasklet(struct r8192_priv *priv); +static void rtl8192_irq_rx_tasklet(struct r8192_priv *priv); +static void rtl8192_cancel_deferred_work(struct r8192_priv *priv); +static int _rtl8192_up(struct net_device *dev, bool is_silent_reset); +static int rtl8192_up(struct net_device *dev); +static int rtl8192_down(struct net_device *dev, bool shutdownrf); +static void rtl8192_restart(void *data); + /**************************************************************************** -----------------------------IO STUFF------------------------- *****************************************************************************/ @@ -273,7 +292,7 @@ static short rtl8192_check_nic_enough_desc(struct net_device *dev, int prio) return 0; } -void rtl8192_tx_timeout(struct net_device *dev) +static void rtl8192_tx_timeout(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); @@ -299,7 +318,7 @@ void rtl8192_irq_disable(struct net_device *dev) priv->irq_enabled = 0; } -void rtl8192_set_chan(struct net_device *dev, short ch) +static void rtl8192_set_chan(struct net_device *dev, short ch) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); @@ -313,7 +332,7 @@ void rtl8192_set_chan(struct net_device *dev, short ch) priv->rf_set_chan(dev, priv->chan); } -void rtl8192_update_cap(struct net_device *dev, u16 cap) +static void rtl8192_update_cap(struct net_device *dev, u16 cap) { struct r8192_priv *priv = rtllib_priv(dev); struct rtllib_network *net = &priv->rtllib->current_network; @@ -1105,7 +1124,7 @@ static short rtl8192_init(struct net_device *dev) /*************************************************************************** -------------------------------WATCHDOG STUFF--------------------------- ***************************************************************************/ -short rtl8192_is_tx_queue_empty(struct net_device *dev) +static short rtl8192_is_tx_queue_empty(struct net_device *dev) { int i = 0; struct r8192_priv *priv = rtllib_priv(dev); @@ -1393,8 +1412,7 @@ static void rtl819x_update_rxcounts(struct r8192_priv *priv, u32 *TotalRxBcnNum, } } - -void rtl819x_watchdog_wqcallback(void *data) +static void rtl819x_watchdog_wqcallback(void *data) { struct r8192_priv *priv = container_of_dwork_rsl(data, struct r8192_priv, watch_dog_wq); @@ -1548,7 +1566,7 @@ void rtl819x_watchdog_wqcallback(void *data) RT_TRACE(COMP_TRACE, " <==RtUsbCheckForHangWorkItemCallback()\n"); } -void watch_dog_timer_callback(unsigned long data) +static void watch_dog_timer_callback(unsigned long data) { struct r8192_priv *priv = rtllib_priv((struct net_device *)data); @@ -1625,16 +1643,15 @@ static void rtl8192_free_tx_ring(struct net_device *dev, unsigned int prio) ring->desc = NULL; } -void rtl8192_data_hard_stop(struct net_device *dev) +static void rtl8192_data_hard_stop(struct net_device *dev) { } - -void rtl8192_data_hard_resume(struct net_device *dev) +static void rtl8192_data_hard_resume(struct net_device *dev) { } -void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, +static void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int rate) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); @@ -1666,7 +1683,7 @@ void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, } } -int rtl8192_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int rtl8192_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); int ret; @@ -1725,7 +1742,7 @@ static void rtl8192_tx_isr(struct net_device *dev, int prio) tasklet_schedule(&priv->irq_tx_tasklet); } -void rtl8192_tx_cmd(struct net_device *dev, struct sk_buff *skb) +static void rtl8192_tx_cmd(struct net_device *dev, struct sk_buff *skb) { struct r8192_priv *priv = rtllib_priv(dev); struct rtl8192_tx_ring *ring; @@ -1748,7 +1765,7 @@ void rtl8192_tx_cmd(struct net_device *dev, struct sk_buff *skb) spin_unlock_irqrestore(&priv->irq_th_lock, flags); } -short rtl8192_tx(struct net_device *dev, struct sk_buff *skb) +static short rtl8192_tx(struct net_device *dev, struct sk_buff *skb) { struct r8192_priv *priv = rtllib_priv(dev); struct rtl8192_tx_ring *ring; @@ -1900,8 +1917,7 @@ static int rtl8192_alloc_tx_desc_ring(struct net_device *dev, return 0; } - -short rtl8192_pci_initdescring(struct net_device *dev) +static short rtl8192_pci_initdescring(struct net_device *dev) { u32 ret; int i; @@ -2178,12 +2194,12 @@ static void rtl8192_tx_resume(struct net_device *dev) } } -void rtl8192_irq_tx_tasklet(struct r8192_priv *priv) +static void rtl8192_irq_tx_tasklet(struct r8192_priv *priv) { rtl8192_tx_resume(priv->rtllib->dev); } -void rtl8192_irq_rx_tasklet(struct r8192_priv *priv) +static void rtl8192_irq_rx_tasklet(struct r8192_priv *priv) { rtl8192_rx_normal(priv->rtllib->dev); @@ -2194,7 +2210,7 @@ void rtl8192_irq_rx_tasklet(struct r8192_priv *priv) /**************************************************************************** ---------------------------- NIC START/CLOSE STUFF--------------------------- *****************************************************************************/ -void rtl8192_cancel_deferred_work(struct r8192_priv *priv) +static void rtl8192_cancel_deferred_work(struct r8192_priv *priv) { cancel_delayed_work(&priv->watch_dog_wq); cancel_delayed_work(&priv->update_beacon_wq); @@ -2203,14 +2219,13 @@ void rtl8192_cancel_deferred_work(struct r8192_priv *priv) cancel_work_sync(&priv->qos_activate); } -int _rtl8192_up(struct net_device *dev, bool is_silent_reset) +static int _rtl8192_up(struct net_device *dev, bool is_silent_reset) { if (_rtl8192_sta_up(dev, is_silent_reset) == -1) return -1; return 0; } - static int rtl8192_open(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); @@ -2223,8 +2238,7 @@ static int rtl8192_open(struct net_device *dev) } - -int rtl8192_up(struct net_device *dev) +static int rtl8192_up(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); @@ -2254,7 +2268,7 @@ static int rtl8192_close(struct net_device *dev) } -int rtl8192_down(struct net_device *dev, bool shutdownrf) +static int rtl8192_down(struct net_device *dev, bool shutdownrf) { if (rtl8192_sta_down(dev, shutdownrf) == -1) return -1; @@ -2274,7 +2288,7 @@ void rtl8192_commit(struct net_device *dev) _rtl8192_up(dev, false); } -void rtl8192_restart(void *data) +static void rtl8192_restart(void *data) { struct r8192_priv *priv = container_of_work_rsl(data, struct r8192_priv, reset_wq); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 6497918cd35d..26e54e41ced6 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -578,9 +578,6 @@ struct r8192_priv { extern const struct ethtool_ops rtl819x_ethtool_ops; -void rtl8192_tx_cmd(struct net_device *dev, struct sk_buff *skb); -short rtl8192_tx(struct net_device *dev, struct sk_buff *skb); - u8 read_nic_byte(struct net_device *dev, int x); u32 read_nic_dword(struct net_device *dev, int x); u16 read_nic_word(struct net_device *dev, int x); @@ -593,40 +590,19 @@ void force_pci_posting(struct net_device *dev); void rtl8192_rx_enable(struct net_device *); void rtl8192_tx_enable(struct net_device *); -int rtl8192_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); -void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, - int rate); -void rtl8192_data_hard_stop(struct net_device *dev); -void rtl8192_data_hard_resume(struct net_device *dev); -void rtl8192_restart(void *data); -void rtl819x_watchdog_wqcallback(void *data); void rtl8192_hw_sleep_wq(void *data); -void watch_dog_timer_callback(unsigned long data); -void rtl8192_irq_rx_tasklet(struct r8192_priv *priv); -void rtl8192_irq_tx_tasklet(struct r8192_priv *priv); -int rtl8192_down(struct net_device *dev, bool shutdownrf); -int rtl8192_up(struct net_device *dev); void rtl8192_commit(struct net_device *dev); -void rtl8192_set_chan(struct net_device *dev, short ch); void check_rfctrl_gpio_timer(unsigned long data); void rtl8192_hw_wakeup_wq(void *data); -short rtl8192_pci_initdescring(struct net_device *dev); - -void rtl8192_cancel_deferred_work(struct r8192_priv *priv); - -int _rtl8192_up(struct net_device *dev, bool is_silent_reset); -short rtl8192_is_tx_queue_empty(struct net_device *dev); void rtl8192_irq_disable(struct net_device *dev); -void rtl8192_tx_timeout(struct net_device *dev); void rtl8192_pci_resetdescring(struct net_device *dev); void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode); void rtl8192_irq_enable(struct net_device *dev); void rtl8192_config_rate(struct net_device *dev, u16 *rate_config); -void rtl8192_update_cap(struct net_device *dev, u16 cap); void rtl8192_irq_disable(struct net_device *dev); void rtl819x_UpdateRxPktTimeStamp(struct net_device *dev, -- cgit v1.3-6-gb490 From cc5a1591dadc01597e0fb48d0f5c16203ec33a00 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:22 +0200 Subject: staging: rtl8192e: r8192e_phy: Make functions static Make as many functions as possible static in r8192E_phy.c. The following functions were affected: - rtl8192_phyConfigBB - rtl8192_SwChnl_WorkItem - rtl8192_SetBWModeWorkItem Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 6 +++--- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index fba7654160e8..32135235f3e2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -357,7 +357,7 @@ void rtl8192_phy_configmac(struct net_device *dev) } -void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType) +static void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType) { int i; u32 *Rtl819XPHY_REGArray_Table = NULL; @@ -986,7 +986,7 @@ static void rtl8192_phy_FinishSwChnlNow(struct net_device *dev, u8 channel) break; } } -void rtl8192_SwChnl_WorkItem(struct net_device *dev) +static void rtl8192_SwChnl_WorkItem(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); @@ -1163,7 +1163,7 @@ static void CCK_Tx_Power_Track_BW_Switch(struct net_device *dev) CCK_Tx_Power_Track_BW_Switch_ThermalMeter(dev); } -void rtl8192_SetBWModeWorkItem(struct net_device *dev) +static void rtl8192_SetBWModeWorkItem(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 18bc58240fbe..ef85587c6a12 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -80,7 +80,6 @@ extern u32 rtl8192_phy_QueryRFReg(struct net_device *dev, enum rf90_radio_path eRFPath, u32 RegAddr, u32 BitMask); extern void rtl8192_phy_configmac(struct net_device *dev); -extern void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType); extern bool rtl8192_phy_checkBBAndRF(struct net_device *dev, enum hw90_block CheckBlock, enum rf90_radio_path eRFPath); @@ -96,8 +95,6 @@ extern u8 rtl8192_phy_SwChnl(struct net_device *dev, u8 channel); extern void rtl8192_SetBWMode(struct net_device *dev, enum ht_channel_width Bandwidth, enum ht_extchnl_offset Offset); -extern void rtl8192_SwChnl_WorkItem(struct net_device *dev); -extern void rtl8192_SetBWModeWorkItem(struct net_device *dev); extern void InitialGain819xPci(struct net_device *dev, u8 Operation); extern void PHY_SetRtl8192eRfOff(struct net_device *dev); -- cgit v1.3-6-gb490 From 01b67faf5c5449f7dc628d48b71faab73ac67343 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:23 +0200 Subject: staging: rtl8192e: Make rtl8192_QueryIsShort() static Relocate function within file to avoid unnecessary fw decl. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 24 ++++++++++++------------ drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 1 - 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index f28676bc8a8d..eb919b634e3c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1176,6 +1176,18 @@ static u8 rtl8192_MapHwQueueToFirmwareQueue(struct net_device *dev, u8 QueueID, return QueueSelect; } +static u8 rtl8192_QueryIsShort(u8 TxHT, u8 TxRate, struct cb_desc *tcb_desc) +{ + u8 tmp_Short; + + tmp_Short = (TxHT == 1) ? ((tcb_desc->bUseShortGI) ? 1 : 0) : + ((tcb_desc->bUseShortPreamble) ? 1 : 0); + if (TxHT == 1 && TxRate != DESC90_RATEMCS15) + tmp_Short = 0; + + return tmp_Short; +} + void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, struct cb_desc *cb_desc, struct sk_buff *skb) { @@ -2380,18 +2392,6 @@ bool rtl8192_GetHalfNmodeSupportByAPs(struct net_device *dev) return Reval; } -u8 rtl8192_QueryIsShort(u8 TxHT, u8 TxRate, struct cb_desc *tcb_desc) -{ - u8 tmp_Short; - - tmp_Short = (TxHT == 1) ? ((tcb_desc->bUseShortGI) ? 1 : 0) : - ((tcb_desc->bUseShortPreamble) ? 1 : 0); - if (TxHT == 1 && TxRate != DESC90_RATEMCS15) - tmp_Short = 0; - - return tmp_Short; -} - void ActUpdateChannelAccessSetting(struct net_device *dev, enum wireless_mode WirelessMode, struct channel_access_setting *ChnlAccessSetting) diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index dbe0e1c87056..4f1b312e90f4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -27,7 +27,6 @@ #include "r8190P_def.h" -u8 rtl8192_QueryIsShort(u8 TxHT, u8 TxRate, struct cb_desc *tcb_desc); bool rtl8192_GetHalfNmodeSupportByAPs(struct net_device *dev); bool rtl8192_GetNmodeSupportBySecCfg(struct net_device *dev); bool rtl8192_HalTxCheckStuck(struct net_device *dev); -- cgit v1.3-6-gb490 From 511998ea5be18a0219151e30c92a5d47533d2c49 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:24 +0200 Subject: staging: rtl8192e: rtllib_tx: Make functions static Make as many functions as possible static in rtllib_tx.c. The following functions were affected: - rtllib_xmit_inter - rtllib_query_seqnum - rtllib_put_snap Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib.h | 3 --- drivers/staging/rtl8192e/rtllib_tx.c | 8 ++++---- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 98f7db00cbca..965ae16b3d05 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -1995,7 +1995,6 @@ extern int rtllib_encrypt_fragment( int hdr_len); extern int rtllib_xmit(struct sk_buff *skb, struct net_device *dev); -extern int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev); extern void rtllib_txb_free(struct rtllib_txb *); /* rtllib_rx.c */ @@ -2092,8 +2091,6 @@ extern void rtllib_ps_tx_ack(struct rtllib_device *ieee, short success); extern void softmac_mgmt_xmit(struct sk_buff *skb, struct rtllib_device *ieee); -extern u16 rtllib_query_seqnum(struct rtllib_device *ieee, - struct sk_buff *skb, u8 *dst); extern u8 rtllib_ap_sec_type(struct rtllib_device *ieee); /* rtllib_softmac_wx.c */ diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c index 517500c83d3e..b992e4612fd8 100644 --- a/drivers/staging/rtl8192e/rtllib_tx.c +++ b/drivers/staging/rtl8192e/rtllib_tx.c @@ -151,7 +151,7 @@ static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; -inline int rtllib_put_snap(u8 *data, u16 h_proto) +static int rtllib_put_snap(u8 *data, u16 h_proto) { struct rtllib_snap_hdr *snap; u8 *oui; @@ -514,8 +514,8 @@ static void rtllib_txrate_selectmode(struct rtllib_device *ieee, } } -u16 rtllib_query_seqnum(struct rtllib_device *ieee, struct sk_buff *skb, - u8 *dst) +static u16 rtllib_query_seqnum(struct rtllib_device *ieee, struct sk_buff *skb, + u8 *dst) { u16 seqnum = 0; @@ -565,7 +565,7 @@ static u8 rtllib_current_rate(struct rtllib_device *ieee) return ieee->rate & 0x7F; } -int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) +static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev) { struct rtllib_device *ieee = (struct rtllib_device *) netdev_priv_rsl(dev); -- cgit v1.3-6-gb490 From ed4360336931ea99d029f1208d3e55b60c2bc621 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:25 +0200 Subject: staging: rtl8192e: Make rtllib_rx_mgt() static Function is not referenced outside of rtllib_rx.c Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib.h | 3 --- drivers/staging/rtl8192e/rtllib_rx.c | 9 ++++++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 965ae16b3d05..57341a1a6e61 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -2000,9 +2000,6 @@ extern void rtllib_txb_free(struct rtllib_txb *); /* rtllib_rx.c */ extern int rtllib_rx(struct rtllib_device *ieee, struct sk_buff *skb, struct rtllib_rx_stats *rx_stats); -extern void rtllib_rx_mgt(struct rtllib_device *ieee, - struct sk_buff *skb, - struct rtllib_rx_stats *stats); extern void rtllib_rx_probe_rq(struct rtllib_device *ieee, struct sk_buff *skb); extern int rtllib_legal_channel(struct rtllib_device *rtllib, u8 channel); diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index 0698a0d1f466..54dfff61f485 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -44,6 +44,9 @@ #include "rtllib.h" #include "dot11d.h" +static void rtllib_rx_mgt(struct rtllib_device *ieee, struct sk_buff *skb, + struct rtllib_rx_stats *stats); + static inline void rtllib_monitor_rx(struct rtllib_device *ieee, struct sk_buff *skb, struct rtllib_rx_stats *rx_status, @@ -2715,9 +2718,9 @@ free_network: kfree(network); } -void rtllib_rx_mgt(struct rtllib_device *ieee, - struct sk_buff *skb, - struct rtllib_rx_stats *stats) +static void rtllib_rx_mgt(struct rtllib_device *ieee, + struct sk_buff *skb, + struct rtllib_rx_stats *stats) { struct rtllib_hdr_4addr *header = (struct rtllib_hdr_4addr *)skb->data; -- cgit v1.3-6-gb490 From 6957248f487e0eeecf7a23a34b08ee26c0c3a151 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 14 Jul 2015 22:04:26 +0200 Subject: staging: rtl8192e: rtllib_softmac: Make functions static Make as many functions as possible static in rtllib_softmac.c. The following functions were affected: - rtllib_sta_wakeup - rtllib_TURBO_Info - rtllib_get_beacon_ - rtllib_send_probe_requests - rtllib_update_active_chan_map - rtllib_softmac_scan_syncro Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib.h | 11 ----------- drivers/staging/rtl8192e/rtllib_softmac.c | 27 +++++++++++++++------------ 2 files changed, 15 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index 57341a1a6e61..617f79efe4ca 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -2026,7 +2026,6 @@ extern int rtllib_wx_set_mlme(struct rtllib_device *ieee, extern int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len); /* rtllib_softmac.c */ -extern short rtllib_is_54g(struct rtllib_network *net); extern int rtllib_rx_frame_softmac(struct rtllib_device *ieee, struct sk_buff *skb, struct rtllib_rx_stats *rx_stats, u16 type, @@ -2040,13 +2039,9 @@ extern void rtllib_softmac_xmit(struct rtllib_txb *txb, extern void rtllib_stop_send_beacons(struct rtllib_device *ieee); extern void notify_wx_assoc_event(struct rtllib_device *ieee); -extern void rtllib_softmac_check_all_nets(struct rtllib_device *ieee); -extern void rtllib_start_bss(struct rtllib_device *ieee); -extern void rtllib_start_master_bss(struct rtllib_device *ieee); extern void rtllib_start_ibss(struct rtllib_device *ieee); extern void rtllib_softmac_init(struct rtllib_device *ieee); extern void rtllib_softmac_free(struct rtllib_device *ieee); -extern void rtllib_associate_abort(struct rtllib_device *ieee); extern void rtllib_disassociate(struct rtllib_device *ieee); extern void rtllib_stop_scan(struct rtllib_device *ieee); extern bool rtllib_act_scanning(struct rtllib_device *ieee, bool sync_scan); @@ -2054,7 +2049,6 @@ extern void rtllib_stop_scan_syncro(struct rtllib_device *ieee); extern void rtllib_start_scan_syncro(struct rtllib_device *ieee, u8 is_mesh); extern void rtllib_sta_ps_send_null_frame(struct rtllib_device *ieee, short pwr); -extern void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl); extern void rtllib_sta_ps_send_pspoll_frame(struct rtllib_device *ieee); extern void rtllib_start_protocol(struct rtllib_device *ieee); extern void rtllib_stop_protocol(struct rtllib_device *ieee, u8 shutdown); @@ -2067,8 +2061,6 @@ extern void rtllib_EnableIntelPromiscuousMode(struct net_device *dev, bool bInitState); extern void rtllib_DisableIntelPromiscuousMode(struct net_device *dev, bool bInitState); -extern void rtllib_send_probe_requests(struct rtllib_device *ieee, u8 is_mesh); - extern void rtllib_softmac_stop_protocol(struct rtllib_device *ieee, u8 mesh_flag, u8 shutdown); extern void rtllib_softmac_start_protocol(struct rtllib_device *ieee, @@ -2214,7 +2206,6 @@ extern void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS); extern void RemovePeerTS(struct rtllib_device *ieee, u8 *Addr); extern void RemoveAllTS(struct rtllib_device *ieee); -void rtllib_softmac_scan_syncro(struct rtllib_device *ieee, u8 is_mesh); extern const long rtllib_wlan_frequencies[]; @@ -2238,7 +2229,6 @@ bool rtllib_MgntDisconnect(struct rtllib_device *rtllib, u8 asRsn); /* For the function is more related to hardware setting, it's better to use the * ieee handler to refer to it. */ -extern void rtllib_update_active_chan_map(struct rtllib_device *ieee); extern void rtllib_FlushRxTsPendingPkts(struct rtllib_device *ieee, struct rx_ts_record *pTS); extern int rtllib_parse_info_param(struct rtllib_device *ieee, @@ -2252,7 +2242,6 @@ void rtllib_indicate_packets(struct rtllib_device *ieee, extern void HTUseDefaultSetting(struct rtllib_device *ieee); #define RT_ASOC_RETRY_LIMIT 5 u8 MgntQuery_TxRateExcludeCCKRates(struct rtllib_device *ieee); -extern void rtllib_TURBO_Info(struct rtllib_device *ieee, u8 **tag_p); #define SEM_DOWN_IEEE_WX(psem) down(psem) #define SEM_UP_IEEE_WX(psem) up(psem) diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index eac7f289d354..635a1c40c309 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -23,7 +23,10 @@ #include #include "dot11d.h" -short rtllib_is_54g(struct rtllib_network *net) +static void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl); + + +static short rtllib_is_54g(struct rtllib_network *net) { return (net->rates_ex_len > 0) || (net->rates_len > 4); } @@ -107,7 +110,7 @@ static void rtllib_WMM_Info(struct rtllib_device *ieee, u8 **tag_p) *tag_p = tag; } -void rtllib_TURBO_Info(struct rtllib_device *ieee, u8 **tag_p) +static void rtllib_TURBO_Info(struct rtllib_device *ieee, u8 **tag_p) { u8 *tag = *tag_p; @@ -369,7 +372,7 @@ static inline struct sk_buff *rtllib_probe_req(struct rtllib_device *ieee) return skb; } -struct sk_buff *rtllib_get_beacon_(struct rtllib_device *ieee); +static struct sk_buff *rtllib_get_beacon_(struct rtllib_device *ieee); static void rtllib_send_beacon(struct rtllib_device *ieee) { @@ -483,7 +486,7 @@ static void rtllib_send_probe(struct rtllib_device *ieee, u8 is_mesh) } -void rtllib_send_probe_requests(struct rtllib_device *ieee, u8 is_mesh) +static void rtllib_send_probe_requests(struct rtllib_device *ieee, u8 is_mesh) { if (ieee->active_scan && (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ)) { @@ -492,7 +495,7 @@ void rtllib_send_probe_requests(struct rtllib_device *ieee, u8 is_mesh) } } -void rtllib_update_active_chan_map(struct rtllib_device *ieee) +static void rtllib_update_active_chan_map(struct rtllib_device *ieee) { memcpy(ieee->active_channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); @@ -501,7 +504,7 @@ void rtllib_update_active_chan_map(struct rtllib_device *ieee) /* this performs syncro scan blocking the caller until all channels * in the allowed channel map has been checked. */ -void rtllib_softmac_scan_syncro(struct rtllib_device *ieee, u8 is_mesh) +static void rtllib_softmac_scan_syncro(struct rtllib_device *ieee, u8 is_mesh) { union iwreq_data wrqu; short ch = 0; @@ -1401,7 +1404,7 @@ inline struct sk_buff *rtllib_association_req(struct rtllib_network *beacon, return skb; } -void rtllib_associate_abort(struct rtllib_device *ieee) +static void rtllib_associate_abort(struct rtllib_device *ieee) { unsigned long flags; @@ -1752,7 +1755,7 @@ inline void rtllib_softmac_new_net(struct rtllib_device *ieee, } } -void rtllib_softmac_check_all_nets(struct rtllib_device *ieee) +static void rtllib_softmac_check_all_nets(struct rtllib_device *ieee) { unsigned long flags; struct rtllib_network *target; @@ -2108,7 +2111,7 @@ out: } -void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl) +static void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl) { if (ieee->sta_sleep == LPS_IS_WAKE) { if (nl) { @@ -2544,7 +2547,7 @@ inline void rtllib_randomize_cell(struct rtllib_device *ieee) } /* called in user context only */ -void rtllib_start_master_bss(struct rtllib_device *ieee) +static void rtllib_start_master_bss(struct rtllib_device *ieee) { ieee->assoc_id = 1; @@ -2719,7 +2722,7 @@ inline void rtllib_start_ibss(struct rtllib_device *ieee) } /* this is called only in user context, with wx_sem held */ -void rtllib_start_bss(struct rtllib_device *ieee) +static void rtllib_start_bss(struct rtllib_device *ieee) { unsigned long flags; @@ -2816,7 +2819,7 @@ exit: up(&ieee->wx_sem); } -struct sk_buff *rtllib_get_beacon_(struct rtllib_device *ieee) +static struct sk_buff *rtllib_get_beacon_(struct rtllib_device *ieee) { const u8 broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -- cgit v1.3-6-gb490 From 3e3148c51190d680b7cc2ebdc556e6ea27a93989 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Fri, 26 Jun 2015 09:37:25 +0530 Subject: Staging: rtl8192e: Replace memset with eth_zero_addr Use eth_zero_addr to assign the zero address to the given address array instead of memset when second argument is address of zero. Note that the 6 in the third argument of memset appears to represent an ethernet address size (ETH_ALEN). The Coccinelle semantic patch that makes this change is as follows: // @eth_zero_addr@ expression e; @@ -memset(e,0x00,6); +eth_zero_addr(e); // Signed-off-by: Vaishali Thakkar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl819x_TSProc.c | 2 +- drivers/staging/rtl8192e/rtllib_softmac.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl819x_TSProc.c b/drivers/staging/rtl8192e/rtl819x_TSProc.c index 05aea4321b9d..7087959443cb 100644 --- a/drivers/staging/rtl8192e/rtl819x_TSProc.c +++ b/drivers/staging/rtl8192e/rtl819x_TSProc.c @@ -113,7 +113,7 @@ static void TsAddBaProcess(unsigned long data) static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo) { - memset(pTsCommonInfo->Addr, 0, 6); + eth_zero_addr(pTsCommonInfo->Addr); memset(&pTsCommonInfo->TSpec, 0, sizeof(union tspec_body)); memset(&pTsCommonInfo->TClass, 0, sizeof(union qos_tclas)*TCLAS_NUM); pTsCommonInfo->TClasProc = 0; diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index 635a1c40c309..1503cbb3574e 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -3086,7 +3086,7 @@ static int rtllib_wpa_enable(struct rtllib_device *ieee, int value) */ netdev_info(ieee->dev, "%s WPA\n", value ? "enabling" : "disabling"); ieee->wpa_enabled = value; - memset(ieee->ap_mac_addr, 0, 6); + eth_zero_addr(ieee->ap_mac_addr); return 0; } -- cgit v1.3-6-gb490 From b44d9ce3b81715311198f0c5fa329e518b4f9f18 Mon Sep 17 00:00:00 2001 From: Gioh Kim Date: Mon, 6 Jul 2015 15:14:40 +0900 Subject: staging: ion: shrink page-pool by page unit This patch shrink page-pool by page unit. The system shrinker calls ion_heap_shrink_count() to get nr_to_scan, and pass it to ion_heap_shrink_scan(). The problem is the return value of ion_heap_shrink_count() is the number of pages but ion_system_heap_shrink(), which is called by ion_heap_shrink_scan(), gets the number of chunk. The main root of this is that ion_page_pool_shrink() returns page count via ion_page_pool_total() if it have to check pool size. But it frees chunks of pages if it have to free pools. This patch first fix ion_page_pool_shrink() to count only pages, not chunks. And then ion_system_heap_shrink() to work on pages. Signed-off-by: Gioh Kim Reviewed-by: Laura Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion_page_pool.c | 5 +++-- drivers/staging/android/ion/ion_system_heap.c | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index 4b88f11e52d3..19ad3aba499a 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -116,7 +116,7 @@ static int ion_page_pool_total(struct ion_page_pool *pool, bool high) int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, int nr_to_scan) { - int freed; + int freed = 0; bool high; if (current_is_kswapd()) @@ -127,7 +127,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, if (nr_to_scan == 0) return ion_page_pool_total(pool, high); - for (freed = 0; freed < nr_to_scan; freed++) { + while (freed < nr_to_scan) { struct page *page; mutex_lock(&pool->mutex); @@ -141,6 +141,7 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, } mutex_unlock(&pool->mutex); ion_page_pool_free_pages(pool, page); + freed += (1 << pool->order); } return freed; diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index da2a63c0a9ba..7a7a9a047230 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -212,14 +212,26 @@ static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask, { struct ion_system_heap *sys_heap; int nr_total = 0; - int i; + int i, nr_freed; + int only_scan = 0; sys_heap = container_of(heap, struct ion_system_heap, heap); + if (!nr_to_scan) + only_scan = 1; + for (i = 0; i < num_orders; i++) { struct ion_page_pool *pool = sys_heap->pools[i]; - nr_total += ion_page_pool_shrink(pool, gfp_mask, nr_to_scan); + nr_freed = ion_page_pool_shrink(pool, gfp_mask, nr_to_scan); + nr_total += nr_freed; + + if (!only_scan) { + nr_to_scan -= nr_freed; + /* shrink completed */ + if (nr_to_scan <= 0) + break; + } } return nr_total; -- cgit v1.3-6-gb490 From aeb7fa7b4f29ce4d7d16c4c3565c4714f2f62b82 Mon Sep 17 00:00:00 2001 From: Gioh Kim Date: Mon, 6 Jul 2015 15:14:41 +0900 Subject: staging: ion: debugfs to shrink pool This patch enables debugfs file /sys/kernel/debug/ion/heaps/system_shrink to shrink pool and get pool size. This technically enables debugfs shrinking for all heaps, not just the system heap although the system heap is the only one with a shrinker right now. It is already implemented but not complete. This patch completes and enables it. Reading the file returns pool size in page unit and writing the number of pages shrinks pool. It flushes all pages to write zero at the file. Signed-off-by: Gioh Kim Reviewed-by: Laura Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 6c922c7817f9..eec878e183f5 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1466,7 +1466,6 @@ static const struct file_operations debug_heap_fops = { .release = single_release, }; -#ifdef DEBUG_HEAP_SHRINKER static int debug_shrink_set(void *data, u64 val) { struct ion_heap *heap = data; @@ -1474,15 +1473,14 @@ static int debug_shrink_set(void *data, u64 val) int objs; sc.gfp_mask = -1; - sc.nr_to_scan = 0; - - if (!val) - return 0; + sc.nr_to_scan = val; - objs = heap->shrinker.shrink(&heap->shrinker, &sc); - sc.nr_to_scan = objs; + if (!val) { + objs = heap->shrinker.count_objects(&heap->shrinker, &sc); + sc.nr_to_scan = objs; + } - heap->shrinker.shrink(&heap->shrinker, &sc); + heap->shrinker.scan_objects(&heap->shrinker, &sc); return 0; } @@ -1495,14 +1493,13 @@ static int debug_shrink_get(void *data, u64 *val) sc.gfp_mask = -1; sc.nr_to_scan = 0; - objs = heap->shrinker.shrink(&heap->shrinker, &sc); + objs = heap->shrinker.count_objects(&heap->shrinker, &sc); *val = objs; return 0; } DEFINE_SIMPLE_ATTRIBUTE(debug_shrink_fops, debug_shrink_get, debug_shrink_set, "%llu\n"); -#endif void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) { @@ -1540,8 +1537,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) path, heap->name); } -#ifdef DEBUG_HEAP_SHRINKER - if (heap->shrinker.shrink) { + if (heap->shrinker.count_objects && heap->shrinker.scan_objects) { char debug_name[64]; snprintf(debug_name, 64, "%s_shrink", heap->name); @@ -1556,7 +1552,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap) path, debug_name); } } -#endif + up_write(&dev->lock); } -- cgit v1.3-6-gb490 From 4d4d138a3e2c2a85df9fa048b341612c235c1027 Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Wed, 15 Jul 2015 08:52:51 +0530 Subject: staging:vt6655: remove checks around dev_kfree_skb dev_kfree_skb checks for NULL pointer itself, Thus no need of explicit NULL check. Signed-off-by: Maninder Singh Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 4f55d5e9a9c5..f7d70427d050 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -758,9 +758,7 @@ static void device_free_td0_ring(struct vnt_private *pDevice) dma_unmap_single(&pDevice->pcid->dev, pTDInfo->skb_dma, pTDInfo->skb->len, DMA_TO_DEVICE); - if (pTDInfo->skb) - dev_kfree_skb(pTDInfo->skb); - + dev_kfree_skb(pTDInfo->skb); kfree(pDesc->pTDInfo); } } @@ -777,9 +775,7 @@ static void device_free_td1_ring(struct vnt_private *pDevice) dma_unmap_single(&pDevice->pcid->dev, pTDInfo->skb_dma, pTDInfo->skb->len, DMA_TO_DEVICE); - if (pTDInfo->skb) - dev_kfree_skb(pTDInfo->skb); - + dev_kfree_skb(pTDInfo->skb); kfree(pDesc->pTDInfo); } } -- cgit v1.3-6-gb490 From 86eadace5d021f50558936ea75234f3262d16bc2 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Fri, 26 Jun 2015 23:39:36 +0300 Subject: staging: vme_user: fix code alignment Signed-off-by: Dmitry Kalinkin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 9cca97af3044..ccf96029ca22 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -128,7 +128,7 @@ struct vme_user_vma_priv { * transfer the data directly into the user space buffers. */ static ssize_t resource_to_user(int minor, char __user *buf, size_t count, - loff_t *ppos) + loff_t *ppos) { ssize_t retval; ssize_t copied = 0; @@ -167,7 +167,7 @@ static ssize_t resource_to_user(int minor, char __user *buf, size_t count, * transfer the data directly from the user space buffers out to VME. */ static ssize_t resource_from_user(unsigned int minor, const char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { ssize_t retval; ssize_t copied = 0; @@ -195,7 +195,7 @@ static ssize_t resource_from_user(unsigned int minor, const char __user *buf, } static ssize_t buffer_to_user(unsigned int minor, char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { void *image_ptr; ssize_t retval; @@ -214,7 +214,7 @@ static ssize_t buffer_to_user(unsigned int minor, char __user *buf, } static ssize_t buffer_from_user(unsigned int minor, const char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { void *image_ptr; size_t retval; @@ -233,7 +233,7 @@ static ssize_t buffer_from_user(unsigned int minor, const char __user *buf, } static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) + loff_t *ppos) { unsigned int minor = MINOR(file_inode(file)->i_rdev); ssize_t retval; @@ -279,7 +279,7 @@ static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count, } static ssize_t vme_user_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { unsigned int minor = MINOR(file_inode(file)->i_rdev); ssize_t retval; @@ -354,7 +354,7 @@ static loff_t vme_user_llseek(struct file *file, loff_t off, int whence) * already been defined. */ static int vme_user_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { struct vme_master master; struct vme_slave slave; @@ -390,12 +390,13 @@ static int vme_user_ioctl(struct inode *inode, struct file *file, * to userspace as they are */ retval = vme_master_get(image[minor].resource, - &master.enable, &master.vme_addr, - &master.size, &master.aspace, - &master.cycle, &master.dwidth); + &master.enable, + &master.vme_addr, + &master.size, &master.aspace, + &master.cycle, &master.dwidth); copied = copy_to_user(argp, &master, - sizeof(struct vme_master)); + sizeof(struct vme_master)); if (copied != 0) { pr_warn("Partial copy to userspace\n"); return -EFAULT; @@ -435,12 +436,12 @@ static int vme_user_ioctl(struct inode *inode, struct file *file, * to userspace as they are */ retval = vme_slave_get(image[minor].resource, - &slave.enable, &slave.vme_addr, - &slave.size, &pci_addr, &slave.aspace, - &slave.cycle); + &slave.enable, &slave.vme_addr, + &slave.size, &pci_addr, + &slave.aspace, &slave.cycle); copied = copy_to_user(argp, &slave, - sizeof(struct vme_slave)); + sizeof(struct vme_slave)); if (copied != 0) { pr_warn("Partial copy to userspace\n"); return -EFAULT; @@ -606,7 +607,7 @@ static int vme_user_probe(struct vme_dev *vdev) /* Assign major and minor numbers for the driver */ err = register_chrdev_region(MKDEV(VME_MAJOR, 0), VME_DEVS, - driver_name); + driver_name); if (err) { dev_warn(&vdev->dev, "Error getting Major Number %d for driver.\n", VME_MAJOR); -- cgit v1.3-6-gb490 From cd974d35ab784d98085ed1b317a9978c026d86f7 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Fri, 26 Jun 2015 23:39:37 +0300 Subject: staging: vme_user: fix blank lines Signed-off-by: Dmitry Kalinkin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index ccf96029ca22..494655ad1264 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -101,13 +101,13 @@ struct image_desc { struct vme_resource *resource; /* VME resource */ int mmap_count; /* Number of current mmap's */ }; + static struct image_desc image[VME_DEVS]; static struct cdev *vme_user_cdev; /* Character device */ static struct class *vme_user_sysfs_class; /* Sysfs class */ static struct vme_dev *vme_user_bridge; /* Pointer to user device */ - static const int type[VME_DEVS] = { MASTER_MINOR, MASTER_MINOR, MASTER_MINOR, MASTER_MINOR, SLAVE_MINOR, SLAVE_MINOR, @@ -120,7 +120,6 @@ struct vme_user_vma_priv { atomic_t refcnt; }; - /* * We are going ot alloc a page during init per window for small transfers. * Small transfers will go VME -> buffer -> user space. Larger (more than a @@ -836,7 +835,6 @@ static void __exit vme_user_exit(void) vme_unregister_driver(&vme_user_driver); } - MODULE_PARM_DESC(bus, "Enumeration of VMEbus to which the driver is connected"); module_param_array(bus, int, &bus_num, 0); -- cgit v1.3-6-gb490 From f99b71be37dd88e7b2f4a7c227da6c4f71cd8fa4 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Fri, 26 Jun 2015 23:39:38 +0300 Subject: staging: vme_user: fix NULL comparison style Signed-off-by: Dmitry Kalinkin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 494655ad1264..2ff15f081776 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -527,7 +527,7 @@ static int vme_user_master_mmap(unsigned int minor, struct vm_area_struct *vma) } vma_priv = kmalloc(sizeof(struct vme_user_vma_priv), GFP_KERNEL); - if (vma_priv == NULL) { + if (!vma_priv) { mutex_unlock(&image[minor].mutex); return -ENOMEM; } @@ -588,7 +588,7 @@ static int vme_user_probe(struct vme_dev *vdev) char *name; /* Save pointer to the bridge device */ - if (vme_user_bridge != NULL) { + if (vme_user_bridge) { dev_err(&vdev->dev, "Driver can only be loaded for 1 device\n"); err = -EINVAL; goto err_dev; @@ -636,7 +636,7 @@ static int vme_user_probe(struct vme_dev *vdev) */ image[i].resource = vme_slave_request(vme_user_bridge, VME_A24, VME_SCT); - if (image[i].resource == NULL) { + if (!image[i].resource) { dev_warn(&vdev->dev, "Unable to allocate slave resource\n"); err = -ENOMEM; @@ -645,7 +645,7 @@ static int vme_user_probe(struct vme_dev *vdev) image[i].size_buf = PCI_BUF_SIZE; image[i].kern_buf = vme_alloc_consistent(image[i].resource, image[i].size_buf, &image[i].pci_buf); - if (image[i].kern_buf == NULL) { + if (!image[i].kern_buf) { dev_warn(&vdev->dev, "Unable to allocate memory for buffer\n"); image[i].pci_buf = 0; @@ -663,7 +663,7 @@ static int vme_user_probe(struct vme_dev *vdev) /* XXX Need to properly request attributes */ image[i].resource = vme_master_request(vme_user_bridge, VME_A32, VME_SCT, VME_D32); - if (image[i].resource == NULL) { + if (!image[i].resource) { dev_warn(&vdev->dev, "Unable to allocate master resource\n"); err = -ENOMEM; @@ -671,7 +671,7 @@ static int vme_user_probe(struct vme_dev *vdev) } image[i].size_buf = PCI_BUF_SIZE; image[i].kern_buf = kmalloc(image[i].size_buf, GFP_KERNEL); - if (image[i].kern_buf == NULL) { + if (!image[i].kern_buf) { err = -ENOMEM; vme_master_free(image[i].resource); goto err_master; -- cgit v1.3-6-gb490 From 1f0622de0d1fb7de187c7cf729971d56def7814e Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Fri, 26 Jun 2015 23:39:39 +0300 Subject: staging: vme_user: fix kmalloc style Signed-off-by: Dmitry Kalinkin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 2ff15f081776..3467cde5ac6c 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -526,7 +526,7 @@ static int vme_user_master_mmap(unsigned int minor, struct vm_area_struct *vma) return err; } - vma_priv = kmalloc(sizeof(struct vme_user_vma_priv), GFP_KERNEL); + vma_priv = kmalloc(sizeof(*vma_priv), GFP_KERNEL); if (!vma_priv) { mutex_unlock(&image[minor].mutex); return -ENOMEM; -- cgit v1.3-6-gb490 From 8e4d138cc083bb960271e79832982e982c35d219 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Fri, 26 Jun 2015 23:39:40 +0300 Subject: staging: vme_user: allow large read()/write() This changes large master transfers to do shorter read/write rather than return -EINVAL. User space will now be able to optimistically request a large transfer and get at least some data. This also removes comments suggesting on how to implement large transfers. Current vme_master_* read and write implementations use CPU copies that don't produce burst PCI accesses and subsequently no block transfer on VME bus. In the end overall performance is quiet low and it can't be fixed by doing direct copy to user space. Much easier solution would be to just reuse kernel buffer. Signed-off-by: Dmitry Kalinkin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 73 +++++++++++----------------------- 1 file changed, 24 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 3467cde5ac6c..a2345db91e85 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -120,75 +120,50 @@ struct vme_user_vma_priv { atomic_t refcnt; }; -/* - * We are going ot alloc a page during init per window for small transfers. - * Small transfers will go VME -> buffer -> user space. Larger (more than a - * page) transfers will lock the user space buffer into memory and then - * transfer the data directly into the user space buffers. - */ static ssize_t resource_to_user(int minor, char __user *buf, size_t count, loff_t *ppos) { ssize_t retval; ssize_t copied = 0; - if (count <= image[minor].size_buf) { - /* We copy to kernel buffer */ - copied = vme_master_read(image[minor].resource, - image[minor].kern_buf, count, *ppos); - if (copied < 0) - return (int)copied; - - retval = __copy_to_user(buf, image[minor].kern_buf, - (unsigned long)copied); - if (retval != 0) { - copied = (copied - retval); - pr_info("User copy failed\n"); - return -EINVAL; - } + if (count > image[minor].size_buf) + count = image[minor].size_buf; - } else { - /* XXX Need to write this */ - pr_info("Currently don't support large transfers\n"); - /* Map in pages from userspace */ + /* We copy to kernel buffer */ + copied = vme_master_read(image[minor].resource, image[minor].kern_buf, + count, *ppos); + if (copied < 0) + return (int)copied; - /* Call vme_master_read to do the transfer */ + retval = __copy_to_user(buf, image[minor].kern_buf, + (unsigned long)copied); + if (retval != 0) { + copied = (copied - retval); + pr_info("User copy failed\n"); return -EINVAL; } return copied; } -/* - * We are going to alloc a page during init per window for small transfers. - * Small transfers will go user space -> buffer -> VME. Larger (more than a - * page) transfers will lock the user space buffer into memory and then - * transfer the data directly from the user space buffers out to VME. - */ static ssize_t resource_from_user(unsigned int minor, const char __user *buf, size_t count, loff_t *ppos) { ssize_t retval; ssize_t copied = 0; - if (count <= image[minor].size_buf) { - retval = __copy_from_user(image[minor].kern_buf, buf, - (unsigned long)count); - if (retval != 0) - copied = (copied - retval); - else - copied = count; - - copied = vme_master_write(image[minor].resource, - image[minor].kern_buf, copied, *ppos); - } else { - /* XXX Need to write this */ - pr_info("Currently don't support large transfers\n"); - /* Map in pages from userspace */ - - /* Call vme_master_write to do the transfer */ - return -EINVAL; - } + if (count > image[minor].size_buf) + count = image[minor].size_buf; + + retval = __copy_from_user(image[minor].kern_buf, buf, + (unsigned long)count); + if (retval != 0) + copied = (copied - retval); + else + copied = count; + + copied = vme_master_write(image[minor].resource, image[minor].kern_buf, + copied, *ppos); return copied; } -- cgit v1.3-6-gb490 From 7c78e0cdd0baaea087f342330ec1cc44cf4312e8 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Fri, 26 Jun 2015 23:39:41 +0300 Subject: staging: vme_user: switch to returning -EFAULT on __copy_*_user errors Signed-off-by: Dmitry Kalinkin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 47 ++++++++-------------------------- 1 file changed, 11 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index a2345db91e85..ef876a44e0cf 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -123,7 +123,6 @@ struct vme_user_vma_priv { static ssize_t resource_to_user(int minor, char __user *buf, size_t count, loff_t *ppos) { - ssize_t retval; ssize_t copied = 0; if (count > image[minor].size_buf) @@ -135,13 +134,8 @@ static ssize_t resource_to_user(int minor, char __user *buf, size_t count, if (copied < 0) return (int)copied; - retval = __copy_to_user(buf, image[minor].kern_buf, - (unsigned long)copied); - if (retval != 0) { - copied = (copied - retval); - pr_info("User copy failed\n"); - return -EINVAL; - } + if (__copy_to_user(buf, image[minor].kern_buf, (unsigned long)copied)) + return -EFAULT; return copied; } @@ -149,21 +143,16 @@ static ssize_t resource_to_user(int minor, char __user *buf, size_t count, static ssize_t resource_from_user(unsigned int minor, const char __user *buf, size_t count, loff_t *ppos) { - ssize_t retval; ssize_t copied = 0; if (count > image[minor].size_buf) count = image[minor].size_buf; - retval = __copy_from_user(image[minor].kern_buf, buf, - (unsigned long)count); - if (retval != 0) - copied = (copied - retval); - else - copied = count; + if (__copy_from_user(image[minor].kern_buf, buf, (unsigned long)count)) + return -EFAULT; copied = vme_master_write(image[minor].resource, image[minor].kern_buf, - copied, *ppos); + count, *ppos); return copied; } @@ -172,38 +161,24 @@ static ssize_t buffer_to_user(unsigned int minor, char __user *buf, size_t count, loff_t *ppos) { void *image_ptr; - ssize_t retval; image_ptr = image[minor].kern_buf + *ppos; + if (__copy_to_user(buf, image_ptr, (unsigned long)count)) + return -EFAULT; - retval = __copy_to_user(buf, image_ptr, (unsigned long)count); - if (retval != 0) { - retval = (count - retval); - pr_warn("Partial copy to userspace\n"); - } else - retval = count; - - /* Return number of bytes successfully read */ - return retval; + return count; } static ssize_t buffer_from_user(unsigned int minor, const char __user *buf, size_t count, loff_t *ppos) { void *image_ptr; - size_t retval; image_ptr = image[minor].kern_buf + *ppos; + if (__copy_from_user(image_ptr, buf, (unsigned long)count)) + return -EFAULT; - retval = __copy_from_user(image_ptr, buf, (unsigned long)count); - if (retval != 0) { - retval = (count - retval); - pr_warn("Partial copy to userspace\n"); - } else - retval = count; - - /* Return number of bytes successfully read */ - return retval; + return count; } static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count, -- cgit v1.3-6-gb490 From 457ab28619abd1a87eefbb2615bb54ede51e339f Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Fri, 26 Jun 2015 23:39:42 +0300 Subject: staging: vme_user: remove unused variable Signed-off-by: Dmitry Kalinkin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index ef876a44e0cf..947a38eb9160 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -143,18 +143,14 @@ static ssize_t resource_to_user(int minor, char __user *buf, size_t count, static ssize_t resource_from_user(unsigned int minor, const char __user *buf, size_t count, loff_t *ppos) { - ssize_t copied = 0; - if (count > image[minor].size_buf) count = image[minor].size_buf; if (__copy_from_user(image[minor].kern_buf, buf, (unsigned long)count)) return -EFAULT; - copied = vme_master_write(image[minor].resource, image[minor].kern_buf, - count, *ppos); - - return copied; + return vme_master_write(image[minor].resource, image[minor].kern_buf, + count, *ppos); } static ssize_t buffer_to_user(unsigned int minor, char __user *buf, -- cgit v1.3-6-gb490 From 18f8bee2066a55b7fee478cac0a91d073d3d24a9 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Fri, 26 Jun 2015 23:39:43 +0300 Subject: staging: vme_user: remove distracting comment Signed-off-by: Dmitry Kalinkin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 947a38eb9160..7ca943cf1b92 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -128,7 +128,6 @@ static ssize_t resource_to_user(int minor, char __user *buf, size_t count, if (count > image[minor].size_buf) count = image[minor].size_buf; - /* We copy to kernel buffer */ copied = vme_master_read(image[minor].resource, image[minor].kern_buf, count, *ppos); if (copied < 0) -- cgit v1.3-6-gb490 From 32491f561bffddfc5c3dee87e439f2ec64a6cf80 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Fri, 26 Jun 2015 23:39:44 +0300 Subject: staging: vme_user: remove okcount variable Signed-off-by: Dmitry Kalinkin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 7ca943cf1b92..b3e3c2d546a1 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -182,7 +182,6 @@ static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count, unsigned int minor = MINOR(file_inode(file)->i_rdev); ssize_t retval; size_t image_size; - size_t okcount; if (minor == CONTROL_MINOR) return 0; @@ -200,16 +199,14 @@ static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count, /* Ensure not reading past end of the image */ if (*ppos + count > image_size) - okcount = image_size - *ppos; - else - okcount = count; + count = image_size - *ppos; switch (type[minor]) { case MASTER_MINOR: - retval = resource_to_user(minor, buf, okcount, ppos); + retval = resource_to_user(minor, buf, count, ppos); break; case SLAVE_MINOR: - retval = buffer_to_user(minor, buf, okcount, ppos); + retval = buffer_to_user(minor, buf, count, ppos); break; default: retval = -EINVAL; @@ -228,7 +225,6 @@ static ssize_t vme_user_write(struct file *file, const char __user *buf, unsigned int minor = MINOR(file_inode(file)->i_rdev); ssize_t retval; size_t image_size; - size_t okcount; if (minor == CONTROL_MINOR) return 0; @@ -245,16 +241,14 @@ static ssize_t vme_user_write(struct file *file, const char __user *buf, /* Ensure not reading past end of the image */ if (*ppos + count > image_size) - okcount = image_size - *ppos; - else - okcount = count; + count = image_size - *ppos; switch (type[minor]) { case MASTER_MINOR: - retval = resource_from_user(minor, buf, okcount, ppos); + retval = resource_from_user(minor, buf, count, ppos); break; case SLAVE_MINOR: - retval = buffer_from_user(minor, buf, okcount, ppos); + retval = buffer_from_user(minor, buf, count, ppos); break; default: retval = -EINVAL; -- cgit v1.3-6-gb490 From 78376535c2b9c2d463a801db81fb38dc26c29532 Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:30 -0700 Subject: staging: sm750fb: use tabs for indentation Replace spaces with tabs for indentation to fix the checkpatch.pl error ERROR: code indent should use tabs where possible WARNING: please, no spaces at the start of a line Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_display.c | 100 ++++---- drivers/staging/sm750fb/ddk750_display.h | 2 +- drivers/staging/sm750fb/ddk750_dvi.c | 66 +++--- drivers/staging/sm750fb/ddk750_help.h | 4 +- drivers/staging/sm750fb/ddk750_hwi2c.c | 246 +++++++++---------- drivers/staging/sm750fb/ddk750_mode.c | 142 +++++------ drivers/staging/sm750fb/ddk750_mode.h | 46 ++-- drivers/staging/sm750fb/ddk750_power.c | 254 ++++++++++---------- drivers/staging/sm750fb/ddk750_power.h | 8 +- drivers/staging/sm750fb/ddk750_reg.h | 18 +- drivers/staging/sm750fb/ddk750_sii164.c | 394 +++++++++++++++---------------- drivers/staging/sm750fb/ddk750_sii164.h | 28 +-- drivers/staging/sm750fb/sm750.h | 26 +- drivers/staging/sm750fb/sm750_accel.c | 370 ++++++++++++++--------------- drivers/staging/sm750fb/sm750_accel.h | 4 +- drivers/staging/sm750fb/sm750_help.h | 26 +- drivers/staging/sm750fb/sm750_hw.h | 28 +-- 17 files changed, 881 insertions(+), 881 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c index a3e672056ef8..1c4049f5c575 100644 --- a/drivers/staging/sm750fb/ddk750_display.c +++ b/drivers/staging/sm750fb/ddk750_display.c @@ -24,7 +24,7 @@ static void setDisplayControl(int ctrl, int dispState) /* Timing should be enabled first before enabling the plane * because changing at the same time does not guarantee that * the plane will also enabled or disabled. - */ + */ ulDisplayCtrlReg = FIELD_SET(ulDisplayCtrlReg, PANEL_DISPLAY_CTRL, TIMING, ENABLE); POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg); @@ -135,8 +135,8 @@ static void waitNextVerticalSync(int ctrl, int delay) if(!ctrl){ /* primary controller */ - /* Do not wait when the Primary PLL is off or display control is already off. - This will prevent the software to wait forever. */ + /* Do not wait when the Primary PLL is off or display control is already off. + This will prevent the software to wait forever. */ if ((FIELD_GET(PEEK32(PANEL_PLL_CTRL), PANEL_PLL_CTRL, POWER) == PANEL_PLL_CTRL_POWER_OFF) || (FIELD_GET(PEEK32(PANEL_DISPLAY_CTRL), PANEL_DISPLAY_CTRL, TIMING) == @@ -145,26 +145,26 @@ static void waitNextVerticalSync(int ctrl, int delay) return; } - while (delay-- > 0) - { - /* Wait for end of vsync. */ - do - { - status = FIELD_GET(PEEK32(SYSTEM_CTRL), - SYSTEM_CTRL, - PANEL_VSYNC); - } - while (status == SYSTEM_CTRL_PANEL_VSYNC_ACTIVE); - - /* Wait for start of vsync. */ - do - { - status = FIELD_GET(PEEK32(SYSTEM_CTRL), - SYSTEM_CTRL, - PANEL_VSYNC); - } - while (status == SYSTEM_CTRL_PANEL_VSYNC_INACTIVE); - } + while (delay-- > 0) + { + /* Wait for end of vsync. */ + do + { + status = FIELD_GET(PEEK32(SYSTEM_CTRL), + SYSTEM_CTRL, + PANEL_VSYNC); + } + while (status == SYSTEM_CTRL_PANEL_VSYNC_ACTIVE); + + /* Wait for start of vsync. */ + do + { + status = FIELD_GET(PEEK32(SYSTEM_CTRL), + SYSTEM_CTRL, + PANEL_VSYNC); + } + while (status == SYSTEM_CTRL_PANEL_VSYNC_INACTIVE); + } }else{ @@ -275,33 +275,33 @@ void ddk750_setLogicalDispOut(disp_output_t output) int ddk750_initDVIDisp(void) { - /* Initialize DVI. If the dviInit fail and the VendorID or the DeviceID are - not zeroed, then set the failure flag. If it is zeroe, it might mean - that the system is in Dual CRT Monitor configuration. */ - - /* De-skew enabled with default 111b value. - This will fix some artifacts problem in some mode on board 2.2. - Somehow this fix does not affect board 2.1. - */ - if ((dviInit(1, /* Select Rising Edge */ - 1, /* Select 24-bit bus */ - 0, /* Select Single Edge clock */ - 1, /* Enable HSync as is */ - 1, /* Enable VSync as is */ - 1, /* Enable De-skew */ - 7, /* Set the de-skew setting to maximum setup */ - 1, /* Enable continuous Sync */ - 1, /* Enable PLL Filter */ - 4 /* Use the recommended value for PLL Filter value */ - ) != 0) && (dviGetVendorID() != 0x0000) && (dviGetDeviceID() != 0x0000)) - { - return (-1); - } - - /* TODO: Initialize other display component */ - - /* Success */ - return 0; + /* Initialize DVI. If the dviInit fail and the VendorID or the DeviceID are + not zeroed, then set the failure flag. If it is zeroe, it might mean + that the system is in Dual CRT Monitor configuration. */ + + /* De-skew enabled with default 111b value. + This will fix some artifacts problem in some mode on board 2.2. + Somehow this fix does not affect board 2.1. + */ + if ((dviInit(1, /* Select Rising Edge */ + 1, /* Select 24-bit bus */ + 0, /* Select Single Edge clock */ + 1, /* Enable HSync as is */ + 1, /* Enable VSync as is */ + 1, /* Enable De-skew */ + 7, /* Set the de-skew setting to maximum setup */ + 1, /* Enable continuous Sync */ + 1, /* Enable PLL Filter */ + 4 /* Use the recommended value for PLL Filter value */ + ) != 0) && (dviGetVendorID() != 0x0000) && (dviGetDeviceID() != 0x0000)) + { + return (-1); + } + + /* TODO: Initialize other display component */ + + /* Success */ + return 0; } diff --git a/drivers/staging/sm750fb/ddk750_display.h b/drivers/staging/sm750fb/ddk750_display.h index ae0f84c68de5..018a66184352 100644 --- a/drivers/staging/sm750fb/ddk750_display.h +++ b/drivers/staging/sm750fb/ddk750_display.h @@ -8,7 +8,7 @@ #define PNL_2_OFFSET 0 #define PNL_2_MASK (3 << PNL_2_OFFSET) #define PNL_2_USAGE (PNL_2_MASK << 16) -#define PNL_2_PRI ((0 << PNL_2_OFFSET)|PNL_2_USAGE) +#define PNL_2_PRI ((0 << PNL_2_OFFSET)|PNL_2_USAGE) #define PNL_2_SEC ((2 << PNL_2_OFFSET)|PNL_2_USAGE) diff --git a/drivers/staging/sm750fb/ddk750_dvi.c b/drivers/staging/sm750fb/ddk750_dvi.c index b2bf7e66d5cb..35866fa7a8af 100644 --- a/drivers/staging/sm750fb/ddk750_dvi.c +++ b/drivers/staging/sm750fb/ddk750_dvi.c @@ -12,35 +12,35 @@ static dvi_ctrl_device_t g_dcftSupportedDviController[] = { #ifdef DVI_CTRL_SII164 - { - .pfnInit = sii164InitChip, - .pfnGetVendorId = sii164GetVendorID, - .pfnGetDeviceId = sii164GetDeviceID, + { + .pfnInit = sii164InitChip, + .pfnGetVendorId = sii164GetVendorID, + .pfnGetDeviceId = sii164GetDeviceID, #ifdef SII164_FULL_FUNCTIONS - .pfnResetChip = sii164ResetChip, - .pfnGetChipString = sii164GetChipString, - .pfnSetPower = sii164SetPower, - .pfnEnableHotPlugDetection = sii164EnableHotPlugDetection, - .pfnIsConnected = sii164IsConnected, - .pfnCheckInterrupt = sii164CheckInterrupt, - .pfnClearInterrupt = sii164ClearInterrupt, + .pfnResetChip = sii164ResetChip, + .pfnGetChipString = sii164GetChipString, + .pfnSetPower = sii164SetPower, + .pfnEnableHotPlugDetection = sii164EnableHotPlugDetection, + .pfnIsConnected = sii164IsConnected, + .pfnCheckInterrupt = sii164CheckInterrupt, + .pfnClearInterrupt = sii164ClearInterrupt, #endif - }, + }, #endif }; int dviInit( - unsigned char edgeSelect, - unsigned char busSelect, - unsigned char dualEdgeClkSelect, - unsigned char hsyncEnable, - unsigned char vsyncEnable, - unsigned char deskewEnable, - unsigned char deskewSetting, - unsigned char continuousSyncEnable, - unsigned char pllFilterEnable, - unsigned char pllFilterValue + unsigned char edgeSelect, + unsigned char busSelect, + unsigned char dualEdgeClkSelect, + unsigned char hsyncEnable, + unsigned char vsyncEnable, + unsigned char deskewEnable, + unsigned char deskewSetting, + unsigned char continuousSyncEnable, + unsigned char pllFilterEnable, + unsigned char pllFilterValue ) { dvi_ctrl_device_t *pCurrentDviCtrl; @@ -48,8 +48,8 @@ int dviInit( if(pCurrentDviCtrl->pfnInit != NULL) { return pCurrentDviCtrl->pfnInit(edgeSelect, busSelect, dualEdgeClkSelect, hsyncEnable, - vsyncEnable, deskewEnable, deskewSetting, continuousSyncEnable, - pllFilterEnable, pllFilterValue); + vsyncEnable, deskewEnable, deskewSetting, continuousSyncEnable, + pllFilterEnable, pllFilterValue); } return -1; /* error */ } @@ -64,13 +64,13 @@ int dviInit( */ unsigned short dviGetVendorID(void) { - dvi_ctrl_device_t *pCurrentDviCtrl; + dvi_ctrl_device_t *pCurrentDviCtrl; - pCurrentDviCtrl = g_dcftSupportedDviController; - if (pCurrentDviCtrl != (dvi_ctrl_device_t *)0) - return pCurrentDviCtrl->pfnGetVendorId(); + pCurrentDviCtrl = g_dcftSupportedDviController; + if (pCurrentDviCtrl != (dvi_ctrl_device_t *)0) + return pCurrentDviCtrl->pfnGetVendorId(); - return 0x0000; + return 0x0000; } @@ -83,13 +83,13 @@ unsigned short dviGetVendorID(void) */ unsigned short dviGetDeviceID(void) { - dvi_ctrl_device_t *pCurrentDviCtrl; + dvi_ctrl_device_t *pCurrentDviCtrl; pCurrentDviCtrl = g_dcftSupportedDviController; - if (pCurrentDviCtrl != (dvi_ctrl_device_t *)0) - return pCurrentDviCtrl->pfnGetDeviceId(); + if (pCurrentDviCtrl != (dvi_ctrl_device_t *)0) + return pCurrentDviCtrl->pfnGetDeviceId(); - return 0x0000; + return 0x0000; } #endif diff --git a/drivers/staging/sm750fb/ddk750_help.h b/drivers/staging/sm750fb/ddk750_help.h index 4285b056585a..3b06aed431bd 100644 --- a/drivers/staging/sm750fb/ddk750_help.h +++ b/drivers/staging/sm750fb/ddk750_help.h @@ -12,8 +12,8 @@ #if 0 /* if 718 big endian turned on,be aware that don't use this driver for general use,only for ppc big-endian */ #warning "big endian on target cpu and enable nature big endian support of 718 capability !" -#define PEEK32(addr) __raw_readl(mmio750 + addr) -#define POKE32(addr, data) __raw_writel(data, mmio750 + addr) +#define PEEK32(addr) __raw_readl(mmio750 + addr) +#define POKE32(addr, data) __raw_writel(data, mmio750 + addr) #else /* software control endianness */ #define PEEK32(addr) readl(addr + mmio750) #define POKE32(addr, data) writel(data, addr + mmio750) diff --git a/drivers/staging/sm750fb/ddk750_hwi2c.c b/drivers/staging/sm750fb/ddk750_hwi2c.c index 7826376ed705..7f3b1f931043 100644 --- a/drivers/staging/sm750fb/ddk750_hwi2c.c +++ b/drivers/staging/sm750fb/ddk750_hwi2c.c @@ -10,70 +10,70 @@ int hwI2CInit( - unsigned char busSpeedMode +unsigned char busSpeedMode ) { - unsigned int value; + unsigned int value; - /* Enable GPIO 30 & 31 as IIC clock & data */ + /* Enable GPIO 30 & 31 as IIC clock & data */ value = PEEK32(GPIO_MUX); - value = FIELD_SET(value, GPIO_MUX, 30, I2C) | - FIELD_SET(0, GPIO_MUX, 31, I2C); + value = FIELD_SET(value, GPIO_MUX, 30, I2C) | + FIELD_SET(0, GPIO_MUX, 31, I2C); POKE32(GPIO_MUX, value); - /* Enable Hardware I2C power. - TODO: Check if we need to enable GPIO power? - */ - enableI2C(1); - - /* Enable the I2C Controller and set the bus speed mode */ - value = PEEK32(I2C_CTRL); - if (busSpeedMode == 0) - value = FIELD_SET(value, I2C_CTRL, MODE, STANDARD); - else - value = FIELD_SET(value, I2C_CTRL, MODE, FAST); - value = FIELD_SET(value, I2C_CTRL, EN, ENABLE); - POKE32(I2C_CTRL, value); - - return 0; + /* Enable Hardware I2C power. + TODO: Check if we need to enable GPIO power? + */ + enableI2C(1); + + /* Enable the I2C Controller and set the bus speed mode */ + value = PEEK32(I2C_CTRL); + if (busSpeedMode == 0) + value = FIELD_SET(value, I2C_CTRL, MODE, STANDARD); + else + value = FIELD_SET(value, I2C_CTRL, MODE, FAST); + value = FIELD_SET(value, I2C_CTRL, EN, ENABLE); + POKE32(I2C_CTRL, value); + + return 0; } void hwI2CClose(void) { - unsigned int value; + unsigned int value; - /* Disable I2C controller */ - value = PEEK32(I2C_CTRL); - value = FIELD_SET(value, I2C_CTRL, EN, DISABLE); - POKE32(I2C_CTRL, value); + /* Disable I2C controller */ + value = PEEK32(I2C_CTRL); + value = FIELD_SET(value, I2C_CTRL, EN, DISABLE); + POKE32(I2C_CTRL, value); - /* Disable I2C Power */ - enableI2C(0); + /* Disable I2C Power */ + enableI2C(0); - /* Set GPIO 30 & 31 back as GPIO pins */ - value = PEEK32(GPIO_MUX); - value = FIELD_SET(value, GPIO_MUX, 30, GPIO); - value = FIELD_SET(value, GPIO_MUX, 31, GPIO); - POKE32(GPIO_MUX, value); + /* Set GPIO 30 & 31 back as GPIO pins */ + value = PEEK32(GPIO_MUX); + value = FIELD_SET(value, GPIO_MUX, 30, GPIO); + value = FIELD_SET(value, GPIO_MUX, 31, GPIO); + POKE32(GPIO_MUX, value); } static long hwI2CWaitTXDone(void) { - unsigned int timeout; + unsigned int timeout; - /* Wait until the transfer is completed. */ - timeout = HWI2C_WAIT_TIMEOUT; + /* Wait until the transfer is completed. */ + timeout = HWI2C_WAIT_TIMEOUT; while ((FIELD_GET(PEEK32(I2C_STATUS), I2C_STATUS, TX) != I2C_STATUS_TX_COMPLETED) && - (timeout != 0)) + (timeout != 0)) timeout--; if (timeout == 0) - return (-1); + return (-1); - return 0; + return 0; } @@ -91,53 +91,53 @@ static long hwI2CWaitTXDone(void) * Total number of bytes those are actually written. */ static unsigned int hwI2CWriteData( - unsigned char deviceAddress, - unsigned int length, - unsigned char *pBuffer + unsigned char deviceAddress, + unsigned int length, + unsigned char *pBuffer ) { - unsigned char count, i; - unsigned int totalBytes = 0; + unsigned char count, i; + unsigned int totalBytes = 0; - /* Set the Device Address */ - POKE32(I2C_SLAVE_ADDRESS, deviceAddress & ~0x01); + /* Set the Device Address */ + POKE32(I2C_SLAVE_ADDRESS, deviceAddress & ~0x01); - /* Write data. - * Note: - * Only 16 byte can be accessed per i2c start instruction. - */ - do - { - /* Reset I2C by writing 0 to I2C_RESET register to clear the previous status. */ - POKE32(I2C_RESET, 0); + /* Write data. + * Note: + * Only 16 byte can be accessed per i2c start instruction. + */ + do + { + /* Reset I2C by writing 0 to I2C_RESET register to clear the previous status. */ + POKE32(I2C_RESET, 0); - /* Set the number of bytes to be written */ - if (length < MAX_HWI2C_FIFO) - count = length - 1; - else - count = MAX_HWI2C_FIFO - 1; - POKE32(I2C_BYTE_COUNT, count); + /* Set the number of bytes to be written */ + if (length < MAX_HWI2C_FIFO) + count = length - 1; + else + count = MAX_HWI2C_FIFO - 1; + POKE32(I2C_BYTE_COUNT, count); - /* Move the data to the I2C data register */ - for (i = 0; i <= count; i++) - POKE32(I2C_DATA0 + i, *pBuffer++); + /* Move the data to the I2C data register */ + for (i = 0; i <= count; i++) + POKE32(I2C_DATA0 + i, *pBuffer++); - /* Start the I2C */ - POKE32(I2C_CTRL, FIELD_SET(PEEK32(I2C_CTRL), I2C_CTRL, CTRL, START)); + /* Start the I2C */ + POKE32(I2C_CTRL, FIELD_SET(PEEK32(I2C_CTRL), I2C_CTRL, CTRL, START)); - /* Wait until the transfer is completed. */ - if (hwI2CWaitTXDone() != 0) - break; + /* Wait until the transfer is completed. */ + if (hwI2CWaitTXDone() != 0) + break; - /* Substract length */ - length -= (count + 1); + /* Substract length */ + length -= (count + 1); - /* Total byte written */ - totalBytes += (count + 1); + /* Total byte written */ + totalBytes += (count + 1); - } while (length > 0); + } while (length > 0); - return totalBytes; + return totalBytes; } @@ -158,53 +158,53 @@ static unsigned int hwI2CWriteData( * Total number of actual bytes read from the slave device */ static unsigned int hwI2CReadData( - unsigned char deviceAddress, - unsigned int length, - unsigned char *pBuffer + unsigned char deviceAddress, + unsigned int length, + unsigned char *pBuffer ) { - unsigned char count, i; - unsigned int totalBytes = 0; + unsigned char count, i; + unsigned int totalBytes = 0; - /* Set the Device Address */ - POKE32(I2C_SLAVE_ADDRESS, deviceAddress | 0x01); + /* Set the Device Address */ + POKE32(I2C_SLAVE_ADDRESS, deviceAddress | 0x01); - /* Read data and save them to the buffer. - * Note: - * Only 16 byte can be accessed per i2c start instruction. - */ - do - { - /* Reset I2C by writing 0 to I2C_RESET register to clear all the status. */ - POKE32(I2C_RESET, 0); + /* Read data and save them to the buffer. + * Note: + * Only 16 byte can be accessed per i2c start instruction. + */ + do + { + /* Reset I2C by writing 0 to I2C_RESET register to clear all the status. */ + POKE32(I2C_RESET, 0); - /* Set the number of bytes to be read */ - if (length <= MAX_HWI2C_FIFO) - count = length - 1; - else - count = MAX_HWI2C_FIFO - 1; - POKE32(I2C_BYTE_COUNT, count); + /* Set the number of bytes to be read */ + if (length <= MAX_HWI2C_FIFO) + count = length - 1; + else + count = MAX_HWI2C_FIFO - 1; + POKE32(I2C_BYTE_COUNT, count); - /* Start the I2C */ - POKE32(I2C_CTRL, FIELD_SET(PEEK32(I2C_CTRL), I2C_CTRL, CTRL, START)); + /* Start the I2C */ + POKE32(I2C_CTRL, FIELD_SET(PEEK32(I2C_CTRL), I2C_CTRL, CTRL, START)); - /* Wait until transaction done. */ - if (hwI2CWaitTXDone() != 0) - break; + /* Wait until transaction done. */ + if (hwI2CWaitTXDone() != 0) + break; - /* Save the data to the given buffer */ - for (i = 0; i <= count; i++) - *pBuffer++ = PEEK32(I2C_DATA0 + i); + /* Save the data to the given buffer */ + for (i = 0; i <= count; i++) + *pBuffer++ = PEEK32(I2C_DATA0 + i); - /* Substract length by 16 */ - length -= (count + 1); + /* Substract length by 16 */ + length -= (count + 1); - /* Number of bytes read. */ - totalBytes += (count + 1); + /* Number of bytes read. */ + totalBytes += (count + 1); - } while (length > 0); + } while (length > 0); - return totalBytes; + return totalBytes; } @@ -222,16 +222,16 @@ static unsigned int hwI2CReadData( * Register value */ unsigned char hwI2CReadReg( - unsigned char deviceAddress, - unsigned char registerIndex + unsigned char deviceAddress, + unsigned char registerIndex ) { - unsigned char value = (0xFF); + unsigned char value = (0xFF); - if (hwI2CWriteData(deviceAddress, 1, ®isterIndex) == 1) - hwI2CReadData(deviceAddress, 1, &value); + if (hwI2CWriteData(deviceAddress, 1, ®isterIndex) == 1) + hwI2CReadData(deviceAddress, 1, &value); - return value; + return value; } @@ -252,19 +252,19 @@ unsigned char hwI2CReadReg( * -1 - Fail */ int hwI2CWriteReg( - unsigned char deviceAddress, - unsigned char registerIndex, - unsigned char data + unsigned char deviceAddress, + unsigned char registerIndex, + unsigned char data ) { - unsigned char value[2]; + unsigned char value[2]; - value[0] = registerIndex; - value[1] = data; - if (hwI2CWriteData(deviceAddress, 2, value) == 2) - return 0; + value[0] = registerIndex; + value[1] = data; + if (hwI2CWriteData(deviceAddress, 2, value) == 2) + return 0; - return (-1); + return (-1); } diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c index 74313ff84e45..1f93d07377fc 100644 --- a/drivers/staging/sm750fb/ddk750_mode.c +++ b/drivers/staging/sm750fb/ddk750_mode.c @@ -20,54 +20,54 @@ static unsigned long displayControlAdjust_SM750LE(mode_parameter_t *pModeParam, x = pModeParam->horizontal_display_end; y = pModeParam->vertical_display_end; - /* SM750LE has to set up the top-left and bottom-right - registers as well. - Note that normal SM750/SM718 only use those two register for - auto-centering mode. - */ - POKE32(CRT_AUTO_CENTERING_TL, - FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, TOP, 0) - | FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, LEFT, 0)); - - POKE32(CRT_AUTO_CENTERING_BR, - FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, BOTTOM, y-1) - | FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, RIGHT, x-1)); - - /* Assume common fields in dispControl have been properly set before - calling this function. - This function only sets the extra fields in dispControl. - */ + /* SM750LE has to set up the top-left and bottom-right + registers as well. + Note that normal SM750/SM718 only use those two register for + auto-centering mode. + */ + POKE32(CRT_AUTO_CENTERING_TL, + FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, TOP, 0) + | FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, LEFT, 0)); + + POKE32(CRT_AUTO_CENTERING_BR, + FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, BOTTOM, y-1) + | FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, RIGHT, x-1)); + + /* Assume common fields in dispControl have been properly set before + calling this function. + This function only sets the extra fields in dispControl. + */ /* Clear bit 29:27 of display control register */ - dispControl &= FIELD_CLEAR(CRT_DISPLAY_CTRL, CLK); + dispControl &= FIELD_CLEAR(CRT_DISPLAY_CTRL, CLK); /* Set bit 29:27 of display control register for the right clock */ /* Note that SM750LE only need to supported 7 resoluitons. */ if ( x == 800 && y == 600 ) - dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL41); + dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL41); else if (x == 1024 && y == 768) - dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL65); + dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL65); else if (x == 1152 && y == 864) - dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL80); + dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL80); else if (x == 1280 && y == 768) - dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL80); + dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL80); else if (x == 1280 && y == 720) - dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL74); + dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL74); else if (x == 1280 && y == 960) - dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL108); + dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL108); else if (x == 1280 && y == 1024) - dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL108); + dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL108); else /* default to VGA clock */ - dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL25); + dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL25); /* Set bit 25:24 of display controller */ - dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CRTSELECT, CRT); - dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, RGBBIT, 24BIT); + dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CRTSELECT, CRT); + dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, RGBBIT, 24BIT); - /* Set bit 14 of display controller */ - dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW); + /* Set bit 14 of display controller */ + dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLOCK_PHASE, ACTIVE_LOW); - POKE32(CRT_DISPLAY_CTRL, dispControl); + POKE32(CRT_DISPLAY_CTRL, dispControl); return dispControl; } @@ -84,21 +84,21 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) { /* programe secondary pixel clock */ POKE32(CRT_PLL_CTRL, formatPllReg(pll)); - POKE32(CRT_HORIZONTAL_TOTAL, - FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1) - | FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1)); + POKE32(CRT_HORIZONTAL_TOTAL, + FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1) + | FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1)); - POKE32(CRT_HORIZONTAL_SYNC, - FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width) - | FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1)); + POKE32(CRT_HORIZONTAL_SYNC, + FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width) + | FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1)); - POKE32(CRT_VERTICAL_TOTAL, - FIELD_VALUE(0, CRT_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1) - | FIELD_VALUE(0, CRT_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1)); + POKE32(CRT_VERTICAL_TOTAL, + FIELD_VALUE(0, CRT_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1) + | FIELD_VALUE(0, CRT_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1)); - POKE32(CRT_VERTICAL_SYNC, - FIELD_VALUE(0, CRT_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height) - | FIELD_VALUE(0, CRT_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1)); + POKE32(CRT_VERTICAL_SYNC, + FIELD_VALUE(0, CRT_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height) + | FIELD_VALUE(0, CRT_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1)); ulTmpValue = FIELD_VALUE(0, CRT_DISPLAY_CTRL, VSYNC_PHASE, pModeParam->vertical_sync_polarity)| @@ -125,39 +125,39 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) unsigned int ulReservedBits; POKE32(PANEL_PLL_CTRL, formatPllReg(pll)); - POKE32(PANEL_HORIZONTAL_TOTAL, - FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1) - | FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1)); + POKE32(PANEL_HORIZONTAL_TOTAL, + FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1) + | FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1)); - POKE32(PANEL_HORIZONTAL_SYNC, - FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width) - | FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1)); + POKE32(PANEL_HORIZONTAL_SYNC, + FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width) + | FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1)); - POKE32(PANEL_VERTICAL_TOTAL, - FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1) - | FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1)); + POKE32(PANEL_VERTICAL_TOTAL, + FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1) + | FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1)); - POKE32(PANEL_VERTICAL_SYNC, - FIELD_VALUE(0, PANEL_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height) - | FIELD_VALUE(0, PANEL_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1)); + POKE32(PANEL_VERTICAL_SYNC, + FIELD_VALUE(0, PANEL_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height) + | FIELD_VALUE(0, PANEL_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1)); ulTmpValue = FIELD_VALUE(0, PANEL_DISPLAY_CTRL, VSYNC_PHASE, pModeParam->vertical_sync_polarity)| - FIELD_VALUE(0, PANEL_DISPLAY_CTRL, HSYNC_PHASE, pModeParam->horizontal_sync_polarity)| - FIELD_VALUE(0, PANEL_DISPLAY_CTRL, CLOCK_PHASE, pModeParam->clock_phase_polarity)| - FIELD_SET(0, PANEL_DISPLAY_CTRL, TIMING, ENABLE)| - FIELD_SET(0, PANEL_DISPLAY_CTRL, PLANE, ENABLE); - - ulReservedBits = FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) | - FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) | - FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE)| - FIELD_SET(0, PANEL_DISPLAY_CTRL, VSYNC, ACTIVE_LOW); - - ulReg = (PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) - & FIELD_CLEAR(PANEL_DISPLAY_CTRL, CLOCK_PHASE) - & FIELD_CLEAR(PANEL_DISPLAY_CTRL, VSYNC_PHASE) - & FIELD_CLEAR(PANEL_DISPLAY_CTRL, HSYNC_PHASE) - & FIELD_CLEAR(PANEL_DISPLAY_CTRL, TIMING) - & FIELD_CLEAR(PANEL_DISPLAY_CTRL, PLANE); + FIELD_VALUE(0, PANEL_DISPLAY_CTRL, HSYNC_PHASE, pModeParam->horizontal_sync_polarity)| + FIELD_VALUE(0, PANEL_DISPLAY_CTRL, CLOCK_PHASE, pModeParam->clock_phase_polarity)| + FIELD_SET(0, PANEL_DISPLAY_CTRL, TIMING, ENABLE)| + FIELD_SET(0, PANEL_DISPLAY_CTRL, PLANE, ENABLE); + + ulReservedBits = FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) | + FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) | + FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE)| + FIELD_SET(0, PANEL_DISPLAY_CTRL, VSYNC, ACTIVE_LOW); + + ulReg = (PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) + & FIELD_CLEAR(PANEL_DISPLAY_CTRL, CLOCK_PHASE) + & FIELD_CLEAR(PANEL_DISPLAY_CTRL, VSYNC_PHASE) + & FIELD_CLEAR(PANEL_DISPLAY_CTRL, HSYNC_PHASE) + & FIELD_CLEAR(PANEL_DISPLAY_CTRL, TIMING) + & FIELD_CLEAR(PANEL_DISPLAY_CTRL, PLANE); /* May a hardware bug or just my test chip (not confirmed). diff --git a/drivers/staging/sm750fb/ddk750_mode.h b/drivers/staging/sm750fb/ddk750_mode.h index 4e8fab3f17e4..3548d671bf97 100644 --- a/drivers/staging/sm750fb/ddk750_mode.h +++ b/drivers/staging/sm750fb/ddk750_mode.h @@ -5,35 +5,35 @@ typedef enum _spolarity_t { - POS = 0, /* positive */ - NEG, /* negative */ + POS = 0, /* positive */ + NEG, /* negative */ } spolarity_t; typedef struct _mode_parameter_t { - /* Horizontal timing. */ - unsigned long horizontal_total; - unsigned long horizontal_display_end; - unsigned long horizontal_sync_start; - unsigned long horizontal_sync_width; - spolarity_t horizontal_sync_polarity; - - /* Vertical timing. */ - unsigned long vertical_total; - unsigned long vertical_display_end; - unsigned long vertical_sync_start; - unsigned long vertical_sync_height; - spolarity_t vertical_sync_polarity; - - /* Refresh timing. */ - unsigned long pixel_clock; - unsigned long horizontal_frequency; - unsigned long vertical_frequency; - - /* Clock Phase. This clock phase only applies to Panel. */ - spolarity_t clock_phase_polarity; + /* Horizontal timing. */ + unsigned long horizontal_total; + unsigned long horizontal_display_end; + unsigned long horizontal_sync_start; + unsigned long horizontal_sync_width; + spolarity_t horizontal_sync_polarity; + + /* Vertical timing. */ + unsigned long vertical_total; + unsigned long vertical_display_end; + unsigned long vertical_sync_start; + unsigned long vertical_sync_height; + spolarity_t vertical_sync_polarity; + + /* Refresh timing. */ + unsigned long pixel_clock; + unsigned long horizontal_frequency; + unsigned long vertical_frequency; + + /* Clock Phase. This clock phase only applies to Panel. */ + spolarity_t clock_phase_polarity; } mode_parameter_t; diff --git a/drivers/staging/sm750fb/ddk750_power.c b/drivers/staging/sm750fb/ddk750_power.c index 1e5f398aed10..b7a108b46e5c 100644 --- a/drivers/staging/sm750fb/ddk750_power.c +++ b/drivers/staging/sm750fb/ddk750_power.c @@ -19,7 +19,7 @@ unsigned int getPowerMode(void) { if(getChipType() == SM750LE) return 0; - return (FIELD_GET(PEEK32(POWER_MODE_CTRL), POWER_MODE_CTRL, MODE)); + return (FIELD_GET(PEEK32(POWER_MODE_CTRL), POWER_MODE_CTRL, MODE)); } @@ -29,76 +29,76 @@ unsigned int getPowerMode(void) */ void setPowerMode(unsigned int powerMode) { - unsigned int control_value = 0; + unsigned int control_value = 0; - control_value = PEEK32(POWER_MODE_CTRL); + control_value = PEEK32(POWER_MODE_CTRL); if(getChipType() == SM750LE) return; - switch (powerMode) - { - case POWER_MODE_CTRL_MODE_MODE0: - control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE0); - break; + switch (powerMode) + { + case POWER_MODE_CTRL_MODE_MODE0: + control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE0); + break; - case POWER_MODE_CTRL_MODE_MODE1: - control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE1); - break; + case POWER_MODE_CTRL_MODE_MODE1: + control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE1); + break; - case POWER_MODE_CTRL_MODE_SLEEP: - control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, SLEEP); - break; + case POWER_MODE_CTRL_MODE_SLEEP: + control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, SLEEP); + break; - default: - break; - } + default: + break; + } - /* Set up other fields in Power Control Register */ - if (powerMode == POWER_MODE_CTRL_MODE_SLEEP) - { - control_value = + /* Set up other fields in Power Control Register */ + if (powerMode == POWER_MODE_CTRL_MODE_SLEEP) + { + control_value = #ifdef VALIDATION_CHIP - FIELD_SET( control_value, POWER_MODE_CTRL, 336CLK, OFF) | + FIELD_SET( control_value, POWER_MODE_CTRL, 336CLK, OFF) | #endif - FIELD_SET( control_value, POWER_MODE_CTRL, OSC_INPUT, OFF); - } - else - { - control_value = + FIELD_SET( control_value, POWER_MODE_CTRL, OSC_INPUT, OFF); + } + else + { + control_value = #ifdef VALIDATION_CHIP - FIELD_SET( control_value, POWER_MODE_CTRL, 336CLK, ON) | + FIELD_SET( control_value, POWER_MODE_CTRL, 336CLK, ON) | #endif - FIELD_SET( control_value, POWER_MODE_CTRL, OSC_INPUT, ON); - } + FIELD_SET( control_value, POWER_MODE_CTRL, OSC_INPUT, ON); + } - /* Program new power mode. */ - POKE32(POWER_MODE_CTRL, control_value); + /* Program new power mode. */ + POKE32(POWER_MODE_CTRL, control_value); } void setCurrentGate(unsigned int gate) { - unsigned int gate_reg; - unsigned int mode; - - /* Get current power mode. */ - mode = getPowerMode(); - - switch (mode) - { - case POWER_MODE_CTRL_MODE_MODE0: - gate_reg = MODE0_GATE; - break; - - case POWER_MODE_CTRL_MODE_MODE1: - gate_reg = MODE1_GATE; - break; - - default: - gate_reg = MODE0_GATE; - break; - } - POKE32(gate_reg, gate); + unsigned int gate_reg; + unsigned int mode; + + /* Get current power mode. */ + mode = getPowerMode(); + + switch (mode) + { + case POWER_MODE_CTRL_MODE_MODE0: + gate_reg = MODE0_GATE; + break; + + case POWER_MODE_CTRL_MODE_MODE1: + gate_reg = MODE1_GATE; + break; + + default: + gate_reg = MODE0_GATE; + break; + } + POKE32(gate_reg, gate); } @@ -108,21 +108,21 @@ void setCurrentGate(unsigned int gate) */ void enable2DEngine(unsigned int enable) { - uint32_t gate; - - gate = PEEK32(CURRENT_GATE); - if (enable) - { - gate = FIELD_SET(gate, CURRENT_GATE, DE, ON); - gate = FIELD_SET(gate, CURRENT_GATE, CSC, ON); - } - else - { - gate = FIELD_SET(gate, CURRENT_GATE, DE, OFF); - gate = FIELD_SET(gate, CURRENT_GATE, CSC, OFF); - } - - setCurrentGate(gate); + uint32_t gate; + + gate = PEEK32(CURRENT_GATE); + if (enable) + { + gate = FIELD_SET(gate, CURRENT_GATE, DE, ON); + gate = FIELD_SET(gate, CURRENT_GATE, CSC, ON); + } + else + { + gate = FIELD_SET(gate, CURRENT_GATE, DE, OFF); + gate = FIELD_SET(gate, CURRENT_GATE, CSC, OFF); + } + + setCurrentGate(gate); } @@ -131,58 +131,58 @@ void enable2DEngine(unsigned int enable) */ void enableZVPort(unsigned int enable) { - uint32_t gate; + uint32_t gate; - /* Enable ZV Port Gate */ - gate = PEEK32(CURRENT_GATE); - if (enable) - { - gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, ON); + /* Enable ZV Port Gate */ + gate = PEEK32(CURRENT_GATE); + if (enable) + { + gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, ON); #if 1 - /* Using Software I2C */ - gate = FIELD_SET(gate, CURRENT_GATE, GPIO, ON); + /* Using Software I2C */ + gate = FIELD_SET(gate, CURRENT_GATE, GPIO, ON); #else - /* Using Hardware I2C */ - gate = FIELD_SET(gate, CURRENT_GATE, I2C, ON); + /* Using Hardware I2C */ + gate = FIELD_SET(gate, CURRENT_GATE, I2C, ON); #endif - } - else - { - /* Disable ZV Port Gate. There is no way to know whether the GPIO pins are being used - or not. Therefore, do not disable the GPIO gate. */ - gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, OFF); - } - - setCurrentGate(gate); + } + else + { + /* Disable ZV Port Gate. There is no way to know whether the GPIO pins are being used + or not. Therefore, do not disable the GPIO gate. */ + gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, OFF); + } + + setCurrentGate(gate); } void enableSSP(unsigned int enable) { - uint32_t gate; + uint32_t gate; - /* Enable SSP Gate */ - gate = PEEK32(CURRENT_GATE); - if (enable) - gate = FIELD_SET(gate, CURRENT_GATE, SSP, ON); - else - gate = FIELD_SET(gate, CURRENT_GATE, SSP, OFF); + /* Enable SSP Gate */ + gate = PEEK32(CURRENT_GATE); + if (enable) + gate = FIELD_SET(gate, CURRENT_GATE, SSP, ON); + else + gate = FIELD_SET(gate, CURRENT_GATE, SSP, OFF); - setCurrentGate(gate); + setCurrentGate(gate); } void enableDMA(unsigned int enable) { - uint32_t gate; + uint32_t gate; - /* Enable DMA Gate */ - gate = PEEK32(CURRENT_GATE); - if (enable) - gate = FIELD_SET(gate, CURRENT_GATE, DMA, ON); - else - gate = FIELD_SET(gate, CURRENT_GATE, DMA, OFF); + /* Enable DMA Gate */ + gate = PEEK32(CURRENT_GATE); + if (enable) + gate = FIELD_SET(gate, CURRENT_GATE, DMA, ON); + else + gate = FIELD_SET(gate, CURRENT_GATE, DMA, OFF); - setCurrentGate(gate); + setCurrentGate(gate); } /* @@ -190,16 +190,16 @@ void enableDMA(unsigned int enable) */ void enableGPIO(unsigned int enable) { - uint32_t gate; + uint32_t gate; - /* Enable GPIO Gate */ - gate = PEEK32(CURRENT_GATE); - if (enable) - gate = FIELD_SET(gate, CURRENT_GATE, GPIO, ON); - else - gate = FIELD_SET(gate, CURRENT_GATE, GPIO, OFF); + /* Enable GPIO Gate */ + gate = PEEK32(CURRENT_GATE); + if (enable) + gate = FIELD_SET(gate, CURRENT_GATE, GPIO, ON); + else + gate = FIELD_SET(gate, CURRENT_GATE, GPIO, OFF); - setCurrentGate(gate); + setCurrentGate(gate); } /* @@ -207,16 +207,16 @@ void enableGPIO(unsigned int enable) */ void enablePWM(unsigned int enable) { - uint32_t gate; + uint32_t gate; - /* Enable PWM Gate */ - gate = PEEK32(CURRENT_GATE); - if (enable) - gate = FIELD_SET(gate, CURRENT_GATE, PWM, ON); - else - gate = FIELD_SET(gate, CURRENT_GATE, PWM, OFF); + /* Enable PWM Gate */ + gate = PEEK32(CURRENT_GATE); + if (enable) + gate = FIELD_SET(gate, CURRENT_GATE, PWM, ON); + else + gate = FIELD_SET(gate, CURRENT_GATE, PWM, OFF); - setCurrentGate(gate); + setCurrentGate(gate); } /* @@ -224,16 +224,16 @@ void enablePWM(unsigned int enable) */ void enableI2C(unsigned int enable) { - uint32_t gate; + uint32_t gate; - /* Enable I2C Gate */ - gate = PEEK32(CURRENT_GATE); - if (enable) - gate = FIELD_SET(gate, CURRENT_GATE, I2C, ON); - else - gate = FIELD_SET(gate, CURRENT_GATE, I2C, OFF); + /* Enable I2C Gate */ + gate = PEEK32(CURRENT_GATE); + if (enable) + gate = FIELD_SET(gate, CURRENT_GATE, I2C, ON); + else + gate = FIELD_SET(gate, CURRENT_GATE, I2C, OFF); - setCurrentGate(gate); + setCurrentGate(gate); } diff --git a/drivers/staging/sm750fb/ddk750_power.h b/drivers/staging/sm750fb/ddk750_power.h index 4e00955a07dd..a20d43863c33 100644 --- a/drivers/staging/sm750fb/ddk750_power.h +++ b/drivers/staging/sm750fb/ddk750_power.h @@ -3,10 +3,10 @@ typedef enum _DPMS_t { - crtDPMS_ON = 0x0, - crtDPMS_STANDBY = 0x1, - crtDPMS_SUSPEND = 0x2, - crtDPMS_OFF = 0x3, + crtDPMS_ON = 0x0, + crtDPMS_STANDBY = 0x1, + crtDPMS_SUSPEND = 0x2, + crtDPMS_OFF = 0x3, } DPMS_t; diff --git a/drivers/staging/sm750fb/ddk750_reg.h b/drivers/staging/sm750fb/ddk750_reg.h index 1a40dc2a2f75..2995625c3d62 100644 --- a/drivers/staging/sm750fb/ddk750_reg.h +++ b/drivers/staging/sm750fb/ddk750_reg.h @@ -1640,9 +1640,9 @@ /* CRT Graphics Control */ #define CRT_DISPLAY_CTRL 0x080200 -#define CRT_DISPLAY_CTRL_RESERVED_1_MASK 31:27 -#define CRT_DISPLAY_CTRL_RESERVED_1_MASK_DISABLE 0 -#define CRT_DISPLAY_CTRL_RESERVED_1_MASK_ENABLE 0x1F +#define CRT_DISPLAY_CTRL_RESERVED_1_MASK 31:27 +#define CRT_DISPLAY_CTRL_RESERVED_1_MASK_DISABLE 0 +#define CRT_DISPLAY_CTRL_RESERVED_1_MASK_ENABLE 0x1F /* SM750LE definition */ #define CRT_DISPLAY_CTRL_DPMS 31:30 @@ -1664,9 +1664,9 @@ #define CRT_DISPLAY_CTRL_SHIFT_VGA_DAC_ENABLE 0 -#define CRT_DISPLAY_CTRL_RESERVED_2_MASK 25:24 -#define CRT_DISPLAY_CTRL_RESERVED_2_MASK_ENABLE 3 -#define CRT_DISPLAY_CTRL_RESERVED_2_MASK_DISABLE 0 +#define CRT_DISPLAY_CTRL_RESERVED_2_MASK 25:24 +#define CRT_DISPLAY_CTRL_RESERVED_2_MASK_ENABLE 3 +#define CRT_DISPLAY_CTRL_RESERVED_2_MASK_DISABLE 0 /* SM750LE definition */ #define CRT_DISPLAY_CTRL_CRTSELECT 25:25 @@ -1677,11 +1677,11 @@ #define CRT_DISPLAY_CTRL_RGBBIT_12BIT 1 -#define CRT_DISPLAY_CTRL_RESERVED_3_MASK 15:15 +#define CRT_DISPLAY_CTRL_RESERVED_3_MASK 15:15 #define CRT_DISPLAY_CTRL_RESERVED_3_MASK_DISABLE 0 #define CRT_DISPLAY_CTRL_RESERVED_3_MASK_ENABLE 1 -#define CRT_DISPLAY_CTRL_RESERVED_4_MASK 9:9 +#define CRT_DISPLAY_CTRL_RESERVED_4_MASK 9:9 #define CRT_DISPLAY_CTRL_RESERVED_4_MASK_DISABLE 0 #define CRT_DISPLAY_CTRL_RESERVED_4_MASK_ENABLE 1 @@ -1882,7 +1882,7 @@ #endif /* sm750le new register to control panel output */ -#define DISPLAY_CONTROL_750LE 0x80288 +#define DISPLAY_CONTROL_750LE 0x80288 /* Palette RAM */ /* Panel Palette register starts at 0x080400 ~ 0x0807FC */ diff --git a/drivers/staging/sm750fb/ddk750_sii164.c b/drivers/staging/sm750fb/ddk750_sii164.c index b6395b87fc21..7f58fbecd35f 100644 --- a/drivers/staging/sm750fb/ddk750_sii164.c +++ b/drivers/staging/sm750fb/ddk750_sii164.c @@ -36,12 +36,12 @@ static char *gDviCtrlChipName = "Silicon Image SiI 164"; */ unsigned short sii164GetVendorID(void) { - unsigned short vendorID; + unsigned short vendorID; - vendorID = ((unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_HIGH) << 8) | - (unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_LOW); + vendorID = ((unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_HIGH) << 8) | + (unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_LOW); - return vendorID; + return vendorID; } /* @@ -53,12 +53,12 @@ unsigned short sii164GetVendorID(void) */ unsigned short sii164GetDeviceID(void) { - unsigned short deviceID; + unsigned short deviceID; - deviceID = ((unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_HIGH) << 8) | - (unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_LOW); + deviceID = ((unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_HIGH) << 8) | + (unsigned short) i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_LOW); - return deviceID; + return deviceID; } @@ -113,132 +113,132 @@ unsigned short sii164GetDeviceID(void) * -1 - Fail. */ long sii164InitChip( - unsigned char edgeSelect, - unsigned char busSelect, - unsigned char dualEdgeClkSelect, - unsigned char hsyncEnable, - unsigned char vsyncEnable, - unsigned char deskewEnable, - unsigned char deskewSetting, - unsigned char continuousSyncEnable, - unsigned char pllFilterEnable, - unsigned char pllFilterValue + unsigned char edgeSelect, + unsigned char busSelect, + unsigned char dualEdgeClkSelect, + unsigned char hsyncEnable, + unsigned char vsyncEnable, + unsigned char deskewEnable, + unsigned char deskewSetting, + unsigned char continuousSyncEnable, + unsigned char pllFilterEnable, + unsigned char pllFilterValue ) { unsigned char config; - /* Initialize the i2c bus */ + /* Initialize the i2c bus */ #ifdef USE_HW_I2C - /* Use fast mode. */ - hwI2CInit(1); + /* Use fast mode. */ + hwI2CInit(1); #else - swI2CInit(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA); + swI2CInit(DEFAULT_I2C_SCL, DEFAULT_I2C_SDA); #endif - /* Check if SII164 Chip exists */ - if ((sii164GetVendorID() == SII164_VENDOR_ID) && (sii164GetDeviceID() == SII164_DEVICE_ID)) - { - /* - * Initialize SII164 controller chip. - */ - - /* Select the edge */ - if (edgeSelect == 0) - config = SII164_CONFIGURATION_LATCH_FALLING; - else - config = SII164_CONFIGURATION_LATCH_RISING; - - /* Select bus wide */ - if (busSelect == 0) - config |= SII164_CONFIGURATION_BUS_12BITS; - else - config |= SII164_CONFIGURATION_BUS_24BITS; - - /* Select Dual/Single Edge Clock */ - if (dualEdgeClkSelect == 0) - config |= SII164_CONFIGURATION_CLOCK_SINGLE; - else - config |= SII164_CONFIGURATION_CLOCK_DUAL; - - /* Select HSync Enable */ - if (hsyncEnable == 0) - config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW; - else - config |= SII164_CONFIGURATION_HSYNC_AS_IS; - - /* Select VSync Enable */ - if (vsyncEnable == 0) - config |= SII164_CONFIGURATION_VSYNC_FORCE_LOW; - else - config |= SII164_CONFIGURATION_VSYNC_AS_IS; - - i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); - - /* De-skew enabled with default 111b value. - This will fix some artifacts problem in some mode on board 2.2. - Somehow this fix does not affect board 2.1. - */ - if (deskewEnable == 0) - config = SII164_DESKEW_DISABLE; - else - config = SII164_DESKEW_ENABLE; - - switch (deskewSetting) - { - case 0: - config |= SII164_DESKEW_1_STEP; - break; - case 1: - config |= SII164_DESKEW_2_STEP; - break; - case 2: - config |= SII164_DESKEW_3_STEP; - break; - case 3: - config |= SII164_DESKEW_4_STEP; - break; - case 4: - config |= SII164_DESKEW_5_STEP; - break; - case 5: - config |= SII164_DESKEW_6_STEP; - break; - case 6: - config |= SII164_DESKEW_7_STEP; - break; - case 7: - config |= SII164_DESKEW_8_STEP; - break; - } - i2cWriteReg(SII164_I2C_ADDRESS, SII164_DESKEW, config); - - /* Enable/Disable Continuous Sync. */ - if (continuousSyncEnable == 0) - config = SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE; - else - config = SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE; - - /* Enable/Disable PLL Filter */ - if (pllFilterEnable == 0) - config |= SII164_PLL_FILTER_DISABLE; - else - config |= SII164_PLL_FILTER_ENABLE; - - /* Set the PLL Filter value */ - config |= ((pllFilterValue & 0x07) << 1); - - i2cWriteReg(SII164_I2C_ADDRESS, SII164_PLL, config); - - /* Recover from Power Down and enable output. */ - config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION); - config |= SII164_CONFIGURATION_POWER_NORMAL; - i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); - - return 0; - } - - /* Return -1 if initialization fails. */ - return (-1); + /* Check if SII164 Chip exists */ + if ((sii164GetVendorID() == SII164_VENDOR_ID) && (sii164GetDeviceID() == SII164_DEVICE_ID)) + { + /* + * Initialize SII164 controller chip. + */ + + /* Select the edge */ + if (edgeSelect == 0) + config = SII164_CONFIGURATION_LATCH_FALLING; + else + config = SII164_CONFIGURATION_LATCH_RISING; + + /* Select bus wide */ + if (busSelect == 0) + config |= SII164_CONFIGURATION_BUS_12BITS; + else + config |= SII164_CONFIGURATION_BUS_24BITS; + + /* Select Dual/Single Edge Clock */ + if (dualEdgeClkSelect == 0) + config |= SII164_CONFIGURATION_CLOCK_SINGLE; + else + config |= SII164_CONFIGURATION_CLOCK_DUAL; + + /* Select HSync Enable */ + if (hsyncEnable == 0) + config |= SII164_CONFIGURATION_HSYNC_FORCE_LOW; + else + config |= SII164_CONFIGURATION_HSYNC_AS_IS; + + /* Select VSync Enable */ + if (vsyncEnable == 0) + config |= SII164_CONFIGURATION_VSYNC_FORCE_LOW; + else + config |= SII164_CONFIGURATION_VSYNC_AS_IS; + + i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); + + /* De-skew enabled with default 111b value. + This will fix some artifacts problem in some mode on board 2.2. + Somehow this fix does not affect board 2.1. + */ + if (deskewEnable == 0) + config = SII164_DESKEW_DISABLE; + else + config = SII164_DESKEW_ENABLE; + + switch (deskewSetting) + { + case 0: + config |= SII164_DESKEW_1_STEP; + break; + case 1: + config |= SII164_DESKEW_2_STEP; + break; + case 2: + config |= SII164_DESKEW_3_STEP; + break; + case 3: + config |= SII164_DESKEW_4_STEP; + break; + case 4: + config |= SII164_DESKEW_5_STEP; + break; + case 5: + config |= SII164_DESKEW_6_STEP; + break; + case 6: + config |= SII164_DESKEW_7_STEP; + break; + case 7: + config |= SII164_DESKEW_8_STEP; + break; + } + i2cWriteReg(SII164_I2C_ADDRESS, SII164_DESKEW, config); + + /* Enable/Disable Continuous Sync. */ + if (continuousSyncEnable == 0) + config = SII164_PLL_FILTER_SYNC_CONTINUOUS_DISABLE; + else + config = SII164_PLL_FILTER_SYNC_CONTINUOUS_ENABLE; + + /* Enable/Disable PLL Filter */ + if (pllFilterEnable == 0) + config |= SII164_PLL_FILTER_DISABLE; + else + config |= SII164_PLL_FILTER_ENABLE; + + /* Set the PLL Filter value */ + config |= ((pllFilterValue & 0x07) << 1); + + i2cWriteReg(SII164_I2C_ADDRESS, SII164_PLL, config); + + /* Recover from Power Down and enable output. */ + config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION); + config |= SII164_CONFIGURATION_POWER_NORMAL; + i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); + + return 0; + } + + /* Return -1 if initialization fails. */ + return (-1); } @@ -255,9 +255,9 @@ long sii164InitChip( */ void sii164ResetChip(void) { - /* Power down */ - sii164SetPower(0); - sii164SetPower(1); + /* Power down */ + sii164SetPower(0); + sii164SetPower(1); } @@ -268,7 +268,7 @@ void sii164ResetChip(void) */ char *sii164GetChipString(void) { - return gDviCtrlChipName; + return gDviCtrlChipName; } @@ -280,26 +280,26 @@ char *sii164GetChipString(void) * powerUp - Flag to set the power down or up */ void sii164SetPower( - unsigned char powerUp + unsigned char powerUp ) { - unsigned char config; - - config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION); - if (powerUp == 1) - { - /* Power up the chip */ - config &= ~SII164_CONFIGURATION_POWER_MASK; - config |= SII164_CONFIGURATION_POWER_NORMAL; - i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); - } - else - { - /* Power down the chip */ - config &= ~SII164_CONFIGURATION_POWER_MASK; - config |= SII164_CONFIGURATION_POWER_DOWN; - i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); - } + unsigned char config; + + config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION); + if (powerUp == 1) + { + /* Power up the chip */ + config &= ~SII164_CONFIGURATION_POWER_MASK; + config |= SII164_CONFIGURATION_POWER_NORMAL; + i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); + } + else + { + /* Power down the chip */ + config &= ~SII164_CONFIGURATION_POWER_MASK; + config |= SII164_CONFIGURATION_POWER_DOWN; + i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); + } } @@ -308,31 +308,31 @@ void sii164SetPower( * This function selects the mode of the hot plug detection. */ static void sii164SelectHotPlugDetectionMode( - sii164_hot_plug_mode_t hotPlugMode + sii164_hot_plug_mode_t hotPlugMode ) { - unsigned char detectReg; - - detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & ~SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG; - switch (hotPlugMode) - { - case SII164_HOTPLUG_DISABLE: - detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH; - break; - case SII164_HOTPLUG_USE_MDI: - detectReg &= ~SII164_DETECT_INTERRUPT_MASK; - detectReg |= SII164_DETECT_INTERRUPT_BY_HTPLG_PIN; - detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI; - break; - case SII164_HOTPLUG_USE_RSEN: - detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN; - break; - case SII164_HOTPLUG_USE_HTPLG: - detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG; - break; - } - - i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg); + unsigned char detectReg; + + detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & ~SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG; + switch (hotPlugMode) + { + case SII164_HOTPLUG_DISABLE: + detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH; + break; + case SII164_HOTPLUG_USE_MDI: + detectReg &= ~SII164_DETECT_INTERRUPT_MASK; + detectReg |= SII164_DETECT_INTERRUPT_BY_HTPLG_PIN; + detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_MDI; + break; + case SII164_HOTPLUG_USE_RSEN: + detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_RSEN; + break; + case SII164_HOTPLUG_USE_HTPLG: + detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HTPLG; + break; + } + + i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg); } /* @@ -342,18 +342,18 @@ static void sii164SelectHotPlugDetectionMode( * enableHotPlug - Enable (=1) / disable (=0) Hot Plug detection */ void sii164EnableHotPlugDetection( - unsigned char enableHotPlug + unsigned char enableHotPlug ) { - unsigned char detectReg; - detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); - - /* Depending on each DVI controller, need to enable the hot plug based on each - individual chip design. */ - if (enableHotPlug != 0) - sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_USE_MDI); - else - sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_DISABLE); + unsigned char detectReg; + detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); + + /* Depending on each DVI controller, need to enable the hot plug based on each + individual chip design. */ + if (enableHotPlug != 0) + sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_USE_MDI); + else + sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_DISABLE); } /* @@ -366,13 +366,13 @@ void sii164EnableHotPlugDetection( */ unsigned char sii164IsConnected(void) { - unsigned char hotPlugValue; + unsigned char hotPlugValue; - hotPlugValue = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & SII164_DETECT_HOT_PLUG_STATUS_MASK; - if (hotPlugValue == SII164_DETECT_HOT_PLUG_STATUS_ON) - return 1; - else - return 0; + hotPlugValue = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & SII164_DETECT_HOT_PLUG_STATUS_MASK; + if (hotPlugValue == SII164_DETECT_HOT_PLUG_STATUS_ON) + return 1; + else + return 0; } /* @@ -385,13 +385,13 @@ unsigned char sii164IsConnected(void) */ unsigned char sii164CheckInterrupt(void) { - unsigned char detectReg; + unsigned char detectReg; - detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & SII164_DETECT_MONITOR_STATE_MASK; - if (detectReg == SII164_DETECT_MONITOR_STATE_CHANGE) - return 1; - else - return 0; + detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & SII164_DETECT_MONITOR_STATE_MASK; + if (detectReg == SII164_DETECT_MONITOR_STATE_CHANGE) + return 1; + else + return 0; } /* @@ -400,11 +400,11 @@ unsigned char sii164CheckInterrupt(void) */ void sii164ClearInterrupt(void) { - unsigned char detectReg; + unsigned char detectReg; - /* Clear the MDI interrupt */ - detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); - i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg | SII164_DETECT_MONITOR_STATE_CLEAR); + /* Clear the MDI interrupt */ + detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); + i2cWriteReg(SII164_I2C_ADDRESS, SII164_DETECT, detectReg | SII164_DETECT_MONITOR_STATE_CLEAR); } #endif diff --git a/drivers/staging/sm750fb/ddk750_sii164.h b/drivers/staging/sm750fb/ddk750_sii164.h index 2b4c7d3381df..0996a32e8dae 100644 --- a/drivers/staging/sm750fb/ddk750_sii164.h +++ b/drivers/staging/sm750fb/ddk750_sii164.h @@ -6,25 +6,25 @@ /* Hot Plug detection mode structure */ typedef enum _sii164_hot_plug_mode_t { - SII164_HOTPLUG_DISABLE = 0, /* Disable Hot Plug output bit (always high). */ - SII164_HOTPLUG_USE_MDI, /* Use Monitor Detect Interrupt bit. */ - SII164_HOTPLUG_USE_RSEN, /* Use Receiver Sense detect bit. */ - SII164_HOTPLUG_USE_HTPLG /* Use Hot Plug detect bit. */ + SII164_HOTPLUG_DISABLE = 0, /* Disable Hot Plug output bit (always high). */ + SII164_HOTPLUG_USE_MDI, /* Use Monitor Detect Interrupt bit. */ + SII164_HOTPLUG_USE_RSEN, /* Use Receiver Sense detect bit. */ + SII164_HOTPLUG_USE_HTPLG /* Use Hot Plug detect bit. */ } sii164_hot_plug_mode_t; /* Silicon Image SiI164 chip prototype */ long sii164InitChip( - unsigned char edgeSelect, - unsigned char busSelect, - unsigned char dualEdgeClkSelect, - unsigned char hsyncEnable, - unsigned char vsyncEnable, - unsigned char deskewEnable, - unsigned char deskewSetting, - unsigned char continuousSyncEnable, - unsigned char pllFilterEnable, - unsigned char pllFilterValue + unsigned char edgeSelect, + unsigned char busSelect, + unsigned char dualEdgeClkSelect, + unsigned char hsyncEnable, + unsigned char vsyncEnable, + unsigned char deskewEnable, + unsigned char deskewSetting, + unsigned char continuousSyncEnable, + unsigned char pllFilterEnable, + unsigned char pllFilterValue ); unsigned short sii164GetVendorID(void); diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index cc80580bc823..71e9a7a3aabb 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -5,7 +5,7 @@ #define FB_ACCEL_SMI 0xab /* please use revision id to distinguish sm750le and sm750*/ -#define SPC_SM750 0 +#define SPC_SM750 0 #define MB(x) ((x)<<20) #define MHZ(x) ((x) * 1000000) @@ -38,8 +38,8 @@ struct lynx_accel{ }; -/* lynx_share stands for a presentation of two frame buffer - that use one smi adaptor , it is similar to a basic class of C++ +/* lynx_share stands for a presentation of two frame buffer + that use one smi adaptor , it is similar to a basic class of C++ */ struct lynx_share{ /* common members */ @@ -115,7 +115,7 @@ struct lynxfb_crtc{ int(*proc_checkMode)(struct lynxfb_crtc*, struct fb_var_screeninfo*); int(*proc_setColReg)(struct lynxfb_crtc*, ushort, ushort, ushort, ushort); void (*clear)(struct lynxfb_crtc*); - /* pan display */ + /* pan display */ int (*proc_panDisplay)(struct lynxfb_crtc *, const struct fb_var_screeninfo *, const struct fb_info *); @@ -126,17 +126,17 @@ struct lynxfb_crtc{ struct lynxfb_output{ int dpms; int paths; - /* which paths(s) this output stands for,for sm750: - paths=1:means output for panel paths - paths=2:means output for crt paths - paths=3:means output for both panel and crt paths + /* which paths(s) this output stands for,for sm750: + paths=1:means output for panel paths + paths=2:means output for crt paths + paths=3:means output for both panel and crt paths */ int *channel; - /* which channel these outputs linked with,for sm750: - *channel=0 means primary channel - *channel=1 means secondary channel - output->channel ==> &crtc->channel + /* which channel these outputs linked with,for sm750: + *channel=0 means primary channel + *channel=1 means secondary channel + output->channel ==> &crtc->channel */ void *priv; @@ -165,7 +165,7 @@ struct lynxfb_par{ #define PS_TO_HZ(ps) \ - ({ \ + ({ \ unsigned long long hz = 1000*1000*1000*1000ULL; \ do_div(hz, ps); \ (unsigned long)hz;}) diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index 8ea3a61ba37c..64d0458190c8 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -151,97 +151,97 @@ unsigned int width, unsigned int height, /* width and height of rectangle in pixel value */ unsigned int rop2) /* ROP value */ { - unsigned int nDirection, de_ctrl; - int opSign; - nDirection = LEFT_TO_RIGHT; + unsigned int nDirection, de_ctrl; + int opSign; + nDirection = LEFT_TO_RIGHT; /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */ - opSign = 1; - de_ctrl = 0; - - /* If source and destination are the same surface, need to check for overlay cases */ - if (sBase == dBase && sPitch == dPitch) - { - /* Determine direction of operation */ - if (sy < dy) - { - /* +----------+ - |S | - | +----------+ - | | | | - | | | | - +---|------+ | - | D| - +----------+ */ - - nDirection = BOTTOM_TO_TOP; - } - else if (sy > dy) - { - /* +----------+ - |D | - | +----------+ - | | | | - | | | | - +---|------+ | - | S| - +----------+ */ - - nDirection = TOP_TO_BOTTOM; - } - else - { - /* sy == dy */ - - if (sx <= dx) - { - /* +------+---+------+ - |S | | D| - | | | | - | | | | - | | | | - +------+---+------+ */ - - nDirection = RIGHT_TO_LEFT; - } - else - { - /* sx > dx */ - - /* +------+---+------+ - |D | | S| - | | | | - | | | | - | | | | - +------+---+------+ */ - - nDirection = LEFT_TO_RIGHT; - } - } - } - - if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) - { - sx += width - 1; - sy += height - 1; - dx += width - 1; - dy += height - 1; - opSign = (-1); - } - - /* Note: - DE_FOREGROUND are DE_BACKGROUND are don't care. - DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency(). - */ + opSign = 1; + de_ctrl = 0; - /* 2D Source Base. - It is an address offset (128 bit aligned) from the beginning of frame buffer. - */ - write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); /* dpr40 */ + /* If source and destination are the same surface, need to check for overlay cases */ + if (sBase == dBase && sPitch == dPitch) + { + /* Determine direction of operation */ + if (sy < dy) + { + /* +----------+ + |S | + | +----------+ + | | | | + | | | | + +---|------+ | + | D| + +----------+ */ + + nDirection = BOTTOM_TO_TOP; + } + else if (sy > dy) + { + /* +----------+ + |D | + | +----------+ + | | | | + | | | | + +---|------+ | + | S| + +----------+ */ + + nDirection = TOP_TO_BOTTOM; + } + else + { + /* sy == dy */ + + if (sx <= dx) + { + /* +------+---+------+ + |S | | D| + | | | | + | | | | + | | | | + +------+---+------+ */ + + nDirection = RIGHT_TO_LEFT; + } + else + { + /* sx > dx */ + + /* +------+---+------+ + |D | | S| + | | | | + | | | | + | | | | + +------+---+------+ */ + + nDirection = LEFT_TO_RIGHT; + } + } + } - /* 2D Destination Base. - It is an address offset (128 bit aligned) from the beginning of frame buffer. - */ - write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */ + if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) + { + sx += width - 1; + sy += height - 1; + dx += width - 1; + dy += height - 1; + opSign = (-1); + } + + /* Note: + DE_FOREGROUND are DE_BACKGROUND are don't care. + DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency(). + */ + + /* 2D Source Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); /* dpr40 */ + + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */ #if 0 /* Program pitch (distance between the 1st points of two adjacent lines). @@ -267,54 +267,54 @@ unsigned int rop2) /* ROP value */ /* Screen Window width in Pixels. 2D engine uses this value to calculate the linear address in frame buffer for a given point. */ - write_dpr(accel, DE_WINDOW_WIDTH, - FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/Bpp)) | - FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (sPitch/Bpp))); /* dpr3c */ + write_dpr(accel, DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/Bpp)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (sPitch/Bpp))); /* dpr3c */ if (accel->de_wait() != 0){ return -1; } - { - - write_dpr(accel, DE_SOURCE, - FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | - FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | - FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); /* dpr0 */ - write_dpr(accel, DE_DESTINATION, - FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | - FIELD_VALUE(0, DE_DESTINATION, X, dx) | - FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ - write_dpr(accel, DE_DIMENSION, - FIELD_VALUE(0, DE_DIMENSION, X, width) | - FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */ - - de_ctrl = - FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | - FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | - FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | - ((nDirection == RIGHT_TO_LEFT) ? - FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT) - : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) | - FIELD_SET(0, DE_CONTROL, STATUS, START); - write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */ - } - - return 0; + { + + write_dpr(accel, DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); /* dpr0 */ + write_dpr(accel, DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ + write_dpr(accel, DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */ + + de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | + ((nDirection == RIGHT_TO_LEFT) ? + FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT) + : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */ + + } + + return 0; } static unsigned int deGetTransparency(struct lynx_accel *accel) { - unsigned int de_ctrl; + unsigned int de_ctrl; - de_ctrl = read_dpr(accel, DE_CONTROL); + de_ctrl = read_dpr(accel, DE_CONTROL); - de_ctrl &= - FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | - FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)| - FIELD_MASK(DE_CONTROL_TRANSPARENCY); + de_ctrl &= + FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | + FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)| + FIELD_MASK(DE_CONTROL_TRANSPARENCY); - return de_ctrl; + return de_ctrl; } int hw_imageblit(struct lynx_accel *accel, @@ -332,32 +332,32 @@ int hw_imageblit(struct lynx_accel *accel, u32 bColor, /* Background color (corresponding to a 0 in the monochrome data */ u32 rop2) /* ROP value */ { - unsigned int ulBytesPerScan; - unsigned int ul4BytesPerScan; - unsigned int ulBytesRemain; - unsigned int de_ctrl = 0; - unsigned char ajRemain[4]; - int i, j; - - startBit &= 7; /* Just make sure the start bit is within legal range */ - ulBytesPerScan = (width + startBit + 7) / 8; - ul4BytesPerScan = ulBytesPerScan & ~3; - ulBytesRemain = ulBytesPerScan & 3; + unsigned int ulBytesPerScan; + unsigned int ul4BytesPerScan; + unsigned int ulBytesRemain; + unsigned int de_ctrl = 0; + unsigned char ajRemain[4]; + int i, j; + + startBit &= 7; /* Just make sure the start bit is within legal range */ + ulBytesPerScan = (width + startBit + 7) / 8; + ul4BytesPerScan = ulBytesPerScan & ~3; + ulBytesRemain = ulBytesPerScan & 3; if(accel->de_wait() != 0) - { - return -1; - } + { + return -1; + } - /* 2D Source Base. - Use 0 for HOST Blt. - */ - write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0); + /* 2D Source Base. + Use 0 for HOST Blt. + */ + write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0); - /* 2D Destination Base. - It is an address offset (128 bit aligned) from the beginning of frame buffer. - */ - write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); + /* 2D Destination Base. + It is an address offset (128 bit aligned) from the beginning of frame buffer. + */ + write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); #if 0 /* Program pitch (distance between the 1st points of two adjacent lines). Note that input pitch is BYTE value, but the 2D Pitch register uses @@ -380,30 +380,30 @@ int hw_imageblit(struct lynx_accel *accel, FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch/bytePerPixel)); /* dpr10 */ } - /* Screen Window width in Pixels. - 2D engine uses this value to calculate the linear address in frame buffer for a given point. - */ - write_dpr(accel, DE_WINDOW_WIDTH, - FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | - FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (dPitch/bytePerPixel))); + /* Screen Window width in Pixels. + 2D engine uses this value to calculate the linear address in frame buffer for a given point. + */ + write_dpr(accel, DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (dPitch/bytePerPixel))); - /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used. - For mono bitmap, use startBit for X_K1. */ - write_dpr(accel, DE_SOURCE, - FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | - FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit)); /* dpr00 */ + /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used. + For mono bitmap, use startBit for X_K1. */ + write_dpr(accel, DE_SOURCE, + FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit)); /* dpr00 */ - write_dpr(accel, DE_DESTINATION, - FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | - FIELD_VALUE(0, DE_DESTINATION, X, dx) | - FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ + write_dpr(accel, DE_DESTINATION, + FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ - write_dpr(accel, DE_DIMENSION, - FIELD_VALUE(0, DE_DIMENSION, X, width) | - FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */ + write_dpr(accel, DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */ - write_dpr(accel, DE_FOREGROUND, fColor); - write_dpr(accel, DE_BACKGROUND, bColor); + write_dpr(accel, DE_FOREGROUND, fColor); + write_dpr(accel, DE_BACKGROUND, bColor); de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | @@ -413,24 +413,24 @@ int hw_imageblit(struct lynx_accel *accel, write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel)); - /* Write MONO data (line by line) to 2D Engine data port */ - for (i=0; i> _LSB(f)) & RAW_MASK(f)) #define TEST_FIELD(d, f, v) (GET_FIELD(d, f) == f ## _ ## v) #define SET_FIELD(d, f, v) (((d) & ~GET_MASK(f)) | \ - (((f ## _ ## v) & RAW_MASK(f)) << _LSB(f))) + (((f ## _ ## v) & RAW_MASK(f)) << _LSB(f))) #define SET_FIELDV(d, f, v) (((d) & ~GET_MASK(f)) | \ - (((v) & RAW_MASK(f)) << _LSB(f))) + (((v) & RAW_MASK(f)) << _LSB(f))) /* Internal macros */ #define _F_START(f) (0 ? f) @@ -26,24 +26,24 @@ /* Global macros */ #define FIELD_GET(x, reg, field) \ ( \ - _F_NORMALIZE((x), reg ## _ ## field) \ + _F_NORMALIZE((x), reg ## _ ## field) \ ) #define FIELD_SET(x, reg, field, value) \ ( \ - (x & ~_F_MASK(reg ## _ ## field)) \ - | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \ + (x & ~_F_MASK(reg ## _ ## field)) \ + | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \ ) #define FIELD_VALUE(x, reg, field, value) \ ( \ - (x & ~_F_MASK(reg ## _ ## field)) \ - | _F_DENORMALIZE(value, reg ## _ ## field) \ + (x & ~_F_MASK(reg ## _ ## field)) \ + | _F_DENORMALIZE(value, reg ## _ ## field) \ ) #define FIELD_CLEAR(reg, field) \ ( \ - ~ _F_MASK(reg ## _ ## field) \ + ~ _F_MASK(reg ## _ ## field) \ ) /* Field Macros */ @@ -55,20 +55,20 @@ #define FIELD_DENORMALIZE(field, value) (((value) << FIELD_START(field)) & FIELD_MASK(field)) #define FIELD_INIT(reg, field, value) FIELD_DENORMALIZE(reg ## _ ## field, \ - reg ## _ ## field ## _ ## value) + reg ## _ ## field ## _ ## value) #define FIELD_INIT_VAL(reg, field, value) \ - (FIELD_DENORMALIZE(reg ## _ ## field, value)) + (FIELD_DENORMALIZE(reg ## _ ## field, value)) #define FIELD_VAL_SET(x, r, f, v) x = x & ~FIELD_MASK(r ## _ ## f) \ - | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) + | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) #define RGB(r, g, b) \ ( \ - (unsigned long) (((r) << 16) | ((g) << 8) | (b)) \ + (unsigned long) (((r) << 16) | ((g) << 8) | (b)) \ ) #define RGB16(r, g, b) \ ( \ - (unsigned short) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | (((b) & 0xF8) >> 3)) \ + (unsigned short) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | (((b) & 0xF8) >> 3)) \ ) static inline unsigned int absDiff(unsigned int a, unsigned int b) diff --git a/drivers/staging/sm750fb/sm750_hw.h b/drivers/staging/sm750fb/sm750_hw.h index 93288b3a99d8..adc61edf2bac 100644 --- a/drivers/staging/sm750fb/sm750_hw.h +++ b/drivers/staging/sm750fb/sm750_hw.h @@ -2,8 +2,8 @@ #define LYNX_HW750_H__ -#define DEFAULT_SM750_CHIP_CLOCK 290 -#define DEFAULT_SM750LE_CHIP_CLOCK 333 +#define DEFAULT_SM750_CHIP_CLOCK 290 +#define DEFAULT_SM750LE_CHIP_CLOCK 333 #ifndef SM750LE_REVISION_ID #define SM750LE_REVISION_ID (unsigned char)0xfe #endif @@ -24,9 +24,9 @@ enum sm750_dataflow{ sm750_simul_sec,/* secondary => all head */ - sm750_dual_normal,/* primary => panel head and secondary => crt */ + sm750_dual_normal,/* primary => panel head and secondary => crt */ - sm750_dual_swap,/* primary => crt head and secondary => panel */ + sm750_dual_swap,/* primary => crt head and secondary => panel */ }; @@ -61,20 +61,20 @@ struct sm750_state{ int yLCD; }; -/* sm750_share stands for a presentation of two frame buffer - that use one sm750 adaptor, it is similar to the super class of lynx_share - in C++ -*/ +/* sm750_share stands for a presentation of two frame buffer + that use one sm750 adaptor, it is similar to the super class of lynx_share + in C++ + */ struct sm750_share{ /* it's better to put lynx_share struct to the first place of sm750_share */ struct lynx_share share; struct sm750_state state; int hwCursor; - /* 0: no hardware cursor - 1: primary crtc hw cursor enabled, - 2: secondary crtc hw cursor enabled - 3: both ctrc hw cursor enabled + /* 0: no hardware cursor + 1: primary crtc hw cursor enabled, + 2: secondary crtc hw cursor enabled + 3: both ctrc hw cursor enabled */ }; @@ -95,7 +95,7 @@ int hw_sm750le_setBLANK(struct lynxfb_output*, int); void hw_sm750_crtc_clear(struct lynxfb_crtc*); void hw_sm750_output_clear(struct lynxfb_output*); int hw_sm750_pan_display(struct lynxfb_crtc *crtc, - const struct fb_var_screeninfo *var, - const struct fb_info *info); + const struct fb_var_screeninfo *var, + const struct fb_info *info); #endif -- cgit v1.3-6-gb490 From 7f0ebcc29082a45bcd3e108b6f65d1190059b36b Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:31 -0700 Subject: staging: sm750fb: remove spacing after open parenthesis Fixes checkpatch.pl warning: ERROR: space prohibited after that open parenthesis '(' Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_chip.c | 6 +++--- drivers/staging/sm750fb/ddk750_mode.c | 2 +- drivers/staging/sm750fb/ddk750_power.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_chip.c b/drivers/staging/sm750fb/ddk750_chip.c index f4975d2d97ad..1069a2d3186f 100644 --- a/drivers/staging/sm750fb/ddk750_chip.c +++ b/drivers/staging/sm750fb/ddk750_chip.c @@ -599,9 +599,9 @@ unsigned int formatPllReg(pll_value_t *pPLL) On returning a 32 bit number, the value can be applied to any PLL in the calling function. */ ulPllReg = - FIELD_SET( 0, PANEL_PLL_CTRL, BYPASS, OFF) - | FIELD_SET( 0, PANEL_PLL_CTRL, POWER, ON) - | FIELD_SET( 0, PANEL_PLL_CTRL, INPUT, OSC) + FIELD_SET(0, PANEL_PLL_CTRL, BYPASS, OFF) + | FIELD_SET(0, PANEL_PLL_CTRL, POWER, ON) + | FIELD_SET(0, PANEL_PLL_CTRL, INPUT, OSC) #ifndef VALIDATION_CHIP | FIELD_VALUE(0, PANEL_PLL_CTRL, POD, pPLL->POD) #endif diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c index 1f93d07377fc..31424b2b7635 100644 --- a/drivers/staging/sm750fb/ddk750_mode.c +++ b/drivers/staging/sm750fb/ddk750_mode.c @@ -43,7 +43,7 @@ static unsigned long displayControlAdjust_SM750LE(mode_parameter_t *pModeParam, /* Set bit 29:27 of display control register for the right clock */ /* Note that SM750LE only need to supported 7 resoluitons. */ - if ( x == 800 && y == 600 ) + if (x == 800 && y == 600 ) dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL41); else if (x == 1024 && y == 768) dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL65); diff --git a/drivers/staging/sm750fb/ddk750_power.c b/drivers/staging/sm750fb/ddk750_power.c index b7a108b46e5c..44b8eb109d27 100644 --- a/drivers/staging/sm750fb/ddk750_power.c +++ b/drivers/staging/sm750fb/ddk750_power.c @@ -59,17 +59,17 @@ void setPowerMode(unsigned int powerMode) { control_value = #ifdef VALIDATION_CHIP - FIELD_SET( control_value, POWER_MODE_CTRL, 336CLK, OFF) | + FIELD_SET(control_value, POWER_MODE_CTRL, 336CLK, OFF) | #endif - FIELD_SET( control_value, POWER_MODE_CTRL, OSC_INPUT, OFF); + FIELD_SET(control_value, POWER_MODE_CTRL, OSC_INPUT, OFF); } else { control_value = #ifdef VALIDATION_CHIP - FIELD_SET( control_value, POWER_MODE_CTRL, 336CLK, ON) | + FIELD_SET(control_value, POWER_MODE_CTRL, 336CLK, ON) | #endif - FIELD_SET( control_value, POWER_MODE_CTRL, OSC_INPUT, ON); + FIELD_SET(control_value, POWER_MODE_CTRL, OSC_INPUT, ON); } /* Program new power mode. */ -- cgit v1.3-6-gb490 From 8332d94c979bc348398d3f1b2581a59c7d60978a Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:32 -0700 Subject: staging: sm750fb: remove space before close parenthesis Fixes checkpatch.pl error: ERROR: space prohibited before that close parenthesis ')' Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_chip.c | 2 +- drivers/staging/sm750fb/ddk750_mode.c | 2 +- drivers/staging/sm750fb/sm750_accel.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_chip.c b/drivers/staging/sm750fb/ddk750_chip.c index 1069a2d3186f..fb1c533c0180 100644 --- a/drivers/staging/sm750fb/ddk750_chip.c +++ b/drivers/staging/sm750fb/ddk750_chip.c @@ -268,7 +268,7 @@ int ddk750_initHw(initchip_param_t *pInitParam) #endif - if (pInitParam->powerMode != 0 ) + if (pInitParam->powerMode != 0) pInitParam->powerMode = 0; setPowerMode(pInitParam->powerMode); diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c index 31424b2b7635..4ee9ceb475cb 100644 --- a/drivers/staging/sm750fb/ddk750_mode.c +++ b/drivers/staging/sm750fb/ddk750_mode.c @@ -43,7 +43,7 @@ static unsigned long displayControlAdjust_SM750LE(mode_parameter_t *pModeParam, /* Set bit 29:27 of display control register for the right clock */ /* Note that SM750LE only need to supported 7 resoluitons. */ - if (x == 800 && y == 600 ) + if (x == 800 && y == 600) dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL41); else if (x == 1024 && y == 768) dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL65); diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index 64d0458190c8..10cc0223eae3 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -363,7 +363,7 @@ int hw_imageblit(struct lynx_accel *accel, Note that input pitch is BYTE value, but the 2D Pitch register uses pixel values. Need Byte to pixel conversion. */ - if(bytePerPixel == 3 ){ + if(bytePerPixel == 3){ dx *= 3; width *= 3; startBit *= 3; -- cgit v1.3-6-gb490 From 9ccc5f4427c2a69553935c33ca4c4b3f9e80214d Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:33 -0700 Subject: staging: sm750fb: add space before open parenthesis Fixes checkpatch.pl error: ERROR: space required before the open parenthesis '(' Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_display.c | 20 ++++++++++---------- drivers/staging/sm750fb/ddk750_dvi.c | 2 +- drivers/staging/sm750fb/ddk750_help.c | 2 +- drivers/staging/sm750fb/ddk750_mode.c | 12 ++++++------ drivers/staging/sm750fb/ddk750_power.c | 6 +++--- drivers/staging/sm750fb/sm750_accel.c | 8 ++++---- drivers/staging/sm750fb/sm750_cursor.c | 32 ++++++++++++++++---------------- drivers/staging/sm750fb/sm750_help.h | 2 +- 8 files changed, 42 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c index 1c4049f5c575..973dec30c3a0 100644 --- a/drivers/staging/sm750fb/ddk750_display.c +++ b/drivers/staging/sm750fb/ddk750_display.c @@ -49,7 +49,7 @@ static void setDisplayControl(int ctrl, int dispState) { cnt++; POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg); - } while((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) != + } while ((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) != (ulDisplayCtrlReg & ~ulReservedBits)); printk("Set Panel Plane enbit:after tried %d times\n", cnt); } @@ -104,7 +104,7 @@ static void setDisplayControl(int ctrl, int dispState) { cnt++; POKE32(CRT_DISPLAY_CTRL, ulDisplayCtrlReg); - } while((PEEK32(CRT_DISPLAY_CTRL) & ~ulReservedBits) != + } while ((PEEK32(CRT_DISPLAY_CTRL) & ~ulReservedBits) != (ulDisplayCtrlReg & ~ulReservedBits)); printk("Set Crt Plane enbit:after tried %d times\n", cnt); } @@ -132,7 +132,7 @@ static void setDisplayControl(int ctrl, int dispState) static void waitNextVerticalSync(int ctrl, int delay) { unsigned int status; - if(!ctrl){ + if (!ctrl){ /* primary controller */ /* Do not wait when the Primary PLL is off or display control is already off. @@ -233,14 +233,14 @@ static void swPanelPowerSequence(int disp, int delay) void ddk750_setLogicalDispOut(disp_output_t output) { unsigned int reg; - if(output & PNL_2_USAGE){ + if (output & PNL_2_USAGE){ /* set panel path controller select */ reg = PEEK32(PANEL_DISPLAY_CTRL); reg = FIELD_VALUE(reg, PANEL_DISPLAY_CTRL, SELECT, (output & PNL_2_MASK)>>PNL_2_OFFSET); POKE32(PANEL_DISPLAY_CTRL, reg); } - if(output & CRT_2_USAGE){ + if (output & CRT_2_USAGE){ /* set crt path controller select */ reg = PEEK32(CRT_DISPLAY_CTRL); reg = FIELD_VALUE(reg, CRT_DISPLAY_CTRL, SELECT, (output & CRT_2_MASK)>>CRT_2_OFFSET); @@ -250,25 +250,25 @@ void ddk750_setLogicalDispOut(disp_output_t output) } - if(output & PRI_TP_USAGE){ + if (output & PRI_TP_USAGE){ /* set primary timing and plane en_bit */ setDisplayControl(0, (output&PRI_TP_MASK)>>PRI_TP_OFFSET); } - if(output & SEC_TP_USAGE){ + if (output & SEC_TP_USAGE){ /* set secondary timing and plane en_bit*/ setDisplayControl(1, (output&SEC_TP_MASK)>>SEC_TP_OFFSET); } - if(output & PNL_SEQ_USAGE){ + if (output & PNL_SEQ_USAGE){ /* set panel sequence */ swPanelPowerSequence((output&PNL_SEQ_MASK)>>PNL_SEQ_OFFSET, 4); } - if(output & DAC_USAGE) + if (output & DAC_USAGE) setDAC((output & DAC_MASK)>>DAC_OFFSET); - if(output & DPMS_USAGE) + if (output & DPMS_USAGE) ddk750_setDPMS((output & DPMS_MASK) >> DPMS_OFFSET); } diff --git a/drivers/staging/sm750fb/ddk750_dvi.c b/drivers/staging/sm750fb/ddk750_dvi.c index 35866fa7a8af..4c64436d8255 100644 --- a/drivers/staging/sm750fb/ddk750_dvi.c +++ b/drivers/staging/sm750fb/ddk750_dvi.c @@ -45,7 +45,7 @@ int dviInit( { dvi_ctrl_device_t *pCurrentDviCtrl; pCurrentDviCtrl = g_dcftSupportedDviController; - if(pCurrentDviCtrl->pfnInit != NULL) + if (pCurrentDviCtrl->pfnInit != NULL) { return pCurrentDviCtrl->pfnInit(edgeSelect, busSelect, dualEdgeClkSelect, hsyncEnable, vsyncEnable, deskewEnable, deskewSetting, continuousSyncEnable, diff --git a/drivers/staging/sm750fb/ddk750_help.c b/drivers/staging/sm750fb/ddk750_help.c index f027df58fc11..9637dd30d037 100644 --- a/drivers/staging/sm750fb/ddk750_help.c +++ b/drivers/staging/sm750fb/ddk750_help.c @@ -10,7 +10,7 @@ void ddk750_set_mmio(void __iomem *addr, unsigned short devId, char revId) mmio750 = addr; devId750 = devId; revId750 = revId; - if(revId == 0xfe) + if (revId == 0xfe) printk("found sm750le\n"); } diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c index 4ee9ceb475cb..cfe528c487f1 100644 --- a/drivers/staging/sm750fb/ddk750_mode.c +++ b/drivers/staging/sm750fb/ddk750_mode.c @@ -80,7 +80,7 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) int ret = 0; int cnt = 0; unsigned int ulTmpValue, ulReg; - if(pll->clockType == SECONDARY_PLL) + if (pll->clockType == SECONDARY_PLL) { /* programe secondary pixel clock */ POKE32(CRT_PLL_CTRL, formatPllReg(pll)); @@ -107,7 +107,7 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) FIELD_SET(0, CRT_DISPLAY_CTRL, PLANE, ENABLE); - if(getChipType() == SM750LE){ + if (getChipType() == SM750LE){ displayControlAdjust_SM750LE(pModeParam, ulTmpValue); }else{ ulReg = PEEK32(CRT_DISPLAY_CTRL) @@ -120,7 +120,7 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) } } - else if(pll->clockType == PRIMARY_PLL) + else if (pll->clockType == PRIMARY_PLL) { unsigned int ulReservedBits; POKE32(PANEL_PLL_CTRL, formatPllReg(pll)); @@ -170,10 +170,10 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) POKE32(PANEL_DISPLAY_CTRL, ulTmpValue|ulReg); #if 1 - while((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) != (ulTmpValue|ulReg)) + while ((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) != (ulTmpValue|ulReg)) { cnt++; - if(cnt > 1000) + if (cnt > 1000) break; POKE32(PANEL_DISPLAY_CTRL, ulTmpValue|ulReg); } @@ -193,7 +193,7 @@ int ddk750_setModeTiming(mode_parameter_t *parm, clock_type_t clock) pll.clockType = clock; uiActualPixelClk = calcPllValue(parm->pixel_clock, &pll); - if(getChipType() == SM750LE){ + if (getChipType() == SM750LE){ /* set graphic mode via IO method */ outb_p(0x88, 0x3d4); outb_p(0x06, 0x3d5); diff --git a/drivers/staging/sm750fb/ddk750_power.c b/drivers/staging/sm750fb/ddk750_power.c index 44b8eb109d27..a2d9ee611c90 100644 --- a/drivers/staging/sm750fb/ddk750_power.c +++ b/drivers/staging/sm750fb/ddk750_power.c @@ -5,7 +5,7 @@ void ddk750_setDPMS(DPMS_t state) { unsigned int value; - if(getChipType() == SM750LE){ + if (getChipType() == SM750LE){ value = PEEK32(CRT_DISPLAY_CTRL); POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(value, CRT_DISPLAY_CTRL, DPMS, state)); }else{ @@ -17,7 +17,7 @@ void ddk750_setDPMS(DPMS_t state) unsigned int getPowerMode(void) { - if(getChipType() == SM750LE) + if (getChipType() == SM750LE) return 0; return (FIELD_GET(PEEK32(POWER_MODE_CTRL), POWER_MODE_CTRL, MODE)); } @@ -33,7 +33,7 @@ void setPowerMode(unsigned int powerMode) control_value = PEEK32(POWER_MODE_CTRL); - if(getChipType() == SM750LE) + if (getChipType() == SM750LE) return; switch (powerMode) diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index 10cc0223eae3..73d84dea4405 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -96,7 +96,7 @@ int hw_fillrect(struct lynx_accel *accel, { u32 deCtrl; - if(accel->de_wait() != 0) + if (accel->de_wait() != 0) { /* int time wait and always busy,seems hardware * got something error */ @@ -248,7 +248,7 @@ unsigned int rop2) /* ROP value */ Note that input pitch is BYTE value, but the 2D Pitch register uses pixel values. Need Byte to pixel conversion. */ - if(Bpp == 3){ + if (Bpp == 3){ sx *= 3; dx *= 3; width *= 3; @@ -344,7 +344,7 @@ int hw_imageblit(struct lynx_accel *accel, ul4BytesPerScan = ulBytesPerScan & ~3; ulBytesRemain = ulBytesPerScan & 3; - if(accel->de_wait() != 0) + if (accel->de_wait() != 0) { return -1; } @@ -363,7 +363,7 @@ int hw_imageblit(struct lynx_accel *accel, Note that input pitch is BYTE value, but the 2D Pitch register uses pixel values. Need Byte to pixel conversion. */ - if(bytePerPixel == 3){ + if (bytePerPixel == 3){ dx *= 3; width *= 3; startBit *= 3; diff --git a/drivers/staging/sm750fb/sm750_cursor.c b/drivers/staging/sm750fb/sm750_cursor.c index 405e24b6768f..95cfb8fe9a07 100644 --- a/drivers/staging/sm750fb/sm750_cursor.c +++ b/drivers/staging/sm750fb/sm750_cursor.c @@ -122,7 +122,7 @@ void hw_cursor_setData(struct lynx_cursor *cursor, odd=0; */ - for(i=0;i> j)) + if (opr & (0x80 >> j)) { /* use fg color,id = 2 */ data |= 2 << (j*2); }else{ @@ -149,9 +149,9 @@ void hw_cursor_setData(struct lynx_cursor *cursor, } } #else - for(j=0;j<8;j++){ - if(mask & (0x80>>j)){ - if(rop == ROP_XOR) + for (j=0;j<8;j++){ + if (mask & (0x80>>j)){ + if (rop == ROP_XOR) opr = mask ^ color; else opr = mask & color; @@ -165,9 +165,9 @@ void hw_cursor_setData(struct lynx_cursor *cursor, /* assume pitch is 1,2,4,8,...*/ #if 0 - if(!((i+1)&(pitch-1))) /* below line equal to is line */ + if (!((i+1)&(pitch-1))) /* below line equal to is line */ #else - if((i+1) % pitch == 0) + if ((i+1) % pitch == 0) #endif { /* need a return */ @@ -204,7 +204,7 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, pstart = cursor->vstart; pbuffer = pstart; - for(i=0;i> j)) + if (opr & (0x80 >> j)) { /* use fg color,id = 2 */ data |= 2 << (j*2); }else{ @@ -229,15 +229,15 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, } } #else - for(j=0;j<8;j++){ - if(mask & (1< Date: Tue, 14 Jul 2015 21:14:34 -0700 Subject: staging: sm750fb: remove space between function name and parenthesis Fixes checkpatch.pl warning: WARNING: space prohibited between function name and open parenthesis '(' Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_accel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index 73d84dea4405..982cf1e01dae 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -278,11 +278,11 @@ unsigned int rop2) /* ROP value */ { write_dpr(accel, DE_SOURCE, - FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); /* dpr0 */ write_dpr(accel, DE_DESTINATION, - FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | FIELD_VALUE(0, DE_DESTINATION, X, dx) | FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ write_dpr(accel, DE_DIMENSION, @@ -390,11 +390,11 @@ int hw_imageblit(struct lynx_accel *accel, /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used. For mono bitmap, use startBit for X_K1. */ write_dpr(accel, DE_SOURCE, - FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit)); /* dpr00 */ write_dpr(accel, DE_DESTINATION, - FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | FIELD_VALUE(0, DE_DESTINATION, X, dx) | FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ -- cgit v1.3-6-gb490 From 8c11f5a2805bd2c257b706d7499ed531b6c5aa5f Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:35 -0700 Subject: staging: sm750fb: add space before open brace Fixes checkpatch.pl error: ERROR: space required before the open brace '{' Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_display.c | 14 +++++++------- drivers/staging/sm750fb/ddk750_mode.c | 8 ++++---- drivers/staging/sm750fb/ddk750_power.c | 4 ++-- drivers/staging/sm750fb/sm750_accel.c | 6 +++--- drivers/staging/sm750fb/sm750_cursor.c | 14 +++++++------- 5 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c index 973dec30c3a0..c7171a4299a0 100644 --- a/drivers/staging/sm750fb/ddk750_display.c +++ b/drivers/staging/sm750fb/ddk750_display.c @@ -132,7 +132,7 @@ static void setDisplayControl(int ctrl, int dispState) static void waitNextVerticalSync(int ctrl, int delay) { unsigned int status; - if (!ctrl){ + if (!ctrl) { /* primary controller */ /* Do not wait when the Primary PLL is off or display control is already off. @@ -166,7 +166,7 @@ static void waitNextVerticalSync(int ctrl, int delay) while (status == SYSTEM_CTRL_PANEL_VSYNC_INACTIVE); } - }else{ + }else { /* Do not wait when the Primary PLL is off or display control is already off. This will prevent the software to wait forever. */ @@ -233,14 +233,14 @@ static void swPanelPowerSequence(int disp, int delay) void ddk750_setLogicalDispOut(disp_output_t output) { unsigned int reg; - if (output & PNL_2_USAGE){ + if (output & PNL_2_USAGE) { /* set panel path controller select */ reg = PEEK32(PANEL_DISPLAY_CTRL); reg = FIELD_VALUE(reg, PANEL_DISPLAY_CTRL, SELECT, (output & PNL_2_MASK)>>PNL_2_OFFSET); POKE32(PANEL_DISPLAY_CTRL, reg); } - if (output & CRT_2_USAGE){ + if (output & CRT_2_USAGE) { /* set crt path controller select */ reg = PEEK32(CRT_DISPLAY_CTRL); reg = FIELD_VALUE(reg, CRT_DISPLAY_CTRL, SELECT, (output & CRT_2_MASK)>>CRT_2_OFFSET); @@ -250,17 +250,17 @@ void ddk750_setLogicalDispOut(disp_output_t output) } - if (output & PRI_TP_USAGE){ + if (output & PRI_TP_USAGE) { /* set primary timing and plane en_bit */ setDisplayControl(0, (output&PRI_TP_MASK)>>PRI_TP_OFFSET); } - if (output & SEC_TP_USAGE){ + if (output & SEC_TP_USAGE) { /* set secondary timing and plane en_bit*/ setDisplayControl(1, (output&SEC_TP_MASK)>>SEC_TP_OFFSET); } - if (output & PNL_SEQ_USAGE){ + if (output & PNL_SEQ_USAGE) { /* set panel sequence */ swPanelPowerSequence((output&PNL_SEQ_MASK)>>PNL_SEQ_OFFSET, 4); } diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c index cfe528c487f1..efc1fabf60ed 100644 --- a/drivers/staging/sm750fb/ddk750_mode.c +++ b/drivers/staging/sm750fb/ddk750_mode.c @@ -107,9 +107,9 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) FIELD_SET(0, CRT_DISPLAY_CTRL, PLANE, ENABLE); - if (getChipType() == SM750LE){ + if (getChipType() == SM750LE) { displayControlAdjust_SM750LE(pModeParam, ulTmpValue); - }else{ + }else { ulReg = PEEK32(CRT_DISPLAY_CTRL) & FIELD_CLEAR(CRT_DISPLAY_CTRL, VSYNC_PHASE) & FIELD_CLEAR(CRT_DISPLAY_CTRL, HSYNC_PHASE) @@ -179,7 +179,7 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) } #endif } - else{ + else { ret = -1; } return ret; @@ -193,7 +193,7 @@ int ddk750_setModeTiming(mode_parameter_t *parm, clock_type_t clock) pll.clockType = clock; uiActualPixelClk = calcPllValue(parm->pixel_clock, &pll); - if (getChipType() == SM750LE){ + if (getChipType() == SM750LE) { /* set graphic mode via IO method */ outb_p(0x88, 0x3d4); outb_p(0x06, 0x3d5); diff --git a/drivers/staging/sm750fb/ddk750_power.c b/drivers/staging/sm750fb/ddk750_power.c index a2d9ee611c90..e2c0bb328106 100644 --- a/drivers/staging/sm750fb/ddk750_power.c +++ b/drivers/staging/sm750fb/ddk750_power.c @@ -5,10 +5,10 @@ void ddk750_setDPMS(DPMS_t state) { unsigned int value; - if (getChipType() == SM750LE){ + if (getChipType() == SM750LE) { value = PEEK32(CRT_DISPLAY_CTRL); POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(value, CRT_DISPLAY_CTRL, DPMS, state)); - }else{ + }else { value = PEEK32(SYSTEM_CTRL); value= FIELD_VALUE(value, SYSTEM_CTRL, DPMS, state); POKE32(SYSTEM_CTRL, value); diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index 982cf1e01dae..afe73e8265d1 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -248,7 +248,7 @@ unsigned int rop2) /* ROP value */ Note that input pitch is BYTE value, but the 2D Pitch register uses pixel values. Need Byte to pixel conversion. */ - if (Bpp == 3){ + if (Bpp == 3) { sx *= 3; dx *= 3; width *= 3; @@ -271,7 +271,7 @@ unsigned int rop2) /* ROP value */ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/Bpp)) | FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (sPitch/Bpp))); /* dpr3c */ - if (accel->de_wait() != 0){ + if (accel->de_wait() != 0) { return -1; } @@ -363,7 +363,7 @@ int hw_imageblit(struct lynx_accel *accel, Note that input pitch is BYTE value, but the 2D Pitch register uses pixel values. Need Byte to pixel conversion. */ - if (bytePerPixel == 3){ + if (bytePerPixel == 3) { dx *= 3; width *= 3; startBit *= 3; diff --git a/drivers/staging/sm750fb/sm750_cursor.c b/drivers/staging/sm750fb/sm750_cursor.c index 95cfb8fe9a07..3a21af94dc47 100644 --- a/drivers/staging/sm750fb/sm750_cursor.c +++ b/drivers/staging/sm750fb/sm750_cursor.c @@ -143,14 +143,14 @@ void hw_cursor_setData(struct lynx_cursor *cursor, if (opr & (0x80 >> j)) { /* use fg color,id = 2 */ data |= 2 << (j*2); - }else{ + }else { /* use bg color,id = 1 */ data |= 1 << (j*2); } } #else - for (j=0;j<8;j++){ - if (mask & (0x80>>j)){ + for (j=0;j<8;j++) { + if (mask & (0x80>>j)) { if (rop == ROP_XOR) opr = mask ^ color; else @@ -173,7 +173,7 @@ void hw_cursor_setData(struct lynx_cursor *cursor, /* need a return */ pstart += offset; pbuffer = pstart; - }else{ + }else { pbuffer += sizeof(u16); } @@ -223,13 +223,13 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, if (opr & (0x80 >> j)) { /* use fg color,id = 2 */ data |= 2 << (j*2); - }else{ + }else { /* use bg color,id = 1 */ data |= 1 << (j*2); } } #else - for (j=0;j<8;j++){ + for (j=0;j<8;j++) { if (mask & (1< Date: Tue, 14 Jul 2015 21:14:36 -0700 Subject: staging: sm750fb: add space after close brace Fixes checkpatch.pl error: ERROR: space required after that close brace '}' Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_display.c | 2 +- drivers/staging/sm750fb/ddk750_mode.c | 2 +- drivers/staging/sm750fb/ddk750_power.c | 2 +- drivers/staging/sm750fb/sm750.h | 2 +- drivers/staging/sm750fb/sm750_cursor.c | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c index c7171a4299a0..4a3cb8654888 100644 --- a/drivers/staging/sm750fb/ddk750_display.c +++ b/drivers/staging/sm750fb/ddk750_display.c @@ -166,7 +166,7 @@ static void waitNextVerticalSync(int ctrl, int delay) while (status == SYSTEM_CTRL_PANEL_VSYNC_INACTIVE); } - }else { + } else { /* Do not wait when the Primary PLL is off or display control is already off. This will prevent the software to wait forever. */ diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c index efc1fabf60ed..3d8b06d2ea63 100644 --- a/drivers/staging/sm750fb/ddk750_mode.c +++ b/drivers/staging/sm750fb/ddk750_mode.c @@ -109,7 +109,7 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) if (getChipType() == SM750LE) { displayControlAdjust_SM750LE(pModeParam, ulTmpValue); - }else { + } else { ulReg = PEEK32(CRT_DISPLAY_CTRL) & FIELD_CLEAR(CRT_DISPLAY_CTRL, VSYNC_PHASE) & FIELD_CLEAR(CRT_DISPLAY_CTRL, HSYNC_PHASE) diff --git a/drivers/staging/sm750fb/ddk750_power.c b/drivers/staging/sm750fb/ddk750_power.c index e2c0bb328106..5f697b838651 100644 --- a/drivers/staging/sm750fb/ddk750_power.c +++ b/drivers/staging/sm750fb/ddk750_power.c @@ -8,7 +8,7 @@ void ddk750_setDPMS(DPMS_t state) if (getChipType() == SM750LE) { value = PEEK32(CRT_DISPLAY_CTRL); POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(value, CRT_DISPLAY_CTRL, DPMS, state)); - }else { + } else { value = PEEK32(SYSTEM_CTRL); value= FIELD_VALUE(value, SYSTEM_CTRL, DPMS, state); POKE32(SYSTEM_CTRL, value); diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index 71e9a7a3aabb..8ac541015d1a 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -53,7 +53,7 @@ struct lynx_share{ int mtrr_off; struct{ int vram; - }mtrr; + } mtrr; /* all smi graphic adaptor got below attributes */ unsigned long vidmem_start; unsigned long vidreg_start; diff --git a/drivers/staging/sm750fb/sm750_cursor.c b/drivers/staging/sm750fb/sm750_cursor.c index 3a21af94dc47..2fcec326fcf3 100644 --- a/drivers/staging/sm750fb/sm750_cursor.c +++ b/drivers/staging/sm750fb/sm750_cursor.c @@ -143,7 +143,7 @@ void hw_cursor_setData(struct lynx_cursor *cursor, if (opr & (0x80 >> j)) { /* use fg color,id = 2 */ data |= 2 << (j*2); - }else { + } else { /* use bg color,id = 1 */ data |= 1 << (j*2); } @@ -173,7 +173,7 @@ void hw_cursor_setData(struct lynx_cursor *cursor, /* need a return */ pstart += offset; pbuffer = pstart; - }else { + } else { pbuffer += sizeof(u16); } @@ -223,7 +223,7 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, if (opr & (0x80 >> j)) { /* use fg color,id = 2 */ data |= 2 << (j*2); - }else { + } else { /* use bg color,id = 1 */ data |= 1 << (j*2); } @@ -242,7 +242,7 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, /* need a return */ pstart += offset; pbuffer = pstart; - }else { + } else { pbuffer += sizeof(u16); } -- cgit v1.3-6-gb490 From b63f3dcab161c18f5ce3741dde07c29364a4af6b Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:37 -0700 Subject: staging: sm750fb: add space after enum definition Fixes checkpatch.pl warning: WARNING: missing space after enum definition Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_display.h | 2 +- drivers/staging/sm750fb/sm750_hw.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_display.h b/drivers/staging/sm750fb/ddk750_display.h index 018a66184352..a7f50cc0db9d 100644 --- a/drivers/staging/sm750fb/ddk750_display.h +++ b/drivers/staging/sm750fb/ddk750_display.h @@ -129,7 +129,7 @@ typedef enum _disp_output_t } disp_output_t; #else -typedef enum _disp_output_t{ +typedef enum _disp_output_t { do_LCD1_PRI = PNL_2_PRI|PRI_TP_ON|PNL_SEQ_ON|DAC_ON, do_LCD1_SEC = PNL_2_SEC|SEC_TP_ON|PNL_SEQ_ON|DAC_ON, #if 0 diff --git a/drivers/staging/sm750fb/sm750_hw.h b/drivers/staging/sm750fb/sm750_hw.h index adc61edf2bac..af2db7ca0e56 100644 --- a/drivers/staging/sm750fb/sm750_hw.h +++ b/drivers/staging/sm750fb/sm750_hw.h @@ -9,7 +9,7 @@ #endif -enum sm750_pnltype{ +enum sm750_pnltype { sm750_24TFT = 0,/* 24bit tft */ @@ -19,7 +19,7 @@ enum sm750_pnltype{ }; /* vga channel is not concerned */ -enum sm750_dataflow{ +enum sm750_dataflow { sm750_simul_pri,/* primary => all head */ sm750_simul_sec,/* secondary => all head */ @@ -30,13 +30,13 @@ enum sm750_dataflow{ }; -enum sm750_channel{ +enum sm750_channel { sm750_primary = 0, /* enum value equal to the register filed data */ sm750_secondary = 1, }; -enum sm750_path{ +enum sm750_path { sm750_panel = 1, sm750_crt = 2, sm750_pnc = 3,/* panel and crt */ -- cgit v1.3-6-gb490 From 5d14c13ae03ed4a8d79f14507eabb1d59cc85b3b Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:38 -0700 Subject: staging: sm750fb: add space after struct definition Fixes checkpatch.pl warning: WARNING: missing space after struct definition Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750.h | 12 ++++++------ drivers/staging/sm750fb/sm750_hw.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index 8ac541015d1a..9989ff6d850a 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -14,7 +14,7 @@ extern int smi_indent; -struct lynx_accel{ +struct lynx_accel { /* base virtual address of DPR registers */ volatile unsigned char __iomem * dprBase; /* base virtual address of de data port */ @@ -41,7 +41,7 @@ struct lynx_accel{ /* lynx_share stands for a presentation of two frame buffer that use one smi adaptor , it is similar to a basic class of C++ */ -struct lynx_share{ +struct lynx_share { /* common members */ u16 devid; u8 revid; @@ -68,7 +68,7 @@ struct lynx_share{ void (*resume)(struct lynx_share*); }; -struct lynx_cursor{ +struct lynx_cursor { /* cursor width ,height and size */ int w; int h; @@ -92,7 +92,7 @@ struct lynx_cursor{ void (*setData)(struct lynx_cursor *, u16, const u8*, const u8*); }; -struct lynxfb_crtc{ +struct lynxfb_crtc { unsigned char __iomem *vCursor; /* virtual address of cursor */ unsigned char __iomem *vScreen; /* virtual address of on_screen */ int oCursor; /* cursor address offset in vidmem */ @@ -123,7 +123,7 @@ struct lynxfb_crtc{ struct lynx_cursor cursor; }; -struct lynxfb_output{ +struct lynxfb_output { int dpms; int paths; /* which paths(s) this output stands for,for sm750: @@ -149,7 +149,7 @@ struct lynxfb_output{ void (*clear)(struct lynxfb_output*); }; -struct lynxfb_par{ +struct lynxfb_par { /* either 0 or 1 for dual head adaptor,0 is the older one registered */ int index; unsigned int pseudo_palette[256]; diff --git a/drivers/staging/sm750fb/sm750_hw.h b/drivers/staging/sm750fb/sm750_hw.h index af2db7ca0e56..ef0a16f27936 100644 --- a/drivers/staging/sm750fb/sm750_hw.h +++ b/drivers/staging/sm750fb/sm750_hw.h @@ -42,7 +42,7 @@ enum sm750_path { sm750_pnc = 3,/* panel and crt */ }; -struct init_status{ +struct init_status { ushort powerMode; /* below three clocks are in unit of MHZ*/ ushort chip_clk; @@ -52,7 +52,7 @@ struct init_status{ ushort resetMemory; }; -struct sm750_state{ +struct sm750_state { struct init_status initParm; enum sm750_pnltype pnltype; enum sm750_dataflow dataflow; @@ -66,7 +66,7 @@ struct sm750_state{ in C++ */ -struct sm750_share{ +struct sm750_share { /* it's better to put lynx_share struct to the first place of sm750_share */ struct lynx_share share; struct sm750_state state; -- cgit v1.3-6-gb490 From f7d8b69a1d6dac9d650714e82390f3b63e2e582f Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:39 -0700 Subject: staging: sm750fb: add space after return type Fixes checkpatch.pl warning: WARNING: missing space after return type Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index 9989ff6d850a..2d04c0ff2941 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -108,12 +108,12 @@ struct lynxfb_crtc { void *priv; - int(*proc_setMode)(struct lynxfb_crtc*, + int (*proc_setMode)(struct lynxfb_crtc*, struct fb_var_screeninfo*, struct fb_fix_screeninfo*); - int(*proc_checkMode)(struct lynxfb_crtc*, struct fb_var_screeninfo*); - int(*proc_setColReg)(struct lynxfb_crtc*, ushort, ushort, ushort, ushort); + int (*proc_checkMode)(struct lynxfb_crtc*, struct fb_var_screeninfo*); + int (*proc_setColReg)(struct lynxfb_crtc*, ushort, ushort, ushort, ushort); void (*clear)(struct lynxfb_crtc*); /* pan display */ int (*proc_panDisplay)(struct lynxfb_crtc *, @@ -140,12 +140,12 @@ struct lynxfb_output { */ void *priv; - int(*proc_setMode)(struct lynxfb_output*, + int (*proc_setMode)(struct lynxfb_output*, struct fb_var_screeninfo*, struct fb_fix_screeninfo*); - int(*proc_checkMode)(struct lynxfb_output*, struct fb_var_screeninfo*); - int(*proc_setBLANK)(struct lynxfb_output*, int); + int (*proc_checkMode)(struct lynxfb_output*, struct fb_var_screeninfo*); + int (*proc_setBLANK)(struct lynxfb_output*, int); void (*clear)(struct lynxfb_output*); }; -- cgit v1.3-6-gb490 From 6ab5b6d16bba08e9665d4ae1b122b55642d990b3 Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:40 -0700 Subject: staging: sm750fb: consistent spacing around operators Fixes checkpatch.pl error: ERROR: need consistent spacing around operator Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_chip.c | 4 ++-- drivers/staging/sm750fb/ddk750_display.h | 4 ++-- drivers/staging/sm750fb/sm750.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_chip.c b/drivers/staging/sm750fb/ddk750_chip.c index fb1c533c0180..633201e134f2 100644 --- a/drivers/staging/sm750fb/ddk750_chip.c +++ b/drivers/staging/sm750fb/ddk750_chip.c @@ -464,7 +464,7 @@ unsigned int calcPllValue(unsigned int request_orig, pll_value_t *pll) RN = N * request; quo = RN / input; rem = RN % input;/* rem always small than 14318181 */ - fl_quo = (rem * 10000 /input); + fl_quo = (rem * 10000 / input); for (d = xcnt - 1; d >= 0; d--) { X = xparm[d].value; @@ -474,7 +474,7 @@ unsigned int calcPllValue(unsigned int request_orig, pll_value_t *pll) M += (fl_quo*X % 10000)>5000?1:0; if (M < 256 && M > 0) { unsigned int diff; - tmpClock = pll->inputFreq *M / N / X; + tmpClock = pll->inputFreq * M / N / X; diff = absDiff(tmpClock, request_orig); if (diff < miniDiff) { pll->M = M; diff --git a/drivers/staging/sm750fb/ddk750_display.h b/drivers/staging/sm750fb/ddk750_display.h index a7f50cc0db9d..afdf201b4975 100644 --- a/drivers/staging/sm750fb/ddk750_display.h +++ b/drivers/staging/sm750fb/ddk750_display.h @@ -46,7 +46,7 @@ 0: both off */ #define SEC_TP_OFFSET 5 -#define SEC_TP_MASK (1<< SEC_TP_OFFSET) +#define SEC_TP_MASK (1 << SEC_TP_OFFSET) #define SEC_TP_USAGE (SEC_TP_MASK << 16) #define SEC_TP_ON ((0x1 << SEC_TP_OFFSET)|SEC_TP_USAGE) #define SEC_TP_OFF ((0x0 << SEC_TP_OFFSET)|SEC_TP_USAGE) @@ -67,7 +67,7 @@ #define DAC_OFFSET 7 #define DAC_MASK (1 << DAC_OFFSET) #define DAC_USAGE (DAC_MASK << 16) -#define DAC_ON ((0x0<< DAC_OFFSET)|DAC_USAGE) +#define DAC_ON ((0x0 << DAC_OFFSET)|DAC_USAGE) #define DAC_OFF ((0x1 << DAC_OFFSET)|DAC_USAGE) /* DPMS only affect D-SUB head diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index 2d04c0ff2941..ae872bd0819e 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -10,7 +10,7 @@ #define MB(x) ((x)<<20) #define MHZ(x) ((x) * 1000000) /* align should be 2,4,8,16 */ -#define PADDING(align, data) (((data)+(align)-1)&(~((align) -1))) +#define PADDING(align, data) (((data)+(align)-1)&(~((align) - 1))) extern int smi_indent; -- cgit v1.3-6-gb490 From 0d5e63c4626c0f8b3c8a12e8ce9a557273ce72ee Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:41 -0700 Subject: staging: sm750fb: add spaces around operators Fixes checkpath.pl error: ERROR: spaces required around that operator Note running checkpatch.pl with '--strict' catches more of these errors along with cases where spacing is optional but preferred. Take care of these in a future patch. Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_chip.c | 2 +- drivers/staging/sm750fb/ddk750_power.c | 2 +- drivers/staging/sm750fb/sm750.h | 2 +- drivers/staging/sm750fb/sm750_accel.c | 4 ++-- drivers/staging/sm750fb/sm750_cursor.c | 12 ++++++------ drivers/staging/sm750fb/sm750_help.h | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_chip.c b/drivers/staging/sm750fb/ddk750_chip.c index 633201e134f2..d7435d7302b4 100644 --- a/drivers/staging/sm750fb/ddk750_chip.c +++ b/drivers/staging/sm750fb/ddk750_chip.c @@ -471,7 +471,7 @@ unsigned int calcPllValue(unsigned int request_orig, pll_value_t *pll) M = quo*X; M += fl_quo * X / 10000; /* round step */ - M += (fl_quo*X % 10000)>5000?1:0; + M += (fl_quo*X % 10000) > 5000?1:0; if (M < 256 && M > 0) { unsigned int diff; tmpClock = pll->inputFreq * M / N / X; diff --git a/drivers/staging/sm750fb/ddk750_power.c b/drivers/staging/sm750fb/ddk750_power.c index 5f697b838651..28d4402928d8 100644 --- a/drivers/staging/sm750fb/ddk750_power.c +++ b/drivers/staging/sm750fb/ddk750_power.c @@ -10,7 +10,7 @@ void ddk750_setDPMS(DPMS_t state) POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(value, CRT_DISPLAY_CTRL, DPMS, state)); } else { value = PEEK32(SYSTEM_CTRL); - value= FIELD_VALUE(value, SYSTEM_CTRL, DPMS, state); + value = FIELD_VALUE(value, SYSTEM_CTRL, DPMS, state); POKE32(SYSTEM_CTRL, value); } } diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index ae872bd0819e..d6916fd697dd 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -172,7 +172,7 @@ struct lynxfb_par { static inline unsigned long ps_to_hz(unsigned int psvalue) { - unsigned long long numerator=1000*1000*1000*1000ULL; + unsigned long long numerator = 1000*1000*1000*1000ULL; /* 10^12 / picosecond period gives frequency in Hz */ do_div(numerator, psvalue); return (unsigned long)numerator; diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index afe73e8265d1..0cfe96c2b5dc 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -414,10 +414,10 @@ int hw_imageblit(struct lynx_accel *accel, write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel)); /* Write MONO data (line by line) to 2D Engine data port */ - for (i=0; i> j)) @@ -149,7 +149,7 @@ void hw_cursor_setData(struct lynx_cursor *cursor, } } #else - for (j=0;j<8;j++) { + for (j = 0;j < 8;j++) { if (mask & (0x80>>j)) { if (rop == ROP_XOR) opr = mask ^ color; @@ -204,7 +204,7 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, pstart = cursor->vstart; pbuffer = pstart; - for (i=0;i> j)) @@ -229,7 +229,7 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, } } #else - for (j=0;j<8;j++) { + for (j = 0;j < 8;j++) { if (mask & (1< Date: Tue, 14 Jul 2015 21:14:42 -0700 Subject: staging: sm750fb: add space after semicolon Fixes checkpatch.pl error: ERROR: space required after that ';' Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750.h | 2 +- drivers/staging/sm750fb/sm750_cursor.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750.h b/drivers/staging/sm750fb/sm750.h index d6916fd697dd..9b101a937964 100644 --- a/drivers/staging/sm750fb/sm750.h +++ b/drivers/staging/sm750fb/sm750.h @@ -168,7 +168,7 @@ struct lynxfb_par { ({ \ unsigned long long hz = 1000*1000*1000*1000ULL; \ do_div(hz, ps); \ - (unsigned long)hz;}) + (unsigned long)hz; }) static inline unsigned long ps_to_hz(unsigned int psvalue) { diff --git a/drivers/staging/sm750fb/sm750_cursor.c b/drivers/staging/sm750fb/sm750_cursor.c index 9dabac1c6433..4ed7ca2c1997 100644 --- a/drivers/staging/sm750fb/sm750_cursor.c +++ b/drivers/staging/sm750fb/sm750_cursor.c @@ -122,7 +122,7 @@ void hw_cursor_setData(struct lynx_cursor *cursor, odd=0; */ - for (i = 0;i < count;i++) + for (i = 0; i < count; i++) { color = *pcol++; mask = *pmsk++; @@ -137,7 +137,7 @@ void hw_cursor_setData(struct lynx_cursor *cursor, else opr = mask & color; - for (j = 0;j < 8;j++) + for (j = 0; j < 8; j++) { if (opr & (0x80 >> j)) @@ -149,7 +149,7 @@ void hw_cursor_setData(struct lynx_cursor *cursor, } } #else - for (j = 0;j < 8;j++) { + for (j = 0; j < 8; j++) { if (mask & (0x80>>j)) { if (rop == ROP_XOR) opr = mask ^ color; @@ -204,7 +204,7 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, pstart = cursor->vstart; pbuffer = pstart; - for (i = 0;i < count;i++) + for (i = 0; i < count; i++) { color = *pcol++; mask = *pmsk++; @@ -217,7 +217,7 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, else opr = mask & color; - for (j = 0;j < 8;j++) + for (j = 0; j < 8; j++) { if (opr & (0x80 >> j)) @@ -229,7 +229,7 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, } } #else - for (j = 0;j < 8;j++) { + for (j = 0; j < 8; j++) { if (mask & (1< Date: Tue, 14 Jul 2015 21:14:43 -0700 Subject: staging: sm750fb: remove trailing whitespace Fixes checkpatch.pl error: ERROR: trailing whitespace Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_dvi.c | 2 +- drivers/staging/sm750fb/sm750_accel.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_dvi.c b/drivers/staging/sm750fb/ddk750_dvi.c index 4c64436d8255..c42db85b162f 100644 --- a/drivers/staging/sm750fb/ddk750_dvi.c +++ b/drivers/staging/sm750fb/ddk750_dvi.c @@ -1,4 +1,4 @@ -#define USE_DVICHIP +#define USE_DVICHIP #ifdef USE_DVICHIP #include "ddk750_help.h" #include "ddk750_reg.h" diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index 0cfe96c2b5dc..db950d4062d1 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -37,7 +37,7 @@ void hw_de_init(struct lynx_accel *accel) { /* setup 2d engine registers */ u32 reg, clr; - + write_dpr(accel, DE_MASKS, 0xFFFFFFFF); /* dpr1c */ @@ -82,7 +82,7 @@ void hw_de_init(struct lynx_accel *accel) void hw_set2dformat(struct lynx_accel *accel, int fmt) { u32 reg; - + /* fmt=0,1,2 for 8,16,32,bpp on sm718/750/502 */ reg = read_dpr(accel, DE_STRETCH_FORMAT); reg = FIELD_VALUE(reg, DE_STRETCH_FORMAT, PIXEL_FORMAT, fmt); -- cgit v1.3-6-gb490 From a1fe154f0f3dea1ba48aa4e96dbb0deec5c17125 Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:44 -0700 Subject: staging: sm750fb: remove unnecessary whitespace Fixes checkpatch.pl warning: WARNING: unnecessary whitespace before a quoted newline Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750.c | 2 +- drivers/staging/sm750fb/sm750_hw.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index 4d165ca3baad..c7ab8189671f 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -967,7 +967,7 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) var->accel_flags = 0; var->vmode = FB_VMODE_NONINTERLACED; - pr_debug("#1 show info->cmap : \nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n", + pr_debug("#1 show info->cmap :\nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n", info->cmap.start, info->cmap.len, info->cmap.red, info->cmap.green, info->cmap.blue, info->cmap.transp); diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index 359165d523d0..fb9c631ff818 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -250,7 +250,7 @@ int hw_sm750_output_setMode(struct lynxfb_output *output, POKE32(DISPLAY_CONTROL_750LE, reg); } - pr_info("ddk setlogicdispout done \n"); + pr_info("ddk setlogicdispout done\n"); return ret; } @@ -489,14 +489,14 @@ int hw_sm750_setBLANK(struct lynxfb_output *output, int blank) #else case VESA_NO_BLANKING: #endif - pr_info("flag = FB_BLANK_UNBLANK \n"); + pr_info("flag = FB_BLANK_UNBLANK\n"); dpms = SYSTEM_CTRL_DPMS_VPHP; pps = PANEL_DISPLAY_CTRL_DATA_ENABLE; crtdb = CRT_DISPLAY_CTRL_BLANK_OFF; break; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) case FB_BLANK_NORMAL: - pr_info("flag = FB_BLANK_NORMAL \n"); + pr_info("flag = FB_BLANK_NORMAL\n"); dpms = SYSTEM_CTRL_DPMS_VPHP; pps = PANEL_DISPLAY_CTRL_DATA_DISABLE; crtdb = CRT_DISPLAY_CTRL_BLANK_ON; -- cgit v1.3-6-gb490 From 259fef35c7688c105137f286c2dc5780979686c9 Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:45 -0700 Subject: staging: sm750fb: fix brace placement Fix brace placement errors caught by checkpatch.pl ERROR: that open brace { should be on the previous line Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_chip.h | 12 +++---- drivers/staging/sm750fb/ddk750_display.c | 56 ++++++++++---------------------- drivers/staging/sm750fb/ddk750_display.h | 3 +- drivers/staging/sm750fb/ddk750_dvi.c | 6 ++-- drivers/staging/sm750fb/ddk750_hwi2c.c | 6 ++-- drivers/staging/sm750fb/ddk750_mode.c | 13 +++----- drivers/staging/sm750fb/ddk750_mode.h | 6 ++-- drivers/staging/sm750fb/ddk750_power.c | 27 +++++---------- drivers/staging/sm750fb/ddk750_power.h | 3 +- drivers/staging/sm750fb/ddk750_sii164.c | 16 +++------ drivers/staging/sm750fb/ddk750_sii164.h | 3 +- drivers/staging/sm750fb/sm750_accel.c | 45 ++++++++----------------- drivers/staging/sm750fb/sm750_cursor.c | 23 +++++-------- 13 files changed, 71 insertions(+), 148 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_chip.h b/drivers/staging/sm750fb/ddk750_chip.h index 4e030e820cf3..6ff043608fe9 100644 --- a/drivers/staging/sm750fb/ddk750_chip.h +++ b/drivers/staging/sm750fb/ddk750_chip.h @@ -8,8 +8,7 @@ #include /* This is all the chips recognized by this library */ -typedef enum _logical_chip_type_t -{ +typedef enum _logical_chip_type_t { SM_UNKNOWN, SM718, SM750, @@ -18,8 +17,7 @@ typedef enum _logical_chip_type_t logical_chip_type_t; -typedef enum _clock_type_t -{ +typedef enum _clock_type_t { MXCLK_PLL, PRIMARY_PLL, SECONDARY_PLL, @@ -28,8 +26,7 @@ typedef enum _clock_type_t } clock_type_t; -typedef struct _pll_value_t -{ +typedef struct _pll_value_t { clock_type_t clockType; unsigned long inputFreq; /* Input clock frequency to the PLL */ @@ -42,8 +39,7 @@ typedef struct _pll_value_t pll_value_t; /* input struct to initChipParam() function */ -typedef struct _initchip_param_t -{ +typedef struct _initchip_param_t { unsigned short powerMode; /* Use power mode 0 or 1 */ unsigned short chipClock; /** * Speed of main chip clock in MHz unit diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c index 4a3cb8654888..a64ea32b91ae 100644 --- a/drivers/staging/sm750fb/ddk750_display.c +++ b/drivers/staging/sm750fb/ddk750_display.c @@ -15,12 +15,10 @@ static void setDisplayControl(int ctrl, int dispState) cnt = 0; /* Set the primary display control */ - if (!ctrl) - { + if (!ctrl) { ulDisplayCtrlReg = PEEK32(PANEL_DISPLAY_CTRL); /* Turn on/off the Panel display control */ - if (dispState) - { + if (dispState) { /* Timing should be enabled first before enabling the plane * because changing at the same time does not guarantee that * the plane will also enabled or disabled. @@ -45,16 +43,13 @@ static void setDisplayControl(int ctrl, int dispState) * until a few delay. Need to write * and read it a couple times */ - do - { + do { cnt++; POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg); } while ((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) != (ulDisplayCtrlReg & ~ulReservedBits)); printk("Set Panel Plane enbit:after tried %d times\n", cnt); - } - else - { + } else { /* When turning off, there is no rule on the programming * sequence since whenever the clock is off, then it does not * matter whether the plane is enabled or disabled. @@ -71,14 +66,11 @@ static void setDisplayControl(int ctrl, int dispState) POKE32(PANEL_DISPLAY_CTRL, ulDisplayCtrlReg); } - } - /* Set the secondary display control */ - else - { + } else { + /* Set the secondary display control */ ulDisplayCtrlReg = PEEK32(CRT_DISPLAY_CTRL); - if (dispState) - { + if (dispState) { /* Timing should be enabled first before enabling the plane because changing at the same time does not guarantee that the plane will also enabled or disabled. */ @@ -100,16 +92,13 @@ static void setDisplayControl(int ctrl, int dispState) FIELD_SET(0, CRT_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE) | FIELD_SET(0, CRT_DISPLAY_CTRL, RESERVED_4_MASK, ENABLE); - do - { + do { cnt++; POKE32(CRT_DISPLAY_CTRL, ulDisplayCtrlReg); } while ((PEEK32(CRT_DISPLAY_CTRL) & ~ulReservedBits) != (ulDisplayCtrlReg & ~ulReservedBits)); printk("Set Crt Plane enbit:after tried %d times\n", cnt); - } - else - { + } else { /* When turning off, there is no rule on the programming * sequence since whenever the clock is off, then it does not * matter whether the plane is enabled or disabled. @@ -140,16 +129,13 @@ static void waitNextVerticalSync(int ctrl, int delay) if ((FIELD_GET(PEEK32(PANEL_PLL_CTRL), PANEL_PLL_CTRL, POWER) == PANEL_PLL_CTRL_POWER_OFF) || (FIELD_GET(PEEK32(PANEL_DISPLAY_CTRL), PANEL_DISPLAY_CTRL, TIMING) == - PANEL_DISPLAY_CTRL_TIMING_DISABLE)) - { + PANEL_DISPLAY_CTRL_TIMING_DISABLE)) { return; } - while (delay-- > 0) - { + while (delay-- > 0) { /* Wait for end of vsync. */ - do - { + do { status = FIELD_GET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, PANEL_VSYNC); @@ -157,8 +143,7 @@ static void waitNextVerticalSync(int ctrl, int delay) while (status == SYSTEM_CTRL_PANEL_VSYNC_ACTIVE); /* Wait for start of vsync. */ - do - { + do { status = FIELD_GET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, PANEL_VSYNC); @@ -173,16 +158,13 @@ static void waitNextVerticalSync(int ctrl, int delay) if ((FIELD_GET(PEEK32(CRT_PLL_CTRL), CRT_PLL_CTRL, POWER) == CRT_PLL_CTRL_POWER_OFF) || (FIELD_GET(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, TIMING) == - CRT_DISPLAY_CTRL_TIMING_DISABLE)) - { + CRT_DISPLAY_CTRL_TIMING_DISABLE)) { return; } - while (delay-- > 0) - { + while (delay-- > 0) { /* Wait for end of vsync. */ - do - { + do { status = FIELD_GET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, CRT_VSYNC); @@ -190,8 +172,7 @@ static void waitNextVerticalSync(int ctrl, int delay) while (status == SYSTEM_CTRL_CRT_VSYNC_ACTIVE); /* Wait for start of vsync. */ - do - { + do { status = FIELD_GET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, CRT_VSYNC); @@ -293,8 +274,7 @@ int ddk750_initDVIDisp(void) 1, /* Enable continuous Sync */ 1, /* Enable PLL Filter */ 4 /* Use the recommended value for PLL Filter value */ - ) != 0) && (dviGetVendorID() != 0x0000) && (dviGetDeviceID() != 0x0000)) - { + ) != 0) && (dviGetVendorID() != 0x0000) && (dviGetDeviceID() != 0x0000)) { return (-1); } diff --git a/drivers/staging/sm750fb/ddk750_display.h b/drivers/staging/sm750fb/ddk750_display.h index afdf201b4975..abccf84a8c9a 100644 --- a/drivers/staging/sm750fb/ddk750_display.h +++ b/drivers/staging/sm750fb/ddk750_display.h @@ -86,8 +86,7 @@ CRT means crt path DSUB */ #if 0 -typedef enum _disp_output_t -{ +typedef enum _disp_output_t { NO_DISPLAY = DPMS_OFF, LCD1_PRI = PNL_2_PRI|PRI_TP_ON|PNL_SEQ_ON|DPMS_OFF|DAC_ON, diff --git a/drivers/staging/sm750fb/ddk750_dvi.c b/drivers/staging/sm750fb/ddk750_dvi.c index c42db85b162f..a18bb4cd08b9 100644 --- a/drivers/staging/sm750fb/ddk750_dvi.c +++ b/drivers/staging/sm750fb/ddk750_dvi.c @@ -9,8 +9,7 @@ /* This global variable contains all the supported driver and its corresponding function API. Please set the function pointer to NULL whenever the function is not supported. */ -static dvi_ctrl_device_t g_dcftSupportedDviController[] = -{ +static dvi_ctrl_device_t g_dcftSupportedDviController[] = { #ifdef DVI_CTRL_SII164 { .pfnInit = sii164InitChip, @@ -45,8 +44,7 @@ int dviInit( { dvi_ctrl_device_t *pCurrentDviCtrl; pCurrentDviCtrl = g_dcftSupportedDviController; - if (pCurrentDviCtrl->pfnInit != NULL) - { + if (pCurrentDviCtrl->pfnInit != NULL) { return pCurrentDviCtrl->pfnInit(edgeSelect, busSelect, dualEdgeClkSelect, hsyncEnable, vsyncEnable, deskewEnable, deskewSetting, continuousSyncEnable, pllFilterEnable, pllFilterValue); diff --git a/drivers/staging/sm750fb/ddk750_hwi2c.c b/drivers/staging/sm750fb/ddk750_hwi2c.c index 7f3b1f931043..5ddac430aea2 100644 --- a/drivers/staging/sm750fb/ddk750_hwi2c.c +++ b/drivers/staging/sm750fb/ddk750_hwi2c.c @@ -106,8 +106,7 @@ static unsigned int hwI2CWriteData( * Note: * Only 16 byte can be accessed per i2c start instruction. */ - do - { + do { /* Reset I2C by writing 0 to I2C_RESET register to clear the previous status. */ POKE32(I2C_RESET, 0); @@ -173,8 +172,7 @@ static unsigned int hwI2CReadData( * Note: * Only 16 byte can be accessed per i2c start instruction. */ - do - { + do { /* Reset I2C by writing 0 to I2C_RESET register to clear all the status. */ POKE32(I2C_RESET, 0); diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c index 3d8b06d2ea63..9d104469ca16 100644 --- a/drivers/staging/sm750fb/ddk750_mode.c +++ b/drivers/staging/sm750fb/ddk750_mode.c @@ -80,8 +80,7 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) int ret = 0; int cnt = 0; unsigned int ulTmpValue, ulReg; - if (pll->clockType == SECONDARY_PLL) - { + if (pll->clockType == SECONDARY_PLL) { /* programe secondary pixel clock */ POKE32(CRT_PLL_CTRL, formatPllReg(pll)); POKE32(CRT_HORIZONTAL_TOTAL, @@ -119,9 +118,7 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) POKE32(CRT_DISPLAY_CTRL, ulTmpValue|ulReg); } - } - else if (pll->clockType == PRIMARY_PLL) - { + } else if (pll->clockType == PRIMARY_PLL) { unsigned int ulReservedBits; POKE32(PANEL_PLL_CTRL, formatPllReg(pll)); @@ -170,16 +167,14 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) POKE32(PANEL_DISPLAY_CTRL, ulTmpValue|ulReg); #if 1 - while ((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) != (ulTmpValue|ulReg)) - { + while ((PEEK32(PANEL_DISPLAY_CTRL) & ~ulReservedBits) != (ulTmpValue|ulReg)) { cnt++; if (cnt > 1000) break; POKE32(PANEL_DISPLAY_CTRL, ulTmpValue|ulReg); } #endif - } - else { + } else { ret = -1; } return ret; diff --git a/drivers/staging/sm750fb/ddk750_mode.h b/drivers/staging/sm750fb/ddk750_mode.h index 3548d671bf97..e846dc2c3d5c 100644 --- a/drivers/staging/sm750fb/ddk750_mode.h +++ b/drivers/staging/sm750fb/ddk750_mode.h @@ -3,16 +3,14 @@ #include "ddk750_chip.h" -typedef enum _spolarity_t -{ +typedef enum _spolarity_t { POS = 0, /* positive */ NEG, /* negative */ } spolarity_t; -typedef struct _mode_parameter_t -{ +typedef struct _mode_parameter_t { /* Horizontal timing. */ unsigned long horizontal_total; unsigned long horizontal_display_end; diff --git a/drivers/staging/sm750fb/ddk750_power.c b/drivers/staging/sm750fb/ddk750_power.c index 28d4402928d8..c545c2d8139e 100644 --- a/drivers/staging/sm750fb/ddk750_power.c +++ b/drivers/staging/sm750fb/ddk750_power.c @@ -36,8 +36,7 @@ void setPowerMode(unsigned int powerMode) if (getChipType() == SM750LE) return; - switch (powerMode) - { + switch (powerMode) { case POWER_MODE_CTRL_MODE_MODE0: control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE0); break; @@ -55,16 +54,13 @@ void setPowerMode(unsigned int powerMode) } /* Set up other fields in Power Control Register */ - if (powerMode == POWER_MODE_CTRL_MODE_SLEEP) - { + if (powerMode == POWER_MODE_CTRL_MODE_SLEEP) { control_value = #ifdef VALIDATION_CHIP FIELD_SET(control_value, POWER_MODE_CTRL, 336CLK, OFF) | #endif FIELD_SET(control_value, POWER_MODE_CTRL, OSC_INPUT, OFF); - } - else - { + } else { control_value = #ifdef VALIDATION_CHIP FIELD_SET(control_value, POWER_MODE_CTRL, 336CLK, ON) | @@ -84,8 +80,7 @@ void setCurrentGate(unsigned int gate) /* Get current power mode. */ mode = getPowerMode(); - switch (mode) - { + switch (mode) { case POWER_MODE_CTRL_MODE_MODE0: gate_reg = MODE0_GATE; break; @@ -111,13 +106,10 @@ void enable2DEngine(unsigned int enable) uint32_t gate; gate = PEEK32(CURRENT_GATE); - if (enable) - { + if (enable) { gate = FIELD_SET(gate, CURRENT_GATE, DE, ON); gate = FIELD_SET(gate, CURRENT_GATE, CSC, ON); - } - else - { + } else { gate = FIELD_SET(gate, CURRENT_GATE, DE, OFF); gate = FIELD_SET(gate, CURRENT_GATE, CSC, OFF); } @@ -135,8 +127,7 @@ void enableZVPort(unsigned int enable) /* Enable ZV Port Gate */ gate = PEEK32(CURRENT_GATE); - if (enable) - { + if (enable) { gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, ON); #if 1 /* Using Software I2C */ @@ -145,9 +136,7 @@ void enableZVPort(unsigned int enable) /* Using Hardware I2C */ gate = FIELD_SET(gate, CURRENT_GATE, I2C, ON); #endif - } - else - { + } else { /* Disable ZV Port Gate. There is no way to know whether the GPIO pins are being used or not. Therefore, do not disable the GPIO gate. */ gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, OFF); diff --git a/drivers/staging/sm750fb/ddk750_power.h b/drivers/staging/sm750fb/ddk750_power.h index a20d43863c33..b7cf6b281fb6 100644 --- a/drivers/staging/sm750fb/ddk750_power.h +++ b/drivers/staging/sm750fb/ddk750_power.h @@ -1,8 +1,7 @@ #ifndef DDK750_POWER_H__ #define DDK750_POWER_H__ -typedef enum _DPMS_t -{ +typedef enum _DPMS_t { crtDPMS_ON = 0x0, crtDPMS_STANDBY = 0x1, crtDPMS_SUSPEND = 0x2, diff --git a/drivers/staging/sm750fb/ddk750_sii164.c b/drivers/staging/sm750fb/ddk750_sii164.c index 7f58fbecd35f..a5153bec37b6 100644 --- a/drivers/staging/sm750fb/ddk750_sii164.c +++ b/drivers/staging/sm750fb/ddk750_sii164.c @@ -136,8 +136,7 @@ long sii164InitChip( #endif /* Check if SII164 Chip exists */ - if ((sii164GetVendorID() == SII164_VENDOR_ID) && (sii164GetDeviceID() == SII164_DEVICE_ID)) - { + if ((sii164GetVendorID() == SII164_VENDOR_ID) && (sii164GetDeviceID() == SII164_DEVICE_ID)) { /* * Initialize SII164 controller chip. */ @@ -183,8 +182,7 @@ long sii164InitChip( else config = SII164_DESKEW_ENABLE; - switch (deskewSetting) - { + switch (deskewSetting) { case 0: config |= SII164_DESKEW_1_STEP; break; @@ -286,15 +284,12 @@ void sii164SetPower( unsigned char config; config = i2cReadReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION); - if (powerUp == 1) - { + if (powerUp == 1) { /* Power up the chip */ config &= ~SII164_CONFIGURATION_POWER_MASK; config |= SII164_CONFIGURATION_POWER_NORMAL; i2cWriteReg(SII164_I2C_ADDRESS, SII164_CONFIGURATION, config); - } - else - { + } else { /* Power down the chip */ config &= ~SII164_CONFIGURATION_POWER_MASK; config |= SII164_CONFIGURATION_POWER_DOWN; @@ -314,8 +309,7 @@ static void sii164SelectHotPlugDetectionMode( unsigned char detectReg; detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT) & ~SII164_DETECT_MONITOR_SENSE_OUTPUT_FLAG; - switch (hotPlugMode) - { + switch (hotPlugMode) { case SII164_HOTPLUG_DISABLE: detectReg |= SII164_DETECT_MONITOR_SENSE_OUTPUT_HIGH; break; diff --git a/drivers/staging/sm750fb/ddk750_sii164.h b/drivers/staging/sm750fb/ddk750_sii164.h index 0996a32e8dae..f2610c90eeb4 100644 --- a/drivers/staging/sm750fb/ddk750_sii164.h +++ b/drivers/staging/sm750fb/ddk750_sii164.h @@ -4,8 +4,7 @@ #define USE_DVICHIP /* Hot Plug detection mode structure */ -typedef enum _sii164_hot_plug_mode_t -{ +typedef enum _sii164_hot_plug_mode_t { SII164_HOTPLUG_DISABLE = 0, /* Disable Hot Plug output bit (always high). */ SII164_HOTPLUG_USE_MDI, /* Use Monitor Detect Interrupt bit. */ SII164_HOTPLUG_USE_RSEN, /* Use Receiver Sense detect bit. */ diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index db950d4062d1..23be0f774dad 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -96,8 +96,7 @@ int hw_fillrect(struct lynx_accel *accel, { u32 deCtrl; - if (accel->de_wait() != 0) - { + if (accel->de_wait() != 0) { /* int time wait and always busy,seems hardware * got something error */ pr_debug("De engine always busy\n"); @@ -159,11 +158,9 @@ unsigned int rop2) /* ROP value */ de_ctrl = 0; /* If source and destination are the same surface, need to check for overlay cases */ - if (sBase == dBase && sPitch == dPitch) - { + if (sBase == dBase && sPitch == dPitch) { /* Determine direction of operation */ - if (sy < dy) - { + if (sy < dy) { /* +----------+ |S | | +----------+ @@ -174,9 +171,7 @@ unsigned int rop2) /* ROP value */ +----------+ */ nDirection = BOTTOM_TO_TOP; - } - else if (sy > dy) - { + } else if (sy > dy) { /* +----------+ |D | | +----------+ @@ -187,13 +182,10 @@ unsigned int rop2) /* ROP value */ +----------+ */ nDirection = TOP_TO_BOTTOM; - } - else - { + } else { /* sy == dy */ - if (sx <= dx) - { + if (sx <= dx) { /* +------+---+------+ |S | | D| | | | | @@ -202,9 +194,7 @@ unsigned int rop2) /* ROP value */ +------+---+------+ */ nDirection = RIGHT_TO_LEFT; - } - else - { + } else { /* sx > dx */ /* +------+---+------+ @@ -219,8 +209,7 @@ unsigned int rop2) /* ROP value */ } } - if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) - { + if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) { sx += width - 1; sy += height - 1; dx += width - 1; @@ -255,8 +244,7 @@ unsigned int rop2) /* ROP value */ write_dpr(accel, DE_PITCH, FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch) | FIELD_VALUE(0, DE_PITCH, SOURCE, sPitch)); /* dpr10 */ - } - else + } else #endif { write_dpr(accel, DE_PITCH, @@ -344,8 +332,7 @@ int hw_imageblit(struct lynx_accel *accel, ul4BytesPerScan = ulBytesPerScan & ~3; ulBytesRemain = ulBytesPerScan & 3; - if (accel->de_wait() != 0) - { + if (accel->de_wait() != 0) { return -1; } @@ -371,8 +358,7 @@ int hw_imageblit(struct lynx_accel *accel, FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch) | FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch)); /* dpr10 */ - } - else + } else #endif { write_dpr(accel, DE_PITCH, @@ -414,16 +400,13 @@ int hw_imageblit(struct lynx_accel *accel, write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel)); /* Write MONO data (line by line) to 2D Engine data port */ - for (i = 0; i < height; i++) - { + for (i = 0; i < height; i++) { /* For each line, send the data in chunks of 4 bytes */ - for (j = 0; j < (ul4BytesPerScan/4); j++) - { + for (j = 0; j < (ul4BytesPerScan/4); j++) { write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4))); } - if (ulBytesRemain) - { + if (ulBytesRemain) { memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain); write_dpPort(accel, *(unsigned int *)ajRemain); } diff --git a/drivers/staging/sm750fb/sm750_cursor.c b/drivers/staging/sm750fb/sm750_cursor.c index 4ed7ca2c1997..ab61fe69635c 100644 --- a/drivers/staging/sm750fb/sm750_cursor.c +++ b/drivers/staging/sm750fb/sm750_cursor.c @@ -122,8 +122,7 @@ void hw_cursor_setData(struct lynx_cursor *cursor, odd=0; */ - for (i = 0; i < count; i++) - { + for (i = 0; i < count; i++) { color = *pcol++; mask = *pmsk++; data = 0; @@ -137,11 +136,10 @@ void hw_cursor_setData(struct lynx_cursor *cursor, else opr = mask & color; - for (j = 0; j < 8; j++) - { + for (j = 0; j < 8; j++) { - if (opr & (0x80 >> j)) - { /* use fg color,id = 2 */ + if (opr & (0x80 >> j)) { + /* use fg color,id = 2 */ data |= 2 << (j*2); } else { /* use bg color,id = 1 */ @@ -204,8 +202,7 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, pstart = cursor->vstart; pbuffer = pstart; - for (i = 0; i < count; i++) - { + for (i = 0; i < count; i++) { color = *pcol++; mask = *pmsk++; data = 0; @@ -217,11 +214,10 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, else opr = mask & color; - for (j = 0; j < 8; j++) - { + for (j = 0; j < 8; j++) { - if (opr & (0x80 >> j)) - { /* use fg color,id = 2 */ + if (opr & (0x80 >> j)) { + /* use fg color,id = 2 */ data |= 2 << (j*2); } else { /* use bg color,id = 1 */ @@ -237,8 +233,7 @@ void hw_cursor_setData2(struct lynx_cursor *cursor, iowrite16(data, pbuffer); /* assume pitch is 1,2,4,8,...*/ - if (!(i&(pitch-1))) - { + if (!(i&(pitch-1))) { /* need a return */ pstart += offset; pbuffer = pstart; -- cgit v1.3-6-gb490 From cebafd8d6fd3a55671c2c5ee88ff27ad1bf9f1d3 Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:46 -0700 Subject: staging: sm750fb: move while to follow do close brace Fixes checkpatch.pl error: ERROR: while should follow close brace '}' Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_display.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c index a64ea32b91ae..abd628343fed 100644 --- a/drivers/staging/sm750fb/ddk750_display.c +++ b/drivers/staging/sm750fb/ddk750_display.c @@ -139,16 +139,14 @@ static void waitNextVerticalSync(int ctrl, int delay) status = FIELD_GET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, PANEL_VSYNC); - } - while (status == SYSTEM_CTRL_PANEL_VSYNC_ACTIVE); + } while (status == SYSTEM_CTRL_PANEL_VSYNC_ACTIVE); /* Wait for start of vsync. */ do { status = FIELD_GET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, PANEL_VSYNC); - } - while (status == SYSTEM_CTRL_PANEL_VSYNC_INACTIVE); + } while (status == SYSTEM_CTRL_PANEL_VSYNC_INACTIVE); } } else { @@ -168,16 +166,14 @@ static void waitNextVerticalSync(int ctrl, int delay) status = FIELD_GET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, CRT_VSYNC); - } - while (status == SYSTEM_CTRL_CRT_VSYNC_ACTIVE); + } while (status == SYSTEM_CTRL_CRT_VSYNC_ACTIVE); /* Wait for start of vsync. */ do { status = FIELD_GET(PEEK32(SYSTEM_CTRL), SYSTEM_CTRL, CRT_VSYNC); - } - while (status == SYSTEM_CTRL_CRT_VSYNC_INACTIVE); + } while (status == SYSTEM_CTRL_CRT_VSYNC_INACTIVE); } } } -- cgit v1.3-6-gb490 From 7b05cbe8b60beb31919baa2b010cd7776904b17b Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:47 -0700 Subject: staging: sm750fb: remove unnecessary braces Fixes checkpatch.pl warning: WARNING: braces {} are not necessary for single statement blocks Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750_accel.c | 9 +++------ drivers/staging/sm750fb/sm750_hw.c | 6 ++---- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index 23be0f774dad..0f563a9f3d20 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -259,9 +259,8 @@ unsigned int rop2) /* ROP value */ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/Bpp)) | FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (sPitch/Bpp))); /* dpr3c */ - if (accel->de_wait() != 0) { + if (accel->de_wait() != 0) return -1; - } { @@ -332,9 +331,8 @@ int hw_imageblit(struct lynx_accel *accel, ul4BytesPerScan = ulBytesPerScan & ~3; ulBytesRemain = ulBytesPerScan & 3; - if (accel->de_wait() != 0) { + if (accel->de_wait() != 0) return -1; - } /* 2D Source Base. Use 0 for HOST Blt. @@ -402,9 +400,8 @@ int hw_imageblit(struct lynx_accel *accel, /* Write MONO data (line by line) to 2D Engine data port */ for (i = 0; i < height; i++) { /* For each line, send the data in chunks of 4 bytes */ - for (j = 0; j < (ul4BytesPerScan/4); j++) { + for (j = 0; j < (ul4BytesPerScan/4); j++) write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4))); - } if (ulBytesRemain) { memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain); diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index fb9c631ff818..d1d6ae745feb 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -188,9 +188,8 @@ int hw_sm750_inithw(struct lynx_share *share, struct pci_dev *pdev) } /* init 2d engine */ - if (!share->accel_off) { + if (!share->accel_off) hw_sm750_initAccel(share); - } return 0; } @@ -537,9 +536,8 @@ int hw_sm750_setBLANK(struct lynxfb_output *output, int blank) POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(PEEK32(CRT_DISPLAY_CTRL), CRT_DISPLAY_CTRL, BLANK, crtdb)); } - if (output->paths & sm750_panel) { + if (output->paths & sm750_panel) POKE32(PANEL_DISPLAY_CTRL, FIELD_VALUE(PEEK32(PANEL_DISPLAY_CTRL), PANEL_DISPLAY_CTRL, DATA, pps)); - } return 0; } -- cgit v1.3-6-gb490 From 40403c1b13cb01d9125df80789b574c2d4172cc0 Mon Sep 17 00:00:00 2001 From: Juston Li Date: Tue, 14 Jul 2015 21:14:48 -0700 Subject: staging: sm750fb: add missing blank line after declarations Fixes checkpatch.pl WARNING: Missing a blank line after declarations Signed-off-by: Juston Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_chip.c | 1 + drivers/staging/sm750fb/ddk750_display.c | 2 ++ drivers/staging/sm750fb/ddk750_dvi.c | 1 + drivers/staging/sm750fb/ddk750_mode.c | 3 +++ drivers/staging/sm750fb/ddk750_power.c | 1 + drivers/staging/sm750fb/ddk750_sii164.c | 1 + drivers/staging/sm750fb/sm750_accel.c | 1 + drivers/staging/sm750fb/sm750_cursor.c | 2 ++ drivers/staging/sm750fb/sm750_hw.c | 7 +++++++ 9 files changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_chip.c b/drivers/staging/sm750fb/ddk750_chip.c index d7435d7302b4..5e6798ea9468 100644 --- a/drivers/staging/sm750fb/ddk750_chip.c +++ b/drivers/staging/sm750fb/ddk750_chip.c @@ -474,6 +474,7 @@ unsigned int calcPllValue(unsigned int request_orig, pll_value_t *pll) M += (fl_quo*X % 10000) > 5000?1:0; if (M < 256 && M > 0) { unsigned int diff; + tmpClock = pll->inputFreq * M / N / X; diff = absDiff(tmpClock, request_orig); if (diff < miniDiff) { diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c index abd628343fed..8348113482d9 100644 --- a/drivers/staging/sm750fb/ddk750_display.c +++ b/drivers/staging/sm750fb/ddk750_display.c @@ -121,6 +121,7 @@ static void setDisplayControl(int ctrl, int dispState) static void waitNextVerticalSync(int ctrl, int delay) { unsigned int status; + if (!ctrl) { /* primary controller */ @@ -210,6 +211,7 @@ static void swPanelPowerSequence(int disp, int delay) void ddk750_setLogicalDispOut(disp_output_t output) { unsigned int reg; + if (output & PNL_2_USAGE) { /* set panel path controller select */ reg = PEEK32(PANEL_DISPLAY_CTRL); diff --git a/drivers/staging/sm750fb/ddk750_dvi.c b/drivers/staging/sm750fb/ddk750_dvi.c index a18bb4cd08b9..a7a23514ac39 100644 --- a/drivers/staging/sm750fb/ddk750_dvi.c +++ b/drivers/staging/sm750fb/ddk750_dvi.c @@ -43,6 +43,7 @@ int dviInit( ) { dvi_ctrl_device_t *pCurrentDviCtrl; + pCurrentDviCtrl = g_dcftSupportedDviController; if (pCurrentDviCtrl->pfnInit != NULL) { return pCurrentDviCtrl->pfnInit(edgeSelect, busSelect, dualEdgeClkSelect, hsyncEnable, diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c index 9d104469ca16..2399b175ade0 100644 --- a/drivers/staging/sm750fb/ddk750_mode.c +++ b/drivers/staging/sm750fb/ddk750_mode.c @@ -80,6 +80,7 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) int ret = 0; int cnt = 0; unsigned int ulTmpValue, ulReg; + if (pll->clockType == SECONDARY_PLL) { /* programe secondary pixel clock */ POKE32(CRT_PLL_CTRL, formatPllReg(pll)); @@ -120,6 +121,7 @@ static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll) } else if (pll->clockType == PRIMARY_PLL) { unsigned int ulReservedBits; + POKE32(PANEL_PLL_CTRL, formatPllReg(pll)); POKE32(PANEL_HORIZONTAL_TOTAL, @@ -184,6 +186,7 @@ int ddk750_setModeTiming(mode_parameter_t *parm, clock_type_t clock) { pll_value_t pll; unsigned int uiActualPixelClk; + pll.inputFreq = DEFAULT_INPUT_CLOCK; pll.clockType = clock; diff --git a/drivers/staging/sm750fb/ddk750_power.c b/drivers/staging/sm750fb/ddk750_power.c index c545c2d8139e..c8c51be53d68 100644 --- a/drivers/staging/sm750fb/ddk750_power.c +++ b/drivers/staging/sm750fb/ddk750_power.c @@ -5,6 +5,7 @@ void ddk750_setDPMS(DPMS_t state) { unsigned int value; + if (getChipType() == SM750LE) { value = PEEK32(CRT_DISPLAY_CTRL); POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(value, CRT_DISPLAY_CTRL, DPMS, state)); diff --git a/drivers/staging/sm750fb/ddk750_sii164.c b/drivers/staging/sm750fb/ddk750_sii164.c index a5153bec37b6..0bdf3db11df0 100644 --- a/drivers/staging/sm750fb/ddk750_sii164.c +++ b/drivers/staging/sm750fb/ddk750_sii164.c @@ -340,6 +340,7 @@ void sii164EnableHotPlugDetection( ) { unsigned char detectReg; + detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); /* Depending on each DVI controller, need to enable the hot plug based on each diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index 0f563a9f3d20..1dd06a2e4ede 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -152,6 +152,7 @@ unsigned int rop2) /* ROP value */ { unsigned int nDirection, de_ctrl; int opSign; + nDirection = LEFT_TO_RIGHT; /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */ opSign = 1; diff --git a/drivers/staging/sm750fb/sm750_cursor.c b/drivers/staging/sm750fb/sm750_cursor.c index ab61fe69635c..2400c6c75863 100644 --- a/drivers/staging/sm750fb/sm750_cursor.c +++ b/drivers/staging/sm750fb/sm750_cursor.c @@ -61,6 +61,7 @@ writel((data), cursor->mmio + (addr)) void hw_cursor_enable(struct lynx_cursor *cursor) { u32 reg; + reg = FIELD_VALUE(0, HWC_ADDRESS, ADDRESS, cursor->offset)| FIELD_SET(0, HWC_ADDRESS, EXT, LOCAL)| FIELD_SET(0, HWC_ADDRESS, ENABLE, ENABLE); @@ -81,6 +82,7 @@ void hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y) { u32 reg; + reg = FIELD_VALUE(0, HWC_LOCATION, Y, y)| FIELD_VALUE(0, HWC_LOCATION, X, x); POKE32(HWC_LOCATION, reg); diff --git a/drivers/staging/sm750fb/sm750_hw.c b/drivers/staging/sm750fb/sm750_hw.c index d1d6ae745feb..7317ba9b7fe5 100644 --- a/drivers/staging/sm750fb/sm750_hw.c +++ b/drivers/staging/sm750fb/sm750_hw.c @@ -244,6 +244,7 @@ int hw_sm750_output_setMode(struct lynxfb_output *output, } else { /* just open DISPLAY_CONTROL_750LE register bit 3:0*/ u32 reg; + reg = PEEK32(DISPLAY_CONTROL_750LE); reg |= 0xf; POKE32(DISPLAY_CONTROL_750LE, reg); @@ -418,6 +419,7 @@ int hw_sm750_setColReg(struct lynxfb_crtc *crtc, ushort index, ushort red, ushort green, ushort blue) { static unsigned int add[] = {PANEL_PALETTE_RAM, CRT_PALETTE_RAM}; + POKE32(add[crtc->channel] + index*4, (red<<16)|(green<<8)|blue); return 0; } @@ -546,6 +548,7 @@ int hw_sm750_setBLANK(struct lynxfb_output *output, int blank) void hw_sm750_initAccel(struct lynx_share *share) { u32 reg; + enable2DEngine(1); if (getChipType() == SM750LE) { @@ -575,8 +578,10 @@ void hw_sm750_initAccel(struct lynx_share *share) int hw_sm750le_deWait(void) { int i = 0x10000000; + while (i--) { unsigned int dwVal = PEEK32(DE_STATE2); + if ((FIELD_GET(dwVal, DE_STATE2, DE_STATUS) == DE_STATE2_DE_STATUS_IDLE) && (FIELD_GET(dwVal, DE_STATE2, DE_FIFO) == DE_STATE2_DE_FIFO_EMPTY) && (FIELD_GET(dwVal, DE_STATE2, DE_MEM_FIFO) == DE_STATE2_DE_MEM_FIFO_EMPTY)) { @@ -591,8 +596,10 @@ int hw_sm750le_deWait(void) int hw_sm750_deWait(void) { int i = 0x10000000; + while (i--) { unsigned int dwVal = PEEK32(SYSTEM_CTRL); + if ((FIELD_GET(dwVal, SYSTEM_CTRL, DE_STATUS) == SYSTEM_CTRL_DE_STATUS_IDLE) && (FIELD_GET(dwVal, SYSTEM_CTRL, DE_FIFO) == SYSTEM_CTRL_DE_FIFO_EMPTY) && (FIELD_GET(dwVal, SYSTEM_CTRL, DE_MEM_FIFO) == SYSTEM_CTRL_DE_MEM_FIFO_EMPTY)) { -- cgit v1.3-6-gb490 From cd13f5ab42a63d267f452ac5fd641136c7b8f17c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 14:12:02 +0200 Subject: drm/i915: fill in more mode members Fill in driver type, hsync, vrefresh and name. Those members are not read out but can be calculated from the mode. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4e64dae78360..cec0a6c4ef2a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7817,9 +7817,14 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, mode->vsync_end = pipe_config->base.adjusted_mode.crtc_vsync_end; mode->flags = pipe_config->base.adjusted_mode.flags; + mode->type = DRM_MODE_TYPE_DRIVER; mode->clock = pipe_config->base.adjusted_mode.crtc_clock; mode->flags |= pipe_config->base.adjusted_mode.flags; + + mode->hsync = drm_mode_hsync(mode); + mode->vrefresh = drm_mode_vrefresh(mode); + drm_mode_set_name(mode); } static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) -- cgit v1.3-6-gb490 From 1f7457b135b075e7a60c9133723363045084c333 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 11:55:05 +0200 Subject: drm/i915: Fix noatomic crtc disabling, v2. This fixes the breakage caused by commit eddfcbcdc27fbecb33bff098967bbdd7ca75bfa6 Author: Maarten Lankhorst Date: Mon Jun 15 12:33:53 2015 +0200 drm/i915: Update less state during modeset. No need to repeatedly call update_watermarks, or update_fbc. Down to a single call to update_watermarks in .crtc_enable Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter Add missing shared dpll disable to the noatomic disable function. This function will be replaced by its atomic counterpart soon. Changes since v1: - intel_crtc->active and watermarks are fixed by a patch from Patrik Jakobsson Signed-off-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cec0a6c4ef2a..10a172681138 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6214,6 +6214,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) intel_crtc_disable_planes(crtc, crtc->state->plane_mask); dev_priv->display.crtc_disable(crtc); + intel_disable_shared_dpll(intel_crtc); domains = intel_crtc->enabled_power_domains; for_each_power_domain(domain, domains) -- cgit v1.3-6-gb490 From 346add7834557b5b9628b9bf2387106d42e631d4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 14 Jul 2015 18:07:30 +0200 Subject: drm/i915: Use expcitly fixed type in compat32 structs I was confused shortly whether the compat was needed for the int, until I noticed the pointer in the original. Also remove typedef. v2: Review from Chris. - Add comments. - Also change the int param in the original structure. Cc: Chris Wilson Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_ioc32.c | 13 +++++++++---- include/uapi/drm/i915_drm.h | 6 +++++- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_ioc32.c b/drivers/gpu/drm/i915/i915_ioc32.c index 6eec2221b44e..a5a2d5b3f44b 100644 --- a/drivers/gpu/drm/i915/i915_ioc32.c +++ b/drivers/gpu/drm/i915/i915_ioc32.c @@ -35,15 +35,20 @@ #include #include "i915_drv.h" -typedef struct drm_i915_getparam32 { - int param; +struct drm_i915_getparam32 { + s32 param; + /* + * We screwed up the generic ioctl struct here and used a variable-sized + * pointer. Use u32 in the compat struct to match the 32bit pointer + * userspace expects. + */ u32 value; -} drm_i915_getparam32_t; +}; static int compat_i915_getparam(struct file *file, unsigned int cmd, unsigned long arg) { - drm_i915_getparam32_t req32; + struct drm_i915_getparam32 req32; drm_i915_getparam_t __user *request; if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index e7c29f1659ad..192027b4f031 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -358,7 +358,11 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_RESOURCE_STREAMER 36 typedef struct drm_i915_getparam { - int param; + s32 param; + /* + * WARNING: Using pointers instead of fixed-size u64 means we need to write + * compat32 code. Don't repeat this mistake. + */ int __user *value; } drm_i915_getparam_t; -- cgit v1.3-6-gb490 From 1aae50a245736aec603c319fea2a83a90dc69aba Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 10 Jul 2015 16:03:25 -0700 Subject: spi: spi-pxa2xx: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Cc: Daniel Mack Cc: Haojian Zhuang Cc: Robert Jarzmik Cc: Mark Brown Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx-pci.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 3cfd4357489a..d19d7f28aecb 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include -- cgit v1.3-6-gb490 From ec081cb337a1edc793d7aa53baa9b8afa096678d Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 15 Jul 2015 19:25:42 +0900 Subject: drm: Fix warning with make xmldocs caused by drm_irq.c This patch fix following warnings. Warning(.//drivers/gpu/drm/drm_irq.c:1279): No description found for parameter drm_crtc' Warning(.//drivers/gpu/drm/drm_irq.c:1279): Excess function parameter 'crtc' description in 'drm_crtc_vblank_reset' Signed-off-by: Masanari Iida Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index f9cc68fbd2a3..9fd784b8966b 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1267,7 +1267,7 @@ EXPORT_SYMBOL(drm_crtc_vblank_off); /** * drm_crtc_vblank_reset - reset vblank state to off on a CRTC - * @crtc: CRTC in question + * @drm_crtc: CRTC in question * * Drivers can use this function to reset the vblank state to off at load time. * Drivers should use this together with the drm_crtc_vblank_off() and -- cgit v1.3-6-gb490 From 6381b55016ec76f18cbc8685ca0774dd4584651b Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Tue, 14 Jul 2015 14:41:15 +0100 Subject: drm/i915/gen9: Implement WaDisableKillLogic for gen 9 v2: Patch leakage fixed Signed-off-by: Nick Hoath Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 97794bc753f2..ef5f69a1607f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -160,6 +160,7 @@ #define GAM_ECOCHK 0x4090 #define BDW_DISABLE_HDC_INVALIDATION (1<<25) #define ECOCHK_SNB_BIT (1<<10) +#define ECOCHK_DIS_TLB (1<<8) #define HSW_ECOCHK_ARB_PRIO_SOL (1<<6) #define ECOCHK_PPGTT_CACHE64B (0x3<<3) #define ECOCHK_PPGTT_CACHE4B (0x0<<3) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 025978548fb6..3a48c4f21f11 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -59,6 +59,10 @@ static void gen9_init_clock_gating(struct drm_device *dev) /* WaEnableLbsSlaRetryTimerDecrement:skl */ I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) | GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE); + + /* WaDisableKillLogic:bxt,skl */ + I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | + ECOCHK_DIS_TLB); } static void skl_init_clock_gating(struct drm_device *dev) -- cgit v1.3-6-gb490 From 0504cffc7b128dc4bd751821abe7c47203d7bd62 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 14 Jul 2015 15:01:27 +0100 Subject: drm/i915: Enable WA batch buffers for Gen9 This patch only enables support for Gen9, the actual WA will be initialized in subsequent patches. The WARN that we use to warn user if WA batch support is not available for a particular Gen is replaced with DRM_ERROR as warning here doesn't really add much value. v2: include all infrastructure bits in this patch so that subsequent changes only correspond the WA added (Chris) v3: use updated macro. Reviewed-by: Mika Kuoppala Cc: Imre Deak Cc: Mika Kuoppala Signed-off-by: Arun Siluvery Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 50 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d7f66d289970..f1a382c685a5 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1248,6 +1248,35 @@ static int gen8_init_perctx_bb(struct intel_engine_cs *ring, return wa_ctx_end(wa_ctx, *offset = index, 1); } +static int gen9_init_indirectctx_bb(struct intel_engine_cs *ring, + struct i915_wa_ctx_bb *wa_ctx, + uint32_t *const batch, + uint32_t *offset) +{ + uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + + /* FIXME: Replace me with WA */ + wa_ctx_emit(batch, index, MI_NOOP); + + /* Pad to end of cacheline */ + while (index % CACHELINE_DWORDS) + wa_ctx_emit(batch, index, MI_NOOP); + + return wa_ctx_end(wa_ctx, *offset = index, CACHELINE_DWORDS); +} + +static int gen9_init_perctx_bb(struct intel_engine_cs *ring, + struct i915_wa_ctx_bb *wa_ctx, + uint32_t *const batch, + uint32_t *offset) +{ + uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + + wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END); + + return wa_ctx_end(wa_ctx, *offset = index, 1); +} + static int lrc_setup_wa_ctx_obj(struct intel_engine_cs *ring, u32 size) { int ret; @@ -1289,10 +1318,11 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring) WARN_ON(ring->id != RCS); /* update this when WA for higher Gen are added */ - if (WARN(INTEL_INFO(ring->dev)->gen > 8, - "WA batch buffer is not initialized for Gen%d\n", - INTEL_INFO(ring->dev)->gen)) + if (INTEL_INFO(ring->dev)->gen > 9) { + DRM_ERROR("WA batch buffer is not initialized for Gen%d\n", + INTEL_INFO(ring->dev)->gen); return 0; + } /* some WA perform writes to scratch page, ensure it is valid */ if (ring->scratch.obj == NULL) { @@ -1324,6 +1354,20 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring) &offset); if (ret) goto out; + } else if (INTEL_INFO(ring->dev)->gen == 9) { + ret = gen9_init_indirectctx_bb(ring, + &wa_ctx->indirect_ctx, + batch, + &offset); + if (ret) + goto out; + + ret = gen9_init_perctx_bb(ring, + &wa_ctx->per_ctx, + batch, + &offset); + if (ret) + goto out; } out: -- cgit v1.3-6-gb490 From 0907c8f7e0047956dabdd70368a710dc048793eb Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 14 Jul 2015 15:01:28 +0100 Subject: drm/i915/gen9: Add WaDisableCtxRestoreArbitration workaround In Indirect and Per context w/a batch buffer, +WaDisableCtxRestoreArbitration v2: SKL revision id was used for BXT, copy paste error found during internal review (Bob Beckett). v3: use updated macro. Reviewed-by: Mika Kuoppala Cc: Robert Beckett Cc: Mika Kuoppala Cc: Imre Deak Signed-off-by: Arun Siluvery Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index f1a382c685a5..07fce8c6e874 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1253,10 +1253,13 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *ring, uint32_t *const batch, uint32_t *offset) { + struct drm_device *dev = ring->dev; uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); - /* FIXME: Replace me with WA */ - wa_ctx_emit(batch, index, MI_NOOP); + /* WaDisableCtxRestoreArbitration:skl,bxt */ + if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) || + (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) + wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE); /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) @@ -1270,8 +1273,14 @@ static int gen9_init_perctx_bb(struct intel_engine_cs *ring, uint32_t *const batch, uint32_t *offset) { + struct drm_device *dev = ring->dev; uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + /* WaDisableCtxRestoreArbitration:skl,bxt */ + if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) || + (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) + wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE); + wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END); return wa_ctx_end(wa_ctx, *offset = index, 1); -- cgit v1.3-6-gb490 From a4106a782d11d44f6740ec8868ad1863546f832a Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 14 Jul 2015 15:01:29 +0100 Subject: drm/i915/gen9: Add WaFlushCoherentL3CacheLinesAtContextSwitch workaround In Indirect context w/a batch buffer, +WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt v2: address static checker warning where unsigned value was checked for less than zero which is never true (Dan Carpenter). v3: The WA uses default value of GEN8_L3SQCREG4 during flush but that disables some other WA; update default value to retain it and document dependency (Mika). Cc: Mika Kuoppala Cc: Imre Deak Signed-off-by: Arun Siluvery Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 16 ++++++++++++++++ drivers/gpu/drm/i915/intel_pm.c | 3 +++ 2 files changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 07fce8c6e874..b7e16293b9a9 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1097,6 +1097,15 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring, { uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); + /* + * WaDisableLSQCROPERFforOCL:skl + * This WA is implemented in skl_init_clock_gating() but since + * this batch updates GEN8_L3SQCREG4 with default value we need to + * set this bit here to retain the WA during flush. + */ + if (IS_SKYLAKE(ring->dev) && INTEL_REVID(ring->dev) <= SKL_REVID_E0) + l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS; + wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8(1) | MI_SRM_LRM_GLOBAL_GTT)); wa_ctx_emit(batch, index, GEN8_L3SQCREG4); @@ -1253,6 +1262,7 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *ring, uint32_t *const batch, uint32_t *offset) { + int ret; struct drm_device *dev = ring->dev; uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); @@ -1261,6 +1271,12 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *ring, (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE); + /* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt */ + ret = gen8_emit_flush_coherentl3_wa(ring, batch, index); + if (ret < 0) + return ret; + index = ret; + /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) wa_ctx_emit(batch, index, MI_NOOP); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3a48c4f21f11..5eeddc97ca2a 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -95,6 +95,9 @@ static void skl_init_clock_gating(struct drm_device *dev) _MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE)); } + /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes + * involving this register should also be added to WA batch as required. + */ if (INTEL_REVID(dev) <= SKL_REVID_E0) /* WaDisableLSQCROPERFforOCL:skl */ I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | -- cgit v1.3-6-gb490 From 9b01435d2802148fcf6e061df0e4926768eeb133 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 14 Jul 2015 15:01:30 +0100 Subject: drm/i915/gen9: Add WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken In Indirect context w/a batch buffer, +WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken v2: SKL revision id was used for BXT, copy paste error found during internal review (Bob Beckett). v3: explain why part of the WA is in Per ctx batch (Mika) Cc: Mika Kuoppala Cc: Imre Deak Signed-off-by: Arun Siluvery Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 10 ++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index b7e16293b9a9..83ed0f7fcbe2 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1292,6 +1292,16 @@ static int gen9_init_perctx_bb(struct intel_engine_cs *ring, struct drm_device *dev = ring->dev; uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ + if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_B0)) || + (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) { + wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1)); + wa_ctx_emit(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0); + wa_ctx_emit(batch, index, + _MASKED_BIT_ENABLE(DISABLE_PIXEL_MASK_CAMMING)); + wa_ctx_emit(batch, index, MI_NOOP); + } + /* WaDisableCtxRestoreArbitration:skl,bxt */ if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) || (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index bddc9032e17e..1c14233d179f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -946,8 +946,11 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1, GEN9_RHWO_OPTIMIZATION_DISABLE); - WA_SET_BIT_MASKED(GEN9_SLICE_COMMON_ECO_CHICKEN0, - DISABLE_PIXEL_MASK_CAMMING); + /* + * WA also requires GEN9_SLICE_COMMON_ECO_CHICKEN0[14:14] to be set + * but we do that in per ctx batchbuffer as there is an issue + * with this register not getting restored on ctx restore + */ } if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) >= SKL_REVID_C0) || -- cgit v1.3-6-gb490 From 74c090b1bdc57b1c9f1361908cca5a3d8a80fb08 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:30 +0200 Subject: drm/i915: Use full atomic modeset. Huzzah! \o/ Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_params.c | 5 - drivers/gpu/drm/i915/intel_atomic.c | 123 --------------- drivers/gpu/drm/i915/intel_display.c | 279 ++++++----------------------------- drivers/gpu/drm/i915/intel_drv.h | 5 - 6 files changed, 43 insertions(+), 372 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index db48aee7f140..f13ed1ef6641 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1731,7 +1731,7 @@ static int __init i915_init(void) * to the atomic ioctl and the atomic properties. Only plane operations on * a single CRTC will actually work. */ - if (i915.nuclear_pageflip) + if (driver.driver_features & DRIVER_MODESET) driver.driver_features |= DRIVER_ATOMIC; return drm_pci_init(&driver, &i915_pci_driver); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2714228e3456..4af33d59d507 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2614,7 +2614,6 @@ struct i915_params { int use_mmio_flip; int mmio_debug; bool verbose_state_checks; - bool nuclear_pageflip; int edp_vswing; }; extern struct i915_params i915 __read_mostly; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 7983fe48a654..5f4e7295295f 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -51,7 +51,6 @@ struct i915_params i915 __read_mostly = { .use_mmio_flip = 0, .mmio_debug = 0, .verbose_state_checks = 1, - .nuclear_pageflip = 0, .edp_vswing = 0, }; @@ -176,10 +175,6 @@ module_param_named(verbose_state_checks, i915.verbose_state_checks, bool, 0600); MODULE_PARM_DESC(verbose_state_checks, "Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions."); -module_param_named_unsafe(nuclear_pageflip, i915.nuclear_pageflip, bool, 0600); -MODULE_PARM_DESC(nuclear_pageflip, - "Force atomic modeset functionality; only planes work for now (default: false)."); - /* WA to get away with the default setting in VBT for early platforms.Will be removed */ module_param_named_unsafe(edp_vswing, i915.edp_vswing, int, 0400); MODULE_PARM_DESC(edp_vswing, diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index dcf4fb458649..e2531cf59266 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -35,129 +35,6 @@ #include #include "intel_drv.h" - -/** - * intel_atomic_check - validate state object - * @dev: drm device - * @state: state to validate - */ -int intel_atomic_check(struct drm_device *dev, - struct drm_atomic_state *state) -{ - int nplanes = dev->mode_config.num_total_plane; - int ncrtcs = dev->mode_config.num_crtc; - int nconnectors = dev->mode_config.num_connector; - enum pipe nuclear_pipe = INVALID_PIPE; - struct intel_crtc *nuclear_crtc = NULL; - struct intel_crtc_state *crtc_state = NULL; - int ret; - int i; - bool not_nuclear = false; - - to_intel_atomic_state(state)->cdclk = to_i915(dev)->cdclk_freq; - - /* - * FIXME: At the moment, we only support "nuclear pageflip" on a - * single CRTC. Cross-crtc updates will be added later. - */ - for (i = 0; i < nplanes; i++) { - struct intel_plane *plane = to_intel_plane(state->planes[i]); - if (!plane) - continue; - - if (nuclear_pipe == INVALID_PIPE) { - nuclear_pipe = plane->pipe; - } else if (nuclear_pipe != plane->pipe) { - DRM_DEBUG_KMS("i915 only support atomic plane operations on a single CRTC at the moment\n"); - return -EINVAL; - } - } - - /* - * FIXME: We only handle planes for now; make sure there are no CRTC's - * or connectors involved. - */ - state->allow_modeset = false; - for (i = 0; i < ncrtcs; i++) { - struct intel_crtc *crtc = to_intel_crtc(state->crtcs[i]); - if (crtc) - memset(&crtc->atomic, 0, sizeof(crtc->atomic)); - if (crtc && crtc->pipe != nuclear_pipe) - not_nuclear = true; - if (crtc && crtc->pipe == nuclear_pipe) { - nuclear_crtc = crtc; - crtc_state = to_intel_crtc_state(state->crtc_states[i]); - } - } - for (i = 0; i < nconnectors; i++) - if (state->connectors[i] != NULL) - not_nuclear = true; - - if (not_nuclear) { - DRM_DEBUG_KMS("i915 only supports atomic plane operations at the moment\n"); - return -EINVAL; - } - - ret = drm_atomic_helper_check_planes(dev, state); - if (ret) - return ret; - - return ret; -} - - -/** - * intel_atomic_commit - commit validated state object - * @dev: DRM device - * @state: the top-level driver state object - * @async: asynchronous commit - * - * This function commits a top-level state object that has been validated - * with drm_atomic_helper_check(). - * - * FIXME: Atomic modeset support for i915 is not yet complete. At the moment - * we can only handle plane-related operations and do not yet support - * asynchronous commit. - * - * RETURNS - * Zero for success or -errno. - */ -int intel_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool async) -{ - struct drm_crtc_state *crtc_state; - struct drm_crtc *crtc; - int ret; - int i; - - if (async) { - DRM_DEBUG_KMS("i915 does not yet support async commit\n"); - return -EINVAL; - } - - ret = drm_atomic_helper_prepare_planes(dev, state); - if (ret) - return ret; - - /* Point of no return */ - drm_atomic_helper_swap_state(dev, state); - - for_each_crtc_in_state(state, crtc, crtc_state, i) { - to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); - - drm_atomic_helper_commit_planes_on_crtc(crtc_state); - } - - /* FIXME: This function should eventually call __intel_set_mode when needed */ - - drm_atomic_helper_wait_for_vblanks(dev, state); - drm_atomic_helper_cleanup_planes(dev, state); - drm_atomic_state_free(state); - - return 0; -} - /** * intel_connector_atomic_get_property - fetch connector property value * @connector: connector to fetch property for diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 10a172681138..83d7753b8b07 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -86,7 +86,6 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, static void ironlake_pch_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); -static int intel_set_mode(struct drm_atomic_state *state); static int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, struct drm_mode_fb_cmd2 *mode_cmd, @@ -111,14 +110,6 @@ static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state, int num_connectors); static void intel_modeset_setup_hw_state(struct drm_device *dev); -static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) -{ - if (!connector->mst_port) - return connector->encoder; - else - return &connector->mst_port->mst_encoders[pipe]->base; -} - typedef struct { int min, max; } intel_range_t; @@ -6262,7 +6253,7 @@ int intel_display_suspend(struct drm_device *dev) } if (crtc_mask) { - ret = intel_set_mode(state); + ret = drm_atomic_commit(state); if (!ret) { for_each_crtc(dev, crtc) @@ -6316,7 +6307,7 @@ int intel_crtc_control(struct drm_crtc *crtc, bool enable) } pipe_config->base.active = enable; - ret = intel_set_mode(state); + ret = drm_atomic_commit(state); if (!ret) return ret; @@ -10430,7 +10421,7 @@ retry: drm_mode_copy(&crtc_state->base.mode, mode); - if (intel_set_mode(state)) { + if (drm_atomic_commit(state)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); @@ -10498,7 +10489,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (ret) goto fail; - ret = intel_set_mode(state); + ret = drm_atomic_commit(state); if (ret) goto fail; @@ -13119,7 +13110,6 @@ static int intel_modeset_all_pipes(struct drm_atomic_state *state) } -/* Code that should eventually be part of atomic_check() */ static int intel_modeset_checks(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; @@ -13160,15 +13150,20 @@ static int intel_modeset_checks(struct drm_atomic_state *state) return 0; } -static int -intel_modeset_compute_config(struct drm_atomic_state *state) +/** + * intel_atomic_check - validate state object + * @dev: drm device + * @state: state to validate + */ +static int intel_atomic_check(struct drm_device *dev, + struct drm_atomic_state *state) { struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int ret, i; bool any_ms = false; - ret = drm_atomic_helper_check_modeset(state->dev, state); + ret = drm_atomic_helper_check_modeset(dev, state); if (ret) return ret; @@ -13231,9 +13226,26 @@ intel_modeset_compute_config(struct drm_atomic_state *state) return drm_atomic_helper_check_planes(state->dev, state); } -static int __intel_set_mode(struct drm_atomic_state *state) +/** + * intel_atomic_commit - commit validated state object + * @dev: DRM device + * @state: the top-level driver state object + * @async: asynchronous commit + * + * This function commits a top-level state object that has been validated + * with drm_atomic_helper_check(). + * + * FIXME: Atomic modeset support for i915 is not yet complete. At the moment + * we can only handle plane-related operations and do not yet support + * asynchronous commit. + * + * RETURNS + * Zero for success or -errno. + */ +static int intel_atomic_commit(struct drm_device *dev, + struct drm_atomic_state *state, + bool async) { - struct drm_device *dev = state->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; @@ -13241,6 +13253,11 @@ static int __intel_set_mode(struct drm_atomic_state *state) int i; bool any_ms = false; + if (async) { + DRM_DEBUG_KMS("i915 does not yet support async commit\n"); + return -EINVAL; + } + ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) return ret; @@ -13285,34 +13302,14 @@ static int __intel_set_mode(struct drm_atomic_state *state) /* FIXME: add subpixel order */ + drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); - drm_atomic_state_free(state); - return 0; -} - -static int intel_set_mode_checked(struct drm_atomic_state *state) -{ - struct drm_device *dev = state->dev; - int ret; - - ret = __intel_set_mode(state); - if (ret == 0) + if (any_ms) intel_modeset_check_state(dev); - return ret; -} - -static int intel_set_mode(struct drm_atomic_state *state) -{ - int ret; - - ret = intel_modeset_compute_config(state); - if (ret) - return ret; - - return intel_set_mode_checked(state); + return 0; } void intel_crtc_restore_mode(struct drm_crtc *crtc) @@ -13339,7 +13336,7 @@ retry: goto out; crtc_state->mode_changed = true; - ret = intel_set_mode(state); + ret = drm_atomic_commit(state); } if (ret == -EDEADLK) { @@ -13355,201 +13352,9 @@ out: #undef for_each_intel_crtc_masked -static bool intel_connector_in_mode_set(struct intel_connector *connector, - struct drm_mode_set *set) -{ - int ro; - - for (ro = 0; ro < set->num_connectors; ro++) - if (set->connectors[ro] == &connector->base) - return true; - - return false; -} - -static int -intel_modeset_stage_output_state(struct drm_device *dev, - struct drm_mode_set *set, - struct drm_atomic_state *state) -{ - struct intel_connector *connector; - struct drm_connector *drm_connector; - struct drm_connector_state *connector_state; - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int i, ret; - - /* The upper layers ensure that we either disable a crtc or have a list - * of connectors. For paranoia, double-check this. */ - WARN_ON(!set->fb && (set->num_connectors != 0)); - WARN_ON(set->fb && (set->num_connectors == 0)); - - for_each_intel_connector(dev, connector) { - bool in_mode_set = intel_connector_in_mode_set(connector, set); - - if (!in_mode_set && connector->base.state->crtc != set->crtc) - continue; - - connector_state = - drm_atomic_get_connector_state(state, &connector->base); - if (IS_ERR(connector_state)) - return PTR_ERR(connector_state); - - if (in_mode_set) { - int pipe = to_intel_crtc(set->crtc)->pipe; - connector_state->best_encoder = - &intel_find_encoder(connector, pipe)->base; - } - - if (connector->base.state->crtc != set->crtc) - continue; - - /* If we disable the crtc, disable all its connectors. Also, if - * the connector is on the changing crtc but not on the new - * connector list, disable it. */ - if (!set->fb || !in_mode_set) { - connector_state->best_encoder = NULL; - - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", - connector->base.base.id, - connector->base.name); - } - } - /* connector->new_encoder is now updated for all connectors. */ - - for_each_connector_in_state(state, drm_connector, connector_state, i) { - connector = to_intel_connector(drm_connector); - - if (!connector_state->best_encoder) { - ret = drm_atomic_set_crtc_for_connector(connector_state, - NULL); - if (ret) - return ret; - - continue; - } - - if (intel_connector_in_mode_set(connector, set)) { - struct drm_crtc *crtc = connector->base.state->crtc; - - /* If this connector was in a previous crtc, add it - * to the state. We might need to disable it. */ - if (crtc) { - crtc_state = - drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - } - - ret = drm_atomic_set_crtc_for_connector(connector_state, - set->crtc); - if (ret) - return ret; - } - - /* Make sure the new CRTC will work with the encoder */ - if (!drm_encoder_crtc_ok(connector_state->best_encoder, - connector_state->crtc)) { - return -EINVAL; - } - - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", - connector->base.base.id, - connector->base.name, - connector_state->crtc->base.id); - - if (connector_state->best_encoder != &connector->encoder->base) - connector->encoder = - to_intel_encoder(connector_state->best_encoder); - } - - for_each_crtc_in_state(state, crtc, crtc_state, i) { - bool has_connectors; - - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - return ret; - - has_connectors = !!drm_atomic_connectors_for_crtc(state, crtc); - if (has_connectors != crtc_state->enable) - crtc_state->enable = - crtc_state->active = has_connectors; - } - - ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode, - set->fb, set->x, set->y); - if (ret) - return ret; - - crtc_state = drm_atomic_get_crtc_state(state, set->crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); - if (ret) - return ret; - - if (set->num_connectors) - crtc_state->active = true; - - return 0; -} - -static int intel_crtc_set_config(struct drm_mode_set *set) -{ - struct drm_device *dev; - struct drm_atomic_state *state = NULL; - int ret; - - BUG_ON(!set); - BUG_ON(!set->crtc); - BUG_ON(!set->crtc->helper_private); - - /* Enforce sane interface api - has been abused by the fb helper. */ - BUG_ON(!set->mode && set->fb); - BUG_ON(set->fb && set->num_connectors == 0); - - if (set->fb) { - DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", - set->crtc->base.id, set->fb->base.id, - (int)set->num_connectors, set->x, set->y); - } else { - DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); - } - - dev = set->crtc->dev; - - state = drm_atomic_state_alloc(dev); - if (!state) - return -ENOMEM; - - state->acquire_ctx = dev->mode_config.acquire_ctx; - - ret = intel_modeset_stage_output_state(dev, set, state); - if (ret) - goto out; - - ret = intel_modeset_compute_config(state); - if (ret) - goto out; - - intel_update_pipe_size(to_intel_crtc(set->crtc)); - - ret = intel_set_mode_checked(state); - if (ret) { - DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n", - set->crtc->base.id, ret); - } - -out: - if (ret) - drm_atomic_state_free(state); - return ret; -} - static const struct drm_crtc_funcs intel_crtc_funcs = { .gamma_set = intel_crtc_gamma_set, - .set_config = intel_crtc_set_config, + .set_config = drm_atomic_helper_set_config, .destroy = intel_crtc_destroy, .page_flip = intel_crtc_page_flip, .atomic_duplicate_state = intel_crtc_duplicate_state, @@ -15654,7 +15459,7 @@ void intel_display_resume(struct drm_device *dev) intel_modeset_setup_hw_state(dev); i915_redisable_vga(dev); - ret = intel_set_mode(state); + ret = drm_atomic_commit(state); if (!ret) return; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f4abce103221..cc91ea370c99 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1393,11 +1393,6 @@ void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count); void intel_tv_init(struct drm_device *dev); /* intel_atomic.c */ -int intel_atomic_check(struct drm_device *dev, - struct drm_atomic_state *state); -int intel_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool async); int intel_connector_atomic_get_property(struct drm_connector *connector, const struct drm_connector_state *state, struct drm_property *property, -- cgit v1.3-6-gb490 From f6ac4b2a121fd3362407b21e36ec71d9886ce379 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:31 +0200 Subject: drm/i915: Call plane update functions directly from intel_atomic_commit. Now that there's only a single path for all atomic updates we can call intel_(pre/post)_plane_update from intel_atomic_commit directly. This makes the intention more clear. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 83d7753b8b07..67c9c4f2a8bc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13292,12 +13292,19 @@ static int intel_atomic_commit(struct drm_device *dev, /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (needs_modeset(crtc->state) && crtc->state->active) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + bool modeset = needs_modeset(crtc->state); + + if (modeset && crtc->state->active) { update_scanline_offset(to_intel_crtc(crtc)); dev_priv->display.crtc_enable(crtc); } + if (!modeset) + intel_pre_plane_update(intel_crtc); + drm_atomic_helper_commit_planes_on_crtc(crtc_state); + intel_post_plane_update(intel_crtc); } /* FIXME: add subpixel order */ @@ -13635,9 +13642,6 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (!needs_modeset(crtc->state)) - intel_pre_plane_update(intel_crtc); - if (intel_crtc->atomic.update_wm_pre) intel_update_watermarks(crtc); @@ -13664,8 +13668,6 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc) intel_crtc->atomic.start_vbl_count); intel_runtime_pm_put(dev_priv); - - intel_post_plane_update(intel_crtc); } /** -- cgit v1.3-6-gb490 From 342defd8646dff96f87cf44c4eee4dfdf0dd8d00 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:33 +0200 Subject: drm/i915: Remove use of runtime pm in atomic commit functions We needed this originally for updating pagetables in plane commit functions. But that's extracted into prepare/cleanup now. The other issue was running updates when the pipe was off. That's also now fixed. Suggested-by: Daniel Vetter Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 67c9c4f2a8bc..755389f18dfe 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13639,14 +13639,11 @@ intel_disable_primary_plane(struct drm_plane *plane, static void intel_begin_crtc_commit(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); if (intel_crtc->atomic.update_wm_pre) intel_update_watermarks(crtc); - intel_runtime_pm_get(dev_priv); - /* Perform vblank evasion around commit operation */ if (crtc->state->active) intel_crtc->atomic.evade = @@ -13659,15 +13656,11 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) static void intel_finish_crtc_commit(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); if (intel_crtc->atomic.evade) intel_pipe_update_end(intel_crtc, intel_crtc->atomic.start_vbl_count); - - intel_runtime_pm_put(dev_priv); } /** -- cgit v1.3-6-gb490 From 8f539a83efa7dceb7c2257ca96e2dfc846bd12f6 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:32 +0200 Subject: drm/i915: always disable irqs in intel_pipe_update_start This can only fail because of a bug in the code. Suggested-by: Daniel Vetter Signed-off-by: Maarten Lankhorst [danvet: Squash in follow-up to also remove start_vbl_count from intel_crtc->atomic and put it into the intel_crtc directly - it's not precomputed state.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 15 +++++---------- drivers/gpu/drm/i915/intel_drv.h | 7 ++----- drivers/gpu/drm/i915/intel_sprite.c | 17 +++++++---------- 3 files changed, 14 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 755389f18dfe..bd92e9ce4127 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11247,12 +11247,11 @@ static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc) static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) { struct drm_device *dev = intel_crtc->base.dev; - bool atomic_update; u32 start_vbl_count; intel_mark_page_flip_active(intel_crtc); - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); + intel_pipe_update_start(intel_crtc, &start_vbl_count); if (INTEL_INFO(dev)->gen >= 9) skl_do_mmio_flip(intel_crtc); @@ -11260,8 +11259,7 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) /* use_mmio_flip() retricts MMIO flips to ilk+ */ ilk_do_mmio_flip(intel_crtc); - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); + intel_pipe_update_end(intel_crtc, start_vbl_count); } static void intel_mmio_flip_work_func(struct work_struct *work) @@ -13646,9 +13644,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) /* Perform vblank evasion around commit operation */ if (crtc->state->active) - intel_crtc->atomic.evade = - intel_pipe_update_start(intel_crtc, - &intel_crtc->atomic.start_vbl_count); + intel_pipe_update_start(intel_crtc, &intel_crtc->start_vbl_count); if (!needs_modeset(crtc->state) && INTEL_INFO(dev)->gen >= 9) skl_detach_scalers(intel_crtc); @@ -13658,9 +13654,8 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (intel_crtc->atomic.evade) - intel_pipe_update_end(intel_crtc, - intel_crtc->atomic.start_vbl_count); + if (crtc->state->active) + intel_pipe_update_end(intel_crtc, intel_crtc->start_vbl_count); } /** diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cc91ea370c99..0fcfa7f179c4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -488,10 +488,6 @@ struct skl_pipe_wm { * and thus can't be run with interrupts disabled. */ struct intel_crtc_atomic_commit { - /* vblank evasion */ - bool evade; - unsigned start_vbl_count; - /* Sleepable operations to perform before commit */ bool wait_for_flips; bool disable_fbc; @@ -559,6 +555,7 @@ struct intel_crtc { int scanline_offset; + unsigned start_vbl_count; struct intel_crtc_atomic_commit atomic; /* scalers available on this crtc */ @@ -1385,7 +1382,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane); int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); -bool intel_pipe_update_start(struct intel_crtc *crtc, +void intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count); void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index cd21525df352..9d8af2f8a875 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -75,10 +75,8 @@ static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs) * until a subsequent call to intel_pipe_update_end(). That is done to * avoid random delays. The value written to @start_vbl_count should be * supplied to intel_pipe_update_end() for error checking. - * - * Return: true if the call was successful */ -bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) +void intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) { struct drm_device *dev = crtc->base.dev; const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode; @@ -96,13 +94,14 @@ bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) min = vblank_start - usecs_to_scanlines(mode, 100); max = vblank_start - 1; + local_irq_disable(); + *start_vbl_count = 0; + if (min <= 0 || max <= 0) - return false; + return; if (WARN_ON(drm_crtc_vblank_get(&crtc->base))) - return false; - - local_irq_disable(); + return; trace_i915_pipe_update_start(crtc, min, max); @@ -138,8 +137,6 @@ bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) *start_vbl_count = dev->driver->get_vblank_counter(dev, pipe); trace_i915_pipe_update_vblank_evaded(crtc, min, max, *start_vbl_count); - - return true; } /** @@ -161,7 +158,7 @@ void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count) local_irq_enable(); - if (start_vbl_count != end_vbl_count) + if (start_vbl_count && start_vbl_count != end_vbl_count) DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u)\n", pipe_name(pipe), start_vbl_count, end_vbl_count); } -- cgit v1.3-6-gb490 From e2ff2d4a467511ef88ae574555ddc0e952777f0c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 15 Jul 2015 14:15:50 +0200 Subject: drm/i915: Unconditionally check gmch pfit state Now that we recompute the pipe config for all CRTCs that have changed we don't have problems with stale configuration data for the global pfit and can remove this hack. Yay! Cc: Maarten Lankhorst Signed-off-by: Daniel Vetter Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ede652867596..c29e7ed5fbb7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12607,21 +12607,11 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(pipe_src_w); PIPE_CONF_CHECK_I(pipe_src_h); - /* - * FIXME: BIOS likes to set up a cloned config with lvds+external - * screen. Since we don't yet re-compute the pipe config when moving - * just the lvds port away to another pipe the sw tracking won't match. - * - * Proper atomic modesets with recomputed global state will fix this. - * Until then just don't check gmch state for inherited modes. - */ - if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_INHERITED_MODE)) { - PIPE_CONF_CHECK_I(gmch_pfit.control); - /* pfit ratios are autocomputed by the hw on gen4+ */ - if (INTEL_INFO(dev)->gen < 4) - PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); - PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits); - } + PIPE_CONF_CHECK_I(gmch_pfit.control); + /* pfit ratios are autocomputed by the hw on gen4+ */ + if (INTEL_INFO(dev)->gen < 4) + PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); + PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits); PIPE_CONF_CHECK_I(pch_pfit.enabled); if (current_config->pch_pfit.enabled) { -- cgit v1.3-6-gb490 From 1ed51de9ca9170d1c5361924a17e7c483050aeb6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 15 Jul 2015 14:15:51 +0200 Subject: drm/i915: Clarify logic for initial modeset Currently we both set mode->private_flags to some value and also use the pipe_config quirk. But since the pipe_config quirk isn't tied to the lifetime of the mode object we need to check both. Simplify this by only using mode.private_flags and stop using the INHERITED_MODE quirk. Also for clarity add an explicit #define for that driver priavete mode flag. By using crtc_state->mode_changed we can also remove the recalc local variable. Cc: Maarten Lankhorst Signed-off-by: Daniel Vetter Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 34 ++++++++++++---------------------- drivers/gpu/drm/i915/intel_drv.h | 4 +++- 2 files changed, 15 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c29e7ed5fbb7..ce71552d4498 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13161,7 +13161,11 @@ static int intel_atomic_check(struct drm_device *dev, for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); - bool modeset, recalc = false; + bool modeset; + + /* Catch I915_MODE_FLAG_INHERITED */ + if (crtc_state->mode.private_flags != crtc->state->mode.private_flags) + crtc_state->mode_changed = true; if (!crtc_state->enable) { if (needs_modeset(crtc_state)) @@ -13170,28 +13174,22 @@ static int intel_atomic_check(struct drm_device *dev, } modeset = needs_modeset(crtc_state); - /* see comment in intel_modeset_readout_hw_state */ - if (!modeset && crtc_state->mode_blob != crtc->state->mode_blob && - pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE) - recalc = true; - if (!modeset && !recalc) + if (!modeset) continue; - if (recalc) { - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - return ret; - } + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + return ret; ret = intel_modeset_pipe_config(crtc, pipe_config); if (ret) return ret; - if (recalc && (!i915.fastboot || + if (!i915.fastboot || !intel_pipe_config_compare(state->dev, to_intel_crtc_state(crtc->state), - pipe_config, true))) { + pipe_config, true)) { modeset = crtc_state->mode_changed = true; ret = drm_atomic_add_affected_planes(state, crtc); @@ -15238,8 +15236,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) memset(crtc->config, 0, sizeof(*crtc->config)); crtc->config->base.crtc = &crtc->base; - crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; - crtc->active = dev_priv->display.get_pipe_config(crtc, crtc->config); @@ -15265,17 +15261,11 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) * right now it would cause a double modeset if * fbdev or userspace chooses a different initial mode. * - * So to prevent the double modeset, fail the memcmp - * test in drm_atomic_set_mode_for_crtc to get a new - * mode blob, and compare if the mode blob changed - * when the PIPE_CONFIG_QUIRK_INHERITED_MODE quirk is - * set. - * * If that happens, someone indicated they wanted a * mode change, which means it's safe to do a full * recalculation. */ - crtc->base.state->mode.private_flags = ~0; + crtc->base.state->mode.private_flags = I915_MODE_FLAG_INHERITED; } crtc->base.hwmode = crtc->config->base.adjusted_mode; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0fcfa7f179c4..3b00d00c0bc0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -317,6 +317,9 @@ struct intel_crtc_scaler_state { int scaler_id; }; +/* drm_mode->private_flags */ +#define I915_MODE_FLAG_INHERITED 1 + struct intel_crtc_state { struct drm_crtc_state base; @@ -329,7 +332,6 @@ struct intel_crtc_state { * accordingly. */ #define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ -#define PIPE_CONFIG_QUIRK_INHERITED_MODE (1<<1) /* mode inherited from firmware */ unsigned long quirks; /* Pipe source size (ie. panel fitter input size) -- cgit v1.3-6-gb490 From 264954811af62dcfe17fc44cef379b315bb066eb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 15 Jul 2015 14:15:52 +0200 Subject: drm/i915: Invert fastboot check Fastboot should only downgrade a modeset if we have a match, not be used to upgrade to a full modeset. Otherwise we can only use it in a very restricted way: Initial modeset when the request mode is the preferred one of the panel and there's still a pfit active. And that only works because our mode_from_pipe_config fills in the wrong mode (it takes the adjusted mode, not the requested one). But we want fast modesets everywhere even after boot-up (especially for testing, but not only there). Hence we need to be able to make any modeset a fast one, which means we need to invert the logic and optionally downgrade a modeset. Note that this needs ->connector_changed split out from ->mode_changed otherwise it's not going to work (because we might loose a modeset because connectors changed but otherwise the config matches). As soon as that's merged we can drop the i915.fastboot check from this code. Also make sure that we don't accidentally clear any_ms and that we add the planes for any kind of modeset. Finally rename fastboot to fastset (yeah it's a silly name) since this really isn't about booting all that much. Cc: Maarten Lankhorst Signed-off-by: Daniel Vetter Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ce71552d4498..af0bcfee4771 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13161,7 +13161,6 @@ static int intel_atomic_check(struct drm_device *dev, for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); - bool modeset; /* Catch I915_MODE_FLAG_INHERITED */ if (crtc_state->mode.private_flags != crtc->state->mode.private_flags) @@ -13173,11 +13172,12 @@ static int intel_atomic_check(struct drm_device *dev, continue; } - modeset = needs_modeset(crtc_state); - - if (!modeset) + if (!needs_modeset(crtc_state)) continue; + /* FIXME: For only active_changed we shouldn't need to do any + * state recomputation at all. */ + ret = drm_atomic_add_affected_connectors(state, crtc); if (ret) return ret; @@ -13186,21 +13186,24 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) return ret; - if (!i915.fastboot || - !intel_pipe_config_compare(state->dev, + if (i915.fastboot && + intel_pipe_config_compare(state->dev, to_intel_crtc_state(crtc->state), pipe_config, true)) { - modeset = crtc_state->mode_changed = true; + crtc_state->mode_changed = false; + } + + if (needs_modeset(crtc_state)) { + any_ms = true; ret = drm_atomic_add_affected_planes(state, crtc); if (ret) return ret; } - any_ms = modeset; - intel_dump_pipe_config(to_intel_crtc(crtc), - pipe_config, - modeset ? "[modeset]" : "[fastboot]"); + intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config, + needs_modeset(crtc_state) ? + "[modeset]" : "[fastset]"); } if (any_ms) { -- cgit v1.3-6-gb490 From 113e0d118a93c964feea376de8c94dd8c7c63ff8 Mon Sep 17 00:00:00 2001 From: Srinidhi Kasagar Date: Wed, 15 Jul 2015 14:59:46 +0530 Subject: PCI / ACPI: Fix pci_acpi_optimize_delay() comment The function takes ACPI handle, not the device itself. Fix the comment Signed-off-by: Srinidhi Kasagar Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 314a625b78d6..a32ba753e413 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -594,7 +594,7 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev) /** * pci_acpi_optimize_delay - optimize PCI D3 and D3cold delay from ACPI * @pdev: the PCI device whose delay is to be updated - * @adev: the companion ACPI device of this PCI device + * @handle: ACPI handle of this device * * Update the d3_delay and d3cold_delay of a PCI device from the ACPI _DSM * control method of either the device itself or the PCI host bridge. -- cgit v1.3-6-gb490 From db3b0fcc5adbda0c7060c9298c2514778547fee2 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Jun 2015 18:20:35 +0200 Subject: gpio: generic: add get_direction support Allow to determine the current direction configuration by reading back from the direction register. Signed-off-by: Philipp Zabel Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 9bda3727fac1..802e6d2c64e9 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -302,6 +302,14 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) return 0; } +static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ? + GPIOF_DIR_OUT : GPIOF_DIR_IN; +} + static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct bgpio_chip *bgc = to_bgpio_chip(gc); @@ -351,6 +359,14 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } +static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ? + GPIOF_DIR_IN : GPIOF_DIR_OUT; +} + static int bgpio_setup_accessors(struct device *dev, struct bgpio_chip *bgc, bool bit_be, @@ -468,10 +484,12 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc, bgc->reg_dir = dirout; bgc->gc.direction_output = bgpio_dir_out; bgc->gc.direction_input = bgpio_dir_in; + bgc->gc.get_direction = bgpio_get_dir; } else if (dirin) { bgc->reg_dir = dirin; bgc->gc.direction_output = bgpio_dir_out_inv; bgc->gc.direction_input = bgpio_dir_in_inv; + bgc->gc.get_direction = bgpio_get_dir_inv; } else { bgc->gc.direction_output = bgpio_simple_dir_out; bgc->gc.direction_input = bgpio_simple_dir_in; -- cgit v1.3-6-gb490 From d32651f68785bd8d73b24481b62e428ca30a2546 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Wed, 17 Jun 2015 15:42:11 +0200 Subject: gpiolib: Fix docs for gpiochip_add_pingroup_range gpiochip_add_pingroup_range() has a pctldev argument, not pinctrl. Signed-off-by: Tomeu Vizoso Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bf4bd1d120c3..b1b08b3fa626 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -671,7 +671,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} /** * gpiochip_add_pingroup_range() - add a range for GPIO <-> pin mapping * @chip: the gpiochip to add the range for - * @pinctrl: the dev_name() of the pin controller to map to + * @pctldev: the pin controller to map to * @gpio_offset: the start offset in the current gpio_chip number space * @pin_group: name of the pin group inside the pin controller */ -- cgit v1.3-6-gb490 From 80d2bf55a1257a277a808128f377ac69216b6587 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 17 Jun 2015 17:51:41 +0900 Subject: gpio: zynq: add missing module_exit function This driver is tristate, so it should be cleanable. Signed-off-by: Masahiro Yamada Tested-by: Michal Simek Signed-off-by: Linus Walleij --- drivers/gpio/gpio-zynq.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 2e87c4b8da26..399c4be9e63c 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -781,6 +781,12 @@ static int __init zynq_gpio_init(void) } postcore_initcall(zynq_gpio_init); +static void __exit zynq_gpio_exit(void) +{ + platform_driver_unregister(&zynq_gpio_driver); +} +module_exit(zynq_gpio_exit); + MODULE_AUTHOR("Xilinx Inc."); MODULE_DESCRIPTION("Zynq GPIO driver"); MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From d58ec58f40dc188fbb08edaa8c17840f71fe8a0e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 19 Jun 2015 20:31:02 +0900 Subject: gpio: altera: kill bogus dependency on GPIO_GENERIC The driver gpio-altera.c does not depend on gpio-generic.c at all. Drop unneeded "select GPIO_GENERIC". Signed-off-by: Masahiro Yamada Acked-by: Tien Hock Loh Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8f1fe739c985..29c2340bffe9 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -113,7 +113,6 @@ config GPIO_74XX_MMIO config GPIO_ALTERA tristate "Altera GPIO" depends on OF_GPIO - select GPIO_GENERIC select GPIOLIB_IRQCHIP help Say Y or M here to build support for the Altera PIO device. -- cgit v1.3-6-gb490 From 1c8b5d688d7ef401c209f3fc84b7de8296f8908a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 17 Jun 2015 20:59:43 +0900 Subject: gpio: altera: fix return value of altera_gpio_remove() The remove callback never succeeds, which seems odd. Signed-off-by: Masahiro Yamada Reviewed-by: Alexandre Courbot Acked-by: Tien Hock Loh Signed-off-by: Linus Walleij --- drivers/gpio/gpio-altera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 0f3d336d6303..675d15d6e9be 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -340,7 +340,7 @@ static int altera_gpio_remove(struct platform_device *pdev) gpiochip_remove(&altera_gc->mmchip.gc); - return -EIO; + return 0; } static const struct of_device_id altera_gpio_of_match[] = { -- cgit v1.3-6-gb490 From 41ec66c92299889ad30871aeede89b960f08a458 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 17 Jun 2015 20:59:42 +0900 Subject: gpio: altera: use of_mm_gpiochip_remove() to fix memory leak This driver calls of_mm_gpiochip_add() to add a memory mapped gpio chip. So, of_mm_gpiochip_remove() should be used when removing it. The direct call of gpiochip_remove() misses unmapping the register and freeing the label. Signed-off-by: Masahiro Yamada Reviewed-by: Alexandre Courbot Acked-by: Tien Hock Loh Signed-off-by: Linus Walleij --- drivers/gpio/gpio-altera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 675d15d6e9be..9b7e0b3db387 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -338,7 +338,7 @@ static int altera_gpio_remove(struct platform_device *pdev) { struct altera_gpio_chip *altera_gc = platform_get_drvdata(pdev); - gpiochip_remove(&altera_gc->mmchip.gc); + of_mm_gpiochip_remove(&altera_gc->mmchip); return 0; } -- cgit v1.3-6-gb490 From 4c52bd5c61118a47166ed5857f17698ce520b5fd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 19 Jun 2015 20:31:03 +0900 Subject: gpio: mvebu: kill bogus dependency on GPIO_GENERIC The driver gpio-mvebu.c does not depend on gpio-generic.c at all. Drop unneeded "select GPIO_GENERIC". Signed-off-by: Masahiro Yamada Acked-by: Gregory CLEMENT Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 29c2340bffe9..4c9fa58c5643 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -307,7 +307,6 @@ config GPIO_MVEBU def_bool y depends on PLAT_ORION depends on OF - select GPIO_GENERIC select GENERIC_IRQ_CHIP config GPIO_MXC -- cgit v1.3-6-gb490 From 39561e8bbb49752092b6afd9764d3f3aeef4e1d2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 10:01:44 +0900 Subject: gpio: of: remove unnecessary variable in of_get_gpio_hog() The variable "desc" is only used for storing the return value at the end of the function. It is unneeded. Signed-off-by: Masahiro Yamada Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 9a0ec48a4737..fd2db4b3a709 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -136,7 +136,6 @@ static struct gpio_desc *of_get_gpio_hog(struct device_node *np, { struct device_node *chip_np; enum of_gpio_flags xlate_flags; - struct gpio_desc *desc; struct gg_data gg_data = { .flags = &xlate_flags, }; @@ -193,9 +192,7 @@ static struct gpio_desc *of_get_gpio_hog(struct device_node *np, if (name && of_property_read_string(np, "line-name", name)) *name = np->name; - desc = gg_data.out_gpio; - - return desc; + return gg_data.out_gpio; } /** -- cgit v1.3-6-gb490 From aa57aca8e15a4e11749640e16ac9814f14be24d2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 16 Jul 2015 02:01:28 +0200 Subject: ACPI / PM: Update the copyright notice and description of power.c The description and copyright notice of drivers/acpi/power.c is out of date, so update it as appropriate. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/power.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 93eac53b5110..ce68ae68840d 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -1,8 +1,10 @@ /* - * acpi_power.c - ACPI Bus Power Management ($Revision: 39 $) + * drivers/acpi/power.c - ACPI Power Resources management. * - * Copyright (C) 2001, 2002 Andy Grover - * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2001 - 2015 Intel Corp. + * Author: Andy Grover + * Author: Paul Diefenbaugh + * Author: Rafael J. Wysocki * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -27,10 +29,11 @@ * ACPI power-managed devices may be controlled in two ways: * 1. via "Device Specific (D-State) Control" * 2. via "Power Resource Control". - * This module is used to manage devices relying on Power Resource Control. + * The code below deals with ACPI Power Resources control. * - * An ACPI "power resource object" describes a software controllable power - * plane, clock plane, or other resource used by a power managed device. + * An ACPI "power resource object" represents a software controllable power + * plane, clock plane, or other resource depended on by a device. + * * A device may rely on multiple power resources, and a power resource * may be shared by multiple devices. */ -- cgit v1.3-6-gb490 From 76f31e8b0911e620ac9191c8d3775cc91ed65c4c Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 13 Jul 2015 16:22:03 +0300 Subject: gianfar: Bundle Rx allocation, cleanup Use a more common consumer/ producer index design to improve rx buffer allocation. Instead of allocating a single new buffer (skb) on each iteration, bundle the allocation of several rx buffers at a time. This also opens the path for further memory optimizations. Remove useless check of rxq->rfbptr, since this patch touches rx pause frame handling code as well. rxq->rfbptr is always initialized as part of Rx BD ring init. Remove redundant (and misleading) 'amount_pull' parameter. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 201 ++++++++++++----------- drivers/net/ethernet/freescale/gianfar.h | 39 +++-- drivers/net/ethernet/freescale/gianfar_ethtool.c | 3 + 3 files changed, 136 insertions(+), 107 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index ff875028fdff..b35bf3de44e0 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -116,8 +116,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); static void gfar_reset_task(struct work_struct *work); static void gfar_timeout(struct net_device *dev); static int gfar_close(struct net_device *dev); -static struct sk_buff *gfar_new_skb(struct net_device *dev, - dma_addr_t *bufaddr); +static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, + int alloc_cnt); static int gfar_set_mac_address(struct net_device *dev); static int gfar_change_mtu(struct net_device *dev, int new_mtu); static irqreturn_t gfar_error(int irq, void *dev_id); @@ -142,7 +142,7 @@ static void gfar_netpoll(struct net_device *dev); int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit); static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - int amount_pull, struct napi_struct *napi); + struct napi_struct *napi); static void gfar_halt_nodisable(struct gfar_private *priv); static void gfar_clear_exact_match(struct net_device *dev); static void gfar_set_mac_for_addr(struct net_device *dev, int num, @@ -169,17 +169,15 @@ static void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp, bdp->lstatus = cpu_to_be32(lstatus); } -static int gfar_init_bds(struct net_device *ndev) +static void gfar_init_bds(struct net_device *ndev) { struct gfar_private *priv = netdev_priv(ndev); struct gfar __iomem *regs = priv->gfargrp[0].regs; struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; struct txbd8 *txbdp; - struct rxbd8 *rxbdp; u32 __iomem *rfbptr; int i, j; - dma_addr_t bufaddr; for (i = 0; i < priv->num_tx_queues; i++) { tx_queue = priv->tx_queue[i]; @@ -207,33 +205,18 @@ static int gfar_init_bds(struct net_device *ndev) rfbptr = ®s->rfbptr0; for (i = 0; i < priv->num_rx_queues; i++) { rx_queue = priv->rx_queue[i]; - rx_queue->cur_rx = rx_queue->rx_bd_base; - rx_queue->skb_currx = 0; - rxbdp = rx_queue->rx_bd_base; - - for (j = 0; j < rx_queue->rx_ring_size; j++) { - struct sk_buff *skb = rx_queue->rx_skbuff[j]; - if (skb) { - bufaddr = be32_to_cpu(rxbdp->bufPtr); - } else { - skb = gfar_new_skb(ndev, &bufaddr); - if (!skb) { - netdev_err(ndev, "Can't allocate RX buffers\n"); - return -ENOMEM; - } - rx_queue->rx_skbuff[j] = skb; - } + rx_queue->next_to_clean = 0; + rx_queue->next_to_use = 0; - gfar_init_rxbdp(rx_queue, rxbdp, bufaddr); - rxbdp++; - } + /* make sure next_to_clean != next_to_use after this + * by leaving at least 1 unused descriptor + */ + gfar_alloc_rx_buffs(rx_queue, gfar_rxbd_unused(rx_queue)); rx_queue->rfbptr = rfbptr; rfbptr += 2; } - - return 0; } static int gfar_alloc_skb_resources(struct net_device *ndev) @@ -311,8 +294,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) rx_queue->rx_skbuff[j] = NULL; } - if (gfar_init_bds(ndev)) - goto cleanup; + gfar_init_bds(ndev); return 0; @@ -1639,10 +1621,7 @@ static int gfar_restore(struct device *dev) return 0; } - if (gfar_init_bds(ndev)) { - free_skb_resources(priv); - return -ENOMEM; - } + gfar_init_bds(ndev); gfar_mac_reset(priv); @@ -2704,30 +2683,19 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) netdev_tx_completed_queue(txq, howmany, bytes_sent); } -static struct sk_buff *gfar_alloc_skb(struct net_device *dev) +static struct sk_buff *gfar_new_skb(struct net_device *ndev, + dma_addr_t *bufaddr) { - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(ndev); struct sk_buff *skb; + dma_addr_t addr; - skb = netdev_alloc_skb(dev, priv->rx_buffer_size + RXBUF_ALIGNMENT); + skb = netdev_alloc_skb(ndev, priv->rx_buffer_size + RXBUF_ALIGNMENT); if (!skb) return NULL; gfar_align_skb(skb); - return skb; -} - -static struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr) -{ - struct gfar_private *priv = netdev_priv(dev); - struct sk_buff *skb; - dma_addr_t addr; - - skb = gfar_alloc_skb(dev); - if (!skb) - return NULL; - addr = dma_map_single(priv->dev, skb->data, priv->rx_buffer_size, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(priv->dev, addr))) { @@ -2739,6 +2707,55 @@ static struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr) return skb; } +static void gfar_rx_alloc_err(struct gfar_priv_rx_q *rx_queue) +{ + struct gfar_private *priv = netdev_priv(rx_queue->dev); + struct gfar_extra_stats *estats = &priv->extra_stats; + + netdev_err(rx_queue->dev, "Can't alloc RX buffers\n"); + atomic64_inc(&estats->rx_alloc_err); +} + +static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, + int alloc_cnt) +{ + struct net_device *ndev = rx_queue->dev; + struct rxbd8 *bdp, *base; + dma_addr_t bufaddr; + int i; + + i = rx_queue->next_to_use; + base = rx_queue->rx_bd_base; + bdp = &rx_queue->rx_bd_base[i]; + + while (alloc_cnt--) { + struct sk_buff *skb = rx_queue->rx_skbuff[i]; + + if (likely(!skb)) { + skb = gfar_new_skb(ndev, &bufaddr); + if (unlikely(!skb)) { + gfar_rx_alloc_err(rx_queue); + break; + } + } else { /* restore from sleep state */ + bufaddr = be32_to_cpu(bdp->bufPtr); + } + + rx_queue->rx_skbuff[i] = skb; + + /* Setup the new RxBD */ + gfar_init_rxbdp(rx_queue, bdp, bufaddr); + + /* Update to the next pointer */ + bdp = next_bd(bdp, base, rx_queue->rx_ring_size); + + if (unlikely(++i == rx_queue->rx_ring_size)) + i = 0; + } + + rx_queue->next_to_use = i; +} + static inline void count_errors(unsigned short status, struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); @@ -2838,7 +2855,7 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb) /* gfar_process_frame() -- handle one incoming packet if skb isn't NULL. */ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - int amount_pull, struct napi_struct *napi) + struct napi_struct *napi) { struct gfar_private *priv = netdev_priv(dev); struct rxfcb *fcb = NULL; @@ -2849,9 +2866,9 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, /* Remove the FCB from the skb * Remove the padded bytes, if there are any */ - if (amount_pull) { + if (priv->uses_rxfcb) { skb_record_rx_queue(skb, fcb->rq); - skb_pull(skb, amount_pull); + skb_pull(skb, GMAC_FCB_LEN); } /* Get receive timestamp from the skb */ @@ -2895,27 +2912,30 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) struct net_device *dev = rx_queue->dev; struct rxbd8 *bdp, *base; struct sk_buff *skb; - int pkt_len; - int amount_pull; - int howmany = 0; + int i, howmany = 0; + int cleaned_cnt = gfar_rxbd_unused(rx_queue); struct gfar_private *priv = netdev_priv(dev); /* Get the first full descriptor */ - bdp = rx_queue->cur_rx; base = rx_queue->rx_bd_base; + i = rx_queue->next_to_clean; - amount_pull = priv->uses_rxfcb ? GMAC_FCB_LEN : 0; + while (rx_work_limit--) { - while (!(be16_to_cpu(bdp->status) & RXBD_EMPTY) && rx_work_limit--) { - struct sk_buff *newskb; - dma_addr_t bufaddr; + if (cleaned_cnt >= GFAR_RX_BUFF_ALLOC) { + gfar_alloc_rx_buffs(rx_queue, cleaned_cnt); + cleaned_cnt = 0; + } - rmb(); + bdp = &rx_queue->rx_bd_base[i]; + if (be16_to_cpu(bdp->status) & RXBD_EMPTY) + break; - /* Add another skb for the future */ - newskb = gfar_new_skb(dev, &bufaddr); + /* order rx buffer descriptor reads */ + rmb(); - skb = rx_queue->rx_skbuff[rx_queue->skb_currx]; + /* fetch next to clean buffer from the ring */ + skb = rx_queue->rx_skbuff[i]; dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr), priv->rx_buffer_size, DMA_FROM_DEVICE); @@ -2924,30 +2944,26 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) be16_to_cpu(bdp->length) > priv->rx_buffer_size)) bdp->status = cpu_to_be16(RXBD_LARGE); - /* We drop the frame if we failed to allocate a new buffer */ - if (unlikely(!newskb || - !(be16_to_cpu(bdp->status) & RXBD_LAST) || + if (unlikely(!(be16_to_cpu(bdp->status) & RXBD_LAST) || be16_to_cpu(bdp->status) & RXBD_ERR)) { count_errors(be16_to_cpu(bdp->status), dev); - if (unlikely(!newskb)) { - newskb = skb; - bufaddr = be32_to_cpu(bdp->bufPtr); - } else if (skb) - dev_kfree_skb(skb); + /* discard faulty buffer */ + dev_kfree_skb(skb); + } else { /* Increment the number of packets */ rx_queue->stats.rx_packets++; howmany++; if (likely(skb)) { - pkt_len = be16_to_cpu(bdp->length) - + int pkt_len = be16_to_cpu(bdp->length) - ETH_FCS_LEN; /* Remove the FCS from the packet length */ skb_put(skb, pkt_len); rx_queue->stats.rx_bytes += pkt_len; skb_record_rx_queue(skb, rx_queue->qindex); - gfar_process_frame(dev, skb, amount_pull, + gfar_process_frame(dev, skb, &rx_queue->grp->napi_rx); } else { @@ -2958,26 +2974,23 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) } - rx_queue->rx_skbuff[rx_queue->skb_currx] = newskb; - - /* Setup the new bdp */ - gfar_init_rxbdp(rx_queue, bdp, bufaddr); + rx_queue->rx_skbuff[i] = NULL; + cleaned_cnt++; + if (unlikely(++i == rx_queue->rx_ring_size)) + i = 0; + } - /* Update Last Free RxBD pointer for LFC */ - if (unlikely(rx_queue->rfbptr && priv->tx_actual_en)) - gfar_write(rx_queue->rfbptr, (u32)bdp); + rx_queue->next_to_clean = i; - /* Update to the next pointer */ - bdp = next_bd(bdp, base, rx_queue->rx_ring_size); + if (cleaned_cnt) + gfar_alloc_rx_buffs(rx_queue, cleaned_cnt); - /* update to point at the next skb */ - rx_queue->skb_currx = (rx_queue->skb_currx + 1) & - RX_RING_MOD_MASK(rx_queue->rx_ring_size); + /* Update Last Free RxBD pointer for LFC */ + if (unlikely(priv->tx_actual_en)) { + bdp = gfar_rxbd_lastfree(rx_queue); + gfar_write(rx_queue->rfbptr, (u32)bdp); } - /* Update the current rxbd pointer to be the next one */ - rx_queue->cur_rx = bdp; - return howmany; } @@ -3552,14 +3565,8 @@ static noinline void gfar_update_link_state(struct gfar_private *priv) if ((tempval1 & MACCFG1_TX_FLOW) && !tx_flow_oldval) { for (i = 0; i < priv->num_rx_queues; i++) { rx_queue = priv->rx_queue[i]; - bdp = rx_queue->cur_rx; - /* skip to previous bd */ - bdp = skip_bd(bdp, rx_queue->rx_ring_size - 1, - rx_queue->rx_bd_base, - rx_queue->rx_ring_size); - - if (rx_queue->rfbptr) - gfar_write(rx_queue->rfbptr, (u32)bdp); + bdp = gfar_rxbd_lastfree(rx_queue); + gfar_write(rx_queue->rfbptr, (u32)bdp); } priv->tx_actual_en = 1; diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index daa1d37de642..cadb068cb37f 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -92,6 +92,8 @@ extern const char gfar_driver_version[]; #define DEFAULT_TX_RING_SIZE 256 #define DEFAULT_RX_RING_SIZE 256 +#define GFAR_RX_BUFF_ALLOC 16 + #define GFAR_RX_MAX_RING_SIZE 256 #define GFAR_TX_MAX_RING_SIZE 256 @@ -640,6 +642,7 @@ struct rmon_mib }; struct gfar_extra_stats { + atomic64_t rx_alloc_err; atomic64_t rx_large; atomic64_t rx_short; atomic64_t rx_nonoctet; @@ -1015,9 +1018,9 @@ struct rx_q_stats { /** * struct gfar_priv_rx_q - per rx queue structure * @rx_skbuff: skb pointers - * @skb_currx: currently use skb pointer * @rx_bd_base: First rx buffer descriptor - * @cur_rx: Next free rx ring entry + * @next_to_use: index of the next buffer to be alloc'd + * @next_to_clean: index of the next buffer to be cleaned * @qindex: index of this queue * @dev: back pointer to the dev structure * @rx_ring_size: Rx ring size @@ -1027,19 +1030,18 @@ struct rx_q_stats { struct gfar_priv_rx_q { struct sk_buff **rx_skbuff __aligned(SMP_CACHE_BYTES); - dma_addr_t rx_bd_dma_base; struct rxbd8 *rx_bd_base; - struct rxbd8 *cur_rx; struct net_device *dev; - struct gfar_priv_grp *grp; + struct gfar_priv_grp *grp; + u16 rx_ring_size; + u16 qindex; + u16 next_to_clean; + u16 next_to_use; struct rx_q_stats stats; - u16 skb_currx; - u16 qindex; - unsigned int rx_ring_size; - /* RX Coalescing values */ + u32 __iomem *rfbptr; unsigned char rxcoalescing; unsigned long rxic; - u32 __iomem *rfbptr; + dma_addr_t rx_bd_dma_base; }; enum gfar_irqinfo_id { @@ -1295,6 +1297,23 @@ static inline void gfar_clear_txbd_status(struct txbd8 *bdp) bdp->lstatus = cpu_to_be32(lstatus); } +static inline int gfar_rxbd_unused(struct gfar_priv_rx_q *rxq) +{ + if (rxq->next_to_clean > rxq->next_to_use) + return rxq->next_to_clean - rxq->next_to_use - 1; + + return rxq->rx_ring_size + rxq->next_to_clean - rxq->next_to_use - 1; +} + +static inline struct rxbd8 *gfar_rxbd_lastfree(struct gfar_priv_rx_q *rxq) +{ + int i; + + i = rxq->next_to_use ? rxq->next_to_use - 1 : rxq->rx_ring_size - 1; + + return &rxq->rx_bd_base[i]; +} + irqreturn_t gfar_receive(int irq, void *dev_id); int startup_gfar(struct net_device *dev); void stop_gfar(struct net_device *dev); diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index fda12fb32ec7..012fa4e79ffa 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -61,6 +61,8 @@ static void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo); static const char stat_gstrings[][ETH_GSTRING_LEN] = { + /* extra stats */ + "rx-allocation-errors", "rx-large-frame-errors", "rx-short-frame-errors", "rx-non-octet-errors", @@ -74,6 +76,7 @@ static const char stat_gstrings[][ETH_GSTRING_LEN] = { "tx-underrun-errors", "rx-skb-missing-errors", "tx-timeout-errors", + /* rmon stats */ "tx-rx-64-frames", "tx-rx-65-127-frames", "tx-rx-128-255-frames", -- cgit v1.3-6-gb490 From f966082e2065d223942cc40e0bc4841f84f0604d Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 13 Jul 2015 16:22:04 +0300 Subject: gianfar: Fix and cleanup rxbd status handling There are several (long standing) problems about how the status field of the rx buffer descriptor (rxbd) is currently handled on the error path: - too many unnecessary 16bit reads of the two halves of the rxbd status field (32bit), also resulting in overuse of endianness convesion macros; - "bdp->status = RXBD_LARGE" makes no sense, since the "large" flag is read only (only eTSEC can write it), and trying to clear the other status bits is also error prone in this context (most of the rx status bits are read only anyway). This is fixed with a single 32bit read of the "status" field, and then the appropriate 16bit shifting is applied to access the various status bits or the rx frame length. Also corrected the use of the RXBD_LARGE flag. Additional fix: "rx_over_errors" stat is incremented instead of "rx_crc_errors" in case of RXBD_OVERRUN occurrence. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 34 +++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index b35bf3de44e0..c839e7628181 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2756,14 +2756,14 @@ static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, rx_queue->next_to_use = i; } -static inline void count_errors(unsigned short status, struct net_device *dev) +static void count_errors(u32 lstatus, struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; struct gfar_extra_stats *estats = &priv->extra_stats; /* If the packet was truncated, none of the other errors matter */ - if (status & RXBD_TRUNCATED) { + if (lstatus & BD_LFLAG(RXBD_TRUNCATED)) { stats->rx_length_errors++; atomic64_inc(&estats->rx_trunc); @@ -2771,25 +2771,25 @@ static inline void count_errors(unsigned short status, struct net_device *dev) return; } /* Count the errors, if there were any */ - if (status & (RXBD_LARGE | RXBD_SHORT)) { + if (lstatus & BD_LFLAG(RXBD_LARGE | RXBD_SHORT)) { stats->rx_length_errors++; - if (status & RXBD_LARGE) + if (lstatus & BD_LFLAG(RXBD_LARGE)) atomic64_inc(&estats->rx_large); else atomic64_inc(&estats->rx_short); } - if (status & RXBD_NONOCTET) { + if (lstatus & BD_LFLAG(RXBD_NONOCTET)) { stats->rx_frame_errors++; atomic64_inc(&estats->rx_nonoctet); } - if (status & RXBD_CRCERR) { + if (lstatus & BD_LFLAG(RXBD_CRCERR)) { atomic64_inc(&estats->rx_crcerr); stats->rx_crc_errors++; } - if (status & RXBD_OVERRUN) { + if (lstatus & BD_LFLAG(RXBD_OVERRUN)) { atomic64_inc(&estats->rx_overrun); - stats->rx_crc_errors++; + stats->rx_over_errors++; } } @@ -2921,6 +2921,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) i = rx_queue->next_to_clean; while (rx_work_limit--) { + u32 lstatus; if (cleaned_cnt >= GFAR_RX_BUFF_ALLOC) { gfar_alloc_rx_buffs(rx_queue, cleaned_cnt); @@ -2928,7 +2929,8 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) } bdp = &rx_queue->rx_bd_base[i]; - if (be16_to_cpu(bdp->status) & RXBD_EMPTY) + lstatus = be32_to_cpu(bdp->lstatus); + if (lstatus & BD_LFLAG(RXBD_EMPTY)) break; /* order rx buffer descriptor reads */ @@ -2940,13 +2942,13 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr), priv->rx_buffer_size, DMA_FROM_DEVICE); - if (unlikely(!(be16_to_cpu(bdp->status) & RXBD_ERR) && - be16_to_cpu(bdp->length) > priv->rx_buffer_size)) - bdp->status = cpu_to_be16(RXBD_LARGE); + if (unlikely(!(lstatus & BD_LFLAG(RXBD_ERR)) && + (lstatus & BD_LENGTH_MASK) > priv->rx_buffer_size)) + lstatus |= BD_LFLAG(RXBD_LARGE); - if (unlikely(!(be16_to_cpu(bdp->status) & RXBD_LAST) || - be16_to_cpu(bdp->status) & RXBD_ERR)) { - count_errors(be16_to_cpu(bdp->status), dev); + if (unlikely(!(lstatus & BD_LFLAG(RXBD_LAST)) || + (lstatus & BD_LFLAG(RXBD_ERR)))) { + count_errors(lstatus, dev); /* discard faulty buffer */ dev_kfree_skb(skb); @@ -2957,7 +2959,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) howmany++; if (likely(skb)) { - int pkt_len = be16_to_cpu(bdp->length) - + int pkt_len = (lstatus & BD_LENGTH_MASK) - ETH_FCS_LEN; /* Remove the FCS from the packet length */ skb_put(skb, pkt_len); -- cgit v1.3-6-gb490 From f23223f15fd7d359a08ea346a0a537ccaf417014 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 13 Jul 2015 16:22:05 +0300 Subject: gianfar: Use ndev, more Rx path cleanup Use "ndev" instead of "dev", as the rx queue back pointer to a net_device struct, to avoid name clashing with a "struct device" reference. This prepares the addition of a "struct device" back pointer to the rx queue structure. Remove duplicated rxq registration in the process. Move napi_gro_receive() outside gfar_process_frame(). Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 54 ++++++++++++++------------------ drivers/net/ethernet/freescale/gianfar.h | 4 +-- 2 files changed, 26 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index c839e7628181..7654d5eafeeb 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -141,8 +141,7 @@ static void gfar_netpoll(struct net_device *dev); #endif int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit); static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); -static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - struct napi_struct *napi); +static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb); static void gfar_halt_nodisable(struct gfar_private *priv); static void gfar_clear_exact_match(struct net_device *dev); static void gfar_set_mac_for_addr(struct net_device *dev, int num, @@ -262,7 +261,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) rx_queue = priv->rx_queue[i]; rx_queue->rx_bd_base = vaddr; rx_queue->rx_bd_dma_base = addr; - rx_queue->dev = ndev; + rx_queue->ndev = ndev; addr += sizeof(struct rxbd8) * rx_queue->rx_ring_size; vaddr += sizeof(struct rxbd8) * rx_queue->rx_ring_size; } @@ -593,7 +592,7 @@ static int gfar_alloc_rx_queues(struct gfar_private *priv) priv->rx_queue[i]->rx_skbuff = NULL; priv->rx_queue[i]->qindex = i; - priv->rx_queue[i]->dev = priv->ndev; + priv->rx_queue[i]->ndev = priv->ndev; } return 0; } @@ -1913,7 +1912,7 @@ static void free_skb_tx_queue(struct gfar_priv_tx_q *tx_queue) static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue) { struct rxbd8 *rxbdp; - struct gfar_private *priv = netdev_priv(rx_queue->dev); + struct gfar_private *priv = netdev_priv(rx_queue->ndev); int i; rxbdp = rx_queue->rx_bd_base; @@ -2709,17 +2708,17 @@ static struct sk_buff *gfar_new_skb(struct net_device *ndev, static void gfar_rx_alloc_err(struct gfar_priv_rx_q *rx_queue) { - struct gfar_private *priv = netdev_priv(rx_queue->dev); + struct gfar_private *priv = netdev_priv(rx_queue->ndev); struct gfar_extra_stats *estats = &priv->extra_stats; - netdev_err(rx_queue->dev, "Can't alloc RX buffers\n"); + netdev_err(rx_queue->ndev, "Can't alloc RX buffers\n"); atomic64_inc(&estats->rx_alloc_err); } static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, int alloc_cnt) { - struct net_device *ndev = rx_queue->dev; + struct net_device *ndev = rx_queue->ndev; struct rxbd8 *bdp, *base; dma_addr_t bufaddr; int i; @@ -2756,10 +2755,10 @@ static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, rx_queue->next_to_use = i; } -static void count_errors(u32 lstatus, struct net_device *dev) +static void count_errors(u32 lstatus, struct net_device *ndev) { - struct gfar_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &dev->stats; + struct gfar_private *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; struct gfar_extra_stats *estats = &priv->extra_stats; /* If the packet was truncated, none of the other errors matter */ @@ -2854,10 +2853,9 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb) } /* gfar_process_frame() -- handle one incoming packet if skb isn't NULL. */ -static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - struct napi_struct *napi) +static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) { - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(ndev); struct rxfcb *fcb = NULL; /* fcb is at the beginning if exists */ @@ -2866,10 +2864,8 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, /* Remove the FCB from the skb * Remove the padded bytes, if there are any */ - if (priv->uses_rxfcb) { - skb_record_rx_queue(skb, fcb->rq); + if (priv->uses_rxfcb) skb_pull(skb, GMAC_FCB_LEN); - } /* Get receive timestamp from the skb */ if (priv->hwts_rx_en) { @@ -2883,24 +2879,20 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, if (priv->padding) skb_pull(skb, priv->padding); - if (dev->features & NETIF_F_RXCSUM) + if (ndev->features & NETIF_F_RXCSUM) gfar_rx_checksum(skb, fcb); /* Tell the skb what kind of packet this is */ - skb->protocol = eth_type_trans(skb, dev); + skb->protocol = eth_type_trans(skb, ndev); /* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here. * Even if vlan rx accel is disabled, on some chips * RXFCB_VLN is pseudo randomly set. */ - if (dev->features & NETIF_F_HW_VLAN_CTAG_RX && + if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX && be16_to_cpu(fcb->flags) & RXFCB_VLN) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(fcb->vlctl)); - - /* Send the packet up the stack */ - napi_gro_receive(napi, skb); - } /* gfar_clean_rx_ring() -- Processes each frame in the rx ring @@ -2909,12 +2901,12 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, */ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) { - struct net_device *dev = rx_queue->dev; + struct net_device *ndev = rx_queue->ndev; struct rxbd8 *bdp, *base; struct sk_buff *skb; int i, howmany = 0; int cleaned_cnt = gfar_rxbd_unused(rx_queue); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(ndev); /* Get the first full descriptor */ base = rx_queue->rx_bd_base; @@ -2948,7 +2940,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) if (unlikely(!(lstatus & BD_LFLAG(RXBD_LAST)) || (lstatus & BD_LFLAG(RXBD_ERR)))) { - count_errors(lstatus, dev); + count_errors(lstatus, ndev); /* discard faulty buffer */ dev_kfree_skb(skb); @@ -2965,11 +2957,13 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) skb_put(skb, pkt_len); rx_queue->stats.rx_bytes += pkt_len; skb_record_rx_queue(skb, rx_queue->qindex); - gfar_process_frame(dev, skb, - &rx_queue->grp->napi_rx); + gfar_process_frame(ndev, skb); + + /* Send the packet up the stack */ + napi_gro_receive(&rx_queue->grp->napi_rx, skb); } else { - netif_warn(priv, rx_err, dev, "Missing skb!\n"); + netif_warn(priv, rx_err, ndev, "Missing skb!\n"); rx_queue->stats.rx_dropped++; atomic64_inc(&priv->extra_stats.rx_skbmissing); } diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index cadb068cb37f..edf8529ed356 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -1022,7 +1022,7 @@ struct rx_q_stats { * @next_to_use: index of the next buffer to be alloc'd * @next_to_clean: index of the next buffer to be cleaned * @qindex: index of this queue - * @dev: back pointer to the dev structure + * @ndev: back pointer to net_device * @rx_ring_size: Rx ring size * @rxcoalescing: enable/disable rx-coalescing * @rxic: receive interrupt coalescing vlaue @@ -1031,7 +1031,7 @@ struct rx_q_stats { struct gfar_priv_rx_q { struct sk_buff **rx_skbuff __aligned(SMP_CACHE_BYTES); struct rxbd8 *rx_bd_base; - struct net_device *dev; + struct net_device *ndev; struct gfar_priv_grp *grp; u16 rx_ring_size; u16 qindex; -- cgit v1.3-6-gb490 From 75354148ce697266b57c13d051ddffa3bb75fc9e Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 13 Jul 2015 16:22:06 +0300 Subject: gianfar: Add paged allocation and Rx S/G The eTSEC h/w is capable of scatter/gather on the receive side too if MAXFRM > MRBLR, when the allowed maximum Rx frame size is set to be greater than the maximum Rx buffer size (MRBLR). It's about time the driver makes use of this h/w capability, by supporting fixed buffer sizes and Rx S/G. The buffer size given to eTSEC for reception is fixed to 1536B (must be multiple of 64), which is the same default buffer size as before, used to accommodate standard MTU (1500B) size frames. As before, eTSEC can receive frames of up to 9600B. Individual Rx buffers are mapped to page halves (page size for eTSEC systems is 4KB). The skb is built around the first buffer of a frame (using build_skb()). In case the frame spans multiple buffers, the trailing buffers are added as Rx fragments to the skb. The last buffer in frame is marked by the L status flag. A mechanism is in place to reuse the pages owned by the driver (for Rx) for subsequent receptions. Supporting fixed size buffers allows the implementation of Rx S/G, which in turn removes the memory pressure issues the driver had before when MTU was set for jumbo frame reception. Also, in most cases, the Rx path becomes faster due to Rx page reusal, since the overhead of allocating new rx buffers is removed from the fast path. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 320 ++++++++++++++--------- drivers/net/ethernet/freescale/gianfar.h | 31 ++- drivers/net/ethernet/freescale/gianfar_ethtool.c | 1 - 3 files changed, 208 insertions(+), 144 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 7654d5eafeeb..648ca85c5859 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -109,7 +109,7 @@ #define TX_TIMEOUT (1*HZ) -const char gfar_driver_version[] = "1.3"; +const char gfar_driver_version[] = "2.0"; static int gfar_enet_open(struct net_device *dev); static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); @@ -207,6 +207,7 @@ static void gfar_init_bds(struct net_device *ndev) rx_queue->next_to_clean = 0; rx_queue->next_to_use = 0; + rx_queue->next_to_alloc = 0; /* make sure next_to_clean != next_to_use after this * by leaving at least 1 unused descriptor @@ -222,7 +223,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) { void *vaddr; dma_addr_t addr; - int i, j, k; + int i, j; struct gfar_private *priv = netdev_priv(ndev); struct device *dev = priv->dev; struct gfar_priv_tx_q *tx_queue = NULL; @@ -262,6 +263,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) rx_queue->rx_bd_base = vaddr; rx_queue->rx_bd_dma_base = addr; rx_queue->ndev = ndev; + rx_queue->dev = dev; addr += sizeof(struct rxbd8) * rx_queue->rx_ring_size; vaddr += sizeof(struct rxbd8) * rx_queue->rx_ring_size; } @@ -276,21 +278,17 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) if (!tx_queue->tx_skbuff) goto cleanup; - for (k = 0; k < tx_queue->tx_ring_size; k++) - tx_queue->tx_skbuff[k] = NULL; + for (j = 0; j < tx_queue->tx_ring_size; j++) + tx_queue->tx_skbuff[j] = NULL; } for (i = 0; i < priv->num_rx_queues; i++) { rx_queue = priv->rx_queue[i]; - rx_queue->rx_skbuff = - kmalloc_array(rx_queue->rx_ring_size, - sizeof(*rx_queue->rx_skbuff), - GFP_KERNEL); - if (!rx_queue->rx_skbuff) + rx_queue->rx_buff = kcalloc(rx_queue->rx_ring_size, + sizeof(*rx_queue->rx_buff), + GFP_KERNEL); + if (!rx_queue->rx_buff) goto cleanup; - - for (j = 0; j < rx_queue->rx_ring_size; j++) - rx_queue->rx_skbuff[j] = NULL; } gfar_init_bds(ndev); @@ -335,10 +333,8 @@ static void gfar_init_rqprm(struct gfar_private *priv) } } -static void gfar_rx_buff_size_config(struct gfar_private *priv) +static void gfar_rx_offload_en(struct gfar_private *priv) { - int frame_size = priv->ndev->mtu + ETH_HLEN + ETH_FCS_LEN; - /* set this when rx hw offload (TOE) functions are being used */ priv->uses_rxfcb = 0; @@ -347,16 +343,6 @@ static void gfar_rx_buff_size_config(struct gfar_private *priv) if (priv->hwts_rx_en) priv->uses_rxfcb = 1; - - if (priv->uses_rxfcb) - frame_size += GMAC_FCB_LEN; - - frame_size += priv->padding; - - frame_size = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) + - INCREMENTAL_BUFFER_SIZE; - - priv->rx_buffer_size = frame_size; } static void gfar_mac_rx_config(struct gfar_private *priv) @@ -590,7 +576,6 @@ static int gfar_alloc_rx_queues(struct gfar_private *priv) if (!priv->rx_queue[i]) return -ENOMEM; - priv->rx_queue[i]->rx_skbuff = NULL; priv->rx_queue[i]->qindex = i; priv->rx_queue[i]->ndev = priv->ndev; } @@ -1184,12 +1169,11 @@ void gfar_mac_reset(struct gfar_private *priv) udelay(3); - /* Compute rx_buff_size based on config flags */ - gfar_rx_buff_size_config(priv); + gfar_rx_offload_en(priv); /* Initialize the max receive frame/buffer lengths */ - gfar_write(®s->maxfrm, priv->rx_buffer_size); - gfar_write(®s->mrblr, priv->rx_buffer_size); + gfar_write(®s->maxfrm, GFAR_JUMBO_FRAME_SIZE); + gfar_write(®s->mrblr, GFAR_RXB_SIZE); /* Initialize the Minimum Frame Length Register */ gfar_write(®s->minflr, MINFLR_INIT_SETTINGS); @@ -1197,12 +1181,11 @@ void gfar_mac_reset(struct gfar_private *priv) /* Initialize MACCFG2. */ tempval = MACCFG2_INIT_SETTINGS; - /* If the mtu is larger than the max size for standard - * ethernet frames (ie, a jumbo frame), then set maccfg2 - * to allow huge frames, and to check the length + /* eTSEC74 erratum: Rx frames of length MAXFRM or MAXFRM-1 + * are marked as truncated. Avoid this by MACCFG2[Huge Frame]=1, + * and by checking RxBD[LG] and discarding larger than MAXFRM. */ - if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE || - gfar_has_errata(priv, GFAR_ERRATA_74)) + if (gfar_has_errata(priv, GFAR_ERRATA_74)) tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK; gfar_write(®s->maccfg2, tempval); @@ -1413,8 +1396,6 @@ static int gfar_probe(struct platform_device *ofdev) priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) dev->needed_headroom = GMAC_FCB_LEN; - priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; - /* Initializing some of the rx/tx queue level parameters */ for (i = 0; i < priv->num_tx_queues; i++) { priv->tx_queue[i]->tx_ring_size = DEFAULT_TX_RING_SIZE; @@ -1911,26 +1892,32 @@ static void free_skb_tx_queue(struct gfar_priv_tx_q *tx_queue) static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue) { - struct rxbd8 *rxbdp; - struct gfar_private *priv = netdev_priv(rx_queue->ndev); int i; - rxbdp = rx_queue->rx_bd_base; + struct rxbd8 *rxbdp = rx_queue->rx_bd_base; + + if (rx_queue->skb) + dev_kfree_skb(rx_queue->skb); for (i = 0; i < rx_queue->rx_ring_size; i++) { - if (rx_queue->rx_skbuff[i]) { - dma_unmap_single(priv->dev, be32_to_cpu(rxbdp->bufPtr), - priv->rx_buffer_size, - DMA_FROM_DEVICE); - dev_kfree_skb_any(rx_queue->rx_skbuff[i]); - rx_queue->rx_skbuff[i] = NULL; - } + struct gfar_rx_buff *rxb = &rx_queue->rx_buff[i]; + rxbdp->lstatus = 0; rxbdp->bufPtr = 0; rxbdp++; + + if (!rxb->page) + continue; + + dma_unmap_single(rx_queue->dev, rxb->dma, + PAGE_SIZE, DMA_FROM_DEVICE); + __free_page(rxb->page); + + rxb->page = NULL; } - kfree(rx_queue->rx_skbuff); - rx_queue->rx_skbuff = NULL; + + kfree(rx_queue->rx_buff); + rx_queue->rx_buff = NULL; } /* If there are any tx skbs or rx skbs still around, free them. @@ -1955,7 +1942,7 @@ static void free_skb_resources(struct gfar_private *priv) for (i = 0; i < priv->num_rx_queues; i++) { rx_queue = priv->rx_queue[i]; - if (rx_queue->rx_skbuff) + if (rx_queue->rx_buff) free_skb_rx_queue(rx_queue); } @@ -2513,7 +2500,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) struct gfar_private *priv = netdev_priv(dev); int frame_size = new_mtu + ETH_HLEN; - if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) { + if ((frame_size < 64) || (frame_size > GFAR_JUMBO_FRAME_SIZE)) { netif_err(priv, drv, dev, "Invalid MTU setting\n"); return -EINVAL; } @@ -2567,15 +2554,6 @@ static void gfar_timeout(struct net_device *dev) schedule_work(&priv->reset_task); } -static void gfar_align_skb(struct sk_buff *skb) -{ - /* We need the data buffer to be aligned properly. We will reserve - * as many bytes as needed to align the data properly - */ - skb_reserve(skb, RXBUF_ALIGNMENT - - (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1))); -} - /* Interrupt Handler for Transmit complete */ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) { @@ -2682,28 +2660,27 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) netdev_tx_completed_queue(txq, howmany, bytes_sent); } -static struct sk_buff *gfar_new_skb(struct net_device *ndev, - dma_addr_t *bufaddr) +static bool gfar_new_page(struct gfar_priv_rx_q *rxq, struct gfar_rx_buff *rxb) { - struct gfar_private *priv = netdev_priv(ndev); - struct sk_buff *skb; + struct page *page; dma_addr_t addr; - skb = netdev_alloc_skb(ndev, priv->rx_buffer_size + RXBUF_ALIGNMENT); - if (!skb) - return NULL; + page = dev_alloc_page(); + if (unlikely(!page)) + return false; - gfar_align_skb(skb); + addr = dma_map_page(rxq->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(rxq->dev, addr))) { + __free_page(page); - addr = dma_map_single(priv->dev, skb->data, - priv->rx_buffer_size, DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(priv->dev, addr))) { - dev_kfree_skb_any(skb); - return NULL; + return false; } - *bufaddr = addr; - return skb; + rxb->dma = addr; + rxb->page = page; + rxb->page_offset = 0; + + return true; } static void gfar_rx_alloc_err(struct gfar_priv_rx_q *rx_queue) @@ -2718,41 +2695,40 @@ static void gfar_rx_alloc_err(struct gfar_priv_rx_q *rx_queue) static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, int alloc_cnt) { - struct net_device *ndev = rx_queue->ndev; - struct rxbd8 *bdp, *base; - dma_addr_t bufaddr; + struct rxbd8 *bdp; + struct gfar_rx_buff *rxb; int i; i = rx_queue->next_to_use; - base = rx_queue->rx_bd_base; bdp = &rx_queue->rx_bd_base[i]; + rxb = &rx_queue->rx_buff[i]; while (alloc_cnt--) { - struct sk_buff *skb = rx_queue->rx_skbuff[i]; - - if (likely(!skb)) { - skb = gfar_new_skb(ndev, &bufaddr); - if (unlikely(!skb)) { + /* try reuse page */ + if (unlikely(!rxb->page)) { + if (unlikely(!gfar_new_page(rx_queue, rxb))) { gfar_rx_alloc_err(rx_queue); break; } - } else { /* restore from sleep state */ - bufaddr = be32_to_cpu(bdp->bufPtr); } - rx_queue->rx_skbuff[i] = skb; - /* Setup the new RxBD */ - gfar_init_rxbdp(rx_queue, bdp, bufaddr); + gfar_init_rxbdp(rx_queue, bdp, + rxb->dma + rxb->page_offset + RXBUF_ALIGNMENT); /* Update to the next pointer */ - bdp = next_bd(bdp, base, rx_queue->rx_ring_size); + bdp++; + rxb++; - if (unlikely(++i == rx_queue->rx_ring_size)) + if (unlikely(++i == rx_queue->rx_ring_size)) { i = 0; + bdp = rx_queue->rx_bd_base; + rxb = rx_queue->rx_buff; + } } rx_queue->next_to_use = i; + rx_queue->next_to_alloc = i; } static void count_errors(u32 lstatus, struct net_device *ndev) @@ -2839,6 +2815,93 @@ static irqreturn_t gfar_transmit(int irq, void *grp_id) return IRQ_HANDLED; } +static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus, + struct sk_buff *skb, bool first) +{ + unsigned int size = lstatus & BD_LENGTH_MASK; + struct page *page = rxb->page; + + /* Remove the FCS from the packet length */ + if (likely(lstatus & BD_LFLAG(RXBD_LAST))) + size -= ETH_FCS_LEN; + + if (likely(first)) + skb_put(skb, size); + else + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, + rxb->page_offset + RXBUF_ALIGNMENT, + size, GFAR_RXB_TRUESIZE); + + /* try reuse page */ + if (unlikely(page_count(page) != 1)) + return false; + + /* change offset to the other half */ + rxb->page_offset ^= GFAR_RXB_TRUESIZE; + + atomic_inc(&page->_count); + + return true; +} + +static void gfar_reuse_rx_page(struct gfar_priv_rx_q *rxq, + struct gfar_rx_buff *old_rxb) +{ + struct gfar_rx_buff *new_rxb; + u16 nta = rxq->next_to_alloc; + + new_rxb = &rxq->rx_buff[nta]; + + /* find next buf that can reuse a page */ + nta++; + rxq->next_to_alloc = (nta < rxq->rx_ring_size) ? nta : 0; + + /* copy page reference */ + *new_rxb = *old_rxb; + + /* sync for use by the device */ + dma_sync_single_range_for_device(rxq->dev, old_rxb->dma, + old_rxb->page_offset, + GFAR_RXB_TRUESIZE, DMA_FROM_DEVICE); +} + +static struct sk_buff *gfar_get_next_rxbuff(struct gfar_priv_rx_q *rx_queue, + u32 lstatus, struct sk_buff *skb) +{ + struct gfar_rx_buff *rxb = &rx_queue->rx_buff[rx_queue->next_to_clean]; + struct page *page = rxb->page; + bool first = false; + + if (likely(!skb)) { + void *buff_addr = page_address(page) + rxb->page_offset; + + skb = build_skb(buff_addr, GFAR_SKBFRAG_SIZE); + if (unlikely(!skb)) { + gfar_rx_alloc_err(rx_queue); + return NULL; + } + skb_reserve(skb, RXBUF_ALIGNMENT); + first = true; + } + + dma_sync_single_range_for_cpu(rx_queue->dev, rxb->dma, rxb->page_offset, + GFAR_RXB_TRUESIZE, DMA_FROM_DEVICE); + + if (gfar_add_rx_frag(rxb, lstatus, skb, first)) { + /* reuse the free half of the page */ + gfar_reuse_rx_page(rx_queue, rxb); + } else { + /* page cannot be reused, unmap it */ + dma_unmap_page(rx_queue->dev, rxb->dma, + PAGE_SIZE, DMA_FROM_DEVICE); + } + + /* clear rxb content */ + rxb->page = NULL; + + return skb; +} + static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb) { /* If valid headers were found, and valid sums @@ -2902,14 +2965,14 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) { struct net_device *ndev = rx_queue->ndev; - struct rxbd8 *bdp, *base; - struct sk_buff *skb; + struct gfar_private *priv = netdev_priv(ndev); + struct rxbd8 *bdp; int i, howmany = 0; + struct sk_buff *skb = rx_queue->skb; int cleaned_cnt = gfar_rxbd_unused(rx_queue); - struct gfar_private *priv = netdev_priv(ndev); + unsigned int total_bytes = 0, total_pkts = 0; /* Get the first full descriptor */ - base = rx_queue->rx_bd_base; i = rx_queue->next_to_clean; while (rx_work_limit--) { @@ -2929,54 +2992,51 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) rmb(); /* fetch next to clean buffer from the ring */ - skb = rx_queue->rx_skbuff[i]; + skb = gfar_get_next_rxbuff(rx_queue, lstatus, skb); + if (unlikely(!skb)) + break; - dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr), - priv->rx_buffer_size, DMA_FROM_DEVICE); + cleaned_cnt++; + howmany++; - if (unlikely(!(lstatus & BD_LFLAG(RXBD_ERR)) && - (lstatus & BD_LENGTH_MASK) > priv->rx_buffer_size)) - lstatus |= BD_LFLAG(RXBD_LARGE); + if (unlikely(++i == rx_queue->rx_ring_size)) + i = 0; + + rx_queue->next_to_clean = i; + + /* fetch next buffer if not the last in frame */ + if (!(lstatus & BD_LFLAG(RXBD_LAST))) + continue; - if (unlikely(!(lstatus & BD_LFLAG(RXBD_LAST)) || - (lstatus & BD_LFLAG(RXBD_ERR)))) { + if (unlikely(lstatus & BD_LFLAG(RXBD_ERR))) { count_errors(lstatus, ndev); /* discard faulty buffer */ dev_kfree_skb(skb); + skb = NULL; + rx_queue->stats.rx_dropped++; + continue; + } - } else { - /* Increment the number of packets */ - rx_queue->stats.rx_packets++; - howmany++; - - if (likely(skb)) { - int pkt_len = (lstatus & BD_LENGTH_MASK) - - ETH_FCS_LEN; - /* Remove the FCS from the packet length */ - skb_put(skb, pkt_len); - rx_queue->stats.rx_bytes += pkt_len; - skb_record_rx_queue(skb, rx_queue->qindex); - gfar_process_frame(ndev, skb); - - /* Send the packet up the stack */ - napi_gro_receive(&rx_queue->grp->napi_rx, skb); + /* Increment the number of packets */ + total_pkts++; + total_bytes += skb->len; - } else { - netif_warn(priv, rx_err, ndev, "Missing skb!\n"); - rx_queue->stats.rx_dropped++; - atomic64_inc(&priv->extra_stats.rx_skbmissing); - } + skb_record_rx_queue(skb, rx_queue->qindex); - } + gfar_process_frame(ndev, skb); - rx_queue->rx_skbuff[i] = NULL; - cleaned_cnt++; - if (unlikely(++i == rx_queue->rx_ring_size)) - i = 0; + /* Send the packet up the stack */ + napi_gro_receive(&rx_queue->grp->napi_rx, skb); + + skb = NULL; } - rx_queue->next_to_clean = i; + /* Store incomplete frames for completion */ + rx_queue->skb = skb; + + rx_queue->stats.rx_packets += total_pkts; + rx_queue->stats.rx_bytes += total_bytes; if (cleaned_cnt) gfar_alloc_rx_buffs(rx_queue, cleaned_cnt); diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index edf8529ed356..44021243c187 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -71,11 +71,6 @@ struct ethtool_rx_list { /* Number of bytes to align the rx bufs to */ #define RXBUF_ALIGNMENT 64 -/* The number of bytes which composes a unit for the purpose of - * allocating data buffers. ie-for any given MTU, the data buffer - * will be the next highest multiple of 512 bytes. */ -#define INCREMENTAL_BUFFER_SIZE 512 - #define PHY_INIT_TIMEOUT 100000 #define DRV_NAME "gfar-enet" @@ -105,11 +100,14 @@ extern const char gfar_driver_version[]; #define DEFAULT_RX_LFC_THR 16 #define DEFAULT_LFC_PTVVAL 4 -#define DEFAULT_RX_BUFFER_SIZE 1536 +#define GFAR_RXB_SIZE 1536 +#define GFAR_SKBFRAG_SIZE (RXBUF_ALIGNMENT + GFAR_RXB_SIZE \ + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +#define GFAR_RXB_TRUESIZE 2048 + #define TX_RING_MOD_MASK(size) (size-1) #define RX_RING_MOD_MASK(size) (size-1) -#define JUMBO_BUFFER_SIZE 9728 -#define JUMBO_FRAME_SIZE 9600 +#define GFAR_JUMBO_FRAME_SIZE 9600 #define DEFAULT_FIFO_TX_THR 0x100 #define DEFAULT_FIFO_TX_STARVE 0x40 @@ -654,7 +652,6 @@ struct gfar_extra_stats { atomic64_t eberr; atomic64_t tx_babt; atomic64_t tx_underrun; - atomic64_t rx_skbmissing; atomic64_t tx_timeout; }; @@ -1015,9 +1012,15 @@ struct rx_q_stats { unsigned long rx_dropped; }; +struct gfar_rx_buff { + dma_addr_t dma; + struct page *page; + unsigned int page_offset; +}; + /** * struct gfar_priv_rx_q - per rx queue structure - * @rx_skbuff: skb pointers + * @rx_buff: Array of buffer info metadata structs * @rx_bd_base: First rx buffer descriptor * @next_to_use: index of the next buffer to be alloc'd * @next_to_clean: index of the next buffer to be cleaned @@ -1029,14 +1032,17 @@ struct rx_q_stats { */ struct gfar_priv_rx_q { - struct sk_buff **rx_skbuff __aligned(SMP_CACHE_BYTES); + struct gfar_rx_buff *rx_buff __aligned(SMP_CACHE_BYTES); struct rxbd8 *rx_bd_base; struct net_device *ndev; - struct gfar_priv_grp *grp; + struct device *dev; u16 rx_ring_size; u16 qindex; + struct gfar_priv_grp *grp; u16 next_to_clean; u16 next_to_use; + u16 next_to_alloc; + struct sk_buff *skb; struct rx_q_stats stats; u32 __iomem *rfbptr; unsigned char rxcoalescing; @@ -1111,7 +1117,6 @@ struct gfar_private { struct device *dev; struct net_device *ndev; enum gfar_errata errata; - unsigned int rx_buffer_size; u16 uses_rxfcb; u16 padding; diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 012fa4e79ffa..3020aaabf0e4 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -74,7 +74,6 @@ static const char stat_gstrings[][ETH_GSTRING_LEN] = { "ethernet-bus-error", "tx-babbling-errors", "tx-underrun-errors", - "rx-skb-missing-errors", "tx-timeout-errors", /* rmon stats */ "tx-rx-64-frames", -- cgit v1.3-6-gb490 From e29dd44325e2fe121088094dcb3055c8d9e5202a Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Mon, 13 Jul 2015 21:51:38 +0200 Subject: net: qlcnic: Deletion of unnecessary memset There is no need to memset memory allocated with vzalloc. Signed-off-by: Christophe JAILLET Acked-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 2f6cc423ab1d..7dbab3c20db5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -2403,7 +2403,6 @@ int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter, qlcnic_free_tx_rings(adapter); return -ENOMEM; } - memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring)); tx_ring->cmd_buf_arr = cmd_buf_arr; spin_lock_init(&tx_ring->tx_clean_lock); } -- cgit v1.3-6-gb490 From a6ed1f4e94e1883742ac79f09f9754ffacfae456 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Fri, 19 Jun 2015 15:57:44 +0800 Subject: PCI: Use "slot" and "pci_slot" for struct hotplug_slot and struct pci_slot Now in pci_hotplug_core.c, we randomly name a struct hotplug_slot and a struct pci_slot. It's easy to confuse them, so let us use "slot" for a struct hotplug_slot and "pci_slot" for a struct pci_slot. No functional change. Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pci_hotplug_core.c | 122 ++++++++++++++++----------------- 1 file changed, 61 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 56d8486dc167..d1fab97d6b01 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -83,12 +83,12 @@ GET_STATUS(attention_status, u8) GET_STATUS(latch_status, u8) GET_STATUS(adapter_status, u8) -static ssize_t power_read_file(struct pci_slot *slot, char *buf) +static ssize_t power_read_file(struct pci_slot *pci_slot, char *buf) { int retval; u8 value; - retval = get_power_status(slot->hotplug, &value); + retval = get_power_status(pci_slot->hotplug, &value); if (retval) return retval; @@ -140,22 +140,22 @@ static struct pci_slot_attribute hotplug_slot_attr_power = { .store = power_write_file }; -static ssize_t attention_read_file(struct pci_slot *slot, char *buf) +static ssize_t attention_read_file(struct pci_slot *pci_slot, char *buf) { int retval; u8 value; - retval = get_attention_status(slot->hotplug, &value); + retval = get_attention_status(pci_slot->hotplug, &value); if (retval) return retval; return sprintf(buf, "%d\n", value); } -static ssize_t attention_write_file(struct pci_slot *slot, const char *buf, +static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf, size_t count) { - struct hotplug_slot_ops *ops = slot->hotplug->ops; + struct hotplug_slot_ops *ops = pci_slot->hotplug->ops; unsigned long lattention; u8 attention; int retval = 0; @@ -169,7 +169,7 @@ static ssize_t attention_write_file(struct pci_slot *slot, const char *buf, goto exit; } if (ops->set_attention_status) - retval = ops->set_attention_status(slot->hotplug, attention); + retval = ops->set_attention_status(pci_slot->hotplug, attention); module_put(ops->owner); exit: @@ -184,12 +184,12 @@ static struct pci_slot_attribute hotplug_slot_attr_attention = { .store = attention_write_file }; -static ssize_t latch_read_file(struct pci_slot *slot, char *buf) +static ssize_t latch_read_file(struct pci_slot *pci_slot, char *buf) { int retval; u8 value; - retval = get_latch_status(slot->hotplug, &value); + retval = get_latch_status(pci_slot->hotplug, &value); if (retval) return retval; @@ -201,12 +201,12 @@ static struct pci_slot_attribute hotplug_slot_attr_latch = { .show = latch_read_file, }; -static ssize_t presence_read_file(struct pci_slot *slot, char *buf) +static ssize_t presence_read_file(struct pci_slot *pci_slot, char *buf) { int retval; u8 value; - retval = get_adapter_status(slot->hotplug, &value); + retval = get_adapter_status(pci_slot->hotplug, &value); if (retval) return retval; @@ -307,43 +307,43 @@ static bool has_test_file(struct pci_slot *pci_slot) return false; } -static int fs_add_slot(struct pci_slot *slot) +static int fs_add_slot(struct pci_slot *pci_slot) { int retval = 0; /* Create symbolic link to the hotplug driver module */ - pci_hp_create_module_link(slot); + pci_hp_create_module_link(pci_slot); - if (has_power_file(slot)) { - retval = sysfs_create_file(&slot->kobj, + if (has_power_file(pci_slot)) { + retval = sysfs_create_file(&pci_slot->kobj, &hotplug_slot_attr_power.attr); if (retval) goto exit_power; } - if (has_attention_file(slot)) { - retval = sysfs_create_file(&slot->kobj, + if (has_attention_file(pci_slot)) { + retval = sysfs_create_file(&pci_slot->kobj, &hotplug_slot_attr_attention.attr); if (retval) goto exit_attention; } - if (has_latch_file(slot)) { - retval = sysfs_create_file(&slot->kobj, + if (has_latch_file(pci_slot)) { + retval = sysfs_create_file(&pci_slot->kobj, &hotplug_slot_attr_latch.attr); if (retval) goto exit_latch; } - if (has_adapter_file(slot)) { - retval = sysfs_create_file(&slot->kobj, + if (has_adapter_file(pci_slot)) { + retval = sysfs_create_file(&pci_slot->kobj, &hotplug_slot_attr_presence.attr); if (retval) goto exit_adapter; } - if (has_test_file(slot)) { - retval = sysfs_create_file(&slot->kobj, + if (has_test_file(pci_slot)) { + retval = sysfs_create_file(&pci_slot->kobj, &hotplug_slot_attr_test.attr); if (retval) goto exit_test; @@ -352,45 +352,45 @@ static int fs_add_slot(struct pci_slot *slot) goto exit; exit_test: - if (has_adapter_file(slot)) - sysfs_remove_file(&slot->kobj, + if (has_adapter_file(pci_slot)) + sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_presence.attr); exit_adapter: - if (has_latch_file(slot)) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); + if (has_latch_file(pci_slot)) + sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_latch.attr); exit_latch: - if (has_attention_file(slot)) - sysfs_remove_file(&slot->kobj, + if (has_attention_file(pci_slot)) + sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_attention.attr); exit_attention: - if (has_power_file(slot)) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); + if (has_power_file(pci_slot)) + sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_power.attr); exit_power: - pci_hp_remove_module_link(slot); + pci_hp_remove_module_link(pci_slot); exit: return retval; } -static void fs_remove_slot(struct pci_slot *slot) +static void fs_remove_slot(struct pci_slot *pci_slot) { - if (has_power_file(slot)) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); + if (has_power_file(pci_slot)) + sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_power.attr); - if (has_attention_file(slot)) - sysfs_remove_file(&slot->kobj, + if (has_attention_file(pci_slot)) + sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_attention.attr); - if (has_latch_file(slot)) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); + if (has_latch_file(pci_slot)) + sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_latch.attr); - if (has_adapter_file(slot)) - sysfs_remove_file(&slot->kobj, + if (has_adapter_file(pci_slot)) + sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_presence.attr); - if (has_test_file(slot)) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); + if (has_test_file(pci_slot)) + sysfs_remove_file(&pci_slot->kobj, &hotplug_slot_attr_test.attr); - pci_hp_remove_module_link(slot); + pci_hp_remove_module_link(pci_slot); } static struct hotplug_slot *get_slot_from_name(const char *name) @@ -467,37 +467,37 @@ EXPORT_SYMBOL_GPL(__pci_hp_register); /** * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem - * @hotplug: pointer to the &struct hotplug_slot to deregister + * @slot: pointer to the &struct hotplug_slot to deregister * * The @slot must have been registered with the pci hotplug subsystem * previously with a call to pci_hp_register(). * * Returns 0 if successful, anything else for an error. */ -int pci_hp_deregister(struct hotplug_slot *hotplug) +int pci_hp_deregister(struct hotplug_slot *slot) { struct hotplug_slot *temp; - struct pci_slot *slot; + struct pci_slot *pci_slot; - if (!hotplug) + if (!slot) return -ENODEV; mutex_lock(&pci_hp_mutex); - temp = get_slot_from_name(hotplug_slot_name(hotplug)); - if (temp != hotplug) { + temp = get_slot_from_name(hotplug_slot_name(slot)); + if (temp != slot) { mutex_unlock(&pci_hp_mutex); return -ENODEV; } - list_del(&hotplug->slot_list); + list_del(&slot->slot_list); - slot = hotplug->pci_slot; - fs_remove_slot(slot); - dbg("Removed slot %s from the list\n", hotplug_slot_name(hotplug)); + pci_slot = slot->pci_slot; + fs_remove_slot(pci_slot); + dbg("Removed slot %s from the list\n", hotplug_slot_name(slot)); - hotplug->release(hotplug); - slot->hotplug = NULL; - pci_destroy_slot(slot); + slot->release(slot); + pci_slot->hotplug = NULL; + pci_destroy_slot(pci_slot); mutex_unlock(&pci_hp_mutex); return 0; @@ -506,7 +506,7 @@ EXPORT_SYMBOL_GPL(pci_hp_deregister); /** * pci_hp_change_slot_info - changes the slot's information structure in the core - * @hotplug: pointer to the slot whose info has changed + * @slot: pointer to the slot whose info has changed * @info: pointer to the info copy into the slot's info structure * * @slot must have been registered with the pci @@ -514,13 +514,13 @@ EXPORT_SYMBOL_GPL(pci_hp_deregister); * * Returns 0 if successful, anything else for an error. */ -int pci_hp_change_slot_info(struct hotplug_slot *hotplug, +int pci_hp_change_slot_info(struct hotplug_slot *slot, struct hotplug_slot_info *info) { - if (!hotplug || !info) + if (!slot || !info) return -ENODEV; - memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info)); + memcpy(slot->info, info, sizeof(struct hotplug_slot_info)); return 0; } -- cgit v1.3-6-gb490 From ac10836b681289f7e430e52b106a209bbdcaa75e Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Fri, 19 Jun 2015 15:57:45 +0800 Subject: PCI: pciehp: Simplify pcie_poll_cmd() Move first slot status read into while to simplify code. Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp_hpc.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 2913f7e68a10..daf54bee720d 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -109,21 +109,17 @@ static int pcie_poll_cmd(struct controller *ctrl, int timeout) struct pci_dev *pdev = ctrl_dev(ctrl); u16 slot_status; - pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); - if (slot_status & PCI_EXP_SLTSTA_CC) { - pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, - PCI_EXP_SLTSTA_CC); - return 1; - } - while (timeout > 0) { - msleep(10); - timeout -= 10; + while (true) { pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); if (slot_status & PCI_EXP_SLTSTA_CC) { pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC); return 1; } + if (timeout < 0) + break; + msleep(10); + timeout -= 10; } return 0; /* timeout */ } -- cgit v1.3-6-gb490 From 2de8530ba0c71a2fba02590681af0f3a2a187a9b Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 13 Jul 2015 13:09:16 -0700 Subject: hv_netvsc: Add close of RNDIS filter into change mtu call The current change mtu call only stops tx before removing RNDIS filter. In case ringbufer is not empty, the rndis_filter_device_remove() may hang on removing the buffers. This patch adds close of RNDIS filter before removing it, also a gradual waiting loop until the ring is empty. The change_mtu hang issue under heavy traffic is solved by this patch. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 58 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index b855ba9a507d..7b36d5fecc1f 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -106,7 +106,7 @@ static int netvsc_open(struct net_device *net) return ret; } - netif_tx_start_all_queues(net); + netif_tx_wake_all_queues(net); nvdev = hv_get_drvdata(device_obj); rdev = nvdev->extension; @@ -120,15 +120,56 @@ static int netvsc_close(struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_device *device_obj = net_device_ctx->device_ctx; + struct netvsc_device *nvdev = hv_get_drvdata(device_obj); int ret; + u32 aread, awrite, i, msec = 10, retry = 0, retry_max = 20; + struct vmbus_channel *chn; netif_tx_disable(net); /* Make sure netvsc_set_multicast_list doesn't re-enable filter! */ cancel_work_sync(&net_device_ctx->work); ret = rndis_filter_close(device_obj); - if (ret != 0) + if (ret != 0) { netdev_err(net, "unable to close device (ret %d).\n", ret); + return ret; + } + + /* Ensure pending bytes in ring are read */ + while (true) { + aread = 0; + for (i = 0; i < nvdev->num_chn; i++) { + chn = nvdev->chn_table[i]; + if (!chn) + continue; + + hv_get_ringbuffer_availbytes(&chn->inbound, &aread, + &awrite); + + if (aread) + break; + + hv_get_ringbuffer_availbytes(&chn->outbound, &aread, + &awrite); + + if (aread) + break; + } + + retry++; + if (retry > retry_max || aread == 0) + break; + + msleep(msec); + + if (msec < 1000) + msec *= 2; + } + + if (aread) { + netdev_err(net, "Ring buffer not empty after closing rndis\n"); + ret = -ETIMEDOUT; + } return ret; } @@ -736,6 +777,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) struct netvsc_device *nvdev = hv_get_drvdata(hdev); struct netvsc_device_info device_info; int limit = ETH_DATA_LEN; + int ret = 0; if (nvdev == NULL || nvdev->destroy) return -ENODEV; @@ -746,9 +788,11 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) if (mtu < NETVSC_MTU_MIN || mtu > limit) return -EINVAL; + ret = netvsc_close(ndev); + if (ret) + goto out; + nvdev->start_remove = true; - cancel_work_sync(&ndevctx->work); - netif_tx_disable(ndev); rndis_filter_device_remove(hdev); ndev->mtu = mtu; @@ -758,9 +802,11 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) device_info.ring_size = ring_size; device_info.max_num_vrss_chns = max_num_vrss_chns; rndis_filter_device_add(hdev, &device_info); - netif_tx_wake_all_queues(ndev); - return 0; +out: + netvsc_open(ndev); + + return ret; } static struct rtnl_link_stats64 *netvsc_get_stats64(struct net_device *net, -- cgit v1.3-6-gb490 From b2a02ac65e40fb3900d176828a407b44bb33f9f4 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 8 Jul 2015 17:14:36 +0200 Subject: cxl: Destroy cxl_adapter_idr on module_exit Destroy cxl_adapter_idr on module exit, reclaiming the allocated memory. This was detected by the following semantic patch (written by Luis Rodriguez ) @ defines_module_init @ declarer name module_init, module_exit; declarer name DEFINE_IDR; identifier init; @@ module_init(init); @ defines_module_exit @ identifier exit; @@ module_exit(exit); @ declares_idr depends on defines_module_init && defines_module_exit @ identifier idr; @@ DEFINE_IDR(idr); @ on_exit_calls_destroy depends on declares_idr && defines_module_exit @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... idr_destroy(&idr); ... } @ missing_module_idr_destroy depends on declares_idr && defines_module_exit && !on_exit_calls_destroy @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... +idr_destroy(&idr); } Signed-off-by: Johannes Thumshirn Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c index 4a164ab8b35a..9fde75ed4fac 100644 --- a/drivers/misc/cxl/main.c +++ b/drivers/misc/cxl/main.c @@ -222,6 +222,7 @@ static void exit_cxl(void) cxl_debugfs_exit(); cxl_file_exit(); unregister_cxl_calls(&cxl_calls); + idr_destroy(&cxl_adapter_idr); } module_init(init_cxl); -- cgit v1.3-6-gb490 From bd664f892e3e2b01c79197cad3111d54b7aedf39 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Thu, 9 Jul 2015 09:39:42 +0200 Subject: cxl: Destroy afu->contexts_idr on release of an afu Destroy afu->contexts_idr on release of an afu, reclaiming the allocated memory. Signed-off-by: Johannes Thumshirn Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index eb05efb74eed..1d314f1f95fe 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -551,6 +551,7 @@ static void cxl_release_afu(struct device *dev) pr_devel("cxl_release_afu\n"); + idr_destroy(&afu->contexts_idr); kfree(afu); } -- cgit v1.3-6-gb490 From 07e6a97da1eba064bb35cfd5c121e90865393a60 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Tue, 14 Jul 2015 10:51:51 -0500 Subject: ibmveth: add support for TSO6 This patch adds support for a new method of signalling the firmware that TSO packets are being sent. The new method removes the need to alter the ip and tcp checksums and allows TSO6 support. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmveth.c | 145 ++++++++++++++++++++++++++++++------- drivers/net/ethernet/ibm/ibmveth.h | 18 ++++- 2 files changed, 135 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 29bbb628d712..7af870a3c549 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -79,6 +79,11 @@ static unsigned int rx_flush __read_mostly = 0; module_param(rx_flush, uint, 0644); MODULE_PARM_DESC(rx_flush, "Flush receive buffers before use"); +static bool old_large_send __read_mostly; +module_param(old_large_send, bool, S_IRUGO); +MODULE_PARM_DESC(old_large_send, + "Use old large send method on firmware that supports the new method"); + struct ibmveth_stat { char name[ETH_GSTRING_LEN]; int offset; @@ -101,7 +106,8 @@ struct ibmveth_stat ibmveth_stats[] = { { "fw_enabled_ipv4_csum", IBMVETH_STAT_OFF(fw_ipv4_csum_support) }, { "fw_enabled_ipv6_csum", IBMVETH_STAT_OFF(fw_ipv6_csum_support) }, { "tx_large_packets", IBMVETH_STAT_OFF(tx_large_packets) }, - { "rx_large_packets", IBMVETH_STAT_OFF(rx_large_packets) } + { "rx_large_packets", IBMVETH_STAT_OFF(rx_large_packets) }, + { "fw_enabled_large_send", IBMVETH_STAT_OFF(fw_large_send_support) } }; /* simple methods of getting data from the current rxq entry */ @@ -848,25 +854,91 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) return rc1 ? rc1 : rc2; } +static int ibmveth_set_tso(struct net_device *dev, u32 data) +{ + struct ibmveth_adapter *adapter = netdev_priv(dev); + unsigned long set_attr, clr_attr, ret_attr; + long ret1, ret2; + int rc1 = 0, rc2 = 0; + int restart = 0; + + if (netif_running(dev)) { + restart = 1; + adapter->pool_config = 1; + ibmveth_close(dev); + adapter->pool_config = 0; + } + + set_attr = 0; + clr_attr = 0; + + if (data) + set_attr = IBMVETH_ILLAN_LRG_SR_ENABLED; + else + clr_attr = IBMVETH_ILLAN_LRG_SR_ENABLED; + + ret1 = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); + + if (ret1 == H_SUCCESS && (ret_attr & IBMVETH_ILLAN_LRG_SND_SUPPORT) && + !old_large_send) { + ret2 = h_illan_attributes(adapter->vdev->unit_address, clr_attr, + set_attr, &ret_attr); + + if (ret2 != H_SUCCESS) { + netdev_err(dev, "unable to change tso settings. %d rc=%ld\n", + data, ret2); + + h_illan_attributes(adapter->vdev->unit_address, + set_attr, clr_attr, &ret_attr); + + if (data == 1) + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + rc1 = -EIO; + + } else { + adapter->fw_large_send_support = data; + adapter->large_send = data; + } + } else { + /* Older firmware version of large send offload does not + * support tcp6/ipv6 + */ + if (data == 1) { + dev->features &= ~NETIF_F_TSO6; + netdev_info(dev, "TSO feature requires all partitions to have updated driver"); + } + adapter->large_send = data; + } + + if (restart) + rc2 = ibmveth_open(dev); + + return rc1 ? rc1 : rc2; +} + static int ibmveth_set_features(struct net_device *dev, netdev_features_t features) { struct ibmveth_adapter *adapter = netdev_priv(dev); int rx_csum = !!(features & NETIF_F_RXCSUM); - int rc; - netdev_features_t changed = features ^ dev->features; - - if (features & NETIF_F_TSO & changed) - netdev_info(dev, "TSO feature requires all partitions to have updated driver"); + int large_send = !!(features & (NETIF_F_TSO | NETIF_F_TSO6)); + int rc1 = 0, rc2 = 0; - if (rx_csum == adapter->rx_csum) - return 0; + if (rx_csum != adapter->rx_csum) { + rc1 = ibmveth_set_csum_offload(dev, rx_csum); + if (rc1 && !adapter->rx_csum) + dev->features = + features & ~(NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); + } - rc = ibmveth_set_csum_offload(dev, rx_csum); - if (rc && !adapter->rx_csum) - dev->features = features & ~(NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); + if (large_send != adapter->large_send) { + rc2 = ibmveth_set_tso(dev, large_send); + if (rc2 && !adapter->large_send) + dev->features = + features & ~(NETIF_F_TSO | NETIF_F_TSO6); + } - return rc; + return rc1 ? rc1 : rc2; } static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -917,7 +989,7 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) #define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1)) static int ibmveth_send(struct ibmveth_adapter *adapter, - union ibmveth_buf_desc *descs) + union ibmveth_buf_desc *descs, unsigned long mss) { unsigned long correlator; unsigned int retry_count; @@ -934,7 +1006,8 @@ static int ibmveth_send(struct ibmveth_adapter *adapter, descs[0].desc, descs[1].desc, descs[2].desc, descs[3].desc, descs[4].desc, descs[5].desc, - correlator, &correlator); + correlator, &correlator, mss, + adapter->fw_large_send_support); } while ((ret == H_BUSY) && (retry_count--)); if (ret != H_SUCCESS && ret != H_DROPPED) { @@ -955,6 +1028,7 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, int last, i; int force_bounce = 0; dma_addr_t dma_addr; + unsigned long mss = 0; /* * veth handles a maximum of 6 segments including the header, so @@ -980,6 +1054,9 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, desc_flags = IBMVETH_BUF_VALID; + if (skb_is_gso(skb) && adapter->fw_large_send_support) + desc_flags |= IBMVETH_BUF_LRG_SND; + if (skb->ip_summed == CHECKSUM_PARTIAL) { unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; @@ -1007,7 +1084,7 @@ retry_bounce: descs[0].fields.flags_len = desc_flags | skb->len; descs[0].fields.address = adapter->bounce_buffer_dma; - if (ibmveth_send(adapter, descs)) { + if (ibmveth_send(adapter, descs, 0)) { adapter->tx_send_failed++; netdev->stats.tx_dropped++; } else { @@ -1041,16 +1118,23 @@ retry_bounce: descs[i+1].fields.address = dma_addr; } - if (skb_is_gso(skb) && !skb_is_gso_v6(skb)) { - /* Put -1 in the IP checksum to tell phyp it - * is a largesend packet and put the mss in the TCP checksum. - */ - ip_hdr(skb)->check = 0xffff; - tcp_hdr(skb)->check = cpu_to_be16(skb_shinfo(skb)->gso_size); - adapter->tx_large_packets++; + if (skb_is_gso(skb)) { + if (adapter->fw_large_send_support) { + mss = (unsigned long)skb_shinfo(skb)->gso_size; + adapter->tx_large_packets++; + } else if (!skb_is_gso_v6(skb)) { + /* Put -1 in the IP checksum to tell phyp it + * is a largesend packet. Put the mss in + * the TCP checksum. + */ + ip_hdr(skb)->check = 0xffff; + tcp_hdr(skb)->check = + cpu_to_be16(skb_shinfo(skb)->gso_size); + adapter->tx_large_packets++; + } } - if (ibmveth_send(adapter, descs)) { + if (ibmveth_send(adapter, descs, mss)) { adapter->tx_send_failed++; netdev->stats.tx_dropped++; } else { @@ -1401,6 +1485,8 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) struct ibmveth_adapter *adapter; unsigned char *mac_addr_p; unsigned int *mcastFilterSize_p; + long ret; + unsigned long ret_attr; dev_dbg(&dev->dev, "entering ibmveth_probe for UA 0x%x\n", dev->unit_address); @@ -1449,10 +1535,19 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) SET_NETDEV_DEV(netdev, &dev->dev); netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + netdev->features |= netdev->hw_features; - /* TSO is disabled by default */ - netdev->hw_features |= NETIF_F_TSO; + ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); + + /* If running older firmware, TSO should not be enabled by default */ + if (ret == H_SUCCESS && (ret_attr & IBMVETH_ILLAN_LRG_SND_SUPPORT) && + !old_large_send) { + netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; + netdev->features |= netdev->hw_features; + } else { + netdev->hw_features |= NETIF_F_TSO; + } memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN); diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index 41dedb1fb2ae..4eade67fe30c 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h @@ -40,6 +40,8 @@ #define IbmVethMcastRemoveFilter 0x2UL #define IbmVethMcastClearFilterTable 0x3UL +#define IBMVETH_ILLAN_LRG_SR_ENABLED 0x0000000000010000UL +#define IBMVETH_ILLAN_LRG_SND_SUPPORT 0x0000000000008000UL #define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000UL #define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00UL #define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004UL @@ -59,13 +61,20 @@ static inline long h_send_logical_lan(unsigned long unit_address, unsigned long desc1, unsigned long desc2, unsigned long desc3, unsigned long desc4, unsigned long desc5, unsigned long desc6, - unsigned long corellator_in, unsigned long *corellator_out) + unsigned long corellator_in, unsigned long *corellator_out, + unsigned long mss, unsigned long large_send_support) { long rc; unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; - rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, desc1, - desc2, desc3, desc4, desc5, desc6, corellator_in); + if (large_send_support) + rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, + desc1, desc2, desc3, desc4, desc5, desc6, + corellator_in, mss); + else + rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, + desc1, desc2, desc3, desc4, desc5, desc6, + corellator_in); *corellator_out = retbuf[0]; @@ -147,11 +156,13 @@ struct ibmveth_adapter { struct ibmveth_rx_q rx_queue; int pool_config; int rx_csum; + int large_send; void *bounce_buffer; dma_addr_t bounce_buffer_dma; u64 fw_ipv6_csum_support; u64 fw_ipv4_csum_support; + u64 fw_large_send_support; /* adapter specific stats */ u64 replenish_task_cycles; u64 replenish_no_mem; @@ -182,6 +193,7 @@ struct ibmveth_buf_desc_fields { #endif #define IBMVETH_BUF_VALID 0x80000000 #define IBMVETH_BUF_TOGGLE 0x40000000 +#define IBMVETH_BUF_LRG_SND 0x04000000 #define IBMVETH_BUF_NO_CSUM 0x02000000 #define IBMVETH_BUF_CSUM_GOOD 0x01000000 #define IBMVETH_BUF_LEN_MASK 0x00FFFFFF -- cgit v1.3-6-gb490 From c305524617dcd617d698dfe2682f3212e698f781 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Tue, 14 Jul 2015 13:43:21 -0700 Subject: rocker: Handle protodown notifications. protodown can be set by user space applications like MLAG on detecting errors on a switch port. This patch provides sample switch driver changes for handling protodown. Rocker PHYS disables the port in response to protodown. Signed-off-by: Anuradha Karuppiah Signed-off-by: Andy Gospodarek Signed-off-by: Roopa Prabhu Signed-off-by: Wilson Kok Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index c0051673c9fa..932428314b80 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4015,7 +4015,8 @@ static int rocker_port_open(struct net_device *dev) napi_enable(&rocker_port->napi_tx); napi_enable(&rocker_port->napi_rx); - rocker_port_set_enable(rocker_port, true); + if (!dev->proto_down) + rocker_port_set_enable(rocker_port, true); netif_start_queue(dev); return 0; @@ -4227,6 +4228,17 @@ static int rocker_port_get_phys_port_name(struct net_device *dev, return err ? -EOPNOTSUPP : 0; } +static int rocker_port_change_proto_down(struct net_device *dev, + bool proto_down) +{ + struct rocker_port *rocker_port = netdev_priv(dev); + + if (rocker_port->dev->flags & IFF_UP) + rocker_port_set_enable(rocker_port, !proto_down); + rocker_port->dev->proto_down = proto_down; + return 0; +} + static const struct net_device_ops rocker_port_netdev_ops = { .ndo_open = rocker_port_open, .ndo_stop = rocker_port_stop, @@ -4240,6 +4252,7 @@ static const struct net_device_ops rocker_port_netdev_ops = { .ndo_fdb_del = switchdev_port_fdb_del, .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_get_phys_port_name = rocker_port_get_phys_port_name, + .ndo_change_proto_down = rocker_port_change_proto_down, }; /******************** -- cgit v1.3-6-gb490 From d8d7a08fa82ff7c241c74c2461f342c5685dda27 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Wed, 13 May 2015 17:58:36 +0300 Subject: clk: tegra: Add library for the DFLL clock source (open-loop mode) Add shared code to support the Tegra DFLL clocksource in open-loop mode. This root clocksource is present on the Tegra124 SoCs. The DFLL is the intended primary clock source for the fast CPU cluster. This code is very closely based on a patch by Paul Walmsley from December (http://comments.gmane.org/gmane.linux.ports.tegra/15273), which in turn comes from the internal driver by originally created by Aleksandr Frid . Subsequent patches will add support for closed loop mode and drivers for the Tegra124 fast CPU cluster DFLL devices, which rely on this code. Signed-off-by: Paul Walmsley Signed-off-by: Tuomas Tynkkynen Signed-off-by: Mikko Perttunen Acked-by: Peter De Schrijver Acked-by: Michael Turquette Signed-off-by: Thierry Reding --- drivers/clk/tegra/Makefile | 1 + drivers/clk/tegra/clk-dfll.c | 1095 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/tegra/clk-dfll.h | 54 +++ 3 files changed, 1150 insertions(+) create mode 100644 drivers/clk/tegra/clk-dfll.c create mode 100644 drivers/clk/tegra/clk-dfll.h (limited to 'drivers') diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index aec862ba7a17..ec2e5163e1ae 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -1,5 +1,6 @@ obj-y += clk.o obj-y += clk-audio-sync.o +obj-y += clk-dfll.o obj-y += clk-divider.o obj-y += clk-periph.o obj-y += clk-periph-gate.o diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c new file mode 100644 index 000000000000..fb138bfa0af2 --- /dev/null +++ b/drivers/clk/tegra/clk-dfll.c @@ -0,0 +1,1095 @@ +/* + * clk-dfll.c - Tegra DFLL clock source common code + * + * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved. + * + * Aleksandr Frid + * Paul Walmsley + * + * 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. + * + * This library is for the DVCO and DFLL IP blocks on the Tegra124 + * SoC. These IP blocks together are also known at NVIDIA as + * "CL-DVFS". To try to avoid confusion, this code refers to them + * collectively as the "DFLL." + * + * The DFLL is a root clocksource which tolerates some amount of + * supply voltage noise. Tegra124 uses it to clock the fast CPU + * complex when the target CPU speed is above a particular rate. The + * DFLL can be operated in either open-loop mode or closed-loop mode. + * In open-loop mode, the DFLL generates an output clock appropriate + * to the supply voltage. In closed-loop mode, when configured with a + * target frequency, the DFLL minimizes supply voltage while + * delivering an average frequency equal to the target. + * + * Devices clocked by the DFLL must be able to tolerate frequency + * variation. In the case of the CPU, it's important to note that the + * CPU cycle time will vary. This has implications for + * performance-measurement code and any code that relies on the CPU + * cycle time to delay for a certain length of time. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk-dfll.h" + +/* + * DFLL control registers - access via dfll_{readl,writel} + */ + +/* DFLL_CTRL: DFLL control register */ +#define DFLL_CTRL 0x00 +#define DFLL_CTRL_MODE_MASK 0x03 + +/* DFLL_CONFIG: DFLL sample rate control */ +#define DFLL_CONFIG 0x04 +#define DFLL_CONFIG_DIV_MASK 0xff +#define DFLL_CONFIG_DIV_PRESCALE 32 + +/* DFLL_PARAMS: tuning coefficients for closed loop integrator */ +#define DFLL_PARAMS 0x08 +#define DFLL_PARAMS_CG_SCALE (0x1 << 24) +#define DFLL_PARAMS_FORCE_MODE_SHIFT 22 +#define DFLL_PARAMS_FORCE_MODE_MASK (0x3 << DFLL_PARAMS_FORCE_MODE_SHIFT) +#define DFLL_PARAMS_CF_PARAM_SHIFT 16 +#define DFLL_PARAMS_CF_PARAM_MASK (0x3f << DFLL_PARAMS_CF_PARAM_SHIFT) +#define DFLL_PARAMS_CI_PARAM_SHIFT 8 +#define DFLL_PARAMS_CI_PARAM_MASK (0x7 << DFLL_PARAMS_CI_PARAM_SHIFT) +#define DFLL_PARAMS_CG_PARAM_SHIFT 0 +#define DFLL_PARAMS_CG_PARAM_MASK (0xff << DFLL_PARAMS_CG_PARAM_SHIFT) + +/* DFLL_TUNE0: delay line configuration register 0 */ +#define DFLL_TUNE0 0x0c + +/* DFLL_TUNE1: delay line configuration register 1 */ +#define DFLL_TUNE1 0x10 + +/* DFLL_FREQ_REQ: target DFLL frequency control */ +#define DFLL_FREQ_REQ 0x14 +#define DFLL_FREQ_REQ_FORCE_ENABLE (0x1 << 28) +#define DFLL_FREQ_REQ_FORCE_SHIFT 16 +#define DFLL_FREQ_REQ_FORCE_MASK (0xfff << DFLL_FREQ_REQ_FORCE_SHIFT) +#define FORCE_MAX 2047 +#define FORCE_MIN -2048 +#define DFLL_FREQ_REQ_SCALE_SHIFT 8 +#define DFLL_FREQ_REQ_SCALE_MASK (0xff << DFLL_FREQ_REQ_SCALE_SHIFT) +#define DFLL_FREQ_REQ_SCALE_MAX 256 +#define DFLL_FREQ_REQ_FREQ_VALID (0x1 << 7) +#define DFLL_FREQ_REQ_MULT_SHIFT 0 +#define DFLL_FREQ_REG_MULT_MASK (0x7f << DFLL_FREQ_REQ_MULT_SHIFT) +#define FREQ_MAX 127 + +/* DFLL_DROOP_CTRL: droop prevention control */ +#define DFLL_DROOP_CTRL 0x1c + +/* DFLL_OUTPUT_CFG: closed loop mode control registers */ +/* NOTE: access via dfll_i2c_{readl,writel} */ +#define DFLL_OUTPUT_CFG 0x20 +#define DFLL_OUTPUT_CFG_I2C_ENABLE (0x1 << 30) +#define OUT_MASK 0x3f +#define DFLL_OUTPUT_CFG_SAFE_SHIFT 24 +#define DFLL_OUTPUT_CFG_SAFE_MASK \ + (OUT_MASK << DFLL_OUTPUT_CFG_SAFE_SHIFT) +#define DFLL_OUTPUT_CFG_MAX_SHIFT 16 +#define DFLL_OUTPUT_CFG_MAX_MASK \ + (OUT_MASK << DFLL_OUTPUT_CFG_MAX_SHIFT) +#define DFLL_OUTPUT_CFG_MIN_SHIFT 8 +#define DFLL_OUTPUT_CFG_MIN_MASK \ + (OUT_MASK << DFLL_OUTPUT_CFG_MIN_SHIFT) +#define DFLL_OUTPUT_CFG_PWM_DELTA (0x1 << 7) +#define DFLL_OUTPUT_CFG_PWM_ENABLE (0x1 << 6) +#define DFLL_OUTPUT_CFG_PWM_DIV_SHIFT 0 +#define DFLL_OUTPUT_CFG_PWM_DIV_MASK \ + (OUT_MASK << DFLL_OUTPUT_CFG_PWM_DIV_SHIFT) + +/* DFLL_OUTPUT_FORCE: closed loop mode voltage forcing control */ +#define DFLL_OUTPUT_FORCE 0x24 +#define DFLL_OUTPUT_FORCE_ENABLE (0x1 << 6) +#define DFLL_OUTPUT_FORCE_VALUE_SHIFT 0 +#define DFLL_OUTPUT_FORCE_VALUE_MASK \ + (OUT_MASK << DFLL_OUTPUT_FORCE_VALUE_SHIFT) + +/* DFLL_MONITOR_CTRL: internal monitor data source control */ +#define DFLL_MONITOR_CTRL 0x28 +#define DFLL_MONITOR_CTRL_FREQ 6 + +/* DFLL_MONITOR_DATA: internal monitor data output */ +#define DFLL_MONITOR_DATA 0x2c +#define DFLL_MONITOR_DATA_NEW_MASK (0x1 << 16) +#define DFLL_MONITOR_DATA_VAL_SHIFT 0 +#define DFLL_MONITOR_DATA_VAL_MASK (0xFFFF << DFLL_MONITOR_DATA_VAL_SHIFT) + +/* + * I2C output control registers - access via dfll_i2c_{readl,writel} + */ + +/* DFLL_I2C_CFG: I2C controller configuration register */ +#define DFLL_I2C_CFG 0x40 +#define DFLL_I2C_CFG_ARB_ENABLE (0x1 << 20) +#define DFLL_I2C_CFG_HS_CODE_SHIFT 16 +#define DFLL_I2C_CFG_HS_CODE_MASK (0x7 << DFLL_I2C_CFG_HS_CODE_SHIFT) +#define DFLL_I2C_CFG_PACKET_ENABLE (0x1 << 15) +#define DFLL_I2C_CFG_SIZE_SHIFT 12 +#define DFLL_I2C_CFG_SIZE_MASK (0x7 << DFLL_I2C_CFG_SIZE_SHIFT) +#define DFLL_I2C_CFG_SLAVE_ADDR_10 (0x1 << 10) +#define DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_7BIT 1 +#define DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_10BIT 0 + +/* DFLL_I2C_VDD_REG_ADDR: PMIC I2C address for closed loop mode */ +#define DFLL_I2C_VDD_REG_ADDR 0x44 + +/* DFLL_I2C_STS: I2C controller status */ +#define DFLL_I2C_STS 0x48 +#define DFLL_I2C_STS_I2C_LAST_SHIFT 1 +#define DFLL_I2C_STS_I2C_REQ_PENDING 0x1 + +/* DFLL_INTR_STS: DFLL interrupt status register */ +#define DFLL_INTR_STS 0x5c + +/* DFLL_INTR_EN: DFLL interrupt enable register */ +#define DFLL_INTR_EN 0x60 +#define DFLL_INTR_MIN_MASK 0x1 +#define DFLL_INTR_MAX_MASK 0x2 + +/* + * Integrated I2C controller registers - relative to td->i2c_controller_base + */ + +/* DFLL_I2C_CLK_DIVISOR: I2C controller clock divisor */ +#define DFLL_I2C_CLK_DIVISOR 0x6c +#define DFLL_I2C_CLK_DIVISOR_MASK 0xffff +#define DFLL_I2C_CLK_DIVISOR_FS_SHIFT 16 +#define DFLL_I2C_CLK_DIVISOR_HS_SHIFT 0 +#define DFLL_I2C_CLK_DIVISOR_PREDIV 8 +#define DFLL_I2C_CLK_DIVISOR_HSMODE_PREDIV 12 + +/* + * Other constants + */ + +/* MAX_DFLL_VOLTAGES: number of LUT entries in the DFLL IP block */ +#define MAX_DFLL_VOLTAGES 33 + +/* + * REF_CLK_CYC_PER_DVCO_SAMPLE: the number of ref_clk cycles that the hardware + * integrates the DVCO counter over - used for debug rate monitoring and + * droop control + */ +#define REF_CLK_CYC_PER_DVCO_SAMPLE 4 + +/* + * REF_CLOCK_RATE: the DFLL reference clock rate currently supported by this + * driver, in Hz + */ +#define REF_CLOCK_RATE 51000000UL + + +/** + * enum dfll_ctrl_mode - DFLL hardware operating mode + * @DFLL_UNINITIALIZED: (uninitialized state - not in hardware bitfield) + * @DFLL_DISABLED: DFLL not generating an output clock + * @DFLL_OPEN_LOOP: DVCO running, but DFLL not adjusting voltage + * + * The integer corresponding to the last two states, minus one, is + * written to the DFLL hardware to change operating modes. + */ +enum dfll_ctrl_mode { + DFLL_UNINITIALIZED = 0, + DFLL_DISABLED = 1, + DFLL_OPEN_LOOP = 2, +}; + +/** + * enum dfll_tune_range - voltage range that the driver believes it's in + * @DFLL_TUNE_UNINITIALIZED: DFLL tuning not yet programmed + * @DFLL_TUNE_LOW: DFLL in the low-voltage range (or open-loop mode) + * + * Some DFLL tuning parameters may need to change depending on the + * DVCO's voltage; these states represent the ranges that the driver + * supports. These are software states; these values are never + * written into registers. + */ +enum dfll_tune_range { + DFLL_TUNE_UNINITIALIZED = 0, + DFLL_TUNE_LOW = 1, +}; + +struct tegra_dfll { + struct device *dev; + struct tegra_dfll_soc_data *soc; + + void __iomem *base; + void __iomem *i2c_base; + void __iomem *i2c_controller_base; + void __iomem *lut_base; + + struct regulator *vdd_reg; + struct clk *soc_clk; + struct clk *ref_clk; + struct clk *i2c_clk; + struct clk *dfll_clk; + struct reset_control *dvco_rst; + unsigned long ref_rate; + unsigned long i2c_clk_rate; + unsigned long dvco_rate_min; + + enum dfll_ctrl_mode mode; + enum dfll_tune_range tune_range; + struct dentry *debugfs_dir; + struct clk_hw dfll_clk_hw; + const char *output_clock_name; + + /* Parameters from DT */ + u32 droop_ctrl; +}; + +#define clk_hw_to_dfll(_hw) container_of(_hw, struct tegra_dfll, dfll_clk_hw) + +/* mode_name: map numeric DFLL modes to names for friendly console messages */ +static const char * const mode_name[] = { + [DFLL_UNINITIALIZED] = "uninitialized", + [DFLL_DISABLED] = "disabled", + [DFLL_OPEN_LOOP] = "open_loop", +}; + +/* + * Register accessors + */ + +static inline u32 dfll_readl(struct tegra_dfll *td, u32 offs) +{ + return __raw_readl(td->base + offs); +} + +static inline void dfll_writel(struct tegra_dfll *td, u32 val, u32 offs) +{ + WARN_ON(offs >= DFLL_I2C_CFG); + __raw_writel(val, td->base + offs); +} + +static inline void dfll_wmb(struct tegra_dfll *td) +{ + dfll_readl(td, DFLL_CTRL); +} + +/* I2C output control registers - for addresses above DFLL_I2C_CFG */ + +static inline u32 dfll_i2c_readl(struct tegra_dfll *td, u32 offs) +{ + return __raw_readl(td->i2c_base + offs); +} + +static inline void dfll_i2c_writel(struct tegra_dfll *td, u32 val, u32 offs) +{ + __raw_writel(val, td->i2c_base + offs); +} + +static inline void dfll_i2c_wmb(struct tegra_dfll *td) +{ + dfll_i2c_readl(td, DFLL_I2C_CFG); +} + +/** + * dfll_is_running - is the DFLL currently generating a clock? + * @td: DFLL instance + * + * If the DFLL is currently generating an output clock signal, return + * true; otherwise return false. + */ +static bool dfll_is_running(struct tegra_dfll *td) +{ + return td->mode >= DFLL_OPEN_LOOP; +} + +/* + * Runtime PM suspend/resume callbacks + */ + +/** + * tegra_dfll_runtime_resume - enable all clocks needed by the DFLL + * @dev: DFLL device * + * + * Enable all clocks needed by the DFLL. Assumes that clk_prepare() + * has already been called on all the clocks. + * + * XXX Should also handle context restore when returning from off. + */ +int tegra_dfll_runtime_resume(struct device *dev) +{ + struct tegra_dfll *td = dev_get_drvdata(dev); + int ret; + + ret = clk_enable(td->ref_clk); + if (ret) { + dev_err(dev, "could not enable ref clock: %d\n", ret); + return ret; + } + + ret = clk_enable(td->soc_clk); + if (ret) { + dev_err(dev, "could not enable register clock: %d\n", ret); + clk_disable(td->ref_clk); + return ret; + } + + ret = clk_enable(td->i2c_clk); + if (ret) { + dev_err(dev, "could not enable i2c clock: %d\n", ret); + clk_disable(td->soc_clk); + clk_disable(td->ref_clk); + return ret; + } + + return 0; +} +EXPORT_SYMBOL(tegra_dfll_runtime_resume); + +/** + * tegra_dfll_runtime_suspend - disable all clocks needed by the DFLL + * @dev: DFLL device * + * + * Disable all clocks needed by the DFLL. Assumes that other code + * will later call clk_unprepare(). + */ +int tegra_dfll_runtime_suspend(struct device *dev) +{ + struct tegra_dfll *td = dev_get_drvdata(dev); + + clk_disable(td->ref_clk); + clk_disable(td->soc_clk); + clk_disable(td->i2c_clk); + + return 0; +} +EXPORT_SYMBOL(tegra_dfll_runtime_suspend); + +/* + * DFLL tuning operations (per-voltage-range tuning settings) + */ + +/** + * dfll_tune_low - tune to DFLL and CPU settings valid for any voltage + * @td: DFLL instance + * + * Tune the DFLL oscillator parameters and the CPU clock shaper for + * the low-voltage range. These settings are valid for any voltage, + * but may not be optimal. + */ +static void dfll_tune_low(struct tegra_dfll *td) +{ + td->tune_range = DFLL_TUNE_LOW; + + dfll_writel(td, td->soc->tune0_low, DFLL_TUNE0); + dfll_writel(td, td->soc->tune1, DFLL_TUNE1); + dfll_wmb(td); + + if (td->soc->set_clock_trimmers_low) + td->soc->set_clock_trimmers_low(); +} + +/* + * Output clock scaler helpers + */ + +/** + * dfll_scale_dvco_rate - calculate scaled rate from the DVCO rate + * @scale_bits: clock scaler value (bits in the DFLL_FREQ_REQ_SCALE field) + * @dvco_rate: the DVCO rate + * + * Apply the same scaling formula that the DFLL hardware uses to scale + * the DVCO rate. + */ +static unsigned long dfll_scale_dvco_rate(int scale_bits, + unsigned long dvco_rate) +{ + return (u64)dvco_rate * (scale_bits + 1) / DFLL_FREQ_REQ_SCALE_MAX; +} + +/* + * Monitor control + */ + +/** + * dfll_calc_monitored_rate - convert DFLL_MONITOR_DATA_VAL rate into real freq + * @monitor_data: value read from the DFLL_MONITOR_DATA_VAL bitfield + * @ref_rate: DFLL reference clock rate + * + * Convert @monitor_data from DFLL_MONITOR_DATA_VAL units into cycles + * per second. Returns the converted value. + */ +static u64 dfll_calc_monitored_rate(u32 monitor_data, + unsigned long ref_rate) +{ + return monitor_data * (ref_rate / REF_CLK_CYC_PER_DVCO_SAMPLE); +} + +/** + * dfll_read_monitor_rate - return the DFLL's output rate from internal monitor + * @td: DFLL instance + * + * If the DFLL is enabled, return the last rate reported by the DFLL's + * internal monitoring hardware. This works in both open-loop and + * closed-loop mode, and takes the output scaler setting into account. + * Assumes that the monitor was programmed to monitor frequency before + * the sample period started. If the driver believes that the DFLL is + * currently uninitialized or disabled, it will return 0, since + * otherwise the DFLL monitor data register will return the last + * measured rate from when the DFLL was active. + */ +static u64 dfll_read_monitor_rate(struct tegra_dfll *td) +{ + u32 v, s; + u64 pre_scaler_rate, post_scaler_rate; + + if (!dfll_is_running(td)) + return 0; + + v = dfll_readl(td, DFLL_MONITOR_DATA); + v = (v & DFLL_MONITOR_DATA_VAL_MASK) >> DFLL_MONITOR_DATA_VAL_SHIFT; + pre_scaler_rate = dfll_calc_monitored_rate(v, td->ref_rate); + + s = dfll_readl(td, DFLL_FREQ_REQ); + s = (s & DFLL_FREQ_REQ_SCALE_MASK) >> DFLL_FREQ_REQ_SCALE_SHIFT; + post_scaler_rate = dfll_scale_dvco_rate(s, pre_scaler_rate); + + return post_scaler_rate; +} + +/* + * DFLL mode switching + */ + +/** + * dfll_set_mode - change the DFLL control mode + * @td: DFLL instance + * @mode: DFLL control mode (see enum dfll_ctrl_mode) + * + * Change the DFLL's operating mode between disabled, open-loop mode, + * and closed-loop mode, or vice versa. + */ +static void dfll_set_mode(struct tegra_dfll *td, + enum dfll_ctrl_mode mode) +{ + td->mode = mode; + dfll_writel(td, mode - 1, DFLL_CTRL); + dfll_wmb(td); +} + +/* + * DFLL enable/disable & open-loop <-> closed-loop transitions + */ + +/** + * dfll_disable - switch from open-loop mode to disabled mode + * @td: DFLL instance + * + * Switch from OPEN_LOOP state to DISABLED state. Returns 0 upon success + * or -EPERM if the DFLL is not currently in open-loop mode. + */ +static int dfll_disable(struct tegra_dfll *td) +{ + if (td->mode != DFLL_OPEN_LOOP) { + dev_err(td->dev, "cannot disable DFLL in %s mode\n", + mode_name[td->mode]); + return -EINVAL; + } + + dfll_set_mode(td, DFLL_DISABLED); + pm_runtime_put_sync(td->dev); + + return 0; +} + +/** + * dfll_enable - switch a disabled DFLL to open-loop mode + * @td: DFLL instance + * + * Switch from DISABLED state to OPEN_LOOP state. Returns 0 upon success + * or -EPERM if the DFLL is not currently disabled. + */ +static int dfll_enable(struct tegra_dfll *td) +{ + if (td->mode != DFLL_DISABLED) { + dev_err(td->dev, "cannot enable DFLL in %s mode\n", + mode_name[td->mode]); + return -EPERM; + } + + pm_runtime_get_sync(td->dev); + dfll_set_mode(td, DFLL_OPEN_LOOP); + + return 0; +} + +/** + * dfll_set_open_loop_config - prepare to switch to open-loop mode + * @td: DFLL instance + * + * Prepare to switch the DFLL to open-loop mode. This switches the + * DFLL to the low-voltage tuning range, ensures that I2C output + * forcing is disabled, and disables the output clock rate scaler. + * The DFLL's low-voltage tuning range parameters must be + * characterized to keep the downstream device stable at any DVCO + * input voltage. No return value. + */ +static void dfll_set_open_loop_config(struct tegra_dfll *td) +{ + u32 val; + + /* always tune low (safe) in open loop */ + if (td->tune_range != DFLL_TUNE_LOW) + dfll_tune_low(td); + + val = dfll_readl(td, DFLL_FREQ_REQ); + val |= DFLL_FREQ_REQ_SCALE_MASK; + val &= ~DFLL_FREQ_REQ_FORCE_ENABLE; + dfll_writel(td, val, DFLL_FREQ_REQ); + dfll_wmb(td); +} + +/* + * Clock framework integration + */ + +static int dfll_clk_is_enabled(struct clk_hw *hw) +{ + struct tegra_dfll *td = clk_hw_to_dfll(hw); + + return dfll_is_running(td); +} + +static int dfll_clk_enable(struct clk_hw *hw) +{ + struct tegra_dfll *td = clk_hw_to_dfll(hw); + + return dfll_enable(td); +} + +static void dfll_clk_disable(struct clk_hw *hw) +{ + struct tegra_dfll *td = clk_hw_to_dfll(hw); + + dfll_disable(td); +} + +static const struct clk_ops dfll_clk_ops = { + .is_enabled = dfll_clk_is_enabled, + .enable = dfll_clk_enable, + .disable = dfll_clk_disable, +}; + +static struct clk_init_data dfll_clk_init_data = { + .flags = CLK_IS_ROOT, + .ops = &dfll_clk_ops, + .num_parents = 0, +}; + +/** + * dfll_register_clk - register the DFLL output clock with the clock framework + * @td: DFLL instance + * + * Register the DFLL's output clock with the Linux clock framework and register + * the DFLL driver as an OF clock provider. Returns 0 upon success or -EINVAL + * or -ENOMEM upon failure. + */ +static int dfll_register_clk(struct tegra_dfll *td) +{ + int ret; + + dfll_clk_init_data.name = td->output_clock_name; + td->dfll_clk_hw.init = &dfll_clk_init_data; + + td->dfll_clk = clk_register(td->dev, &td->dfll_clk_hw); + if (IS_ERR(td->dfll_clk)) { + dev_err(td->dev, "DFLL clock registration error\n"); + return -EINVAL; + } + + ret = of_clk_add_provider(td->dev->of_node, of_clk_src_simple_get, + td->dfll_clk); + if (ret) { + dev_err(td->dev, "of_clk_add_provider() failed\n"); + + clk_unregister(td->dfll_clk); + return ret; + } + + return 0; +} + +/** + * dfll_unregister_clk - unregister the DFLL output clock + * @td: DFLL instance + * + * Unregister the DFLL's output clock from the Linux clock framework + * and from clkdev. No return value. + */ +static void dfll_unregister_clk(struct tegra_dfll *td) +{ + of_clk_del_provider(td->dev->of_node); + clk_unregister(td->dfll_clk); + td->dfll_clk = NULL; +} + +/* + * Debugfs interface + */ + +#ifdef CONFIG_DEBUG_FS + +static int attr_enable_get(void *data, u64 *val) +{ + struct tegra_dfll *td = data; + + *val = dfll_is_running(td); + + return 0; +} +static int attr_enable_set(void *data, u64 val) +{ + struct tegra_dfll *td = data; + + return val ? dfll_enable(td) : dfll_disable(td); +} +DEFINE_SIMPLE_ATTRIBUTE(enable_fops, attr_enable_get, attr_enable_set, + "%llu\n"); + +static int attr_rate_get(void *data, u64 *val) +{ + struct tegra_dfll *td = data; + + *val = dfll_read_monitor_rate(td); + + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(rate_fops, attr_rate_get, NULL, "%llu\n"); + +static int attr_registers_show(struct seq_file *s, void *data) +{ + u32 val, offs; + struct tegra_dfll *td = s->private; + + seq_puts(s, "CONTROL REGISTERS:\n"); + for (offs = 0; offs <= DFLL_MONITOR_DATA; offs += 4) { + if (offs == DFLL_OUTPUT_CFG) + val = dfll_i2c_readl(td, offs); + else + val = dfll_readl(td, offs); + seq_printf(s, "[0x%02x] = 0x%08x\n", offs, val); + } + + seq_puts(s, "\nI2C and INTR REGISTERS:\n"); + for (offs = DFLL_I2C_CFG; offs <= DFLL_I2C_STS; offs += 4) + seq_printf(s, "[0x%02x] = 0x%08x\n", offs, + dfll_i2c_readl(td, offs)); + for (offs = DFLL_INTR_STS; offs <= DFLL_INTR_EN; offs += 4) + seq_printf(s, "[0x%02x] = 0x%08x\n", offs, + dfll_i2c_readl(td, offs)); + + seq_puts(s, "\nINTEGRATED I2C CONTROLLER REGISTERS:\n"); + offs = DFLL_I2C_CLK_DIVISOR; + seq_printf(s, "[0x%02x] = 0x%08x\n", offs, + __raw_readl(td->i2c_controller_base + offs)); + + seq_puts(s, "\nLUT:\n"); + for (offs = 0; offs < 4 * MAX_DFLL_VOLTAGES; offs += 4) + seq_printf(s, "[0x%02x] = 0x%08x\n", offs, + __raw_readl(td->lut_base + offs)); + + return 0; +} + +static int attr_registers_open(struct inode *inode, struct file *file) +{ + return single_open(file, attr_registers_show, inode->i_private); +} + +static const struct file_operations attr_registers_fops = { + .open = attr_registers_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int dfll_debug_init(struct tegra_dfll *td) +{ + int ret; + + if (!td || (td->mode == DFLL_UNINITIALIZED)) + return 0; + + td->debugfs_dir = debugfs_create_dir("tegra_dfll_fcpu", NULL); + if (!td->debugfs_dir) + return -ENOMEM; + + ret = -ENOMEM; + + if (!debugfs_create_file("enable", S_IRUGO | S_IWUSR, + td->debugfs_dir, td, &enable_fops)) + goto err_out; + + if (!debugfs_create_file("rate", S_IRUGO, + td->debugfs_dir, td, &rate_fops)) + goto err_out; + + if (!debugfs_create_file("registers", S_IRUGO, + td->debugfs_dir, td, &attr_registers_fops)) + goto err_out; + + return 0; + +err_out: + debugfs_remove_recursive(td->debugfs_dir); + return ret; +} + +#endif /* CONFIG_DEBUG_FS */ + +/* + * DFLL initialization + */ + +/** + * dfll_set_default_params - program non-output related DFLL parameters + * @td: DFLL instance + * + * During DFLL driver initialization or resume from context loss, + * program parameters for the closed loop integrator, DVCO tuning, + * voltage droop control and monitor control. + */ +static void dfll_set_default_params(struct tegra_dfll *td) +{ + dfll_tune_low(td); + dfll_writel(td, td->droop_ctrl, DFLL_DROOP_CTRL); + dfll_writel(td, DFLL_MONITOR_CTRL_FREQ, DFLL_MONITOR_CTRL); +} + +/** + * dfll_init_clks - clk_get() the DFLL source clocks + * @td: DFLL instance + * + * Call clk_get() on the DFLL source clocks and save the pointers for later + * use. Returns 0 upon success or error (see devm_clk_get) if one or more + * of the clocks couldn't be looked up. + */ +static int dfll_init_clks(struct tegra_dfll *td) +{ + td->ref_clk = devm_clk_get(td->dev, "ref"); + if (IS_ERR(td->ref_clk)) { + dev_err(td->dev, "missing ref clock\n"); + return PTR_ERR(td->ref_clk); + } + + td->soc_clk = devm_clk_get(td->dev, "soc"); + if (IS_ERR(td->soc_clk)) { + dev_err(td->dev, "missing soc clock\n"); + return PTR_ERR(td->soc_clk); + } + + td->i2c_clk = devm_clk_get(td->dev, "i2c"); + if (IS_ERR(td->i2c_clk)) { + dev_err(td->dev, "missing i2c clock\n"); + return PTR_ERR(td->i2c_clk); + } + td->i2c_clk_rate = clk_get_rate(td->i2c_clk); + + return 0; +} + +/** + * dfll_init - Prepare the DFLL IP block for use + * @td: DFLL instance + * + * Do everything necessary to prepare the DFLL IP block for use. The + * DFLL will be left in DISABLED state. Called by dfll_probe(). + * Returns 0 upon success, or passes along the error from whatever + * function returned it. + */ +static int dfll_init(struct tegra_dfll *td) +{ + int ret; + + td->ref_rate = clk_get_rate(td->ref_clk); + if (td->ref_rate != REF_CLOCK_RATE) { + dev_err(td->dev, "unexpected ref clk rate %lu, expecting %lu", + td->ref_rate, REF_CLOCK_RATE); + return -EINVAL; + } + + reset_control_deassert(td->dvco_rst); + + ret = clk_prepare(td->ref_clk); + if (ret) { + dev_err(td->dev, "failed to prepare ref_clk\n"); + return ret; + } + + ret = clk_prepare(td->soc_clk); + if (ret) { + dev_err(td->dev, "failed to prepare soc_clk\n"); + goto di_err1; + } + + ret = clk_prepare(td->i2c_clk); + if (ret) { + dev_err(td->dev, "failed to prepare i2c_clk\n"); + goto di_err2; + } + + pm_runtime_enable(td->dev); + pm_runtime_get_sync(td->dev); + + dfll_set_mode(td, DFLL_DISABLED); + dfll_set_default_params(td); + + if (td->soc->init_clock_trimmers) + td->soc->init_clock_trimmers(); + + dfll_set_open_loop_config(td); + + pm_runtime_put_sync(td->dev); + + return 0; + +di_err2: + clk_unprepare(td->soc_clk); +di_err1: + clk_unprepare(td->ref_clk); + + reset_control_assert(td->dvco_rst); + + return ret; +} + +/* + * DT data fetch + */ + +/** + * read_dt_param - helper function for reading required parameters from the DT + * @td: DFLL instance + * @param: DT property name + * @dest: output pointer for the value read + * + * Read a required numeric parameter from the DFLL device node, or complain + * if the property doesn't exist. Returns a boolean indicating success for + * easy chaining of multiple calls to this function. + */ +static bool read_dt_param(struct tegra_dfll *td, const char *param, u32 *dest) +{ + int err = of_property_read_u32(td->dev->of_node, param, dest); + + if (err < 0) { + dev_err(td->dev, "failed to read DT parameter %s: %d\n", + param, err); + return false; + } + + return true; +} + +/** + * dfll_fetch_common_params - read DFLL parameters from the device tree + * @td: DFLL instance + * + * Read all the DT parameters that are common to both I2C and PWM operation. + * Returns 0 on success or -EINVAL on any failure. + */ +static int dfll_fetch_common_params(struct tegra_dfll *td) +{ + bool ok = true; + + ok &= read_dt_param(td, "nvidia,droop-ctrl", &td->droop_ctrl); + + if (of_property_read_string(td->dev->of_node, "clock-output-names", + &td->output_clock_name)) { + dev_err(td->dev, "missing clock-output-names property\n"); + ok = false; + } + + return ok ? 0 : -EINVAL; +} + +/* + * API exported to per-SoC platform drivers + */ + +/** + * tegra_dfll_register - probe a Tegra DFLL device + * @pdev: DFLL platform_device * + * @soc: Per-SoC integration and characterization data for this DFLL instance + * + * Probe and initialize a DFLL device instance. Intended to be called + * by a SoC-specific shim driver that passes in per-SoC integration + * and configuration data via @soc. Returns 0 on success or -err on failure. + */ +int tegra_dfll_register(struct platform_device *pdev, + struct tegra_dfll_soc_data *soc) +{ + struct resource *mem; + struct tegra_dfll *td; + int ret; + + if (!soc) { + dev_err(&pdev->dev, "no tegra_dfll_soc_data provided\n"); + return -EINVAL; + } + + td = devm_kzalloc(&pdev->dev, sizeof(*td), GFP_KERNEL); + if (!td) + return -ENOMEM; + td->dev = &pdev->dev; + platform_set_drvdata(pdev, td); + + td->soc = soc; + + td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu"); + if (IS_ERR(td->vdd_reg)) { + dev_err(td->dev, "couldn't get vdd_cpu regulator\n"); + return PTR_ERR(td->vdd_reg); + } + + td->dvco_rst = devm_reset_control_get(td->dev, "dvco"); + if (IS_ERR(td->dvco_rst)) { + dev_err(td->dev, "couldn't get dvco reset\n"); + return PTR_ERR(td->dvco_rst); + } + + ret = dfll_fetch_common_params(td); + if (ret) { + dev_err(td->dev, "couldn't parse device tree parameters\n"); + return ret; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(td->dev, "no control register resource\n"); + return -ENODEV; + } + + td->base = devm_ioremap(td->dev, mem->start, resource_size(mem)); + if (!td->base) { + dev_err(td->dev, "couldn't ioremap DFLL control registers\n"); + return -ENODEV; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!mem) { + dev_err(td->dev, "no i2c_base resource\n"); + return -ENODEV; + } + + td->i2c_base = devm_ioremap(td->dev, mem->start, resource_size(mem)); + if (!td->i2c_base) { + dev_err(td->dev, "couldn't ioremap i2c_base resource\n"); + return -ENODEV; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 2); + if (!mem) { + dev_err(td->dev, "no i2c_controller_base resource\n"); + return -ENODEV; + } + + td->i2c_controller_base = devm_ioremap(td->dev, mem->start, + resource_size(mem)); + if (!td->i2c_controller_base) { + dev_err(td->dev, + "couldn't ioremap i2c_controller_base resource\n"); + return -ENODEV; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 3); + if (!mem) { + dev_err(td->dev, "no lut_base resource\n"); + return -ENODEV; + } + + td->lut_base = devm_ioremap(td->dev, mem->start, resource_size(mem)); + if (!td->lut_base) { + dev_err(td->dev, + "couldn't ioremap lut_base resource\n"); + return -ENODEV; + } + + ret = dfll_init_clks(td); + if (ret) { + dev_err(&pdev->dev, "DFLL clock init error\n"); + return ret; + } + + /* Enable the clocks and set the device up */ + ret = dfll_init(td); + if (ret) + return ret; + + ret = dfll_register_clk(td); + if (ret) { + dev_err(&pdev->dev, "DFLL clk registration failed\n"); + return ret; + } + +#ifdef CONFIG_DEBUG_FS + dfll_debug_init(td); +#endif + + return 0; +} +EXPORT_SYMBOL(tegra_dfll_register); + +/** + * tegra_dfll_unregister - release all of the DFLL driver resources for a device + * @pdev: DFLL platform_device * + * + * Unbind this driver from the DFLL hardware device represented by + * @pdev. The DFLL must be disabled for this to succeed. Returns 0 + * upon success or -EBUSY if the DFLL is still active. + */ +int tegra_dfll_unregister(struct platform_device *pdev) +{ + struct tegra_dfll *td = platform_get_drvdata(pdev); + + /* Try to prevent removal while the DFLL is active */ + if (td->mode != DFLL_DISABLED) { + dev_err(&pdev->dev, + "must disable DFLL before removing driver\n"); + return -EBUSY; + } + + debugfs_remove_recursive(td->debugfs_dir); + + dfll_unregister_clk(td); + pm_runtime_disable(&pdev->dev); + + clk_unprepare(td->ref_clk); + clk_unprepare(td->soc_clk); + clk_unprepare(td->i2c_clk); + + reset_control_assert(td->dvco_rst); + + return 0; +} +EXPORT_SYMBOL(tegra_dfll_unregister); diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h new file mode 100644 index 000000000000..b5d1fd47684e --- /dev/null +++ b/drivers/clk/tegra/clk-dfll.h @@ -0,0 +1,54 @@ +/* + * clk-dfll.h - prototypes and macros for the Tegra DFLL clocksource driver + * Copyright (C) 2013 NVIDIA Corporation. All rights reserved. + * + * Aleksandr Frid + * Paul Walmsley + * + * 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 __DRIVERS_CLK_TEGRA_CLK_DFLL_H +#define __DRIVERS_CLK_TEGRA_CLK_DFLL_H + +#include +#include +#include + +/** + * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver + * @opp_dev: struct device * that holds the OPP table for the DFLL + * @min_millivolts: minimum voltage (in mV) that the DFLL can operate + * @tune0_low: DFLL tuning register 0 (low voltage range) + * @tune0_high: DFLL tuning register 0 (high voltage range) + * @tune1: DFLL tuning register 1 + * @assert_dvco_reset: fn ptr to place the DVCO in reset + * @deassert_dvco_reset: fn ptr to release the DVCO reset + * @set_clock_trimmers_high: fn ptr to tune clock trimmers for high voltage + * @set_clock_trimmers_low: fn ptr to tune clock trimmers for low voltage + */ +struct tegra_dfll_soc_data { + struct device *opp_dev; + unsigned int min_millivolts; + u32 tune0_low; + u32 tune0_high; + u32 tune1; + void (*init_clock_trimmers)(void); + void (*set_clock_trimmers_high)(void); + void (*set_clock_trimmers_low)(void); +}; + +int tegra_dfll_register(struct platform_device *pdev, + struct tegra_dfll_soc_data *soc); +int tegra_dfll_unregister(struct platform_device *pdev); +int tegra_dfll_runtime_suspend(struct device *dev); +int tegra_dfll_runtime_resume(struct device *dev); + +#endif /* __DRIVERS_CLK_TEGRA_CLK_DFLL_H */ -- cgit v1.3-6-gb490 From c4fe70ada40f53e8cd5e6f8d9a2433781e935835 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Wed, 13 May 2015 17:58:37 +0300 Subject: clk: tegra: Add closed loop support for the DFLL With closed loop support, the clock rate of the DFLL can be adjusted. The oscillator itself in the DFLL is a free-running oscillator whose rate is directly determined the supply voltage. However, the DFLL module contains logic to compare the DFLL output rate to a fixed reference clock (51 MHz) and make a decision to either lower or raise the DFLL supply voltage. The DFLL module can then autonomously change the supply voltage by communicating with an off-chip PMIC via either I2C or PWM signals. This driver currently supports only I2C. Signed-off-by: Tuomas Tynkkynen Signed-off-by: Mikko Perttunen Acked-by: Peter De Schrijver Acked-by: Michael Turquette Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-dfll.c | 666 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 663 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index fb138bfa0af2..6ec645776897 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -206,12 +206,16 @@ */ #define REF_CLOCK_RATE 51000000UL +#define DVCO_RATE_TO_MULT(rate, ref_rate) ((rate) / ((ref_rate) / 2)) +#define MULT_TO_DVCO_RATE(mult, ref_rate) ((mult) * ((ref_rate) / 2)) /** * enum dfll_ctrl_mode - DFLL hardware operating mode * @DFLL_UNINITIALIZED: (uninitialized state - not in hardware bitfield) * @DFLL_DISABLED: DFLL not generating an output clock * @DFLL_OPEN_LOOP: DVCO running, but DFLL not adjusting voltage + * @DFLL_CLOSED_LOOP: DVCO running, and DFLL adjusting voltage to match + * the requested rate * * The integer corresponding to the last two states, minus one, is * written to the DFLL hardware to change operating modes. @@ -220,6 +224,7 @@ enum dfll_ctrl_mode { DFLL_UNINITIALIZED = 0, DFLL_DISABLED = 1, DFLL_OPEN_LOOP = 2, + DFLL_CLOSED_LOOP = 3, }; /** @@ -237,6 +242,22 @@ enum dfll_tune_range { DFLL_TUNE_LOW = 1, }; +/** + * struct dfll_rate_req - target DFLL rate request data + * @rate: target frequency, after the postscaling + * @dvco_target_rate: target frequency, after the postscaling + * @lut_index: LUT index at which voltage the dvco_target_rate will be reached + * @mult_bits: value to program to the MULT bits of the DFLL_FREQ_REQ register + * @scale_bits: value to program to the SCALE bits of the DFLL_FREQ_REQ register + */ +struct dfll_rate_req { + unsigned long rate; + unsigned long dvco_target_rate; + int lut_index; + u8 mult_bits; + u8 scale_bits; +}; + struct tegra_dfll { struct device *dev; struct tegra_dfll_soc_data *soc; @@ -261,9 +282,27 @@ struct tegra_dfll { struct dentry *debugfs_dir; struct clk_hw dfll_clk_hw; const char *output_clock_name; + struct dfll_rate_req last_req; + unsigned long last_unrounded_rate; /* Parameters from DT */ u32 droop_ctrl; + u32 sample_rate; + u32 force_mode; + u32 cf; + u32 ci; + u32 cg; + bool cg_scale; + + /* I2C interface parameters */ + u32 i2c_fs_rate; + u32 i2c_reg; + u32 i2c_slave_addr; + + /* i2c_lut array entries are regulator framework selectors */ + unsigned i2c_lut[MAX_DFLL_VOLTAGES]; + int i2c_lut_size; + u8 lut_min, lut_max, lut_safe; }; #define clk_hw_to_dfll(_hw) container_of(_hw, struct tegra_dfll, dfll_clk_hw) @@ -273,6 +312,7 @@ static const char * const mode_name[] = { [DFLL_UNINITIALIZED] = "uninitialized", [DFLL_DISABLED] = "disabled", [DFLL_OPEN_LOOP] = "open_loop", + [DFLL_CLOSED_LOOP] = "closed_loop", }; /* @@ -498,6 +538,283 @@ static void dfll_set_mode(struct tegra_dfll *td, dfll_wmb(td); } +/* + * DFLL-to-I2C controller interface + */ + +/** + * dfll_i2c_set_output_enabled - enable/disable I2C PMIC voltage requests + * @td: DFLL instance + * @enable: whether to enable or disable the I2C voltage requests + * + * Set the master enable control for I2C control value updates. If disabled, + * then I2C control messages are inhibited, regardless of the DFLL mode. + */ +static int dfll_i2c_set_output_enabled(struct tegra_dfll *td, bool enable) +{ + u32 val; + + val = dfll_i2c_readl(td, DFLL_OUTPUT_CFG); + + if (enable) + val |= DFLL_OUTPUT_CFG_I2C_ENABLE; + else + val &= ~DFLL_OUTPUT_CFG_I2C_ENABLE; + + dfll_i2c_writel(td, val, DFLL_OUTPUT_CFG); + dfll_i2c_wmb(td); + + return 0; +} + +/** + * dfll_load_lut - load the voltage lookup table + * @td: struct tegra_dfll * + * + * Load the voltage-to-PMIC register value lookup table into the DFLL + * IP block memory. Look-up tables can be loaded at any time. + */ +static void dfll_load_i2c_lut(struct tegra_dfll *td) +{ + int i, lut_index; + u32 val; + + for (i = 0; i < MAX_DFLL_VOLTAGES; i++) { + if (i < td->lut_min) + lut_index = td->lut_min; + else if (i > td->lut_max) + lut_index = td->lut_max; + else + lut_index = i; + + val = regulator_list_hardware_vsel(td->vdd_reg, + td->i2c_lut[lut_index]); + __raw_writel(val, td->lut_base + i * 4); + } + + dfll_i2c_wmb(td); +} + +/** + * dfll_init_i2c_if - set up the DFLL's DFLL-I2C interface + * @td: DFLL instance + * + * During DFLL driver initialization, program the DFLL-I2C interface + * with the PMU slave address, vdd register offset, and transfer mode. + * This data is used by the DFLL to automatically construct I2C + * voltage-set commands, which are then passed to the DFLL's internal + * I2C controller. + */ +static void dfll_init_i2c_if(struct tegra_dfll *td) +{ + u32 val; + + if (td->i2c_slave_addr > 0x7f) { + val = td->i2c_slave_addr << DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_10BIT; + val |= DFLL_I2C_CFG_SLAVE_ADDR_10; + } else { + val = td->i2c_slave_addr << DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_7BIT; + } + val |= DFLL_I2C_CFG_SIZE_MASK; + val |= DFLL_I2C_CFG_ARB_ENABLE; + dfll_i2c_writel(td, val, DFLL_I2C_CFG); + + dfll_i2c_writel(td, td->i2c_reg, DFLL_I2C_VDD_REG_ADDR); + + val = DIV_ROUND_UP(td->i2c_clk_rate, td->i2c_fs_rate * 8); + BUG_ON(!val || (val > DFLL_I2C_CLK_DIVISOR_MASK)); + val = (val - 1) << DFLL_I2C_CLK_DIVISOR_FS_SHIFT; + + /* default hs divisor just in case */ + val |= 1 << DFLL_I2C_CLK_DIVISOR_HS_SHIFT; + __raw_writel(val, td->i2c_controller_base + DFLL_I2C_CLK_DIVISOR); + dfll_i2c_wmb(td); +} + +/** + * dfll_init_out_if - prepare DFLL-to-PMIC interface + * @td: DFLL instance + * + * During DFLL driver initialization or resume from context loss, + * disable the I2C command output to the PMIC, set safe voltage and + * output limits, and disable and clear limit interrupts. + */ +static void dfll_init_out_if(struct tegra_dfll *td) +{ + u32 val; + + td->lut_min = 0; + td->lut_max = td->i2c_lut_size - 1; + td->lut_safe = td->lut_min + 1; + + dfll_i2c_writel(td, 0, DFLL_OUTPUT_CFG); + val = (td->lut_safe << DFLL_OUTPUT_CFG_SAFE_SHIFT) | + (td->lut_max << DFLL_OUTPUT_CFG_MAX_SHIFT) | + (td->lut_min << DFLL_OUTPUT_CFG_MIN_SHIFT); + dfll_i2c_writel(td, val, DFLL_OUTPUT_CFG); + dfll_i2c_wmb(td); + + dfll_writel(td, 0, DFLL_OUTPUT_FORCE); + dfll_i2c_writel(td, 0, DFLL_INTR_EN); + dfll_i2c_writel(td, DFLL_INTR_MAX_MASK | DFLL_INTR_MIN_MASK, + DFLL_INTR_STS); + + dfll_load_i2c_lut(td); + dfll_init_i2c_if(td); +} + +/* + * Set/get the DFLL's targeted output clock rate + */ + +/** + * find_lut_index_for_rate - determine I2C LUT index for given DFLL rate + * @td: DFLL instance + * @rate: clock rate + * + * Determines the index of a I2C LUT entry for a voltage that approximately + * produces the given DFLL clock rate. This is used when forcing a value + * to the integrator during rate changes. Returns -ENOENT if a suitable + * LUT index is not found. + */ +static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate) +{ + struct dev_pm_opp *opp; + int i, uv; + + opp = dev_pm_opp_find_freq_ceil(td->soc->opp_dev, &rate); + if (IS_ERR(opp)) + return PTR_ERR(opp); + uv = dev_pm_opp_get_voltage(opp); + + for (i = 0; i < td->i2c_lut_size; i++) { + if (regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) == uv) + return i; + } + + return -ENOENT; +} + +/** + * dfll_calculate_rate_request - calculate DFLL parameters for a given rate + * @td: DFLL instance + * @req: DFLL-rate-request structure + * @rate: the desired DFLL rate + * + * Populate the DFLL-rate-request record @req fields with the scale_bits + * and mult_bits fields, based on the target input rate. Returns 0 upon + * success, or -EINVAL if the requested rate in req->rate is too high + * or low for the DFLL to generate. + */ +static int dfll_calculate_rate_request(struct tegra_dfll *td, + struct dfll_rate_req *req, + unsigned long rate) +{ + u32 val; + + /* + * If requested rate is below the minimum DVCO rate, active the scaler. + * In the future the DVCO minimum voltage should be selected based on + * chip temperature and the actual minimum rate should be calibrated + * at runtime. + */ + req->scale_bits = DFLL_FREQ_REQ_SCALE_MAX - 1; + if (rate < td->dvco_rate_min) { + int scale; + + scale = DIV_ROUND_CLOSEST(rate / 1000 * DFLL_FREQ_REQ_SCALE_MAX, + td->dvco_rate_min / 1000); + if (!scale) { + dev_err(td->dev, "%s: Rate %lu is too low\n", + __func__, rate); + return -EINVAL; + } + req->scale_bits = scale - 1; + rate = td->dvco_rate_min; + } + + /* Convert requested rate into frequency request and scale settings */ + val = DVCO_RATE_TO_MULT(rate, td->ref_rate); + if (val > FREQ_MAX) { + dev_err(td->dev, "%s: Rate %lu is above dfll range\n", + __func__, rate); + return -EINVAL; + } + req->mult_bits = val; + req->dvco_target_rate = MULT_TO_DVCO_RATE(req->mult_bits, td->ref_rate); + req->rate = dfll_scale_dvco_rate(req->scale_bits, + req->dvco_target_rate); + req->lut_index = find_lut_index_for_rate(td, req->dvco_target_rate); + if (req->lut_index < 0) + return req->lut_index; + + return 0; +} + +/** + * dfll_set_frequency_request - start the frequency change operation + * @td: DFLL instance + * @req: rate request structure + * + * Tell the DFLL to try to change its output frequency to the + * frequency represented by @req. DFLL must be in closed-loop mode. + */ +static void dfll_set_frequency_request(struct tegra_dfll *td, + struct dfll_rate_req *req) +{ + u32 val = 0; + int force_val; + int coef = 128; /* FIXME: td->cg_scale? */; + + force_val = (req->lut_index - td->lut_safe) * coef / td->cg; + force_val = clamp(force_val, FORCE_MIN, FORCE_MAX); + + val |= req->mult_bits << DFLL_FREQ_REQ_MULT_SHIFT; + val |= req->scale_bits << DFLL_FREQ_REQ_SCALE_SHIFT; + val |= ((u32)force_val << DFLL_FREQ_REQ_FORCE_SHIFT) & + DFLL_FREQ_REQ_FORCE_MASK; + val |= DFLL_FREQ_REQ_FREQ_VALID | DFLL_FREQ_REQ_FORCE_ENABLE; + + dfll_writel(td, val, DFLL_FREQ_REQ); + dfll_wmb(td); +} + +/** + * tegra_dfll_request_rate - set the next rate for the DFLL to tune to + * @td: DFLL instance + * @rate: clock rate to target + * + * Convert the requested clock rate @rate into the DFLL control logic + * settings. In closed-loop mode, update new settings immediately to + * adjust DFLL output rate accordingly. Otherwise, just save them + * until the next switch to closed loop. Returns 0 upon success, + * -EPERM if the DFLL driver has not yet been initialized, or -EINVAL + * if @rate is outside the DFLL's tunable range. + */ +static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate) +{ + int ret; + struct dfll_rate_req req; + + if (td->mode == DFLL_UNINITIALIZED) { + dev_err(td->dev, "%s: Cannot set DFLL rate in %s mode\n", + __func__, mode_name[td->mode]); + return -EPERM; + } + + ret = dfll_calculate_rate_request(td, &req, rate); + if (ret) + return ret; + + td->last_unrounded_rate = rate; + td->last_req = req; + + if (td->mode == DFLL_CLOSED_LOOP) + dfll_set_frequency_request(td, &td->last_req); + + return 0; +} + /* * DFLL enable/disable & open-loop <-> closed-loop transitions */ @@ -570,8 +887,76 @@ static void dfll_set_open_loop_config(struct tegra_dfll *td) dfll_wmb(td); } +/** + * tegra_dfll_lock - switch from open-loop to closed-loop mode + * @td: DFLL instance + * + * Switch from OPEN_LOOP state to CLOSED_LOOP state. Returns 0 upon success, + * -EINVAL if the DFLL's target rate hasn't been set yet, or -EPERM if the + * DFLL is not currently in open-loop mode. + */ +static int dfll_lock(struct tegra_dfll *td) +{ + struct dfll_rate_req *req = &td->last_req; + + switch (td->mode) { + case DFLL_CLOSED_LOOP: + return 0; + + case DFLL_OPEN_LOOP: + if (req->rate == 0) { + dev_err(td->dev, "%s: Cannot lock DFLL at rate 0\n", + __func__); + return -EINVAL; + } + + dfll_i2c_set_output_enabled(td, true); + dfll_set_mode(td, DFLL_CLOSED_LOOP); + dfll_set_frequency_request(td, req); + return 0; + + default: + BUG_ON(td->mode > DFLL_CLOSED_LOOP); + dev_err(td->dev, "%s: Cannot lock DFLL in %s mode\n", + __func__, mode_name[td->mode]); + return -EPERM; + } +} + +/** + * tegra_dfll_unlock - switch from closed-loop to open-loop mode + * @td: DFLL instance + * + * Switch from CLOSED_LOOP state to OPEN_LOOP state. Returns 0 upon success, + * or -EPERM if the DFLL is not currently in open-loop mode. + */ +static int dfll_unlock(struct tegra_dfll *td) +{ + switch (td->mode) { + case DFLL_CLOSED_LOOP: + dfll_set_open_loop_config(td); + dfll_set_mode(td, DFLL_OPEN_LOOP); + dfll_i2c_set_output_enabled(td, false); + return 0; + + case DFLL_OPEN_LOOP: + return 0; + + default: + BUG_ON(td->mode > DFLL_CLOSED_LOOP); + dev_err(td->dev, "%s: Cannot unlock DFLL in %s mode\n", + __func__, mode_name[td->mode]); + return -EPERM; + } +} + /* * Clock framework integration + * + * When the DFLL is being controlled by the CCF, always enter closed loop + * mode when the clk is enabled. This requires that a DFLL rate request + * has been set beforehand, which implies that a clk_set_rate() call is + * always required before a clk_enable(). */ static int dfll_clk_is_enabled(struct clk_hw *hw) @@ -584,21 +969,72 @@ static int dfll_clk_is_enabled(struct clk_hw *hw) static int dfll_clk_enable(struct clk_hw *hw) { struct tegra_dfll *td = clk_hw_to_dfll(hw); + int ret; + + ret = dfll_enable(td); + if (ret) + return ret; + + ret = dfll_lock(td); + if (ret) + dfll_disable(td); - return dfll_enable(td); + return ret; } static void dfll_clk_disable(struct clk_hw *hw) +{ + struct tegra_dfll *td = clk_hw_to_dfll(hw); + int ret; + + ret = dfll_unlock(td); + if (!ret) + dfll_disable(td); +} + +static unsigned long dfll_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { struct tegra_dfll *td = clk_hw_to_dfll(hw); - dfll_disable(td); + return td->last_unrounded_rate; +} + +static long dfll_clk_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate) +{ + struct tegra_dfll *td = clk_hw_to_dfll(hw); + struct dfll_rate_req req; + int ret; + + ret = dfll_calculate_rate_request(td, &req, rate); + if (ret) + return ret; + + /* + * Don't return the rounded rate, since it doesn't really matter as + * the output rate will be voltage controlled anyway, and cpufreq + * freaks out if any rounding happens. + */ + return rate; +} + +static int dfll_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tegra_dfll *td = clk_hw_to_dfll(hw); + + return dfll_request_rate(td, rate); } static const struct clk_ops dfll_clk_ops = { .is_enabled = dfll_clk_is_enabled, .enable = dfll_clk_enable, .disable = dfll_clk_disable, + .recalc_rate = dfll_clk_recalc_rate, + .round_rate = dfll_clk_round_rate, + .set_rate = dfll_clk_set_rate, }; static struct clk_init_data dfll_clk_init_data = { @@ -677,6 +1113,23 @@ static int attr_enable_set(void *data, u64 val) DEFINE_SIMPLE_ATTRIBUTE(enable_fops, attr_enable_get, attr_enable_set, "%llu\n"); +static int attr_lock_get(void *data, u64 *val) +{ + struct tegra_dfll *td = data; + + *val = (td->mode == DFLL_CLOSED_LOOP); + + return 0; +} +static int attr_lock_set(void *data, u64 val) +{ + struct tegra_dfll *td = data; + + return val ? dfll_lock(td) : dfll_unlock(td); +} +DEFINE_SIMPLE_ATTRIBUTE(lock_fops, attr_lock_get, attr_lock_set, + "%llu\n"); + static int attr_rate_get(void *data, u64 *val) { struct tegra_dfll *td = data; @@ -685,7 +1138,14 @@ static int attr_rate_get(void *data, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(rate_fops, attr_rate_get, NULL, "%llu\n"); + +static int attr_rate_set(void *data, u64 val) +{ + struct tegra_dfll *td = data; + + return dfll_request_rate(td, val); +} +DEFINE_SIMPLE_ATTRIBUTE(rate_fops, attr_rate_get, attr_rate_set, "%llu\n"); static int attr_registers_show(struct seq_file *s, void *data) { @@ -751,6 +1211,10 @@ static int dfll_debug_init(struct tegra_dfll *td) td->debugfs_dir, td, &enable_fops)) goto err_out; + if (!debugfs_create_file("lock", S_IRUGO, + td->debugfs_dir, td, &lock_fops)) + goto err_out; + if (!debugfs_create_file("rate", S_IRUGO, td->debugfs_dir, td, &rate_fops)) goto err_out; @@ -782,6 +1246,19 @@ err_out: */ static void dfll_set_default_params(struct tegra_dfll *td) { + u32 val; + + val = DIV_ROUND_UP(td->ref_rate, td->sample_rate * 32); + BUG_ON(val > DFLL_CONFIG_DIV_MASK); + dfll_writel(td, val, DFLL_CONFIG); + + val = (td->force_mode << DFLL_PARAMS_FORCE_MODE_SHIFT) | + (td->cf << DFLL_PARAMS_CF_PARAM_SHIFT) | + (td->ci << DFLL_PARAMS_CI_PARAM_SHIFT) | + (td->cg << DFLL_PARAMS_CG_PARAM_SHIFT) | + (td->cg_scale ? DFLL_PARAMS_CG_SCALE : 0); + dfll_writel(td, val, DFLL_PARAMS); + dfll_tune_low(td); dfll_writel(td, td->droop_ctrl, DFLL_DROOP_CTRL); dfll_writel(td, DFLL_MONITOR_CTRL_FREQ, DFLL_MONITOR_CTRL); @@ -859,6 +1336,8 @@ static int dfll_init(struct tegra_dfll *td) goto di_err2; } + td->last_unrounded_rate = 0; + pm_runtime_enable(td->dev); pm_runtime_get_sync(td->dev); @@ -870,6 +1349,8 @@ static int dfll_init(struct tegra_dfll *td) dfll_set_open_loop_config(td); + dfll_init_out_if(td); + pm_runtime_put_sync(td->dev); return 0; @@ -888,6 +1369,130 @@ di_err1: * DT data fetch */ +/* + * Find a PMIC voltage register-to-voltage mapping for the given voltage. + * An exact voltage match is required. + */ +static int find_vdd_map_entry_exact(struct tegra_dfll *td, int uV) +{ + int i, n_voltages, reg_uV; + + n_voltages = regulator_count_voltages(td->vdd_reg); + for (i = 0; i < n_voltages; i++) { + reg_uV = regulator_list_voltage(td->vdd_reg, i); + if (reg_uV < 0) + break; + + if (uV == reg_uV) + return i; + } + + dev_err(td->dev, "no voltage map entry for %d uV\n", uV); + return -EINVAL; +} + +/* + * Find a PMIC voltage register-to-voltage mapping for the given voltage, + * rounding up to the closest supported voltage. + * */ +static int find_vdd_map_entry_min(struct tegra_dfll *td, int uV) +{ + int i, n_voltages, reg_uV; + + n_voltages = regulator_count_voltages(td->vdd_reg); + for (i = 0; i < n_voltages; i++) { + reg_uV = regulator_list_voltage(td->vdd_reg, i); + if (reg_uV < 0) + break; + + if (uV <= reg_uV) + return i; + } + + dev_err(td->dev, "no voltage map entry rounding to %d uV\n", uV); + return -EINVAL; +} + +/** + * dfll_build_i2c_lut - build the I2C voltage register lookup table + * @td: DFLL instance + * + * The DFLL hardware has 33 bytes of look-up table RAM that must be filled with + * PMIC voltage register values that span the entire DFLL operating range. + * This function builds the look-up table based on the OPP table provided by + * the soc-specific platform driver (td->soc->opp_dev) and the PMIC + * register-to-voltage mapping queried from the regulator framework. + * + * On success, fills in td->i2c_lut and returns 0, or -err on failure. + */ +static int dfll_build_i2c_lut(struct tegra_dfll *td) +{ + int ret = -EINVAL; + int j, v, v_max, v_opp; + int selector; + unsigned long rate; + struct dev_pm_opp *opp; + + rcu_read_lock(); + + rate = ULONG_MAX; + opp = dev_pm_opp_find_freq_floor(td->soc->opp_dev, &rate); + if (IS_ERR(opp)) { + dev_err(td->dev, "couldn't get vmax opp, empty opp table?\n"); + goto out; + } + v_max = dev_pm_opp_get_voltage(opp); + + v = td->soc->min_millivolts * 1000; + td->i2c_lut[0] = find_vdd_map_entry_exact(td, v); + if (td->i2c_lut[0] < 0) + goto out; + + for (j = 1, rate = 0; ; rate++) { + opp = dev_pm_opp_find_freq_ceil(td->soc->opp_dev, &rate); + if (IS_ERR(opp)) + break; + v_opp = dev_pm_opp_get_voltage(opp); + + if (v_opp <= td->soc->min_millivolts * 1000) + td->dvco_rate_min = dev_pm_opp_get_freq(opp); + + for (;;) { + v += max(1, (v_max - v) / (MAX_DFLL_VOLTAGES - j)); + if (v >= v_opp) + break; + + selector = find_vdd_map_entry_min(td, v); + if (selector < 0) + goto out; + if (selector != td->i2c_lut[j - 1]) + td->i2c_lut[j++] = selector; + } + + v = (j == MAX_DFLL_VOLTAGES - 1) ? v_max : v_opp; + selector = find_vdd_map_entry_exact(td, v); + if (selector < 0) + goto out; + if (selector != td->i2c_lut[j - 1]) + td->i2c_lut[j++] = selector; + + if (v >= v_max) + break; + } + td->i2c_lut_size = j; + + if (!td->dvco_rate_min) + dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n", + td->soc->min_millivolts); + else + ret = 0; + +out: + rcu_read_unlock(); + + return ret; +} + /** * read_dt_param - helper function for reading required parameters from the DT * @td: DFLL instance @@ -911,6 +1516,50 @@ static bool read_dt_param(struct tegra_dfll *td, const char *param, u32 *dest) return true; } +/** + * dfll_fetch_i2c_params - query PMIC I2C params from DT & regulator subsystem + * @td: DFLL instance + * + * Read all the parameters required for operation in I2C mode. The parameters + * can originate from the device tree or the regulator subsystem. + * Returns 0 on success or -err on failure. + */ +static int dfll_fetch_i2c_params(struct tegra_dfll *td) +{ + struct regmap *regmap; + struct device *i2c_dev; + struct i2c_client *i2c_client; + int vsel_reg, vsel_mask; + int ret; + + if (!read_dt_param(td, "nvidia,i2c-fs-rate", &td->i2c_fs_rate)) + return -EINVAL; + + regmap = regulator_get_regmap(td->vdd_reg); + i2c_dev = regmap_get_device(regmap); + i2c_client = to_i2c_client(i2c_dev); + + td->i2c_slave_addr = i2c_client->addr; + + ret = regulator_get_hardware_vsel_register(td->vdd_reg, + &vsel_reg, + &vsel_mask); + if (ret < 0) { + dev_err(td->dev, + "regulator unsuitable for DFLL I2C operation\n"); + return -EINVAL; + } + td->i2c_reg = vsel_reg; + + ret = dfll_build_i2c_lut(td); + if (ret) { + dev_err(td->dev, "couldn't build I2C LUT\n"); + return ret; + } + + return 0; +} + /** * dfll_fetch_common_params - read DFLL parameters from the device tree * @td: DFLL instance @@ -923,6 +1572,13 @@ static int dfll_fetch_common_params(struct tegra_dfll *td) bool ok = true; ok &= read_dt_param(td, "nvidia,droop-ctrl", &td->droop_ctrl); + ok &= read_dt_param(td, "nvidia,sample-rate", &td->sample_rate); + ok &= read_dt_param(td, "nvidia,force-mode", &td->force_mode); + ok &= read_dt_param(td, "nvidia,cf", &td->cf); + ok &= read_dt_param(td, "nvidia,ci", &td->ci); + ok &= read_dt_param(td, "nvidia,cg", &td->cg); + td->cg_scale = of_property_read_bool(td->dev->of_node, + "nvidia,cg-scale"); if (of_property_read_string(td->dev->of_node, "clock-output-names", &td->output_clock_name)) { @@ -984,6 +1640,10 @@ int tegra_dfll_register(struct platform_device *pdev, return ret; } + ret = dfll_fetch_i2c_params(td); + if (ret) + return ret; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(td->dev, "no control register resource\n"); -- cgit v1.3-6-gb490 From fa63aa3dea48fd18e560c232424e080a2e2c4779 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Wed, 13 May 2015 17:58:38 +0300 Subject: clk: tegra: Add functions for parsing CVB tables Tegra CVB tables encode the relationship between operating voltage and optimal frequency as a function of the so-called speedo value. The speedo value is written to the on-chip fuses at the factory, which allows the voltage-frequency operating points to be calculated on an per-chip basis. Add utility functions to parse the Tegra-specific tables and export the voltage-frequency pairs to the generic OPP framework for other drivers to use. Signed-off-by: Tuomas Tynkkynen Signed-off-by: Mikko Perttunen Acked-by: Peter De Schrijver Acked-by: Michael Turquette Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/Kconfig | 1 + drivers/clk/tegra/cvb.c | 140 ++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/tegra/cvb.h | 67 +++++++++++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 drivers/clk/tegra/cvb.c create mode 100644 drivers/clk/tegra/cvb.h (limited to 'drivers') diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 5d1a318f1302..0fa4c5f8b1be 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -8,6 +8,7 @@ menuconfig ARCH_TEGRA select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP select PINCTRL + select PM_OPP select ARCH_HAS_RESET_CONTROLLER select RESET_CONTROLLER select SOC_BUS diff --git a/drivers/clk/tegra/cvb.c b/drivers/clk/tegra/cvb.c new file mode 100644 index 000000000000..0204e0861134 --- /dev/null +++ b/drivers/clk/tegra/cvb.c @@ -0,0 +1,140 @@ +/* + * Utility functions for parsing Tegra CVB voltage tables + * + * Copyright (C) 2012-2014 NVIDIA 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 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 "cvb.h" + +/* cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) */ +static inline int get_cvb_voltage(int speedo, int s_scale, + const struct cvb_coefficients *cvb) +{ + int mv; + + /* apply only speedo scale: output mv = cvb_mv * v_scale */ + mv = DIV_ROUND_CLOSEST(cvb->c2 * speedo, s_scale); + mv = DIV_ROUND_CLOSEST((mv + cvb->c1) * speedo, s_scale) + cvb->c0; + return mv; +} + +static int round_cvb_voltage(int mv, int v_scale, + const struct rail_alignment *align) +{ + /* combined: apply voltage scale and round to cvb alignment step */ + int uv; + int step = (align->step_uv ? : 1000) * v_scale; + int offset = align->offset_uv * v_scale; + + uv = max(mv * 1000, offset) - offset; + uv = DIV_ROUND_UP(uv, step) * align->step_uv + align->offset_uv; + return uv / 1000; +} + +enum { + DOWN, + UP +}; + +static int round_voltage(int mv, const struct rail_alignment *align, int up) +{ + if (align->step_uv) { + int uv; + + uv = max(mv * 1000, align->offset_uv) - align->offset_uv; + uv = (uv + (up ? align->step_uv - 1 : 0)) / align->step_uv; + return (uv * align->step_uv + align->offset_uv) / 1000; + } + return mv; +} + +static int build_opp_table(const struct cvb_table *d, + int speedo_value, + unsigned long max_freq, + struct device *opp_dev) +{ + int i, ret, dfll_mv, min_mv, max_mv; + const struct cvb_table_freq_entry *table = NULL; + const struct rail_alignment *align = &d->alignment; + + min_mv = round_voltage(d->min_millivolts, align, UP); + max_mv = round_voltage(d->max_millivolts, align, DOWN); + + for (i = 0; i < MAX_DVFS_FREQS; i++) { + table = &d->cvb_table[i]; + if (!table->freq || (table->freq > max_freq)) + break; + + /* + * FIXME after clk_round_rate/clk_determine_rate prototypes + * have been updated + */ + if (table->freq & (1<<31)) + continue; + + dfll_mv = get_cvb_voltage( + speedo_value, d->speedo_scale, &table->coefficients); + dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale, align); + dfll_mv = clamp(dfll_mv, min_mv, max_mv); + + ret = dev_pm_opp_add(opp_dev, table->freq, dfll_mv * 1000); + if (ret) + return ret; + } + + return 0; +} + +/** + * tegra_cvb_build_opp_table - build OPP table from Tegra CVB tables + * @cvb_tables: array of CVB tables + * @sz: size of the previously mentioned array + * @process_id: process id of the HW module + * @speedo_id: speedo id of the HW module + * @speedo_value: speedo value of the HW module + * @max_rate: highest safe clock rate + * @opp_dev: the struct device * for which the OPP table is built + * + * On Tegra, a CVB table encodes the relationship between operating voltage + * and safe maximal frequency for a given module (e.g. GPU or CPU). This + * function calculates the optimal voltage-frequency operating points + * for the given arguments and exports them via the OPP library for the + * given @opp_dev. Returns a pointer to the struct cvb_table that matched + * or an ERR_PTR on failure. + */ +const struct cvb_table *tegra_cvb_build_opp_table( + const struct cvb_table *cvb_tables, + size_t sz, int process_id, + int speedo_id, int speedo_value, + unsigned long max_rate, + struct device *opp_dev) +{ + int i, ret; + + for (i = 0; i < sz; i++) { + const struct cvb_table *d = &cvb_tables[i]; + + if (d->speedo_id != -1 && d->speedo_id != speedo_id) + continue; + if (d->process_id != -1 && d->process_id != process_id) + continue; + + ret = build_opp_table(d, speedo_value, max_rate, opp_dev); + return ret ? ERR_PTR(ret) : d; + } + + return ERR_PTR(-EINVAL); +} diff --git a/drivers/clk/tegra/cvb.h b/drivers/clk/tegra/cvb.h new file mode 100644 index 000000000000..f62cdc4f4234 --- /dev/null +++ b/drivers/clk/tegra/cvb.h @@ -0,0 +1,67 @@ +/* + * Utility functions for parsing Tegra CVB voltage tables + * + * 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 __DRIVERS_CLK_TEGRA_CVB_H +#define __DRIVERS_CLK_TEGRA_CVB_H + +#include + +struct device; + +#define MAX_DVFS_FREQS 40 + +struct rail_alignment { + int offset_uv; + int step_uv; +}; + +struct cvb_coefficients { + int c0; + int c1; + int c2; +}; + +struct cvb_table_freq_entry { + unsigned long freq; + struct cvb_coefficients coefficients; +}; + +struct cvb_cpu_dfll_data { + u32 tune0_low; + u32 tune0_high; + u32 tune1; +}; + +struct cvb_table { + int speedo_id; + int process_id; + + int min_millivolts; + int max_millivolts; + struct rail_alignment alignment; + + int speedo_scale; + int voltage_scale; + struct cvb_table_freq_entry cvb_table[MAX_DVFS_FREQS]; + struct cvb_cpu_dfll_data cpu_dfll_data; +}; + +const struct cvb_table *tegra_cvb_build_opp_table( + const struct cvb_table *cvb_tables, + size_t sz, int process_id, + int speedo_id, int speedo_value, + unsigned long max_rate, + struct device *opp_dev); + +#endif -- cgit v1.3-6-gb490 From 66b6f3d07454a66ec029543c653d3bce7e6cb3c1 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Wed, 20 May 2015 09:27:05 +0300 Subject: clk: tegra: Introduce ability for SoC-specific reset control callbacks This patch allows SoC-specific CAR initialization routines to register their own reset_assert and reset_deassert callbacks with the common Tegra CAR code. If defined, the common code will call these callbacks when a reset control with number >= num_periph_banks * 32 is attempted to be asserted or deasserted respectively. Numbers greater than or equal to num_periph_banks * 32 are used to avoid clashes with low numbers that are automatically mapped to standard CAR reset lines. Each SoC with these special resets should specify the defined reset control numbers in a device tree header file. Signed-off-by: Mikko Perttunen Acked-by: Michael Turquette Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk.c | 39 +++++++++++++++++++++++++++++++-------- drivers/clk/tegra/clk.h | 3 +++ 2 files changed, 34 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index 41cd87c67be6..3290fd648d1e 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -49,7 +49,6 @@ #define RST_DEVICES_L 0x004 #define RST_DEVICES_H 0x008 #define RST_DEVICES_U 0x00C -#define RST_DFLL_DVCO 0x2F4 #define RST_DEVICES_V 0x358 #define RST_DEVICES_W 0x35C #define RST_DEVICES_X 0x28C @@ -79,6 +78,11 @@ static struct clk **clks; static int clk_num; static struct clk_onecell_data clk_data; +/* Handlers for SoC-specific reset lines */ +static int (*special_reset_assert)(unsigned long); +static int (*special_reset_deassert)(unsigned long); +static unsigned int num_special_reset; + static struct tegra_clk_periph_regs periph_regs[] = { [0] = { .enb_reg = CLK_OUT_ENB_L, @@ -152,19 +156,29 @@ static int tegra_clk_rst_assert(struct reset_controller_dev *rcdev, */ tegra_read_chipid(); - writel_relaxed(BIT(id % 32), - clk_base + periph_regs[id / 32].rst_set_reg); + if (id < periph_banks * 32) { + writel_relaxed(BIT(id % 32), + clk_base + periph_regs[id / 32].rst_set_reg); + return 0; + } else if (id < periph_banks * 32 + num_special_reset) { + return special_reset_assert(id); + } - return 0; + return -EINVAL; } static int tegra_clk_rst_deassert(struct reset_controller_dev *rcdev, unsigned long id) { - writel_relaxed(BIT(id % 32), - clk_base + periph_regs[id / 32].rst_clr_reg); + if (id < periph_banks * 32) { + writel_relaxed(BIT(id % 32), + clk_base + periph_regs[id / 32].rst_clr_reg); + return 0; + } else if (id < periph_banks * 32 + num_special_reset) { + return special_reset_deassert(id); + } - return 0; + return -EINVAL; } struct tegra_clk_periph_regs *get_reg_bank(int clkid) @@ -286,10 +300,19 @@ void __init tegra_add_of_provider(struct device_node *np) of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); rst_ctlr.of_node = np; - rst_ctlr.nr_resets = periph_banks * 32; + rst_ctlr.nr_resets = periph_banks * 32 + num_special_reset; reset_controller_register(&rst_ctlr); } +void __init tegra_init_special_resets(unsigned int num, + int (*assert)(unsigned long), + int (*deassert)(unsigned long)) +{ + num_special_reset = num; + special_reset_assert = assert; + special_reset_deassert = deassert; +} + void __init tegra_register_devclks(struct tegra_devclk *dev_clks, int num) { int i; diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 75ddc8ff8bd4..0621887e06f7 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -591,6 +591,9 @@ struct tegra_devclk { char *con_id; }; +void tegra_init_special_resets(unsigned int num, int (*assert)(unsigned long), + int (*deassert)(unsigned long)); + void tegra_init_from_table(struct tegra_clk_init_table *tbl, struct clk *clks[], int clk_max); -- cgit v1.3-6-gb490 From a3c83ff20c64a0ea3580aa7ed2953ff1602334dd Mon Sep 17 00:00:00 2001 From: Paul Walmsley Date: Tue, 19 May 2015 14:43:30 +0300 Subject: clk: tegra: Add DFLL DVCO reset control for Tegra124 The DVCO present in the DFLL IP block has a separate reset line, exposed via the CAR IP block. This reset line is asserted upon SoC reset. Unless something (such as the DFLL driver) deasserts this line, the DVCO will not oscillate, although reads and writes to the DFLL IP block will complete. Thanks to Aleksandr Frid for identifying this and saving hours of debugging time. Signed-off-by: Paul Walmsley [ttynkkynen: ported to tegra124 from tegra114] Signed-off-by: Tuomas Tynkkynen [mikko.perttunen: ported to special reset callback] Signed-off-by: Mikko Perttunen Acked-by: Michael Turquette Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra124.c | 68 ++++++++++++++++++++++++++++++++ include/dt-bindings/reset/tegra124-car.h | 12 ++++++ 2 files changed, 80 insertions(+) create mode 100644 include/dt-bindings/reset/tegra124-car.h (limited to 'drivers') diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index e8cca3eac007..106ec458c945 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "clk.h" #include "clk-id.h" @@ -39,6 +40,9 @@ #define CLK_SOURCE_CSITE 0x1d4 #define CLK_SOURCE_EMC 0x19c +#define RST_DFLL_DVCO 0x2f4 +#define DVFS_DFLL_RESET_SHIFT 0 + #define PLLC_BASE 0x80 #define PLLC_OUT 0x84 #define PLLC_MISC2 0x88 @@ -1414,6 +1418,68 @@ static void __init tegra124_clock_apply_init_table(void) tegra_init_from_table(tegra124_init_table, clks, TEGRA124_CLK_CLK_MAX); } +/** + * tegra124_car_barrier - wait for pending writes to the CAR to complete + * + * Wait for any outstanding writes to the CAR MMIO space from this CPU + * to complete before continuing execution. No return value. + */ +static void tegra124_car_barrier(void) +{ + readl_relaxed(clk_base + RST_DFLL_DVCO); +} + +/** + * tegra124_clock_assert_dfll_dvco_reset - assert the DFLL's DVCO reset + * + * Assert the reset line of the DFLL's DVCO. No return value. + */ +void tegra124_clock_assert_dfll_dvco_reset(void) +{ + u32 v; + + v = readl_relaxed(clk_base + RST_DFLL_DVCO); + v |= (1 << DVFS_DFLL_RESET_SHIFT); + writel_relaxed(v, clk_base + RST_DFLL_DVCO); + tegra124_car_barrier(); +} + +/** + * tegra124_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset + * + * Deassert the reset line of the DFLL's DVCO, allowing the DVCO to + * operate. No return value. + */ +void tegra124_clock_deassert_dfll_dvco_reset(void) +{ + u32 v; + + v = readl_relaxed(clk_base + RST_DFLL_DVCO); + v &= ~(1 << DVFS_DFLL_RESET_SHIFT); + writel_relaxed(v, clk_base + RST_DFLL_DVCO); + tegra124_car_barrier(); +} + +int tegra124_reset_assert(unsigned long id) +{ + if (id == TEGRA124_RST_DFLL_DVCO) + tegra124_clock_assert_dfll_dvco_reset(); + else + return -EINVAL; + + return 0; +} + +int tegra124_reset_deassert(unsigned long id) +{ + if (id == TEGRA124_RST_DFLL_DVCO) + tegra124_clock_deassert_dfll_dvco_reset(); + else + return -EINVAL; + + return 0; +} + /** * tegra132_clock_apply_init_table - initialize clocks on Tegra132 SoCs * @@ -1499,6 +1565,8 @@ static void __init tegra124_132_clock_init_post(struct device_node *np) { tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks, &pll_x_params); + tegra_init_special_resets(1, tegra124_reset_assert, + tegra124_reset_deassert); tegra_add_of_provider(np); clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np, diff --git a/include/dt-bindings/reset/tegra124-car.h b/include/dt-bindings/reset/tegra124-car.h new file mode 100644 index 000000000000..070e4f6e7486 --- /dev/null +++ b/include/dt-bindings/reset/tegra124-car.h @@ -0,0 +1,12 @@ +/* + * This header provides Tegra124-specific constants for binding + * nvidia,tegra124-car. + */ + +#ifndef _DT_BINDINGS_RESET_TEGRA124_CAR_H +#define _DT_BINDINGS_RESET_TEGRA124_CAR_H + +#define TEGRA124_RESET(x) (6 * 32 + (x)) +#define TEGRA124_RST_DFLL_DVCO TEGRA124_RESET(0) + +#endif /* _DT_BINDINGS_RESET_TEGRA124_CAR_H */ -- cgit v1.3-6-gb490 From 109e13eaa40dfebf8893234cc5f1535a04e23acf Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Wed, 13 May 2015 17:58:47 +0300 Subject: cpufreq: tegra: Rename tegra-cpufreq to tegra20-cpufreq The Tegra124 will use a different driver for frequency scaling, so rename the old driver (which handles only Tegra20) appropriately. Signed-off-by: Tuomas Tynkkynen Signed-off-by: Mikko Perttunen Acked-by: Viresh Kumar Signed-off-by: Thierry Reding --- drivers/cpufreq/Kconfig.arm | 6 +- drivers/cpufreq/Makefile | 2 +- drivers/cpufreq/tegra-cpufreq.c | 218 -------------------------------------- drivers/cpufreq/tegra20-cpufreq.c | 218 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 222 insertions(+), 222 deletions(-) delete mode 100644 drivers/cpufreq/tegra-cpufreq.c create mode 100644 drivers/cpufreq/tegra20-cpufreq.c (limited to 'drivers') diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index cc8a71c267b8..ef402869576f 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -247,12 +247,12 @@ config ARM_SPEAR_CPUFREQ help This adds the CPUFreq driver support for SPEAr SOCs. -config ARM_TEGRA_CPUFREQ - bool "TEGRA CPUFreq support" +config ARM_TEGRA20_CPUFREQ + bool "Tegra20 CPUFreq support" depends on ARCH_TEGRA default y help - This adds the CPUFreq driver support for TEGRA SOCs. + This adds the CPUFreq driver support for Tegra20 SOCs. config ARM_PXA2xx_CPUFREQ tristate "Intel PXA2xx CPUfreq driver" diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 2169bf792db7..d0b70ce56dd7 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -76,7 +76,7 @@ obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o -obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o +obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o ################################################################################## diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c deleted file mode 100644 index 8084c7f7e206..000000000000 --- a/drivers/cpufreq/tegra-cpufreq.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2010 Google, Inc. - * - * Author: - * Colin Cross - * Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct cpufreq_frequency_table freq_table[] = { - { .frequency = 216000 }, - { .frequency = 312000 }, - { .frequency = 456000 }, - { .frequency = 608000 }, - { .frequency = 760000 }, - { .frequency = 816000 }, - { .frequency = 912000 }, - { .frequency = 1000000 }, - { .frequency = CPUFREQ_TABLE_END }, -}; - -#define NUM_CPUS 2 - -static struct clk *cpu_clk; -static struct clk *pll_x_clk; -static struct clk *pll_p_clk; -static struct clk *emc_clk; -static bool pll_x_prepared; - -static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy, - unsigned int index) -{ - unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000; - - /* - * Don't switch to intermediate freq if: - * - we are already at it, i.e. policy->cur == ifreq - * - index corresponds to ifreq - */ - if ((freq_table[index].frequency == ifreq) || (policy->cur == ifreq)) - return 0; - - return ifreq; -} - -static int tegra_target_intermediate(struct cpufreq_policy *policy, - unsigned int index) -{ - int ret; - - /* - * Take an extra reference to the main pll so it doesn't turn - * off when we move the cpu off of it as enabling it again while we - * switch to it from tegra_target() would take additional time. - * - * When target-freq is equal to intermediate freq we don't need to - * switch to an intermediate freq and so this routine isn't called. - * Also, we wouldn't be using pll_x anymore and must not take extra - * reference to it, as it can be disabled now to save some power. - */ - clk_prepare_enable(pll_x_clk); - - ret = clk_set_parent(cpu_clk, pll_p_clk); - if (ret) - clk_disable_unprepare(pll_x_clk); - else - pll_x_prepared = true; - - return ret; -} - -static int tegra_target(struct cpufreq_policy *policy, unsigned int index) -{ - unsigned long rate = freq_table[index].frequency; - unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000; - int ret = 0; - - /* - * Vote on memory bus frequency based on cpu frequency - * This sets the minimum frequency, display or avp may request higher - */ - if (rate >= 816000) - clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */ - else if (rate >= 456000) - clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */ - else - clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */ - - /* - * target freq == pll_p, don't need to take extra reference to pll_x_clk - * as it isn't used anymore. - */ - if (rate == ifreq) - return clk_set_parent(cpu_clk, pll_p_clk); - - ret = clk_set_rate(pll_x_clk, rate * 1000); - /* Restore to earlier frequency on error, i.e. pll_x */ - if (ret) - pr_err("Failed to change pll_x to %lu\n", rate); - - ret = clk_set_parent(cpu_clk, pll_x_clk); - /* This shouldn't fail while changing or restoring */ - WARN_ON(ret); - - /* - * Drop count to pll_x clock only if we switched to intermediate freq - * earlier while transitioning to a target frequency. - */ - if (pll_x_prepared) { - clk_disable_unprepare(pll_x_clk); - pll_x_prepared = false; - } - - return ret; -} - -static int tegra_cpu_init(struct cpufreq_policy *policy) -{ - int ret; - - if (policy->cpu >= NUM_CPUS) - return -EINVAL; - - clk_prepare_enable(emc_clk); - clk_prepare_enable(cpu_clk); - - /* FIXME: what's the actual transition time? */ - ret = cpufreq_generic_init(policy, freq_table, 300 * 1000); - if (ret) { - clk_disable_unprepare(cpu_clk); - clk_disable_unprepare(emc_clk); - return ret; - } - - policy->clk = cpu_clk; - policy->suspend_freq = freq_table[0].frequency; - return 0; -} - -static int tegra_cpu_exit(struct cpufreq_policy *policy) -{ - clk_disable_unprepare(cpu_clk); - clk_disable_unprepare(emc_clk); - return 0; -} - -static struct cpufreq_driver tegra_cpufreq_driver = { - .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, - .verify = cpufreq_generic_frequency_table_verify, - .get_intermediate = tegra_get_intermediate, - .target_intermediate = tegra_target_intermediate, - .target_index = tegra_target, - .get = cpufreq_generic_get, - .init = tegra_cpu_init, - .exit = tegra_cpu_exit, - .name = "tegra", - .attr = cpufreq_generic_attr, -#ifdef CONFIG_PM - .suspend = cpufreq_generic_suspend, -#endif -}; - -static int __init tegra_cpufreq_init(void) -{ - cpu_clk = clk_get_sys(NULL, "cclk"); - if (IS_ERR(cpu_clk)) - return PTR_ERR(cpu_clk); - - pll_x_clk = clk_get_sys(NULL, "pll_x"); - if (IS_ERR(pll_x_clk)) - return PTR_ERR(pll_x_clk); - - pll_p_clk = clk_get_sys(NULL, "pll_p"); - if (IS_ERR(pll_p_clk)) - return PTR_ERR(pll_p_clk); - - emc_clk = clk_get_sys("cpu", "emc"); - if (IS_ERR(emc_clk)) { - clk_put(cpu_clk); - return PTR_ERR(emc_clk); - } - - return cpufreq_register_driver(&tegra_cpufreq_driver); -} - -static void __exit tegra_cpufreq_exit(void) -{ - cpufreq_unregister_driver(&tegra_cpufreq_driver); - clk_put(emc_clk); - clk_put(cpu_clk); -} - - -MODULE_AUTHOR("Colin Cross "); -MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2"); -MODULE_LICENSE("GPL"); -module_init(tegra_cpufreq_init); -module_exit(tegra_cpufreq_exit); diff --git a/drivers/cpufreq/tegra20-cpufreq.c b/drivers/cpufreq/tegra20-cpufreq.c new file mode 100644 index 000000000000..8084c7f7e206 --- /dev/null +++ b/drivers/cpufreq/tegra20-cpufreq.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * Author: + * Colin Cross + * Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct cpufreq_frequency_table freq_table[] = { + { .frequency = 216000 }, + { .frequency = 312000 }, + { .frequency = 456000 }, + { .frequency = 608000 }, + { .frequency = 760000 }, + { .frequency = 816000 }, + { .frequency = 912000 }, + { .frequency = 1000000 }, + { .frequency = CPUFREQ_TABLE_END }, +}; + +#define NUM_CPUS 2 + +static struct clk *cpu_clk; +static struct clk *pll_x_clk; +static struct clk *pll_p_clk; +static struct clk *emc_clk; +static bool pll_x_prepared; + +static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy, + unsigned int index) +{ + unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000; + + /* + * Don't switch to intermediate freq if: + * - we are already at it, i.e. policy->cur == ifreq + * - index corresponds to ifreq + */ + if ((freq_table[index].frequency == ifreq) || (policy->cur == ifreq)) + return 0; + + return ifreq; +} + +static int tegra_target_intermediate(struct cpufreq_policy *policy, + unsigned int index) +{ + int ret; + + /* + * Take an extra reference to the main pll so it doesn't turn + * off when we move the cpu off of it as enabling it again while we + * switch to it from tegra_target() would take additional time. + * + * When target-freq is equal to intermediate freq we don't need to + * switch to an intermediate freq and so this routine isn't called. + * Also, we wouldn't be using pll_x anymore and must not take extra + * reference to it, as it can be disabled now to save some power. + */ + clk_prepare_enable(pll_x_clk); + + ret = clk_set_parent(cpu_clk, pll_p_clk); + if (ret) + clk_disable_unprepare(pll_x_clk); + else + pll_x_prepared = true; + + return ret; +} + +static int tegra_target(struct cpufreq_policy *policy, unsigned int index) +{ + unsigned long rate = freq_table[index].frequency; + unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000; + int ret = 0; + + /* + * Vote on memory bus frequency based on cpu frequency + * This sets the minimum frequency, display or avp may request higher + */ + if (rate >= 816000) + clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */ + else if (rate >= 456000) + clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */ + else + clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */ + + /* + * target freq == pll_p, don't need to take extra reference to pll_x_clk + * as it isn't used anymore. + */ + if (rate == ifreq) + return clk_set_parent(cpu_clk, pll_p_clk); + + ret = clk_set_rate(pll_x_clk, rate * 1000); + /* Restore to earlier frequency on error, i.e. pll_x */ + if (ret) + pr_err("Failed to change pll_x to %lu\n", rate); + + ret = clk_set_parent(cpu_clk, pll_x_clk); + /* This shouldn't fail while changing or restoring */ + WARN_ON(ret); + + /* + * Drop count to pll_x clock only if we switched to intermediate freq + * earlier while transitioning to a target frequency. + */ + if (pll_x_prepared) { + clk_disable_unprepare(pll_x_clk); + pll_x_prepared = false; + } + + return ret; +} + +static int tegra_cpu_init(struct cpufreq_policy *policy) +{ + int ret; + + if (policy->cpu >= NUM_CPUS) + return -EINVAL; + + clk_prepare_enable(emc_clk); + clk_prepare_enable(cpu_clk); + + /* FIXME: what's the actual transition time? */ + ret = cpufreq_generic_init(policy, freq_table, 300 * 1000); + if (ret) { + clk_disable_unprepare(cpu_clk); + clk_disable_unprepare(emc_clk); + return ret; + } + + policy->clk = cpu_clk; + policy->suspend_freq = freq_table[0].frequency; + return 0; +} + +static int tegra_cpu_exit(struct cpufreq_policy *policy) +{ + clk_disable_unprepare(cpu_clk); + clk_disable_unprepare(emc_clk); + return 0; +} + +static struct cpufreq_driver tegra_cpufreq_driver = { + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, + .verify = cpufreq_generic_frequency_table_verify, + .get_intermediate = tegra_get_intermediate, + .target_intermediate = tegra_target_intermediate, + .target_index = tegra_target, + .get = cpufreq_generic_get, + .init = tegra_cpu_init, + .exit = tegra_cpu_exit, + .name = "tegra", + .attr = cpufreq_generic_attr, +#ifdef CONFIG_PM + .suspend = cpufreq_generic_suspend, +#endif +}; + +static int __init tegra_cpufreq_init(void) +{ + cpu_clk = clk_get_sys(NULL, "cclk"); + if (IS_ERR(cpu_clk)) + return PTR_ERR(cpu_clk); + + pll_x_clk = clk_get_sys(NULL, "pll_x"); + if (IS_ERR(pll_x_clk)) + return PTR_ERR(pll_x_clk); + + pll_p_clk = clk_get_sys(NULL, "pll_p"); + if (IS_ERR(pll_p_clk)) + return PTR_ERR(pll_p_clk); + + emc_clk = clk_get_sys("cpu", "emc"); + if (IS_ERR(emc_clk)) { + clk_put(cpu_clk); + return PTR_ERR(emc_clk); + } + + return cpufreq_register_driver(&tegra_cpufreq_driver); +} + +static void __exit tegra_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&tegra_cpufreq_driver); + clk_put(emc_clk); + clk_put(cpu_clk); +} + + +MODULE_AUTHOR("Colin Cross "); +MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2"); +MODULE_LICENSE("GPL"); +module_init(tegra_cpufreq_init); +module_exit(tegra_cpufreq_exit); -- cgit v1.3-6-gb490 From 9eb15dbbfa1a23b5e65efaf1d5d6c47798e7264b Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Wed, 13 May 2015 17:58:48 +0300 Subject: cpufreq: Add cpufreq driver for Tegra124 Add a new cpufreq driver for Tegra124. Instead of using the PLLX as the CPU clocksource, switch immediately to the DFLL. It allows the use of higher clock rates, and will automatically scale the CPU voltage as well. Besides the CPU clocksource switch, we let the cpufreq-dt driver for all the cpufreq operations. This driver also relies on the DFLL driver to fill the OPP table for the CPU0 device, so that the cpufreq-dt driver knows what frequencies to use. Signed-off-by: Tuomas Tynkkynen Signed-off-by: Mikko Perttunen Acked-by: Viresh Kumar Signed-off-by: Thierry Reding --- drivers/cpufreq/Kconfig.arm | 7 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/tegra124-cpufreq.c | 214 +++++++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 drivers/cpufreq/tegra124-cpufreq.c (limited to 'drivers') diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index ef402869576f..24e5c664683f 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -254,6 +254,13 @@ config ARM_TEGRA20_CPUFREQ help This adds the CPUFreq driver support for Tegra20 SOCs. +config ARM_TEGRA124_CPUFREQ + tristate "Tegra124 CPUFreq support" + depends on ARCH_TEGRA && CPUFREQ_DT + default y + help + This adds the CPUFreq driver support for Tegra124 SOCs. + config ARM_PXA2xx_CPUFREQ tristate "Intel PXA2xx CPUfreq driver" depends on PXA27x || PXA25x diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index d0b70ce56dd7..032745de8fcc 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o +obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o ################################################################################## diff --git a/drivers/cpufreq/tegra124-cpufreq.c b/drivers/cpufreq/tegra124-cpufreq.c new file mode 100644 index 000000000000..20bcceb58ccc --- /dev/null +++ b/drivers/cpufreq/tegra124-cpufreq.c @@ -0,0 +1,214 @@ +/* + * Tegra 124 cpufreq driver + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct tegra124_cpufreq_priv { + struct regulator *vdd_cpu_reg; + struct clk *cpu_clk; + struct clk *pllp_clk; + struct clk *pllx_clk; + struct clk *dfll_clk; + struct platform_device *cpufreq_dt_pdev; +}; + +static int tegra124_cpu_switch_to_dfll(struct tegra124_cpufreq_priv *priv) +{ + struct clk *orig_parent; + int ret; + + ret = clk_set_rate(priv->dfll_clk, clk_get_rate(priv->cpu_clk)); + if (ret) + return ret; + + orig_parent = clk_get_parent(priv->cpu_clk); + clk_set_parent(priv->cpu_clk, priv->pllp_clk); + + ret = clk_prepare_enable(priv->dfll_clk); + if (ret) + goto out; + + clk_set_parent(priv->cpu_clk, priv->dfll_clk); + + return 0; + +out: + clk_set_parent(priv->cpu_clk, orig_parent); + + return ret; +} + +static void tegra124_cpu_switch_to_pllx(struct tegra124_cpufreq_priv *priv) +{ + clk_set_parent(priv->cpu_clk, priv->pllp_clk); + clk_disable_unprepare(priv->dfll_clk); + regulator_sync_voltage(priv->vdd_cpu_reg); + clk_set_parent(priv->cpu_clk, priv->pllx_clk); +} + +static struct cpufreq_dt_platform_data cpufreq_dt_pd = { + .independent_clocks = false, +}; + +static int tegra124_cpufreq_probe(struct platform_device *pdev) +{ + struct tegra124_cpufreq_priv *priv; + struct device_node *np; + struct device *cpu_dev; + struct platform_device_info cpufreq_dt_devinfo = {}; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + cpu_dev = get_cpu_device(0); + if (!cpu_dev) + return -ENODEV; + + np = of_cpu_device_node_get(0); + if (!np) + return -ENODEV; + + priv->vdd_cpu_reg = regulator_get(cpu_dev, "vdd-cpu"); + if (IS_ERR(priv->vdd_cpu_reg)) { + ret = PTR_ERR(priv->vdd_cpu_reg); + goto out_put_np; + } + + priv->cpu_clk = of_clk_get_by_name(np, "cpu_g"); + if (IS_ERR(priv->cpu_clk)) { + ret = PTR_ERR(priv->cpu_clk); + goto out_put_vdd_cpu_reg; + } + + priv->dfll_clk = of_clk_get_by_name(np, "dfll"); + if (IS_ERR(priv->dfll_clk)) { + ret = PTR_ERR(priv->dfll_clk); + goto out_put_cpu_clk; + } + + priv->pllx_clk = of_clk_get_by_name(np, "pll_x"); + if (IS_ERR(priv->pllx_clk)) { + ret = PTR_ERR(priv->pllx_clk); + goto out_put_dfll_clk; + } + + priv->pllp_clk = of_clk_get_by_name(np, "pll_p"); + if (IS_ERR(priv->pllp_clk)) { + ret = PTR_ERR(priv->pllp_clk); + goto out_put_pllx_clk; + } + + ret = tegra124_cpu_switch_to_dfll(priv); + if (ret) + goto out_put_pllp_clk; + + cpufreq_dt_devinfo.name = "cpufreq-dt"; + cpufreq_dt_devinfo.parent = &pdev->dev; + cpufreq_dt_devinfo.data = &cpufreq_dt_pd; + cpufreq_dt_devinfo.size_data = sizeof(cpufreq_dt_pd); + + priv->cpufreq_dt_pdev = + platform_device_register_full(&cpufreq_dt_devinfo); + if (IS_ERR(priv->cpufreq_dt_pdev)) { + ret = PTR_ERR(priv->cpufreq_dt_pdev); + goto out_switch_to_pllx; + } + + platform_set_drvdata(pdev, priv); + + return 0; + +out_switch_to_pllx: + tegra124_cpu_switch_to_pllx(priv); +out_put_pllp_clk: + clk_put(priv->pllp_clk); +out_put_pllx_clk: + clk_put(priv->pllx_clk); +out_put_dfll_clk: + clk_put(priv->dfll_clk); +out_put_cpu_clk: + clk_put(priv->cpu_clk); +out_put_vdd_cpu_reg: + regulator_put(priv->vdd_cpu_reg); +out_put_np: + of_node_put(np); + + return ret; +} + +static int tegra124_cpufreq_remove(struct platform_device *pdev) +{ + struct tegra124_cpufreq_priv *priv = platform_get_drvdata(pdev); + + platform_device_unregister(priv->cpufreq_dt_pdev); + tegra124_cpu_switch_to_pllx(priv); + + clk_put(priv->pllp_clk); + clk_put(priv->pllx_clk); + clk_put(priv->dfll_clk); + clk_put(priv->cpu_clk); + regulator_put(priv->vdd_cpu_reg); + + return 0; +} + +static struct platform_driver tegra124_cpufreq_platdrv = { + .driver.name = "cpufreq-tegra124", + .probe = tegra124_cpufreq_probe, + .remove = tegra124_cpufreq_remove, +}; + +static int __init tegra_cpufreq_init(void) +{ + int ret; + struct platform_device *pdev; + + if (!of_machine_is_compatible("nvidia,tegra124")) + return -ENODEV; + + /* + * Platform driver+device required for handling EPROBE_DEFER with + * the regulator and the DFLL clock + */ + ret = platform_driver_register(&tegra124_cpufreq_platdrv); + if (ret) + return ret; + + pdev = platform_device_register_simple("cpufreq-tegra124", -1, NULL, 0); + if (IS_ERR(pdev)) { + platform_driver_unregister(&tegra124_cpufreq_platdrv); + return PTR_ERR(pdev); + } + + return 0; +} +module_init(tegra_cpufreq_init); + +MODULE_AUTHOR("Tuomas Tynkkynen "); +MODULE_DESCRIPTION("cpufreq driver for NVIDIA Tegra124"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From 13b8a68a9c08410f03047fc888706299b5b75754 Mon Sep 17 00:00:00 2001 From: Mario Bambagini Date: Tue, 16 Jun 2015 22:32:30 +0200 Subject: added tabs instead of spaces Tabs have been inserted instead of spaces to indent the code correctly. Same error fixed four times. Signed-off-by: Mario Bambagini Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-adi2-bf60x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-adi2-bf60x.c b/drivers/pinctrl/pinctrl-adi2-bf60x.c index 4cb59fe9be70..fcfa00821f12 100644 --- a/drivers/pinctrl/pinctrl-adi2-bf60x.c +++ b/drivers/pinctrl/pinctrl-adi2-bf60x.c @@ -394,25 +394,25 @@ static const unsigned short ppi2_16b_mux[] = { static const unsigned short lp0_mux[] = { P_LP0_CLK, P_LP0_ACK, P_LP0_D0, P_LP0_D1, P_LP0_D2, P_LP0_D3, P_LP0_D4, P_LP0_D5, P_LP0_D6, P_LP0_D7, - 0 + 0 }; static const unsigned short lp1_mux[] = { P_LP1_CLK, P_LP1_ACK, P_LP1_D0, P_LP1_D1, P_LP1_D2, P_LP1_D3, P_LP1_D4, P_LP1_D5, P_LP1_D6, P_LP1_D7, - 0 + 0 }; static const unsigned short lp2_mux[] = { P_LP2_CLK, P_LP2_ACK, P_LP2_D0, P_LP2_D1, P_LP2_D2, P_LP2_D3, P_LP2_D4, P_LP2_D5, P_LP2_D6, P_LP2_D7, - 0 + 0 }; static const unsigned short lp3_mux[] = { P_LP3_CLK, P_LP3_ACK, P_LP3_D0, P_LP3_D1, P_LP3_D2, P_LP3_D3, P_LP3_D4, P_LP3_D5, P_LP3_D6, P_LP3_D7, - 0 + 0 }; static const struct adi_pin_group adi_pin_groups[] = { -- cgit v1.3-6-gb490 From b5599df20f1ee45cef811a7ab1c7358d9faf7bf8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 26 Jun 2015 01:42:04 +0300 Subject: sh-pfc: r8a7790: remove non-existing GPIO pins GPIO banks 1 and 2 are missing pins 30 and 31. Remove them. Signed-off-by: Laurent Pinchart Signed-off-by: Sergei Shtylyov Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/pfc-r8a7790.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c index baab81ead9ff..fc344a7c2b53 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c @@ -27,10 +27,27 @@ #include "core.h" #include "sh_pfc.h" +#define PORT_GP_30(bank, fn, sfx) \ + PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx), \ + PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx), \ + PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx), \ + PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx), \ + PORT_GP_1(bank, 8, fn, sfx), PORT_GP_1(bank, 9, fn, sfx), \ + PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx), \ + PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx), \ + PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx), \ + PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx), \ + PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx), \ + PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx), \ + PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx), \ + PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx), \ + PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx), \ + PORT_GP_1(bank, 28, fn, sfx), PORT_GP_1(bank, 29, fn, sfx) + #define CPU_ALL_PORT(fn, sfx) \ PORT_GP_32(0, fn, sfx), \ - PORT_GP_32(1, fn, sfx), \ - PORT_GP_32(2, fn, sfx), \ + PORT_GP_30(1, fn, sfx), \ + PORT_GP_30(2, fn, sfx), \ PORT_GP_32(3, fn, sfx), \ PORT_GP_32(4, fn, sfx), \ PORT_GP_32(5, fn, sfx) -- cgit v1.3-6-gb490 From 441f77dcf8defcebb4477fea6db03624259fef42 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 26 Jun 2015 01:43:07 +0300 Subject: sh-pfc: r8a7791: remove non-existing GPIO pins GPIO banks 1 and 7 are missing pins 26 to 31. Remove them. Signed-off-by: Laurent Pinchart Signed-off-by: Sergei Shtylyov Tested-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/pfc-r8a7791.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index 3ddf23ec9f0b..25e8117f5a1a 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -14,15 +14,30 @@ #include "core.h" #include "sh_pfc.h" +#define PORT_GP_26(bank, fn, sfx) \ + PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx), \ + PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx), \ + PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx), \ + PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx), \ + PORT_GP_1(bank, 8, fn, sfx), PORT_GP_1(bank, 9, fn, sfx), \ + PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx), \ + PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx), \ + PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx), \ + PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx), \ + PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx), \ + PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx), \ + PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx), \ + PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx) + #define CPU_ALL_PORT(fn, sfx) \ PORT_GP_32(0, fn, sfx), \ - PORT_GP_32(1, fn, sfx), \ + PORT_GP_26(1, fn, sfx), \ PORT_GP_32(2, fn, sfx), \ PORT_GP_32(3, fn, sfx), \ PORT_GP_32(4, fn, sfx), \ PORT_GP_32(5, fn, sfx), \ PORT_GP_32(6, fn, sfx), \ - PORT_GP_32(7, fn, sfx) + PORT_GP_26(7, fn, sfx) enum { PINMUX_RESERVED = 0, -- cgit v1.3-6-gb490 From 9612327c1ffcdacc863b3baf0a3c8c9b0837ffd2 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 19 Jun 2015 23:32:27 +0800 Subject: pinctrl: imx: add i.mx6ul subdriver Add i.MX6UL pinctrl driver support. Signed-off-by: Anson Huang Signed-off-by: Frank Li Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/Kconfig | 7 + drivers/pinctrl/freescale/Makefile | 1 + drivers/pinctrl/freescale/pinctrl-imx6ul.c | 323 +++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 drivers/pinctrl/freescale/pinctrl-imx6ul.c (limited to 'drivers') diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index 12ef544b4894..debe1219d76d 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -87,6 +87,13 @@ config PINCTRL_IMX6SX help Say Y here to enable the imx6sx pinctrl driver +config PINCTRL_IMX6UL + bool "IMX6UL pinctrl driver" + depends on SOC_IMX6UL + select PINCTRL_IMX + help + Say Y here to enable the imx6ul pinctrl driver + config PINCTRL_IMX7D bool "IMX7D pinctrl driver" depends on SOC_IMX7D diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile index 343cb436ab17..d44c9e253f21 100644 --- a/drivers/pinctrl/freescale/Makefile +++ b/drivers/pinctrl/freescale/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6dl.o obj-$(CONFIG_PINCTRL_IMX6SL) += pinctrl-imx6sl.o obj-$(CONFIG_PINCTRL_IMX6SX) += pinctrl-imx6sx.o +obj-$(CONFIG_PINCTRL_IMX6UL) += pinctrl-imx6ul.o obj-$(CONFIG_PINCTRL_IMX7D) += pinctrl-imx7d.o obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o diff --git a/drivers/pinctrl/freescale/pinctrl-imx6ul.c b/drivers/pinctrl/freescale/pinctrl-imx6ul.c new file mode 100644 index 000000000000..b182be729382 --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-imx6ul.c @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2015 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pinctrl-imx.h" + +enum imx6ul_pads { + MX6UL_PAD_RESERVE0 = 0, + MX6UL_PAD_RESERVE1 = 1, + MX6UL_PAD_RESERVE2 = 2, + MX6UL_PAD_RESERVE3 = 3, + MX6UL_PAD_RESERVE4 = 4, + MX6UL_PAD_RESERVE5 = 5, + MX6UL_PAD_RESERVE6 = 6, + MX6UL_PAD_RESERVE7 = 7, + MX6UL_PAD_RESERVE8 = 8, + MX6UL_PAD_RESERVE9 = 9, + MX6UL_PAD_RESERVE10 = 10, + MX6UL_PAD_SNVS_TAMPER4 = 11, + MX6UL_PAD_RESERVE12 = 12, + MX6UL_PAD_RESERVE13 = 13, + MX6UL_PAD_RESERVE14 = 14, + MX6UL_PAD_RESERVE15 = 15, + MX6UL_PAD_RESERVE16 = 16, + MX6UL_PAD_JTAG_MOD = 17, + MX6UL_PAD_JTAG_TMS = 18, + MX6UL_PAD_JTAG_TDO = 19, + MX6UL_PAD_JTAG_TDI = 20, + MX6UL_PAD_JTAG_TCK = 21, + MX6UL_PAD_JTAG_TRST_B = 22, + MX6UL_PAD_GPIO1_IO00 = 23, + MX6UL_PAD_GPIO1_IO01 = 24, + MX6UL_PAD_GPIO1_IO02 = 25, + MX6UL_PAD_GPIO1_IO03 = 26, + MX6UL_PAD_GPIO1_IO04 = 27, + MX6UL_PAD_GPIO1_IO05 = 28, + MX6UL_PAD_GPIO1_IO06 = 29, + MX6UL_PAD_GPIO1_IO07 = 30, + MX6UL_PAD_GPIO1_IO08 = 31, + MX6UL_PAD_GPIO1_IO09 = 32, + MX6UL_PAD_UART1_TX_DATA = 33, + MX6UL_PAD_UART1_RX_DATA = 34, + MX6UL_PAD_UART1_CTS_B = 35, + MX6UL_PAD_UART1_RTS_B = 36, + MX6UL_PAD_UART2_TX_DATA = 37, + MX6UL_PAD_UART2_RX_DATA = 38, + MX6UL_PAD_UART2_CTS_B = 39, + MX6UL_PAD_UART2_RTS_B = 40, + MX6UL_PAD_UART3_TX_DATA = 41, + MX6UL_PAD_UART3_RX_DATA = 42, + MX6UL_PAD_UART3_CTS_B = 43, + MX6UL_PAD_UART3_RTS_B = 44, + MX6UL_PAD_UART4_TX_DATA = 45, + MX6UL_PAD_UART4_RX_DATA = 46, + MX6UL_PAD_UART5_TX_DATA = 47, + MX6UL_PAD_UART5_RX_DATA = 48, + MX6UL_PAD_ENET1_RX_DATA0 = 49, + MX6UL_PAD_ENET1_RX_DATA1 = 50, + MX6UL_PAD_ENET1_RX_EN = 51, + MX6UL_PAD_ENET1_TX_DATA0 = 52, + MX6UL_PAD_ENET1_TX_DATA1 = 53, + MX6UL_PAD_ENET1_TX_EN = 54, + MX6UL_PAD_ENET1_TX_CLK = 55, + MX6UL_PAD_ENET1_RX_ER = 56, + MX6UL_PAD_ENET2_RX_DATA0 = 57, + MX6UL_PAD_ENET2_RX_DATA1 = 58, + MX6UL_PAD_ENET2_RX_EN = 59, + MX6UL_PAD_ENET2_TX_DATA0 = 60, + MX6UL_PAD_ENET2_TX_DATA1 = 61, + MX6UL_PAD_ENET2_TX_EN = 62, + MX6UL_PAD_ENET2_TX_CLK = 63, + MX6UL_PAD_ENET2_RX_ER = 64, + MX6UL_PAD_LCD_CLK = 65, + MX6UL_PAD_LCD_ENABLE = 66, + MX6UL_PAD_LCD_HSYNC = 67, + MX6UL_PAD_LCD_VSYNC = 68, + MX6UL_PAD_LCD_RESET = 69, + MX6UL_PAD_LCD_DATA00 = 70, + MX6UL_PAD_LCD_DATA01 = 71, + MX6UL_PAD_LCD_DATA02 = 72, + MX6UL_PAD_LCD_DATA03 = 73, + MX6UL_PAD_LCD_DATA04 = 74, + MX6UL_PAD_LCD_DATA05 = 75, + MX6UL_PAD_LCD_DATA06 = 76, + MX6UL_PAD_LCD_DATA07 = 77, + MX6UL_PAD_LCD_DATA08 = 78, + MX6UL_PAD_LCD_DATA09 = 79, + MX6UL_PAD_LCD_DATA10 = 80, + MX6UL_PAD_LCD_DATA11 = 81, + MX6UL_PAD_LCD_DATA12 = 82, + MX6UL_PAD_LCD_DATA13 = 83, + MX6UL_PAD_LCD_DATA14 = 84, + MX6UL_PAD_LCD_DATA15 = 85, + MX6UL_PAD_LCD_DATA16 = 86, + MX6UL_PAD_LCD_DATA17 = 87, + MX6UL_PAD_LCD_DATA18 = 88, + MX6UL_PAD_LCD_DATA19 = 89, + MX6UL_PAD_LCD_DATA20 = 90, + MX6UL_PAD_LCD_DATA21 = 91, + MX6UL_PAD_LCD_DATA22 = 92, + MX6UL_PAD_LCD_DATA23 = 93, + MX6UL_PAD_NAND_RE_B = 94, + MX6UL_PAD_NAND_WE_B = 95, + MX6UL_PAD_NAND_DATA00 = 96, + MX6UL_PAD_NAND_DATA01 = 97, + MX6UL_PAD_NAND_DATA02 = 98, + MX6UL_PAD_NAND_DATA03 = 99, + MX6UL_PAD_NAND_DATA04 = 100, + MX6UL_PAD_NAND_DATA05 = 101, + MX6UL_PAD_NAND_DATA06 = 102, + MX6UL_PAD_NAND_DATA07 = 103, + MX6UL_PAD_NAND_ALE = 104, + MX6UL_PAD_NAND_WP_B = 105, + MX6UL_PAD_NAND_READY_B = 106, + MX6UL_PAD_NAND_CE0_B = 107, + MX6UL_PAD_NAND_CE1_B = 108, + MX6UL_PAD_NAND_CLE = 109, + MX6UL_PAD_NAND_DQS = 110, + MX6UL_PAD_SD1_CMD = 111, + MX6UL_PAD_SD1_CLK = 112, + MX6UL_PAD_SD1_DATA0 = 113, + MX6UL_PAD_SD1_DATA1 = 114, + MX6UL_PAD_SD1_DATA2 = 115, + MX6UL_PAD_SD1_DATA3 = 116, + MX6UL_PAD_CSI_MCLK = 117, + MX6UL_PAD_CSI_PIXCLK = 118, + MX6UL_PAD_CSI_VSYNC = 119, + MX6UL_PAD_CSI_HSYNC = 120, + MX6UL_PAD_CSI_DATA00 = 121, + MX6UL_PAD_CSI_DATA01 = 122, + MX6UL_PAD_CSI_DATA02 = 123, + MX6UL_PAD_CSI_DATA03 = 124, + MX6UL_PAD_CSI_DATA04 = 125, + MX6UL_PAD_CSI_DATA05 = 126, + MX6UL_PAD_CSI_DATA06 = 127, + MX6UL_PAD_CSI_DATA07 = 128, +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx6ul_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE0), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE1), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE2), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE3), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE4), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE5), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE6), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE7), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE8), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE9), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE10), + IMX_PINCTRL_PIN(MX6UL_PAD_SNVS_TAMPER4), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE12), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE13), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE14), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE15), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE16), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_MOD), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_TMS), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_TDO), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_TDI), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_TCK), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_TRST_B), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO00), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO01), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO02), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO03), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO04), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO05), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO06), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO07), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO08), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO09), + IMX_PINCTRL_PIN(MX6UL_PAD_UART1_TX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART1_RX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART1_CTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART1_RTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART2_TX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART2_RX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART2_CTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART2_RTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART3_TX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART3_RX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART3_CTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART3_RTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART4_TX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART4_RX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART5_TX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART5_RX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_RX_DATA0), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_RX_DATA1), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_RX_EN), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_TX_DATA0), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_TX_DATA1), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_TX_EN), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_TX_CLK), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_RX_ER), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_RX_DATA0), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_RX_DATA1), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_RX_EN), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_TX_DATA0), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_TX_DATA1), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_TX_EN), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_TX_CLK), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_RX_ER), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_CLK), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_ENABLE), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_HSYNC), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_VSYNC), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_RESET), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA00), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA01), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA02), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA03), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA04), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA05), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA06), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA07), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA08), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA09), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA10), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA11), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA12), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA13), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA14), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA15), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA16), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA17), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA18), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA19), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA20), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA21), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA22), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA23), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_RE_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_WE_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA00), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA01), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA02), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA03), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA04), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA05), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA06), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA07), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_ALE), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_WP_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_READY_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_CE0_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_CE1_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_CLE), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DQS), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_CMD), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_CLK), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_DATA0), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_DATA1), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_DATA2), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_DATA3), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_MCLK), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_PIXCLK), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_VSYNC), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_HSYNC), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA00), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA01), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA02), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA03), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA04), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA05), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA06), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA07), +}; + +static struct imx_pinctrl_soc_info imx6ul_pinctrl_info = { + .pins = imx6ul_pinctrl_pads, + .npins = ARRAY_SIZE(imx6ul_pinctrl_pads), +}; + +static struct of_device_id imx6ul_pinctrl_of_match[] = { + { .compatible = "fsl,imx6ul-iomuxc", }, + { /* sentinel */ } +}; + +static int imx6ul_pinctrl_probe(struct platform_device *pdev) +{ + return imx_pinctrl_probe(pdev, &imx6ul_pinctrl_info); +} + +static struct platform_driver imx6ul_pinctrl_driver = { + .driver = { + .name = "imx6ul-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(imx6ul_pinctrl_of_match), + }, + .probe = imx6ul_pinctrl_probe, + .remove = imx_pinctrl_remove, +}; + +static int __init imx6ul_pinctrl_init(void) +{ + return platform_driver_register(&imx6ul_pinctrl_driver); +} +arch_initcall(imx6ul_pinctrl_init); + +static void __exit imx6ul_pinctrl_exit(void) +{ + platform_driver_unregister(&imx6ul_pinctrl_driver); +} +module_exit(imx6ul_pinctrl_exit); + +MODULE_AUTHOR("Anson Huang "); +MODULE_DESCRIPTION("Freescale imx6ul pinctrl driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From fb00de771b0c35fc42212272596ddb07bf120b21 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jun 2015 14:42:45 +0900 Subject: pinctrl: simplify of_pinctrl_get() This commit does not change the logic at all. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/devicetree.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index 0bbf7d71b281..fe04e748dfe4 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -97,13 +97,7 @@ static int dt_remember_or_free_map(struct pinctrl *p, const char *statename, struct pinctrl_dev *of_pinctrl_get(struct device_node *np) { - struct pinctrl_dev *pctldev; - - pctldev = get_pinctrl_dev_from_of_node(np); - if (!pctldev) - return NULL; - - return pctldev; + return get_pinctrl_dev_from_of_node(np); } static int dt_to_map_one_config(struct pinctrl *p, const char *statename, -- cgit v1.3-6-gb490 From ba5f94cd566ac562c9374729baab156886759946 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 17 Jun 2015 23:47:25 -0700 Subject: pinctrl: qcom: spmi-mpp: Transition to generic dt binding parser Use the newly introduced extensible generic dt parser instead of rolling our own dt parsing functions. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 130 ++++---------------------------- 1 file changed, 16 insertions(+), 114 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 3121de9b6331..b247a17bc2af 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -129,15 +129,17 @@ struct pmic_mpp_state { struct gpio_chip chip; }; -struct pmic_mpp_bindings { - const char *property; - unsigned param; +static const struct pinconf_generic_params pmic_mpp_bindings[] = { + {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE, 0}, + {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE, 0}, }; -static struct pmic_mpp_bindings pmic_mpp_bindings[] = { - {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE}, - {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE}, +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item pmic_conf_items[] = { + PCONFDUMP(PMIC_MPP_CONF_AMUX_ROUTE, "analog mux", NULL, true), + PCONFDUMP(PMIC_MPP_CONF_ANALOG_MODE, "analog output", NULL, false), }; +#endif static const char *const pmic_mpp_groups[] = { "mpp1", "mpp2", "mpp3", "mpp4", "mpp5", "mpp6", "mpp7", "mpp8", @@ -204,118 +206,11 @@ static int pmic_mpp_get_group_pins(struct pinctrl_dev *pctldev, return 0; } -static int pmic_mpp_parse_dt_config(struct device_node *np, - struct pinctrl_dev *pctldev, - unsigned long **configs, - unsigned int *nconfs) -{ - struct pmic_mpp_bindings *par; - unsigned long cfg; - int ret, i; - u32 val; - - for (i = 0; i < ARRAY_SIZE(pmic_mpp_bindings); i++) { - par = &pmic_mpp_bindings[i]; - ret = of_property_read_u32(np, par->property, &val); - - /* property not found */ - if (ret == -EINVAL) - continue; - - /* use zero as default value, when no value is specified */ - if (ret) - val = 0; - - dev_dbg(pctldev->dev, "found %s with value %u\n", - par->property, val); - - cfg = pinconf_to_config_packed(par->param, val); - - ret = pinctrl_utils_add_config(pctldev, configs, nconfs, cfg); - if (ret) - return ret; - } - - return 0; -} - -static int pmic_mpp_dt_subnode_to_map(struct pinctrl_dev *pctldev, - struct device_node *np, - struct pinctrl_map **map, - unsigned *reserv, unsigned *nmaps, - enum pinctrl_map_type type) -{ - unsigned long *configs = NULL; - unsigned nconfs = 0; - struct property *prop; - const char *group; - int ret; - - ret = pmic_mpp_parse_dt_config(np, pctldev, &configs, &nconfs); - if (ret < 0) - return ret; - - if (!nconfs) - return 0; - - ret = of_property_count_strings(np, "pins"); - if (ret < 0) - goto exit; - - ret = pinctrl_utils_reserve_map(pctldev, map, reserv, nmaps, ret); - if (ret < 0) - goto exit; - - of_property_for_each_string(np, "pins", prop, group) { - ret = pinctrl_utils_add_map_configs(pctldev, map, - reserv, nmaps, group, - configs, nconfs, type); - if (ret < 0) - break; - } -exit: - kfree(configs); - return ret; -} - -static int pmic_mpp_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np_config, - struct pinctrl_map **map, unsigned *nmaps) -{ - struct device_node *np; - enum pinctrl_map_type type; - unsigned reserv; - int ret; - - ret = 0; - *map = NULL; - *nmaps = 0; - reserv = 0; - type = PIN_MAP_TYPE_CONFIGS_GROUP; - - for_each_child_of_node(np_config, np) { - ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map, - &reserv, nmaps, type); - if (ret) - break; - - ret = pmic_mpp_dt_subnode_to_map(pctldev, np, map, &reserv, - nmaps, type); - if (ret) - break; - } - - if (ret < 0) - pinctrl_utils_dt_free_map(pctldev, *map, *nmaps); - - return ret; -} - static const struct pinctrl_ops pmic_mpp_pinctrl_ops = { .get_groups_count = pmic_mpp_get_groups_count, .get_group_name = pmic_mpp_get_group_name, .get_group_pins = pmic_mpp_get_group_pins, - .dt_node_to_map = pmic_mpp_dt_node_to_map, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, .dt_free_map = pinctrl_utils_dt_free_map, }; @@ -594,6 +489,7 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, } static const struct pinconf_ops pmic_mpp_pinconf_ops = { + .is_generic = true, .pin_config_group_get = pmic_mpp_config_get, .pin_config_group_set = pmic_mpp_config_set, .pin_config_group_dbg_show = pmic_mpp_config_dbg_show, @@ -866,6 +762,12 @@ static int pmic_mpp_probe(struct platform_device *pdev) pctrldesc->pins = pindesc; pctrldesc->npins = npins; + pctrldesc->num_custom_params = ARRAY_SIZE(pmic_mpp_bindings); + pctrldesc->custom_params = pmic_mpp_bindings; +#ifdef CONFIG_DEBUG_FS + pctrldesc->custom_conf_items = pmic_conf_items; +#endif + for (i = 0; i < npins; i++, pindesc++) { pad = &pads[i]; pindesc->drv_data = pad; -- cgit v1.3-6-gb490 From 7682b3740dd7e3039ec9885b423f7e68f0dc24d0 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 17 Jun 2015 23:47:26 -0700 Subject: pinctrl: qcom: spmi-mpp: Fixes related to enable handling There's currently no way to re-enable a mpp block once you've entered a state that disables the state, this patch makes it possible to leave the bias-high-impedance state. Also read the enable state from the hardware on probe. With this in place the is_enabled variable is accurately tracking the state of the hardware and we can use that for the debug output as well. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index b247a17bc2af..6d9abeea810d 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -354,6 +354,9 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, pad = pctldev->desc->pins[pin].drv_data; + /* Make it possible to enable the pin, by not setting high impedance */ + pad->is_enabled = true; + for (i = 0; i < nconfs; i++) { param = pinconf_to_config_param(configs[i]); arg = pinconf_to_config_argument(configs[i]); @@ -445,7 +448,13 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT; val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK; - return pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); + ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); + if (ret < 0) + return ret; + + val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT; + + return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val); } static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, @@ -453,7 +462,7 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, { struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); struct pmic_mpp_pad *pad; - int ret, val; + int ret; static const char *const biases[] = { "0.6kOhm", "10kOhm", "30kOhm", "Disabled" @@ -464,9 +473,7 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, seq_printf(s, " mpp%-2d:", pin + PMIC_MPP_PHYSICAL_OFFSET); - val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL); - - if (val < 0 || !(val >> PMIC_MPP_REG_MASTER_EN_SHIFT)) { + if (!pad->is_enabled) { seq_puts(s, " ---"); } else { @@ -706,8 +713,12 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, pad->amux_input = val >> PMIC_MPP_REG_AIN_ROUTE_SHIFT; pad->amux_input &= PMIC_MPP_REG_AIN_ROUTE_MASK; - /* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */ - pad->is_enabled = true; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL); + if (val < 0) + return val; + + pad->is_enabled = !!val; + return 0; } -- cgit v1.3-6-gb490 From eaaf5dd46457c4fa3a9e2d1be775821d4e72773c Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 17 Jun 2015 23:47:27 -0700 Subject: pinctrl: qcom: spmi-mpp: Introduce defines for MODE_CTL Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 6d9abeea810d..745c37dea7d0 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -85,6 +85,14 @@ #define PMIC_MPP_REG_AIN_ROUTE_SHIFT 0 #define PMIC_MPP_REG_AIN_ROUTE_MASK 0x7 +#define PMIC_MPP_MODE_DIGITAL_INPUT 0 +#define PMIC_MPP_MODE_DIGITAL_OUTPUT 1 +#define PMIC_MPP_MODE_DIGITAL_BIDIR 2 +#define PMIC_MPP_MODE_ANALOG_BIDIR 3 +#define PMIC_MPP_MODE_ANALOG_INPUT 4 +#define PMIC_MPP_MODE_ANALOG_OUTPUT 5 +#define PMIC_MPP_MODE_CURRENT_SINK 6 + #define PMIC_MPP_PHYSICAL_OFFSET 1 /* Qualcomm specific pin configurations */ @@ -248,20 +256,20 @@ static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, pad->function = function; if (!pad->analog_mode) { - val = 0; /* just digital input */ + val = PMIC_MPP_MODE_DIGITAL_INPUT; if (pad->output_enabled) { if (pad->input_enabled) - val = 2; /* digital input and output */ + val = PMIC_MPP_MODE_DIGITAL_BIDIR; else - val = 1; /* just digital output */ + val = PMIC_MPP_MODE_DIGITAL_OUTPUT; } } else { - val = 4; /* just analog input */ + val = PMIC_MPP_MODE_ANALOG_INPUT; if (pad->output_enabled) { if (pad->input_enabled) - val = 3; /* analog input and output */ + val = PMIC_MPP_MODE_ANALOG_BIDIR; else - val = 5; /* just analog output */ + val = PMIC_MPP_MODE_ANALOG_OUTPUT; } } @@ -654,32 +662,32 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, dir &= PMIC_MPP_REG_MODE_DIR_MASK; switch (dir) { - case 0: + case PMIC_MPP_MODE_DIGITAL_INPUT: pad->input_enabled = true; pad->output_enabled = false; pad->analog_mode = false; break; - case 1: + case PMIC_MPP_MODE_DIGITAL_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; pad->analog_mode = false; break; - case 2: + case PMIC_MPP_MODE_DIGITAL_BIDIR: pad->input_enabled = true; pad->output_enabled = true; pad->analog_mode = false; break; - case 3: + case PMIC_MPP_MODE_ANALOG_BIDIR: pad->input_enabled = true; pad->output_enabled = true; pad->analog_mode = true; break; - case 4: + case PMIC_MPP_MODE_ANALOG_INPUT: pad->input_enabled = true; pad->output_enabled = false; pad->analog_mode = true; break; - case 5: + case PMIC_MPP_MODE_ANALOG_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; pad->analog_mode = true; -- cgit v1.3-6-gb490 From 0e948042c4203b97e44370993ef042c945308282 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 17 Jun 2015 23:47:28 -0700 Subject: pinctrl: qcom: spmi-mpp: Implement support for sink mode The MPP supports three modes; digital, analog and sink mode. This patch implements support for the latter. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/qcom,pmic-mpp.txt | 5 + drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 115 +++++++++++++-------- 2 files changed, 76 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt index ed19991aad35..d29fb96a57d3 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt @@ -134,6 +134,11 @@ to specify in a pin configuration subnode: and/or output-high, output-low MPP could operate as Bidirectional Logic, Analog Input, Analog Output. +- qcom,sink-mode: + Usage: optional + Value type: or + Definition: Selects sink mode of operation + - qcom,amux-route: Usage: optional Value type: diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 745c37dea7d0..9dde023640ba 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -62,6 +62,7 @@ #define PMIC_MPP_REG_DIG_IN_CTL 0x43 #define PMIC_MPP_REG_EN_CTL 0x46 #define PMIC_MPP_REG_AIN_CTL 0x4a +#define PMIC_MPP_REG_SINK_CTL 0x4c /* PMIC_MPP_REG_MODE_CTL */ #define PMIC_MPP_REG_MODE_VALUE_MASK 0x1 @@ -98,6 +99,7 @@ /* Qualcomm specific pin configurations */ #define PMIC_MPP_CONF_AMUX_ROUTE (PIN_CONFIG_END + 1) #define PMIC_MPP_CONF_ANALOG_MODE (PIN_CONFIG_END + 2) +#define PMIC_MPP_CONF_SINK_MODE (PIN_CONFIG_END + 3) /** * struct pmic_mpp_pad - keep current MPP settings @@ -109,11 +111,13 @@ * @input_enabled: Set to true if MPP input buffer logic is enabled. * @analog_mode: Set to true when MPP should operate in Analog Input, Analog * Output or Bidirectional Analog mode. + * @sink_mode: Boolean indicating if ink mode is slected * @num_sources: Number of power-sources supported by this MPP. * @power_source: Current power-source used. * @amux_input: Set the source for analog input. * @pullup: Pullup resistor value. Valid in Bidirectional mode only. * @function: See pmic_mpp_functions[]. + * @drive_strength: Amount of current in sink mode */ struct pmic_mpp_pad { u16 base; @@ -123,11 +127,13 @@ struct pmic_mpp_pad { bool output_enabled; bool input_enabled; bool analog_mode; + bool sink_mode; unsigned int num_sources; unsigned int power_source; unsigned int amux_input; unsigned int pullup; unsigned int function; + unsigned int drive_strength; }; struct pmic_mpp_state { @@ -140,12 +146,14 @@ struct pmic_mpp_state { static const struct pinconf_generic_params pmic_mpp_bindings[] = { {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE, 0}, {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE, 0}, + {"qcom,sink-mode", PMIC_MPP_CONF_SINK_MODE, 0}, }; #ifdef CONFIG_DEBUG_FS static const struct pin_config_item pmic_conf_items[] = { PCONFDUMP(PMIC_MPP_CONF_AMUX_ROUTE, "analog mux", NULL, true), PCONFDUMP(PMIC_MPP_CONF_ANALOG_MODE, "analog output", NULL, false), + PCONFDUMP(PMIC_MPP_CONF_SINK_MODE, "sink mode", NULL, false), }; #endif @@ -243,33 +251,28 @@ static int pmic_mpp_get_function_groups(struct pinctrl_dev *pctldev, return 0; } -static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, - unsigned pin) +static int pmic_mpp_write_mode_ctl(struct pmic_mpp_state *state, + struct pmic_mpp_pad *pad) { - struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); - struct pmic_mpp_pad *pad; unsigned int val; - int ret; - - pad = pctldev->desc->pins[pin].drv_data; - - pad->function = function; - if (!pad->analog_mode) { - val = PMIC_MPP_MODE_DIGITAL_INPUT; + if (pad->analog_mode) { + val = PMIC_MPP_MODE_ANALOG_INPUT; if (pad->output_enabled) { if (pad->input_enabled) - val = PMIC_MPP_MODE_DIGITAL_BIDIR; + val = PMIC_MPP_MODE_ANALOG_BIDIR; else - val = PMIC_MPP_MODE_DIGITAL_OUTPUT; + val = PMIC_MPP_MODE_ANALOG_OUTPUT; } + } else if (pad->sink_mode) { + val = PMIC_MPP_MODE_CURRENT_SINK; } else { - val = PMIC_MPP_MODE_ANALOG_INPUT; + val = PMIC_MPP_MODE_DIGITAL_INPUT; if (pad->output_enabled) { if (pad->input_enabled) - val = PMIC_MPP_MODE_ANALOG_BIDIR; + val = PMIC_MPP_MODE_DIGITAL_BIDIR; else - val = PMIC_MPP_MODE_ANALOG_OUTPUT; + val = PMIC_MPP_MODE_DIGITAL_OUTPUT; } } @@ -277,9 +280,22 @@ static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT; val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK; - ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); - if (ret < 0) - return ret; + return pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); +} + +static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, + unsigned pin) +{ + struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); + struct pmic_mpp_pad *pad; + unsigned int val; + int ret; + + pad = pctldev->desc->pins[pin].drv_data; + + pad->function = function; + + ret = pmic_mpp_write_mode_ctl(state, pad); val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT; @@ -339,9 +355,15 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, case PMIC_MPP_CONF_AMUX_ROUTE: arg = pad->amux_input; break; + case PIN_CONFIG_DRIVE_STRENGTH: + arg = pad->drive_strength; + break; case PMIC_MPP_CONF_ANALOG_MODE: arg = pad->analog_mode; break; + case PMIC_MPP_CONF_SINK_MODE: + arg = pad->sink_mode; + break; default: return -EINVAL; } @@ -403,13 +425,19 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, pad->output_enabled = true; pad->out_value = arg; break; + case PIN_CONFIG_DRIVE_STRENGTH: + arg = pad->drive_strength; + break; case PMIC_MPP_CONF_AMUX_ROUTE: if (arg >= PMIC_MPP_AMUX_ROUTE_ABUS4) return -EINVAL; pad->amux_input = arg; break; case PMIC_MPP_CONF_ANALOG_MODE: - pad->analog_mode = true; + pad->analog_mode = !!arg; + break; + case PMIC_MPP_CONF_SINK_MODE: + pad->sink_mode = !!arg; break; default: return -EINVAL; @@ -434,29 +462,7 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, if (ret < 0) return ret; - if (!pad->analog_mode) { - val = 0; /* just digital input */ - if (pad->output_enabled) { - if (pad->input_enabled) - val = 2; /* digital input and output */ - else - val = 1; /* just digital output */ - } - } else { - val = 4; /* just analog input */ - if (pad->output_enabled) { - if (pad->input_enabled) - val = 3; /* analog input and output */ - else - val = 5; /* just analog output */ - } - } - - val = val << PMIC_MPP_REG_MODE_DIR_SHIFT; - val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT; - val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK; - - ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); + ret = pmic_mpp_write_mode_ctl(state, pad); if (ret < 0) return ret; @@ -476,6 +482,9 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, "0.6kOhm", "10kOhm", "30kOhm", "Disabled" }; + static const char *const modes[] = { + "digital", "analog", "sink" + }; pad = pctldev->desc->pins[pin].drv_data; @@ -495,7 +504,7 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, } seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); - seq_printf(s, " %-4s", pad->analog_mode ? "ana" : "dig"); + seq_printf(s, " %-7s", modes[pad->analog_mode ? 1 : (pad->sink_mode ? 2 : 0)]); seq_printf(s, " %-7s", pmic_mpp_functions[pad->function]); seq_printf(s, " vin-%d", pad->power_source); seq_printf(s, " %-8s", biases[pad->pullup]); @@ -666,31 +675,43 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, pad->input_enabled = true; pad->output_enabled = false; pad->analog_mode = false; + pad->sink_mode = false; break; case PMIC_MPP_MODE_DIGITAL_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; pad->analog_mode = false; + pad->sink_mode = false; break; case PMIC_MPP_MODE_DIGITAL_BIDIR: pad->input_enabled = true; pad->output_enabled = true; pad->analog_mode = false; + pad->sink_mode = false; break; case PMIC_MPP_MODE_ANALOG_BIDIR: pad->input_enabled = true; pad->output_enabled = true; pad->analog_mode = true; + pad->sink_mode = false; break; case PMIC_MPP_MODE_ANALOG_INPUT: pad->input_enabled = true; pad->output_enabled = false; pad->analog_mode = true; + pad->sink_mode = false; break; case PMIC_MPP_MODE_ANALOG_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; pad->analog_mode = true; + pad->sink_mode = false; + break; + case PMIC_MPP_MODE_CURRENT_SINK: + pad->input_enabled = false; + pad->output_enabled = true; + pad->analog_mode = false; + pad->sink_mode = true; break; default: dev_err(state->dev, "unknown MPP direction\n"); @@ -721,6 +742,12 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, pad->amux_input = val >> PMIC_MPP_REG_AIN_ROUTE_SHIFT; pad->amux_input &= PMIC_MPP_REG_AIN_ROUTE_MASK; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_SINK_CTL); + if (val < 0) + return val; + + pad->drive_strength = val; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL); if (val < 0) return val; -- cgit v1.3-6-gb490 From 6e908892025885b07e804dc6c05aab6ce1e06832 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:01 +0900 Subject: pinctrl: UniPhier: add UniPhier pinctrl core support The core support for the pinctrl drivers for all the UniPhier SoCs. Changes in v2: - drop vogus THIS_MODULE because this file is always built-in - drop vogus "include because this file is always built-in Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/uniphier/Kconfig | 8 + drivers/pinctrl/uniphier/Makefile | 1 + drivers/pinctrl/uniphier/pinctrl-uniphier-core.c | 684 +++++++++++++++++++++++ drivers/pinctrl/uniphier/pinctrl-uniphier.h | 217 +++++++ 6 files changed, 912 insertions(+) create mode 100644 drivers/pinctrl/uniphier/Kconfig create mode 100644 drivers/pinctrl/uniphier/Makefile create mode 100644 drivers/pinctrl/uniphier/pinctrl-uniphier-core.c create mode 100644 drivers/pinctrl/uniphier/pinctrl-uniphier.h (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 100d9ac2ae1f..e6362c61b560 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -240,6 +240,7 @@ source "drivers/pinctrl/samsung/Kconfig" source "drivers/pinctrl/sh-pfc/Kconfig" source "drivers/pinctrl/spear/Kconfig" source "drivers/pinctrl/sunxi/Kconfig" +source "drivers/pinctrl/uniphier/Kconfig" source "drivers/pinctrl/vt8500/Kconfig" source "drivers/pinctrl/mediatek/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f4216d9347e2..f6710a8a1503 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -51,5 +51,6 @@ obj-$(CONFIG_PINCTRL_SAMSUNG) += samsung/ obj-$(CONFIG_PINCTRL_SH_PFC) += sh-pfc/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ +obj-$(CONFIG_ARCH_UNIPHIER) += uniphier/ obj-$(CONFIG_ARCH_VT8500) += vt8500/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig new file mode 100644 index 000000000000..37e39c8dd030 --- /dev/null +++ b/drivers/pinctrl/uniphier/Kconfig @@ -0,0 +1,8 @@ +if ARCH_UNIPHIER + +config PINCTRL_UNIPHIER_CORE + bool + select PINMUX + select GENERIC_PINCONF + +endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile new file mode 100644 index 000000000000..748aa1b4e420 --- /dev/null +++ b/drivers/pinctrl/uniphier/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c new file mode 100644 index 000000000000..918f3b643f1b --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c @@ -0,0 +1,684 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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 +#include +#include +#include +#include + +#include "../core.h" +#include "../pinctrl-utils.h" +#include "pinctrl-uniphier.h" + +struct uniphier_pinctrl_priv { + struct pinctrl_dev *pctldev; + struct regmap *regmap; + struct uniphier_pinctrl_socdata *socdata; +}; + +static int uniphier_pctl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + return priv->socdata->groups_count; +} + +static const char *uniphier_pctl_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + return priv->socdata->groups[selector].name; +} + +static int uniphier_pctl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + *pins = priv->socdata->groups[selector].pins; + *num_pins = priv->socdata->groups[selector].num_pins; + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned offset) +{ + const struct pinctrl_pin_desc *pin = &pctldev->desc->pins[offset]; + const char *pull_dir, *drv_str; + + switch (uniphier_pin_get_pull_dir(pin->drv_data)) { + case UNIPHIER_PIN_PULL_UP: + pull_dir = "UP"; + break; + case UNIPHIER_PIN_PULL_DOWN: + pull_dir = "DOWN"; + break; + case UNIPHIER_PIN_PULL_NONE: + pull_dir = "NONE"; + break; + default: + BUG(); + } + + switch (uniphier_pin_get_drv_str(pin->drv_data)) { + case UNIPHIER_PIN_DRV_4_8: + drv_str = "4/8(mA)"; + break; + case UNIPHIER_PIN_DRV_8_12_16_20: + drv_str = "8/12/16/20(mA)"; + break; + case UNIPHIER_PIN_DRV_FIXED_4: + drv_str = "4(mA)"; + break; + case UNIPHIER_PIN_DRV_FIXED_5: + drv_str = "5(mA)"; + break; + case UNIPHIER_PIN_DRV_FIXED_8: + drv_str = "8(mA)"; + break; + case UNIPHIER_PIN_DRV_NONE: + drv_str = "NONE"; + break; + default: + BUG(); + } + + seq_printf(s, " PULL_DIR=%s DRV_STR=%s", pull_dir, drv_str); +} +#endif + +static const struct pinctrl_ops uniphier_pctlops = { + .get_groups_count = uniphier_pctl_get_groups_count, + .get_group_name = uniphier_pctl_get_group_name, + .get_group_pins = uniphier_pctl_get_group_pins, +#ifdef CONFIG_DEBUG_FS + .pin_dbg_show = uniphier_pctl_pin_dbg_show, +#endif + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin, + enum pin_config_param param) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + enum uniphier_pin_pull_dir pull_dir = + uniphier_pin_get_pull_dir(pin->drv_data); + unsigned int pupdctrl, reg, shift, val; + unsigned int expected = 1; + int ret; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (pull_dir == UNIPHIER_PIN_PULL_NONE) + return 0; + if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || + pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) + return -EINVAL; + expected = 0; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED) + return 0; + if (pull_dir != UNIPHIER_PIN_PULL_UP) + return -EINVAL; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) + return 0; + if (pull_dir != UNIPHIER_PIN_PULL_DOWN) + return -EINVAL; + break; + default: + BUG(); + } + + pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data); + + reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; + shift = pupdctrl % 32; + + ret = regmap_read(priv->regmap, reg, &val); + if (ret) + return ret; + + val = (val >> shift) & 1; + + return (val == expected) ? 0 : -EINVAL; +} + +static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin, + u16 *strength) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + enum uniphier_pin_drv_str drv_str = + uniphier_pin_get_drv_str(pin->drv_data); + const unsigned int strength_4_8[] = {4, 8}; + const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20}; + const unsigned int *supported_strength; + unsigned int drvctrl, reg, shift, mask, width, val; + int ret; + + switch (drv_str) { + case UNIPHIER_PIN_DRV_4_8: + supported_strength = strength_4_8; + width = 1; + break; + case UNIPHIER_PIN_DRV_8_12_16_20: + supported_strength = strength_8_12_16_20; + width = 2; + break; + case UNIPHIER_PIN_DRV_FIXED_4: + *strength = 4; + return 0; + case UNIPHIER_PIN_DRV_FIXED_5: + *strength = 5; + return 0; + case UNIPHIER_PIN_DRV_FIXED_8: + *strength = 8; + return 0; + default: + /* drive strength control is not supported for this pin */ + return -EINVAL; + } + + drvctrl = uniphier_pin_get_drvctrl(pin->drv_data); + drvctrl *= width; + + reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE : + UNIPHIER_PINCTRL_DRVCTRL_BASE; + + reg += drvctrl / 32 * 4; + shift = drvctrl % 32; + mask = (1U << width) - 1; + + ret = regmap_read(priv->regmap, reg, &val); + if (ret) + return ret; + + *strength = supported_strength[(val >> shift) & mask]; + + return 0; +} + +static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data); + unsigned int val; + int ret; + + if (iectrl == UNIPHIER_PIN_IECTRL_NONE) + /* This pin is always input-enabled. */ + return 0; + + ret = regmap_read(priv->regmap, UNIPHIER_PINCTRL_IECTRL, &val); + if (ret) + return ret; + + return val & BIT(iectrl) ? 0 : -EINVAL; +} + +static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs) +{ + const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin]; + enum pin_config_param param = pinconf_to_config_param(*configs); + bool has_arg = false; + u16 arg; + int ret; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = uniphier_conf_pin_bias_get(pctldev, pin_desc, param); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + ret = uniphier_conf_pin_drive_get(pctldev, pin_desc, &arg); + has_arg = true; + break; + case PIN_CONFIG_INPUT_ENABLE: + ret = uniphier_conf_pin_input_enable_get(pctldev, pin_desc); + break; + default: + /* unsupported parameter */ + ret = -EINVAL; + break; + } + + if (ret == 0 && has_arg) + *configs = pinconf_to_config_packed(param, arg); + + return ret; +} + +static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin, + enum pin_config_param param, + u16 arg) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + enum uniphier_pin_pull_dir pull_dir = + uniphier_pin_get_pull_dir(pin->drv_data); + unsigned int pupdctrl, reg, shift; + unsigned int val = 1; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (pull_dir == UNIPHIER_PIN_PULL_NONE) + return 0; + if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || + pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) { + dev_err(pctldev->dev, + "can not disable pull register for pin %u (%s)\n", + pin->number, pin->name); + return -EINVAL; + } + val = 0; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED && arg != 0) + return 0; + if (pull_dir != UNIPHIER_PIN_PULL_UP) { + dev_err(pctldev->dev, + "pull-up is unsupported for pin %u (%s)\n", + pin->number, pin->name); + return -EINVAL; + } + if (arg == 0) { + dev_err(pctldev->dev, "pull-up can not be total\n"); + return -EINVAL; + } + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED && arg != 0) + return 0; + if (pull_dir != UNIPHIER_PIN_PULL_DOWN) { + dev_err(pctldev->dev, + "pull-down is unsupported for pin %u (%s)\n", + pin->number, pin->name); + return -EINVAL; + } + if (arg == 0) { + dev_err(pctldev->dev, "pull-down can not be total\n"); + return -EINVAL; + } + break; + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + if (pull_dir == UNIPHIER_PIN_PULL_NONE) { + dev_err(pctldev->dev, + "pull-up/down is unsupported for pin %u (%s)\n", + pin->number, pin->name); + return -EINVAL; + } + + if (arg == 0) + return 0; /* configuration ingored */ + break; + default: + BUG(); + } + + pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data); + + reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; + shift = pupdctrl % 32; + + return regmap_update_bits(priv->regmap, reg, 1 << shift, val << shift); +} + +static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin, + u16 strength) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + enum uniphier_pin_drv_str drv_str = + uniphier_pin_get_drv_str(pin->drv_data); + const unsigned int strength_4_8[] = {4, 8, -1}; + const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20, -1}; + const unsigned int *supported_strength; + unsigned int drvctrl, reg, shift, mask, width, val; + + switch (drv_str) { + case UNIPHIER_PIN_DRV_4_8: + supported_strength = strength_4_8; + width = 1; + break; + case UNIPHIER_PIN_DRV_8_12_16_20: + supported_strength = strength_8_12_16_20; + width = 2; + break; + default: + dev_err(pctldev->dev, + "cannot change drive strength for pin %u (%s)\n", + pin->number, pin->name); + return -EINVAL; + } + + for (val = 0; supported_strength[val] > 0; val++) { + if (supported_strength[val] > strength) + break; + } + + if (val == 0) { + dev_err(pctldev->dev, + "unsupported drive strength %u mA for pin %u (%s)\n", + strength, pin->number, pin->name); + return -EINVAL; + } + + val--; + + drvctrl = uniphier_pin_get_drvctrl(pin->drv_data); + drvctrl *= width; + + reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE : + UNIPHIER_PINCTRL_DRVCTRL_BASE; + + reg += drvctrl / 32 * 4; + shift = drvctrl % 32; + mask = (1U << width) - 1; + + return regmap_update_bits(priv->regmap, reg, + mask << shift, val << shift); +} + +static int uniphier_conf_pin_input_enable(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin, + u16 enable) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data); + + if (enable == 0) { + /* + * Multiple pins share one input enable, so per-pin disabling + * is impossible. + */ + dev_err(pctldev->dev, "unable to disable input\n"); + return -EINVAL; + } + + if (iectrl == UNIPHIER_PIN_IECTRL_NONE) + /* This pin is always input-enabled. nothing to do. */ + return 0; + + return regmap_update_bits(priv->regmap, UNIPHIER_PINCTRL_IECTRL, + BIT(iectrl), BIT(iectrl)); +} + +static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs, + unsigned num_configs) +{ + const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin]; + int i, ret; + + for (i = 0; i < num_configs; i++) { + enum pin_config_param param = + pinconf_to_config_param(configs[i]); + u16 arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + ret = uniphier_conf_pin_bias_set(pctldev, pin_desc, + param, arg); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + ret = uniphier_conf_pin_drive_set(pctldev, pin_desc, + arg); + break; + case PIN_CONFIG_INPUT_ENABLE: + ret = uniphier_conf_pin_input_enable(pctldev, + pin_desc, arg); + break; + default: + dev_err(pctldev->dev, + "unsupported configuration parameter %u\n", + param); + return -EINVAL; + } + + if (ret) + return ret; + } + + return 0; +} + +static int uniphier_conf_pin_config_group_set(struct pinctrl_dev *pctldev, + unsigned selector, + unsigned long *configs, + unsigned num_configs) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + const unsigned *pins = priv->socdata->groups[selector].pins; + unsigned num_pins = priv->socdata->groups[selector].num_pins; + int i, ret; + + for (i = 0; i < num_pins; i++) { + ret = uniphier_conf_pin_config_set(pctldev, pins[i], + configs, num_configs); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinconf_ops uniphier_confops = { + .is_generic = true, + .pin_config_get = uniphier_conf_pin_config_get, + .pin_config_set = uniphier_conf_pin_config_set, + .pin_config_group_set = uniphier_conf_pin_config_group_set, +}; + +static int uniphier_pmx_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + return priv->socdata->functions_count; +} + +static const char *uniphier_pmx_get_function_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + return priv->socdata->functions[selector].name; +} + +static int uniphier_pmx_get_function_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned *num_groups) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + *groups = priv->socdata->functions[selector].groups; + *num_groups = priv->socdata->functions[selector].num_groups; + + return 0; +} + +static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin, + unsigned muxval) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned mux_bits = priv->socdata->mux_bits; + unsigned reg_stride = priv->socdata->reg_stride; + unsigned reg, reg_end, shift, mask; + int ret; + + reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride; + reg_end = reg + reg_stride; + shift = pin * mux_bits % 32; + mask = (1U << mux_bits) - 1; + + /* + * If reg_stride is greater than 4, the MSB of each pinsel shall be + * stored in the offset+4. + */ + for (; reg < reg_end; reg += 4) { + ret = regmap_update_bits(priv->regmap, reg, + mask << shift, muxval << shift); + if (ret) + return ret; + muxval >>= mux_bits; + } + + if (priv->socdata->load_pinctrl) { + ret = regmap_write(priv->regmap, + UNIPHIER_PINCTRL_LOAD_PINMUX, 1); + if (ret) + return ret; + } + + /* some pins need input-enabling */ + return uniphier_conf_pin_input_enable(pctldev, + &pctldev->desc->pins[pin], 1); +} + +static int uniphier_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned func_selector, + unsigned group_selector) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + const struct uniphier_pinctrl_group *grp = + &priv->socdata->groups[group_selector]; + int i; + int ret; + + for (i = 0; i < grp->num_pins; i++) { + ret = uniphier_pmx_set_one_mux(pctldev, grp->pins[i], + grp->muxvals[i]); + if (ret) + return ret; + } + + return 0; +} + +static int uniphier_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + const struct uniphier_pinctrl_group *groups = priv->socdata->groups; + int groups_count = priv->socdata->groups_count; + enum uniphier_pinmux_gpio_range_type range_type; + int i, j; + + if (strstr(range->name, "irq")) + range_type = UNIPHIER_PINMUX_GPIO_RANGE_IRQ; + else + range_type = UNIPHIER_PINMUX_GPIO_RANGE_PORT; + + for (i = 0; i < groups_count; i++) { + if (groups[i].range_type != range_type) + continue; + + for (j = 0; j < groups[i].num_pins; j++) + if (groups[i].pins[j] == offset) + goto found; + } + + dev_err(pctldev->dev, "pin %u does not support GPIO\n", offset); + return -EINVAL; + +found: + return uniphier_pmx_set_one_mux(pctldev, offset, groups[i].muxvals[j]); +} + +static const struct pinmux_ops uniphier_pmxops = { + .get_functions_count = uniphier_pmx_get_functions_count, + .get_function_name = uniphier_pmx_get_function_name, + .get_function_groups = uniphier_pmx_get_function_groups, + .set_mux = uniphier_pmx_set_mux, + .gpio_request_enable = uniphier_pmx_gpio_request_enable, + .strict = true, +}; + +int uniphier_pinctrl_probe(struct platform_device *pdev, + struct pinctrl_desc *desc, + struct uniphier_pinctrl_socdata *socdata) +{ + struct device *dev = &pdev->dev; + struct uniphier_pinctrl_priv *priv; + + if (!socdata || + !socdata->groups || + !socdata->groups_count || + !socdata->functions || + !socdata->functions_count || + !socdata->mux_bits || + !socdata->reg_stride) { + dev_err(dev, "pinctrl socdata lacks necessary members\n"); + return -EINVAL; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(priv->regmap)) { + dev_err(dev, "failed to get regmap\n"); + return PTR_ERR(priv->regmap); + } + + priv->socdata = socdata; + desc->pctlops = &uniphier_pctlops; + desc->pmxops = &uniphier_pmxops; + desc->confops = &uniphier_confops; + + priv->pctldev = pinctrl_register(desc, dev, priv); + if (IS_ERR(priv->pctldev)) { + dev_err(dev, "failed to register UniPhier pinctrl driver\n"); + return PTR_ERR(priv->pctldev); + } + + platform_set_drvdata(pdev, priv); + + return 0; +} +EXPORT_SYMBOL_GPL(uniphier_pinctrl_probe); + +int uniphier_pinctrl_remove(struct platform_device *pdev) +{ + struct uniphier_pinctrl_priv *priv = platform_get_drvdata(pdev); + + pinctrl_unregister(priv->pctldev); + + return 0; +} +EXPORT_SYMBOL_GPL(uniphier_pinctrl_remove); diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier.h b/drivers/pinctrl/uniphier/pinctrl-uniphier.h new file mode 100644 index 000000000000..e1e98b868be5 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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 __PINCTRL_UNIPHIER_H__ +#define __PINCTRL_UNIPHIER_H__ + +#include +#include +#include + +#define UNIPHIER_PINCTRL_PINMUX_BASE 0x0 +#define UNIPHIER_PINCTRL_LOAD_PINMUX 0x700 +#define UNIPHIER_PINCTRL_DRVCTRL_BASE 0x800 +#define UNIPHIER_PINCTRL_DRV2CTRL_BASE 0x900 +#define UNIPHIER_PINCTRL_PUPDCTRL_BASE 0xa00 +#define UNIPHIER_PINCTRL_IECTRL 0xd00 + +/* input enable control register bit */ +#define UNIPHIER_PIN_IECTRL_SHIFT 0 +#define UNIPHIER_PIN_IECTRL_BITS 8 +#define UNIPHIER_PIN_IECTRL_MASK ((1UL << (UNIPHIER_PIN_IECTRL_BITS)) \ + - 1) + +/* drive strength control register number */ +#define UNIPHIER_PIN_DRVCTRL_SHIFT ((UNIPHIER_PIN_IECTRL_SHIFT) + \ + (UNIPHIER_PIN_IECTRL_BITS)) +#define UNIPHIER_PIN_DRVCTRL_BITS 9 +#define UNIPHIER_PIN_DRVCTRL_MASK ((1UL << (UNIPHIER_PIN_DRVCTRL_BITS)) \ + - 1) + +/* supported drive strength (mA) */ +#define UNIPHIER_PIN_DRV_STR_SHIFT ((UNIPHIER_PIN_DRVCTRL_SHIFT) + \ + (UNIPHIER_PIN_DRVCTRL_BITS)) +#define UNIPHIER_PIN_DRV_STR_BITS 3 +#define UNIPHIER_PIN_DRV_STR_MASK ((1UL << (UNIPHIER_PIN_DRV_STR_BITS)) \ + - 1) + +/* pull-up / pull-down register number */ +#define UNIPHIER_PIN_PUPDCTRL_SHIFT ((UNIPHIER_PIN_DRV_STR_SHIFT) + \ + (UNIPHIER_PIN_DRV_STR_BITS)) +#define UNIPHIER_PIN_PUPDCTRL_BITS 9 +#define UNIPHIER_PIN_PUPDCTRL_MASK ((1UL << (UNIPHIER_PIN_PUPDCTRL_BITS))\ + - 1) + +/* direction of pull register */ +#define UNIPHIER_PIN_PULL_DIR_SHIFT ((UNIPHIER_PIN_PUPDCTRL_SHIFT) + \ + (UNIPHIER_PIN_PUPDCTRL_BITS)) +#define UNIPHIER_PIN_PULL_DIR_BITS 3 +#define UNIPHIER_PIN_PULL_DIR_MASK ((1UL << (UNIPHIER_PIN_PULL_DIR_BITS))\ + - 1) + +#if UNIPHIER_PIN_PULL_DIR_SHIFT + UNIPHIER_PIN_PULL_DIR_BITS > BITS_PER_LONG +#error "unable to pack pin attributes." +#endif + +#define UNIPHIER_PIN_IECTRL_NONE (UNIPHIER_PIN_IECTRL_MASK) + +/* selectable drive strength */ +enum uniphier_pin_drv_str { + UNIPHIER_PIN_DRV_4_8, /* 2 level control: 4/8 mA */ + UNIPHIER_PIN_DRV_8_12_16_20, /* 4 level control: 8/12/16/20 mA */ + UNIPHIER_PIN_DRV_FIXED_4, /* fixed to 4mA */ + UNIPHIER_PIN_DRV_FIXED_5, /* fixed to 5mA */ + UNIPHIER_PIN_DRV_FIXED_8, /* fixed to 8mA */ + UNIPHIER_PIN_DRV_NONE, /* no support (input only pin) */ +}; + +/* direction of pull register (no pin supports bi-directional pull biasing) */ +enum uniphier_pin_pull_dir { + UNIPHIER_PIN_PULL_UP, /* pull-up or disabled */ + UNIPHIER_PIN_PULL_DOWN, /* pull-down or disabled */ + UNIPHIER_PIN_PULL_UP_FIXED, /* always pull-up */ + UNIPHIER_PIN_PULL_DOWN_FIXED, /* always pull-down */ + UNIPHIER_PIN_PULL_NONE, /* no pull register */ +}; + +#define UNIPHIER_PIN_IECTRL(x) \ + (((x) & (UNIPHIER_PIN_IECTRL_MASK)) << (UNIPHIER_PIN_IECTRL_SHIFT)) +#define UNIPHIER_PIN_DRVCTRL(x) \ + (((x) & (UNIPHIER_PIN_DRVCTRL_MASK)) << (UNIPHIER_PIN_DRVCTRL_SHIFT)) +#define UNIPHIER_PIN_DRV_STR(x) \ + (((x) & (UNIPHIER_PIN_DRV_STR_MASK)) << (UNIPHIER_PIN_DRV_STR_SHIFT)) +#define UNIPHIER_PIN_PUPDCTRL(x) \ + (((x) & (UNIPHIER_PIN_PUPDCTRL_MASK)) << (UNIPHIER_PIN_PUPDCTRL_SHIFT)) +#define UNIPHIER_PIN_PULL_DIR(x) \ + (((x) & (UNIPHIER_PIN_PULL_DIR_MASK)) << (UNIPHIER_PIN_PULL_DIR_SHIFT)) + +#define UNIPHIER_PIN_ATTR_PACKED(iectrl, drvctrl, drv_str, pupdctrl, pull_dir)\ + (UNIPHIER_PIN_IECTRL(iectrl) | \ + UNIPHIER_PIN_DRVCTRL(drvctrl) | \ + UNIPHIER_PIN_DRV_STR(drv_str) | \ + UNIPHIER_PIN_PUPDCTRL(pupdctrl) | \ + UNIPHIER_PIN_PULL_DIR(pull_dir)) + +static inline unsigned int uniphier_pin_get_iectrl(void *drv_data) +{ + return ((unsigned long)drv_data >> UNIPHIER_PIN_IECTRL_SHIFT) & + UNIPHIER_PIN_IECTRL_MASK; +} + +static inline unsigned int uniphier_pin_get_drvctrl(void *drv_data) +{ + return ((unsigned long)drv_data >> UNIPHIER_PIN_DRVCTRL_SHIFT) & + UNIPHIER_PIN_DRVCTRL_MASK; +} + +static inline unsigned int uniphier_pin_get_drv_str(void *drv_data) +{ + return ((unsigned long)drv_data >> UNIPHIER_PIN_DRV_STR_SHIFT) & + UNIPHIER_PIN_DRV_STR_MASK; +} + +static inline unsigned int uniphier_pin_get_pupdctrl(void *drv_data) +{ + return ((unsigned long)drv_data >> UNIPHIER_PIN_PUPDCTRL_SHIFT) & + UNIPHIER_PIN_PUPDCTRL_MASK; +} + +static inline unsigned int uniphier_pin_get_pull_dir(void *drv_data) +{ + return ((unsigned long)drv_data >> UNIPHIER_PIN_PULL_DIR_SHIFT) & + UNIPHIER_PIN_PULL_DIR_MASK; +} + +enum uniphier_pinmux_gpio_range_type { + UNIPHIER_PINMUX_GPIO_RANGE_PORT, + UNIPHIER_PINMUX_GPIO_RANGE_IRQ, + UNIPHIER_PINMUX_GPIO_RANGE_NONE, +}; + +struct uniphier_pinctrl_group { + const char *name; + const unsigned *pins; + unsigned num_pins; + const unsigned *muxvals; + enum uniphier_pinmux_gpio_range_type range_type; +}; + +struct uniphier_pinmux_function { + const char *name; + const char * const *groups; + unsigned num_groups; +}; + +struct uniphier_pinctrl_socdata { + const struct uniphier_pinctrl_group *groups; + int groups_count; + const struct uniphier_pinmux_function *functions; + int functions_count; + unsigned mux_bits; + unsigned reg_stride; + bool load_pinctrl; +}; + +#define UNIPHIER_PINCTRL_PIN(a, b, c, d, e, f, g) \ +{ \ + .number = a, \ + .name = b, \ + .drv_data = (void *)UNIPHIER_PIN_ATTR_PACKED(c, d, e, f, g), \ +} + +#define __UNIPHIER_PINCTRL_GROUP(grp, type) \ + { \ + .name = #grp, \ + .pins = grp##_pins, \ + .num_pins = ARRAY_SIZE(grp##_pins), \ + .muxvals = grp##_muxvals + \ + BUILD_BUG_ON_ZERO(ARRAY_SIZE(grp##_pins) != \ + ARRAY_SIZE(grp##_muxvals)), \ + .range_type = type, \ + } + +#define UNIPHIER_PINCTRL_GROUP(grp) \ + __UNIPHIER_PINCTRL_GROUP(grp, UNIPHIER_PINMUX_GPIO_RANGE_NONE) + +#define UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(grp) \ + __UNIPHIER_PINCTRL_GROUP(grp, UNIPHIER_PINMUX_GPIO_RANGE_PORT) + +#define UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(grp) \ + __UNIPHIER_PINCTRL_GROUP(grp, UNIPHIER_PINMUX_GPIO_RANGE_IRQ) + +#define UNIPHIER_PINCTRL_GROUP_SINGLE(grp, array, ofst) \ + { \ + .name = #grp, \ + .pins = array##_pins + ofst, \ + .num_pins = 1, \ + .muxvals = array##_muxvals + ofst, \ + } + +#define UNIPHIER_PINMUX_FUNCTION(func) \ + { \ + .name = #func, \ + .groups = func##_groups, \ + .num_groups = ARRAY_SIZE(func##_groups), \ + } + +struct platform_device; +struct pinctrl_desc; + +int uniphier_pinctrl_probe(struct platform_device *pdev, + struct pinctrl_desc *desc, + struct uniphier_pinctrl_socdata *socdata); + +int uniphier_pinctrl_remove(struct platform_device *pdev); + +#endif /* __PINCTRL_UNIPHIER_H__ */ -- cgit v1.3-6-gb490 From edd95a4a95f32c701e291e06016c6ca110ef65b7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:02 +0900 Subject: pinctrl: UniPhier: add UniPhier PH1-LD4 pinctrl driver Add pin configuration and pinmux support for UniPhier PH1-LD4 SoC. Changes in v2: - sort groups and funcs alphabetically - add missing "emmc_dat8" group - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 2 + drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c | 886 +++++++++++++++++++++++++++++ 3 files changed, 892 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c (limited to 'drivers') diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index 37e39c8dd030..78d25df6d0fd 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -5,4 +5,8 @@ config PINCTRL_UNIPHIER_CORE select PINMUX select GENERIC_PINCONF +config PINCTRL_UNIPHIER_PH1_LD4 + tristate "UniPhier PH1-LD4 SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index 748aa1b4e420..b4bd042ac4f6 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -1 +1,3 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o + +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c b/drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c new file mode 100644 index 000000000000..7beb87e8f499 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c @@ -0,0 +1,886 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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 + +#include "pinctrl-uniphier.h" + +#define DRIVER_NAME "ph1-ld4-pinctrl" + +static const struct pinctrl_pin_desc ph1_ld4_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "EA1", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_4_8, + 8, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "EA2", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_4_8, + 9, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "EA3", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_4_8, + 10, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "EA4", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_4_8, + 11, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "EA5", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_4_8, + 12, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(5, "EA6", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_4_8, + 13, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "EA7", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_4_8, + 14, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "EA8", 0, + 15, UNIPHIER_PIN_DRV_4_8, + 15, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "EA9", 0, + 16, UNIPHIER_PIN_DRV_4_8, + 16, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "EA10", 0, + 17, UNIPHIER_PIN_DRV_4_8, + 17, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "EA11", 0, + 18, UNIPHIER_PIN_DRV_4_8, + 18, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "EA12", 0, + 19, UNIPHIER_PIN_DRV_4_8, + 19, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(12, "EA13", 0, + 20, UNIPHIER_PIN_DRV_4_8, + 20, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(13, "EA14", 0, + 21, UNIPHIER_PIN_DRV_4_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(14, "EA15", 0, + 22, UNIPHIER_PIN_DRV_4_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(15, "ECLK", UNIPHIER_PIN_IECTRL_NONE, + 23, UNIPHIER_PIN_DRV_4_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(16, "XERWE0", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_4_8, + 24, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(17, "XERWE1", UNIPHIER_PIN_IECTRL_NONE, + 25, UNIPHIER_PIN_DRV_4_8, + 25, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(18, "ES0", UNIPHIER_PIN_IECTRL_NONE, + 27, UNIPHIER_PIN_DRV_4_8, + 27, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(19, "ES1", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_4_8, + 28, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(20, "ES2", UNIPHIER_PIN_IECTRL_NONE, + 29, UNIPHIER_PIN_DRV_4_8, + 29, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(21, "XERST", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(22, "MMCCLK", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_8_12_16_20, + 146, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(23, "MMCCMD", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_8_12_16_20, + 147, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(24, "MMCDAT0", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_8_12_16_20, + 148, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(25, "MMCDAT1", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_8_12_16_20, + 149, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(26, "MMCDAT2", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_8_12_16_20, + 150, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(27, "MMCDAT3", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_8_12_16_20, + 151, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(28, "MMCDAT4", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_8_12_16_20, + 152, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(29, "MMCDAT5", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_8_12_16_20, + 153, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(30, "MMCDAT6", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_8_12_16_20, + 154, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(31, "MMCDAT7", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_8_12_16_20, + 155, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(32, "RMII_RXD0", 6, + 39, UNIPHIER_PIN_DRV_4_8, + 39, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(33, "RMII_RXD1", 6, + 40, UNIPHIER_PIN_DRV_4_8, + 40, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(34, "RMII_CRS_DV", 6, + 41, UNIPHIER_PIN_DRV_4_8, + 41, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(35, "RMII_RXER", 6, + 42, UNIPHIER_PIN_DRV_4_8, + 42, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(36, "RMII_REFCLK", 6, + 43, UNIPHIER_PIN_DRV_4_8, + 43, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(37, "RMII_TXD0", 6, + 44, UNIPHIER_PIN_DRV_4_8, + 44, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(38, "RMII_TXD1", 6, + 45, UNIPHIER_PIN_DRV_4_8, + 45, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(39, "RMII_TXEN", 6, + 46, UNIPHIER_PIN_DRV_4_8, + 46, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(40, "MDC", 6, + 47, UNIPHIER_PIN_DRV_4_8, + 47, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(41, "MDIO", 6, + 48, UNIPHIER_PIN_DRV_4_8, + 48, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(42, "MDIO_INTL", 6, + 49, UNIPHIER_PIN_DRV_4_8, + 49, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(43, "PHYRSTL", 6, + 50, UNIPHIER_PIN_DRV_4_8, + 50, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(44, "SDCLK", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_8_12_16_20, + 156, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(45, "SDCMD", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_8_12_16_20, + 157, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(46, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE, + 48, UNIPHIER_PIN_DRV_8_12_16_20, + 158, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(47, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_8_12_16_20, + 159, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(48, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE, + 56, UNIPHIER_PIN_DRV_8_12_16_20, + 160, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(49, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE, + 60, UNIPHIER_PIN_DRV_8_12_16_20, + 161, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(50, "SDCD", UNIPHIER_PIN_IECTRL_NONE, + 51, UNIPHIER_PIN_DRV_4_8, + 51, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(51, "SDWP", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_4_8, + 52, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(52, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE, + 53, UNIPHIER_PIN_DRV_4_8, + 53, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(53, "USB0VBUS", 0, + 54, UNIPHIER_PIN_DRV_4_8, + 54, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(54, "USB0OD", 0, + 55, UNIPHIER_PIN_DRV_4_8, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(55, "USB1VBUS", 0, + 56, UNIPHIER_PIN_DRV_4_8, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(56, "USB1OD", 0, + 57, UNIPHIER_PIN_DRV_4_8, + 57, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(57, "PCRESET", 0, + 58, UNIPHIER_PIN_DRV_4_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "PCREG", 0, + 59, UNIPHIER_PIN_DRV_4_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(59, "PCCE2", 0, + 60, UNIPHIER_PIN_DRV_4_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(60, "PCVS1", 0, + 61, UNIPHIER_PIN_DRV_4_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "PCCD2", 0, + 62, UNIPHIER_PIN_DRV_4_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(62, "PCCD1", 0, + 63, UNIPHIER_PIN_DRV_4_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(63, "PCREADY", 0, + 64, UNIPHIER_PIN_DRV_4_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(64, "PCDOE", 0, + 65, UNIPHIER_PIN_DRV_4_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "PCCE1", 0, + 66, UNIPHIER_PIN_DRV_4_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "PCWE", 0, + 67, UNIPHIER_PIN_DRV_4_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "PCOE", 0, + 68, UNIPHIER_PIN_DRV_4_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "PCWAIT", 0, + 69, UNIPHIER_PIN_DRV_4_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "PCIOWR", 0, + 70, UNIPHIER_PIN_DRV_4_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "PCIORD", 0, + 71, UNIPHIER_PIN_DRV_4_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "HS0DIN0", 0, + 72, UNIPHIER_PIN_DRV_4_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "HS0DIN1", 0, + 73, UNIPHIER_PIN_DRV_4_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "HS0DIN2", 0, + 74, UNIPHIER_PIN_DRV_4_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "HS0DIN3", 0, + 75, UNIPHIER_PIN_DRV_4_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "HS0DIN4", 0, + 76, UNIPHIER_PIN_DRV_4_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "HS0DIN5", 0, + 77, UNIPHIER_PIN_DRV_4_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "HS0DIN6", 0, + 78, UNIPHIER_PIN_DRV_4_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "HS0DIN7", 0, + 79, UNIPHIER_PIN_DRV_4_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "HS0BCLKIN", 0, + 80, UNIPHIER_PIN_DRV_4_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "HS0VALIN", 0, + 81, UNIPHIER_PIN_DRV_4_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "HS0SYNCIN", 0, + 82, UNIPHIER_PIN_DRV_4_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "HSDOUT0", 0, + 83, UNIPHIER_PIN_DRV_4_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "HSDOUT1", 0, + 84, UNIPHIER_PIN_DRV_4_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "HSDOUT2", 0, + 85, UNIPHIER_PIN_DRV_4_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "HSDOUT3", 0, + 86, UNIPHIER_PIN_DRV_4_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "HSDOUT4", 0, + 87, UNIPHIER_PIN_DRV_4_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "HSDOUT5", 0, + 88, UNIPHIER_PIN_DRV_4_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "HSDOUT6", 0, + 89, UNIPHIER_PIN_DRV_4_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "HSDOUT7", 0, + 90, UNIPHIER_PIN_DRV_4_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "HSBCLKOUT", 0, + 91, UNIPHIER_PIN_DRV_4_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "HSVALOUT", 0, + 92, UNIPHIER_PIN_DRV_4_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "HSSYNCOUT", 0, + 93, UNIPHIER_PIN_DRV_4_8, + 93, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "AGCI", 3, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 162, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "AGCR", 4, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 163, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "AGCBS", 5, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 164, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "IECOUT", 0, + 94, UNIPHIER_PIN_DRV_4_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "ASMCK", 0, + 95, UNIPHIER_PIN_DRV_4_8, + 95, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "ABCKO", UNIPHIER_PIN_IECTRL_NONE, + 96, UNIPHIER_PIN_DRV_4_8, + 96, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "ALRCKO", UNIPHIER_PIN_IECTRL_NONE, + 97, UNIPHIER_PIN_DRV_4_8, + 97, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "ASDOUT0", UNIPHIER_PIN_IECTRL_NONE, + 98, UNIPHIER_PIN_DRV_4_8, + 98, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(101, "ARCOUT", 0, + 99, UNIPHIER_PIN_DRV_4_8, + 99, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(103, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(104, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(105, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(106, "DMDSDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(107, "DMDSCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(108, "DMDSDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(109, "DMDSCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(110, "SBO0", UNIPHIER_PIN_IECTRL_NONE, + 100, UNIPHIER_PIN_DRV_4_8, + 100, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(111, "SBI0", UNIPHIER_PIN_IECTRL_NONE, + 101, UNIPHIER_PIN_DRV_4_8, + 101, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(112, "HIN", 1, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(113, "VIN", 2, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(114, "TCON0", UNIPHIER_PIN_IECTRL_NONE, + 102, UNIPHIER_PIN_DRV_4_8, + 102, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(115, "TCON1", UNIPHIER_PIN_IECTRL_NONE, + 103, UNIPHIER_PIN_DRV_4_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(116, "TCON2", UNIPHIER_PIN_IECTRL_NONE, + 104, UNIPHIER_PIN_DRV_4_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(117, "TCON3", UNIPHIER_PIN_IECTRL_NONE, + 105, UNIPHIER_PIN_DRV_4_8, + 105, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(118, "TCON4", UNIPHIER_PIN_IECTRL_NONE, + 106, UNIPHIER_PIN_DRV_4_8, + 106, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(119, "TCON5", UNIPHIER_PIN_IECTRL_NONE, + 107, UNIPHIER_PIN_DRV_4_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(120, "TCON6", 0, + 108, UNIPHIER_PIN_DRV_4_8, + 108, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(121, "TCON7", 0, + 109, UNIPHIER_PIN_DRV_4_8, + 109, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "PWMA", 0, + 110, UNIPHIER_PIN_DRV_4_8, + 110, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(123, "XIRQ1", 0, + 111, UNIPHIER_PIN_DRV_4_8, + 111, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "XIRQ2", 0, + 112, UNIPHIER_PIN_DRV_4_8, + 112, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(125, "XIRQ3", 0, + 113, UNIPHIER_PIN_DRV_4_8, + 113, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(126, "XIRQ4", 0, + 114, UNIPHIER_PIN_DRV_4_8, + 114, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(127, "XIRQ5", 0, + 115, UNIPHIER_PIN_DRV_4_8, + 115, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(128, "XIRQ6", 0, + 116, UNIPHIER_PIN_DRV_4_8, + 116, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(129, "XIRQ7", 0, + 117, UNIPHIER_PIN_DRV_4_8, + 117, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(130, "XIRQ8", 0, + 118, UNIPHIER_PIN_DRV_4_8, + 118, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(131, "XIRQ9", 0, + 119, UNIPHIER_PIN_DRV_4_8, + 119, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(132, "XIRQ10", 0, + 120, UNIPHIER_PIN_DRV_4_8, + 120, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(133, "XIRQ11", 0, + 121, UNIPHIER_PIN_DRV_4_8, + 121, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(134, "XIRQ14", 0, + 122, UNIPHIER_PIN_DRV_4_8, + 122, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(135, "PORT00", 0, + 123, UNIPHIER_PIN_DRV_4_8, + 123, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(136, "PORT01", 0, + 124, UNIPHIER_PIN_DRV_4_8, + 124, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(137, "PORT02", 0, + 125, UNIPHIER_PIN_DRV_4_8, + 125, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(138, "PORT03", 0, + 126, UNIPHIER_PIN_DRV_4_8, + 126, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(139, "PORT04", 0, + 127, UNIPHIER_PIN_DRV_4_8, + 127, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(140, "PORT05", 0, + 128, UNIPHIER_PIN_DRV_4_8, + 128, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(141, "PORT06", 0, + 129, UNIPHIER_PIN_DRV_4_8, + 129, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(142, "PORT07", 0, + 130, UNIPHIER_PIN_DRV_4_8, + 130, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(143, "PORT10", 0, + 131, UNIPHIER_PIN_DRV_4_8, + 131, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(144, "PORT11", 0, + 132, UNIPHIER_PIN_DRV_4_8, + 132, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(145, "PORT12", 0, + 133, UNIPHIER_PIN_DRV_4_8, + 133, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(146, "PORT13", 0, + 134, UNIPHIER_PIN_DRV_4_8, + 134, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(147, "PORT14", 0, + 135, UNIPHIER_PIN_DRV_4_8, + 135, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(148, "PORT15", 0, + 136, UNIPHIER_PIN_DRV_4_8, + 136, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(149, "PORT16", 0, + 137, UNIPHIER_PIN_DRV_4_8, + 137, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(150, "PORT17", UNIPHIER_PIN_IECTRL_NONE, + 138, UNIPHIER_PIN_DRV_4_8, + 138, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(151, "PORT20", 0, + 139, UNIPHIER_PIN_DRV_4_8, + 139, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(152, "PORT21", 0, + 140, UNIPHIER_PIN_DRV_4_8, + 140, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(153, "PORT22", 0, + 141, UNIPHIER_PIN_DRV_4_8, + 141, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(154, "PORT23", 0, + 142, UNIPHIER_PIN_DRV_4_8, + 142, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(155, "PORT24", UNIPHIER_PIN_IECTRL_NONE, + 143, UNIPHIER_PIN_DRV_4_8, + 143, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(156, "PORT25", 0, + 144, UNIPHIER_PIN_DRV_4_8, + 144, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(157, "PORT26", 0, + 145, UNIPHIER_PIN_DRV_4_8, + 145, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(158, "XNFRE", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(159, "XNFWE", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(160, "NFALE", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(161, "NFCLE", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(162, "XNFWP", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(163, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(164, "NANDRYBY0", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_UP), +}; + +static const unsigned emmc_pins[] = {21, 22, 23, 24, 25, 26, 27}; +static const unsigned emmc_muxvals[] = {0, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {28, 29, 30, 31}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {102, 103}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {104, 105}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {108, 109}; +static const unsigned i2c2_muxvals[] = {2, 2}; +static const unsigned i2c3_pins[] = {108, 109}; +static const unsigned i2c3_muxvals[] = {3, 3}; +static const unsigned nand_pins[] = {24, 25, 26, 27, 28, 29, 30, 31, 158, 159, + 160, 161, 162, 163, 164}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {22, 23}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned uart0_pins[] = {85, 88}; +static const unsigned uart0_muxvals[] = {1, 1}; +static const unsigned uart1_pins[] = {155, 156}; +static const unsigned uart1_muxvals[] = {13, 13}; +static const unsigned uart1b_pins[] = {69, 70}; +static const unsigned uart1b_muxvals[] = {23, 23}; +static const unsigned uart2_pins[] = {128, 129}; +static const unsigned uart2_muxvals[] = {13, 13}; +static const unsigned uart3_pins[] = {110, 111}; +static const unsigned uart3_muxvals[] = {1, 1}; +static const unsigned usb0_pins[] = {53, 54}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {55, 56}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {155, 156}; +static const unsigned usb2_muxvals[] = {4, 4}; +static const unsigned usb2b_pins[] = {67, 68}; +static const unsigned usb2b_muxvals[] = {23, 23}; +static const unsigned port_range0_pins[] = { + 135, 136, 137, 138, 139, 140, 141, 142, /* PORT0x */ + 143, 144, 145, 146, 147, 148, 149, 150, /* PORT1x */ + 151, 152, 153, 154, 155, 156, 157, 0, /* PORT2x */ + 1, 2, 3, 4, 5, 120, 121, 122, /* PORT3x */ + 24, 25, 26, 27, 28, 29, 30, 31, /* PORT4x */ + 40, 41, 42, 43, 44, 45, 46, 47, /* PORT5x */ + 48, 49, 50, 51, 52, 53, 54, 55, /* PORT6x */ + 56, 85, 84, 59, 82, 61, 64, 65, /* PORT7x */ + 8, 9, 10, 11, 12, 13, 14, 15, /* PORT8x */ + 66, 67, 68, 69, 70, 71, 72, 73, /* PORT9x */ + 74, 75, 89, 86, 78, 79, 80, 81, /* PORT10x */ + 60, 83, 58, 57, 88, 87, 77, 76, /* PORT11x */ + 90, 91, 92, 93, 94, 95, 96, 97, /* PORT12x */ + 98, 99, 100, 6, 101, 114, 115, 116, /* PORT13x */ + 103, 108, 21, 22, 23, 117, 118, 119, /* PORT14x */ +}; +static const unsigned port_range0_muxvals[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* PORT0x */ + 0, 0, 0, 0, 0, 0, 0, 0, /* PORT1x */ + 0, 0, 0, 0, 0, 0, 0, 15, /* PORT2x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT3x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT4x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT5x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT6x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT11x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */ +}; +static const unsigned port_range1_pins[] = { + 7, /* PORT166 */ +}; +static const unsigned port_range1_muxvals[] = { + 15, /* PORT166 */ +}; +static const unsigned xirq_range0_pins[] = { + 151, 123, 124, 125, 126, 127, 128, 129, /* XIRQ0-7 */ + 130, 131, 132, 133, 62, /* XIRQ8-12 */ +}; +static const unsigned xirq_range0_muxvals[] = { + 14, 0, 0, 0, 0, 0, 0, 0, /* XIRQ0-7 */ + 0, 0, 0, 0, 14, /* XIRQ8-12 */ +}; +static const unsigned xirq_range1_pins[] = { + 134, 63, /* XIRQ14-15 */ +}; +static const unsigned xirq_range1_muxvals[] = { + 0, 14, /* XIRQ14-15 */ +}; + +static const struct uniphier_pinctrl_group ph1_ld4_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart1b), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb2b), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_range1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port110, port_range0, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port111, port_range0, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port112, port_range0, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port113, port_range0, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port114, port_range0, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port115, port_range0, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port116, port_range0, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port117, port_range0, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range0, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range0, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range0, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range0, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range0, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range0, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range0, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range0, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range0, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range0, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range0, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range0, 107), + UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range0, 108), + UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range0, 109), + UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range0, 110), + UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range0, 111), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range0, 112), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range0, 113), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range0, 114), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range0, 115), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range0, 116), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range0, 117), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range0, 118), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range0, 119), + UNIPHIER_PINCTRL_GROUP_SINGLE(port165, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq_range1, 1), +}; + +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0"}; +static const char * const uart1_groups[] = {"uart1", "uart1b"}; +static const char * const uart2_groups[] = {"uart2"}; +static const char * const uart3_groups[] = {"uart3"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2", "usb2b"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + "port110", "port111", "port112", "port113", + "port114", "port115", "port116", "port117", + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + /* port150-164 missing */ + /* none */ "port165", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", /* none*/ "xirq14", "xirq15", +}; + +static const struct uniphier_pinmux_function ph1_ld4_functions[] = { + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(uart3), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata ph1_ld4_pindata = { + .groups = ph1_ld4_groups, + .groups_count = ARRAY_SIZE(ph1_ld4_groups), + .functions = ph1_ld4_functions, + .functions_count = ARRAY_SIZE(ph1_ld4_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static struct pinctrl_desc ph1_ld4_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = ph1_ld4_pins, + .npins = ARRAY_SIZE(ph1_ld4_pins), + .owner = THIS_MODULE, +}; + +static int ph1_ld4_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &ph1_ld4_pinctrl_desc, + &ph1_ld4_pindata); +} + +static const struct of_device_id ph1_ld4_pinctrl_match[] = { + { .compatible = "socionext,ph1-ld4-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ph1_ld4_pinctrl_match); + +static struct platform_driver ph1_ld4_pinctrl_driver = { + .probe = ph1_ld4_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = ph1_ld4_pinctrl_match, + }, +}; +module_platform_driver(ph1_ld4_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier PH1-LD4 pinctrl driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From b5cf4161ca8a54c79a05beaaf5d18c2c67193105 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:03 +0900 Subject: pinctrl: UniPhier: add UniPhier PH1-Pro4 pinctrl driver Add pin configuration and pinmux support for UniPhier PH1-Pro4 SoC. Changes in v2: - sort groups and funcs alphabetically - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 1 + drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c | 1554 +++++++++++++++++++++++++++ 3 files changed, 1559 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c (limited to 'drivers') diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index 78d25df6d0fd..944803ffb5cc 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -9,4 +9,8 @@ config PINCTRL_UNIPHIER_PH1_LD4 tristate "UniPhier PH1-LD4 SoC pinctrl driver" select PINCTRL_UNIPHIER_CORE +config PINCTRL_UNIPHIER_PH1_PRO4 + tristate "UniPhier PH1-Pro4 SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index b4bd042ac4f6..b1b597e0dccb 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c b/drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c new file mode 100644 index 000000000000..96921e40da5f --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c @@ -0,0 +1,1554 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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 program5 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 "pinctrl-uniphier.h" + +#define DRIVER_NAME "ph1-pro4-pinctrl" + +static const struct pinctrl_pin_desc ph1_pro4_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "CK24O", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_4_8, + 0, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "VC27A", UNIPHIER_PIN_IECTRL_NONE, + 1, UNIPHIER_PIN_DRV_4_8, + 1, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "CK27AI", UNIPHIER_PIN_IECTRL_NONE, + 2, UNIPHIER_PIN_DRV_4_8, + 2, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "CK27AO", UNIPHIER_PIN_IECTRL_NONE, + 3, UNIPHIER_PIN_DRV_4_8, + 3, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "CKSEL", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_4_8, + 4, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(5, "CK27AV", UNIPHIER_PIN_IECTRL_NONE, + 5, UNIPHIER_PIN_DRV_4_8, + 5, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "AEXCKA", UNIPHIER_PIN_IECTRL_NONE, + 6, UNIPHIER_PIN_DRV_4_8, + 6, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "ASEL", UNIPHIER_PIN_IECTRL_NONE, + 7, UNIPHIER_PIN_DRV_4_8, + 7, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "ARCRESET", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_4_8, + 8, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "ARCUNLOCK", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_4_8, + 9, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "XSRST", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_4_8, + 10, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "XNMIRQ", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_4_8, + 11, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(12, "XSCIRQ", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_4_8, + 12, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(13, "EXTRG", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_4_8, + 13, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(14, "TRCCLK", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_4_8, + 14, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(15, "TRCCTL", UNIPHIER_PIN_IECTRL_NONE, + 15, UNIPHIER_PIN_DRV_4_8, + 15, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(16, "TRCD0", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_4_8, + 16, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(17, "TRCD1", UNIPHIER_PIN_IECTRL_NONE, + 17, UNIPHIER_PIN_DRV_4_8, + 17, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(18, "TRCD2", UNIPHIER_PIN_IECTRL_NONE, + 18, UNIPHIER_PIN_DRV_4_8, + 18, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(19, "TRCD3", UNIPHIER_PIN_IECTRL_NONE, + 19, UNIPHIER_PIN_DRV_4_8, + 19, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(20, "TRCD4", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_4_8, + 20, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(21, "TRCD5", UNIPHIER_PIN_IECTRL_NONE, + 21, UNIPHIER_PIN_DRV_4_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(22, "TRCD6", UNIPHIER_PIN_IECTRL_NONE, + 22, UNIPHIER_PIN_DRV_4_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(23, "TRCD7", UNIPHIER_PIN_IECTRL_NONE, + 23, UNIPHIER_PIN_DRV_4_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(24, "XECS1", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_4_8, + 24, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(25, "ERXW", UNIPHIER_PIN_IECTRL_NONE, + 25, UNIPHIER_PIN_DRV_4_8, + 25, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(26, "XERWE0", UNIPHIER_PIN_IECTRL_NONE, + 26, UNIPHIER_PIN_DRV_4_8, + 26, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(27, "XERWE1", UNIPHIER_PIN_IECTRL_NONE, + 27, UNIPHIER_PIN_DRV_4_8, + 27, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(28, "ES0", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_4_8, + 28, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(29, "ES1", UNIPHIER_PIN_IECTRL_NONE, + 29, UNIPHIER_PIN_DRV_4_8, + 29, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(30, "ES2", UNIPHIER_PIN_IECTRL_NONE, + 30, UNIPHIER_PIN_DRV_4_8, + 30, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(31, "ED0", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(32, "ED1", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(33, "ED2", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(34, "ED3", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(35, "ED4", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(36, "ED5", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(37, "ED6", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(38, "ED7", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(39, "BOOTSWAP", UNIPHIER_PIN_IECTRL_NONE, + 39, UNIPHIER_PIN_DRV_NONE, + 39, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(40, "NFD0", UNIPHIER_PIN_IECTRL_NONE, + 2, UNIPHIER_PIN_DRV_8_12_16_20, + 40, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(41, "NFD1", UNIPHIER_PIN_IECTRL_NONE, + 3, UNIPHIER_PIN_DRV_8_12_16_20, + 41, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(42, "NFD2", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_8_12_16_20, + 42, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(43, "NFD3", UNIPHIER_PIN_IECTRL_NONE, + 5, UNIPHIER_PIN_DRV_8_12_16_20, + 43, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(44, "NFD4", UNIPHIER_PIN_IECTRL_NONE, + 6, UNIPHIER_PIN_DRV_8_12_16_20, + 44, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(45, "NFD5", UNIPHIER_PIN_IECTRL_NONE, + 7, UNIPHIER_PIN_DRV_8_12_16_20, + 45, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(46, "NFD6", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_8_12_16_20, + 46, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(47, "NFD7", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_8_12_16_20, + 47, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(48, "NFALE", UNIPHIER_PIN_IECTRL_NONE, + 48, UNIPHIER_PIN_DRV_4_8, + 48, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(49, "NFCLE", UNIPHIER_PIN_IECTRL_NONE, + 49, UNIPHIER_PIN_DRV_4_8, + 49, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(50, "XNFRE", UNIPHIER_PIN_IECTRL_NONE, + 50, UNIPHIER_PIN_DRV_4_8, + 50, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(51, "XNFWE", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_8_12_16_20, + 51, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(52, "XNFWP", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_4_8, + 52, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(53, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE, + 1, UNIPHIER_PIN_DRV_8_12_16_20, + 53, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(54, "NRYBY0", UNIPHIER_PIN_IECTRL_NONE, + 54, UNIPHIER_PIN_DRV_4_8, + 54, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(55, "DMDSCLTST", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_NONE, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(56, "DMDSDATST", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(57, "AGCI0", 3, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "DMDSCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(59, "DMDSDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(60, "AGCBS0", 5, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "DMDSCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(62, "DMDSDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(63, "ANTSHORT", UNIPHIER_PIN_IECTRL_NONE, + 57, UNIPHIER_PIN_DRV_4_8, + 57, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(64, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE, + 58, UNIPHIER_PIN_DRV_4_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE, + 59, UNIPHIER_PIN_DRV_4_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 60, UNIPHIER_PIN_DRV_4_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE, + 61, UNIPHIER_PIN_DRV_4_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE, + 62, UNIPHIER_PIN_DRV_4_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE, + 63, UNIPHIER_PIN_DRV_4_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 64, UNIPHIER_PIN_DRV_4_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE, + 65, UNIPHIER_PIN_DRV_4_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE, + 66, UNIPHIER_PIN_DRV_4_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE, + 67, UNIPHIER_PIN_DRV_4_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 68, UNIPHIER_PIN_DRV_4_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE, + 69, UNIPHIER_PIN_DRV_4_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE, + 70, UNIPHIER_PIN_DRV_4_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE, + 71, UNIPHIER_PIN_DRV_4_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 72, UNIPHIER_PIN_DRV_4_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE, + 73, UNIPHIER_PIN_DRV_4_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE, + 74, UNIPHIER_PIN_DRV_4_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE, + 75, UNIPHIER_PIN_DRV_4_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 76, UNIPHIER_PIN_DRV_4_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE, + 77, UNIPHIER_PIN_DRV_4_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE, + 78, UNIPHIER_PIN_DRV_4_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE, + 79, UNIPHIER_PIN_DRV_4_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 80, UNIPHIER_PIN_DRV_4_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE, + 81, UNIPHIER_PIN_DRV_4_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE, + 82, UNIPHIER_PIN_DRV_4_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE, + 83, UNIPHIER_PIN_DRV_4_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 84, UNIPHIER_PIN_DRV_4_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE, + 85, UNIPHIER_PIN_DRV_4_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "CKFEO", UNIPHIER_PIN_IECTRL_NONE, + 86, UNIPHIER_PIN_DRV_4_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "XFERST", UNIPHIER_PIN_IECTRL_NONE, + 87, UNIPHIER_PIN_DRV_4_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "P_FE_ON", UNIPHIER_PIN_IECTRL_NONE, + 88, UNIPHIER_PIN_DRV_4_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "P_TU0_ON", UNIPHIER_PIN_IECTRL_NONE, + 89, UNIPHIER_PIN_DRV_4_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "XFEIRQ0", UNIPHIER_PIN_IECTRL_NONE, + 90, UNIPHIER_PIN_DRV_4_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "XFEIRQ1", UNIPHIER_PIN_IECTRL_NONE, + 91, UNIPHIER_PIN_DRV_4_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "XFEIRQ2", UNIPHIER_PIN_IECTRL_NONE, + 92, UNIPHIER_PIN_DRV_4_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "XFEIRQ3", UNIPHIER_PIN_IECTRL_NONE, + 93, UNIPHIER_PIN_DRV_4_8, + 93, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "XFEIRQ4", UNIPHIER_PIN_IECTRL_NONE, + 94, UNIPHIER_PIN_DRV_4_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(101, "XFEIRQ5", UNIPHIER_PIN_IECTRL_NONE, + 95, UNIPHIER_PIN_DRV_4_8, + 95, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "XFEIRQ6", UNIPHIER_PIN_IECTRL_NONE, + 96, UNIPHIER_PIN_DRV_4_8, + 96, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(103, "SMTCLK0", UNIPHIER_PIN_IECTRL_NONE, + 97, UNIPHIER_PIN_DRV_4_8, + 97, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(104, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE, + 98, UNIPHIER_PIN_DRV_4_8, + 98, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(105, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE, + 99, UNIPHIER_PIN_DRV_4_8, + 99, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(106, "SMTD0", UNIPHIER_PIN_IECTRL_NONE, + 100, UNIPHIER_PIN_DRV_4_8, + 100, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(107, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE, + 101, UNIPHIER_PIN_DRV_4_8, + 101, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(108, "SMTDET0", UNIPHIER_PIN_IECTRL_NONE, + 102, UNIPHIER_PIN_DRV_4_8, + 102, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(109, "SMTCLK1", UNIPHIER_PIN_IECTRL_NONE, + 103, UNIPHIER_PIN_DRV_4_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(110, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE, + 104, UNIPHIER_PIN_DRV_4_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(111, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE, + 105, UNIPHIER_PIN_DRV_4_8, + 105, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(112, "SMTD1", UNIPHIER_PIN_IECTRL_NONE, + 106, UNIPHIER_PIN_DRV_4_8, + 106, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(113, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE, + 107, UNIPHIER_PIN_DRV_4_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(114, "SMTDET1", UNIPHIER_PIN_IECTRL_NONE, + 108, UNIPHIER_PIN_DRV_4_8, + 108, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(115, "XINTM", UNIPHIER_PIN_IECTRL_NONE, + 109, UNIPHIER_PIN_DRV_4_8, + 109, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(116, "SCLKM", UNIPHIER_PIN_IECTRL_NONE, + 110, UNIPHIER_PIN_DRV_4_8, + 110, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(117, "SBMTP", UNIPHIER_PIN_IECTRL_NONE, + 111, UNIPHIER_PIN_DRV_4_8, + 111, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(118, "SBPTM", UNIPHIER_PIN_IECTRL_NONE, + 112, UNIPHIER_PIN_DRV_4_8, + 112, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(119, "XMPREQ", UNIPHIER_PIN_IECTRL_NONE, + 113, UNIPHIER_PIN_DRV_4_8, + 113, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(120, "XINTP", UNIPHIER_PIN_IECTRL_NONE, + 114, UNIPHIER_PIN_DRV_4_8, + 114, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(121, "LPST", UNIPHIER_PIN_IECTRL_NONE, + 115, UNIPHIER_PIN_DRV_4_8, + 115, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "SDBOOT", UNIPHIER_PIN_IECTRL_NONE, + 116, UNIPHIER_PIN_DRV_4_8, + 116, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(123, "BFAIL", UNIPHIER_PIN_IECTRL_NONE, + 117, UNIPHIER_PIN_DRV_4_8, + 117, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "XFWE", UNIPHIER_PIN_IECTRL_NONE, + 118, UNIPHIER_PIN_DRV_4_8, + 118, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(125, "RF_COM_RDY", UNIPHIER_PIN_IECTRL_NONE, + 119, UNIPHIER_PIN_DRV_4_8, + 119, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(126, "XDIAG0", UNIPHIER_PIN_IECTRL_NONE, + 120, UNIPHIER_PIN_DRV_4_8, + 120, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(127, "RXD0", UNIPHIER_PIN_IECTRL_NONE, + 121, UNIPHIER_PIN_DRV_4_8, + 121, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(128, "TXD0", UNIPHIER_PIN_IECTRL_NONE, + 122, UNIPHIER_PIN_DRV_4_8, + 122, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(129, "RXD1", UNIPHIER_PIN_IECTRL_NONE, + 123, UNIPHIER_PIN_DRV_4_8, + 123, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(130, "TXD1", UNIPHIER_PIN_IECTRL_NONE, + 124, UNIPHIER_PIN_DRV_4_8, + 124, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(131, "RXD2", UNIPHIER_PIN_IECTRL_NONE, + 125, UNIPHIER_PIN_DRV_4_8, + 125, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(132, "TXD2", UNIPHIER_PIN_IECTRL_NONE, + 126, UNIPHIER_PIN_DRV_4_8, + 126, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(133, "SS0CS", UNIPHIER_PIN_IECTRL_NONE, + 127, UNIPHIER_PIN_DRV_4_8, + 127, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(134, "SS0CLK", UNIPHIER_PIN_IECTRL_NONE, + 128, UNIPHIER_PIN_DRV_4_8, + 128, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(135, "SS0DO", UNIPHIER_PIN_IECTRL_NONE, + 129, UNIPHIER_PIN_DRV_4_8, + 129, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(136, "SS0DI", UNIPHIER_PIN_IECTRL_NONE, + 130, UNIPHIER_PIN_DRV_4_8, + 130, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(137, "MS0CS0", UNIPHIER_PIN_IECTRL_NONE, + 131, UNIPHIER_PIN_DRV_4_8, + 131, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(138, "MS0CLK", UNIPHIER_PIN_IECTRL_NONE, + 132, UNIPHIER_PIN_DRV_4_8, + 132, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(139, "MS0DI", UNIPHIER_PIN_IECTRL_NONE, + 133, UNIPHIER_PIN_DRV_4_8, + 133, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(140, "MS0DO", UNIPHIER_PIN_IECTRL_NONE, + 134, UNIPHIER_PIN_DRV_4_8, + 134, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(141, "XMDMRST", UNIPHIER_PIN_IECTRL_NONE, + 135, UNIPHIER_PIN_DRV_4_8, + 135, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(142, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(143, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(144, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(145, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(146, "SCL2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(147, "SDA2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(148, "SCL3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(149, "SDA3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(150, "SD0DAT0", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_8_12_16_20, + 136, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(151, "SD0DAT1", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_8_12_16_20, + 137, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(152, "SD0DAT2", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_8_12_16_20, + 138, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(153, "SD0DAT3", UNIPHIER_PIN_IECTRL_NONE, + 15, UNIPHIER_PIN_DRV_8_12_16_20, + 139, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(154, "SD0CMD", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_8_12_16_20, + 141, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(155, "SD0CLK", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_8_12_16_20, + 140, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(156, "SD0CD", UNIPHIER_PIN_IECTRL_NONE, + 142, UNIPHIER_PIN_DRV_4_8, + 142, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(157, "SD0WP", UNIPHIER_PIN_IECTRL_NONE, + 143, UNIPHIER_PIN_DRV_4_8, + 143, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(158, "SD0VTCG", UNIPHIER_PIN_IECTRL_NONE, + 144, UNIPHIER_PIN_DRV_4_8, + 144, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(159, "CK25O", UNIPHIER_PIN_IECTRL_NONE, + 145, UNIPHIER_PIN_DRV_4_8, + 145, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(160, "RGMII_TXCLK", 6, + 146, UNIPHIER_PIN_DRV_4_8, + 146, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(161, "RGMII_TXD0", 6, + 147, UNIPHIER_PIN_DRV_4_8, + 147, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(162, "RGMII_TXD1", 6, + 148, UNIPHIER_PIN_DRV_4_8, + 148, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(163, "RGMII_TXD2", 6, + 149, UNIPHIER_PIN_DRV_4_8, + 149, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(164, "RGMII_TXD3", 6, + 150, UNIPHIER_PIN_DRV_4_8, + 150, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(165, "RGMII_TXCTL", 6, + 151, UNIPHIER_PIN_DRV_4_8, + 151, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(166, "MII_TXER", UNIPHIER_PIN_IECTRL_NONE, + 152, UNIPHIER_PIN_DRV_4_8, + 152, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(167, "RGMII_RXCLK", 6, + 153, UNIPHIER_PIN_DRV_4_8, + 153, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(168, "RGMII_RXD0", 6, + 154, UNIPHIER_PIN_DRV_4_8, + 154, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(169, "RGMII_RXD1", 6, + 155, UNIPHIER_PIN_DRV_4_8, + 155, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(170, "RGMII_RXD2", 6, + 156, UNIPHIER_PIN_DRV_4_8, + 156, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(171, "RGMII_RXD3", 6, + 157, UNIPHIER_PIN_DRV_4_8, + 157, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(172, "RGMII_RXCTL", 6, + 158, UNIPHIER_PIN_DRV_4_8, + 158, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(173, "MII_RXER", 6, + 159, UNIPHIER_PIN_DRV_4_8, + 159, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(174, "MII_CRS", 6, + 160, UNIPHIER_PIN_DRV_4_8, + 160, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(175, "MII_COL", 6, + 161, UNIPHIER_PIN_DRV_4_8, + 161, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(176, "MDC", 6, + 162, UNIPHIER_PIN_DRV_4_8, + 162, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(177, "MDIO", 6, + 163, UNIPHIER_PIN_DRV_4_8, + 163, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(178, "MDIO_INTL", 6, + 164, UNIPHIER_PIN_DRV_4_8, + 164, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(179, "XETH_RST", 6, + 165, UNIPHIER_PIN_DRV_4_8, + 165, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(180, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE, + 166, UNIPHIER_PIN_DRV_4_8, + 166, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(181, "USB0OD", UNIPHIER_PIN_IECTRL_NONE, + 167, UNIPHIER_PIN_DRV_4_8, + 167, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(182, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE, + 168, UNIPHIER_PIN_DRV_4_8, + 168, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(183, "USB1OD", UNIPHIER_PIN_IECTRL_NONE, + 169, UNIPHIER_PIN_DRV_4_8, + 169, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(184, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE, + 170, UNIPHIER_PIN_DRV_4_8, + 170, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(185, "USB2OD", UNIPHIER_PIN_IECTRL_NONE, + 171, UNIPHIER_PIN_DRV_4_8, + 171, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(186, "USB2ID", UNIPHIER_PIN_IECTRL_NONE, + 172, UNIPHIER_PIN_DRV_4_8, + 172, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(187, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE, + 173, UNIPHIER_PIN_DRV_4_8, + 173, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(188, "USB3OD", UNIPHIER_PIN_IECTRL_NONE, + 174, UNIPHIER_PIN_DRV_4_8, + 174, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(189, "LINKCLK", UNIPHIER_PIN_IECTRL_NONE, + 175, UNIPHIER_PIN_DRV_4_8, + 175, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(190, "LINKREQ", UNIPHIER_PIN_IECTRL_NONE, + 176, UNIPHIER_PIN_DRV_4_8, + 176, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(191, "LINKCTL0", UNIPHIER_PIN_IECTRL_NONE, + 177, UNIPHIER_PIN_DRV_4_8, + 177, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(192, "LINKCTL1", UNIPHIER_PIN_IECTRL_NONE, + 178, UNIPHIER_PIN_DRV_4_8, + 178, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(193, "LINKDT0", UNIPHIER_PIN_IECTRL_NONE, + 179, UNIPHIER_PIN_DRV_4_8, + 179, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(194, "LINKDT1", UNIPHIER_PIN_IECTRL_NONE, + 180, UNIPHIER_PIN_DRV_4_8, + 180, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(195, "LINKDT2", UNIPHIER_PIN_IECTRL_NONE, + 181, UNIPHIER_PIN_DRV_4_8, + 181, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(196, "LINKDT3", UNIPHIER_PIN_IECTRL_NONE, + 182, UNIPHIER_PIN_DRV_4_8, + 182, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(197, "LINKDT4", UNIPHIER_PIN_IECTRL_NONE, + 183, UNIPHIER_PIN_DRV_4_8, + 183, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(198, "LINKDT5", UNIPHIER_PIN_IECTRL_NONE, + 184, UNIPHIER_PIN_DRV_4_8, + 184, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(199, "LINKDT6", UNIPHIER_PIN_IECTRL_NONE, + 185, UNIPHIER_PIN_DRV_4_8, + 185, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(200, "LINKDT7", UNIPHIER_PIN_IECTRL_NONE, + 186, UNIPHIER_PIN_DRV_4_8, + 186, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(201, "CKDVO", UNIPHIER_PIN_IECTRL_NONE, + 187, UNIPHIER_PIN_DRV_4_8, + 187, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(202, "PHY_PD", UNIPHIER_PIN_IECTRL_NONE, + 188, UNIPHIER_PIN_DRV_4_8, + 188, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(203, "X1394_RST", UNIPHIER_PIN_IECTRL_NONE, + 189, UNIPHIER_PIN_DRV_4_8, + 189, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(204, "VOUT_MUTE_L", UNIPHIER_PIN_IECTRL_NONE, + 190, UNIPHIER_PIN_DRV_4_8, + 190, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(205, "CLK54O", UNIPHIER_PIN_IECTRL_NONE, + 191, UNIPHIER_PIN_DRV_4_8, + 191, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(206, "CLK54I", UNIPHIER_PIN_IECTRL_NONE, + 192, UNIPHIER_PIN_DRV_NONE, + 192, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(207, "YIN0", UNIPHIER_PIN_IECTRL_NONE, + 193, UNIPHIER_PIN_DRV_4_8, + 193, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(208, "YIN1", UNIPHIER_PIN_IECTRL_NONE, + 194, UNIPHIER_PIN_DRV_4_8, + 194, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(209, "YIN2", UNIPHIER_PIN_IECTRL_NONE, + 195, UNIPHIER_PIN_DRV_4_8, + 195, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(210, "YIN3", UNIPHIER_PIN_IECTRL_NONE, + 196, UNIPHIER_PIN_DRV_4_8, + 196, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(211, "YIN4", UNIPHIER_PIN_IECTRL_NONE, + 197, UNIPHIER_PIN_DRV_4_8, + 197, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(212, "YIN5", UNIPHIER_PIN_IECTRL_NONE, + 198, UNIPHIER_PIN_DRV_4_8, + 198, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(213, "CIN0", UNIPHIER_PIN_IECTRL_NONE, + 199, UNIPHIER_PIN_DRV_4_8, + 199, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(214, "CIN1", UNIPHIER_PIN_IECTRL_NONE, + 200, UNIPHIER_PIN_DRV_4_8, + 200, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(215, "CIN2", UNIPHIER_PIN_IECTRL_NONE, + 201, UNIPHIER_PIN_DRV_4_8, + 201, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(216, "CIN3", UNIPHIER_PIN_IECTRL_NONE, + 202, UNIPHIER_PIN_DRV_4_8, + 202, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(217, "CIN4", UNIPHIER_PIN_IECTRL_NONE, + 203, UNIPHIER_PIN_DRV_4_8, + 203, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(218, "CIN5", UNIPHIER_PIN_IECTRL_NONE, + 204, UNIPHIER_PIN_DRV_4_8, + 204, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(219, "GCP", UNIPHIER_PIN_IECTRL_NONE, + 205, UNIPHIER_PIN_DRV_4_8, + 205, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(220, "ADFLG", UNIPHIER_PIN_IECTRL_NONE, + 206, UNIPHIER_PIN_DRV_4_8, + 206, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(221, "CK27AIOF", UNIPHIER_PIN_IECTRL_NONE, + 207, UNIPHIER_PIN_DRV_4_8, + 207, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(222, "DACOUT", UNIPHIER_PIN_IECTRL_NONE, + 208, UNIPHIER_PIN_DRV_4_8, + 208, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(223, "DAFLG", UNIPHIER_PIN_IECTRL_NONE, + 209, UNIPHIER_PIN_DRV_4_8, + 209, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(224, "VBIH", UNIPHIER_PIN_IECTRL_NONE, + 210, UNIPHIER_PIN_DRV_4_8, + 210, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(225, "VBIL", UNIPHIER_PIN_IECTRL_NONE, + 211, UNIPHIER_PIN_DRV_4_8, + 211, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(226, "XSUB_RST", UNIPHIER_PIN_IECTRL_NONE, + 212, UNIPHIER_PIN_DRV_4_8, + 212, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(227, "XADC_PD", UNIPHIER_PIN_IECTRL_NONE, + 213, UNIPHIER_PIN_DRV_4_8, + 213, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(228, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE, + 214, UNIPHIER_PIN_DRV_4_8, + 214, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(229, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE, + 215, UNIPHIER_PIN_DRV_4_8, + 215, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(230, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE, + 216, UNIPHIER_PIN_DRV_4_8, + 216, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(231, "AI1DMIX", UNIPHIER_PIN_IECTRL_NONE, + 217, UNIPHIER_PIN_DRV_4_8, + 217, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(232, "CK27HD", UNIPHIER_PIN_IECTRL_NONE, + 218, UNIPHIER_PIN_DRV_4_8, + 218, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(233, "XHD_RST", UNIPHIER_PIN_IECTRL_NONE, + 219, UNIPHIER_PIN_DRV_4_8, + 219, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(234, "INTHD", UNIPHIER_PIN_IECTRL_NONE, + 220, UNIPHIER_PIN_DRV_4_8, + 220, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(235, "VO1HDCK", UNIPHIER_PIN_IECTRL_NONE, + 221, UNIPHIER_PIN_DRV_4_8, + 221, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(236, "VO1HSYNC", UNIPHIER_PIN_IECTRL_NONE, + 222, UNIPHIER_PIN_DRV_4_8, + 222, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(237, "VO1VSYNC", UNIPHIER_PIN_IECTRL_NONE, + 223, UNIPHIER_PIN_DRV_4_8, + 223, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(238, "VO1DE", UNIPHIER_PIN_IECTRL_NONE, + 224, UNIPHIER_PIN_DRV_4_8, + 224, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(239, "VO1Y0", UNIPHIER_PIN_IECTRL_NONE, + 225, UNIPHIER_PIN_DRV_4_8, + 225, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(240, "VO1Y1", UNIPHIER_PIN_IECTRL_NONE, + 226, UNIPHIER_PIN_DRV_4_8, + 226, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(241, "VO1Y2", UNIPHIER_PIN_IECTRL_NONE, + 227, UNIPHIER_PIN_DRV_4_8, + 227, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(242, "VO1Y3", UNIPHIER_PIN_IECTRL_NONE, + 228, UNIPHIER_PIN_DRV_4_8, + 228, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(243, "VO1Y4", UNIPHIER_PIN_IECTRL_NONE, + 229, UNIPHIER_PIN_DRV_4_8, + 229, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(244, "VO1Y5", UNIPHIER_PIN_IECTRL_NONE, + 230, UNIPHIER_PIN_DRV_4_8, + 230, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(245, "VO1Y6", UNIPHIER_PIN_IECTRL_NONE, + 231, UNIPHIER_PIN_DRV_4_8, + 231, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(246, "VO1Y7", UNIPHIER_PIN_IECTRL_NONE, + 232, UNIPHIER_PIN_DRV_4_8, + 232, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(247, "VO1Y8", UNIPHIER_PIN_IECTRL_NONE, + 233, UNIPHIER_PIN_DRV_4_8, + 233, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(248, "VO1Y9", UNIPHIER_PIN_IECTRL_NONE, + 234, UNIPHIER_PIN_DRV_4_8, + 234, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(249, "VO1Y10", UNIPHIER_PIN_IECTRL_NONE, + 235, UNIPHIER_PIN_DRV_4_8, + 235, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(250, "VO1Y11", UNIPHIER_PIN_IECTRL_NONE, + 236, UNIPHIER_PIN_DRV_4_8, + 236, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(251, "VO1CB0", UNIPHIER_PIN_IECTRL_NONE, + 237, UNIPHIER_PIN_DRV_4_8, + 237, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(252, "VO1CB1", UNIPHIER_PIN_IECTRL_NONE, + 238, UNIPHIER_PIN_DRV_4_8, + 238, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(253, "VO1CB2", UNIPHIER_PIN_IECTRL_NONE, + 239, UNIPHIER_PIN_DRV_4_8, + 239, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(254, "VO1CB3", UNIPHIER_PIN_IECTRL_NONE, + 240, UNIPHIER_PIN_DRV_4_8, + 240, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(255, "VO1CB4", UNIPHIER_PIN_IECTRL_NONE, + 241, UNIPHIER_PIN_DRV_4_8, + 241, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(256, "VO1CB5", UNIPHIER_PIN_IECTRL_NONE, + 242, UNIPHIER_PIN_DRV_4_8, + 242, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(257, "VO1CB6", UNIPHIER_PIN_IECTRL_NONE, + 243, UNIPHIER_PIN_DRV_4_8, + 243, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(258, "VO1CB7", UNIPHIER_PIN_IECTRL_NONE, + 244, UNIPHIER_PIN_DRV_4_8, + 244, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(259, "VO1CB8", UNIPHIER_PIN_IECTRL_NONE, + 245, UNIPHIER_PIN_DRV_4_8, + 245, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(260, "VO1CB9", UNIPHIER_PIN_IECTRL_NONE, + 246, UNIPHIER_PIN_DRV_4_8, + 246, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(261, "VO1CB10", UNIPHIER_PIN_IECTRL_NONE, + 247, UNIPHIER_PIN_DRV_4_8, + 247, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(262, "VO1CB11", UNIPHIER_PIN_IECTRL_NONE, + 248, UNIPHIER_PIN_DRV_4_8, + 248, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(263, "VO1CR0", UNIPHIER_PIN_IECTRL_NONE, + 249, UNIPHIER_PIN_DRV_4_8, + 249, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(264, "VO1CR1", UNIPHIER_PIN_IECTRL_NONE, + 250, UNIPHIER_PIN_DRV_4_8, + 250, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(265, "VO1CR2", UNIPHIER_PIN_IECTRL_NONE, + 251, UNIPHIER_PIN_DRV_4_8, + 251, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(266, "VO1CR3", UNIPHIER_PIN_IECTRL_NONE, + 252, UNIPHIER_PIN_DRV_4_8, + 252, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(267, "VO1CR4", UNIPHIER_PIN_IECTRL_NONE, + 253, UNIPHIER_PIN_DRV_4_8, + 253, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(268, "VO1CR5", UNIPHIER_PIN_IECTRL_NONE, + 254, UNIPHIER_PIN_DRV_4_8, + 254, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(269, "VO1CR6", UNIPHIER_PIN_IECTRL_NONE, + 255, UNIPHIER_PIN_DRV_4_8, + 255, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(270, "VO1CR7", UNIPHIER_PIN_IECTRL_NONE, + 256, UNIPHIER_PIN_DRV_4_8, + 256, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(271, "VO1CR8", UNIPHIER_PIN_IECTRL_NONE, + 257, UNIPHIER_PIN_DRV_4_8, + 257, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(272, "VO1CR9", UNIPHIER_PIN_IECTRL_NONE, + 258, UNIPHIER_PIN_DRV_4_8, + 258, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(273, "VO1CR10", UNIPHIER_PIN_IECTRL_NONE, + 259, UNIPHIER_PIN_DRV_4_8, + 259, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(274, "VO1CR11", UNIPHIER_PIN_IECTRL_NONE, + 260, UNIPHIER_PIN_DRV_4_8, + 260, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(275, "VO1EX0", UNIPHIER_PIN_IECTRL_NONE, + 261, UNIPHIER_PIN_DRV_4_8, + 261, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(276, "VO1EX1", UNIPHIER_PIN_IECTRL_NONE, + 262, UNIPHIER_PIN_DRV_4_8, + 262, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(277, "VO1EX2", UNIPHIER_PIN_IECTRL_NONE, + 263, UNIPHIER_PIN_DRV_4_8, + 263, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(278, "VO1EX3", UNIPHIER_PIN_IECTRL_NONE, + 264, UNIPHIER_PIN_DRV_4_8, + 264, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(279, "VEXCKA", UNIPHIER_PIN_IECTRL_NONE, + 265, UNIPHIER_PIN_DRV_4_8, + 265, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(280, "VSEL0", UNIPHIER_PIN_IECTRL_NONE, + 266, UNIPHIER_PIN_DRV_4_8, + 266, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(281, "VSEL1", UNIPHIER_PIN_IECTRL_NONE, + 267, UNIPHIER_PIN_DRV_4_8, + 267, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(282, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE, + 268, UNIPHIER_PIN_DRV_4_8, + 268, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(283, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE, + 269, UNIPHIER_PIN_DRV_4_8, + 269, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(284, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE, + 270, UNIPHIER_PIN_DRV_4_8, + 270, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(285, "AO1D0", UNIPHIER_PIN_IECTRL_NONE, + 271, UNIPHIER_PIN_DRV_4_8, + 271, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(286, "AO1D1", UNIPHIER_PIN_IECTRL_NONE, + 272, UNIPHIER_PIN_DRV_4_8, + 272, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(287, "AO1D2", UNIPHIER_PIN_IECTRL_NONE, + 273, UNIPHIER_PIN_DRV_4_8, + 273, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(288, "AO1D3", UNIPHIER_PIN_IECTRL_NONE, + 274, UNIPHIER_PIN_DRV_4_8, + 274, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(289, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE, + 275, UNIPHIER_PIN_DRV_4_8, + 275, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(290, "XDAC_PD", UNIPHIER_PIN_IECTRL_NONE, + 276, UNIPHIER_PIN_DRV_4_8, + 276, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(291, "EX_A_MUTE", UNIPHIER_PIN_IECTRL_NONE, + 277, UNIPHIER_PIN_DRV_4_8, + 277, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(292, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE, + 278, UNIPHIER_PIN_DRV_4_8, + 278, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(293, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE, + 279, UNIPHIER_PIN_DRV_4_8, + 279, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(294, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE, + 280, UNIPHIER_PIN_DRV_4_8, + 280, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(295, "AO2DMIX", UNIPHIER_PIN_IECTRL_NONE, + 281, UNIPHIER_PIN_DRV_4_8, + 281, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(296, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE, + 282, UNIPHIER_PIN_DRV_4_8, + 282, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(297, "HTHPD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(298, "HTSCL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(299, "HTSDA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(300, "PORT00", UNIPHIER_PIN_IECTRL_NONE, + 284, UNIPHIER_PIN_DRV_4_8, + 284, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(301, "PORT01", UNIPHIER_PIN_IECTRL_NONE, + 285, UNIPHIER_PIN_DRV_4_8, + 285, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(302, "PORT02", UNIPHIER_PIN_IECTRL_NONE, + 286, UNIPHIER_PIN_DRV_4_8, + 286, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(303, "PORT03", UNIPHIER_PIN_IECTRL_NONE, + 287, UNIPHIER_PIN_DRV_4_8, + 287, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(304, "PORT04", UNIPHIER_PIN_IECTRL_NONE, + 288, UNIPHIER_PIN_DRV_4_8, + 288, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(305, "PORT05", UNIPHIER_PIN_IECTRL_NONE, + 289, UNIPHIER_PIN_DRV_4_8, + 289, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(306, "PORT06", UNIPHIER_PIN_IECTRL_NONE, + 290, UNIPHIER_PIN_DRV_4_8, + 290, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(307, "PORT07", UNIPHIER_PIN_IECTRL_NONE, + 291, UNIPHIER_PIN_DRV_4_8, + 291, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(308, "PORT10", UNIPHIER_PIN_IECTRL_NONE, + 292, UNIPHIER_PIN_DRV_4_8, + 292, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(309, "PORT11", UNIPHIER_PIN_IECTRL_NONE, + 293, UNIPHIER_PIN_DRV_4_8, + 293, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(310, "PORT12", UNIPHIER_PIN_IECTRL_NONE, + 294, UNIPHIER_PIN_DRV_4_8, + 294, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(311, "PORT13", UNIPHIER_PIN_IECTRL_NONE, + 295, UNIPHIER_PIN_DRV_4_8, + 295, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(312, "PORT14", UNIPHIER_PIN_IECTRL_NONE, + 296, UNIPHIER_PIN_DRV_4_8, + 296, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(313, "PORT15", UNIPHIER_PIN_IECTRL_NONE, + 297, UNIPHIER_PIN_DRV_4_8, + 297, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(314, "PORT16", UNIPHIER_PIN_IECTRL_NONE, + 298, UNIPHIER_PIN_DRV_4_8, + 298, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(315, "PORT17", UNIPHIER_PIN_IECTRL_NONE, + 299, UNIPHIER_PIN_DRV_4_8, + 299, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(316, "PORT20", UNIPHIER_PIN_IECTRL_NONE, + 300, UNIPHIER_PIN_DRV_4_8, + 300, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(317, "PORT21", UNIPHIER_PIN_IECTRL_NONE, + 301, UNIPHIER_PIN_DRV_4_8, + 301, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(318, "PORT22", UNIPHIER_PIN_IECTRL_NONE, + 302, UNIPHIER_PIN_DRV_4_8, + 302, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(319, "SD1DAT0", UNIPHIER_PIN_IECTRL_NONE, + 303, UNIPHIER_PIN_DRV_4_8, + 303, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(320, "SD1DAT1", UNIPHIER_PIN_IECTRL_NONE, + 304, UNIPHIER_PIN_DRV_4_8, + 304, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(321, "SD1DAT2", UNIPHIER_PIN_IECTRL_NONE, + 305, UNIPHIER_PIN_DRV_4_8, + 305, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(322, "SD1DAT3", UNIPHIER_PIN_IECTRL_NONE, + 306, UNIPHIER_PIN_DRV_4_8, + 306, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(323, "SD1CMD", UNIPHIER_PIN_IECTRL_NONE, + 307, UNIPHIER_PIN_DRV_4_8, + 307, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(324, "SD1CLK", UNIPHIER_PIN_IECTRL_NONE, + 308, UNIPHIER_PIN_DRV_4_8, + 308, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(325, "SD1CD", UNIPHIER_PIN_IECTRL_NONE, + 309, UNIPHIER_PIN_DRV_4_8, + 309, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(326, "SD1WP", UNIPHIER_PIN_IECTRL_NONE, + 310, UNIPHIER_PIN_DRV_4_8, + 310, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(327, "SD1VTCG", UNIPHIER_PIN_IECTRL_NONE, + 311, UNIPHIER_PIN_DRV_4_8, + 311, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(328, "DMDISO", UNIPHIER_PIN_IECTRL_NONE, + 312, UNIPHIER_PIN_DRV_NONE, + 312, UNIPHIER_PIN_PULL_DOWN), +}; + +static const unsigned emmc_pins[] = {40, 41, 42, 43, 51, 52, 53}; +static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {44, 45, 46, 47}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {142, 143}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {144, 145}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {146, 147}; +static const unsigned i2c2_muxvals[] = {0, 0}; +static const unsigned i2c3_pins[] = {148, 149}; +static const unsigned i2c3_muxvals[] = {0, 0}; +static const unsigned i2c6_pins[] = {308, 309}; +static const unsigned i2c6_muxvals[] = {6, 6}; +static const unsigned nand_pins[] = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {131, 132}; +static const unsigned nand_cs1_muxvals[] = {1, 1}; +static const unsigned uart0_pins[] = {127, 128}; +static const unsigned uart0_muxvals[] = {0, 0}; +static const unsigned uart1_pins[] = {129, 130}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart2_pins[] = {131, 132}; +static const unsigned uart2_muxvals[] = {0, 0}; +static const unsigned uart3_pins[] = {88, 89}; +static const unsigned uart3_muxvals[] = {2, 2}; +static const unsigned usb0_pins[] = {180, 181}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {182, 183}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {184, 185}; +static const unsigned usb2_muxvals[] = {0, 0}; +static const unsigned usb3_pins[] = {186, 187}; +static const unsigned usb3_muxvals[] = {0, 0}; +static const unsigned port_range0_pins[] = { + 300, 301, 302, 303, 304, 305, 306, 307, /* PORT0x */ + 308, 309, 310, 311, 312, 313, 314, 315, /* PORT1x */ + 316, 317, 318, 16, 17, 18, 19, 20, /* PORT2x */ + 21, 22, 23, 4, 93, 94, 95, 63, /* PORT3x */ + 123, 122, 124, 125, 126, 141, 202, 203, /* PORT4x */ + 204, 226, 227, 290, 291, 233, 280, 281, /* PORT5x */ + 8, 7, 10, 29, 30, 48, 49, 50, /* PORT6x */ + 40, 41, 42, 43, 44, 45, 46, 47, /* PORT7x */ + 54, 51, 52, 53, 127, 128, 129, 130, /* PORT8x */ + 131, 132, 57, 60, 134, 133, 135, 136, /* PORT9x */ + 138, 137, 140, 139, 64, 65, 66, 67, /* PORT10x */ + 107, 106, 105, 104, 113, 112, 111, 110, /* PORT11x */ + 68, 69, 70, 71, 72, 73, 74, 75, /* PORT12x */ + 76, 77, 78, 79, 80, 81, 82, 83, /* PORT13x */ + 84, 85, 86, 87, 88, 89, 90, 91, /* PORT14x */ +}; +static const unsigned port_range0_muxvals[] = { + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT0x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT1x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT2x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT3x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT4x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT5x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT6x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT7x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT8x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT9x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT10x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT11x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT12x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT13x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT14x */ +}; +static const unsigned port_range1_pins[] = { + 13, 14, 15, /* PORT175-177 */ + 157, 158, 156, 154, 150, 151, 152, 153, /* PORT18x */ + 326, 327, 325, 323, 319, 320, 321, 322, /* PORT19x */ + 160, 161, 162, 163, 164, 165, 166, 167, /* PORT20x */ + 168, 169, 170, 171, 172, 173, 174, 175, /* PORT21x */ + 180, 181, 182, 183, 184, 185, 187, 188, /* PORT22x */ + 193, 194, 195, 196, 197, 198, 199, 200, /* PORT23x */ + 191, 192, 215, 216, 217, 218, 219, 220, /* PORT24x */ + 222, 223, 224, 225, 228, 229, 230, 231, /* PORT25x */ + 282, 283, 284, 285, 286, 287, 288, 289, /* PORT26x */ + 292, 293, 294, 295, 296, 236, 237, 238, /* PORT27x */ + 275, 276, 277, 278, 239, 240, 249, 250, /* PORT28x */ + 251, 252, 261, 262, 263, 264, 273, 274, /* PORT29x */ + 31, 32, 33, 34, 35, 36, 37, 38, /* PORT30x */ +}; +static const unsigned port_range1_muxvals[] = { + 7, 7, 7, /* PORT175-177 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT18x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT19x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT20x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT21x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT22x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT23x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT24x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT25x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT26x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT27x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT28x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT29x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT30x */ +}; +static const unsigned xirq_pins[] = { + 11, 9, 12, 96, 97, 98, 108, 114, /* XIRQ0-7 */ + 234, 186, 99, 100, 101, 102, 184, 301, /* XIRQ8-15 */ + 302, 303, 304, 305, 306, /* XIRQ16-20 */ +}; +static const unsigned xirq_muxvals[] = { + 7, 7, 7, 7, 7, 7, 7, 7, /* XIRQ0-7 */ + 7, 7, 7, 7, 7, 7, 2, 2, /* XIRQ8-15 */ + 2, 2, 2, 2, 2, /* XIRQ16-20 */ +}; +static const unsigned xirq_alternatives_pins[] = { + 184, 310, 316, +}; +static const unsigned xirq_alternatives_muxvals[] = { + 2, 2, 2, +}; + +static const struct uniphier_pinctrl_group ph1_pro4_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(i2c6), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb3), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port110, port_range0, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port111, port_range0, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port112, port_range0, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port113, port_range0, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port114, port_range0, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port115, port_range0, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port116, port_range0, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port117, port_range0, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range0, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range0, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range0, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range0, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range0, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range0, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range0, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range0, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range0, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range0, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range0, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range0, 107), + UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range0, 108), + UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range0, 109), + UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range0, 110), + UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range0, 111), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range0, 112), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range0, 113), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range0, 114), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range0, 115), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range0, 116), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range0, 117), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range0, 118), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range0, 119), + UNIPHIER_PINCTRL_GROUP_SINGLE(port175, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port176, port_range1, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port177, port_range1, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range1, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range1, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range1, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range1, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range1, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range1, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range1, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range1, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port190, port_range1, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port191, port_range1, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port192, port_range1, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port193, port_range1, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port194, port_range1, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port195, port_range1, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port196, port_range1, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port197, port_range1, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range1, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range1, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range1, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range1, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range1, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range1, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range1, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range1, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range1, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range1, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range1, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range1, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range1, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range1, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range1, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range1, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range1, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range1, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range1, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range1, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range1, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range1, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range1, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range1, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range1, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range1, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range1, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range1, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range1, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range1, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range1, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range1, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range1, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range1, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range1, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range1, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range1, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range1, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range1, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range1, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range1, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range1, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range1, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range1, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range1, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port255, port_range1, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port256, port_range1, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port257, port_range1, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port260, port_range1, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port261, port_range1, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port262, port_range1, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port263, port_range1, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port264, port_range1, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port265, port_range1, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port266, port_range1, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port267, port_range1, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port270, port_range1, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port271, port_range1, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port272, port_range1, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port273, port_range1, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port274, port_range1, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port275, port_range1, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port276, port_range1, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port277, port_range1, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port280, port_range1, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port281, port_range1, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port282, port_range1, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port283, port_range1, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port284, port_range1, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port285, port_range1, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port286, port_range1, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port287, port_range1, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port290, port_range1, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port291, port_range1, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port292, port_range1, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port293, port_range1, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port294, port_range1, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port295, port_range1, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port296, port_range1, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port297, port_range1, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port300, port_range1, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port301, port_range1, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port302, port_range1, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port303, port_range1, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port304, port_range1, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port305, port_range1, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port306, port_range1, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port307, port_range1, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14b, xirq_alternatives, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17b, xirq_alternatives, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18b, xirq_alternatives, 2), +}; + +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const i2c6_groups[] = {"i2c6"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0"}; +static const char * const uart1_groups[] = {"uart1"}; +static const char * const uart2_groups[] = {"uart2"}; +static const char * const uart3_groups[] = {"uart3"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2"}; +static const char * const usb3_groups[] = {"usb3"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + "port110", "port111", "port112", "port113", + "port114", "port115", "port116", "port117", + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + /* port150-174 missing */ + /* none */ "port175", "port176", "port177", + "port180", "port181", "port182", "port183", + "port184", "port185", "port186", "port187", + "port190", "port191", "port192", "port193", + "port194", "port195", "port196", "port197", + "port200", "port201", "port202", "port203", + "port204", "port205", "port206", "port207", + "port210", "port211", "port212", "port213", + "port214", "port215", "port216", "port217", + "port220", "port221", "port222", "port223", + "port224", "port225", "port226", "port227", + "port230", "port231", "port232", "port233", + "port234", "port235", "port236", "port237", + "port240", "port241", "port242", "port243", + "port244", "port245", "port246", "port247", + "port250", "port251", "port252", "port253", + "port254", "port255", "port256", "port257", + "port260", "port261", "port262", "port263", + "port264", "port265", "port266", "port267", + "port270", "port271", "port272", "port273", + "port274", "port275", "port276", "port277", + "port280", "port281", "port282", "port283", + "port284", "port285", "port286", "port287", + "port290", "port291", "port292", "port293", + "port294", "port295", "port296", "port297", + "port300", "port301", "port302", "port303", + "port304", "port305", "port306", "port307", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", "xirq13", "xirq14", "xirq15", + "xirq16", "xirq17", "xirq18", "xirq19", + "xirq20", + "xirq14b", "xirq17b", "xirq18b", +}; + +static const struct uniphier_pinmux_function ph1_pro4_functions[] = { + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(i2c6), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(uart3), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(usb3), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata ph1_pro4_pindata = { + .groups = ph1_pro4_groups, + .groups_count = ARRAY_SIZE(ph1_pro4_groups), + .functions = ph1_pro4_functions, + .functions_count = ARRAY_SIZE(ph1_pro4_functions), + .mux_bits = 4, + .reg_stride = 8, + .load_pinctrl = true, +}; + +static struct pinctrl_desc ph1_pro4_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = ph1_pro4_pins, + .npins = ARRAY_SIZE(ph1_pro4_pins), + .owner = THIS_MODULE, +}; + +static int ph1_pro4_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &ph1_pro4_pinctrl_desc, + &ph1_pro4_pindata); +} + +static const struct of_device_id ph1_pro4_pinctrl_match[] = { + { .compatible = "socionext,ph1-pro4-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ph1_pro4_pinctrl_match); + +static struct platform_driver ph1_pro4_pinctrl_driver = { + .probe = ph1_pro4_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = ph1_pro4_pinctrl_match, + }, +}; +module_platform_driver(ph1_pro4_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier PH1-Pro4 pinctrl driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 95372f9dc892a79bce1e81b8862bb4ad15cf4f76 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:04 +0900 Subject: pinctrl: UniPhier: add UniPhier PH1-sLD8 pinctrl driver Add pin configuration and pinmux support for UniPhier PH1-sLD8 SoC. Changes in v2: - sort groups and funcs alphabetically - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 1 + drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c | 794 ++++++++++++++++++++++++++++ 3 files changed, 799 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c (limited to 'drivers') diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index 944803ffb5cc..f4a21feeff61 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -13,4 +13,8 @@ config PINCTRL_UNIPHIER_PH1_PRO4 tristate "UniPhier PH1-Pro4 SoC pinctrl driver" select PINCTRL_UNIPHIER_CORE +config PINCTRL_UNIPHIER_PH1_SLD8 + tristate "UniPhier PH1-sLD8 SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index b1b597e0dccb..3349fff80aa9 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_SLD8) += pinctrl-ph1-sld8.o diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c b/drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c new file mode 100644 index 000000000000..7e9dae54fcb2 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c @@ -0,0 +1,794 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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 + +#include "pinctrl-uniphier.h" + +#define DRIVER_NAME "ph1-sld8-pinctrl" + +static const struct pinctrl_pin_desc ph1_sld8_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "PCA00", UNIPHIER_PIN_IECTRL_NONE, + 15, UNIPHIER_PIN_DRV_4_8, + 15, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "PCA01", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_4_8, + 16, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "PCA02", UNIPHIER_PIN_IECTRL_NONE, + 17, UNIPHIER_PIN_DRV_4_8, + 17, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "PCA03", UNIPHIER_PIN_IECTRL_NONE, + 18, UNIPHIER_PIN_DRV_4_8, + 18, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "PCA04", UNIPHIER_PIN_IECTRL_NONE, + 19, UNIPHIER_PIN_DRV_4_8, + 19, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(5, "PCA05", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_4_8, + 20, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "PCA06", UNIPHIER_PIN_IECTRL_NONE, + 21, UNIPHIER_PIN_DRV_4_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "PCA07", UNIPHIER_PIN_IECTRL_NONE, + 22, UNIPHIER_PIN_DRV_4_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "PCA08", UNIPHIER_PIN_IECTRL_NONE, + 23, UNIPHIER_PIN_DRV_4_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "PCA09", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_4_8, + 24, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "PCA10", UNIPHIER_PIN_IECTRL_NONE, + 25, UNIPHIER_PIN_DRV_4_8, + 25, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "PCA11", UNIPHIER_PIN_IECTRL_NONE, + 26, UNIPHIER_PIN_DRV_4_8, + 26, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(12, "PCA12", UNIPHIER_PIN_IECTRL_NONE, + 27, UNIPHIER_PIN_DRV_4_8, + 27, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(13, "PCA13", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_4_8, + 28, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(14, "PCA14", UNIPHIER_PIN_IECTRL_NONE, + 29, UNIPHIER_PIN_DRV_4_8, + 29, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(15, "XNFRE_GB", UNIPHIER_PIN_IECTRL_NONE, + 30, UNIPHIER_PIN_DRV_4_8, + 30, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(16, "XNFWE_GB", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(17, "NFALE_GB", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(18, "NFCLE_GB", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(19, "XNFWP_GB", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(20, "XNFCE0_GB", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(21, "NANDRYBY0_GB", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(22, "XNFCE1_GB", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_8_12_16_20, + 119, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(23, "NANDRYBY1_GB", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_8_12_16_20, + 120, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(24, "NFD0_GB", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_8_12_16_20, + 121, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(25, "NFD1_GB", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_8_12_16_20, + 122, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(26, "NFD2_GB", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_8_12_16_20, + 123, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(27, "NFD3_GB", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_8_12_16_20, + 124, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(28, "NFD4_GB", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_8_12_16_20, + 125, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(29, "NFD5_GB", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_8_12_16_20, + 126, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(30, "NFD6_GB", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_8_12_16_20, + 127, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(31, "NFD7_GB", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_8_12_16_20, + 128, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(32, "SDCLK", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(33, "SDCMD", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(34, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE, + 48, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(35, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(36, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE, + 56, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(37, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE, + 60, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(38, "SDCD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 129, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(39, "SDWP", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 130, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(40, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 131, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(41, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(42, "USB0OD", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(43, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE, + 39, UNIPHIER_PIN_DRV_4_8, + 39, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(44, "USB1OD", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_4_8, + 40, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(45, "PCRESET", UNIPHIER_PIN_IECTRL_NONE, + 41, UNIPHIER_PIN_DRV_4_8, + 41, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(46, "PCREG", UNIPHIER_PIN_IECTRL_NONE, + 42, UNIPHIER_PIN_DRV_4_8, + 42, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(47, "PCCE2", UNIPHIER_PIN_IECTRL_NONE, + 43, UNIPHIER_PIN_DRV_4_8, + 43, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(48, "PCVS1", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_4_8, + 44, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(49, "PCCD2", UNIPHIER_PIN_IECTRL_NONE, + 45, UNIPHIER_PIN_DRV_4_8, + 45, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(50, "PCCD1", UNIPHIER_PIN_IECTRL_NONE, + 46, UNIPHIER_PIN_DRV_4_8, + 46, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(51, "PCREADY", UNIPHIER_PIN_IECTRL_NONE, + 47, UNIPHIER_PIN_DRV_4_8, + 47, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(52, "PCDOE", UNIPHIER_PIN_IECTRL_NONE, + 48, UNIPHIER_PIN_DRV_4_8, + 48, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(53, "PCCE1", UNIPHIER_PIN_IECTRL_NONE, + 49, UNIPHIER_PIN_DRV_4_8, + 49, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(54, "PCWE", UNIPHIER_PIN_IECTRL_NONE, + 50, UNIPHIER_PIN_DRV_4_8, + 50, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(55, "PCOE", UNIPHIER_PIN_IECTRL_NONE, + 51, UNIPHIER_PIN_DRV_4_8, + 51, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(56, "PCWAIT", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_4_8, + 52, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(57, "PCIOWR", UNIPHIER_PIN_IECTRL_NONE, + 53, UNIPHIER_PIN_DRV_4_8, + 53, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "PCIORD", UNIPHIER_PIN_IECTRL_NONE, + 54, UNIPHIER_PIN_DRV_4_8, + 54, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(59, "HS0DIN0", UNIPHIER_PIN_IECTRL_NONE, + 55, UNIPHIER_PIN_DRV_4_8, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(60, "HS0DIN1", UNIPHIER_PIN_IECTRL_NONE, + 56, UNIPHIER_PIN_DRV_4_8, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "HS0DIN2", UNIPHIER_PIN_IECTRL_NONE, + 57, UNIPHIER_PIN_DRV_4_8, + 57, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(62, "HS0DIN3", UNIPHIER_PIN_IECTRL_NONE, + 58, UNIPHIER_PIN_DRV_4_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(63, "HS0DIN4", UNIPHIER_PIN_IECTRL_NONE, + 59, UNIPHIER_PIN_DRV_4_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(64, "HS0DIN5", UNIPHIER_PIN_IECTRL_NONE, + 60, UNIPHIER_PIN_DRV_4_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "HS0DIN6", UNIPHIER_PIN_IECTRL_NONE, + 61, UNIPHIER_PIN_DRV_4_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "HS0DIN7", UNIPHIER_PIN_IECTRL_NONE, + 62, UNIPHIER_PIN_DRV_4_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "HS0BCLKIN", UNIPHIER_PIN_IECTRL_NONE, + 63, UNIPHIER_PIN_DRV_4_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "HS0VALIN", UNIPHIER_PIN_IECTRL_NONE, + 64, UNIPHIER_PIN_DRV_4_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "HS0SYNCIN", UNIPHIER_PIN_IECTRL_NONE, + 65, UNIPHIER_PIN_DRV_4_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "HSDOUT0", UNIPHIER_PIN_IECTRL_NONE, + 66, UNIPHIER_PIN_DRV_4_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "HSDOUT1", UNIPHIER_PIN_IECTRL_NONE, + 67, UNIPHIER_PIN_DRV_4_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "HSDOUT2", UNIPHIER_PIN_IECTRL_NONE, + 68, UNIPHIER_PIN_DRV_4_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "HSDOUT3", UNIPHIER_PIN_IECTRL_NONE, + 69, UNIPHIER_PIN_DRV_4_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "HSDOUT4", UNIPHIER_PIN_IECTRL_NONE, + 70, UNIPHIER_PIN_DRV_4_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "HSDOUT5", UNIPHIER_PIN_IECTRL_NONE, + 71, UNIPHIER_PIN_DRV_4_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "HSDOUT6", UNIPHIER_PIN_IECTRL_NONE, + 72, UNIPHIER_PIN_DRV_4_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "HSDOUT7", UNIPHIER_PIN_IECTRL_NONE, + 73, UNIPHIER_PIN_DRV_4_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "HSBCLKOUT", UNIPHIER_PIN_IECTRL_NONE, + 74, UNIPHIER_PIN_DRV_4_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "HSVALOUT", UNIPHIER_PIN_IECTRL_NONE, + 75, UNIPHIER_PIN_DRV_4_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "HSSYNCOUT", UNIPHIER_PIN_IECTRL_NONE, + 76, UNIPHIER_PIN_DRV_4_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "HS1DIN0", UNIPHIER_PIN_IECTRL_NONE, + 77, UNIPHIER_PIN_DRV_4_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "HS1DIN1", UNIPHIER_PIN_IECTRL_NONE, + 78, UNIPHIER_PIN_DRV_4_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "HS1DIN2", UNIPHIER_PIN_IECTRL_NONE, + 79, UNIPHIER_PIN_DRV_4_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "HS1DIN3", UNIPHIER_PIN_IECTRL_NONE, + 80, UNIPHIER_PIN_DRV_4_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "HS1DIN4", UNIPHIER_PIN_IECTRL_NONE, + 81, UNIPHIER_PIN_DRV_4_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "HS1DIN5", UNIPHIER_PIN_IECTRL_NONE, + 82, UNIPHIER_PIN_DRV_4_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "HS1DIN6", UNIPHIER_PIN_IECTRL_NONE, + 83, UNIPHIER_PIN_DRV_4_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "HS1DIN7", UNIPHIER_PIN_IECTRL_NONE, + 84, UNIPHIER_PIN_DRV_4_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "HS1BCLKIN", UNIPHIER_PIN_IECTRL_NONE, + 85, UNIPHIER_PIN_DRV_4_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "HS1VALIN", UNIPHIER_PIN_IECTRL_NONE, + 86, UNIPHIER_PIN_DRV_4_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "HS1SYNCIN", UNIPHIER_PIN_IECTRL_NONE, + 87, UNIPHIER_PIN_DRV_4_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "AGCI", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 132, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "AGCR", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 133, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "AGCBS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 134, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "IECOUT", UNIPHIER_PIN_IECTRL_NONE, + 88, UNIPHIER_PIN_DRV_4_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "ASMCK", UNIPHIER_PIN_IECTRL_NONE, + 89, UNIPHIER_PIN_DRV_4_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "ABCKO", UNIPHIER_PIN_IECTRL_NONE, + 90, UNIPHIER_PIN_DRV_4_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "ALRCKO", UNIPHIER_PIN_IECTRL_NONE, + 91, UNIPHIER_PIN_DRV_4_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "ASDOUT0", UNIPHIER_PIN_IECTRL_NONE, + 92, UNIPHIER_PIN_DRV_4_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "ASDOUT1", UNIPHIER_PIN_IECTRL_NONE, + 93, UNIPHIER_PIN_DRV_4_8, + 93, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(101, "ARCOUT", UNIPHIER_PIN_IECTRL_NONE, + 94, UNIPHIER_PIN_DRV_4_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(103, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(104, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(105, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(106, "DMDSDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(107, "DMDSCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(108, "DMDSDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(109, "DMDSCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(110, "SBO0", UNIPHIER_PIN_IECTRL_NONE, + 95, UNIPHIER_PIN_DRV_4_8, + 95, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(111, "SBI0", UNIPHIER_PIN_IECTRL_NONE, + 96, UNIPHIER_PIN_DRV_4_8, + 96, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(112, "SBO1", UNIPHIER_PIN_IECTRL_NONE, + 97, UNIPHIER_PIN_DRV_4_8, + 97, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(113, "SBI1", UNIPHIER_PIN_IECTRL_NONE, + 98, UNIPHIER_PIN_DRV_4_8, + 98, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(114, "TXD1", UNIPHIER_PIN_IECTRL_NONE, + 99, UNIPHIER_PIN_DRV_4_8, + 99, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(115, "RXD1", UNIPHIER_PIN_IECTRL_NONE, + 100, UNIPHIER_PIN_DRV_4_8, + 100, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(116, "HIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(117, "VIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(118, "TCON0", UNIPHIER_PIN_IECTRL_NONE, + 101, UNIPHIER_PIN_DRV_4_8, + 101, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(119, "TCON1", UNIPHIER_PIN_IECTRL_NONE, + 102, UNIPHIER_PIN_DRV_4_8, + 102, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(120, "TCON2", UNIPHIER_PIN_IECTRL_NONE, + 103, UNIPHIER_PIN_DRV_4_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(121, "TCON3", UNIPHIER_PIN_IECTRL_NONE, + 104, UNIPHIER_PIN_DRV_4_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "TCON4", UNIPHIER_PIN_IECTRL_NONE, + 105, UNIPHIER_PIN_DRV_4_8, + 105, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(123, "TCON5", UNIPHIER_PIN_IECTRL_NONE, + 106, UNIPHIER_PIN_DRV_4_8, + 106, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "TCON6", UNIPHIER_PIN_IECTRL_NONE, + 107, UNIPHIER_PIN_DRV_4_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(125, "TCON7", UNIPHIER_PIN_IECTRL_NONE, + 108, UNIPHIER_PIN_DRV_4_8, + 108, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(126, "TCON8", UNIPHIER_PIN_IECTRL_NONE, + 109, UNIPHIER_PIN_DRV_4_8, + 109, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(127, "PWMA", UNIPHIER_PIN_IECTRL_NONE, + 110, UNIPHIER_PIN_DRV_4_8, + 110, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(128, "XIRQ0", UNIPHIER_PIN_IECTRL_NONE, + 111, UNIPHIER_PIN_DRV_4_8, + 111, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(129, "XIRQ1", UNIPHIER_PIN_IECTRL_NONE, + 112, UNIPHIER_PIN_DRV_4_8, + 112, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(130, "XIRQ2", UNIPHIER_PIN_IECTRL_NONE, + 113, UNIPHIER_PIN_DRV_4_8, + 113, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(131, "XIRQ3", UNIPHIER_PIN_IECTRL_NONE, + 114, UNIPHIER_PIN_DRV_4_8, + 114, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(132, "XIRQ4", UNIPHIER_PIN_IECTRL_NONE, + 115, UNIPHIER_PIN_DRV_4_8, + 115, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(133, "XIRQ5", UNIPHIER_PIN_IECTRL_NONE, + 116, UNIPHIER_PIN_DRV_4_8, + 116, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(134, "XIRQ6", UNIPHIER_PIN_IECTRL_NONE, + 117, UNIPHIER_PIN_DRV_4_8, + 117, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(135, "XIRQ7", UNIPHIER_PIN_IECTRL_NONE, + 118, UNIPHIER_PIN_DRV_4_8, + 118, UNIPHIER_PIN_PULL_DOWN), +}; + +static const unsigned emmc_pins[] = {21, 22, 23, 24, 25, 26, 27}; +static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {28, 29, 30, 31}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {102, 103}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {104, 105}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {108, 109}; +static const unsigned i2c2_muxvals[] = {2, 2}; +static const unsigned i2c3_pins[] = {108, 109}; +static const unsigned i2c3_muxvals[] = {3, 3}; +static const unsigned nand_pins[] = {15, 16, 17, 18, 19, 20, 21, 24, 25, 26, + 27, 28, 29, 30, 31}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {22, 23}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned uart0_pins[] = {70, 71}; +static const unsigned uart0_muxvals[] = {3, 3}; +static const unsigned uart1_pins[] = {114, 115}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart2_pins[] = {112, 113}; +static const unsigned uart2_muxvals[] = {1, 1}; +static const unsigned uart3_pins[] = {110, 111}; +static const unsigned uart3_muxvals[] = {1, 1}; +static const unsigned usb0_pins[] = {41, 42}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {43, 44}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {114, 115}; +static const unsigned usb2_muxvals[] = {1, 1}; +static const unsigned port_range0_pins[] = { + 0, 1, 2, 3, 4, 5, 6, 7, /* PORT0x */ + 8, 9, 10, 11, 12, 13, 14, 15, /* PORT1x */ + 32, 33, 34, 35, 36, 37, 38, 39, /* PORT2x */ + 59, 60, 61, 62, 63, 64, 65, 66, /* PORT3x */ + 95, 96, 97, 98, 99, 100, 101, 57, /* PORT4x */ + 70, 71, 72, 73, 74, 75, 76, 77, /* PORT5x */ + 81, 83, 84, 85, 86, 89, 90, 91, /* PORT6x */ + 118, 119, 120, 121, 122, 53, 54, 55, /* PORT7x */ + 41, 42, 43, 44, 79, 80, 18, 19, /* PORT8x */ + 110, 111, 112, 113, 114, 115, 16, 17, /* PORT9x */ + 40, 67, 68, 69, 78, 92, 93, 94, /* PORT10x */ + 48, 49, 46, 45, 123, 124, 125, 126, /* PORT11x */ + 47, 127, 20, 56, 22, /* PORT120-124 */ +}; +static const unsigned port_range0_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT3x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT4x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT5x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT6x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT11x */ + 15, 15, 15, 15, 15, /* PORT120-124 */ +}; +static const unsigned port_range1_pins[] = { + 116, 117, /* PORT130-131 */ +}; +static const unsigned port_range1_muxvals[] = { + 15, 15, /* PORT130-131 */ +}; +static const unsigned port_range2_pins[] = { + 102, 103, 104, 105, 106, 107, 108, 109, /* PORT14x */ +}; +static const unsigned port_range2_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */ +}; +static const unsigned port_range3_pins[] = { + 23, /* PORT166 */ +}; +static const unsigned port_range3_muxvals[] = { + 15, /* PORT166 */ +}; +static const unsigned xirq_range0_pins[] = { + 128, 129, 130, 131, 132, 133, 134, 135, /* XIRQ0-7 */ + 82, 87, 88, 50, 51, /* XIRQ8-12 */ +}; +static const unsigned xirq_range0_muxvals[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* XIRQ0-7 */ + 14, 14, 14, 14, 14, /* XIRQ8-12 */ +}; +static const unsigned xirq_range1_pins[] = { + 52, 58, /* XIRQ14-15 */ +}; +static const unsigned xirq_range1_muxvals[] = { + 14, 14, /* XIRQ14-15 */ +}; + +static const struct uniphier_pinctrl_group ph1_sld8_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range2), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range3), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_range1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port110, port_range0, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port111, port_range0, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port112, port_range0, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port113, port_range0, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port114, port_range0, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port115, port_range0, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port116, port_range0, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port117, port_range0, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range0, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range0, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range0, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range0, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range0, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range1, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range2, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range2, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range2, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range2, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range2, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range2, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range2, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range2, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port166, port_range3, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq_range1, 1), +}; + +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0"}; +static const char * const uart1_groups[] = {"uart1"}; +static const char * const uart2_groups[] = {"uart2"}; +static const char * const uart3_groups[] = {"uart3"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + "port110", "port111", "port112", "port113", + "port114", "port115", "port116", "port117", + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + /* port150-164 missing */ + /* none */ "port165", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", /* none*/ "xirq14", "xirq15", +}; + +static const struct uniphier_pinmux_function ph1_sld8_functions[] = { + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(uart3), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata ph1_sld8_pindata = { + .groups = ph1_sld8_groups, + .groups_count = ARRAY_SIZE(ph1_sld8_groups), + .functions = ph1_sld8_functions, + .functions_count = ARRAY_SIZE(ph1_sld8_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static struct pinctrl_desc ph1_sld8_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = ph1_sld8_pins, + .npins = ARRAY_SIZE(ph1_sld8_pins), + .owner = THIS_MODULE, +}; + +static int ph1_sld8_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &ph1_sld8_pinctrl_desc, + &ph1_sld8_pindata); +} + +static const struct of_device_id ph1_sld8_pinctrl_match[] = { + { .compatible = "socionext,ph1-sld8-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ph1_sld8_pinctrl_match); + +static struct platform_driver ph1_sld8_pinctrl_driver = { + .probe = ph1_sld8_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = ph1_sld8_pinctrl_match, + }, +}; +module_platform_driver(ph1_sld8_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier PH1-sLD8 pinctrl driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 1950b0488780d0d93481e17c56bc7a97a6037459 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:05 +0900 Subject: pinctrl: UniPhier: add UniPhier PH1-Pro5 pinctrl driver Add pin configuration and pinmux support for UniPhier PH1-Pro5 SoC. Changes in v2: - sort groups and funcs alphabetically - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 1 + drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c | 1346 +++++++++++++++++++++++++++ 3 files changed, 1351 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c (limited to 'drivers') diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index f4a21feeff61..89bda60066bd 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -17,4 +17,8 @@ config PINCTRL_UNIPHIER_PH1_SLD8 tristate "UniPhier PH1-sLD8 SoC pinctrl driver" select PINCTRL_UNIPHIER_CORE +config PINCTRL_UNIPHIER_PH1_PRO5 + tristate "UniPhier PH1-Pro5 SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index 3349fff80aa9..b0cd3e86bc94 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_SLD8) += pinctrl-ph1-sld8.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO5) += pinctrl-ph1-pro5.o diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c b/drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c new file mode 100644 index 000000000000..b35cf4a24bb7 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c @@ -0,0 +1,1346 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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 program5 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 "pinctrl-uniphier.h" + +#define DRIVER_NAME "ph1-pro5-pinctrl" + +static const struct pinctrl_pin_desc ph1_pro5_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "AEXCKA1", 0, + 0, UNIPHIER_PIN_DRV_4_8, + 0, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "AEXCKA2", 0, + 1, UNIPHIER_PIN_DRV_4_8, + 1, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "CK27EXI", 0, + 2, UNIPHIER_PIN_DRV_4_8, + 2, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "CK54EXI", 0, + 3, UNIPHIER_PIN_DRV_4_8, + 3, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "ED0", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_4_8, + 4, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(5, "ED1", UNIPHIER_PIN_IECTRL_NONE, + 5, UNIPHIER_PIN_DRV_4_8, + 5, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "ED2", UNIPHIER_PIN_IECTRL_NONE, + 6, UNIPHIER_PIN_DRV_4_8, + 6, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "ED3", UNIPHIER_PIN_IECTRL_NONE, + 7, UNIPHIER_PIN_DRV_4_8, + 7, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "ED4", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_4_8, + 8, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "ED5", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_4_8, + 9, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "ED6", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_4_8, + 10, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "ED7", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_4_8, + 11, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(12, "XERWE0", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_4_8, + 12, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(13, "XERWE1", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_4_8, + 13, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(14, "ERXW", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_4_8, + 14, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(15, "ES0", UNIPHIER_PIN_IECTRL_NONE, + 15, UNIPHIER_PIN_DRV_4_8, + 15, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(16, "ES1", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_4_8, + 16, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(17, "ES2", UNIPHIER_PIN_IECTRL_NONE, + 17, UNIPHIER_PIN_DRV_4_8, + 17, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(18, "XECS1", UNIPHIER_PIN_IECTRL_NONE, + 18, UNIPHIER_PIN_DRV_4_8, + 18, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(19, "XNFRE", UNIPHIER_PIN_IECTRL_NONE, + 19, UNIPHIER_PIN_DRV_4_8, + 19, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(20, "XNFWE", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_4_8, + 20, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(21, "NFALE", UNIPHIER_PIN_IECTRL_NONE, + 21, UNIPHIER_PIN_DRV_4_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(22, "NFCLE", UNIPHIER_PIN_IECTRL_NONE, + 22, UNIPHIER_PIN_DRV_4_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(23, "XNFWP", UNIPHIER_PIN_IECTRL_NONE, + 23, UNIPHIER_PIN_DRV_4_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(24, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_4_8, + 24, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(25, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE, + 25, UNIPHIER_PIN_DRV_4_8, + 25, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(26, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE, + 26, UNIPHIER_PIN_DRV_4_8, + 26, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(27, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE, + 27, UNIPHIER_PIN_DRV_4_8, + 27, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(28, "NFD0", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_4_8, + 28, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(29, "NFD1", UNIPHIER_PIN_IECTRL_NONE, + 29, UNIPHIER_PIN_DRV_4_8, + 29, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(30, "NFD2", UNIPHIER_PIN_IECTRL_NONE, + 30, UNIPHIER_PIN_DRV_4_8, + 30, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(31, "NFD3", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(32, "NFD4", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(33, "NFD5", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(34, "NFD6", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(35, "NFD7", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(36, "XERST", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(37, "MMCCLK", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(38, "MMCCMD", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(39, "MMCDAT0", UNIPHIER_PIN_IECTRL_NONE, + 39, UNIPHIER_PIN_DRV_4_8, + 39, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(40, "MMCDAT1", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_4_8, + 40, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(41, "MMCDAT2", UNIPHIER_PIN_IECTRL_NONE, + 41, UNIPHIER_PIN_DRV_4_8, + 41, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(42, "MMCDAT3", UNIPHIER_PIN_IECTRL_NONE, + 42, UNIPHIER_PIN_DRV_4_8, + 42, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(43, "MMCDAT4", UNIPHIER_PIN_IECTRL_NONE, + 43, UNIPHIER_PIN_DRV_4_8, + 43, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(44, "MMCDAT5", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_4_8, + 44, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(45, "MMCDAT6", UNIPHIER_PIN_IECTRL_NONE, + 45, UNIPHIER_PIN_DRV_4_8, + 45, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(46, "MMCDAT7", UNIPHIER_PIN_IECTRL_NONE, + 46, UNIPHIER_PIN_DRV_4_8, + 46, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(47, "TXD0", 0, + 47, UNIPHIER_PIN_DRV_4_8, + 47, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(48, "RXD0", 0, + 48, UNIPHIER_PIN_DRV_4_8, + 48, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(49, "TXD1", 0, + 49, UNIPHIER_PIN_DRV_4_8, + 49, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(50, "RXD1", 0, + 50, UNIPHIER_PIN_DRV_4_8, + 50, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(51, "TXD2", UNIPHIER_PIN_IECTRL_NONE, + 51, UNIPHIER_PIN_DRV_4_8, + 51, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(52, "RXD2", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_4_8, + 52, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(53, "TXD3", 0, + 53, UNIPHIER_PIN_DRV_4_8, + 53, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(54, "RXD3", 0, + 54, UNIPHIER_PIN_DRV_4_8, + 54, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(55, "MS0CS0", 0, + 55, UNIPHIER_PIN_DRV_4_8, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(56, "MS0DO", 0, + 56, UNIPHIER_PIN_DRV_4_8, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(57, "MS0DI", 0, + 57, UNIPHIER_PIN_DRV_4_8, + 57, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "MS0CLK", 0, + 58, UNIPHIER_PIN_DRV_4_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(59, "CSCLK", 0, + 59, UNIPHIER_PIN_DRV_4_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(60, "CSBPTM", 0, + 60, UNIPHIER_PIN_DRV_4_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "CSBMTP", 0, + 61, UNIPHIER_PIN_DRV_4_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(62, "XCINTP", 0, + 62, UNIPHIER_PIN_DRV_4_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(63, "XCINTM", 0, + 63, UNIPHIER_PIN_DRV_4_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(64, "XCMPREQ", 0, + 64, UNIPHIER_PIN_DRV_4_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "XSRST", 0, + 65, UNIPHIER_PIN_DRV_4_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "LPST", UNIPHIER_PIN_IECTRL_NONE, + 66, UNIPHIER_PIN_DRV_4_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "PWMA", 0, + 67, UNIPHIER_PIN_DRV_4_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "XIRQ0", 0, + 68, UNIPHIER_PIN_DRV_4_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "XIRQ1", 0, + 69, UNIPHIER_PIN_DRV_4_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "XIRQ2", 0, + 70, UNIPHIER_PIN_DRV_4_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "XIRQ3", 0, + 71, UNIPHIER_PIN_DRV_4_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "XIRQ4", 0, + 72, UNIPHIER_PIN_DRV_4_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "XIRQ5", 0, + 73, UNIPHIER_PIN_DRV_4_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "XIRQ6", 0, + 74, UNIPHIER_PIN_DRV_4_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "XIRQ7", 0, + 75, UNIPHIER_PIN_DRV_4_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "XIRQ8", 0, + 76, UNIPHIER_PIN_DRV_4_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "XIRQ9", 0, + 77, UNIPHIER_PIN_DRV_4_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "XIRQ10", 0, + 78, UNIPHIER_PIN_DRV_4_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "XIRQ11", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "XIRQ12", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "XIRQ13", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "XIRQ14", 0, + 82, UNIPHIER_PIN_DRV_4_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "XIRQ15", 0, + 83, UNIPHIER_PIN_DRV_4_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "XIRQ16", 0, + 84, UNIPHIER_PIN_DRV_4_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "XIRQ17", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "XIRQ18", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "XIRQ19", 0, + 87, UNIPHIER_PIN_DRV_4_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "XIRQ20", 0, + 88, UNIPHIER_PIN_DRV_4_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "PORT00", 0, + 89, UNIPHIER_PIN_DRV_4_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "PORT01", 0, + 90, UNIPHIER_PIN_DRV_4_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "PORT02", 0, + 91, UNIPHIER_PIN_DRV_4_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "PORT03", 0, + 92, UNIPHIER_PIN_DRV_4_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "PORT04", 0, + 93, UNIPHIER_PIN_DRV_4_8, + 93, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "PORT05", 0, + 94, UNIPHIER_PIN_DRV_4_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "PORT06", 0, + 95, UNIPHIER_PIN_DRV_4_8, + 95, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "PORT07", 0, + 96, UNIPHIER_PIN_DRV_4_8, + 96, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "PORT10", 0, + 97, UNIPHIER_PIN_DRV_4_8, + 97, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "PORT11", 0, + 98, UNIPHIER_PIN_DRV_4_8, + 98, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "PORT12", 0, + 99, UNIPHIER_PIN_DRV_4_8, + 99, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "PORT13", 0, + 100, UNIPHIER_PIN_DRV_4_8, + 100, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(101, "PORT14", 0, + 101, UNIPHIER_PIN_DRV_4_8, + 101, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "PORT15", 0, + 102, UNIPHIER_PIN_DRV_4_8, + 102, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(103, "PORT16", 0, + 103, UNIPHIER_PIN_DRV_4_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(104, "PORT17", 0, + 104, UNIPHIER_PIN_DRV_4_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(105, "T0HPD", 0, + 105, UNIPHIER_PIN_DRV_4_8, + 105, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(106, "T1HPD", 0, + 106, UNIPHIER_PIN_DRV_4_8, + 106, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(107, "R0HPD", 0, + 107, UNIPHIER_PIN_DRV_4_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(108, "R1HPD", 0, + 108, UNIPHIER_PIN_DRV_4_8, + 108, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(109, "XPERST", 0, + 109, UNIPHIER_PIN_DRV_4_8, + 109, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(110, "XPEWAKE", 0, + 110, UNIPHIER_PIN_DRV_4_8, + 110, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(111, "XPECLKRQ", 0, + 111, UNIPHIER_PIN_DRV_4_8, + 111, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(112, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 112, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(113, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 113, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(114, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 114, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(115, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 115, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(116, "SDA2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 116, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(117, "SCL2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 117, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(118, "SDA3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 118, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(119, "SCL3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 119, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(120, "SPISYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 120, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(121, "SPISCLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 121, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "SPITXD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 122, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(123, "SPIRXD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 123, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 124, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(125, "USB0OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 125, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(126, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 126, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(127, "USB1OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 127, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(128, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 128, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(129, "USB2OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 129, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(130, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 130, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(131, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 131, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(132, "SMTD0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 132, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(133, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 133, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(134, "SMTCLK0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 134, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(135, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 135, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(136, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 136, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(137, "SMTD1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 137, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(138, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 138, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(139, "SMTCLK1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 139, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(140, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 140, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(141, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 141, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(142, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 142, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(143, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 143, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(144, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 144, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(145, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 145, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(146, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 146, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(147, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 147, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(148, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 148, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(149, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 149, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(150, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 150, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(151, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 151, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(152, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 152, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(153, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 153, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(154, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 154, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(155, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 155, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(156, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 156, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(157, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 157, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(158, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 158, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(159, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 159, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(160, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 160, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(161, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 161, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(162, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 162, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(163, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 163, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(164, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 164, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(165, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 165, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(166, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 166, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(167, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 167, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(168, "CH7CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 168, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(169, "CH7PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 169, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(170, "CH7VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 170, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(171, "CH7DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 171, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(172, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 172, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(173, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 173, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(174, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 174, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(175, "AI1D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 175, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(176, "AI1D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 176, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(177, "AI1D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 177, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(178, "AI1D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 178, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(179, "AI2ADCCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 179, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(180, "AI2BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 180, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(181, "AI2LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 181, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(182, "AI2D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 182, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(183, "AI2D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 183, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(184, "AI2D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 184, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(185, "AI2D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 185, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(186, "AI3ADCCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 186, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(187, "AI3BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 187, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(188, "AI3LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 188, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(189, "AI3D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 189, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(190, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 190, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(191, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 191, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(192, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 192, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(193, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 193, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(194, "AO1D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 194, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(195, "AO1D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 195, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(196, "AO1D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 196, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(197, "AO1D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 197, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(198, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 198, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(199, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 199, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(200, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 200, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(201, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 201, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(202, "AO2D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 202, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(203, "AO2D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 203, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(204, "AO2D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 204, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(205, "AO2D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 205, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(206, "AO3DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 206, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(207, "AO3BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 207, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(208, "AO3LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 208, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(209, "AO3DMIX", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 209, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(210, "AO4DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 210, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(211, "AO4BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 211, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(212, "AO4LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 212, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(213, "AO4DMIX", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 213, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(214, "VI1CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 214, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(215, "VI1C0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 215, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(216, "VI1C1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 216, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(217, "VI1C2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 217, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(218, "VI1C3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 218, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(219, "VI1C4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 219, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(220, "VI1C5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 220, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(221, "VI1C6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 221, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(222, "VI1C7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 222, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(223, "VI1C8", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 223, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(224, "VI1C9", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 224, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(225, "VI1Y0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 225, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(226, "VI1Y1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 226, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(227, "VI1Y2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 227, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(228, "VI1Y3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 228, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(229, "VI1Y4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 229, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(230, "VI1Y5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 230, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(231, "VI1Y6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 231, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(232, "VI1Y7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 232, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(233, "VI1Y8", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 233, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(234, "VI1Y9", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 234, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(235, "VI1DE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 235, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(236, "VI1HSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 236, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(237, "VI1VSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 237, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(238, "VO1CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 238, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(239, "VO1D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 239, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(240, "VO1D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 240, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(241, "VO1D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 241, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(242, "VO1D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 242, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(243, "VO1D4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 243, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(244, "VO1D5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 244, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(245, "VO1D6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 245, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(246, "VO1D7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 246, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(247, "SDCD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 247, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(248, "SDWP", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 248, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(249, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 249, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(250, "SDCLK", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(251, "SDCMD", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(252, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE, + 48, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(253, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(254, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE, + 56, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(255, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE, + 60, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), +}; + +static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42}; +static const unsigned emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0}; +static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46}; +static const unsigned emmc_dat8_muxvals[] = {0, 0, 0, 0}; +static const unsigned i2c0_pins[] = {112, 113}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {114, 115}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {116, 117}; +static const unsigned i2c2_muxvals[] = {0, 0}; +static const unsigned i2c3_pins[] = {118, 119}; +static const unsigned i2c3_muxvals[] = {0, 0}; +static const unsigned i2c5_pins[] = {87, 88}; +static const unsigned i2c5_muxvals[] = {2, 2}; +static const unsigned i2c5b_pins[] = {196, 197}; +static const unsigned i2c5b_muxvals[] = {2, 2}; +static const unsigned i2c5c_pins[] = {215, 216}; +static const unsigned i2c5c_muxvals[] = {2, 2}; +static const unsigned nand_pins[] = {19, 20, 21, 22, 23, 24, 25, 28, 29, 30, + 31, 32, 33, 34, 35}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {26, 27}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned uart0_pins[] = {47, 48}; +static const unsigned uart0_muxvals[] = {0, 0}; +static const unsigned uart0b_pins[] = {227, 228}; +static const unsigned uart0b_muxvals[] = {3, 3}; +static const unsigned uart1_pins[] = {49, 50}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart2_pins[] = {51, 52}; +static const unsigned uart2_muxvals[] = {0, 0}; +static const unsigned uart3_pins[] = {53, 54}; +static const unsigned uart3_muxvals[] = {0, 0}; +static const unsigned usb0_pins[] = {124, 125}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {126, 127}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {128, 129}; +static const unsigned usb2_muxvals[] = {0, 0}; +static const unsigned port_range0_pins[] = { + 89, 90, 91, 92, 93, 94, 95, 96, /* PORT0x */ + 97, 98, 99, 100, 101, 102, 103, 104, /* PORT1x */ + 251, 252, 253, 254, 255, 247, 248, 249, /* PORT2x */ + 39, 40, 41, 42, 43, 44, 45, 46, /* PORT3x */ + 156, 157, 158, 159, 160, 161, 162, 163, /* PORT4x */ + 164, 165, 166, 167, 168, 169, 170, 171, /* PORT5x */ + 190, 191, 192, 193, 194, 195, 196, 197, /* PORT6x */ + 198, 199, 200, 201, 202, 203, 204, 205, /* PORT7x */ + 120, 121, 122, 123, 55, 56, 57, 58, /* PORT8x */ + 124, 125, 126, 127, 49, 50, 53, 54, /* PORT9x */ + 148, 149, 150, 151, 152, 153, 154, 155, /* PORT10x */ + 133, 134, 131, 130, 138, 139, 136, 135, /* PORT11x */ + 28, 29, 30, 31, 32, 33, 34, 35, /* PORT12x */ + 179, 180, 181, 182, 186, 187, 188, 189, /* PORT13x */ + 4, 5, 6, 7, 8, 9, 10, 11, /* PORT14x */ +}; +static const unsigned port_range0_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT3x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT4x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT5x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT6x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT11x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */ +}; +static const unsigned port_range1_pins[] = { + 109, 110, 111, /* PORT175-177 */ + 206, 207, 208, 209, 210, 211, 212, 213, /* PORT18x */ + 12, 13, 14, 15, 16, 17, 107, 108, /* PORT19x */ + 140, 141, 142, 143, 144, 145, 146, 147, /* PORT20x */ + 59, 60, 61, 62, 63, 64, 65, 66, /* PORT21x */ + 214, 215, 216, 217, 218, 219, 220, 221, /* PORT22x */ + 222, 223, 224, 225, 226, 227, 228, 229, /* PORT23x */ + 19, 20, 21, 22, 23, 24, 25, 26, /* PORT24x */ + 230, 231, 232, 233, 234, 235, 236, 237, /* PORT25x */ + 239, 240, 241, 242, 243, 244, 245, 246, /* PORT26x */ + 172, 173, 174, 175, 176, 177, 178, 129, /* PORT27x */ + 0, 1, 2, 67, 85, 86, 87, 88, /* PORT28x */ + 105, 106, 18, 27, 36, 128, 132, 137, /* PORT29x */ + 183, 184, 185, 84, 47, 48, 51, 52, /* PORT30x */ +}; +static const unsigned port_range1_muxvals[] = { + 15, 15, 15, /* PORT175-177 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT18x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT19x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT20x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT21x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT22x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT23x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT24x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT25x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT26x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT27x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT28x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT29x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT30x */ +}; +static const unsigned xirq_pins[] = { + 68, 69, 70, 71, 72, 73, 74, 75, /* XIRQ0-7 */ + 76, 77, 78, 79, 80, 81, 82, 83, /* XIRQ8-15 */ + 84, 85, 86, 87, 88, /* XIRQ16-20 */ +}; +static const unsigned xirq_muxvals[] = { + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ0-7 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ8-15 */ + 14, 14, 14, 14, 14, /* XIRQ16-20 */ +}; +static const unsigned xirq_alternatives_pins[] = { + 91, 92, 239, 144, 240, 156, 241, 106, 128, +}; +static const unsigned xirq_alternatives_muxvals[] = { + 14, 14, 14, 14, 14, 14, 14, 14, 14, +}; + +static const struct uniphier_pinctrl_group ph1_pro5_groups[] = { + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(i2c5), + UNIPHIER_PINCTRL_GROUP(i2c5b), + UNIPHIER_PINCTRL_GROUP(i2c5c), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart0b), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port110, port_range0, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port111, port_range0, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port112, port_range0, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port113, port_range0, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port114, port_range0, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port115, port_range0, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port116, port_range0, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port117, port_range0, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range0, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range0, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range0, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range0, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range0, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range0, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range0, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range0, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range0, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range0, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range0, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range0, 107), + UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range0, 108), + UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range0, 109), + UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range0, 110), + UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range0, 111), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range0, 112), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range0, 113), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range0, 114), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range0, 115), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range0, 116), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range0, 117), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range0, 118), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range0, 119), + UNIPHIER_PINCTRL_GROUP_SINGLE(port175, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port176, port_range1, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port177, port_range1, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range1, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range1, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range1, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range1, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range1, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range1, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range1, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range1, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port190, port_range1, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port191, port_range1, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port192, port_range1, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port193, port_range1, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port194, port_range1, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port195, port_range1, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port196, port_range1, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port197, port_range1, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range1, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range1, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range1, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range1, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range1, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range1, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range1, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range1, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range1, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range1, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range1, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range1, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range1, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range1, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range1, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range1, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range1, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range1, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range1, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range1, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range1, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range1, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range1, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range1, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range1, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range1, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range1, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range1, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range1, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range1, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range1, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range1, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range1, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range1, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range1, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range1, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range1, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range1, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range1, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range1, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range1, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range1, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range1, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range1, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range1, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port255, port_range1, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port256, port_range1, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port257, port_range1, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port260, port_range1, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port261, port_range1, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port262, port_range1, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port263, port_range1, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port264, port_range1, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port265, port_range1, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port266, port_range1, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port267, port_range1, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port270, port_range1, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port271, port_range1, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port272, port_range1, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port273, port_range1, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port274, port_range1, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port275, port_range1, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port276, port_range1, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port277, port_range1, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port280, port_range1, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port281, port_range1, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port282, port_range1, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port283, port_range1, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port284, port_range1, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port285, port_range1, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port286, port_range1, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port287, port_range1, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port290, port_range1, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port291, port_range1, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port292, port_range1, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port293, port_range1, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port294, port_range1, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port295, port_range1, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port296, port_range1, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port297, port_range1, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port300, port_range1, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port301, port_range1, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port302, port_range1, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port303, port_range1, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port304, port_range1, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port305, port_range1, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port306, port_range1, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port307, port_range1, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3b, xirq_alternatives, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4b, xirq_alternatives, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16b, xirq_alternatives, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17b, xirq_alternatives, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17c, xirq_alternatives, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18b, xirq_alternatives, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18c, xirq_alternatives, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19b, xirq_alternatives, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20b, xirq_alternatives, 8), +}; + +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const i2c5_groups[] = {"i2c5", "i2c5b", "i2c5c"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0", "uart0b"}; +static const char * const uart1_groups[] = {"uart1"}; +static const char * const uart2_groups[] = {"uart2"}; +static const char * const uart3_groups[] = {"uart3"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + "port110", "port111", "port112", "port113", + "port114", "port115", "port116", "port117", + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + /* port150-174 missing */ + /* none */ "port175", "port176", "port177", + "port180", "port181", "port182", "port183", + "port184", "port185", "port186", "port187", + "port190", "port191", "port192", "port193", + "port194", "port195", "port196", "port197", + "port200", "port201", "port202", "port203", + "port204", "port205", "port206", "port207", + "port210", "port211", "port212", "port213", + "port214", "port215", "port216", "port217", + "port220", "port221", "port222", "port223", + "port224", "port225", "port226", "port227", + "port230", "port231", "port232", "port233", + "port234", "port235", "port236", "port237", + "port240", "port241", "port242", "port243", + "port244", "port245", "port246", "port247", + "port250", "port251", "port252", "port253", + "port254", "port255", "port256", "port257", + "port260", "port261", "port262", "port263", + "port264", "port265", "port266", "port267", + "port270", "port271", "port272", "port273", + "port274", "port275", "port276", "port277", + "port280", "port281", "port282", "port283", + "port284", "port285", "port286", "port287", + "port290", "port291", "port292", "port293", + "port294", "port295", "port296", "port297", + "port300", "port301", "port302", "port303", + "port304", "port305", "port306", "port307", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", "xirq13", "xirq14", "xirq15", + "xirq16", "xirq17", "xirq18", "xirq19", + "xirq20", + "xirq3b", "xirq4b", "xirq16b", "xirq17b", "xirq17c", + "xirq18b", "xirq18c", "xirq19b", "xirq20b", +}; + +static const struct uniphier_pinmux_function ph1_pro5_functions[] = { + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(i2c5), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(uart3), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata ph1_pro5_pindata = { + .groups = ph1_pro5_groups, + .groups_count = ARRAY_SIZE(ph1_pro5_groups), + .functions = ph1_pro5_functions, + .functions_count = ARRAY_SIZE(ph1_pro5_functions), + .mux_bits = 4, + .reg_stride = 8, + .load_pinctrl = true, +}; + +static struct pinctrl_desc ph1_pro5_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = ph1_pro5_pins, + .npins = ARRAY_SIZE(ph1_pro5_pins), + .owner = THIS_MODULE, +}; + +static int ph1_pro5_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &ph1_pro5_pinctrl_desc, + &ph1_pro5_pindata); +} + +static const struct of_device_id ph1_pro5_pinctrl_match[] = { + { .compatible = "socionext,ph1-pro5-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ph1_pro5_pinctrl_match); + +static struct platform_driver ph1_pro5_pinctrl_driver = { + .probe = ph1_pro5_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = ph1_pro5_pinctrl_match, + }, +}; +module_platform_driver(ph1_pro5_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier PH1-Pro5 pinctrl driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 3c0fd8e3de93fc12b35cf5be585a5d8dc68b7162 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:06 +0900 Subject: pinctrl: UniPhier: add UniPhier ProXstream2 pinctrl driver Add pin configuration and pinmux support for UniPhier ProXstream2 SoC. Changes in v2: - sort groups and funcs alphabetically - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 1 + drivers/pinctrl/uniphier/pinctrl-proxstream2.c | 1269 ++++++++++++++++++++++++ 3 files changed, 1274 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-proxstream2.c (limited to 'drivers') diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index 89bda60066bd..69c5d5fa61da 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -21,4 +21,8 @@ config PINCTRL_UNIPHIER_PH1_PRO5 tristate "UniPhier PH1-Pro5 SoC pinctrl driver" select PINCTRL_UNIPHIER_CORE +config PINCTRL_UNIPHIER_PROXSTREAM2 + tristate "UniPhier ProXstream2 SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index b0cd3e86bc94..aed038c59f04 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_SLD8) += pinctrl-ph1-sld8.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO5) += pinctrl-ph1-pro5.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PROXSTREAM2) += pinctrl-proxstream2.o diff --git a/drivers/pinctrl/uniphier/pinctrl-proxstream2.c b/drivers/pinctrl/uniphier/pinctrl-proxstream2.c new file mode 100644 index 000000000000..3f036e236ad9 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-proxstream2.c @@ -0,0 +1,1269 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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 + +#include "pinctrl-uniphier.h" + +#define DRIVER_NAME "proxstream2-pinctrl" + +static const struct pinctrl_pin_desc proxstream2_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "ED0", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_4_8, + 0, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "ED1", UNIPHIER_PIN_IECTRL_NONE, + 1, UNIPHIER_PIN_DRV_4_8, + 1, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "ED2", UNIPHIER_PIN_IECTRL_NONE, + 2, UNIPHIER_PIN_DRV_4_8, + 2, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "ED3", UNIPHIER_PIN_IECTRL_NONE, + 3, UNIPHIER_PIN_DRV_4_8, + 3, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "ED4", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_4_8, + 4, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(5, "ED5", UNIPHIER_PIN_IECTRL_NONE, + 5, UNIPHIER_PIN_DRV_4_8, + 5, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "ED6", UNIPHIER_PIN_IECTRL_NONE, + 6, UNIPHIER_PIN_DRV_4_8, + 6, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "ED7", UNIPHIER_PIN_IECTRL_NONE, + 7, UNIPHIER_PIN_DRV_4_8, + 7, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "XERWE0", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_4_8, + 8, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "XERWE1", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_4_8, + 9, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "ERXW", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_4_8, + 10, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "ES0", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_4_8, + 11, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(12, "ES1", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_4_8, + 12, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(13, "ES2", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_4_8, + 13, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(14, "XECS1", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_4_8, + 14, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(15, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 15, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(16, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 16, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(17, "SMTD0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 17, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(18, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 18, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(19, "SMTCLK0CG", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 19, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(20, "SMTDET0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 20, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(21, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(22, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(23, "SMTD1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(24, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 24, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(25, "SMTCLK1CG", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 25, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(26, "SMTDET1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 26, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(27, "XIRQ18", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 27, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(28, "XIRQ19", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 28, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(29, "XIRQ20", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 29, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(30, "XNFRE", UNIPHIER_PIN_IECTRL_NONE, + 30, UNIPHIER_PIN_DRV_4_8, + 30, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(31, "XNFWE", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(32, "NFALE", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(33, "NFCLE", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(34, "XNFWP", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(35, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(36, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(37, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(38, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(39, "NFD0", UNIPHIER_PIN_IECTRL_NONE, + 39, UNIPHIER_PIN_DRV_4_8, + 39, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(40, "NFD1", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_4_8, + 40, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(41, "NFD2", UNIPHIER_PIN_IECTRL_NONE, + 41, UNIPHIER_PIN_DRV_4_8, + 41, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(42, "NFD3", UNIPHIER_PIN_IECTRL_NONE, + 42, UNIPHIER_PIN_DRV_4_8, + 42, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(43, "NFD4", UNIPHIER_PIN_IECTRL_NONE, + 43, UNIPHIER_PIN_DRV_4_8, + 43, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(44, "NFD5", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_4_8, + 44, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(45, "NFD6", UNIPHIER_PIN_IECTRL_NONE, + 45, UNIPHIER_PIN_DRV_4_8, + 45, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(46, "NFD7", UNIPHIER_PIN_IECTRL_NONE, + 46, UNIPHIER_PIN_DRV_4_8, + 46, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(47, "SDCLK", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(48, "SDCMD", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(49, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(50, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(51, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(52, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(53, "SDCD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 53, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(54, "SDWP", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 54, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(55, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(56, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(57, "USB0OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 57, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(59, "USB1OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(60, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "USB2OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(62, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(63, "USB3OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(64, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "XIRQ9", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "XIRQ10", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "XIRQ16", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "STS0CLKO", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "STS0SYNCO", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "STS0VALO", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "STS0DATAO", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "XIRQ17", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "PORT163", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "PORT165", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 93, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "PORT166", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "PORT132", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 95, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "PORT133", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 96, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 97, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "AI2ADCCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 98, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "AI2BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 99, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "AI2LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 100, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(101, "AI2D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 101, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "AI2D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 102, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(103, "AI2D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(104, "AI2D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(105, "AO3DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 105, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(106, "AO3BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 106, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(107, "AO3LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(108, "AO3DMIX", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 108, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(109, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 109, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(110, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 110, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(111, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 111, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(112, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 112, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(113, "TXD2", 0, + 113, UNIPHIER_PIN_DRV_4_8, + 113, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(114, "RXD2", 0, + 114, UNIPHIER_PIN_DRV_4_8, + 114, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(115, "TXD1", 0, + 115, UNIPHIER_PIN_DRV_4_8, + 115, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(116, "RXD1", 0, + 116, UNIPHIER_PIN_DRV_4_8, + 116, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(117, "PORT190", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 117, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(118, "VI1HSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 118, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(119, "VI1VSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 119, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(120, "VI1DE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 120, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(121, "XIRQ3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 121, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "XIRQ4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 122, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(123, "VI1G2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 123, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "VI1G3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 124, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(125, "VI1G4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 125, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(126, "VI1G5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 126, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(127, "VI1G6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 127, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(128, "VI1G7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 128, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(129, "VI1G8", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 129, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(130, "VI1G9", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 130, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(131, "VI1CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 131, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(132, "PORT05", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 132, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(133, "PORT06", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 133, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(134, "VI1R2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 134, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(135, "VI1R3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 135, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(136, "VI1R4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 136, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(137, "VI1R5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 137, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(138, "VI1R6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 138, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(139, "VI1R7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 139, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(140, "VI1R8", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 140, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(141, "VI1R9", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 141, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(142, "LPST", UNIPHIER_PIN_IECTRL_NONE, + 142, UNIPHIER_PIN_DRV_4_8, + 142, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(143, "MDC", 0, + 143, UNIPHIER_PIN_DRV_4_8, + 143, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(144, "MDIO", 0, + 144, UNIPHIER_PIN_DRV_4_8, + 144, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(145, "MDIO_INTL", 0, + 145, UNIPHIER_PIN_DRV_4_8, + 145, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(146, "PHYRSTL", 0, + 146, UNIPHIER_PIN_DRV_4_8, + 146, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(147, "RGMII_RXCLK", 0, + 147, UNIPHIER_PIN_DRV_4_8, + 147, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(148, "RGMII_RXD0", 0, + 148, UNIPHIER_PIN_DRV_4_8, + 148, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(149, "RGMII_RXD1", 0, + 149, UNIPHIER_PIN_DRV_4_8, + 149, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(150, "RGMII_RXD2", 0, + 150, UNIPHIER_PIN_DRV_4_8, + 150, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(151, "RGMII_RXD3", 0, + 151, UNIPHIER_PIN_DRV_4_8, + 151, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(152, "RGMII_RXCTL", 0, + 152, UNIPHIER_PIN_DRV_4_8, + 152, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(153, "RGMII_TXCLK", 0, + 153, UNIPHIER_PIN_DRV_4_8, + 153, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(154, "RGMII_TXD0", 0, + 154, UNIPHIER_PIN_DRV_4_8, + 154, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(155, "RGMII_TXD1", 0, + 155, UNIPHIER_PIN_DRV_4_8, + 155, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(156, "RGMII_TXD2", 0, + 156, UNIPHIER_PIN_DRV_4_8, + 156, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(157, "RGMII_TXD3", 0, + 157, UNIPHIER_PIN_DRV_4_8, + 157, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(158, "RGMII_TXCTL", 0, + 158, UNIPHIER_PIN_DRV_4_8, + 158, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(159, "SDA3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 159, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(160, "SCL3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 160, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(161, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 161, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(162, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 162, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(163, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 163, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(164, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 164, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(165, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 165, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(166, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 166, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(167, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 167, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(168, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 168, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(169, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 169, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(170, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 170, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(171, "SDA2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 171, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(172, "SCL2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 172, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(173, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 173, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(174, "AI1D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 174, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(175, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 175, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(176, "AO2D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 176, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(177, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 177, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(178, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 178, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(179, "PORT222", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 179, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(180, "PORT223", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 180, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(181, "PORT224", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 181, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(182, "PORT225", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 182, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(183, "PORT226", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 183, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(184, "PORT227", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 184, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(185, "PORT230", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 185, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(186, "FANPWM", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 186, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(187, "HRDDCSDA0", 0, + 187, UNIPHIER_PIN_DRV_4_8, + 187, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(188, "HRDDCSCL0", 0, + 188, UNIPHIER_PIN_DRV_4_8, + 188, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(189, "HRDDCSDA1", 0, + 189, UNIPHIER_PIN_DRV_4_8, + 189, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(190, "HRDDCSCL1", 0, + 190, UNIPHIER_PIN_DRV_4_8, + 190, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(191, "HTDDCSDA0", 0, + 191, UNIPHIER_PIN_DRV_4_8, + 191, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(192, "HTDDCSCL0", 0, + 192, UNIPHIER_PIN_DRV_4_8, + 192, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(193, "HTDDCSDA1", 0, + 193, UNIPHIER_PIN_DRV_4_8, + 193, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(194, "HTDDCSCL1", 0, + 194, UNIPHIER_PIN_DRV_4_8, + 194, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(195, "PORT241", 0, + 195, UNIPHIER_PIN_DRV_4_8, + 195, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(196, "PORT242", 0, + 196, UNIPHIER_PIN_DRV_4_8, + 196, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(197, "PORT243", 0, + 197, UNIPHIER_PIN_DRV_4_8, + 197, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(198, "MVSYNC", 0, + 198, UNIPHIER_PIN_DRV_4_8, + 198, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(199, "SPISYNC0", UNIPHIER_PIN_IECTRL_NONE, + 199, UNIPHIER_PIN_DRV_4_8, + 199, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(200, "SPISCLK0", UNIPHIER_PIN_IECTRL_NONE, + 200, UNIPHIER_PIN_DRV_4_8, + 200, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(201, "SPITXD0", UNIPHIER_PIN_IECTRL_NONE, + 201, UNIPHIER_PIN_DRV_4_8, + 201, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(202, "SPIRXD0", UNIPHIER_PIN_IECTRL_NONE, + 202, UNIPHIER_PIN_DRV_4_8, + 202, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(203, "CK54EXI", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 203, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(204, "AEXCKA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 204, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(205, "AEXCKA2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 205, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(206, "CK27EXI", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 206, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(207, "STCDIN", 0, + 207, UNIPHIER_PIN_DRV_4_8, + 207, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(208, "PHSYNI", 0, + 208, UNIPHIER_PIN_DRV_4_8, + 208, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(209, "PVSYNI", 0, + 209, UNIPHIER_PIN_DRV_4_8, + 209, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(210, "MVSYN", UNIPHIER_PIN_IECTRL_NONE, + 210, UNIPHIER_PIN_DRV_4_8, + 210, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(211, "STCV", UNIPHIER_PIN_IECTRL_NONE, + 211, UNIPHIER_PIN_DRV_4_8, + 211, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(212, "PORT262", UNIPHIER_PIN_IECTRL_NONE, + 212, UNIPHIER_PIN_DRV_4_8, + 212, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(213, "USB0VBUS_IRQ", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 213, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(214, "USB1VBUS_IRQ", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 214, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(215, "PORT265", UNIPHIER_PIN_IECTRL_NONE, + 215, UNIPHIER_PIN_DRV_4_8, + 215, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(216, "CK25O", 0, + 216, UNIPHIER_PIN_DRV_4_8, + 216, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(217, "TXD0", 0, + 217, UNIPHIER_PIN_DRV_4_8, + 217, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(218, "RXD0", 0, + 218, UNIPHIER_PIN_DRV_4_8, + 218, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(219, "TXD3", 0, + 219, UNIPHIER_PIN_DRV_4_8, + 219, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(220, "RXD3", 0, + 220, UNIPHIER_PIN_DRV_4_8, + 220, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(221, "PORT273", 0, + 221, UNIPHIER_PIN_DRV_4_8, + 221, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(222, "STCDOUTC", 0, + 222, UNIPHIER_PIN_DRV_4_8, + 222, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(223, "PORT274", 0, + 223, UNIPHIER_PIN_DRV_4_8, + 223, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(224, "PORT275", 0, + 224, UNIPHIER_PIN_DRV_4_8, + 224, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(225, "PORT276", 0, + 225, UNIPHIER_PIN_DRV_4_8, + 225, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(226, "PORT277", 0, + 226, UNIPHIER_PIN_DRV_4_8, + 226, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(227, "PORT280", 0, + 227, UNIPHIER_PIN_DRV_4_8, + 227, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(228, "PORT281", 0, + 228, UNIPHIER_PIN_DRV_4_8, + 228, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(229, "PORT282", 0, + 229, UNIPHIER_PIN_DRV_4_8, + 229, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(230, "PORT283", 0, + 230, UNIPHIER_PIN_DRV_4_8, + 230, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(231, "PORT284", 0, + 231, UNIPHIER_PIN_DRV_4_8, + 231, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(232, "PORT285", 0, + 232, UNIPHIER_PIN_DRV_4_8, + 232, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(233, "T0HPD", 0, + 233, UNIPHIER_PIN_DRV_4_8, + 233, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(234, "T1HPD", 0, + 234, UNIPHIER_PIN_DRV_4_8, + 234, UNIPHIER_PIN_PULL_DOWN), +}; + +static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42}; +static const unsigned emmc_muxvals[] = {9, 9, 9, 9, 9, 9, 9}; +static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46}; +static const unsigned emmc_dat8_muxvals[] = {9, 9, 9, 9}; +static const unsigned i2c0_pins[] = {109, 110}; +static const unsigned i2c0_muxvals[] = {8, 8}; +static const unsigned i2c1_pins[] = {111, 112}; +static const unsigned i2c1_muxvals[] = {8, 8}; +static const unsigned i2c2_pins[] = {171, 172}; +static const unsigned i2c2_muxvals[] = {8, 8}; +static const unsigned i2c3_pins[] = {159, 160}; +static const unsigned i2c3_muxvals[] = {8, 8}; +static const unsigned i2c5_pins[] = {183, 184}; +static const unsigned i2c5_muxvals[] = {11, 11}; +static const unsigned i2c6_pins[] = {185, 186}; +static const unsigned i2c6_muxvals[] = {11, 11}; +static const unsigned nand_pins[] = {30, 31, 32, 33, 34, 35, 36, 39, 40, 41, + 42, 43, 44, 45, 46}; +static const unsigned nand_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8}; +static const unsigned nand_cs1_pins[] = {37, 38}; +static const unsigned nand_cs1_muxvals[] = {8, 8}; +static const unsigned uart0_pins[] = {217, 218}; +static const unsigned uart0_muxvals[] = {8, 8}; +static const unsigned uart0b_pins[] = {179, 180}; +static const unsigned uart0b_muxvals[] = {10, 10}; +static const unsigned uart1_pins[] = {115, 116}; +static const unsigned uart1_muxvals[] = {8, 8}; +static const unsigned uart2_pins[] = {113, 114}; +static const unsigned uart2_muxvals[] = {8, 8}; +static const unsigned uart3_pins[] = {219, 220}; +static const unsigned uart3_muxvals[] = {8, 8}; +static const unsigned uart3b_pins[] = {181, 182}; +static const unsigned uart3b_muxvals[] = {10, 10}; +static const unsigned usb0_pins[] = {56, 57}; +static const unsigned usb0_muxvals[] = {8, 8}; +static const unsigned usb1_pins[] = {58, 59}; +static const unsigned usb1_muxvals[] = {8, 8}; +static const unsigned usb2_pins[] = {60, 61}; +static const unsigned usb2_muxvals[] = {8, 8}; +static const unsigned usb3_pins[] = {62, 63}; +static const unsigned usb3_muxvals[] = {8, 8}; +static const unsigned port_range0_pins[] = { + 127, 128, 129, 130, 131, 132, 133, 134, /* PORT0x */ + 135, 136, 137, 138, 139, 140, 141, 142, /* PORT1x */ + 0, 1, 2, 3, 4, 5, 6, 7, /* PORT2x */ + 8, 9, 10, 11, 12, 13, 14, 15, /* PORT3x */ + 16, 17, 18, 19, 21, 22, 23, 24, /* PORT4x */ + 25, 30, 31, 32, 33, 34, 35, 36, /* PORT5x */ + 37, 38, 39, 40, 41, 42, 43, 44, /* PORT6x */ + 45, 46, 47, 48, 49, 50, 51, 52, /* PORT7x */ + 53, 54, 55, 56, 57, 58, 59, 60, /* PORT8x */ + 61, 62, 63, 64, 65, 66, 67, 68, /* PORT9x */ + 69, 70, 71, 76, 77, 78, 79, 80, /* PORT10x */ +}; +static const unsigned port_range0_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT3x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT4x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT5x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT6x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */ +}; +static const unsigned port_range1_pins[] = { + 81, 82, 83, 84, 85, 86, 87, 88, /* PORT12x */ + 89, 90, 95, 96, 97, 98, 99, 100, /* PORT13x */ + 101, 102, 103, 104, 105, 106, 107, 108, /* PORT14x */ + 118, 119, 120, 121, 122, 123, 124, 125, /* PORT15x */ + 126, 72, 73, 92, 177, 93, 94, 176, /* PORT16x */ + 74, 91, 27, 28, 29, 75, 20, 26, /* PORT17x */ + 109, 110, 111, 112, 113, 114, 115, 116, /* PORT18x */ + 117, 143, 144, 145, 146, 147, 148, 149, /* PORT19x */ + 150, 151, 152, 153, 154, 155, 156, 157, /* PORT20x */ + 158, 159, 160, 161, 162, 163, 164, 165, /* PORT21x */ + 166, 178, 179, 180, 181, 182, 183, 184, /* PORT22x */ + 185, 187, 188, 189, 190, 191, 192, 193, /* PORT23x */ + 194, 195, 196, 197, 198, 199, 200, 201, /* PORT24x */ + 202, 203, 204, 205, 206, 207, 208, 209, /* PORT25x */ + 210, 211, 212, 213, 214, 215, 216, 217, /* PORT26x */ + 218, 219, 220, 221, 223, 224, 225, 226, /* PORT27x */ + 227, 228, 229, 230, 231, 232, 233, 234, /* PORT28x */ +}; +static const unsigned port_range1_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT15x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT16x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT17x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT18x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT19x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT20x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT21x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT22x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT23x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT24x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT25x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT26x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT27x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT28x */ +}; +static const unsigned xirq_pins[] = { + 118, 119, 120, 121, 122, 123, 124, 125, /* XIRQ0-7 */ + 126, 72, 73, 92, 177, 93, 94, 176, /* XIRQ8-15 */ + 74, 91, 27, 28, 29, 75, 20, 26, /* XIRQ16-23 */ +}; +static const unsigned xirq_muxvals[] = { + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ0-7 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ8-15 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ16-23 */ +}; + +static const struct uniphier_pinctrl_group proxstream2_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(i2c5), + UNIPHIER_PINCTRL_GROUP(i2c6), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart0b), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(uart3b), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb3), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range1, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range1, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range1, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range1, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range1, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range1, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range1, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range1, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range1, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range1, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range1, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range1, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range1, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range1, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range1, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range1, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range1, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range1, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range1, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range1, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range1, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range1, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range1, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port150, port_range1, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port151, port_range1, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port152, port_range1, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port153, port_range1, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port154, port_range1, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port155, port_range1, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port156, port_range1, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port157, port_range1, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port160, port_range1, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port161, port_range1, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port162, port_range1, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port163, port_range1, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port164, port_range1, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port165, port_range1, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port166, port_range1, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port167, port_range1, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port170, port_range1, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port171, port_range1, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port172, port_range1, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port173, port_range1, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port174, port_range1, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port175, port_range1, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port176, port_range1, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port177, port_range1, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range1, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range1, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range1, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range1, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range1, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range1, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range1, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range1, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port190, port_range1, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port191, port_range1, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port192, port_range1, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port193, port_range1, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port194, port_range1, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port195, port_range1, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port196, port_range1, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port197, port_range1, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range1, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range1, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range1, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range1, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range1, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range1, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range1, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range1, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range1, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range1, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range1, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range1, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range1, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range1, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range1, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range1, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range1, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range1, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range1, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range1, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range1, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range1, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range1, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range1, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range1, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range1, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range1, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range1, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range1, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range1, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range1, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range1, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range1, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range1, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range1, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range1, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range1, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range1, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range1, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range1, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range1, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range1, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range1, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range1, 107), + UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range1, 108), + UNIPHIER_PINCTRL_GROUP_SINGLE(port255, port_range1, 109), + UNIPHIER_PINCTRL_GROUP_SINGLE(port256, port_range1, 110), + UNIPHIER_PINCTRL_GROUP_SINGLE(port257, port_range1, 111), + UNIPHIER_PINCTRL_GROUP_SINGLE(port260, port_range1, 112), + UNIPHIER_PINCTRL_GROUP_SINGLE(port261, port_range1, 113), + UNIPHIER_PINCTRL_GROUP_SINGLE(port262, port_range1, 114), + UNIPHIER_PINCTRL_GROUP_SINGLE(port263, port_range1, 115), + UNIPHIER_PINCTRL_GROUP_SINGLE(port264, port_range1, 116), + UNIPHIER_PINCTRL_GROUP_SINGLE(port265, port_range1, 117), + UNIPHIER_PINCTRL_GROUP_SINGLE(port266, port_range1, 118), + UNIPHIER_PINCTRL_GROUP_SINGLE(port267, port_range1, 119), + UNIPHIER_PINCTRL_GROUP_SINGLE(port270, port_range1, 120), + UNIPHIER_PINCTRL_GROUP_SINGLE(port271, port_range1, 121), + UNIPHIER_PINCTRL_GROUP_SINGLE(port272, port_range1, 122), + UNIPHIER_PINCTRL_GROUP_SINGLE(port273, port_range1, 123), + UNIPHIER_PINCTRL_GROUP_SINGLE(port274, port_range1, 124), + UNIPHIER_PINCTRL_GROUP_SINGLE(port275, port_range1, 125), + UNIPHIER_PINCTRL_GROUP_SINGLE(port276, port_range1, 126), + UNIPHIER_PINCTRL_GROUP_SINGLE(port277, port_range1, 127), + UNIPHIER_PINCTRL_GROUP_SINGLE(port280, port_range1, 128), + UNIPHIER_PINCTRL_GROUP_SINGLE(port281, port_range1, 129), + UNIPHIER_PINCTRL_GROUP_SINGLE(port282, port_range1, 130), + UNIPHIER_PINCTRL_GROUP_SINGLE(port283, port_range1, 131), + UNIPHIER_PINCTRL_GROUP_SINGLE(port284, port_range1, 132), + UNIPHIER_PINCTRL_GROUP_SINGLE(port285, port_range1, 133), + UNIPHIER_PINCTRL_GROUP_SINGLE(port286, port_range1, 134), + UNIPHIER_PINCTRL_GROUP_SINGLE(port287, port_range1, 135), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21, xirq, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22, xirq, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23, xirq, 23), +}; + +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const i2c5_groups[] = {"i2c5"}; +static const char * const i2c6_groups[] = {"i2c6"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0", "uart0b"}; +static const char * const uart1_groups[] = {"uart1"}; +static const char * const uart2_groups[] = {"uart2"}; +static const char * const uart3_groups[] = {"uart3", "uart3b"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2"}; +static const char * const usb3_groups[] = {"usb3"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + /* port110-117 missing */ + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + "port150", "port151", "port152", "port153", + "port154", "port155", "port156", "port157", + "port160", "port161", "port162", "port163", + "port164", "port165", "port166", "port167", + "port170", "port171", "port172", "port173", + "port174", "port175", "port176", "port177", + "port180", "port181", "port182", "port183", + "port184", "port185", "port186", "port187", + "port190", "port191", "port192", "port193", + "port194", "port195", "port196", "port197", + "port200", "port201", "port202", "port203", + "port204", "port205", "port206", "port207", + "port210", "port211", "port212", "port213", + "port214", "port215", "port216", "port217", + "port220", "port221", "port222", "port223", + "port224", "port225", "port226", "port227", + "port230", "port231", "port232", "port233", + "port234", "port235", "port236", "port237", + "port240", "port241", "port242", "port243", + "port244", "port245", "port246", "port247", + "port250", "port251", "port252", "port253", + "port254", "port255", "port256", "port257", + "port260", "port261", "port262", "port263", + "port264", "port265", "port266", "port267", + "port270", "port271", "port272", "port273", + "port274", "port275", "port276", "port277", + "port280", "port281", "port282", "port283", + "port284", "port285", "port286", "port287", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", "xirq13", "xirq14", "xirq15", + "xirq16", "xirq17", "xirq18", "xirq19", + "xirq20", "xirq21", "xirq22", "xirq23", +}; + +static const struct uniphier_pinmux_function proxstream2_functions[] = { + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(i2c5), + UNIPHIER_PINMUX_FUNCTION(i2c6), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(uart3), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(usb3), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata proxstream2_pindata = { + .groups = proxstream2_groups, + .groups_count = ARRAY_SIZE(proxstream2_groups), + .functions = proxstream2_functions, + .functions_count = ARRAY_SIZE(proxstream2_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static struct pinctrl_desc proxstream2_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = proxstream2_pins, + .npins = ARRAY_SIZE(proxstream2_pins), + .owner = THIS_MODULE, +}; + +static int proxstream2_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &proxstream2_pinctrl_desc, + &proxstream2_pindata); +} + +static const struct of_device_id proxstream2_pinctrl_match[] = { + { .compatible = "socionext,proxstream2-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, proxstream2_pinctrl_match); + +static struct platform_driver proxstream2_pinctrl_driver = { + .probe = proxstream2_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = proxstream2_pinctrl_match, + }, +}; +module_platform_driver(proxstream2_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier ProXstream2 pinctrl driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From b3b6616378a4dcf1e903c8ad70fabfe4c2ad529b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:07 +0900 Subject: pinctrl: UniPhier: add UniPhier PH1-LD6b pinctrl driver Add pin configuration and pinmux support for UniPhier PH1-LD6b SoC. Changes in v2: - sort groups and funcs alphabetically - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 1 + drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c | 1274 +++++++++++++++++++++++++++ 3 files changed, 1279 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c (limited to 'drivers') diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index 69c5d5fa61da..eab23ef9ddbf 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -25,4 +25,8 @@ config PINCTRL_UNIPHIER_PROXSTREAM2 tristate "UniPhier ProXstream2 SoC pinctrl driver" select PINCTRL_UNIPHIER_CORE +config PINCTRL_UNIPHIER_PH1_LD6B + tristate "UniPhier PH1-LD6b SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index aed038c59f04..e215b1097297 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_SLD8) += pinctrl-ph1-sld8.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO5) += pinctrl-ph1-pro5.o obj-$(CONFIG_PINCTRL_UNIPHIER_PROXSTREAM2) += pinctrl-proxstream2.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD6B) += pinctrl-ph1-ld6b.o diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c b/drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c new file mode 100644 index 000000000000..9720e697fbc1 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c @@ -0,0 +1,1274 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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 + +#include "pinctrl-uniphier.h" + +#define DRIVER_NAME "ph1-ld6b-pinctrl" + +static const struct pinctrl_pin_desc ph1_ld6b_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "ED0", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_4_8, + 0, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "ED1", UNIPHIER_PIN_IECTRL_NONE, + 1, UNIPHIER_PIN_DRV_4_8, + 1, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "ED2", UNIPHIER_PIN_IECTRL_NONE, + 2, UNIPHIER_PIN_DRV_4_8, + 2, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "ED3", UNIPHIER_PIN_IECTRL_NONE, + 3, UNIPHIER_PIN_DRV_4_8, + 3, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "ED4", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_4_8, + 4, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(5, "ED5", UNIPHIER_PIN_IECTRL_NONE, + 5, UNIPHIER_PIN_DRV_4_8, + 5, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "ED6", UNIPHIER_PIN_IECTRL_NONE, + 6, UNIPHIER_PIN_DRV_4_8, + 6, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "ED7", UNIPHIER_PIN_IECTRL_NONE, + 7, UNIPHIER_PIN_DRV_4_8, + 7, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "XERWE0", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_4_8, + 8, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "XERWE1", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_4_8, + 9, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "ERXW", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_4_8, + 10, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "ES0", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_4_8, + 11, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(12, "ES1", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_4_8, + 12, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(13, "ES2", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_4_8, + 13, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(14, "XECS1", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_4_8, + 14, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(15, "PCA00", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 15, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(16, "PCA01", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 16, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(17, "PCA02", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 17, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(18, "PCA03", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 18, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(19, "PCA04", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 19, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(20, "PCA05", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 20, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(21, "PCA06", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(22, "PCA07", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(23, "PCA08", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(24, "PCA09", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 24, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(25, "PCA10", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 25, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(26, "PCA11", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 26, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(27, "PCA12", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 27, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(28, "PCA13", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 28, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(29, "PCA14", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 29, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(30, "XNFRE", UNIPHIER_PIN_IECTRL_NONE, + 30, UNIPHIER_PIN_DRV_4_8, + 30, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(31, "XNFWE", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(32, "NFALE", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(33, "NFCLE", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(34, "XNFWP", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(35, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(36, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(37, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(38, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(39, "NFD0", UNIPHIER_PIN_IECTRL_NONE, + 39, UNIPHIER_PIN_DRV_4_8, + 39, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(40, "NFD1", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_4_8, + 40, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(41, "NFD2", UNIPHIER_PIN_IECTRL_NONE, + 41, UNIPHIER_PIN_DRV_4_8, + 41, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(42, "NFD3", UNIPHIER_PIN_IECTRL_NONE, + 42, UNIPHIER_PIN_DRV_4_8, + 42, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(43, "NFD4", UNIPHIER_PIN_IECTRL_NONE, + 43, UNIPHIER_PIN_DRV_4_8, + 43, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(44, "NFD5", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_4_8, + 44, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(45, "NFD6", UNIPHIER_PIN_IECTRL_NONE, + 45, UNIPHIER_PIN_DRV_4_8, + 45, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(46, "NFD7", UNIPHIER_PIN_IECTRL_NONE, + 46, UNIPHIER_PIN_DRV_4_8, + 46, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(47, "SDCLK", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(48, "SDCMD", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(49, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(50, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(51, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(52, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(53, "SDCD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 53, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(54, "SDWP", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 54, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(55, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(56, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(57, "USB0OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 57, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(59, "USB1OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(60, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "USB2OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(62, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(63, "USB3OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(64, "HS0BCLKOUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "HS0SYNCOUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "HS0VALOUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "HS0DOUT0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "HS0DOUT1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "HS0DOUT2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "HS0DOUT3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "HS0DOUT4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "HS0DOUT5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "HS0DOUT6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "HS0DOUT7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "HS1BCLKIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "HS1SYNCIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "HS1VALIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "HS1DIN0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "HS1DIN1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "HS1DIN2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "HS1DIN3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "HS1DIN4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "HS1DIN5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "HS1DIN6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "HS1DIN7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "HS2BCLKIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "HS2SYNCIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "HS2VALIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "HS2DIN0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "HS2DIN1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "HS2DIN2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "HS2DIN3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "HS2DIN4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 93, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "HS2DIN5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "HS2DIN6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 95, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "HS2DIN7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 96, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 97, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 98, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 99, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 100, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(101, "AO1D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 101, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "AO1D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 102, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(103, "AO1D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(104, "AO1D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(105, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 105, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(106, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 106, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(107, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(108, "AO2D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 108, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(109, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 109, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(110, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 110, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(111, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 111, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(112, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 112, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(113, "SBO0", 0, + 113, UNIPHIER_PIN_DRV_4_8, + 113, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(114, "SBI0", 0, + 114, UNIPHIER_PIN_DRV_4_8, + 114, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(115, "TXD1", 0, + 115, UNIPHIER_PIN_DRV_4_8, + 115, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(116, "RXD1", 0, + 116, UNIPHIER_PIN_DRV_4_8, + 116, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(117, "PWSRA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 117, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(118, "XIRQ0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 118, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(119, "XIRQ1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 119, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(120, "XIRQ2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 120, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(121, "XIRQ3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 121, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "XIRQ4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 122, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(123, "XIRQ5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 123, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "XIRQ6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 124, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(125, "XIRQ7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 125, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(126, "XIRQ8", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 126, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(127, "PORT00", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 127, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(128, "PORT01", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 128, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(129, "PORT02", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 129, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(130, "PORT03", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 130, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(131, "PORT04", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 131, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(132, "PORT05", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 132, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(133, "PORT06", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 133, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(134, "PORT07", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 134, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(135, "PORT10", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 135, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(136, "PORT11", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 136, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(137, "PORT12", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 137, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(138, "PORT13", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 138, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(139, "PORT14", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 139, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(140, "PORT15", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 140, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(141, "PORT16", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 141, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(142, "LPST", UNIPHIER_PIN_IECTRL_NONE, + 142, UNIPHIER_PIN_DRV_4_8, + 142, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(143, "MDC", 0, + 143, UNIPHIER_PIN_DRV_4_8, + 143, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(144, "MDIO", 0, + 144, UNIPHIER_PIN_DRV_4_8, + 144, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(145, "MDIO_INTL", 0, + 145, UNIPHIER_PIN_DRV_4_8, + 145, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(146, "PHYRSTL", 0, + 146, UNIPHIER_PIN_DRV_4_8, + 146, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(147, "RGMII_RXCLK", 0, + 147, UNIPHIER_PIN_DRV_4_8, + 147, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(148, "RGMII_RXD0", 0, + 148, UNIPHIER_PIN_DRV_4_8, + 148, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(149, "RGMII_RXD1", 0, + 149, UNIPHIER_PIN_DRV_4_8, + 149, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(150, "RGMII_RXD2", 0, + 150, UNIPHIER_PIN_DRV_4_8, + 150, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(151, "RGMII_RXD3", 0, + 151, UNIPHIER_PIN_DRV_4_8, + 151, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(152, "RGMII_RXCTL", 0, + 152, UNIPHIER_PIN_DRV_4_8, + 152, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(153, "RGMII_TXCLK", 0, + 153, UNIPHIER_PIN_DRV_4_8, + 153, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(154, "RGMII_TXD0", 0, + 154, UNIPHIER_PIN_DRV_4_8, + 154, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(155, "RGMII_TXD1", 0, + 155, UNIPHIER_PIN_DRV_4_8, + 155, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(156, "RGMII_TXD2", 0, + 156, UNIPHIER_PIN_DRV_4_8, + 156, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(157, "RGMII_TXD3", 0, + 157, UNIPHIER_PIN_DRV_4_8, + 157, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(158, "RGMII_TXCTL", 0, + 158, UNIPHIER_PIN_DRV_4_8, + 158, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(159, "A_D_PCD00OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 159, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(160, "A_D_PCD01OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 160, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(161, "A_D_PCD02OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 161, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(162, "A_D_PCD03OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 162, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(163, "A_D_PCD04OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 163, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(164, "A_D_PCD05OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 164, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(165, "A_D_PCD06OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 165, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(166, "A_D_PCD07OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 166, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(167, "A_D_PCD00IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 167, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(168, "A_D_PCD01IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 168, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(169, "A_D_PCD02IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 169, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(170, "A_D_PCD03IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 170, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(171, "A_D_PCD04IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 171, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(172, "A_D_PCD05IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 172, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(173, "A_D_PCD06IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 173, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(174, "A_D_PCD07IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 174, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(175, "A_D_PCDNOE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 175, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(176, "A_D_PC0READY", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 176, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(177, "A_D_PC0CD1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 177, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(178, "A_D_PC0CD2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 178, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(179, "A_D_PC0WAIT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 179, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(180, "A_D_PC0RESET", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 180, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(181, "A_D_PC0CE1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 181, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(182, "A_D_PC0WE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 182, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(183, "A_D_PC0OE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 183, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(184, "A_D_PC0IOWR", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 184, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(185, "A_D_PC0IORD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 185, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(186, "A_D_PC0NOE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 186, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(187, "A_D_HS0BCLKIN", 0, + 187, UNIPHIER_PIN_DRV_4_8, + 187, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(188, "A_D_HS0SYNCIN", 0, + 188, UNIPHIER_PIN_DRV_4_8, + 188, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(189, "A_D_HS0VALIN", 0, + 189, UNIPHIER_PIN_DRV_4_8, + 189, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(190, "A_D_HS0DIN0", 0, + 190, UNIPHIER_PIN_DRV_4_8, + 190, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(191, "A_D_HS0DIN1", 0, + 191, UNIPHIER_PIN_DRV_4_8, + 191, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(192, "A_D_HS0DIN2", 0, + 192, UNIPHIER_PIN_DRV_4_8, + 192, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(193, "A_D_HS0DIN3", 0, + 193, UNIPHIER_PIN_DRV_4_8, + 193, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(194, "A_D_HS0DIN4", 0, + 194, UNIPHIER_PIN_DRV_4_8, + 194, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(195, "A_D_HS0DIN5", 0, + 195, UNIPHIER_PIN_DRV_4_8, + 195, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(196, "A_D_HS0DIN6", 0, + 196, UNIPHIER_PIN_DRV_4_8, + 196, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(197, "A_D_HS0DIN7", 0, + 197, UNIPHIER_PIN_DRV_4_8, + 197, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(198, "A_D_AO1ARC", 0, + 198, UNIPHIER_PIN_DRV_4_8, + 198, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(199, "A_D_SPIXRST", UNIPHIER_PIN_IECTRL_NONE, + 199, UNIPHIER_PIN_DRV_4_8, + 199, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(200, "A_D_SPISCLK0", UNIPHIER_PIN_IECTRL_NONE, + 200, UNIPHIER_PIN_DRV_4_8, + 200, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(201, "A_D_SPITXD0", UNIPHIER_PIN_IECTRL_NONE, + 201, UNIPHIER_PIN_DRV_4_8, + 201, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(202, "A_D_SPIRXD0", UNIPHIER_PIN_IECTRL_NONE, + 202, UNIPHIER_PIN_DRV_4_8, + 202, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(203, "A_D_DMDCLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 203, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(204, "A_D_DMDPSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 204, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(205, "A_D_DMDVAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 205, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(206, "A_D_DMDDATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 206, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(207, "A_D_HDMIRXXIRQ", 0, + 207, UNIPHIER_PIN_DRV_4_8, + 207, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(208, "A_D_VBIXIRQ", 0, + 208, UNIPHIER_PIN_DRV_4_8, + 208, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(209, "A_D_HDMITXXIRQ", 0, + 209, UNIPHIER_PIN_DRV_4_8, + 209, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(210, "A_D_DMDIRQ", UNIPHIER_PIN_IECTRL_NONE, + 210, UNIPHIER_PIN_DRV_4_8, + 210, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(211, "A_D_SPICIRQ", UNIPHIER_PIN_IECTRL_NONE, + 211, UNIPHIER_PIN_DRV_4_8, + 211, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(212, "A_D_SPIBIRQ", UNIPHIER_PIN_IECTRL_NONE, + 212, UNIPHIER_PIN_DRV_4_8, + 212, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(213, "A_D_BESDAOUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 213, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(214, "A_D_BESDAIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 214, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(215, "A_D_BESCLOUT", UNIPHIER_PIN_IECTRL_NONE, + 215, UNIPHIER_PIN_DRV_4_8, + 215, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(216, "A_D_VDACCLKOUT", 0, + 216, UNIPHIER_PIN_DRV_4_8, + 216, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(217, "A_D_VDACDOUT5", 0, + 217, UNIPHIER_PIN_DRV_4_8, + 217, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(218, "A_D_VDACDOUT6", 0, + 218, UNIPHIER_PIN_DRV_4_8, + 218, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(219, "A_D_VDACDOUT7", 0, + 219, UNIPHIER_PIN_DRV_4_8, + 219, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(220, "A_D_VDACDOUT8", 0, + 220, UNIPHIER_PIN_DRV_4_8, + 220, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(221, "A_D_VDACDOUT9", 0, + 221, UNIPHIER_PIN_DRV_4_8, + 221, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(222, "A_D_SIFBCKIN", 0, + 222, UNIPHIER_PIN_DRV_4_8, + 222, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(223, "A_D_SIFLRCKIN", 0, + 223, UNIPHIER_PIN_DRV_4_8, + 223, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(224, "A_D_SIFDIN", 0, + 224, UNIPHIER_PIN_DRV_4_8, + 224, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(225, "A_D_LIBCKOUT", 0, + 225, UNIPHIER_PIN_DRV_4_8, + 225, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(226, "A_D_LILRCKOUT", 0, + 226, UNIPHIER_PIN_DRV_4_8, + 226, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(227, "A_D_LIDIN", 0, + 227, UNIPHIER_PIN_DRV_4_8, + 227, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(228, "A_D_LODOUT", 0, + 228, UNIPHIER_PIN_DRV_4_8, + 228, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(229, "A_D_HPDOUT", 0, + 229, UNIPHIER_PIN_DRV_4_8, + 229, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(230, "A_D_MCLK", 0, + 230, UNIPHIER_PIN_DRV_4_8, + 230, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(231, "A_D_A2PLLREFOUT", 0, + 231, UNIPHIER_PIN_DRV_4_8, + 231, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(232, "A_D_HDMI3DSDAOUT", 0, + 232, UNIPHIER_PIN_DRV_4_8, + 232, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(233, "A_D_HDMI3DSDAIN", 0, + 233, UNIPHIER_PIN_DRV_4_8, + 233, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(234, "A_D_HDMI3DSCLIN", 0, + 234, UNIPHIER_PIN_DRV_4_8, + 234, UNIPHIER_PIN_PULL_DOWN), +}; + +static const unsigned adinter_pins[] = { + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, +}; +static const unsigned adinter_muxvals[] = { + 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, 0, 0, 0, + 0, 0, 0, 0, +}; +static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42}; +static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {109, 110}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {111, 112}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {115, 116}; +static const unsigned i2c2_muxvals[] = {1, 1}; +static const unsigned i2c3_pins[] = {118, 119}; +static const unsigned i2c3_muxvals[] = {1, 1}; +static const unsigned nand_pins[] = {30, 31, 32, 33, 34, 35, 36, 39, 40, 41, + 42, 43, 44, 45, 46}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {37, 38}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned uart0_pins[] = {135, 136}; +static const unsigned uart0_muxvals[] = {3, 3}; +static const unsigned uart0b_pins[] = {11, 12}; +static const unsigned uart0b_muxvals[] = {2, 2}; +static const unsigned uart1_pins[] = {115, 116}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart1b_pins[] = {113, 114}; +static const unsigned uart1b_muxvals[] = {1, 1}; +static const unsigned uart2_pins[] = {113, 114}; +static const unsigned uart2_muxvals[] = {2, 2}; +static const unsigned uart2b_pins[] = {86, 87}; +static const unsigned uart2b_muxvals[] = {1, 1}; +static const unsigned usb0_pins[] = {56, 57}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {58, 59}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {60, 61}; +static const unsigned usb2_muxvals[] = {0, 0}; +static const unsigned usb3_pins[] = {62, 63}; +static const unsigned usb3_muxvals[] = {0, 0}; +static const unsigned port_range0_pins[] = { + 127, 128, 129, 130, 131, 132, 133, 134, /* PORT0x */ + 135, 136, 137, 138, 139, 140, 141, 142, /* PORT1x */ + 0, 1, 2, 3, 4, 5, 6, 7, /* PORT2x */ + 8, 9, 10, 11, 12, 13, 14, 15, /* PORT3x */ + 16, 17, 18, 19, 21, 22, 23, 24, /* PORT4x */ + 25, 30, 31, 32, 33, 34, 35, 36, /* PORT5x */ + 37, 38, 39, 40, 41, 42, 43, 44, /* PORT6x */ + 45, 46, 47, 48, 49, 50, 51, 52, /* PORT7x */ + 53, 54, 55, 56, 57, 58, 59, 60, /* PORT8x */ + 61, 62, 63, 64, 65, 66, 67, 68, /* PORT9x */ + 69, 70, 71, 76, 77, 78, 79, 80, /* PORT10x */ +}; +static const unsigned port_range0_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT3x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT4x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT5x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT6x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */ +}; +static const unsigned port_range1_pins[] = { + 81, 82, 83, 84, 85, 86, 87, 88, /* PORT12x */ + 89, 90, 95, 96, 97, 98, 99, 100, /* PORT13x */ + 101, 102, 103, 104, 105, 106, 107, 108, /* PORT14x */ + 118, 119, 120, 121, 122, 123, 124, 125, /* PORT15x */ + 126, 72, 73, 92, 177, 93, 94, 176, /* PORT16x */ + 74, 91, 27, 28, 29, 75, 20, 26, /* PORT17x */ + 109, 110, 111, 112, 113, 114, 115, 116, /* PORT18x */ + 117, 143, 144, 145, 146, 147, 148, 149, /* PORT19x */ + 150, 151, 152, 153, 154, 155, 156, 157, /* PORT20x */ + 158, 159, 160, 161, 162, 163, 164, 165, /* PORT21x */ + 166, 178, 179, 180, 181, 182, 183, 184, /* PORT22x */ + 185, 187, 188, 189, 190, 191, 192, 193, /* PORT23x */ + 194, 195, 196, 197, 198, 199, 200, 201, /* PORT24x */ + 202, 203, 204, 205, 206, 207, 208, 209, /* PORT25x */ + 210, 211, 212, 213, 214, 215, 216, 217, /* PORT26x */ + 218, 219, 220, 221, 223, 224, 225, 226, /* PORT27x */ + 227, 228, 229, 230, 231, 232, 233, 234, /* PORT28x */ +}; +static const unsigned port_range1_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT15x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT16x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT17x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT18x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT19x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT20x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT21x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT22x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT23x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT24x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT25x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT26x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT27x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT28x */ +}; +static const unsigned xirq_pins[] = { + 118, 119, 120, 121, 122, 123, 124, 125, /* XIRQ0-7 */ + 126, 72, 73, 92, 177, 93, 94, 176, /* XIRQ8-15 */ + 74, 91, 27, 28, 29, 75, 20, 26, /* XIRQ16-23 */ +}; +static const unsigned xirq_muxvals[] = { + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ0-7 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ8-15 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ16-23 */ +}; + +static const struct uniphier_pinctrl_group ph1_ld6b_groups[] = { + UNIPHIER_PINCTRL_GROUP(adinter), + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart0b), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart1b), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart2b), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb3), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range1, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range1, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range1, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range1, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range1, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range1, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range1, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range1, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range1, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range1, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range1, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range1, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range1, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range1, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range1, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range1, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range1, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range1, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range1, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range1, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range1, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range1, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range1, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port150, port_range1, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port151, port_range1, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port152, port_range1, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port153, port_range1, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port154, port_range1, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port155, port_range1, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port156, port_range1, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port157, port_range1, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port160, port_range1, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port161, port_range1, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port162, port_range1, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port163, port_range1, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port164, port_range1, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port165, port_range1, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port166, port_range1, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port167, port_range1, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port170, port_range1, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port171, port_range1, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port172, port_range1, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port173, port_range1, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port174, port_range1, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port175, port_range1, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port176, port_range1, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port177, port_range1, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range1, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range1, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range1, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range1, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range1, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range1, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range1, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range1, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port190, port_range1, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port191, port_range1, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port192, port_range1, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port193, port_range1, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port194, port_range1, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port195, port_range1, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port196, port_range1, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port197, port_range1, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range1, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range1, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range1, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range1, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range1, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range1, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range1, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range1, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range1, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range1, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range1, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range1, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range1, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range1, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range1, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range1, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range1, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range1, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range1, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range1, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range1, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range1, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range1, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range1, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range1, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range1, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range1, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range1, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range1, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range1, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range1, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range1, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range1, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range1, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range1, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range1, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range1, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range1, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range1, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range1, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range1, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range1, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range1, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range1, 107), + UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range1, 108), + UNIPHIER_PINCTRL_GROUP_SINGLE(port255, port_range1, 109), + UNIPHIER_PINCTRL_GROUP_SINGLE(port256, port_range1, 110), + UNIPHIER_PINCTRL_GROUP_SINGLE(port257, port_range1, 111), + UNIPHIER_PINCTRL_GROUP_SINGLE(port260, port_range1, 112), + UNIPHIER_PINCTRL_GROUP_SINGLE(port261, port_range1, 113), + UNIPHIER_PINCTRL_GROUP_SINGLE(port262, port_range1, 114), + UNIPHIER_PINCTRL_GROUP_SINGLE(port263, port_range1, 115), + UNIPHIER_PINCTRL_GROUP_SINGLE(port264, port_range1, 116), + UNIPHIER_PINCTRL_GROUP_SINGLE(port265, port_range1, 117), + UNIPHIER_PINCTRL_GROUP_SINGLE(port266, port_range1, 118), + UNIPHIER_PINCTRL_GROUP_SINGLE(port267, port_range1, 119), + UNIPHIER_PINCTRL_GROUP_SINGLE(port270, port_range1, 120), + UNIPHIER_PINCTRL_GROUP_SINGLE(port271, port_range1, 121), + UNIPHIER_PINCTRL_GROUP_SINGLE(port272, port_range1, 122), + UNIPHIER_PINCTRL_GROUP_SINGLE(port273, port_range1, 123), + UNIPHIER_PINCTRL_GROUP_SINGLE(port274, port_range1, 124), + UNIPHIER_PINCTRL_GROUP_SINGLE(port275, port_range1, 125), + UNIPHIER_PINCTRL_GROUP_SINGLE(port276, port_range1, 126), + UNIPHIER_PINCTRL_GROUP_SINGLE(port277, port_range1, 127), + UNIPHIER_PINCTRL_GROUP_SINGLE(port280, port_range1, 128), + UNIPHIER_PINCTRL_GROUP_SINGLE(port281, port_range1, 129), + UNIPHIER_PINCTRL_GROUP_SINGLE(port282, port_range1, 130), + UNIPHIER_PINCTRL_GROUP_SINGLE(port283, port_range1, 131), + UNIPHIER_PINCTRL_GROUP_SINGLE(port284, port_range1, 132), + UNIPHIER_PINCTRL_GROUP_SINGLE(port285, port_range1, 133), + UNIPHIER_PINCTRL_GROUP_SINGLE(port286, port_range1, 134), + UNIPHIER_PINCTRL_GROUP_SINGLE(port287, port_range1, 135), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21, xirq, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22, xirq, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23, xirq, 23), +}; + +static const char * const adinter_groups[] = {"adinter"}; +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0", "uart0b"}; +static const char * const uart1_groups[] = {"uart1", "uart1b"}; +static const char * const uart2_groups[] = {"uart2", "uart2b"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2"}; +static const char * const usb3_groups[] = {"usb3"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + /* port110-117 missing */ + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + "port150", "port151", "port152", "port153", + "port154", "port155", "port156", "port157", + "port160", "port161", "port162", "port163", + "port164", "port165", "port166", "port167", + "port170", "port171", "port172", "port173", + "port174", "port175", "port176", "port177", + "port180", "port181", "port182", "port183", + "port184", "port185", "port186", "port187", + "port190", "port191", "port192", "port193", + "port194", "port195", "port196", "port197", + "port200", "port201", "port202", "port203", + "port204", "port205", "port206", "port207", + "port210", "port211", "port212", "port213", + "port214", "port215", "port216", "port217", + "port220", "port221", "port222", "port223", + "port224", "port225", "port226", "port227", + "port230", "port231", "port232", "port233", + "port234", "port235", "port236", "port237", + "port240", "port241", "port242", "port243", + "port244", "port245", "port246", "port247", + "port250", "port251", "port252", "port253", + "port254", "port255", "port256", "port257", + "port260", "port261", "port262", "port263", + "port264", "port265", "port266", "port267", + "port270", "port271", "port272", "port273", + "port274", "port275", "port276", "port277", + "port280", "port281", "port282", "port283", + "port284", "port285", "port286", "port287", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", "xirq13", "xirq14", "xirq15", + "xirq16", "xirq17", "xirq18", "xirq19", + "xirq20", "xirq21", "xirq22", "xirq23", +}; + +static const struct uniphier_pinmux_function ph1_ld6b_functions[] = { + UNIPHIER_PINMUX_FUNCTION(adinter), /* Achip-Dchip interconnect */ + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(usb3), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata ph1_ld6b_pindata = { + .groups = ph1_ld6b_groups, + .groups_count = ARRAY_SIZE(ph1_ld6b_groups), + .functions = ph1_ld6b_functions, + .functions_count = ARRAY_SIZE(ph1_ld6b_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static struct pinctrl_desc ph1_ld6b_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = ph1_ld6b_pins, + .npins = ARRAY_SIZE(ph1_ld6b_pins), + .owner = THIS_MODULE, +}; + +static int ph1_ld6b_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &ph1_ld6b_pinctrl_desc, + &ph1_ld6b_pindata); +} + +static const struct of_device_id ph1_ld6b_pinctrl_match[] = { + { .compatible = "socionext,ph1-ld6b-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ph1_ld6b_pinctrl_match); + +static struct platform_driver ph1_ld6b_pinctrl_driver = { + .probe = ph1_ld6b_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = ph1_ld6b_pinctrl_match, + }, +}; +module_platform_driver(ph1_ld6b_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier PH1-LD6b pinctrl driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 95b612cc6c7f95f4e08f1b3dbc6588fda49b1b12 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 9 Jul 2015 10:55:01 +0900 Subject: pinctrl: move CONFIG_PINCTRL to drivers/Makefile Kbuild should descend into drivers/pinctrl/ only when CONFIG_PINCTRL is enabled because everything under that directory depends on CONFIG_PINCTRL. We can avoid the conditional, ifeq ($(CONFIG_OF),y) ... endif. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/Makefile | 2 +- drivers/pinctrl/Makefile | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/Makefile b/drivers/Makefile index b64b49f6e01b..e4b260ecec15 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -11,7 +11,7 @@ obj-y += bus/ obj-$(CONFIG_GENERIC_PHY) += phy/ # GPIO must come after pinctrl as gpios may need to mux pins etc -obj-y += pinctrl/ +obj-$(CONFIG_PINCTRL) += pinctrl/ obj-y += gpio/ obj-y += pwm/ obj-$(CONFIG_PCI) += pci/ diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f6710a8a1503..76ba976cb9ca 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -2,12 +2,10 @@ subdir-ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG -obj-$(CONFIG_PINCTRL) += core.o pinctrl-utils.o +obj-y += core.o pinctrl-utils.o obj-$(CONFIG_PINMUX) += pinmux.o obj-$(CONFIG_PINCONF) += pinconf.o -ifeq ($(CONFIG_OF),y) -obj-$(CONFIG_PINCTRL) += devicetree.o -endif +obj-$(CONFIG_OF) += devicetree.o obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o -- cgit v1.3-6-gb490 From ad09c8c23e372182fe1454b3c10bef1c44df5cea Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 23 Mar 2015 11:28:53 +0100 Subject: soc/tegra: Add Tegra132 support Add Tegra132 to the matching table for NVIDIA Tegra SoCs. Signed-off-by: Thierry Reding --- drivers/soc/tegra/common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index a71cb74f3674..a952986a14b7 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -15,6 +15,7 @@ static const struct of_device_id tegra_machine_match[] = { { .compatible = "nvidia,tegra30", }, { .compatible = "nvidia,tegra114", }, { .compatible = "nvidia,tegra124", }, + { .compatible = "nvidia,tegra132", }, { } }; -- cgit v1.3-6-gb490 From 3a369982b88e5f162fc48b968ad989529db58401 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 23 Mar 2015 11:29:25 +0100 Subject: soc/tegra: Add Tegra210 support Add Tegra210 to the matching table for NVIDIA Tegra SoCs. Signed-off-by: Thierry Reding --- drivers/soc/tegra/common.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index a952986a14b7..cd8f41351add 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -16,6 +16,7 @@ static const struct of_device_id tegra_machine_match[] = { { .compatible = "nvidia,tegra114", }, { .compatible = "nvidia,tegra124", }, { .compatible = "nvidia,tegra132", }, + { .compatible = "nvidia,tegra210", }, { } }; -- cgit v1.3-6-gb490 From 30a636f984984655ad5350e73a6a3141c9ba85ae Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 18 May 2015 17:35:30 +0200 Subject: memory: tegra: Expose supported rates via debugfs In order to ease testing, expose the list of supported EMC frequencies via debugfs. Reviewed-by: Tomeu Vizoso Signed-off-by: Thierry Reding --- drivers/memory/tegra/tegra124-emc.c | 42 +++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c index 8620355776fe..3dac7be39654 100644 --- a/drivers/memory/tegra/tegra124-emc.c +++ b/drivers/memory/tegra/tegra124-emc.c @@ -1027,7 +1027,40 @@ static int emc_debug_rate_set(void *data, u64 rate) DEFINE_SIMPLE_ATTRIBUTE(emc_debug_rate_fops, emc_debug_rate_get, emc_debug_rate_set, "%lld\n"); -static void emc_debugfs_init(struct device *dev) +static int emc_debug_supported_rates_show(struct seq_file *s, void *data) +{ + struct tegra_emc *emc = s->private; + const char *prefix = ""; + unsigned int i; + + for (i = 0; i < emc->num_timings; i++) { + struct emc_timing *timing = &emc->timings[i]; + + seq_printf(s, "%s%lu", prefix, timing->rate); + + prefix = " "; + } + + seq_puts(s, "\n"); + + return 0; +} + +static int emc_debug_supported_rates_open(struct inode *inode, + struct file *file) +{ + return single_open(file, emc_debug_supported_rates_show, + inode->i_private); +} + +static const struct file_operations emc_debug_supported_rates_fops = { + .open = emc_debug_supported_rates_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void emc_debugfs_init(struct device *dev, struct tegra_emc *emc) { struct dentry *root, *file; struct clk *clk; @@ -1048,6 +1081,11 @@ static void emc_debugfs_init(struct device *dev) &emc_debug_rate_fops); if (!file) dev_err(dev, "failed to create debugfs entry\n"); + + file = debugfs_create_file("supported_rates", S_IRUGO, root, emc, + &emc_debug_supported_rates_fops); + if (!file) + dev_err(dev, "failed to create debugfs entry\n"); } static int tegra_emc_probe(struct platform_device *pdev) @@ -1119,7 +1157,7 @@ static int tegra_emc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, emc); if (IS_ENABLED(CONFIG_DEBUG_FS)) - emc_debugfs_init(&pdev->dev); + emc_debugfs_init(&pdev->dev, emc); return 0; }; -- cgit v1.3-6-gb490 From e7aa6d8c1ba2429deef75fb24d029e00ab71bebf Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Mon, 29 Jun 2015 10:35:57 +0800 Subject: gpio: zx: Add ZTE zx296702 GPIO support Add ZTE zx296702 GPIO controller support Signed-off-by: Jun Nie Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 6 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-zx.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 drivers/gpio/gpio-zx.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4c9fa58c5643..3a9dc1a8f56e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1003,6 +1003,12 @@ config GPIO_MC33880 SPI driver for Freescale MC33880 high-side/low-side switch. This provides GPIO interface supporting inputs and outputs. +config GPIO_ZX + bool "ZTE ZX GPIO support" + select GPIOLIB_IRQCHIP + help + Say yes here to support the GPIO device on ZTE ZX SoCs. + endmenu menu "USB GPIO expanders" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index f82cd678ce08..558b867ccebb 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -116,3 +116,4 @@ obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o +obj-$(CONFIG_GPIO_ZX) += gpio-zx.o diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c new file mode 100644 index 000000000000..12ee1969298c --- /dev/null +++ b/drivers/gpio/gpio-zx.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2015 Linaro 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ZX_GPIO_DIR 0x00 +#define ZX_GPIO_IVE 0x04 +#define ZX_GPIO_IV 0x08 +#define ZX_GPIO_IEP 0x0C +#define ZX_GPIO_IEN 0x10 +#define ZX_GPIO_DI 0x14 +#define ZX_GPIO_DO1 0x18 +#define ZX_GPIO_DO0 0x1C +#define ZX_GPIO_DO 0x20 + +#define ZX_GPIO_IM 0x28 +#define ZX_GPIO_IE 0x2C + +#define ZX_GPIO_MIS 0x30 +#define ZX_GPIO_IC 0x34 + +#define ZX_GPIO_NR 16 + +struct zx_gpio { + spinlock_t lock; + + void __iomem *base; + struct gpio_chip gc; + bool uses_pinctrl; +}; + +static inline struct zx_gpio *to_zx(struct gpio_chip *gc) +{ + return container_of(gc, struct zx_gpio, gc); +} + +static int zx_gpio_request(struct gpio_chip *gc, unsigned offset) +{ + struct zx_gpio *chip = to_zx(gc); + int gpio = gc->base + offset; + + if (chip->uses_pinctrl) + return pinctrl_request_gpio(gpio); + return 0; +} + +static void zx_gpio_free(struct gpio_chip *gc, unsigned offset) +{ + struct zx_gpio *chip = to_zx(gc); + int gpio = gc->base + offset; + + if (chip->uses_pinctrl) + pinctrl_free_gpio(gpio); +} + +static int zx_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct zx_gpio *chip = to_zx(gc); + unsigned long flags; + u16 gpiodir; + + if (offset >= gc->ngpio) + return -EINVAL; + + spin_lock_irqsave(&chip->lock, flags); + gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR); + gpiodir &= ~BIT(offset); + writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int zx_direction_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct zx_gpio *chip = to_zx(gc); + unsigned long flags; + u16 gpiodir; + + if (offset >= gc->ngpio) + return -EINVAL; + + spin_lock_irqsave(&chip->lock, flags); + gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR); + gpiodir |= BIT(offset); + writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR); + + if (value) + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1); + else + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int zx_get_value(struct gpio_chip *gc, unsigned offset) +{ + struct zx_gpio *chip = to_zx(gc); + + return !!(readw_relaxed(chip->base + ZX_GPIO_DI) & BIT(offset)); +} + +static void zx_set_value(struct gpio_chip *gc, unsigned offset, int value) +{ + struct zx_gpio *chip = to_zx(gc); + + if (value) + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1); + else + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0); +} + +static int zx_irq_type(struct irq_data *d, unsigned trigger) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct zx_gpio *chip = to_zx(gc); + int offset = irqd_to_hwirq(d); + unsigned long flags; + u16 gpiois, gpioi_epos, gpioi_eneg, gpioiev; + u16 bit = BIT(offset); + + if (offset < 0 || offset >= ZX_GPIO_NR) + return -EINVAL; + + spin_lock_irqsave(&chip->lock, flags); + + gpioiev = readw_relaxed(chip->base + ZX_GPIO_IV); + gpiois = readw_relaxed(chip->base + ZX_GPIO_IVE); + gpioi_epos = readw_relaxed(chip->base + ZX_GPIO_IEP); + gpioi_eneg = readw_relaxed(chip->base + ZX_GPIO_IEN); + + if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { + gpiois |= bit; + if (trigger & IRQ_TYPE_LEVEL_HIGH) + gpioiev |= bit; + else + gpioiev &= ~bit; + } else + gpiois &= ~bit; + + if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { + gpioi_epos |= bit; + gpioi_eneg |= bit; + } else { + if (trigger & IRQ_TYPE_EDGE_RISING) { + gpioi_epos |= bit; + gpioi_eneg &= ~bit; + } else if (trigger & IRQ_TYPE_EDGE_FALLING) { + gpioi_eneg |= bit; + gpioi_epos &= ~bit; + } + } + + writew_relaxed(gpiois, chip->base + ZX_GPIO_IVE); + writew_relaxed(gpioi_epos, chip->base + ZX_GPIO_IEP); + writew_relaxed(gpioi_eneg, chip->base + ZX_GPIO_IEN); + writew_relaxed(gpioiev, chip->base + ZX_GPIO_IV); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static void zx_irq_handler(unsigned irq, struct irq_desc *desc) +{ + unsigned long pending; + int offset; + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct zx_gpio *chip = to_zx(gc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + + chained_irq_enter(irqchip, desc); + + pending = readw_relaxed(chip->base + ZX_GPIO_MIS); + writew_relaxed(pending, chip->base + ZX_GPIO_IC); + if (pending) { + for_each_set_bit(offset, &pending, ZX_GPIO_NR) + generic_handle_irq(irq_find_mapping(gc->irqdomain, + offset)); + } + + chained_irq_exit(irqchip, desc); +} + +static void zx_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct zx_gpio *chip = to_zx(gc); + u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR); + u16 gpioie; + + spin_lock(&chip->lock); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) | mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IM); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) & ~mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IE); + spin_unlock(&chip->lock); +} + +static void zx_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct zx_gpio *chip = to_zx(gc); + u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR); + u16 gpioie; + + spin_lock(&chip->lock); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) & ~mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IM); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) | mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IE); + spin_unlock(&chip->lock); +} + +static struct irq_chip zx_irqchip = { + .name = "zx-gpio", + .irq_mask = zx_irq_mask, + .irq_unmask = zx_irq_unmask, + .irq_set_type = zx_irq_type, +}; + +static int zx_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct zx_gpio *chip; + struct resource *res; + int irq, id, ret; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + chip->base = devm_ioremap_resource(dev, res); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); + + spin_lock_init(&chip->lock); + if (of_property_read_bool(dev->of_node, "gpio-ranges")) + chip->uses_pinctrl = true; + + id = of_alias_get_id(dev->of_node, "gpio"); + chip->gc.request = zx_gpio_request; + chip->gc.free = zx_gpio_free; + chip->gc.direction_input = zx_direction_input; + chip->gc.direction_output = zx_direction_output; + chip->gc.get = zx_get_value; + chip->gc.set = zx_set_value; + chip->gc.base = ZX_GPIO_NR * id; + chip->gc.ngpio = ZX_GPIO_NR; + chip->gc.label = dev_name(dev); + chip->gc.dev = dev; + chip->gc.owner = THIS_MODULE; + + ret = gpiochip_add(&chip->gc); + if (ret) + return ret; + + /* + * irq_chip support + */ + writew_relaxed(0xffff, chip->base + ZX_GPIO_IM); + writew_relaxed(0, chip->base + ZX_GPIO_IE); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "invalid IRQ\n"); + gpiochip_remove(&chip->gc); + return -ENODEV; + } + + ret = gpiochip_irqchip_add(&chip->gc, &zx_irqchip, + 0, handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "could not add irqchip\n"); + gpiochip_remove(&chip->gc); + return ret; + } + gpiochip_set_chained_irqchip(&chip->gc, &zx_irqchip, + irq, zx_irq_handler); + + platform_set_drvdata(pdev, chip); + dev_info(dev, "ZX GPIO chip registered\n"); + + return 0; +} + +static const struct of_device_id zx_gpio_match[] = { + { + .compatible = "zte,zx296702-gpio", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, zx_gpio_match); + +static struct platform_driver zx_gpio_driver = { + .probe = zx_gpio_probe, + .driver = { + .name = "zx_gpio", + .of_match_table = of_match_ptr(zx_gpio_match), + }, +}; + +module_platform_driver(zx_gpio_driver) + +MODULE_AUTHOR("Jun Nie "); +MODULE_DESCRIPTION("ZTE ZX296702 GPIO driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 8749f8ed5cc07f4f130f2e5b2c41da78388146ec Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Jun 2015 18:12:24 +0300 Subject: pinctrl: samsung: don't truncate the last char We were allocating enough space because sizeof("-grp") and sizeof("-mux") are both equal to 5 but in the snprintf() we only allowed for 4 characters so the last 'p' and 'x' characters were truncated. The allocate and sprintf can be done in one step with the kasprintf(). Signed-off-by: Dan Carpenter Reviewed-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij --- drivers/pinctrl/samsung/pinctrl-exynos5440.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c index f5619fb50447..fa84db6a5b15 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c @@ -44,9 +44,7 @@ #define PIN_NAME_LENGTH 10 #define GROUP_SUFFIX "-grp" -#define GSUFFIX_LEN sizeof(GROUP_SUFFIX) #define FUNCTION_SUFFIX "-mux" -#define FSUFFIX_LEN sizeof(FUNCTION_SUFFIX) /* * pin configuration type and its value are packed together into a 16-bits. @@ -215,12 +213,11 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, * Allocate memory for pin group name. The pin group name is derived * from the node name from which these map entries are be created. */ - gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); + gname = kasprintf(GFP_KERNEL, "%s%s", np->name, GROUP_SUFFIX); if (!gname) { dev_err(dev, "failed to alloc memory for group name\n"); goto free_map; } - snprintf(gname, strlen(np->name) + 4, "%s%s", np->name, GROUP_SUFFIX); /* * don't have config options? then skip over to creating function @@ -254,13 +251,12 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, skip_cfgs: /* create the function map entry */ if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) { - fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL); + fname = kasprintf(GFP_KERNEL, + "%s%s", np->name, FUNCTION_SUFFIX); if (!fname) { dev_err(dev, "failed to alloc memory for func name\n"); goto free_cfg; } - snprintf(fname, strlen(np->name) + 4, "%s%s", np->name, - FUNCTION_SUFFIX); map[*nmaps].data.mux.group = gname; map[*nmaps].data.mux.function = fname; @@ -710,14 +706,12 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev, } /* derive pin group name from the node name */ - gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, - GFP_KERNEL); + gname = devm_kasprintf(dev, GFP_KERNEL, + "%s%s", cfg_np->name, GROUP_SUFFIX); if (!gname) { dev_err(dev, "failed to alloc memory for group name\n"); return -ENOMEM; } - snprintf(gname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name, - GROUP_SUFFIX); grp->name = gname; grp->pins = pin_list; @@ -731,14 +725,12 @@ skip_to_pin_function: continue; /* derive function name from the node name */ - fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, - GFP_KERNEL); + fname = devm_kasprintf(dev, GFP_KERNEL, + "%s%s", cfg_np->name, FUNCTION_SUFFIX); if (!fname) { dev_err(dev, "failed to alloc memory for func name\n"); return -ENOMEM; } - snprintf(fname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name, - FUNCTION_SUFFIX); func->name = fname; func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); -- cgit v1.3-6-gb490 From 583facb6ae27dfb4d0fb5a952dade5aa990a05c9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Jun 2015 18:13:15 +0300 Subject: pinctrl: samsung: remove "out of memory" messages Checkpatch.pl complains about these: WARNING: Possible unnecessary 'out of memory' message The messages use a little extra RAM and they add a few extra lines of code. We're probably never going to hit these out of memory situations but if we did then kmalloc() has pretty good error messages built-in. Signed-off-by: Dan Carpenter Reviewed-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij --- drivers/pinctrl/samsung/pinctrl-exynos5440.c | 67 ++++++++-------------------- 1 file changed, 18 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c index fa84db6a5b15..5574b8ae5949 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c @@ -203,10 +203,8 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, /* Allocate memory for pin-map entries */ map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); - if (!map) { - dev_err(dev, "could not alloc memory for pin-maps\n"); + if (!map) return -ENOMEM; - } *nmaps = 0; /* @@ -214,10 +212,8 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, * from the node name from which these map entries are be created. */ gname = kasprintf(GFP_KERNEL, "%s%s", np->name, GROUP_SUFFIX); - if (!gname) { - dev_err(dev, "failed to alloc memory for group name\n"); + if (!gname) goto free_map; - } /* * don't have config options? then skip over to creating function @@ -228,10 +224,8 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, /* Allocate memory for config entries */ cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); - if (!cfg) { - dev_err(dev, "failed to alloc memory for configs\n"); + if (!cfg) goto free_gname; - } /* Prepare a list of config settings */ for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { @@ -253,10 +247,8 @@ skip_cfgs: if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) { fname = kasprintf(GFP_KERNEL, "%s%s", np->name, FUNCTION_SUFFIX); - if (!fname) { - dev_err(dev, "failed to alloc memory for func name\n"); + if (!fname) goto free_cfg; - } map[*nmaps].data.mux.group = gname; map[*nmaps].data.mux.function = fname; @@ -647,10 +639,8 @@ static int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev, } *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); - if (!*pin_list) { - dev_err(dev, "failed to allocate memory for pin list\n"); + if (!*pin_list) return -ENOMEM; - } return of_property_read_u32_array(cfg_np, "samsung,exynos5440-pins", *pin_list, *npins); @@ -678,17 +668,15 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev, return -EINVAL; groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); - if (!groups) { - dev_err(dev, "failed allocate memory for ping group list\n"); + if (!groups) return -EINVAL; - } + grp = groups; functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); - if (!functions) { - dev_err(dev, "failed to allocate memory for function list\n"); + if (!functions) return -EINVAL; - } + func = functions; /* @@ -708,10 +696,8 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev, /* derive pin group name from the node name */ gname = devm_kasprintf(dev, GFP_KERNEL, "%s%s", cfg_np->name, GROUP_SUFFIX); - if (!gname) { - dev_err(dev, "failed to alloc memory for group name\n"); + if (!gname) return -ENOMEM; - } grp->name = gname; grp->pins = pin_list; @@ -727,18 +713,13 @@ skip_to_pin_function: /* derive function name from the node name */ fname = devm_kasprintf(dev, GFP_KERNEL, "%s%s", cfg_np->name, FUNCTION_SUFFIX); - if (!fname) { - dev_err(dev, "failed to alloc memory for func name\n"); + if (!fname) return -ENOMEM; - } func->name = fname; func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); - if (!func->groups) { - dev_err(dev, "failed to alloc memory for group list " - "in pin function"); + if (!func->groups) return -ENOMEM; - } func->groups[0] = gname; func->num_groups = gname ? 1 : 0; func->function = function; @@ -766,10 +747,8 @@ static int exynos5440_pinctrl_register(struct platform_device *pdev, int pin, ret; ctrldesc = devm_kzalloc(dev, sizeof(*ctrldesc), GFP_KERNEL); - if (!ctrldesc) { - dev_err(dev, "could not allocate memory for pinctrl desc\n"); + if (!ctrldesc) return -ENOMEM; - } ctrldesc->name = "exynos5440-pinctrl"; ctrldesc->owner = THIS_MODULE; @@ -779,10 +758,8 @@ static int exynos5440_pinctrl_register(struct platform_device *pdev, pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * EXYNOS5440_MAX_PINS, GFP_KERNEL); - if (!pindesc) { - dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); + if (!pindesc) return -ENOMEM; - } ctrldesc->pins = pindesc; ctrldesc->npins = EXYNOS5440_MAX_PINS; @@ -796,10 +773,8 @@ static int exynos5440_pinctrl_register(struct platform_device *pdev, */ pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * ctrldesc->npins, GFP_KERNEL); - if (!pin_names) { - dev_err(&pdev->dev, "mem alloc for pin names failed\n"); + if (!pin_names) return -ENOMEM; - } /* for each pin, set the name of the pin */ for (pin = 0; pin < ctrldesc->npins; pin++) { @@ -836,10 +811,8 @@ static int exynos5440_gpiolib_register(struct platform_device *pdev, int ret; gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); - if (!gc) { - dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); + if (!gc) return -ENOMEM; - } priv->gc = gc; gc->base = 0; @@ -941,10 +914,8 @@ static int exynos5440_gpio_irq_init(struct platform_device *pdev, intd = devm_kzalloc(dev, sizeof(*intd) * EXYNOS5440_MAX_GPIO_INT, GFP_KERNEL); - if (!intd) { - dev_err(dev, "failed to allocate memory for gpio intr data\n"); + if (!intd) return -ENOMEM; - } for (i = 0; i < EXYNOS5440_MAX_GPIO_INT; i++) { irq = irq_of_parse_and_map(dev->of_node, i); @@ -987,10 +958,8 @@ static int exynos5440_pinctrl_probe(struct platform_device *pdev) } priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(dev, "could not allocate memory for private data\n"); + if (!priv) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->reg_base = devm_ioremap_resource(&pdev->dev, res); -- cgit v1.3-6-gb490 From 527b397a7a3647b8ba2eae2e7a12b237bf411476 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Jun 2015 15:48:02 +0200 Subject: gpio: em: Remove obsolete platform data support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 59032702ead90562 ("ARM: shmobile: Remove legacy platform devices from EMEV2 SoC code"), EMMA Mobile SoCs are only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to use platform data anymore, hence remove platform data configuration. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Tested-by: Niklas Söderlund Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 34 ++++++++-------------------------- include/linux/platform_data/gpio-em.h | 11 ----------- 2 files changed, 8 insertions(+), 37 deletions(-) delete mode 100644 include/linux/platform_data/gpio-em.h (limited to 'drivers') diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index fbf287307c4c..a77f16c8d142 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -31,7 +31,6 @@ #include #include #include -#include struct em_gio_priv { void __iomem *base0; @@ -273,13 +272,12 @@ static const struct irq_domain_ops em_gio_irq_domain_ops = { static int em_gio_probe(struct platform_device *pdev) { - struct gpio_em_config pdata_dt; - struct gpio_em_config *pdata = dev_get_platdata(&pdev->dev); struct em_gio_priv *p; struct resource *io[2], *irq[2]; struct gpio_chip *gpio_chip; struct irq_chip *irq_chip; const char *name = dev_name(&pdev->dev); + unsigned int ngpios; int ret; p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); @@ -319,18 +317,10 @@ static int em_gio_probe(struct platform_device *pdev) goto err0; } - if (!pdata) { - memset(&pdata_dt, 0, sizeof(pdata_dt)); - pdata = &pdata_dt; - - if (of_property_read_u32(pdev->dev.of_node, "ngpios", - &pdata->number_of_pins)) { - dev_err(&pdev->dev, "Missing ngpios OF property\n"); - ret = -EINVAL; - goto err0; - } - - pdata->gpio_base = -1; + if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { + dev_err(&pdev->dev, "Missing ngpios OF property\n"); + ret = -EINVAL; + goto err0; } gpio_chip = &p->gpio_chip; @@ -345,8 +335,8 @@ static int em_gio_probe(struct platform_device *pdev) gpio_chip->label = name; gpio_chip->dev = &pdev->dev; gpio_chip->owner = THIS_MODULE; - gpio_chip->base = pdata->gpio_base; - gpio_chip->ngpio = pdata->number_of_pins; + gpio_chip->base = -1; + gpio_chip->ngpio = ngpios; irq_chip = &p->irq_chip; irq_chip->name = name; @@ -357,9 +347,7 @@ static int em_gio_probe(struct platform_device *pdev) 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, - pdata->number_of_pins, - pdata->irq_base, + p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, ngpios, 0, &em_gio_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; @@ -387,12 +375,6 @@ static int em_gio_probe(struct platform_device *pdev) goto err1; } - if (pdata->pctl_name) { - ret = gpiochip_add_pin_range(gpio_chip, pdata->pctl_name, 0, - gpio_chip->base, gpio_chip->ngpio); - if (ret < 0) - dev_warn(&pdev->dev, "failed to add pin range\n"); - } return 0; err1: diff --git a/include/linux/platform_data/gpio-em.h b/include/linux/platform_data/gpio-em.h deleted file mode 100644 index 7c5a519d2dcd..000000000000 --- a/include/linux/platform_data/gpio-em.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __GPIO_EM_H__ -#define __GPIO_EM_H__ - -struct gpio_em_config { - unsigned int gpio_base; - unsigned int irq_base; - unsigned int number_of_pins; - const char *pctl_name; -}; - -#endif /* __GPIO_EM_H__ */ -- cgit v1.3-6-gb490 From 95169cd23bfa88003f8be06234dbd65f5737add0 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 9 Jul 2015 09:59:55 +0200 Subject: soc/tegra: pmc: Avoid usage of uninitialized variable Make sure to only drop the reference to the OF node after it's been successfully obtained. Fixes: 3568df3d31d6 ("soc: tegra: Add thermal reset (thermtrip) support to PMC") Cc: # v4.0+ Reviewed-by: Mikko Perttunen Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 75d0457a77b7..fa7036c4daf9 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -736,12 +736,12 @@ void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc) u32 value, checksum; if (!pmc->soc->has_tsense_reset) - goto out; + return; np = of_find_node_by_name(pmc->dev->of_node, "i2c-thermtrip"); if (!np) { dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled); - goto out; + return; } if (of_property_read_u32(np, "nvidia,i2c-controller-id", &ctrl_id)) { -- cgit v1.3-6-gb490 From 7d71e90377fd74334dcfb5c265e204eef1613b53 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 29 Apr 2015 12:42:28 +0200 Subject: soc/tegra: pmc: Restrict legacy code to 32-bit ARM For backwards-compatibility with old device trees, if no PMC node exists this driver hard-codes the I/O memory region. All 64-bit ARM device tree files are recent enough that they can be required to have this node, and therefore the legacy code path is not required on 64-bit ARM. Based on work done by Paul Walmsley . Cc: Paul Walmsley Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 56 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index fa7036c4daf9..84da174bedec 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -17,6 +17,8 @@ * */ +#define pr_fmt(fmt) "tegra-pmc: " fmt + #include #include #include @@ -1003,6 +1005,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { }; static const struct of_device_id tegra_pmc_match[] = { + { .compatible = "nvidia,tegra132-pmc", .data = &tegra124_pmc_soc }, { .compatible = "nvidia,tegra124-pmc", .data = &tegra124_pmc_soc }, { .compatible = "nvidia,tegra114-pmc", .data = &tegra114_pmc_soc }, { .compatible = "nvidia,tegra30-pmc", .data = &tegra30_pmc_soc }, @@ -1035,25 +1038,44 @@ static int __init tegra_pmc_early_init(void) bool invert; u32 value; - if (!soc_is_tegra()) - return 0; - np = of_find_matching_node_and_match(NULL, tegra_pmc_match, &match); if (!np) { - pr_warn("PMC device node not found, disabling powergating\n"); - - regs.start = 0x7000e400; - regs.end = 0x7000e7ff; - regs.flags = IORESOURCE_MEM; - - pr_warn("Using memory region %pR\n", ®s); + /* + * Fall back to legacy initialization for 32-bit ARM only. All + * 64-bit ARM device tree files for Tegra are required to have + * a PMC node. + * + * This is for backwards-compatibility with old device trees + * that didn't contain a PMC node. Note that in this case the + * SoC data can't be matched and therefore powergating is + * disabled. + */ + if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) { + pr_warn("DT node not found, powergating disabled\n"); + + regs.start = 0x7000e400; + regs.end = 0x7000e7ff; + regs.flags = IORESOURCE_MEM; + + pr_warn("Using memory region %pR\n", ®s); + } else { + /* + * At this point we're not running on Tegra, so play + * nice with multi-platform kernels. + */ + return 0; + } } else { - pmc->soc = match->data; - } + /* + * Extract information from the device tree if we've found a + * matching node. + */ + if (of_address_to_resource(np, 0, ®s) < 0) { + pr_err("failed to get PMC registers\n"); + return -ENXIO; + } - if (of_address_to_resource(np, 0, ®s) < 0) { - pr_err("failed to get PMC registers\n"); - return -ENXIO; + pmc->soc = match->data; } pmc->base = ioremap_nocache(regs.start, resource_size(®s)); @@ -1064,6 +1086,10 @@ static int __init tegra_pmc_early_init(void) mutex_init(&pmc->powergates_lock); + /* + * Invert the interrupt polarity if a PMC device tree node exists and + * contains the nvidia,invert-interrupt property. + */ invert = of_property_read_bool(np, "nvidia,invert-interrupt"); value = tegra_pmc_readl(PMC_CNTRL); -- cgit v1.3-6-gb490 From c2fe4694d8ac0f997f6d7088437b710fc4e4a185 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 23 Mar 2015 11:31:29 +0100 Subject: soc/tegra: pmc: Add Tegra210 support Tegra210 uses a power management controller that is compatible with earlier SoC generations but adds a couple of power partitions for new hardware blocks. Reviewed-by: Paul Walmsley Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ include/soc/tegra/pmc.h | 5 +++++ 2 files changed, 53 insertions(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 84da174bedec..0748174ed4e4 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1004,7 +1004,55 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .has_gpu_clamps = true, }; +static const char * const tegra210_powergates[] = { + [TEGRA_POWERGATE_CPU] = "crail", + [TEGRA_POWERGATE_3D] = "3d", + [TEGRA_POWERGATE_VENC] = "venc", + [TEGRA_POWERGATE_PCIE] = "pcie", + [TEGRA_POWERGATE_L2] = "l2", + [TEGRA_POWERGATE_MPE] = "mpe", + [TEGRA_POWERGATE_HEG] = "heg", + [TEGRA_POWERGATE_SATA] = "sata", + [TEGRA_POWERGATE_CPU1] = "cpu1", + [TEGRA_POWERGATE_CPU2] = "cpu2", + [TEGRA_POWERGATE_CPU3] = "cpu3", + [TEGRA_POWERGATE_CELP] = "celp", + [TEGRA_POWERGATE_CPU0] = "cpu0", + [TEGRA_POWERGATE_C0NC] = "c0nc", + [TEGRA_POWERGATE_C1NC] = "c1nc", + [TEGRA_POWERGATE_SOR] = "sor", + [TEGRA_POWERGATE_DIS] = "dis", + [TEGRA_POWERGATE_DISB] = "disb", + [TEGRA_POWERGATE_XUSBA] = "xusba", + [TEGRA_POWERGATE_XUSBB] = "xusbb", + [TEGRA_POWERGATE_XUSBC] = "xusbc", + [TEGRA_POWERGATE_VIC] = "vic", + [TEGRA_POWERGATE_IRAM] = "iram", + [TEGRA_POWERGATE_NVDEC] = "nvdec", + [TEGRA_POWERGATE_NVJPG] = "nvjpg", + [TEGRA_POWERGATE_AUD] = "aud", + [TEGRA_POWERGATE_DFD] = "dfd", + [TEGRA_POWERGATE_VE2] = "ve2", +}; + +static const u8 tegra210_cpu_powergates[] = { + TEGRA_POWERGATE_CPU0, + TEGRA_POWERGATE_CPU1, + TEGRA_POWERGATE_CPU2, + TEGRA_POWERGATE_CPU3, +}; + +static const struct tegra_pmc_soc tegra210_pmc_soc = { + .num_powergates = ARRAY_SIZE(tegra210_powergates), + .powergates = tegra210_powergates, + .num_cpu_powergates = ARRAY_SIZE(tegra210_cpu_powergates), + .cpu_powergates = tegra210_cpu_powergates, + .has_tsense_reset = true, + .has_gpu_clamps = true, +}; + static const struct of_device_id tegra_pmc_match[] = { + { .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc }, { .compatible = "nvidia,tegra132-pmc", .data = &tegra124_pmc_soc }, { .compatible = "nvidia,tegra124-pmc", .data = &tegra124_pmc_soc }, { .compatible = "nvidia,tegra114-pmc", .data = &tegra114_pmc_soc }, diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h index f5c0de43a5fa..d18efe402ff1 100644 --- a/include/soc/tegra/pmc.h +++ b/include/soc/tegra/pmc.h @@ -67,6 +67,11 @@ int tegra_pmc_cpu_remove_clamping(int cpuid); #define TEGRA_POWERGATE_XUSBC 22 #define TEGRA_POWERGATE_VIC 23 #define TEGRA_POWERGATE_IRAM 24 +#define TEGRA_POWERGATE_NVDEC 25 +#define TEGRA_POWERGATE_NVJPG 26 +#define TEGRA_POWERGATE_AUD 27 +#define TEGRA_POWERGATE_DFD 28 +#define TEGRA_POWERGATE_VE2 29 #define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D -- cgit v1.3-6-gb490 From 297c4f3dcbffe11ce899a7d068ea18079094403b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 4 May 2015 13:30:50 +0200 Subject: soc/tegra: fuse: Restrict legacy code to 32-bit ARM For backwards-compatibility with old device trees, if no APBMISC node exists this driver hard-codes the I/O memory region. All 64-bit ARM device tree files are recent enough that they can be required to have this node, and therefore the legacy code path is not required. Based on work done by Paul Walmsley . Cc: Paul Walmsley Signed-off-by: Thierry Reding --- drivers/soc/tegra/fuse/tegra-apbmisc.c | 67 +++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index 73fad05d8f2c..29d7714515b7 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -21,11 +21,10 @@ #include #include +#include #include "fuse.h" -#define APBMISC_BASE 0x70000800 -#define APBMISC_SIZE 0x64 #define FUSE_SKU_INFO 0x10 #define PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT 4 @@ -118,19 +117,69 @@ void __init tegra_init_revision(void) void __init tegra_init_apbmisc(void) { + struct resource apbmisc, straps; struct device_node *np; np = of_find_matching_node(NULL, apbmisc_match); - apbmisc_base = of_iomap(np, 0); - if (!apbmisc_base) { - pr_warn("ioremap tegra apbmisc failed. using %08x instead\n", - APBMISC_BASE); - apbmisc_base = ioremap(APBMISC_BASE, APBMISC_SIZE); + if (!np) { + /* + * Fall back to legacy initialization for 32-bit ARM only. All + * 64-bit ARM device tree files for Tegra are required to have + * an APBMISC node. + * + * This is for backwards-compatibility with old device trees + * that didn't contain an APBMISC node. + */ + if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) { + /* APBMISC registers (chip revision, ...) */ + apbmisc.start = 0x70000800; + apbmisc.end = 0x70000863; + apbmisc.flags = IORESOURCE_MEM; + + /* strapping options */ + if (tegra_get_chip_id() == TEGRA124) { + straps.start = 0x7000e864; + straps.end = 0x7000e867; + } else { + straps.start = 0x70000008; + straps.end = 0x7000000b; + } + + straps.flags = IORESOURCE_MEM; + + pr_warn("Using APBMISC region %pR\n", &apbmisc); + pr_warn("Using strapping options registers %pR\n", + &straps); + } else { + /* + * At this point we're not running on Tegra, so play + * nice with multi-platform kernels. + */ + return; + } + } else { + /* + * Extract information from the device tree if we've found a + * matching node. + */ + if (of_address_to_resource(np, 0, &apbmisc) < 0) { + pr_err("failed to get APBMISC registers\n"); + return; + } + + if (of_address_to_resource(np, 1, &straps) < 0) { + pr_err("failed to get strapping options registers\n"); + return; + } } - strapping_base = of_iomap(np, 1); + apbmisc_base = ioremap_nocache(apbmisc.start, resource_size(&apbmisc)); + if (!apbmisc_base) + pr_err("failed to map APBMISC registers\n"); + + strapping_base = ioremap_nocache(straps.start, resource_size(&straps)); if (!strapping_base) - pr_err("ioremap tegra strapping_base failed\n"); + pr_err("failed to map strapping options registers\n"); long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code"); } -- cgit v1.3-6-gb490 From 7e939de1b2bb26496e4967e5346619700245e7c0 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 29 Apr 2015 16:54:04 +0200 Subject: soc/tegra: fuse: Unify Tegra20 and Tegra30 drivers Unifying the drivers makes it easier to restrict the legacy probing paths to 32-bit ARM. This in turn will come in handy as support for new 64-bit ARM SoCs is added. Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/iomap.h | 3 - drivers/soc/tegra/fuse/Makefile | 1 + drivers/soc/tegra/fuse/fuse-tegra.c | 245 ++++++++++++++++++++++++------- drivers/soc/tegra/fuse/fuse-tegra20.c | 173 ++++++++-------------- drivers/soc/tegra/fuse/fuse-tegra30.c | 213 +++++++++------------------ drivers/soc/tegra/fuse/fuse.h | 87 +++++++---- drivers/soc/tegra/fuse/speedo-tegra114.c | 8 +- drivers/soc/tegra/fuse/speedo-tegra124.c | 14 +- drivers/soc/tegra/fuse/speedo-tegra20.c | 8 +- drivers/soc/tegra/fuse/speedo-tegra30.c | 22 +-- drivers/soc/tegra/fuse/tegra-apbmisc.c | 9 +- 11 files changed, 413 insertions(+), 370 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-tegra/iomap.h b/arch/arm/mach-tegra/iomap.h index 81dc950b4881..9e5b2f869fc8 100644 --- a/arch/arm/mach-tegra/iomap.h +++ b/arch/arm/mach-tegra/iomap.h @@ -82,9 +82,6 @@ #define TEGRA_EMC_BASE 0x7000F400 #define TEGRA_EMC_SIZE SZ_1K -#define TEGRA_FUSE_BASE 0x7000F800 -#define TEGRA_FUSE_SIZE SZ_1K - #define TEGRA_EMC0_BASE 0x7001A000 #define TEGRA_EMC0_SIZE SZ_2K diff --git a/drivers/soc/tegra/fuse/Makefile b/drivers/soc/tegra/fuse/Makefile index 3af357da91f3..4adfce09d3a9 100644 --- a/drivers/soc/tegra/fuse/Makefile +++ b/drivers/soc/tegra/fuse/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += speedo-tegra20.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += speedo-tegra30.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += speedo-tegra114.o obj-$(CONFIG_ARCH_TEGRA_124_SOC) += speedo-tegra124.o +obj-$(CONFIG_ARCH_TEGRA_132_SOC) += speedo-tegra124.o diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index c0d660f1aaac..407d7e359381 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -15,9 +15,10 @@ * */ +#include #include #include -#include +#include #include #include #include @@ -28,8 +29,6 @@ #include "fuse.h" -static u32 (*fuse_readl)(const unsigned int offset); -static int fuse_size; struct tegra_sku_info tegra_sku_info; EXPORT_SYMBOL(tegra_sku_info); @@ -42,11 +41,11 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = { [TEGRA_REVISION_A04] = "A04", }; -static u8 fuse_readb(const unsigned int offset) +static u8 fuse_readb(struct tegra_fuse *fuse, unsigned int offset) { u32 val; - val = fuse_readl(round_down(offset, 4)); + val = fuse->read(fuse, round_down(offset, 4)); val >>= (offset % 4) * 8; val &= 0xff; @@ -54,19 +53,21 @@ static u8 fuse_readb(const unsigned int offset) } static ssize_t fuse_read(struct file *fd, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t pos, size_t size) + struct bin_attribute *attr, char *buf, + loff_t pos, size_t size) { + struct device *dev = kobj_to_dev(kobj); + struct tegra_fuse *fuse = dev_get_drvdata(dev); int i; - if (pos < 0 || pos >= fuse_size) + if (pos < 0 || pos >= attr->size) return 0; - if (size > fuse_size - pos) - size = fuse_size - pos; + if (size > attr->size - pos) + size = attr->size - pos; for (i = 0; i < size; i++) - buf[i] = fuse_readb(pos + i); + buf[i] = fuse_readb(fuse, pos + i); return i; } @@ -76,6 +77,14 @@ static struct bin_attribute fuse_bin_attr = { .read = fuse_read, }; +static int tegra_fuse_create_sysfs(struct device *dev, unsigned int size, + const struct tegra_fuse_info *info) +{ + fuse_bin_attr.size = size; + + return device_create_bin_file(dev, &fuse_bin_attr); +} + static const struct of_device_id car_match[] __initconst = { { .compatible = "nvidia,tegra20-car", }, { .compatible = "nvidia,tegra30-car", }, @@ -85,73 +94,211 @@ static const struct of_device_id car_match[] __initconst = { {}, }; -static void tegra_enable_fuse_clk(void __iomem *base) +static struct tegra_fuse *fuse = &(struct tegra_fuse) { + .base = NULL, + .soc = NULL, +}; + +static const struct of_device_id tegra_fuse_match[] = { +#ifdef CONFIG_ARCH_TEGRA_132_SOC + { .compatible = "nvidia,tegra132-efuse", .data = &tegra124_fuse_soc }, +#endif +#ifdef CONFIG_ARCH_TEGRA_124_SOC + { .compatible = "nvidia,tegra124-efuse", .data = &tegra124_fuse_soc }, +#endif +#ifdef CONFIG_ARCH_TEGRA_114_SOC + { .compatible = "nvidia,tegra114-efuse", .data = &tegra114_fuse_soc }, +#endif +#ifdef CONFIG_ARCH_TEGRA_3x_SOC + { .compatible = "nvidia,tegra30-efuse", .data = &tegra30_fuse_soc }, +#endif +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + { .compatible = "nvidia,tegra20-efuse", .data = &tegra20_fuse_soc }, +#endif + { /* sentinel */ } +}; + +static int tegra_fuse_probe(struct platform_device *pdev) { - u32 reg; + void __iomem *base = fuse->base; + struct resource *res; + int err; + + /* take over the memory region from the early initialization */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fuse->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(fuse->base)) + return PTR_ERR(fuse->base); + + fuse->clk = devm_clk_get(&pdev->dev, "fuse"); + if (IS_ERR(fuse->clk)) { + dev_err(&pdev->dev, "failed to get FUSE clock: %ld", + PTR_ERR(fuse->clk)); + return PTR_ERR(fuse->clk); + } - reg = readl_relaxed(base + 0x48); - reg |= 1 << 28; - writel(reg, base + 0x48); + platform_set_drvdata(pdev, fuse); + fuse->dev = &pdev->dev; - /* - * Enable FUSE clock. This needs to be hardcoded because the clock - * subsystem is not active during early boot. - */ - reg = readl(base + 0x14); - reg |= 1 << 7; - writel(reg, base + 0x14); + if (fuse->soc->probe) { + err = fuse->soc->probe(fuse); + if (err < 0) + return err; + } + + if (tegra_fuse_create_sysfs(&pdev->dev, fuse->soc->info->size, + fuse->soc->info)) + return -ENODEV; + + /* release the early I/O memory mapping */ + iounmap(base); + + return 0; +} + +static struct platform_driver tegra_fuse_driver = { + .driver = { + .name = "tegra-fuse", + .of_match_table = tegra_fuse_match, + .suppress_bind_attrs = true, + }, + .probe = tegra_fuse_probe, +}; +module_platform_driver(tegra_fuse_driver); + +bool __init tegra_fuse_read_spare(unsigned int spare) +{ + unsigned int offset = fuse->soc->info->spare + spare * 4; + + return fuse->read_early(fuse, offset) & 1; +} + +u32 __init tegra_fuse_read_early(unsigned int offset) +{ + return fuse->read_early(fuse, offset); } int tegra_fuse_readl(unsigned long offset, u32 *value) { - if (!fuse_readl) + if (!fuse->read) return -EPROBE_DEFER; - *value = fuse_readl(offset); + *value = fuse->read(fuse, offset); return 0; } EXPORT_SYMBOL(tegra_fuse_readl); -int tegra_fuse_create_sysfs(struct device *dev, int size, - u32 (*readl)(const unsigned int offset)) +static void tegra_enable_fuse_clk(void __iomem *base) { - if (fuse_size) - return -ENODEV; - - fuse_bin_attr.size = size; - fuse_bin_attr.read = fuse_read; + u32 reg; - fuse_size = size; - fuse_readl = readl; + reg = readl_relaxed(base + 0x48); + reg |= 1 << 28; + writel(reg, base + 0x48); - return device_create_bin_file(dev, &fuse_bin_attr); + /* + * Enable FUSE clock. This needs to be hardcoded because the clock + * subsystem is not active during early boot. + */ + reg = readl(base + 0x14); + reg |= 1 << 7; + writel(reg, base + 0x14); } static int __init tegra_init_fuse(void) { + const struct of_device_id *match; struct device_node *np; - void __iomem *car_base; - - if (!soc_is_tegra()) - return 0; + struct resource regs; tegra_init_apbmisc(); - np = of_find_matching_node(NULL, car_match); - car_base = of_iomap(np, 0); - if (car_base) { - tegra_enable_fuse_clk(car_base); - iounmap(car_base); + np = of_find_matching_node_and_match(NULL, tegra_fuse_match, &match); + if (!np) { + /* + * Fall back to legacy initialization for 32-bit ARM only. All + * 64-bit ARM device tree files for Tegra are required to have + * a FUSE node. + * + * This is for backwards-compatibility with old device trees + * that didn't contain a FUSE node. + */ + if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) { + u8 chip = tegra_get_chip_id(); + + regs.start = 0x7000f800; + regs.end = 0x7000fbff; + regs.flags = IORESOURCE_MEM; + + switch (chip) { +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + case TEGRA20: + fuse->soc = &tegra20_fuse_soc; + break; +#endif + +#ifdef CONFIG_ARCH_TEGRA_3x_SOC + case TEGRA30: + fuse->soc = &tegra30_fuse_soc; + break; +#endif + +#ifdef CONFIG_ARCH_TEGRA_114_SOC + case TEGRA114: + fuse->soc = &tegra114_fuse_soc; + break; +#endif + +#ifdef CONFIG_ARCH_TEGRA_124_SOC + case TEGRA124: + fuse->soc = &tegra124_fuse_soc; + break; +#endif + + default: + pr_warn("Unsupported SoC: %02x\n", chip); + break; + } + } else { + /* + * At this point we're not running on Tegra, so play + * nice with multi-platform kernels. + */ + return 0; + } } else { - pr_err("Could not enable fuse clk. ioremap tegra car failed.\n"); + /* + * Extract information from the device tree if we've found a + * matching node. + */ + if (of_address_to_resource(np, 0, ®s) < 0) { + pr_err("failed to get FUSE register\n"); + return -ENXIO; + } + + fuse->soc = match->data; + } + + np = of_find_matching_node(NULL, car_match); + if (np) { + void __iomem *base = of_iomap(np, 0); + if (base) { + tegra_enable_fuse_clk(base); + iounmap(base); + } else { + pr_err("failed to map clock registers\n"); + return -ENXIO; + } + } + + fuse->base = ioremap_nocache(regs.start, resource_size(®s)); + if (!fuse->base) { + pr_err("failed to map FUSE registers\n"); return -ENXIO; } - if (tegra_get_chip_id() == TEGRA20) - tegra20_init_fuse_early(); - else - tegra30_init_fuse_early(); + fuse->soc->init(fuse); pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", tegra_revision_name[tegra_sku_info.revision], diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c index 6acc2c44ee2c..b2f2aaad5627 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra20.c +++ b/drivers/soc/tegra/fuse/fuse-tegra20.c @@ -34,159 +34,107 @@ #include "fuse.h" #define FUSE_BEGIN 0x100 -#define FUSE_SIZE 0x1f8 #define FUSE_UID_LOW 0x08 #define FUSE_UID_HIGH 0x0c -static phys_addr_t fuse_phys; -static struct clk *fuse_clk; -static void __iomem __initdata *fuse_base; - -static DEFINE_MUTEX(apb_dma_lock); -static DECLARE_COMPLETION(apb_dma_wait); -static struct dma_chan *apb_dma_chan; -static struct dma_slave_config dma_sconfig; -static u32 *apb_buffer; -static dma_addr_t apb_buffer_phys; +static u32 tegra20_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) +{ + return readl_relaxed(fuse->base + FUSE_BEGIN + offset); +} static void apb_dma_complete(void *args) { - complete(&apb_dma_wait); + struct tegra_fuse *fuse = args; + + complete(&fuse->apbdma.wait); } -static u32 tegra20_fuse_readl(const unsigned int offset) +static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset) { - int ret; - u32 val = 0; + unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; struct dma_async_tx_descriptor *dma_desc; unsigned long time_left; + u32 value = 0; + int err; + + mutex_lock(&fuse->apbdma.lock); - mutex_lock(&apb_dma_lock); + fuse->apbdma.config.src_addr = fuse->apbdma.phys + FUSE_BEGIN + offset; - dma_sconfig.src_addr = fuse_phys + FUSE_BEGIN + offset; - ret = dmaengine_slave_config(apb_dma_chan, &dma_sconfig); - if (ret) + err = dmaengine_slave_config(fuse->apbdma.chan, &fuse->apbdma.config); + if (err) goto out; - dma_desc = dmaengine_prep_slave_single(apb_dma_chan, apb_buffer_phys, - sizeof(u32), DMA_DEV_TO_MEM, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + dma_desc = dmaengine_prep_slave_single(fuse->apbdma.chan, + fuse->apbdma.phys, + sizeof(u32), DMA_DEV_TO_MEM, + flags); if (!dma_desc) goto out; dma_desc->callback = apb_dma_complete; - dma_desc->callback_param = NULL; + dma_desc->callback_param = fuse; - reinit_completion(&apb_dma_wait); + reinit_completion(&fuse->apbdma.wait); - clk_prepare_enable(fuse_clk); + clk_prepare_enable(fuse->clk); dmaengine_submit(dma_desc); - dma_async_issue_pending(apb_dma_chan); - time_left = wait_for_completion_timeout(&apb_dma_wait, + dma_async_issue_pending(fuse->apbdma.chan); + time_left = wait_for_completion_timeout(&fuse->apbdma.wait, msecs_to_jiffies(50)); if (WARN(time_left == 0, "apb read dma timed out")) - dmaengine_terminate_all(apb_dma_chan); + dmaengine_terminate_all(fuse->apbdma.chan); else - val = *apb_buffer; + value = *fuse->apbdma.virt; - clk_disable_unprepare(fuse_clk); -out: - mutex_unlock(&apb_dma_lock); + clk_disable_unprepare(fuse->clk); - return val; +out: + mutex_unlock(&fuse->apbdma.lock); + return value; } -static const struct of_device_id tegra20_fuse_of_match[] = { - { .compatible = "nvidia,tegra20-efuse" }, - {}, -}; - -static int apb_dma_init(void) +static int tegra20_fuse_probe(struct tegra_fuse *fuse) { dma_cap_mask_t mask; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - apb_dma_chan = dma_request_channel(mask, NULL, NULL); - if (!apb_dma_chan) + + fuse->apbdma.chan = dma_request_channel(mask, NULL, NULL); + if (!fuse->apbdma.chan) return -EPROBE_DEFER; - apb_buffer = dma_alloc_coherent(NULL, sizeof(u32), &apb_buffer_phys, - GFP_KERNEL); - if (!apb_buffer) { - dma_release_channel(apb_dma_chan); + fuse->apbdma.virt = dma_alloc_coherent(fuse->dev, sizeof(u32), + &fuse->apbdma.phys, + GFP_KERNEL); + if (!fuse->apbdma.virt) { + dma_release_channel(fuse->apbdma.chan); return -ENOMEM; } - dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dma_sconfig.src_maxburst = 1; - dma_sconfig.dst_maxburst = 1; + fuse->apbdma.config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + fuse->apbdma.config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + fuse->apbdma.config.src_maxburst = 1; + fuse->apbdma.config.dst_maxburst = 1; - return 0; -} - -static int tegra20_fuse_probe(struct platform_device *pdev) -{ - struct resource *res; - int err; - - fuse_clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(fuse_clk)) { - dev_err(&pdev->dev, "missing clock"); - return PTR_ERR(fuse_clk); - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - fuse_phys = res->start; - - err = apb_dma_init(); - if (err) - return err; - - if (tegra_fuse_create_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl)) - return -ENODEV; - - dev_dbg(&pdev->dev, "loaded\n"); + init_completion(&fuse->apbdma.wait); + mutex_init(&fuse->apbdma.lock); + fuse->read = tegra20_fuse_read; return 0; } -static struct platform_driver tegra20_fuse_driver = { - .probe = tegra20_fuse_probe, - .driver = { - .name = "tegra20_fuse", - .of_match_table = tegra20_fuse_of_match, - } +static const struct tegra_fuse_info tegra20_fuse_info = { + .read = tegra20_fuse_read, + .size = 0x1f8, + .spare = 0x100, }; -static int __init tegra20_fuse_init(void) -{ - return platform_driver_register(&tegra20_fuse_driver); -} -postcore_initcall(tegra20_fuse_init); - /* Early boot code. This code is called before the devices are created */ -u32 __init tegra20_fuse_early(const unsigned int offset) -{ - return readl_relaxed(fuse_base + FUSE_BEGIN + offset); -} - -bool __init tegra20_spare_fuse_early(int spare_bit) -{ - u32 offset = spare_bit * 4; - bool value; - - value = tegra20_fuse_early(offset + 0x100); - - return value; -} - static void __init tegra20_fuse_add_randomness(void) { u32 randomness[7]; @@ -198,19 +146,24 @@ static void __init tegra20_fuse_add_randomness(void) randomness[3] |= tegra_sku_info.core_process_id; randomness[4] = tegra_sku_info.cpu_speedo_id << 16; randomness[4] |= tegra_sku_info.soc_speedo_id; - randomness[5] = tegra20_fuse_early(FUSE_UID_LOW); - randomness[6] = tegra20_fuse_early(FUSE_UID_HIGH); + randomness[5] = tegra_fuse_read_early(FUSE_UID_LOW); + randomness[6] = tegra_fuse_read_early(FUSE_UID_HIGH); add_device_randomness(randomness, sizeof(randomness)); } -void __init tegra20_init_fuse_early(void) +static void __init tegra20_fuse_init(struct tegra_fuse *fuse) { - fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE); + fuse->read_early = tegra20_fuse_read_early; tegra_init_revision(); - tegra20_init_speedo_data(&tegra_sku_info); + fuse->soc->speedo_init(&tegra_sku_info); tegra20_fuse_add_randomness(); - - iounmap(fuse_base); } + +const struct tegra_fuse_soc tegra20_fuse_soc = { + .init = tegra20_fuse_init, + .speedo_init = tegra20_init_speedo_data, + .probe = tegra20_fuse_probe, + .info = &tegra20_fuse_info, +}; diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 4d2f71bf65c5..23f8a4b5ca42 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -42,113 +42,32 @@ #define FUSE_HAS_REVISION_INFO BIT(0) -enum speedo_idx { - SPEEDO_TEGRA30 = 0, - SPEEDO_TEGRA114, - SPEEDO_TEGRA124, -}; - -struct tegra_fuse_info { - int size; - int spare_bit; - enum speedo_idx speedo_idx; -}; - -static void __iomem *fuse_base; -static struct clk *fuse_clk; -static const struct tegra_fuse_info *fuse_info; - -u32 tegra30_fuse_readl(const unsigned int offset) +#if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \ + defined(CONFIG_ARCH_TEGRA_114_SOC) || \ + defined(CONFIG_ARCH_TEGRA_124_SOC) || \ + defined(CONFIG_ARCH_TEGRA_132_SOC) +static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) { - u32 val; - - /* - * early in the boot, the fuse clock will be enabled by - * tegra_init_fuse() - */ - - if (fuse_clk) - clk_prepare_enable(fuse_clk); - - val = readl_relaxed(fuse_base + FUSE_BEGIN + offset); - - if (fuse_clk) - clk_disable_unprepare(fuse_clk); - - return val; + return readl_relaxed(fuse->base + FUSE_BEGIN + offset); } -static const struct tegra_fuse_info tegra30_info = { - .size = 0x2a4, - .spare_bit = 0x144, - .speedo_idx = SPEEDO_TEGRA30, -}; - -static const struct tegra_fuse_info tegra114_info = { - .size = 0x2a0, - .speedo_idx = SPEEDO_TEGRA114, -}; - -static const struct tegra_fuse_info tegra124_info = { - .size = 0x300, - .speedo_idx = SPEEDO_TEGRA124, -}; - -static const struct of_device_id tegra30_fuse_of_match[] = { - { .compatible = "nvidia,tegra30-efuse", .data = &tegra30_info }, - { .compatible = "nvidia,tegra114-efuse", .data = &tegra114_info }, - { .compatible = "nvidia,tegra124-efuse", .data = &tegra124_info }, - {}, -}; - -static int tegra30_fuse_probe(struct platform_device *pdev) +static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset) { - const struct of_device_id *of_dev_id; + u32 value; + int err; - of_dev_id = of_match_device(tegra30_fuse_of_match, &pdev->dev); - if (!of_dev_id) - return -ENODEV; - - fuse_clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(fuse_clk)) { - dev_err(&pdev->dev, "missing clock"); - return PTR_ERR(fuse_clk); + err = clk_prepare_enable(fuse->clk); + if (err < 0) { + dev_err(fuse->dev, "failed to enable FUSE clock: %d\n", err); + return 0; } - platform_set_drvdata(pdev, NULL); - - if (tegra_fuse_create_sysfs(&pdev->dev, fuse_info->size, - tegra30_fuse_readl)) - return -ENODEV; - - dev_dbg(&pdev->dev, "loaded\n"); + value = readl_relaxed(fuse->base + FUSE_BEGIN + offset); - return 0; -} - -static struct platform_driver tegra30_fuse_driver = { - .probe = tegra30_fuse_probe, - .driver = { - .name = "tegra_fuse", - .of_match_table = tegra30_fuse_of_match, - } -}; + clk_disable_unprepare(fuse->clk); -static int __init tegra30_fuse_init(void) -{ - return platform_driver_register(&tegra30_fuse_driver); + return value; } -postcore_initcall(tegra30_fuse_init); - -/* Early boot code. This code is called before the devices are created */ - -typedef void (*speedo_f)(struct tegra_sku_info *sku_info); - -static speedo_f __initdata speedo_tbl[] = { - [SPEEDO_TEGRA30] = tegra30_init_speedo_data, - [SPEEDO_TEGRA114] = tegra114_init_speedo_data, - [SPEEDO_TEGRA124] = tegra124_init_speedo_data, -}; static void __init tegra30_fuse_add_randomness(void) { @@ -161,64 +80,64 @@ static void __init tegra30_fuse_add_randomness(void) randomness[3] |= tegra_sku_info.core_process_id; randomness[4] = tegra_sku_info.cpu_speedo_id << 16; randomness[4] |= tegra_sku_info.soc_speedo_id; - randomness[5] = tegra30_fuse_readl(FUSE_VENDOR_CODE); - randomness[6] = tegra30_fuse_readl(FUSE_FAB_CODE); - randomness[7] = tegra30_fuse_readl(FUSE_LOT_CODE_0); - randomness[8] = tegra30_fuse_readl(FUSE_LOT_CODE_1); - randomness[9] = tegra30_fuse_readl(FUSE_WAFER_ID); - randomness[10] = tegra30_fuse_readl(FUSE_X_COORDINATE); - randomness[11] = tegra30_fuse_readl(FUSE_Y_COORDINATE); + randomness[5] = tegra_fuse_read_early(FUSE_VENDOR_CODE); + randomness[6] = tegra_fuse_read_early(FUSE_FAB_CODE); + randomness[7] = tegra_fuse_read_early(FUSE_LOT_CODE_0); + randomness[8] = tegra_fuse_read_early(FUSE_LOT_CODE_1); + randomness[9] = tegra_fuse_read_early(FUSE_WAFER_ID); + randomness[10] = tegra_fuse_read_early(FUSE_X_COORDINATE); + randomness[11] = tegra_fuse_read_early(FUSE_Y_COORDINATE); add_device_randomness(randomness, sizeof(randomness)); } -static void __init legacy_fuse_init(void) +static void __init tegra30_fuse_init(struct tegra_fuse *fuse) { - switch (tegra_get_chip_id()) { - case TEGRA30: - fuse_info = &tegra30_info; - break; - case TEGRA114: - fuse_info = &tegra114_info; - break; - case TEGRA124: - case TEGRA132: - fuse_info = &tegra124_info; - break; - default: - return; - } + fuse->read_early = tegra30_fuse_read_early; + fuse->read = tegra30_fuse_read; - fuse_base = ioremap(TEGRA_FUSE_BASE, TEGRA_FUSE_SIZE); + tegra_init_revision(); + fuse->soc->speedo_init(&tegra_sku_info); + tegra30_fuse_add_randomness(); } +#endif -bool __init tegra30_spare_fuse(int spare_bit) -{ - u32 offset = fuse_info->spare_bit + spare_bit * 4; +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +static const struct tegra_fuse_info tegra30_fuse_info = { + .read = tegra30_fuse_read, + .size = 0x2a4, + .spare = 0x144, +}; - return tegra30_fuse_readl(offset) & 1; -} +const struct tegra_fuse_soc tegra30_fuse_soc = { + .init = tegra30_fuse_init, + .speedo_init = tegra30_init_speedo_data, + .info = &tegra30_fuse_info, +}; +#endif -void __init tegra30_init_fuse_early(void) -{ - struct device_node *np; - const struct of_device_id *of_match; - - np = of_find_matching_node_and_match(NULL, tegra30_fuse_of_match, - &of_match); - if (np) { - fuse_base = of_iomap(np, 0); - fuse_info = (struct tegra_fuse_info *)of_match->data; - } else - legacy_fuse_init(); - - if (!fuse_base) { - pr_warn("fuse DT node missing and unknown chip id: 0x%02x\n", - tegra_get_chip_id()); - return; - } +#ifdef CONFIG_ARCH_TEGRA_114_SOC +static const struct tegra_fuse_info tegra114_fuse_info = { + .read = tegra30_fuse_read, + .size = 0x2a0, +}; - tegra_init_revision(); - speedo_tbl[fuse_info->speedo_idx](&tegra_sku_info); - tegra30_fuse_add_randomness(); -} +const struct tegra_fuse_soc tegra114_fuse_soc = { + .init = tegra30_fuse_init, + .speedo_init = tegra114_init_speedo_data, + .info = &tegra114_fuse_info, +}; +#endif + +#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) +static const struct tegra_fuse_info tegra124_fuse_info = { + .read = tegra30_fuse_read, + .size = 0x300, +}; + +const struct tegra_fuse_soc tegra124_fuse_soc = { + .init = tegra30_fuse_init, + .speedo_init = tegra124_init_speedo_data, + .info = &tegra124_fuse_info, +}; +#endif diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h index 3a398bf3572c..2a32bf9381ce 100644 --- a/drivers/soc/tegra/fuse/fuse.h +++ b/drivers/soc/tegra/fuse/fuse.h @@ -19,53 +19,82 @@ #ifndef __DRIVERS_MISC_TEGRA_FUSE_H #define __DRIVERS_MISC_TEGRA_FUSE_H -#define TEGRA_FUSE_BASE 0x7000f800 -#define TEGRA_FUSE_SIZE 0x400 +#include +#include -int tegra_fuse_create_sysfs(struct device *dev, int size, - u32 (*readl)(const unsigned int offset)); +struct tegra_fuse; + +struct tegra_fuse_info { + u32 (*read)(struct tegra_fuse *fuse, unsigned int offset); + unsigned int size; + unsigned int spare; +}; + +struct tegra_fuse_soc { + void (*init)(struct tegra_fuse *fuse); + void (*speedo_init)(struct tegra_sku_info *info); + int (*probe)(struct tegra_fuse *fuse); + + const struct tegra_fuse_info *info; +}; + +struct tegra_fuse { + struct device *dev; + void __iomem *base; + phys_addr_t phys; + struct clk *clk; + + u32 (*read_early)(struct tegra_fuse *fuse, unsigned int offset); + u32 (*read)(struct tegra_fuse *fuse, unsigned int offset); + const struct tegra_fuse_soc *soc; + + /* APBDMA on Tegra20 */ + struct { + struct mutex lock; + struct completion wait; + struct dma_chan *chan; + struct dma_slave_config config; + dma_addr_t phys; + u32 *virt; + } apbdma; +}; -bool tegra30_spare_fuse(int bit); -u32 tegra30_fuse_readl(const unsigned int offset); -void tegra30_init_fuse_early(void); void tegra_init_revision(void); void tegra_init_apbmisc(void); +bool __init tegra_fuse_read_spare(unsigned int spare); +u32 __init tegra_fuse_read_early(unsigned int offset); + #ifdef CONFIG_ARCH_TEGRA_2x_SOC void tegra20_init_speedo_data(struct tegra_sku_info *sku_info); -bool tegra20_spare_fuse_early(int spare_bit); -void tegra20_init_fuse_early(void); -u32 tegra20_fuse_early(const unsigned int offset); -#else -static inline void tegra20_init_speedo_data(struct tegra_sku_info *sku_info) {} -static inline bool tegra20_spare_fuse_early(int spare_bit) -{ - return false; -} -static inline void tegra20_init_fuse_early(void) {} -static inline u32 tegra20_fuse_early(const unsigned int offset) -{ - return 0; -} #endif - #ifdef CONFIG_ARCH_TEGRA_3x_SOC void tegra30_init_speedo_data(struct tegra_sku_info *sku_info); -#else -static inline void tegra30_init_speedo_data(struct tegra_sku_info *sku_info) {} #endif #ifdef CONFIG_ARCH_TEGRA_114_SOC void tegra114_init_speedo_data(struct tegra_sku_info *sku_info); -#else -static inline void tegra114_init_speedo_data(struct tegra_sku_info *sku_info) {} #endif -#ifdef CONFIG_ARCH_TEGRA_124_SOC +#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) void tegra124_init_speedo_data(struct tegra_sku_info *sku_info); -#else -static inline void tegra124_init_speedo_data(struct tegra_sku_info *sku_info) {} +#endif + +#ifdef CONFIG_ARCH_TEGRA_2x_SOC +extern const struct tegra_fuse_soc tegra20_fuse_soc; +#endif + +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +extern const struct tegra_fuse_soc tegra30_fuse_soc; +#endif + +#ifdef CONFIG_ARCH_TEGRA_114_SOC +extern const struct tegra_fuse_soc tegra114_fuse_soc; +#endif + +#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC) +extern const struct tegra_fuse_soc tegra124_fuse_soc; #endif #endif diff --git a/drivers/soc/tegra/fuse/speedo-tegra114.c b/drivers/soc/tegra/fuse/speedo-tegra114.c index 2a6ca036f09f..554c54b98b0c 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra114.c +++ b/drivers/soc/tegra/fuse/speedo-tegra114.c @@ -74,8 +74,8 @@ static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, } if (rev == TEGRA_REVISION_A01) { - tmp = tegra30_fuse_readl(0x270) << 1; - tmp |= tegra30_fuse_readl(0x26c); + tmp = tegra_fuse_read_early(0x270) << 1; + tmp |= tegra_fuse_read_early(0x26c); if (!tmp) sku_info->cpu_speedo_id = 0; } @@ -95,8 +95,8 @@ void __init tegra114_init_speedo_data(struct tegra_sku_info *sku_info) rev_sku_to_speedo_ids(sku_info, &threshold); - cpu_speedo_val = tegra30_fuse_readl(0x12c) + 1024; - core_speedo_val = tegra30_fuse_readl(0x134); + cpu_speedo_val = tegra_fuse_read_early(0x12c) + 1024; + core_speedo_val = tegra_fuse_read_early(0x134); for (i = 0; i < CPU_PROCESS_CORNERS; i++) if (cpu_speedo_val < cpu_process_speedos[threshold][i]) diff --git a/drivers/soc/tegra/fuse/speedo-tegra124.c b/drivers/soc/tegra/fuse/speedo-tegra124.c index 46362387d974..d1e896d8d8a2 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra124.c +++ b/drivers/soc/tegra/fuse/speedo-tegra124.c @@ -122,16 +122,16 @@ void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info) BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != THRESHOLD_INDEX_COUNT); - cpu_speedo_0_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_0); + cpu_speedo_0_value = tegra_fuse_read_early(FUSE_CPU_SPEEDO_0); /* GPU Speedo is stored in CPU_SPEEDO_2 */ - sku_info->gpu_speedo_value = tegra30_fuse_readl(FUSE_CPU_SPEEDO_2); + sku_info->gpu_speedo_value = tegra_fuse_read_early(FUSE_CPU_SPEEDO_2); - soc_speedo_0_value = tegra30_fuse_readl(FUSE_SOC_SPEEDO_0); + soc_speedo_0_value = tegra_fuse_read_early(FUSE_SOC_SPEEDO_0); - cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ); - soc_iddq_value = tegra30_fuse_readl(FUSE_SOC_IDDQ); - gpu_iddq_value = tegra30_fuse_readl(FUSE_GPU_IDDQ); + cpu_iddq_value = tegra_fuse_read_early(FUSE_CPU_IDDQ); + soc_iddq_value = tegra_fuse_read_early(FUSE_SOC_IDDQ); + gpu_iddq_value = tegra_fuse_read_early(FUSE_GPU_IDDQ); sku_info->cpu_speedo_value = cpu_speedo_0_value; @@ -143,7 +143,7 @@ void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info) rev_sku_to_speedo_ids(sku_info, &threshold); - sku_info->cpu_iddq_value = tegra30_fuse_readl(FUSE_CPU_IDDQ); + sku_info->cpu_iddq_value = tegra_fuse_read_early(FUSE_CPU_IDDQ); for (i = 0; i < GPU_PROCESS_CORNERS; i++) if (sku_info->gpu_speedo_value < diff --git a/drivers/soc/tegra/fuse/speedo-tegra20.c b/drivers/soc/tegra/fuse/speedo-tegra20.c index eff1b63f330d..ed5180b01e17 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra20.c +++ b/drivers/soc/tegra/fuse/speedo-tegra20.c @@ -80,8 +80,8 @@ void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info) val = 0; for (i = CPU_SPEEDO_MSBIT; i >= CPU_SPEEDO_LSBIT; i--) { - reg = tegra20_spare_fuse_early(i) | - tegra20_spare_fuse_early(i + CPU_SPEEDO_REDUND_OFFS); + reg = tegra_fuse_read_spare(i) | + tegra_fuse_read_spare(i + CPU_SPEEDO_REDUND_OFFS); val = (val << 1) | (reg & 0x1); } val = val * SPEEDO_MULT; @@ -95,8 +95,8 @@ void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info) val = 0; for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) { - reg = tegra20_spare_fuse_early(i) | - tegra20_spare_fuse_early(i + CORE_SPEEDO_REDUND_OFFS); + reg = tegra_fuse_read_spare(i) | + tegra_fuse_read_spare(i + CORE_SPEEDO_REDUND_OFFS); val = (val << 1) | (reg & 0x1); } val = val * SPEEDO_MULT; diff --git a/drivers/soc/tegra/fuse/speedo-tegra30.c b/drivers/soc/tegra/fuse/speedo-tegra30.c index b17f0dcdfebe..fd0cefae54ef 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra30.c +++ b/drivers/soc/tegra/fuse/speedo-tegra30.c @@ -93,25 +93,25 @@ static void __init fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp) int bit_minus1; int bit_minus2; - reg = tegra30_fuse_readl(FUSE_SPEEDO_CALIB_0); + reg = tegra_fuse_read_early(FUSE_SPEEDO_CALIB_0); *speedo_lp = (reg & 0xFFFF) * 4; *speedo_g = ((reg >> 16) & 0xFFFF) * 4; - ate_ver = tegra30_fuse_readl(FUSE_TEST_PROG_VER); + ate_ver = tegra_fuse_read_early(FUSE_TEST_PROG_VER); pr_debug("Tegra ATE prog ver %d.%d\n", ate_ver/10, ate_ver%10); if (ate_ver >= 26) { - bit_minus1 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1); - bit_minus1 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS1_R); - bit_minus2 = tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2); - bit_minus2 |= tegra30_spare_fuse(LP_SPEEDO_BIT_MINUS2_R); + bit_minus1 = tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS1); + bit_minus1 |= tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS1_R); + bit_minus2 = tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS2); + bit_minus2 |= tegra_fuse_read_spare(LP_SPEEDO_BIT_MINUS2_R); *speedo_lp |= (bit_minus1 << 1) | bit_minus2; - bit_minus1 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1); - bit_minus1 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS1_R); - bit_minus2 = tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2); - bit_minus2 |= tegra30_spare_fuse(G_SPEEDO_BIT_MINUS2_R); + bit_minus1 = tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS1); + bit_minus1 |= tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS1_R); + bit_minus2 = tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS2); + bit_minus2 |= tegra_fuse_read_spare(G_SPEEDO_BIT_MINUS2_R); *speedo_g |= (bit_minus1 << 1) | bit_minus2; } else { *speedo_lp |= 0x3; @@ -121,7 +121,7 @@ static void __init fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp) static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info) { - int package_id = tegra30_fuse_readl(FUSE_PACKAGE_INFO) & 0x0F; + int package_id = tegra_fuse_read_early(FUSE_PACKAGE_INFO) & 0x0F; switch (sku_info->revision) { case TEGRA_REVISION_A01: diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index 29d7714515b7..5b18f6ffa45c 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -94,8 +94,8 @@ void __init tegra_init_revision(void) rev = TEGRA_REVISION_A02; break; case 3: - if (chip_id == TEGRA20 && (tegra20_spare_fuse_early(18) || - tegra20_spare_fuse_early(19))) + if (chip_id == TEGRA20 && (tegra_fuse_read_spare(18) || + tegra_fuse_read_spare(19))) rev = TEGRA_REVISION_A03p; else rev = TEGRA_REVISION_A03; @@ -109,10 +109,7 @@ void __init tegra_init_revision(void) tegra_sku_info.revision = rev; - if (chip_id == TEGRA20) - tegra_sku_info.sku_id = tegra20_fuse_early(FUSE_SKU_INFO); - else - tegra_sku_info.sku_id = tegra30_fuse_readl(FUSE_SKU_INFO); + tegra_sku_info.sku_id = tegra_fuse_read_early(FUSE_SKU_INFO); } void __init tegra_init_apbmisc(void) -- cgit v1.3-6-gb490 From 0dc5a0d836751099f2e08deec28f56ec881925dd Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 29 Apr 2015 16:55:57 +0200 Subject: soc/tegra: fuse: Add Tegra210 support Add Tegra210 support to the fuses driver and add Tegra210-specific speedo definitions. Signed-off-by: Thierry Reding --- drivers/soc/tegra/fuse/Makefile | 1 + drivers/soc/tegra/fuse/fuse-tegra.c | 4 + drivers/soc/tegra/fuse/fuse-tegra30.c | 16 ++- drivers/soc/tegra/fuse/fuse.h | 8 ++ drivers/soc/tegra/fuse/speedo-tegra210.c | 184 +++++++++++++++++++++++++++++++ include/soc/tegra/fuse.h | 4 +- 6 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 drivers/soc/tegra/fuse/speedo-tegra210.c (limited to 'drivers') diff --git a/drivers/soc/tegra/fuse/Makefile b/drivers/soc/tegra/fuse/Makefile index 4adfce09d3a9..21bc27580178 100644 --- a/drivers/soc/tegra/fuse/Makefile +++ b/drivers/soc/tegra/fuse/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += speedo-tegra30.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += speedo-tegra114.o obj-$(CONFIG_ARCH_TEGRA_124_SOC) += speedo-tegra124.o obj-$(CONFIG_ARCH_TEGRA_132_SOC) += speedo-tegra124.o +obj-$(CONFIG_ARCH_TEGRA_210_SOC) += speedo-tegra210.o diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index 407d7e359381..5a0846474cb4 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -91,6 +91,7 @@ static const struct of_device_id car_match[] __initconst = { { .compatible = "nvidia,tegra114-car", }, { .compatible = "nvidia,tegra124-car", }, { .compatible = "nvidia,tegra132-car", }, + { .compatible = "nvidia,tegra210-car", }, {}, }; @@ -100,6 +101,9 @@ static struct tegra_fuse *fuse = &(struct tegra_fuse) { }; static const struct of_device_id tegra_fuse_match[] = { +#ifdef CONFIG_ARCH_TEGRA_210_SOC + { .compatible = "nvidia,tegra210-efuse", .data = &tegra210_fuse_soc }, +#endif #ifdef CONFIG_ARCH_TEGRA_132_SOC { .compatible = "nvidia,tegra132-efuse", .data = &tegra124_fuse_soc }, #endif diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 23f8a4b5ca42..60820baf4364 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -45,7 +45,8 @@ #if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \ defined(CONFIG_ARCH_TEGRA_114_SOC) || \ defined(CONFIG_ARCH_TEGRA_124_SOC) || \ - defined(CONFIG_ARCH_TEGRA_132_SOC) + defined(CONFIG_ARCH_TEGRA_132_SOC) || \ + defined(CONFIG_ARCH_TEGRA_210_SOC) static u32 tegra30_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset) { return readl_relaxed(fuse->base + FUSE_BEGIN + offset); @@ -141,3 +142,16 @@ const struct tegra_fuse_soc tegra124_fuse_soc = { .info = &tegra124_fuse_info, }; #endif + +#if defined(CONFIG_ARCH_TEGRA_210_SOC) +static const struct tegra_fuse_info tegra210_fuse_info = { + .read = tegra30_fuse_read, + .size = 0x300, +}; + +const struct tegra_fuse_soc tegra210_fuse_soc = { + .init = tegra30_fuse_init, + .speedo_init = tegra210_init_speedo_data, + .info = &tegra210_fuse_info, +}; +#endif diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h index 2a32bf9381ce..10c2076d5089 100644 --- a/drivers/soc/tegra/fuse/fuse.h +++ b/drivers/soc/tegra/fuse/fuse.h @@ -81,6 +81,10 @@ void tegra114_init_speedo_data(struct tegra_sku_info *sku_info); void tegra124_init_speedo_data(struct tegra_sku_info *sku_info); #endif +#ifdef CONFIG_ARCH_TEGRA_210_SOC +void tegra210_init_speedo_data(struct tegra_sku_info *sku_info); +#endif + #ifdef CONFIG_ARCH_TEGRA_2x_SOC extern const struct tegra_fuse_soc tegra20_fuse_soc; #endif @@ -97,4 +101,8 @@ extern const struct tegra_fuse_soc tegra114_fuse_soc; extern const struct tegra_fuse_soc tegra124_fuse_soc; #endif +#ifdef CONFIG_ARCH_TEGRA_210_SOC +extern const struct tegra_fuse_soc tegra210_fuse_soc; +#endif + #endif diff --git a/drivers/soc/tegra/fuse/speedo-tegra210.c b/drivers/soc/tegra/fuse/speedo-tegra210.c new file mode 100644 index 000000000000..5373f4c16b54 --- /dev/null +++ b/drivers/soc/tegra/fuse/speedo-tegra210.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2013-2015, NVIDIA 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 +#include + +#include + +#include "fuse.h" + +#define CPU_PROCESS_CORNERS 2 +#define GPU_PROCESS_CORNERS 2 +#define SOC_PROCESS_CORNERS 3 + +#define FUSE_CPU_SPEEDO_0 0x014 +#define FUSE_CPU_SPEEDO_1 0x02c +#define FUSE_CPU_SPEEDO_2 0x030 +#define FUSE_SOC_SPEEDO_0 0x034 +#define FUSE_SOC_SPEEDO_1 0x038 +#define FUSE_SOC_SPEEDO_2 0x03c +#define FUSE_CPU_IDDQ 0x018 +#define FUSE_SOC_IDDQ 0x040 +#define FUSE_GPU_IDDQ 0x128 +#define FUSE_FT_REV 0x028 + +enum { + THRESHOLD_INDEX_0, + THRESHOLD_INDEX_1, + THRESHOLD_INDEX_COUNT, +}; + +static const u32 __initconst cpu_process_speedos[][CPU_PROCESS_CORNERS] = { + { 2119, UINT_MAX }, + { 2119, UINT_MAX }, +}; + +static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = { + { UINT_MAX, UINT_MAX }, + { UINT_MAX, UINT_MAX }, +}; + +static const u32 __initconst soc_process_speedos[][SOC_PROCESS_CORNERS] = { + { 1950, 2100, UINT_MAX }, + { 1950, 2100, UINT_MAX }, +}; + +static u8 __init get_speedo_revision(void) +{ + return tegra_fuse_read_spare(4) << 2 | + tegra_fuse_read_spare(3) << 1 | + tegra_fuse_read_spare(2) << 0; +} + +static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, + u8 speedo_rev, int *threshold) +{ + int sku = sku_info->sku_id; + + /* Assign to default */ + sku_info->cpu_speedo_id = 0; + sku_info->soc_speedo_id = 0; + sku_info->gpu_speedo_id = 0; + *threshold = THRESHOLD_INDEX_0; + + switch (sku) { + case 0x00: /* Engineering SKU */ + case 0x01: /* Engineering SKU */ + case 0x07: + case 0x17: + case 0x27: + if (speedo_rev >= 2) + sku_info->gpu_speedo_id = 1; + break; + + case 0x13: + if (speedo_rev >= 2) + sku_info->gpu_speedo_id = 1; + + sku_info->cpu_speedo_id = 1; + break; + + default: + pr_err("Tegra210: unknown SKU %#04x\n", sku); + /* Using the default for the error case */ + break; + } +} + +static int get_process_id(int value, const u32 *speedos, unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) + if (value < speedos[num]) + return i; + + return -EINVAL; +} + +void __init tegra210_init_speedo_data(struct tegra_sku_info *sku_info) +{ + int cpu_speedo[3], soc_speedo[3], cpu_iddq, gpu_iddq, soc_iddq; + unsigned int index; + u8 speedo_revision; + + BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != + THRESHOLD_INDEX_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(gpu_process_speedos) != + THRESHOLD_INDEX_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(soc_process_speedos) != + THRESHOLD_INDEX_COUNT); + + /* Read speedo/IDDQ fuses */ + cpu_speedo[0] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_0); + cpu_speedo[1] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_1); + cpu_speedo[2] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_2); + + soc_speedo[0] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_0); + soc_speedo[1] = tegra_fuse_read_early(FUSE_SOC_SPEEDO_1); + soc_speedo[2] = tegra_fuse_read_early(FUSE_CPU_SPEEDO_2); + + cpu_iddq = tegra_fuse_read_early(FUSE_CPU_IDDQ) * 4; + soc_iddq = tegra_fuse_read_early(FUSE_SOC_IDDQ) * 4; + gpu_iddq = tegra_fuse_read_early(FUSE_GPU_IDDQ) * 5; + + /* + * Determine CPU, GPU and SoC speedo values depending on speedo fusing + * revision. Note that GPU speedo value is fused in CPU_SPEEDO_2. + */ + speedo_revision = get_speedo_revision(); + pr_info("Speedo Revision %u\n", speedo_revision); + + if (speedo_revision >= 3) { + sku_info->cpu_speedo_value = cpu_speedo[0]; + sku_info->gpu_speedo_value = cpu_speedo[2]; + sku_info->soc_speedo_value = soc_speedo[0]; + } else if (speedo_revision == 2) { + sku_info->cpu_speedo_value = (-1938 + (1095 * cpu_speedo[0] / 100)) / 10; + sku_info->gpu_speedo_value = (-1662 + (1082 * cpu_speedo[2] / 100)) / 10; + sku_info->soc_speedo_value = ( -705 + (1037 * soc_speedo[0] / 100)) / 10; + } else { + sku_info->cpu_speedo_value = 2100; + sku_info->gpu_speedo_value = cpu_speedo[2] - 75; + sku_info->soc_speedo_value = 1900; + } + + if ((sku_info->cpu_speedo_value <= 0) || + (sku_info->gpu_speedo_value <= 0) || + (sku_info->soc_speedo_value <= 0)) { + WARN(1, "speedo value not fused\n"); + return; + } + + rev_sku_to_speedo_ids(sku_info, speedo_revision, &index); + + sku_info->gpu_process_id = get_process_id(sku_info->gpu_speedo_value, + gpu_process_speedos[index], + GPU_PROCESS_CORNERS); + + sku_info->cpu_process_id = get_process_id(sku_info->cpu_speedo_value, + cpu_process_speedos[index], + CPU_PROCESS_CORNERS); + + sku_info->soc_process_id = get_process_id(sku_info->soc_speedo_value, + soc_process_speedos[index], + SOC_PROCESS_CORNERS); + + pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n", + sku_info->gpu_speedo_id, sku_info->gpu_speedo_value); +} diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index b019e3465f11..4a0eb02d2cba 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h @@ -22,6 +22,7 @@ #define TEGRA114 0x35 #define TEGRA124 0x40 #define TEGRA132 0x13 +#define TEGRA210 0x21 #define TEGRA_FUSE_SKU_CALIB_0 0xf0 #define TEGRA30_FUSE_SATA_CALIB 0x124 @@ -49,8 +50,9 @@ struct tegra_sku_info { int cpu_iddq_value; int core_process_id; int soc_speedo_id; - int gpu_speedo_id; + int soc_speedo_value; int gpu_process_id; + int gpu_speedo_id; int gpu_speedo_value; enum tegra_revision revision; }; -- cgit v1.3-6-gb490 From 03b3f4c8b76180ba5bd800c57a7efdb142c2341d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 23 Mar 2015 14:44:08 +0100 Subject: soc/tegra: fuse: Rename core_* to soc_* There's a mixture of core_* and soc_* prefixes for variables storing information related to the VDD_CORE rail. Choose one (soc_*) and use it more consistently. Signed-off-by: Thierry Reding --- drivers/soc/tegra/fuse/fuse-tegra.c | 8 ++++---- drivers/soc/tegra/fuse/fuse-tegra20.c | 2 +- drivers/soc/tegra/fuse/fuse-tegra30.c | 2 +- drivers/soc/tegra/fuse/speedo-tegra114.c | 16 ++++++++-------- drivers/soc/tegra/fuse/speedo-tegra124.c | 12 ++++++------ drivers/soc/tegra/fuse/speedo-tegra20.c | 22 +++++++++++----------- drivers/soc/tegra/fuse/speedo-tegra30.c | 26 +++++++++++++------------- include/soc/tegra/fuse.h | 2 +- 8 files changed, 45 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index 5a0846474cb4..de2c1bfe28b5 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -304,12 +304,12 @@ static int __init tegra_init_fuse(void) fuse->soc->init(fuse); - pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n", + pr_info("Tegra Revision: %s SKU: %d CPU Process: %d SoC Process: %d\n", tegra_revision_name[tegra_sku_info.revision], tegra_sku_info.sku_id, tegra_sku_info.cpu_process_id, - tegra_sku_info.core_process_id); - pr_debug("Tegra CPU Speedo ID %d, Soc Speedo ID %d\n", - tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id); + tegra_sku_info.soc_process_id); + pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n", + tegra_sku_info.cpu_speedo_id, tegra_sku_info.soc_speedo_id); return 0; } diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c index b2f2aaad5627..294413a969a0 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra20.c +++ b/drivers/soc/tegra/fuse/fuse-tegra20.c @@ -143,7 +143,7 @@ static void __init tegra20_fuse_add_randomness(void) randomness[1] = tegra_read_straps(); randomness[2] = tegra_read_chipid(); randomness[3] = tegra_sku_info.cpu_process_id << 16; - randomness[3] |= tegra_sku_info.core_process_id; + randomness[3] |= tegra_sku_info.soc_process_id; randomness[4] = tegra_sku_info.cpu_speedo_id << 16; randomness[4] |= tegra_sku_info.soc_speedo_id; randomness[5] = tegra_fuse_read_early(FUSE_UID_LOW); diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 60820baf4364..1e184f5dc31b 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -78,7 +78,7 @@ static void __init tegra30_fuse_add_randomness(void) randomness[1] = tegra_read_straps(); randomness[2] = tegra_read_chipid(); randomness[3] = tegra_sku_info.cpu_process_id << 16; - randomness[3] |= tegra_sku_info.core_process_id; + randomness[3] |= tegra_sku_info.soc_process_id; randomness[4] = tegra_sku_info.cpu_speedo_id << 16; randomness[4] |= tegra_sku_info.soc_speedo_id; randomness[5] = tegra_fuse_read_early(FUSE_VENDOR_CODE); diff --git a/drivers/soc/tegra/fuse/speedo-tegra114.c b/drivers/soc/tegra/fuse/speedo-tegra114.c index 554c54b98b0c..1ba41ebbb23d 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra114.c +++ b/drivers/soc/tegra/fuse/speedo-tegra114.c @@ -22,7 +22,7 @@ #include "fuse.h" -#define CORE_PROCESS_CORNERS 2 +#define SOC_PROCESS_CORNERS 2 #define CPU_PROCESS_CORNERS 2 enum { @@ -31,7 +31,7 @@ enum { THRESHOLD_INDEX_COUNT, }; -static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { +static const u32 __initconst soc_process_speedos[][SOC_PROCESS_CORNERS] = { {1123, UINT_MAX}, {0, UINT_MAX}, }; @@ -84,27 +84,27 @@ static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info, void __init tegra114_init_speedo_data(struct tegra_sku_info *sku_info) { u32 cpu_speedo_val; - u32 core_speedo_val; + u32 soc_speedo_val; int threshold; int i; BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != THRESHOLD_INDEX_COUNT); - BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != + BUILD_BUG_ON(ARRAY_SIZE(soc_process_speedos) != THRESHOLD_INDEX_COUNT); rev_sku_to_speedo_ids(sku_info, &threshold); cpu_speedo_val = tegra_fuse_read_early(0x12c) + 1024; - core_speedo_val = tegra_fuse_read_early(0x134); + soc_speedo_val = tegra_fuse_read_early(0x134); for (i = 0; i < CPU_PROCESS_CORNERS; i++) if (cpu_speedo_val < cpu_process_speedos[threshold][i]) break; sku_info->cpu_process_id = i; - for (i = 0; i < CORE_PROCESS_CORNERS; i++) - if (core_speedo_val < core_process_speedos[threshold][i]) + for (i = 0; i < SOC_PROCESS_CORNERS; i++) + if (soc_speedo_val < soc_process_speedos[threshold][i]) break; - sku_info->core_process_id = i; + sku_info->soc_process_id = i; } diff --git a/drivers/soc/tegra/fuse/speedo-tegra124.c b/drivers/soc/tegra/fuse/speedo-tegra124.c index d1e896d8d8a2..a63a134101ab 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra124.c +++ b/drivers/soc/tegra/fuse/speedo-tegra124.c @@ -24,7 +24,7 @@ #define CPU_PROCESS_CORNERS 2 #define GPU_PROCESS_CORNERS 2 -#define CORE_PROCESS_CORNERS 2 +#define SOC_PROCESS_CORNERS 2 #define FUSE_CPU_SPEEDO_0 0x14 #define FUSE_CPU_SPEEDO_1 0x2c @@ -53,7 +53,7 @@ static const u32 __initconst gpu_process_speedos[][GPU_PROCESS_CORNERS] = { {0, UINT_MAX}, }; -static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { +static const u32 __initconst soc_process_speedos[][SOC_PROCESS_CORNERS] = { {2101, UINT_MAX}, {0, UINT_MAX}, }; @@ -119,7 +119,7 @@ void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info) THRESHOLD_INDEX_COUNT); BUILD_BUG_ON(ARRAY_SIZE(gpu_process_speedos) != THRESHOLD_INDEX_COUNT); - BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != + BUILD_BUG_ON(ARRAY_SIZE(soc_process_speedos) != THRESHOLD_INDEX_COUNT); cpu_speedo_0_value = tegra_fuse_read_early(FUSE_CPU_SPEEDO_0); @@ -157,11 +157,11 @@ void __init tegra124_init_speedo_data(struct tegra_sku_info *sku_info) break; sku_info->cpu_process_id = i; - for (i = 0; i < CORE_PROCESS_CORNERS; i++) + for (i = 0; i < SOC_PROCESS_CORNERS; i++) if (soc_speedo_0_value < - core_process_speedos[threshold][i]) + soc_process_speedos[threshold][i]) break; - sku_info->core_process_id = i; + sku_info->soc_process_id = i; pr_debug("Tegra GPU Speedo ID=%d, Speedo Value=%d\n", sku_info->gpu_speedo_id, sku_info->gpu_speedo_value); diff --git a/drivers/soc/tegra/fuse/speedo-tegra20.c b/drivers/soc/tegra/fuse/speedo-tegra20.c index ed5180b01e17..5f7818bf6072 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra20.c +++ b/drivers/soc/tegra/fuse/speedo-tegra20.c @@ -28,11 +28,11 @@ #define CPU_SPEEDO_REDUND_MSBIT 39 #define CPU_SPEEDO_REDUND_OFFS (CPU_SPEEDO_REDUND_MSBIT - CPU_SPEEDO_MSBIT) -#define CORE_SPEEDO_LSBIT 40 -#define CORE_SPEEDO_MSBIT 47 -#define CORE_SPEEDO_REDUND_LSBIT 48 -#define CORE_SPEEDO_REDUND_MSBIT 55 -#define CORE_SPEEDO_REDUND_OFFS (CORE_SPEEDO_REDUND_MSBIT - CORE_SPEEDO_MSBIT) +#define SOC_SPEEDO_LSBIT 40 +#define SOC_SPEEDO_MSBIT 47 +#define SOC_SPEEDO_REDUND_LSBIT 48 +#define SOC_SPEEDO_REDUND_MSBIT 55 +#define SOC_SPEEDO_REDUND_OFFS (SOC_SPEEDO_REDUND_MSBIT - SOC_SPEEDO_MSBIT) #define SPEEDO_MULT 4 @@ -56,7 +56,7 @@ static const u32 __initconst cpu_process_speedos[][PROCESS_CORNERS_NUM] = { {316, 331, 383, UINT_MAX}, }; -static const u32 __initconst core_process_speedos[][PROCESS_CORNERS_NUM] = { +static const u32 __initconst soc_process_speedos[][PROCESS_CORNERS_NUM] = { {165, 195, 224, UINT_MAX}, {165, 195, 224, UINT_MAX}, {165, 195, 224, UINT_MAX}, @@ -69,7 +69,7 @@ void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info) int i; BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != SPEEDO_ID_COUNT); - BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != SPEEDO_ID_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(soc_process_speedos) != SPEEDO_ID_COUNT); if (SPEEDO_ID_SELECT_0(sku_info->revision)) sku_info->soc_speedo_id = SPEEDO_ID_0; @@ -94,17 +94,17 @@ void __init tegra20_init_speedo_data(struct tegra_sku_info *sku_info) sku_info->cpu_process_id = i; val = 0; - for (i = CORE_SPEEDO_MSBIT; i >= CORE_SPEEDO_LSBIT; i--) { + for (i = SOC_SPEEDO_MSBIT; i >= SOC_SPEEDO_LSBIT; i--) { reg = tegra_fuse_read_spare(i) | - tegra_fuse_read_spare(i + CORE_SPEEDO_REDUND_OFFS); + tegra_fuse_read_spare(i + SOC_SPEEDO_REDUND_OFFS); val = (val << 1) | (reg & 0x1); } val = val * SPEEDO_MULT; pr_debug("Core speedo value %u\n", val); for (i = 0; i < (PROCESS_CORNERS_NUM - 1); i++) { - if (val <= core_process_speedos[sku_info->soc_speedo_id][i]) + if (val <= soc_process_speedos[sku_info->soc_speedo_id][i]) break; } - sku_info->core_process_id = i; + sku_info->soc_process_id = i; } diff --git a/drivers/soc/tegra/fuse/speedo-tegra30.c b/drivers/soc/tegra/fuse/speedo-tegra30.c index fd0cefae54ef..9b010b3ef009 100644 --- a/drivers/soc/tegra/fuse/speedo-tegra30.c +++ b/drivers/soc/tegra/fuse/speedo-tegra30.c @@ -22,7 +22,7 @@ #include "fuse.h" -#define CORE_PROCESS_CORNERS 1 +#define SOC_PROCESS_CORNERS 1 #define CPU_PROCESS_CORNERS 6 #define FUSE_SPEEDO_CALIB_0 0x14 @@ -54,7 +54,7 @@ enum { THRESHOLD_INDEX_COUNT, }; -static const u32 __initconst core_process_speedos[][CORE_PROCESS_CORNERS] = { +static const u32 __initconst soc_process_speedos[][SOC_PROCESS_CORNERS] = { {180}, {170}, {195}, @@ -246,19 +246,19 @@ static void __init rev_sku_to_speedo_ids(struct tegra_sku_info *sku_info) void __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info) { u32 cpu_speedo_val; - u32 core_speedo_val; + u32 soc_speedo_val; int i; BUILD_BUG_ON(ARRAY_SIZE(cpu_process_speedos) != THRESHOLD_INDEX_COUNT); - BUILD_BUG_ON(ARRAY_SIZE(core_process_speedos) != + BUILD_BUG_ON(ARRAY_SIZE(soc_process_speedos) != THRESHOLD_INDEX_COUNT); rev_sku_to_speedo_ids(sku_info); - fuse_speedo_calib(&cpu_speedo_val, &core_speedo_val); + fuse_speedo_calib(&cpu_speedo_val, &soc_speedo_val); pr_debug("Tegra CPU speedo value %u\n", cpu_speedo_val); - pr_debug("Tegra Core speedo value %u\n", core_speedo_val); + pr_debug("Tegra Core speedo value %u\n", soc_speedo_val); for (i = 0; i < CPU_PROCESS_CORNERS; i++) { if (cpu_speedo_val < cpu_process_speedos[threshold_index][i]) @@ -273,16 +273,16 @@ void __init tegra30_init_speedo_data(struct tegra_sku_info *sku_info) sku_info->cpu_speedo_id = 1; } - for (i = 0; i < CORE_PROCESS_CORNERS; i++) { - if (core_speedo_val < core_process_speedos[threshold_index][i]) + for (i = 0; i < SOC_PROCESS_CORNERS; i++) { + if (soc_speedo_val < soc_process_speedos[threshold_index][i]) break; } - sku_info->core_process_id = i - 1; + sku_info->soc_process_id = i - 1; - if (sku_info->core_process_id == -1) { - pr_warn("Tegra CORE speedo value %3d out of range", - core_speedo_val); - sku_info->core_process_id = 0; + if (sku_info->soc_process_id == -1) { + pr_warn("Tegra SoC speedo value %3d out of range", + soc_speedo_val); + sku_info->soc_process_id = 0; sku_info->soc_speedo_id = 1; } } diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 4a0eb02d2cba..961b821b6a46 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h @@ -48,7 +48,7 @@ struct tegra_sku_info { int cpu_speedo_id; int cpu_speedo_value; int cpu_iddq_value; - int core_process_id; + int soc_process_id; int soc_speedo_id; int soc_speedo_value; int gpu_process_id; -- cgit v1.3-6-gb490 From b23083a9c6829675d367b4f06a64d74ead82eb14 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 4 May 2015 16:38:28 +0200 Subject: soc/tegra: fuse: Add spare bit offset for Tegra114 The offset of the first spare bit register on Tegra114 is 0x280, but account for the fixed offset of 0x100 in the fuse accessor. Signed-off-by: Thierry Reding --- drivers/soc/tegra/fuse/fuse-tegra30.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 1e184f5dc31b..1fb64f842e41 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -121,6 +121,7 @@ const struct tegra_fuse_soc tegra30_fuse_soc = { static const struct tegra_fuse_info tegra114_fuse_info = { .read = tegra30_fuse_read, .size = 0x2a0, + .spare = 0x180, }; const struct tegra_fuse_soc tegra114_fuse_soc = { -- cgit v1.3-6-gb490 From 82df0e5e78d956ea3552f7315a4d559f657047da Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 4 May 2015 16:44:29 +0200 Subject: soc/tegra: fuse: Add spare bit offset for Tegra124 The offset of the first spare bit register on Tegra124 is 0x300, but account for the fixed offset of 0x100 in the fuse accessor. Signed-off-by: Thierry Reding --- drivers/soc/tegra/fuse/fuse-tegra30.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 1fb64f842e41..04e799e33ae3 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -135,6 +135,7 @@ const struct tegra_fuse_soc tegra114_fuse_soc = { static const struct tegra_fuse_info tegra124_fuse_info = { .read = tegra30_fuse_read, .size = 0x300, + .spare = 0x200, }; const struct tegra_fuse_soc tegra124_fuse_soc = { -- cgit v1.3-6-gb490 From 1dad36cdd5d20b4d7ceca5026553e86b3315b022 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 4 May 2015 16:45:25 +0200 Subject: soc/tegra: fuse: Add spare bit offset for Tegra210 The offset of the first spare bit register on Tegra210 is 0x380, but account for the fixed offset of 0x100 in the fuse accessor. Signed-off-by: Thierry Reding --- drivers/soc/tegra/fuse/fuse-tegra30.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 04e799e33ae3..882607bcaa6c 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -149,6 +149,7 @@ const struct tegra_fuse_soc tegra124_fuse_soc = { static const struct tegra_fuse_info tegra210_fuse_info = { .read = tegra30_fuse_read, .size = 0x300, + .spare = 0x280, }; const struct tegra_fuse_soc tegra210_fuse_soc = { -- cgit v1.3-6-gb490 From 62a8a094b0e1de782a1b3dcb5e42a7d44379e583 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Wed, 13 May 2015 17:58:41 +0300 Subject: clk: tegra: Add Tegra124 DFLL clocksource platform driver Add basic platform driver support for the fast CPU cluster DFLL clocksource found on Tegra124 SoCs. This small driver selects the appropriate Tegra124-specific characterization data and integration code. It relies on the DFLL common code to do most of the work. Signed-off-by: Tuomas Tynkkynen Signed-off-by: Mikko Perttunen Acked-by: Michael Turquette [treding@nvidia.com: move setup code into ->probe()] Signed-off-by: Thierry Reding --- drivers/clk/tegra/Makefile | 2 + drivers/clk/tegra/clk-dfll.c | 6 +- drivers/clk/tegra/clk-dfll.h | 2 +- drivers/clk/tegra/clk-tegra124-dfll-fcpu.c | 166 +++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 drivers/clk/tegra/clk-tegra124-dfll-fcpu.c (limited to 'drivers') diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index ec2e5163e1ae..826c325dc2e8 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -17,4 +17,6 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o +obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124-dfll-fcpu.o obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o +obj-y += cvb.o diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index 6ec645776897..109a79b95238 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -682,7 +682,7 @@ static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate) struct dev_pm_opp *opp; int i, uv; - opp = dev_pm_opp_find_freq_ceil(td->soc->opp_dev, &rate); + opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate); if (IS_ERR(opp)) return PTR_ERR(opp); uv = dev_pm_opp_get_voltage(opp); @@ -1436,7 +1436,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) rcu_read_lock(); rate = ULONG_MAX; - opp = dev_pm_opp_find_freq_floor(td->soc->opp_dev, &rate); + opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate); if (IS_ERR(opp)) { dev_err(td->dev, "couldn't get vmax opp, empty opp table?\n"); goto out; @@ -1449,7 +1449,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) goto out; for (j = 1, rate = 0; ; rate++) { - opp = dev_pm_opp_find_freq_ceil(td->soc->opp_dev, &rate); + opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate); if (IS_ERR(opp)) break; v_opp = dev_pm_opp_get_voltage(opp); diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h index b5d1fd47684e..2e4c0772a5dc 100644 --- a/drivers/clk/tegra/clk-dfll.h +++ b/drivers/clk/tegra/clk-dfll.h @@ -35,7 +35,7 @@ * @set_clock_trimmers_low: fn ptr to tune clock trimmers for low voltage */ struct tegra_dfll_soc_data { - struct device *opp_dev; + struct device *dev; unsigned int min_millivolts; u32 tune0_low; u32 tune0_high; diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c new file mode 100644 index 000000000000..61253330c12b --- /dev/null +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -0,0 +1,166 @@ +/* + * Tegra124 DFLL FCPU clock source driver + * + * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved. + * + * Aleksandr Frid + * Paul Walmsley + * + * 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 + +#include "clk.h" +#include "clk-dfll.h" +#include "cvb.h" + +/* Maximum CPU frequency, indexed by CPU speedo id */ +static const unsigned long cpu_max_freq_table[] = { + [0] = 2014500000UL, + [1] = 2320500000UL, + [2] = 2116500000UL, + [3] = 2524500000UL, +}; + +static const struct cvb_table tegra124_cpu_cvb_tables[] = { + { + .speedo_id = -1, + .process_id = -1, + .min_millivolts = 900, + .max_millivolts = 1260, + .alignment = { + .step_uv = 10000, /* 10mV */ + }, + .speedo_scale = 100, + .voltage_scale = 1000, + .cvb_table = { + {204000000UL, {1112619, -29295, 402} }, + {306000000UL, {1150460, -30585, 402} }, + {408000000UL, {1190122, -31865, 402} }, + {510000000UL, {1231606, -33155, 402} }, + {612000000UL, {1274912, -34435, 402} }, + {714000000UL, {1320040, -35725, 402} }, + {816000000UL, {1366990, -37005, 402} }, + {918000000UL, {1415762, -38295, 402} }, + {1020000000UL, {1466355, -39575, 402} }, + {1122000000UL, {1518771, -40865, 402} }, + {1224000000UL, {1573009, -42145, 402} }, + {1326000000UL, {1629068, -43435, 402} }, + {1428000000UL, {1686950, -44715, 402} }, + {1530000000UL, {1746653, -46005, 402} }, + {1632000000UL, {1808179, -47285, 402} }, + {1734000000UL, {1871526, -48575, 402} }, + {1836000000UL, {1936696, -49855, 402} }, + {1938000000UL, {2003687, -51145, 402} }, + {2014500000UL, {2054787, -52095, 402} }, + {2116500000UL, {2124957, -53385, 402} }, + {2218500000UL, {2196950, -54665, 402} }, + {2320500000UL, {2270765, -55955, 402} }, + {2422500000UL, {2346401, -57235, 402} }, + {2524500000UL, {2437299, -58535, 402} }, + {0, { 0, 0, 0} }, + }, + .cpu_dfll_data = { + .tune0_low = 0x005020ff, + .tune0_high = 0x005040ff, + .tune1 = 0x00000060, + } + }, +}; + +static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) +{ + int process_id, speedo_id, speedo_value; + struct tegra_dfll_soc_data *soc; + const struct cvb_table *cvb; + + process_id = tegra_sku_info.cpu_process_id; + speedo_id = tegra_sku_info.cpu_speedo_id; + speedo_value = tegra_sku_info.cpu_speedo_value; + + if (speedo_id >= ARRAY_SIZE(cpu_max_freq_table)) { + dev_err(&pdev->dev, "unknown max CPU freq for speedo_id=%d\n", + speedo_id); + return -ENODEV; + } + + soc = devm_kzalloc(&pdev->dev, sizeof(*soc), GFP_KERNEL); + if (!soc) + return -ENOMEM; + + soc->dev = get_cpu_device(0); + if (!soc->dev) { + dev_err(&pdev->dev, "no CPU0 device\n"); + return -ENODEV; + } + + cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables, + ARRAY_SIZE(tegra124_cpu_cvb_tables), + process_id, speedo_id, speedo_value, + cpu_max_freq_table[speedo_id], + soc->dev); + if (IS_ERR(cvb)) { + dev_err(&pdev->dev, "couldn't build OPP table: %ld\n", + PTR_ERR(cvb)); + return PTR_ERR(cvb); + } + + soc->min_millivolts = cvb->min_millivolts; + soc->tune0_low = cvb->cpu_dfll_data.tune0_low; + soc->tune0_high = cvb->cpu_dfll_data.tune0_high; + soc->tune1 = cvb->cpu_dfll_data.tune1; + + return tegra_dfll_register(pdev, soc); +} + +static const struct of_device_id tegra124_dfll_fcpu_of_match[] = { + { .compatible = "nvidia,tegra124-dfll", }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra124_dfll_fcpu_of_match); + +static const struct dev_pm_ops tegra124_dfll_pm_ops = { + SET_RUNTIME_PM_OPS(tegra_dfll_runtime_suspend, + tegra_dfll_runtime_resume, NULL) +}; + +static struct platform_driver tegra124_dfll_fcpu_driver = { + .probe = tegra124_dfll_fcpu_probe, + .remove = tegra_dfll_unregister, + .driver = { + .name = "tegra124-dfll", + .of_match_table = tegra124_dfll_fcpu_of_match, + .pm = &tegra124_dfll_pm_ops, + }, +}; + +static int __init tegra124_dfll_fcpu_init(void) +{ + return platform_driver_register(&tegra124_dfll_fcpu_driver); +} +module_init(tegra124_dfll_fcpu_init); + +static void __exit tegra124_dfll_fcpu_exit(void) +{ + platform_driver_unregister(&tegra124_dfll_fcpu_driver); +} +module_exit(tegra124_dfll_fcpu_exit); + +MODULE_DESCRIPTION("Tegra124 DFLL clock source driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Aleksandr Frid "); +MODULE_AUTHOR("Paul Walmsley "); -- cgit v1.3-6-gb490 From c38864a703f3fe50e2b87883a0def392dd5bf26f Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Wed, 13 May 2015 17:58:42 +0300 Subject: clk: tegra: Save/restore CCLKG_BURST_POLICY on suspend Save and restore this register since the LP1 restore assembly routines fiddle with it. Otherwise the CPU would keep running on PLLX after resume from suspend even when DFLL was the original clocksource. Signed-off-by: Tuomas Tynkkynen Signed-off-by: Mikko Perttunen Acked-by: Peter De Schrijver Acked-by: Michael Turquette Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra124.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index 106ec458c945..a4886741e293 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -98,6 +98,8 @@ #define PMC_PLLM_WB0_OVERRIDE 0x1dc #define PMC_PLLM_WB0_OVERRIDE_2 0x2b0 +#define CCLKG_BURST_POLICY 0x368 + #define UTMIP_PLL_CFG2 0x488 #define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6) #define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18) @@ -130,6 +132,8 @@ #ifdef CONFIG_PM_SLEEP static struct cpu_clk_suspend_context { u32 clk_csite_src; + u32 cclkg_burst; + u32 cclkg_divider; } tegra124_cpu_clk_sctx; #endif @@ -1323,12 +1327,22 @@ static void tegra124_cpu_clock_suspend(void) tegra124_cpu_clk_sctx.clk_csite_src = readl(clk_base + CLK_SOURCE_CSITE); writel(3 << 30, clk_base + CLK_SOURCE_CSITE); + + tegra124_cpu_clk_sctx.cclkg_burst = + readl(clk_base + CCLKG_BURST_POLICY); + tegra124_cpu_clk_sctx.cclkg_divider = + readl(clk_base + CCLKG_BURST_POLICY + 4); } static void tegra124_cpu_clock_resume(void) { writel(tegra124_cpu_clk_sctx.clk_csite_src, clk_base + CLK_SOURCE_CSITE); + + writel(tegra124_cpu_clk_sctx.cclkg_burst, + clk_base + CCLKG_BURST_POLICY); + writel(tegra124_cpu_clk_sctx.cclkg_divider, + clk_base + CCLKG_BURST_POLICY + 4); } #endif -- cgit v1.3-6-gb490 From 79cf95c763a11d4b365cd5a627fd1ab4dca67890 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Wed, 13 May 2015 17:58:43 +0300 Subject: clk: tegra: Add the DFLL as a possible parent of the cclk_g clock The DFLL clocksource was missing from the list of possible parents for the fast CPU cluster. Add it to the list. Signed-off-by: Tuomas Tynkkynen Signed-off-by: Mikko Perttunen Acked-by: Michael Turquette Signed-off-by: Thierry Reding --- drivers/clk/tegra/clk-tegra-super-gen4.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c index feb3201c85ce..f1f441034b86 100644 --- a/drivers/clk/tegra/clk-tegra-super-gen4.c +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c @@ -44,7 +44,9 @@ static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", "pll_p", "pll_p_out4", "unused", - "unused", "pll_x" }; + "unused", "pll_x", "unused", "unused", + "unused", "unused", "unused", "unused", + "dfllCPU_out" }; static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", "pll_p", "pll_p_out4", "unused", -- cgit v1.3-6-gb490 From 65194cb174b873448b208eb6e04ecb72237af76e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 25 Jun 2015 16:45:57 +0200 Subject: gpio: rcar: Fine-grained Runtime PM support Currently gpio modules are runtime-resumed at probe time. This means the gpio module will be active all the time (except during system suspend, if not configured as a wake-up source). While an R-Car Gen2 gpio module retains pins configured for output at the requested level while put in standby mode, gpio registercannot be accessed while suspended. Unfortunately pm_runtime_get_sync() cannot be called from all contexts where gpio register access is needed. Hence move the Runtime PM handling from probe/remove time to gpio request/free time, which is probably the best we can do. On r8a7791/koelsch, gpio modules 0, 1, 3, and 4 are now suspended during normal use (gpio2 is used for LEDs and regulators, gpio5 for keys, gpio6 for SD-Card CD & WP, gpio7 for keys and regulators). Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 1e14a6c74ed1..4fc13ce9c60a 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -251,17 +251,32 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip, static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset) { - return pinctrl_request_gpio(chip->base + offset); + struct gpio_rcar_priv *p = gpio_to_priv(chip); + int error; + + error = pm_runtime_get_sync(&p->pdev->dev); + if (error < 0) + return error; + + error = pinctrl_request_gpio(chip->base + offset); + if (error) + pm_runtime_put(&p->pdev->dev); + + return error; } static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset) { + struct gpio_rcar_priv *p = gpio_to_priv(chip); + pinctrl_free_gpio(chip->base + offset); /* Set the GPIO as an input to ensure that the next GPIO request won't * drive the GPIO pin as an output. */ gpio_rcar_config_general_input_output_mode(chip, offset, false); + + pm_runtime_put(&p->pdev->dev); } static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset) @@ -405,7 +420,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) } pm_runtime_enable(dev); - pm_runtime_get_sync(dev); io = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -487,7 +501,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) err1: gpiochip_remove(gpio_chip); err0: - pm_runtime_put(dev); pm_runtime_disable(dev); return ret; } @@ -498,7 +511,6 @@ static int gpio_rcar_remove(struct platform_device *pdev) gpiochip_remove(&p->gpio_chip); - pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; } -- cgit v1.3-6-gb490 From 049aaf9f7e30731ce030eef3e4fd255cf8b1ae02 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 25 Jun 2015 18:18:11 +0300 Subject: gpio: pcf857x: get rid of slock spinlock The spinlock 'slock' is used now to protect pcf857x_irq() from itself which is unnecessary (especially after switching to use threaded IRQs). Hence, remove it and use mutex to protect device data in IRQ handler. Cc: Geert Uytterhoeven Signed-off-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pcf857x.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 404f3c61ef9b..1d4d9bc8b69d 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -88,7 +88,6 @@ struct pcf857x { struct gpio_chip chip; struct i2c_client *client; struct mutex lock; /* protect 'out' */ - spinlock_t slock; /* protect irq demux */ unsigned out; /* software latch */ unsigned status; /* current status */ unsigned int irq_parent; @@ -185,23 +184,21 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) static irqreturn_t pcf857x_irq(int irq, void *data) { struct pcf857x *gpio = data; - unsigned long change, i, status, flags; + unsigned long change, i, status; status = gpio->read(gpio->client); - spin_lock_irqsave(&gpio->slock, flags); - /* * call the interrupt handler iff gpio is used as * interrupt source, just to avoid bad irqs */ - + mutex_lock(&gpio->lock); change = (gpio->status ^ status) & gpio->irq_enabled; - for_each_set_bit(i, &change, gpio->chip.ngpio) - handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i)); gpio->status = status; + mutex_unlock(&gpio->lock); - spin_unlock_irqrestore(&gpio->slock, flags); + for_each_set_bit(i, &change, gpio->chip.ngpio) + handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i)); return IRQ_HANDLED; } @@ -293,7 +290,6 @@ static int pcf857x_probe(struct i2c_client *client, return -ENOMEM; mutex_init(&gpio->lock); - spin_lock_init(&gpio->slock); gpio->chip.base = pdata ? pdata->gpio_base : -1; gpio->chip.can_sleep = true; -- cgit v1.3-6-gb490 From 9cf705de06a27cc99874626c9717b32e9874b3bb Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 16 Jul 2015 01:55:57 -0700 Subject: ARM: OMAP2+: Add support for initializing dm814x clocks Let's add a minimal clocks for dm814x to get it booted. This is mostly a placeholder and relies on the PLLs being on from the bootloader. Note that the divider clocks work the same way as on dm816x and am335x. Cc: Matthijs van Duin Cc: Mike Turquette Cc: Paul Walmsley Cc: Stephen Boyd Cc: Tero Kristo Acked-by: Stephen Boyd Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/io.c | 4 ++-- drivers/clk/ti/Makefile | 2 +- drivers/clk/ti/clk-814x.c | 31 +++++++++++++++++++++++++++++++ drivers/clk/ti/clk-816x.c | 2 +- include/linux/clk/ti.h | 3 ++- 5 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 drivers/clk/ti/clk-814x.c (limited to 'drivers') diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 6779a9ff0d10..596af73c7549 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -558,7 +558,7 @@ void __init ti814x_init_early(void) ti81xx_hwmod_init(); omap_hwmod_init_postsetup(); if (of_have_populated_dt()) - omap_clk_soc_init = ti81xx_dt_clk_init; + omap_clk_soc_init = dm814x_dt_clk_init; } void __init ti816x_init_early(void) @@ -575,7 +575,7 @@ void __init ti816x_init_early(void) ti81xx_hwmod_init(); omap_hwmod_init_postsetup(); if (of_have_populated_dt()) - omap_clk_soc_init = ti81xx_dt_clk_init; + omap_clk_soc_init = dm816x_dt_clk_init; } #endif diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index 105ffd0f5e79..80b42884a0e9 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile @@ -2,7 +2,7 @@ obj-y += clk.o autoidle.o clockdomain.o clk-common = dpll.o composite.o divider.o gate.o \ fixed-factor.o mux.o apll.o obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o -obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o +obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-814x.o clk-816x.o obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \ clk-3xxx.o diff --git a/drivers/clk/ti/clk-814x.c b/drivers/clk/ti/clk-814x.c new file mode 100644 index 000000000000..d490d427cc20 --- /dev/null +++ b/drivers/clk/ti/clk-814x.c @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#include +#include +#include + +static struct ti_dt_clk dm814_clks[] = { + DT_CLK(NULL, "devosc_ck", "devosc_ck"), + DT_CLK(NULL, "mpu_ck", "mpu_ck"), + DT_CLK(NULL, "sysclk4_ck", "sysclk4_ck"), + DT_CLK(NULL, "sysclk6_ck", "sysclk6_ck"), + DT_CLK(NULL, "sysclk10_ck", "sysclk10_ck"), + DT_CLK(NULL, "sysclk18_ck", "sysclk18_ck"), + DT_CLK(NULL, "timer_sys_ck", "devosc_ck"), + DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"), + DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"), + { .node_name = NULL }, +}; + +int __init dm814x_dt_clk_init(void) +{ + ti_dt_clocks_register(dm814_clks); + omap2_clk_disable_autoidle_all(); + omap2_clk_enable_init_clocks(NULL, 0); + + return 0; +} diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c index 9451e651a1ff..43d07456e78d 100644 --- a/drivers/clk/ti/clk-816x.c +++ b/drivers/clk/ti/clk-816x.c @@ -42,7 +42,7 @@ static const char *enable_init_clks[] = { "ddr_pll_clk3", }; -int __init ti81xx_dt_clk_init(void) +int __init dm816x_dt_clk_init(void) { ti_dt_clocks_register(dm816x_clks); omap2_clk_disable_autoidle_all(); diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 79b76e13d904..1736e29cee1b 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -329,7 +329,8 @@ int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type); int omap3430_dt_clk_init(void); int omap3630_dt_clk_init(void); int am35xx_dt_clk_init(void); -int ti81xx_dt_clk_init(void); +int dm814x_dt_clk_init(void); +int dm816x_dt_clk_init(void); int omap4xxx_dt_clk_init(void); int omap5xxx_dt_clk_init(void); int dra7xx_dt_clk_init(void); -- cgit v1.3-6-gb490 From 6066677cfd9d73734ab678b9d14013c860f0f732 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 9 Jul 2015 13:15:34 +1000 Subject: drm/fb: drop panic handling This really doesn't seem to have much chance of working anymore, esp for irq context, qxl at least tries to talk to the hw, and waits for irqs, and fails. with runtime pm and other stuff I think we should just bail on this for now. Signed-off-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index cac422916c7a..eaf652b389d9 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -429,24 +429,6 @@ static bool drm_fb_helper_force_kernel_mode(void) return error; } -static int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed, - void *panic_str) -{ - /* - * It's a waste of time and effort to switch back to text console - * if the kernel should reboot before panic messages can be seen. - */ - if (panic_timeout < 0) - return 0; - - pr_err("panic occurred, switching back to text console\n"); - return drm_fb_helper_force_kernel_mode(); -} - -static struct notifier_block paniced = { - .notifier_call = drm_fb_helper_panic, -}; - static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) { struct drm_device *dev = fb_helper->dev; @@ -672,9 +654,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) if (!list_empty(&fb_helper->kernel_fb_list)) { list_del(&fb_helper->kernel_fb_list); if (list_empty(&kernel_fb_helper_list)) { - pr_info("drm: unregistered panic notifier\n"); - atomic_notifier_chain_unregister(&panic_notifier_list, - &paniced); unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); } } @@ -1109,12 +1088,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n", info->node, info->fix.id); - /* Switch back to kernel console on panic */ - /* multi card linked list maybe */ if (list_empty(&kernel_fb_helper_list)) { - dev_info(fb_helper->dev->dev, "registered panic notifier\n"); - atomic_notifier_chain_register(&panic_notifier_list, - &paniced); register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); } -- cgit v1.3-6-gb490 From 16ccaf5bb5a52372bfebd3dfbb79dd810ad49c09 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 30 Jun 2015 11:29:57 +0300 Subject: pinctrl: sh-pfc: Accept standard function, pins and groups properties The "function", "pins" and "groups" pinmux and pinctrl properties have been standardized. Support them in addition to the custom "renesas,*" properties. New-style and old-style properties can't be mixed in DT. Signed-off-by: Laurent Pinchart Signed-off-by: Linus Walleij --- .../bindings/pinctrl/renesas,pfc-pinctrl.txt | 20 +++++------ drivers/pinctrl/sh-pfc/pinctrl.c | 42 +++++++++++++++++----- 2 files changed, 44 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt index 51cee44fc140..e089142cfb14 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt @@ -58,12 +58,12 @@ are parsed through phandles and processed purely based on their content. Pin Configuration Node Properties: -- renesas,pins : An array of strings, each string containing the name of a pin. -- renesas,groups : An array of strings, each string containing the name of a pin +- pins : An array of strings, each string containing the name of a pin. +- groups : An array of strings, each string containing the name of a pin group. -- renesas,function: A string containing the name of the function to mux to the - pin group(s) specified by the renesas,groups property +- function: A string containing the name of the function to mux to the pin + group(s) specified by the groups property. Valid values for pin, group and function names can be found in the group and function arrays of the PFC data file corresponding to the SoC @@ -141,19 +141,19 @@ Example 3: KZM-A9-GT (SH-Mobile AG5) default pin state hog and pin control maps mmcif_pins: mmcif { mux { - renesas,groups = "mmc0_data8_0", "mmc0_ctrl_0"; - renesas,function = "mmc0"; + groups = "mmc0_data8_0", "mmc0_ctrl_0"; + function = "mmc0"; }; cfg { - renesas,groups = "mmc0_data8_0"; - renesas,pins = "PORT279"; + groups = "mmc0_data8_0"; + pins = "PORT279"; bias-pull-up; }; }; scifa4_pins: scifa4 { - renesas,groups = "scifa4_data", "scifa4_ctrl"; - renesas,function = "scifa4"; + groups = "scifa4_data", "scifa4_ctrl"; + function = "scifa4"; }; }; diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index ff678966008b..6fe7459f0ccb 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c @@ -40,6 +40,10 @@ struct sh_pfc_pinctrl { struct pinctrl_pin_desc *pins; struct sh_pfc_pin_config *configs; + + const char *func_prop_name; + const char *groups_prop_name; + const char *pins_prop_name; }; static int sh_pfc_get_groups_count(struct pinctrl_dev *pctldev) @@ -96,10 +100,13 @@ static int sh_pfc_map_add_config(struct pinctrl_map *map, return 0; } -static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, +static int sh_pfc_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, struct pinctrl_map **map, unsigned int *num_maps, unsigned int *index) { + struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); + struct device *dev = pmx->pfc->dev; struct pinctrl_map *maps = *map; unsigned int nmaps = *num_maps; unsigned int idx = *index; @@ -113,10 +120,27 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, const char *pin; int ret; + /* Support both the old Renesas-specific properties and the new standard + * properties. Mixing old and new properties isn't allowed, neither + * inside a subnode nor across subnodes. + */ + if (!pmx->func_prop_name) { + if (of_find_property(np, "groups", NULL) || + of_find_property(np, "pins", NULL)) { + pmx->func_prop_name = "function"; + pmx->groups_prop_name = "groups"; + pmx->pins_prop_name = "pins"; + } else { + pmx->func_prop_name = "renesas,function"; + pmx->groups_prop_name = "renesas,groups"; + pmx->pins_prop_name = "renesas,pins"; + } + } + /* Parse the function and configuration properties. At least a function * or one configuration must be specified. */ - ret = of_property_read_string(np, "renesas,function", &function); + ret = of_property_read_string(np, pmx->func_prop_name, &function); if (ret < 0 && ret != -EINVAL) { dev_err(dev, "Invalid function in DT\n"); return ret; @@ -129,11 +153,12 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, if (!function && num_configs == 0) { dev_err(dev, "DT node must contain at least a function or config\n"); + ret = -ENODEV; goto done; } /* Count the number of pins and groups and reallocate mappings. */ - ret = of_property_count_strings(np, "renesas,pins"); + ret = of_property_count_strings(np, pmx->pins_prop_name); if (ret == -EINVAL) { num_pins = 0; } else if (ret < 0) { @@ -143,7 +168,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, num_pins = ret; } - ret = of_property_count_strings(np, "renesas,groups"); + ret = of_property_count_strings(np, pmx->groups_prop_name); if (ret == -EINVAL) { num_groups = 0; } else if (ret < 0) { @@ -174,7 +199,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, *num_maps = nmaps; /* Iterate over pins and groups and create the mappings. */ - of_property_for_each_string(np, "renesas,groups", prop, group) { + of_property_for_each_string(np, pmx->groups_prop_name, prop, group) { if (function) { maps[idx].type = PIN_MAP_TYPE_MUX_GROUP; maps[idx].data.mux.group = group; @@ -198,7 +223,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, goto done; } - of_property_for_each_string(np, "renesas,pins", prop, pin) { + of_property_for_each_string(np, pmx->pins_prop_name, prop, pin) { ret = sh_pfc_map_add_config(&maps[idx], pin, PIN_MAP_TYPE_CONFIGS_PIN, configs, num_configs); @@ -246,7 +271,7 @@ static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev, index = 0; for_each_child_of_node(np, child) { - ret = sh_pfc_dt_subnode_to_map(dev, child, map, num_maps, + ret = sh_pfc_dt_subnode_to_map(pctldev, child, map, num_maps, &index); if (ret < 0) goto done; @@ -254,7 +279,8 @@ static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev, /* If no mapping has been found in child nodes try the config node. */ if (*num_maps == 0) { - ret = sh_pfc_dt_subnode_to_map(dev, np, map, num_maps, &index); + ret = sh_pfc_dt_subnode_to_map(pctldev, np, map, num_maps, + &index); if (ret < 0) goto done; } -- cgit v1.3-6-gb490 From c7977ec4a33633c8e8d9267dd014356cf857351c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 25 Jun 2015 11:39:53 +0200 Subject: pinctrl: sh-pfc: Convert to platform_get_*() If the pin function controller (which can be a GPIO controller) is instantiated before the interrupt controllers, due to the ordering in the DTS, the irq domains for the interrupt controllers referenced by its "interrupts-extended" property cannot be found yet: irq: no irq domain found for /interrupt-controller@e61c0000 ! As the sh-pfc driver accesses the platform device's resources directly, it cannot find the (optional) IRQ resources, and thinks no interrupts are available. This may lead to failures later, when GPIOs are used as interupts: gpio-keys keyboard: Unable to claim irq 0; error -22 gpio-keys: probe of keyboard failed with error -22 To fix this, add support for deferred probing to sh-pfc, by converting the driver from direct platform device resource access to using the platform_get_resource() and platform_get_irq() helpers. Note that while this fixes the root cause worked around by commit e4ba0a9bddff3ba5 ("ARM: shmobile: r8a73a4: Move pfc node to work around probe ordering bug"), I strongly recommend against reverting the workaround now, as this would lead to lots of probe deferrals in drivers relying on pinctrl. This may be reconsidered once the DT code starts taking into account phandle dependencies during device instantation. Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/core.c | 46 ++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 865d235612c5..979623895904 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -29,24 +29,25 @@ static int sh_pfc_map_resources(struct sh_pfc *pfc, struct platform_device *pdev) { - unsigned int num_windows = 0; - unsigned int num_irqs = 0; + unsigned int num_windows, num_irqs; struct sh_pfc_window *windows; unsigned int *irqs = NULL; struct resource *res; unsigned int i; + int irq; /* Count the MEM and IRQ resources. */ - for (i = 0; i < pdev->num_resources; ++i) { - switch (resource_type(&pdev->resource[i])) { - case IORESOURCE_MEM: - num_windows++; + for (num_windows = 0;; num_windows++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, num_windows); + if (!res) break; - - case IORESOURCE_IRQ: - num_irqs++; + } + for (num_irqs = 0;; num_irqs++) { + irq = platform_get_irq(pdev, num_irqs); + if (irq == -EPROBE_DEFER) + return irq; + if (irq < 0) break; - } } if (num_windows == 0) @@ -72,22 +73,17 @@ static int sh_pfc_map_resources(struct sh_pfc *pfc, } /* Fill them. */ - for (i = 0, res = pdev->resource; i < pdev->num_resources; i++, res++) { - switch (resource_type(res)) { - case IORESOURCE_MEM: - windows->phys = res->start; - windows->size = resource_size(res); - windows->virt = devm_ioremap_resource(pfc->dev, res); - if (IS_ERR(windows->virt)) - return -ENOMEM; - windows++; - break; - - case IORESOURCE_IRQ: - *irqs++ = res->start; - break; - } + for (i = 0; i < num_windows; i++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + windows->phys = res->start; + windows->size = resource_size(res); + windows->virt = devm_ioremap_resource(pfc->dev, res); + if (IS_ERR(windows->virt)) + return -ENOMEM; + windows++; } + for (i = 0; i < num_irqs; i++) + *irqs++ = platform_get_irq(pdev, i); return 0; } -- cgit v1.3-6-gb490 From 9f21c67da6a62aa082a1f20feb983ab5ed89a915 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 14 Jul 2015 13:56:52 +0200 Subject: pinctrl: sh-pfc: sh73a0: Remove obsolete multi-platform check Since the removal of the sh73a0 legacy SoC code in commit 9a9863987bf7307f ("ARM: shmobile: Remove legacy SoC code for SH-Mobile AG5"), sh73a0 is only supported in generic ARM multi-platform builds. Hence CONFIG_ARCH_MULTIPLATFORM is always set, and the check can be removed. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/pfc-sh73a0.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c index d2efbfb776ac..097526576f88 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c @@ -26,10 +26,6 @@ #include #include -#ifndef CONFIG_ARCH_MULTIPLATFORM -#include -#endif - #include "core.h" #include "sh_pfc.h" -- cgit v1.3-6-gb490 From 39ad6ff12cd54607b64642562ad850bb09176734 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 14 Jul 2015 13:56:53 +0200 Subject: pinctrl: sh-pfc: Remove obsolete sh73a0 platform_device_id entry Since the removal of the sh73a0 legacy SoC code in commit 9a9863987bf7307f ("ARM: shmobile: Remove legacy SoC code for SH-Mobile AG5"), sh73a0 is only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the corresponding platform_device_id entry. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 979623895904..23b2b3be26fd 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -605,9 +605,6 @@ static const struct platform_device_id sh_pfc_id_table[] = { #ifdef CONFIG_PINCTRL_PFC_SH7269 { "pfc-sh7269", (kernel_ulong_t)&sh7269_pinmux_info }, #endif -#ifdef CONFIG_PINCTRL_PFC_SH73A0 - { "pfc-sh73a0", (kernel_ulong_t)&sh73a0_pinmux_info }, -#endif #ifdef CONFIG_PINCTRL_PFC_SH7720 { "pfc-sh7720", (kernel_ulong_t)&sh7720_pinmux_info }, #endif -- cgit v1.3-6-gb490 From d009fa3b2b28b28f58920aaa76fa0abeb573828c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 14 Jul 2015 13:56:54 +0200 Subject: pinctrl: sh-pfc: r8a7740: Remove obsolete multi-platform check Since the removal of the r8a7740 legacy SoC code in commit 44d88c754e57a6d9 ("ARM: shmobile: Remove legacy SoC code for R-Mobile A1"), r8a7740 is only supported in generic ARM multi-platform builds. Hence CONFIG_ARCH_MULTIPLATFORM is always set, and the check can be removed. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/pfc-r8a7740.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c index d0bb1459783a..82ef1862dd1b 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c @@ -22,10 +22,6 @@ #include #include -#ifndef CONFIG_ARCH_MULTIPLATFORM -#include -#endif - #include "core.h" #include "sh_pfc.h" -- cgit v1.3-6-gb490 From 03c42c3e5216e2777f8ae819d6a076e94dcdfbdd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 14 Jul 2015 13:56:55 +0200 Subject: pinctrl: sh-pfc: Remove obsolete r8a7740 platform_device_id entry Since the removal of the r8a7740 legacy SoC code in commit 44d88c754e57a6d9 ("ARM: shmobile: Remove legacy SoC code for R-Mobile A1"), r8a7740 is only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the corresponding platform_device_id entry. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 23b2b3be26fd..fb9c44805234 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -587,9 +587,6 @@ static int sh_pfc_remove(struct platform_device *pdev) } static const struct platform_device_id sh_pfc_id_table[] = { -#ifdef CONFIG_PINCTRL_PFC_R8A7740 - { "pfc-r8a7740", (kernel_ulong_t)&r8a7740_pinmux_info }, -#endif #ifdef CONFIG_PINCTRL_PFC_R8A7778 { "pfc-r8a7778", (kernel_ulong_t)&r8a7778_pinmux_info }, #endif -- cgit v1.3-6-gb490 From 5b76e79c772648991e700f004205e9ac861c77c0 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 25 Jun 2015 20:30:50 +0300 Subject: gpiolib: irqchip: prevent driver unloading if gpio is used as irq only Now nothing prevents GPIO driver from being unloaded if its gpios were requested as GPIO IRQs only (without calling gpio_request()). Hence, add calls of try_module_get()/module_put() into gpiochip_irq_reqres/relres() to track such scenario properly. Cc: Johan Hovold Signed-off-by: Grygorii Strashko Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b1b08b3fa626..debd7c56187d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -522,10 +522,14 @@ static int gpiochip_irq_reqres(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + if (!try_module_get(chip->owner)) + return -ENODEV; + if (gpiochip_lock_as_irq(chip, d->hwirq)) { chip_err(chip, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); + module_put(chip->owner); return -EINVAL; } return 0; @@ -536,6 +540,7 @@ static void gpiochip_irq_relres(struct irq_data *d) struct gpio_chip *chip = irq_data_get_irq_chip_data(d); gpiochip_unlock_as_irq(chip, d->hwirq); + module_put(chip->owner); } static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) -- cgit v1.3-6-gb490 From 3726960edc63bb1e09678841df44b44feee20305 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 25 Jun 2015 20:30:51 +0300 Subject: gpiolib: assign chip owner to dev->driver->owner if not set Assign GPIO chip owner field to chip->dev->driver->owner if it was not configured by GPIO driver. Cc: Johan Hovold Signed-off-by: Grygorii Strashko Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index debd7c56187d..d11f325eeea3 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -287,6 +287,9 @@ int gpiochip_add(struct gpio_chip *chip) INIT_LIST_HEAD(&chip->pin_ranges); #endif + if (!chip->owner && chip->dev && chip->dev->driver) + chip->owner = chip->dev->driver->owner; + of_gpiochip_add(chip); acpi_gpiochip_add(chip); -- cgit v1.3-6-gb490 From 54442658d8e83b0589731620bd958cc8b2857167 Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Sat, 4 Jul 2015 16:34:32 -0400 Subject: gpio: 74xx: Fix build warning about void to integer cast This fixes the build warning , warning: cast from pointer to integer of different size when building this file on a x86 allmodconfig configuration. In order for me to fix this build warning I changed the cast in the function mmio_74xx_gpio_probe from casting the variable data of the stucture pointer of_id to uintptr_t rather then unsigned when assigning to the variable flag of the structure pointer priv of the structure type mmio_74xx_gpio_priv. Signed-off-by: Nicholas Krause Signed-off-by: Linus Walleij --- drivers/gpio/gpio-74xx-mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c index 0763655cca6c..6ed7c0fb3378 100644 --- a/drivers/gpio/gpio-74xx-mmio.c +++ b/drivers/gpio/gpio-74xx-mmio.c @@ -129,7 +129,7 @@ static int mmio_74xx_gpio_probe(struct platform_device *pdev) if (IS_ERR(dat)) return PTR_ERR(dat); - priv->flags = (unsigned)of_id->data; + priv->flags = (uintptr_t) of_id->data; err = bgpio_init(&priv->bgc, &pdev->dev, DIV_ROUND_UP(MMIO_74XX_BIT_CNT(priv->flags), 8), -- cgit v1.3-6-gb490 From ffe2288828cb3aa45f6752d99ec7113f5135d1fa Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 15 Jul 2015 14:22:33 -0300 Subject: spi: spidev: Fix typo Fix the typo in "compatible". Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index dd616ff0ffc5..9d8841efffd8 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -708,7 +708,7 @@ static int spidev_probe(struct spi_device *spi) /* * spidev should never be referenced in DT without a specific - * compatbile string, it is a Linux implementation thing + * compatible string, it is a Linux implementation thing * rather than a description of the hardware. */ if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) { -- cgit v1.3-6-gb490 From 6417049f662d85a6f3a6b7cb8bc98bae3edae0a4 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 6 Jul 2015 18:11:50 +0300 Subject: pinctrl: single: dra7: remove PCS_QUIRK_SHARED_IRQ On DRA7 there is one pinctrl domain (dra7_pmx_core) and PRCM wake-up IRQ is not shared, so remove quirk. Cc: Nishanth Menon Fixes: 31320beaa3d3 ('pinctrl: single: Add DRA7 pinctrl compatibility') Signed-off-by: Grygorii Strashko Acked-by: Tero Kristo Acked-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-single.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index b2de09d3b1a0..1cd085d92147 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1982,7 +1982,6 @@ static const struct pcs_soc_data pinctrl_single_omap_wkup = { }; static const struct pcs_soc_data pinctrl_single_dra7 = { - .flags = PCS_QUIRK_SHARED_IRQ, .irq_enable_mask = (1 << 24), /* WAKEUPENABLE */ .irq_status_mask = (1 << 25), /* WAKEUPEVENT */ }; -- cgit v1.3-6-gb490 From b6c52c634506d52b3a2dc18503980d717e478739 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 8 Jul 2015 15:41:42 +0800 Subject: dmaengine: ioatdma: Ignore IOAT devices under hotplug-capable PCI host bridge The dmaengine core assumes that async DMA devices will only be removed when they not used anymore, or it assumes dma_async_device_unregister() will only be called by dma driver exit routines. But this assumption is not true for the IOAT driver, which calls dma_async_device_unregister() from ioat_remove(). So current IOAT driver doesn't support device hot-removal because it may cause system crash to hot-remove an inuse IOAT device. To support CPU socket hot-removal, all PCI devices, including IOAT devices embedded in the socket, will be hot-removed. The idea solution is to enhance the dmaengine core and IOAT driver to support hot-removal, but that's too hard. This patch implements a hack to disable IOAT devices under hotplug-capable CPU socket so it won't break socket hot-removal. Signed-off-by: Jiang Liu Signed-off-by: Vinod Koul --- drivers/dma/ioat/pci.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/ioat/pci.c b/drivers/dma/ioat/pci.c index 76f0dc688a19..3b8c9b03f4b3 100644 --- a/drivers/dma/ioat/pci.c +++ b/drivers/dma/ioat/pci.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dma.h" #include "dma_v2.h" #include "registers.h" @@ -148,6 +149,34 @@ alloc_ioatdma(struct pci_dev *pdev, void __iomem *iobase) return d; } +/* + * The dmaengine core assumes that async DMA devices will only be removed + * when they not used anymore, or it assumes dma_async_device_unregister() + * will only be called by dma driver exit routines. But this assumption is + * not true for the IOAT driver, which calls dma_async_device_unregister() + * from ioat_remove(). So current IOAT driver doesn't support device + * hot-removal because it may cause system crash to hot-remove inuse IOAT + * devices. + * + * This is a hack to disable IOAT devices under ejectable PCI host bridge + * so it won't break PCI host bridge hot-removal. + */ +static bool ioat_pci_has_ejectable_acpi_ancestor(struct pci_dev *pdev) +{ +#ifdef CONFIG_ACPI + struct pci_bus *bus = pdev->bus; + struct acpi_device *adev; + + while (bus->parent) + bus = bus->parent; + for (adev = ACPI_COMPANION(bus->bridge); adev; adev = adev->parent) + if (adev->flags.ejectable) + return true; +#endif + + return false; +} + static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { void __iomem * const *iomap; @@ -155,6 +184,11 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct ioatdma_device *device; int err; + if (ioat_pci_has_ejectable_acpi_ancestor(pdev)) { + dev_dbg(&pdev->dev, "ignore ejectable IOAT device.\n"); + return -ENODEV; + } + err = pcim_enable_device(pdev); if (err) return err; -- cgit v1.3-6-gb490 From 03734485b71129a954861f298825a490bcade986 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 9 Jul 2015 13:25:37 +0300 Subject: dmaengine: hsu: remove excessive lock All hardware accesses are done under virtual channel lock. That's why specific channel lock is excessive and can be removed safely. This has been tested on Intel Medfield and Merrifield. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/hsu/hsu.c | 39 ++++----------------------------------- drivers/dma/hsu/hsu.h | 1 - 2 files changed, 4 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index f42f71e37e73..7669c7dd1e34 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -99,21 +99,13 @@ static void hsu_dma_chan_start(struct hsu_dma_chan *hsuc) static void hsu_dma_stop_channel(struct hsu_dma_chan *hsuc) { - unsigned long flags; - - spin_lock_irqsave(&hsuc->lock, flags); hsu_chan_disable(hsuc); hsu_chan_writel(hsuc, HSU_CH_DCR, 0); - spin_unlock_irqrestore(&hsuc->lock, flags); } static void hsu_dma_start_channel(struct hsu_dma_chan *hsuc) { - unsigned long flags; - - spin_lock_irqsave(&hsuc->lock, flags); hsu_dma_chan_start(hsuc); - spin_unlock_irqrestore(&hsuc->lock, flags); } static void hsu_dma_start_transfer(struct hsu_dma_chan *hsuc) @@ -139,9 +131,9 @@ static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc) unsigned long flags; u32 sr; - spin_lock_irqsave(&hsuc->lock, flags); + spin_lock_irqsave(&hsuc->vchan.lock, flags); sr = hsu_chan_readl(hsuc, HSU_CH_SR); - spin_unlock_irqrestore(&hsuc->lock, flags); + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); return sr; } @@ -273,14 +265,11 @@ static size_t hsu_dma_active_desc_size(struct hsu_dma_chan *hsuc) struct hsu_dma_desc *desc = hsuc->desc; size_t bytes = hsu_dma_desc_size(desc); int i; - unsigned long flags; - spin_lock_irqsave(&hsuc->lock, flags); i = desc->active % HSU_DMA_CHAN_NR_DESC; do { bytes += hsu_chan_readl(hsuc, HSU_CH_DxTSR(i)); } while (--i >= 0); - spin_unlock_irqrestore(&hsuc->lock, flags); return bytes; } @@ -327,24 +316,6 @@ static int hsu_dma_slave_config(struct dma_chan *chan, return 0; } -static void hsu_dma_chan_deactivate(struct hsu_dma_chan *hsuc) -{ - unsigned long flags; - - spin_lock_irqsave(&hsuc->lock, flags); - hsu_chan_disable(hsuc); - spin_unlock_irqrestore(&hsuc->lock, flags); -} - -static void hsu_dma_chan_activate(struct hsu_dma_chan *hsuc) -{ - unsigned long flags; - - spin_lock_irqsave(&hsuc->lock, flags); - hsu_chan_enable(hsuc); - spin_unlock_irqrestore(&hsuc->lock, flags); -} - static int hsu_dma_pause(struct dma_chan *chan) { struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); @@ -352,7 +323,7 @@ static int hsu_dma_pause(struct dma_chan *chan) spin_lock_irqsave(&hsuc->vchan.lock, flags); if (hsuc->desc && hsuc->desc->status == DMA_IN_PROGRESS) { - hsu_dma_chan_deactivate(hsuc); + hsu_chan_disable(hsuc); hsuc->desc->status = DMA_PAUSED; } spin_unlock_irqrestore(&hsuc->vchan.lock, flags); @@ -368,7 +339,7 @@ static int hsu_dma_resume(struct dma_chan *chan) spin_lock_irqsave(&hsuc->vchan.lock, flags); if (hsuc->desc && hsuc->desc->status == DMA_PAUSED) { hsuc->desc->status = DMA_IN_PROGRESS; - hsu_dma_chan_activate(hsuc); + hsu_chan_enable(hsuc); } spin_unlock_irqrestore(&hsuc->vchan.lock, flags); @@ -441,8 +412,6 @@ int hsu_dma_probe(struct hsu_dma_chip *chip) hsuc->direction = (i & 0x1) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; hsuc->reg = addr + i * HSU_DMA_CHAN_LENGTH; - - spin_lock_init(&hsuc->lock); } dma_cap_set(DMA_SLAVE, hsu->dma.cap_mask); diff --git a/drivers/dma/hsu/hsu.h b/drivers/dma/hsu/hsu.h index 0275233cf550..eeb9fff66967 100644 --- a/drivers/dma/hsu/hsu.h +++ b/drivers/dma/hsu/hsu.h @@ -78,7 +78,6 @@ struct hsu_dma_chan { struct virt_dma_chan vchan; void __iomem *reg; - spinlock_t lock; /* hardware configuration */ enum dma_transfer_direction direction; -- cgit v1.3-6-gb490 From d7fdb356902a13bb92229722d88a836523a3c6e3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:39:52 +0000 Subject: dmaengine: ipu: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Dan Williams Cc: Vinod Koul Cc: dmaengine@vger.kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ipu/ipu_irq.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index 2e284a4438bc..8d36f07b5801 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -382,11 +382,9 @@ int __init ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev) #endif } - irq_set_handler_data(ipu->irq_fn, ipu); - irq_set_chained_handler(ipu->irq_fn, ipu_irq_fn); + irq_set_chained_handler_and_data(ipu->irq_fn, ipu_irq_fn, ipu); - irq_set_handler_data(ipu->irq_err, ipu); - irq_set_chained_handler(ipu->irq_err, ipu_irq_err); + irq_set_chained_handler_and_data(ipu->irq_err, ipu_irq_err, ipu); ipu->irq_base = irq_base; @@ -399,11 +397,9 @@ void ipu_irq_detach_irq(struct ipu *ipu, struct platform_device *dev) irq_base = ipu->irq_base; - irq_set_chained_handler(ipu->irq_fn, NULL); - irq_set_handler_data(ipu->irq_fn, NULL); + irq_set_chained_handler_and_data(ipu->irq_fn, NULL, NULL); - irq_set_chained_handler(ipu->irq_err, NULL); - irq_set_handler_data(ipu->irq_err, NULL); + irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL); for (irq = irq_base; irq < irq_base + CONFIG_MX3_IPU_IRQS; irq++) { #ifdef CONFIG_ARM -- cgit v1.3-6-gb490 From 4d9efdfce73c8f0c9e39d118833e4776719a8d40 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:39:54 +0000 Subject: dmaengine: ipu: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. This is also a preparation for the removal of the 'irq' argument from interrupt flow handlers. Signed-off-by: Jiang Liu Cc: Dan Williams Cc: Vinod Koul Cc: dmaengine@vger.kernel.org Signed-off-by: Thomas Gleixner Signed-off-by: Vinod Koul --- drivers/dma/ipu/ipu_irq.c | 2 +- drivers/gpu/ipu-v3/ipu-common.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index 8d36f07b5801..4357063980e1 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -268,7 +268,7 @@ int ipu_irq_unmap(unsigned int source) /* Chained IRQ handler for IPU error interrupt */ static void ipu_irq_err(unsigned int irq, struct irq_desc *desc) { - struct ipu *ipu = irq_get_handler_data(irq); + struct ipu *ipu = irq_desc_get_handler_data(desc); u32 status; int i, line; diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 6d2f39d36e44..552178799062 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -915,8 +915,8 @@ static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs) static void ipu_irq_handler(unsigned int irq, struct irq_desc *desc) { struct ipu_soc *ipu = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14}; - struct irq_chip *chip = irq_get_chip(irq); chained_irq_enter(chip, desc); @@ -928,8 +928,8 @@ static void ipu_irq_handler(unsigned int irq, struct irq_desc *desc) static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc) { struct ipu_soc *ipu = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); const int int_reg[] = { 4, 5, 8, 9}; - struct irq_chip *chip = irq_get_chip(irq); chained_irq_enter(chip, desc); -- cgit v1.3-6-gb490 From e3f3aaac06657e6fc834e217ae450f51a6e0968c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:27:30 +0900 Subject: pinctrl: sirf: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij --- drivers/pinctrl/sirf/pinctrl-atlas7.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c index 9384e0aa3996..d6e80fe1c7f7 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas7.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c @@ -4621,7 +4621,6 @@ failed: static struct platform_driver atlas7_gpio_driver = { .driver = { .name = "atlas7-gpio", - .owner = THIS_MODULE, .of_match_table = atlas7_gpio_ids, }, .probe = atlas7_gpio_probe, -- cgit v1.3-6-gb490 From e3fa9841d309ae7992b658eba0f973543b97ed1f Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Tue, 5 May 2015 22:06:08 +0800 Subject: dmaengine: zxdma: Support ZTE ZX296702 dma Add ZTE ZX296702 dma controller support. Only device tree probe is support currently. Signed-off-by: Jun Nie Reviewed-by: Maxime Ripard Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 7 + drivers/dma/Makefile | 1 + drivers/dma/zx296702_dma.c | 870 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 878 insertions(+) create mode 100644 drivers/dma/zx296702_dma.c (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 88d474b78076..bcbfc6b3b71b 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -458,6 +458,13 @@ config XGENE_DMA select ASYNC_TX_ENABLE_CHANNEL_SWITCH help Enable support for the APM X-Gene SoC DMA engine. +config ZX_DMA + tristate "ZTE ZX296702 DMA support" + depends on ARCH_ZX + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Support the DMA engine for ZTE ZX296702 platform devices. config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 6a4d6f2827da..c4c1ccb00138 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -56,3 +56,4 @@ obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o obj-$(CONFIG_XGENE_DMA) += xgene-dma.o +obj-$(CONFIG_ZX_DMA) += zx296702_dma.o diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx296702_dma.c new file mode 100644 index 000000000000..c99f0d1ac88a --- /dev/null +++ b/drivers/dma/zx296702_dma.c @@ -0,0 +1,870 @@ +/* + * Copyright 2015 Linaro. + * + * 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 "virt-dma.h" + +#define DRIVER_NAME "zx-dma" +#define DMA_ALIGN 4 +#define DMA_MAX_SIZE (0x10000 - PAGE_SIZE) +#define LLI_BLOCK_SIZE (4 * PAGE_SIZE) + +#define REG_ZX_SRC_ADDR 0x00 +#define REG_ZX_DST_ADDR 0x04 +#define REG_ZX_TX_X_COUNT 0x08 +#define REG_ZX_TX_ZY_COUNT 0x0c +#define REG_ZX_SRC_ZY_STEP 0x10 +#define REG_ZX_DST_ZY_STEP 0x14 +#define REG_ZX_LLI_ADDR 0x1c +#define REG_ZX_CTRL 0x20 +#define REG_ZX_TC_IRQ 0x800 +#define REG_ZX_SRC_ERR_IRQ 0x804 +#define REG_ZX_DST_ERR_IRQ 0x808 +#define REG_ZX_CFG_ERR_IRQ 0x80c +#define REG_ZX_TC_IRQ_RAW 0x810 +#define REG_ZX_SRC_ERR_IRQ_RAW 0x814 +#define REG_ZX_DST_ERR_IRQ_RAW 0x818 +#define REG_ZX_CFG_ERR_IRQ_RAW 0x81c +#define REG_ZX_STATUS 0x820 +#define REG_ZX_DMA_GRP_PRIO 0x824 +#define REG_ZX_DMA_ARB 0x828 + +#define ZX_FORCE_CLOSE BIT(31) +#define ZX_DST_BURST_WIDTH(x) (((x) & 0x7) << 13) +#define ZX_MAX_BURST_LEN 16 +#define ZX_SRC_BURST_LEN(x) (((x) & 0xf) << 9) +#define ZX_SRC_BURST_WIDTH(x) (((x) & 0x7) << 6) +#define ZX_IRQ_ENABLE_ALL (3 << 4) +#define ZX_DST_FIFO_MODE BIT(3) +#define ZX_SRC_FIFO_MODE BIT(2) +#define ZX_SOFT_REQ BIT(1) +#define ZX_CH_ENABLE BIT(0) + +#define ZX_DMA_BUSWIDTHS \ + (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \ + BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)) + +enum zx_dma_burst_width { + ZX_DMA_WIDTH_8BIT = 0, + ZX_DMA_WIDTH_16BIT = 1, + ZX_DMA_WIDTH_32BIT = 2, + ZX_DMA_WIDTH_64BIT = 3, +}; + +struct zx_desc_hw { + u32 saddr; + u32 daddr; + u32 src_x; + u32 src_zy; + u32 src_zy_step; + u32 dst_zy_step; + u32 reserved1; + u32 lli; + u32 ctr; + u32 reserved[7]; /* pack as hardware registers region size */ +} __aligned(32); + +struct zx_dma_desc_sw { + struct virt_dma_desc vd; + dma_addr_t desc_hw_lli; + size_t desc_num; + size_t size; + struct zx_desc_hw *desc_hw; +}; + +struct zx_dma_phy; + +struct zx_dma_chan { + struct dma_slave_config slave_cfg; + int id; /* Request phy chan id */ + u32 ccfg; + struct virt_dma_chan vc; + struct zx_dma_phy *phy; + struct list_head node; + dma_addr_t dev_addr; + enum dma_status status; +}; + +struct zx_dma_phy { + u32 idx; + void __iomem *base; + struct zx_dma_chan *vchan; + struct zx_dma_desc_sw *ds_run; + struct zx_dma_desc_sw *ds_done; +}; + +struct zx_dma_dev { + struct dma_device slave; + void __iomem *base; + spinlock_t lock; /* lock for ch and phy */ + struct list_head chan_pending; + struct zx_dma_phy *phy; + struct zx_dma_chan *chans; + struct clk *clk; + struct dma_pool *pool; + u32 dma_channels; + u32 dma_requests; +}; + +#define to_zx_dma(dmadev) container_of(dmadev, struct zx_dma_dev, slave) + +static struct zx_dma_chan *to_zx_chan(struct dma_chan *chan) +{ + return container_of(chan, struct zx_dma_chan, vc.chan); +} + +static void zx_dma_terminate_chan(struct zx_dma_phy *phy, struct zx_dma_dev *d) +{ + u32 val = 0; + + val = readl_relaxed(phy->base + REG_ZX_CTRL); + val &= ~ZX_CH_ENABLE; + writel_relaxed(val, phy->base + REG_ZX_CTRL); + + val = 0x1 << phy->idx; + writel_relaxed(val, d->base + REG_ZX_TC_IRQ_RAW); + writel_relaxed(val, d->base + REG_ZX_SRC_ERR_IRQ_RAW); + writel_relaxed(val, d->base + REG_ZX_DST_ERR_IRQ_RAW); + writel_relaxed(val, d->base + REG_ZX_CFG_ERR_IRQ_RAW); +} + +static void zx_dma_set_desc(struct zx_dma_phy *phy, struct zx_desc_hw *hw) +{ + writel_relaxed(hw->saddr, phy->base + REG_ZX_SRC_ADDR); + writel_relaxed(hw->daddr, phy->base + REG_ZX_DST_ADDR); + writel_relaxed(hw->src_x, phy->base + REG_ZX_TX_X_COUNT); + writel_relaxed(0, phy->base + REG_ZX_TX_ZY_COUNT); + writel_relaxed(0, phy->base + REG_ZX_SRC_ZY_STEP); + writel_relaxed(0, phy->base + REG_ZX_DST_ZY_STEP); + writel_relaxed(hw->lli, phy->base + REG_ZX_LLI_ADDR); + writel_relaxed(hw->ctr, phy->base + REG_ZX_CTRL); +} + +static u32 zx_dma_get_curr_lli(struct zx_dma_phy *phy) +{ + return readl_relaxed(phy->base + REG_ZX_LLI_ADDR); +} + +static u32 zx_dma_get_chan_stat(struct zx_dma_dev *d) +{ + return readl_relaxed(d->base + REG_ZX_STATUS); +} + +static void zx_dma_init_state(struct zx_dma_dev *d) +{ + /* set same priority */ + writel_relaxed(0x0, d->base + REG_ZX_DMA_ARB); + /* clear all irq */ + writel_relaxed(0xffffffff, d->base + REG_ZX_TC_IRQ_RAW); + writel_relaxed(0xffffffff, d->base + REG_ZX_SRC_ERR_IRQ_RAW); + writel_relaxed(0xffffffff, d->base + REG_ZX_DST_ERR_IRQ_RAW); + writel_relaxed(0xffffffff, d->base + REG_ZX_CFG_ERR_IRQ_RAW); +} + +static int zx_dma_start_txd(struct zx_dma_chan *c) +{ + struct zx_dma_dev *d = to_zx_dma(c->vc.chan.device); + struct virt_dma_desc *vd = vchan_next_desc(&c->vc); + + if (!c->phy) + return -EAGAIN; + + if (BIT(c->phy->idx) & zx_dma_get_chan_stat(d)) + return -EAGAIN; + + if (vd) { + struct zx_dma_desc_sw *ds = + container_of(vd, struct zx_dma_desc_sw, vd); + /* + * fetch and remove request from vc->desc_issued + * so vc->desc_issued only contains desc pending + */ + list_del(&ds->vd.node); + c->phy->ds_run = ds; + c->phy->ds_done = NULL; + /* start dma */ + zx_dma_set_desc(c->phy, ds->desc_hw); + return 0; + } + c->phy->ds_done = NULL; + c->phy->ds_run = NULL; + return -EAGAIN; +} + +static void zx_dma_task(struct zx_dma_dev *d) +{ + struct zx_dma_phy *p; + struct zx_dma_chan *c, *cn; + unsigned pch, pch_alloc = 0; + unsigned long flags; + + /* check new dma request of running channel in vc->desc_issued */ + list_for_each_entry_safe(c, cn, &d->slave.channels, + vc.chan.device_node) { + spin_lock_irqsave(&c->vc.lock, flags); + p = c->phy; + if (p && p->ds_done && zx_dma_start_txd(c)) { + /* No current txd associated with this channel */ + dev_dbg(d->slave.dev, "pchan %u: free\n", p->idx); + /* Mark this channel free */ + c->phy = NULL; + p->vchan = NULL; + } + spin_unlock_irqrestore(&c->vc.lock, flags); + } + + /* check new channel request in d->chan_pending */ + spin_lock_irqsave(&d->lock, flags); + while (!list_empty(&d->chan_pending)) { + c = list_first_entry(&d->chan_pending, + struct zx_dma_chan, node); + p = &d->phy[c->id]; + if (!p->vchan) { + /* remove from d->chan_pending */ + list_del_init(&c->node); + pch_alloc |= 1 << c->id; + /* Mark this channel allocated */ + p->vchan = c; + c->phy = p; + } else { + dev_dbg(d->slave.dev, "pchan %u: busy!\n", c->id); + } + } + spin_unlock_irqrestore(&d->lock, flags); + + for (pch = 0; pch < d->dma_channels; pch++) { + if (pch_alloc & (1 << pch)) { + p = &d->phy[pch]; + c = p->vchan; + if (c) { + spin_lock_irqsave(&c->vc.lock, flags); + zx_dma_start_txd(c); + spin_unlock_irqrestore(&c->vc.lock, flags); + } + } + } +} + +static irqreturn_t zx_dma_int_handler(int irq, void *dev_id) +{ + struct zx_dma_dev *d = (struct zx_dma_dev *)dev_id; + struct zx_dma_phy *p; + struct zx_dma_chan *c; + u32 tc = readl_relaxed(d->base + REG_ZX_TC_IRQ); + u32 serr = readl_relaxed(d->base + REG_ZX_SRC_ERR_IRQ); + u32 derr = readl_relaxed(d->base + REG_ZX_DST_ERR_IRQ); + u32 cfg = readl_relaxed(d->base + REG_ZX_CFG_ERR_IRQ); + u32 i, irq_chan = 0; + + while (tc) { + i = __ffs(tc); + tc &= ~BIT(i); + p = &d->phy[i]; + c = p->vchan; + if (c) { + unsigned long flags; + + spin_lock_irqsave(&c->vc.lock, flags); + vchan_cookie_complete(&p->ds_run->vd); + p->ds_done = p->ds_run; + spin_unlock_irqrestore(&c->vc.lock, flags); + } + irq_chan |= BIT(i); + } + + if (serr || derr || cfg) + dev_warn(d->slave.dev, "DMA ERR src 0x%x, dst 0x%x, cfg 0x%x\n", + serr, derr, cfg); + + writel_relaxed(irq_chan, d->base + REG_ZX_TC_IRQ_RAW); + writel_relaxed(serr, d->base + REG_ZX_SRC_ERR_IRQ_RAW); + writel_relaxed(derr, d->base + REG_ZX_DST_ERR_IRQ_RAW); + writel_relaxed(cfg, d->base + REG_ZX_CFG_ERR_IRQ_RAW); + + if (irq_chan) { + zx_dma_task(d); + return IRQ_HANDLED; + } else { + return IRQ_NONE; + } +} + +static void zx_dma_free_chan_resources(struct dma_chan *chan) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_dev *d = to_zx_dma(chan->device); + unsigned long flags; + + spin_lock_irqsave(&d->lock, flags); + list_del_init(&c->node); + spin_unlock_irqrestore(&d->lock, flags); + + vchan_free_chan_resources(&c->vc); + c->ccfg = 0; +} + +static enum dma_status zx_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, + struct dma_tx_state *state) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_phy *p; + struct virt_dma_desc *vd; + unsigned long flags; + enum dma_status ret; + size_t bytes = 0; + + ret = dma_cookie_status(&c->vc.chan, cookie, state); + if (ret == DMA_COMPLETE || !state) + return ret; + + spin_lock_irqsave(&c->vc.lock, flags); + p = c->phy; + ret = c->status; + + /* + * If the cookie is on our issue queue, then the residue is + * its total size. + */ + vd = vchan_find_desc(&c->vc, cookie); + if (vd) { + bytes = container_of(vd, struct zx_dma_desc_sw, vd)->size; + } else if ((!p) || (!p->ds_run)) { + bytes = 0; + } else { + struct zx_dma_desc_sw *ds = p->ds_run; + u32 clli = 0, index = 0; + + bytes = 0; + clli = zx_dma_get_curr_lli(p); + index = (clli - ds->desc_hw_lli) / sizeof(struct zx_desc_hw); + for (; index < ds->desc_num; index++) { + bytes += ds->desc_hw[index].src_x; + /* end of lli */ + if (!ds->desc_hw[index].lli) + break; + } + } + spin_unlock_irqrestore(&c->vc.lock, flags); + dma_set_residue(state, bytes); + return ret; +} + +static void zx_dma_issue_pending(struct dma_chan *chan) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_dev *d = to_zx_dma(chan->device); + unsigned long flags; + int issue = 0; + + spin_lock_irqsave(&c->vc.lock, flags); + /* add request to vc->desc_issued */ + if (vchan_issue_pending(&c->vc)) { + spin_lock(&d->lock); + if (!c->phy && list_empty(&c->node)) { + /* if new channel, add chan_pending */ + list_add_tail(&c->node, &d->chan_pending); + issue = 1; + dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc); + } + spin_unlock(&d->lock); + } else { + dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc); + } + spin_unlock_irqrestore(&c->vc.lock, flags); + + if (issue) + zx_dma_task(d); +} + +static void zx_dma_fill_desc(struct zx_dma_desc_sw *ds, dma_addr_t dst, + dma_addr_t src, size_t len, u32 num, u32 ccfg) +{ + if ((num + 1) < ds->desc_num) + ds->desc_hw[num].lli = ds->desc_hw_lli + (num + 1) * + sizeof(struct zx_desc_hw); + ds->desc_hw[num].saddr = src; + ds->desc_hw[num].daddr = dst; + ds->desc_hw[num].src_x = len; + ds->desc_hw[num].ctr = ccfg; +} + +static struct zx_dma_desc_sw *zx_alloc_desc_resource(int num, + struct dma_chan *chan) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_desc_sw *ds; + struct zx_dma_dev *d = to_zx_dma(chan->device); + int lli_limit = LLI_BLOCK_SIZE / sizeof(struct zx_desc_hw); + + if (num > lli_limit) { + dev_dbg(chan->device->dev, "vch %p: sg num %d exceed max %d\n", + &c->vc, num, lli_limit); + return NULL; + } + + ds = kzalloc(sizeof(*ds), GFP_ATOMIC); + if (!ds) + return NULL; + + ds->desc_hw = dma_pool_alloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli); + if (!ds->desc_hw) { + dev_dbg(chan->device->dev, "vch %p: dma alloc fail\n", &c->vc); + kfree(ds); + return NULL; + } + memset(ds->desc_hw, sizeof(struct zx_desc_hw) * num, 0); + ds->desc_num = num; + return ds; +} + +static enum zx_dma_burst_width zx_dma_burst_width(enum dma_slave_buswidth width) +{ + switch (width) { + case DMA_SLAVE_BUSWIDTH_1_BYTE: + case DMA_SLAVE_BUSWIDTH_2_BYTES: + case DMA_SLAVE_BUSWIDTH_4_BYTES: + case DMA_SLAVE_BUSWIDTH_8_BYTES: + return ffs(width) - 1; + default: + return ZX_DMA_WIDTH_32BIT; + } +} + +static int zx_pre_config(struct zx_dma_chan *c, enum dma_transfer_direction dir) +{ + struct dma_slave_config *cfg = &c->slave_cfg; + enum zx_dma_burst_width src_width; + enum zx_dma_burst_width dst_width; + u32 maxburst = 0; + + switch (dir) { + case DMA_MEM_TO_MEM: + c->ccfg = ZX_CH_ENABLE | ZX_SOFT_REQ + | ZX_SRC_BURST_LEN(ZX_MAX_BURST_LEN - 1) + | ZX_SRC_BURST_WIDTH(ZX_DMA_WIDTH_32BIT) + | ZX_DST_BURST_WIDTH(ZX_DMA_WIDTH_32BIT); + break; + case DMA_MEM_TO_DEV: + c->dev_addr = cfg->dst_addr; + /* dst len is calculated from src width, len and dst width. + * We need make sure dst len not exceed MAX LEN. + */ + dst_width = zx_dma_burst_width(cfg->dst_addr_width); + maxburst = cfg->dst_maxburst * cfg->dst_addr_width + / DMA_SLAVE_BUSWIDTH_8_BYTES; + maxburst = maxburst < ZX_MAX_BURST_LEN ? + maxburst : ZX_MAX_BURST_LEN; + c->ccfg = ZX_DST_FIFO_MODE | ZX_CH_ENABLE + | ZX_SRC_BURST_LEN(maxburst - 1) + | ZX_SRC_BURST_WIDTH(ZX_DMA_WIDTH_64BIT) + | ZX_DST_BURST_WIDTH(dst_width); + break; + case DMA_DEV_TO_MEM: + c->dev_addr = cfg->src_addr; + src_width = zx_dma_burst_width(cfg->src_addr_width); + maxburst = cfg->src_maxburst; + maxburst = maxburst < ZX_MAX_BURST_LEN ? + maxburst : ZX_MAX_BURST_LEN; + c->ccfg = ZX_SRC_FIFO_MODE | ZX_CH_ENABLE + | ZX_SRC_BURST_LEN(maxburst - 1) + | ZX_SRC_BURST_WIDTH(src_width) + | ZX_DST_BURST_WIDTH(ZX_DMA_WIDTH_64BIT); + break; + default: + return -EINVAL; + } + return 0; +} + +static struct dma_async_tx_descriptor *zx_dma_prep_memcpy( + struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, + size_t len, unsigned long flags) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_desc_sw *ds; + size_t copy = 0; + int num = 0; + + if (!len) + return NULL; + + if (zx_pre_config(c, DMA_MEM_TO_MEM)) + return NULL; + + num = DIV_ROUND_UP(len, DMA_MAX_SIZE); + + ds = zx_alloc_desc_resource(num, chan); + if (!ds) + return NULL; + + ds->size = len; + num = 0; + + do { + copy = min_t(size_t, len, DMA_MAX_SIZE); + zx_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg); + + src += copy; + dst += copy; + len -= copy; + } while (len); + + ds->desc_hw[num - 1].lli = 0; /* end of link */ + ds->desc_hw[num - 1].ctr |= ZX_IRQ_ENABLE_ALL; + return vchan_tx_prep(&c->vc, &ds->vd, flags); +} + +static struct dma_async_tx_descriptor *zx_dma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, unsigned int sglen, + enum dma_transfer_direction dir, unsigned long flags, void *context) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_desc_sw *ds; + size_t len, avail, total = 0; + struct scatterlist *sg; + dma_addr_t addr, src = 0, dst = 0; + int num = sglen, i; + + if (!sgl) + return NULL; + + if (zx_pre_config(c, dir)) + return NULL; + + for_each_sg(sgl, sg, sglen, i) { + avail = sg_dma_len(sg); + if (avail > DMA_MAX_SIZE) + num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1; + } + + ds = zx_alloc_desc_resource(num, chan); + if (!ds) + return NULL; + + num = 0; + for_each_sg(sgl, sg, sglen, i) { + addr = sg_dma_address(sg); + avail = sg_dma_len(sg); + total += avail; + + do { + len = min_t(size_t, avail, DMA_MAX_SIZE); + + if (dir == DMA_MEM_TO_DEV) { + src = addr; + dst = c->dev_addr; + } else if (dir == DMA_DEV_TO_MEM) { + src = c->dev_addr; + dst = addr; + } + + zx_dma_fill_desc(ds, dst, src, len, num++, c->ccfg); + + addr += len; + avail -= len; + } while (avail); + } + + ds->desc_hw[num - 1].lli = 0; /* end of link */ + ds->desc_hw[num - 1].ctr |= ZX_IRQ_ENABLE_ALL; + ds->size = total; + return vchan_tx_prep(&c->vc, &ds->vd, flags); +} + +static int zx_dma_config(struct dma_chan *chan, + struct dma_slave_config *cfg) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + + if (!cfg) + return -EINVAL; + + memcpy(&c->slave_cfg, cfg, sizeof(*cfg)); + + return 0; +} + +static int zx_dma_terminate_all(struct dma_chan *chan) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_dev *d = to_zx_dma(chan->device); + struct zx_dma_phy *p = c->phy; + unsigned long flags; + LIST_HEAD(head); + + dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc); + + /* Prevent this channel being scheduled */ + spin_lock(&d->lock); + list_del_init(&c->node); + spin_unlock(&d->lock); + + /* Clear the tx descriptor lists */ + spin_lock_irqsave(&c->vc.lock, flags); + vchan_get_all_descriptors(&c->vc, &head); + if (p) { + /* vchan is assigned to a pchan - stop the channel */ + zx_dma_terminate_chan(p, d); + c->phy = NULL; + p->vchan = NULL; + p->ds_run = NULL; + p->ds_done = NULL; + } + spin_unlock_irqrestore(&c->vc.lock, flags); + vchan_dma_desc_free_list(&c->vc, &head); + + return 0; +} + +static void zx_dma_free_desc(struct virt_dma_desc *vd) +{ + struct zx_dma_desc_sw *ds = + container_of(vd, struct zx_dma_desc_sw, vd); + struct zx_dma_dev *d = to_zx_dma(vd->tx.chan->device); + + dma_pool_free(d->pool, ds->desc_hw, ds->desc_hw_lli); + kfree(ds); +} + +static const struct of_device_id zx6702_dma_dt_ids[] = { + { .compatible = "zte,zx296702-dma", }, + {} +}; +MODULE_DEVICE_TABLE(of, zx6702_dma_dt_ids); + +static struct dma_chan *zx_of_dma_simple_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct zx_dma_dev *d = ofdma->of_dma_data; + unsigned int request = dma_spec->args[0]; + struct dma_chan *chan; + struct zx_dma_chan *c; + + if (request > d->dma_requests) + return NULL; + + chan = dma_get_any_slave_channel(&d->slave); + if (!chan) { + dev_err(d->slave.dev, "get channel fail in %s.\n", __func__); + return NULL; + } + c = to_zx_chan(chan); + c->id = request; + dev_info(d->slave.dev, "zx_dma: pchan %u: alloc vchan %p\n", + c->id, &c->vc); + return chan; +} + +static int zx_dma_probe(struct platform_device *op) +{ + struct zx_dma_dev *d; + struct resource *iores; + int i, ret = 0, irq = 0; + + iores = platform_get_resource(op, IORESOURCE_MEM, 0); + if (!iores) + return -EINVAL; + + d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + d->base = devm_ioremap_resource(&op->dev, iores); + if (IS_ERR(d->base)) + return PTR_ERR(d->base); + + of_property_read_u32((&op->dev)->of_node, + "dma-channels", &d->dma_channels); + of_property_read_u32((&op->dev)->of_node, + "dma-requests", &d->dma_requests); + if (!d->dma_requests || !d->dma_channels) + return -EINVAL; + + d->clk = devm_clk_get(&op->dev, NULL); + if (IS_ERR(d->clk)) { + dev_err(&op->dev, "no dma clk\n"); + return PTR_ERR(d->clk); + } + + irq = platform_get_irq(op, 0); + ret = devm_request_irq(&op->dev, irq, zx_dma_int_handler, + 0, DRIVER_NAME, d); + if (ret) + return ret; + + /* A DMA memory pool for LLIs, align on 32-byte boundary */ + d->pool = dmam_pool_create(DRIVER_NAME, &op->dev, + LLI_BLOCK_SIZE, 32, 0); + if (!d->pool) + return -ENOMEM; + + /* init phy channel */ + d->phy = devm_kzalloc(&op->dev, + d->dma_channels * sizeof(struct zx_dma_phy), GFP_KERNEL); + if (!d->phy) + return -ENOMEM; + + for (i = 0; i < d->dma_channels; i++) { + struct zx_dma_phy *p = &d->phy[i]; + + p->idx = i; + p->base = d->base + i * 0x40; + } + + INIT_LIST_HEAD(&d->slave.channels); + dma_cap_set(DMA_SLAVE, d->slave.cap_mask); + dma_cap_set(DMA_MEMCPY, d->slave.cap_mask); + dma_cap_set(DMA_PRIVATE, d->slave.cap_mask); + d->slave.dev = &op->dev; + d->slave.device_free_chan_resources = zx_dma_free_chan_resources; + d->slave.device_tx_status = zx_dma_tx_status; + d->slave.device_prep_dma_memcpy = zx_dma_prep_memcpy; + d->slave.device_prep_slave_sg = zx_dma_prep_slave_sg; + d->slave.device_issue_pending = zx_dma_issue_pending; + d->slave.device_config = zx_dma_config; + d->slave.device_terminate_all = zx_dma_terminate_all; + d->slave.copy_align = DMA_ALIGN; + d->slave.src_addr_widths = ZX_DMA_BUSWIDTHS; + d->slave.dst_addr_widths = ZX_DMA_BUSWIDTHS; + d->slave.directions = BIT(DMA_MEM_TO_MEM) | BIT(DMA_MEM_TO_DEV) + | BIT(DMA_DEV_TO_MEM); + d->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; + + /* init virtual channel */ + d->chans = devm_kzalloc(&op->dev, + d->dma_requests * sizeof(struct zx_dma_chan), GFP_KERNEL); + if (!d->chans) + return -ENOMEM; + + for (i = 0; i < d->dma_requests; i++) { + struct zx_dma_chan *c = &d->chans[i]; + + c->status = DMA_IN_PROGRESS; + INIT_LIST_HEAD(&c->node); + c->vc.desc_free = zx_dma_free_desc; + vchan_init(&c->vc, &d->slave); + } + + /* Enable clock before accessing registers */ + ret = clk_prepare_enable(d->clk); + if (ret < 0) { + dev_err(&op->dev, "clk_prepare_enable failed: %d\n", ret); + goto zx_dma_out; + } + + zx_dma_init_state(d); + + spin_lock_init(&d->lock); + INIT_LIST_HEAD(&d->chan_pending); + platform_set_drvdata(op, d); + + ret = dma_async_device_register(&d->slave); + if (ret) + goto clk_dis; + + ret = of_dma_controller_register((&op->dev)->of_node, + zx_of_dma_simple_xlate, d); + if (ret) + goto of_dma_register_fail; + + dev_info(&op->dev, "initialized\n"); + return 0; + +of_dma_register_fail: + dma_async_device_unregister(&d->slave); +clk_dis: + clk_disable_unprepare(d->clk); +zx_dma_out: + return ret; +} + +static int zx_dma_remove(struct platform_device *op) +{ + struct zx_dma_chan *c, *cn; + struct zx_dma_dev *d = platform_get_drvdata(op); + + dma_async_device_unregister(&d->slave); + of_dma_controller_free((&op->dev)->of_node); + + list_for_each_entry_safe(c, cn, &d->slave.channels, + vc.chan.device_node) { + list_del(&c->vc.chan.device_node); + } + clk_disable_unprepare(d->clk); + dmam_pool_destroy(d->pool); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int zx_dma_suspend_dev(struct device *dev) +{ + struct zx_dma_dev *d = dev_get_drvdata(dev); + u32 stat = 0; + + stat = zx_dma_get_chan_stat(d); + if (stat) { + dev_warn(d->slave.dev, + "chan %d is running fail to suspend\n", stat); + return -1; + } + clk_disable_unprepare(d->clk); + return 0; +} + +static int zx_dma_resume_dev(struct device *dev) +{ + struct zx_dma_dev *d = dev_get_drvdata(dev); + int ret = 0; + + ret = clk_prepare_enable(d->clk); + if (ret < 0) { + dev_err(d->slave.dev, "clk_prepare_enable failed: %d\n", ret); + return ret; + } + zx_dma_init_state(d); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(zx_dma_pmops, zx_dma_suspend_dev, zx_dma_resume_dev); + +static struct platform_driver zx_pdma_driver = { + .driver = { + .name = DRIVER_NAME, + .pm = &zx_dma_pmops, + .of_match_table = zx6702_dma_dt_ids, + }, + .probe = zx_dma_probe, + .remove = zx_dma_remove, +}; + +module_platform_driver(zx_pdma_driver); + +MODULE_DESCRIPTION("ZTE ZX296702 DMA Driver"); +MODULE_AUTHOR("Jun Nie jun.nie@linaro.org"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From 9bde2823dcb97997456645f9b18f8c3468b727ca Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 18 May 2015 15:33:13 +0530 Subject: dmaengine: zxdma: explicitly free irq on device removal At device removal, tasklets are not disabled and irqs are still enabled, so free the irq explicitly on device removal Signed-off-by: Vinod Koul --- drivers/dma/zx296702_dma.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx296702_dma.c index c99f0d1ac88a..ec470bc74df8 100644 --- a/drivers/dma/zx296702_dma.c +++ b/drivers/dma/zx296702_dma.c @@ -127,6 +127,7 @@ struct zx_dma_dev { struct dma_pool *pool; u32 dma_channels; u32 dma_requests; + int irq; }; #define to_zx_dma(dmadev) container_of(dmadev, struct zx_dma_dev, slave) @@ -683,7 +684,7 @@ static int zx_dma_probe(struct platform_device *op) { struct zx_dma_dev *d; struct resource *iores; - int i, ret = 0, irq = 0; + int i, ret = 0; iores = platform_get_resource(op, IORESOURCE_MEM, 0); if (!iores) @@ -710,8 +711,8 @@ static int zx_dma_probe(struct platform_device *op) return PTR_ERR(d->clk); } - irq = platform_get_irq(op, 0); - ret = devm_request_irq(&op->dev, irq, zx_dma_int_handler, + d->irq = platform_get_irq(op, 0); + ret = devm_request_irq(&op->dev, d->irq, zx_dma_int_handler, 0, DRIVER_NAME, d); if (ret) return ret; @@ -807,6 +808,9 @@ static int zx_dma_remove(struct platform_device *op) struct zx_dma_chan *c, *cn; struct zx_dma_dev *d = platform_get_drvdata(op); + /* explictly free the irq */ + devm_free_irq(&op->dev, d->irq, d); + dma_async_device_unregister(&d->slave); of_dma_controller_free((&op->dev)->of_node); -- cgit v1.3-6-gb490 From 72858602e167ea2d7487337bac279beec7a99c84 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Tue, 7 Jul 2015 22:22:15 +0200 Subject: gpiolib: remove unneeded assignation ret is assigned value from of_property_read_string_index but is overwritten before being used so remove it. Also fix coverity CID 1309759 Reported-by: coverity (CID 1309759) Signed-off-by: Laurent Navet Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index fd2db4b3a709..1e36ec5e2e0c 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -362,7 +362,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) if (pinspec.args[2]) { if (group_names) { - ret = of_property_read_string_index(np, + of_property_read_string_index(np, group_names_propname, index, &name); if (strlen(name)) { -- cgit v1.3-6-gb490 From 2660801f7323b84fc2ad46449a5d1f331266d9f7 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 16 Jul 2015 15:51:01 +0200 Subject: drm/atomic: Only update crtc->x/y if it's part of the state, v2. Universal planes may not be assigned to the current crtc, so only update crtc->x/y when the primary is part of the state and bound to the current crtc. Changes since v1: - Add the crtc check. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0898afbc9e23..f94cc371742e 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -665,10 +665,16 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev, /* set legacy state in the crtc structure */ for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { + struct drm_plane *primary = crtc->primary; + crtc->mode = crtc->state->mode; crtc->enabled = crtc->state->enable; - crtc->x = crtc->primary->state->src_x >> 16; - crtc->y = crtc->primary->state->src_y >> 16; + + if (drm_atomic_get_existing_plane_state(old_state, primary) && + primary->state->crtc == crtc) { + crtc->x = primary->state->src_x >> 16; + crtc->y = primary->state->src_y >> 16; + } if (crtc->state->enable) drm_calc_timestamping_constants(crtc, -- cgit v1.3-6-gb490 From 6f14cc18f8dd5d1b05ae6583361e08222381ca84 Mon Sep 17 00:00:00 2001 From: Benjamin Romer Date: Thu, 16 Jul 2015 12:40:48 -0400 Subject: staging: unisys: fix copyright statements The copyright statements in the drivers need to be correct and consistent; this patch fixes the year for all of them, and makes the statement text cover just the GPL V2. Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorbus/controlvmchannel.h | 9 ++++----- drivers/staging/unisys/visorbus/controlvmcompletionstatus.h | 9 ++++----- drivers/staging/unisys/visorbus/iovmcall_gnuc.h | 9 ++++----- drivers/staging/unisys/visorbus/periodic_work.c | 9 ++++----- drivers/staging/unisys/visorbus/vbuschannel.h | 9 ++++----- drivers/staging/unisys/visorbus/vbusdeviceinfo.h | 9 ++++----- drivers/staging/unisys/visorbus/visorbus_main.c | 9 ++++----- drivers/staging/unisys/visorbus/visorbus_private.h | 9 ++++----- drivers/staging/unisys/visorbus/visorchannel.c | 9 ++++----- drivers/staging/unisys/visorbus/visorchipset.c | 9 ++++----- drivers/staging/unisys/visorbus/vmcallinterface.h | 9 ++++----- drivers/staging/unisys/visornic/visornic_main.c | 7 +++---- 12 files changed, 47 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorbus/controlvmchannel.h b/drivers/staging/unisys/visorbus/controlvmchannel.h index a50d9cf4bed7..ec25366b127c 100644 --- a/drivers/staging/unisys/visorbus/controlvmchannel.h +++ b/drivers/staging/unisys/visorbus/controlvmchannel.h @@ -1,10 +1,9 @@ -/* Copyright (C) 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h b/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h index f74f5d8c2820..3c97ebac4f32 100644 --- a/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h +++ b/drivers/staging/unisys/visorbus/controlvmcompletionstatus.h @@ -1,12 +1,11 @@ /* controlvmcompletionstatus.c * - * Copyright (C) 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/staging/unisys/visorbus/iovmcall_gnuc.h b/drivers/staging/unisys/visorbus/iovmcall_gnuc.h index 57dd93e0cc83..b08b6ecc8d31 100644 --- a/drivers/staging/unisys/visorbus/iovmcall_gnuc.h +++ b/drivers/staging/unisys/visorbus/iovmcall_gnuc.h @@ -1,10 +1,9 @@ -/* Copyright (C) 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/staging/unisys/visorbus/periodic_work.c b/drivers/staging/unisys/visorbus/periodic_work.c index 5e56088cf855..a3631c3591f6 100644 --- a/drivers/staging/unisys/visorbus/periodic_work.c +++ b/drivers/staging/unisys/visorbus/periodic_work.c @@ -1,12 +1,11 @@ /* periodic_work.c * - * Copyright (C) 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/staging/unisys/visorbus/vbuschannel.h b/drivers/staging/unisys/visorbus/vbuschannel.h index 5ed83a3f1428..80e64477e547 100644 --- a/drivers/staging/unisys/visorbus/vbuschannel.h +++ b/drivers/staging/unisys/visorbus/vbuschannel.h @@ -1,10 +1,9 @@ -/* Copyright (C) 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/staging/unisys/visorbus/vbusdeviceinfo.h b/drivers/staging/unisys/visorbus/vbusdeviceinfo.h index 9b6d3e69355c..f59fd8a523c4 100644 --- a/drivers/staging/unisys/visorbus/vbusdeviceinfo.h +++ b/drivers/staging/unisys/visorbus/vbusdeviceinfo.h @@ -1,10 +1,9 @@ -/* Copyright (C) 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/staging/unisys/visorbus/visorbus_main.c b/drivers/staging/unisys/visorbus/visorbus_main.c index 3e33e3629682..403c13b7864b 100644 --- a/drivers/staging/unisys/visorbus/visorbus_main.c +++ b/drivers/staging/unisys/visorbus/visorbus_main.c @@ -1,12 +1,11 @@ /* visorbus_main.c * - * Copyright � 2010 - 2013 UNISYS CORPORATION + * Copyright � 2010 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/staging/unisys/visorbus/visorbus_private.h b/drivers/staging/unisys/visorbus/visorbus_private.h index 2f12483e38ab..39edd2018453 100644 --- a/drivers/staging/unisys/visorbus/visorbus_private.h +++ b/drivers/staging/unisys/visorbus/visorbus_private.h @@ -1,12 +1,11 @@ /* visorchipset.h * - * Copyright (C) 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/staging/unisys/visorbus/visorchannel.c b/drivers/staging/unisys/visorbus/visorchannel.c index c6452c3908e6..242246492b7a 100644 --- a/drivers/staging/unisys/visorbus/visorchannel.c +++ b/drivers/staging/unisys/visorbus/visorchannel.c @@ -1,12 +1,11 @@ /* visorchannel_funcs.c * - * Copyright (C) 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/staging/unisys/visorbus/visorchipset.c b/drivers/staging/unisys/visorbus/visorchipset.c index fb08f9523ab3..4b76cb441ed4 100644 --- a/drivers/staging/unisys/visorbus/visorchipset.c +++ b/drivers/staging/unisys/visorbus/visorchipset.c @@ -1,12 +1,11 @@ /* visorchipset_main.c * - * Copyright (C) 2010 - 2013 UNISYS CORPORATION + * Copyright (C) 2010 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/staging/unisys/visorbus/vmcallinterface.h b/drivers/staging/unisys/visorbus/vmcallinterface.h index 7a53df00726a..7abd27a618f8 100644 --- a/drivers/staging/unisys/visorbus/vmcallinterface.h +++ b/drivers/staging/unisys/visorbus/vmcallinterface.h @@ -1,10 +1,9 @@ -/* Copyright (C) 2010 - 2013 UNISYS CORPORATION +/* Copyright (C) 2010 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 9350473a732b..c28a34767552 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1,10 +1,9 @@ /* Copyright (c) 2012 - 2015 UNISYS 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; either version 2 of the License, or (at - * your option) any later version. + * 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 that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of -- cgit v1.3-6-gb490 From 4bdc190a929c6f99732a9a0ff03dba7b0137d4bd Mon Sep 17 00:00:00 2001 From: Vasiliy Korchagin Date: Wed, 15 Jul 2015 00:40:40 +0000 Subject: staging: lustre: obdclass: simplify class_uuid_unparse This patch simplifies uuid unparse logic by using sprintf "%pU" extension. And eliminates the code with a coding style error: ERROR: Macros with complex values should be enclosed in parentheses +#define CONSUME(val, ptr) (val) = consume(sizeof(val), (ptr)) Signed-off-by: Vasiliy Korchagin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/uuid.c | 34 +-------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/uuid.c b/drivers/staging/lustre/lustre/obdclass/uuid.c index ff0a01bcf8da..b0b0157a6334 100644 --- a/drivers/staging/lustre/lustre/obdclass/uuid.c +++ b/drivers/staging/lustre/lustre/obdclass/uuid.c @@ -43,40 +43,8 @@ #include "../include/obd_support.h" #include "../include/obd_class.h" - -static inline __u32 consume(int nob, __u8 **ptr) -{ - __u32 value; - - LASSERT(nob <= sizeof(value)); - - for (value = 0; nob > 0; --nob) - value = (value << 8) | *((*ptr)++); - return value; -} - -#define CONSUME(val, ptr) (val) = consume(sizeof(val), (ptr)) - -static void uuid_unpack(class_uuid_t in, __u16 *uu, int nr) -{ - __u8 *ptr = in; - - LASSERT(nr * sizeof(*uu) == sizeof(class_uuid_t)); - - while (nr-- > 0) - CONSUME(uu[nr], &ptr); -} - void class_uuid_unparse(class_uuid_t uu, struct obd_uuid *out) { - /* uu as an array of __u16's */ - __u16 uuid[sizeof(class_uuid_t) / sizeof(__u16)]; - - CLASSERT(ARRAY_SIZE(uuid) == 8); - - uuid_unpack(uu, uuid, ARRAY_SIZE(uuid)); - sprintf(out->uuid, "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7]); + sprintf(out->uuid, "%pU", uu); } EXPORT_SYMBOL(class_uuid_unparse); -- cgit v1.3-6-gb490 From 9c7e397c98d646a3a23ffd304def1750be916803 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Wed, 15 Jul 2015 12:21:16 -0400 Subject: staging/lustre/ldlm: Unregister ldlm namespace from sysfs on free ldlm_namespace_sysfs_unregister needs to be called ldlm_namespace_free_post so that we don't have this dangling object there after the namespace has disappeared. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ldlm/ldlm_resource.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c index cdb63665a113..4bb3173bcd5f 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c @@ -939,6 +939,7 @@ void ldlm_namespace_free_post(struct ldlm_namespace *ns) ldlm_pool_fini(&ns->ns_pool); ldlm_namespace_debugfs_unregister(ns); + ldlm_namespace_sysfs_unregister(ns); cfs_hash_putref(ns->ns_rs_hash); /* Namespace \a ns should be not on list at this time, otherwise * this will cause issues related to using freed \a ns in poold -- cgit v1.3-6-gb490 From 315c928ba99af23dd25ac664b7c02828cf047f19 Mon Sep 17 00:00:00 2001 From: Pedro Marzo Perez Date: Thu, 16 Jul 2015 20:50:00 +0200 Subject: Staging: lustre: make obd_device_cachep static Variable obd_device_cachep is only used inside the file it is declared, so it is better set as static Signed-off-by: Pedro Marzo Perez Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/genops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c index d36697d2c47f..0ca730948f7a 100644 --- a/drivers/staging/lustre/lustre/obdclass/genops.c +++ b/drivers/staging/lustre/lustre/obdclass/genops.c @@ -45,7 +45,7 @@ spinlock_t obd_types_lock; -struct kmem_cache *obd_device_cachep; +static struct kmem_cache *obd_device_cachep; struct kmem_cache *obdo_cachep; EXPORT_SYMBOL(obdo_cachep); static struct kmem_cache *import_cachep; -- cgit v1.3-6-gb490 From c8011d90c68d10d67b797e0704c16697bba683a1 Mon Sep 17 00:00:00 2001 From: CHANG FU CHIAO Date: Wed, 15 Jul 2015 15:32:21 +0800 Subject: staging: ft1000: ft1000-usb: remove unnecessary out of memory warning fixes "Possible unnecessary 'out of memory' message" Signed-off-by: CHANG FU CHIAO Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index e6b5976a09e3..96209703ba25 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -842,7 +842,6 @@ static int ft1000_copy_up_pkt(struct urb *urb) skb = dev_alloc_skb(len + 12 + 2); if (skb == NULL) { - pr_debug("No Network buffers available\n"); info->stats.rx_errors++; ft1000_submit_rx_urb(info); return -1; -- cgit v1.3-6-gb490 From 42748bc905d57aa96a3b8ef50261bcf95890bef7 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Wed, 15 Jul 2015 00:44:53 +0200 Subject: staging: rtl8188eu: remove unused {en,dis}able_interrupt rtw_hal_enable_interrupt() and rtw_hal_disable_interrupt() are never referenced, so remove them. They used to be the only place where the enable_interrupt() and disable_interrupt() callbacks were called, and the function pointer is never set, so get rid of the function pointer as well. Signed-off-by: Luca Ceresoli Cc: Greg Kroah-Hartman Cc: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/hal/hal_intf.c | 16 ---------------- drivers/staging/rtl8188eu/include/hal_intf.h | 5 ----- 2 files changed, 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/hal/hal_intf.c b/drivers/staging/rtl8188eu/hal/hal_intf.c index 5edb5c41c8e7..fecd2ef11b85 100644 --- a/drivers/staging/rtl8188eu/hal/hal_intf.c +++ b/drivers/staging/rtl8188eu/hal/hal_intf.c @@ -156,22 +156,6 @@ void rtw_hal_set_odm_var(struct adapter *adapt, val1, set); } -void rtw_hal_enable_interrupt(struct adapter *adapt) -{ - if (adapt->HalFunc.enable_interrupt) - adapt->HalFunc.enable_interrupt(adapt); - else - DBG_88E("%s: HalFunc.enable_interrupt is NULL!\n", __func__); -} - -void rtw_hal_disable_interrupt(struct adapter *adapt) -{ - if (adapt->HalFunc.disable_interrupt) - adapt->HalFunc.disable_interrupt(adapt); - else - DBG_88E("%s: HalFunc.disable_interrupt is NULL!\n", __func__); -} - u32 rtw_hal_inirp_init(struct adapter *adapt) { u32 rst = _FAIL; diff --git a/drivers/staging/rtl8188eu/include/hal_intf.h b/drivers/staging/rtl8188eu/include/hal_intf.h index 3b476d80f64d..d85bc441d98e 100644 --- a/drivers/staging/rtl8188eu/include/hal_intf.h +++ b/drivers/staging/rtl8188eu/include/hal_intf.h @@ -171,8 +171,6 @@ struct hal_ops { void (*read_adapter_info)(struct adapter *padapter); - void (*enable_interrupt)(struct adapter *padapter); - void (*disable_interrupt)(struct adapter *padapter); s32 (*interrupt_handler)(struct adapter *padapter); void (*set_bwmode_handler)(struct adapter *padapter, @@ -276,9 +274,6 @@ void rtw_hal_set_odm_var(struct adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet); -void rtw_hal_enable_interrupt(struct adapter *padapter); -void rtw_hal_disable_interrupt(struct adapter *padapter); - u32 rtw_hal_inirp_init(struct adapter *padapter); u32 rtw_hal_inirp_deinit(struct adapter *padapter); -- cgit v1.3-6-gb490 From f83113d3e6f2cef66890a90d01c5347ece4ecd97 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Wed, 15 Jul 2015 00:44:54 +0200 Subject: staging: rtl8188eu: remove unused rtw_hal_set_def_var rtw_hal_set_def_var() is never referenced, so remove it. It used to be the only place where the SetHalDefVarHandler callback was called, so get rid of the function pointer as well. Also remove the callback itself, SetHalDefVar8188EUsb(), which was not called anywhere else. Signed-off-by: Luca Ceresoli Cc: Greg Kroah-Hartman Cc: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/hal/hal_intf.c | 8 ---- drivers/staging/rtl8188eu/hal/usb_halinit.c | 70 ---------------------------- drivers/staging/rtl8188eu/include/hal_intf.h | 5 -- 3 files changed, 83 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/hal/hal_intf.c b/drivers/staging/rtl8188eu/hal/hal_intf.c index fecd2ef11b85..5af574005035 100644 --- a/drivers/staging/rtl8188eu/hal/hal_intf.c +++ b/drivers/staging/rtl8188eu/hal/hal_intf.c @@ -131,14 +131,6 @@ void rtw_hal_get_hwreg(struct adapter *adapt, u8 variable, u8 *val) adapt->HalFunc.GetHwRegHandler(adapt, variable, val); } -u8 rtw_hal_set_def_var(struct adapter *adapt, enum hal_def_variable var, - void *val) -{ - if (adapt->HalFunc.SetHalDefVarHandler) - return adapt->HalFunc.SetHalDefVarHandler(adapt, var, val); - return _FAIL; -} - u8 rtw_hal_get_def_var(struct adapter *adapt, enum hal_def_variable var, void *val) { diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c index ffcca6b03fe2..6dc0869924ec 100644 --- a/drivers/staging/rtl8188eu/hal/usb_halinit.c +++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c @@ -1961,75 +1961,6 @@ GetHalDefVar8188EUsb( return bResult; } -/* */ -/* Description: */ -/* Change default setting of specified variable. */ -/* */ -static u8 SetHalDefVar8188EUsb(struct adapter *Adapter, enum hal_def_variable eVariable, void *pValue) -{ - struct hal_data_8188e *haldata = GET_HAL_DATA(Adapter); - u8 bResult = _SUCCESS; - - switch (eVariable) { - case HAL_DEF_DBG_DM_FUNC: - { - u8 dm_func = *((u8 *)pValue); - struct odm_dm_struct *podmpriv = &haldata->odmpriv; - - if (dm_func == 0) { /* disable all dynamic func */ - podmpriv->SupportAbility = DYNAMIC_FUNC_DISABLE; - DBG_88E("==> Disable all dynamic function...\n"); - } else if (dm_func == 1) {/* disable DIG */ - podmpriv->SupportAbility &= (~DYNAMIC_BB_DIG); - DBG_88E("==> Disable DIG...\n"); - } else if (dm_func == 2) {/* disable High power */ - podmpriv->SupportAbility &= (~DYNAMIC_BB_DYNAMIC_TXPWR); - } else if (dm_func == 3) {/* disable tx power tracking */ - podmpriv->SupportAbility &= (~DYNAMIC_RF_CALIBRATION); - DBG_88E("==> Disable tx power tracking...\n"); - } else if (dm_func == 5) {/* disable antenna diversity */ - podmpriv->SupportAbility &= (~DYNAMIC_BB_ANT_DIV); - } else if (dm_func == 6) {/* turn on all dynamic func */ - if (!(podmpriv->SupportAbility & DYNAMIC_BB_DIG)) { - struct rtw_dig *pDigTable = &podmpriv->DM_DigTable; - pDigTable->CurIGValue = usb_read8(Adapter, 0xc50); - } - podmpriv->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE; - DBG_88E("==> Turn on all dynamic function...\n"); - } - } - break; - case HAL_DEF_DBG_DUMP_RXPKT: - haldata->bDumpRxPkt = *((u8 *)pValue); - break; - case HAL_DEF_DBG_DUMP_TXPKT: - haldata->bDumpTxPkt = *((u8 *)pValue); - break; - case HW_DEF_FA_CNT_DUMP: - { - u8 bRSSIDump = *((u8 *)pValue); - struct odm_dm_struct *dm_ocm = &(haldata->odmpriv); - if (bRSSIDump) - dm_ocm->DebugComponents = ODM_COMP_DIG|ODM_COMP_FA_CNT; - else - dm_ocm->DebugComponents = 0; - } - break; - case HW_DEF_ODM_DBG_FLAG: - { - u64 DebugComponents = *((u64 *)pValue); - struct odm_dm_struct *dm_ocm = &(haldata->odmpriv); - dm_ocm->DebugComponents = DebugComponents; - } - break; - default: - bResult = _FAIL; - break; - } - - return bResult; -} - static void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_level) { u8 init_rate = 0; @@ -2200,7 +2131,6 @@ void rtl8188eu_set_hal_ops(struct adapter *adapt) halfunc->SetHwRegHandler = &SetHwReg8188EU; halfunc->GetHwRegHandler = &GetHwReg8188EU; halfunc->GetHalDefVarHandler = &GetHalDefVar8188EUsb; - halfunc->SetHalDefVarHandler = &SetHalDefVar8188EUsb; halfunc->UpdateRAMaskHandler = &UpdateHalRAMask8188EUsb; halfunc->SetBeaconRelatedRegistersHandler = &SetBeaconRelatedRegisters8188EUsb; diff --git a/drivers/staging/rtl8188eu/include/hal_intf.h b/drivers/staging/rtl8188eu/include/hal_intf.h index d85bc441d98e..bf894ce8eab1 100644 --- a/drivers/staging/rtl8188eu/include/hal_intf.h +++ b/drivers/staging/rtl8188eu/include/hal_intf.h @@ -188,9 +188,6 @@ struct hal_ops { u8 (*GetHalDefVarHandler)(struct adapter *padapter, enum hal_def_variable eVariable, void *pValue); - u8 (*SetHalDefVarHandler)(struct adapter *padapter, - enum hal_def_variable eVariable, - void *pValue); void (*SetHalODMVarHandler)(struct adapter *padapter, enum hal_odm_variable eVariable, @@ -265,8 +262,6 @@ void rtw_hal_chip_configure(struct adapter *padapter); void rtw_hal_read_chip_info(struct adapter *padapter); void rtw_hal_read_chip_version(struct adapter *padapter); -u8 rtw_hal_set_def_var(struct adapter *padapter, - enum hal_def_variable eVariable, void *pValue); u8 rtw_hal_get_def_var(struct adapter *padapter, enum hal_def_variable eVariable, void *pValue); -- cgit v1.3-6-gb490 From 9431fda3ff9193249ee7bc7731bb74e9f51f6f36 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Wed, 15 Jul 2015 00:44:55 +0200 Subject: staging: rtl8188eu: remove unused rtw_hal_write_rfreg rtw_hal_write_rfreg() is never referenced, so remove it. It used to be the only place where the write_rfreg callback was called, so get rid of the function pointer as well. Signed-off-by: Luca Ceresoli Cc: Greg Kroah-Hartman Cc: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/hal/hal_intf.c | 8 -------- drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c | 1 - drivers/staging/rtl8188eu/include/hal_intf.h | 6 ------ 3 files changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/hal/hal_intf.c b/drivers/staging/rtl8188eu/hal/hal_intf.c index 5af574005035..85c17ef942f3 100644 --- a/drivers/staging/rtl8188eu/hal/hal_intf.c +++ b/drivers/staging/rtl8188eu/hal/hal_intf.c @@ -245,14 +245,6 @@ u32 rtw_hal_read_rfreg(struct adapter *adapt, enum rf_radio_path rfpath, return data; } -void rtw_hal_write_rfreg(struct adapter *adapt, enum rf_radio_path rfpath, - u32 regaddr, u32 bitmask, u32 data) -{ - if (adapt->HalFunc.write_rfreg) - adapt->HalFunc.write_rfreg(adapt, rfpath, regaddr, - bitmask, data); -} - void rtw_hal_set_bwmode(struct adapter *adapt, enum ht_channel_width bandwidth, u8 offset) { diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c index b05da9d6b693..a6295ca6a73e 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c @@ -208,7 +208,6 @@ void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc) pHalFunc->AntDivBeforeLinkHandler = &AntDivBeforeLink8188E; pHalFunc->AntDivCompareHandler = &AntDivCompare8188E; pHalFunc->read_rfreg = &phy_query_rf_reg; - pHalFunc->write_rfreg = &phy_set_rf_reg; pHalFunc->sreset_init_value = &sreset_init_value; pHalFunc->sreset_get_wifi_status = &sreset_get_wifi_status; diff --git a/drivers/staging/rtl8188eu/include/hal_intf.h b/drivers/staging/rtl8188eu/include/hal_intf.h index bf894ce8eab1..e73c6341248e 100644 --- a/drivers/staging/rtl8188eu/include/hal_intf.h +++ b/drivers/staging/rtl8188eu/include/hal_intf.h @@ -211,9 +211,6 @@ struct hal_ops { u32 (*read_rfreg)(struct adapter *padapter, enum rf_radio_path eRFPath, u32 RegAddr, u32 BitMask); - void (*write_rfreg)(struct adapter *padapter, - enum rf_radio_path eRFPath, u32 RegAddr, - u32 BitMask, u32 Data); void (*sreset_init_value)(struct adapter *padapter); u8 (*sreset_get_wifi_status)(struct adapter *padapter); @@ -290,9 +287,6 @@ void rtw_hal_bcn_related_reg_setting(struct adapter *padapter); u32 rtw_hal_read_rfreg(struct adapter *padapter, enum rf_radio_path eRFPath, u32 RegAddr, u32 BitMask); -void rtw_hal_write_rfreg(struct adapter *padapter, - enum rf_radio_path eRFPath, u32 RegAddr, - u32 BitMask, u32 Data); void rtw_hal_set_bwmode(struct adapter *padapter, enum ht_channel_width Bandwidth, u8 Offset); -- cgit v1.3-6-gb490 From 87bf79298036a47ab158ae7e335cc7f8b0df4e9c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 15 Jul 2015 13:59:45 +0530 Subject: staging: sm7xxfb: define new macros Define and use some new macros to work with different situations based on little-endian and big-endian. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm7xxfb/sm7xx.h | 19 ++++++++++++++++ drivers/staging/sm7xxfb/sm7xxfb.c | 48 ++++++++------------------------------- 2 files changed, 29 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm7xxfb/sm7xx.h b/drivers/staging/sm7xxfb/sm7xx.h index 31a21bd85dae..aad1cc4be34a 100644 --- a/drivers/staging/sm7xxfb/sm7xx.h +++ b/drivers/staging/sm7xxfb/sm7xx.h @@ -95,3 +95,22 @@ struct modeinit { unsigned char init_cr30_cr4d[SIZE_CR30_CR4D]; unsigned char init_cr90_cra7[SIZE_CR90_CRA7]; }; + +#ifdef __BIG_ENDIAN +#define pal_rgb(r, g, b, val) (((r & 0xf800) >> 8) | \ + ((g & 0xe000) >> 13) | \ + ((g & 0x1c00) << 3) | \ + ((b & 0xf800) >> 3)) +#define big_addr 0x800000 +#define mmio_addr 0x00800000 +#define seqw17() smtc_seqw(0x17, 0x30) +#define big_pixel_depth(p, d) {if (p == 24) {p = 32; d = 32; } } +#define big_swap(p) ((p & 0xff00ff00 >> 8) | (p & 0x00ff00ff << 8)) +#else +#define pal_rgb(r, g, b, val) val +#define big_addr 0 +#define mmio_addr 0x00c00000 +#define seqw17() do { } while (0) +#define big_pixel_depth(p, d) do { } while (0) +#define big_swap(p) p +#endif diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c index 4dc9d5f32517..106465c91997 100644 --- a/drivers/staging/sm7xxfb/sm7xxfb.c +++ b/drivers/staging/sm7xxfb/sm7xxfb.c @@ -923,25 +923,14 @@ static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green, val = chan_to_field(red, &sfb->fb->var.red); val |= chan_to_field(green, &sfb->fb->var.green); val |= chan_to_field(blue, &sfb->fb->var.blue); -#ifdef __BIG_ENDIAN - pal[regno] = ((red & 0xf800) >> 8) | - ((green & 0xe000) >> 13) | - ((green & 0x1c00) << 3) | - ((blue & 0xf800) >> 3); -#else - pal[regno] = val; -#endif + pal[regno] = pal_rgb(red, green, blue, val); } else { u32 *pal = sfb->fb->pseudo_palette; val = chan_to_field(red, &sfb->fb->var.red); val |= chan_to_field(green, &sfb->fb->var.green); val |= chan_to_field(blue, &sfb->fb->var.blue); -#ifdef __BIG_ENDIAN - val = (val & 0xff00ff00 >> 8) | - (val & 0x00ff00ff << 8); -#endif - pal[regno] = val; + pal[regno] = big_swap(val); } break; @@ -1002,8 +991,7 @@ static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, dst = buffer; for (i = c >> 2; i--;) { *dst = fb_readl(src++); - *dst = (*dst & 0xff00ff00 >> 8) | - (*dst & 0x00ff00ff << 8); + *dst = big_swap(*dst); dst++; } if (c & 3) { @@ -1091,8 +1079,7 @@ static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf, } for (i = c >> 2; i--;) { - fb_writel((*src & 0xff00ff00 >> 8) | - (*src & 0x00ff00ff << 8), dst++); + fb_writel(big_swap(*src), dst++); src++; } if (c & 3) { @@ -1341,10 +1328,8 @@ static int smtc_map_smem(struct smtcfb_info *sfb, { sfb->fb->fix.smem_start = pci_resource_start(pdev, 0); -#ifdef __BIG_ENDIAN if (sfb->fb->var.bits_per_pixel == 32) - sfb->fb->fix.smem_start += 0x800000; -#endif + sfb->fb->fix.smem_start += big_addr; sfb->fb->fix.smem_len = smem_len; @@ -1437,10 +1422,7 @@ static int smtcfb_pci_probe(struct pci_dev *pdev, sfb->fb->var.bits_per_pixel = SCREEN_BPP; } -#ifdef __BIG_ENDIAN - if (sfb->fb->var.bits_per_pixel == 24) - sfb->fb->var.bits_per_pixel = (smtc_scr_info.lfb_depth = 32); -#endif + big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth); /* Map address and memory detection */ mmio_base = pci_resource_start(pdev, 0); pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); @@ -1451,11 +1433,7 @@ static int smtcfb_pci_probe(struct pci_dev *pdev, sfb->fb->fix.mmio_start = mmio_base + 0x00400000; sfb->fb->fix.mmio_len = 0x00400000; smem_size = SM712_VIDEOMEMORYSIZE; -#ifdef __BIG_ENDIAN - sfb->lfb = ioremap(mmio_base, 0x00c00000); -#else - sfb->lfb = ioremap(mmio_base, 0x00800000); -#endif + sfb->lfb = ioremap(mmio_base, mmio_addr); if (!sfb->lfb) { dev_err(&pdev->dev, "%s: unable to map memory mapped IO!\n", @@ -1468,12 +1446,10 @@ static int smtcfb_pci_probe(struct pci_dev *pdev, sfb->lfb + 0x00700000); sfb->dp_regs = sfb->lfb + 0x00408000; sfb->vp_regs = sfb->lfb + 0x0040c000; -#ifdef __BIG_ENDIAN if (sfb->fb->var.bits_per_pixel == 32) { - sfb->lfb += 0x800000; + sfb->lfb += big_addr; dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb); } -#endif /* set MCLK = 14.31818 * (0x16 / 0x2) */ smtc_seqw(0x6a, 0x16); @@ -1482,10 +1458,8 @@ static int smtcfb_pci_probe(struct pci_dev *pdev, /* enable PCI burst */ smtc_seqw(0x17, 0x20); /* enable word swap */ -#ifdef __BIG_ENDIAN if (sfb->fb->var.bits_per_pixel == 32) - smtc_seqw(0x17, 0x30); -#endif + seqw17(); break; case 0x720: sfb->fb->fix.mmio_start = mmio_base; @@ -1617,10 +1591,8 @@ static int smtcfb_pci_resume(struct device *device) smtc_seqw(0x62, 0x3e); /* enable PCI burst */ smtc_seqw(0x17, 0x20); -#ifdef __BIG_ENDIAN if (sfb->fb->var.bits_per_pixel == 32) - smtc_seqw(0x17, 0x30); -#endif + seqw17(); break; case 0x720: smtc_seqw(0x62, 0xff); -- cgit v1.3-6-gb490 From 613a7c5e0f2b216e62b7dfaa92c54959319bed42 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 15 Jul 2015 13:59:46 +0530 Subject: staging: sm7xxfb: usr fb_read and fb_write Now since the Big-Endian and Little-Endian based calculations are moved into a macro we can make fb_read() and fb_write() common for both Little-Endian and Big-Endian. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm7xxfb/sm7xxfb.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c index 106465c91997..07c2199c9ac7 100644 --- a/drivers/staging/sm7xxfb/sm7xxfb.c +++ b/drivers/staging/sm7xxfb/sm7xxfb.c @@ -946,7 +946,6 @@ static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } -#ifdef __BIG_ENDIAN static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t count, loff_t *ppos) { @@ -1107,7 +1106,6 @@ static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf, return (cnt) ? cnt : err; } -#endif /* ! __BIG_ENDIAN */ static void sm7xx_set_timing(struct smtcfb_info *sfb) { @@ -1303,10 +1301,8 @@ static struct fb_ops smtcfb_ops = { .fb_fillrect = cfb_fillrect, .fb_imageblit = cfb_imageblit, .fb_copyarea = cfb_copyarea, -#ifdef __BIG_ENDIAN .fb_read = smtcfb_read, .fb_write = smtcfb_write, -#endif }; /* -- cgit v1.3-6-gb490 From 48028c61e45acf644aaaa47db475974829fc64dd Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 16 Jul 2015 16:58:07 +0530 Subject: staging: rtl8188eu: remove unused function The inline function rtw_set_ips_deny() was only defined but was never used. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_pwrctrl.c | 6 ------ drivers/staging/rtl8188eu/include/rtw_pwrctrl.h | 1 - 2 files changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c index ec0a8a4cdc6e..a2b54de21ed7 100644 --- a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c @@ -549,12 +549,6 @@ void rtw_init_pwrctrl_priv(struct adapter *padapter) (unsigned long)padapter); } -inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms) -{ - struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; - pwrpriv->ips_deny_time = jiffies + msecs_to_jiffies(ms); -} - /* * rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend * @adapter: pointer to struct adapter structure diff --git a/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h b/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h index aa1fd87c47fb..a493d4c37ef1 100644 --- a/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h +++ b/drivers/staging/rtl8188eu/include/rtw_pwrctrl.h @@ -257,7 +257,6 @@ s32 LPS_RF_ON_check(struct adapter *adapter, u32 delay_ms); void LPS_Enter(struct adapter *adapter); void LPS_Leave(struct adapter *adapter); -void rtw_set_ips_deny(struct adapter *adapter, u32 ms); int _rtw_pwr_wakeup(struct adapter *adapter, u32 ips_defer_ms, const char *caller); #define rtw_pwr_wakeup(adapter) \ -- cgit v1.3-6-gb490 From 277394198413fc46e81767827533e5ab8ef167af Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 16 Jul 2015 16:58:08 +0530 Subject: staging: rtl8188eu: remove redundant NULL check The check for pstat and pdvobjpriv is not required here as we have already checked for them before. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_mlme_ext.c | 2 +- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index a0b8f665fa2f..ba8f9aa5d259 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -3367,7 +3367,7 @@ static unsigned int OnAssocReq(struct adapter *padapter, spin_unlock_bh(&pstapriv->asoc_list_lock); /* now the station is qualified to join our BSS... */ - if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_ == status)) { + if ((pstat->state & WIFI_FW_ASSOC_SUCCESS) && (_STATS_SUCCESSFUL_ == status)) { /* 1 bss_cap_update & sta_info_update */ bss_cap_update_on_sta_join(padapter, pstat); sta_info_update(padapter, pstat); diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index d0d4335b444c..21744a548bb8 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -123,7 +123,7 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) status = _SUCCESS; free_dvobj: - if (status != _SUCCESS && pdvobjpriv) { + if (status != _SUCCESS) { usb_set_intfdata(usb_intf, NULL); kfree(pdvobjpriv); pdvobjpriv = NULL; -- cgit v1.3-6-gb490 From 47ccb34ac72c0dbbb68f6a07ce63e9f0d21510ea Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 16 Jul 2015 16:58:09 +0530 Subject: staging: rtl8188eu: remove goto label By checking for the success of kzalloc we were able to remove the goto label thus making the code more readable. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 21744a548bb8..f68875bd9511 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -115,14 +115,11 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) mutex_init(&pdvobjpriv->usb_vendor_req_mutex); pdvobjpriv->usb_vendor_req_buf = kzalloc(MAX_USB_IO_CTL_SIZE, GFP_KERNEL); - if (!pdvobjpriv->usb_vendor_req_buf) - goto free_dvobj; - - usb_get_dev(pusbd); - - status = _SUCCESS; + if (pdvobjpriv->usb_vendor_req_buf) { + usb_get_dev(pusbd); + status = _SUCCESS; + } -free_dvobj: if (status != _SUCCESS) { usb_set_intfdata(usb_intf, NULL); kfree(pdvobjpriv); -- cgit v1.3-6-gb490 From ce806322730a2b29fd15c7873c09335a49b7a941 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 16 Jul 2015 16:58:10 +0530 Subject: staging: rtl8188eu: remove unneeded variable The default value of status was _FAIL, it was only changed if kzalloc succeeds and the check for status is immediately following kzalloc. We can have the failure code in the else part as the failure code will be executed only if kzalloc fails. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index f68875bd9511..2d75c77c8cdb 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -55,7 +55,6 @@ MODULE_DEVICE_TABLE(usb, rtw_usb_id_tbl); static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) { int i; - int status = _FAIL; struct dvobj_priv *pdvobjpriv; struct usb_host_config *phost_conf; struct usb_config_descriptor *pconf_desc; @@ -117,10 +116,7 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) if (pdvobjpriv->usb_vendor_req_buf) { usb_get_dev(pusbd); - status = _SUCCESS; - } - - if (status != _SUCCESS) { + } else { usb_set_intfdata(usb_intf, NULL); kfree(pdvobjpriv); pdvobjpriv = NULL; -- cgit v1.3-6-gb490 From 9aa39bc4d35ca33b406c15da563d6719aae3931e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 16 Jul 2015 16:58:11 +0530 Subject: staging: rtl8188eu: stop using DBG_88E Stop using DBG_88E which is a custom macro for printing debugging messages. Instead start using pr_debug and in the process define pr_fmt. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 39 +++++++++++++++-------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 2d75c77c8cdb..b245e9cd780e 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -19,6 +19,7 @@ ******************************************************************************/ #define _HCI_INTF_C_ +#define pr_fmt(fmt) "R8188EU: " fmt #include #include #include @@ -143,7 +144,7 @@ static void usb_dvobj_deinit(struct usb_interface *usb_intf) * on sitesurvey for the first time when * device is up . Reset usb port for sitesurvey * fail issue. */ - DBG_88E("usb attached..., try to reset usb device\n"); + pr_debug("usb attached..., try to reset usb device\n"); usb_reset_device(interface_to_usbdev(usb_intf)); } } @@ -194,7 +195,7 @@ static void rtw_dev_unload(struct adapter *padapter) RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_dev_unload\n")); if (padapter->bup) { - DBG_88E("===> rtw_dev_unload\n"); + pr_debug("===> rtw_dev_unload\n"); padapter->bDriverStopped = true; if (padapter->xmitpriv.ack_tx) rtw_ack_tx_done(&padapter->xmitpriv, RTW_SCTX_DONE_DRV_STOP); @@ -217,7 +218,7 @@ static void rtw_dev_unload(struct adapter *padapter) ("r871x_dev_unload():padapter->bup == false\n")); } - DBG_88E("<=== rtw_dev_unload\n"); + pr_debug("<=== rtw_dev_unload\n"); RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-rtw_dev_unload\n")); } @@ -234,11 +235,11 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) u32 start_time = jiffies; - DBG_88E("==> %s (%s:%d)\n", __func__, current->comm, current->pid); + pr_debug("==> %s (%s:%d)\n", __func__, current->comm, current->pid); if ((!padapter->bup) || (padapter->bDriverStopped) || (padapter->bSurpriseRemoved)) { - DBG_88E("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", + pr_debug("padapter->bup=%d bDriverStopped=%d bSurpriseRemoved = %d\n", padapter->bup, padapter->bDriverStopped, padapter->bSurpriseRemoved); goto exit; @@ -260,7 +261,7 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) { - DBG_88E("%s:%d %s(%pM), length:%d assoc_ssid.length:%d\n", + pr_debug("%s:%d %s(%pM), length:%d assoc_ssid.length:%d\n", __func__, __LINE__, pmlmepriv->cur_network.network.Ssid.Ssid, pmlmepriv->cur_network.network.MacAddress, @@ -286,7 +287,7 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) rtw_indicate_disconnect(padapter); exit: - DBG_88E("<=== %s return %d.............. in %dms\n", __func__ + pr_debug("<=== %s return %d.............. in %dms\n", __func__ , ret, rtw_get_passing_time_ms(start_time)); return ret; @@ -299,7 +300,7 @@ static int rtw_resume_process(struct adapter *padapter) int ret = -1; u32 start_time = jiffies; - DBG_88E("==> %s (%s:%d)\n", __func__, current->comm, current->pid); + pr_debug("==> %s (%s:%d)\n", __func__, current->comm, current->pid); if (padapter) { pnetdev = padapter->pnetdev; @@ -312,7 +313,7 @@ static int rtw_resume_process(struct adapter *padapter) rtw_reset_drv_sw(padapter); pwrpriv->bkeepfwalive = false; - DBG_88E("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive); + pr_debug("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive); if (pm_netdev_open(pnetdev, true) != 0) goto exit; @@ -327,7 +328,7 @@ static int rtw_resume_process(struct adapter *padapter) exit: if (pwrpriv) pwrpriv->bInSuspend = false; - DBG_88E("<=== %s return %d.............. in %dms\n", __func__, + pr_debug("<=== %s return %d.............. in %dms\n", __func__, ret, rtw_get_passing_time_ms(start_time)); @@ -400,8 +401,8 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, dvobj->pusbdev->do_remote_wakeup = 1; pusb_intf->needs_remote_wakeup = 1; device_init_wakeup(&pusb_intf->dev, 1); - DBG_88E("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~~~~\n"); - DBG_88E("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n", + pr_debug("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~~~~\n"); + pr_debug("\n padapter->pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n", device_may_wakeup(&pusb_intf->dev)); } #endif @@ -409,13 +410,13 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, /* 2012-07-11 Move here to prevent the 8723AS-VAU BT auto * suspend influence */ if (usb_autopm_get_interface(pusb_intf) < 0) - DBG_88E("can't get autopm:\n"); + pr_debug("can't get autopm:\n"); /* alloc dev name after read efuse. */ rtw_init_netdev_name(pnetdev, padapter->registrypriv.ifname); rtw_macaddr_cfg(padapter->eeprompriv.mac_addr); memcpy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr, ETH_ALEN); - DBG_88E("MAC Address from pnetdev->dev_addr = %pM\n", + pr_debug("MAC Address from pnetdev->dev_addr = %pM\n", pnetdev->dev_addr); /* step 6. Tell the network stack we exist */ @@ -424,7 +425,7 @@ static struct adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj, goto free_hal_data; } - DBG_88E("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n" + pr_debug("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n" , padapter->bDriverStopped , padapter->bSurpriseRemoved , padapter->bup @@ -468,7 +469,7 @@ static void rtw_usb_if1_deinit(struct adapter *if1) rtw_cancel_all_timer(if1); rtw_dev_unload(if1); - DBG_88E("+r871xu_dev_remove, hw_init_completed=%d\n", + pr_debug("+r871xu_dev_remove, hw_init_completed=%d\n", if1->hw_init_completed); rtw_free_drv_sw(if1); if (pnetdev) @@ -493,7 +494,7 @@ static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device if1 = rtw_usb_if1_init(dvobj, pusb_intf, pdid); if (if1 == NULL) { - DBG_88E("rtw_init_primarystruct adapter Failed!\n"); + pr_debug("rtw_init_primarystruct adapter Failed!\n"); goto free_dvobj; } @@ -518,7 +519,7 @@ static void rtw_dev_remove(struct usb_interface *pusb_intf) struct adapter *padapter = dvobj->if1; - DBG_88E("+rtw_dev_remove\n"); + pr_debug("+rtw_dev_remove\n"); RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+dev_remove()\n")); if (!pusb_intf->unregistering) @@ -534,7 +535,7 @@ static void rtw_dev_remove(struct usb_interface *pusb_intf) usb_dvobj_deinit(pusb_intf); RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-dev_remove()\n")); - DBG_88E("-r871xu_dev_remove, done\n"); + pr_debug("-r871xu_dev_remove, done\n"); } static struct usb_driver rtl8188e_usb_drv = { -- cgit v1.3-6-gb490 From 7d708e52c2295d4d74c58881668a05ff7af8dc16 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 16 Jul 2015 16:58:12 +0530 Subject: staging: rtl8188eu: remove unneeded ret The variable ret was always 0. So remove the variable and always return 0 from the function. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index b245e9cd780e..5490b2905075 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -230,11 +230,8 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) struct net_device *pnetdev = padapter->pnetdev; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv; - - int ret = 0; u32 start_time = jiffies; - pr_debug("==> %s (%s:%d)\n", __func__, current->comm, current->pid); if ((!padapter->bup) || (padapter->bDriverStopped) || @@ -287,10 +284,10 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) rtw_indicate_disconnect(padapter); exit: - pr_debug("<=== %s return %d.............. in %dms\n", __func__ - , ret, rtw_get_passing_time_ms(start_time)); + pr_debug("<=== %s .............. in %dms\n", __func__, + rtw_get_passing_time_ms(start_time)); - return ret; + return 0; } static int rtw_resume_process(struct adapter *padapter) -- cgit v1.3-6-gb490 From ac4e504a597903f65e6b365eee3e2675a7d8fe4e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 16 Jul 2015 18:28:17 +0530 Subject: staging: dgap: fix error path The code in dgap_stop() is almost a duplicate of the code that will be executed on pci_unregister_driver(). So the error code was stopping and unregistering everything twice. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/dgap/dgap.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c index 26b0446d943a..3a783bff112d 100644 --- a/drivers/staging/dgap/dgap.c +++ b/drivers/staging/dgap/dgap.c @@ -7133,8 +7133,10 @@ static int dgap_init_module(void) return rc; rc = pci_register_driver(&dgap_driver); - if (rc) - goto err_stop; + if (rc) { + dgap_stop(); + return rc; + } rc = dgap_create_driver_sysfiles(&dgap_driver); if (rc) @@ -7146,9 +7148,6 @@ static int dgap_init_module(void) err_unregister: pci_unregister_driver(&dgap_driver); -err_stop: - dgap_stop(); - return rc; } -- cgit v1.3-6-gb490 From eda03951c3edc1f95e974096770ee3b02df2a8f5 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 16 Jul 2015 18:28:18 +0530 Subject: staging: dgap: rearrange function Relocate the function dgap_stop() so that in a later patch we can remove the duplicate codes between dgap_stop() and dgap_remove_one(). Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/dgap/dgap.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c index 3a783bff112d..8956228a0e52 100644 --- a/drivers/staging/dgap/dgap.c +++ b/drivers/staging/dgap/dgap.c @@ -7004,6 +7004,21 @@ static void dgap_cleanup_board(struct board_t *brd) kfree(brd); } +static void dgap_stop(void) +{ + unsigned long lock_flags; + + spin_lock_irqsave(&dgap_poll_lock, lock_flags); + dgap_poll_stop = 1; + spin_unlock_irqrestore(&dgap_poll_lock, lock_flags); + + del_timer_sync(&dgap_poll_timer); + + device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0)); + class_destroy(dgap_class); + unregister_chrdev(DIGI_DGAP_MAJOR, "dgap"); +} + static void dgap_remove_one(struct pci_dev *dev) { unsigned int i; @@ -7096,21 +7111,6 @@ failed_class: return rc; } -static void dgap_stop(void) -{ - unsigned long lock_flags; - - spin_lock_irqsave(&dgap_poll_lock, lock_flags); - dgap_poll_stop = 1; - spin_unlock_irqrestore(&dgap_poll_lock, lock_flags); - - del_timer_sync(&dgap_poll_timer); - - device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0)); - class_destroy(dgap_class); - unregister_chrdev(DIGI_DGAP_MAJOR, "dgap"); -} - /************************************************************************ * * Driver load/unload functions -- cgit v1.3-6-gb490 From 174b83c0eb577d7db8f1867f1d76dc14f0b8eb40 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 16 Jul 2015 18:28:19 +0530 Subject: staging: dgap: new arguments to dgap_stop In a later patch we will remove the duplicate codes. But the code also needs to execute dgap_remove_driver_sysfiles() if it is being called from dgap_remove_one() but if being called fron the error path of the dgap_init_module() then the sysfiles should not be removed. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/dgap/dgap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c index 8956228a0e52..4f07a0cae987 100644 --- a/drivers/staging/dgap/dgap.c +++ b/drivers/staging/dgap/dgap.c @@ -7004,7 +7004,7 @@ static void dgap_cleanup_board(struct board_t *brd) kfree(brd); } -static void dgap_stop(void) +static void dgap_stop(bool removesys, struct pci_driver *drv) { unsigned long lock_flags; @@ -7013,6 +7013,8 @@ static void dgap_stop(void) spin_unlock_irqrestore(&dgap_poll_lock, lock_flags); del_timer_sync(&dgap_poll_timer); + if (removesys) + dgap_remove_driver_sysfiles(drv); device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0)); class_destroy(dgap_class); @@ -7134,7 +7136,7 @@ static int dgap_init_module(void) rc = pci_register_driver(&dgap_driver); if (rc) { - dgap_stop(); + dgap_stop(false, NULL); return rc; } -- cgit v1.3-6-gb490 From b8d1f261fe7e4967593a5637d62991b6197a03f8 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 16 Jul 2015 18:28:20 +0530 Subject: staging: dgap: remove duplicate code Remove the duplicate code of dgap_remove_one() and dgap_stop(). Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/dgap/dgap.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c index 4f07a0cae987..b344e035b0ef 100644 --- a/drivers/staging/dgap/dgap.c +++ b/drivers/staging/dgap/dgap.c @@ -7024,22 +7024,9 @@ static void dgap_stop(bool removesys, struct pci_driver *drv) static void dgap_remove_one(struct pci_dev *dev) { unsigned int i; - ulong lock_flags; struct pci_driver *drv = to_pci_driver(dev->dev.driver); - spin_lock_irqsave(&dgap_poll_lock, lock_flags); - dgap_poll_stop = 1; - spin_unlock_irqrestore(&dgap_poll_lock, lock_flags); - - /* Turn off poller right away. */ - del_timer_sync(&dgap_poll_timer); - - dgap_remove_driver_sysfiles(drv); - - device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0)); - class_destroy(dgap_class); - unregister_chrdev(DIGI_DGAP_MAJOR, "dgap"); - + dgap_stop(true, drv); for (i = 0; i < dgap_numboards; ++i) { dgap_remove_ports_sysfiles(dgap_board[i]); dgap_cleanup_tty(dgap_board[i]); -- cgit v1.3-6-gb490 From e1443d2849b146be4ed8d4ef89ae7e215aafaa5b Mon Sep 17 00:00:00 2001 From: Stephen Chandler Paul Date: Wed, 15 Jul 2015 10:20:17 -0700 Subject: Input: i8042 - add unmask_kbd_data option A big problem with the current i8042 debugging option is that it outputs data going to and from the keyboard by default. As a result, many dmesg logs uploaded by users will unintentionally contain sensitive information such as their password, as such it's probably a good idea not to output data coming from the keyboard unless specifically enabled by the user. Signed-off-by: Stephen Chandler Paul Reviewed-by: Andreas Mohr Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- Documentation/kernel-parameters.txt | 4 ++++ drivers/input/serio/i8042.c | 43 +++++++++++++++++++++++++++++++++---- drivers/input/serio/i8042.h | 13 +++++++++++ drivers/input/serio/serio.c | 5 ++--- include/linux/serio.h | 2 ++ 5 files changed, 60 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index bfcb1a62a7b4..fd0f7cd8e496 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1274,6 +1274,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. , i8042.debug [HW] Toggle i8042 debug mode + i8042.unmask_kbd_data + [HW] Enable printing of interrupt data from the KBD port + (disabled by default, and as a pre-condition + requires that i8042.debug=1 be enabled) i8042.direct [HW] Put keyboard port into non-translated mode i8042.dumbkbd [HW] Pretend that controller can only read data from keyboard and cannot control its state diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index cb5ece77fd7d..c9c98f0ab284 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -88,6 +88,10 @@ MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); static bool i8042_debug; module_param_named(debug, i8042_debug, bool, 0600); MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); + +static bool i8042_unmask_kbd_data; +module_param_named(unmask_kbd_data, i8042_unmask_kbd_data, bool, 0600); +MODULE_PARM_DESC(unmask_kbd_data, "Unconditional enable (may reveal sensitive data) of normally sanitize-filtered kbd data traffic debug log [pre-condition: i8042.debug=1 enabled]"); #endif static bool i8042_bypass_aux_irq_test; @@ -116,6 +120,7 @@ struct i8042_port { struct serio *serio; int irq; bool exists; + bool driver_bound; signed char mux; }; @@ -133,6 +138,7 @@ static bool i8042_kbd_irq_registered; static bool i8042_aux_irq_registered; static unsigned char i8042_suppress_kbd_ack; static struct platform_device *i8042_platform_device; +static struct notifier_block i8042_kbd_bind_notifier_block; static irqreturn_t i8042_interrupt(int irq, void *dev_id); static bool (*i8042_platform_filter)(unsigned char data, unsigned char str, @@ -528,10 +534,10 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) port = &i8042_ports[port_no]; serio = port->exists ? port->serio : NULL; - dbg("%02x <- i8042 (interrupt, %d, %d%s%s)\n", - data, port_no, irq, - dfl & SERIO_PARITY ? ", bad parity" : "", - dfl & SERIO_TIMEOUT ? ", timeout" : ""); + filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n", + port_no, irq, + dfl & SERIO_PARITY ? ", bad parity" : "", + dfl & SERIO_TIMEOUT ? ", timeout" : ""); filtered = i8042_filter(data, str, serio); @@ -1438,6 +1444,29 @@ static int __init i8042_setup_kbd(void) return error; } +static int i8042_kbd_bind_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct serio *serio = to_serio_port(dev); + struct i8042_port *port = serio->port_data; + + if (serio != i8042_ports[I8042_KBD_PORT_NO].serio) + return 0; + + switch (action) { + case BUS_NOTIFY_BOUND_DRIVER: + port->driver_bound = true; + break; + + case BUS_NOTIFY_UNBIND_DRIVER: + port->driver_bound = false; + break; + } + + return 0; +} + static int __init i8042_probe(struct platform_device *dev) { int error; @@ -1507,6 +1536,10 @@ static struct platform_driver i8042_driver = { .shutdown = i8042_shutdown, }; +static struct notifier_block i8042_kbd_bind_notifier_block = { + .notifier_call = i8042_kbd_bind_notifier, +}; + static int __init i8042_init(void) { struct platform_device *pdev; @@ -1528,6 +1561,7 @@ static int __init i8042_init(void) goto err_platform_exit; } + bus_register_notifier(&serio_bus, &i8042_kbd_bind_notifier_block); panic_blink = i8042_panic_blink; return 0; @@ -1543,6 +1577,7 @@ static void __exit i8042_exit(void) platform_driver_unregister(&i8042_driver); i8042_platform_exit(); + bus_unregister_notifier(&serio_bus, &i8042_kbd_bind_notifier_block); panic_blink = NULL; } diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index fc080beffedc..1db0a40c9bab 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h @@ -73,6 +73,17 @@ static unsigned long i8042_start_time; printk(KERN_DEBUG KBUILD_MODNAME ": [%d] " format, \ (int) (jiffies - i8042_start_time), ##arg); \ } while (0) + +#define filter_dbg(filter, data, format, args...) \ + do { \ + if (!i8042_debug) \ + break; \ + \ + if (!filter || i8042_unmask_kbd_data) \ + dbg("%02x " format, data, ##args); \ + else \ + dbg("** " format, ##args); \ + } while (0) #else #define dbg_init() do { } while (0) #define dbg(format, arg...) \ @@ -80,6 +91,8 @@ static unsigned long i8042_start_time; if (0) \ printk(KERN_DEBUG pr_fmt(format), ##arg); \ } while (0) + +#define filter_dbg(filter, data, format, args...) do { } while (0) #endif #endif /* _I8042_H */ diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index a05a5179da32..8f828975ab10 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -49,8 +49,6 @@ static DEFINE_MUTEX(serio_mutex); static LIST_HEAD(serio_list); -static struct bus_type serio_bus; - static void serio_add_port(struct serio *serio); static int serio_reconnect_port(struct serio *serio); static void serio_disconnect_port(struct serio *serio); @@ -1017,7 +1015,7 @@ irqreturn_t serio_interrupt(struct serio *serio, } EXPORT_SYMBOL(serio_interrupt); -static struct bus_type serio_bus = { +struct bus_type serio_bus = { .name = "serio", .drv_groups = serio_driver_groups, .match = serio_bus_match, @@ -1029,6 +1027,7 @@ static struct bus_type serio_bus = { .pm = &serio_pm_ops, #endif }; +EXPORT_SYMBOL(serio_bus); static int __init serio_init(void) { diff --git a/include/linux/serio.h b/include/linux/serio.h index 9f779c7a2da4..df4ab5de1586 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -18,6 +18,8 @@ #include #include +extern struct bus_type serio_bus; + struct serio { void *port_data; -- cgit v1.3-6-gb490 From cee3d8ccbecb8af6788edaaac46befca78b000dc Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 16 Jul 2015 10:32:40 -0700 Subject: Input: ambakmi - fix system PM by converting to modern callbacks The legacy system PM support has long time ago been dropped from the AMBA bus. Align to that by converting to the modern system PM callbacks. Fixes: 26825cfd90f9 (ARM: 7914/1: amba: Drop legacy PM support ...) Signed-off-by: Ulf Hansson Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ambakmi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 8b748d99b934..c6606cacb6a7 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -175,9 +175,9 @@ static int amba_kmi_remove(struct amba_device *dev) return 0; } -static int amba_kmi_resume(struct amba_device *dev) +static int __maybe_unused amba_kmi_resume(struct device *dev) { - struct amba_kmi_port *kmi = amba_get_drvdata(dev); + struct amba_kmi_port *kmi = dev_get_drvdata(dev); /* kick the serio layer to rescan this port */ serio_reconnect(kmi->io); @@ -185,6 +185,8 @@ static int amba_kmi_resume(struct amba_device *dev) return 0; } +static SIMPLE_DEV_PM_OPS(amba_kmi_dev_pm_ops, NULL, amba_kmi_resume); + static struct amba_id amba_kmi_idtable[] = { { .id = 0x00041050, @@ -199,11 +201,11 @@ static struct amba_driver ambakmi_driver = { .drv = { .name = "kmi-pl050", .owner = THIS_MODULE, + .pm = &amba_kmi_dev_pm_ops, }, .id_table = amba_kmi_idtable, .probe = amba_kmi_probe, .remove = amba_kmi_remove, - .resume = amba_kmi_resume, }; module_amba_driver(ambakmi_driver); -- cgit v1.3-6-gb490 From 4d45c70bfb3ffe55fad1d1681feaec2094f4da3b Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Thu, 16 Jul 2015 23:46:54 +0530 Subject: regulator: 88pm800: Fix indentation of assignments of data structures This patch makes code more clean from readability point of view, make all assignments of LDO, BUCk and regulator_ops structure at the same indentation. Signed-off-by: Vaibhav Hiremath Signed-off-by: Mark Brown --- drivers/regulator/88pm800.c | 68 ++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index 832932bdc977..11f7ab22ff88 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -95,11 +95,11 @@ struct pm800_regulators { #define PM800_BUCK(vreg, ereg, ebit, amax, volt_ranges, n_volt) \ { \ .desc = { \ - .name = #vreg, \ - .ops = &pm800_volt_range_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = PM800_ID_##vreg, \ - .owner = THIS_MODULE, \ + .name = #vreg, \ + .ops = &pm800_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PM800_ID_##vreg, \ + .owner = THIS_MODULE, \ .n_voltages = n_volt, \ .linear_ranges = volt_ranges, \ .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ @@ -108,7 +108,7 @@ struct pm800_regulators { .enable_reg = PM800_##ereg, \ .enable_mask = 1 << (ebit), \ }, \ - .max_ua = (amax), \ + .max_ua = (amax), \ } /* @@ -123,19 +123,19 @@ struct pm800_regulators { #define PM800_LDO(vreg, ereg, ebit, amax, ldo_volt_table) \ { \ .desc = { \ - .name = #vreg, \ - .ops = &pm800_volt_table_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = PM800_ID_##vreg, \ - .owner = THIS_MODULE, \ - .n_voltages = ARRAY_SIZE(ldo_volt_table), \ - .vsel_reg = PM800_##vreg##_VOUT, \ - .vsel_mask = 0x1f, \ - .enable_reg = PM800_##ereg, \ - .enable_mask = 1 << (ebit), \ - .volt_table = ldo_volt_table, \ + .name = #vreg, \ + .ops = &pm800_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = PM800_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(ldo_volt_table), \ + .vsel_reg = PM800_##vreg##_VOUT, \ + .vsel_mask = 0x1f, \ + .enable_reg = PM800_##ereg, \ + .enable_mask = 1 << (ebit), \ + .volt_table = ldo_volt_table, \ }, \ - .max_ua = (amax), \ + .max_ua = (amax), \ } /* Ranges are sorted in ascending order. */ @@ -178,25 +178,25 @@ static int pm800_get_current_limit(struct regulator_dev *rdev) } static struct regulator_ops pm800_volt_range_ops = { - .list_voltage = regulator_list_voltage_linear_range, - .map_voltage = regulator_map_voltage_linear_range, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .get_current_limit = pm800_get_current_limit, + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_current_limit = pm800_get_current_limit, }; static struct regulator_ops pm800_volt_table_ops = { - .list_voltage = regulator_list_voltage_table, - .map_voltage = regulator_map_voltage_iterate, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .is_enabled = regulator_is_enabled_regmap, - .get_current_limit = pm800_get_current_limit, + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_current_limit = pm800_get_current_limit, }; /* The array is indexed by id(PM800_ID_XXX) */ -- cgit v1.3-6-gb490 From a07d94a54b93d94d8cb990ffe018c595cfb94662 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Thu, 16 Jul 2015 23:46:55 +0530 Subject: regulator: 88pm800: Update driver to use devm_regulator_register fn This patch replaces standard regulator_register with devm_regulator_register() fn, as using devm_regulator_register() fn simplifies the driver return/exit path. As part of this update, patch also cleanups up all unnecessary changes which is result of this patch - - Remove _remove() fn, as devm_ variant takes care of it. - Remove pm800_regulators.regulators[] field, as it was only needed during cleanup, so we no longer need this. This also saved some amount of memory. Signed-off-by: Vaibhav Hiremath Signed-off-by: Mark Brown --- drivers/regulator/88pm800.c | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index 11f7ab22ff88..3b371701093d 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -78,7 +78,6 @@ struct pm800_regulator_info { }; struct pm800_regulators { - struct regulator_dev *regulators[PM800_ID_RG_MAX]; struct pm80x_chip *chip; struct regmap *map; }; @@ -318,6 +317,8 @@ static int pm800_regulator_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pm800_data); for (i = 0; i < PM800_ID_RG_MAX; i++) { + struct regulator_dev *regulator; + if (!pdata || pdata->num_regulators == 0) init_data = pm800_regulator_matches[i].init_data; else @@ -331,16 +332,12 @@ static int pm800_regulator_probe(struct platform_device *pdev) config.regmap = pm800_data->map; config.of_node = pm800_regulator_matches[i].of_node; - pm800_data->regulators[i] = - regulator_register(&info->desc, &config); - if (IS_ERR(pm800_data->regulators[i])) { - ret = PTR_ERR(pm800_data->regulators[i]); + regulator = devm_regulator_register(&pdev->dev, + &info->desc, &config); + if (IS_ERR(regulator)) { + ret = PTR_ERR(regulator); dev_err(&pdev->dev, "Failed to register %s\n", info->desc.name); - - while (--i >= 0) - regulator_unregister(pm800_data->regulators[i]); - return ret; } } @@ -348,23 +345,11 @@ static int pm800_regulator_probe(struct platform_device *pdev) return 0; } -static int pm800_regulator_remove(struct platform_device *pdev) -{ - struct pm800_regulators *pm800_data = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < PM800_ID_RG_MAX; i++) - regulator_unregister(pm800_data->regulators[i]); - - return 0; -} - static struct platform_driver pm800_regulator_driver = { .driver = { .name = "88pm80x-regulator", }, .probe = pm800_regulator_probe, - .remove = pm800_regulator_remove, }; module_platform_driver(pm800_regulator_driver); -- cgit v1.3-6-gb490 From fa26e4d2b3cf1c84f20fbc003501bb028f682d92 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Thu, 16 Jul 2015 23:46:56 +0530 Subject: regulator: 88pm800: Use regulator_nodes/of_match in the descriptor This patch is add regulator_nodes/of_match in the regulator descriptor for using information from DT instead of specific codes. With this patch, driver gets simplified, - No need to maintain "struct of_regulator_match" table and call of_regulator_match() fn. - No need for pm800_regulator_dt_init() fn, as it was only used for of_regulator_match(). - probe() fn got simplified around regulator_config and regulator_desc initialization. Signed-off-by: Vaibhav Hiremath Signed-off-by: Mark Brown --- drivers/regulator/88pm800.c | 143 ++++++++++++++------------------------------ 1 file changed, 44 insertions(+), 99 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index 3b371701093d..26c277f7c98e 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -91,10 +91,12 @@ struct pm800_regulators { * not the constant voltage table. * n_volt - Number of available selectors */ -#define PM800_BUCK(vreg, ereg, ebit, amax, volt_ranges, n_volt) \ +#define PM800_BUCK(match, vreg, ereg, ebit, amax, volt_ranges, n_volt) \ { \ .desc = { \ .name = #vreg, \ + .of_match = of_match_ptr(#match), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &pm800_volt_range_ops, \ .type = REGULATOR_VOLTAGE, \ .id = PM800_ID_##vreg, \ @@ -119,10 +121,12 @@ struct pm800_regulators { * For all the LDOes, there are too many ranges. Using volt_table will be * simpler and faster. */ -#define PM800_LDO(vreg, ereg, ebit, amax, ldo_volt_table) \ +#define PM800_LDO(match, vreg, ereg, ebit, amax, ldo_volt_table) \ { \ .desc = { \ .name = #vreg, \ + .of_match = of_match_ptr(#match), \ + .regulators_node = of_match_ptr("regulators"), \ .ops = &pm800_volt_table_ops, \ .type = REGULATOR_VOLTAGE, \ .id = PM800_ID_##vreg, \ @@ -200,99 +204,43 @@ static struct regulator_ops pm800_volt_table_ops = { /* The array is indexed by id(PM800_ID_XXX) */ static struct pm800_regulator_info pm800_regulator_info[] = { - PM800_BUCK(BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range, 0x55), - PM800_BUCK(BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range, 0x73), - PM800_BUCK(BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range, 0x73), - PM800_BUCK(BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range, 0x73), - PM800_BUCK(BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range, 0x73), - - PM800_LDO(LDO1, LDO_ENA1_1, 0, 200000, ldo1_volt_table), - PM800_LDO(LDO2, LDO_ENA1_1, 1, 10000, ldo2_volt_table), - PM800_LDO(LDO3, LDO_ENA1_1, 2, 300000, ldo3_17_volt_table), - PM800_LDO(LDO4, LDO_ENA1_1, 3, 300000, ldo3_17_volt_table), - PM800_LDO(LDO5, LDO_ENA1_1, 4, 300000, ldo3_17_volt_table), - PM800_LDO(LDO6, LDO_ENA1_1, 5, 300000, ldo3_17_volt_table), - PM800_LDO(LDO7, LDO_ENA1_1, 6, 300000, ldo3_17_volt_table), - PM800_LDO(LDO8, LDO_ENA1_1, 7, 300000, ldo3_17_volt_table), - PM800_LDO(LDO9, LDO_ENA1_2, 0, 300000, ldo3_17_volt_table), - PM800_LDO(LDO10, LDO_ENA1_2, 1, 300000, ldo3_17_volt_table), - PM800_LDO(LDO11, LDO_ENA1_2, 2, 300000, ldo3_17_volt_table), - PM800_LDO(LDO12, LDO_ENA1_2, 3, 300000, ldo3_17_volt_table), - PM800_LDO(LDO13, LDO_ENA1_2, 4, 300000, ldo3_17_volt_table), - PM800_LDO(LDO14, LDO_ENA1_2, 5, 300000, ldo3_17_volt_table), - PM800_LDO(LDO15, LDO_ENA1_2, 6, 300000, ldo3_17_volt_table), - PM800_LDO(LDO16, LDO_ENA1_2, 7, 300000, ldo3_17_volt_table), - PM800_LDO(LDO17, LDO_ENA1_3, 0, 300000, ldo3_17_volt_table), - PM800_LDO(LDO18, LDO_ENA1_3, 1, 200000, ldo18_19_volt_table), - PM800_LDO(LDO19, LDO_ENA1_3, 2, 200000, ldo18_19_volt_table), + PM800_BUCK(buck1, BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range, 0x55), + PM800_BUCK(buck2, BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(buck3, BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(buck4, BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range, 0x73), + PM800_BUCK(buck5, BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range, 0x73), + + PM800_LDO(ldo1, LDO1, LDO_ENA1_1, 0, 200000, ldo1_volt_table), + PM800_LDO(ldo2, LDO2, LDO_ENA1_1, 1, 10000, ldo2_volt_table), + PM800_LDO(ldo3, LDO3, LDO_ENA1_1, 2, 300000, ldo3_17_volt_table), + PM800_LDO(ldo4, LDO4, LDO_ENA1_1, 3, 300000, ldo3_17_volt_table), + PM800_LDO(ldo5, LDO5, LDO_ENA1_1, 4, 300000, ldo3_17_volt_table), + PM800_LDO(ldo6, LDO6, LDO_ENA1_1, 5, 300000, ldo3_17_volt_table), + PM800_LDO(ldo7, LDO7, LDO_ENA1_1, 6, 300000, ldo3_17_volt_table), + PM800_LDO(ldo8, LDO8, LDO_ENA1_1, 7, 300000, ldo3_17_volt_table), + PM800_LDO(ldo9, LDO9, LDO_ENA1_2, 0, 300000, ldo3_17_volt_table), + PM800_LDO(ldo10, LDO10, LDO_ENA1_2, 1, 300000, ldo3_17_volt_table), + PM800_LDO(ldo11, LDO11, LDO_ENA1_2, 2, 300000, ldo3_17_volt_table), + PM800_LDO(ldo12, LDO12, LDO_ENA1_2, 3, 300000, ldo3_17_volt_table), + PM800_LDO(ldo13, LDO13, LDO_ENA1_2, 4, 300000, ldo3_17_volt_table), + PM800_LDO(ldo14, LDO14, LDO_ENA1_2, 5, 300000, ldo3_17_volt_table), + PM800_LDO(ldo15, LDO15, LDO_ENA1_2, 6, 300000, ldo3_17_volt_table), + PM800_LDO(ldo16, LDO16, LDO_ENA1_2, 7, 300000, ldo3_17_volt_table), + PM800_LDO(ldo17, LDO17, LDO_ENA1_3, 0, 300000, ldo3_17_volt_table), + PM800_LDO(ldo18, LDO18, LDO_ENA1_3, 1, 200000, ldo18_19_volt_table), + PM800_LDO(ldo19, LDO19, LDO_ENA1_3, 2, 200000, ldo18_19_volt_table), }; -#define PM800_REGULATOR_OF_MATCH(_name, _id) \ - [PM800_ID_##_id] = { \ - .name = #_name, \ - .driver_data = &pm800_regulator_info[PM800_ID_##_id], \ - } - -static struct of_regulator_match pm800_regulator_matches[] = { - PM800_REGULATOR_OF_MATCH(buck1, BUCK1), - PM800_REGULATOR_OF_MATCH(buck2, BUCK2), - PM800_REGULATOR_OF_MATCH(buck3, BUCK3), - PM800_REGULATOR_OF_MATCH(buck4, BUCK4), - PM800_REGULATOR_OF_MATCH(buck5, BUCK5), - PM800_REGULATOR_OF_MATCH(ldo1, LDO1), - PM800_REGULATOR_OF_MATCH(ldo2, LDO2), - PM800_REGULATOR_OF_MATCH(ldo3, LDO3), - PM800_REGULATOR_OF_MATCH(ldo4, LDO4), - PM800_REGULATOR_OF_MATCH(ldo5, LDO5), - PM800_REGULATOR_OF_MATCH(ldo6, LDO6), - PM800_REGULATOR_OF_MATCH(ldo7, LDO7), - PM800_REGULATOR_OF_MATCH(ldo8, LDO8), - PM800_REGULATOR_OF_MATCH(ldo9, LDO9), - PM800_REGULATOR_OF_MATCH(ldo10, LDO10), - PM800_REGULATOR_OF_MATCH(ldo11, LDO11), - PM800_REGULATOR_OF_MATCH(ldo12, LDO12), - PM800_REGULATOR_OF_MATCH(ldo13, LDO13), - PM800_REGULATOR_OF_MATCH(ldo14, LDO14), - PM800_REGULATOR_OF_MATCH(ldo15, LDO15), - PM800_REGULATOR_OF_MATCH(ldo16, LDO16), - PM800_REGULATOR_OF_MATCH(ldo17, LDO17), - PM800_REGULATOR_OF_MATCH(ldo18, LDO18), - PM800_REGULATOR_OF_MATCH(ldo19, LDO19), -}; - -static int pm800_regulator_dt_init(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - int ret; - - ret = of_regulator_match(&pdev->dev, np, - pm800_regulator_matches, - ARRAY_SIZE(pm800_regulator_matches)); - if (ret < 0) - return ret; - - return 0; -} - static int pm800_regulator_probe(struct platform_device *pdev) { struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm80x_platform_data *pdata = dev_get_platdata(pdev->dev.parent); struct pm800_regulators *pm800_data; - struct pm800_regulator_info *info; struct regulator_config config = { }; struct regulator_init_data *init_data; int i, ret; - if (!pdata || pdata->num_regulators == 0) { - if (IS_ENABLED(CONFIG_OF)) { - ret = pm800_regulator_dt_init(pdev); - if (ret) - return ret; - } else { - return -ENODEV; - } - } else if (pdata->num_regulators) { + if (pdata && pdata->num_regulators) { unsigned int count = 0; /* Check whether num_regulator is valid. */ @@ -302,8 +250,6 @@ static int pm800_regulator_probe(struct platform_device *pdev) } if (count != pdata->num_regulators) return -EINVAL; - } else { - return -EINVAL; } pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data), @@ -316,28 +262,27 @@ static int pm800_regulator_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pm800_data); + config.dev = chip->dev; + config.regmap = pm800_data->map; for (i = 0; i < PM800_ID_RG_MAX; i++) { struct regulator_dev *regulator; - if (!pdata || pdata->num_regulators == 0) - init_data = pm800_regulator_matches[i].init_data; - else + if (pdata && pdata->num_regulators) { init_data = pdata->regulators[i]; - if (!init_data) - continue; - info = pm800_regulator_matches[i].driver_data; - config.dev = &pdev->dev; - config.init_data = init_data; - config.driver_data = info; - config.regmap = pm800_data->map; - config.of_node = pm800_regulator_matches[i].of_node; + if (!init_data) + continue; + + config.init_data = init_data; + } + + config.driver_data = &pm800_regulator_info[i]; regulator = devm_regulator_register(&pdev->dev, - &info->desc, &config); + &pm800_regulator_info[i].desc, &config); if (IS_ERR(regulator)) { ret = PTR_ERR(regulator); dev_err(&pdev->dev, "Failed to register %s\n", - info->desc.name); + pm800_regulator_info[i].desc.name); return ret; } } -- cgit v1.3-6-gb490 From 0afab670bda6f3c9980be9e6de0effcc2c6d456c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 15 Jul 2015 21:59:47 +0900 Subject: mfd/extcon: max77693: Remove unused extern declarations and max77693_dev members Clean up the max77693 private header file by removing: 1. Left-overs from previous way of interrupt handling (driver uses regmap_irq_chip). 2. Unused members of struct 'max77693_dev' related to interrupts in extcon driver. Signed-off-by: Krzysztof Kozlowski Acked-by: Chanwoo Choi Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/extcon/extcon-max77693.c | 19 ------------------- include/linux/mfd/max77693-private.h | 8 -------- 2 files changed, 27 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index f4f3b3d53928..770db3a72a6a 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -1164,28 +1164,9 @@ static int max77693_muic_probe(struct platform_device *pdev) } for (i = 0; i < num_init_data; i++) { - enum max77693_irq_source irq_src - = MAX77693_IRQ_GROUP_NR; - regmap_write(info->max77693->regmap_muic, init_data[i].addr, init_data[i].data); - - switch (init_data[i].addr) { - case MAX77693_MUIC_REG_INTMASK1: - irq_src = MUIC_INT1; - break; - case MAX77693_MUIC_REG_INTMASK2: - irq_src = MUIC_INT2; - break; - case MAX77693_MUIC_REG_INTMASK3: - irq_src = MUIC_INT3; - break; - } - - if (irq_src < MAX77693_IRQ_GROUP_NR) - info->max77693->irq_masks_cur[irq_src] - = init_data[i].data; } if (pdata && pdata->muic_data) { diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h index 51633ea6f910..ad67b8235a8d 100644 --- a/include/linux/mfd/max77693-private.h +++ b/include/linux/mfd/max77693-private.h @@ -547,18 +547,10 @@ struct max77693_dev { struct regmap_irq_chip_data *irq_data_muic; int irq; - int irq_gpio; - struct mutex irqlock; - int irq_masks_cur[MAX77693_IRQ_GROUP_NR]; - int irq_masks_cache[MAX77693_IRQ_GROUP_NR]; }; enum max77693_types { TYPE_MAX77693, }; -extern int max77693_irq_init(struct max77693_dev *max77686); -extern void max77693_irq_exit(struct max77693_dev *max77686); -extern int max77693_irq_resume(struct max77693_dev *max77686); - #endif /* __LINUX_MFD_MAX77693_PRIV_H */ -- cgit v1.3-6-gb490 From 5b5e771fb711f95da859bf6be9fba4bc9919b5d5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 15 Jul 2015 21:59:49 +0900 Subject: regulator: max77693: Support different register configurations Add support for different configurations of charger's registers so the same driver could be used on other devices (e.g. MAX77843). Signed-off-by: Krzysztof Kozlowski Acked-by: Mark Brown Signed-off-by: Mark Brown --- drivers/regulator/max77693.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c index 38722c8311a5..236851ab575a 100644 --- a/drivers/regulator/max77693.c +++ b/drivers/regulator/max77693.c @@ -33,7 +33,13 @@ #include #include -#define CHGIN_ILIM_STEP_20mA 20000 +/* Charger regulator differences between MAX77693 and MAX77843 */ +struct chg_reg_data { + unsigned int linear_reg; + unsigned int linear_mask; + unsigned int uA_step; + unsigned int min_sel; +}; /* * CHARGER regulator - Min : 20mA, Max : 2580mA, step : 20mA @@ -42,25 +48,26 @@ */ static int max77693_chg_get_current_limit(struct regulator_dev *rdev) { + const struct chg_reg_data *reg_data = rdev_get_drvdata(rdev); unsigned int chg_min_uA = rdev->constraints->min_uA; unsigned int chg_max_uA = rdev->constraints->max_uA; unsigned int reg, sel; unsigned int val; int ret; - ret = regmap_read(rdev->regmap, MAX77693_CHG_REG_CHG_CNFG_09, ®); + ret = regmap_read(rdev->regmap, reg_data->linear_reg, ®); if (ret < 0) return ret; - sel = reg & CHG_CNFG_09_CHGIN_ILIM_MASK; + sel = reg & reg_data->linear_mask; /* the first four codes for charger current are all 60mA */ - if (sel <= 3) + if (sel <= reg_data->min_sel) sel = 0; else - sel -= 3; + sel -= reg_data->min_sel; - val = chg_min_uA + CHGIN_ILIM_STEP_20mA * sel; + val = chg_min_uA + reg_data->uA_step * sel; if (val > chg_max_uA) return -EINVAL; @@ -70,20 +77,20 @@ static int max77693_chg_get_current_limit(struct regulator_dev *rdev) static int max77693_chg_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA) { + const struct chg_reg_data *reg_data = rdev_get_drvdata(rdev); unsigned int chg_min_uA = rdev->constraints->min_uA; int sel = 0; - while (chg_min_uA + CHGIN_ILIM_STEP_20mA * sel < min_uA) + while (chg_min_uA + reg_data->uA_step * sel < min_uA) sel++; - if (chg_min_uA + CHGIN_ILIM_STEP_20mA * sel > max_uA) + if (chg_min_uA + reg_data->uA_step * sel > max_uA) return -EINVAL; /* the first four codes for charger current are all 60mA */ - sel += 3; + sel += reg_data->min_sel; - return regmap_write(rdev->regmap, - MAX77693_CHG_REG_CHG_CNFG_09, sel); + return regmap_write(rdev->regmap, reg_data->linear_reg, sel); } /* end of CHARGER regulator ops */ @@ -145,6 +152,13 @@ static const struct regulator_desc regulators[] = { }, }; +static const struct chg_reg_data max77693_chg_reg_data = { + .linear_reg = MAX77693_CHG_REG_CHG_CNFG_09, + .linear_mask = CHG_CNFG_09_CHGIN_ILIM_MASK, + .uA_step = 20000, + .min_sel = 3, +}; + static int max77693_pmic_probe(struct platform_device *pdev) { struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent); @@ -153,6 +167,7 @@ static int max77693_pmic_probe(struct platform_device *pdev) config.dev = iodev->dev; config.regmap = iodev->regmap; + config.driver_data = (void *)&max77693_chg_reg_data; for (i = 0; i < ARRAY_SIZE(regulators); i++) { struct regulator_dev *rdev; @@ -170,7 +185,7 @@ static int max77693_pmic_probe(struct platform_device *pdev) } static const struct platform_device_id max77693_pmic_id[] = { - {"max77693-pmic", 0}, + { "max77693-pmic", TYPE_MAX77693 }, {}, }; -- cgit v1.3-6-gb490 From 61b305cd2ae747b8c9a2e4467dea2575a390162c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 15 Jul 2015 21:59:50 +0900 Subject: drivers: max77693: Move state container to common header This prepares for merging some of the drivers between max77693 and max77843 so the child MFD driver can be attached to any parent MFD main driver. Move the state container to common header file. Additionally add consistent 'i2c' prefixes to its members (of 'struct i2c_client' type). Signed-off-by: Krzysztof Kozlowski Acked-by: Sebastian Reichel Acked-by: Dmitry Torokhov Acked-by: Lee Jones Acked-by: Chanwoo Choi Acked-by: Jacek Anaszewski Signed-off-by: Mark Brown --- drivers/extcon/extcon-max77693.c | 3 ++- drivers/input/misc/max77693-haptic.c | 1 + drivers/leds/leds-max77693.c | 1 + drivers/mfd/max77693.c | 31 +++++++++++++------------ drivers/power/max77693_charger.c | 1 + drivers/regulator/max77693.c | 1 + include/linux/mfd/max77693-common.h | 44 ++++++++++++++++++++++++++++++++++++ include/linux/mfd/max77693-private.h | 25 -------------------- 8 files changed, 66 insertions(+), 41 deletions(-) create mode 100644 include/linux/mfd/max77693-common.h (limited to 'drivers') diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index 770db3a72a6a..c7bb180cfff4 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1077,7 +1078,7 @@ static int max77693_muic_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "allocate register map\n"); } else { info->max77693->regmap_muic = devm_regmap_init_i2c( - info->max77693->muic, + info->max77693->i2c_muic, &max77693_muic_regmap_config); if (IS_ERR(info->max77693->regmap_muic)) { ret = PTR_ERR(info->max77693->regmap_muic); diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c index 39e930c10ebb..4524499ea72f 100644 --- a/drivers/input/misc/max77693-haptic.c +++ b/drivers/input/misc/max77693-haptic.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #define MAX_MAGNITUDE_SHIFT 16 diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c index b8b0eec7b540..df348a06d8c7 100644 --- a/drivers/leds/leds-max77693.c +++ b/drivers/leds/leds-max77693.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index cb14afa97e6f..67bc53fdc389 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -193,22 +194,22 @@ static int max77693_i2c_probe(struct i2c_client *i2c, } else dev_info(max77693->dev, "device ID: 0x%x\n", reg_data); - max77693->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC); - if (!max77693->muic) { + max77693->i2c_muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC); + if (!max77693->i2c_muic) { dev_err(max77693->dev, "Failed to allocate I2C device for MUIC\n"); return -ENODEV; } - i2c_set_clientdata(max77693->muic, max77693); + i2c_set_clientdata(max77693->i2c_muic, max77693); - max77693->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC); - if (!max77693->haptic) { + max77693->i2c_haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC); + if (!max77693->i2c_haptic) { dev_err(max77693->dev, "Failed to allocate I2C device for Haptic\n"); ret = -ENODEV; goto err_i2c_haptic; } - i2c_set_clientdata(max77693->haptic, max77693); + i2c_set_clientdata(max77693->i2c_haptic, max77693); - max77693->regmap_haptic = devm_regmap_init_i2c(max77693->haptic, + max77693->regmap_haptic = devm_regmap_init_i2c(max77693->i2c_haptic, &max77693_regmap_haptic_config); if (IS_ERR(max77693->regmap_haptic)) { ret = PTR_ERR(max77693->regmap_haptic); @@ -222,7 +223,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c, * instance of MUIC device when irq of max77693 is initialized * before call max77693-muic probe() function. */ - max77693->regmap_muic = devm_regmap_init_i2c(max77693->muic, + max77693->regmap_muic = devm_regmap_init_i2c(max77693->i2c_muic, &max77693_regmap_muic_config); if (IS_ERR(max77693->regmap_muic)) { ret = PTR_ERR(max77693->regmap_muic); @@ -255,7 +256,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c, IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_FALLING, 0, &max77693_charger_irq_chip, - &max77693->irq_data_charger); + &max77693->irq_data_chg); if (ret) { dev_err(max77693->dev, "failed to add irq chip: %d\n", ret); goto err_irq_charger; @@ -296,15 +297,15 @@ err_mfd: err_intsrc: regmap_del_irq_chip(max77693->irq, max77693->irq_data_muic); err_irq_muic: - regmap_del_irq_chip(max77693->irq, max77693->irq_data_charger); + regmap_del_irq_chip(max77693->irq, max77693->irq_data_chg); err_irq_charger: regmap_del_irq_chip(max77693->irq, max77693->irq_data_topsys); err_irq_topsys: regmap_del_irq_chip(max77693->irq, max77693->irq_data_led); err_regmap: - i2c_unregister_device(max77693->haptic); + i2c_unregister_device(max77693->i2c_haptic); err_i2c_haptic: - i2c_unregister_device(max77693->muic); + i2c_unregister_device(max77693->i2c_muic); return ret; } @@ -315,12 +316,12 @@ static int max77693_i2c_remove(struct i2c_client *i2c) mfd_remove_devices(max77693->dev); regmap_del_irq_chip(max77693->irq, max77693->irq_data_muic); - regmap_del_irq_chip(max77693->irq, max77693->irq_data_charger); + regmap_del_irq_chip(max77693->irq, max77693->irq_data_chg); regmap_del_irq_chip(max77693->irq, max77693->irq_data_topsys); regmap_del_irq_chip(max77693->irq, max77693->irq_data_led); - i2c_unregister_device(max77693->muic); - i2c_unregister_device(max77693->haptic); + i2c_unregister_device(max77693->i2c_muic); + i2c_unregister_device(max77693->i2c_haptic); return 0; } diff --git a/drivers/power/max77693_charger.c b/drivers/power/max77693_charger.c index 754879eb59f6..060cab5ae3aa 100644 --- a/drivers/power/max77693_charger.c +++ b/drivers/power/max77693_charger.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #define MAX77693_CHARGER_NAME "max77693-charger" diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c index 236851ab575a..c6ab440a74b7 100644 --- a/drivers/regulator/max77693.c +++ b/drivers/regulator/max77693.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include diff --git a/include/linux/mfd/max77693-common.h b/include/linux/mfd/max77693-common.h new file mode 100644 index 000000000000..7da4cc38e982 --- /dev/null +++ b/include/linux/mfd/max77693-common.h @@ -0,0 +1,44 @@ +/* + * Common data shared between Maxim 77693 and 77843 drivers + * + * Copyright (C) 2015 Samsung Electronics + * + * 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 __LINUX_MFD_MAX77693_COMMON_H +#define __LINUX_MFD_MAX77693_COMMON_H + +enum max77693_types { + TYPE_MAX77693_UNKNOWN, + TYPE_MAX77693, +}; + +/* + * Shared also with max77843. + */ +struct max77693_dev { + struct device *dev; + struct i2c_client *i2c; /* 0xCC , PMIC, Charger, Flash LED */ + struct i2c_client *i2c_muic; /* 0x4A , MUIC */ + struct i2c_client *i2c_haptic; /* MAX77693: 0x90 , Haptic */ + + enum max77693_types type; + + struct regmap *regmap; + struct regmap *regmap_muic; + struct regmap *regmap_haptic; /* Only MAX77693 */ + + struct regmap_irq_chip_data *irq_data_led; + struct regmap_irq_chip_data *irq_data_topsys; + struct regmap_irq_chip_data *irq_data_chg; /* Only MAX77693 */ + struct regmap_irq_chip_data *irq_data_muic; + + int irq; +}; + + +#endif /* __LINUX_MFD_MAX77693_COMMON_H */ diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h index e3c0afff38d3..8c4143c0c651 100644 --- a/include/linux/mfd/max77693-private.h +++ b/include/linux/mfd/max77693-private.h @@ -529,29 +529,4 @@ enum max77693_irq_muic { MAX77693_MUIC_IRQ_NR, }; -enum max77693_types { - TYPE_MAX77693_UNKNOWN, - TYPE_MAX77693, -}; - -struct max77693_dev { - struct device *dev; - struct i2c_client *i2c; /* 0xCC , PMIC, Charger, Flash LED */ - struct i2c_client *muic; /* 0x4A , MUIC */ - struct i2c_client *haptic; /* 0x90 , Haptic */ - - enum max77693_types type; - - struct regmap *regmap; - struct regmap *regmap_muic; - struct regmap *regmap_haptic; - - struct regmap_irq_chip_data *irq_data_led; - struct regmap_irq_chip_data *irq_data_topsys; - struct regmap_irq_chip_data *irq_data_charger; - struct regmap_irq_chip_data *irq_data_muic; - - int irq; -}; - #endif /* __LINUX_MFD_MAX77693_PRIV_H */ -- cgit v1.3-6-gb490 From bc1aadc18621ccf93fb33ecbb847b422c354899d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 15 Jul 2015 21:59:51 +0900 Subject: drivers: max77843: Switch to common max77693 state container Switch to the same definition of state container as in MAX77693 drivers. This will allow usage of one regulator driver in both devices: MAX77693 and MAX77843. Signed-off-by: Krzysztof Kozlowski Acked-by: Dmitry Torokhov Acked-by: Lee Jones Acked-by: Chanwoo Choi Signed-off-by: Mark Brown --- drivers/extcon/extcon-max77843.c | 17 +++++++++-------- drivers/input/misc/max77843-haptic.c | 3 ++- drivers/mfd/max77843.c | 20 +++++++++++--------- drivers/regulator/max77843.c | 6 ++++-- include/linux/mfd/max77693-common.h | 5 +++++ include/linux/mfd/max77843-private.h | 20 -------------------- 6 files changed, 31 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c index fac2f1417a79..4dfe0a6337d8 100644 --- a/drivers/extcon/extcon-max77843.c +++ b/drivers/extcon/extcon-max77843.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -32,7 +33,7 @@ enum max77843_muic_status { struct max77843_muic_info { struct device *dev; - struct max77843 *max77843; + struct max77693_dev *max77843; struct extcon_dev *edev; struct mutex mutex; @@ -198,7 +199,7 @@ static const struct regmap_irq_chip max77843_muic_irq_chip = { static int max77843_muic_set_path(struct max77843_muic_info *info, u8 val, bool attached) { - struct max77843 *max77843 = info->max77843; + struct max77693_dev *max77843 = info->max77843; int ret = 0; unsigned int ctrl1, ctrl2; @@ -539,7 +540,7 @@ static void max77843_muic_irq_work(struct work_struct *work) { struct max77843_muic_info *info = container_of(work, struct max77843_muic_info, irq_work); - struct max77843 *max77843 = info->max77843; + struct max77693_dev *max77843 = info->max77843; int ret = 0; mutex_lock(&info->mutex); @@ -615,7 +616,7 @@ static void max77843_muic_detect_cable_wq(struct work_struct *work) { struct max77843_muic_info *info = container_of(to_delayed_work(work), struct max77843_muic_info, wq_detcable); - struct max77843 *max77843 = info->max77843; + struct max77693_dev *max77843 = info->max77843; int chg_type, adc, ret; bool attached; @@ -656,7 +657,7 @@ err_cable_wq: static int max77843_muic_set_debounce_time(struct max77843_muic_info *info, enum max77843_muic_adc_debounce_time time) { - struct max77843 *max77843 = info->max77843; + struct max77693_dev *max77843 = info->max77843; int ret; switch (time) { @@ -681,7 +682,7 @@ static int max77843_muic_set_debounce_time(struct max77843_muic_info *info, return 0; } -static int max77843_init_muic_regmap(struct max77843 *max77843) +static int max77843_init_muic_regmap(struct max77693_dev *max77843) { int ret; @@ -720,7 +721,7 @@ err_muic_i2c: static int max77843_muic_probe(struct platform_device *pdev) { - struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent); + struct max77693_dev *max77843 = dev_get_drvdata(pdev->dev.parent); struct max77843_muic_info *info; unsigned int id; int i, ret; @@ -821,7 +822,7 @@ err_muic_irq: static int max77843_muic_remove(struct platform_device *pdev) { struct max77843_muic_info *info = platform_get_drvdata(pdev); - struct max77843 *max77843 = info->max77843; + struct max77693_dev *max77843 = info->max77843; cancel_work_sync(&info->irq_work); regmap_del_irq_chip(max77843->irq, max77843->irq_data_muic); diff --git a/drivers/input/misc/max77843-haptic.c b/drivers/input/misc/max77843-haptic.c index dccbb465a055..30da81ab5a21 100644 --- a/drivers/input/misc/max77843-haptic.c +++ b/drivers/input/misc/max77843-haptic.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -243,7 +244,7 @@ static void max77843_haptic_close(struct input_dev *dev) static int max77843_haptic_probe(struct platform_device *pdev) { - struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent); + struct max77693_dev *max77843 = dev_get_drvdata(pdev->dev.parent); struct max77843_haptic *haptic; int error; diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c index a354ac677ec7..c52162ea3d0a 100644 --- a/drivers/mfd/max77843.c +++ b/drivers/mfd/max77843.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -71,7 +72,7 @@ static const struct regmap_irq_chip max77843_irq_chip = { }; /* Charger and Charger regulator use same regmap. */ -static int max77843_chg_init(struct max77843 *max77843) +static int max77843_chg_init(struct max77693_dev *max77843) { int ret; @@ -101,7 +102,7 @@ err_chg_i2c: static int max77843_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct max77843 *max77843; + struct max77693_dev *max77843; unsigned int reg_data; int ret; @@ -113,6 +114,7 @@ static int max77843_probe(struct i2c_client *i2c, max77843->dev = &i2c->dev; max77843->i2c = i2c; max77843->irq = i2c->irq; + max77843->type = id->driver_data; max77843->regmap = devm_regmap_init_i2c(i2c, &max77843_regmap_config); @@ -123,7 +125,7 @@ static int max77843_probe(struct i2c_client *i2c, ret = regmap_add_irq_chip(max77843->regmap, max77843->irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, - 0, &max77843_irq_chip, &max77843->irq_data); + 0, &max77843_irq_chip, &max77843->irq_data_topsys); if (ret) { dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n"); return ret; @@ -164,18 +166,18 @@ static int max77843_probe(struct i2c_client *i2c, return 0; err_pmic_id: - regmap_del_irq_chip(max77843->irq, max77843->irq_data); + regmap_del_irq_chip(max77843->irq, max77843->irq_data_topsys); return ret; } static int max77843_remove(struct i2c_client *i2c) { - struct max77843 *max77843 = i2c_get_clientdata(i2c); + struct max77693_dev *max77843 = i2c_get_clientdata(i2c); mfd_remove_devices(max77843->dev); - regmap_del_irq_chip(max77843->irq, max77843->irq_data); + regmap_del_irq_chip(max77843->irq, max77843->irq_data_topsys); i2c_unregister_device(max77843->i2c_chg); @@ -188,7 +190,7 @@ static const struct of_device_id max77843_dt_match[] = { }; static const struct i2c_device_id max77843_id[] = { - { "max77843", }, + { "max77843", TYPE_MAX77843, }, { }, }; MODULE_DEVICE_TABLE(i2c, max77843_id); @@ -196,7 +198,7 @@ MODULE_DEVICE_TABLE(i2c, max77843_id); static int __maybe_unused max77843_suspend(struct device *dev) { struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); - struct max77843 *max77843 = i2c_get_clientdata(i2c); + struct max77693_dev *max77843 = i2c_get_clientdata(i2c); disable_irq(max77843->irq); if (device_may_wakeup(dev)) @@ -208,7 +210,7 @@ static int __maybe_unused max77843_suspend(struct device *dev) static int __maybe_unused max77843_resume(struct device *dev) { struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); - struct max77843 *max77843 = i2c_get_clientdata(i2c); + struct max77693_dev *max77843 = i2c_get_clientdata(i2c); if (device_may_wakeup(dev)) disable_irq_wake(max77843->irq); diff --git a/drivers/regulator/max77843.c b/drivers/regulator/max77843.c index f4fd0d3cfa6e..9926247aae6b 100644 --- a/drivers/regulator/max77843.c +++ b/drivers/regulator/max77843.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -130,7 +131,8 @@ static const struct regulator_desc max77843_supported_regulators[] = { }, }; -static struct regmap *max77843_get_regmap(struct max77843 *max77843, int reg_id) +static struct regmap *max77843_get_regmap(struct max77693_dev *max77843, + int reg_id) { switch (reg_id) { case MAX77843_SAFEOUT1: @@ -145,7 +147,7 @@ static struct regmap *max77843_get_regmap(struct max77843 *max77843, int reg_id) static int max77843_regulator_probe(struct platform_device *pdev) { - struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent); + struct max77693_dev *max77843 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = {}; int i; diff --git a/include/linux/mfd/max77693-common.h b/include/linux/mfd/max77693-common.h index 7da4cc38e982..095b121aa725 100644 --- a/include/linux/mfd/max77693-common.h +++ b/include/linux/mfd/max77693-common.h @@ -15,6 +15,9 @@ enum max77693_types { TYPE_MAX77693_UNKNOWN, TYPE_MAX77693, + TYPE_MAX77843, + + TYPE_MAX77693_NUM, }; /* @@ -25,12 +28,14 @@ struct max77693_dev { struct i2c_client *i2c; /* 0xCC , PMIC, Charger, Flash LED */ struct i2c_client *i2c_muic; /* 0x4A , MUIC */ struct i2c_client *i2c_haptic; /* MAX77693: 0x90 , Haptic */ + struct i2c_client *i2c_chg; /* MAX77843: 0xD2, Charger */ enum max77693_types type; struct regmap *regmap; struct regmap *regmap_muic; struct regmap *regmap_haptic; /* Only MAX77693 */ + struct regmap *regmap_chg; /* Only MAX77843 */ struct regmap_irq_chip_data *irq_data_led; struct regmap_irq_chip_data *irq_data_topsys; diff --git a/include/linux/mfd/max77843-private.h b/include/linux/mfd/max77843-private.h index 7178ace8379e..0121d9440340 100644 --- a/include/linux/mfd/max77843-private.h +++ b/include/linux/mfd/max77843-private.h @@ -431,24 +431,4 @@ enum max77843_irq_muic { #define MAX77843_REG_SAFEOUTCTRL_SAFEOUT2_MASK \ (0x3 << SAFEOUTCTRL_SAFEOUT2_SHIFT) -struct max77843 { - struct device *dev; - - struct i2c_client *i2c; - struct i2c_client *i2c_chg; - struct i2c_client *i2c_fuel; - struct i2c_client *i2c_muic; - - struct regmap *regmap; - struct regmap *regmap_chg; - struct regmap *regmap_fuel; - struct regmap *regmap_muic; - - struct regmap_irq_chip_data *irq_data; - struct regmap_irq_chip_data *irq_data_chg; - struct regmap_irq_chip_data *irq_data_fuel; - struct regmap_irq_chip_data *irq_data_muic; - - int irq; -}; #endif /* __MAX77843_H__ */ -- cgit v1.3-6-gb490 From cceb433a1e2930301b33c79016eff147eb555cea Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 15 Jul 2015 21:59:52 +0900 Subject: mfd/extcon: max77693: Rename defines to allow inclusion with max77843 Add MAX77693 prefix to some of the defines used in max77693 extcon driver so the max77693-private.h can be included simultaneously with max77843-private.h. Additionally use BIT() macro in header. Signed-off-by: Krzysztof Kozlowski Acked-by: Lee Jones Acked-by: Chanwoo Choi Signed-off-by: Mark Brown --- drivers/extcon/extcon-max77693.c | 72 +++++++++++++------------ include/linux/mfd/max77693-private.h | 102 +++++++++++++++++------------------ 2 files changed, 89 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index c7bb180cfff4..35b9e118b2fb 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -43,7 +43,7 @@ static struct max77693_reg_data default_init_data[] = { { /* STATUS2 - [3]ChgDetRun */ .addr = MAX77693_MUIC_REG_STATUS2, - .data = STATUS2_CHGDETRUN_MASK, + .data = MAX77693_STATUS2_CHGDETRUN_MASK, }, { /* INTMASK1 - Unmask [3]ADC1KM,[0]ADCM */ .addr = MAX77693_MUIC_REG_INTMASK1, @@ -236,7 +236,7 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info, */ ret = regmap_write(info->max77693->regmap_muic, MAX77693_MUIC_REG_CTRL3, - time << CONTROL3_ADCDBSET_SHIFT); + time << MAX77693_CONTROL3_ADCDBSET_SHIFT); if (ret) { dev_err(info->dev, "failed to set ADC debounce time\n"); return ret; @@ -269,7 +269,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info, if (attached) ctrl1 = val; else - ctrl1 = CONTROL1_SW_OPEN; + ctrl1 = MAX77693_CONTROL1_SW_OPEN; ret = regmap_update_bits(info->max77693->regmap_muic, MAX77693_MUIC_REG_CTRL1, COMP_SW_MASK, ctrl1); @@ -279,13 +279,14 @@ static int max77693_muic_set_path(struct max77693_muic_info *info, } if (attached) - ctrl2 |= CONTROL2_CPEN_MASK; /* LowPwr=0, CPEn=1 */ + ctrl2 |= MAX77693_CONTROL2_CPEN_MASK; /* LowPwr=0, CPEn=1 */ else - ctrl2 |= CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */ + ctrl2 |= MAX77693_CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */ ret = regmap_update_bits(info->max77693->regmap_muic, MAX77693_MUIC_REG_CTRL2, - CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK, ctrl2); + MAX77693_CONTROL2_LOWPWR_MASK | MAX77693_CONTROL2_CPEN_MASK, + ctrl2); if (ret < 0) { dev_err(info->dev, "failed to update MUIC register\n"); return ret; @@ -327,8 +328,8 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, * Read ADC value to check cable type and decide cable state * according to cable type */ - adc = info->status[0] & STATUS1_ADC_MASK; - adc >>= STATUS1_ADC_SHIFT; + adc = info->status[0] & MAX77693_STATUS1_ADC_MASK; + adc >>= MAX77693_STATUS1_ADC_SHIFT; /* * Check current cable state/cable type and store cable type @@ -351,8 +352,8 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, * Read ADC value to check cable type and decide cable state * according to cable type */ - adc = info->status[0] & STATUS1_ADC_MASK; - adc >>= STATUS1_ADC_SHIFT; + adc = info->status[0] & MAX77693_STATUS1_ADC_MASK; + adc >>= MAX77693_STATUS1_ADC_SHIFT; /* * Check current cable state/cable type and store cable type @@ -367,13 +368,13 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, } else { *attached = true; - adclow = info->status[0] & STATUS1_ADCLOW_MASK; - adclow >>= STATUS1_ADCLOW_SHIFT; - adc1k = info->status[0] & STATUS1_ADC1K_MASK; - adc1k >>= STATUS1_ADC1K_SHIFT; + adclow = info->status[0] & MAX77693_STATUS1_ADCLOW_MASK; + adclow >>= MAX77693_STATUS1_ADCLOW_SHIFT; + adc1k = info->status[0] & MAX77693_STATUS1_ADC1K_MASK; + adc1k >>= MAX77693_STATUS1_ADC1K_SHIFT; - vbvolt = info->status[1] & STATUS2_VBVOLT_MASK; - vbvolt >>= STATUS2_VBVOLT_SHIFT; + vbvolt = info->status[1] & MAX77693_STATUS2_VBVOLT_MASK; + vbvolt >>= MAX77693_STATUS2_VBVOLT_SHIFT; /** * [0x1|VBVolt|ADCLow|ADC1K] @@ -398,8 +399,8 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, * Read charger type to check cable type and decide cable state * according to type of charger cable. */ - chg_type = info->status[1] & STATUS2_CHGTYP_MASK; - chg_type >>= STATUS2_CHGTYP_SHIFT; + chg_type = info->status[1] & MAX77693_STATUS2_CHGTYP_MASK; + chg_type >>= MAX77693_STATUS2_CHGTYP_SHIFT; if (chg_type == MAX77693_CHARGER_TYPE_NONE) { *attached = false; @@ -423,10 +424,10 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, * Read ADC value to check cable type and decide cable state * according to cable type */ - adc = info->status[0] & STATUS1_ADC_MASK; - adc >>= STATUS1_ADC_SHIFT; - chg_type = info->status[1] & STATUS2_CHGTYP_MASK; - chg_type >>= STATUS2_CHGTYP_SHIFT; + adc = info->status[0] & MAX77693_STATUS1_ADC_MASK; + adc >>= MAX77693_STATUS1_ADC_SHIFT; + chg_type = info->status[1] & MAX77693_STATUS2_CHGTYP_MASK; + chg_type >>= MAX77693_STATUS2_CHGTYP_SHIFT; if (adc == MAX77693_MUIC_ADC_OPEN && chg_type == MAX77693_CHARGER_TYPE_NONE) @@ -438,8 +439,8 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info, * Read vbvolt field, if vbvolt is 1, * this cable is used for charging. */ - vbvolt = info->status[1] & STATUS2_VBVOLT_MASK; - vbvolt >>= STATUS2_VBVOLT_SHIFT; + vbvolt = info->status[1] & MAX77693_STATUS2_VBVOLT_MASK; + vbvolt >>= MAX77693_STATUS2_VBVOLT_SHIFT; cable_type = vbvolt; break; @@ -521,7 +522,8 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, } /* Dock-Car/Desk/Audio, PATH:AUDIO */ - ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); + ret = max77693_muic_set_path(info, MAX77693_CONTROL1_SW_AUDIO, + attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, dock_id, attached); @@ -586,14 +588,16 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) case MAX77693_MUIC_GND_USB_HOST: case MAX77693_MUIC_GND_USB_HOST_VB: /* USB_HOST, PATH: AP_USB */ - ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached); + ret = max77693_muic_set_path(info, MAX77693_CONTROL1_SW_USB, + attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached); break; case MAX77693_MUIC_GND_AV_CABLE_LOAD: /* Audio Video Cable with load, PATH:AUDIO */ - ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); + ret = max77693_muic_set_path(info, MAX77693_CONTROL1_SW_AUDIO, + attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_USB, attached); @@ -616,7 +620,7 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info, int cable_type, bool attached) { int ret = 0; - u8 path = CONTROL1_SW_OPEN; + u8 path = MAX77693_CONTROL1_SW_OPEN; dev_info(info->dev, "external connector is %s (adc:0x%02x)\n", @@ -626,12 +630,12 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info, case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */ case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */ /* PATH:AP_USB */ - path = CONTROL1_SW_USB; + path = MAX77693_CONTROL1_SW_USB; break; case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */ case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* ADC_JIG_UART_ON */ /* PATH:AP_UART */ - path = CONTROL1_SW_UART; + path = MAX77693_CONTROL1_SW_UART; break; default: dev_err(info->dev, "failed to detect %s jig cable\n", @@ -1181,12 +1185,12 @@ static int max77693_muic_probe(struct platform_device *pdev) if (muic_pdata->path_uart) info->path_uart = muic_pdata->path_uart; else - info->path_uart = CONTROL1_SW_UART; + info->path_uart = MAX77693_CONTROL1_SW_UART; if (muic_pdata->path_usb) info->path_usb = muic_pdata->path_usb; else - info->path_usb = CONTROL1_SW_USB; + info->path_usb = MAX77693_CONTROL1_SW_USB; /* * Default delay time for detecting cable state @@ -1198,8 +1202,8 @@ static int max77693_muic_probe(struct platform_device *pdev) else delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); } else { - info->path_usb = CONTROL1_SW_USB; - info->path_uart = CONTROL1_SW_UART; + info->path_usb = MAX77693_CONTROL1_SW_USB; + info->path_uart = MAX77693_CONTROL1_SW_UART; delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); } diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h index 8c4143c0c651..3c7a63b98ad6 100644 --- a/include/linux/mfd/max77693-private.h +++ b/include/linux/mfd/max77693-private.h @@ -310,30 +310,30 @@ enum max77693_muic_reg { #define INTMASK2_CHGTYP_MASK (1 << INTMASK2_CHGTYP_SHIFT) /* MAX77693 MUIC - STATUS1~3 Register */ -#define STATUS1_ADC_SHIFT (0) -#define STATUS1_ADCLOW_SHIFT (5) -#define STATUS1_ADCERR_SHIFT (6) -#define STATUS1_ADC1K_SHIFT (7) -#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT) -#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT) -#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT) -#define STATUS1_ADC1K_MASK (0x1 << STATUS1_ADC1K_SHIFT) - -#define STATUS2_CHGTYP_SHIFT (0) -#define STATUS2_CHGDETRUN_SHIFT (3) -#define STATUS2_DCDTMR_SHIFT (4) -#define STATUS2_DXOVP_SHIFT (5) -#define STATUS2_VBVOLT_SHIFT (6) -#define STATUS2_VIDRM_SHIFT (7) -#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT) -#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT) -#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT) -#define STATUS2_DXOVP_MASK (0x1 << STATUS2_DXOVP_SHIFT) -#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT) -#define STATUS2_VIDRM_MASK (0x1 << STATUS2_VIDRM_SHIFT) - -#define STATUS3_OVP_SHIFT (2) -#define STATUS3_OVP_MASK (0x1 << STATUS3_OVP_SHIFT) +#define MAX77693_STATUS1_ADC_SHIFT 0 +#define MAX77693_STATUS1_ADCLOW_SHIFT 5 +#define MAX77693_STATUS1_ADCERR_SHIFT 6 +#define MAX77693_STATUS1_ADC1K_SHIFT 7 +#define MAX77693_STATUS1_ADC_MASK (0x1f << MAX77693_STATUS1_ADC_SHIFT) +#define MAX77693_STATUS1_ADCLOW_MASK BIT(MAX77693_STATUS1_ADCLOW_SHIFT) +#define MAX77693_STATUS1_ADCERR_MASK BIT(MAX77693_STATUS1_ADCERR_SHIFT) +#define MAX77693_STATUS1_ADC1K_MASK BIT(MAX77693_STATUS1_ADC1K_SHIFT) + +#define MAX77693_STATUS2_CHGTYP_SHIFT 0 +#define MAX77693_STATUS2_CHGDETRUN_SHIFT 3 +#define MAX77693_STATUS2_DCDTMR_SHIFT 4 +#define MAX77693_STATUS2_DXOVP_SHIFT 5 +#define MAX77693_STATUS2_VBVOLT_SHIFT 6 +#define MAX77693_STATUS2_VIDRM_SHIFT 7 +#define MAX77693_STATUS2_CHGTYP_MASK (0x7 << MAX77693_STATUS2_CHGTYP_SHIFT) +#define MAX77693_STATUS2_CHGDETRUN_MASK BIT(MAX77693_STATUS2_CHGDETRUN_SHIFT) +#define MAX77693_STATUS2_DCDTMR_MASK BIT(MAX77693_STATUS2_DCDTMR_SHIFT) +#define MAX77693_STATUS2_DXOVP_MASK BIT(MAX77693_STATUS2_DXOVP_SHIFT) +#define MAX77693_STATUS2_VBVOLT_MASK BIT(MAX77693_STATUS2_VBVOLT_SHIFT) +#define MAX77693_STATUS2_VIDRM_MASK BIT(MAX77693_STATUS2_VIDRM_SHIFT) + +#define MAX77693_STATUS3_OVP_SHIFT 2 +#define MAX77693_STATUS3_OVP_MASK BIT(MAX77693_STATUS3_OVP_SHIFT) /* MAX77693 CDETCTRL1~2 register */ #define CDETCTRL1_CHGDETEN_SHIFT (0) @@ -362,38 +362,38 @@ enum max77693_muic_reg { #define COMN1SW_MASK (0x7 << COMN1SW_SHIFT) #define COMP2SW_MASK (0x7 << COMP2SW_SHIFT) #define COMP_SW_MASK (COMP2SW_MASK | COMN1SW_MASK) -#define CONTROL1_SW_USB ((1 << COMP2SW_SHIFT) \ +#define MAX77693_CONTROL1_SW_USB ((1 << COMP2SW_SHIFT) \ | (1 << COMN1SW_SHIFT)) -#define CONTROL1_SW_AUDIO ((2 << COMP2SW_SHIFT) \ +#define MAX77693_CONTROL1_SW_AUDIO ((2 << COMP2SW_SHIFT) \ | (2 << COMN1SW_SHIFT)) -#define CONTROL1_SW_UART ((3 << COMP2SW_SHIFT) \ +#define MAX77693_CONTROL1_SW_UART ((3 << COMP2SW_SHIFT) \ | (3 << COMN1SW_SHIFT)) -#define CONTROL1_SW_OPEN ((0 << COMP2SW_SHIFT) \ +#define MAX77693_CONTROL1_SW_OPEN ((0 << COMP2SW_SHIFT) \ | (0 << COMN1SW_SHIFT)) -#define CONTROL2_LOWPWR_SHIFT (0) -#define CONTROL2_ADCEN_SHIFT (1) -#define CONTROL2_CPEN_SHIFT (2) -#define CONTROL2_SFOUTASRT_SHIFT (3) -#define CONTROL2_SFOUTORD_SHIFT (4) -#define CONTROL2_ACCDET_SHIFT (5) -#define CONTROL2_USBCPINT_SHIFT (6) -#define CONTROL2_RCPS_SHIFT (7) -#define CONTROL2_LOWPWR_MASK (0x1 << CONTROL2_LOWPWR_SHIFT) -#define CONTROL2_ADCEN_MASK (0x1 << CONTROL2_ADCEN_SHIFT) -#define CONTROL2_CPEN_MASK (0x1 << CONTROL2_CPEN_SHIFT) -#define CONTROL2_SFOUTASRT_MASK (0x1 << CONTROL2_SFOUTASRT_SHIFT) -#define CONTROL2_SFOUTORD_MASK (0x1 << CONTROL2_SFOUTORD_SHIFT) -#define CONTROL2_ACCDET_MASK (0x1 << CONTROL2_ACCDET_SHIFT) -#define CONTROL2_USBCPINT_MASK (0x1 << CONTROL2_USBCPINT_SHIFT) -#define CONTROL2_RCPS_MASK (0x1 << CONTROL2_RCPS_SHIFT) - -#define CONTROL3_JIGSET_SHIFT (0) -#define CONTROL3_BTLDSET_SHIFT (2) -#define CONTROL3_ADCDBSET_SHIFT (4) -#define CONTROL3_JIGSET_MASK (0x3 << CONTROL3_JIGSET_SHIFT) -#define CONTROL3_BTLDSET_MASK (0x3 << CONTROL3_BTLDSET_SHIFT) -#define CONTROL3_ADCDBSET_MASK (0x3 << CONTROL3_ADCDBSET_SHIFT) +#define MAX77693_CONTROL2_LOWPWR_SHIFT 0 +#define MAX77693_CONTROL2_ADCEN_SHIFT 1 +#define MAX77693_CONTROL2_CPEN_SHIFT 2 +#define MAX77693_CONTROL2_SFOUTASRT_SHIFT 3 +#define MAX77693_CONTROL2_SFOUTORD_SHIFT 4 +#define MAX77693_CONTROL2_ACCDET_SHIFT 5 +#define MAX77693_CONTROL2_USBCPINT_SHIFT 6 +#define MAX77693_CONTROL2_RCPS_SHIFT 7 +#define MAX77693_CONTROL2_LOWPWR_MASK BIT(MAX77693_CONTROL2_LOWPWR_SHIFT) +#define MAX77693_CONTROL2_ADCEN_MASK BIT(MAX77693_CONTROL2_ADCEN_SHIFT) +#define MAX77693_CONTROL2_CPEN_MASK BIT(MAX77693_CONTROL2_CPEN_SHIFT) +#define MAX77693_CONTROL2_SFOUTASRT_MASK BIT(MAX77693_CONTROL2_SFOUTASRT_SHIFT) +#define MAX77693_CONTROL2_SFOUTORD_MASK BIT(MAX77693_CONTROL2_SFOUTORD_SHIFT) +#define MAX77693_CONTROL2_ACCDET_MASK BIT(MAX77693_CONTROL2_ACCDET_SHIFT) +#define MAX77693_CONTROL2_USBCPINT_MASK BIT(MAX77693_CONTROL2_USBCPINT_SHIFT) +#define MAX77693_CONTROL2_RCPS_MASK BIT(MAX77693_CONTROL2_RCPS_SHIFT) + +#define MAX77693_CONTROL3_JIGSET_SHIFT 0 +#define MAX77693_CONTROL3_BTLDSET_SHIFT 2 +#define MAX77693_CONTROL3_ADCDBSET_SHIFT 4 +#define MAX77693_CONTROL3_JIGSET_MASK (0x3 << MAX77693_CONTROL3_JIGSET_SHIFT) +#define MAX77693_CONTROL3_BTLDSET_MASK (0x3 << MAX77693_CONTROL3_BTLDSET_SHIFT) +#define MAX77693_CONTROL3_ADCDBSET_MASK (0x3 << MAX77693_CONTROL3_ADCDBSET_SHIFT) /* Slave addr = 0x90: Haptic */ enum max77693_haptic_reg { -- cgit v1.3-6-gb490 From 309a3e00a511a233acb25eec567a4b11c99d016a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 15 Jul 2015 21:59:53 +0900 Subject: mfd/extcon: max77843: Rename defines to allow inclusion with max77693 Add MAX77843_MUIC prefix to some of the defines used in max77843 extcon driver so the max77693-private.h can be included simultaneously with max77843-private.h. Signed-off-by: Krzysztof Kozlowski Acked-by: Lee Jones Acked-by: Chanwoo Choi Signed-off-by: Mark Brown --- drivers/extcon/extcon-max77843.c | 49 +++++++---- include/linux/mfd/max77843-private.h | 154 +++++++++++++++++------------------ 2 files changed, 109 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c index 4dfe0a6337d8..f652c4199870 100644 --- a/drivers/extcon/extcon-max77843.c +++ b/drivers/extcon/extcon-max77843.c @@ -206,11 +206,11 @@ static int max77843_muic_set_path(struct max77843_muic_info *info, if (attached) ctrl1 = val; else - ctrl1 = CONTROL1_SW_OPEN; + ctrl1 = MAX77843_MUIC_CONTROL1_SW_OPEN; ret = regmap_update_bits(max77843->regmap_muic, MAX77843_MUIC_REG_CONTROL1, - CONTROL1_COM_SW, ctrl1); + MAX77843_MUIC_CONTROL1_COM_SW, ctrl1); if (ret < 0) { dev_err(info->dev, "Cannot switch MUIC port\n"); return ret; @@ -244,7 +244,7 @@ static int max77843_muic_get_cable_type(struct max77843_muic_info *info, adc = info->status[MAX77843_MUIC_STATUS1] & MAX77843_MUIC_STATUS1_ADC_MASK; - adc >>= STATUS1_ADC_SHIFT; + adc >>= MAX77843_MUIC_STATUS1_ADC_SHIFT; switch (group) { case MAX77843_CABLE_GROUP_ADC: @@ -310,7 +310,7 @@ static int max77843_muic_get_cable_type(struct max77843_muic_info *info, /* Get VBVolt register bit */ gnd_type |= (info->status[MAX77843_MUIC_STATUS2] & MAX77843_MUIC_STATUS2_VBVOLT_MASK); - gnd_type >>= STATUS2_VBVOLT_SHIFT; + gnd_type >>= MAX77843_MUIC_STATUS2_VBVOLT_SHIFT; /* Offset of GND cable */ gnd_type |= MAX77843_MUIC_GND_USB_HOST; @@ -339,7 +339,9 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info) switch (gnd_cable_type) { case MAX77843_MUIC_GND_USB_HOST: case MAX77843_MUIC_GND_USB_HOST_VB: - ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_USB, + attached); if (ret < 0) return ret; @@ -347,7 +349,9 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info) break; case MAX77843_MUIC_GND_MHL_VB: case MAX77843_MUIC_GND_MHL: - ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); if (ret < 0) return ret; @@ -366,7 +370,7 @@ static int max77843_muic_jig_handler(struct max77843_muic_info *info, int cable_type, bool attached) { int ret; - u8 path = CONTROL1_SW_OPEN; + u8 path = MAX77843_MUIC_CONTROL1_SW_OPEN; dev_dbg(info->dev, "external connector is %s (adc:0x%02x)\n", attached ? "attached" : "detached", cable_type); @@ -374,10 +378,10 @@ static int max77843_muic_jig_handler(struct max77843_muic_info *info, switch (cable_type) { case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF: case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON: - path = CONTROL1_SW_USB; + path = MAX77843_MUIC_CONTROL1_SW_USB; break; case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF: - path = CONTROL1_SW_UART; + path = MAX77843_MUIC_CONTROL1_SW_UART; break; default: return -EINVAL; @@ -475,14 +479,18 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) switch (chg_type) { case MAX77843_MUIC_CHG_USB: - ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_USB, + attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_USB, attached); break; case MAX77843_MUIC_CHG_DOWNSTREAM: - ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); if (ret < 0) return ret; @@ -490,14 +498,18 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) attached); break; case MAX77843_MUIC_CHG_DEDICATED: - ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_TA, attached); break; case MAX77843_MUIC_CHG_SPECIAL_500MA: - ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); if (ret < 0) return ret; @@ -505,7 +517,9 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) attached); break; case MAX77843_MUIC_CHG_SPECIAL_1A: - ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + ret = max77843_muic_set_path(info, + MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); if (ret < 0) return ret; @@ -529,7 +543,8 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) "failed to detect %s accessory (chg_type:0x%x)\n", attached ? "attached" : "detached", chg_type); - max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); + max77843_muic_set_path(info, MAX77843_MUIC_CONTROL1_SW_OPEN, + attached); return -EINVAL; } @@ -668,7 +683,7 @@ static int max77843_muic_set_debounce_time(struct max77843_muic_info *info, ret = regmap_update_bits(max77843->regmap_muic, MAX77843_MUIC_REG_CONTROL4, MAX77843_MUIC_CONTROL4_ADCDBSET_MASK, - time << CONTROL4_ADCDBSET_SHIFT); + time << MAX77843_MUIC_CONTROL4_ADCDBSET_SHIFT); if (ret < 0) { dev_err(info->dev, "Cannot write MUIC regmap\n"); return ret; @@ -769,7 +784,7 @@ static int max77843_muic_probe(struct platform_device *pdev) max77843_muic_set_debounce_time(info, MAX77843_DEBOUNCE_TIME_25MS); /* Set initial path for UART */ - max77843_muic_set_path(info, CONTROL1_SW_UART, true); + max77843_muic_set_path(info, MAX77843_MUIC_CONTROL1_SW_UART, true); /* Check revision number of MUIC device */ ret = regmap_read(max77843->regmap_muic, MAX77843_MUIC_REG_ID, &id); diff --git a/include/linux/mfd/max77843-private.h b/include/linux/mfd/max77843-private.h index 0121d9440340..c19303b0ccfd 100644 --- a/include/linux/mfd/max77843-private.h +++ b/include/linux/mfd/max77843-private.h @@ -318,62 +318,62 @@ enum max77843_irq_muic { MAX77843_INTSRCMASK_SYS_MASK | MAX77843_INTSRCMASK_CHGR_MASK) /* MAX77843 STATUS register*/ -#define STATUS1_ADC_SHIFT 0 -#define STATUS1_ADCERROR_SHIFT 6 -#define STATUS1_ADC1K_SHIFT 7 -#define STATUS2_CHGTYP_SHIFT 0 -#define STATUS2_CHGDETRUN_SHIFT 3 -#define STATUS2_DCDTMR_SHIFT 4 -#define STATUS2_DXOVP_SHIFT 5 -#define STATUS2_VBVOLT_SHIFT 6 -#define STATUS3_VBADC_SHIFT 0 -#define STATUS3_VDNMON_SHIFT 4 -#define STATUS3_DNRES_SHIFT 5 -#define STATUS3_MPNACK_SHIFT 6 - -#define MAX77843_MUIC_STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT) -#define MAX77843_MUIC_STATUS1_ADCERROR_MASK BIT(STATUS1_ADCERROR_SHIFT) -#define MAX77843_MUIC_STATUS1_ADC1K_MASK BIT(STATUS1_ADC1K_SHIFT) -#define MAX77843_MUIC_STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT) -#define MAX77843_MUIC_STATUS2_CHGDETRUN_MASK BIT(STATUS2_CHGDETRUN_SHIFT) -#define MAX77843_MUIC_STATUS2_DCDTMR_MASK BIT(STATUS2_DCDTMR_SHIFT) -#define MAX77843_MUIC_STATUS2_DXOVP_MASK BIT(STATUS2_DXOVP_SHIFT) -#define MAX77843_MUIC_STATUS2_VBVOLT_MASK BIT(STATUS2_VBVOLT_SHIFT) -#define MAX77843_MUIC_STATUS3_VBADC_MASK (0xf << STATUS3_VBADC_SHIFT) -#define MAX77843_MUIC_STATUS3_VDNMON_MASK BIT(STATUS3_VDNMON_SHIFT) -#define MAX77843_MUIC_STATUS3_DNRES_MASK BIT(STATUS3_DNRES_SHIFT) -#define MAX77843_MUIC_STATUS3_MPNACK_MASK BIT(STATUS3_MPNACK_SHIFT) +#define MAX77843_MUIC_STATUS1_ADC_SHIFT 0 +#define MAX77843_MUIC_STATUS1_ADCERROR_SHIFT 6 +#define MAX77843_MUIC_STATUS1_ADC1K_SHIFT 7 +#define MAX77843_MUIC_STATUS2_CHGTYP_SHIFT 0 +#define MAX77843_MUIC_STATUS2_CHGDETRUN_SHIFT 3 +#define MAX77843_MUIC_STATUS2_DCDTMR_SHIFT 4 +#define MAX77843_MUIC_STATUS2_DXOVP_SHIFT 5 +#define MAX77843_MUIC_STATUS2_VBVOLT_SHIFT 6 +#define MAX77843_MUIC_STATUS3_VBADC_SHIFT 0 +#define MAX77843_MUIC_STATUS3_VDNMON_SHIFT 4 +#define MAX77843_MUIC_STATUS3_DNRES_SHIFT 5 +#define MAX77843_MUIC_STATUS3_MPNACK_SHIFT 6 + +#define MAX77843_MUIC_STATUS1_ADC_MASK (0x1f << MAX77843_MUIC_STATUS1_ADC_SHIFT) +#define MAX77843_MUIC_STATUS1_ADCERROR_MASK BIT(MAX77843_MUIC_STATUS1_ADCERROR_SHIFT) +#define MAX77843_MUIC_STATUS1_ADC1K_MASK BIT(MAX77843_MUIC_STATUS1_ADC1K_SHIFT) +#define MAX77843_MUIC_STATUS2_CHGTYP_MASK (0x7 << MAX77843_MUIC_STATUS2_CHGTYP_SHIFT) +#define MAX77843_MUIC_STATUS2_CHGDETRUN_MASK BIT(MAX77843_MUIC_STATUS2_CHGDETRUN_SHIFT) +#define MAX77843_MUIC_STATUS2_DCDTMR_MASK BIT(MAX77843_MUIC_STATUS2_DCDTMR_SHIFT) +#define MAX77843_MUIC_STATUS2_DXOVP_MASK BIT(MAX77843_MUIC_STATUS2_DXOVP_SHIFT) +#define MAX77843_MUIC_STATUS2_VBVOLT_MASK BIT(MAX77843_MUIC_STATUS2_VBVOLT_SHIFT) +#define MAX77843_MUIC_STATUS3_VBADC_MASK (0xf << MAX77843_MUIC_STATUS3_VBADC_SHIFT) +#define MAX77843_MUIC_STATUS3_VDNMON_MASK BIT(MAX77843_MUIC_STATUS3_VDNMON_SHIFT) +#define MAX77843_MUIC_STATUS3_DNRES_MASK BIT(MAX77843_MUIC_STATUS3_DNRES_SHIFT) +#define MAX77843_MUIC_STATUS3_MPNACK_MASK BIT(MAX77843_MUIC_STATUS3_MPNACK_SHIFT) /* MAX77843 CONTROL register */ -#define CONTROL1_COMP1SW_SHIFT 0 -#define CONTROL1_COMP2SW_SHIFT 3 -#define CONTROL1_IDBEN_SHIFT 7 -#define CONTROL2_LOWPWR_SHIFT 0 -#define CONTROL2_ADCEN_SHIFT 1 -#define CONTROL2_CPEN_SHIFT 2 -#define CONTROL2_ACC_DET_SHIFT 5 -#define CONTROL2_USBCPINT_SHIFT 6 -#define CONTROL2_RCPS_SHIFT 7 -#define CONTROL3_JIGSET_SHIFT 0 -#define CONTROL4_ADCDBSET_SHIFT 0 -#define CONTROL4_USBAUTO_SHIFT 4 -#define CONTROL4_FCTAUTO_SHIFT 5 -#define CONTROL4_ADCMODE_SHIFT 6 - -#define MAX77843_MUIC_CONTROL1_COMP1SW_MASK (0x7 << CONTROL1_COMP1SW_SHIFT) -#define MAX77843_MUIC_CONTROL1_COMP2SW_MASK (0x7 << CONTROL1_COMP2SW_SHIFT) -#define MAX77843_MUIC_CONTROL1_IDBEN_MASK BIT(CONTROL1_IDBEN_SHIFT) -#define MAX77843_MUIC_CONTROL2_LOWPWR_MASK BIT(CONTROL2_LOWPWR_SHIFT) -#define MAX77843_MUIC_CONTROL2_ADCEN_MASK BIT(CONTROL2_ADCEN_SHIFT) -#define MAX77843_MUIC_CONTROL2_CPEN_MASK BIT(CONTROL2_CPEN_SHIFT) -#define MAX77843_MUIC_CONTROL2_ACC_DET_MASK BIT(CONTROL2_ACC_DET_SHIFT) -#define MAX77843_MUIC_CONTROL2_USBCPINT_MASK BIT(CONTROL2_USBCPINT_SHIFT) -#define MAX77843_MUIC_CONTROL2_RCPS_MASK BIT(CONTROL2_RCPS_SHIFT) -#define MAX77843_MUIC_CONTROL3_JIGSET_MASK (0x3 << CONTROL3_JIGSET_SHIFT) -#define MAX77843_MUIC_CONTROL4_ADCDBSET_MASK (0x3 << CONTROL4_ADCDBSET_SHIFT) -#define MAX77843_MUIC_CONTROL4_USBAUTO_MASK BIT(CONTROL4_USBAUTO_SHIFT) -#define MAX77843_MUIC_CONTROL4_FCTAUTO_MASK BIT(CONTROL4_FCTAUTO_SHIFT) -#define MAX77843_MUIC_CONTROL4_ADCMODE_MASK (0x3 << CONTROL4_ADCMODE_SHIFT) +#define MAX77843_MUIC_CONTROL1_COMP1SW_SHIFT 0 +#define MAX77843_MUIC_CONTROL1_COMP2SW_SHIFT 3 +#define MAX77843_MUIC_CONTROL1_IDBEN_SHIFT 7 +#define MAX77843_MUIC_CONTROL2_LOWPWR_SHIFT 0 +#define MAX77843_MUIC_CONTROL2_ADCEN_SHIFT 1 +#define MAX77843_MUIC_CONTROL2_CPEN_SHIFT 2 +#define MAX77843_MUIC_CONTROL2_ACC_DET_SHIFT 5 +#define MAX77843_MUIC_CONTROL2_USBCPINT_SHIFT 6 +#define MAX77843_MUIC_CONTROL2_RCPS_SHIFT 7 +#define MAX77843_MUIC_CONTROL3_JIGSET_SHIFT 0 +#define MAX77843_MUIC_CONTROL4_ADCDBSET_SHIFT 0 +#define MAX77843_MUIC_CONTROL4_USBAUTO_SHIFT 4 +#define MAX77843_MUIC_CONTROL4_FCTAUTO_SHIFT 5 +#define MAX77843_MUIC_CONTROL4_ADCMODE_SHIFT 6 + +#define MAX77843_MUIC_CONTROL1_COMP1SW_MASK (0x7 << MAX77843_MUIC_CONTROL1_COMP1SW_SHIFT) +#define MAX77843_MUIC_CONTROL1_COMP2SW_MASK (0x7 << MAX77843_MUIC_CONTROL1_COMP2SW_SHIFT) +#define MAX77843_MUIC_CONTROL1_IDBEN_MASK BIT(MAX77843_MUIC_CONTROL1_IDBEN_SHIFT) +#define MAX77843_MUIC_CONTROL2_LOWPWR_MASK BIT(MAX77843_MUIC_CONTROL2_LOWPWR_SHIFT) +#define MAX77843_MUIC_CONTROL2_ADCEN_MASK BIT(MAX77843_MUIC_CONTROL2_ADCEN_SHIFT) +#define MAX77843_MUIC_CONTROL2_CPEN_MASK BIT(MAX77843_MUIC_CONTROL2_CPEN_SHIFT) +#define MAX77843_MUIC_CONTROL2_ACC_DET_MASK BIT(MAX77843_MUIC_CONTROL2_ACC_DET_SHIFT) +#define MAX77843_MUIC_CONTROL2_USBCPINT_MASK BIT(MAX77843_MUIC_CONTROL2_USBCPINT_SHIFT) +#define MAX77843_MUIC_CONTROL2_RCPS_MASK BIT(MAX77843_MUIC_CONTROL2_RCPS_SHIFT) +#define MAX77843_MUIC_CONTROL3_JIGSET_MASK (0x3 << MAX77843_MUIC_CONTROL3_JIGSET_SHIFT) +#define MAX77843_MUIC_CONTROL4_ADCDBSET_MASK (0x3 << MAX77843_MUIC_CONTROL4_ADCDBSET_SHIFT) +#define MAX77843_MUIC_CONTROL4_USBAUTO_MASK BIT(MAX77843_MUIC_CONTROL4_USBAUTO_SHIFT) +#define MAX77843_MUIC_CONTROL4_FCTAUTO_MASK BIT(MAX77843_MUIC_CONTROL4_FCTAUTO_SHIFT) +#define MAX77843_MUIC_CONTROL4_ADCMODE_MASK (0x3 << MAX77843_MUIC_CONTROL4_ADCMODE_SHIFT) /* MAX77843 switch port */ #define COM_OPEN 0 @@ -383,38 +383,38 @@ enum max77843_irq_muic { #define COM_AUX_USB 4 #define COM_AUX_UART 5 -#define CONTROL1_COM_SW \ +#define MAX77843_MUIC_CONTROL1_COM_SW \ ((MAX77843_MUIC_CONTROL1_COMP1SW_MASK | \ MAX77843_MUIC_CONTROL1_COMP2SW_MASK)) -#define CONTROL1_SW_OPEN \ - ((COM_OPEN << CONTROL1_COMP1SW_SHIFT | \ - COM_OPEN << CONTROL1_COMP2SW_SHIFT)) -#define CONTROL1_SW_USB \ - ((COM_USB << CONTROL1_COMP1SW_SHIFT | \ - COM_USB << CONTROL1_COMP2SW_SHIFT)) -#define CONTROL1_SW_AUDIO \ - ((COM_AUDIO << CONTROL1_COMP1SW_SHIFT | \ - COM_AUDIO << CONTROL1_COMP2SW_SHIFT)) -#define CONTROL1_SW_UART \ - ((COM_UART << CONTROL1_COMP1SW_SHIFT | \ - COM_UART << CONTROL1_COMP2SW_SHIFT)) -#define CONTROL1_SW_AUX_USB \ - ((COM_AUX_USB << CONTROL1_COMP1SW_SHIFT | \ - COM_AUX_USB << CONTROL1_COMP2SW_SHIFT)) -#define CONTROL1_SW_AUX_UART \ - ((COM_AUX_UART << CONTROL1_COMP1SW_SHIFT | \ - COM_AUX_UART << CONTROL1_COMP2SW_SHIFT)) +#define MAX77843_MUIC_CONTROL1_SW_OPEN \ + ((COM_OPEN << MAX77843_MUIC_CONTROL1_COMP1SW_SHIFT | \ + COM_OPEN << MAX77843_MUIC_CONTROL1_COMP2SW_SHIFT)) +#define MAX77843_MUIC_CONTROL1_SW_USB \ + ((COM_USB << MAX77843_MUIC_CONTROL1_COMP1SW_SHIFT | \ + COM_USB << MAX77843_MUIC_CONTROL1_COMP2SW_SHIFT)) +#define MAX77843_MUIC_CONTROL1_SW_AUDIO \ + ((COM_AUDIO << MAX77843_MUIC_CONTROL1_COMP1SW_SHIFT | \ + COM_AUDIO << MAX77843_MUIC_CONTROL1_COMP2SW_SHIFT)) +#define MAX77843_MUIC_CONTROL1_SW_UART \ + ((COM_UART << MAX77843_MUIC_CONTROL1_COMP1SW_SHIFT | \ + COM_UART << MAX77843_MUIC_CONTROL1_COMP2SW_SHIFT)) +#define MAX77843_MUIC_CONTROL1_SW_AUX_USB \ + ((COM_AUX_USB << MAX77843_MUIC_CONTROL1_COMP1SW_SHIFT | \ + COM_AUX_USB << MAX77843_MUIC_CONTROL1_COMP2SW_SHIFT)) +#define MAX77843_MUIC_CONTROL1_SW_AUX_UART \ + ((COM_AUX_UART << MAX77843_MUIC_CONTROL1_COMP1SW_SHIFT | \ + COM_AUX_UART << MAX77843_MUIC_CONTROL1_COMP2SW_SHIFT)) #define MAX77843_DISABLE 0 #define MAX77843_ENABLE 1 #define CONTROL4_AUTO_DISABLE \ - ((MAX77843_DISABLE << CONTROL4_USBAUTO_SHIFT) | \ - (MAX77843_DISABLE << CONTROL4_FCTAUTO_SHIFT)) + ((MAX77843_DISABLE << MAX77843_MUIC_CONTROL4_USBAUTO_SHIFT) | \ + (MAX77843_DISABLE << MAX77843_MUIC_CONTROL4_FCTAUTO_SHIFT)) #define CONTROL4_AUTO_ENABLE \ - ((MAX77843_ENABLE << CONTROL4_USBAUTO_SHIFT) | \ - (MAX77843_ENABLE << CONTROL4_FCTAUTO_SHIFT)) + ((MAX77843_ENABLE << MAX77843_MUIC_CONTROL4_USBAUTO_SHIFT) | \ + (MAX77843_ENABLE << MAX77843_MUIC_CONTROL4_FCTAUTO_SHIFT)) /* MAX77843 SAFEOUT LDO Control register */ #define SAFEOUTCTRL_SAFEOUT1_SHIFT 0 -- cgit v1.3-6-gb490 From 9e9a08e86733d994fe08876de7878148411d6bb5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 15 Jul 2015 21:59:54 +0900 Subject: regulator: max77693: Add support for MAX77843 device The charger and safeout parts of MAX77843 are almost the same as MAX77693. From regulator point of view the only differences are the constraints and register values related to these constraints. Now the max77693 regulator driver can be used for MAX77843 device. Signed-off-by: Krzysztof Kozlowski Acked-by: Mark Brown Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 8 +-- drivers/regulator/max77693.c | 125 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 117 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index bef3bde6971b..b1022c2fd877 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -407,13 +407,13 @@ config REGULATOR_MAX77686 Exynos-4 chips to control VARM and VINT voltages. config REGULATOR_MAX77693 - tristate "Maxim MAX77693 regulator" - depends on MFD_MAX77693 + tristate "Maxim 77693/77843 regulator" + depends on (MFD_MAX77693 || MFD_MAX77843) help - This driver controls a Maxim 77693 regulator via I2C bus. + This driver controls a Maxim 77693/77843 regulators via I2C bus. The regulators include two LDOs, 'SAFEOUT1', 'SAFEOUT2' and one current regulator 'CHARGER'. This is suitable for - Exynos-4x12 chips. + Exynos-4x12 (MAX77693) or Exynos5433 (MAX77843) SoC chips. config REGULATOR_MAX77802 tristate "Maxim 77802 regulator" diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c index c6ab440a74b7..788379b87962 100644 --- a/drivers/regulator/max77693.c +++ b/drivers/regulator/max77693.c @@ -1,8 +1,9 @@ /* - * max77693.c - Regulator driver for the Maxim 77693 + * max77693.c - Regulator driver for the Maxim 77693 and 77843 * - * Copyright (C) 2013 Samsung Electronics + * Copyright (C) 2013-2015 Samsung Electronics * Jonghwa Lee + * Krzysztof Kozlowski * * 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 @@ -31,10 +32,23 @@ #include #include #include +#include #include #include -/* Charger regulator differences between MAX77693 and MAX77843 */ +/* + * ID for MAX77843 regulators. + * There is no need for such for MAX77693. + */ +enum max77843_regulator_type { + MAX77843_SAFEOUT1 = 0, + MAX77843_SAFEOUT2, + MAX77843_CHARGER, + + MAX77843_NUM, +}; + +/* Register differences between chargers: MAX77693 and MAX77843 */ struct chg_reg_data { unsigned int linear_reg; unsigned int linear_mask; @@ -43,9 +57,14 @@ struct chg_reg_data { }; /* - * CHARGER regulator - Min : 20mA, Max : 2580mA, step : 20mA + * MAX77693 CHARGER regulator - Min : 20mA, Max : 2580mA, step : 20mA * 0x00, 0x01, 0x2, 0x03 = 60 mA * 0x04 ~ 0x7E = (60 + (X - 3) * 20) mA + * Actually for MAX77693 the driver manipulates the maximum input current, + * not the fast charge current (output). This should be fixed. + * + * On MAX77843 the calculation formula is the same (except values). + * Fortunately it properly manipulates the fast charge current. */ static int max77693_chg_get_current_limit(struct regulator_dev *rdev) { @@ -95,6 +114,26 @@ static int max77693_chg_set_current_limit(struct regulator_dev *rdev, } /* end of CHARGER regulator ops */ +/* Returns regmap suitable for given regulator on chosen device */ +static struct regmap *max77693_get_regmap(enum max77693_types type, + struct max77693_dev *max77693, + int reg_id) +{ + if (type == TYPE_MAX77693) + return max77693->regmap; + + /* Else: TYPE_MAX77843 */ + switch (reg_id) { + case MAX77843_SAFEOUT1: + case MAX77843_SAFEOUT2: + return max77693->regmap; + case MAX77843_CHARGER: + return max77693->regmap_chg; + default: + return max77693->regmap; + } +} + static const unsigned int max77693_safeout_table[] = { 4850000, 4900000, @@ -119,7 +158,7 @@ static struct regulator_ops max77693_charger_ops = { .set_current_limit = max77693_chg_set_current_limit, }; -#define regulator_desc_esafeout(_num) { \ +#define max77693_regulator_desc_esafeout(_num) { \ .name = "ESAFEOUT"#_num, \ .id = MAX77693_ESAFEOUT##_num, \ .of_match = of_match_ptr("ESAFEOUT"#_num), \ @@ -135,9 +174,9 @@ static struct regulator_ops max77693_charger_ops = { .enable_mask = SAFEOUT_CTRL_ENSAFEOUT##_num##_MASK , \ } -static const struct regulator_desc regulators[] = { - regulator_desc_esafeout(1), - regulator_desc_esafeout(2), +static const struct regulator_desc max77693_supported_regulators[] = { + max77693_regulator_desc_esafeout(1), + max77693_regulator_desc_esafeout(2), { .name = "CHARGER", .id = MAX77693_CHARGER, @@ -160,19 +199,79 @@ static const struct chg_reg_data max77693_chg_reg_data = { .min_sel = 3, }; +#define max77843_regulator_desc_esafeout(num) { \ + .name = "SAFEOUT" # num, \ + .id = MAX77843_SAFEOUT ## num, \ + .ops = &max77693_safeout_ops, \ + .of_match = of_match_ptr("SAFEOUT" # num), \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(max77693_safeout_table), \ + .volt_table = max77693_safeout_table, \ + .enable_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ + .enable_mask = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT ## num, \ + .vsel_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ + .vsel_mask = MAX77843_REG_SAFEOUTCTRL_SAFEOUT ## num ## _MASK, \ +} + +static const struct regulator_desc max77843_supported_regulators[] = { + [MAX77843_SAFEOUT1] = max77843_regulator_desc_esafeout(1), + [MAX77843_SAFEOUT2] = max77843_regulator_desc_esafeout(2), + [MAX77843_CHARGER] = { + .name = "CHARGER", + .id = MAX77843_CHARGER, + .ops = &max77693_charger_ops, + .of_match = of_match_ptr("CHARGER"), + .regulators_node = of_match_ptr("regulators"), + .type = REGULATOR_CURRENT, + .owner = THIS_MODULE, + .enable_reg = MAX77843_CHG_REG_CHG_CNFG_00, + .enable_mask = MAX77843_CHG_MASK, + .enable_val = MAX77843_CHG_MASK, + }, +}; + +static const struct chg_reg_data max77843_chg_reg_data = { + .linear_reg = MAX77843_CHG_REG_CHG_CNFG_02, + .linear_mask = MAX77843_CHG_FAST_CHG_CURRENT_MASK, + .uA_step = MAX77843_CHG_FAST_CHG_CURRENT_STEP, + .min_sel = 2, +}; + static int max77693_pmic_probe(struct platform_device *pdev) { + enum max77693_types type = platform_get_device_id(pdev)->driver_data; struct max77693_dev *iodev = dev_get_drvdata(pdev->dev.parent); + const struct regulator_desc *regulators; + unsigned int regulators_size; int i; struct regulator_config config = { }; config.dev = iodev->dev; - config.regmap = iodev->regmap; - config.driver_data = (void *)&max77693_chg_reg_data; - for (i = 0; i < ARRAY_SIZE(regulators); i++) { + switch (type) { + case TYPE_MAX77693: + regulators = max77693_supported_regulators; + regulators_size = ARRAY_SIZE(max77693_supported_regulators); + config.driver_data = (void *)&max77693_chg_reg_data; + break; + case TYPE_MAX77843: + regulators = max77843_supported_regulators; + regulators_size = ARRAY_SIZE(max77843_supported_regulators); + config.driver_data = (void *)&max77843_chg_reg_data; + break; + default: + dev_err(&pdev->dev, "Unsupported device type: %u\n", type); + return -ENODEV; + } + + for (i = 0; i < regulators_size; i++) { struct regulator_dev *rdev; + config.regmap = max77693_get_regmap(type, iodev, + regulators[i].id); + rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); if (IS_ERR(rdev)) { @@ -187,6 +286,7 @@ static int max77693_pmic_probe(struct platform_device *pdev) static const struct platform_device_id max77693_pmic_id[] = { { "max77693-pmic", TYPE_MAX77693 }, + { "max77843-regulator", TYPE_MAX77843 }, {}, }; @@ -202,6 +302,7 @@ static struct platform_driver max77693_pmic_driver = { module_platform_driver(max77693_pmic_driver); -MODULE_DESCRIPTION("MAXIM MAX77693 regulator driver"); +MODULE_DESCRIPTION("MAXIM 77693/77843 regulator driver"); MODULE_AUTHOR("Jonghwa Lee "); +MODULE_AUTHOR("Krzysztof Kozlowski "); MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 2a32b401a11fc48193e58b0a5af6ea82de0272de Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 15 Jul 2015 21:59:55 +0900 Subject: regulator: Remove the max77843 driver The max77693 regulator driver supports Maxim 77843 device so remove the max77843 driver. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 8 -- drivers/regulator/Makefile | 1 - drivers/regulator/max77843.c | 203 ------------------------------------------- 3 files changed, 212 deletions(-) delete mode 100644 drivers/regulator/max77843.c (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index b1022c2fd877..ed5ac9eb5063 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -424,14 +424,6 @@ config REGULATOR_MAX77802 Exynos5420/Exynos5800 SoCs to control various voltages. It includes support for control of voltage and ramp speed. -config REGULATOR_MAX77843 - tristate "Maxim 77843 regulator" - depends on MFD_MAX77843 - help - This driver controls a Maxim 77843 regulator. - The regulator include two 'SAFEOUT' for USB(Universal Serial Bus) - This is suitable for Exynos5433 SoC chips. - config REGULATOR_MC13XXX_CORE tristate diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 91bf76267404..6429e629dcb6 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -56,7 +56,6 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o -obj-$(CONFIG_REGULATOR_MAX77843) += max77843.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o diff --git a/drivers/regulator/max77843.c b/drivers/regulator/max77843.c deleted file mode 100644 index 9926247aae6b..000000000000 --- a/drivers/regulator/max77843.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * max77843.c - Regulator driver for the Maxim MAX77843 - * - * Copyright (C) 2015 Samsung Electronics - * Author: Jaewon Kim - * Author: Beomho Seo - * - * 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 - -enum max77843_regulator_type { - MAX77843_SAFEOUT1 = 0, - MAX77843_SAFEOUT2, - MAX77843_CHARGER, - - MAX77843_NUM, -}; - -static const unsigned int max77843_safeout_voltage_table[] = { - 4850000, - 4900000, - 4950000, - 3300000, -}; - -static int max77843_reg_get_current_limit(struct regulator_dev *rdev) -{ - struct regmap *regmap = rdev->regmap; - unsigned int chg_min_uA = rdev->constraints->min_uA; - unsigned int chg_max_uA = rdev->constraints->max_uA; - unsigned int val; - int ret; - unsigned int reg, sel; - - ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, ®); - if (ret) { - dev_err(&rdev->dev, "Failed to read charger register\n"); - return ret; - } - - sel = reg & MAX77843_CHG_FAST_CHG_CURRENT_MASK; - - if (sel < 0x03) - sel = 0; - else - sel -= 2; - - val = chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel; - if (val > chg_max_uA) - return -EINVAL; - - return val; -} - -static int max77843_reg_set_current_limit(struct regulator_dev *rdev, - int min_uA, int max_uA) -{ - struct regmap *regmap = rdev->regmap; - unsigned int chg_min_uA = rdev->constraints->min_uA; - int sel = 0; - - while (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel < min_uA) - sel++; - - if (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel > max_uA) - return -EINVAL; - - sel += 2; - - return regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_02, sel); -} - -static struct regulator_ops max77843_charger_ops = { - .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .get_current_limit = max77843_reg_get_current_limit, - .set_current_limit = max77843_reg_set_current_limit, -}; - -static struct regulator_ops max77843_regulator_ops = { - .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, - .list_voltage = regulator_list_voltage_table, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, -}; - -#define MAX77843_SAFEOUT(num) { \ - .name = "SAFEOUT" # num, \ - .id = MAX77843_SAFEOUT ## num, \ - .ops = &max77843_regulator_ops, \ - .of_match = of_match_ptr("SAFEOUT" # num), \ - .regulators_node = of_match_ptr("regulators"), \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - .n_voltages = ARRAY_SIZE(max77843_safeout_voltage_table), \ - .volt_table = max77843_safeout_voltage_table, \ - .enable_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ - .enable_mask = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT ## num, \ - .vsel_reg = MAX77843_SYS_REG_SAFEOUTCTRL, \ - .vsel_mask = MAX77843_REG_SAFEOUTCTRL_SAFEOUT ## num ## _MASK, \ -} - -static const struct regulator_desc max77843_supported_regulators[] = { - [MAX77843_SAFEOUT1] = MAX77843_SAFEOUT(1), - [MAX77843_SAFEOUT2] = MAX77843_SAFEOUT(2), - [MAX77843_CHARGER] = { - .name = "CHARGER", - .id = MAX77843_CHARGER, - .ops = &max77843_charger_ops, - .of_match = of_match_ptr("CHARGER"), - .regulators_node = of_match_ptr("regulators"), - .type = REGULATOR_CURRENT, - .owner = THIS_MODULE, - .enable_reg = MAX77843_CHG_REG_CHG_CNFG_00, - .enable_mask = MAX77843_CHG_MASK | MAX77843_CHG_BUCK_MASK, - .enable_val = MAX77843_CHG_MASK | MAX77843_CHG_BUCK_MASK, - }, -}; - -static struct regmap *max77843_get_regmap(struct max77693_dev *max77843, - int reg_id) -{ - switch (reg_id) { - case MAX77843_SAFEOUT1: - case MAX77843_SAFEOUT2: - return max77843->regmap; - case MAX77843_CHARGER: - return max77843->regmap_chg; - default: - return max77843->regmap; - } -} - -static int max77843_regulator_probe(struct platform_device *pdev) -{ - struct max77693_dev *max77843 = dev_get_drvdata(pdev->dev.parent); - struct regulator_config config = {}; - int i; - - config.dev = max77843->dev; - config.driver_data = max77843; - - for (i = 0; i < ARRAY_SIZE(max77843_supported_regulators); i++) { - struct regulator_dev *regulator; - - config.regmap = max77843_get_regmap(max77843, - max77843_supported_regulators[i].id); - - regulator = devm_regulator_register(&pdev->dev, - &max77843_supported_regulators[i], &config); - if (IS_ERR(regulator)) { - dev_err(&pdev->dev, - "Failed to regiser regulator-%d\n", i); - return PTR_ERR(regulator); - } - } - - return 0; -} - -static const struct platform_device_id max77843_regulator_id[] = { - { "max77843-regulator", }, - { /* sentinel */ }, -}; - -static struct platform_driver max77843_regulator_driver = { - .driver = { - .name = "max77843-regulator", - }, - .probe = max77843_regulator_probe, - .id_table = max77843_regulator_id, -}; - -static int __init max77843_regulator_init(void) -{ - return platform_driver_register(&max77843_regulator_driver); -} -subsys_initcall(max77843_regulator_init); - -static void __exit max77843_regulator_exit(void) -{ - platform_driver_unregister(&max77843_regulator_driver); -} -module_exit(max77843_regulator_exit); - -MODULE_AUTHOR("Jaewon Kim "); -MODULE_AUTHOR("Beomho Seo "); -MODULE_DESCRIPTION("Maxim MAX77843 regulator driver"); -MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 77b563ed06a63e59ce1bf2803170898e852b3866 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:21:39 +0200 Subject: irqchip/exynos: Prepare combiner_handle_cascade_irq for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall --- drivers/irqchip/exynos-combiner.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 1a4a1b09394c..04e0892d2511 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -65,10 +65,12 @@ static void combiner_unmask_irq(struct irq_data *data) __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET); } -static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) +static void combiner_handle_cascade_irq(unsigned int __irq, + struct irq_desc *desc) { struct combiner_chip_data *chip_data = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int irq = irq_desc_get_irq(desc); unsigned int cascade_irq, combiner_irq; unsigned long status; -- cgit v1.3-6-gb490 From 00db2ae52a78f6ba23c16c22696da59f4f2a4da0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:35:20 +0200 Subject: irqchip/brcmstb-l2: Prepare brcmstb_l2_intc_irq_handle for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall --- drivers/irqchip/irq-brcmstb-l2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index cef15189aa5b..aedda06191eb 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -49,11 +49,13 @@ struct brcmstb_l2_intc_data { u32 saved_mask; /* for suspend/resume */ }; -static void brcmstb_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) +static void brcmstb_l2_intc_irq_handle(unsigned int __irq, + struct irq_desc *desc) { struct brcmstb_l2_intc_data *b = irq_desc_get_handler_data(desc); struct irq_chip_generic *gc = irq_get_domain_generic_chip(b->domain, 0); struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int irq = irq_desc_get_irq(desc); u32 status; chained_irq_enter(chip, desc); -- cgit v1.3-6-gb490 From 99705f995a704fdf8625464d70ef5c5750ea55e2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:37:28 +0200 Subject: irqchip/imgpdc: Prepare pdc_intc_perip_isr for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall --- drivers/irqchip/irq-imgpdc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index 03d91cbfc45e..841604b81004 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -218,8 +218,9 @@ static int pdc_irq_set_wake(struct irq_data *data, unsigned int on) return 0; } -static void pdc_intc_perip_isr(unsigned int irq, struct irq_desc *desc) +static void pdc_intc_perip_isr(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct pdc_intc_priv *priv; unsigned int i, irq_no; -- cgit v1.3-6-gb490 From 283653a368f49773ee7242e2a03227d7de5d3a7e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:38:07 +0200 Subject: irqchip/keystone: Prepare keystone_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall --- drivers/irqchip/irq-keystone.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index d10244fa743a..c1517267b5db 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -83,8 +83,9 @@ static void keystone_irq_ack(struct irq_data *d) /* nothing to do here */ } -static void keystone_irq_handler(unsigned irq, struct irq_desc *desc) +static void keystone_irq_handler(unsigned __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct keystone_irq_device *kirq = irq_desc_get_handler_data(desc); unsigned long pending; int src, virq; -- cgit v1.3-6-gb490 From 14873aa1d1c97a11cec57ae1345da467d4b6d4d7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:38:51 +0200 Subject: irqchip/mmp: Prepare icu_mux_irq_demux for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall --- drivers/irqchip/irq-mmp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c index c9c03a264632..781ed6e71dbb 100644 --- a/drivers/irqchip/irq-mmp.c +++ b/drivers/irqchip/irq-mmp.c @@ -129,8 +129,9 @@ struct irq_chip icu_irq_chip = { .irq_unmask = icu_unmask_irq, }; -static void icu_mux_irq_demux(unsigned int irq, struct irq_desc *desc) +static void icu_mux_irq_demux(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct irq_domain *domain; struct icu_chip_data *data; int i; -- cgit v1.3-6-gb490 From 4df18a668c45d2069d731eccb75b7558052c8718 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:39:29 +0200 Subject: irqchip/s3c24xx: Prepare s3c_irq_demux for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall --- drivers/irqchip/irq-s3c24xx.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c index aee4266f27f7..506d9f20ca51 100644 --- a/drivers/irqchip/irq-s3c24xx.c +++ b/drivers/irqchip/irq-s3c24xx.c @@ -298,16 +298,14 @@ static struct irq_chip s3c_irq_eint0t4 = { .irq_set_type = s3c_irqext0_type, }; -static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc) +static void s3c_irq_demux(unsigned int __irq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct s3c_irq_data *irq_data = irq_desc_get_chip_data(desc); struct s3c_irq_intc *intc = irq_data->intc; struct s3c_irq_intc *sub_intc = irq_data->sub_intc; - unsigned long src; - unsigned long msk; - unsigned int n; - unsigned int offset; + unsigned int n, offset, irq; + unsigned long src, msk; /* we're using individual domains for the non-dt case * and one big domain for the dt case where the subintc -- cgit v1.3-6-gb490 From e616e9af87206dfd00753c1546388210fe5d0002 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:40:58 +0200 Subject: irqchip/tb10x: Prepare tb10x_irq_cascade for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall --- drivers/irqchip/irq-tb10x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c index c7e1407c2b40..331829661366 100644 --- a/drivers/irqchip/irq-tb10x.c +++ b/drivers/irqchip/irq-tb10x.c @@ -97,9 +97,10 @@ static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type) return IRQ_SET_MASK_OK; } -static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc) +static void tb10x_irq_cascade(unsigned int __irq, struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); + unsigned int irq = irq_desc_get_irq(desc); generic_handle_irq(irq_find_mapping(domain, irq)); } -- cgit v1.3-6-gb490 From 71093eb2cf720a1eded53c0711c4fa691185e82c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:41:39 +0200 Subject: irqchip/versatile-fpga: Prepare fpga_irq_handle for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall --- drivers/irqchip/irq-versatile-fpga.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 70088bb3fb53..16123f688768 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -65,9 +65,10 @@ static void fpga_irq_unmask(struct irq_data *d) writel(mask, f->base + IRQ_ENABLE_SET); } -static void fpga_irq_handle(unsigned int irq, struct irq_desc *desc) +static void fpga_irq_handle(unsigned int __irq, struct irq_desc *desc) { struct fpga_irq_data *f = irq_desc_get_handler_data(desc); + unsigned int irq = irq_desc_get_irq(desc); u32 status = readl(f->base + IRQ_STATUS); if (status == 0) { -- cgit v1.3-6-gb490 From 9fc0fd6b052be4390138bb6c4bae07d6b7e1aa66 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:42:21 +0200 Subject: irqchip/spear-shirq: Prepare shirq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall --- drivers/irqchip/spear-shirq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c index 61718550a064..ee175d2b9926 100644 --- a/drivers/irqchip/spear-shirq.c +++ b/drivers/irqchip/spear-shirq.c @@ -182,7 +182,7 @@ static struct spear_shirq *spear320_shirq_blocks[] = { &spear320_shirq_intrcomm_ras, }; -static void shirq_handler(unsigned irq, struct irq_desc *desc) +static void shirq_handler(unsigned __irq, struct irq_desc *desc) { struct spear_shirq *shirq = irq_desc_get_handler_data(desc); u32 pend; -- cgit v1.3-6-gb490 From 8019ff6cfc0440415fcfb6352c58c3951e6ab053 Mon Sep 17 00:00:00 2001 From: Nariman Poushin Date: Thu, 16 Jul 2015 16:36:21 +0100 Subject: regmap: Use reg_sequence for multi_reg_write / register_patch Separate the functionality using sequences of register writes from the functions that take register defaults. This change renames the arguments in order to support the extension of reg_sequence to take an optional delay to be applied after any given register in a sequence is written. This avoids adding an int to all register defaults, which could substantially increase memory usage for regmaps with large default tables. This also updates all the clients of multi_reg_write/register_patch. Signed-off-by: Nariman Poushin Signed-off-by: Mark Brown --- drivers/base/regmap/internal.h | 2 +- drivers/base/regmap/regmap.c | 22 +++++++++++----------- drivers/gpu/drm/i2c/adv7511.c | 2 +- drivers/input/misc/drv260x.c | 6 +++--- drivers/input/misc/drv2665.c | 2 +- drivers/input/misc/drv2667.c | 4 ++-- drivers/mfd/arizona-core.c | 2 +- drivers/mfd/twl6040.c | 2 +- drivers/mfd/wm5102-tables.c | 6 +++--- drivers/mfd/wm5110-tables.c | 6 +++--- drivers/mfd/wm8994-core.c | 8 ++++---- drivers/mfd/wm8997-tables.c | 2 +- include/linux/regmap.h | 17 ++++++++++++++--- sound/soc/codecs/arizona.c | 2 +- sound/soc/codecs/cs35l32.c | 2 +- sound/soc/codecs/cs42l52.c | 2 +- sound/soc/codecs/da7210.c | 4 ++-- sound/soc/codecs/rt5640.c | 2 +- sound/soc/codecs/rt5645.c | 4 ++-- sound/soc/codecs/rt5651.c | 2 +- sound/soc/codecs/rt5670.c | 2 +- sound/soc/codecs/rt5677.c | 2 +- sound/soc/codecs/tlv320aic3x.c | 2 +- sound/soc/codecs/wm2200.c | 2 +- sound/soc/codecs/wm5100.c | 2 +- sound/soc/codecs/wm8962.c | 2 +- sound/soc/codecs/wm8993.c | 2 +- 27 files changed, 62 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index b2b2849fc6d3..873ddf91c9d3 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -136,7 +136,7 @@ struct regmap { /* if set, the HW registers are known to match map->reg_defaults */ bool no_sync_defaults; - struct reg_default *patch; + struct reg_sequence *patch; int patch_regs; /* if set, converts bulk rw to single rw */ diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7111d04f2621..2cbb4502747d 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1743,7 +1743,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write); * relative. The page register has been written if that was neccessary. */ static int _regmap_raw_multi_reg_write(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, size_t num_regs) { int ret; @@ -1800,12 +1800,12 @@ static unsigned int _regmap_register_page(struct regmap *map, } static int _regmap_range_multi_paged_reg_write(struct regmap *map, - struct reg_default *regs, + struct reg_sequence *regs, size_t num_regs) { int ret; int i, n; - struct reg_default *base; + struct reg_sequence *base; unsigned int this_page = 0; /* * the set of registers are not neccessarily in order, but @@ -1843,7 +1843,7 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map, } static int _regmap_multi_reg_write(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, size_t num_regs) { int i; @@ -1895,8 +1895,8 @@ static int _regmap_multi_reg_write(struct regmap *map, struct regmap_range_node *range; range = _regmap_range_lookup(map, reg); if (range) { - size_t len = sizeof(struct reg_default)*num_regs; - struct reg_default *base = kmemdup(regs, len, + size_t len = sizeof(struct reg_sequence)*num_regs; + struct reg_sequence *base = kmemdup(regs, len, GFP_KERNEL); if (!base) return -ENOMEM; @@ -1929,7 +1929,7 @@ static int _regmap_multi_reg_write(struct regmap *map, * A value of zero will be returned on success, a negative errno will be * returned in error cases. */ -int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs, +int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, int num_regs) { int ret; @@ -1962,7 +1962,7 @@ EXPORT_SYMBOL_GPL(regmap_multi_reg_write); * be returned in error cases. */ int regmap_multi_reg_write_bypassed(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, int num_regs) { int ret; @@ -2552,10 +2552,10 @@ EXPORT_SYMBOL_GPL(regmap_async_complete); * The caller must ensure that this function cannot be called * concurrently with either itself or regcache_sync(). */ -int regmap_register_patch(struct regmap *map, const struct reg_default *regs, +int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs, int num_regs) { - struct reg_default *p; + struct reg_sequence *p; int ret; bool bypass; @@ -2564,7 +2564,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, return 0; p = krealloc(map->patch, - sizeof(struct reg_default) * (map->patch_regs + num_regs), + sizeof(struct reg_sequence) * (map->patch_regs + num_regs), GFP_KERNEL); if (p) { memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs)); diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c index 2aaa3c88999e..00416f23b5cb 100644 --- a/drivers/gpu/drm/i2c/adv7511.c +++ b/drivers/gpu/drm/i2c/adv7511.c @@ -54,7 +54,7 @@ static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder) } /* ADI recommended values for proper operation. */ -static const struct reg_default adv7511_fixed_registers[] = { +static const struct reg_sequence adv7511_fixed_registers[] = { { 0x98, 0x03 }, { 0x9a, 0xe0 }, { 0x9c, 0x30 }, diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index e5d60ecd29a4..f5c9cf2f4073 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -313,14 +313,14 @@ static void drv260x_close(struct input_dev *input) gpiod_set_value(haptics->enable_gpio, 0); } -static const struct reg_default drv260x_lra_cal_regs[] = { +static const struct reg_sequence drv260x_lra_cal_regs[] = { { DRV260X_MODE, DRV260X_AUTO_CAL }, { DRV260X_CTRL3, DRV260X_NG_THRESH_2 }, { DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE | DRV260X_BRAKE_FACTOR_4X | DRV260X_LOOP_GAIN_HIGH }, }; -static const struct reg_default drv260x_lra_init_regs[] = { +static const struct reg_sequence drv260x_lra_init_regs[] = { { DRV260X_MODE, DRV260X_RT_PLAYBACK }, { DRV260X_A_TO_V_CTRL, DRV260X_AUDIO_HAPTICS_PEAK_20MS | DRV260X_AUDIO_HAPTICS_FILTER_125HZ }, @@ -337,7 +337,7 @@ static const struct reg_default drv260x_lra_init_regs[] = { { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS }, }; -static const struct reg_default drv260x_erm_cal_regs[] = { +static const struct reg_sequence drv260x_erm_cal_regs[] = { { DRV260X_MODE, DRV260X_AUTO_CAL }, { DRV260X_A_TO_V_MIN_INPUT, DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT }, { DRV260X_A_TO_V_MAX_INPUT, DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT }, diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index 0afaa33de07d..924456e3ca75 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -132,7 +132,7 @@ static void drv2665_close(struct input_dev *input) "Failed to enter standby mode: %d\n", error); } -static const struct reg_default drv2665_init_regs[] = { +static const struct reg_sequence drv2665_init_regs[] = { { DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT }, { DRV2665_CTRL_1, DRV2665_25_VPP_GAIN }, }; diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index fc0fddf0896a..047136aa646f 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -262,14 +262,14 @@ static void drv2667_close(struct input_dev *input) "Failed to enter standby mode: %d\n", error); } -static const struct reg_default drv2667_init_regs[] = { +static const struct reg_sequence drv2667_init_regs[] = { { DRV2667_CTRL_2, 0 }, { DRV2667_CTRL_1, DRV2667_25_VPP_GAIN }, { DRV2667_WV_SEQ_0, 1 }, { DRV2667_WV_SEQ_1, 0 } }; -static const struct reg_default drv2667_page1_init[] = { +static const struct reg_sequence drv2667_page1_init[] = { { DRV2667_RAM_HDR_SZ, 0x05 }, { DRV2667_RAM_START_HI, 0x80 }, { DRV2667_RAM_START_LO, 0x06 }, diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index bebf58a06a6b..66d50be11960 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -392,7 +392,7 @@ err: * Register patch to some of the CODECs internal write sequences * to ensure a clean exit from the low power sleep state. */ -static const struct reg_default wm5110_sleep_patch[] = { +static const struct reg_sequence wm5110_sleep_patch[] = { { 0x337A, 0xC100 }, { 0x337B, 0x0041 }, { 0x3300, 0xA210 }, diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index c5265c1262c5..583dc33432f3 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -86,7 +86,7 @@ static const struct reg_default twl6040_defaults[] = { { 0x2E, 0x00 }, /* REG_STATUS (ro) */ }; -static struct reg_default twl6040_patch[] = { +static struct reg_sequence twl6040_patch[] = { /* * Select I2C bus access to dual access registers * Interrupt register is cleared on read diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index aeae6ec123b3..423fb3730dc7 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -21,7 +21,7 @@ #define WM5102_NUM_AOD_ISR 2 #define WM5102_NUM_ISR 5 -static const struct reg_default wm5102_reva_patch[] = { +static const struct reg_sequence wm5102_reva_patch[] = { { 0x80, 0x0003 }, { 0x221, 0x0090 }, { 0x211, 0x0014 }, @@ -57,7 +57,7 @@ static const struct reg_default wm5102_reva_patch[] = { { 0x80, 0x0000 }, }; -static const struct reg_default wm5102_revb_patch[] = { +static const struct reg_sequence wm5102_revb_patch[] = { { 0x19, 0x0001 }, { 0x80, 0x0003 }, { 0x081, 0xE022 }, @@ -80,7 +80,7 @@ static const struct reg_default wm5102_revb_patch[] = { /* We use a function so we can use ARRAY_SIZE() */ int wm5102_patch(struct arizona *arizona) { - const struct reg_default *wm5102_patch; + const struct reg_sequence *wm5102_patch; int patch_size; switch (arizona->rev) { diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 12cad94b4035..26ce14f903fe 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -21,7 +21,7 @@ #define WM5110_NUM_AOD_ISR 2 #define WM5110_NUM_ISR 5 -static const struct reg_default wm5110_reva_patch[] = { +static const struct reg_sequence wm5110_reva_patch[] = { { 0x80, 0x3 }, { 0x44, 0x20 }, { 0x45, 0x40 }, @@ -134,7 +134,7 @@ static const struct reg_default wm5110_reva_patch[] = { { 0x209, 0x002A }, }; -static const struct reg_default wm5110_revb_patch[] = { +static const struct reg_sequence wm5110_revb_patch[] = { { 0x80, 0x3 }, { 0x36e, 0x0210 }, { 0x370, 0x0210 }, @@ -224,7 +224,7 @@ static const struct reg_default wm5110_revb_patch[] = { { 0x80, 0x0 }, }; -static const struct reg_default wm5110_revd_patch[] = { +static const struct reg_sequence wm5110_revd_patch[] = { { 0x80, 0x3 }, { 0x80, 0x3 }, { 0x393, 0x27 }, diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 53ae5af5d6e4..0f4169a3a5d4 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -243,21 +243,21 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) } #endif -static const struct reg_default wm8994_revc_patch[] = { +static const struct reg_sequence wm8994_revc_patch[] = { { 0x102, 0x3 }, { 0x56, 0x3 }, { 0x817, 0x0 }, { 0x102, 0x0 }, }; -static const struct reg_default wm8958_reva_patch[] = { +static const struct reg_sequence wm8958_reva_patch[] = { { 0x102, 0x3 }, { 0xcb, 0x81 }, { 0x817, 0x0 }, { 0x102, 0x0 }, }; -static const struct reg_default wm1811_reva_patch[] = { +static const struct reg_sequence wm1811_reva_patch[] = { { 0x102, 0x3 }, { 0x56, 0xc07 }, { 0x5d, 0x7e }, @@ -326,7 +326,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) { struct wm8994_pdata *pdata; struct regmap_config *regmap_config; - const struct reg_default *regmap_patch = NULL; + const struct reg_sequence *regmap_patch = NULL; const char *devname; int ret, i, patch_regs = 0; int pulls = 0; diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c index c0c25d75aacc..cab2c68f1737 100644 --- a/drivers/mfd/wm8997-tables.c +++ b/drivers/mfd/wm8997-tables.c @@ -17,7 +17,7 @@ #include "arizona.h" -static const struct reg_default wm8997_reva_patch[] = { +static const struct reg_sequence wm8997_reva_patch[] = { { 0x80, 0x0003 }, { 0x214, 0x0008 }, { 0x458, 0x0000 }, diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 59c55ea0f0b5..c9ef2ec69142 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -50,6 +50,17 @@ struct reg_default { unsigned int def; }; +/** + * Register/value pairs for sequences of writes + * + * @reg: Register address. + * @def: Register value. + */ +struct reg_sequence { + unsigned int reg; + unsigned int def; +}; + #ifdef CONFIG_REGMAP enum regmap_endian { @@ -410,10 +421,10 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len); int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, size_t val_count); -int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs, +int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, int num_regs); int regmap_multi_reg_write_bypassed(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, int num_regs); int regmap_raw_write_async(struct regmap *map, unsigned int reg, const void *val, size_t val_len); @@ -450,7 +461,7 @@ void regcache_mark_dirty(struct regmap *map); bool regmap_check_range_table(struct regmap *map, unsigned int reg, const struct regmap_access_table *table); -int regmap_register_patch(struct regmap *map, const struct reg_default *regs, +int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs, int num_regs); int regmap_parse_val(struct regmap *map, const void *buf, unsigned int *val); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 802e05eae3e9..5edd33fcd68c 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1366,7 +1366,7 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec, { struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona *arizona = priv->arizona; - struct reg_default dac_comp[] = { + struct reg_sequence dac_comp[] = { { 0x80, 0x3 }, { ARIZONA_DAC_COMP_1, 0 }, { ARIZONA_DAC_COMP_2, 0 }, diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 8f40025b7e7c..2813a1b0c949 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -276,7 +276,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { }; /* Current and threshold powerup sequence Pg37 in datasheet */ -static const struct reg_default cs35l32_monitor_patch[] = { +static const struct reg_sequence cs35l32_monitor_patch[] = { { 0x00, 0x99 }, { 0x48, 0x17 }, diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 4de52c9957ac..8b2d05933594 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1118,7 +1118,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = { }; /* Current and threshold powerup sequence Pg37 */ -static const struct reg_default cs42l52_threshold_patch[] = { +static const struct reg_sequence cs42l52_threshold_patch[] = { { 0x00, 0x99 }, { 0x3E, 0xBA }, diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 21810e5f3321..bf0fb3d4df22 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1182,7 +1182,7 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = { #if IS_ENABLED(CONFIG_I2C) -static struct reg_default da7210_regmap_i2c_patch[] = { +static struct reg_sequence da7210_regmap_i2c_patch[] = { /* System controller master disable */ { DA7210_STARTUP1, 0x00 }, @@ -1269,7 +1269,7 @@ static struct i2c_driver da7210_i2c_driver = { #if defined(CONFIG_SPI_MASTER) -static struct reg_default da7210_regmap_spi_patch[] = { +static struct reg_sequence da7210_regmap_spi_patch[] = { /* Dummy read to give two pulses over nCS for SPI */ { DA7210_AUX2, 0x00 }, { DA7210_AUX2, 0x00 }, diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 9bc78e57513d..1ed1f8895e12 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -51,7 +51,7 @@ static const struct regmap_range_cfg rt5640_ranges[] = { .window_len = 0x1, }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { {RT5640_PR_BASE + 0x3d, 0x3600}, {RT5640_PR_BASE + 0x12, 0x0aa8}, {RT5640_PR_BASE + 0x14, 0x0aaa}, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e088fc..c0f4be430e70 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -54,7 +54,7 @@ static const struct regmap_range_cfg rt5645_ranges[] = { }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { {RT5645_PR_BASE + 0x3d, 0x3600}, {RT5645_PR_BASE + 0x1c, 0xfd20}, {RT5645_PR_BASE + 0x20, 0x611f}, @@ -63,7 +63,7 @@ static const struct reg_default init_list[] = { }; #define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list) -static const struct reg_default rt5650_init_list[] = { +static const struct reg_sequence rt5650_init_list[] = { {0xf6, 0x0100}, }; diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index a3506e193abc..db9b8667f136 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -46,7 +46,7 @@ static const struct regmap_range_cfg rt5651_ranges[] = { .window_len = 0x1, }, }; -static struct reg_default init_list[] = { +static struct reg_sequence init_list[] = { {RT5651_PR_BASE + 0x3d, 0x3e00}, }; diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a9123d414178..462a91f7cf68 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -51,7 +51,7 @@ static const struct regmap_range_cfg rt5670_ranges[] = { .window_len = 0x1, }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { { RT5670_PR_BASE + 0x14, 0x9a8a }, { RT5670_PR_BASE + 0x38, 0x3ba1 }, { RT5670_PR_BASE + 0x3d, 0x3640 }, diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969ac1192..b89775251470 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -54,7 +54,7 @@ static const struct regmap_range_cfg rt5677_ranges[] = { }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { {RT5677_ASRC_12, 0x0018}, {RT5677_PR_BASE + 0x3d, 0x364d}, {RT5677_PR_BASE + 0x17, 0x4fc0}, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index a7cf19b53fb2..83ae1eb44d4f 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1668,7 +1668,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); -static const struct reg_default aic3007_class_d[] = { +static const struct reg_sequence aic3007_class_d[] = { /* Class-D speaker driver init; datasheet p. 46 */ { AIC3X_PAGE_SELECT, 0x0D }, { 0xD, 0x0D }, diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c83083285e53..6c607928fb9b 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -897,7 +897,7 @@ static bool wm2200_readable_register(struct device *dev, unsigned int reg) } } -static const struct reg_default wm2200_reva_patch[] = { +static const struct reg_sequence wm2200_reva_patch[] = { { 0x07, 0x0003 }, { 0x102, 0x0200 }, { 0x203, 0x0084 }, diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4c10cd88c1af..26d79bbb7599 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1247,7 +1247,7 @@ static const struct snd_soc_dapm_route wm5100_dapm_routes[] = { { "PWM2", NULL, "PWM2 Driver" }, }; -static const struct reg_default wm5100_reva_patches[] = { +static const struct reg_sequence wm5100_reva_patches[] = { { WM5100_AUDIO_IF_1_10, 0 }, { WM5100_AUDIO_IF_1_11, 1 }, { WM5100_AUDIO_IF_1_12, 2 }, diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index c5748fd4f296..05492e826aea 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3495,7 +3495,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8962 = { }; /* Improve power consumption for IN4 DC measurement mode */ -static const struct reg_default wm8962_dc_measure[] = { +static const struct reg_sequence wm8962_dc_measure[] = { { 0xfd, 0x1 }, { 0xcc, 0x40 }, { 0xfd, 0 }, diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 8a8db8605dc2..52ec64d8502d 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1595,7 +1595,7 @@ static int wm8993_resume(struct snd_soc_codec *codec) #endif /* Tune DC servo configuration */ -static struct reg_default wm8993_regmap_patch[] = { +static struct reg_sequence wm8993_regmap_patch[] = { { 0x44, 3 }, { 0x56, 3 }, { 0x44, 0 }, -- cgit v1.3-6-gb490 From 2de9d6006c190bb0f706e8404de94cd94293801f Mon Sep 17 00:00:00 2001 From: Nariman Poushin Date: Thu, 16 Jul 2015 16:36:22 +0100 Subject: regmap: Apply optional delay in multi_reg_write/register_patch Add an optional delay_us field in reg_sequence to allow the client to specify a delay (in microseconds) to be applied after any given write in a sequence of writes. We treat a delay in a sequence the same way we treat a page change as they are logically similar in that you can coalesce all write before a delay (in the same way you can coalesce all writes before a page change is needed) Signed-off-by: Nariman Poushin Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 54 +++++++++++++++++++++++++++++++++++++++----- include/linux/regmap.h | 5 +++- 2 files changed, 52 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 2cbb4502747d..b3a5aa5cd580 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -18,6 +18,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include "trace.h" @@ -1807,10 +1808,12 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map, int i, n; struct reg_sequence *base; unsigned int this_page = 0; + unsigned int page_change = 0; /* * the set of registers are not neccessarily in order, but * since the order of write must be preserved this algorithm - * chops the set each time the page changes + * chops the set each time the page changes. This also applies + * if there is a delay required at any point in the sequence. */ base = regs; for (i = 0, n = 0; i < num_regs; i++, n++) { @@ -1826,16 +1829,48 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map, this_page = win_page; if (win_page != this_page) { this_page = win_page; + page_change = 1; + } + } + + /* If we have both a page change and a delay make sure to + * write the regs and apply the delay before we change the + * page. + */ + + if (page_change || regs[i].delay_us) { + + /* For situations where the first write requires + * a delay we need to make sure we don't call + * raw_multi_reg_write with n=0 + * This can't occur with page breaks as we + * never write on the first iteration + */ + if (regs[i].delay_us && i == 0) + n = 1; + ret = _regmap_raw_multi_reg_write(map, base, n); if (ret != 0) return ret; + + if (regs[i].delay_us) + udelay(regs[i].delay_us); + base += n; n = 0; - } - ret = _regmap_select_page(map, &base[n].reg, range, 1); - if (ret != 0) - return ret; + + if (page_change) { + ret = _regmap_select_page(map, + &base[n].reg, + range, 1); + if (ret != 0) + return ret; + + page_change = 0; + } + } + } if (n > 0) return _regmap_raw_multi_reg_write(map, base, n); @@ -1854,6 +1889,9 @@ static int _regmap_multi_reg_write(struct regmap *map, ret = _regmap_write(map, regs[i].reg, regs[i].def); if (ret != 0) return ret; + + if (regs[i].delay_us) + udelay(regs[i].delay_us); } return 0; } @@ -1893,8 +1931,12 @@ static int _regmap_multi_reg_write(struct regmap *map, for (i = 0; i < num_regs; i++) { unsigned int reg = regs[i].reg; struct regmap_range_node *range; + + /* Coalesce all the writes between a page break or a delay + * in a sequence + */ range = _regmap_range_lookup(map, reg); - if (range) { + if (range || regs[i].delay_us) { size_t len = sizeof(struct reg_sequence)*num_regs; struct reg_sequence *base = kmemdup(regs, len, GFP_KERNEL); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index c9ef2ec69142..5a7cf2136c81 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -51,14 +51,17 @@ struct reg_default { }; /** - * Register/value pairs for sequences of writes + * Register/value pairs for sequences of writes with an optional delay in + * microseconds to be applied after each write. * * @reg: Register address. * @def: Register value. + * @delay_us: Delay to be applied after the register write in microseconds */ struct reg_sequence { unsigned int reg; unsigned int def; + unsigned int delay_us; }; #ifdef CONFIG_REGMAP -- cgit v1.3-6-gb490 From c391f262bee9d0d6424a99c85183a06c50e307ee Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:41 +0800 Subject: genirq: Rename irq_data_get_msi() as irq_data_get_msi_desc() Rename irq_data_get_msi() as irq_data_get_msi_desc() to keep consistency with other irq_data access helpers. Signed-off-by: Jiang Liu Acked-by: Bjorn Helgaas Cc: Jason Cooper Signed-off-by: Thomas Gleixner --- drivers/pci/host/pcie-designware.c | 2 +- drivers/pci/msi.c | 2 +- include/linux/irq.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 69486be7181e..85c7735d7511 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -326,7 +326,7 @@ static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq) { struct irq_data *data = irq_get_irq_data(irq); - struct msi_desc *msi = irq_data_get_msi(data); + struct msi_desc *msi = irq_data_get_msi_desc(data); struct pcie_port *pp = sys_to_pcie(msi->dev->bus->sysdata); clear_irq_range(pp, irq, 1, data->hwirq); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f66be868ad21..64673f13bbb9 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -249,7 +249,7 @@ static void msix_mask_irq(struct msi_desc *desc, u32 flag) static void msi_set_mask_bit(struct irq_data *data, u32 flag) { - struct msi_desc *desc = irq_data_get_msi(data); + struct msi_desc *desc = irq_data_get_msi_desc(data); if (desc->msi_attrib.is_msix) { msix_mask_irq(desc, flag); diff --git a/include/linux/irq.h b/include/linux/irq.h index 429ac266c7c6..5284cb166d90 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -638,7 +638,7 @@ static inline struct msi_desc *irq_get_msi_desc(unsigned int irq) return d ? d->msi_desc : NULL; } -static inline struct msi_desc *irq_data_get_msi(struct irq_data *d) +static inline struct msi_desc *irq_data_get_msi_desc(struct irq_data *d) { return d->msi_desc; } -- cgit v1.3-6-gb490 From 507a883ed5396825b88631b06cd27e050f5aa8fe Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:42 +0800 Subject: treewide: Use helper function to access irq_data->msi_desc Use irq_data access helper to access irq_data->msi_desc, so we can move msi_desc from struct irq_data into struct irq_common_data later. Signed-off-by: Jiang Liu Cc: Bjorn Helgaas Cc: Tony Luck Cc: Fenghua Yu Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Chris Metcalf Signed-off-by: Thomas Gleixner --- arch/ia64/kernel/msi_ia64.c | 2 +- arch/ia64/sn/kernel/msi_sn.c | 2 +- arch/powerpc/sysdev/xics/ics-opal.c | 2 +- arch/powerpc/sysdev/xics/ics-rtas.c | 2 +- arch/tile/kernel/pci_gx.c | 2 +- drivers/pci/msi.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c index d70bf15c690a..4d3053e25394 100644 --- a/arch/ia64/kernel/msi_ia64.c +++ b/arch/ia64/kernel/msi_ia64.c @@ -23,7 +23,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata, if (irq_prepare_move(irq, cpu)) return -1; - __get_cached_msi_msg(idata->msi_desc, &msg); + __get_cached_msi_msg(irq_data_get_msi_desc(idata), &msg); addr = msg.address_lo; addr &= MSI_ADDR_DEST_ID_MASK; diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c index a0eb27b66d13..59ba6322b9f6 100644 --- a/arch/ia64/sn/kernel/msi_sn.c +++ b/arch/ia64/sn/kernel/msi_sn.c @@ -175,7 +175,7 @@ static int sn_set_msi_irq_affinity(struct irq_data *data, * Release XIO resources for the old MSI PCI address */ - __get_cached_msi_msg(data->msi_desc, &msg); + __get_cached_msi_msg(irq_data_get_msi_desc(data), &msg); sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; pdev = sn_pdev->pdi_linux_pcidev; provider = SN_PCIDEV_BUSPROVIDER(pdev); diff --git a/arch/powerpc/sysdev/xics/ics-opal.c b/arch/powerpc/sysdev/xics/ics-opal.c index 68c7e5cc98e0..11ac964d5175 100644 --- a/arch/powerpc/sysdev/xics/ics-opal.c +++ b/arch/powerpc/sysdev/xics/ics-opal.c @@ -72,7 +72,7 @@ static unsigned int ics_opal_startup(struct irq_data *d) * card, using the MSI mask bits. Firmware doesn't appear to unmask * at that level, so we do it here by hand. */ - if (d->msi_desc) + if (irq_data_get_msi_desc(d)) pci_msi_unmask_irq(d); #endif diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c index 0af97deb83f3..d1c625c4cc5a 100644 --- a/arch/powerpc/sysdev/xics/ics-rtas.c +++ b/arch/powerpc/sysdev/xics/ics-rtas.c @@ -75,7 +75,7 @@ static unsigned int ics_rtas_startup(struct irq_data *d) * card, using the MSI mask bits. Firmware doesn't appear to unmask * at that level, so we do it here by hand. */ - if (d->msi_desc) + if (irq_data_get_msi_desc(d)) pci_msi_unmask_irq(d); #endif /* unmask it */ diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c index b1df847d0686..65b701b3b5ed 100644 --- a/arch/tile/kernel/pci_gx.c +++ b/arch/tile/kernel/pci_gx.c @@ -1442,7 +1442,7 @@ static struct pci_ops tile_cfg_ops = { /* MSI support starts here. */ static unsigned int tilegx_msi_startup(struct irq_data *d) { - if (d->msi_desc) + if (irq_data_get_msi_desc(d)) pci_msi_unmask_irq(d); return 0; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 64673f13bbb9..157eb8817fb8 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1145,7 +1145,7 @@ EXPORT_SYMBOL(pci_enable_msix_range); */ void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg) { - struct msi_desc *desc = irq_data->msi_desc; + struct msi_desc *desc = irq_data_get_msi_desc(irq_data); /* * For MSI-X desc->irq is always equal to irq_data->irq. For -- cgit v1.3-6-gb490 From 40b6d3faef73e6a877fe157f48df1af90bddd9e5 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:23 +0800 Subject: PCI/keystone: Use irq_data_get_msi_desc() to avoid redundant lookup of irq_data Use irq_data_get_msi_desc() to avoid redundant lookup of irq_data while we already have a pointer to corresponding irq_data. Signed-off-by: Jiang Liu Cc: Bjorn Helgaas Cc: Murali Karicheri Cc: linux-pci@vger.kernel.org Signed-off-by: Thomas Gleixner --- drivers/pci/host/pci-keystone-dw.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c index f34892e0edb4..e42d077039d3 100644 --- a/drivers/pci/host/pci-keystone-dw.c +++ b/drivers/pci/host/pci-keystone-dw.c @@ -104,14 +104,13 @@ static void ks_dw_pcie_msi_irq_ack(struct irq_data *d) { u32 offset, reg_offset, bit_pos; struct keystone_pcie *ks_pcie; - unsigned int irq = d->irq; struct msi_desc *msi; struct pcie_port *pp; - msi = irq_get_msi_desc(irq); + msi = irq_data_get_msi_desc(d); pp = sys_to_pcie(msi->dev->bus->sysdata); ks_pcie = to_keystone_pcie(pp); - offset = irq - irq_linear_revmap(pp->irq_domain, 0); + offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); update_reg_offset_bit_pos(offset, ®_offset, &bit_pos); writel(BIT(bit_pos), @@ -142,15 +141,14 @@ void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) static void ks_dw_pcie_msi_irq_mask(struct irq_data *d) { struct keystone_pcie *ks_pcie; - unsigned int irq = d->irq; struct msi_desc *msi; struct pcie_port *pp; u32 offset; - msi = irq_get_msi_desc(irq); + msi = irq_data_get_msi_desc(d); pp = sys_to_pcie(msi->dev->bus->sysdata); ks_pcie = to_keystone_pcie(pp); - offset = irq - irq_linear_revmap(pp->irq_domain, 0); + offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); /* Mask the end point if PVM implemented */ if (IS_ENABLED(CONFIG_PCI_MSI)) { @@ -164,15 +162,14 @@ static void ks_dw_pcie_msi_irq_mask(struct irq_data *d) static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d) { struct keystone_pcie *ks_pcie; - unsigned int irq = d->irq; struct msi_desc *msi; struct pcie_port *pp; u32 offset; - msi = irq_get_msi_desc(irq); + msi = irq_data_get_msi_desc(d); pp = sys_to_pcie(msi->dev->bus->sysdata); ks_pcie = to_keystone_pcie(pp); - offset = irq - irq_linear_revmap(pp->irq_domain, 0); + offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); /* Mask the end point if PVM implemented */ if (IS_ENABLED(CONFIG_PCI_MSI)) { -- cgit v1.3-6-gb490 From 5168a73ce32d38170a943aab4ff3402e2ddce641 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:05 +0200 Subject: PCI/keystone: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Murali Karicheri Cc: Bjorn Helgaas Cc: linux-pci@vger.kernel.org Cc: Jiang Liu --- drivers/pci/host/pci-keystone.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index 734da589cdfb..5998e93a03b1 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -212,9 +212,9 @@ static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) /* Legacy IRQ */ for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) { - irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie); - irq_set_chained_handler(ks_pcie->legacy_host_irqs[i], - ks_pcie_legacy_irq_handler); + irq_set_chained_handler_and_data(ks_pcie->legacy_host_irqs[i], + ks_pcie_legacy_irq_handler, + ks_pcie); } ks_dw_pcie_enable_legacy_irqs(ks_pcie); -- cgit v1.3-6-gb490 From 97a859641ba1a5d7adf547ab971ab1867b467493 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 23:24:10 +0200 Subject: PCI/keystone: Prepare irq handlers for irq argument removal Signed-off-by: Thomas Gleixner --- drivers/pci/host/pci-keystone.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index 5998e93a03b1..81253e70b1c5 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -110,8 +110,9 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) return -EINVAL; } -static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc) +static void ks_pcie_msi_irq_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); u32 offset = irq - ks_pcie->msi_host_irqs[0]; struct pcie_port *pp = &ks_pcie->pp; @@ -137,8 +138,10 @@ static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc) * Traverse through pending legacy interrupts and invoke handler for each. Also * takes care of interrupt controller level mask/ack operation. */ -static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc) +static void ks_pcie_legacy_irq_handler(unsigned int __irq, + struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); struct pcie_port *pp = &ks_pcie->pp; u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0]; -- cgit v1.3-6-gb490 From eb0b3e78e6290e5a1bf970830939d5c8c9151892 Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Tue, 7 Jul 2015 20:43:26 +0800 Subject: acpi-cpufreq: replace per_cpu with driver_data of policy Drivers can store their internal per-policy information in policy->driver_data, lets use it. we have benefits after this replacing. 1) memory saving. 2) policy is shared by several cpus, per_cpu seems not correct. using *driver_data* is more reasonable. 3) fix a memory leak in acpi_cpufreq_cpu_exit. as policy->cpu might change during cpu hotplug. So sometimes we cant't free *data*, use *driver_data* to fix it. 4) fix a zero return value of get_cur_freq_on_cpu. Only per_cpu of policy->cpu is set to *data*, if we try to get cpufreq on other cpus, we get zero instead of correct values. Use *driver_data* to fix it. Signed-off-by: Pan Xinhui Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/acpi-cpufreq.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 0136dfcdabf0..e7fcaa6eedbd 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -72,8 +72,6 @@ struct acpi_cpufreq_data { cpumask_var_t freqdomain_cpus; }; -static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data); - /* acpi_perf_data is a pointer to percpu data. */ static struct acpi_processor_performance __percpu *acpi_perf_data; @@ -144,7 +142,7 @@ static int _store_boost(int val) static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf) { - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + struct acpi_cpufreq_data *data = policy->driver_data; return cpufreq_show_cpus(data->freqdomain_cpus, buf); } @@ -327,7 +325,8 @@ static void drv_write(struct drv_cmd *cmd) put_cpu(); } -static u32 get_cur_val(const struct cpumask *mask) +static u32 +get_cur_val(const struct cpumask *mask, struct acpi_cpufreq_data *data) { struct acpi_processor_performance *perf; struct drv_cmd cmd; @@ -335,7 +334,7 @@ static u32 get_cur_val(const struct cpumask *mask) if (unlikely(cpumask_empty(mask))) return 0; - switch (per_cpu(acfreq_data, cpumask_first(mask))->cpu_feature) { + switch (data->cpu_feature) { case SYSTEM_INTEL_MSR_CAPABLE: cmd.type = SYSTEM_INTEL_MSR_CAPABLE; cmd.addr.msr.reg = MSR_IA32_PERF_CTL; @@ -346,7 +345,7 @@ static u32 get_cur_val(const struct cpumask *mask) break; case SYSTEM_IO_CAPABLE: cmd.type = SYSTEM_IO_CAPABLE; - perf = per_cpu(acfreq_data, cpumask_first(mask))->acpi_data; + perf = data->acpi_data; cmd.addr.io.port = perf->control_register.address; cmd.addr.io.bit_width = perf->control_register.bit_width; break; @@ -364,19 +363,24 @@ static u32 get_cur_val(const struct cpumask *mask) static unsigned int get_cur_freq_on_cpu(unsigned int cpu) { - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu); + struct acpi_cpufreq_data *data; + struct cpufreq_policy *policy; unsigned int freq; unsigned int cached_freq; pr_debug("get_cur_freq_on_cpu (%d)\n", cpu); - if (unlikely(data == NULL || - data->acpi_data == NULL || data->freq_table == NULL)) { + policy = cpufreq_cpu_get(cpu); + if (unlikely(!policy)) + return 0; + + data = policy->driver_data; + cpufreq_cpu_put(policy); + if (unlikely(!data || !data->acpi_data || !data->freq_table)) return 0; - } cached_freq = data->freq_table[data->acpi_data->state].frequency; - freq = extract_freq(get_cur_val(cpumask_of(cpu)), data); + freq = extract_freq(get_cur_val(cpumask_of(cpu), data), data); if (freq != cached_freq) { /* * The dreaded BIOS frequency change behind our back. @@ -397,7 +401,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq, unsigned int i; for (i = 0; i < 100; i++) { - cur_freq = extract_freq(get_cur_val(mask), data); + cur_freq = extract_freq(get_cur_val(mask, data), data); if (cur_freq == freq) return 1; udelay(10); @@ -408,7 +412,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq, static int acpi_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) { - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + struct acpi_cpufreq_data *data = policy->driver_data; struct acpi_processor_performance *perf; struct drv_cmd cmd; unsigned int next_perf_state = 0; /* Index into perf table */ @@ -673,7 +677,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) } data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu); - per_cpu(acfreq_data, cpu) = data; + policy->driver_data = data; if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; @@ -843,19 +847,19 @@ err_free_mask: free_cpumask_var(data->freqdomain_cpus); err_free: kfree(data); - per_cpu(acfreq_data, cpu) = NULL; + policy->driver_data = NULL; return result; } static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) { - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + struct acpi_cpufreq_data *data = policy->driver_data; pr_debug("acpi_cpufreq_cpu_exit\n"); if (data) { - per_cpu(acfreq_data, policy->cpu) = NULL; + policy->driver_data = NULL; acpi_processor_unregister_performance(data->acpi_data, policy->cpu); free_cpumask_var(data->freqdomain_cpus); @@ -868,7 +872,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) static int acpi_cpufreq_resume(struct cpufreq_policy *policy) { - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + struct acpi_cpufreq_data *data = policy->driver_data; pr_debug("acpi_cpufreq_resume\n"); -- cgit v1.3-6-gb490 From 8101f99703048ceaa31c756abe1098d099249ad9 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 8 Jul 2015 15:12:15 +0530 Subject: cpufreq: cpufreq_add_dev: name goto labels based on what they do These labels are are named in two ways normally: - Based on what caused to jump to such labels - Based on what we do under such labels We follow the first naming convention today and that leads to multiple labels for doing the same work. Fix it by switching to the second way of naming them. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 26063afb3eba..702777b1d645 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1288,7 +1288,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) recover_policy = false; policy = cpufreq_policy_alloc(dev); if (!policy) - goto nomem_out; + goto out_release_rwsem; } cpumask_copy(policy->cpus, cpumask_of(cpu)); @@ -1299,7 +1299,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) ret = cpufreq_driver->init(policy); if (ret) { pr_debug("initialization failed\n"); - goto err_set_policy_cpu; + goto out_free_policy; } down_write(&policy->rwsem); @@ -1327,7 +1327,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) policy->cur = cpufreq_driver->get(policy->cpu); if (!policy->cur) { pr_err("%s: ->get() failed\n", __func__); - goto err_get_freq; + goto out_exit_policy; } } @@ -1377,7 +1377,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) if (!recover_policy) { ret = cpufreq_add_dev_interface(policy, dev); if (ret) - goto err_out_unregister; + goto out_exit_policy; blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_CREATE_POLICY, policy); @@ -1406,15 +1406,14 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) return 0; -err_out_unregister: -err_get_freq: +out_exit_policy: up_write(&policy->rwsem); if (cpufreq_driver->exit) cpufreq_driver->exit(policy); -err_set_policy_cpu: +out_free_policy: cpufreq_policy_free(policy, recover_policy); -nomem_out: +out_release_rwsem: up_read(&cpufreq_rwsem); return ret; -- cgit v1.3-6-gb490 From 7f0fa40f5a587c2a026de776cc6a26373ac0f244 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 8 Jul 2015 15:12:16 +0530 Subject: cpufreq: Properly handle errors from cpufreq_init_policy() cpufreq_init_policy() can fail, and we don't do anything except a call to ->exit() on that. The policy should be freed if this happens. Do it properly. Reported-and-tested-by: "Jon Medhurst (Tixy)" Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 702777b1d645..a7b6ac6e048e 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1060,11 +1060,10 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy, return cpufreq_add_dev_symlink(policy); } -static void cpufreq_init_policy(struct cpufreq_policy *policy) +static int cpufreq_init_policy(struct cpufreq_policy *policy) { struct cpufreq_governor *gov = NULL; struct cpufreq_policy new_policy; - int ret = 0; memcpy(&new_policy, policy, sizeof(*policy)); @@ -1083,12 +1082,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) cpufreq_parse_governor(gov->name, &new_policy.policy, NULL); /* set default policy */ - ret = cpufreq_set_policy(policy, &new_policy); - if (ret) { - pr_debug("setting policy failed\n"); - if (cpufreq_driver->exit) - cpufreq_driver->exit(policy); - } + return cpufreq_set_policy(policy, &new_policy); } static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, @@ -1386,7 +1380,12 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) write_unlock_irqrestore(&cpufreq_driver_lock, flags); } - cpufreq_init_policy(policy); + ret = cpufreq_init_policy(policy); + if (ret) { + pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n", + __func__, cpu, ret); + goto out_remove_policy_notify; + } if (!recover_policy) { policy->user_policy.policy = policy->policy; @@ -1406,6 +1405,9 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) return 0; +out_remove_policy_notify: + /* cpufreq_policy_free() will notify based on this */ + recover_policy = true; out_exit_policy: up_write(&policy->rwsem); -- cgit v1.3-6-gb490 From 8cfcfd39000d54188e0df1e0fafe63f53897b62a Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Fri, 10 Jul 2015 14:36:20 +0800 Subject: acpi-cpufreq: Fix an ACPI perf unregister issue As policy->cpu may not be same in acpi_cpufreq_cpu_init() and acpi_cpufreq_cpu_exit(). There is a risk that we use different CPU to un/register ACPI performance. So acpi_processor_unregister_performance() may not be able to do the cleanup work. That causes a memory leak. And if there will be another acpi_processor_register_performance() call, it may also fail thanks to the internal check of pr->performace. So add a new struct acpi_cpufreq_data field, acpi_perf_cpu, to fix this issue. Signed-off-by: Pan Xinhui Acked-by: Viresh Kumar [ rjw: Changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/acpi-cpufreq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index e7fcaa6eedbd..de54ce14eb39 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -69,6 +69,7 @@ struct acpi_cpufreq_data { struct cpufreq_frequency_table *freq_table; unsigned int resume; unsigned int cpu_feature; + unsigned int acpi_perf_cpu; cpumask_var_t freqdomain_cpus; }; @@ -677,6 +678,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) } data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu); + data->acpi_perf_cpu = cpu; policy->driver_data = data; if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) @@ -861,7 +863,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) if (data) { policy->driver_data = NULL; acpi_processor_unregister_performance(data->acpi_data, - policy->cpu); + data->acpi_perf_cpu); free_cpumask_var(data->freqdomain_cpus); kfree(data->freq_table); kfree(data); -- cgit v1.3-6-gb490 From 3a5f5b2e3b4ba165e342c4e969c7fa8d85be0d94 Mon Sep 17 00:00:00 2001 From: Cristian Ardelean Date: Fri, 10 Jul 2015 14:42:15 -0400 Subject: cpufreq: integrator: fixed coding style issues Fixed coding style issues found by checkpatch.pl tool. Changed space indentation to tab, removed unneccesary braces, removed space between MODULE macros and parentheses. REMARKS: failed to 'make' this file with error message 'fatal error: asm/mach-types.h: No such file or directory'. Signed-off-by: Cristian Ardelean Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/integrator-cpufreq.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/integrator-cpufreq.c b/drivers/cpufreq/integrator-cpufreq.c index 129e266f7621..2faa4216bf2a 100644 --- a/drivers/cpufreq/integrator-cpufreq.c +++ b/drivers/cpufreq/integrator-cpufreq.c @@ -98,11 +98,10 @@ static int integrator_set_target(struct cpufreq_policy *policy, /* get current setting */ cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET); - if (machine_is_integrator()) { + if (machine_is_integrator()) vco.s = (cm_osc >> 8) & 7; - } else if (machine_is_cintegrator()) { + else if (machine_is_cintegrator()) vco.s = 1; - } vco.v = cm_osc & 255; vco.r = 22; freqs.old = icst_hz(&cclk_params, vco) / 1000; @@ -163,11 +162,10 @@ static unsigned int integrator_get(unsigned int cpu) /* detect memory etc. */ cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET); - if (machine_is_integrator()) { + if (machine_is_integrator()) vco.s = (cm_osc >> 8) & 7; - } else { + else vco.s = 1; - } vco.v = cm_osc & 255; vco.r = 22; @@ -203,7 +201,7 @@ static int __init integrator_cpufreq_probe(struct platform_device *pdev) struct resource *res; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) + if (!res) return -ENODEV; cm_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); @@ -234,6 +232,6 @@ static struct platform_driver integrator_cpufreq_driver = { module_platform_driver_probe(integrator_cpufreq_driver, integrator_cpufreq_probe); -MODULE_AUTHOR ("Russell M. King"); -MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs"); -MODULE_LICENSE ("GPL"); +MODULE_AUTHOR("Russell M. King"); +MODULE_DESCRIPTION("cpufreq driver for ARM Integrator CPUs"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From ba88d4338f226766f510e207911dde8c1875e072 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Tue, 14 Jul 2015 09:46:23 -0700 Subject: intel_pstate: enable HWP per CPU HWP previously was only enabled at driver load time, on the boot CPU, however, HWP must be enabled per package. Move the code to enable HWP to the cpufreq driver init path so that it will be called per CPU. Signed-off-by: Kristen Carlson Accardi Tested-by: David Zhuang Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 15ada47bb720..763d8f34ab49 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -484,12 +484,11 @@ static void __init intel_pstate_sysfs_expose_params(void) } /************************** sysfs end ************************/ -static void intel_pstate_hwp_enable(void) +static void intel_pstate_hwp_enable(struct cpudata *cpudata) { - hwp_active++; pr_info("intel_pstate: HWP enabled\n"); - wrmsrl( MSR_PM_ENABLE, 0x1); + wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1); } static int byt_get_min_pstate(void) @@ -932,6 +931,10 @@ static int intel_pstate_init_cpu(unsigned int cpunum) cpu = all_cpu_data[cpunum]; cpu->cpu = cpunum; + + if (hwp_active) + intel_pstate_hwp_enable(cpu); + intel_pstate_get_cpu_pstates(cpu); init_timer_deferrable(&cpu->timer); @@ -1245,7 +1248,7 @@ static int __init intel_pstate_init(void) return -ENOMEM; if (static_cpu_has_safe(X86_FEATURE_HWP) && !no_hwp) - intel_pstate_hwp_enable(); + hwp_active++; if (!hwp_active && hwp_only) goto out; -- cgit v1.3-6-gb490 From 546aee51ecacf6605b15f6a2580926f956dc5a3e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 1 Jul 2015 17:12:45 +0530 Subject: drm/mgag200: remove unused variables These variables were assigned some values but they were never used. Signed-off-by: Sudip Mukherjee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/mgag200/mgag200_fb.c | 2 -- drivers/gpu/drm/mgag200/mgag200_mode.c | 9 +++------ 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c index c36b8304042b..958cf3cf082d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_fb.c +++ b/drivers/gpu/drm/mgag200/mgag200_fb.c @@ -167,7 +167,6 @@ static int mgag200fb_create(struct drm_fb_helper *helper, struct drm_framebuffer *fb; struct drm_gem_object *gobj = NULL; struct device *device = &dev->pdev->dev; - struct mgag200_bo *bo; int ret; void *sysram; int size; @@ -185,7 +184,6 @@ static int mgag200fb_create(struct drm_fb_helper *helper, DRM_ERROR("failed to create fbcon backing object %d\n", ret); return ret; } - bo = gem_to_mga_bo(gobj); sysram = vmalloc(size); if (!sysram) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 6e84df9369a6..67ae9f79dbd2 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -158,7 +158,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) { unsigned int vcomax, vcomin, pllreffreq; - unsigned int delta, tmpdelta, permitteddelta; + unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n; unsigned int computed; @@ -172,7 +172,6 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) pllreffreq = 48000; delta = 0xffffffff; - permitteddelta = clock * 5 / 1000; for (testp = 1; testp < 9; testp++) { if (clock * testp > vcomax) @@ -298,7 +297,7 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) { unsigned int vcomax, vcomin, pllreffreq; - unsigned int delta, tmpdelta, permitteddelta; + unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n; unsigned int computed; @@ -310,7 +309,6 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) pllreffreq = 50000; delta = 0xffffffff; - permitteddelta = clock * 5 / 1000; for (testp = 16; testp > 0; testp--) { if (clock * testp > vcomax) @@ -392,7 +390,7 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) { unsigned int vcomax, vcomin, pllreffreq; - unsigned int delta, tmpdelta, permitteddelta; + unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n; unsigned int computed; @@ -406,7 +404,6 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) pllreffreq = 33333; delta = 0xffffffff; - permitteddelta = clock * 5 / 1000; for (testp = 16; testp > 0; testp >>= 1) { if (clock * testp > vcomax) -- cgit v1.3-6-gb490 From f9fe4b9b2ad4f2b801fdff3d634b07c9f9fc4327 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 1 Jul 2015 17:12:46 +0530 Subject: drm/mgag200: remove unneeded variable ttm_bo_validate() returns 0 or error. So we can return the value directly and remove the variable 'ret'. Signed-off-by: Sudip Mukherjee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/mgag200/mgag200_ttm.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index d16964ea0ed4..05108b505fbf 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -378,7 +378,7 @@ int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr) int mgag200_bo_unpin(struct mgag200_bo *bo) { - int i, ret; + int i; if (!bo->pin_count) { DRM_ERROR("unpin bad %p\n", bo); return 0; @@ -389,11 +389,7 @@ int mgag200_bo_unpin(struct mgag200_bo *bo) for (i = 0; i < bo->placement.num_placement ; i++) bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; - ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); - if (ret) - return ret; - - return 0; + return ttm_bo_validate(&bo->bo, &bo->placement, false, false); } int mgag200_bo_push_sysram(struct mgag200_bo *bo) -- cgit v1.3-6-gb490 From 661abfc028886eb1c6b5b9dbc433ef8cfb11217d Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 16 Jul 2015 19:36:51 +0300 Subject: drm/i915: Fix divide by zero on watermark update Fix divide by zero if we end up updating the watermarks with zero dotclock. This is a stop gap measure to allow module load in cases where our state keeping fails. v2: WARN_ON added (Paulo) Cc: Paulo Zanoni Cc: Damien Lespiau Signed-off-by: Mika Kuoppala Reviewed-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5eeddc97ca2a..0d3e01434860 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3316,8 +3316,10 @@ skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p) if (!to_intel_crtc(crtc)->active) return 0; - return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate); + if (WARN_ON(p->pixel_rate == 0)) + return 0; + return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate); } static void skl_compute_transition_wm(struct drm_crtc *crtc, -- cgit v1.3-6-gb490 From edd43ed8cebafd29cc24e4798cdf0412c668e644 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 16 Jul 2015 17:08:08 +0100 Subject: drm/i915/skl: Don't expose the top most plane on gen9 display on SKL/BXT, the top most plane hardware is shared between the legacy cursor registers and an actual plane. Daniel and Ville don't want to expose 2 DRM planes and would rather expose a CURSOR plane that has all the usual plane properties, and that's a blocker for lifting the prelimary_hw_support flag. Unfortunately noone has had the time to finish this yet, but lifting the prelimary_hw_support flag is long overdue. As an intermediate solution we can merely not expose the top most plane Cc: Imre Deak Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 5e63076cc769..b1f9e5561cf2 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -726,11 +726,19 @@ static void intel_device_info_runtime_init(struct drm_device *dev) info = (struct intel_device_info *)&dev_priv->info; + /* + * Skylake and Broxton currently don't expose the topmost plane as its + * use is exclusive with the legacy cursor and we only want to expose + * one of those, not both. Until we can safely expose the topmost plane + * as a DRM_PLANE_TYPE_CURSOR with all the features exposed/supported, + * we don't expose the topmost plane at all to prevent ABI breakage + * down the line. + */ if (IS_BROXTON(dev)) { - info->num_sprites[PIPE_A] = 3; - info->num_sprites[PIPE_B] = 3; - info->num_sprites[PIPE_C] = 2; - } else if (IS_VALLEYVIEW(dev) || INTEL_INFO(dev)->gen == 9) + info->num_sprites[PIPE_A] = 2; + info->num_sprites[PIPE_B] = 2; + info->num_sprites[PIPE_C] = 1; + } else if (IS_VALLEYVIEW(dev)) for_each_pipe(dev_priv, pipe) info->num_sprites[pipe] = 2; else -- cgit v1.3-6-gb490 From 4b0c8bb016e7f36e2d6ec230f9177f88def690d5 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 16 Jul 2015 17:08:09 +0100 Subject: drm/i915/skl: Drop the preliminary_hw_support flag Time to light a candle and remove the preliminary_hw_support flag. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f13ed1ef6641..0d6775a3e88c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -356,7 +356,6 @@ static const struct intel_device_info intel_cherryview_info = { }; static const struct intel_device_info intel_skylake_info = { - .is_preliminary = 1, .is_skylake = 1, .gen = 9, .num_pipes = 3, .need_gfx_hws = 1, .has_hotplug = 1, @@ -369,7 +368,6 @@ static const struct intel_device_info intel_skylake_info = { }; static const struct intel_device_info intel_skylake_gt3_info = { - .is_preliminary = 1, .is_skylake = 1, .gen = 9, .num_pipes = 3, .need_gfx_hws = 1, .has_hotplug = 1, -- cgit v1.3-6-gb490 From 015403145a65f0a0f7c4d9badfb12759349d1e13 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 9 Jul 2015 22:19:53 +0900 Subject: gpio: etraxfs: Fix devm_ioremap_resource return value check Value returned by devm_ioremap_resource() was checked for non-NULL but devm_ioremap_resource() returns IOMEM_ERR_PTR, not NULL. In case of error this could lead to dereference of ERR_PTR. Signed-off-by: Krzysztof Kozlowski Acked-by: Alexandre Courbot Acked-by: Rabin Vincent Signed-off-by: Linus Walleij --- drivers/gpio/gpio-etraxfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c index 28071f4a5672..0e643140efde 100644 --- a/drivers/gpio/gpio-etraxfs.c +++ b/drivers/gpio/gpio-etraxfs.c @@ -117,8 +117,8 @@ static int etraxfs_gpio_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); - if (!regs) - return -ENOMEM; + if (IS_ERR(regs)) + return PTR_ERR(regs); match = of_match_node(etraxfs_gpio_of_table, dev->of_node); if (!match) -- cgit v1.3-6-gb490 From ad64498762dd6f262f8c7c37926cd56693e109ba Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 6 Jul 2015 18:09:30 -0700 Subject: pinctrl: qcom: Hook pm_power_down for shutdown support Assign pm_power_off() if we have the PS_HOLD functionality so that we can properly shutdown the SoC. Otherwise, shutdown won't do anything besides put the CPU into a tight loop. Unfortunately, we have to use a singleton here because pm_power_off() doesn't take any arguments. Fortunately there's only one instance of the pinctrl device on a running system so this isn't a problem. Cc: Pramod Gurav Signed-off-by: Stephen Boyd Acked-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-msm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index e457d52302a2..6242af8a42d5 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "../core.h" #include "../pinconf.h" @@ -855,6 +856,13 @@ static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action, return NOTIFY_DONE; } +static struct msm_pinctrl *poweroff_pctrl; + +static void msm_ps_hold_poweroff(void) +{ + msm_ps_hold_restart(&poweroff_pctrl->restart_nb, 0, NULL); +} + static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) { int i; @@ -867,6 +875,8 @@ static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) if (register_restart_handler(&pctrl->restart_nb)) dev_err(pctrl->dev, "failed to setup restart handler.\n"); + poweroff_pctrl = pctrl; + pm_power_off = msm_ps_hold_poweroff; break; } } -- cgit v1.3-6-gb490 From d9f2d203ab42f099b32ec4580e43eb08b3e4c412 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 13 Jul 2015 18:03:44 -0700 Subject: HID: wacom: Properly free inputs if 'wacom_allocate_inputs' fails The 'wacom_allocate_inputs' function tries to allocate three input devices: one each for the pen, touch, and pad. The pointers that are returned by the 'wacom_allocate_input' calls are temporarily stored to local variables where they are checked to ensure they're non-null before storing them in the 'wacom_wac' structure. If an allocation fails, the 'wacom_free_inputs' function is called to reclaim the memory. Unfortunately, 'wacom_free_inputs' is called prior to the pointers being copied, so it is not actually able to free anything. This patch has the calls to 'wacom_allocate_input' store the pointer directly in the 'wacom_wac' structure where they can be freed. Also, it replaces the call to 'wacom_free_inputs' with the (more general) 'wacom_clean_inputs' and removes the no-longer-used function. [jkosina@suse.com: modify to resolve conflict with 67e123f ("Delete unnecessary checks")] Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 52 +++++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 936ad7770ec3..3512d833cc24 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1145,40 +1145,6 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom) return input_dev; } -static void wacom_free_inputs(struct wacom *wacom) -{ - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - - input_free_device(wacom_wac->pen_input); - input_free_device(wacom_wac->touch_input); - input_free_device(wacom_wac->pad_input); - wacom_wac->pen_input = NULL; - wacom_wac->touch_input = NULL; - wacom_wac->pad_input = NULL; -} - -static int wacom_allocate_inputs(struct wacom *wacom) -{ - struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - - pen_input_dev = wacom_allocate_input(wacom); - touch_input_dev = wacom_allocate_input(wacom); - pad_input_dev = wacom_allocate_input(wacom); - if (!pen_input_dev || !touch_input_dev || !pad_input_dev) { - wacom_free_inputs(wacom); - return -ENOMEM; - } - - wacom_wac->pen_input = pen_input_dev; - wacom_wac->touch_input = touch_input_dev; - wacom_wac->touch_input->name = wacom_wac->touch_name; - wacom_wac->pad_input = pad_input_dev; - wacom_wac->pad_input->name = wacom_wac->pad_name; - - return 0; -} - static void wacom_clean_inputs(struct wacom *wacom) { if (wacom->wacom_wac.pen_input) { @@ -1205,6 +1171,24 @@ static void wacom_clean_inputs(struct wacom *wacom) wacom_destroy_leds(wacom); } +static int wacom_allocate_inputs(struct wacom *wacom) +{ + struct wacom_wac *wacom_wac = &(wacom->wacom_wac); + + wacom_wac->pen_input = wacom_allocate_input(wacom); + wacom_wac->touch_input = wacom_allocate_input(wacom); + wacom_wac->pad_input = wacom_allocate_input(wacom); + if (!wacom_wac->pen_input || !wacom_wac->touch_input || !wacom_wac->pad_input) { + wacom_clean_inputs(wacom); + return -ENOMEM; + } + + wacom_wac->touch_input->name = wacom_wac->touch_name; + wacom_wac->pad_input->name = wacom_wac->pad_name; + + return 0; +} + static int wacom_register_inputs(struct wacom *wacom) { struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; -- cgit v1.3-6-gb490 From 2bdd163cfd262914e8f6152e37aebea2034f801e Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 13 Jul 2015 18:03:45 -0700 Subject: HID: wacom: Set default device name to value from wacom->features Allocated input devices should not use the 'pen_name' by default since we do not know at that point in time if that is an appropriate choice of name. Instead, use the (tool-agnostic) name that is stored in the device's 'wacom_features' structure. This also has the nice side-effect of requring us to be explicit about the naming of the pen device, as we already are for touch and pad devices. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 3512d833cc24..2a221630d8dc 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1130,7 +1130,7 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom) if (!input_dev) return NULL; - input_dev->name = wacom_wac->pen_name; + input_dev->name = wacom_wac->features.name; input_dev->phys = hdev->phys; input_dev->dev.parent = &hdev->dev; input_dev->open = wacom_open; @@ -1183,6 +1183,7 @@ static int wacom_allocate_inputs(struct wacom *wacom) return -ENOMEM; } + wacom_wac->pen_input->name = wacom_wac->pen_name; wacom_wac->touch_input->name = wacom_wac->touch_name; wacom_wac->pad_input->name = wacom_wac->pad_name; -- cgit v1.3-6-gb490 From 9a98b3387e7bd9af5a6495b32e07d6f25071f4ba Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Thu, 16 Jul 2015 17:14:00 -0700 Subject: HID: rmi: Set F01 interrupt enable register when not set A firmware bug in some touchpads causes the F01 interrupt enable register to be cleared on reset. This register controls which RMI functions generate interrupts and when it is cleared, the touchpad stops reporting all data. This patch looks for the cleared F01 control register and writes the correct value based on interrupt mask computed while scanning the PDT. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=91102 Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina --- drivers/hid/hid-rmi.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 9a792e725ea3..2c148129beb2 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -141,6 +141,8 @@ struct rmi_data { unsigned long firmware_id; u8 f01_ctrl0; + u8 interrupt_enable_mask; + bool restore_interrupt_mask; }; #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) @@ -361,13 +363,34 @@ static void rmi_f11_process_touch(struct rmi_data *hdata, int slot, } } +static int rmi_reset_attn_mode(struct hid_device *hdev) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + + ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + if (ret) + return ret; + + if (data->restore_interrupt_mask) { + ret = rmi_write(hdev, data->f01.control_base_addr + 1, + &data->interrupt_enable_mask); + if (ret) { + hid_err(hdev, "can not write F01 control register\n"); + return ret; + } + } + + return 0; +} + static void rmi_reset_work(struct work_struct *work) { struct rmi_data *hdata = container_of(work, struct rmi_data, reset_work); /* switch the device to RMI if we receive a generic mouse report */ - rmi_set_mode(hdata->hdev, RMI_MODE_ATTN_REPORTS); + rmi_reset_attn_mode(hdata->hdev); } static inline int rmi_schedule_reset(struct hid_device *hdev) @@ -590,7 +613,7 @@ static int rmi_post_reset(struct hid_device *hdev) struct rmi_data *data = hid_get_drvdata(hdev); int ret; - ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + ret = rmi_reset_attn_mode(hdev); if (ret) { hid_err(hdev, "can not set rmi mode\n"); return ret; @@ -617,7 +640,7 @@ static int rmi_post_reset(struct hid_device *hdev) static int rmi_post_resume(struct hid_device *hdev) { - return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + return rmi_reset_attn_mode(hdev); } #endif /* CONFIG_PM */ @@ -673,6 +696,7 @@ static void rmi_register_function(struct rmi_data *data, f->interrupt_count = pdt_entry->interrupt_source_count; f->irq_mask = rmi_gen_mask(f->interrupt_base, f->interrupt_count); + data->interrupt_enable_mask |= f->irq_mask; } } @@ -810,12 +834,35 @@ static int rmi_populate_f01(struct hid_device *hdev) data->firmware_id += info[2] * 65536; } - ret = rmi_read(hdev, data->f01.control_base_addr, &data->f01_ctrl0); + ret = rmi_read_block(hdev, data->f01.control_base_addr, info, + 2); if (ret) { - hid_err(hdev, "can not read f01 ctrl0\n"); + hid_err(hdev, "can not read f01 ctrl registers\n"); return ret; } + + data->f01_ctrl0 = info[0]; + + if (!info[1]) { + /* + * Do to a firmware bug in some touchpads the F01 interrupt + * enable control register will be cleared on reset. + * This will stop the touchpad from reporting data, so + * if F01 CTRL1 is 0 then we need to explicitly enable + * interrupts for the functions we want data for. + */ + data->restore_interrupt_mask = true; + + ret = rmi_write(hdev, data->f01.control_base_addr + 1, + &data->interrupt_enable_mask); + if (ret) { + hid_err(hdev, "can not write to control reg 1: %d.\n", + ret); + return ret; + } + } + return 0; } -- cgit v1.3-6-gb490 From 41cc14ba11d7d8532ef4f615c39eb6ebdcdeef61 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:32:44 -0300 Subject: [media] ttusb-dec: use swap() in swap_bytes() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/ttusb-dec/ttusb_dec.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 322b53a4f1dd..7c3a7c55d969 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -593,14 +593,9 @@ static void ttusb_dec_process_packet(struct ttusb_dec *dec) static void swap_bytes(u8 *b, int length) { - u8 c; - length -= length % 2; - for (; length; b += 2, length -= 2) { - c = *b; - *b = *(b + 1); - *(b + 1) = c; - } + for (; length; b += 2, length -= 2) + swap(*b, *(b + 1)); } static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, -- cgit v1.3-6-gb490 From 3685bbce2ea6142e81c78e6f3d5b2a1cdc37660e Mon Sep 17 00:00:00 2001 From: Vitaly Andrianov Date: Thu, 2 Jul 2015 14:31:30 -0400 Subject: gpio/davinci: add interrupt support for GPIOs 16-31 Interrupts for GPIOs 16 through 31 are enabled by bit 1 in the "binten" register (offset 8). Previous versions of GPIO only used bit 0, which enables GPIO 0-15 interrupts. Signed-off-by: Vitaly Andrianov Reviewed-by: Grygorii Strashko Reviewed-by: Sekhar Nori Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index c5e05c82d67c..86cfe1892cae 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -545,7 +545,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) chips[0].chip.to_irq = gpio_to_irq_unbanked; chips[0].gpio_irq = bank_irq; chips[0].gpio_unbanked = pdata->gpio_unbanked; - binten = BIT(0); + binten = GENMASK(pdata->gpio_unbanked / 16, 0); /* AINTC handles mask/unmask; GPIO handles triggering */ irq = bank_irq; -- cgit v1.3-6-gb490 From fb8dfda980bdaf178a7addb0a4f68574e390a9d9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 23 Jun 2015 06:20:23 -0300 Subject: [media] v4l2-event: v4l2_event_queue: do nothing if vdev == NULL If the vdev pointer == NULL, then just return. This makes it easier for subdev drivers to use this function without having to check if the sd->devnode pointer is NULL or not. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-event.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c index 8761aab99de9..8d3171c6bee8 100644 --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c @@ -172,6 +172,9 @@ void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev) unsigned long flags; struct timespec timestamp; + if (vdev == NULL) + return; + ktime_get_ts(×tamp); spin_lock_irqsave(&vdev->fh_lock, flags); -- cgit v1.3-6-gb490 From 75629981069cf194336426bbbfb03f9c93d7ad67 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 14 Jul 2015 11:17:58 +0100 Subject: pinctrl: pinconf: Allow groups to be configured via debugfs The function pinconf_dbg_config_write() currently only supports configuring a pin configuration mapping via the debugfs. Allow group mappings to also be configured via the debugfs. Signed-off-by: Jon Hunter Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 1fc09dc20199..4744d6363dfb 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -470,10 +470,12 @@ exit: * pinconf_dbg_config_write() - modify the pinctrl config in the pinctrl * map, of a dev/pin/state entry based on user entries to pinconf-config * @user_buf: contains the modification request with expected format: - * modify config_pin + * modify * modify is literal string, alternatives like add/delete not supported yet - * config_pin is literal, alternatives like config_mux not supported yet - * are values that should match the pinctrl-maps + * is the configuration to be changed. Supported configs are + * "config_pin" or "config_group", alternatives like config_mux are not + * supported yet. + * are values that should match the pinctrl-maps * reflects the new config and is driver dependant */ static ssize_t pinconf_dbg_config_write(struct file *file, @@ -511,13 +513,19 @@ static ssize_t pinconf_dbg_config_write(struct file *file, if (strcmp(token, "modify")) return -EINVAL; - /* Get arg type: "config_pin" type supported so far */ + /* + * Get arg type: "config_pin" and "config_group" + * types are supported so far + */ token = strsep(&b, " "); if (!token) return -EINVAL; - if (strcmp(token, "config_pin")) + if (!strcmp(token, "config_pin")) + dbg->map_type = PIN_MAP_TYPE_CONFIGS_PIN; + else if (!strcmp(token, "config_group")) + dbg->map_type = PIN_MAP_TYPE_CONFIGS_GROUP; + else return -EINVAL; - dbg->map_type = PIN_MAP_TYPE_CONFIGS_PIN; /* get arg 'device_name' */ token = strsep(&b, " "); -- cgit v1.3-6-gb490 From d96310aeddc692cf1f06861cf722c4843e0a3f28 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 14 Jul 2015 11:17:59 +0100 Subject: pinctrl: pinconf: Fix display of configs The function pinconf_dbg_config_print() only prints the configuration of the 1st pin config in an array of pin configurations. Fix this so that all pin configurations in the array are displayed. There are a few places in the code where the pin configs are displayed and so add a helper function to display the pin configs to simplify the code. Signed-off-by: Jon Hunter Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf.c | 64 ++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 4744d6363dfb..cbf26a6992a0 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -202,18 +202,34 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) #ifdef CONFIG_DEBUG_FS -void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) +void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev, + unsigned long *configs, unsigned num_configs) { - struct pinctrl_dev *pctldev; const struct pinconf_ops *confops; int i; - pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); if (pctldev) confops = pctldev->desc->confops; else confops = NULL; + for (i = 0; i < num_configs; i++) { + seq_puts(s, "config "); + if (confops && confops->pin_config_config_dbg_show) + confops->pin_config_config_dbg_show(pctldev, s, + configs[i]); + else + seq_printf(s, "%08lx", configs[i]); + seq_puts(s, "\n"); + } +} + +void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) +{ + struct pinctrl_dev *pctldev; + + pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); + switch (map->type) { case PIN_MAP_TYPE_CONFIGS_PIN: seq_printf(s, "pin "); @@ -227,15 +243,8 @@ void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) seq_printf(s, "%s\n", map->data.configs.group_or_pin); - for (i = 0; i < map->data.configs.num_configs; i++) { - seq_printf(s, "config "); - if (confops && confops->pin_config_config_dbg_show) - confops->pin_config_config_dbg_show(pctldev, s, - map->data.configs.configs[i]); - else - seq_printf(s, "%08lx", map->data.configs.configs[i]); - seq_printf(s, "\n"); - } + pinconf_show_config(s, pctldev, map->data.configs.configs, + map->data.configs.num_configs); } void pinconf_show_setting(struct seq_file *s, @@ -243,9 +252,7 @@ void pinconf_show_setting(struct seq_file *s, { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; - const struct pinconf_ops *confops = pctldev->desc->confops; struct pin_desc *desc; - int i; switch (setting->type) { case PIN_MAP_TYPE_CONFIGS_PIN: @@ -269,17 +276,8 @@ void pinconf_show_setting(struct seq_file *s, * FIXME: We should really get the pin controler to dump the config * values, so they can be decoded to something meaningful. */ - for (i = 0; i < setting->data.configs.num_configs; i++) { - seq_printf(s, " "); - if (confops && confops->pin_config_config_dbg_show) - confops->pin_config_config_dbg_show(pctldev, s, - setting->data.configs.configs[i]); - else - seq_printf(s, "%08lx", - setting->data.configs.configs[i]); - } - - seq_printf(s, "\n"); + pinconf_show_config(s, pctldev, setting->data.configs.configs, + setting->data.configs.num_configs); } static void pinconf_dump_pin(struct pinctrl_dev *pctldev, @@ -412,10 +410,8 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) const struct pinctrl_map *map; const struct pinctrl_map *found = NULL; struct pinctrl_dev *pctldev; - const struct pinconf_ops *confops = NULL; struct dbg_cfg *dbg = &pinconf_dbg_conf; int i, j; - unsigned long config; mutex_lock(&pinctrl_maps_mutex); @@ -449,16 +445,10 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) } pctldev = get_pinctrl_dev_from_devname(found->ctrl_dev_name); - config = *found->data.configs.configs; - seq_printf(s, "Dev %s has config of %s in state %s: 0x%08lX\n", - dbg->dev_name, dbg->pin_name, - dbg->state_name, config); - - if (pctldev) - confops = pctldev->desc->confops; - - if (confops && confops->pin_config_config_dbg_show) - confops->pin_config_config_dbg_show(pctldev, s, config); + seq_printf(s, "Dev %s has config of %s in state %s:\n", + dbg->dev_name, dbg->pin_name, dbg->state_name); + pinconf_show_config(s, pctldev, found->data.configs.configs, + found->data.configs.num_configs); exit: mutex_unlock(&pinctrl_maps_mutex); -- cgit v1.3-6-gb490 From bd6eab90073814a3211fc9688c2d59ce369ccff2 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 15 Jul 2015 00:25:27 +0200 Subject: pinctrl: lpc18xx: add support for usb1 pinconf The dedicated USB1 pins can be configured with pull-down and for low power mode (suspend). Add support for this in the pinctrl driver. Signed-off-by: Joachim Eastwood Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-lpc18xx.c | 54 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c index ef0b697639a7..e56f9203cc87 100644 --- a/drivers/pinctrl/pinctrl-lpc18xx.c +++ b/drivers/pinctrl/pinctrl-lpc18xx.c @@ -37,6 +37,9 @@ #define LPC18XX_SCU_PIN_EHD_MASK 0x300 #define LPC18XX_SCU_PIN_EHD_POS 8 +#define LPC18XX_SCU_USB1_EPD BIT(2) +#define LPC18XX_SCU_USB1_EPWR BIT(4) + #define LPC18XX_SCU_I2C0_EFP BIT(0) #define LPC18XX_SCU_I2C0_EHD BIT(2) #define LPC18XX_SCU_I2C0_EZI BIT(3) @@ -617,8 +620,31 @@ static const struct pinctrl_pin_desc lpc18xx_pins[] = { static int lpc18xx_pconf_get_usb1(enum pin_config_param param, int *arg, u32 reg) { - /* TODO */ - return -ENOTSUPP; + switch (param) { + case PIN_CONFIG_LOW_POWER_MODE: + if (reg & LPC18XX_SCU_USB1_EPWR) + *arg = 0; + else + *arg = 1; + break; + + case PIN_CONFIG_BIAS_DISABLE: + if (reg & LPC18XX_SCU_USB1_EPD) + return -EINVAL; + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + if (reg & LPC18XX_SCU_USB1_EPD) + *arg = 1; + else + return -EINVAL; + break; + + default: + return -ENOTSUPP; + } + + return 0; } static int lpc18xx_pconf_get_i2c0(enum pin_config_param param, int *arg, u32 reg, @@ -782,8 +808,28 @@ static int lpc18xx_pconf_set_usb1(struct pinctrl_dev *pctldev, enum pin_config_param param, u16 param_val, u32 *reg) { - /* TODO */ - return -ENOTSUPP; + switch (param) { + case PIN_CONFIG_LOW_POWER_MODE: + if (param_val) + *reg &= ~LPC18XX_SCU_USB1_EPWR; + else + *reg |= LPC18XX_SCU_USB1_EPWR; + break; + + case PIN_CONFIG_BIAS_DISABLE: + *reg &= ~LPC18XX_SCU_USB1_EPD; + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + *reg |= LPC18XX_SCU_USB1_EPD; + break; + + default: + dev_err(pctldev->dev, "Property not supported\n"); + return -ENOTSUPP; + } + + return 0; } static int lpc18xx_pconf_set_i2c0(struct pinctrl_dev *pctldev, -- cgit v1.3-6-gb490 From 099f3e4adddc8fe9899fb879053887a95e9aed7d Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 14 Jul 2015 23:40:33 -0700 Subject: pinctrl: qcom: spmi-mpp: Add support for setting analog output level When the MPP is configured for analog output the output level is selected by the AOUT_CTL register, this patch makes it possible to control this. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/qcom,pmic-mpp.txt | 7 +++++++ drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 23 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt index d29fb96a57d3..0e4d4e62e220 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt @@ -127,6 +127,13 @@ to specify in a pin configuration subnode: Definition: Selects the power source for the specified pins. Valid power sources are defined in +- qcom,analog-level: + Usage: optional + Value type: + Definition: Selects the source for analog output. Valued values are + defined in + PMIC_MPP_AOUT_LVL_* + - qcom,analog-mode: Usage: optional Value type: diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 9dde023640ba..e52a72348a67 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -61,6 +61,7 @@ #define PMIC_MPP_REG_DIG_PULL_CTL 0x42 #define PMIC_MPP_REG_DIG_IN_CTL 0x43 #define PMIC_MPP_REG_EN_CTL 0x46 +#define PMIC_MPP_REG_AOUT_CTL 0x48 #define PMIC_MPP_REG_AIN_CTL 0x4a #define PMIC_MPP_REG_SINK_CTL 0x4c @@ -100,6 +101,7 @@ #define PMIC_MPP_CONF_AMUX_ROUTE (PIN_CONFIG_END + 1) #define PMIC_MPP_CONF_ANALOG_MODE (PIN_CONFIG_END + 2) #define PMIC_MPP_CONF_SINK_MODE (PIN_CONFIG_END + 3) +#define PMIC_MPP_CONF_ANALOG_LEVEL (PIN_CONFIG_END + 4) /** * struct pmic_mpp_pad - keep current MPP settings @@ -115,6 +117,7 @@ * @num_sources: Number of power-sources supported by this MPP. * @power_source: Current power-source used. * @amux_input: Set the source for analog input. + * @aout_level: Analog output level * @pullup: Pullup resistor value. Valid in Bidirectional mode only. * @function: See pmic_mpp_functions[]. * @drive_strength: Amount of current in sink mode @@ -131,6 +134,7 @@ struct pmic_mpp_pad { unsigned int num_sources; unsigned int power_source; unsigned int amux_input; + unsigned int aout_level; unsigned int pullup; unsigned int function; unsigned int drive_strength; @@ -145,6 +149,7 @@ struct pmic_mpp_state { static const struct pinconf_generic_params pmic_mpp_bindings[] = { {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE, 0}, + {"qcom,analog-level", PMIC_MPP_CONF_ANALOG_LEVEL, 0}, {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE, 0}, {"qcom,sink-mode", PMIC_MPP_CONF_SINK_MODE, 0}, }; @@ -152,6 +157,7 @@ static const struct pinconf_generic_params pmic_mpp_bindings[] = { #ifdef CONFIG_DEBUG_FS static const struct pin_config_item pmic_conf_items[] = { PCONFDUMP(PMIC_MPP_CONF_AMUX_ROUTE, "analog mux", NULL, true), + PCONFDUMP(PMIC_MPP_CONF_ANALOG_LEVEL, "analog level", NULL, true), PCONFDUMP(PMIC_MPP_CONF_ANALOG_MODE, "analog output", NULL, false), PCONFDUMP(PMIC_MPP_CONF_SINK_MODE, "sink mode", NULL, false), }; @@ -358,6 +364,9 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, case PIN_CONFIG_DRIVE_STRENGTH: arg = pad->drive_strength; break; + case PMIC_MPP_CONF_ANALOG_LEVEL: + arg = pad->aout_level; + break; case PMIC_MPP_CONF_ANALOG_MODE: arg = pad->analog_mode; break; @@ -433,6 +442,9 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, return -EINVAL; pad->amux_input = arg; break; + case PMIC_MPP_CONF_ANALOG_LEVEL: + pad->aout_level = arg; + break; case PMIC_MPP_CONF_ANALOG_MODE: pad->analog_mode = !!arg; break; @@ -462,6 +474,10 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, if (ret < 0) return ret; + ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_AOUT_CTL, pad->aout_level); + if (ret < 0) + return ret; + ret = pmic_mpp_write_mode_ctl(state, pad); if (ret < 0) return ret; @@ -507,6 +523,7 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, seq_printf(s, " %-7s", modes[pad->analog_mode ? 1 : (pad->sink_mode ? 2 : 0)]); seq_printf(s, " %-7s", pmic_mpp_functions[pad->function]); seq_printf(s, " vin-%d", pad->power_source); + seq_printf(s, " %d", pad->aout_level); seq_printf(s, " %-8s", biases[pad->pullup]); seq_printf(s, " %-4s", pad->out_value ? "high" : "low"); } @@ -748,6 +765,12 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, pad->drive_strength = val; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AOUT_CTL); + if (val < 0) + return val; + + pad->aout_level = val; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL); if (val < 0) return val; -- cgit v1.3-6-gb490 From eb5c144cbbc0ca9bb9a77c7c83fddc87469318de Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 17 Jun 2015 23:47:30 -0700 Subject: pinctrl: qcom: spmi-mpp: Transpose pinmux function The "function" of the MPP driver was inherited from the GPIO driver, but the differences between the two hardware blocks makes both the driver and the device tree binding to be awkward. Instead of overloading the "normal" function with various modes this patch transposes the pinmux function to represent the three operating modes of the MPP (digital, analog and current sink). The properties of pin pairing and DTEST routing is moved to separate properties. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/qcom,pmic-mpp.txt | 29 ++-- drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 157 ++++++++++++--------- 2 files changed, 99 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt index 0e4d4e62e220..b096d8351b8f 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt @@ -77,12 +77,9 @@ to specify in a pin configuration subnode: Value type: Definition: Specify the alternative function to be configured for the specified pins. Valid values are: - "normal", - "paired", - "dtest1", - "dtest2", - "dtest3", - "dtest4" + "digital", + "analog", + "sink" - bias-disable: Usage: optional @@ -134,17 +131,11 @@ to specify in a pin configuration subnode: defined in PMIC_MPP_AOUT_LVL_* -- qcom,analog-mode: +- qcom,dtest: Usage: optional - Value type: - Definition: Selects Analog mode of operation: combined with input-enable - and/or output-high, output-low MPP could operate as - Bidirectional Logic, Analog Input, Analog Output. - -- qcom,sink-mode: - Usage: optional - Value type: or - Definition: Selects sink mode of operation + Value type: + Definition: Selects which dtest rail to be routed in the various functions. + Valid values are 1-4 - qcom,amux-route: Usage: optional @@ -152,6 +143,10 @@ to specify in a pin configuration subnode: Definition: Selects the source for analog input. Valid values are defined in PMIC_MPP_AMUX_ROUTE_CH5, PMIC_MPP_AMUX_ROUTE_CH6... +- qcom,paired: + Usage: optional + Value type: + Definition: Indicates that the pin should be operating in paired mode. Example: @@ -168,7 +163,7 @@ Example: pm8841_default: default { gpio { pins = "mpp1", "mpp2", "mpp3", "mpp4"; - function = "normal"; + function = "digital"; input-enable; power-source = ; }; diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index e52a72348a67..e3be3ce2cada 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -95,13 +95,17 @@ #define PMIC_MPP_MODE_ANALOG_OUTPUT 5 #define PMIC_MPP_MODE_CURRENT_SINK 6 +#define PMIC_MPP_SELECTOR_NORMAL 0 +#define PMIC_MPP_SELECTOR_PAIRED 1 +#define PMIC_MPP_SELECTOR_DTEST_FIRST 4 + #define PMIC_MPP_PHYSICAL_OFFSET 1 /* Qualcomm specific pin configurations */ #define PMIC_MPP_CONF_AMUX_ROUTE (PIN_CONFIG_END + 1) -#define PMIC_MPP_CONF_ANALOG_MODE (PIN_CONFIG_END + 2) -#define PMIC_MPP_CONF_SINK_MODE (PIN_CONFIG_END + 3) -#define PMIC_MPP_CONF_ANALOG_LEVEL (PIN_CONFIG_END + 4) +#define PMIC_MPP_CONF_ANALOG_LEVEL (PIN_CONFIG_END + 2) +#define PMIC_MPP_CONF_DTEST_SELECTOR (PIN_CONFIG_END + 3) +#define PMIC_MPP_CONF_PAIRED (PIN_CONFIG_END + 4) /** * struct pmic_mpp_pad - keep current MPP settings @@ -111,9 +115,7 @@ * @out_value: Cached pin output value. * @output_enabled: Set to true if MPP output logic is enabled. * @input_enabled: Set to true if MPP input buffer logic is enabled. - * @analog_mode: Set to true when MPP should operate in Analog Input, Analog - * Output or Bidirectional Analog mode. - * @sink_mode: Boolean indicating if ink mode is slected + * @paired: Pin operates in paired mode * @num_sources: Number of power-sources supported by this MPP. * @power_source: Current power-source used. * @amux_input: Set the source for analog input. @@ -121,6 +123,7 @@ * @pullup: Pullup resistor value. Valid in Bidirectional mode only. * @function: See pmic_mpp_functions[]. * @drive_strength: Amount of current in sink mode + * @dtest: DTEST route selector */ struct pmic_mpp_pad { u16 base; @@ -129,8 +132,7 @@ struct pmic_mpp_pad { bool out_value; bool output_enabled; bool input_enabled; - bool analog_mode; - bool sink_mode; + bool paired; unsigned int num_sources; unsigned int power_source; unsigned int amux_input; @@ -138,6 +140,7 @@ struct pmic_mpp_pad { unsigned int pullup; unsigned int function; unsigned int drive_strength; + unsigned int dtest; }; struct pmic_mpp_state { @@ -150,16 +153,16 @@ struct pmic_mpp_state { static const struct pinconf_generic_params pmic_mpp_bindings[] = { {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE, 0}, {"qcom,analog-level", PMIC_MPP_CONF_ANALOG_LEVEL, 0}, - {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE, 0}, - {"qcom,sink-mode", PMIC_MPP_CONF_SINK_MODE, 0}, + {"qcom,dtest", PMIC_MPP_CONF_DTEST_SELECTOR, 0}, + {"qcom,paired", PMIC_MPP_CONF_PAIRED, 0}, }; #ifdef CONFIG_DEBUG_FS static const struct pin_config_item pmic_conf_items[] = { PCONFDUMP(PMIC_MPP_CONF_AMUX_ROUTE, "analog mux", NULL, true), PCONFDUMP(PMIC_MPP_CONF_ANALOG_LEVEL, "analog level", NULL, true), - PCONFDUMP(PMIC_MPP_CONF_ANALOG_MODE, "analog output", NULL, false), - PCONFDUMP(PMIC_MPP_CONF_SINK_MODE, "sink mode", NULL, false), + PCONFDUMP(PMIC_MPP_CONF_DTEST_SELECTOR, "dtest", NULL, true), + PCONFDUMP(PMIC_MPP_CONF_PAIRED, "paired", NULL, false), }; #endif @@ -167,11 +170,12 @@ static const char *const pmic_mpp_groups[] = { "mpp1", "mpp2", "mpp3", "mpp4", "mpp5", "mpp6", "mpp7", "mpp8", }; +#define PMIC_MPP_DIGITAL 0 +#define PMIC_MPP_ANALOG 1 +#define PMIC_MPP_SINK 2 + static const char *const pmic_mpp_functions[] = { - PMIC_MPP_FUNC_NORMAL, PMIC_MPP_FUNC_PAIRED, - "reserved1", "reserved2", - PMIC_MPP_FUNC_DTEST1, PMIC_MPP_FUNC_DTEST2, - PMIC_MPP_FUNC_DTEST3, PMIC_MPP_FUNC_DTEST4, + "digital", "analog", "sink" }; static inline struct pmic_mpp_state *to_mpp_state(struct gpio_chip *chip) @@ -260,31 +264,46 @@ static int pmic_mpp_get_function_groups(struct pinctrl_dev *pctldev, static int pmic_mpp_write_mode_ctl(struct pmic_mpp_state *state, struct pmic_mpp_pad *pad) { + unsigned int mode; + unsigned int sel; unsigned int val; - - if (pad->analog_mode) { - val = PMIC_MPP_MODE_ANALOG_INPUT; - if (pad->output_enabled) { - if (pad->input_enabled) - val = PMIC_MPP_MODE_ANALOG_BIDIR; - else - val = PMIC_MPP_MODE_ANALOG_OUTPUT; - } - } else if (pad->sink_mode) { - val = PMIC_MPP_MODE_CURRENT_SINK; - } else { - val = PMIC_MPP_MODE_DIGITAL_INPUT; - if (pad->output_enabled) { - if (pad->input_enabled) - val = PMIC_MPP_MODE_DIGITAL_BIDIR; - else - val = PMIC_MPP_MODE_DIGITAL_OUTPUT; - } + unsigned int en; + + switch (pad->function) { + case PMIC_MPP_ANALOG: + if (pad->input_enabled && pad->output_enabled) + mode = PMIC_MPP_MODE_ANALOG_BIDIR; + else if (pad->input_enabled) + mode = PMIC_MPP_MODE_ANALOG_INPUT; + else + mode = PMIC_MPP_MODE_ANALOG_OUTPUT; + break; + case PMIC_MPP_DIGITAL: + if (pad->input_enabled && pad->output_enabled) + mode = PMIC_MPP_MODE_DIGITAL_BIDIR; + else if (pad->input_enabled) + mode = PMIC_MPP_MODE_DIGITAL_INPUT; + else + mode = PMIC_MPP_MODE_DIGITAL_OUTPUT; + break; + case PMIC_MPP_SINK: + default: + mode = PMIC_MPP_MODE_CURRENT_SINK; + break; } - val = val << PMIC_MPP_REG_MODE_DIR_SHIFT; - val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT; - val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK; + if (pad->dtest) + sel = PMIC_MPP_SELECTOR_DTEST_FIRST + pad->dtest - 1; + else if (pad->paired) + sel = PMIC_MPP_SELECTOR_PAIRED; + else + sel = PMIC_MPP_SELECTOR_NORMAL; + + en = !!pad->out_value; + + val = mode << PMIC_MPP_REG_MODE_DIR_SHIFT | + sel << PMIC_MPP_REG_MODE_FUNCTION_SHIFT | + en; return pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); } @@ -358,21 +377,21 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, case PIN_CONFIG_OUTPUT: arg = pad->out_value; break; + case PMIC_MPP_CONF_DTEST_SELECTOR: + arg = pad->dtest; + break; case PMIC_MPP_CONF_AMUX_ROUTE: arg = pad->amux_input; break; + case PMIC_MPP_CONF_PAIRED: + arg = pad->paired; + break; case PIN_CONFIG_DRIVE_STRENGTH: arg = pad->drive_strength; break; case PMIC_MPP_CONF_ANALOG_LEVEL: arg = pad->aout_level; break; - case PMIC_MPP_CONF_ANALOG_MODE: - arg = pad->analog_mode; - break; - case PMIC_MPP_CONF_SINK_MODE: - arg = pad->sink_mode; - break; default: return -EINVAL; } @@ -434,6 +453,9 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, pad->output_enabled = true; pad->out_value = arg; break; + case PMIC_MPP_CONF_DTEST_SELECTOR: + pad->dtest = arg; + break; case PIN_CONFIG_DRIVE_STRENGTH: arg = pad->drive_strength; break; @@ -445,11 +467,8 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, case PMIC_MPP_CONF_ANALOG_LEVEL: pad->aout_level = arg; break; - case PMIC_MPP_CONF_ANALOG_MODE: - pad->analog_mode = !!arg; - break; - case PMIC_MPP_CONF_SINK_MODE: - pad->sink_mode = !!arg; + case PMIC_MPP_CONF_PAIRED: + pad->paired = !!arg; break; default: return -EINVAL; @@ -498,10 +517,6 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, "0.6kOhm", "10kOhm", "30kOhm", "Disabled" }; - static const char *const modes[] = { - "digital", "analog", "sink" - }; - pad = pctldev->desc->pins[pin].drv_data; seq_printf(s, " mpp%-2d:", pin + PMIC_MPP_PHYSICAL_OFFSET); @@ -520,12 +535,15 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, } seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); - seq_printf(s, " %-7s", modes[pad->analog_mode ? 1 : (pad->sink_mode ? 2 : 0)]); seq_printf(s, " %-7s", pmic_mpp_functions[pad->function]); seq_printf(s, " vin-%d", pad->power_source); seq_printf(s, " %d", pad->aout_level); seq_printf(s, " %-8s", biases[pad->pullup]); seq_printf(s, " %-4s", pad->out_value ? "high" : "low"); + if (pad->dtest) + seq_printf(s, " dtest%d", pad->dtest); + if (pad->paired) + seq_puts(s, " paired"); } } @@ -646,6 +664,7 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, struct pmic_mpp_pad *pad) { int type, subtype, val, dir; + unsigned int sel; type = pmic_mpp_read(state, pad, PMIC_MPP_REG_TYPE); if (type < 0) @@ -691,52 +710,50 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, case PMIC_MPP_MODE_DIGITAL_INPUT: pad->input_enabled = true; pad->output_enabled = false; - pad->analog_mode = false; - pad->sink_mode = false; + pad->function = PMIC_MPP_DIGITAL; break; case PMIC_MPP_MODE_DIGITAL_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; - pad->analog_mode = false; - pad->sink_mode = false; + pad->function = PMIC_MPP_DIGITAL; break; case PMIC_MPP_MODE_DIGITAL_BIDIR: pad->input_enabled = true; pad->output_enabled = true; - pad->analog_mode = false; - pad->sink_mode = false; + pad->function = PMIC_MPP_DIGITAL; break; case PMIC_MPP_MODE_ANALOG_BIDIR: pad->input_enabled = true; pad->output_enabled = true; - pad->analog_mode = true; - pad->sink_mode = false; + pad->function = PMIC_MPP_ANALOG; break; case PMIC_MPP_MODE_ANALOG_INPUT: pad->input_enabled = true; pad->output_enabled = false; - pad->analog_mode = true; - pad->sink_mode = false; + pad->function = PMIC_MPP_ANALOG; break; case PMIC_MPP_MODE_ANALOG_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; - pad->analog_mode = true; - pad->sink_mode = false; + pad->function = PMIC_MPP_ANALOG; break; case PMIC_MPP_MODE_CURRENT_SINK: pad->input_enabled = false; pad->output_enabled = true; - pad->analog_mode = false; - pad->sink_mode = true; + pad->function = PMIC_MPP_SINK; break; default: dev_err(state->dev, "unknown MPP direction\n"); return -ENODEV; } - pad->function = val >> PMIC_MPP_REG_MODE_FUNCTION_SHIFT; - pad->function &= PMIC_MPP_REG_MODE_FUNCTION_MASK; + sel = val >> PMIC_MPP_REG_MODE_FUNCTION_SHIFT; + sel &= PMIC_MPP_REG_MODE_FUNCTION_MASK; + + if (sel >= PMIC_MPP_SELECTOR_DTEST_FIRST) + pad->dtest = sel + 1; + else if (sel == PMIC_MPP_SELECTOR_PAIRED) + pad->paired = true; val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_VIN_CTL); if (val < 0) -- cgit v1.3-6-gb490 From 0975626d08b623ad42c89a6294b7c2f8391c69af Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 24 Jun 2015 13:50:27 -0300 Subject: [media] adv7604: Add support for control event notifications Allow userspace applications to subscribe to control change events. This can e.g. be used to monitor the 5V detect control to be notified when a source is connected or disconnected. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 21b549a8dc74..a7d47e079343 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -2362,6 +2363,8 @@ static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = { static const struct v4l2_subdev_core_ops adv76xx_core_ops = { .log_status = adv76xx_log_status, .interrupt_service_routine = adv76xx_isr, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = adv76xx_g_register, .s_register = adv76xx_s_register, @@ -3047,7 +3050,7 @@ static int adv76xx_probe(struct i2c_client *client, snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", id->name, i2c_adapter_id(client->adapter), client->addr); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; /* Configure IO Regmap region */ err = configure_regmap(state, ADV76XX_PAGE_IO); -- cgit v1.3-6-gb490 From aef5159ffc6bbf65d77af3a2e5b3d377c7c4f37a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 24 Jun 2015 13:50:28 -0300 Subject: [media] adv7842: Add support for control event notifications Allow userspace applications to subscribe to control change events. This can e.g. be used to monitor the 5V detect control to be notified when a source is connected or disconnected. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7842.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index aa0d1a04543b..0535463d2fed 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -3015,6 +3016,8 @@ static const struct v4l2_subdev_core_ops adv7842_core_ops = { .log_status = adv7842_log_status, .ioctl = adv7842_ioctl, .interrupt_service_routine = adv7842_isr, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = adv7842_g_register, .s_register = adv7842_s_register, @@ -3210,7 +3213,7 @@ static int adv7842_probe(struct i2c_client *client, sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7842_ops); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; state->mode = pdata->mode; state->hdmi_port_a = pdata->input == ADV7842_SELECT_HDMI_PORT_A; -- cgit v1.3-6-gb490 From 8ae5640f1b4af2e903802f771ba6a8f0c3497cab Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 24 Jun 2015 13:50:29 -0300 Subject: [media] Add helper function for subdev event notifications Add a new helper function called v4l2_subdev_notify_event() which will deliver the specified event to both the v4l2 subdev event queue as well as to the notify callback. The former is typically used by userspace applications to listen to notification events while the later is used by bridge drivers. Combining both into the same function avoids boilerplate code in subdev drivers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 18 ++++++++++++++++++ include/media/v4l2-subdev.h | 4 ++++ 2 files changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 63596063b213..83615b8fb46a 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -588,3 +588,21 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) #endif } EXPORT_SYMBOL(v4l2_subdev_init); + +/** + * v4l2_subdev_notify_event() - Delivers event notification for subdevice + * @sd: The subdev for which to deliver the event + * @ev: The event to deliver + * + * Will deliver the specified event to all userspace event listeners which are + * subscribed to the v42l subdev event queue as well as to the bridge driver + * using the notify callback. The notification type for the notify callback + * will be V4L2_DEVICE_NOTIFY_EVENT. + */ +void v4l2_subdev_notify_event(struct v4l2_subdev *sd, + const struct v4l2_event *ev) +{ + v4l2_event_queue(sd->devnode, ev); + v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, (void *)ev); +} +EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 4e18318eb425..370fc38c34f1 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -44,6 +44,7 @@ struct v4l2_device; struct v4l2_ctrl_handler; +struct v4l2_event; struct v4l2_event_subscription; struct v4l2_fh; struct v4l2_subdev; @@ -695,4 +696,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, #define v4l2_subdev_has_op(sd, o, f) \ ((sd)->ops->o && (sd)->ops->o->f) +void v4l2_subdev_notify_event(struct v4l2_subdev *sd, + const struct v4l2_event *ev); + #endif -- cgit v1.3-6-gb490 From 6f5bcfc30e1918c6029ebfdc9ed5002d618ab3de Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 24 Jun 2015 13:50:30 -0300 Subject: [media] adv7604: Deliver resolution change events to userspace Use the new v4l2_subdev_notify_event() helper function to deliver the resolution change event to userspace via the v4l2 subdev event queue as well as to the bridge driver using the callback notify mechanism. This allows userspace applications to react to changes in resolution. This is useful and often necessary for video pipelines where there is no direct 1-to-1 relationship between the subdevice converter and the video capture device and hence it does not make sense to directly forward the event to the video capture device node. Signed-off-by: Lars-Peter Clausen [hans.verkuil@cisco.com: fix obvious mistake: v4l2_event_subdev_unsubscribe -> v4l2_ctrl_subdev_subscribe_event] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index a7d47e079343..bfb0b6a72bbc 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1767,8 +1767,8 @@ static int adv76xx_s_routing(struct v4l2_subdev *sd, select_input(sd); enable_input(sd); - v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, - (void *)&adv76xx_ev_fmt); + v4l2_subdev_notify_event(sd, &adv76xx_ev_fmt); + return 0; } @@ -1935,8 +1935,7 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) "%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n", __func__, fmt_change, fmt_change_digital); - v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, - (void *)&adv76xx_ev_fmt); + v4l2_subdev_notify_event(sd, &adv76xx_ev_fmt); if (handled) *handled = true; @@ -2354,6 +2353,20 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) return 0; } +static int adv76xx_subscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); + default: + return -EINVAL; + } +} + /* ----------------------------------------------------------------------- */ static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = { @@ -2363,7 +2376,7 @@ static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = { static const struct v4l2_subdev_core_ops adv76xx_core_ops = { .log_status = adv76xx_log_status, .interrupt_service_routine = adv76xx_isr, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .subscribe_event = adv76xx_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = adv76xx_g_register, -- cgit v1.3-6-gb490 From 2cf4090fc8db8f9c2f3778a6a3768357a2b6aa6e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 24 Jun 2015 13:50:31 -0300 Subject: [media] adv7842: Deliver resolution change events to userspace Use the new v4l2_subdev_notify_event() helper function to deliver the resolution change event to userspace via the v4l2 subdev event queue as well as to the bridge driver using the callback notify mechanism. This allows userspace applications to react to changes in resolution. This is useful and often necessary for video pipelines where there is no direct 1-to-1 relationship between the subdevice converter and the video capture device and hence it does not make sense to directly forward the event to the video capture device node. Signed-off-by: Lars-Peter Clausen [hans.verkuil@cisco.com: fix obvious mistake: v4l2_event_subdev_unsubscribe -> v4l2_ctrl_subdev_subscribe_event] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7842.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 0535463d2fed..897d68c78b06 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1981,8 +1981,7 @@ static int adv7842_s_routing(struct v4l2_subdev *sd, select_input(sd, state->vid_std_select); enable_input(sd); - v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, - (void *)&adv7842_ev_fmt); + v4l2_subdev_notify_event(sd, &adv7842_ev_fmt); return 0; } @@ -2215,8 +2214,7 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) "%s: fmt_change_cp = 0x%x, fmt_change_digital = 0x%x, fmt_change_sdp = 0x%x\n", __func__, fmt_change_cp, fmt_change_digital, fmt_change_sdp); - v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, - (void *)&adv7842_ev_fmt); + v4l2_subdev_notify_event(sd, &adv7842_ev_fmt); if (handled) *handled = true; } @@ -3006,6 +3004,20 @@ static long adv7842_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) return -ENOTTY; } +static int adv7842_subscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); + default: + return -EINVAL; + } +} + /* ----------------------------------------------------------------------- */ static const struct v4l2_ctrl_ops adv7842_ctrl_ops = { @@ -3016,7 +3028,7 @@ static const struct v4l2_subdev_core_ops adv7842_core_ops = { .log_status = adv7842_log_status, .ioctl = adv7842_ioctl, .interrupt_service_routine = adv7842_isr, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .subscribe_event = adv7842_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = adv7842_g_register, -- cgit v1.3-6-gb490 From 2f8e75d2762496bb2fcea7fa437a3339d2a6d9d4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 29 Jun 2015 10:45:56 -0300 Subject: [media] adv7604/cobalt: Allow compile test if !GPIOLIB The GPIO subsystem provides dummy GPIO consumer functions if GPIOLIB is not enabled. Hence drivers that depend on GPIOLIB, but use GPIO consumer functionality only, can still be compiled if GPIOLIB is not enabled. Relax the dependency of VIDEO_ADV7604 and VIDEO_COBALT (the latter selects the former) on GPIOLIB if COMPILE_TEST is enabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 3 ++- drivers/media/pci/cobalt/Kconfig | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 71ee8f586430..8d1268648fe0 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -196,7 +196,8 @@ config VIDEO_ADV7183 config VIDEO_ADV7604 tristate "Analog Devices ADV7604 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && GPIOLIB + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on GPIOLIB || COMPILE_TEST select HDMI ---help--- Support for the Analog Devices ADV7604 video decoder. diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig index 6a1c0089bb62..1f88ccc174da 100644 --- a/drivers/media/pci/cobalt/Kconfig +++ b/drivers/media/pci/cobalt/Kconfig @@ -1,7 +1,8 @@ config VIDEO_COBALT tristate "Cisco Cobalt support" depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER - depends on PCI_MSI && MTD_COMPLEX_MAPPINGS && GPIOLIB + depends on PCI_MSI && MTD_COMPLEX_MAPPINGS + depends on GPIOLIB || COMPILE_TEST depends on SND select I2C_ALGOBIT select VIDEO_ADV7604 -- cgit v1.3-6-gb490 From f47c9045643f91e76d8a9030828b9fe1cf4a6bcf Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Mon, 29 Jun 2015 18:19:06 -0300 Subject: [media] media: am437x-vpfe: Requested frame size and fmt overwritten by current sensor setting Upon a S_FMT the input/requested frame size and pixel format is overwritten by the current sub-device settings. Fix this so application can actually set the frame size and format. Fixes: 417d2e507edc ("[media] media: platform: add VPFE capture driver support for AM437X") Cc: # v4.0+ Signed-off-by: Benoit Parrot Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/am437x/am437x-vpfe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 1fba339cddc1..1fed7a56c8ae 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1565,7 +1565,7 @@ static int vpfe_s_fmt(struct file *file, void *priv, return -EBUSY; } - ret = vpfe_try_fmt(file, priv, fmt); + ret = vpfe_try_fmt(file, priv, &format); if (ret) return ret; -- cgit v1.3-6-gb490 From 890024ad144902bfa637f23b94b396701a88ed88 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 3 Jul 2015 16:11:41 -0300 Subject: [media] stk1160: Reduce driver verbosity These messages are not really informational, and just makes the driver's output too verbose. This commit changes some messages to a debug level, removes a really useless "driver loaded" message and finally undefines the DEBUG macro. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stk1160/stk1160-core.c | 5 +---- drivers/media/usb/stk1160/stk1160-v4l.c | 16 ++++++++-------- drivers/media/usb/stk1160/stk1160.h | 1 - 3 files changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index 03504dcf3c52..1b6836f15370 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -162,7 +162,7 @@ static void stk1160_release(struct v4l2_device *v4l2_dev) { struct stk1160 *dev = container_of(v4l2_dev, struct stk1160, v4l2_dev); - stk1160_info("releasing all resources\n"); + stk1160_dbg("releasing all resources\n"); stk1160_i2c_unregister(dev); @@ -363,9 +363,6 @@ static int stk1160_probe(struct usb_interface *interface, dev->sd_saa7115 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, "saa7115_auto", 0, saa7113_addrs); - stk1160_info("driver ver %s successfully loaded\n", - STK1160_VERSION); - /* i2c reset saa711x */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 7291cca58704..b4b737b0b35a 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -136,7 +136,7 @@ static bool stk1160_set_alternate(struct stk1160 *dev) dev->alt = i; } - stk1160_info("setting alternate %d\n", dev->alt); + stk1160_dbg("setting alternate %d\n", dev->alt); if (dev->alt != prev_alt) { stk1160_dbg("minimum isoc packet size: %u (alt=%d)\n", @@ -226,7 +226,7 @@ static void stk1160_stop_hw(struct stk1160 *dev) /* set alternate 0 */ dev->alt = 0; - stk1160_info("setting alternate %d\n", dev->alt); + stk1160_dbg("setting alternate %d\n", dev->alt); usb_set_interface(dev->udev, 0, 0); /* Stop stk1160 */ @@ -540,8 +540,8 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *v4l_fmt, sizes[0] = size; - stk1160_info("%s: buffer count %d, each %ld bytes\n", - __func__, *nbuffers, size); + stk1160_dbg("%s: buffer count %d, each %ld bytes\n", + __func__, *nbuffers, size); return 0; } @@ -625,8 +625,8 @@ void stk1160_clear_queue(struct stk1160 *dev) struct stk1160_buffer, list); list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - stk1160_info("buffer [%p/%d] aborted\n", - buf, buf->vb.v4l2_buf.index); + stk1160_dbg("buffer [%p/%d] aborted\n", + buf, buf->vb.v4l2_buf.index); } /* It's important to release the current buffer */ @@ -635,8 +635,8 @@ void stk1160_clear_queue(struct stk1160 *dev) dev->isoc_ctl.buf = NULL; vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - stk1160_info("buffer [%p/%d] aborted\n", - buf, buf->vb.v4l2_buf.index); + stk1160_dbg("buffer [%p/%d] aborted\n", + buf, buf->vb.v4l2_buf.index); } spin_unlock_irqrestore(&dev->buf_lock, flags); } diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index 3922a6cabde2..72cc8e8cbef7 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -58,7 +58,6 @@ * new drivers should use. * */ -#define DEBUG #ifdef DEBUG #define stk1160_dbg(fmt, args...) \ printk(KERN_DEBUG "stk1160: " fmt, ## args) -- cgit v1.3-6-gb490 From d3194520e2790591b5fabeb913dd74af908ca160 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 3 Jul 2015 16:11:42 -0300 Subject: [media] stk1160: Add frame scaling support This commit implements frame decimation for stk1160, which allows to support format changes instead of a static frame size. The stk1160 supports independent row and column decimation, in two different modes: * set a number of rows/columns units to skip for each unit sent. * set a number of rows/columns units to send for each unit skipped. This effectively allows to achieve different frame scaling ratios. The unit number can be set to either two row/columns sent/skipped, or four row/columns sent/skipped. Since the video format (UYVY) has 4-bytes, using a unit number of two row/columns results in frame color 'shifting', so set to four row/columns sent/skipped. Signed-off-by: Michael Stegemann Signed-off-by: Dale Hamel Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stk1160/stk1160-reg.h | 34 ++++++ drivers/media/usb/stk1160/stk1160-v4l.c | 201 +++++++++++++++++++++++++++----- 2 files changed, 207 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/stk1160/stk1160-reg.h b/drivers/media/usb/stk1160/stk1160-reg.h index 3e49da6e7edd..81ff3a15d96e 100644 --- a/drivers/media/usb/stk1160/stk1160-reg.h +++ b/drivers/media/usb/stk1160/stk1160-reg.h @@ -33,6 +33,40 @@ */ #define STK1160_DCTRL 0x100 +/* + * Decimation Control Register: + * Byte 104: Horizontal Decimation Line Unit Count + * Byte 105: Vertical Decimation Line Unit Count + * Byte 106: Decimation Control + * Bit 0 - Horizontal Decimation Control + * 0 Horizontal decimation is disabled. + * 1 Horizontal decimation is enabled. + * Bit 1 - Decimates Half or More Column + * 0 Decimates less than half from original column, + * send count unit (0x105) before each unit skipped. + * 1 Decimates half or more from original column, + * skip count unit (0x105) before each unit sent. + * Bit 2 - Vertical Decimation Control + * 0 Vertical decimation is disabled. + * 1 Vertical decimation is enabled. + * Bit 3 - Vertical Greater or Equal to Half + * 0 Decimates less than half from original row, + * send count unit (0x105) before each unit skipped. + * 1 Decimates half or more from original row, + * skip count unit (0x105) before each unit sent. + * Bit 4 - Decimation Unit + * 0 Decimation will work with 2 rows or columns per unit. + * 1 Decimation will work with 4 rows or columns per unit. + */ +#define STK1160_DMCTRL_H_UNITS 0x104 +#define STK1160_DMCTRL_V_UNITS 0x105 +#define STK1160_DMCTRL 0x106 +#define STK1160_H_DEC_EN BIT(0) +#define STK1160_H_DEC_MODE BIT(1) +#define STK1160_V_DEC_EN BIT(2) +#define STK1160_V_DEC_MODE BIT(3) +#define STK1160_DEC_UNIT_SIZE BIT(4) + /* Capture Frame Start Position */ #define STK116_CFSPO 0x110 #define STK116_CFSPO_STX_L 0x110 diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index b4b737b0b35a..e12b10352871 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -42,6 +42,17 @@ static bool keep_buffers; module_param(keep_buffers, bool, 0644); MODULE_PARM_DESC(keep_buffers, "don't release buffers upon stop streaming"); +enum stk1160_decimate_mode { + STK1160_DECIMATE_MORE_THAN_HALF, + STK1160_DECIMATE_LESS_THAN_HALF, +}; + +struct stk1160_decimate_ctrl { + bool col_en, row_en; + enum stk1160_decimate_mode col_mode, row_mode; + unsigned int col_n, row_n; +}; + /* supported video standards */ static struct stk1160_fmt format[] = { { @@ -51,6 +62,19 @@ static struct stk1160_fmt format[] = { } }; +/* + * Helper to find the next divisor that results in modulo being zero. + * This is required to guarantee valid decimation unit counts. + */ +static unsigned int +div_round_integer(unsigned int x, unsigned int y) +{ + for (;; y++) { + if (x % y == 0) + return x / y; + } +} + static void stk1160_set_std(struct stk1160 *dev) { int i; @@ -106,6 +130,41 @@ static void stk1160_set_std(struct stk1160 *dev) } +static void stk1160_set_fmt(struct stk1160 *dev, + struct stk1160_decimate_ctrl *ctrl) +{ + u32 val = 0; + + if (ctrl) { + /* + * Since the format is UYVY, the device must skip or send + * a number of rows/columns multiple of four. This way, the + * colour format is preserved. The STK1160_DEC_UNIT_SIZE bit + * does exactly this. + */ + val |= STK1160_DEC_UNIT_SIZE; + val |= ctrl->col_en ? STK1160_H_DEC_EN : 0; + val |= ctrl->row_en ? STK1160_V_DEC_EN : 0; + val |= ctrl->col_mode == + STK1160_DECIMATE_MORE_THAN_HALF ? + STK1160_H_DEC_MODE : 0; + val |= ctrl->row_mode == + STK1160_DECIMATE_MORE_THAN_HALF ? + STK1160_V_DEC_MODE : 0; + + /* Horizontal count units */ + stk1160_write_reg(dev, STK1160_DMCTRL_H_UNITS, ctrl->col_n); + /* Vertical count units */ + stk1160_write_reg(dev, STK1160_DMCTRL_V_UNITS, ctrl->row_n); + + stk1160_dbg("decimate 0x%x, column units %d, row units %d\n", + val, ctrl->col_n, ctrl->row_n); + } + + /* Decimation control */ + stk1160_write_reg(dev, STK1160_DMCTRL, val); +} + /* * Set a new alternate setting. * Returns true is dev->max_pkt_size has changed, false otherwise. @@ -323,41 +382,134 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int stk1160_try_fmt(struct stk1160 *dev, struct v4l2_format *f, + struct stk1160_decimate_ctrl *ctrl) { - struct stk1160 *dev = video_drvdata(file); + unsigned int width, height; + unsigned int base_width, base_height; + unsigned int col_n, row_n; + enum stk1160_decimate_mode col_mode, row_mode; + bool col_en, row_en; + + base_width = 720; + base_height = (dev->norm & V4L2_STD_525_60) ? 480 : 576; + + /* Minimum width and height is 5% the frame size */ + width = clamp_t(unsigned int, f->fmt.pix.width, + base_width / 20, base_width); + height = clamp_t(unsigned int, f->fmt.pix.height, + base_height / 20, base_height); + + /* Let's set default no decimation values */ + col_n = 0; + row_n = 0; + col_en = false; + row_en = false; + f->fmt.pix.width = base_width; + f->fmt.pix.height = base_height; + row_mode = STK1160_DECIMATE_LESS_THAN_HALF; + col_mode = STK1160_DECIMATE_LESS_THAN_HALF; + + if (width < base_width && width > base_width / 2) { + /* + * The device will send count units for each + * unit skipped. This means count unit is: + * + * n = width / (frame width - width) + * + * And the width is: + * + * width = (n / n + 1) * frame width + */ + col_n = div_round_integer(width, base_width - width); + if (col_n > 0 && col_n <= 255) { + col_en = true; + col_mode = STK1160_DECIMATE_LESS_THAN_HALF; + f->fmt.pix.width = (base_width * col_n) / (col_n + 1); + } - /* - * User can't choose size at his own will, - * so we just return him the current size chosen - * at standard selection. - * TODO: Implement frame scaling? - */ + } else if (width <= base_width / 2) { + + /* + * The device will skip count units for each + * unit sent. This means count is: + * + * n = (frame width / width) - 1 + * + * And the width is: + * + * width = frame width / (n + 1) + */ + col_n = div_round_integer(base_width, width) - 1; + if (col_n > 0 && col_n <= 255) { + col_en = true; + col_mode = STK1160_DECIMATE_MORE_THAN_HALF; + f->fmt.pix.width = base_width / (col_n + 1); + } + } + + if (height < base_height && height > base_height / 2) { + row_n = div_round_integer(height, base_height - height); + if (row_n > 0 && row_n <= 255) { + row_en = true; + row_mode = STK1160_DECIMATE_LESS_THAN_HALF; + f->fmt.pix.height = (base_height * row_n) / (row_n + 1); + } + + } else if (height <= base_height / 2) { + row_n = div_round_integer(base_height, height) - 1; + if (row_n > 0 && row_n <= 255) { + row_en = true; + row_mode = STK1160_DECIMATE_MORE_THAN_HALF; + f->fmt.pix.height = base_height / (row_n + 1); + } + } f->fmt.pix.pixelformat = dev->fmt->fourcc; - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; f->fmt.pix.field = V4L2_FIELD_INTERLACED; - f->fmt.pix.bytesperline = dev->width * 2; - f->fmt.pix.sizeimage = dev->height * f->fmt.pix.bytesperline; + f->fmt.pix.bytesperline = f->fmt.pix.width * 2; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + if (ctrl) { + ctrl->col_en = col_en; + ctrl->col_n = col_n; + ctrl->col_mode = col_mode; + ctrl->row_en = row_en; + ctrl->row_n = row_n; + ctrl->row_mode = row_mode; + } + + stk1160_dbg("width %d, height %d\n", + f->fmt.pix.width, f->fmt.pix.height); return 0; } +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct stk1160 *dev = video_drvdata(file); + + return stk1160_try_fmt(dev, f, NULL); +} + static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct stk1160 *dev = video_drvdata(file); struct vb2_queue *q = &dev->vb_vidq; + struct stk1160_decimate_ctrl ctrl; + int rc; if (vb2_is_busy(q)) return -EBUSY; - vidioc_try_fmt_vid_cap(file, priv, f); - - /* We don't support any format changes */ + rc = stk1160_try_fmt(dev, f, &ctrl); + if (rc < 0) + return rc; + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; + stk1160_set_fmt(dev, &ctrl); return 0; } @@ -393,22 +545,15 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) return -ENODEV; /* We need to set this now, before we call stk1160_set_std */ + dev->width = 720; + dev->height = (norm & V4L2_STD_525_60) ? 480 : 576; dev->norm = norm; - /* This is taken from saa7115 video decoder */ - if (dev->norm & V4L2_STD_525_60) { - dev->width = 720; - dev->height = 480; - } else if (dev->norm & V4L2_STD_625_50) { - dev->width = 720; - dev->height = 576; - } else { - stk1160_err("invalid standard\n"); - return -EINVAL; - } - stk1160_set_std(dev); + /* Calling with NULL disables frame decimation */ + stk1160_set_fmt(dev, NULL); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm); -- cgit v1.3-6-gb490 From 3d8bffe88316c0c8b5edad633fc8a25cae644bb4 Mon Sep 17 00:00:00 2001 From: Fabien Dessenne Date: Fri, 10 Jul 2015 05:29:22 -0300 Subject: [media] bdisp: composing support Support the composing (at VIDEO_CAPTURE) with the _selection API. v4l2-compliance successfully run ("test Composing: OK") Signed-off-by: Fabien Dessenne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/bdisp/bdisp-hw.c | 8 +-- drivers/media/platform/sti/bdisp/bdisp-v4l2.c | 76 ++++++++++++++++++--------- 2 files changed, 55 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sti/bdisp/bdisp-hw.c b/drivers/media/platform/sti/bdisp/bdisp-hw.c index 465828e859e2..c83f9c2fbe3c 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-hw.c +++ b/drivers/media/platform/sti/bdisp/bdisp-hw.c @@ -336,8 +336,8 @@ static int bdisp_hw_get_hv_inc(struct bdisp_ctx *ctx, u16 *h_inc, u16 *v_inc) src_w = ctx->src.crop.width; src_h = ctx->src.crop.height; - dst_w = ctx->dst.width; - dst_h = ctx->dst.height; + dst_w = ctx->dst.crop.width; + dst_h = ctx->dst.crop.height; if (bdisp_hw_get_inc(src_w, dst_w, h_inc) || bdisp_hw_get_inc(src_h, dst_h, v_inc)) { @@ -483,9 +483,9 @@ static void bdisp_hw_build_node(struct bdisp_ctx *ctx, src_rect.width -= src_x_offset; src_rect.width = min_t(__s32, MAX_SRC_WIDTH, src_rect.width); - dst_x_offset = (src_x_offset * dst->width) / ctx->src.crop.width; + dst_x_offset = (src_x_offset * dst_width) / ctx->src.crop.width; dst_rect.left += dst_x_offset; - dst_rect.width = (src_rect.width * dst->width) / ctx->src.crop.width; + dst_rect.width = (src_rect.width * dst_width) / ctx->src.crop.width; /* General */ src_fmt = src->fmt->pixelformat; diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index 9e782ebe18da..df61355b46f1 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -851,33 +851,56 @@ static int bdisp_g_selection(struct file *file, void *fh, struct bdisp_frame *frame; struct bdisp_ctx *ctx = fh_to_ctx(fh); - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - /* Composing / capture is not supported */ - dev_dbg(ctx->bdisp_dev->dev, "Not supported for capture\n"); - return -EINVAL; - } - frame = ctx_get_frame(ctx, s->type); if (IS_ERR(frame)) { dev_err(ctx->bdisp_dev->dev, "Invalid frame (%p)\n", frame); return PTR_ERR(frame); } - switch (s->target) { - case V4L2_SEL_TGT_CROP: - /* cropped frame */ - s->r = frame->crop; + switch (s->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + switch (s->target) { + case V4L2_SEL_TGT_CROP: + /* cropped frame */ + s->r = frame->crop; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + /* complete frame */ + s->r.left = 0; + s->r.top = 0; + s->r.width = frame->width; + s->r.height = frame->height; + break; + default: + dev_err(ctx->bdisp_dev->dev, "Invalid target\n"); + return -EINVAL; + } break; - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - /* complete frame */ - s->r.left = 0; - s->r.top = 0; - s->r.width = frame->width; - s->r.height = frame->height; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_PADDED: + /* composed (cropped) frame */ + s->r = frame->crop; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + /* complete frame */ + s->r.left = 0; + s->r.top = 0; + s->r.width = frame->width; + s->r.height = frame->height; + break; + default: + dev_err(ctx->bdisp_dev->dev, "Invalid target\n"); + return -EINVAL; + } break; + default: - dev_dbg(ctx->bdisp_dev->dev, "Invalid target\n"); + dev_err(ctx->bdisp_dev->dev, "Invalid type\n"); return -EINVAL; } @@ -906,15 +929,18 @@ static int bdisp_s_selection(struct file *file, void *fh, struct bdisp_frame *frame; struct bdisp_ctx *ctx = fh_to_ctx(fh); struct v4l2_rect *in, out; + bool valid = false; - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - /* Composing / capture is not supported */ - dev_dbg(ctx->bdisp_dev->dev, "Not supported for capture\n"); - return -EINVAL; - } + if ((s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) && + (s->target == V4L2_SEL_TGT_CROP)) + valid = true; + + if ((s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (s->target == V4L2_SEL_TGT_COMPOSE)) + valid = true; - if (s->target != V4L2_SEL_TGT_CROP) { - dev_dbg(ctx->bdisp_dev->dev, "Invalid target\n"); + if (!valid) { + dev_err(ctx->bdisp_dev->dev, "Invalid type / target\n"); return -EINVAL; } -- cgit v1.3-6-gb490 From 24310279eb2851a2bdef9b267b43b98e252ce435 Mon Sep 17 00:00:00 2001 From: Fabien Dessenne Date: Fri, 10 Jul 2015 05:29:37 -0300 Subject: [media] bdisp: add debug info for RGB24 format Add this missing debug information Signed-off-by: Fabien Dessenne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/bdisp/bdisp-debug.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/sti/bdisp/bdisp-debug.c b/drivers/media/platform/sti/bdisp/bdisp-debug.c index 18282a0f80c9..79c56356a7c7 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-debug.c +++ b/drivers/media/platform/sti/bdisp/bdisp-debug.c @@ -116,6 +116,9 @@ static void bdisp_dbg_dump_tty(struct seq_file *s, u32 val) case BDISP_RGB565: seq_puts(s, "RGB565 - "); break; + case BDISP_RGB888: + seq_puts(s, "RGB888 - "); + break; case BDISP_XRGB8888: seq_puts(s, "xRGB888 - "); break; @@ -185,6 +188,9 @@ static void bdisp_dbg_dump_sty(struct seq_file *s, case BDISP_RGB565: seq_puts(s, "RGB565 - "); break; + case BDISP_RGB888: + seq_puts(s, "RGB888 - "); + break; case BDISP_XRGB8888: seq_puts(s, "xRGB888 - "); break; @@ -420,6 +426,8 @@ static const char *bdisp_fmt_to_str(struct bdisp_frame frame) return "NV12"; case V4L2_PIX_FMT_RGB565: return "RGB16"; + case V4L2_PIX_FMT_RGB24: + return "RGB24"; case V4L2_PIX_FMT_XBGR32: return "XRGB"; case V4L2_PIX_FMT_ABGR32: -- cgit v1.3-6-gb490 From bde2b96d6dfb1c14e5d27a4e7e7d492e9be102cd Mon Sep 17 00:00:00 2001 From: Fabien Dessenne Date: Mon, 13 Jul 2015 06:54:11 -0300 Subject: [media] bdisp: fix debug info memory access bdisp_dev->dbg.copy_node shall be a copy of (and not point to) bdisp_ctx->node, since this resource is freed upon driver release. Signed-off-by: Fabien Dessenne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/bdisp/bdisp-hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sti/bdisp/bdisp-hw.c b/drivers/media/platform/sti/bdisp/bdisp-hw.c index c83f9c2fbe3c..052c932ac942 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-hw.c +++ b/drivers/media/platform/sti/bdisp/bdisp-hw.c @@ -768,12 +768,12 @@ static void bdisp_hw_save_request(struct bdisp_ctx *ctx) /* Allocate memory if not done yet */ if (!copy_node[i]) { copy_node[i] = devm_kzalloc(ctx->bdisp_dev->dev, - sizeof(*copy_node), + sizeof(*copy_node[i]), GFP_KERNEL); if (!copy_node[i]) return; } - copy_node[i] = node[i]; + *copy_node[i] = *node[i]; } } -- cgit v1.3-6-gb490 From d32d98642de66048f9534a05f3641558e811bbc9 Mon Sep 17 00:00:00 2001 From: Mats Randgaard Date: Thu, 9 Jul 2015 05:45:47 -0300 Subject: [media] Driver for Toshiba TC358743 HDMI to CSI-2 bridge The driver is tested on our hardware and all the implemented features works as expected. Missing features: - CEC support - HDCP repeater support - IR support Signed-off-by: Mats Randgaard [hans.verkuil@cisco.com: updated copyright year to 2015] [hans.verkuil@cisco.com: update confusing confctl_mutex comment] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 7 + drivers/media/i2c/Kconfig | 9 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/tc358743.c | 1778 ++++++++++++++++++++++++++++++++++++ drivers/media/i2c/tc358743_regs.h | 681 ++++++++++++++ include/media/tc358743.h | 131 +++ include/uapi/linux/v4l2-controls.h | 4 + 7 files changed, 2611 insertions(+) create mode 100644 drivers/media/i2c/tc358743.c create mode 100644 drivers/media/i2c/tc358743_regs.h create mode 100644 include/media/tc358743.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index fd6078443083..2bb989be111d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10319,6 +10319,13 @@ F: drivers/char/toshiba.c F: include/linux/toshiba.h F: include/uapi/linux/toshiba.h +TOSHIBA TC358743 DRIVER +M: Mats Randgaard +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/i2c/tc358743* +F: include/media/tc358743.h + TMIO MMC DRIVER M: Ian Molton L: linux-mmc@vger.kernel.org diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 8d1268648fe0..0e0490d60e7e 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -287,6 +287,15 @@ config VIDEO_SAA711X To compile this driver as a module, choose M here: the module will be called saa7115. +config VIDEO_TC358743 + tristate "Toshiba TC358743 decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Toshiba TC358743 HDMI to MIPI CSI-2 bridge. + + To compile this driver as a module, choose M here: the + module will be called tc358743. + config VIDEO_TVP514X tristate "Texas Instruments TVP514x video decoder" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index f165faea5b3f..07db257abfc1 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -78,3 +78,4 @@ obj-$(CONFIG_VIDEO_AK881X) += ak881x.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o obj-$(CONFIG_VIDEO_OV2659) += ov2659.o +obj-$(CONFIG_VIDEO_TC358743) += tc358743.o diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c new file mode 100644 index 000000000000..4e8811c3e771 --- /dev/null +++ b/drivers/media/i2c/tc358743.c @@ -0,0 +1,1778 @@ +/* + * tc358743 - Toshiba HDMI to CSI-2 bridge + * + * Copyright 2015 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. + * + */ + +/* + * References (c = chapter, p = page): + * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60 + * REF_02 - Toshiba, TC358743XBG_HDMI-CSI_Tv11p_nm.xls + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tc358743_regs.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-3)"); + +MODULE_DESCRIPTION("Toshiba TC358743 HDMI to CSI-2 bridge driver"); +MODULE_AUTHOR("Ramakrishnan Muthukrishnan "); +MODULE_AUTHOR("Mikhail Khelik "); +MODULE_AUTHOR("Mats Randgaard "); +MODULE_LICENSE("GPL"); + +#define EDID_NUM_BLOCKS_MAX 8 +#define EDID_BLOCK_SIZE 128 + +static const struct v4l2_dv_timings_cap tc358743_timings_cap = { + .type = V4L2_DV_BT_656_1120, + /* keep this initialization for compatibility with GCC < 4.4.6 */ + .reserved = { 0 }, + /* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */ + V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 165000000, + V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, + V4L2_DV_BT_CAP_PROGRESSIVE | + V4L2_DV_BT_CAP_REDUCED_BLANKING | + V4L2_DV_BT_CAP_CUSTOM) +}; + +struct tc358743_state { + struct tc358743_platform_data pdata; + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_ctrl_handler hdl; + struct i2c_client *i2c_client; + /* CONFCTL is modified in ops and tc358743_hdmi_sys_int_handler */ + struct mutex confctl_mutex; + + /* controls */ + struct v4l2_ctrl *detect_tx_5v_ctrl; + struct v4l2_ctrl *audio_sampling_rate_ctrl; + struct v4l2_ctrl *audio_present_ctrl; + + /* work queues */ + struct workqueue_struct *work_queues; + struct delayed_work delayed_work_enable_hotplug; + + /* edid */ + u8 edid_blocks_written; + + struct v4l2_dv_timings timings; + u32 mbus_fmt_code; +}; + +static void tc358743_enable_interrupts(struct v4l2_subdev *sd, + bool cable_connected); +static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd); + +static inline struct tc358743_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct tc358743_state, sd); +} + +/* --------------- I2C --------------- */ + +static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) +{ + struct tc358743_state *state = to_state(sd); + struct i2c_client *client = state->i2c_client; + int err; + u8 buf[2] = { reg >> 8, reg & 0xff }; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = buf, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = n, + .buf = values, + }, + }; + + err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (err != ARRAY_SIZE(msgs)) { + v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", + __func__, reg, client->addr); + } +} + +static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) +{ + struct tc358743_state *state = to_state(sd); + struct i2c_client *client = state->i2c_client; + int err, i; + struct i2c_msg msg; + u8 data[2 + n]; + + msg.addr = client->addr; + msg.buf = data; + msg.len = 2 + n; + msg.flags = 0; + + data[0] = reg >> 8; + data[1] = reg & 0xff; + + for (i = 0; i < n; i++) + data[2 + i] = values[i]; + + err = i2c_transfer(client->adapter, &msg, 1); + if (err != 1) { + v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n", + __func__, reg, client->addr); + return; + } + + if (debug < 3) + return; + + switch (n) { + case 1: + v4l2_info(sd, "I2C write 0x%04x = 0x%02x", + reg, data[2]); + break; + case 2: + v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x", + reg, data[3], data[2]); + break; + case 4: + v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x%02x%02x", + reg, data[5], data[4], data[3], data[2]); + break; + default: + v4l2_info(sd, "I2C write %d bytes from address 0x%04x\n", + n, reg); + } +} + +static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg) +{ + u8 val; + + i2c_rd(sd, reg, &val, 1); + + return val; +} + +static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) +{ + i2c_wr(sd, reg, &val, 1); +} + +static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg, + u8 mask, u8 val) +{ + i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val); +} + +static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) +{ + u16 val; + + i2c_rd(sd, reg, (u8 *)&val, 2); + + return val; +} + +static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) +{ + i2c_wr(sd, reg, (u8 *)&val, 2); +} + +static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val) +{ + i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val); +} + +static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg) +{ + u32 val; + + i2c_rd(sd, reg, (u8 *)&val, 4); + + return val; +} + +static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val) +{ + i2c_wr(sd, reg, (u8 *)&val, 4); +} + +/* --------------- STATUS --------------- */ + +static inline bool is_hdmi(struct v4l2_subdev *sd) +{ + return i2c_rd8(sd, SYS_STATUS) & MASK_S_HDMI; +} + +static inline bool tx_5v_power_present(struct v4l2_subdev *sd) +{ + return i2c_rd8(sd, SYS_STATUS) & MASK_S_DDC5V; +} + +static inline bool no_signal(struct v4l2_subdev *sd) +{ + return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_TMDS); +} + +static inline bool no_sync(struct v4l2_subdev *sd) +{ + return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_SYNC); +} + +static inline bool audio_present(struct v4l2_subdev *sd) +{ + return i2c_rd8(sd, AU_STATUS0) & MASK_S_A_SAMPLE; +} + +static int get_audio_sampling_rate(struct v4l2_subdev *sd) +{ + static const int code_to_rate[] = { + 44100, 0, 48000, 32000, 22050, 384000, 24000, 352800, + 88200, 768000, 96000, 705600, 176400, 0, 192000, 0 + }; + + /* Register FS_SET is not cleared when the cable is disconnected */ + if (no_signal(sd)) + return 0; + + return code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS]; +} + +static unsigned tc358743_num_csi_lanes_in_use(struct v4l2_subdev *sd) +{ + return ((i2c_rd32(sd, CSI_CONTROL) & MASK_NOL) >> 1) + 1; +} + +/* --------------- TIMINGS --------------- */ + +static inline unsigned fps(const struct v4l2_bt_timings *t) +{ + if (!V4L2_DV_BT_FRAME_HEIGHT(t) || !V4L2_DV_BT_FRAME_WIDTH(t)) + return 0; + + return DIV_ROUND_CLOSEST((unsigned)t->pixelclock, + V4L2_DV_BT_FRAME_HEIGHT(t) * V4L2_DV_BT_FRAME_WIDTH(t)); +} + +static int tc358743_get_detected_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct v4l2_bt_timings *bt = &timings->bt; + unsigned width, height, frame_width, frame_height, frame_interval, fps; + + memset(timings, 0, sizeof(struct v4l2_dv_timings)); + + if (no_signal(sd)) { + v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); + return -ENOLINK; + } + if (no_sync(sd)) { + v4l2_dbg(1, debug, sd, "%s: no sync on signal\n", __func__); + return -ENOLCK; + } + + timings->type = V4L2_DV_BT_656_1120; + bt->interlaced = i2c_rd8(sd, VI_STATUS1) & MASK_S_V_INTERLACE ? + V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; + + width = ((i2c_rd8(sd, DE_WIDTH_H_HI) & 0x1f) << 8) + + i2c_rd8(sd, DE_WIDTH_H_LO); + height = ((i2c_rd8(sd, DE_WIDTH_V_HI) & 0x1f) << 8) + + i2c_rd8(sd, DE_WIDTH_V_LO); + frame_width = ((i2c_rd8(sd, H_SIZE_HI) & 0x1f) << 8) + + i2c_rd8(sd, H_SIZE_LO); + frame_height = (((i2c_rd8(sd, V_SIZE_HI) & 0x3f) << 8) + + i2c_rd8(sd, V_SIZE_LO)) / 2; + /* frame interval in milliseconds * 10 + * Require SYS_FREQ0 and SYS_FREQ1 are precisely set */ + frame_interval = ((i2c_rd8(sd, FV_CNT_HI) & 0x3) << 8) + + i2c_rd8(sd, FV_CNT_LO); + fps = (frame_interval > 0) ? + DIV_ROUND_CLOSEST(10000, frame_interval) : 0; + + bt->width = width; + bt->height = height; + bt->vsync = frame_height - height; + bt->hsync = frame_width - width; + bt->pixelclock = frame_width * frame_height * fps; + if (bt->interlaced == V4L2_DV_INTERLACED) { + bt->height *= 2; + bt->il_vsync = bt->vsync + 1; + bt->pixelclock /= 2; + } + + return 0; +} + +/* --------------- HOTPLUG / HDCP / EDID --------------- */ + +static void tc358743_delayed_work_enable_hotplug(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct tc358743_state *state = container_of(dwork, + struct tc358743_state, delayed_work_enable_hotplug); + struct v4l2_subdev *sd = &state->sd; + + v4l2_dbg(2, debug, sd, "%s:\n", __func__); + + i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, MASK_HPD_OUT0); +} + +static void tc358743_set_hdmi_hdcp(struct v4l2_subdev *sd, bool enable) +{ + v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? + "enable" : "disable"); + + i2c_wr8_and_or(sd, HDCP_REG1, + ~(MASK_AUTH_UNAUTH_SEL | MASK_AUTH_UNAUTH), + MASK_AUTH_UNAUTH_SEL_16_FRAMES | MASK_AUTH_UNAUTH_AUTO); + + i2c_wr8_and_or(sd, HDCP_REG2, ~MASK_AUTO_P3_RESET, + SET_AUTO_P3_RESET_FRAMES(0x0f)); + + /* HDCP is disabled by configuring the receiver as HDCP repeater. The + * repeater mode require software support to work, so HDCP + * authentication will fail. + */ + i2c_wr8_and_or(sd, HDCP_REG3, ~KEY_RD_CMD, enable ? KEY_RD_CMD : 0); + i2c_wr8_and_or(sd, HDCP_MODE, ~(MASK_AUTO_CLR | MASK_MODE_RST_TN), + enable ? (MASK_AUTO_CLR | MASK_MODE_RST_TN) : 0); + + /* Apple MacBook Pro gen.8 has a bug that makes it freeze every fifth + * second when HDCP is disabled, but the MAX_EXCED bit is handled + * correctly and HDCP is disabled on the HDMI output. + */ + i2c_wr8_and_or(sd, BSTATUS1, ~MASK_MAX_EXCED, + enable ? 0 : MASK_MAX_EXCED); + i2c_wr8_and_or(sd, BCAPS, ~(MASK_REPEATER | MASK_READY), + enable ? 0 : MASK_REPEATER | MASK_READY); +} + +static void tc358743_disable_edid(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + v4l2_dbg(2, debug, sd, "%s:\n", __func__); + + cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); + + /* DDC access to EDID is also disabled when hotplug is disabled. See + * register DDC_CTL */ + i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, 0x0); +} + +static void tc358743_enable_edid(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + if (state->edid_blocks_written == 0) { + v4l2_dbg(2, debug, sd, "%s: no EDID -> no hotplug\n", __func__); + return; + } + + v4l2_dbg(2, debug, sd, "%s:\n", __func__); + + /* Enable hotplug after 100 ms. DDC access to EDID is also enabled when + * hotplug is enabled. See register DDC_CTL */ + queue_delayed_work(state->work_queues, + &state->delayed_work_enable_hotplug, HZ / 10); + + tc358743_enable_interrupts(sd, true); + tc358743_s_ctrl_detect_tx_5v(sd); +} + +static void tc358743_erase_bksv(struct v4l2_subdev *sd) +{ + int i; + + for (i = 0; i < 5; i++) + i2c_wr8(sd, BKSV + i, 0); +} + +/* --------------- AVI infoframe --------------- */ + +static void print_avi_infoframe(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct device *dev = &client->dev; + union hdmi_infoframe frame; + u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; + + if (!is_hdmi(sd)) { + v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); + return; + } + + i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI)); + + if (hdmi_infoframe_unpack(&frame, buffer) < 0) { + v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__); + return; + } + + hdmi_infoframe_log(KERN_INFO, dev, &frame); +} + +/* --------------- CTRLS --------------- */ + +static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, + tx_5v_power_present(sd)); +} + +static int tc358743_s_ctrl_audio_sampling_rate(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + return v4l2_ctrl_s_ctrl(state->audio_sampling_rate_ctrl, + get_audio_sampling_rate(sd)); +} + +static int tc358743_s_ctrl_audio_present(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + return v4l2_ctrl_s_ctrl(state->audio_present_ctrl, + audio_present(sd)); +} + +static int tc358743_update_controls(struct v4l2_subdev *sd) +{ + int ret = 0; + + ret |= tc358743_s_ctrl_detect_tx_5v(sd); + ret |= tc358743_s_ctrl_audio_sampling_rate(sd); + ret |= tc358743_s_ctrl_audio_present(sd); + + return ret; +} + +/* --------------- INIT --------------- */ + +static void tc358743_reset_phy(struct v4l2_subdev *sd) +{ + v4l2_dbg(1, debug, sd, "%s:\n", __func__); + + i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, 0); + i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, MASK_RESET_CTRL); +} + +static void tc358743_reset(struct v4l2_subdev *sd, uint16_t mask) +{ + u16 sysctl = i2c_rd16(sd, SYSCTL); + + i2c_wr16(sd, SYSCTL, sysctl | mask); + i2c_wr16(sd, SYSCTL, sysctl & ~mask); +} + +static inline void tc358743_sleep_mode(struct v4l2_subdev *sd, bool enable) +{ + i2c_wr16_and_or(sd, SYSCTL, ~MASK_SLEEP, + enable ? MASK_SLEEP : 0); +} + +static inline void enable_stream(struct v4l2_subdev *sd, bool enable) +{ + struct tc358743_state *state = to_state(sd); + + v4l2_dbg(3, debug, sd, "%s: %sable\n", + __func__, enable ? "en" : "dis"); + + if (enable) { + /* It is critical for CSI receiver to see lane transition + * LP11->HS. Set to non-continuous mode to enable clock lane + * LP11 state. */ + i2c_wr32(sd, TXOPTIONCNTRL, 0); + /* Set to continuous mode to trigger LP11->HS transition */ + i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE); + /* Unmute video */ + i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE); + } else { + /* Mute video so that all data lanes go to LSP11 state. + * No data is output to CSI Tx block. */ + i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE | MASK_VI_MUTE); + } + + mutex_lock(&state->confctl_mutex); + i2c_wr16_and_or(sd, CONFCTL, ~(MASK_VBUFEN | MASK_ABUFEN), + enable ? (MASK_VBUFEN | MASK_ABUFEN) : 0x0); + mutex_unlock(&state->confctl_mutex); +} + +static void tc358743_set_pll(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct tc358743_platform_data *pdata = &state->pdata; + u16 pllctl0 = i2c_rd16(sd, PLLCTL0); + u16 pllctl1 = i2c_rd16(sd, PLLCTL1); + u16 pllctl0_new = SET_PLL_PRD(pdata->pll_prd) | + SET_PLL_FBD(pdata->pll_fbd); + u32 hsck = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd; + + v4l2_dbg(2, debug, sd, "%s:\n", __func__); + + /* Only rewrite when needed (new value or disabled), since rewriting + * triggers another format change event. */ + if ((pllctl0 != pllctl0_new) || ((pllctl1 & MASK_PLL_EN) == 0)) { + u16 pll_frs; + + if (hsck > 500000000) + pll_frs = 0x0; + else if (hsck > 250000000) + pll_frs = 0x1; + else if (hsck > 125000000) + pll_frs = 0x2; + else + pll_frs = 0x3; + + v4l2_dbg(1, debug, sd, "%s: updating PLL clock\n", __func__); + tc358743_sleep_mode(sd, true); + i2c_wr16(sd, PLLCTL0, pllctl0_new); + i2c_wr16_and_or(sd, PLLCTL1, + ~(MASK_PLL_FRS | MASK_RESETB | MASK_PLL_EN), + (SET_PLL_FRS(pll_frs) | MASK_RESETB | + MASK_PLL_EN)); + udelay(10); /* REF_02, Sheet "Source HDMI" */ + i2c_wr16_and_or(sd, PLLCTL1, ~MASK_CKEN, MASK_CKEN); + tc358743_sleep_mode(sd, false); + } +} + +static void tc358743_set_ref_clk(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct tc358743_platform_data *pdata = &state->pdata; + u32 sys_freq; + u32 lockdet_ref; + u16 fh_min; + u16 fh_max; + + BUG_ON(!(pdata->refclk_hz == 26000000 || + pdata->refclk_hz == 27000000 || + pdata->refclk_hz == 42000000)); + + sys_freq = pdata->refclk_hz / 10000; + i2c_wr8(sd, SYS_FREQ0, sys_freq & 0x00ff); + i2c_wr8(sd, SYS_FREQ1, (sys_freq & 0xff00) >> 8); + + i2c_wr8_and_or(sd, PHY_CTL0, ~MASK_PHY_SYSCLK_IND, + (pdata->refclk_hz == 42000000) ? + MASK_PHY_SYSCLK_IND : 0x0); + + fh_min = pdata->refclk_hz / 100000; + i2c_wr8(sd, FH_MIN0, fh_min & 0x00ff); + i2c_wr8(sd, FH_MIN1, (fh_min & 0xff00) >> 8); + + fh_max = (fh_min * 66) / 10; + i2c_wr8(sd, FH_MAX0, fh_max & 0x00ff); + i2c_wr8(sd, FH_MAX1, (fh_max & 0xff00) >> 8); + + lockdet_ref = pdata->refclk_hz / 100; + i2c_wr8(sd, LOCKDET_REF0, lockdet_ref & 0x0000ff); + i2c_wr8(sd, LOCKDET_REF1, (lockdet_ref & 0x00ff00) >> 8); + i2c_wr8(sd, LOCKDET_REF2, (lockdet_ref & 0x0f0000) >> 16); + + i2c_wr8_and_or(sd, NCO_F0_MOD, ~MASK_NCO_F0_MOD, + (pdata->refclk_hz == 27000000) ? + MASK_NCO_F0_MOD_27MHZ : 0x0); +} + +static void tc358743_set_csi_color_space(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + switch (state->mbus_fmt_code) { + case MEDIA_BUS_FMT_UYVY8_1X16: + v4l2_dbg(2, debug, sd, "%s: YCbCr 422 16-bit\n", __func__); + i2c_wr8_and_or(sd, VOUT_SET2, + ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, + MASK_SEL422 | MASK_VOUT_422FIL_100); + i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, + MASK_VOUT_COLOR_601_YCBCR_LIMITED); + mutex_lock(&state->confctl_mutex); + i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, + MASK_YCBCRFMT_422_8_BIT); + mutex_unlock(&state->confctl_mutex); + break; + case MEDIA_BUS_FMT_RGB888_1X24: + v4l2_dbg(2, debug, sd, "%s: RGB 888 24-bit\n", __func__); + i2c_wr8_and_or(sd, VOUT_SET2, + ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, + 0x00); + i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, + MASK_VOUT_COLOR_RGB_FULL); + mutex_lock(&state->confctl_mutex); + i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, 0); + mutex_unlock(&state->confctl_mutex); + break; + default: + v4l2_dbg(2, debug, sd, "%s: Unsupported format code 0x%x\n", + __func__, state->mbus_fmt_code); + } +} + +static unsigned tc358743_num_csi_lanes_needed(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct v4l2_bt_timings *bt = &state->timings.bt; + struct tc358743_platform_data *pdata = &state->pdata; + u32 bits_pr_pixel = + (state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16) ? 16 : 24; + u32 bps = bt->width * bt->height * fps(bt) * bits_pr_pixel; + u32 bps_pr_lane = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd; + + return DIV_ROUND_UP(bps, bps_pr_lane); +} + +static void tc358743_set_csi(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct tc358743_platform_data *pdata = &state->pdata; + unsigned lanes = tc358743_num_csi_lanes_needed(sd); + + v4l2_dbg(3, debug, sd, "%s:\n", __func__); + + tc358743_reset(sd, MASK_CTXRST); + + if (lanes < 1) + i2c_wr32(sd, CLW_CNTRL, MASK_CLW_LANEDISABLE); + if (lanes < 1) + i2c_wr32(sd, D0W_CNTRL, MASK_D0W_LANEDISABLE); + if (lanes < 2) + i2c_wr32(sd, D1W_CNTRL, MASK_D1W_LANEDISABLE); + if (lanes < 3) + i2c_wr32(sd, D2W_CNTRL, MASK_D2W_LANEDISABLE); + if (lanes < 4) + i2c_wr32(sd, D3W_CNTRL, MASK_D3W_LANEDISABLE); + + i2c_wr32(sd, LINEINITCNT, pdata->lineinitcnt); + i2c_wr32(sd, LPTXTIMECNT, pdata->lptxtimecnt); + i2c_wr32(sd, TCLK_HEADERCNT, pdata->tclk_headercnt); + i2c_wr32(sd, TCLK_TRAILCNT, pdata->tclk_trailcnt); + i2c_wr32(sd, THS_HEADERCNT, pdata->ths_headercnt); + i2c_wr32(sd, TWAKEUP, pdata->twakeup); + i2c_wr32(sd, TCLK_POSTCNT, pdata->tclk_postcnt); + i2c_wr32(sd, THS_TRAILCNT, pdata->ths_trailcnt); + i2c_wr32(sd, HSTXVREGCNT, pdata->hstxvregcnt); + + i2c_wr32(sd, HSTXVREGEN, + ((lanes > 0) ? MASK_CLM_HSTXVREGEN : 0x0) | + ((lanes > 0) ? MASK_D0M_HSTXVREGEN : 0x0) | + ((lanes > 1) ? MASK_D1M_HSTXVREGEN : 0x0) | + ((lanes > 2) ? MASK_D2M_HSTXVREGEN : 0x0) | + ((lanes > 3) ? MASK_D3M_HSTXVREGEN : 0x0)); + + i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE); + i2c_wr32(sd, STARTCNTRL, MASK_START); + i2c_wr32(sd, CSI_START, MASK_STRT); + + i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | + MASK_ADDRESS_CSI_CONTROL | + MASK_CSI_MODE | + MASK_TXHSMD | + ((lanes == 4) ? MASK_NOL_4 : + (lanes == 3) ? MASK_NOL_3 : + (lanes == 2) ? MASK_NOL_2 : MASK_NOL_1)); + + i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | + MASK_ADDRESS_CSI_ERR_INTENA | MASK_TXBRK | MASK_QUNK | + MASK_WCER | MASK_INER); + + i2c_wr32(sd, CSI_CONFW, MASK_MODE_CLEAR | + MASK_ADDRESS_CSI_ERR_HALT | MASK_TXBRK | MASK_QUNK); + + i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | + MASK_ADDRESS_CSI_INT_ENA | MASK_INTER); +} + +static void tc358743_set_hdmi_phy(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct tc358743_platform_data *pdata = &state->pdata; + + /* Default settings from REF_02, sheet "Source HDMI" + * and custom settings as platform data */ + i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, 0x0); + i2c_wr8(sd, PHY_CTL1, SET_PHY_AUTO_RST1_US(1600) | + SET_FREQ_RANGE_MODE_CYCLES(1)); + i2c_wr8_and_or(sd, PHY_CTL2, ~MASK_PHY_AUTO_RSTn, + (pdata->hdmi_phy_auto_reset_tmds_detected ? + MASK_PHY_AUTO_RST2 : 0) | + (pdata->hdmi_phy_auto_reset_tmds_in_range ? + MASK_PHY_AUTO_RST3 : 0) | + (pdata->hdmi_phy_auto_reset_tmds_valid ? + MASK_PHY_AUTO_RST4 : 0)); + i2c_wr8(sd, PHY_BIAS, 0x40); + i2c_wr8(sd, PHY_CSQ, SET_CSQ_CNT_LEVEL(0x0a)); + i2c_wr8(sd, AVM_CTL, 45); + i2c_wr8_and_or(sd, HDMI_DET, ~MASK_HDMI_DET_V, + pdata->hdmi_detection_delay << 4); + i2c_wr8_and_or(sd, HV_RST, ~(MASK_H_PI_RST | MASK_V_PI_RST), + (pdata->hdmi_phy_auto_reset_hsync_out_of_range ? + MASK_H_PI_RST : 0) | + (pdata->hdmi_phy_auto_reset_vsync_out_of_range ? + MASK_V_PI_RST : 0)); + i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, MASK_ENABLE_PHY); +} + +static void tc358743_set_hdmi_audio(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + /* Default settings from REF_02, sheet "Source HDMI" */ + i2c_wr8(sd, FORCE_MUTE, 0x00); + i2c_wr8(sd, AUTO_CMD0, MASK_AUTO_MUTE7 | MASK_AUTO_MUTE6 | + MASK_AUTO_MUTE5 | MASK_AUTO_MUTE4 | + MASK_AUTO_MUTE1 | MASK_AUTO_MUTE0); + i2c_wr8(sd, AUTO_CMD1, MASK_AUTO_MUTE9); + i2c_wr8(sd, AUTO_CMD2, MASK_AUTO_PLAY3 | MASK_AUTO_PLAY2); + i2c_wr8(sd, BUFINIT_START, SET_BUFINIT_START_MS(500)); + i2c_wr8(sd, FS_MUTE, 0x00); + i2c_wr8(sd, FS_IMODE, MASK_NLPCM_SMODE | MASK_FS_SMODE); + i2c_wr8(sd, ACR_MODE, MASK_CTS_MODE); + i2c_wr8(sd, ACR_MDF0, MASK_ACR_L2MDF_1976_PPM | MASK_ACR_L1MDF_976_PPM); + i2c_wr8(sd, ACR_MDF1, MASK_ACR_L3MDF_3906_PPM); + i2c_wr8(sd, SDO_MODE1, MASK_SDO_FMT_I2S); + i2c_wr8(sd, DIV_MODE, SET_DIV_DLY_MS(100)); + + mutex_lock(&state->confctl_mutex); + i2c_wr16_and_or(sd, CONFCTL, 0xffff, MASK_AUDCHNUM_2 | + MASK_AUDOUTSEL_I2S | MASK_AUTOINDEX); + mutex_unlock(&state->confctl_mutex); +} + +static void tc358743_set_hdmi_info_frame_mode(struct v4l2_subdev *sd) +{ + /* Default settings from REF_02, sheet "Source HDMI" */ + i2c_wr8(sd, PK_INT_MODE, MASK_ISRC2_INT_MODE | MASK_ISRC_INT_MODE | + MASK_ACP_INT_MODE | MASK_VS_INT_MODE | + MASK_SPD_INT_MODE | MASK_MS_INT_MODE | + MASK_AUD_INT_MODE | MASK_AVI_INT_MODE); + i2c_wr8(sd, NO_PKT_LIMIT, 0x2c); + i2c_wr8(sd, NO_PKT_CLR, 0x53); + i2c_wr8(sd, ERR_PK_LIMIT, 0x01); + i2c_wr8(sd, NO_PKT_LIMIT2, 0x30); + i2c_wr8(sd, NO_GDB_LIMIT, 0x10); +} + +static void tc358743_initial_setup(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct tc358743_platform_data *pdata = &state->pdata; + + /* CEC and IR are not supported by this driver */ + i2c_wr16_and_or(sd, SYSCTL, ~(MASK_CECRST | MASK_IRRST), + (MASK_CECRST | MASK_IRRST)); + + tc358743_reset(sd, MASK_CTXRST | MASK_HDMIRST); + tc358743_sleep_mode(sd, false); + + i2c_wr16(sd, FIFOCTL, pdata->fifo_level); + + tc358743_set_ref_clk(sd); + + i2c_wr8_and_or(sd, DDC_CTL, ~MASK_DDC5V_MODE, + pdata->ddc5v_delay & MASK_DDC5V_MODE); + i2c_wr8_and_or(sd, EDID_MODE, ~MASK_EDID_MODE, MASK_EDID_MODE_E_DDC); + + tc358743_set_hdmi_phy(sd); + tc358743_set_hdmi_hdcp(sd, pdata->enable_hdcp); + tc358743_set_hdmi_audio(sd); + tc358743_set_hdmi_info_frame_mode(sd); + + /* All CE and IT formats are detected as RGB full range in DVI mode */ + i2c_wr8_and_or(sd, VI_MODE, ~MASK_RGB_DVI, 0); + + i2c_wr8_and_or(sd, VOUT_SET2, ~MASK_VOUTCOLORMODE, + MASK_VOUTCOLORMODE_AUTO); + i2c_wr8(sd, VOUT_SET3, MASK_VOUT_EXTCNT); +} + +/* --------------- IRQ --------------- */ + +static void tc358743_format_change(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct v4l2_dv_timings timings; + const struct v4l2_event tc358743_ev_fmt = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + if (tc358743_get_detected_timings(sd, &timings)) { + enable_stream(sd, false); + + v4l2_dbg(1, debug, sd, "%s: Format changed. No signal\n", + __func__); + } else { + if (!v4l2_match_dv_timings(&state->timings, &timings, 0)) + enable_stream(sd, false); + + v4l2_print_dv_timings(sd->name, + "tc358743_format_change: Format changed. New format: ", + &timings, false); + } + + v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, + (void *)&tc358743_ev_fmt); +} + +static void tc358743_init_interrupts(struct v4l2_subdev *sd) +{ + u16 i; + + /* clear interrupt status registers */ + for (i = SYS_INT; i <= KEY_INT; i++) + i2c_wr8(sd, i, 0xff); + + i2c_wr16(sd, INTSTATUS, 0xffff); +} + +static void tc358743_enable_interrupts(struct v4l2_subdev *sd, + bool cable_connected) +{ + v4l2_dbg(2, debug, sd, "%s: cable connected = %d\n", __func__, + cable_connected); + + if (cable_connected) { + i2c_wr8(sd, SYS_INTM, ~(MASK_M_DDC | MASK_M_DVI_DET | + MASK_M_HDMI_DET) & 0xff); + i2c_wr8(sd, CLK_INTM, ~MASK_M_IN_DE_CHG); + i2c_wr8(sd, CBIT_INTM, ~(MASK_M_CBIT_FS | MASK_M_AF_LOCK | + MASK_M_AF_UNLOCK) & 0xff); + i2c_wr8(sd, AUDIO_INTM, ~MASK_M_BUFINIT_END); + i2c_wr8(sd, MISC_INTM, ~MASK_M_SYNC_CHG); + } else { + i2c_wr8(sd, SYS_INTM, ~MASK_M_DDC & 0xff); + i2c_wr8(sd, CLK_INTM, 0xff); + i2c_wr8(sd, CBIT_INTM, 0xff); + i2c_wr8(sd, AUDIO_INTM, 0xff); + i2c_wr8(sd, MISC_INTM, 0xff); + } +} + +static void tc358743_hdmi_audio_int_handler(struct v4l2_subdev *sd, + bool *handled) +{ + u8 audio_int_mask = i2c_rd8(sd, AUDIO_INTM); + u8 audio_int = i2c_rd8(sd, AUDIO_INT) & ~audio_int_mask; + + i2c_wr8(sd, AUDIO_INT, audio_int); + + v4l2_dbg(3, debug, sd, "%s: AUDIO_INT = 0x%02x\n", __func__, audio_int); + + tc358743_s_ctrl_audio_sampling_rate(sd); + tc358743_s_ctrl_audio_present(sd); +} + +static void tc358743_csi_err_int_handler(struct v4l2_subdev *sd, bool *handled) +{ + v4l2_err(sd, "%s: CSI_ERR = 0x%x\n", __func__, i2c_rd32(sd, CSI_ERR)); + + i2c_wr32(sd, CSI_INT_CLR, MASK_ICRER); +} + +static void tc358743_hdmi_misc_int_handler(struct v4l2_subdev *sd, + bool *handled) +{ + u8 misc_int_mask = i2c_rd8(sd, MISC_INTM); + u8 misc_int = i2c_rd8(sd, MISC_INT) & ~misc_int_mask; + + i2c_wr8(sd, MISC_INT, misc_int); + + v4l2_dbg(3, debug, sd, "%s: MISC_INT = 0x%02x\n", __func__, misc_int); + + if (misc_int & MASK_I_SYNC_CHG) { + /* Reset the HDMI PHY to try to trigger proper lock on the + * incoming video format. Erase BKSV to prevent that old keys + * are used when a new source is connected. */ + if (no_sync(sd) || no_signal(sd)) { + tc358743_reset_phy(sd); + tc358743_erase_bksv(sd); + } + + tc358743_format_change(sd); + + misc_int &= ~MASK_I_SYNC_CHG; + if (handled) + *handled = true; + } + + if (misc_int) { + v4l2_err(sd, "%s: Unhandled MISC_INT interrupts: 0x%02x\n", + __func__, misc_int); + } +} + +static void tc358743_hdmi_cbit_int_handler(struct v4l2_subdev *sd, + bool *handled) +{ + u8 cbit_int_mask = i2c_rd8(sd, CBIT_INTM); + u8 cbit_int = i2c_rd8(sd, CBIT_INT) & ~cbit_int_mask; + + i2c_wr8(sd, CBIT_INT, cbit_int); + + v4l2_dbg(3, debug, sd, "%s: CBIT_INT = 0x%02x\n", __func__, cbit_int); + + if (cbit_int & MASK_I_CBIT_FS) { + + v4l2_dbg(1, debug, sd, "%s: Audio sample rate changed\n", + __func__); + tc358743_s_ctrl_audio_sampling_rate(sd); + + cbit_int &= ~MASK_I_CBIT_FS; + if (handled) + *handled = true; + } + + if (cbit_int & (MASK_I_AF_LOCK | MASK_I_AF_UNLOCK)) { + + v4l2_dbg(1, debug, sd, "%s: Audio present changed\n", + __func__); + tc358743_s_ctrl_audio_present(sd); + + cbit_int &= ~(MASK_I_AF_LOCK | MASK_I_AF_UNLOCK); + if (handled) + *handled = true; + } + + if (cbit_int) { + v4l2_err(sd, "%s: Unhandled CBIT_INT interrupts: 0x%02x\n", + __func__, cbit_int); + } +} + +static void tc358743_hdmi_clk_int_handler(struct v4l2_subdev *sd, bool *handled) +{ + u8 clk_int_mask = i2c_rd8(sd, CLK_INTM); + u8 clk_int = i2c_rd8(sd, CLK_INT) & ~clk_int_mask; + + /* Bit 7 and bit 6 are set even when they are masked */ + i2c_wr8(sd, CLK_INT, clk_int | 0x80 | MASK_I_OUT_H_CHG); + + v4l2_dbg(3, debug, sd, "%s: CLK_INT = 0x%02x\n", __func__, clk_int); + + if (clk_int & (MASK_I_IN_DE_CHG)) { + + v4l2_dbg(1, debug, sd, "%s: DE size or position has changed\n", + __func__); + + /* If the source switch to a new resolution with the same pixel + * frequency as the existing (e.g. 1080p25 -> 720p50), the + * I_SYNC_CHG interrupt is not always triggered, while the + * I_IN_DE_CHG interrupt seems to work fine. Format change + * notifications are only sent when the signal is stable to + * reduce the number of notifications. */ + if (!no_signal(sd) && !no_sync(sd)) + tc358743_format_change(sd); + + clk_int &= ~(MASK_I_IN_DE_CHG); + if (handled) + *handled = true; + } + + if (clk_int) { + v4l2_err(sd, "%s: Unhandled CLK_INT interrupts: 0x%02x\n", + __func__, clk_int); + } +} + +static void tc358743_hdmi_sys_int_handler(struct v4l2_subdev *sd, bool *handled) +{ + struct tc358743_state *state = to_state(sd); + u8 sys_int_mask = i2c_rd8(sd, SYS_INTM); + u8 sys_int = i2c_rd8(sd, SYS_INT) & ~sys_int_mask; + + i2c_wr8(sd, SYS_INT, sys_int); + + v4l2_dbg(3, debug, sd, "%s: SYS_INT = 0x%02x\n", __func__, sys_int); + + if (sys_int & MASK_I_DDC) { + bool tx_5v = tx_5v_power_present(sd); + + v4l2_dbg(1, debug, sd, "%s: Tx 5V power present: %s\n", + __func__, tx_5v ? "yes" : "no"); + + if (tx_5v) { + tc358743_enable_edid(sd); + } else { + tc358743_enable_interrupts(sd, false); + tc358743_disable_edid(sd); + memset(&state->timings, 0, sizeof(state->timings)); + tc358743_erase_bksv(sd); + tc358743_update_controls(sd); + } + + sys_int &= ~MASK_I_DDC; + if (handled) + *handled = true; + } + + if (sys_int & MASK_I_DVI) { + v4l2_dbg(1, debug, sd, "%s: HDMI->DVI change detected\n", + __func__); + + /* Reset the HDMI PHY to try to trigger proper lock on the + * incoming video format. Erase BKSV to prevent that old keys + * are used when a new source is connected. */ + if (no_sync(sd) || no_signal(sd)) { + tc358743_reset_phy(sd); + tc358743_erase_bksv(sd); + } + + sys_int &= ~MASK_I_DVI; + if (handled) + *handled = true; + } + + if (sys_int & MASK_I_HDMI) { + v4l2_dbg(1, debug, sd, "%s: DVI->HDMI change detected\n", + __func__); + + /* Register is reset in DVI mode (REF_01, c. 6.6.41) */ + i2c_wr8(sd, ANA_CTL, MASK_APPL_PCSX_NORMAL | MASK_ANALOG_ON); + + sys_int &= ~MASK_I_HDMI; + if (handled) + *handled = true; + } + + if (sys_int) { + v4l2_err(sd, "%s: Unhandled SYS_INT interrupts: 0x%02x\n", + __func__, sys_int); + } +} + +/* --------------- CORE OPS --------------- */ + +static int tc358743_log_status(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct v4l2_dv_timings timings; + uint8_t hdmi_sys_status = i2c_rd8(sd, SYS_STATUS); + uint16_t sysctl = i2c_rd16(sd, SYSCTL); + u8 vi_status3 = i2c_rd8(sd, VI_STATUS3); + const int deep_color_mode[4] = { 8, 10, 12, 16 }; + static const char * const input_color_space[] = { + "RGB", "YCbCr 601", "Adobe RGB", "YCbCr 709", "NA (4)", + "xvYCC 601", "NA(6)", "xvYCC 709", "NA(8)", "sYCC601", + "NA(10)", "NA(11)", "NA(12)", "Adobe YCC 601"}; + + v4l2_info(sd, "-----Chip status-----\n"); + v4l2_info(sd, "Chip ID: 0x%02x\n", + (i2c_rd16(sd, CHIPID) & MASK_CHIPID) >> 8); + v4l2_info(sd, "Chip revision: 0x%02x\n", + i2c_rd16(sd, CHIPID) & MASK_REVID); + v4l2_info(sd, "Reset: IR: %d, CEC: %d, CSI TX: %d, HDMI: %d\n", + !!(sysctl & MASK_IRRST), + !!(sysctl & MASK_CECRST), + !!(sysctl & MASK_CTXRST), + !!(sysctl & MASK_HDMIRST)); + v4l2_info(sd, "Sleep mode: %s\n", sysctl & MASK_SLEEP ? "on" : "off"); + v4l2_info(sd, "Cable detected (+5V power): %s\n", + hdmi_sys_status & MASK_S_DDC5V ? "yes" : "no"); + v4l2_info(sd, "DDC lines enabled: %s\n", + (i2c_rd8(sd, EDID_MODE) & MASK_EDID_MODE_E_DDC) ? + "yes" : "no"); + v4l2_info(sd, "Hotplug enabled: %s\n", + (i2c_rd8(sd, HPD_CTL) & MASK_HPD_OUT0) ? + "yes" : "no"); + v4l2_info(sd, "CEC enabled: %s\n", + (i2c_rd16(sd, CECEN) & MASK_CECEN) ? "yes" : "no"); + v4l2_info(sd, "-----Signal status-----\n"); + v4l2_info(sd, "TMDS signal detected: %s\n", + hdmi_sys_status & MASK_S_TMDS ? "yes" : "no"); + v4l2_info(sd, "Stable sync signal: %s\n", + hdmi_sys_status & MASK_S_SYNC ? "yes" : "no"); + v4l2_info(sd, "PHY PLL locked: %s\n", + hdmi_sys_status & MASK_S_PHY_PLL ? "yes" : "no"); + v4l2_info(sd, "PHY DE detected: %s\n", + hdmi_sys_status & MASK_S_PHY_SCDT ? "yes" : "no"); + + if (tc358743_get_detected_timings(sd, &timings)) { + v4l2_info(sd, "No video detected\n"); + } else { + v4l2_print_dv_timings(sd->name, "Detected format: ", &timings, + true); + } + v4l2_print_dv_timings(sd->name, "Configured format: ", &state->timings, + true); + + v4l2_info(sd, "-----CSI-TX status-----\n"); + v4l2_info(sd, "Lanes needed: %d\n", + tc358743_num_csi_lanes_needed(sd)); + v4l2_info(sd, "Lanes in use: %d\n", + tc358743_num_csi_lanes_in_use(sd)); + v4l2_info(sd, "Waiting for particular sync signal: %s\n", + (i2c_rd16(sd, CSI_STATUS) & MASK_S_WSYNC) ? + "yes" : "no"); + v4l2_info(sd, "Transmit mode: %s\n", + (i2c_rd16(sd, CSI_STATUS) & MASK_S_TXACT) ? + "yes" : "no"); + v4l2_info(sd, "Receive mode: %s\n", + (i2c_rd16(sd, CSI_STATUS) & MASK_S_RXACT) ? + "yes" : "no"); + v4l2_info(sd, "Stopped: %s\n", + (i2c_rd16(sd, CSI_STATUS) & MASK_S_HLT) ? + "yes" : "no"); + v4l2_info(sd, "Color space: %s\n", + state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16 ? + "YCbCr 422 16-bit" : + state->mbus_fmt_code == MEDIA_BUS_FMT_RGB888_1X24 ? + "RGB 888 24-bit" : "Unsupported"); + + v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); + v4l2_info(sd, "HDCP encrypted content: %s\n", + hdmi_sys_status & MASK_S_HDCP ? "yes" : "no"); + v4l2_info(sd, "Input color space: %s %s range\n", + input_color_space[(vi_status3 & MASK_S_V_COLOR) >> 1], + (vi_status3 & MASK_LIMITED) ? "limited" : "full"); + if (!is_hdmi(sd)) + return 0; + v4l2_info(sd, "AV Mute: %s\n", hdmi_sys_status & MASK_S_AVMUTE ? "on" : + "off"); + v4l2_info(sd, "Deep color mode: %d-bits per channel\n", + deep_color_mode[(i2c_rd8(sd, VI_STATUS1) & + MASK_S_DEEPCOLOR) >> 2]); + print_avi_infoframe(sd); + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static void tc358743_print_register_map(struct v4l2_subdev *sd) +{ + v4l2_info(sd, "0x0000–0x00FF: Global Control Register\n"); + v4l2_info(sd, "0x0100–0x01FF: CSI2-TX PHY Register\n"); + v4l2_info(sd, "0x0200–0x03FF: CSI2-TX PPI Register\n"); + v4l2_info(sd, "0x0400–0x05FF: Reserved\n"); + v4l2_info(sd, "0x0600–0x06FF: CEC Register\n"); + v4l2_info(sd, "0x0700–0x84FF: Reserved\n"); + v4l2_info(sd, "0x8500–0x85FF: HDMIRX System Control Register\n"); + v4l2_info(sd, "0x8600–0x86FF: HDMIRX Audio Control Register\n"); + v4l2_info(sd, "0x8700–0x87FF: HDMIRX InfoFrame packet data Register\n"); + v4l2_info(sd, "0x8800–0x88FF: HDMIRX HDCP Port Register\n"); + v4l2_info(sd, "0x8900–0x89FF: HDMIRX Video Output Port & 3D Register\n"); + v4l2_info(sd, "0x8A00–0x8BFF: Reserved\n"); + v4l2_info(sd, "0x8C00–0x8FFF: HDMIRX EDID-RAM (1024bytes)\n"); + v4l2_info(sd, "0x9000–0x90FF: HDMIRX GBD Extraction Control\n"); + v4l2_info(sd, "0x9100–0x92FF: HDMIRX GBD RAM read\n"); + v4l2_info(sd, "0x9300- : Reserved\n"); +} + +static int tc358743_get_reg_size(u16 address) +{ + /* REF_01 p. 66-72 */ + if (address <= 0x00ff) + return 2; + else if ((address >= 0x0100) && (address <= 0x06FF)) + return 4; + else if ((address >= 0x0700) && (address <= 0x84ff)) + return 2; + else + return 1; +} + +static int tc358743_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + if (reg->reg > 0xffff) { + tc358743_print_register_map(sd); + return -EINVAL; + } + + reg->size = tc358743_get_reg_size(reg->reg); + + i2c_rd(sd, reg->reg, (u8 *)®->val, reg->size); + + return 0; +} + +static int tc358743_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + if (reg->reg > 0xffff) { + tc358743_print_register_map(sd); + return -EINVAL; + } + + /* It should not be possible for the user to enable HDCP with a simple + * v4l2-dbg command. + * + * DO NOT REMOVE THIS unless all other issues with HDCP have been + * resolved. + */ + if (reg->reg == HDCP_MODE || + reg->reg == HDCP_REG1 || + reg->reg == HDCP_REG2 || + reg->reg == HDCP_REG3 || + reg->reg == BCAPS) + return 0; + + i2c_wr(sd, (u16)reg->reg, (u8 *)®->val, + tc358743_get_reg_size(reg->reg)); + + return 0; +} +#endif + +static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled) +{ + u16 intstatus = i2c_rd16(sd, INTSTATUS); + + v4l2_dbg(1, debug, sd, "%s: IntStatus = 0x%04x\n", __func__, intstatus); + + if (intstatus & MASK_HDMI_INT) { + u8 hdmi_int0 = i2c_rd8(sd, HDMI_INT0); + u8 hdmi_int1 = i2c_rd8(sd, HDMI_INT1); + + if (hdmi_int0 & MASK_I_MISC) + tc358743_hdmi_misc_int_handler(sd, handled); + if (hdmi_int1 & MASK_I_CBIT) + tc358743_hdmi_cbit_int_handler(sd, handled); + if (hdmi_int1 & MASK_I_CLK) + tc358743_hdmi_clk_int_handler(sd, handled); + if (hdmi_int1 & MASK_I_SYS) + tc358743_hdmi_sys_int_handler(sd, handled); + if (hdmi_int1 & MASK_I_AUD) + tc358743_hdmi_audio_int_handler(sd, handled); + + i2c_wr16(sd, INTSTATUS, MASK_HDMI_INT); + intstatus &= ~MASK_HDMI_INT; + } + + if (intstatus & MASK_CSI_INT) { + u32 csi_int = i2c_rd32(sd, CSI_INT); + + if (csi_int & MASK_INTER) + tc358743_csi_err_int_handler(sd, handled); + + i2c_wr16(sd, INTSTATUS, MASK_CSI_INT); + intstatus &= ~MASK_CSI_INT; + } + + intstatus = i2c_rd16(sd, INTSTATUS); + if (intstatus) { + v4l2_dbg(1, debug, sd, + "%s: Unhandled IntStatus interrupts: 0x%02x\n", + __func__, intstatus); + } + + return 0; +} + +/* --------------- VIDEO OPS --------------- */ + +static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + *status = 0; + *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; + *status |= no_sync(sd) ? V4L2_IN_ST_NO_SYNC : 0; + + v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); + + return 0; +} + +static int tc358743_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct tc358743_state *state = to_state(sd); + struct v4l2_bt_timings *bt; + + if (!timings) + return -EINVAL; + + if (debug) + v4l2_print_dv_timings(sd->name, "tc358743_s_dv_timings: ", + timings, false); + + if (v4l2_match_dv_timings(&state->timings, timings, 0)) { + v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); + return 0; + } + + bt = &timings->bt; + + if (!v4l2_valid_dv_timings(timings, + &tc358743_timings_cap, NULL, NULL)) { + v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); + return -ERANGE; + } + + state->timings = *timings; + + enable_stream(sd, false); + tc358743_set_pll(sd); + tc358743_set_csi(sd); + + return 0; +} + +static int tc358743_g_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct tc358743_state *state = to_state(sd); + + *timings = state->timings; + + return 0; +} + +static int tc358743_enum_dv_timings(struct v4l2_subdev *sd, + struct v4l2_enum_dv_timings *timings) +{ + if (timings->pad != 0) + return -EINVAL; + + return v4l2_enum_dv_timings_cap(timings, + &tc358743_timings_cap, NULL, NULL); +} + +static int tc358743_query_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + int ret; + + ret = tc358743_get_detected_timings(sd, timings); + if (ret) + return ret; + + if (debug) + v4l2_print_dv_timings(sd->name, "tc358743_query_dv_timings: ", + timings, false); + + if (!v4l2_valid_dv_timings(timings, + &tc358743_timings_cap, NULL, NULL)) { + v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); + return -ERANGE; + } + + return 0; +} + +static int tc358743_dv_timings_cap(struct v4l2_subdev *sd, + struct v4l2_dv_timings_cap *cap) +{ + if (cap->pad != 0) + return -EINVAL; + + *cap = tc358743_timings_cap; + + return 0; +} + +static int tc358743_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + cfg->type = V4L2_MBUS_CSI2; + + /* Support for non-continuous CSI-2 clock is missing in the driver */ + cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + + switch (tc358743_num_csi_lanes_in_use(sd)) { + case 1: + cfg->flags |= V4L2_MBUS_CSI2_1_LANE; + break; + case 2: + cfg->flags |= V4L2_MBUS_CSI2_2_LANE; + break; + case 3: + cfg->flags |= V4L2_MBUS_CSI2_3_LANE; + break; + case 4: + cfg->flags |= V4L2_MBUS_CSI2_4_LANE; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int tc358743_s_stream(struct v4l2_subdev *sd, int enable) +{ + enable_stream(sd, enable); + + return 0; +} + +/* --------------- PAD OPS --------------- */ + +static int tc358743_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct tc358743_state *state = to_state(sd); + u8 vi_rep = i2c_rd8(sd, VI_REP); + + if (format->pad != 0) + return -EINVAL; + + format->format.code = state->mbus_fmt_code; + format->format.width = state->timings.bt.width; + format->format.height = state->timings.bt.height; + format->format.field = V4L2_FIELD_NONE; + + switch (vi_rep & MASK_VOUT_COLOR_SEL) { + case MASK_VOUT_COLOR_RGB_FULL: + case MASK_VOUT_COLOR_RGB_LIMITED: + format->format.colorspace = V4L2_COLORSPACE_SRGB; + break; + case MASK_VOUT_COLOR_601_YCBCR_LIMITED: + case MASK_VOUT_COLOR_601_YCBCR_FULL: + format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; + break; + case MASK_VOUT_COLOR_709_YCBCR_FULL: + case MASK_VOUT_COLOR_709_YCBCR_LIMITED: + format->format.colorspace = V4L2_COLORSPACE_REC709; + break; + default: + format->format.colorspace = 0; + break; + } + + return 0; +} + +static int tc358743_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct tc358743_state *state = to_state(sd); + + u32 code = format->format.code; /* is overwritten by get_fmt */ + int ret = tc358743_get_fmt(sd, cfg, format); + + format->format.code = code; + + if (ret) + return ret; + + switch (code) { + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_UYVY8_1X16: + break; + default: + return -EINVAL; + } + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + + state->mbus_fmt_code = format->format.code; + + enable_stream(sd, false); + tc358743_set_pll(sd); + tc358743_set_csi(sd); + tc358743_set_csi_color_space(sd); + + return 0; +} + +static int tc358743_g_edid(struct v4l2_subdev *sd, + struct v4l2_subdev_edid *edid) +{ + struct tc358743_state *state = to_state(sd); + + if (edid->pad != 0) + return -EINVAL; + + if (edid->start_block == 0 && edid->blocks == 0) { + edid->blocks = state->edid_blocks_written; + return 0; + } + + if (state->edid_blocks_written == 0) + return -ENODATA; + + if (edid->start_block >= state->edid_blocks_written || + edid->blocks == 0) + return -EINVAL; + + if (edid->start_block + edid->blocks > state->edid_blocks_written) + edid->blocks = state->edid_blocks_written - edid->start_block; + + i2c_rd(sd, EDID_RAM + (edid->start_block * EDID_BLOCK_SIZE), edid->edid, + edid->blocks * EDID_BLOCK_SIZE); + + return 0; +} + +static int tc358743_s_edid(struct v4l2_subdev *sd, + struct v4l2_subdev_edid *edid) +{ + struct tc358743_state *state = to_state(sd); + u16 edid_len = edid->blocks * EDID_BLOCK_SIZE; + + v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n", + __func__, edid->pad, edid->start_block, edid->blocks); + + if (edid->pad != 0) + return -EINVAL; + + if (edid->start_block != 0) + return -EINVAL; + + if (edid->blocks > EDID_NUM_BLOCKS_MAX) { + edid->blocks = EDID_NUM_BLOCKS_MAX; + return -E2BIG; + } + + tc358743_disable_edid(sd); + + i2c_wr8(sd, EDID_LEN1, edid_len & 0xff); + i2c_wr8(sd, EDID_LEN2, edid_len >> 8); + + if (edid->blocks == 0) { + state->edid_blocks_written = 0; + return 0; + } + + i2c_wr(sd, EDID_RAM, edid->edid, edid_len); + + state->edid_blocks_written = edid->blocks; + + if (tx_5v_power_present(sd)) + tc358743_enable_edid(sd); + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops tc358743_core_ops = { + .log_status = tc358743_log_status, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = tc358743_g_register, + .s_register = tc358743_s_register, +#endif + .interrupt_service_routine = tc358743_isr, +}; + +static const struct v4l2_subdev_video_ops tc358743_video_ops = { + .g_input_status = tc358743_g_input_status, + .s_dv_timings = tc358743_s_dv_timings, + .g_dv_timings = tc358743_g_dv_timings, + .query_dv_timings = tc358743_query_dv_timings, + .g_mbus_config = tc358743_g_mbus_config, + .s_stream = tc358743_s_stream, +}; + +static const struct v4l2_subdev_pad_ops tc358743_pad_ops = { + .set_fmt = tc358743_set_fmt, + .get_fmt = tc358743_get_fmt, + .get_edid = tc358743_g_edid, + .set_edid = tc358743_s_edid, + .enum_dv_timings = tc358743_enum_dv_timings, + .dv_timings_cap = tc358743_dv_timings_cap, +}; + +static const struct v4l2_subdev_ops tc358743_ops = { + .core = &tc358743_core_ops, + .video = &tc358743_video_ops, + .pad = &tc358743_pad_ops, +}; + +/* --------------- CUSTOM CTRLS --------------- */ + +static const struct v4l2_ctrl_config tc358743_ctrl_audio_sampling_rate = { + .id = TC358743_CID_AUDIO_SAMPLING_RATE, + .name = "Audio sampling rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 768000, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_READ_ONLY, +}; + +static const struct v4l2_ctrl_config tc358743_ctrl_audio_present = { + .id = TC358743_CID_AUDIO_PRESENT, + .name = "Audio present", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_READ_ONLY, +}; + +/* --------------- PROBE / REMOVE --------------- */ + +static int tc358743_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + static struct v4l2_dv_timings default_timing = + V4L2_DV_BT_CEA_640X480P59_94; + struct tc358743_state *state; + struct tc358743_platform_data *pdata = client->dev.platform_data; + struct v4l2_subdev *sd; + int err; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + v4l_dbg(1, debug, client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + state = devm_kzalloc(&client->dev, sizeof(struct tc358743_state), + GFP_KERNEL); + if (!state) + return -ENOMEM; + + /* platform data */ + if (!pdata) { + v4l_err(client, "No platform data!\n"); + return -ENODEV; + } + state->pdata = *pdata; + + state->i2c_client = client; + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &tc358743_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + + /* i2c access */ + if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) { + v4l2_info(sd, "not a TC358743 on address 0x%x\n", + client->addr << 1); + return -ENODEV; + } + + /* control handlers */ + v4l2_ctrl_handler_init(&state->hdl, 3); + + /* private controls */ + state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL, + V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); + + /* custom controls */ + state->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(&state->hdl, + &tc358743_ctrl_audio_sampling_rate, NULL); + + state->audio_present_ctrl = v4l2_ctrl_new_custom(&state->hdl, + &tc358743_ctrl_audio_present, NULL); + + sd->ctrl_handler = &state->hdl; + if (state->hdl.error) { + err = state->hdl.error; + goto err_hdl; + } + + if (tc358743_update_controls(sd)) { + err = -ENODEV; + goto err_hdl; + } + + /* work queues */ + state->work_queues = create_singlethread_workqueue(client->name); + if (!state->work_queues) { + v4l2_err(sd, "Could not create work queue\n"); + err = -ENOMEM; + goto err_hdl; + } + + mutex_init(&state->confctl_mutex); + + INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, + tc358743_delayed_work_enable_hotplug); + + tc358743_initial_setup(sd); + + tc358743_s_dv_timings(sd, &default_timing); + + state->mbus_fmt_code = MEDIA_BUS_FMT_RGB888_1X24; + tc358743_set_csi_color_space(sd); + + tc358743_init_interrupts(sd); + tc358743_enable_interrupts(sd, tx_5v_power_present(sd)); + i2c_wr16(sd, INTMASK, ~(MASK_HDMI_MSK | MASK_CSI_MSK) & 0xffff); + + err = v4l2_ctrl_handler_setup(sd->ctrl_handler); + if (err) + goto err_work_queues; + + v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, + client->addr << 1, client->adapter->name); + + return 0; + +err_work_queues: + cancel_delayed_work(&state->delayed_work_enable_hotplug); + destroy_workqueue(state->work_queues); + mutex_destroy(&state->confctl_mutex); +err_hdl: + v4l2_ctrl_handler_free(&state->hdl); + return err; +} + +static int tc358743_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct tc358743_state *state = to_state(sd); + + cancel_delayed_work(&state->delayed_work_enable_hotplug); + destroy_workqueue(state->work_queues); + v4l2_device_unregister_subdev(sd); + mutex_destroy(&state->confctl_mutex); + v4l2_ctrl_handler_free(&state->hdl); + + return 0; +} + +static struct i2c_device_id tc358743_id[] = { + {"tc358743", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, tc358743_id); + +static struct i2c_driver tc358743_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tc358743", + }, + .probe = tc358743_probe, + .remove = tc358743_remove, + .id_table = tc358743_id, +}; + +module_i2c_driver(tc358743_driver); diff --git a/drivers/media/i2c/tc358743_regs.h b/drivers/media/i2c/tc358743_regs.h new file mode 100644 index 000000000000..81f1db558e7c --- /dev/null +++ b/drivers/media/i2c/tc358743_regs.h @@ -0,0 +1,681 @@ +/* + * tc358743 - Toshiba HDMI to CSI-2 bridge - register names and bit masks + * + * Copyright 2015 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. + * + */ + +/* + * References (c = chapter, p = page): + * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60 + */ + +/* Bit masks has prefix 'MASK_' and options after '_'. */ + +#ifndef __TC358743_REGS_H +#define __TC358743_REGS_H + +#define CHIPID 0x0000 +#define MASK_CHIPID 0xff00 +#define MASK_REVID 0x00ff + +#define SYSCTL 0x0002 +#define MASK_IRRST 0x0800 +#define MASK_CECRST 0x0400 +#define MASK_CTXRST 0x0200 +#define MASK_HDMIRST 0x0100 +#define MASK_SLEEP 0x0001 + +#define CONFCTL 0x0004 +#define MASK_PWRISO 0x8000 +#define MASK_ACLKOPT 0x1000 +#define MASK_AUDCHNUM 0x0c00 +#define MASK_AUDCHNUM_8 0x0000 +#define MASK_AUDCHNUM_6 0x0400 +#define MASK_AUDCHNUM_4 0x0800 +#define MASK_AUDCHNUM_2 0x0c00 +#define MASK_AUDCHSEL 0x0200 +#define MASK_I2SDLYOPT 0x0100 +#define MASK_YCBCRFMT 0x00c0 +#define MASK_YCBCRFMT_444 0x0000 +#define MASK_YCBCRFMT_422_12_BIT 0x0040 +#define MASK_YCBCRFMT_COLORBAR 0x0080 +#define MASK_YCBCRFMT_422_8_BIT 0x00c0 +#define MASK_INFRMEN 0x0020 +#define MASK_AUDOUTSEL 0x0018 +#define MASK_AUDOUTSEL_CSI 0x0000 +#define MASK_AUDOUTSEL_I2S 0x0010 +#define MASK_AUDOUTSEL_TDM 0x0018 +#define MASK_AUTOINDEX 0x0004 +#define MASK_ABUFEN 0x0002 +#define MASK_VBUFEN 0x0001 + +#define FIFOCTL 0x0006 + +#define INTSTATUS 0x0014 +#define MASK_AMUTE_INT 0x0400 +#define MASK_HDMI_INT 0x0200 +#define MASK_CSI_INT 0x0100 +#define MASK_SYS_INT 0x0020 +#define MASK_CEC_EINT 0x0010 +#define MASK_CEC_TINT 0x0008 +#define MASK_CEC_RINT 0x0004 +#define MASK_IR_EINT 0x0002 +#define MASK_IR_DINT 0x0001 + +#define INTMASK 0x0016 +#define MASK_AMUTE_MSK 0x0400 +#define MASK_HDMI_MSK 0x0200 +#define MASK_CSI_MSK 0x0100 +#define MASK_SYS_MSK 0x0020 +#define MASK_CEC_EMSK 0x0010 +#define MASK_CEC_TMSK 0x0008 +#define MASK_CEC_RMSK 0x0004 +#define MASK_IR_EMSK 0x0002 +#define MASK_IR_DMSK 0x0001 + +#define INTFLAG 0x0018 +#define INTSYSSTATUS 0x001A + +#define PLLCTL0 0x0020 +#define MASK_PLL_PRD 0xf000 +#define SET_PLL_PRD(prd) ((((prd) - 1) << 12) &\ + MASK_PLL_PRD) +#define MASK_PLL_FBD 0x01ff +#define SET_PLL_FBD(fbd) (((fbd) - 1) & MASK_PLL_FBD) + +#define PLLCTL1 0x0022 +#define MASK_PLL_FRS 0x0c00 +#define SET_PLL_FRS(frs) (((frs) << 10) & MASK_PLL_FRS) +#define MASK_PLL_LBWS 0x0300 +#define MASK_LFBREN 0x0040 +#define MASK_BYPCKEN 0x0020 +#define MASK_CKEN 0x0010 +#define MASK_RESETB 0x0002 +#define MASK_PLL_EN 0x0001 + +#define CLW_CNTRL 0x0140 +#define MASK_CLW_LANEDISABLE 0x0001 + +#define D0W_CNTRL 0x0144 +#define MASK_D0W_LANEDISABLE 0x0001 + +#define D1W_CNTRL 0x0148 +#define MASK_D1W_LANEDISABLE 0x0001 + +#define D2W_CNTRL 0x014C +#define MASK_D2W_LANEDISABLE 0x0001 + +#define D3W_CNTRL 0x0150 +#define MASK_D3W_LANEDISABLE 0x0001 + +#define STARTCNTRL 0x0204 +#define MASK_START 0x00000001 + +#define LINEINITCNT 0x0210 +#define LPTXTIMECNT 0x0214 +#define TCLK_HEADERCNT 0x0218 +#define TCLK_TRAILCNT 0x021C +#define THS_HEADERCNT 0x0220 +#define TWAKEUP 0x0224 +#define TCLK_POSTCNT 0x0228 +#define THS_TRAILCNT 0x022C +#define HSTXVREGCNT 0x0230 + +#define HSTXVREGEN 0x0234 +#define MASK_D3M_HSTXVREGEN 0x0010 +#define MASK_D2M_HSTXVREGEN 0x0008 +#define MASK_D1M_HSTXVREGEN 0x0004 +#define MASK_D0M_HSTXVREGEN 0x0002 +#define MASK_CLM_HSTXVREGEN 0x0001 + + +#define TXOPTIONCNTRL 0x0238 +#define MASK_CONTCLKMODE 0x00000001 + +#define CSI_CONTROL 0x040C +#define MASK_CSI_MODE 0x8000 +#define MASK_HTXTOEN 0x0400 +#define MASK_TXHSMD 0x0080 +#define MASK_HSCKMD 0x0020 +#define MASK_NOL 0x0006 +#define MASK_NOL_1 0x0000 +#define MASK_NOL_2 0x0002 +#define MASK_NOL_3 0x0004 +#define MASK_NOL_4 0x0006 +#define MASK_EOTDIS 0x0001 + +#define CSI_INT 0x0414 +#define MASK_INTHLT 0x00000008 +#define MASK_INTER 0x00000004 + +#define CSI_INT_ENA 0x0418 +#define MASK_IENHLT 0x00000008 +#define MASK_IENER 0x00000004 + +#define CSI_ERR 0x044C +#define MASK_INER 0x00000200 +#define MASK_WCER 0x00000100 +#define MASK_QUNK 0x00000010 +#define MASK_TXBRK 0x00000002 + +#define CSI_ERR_INTENA 0x0450 +#define CSI_ERR_HALT 0x0454 + +#define CSI_CONFW 0x0500 +#define MASK_MODE 0xe0000000 +#define MASK_MODE_SET 0xa0000000 +#define MASK_MODE_CLEAR 0xc0000000 +#define MASK_ADDRESS 0x1f000000 +#define MASK_ADDRESS_CSI_CONTROL 0x03000000 +#define MASK_ADDRESS_CSI_INT_ENA 0x06000000 +#define MASK_ADDRESS_CSI_ERR_INTENA 0x14000000 +#define MASK_ADDRESS_CSI_ERR_HALT 0x15000000 +#define MASK_DATA 0x0000ffff + +#define CSI_INT_CLR 0x050C +#define MASK_ICRER 0x00000004 + +#define CSI_START 0x0518 +#define MASK_STRT 0x00000001 + +#define CECEN 0x0600 +#define MASK_CECEN 0x0001 + +#define HDMI_INT0 0x8500 +#define MASK_I_KEY 0x80 +#define MASK_I_MISC 0x02 +#define MASK_I_PHYERR 0x01 + +#define HDMI_INT1 0x8501 +#define MASK_I_GBD 0x80 +#define MASK_I_HDCP 0x40 +#define MASK_I_ERR 0x20 +#define MASK_I_AUD 0x10 +#define MASK_I_CBIT 0x08 +#define MASK_I_PACKET 0x04 +#define MASK_I_CLK 0x02 +#define MASK_I_SYS 0x01 + +#define SYS_INT 0x8502 +#define MASK_I_ACR_CTS 0x80 +#define MASK_I_ACRN 0x40 +#define MASK_I_DVI 0x20 +#define MASK_I_HDMI 0x10 +#define MASK_I_NOPMBDET 0x08 +#define MASK_I_DPMBDET 0x04 +#define MASK_I_TMDS 0x02 +#define MASK_I_DDC 0x01 + +#define CLK_INT 0x8503 +#define MASK_I_OUT_H_CHG 0x40 +#define MASK_I_IN_DE_CHG 0x20 +#define MASK_I_IN_HV_CHG 0x10 +#define MASK_I_DC_CHG 0x08 +#define MASK_I_PXCLK_CHG 0x04 +#define MASK_I_PHYCLK_CHG 0x02 +#define MASK_I_TMDSCLK_CHG 0x01 + +#define CBIT_INT 0x8505 +#define MASK_I_AF_LOCK 0x80 +#define MASK_I_AF_UNLOCK 0x40 +#define MASK_I_CBIT_FS 0x02 + +#define AUDIO_INT 0x8506 + +#define ERR_INT 0x8507 +#define MASK_I_EESS_ERR 0x80 + +#define HDCP_INT 0x8508 +#define MASK_I_AVM_SET 0x80 +#define MASK_I_AVM_CLR 0x40 +#define MASK_I_LINKERR 0x20 +#define MASK_I_SHA_END 0x10 +#define MASK_I_R0_END 0x08 +#define MASK_I_KM_END 0x04 +#define MASK_I_AKSV_END 0x02 +#define MASK_I_AN_END 0x01 + +#define MISC_INT 0x850B +#define MASK_I_AS_LAYOUT 0x10 +#define MASK_I_NO_SPD 0x08 +#define MASK_I_NO_VS 0x03 +#define MASK_I_SYNC_CHG 0x02 +#define MASK_I_AUDIO_MUTE 0x01 + +#define KEY_INT 0x850F + +#define SYS_INTM 0x8512 +#define MASK_M_ACR_CTS 0x80 +#define MASK_M_ACR_N 0x40 +#define MASK_M_DVI_DET 0x20 +#define MASK_M_HDMI_DET 0x10 +#define MASK_M_NOPMBDET 0x08 +#define MASK_M_BPMBDET 0x04 +#define MASK_M_TMDS 0x02 +#define MASK_M_DDC 0x01 + +#define CLK_INTM 0x8513 +#define MASK_M_OUT_H_CHG 0x40 +#define MASK_M_IN_DE_CHG 0x20 +#define MASK_M_IN_HV_CHG 0x10 +#define MASK_M_DC_CHG 0x08 +#define MASK_M_PXCLK_CHG 0x04 +#define MASK_M_PHYCLK_CHG 0x02 +#define MASK_M_TMDS_CHG 0x01 + +#define PACKET_INTM 0x8514 + +#define CBIT_INTM 0x8515 +#define MASK_M_AF_LOCK 0x80 +#define MASK_M_AF_UNLOCK 0x40 +#define MASK_M_CBIT_FS 0x02 + +#define AUDIO_INTM 0x8516 +#define MASK_M_BUFINIT_END 0x01 + +#define ERR_INTM 0x8517 +#define MASK_M_EESS_ERR 0x80 + +#define HDCP_INTM 0x8518 +#define MASK_M_AVM_SET 0x80 +#define MASK_M_AVM_CLR 0x40 +#define MASK_M_LINKERR 0x20 +#define MASK_M_SHA_END 0x10 +#define MASK_M_R0_END 0x08 +#define MASK_M_KM_END 0x04 +#define MASK_M_AKSV_END 0x02 +#define MASK_M_AN_END 0x01 + +#define MISC_INTM 0x851B +#define MASK_M_AS_LAYOUT 0x10 +#define MASK_M_NO_SPD 0x08 +#define MASK_M_NO_VS 0x03 +#define MASK_M_SYNC_CHG 0x02 +#define MASK_M_AUDIO_MUTE 0x01 + +#define KEY_INTM 0x851F + +#define SYS_STATUS 0x8520 +#define MASK_S_SYNC 0x80 +#define MASK_S_AVMUTE 0x40 +#define MASK_S_HDCP 0x20 +#define MASK_S_HDMI 0x10 +#define MASK_S_PHY_SCDT 0x08 +#define MASK_S_PHY_PLL 0x04 +#define MASK_S_TMDS 0x02 +#define MASK_S_DDC5V 0x01 + +#define CSI_STATUS 0x0410 +#define MASK_S_WSYNC 0x0400 +#define MASK_S_TXACT 0x0200 +#define MASK_S_RXACT 0x0100 +#define MASK_S_HLT 0x0001 + +#define VI_STATUS1 0x8522 +#define MASK_S_V_GBD 0x08 +#define MASK_S_DEEPCOLOR 0x0c +#define MASK_S_V_422 0x02 +#define MASK_S_V_INTERLACE 0x01 + +#define AU_STATUS0 0x8523 +#define MASK_S_A_SAMPLE 0x01 + +#define VI_STATUS3 0x8528 +#define MASK_S_V_COLOR 0x1e +#define MASK_LIMITED 0x01 + +#define PHY_CTL0 0x8531 +#define MASK_PHY_SYSCLK_IND 0x02 +#define MASK_PHY_CTL 0x01 + + +#define PHY_CTL1 0x8532 /* Not in REF_01 */ +#define MASK_PHY_AUTO_RST1 0xf0 +#define MASK_PHY_AUTO_RST1_OFF 0x00 +#define SET_PHY_AUTO_RST1_US(us) ((((us) / 200) << 4) & \ + MASK_PHY_AUTO_RST1) +#define MASK_FREQ_RANGE_MODE 0x0f +#define SET_FREQ_RANGE_MODE_CYCLES(cycles) (((cycles) - 1) & \ + MASK_FREQ_RANGE_MODE) + +#define PHY_CTL2 0x8533 /* Not in REF_01 */ +#define MASK_PHY_AUTO_RST4 0x04 +#define MASK_PHY_AUTO_RST3 0x02 +#define MASK_PHY_AUTO_RST2 0x01 +#define MASK_PHY_AUTO_RSTn (MASK_PHY_AUTO_RST4 | \ + MASK_PHY_AUTO_RST3 | \ + MASK_PHY_AUTO_RST2) + +#define PHY_EN 0x8534 +#define MASK_ENABLE_PHY 0x01 + +#define PHY_RST 0x8535 +#define MASK_RESET_CTRL 0x01 /* Reset active low */ + +#define PHY_BIAS 0x8536 /* Not in REF_01 */ + +#define PHY_CSQ 0x853F /* Not in REF_01 */ +#define MASK_CSQ_CNT 0x0f +#define SET_CSQ_CNT_LEVEL(n) (n & MASK_CSQ_CNT) + +#define SYS_FREQ0 0x8540 +#define SYS_FREQ1 0x8541 + +#define SYS_CLK 0x8542 /* Not in REF_01 */ +#define MASK_CLK_DIFF 0x0C +#define MASK_CLK_DIV 0x03 + +#define DDC_CTL 0x8543 +#define MASK_DDC_ACK_POL 0x08 +#define MASK_DDC_ACTION 0x04 +#define MASK_DDC5V_MODE 0x03 +#define MASK_DDC5V_MODE_0MS 0x00 +#define MASK_DDC5V_MODE_50MS 0x01 +#define MASK_DDC5V_MODE_100MS 0x02 +#define MASK_DDC5V_MODE_200MS 0x03 + +#define HPD_CTL 0x8544 +#define MASK_HPD_CTL0 0x10 +#define MASK_HPD_OUT0 0x01 + +#define ANA_CTL 0x8545 +#define MASK_APPL_PCSX 0x30 +#define MASK_APPL_PCSX_HIZ 0x00 +#define MASK_APPL_PCSX_L_FIX 0x10 +#define MASK_APPL_PCSX_H_FIX 0x20 +#define MASK_APPL_PCSX_NORMAL 0x30 +#define MASK_ANALOG_ON 0x01 + +#define AVM_CTL 0x8546 + +#define INIT_END 0x854A +#define MASK_INIT_END 0x01 + +#define HDMI_DET 0x8552 /* Not in REF_01 */ +#define MASK_HDMI_DET_MOD1 0x80 +#define MASK_HDMI_DET_MOD0 0x40 +#define MASK_HDMI_DET_V 0x30 +#define MASK_HDMI_DET_V_SYNC 0x00 +#define MASK_HDMI_DET_V_ASYNC_25MS 0x10 +#define MASK_HDMI_DET_V_ASYNC_50MS 0x20 +#define MASK_HDMI_DET_V_ASYNC_100MS 0x30 +#define MASK_HDMI_DET_NUM 0x0f + +#define HDCP_MODE 0x8560 +#define MASK_MODE_RST_TN 0x20 +#define MASK_LINE_REKEY 0x10 +#define MASK_AUTO_CLR 0x04 + +#define HDCP_REG1 0x8563 /* Not in REF_01 */ +#define MASK_AUTH_UNAUTH_SEL 0x70 +#define MASK_AUTH_UNAUTH_SEL_12_FRAMES 0x70 +#define MASK_AUTH_UNAUTH_SEL_8_FRAMES 0x60 +#define MASK_AUTH_UNAUTH_SEL_4_FRAMES 0x50 +#define MASK_AUTH_UNAUTH_SEL_2_FRAMES 0x40 +#define MASK_AUTH_UNAUTH_SEL_64_FRAMES 0x30 +#define MASK_AUTH_UNAUTH_SEL_32_FRAMES 0x20 +#define MASK_AUTH_UNAUTH_SEL_16_FRAMES 0x10 +#define MASK_AUTH_UNAUTH_SEL_ONCE 0x00 +#define MASK_AUTH_UNAUTH 0x01 +#define MASK_AUTH_UNAUTH_AUTO 0x01 + +#define HDCP_REG2 0x8564 /* Not in REF_01 */ +#define MASK_AUTO_P3_RESET 0x0F +#define SET_AUTO_P3_RESET_FRAMES(n) (n & MASK_AUTO_P3_RESET) +#define MASK_AUTO_P3_RESET_OFF 0x00 + +#define VI_MODE 0x8570 +#define MASK_RGB_DVI 0x08 /* Not in REF_01 */ + +#define VOUT_SET2 0x8573 +#define MASK_SEL422 0x80 +#define MASK_VOUT_422FIL_100 0x40 +#define MASK_VOUTCOLORMODE 0x03 +#define MASK_VOUTCOLORMODE_THROUGH 0x00 +#define MASK_VOUTCOLORMODE_AUTO 0x01 +#define MASK_VOUTCOLORMODE_MANUAL 0x03 + +#define VOUT_SET3 0x8574 +#define MASK_VOUT_EXTCNT 0x08 + +#define VI_REP 0x8576 +#define MASK_VOUT_COLOR_SEL 0xe0 +#define MASK_VOUT_COLOR_RGB_FULL 0x00 +#define MASK_VOUT_COLOR_RGB_LIMITED 0x20 +#define MASK_VOUT_COLOR_601_YCBCR_FULL 0x40 +#define MASK_VOUT_COLOR_601_YCBCR_LIMITED 0x60 +#define MASK_VOUT_COLOR_709_YCBCR_FULL 0x80 +#define MASK_VOUT_COLOR_709_YCBCR_LIMITED 0xa0 +#define MASK_VOUT_COLOR_FULL_TO_LIMITED 0xc0 +#define MASK_VOUT_COLOR_LIMITED_TO_FULL 0xe0 +#define MASK_IN_REP_HEN 0x10 +#define MASK_IN_REP 0x0f + +#define VI_MUTE 0x857F +#define MASK_AUTO_MUTE 0xc0 +#define MASK_VI_MUTE 0x10 + +#define DE_WIDTH_H_LO 0x8582 /* Not in REF_01 */ +#define DE_WIDTH_H_HI 0x8583 /* Not in REF_01 */ +#define DE_WIDTH_V_LO 0x8588 /* Not in REF_01 */ +#define DE_WIDTH_V_HI 0x8589 /* Not in REF_01 */ +#define H_SIZE_LO 0x858A /* Not in REF_01 */ +#define H_SIZE_HI 0x858B /* Not in REF_01 */ +#define V_SIZE_LO 0x858C /* Not in REF_01 */ +#define V_SIZE_HI 0x858D /* Not in REF_01 */ +#define FV_CNT_LO 0x85A1 /* Not in REF_01 */ +#define FV_CNT_HI 0x85A2 /* Not in REF_01 */ + +#define FH_MIN0 0x85AA /* Not in REF_01 */ +#define FH_MIN1 0x85AB /* Not in REF_01 */ +#define FH_MAX0 0x85AC /* Not in REF_01 */ +#define FH_MAX1 0x85AD /* Not in REF_01 */ + +#define HV_RST 0x85AF /* Not in REF_01 */ +#define MASK_H_PI_RST 0x20 +#define MASK_V_PI_RST 0x10 + +#define EDID_MODE 0x85C7 +#define MASK_EDID_SPEED 0x40 +#define MASK_EDID_MODE 0x03 +#define MASK_EDID_MODE_DISABLE 0x00 +#define MASK_EDID_MODE_DDC2B 0x01 +#define MASK_EDID_MODE_E_DDC 0x02 + +#define EDID_LEN1 0x85CA +#define EDID_LEN2 0x85CB + +#define HDCP_REG3 0x85D1 /* Not in REF_01 */ +#define KEY_RD_CMD 0x01 + +#define FORCE_MUTE 0x8600 +#define MASK_FORCE_AMUTE 0x10 +#define MASK_FORCE_DMUTE 0x01 + +#define CMD_AUD 0x8601 +#define MASK_CMD_BUFINIT 0x04 +#define MASK_CMD_LOCKDET 0x02 +#define MASK_CMD_MUTE 0x01 + +#define AUTO_CMD0 0x8602 +#define MASK_AUTO_MUTE7 0x80 +#define MASK_AUTO_MUTE6 0x40 +#define MASK_AUTO_MUTE5 0x20 +#define MASK_AUTO_MUTE4 0x10 +#define MASK_AUTO_MUTE3 0x08 +#define MASK_AUTO_MUTE2 0x04 +#define MASK_AUTO_MUTE1 0x02 +#define MASK_AUTO_MUTE0 0x01 + +#define AUTO_CMD1 0x8603 +#define MASK_AUTO_MUTE10 0x04 +#define MASK_AUTO_MUTE9 0x02 +#define MASK_AUTO_MUTE8 0x01 + +#define AUTO_CMD2 0x8604 +#define MASK_AUTO_PLAY3 0x08 +#define MASK_AUTO_PLAY2 0x04 + +#define BUFINIT_START 0x8606 +#define SET_BUFINIT_START_MS(milliseconds) ((milliseconds) / 100) + +#define FS_MUTE 0x8607 +#define MASK_FS_ELSE_MUTE 0x80 +#define MASK_FS22_MUTE 0x40 +#define MASK_FS24_MUTE 0x20 +#define MASK_FS88_MUTE 0x10 +#define MASK_FS96_MUTE 0x08 +#define MASK_FS176_MUTE 0x04 +#define MASK_FS192_MUTE 0x02 +#define MASK_FS_NO_MUTE 0x01 + +#define FS_IMODE 0x8620 +#define MASK_NLPCM_HMODE 0x40 +#define MASK_NLPCM_SMODE 0x20 +#define MASK_NLPCM_IMODE 0x10 +#define MASK_FS_HMODE 0x08 +#define MASK_FS_AMODE 0x04 +#define MASK_FS_SMODE 0x02 +#define MASK_FS_IMODE 0x01 + +#define FS_SET 0x8621 +#define MASK_FS 0x0f + +#define LOCKDET_REF0 0x8630 +#define LOCKDET_REF1 0x8631 +#define LOCKDET_REF2 0x8632 + +#define ACR_MODE 0x8640 +#define MASK_ACR_LOAD 0x10 +#define MASK_N_MODE 0x04 +#define MASK_CTS_MODE 0x01 + +#define ACR_MDF0 0x8641 +#define MASK_ACR_L2MDF 0x70 +#define MASK_ACR_L2MDF_0_PPM 0x00 +#define MASK_ACR_L2MDF_61_PPM 0x10 +#define MASK_ACR_L2MDF_122_PPM 0x20 +#define MASK_ACR_L2MDF_244_PPM 0x30 +#define MASK_ACR_L2MDF_488_PPM 0x40 +#define MASK_ACR_L2MDF_976_PPM 0x50 +#define MASK_ACR_L2MDF_1976_PPM 0x60 +#define MASK_ACR_L2MDF_3906_PPM 0x70 +#define MASK_ACR_L1MDF 0x07 +#define MASK_ACR_L1MDF_0_PPM 0x00 +#define MASK_ACR_L1MDF_61_PPM 0x01 +#define MASK_ACR_L1MDF_122_PPM 0x02 +#define MASK_ACR_L1MDF_244_PPM 0x03 +#define MASK_ACR_L1MDF_488_PPM 0x04 +#define MASK_ACR_L1MDF_976_PPM 0x05 +#define MASK_ACR_L1MDF_1976_PPM 0x06 +#define MASK_ACR_L1MDF_3906_PPM 0x07 + +#define ACR_MDF1 0x8642 +#define MASK_ACR_L3MDF 0x07 +#define MASK_ACR_L3MDF_0_PPM 0x00 +#define MASK_ACR_L3MDF_61_PPM 0x01 +#define MASK_ACR_L3MDF_122_PPM 0x02 +#define MASK_ACR_L3MDF_244_PPM 0x03 +#define MASK_ACR_L3MDF_488_PPM 0x04 +#define MASK_ACR_L3MDF_976_PPM 0x05 +#define MASK_ACR_L3MDF_1976_PPM 0x06 +#define MASK_ACR_L3MDF_3906_PPM 0x07 + +#define SDO_MODE1 0x8652 +#define MASK_SDO_BIT_LENG 0x70 +#define MASK_SDO_FMT 0x03 +#define MASK_SDO_FMT_RIGHT 0x00 +#define MASK_SDO_FMT_LEFT 0x01 +#define MASK_SDO_FMT_I2S 0x02 + +#define DIV_MODE 0x8665 /* Not in REF_01 */ +#define MASK_DIV_DLY 0xf0 +#define SET_DIV_DLY_MS(milliseconds) ((((milliseconds) / 100) << 4) & \ + MASK_DIV_DLY) +#define MASK_DIV_MODE 0x01 + +#define NCO_F0_MOD 0x8670 +#define MASK_NCO_F0_MOD 0x03 +#define MASK_NCO_F0_MOD_42MHZ 0x00 +#define MASK_NCO_F0_MOD_27MHZ 0x01 + +#define PK_INT_MODE 0x8709 +#define MASK_ISRC2_INT_MODE 0x80 +#define MASK_ISRC_INT_MODE 0x40 +#define MASK_ACP_INT_MODE 0x20 +#define MASK_VS_INT_MODE 0x10 +#define MASK_SPD_INT_MODE 0x08 +#define MASK_MS_INT_MODE 0x04 +#define MASK_AUD_INT_MODE 0x02 +#define MASK_AVI_INT_MODE 0x01 + +#define NO_PKT_LIMIT 0x870B +#define MASK_NO_ACP_LIMIT 0xf0 +#define SET_NO_ACP_LIMIT_MS(milliseconds) ((((milliseconds) / 80) << 4) & \ + MASK_NO_ACP_LIMIT) +#define MASK_NO_AVI_LIMIT 0x0f +#define SET_NO_AVI_LIMIT_MS(milliseconds) (((milliseconds) / 80) & \ + MASK_NO_AVI_LIMIT) + +#define NO_PKT_CLR 0x870C +#define MASK_NO_VS_CLR 0x40 +#define MASK_NO_SPD_CLR 0x20 +#define MASK_NO_ACP_CLR 0x10 +#define MASK_NO_AVI_CLR1 0x02 +#define MASK_NO_AVI_CLR0 0x01 + +#define ERR_PK_LIMIT 0x870D +#define NO_PKT_LIMIT2 0x870E +#define PK_AVI_0HEAD 0x8710 +#define PK_AVI_1HEAD 0x8711 +#define PK_AVI_2HEAD 0x8712 +#define PK_AVI_0BYTE 0x8713 +#define PK_AVI_1BYTE 0x8714 +#define PK_AVI_2BYTE 0x8715 +#define PK_AVI_3BYTE 0x8716 +#define PK_AVI_4BYTE 0x8717 +#define PK_AVI_5BYTE 0x8718 +#define PK_AVI_6BYTE 0x8719 +#define PK_AVI_7BYTE 0x871A +#define PK_AVI_8BYTE 0x871B +#define PK_AVI_9BYTE 0x871C +#define PK_AVI_10BYTE 0x871D +#define PK_AVI_11BYTE 0x871E +#define PK_AVI_12BYTE 0x871F +#define PK_AVI_13BYTE 0x8720 +#define PK_AVI_14BYTE 0x8721 +#define PK_AVI_15BYTE 0x8722 +#define PK_AVI_16BYTE 0x8723 + +#define BKSV 0x8800 + +#define BCAPS 0x8840 +#define MASK_HDMI_RSVD 0x80 +#define MASK_REPEATER 0x40 +#define MASK_READY 0x20 +#define MASK_FASTI2C 0x10 +#define MASK_1_1_FEA 0x02 +#define MASK_FAST_REAU 0x01 + +#define BSTATUS1 0x8842 +#define MASK_MAX_EXCED 0x08 + +#define EDID_RAM 0x8C00 +#define NO_GDB_LIMIT 0x9007 + +#endif diff --git a/include/media/tc358743.h b/include/media/tc358743.h new file mode 100644 index 000000000000..4513f2f9cfbc --- /dev/null +++ b/include/media/tc358743.h @@ -0,0 +1,131 @@ +/* + * tc358743 - Toshiba HDMI to CSI-2 bridge + * + * Copyright 2015 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. + * + */ + +/* + * References (c = chapter, p = page): + * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60 + * REF_02 - Toshiba, TC358743XBG_HDMI-CSI_Tv11p_nm.xls + */ + +#ifndef _TC358743_ +#define _TC358743_ + +enum tc358743_ddc5v_delays { + DDC5V_DELAY_0_MS, + DDC5V_DELAY_50_MS, + DDC5V_DELAY_100_MS, + DDC5V_DELAY_200_MS, +}; + +enum tc358743_hdmi_detection_delay { + HDMI_MODE_DELAY_0_MS, + HDMI_MODE_DELAY_25_MS, + HDMI_MODE_DELAY_50_MS, + HDMI_MODE_DELAY_100_MS, +}; + +struct tc358743_platform_data { + /* System clock connected to REFCLK (pin H5) */ + u32 refclk_hz; /* 26 MHz, 27 MHz or 42 MHz */ + + /* DDC +5V debounce delay to avoid spurious interrupts when the cable + * is connected. + * Sets DDC5V_MODE in register DDC_CTL. + * Default: DDC5V_DELAY_0_MS + */ + enum tc358743_ddc5v_delays ddc5v_delay; + + bool enable_hdcp; + + /* + * The FIFO size is 512x32, so Toshiba recommend to set the default FIFO + * level to somewhere in the middle (e.g. 300), so it can cover speed + * mismatches in input and output ports. + */ + u16 fifo_level; + + /* Bps pr lane is (refclk_hz / pll_prd) * pll_fbd */ + u16 pll_prd; + u16 pll_fbd; + + /* CSI + * Calculate CSI parameters with REF_02 for the highest resolution your + * CSI interface can handle. The driver will adjust the number of CSI + * lanes in use according to the pixel clock. + * + * The values in brackets are calculated with REF_02 when the number of + * bps pr lane is 823.5 MHz, and can serve as a starting point. + */ + u32 lineinitcnt; /* (0x00001770) */ + u32 lptxtimecnt; /* (0x00000005) */ + u32 tclk_headercnt; /* (0x00001d04) */ + u32 tclk_trailcnt; /* (0x00000000) */ + u32 ths_headercnt; /* (0x00000505) */ + u32 twakeup; /* (0x00004650) */ + u32 tclk_postcnt; /* (0x00000000) */ + u32 ths_trailcnt; /* (0x00000004) */ + u32 hstxvregcnt; /* (0x00000005) */ + + /* DVI->HDMI detection delay to avoid unnecessary switching between DVI + * and HDMI mode. + * Sets HDMI_DET_V in register HDMI_DET. + * Default: HDMI_MODE_DELAY_0_MS + */ + enum tc358743_hdmi_detection_delay hdmi_detection_delay; + + /* Reset PHY automatically when TMDS clock goes from DC to AC. + * Sets PHY_AUTO_RST2 in register PHY_CTL2. + * Default: false + */ + bool hdmi_phy_auto_reset_tmds_detected; + + /* Reset PHY automatically when TMDS clock passes 21 MHz. + * Sets PHY_AUTO_RST3 in register PHY_CTL2. + * Default: false + */ + bool hdmi_phy_auto_reset_tmds_in_range; + + /* Reset PHY automatically when TMDS clock is detected. + * Sets PHY_AUTO_RST4 in register PHY_CTL2. + * Default: false + */ + bool hdmi_phy_auto_reset_tmds_valid; + + /* Reset HDMI PHY automatically when hsync period is out of range. + * Sets H_PI_RST in register HV_RST. + * Default: false + */ + bool hdmi_phy_auto_reset_hsync_out_of_range; + + /* Reset HDMI PHY automatically when vsync period is out of range. + * Sets V_PI_RST in register HV_RST. + * Default: false + */ + bool hdmi_phy_auto_reset_vsync_out_of_range; +}; + +/* custom controls */ +/* Audio sample rate in Hz */ +#define TC358743_CID_AUDIO_SAMPLING_RATE (V4L2_CID_USER_TC358743_BASE + 0) +/* Audio present status */ +#define TC358743_CID_AUDIO_PRESENT (V4L2_CID_USER_TC358743_BASE + 1) + +#endif diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 9f6e108ff4a0..d448c536b49d 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -174,6 +174,10 @@ enum v4l2_colorfx { * We reserve 16 controls for this driver. */ #define V4L2_CID_USER_ADV7180_BASE (V4L2_CID_USER_BASE + 0x1070) +/* The base for the tc358743 driver controls. + * We reserve 16 controls for this driver. */ +#define V4L2_CID_USER_TC358743_BASE (V4L2_CID_USER_BASE + 0x1080) + /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ -- cgit v1.3-6-gb490 From e31f8f00bfc081ec1881d92a2dd192aeddf1d9d7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 24 Jun 2015 11:28:31 -0300 Subject: [media] v4l: xilinx: missing error code We should set "ret" on this error path instead of returning success. Fixes: df3305156f98 ('[media] v4l: xilinx: Add Xilinx Video IP core') Signed-off-by: Dan Carpenter Acked-by: Hyun Kwon Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/xilinx/xilinx-dma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 98e50e446d57..e779c93cb015 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -699,8 +699,10 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, /* ... and the buffers queue... */ dma->alloc_ctx = vb2_dma_contig_init_ctx(dma->xdev->dev); - if (IS_ERR(dma->alloc_ctx)) + if (IS_ERR(dma->alloc_ctx)) { + ret = PTR_ERR(dma->alloc_ctx); goto error; + } /* Don't enable VB2_READ and VB2_WRITE, as using the read() and write() * V4L2 APIs would be inefficient. Testing on the command line with a -- cgit v1.3-6-gb490 From df5c3e7c8a87a4384ff7a0adba16baae9a40a566 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 19 Jun 2015 08:51:22 -0300 Subject: [media] v4l: vsp1: Fix plane stride and size checks The checks need to be performed on up to two planes, as the third plane, if present, must have the same stride and size as the second plane. The code incorrectly performs the checks on at least two planes instead of at most two planes, fix it. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 770e08dc03f1..3c124c14ce14 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -245,7 +245,7 @@ static int __vsp1_video_try_format(struct vsp1_video *video, * the datasheet, strides not aligned to a multiple of 128 bytes result * in image corruption. */ - for (i = 0; i < max(info->planes, 2U); ++i) { + for (i = 0; i < min(info->planes, 2U); ++i) { unsigned int hsub = i > 0 ? info->hsub : 1; unsigned int vsub = i > 0 ? info->vsub : 1; unsigned int align = 128; -- cgit v1.3-6-gb490 From adb8963f27e00273c912a53f28f7af5d14cfd32e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 13 Apr 2015 11:43:40 -0300 Subject: [media] v4l: vsp1: Don't sleep in atomic context The vsp1_entity_is_streaming() function is called in atomic context when queuing buffers, and sleeps due to a mutex. As the mutex just protects access to one structure field, fix this by replace the mutex with a spinlock. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_entity.c | 18 +++++++++--------- drivers/media/platform/vsp1/vsp1_entity.h | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index a453bb4ddd37..fd95a75b04f4 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -24,22 +24,24 @@ bool vsp1_entity_is_streaming(struct vsp1_entity *entity) { + unsigned long flags; bool streaming; - mutex_lock(&entity->lock); + spin_lock_irqsave(&entity->lock, flags); streaming = entity->streaming; - mutex_unlock(&entity->lock); + spin_unlock_irqrestore(&entity->lock, flags); return streaming; } int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming) { + unsigned long flags; int ret; - mutex_lock(&entity->lock); + spin_lock_irqsave(&entity->lock, flags); entity->streaming = streaming; - mutex_unlock(&entity->lock); + spin_unlock_irqrestore(&entity->lock, flags); if (!streaming) return 0; @@ -49,9 +51,9 @@ int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming) ret = v4l2_ctrl_handler_setup(entity->subdev.ctrl_handler); if (ret < 0) { - mutex_lock(&entity->lock); + spin_lock_irqsave(&entity->lock, flags); entity->streaming = false; - mutex_unlock(&entity->lock); + spin_unlock_irqrestore(&entity->lock, flags); } return ret; @@ -193,7 +195,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, if (i == ARRAY_SIZE(vsp1_routes)) return -EINVAL; - mutex_init(&entity->lock); + spin_lock_init(&entity->lock); entity->vsp1 = vsp1; entity->source_pad = num_pads - 1; @@ -228,6 +230,4 @@ void vsp1_entity_destroy(struct vsp1_entity *entity) if (entity->subdev.ctrl_handler) v4l2_ctrl_handler_free(entity->subdev.ctrl_handler); media_entity_cleanup(&entity->subdev.entity); - - mutex_destroy(&entity->lock); } diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index 62c768d1c6aa..8867a5787c28 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -14,7 +14,7 @@ #define __VSP1_ENTITY_H__ #include -#include +#include #include @@ -73,7 +73,7 @@ struct vsp1_entity { struct vsp1_video *video; - struct mutex lock; /* Protects the streaming field */ + spinlock_t lock; /* Protects the streaming field */ bool streaming; }; -- cgit v1.3-6-gb490 From cc81565307822a062820da294c17d9f3b6f49ecd Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 14 Jul 2015 16:53:21 +0800 Subject: crypto: nx - Convert ccm to new AEAD interface This patch converts the nx ccm and 4309 implementations to the new AEAD interface. Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-aes-ccm.c | 153 +++++++++++++++++++---------------------- drivers/crypto/nx/nx.c | 21 +++--- drivers/crypto/nx/nx.h | 6 +- 3 files changed, 85 insertions(+), 95 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c index e4311ce0cd78..195c9207a98d 100644 --- a/drivers/crypto/nx/nx-aes-ccm.c +++ b/drivers/crypto/nx/nx-aes-ccm.c @@ -94,8 +94,6 @@ static int ccm_aes_nx_setauthsize(struct crypto_aead *tfm, return -EINVAL; } - crypto_aead_crt(tfm)->authsize = authsize; - return 0; } @@ -111,8 +109,6 @@ static int ccm4309_aes_nx_setauthsize(struct crypto_aead *tfm, return -EINVAL; } - crypto_aead_crt(tfm)->authsize = authsize; - return 0; } @@ -174,6 +170,7 @@ static int generate_pat(u8 *iv, struct nx_crypto_ctx *nx_ctx, unsigned int authsize, unsigned int nbytes, + unsigned int assoclen, u8 *out) { struct nx_sg *nx_insg = nx_ctx->in_sg; @@ -200,16 +197,16 @@ static int generate_pat(u8 *iv, * greater than 2^32. */ - if (!req->assoclen) { + if (!assoclen) { b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0; - } else if (req->assoclen <= 14) { + } else if (assoclen <= 14) { /* if associated data is 14 bytes or less, we do 1 GCM * operation on 2 AES blocks, B0 (stored in the csbcpb) and B1, * which is fed in through the source buffers here */ b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0; b1 = nx_ctx->priv.ccm.iauth_tag; - iauth_len = req->assoclen; - } else if (req->assoclen <= 65280) { + iauth_len = assoclen; + } else if (assoclen <= 65280) { /* if associated data is less than (2^16 - 2^8), we construct * B1 differently and feed in the associated data to a CCA * operation */ @@ -223,7 +220,7 @@ static int generate_pat(u8 *iv, } /* generate B0 */ - rc = generate_b0(iv, req->assoclen, authsize, nbytes, b0); + rc = generate_b0(iv, assoclen, authsize, nbytes, b0); if (rc) return rc; @@ -233,22 +230,22 @@ static int generate_pat(u8 *iv, */ if (b1) { memset(b1, 0, 16); - if (req->assoclen <= 65280) { - *(u16 *)b1 = (u16)req->assoclen; - scatterwalk_map_and_copy(b1 + 2, req->assoc, 0, + if (assoclen <= 65280) { + *(u16 *)b1 = assoclen; + scatterwalk_map_and_copy(b1 + 2, req->src, 0, iauth_len, SCATTERWALK_FROM_SG); } else { *(u16 *)b1 = (u16)(0xfffe); - *(u32 *)&b1[2] = (u32)req->assoclen; - scatterwalk_map_and_copy(b1 + 6, req->assoc, 0, + *(u32 *)&b1[2] = assoclen; + scatterwalk_map_and_copy(b1 + 6, req->src, 0, iauth_len, SCATTERWALK_FROM_SG); } } /* now copy any remaining AAD to scatterlist and call nx... */ - if (!req->assoclen) { + if (!assoclen) { return rc; - } else if (req->assoclen <= 14) { + } else if (assoclen <= 14) { unsigned int len = 16; nx_insg = nx_build_sg_list(nx_insg, b1, &len, nx_ctx->ap->sglen); @@ -280,7 +277,7 @@ static int generate_pat(u8 *iv, return rc; atomic_inc(&(nx_ctx->stats->aes_ops)); - atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes)); + atomic64_add(assoclen, &nx_ctx->stats->aes_bytes); } else { unsigned int processed = 0, to_process; @@ -294,15 +291,15 @@ static int generate_pat(u8 *iv, nx_ctx->ap->databytelen/NX_PAGE_SIZE); do { - to_process = min_t(u32, req->assoclen - processed, + to_process = min_t(u32, assoclen - processed, nx_ctx->ap->databytelen); nx_insg = nx_walk_and_build(nx_ctx->in_sg, nx_ctx->ap->sglen, - req->assoc, processed, + req->src, processed, &to_process); - if ((to_process + processed) < req->assoclen) { + if ((to_process + processed) < assoclen) { NX_CPB_FDM(nx_ctx->csbcpb_aead) |= NX_FDM_INTERMEDIATE; } else { @@ -328,11 +325,10 @@ static int generate_pat(u8 *iv, NX_CPB_FDM(nx_ctx->csbcpb_aead) |= NX_FDM_CONTINUATION; atomic_inc(&(nx_ctx->stats->aes_ops)); - atomic64_add(req->assoclen, - &(nx_ctx->stats->aes_bytes)); + atomic64_add(assoclen, &nx_ctx->stats->aes_bytes); processed += to_process; - } while (processed < req->assoclen); + } while (processed < assoclen); result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0; } @@ -343,7 +339,8 @@ static int generate_pat(u8 *iv, } static int ccm_nx_decrypt(struct aead_request *req, - struct blkcipher_desc *desc) + struct blkcipher_desc *desc, + unsigned int assoclen) { struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; @@ -360,10 +357,10 @@ static int ccm_nx_decrypt(struct aead_request *req, /* copy out the auth tag to compare with later */ scatterwalk_map_and_copy(priv->oauth_tag, - req->src, nbytes, authsize, + req->src, nbytes + req->assoclen, authsize, SCATTERWALK_FROM_SG); - rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes, + rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes, assoclen, csbcpb->cpb.aes_ccm.in_pat_or_b0); if (rc) goto out; @@ -383,8 +380,8 @@ static int ccm_nx_decrypt(struct aead_request *req, NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT; rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, - &to_process, processed, - csbcpb->cpb.aes_ccm.iv_or_ctr); + &to_process, processed + req->assoclen, + csbcpb->cpb.aes_ccm.iv_or_ctr); if (rc) goto out; @@ -420,7 +417,8 @@ out: } static int ccm_nx_encrypt(struct aead_request *req, - struct blkcipher_desc *desc) + struct blkcipher_desc *desc, + unsigned int assoclen) { struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm); struct nx_csbcpb *csbcpb = nx_ctx->csbcpb; @@ -432,7 +430,7 @@ static int ccm_nx_encrypt(struct aead_request *req, spin_lock_irqsave(&nx_ctx->lock, irq_flags); - rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes, + rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes, assoclen, csbcpb->cpb.aes_ccm.in_pat_or_b0); if (rc) goto out; @@ -451,7 +449,7 @@ static int ccm_nx_encrypt(struct aead_request *req, NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT; rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, - &to_process, processed, + &to_process, processed + req->assoclen, csbcpb->cpb.aes_ccm.iv_or_ctr); if (rc) goto out; @@ -483,7 +481,7 @@ static int ccm_nx_encrypt(struct aead_request *req, /* copy out the auth tag */ scatterwalk_map_and_copy(csbcpb->cpb.aes_ccm.out_pat_or_mac, - req->dst, nbytes, authsize, + req->dst, nbytes + req->assoclen, authsize, SCATTERWALK_TO_SG); out: @@ -503,9 +501,8 @@ static int ccm4309_aes_nx_encrypt(struct aead_request *req) memcpy(iv + 4, req->iv, 8); desc.info = iv; - desc.tfm = (struct crypto_blkcipher *)req->base.tfm; - return ccm_nx_encrypt(req, &desc); + return ccm_nx_encrypt(req, &desc, req->assoclen - 8); } static int ccm_aes_nx_encrypt(struct aead_request *req) @@ -514,13 +511,12 @@ static int ccm_aes_nx_encrypt(struct aead_request *req) int rc; desc.info = req->iv; - desc.tfm = (struct crypto_blkcipher *)req->base.tfm; rc = crypto_ccm_check_iv(desc.info); if (rc) return rc; - return ccm_nx_encrypt(req, &desc); + return ccm_nx_encrypt(req, &desc, req->assoclen); } static int ccm4309_aes_nx_decrypt(struct aead_request *req) @@ -535,9 +531,8 @@ static int ccm4309_aes_nx_decrypt(struct aead_request *req) memcpy(iv + 4, req->iv, 8); desc.info = iv; - desc.tfm = (struct crypto_blkcipher *)req->base.tfm; - return ccm_nx_decrypt(req, &desc); + return ccm_nx_decrypt(req, &desc, req->assoclen - 8); } static int ccm_aes_nx_decrypt(struct aead_request *req) @@ -546,13 +541,12 @@ static int ccm_aes_nx_decrypt(struct aead_request *req) int rc; desc.info = req->iv; - desc.tfm = (struct crypto_blkcipher *)req->base.tfm; rc = crypto_ccm_check_iv(desc.info); if (rc) return rc; - return ccm_nx_decrypt(req, &desc); + return ccm_nx_decrypt(req, &desc, req->assoclen); } /* tell the block cipher walk routines that this is a stream cipher by @@ -560,47 +554,44 @@ static int ccm_aes_nx_decrypt(struct aead_request *req) * during encrypt/decrypt doesn't solve this problem, because it calls * blkcipher_walk_done under the covers, which doesn't use walk->blocksize, * but instead uses this tfm->blocksize. */ -struct crypto_alg nx_ccm_aes_alg = { - .cra_name = "ccm(aes)", - .cra_driver_name = "ccm-aes-nx", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct nx_crypto_ctx), - .cra_type = &crypto_aead_type, - .cra_module = THIS_MODULE, - .cra_init = nx_crypto_ctx_aes_ccm_init, - .cra_exit = nx_crypto_ctx_exit, - .cra_aead = { - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = AES_BLOCK_SIZE, - .setkey = ccm_aes_nx_set_key, - .setauthsize = ccm_aes_nx_setauthsize, - .encrypt = ccm_aes_nx_encrypt, - .decrypt = ccm_aes_nx_decrypt, - } +struct aead_alg nx_ccm_aes_alg = { + .base = { + .cra_name = "ccm(aes)", + .cra_driver_name = "ccm-aes-nx", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_AEAD_NEW, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct nx_crypto_ctx), + .cra_module = THIS_MODULE, + }, + .init = nx_crypto_ctx_aes_ccm_init, + .exit = nx_crypto_ctx_aead_exit, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = AES_BLOCK_SIZE, + .setkey = ccm_aes_nx_set_key, + .setauthsize = ccm_aes_nx_setauthsize, + .encrypt = ccm_aes_nx_encrypt, + .decrypt = ccm_aes_nx_decrypt, }; -struct crypto_alg nx_ccm4309_aes_alg = { - .cra_name = "rfc4309(ccm(aes))", - .cra_driver_name = "rfc4309-ccm-aes-nx", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct nx_crypto_ctx), - .cra_type = &crypto_nivaead_type, - .cra_module = THIS_MODULE, - .cra_init = nx_crypto_ctx_aes_ccm_init, - .cra_exit = nx_crypto_ctx_exit, - .cra_aead = { - .ivsize = 8, - .maxauthsize = AES_BLOCK_SIZE, - .setkey = ccm4309_aes_nx_set_key, - .setauthsize = ccm4309_aes_nx_setauthsize, - .encrypt = ccm4309_aes_nx_encrypt, - .decrypt = ccm4309_aes_nx_decrypt, - .geniv = "seqiv", - } +struct aead_alg nx_ccm4309_aes_alg = { + .base = { + .cra_name = "rfc4309(ccm(aes))", + .cra_driver_name = "rfc4309-ccm-aes-nx", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_AEAD_NEW, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct nx_crypto_ctx), + .cra_module = THIS_MODULE, + }, + .init = nx_crypto_ctx_aes_ccm_init, + .exit = nx_crypto_ctx_aead_exit, + .ivsize = 8, + .maxauthsize = AES_BLOCK_SIZE, + .setkey = ccm4309_aes_nx_set_key, + .setauthsize = ccm4309_aes_nx_setauthsize, + .encrypt = ccm4309_aes_nx_encrypt, + .decrypt = ccm4309_aes_nx_decrypt, }; diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index 436971343ff7..9a5e643af5bc 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -612,11 +612,11 @@ static int nx_register_algs(void) if (rc) goto out_unreg_gcm; - rc = nx_register_alg(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); + rc = nx_register_aead(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); if (rc) goto out_unreg_gcm4106; - rc = nx_register_alg(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); + rc = nx_register_aead(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); if (rc) goto out_unreg_ccm; @@ -644,9 +644,9 @@ out_unreg_s256: nx_unregister_shash(&nx_shash_sha256_alg, NX_FC_SHA, NX_MODE_SHA, NX_PROPS_SHA256); out_unreg_ccm4309: - nx_unregister_alg(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); + nx_unregister_aead(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); out_unreg_ccm: - nx_unregister_alg(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); + nx_unregister_aead(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); out_unreg_gcm4106: nx_unregister_aead(&nx_gcm4106_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); out_unreg_gcm: @@ -711,11 +711,10 @@ static int nx_crypto_ctx_init(struct nx_crypto_ctx *nx_ctx, u32 fc, u32 mode) } /* entry points from the crypto tfm initializers */ -int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm) +int nx_crypto_ctx_aes_ccm_init(struct crypto_aead *tfm) { - crypto_aead_set_reqsize(__crypto_aead_cast(tfm), - sizeof(struct nx_ccm_rctx)); - return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES, + crypto_aead_set_reqsize(tfm, sizeof(struct nx_ccm_rctx)); + return nx_crypto_ctx_init(crypto_aead_ctx(tfm), NX_FC_AES, NX_MODE_AES_CCM); } @@ -813,9 +812,9 @@ static int nx_remove(struct vio_dev *viodev) NX_FC_SHA, NX_MODE_SHA, NX_PROPS_SHA256); nx_unregister_shash(&nx_shash_sha256_alg, NX_FC_SHA, NX_MODE_SHA, NX_PROPS_SHA512); - nx_unregister_alg(&nx_ccm4309_aes_alg, - NX_FC_AES, NX_MODE_AES_CCM); - nx_unregister_alg(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); + nx_unregister_aead(&nx_ccm4309_aes_alg, + NX_FC_AES, NX_MODE_AES_CCM); + nx_unregister_aead(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); nx_unregister_aead(&nx_gcm4106_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); nx_unregister_aead(&nx_gcm_aes_alg, diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h index cdff03a42ae7..8a4d1fd752d6 100644 --- a/drivers/crypto/nx/nx.h +++ b/drivers/crypto/nx/nx.h @@ -150,7 +150,7 @@ struct nx_crypto_ctx { }; /* prototypes */ -int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm); +int nx_crypto_ctx_aes_ccm_init(struct crypto_aead *tfm); int nx_crypto_ctx_aes_gcm_init(struct crypto_aead *tfm); int nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm); int nx_crypto_ctx_aes_ctr_init(struct crypto_tfm *tfm); @@ -189,8 +189,8 @@ extern struct aead_alg nx_gcm_aes_alg; extern struct aead_alg nx_gcm4106_aes_alg; extern struct crypto_alg nx_ctr_aes_alg; extern struct crypto_alg nx_ctr3686_aes_alg; -extern struct crypto_alg nx_ccm_aes_alg; -extern struct crypto_alg nx_ccm4309_aes_alg; +extern struct aead_alg nx_ccm_aes_alg; +extern struct aead_alg nx_ccm4309_aes_alg; extern struct shash_alg nx_shash_aes_xcbc_alg; extern struct shash_alg nx_shash_sha512_alg; extern struct shash_alg nx_shash_sha256_alg; -- cgit v1.3-6-gb490 From f3dd7e60d2028b8391dea7a3b214e3083dadf6d6 Mon Sep 17 00:00:00 2001 From: Pingchao Yang Date: Wed, 15 Jul 2015 15:28:26 -0700 Subject: crypto: qat - add support for MMP FW Load Modular Math Processor(MMP) firmware into QAT devices to support public key algorithm acceleration. Signed-off-by: Pingchao Yang Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_accel_devices.h | 1 + drivers/crypto/qat/qat_common/adf_common_drv.h | 2 ++ drivers/crypto/qat/qat_common/qat_hal.c | 13 +++++++---- drivers/crypto/qat/qat_common/qat_uclo.c | 27 +++++----------------- .../crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c | 6 +++++ .../crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h | 1 + 6 files changed, 24 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index 5fe902967620..91c969eb6e6b 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -135,6 +135,7 @@ struct adf_hw_device_data { struct adf_hw_device_class *dev_class; uint32_t (*get_accel_mask)(uint32_t fuse); uint32_t (*get_ae_mask)(uint32_t fuse); + uint32_t (*get_sram_bar_id)(struct adf_hw_device_data *self); uint32_t (*get_misc_bar_id)(struct adf_hw_device_data *self); uint32_t (*get_etr_bar_id)(struct adf_hw_device_data *self); uint32_t (*get_num_aes)(struct adf_hw_device_data *self); diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index 27e16c09230b..1e82ad4bf43d 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -196,4 +196,6 @@ int qat_uclo_wr_all_uimage(struct icp_qat_fw_loader_handle *handle); void qat_uclo_del_uof_obj(struct icp_qat_fw_loader_handle *handle); int qat_uclo_map_uof_obj(struct icp_qat_fw_loader_handle *handle, void *addr_ptr, int mem_size); +void qat_uclo_wr_mimage(struct icp_qat_fw_loader_handle *handle, + void *addr_ptr, int mem_size); #endif diff --git a/drivers/crypto/qat/qat_common/qat_hal.c b/drivers/crypto/qat/qat_common/qat_hal.c index 274ff7e9de6e..1d6d28916590 100644 --- a/drivers/crypto/qat/qat_common/qat_hal.c +++ b/drivers/crypto/qat/qat_common/qat_hal.c @@ -679,21 +679,24 @@ int qat_hal_init(struct adf_accel_dev *accel_dev) struct icp_qat_fw_loader_handle *handle; struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; struct adf_hw_device_data *hw_data = accel_dev->hw_device; - struct adf_bar *bar = + struct adf_bar *misc_bar = &pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)]; + struct adf_bar *sram_bar = + &pci_info->pci_bars[hw_data->get_sram_bar_id(hw_data)]; handle = kzalloc(sizeof(*handle), GFP_KERNEL); if (!handle) return -ENOMEM; - handle->hal_cap_g_ctl_csr_addr_v = bar->virt_addr + + handle->hal_cap_g_ctl_csr_addr_v = misc_bar->virt_addr + ICP_DH895XCC_CAP_OFFSET; - handle->hal_cap_ae_xfer_csr_addr_v = bar->virt_addr + + handle->hal_cap_ae_xfer_csr_addr_v = misc_bar->virt_addr + ICP_DH895XCC_AE_OFFSET; - handle->hal_ep_csr_addr_v = bar->virt_addr + ICP_DH895XCC_EP_OFFSET; + handle->hal_ep_csr_addr_v = misc_bar->virt_addr + + ICP_DH895XCC_EP_OFFSET; handle->hal_cap_ae_local_csr_addr_v = handle->hal_cap_ae_xfer_csr_addr_v + LOCAL_TO_XFER_REG_OFFSET; - + handle->hal_sram_addr_v = sram_bar->virt_addr; handle->hal_handle = kzalloc(sizeof(*handle->hal_handle), GFP_KERNEL); if (!handle->hal_handle) goto out_hal_handle; diff --git a/drivers/crypto/qat/qat_common/qat_uclo.c b/drivers/crypto/qat/qat_common/qat_uclo.c index 1e27f9f7fddf..c48f181e8941 100644 --- a/drivers/crypto/qat/qat_common/qat_uclo.c +++ b/drivers/crypto/qat/qat_common/qat_uclo.c @@ -359,28 +359,7 @@ static int qat_uclo_init_umem_seg(struct icp_qat_fw_loader_handle *handle, static int qat_uclo_init_ae_memory(struct icp_qat_fw_loader_handle *handle, struct icp_qat_uof_initmem *init_mem) { - unsigned int i; - struct icp_qat_uof_memvar_attr *mem_val_attr; - - mem_val_attr = - (struct icp_qat_uof_memvar_attr *)((unsigned long)init_mem + - sizeof(struct icp_qat_uof_initmem)); - switch (init_mem->region) { - case ICP_QAT_UOF_SRAM_REGION: - if ((init_mem->addr + init_mem->num_in_bytes) > - ICP_DH895XCC_PESRAM_BAR_SIZE) { - pr_err("QAT: initmem on SRAM is out of range"); - return -EINVAL; - } - for (i = 0; i < init_mem->val_attr_num; i++) { - qat_uclo_wr_sram_by_words(handle, - init_mem->addr + - mem_val_attr->offset_in_byte, - &mem_val_attr->value, 4); - mem_val_attr++; - } - break; case ICP_QAT_UOF_LMEM_REGION: if (qat_uclo_init_lmem_seg(handle, init_mem)) return -EINVAL; @@ -990,6 +969,12 @@ out_err: return -EFAULT; } +void qat_uclo_wr_mimage(struct icp_qat_fw_loader_handle *handle, + void *addr_ptr, int mem_size) +{ + qat_uclo_wr_sram_by_words(handle, 0, addr_ptr, ALIGN(mem_size, 4)); +} + int qat_uclo_map_uof_obj(struct icp_qat_fw_loader_handle *handle, void *addr_ptr, int mem_size) { diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c index b1386922d7a2..7093fc0fe8da 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -117,6 +117,11 @@ static uint32_t get_etr_bar_id(struct adf_hw_device_data *self) return ADF_DH895XCC_ETR_BAR; } +static uint32_t get_sram_bar_id(struct adf_hw_device_data *self) +{ + return ADF_DH895XCC_SRAM_BAR; +} + static enum dev_sku_info get_sku(struct adf_hw_device_data *self) { int sku = (self->fuses & ADF_DH895XCC_FUSECTL_SKU_MASK) @@ -219,6 +224,7 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) hw_data->get_num_aes = get_num_aes; hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; + hw_data->get_sram_bar_id = get_sram_bar_id; hw_data->get_sku = get_sku; hw_data->fw_name = ADF_DH895XCC_FW; hw_data->init_admin_comms = adf_init_admin_comms; diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h index 25269a9f24a2..87fb1fadb4b2 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h @@ -48,6 +48,7 @@ #define ADF_DH895x_HW_DATA_H_ /* PCIe configuration space */ +#define ADF_DH895XCC_SRAM_BAR 0 #define ADF_DH895XCC_PMISC_BAR 1 #define ADF_DH895XCC_ETR_BAR 2 #define ADF_DH895XCC_RX_RINGS_OFFSET 8 -- cgit v1.3-6-gb490 From 28cfaf67e5c1f5b6b0d549eea398f8401a40e566 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Wed, 15 Jul 2015 15:28:32 -0700 Subject: crypto: qat - add MMP FW support to accel engine Add code that loads the MMP firmware Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_accel_devices.h | 2 ++ drivers/crypto/qat/qat_common/adf_accel_engine.c | 42 +++++++++++++++++++--- .../crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c | 1 + .../crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h | 2 ++ 4 files changed, 42 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index 91c969eb6e6b..45db8d53a9d3 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -152,6 +152,7 @@ struct adf_hw_device_data { void (*exit_arb)(struct adf_accel_dev *accel_dev); void (*enable_ints)(struct adf_accel_dev *accel_dev); const char *fw_name; + const char *fw_mmp_name; uint32_t pci_dev_id; uint32_t fuses; uint32_t accel_capabilities_mask; @@ -185,6 +186,7 @@ struct icp_qat_fw_loader_handle; struct adf_fw_loader_data { struct icp_qat_fw_loader_handle *fw_loader; const struct firmware *uof_fw; + const struct firmware *mmp_fw; }; struct adf_accel_dev { diff --git a/drivers/crypto/qat/qat_common/adf_accel_engine.c b/drivers/crypto/qat/qat_common/adf_accel_engine.c index fdda8e7ae302..20b08bdcb146 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_engine.c +++ b/drivers/crypto/qat/qat_common/adf_accel_engine.c @@ -55,24 +55,36 @@ int adf_ae_fw_load(struct adf_accel_dev *accel_dev) { struct adf_fw_loader_data *loader_data = accel_dev->fw_loader; struct adf_hw_device_data *hw_device = accel_dev->hw_device; - void *uof_addr; - uint32_t uof_size; + void *uof_addr, *mmp_addr; + u32 uof_size, mmp_size; + if (!hw_device->fw_name) + return 0; + + if (request_firmware(&loader_data->mmp_fw, hw_device->fw_mmp_name, + &accel_dev->accel_pci_dev.pci_dev->dev)) { + dev_err(&GET_DEV(accel_dev), "Failed to load MMP firmware %s\n", + hw_device->fw_mmp_name); + return -EFAULT; + } if (request_firmware(&loader_data->uof_fw, hw_device->fw_name, &accel_dev->accel_pci_dev.pci_dev->dev)) { - dev_err(&GET_DEV(accel_dev), "Failed to load firmware %s\n", + dev_err(&GET_DEV(accel_dev), "Failed to load UOF firmware %s\n", hw_device->fw_name); - return -EFAULT; + goto out_err; } uof_size = loader_data->uof_fw->size; uof_addr = (void *)loader_data->uof_fw->data; + mmp_size = loader_data->mmp_fw->size; + mmp_addr = (void *)loader_data->mmp_fw->data; + qat_uclo_wr_mimage(loader_data->fw_loader, mmp_addr, mmp_size); if (qat_uclo_map_uof_obj(loader_data->fw_loader, uof_addr, uof_size)) { dev_err(&GET_DEV(accel_dev), "Failed to map UOF\n"); goto out_err; } if (qat_uclo_wr_all_uimage(loader_data->fw_loader)) { - dev_err(&GET_DEV(accel_dev), "Failed to map UOF\n"); + dev_err(&GET_DEV(accel_dev), "Failed to load UOF\n"); goto out_err; } return 0; @@ -85,11 +97,17 @@ out_err: void adf_ae_fw_release(struct adf_accel_dev *accel_dev) { struct adf_fw_loader_data *loader_data = accel_dev->fw_loader; + struct adf_hw_device_data *hw_device = accel_dev->hw_device; + + if (!hw_device->fw_name) + return; qat_uclo_del_uof_obj(loader_data->fw_loader); qat_hal_deinit(loader_data->fw_loader); release_firmware(loader_data->uof_fw); + release_firmware(loader_data->mmp_fw); loader_data->uof_fw = NULL; + loader_data->mmp_fw = NULL; loader_data->fw_loader = NULL; } @@ -99,6 +117,9 @@ int adf_ae_start(struct adf_accel_dev *accel_dev) struct adf_hw_device_data *hw_data = accel_dev->hw_device; uint32_t ae_ctr, ae, max_aes = GET_MAX_ACCELENGINES(accel_dev); + if (!hw_data->fw_name) + return 0; + for (ae = 0, ae_ctr = 0; ae < max_aes; ae++) { if (hw_data->ae_mask & (1 << ae)) { qat_hal_start(loader_data->fw_loader, ae, 0xFF); @@ -117,6 +138,9 @@ int adf_ae_stop(struct adf_accel_dev *accel_dev) struct adf_hw_device_data *hw_data = accel_dev->hw_device; uint32_t ae_ctr, ae, max_aes = GET_MAX_ACCELENGINES(accel_dev); + if (!hw_data->fw_name) + return 0; + for (ae = 0, ae_ctr = 0; ae < max_aes; ae++) { if (hw_data->ae_mask & (1 << ae)) { qat_hal_stop(loader_data->fw_loader, ae, 0xFF); @@ -143,6 +167,10 @@ static int adf_ae_reset(struct adf_accel_dev *accel_dev, int ae) int adf_ae_init(struct adf_accel_dev *accel_dev) { struct adf_fw_loader_data *loader_data; + struct adf_hw_device_data *hw_device = accel_dev->hw_device; + + if (!hw_device->fw_name) + return 0; loader_data = kzalloc(sizeof(*loader_data), GFP_KERNEL); if (!loader_data) @@ -166,6 +194,10 @@ int adf_ae_init(struct adf_accel_dev *accel_dev) int adf_ae_shutdown(struct adf_accel_dev *accel_dev) { struct adf_fw_loader_data *loader_data = accel_dev->fw_loader; + struct adf_hw_device_data *hw_device = accel_dev->hw_device; + + if (!hw_device->fw_name) + return 0; qat_hal_deinit(loader_data->fw_loader); kfree(accel_dev->fw_loader); diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c index 7093fc0fe8da..eb2f408d4302 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -227,6 +227,7 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) hw_data->get_sram_bar_id = get_sram_bar_id; hw_data->get_sku = get_sku; hw_data->fw_name = ADF_DH895XCC_FW; + hw_data->fw_mmp_name = ADF_DH895XCC_MMP; hw_data->init_admin_comms = adf_init_admin_comms; hw_data->exit_admin_comms = adf_exit_admin_comms; hw_data->init_arb = adf_init_arb; diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h index 87fb1fadb4b2..a4963a9b687b 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h @@ -85,5 +85,7 @@ #define ADF_DH895XCC_ADMINMSGLR_OFFSET (0x3A000 + 0x578) #define ADF_DH895XCC_MAILBOX_BASE_OFFSET 0x20970 #define ADF_DH895XCC_MAILBOX_STRIDE 0x1000 +/* FW names */ #define ADF_DH895XCC_FW "qat_895xcc.bin" +#define ADF_DH895XCC_MMP "qat_mmp.bin" #endif -- cgit v1.3-6-gb490 From a990532023b903b10cf14736241cdd138e4bc92c Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Wed, 15 Jul 2015 15:28:38 -0700 Subject: crypto: qat - Add support for RSA algorithm Add RSA support to QAT driver. Removed unused RNG rings. Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/Kconfig | 2 + drivers/crypto/qat/qat_common/.gitignore | 1 + drivers/crypto/qat/qat_common/Makefile | 5 + drivers/crypto/qat/qat_common/adf_common_drv.h | 10 +- drivers/crypto/qat/qat_common/adf_init.c | 4 +- drivers/crypto/qat/qat_common/icp_qat_fw.h | 2 + drivers/crypto/qat/qat_common/icp_qat_fw_pke.h | 112 +++++ drivers/crypto/qat/qat_common/qat_algs.c | 5 - drivers/crypto/qat/qat_common/qat_asym_algs.c | 639 +++++++++++++++++++++++++ drivers/crypto/qat/qat_common/qat_crypto.c | 19 +- drivers/crypto/qat/qat_common/qat_crypto.h | 2 - drivers/crypto/qat/qat_common/qat_rsakey.asn1 | 5 + drivers/crypto/qat/qat_dh895xcc/adf_drv.c | 12 - 13 files changed, 779 insertions(+), 39 deletions(-) create mode 100644 drivers/crypto/qat/qat_common/.gitignore create mode 100644 drivers/crypto/qat/qat_common/icp_qat_fw_pke.h create mode 100644 drivers/crypto/qat/qat_common/qat_asym_algs.c create mode 100644 drivers/crypto/qat/qat_common/qat_rsakey.asn1 (limited to 'drivers') diff --git a/drivers/crypto/qat/Kconfig b/drivers/crypto/qat/Kconfig index 6fdb9e8b22a7..d8c3d595d98b 100644 --- a/drivers/crypto/qat/Kconfig +++ b/drivers/crypto/qat/Kconfig @@ -3,11 +3,13 @@ config CRYPTO_DEV_QAT select CRYPTO_AEAD select CRYPTO_AUTHENC select CRYPTO_BLKCIPHER + select CRYPTO_AKCIPHER select CRYPTO_HMAC select CRYPTO_SHA1 select CRYPTO_SHA256 select CRYPTO_SHA512 select FW_LOADER + select ASN1 config CRYPTO_DEV_QAT_DH895xCC tristate "Support for Intel(R) DH895xCC" diff --git a/drivers/crypto/qat/qat_common/.gitignore b/drivers/crypto/qat/qat_common/.gitignore new file mode 100644 index 000000000000..ee328374dba8 --- /dev/null +++ b/drivers/crypto/qat/qat_common/.gitignore @@ -0,0 +1 @@ +*-asn1.[ch] diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile index e0424dc382fe..184605f76bea 100644 --- a/drivers/crypto/qat/qat_common/Makefile +++ b/drivers/crypto/qat/qat_common/Makefile @@ -1,3 +1,6 @@ +$(obj)/qat_rsakey-asn1.o: $(obj)/qat_rsakey-asn1.c $(obj)/qat_rsakey-asn1.h +clean-files += qat_rsakey-asn1.c qat_rsakey-asn1.h + obj-$(CONFIG_CRYPTO_DEV_QAT) += intel_qat.o intel_qat-objs := adf_cfg.o \ adf_ctl_drv.o \ @@ -8,6 +11,8 @@ intel_qat-objs := adf_cfg.o \ adf_transport.o \ qat_crypto.o \ qat_algs.o \ + qat_rsakey-asn1.o \ + qat_asym_algs.o \ qat_uclo.o \ qat_hal.o diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index 1e82ad4bf43d..3c33feefee67 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -55,7 +55,7 @@ #define ADF_MAJOR_VERSION 0 #define ADF_MINOR_VERSION 1 -#define ADF_BUILD_VERSION 3 +#define ADF_BUILD_VERSION 4 #define ADF_DRV_VERSION __stringify(ADF_MAJOR_VERSION) "." \ __stringify(ADF_MINOR_VERSION) "." \ __stringify(ADF_BUILD_VERSION) @@ -94,6 +94,11 @@ struct service_hndl { int admin; }; +static inline int get_current_node(void) +{ + return cpu_data(current_thread_info()->cpu).phys_proc_id; +} + int adf_service_register(struct service_hndl *service); int adf_service_unregister(struct service_hndl *service); @@ -141,10 +146,13 @@ int qat_crypto_unregister(void); struct qat_crypto_instance *qat_crypto_get_instance_node(int node); void qat_crypto_put_instance(struct qat_crypto_instance *inst); void qat_alg_callback(void *resp); +void qat_alg_asym_callback(void *resp); int qat_algs_init(void); void qat_algs_exit(void); int qat_algs_register(void); int qat_algs_unregister(void); +int qat_asym_algs_register(void); +void qat_asym_algs_unregister(void); int qat_hal_init(struct adf_accel_dev *accel_dev); void qat_hal_deinit(struct icp_qat_fw_loader_handle *handle); diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c index 245f43237a2d..7f9dffad7931 100644 --- a/drivers/crypto/qat/qat_common/adf_init.c +++ b/drivers/crypto/qat/qat_common/adf_init.c @@ -257,7 +257,7 @@ int adf_dev_start(struct adf_accel_dev *accel_dev) clear_bit(ADF_STATUS_STARTING, &accel_dev->status); set_bit(ADF_STATUS_STARTED, &accel_dev->status); - if (qat_algs_register()) { + if (qat_algs_register() || qat_asym_algs_register()) { dev_err(&GET_DEV(accel_dev), "Failed to register crypto algs\n"); set_bit(ADF_STATUS_STARTING, &accel_dev->status); @@ -296,6 +296,8 @@ int adf_dev_stop(struct adf_accel_dev *accel_dev) dev_err(&GET_DEV(accel_dev), "Failed to unregister crypto algs\n"); + qat_asym_algs_unregister(); + list_for_each(list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list); if (service->admin) diff --git a/drivers/crypto/qat/qat_common/icp_qat_fw.h b/drivers/crypto/qat/qat_common/icp_qat_fw.h index f1e30e24a419..46747f01b1d1 100644 --- a/drivers/crypto/qat/qat_common/icp_qat_fw.h +++ b/drivers/crypto/qat/qat_common/icp_qat_fw.h @@ -249,6 +249,8 @@ struct icp_qat_fw_comn_resp { #define QAT_COMN_RESP_CRYPTO_STATUS_BITPOS 7 #define QAT_COMN_RESP_CRYPTO_STATUS_MASK 0x1 +#define QAT_COMN_RESP_PKE_STATUS_BITPOS 6 +#define QAT_COMN_RESP_PKE_STATUS_MASK 0x1 #define QAT_COMN_RESP_CMP_STATUS_BITPOS 5 #define QAT_COMN_RESP_CMP_STATUS_MASK 0x1 #define QAT_COMN_RESP_XLAT_STATUS_BITPOS 4 diff --git a/drivers/crypto/qat/qat_common/icp_qat_fw_pke.h b/drivers/crypto/qat/qat_common/icp_qat_fw_pke.h new file mode 100644 index 000000000000..0d7a9b51ce9f --- /dev/null +++ b/drivers/crypto/qat/qat_common/icp_qat_fw_pke.h @@ -0,0 +1,112 @@ +/* + 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. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2014 Intel Corporation. + 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 of 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 _ICP_QAT_FW_PKE_ +#define _ICP_QAT_FW_PKE_ + +#include "icp_qat_fw.h" + +struct icp_qat_fw_req_hdr_pke_cd_pars { + u64 content_desc_addr; + u32 content_desc_resrvd; + u32 func_id; +}; + +struct icp_qat_fw_req_pke_mid { + u64 opaque; + u64 src_data_addr; + u64 dest_data_addr; +}; + +struct icp_qat_fw_req_pke_hdr { + u8 resrvd1; + u8 resrvd2; + u8 service_type; + u8 hdr_flags; + u16 comn_req_flags; + u16 resrvd4; + struct icp_qat_fw_req_hdr_pke_cd_pars cd_pars; +}; + +struct icp_qat_fw_pke_request { + struct icp_qat_fw_req_pke_hdr pke_hdr; + struct icp_qat_fw_req_pke_mid pke_mid; + u8 output_param_count; + u8 input_param_count; + u16 resrvd1; + u32 resrvd2; + u64 next_req_adr; +}; + +struct icp_qat_fw_resp_pke_hdr { + u8 resrvd1; + u8 resrvd2; + u8 response_type; + u8 hdr_flags; + u16 comn_resp_flags; + u16 resrvd4; +}; + +struct icp_qat_fw_pke_resp { + struct icp_qat_fw_resp_pke_hdr pke_resp_hdr; + u64 opaque; + u64 src_data_addr; + u64 dest_data_addr; +}; + +#define ICP_QAT_FW_PKE_HDR_VALID_FLAG_BITPOS 7 +#define ICP_QAT_FW_PKE_HDR_VALID_FLAG_MASK 0x1 +#define ICP_QAT_FW_PKE_RESP_PKE_STAT_GET(status_word) \ + QAT_FIELD_GET(((status_word >> ICP_QAT_FW_COMN_ONE_BYTE_SHIFT) & \ + ICP_QAT_FW_COMN_SINGLE_BYTE_MASK), \ + QAT_COMN_RESP_PKE_STATUS_BITPOS, \ + QAT_COMN_RESP_PKE_STATUS_MASK) + +#define ICP_QAT_FW_PKE_HDR_VALID_FLAG_SET(hdr_t, val) \ + QAT_FIELD_SET((hdr_t.hdr_flags), (val), \ + ICP_QAT_FW_PKE_HDR_VALID_FLAG_BITPOS, \ + ICP_QAT_FW_PKE_HDR_VALID_FLAG_MASK) +#endif diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c index 067402c7c2a9..31abfd07379a 100644 --- a/drivers/crypto/qat/qat_common/qat_algs.c +++ b/drivers/crypto/qat/qat_common/qat_algs.c @@ -129,11 +129,6 @@ struct qat_alg_ablkcipher_ctx { spinlock_t lock; /* protects qat_alg_ablkcipher_ctx struct */ }; -static int get_current_node(void) -{ - return cpu_data(current_thread_info()->cpu).phys_proc_id; -} - static int qat_get_inter_state_size(enum icp_qat_hw_auth_algo qat_hash_alg) { switch (qat_hash_alg) { diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c new file mode 100644 index 000000000000..13a76a0325ed --- /dev/null +++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c @@ -0,0 +1,639 @@ +/* + 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. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2014 Intel Corporation. + 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 of 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 +#include "qat_rsakey-asn1.h" +#include "icp_qat_fw_pke.h" +#include "adf_accel_devices.h" +#include "adf_transport.h" +#include "adf_common_drv.h" +#include "qat_crypto.h" + +struct qat_rsa_input_params { + union { + struct { + dma_addr_t m; + dma_addr_t e; + dma_addr_t n; + } enc; + struct { + dma_addr_t c; + dma_addr_t d; + dma_addr_t n; + } dec; + u64 in_tab[8]; + }; +} __packed __aligned(64); + +struct qat_rsa_output_params { + union { + struct { + dma_addr_t c; + } enc; + struct { + dma_addr_t m; + } dec; + u64 out_tab[8]; + }; +} __packed __aligned(64); + +struct qat_rsa_ctx { + char *n; + char *e; + char *d; + dma_addr_t dma_n; + dma_addr_t dma_e; + dma_addr_t dma_d; + unsigned int key_sz; + struct qat_crypto_instance *inst; +} __packed __aligned(64); + +struct qat_rsa_request { + struct qat_rsa_input_params in; + struct qat_rsa_output_params out; + dma_addr_t phy_in; + dma_addr_t phy_out; + char *src_align; + struct icp_qat_fw_pke_request req; + struct qat_rsa_ctx *ctx; + int err; +} __aligned(64); + +static void qat_rsa_cb(struct icp_qat_fw_pke_resp *resp) +{ + struct akcipher_request *areq = (void *)(__force long)resp->opaque; + struct qat_rsa_request *req = PTR_ALIGN(akcipher_request_ctx(areq), 64); + struct device *dev = &GET_DEV(req->ctx->inst->accel_dev); + int err = ICP_QAT_FW_PKE_RESP_PKE_STAT_GET( + resp->pke_resp_hdr.comn_resp_flags); + char *ptr = areq->dst; + + err = (err == ICP_QAT_FW_COMN_STATUS_FLAG_OK) ? 0 : -EINVAL; + + if (req->src_align) + dma_free_coherent(dev, req->ctx->key_sz, req->src_align, + req->in.enc.m); + else + dma_unmap_single(dev, req->in.enc.m, req->ctx->key_sz, + DMA_TO_DEVICE); + + dma_unmap_single(dev, req->out.enc.c, req->ctx->key_sz, + DMA_FROM_DEVICE); + dma_unmap_single(dev, req->phy_in, sizeof(struct qat_rsa_input_params), + DMA_TO_DEVICE); + dma_unmap_single(dev, req->phy_out, + sizeof(struct qat_rsa_output_params), + DMA_TO_DEVICE); + + areq->dst_len = req->ctx->key_sz; + /* Need to set the corect length of the output */ + while (!(*ptr) && areq->dst_len) { + areq->dst_len--; + ptr++; + } + + if (areq->dst_len != req->ctx->key_sz) + memcpy(areq->dst, ptr, areq->dst_len); + + akcipher_request_complete(areq, err); +} + +void qat_alg_asym_callback(void *_resp) +{ + struct icp_qat_fw_pke_resp *resp = _resp; + + qat_rsa_cb(resp); +} + +#define PKE_RSA_EP_512 0x1c161b21 +#define PKE_RSA_EP_1024 0x35111bf7 +#define PKE_RSA_EP_1536 0x4d111cdc +#define PKE_RSA_EP_2048 0x6e111dba +#define PKE_RSA_EP_3072 0x7d111ea3 +#define PKE_RSA_EP_4096 0xa5101f7e + +static unsigned long qat_rsa_enc_fn_id(unsigned int len) +{ + unsigned int bitslen = len << 3; + + switch (bitslen) { + case 512: + return PKE_RSA_EP_512; + case 1024: + return PKE_RSA_EP_1024; + case 1536: + return PKE_RSA_EP_1536; + case 2048: + return PKE_RSA_EP_2048; + case 3072: + return PKE_RSA_EP_3072; + case 4096: + return PKE_RSA_EP_4096; + default: + return 0; + }; +} + +#define PKE_RSA_DP1_512 0x1c161b3c +#define PKE_RSA_DP1_1024 0x35111c12 +#define PKE_RSA_DP1_1536 0x4d111cf7 +#define PKE_RSA_DP1_2048 0x6e111dda +#define PKE_RSA_DP1_3072 0x7d111ebe +#define PKE_RSA_DP1_4096 0xa5101f98 + +static unsigned long qat_rsa_dec_fn_id(unsigned int len) +{ + unsigned int bitslen = len << 3; + + switch (bitslen) { + case 512: + return PKE_RSA_DP1_512; + case 1024: + return PKE_RSA_DP1_1024; + case 1536: + return PKE_RSA_DP1_1536; + case 2048: + return PKE_RSA_DP1_2048; + case 3072: + return PKE_RSA_DP1_3072; + case 4096: + return PKE_RSA_DP1_4096; + default: + return 0; + }; +} + +static int qat_rsa_enc(struct akcipher_request *req) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct qat_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); + struct qat_crypto_instance *inst = ctx->inst; + struct device *dev = &GET_DEV(inst->accel_dev); + struct qat_rsa_request *qat_req = + PTR_ALIGN(akcipher_request_ctx(req), 64); + struct icp_qat_fw_pke_request *msg = &qat_req->req; + int ret, ctr = 0; + + if (unlikely(!ctx->n || !ctx->e)) + return -EINVAL; + + if (req->dst_len < ctx->key_sz) { + req->dst_len = ctx->key_sz; + return -EOVERFLOW; + } + memset(msg, '\0', sizeof(*msg)); + ICP_QAT_FW_PKE_HDR_VALID_FLAG_SET(msg->pke_hdr, + ICP_QAT_FW_COMN_REQ_FLAG_SET); + msg->pke_hdr.cd_pars.func_id = qat_rsa_enc_fn_id(ctx->key_sz); + if (unlikely(!msg->pke_hdr.cd_pars.func_id)) + return -EINVAL; + + qat_req->ctx = ctx; + msg->pke_hdr.service_type = ICP_QAT_FW_COMN_REQ_CPM_FW_PKE; + msg->pke_hdr.comn_req_flags = + ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_PTR_TYPE_FLAT, + QAT_COMN_CD_FLD_TYPE_64BIT_ADR); + + qat_req->in.enc.e = ctx->dma_e; + qat_req->in.enc.n = ctx->dma_n; + ret = -ENOMEM; + + /* + * src can be of any size in valid range, but HW expects it to be the + * same as modulo n so in case it is different we need to allocate a + * new buf and copy src data. + * In other case we just need to map the user provided buffer. + */ + if (req->src_len < ctx->key_sz) { + int shift = ctx->key_sz - req->src_len; + + qat_req->src_align = dma_zalloc_coherent(dev, ctx->key_sz, + &qat_req->in.enc.m, + GFP_KERNEL); + if (unlikely(!qat_req->src_align)) + return ret; + + memcpy(qat_req->src_align + shift, req->src, req->src_len); + } else { + qat_req->src_align = NULL; + qat_req->in.enc.m = dma_map_single(dev, req->src, req->src_len, + DMA_TO_DEVICE); + } + qat_req->in.in_tab[3] = 0; + qat_req->out.enc.c = dma_map_single(dev, req->dst, req->dst_len, + DMA_FROM_DEVICE); + qat_req->out.out_tab[1] = 0; + qat_req->phy_in = dma_map_single(dev, &qat_req->in.enc.m, + sizeof(struct qat_rsa_input_params), + DMA_TO_DEVICE); + qat_req->phy_out = dma_map_single(dev, &qat_req->out.enc.c, + sizeof(struct qat_rsa_output_params), + DMA_TO_DEVICE); + + if (unlikely((!qat_req->src_align && + dma_mapping_error(dev, qat_req->in.enc.m)) || + dma_mapping_error(dev, qat_req->out.enc.c) || + dma_mapping_error(dev, qat_req->phy_in) || + dma_mapping_error(dev, qat_req->phy_out))) + goto unmap; + + msg->pke_mid.src_data_addr = qat_req->phy_in; + msg->pke_mid.dest_data_addr = qat_req->phy_out; + msg->pke_mid.opaque = (uint64_t)(__force long)req; + msg->input_param_count = 3; + msg->output_param_count = 1; + do { + ret = adf_send_message(ctx->inst->pke_tx, (uint32_t *)msg); + } while (ret == -EBUSY && ctr++ < 100); + + if (!ret) + return -EINPROGRESS; +unmap: + if (qat_req->src_align) + dma_free_coherent(dev, ctx->key_sz, qat_req->src_align, + qat_req->in.enc.m); + else + if (!dma_mapping_error(dev, qat_req->in.enc.m)) + dma_unmap_single(dev, qat_req->in.enc.m, ctx->key_sz, + DMA_TO_DEVICE); + if (!dma_mapping_error(dev, qat_req->out.enc.c)) + dma_unmap_single(dev, qat_req->out.enc.c, ctx->key_sz, + DMA_FROM_DEVICE); + if (!dma_mapping_error(dev, qat_req->phy_in)) + dma_unmap_single(dev, qat_req->phy_in, + sizeof(struct qat_rsa_input_params), + DMA_TO_DEVICE); + if (!dma_mapping_error(dev, qat_req->phy_out)) + dma_unmap_single(dev, qat_req->phy_out, + sizeof(struct qat_rsa_output_params), + DMA_TO_DEVICE); + return ret; +} + +static int qat_rsa_dec(struct akcipher_request *req) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct qat_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); + struct qat_crypto_instance *inst = ctx->inst; + struct device *dev = &GET_DEV(inst->accel_dev); + struct qat_rsa_request *qat_req = + PTR_ALIGN(akcipher_request_ctx(req), 64); + struct icp_qat_fw_pke_request *msg = &qat_req->req; + int ret, ctr = 0; + + if (unlikely(!ctx->n || !ctx->d)) + return -EINVAL; + + if (req->dst_len < ctx->key_sz) { + req->dst_len = ctx->key_sz; + return -EOVERFLOW; + } + memset(msg, '\0', sizeof(*msg)); + ICP_QAT_FW_PKE_HDR_VALID_FLAG_SET(msg->pke_hdr, + ICP_QAT_FW_COMN_REQ_FLAG_SET); + msg->pke_hdr.cd_pars.func_id = qat_rsa_dec_fn_id(ctx->key_sz); + if (unlikely(!msg->pke_hdr.cd_pars.func_id)) + return -EINVAL; + + qat_req->ctx = ctx; + msg->pke_hdr.service_type = ICP_QAT_FW_COMN_REQ_CPM_FW_PKE; + msg->pke_hdr.comn_req_flags = + ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_PTR_TYPE_FLAT, + QAT_COMN_CD_FLD_TYPE_64BIT_ADR); + + qat_req->in.dec.d = ctx->dma_d; + qat_req->in.dec.n = ctx->dma_n; + ret = -ENOMEM; + + /* + * src can be of any size in valid range, but HW expects it to be the + * same as modulo n so in case it is different we need to allocate a + * new buf and copy src data. + * In other case we just need to map the user provided buffer. + */ + if (req->src_len < ctx->key_sz) { + int shift = ctx->key_sz - req->src_len; + + qat_req->src_align = dma_zalloc_coherent(dev, ctx->key_sz, + &qat_req->in.dec.c, + GFP_KERNEL); + if (unlikely(!qat_req->src_align)) + return ret; + + memcpy(qat_req->src_align + shift, req->src, req->src_len); + } else { + qat_req->src_align = NULL; + qat_req->in.dec.c = dma_map_single(dev, req->src, req->src_len, + DMA_TO_DEVICE); + } + qat_req->in.in_tab[3] = 0; + qat_req->out.dec.m = dma_map_single(dev, req->dst, req->dst_len, + DMA_FROM_DEVICE); + qat_req->out.out_tab[1] = 0; + qat_req->phy_in = dma_map_single(dev, &qat_req->in.dec.c, + sizeof(struct qat_rsa_input_params), + DMA_TO_DEVICE); + qat_req->phy_out = dma_map_single(dev, &qat_req->out.dec.m, + sizeof(struct qat_rsa_output_params), + DMA_TO_DEVICE); + + if (unlikely((!qat_req->src_align && + dma_mapping_error(dev, qat_req->in.dec.c)) || + dma_mapping_error(dev, qat_req->out.dec.m) || + dma_mapping_error(dev, qat_req->phy_in) || + dma_mapping_error(dev, qat_req->phy_out))) + goto unmap; + + msg->pke_mid.src_data_addr = qat_req->phy_in; + msg->pke_mid.dest_data_addr = qat_req->phy_out; + msg->pke_mid.opaque = (uint64_t)(__force long)req; + msg->input_param_count = 3; + msg->output_param_count = 1; + do { + ret = adf_send_message(ctx->inst->pke_tx, (uint32_t *)msg); + } while (ret == -EBUSY && ctr++ < 100); + + if (!ret) + return -EINPROGRESS; +unmap: + if (qat_req->src_align) + dma_free_coherent(dev, ctx->key_sz, qat_req->src_align, + qat_req->in.dec.c); + else + if (!dma_mapping_error(dev, qat_req->in.dec.c)) + dma_unmap_single(dev, qat_req->in.dec.c, ctx->key_sz, + DMA_TO_DEVICE); + if (!dma_mapping_error(dev, qat_req->out.dec.m)) + dma_unmap_single(dev, qat_req->out.dec.m, ctx->key_sz, + DMA_FROM_DEVICE); + if (!dma_mapping_error(dev, qat_req->phy_in)) + dma_unmap_single(dev, qat_req->phy_in, + sizeof(struct qat_rsa_input_params), + DMA_TO_DEVICE); + if (!dma_mapping_error(dev, qat_req->phy_out)) + dma_unmap_single(dev, qat_req->phy_out, + sizeof(struct qat_rsa_output_params), + DMA_TO_DEVICE); + return ret; +} + +int qat_rsa_get_n(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct qat_rsa_ctx *ctx = context; + struct qat_crypto_instance *inst = ctx->inst; + struct device *dev = &GET_DEV(inst->accel_dev); + const char *ptr = value; + int ret; + + while (!*ptr && vlen) { + ptr++; + vlen--; + } + + ctx->key_sz = vlen; + ret = -EINVAL; + /* In FIPS mode only allow key size 2K & 3K */ + if (fips_enabled && (ctx->key_sz != 256 || ctx->key_sz != 384)) { + pr_err("QAT: RSA: key size not allowed in FIPS mode\n"); + goto err; + } + /* invalid key size provided */ + if (!qat_rsa_enc_fn_id(ctx->key_sz)) + goto err; + + ret = -ENOMEM; + ctx->n = dma_zalloc_coherent(dev, ctx->key_sz, &ctx->dma_n, GFP_KERNEL); + if (!ctx->n) + goto err; + + memcpy(ctx->n, ptr, ctx->key_sz); + return 0; +err: + ctx->key_sz = 0; + ctx->n = NULL; + return ret; +} + +int qat_rsa_get_e(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct qat_rsa_ctx *ctx = context; + struct qat_crypto_instance *inst = ctx->inst; + struct device *dev = &GET_DEV(inst->accel_dev); + const char *ptr = value; + + while (!*ptr && vlen) { + ptr++; + vlen--; + } + + if (!ctx->key_sz || !vlen || vlen > ctx->key_sz) { + ctx->e = NULL; + return -EINVAL; + } + + ctx->e = dma_zalloc_coherent(dev, ctx->key_sz, &ctx->dma_e, GFP_KERNEL); + if (!ctx->e) { + ctx->e = NULL; + return -ENOMEM; + } + memcpy(ctx->e + (ctx->key_sz - vlen), ptr, vlen); + return 0; +} + +int qat_rsa_get_d(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct qat_rsa_ctx *ctx = context; + struct qat_crypto_instance *inst = ctx->inst; + struct device *dev = &GET_DEV(inst->accel_dev); + const char *ptr = value; + int ret; + + while (!*ptr && vlen) { + ptr++; + vlen--; + } + + ret = -EINVAL; + if (!ctx->key_sz || !vlen || vlen > ctx->key_sz) + goto err; + + /* In FIPS mode only allow key size 2K & 3K */ + if (fips_enabled && (vlen != 256 || vlen != 384)) { + pr_err("QAT: RSA: key size not allowed in FIPS mode\n"); + goto err; + } + + ret = -ENOMEM; + ctx->d = dma_zalloc_coherent(dev, ctx->key_sz, &ctx->dma_d, GFP_KERNEL); + if (!ctx->n) + goto err; + + memcpy(ctx->d + (ctx->key_sz - vlen), ptr, vlen); + return 0; +err: + ctx->d = NULL; + return ret; +} + +static int qat_rsa_setkey(struct crypto_akcipher *tfm, const void *key, + unsigned int keylen) +{ + struct qat_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); + struct device *dev = &GET_DEV(ctx->inst->accel_dev); + int ret; + + /* Free the old key if any */ + if (ctx->n) + dma_free_coherent(dev, ctx->key_sz, ctx->n, ctx->dma_n); + if (ctx->e) + dma_free_coherent(dev, ctx->key_sz, ctx->e, ctx->dma_e); + if (ctx->d) { + memset(ctx->d, '\0', ctx->key_sz); + dma_free_coherent(dev, ctx->key_sz, ctx->d, ctx->dma_d); + } + + ctx->n = NULL; + ctx->e = NULL; + ctx->d = NULL; + ret = asn1_ber_decoder(&qat_rsakey_decoder, ctx, key, keylen); + if (ret < 0) + goto free; + + if (!ctx->n || !ctx->e) { + /* invalid key provided */ + ret = -EINVAL; + goto free; + } + + return 0; +free: + if (ctx->d) { + memset(ctx->d, '\0', ctx->key_sz); + dma_free_coherent(dev, ctx->key_sz, ctx->d, ctx->dma_d); + ctx->d = NULL; + } + if (ctx->e) { + dma_free_coherent(dev, ctx->key_sz, ctx->e, ctx->dma_e); + ctx->e = NULL; + } + if (ctx->n) { + dma_free_coherent(dev, ctx->key_sz, ctx->n, ctx->dma_n); + ctx->n = NULL; + ctx->key_sz = 0; + } + return ret; +} + +static int qat_rsa_init_tfm(struct crypto_akcipher *tfm) +{ + struct qat_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); + struct qat_crypto_instance *inst = + qat_crypto_get_instance_node(get_current_node()); + + if (!inst) + return -EINVAL; + + ctx->key_sz = 0; + ctx->inst = inst; + return 0; +} + +static void qat_rsa_exit_tfm(struct crypto_akcipher *tfm) +{ + struct qat_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); + struct device *dev = &GET_DEV(ctx->inst->accel_dev); + + if (ctx->n) + dma_free_coherent(dev, ctx->key_sz, ctx->n, ctx->dma_n); + if (ctx->e) + dma_free_coherent(dev, ctx->key_sz, ctx->e, ctx->dma_e); + if (ctx->d) { + memset(ctx->d, '\0', ctx->key_sz); + dma_free_coherent(dev, ctx->key_sz, ctx->d, ctx->dma_d); + } + qat_crypto_put_instance(ctx->inst); + ctx->n = NULL; + ctx->d = NULL; + ctx->d = NULL; +} + +static struct akcipher_alg rsa = { + .encrypt = qat_rsa_enc, + .decrypt = qat_rsa_dec, + .sign = qat_rsa_dec, + .verify = qat_rsa_enc, + .setkey = qat_rsa_setkey, + .init = qat_rsa_init_tfm, + .exit = qat_rsa_exit_tfm, + .reqsize = sizeof(struct qat_rsa_request) + 64, + .base = { + .cra_name = "rsa", + .cra_driver_name = "qat-rsa", + .cra_priority = 1000, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct qat_rsa_ctx), + }, +}; + +int qat_asym_algs_register(void) +{ + rsa.base.cra_flags = 0; + return crypto_register_akcipher(&rsa); +} + +void qat_asym_algs_unregister(void) +{ + crypto_unregister_akcipher(&rsa); +} diff --git a/drivers/crypto/qat/qat_common/qat_crypto.c b/drivers/crypto/qat/qat_common/qat_crypto.c index 3bd705ca5973..e23ce6fe074b 100644 --- a/drivers/crypto/qat/qat_common/qat_crypto.c +++ b/drivers/crypto/qat/qat_common/qat_crypto.c @@ -88,12 +88,6 @@ static int qat_crypto_free_instances(struct adf_accel_dev *accel_dev) if (inst->pke_rx) adf_remove_ring(inst->pke_rx); - if (inst->rnd_tx) - adf_remove_ring(inst->rnd_tx); - - if (inst->rnd_rx) - adf_remove_ring(inst->rnd_rx); - list_del(list_ptr); kfree(inst); } @@ -202,11 +196,6 @@ static int qat_crypto_create_instances(struct adf_accel_dev *accel_dev) msg_size, key, NULL, 0, &inst->sym_tx)) goto err; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_RND_TX, i); - if (adf_create_ring(accel_dev, SEC, bank, num_msg_asym, - msg_size, key, NULL, 0, &inst->rnd_tx)) - goto err; - msg_size = msg_size >> 1; snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_TX, i); if (adf_create_ring(accel_dev, SEC, bank, num_msg_asym, @@ -220,15 +209,9 @@ static int qat_crypto_create_instances(struct adf_accel_dev *accel_dev) &inst->sym_rx)) goto err; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_RND_RX, i); - if (adf_create_ring(accel_dev, SEC, bank, num_msg_asym, - msg_size, key, qat_alg_callback, 0, - &inst->rnd_rx)) - goto err; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_RX, i); if (adf_create_ring(accel_dev, SEC, bank, num_msg_asym, - msg_size, key, qat_alg_callback, 0, + msg_size, key, qat_alg_asym_callback, 0, &inst->pke_rx)) goto err; } diff --git a/drivers/crypto/qat/qat_common/qat_crypto.h b/drivers/crypto/qat/qat_common/qat_crypto.h index d503007b49e6..dc0273fe3620 100644 --- a/drivers/crypto/qat/qat_common/qat_crypto.h +++ b/drivers/crypto/qat/qat_common/qat_crypto.h @@ -57,8 +57,6 @@ struct qat_crypto_instance { struct adf_etr_ring_data *sym_rx; struct adf_etr_ring_data *pke_tx; struct adf_etr_ring_data *pke_rx; - struct adf_etr_ring_data *rnd_tx; - struct adf_etr_ring_data *rnd_rx; struct adf_accel_dev *accel_dev; struct list_head list; unsigned long state; diff --git a/drivers/crypto/qat/qat_common/qat_rsakey.asn1 b/drivers/crypto/qat/qat_common/qat_rsakey.asn1 new file mode 100644 index 000000000000..97b0e02b600a --- /dev/null +++ b/drivers/crypto/qat/qat_common/qat_rsakey.asn1 @@ -0,0 +1,5 @@ +RsaKey ::= SEQUENCE { + n INTEGER ({ qat_rsa_get_n }), + e INTEGER ({ qat_rsa_get_e }), + d INTEGER ({ qat_rsa_get_d }) +} diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c index 1bde45b7a3c5..d241037f8728 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c @@ -167,12 +167,6 @@ static int adf_dev_configure(struct adf_accel_dev *accel_dev) key, (void *)&val, ADF_DEC)) goto err; - val = 4; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_RND_TX, i); - if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, (void *)&val, ADF_DEC)) - goto err; - val = 8; snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_RX, i); if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, @@ -185,12 +179,6 @@ static int adf_dev_configure(struct adf_accel_dev *accel_dev) key, (void *)&val, ADF_DEC)) goto err; - val = 12; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_RND_RX, i); - if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, (void *)&val, ADF_DEC)) - goto err; - val = ADF_COALESCING_DEF_TIME; snprintf(key, sizeof(key), ADF_ETRMGR_COALESCE_TIMER_FORMAT, i); if (adf_cfg_add_key_value_param(accel_dev, "Accelerator0", -- cgit v1.3-6-gb490 From af9f9b22beee70aae58651cdbb9d6375e6e51797 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jun 2015 16:02:32 +0200 Subject: mac80211: don't store napi struct When introducing multiple RX queues, a single NAPI struct will not be sufficient. Instead of trying to store multiple, simply change the API to have the NAPI struct passed to the RX function. This of course means that drivers using rx_irqsafe() cannot use NAPI, but that seems a reasonable trade-off, particularly since only two of all drivers are currently using it at all. While at it, we can now remove the IEEE80211_RX_REORDER_TIMER flag again since this code path cannot have a napi struct anyway. Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/dev.h | 2 ++ drivers/net/wireless/iwlwifi/dvm/main.c | 3 ++- drivers/net/wireless/iwlwifi/dvm/rx.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/ops.c | 3 ++- drivers/net/wireless/iwlwifi/mvm/rx.c | 2 +- include/net/mac80211.h | 37 +++++++++++++++++++++------------ net/mac80211/ieee80211_i.h | 6 +----- net/mac80211/main.c | 12 ----------- net/mac80211/rx.c | 18 +++++++++------- 10 files changed, 44 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 3811878ab9cd..074977ede343 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -669,6 +669,8 @@ struct iwl_priv { /* ieee device used by generic ieee processing code */ struct ieee80211_hw *hw; + struct napi_struct *napi; + struct list_head calib_results; struct workqueue_struct *workqueue; diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 234e30f498b2..644819563cf0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -2037,7 +2037,8 @@ static void iwl_napi_add(struct iwl_op_mode *op_mode, { struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); - ieee80211_napi_add(priv->hw, napi, napi_dev, poll, weight); + netif_napi_add(napi_dev, napi, poll, weight); + priv->napi = napi; } static const struct iwl_op_mode_ops iwl_dvm_ops = { diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index debec963c610..5a91f5d6b1dc 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -786,7 +786,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); - ieee80211_rx(priv->hw, skb); + ieee80211_rx_napi(priv->hw, skb, priv->napi); } static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2d4bad5fe825..605f57a2c6be 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -559,6 +559,7 @@ struct iwl_mvm { const struct iwl_cfg *cfg; struct iwl_phy_db *phy_db; struct ieee80211_hw *hw; + struct napi_struct *napi; /* for protecting access to iwl_mvm */ struct mutex mutex; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index e4fa50075ffd..3967df63e0f3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -1316,7 +1316,8 @@ static void iwl_mvm_napi_add(struct iwl_op_mode *op_mode, { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - ieee80211_napi_add(mvm->hw, napi, napi_dev, poll, weight); + netif_napi_add(napi_dev, napi, poll, weight); + mvm->napi = napi; } static const struct iwl_op_mode_ops iwl_mvm_ops = { diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 8f1d93b7a13a..9ff0b4321df3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -129,7 +129,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, fraglen, rxb->truesize); } - ieee80211_rx(mvm->hw, skb); + ieee80211_rx_napi(mvm->hw, skb, mvm->napi); } /* diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 43dbddfa06c0..ff68b8c4ab35 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3694,20 +3694,28 @@ void ieee80211_free_hw(struct ieee80211_hw *hw); void ieee80211_restart_hw(struct ieee80211_hw *hw); /** - * ieee80211_napi_add - initialize mac80211 NAPI context - * @hw: the hardware to initialize the NAPI context on - * @napi: the NAPI context to initialize - * @napi_dev: dummy NAPI netdevice, here to not waste the space if the - * driver doesn't use NAPI - * @poll: poll function - * @weight: default weight + * ieee80211_rx_napi - receive frame from NAPI context * - * See also netif_napi_add(). + * Use this function to hand received frames to mac80211. The receive + * buffer in @skb must start with an IEEE 802.11 header. In case of a + * paged @skb is used, the driver is recommended to put the ieee80211 + * header of the frame on the linear part of the @skb to avoid memory + * allocation and/or memcpy by the stack. + * + * This function may not be called in IRQ context. Calls to this function + * for a single hardware must be synchronized against each other. Calls to + * this function, ieee80211_rx_ni() and ieee80211_rx_irqsafe() may not be + * mixed for a single hardware. Must not run concurrently with + * ieee80211_tx_status() or ieee80211_tx_status_ni(). + * + * This function must be called with BHs disabled. + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac80211 after this call + * @napi: the NAPI context */ -void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, - struct net_device *napi_dev, - int (*poll)(struct napi_struct *, int), - int weight); +void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb, + struct napi_struct *napi); /** * ieee80211_rx - receive frame @@ -3729,7 +3737,10 @@ void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, * @hw: the hardware this frame came in on * @skb: the buffer to receive, owned by mac80211 after this call */ -void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb); +static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + ieee80211_rx_napi(hw, skb, NULL); +} /** * ieee80211_rx_irqsafe - receive frame diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 361bb3ca335c..7d75f93bac7d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -202,8 +202,6 @@ enum ieee80211_packet_rx_flags { * @IEEE80211_RX_CMNTR: received on cooked monitor already * @IEEE80211_RX_BEACON_REPORTED: This frame was already reported * to cfg80211_report_obss_beacon(). - * @IEEE80211_RX_REORDER_TIMER: this frame is released by the - * reorder buffer timeout timer, not the normal RX path * * These flags are used across handling multiple interfaces * for a single frame. @@ -211,10 +209,10 @@ enum ieee80211_packet_rx_flags { enum ieee80211_rx_flags { IEEE80211_RX_CMNTR = BIT(0), IEEE80211_RX_BEACON_REPORTED = BIT(1), - IEEE80211_RX_REORDER_TIMER = BIT(2), }; struct ieee80211_rx_data { + struct napi_struct *napi; struct sk_buff *skb; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; @@ -1347,8 +1345,6 @@ struct ieee80211_local { struct ieee80211_sub_if_data __rcu *p2p_sdata; - struct napi_struct *napi; - /* virtual monitor interface */ struct ieee80211_sub_if_data __rcu *monitor_sdata; struct cfg80211_chan_def monitor_chandef; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 3c63468b4dfb..dba0a86dee18 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1132,18 +1132,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_register_hw); -void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, - struct net_device *napi_dev, - int (*poll)(struct napi_struct *, int), - int weight) -{ - struct ieee80211_local *local = hw_to_local(hw); - - netif_napi_add(napi_dev, napi, poll, weight); - local->napi = napi; -} -EXPORT_SYMBOL_GPL(ieee80211_napi_add); - void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index dd6bb2a54d45..817bf22dad5a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2148,9 +2148,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) /* deliver to local stack */ skb->protocol = eth_type_trans(skb, dev); memset(skb->cb, 0, sizeof(skb->cb)); - if (!(rx->flags & IEEE80211_RX_REORDER_TIMER) && - rx->local->napi) - napi_gro_receive(rx->local->napi, skb); + if (rx->napi) + napi_gro_receive(rx->napi, skb); else netif_receive_skb(skb); } @@ -3256,7 +3255,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) /* This is OK -- must be QoS data frame */ .security_idx = tid, .seqno_idx = tid, - .flags = IEEE80211_RX_REORDER_TIMER, + .napi = NULL, /* must be NULL to not have races */ }; struct tid_ampdu_rx *tid_agg_rx; @@ -3433,7 +3432,8 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, * be called with rcu_read_lock protection. */ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, - struct sk_buff *skb) + struct sk_buff *skb, + struct napi_struct *napi) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; @@ -3449,6 +3449,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, memset(&rx, 0, sizeof(rx)); rx.skb = skb; rx.local = local; + rx.napi = napi; if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) I802_DEBUG_INC(local->dot11ReceivedFragmentCount); @@ -3550,7 +3551,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, * This is the receive path handler. It is called by a low level driver when an * 802.11 MPDU is received from the hardware. */ -void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) +void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb, + struct napi_struct *napi) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate = NULL; @@ -3649,7 +3651,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) ieee80211_tpt_led_trig_rx(local, ((struct ieee80211_hdr *)skb->data)->frame_control, skb->len); - __ieee80211_rx_handle_packet(hw, skb); + __ieee80211_rx_handle_packet(hw, skb, napi); rcu_read_unlock(); @@ -3657,7 +3659,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) drop: kfree_skb(skb); } -EXPORT_SYMBOL(ieee80211_rx); +EXPORT_SYMBOL(ieee80211_rx_napi); /* This is a version of the rx handler that can be called from hard irq * context. Post the skb on the queue and schedule the tasklet */ -- cgit v1.3-6-gb490 From 33c2f538d8080845e11af500993cc61ad30934e2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2015 13:07:14 +0200 Subject: mac80211_hwsim: support wider TDLS bandwidth There's no reason not to support this, allow it to test those code paths. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 99e873dc8684..08022ded6307 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2399,6 +2399,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, TDLS_WIDER_BW); if (rctbl) ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); -- cgit v1.3-6-gb490 From f964c409f7cc626335cf2370f55690660a273dad Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 9 Jul 2015 07:10:12 -0300 Subject: [media] coda: clamp frame sequence counters to 16 bit This is already done for one side of the comparison with the expectation that the HW counter rolls over at the 16 bit boundary. This is true when decoding a h.264 stream, but doesn't hold for at least MJPEG. As we don't know the exact wrap-around point for this format just clamp the HW counter to the same 16 bits. This should be enough to detect most of the errors and saves us from doing different comparisons based on the decoded format. Signed-off-by: Lucas Stach Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 109797bb8fbb..9fbff248d7fa 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1902,7 +1902,14 @@ static void coda_finish_decode(struct coda_ctx *ctx) meta = list_first_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, list); list_del(&meta->list); - if (val != (meta->sequence & 0xffff)) { + /* + * Clamp counters to 16 bits for comparison, as the HW + * counter rolls over at this point for h.264. This + * may be different for other formats, but using 16 bits + * should be enough to detect most errors and saves us + * from doing different things based on the format. + */ + if ((val & 0xffff) != (meta->sequence & 0xffff)) { v4l2_err(&dev->v4l2_dev, "sequence number mismatch (%d(%d) != %d)\n", val, ctx->sequence_offset, -- cgit v1.3-6-gb490 From b05959c66e865fb9eb5b93e223da925572130d7f Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:13 -0300 Subject: [media] coda: fix mvcol buffer for MPEG4 decoding The mvcol buffer is allocated at the end of the first internal buffer. This patch fixes an out of bounds array access. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 9fbff248d7fa..47fc2f19a4a9 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -384,7 +384,7 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, /* mvcol buffer for mpeg4 */ if ((dev->devtype->product != CODA_DX6) && (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4)) - coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr + + coda_parabuf_write(ctx, 97, ctx->internal_frames[0].paddr + ysize + ysize/4 + ysize/4); return 0; -- cgit v1.3-6-gb490 From 58bc7edf1d9a16073761031a03291af887ccdf66 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:14 -0300 Subject: [media] coda: fix bitstream preloading for MPEG4 decoding All decoder instances using the BIT processor should preload buffers into the bitstream ring buffer, including MPEG4 decoding. Fix this by explicitly stating the above condition instead of listing all relevant input formats. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 58f65486de33..3259ea61cd9b 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1244,9 +1244,7 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - if (q_data_src->fourcc == V4L2_PIX_FMT_H264 || - (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && - ctx->dev->devtype->product == CODA_7541)) { + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { /* copy the buffers that were queued before streamon */ mutex_lock(&ctx->bitstream_mutex); coda_fill_bitstream(ctx, false); -- cgit v1.3-6-gb490 From 30a09579b2e238646bca4e7cc443db24d91436d6 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:15 -0300 Subject: [media] coda: keep buffers on the queue in bitstream end mode In stream end mode the hardware will read the bitstream to its end, overshooting the write pointer. Do not write additional data into the bitstream in this mode. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 47fc2f19a4a9..0f8dcea065af 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -228,6 +228,9 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) struct coda_buffer_meta *meta; u32 start; + if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) + return; + while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { /* * Only queue a single JPEG into the bitstream buffer, except -- cgit v1.3-6-gb490 From 5c718bb323aef02ea580073a3640b072fb2f6838 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:16 -0300 Subject: [media] coda: avoid calling SEQ_END twice Allow coda_seq_end_work to be called multiple times, move the setting of ctx->initialized from coda_start/stop_streaming() into coda_start_encoding/decoding and coda_seq_end_work, respectively, and skip the SEQ_END command in coda_seq_end_work if the context is already deinitialized before. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 8 ++++++++ drivers/media/platform/coda/coda-common.c | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 0f8dcea065af..ac4dcb1f446a 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -999,6 +999,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) ret = -EFAULT; goto out; } + ctx->initialized = 1; if (dst_fourcc != V4L2_PIX_FMT_JPEG) { if (dev->devtype->product == CODA_960) @@ -1329,6 +1330,9 @@ static void coda_seq_end_work(struct work_struct *work) mutex_lock(&ctx->buffer_mutex); mutex_lock(&dev->coda_mutex); + if (ctx->initialized == 0) + goto out; + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__); @@ -1342,6 +1346,9 @@ static void coda_seq_end_work(struct work_struct *work) coda_free_framebuffers(ctx); + ctx->initialized = 0; + +out: mutex_unlock(&dev->coda_mutex); mutex_unlock(&ctx->buffer_mutex); } @@ -1499,6 +1506,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx) coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); return -ETIMEDOUT; } + ctx->initialized = 1; /* Update kfifo out pointer from coda bitstream read pointer */ coda_kfifo_sync_from_device(ctx); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3259ea61cd9b..de0e24533727 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1313,7 +1313,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) goto err; } - ctx->initialized = 1; return ret; err: @@ -1376,7 +1375,6 @@ static void coda_stop_streaming(struct vb2_queue *q) mutex_unlock(&ctx->bitstream_mutex); kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); - ctx->initialized = 0; ctx->runcounter = 0; ctx->aborting = 0; } @@ -1767,7 +1765,7 @@ static int coda_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); /* In case the instance was not running, we still need to call SEQ_END */ - if (ctx->initialized && ctx->ops->seq_end_work) { + if (ctx->ops->seq_end_work) { queue_work(dev->workqueue, &ctx->seq_end_work); flush_work(&ctx->seq_end_work); } -- cgit v1.3-6-gb490 From c1ae0b283d13ad8b53bf3be379b1207085da4b22 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:17 -0300 Subject: [media] coda: reset stream end in stop_streaming Otherwise a restarted stream won't queue buffers. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index de0e24533727..8b91bda784a7 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1378,6 +1378,9 @@ static void coda_stop_streaming(struct vb2_queue *q) ctx->runcounter = 0; ctx->aborting = 0; } + + if (!ctx->streamon_out && !ctx->streamon_cap) + ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; } static const struct vb2_ops coda_qops = { -- cgit v1.3-6-gb490 From 8076c7e3f68547ee1d8e07715329f26f7883152a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:18 -0300 Subject: [media] coda: drop custom list of pixel format descriptions Since commit ba3002045f80 ("[media] v4l2-ioctl: fill in the description for VIDIOC_ENUM_FMT"), all pixel formats are assigned their description in a central place. We can now drop the custom list. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 75 +++---------------------------- 1 file changed, 7 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 8b91bda784a7..b265edd8d277 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -61,11 +61,6 @@ int coda_debug; module_param(coda_debug, int, 0644); MODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); -struct coda_fmt { - char *name; - u32 fourcc; -}; - void coda_write(struct coda_dev *dev, u32 data, u32 reg) { v4l2_dbg(2, coda_debug, &dev->v4l2_dev, @@ -111,40 +106,6 @@ void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, coda_write(ctx->dev, base_cr, reg_y + 8); } -/* - * Array of all formats supported by any version of Coda: - */ -static const struct coda_fmt coda_formats[] = { - { - .name = "YUV 4:2:0 Planar, YCbCr", - .fourcc = V4L2_PIX_FMT_YUV420, - }, - { - .name = "YUV 4:2:0 Planar, YCrCb", - .fourcc = V4L2_PIX_FMT_YVU420, - }, - { - .name = "YUV 4:2:0 Partial interleaved Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV12, - }, - { - .name = "YUV 4:2:2 Planar, YCbCr", - .fourcc = V4L2_PIX_FMT_YUV422P, - }, - { - .name = "H264 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H264, - }, - { - .name = "MPEG4 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG4, - }, - { - .name = "JPEG Encoded Images", - .fourcc = V4L2_PIX_FMT_JPEG, - }, -}; - #define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \ { mode, src_fourcc, dst_fourcc, max_w, max_h } @@ -261,40 +222,23 @@ static const struct coda_video_device *coda9_video_devices[] = { &coda_bit_decoder, }; -static bool coda_format_is_yuv(u32 fourcc) +/* + * Normalize all supported YUV 4:2:0 formats to the value used in the codec + * tables. + */ +static u32 coda_format_normalize_yuv(u32 fourcc) { switch (fourcc) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_YUV422P: - return true; + return V4L2_PIX_FMT_YUV420; default: - return false; + return fourcc; } } -static const char *coda_format_name(u32 fourcc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(coda_formats); i++) { - if (coda_formats[i].fourcc == fourcc) - return coda_formats[i].name; - } - - return NULL; -} - -/* - * Normalize all supported YUV 4:2:0 formats to the value used in the codec - * tables. - */ -static u32 coda_format_normalize_yuv(u32 fourcc) -{ - return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc; -} - static const struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc, int dst_fourcc) { @@ -396,7 +340,6 @@ static int coda_enum_fmt(struct file *file, void *priv, struct video_device *vdev = video_devdata(file); const struct coda_video_device *cvd = to_coda_video_device(vdev); const u32 *formats; - const char *name; if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) formats = cvd->src_formats; @@ -408,11 +351,7 @@ static int coda_enum_fmt(struct file *file, void *priv, if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0) return -EINVAL; - name = coda_format_name(formats[f->index]); - strlcpy(f->description, name, sizeof(f->description)); f->pixelformat = formats[f->index]; - if (!coda_format_is_yuv(formats[f->index])) - f->flags |= V4L2_FMT_FLAG_COMPRESSED; return 0; } -- cgit v1.3-6-gb490 From f0710815a0e17c63d3f17d365ae556ab15eccb03 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:19 -0300 Subject: [media] coda: use event class to deduplicate v4l2 trace events Trace events with exactly the same parameters and trace output, such as coda_enc_pic_run and coda_enc_pic_done, are supposed to use the DECLARE_EVENT_CLASS and DEFINE_EVENT macros instead of duplicated TRACE_EVENT macro calls. This patch changes the order of parameters to coda_dec_rot_done and adds a timestamp so it can share an event class with coda_bit_queue. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 2 +- drivers/media/platform/coda/trace.h | 89 ++++++++++------------------------ 2 files changed, 26 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index ac4dcb1f446a..226ce4a786ea 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1978,7 +1978,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) dst_buf->v4l2_buf.timecode = meta->timecode; dst_buf->v4l2_buf.timestamp = meta->timestamp; - trace_coda_dec_rot_done(ctx, meta, dst_buf); + trace_coda_dec_rot_done(ctx, dst_buf, meta); switch (q_data_dst->fourcc) { case V4L2_PIX_FMT_YUV420: diff --git a/drivers/media/platform/coda/trace.h b/drivers/media/platform/coda/trace.h index 781bf7286d53..d9099a0f7c32 100644 --- a/drivers/media/platform/coda/trace.h +++ b/drivers/media/platform/coda/trace.h @@ -48,7 +48,7 @@ TRACE_EVENT(coda_bit_done, TP_printk("minor = %d, ctx = %d", __entry->minor, __entry->ctx) ); -TRACE_EVENT(coda_enc_pic_run, +DECLARE_EVENT_CLASS(coda_buf_class, TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf), TP_ARGS(ctx, buf), @@ -69,28 +69,17 @@ TRACE_EVENT(coda_enc_pic_run, __entry->minor, __entry->index, __entry->ctx) ); -TRACE_EVENT(coda_enc_pic_done, +DEFINE_EVENT(coda_buf_class, coda_enc_pic_run, TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf), + TP_ARGS(ctx, buf) +); - TP_ARGS(ctx, buf), - - TP_STRUCT__entry( - __field(int, minor) - __field(int, index) - __field(int, ctx) - ), - - TP_fast_assign( - __entry->minor = ctx->fh.vdev->minor; - __entry->index = buf->v4l2_buf.index; - __entry->ctx = ctx->idx; - ), - - TP_printk("minor = %d, index = %d, ctx = %d", - __entry->minor, __entry->index, __entry->ctx) +DEFINE_EVENT(coda_buf_class, coda_enc_pic_done, + TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf), + TP_ARGS(ctx, buf) ); -TRACE_EVENT(coda_bit_queue, +DECLARE_EVENT_CLASS(coda_buf_meta_class, TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf, struct coda_buffer_meta *meta), @@ -117,7 +106,13 @@ TRACE_EVENT(coda_bit_queue, __entry->ctx) ); -TRACE_EVENT(coda_dec_pic_run, +DEFINE_EVENT(coda_buf_meta_class, coda_bit_queue, + TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf, + struct coda_buffer_meta *meta), + TP_ARGS(ctx, buf, meta) +); + +DECLARE_EVENT_CLASS(coda_meta_class, TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), TP_ARGS(ctx, meta), @@ -140,54 +135,20 @@ TRACE_EVENT(coda_dec_pic_run, __entry->minor, __entry->start, __entry->end, __entry->ctx) ); -TRACE_EVENT(coda_dec_pic_done, +DEFINE_EVENT(coda_meta_class, coda_dec_pic_run, TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), - - TP_ARGS(ctx, meta), - - TP_STRUCT__entry( - __field(int, minor) - __field(int, start) - __field(int, end) - __field(int, ctx) - ), - - TP_fast_assign( - __entry->minor = ctx->fh.vdev->minor; - __entry->start = meta->start; - __entry->end = meta->end; - __entry->ctx = ctx->idx; - ), - - TP_printk("minor = %d, start = 0x%x, end = 0x%x, ctx = %d", - __entry->minor, __entry->start, __entry->end, __entry->ctx) + TP_ARGS(ctx, meta) ); -TRACE_EVENT(coda_dec_rot_done, - TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta, - struct vb2_buffer *buf), - - TP_ARGS(ctx, meta, buf), - - TP_STRUCT__entry( - __field(int, minor) - __field(int, start) - __field(int, end) - __field(int, index) - __field(int, ctx) - ), - - TP_fast_assign( - __entry->minor = ctx->fh.vdev->minor; - __entry->start = meta->start; - __entry->end = meta->end; - __entry->index = buf->v4l2_buf.index; - __entry->ctx = ctx->idx; - ), +DEFINE_EVENT(coda_meta_class, coda_dec_pic_done, + TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), + TP_ARGS(ctx, meta) +); - TP_printk("minor = %d, start = 0x%x, end = 0x%x, index = %d, ctx = %d", - __entry->minor, __entry->start, __entry->end, __entry->index, - __entry->ctx) +DEFINE_EVENT(coda_buf_meta_class, coda_dec_rot_done, + TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf, + struct coda_buffer_meta *meta), + TP_ARGS(ctx, buf, meta) ); #endif /* __CODA_TRACE_H__ */ -- cgit v1.3-6-gb490 From 2cf251c0c3961bd467e086033c6073ef62b29b02 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:20 -0300 Subject: [media] coda: reuse src_bufs in coda_job_ready The v4l2_m2m_num_src_bufs_ready() function is called in multiple places in coda_cob_ready, and there already is a variable src_bufs that is assigned to its result. Move it to the beginning and use it everywhere. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index b265edd8d277..267fda760b38 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -888,14 +888,14 @@ static void coda_pic_run_work(struct work_struct *work) static int coda_job_ready(void *m2m_priv) { struct coda_ctx *ctx = m2m_priv; + int src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx); /* * For both 'P' and 'key' frame cases 1 picture * and 1 frame are needed. In the decoder case, * the compressed frame can be in the bitstream. */ - if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && - ctx->inst_type != CODA_INST_DECODER) { + if (!src_bufs && ctx->inst_type != CODA_INST_DECODER) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "not ready: not enough video buffers.\n"); return 0; @@ -911,9 +911,8 @@ static int coda_job_ready(void *m2m_priv) struct list_head *meta; bool stream_end; int num_metas; - int src_bufs; - if (ctx->hold && !v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) { + if (ctx->hold && !src_bufs) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "%d: not ready: on hold for more buffers.\n", ctx->idx); @@ -927,8 +926,6 @@ static int coda_job_ready(void *m2m_priv) list_for_each(meta, &ctx->buffer_meta_list) num_metas++; - src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx); - if (!stream_end && (num_metas + src_bufs) < 2) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "%d: not ready: need 2 buffers available (%d, %d)\n", @@ -937,8 +934,8 @@ static int coda_job_ready(void *m2m_priv) } - if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && - !stream_end && (coda_get_bitstream_payload(ctx) < 512)) { + if (!src_bufs && !stream_end && + (coda_get_bitstream_payload(ctx) < 512)) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "%d: not ready: not enough bitstream data (%d).\n", ctx->idx, coda_get_bitstream_payload(ctx)); -- cgit v1.3-6-gb490 From 47f3fa63ee5c0e6bdf9c9d5ed73fc791981336e4 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:21 -0300 Subject: [media] coda: rework meta counting and add separate lock Keep count of number of buffer meta structures in the list and use a separate spinlock for operations on this counted list instead of reusing the bitstream mutex in some places and none at all in others. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 16 ++++++++++++++-- drivers/media/platform/coda/coda-common.c | 21 +++++++++------------ drivers/media/platform/coda/coda.h | 2 ++ 3 files changed, 25 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 226ce4a786ea..25910ccd2da0 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -226,6 +226,7 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) { struct vb2_buffer *src_buf; struct coda_buffer_meta *meta; + unsigned long flags; u32 start; if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) @@ -274,8 +275,13 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) meta->start = start; meta->end = ctx->bitstream_fifo.kfifo.in & ctx->bitstream_fifo.kfifo.mask; + spin_lock_irqsave(&ctx->buffer_meta_lock, + flags); list_add_tail(&meta->list, &ctx->buffer_meta_list); + ctx->num_metas++; + spin_unlock_irqrestore(&ctx->buffer_meta_lock, + flags); trace_coda_bit_queue(ctx, src_buf, meta); } @@ -1665,6 +1671,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) struct coda_dev *dev = ctx->dev; struct coda_q_data *q_data_dst; struct coda_buffer_meta *meta; + unsigned long flags; u32 reg_addr, reg_stride; dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -1743,6 +1750,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_write(dev, ctx->iram_info.axi_sram_use, CODA7_REG_BIT_AXI_SRAM_USE); + spin_lock_irqsave(&ctx->buffer_meta_lock, flags); meta = list_first_entry_or_null(&ctx->buffer_meta_list, struct coda_buffer_meta, list); @@ -1762,6 +1770,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) kfifo_in(&ctx->bitstream_fifo, buf, pad); } } + spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); coda_kfifo_sync_to_device_full(ctx); @@ -1783,6 +1792,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) struct vb2_buffer *dst_buf; struct coda_buffer_meta *meta; unsigned long payload; + unsigned long flags; int width, height; int decoded_idx; int display_idx; @@ -1908,11 +1918,13 @@ static void coda_finish_decode(struct coda_ctx *ctx) } else { val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; val -= ctx->sequence_offset; - mutex_lock(&ctx->bitstream_mutex); + spin_lock_irqsave(&ctx->buffer_meta_lock, flags); if (!list_empty(&ctx->buffer_meta_list)) { meta = list_first_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, list); list_del(&meta->list); + ctx->num_metas--; + spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); /* * Clamp counters to 16 bits for comparison, as the HW * counter rolls over at this point for h.264. This @@ -1929,13 +1941,13 @@ static void coda_finish_decode(struct coda_ctx *ctx) ctx->frame_metas[decoded_idx] = *meta; kfree(meta); } else { + spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); memset(&ctx->frame_metas[decoded_idx], 0, sizeof(struct coda_buffer_meta)); ctx->frame_metas[decoded_idx].sequence = val; ctx->sequence_offset++; } - mutex_unlock(&ctx->bitstream_mutex); trace_coda_dec_pic_done(ctx, &ctx->frame_metas[decoded_idx]); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 267fda760b38..367b6baa8f31 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -908,9 +908,9 @@ static int coda_job_ready(void *m2m_priv) } if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { - struct list_head *meta; - bool stream_end; - int num_metas; + bool stream_end = ctx->bit_stream_param & + CODA_BIT_STREAM_END_FLAG; + int num_metas = ctx->num_metas; if (ctx->hold && !src_bufs) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, @@ -919,13 +919,6 @@ static int coda_job_ready(void *m2m_priv) return 0; } - stream_end = ctx->bit_stream_param & - CODA_BIT_STREAM_END_FLAG; - - num_metas = 0; - list_for_each(meta, &ctx->buffer_meta_list) - num_metas++; - if (!stream_end && (num_metas + src_bufs) < 2) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "%d: not ready: need 2 buffers available (%d, %d)\n", @@ -951,6 +944,7 @@ static int coda_job_ready(void *m2m_priv) v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "job ready\n"); + return 1; } @@ -1267,6 +1261,7 @@ static void coda_stop_streaming(struct vb2_queue *q) struct coda_ctx *ctx = vb2_get_drv_priv(q); struct coda_dev *dev = ctx->dev; struct vb2_buffer *buf; + unsigned long flags; bool stop; stop = ctx->streamon_out && ctx->streamon_cap; @@ -1301,14 +1296,15 @@ static void coda_stop_streaming(struct vb2_queue *q) queue_work(dev->workqueue, &ctx->seq_end_work); flush_work(&ctx->seq_end_work); } - mutex_lock(&ctx->bitstream_mutex); + spin_lock_irqsave(&ctx->buffer_meta_lock, flags); while (!list_empty(&ctx->buffer_meta_list)) { meta = list_first_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, list); list_del(&meta->list); kfree(meta); } - mutex_unlock(&ctx->bitstream_mutex); + ctx->num_metas = 0; + spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); ctx->runcounter = 0; @@ -1661,6 +1657,7 @@ static int coda_open(struct file *file) mutex_init(&ctx->bitstream_mutex); mutex_init(&ctx->buffer_mutex); INIT_LIST_HEAD(&ctx->buffer_meta_list); + spin_lock_init(&ctx->buffer_meta_lock); coda_lock(ctx); list_add(&ctx->list, &dev->instances); diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 8e0af221b2e9..a3d70ccd1020 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -227,6 +227,8 @@ struct coda_ctx { struct coda_buffer_meta frame_metas[CODA_MAX_FRAMEBUFFERS]; u32 frame_errors[CODA_MAX_FRAMEBUFFERS]; struct list_head buffer_meta_list; + spinlock_t buffer_meta_lock; + int num_metas; struct coda_aux_buf workbuf; int num_internal_frames; int idx; -- cgit v1.3-6-gb490 From 68aa7ee15cd683006ec1ac91ad60c019bf62d978 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 10 Jul 2015 10:37:44 -0300 Subject: [media] coda: reset CODA960 hardware after sequence end On i.MX6, sometimes after decoding a stream, encoding will produce macroblock errors caused by missing 8-byte sequences in the output stream. Until the cause for this is found, reset the hardware after sequence end, which seems to help. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 25910ccd2da0..bcb9911d5e3f 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1347,6 +1347,14 @@ static void coda_seq_end_work(struct work_struct *work) "CODA_COMMAND_SEQ_END failed\n"); } + /* + * FIXME: Sometimes h.264 encoding fails with 8-byte sequences missing + * from the output stream after the h.264 decoder has run. Resetting the + * hardware after the decoder has finished seems to help. + */ + if (dev->devtype->product == CODA_960) + coda_hw_reset(ctx); + kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); -- cgit v1.3-6-gb490 From da2b3b3e115d2793b5475039ca4d7f364135fcf4 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 10 Jul 2015 10:37:52 -0300 Subject: [media] coda: implement VBV delay and buffer size controls The encoder allows to specify the VBV model reference decoder's initial delay and buffer size. Export the corresponding V4L2 controls. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 5 ++++- drivers/media/platform/coda/coda-common.c | 14 ++++++++++++++ drivers/media/platform/coda/coda.h | 2 ++ 3 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index bcb9911d5e3f..b14affcf8dc0 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -922,6 +922,9 @@ static int coda_start_encoding(struct coda_ctx *ctx) value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; value |= 1 & CODA_RATECONTROL_ENABLE_MASK; + value |= (ctx->params.vbv_delay & + CODA_RATECONTROL_INITIALDELAY_MASK) + << CODA_RATECONTROL_INITIALDELAY_OFFSET; if (dev->devtype->product == CODA_960) value |= BIT(31); /* disable autoskip */ } else { @@ -929,7 +932,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) } coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); - coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); + coda_write(dev, ctx->params.vbv_size, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); coda_write(dev, ctx->params.intra_refresh, CODA_CMD_ENC_SEQ_INTRA_REFRESH); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 367b6baa8f31..24737f1a1a1b 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1400,6 +1400,12 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_JPEG_RESTART_INTERVAL: ctx->params.jpeg_restart_interval = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_VBV_DELAY: + ctx->params.vbv_delay = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VBV_SIZE: + ctx->params.vbv_size = min(ctrl->val * 8192, 0x7fffffff); + break; default: v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", @@ -1459,6 +1465,14 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, 0, 0x7fff, 1, 0); + /* + * The maximum VBV size value is 0x7fffffff bits, + * one bit less than 262144 KiB + */ + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VBV_SIZE, 0, 262144, 1, 0); } static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx) diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index a3d70ccd1020..26c9c4bb6e4a 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -128,6 +128,8 @@ struct coda_params { enum v4l2_mpeg_video_multi_slice_mode slice_mode; u32 framerate; u16 bitrate; + u16 vbv_delay; + u32 vbv_size; u32 slice_max_bits; u32 slice_max_mb; }; -- cgit v1.3-6-gb490 From cde29ef313de391ec9a1e461458274623ab1eb87 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 16 Jul 2015 13:13:24 -0300 Subject: [media] coda: Use S_PARM to set nominal framerate for h.264 encoder The encoder needs to know the nominal framerate for the constant bitrate control mechanism to work. Currently the only way to set the framerate is by using VIDIOC_S_PARM on the output queue. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 102 ++++++++++++++++++++++++++++++ drivers/media/platform/coda/coda_regs.h | 4 ++ 2 files changed, 106 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 24737f1a1a1b..a7cab14d10c9 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -770,6 +771,104 @@ static int coda_decoder_cmd(struct file *file, void *fh, return 0; } +static int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct v4l2_fract *tpf; + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + tpf = &a->parm.output.timeperframe; + tpf->denominator = ctx->params.framerate & CODA_FRATE_RES_MASK; + tpf->numerator = 1 + (ctx->params.framerate >> + CODA_FRATE_DIV_OFFSET); + + return 0; +} + +/* + * Approximate timeperframe v4l2_fract with values that can be written + * into the 16-bit CODA_FRATE_DIV and CODA_FRATE_RES fields. + */ +static void coda_approximate_timeperframe(struct v4l2_fract *timeperframe) +{ + struct v4l2_fract s = *timeperframe; + struct v4l2_fract f0; + struct v4l2_fract f1 = { 1, 0 }; + struct v4l2_fract f2 = { 0, 1 }; + unsigned int i, div, s_denominator; + + /* Lower bound is 1/65535 */ + if (s.numerator == 0 || s.denominator / s.numerator > 65535) { + timeperframe->numerator = 1; + timeperframe->denominator = 65535; + return; + } + + /* Upper bound is 65536/1, map everything above to infinity */ + if (s.denominator == 0 || s.numerator / s.denominator > 65536) { + timeperframe->numerator = 1; + timeperframe->denominator = 0; + return; + } + + /* Reduce fraction to lowest terms */ + div = gcd(s.numerator, s.denominator); + if (div > 1) { + s.numerator /= div; + s.denominator /= div; + } + + if (s.numerator <= 65536 && s.denominator < 65536) { + *timeperframe = s; + return; + } + + /* Find successive convergents from continued fraction expansion */ + while (f2.numerator <= 65536 && f2.denominator < 65536) { + f0 = f1; + f1 = f2; + + /* Stop when f2 exactly equals timeperframe */ + if (s.numerator == 0) + break; + + i = s.denominator / s.numerator; + + f2.numerator = f0.numerator + i * f1.numerator; + f2.denominator = f0.denominator + i * f2.denominator; + + s_denominator = s.numerator; + s.numerator = s.denominator % s.numerator; + s.denominator = s_denominator; + } + + *timeperframe = f1; +} + +static uint32_t coda_timeperframe_to_frate(struct v4l2_fract *timeperframe) +{ + return ((timeperframe->numerator - 1) << CODA_FRATE_DIV_OFFSET) | + timeperframe->denominator; +} + +static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct v4l2_fract *tpf; + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + tpf = &a->parm.output.timeperframe; + coda_approximate_timeperframe(tpf); + ctx->params.framerate = coda_timeperframe_to_frate(tpf); + + return 0; +} + static int coda_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { @@ -810,6 +909,9 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_try_decoder_cmd = coda_try_decoder_cmd, .vidioc_decoder_cmd = coda_decoder_cmd, + .vidioc_g_parm = coda_g_parm, + .vidioc_s_parm = coda_s_parm, + .vidioc_subscribe_event = coda_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index 7d026241171b..00e4f5160c1f 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -263,6 +263,10 @@ #define CODADX6_PICHEIGHT_MASK 0x3ff #define CODA7_PICHEIGHT_MASK 0xffff #define CODA_CMD_ENC_SEQ_SRC_F_RATE 0x194 +#define CODA_FRATE_RES_OFFSET 0 +#define CODA_FRATE_RES_MASK 0xffff +#define CODA_FRATE_DIV_OFFSET 16 +#define CODA_FRATE_DIV_MASK 0xffff #define CODA_CMD_ENC_SEQ_MP4_PARA 0x198 #define CODA_MP4PARAM_VERID_OFFSET 6 #define CODA_MP4PARAM_VERID_MASK 0x01 -- cgit v1.3-6-gb490 From 4e447ff199cfc4bc04ddb515d3d9ab46bb19530a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 16 Jul 2015 13:19:37 -0300 Subject: [media] coda: move cache setup into coda9_set_frame_cache, also use it in start_encoding The frame cache should be set up correctly to encode NV12 source frames. This was not done before, so move the cache setup out of start_decoding into its own function and call it from both start_encoding and start_decoding. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 45 +++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index b14affcf8dc0..46c70547fc12 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -721,6 +721,26 @@ err_clk_per: return ret; } +static void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc) +{ + u32 cache_size, cache_config; + + /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ + cache_size = 0x20262024; + cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET; + coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE); + if (fourcc == V4L2_PIX_FMT_NV12) { + cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | + 16 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | + 0 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; + } else { + cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; + } + coda_write(ctx->dev, cache_config, CODA9_CMD_SET_FRAME_CACHE_CONFIG); +} + /* * Encoder context operations */ @@ -1049,6 +1069,8 @@ static int coda_start_encoding(struct coda_ctx *ctx) coda_write(dev, ctx->iram_info.buf_btp_use, CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); + coda9_set_frame_cache(ctx, q_data_src->fourcc); + /* FIXME */ coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); @@ -1606,30 +1628,13 @@ static int __coda_start_decoding(struct coda_ctx *ctx) CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); coda_write(dev, ctx->iram_info.buf_ovl_use, CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); - if (dev->devtype->product == CODA_960) + if (dev->devtype->product == CODA_960) { coda_write(dev, ctx->iram_info.buf_btp_use, CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); - } - - if (dev->devtype->product == CODA_960) { - int cbb_size, crb_size; - - coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); - /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ - coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE); - if (dst_fourcc == V4L2_PIX_FMT_NV12) { - cbb_size = 0; - crb_size = 16; - } else { - cbb_size = 8; - crb_size = 8; + coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); + coda9_set_frame_cache(ctx, dst_fourcc); } - coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET | - 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | - cbb_size << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET | - crb_size << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET, - CODA9_CMD_SET_FRAME_CACHE_CONFIG); } if (src_fourcc == V4L2_PIX_FMT_H264) { -- cgit v1.3-6-gb490 From a269e53b1aa87157311e53e5b69699ba8f3ba4d0 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 16 Jul 2015 13:19:38 -0300 Subject: [media] coda: add macroblock tiling support Storing internal frames in macroblock tiled order improves memory access patterns by allowing increased burst sizes when transferring the uncompressed macroblocks to or from main memory. The translation logic only supports a single chroma base address, so this is only supported for the chroma interleaved NV12 format. Since the rotator used to copy the decoder output into the v4l2 capture buffers does not seem to support the tiled format correctly, only enable it in the encoder for now. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/Makefile | 2 +- drivers/media/platform/coda/coda-bit.c | 48 +++++++--- drivers/media/platform/coda/coda-common.c | 74 +++++---------- drivers/media/platform/coda/coda-gdi.c | 150 ++++++++++++++++++++++++++++++ drivers/media/platform/coda/coda.h | 11 +-- drivers/media/platform/coda/coda_regs.h | 6 ++ 6 files changed, 221 insertions(+), 70 deletions(-) create mode 100644 drivers/media/platform/coda/coda-gdi.c (limited to 'drivers') diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 834e504bf085..9342ac57b230 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,5 +1,5 @@ ccflags-y += -I$(src) -coda-objs := coda-common.o coda-bit.o coda-h264.o coda-jpeg.o +coda-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-jpeg.o obj-$(CONFIG_VIDEO_CODA) += coda.o diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 46c70547fc12..3d434a4ed537 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -340,7 +340,6 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, { struct coda_dev *dev = ctx->dev; int width, height; - dma_addr_t paddr; int ysize; int ret; int i; @@ -360,7 +359,10 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, size_t size; char *name; - size = ysize + ysize / 2; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + size = round_up(ysize, 4096) + ysize / 2; + else + size = ysize + ysize / 2; if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && dev->devtype->product != CODA_DX6) size += ysize / 4; @@ -376,11 +378,23 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, /* Register frame buffers in the parameter buffer */ for (i = 0; i < ctx->num_internal_frames; i++) { - paddr = ctx->internal_frames[i].paddr; + u32 y, cb, cr; + /* Start addresses of Y, Cb, Cr planes */ - coda_parabuf_write(ctx, i * 3 + 0, paddr); - coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); - coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize / 4); + y = ctx->internal_frames[i].paddr; + cb = y + ysize; + cr = y + ysize + ysize/4; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) { + cb = round_up(cb, 4096); + cr = 0; + /* Packed 20-bit MSB of base addresses */ + /* YYYYYCCC, CCyyyyyc, cccc.... */ + y = (y & 0xfffff000) | cb >> 20; + cb = (cb & 0x000ff000) << 12; + } + coda_parabuf_write(ctx, i * 3 + 0, y); + coda_parabuf_write(ctx, i * 3 + 1, cb); + coda_parabuf_write(ctx, i * 3 + 2, cr); /* mvcol buffer for h.264 */ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && @@ -725,9 +739,15 @@ static void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc) { u32 cache_size, cache_config; - /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ - cache_size = 0x20262024; - cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET; + if (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) { + /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ + cache_size = 0x20262024; + cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET; + } else { + /* Luma 0x2 page, 4x4 cache, chroma 0x2 page, 4x3 cache size */ + cache_size = 0x02440243; + cache_config = 1 << CODA9_CACHE_PAGEMERGE_OFFSET; + } coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE); if (fourcc == V4L2_PIX_FMT_NV12) { cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | @@ -818,9 +838,12 @@ static int coda_start_encoding(struct coda_ctx *ctx) break; } - ctx->frame_mem_ctrl &= ~CODA_FRAME_CHROMA_INTERLEAVE; + ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | + CODA9_FRAME_TILED2LINEAR); if (q_data_src->fourcc == V4L2_PIX_FMT_NV12) ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR; coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); if (dev->devtype->product == CODA_DX6) { @@ -1497,9 +1520,12 @@ static int __coda_start_decoding(struct coda_ctx *ctx) /* Update coda bitstream read and write pointers from kfifo */ coda_kfifo_sync_to_device_full(ctx); - ctx->frame_mem_ctrl &= ~CODA_FRAME_CHROMA_INTERLEAVE; + ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | + CODA9_FRAME_TILED2LINEAR); if (dst_fourcc == V4L2_PIX_FMT_NV12) ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR; coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); ctx->display_idx = -1; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index a7cab14d10c9..d62b82846037 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -62,6 +62,10 @@ int coda_debug; module_param(coda_debug, int, 0644); MODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); +static int disable_tiling; +module_param(disable_tiling, int, 0644); +MODULE_PARM_DESC(disable_tiling, "Disable tiled frame buffers"); + void coda_write(struct coda_dev *dev, u32 data, u32 reg) { v4l2_dbg(2, coda_debug, &dev->v4l2_dev, @@ -585,6 +589,22 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f) q_data->rect.width = f->fmt.pix.width; q_data->rect.height = f->fmt.pix.height; + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_NV12: + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; + if (!disable_tiling) + break; + } + /* else fall through */ + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; + break; + default: + break; + } + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %d\n", f->type, q_data->width, q_data->height, q_data->fourcc); @@ -916,27 +936,6 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -void coda_set_gdi_regs(struct coda_ctx *ctx) -{ - struct gdi_tiled_map *tiled_map = &ctx->tiled_map; - struct coda_dev *dev = ctx->dev; - int i; - - for (i = 0; i < 16; i++) - coda_write(dev, tiled_map->xy2ca_map[i], - CODA9_GDI_XY2_CAS_0 + 4 * i); - for (i = 0; i < 4; i++) - coda_write(dev, tiled_map->xy2ba_map[i], - CODA9_GDI_XY2_BA_0 + 4 * i); - for (i = 0; i < 16; i++) - coda_write(dev, tiled_map->xy2ra_map[i], - CODA9_GDI_XY2_RAS_0 + 4 * i); - coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG); - for (i = 0; i < 32; i++) - coda_write(dev, tiled_map->rbc2axi_map[i], - CODA9_GDI_RBC2_AXI_0 + 4 * i); -} - /* * Mem-to-mem operations. */ @@ -1084,32 +1083,6 @@ static const struct v4l2_m2m_ops coda_m2m_ops = { .unlock = coda_unlock, }; -static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type) -{ - struct gdi_tiled_map *tiled_map = &ctx->tiled_map; - int luma_map, chro_map, i; - - memset(tiled_map, 0, sizeof(*tiled_map)); - - luma_map = 64; - chro_map = 64; - tiled_map->map_type = tiled_map_type; - for (i = 0; i < 16; i++) - tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map; - for (i = 0; i < 4; i++) - tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map; - for (i = 0; i < 16; i++) - tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map; - - if (tiled_map_type == GDI_LINEAR_FRAME_MAP) { - tiled_map->xy2rbc_config = 0; - } else { - dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n", - tiled_map_type); - return; - } -} - static void set_default_params(struct coda_ctx *ctx) { unsigned int max_w, max_h, usize, csize; @@ -1148,8 +1121,11 @@ static void set_default_params(struct coda_ctx *ctx) ctx->q_data[V4L2_M2M_DST].rect.width = max_w; ctx->q_data[V4L2_M2M_DST].rect.height = max_h; - if (ctx->dev->devtype->product == CODA_960) - coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP); + /* + * Since the RBC2AXI logic only supports a single chroma plane, + * macroblock tiling only works for to NV12 pixel format. + */ + ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; } /* diff --git a/drivers/media/platform/coda/coda-gdi.c b/drivers/media/platform/coda/coda-gdi.c new file mode 100644 index 000000000000..aaa7afc6870f --- /dev/null +++ b/drivers/media/platform/coda/coda-gdi.c @@ -0,0 +1,150 @@ +/* + * Coda multi-standard codec IP + * + * Copyright (C) 2014 Philipp Zabel, Pengutronix + * + * 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 "coda.h" + +#define XY2_INVERT BIT(7) +#define XY2_ZERO BIT(6) +#define XY2_TB_XOR BIT(5) +#define XY2_XYSEL BIT(4) +#define XY2_Y (1 << 4) +#define XY2_X (0 << 4) + +#define XY2(luma_sel, luma_bit, chroma_sel, chroma_bit) \ + (((XY2_##luma_sel) | (luma_bit)) << 8 | \ + (XY2_##chroma_sel) | (chroma_bit)) + +static const u16 xy2ca_zero_map[16] = { + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), +}; + +static const u16 xy2ca_tiled_map[16] = { + XY2(Y, 0, Y, 0), + XY2(Y, 1, Y, 1), + XY2(Y, 2, Y, 2), + XY2(Y, 3, X, 3), + XY2(X, 3, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), +}; + +/* + * RA[15:0], CA[15:8] are hardwired to contain the 24-bit macroblock + * start offset (macroblock size is 16x16 for luma, 16x8 for chroma). + * Bits CA[4:0] are set using XY2CA above. BA[3:0] seems to be unused. + */ + +#define RBC_CA (0 << 4) +#define RBC_BA (1 << 4) +#define RBC_RA (2 << 4) +#define RBC_ZERO (3 << 4) + +#define RBC(luma_sel, luma_bit, chroma_sel, chroma_bit) \ + (((RBC_##luma_sel) | (luma_bit)) << 6 | \ + (RBC_##chroma_sel) | (chroma_bit)) + +static const u16 rbc2axi_tiled_map[32] = { + RBC(ZERO, 0, ZERO, 0), + RBC(ZERO, 0, ZERO, 0), + RBC(ZERO, 0, ZERO, 0), + RBC(CA, 0, CA, 0), + RBC(CA, 1, CA, 1), + RBC(CA, 2, CA, 2), + RBC(CA, 3, CA, 3), + RBC(CA, 4, CA, 8), + RBC(CA, 8, CA, 9), + RBC(CA, 9, CA, 10), + RBC(CA, 10, CA, 11), + RBC(CA, 11, CA, 12), + RBC(CA, 12, CA, 13), + RBC(CA, 13, CA, 14), + RBC(CA, 14, CA, 15), + RBC(CA, 15, RA, 0), + RBC(RA, 0, RA, 1), + RBC(RA, 1, RA, 2), + RBC(RA, 2, RA, 3), + RBC(RA, 3, RA, 4), + RBC(RA, 4, RA, 5), + RBC(RA, 5, RA, 6), + RBC(RA, 6, RA, 7), + RBC(RA, 7, RA, 8), + RBC(RA, 8, RA, 9), + RBC(RA, 9, RA, 10), + RBC(RA, 10, RA, 11), + RBC(RA, 11, RA, 12), + RBC(RA, 12, RA, 13), + RBC(RA, 13, RA, 14), + RBC(RA, 14, RA, 15), + RBC(RA, 15, ZERO, 0), +}; + +void coda_set_gdi_regs(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + const u16 *xy2ca_map; + u32 xy2rbc_config; + int i; + + switch (ctx->tiled_map_type) { + case GDI_LINEAR_FRAME_MAP: + default: + xy2ca_map = xy2ca_zero_map; + xy2rbc_config = 0; + break; + case GDI_TILED_FRAME_MB_RASTER_MAP: + xy2ca_map = xy2ca_tiled_map; + xy2rbc_config = CODA9_XY2RBC_TILED_MAP | + CODA9_XY2RBC_CA_INC_HOR | + (16 - 1) << 12 | (8 - 1) << 4; + break; + } + + for (i = 0; i < 16; i++) + coda_write(dev, xy2ca_map[i], + CODA9_GDI_XY2_CAS_0 + 4 * i); + for (i = 0; i < 4; i++) + coda_write(dev, XY2(ZERO, 0, ZERO, 0), + CODA9_GDI_XY2_BA_0 + 4 * i); + for (i = 0; i < 16; i++) + coda_write(dev, XY2(ZERO, 0, ZERO, 0), + CODA9_GDI_XY2_RAS_0 + 4 * i); + coda_write(dev, xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG); + if (xy2rbc_config) { + for (i = 0; i < 32; i++) + coda_write(dev, rbc2axi_tiled_map[i], + CODA9_GDI_RBC2_AXI_0 + 4 * i); + } +} diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 26c9c4bb6e4a..59b2af9c7749 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -167,15 +167,8 @@ struct coda_iram_info { phys_addr_t next_paddr; }; -struct gdi_tiled_map { - int xy2ca_map[16]; - int xy2ba_map[16]; - int xy2ra_map[16]; - int rbc2axi_map[32]; - int xy2rbc_config; - int map_type; #define GDI_LINEAR_FRAME_MAP 0 -}; +#define GDI_TILED_FRAME_MB_RASTER_MAP 1 struct coda_ctx; @@ -236,7 +229,7 @@ struct coda_ctx { int idx; int reg_idx; struct coda_iram_info iram_info; - struct gdi_tiled_map tiled_map; + int tiled_map_type; u32 bit_stream_param; u32 frm_dis_flg; u32 frame_mem_ctrl; diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index 00e4f5160c1f..3490602fa6e1 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -51,6 +51,7 @@ #define CODA7_STREAM_SEL_64BITS_ENDIAN (1 << 1) #define CODA_STREAM_ENDIAN_SELECT (1 << 0) #define CODA_REG_BIT_FRAME_MEM_CTRL 0x110 +#define CODA9_FRAME_TILED2LINEAR (1 << 11) #define CODA_FRAME_CHROMA_INTERLEAVE (1 << 2) #define CODA_IMAGE_ENDIAN_SELECT (1 << 0) #define CODA_REG_BIT_BIT_STREAM_PARAM 0x114 @@ -452,7 +453,12 @@ #define CODA9_GDI_XY2_RAS_F (CODA9_GDMA_BASE + 0x88c) #define CODA9_GDI_XY2_RBC_CONFIG (CODA9_GDMA_BASE + 0x890) +#define CODA9_XY2RBC_SEPARATE_MAP BIT(19) +#define CODA9_XY2RBC_TOP_BOT_SPLIT BIT(18) +#define CODA9_XY2RBC_TILED_MAP BIT(17) +#define CODA9_XY2RBC_CA_INC_HOR BIT(16) #define CODA9_GDI_RBC2_AXI_0 (CODA9_GDMA_BASE + 0x8a0) #define CODA9_GDI_RBC2_AXI_1F (CODA9_GDMA_BASE + 0x91c) +#define CODA9_GDI_TILEDBUF_BASE (CODA9_GDMA_BASE + 0x920) #endif -- cgit v1.3-6-gb490 From 6727d4fce95586e60922bdaf57b8a0eb99482557 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 16 Jul 2015 13:19:39 -0300 Subject: [media] coda: make NV12 format default The chroma interleaved NV12 format has higher memory bandwidth efficiency because the chroma planes can be read/written with longer burst lengths. Use NV12 as default format if available and consistently sort it first. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index d62b82846037..04310cd35bc1 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -90,17 +90,17 @@ void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 base_cb, base_cr; switch (q_data->fourcc) { - case V4L2_PIX_FMT_YVU420: - /* Switch Cb and Cr for YVU420 format */ - base_cr = base_y + q_data->bytesperline * q_data->height; - base_cb = base_cr + q_data->bytesperline * q_data->height / 4; - break; - case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_YUV420: default: base_cb = base_y + q_data->bytesperline * q_data->height; base_cr = base_cb + q_data->bytesperline * q_data->height / 4; break; + case V4L2_PIX_FMT_YVU420: + /* Switch Cb and Cr for YVU420 format */ + base_cr = base_y + q_data->bytesperline * q_data->height; + base_cb = base_cr + q_data->bytesperline * q_data->height / 4; + break; case V4L2_PIX_FMT_YUV422P: base_cb = base_y + q_data->bytesperline * q_data->height; base_cr = base_cb + q_data->bytesperline * q_data->height / 2; @@ -156,9 +156,9 @@ static const struct coda_video_device coda_bit_encoder = { .type = CODA_INST_ENCODER, .ops = &coda_bit_encode_ops, .src_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, }, .dst_formats = { V4L2_PIX_FMT_H264, @@ -171,9 +171,9 @@ static const struct coda_video_device coda_bit_jpeg_encoder = { .type = CODA_INST_ENCODER, .ops = &coda_bit_encode_ops, .src_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV422P, }, .dst_formats = { @@ -190,9 +190,9 @@ static const struct coda_video_device coda_bit_decoder = { V4L2_PIX_FMT_MPEG4, }, .dst_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, }, }; @@ -204,9 +204,9 @@ static const struct coda_video_device coda_bit_jpeg_decoder = { V4L2_PIX_FMT_JPEG, }, .dst_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV422P, }, }; @@ -234,9 +234,9 @@ static const struct coda_video_device *coda9_video_devices[] = { static u32 coda_format_normalize_yuv(u32 fourcc) { switch (fourcc) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_YUV422P: return V4L2_PIX_FMT_YUV420; default: @@ -448,9 +448,9 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, S_ALIGN); switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_NV12: /* * Frame stride must be at least multiple of 8, * but multiple of 16 for h.264 or JPEG 4:2:x @@ -1099,8 +1099,8 @@ static void set_default_params(struct coda_ctx *ctx) ctx->params.framerate = 30; /* Default formats for output and input queues */ - ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc; - ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc; + ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->cvd->src_formats[0]; + ctx->q_data[V4L2_M2M_DST].fourcc = ctx->cvd->dst_formats[0]; ctx->q_data[V4L2_M2M_SRC].width = max_w; ctx->q_data[V4L2_M2M_SRC].height = max_h; ctx->q_data[V4L2_M2M_DST].width = max_w; -- cgit v1.3-6-gb490 From 2bb4cd5cc472b191a46938becb7dafdd44644329 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 14 Jul 2015 08:15:12 -0600 Subject: block: have drivers use blk_queue_max_discard_sectors() Some drivers use it now, others just set the limits field manually. But in preparation for splitting this into a hard and soft limit, ensure that they all call the proper function for setting the hw limit for discards. Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe --- drivers/block/brd.c | 2 +- drivers/block/drbd/drbd_nl.c | 4 ++-- drivers/block/loop.c | 4 ++-- drivers/block/nbd.c | 2 +- drivers/block/nvme-core.c | 2 +- drivers/block/rbd.c | 2 +- drivers/block/skd_main.c | 2 +- drivers/block/zram/zram_drv.c | 2 +- drivers/md/bcache/super.c | 2 +- drivers/mmc/card/queue.c | 2 +- drivers/mtd/mtd_blkdevs.c | 2 +- drivers/scsi/sd.c | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 64ab4951e9d6..e573e470bd8a 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -500,7 +500,7 @@ static struct brd_device *brd_alloc(int i) blk_queue_physical_block_size(brd->brd_queue, PAGE_SIZE); brd->brd_queue->limits.discard_granularity = PAGE_SIZE; - brd->brd_queue->limits.max_discard_sectors = UINT_MAX; + blk_queue_max_discard_sectors(brd->brd_queue, UINT_MAX); brd->brd_queue->limits.discard_zeroes_data = 1; queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 74df8cfad414..e80cbefbc2b5 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1156,14 +1156,14 @@ static void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backi /* For now, don't allow more than one activity log extent worth of data * to be discarded in one go. We may need to rework drbd_al_begin_io() * to allow for even larger discard ranges */ - q->limits.max_discard_sectors = DRBD_MAX_DISCARD_SECTORS; + blk_queue_max_discard_sectors(q, DRBD_MAX_DISCARD_SECTORS); queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); /* REALLY? Is stacking secdiscard "legal"? */ if (blk_queue_secdiscard(b)) queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q); } else { - q->limits.max_discard_sectors = 0; + blk_queue_max_discard_sectors(q, 0); queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); queue_flag_clear_unlocked(QUEUE_FLAG_SECDISCARD, q); } diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f7a4c9d7f721..f9889b6bc02c 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -675,7 +675,7 @@ static void loop_config_discard(struct loop_device *lo) lo->lo_encrypt_key_size) { q->limits.discard_granularity = 0; q->limits.discard_alignment = 0; - q->limits.max_discard_sectors = 0; + blk_queue_max_discard_sectors(q, 0); q->limits.discard_zeroes_data = 0; queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); return; @@ -683,7 +683,7 @@ static void loop_config_discard(struct loop_device *lo) q->limits.discard_granularity = inode->i_sb->s_blocksize; q->limits.discard_alignment = 0; - q->limits.max_discard_sectors = UINT_MAX >> 9; + blk_queue_max_discard_sectors(q, UINT_MAX >> 9); q->limits.discard_zeroes_data = 1; queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 0e385d8e9b86..f169faf9838a 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -822,7 +822,7 @@ static int __init nbd_init(void) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue); queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, disk->queue); disk->queue->limits.discard_granularity = 512; - disk->queue->limits.max_discard_sectors = UINT_MAX; + blk_queue_max_discard_sectors(disk->queue, UINT_MAX); disk->queue->limits.discard_zeroes_data = 0; blk_queue_max_hw_sectors(disk->queue, 65536); disk->queue->limits.max_sectors = 256; diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 7920c2741b47..d844ec4a2b85 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1935,7 +1935,7 @@ static void nvme_config_discard(struct nvme_ns *ns) ns->queue->limits.discard_zeroes_data = 0; ns->queue->limits.discard_alignment = logical_block_size; ns->queue->limits.discard_granularity = logical_block_size; - ns->queue->limits.max_discard_sectors = 0xffffffff; + blk_queue_max_discard_sectors(ns->queue, 0xffffffff); queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue); } diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index d94529d5c8e9..dcc86937f55c 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3803,7 +3803,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); q->limits.discard_granularity = segment_size; q->limits.discard_alignment = segment_size; - q->limits.max_discard_sectors = segment_size / SECTOR_SIZE; + blk_queue_max_discard_sectors(q, segment_size / SECTOR_SIZE); q->limits.discard_zeroes_data = 1; blk_queue_merge_bvec(q, rbd_merge_bvec); diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 1e46eb2305c0..586f9168ffa4 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -4422,7 +4422,7 @@ static int skd_cons_disk(struct skd_device *skdev) /* DISCARD Flag initialization. */ q->limits.discard_granularity = 8192; q->limits.discard_alignment = 0; - q->limits.max_discard_sectors = UINT_MAX >> 9; + blk_queue_max_discard_sectors(q, UINT_MAX >> 9); q->limits.discard_zeroes_data = 1; queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index fb655e8d1e3b..f439ad2800da 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1244,7 +1244,7 @@ static int zram_add(void) blk_queue_io_min(zram->disk->queue, PAGE_SIZE); blk_queue_io_opt(zram->disk->queue, PAGE_SIZE); zram->disk->queue->limits.discard_granularity = PAGE_SIZE; - zram->disk->queue->limits.max_discard_sectors = UINT_MAX; + blk_queue_max_discard_sectors(zram->disk->queue, UINT_MAX); /* * zram_bio_discard() will clear all logical blocks if logical block * size is identical with physical block size(PAGE_SIZE). But if it is diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 94980bfca434..fc8e545ced18 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -830,7 +830,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size, q->limits.max_sectors = UINT_MAX; q->limits.max_segment_size = UINT_MAX; q->limits.max_segments = BIO_MAX_PAGES; - q->limits.max_discard_sectors = UINT_MAX; + blk_queue_max_discard_sectors(q, UINT_MAX); q->limits.discard_granularity = 512; q->limits.io_min = block_size; q->limits.logical_block_size = block_size; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index b5a2b145d89f..5daf302835b1 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -165,7 +165,7 @@ static void mmc_queue_setup_discard(struct request_queue *q, return; queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); - q->limits.max_discard_sectors = max_discard; + blk_queue_max_discard_sectors(q, max_discard); if (card->erased_byte == 0 && !mmc_can_discard(card)) q->limits.discard_zeroes_data = 1; q->limits.discard_granularity = card->pref_erase << 9; diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 41acc507b22e..1b96cf771d2b 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -423,7 +423,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) if (tr->discard) { queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, new->rq); - new->rq->limits.max_discard_sectors = UINT_MAX; + blk_queue_max_discard_sectors(new->rq, UINT_MAX); } gd->queue = new->rq; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3b2fcb4fada0..160e44e7b24a 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -647,7 +647,7 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) switch (mode) { case SD_LBP_DISABLE: - q->limits.max_discard_sectors = 0; + blk_queue_max_discard_sectors(q, 0); queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); return; @@ -675,7 +675,7 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) break; } - q->limits.max_discard_sectors = max_blocks * (logical_block_size >> 9); + blk_queue_max_discard_sectors(q, max_blocks * (logical_block_size >> 9)); queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); } -- cgit v1.3-6-gb490 From c13a5ccf5da86239213033214658b8a170eeab87 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 10 Jul 2015 10:49:25 -0300 Subject: [media] v4l2-mem2mem: set the queue owner field just as vb2_ioctl_reqbufs does The queue owner will be used by videobuf2 trace events to determine and record the device minor number. It is set in v4l2_m2m_reqbufs instead of v4l2_m2m_ioctl_reqbufs because several drivers implement their own vidioc_reqbufs handlers that still call v4l2_m2m_reqbufs directly. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-mem2mem.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index dc853e57f91f..af8d6b4aa807 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -357,9 +357,16 @@ int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct v4l2_requestbuffers *reqbufs) { struct vb2_queue *vq; + int ret; vq = v4l2_m2m_get_vq(m2m_ctx, reqbufs->type); - return vb2_reqbufs(vq, reqbufs); + ret = vb2_reqbufs(vq, reqbufs); + /* If count == 0, then the owner has released all buffers and he + is no longer owner of the queue. Otherwise we have an owner. */ + if (ret == 0) + vq->owner = reqbufs->count ? file->private_data : NULL; + + return ret; } EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs); -- cgit v1.3-6-gb490 From 2091f5181c66b3617a977e79843aba10e087be6c Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 10 Jul 2015 10:49:26 -0300 Subject: [media] videobuf2: add trace events Add videobuf2 specific vb2_qbuf and vb2_dqbuf trace events that mirror the v4l2_qbuf and v4l2_dqbuf trace events, only they include additional information about queue fill state and are emitted right before the buffer is enqueued in the driver or userspace is woken up. This allows to make sense of the timeline of trace events in combination with others that might be triggered by __enqueue_in_driver. Also two new trace events vb2_buf_queue and vb2_buf_done are added, allowing to trace the handover between videobuf2 framework and driver. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 11 ++++ include/trace/events/v4l2.h | 97 ++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 93b315459098..b866a6becd99 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -30,6 +30,8 @@ #include #include +#include + static int debug; module_param(debug, int, 0644); @@ -1207,6 +1209,8 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) atomic_dec(&q->owned_by_drv_count); spin_unlock_irqrestore(&q->done_lock, flags); + trace_vb2_buf_done(q, vb); + if (state == VB2_BUF_STATE_QUEUED) { if (q->start_streaming_called) __enqueue_in_driver(vb); @@ -1629,6 +1633,8 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) vb->state = VB2_BUF_STATE_ACTIVE; atomic_inc(&q->owned_by_drv_count); + trace_vb2_buf_queue(q, vb); + /* sync buffers */ for (plane = 0; plane < vb->num_planes; ++plane) call_void_memop(vb, prepare, vb->planes[plane].mem_priv); @@ -1878,6 +1884,8 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) vb->v4l2_buf.timecode = b->timecode; } + trace_vb2_qbuf(q, vb); + /* * If already streaming, give the buffer to driver for processing. * If not, the buffer will be given to driver on next streamon. @@ -2123,6 +2131,9 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n /* Remove from videobuf queue */ list_del(&vb->queued_entry); q->queued_count--; + + trace_vb2_dqbuf(q, vb); + if (!V4L2_TYPE_IS_OUTPUT(q->type) && vb->v4l2_buf.flags & V4L2_BUF_FLAG_LAST) q->last_buffer_dequeued = true; diff --git a/include/trace/events/v4l2.h b/include/trace/events/v4l2.h index 4c88a3241c18..dbf017bfddd9 100644 --- a/include/trace/events/v4l2.h +++ b/include/trace/events/v4l2.h @@ -174,6 +174,103 @@ DEFINE_EVENT(v4l2_event_class, v4l2_qbuf, TP_ARGS(minor, buf) ); +DECLARE_EVENT_CLASS(vb2_event_class, + TP_PROTO(struct vb2_queue *q, struct vb2_buffer *vb), + TP_ARGS(q, vb), + + TP_STRUCT__entry( + __field(int, minor) + __field(u32, queued_count) + __field(int, owned_by_drv_count) + __field(u32, index) + __field(u32, type) + __field(u32, bytesused) + __field(u32, flags) + __field(u32, field) + __field(s64, timestamp) + __field(u32, timecode_type) + __field(u32, timecode_flags) + __field(u8, timecode_frames) + __field(u8, timecode_seconds) + __field(u8, timecode_minutes) + __field(u8, timecode_hours) + __field(u8, timecode_userbits0) + __field(u8, timecode_userbits1) + __field(u8, timecode_userbits2) + __field(u8, timecode_userbits3) + __field(u32, sequence) + ), + + TP_fast_assign( + __entry->minor = q->owner ? q->owner->vdev->minor : -1; + __entry->queued_count = q->queued_count; + __entry->owned_by_drv_count = + atomic_read(&q->owned_by_drv_count); + __entry->index = vb->v4l2_buf.index; + __entry->type = vb->v4l2_buf.type; + __entry->bytesused = vb->v4l2_planes[0].bytesused; + __entry->flags = vb->v4l2_buf.flags; + __entry->field = vb->v4l2_buf.field; + __entry->timestamp = timeval_to_ns(&vb->v4l2_buf.timestamp); + __entry->timecode_type = vb->v4l2_buf.timecode.type; + __entry->timecode_flags = vb->v4l2_buf.timecode.flags; + __entry->timecode_frames = vb->v4l2_buf.timecode.frames; + __entry->timecode_seconds = vb->v4l2_buf.timecode.seconds; + __entry->timecode_minutes = vb->v4l2_buf.timecode.minutes; + __entry->timecode_hours = vb->v4l2_buf.timecode.hours; + __entry->timecode_userbits0 = vb->v4l2_buf.timecode.userbits[0]; + __entry->timecode_userbits1 = vb->v4l2_buf.timecode.userbits[1]; + __entry->timecode_userbits2 = vb->v4l2_buf.timecode.userbits[2]; + __entry->timecode_userbits3 = vb->v4l2_buf.timecode.userbits[3]; + __entry->sequence = vb->v4l2_buf.sequence; + ), + + TP_printk("minor = %d, queued = %u, owned_by_drv = %d, index = %u, " + "type = %s, bytesused = %u, flags = %s, field = %s, " + "timestamp = %llu, timecode = { type = %s, flags = %s, " + "frames = %u, seconds = %u, minutes = %u, hours = %u, " + "userbits = { %u %u %u %u } }, sequence = %u", __entry->minor, + __entry->queued_count, + __entry->owned_by_drv_count, + __entry->index, show_type(__entry->type), + __entry->bytesused, + show_flags(__entry->flags), + show_field(__entry->field), + __entry->timestamp, + show_timecode_type(__entry->timecode_type), + show_timecode_flags(__entry->timecode_flags), + __entry->timecode_frames, + __entry->timecode_seconds, + __entry->timecode_minutes, + __entry->timecode_hours, + __entry->timecode_userbits0, + __entry->timecode_userbits1, + __entry->timecode_userbits2, + __entry->timecode_userbits3, + __entry->sequence + ) +) + +DEFINE_EVENT(vb2_event_class, vb2_buf_done, + TP_PROTO(struct vb2_queue *q, struct vb2_buffer *vb), + TP_ARGS(q, vb) +); + +DEFINE_EVENT(vb2_event_class, vb2_buf_queue, + TP_PROTO(struct vb2_queue *q, struct vb2_buffer *vb), + TP_ARGS(q, vb) +); + +DEFINE_EVENT(vb2_event_class, vb2_dqbuf, + TP_PROTO(struct vb2_queue *q, struct vb2_buffer *vb), + TP_ARGS(q, vb) +); + +DEFINE_EVENT(vb2_event_class, vb2_qbuf, + TP_PROTO(struct vb2_queue *q, struct vb2_buffer *vb), + TP_ARGS(q, vb) +); + #endif /* if !defined(_TRACE_V4L2_H) || defined(TRACE_HEADER_MULTI_READ) */ /* This part must be outside protection */ -- cgit v1.3-6-gb490 From 17c50b700c3b46fe85e96caa1d0fc5940cc276d4 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Mon, 13 Jul 2015 23:20:11 +0200 Subject: memory: add ARM PL172 MultiPort Memory Controller driver This driver makes it possible to configure the static memory chip selects on the ARM PL172 MultiPort Memory Controller from a set of properties in DT. Configuration of dynamic memory is not supported and is left to the boot loader. The intended usage is to setup timing and configuration for static memory devices like NAND and NOR Flash before they are probed by a driver. Signed-off-by: Joachim Eastwood Signed-off-by: Olof Johansson --- drivers/memory/Kconfig | 8 ++ drivers/memory/Makefile | 1 + drivers/memory/pl172.c | 302 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 311 insertions(+) create mode 100644 drivers/memory/pl172.c (limited to 'drivers') diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 8406c668ecdc..c6a644b22af4 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -7,6 +7,14 @@ menuconfig MEMORY if MEMORY +config ARM_PL172_MPMC + tristate "ARM PL172 MPMC driver" + depends on ARM_AMBA && OF + help + This selects the ARM PrimeCell PL172 MultiPort Memory Controller. + If you have an embedded system with an AMBA bus and a PL172 + controller, say Y or M here. + config ATMEL_SDRAMC bool "Atmel (Multi-port DDR-)SDRAM Controller" default y diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index b670441e3cdf..1c46af501610 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -5,6 +5,7 @@ ifeq ($(CONFIG_DDR),y) obj-$(CONFIG_OF) += of_memory.o endif +obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o obj-$(CONFIG_TI_AEMIF) += ti-aemif.o obj-$(CONFIG_TI_EMIF) += emif.o diff --git a/drivers/memory/pl172.c b/drivers/memory/pl172.c new file mode 100644 index 000000000000..3a8e57ee96f0 --- /dev/null +++ b/drivers/memory/pl172.c @@ -0,0 +1,302 @@ +/* + * Memory controller driver for ARM PrimeCell PL172 + * PrimeCell MultiPort Memory Controller (PL172) + * + * Copyright (C) 2015 Joachim Eastwood + * + * Based on: + * TI AEMIF driver, Copyright (C) 2010 - 2013 Texas Instruments 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MPMC_STATIC_CFG(n) (0x200 + 0x20 * n) +#define MPMC_STATIC_CFG_MW_8BIT 0x0 +#define MPMC_STATIC_CFG_MW_16BIT 0x1 +#define MPMC_STATIC_CFG_MW_32BIT 0x2 +#define MPMC_STATIC_CFG_PM BIT(3) +#define MPMC_STATIC_CFG_PC BIT(6) +#define MPMC_STATIC_CFG_PB BIT(7) +#define MPMC_STATIC_CFG_EW BIT(8) +#define MPMC_STATIC_CFG_B BIT(19) +#define MPMC_STATIC_CFG_P BIT(20) +#define MPMC_STATIC_WAIT_WEN(n) (0x204 + 0x20 * n) +#define MPMC_STATIC_WAIT_WEN_MAX 0x0f +#define MPMC_STATIC_WAIT_OEN(n) (0x208 + 0x20 * n) +#define MPMC_STATIC_WAIT_OEN_MAX 0x0f +#define MPMC_STATIC_WAIT_RD(n) (0x20c + 0x20 * n) +#define MPMC_STATIC_WAIT_RD_MAX 0x1f +#define MPMC_STATIC_WAIT_PAGE(n) (0x210 + 0x20 * n) +#define MPMC_STATIC_WAIT_PAGE_MAX 0x1f +#define MPMC_STATIC_WAIT_WR(n) (0x214 + 0x20 * n) +#define MPMC_STATIC_WAIT_WR_MAX 0x1f +#define MPMC_STATIC_WAIT_TURN(n) (0x218 + 0x20 * n) +#define MPMC_STATIC_WAIT_TURN_MAX 0x0f + +/* Maximum number of static chip selects */ +#define PL172_MAX_CS 4 + +struct pl172_data { + void __iomem *base; + unsigned long rate; + struct clk *clk; +}; + +static int pl172_timing_prop(struct amba_device *adev, + const struct device_node *np, const char *name, + u32 reg_offset, u32 max, int start) +{ + struct pl172_data *pl172 = amba_get_drvdata(adev); + int cycles; + u32 val; + + if (!of_property_read_u32(np, name, &val)) { + cycles = DIV_ROUND_UP(val * pl172->rate, NSEC_PER_MSEC) - start; + if (cycles < 0) { + cycles = 0; + } else if (cycles > max) { + dev_err(&adev->dev, "%s timing too tight\n", name); + return -EINVAL; + } + + writel(cycles, pl172->base + reg_offset); + } + + dev_dbg(&adev->dev, "%s: %u cycle(s)\n", name, start + + readl(pl172->base + reg_offset)); + + return 0; +} + +static int pl172_setup_static(struct amba_device *adev, + struct device_node *np, u32 cs) +{ + struct pl172_data *pl172 = amba_get_drvdata(adev); + u32 cfg; + int ret; + + /* MPMC static memory configuration */ + if (!of_property_read_u32(np, "mpmc,memory-width", &cfg)) { + if (cfg == 8) { + cfg = MPMC_STATIC_CFG_MW_8BIT; + } else if (cfg == 16) { + cfg = MPMC_STATIC_CFG_MW_16BIT; + } else if (cfg == 32) { + cfg = MPMC_STATIC_CFG_MW_32BIT; + } else { + dev_err(&adev->dev, "invalid memory width cs%u\n", cs); + return -EINVAL; + } + } else { + dev_err(&adev->dev, "memory-width property required\n"); + return -EINVAL; + } + + if (of_property_read_bool(np, "mpmc,async-page-mode")) + cfg |= MPMC_STATIC_CFG_PM; + + if (of_property_read_bool(np, "mpmc,cs-active-high")) + cfg |= MPMC_STATIC_CFG_PC; + + if (of_property_read_bool(np, "mpmc,byte-lane-low")) + cfg |= MPMC_STATIC_CFG_PB; + + if (of_property_read_bool(np, "mpmc,extended-wait")) + cfg |= MPMC_STATIC_CFG_EW; + + if (of_property_read_bool(np, "mpmc,buffer-enable")) + cfg |= MPMC_STATIC_CFG_B; + + if (of_property_read_bool(np, "mpmc,write-protect")) + cfg |= MPMC_STATIC_CFG_P; + + writel(cfg, pl172->base + MPMC_STATIC_CFG(cs)); + dev_dbg(&adev->dev, "mpmc static config cs%u: 0x%08x\n", cs, cfg); + + /* MPMC static memory timing */ + ret = pl172_timing_prop(adev, np, "mpmc,write-enable-delay", + MPMC_STATIC_WAIT_WEN(cs), + MPMC_STATIC_WAIT_WEN_MAX, 1); + if (ret) + goto fail; + + ret = pl172_timing_prop(adev, np, "mpmc,output-enable-delay", + MPMC_STATIC_WAIT_OEN(cs), + MPMC_STATIC_WAIT_OEN_MAX, 0); + if (ret) + goto fail; + + ret = pl172_timing_prop(adev, np, "mpmc,read-access-delay", + MPMC_STATIC_WAIT_RD(cs), + MPMC_STATIC_WAIT_RD_MAX, 1); + if (ret) + goto fail; + + ret = pl172_timing_prop(adev, np, "mpmc,page-mode-read-delay", + MPMC_STATIC_WAIT_PAGE(cs), + MPMC_STATIC_WAIT_PAGE_MAX, 1); + if (ret) + goto fail; + + ret = pl172_timing_prop(adev, np, "mpmc,write-access-delay", + MPMC_STATIC_WAIT_WR(cs), + MPMC_STATIC_WAIT_WR_MAX, 2); + if (ret) + goto fail; + + ret = pl172_timing_prop(adev, np, "mpmc,turn-round-delay", + MPMC_STATIC_WAIT_TURN(cs), + MPMC_STATIC_WAIT_TURN_MAX, 1); + if (ret) + goto fail; + + return 0; +fail: + dev_err(&adev->dev, "failed to configure cs%u\n", cs); + return ret; +} + +static int pl172_parse_cs_config(struct amba_device *adev, + struct device_node *np) +{ + u32 cs; + + if (!of_property_read_u32(np, "mpmc,cs", &cs)) { + if (cs >= PL172_MAX_CS) { + dev_err(&adev->dev, "cs%u invalid\n", cs); + return -EINVAL; + } + + return pl172_setup_static(adev, np, cs); + } + + dev_err(&adev->dev, "cs property required\n"); + + return -EINVAL; +} + +static const char * const pl172_revisions[] = {"r1", "r2", "r2p3", "r2p4"}; + +static int pl172_probe(struct amba_device *adev, const struct amba_id *id) +{ + struct device_node *child_np, *np = adev->dev.of_node; + struct device *dev = &adev->dev; + static const char *rev = "?"; + struct pl172_data *pl172; + int ret; + + if (amba_part(adev) == 0x172) { + if (amba_rev(adev) < ARRAY_SIZE(pl172_revisions)) + rev = pl172_revisions[amba_rev(adev)]; + } + + dev_info(dev, "ARM PL%x revision %s\n", amba_part(adev), rev); + + pl172 = devm_kzalloc(dev, sizeof(*pl172), GFP_KERNEL); + if (!pl172) + return -ENOMEM; + + pl172->clk = devm_clk_get(dev, "mpmcclk"); + if (IS_ERR(pl172->clk)) { + dev_err(dev, "no mpmcclk provided clock\n"); + return PTR_ERR(pl172->clk); + } + + ret = clk_prepare_enable(pl172->clk); + if (ret) { + dev_err(dev, "unable to mpmcclk enable clock\n"); + return ret; + } + + pl172->rate = clk_get_rate(pl172->clk) / MSEC_PER_SEC; + if (!pl172->rate) { + dev_err(dev, "unable to get mpmcclk clock rate\n"); + ret = -EINVAL; + goto err_clk_enable; + } + + ret = amba_request_regions(adev, NULL); + if (ret) { + dev_err(dev, "unable to request AMBA regions\n"); + goto err_clk_enable; + } + + pl172->base = devm_ioremap(dev, adev->res.start, + resource_size(&adev->res)); + if (!pl172->base) { + dev_err(dev, "ioremap failed\n"); + ret = -ENOMEM; + goto err_no_ioremap; + } + + amba_set_drvdata(adev, pl172); + + /* + * Loop through each child node, which represent a chip select, and + * configure parameters and timing. If successful; populate devices + * under that node. + */ + for_each_available_child_of_node(np, child_np) { + ret = pl172_parse_cs_config(adev, child_np); + if (ret) + continue; + + of_platform_populate(child_np, of_default_bus_match_table, + NULL, dev); + } + + return 0; + +err_no_ioremap: + amba_release_regions(adev); +err_clk_enable: + clk_disable_unprepare(pl172->clk); + return ret; +} + +static int pl172_remove(struct amba_device *adev) +{ + struct pl172_data *pl172 = amba_get_drvdata(adev); + + clk_disable_unprepare(pl172->clk); + amba_release_regions(adev); + + return 0; +} + +static const struct amba_id pl172_ids[] = { + { + .id = 0x07341172, + .mask = 0xffffffff, + }, + { 0, 0 }, +}; +MODULE_DEVICE_TABLE(amba, pl172_ids); + +static struct amba_driver pl172_driver = { + .drv = { + .name = "memory-pl172", + }, + .probe = pl172_probe, + .remove = pl172_remove, + .id_table = pl172_ids, +}; +module_amba_driver(pl172_driver); + +MODULE_AUTHOR("Joachim Eastwood "); +MODULE_DESCRIPTION("PL172 Memory Controller Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From 8bf960985dfc9fcb231a07dc3102ed828f66fe81 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 14 Jul 2015 11:19:56 +0200 Subject: spi: mpc512x-psc: add support for Freescale MPC5125 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The register layout of the PSC devices differ between MPC5121 and MPC5125, but the registers are named nearly identical and their purpose is similar enough ("freescale identical") such that substituting mpc52xx_psc by mpc5125_psc is nearly enough to make the driver work on MPC5125. To keep supporting MPC5121 this patch introduces a cpp macro to select the right struct that defines the register layout. Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown --- arch/powerpc/include/asm/mpc52xx_psc.h | 5 ++- drivers/spi/spi-mpc512x-psc.c | 70 +++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/mpc52xx_psc.h b/arch/powerpc/include/asm/mpc52xx_psc.h index d0ece257d310..04c7e8fc24c2 100644 --- a/arch/powerpc/include/asm/mpc52xx_psc.h +++ b/arch/powerpc/include/asm/mpc52xx_psc.h @@ -150,7 +150,10 @@ /* Structure of the hardware registers */ struct mpc52xx_psc { - u8 mode; /* PSC + 0x00 */ + union { + u8 mode; /* PSC + 0x00 */ + u8 mr2; + }; u8 reserved0[3]; union { /* PSC + 0x04 */ u16 status; diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 965d2bdcfdcc..280794dd248a 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -30,11 +30,37 @@ #include #include +enum { + TYPE_MPC5121, + TYPE_MPC5125, +}; + +/* + * This macro abstracts the differences in the PSC register layout between + * MPC5121 (which uses a struct mpc52xx_psc) and MPC5125 (using mpc5125_psc). + */ +#define psc_addr(mps, regname) ({ \ + void *__ret; \ + switch(mps->type) { \ + case TYPE_MPC5121: { \ + struct mpc52xx_psc __iomem *psc = mps->psc; \ + __ret = &psc->regname; \ + }; \ + break; \ + case TYPE_MPC5125: { \ + struct mpc5125_psc __iomem *psc = mps->psc; \ + __ret = &psc->regname; \ + }; \ + break; \ + } \ + __ret; }) + struct mpc512x_psc_spi { void (*cs_control)(struct spi_device *spi, bool on); /* driver internal data */ - struct mpc52xx_psc __iomem *psc; + int type; + void __iomem *psc; struct mpc512x_psc_fifo __iomem *fifo; unsigned int irq; u8 bits_per_word; @@ -71,13 +97,12 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) { struct mpc512x_psc_spi_cs *cs = spi->controller_state; struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master); - struct mpc52xx_psc __iomem *psc = mps->psc; u32 sicr; u32 ccr; int speed; u16 bclkdiv; - sicr = in_be32(&psc->sicr); + sicr = in_be32(psc_addr(mps, sicr)); /* Set clock phase and polarity */ if (spi->mode & SPI_CPHA) @@ -94,9 +119,9 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) sicr |= 0x10000000; else sicr &= ~0x10000000; - out_be32(&psc->sicr, sicr); + out_be32(psc_addr(mps, sicr), sicr); - ccr = in_be32(&psc->ccr); + ccr = in_be32(psc_addr(mps, ccr)); ccr &= 0xFF000000; speed = cs->speed_hz; if (!speed) @@ -104,7 +129,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) bclkdiv = (mps->mclk_rate / speed) - 1; ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); - out_be32(&psc->ccr, ccr); + out_be32(psc_addr(mps, ccr), ccr); mps->bits_per_word = cs->bits_per_word; if (mps->cs_control && gpio_is_valid(spi->cs_gpio)) @@ -315,16 +340,15 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master, static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master) { struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); - struct mpc52xx_psc __iomem *psc = mps->psc; dev_dbg(&master->dev, "%s()\n", __func__); /* Zero MR2 */ - in_8(&psc->mode); - out_8(&psc->mode, 0x0); + in_8(psc_addr(mps, mr2)); + out_8(psc_addr(mps, mr2), 0x0); /* enable transmitter/receiver */ - out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); + out_8(psc_addr(mps, command), MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); return 0; } @@ -332,13 +356,12 @@ static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master) static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master) { struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); - struct mpc52xx_psc __iomem *psc = mps->psc; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; dev_dbg(&master->dev, "%s()\n", __func__); /* disable transmitter/receiver and fifo interrupt */ - out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); + out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); out_be32(&fifo->tximr, 0); return 0; @@ -388,7 +411,6 @@ static void mpc512x_psc_spi_cleanup(struct spi_device *spi) static int mpc512x_psc_spi_port_config(struct spi_master *master, struct mpc512x_psc_spi *mps) { - struct mpc52xx_psc __iomem *psc = mps->psc; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; u32 sicr; u32 ccr; @@ -396,12 +418,12 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, u16 bclkdiv; /* Reset the PSC into a known state */ - out_8(&psc->command, MPC52xx_PSC_RST_RX); - out_8(&psc->command, MPC52xx_PSC_RST_TX); - out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); + out_8(psc_addr(mps, command), MPC52xx_PSC_RST_RX); + out_8(psc_addr(mps, command), MPC52xx_PSC_RST_TX); + out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); /* Disable psc interrupts all useful interrupts are in fifo */ - out_be16(&psc->isr_imr.imr, 0); + out_be16(psc_addr(mps, isr_imr.imr), 0); /* Disable fifo interrupts, will be enabled later */ out_be32(&fifo->tximr, 0); @@ -417,18 +439,18 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, 0x00004000 | /* MSTR = 1 -- SPI master */ 0x00000800; /* UseEOF = 1 -- SS low until EOF */ - out_be32(&psc->sicr, sicr); + out_be32(psc_addr(mps, sicr), sicr); - ccr = in_be32(&psc->ccr); + ccr = in_be32(psc_addr(mps, ccr)); ccr &= 0xFF000000; speed = 1000000; /* default 1MHz */ bclkdiv = (mps->mclk_rate / speed) - 1; ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); - out_be32(&psc->ccr, ccr); + out_be32(psc_addr(mps, ccr), ccr); /* Set 2ms DTL delay */ - out_8(&psc->ctur, 0x00); - out_8(&psc->ctlr, 0x82); + out_8(psc_addr(mps, ctur), 0x00); + out_8(psc_addr(mps, ctlr), 0x82); /* we don't use the alarms */ out_be32(&fifo->rxalarm, 0xfff); @@ -482,6 +504,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, dev_set_drvdata(dev, master); mps = spi_master_get_devdata(master); + mps->type = (int)of_device_get_match_data(dev); mps->irq = irq; if (pdata == NULL) { @@ -589,7 +612,8 @@ static int mpc512x_psc_spi_of_remove(struct platform_device *op) } static const struct of_device_id mpc512x_psc_spi_of_match[] = { - { .compatible = "fsl,mpc5121-psc-spi", }, + { .compatible = "fsl,mpc5121-psc-spi", .data = (void *)TYPE_MPC5121 }, + { .compatible = "fsl,mpc5125-psc-spi", .data = (void *)TYPE_MPC5125 }, {}, }; -- cgit v1.3-6-gb490 From b4c45fe974bc5fa6240a729ea1f77db8b56d132a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 14 Jul 2015 23:40:35 -0700 Subject: pinctrl: qcom: ssbi: Family A gpio & mpp drivers This introduces pinctrl drivers for gpio and mpp blocks found in family A PMICs. Tested-by: Srinivas Kandagatla Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/qcom,pmic-mpp.txt | 5 + drivers/pinctrl/qcom/Kconfig | 12 + drivers/pinctrl/qcom/Makefile | 2 + drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c | 791 ++++++++++++++++++ drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c | 882 +++++++++++++++++++++ include/dt-bindings/pinctrl/qcom,pmic-mpp.h | 51 ++ 6 files changed, 1743 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c create mode 100644 drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt index b096d8351b8f..d7803a2a94e9 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt @@ -7,8 +7,13 @@ of PMIC's from Qualcomm. Usage: required Value type: Definition: Should contain one of: + "qcom,pm8018-mpp", + "qcom,pm8038-mpp", + "qcom,pm8821-mpp", "qcom,pm8841-mpp", "qcom,pm8916-mpp", + "qcom,pm8917-mpp", + "qcom,pm8921-mpp", "qcom,pm8941-mpp", "qcom,pma8084-mpp", diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 58f5632b27f4..8eef820b216e 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -76,4 +76,16 @@ config PINCTRL_QCOM_SPMI_PMIC which are using SPMI for communication with SoC. Example PMIC's devices are pm8841, pm8941 and pma8084. +config PINCTRL_QCOM_SSBI_PMIC + tristate "Qualcomm SSBI PMIC pin controller driver" + depends on GPIOLIB && OF + select PINMUX + select PINCONF + select GENERIC_PINCONF + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm GPIO and MPP blocks found in the Qualcomm PMIC's chips, + which are using SSBI for communication with SoC. Example PMIC's + devices are pm8058 and pm8921. + endif diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 3666c703ce88..e321f7ab325b 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -9,3 +9,5 @@ obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o obj-$(CONFIG_PINCTRL_MSM8916) += pinctrl-msm8916.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o +obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o +obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c new file mode 100644 index 000000000000..c978b311031b --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c @@ -0,0 +1,791 @@ +/* + * Copyright (c) 2015, Sony Mobile Communications AB. + * Copyright (c) 2013, 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 + * only 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 +#include +#include +#include +#include +#include + +#include + +#include "../core.h" +#include "../pinctrl-utils.h" + +/* mode */ +#define PM8XXX_GPIO_MODE_ENABLED BIT(0) +#define PM8XXX_GPIO_MODE_INPUT 0 +#define PM8XXX_GPIO_MODE_OUTPUT 2 + +/* output buffer */ +#define PM8XXX_GPIO_PUSH_PULL 0 +#define PM8XXX_GPIO_OPEN_DRAIN 1 + +/* bias */ +#define PM8XXX_GPIO_BIAS_PU_30 0 +#define PM8XXX_GPIO_BIAS_PU_1P5 1 +#define PM8XXX_GPIO_BIAS_PU_31P5 2 +#define PM8XXX_GPIO_BIAS_PU_1P5_30 3 +#define PM8XXX_GPIO_BIAS_PD 4 +#define PM8XXX_GPIO_BIAS_NP 5 + +/* GPIO registers */ +#define SSBI_REG_ADDR_GPIO_BASE 0x150 +#define SSBI_REG_ADDR_GPIO(n) (SSBI_REG_ADDR_GPIO_BASE + n) + +#define PM8XXX_BANK_WRITE BIT(7) + +#define PM8XXX_MAX_GPIOS 44 + +/* custom pinconf parameters */ +#define PM8XXX_QCOM_DRIVE_STRENGH (PIN_CONFIG_END + 1) +#define PM8XXX_QCOM_PULL_UP_STRENGTH (PIN_CONFIG_END + 2) + +/** + * struct pm8xxx_pin_data - dynamic configuration for a pin + * @reg: address of the control register + * @irq: IRQ from the PMIC interrupt controller + * @power_source: logical selected voltage source, mapping in static data + * is used translate to register values + * @mode: operating mode for the pin (input/output) + * @open_drain: output buffer configured as open-drain (vs push-pull) + * @output_value: configured output value + * @bias: register view of configured bias + * @pull_up_strength: placeholder for selected pull up strength + * only used to configure bias when pull up is selected + * @output_strength: selector of output-strength + * @disable: pin disabled / configured as tristate + * @function: pinmux selector + * @inverted: pin logic is inverted + */ +struct pm8xxx_pin_data { + unsigned reg; + int irq; + u8 power_source; + u8 mode; + bool open_drain; + bool output_value; + u8 bias; + u8 pull_up_strength; + u8 output_strength; + bool disable; + u8 function; + bool inverted; +}; + +struct pm8xxx_gpio { + struct device *dev; + struct regmap *regmap; + struct pinctrl_dev *pctrl; + struct gpio_chip chip; + + struct pinctrl_desc desc; + unsigned npins; +}; + +static const struct pinconf_generic_params pm8xxx_gpio_bindings[] = { + {"qcom,drive-strength", PM8XXX_QCOM_DRIVE_STRENGH, 0}, + {"qcom,pull-up-strength", PM8XXX_QCOM_PULL_UP_STRENGTH, 0}, +}; + +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item pm8xxx_conf_items[ARRAY_SIZE(pm8xxx_gpio_bindings)] = { + PCONFDUMP(PM8XXX_QCOM_DRIVE_STRENGH, "drive-strength", NULL, true), + PCONFDUMP(PM8XXX_QCOM_PULL_UP_STRENGTH, "pull up strength", NULL, true), +}; +#endif + +static const char * const pm8xxx_groups[PM8XXX_MAX_GPIOS] = { + "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8", + "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", + "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", + "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", + "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", + "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", + "gpio44", +}; + +static const char * const pm8xxx_gpio_functions[] = { + PMIC_GPIO_FUNC_NORMAL, PMIC_GPIO_FUNC_PAIRED, + PMIC_GPIO_FUNC_FUNC1, PMIC_GPIO_FUNC_FUNC2, + PMIC_GPIO_FUNC_DTEST1, PMIC_GPIO_FUNC_DTEST2, + PMIC_GPIO_FUNC_DTEST3, PMIC_GPIO_FUNC_DTEST4, +}; + +static int pm8xxx_read_bank(struct pm8xxx_gpio *pctrl, + struct pm8xxx_pin_data *pin, int bank) +{ + unsigned int val = bank << 4; + int ret; + + ret = regmap_write(pctrl->regmap, pin->reg, val); + if (ret) { + dev_err(pctrl->dev, "failed to select bank %d\n", bank); + return ret; + } + + ret = regmap_read(pctrl->regmap, pin->reg, &val); + if (ret) { + dev_err(pctrl->dev, "failed to read register %d\n", bank); + return ret; + } + + return val; +} + +static int pm8xxx_write_bank(struct pm8xxx_gpio *pctrl, + struct pm8xxx_pin_data *pin, + int bank, + u8 val) +{ + int ret; + + val |= PM8XXX_BANK_WRITE; + val |= bank << 4; + + ret = regmap_write(pctrl->regmap, pin->reg, val); + if (ret) + dev_err(pctrl->dev, "failed to write register\n"); + + return ret; +} + +static int pm8xxx_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->npins; +} + +static const char *pm8xxx_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + return pm8xxx_groups[group]; +} + + +static int pm8xxx_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, + const unsigned **pins, + unsigned *num_pins) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = &pctrl->desc.pins[group].number; + *num_pins = 1; + + return 0; +} + +static const struct pinctrl_ops pm8xxx_pinctrl_ops = { + .get_groups_count = pm8xxx_get_groups_count, + .get_group_name = pm8xxx_get_group_name, + .get_group_pins = pm8xxx_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int pm8xxx_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(pm8xxx_gpio_functions); +} + +static const char *pm8xxx_get_function_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + return pm8xxx_gpio_functions[function]; +} + +static int pm8xxx_get_function_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char * const **groups, + unsigned * const num_groups) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pm8xxx_groups; + *num_groups = pctrl->npins; + return 0; +} + +static int pm8xxx_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[group].drv_data; + u8 val; + + pin->function = function; + val = pin->function << 1; + + pm8xxx_write_bank(pctrl, pin, 4, val); + + return 0; +} + +static const struct pinmux_ops pm8xxx_pinmux_ops = { + .get_functions_count = pm8xxx_get_functions_count, + .get_function_name = pm8xxx_get_function_name, + .get_function_groups = pm8xxx_get_function_groups, + .set_mux = pm8xxx_pinmux_set_mux, +}; + +static int pm8xxx_pin_config_get(struct pinctrl_dev *pctldev, + unsigned int offset, + unsigned long *config) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + unsigned param = pinconf_to_config_param(*config); + unsigned arg; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + arg = pin->bias == PM8XXX_GPIO_BIAS_NP; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + arg = pin->bias == PM8XXX_GPIO_BIAS_PD; + break; + case PIN_CONFIG_BIAS_PULL_UP: + arg = pin->bias <= PM8XXX_GPIO_BIAS_PU_1P5_30; + break; + case PM8XXX_QCOM_PULL_UP_STRENGTH: + arg = pin->pull_up_strength; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + arg = pin->disable; + break; + case PIN_CONFIG_INPUT_ENABLE: + arg = pin->mode == PM8XXX_GPIO_MODE_INPUT; + break; + case PIN_CONFIG_OUTPUT: + if (pin->mode & PM8XXX_GPIO_MODE_OUTPUT) + arg = pin->output_value; + else + arg = 0; + break; + case PIN_CONFIG_POWER_SOURCE: + arg = pin->power_source; + break; + case PM8XXX_QCOM_DRIVE_STRENGH: + arg = pin->output_strength; + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + arg = !pin->open_drain; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + arg = pin->open_drain; + break; + default: + return -EINVAL; + } + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int pm8xxx_pin_config_set(struct pinctrl_dev *pctldev, + unsigned int offset, + unsigned long *configs, + unsigned num_configs) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + unsigned param; + unsigned arg; + unsigned i; + u8 banks = 0; + u8 val; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + pin->bias = PM8XXX_GPIO_BIAS_NP; + banks |= BIT(2); + pin->disable = 0; + banks |= BIT(3); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + pin->bias = PM8XXX_GPIO_BIAS_PD; + banks |= BIT(2); + pin->disable = 0; + banks |= BIT(3); + break; + case PM8XXX_QCOM_PULL_UP_STRENGTH: + if (arg > PM8XXX_GPIO_BIAS_PU_1P5_30) { + dev_err(pctrl->dev, "invalid pull-up strength\n"); + return -EINVAL; + } + pin->pull_up_strength = arg; + /* FALLTHROUGH */ + case PIN_CONFIG_BIAS_PULL_UP: + pin->bias = pin->pull_up_strength; + banks |= BIT(2); + pin->disable = 0; + banks |= BIT(3); + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + pin->disable = 1; + banks |= BIT(3); + break; + case PIN_CONFIG_INPUT_ENABLE: + pin->mode = PM8XXX_GPIO_MODE_INPUT; + banks |= BIT(0) | BIT(1); + break; + case PIN_CONFIG_OUTPUT: + pin->mode = PM8XXX_GPIO_MODE_OUTPUT; + pin->output_value = !!arg; + banks |= BIT(0) | BIT(1); + break; + case PIN_CONFIG_POWER_SOURCE: + pin->power_source = arg; + banks |= BIT(0); + break; + case PM8XXX_QCOM_DRIVE_STRENGH: + if (arg > PMIC_GPIO_STRENGTH_LOW) { + dev_err(pctrl->dev, "invalid drive strength\n"); + return -EINVAL; + } + pin->output_strength = arg; + banks |= BIT(3); + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + pin->open_drain = 0; + banks |= BIT(1); + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + pin->open_drain = 1; + banks |= BIT(1); + break; + default: + dev_err(pctrl->dev, + "unsupported config parameter: %x\n", + param); + return -EINVAL; + } + } + + if (banks & BIT(0)) { + val = pin->power_source << 1; + val |= PM8XXX_GPIO_MODE_ENABLED; + pm8xxx_write_bank(pctrl, pin, 0, val); + } + + if (banks & BIT(1)) { + val = pin->mode << 2; + val |= pin->open_drain << 1; + val |= pin->output_value; + pm8xxx_write_bank(pctrl, pin, 1, val); + } + + if (banks & BIT(2)) { + val = pin->bias << 1; + pm8xxx_write_bank(pctrl, pin, 2, val); + } + + if (banks & BIT(3)) { + val = pin->output_strength << 2; + val |= pin->disable; + pm8xxx_write_bank(pctrl, pin, 3, val); + } + + if (banks & BIT(4)) { + val = pin->function << 1; + pm8xxx_write_bank(pctrl, pin, 4, val); + } + + if (banks & BIT(5)) { + val = 0; + if (!pin->inverted) + val |= BIT(3); + pm8xxx_write_bank(pctrl, pin, 5, val); + } + + return 0; +} + +static const struct pinconf_ops pm8xxx_pinconf_ops = { + .is_generic = true, + .pin_config_group_get = pm8xxx_pin_config_get, + .pin_config_group_set = pm8xxx_pin_config_set, +}; + +static struct pinctrl_desc pm8xxx_pinctrl_desc = { + .name = "pm8xxx_gpio", + .pctlops = &pm8xxx_pinctrl_ops, + .pmxops = &pm8xxx_pinmux_ops, + .confops = &pm8xxx_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int pm8xxx_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + u8 val; + + pin->mode = PM8XXX_GPIO_MODE_INPUT; + val = pin->mode << 2; + + pm8xxx_write_bank(pctrl, pin, 1, val); + + return 0; +} + +static int pm8xxx_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, + int value) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + u8 val; + + pin->mode = PM8XXX_GPIO_MODE_OUTPUT; + pin->output_value = !!value; + + val = pin->mode << 2; + val |= pin->open_drain << 1; + val |= pin->output_value; + + pm8xxx_write_bank(pctrl, pin, 1, val); + + return 0; +} + +static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + bool state; + int ret; + + if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT) { + ret = pin->output_value; + } else { + ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state); + if (!ret) + ret = !!state; + } + + return ret; +} + +static void pm8xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + u8 val; + + pin->output_value = !!value; + + val = pin->mode << 2; + val |= pin->open_drain << 1; + val |= pin->output_value; + + pm8xxx_write_bank(pctrl, pin, 1, val); +} + +static int pm8xxx_gpio_of_xlate(struct gpio_chip *chip, + const struct of_phandle_args *gpio_desc, + u32 *flags) +{ + if (chip->of_gpio_n_cells < 2) + return -EINVAL; + + if (flags) + *flags = gpio_desc->args[1]; + + return gpio_desc->args[0] - 1; +} + + +static int pm8xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + return pin->irq; +} + +#ifdef CONFIG_DEBUG_FS +#include + +static void pm8xxx_gpio_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, + struct gpio_chip *chip, + unsigned offset, + unsigned gpio) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + static const char * const modes[] = { + "in", "both", "out", "off" + }; + static const char * const biases[] = { + "pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA", + "pull-up 1.5uA + 30uA boost", "pull-down 10uA", "no pull" + }; + static const char * const buffer_types[] = { + "push-pull", "open-drain" + }; + static const char * const strengths[] = { + "no", "high", "medium", "low" + }; + + seq_printf(s, " gpio%-2d:", offset + 1); + if (pin->disable) { + seq_puts(s, " ---"); + } else { + seq_printf(s, " %-4s", modes[pin->mode]); + seq_printf(s, " %-7s", pm8xxx_gpio_functions[pin->function]); + seq_printf(s, " VIN%d", pin->power_source); + seq_printf(s, " %-27s", biases[pin->bias]); + seq_printf(s, " %-10s", buffer_types[pin->open_drain]); + seq_printf(s, " %-4s", pin->output_value ? "high" : "low"); + seq_printf(s, " %-7s", strengths[pin->output_strength]); + if (pin->inverted) + seq_puts(s, " inverted"); + } +} + +static void pm8xxx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + unsigned gpio = chip->base; + unsigned i; + + for (i = 0; i < chip->ngpio; i++, gpio++) { + pm8xxx_gpio_dbg_show_one(s, NULL, chip, i, gpio); + seq_puts(s, "\n"); + } +} + +#else +#define msm_gpio_dbg_show NULL +#endif + +static struct gpio_chip pm8xxx_gpio_template = { + .direction_input = pm8xxx_gpio_direction_input, + .direction_output = pm8xxx_gpio_direction_output, + .get = pm8xxx_gpio_get, + .set = pm8xxx_gpio_set, + .of_xlate = pm8xxx_gpio_of_xlate, + .to_irq = pm8xxx_gpio_to_irq, + .dbg_show = pm8xxx_gpio_dbg_show, + .owner = THIS_MODULE, +}; + +static int pm8xxx_pin_populate(struct pm8xxx_gpio *pctrl, + struct pm8xxx_pin_data *pin) +{ + int val; + + val = pm8xxx_read_bank(pctrl, pin, 0); + if (val < 0) + return val; + + pin->power_source = (val >> 1) & 0x7; + + val = pm8xxx_read_bank(pctrl, pin, 1); + if (val < 0) + return val; + + pin->mode = (val >> 2) & 0x3; + pin->open_drain = !!(val & BIT(1)); + pin->output_value = val & BIT(0); + + val = pm8xxx_read_bank(pctrl, pin, 2); + if (val < 0) + return val; + + pin->bias = (val >> 1) & 0x7; + if (pin->bias <= PM8XXX_GPIO_BIAS_PU_1P5_30) + pin->pull_up_strength = pin->bias; + else + pin->pull_up_strength = PM8XXX_GPIO_BIAS_PU_30; + + val = pm8xxx_read_bank(pctrl, pin, 3); + if (val < 0) + return val; + + pin->output_strength = (val >> 2) & 0x3; + pin->disable = val & BIT(0); + + val = pm8xxx_read_bank(pctrl, pin, 4); + if (val < 0) + return val; + + pin->function = (val >> 1) & 0x7; + + val = pm8xxx_read_bank(pctrl, pin, 5); + if (val < 0) + return val; + + pin->inverted = !(val & BIT(3)); + + return 0; +} + +static const struct of_device_id pm8xxx_gpio_of_match[] = { + { .compatible = "qcom,pm8018-gpio", .data = (void *)6 }, + { .compatible = "qcom,pm8038-gpio", .data = (void *)12 }, + { .compatible = "qcom,pm8058-gpio", .data = (void *)40 }, + { .compatible = "qcom,pm8917-gpio", .data = (void *)38 }, + { .compatible = "qcom,pm8921-gpio", .data = (void *)44 }, + { }, +}; +MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match); + +static int pm8xxx_gpio_probe(struct platform_device *pdev) +{ + struct pm8xxx_pin_data *pin_data; + struct pinctrl_pin_desc *pins; + struct pm8xxx_gpio *pctrl; + int ret; + int i; + + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->dev = &pdev->dev; + pctrl->npins = (unsigned)of_device_get_match_data(&pdev->dev); + + pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!pctrl->regmap) { + dev_err(&pdev->dev, "parent regmap unavailable\n"); + return -ENXIO; + } + + pctrl->desc = pm8xxx_pinctrl_desc; + pctrl->desc.npins = pctrl->npins; + + pins = devm_kcalloc(&pdev->dev, + pctrl->desc.npins, + sizeof(struct pinctrl_pin_desc), + GFP_KERNEL); + if (!pins) + return -ENOMEM; + + pin_data = devm_kcalloc(&pdev->dev, + pctrl->desc.npins, + sizeof(struct pm8xxx_pin_data), + GFP_KERNEL); + if (!pin_data) + return -ENOMEM; + + for (i = 0; i < pctrl->desc.npins; i++) { + pin_data[i].reg = SSBI_REG_ADDR_GPIO(i); + pin_data[i].irq = platform_get_irq(pdev, i); + if (pin_data[i].irq < 0) { + dev_err(&pdev->dev, + "missing interrupts for pin %d\n", i); + return pin_data[i].irq; + } + + ret = pm8xxx_pin_populate(pctrl, &pin_data[i]); + if (ret) + return ret; + + pins[i].number = i; + pins[i].name = pm8xxx_groups[i]; + pins[i].drv_data = &pin_data[i]; + } + pctrl->desc.pins = pins; + + pctrl->desc.num_custom_params = ARRAY_SIZE(pm8xxx_gpio_bindings); + pctrl->desc.custom_params = pm8xxx_gpio_bindings; +#ifdef CONFIG_DEBUG_FS + pctrl->desc.custom_conf_items = pm8xxx_conf_items; +#endif + + pctrl->pctrl = pinctrl_register(&pctrl->desc, &pdev->dev, pctrl); + if (!pctrl->pctrl) { + dev_err(&pdev->dev, "couldn't register pm8xxx gpio driver\n"); + return -ENODEV; + } + + pctrl->chip = pm8xxx_gpio_template; + pctrl->chip.base = -1; + pctrl->chip.dev = &pdev->dev; + pctrl->chip.of_node = pdev->dev.of_node; + pctrl->chip.of_gpio_n_cells = 2; + pctrl->chip.label = dev_name(pctrl->dev); + pctrl->chip.ngpio = pctrl->npins; + ret = gpiochip_add(&pctrl->chip); + if (ret) { + dev_err(&pdev->dev, "failed register gpiochip\n"); + goto unregister_pinctrl; + } + + ret = gpiochip_add_pin_range(&pctrl->chip, + dev_name(pctrl->dev), + 0, 0, pctrl->chip.ngpio); + if (ret) { + dev_err(pctrl->dev, "failed to add pin range\n"); + goto unregister_gpiochip; + } + + platform_set_drvdata(pdev, pctrl); + + dev_dbg(&pdev->dev, "Qualcomm pm8xxx gpio driver probed\n"); + + return 0; + +unregister_gpiochip: + gpiochip_remove(&pctrl->chip); + +unregister_pinctrl: + pinctrl_unregister(pctrl->pctrl); + + return ret; +} + +static int pm8xxx_gpio_remove(struct platform_device *pdev) +{ + struct pm8xxx_gpio *pctrl = platform_get_drvdata(pdev); + + gpiochip_remove(&pctrl->chip); + + pinctrl_unregister(pctrl->pctrl); + + return 0; +} + +static struct platform_driver pm8xxx_gpio_driver = { + .driver = { + .name = "qcom-ssbi-gpio", + .of_match_table = pm8xxx_gpio_of_match, + }, + .probe = pm8xxx_gpio_probe, + .remove = pm8xxx_gpio_remove, +}; + +module_platform_driver(pm8xxx_gpio_driver); + +MODULE_AUTHOR("Bjorn Andersson "); +MODULE_DESCRIPTION("Qualcomm PM8xxx GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c new file mode 100644 index 000000000000..2d1b69f171be --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c @@ -0,0 +1,882 @@ +/* + * Copyright (c) 2015, Sony Mobile Communications AB. + * Copyright (c) 2013, 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 + * only 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 +#include +#include +#include +#include +#include + +#include + +#include "../core.h" +#include "../pinctrl-utils.h" + +/* MPP registers */ +#define SSBI_REG_ADDR_MPP_BASE 0x50 +#define SSBI_REG_ADDR_MPP(n) (SSBI_REG_ADDR_MPP_BASE + n) + +/* MPP Type: type */ +#define PM8XXX_MPP_TYPE_D_INPUT 0 +#define PM8XXX_MPP_TYPE_D_OUTPUT 1 +#define PM8XXX_MPP_TYPE_D_BI_DIR 2 +#define PM8XXX_MPP_TYPE_A_INPUT 3 +#define PM8XXX_MPP_TYPE_A_OUTPUT 4 +#define PM8XXX_MPP_TYPE_SINK 5 +#define PM8XXX_MPP_TYPE_DTEST_SINK 6 +#define PM8XXX_MPP_TYPE_DTEST_OUTPUT 7 + +/* Digital Input: control */ +#define PM8XXX_MPP_DIN_TO_INT 0 +#define PM8XXX_MPP_DIN_TO_DBUS1 1 +#define PM8XXX_MPP_DIN_TO_DBUS2 2 +#define PM8XXX_MPP_DIN_TO_DBUS3 3 + +/* Digital Output: control */ +#define PM8XXX_MPP_DOUT_CTRL_LOW 0 +#define PM8XXX_MPP_DOUT_CTRL_HIGH 1 +#define PM8XXX_MPP_DOUT_CTRL_MPP 2 +#define PM8XXX_MPP_DOUT_CTRL_INV_MPP 3 + +/* Bidirectional: control */ +#define PM8XXX_MPP_BI_PULLUP_1KOHM 0 +#define PM8XXX_MPP_BI_PULLUP_OPEN 1 +#define PM8XXX_MPP_BI_PULLUP_10KOHM 2 +#define PM8XXX_MPP_BI_PULLUP_30KOHM 3 + +/* Analog Output: control */ +#define PM8XXX_MPP_AOUT_CTRL_DISABLE 0 +#define PM8XXX_MPP_AOUT_CTRL_ENABLE 1 +#define PM8XXX_MPP_AOUT_CTRL_MPP_HIGH_EN 2 +#define PM8XXX_MPP_AOUT_CTRL_MPP_LOW_EN 3 + +/* Current Sink: control */ +#define PM8XXX_MPP_CS_CTRL_DISABLE 0 +#define PM8XXX_MPP_CS_CTRL_ENABLE 1 +#define PM8XXX_MPP_CS_CTRL_MPP_HIGH_EN 2 +#define PM8XXX_MPP_CS_CTRL_MPP_LOW_EN 3 + +/* DTEST Current Sink: control */ +#define PM8XXX_MPP_DTEST_CS_CTRL_EN1 0 +#define PM8XXX_MPP_DTEST_CS_CTRL_EN2 1 +#define PM8XXX_MPP_DTEST_CS_CTRL_EN3 2 +#define PM8XXX_MPP_DTEST_CS_CTRL_EN4 3 + +/* DTEST Digital Output: control */ +#define PM8XXX_MPP_DTEST_DBUS1 0 +#define PM8XXX_MPP_DTEST_DBUS2 1 +#define PM8XXX_MPP_DTEST_DBUS3 2 +#define PM8XXX_MPP_DTEST_DBUS4 3 + +/* custom pinconf parameters */ +#define PM8XXX_CONFIG_AMUX (PIN_CONFIG_END + 1) +#define PM8XXX_CONFIG_DTEST_SELECTOR (PIN_CONFIG_END + 2) +#define PM8XXX_CONFIG_ALEVEL (PIN_CONFIG_END + 3) +#define PM8XXX_CONFIG_PAIRED (PIN_CONFIG_END + 4) + +/** + * struct pm8xxx_pin_data - dynamic configuration for a pin + * @reg: address of the control register + * @irq: IRQ from the PMIC interrupt controller + * @mode: operating mode for the pin (digital, analog or current sink) + * @input: pin is input + * @output: pin is output + * @high_z: pin is floating + * @paired: mpp operates in paired mode + * @output_value: logical output value of the mpp + * @power_source: selected power source + * @dtest: DTEST route selector + * @amux: input muxing in analog mode + * @aout_level: selector of the output in analog mode + * @drive_strength: drive strength of the current sink + * @pullup: pull up value, when in digital bidirectional mode + */ +struct pm8xxx_pin_data { + unsigned reg; + int irq; + + u8 mode; + + bool input; + bool output; + bool high_z; + bool paired; + bool output_value; + + u8 power_source; + u8 dtest; + u8 amux; + u8 aout_level; + u8 drive_strength; + unsigned pullup; +}; + +struct pm8xxx_mpp { + struct device *dev; + struct regmap *regmap; + struct pinctrl_dev *pctrl; + struct gpio_chip chip; + + struct pinctrl_desc desc; + unsigned npins; +}; + +static const struct pinconf_generic_params pm8xxx_mpp_bindings[] = { + {"qcom,amux-route", PM8XXX_CONFIG_AMUX, 0}, + {"qcom,analog-level", PM8XXX_CONFIG_ALEVEL, 0}, + {"qcom,dtest", PM8XXX_CONFIG_DTEST_SELECTOR, 0}, + {"qcom,paired", PM8XXX_CONFIG_PAIRED, 0}, +}; + +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item pm8xxx_conf_items[] = { + PCONFDUMP(PM8XXX_CONFIG_AMUX, "analog mux", NULL, true), + PCONFDUMP(PM8XXX_CONFIG_ALEVEL, "analog level", NULL, true), + PCONFDUMP(PM8XXX_CONFIG_DTEST_SELECTOR, "dtest", NULL, true), + PCONFDUMP(PM8XXX_CONFIG_PAIRED, "paired", NULL, false), +}; +#endif + +#define PM8XXX_MAX_MPPS 12 +static const char * const pm8xxx_groups[PM8XXX_MAX_MPPS] = { + "mpp1", "mpp2", "mpp3", "mpp4", "mpp5", "mpp6", "mpp7", "mpp8", + "mpp9", "mpp10", "mpp11", "mpp12", +}; + +#define PM8XXX_MPP_DIGITAL 0 +#define PM8XXX_MPP_ANALOG 1 +#define PM8XXX_MPP_SINK 2 + +static const char * const pm8xxx_mpp_functions[] = { + "digital", "analog", "sink", +}; + +static int pm8xxx_mpp_update(struct pm8xxx_mpp *pctrl, + struct pm8xxx_pin_data *pin) +{ + unsigned level; + unsigned ctrl; + unsigned type; + int ret; + u8 val; + + switch (pin->mode) { + case PM8XXX_MPP_DIGITAL: + if (pin->dtest) { + type = PM8XXX_MPP_TYPE_DTEST_OUTPUT; + ctrl = pin->dtest - 1; + } else if (pin->input && pin->output) { + type = PM8XXX_MPP_TYPE_D_BI_DIR; + if (pin->high_z) + ctrl = PM8XXX_MPP_BI_PULLUP_OPEN; + else if (pin->pullup == 600) + ctrl = PM8XXX_MPP_BI_PULLUP_1KOHM; + else if (pin->pullup == 10000) + ctrl = PM8XXX_MPP_BI_PULLUP_10KOHM; + else + ctrl = PM8XXX_MPP_BI_PULLUP_30KOHM; + } else if (pin->input) { + type = PM8XXX_MPP_TYPE_D_INPUT; + if (pin->dtest) + ctrl = pin->dtest; + else + ctrl = PM8XXX_MPP_DIN_TO_INT; + } else { + type = PM8XXX_MPP_TYPE_D_OUTPUT; + ctrl = !!pin->output_value; + if (pin->paired) + ctrl |= BIT(1); + } + + level = pin->power_source; + break; + case PM8XXX_MPP_ANALOG: + if (pin->output) { + type = PM8XXX_MPP_TYPE_A_OUTPUT; + level = pin->aout_level; + ctrl = pin->output_value; + if (pin->paired) + ctrl |= BIT(1); + } else { + type = PM8XXX_MPP_TYPE_A_INPUT; + level = pin->amux; + ctrl = 0; + } + break; + case PM8XXX_MPP_SINK: + level = (pin->drive_strength / 5) - 1; + if (pin->dtest) { + type = PM8XXX_MPP_TYPE_DTEST_SINK; + ctrl = pin->dtest - 1; + } else { + type = PM8XXX_MPP_TYPE_SINK; + ctrl = pin->output_value; + if (pin->paired) + ctrl |= BIT(1); + } + break; + default: + return -EINVAL; + } + + val = type << 5 | level << 2 | ctrl; + ret = regmap_write(pctrl->regmap, pin->reg, val); + if (ret) + dev_err(pctrl->dev, "failed to write register\n"); + + return ret; +} + +static int pm8xxx_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->npins; +} + +static const char *pm8xxx_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + return pm8xxx_groups[group]; +} + + +static int pm8xxx_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, + const unsigned **pins, + unsigned *num_pins) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = &pctrl->desc.pins[group].number; + *num_pins = 1; + + return 0; +} + +static const struct pinctrl_ops pm8xxx_pinctrl_ops = { + .get_groups_count = pm8xxx_get_groups_count, + .get_group_name = pm8xxx_get_group_name, + .get_group_pins = pm8xxx_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int pm8xxx_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(pm8xxx_mpp_functions); +} + +static const char *pm8xxx_get_function_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + return pm8xxx_mpp_functions[function]; +} + +static int pm8xxx_get_function_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char * const **groups, + unsigned * const num_groups) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pm8xxx_groups; + *num_groups = pctrl->npins; + return 0; +} + +static int pm8xxx_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[group].drv_data; + + pin->mode = function; + pm8xxx_mpp_update(pctrl, pin); + + return 0; +} + +static const struct pinmux_ops pm8xxx_pinmux_ops = { + .get_functions_count = pm8xxx_get_functions_count, + .get_function_name = pm8xxx_get_function_name, + .get_function_groups = pm8xxx_get_function_groups, + .set_mux = pm8xxx_pinmux_set_mux, +}; + +static int pm8xxx_pin_config_get(struct pinctrl_dev *pctldev, + unsigned int offset, + unsigned long *config) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + unsigned param = pinconf_to_config_param(*config); + unsigned arg; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + arg = pin->pullup; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + arg = pin->high_z; + break; + case PIN_CONFIG_INPUT_ENABLE: + arg = pin->input; + break; + case PIN_CONFIG_OUTPUT: + arg = pin->output_value; + break; + case PIN_CONFIG_POWER_SOURCE: + arg = pin->power_source; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + arg = pin->drive_strength; + break; + case PM8XXX_CONFIG_DTEST_SELECTOR: + arg = pin->dtest; + break; + case PM8XXX_CONFIG_AMUX: + arg = pin->amux; + break; + case PM8XXX_CONFIG_ALEVEL: + arg = pin->aout_level; + break; + case PM8XXX_CONFIG_PAIRED: + arg = pin->paired; + break; + default: + return -EINVAL; + } + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int pm8xxx_pin_config_set(struct pinctrl_dev *pctldev, + unsigned int offset, + unsigned long *configs, + unsigned num_configs) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + unsigned param; + unsigned arg; + unsigned i; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + pin->pullup = arg; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + pin->high_z = true; + break; + case PIN_CONFIG_INPUT_ENABLE: + pin->input = true; + break; + case PIN_CONFIG_OUTPUT: + pin->output = true; + pin->output_value = !!arg; + break; + case PIN_CONFIG_POWER_SOURCE: + pin->power_source = arg; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + pin->drive_strength = arg; + break; + case PM8XXX_CONFIG_DTEST_SELECTOR: + pin->dtest = arg; + break; + case PM8XXX_CONFIG_AMUX: + pin->amux = arg; + break; + case PM8XXX_CONFIG_ALEVEL: + pin->aout_level = arg; + break; + case PM8XXX_CONFIG_PAIRED: + pin->paired = !!arg; + break; + default: + dev_err(pctrl->dev, + "unsupported config parameter: %x\n", + param); + return -EINVAL; + } + } + + pm8xxx_mpp_update(pctrl, pin); + + return 0; +} + +static const struct pinconf_ops pm8xxx_pinconf_ops = { + .is_generic = true, + .pin_config_group_get = pm8xxx_pin_config_get, + .pin_config_group_set = pm8xxx_pin_config_set, +}; + +static struct pinctrl_desc pm8xxx_pinctrl_desc = { + .name = "pm8xxx_mpp", + .pctlops = &pm8xxx_pinctrl_ops, + .pmxops = &pm8xxx_pinmux_ops, + .confops = &pm8xxx_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int pm8xxx_mpp_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + switch (pin->mode) { + case PM8XXX_MPP_DIGITAL: + pin->input = true; + break; + case PM8XXX_MPP_ANALOG: + pin->input = true; + pin->output = true; + break; + case PM8XXX_MPP_SINK: + return -EINVAL; + } + + pm8xxx_mpp_update(pctrl, pin); + + return 0; +} + +static int pm8xxx_mpp_direction_output(struct gpio_chip *chip, + unsigned offset, + int value) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + switch (pin->mode) { + case PM8XXX_MPP_DIGITAL: + pin->output = true; + break; + case PM8XXX_MPP_ANALOG: + pin->input = false; + pin->output = true; + break; + case PM8XXX_MPP_SINK: + pin->input = false; + pin->output = true; + break; + } + + pm8xxx_mpp_update(pctrl, pin); + + return 0; +} + +static int pm8xxx_mpp_get(struct gpio_chip *chip, unsigned offset) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + bool state; + int ret; + + if (!pin->input) + return pin->output_value; + + ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state); + if (!ret) + ret = !!state; + + return ret; +} + +static void pm8xxx_mpp_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + pin->output_value = !!value; + + pm8xxx_mpp_update(pctrl, pin); +} + +static int pm8xxx_mpp_of_xlate(struct gpio_chip *chip, + const struct of_phandle_args *gpio_desc, + u32 *flags) +{ + if (chip->of_gpio_n_cells < 2) + return -EINVAL; + + if (flags) + *flags = gpio_desc->args[1]; + + return gpio_desc->args[0] - 1; +} + + +static int pm8xxx_mpp_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + return pin->irq; +} + +#ifdef CONFIG_DEBUG_FS +#include + +static void pm8xxx_mpp_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, + struct gpio_chip *chip, + unsigned offset, + unsigned gpio) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + static const char * const aout_lvls[] = { + "1v25", "1v25_2", "0v625", "0v3125", "mpp", "abus1", "abus2", + "abus3" + }; + + static const char * const amuxs[] = { + "amux5", "amux6", "amux7", "amux8", "amux9", "abus1", "abus2", + "abus3", + }; + + seq_printf(s, " mpp%-2d:", offset + 1); + + switch (pin->mode) { + case PM8XXX_MPP_DIGITAL: + seq_puts(s, " digital "); + if (pin->dtest) { + seq_printf(s, "dtest%d\n", pin->dtest); + } else if (pin->input && pin->output) { + if (pin->high_z) + seq_puts(s, "bi-dir high-z"); + else + seq_printf(s, "bi-dir %dOhm", pin->pullup); + } else if (pin->input) { + if (pin->dtest) + seq_printf(s, "in dtest%d", pin->dtest); + else + seq_puts(s, "in gpio"); + } else if (pin->output) { + seq_puts(s, "out "); + + if (!pin->paired) { + seq_puts(s, pin->output_value ? + "high" : "low"); + } else { + seq_puts(s, pin->output_value ? + "inverted" : "follow"); + } + } + break; + case PM8XXX_MPP_ANALOG: + seq_puts(s, " analog "); + if (pin->output) { + seq_printf(s, "out %s ", aout_lvls[pin->aout_level]); + if (!pin->paired) { + seq_puts(s, pin->output_value ? + "high" : "low"); + } else { + seq_puts(s, pin->output_value ? + "inverted" : "follow"); + } + } else { + seq_printf(s, "input mux %s", amuxs[pin->amux]); + } + break; + case PM8XXX_MPP_SINK: + seq_printf(s, " sink %dmA ", pin->drive_strength); + if (pin->dtest) { + seq_printf(s, "dtest%d", pin->dtest); + } else { + if (!pin->paired) { + seq_puts(s, pin->output_value ? + "high" : "low"); + } else { + seq_puts(s, pin->output_value ? + "inverted" : "follow"); + } + } + break; + } + +} + +static void pm8xxx_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + unsigned gpio = chip->base; + unsigned i; + + for (i = 0; i < chip->ngpio; i++, gpio++) { + pm8xxx_mpp_dbg_show_one(s, NULL, chip, i, gpio); + seq_puts(s, "\n"); + } +} + +#else +#define msm_mpp_dbg_show NULL +#endif + +static struct gpio_chip pm8xxx_mpp_template = { + .direction_input = pm8xxx_mpp_direction_input, + .direction_output = pm8xxx_mpp_direction_output, + .get = pm8xxx_mpp_get, + .set = pm8xxx_mpp_set, + .of_xlate = pm8xxx_mpp_of_xlate, + .to_irq = pm8xxx_mpp_to_irq, + .dbg_show = pm8xxx_mpp_dbg_show, + .owner = THIS_MODULE, +}; + +static int pm8xxx_pin_populate(struct pm8xxx_mpp *pctrl, + struct pm8xxx_pin_data *pin) +{ + unsigned int val; + unsigned level; + unsigned ctrl; + unsigned type; + int ret; + + ret = regmap_read(pctrl->regmap, pin->reg, &val); + if (ret) { + dev_err(pctrl->dev, "failed to read register\n"); + return ret; + } + + type = (val >> 5) & 7; + level = (val >> 2) & 7; + ctrl = (val) & 3; + + switch (type) { + case PM8XXX_MPP_TYPE_D_INPUT: + pin->mode = PM8XXX_MPP_DIGITAL; + pin->input = true; + pin->power_source = level; + pin->dtest = ctrl; + break; + case PM8XXX_MPP_TYPE_D_OUTPUT: + pin->mode = PM8XXX_MPP_DIGITAL; + pin->output = true; + pin->power_source = level; + pin->output_value = !!(ctrl & BIT(0)); + pin->paired = !!(ctrl & BIT(1)); + break; + case PM8XXX_MPP_TYPE_D_BI_DIR: + pin->mode = PM8XXX_MPP_DIGITAL; + pin->input = true; + pin->output = true; + pin->power_source = level; + switch (ctrl) { + case PM8XXX_MPP_BI_PULLUP_1KOHM: + pin->pullup = 600; + break; + case PM8XXX_MPP_BI_PULLUP_OPEN: + pin->high_z = true; + break; + case PM8XXX_MPP_BI_PULLUP_10KOHM: + pin->pullup = 10000; + break; + case PM8XXX_MPP_BI_PULLUP_30KOHM: + pin->pullup = 30000; + break; + } + break; + case PM8XXX_MPP_TYPE_A_INPUT: + pin->mode = PM8XXX_MPP_ANALOG; + pin->input = true; + pin->amux = level; + break; + case PM8XXX_MPP_TYPE_A_OUTPUT: + pin->mode = PM8XXX_MPP_ANALOG; + pin->output = true; + pin->aout_level = level; + pin->output_value = !!(ctrl & BIT(0)); + pin->paired = !!(ctrl & BIT(1)); + break; + case PM8XXX_MPP_TYPE_SINK: + pin->mode = PM8XXX_MPP_SINK; + pin->drive_strength = 5 * (level + 1); + pin->output_value = !!(ctrl & BIT(0)); + pin->paired = !!(ctrl & BIT(1)); + break; + case PM8XXX_MPP_TYPE_DTEST_SINK: + pin->mode = PM8XXX_MPP_SINK; + pin->dtest = ctrl + 1; + pin->drive_strength = 5 * (level + 1); + break; + case PM8XXX_MPP_TYPE_DTEST_OUTPUT: + pin->mode = PM8XXX_MPP_DIGITAL; + pin->power_source = level; + if (ctrl >= 1) + pin->dtest = ctrl; + break; + } + + return 0; +} + +static const struct of_device_id pm8xxx_mpp_of_match[] = { + { .compatible = "qcom,pm8018-mpp", .data = (void *)6 }, + { .compatible = "qcom,pm8038-mpp", .data = (void *)6 }, + { .compatible = "qcom,pm8917-mpp", .data = (void *)10 }, + { .compatible = "qcom,pm8821-mpp", .data = (void *)4 }, + { .compatible = "qcom,pm8921-mpp", .data = (void *)12 }, + { }, +}; +MODULE_DEVICE_TABLE(of, pm8xxx_mpp_of_match); + +static int pm8xxx_mpp_probe(struct platform_device *pdev) +{ + struct pm8xxx_pin_data *pin_data; + struct pinctrl_pin_desc *pins; + struct pm8xxx_mpp *pctrl; + int ret; + int i; + + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->dev = &pdev->dev; + pctrl->npins = (unsigned)of_device_get_match_data(&pdev->dev); + + pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!pctrl->regmap) { + dev_err(&pdev->dev, "parent regmap unavailable\n"); + return -ENXIO; + } + + pctrl->desc = pm8xxx_pinctrl_desc; + pctrl->desc.npins = pctrl->npins; + + pins = devm_kcalloc(&pdev->dev, + pctrl->desc.npins, + sizeof(struct pinctrl_pin_desc), + GFP_KERNEL); + if (!pins) + return -ENOMEM; + + pin_data = devm_kcalloc(&pdev->dev, + pctrl->desc.npins, + sizeof(struct pm8xxx_pin_data), + GFP_KERNEL); + if (!pin_data) + return -ENOMEM; + + for (i = 0; i < pctrl->desc.npins; i++) { + pin_data[i].reg = SSBI_REG_ADDR_MPP(i); + pin_data[i].irq = platform_get_irq(pdev, i); + if (pin_data[i].irq < 0) { + dev_err(&pdev->dev, + "missing interrupts for pin %d\n", i); + return pin_data[i].irq; + } + + ret = pm8xxx_pin_populate(pctrl, &pin_data[i]); + if (ret) + return ret; + + pins[i].number = i; + pins[i].name = pm8xxx_groups[i]; + pins[i].drv_data = &pin_data[i]; + } + pctrl->desc.pins = pins; + + pctrl->desc.num_custom_params = ARRAY_SIZE(pm8xxx_mpp_bindings); + pctrl->desc.custom_params = pm8xxx_mpp_bindings; +#ifdef CONFIG_DEBUG_FS + pctrl->desc.custom_conf_items = pm8xxx_conf_items; +#endif + + pctrl->pctrl = pinctrl_register(&pctrl->desc, &pdev->dev, pctrl); + if (!pctrl->pctrl) { + dev_err(&pdev->dev, "couldn't register pm8xxx mpp driver\n"); + return -ENODEV; + } + + pctrl->chip = pm8xxx_mpp_template; + pctrl->chip.base = -1; + pctrl->chip.dev = &pdev->dev; + pctrl->chip.of_node = pdev->dev.of_node; + pctrl->chip.of_gpio_n_cells = 2; + pctrl->chip.label = dev_name(pctrl->dev); + pctrl->chip.ngpio = pctrl->npins; + ret = gpiochip_add(&pctrl->chip); + if (ret) { + dev_err(&pdev->dev, "failed register gpiochip\n"); + goto unregister_pinctrl; + } + + ret = gpiochip_add_pin_range(&pctrl->chip, + dev_name(pctrl->dev), + 0, 0, pctrl->chip.ngpio); + if (ret) { + dev_err(pctrl->dev, "failed to add pin range\n"); + goto unregister_gpiochip; + } + + platform_set_drvdata(pdev, pctrl); + + dev_dbg(&pdev->dev, "Qualcomm pm8xxx mpp driver probed\n"); + + return 0; + +unregister_gpiochip: + gpiochip_remove(&pctrl->chip); + +unregister_pinctrl: + pinctrl_unregister(pctrl->pctrl); + + return ret; +} + +static int pm8xxx_mpp_remove(struct platform_device *pdev) +{ + struct pm8xxx_mpp *pctrl = platform_get_drvdata(pdev); + + gpiochip_remove(&pctrl->chip); + + pinctrl_unregister(pctrl->pctrl); + + return 0; +} + +static struct platform_driver pm8xxx_mpp_driver = { + .driver = { + .name = "qcom-ssbi-mpp", + .of_match_table = pm8xxx_mpp_of_match, + }, + .probe = pm8xxx_mpp_probe, + .remove = pm8xxx_mpp_remove, +}; + +module_platform_driver(pm8xxx_mpp_driver); + +MODULE_AUTHOR("Bjorn Andersson "); +MODULE_DESCRIPTION("Qualcomm PM8xxx MPP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/dt-bindings/pinctrl/qcom,pmic-mpp.h b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h index c10205491f8d..a15c1704d0ec 100644 --- a/include/dt-bindings/pinctrl/qcom,pmic-mpp.h +++ b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h @@ -7,6 +7,47 @@ #define _DT_BINDINGS_PINCTRL_QCOM_PMIC_MPP_H /* power-source */ + +/* Digital Input/Output: level [PM8058] */ +#define PM8058_MPP_VPH 0 +#define PM8058_MPP_S3 1 +#define PM8058_MPP_L2 2 +#define PM8058_MPP_L3 3 + +/* Digital Input/Output: level [PM8901] */ +#define PM8901_MPP_MSMIO 0 +#define PM8901_MPP_DIG 1 +#define PM8901_MPP_L5 2 +#define PM8901_MPP_S4 3 +#define PM8901_MPP_VPH 4 + +/* Digital Input/Output: level [PM8921] */ +#define PM8921_MPP_S4 1 +#define PM8921_MPP_L15 3 +#define PM8921_MPP_L17 4 +#define PM8921_MPP_VPH 7 + +/* Digital Input/Output: level [PM8821] */ +#define PM8821_MPP_1P8 0 +#define PM8821_MPP_VPH 7 + +/* Digital Input/Output: level [PM8018] */ +#define PM8018_MPP_L4 0 +#define PM8018_MPP_L14 1 +#define PM8018_MPP_S3 2 +#define PM8018_MPP_L6 3 +#define PM8018_MPP_L2 4 +#define PM8018_MPP_L5 5 +#define PM8018_MPP_VPH 7 + +/* Digital Input/Output: level [PM8038] */ +#define PM8038_MPP_L20 0 +#define PM8038_MPP_L11 1 +#define PM8038_MPP_L5 2 +#define PM8038_MPP_L15 3 +#define PM8038_MPP_L17 4 +#define PM8038_MPP_VPH 7 + #define PM8841_MPP_VPH 0 #define PM8841_MPP_S3 2 @@ -37,6 +78,16 @@ #define PMIC_MPP_AMUX_ROUTE_ABUS3 6 #define PMIC_MPP_AMUX_ROUTE_ABUS4 7 +/* Analog Output: level */ +#define PMIC_MPP_AOUT_LVL_1V25 0 +#define PMIC_MPP_AOUT_LVL_1V25_2 1 +#define PMIC_MPP_AOUT_LVL_0V625 2 +#define PMIC_MPP_AOUT_LVL_0V3125 3 +#define PMIC_MPP_AOUT_LVL_MPP 4 +#define PMIC_MPP_AOUT_LVL_ABUS1 5 +#define PMIC_MPP_AOUT_LVL_ABUS2 6 +#define PMIC_MPP_AOUT_LVL_ABUS3 7 + /* To be used with "function" */ #define PMIC_MPP_FUNC_NORMAL "normal" #define PMIC_MPP_FUNC_PAIRED "paired" -- cgit v1.3-6-gb490 From 8f1338cd80648adf5434798f5393ad7c55d10848 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Wed, 15 Jul 2015 11:47:14 -0500 Subject: pinctrl: add support for Qualcomm Technologies QDF2xxx ARM64 SoCs Add the pinctrl driver for the Qualcomm Technologies QDF2xxx ARM64 SoCs, which uses the Qualcomm Technologies TLMM pinctrl/gpio device. This driver is probed via ACPI and uses the pinctrl-msm.c backend driver. This driver is intended to be used only an ACPI-enabled system. As such, UEFI will handle all pin control configuration, so this driver does not provide pin control functions. It is effectively a GPIO-only driver. Signed-off-by: Timur Tabi Reviewed-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/Kconfig | 8 +++ drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-qdf2xxx.c | 122 +++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-qdf2xxx.c (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 8eef820b216e..383263a92e59 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -63,6 +63,14 @@ config PINCTRL_MSM8916 This is the pinctrl, pinmux, pinconf and gpiolib driver for the Qualcomm TLMM block found on the Qualcomm 8916 platform. +config PINCTRL_QDF2XXX + tristate "Qualcomm Technologies QDF2xxx pin controller driver" + depends on GPIOLIB && ACPI + select PINCTRL_MSM + help + This is the GPIO driver for the TLMM block found on the + Qualcomm Technologies QDF2xxx SOCs. + config PINCTRL_QCOM_SPMI_PMIC tristate "Qualcomm SPMI PMIC pin controller driver" depends on GPIOLIB && OF && SPMI diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index e321f7ab325b..13b190e72c21 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_PINCTRL_MSM8660) += pinctrl-msm8660.o obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o obj-$(CONFIG_PINCTRL_MSM8916) += pinctrl-msm8916.o +obj-$(CONFIG_PINCTRL_QDF2XXX) += pinctrl-qdf2xxx.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o diff --git a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c new file mode 100644 index 000000000000..e9ff3bc150bb --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015, 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 + * only 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. + * + * GPIO and pin control functions on this SOC are handled by the "TLMM" + * device. The driver which controls this device is pinctrl-msm.c. Each + * SOC with a TLMM is expected to create a client driver that registers + * with pinctrl-msm.c. This means that all TLMM drivers are pin control + * drivers. + * + * This pin control driver is intended to be used only an ACPI-enabled + * system. As such, UEFI will handle all pin control configuration, so + * this driver does not provide pin control functions. It is effectively + * a GPIO-only driver. The alternative is to duplicate the GPIO code of + * pinctrl-msm.c into another driver. + */ + +#include +#include +#include +#include + +#include "pinctrl-msm.h" + +static struct msm_pinctrl_soc_data qdf2xxx_pinctrl; + +static int qdf2xxx_pinctrl_probe(struct platform_device *pdev) +{ + struct pinctrl_pin_desc *pins; + struct msm_pingroup *groups; + unsigned int i; + u32 num_gpios; + int ret; + + /* Query the number of GPIOs from ACPI */ + ret = device_property_read_u32(&pdev->dev, "num-gpios", &num_gpios); + if (ret < 0) + return ret; + + if (!num_gpios) { + dev_warn(&pdev->dev, "missing num-gpios property\n"); + return -ENODEV; + } + + pins = devm_kcalloc(&pdev->dev, num_gpios, + sizeof(struct pinctrl_pin_desc), GFP_KERNEL); + groups = devm_kcalloc(&pdev->dev, num_gpios, + sizeof(struct msm_pingroup), GFP_KERNEL); + + for (i = 0; i < num_gpios; i++) { + pins[i].number = i; + + groups[i].npins = 1, + groups[i].pins = &pins[i].number; + groups[i].ctl_reg = 0x10000 * i; + groups[i].io_reg = 0x04 + 0x10000 * i; + groups[i].intr_cfg_reg = 0x08 + 0x10000 * i; + groups[i].intr_status_reg = 0x0c + 0x10000 * i; + groups[i].intr_target_reg = 0x08 + 0x10000 * i; + + groups[i].mux_bit = 2; + groups[i].pull_bit = 0; + groups[i].drv_bit = 6; + groups[i].oe_bit = 9; + groups[i].in_bit = 0; + groups[i].out_bit = 1; + groups[i].intr_enable_bit = 0; + groups[i].intr_status_bit = 0; + groups[i].intr_target_bit = 5; + groups[i].intr_target_kpss_val = 1; + groups[i].intr_raw_status_bit = 4; + groups[i].intr_polarity_bit = 1; + groups[i].intr_detection_bit = 2; + groups[i].intr_detection_width = 2; + } + + qdf2xxx_pinctrl.pins = pins; + qdf2xxx_pinctrl.groups = groups; + qdf2xxx_pinctrl.npins = num_gpios; + qdf2xxx_pinctrl.ngroups = num_gpios; + qdf2xxx_pinctrl.ngpios = num_gpios; + + return msm_pinctrl_probe(pdev, &qdf2xxx_pinctrl); +} + +static const struct acpi_device_id qdf2xxx_acpi_ids[] = { + {"QCOM8001"}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, qdf2xxx_acpi_ids); + +static struct platform_driver qdf2xxx_pinctrl_driver = { + .driver = { + .name = "qdf2xxx-pinctrl", + .acpi_match_table = ACPI_PTR(qdf2xxx_acpi_ids), + }, + .probe = qdf2xxx_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init qdf2xxx_pinctrl_init(void) +{ + return platform_driver_register(&qdf2xxx_pinctrl_driver); +} +arch_initcall(qdf2xxx_pinctrl_init); + +static void __exit qdf2xxx_pinctrl_exit(void) +{ + platform_driver_unregister(&qdf2xxx_pinctrl_driver); +} +module_exit(qdf2xxx_pinctrl_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies QDF2xxx pin control driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From 03051bc242209f7130aec42d1a6ecb3be9f8f93b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:06 +0200 Subject: pinctrl/rockchip: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 9affcd725776..626a4a6287e8 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1689,8 +1689,8 @@ static int rockchip_interrupts_register(struct platform_device *pdev, gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type; gc->wake_enabled = IRQ_MSK(bank->nr_pins); - irq_set_handler_data(bank->irq, bank); - irq_set_chained_handler(bank->irq, rockchip_irq_demux); + irq_set_chained_handler_and_data(bank->irq, + rockchip_irq_demux, bank); } return 0; -- cgit v1.3-6-gb490 From 20d5d142a645600f28cf42b8e3336f7309897b1e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:06 +0200 Subject: pinctrl: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-single.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 1cd085d92147..07661c86f7ef 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1767,9 +1767,9 @@ static int pcs_irq_init_chained_handler(struct pcs_device *pcs, return res; } } else { - irq_set_handler_data(pcs_soc->irq, pcs_soc); - irq_set_chained_handler(pcs_soc->irq, - pcs_irq_chain_handler); + irq_set_chained_handler_and_data(pcs_soc->irq, + pcs_irq_chain_handler, + pcs_soc); } /* -- cgit v1.3-6-gb490 From c21f7849f126570c0bb1ececbb3ddba7b20cfc03 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:07 +0200 Subject: pinctrl/exynos: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/samsung/pinctrl-exynos.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index b18dabba03a4..14b02fcedb4b 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -542,8 +542,9 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) } weint_data[idx].irq = idx; weint_data[idx].bank = bank; - irq_set_handler_data(irq, &weint_data[idx]); - irq_set_chained_handler(irq, exynos_irq_eint0_15); + irq_set_chained_handler_and_data(irq, + exynos_irq_eint0_15, + &weint_data[idx]); } } -- cgit v1.3-6-gb490 From 1aa74fd0bb2cc344c18a625fa1d8e75c00b9bbf8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:41 +0200 Subject: pinctrl/bcm2835: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index efcf2a2b3975..104d8a63bbce 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -584,9 +584,9 @@ static int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type) ret = __bcm2835_gpio_irq_set_type_disabled(pc, gpio, type); if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(data->irq, handle_edge_irq); + irq_set_handler_locked(data, handle_edge_irq); else - __irq_set_handler_locked(data->irq, handle_level_irq); + irq_set_handler_locked(data, handle_level_irq); spin_unlock_irqrestore(&pc->irq_lock[bank], flags); -- cgit v1.3-6-gb490 From f3a085b4174e5806e2e6543323f9a70435ca0098 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:44 +0200 Subject: pinctrl/baytrail: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/intel/pinctrl-baytrail.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 2062c224e32f..8834fa9df87f 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -265,9 +265,9 @@ static int byt_irq_type(struct irq_data *d, unsigned type) writel(value, reg); if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else if (type & IRQ_TYPE_LEVEL_MASK) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); spin_unlock_irqrestore(&vg->lock, flags); -- cgit v1.3-6-gb490 From a4e3f7830fb742039c2c24535af931df3d6d2124 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:44 +0200 Subject: pinctrl/cherryview: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/intel/pinctrl-cherryview.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index 3f737daa3fd2..ab87f5c5e9df 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1325,7 +1325,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d) spin_lock_irqsave(&pctrl->lock, flags); if (!pctrl->intr_lines[intsel]) { - __irq_set_handler_locked(d->irq, handler); + irq_set_handler_locked(d, handler); pctrl->intr_lines[intsel] = offset; } spin_unlock_irqrestore(&pctrl->lock, flags); @@ -1389,9 +1389,9 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type) pctrl->intr_lines[value] = offset; if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else if (type & IRQ_TYPE_LEVEL_MASK) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); spin_unlock_irqrestore(&pctrl->lock, flags); -- cgit v1.3-6-gb490 From fc756bcd6aadbc59fa7142521729c8d38096ef9c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:45 +0200 Subject: pinctrl/intel: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/intel/pinctrl-intel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index f9ee0d68b288..27e4aa6971d1 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -758,9 +758,9 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type) writel(value, reg); if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else if (type & IRQ_TYPE_LEVEL_MASK) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); spin_unlock_irqrestore(&pctrl->lock, flags); -- cgit v1.3-6-gb490 From e0d6a2c6cefc50f123a2386686738820d9a088c6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:47 +0200 Subject: pinctrl/adi2: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and update was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-adi2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c index c3c3d2345fc6..a5976ebc4482 100644 --- a/drivers/pinctrl/pinctrl-adi2.c +++ b/drivers/pinctrl/pinctrl-adi2.c @@ -427,10 +427,10 @@ static int adi_gpio_irq_type(struct irq_data *d, unsigned int type) if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { writel(pintmask, &pint_regs->edge_set); - __irq_set_handler_locked(irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); } else { writel(pintmask, &pint_regs->edge_clear); - __irq_set_handler_locked(irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); } out: -- cgit v1.3-6-gb490 From 9d8293147e8a09ac42018cfeb672cc0a3b90f65b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:47 +0200 Subject: pinctrl/amd: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-amd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index d8e3f7c7fea3..ef72a8a8dc20 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -420,7 +420,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); pin_reg |= ACTIVE_HIGH << ACTIVE_LEVEL_OFF; pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF; - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); break; case IRQ_TYPE_EDGE_FALLING: @@ -428,7 +428,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); pin_reg |= ACTIVE_LOW << ACTIVE_LEVEL_OFF; pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF; - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); break; case IRQ_TYPE_EDGE_BOTH: @@ -436,7 +436,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); pin_reg |= BOTH_EADGE << ACTIVE_LEVEL_OFF; pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF; - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); break; case IRQ_TYPE_LEVEL_HIGH: @@ -445,7 +445,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin_reg |= ACTIVE_HIGH << ACTIVE_LEVEL_OFF; pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF); pin_reg |= DB_TYPE_PRESERVE_LOW_GLITCH << DB_CNTRL_OFF; - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); break; case IRQ_TYPE_LEVEL_LOW: @@ -454,7 +454,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin_reg |= ACTIVE_LOW << ACTIVE_LEVEL_OFF; pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF); pin_reg |= DB_TYPE_PRESERVE_HIGH_GLITCH << DB_CNTRL_OFF; - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); break; case IRQ_TYPE_NONE: -- cgit v1.3-6-gb490 From c639845bcb87df4abffab94d72bd165d203c34a1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:49 +0200 Subject: pinctrl/at91: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-at91.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index a0824477072b..6cec3861dff7 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1444,22 +1444,22 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type) switch (type) { case IRQ_TYPE_EDGE_RISING: - __irq_set_handler_locked(d->irq, handle_simple_irq); + irq_set_handler_locked(d, handle_simple_irq); writel_relaxed(mask, pio + PIO_ESR); writel_relaxed(mask, pio + PIO_REHLSR); break; case IRQ_TYPE_EDGE_FALLING: - __irq_set_handler_locked(d->irq, handle_simple_irq); + irq_set_handler_locked(d, handle_simple_irq); writel_relaxed(mask, pio + PIO_ESR); writel_relaxed(mask, pio + PIO_FELLSR); break; case IRQ_TYPE_LEVEL_LOW: - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); writel_relaxed(mask, pio + PIO_LSR); writel_relaxed(mask, pio + PIO_FELLSR); break; case IRQ_TYPE_LEVEL_HIGH: - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); writel_relaxed(mask, pio + PIO_LSR); writel_relaxed(mask, pio + PIO_REHLSR); break; @@ -1468,7 +1468,7 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type) * disable additional interrupt modes: * fall back to default behavior */ - __irq_set_handler_locked(d->irq, handle_simple_irq); + irq_set_handler_locked(d, handle_simple_irq); writel_relaxed(mask, pio + PIO_AIMDR); return 0; case IRQ_TYPE_NONE: -- cgit v1.3-6-gb490 From 2dbf1bc5a29c5912679d687d2a826f201e75e89d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:50 +0200 Subject: pinctrl/rockchip: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 626a4a6287e8..6e56c962b655 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1555,9 +1555,9 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) spin_unlock_irqrestore(&bank->slock, flags); if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); spin_lock_irqsave(&bank->slock, flags); irq_gc_lock(gc); -- cgit v1.3-6-gb490 From 34c0ad84f316e19f06af3c2764fe20cac110d985 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:51 +0200 Subject: pinctrl/qcom: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/qcom/pinctrl-msm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 6242af8a42d5..367ddbf518f7 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -734,9 +734,9 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) spin_unlock_irqrestore(&pctrl->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); return 0; } -- cgit v1.3-6-gb490 From 40ec168ace3b963ddf768919ce96461ed885f9c8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:57 +0200 Subject: pinctrl/exynos: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/samsung/pinctrl-exynos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 14b02fcedb4b..f402eff2867a 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -148,9 +148,9 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type) } if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(irqd->irq, handle_edge_irq); + irq_set_handler_locked(irqd, handle_edge_irq); else - __irq_set_handler_locked(irqd->irq, handle_level_irq); + irq_set_handler_locked(irqd, handle_level_irq); con = readl(d->virt_base + reg_con); con &= ~(EXYNOS_EINT_CON_MASK << shift); -- cgit v1.3-6-gb490 From f66eb498ff131d52f9c7b73f0a25a5e3b9095528 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:57 +0200 Subject: pinctrl/samsung: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 8 ++++---- drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index 01b43dbfb795..7a77eae60b83 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -131,13 +131,13 @@ static int s3c24xx_eint_get_trigger(unsigned int type) } } -static void s3c24xx_eint_set_handler(unsigned int irq, unsigned int type) +static void s3c24xx_eint_set_handler(struct irq_data *d, unsigned int type) { /* Edge- and level-triggered interrupts need different handlers */ if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else - __irq_set_handler_locked(irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); } static void s3c24xx_eint_set_function(struct samsung_pinctrl_drv_data *d, @@ -181,7 +181,7 @@ static int s3c24xx_eint_type(struct irq_data *data, unsigned int type) return -EINVAL; } - s3c24xx_eint_set_handler(data->irq, type); + s3c24xx_eint_set_handler(data, type); /* Set up interrupt trigger */ reg = d->virt_base + EINT_REG(index); diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index ec8cc3b47621..41050f4c67dc 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -260,13 +260,13 @@ static int s3c64xx_irq_get_trigger(unsigned int type) return trigger; } -static void s3c64xx_irq_set_handler(unsigned int irq, unsigned int type) +static void s3c64xx_irq_set_handler(struct irq_data *d, unsigned int type) { /* Edge- and level-triggered interrupts need different handlers */ if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else - __irq_set_handler_locked(irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); } static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d, @@ -356,7 +356,7 @@ static int s3c64xx_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) return -EINVAL; } - s3c64xx_irq_set_handler(irqd->irq, type); + s3c64xx_irq_set_handler(irqd, type); /* Set up interrupt trigger */ reg = d->virt_base + EINTCON_REG(bank->eint_offset); @@ -567,7 +567,7 @@ static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type) return -EINVAL; } - s3c64xx_irq_set_handler(irqd->irq, type); + s3c64xx_irq_set_handler(irqd, type); /* Set up interrupt trigger */ reg = d->virt_base + EINT0CON0_REG; -- cgit v1.3-6-gb490 From 5663bb27dec1a2bfaf9d92e3685834b91a36a5a3 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:16 +0800 Subject: pinctrl: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. Signed-off-by: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org Signed-off-by: Thomas Gleixner --- drivers/pinctrl/intel/pinctrl-cherryview.c | 2 +- drivers/pinctrl/intel/pinctrl-intel.c | 2 +- drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 4 ++-- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 12 +++++------- drivers/pinctrl/pinctrl-amd.c | 2 +- drivers/pinctrl/pinctrl-at91.c | 2 +- drivers/pinctrl/pinctrl-coh901.c | 4 ++-- drivers/pinctrl/pinctrl-rockchip.c | 4 ++-- drivers/pinctrl/pinctrl-single.c | 2 +- drivers/pinctrl/pinctrl-st.c | 6 +++--- drivers/pinctrl/qcom/pinctrl-msm.c | 2 +- drivers/pinctrl/samsung/pinctrl-exynos.c | 8 ++++---- drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 18 +++++++++--------- drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 22 ++++++++++------------ drivers/pinctrl/sirf/pinctrl-sirf.c | 2 +- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 4 ++-- 16 files changed, 46 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index ab87f5c5e9df..f9a476765736 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1412,7 +1412,7 @@ static void chv_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc); - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned long pending; u32 intr_line; diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 27e4aa6971d1..bb377c110541 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -840,7 +840,7 @@ static void intel_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(gc); - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); int i; chained_irq_enter(chip, desc); diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index ad1ea1695b4a..4be0124e9936 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -1118,8 +1118,8 @@ mtk_eint_debounce_process(struct mtk_pinctrl *pctl, int index) static void mtk_eint_irq_handler(unsigned irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct mtk_pinctrl *pctl = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct mtk_pinctrl *pctl = irq_desc_get_handler_data(desc); unsigned int status, eint_num; int offset, index, virq; const struct mtk_eint_offsets *eint_offsets = diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 809d88445db5..56e79c12562e 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -843,10 +843,9 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d) clk_disable(nmk_chip->clk); } -static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, - u32 status) +static void __nmk_gpio_irq_handler(struct irq_desc *desc, u32 status) { - struct irq_chip *host_chip = irq_get_chip(irq); + struct irq_chip *host_chip = irq_desc_get_chip(desc); struct gpio_chip *chip = irq_desc_get_handler_data(desc); chained_irq_enter(host_chip, desc); @@ -871,17 +870,16 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) status = readl(nmk_chip->addr + NMK_GPIO_IS); clk_disable(nmk_chip->clk); - __nmk_gpio_irq_handler(irq, desc, status); + __nmk_gpio_irq_handler(desc, status); } -static void nmk_gpio_latent_irq_handler(unsigned int irq, - struct irq_desc *desc) +static void nmk_gpio_latent_irq_handler(unsigned int irq, struct irq_desc *desc) { struct gpio_chip *chip = irq_desc_get_handler_data(desc); struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); u32 status = nmk_chip->get_latent_status(nmk_chip->bank); - __nmk_gpio_irq_handler(irq, desc, status); + __nmk_gpio_irq_handler(desc, status); } /* I/O Functions */ diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index ef72a8a8dc20..2663a055546e 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -501,7 +501,7 @@ static void amd_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) u64 reg64; int handled = 0; unsigned long flags; - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct amd_gpio *gpio_dev = to_amd_gpio(gc); diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 6cec3861dff7..e1ab69928bba 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1596,7 +1596,7 @@ static struct irq_chip gpio_irqchip = { static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); struct gpio_chip *gpio_chip = irq_desc_get_handler_data(desc); struct at91_gpio_chip *at91_gpio = container_of(gpio_chip, struct at91_gpio_chip, chip); diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 29cbbab8c3a6..9579442a221d 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -521,8 +521,8 @@ static struct irq_chip u300_gpio_irqchip = { static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { - struct irq_chip *parent_chip = irq_get_chip(irq); - struct gpio_chip *chip = irq_get_handler_data(irq); + struct irq_chip *parent_chip = irq_desc_get_chip(desc); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); struct u300_gpio *gpio = to_u300_gpio(chip); struct u300_gpio_port *port = &gpio->ports[irq - chip->base]; int pinoffset = port->number << 3; /* get the right stride */ diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 6e56c962b655..28f9d08faf27 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1471,8 +1471,8 @@ static const struct gpio_chip rockchip_gpiolib_chip = { static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct rockchip_pin_bank *bank = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct rockchip_pin_bank *bank = irq_desc_get_handler_data(desc); u32 pend; dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name); diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 07661c86f7ef..b8aaf9559ddd 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1684,7 +1684,7 @@ static void pcs_irq_chain_handler(unsigned int irq, struct irq_desc *desc) struct pcs_soc_data *pcs_soc = irq_desc_get_handler_data(desc); struct irq_chip *chip; - chip = irq_get_chip(irq); + chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); pcs_irq_handle(pcs_soc); /* REVISIT: export and add handle_bad_irq(irq, desc)? */ diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index c262e5f35c28..f8338d2e6b6b 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -1463,7 +1463,7 @@ static void __gpio_irq_handler(struct st_gpio_bank *bank) static void st_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { /* interrupt dedicated per bank */ - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct st_gpio_bank *bank = gpio_chip_to_bank(gc); @@ -1474,8 +1474,8 @@ static void st_gpio_irq_handler(unsigned irq, struct irq_desc *desc) static void st_gpio_irqmux_handler(unsigned irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct st_pinctrl *info = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct st_pinctrl *info = irq_desc_get_handler_data(desc); unsigned long status; int n; diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 367ddbf518f7..3fd39921b3e8 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -770,7 +770,7 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) struct gpio_chip *gc = irq_desc_get_handler_data(desc); const struct msm_pingroup *g; struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); int irq_pin; int handled = 0; u32 val; diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index f402eff2867a..07773c70c12c 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -422,9 +422,9 @@ static const struct of_device_id exynos_wkup_irq_ids[] = { /* interrupt handler for wakeup interrupts 0..15 */ static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) { - struct exynos_weint_data *eintd = irq_get_handler_data(irq); + struct exynos_weint_data *eintd = irq_desc_get_handler_data(desc); struct samsung_pin_bank *bank = eintd->bank; - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); int eint_irq; chained_irq_enter(chip, desc); @@ -454,8 +454,8 @@ static inline void exynos_irq_demux_eint(unsigned long pend, /* interrupt handler for wakeup interrupt 16 */ static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct exynos_muxed_weint_data *eintd = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct exynos_muxed_weint_data *eintd = irq_desc_get_handler_data(desc); struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata; unsigned long pend; unsigned long mask; diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index 7a77eae60b83..5d7b6112fc7e 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -243,7 +243,7 @@ static struct irq_chip s3c2410_eint0_3_chip = { static void s3c2410_demux_eint0_3(unsigned int irq, struct irq_desc *desc) { struct irq_data *data = irq_desc_get_irq_data(desc); - struct s3c24xx_eint_data *eint_data = irq_get_handler_data(irq); + struct s3c24xx_eint_data *eint_data = irq_desc_get_handler_data(desc); unsigned int virq; /* the first 4 eints have a simple 1 to 1 mapping */ @@ -297,9 +297,9 @@ static struct irq_chip s3c2412_eint0_3_chip = { static void s3c2412_demux_eint0_3(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); + struct s3c24xx_eint_data *eint_data = irq_desc_get_handler_data(desc); struct irq_data *data = irq_desc_get_irq_data(desc); - struct s3c24xx_eint_data *eint_data = irq_get_handler_data(irq); + struct irq_chip *chip = irq_data_get_irq_chip(data); unsigned int virq; chained_irq_enter(chip, desc); @@ -357,11 +357,11 @@ static struct irq_chip s3c24xx_eint_chip = { .irq_set_type = s3c24xx_eint_type, }; -static inline void s3c24xx_demux_eint(unsigned int irq, struct irq_desc *desc, +static inline void s3c24xx_demux_eint(struct irq_desc *desc, u32 offset, u32 range) { - struct irq_chip *chip = irq_get_chip(irq); - struct s3c24xx_eint_data *data = irq_get_handler_data(irq); + struct s3c24xx_eint_data *data = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_irq_chip(desc); struct samsung_pinctrl_drv_data *d = data->drvdata; unsigned int pend, mask; @@ -374,7 +374,7 @@ static inline void s3c24xx_demux_eint(unsigned int irq, struct irq_desc *desc, pend &= range; while (pend) { - unsigned int virq; + unsigned int virq, irq; irq = __ffs(pend); pend &= ~(1 << irq); @@ -390,12 +390,12 @@ static inline void s3c24xx_demux_eint(unsigned int irq, struct irq_desc *desc, static void s3c24xx_demux_eint4_7(unsigned int irq, struct irq_desc *desc) { - s3c24xx_demux_eint(irq, desc, 0, 0xf0); + s3c24xx_demux_eint(desc, 0, 0xf0); } static void s3c24xx_demux_eint8_23(unsigned int irq, struct irq_desc *desc) { - s3c24xx_demux_eint(irq, desc, 8, 0xffff00); + s3c24xx_demux_eint(desc, 8, 0xffff00); } static irq_flow_handler_t s3c2410_eint_handlers[NUM_EINT_IRQ] = { diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index 41050f4c67dc..8700f0c9eee1 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -410,8 +410,8 @@ static const struct irq_domain_ops s3c64xx_gpio_irqd_ops = { static void s3c64xx_eint_gpio_irq(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct s3c64xx_eint_gpio_data *data = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct s3c64xx_eint_gpio_data *data = irq_desc_get_handler_data(desc); struct samsung_pinctrl_drv_data *drvdata = data->drvdata; chained_irq_enter(chip, desc); @@ -599,11 +599,10 @@ static struct irq_chip s3c64xx_eint0_irq_chip = { .irq_set_type = s3c64xx_eint0_irq_set_type, }; -static inline void s3c64xx_irq_demux_eint(unsigned int irq, - struct irq_desc *desc, u32 range) +static inline void s3c64xx_irq_demux_eint(struct irq_desc *desc, u32 range) { - struct irq_chip *chip = irq_get_chip(irq); - struct s3c64xx_eint0_data *data = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct s3c64xx_eint0_data *data = irq_desc_get_handler_data(desc); struct samsung_pinctrl_drv_data *drvdata = data->drvdata; unsigned int pend, mask; @@ -616,11 +615,10 @@ static inline void s3c64xx_irq_demux_eint(unsigned int irq, pend &= range; while (pend) { - unsigned int virq; + unsigned int virq, irq; irq = fls(pend) - 1; pend &= ~(1 << irq); - virq = irq_linear_revmap(data->domains[irq], data->pins[irq]); /* * Something must be really wrong if an unmapped EINT @@ -636,22 +634,22 @@ static inline void s3c64xx_irq_demux_eint(unsigned int irq, static void s3c64xx_demux_eint0_3(unsigned int irq, struct irq_desc *desc) { - s3c64xx_irq_demux_eint(irq, desc, 0xf); + s3c64xx_irq_demux_eint(desc, 0xf); } static void s3c64xx_demux_eint4_11(unsigned int irq, struct irq_desc *desc) { - s3c64xx_irq_demux_eint(irq, desc, 0xff0); + s3c64xx_irq_demux_eint(desc, 0xff0); } static void s3c64xx_demux_eint12_19(unsigned int irq, struct irq_desc *desc) { - s3c64xx_irq_demux_eint(irq, desc, 0xff000); + s3c64xx_irq_demux_eint(desc, 0xff000); } static void s3c64xx_demux_eint20_27(unsigned int irq, struct irq_desc *desc) { - s3c64xx_irq_demux_eint(irq, desc, 0xff00000); + s3c64xx_irq_demux_eint(desc, 0xff00000); } static irq_flow_handler_t s3c64xx_eint0_handlers[NUM_EINT0_IRQ] = { diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 8ba26e45499a..9455a2acf6c6 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -552,7 +552,7 @@ static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) struct sirfsoc_gpio_bank *bank; u32 status, ctrl; int idx = 0; - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); int i; for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index f09573e13203..4b1a35cc5578 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -711,8 +711,8 @@ static struct irq_chip sunxi_pinctrl_level_irq_chip = { static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct sunxi_pinctrl *pctl = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc); unsigned long bank, reg, val; for (bank = 0; bank < pctl->desc->irq_banks; bank++) -- cgit v1.3-6-gb490 From fa00fecc16acd80b455f14803ad35195cdcef65d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:48:51 +0200 Subject: pinctrl/amd: Prepare amd_gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij --- drivers/pinctrl/pinctrl-amd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 2663a055546e..5e86bb8ca80e 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -492,8 +492,9 @@ static struct irq_chip amd_gpio_irqchip = { .irq_set_type = amd_gpio_irq_set_type, }; -static void amd_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void amd_gpio_irq_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); u32 i; u32 off; u32 reg; -- cgit v1.3-6-gb490 From fc02a46938fa2dd2494e20ca7b81c687bd027df4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:50:02 +0200 Subject: pinctrl/coh901: Prepare u300_gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-coh901.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 9579442a221d..3731cc67a88b 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -519,8 +519,9 @@ static struct irq_chip u300_gpio_irqchip = { .irq_set_type = u300_gpio_irq_type, }; -static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +static void u300_gpio_irq_handler(unsigned __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct irq_chip *parent_chip = irq_desc_get_chip(desc); struct gpio_chip *chip = irq_desc_get_handler_data(desc); struct u300_gpio *gpio = to_u300_gpio(chip); -- cgit v1.3-6-gb490 From f43ebaf126d3f4b869ba5bcfb11a00f33f0892cf Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:50:50 +0200 Subject: pinctrl/pistachio: Prepare pistachio_gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-pistachio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c index 63100be81015..3dc2ae15f3a1 100644 --- a/drivers/pinctrl/pinctrl-pistachio.c +++ b/drivers/pinctrl/pinctrl-pistachio.c @@ -1310,9 +1310,11 @@ static int pistachio_gpio_irq_set_type(struct irq_data *data, unsigned int type) return 0; } -static void pistachio_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void pistachio_gpio_irq_handler(unsigned int __irq, + struct irq_desc *desc) { - struct gpio_chip *gc = irq_get_handler_data(irq); + unsigned int irq = irq_desc_get_irq(desc); + struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct pistachio_gpio_bank *bank = gc_to_bank(gc); struct irq_chip *chip = irq_get_chip(irq); unsigned long pending; -- cgit v1.3-6-gb490 From 415f748c8658033d37af520dfa321a9413b7d665 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:52:00 +0200 Subject: pinctrl/rockchip: Prepare rockchip_irq_demux for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 28f9d08faf27..cc2843a1f38c 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1469,7 +1469,7 @@ static const struct gpio_chip rockchip_gpiolib_chip = { * Interrupt handling */ -static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) +static void rockchip_irq_demux(unsigned int __irq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct rockchip_pin_bank *bank = irq_desc_get_handler_data(desc); @@ -1482,7 +1482,7 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) pend = readl_relaxed(bank->reg_base + GPIO_INT_STATUS); while (pend) { - unsigned int virq; + unsigned int irq, virq; irq = __ffs(pend); pend &= ~BIT(irq); -- cgit v1.3-6-gb490 From d1800c234703465b1f0b75aba51e27d7a3f47060 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:53:06 +0200 Subject: pinctrl/qcom/msm: Prepare msm_gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/qcom/pinctrl-msm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 3fd39921b3e8..492cdd51dc5c 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -765,8 +765,9 @@ static struct irq_chip msm_gpio_irq_chip = { .irq_set_wake = msm_gpio_irq_set_wake, }; -static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void msm_gpio_irq_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct gpio_chip *gc = irq_desc_get_handler_data(desc); const struct msm_pingroup *g; struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); -- cgit v1.3-6-gb490 From 3b0d1561ea5787a40b2f014d4f3dc48a575c3675 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:54:35 +0200 Subject: pinctrl/sirf: Prepare xxx_gpio-handle_irq for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/sirf/pinctrl-atlas7.c | 5 +++-- drivers/pinctrl/sirf/pinctrl-sirf.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c index d6e80fe1c7f7..0cd945c3af67 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas7.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c @@ -4286,14 +4286,15 @@ static struct irq_chip atlas7_gpio_irq_chip = { .irq_set_type = atlas7_gpio_irq_type, }; -static void atlas7_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) +static void atlas7_gpio_handle_irq(unsigned int __irq, struct irq_desc *desc) { struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc); struct atlas7_gpio_bank *bank = NULL; u32 status, ctrl; int pin_in_bank = 0, idx; - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int irq = irq_desc_get_irq(desc); for (idx = 0; idx < a7gc->nbank; idx++) { bank = &a7gc->banks[idx]; diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 9455a2acf6c6..f8bd9fb52033 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -545,8 +545,9 @@ static struct irq_chip sirfsoc_irq_chip = { .irq_set_type = sirfsoc_gpio_irq_type, }; -static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) +static void sirfsoc_gpio_handle_irq(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc); struct sirfsoc_gpio_bank *bank; -- cgit v1.3-6-gb490 From eeef97b182fcbd4e32803be4f0b369d51e4c8535 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:55:27 +0200 Subject: pinctrl/sunxi: Prepare sunxi_pinctrl_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 4b1a35cc5578..3e905480ec56 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -709,8 +709,9 @@ static struct irq_chip sunxi_pinctrl_level_irq_chip = { IRQCHIP_EOI_IF_HANDLED, }; -static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc) +static void sunxi_pinctrl_irq_handler(unsigned __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct irq_chip *chip = irq_desc_get_chip(desc); struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc); unsigned long bank, reg, val; -- cgit v1.3-6-gb490 From 6de52c15132f6b86030bf3159020e3314ec14952 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 17 Jul 2015 21:37:09 +0800 Subject: pinctrl: pinconf: pinconf_show_config() can be static Signed-off-by: Fengguang Wu Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index cbf26a6992a0..078e58d74fc0 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -202,7 +202,7 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) #ifdef CONFIG_DEBUG_FS -void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev, +static void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev, unsigned long *configs, unsigned num_configs) { const struct pinconf_ops *confops; -- cgit v1.3-6-gb490 From e0548f1979bfee900fb0671a5dd3a2f217dce5df Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 17 Jul 2015 22:24:32 +0200 Subject: drm/i915: Update DRIVER_DATE to 20150717 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 01fbdc57462a..23ce125e0298 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -56,7 +56,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20150703" +#define DRIVER_DATE "20150717" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ -- cgit v1.3-6-gb490 From c2efefb33abfb245395199137ece3c1e3df47f51 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 17 Jul 2015 22:53:43 +0200 Subject: ACPI / scan: Move sysfs-related device code to a separate file To reduce the size of scan.c and improve the readability of it, move all code related to device sysfs, modalias creation etc. to a new file called device_sysfs.c. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Makefile | 2 +- drivers/acpi/device_sysfs.c | 521 ++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/internal.h | 9 + drivers/acpi/scan.c | 483 +--------------------------------------- 4 files changed, 532 insertions(+), 483 deletions(-) create mode 100644 drivers/acpi/device_sysfs.c (limited to 'drivers') diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 8321430d7f24..08ac1100e2dc 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -24,7 +24,7 @@ acpi-y += nvs.o # Power management related files acpi-y += wakeup.o acpi-$(CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT) += sleep.o -acpi-y += device_pm.o +acpi-y += device_sysfs.o device_pm.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c new file mode 100644 index 000000000000..4ab4582e586b --- /dev/null +++ b/drivers/acpi/device_sysfs.c @@ -0,0 +1,521 @@ +/* + * drivers/acpi/device_sysfs.c - ACPI device sysfs attributes and modalias. + * + * Copyright (C) 2015, Intel Corp. + * Author: Mika Westerberg + * Author: Rafael J. Wysocki + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 "internal.h" + +/** + * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent + * @acpi_dev: ACPI device object. + * @modalias: Buffer to print into. + * @size: Size of the buffer. + * + * Creates hid/cid(s) string needed for modalias and uevent + * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: + * char *modalias: "acpi:IBM0001:ACPI0001" + * Return: 0: no _HID and no _CID + * -EINVAL: output error + * -ENOMEM: output is truncated +*/ +static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias, + int size) +{ + int len; + int count; + struct acpi_hardware_id *id; + + /* + * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should + * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the + * device's list. + */ + count = 0; + list_for_each_entry(id, &acpi_dev->pnp.ids, list) + if (strcmp(id->id, ACPI_DT_NAMESPACE_HID)) + count++; + + if (!count) + return 0; + + len = snprintf(modalias, size, "acpi:"); + if (len <= 0) + return len; + + size -= len; + + list_for_each_entry(id, &acpi_dev->pnp.ids, list) { + if (!strcmp(id->id, ACPI_DT_NAMESPACE_HID)) + continue; + + count = snprintf(&modalias[len], size, "%s:", id->id); + if (count < 0) + return -EINVAL; + + if (count >= size) + return -ENOMEM; + + len += count; + size -= count; + } + modalias[len] = '\0'; + return len; +} + +/** + * create_of_modalias - Creates DT compatible string for modalias and uevent + * @acpi_dev: ACPI device object. + * @modalias: Buffer to print into. + * @size: Size of the buffer. + * + * Expose DT compatible modalias as of:NnameTCcompatible. This function should + * only be called for devices having ACPI_DT_NAMESPACE_HID in their list of + * ACPI/PNP IDs. + */ +static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias, + int size) +{ + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; + const union acpi_object *of_compatible, *obj; + int len, count; + int i, nval; + char *c; + + acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf); + /* DT strings are all in lower case */ + for (c = buf.pointer; *c != '\0'; c++) + *c = tolower(*c); + + len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer); + ACPI_FREE(buf.pointer); + + if (len <= 0) + return len; + + of_compatible = acpi_dev->data.of_compatible; + if (of_compatible->type == ACPI_TYPE_PACKAGE) { + nval = of_compatible->package.count; + obj = of_compatible->package.elements; + } else { /* Must be ACPI_TYPE_STRING. */ + nval = 1; + obj = of_compatible; + } + for (i = 0; i < nval; i++, obj++) { + count = snprintf(&modalias[len], size, "C%s", + obj->string.pointer); + if (count < 0) + return -EINVAL; + + if (count >= size) + return -ENOMEM; + + len += count; + size -= count; + } + modalias[len] = '\0'; + return len; +} + +int __acpi_device_uevent_modalias(struct acpi_device *adev, + struct kobj_uevent_env *env) +{ + int len; + + if (!adev) + return -ENODEV; + + if (list_empty(&adev->pnp.ids)) + return 0; + + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + + len = create_pnp_modalias(adev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len < 0) + return len; + + env->buflen += len; + if (!adev->data.of_compatible) + return 0; + + if (len > 0 && add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + + len = create_of_modalias(adev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len < 0) + return len; + + env->buflen += len; + + return 0; +} + +/** + * acpi_device_uevent_modalias - uevent modalias for ACPI-enumerated devices. + * + * Create the uevent modalias field for ACPI-enumerated devices. + * + * Because other buses do not support ACPI HIDs & CIDs, e.g. for a device with + * hid:IBM0001 and cid:ACPI0001 you get: "acpi:IBM0001:ACPI0001". + */ +int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) +{ + return __acpi_device_uevent_modalias(acpi_companion_match(dev), env); +} +EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias); + +static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size) +{ + int len, count; + + if (!adev) + return -ENODEV; + + if (list_empty(&adev->pnp.ids)) + return 0; + + len = create_pnp_modalias(adev, buf, size - 1); + if (len < 0) { + return len; + } else if (len > 0) { + buf[len++] = '\n'; + size -= len; + } + if (!adev->data.of_compatible) + return len; + + count = create_of_modalias(adev, buf + len, size - 1); + if (count < 0) { + return count; + } else if (count > 0) { + len += count; + buf[len++] = '\n'; + } + + return len; +} + +/** + * acpi_device_modalias - modalias sysfs attribute for ACPI-enumerated devices. + * + * Create the modalias sysfs attribute for ACPI-enumerated devices. + * + * Because other buses do not support ACPI HIDs & CIDs, e.g. for a device with + * hid:IBM0001 and cid:ACPI0001 you get: "acpi:IBM0001:ACPI0001". + */ +int acpi_device_modalias(struct device *dev, char *buf, int size) +{ + return __acpi_device_modalias(acpi_companion_match(dev), buf, size); +} +EXPORT_SYMBOL_GPL(acpi_device_modalias); + +static ssize_t +acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { + return __acpi_device_modalias(to_acpi_device(dev), buf, 1024); +} +static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); + +static ssize_t real_power_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *adev = to_acpi_device(dev); + int state; + int ret; + + ret = acpi_device_get_power(adev, &state); + if (ret) + return ret; + + return sprintf(buf, "%s\n", acpi_power_state_string(state)); +} + +static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL); + +static ssize_t power_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *adev = to_acpi_device(dev); + + return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state)); +} + +static DEVICE_ATTR(power_state, 0444, power_state_show, NULL); + +static ssize_t +acpi_eject_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_device *acpi_device = to_acpi_device(d); + acpi_object_type not_used; + acpi_status status; + + if (!count || buf[0] != '1') + return -EINVAL; + + if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled) + && !acpi_device->driver) + return -ENODEV; + + status = acpi_get_type(acpi_device->handle, ¬_used); + if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) + return -ENODEV; + + get_device(&acpi_device->dev); + status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT); + if (ACPI_SUCCESS(status)) + return count; + + put_device(&acpi_device->dev); + acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, + ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); + return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; +} + +static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); + +static ssize_t +acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev)); +} +static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); + +static ssize_t acpi_device_uid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id); +} +static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL); + +static ssize_t acpi_device_adr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "0x%08x\n", + (unsigned int)(acpi_dev->pnp.bus_address)); +} +static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL); + +static ssize_t +acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; + int result; + + result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path); + if (result) + goto end; + + result = sprintf(buf, "%s\n", (char*)path.pointer); + kfree(path.pointer); +end: + return result; +} +static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL); + +/* sysfs file that shows description text from the ACPI _STR method */ +static ssize_t description_show(struct device *dev, + struct device_attribute *attr, + char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + int result; + + if (acpi_dev->pnp.str_obj == NULL) + return 0; + + /* + * The _STR object contains a Unicode identifier for a device. + * We need to convert to utf-8 so it can be displayed. + */ + result = utf16s_to_utf8s( + (wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer, + acpi_dev->pnp.str_obj->buffer.length, + UTF16_LITTLE_ENDIAN, buf, + PAGE_SIZE); + + buf[result++] = '\n'; + + return result; +} +static DEVICE_ATTR(description, 0444, description_show, NULL); + +static ssize_t +acpi_device_sun_show(struct device *dev, struct device_attribute *attr, + char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + acpi_status status; + unsigned long long sun; + + status = acpi_evaluate_integer(acpi_dev->handle, "_SUN", NULL, &sun); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return sprintf(buf, "%llu\n", sun); +} +static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL); + +static ssize_t status_show(struct device *dev, struct device_attribute *attr, + char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + acpi_status status; + unsigned long long sta; + + status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return sprintf(buf, "%llu\n", sta); +} +static DEVICE_ATTR_RO(status); + +/** + * acpi_device_setup_files - Create sysfs attributes of an ACPI device. + * @dev: ACPI device object. + */ +int acpi_device_setup_files(struct acpi_device *dev) +{ + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_status status; + int result = 0; + + /* + * Devices gotten from FADT don't have a "path" attribute + */ + if (dev->handle) { + result = device_create_file(&dev->dev, &dev_attr_path); + if (result) + goto end; + } + + if (!list_empty(&dev->pnp.ids)) { + result = device_create_file(&dev->dev, &dev_attr_hid); + if (result) + goto end; + + result = device_create_file(&dev->dev, &dev_attr_modalias); + if (result) + goto end; + } + + /* + * If device has _STR, 'description' file is created + */ + if (acpi_has_method(dev->handle, "_STR")) { + status = acpi_evaluate_object(dev->handle, "_STR", + NULL, &buffer); + if (ACPI_FAILURE(status)) + buffer.pointer = NULL; + dev->pnp.str_obj = buffer.pointer; + result = device_create_file(&dev->dev, &dev_attr_description); + if (result) + goto end; + } + + if (dev->pnp.type.bus_address) + result = device_create_file(&dev->dev, &dev_attr_adr); + if (dev->pnp.unique_id) + result = device_create_file(&dev->dev, &dev_attr_uid); + + if (acpi_has_method(dev->handle, "_SUN")) { + result = device_create_file(&dev->dev, &dev_attr_sun); + if (result) + goto end; + } + + if (acpi_has_method(dev->handle, "_STA")) { + result = device_create_file(&dev->dev, &dev_attr_status); + if (result) + goto end; + } + + /* + * If device has _EJ0, 'eject' file is created that is used to trigger + * hot-removal function from userland. + */ + if (acpi_has_method(dev->handle, "_EJ0")) { + result = device_create_file(&dev->dev, &dev_attr_eject); + if (result) + return result; + } + + if (dev->flags.power_manageable) { + result = device_create_file(&dev->dev, &dev_attr_power_state); + if (result) + return result; + + if (dev->power.flags.power_resources) + result = device_create_file(&dev->dev, + &dev_attr_real_power_state); + } + +end: + return result; +} + +/** + * acpi_device_remove_files - Remove sysfs attributes of an ACPI device. + * @dev: ACPI device object. + */ +void acpi_device_remove_files(struct acpi_device *dev) +{ + if (dev->flags.power_manageable) { + device_remove_file(&dev->dev, &dev_attr_power_state); + if (dev->power.flags.power_resources) + device_remove_file(&dev->dev, + &dev_attr_real_power_state); + } + + /* + * If device has _STR, remove 'description' file + */ + if (acpi_has_method(dev->handle, "_STR")) { + kfree(dev->pnp.str_obj); + device_remove_file(&dev->dev, &dev_attr_description); + } + /* + * If device has _EJ0, remove 'eject' file. + */ + if (acpi_has_method(dev->handle, "_EJ0")) + device_remove_file(&dev->dev, &dev_attr_eject); + + if (acpi_has_method(dev->handle, "_SUN")) + device_remove_file(&dev->dev, &dev_attr_sun); + + if (dev->pnp.unique_id) + device_remove_file(&dev->dev, &dev_attr_uid); + if (dev->pnp.type.bus_address) + device_remove_file(&dev->dev, &dev_attr_adr); + device_remove_file(&dev->dev, &dev_attr_modalias); + device_remove_file(&dev->dev, &dev_attr_hid); + if (acpi_has_method(dev->handle, "_STA")) + device_remove_file(&dev->dev, &dev_attr_status); + if (dev->handle) + device_remove_file(&dev->dev, &dev_attr_path); +} diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 4683a96932b9..c529454532dc 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -93,11 +93,20 @@ int acpi_device_add(struct acpi_device *device, void (*release)(struct device *)); void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, int type, unsigned long long sta); +int acpi_device_setup_files(struct acpi_device *dev); +void acpi_device_remove_files(struct acpi_device *dev); void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); bool acpi_device_is_present(struct acpi_device *adev); bool acpi_device_is_battery(struct acpi_device *adev); +/* -------------------------------------------------------------------------- + Device Matching and Notification + -------------------------------------------------------------------------- */ +struct acpi_device *acpi_companion_match(const struct device *dev); +int __acpi_device_uevent_modalias(struct acpi_device *adev, + struct kobj_uevent_env *env); + /* -------------------------------------------------------------------------- Power Resource -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ec256352f423..099831fc8449 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -115,117 +115,6 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, return 0; } -/** - * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent - * @acpi_dev: ACPI device object. - * @modalias: Buffer to print into. - * @size: Size of the buffer. - * - * Creates hid/cid(s) string needed for modalias and uevent - * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: - * char *modalias: "acpi:IBM0001:ACPI0001" - * Return: 0: no _HID and no _CID - * -EINVAL: output error - * -ENOMEM: output is truncated -*/ -static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias, - int size) -{ - int len; - int count; - struct acpi_hardware_id *id; - - /* - * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should - * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the - * device's list. - */ - count = 0; - list_for_each_entry(id, &acpi_dev->pnp.ids, list) - if (strcmp(id->id, ACPI_DT_NAMESPACE_HID)) - count++; - - if (!count) - return 0; - - len = snprintf(modalias, size, "acpi:"); - if (len <= 0) - return len; - - size -= len; - - list_for_each_entry(id, &acpi_dev->pnp.ids, list) { - if (!strcmp(id->id, ACPI_DT_NAMESPACE_HID)) - continue; - - count = snprintf(&modalias[len], size, "%s:", id->id); - if (count < 0) - return -EINVAL; - - if (count >= size) - return -ENOMEM; - - len += count; - size -= count; - } - modalias[len] = '\0'; - return len; -} - -/** - * create_of_modalias - Creates DT compatible string for modalias and uevent - * @acpi_dev: ACPI device object. - * @modalias: Buffer to print into. - * @size: Size of the buffer. - * - * Expose DT compatible modalias as of:NnameTCcompatible. This function should - * only be called for devices having ACPI_DT_NAMESPACE_HID in their list of - * ACPI/PNP IDs. - */ -static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias, - int size) -{ - struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; - const union acpi_object *of_compatible, *obj; - int len, count; - int i, nval; - char *c; - - acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf); - /* DT strings are all in lower case */ - for (c = buf.pointer; *c != '\0'; c++) - *c = tolower(*c); - - len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer); - ACPI_FREE(buf.pointer); - - if (len <= 0) - return len; - - of_compatible = acpi_dev->data.of_compatible; - if (of_compatible->type == ACPI_TYPE_PACKAGE) { - nval = of_compatible->package.count; - obj = of_compatible->package.elements; - } else { /* Must be ACPI_TYPE_STRING. */ - nval = 1; - obj = of_compatible; - } - for (i = 0; i < nval; i++, obj++) { - count = snprintf(&modalias[len], size, "C%s", - obj->string.pointer); - if (count < 0) - return -EINVAL; - - if (count >= size) - return -ENOMEM; - - len += count; - size -= count; - } - modalias[len] = '\0'; - return len; -} - /* * acpi_companion_match() - Can we match via ACPI companion device * @dev: Device in question @@ -247,7 +136,7 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias, * resources available from it but they will be matched normally using functions * provided by their bus types (and analogously for their modalias). */ -static struct acpi_device *acpi_companion_match(const struct device *dev) +struct acpi_device *acpi_companion_match(const struct device *dev) { struct acpi_device *adev; struct mutex *physical_node_lock; @@ -276,103 +165,6 @@ static struct acpi_device *acpi_companion_match(const struct device *dev) return adev; } -static int __acpi_device_uevent_modalias(struct acpi_device *adev, - struct kobj_uevent_env *env) -{ - int len; - - if (!adev) - return -ENODEV; - - if (list_empty(&adev->pnp.ids)) - return 0; - - if (add_uevent_var(env, "MODALIAS=")) - return -ENOMEM; - - len = create_pnp_modalias(adev, &env->buf[env->buflen - 1], - sizeof(env->buf) - env->buflen); - if (len < 0) - return len; - - env->buflen += len; - if (!adev->data.of_compatible) - return 0; - - if (len > 0 && add_uevent_var(env, "MODALIAS=")) - return -ENOMEM; - - len = create_of_modalias(adev, &env->buf[env->buflen - 1], - sizeof(env->buf) - env->buflen); - if (len < 0) - return len; - - env->buflen += len; - - return 0; -} - -/* - * Creates uevent modalias field for ACPI enumerated devices. - * Because the other buses does not support ACPI HIDs & CIDs. - * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: - * "acpi:IBM0001:ACPI0001" - */ -int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) -{ - return __acpi_device_uevent_modalias(acpi_companion_match(dev), env); -} -EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias); - -static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size) -{ - int len, count; - - if (!adev) - return -ENODEV; - - if (list_empty(&adev->pnp.ids)) - return 0; - - len = create_pnp_modalias(adev, buf, size - 1); - if (len < 0) { - return len; - } else if (len > 0) { - buf[len++] = '\n'; - size -= len; - } - if (!adev->data.of_compatible) - return len; - - count = create_of_modalias(adev, buf + len, size - 1); - if (count < 0) { - return count; - } else if (count > 0) { - len += count; - buf[len++] = '\n'; - } - - return len; -} - -/* - * Creates modalias sysfs attribute for ACPI enumerated devices. - * Because the other buses does not support ACPI HIDs & CIDs. - * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: - * "acpi:IBM0001:ACPI0001" - */ -int acpi_device_modalias(struct device *dev, char *buf, int size) -{ - return __acpi_device_modalias(acpi_companion_match(dev), buf, size); -} -EXPORT_SYMBOL_GPL(acpi_device_modalias); - -static ssize_t -acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { - return __acpi_device_modalias(to_acpi_device(dev), buf, 1024); -} -static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); - bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) { struct acpi_device_physical_node *pn; @@ -701,279 +493,6 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src) unlock_device_hotplug(); } -static ssize_t real_power_state_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct acpi_device *adev = to_acpi_device(dev); - int state; - int ret; - - ret = acpi_device_get_power(adev, &state); - if (ret) - return ret; - - return sprintf(buf, "%s\n", acpi_power_state_string(state)); -} - -static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL); - -static ssize_t power_state_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct acpi_device *adev = to_acpi_device(dev); - - return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state)); -} - -static DEVICE_ATTR(power_state, 0444, power_state_show, NULL); - -static ssize_t -acpi_eject_store(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct acpi_device *acpi_device = to_acpi_device(d); - acpi_object_type not_used; - acpi_status status; - - if (!count || buf[0] != '1') - return -EINVAL; - - if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled) - && !acpi_device->driver) - return -ENODEV; - - status = acpi_get_type(acpi_device->handle, ¬_used); - if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) - return -ENODEV; - - get_device(&acpi_device->dev); - status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT); - if (ACPI_SUCCESS(status)) - return count; - - put_device(&acpi_device->dev); - acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, - ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); - return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; -} - -static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); - -static ssize_t -acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - - return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev)); -} -static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); - -static ssize_t acpi_device_uid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - - return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id); -} -static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL); - -static ssize_t acpi_device_adr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - - return sprintf(buf, "0x%08x\n", - (unsigned int)(acpi_dev->pnp.bus_address)); -} -static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL); - -static ssize_t -acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; - int result; - - result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path); - if (result) - goto end; - - result = sprintf(buf, "%s\n", (char*)path.pointer); - kfree(path.pointer); -end: - return result; -} -static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL); - -/* sysfs file that shows description text from the ACPI _STR method */ -static ssize_t description_show(struct device *dev, - struct device_attribute *attr, - char *buf) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - int result; - - if (acpi_dev->pnp.str_obj == NULL) - return 0; - - /* - * The _STR object contains a Unicode identifier for a device. - * We need to convert to utf-8 so it can be displayed. - */ - result = utf16s_to_utf8s( - (wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer, - acpi_dev->pnp.str_obj->buffer.length, - UTF16_LITTLE_ENDIAN, buf, - PAGE_SIZE); - - buf[result++] = '\n'; - - return result; -} -static DEVICE_ATTR(description, 0444, description_show, NULL); - -static ssize_t -acpi_device_sun_show(struct device *dev, struct device_attribute *attr, - char *buf) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - acpi_status status; - unsigned long long sun; - - status = acpi_evaluate_integer(acpi_dev->handle, "_SUN", NULL, &sun); - if (ACPI_FAILURE(status)) - return -ENODEV; - - return sprintf(buf, "%llu\n", sun); -} -static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL); - -static ssize_t status_show(struct device *dev, struct device_attribute *attr, - char *buf) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - acpi_status status; - unsigned long long sta; - - status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta); - if (ACPI_FAILURE(status)) - return -ENODEV; - - return sprintf(buf, "%llu\n", sta); -} -static DEVICE_ATTR_RO(status); - -static int acpi_device_setup_files(struct acpi_device *dev) -{ - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_status status; - int result = 0; - - /* - * Devices gotten from FADT don't have a "path" attribute - */ - if (dev->handle) { - result = device_create_file(&dev->dev, &dev_attr_path); - if (result) - goto end; - } - - if (!list_empty(&dev->pnp.ids)) { - result = device_create_file(&dev->dev, &dev_attr_hid); - if (result) - goto end; - - result = device_create_file(&dev->dev, &dev_attr_modalias); - if (result) - goto end; - } - - /* - * If device has _STR, 'description' file is created - */ - if (acpi_has_method(dev->handle, "_STR")) { - status = acpi_evaluate_object(dev->handle, "_STR", - NULL, &buffer); - if (ACPI_FAILURE(status)) - buffer.pointer = NULL; - dev->pnp.str_obj = buffer.pointer; - result = device_create_file(&dev->dev, &dev_attr_description); - if (result) - goto end; - } - - if (dev->pnp.type.bus_address) - result = device_create_file(&dev->dev, &dev_attr_adr); - if (dev->pnp.unique_id) - result = device_create_file(&dev->dev, &dev_attr_uid); - - if (acpi_has_method(dev->handle, "_SUN")) { - result = device_create_file(&dev->dev, &dev_attr_sun); - if (result) - goto end; - } - - if (acpi_has_method(dev->handle, "_STA")) { - result = device_create_file(&dev->dev, &dev_attr_status); - if (result) - goto end; - } - - /* - * If device has _EJ0, 'eject' file is created that is used to trigger - * hot-removal function from userland. - */ - if (acpi_has_method(dev->handle, "_EJ0")) { - result = device_create_file(&dev->dev, &dev_attr_eject); - if (result) - return result; - } - - if (dev->flags.power_manageable) { - result = device_create_file(&dev->dev, &dev_attr_power_state); - if (result) - return result; - - if (dev->power.flags.power_resources) - result = device_create_file(&dev->dev, - &dev_attr_real_power_state); - } - -end: - return result; -} - -static void acpi_device_remove_files(struct acpi_device *dev) -{ - if (dev->flags.power_manageable) { - device_remove_file(&dev->dev, &dev_attr_power_state); - if (dev->power.flags.power_resources) - device_remove_file(&dev->dev, - &dev_attr_real_power_state); - } - - /* - * If device has _STR, remove 'description' file - */ - if (acpi_has_method(dev->handle, "_STR")) { - kfree(dev->pnp.str_obj); - device_remove_file(&dev->dev, &dev_attr_description); - } - /* - * If device has _EJ0, remove 'eject' file. - */ - if (acpi_has_method(dev->handle, "_EJ0")) - device_remove_file(&dev->dev, &dev_attr_eject); - - if (acpi_has_method(dev->handle, "_SUN")) - device_remove_file(&dev->dev, &dev_attr_sun); - - if (dev->pnp.unique_id) - device_remove_file(&dev->dev, &dev_attr_uid); - if (dev->pnp.type.bus_address) - device_remove_file(&dev->dev, &dev_attr_adr); - device_remove_file(&dev->dev, &dev_attr_modalias); - device_remove_file(&dev->dev, &dev_attr_hid); - if (acpi_has_method(dev->handle, "_STA")) - device_remove_file(&dev->dev, &dev_attr_status); - if (dev->handle) - device_remove_file(&dev->dev, &dev_attr_path); -} /* -------------------------------------------------------------------------- ACPI Bus operations -------------------------------------------------------------------------- */ -- cgit v1.3-6-gb490 From 68c6b148daa6e45a85b31ef60ed9c9bfd556fff0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 17 Jul 2015 22:53:52 +0200 Subject: ACPI / scan: Move device matching code to bus.c To reduce the size of scan.c and improve the readability of it, move code related device matching into drivers/acpi/bus.c. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/scan.c | 189 -------------------------------------------------- 2 files changed, 194 insertions(+), 189 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 513e7230e3d0..ce805809b00b 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -423,6 +423,200 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) acpi_evaluate_ost(handle, type, ost_code, NULL); } +/* -------------------------------------------------------------------------- + Device Matching + -------------------------------------------------------------------------- */ + +/* + * acpi_companion_match() - Can we match via ACPI companion device + * @dev: Device in question + * + * Check if the given device has an ACPI companion and if that companion has + * a valid list of PNP IDs, and if the device is the first (primary) physical + * device associated with it. Return the companion pointer if that's the case + * or NULL otherwise. + * + * If multiple physical devices are attached to a single ACPI companion, we need + * to be careful. The usage scenario for this kind of relationship is that all + * of the physical devices in question use resources provided by the ACPI + * companion. A typical case is an MFD device where all the sub-devices share + * the parent's ACPI companion. In such cases we can only allow the primary + * (first) physical device to be matched with the help of the companion's PNP + * IDs. + * + * Additional physical devices sharing the ACPI companion can still use + * resources available from it but they will be matched normally using functions + * provided by their bus types (and analogously for their modalias). + */ +struct acpi_device *acpi_companion_match(const struct device *dev) +{ + struct acpi_device *adev; + struct mutex *physical_node_lock; + + adev = ACPI_COMPANION(dev); + if (!adev) + return NULL; + + if (list_empty(&adev->pnp.ids)) + return NULL; + + physical_node_lock = &adev->physical_node_lock; + mutex_lock(physical_node_lock); + if (list_empty(&adev->physical_node_list)) { + adev = NULL; + } else { + const struct acpi_device_physical_node *node; + + node = list_first_entry(&adev->physical_node_list, + struct acpi_device_physical_node, node); + if (node->dev != dev) + adev = NULL; + } + mutex_unlock(physical_node_lock); + + return adev; +} + +/** + * acpi_of_match_device - Match device object using the "compatible" property. + * @adev: ACPI device object to match. + * @of_match_table: List of device IDs to match against. + * + * If @dev has an ACPI companion which has ACPI_DT_NAMESPACE_HID in its list of + * identifiers and a _DSD object with the "compatible" property, use that + * property to match against the given list of identifiers. + */ +static bool acpi_of_match_device(struct acpi_device *adev, + const struct of_device_id *of_match_table) +{ + const union acpi_object *of_compatible, *obj; + int i, nval; + + if (!adev) + return false; + + of_compatible = adev->data.of_compatible; + if (!of_match_table || !of_compatible) + return false; + + if (of_compatible->type == ACPI_TYPE_PACKAGE) { + nval = of_compatible->package.count; + obj = of_compatible->package.elements; + } else { /* Must be ACPI_TYPE_STRING. */ + nval = 1; + obj = of_compatible; + } + /* Now we can look for the driver DT compatible strings */ + for (i = 0; i < nval; i++, obj++) { + const struct of_device_id *id; + + for (id = of_match_table; id->compatible[0]; id++) + if (!strcasecmp(obj->string.pointer, id->compatible)) + return true; + } + + return false; +} + +static bool __acpi_match_device_cls(const struct acpi_device_id *id, + struct acpi_hardware_id *hwid) +{ + int i, msk, byte_shift; + char buf[3]; + + if (!id->cls) + return false; + + /* Apply class-code bitmask, before checking each class-code byte */ + for (i = 1; i <= 3; i++) { + byte_shift = 8 * (3 - i); + msk = (id->cls_msk >> byte_shift) & 0xFF; + if (!msk) + continue; + + sprintf(buf, "%02x", (id->cls >> byte_shift) & msk); + if (strncmp(buf, &hwid->id[(i - 1) * 2], 2)) + return false; + } + return true; +} + +static const struct acpi_device_id *__acpi_match_device( + struct acpi_device *device, + const struct acpi_device_id *ids, + const struct of_device_id *of_ids) +{ + const struct acpi_device_id *id; + struct acpi_hardware_id *hwid; + + /* + * If the device is not present, it is unnecessary to load device + * driver for it. + */ + if (!device || !device->status.present) + return NULL; + + list_for_each_entry(hwid, &device->pnp.ids, list) { + /* First, check the ACPI/PNP IDs provided by the caller. */ + for (id = ids; id->id[0] || id->cls; id++) { + if (id->id[0] && !strcmp((char *) id->id, hwid->id)) + return id; + else if (id->cls && __acpi_match_device_cls(id, hwid)) + return id; + } + + /* + * Next, check ACPI_DT_NAMESPACE_HID and try to match the + * "compatible" property if found. + * + * The id returned by the below is not valid, but the only + * caller passing non-NULL of_ids here is only interested in + * whether or not the return value is NULL. + */ + if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id) + && acpi_of_match_device(device, of_ids)) + return id; + } + return NULL; +} + +/** + * acpi_match_device - Match a struct device against a given list of ACPI IDs + * @ids: Array of struct acpi_device_id object to match against. + * @dev: The device structure to match. + * + * Check if @dev has a valid ACPI handle and if there is a struct acpi_device + * object for that handle and use that object to match against a given list of + * device IDs. + * + * Return a pointer to the first matching ID on success or %NULL on failure. + */ +const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, + const struct device *dev) +{ + return __acpi_match_device(acpi_companion_match(dev), ids, NULL); +} +EXPORT_SYMBOL_GPL(acpi_match_device); + +int acpi_match_device_ids(struct acpi_device *device, + const struct acpi_device_id *ids) +{ + return __acpi_match_device(device, ids, NULL) ? 0 : -ENOENT; +} +EXPORT_SYMBOL(acpi_match_device_ids); + +bool acpi_driver_match_device(struct device *dev, + const struct device_driver *drv) +{ + if (!drv->acpi_match_table) + return acpi_of_match_device(ACPI_COMPANION(dev), + drv->of_match_table); + + return !!__acpi_match_device(acpi_companion_match(dev), + drv->acpi_match_table, drv->of_match_table); +} +EXPORT_SYMBOL_GPL(acpi_driver_match_device); + /* -------------------------------------------------------------------------- Initialization/Cleanup -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 099831fc8449..68877bc22357 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -115,55 +115,6 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, return 0; } -/* - * acpi_companion_match() - Can we match via ACPI companion device - * @dev: Device in question - * - * Check if the given device has an ACPI companion and if that companion has - * a valid list of PNP IDs, and if the device is the first (primary) physical - * device associated with it. Return the companion pointer if that's the case - * or NULL otherwise. - * - * If multiple physical devices are attached to a single ACPI companion, we need - * to be careful. The usage scenario for this kind of relationship is that all - * of the physical devices in question use resources provided by the ACPI - * companion. A typical case is an MFD device where all the sub-devices share - * the parent's ACPI companion. In such cases we can only allow the primary - * (first) physical device to be matched with the help of the companion's PNP - * IDs. - * - * Additional physical devices sharing the ACPI companion can still use - * resources available from it but they will be matched normally using functions - * provided by their bus types (and analogously for their modalias). - */ -struct acpi_device *acpi_companion_match(const struct device *dev) -{ - struct acpi_device *adev; - struct mutex *physical_node_lock; - - adev = ACPI_COMPANION(dev); - if (!adev) - return NULL; - - if (list_empty(&adev->pnp.ids)) - return NULL; - - physical_node_lock = &adev->physical_node_lock; - mutex_lock(physical_node_lock); - if (list_empty(&adev->physical_node_list)) { - adev = NULL; - } else { - const struct acpi_device_physical_node *node; - - node = list_first_entry(&adev->physical_node_list, - struct acpi_device_physical_node, node); - if (node->dev != dev) - adev = NULL; - } - mutex_unlock(physical_node_lock); - - return adev; -} bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) { @@ -497,146 +448,6 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src) ACPI Bus operations -------------------------------------------------------------------------- */ -/** - * acpi_of_match_device - Match device object using the "compatible" property. - * @adev: ACPI device object to match. - * @of_match_table: List of device IDs to match against. - * - * If @dev has an ACPI companion which has ACPI_DT_NAMESPACE_HID in its list of - * identifiers and a _DSD object with the "compatible" property, use that - * property to match against the given list of identifiers. - */ -static bool acpi_of_match_device(struct acpi_device *adev, - const struct of_device_id *of_match_table) -{ - const union acpi_object *of_compatible, *obj; - int i, nval; - - if (!adev) - return false; - - of_compatible = adev->data.of_compatible; - if (!of_match_table || !of_compatible) - return false; - - if (of_compatible->type == ACPI_TYPE_PACKAGE) { - nval = of_compatible->package.count; - obj = of_compatible->package.elements; - } else { /* Must be ACPI_TYPE_STRING. */ - nval = 1; - obj = of_compatible; - } - /* Now we can look for the driver DT compatible strings */ - for (i = 0; i < nval; i++, obj++) { - const struct of_device_id *id; - - for (id = of_match_table; id->compatible[0]; id++) - if (!strcasecmp(obj->string.pointer, id->compatible)) - return true; - } - - return false; -} - -static bool __acpi_match_device_cls(const struct acpi_device_id *id, - struct acpi_hardware_id *hwid) -{ - int i, msk, byte_shift; - char buf[3]; - - if (!id->cls) - return false; - - /* Apply class-code bitmask, before checking each class-code byte */ - for (i = 1; i <= 3; i++) { - byte_shift = 8 * (3 - i); - msk = (id->cls_msk >> byte_shift) & 0xFF; - if (!msk) - continue; - - sprintf(buf, "%02x", (id->cls >> byte_shift) & msk); - if (strncmp(buf, &hwid->id[(i - 1) * 2], 2)) - return false; - } - return true; -} - -static const struct acpi_device_id *__acpi_match_device( - struct acpi_device *device, - const struct acpi_device_id *ids, - const struct of_device_id *of_ids) -{ - const struct acpi_device_id *id; - struct acpi_hardware_id *hwid; - - /* - * If the device is not present, it is unnecessary to load device - * driver for it. - */ - if (!device || !device->status.present) - return NULL; - - list_for_each_entry(hwid, &device->pnp.ids, list) { - /* First, check the ACPI/PNP IDs provided by the caller. */ - for (id = ids; id->id[0] || id->cls; id++) { - if (id->id[0] && !strcmp((char *) id->id, hwid->id)) - return id; - else if (id->cls && __acpi_match_device_cls(id, hwid)) - return id; - } - - /* - * Next, check ACPI_DT_NAMESPACE_HID and try to match the - * "compatible" property if found. - * - * The id returned by the below is not valid, but the only - * caller passing non-NULL of_ids here is only interested in - * whether or not the return value is NULL. - */ - if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id) - && acpi_of_match_device(device, of_ids)) - return id; - } - return NULL; -} - -/** - * acpi_match_device - Match a struct device against a given list of ACPI IDs - * @ids: Array of struct acpi_device_id object to match against. - * @dev: The device structure to match. - * - * Check if @dev has a valid ACPI handle and if there is a struct acpi_device - * object for that handle and use that object to match against a given list of - * device IDs. - * - * Return a pointer to the first matching ID on success or %NULL on failure. - */ -const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, - const struct device *dev) -{ - return __acpi_match_device(acpi_companion_match(dev), ids, NULL); -} -EXPORT_SYMBOL_GPL(acpi_match_device); - -int acpi_match_device_ids(struct acpi_device *device, - const struct acpi_device_id *ids) -{ - return __acpi_match_device(device, ids, NULL) ? 0 : -ENOENT; -} -EXPORT_SYMBOL(acpi_match_device_ids); - -bool acpi_driver_match_device(struct device *dev, - const struct device_driver *drv) -{ - if (!drv->acpi_match_table) - return acpi_of_match_device(ACPI_COMPANION(dev), - drv->of_match_table); - - return !!__acpi_match_device(acpi_companion_match(dev), - drv->acpi_match_table, drv->of_match_table); -} -EXPORT_SYMBOL_GPL(acpi_driver_match_device); - static void acpi_free_power_resources_lists(struct acpi_device *device) { int i; -- cgit v1.3-6-gb490 From 5894b0c46e49b5ecc25f22b2d1b8232aab00ce97 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 17 Jul 2015 22:54:01 +0200 Subject: ACPI / scan: Move bus operations and notification routines to bus.c To reduce the size of scan.c and improve the readability of it, move code related to device notification, the definitions of the ACPI bus operations and the driver management code to drivers/acpi/bus.c. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/scan.c | 183 --------------------------------------------------- 2 files changed, 184 insertions(+), 183 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index ce805809b00b..2f50fc4be1d4 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -423,6 +423,65 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) acpi_evaluate_ost(handle, type, ost_code, NULL); } +static void acpi_device_notify(acpi_handle handle, u32 event, void *data) +{ + struct acpi_device *device = data; + + device->driver->ops.notify(device, event); +} + +static void acpi_device_notify_fixed(void *data) +{ + struct acpi_device *device = data; + + /* Fixed hardware devices have no handles */ + acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device); +} + +static u32 acpi_device_fixed_event(void *data) +{ + acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_device_notify_fixed, data); + return ACPI_INTERRUPT_HANDLED; +} + +static int acpi_device_install_notify_handler(struct acpi_device *device) +{ + acpi_status status; + + if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) + status = + acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, + acpi_device_fixed_event, + device); + else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) + status = + acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, + acpi_device_fixed_event, + device); + else + status = acpi_install_notify_handler(device->handle, + ACPI_DEVICE_NOTIFY, + acpi_device_notify, + device); + + if (ACPI_FAILURE(status)) + return -EINVAL; + return 0; +} + +static void acpi_device_remove_notify_handler(struct acpi_device *device) +{ + if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) + acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, + acpi_device_fixed_event); + else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) + acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, + acpi_device_fixed_event); + else + acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + acpi_device_notify); +} + /* -------------------------------------------------------------------------- Device Matching -------------------------------------------------------------------------- */ @@ -617,6 +676,131 @@ bool acpi_driver_match_device(struct device *dev, } EXPORT_SYMBOL_GPL(acpi_driver_match_device); +/* -------------------------------------------------------------------------- + ACPI Driver Management + -------------------------------------------------------------------------- */ + +/** + * acpi_bus_register_driver - register a driver with the ACPI bus + * @driver: driver being registered + * + * Registers a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and binds. Returns zero for + * success or a negative error status for failure. + */ +int acpi_bus_register_driver(struct acpi_driver *driver) +{ + int ret; + + if (acpi_disabled) + return -ENODEV; + driver->drv.name = driver->name; + driver->drv.bus = &acpi_bus_type; + driver->drv.owner = driver->owner; + + ret = driver_register(&driver->drv); + return ret; +} + +EXPORT_SYMBOL(acpi_bus_register_driver); + +/** + * acpi_bus_unregister_driver - unregisters a driver with the ACPI bus + * @driver: driver to unregister + * + * Unregisters a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and unbinds. + */ +void acpi_bus_unregister_driver(struct acpi_driver *driver) +{ + driver_unregister(&driver->drv); +} + +EXPORT_SYMBOL(acpi_bus_unregister_driver); + +/* -------------------------------------------------------------------------- + ACPI Bus operations + -------------------------------------------------------------------------- */ + +static int acpi_bus_match(struct device *dev, struct device_driver *drv) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = to_acpi_driver(drv); + + return acpi_dev->flags.match_driver + && !acpi_match_device_ids(acpi_dev, acpi_drv->ids); +} + +static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + return __acpi_device_uevent_modalias(to_acpi_device(dev), env); +} + +static int acpi_device_probe(struct device *dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); + int ret; + + if (acpi_dev->handler && !acpi_is_pnp_device(acpi_dev)) + return -EINVAL; + + if (!acpi_drv->ops.add) + return -ENOSYS; + + ret = acpi_drv->ops.add(acpi_dev); + if (ret) + return ret; + + acpi_dev->driver = acpi_drv; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Driver [%s] successfully bound to device [%s]\n", + acpi_drv->name, acpi_dev->pnp.bus_id)); + + if (acpi_drv->ops.notify) { + ret = acpi_device_install_notify_handler(acpi_dev); + if (ret) { + if (acpi_drv->ops.remove) + acpi_drv->ops.remove(acpi_dev); + + acpi_dev->driver = NULL; + acpi_dev->driver_data = NULL; + return ret; + } + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", + acpi_drv->name, acpi_dev->pnp.bus_id)); + get_device(dev); + return 0; +} + +static int acpi_device_remove(struct device * dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; + + if (acpi_drv) { + if (acpi_drv->ops.notify) + acpi_device_remove_notify_handler(acpi_dev); + if (acpi_drv->ops.remove) + acpi_drv->ops.remove(acpi_dev); + } + acpi_dev->driver = NULL; + acpi_dev->driver_data = NULL; + + put_device(dev); + return 0; +} + +struct bus_type acpi_bus_type = { + .name = "acpi", + .match = acpi_bus_match, + .probe = acpi_device_probe, + .remove = acpi_device_remove, + .uevent = acpi_device_uevent, +}; + /* -------------------------------------------------------------------------- Initialization/Cleanup -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 68877bc22357..f541f689ae80 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -444,10 +444,6 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src) unlock_device_hotplug(); } -/* -------------------------------------------------------------------------- - ACPI Bus operations - -------------------------------------------------------------------------- */ - static void acpi_free_power_resources_lists(struct acpi_device *device) { int i; @@ -474,144 +470,6 @@ static void acpi_device_release(struct device *dev) kfree(acpi_dev); } -static int acpi_bus_match(struct device *dev, struct device_driver *drv) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - struct acpi_driver *acpi_drv = to_acpi_driver(drv); - - return acpi_dev->flags.match_driver - && !acpi_match_device_ids(acpi_dev, acpi_drv->ids); -} - -static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return __acpi_device_uevent_modalias(to_acpi_device(dev), env); -} - -static void acpi_device_notify(acpi_handle handle, u32 event, void *data) -{ - struct acpi_device *device = data; - - device->driver->ops.notify(device, event); -} - -static void acpi_device_notify_fixed(void *data) -{ - struct acpi_device *device = data; - - /* Fixed hardware devices have no handles */ - acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device); -} - -static u32 acpi_device_fixed_event(void *data) -{ - acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_device_notify_fixed, data); - return ACPI_INTERRUPT_HANDLED; -} - -static int acpi_device_install_notify_handler(struct acpi_device *device) -{ - acpi_status status; - - if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) - status = - acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, - acpi_device_fixed_event, - device); - else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) - status = - acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, - acpi_device_fixed_event, - device); - else - status = acpi_install_notify_handler(device->handle, - ACPI_DEVICE_NOTIFY, - acpi_device_notify, - device); - - if (ACPI_FAILURE(status)) - return -EINVAL; - return 0; -} - -static void acpi_device_remove_notify_handler(struct acpi_device *device) -{ - if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) - acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, - acpi_device_fixed_event); - else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) - acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, - acpi_device_fixed_event); - else - acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, - acpi_device_notify); -} - -static int acpi_device_probe(struct device *dev) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); - int ret; - - if (acpi_dev->handler && !acpi_is_pnp_device(acpi_dev)) - return -EINVAL; - - if (!acpi_drv->ops.add) - return -ENOSYS; - - ret = acpi_drv->ops.add(acpi_dev); - if (ret) - return ret; - - acpi_dev->driver = acpi_drv; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Driver [%s] successfully bound to device [%s]\n", - acpi_drv->name, acpi_dev->pnp.bus_id)); - - if (acpi_drv->ops.notify) { - ret = acpi_device_install_notify_handler(acpi_dev); - if (ret) { - if (acpi_drv->ops.remove) - acpi_drv->ops.remove(acpi_dev); - - acpi_dev->driver = NULL; - acpi_dev->driver_data = NULL; - return ret; - } - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", - acpi_drv->name, acpi_dev->pnp.bus_id)); - get_device(dev); - return 0; -} - -static int acpi_device_remove(struct device * dev) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - struct acpi_driver *acpi_drv = acpi_dev->driver; - - if (acpi_drv) { - if (acpi_drv->ops.notify) - acpi_device_remove_notify_handler(acpi_dev); - if (acpi_drv->ops.remove) - acpi_drv->ops.remove(acpi_dev); - } - acpi_dev->driver = NULL; - acpi_dev->driver_data = NULL; - - put_device(dev); - return 0; -} - -struct bus_type acpi_bus_type = { - .name = "acpi", - .match = acpi_bus_match, - .probe = acpi_device_probe, - .remove = acpi_device_remove, - .uevent = acpi_device_uevent, -}; - static void acpi_device_del(struct acpi_device *device) { mutex_lock(&acpi_device_lock); @@ -858,47 +716,6 @@ struct acpi_device *acpi_get_next_child(struct device *dev, return next == head ? NULL : list_entry(next, struct acpi_device, node); } -/* -------------------------------------------------------------------------- - Driver Management - -------------------------------------------------------------------------- */ -/** - * acpi_bus_register_driver - register a driver with the ACPI bus - * @driver: driver being registered - * - * Registers a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and binds. Returns zero for - * success or a negative error status for failure. - */ -int acpi_bus_register_driver(struct acpi_driver *driver) -{ - int ret; - - if (acpi_disabled) - return -ENODEV; - driver->drv.name = driver->name; - driver->drv.bus = &acpi_bus_type; - driver->drv.owner = driver->owner; - - ret = driver_register(&driver->drv); - return ret; -} - -EXPORT_SYMBOL(acpi_bus_register_driver); - -/** - * acpi_bus_unregister_driver - unregisters a driver with the ACPI bus - * @driver: driver to unregister - * - * Unregisters a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and unbinds. - */ -void acpi_bus_unregister_driver(struct acpi_driver *driver) -{ - driver_unregister(&driver->drv); -} - -EXPORT_SYMBOL(acpi_bus_unregister_driver); - /* -------------------------------------------------------------------------- Device Enumeration -------------------------------------------------------------------------- */ -- cgit v1.3-6-gb490 From 1dcc3d3362b0c97e48290f7786be85b4cec2a147 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 17 Jul 2015 22:54:09 +0200 Subject: ACPI / bus: Move ACPI bus type registration Move the registration of the ACPI bus type to acpi_bus_init() and avoid using ACPI going forward if it fails (too many things depend on the presence of the ACPI bus type). Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 4 +++- drivers/acpi/scan.c | 6 ------ 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2f50fc4be1d4..7a3ad929f095 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1039,7 +1039,9 @@ static int __init acpi_bus_init(void) */ acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL); - return 0; + result = bus_register(&acpi_bus_type); + if (!result) + return 0; /* Mimic structured exception handling */ error1: diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index f541f689ae80..2fe5a37c385c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1891,12 +1891,6 @@ int __init acpi_scan_init(void) { int result; - result = bus_register(&acpi_bus_type); - if (result) { - /* We don't want to quit even if we failed to add suspend/resume */ - printk(KERN_ERR PREFIX "Could not register bus type\n"); - } - acpi_pci_root_init(); acpi_pci_link_init(); acpi_processor_init(); -- cgit v1.3-6-gb490 From f4745a92781b872455f32feb01d1dce92aefcb6c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 29 Jun 2015 22:13:38 +0100 Subject: PM / clk: don't return int on __pm_clk_enable() Static analysis by cppcheck found an issue that was recently introduced by commit 471f7707b6f0b1 ("PM / clock_ops: make __pm_clk_enable more generic") where a return status in ret was not being initialised and garbage being returned when ce->status >= PCE_STATUS_ERROR. The fact that ret is not being checked by the caller and that ret is only used internally __pm_clk_enable() to check if clk_enable() was OK means we can ignore returning it instead turn __pm_clk_enable() into function with a void return. Fixes: 471f7707b6f0b1 ("PM / clock_ops: make __pm_clk_enable more generic") Signed-off-by: Colin Ian King Signed-off-by: Rafael J. Wysocki --- drivers/base/power/clock_ops.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index acef9f9f759a..652b5a367c1f 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -38,7 +38,7 @@ struct pm_clock_entry { * @dev: The device for the given clock * @ce: PM clock entry corresponding to the clock. */ -static inline int __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce) +static inline void __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce) { int ret; @@ -50,8 +50,6 @@ static inline int __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce) dev_err(dev, "%s: failed to enable clk %p, error %d\n", __func__, ce->clk, ret); } - - return ret; } /** -- cgit v1.3-6-gb490 From 386d46e6d5238c9648399eb1e0c418d06f4126a2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 19 Jun 2015 17:18:01 +0530 Subject: cpufreq: governor: Name delayed-work as dwork Delayed work was named as 'work' and to access work within it we do work.work. Not much readable. Rename delayed_work as 'dwork'. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_conservative.c | 2 +- drivers/cpufreq/cpufreq_governor.c | 6 +++--- drivers/cpufreq/cpufreq_governor.h | 2 +- drivers/cpufreq/cpufreq_ondemand.c | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index c86a10c30912..0e3ec1d968d9 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -105,7 +105,7 @@ static void cs_check_cpu(int cpu, unsigned int load) static void cs_dbs_timer(struct work_struct *work) { struct cs_cpu_dbs_info_s *dbs_info = container_of(work, - struct cs_cpu_dbs_info_s, cdbs.work.work); + struct cs_cpu_dbs_info_s, cdbs.dwork.work); unsigned int cpu = dbs_info->cdbs.cur_policy->cpu; struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 57a39f8a92b7..6024bbc782c0 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -165,7 +165,7 @@ static inline void __gov_queue_work(int cpu, struct dbs_data *dbs_data, { struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); - mod_delayed_work_on(cpu, system_wq, &cdbs->work, delay); + mod_delayed_work_on(cpu, system_wq, &cdbs->dwork, delay); } void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, @@ -204,7 +204,7 @@ static inline void gov_cancel_work(struct dbs_data *dbs_data, for_each_cpu(i, policy->cpus) { cdbs = dbs_data->cdata->get_cpu_cdbs(i); - cancel_delayed_work_sync(&cdbs->work); + cancel_delayed_work_sync(&cdbs->dwork); } } @@ -367,7 +367,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; mutex_init(&j_cdbs->timer_mutex); - INIT_DEFERRABLE_WORK(&j_cdbs->work, cdata->gov_dbs_timer); + INIT_DEFERRABLE_WORK(&j_cdbs->dwork, cdata->gov_dbs_timer); } if (cdata->governor == GOV_CONSERVATIVE) { diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 34736f5e869d..352eecaae789 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -142,7 +142,7 @@ struct cpu_dbs_common_info { */ unsigned int prev_load; struct cpufreq_policy *cur_policy; - struct delayed_work work; + struct delayed_work dwork; /* * percpu mutex that serializes governor limit change with gov_dbs_timer * invocation. We do not want gov_dbs_timer to run when user is changing diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 3c1e10f2304c..830aef1db8c3 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -194,7 +194,7 @@ static void od_check_cpu(int cpu, unsigned int load) static void od_dbs_timer(struct work_struct *work) { struct od_cpu_dbs_info_s *dbs_info = - container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work); + container_of(work, struct od_cpu_dbs_info_s, cdbs.dwork.work); unsigned int cpu = dbs_info->cdbs.cur_policy->cpu; struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); @@ -275,18 +275,18 @@ static void update_sampling_rate(struct dbs_data *dbs_data, mutex_lock(&dbs_info->cdbs.timer_mutex); - if (!delayed_work_pending(&dbs_info->cdbs.work)) { + if (!delayed_work_pending(&dbs_info->cdbs.dwork)) { mutex_unlock(&dbs_info->cdbs.timer_mutex); continue; } next_sampling = jiffies + usecs_to_jiffies(new_rate); - appointed_at = dbs_info->cdbs.work.timer.expires; + appointed_at = dbs_info->cdbs.dwork.timer.expires; if (time_before(next_sampling, appointed_at)) { mutex_unlock(&dbs_info->cdbs.timer_mutex); - cancel_delayed_work_sync(&dbs_info->cdbs.work); + cancel_delayed_work_sync(&dbs_info->cdbs.dwork); mutex_lock(&dbs_info->cdbs.timer_mutex); gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, -- cgit v1.3-6-gb490 From d3574c851148266177ea9ecae10a317e6eae94de Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 19 Jun 2015 17:18:02 +0530 Subject: cpufreq: governor: Drop unused field 'cpu' Its not used at all, drop it. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 1 - drivers/cpufreq/cpufreq_governor.h | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 6024bbc782c0..2149ba7d32a8 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -353,7 +353,6 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, struct cpu_dbs_common_info *j_cdbs = cdata->get_cpu_cdbs(j); unsigned int prev_load; - j_cdbs->cpu = j; j_cdbs->cur_policy = policy; j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy); diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 352eecaae789..1bbf8c87fdd5 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -130,7 +130,6 @@ static void *get_cpu_dbs_info_s(int cpu) \ /* Per cpu structures */ struct cpu_dbs_common_info { - int cpu; u64 prev_cpu_idle; u64 prev_cpu_wall; u64 prev_cpu_nice; -- cgit v1.3-6-gb490 From 875b8508f9607b92e3ef4ece2fddf86d61351085 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 19 Jun 2015 17:18:03 +0530 Subject: cpufreq: governor: Rename 'cpu_dbs_common_info' to 'cpu_dbs_info' Its not common info to all CPUs, but a structure representing common type of cpu info to both governor types. Lets drop 'common_' from its name. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 19 +++++++++---------- drivers/cpufreq/cpufreq_governor.h | 13 ++++++------- 2 files changed, 15 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 2149ba7d32a8..529f236f2d05 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -32,7 +32,7 @@ static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data) void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) { - struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); struct od_dbs_tuners *od_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; struct cpufreq_policy *policy; @@ -64,7 +64,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) /* Get Absolute Load */ for_each_cpu(j, policy->cpus) { - struct cpu_dbs_common_info *j_cdbs; + struct cpu_dbs_info *j_cdbs; u64 cur_wall_time, cur_idle_time; unsigned int idle_time, wall_time; unsigned int load; @@ -163,7 +163,7 @@ EXPORT_SYMBOL_GPL(dbs_check_cpu); static inline void __gov_queue_work(int cpu, struct dbs_data *dbs_data, unsigned int delay) { - struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); mod_delayed_work_on(cpu, system_wq, &cdbs->dwork, delay); } @@ -199,7 +199,7 @@ EXPORT_SYMBOL_GPL(gov_queue_work); static inline void gov_cancel_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy) { - struct cpu_dbs_common_info *cdbs; + struct cpu_dbs_info *cdbs; int i; for_each_cpu(i, policy->cpus) { @@ -209,8 +209,7 @@ static inline void gov_cancel_work(struct dbs_data *dbs_data, } /* Will return if we need to evaluate cpu load again or not */ -bool need_load_eval(struct cpu_dbs_common_info *cdbs, - unsigned int sampling_rate) +bool need_load_eval(struct cpu_dbs_info *cdbs, unsigned int sampling_rate) { if (policy_is_shared(cdbs->cur_policy)) { ktime_t time_now = ktime_get(); @@ -330,7 +329,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int sampling_rate, ignore_nice, j, cpu = policy->cpu; - struct cpu_dbs_common_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); int io_busy = 0; if (!policy->cur) @@ -350,7 +349,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, } for_each_cpu(j, policy->cpus) { - struct cpu_dbs_common_info *j_cdbs = cdata->get_cpu_cdbs(j); + struct cpu_dbs_info *j_cdbs = cdata->get_cpu_cdbs(j); unsigned int prev_load; j_cdbs->cur_policy = policy; @@ -398,7 +397,7 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; - struct cpu_dbs_common_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); if (cdata->governor == GOV_CONSERVATIVE) { struct cs_cpu_dbs_info_s *cs_dbs_info = @@ -418,7 +417,7 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; - struct cpu_dbs_common_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); if (!cpu_cdbs->cur_policy) return; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 1bbf8c87fdd5..6b5e33f68064 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -109,7 +109,7 @@ store_one(_gov, file_name) /* create helper routines */ #define define_get_cpu_dbs_routines(_dbs_info) \ -static struct cpu_dbs_common_info *get_cpu_cdbs(int cpu) \ +static struct cpu_dbs_info *get_cpu_cdbs(int cpu) \ { \ return &per_cpu(_dbs_info, cpu).cdbs; \ } \ @@ -129,7 +129,7 @@ static void *get_cpu_dbs_info_s(int cpu) \ */ /* Per cpu structures */ -struct cpu_dbs_common_info { +struct cpu_dbs_info { u64 prev_cpu_idle; u64 prev_cpu_wall; u64 prev_cpu_nice; @@ -152,7 +152,7 @@ struct cpu_dbs_common_info { }; struct od_cpu_dbs_info_s { - struct cpu_dbs_common_info cdbs; + struct cpu_dbs_info cdbs; struct cpufreq_frequency_table *freq_table; unsigned int freq_lo; unsigned int freq_lo_jiffies; @@ -162,7 +162,7 @@ struct od_cpu_dbs_info_s { }; struct cs_cpu_dbs_info_s { - struct cpu_dbs_common_info cdbs; + struct cpu_dbs_info cdbs; unsigned int down_skip; unsigned int requested_freq; unsigned int enable:1; @@ -203,7 +203,7 @@ struct common_dbs_data { */ struct dbs_data *gdbs_data; - struct cpu_dbs_common_info *(*get_cpu_cdbs)(int cpu); + struct cpu_dbs_info *(*get_cpu_cdbs)(int cpu); void *(*get_cpu_dbs_info_s)(int cpu); void (*gov_dbs_timer)(struct work_struct *work); void (*gov_check_cpu)(int cpu, unsigned int load); @@ -264,8 +264,7 @@ static ssize_t show_sampling_rate_min_gov_pol \ extern struct mutex cpufreq_governor_lock; void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); -bool need_load_eval(struct cpu_dbs_common_info *cdbs, - unsigned int sampling_rate); +bool need_load_eval(struct cpu_dbs_info *cdbs, unsigned int sampling_rate); int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct common_dbs_data *cdata, unsigned int event); void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, -- cgit v1.3-6-gb490 From 49a9a40c1b48d24f0fd9a6b6be8a4038f47d13bf Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 19 Jun 2015 17:18:04 +0530 Subject: cpufreq: governor: name pointer to cpu_dbs_info as 'cdbs' It is called as 'cdbs' at most of the places and 'cpu_dbs' at others. Lets use 'cdbs' consistently for better readability. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 529f236f2d05..4ea13f182154 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -329,7 +329,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int sampling_rate, ignore_nice, j, cpu = policy->cpu; - struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); int io_busy = 0; if (!policy->cur) @@ -385,7 +385,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, } /* Initiate timer time stamp */ - cpu_cdbs->time_stamp = ktime_get(); + cdbs->time_stamp = ktime_get(); gov_queue_work(dbs_data, policy, delay_for_sampling_rate(sampling_rate), true); @@ -397,7 +397,7 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; - struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); if (cdata->governor == GOV_CONSERVATIVE) { struct cs_cpu_dbs_info_s *cs_dbs_info = @@ -408,8 +408,8 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, gov_cancel_work(dbs_data, policy); - mutex_destroy(&cpu_cdbs->timer_mutex); - cpu_cdbs->cur_policy = NULL; + mutex_destroy(&cdbs->timer_mutex); + cdbs->cur_policy = NULL; } static void cpufreq_governor_limits(struct cpufreq_policy *policy, @@ -417,20 +417,20 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; - struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); - if (!cpu_cdbs->cur_policy) + if (!cdbs->cur_policy) return; - mutex_lock(&cpu_cdbs->timer_mutex); - if (policy->max < cpu_cdbs->cur_policy->cur) - __cpufreq_driver_target(cpu_cdbs->cur_policy, policy->max, + mutex_lock(&cdbs->timer_mutex); + if (policy->max < cdbs->cur_policy->cur) + __cpufreq_driver_target(cdbs->cur_policy, policy->max, CPUFREQ_RELATION_H); - else if (policy->min > cpu_cdbs->cur_policy->cur) - __cpufreq_driver_target(cpu_cdbs->cur_policy, policy->min, + else if (policy->min > cdbs->cur_policy->cur) + __cpufreq_driver_target(cdbs->cur_policy, policy->min, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); - mutex_unlock(&cpu_cdbs->timer_mutex); + mutex_unlock(&cdbs->timer_mutex); } int cpufreq_governor_dbs(struct cpufreq_policy *policy, -- cgit v1.3-6-gb490 From 42994af63cd1aafc9289035cf621e501b08732e9 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 19 Jun 2015 17:18:05 +0530 Subject: cpufreq: governor: rename cur_policy as policy Just call it 'policy', cur_policy is unnecessarily long and doesn't have any special meaning. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_conservative.c | 10 +++++----- drivers/cpufreq/cpufreq_governor.c | 18 +++++++++--------- drivers/cpufreq/cpufreq_governor.h | 2 +- drivers/cpufreq/cpufreq_ondemand.c | 19 ++++++++++--------- 4 files changed, 25 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 0e3ec1d968d9..af47d322679e 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -47,7 +47,7 @@ static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners, static void cs_check_cpu(int cpu, unsigned int load) { struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); - struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; + struct cpufreq_policy *policy = dbs_info->cdbs.policy; struct dbs_data *dbs_data = policy->governor_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; @@ -106,10 +106,10 @@ static void cs_dbs_timer(struct work_struct *work) { struct cs_cpu_dbs_info_s *dbs_info = container_of(work, struct cs_cpu_dbs_info_s, cdbs.dwork.work); - unsigned int cpu = dbs_info->cdbs.cur_policy->cpu; + unsigned int cpu = dbs_info->cdbs.policy->cpu; struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); - struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data; + struct dbs_data *dbs_data = dbs_info->cdbs.policy->governor_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; int delay = delay_for_sampling_rate(cs_tuners->sampling_rate); bool modify_all = true; @@ -120,7 +120,7 @@ static void cs_dbs_timer(struct work_struct *work) else dbs_check_cpu(dbs_data, cpu); - gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all); + gov_queue_work(dbs_data, dbs_info->cdbs.policy, delay, modify_all); mutex_unlock(&core_dbs_info->cdbs.timer_mutex); } @@ -135,7 +135,7 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, if (!dbs_info->enable) return 0; - policy = dbs_info->cdbs.cur_policy; + policy = dbs_info->cdbs.policy; /* * we only care if our internally tracked freq moves outside the 'valid' diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 4ea13f182154..c0566f86caed 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -60,7 +60,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) ignore_nice = cs_tuners->ignore_nice_load; } - policy = cdbs->cur_policy; + policy = cdbs->policy; /* Get Absolute Load */ for_each_cpu(j, policy->cpus) { @@ -211,7 +211,7 @@ static inline void gov_cancel_work(struct dbs_data *dbs_data, /* Will return if we need to evaluate cpu load again or not */ bool need_load_eval(struct cpu_dbs_info *cdbs, unsigned int sampling_rate) { - if (policy_is_shared(cdbs->cur_policy)) { + if (policy_is_shared(cdbs->policy)) { ktime_t time_now = ktime_get(); s64 delta_us = ktime_us_delta(time_now, cdbs->time_stamp); @@ -352,7 +352,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, struct cpu_dbs_info *j_cdbs = cdata->get_cpu_cdbs(j); unsigned int prev_load; - j_cdbs->cur_policy = policy; + j_cdbs->policy = policy; j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy); @@ -409,7 +409,7 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, gov_cancel_work(dbs_data, policy); mutex_destroy(&cdbs->timer_mutex); - cdbs->cur_policy = NULL; + cdbs->policy = NULL; } static void cpufreq_governor_limits(struct cpufreq_policy *policy, @@ -419,15 +419,15 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy, unsigned int cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); - if (!cdbs->cur_policy) + if (!cdbs->policy) return; mutex_lock(&cdbs->timer_mutex); - if (policy->max < cdbs->cur_policy->cur) - __cpufreq_driver_target(cdbs->cur_policy, policy->max, + if (policy->max < cdbs->policy->cur) + __cpufreq_driver_target(cdbs->policy, policy->max, CPUFREQ_RELATION_H); - else if (policy->min > cdbs->cur_policy->cur) - __cpufreq_driver_target(cdbs->cur_policy, policy->min, + else if (policy->min > cdbs->policy->cur) + __cpufreq_driver_target(cdbs->policy, policy->min, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); mutex_unlock(&cdbs->timer_mutex); diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 6b5e33f68064..a0f8eb79ee6d 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -140,7 +140,7 @@ struct cpu_dbs_info { * wake-up from idle. */ unsigned int prev_load; - struct cpufreq_policy *cur_policy; + struct cpufreq_policy *policy; struct delayed_work dwork; /* * percpu mutex that serializes governor limit change with gov_dbs_timer diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 830aef1db8c3..d29c6f9c6e3e 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -155,7 +155,7 @@ static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq) static void od_check_cpu(int cpu, unsigned int load) { struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; + struct cpufreq_policy *policy = dbs_info->cdbs.policy; struct dbs_data *dbs_data = policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; @@ -195,10 +195,10 @@ static void od_dbs_timer(struct work_struct *work) { struct od_cpu_dbs_info_s *dbs_info = container_of(work, struct od_cpu_dbs_info_s, cdbs.dwork.work); - unsigned int cpu = dbs_info->cdbs.cur_policy->cpu; + unsigned int cpu = dbs_info->cdbs.policy->cpu; struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data; + struct dbs_data *dbs_data = dbs_info->cdbs.policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; int delay = 0, sample_type = core_dbs_info->sample_type; bool modify_all = true; @@ -213,8 +213,9 @@ static void od_dbs_timer(struct work_struct *work) core_dbs_info->sample_type = OD_NORMAL_SAMPLE; if (sample_type == OD_SUB_SAMPLE) { delay = core_dbs_info->freq_lo_jiffies; - __cpufreq_driver_target(core_dbs_info->cdbs.cur_policy, - core_dbs_info->freq_lo, CPUFREQ_RELATION_H); + __cpufreq_driver_target(core_dbs_info->cdbs.policy, + core_dbs_info->freq_lo, + CPUFREQ_RELATION_H); } else { dbs_check_cpu(dbs_data, cpu); if (core_dbs_info->freq_lo) { @@ -229,7 +230,7 @@ max_delay: delay = delay_for_sampling_rate(od_tuners->sampling_rate * core_dbs_info->rate_mult); - gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all); + gov_queue_work(dbs_data, dbs_info->cdbs.policy, delay, modify_all); mutex_unlock(&core_dbs_info->cdbs.timer_mutex); } @@ -289,8 +290,8 @@ static void update_sampling_rate(struct dbs_data *dbs_data, cancel_delayed_work_sync(&dbs_info->cdbs.dwork); mutex_lock(&dbs_info->cdbs.timer_mutex); - gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, - usecs_to_jiffies(new_rate), true); + gov_queue_work(dbs_data, dbs_info->cdbs.policy, + usecs_to_jiffies(new_rate), true); } mutex_unlock(&dbs_info->cdbs.timer_mutex); @@ -559,7 +560,7 @@ static void od_set_powersave_bias(unsigned int powersave_bias) if (cpumask_test_cpu(cpu, &done)) continue; - policy = per_cpu(od_cpu_dbs_info, cpu).cdbs.cur_policy; + policy = per_cpu(od_cpu_dbs_info, cpu).cdbs.policy; if (!policy) continue; -- cgit v1.3-6-gb490 From 800e3b9a68011c4124f380d50e2117523c41a843 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 17 Jul 2015 16:44:05 -0700 Subject: Input: drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5589-keys.c | 1 - drivers/input/keyboard/cap11xx.c | 1 - drivers/input/keyboard/lm8333.c | 1 - drivers/input/keyboard/mcs_touchkey.c | 1 - drivers/input/keyboard/mpr121_touchkey.c | 1 - drivers/input/keyboard/qt1070.c | 1 - drivers/input/keyboard/qt2160.c | 1 - drivers/input/keyboard/tca8418_keypad.c | 1 - drivers/input/misc/adxl34x-i2c.c | 1 - drivers/input/misc/bma150.c | 1 - drivers/input/misc/cma3000_d0x_i2c.c | 1 - drivers/input/misc/drv260x.c | 1 - drivers/input/misc/drv2665.c | 1 - drivers/input/misc/drv2667.c | 1 - drivers/input/misc/gp2ap002a00f.c | 1 - drivers/input/misc/kxtj9.c | 1 - drivers/input/misc/mpu3050.c | 1 - drivers/input/misc/pcf8574_keypad.c | 1 - drivers/input/mouse/cyapa.c | 1 - drivers/input/mouse/elan_i2c_core.c | 1 - drivers/input/mouse/synaptics_i2c.c | 1 - drivers/input/touchscreen/ad7879-i2c.c | 1 - drivers/input/touchscreen/ar1021_i2c.c | 1 - drivers/input/touchscreen/atmel_mxt_ts.c | 1 - drivers/input/touchscreen/auo-pixcir-ts.c | 1 - drivers/input/touchscreen/bu21013_ts.c | 1 - drivers/input/touchscreen/chipone_icn8318.c | 1 - drivers/input/touchscreen/cy8ctmg110_ts.c | 1 - drivers/input/touchscreen/cyttsp4_i2c.c | 1 - drivers/input/touchscreen/cyttsp_i2c.c | 1 - drivers/input/touchscreen/edt-ft5x06.c | 1 - drivers/input/touchscreen/egalax_ts.c | 1 - drivers/input/touchscreen/elants_i2c.c | 1 - drivers/input/touchscreen/goodix.c | 1 - drivers/input/touchscreen/ili210x.c | 1 - drivers/input/touchscreen/max11801_ts.c | 1 - drivers/input/touchscreen/mms114.c | 1 - drivers/input/touchscreen/pixcir_i2c_ts.c | 1 - drivers/input/touchscreen/st1232.c | 1 - drivers/input/touchscreen/tsc2007.c | 1 - drivers/input/touchscreen/wacom_i2c.c | 1 - drivers/input/touchscreen/zforce_ts.c | 1 - 42 files changed, 42 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 6ed83cf8b74e..4d446d5085aa 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -1097,7 +1097,6 @@ MODULE_DEVICE_TABLE(i2c, adp5589_id); static struct i2c_driver adp5589_driver = { .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, .pm = &adp5589_dev_pm_ops, }, .probe = adp5589_probe, diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index f07461a64d85..b58fd9d72d92 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c @@ -361,7 +361,6 @@ MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids); static struct i2c_driver cap11xx_i2c_driver = { .driver = { .name = "cap11xx", - .owner = THIS_MODULE, .of_match_table = cap11xx_dt_ids, }, .id_table = cap11xx_i2c_ids, diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c index 0ad422b8a260..c717e8f3c964 100644 --- a/drivers/input/keyboard/lm8333.c +++ b/drivers/input/keyboard/lm8333.c @@ -223,7 +223,6 @@ MODULE_DEVICE_TABLE(i2c, lm8333_id); static struct i2c_driver lm8333_driver = { .driver = { .name = "lm8333", - .owner = THIS_MODULE, }, .probe = lm8333_probe, .remove = lm8333_remove, diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index 375b05ca8e2a..31090d71a685 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -265,7 +265,6 @@ MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id); static struct i2c_driver mcs_touchkey_driver = { .driver = { .name = "mcs_touchkey", - .owner = THIS_MODULE, .pm = &mcs_touchkey_pm_ops, }, .probe = mcs_touchkey_probe, diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 3aa2ec45bcab..0fd612dd76ed 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -305,7 +305,6 @@ MODULE_DEVICE_TABLE(i2c, mpr121_id); static struct i2c_driver mpr_touchkey_driver = { .driver = { .name = "mpr121", - .owner = THIS_MODULE, .pm = &mpr121_touchkey_pm_ops, }, .id_table = mpr121_id, diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index 52cd6e88acd7..5a5778729e37 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -277,7 +277,6 @@ MODULE_DEVICE_TABLE(i2c, qt1070_id); static struct i2c_driver qt1070_driver = { .driver = { .name = "qt1070", - .owner = THIS_MODULE, .pm = &qt1070_pm_ops, }, .id_table = qt1070_id, diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 819b22897c13..43b86482dda0 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -497,7 +497,6 @@ MODULE_DEVICE_TABLE(i2c, qt2160_idtable); static struct i2c_driver qt2160_driver = { .driver = { .name = "qt2160", - .owner = THIS_MODULE, }, .id_table = qt2160_idtable, diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 4e491c1762cf..9002298698fc 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -404,7 +404,6 @@ MODULE_ALIAS("i2c:tca8418"); static struct i2c_driver tca8418_keypad_driver = { .driver = { .name = TCA8418_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tca8418_dt_ids), }, .probe = tca8418_keypad_probe, diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c index bdb5d03b296e..a8b0a2eec344 100644 --- a/drivers/input/misc/adxl34x-i2c.c +++ b/drivers/input/misc/adxl34x-i2c.c @@ -158,7 +158,6 @@ MODULE_DEVICE_TABLE(of, adxl34x_of_id); static struct i2c_driver adxl34x_driver = { .driver = { .name = "adxl34x", - .owner = THIS_MODULE, .pm = &adxl34x_i2c_pm, .of_match_table = of_match_ptr(adxl34x_of_id), }, diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index c2780493b0ed..1d0e61d7c131 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -653,7 +653,6 @@ MODULE_DEVICE_TABLE(i2c, bma150_id); static struct i2c_driver bma150_driver = { .driver = { - .owner = THIS_MODULE, .name = BMA150_DRIVER, .pm = &bma150_pm, }, diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c index 4fdef98ceb56..c7021916b64b 100644 --- a/drivers/input/misc/cma3000_d0x_i2c.c +++ b/drivers/input/misc/cma3000_d0x_i2c.c @@ -118,7 +118,6 @@ static struct i2c_driver cma3000_i2c_driver = { .id_table = cma3000_i2c_id, .driver = { .name = "cma3000_i2c_accl", - .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &cma3000_i2c_pm_ops, #endif diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 0e3af55d9e25..e65496e6463d 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -720,7 +720,6 @@ static struct i2c_driver drv260x_driver = { .probe = drv260x_probe, .driver = { .name = "drv260x-haptics", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(drv260x_of_match), .pm = &drv260x_pm_ops, }, diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index e9501fdca5ef..327a63c2f07d 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -309,7 +309,6 @@ static struct i2c_driver drv2665_driver = { .probe = drv2665_probe, .driver = { .name = "drv2665-haptics", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(drv2665_of_match), .pm = &drv2665_pm_ops, }, diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index a231342207f9..46a4be4e9dc3 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -484,7 +484,6 @@ static struct i2c_driver drv2667_driver = { .probe = drv2667_probe, .driver = { .name = "drv2667-haptics", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(drv2667_of_match), .pm = &drv2667_pm_ops, }, diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c index 0ac176d66a6f..ba301af91b95 100644 --- a/drivers/input/misc/gp2ap002a00f.c +++ b/drivers/input/misc/gp2ap002a00f.c @@ -271,7 +271,6 @@ static const struct i2c_device_id gp2a_i2c_id[] = { static struct i2c_driver gp2a_i2c_driver = { .driver = { .name = GP2A_I2C_NAME, - .owner = THIS_MODULE, .pm = &gp2a_pm, }, .probe = gp2a_probe, diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index 6e29349da537..e058d711256a 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -658,7 +658,6 @@ MODULE_DEVICE_TABLE(i2c, kxtj9_id); static struct i2c_driver kxtj9_driver = { .driver = { .name = NAME, - .owner = THIS_MODULE, .pm = &kxtj9_pm_ops, }, .probe = kxtj9_probe, diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c index 5e5051351c3a..f088db31cfc7 100644 --- a/drivers/input/misc/mpu3050.c +++ b/drivers/input/misc/mpu3050.c @@ -466,7 +466,6 @@ MODULE_DEVICE_TABLE(of, mpu3050_of_match); static struct i2c_driver mpu3050_i2c_driver = { .driver = { .name = "mpu3050", - .owner = THIS_MODULE, .pm = &mpu3050_pm, .of_match_table = mpu3050_of_match, }, diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index 97f711a7bd20..4abdf1efb3e0 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -208,7 +208,6 @@ MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id); static struct i2c_driver pcf8574_kp_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &pcf8574_kp_pm_ops, #endif diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index efe148474e7f..dfbfd494bb1f 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -1382,7 +1382,6 @@ MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id); static struct i2c_driver cyapa_driver = { .driver = { .name = "cyapa", - .owner = THIS_MODULE, .pm = &cyapa_pm_ops, .acpi_match_table = ACPI_PTR(cyapa_acpi_id), }, diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 62641f2adaf7..e7ef4ab1b37d 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1183,7 +1183,6 @@ MODULE_DEVICE_TABLE(of, elan_of_match); static struct i2c_driver elan_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .pm = &elan_pm_ops, .acpi_match_table = ACPI_PTR(elan_acpi_id), .of_match_table = of_match_ptr(elan_of_match), diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index ffceedcaf3c8..aa7c5da60800 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -655,7 +655,6 @@ MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table); static struct i2c_driver synaptics_i2c_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .pm = &synaptics_i2c_pm, }, diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index dcf390771549..d66962c5b1c2 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -94,7 +94,6 @@ MODULE_DEVICE_TABLE(i2c, ad7879_id); static struct i2c_driver ad7879_i2c_driver = { .driver = { .name = "ad7879", - .owner = THIS_MODULE, .pm = &ad7879_pm_ops, }, .probe = ad7879_i2c_probe, diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index f0b954d46a25..71b5a634cf6d 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -166,7 +166,6 @@ MODULE_DEVICE_TABLE(of, ar1021_i2c_of_match); static struct i2c_driver ar1021_i2c_driver = { .driver = { .name = "ar1021_i2c", - .owner = THIS_MODULE, .pm = &ar1021_i2c_pm, .of_match_table = ar1021_i2c_of_match, }, diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index dfc7309e3d38..8efe7a002f1e 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2666,7 +2666,6 @@ MODULE_DEVICE_TABLE(i2c, mxt_id); static struct i2c_driver mxt_driver = { .driver = { .name = "atmel_mxt_ts", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(mxt_of_match), .acpi_match_table = ACPI_PTR(mxt_acpi_id), .pm = &mxt_pm_ops, diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 40e02dd5b2f9..38c06f754acd 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -686,7 +686,6 @@ MODULE_DEVICE_TABLE(of, auo_pixcir_ts_dt_idtable); static struct i2c_driver auo_pixcir_driver = { .driver = { - .owner = THIS_MODULE, .name = "auo_pixcir_ts", .pm = &auo_pixcir_pm_ops, .of_match_table = of_match_ptr(auo_pixcir_ts_dt_idtable), diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index b9b5ddad6658..931417eb4f5a 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -716,7 +716,6 @@ MODULE_DEVICE_TABLE(i2c, bu21013_id); static struct i2c_driver bu21013_driver = { .driver = { .name = DRIVER_TP, - .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &bu21013_dev_pm_ops, #endif diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c index 32e9db0e04bf..22a6fead8cfb 100644 --- a/drivers/input/touchscreen/chipone_icn8318.c +++ b/drivers/input/touchscreen/chipone_icn8318.c @@ -300,7 +300,6 @@ MODULE_DEVICE_TABLE(i2c, icn8318_i2c_id); static struct i2c_driver icn8318_driver = { .driver = { - .owner = THIS_MODULE, .name = "chipone_icn8318", .pm = &icn8318_pm_ops, .of_match_table = icn8318_of_match, diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index f2119ee0e21b..cc1d1350074e 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -347,7 +347,6 @@ MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable); static struct i2c_driver cy8ctmg110_driver = { .driver = { - .owner = THIS_MODULE, .name = CY8CTMG110_DRIVER_NAME, .pm = &cy8ctmg110_pm, }, diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c index 8e2012c79058..9a323dd915de 100644 --- a/drivers/input/touchscreen/cyttsp4_i2c.c +++ b/drivers/input/touchscreen/cyttsp4_i2c.c @@ -74,7 +74,6 @@ MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id); static struct i2c_driver cyttsp4_i2c_driver = { .driver = { .name = CYTTSP4_I2C_NAME, - .owner = THIS_MODULE, .pm = &cyttsp4_pm_ops, }, .probe = cyttsp4_i2c_probe, diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 63104a86a9bd..519e2de2f8df 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -74,7 +74,6 @@ MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id); static struct i2c_driver cyttsp_i2c_driver = { .driver = { .name = CY_I2C_NAME, - .owner = THIS_MODULE, .pm = &cyttsp_pm_ops, }, .probe = cyttsp_i2c_probe, diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 8f8f3199be39..48de1e8b3c93 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1134,7 +1134,6 @@ MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); static struct i2c_driver edt_ft5x06_ts_driver = { .driver = { - .owner = THIS_MODULE, .name = "edt_ft5x06", .of_match_table = of_match_ptr(edt_ft5x06_of_match), .pm = &edt_ft5x06_ts_pm_ops, diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 4c56299284ef..7bce2d90ec74 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -268,7 +268,6 @@ static const struct of_device_id egalax_ts_dt_ids[] = { static struct i2c_driver egalax_ts_driver = { .driver = { .name = "egalax_ts", - .owner = THIS_MODULE, .pm = &egalax_ts_pm_ops, .of_match_table = egalax_ts_dt_ids, }, diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 0efd766a545b..746137694137 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1261,7 +1261,6 @@ static struct i2c_driver elants_i2c_driver = { .id_table = elants_i2c_id, .driver = { .name = DEVICE_NAME, - .owner = THIS_MODULE, .pm = &elants_i2c_pm_ops, .acpi_match_table = ACPI_PTR(elants_acpi_id), .of_match_table = of_match_ptr(elants_of_match), diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index b4d12e29abff..ccd9dca61195 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -412,7 +412,6 @@ static struct i2c_driver goodix_ts_driver = { .id_table = goodix_ts_id, .driver = { .name = "Goodix-TS", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(goodix_acpi_match), .of_match_table = of_match_ptr(goodix_of_match), }, diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index da6dc819c846..cf0dc2f0b1be 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -343,7 +343,6 @@ MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); static struct i2c_driver ili210x_ts_driver = { .driver = { .name = "ili210x_i2c", - .owner = THIS_MODULE, .pm = &ili210x_i2c_pm, }, .id_table = ili210x_i2c_id, diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index a68ec142ee9a..82079cde849c 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -229,7 +229,6 @@ MODULE_DEVICE_TABLE(i2c, max11801_ts_id); static struct i2c_driver max11801_ts_driver = { .driver = { .name = "max11801_ts", - .owner = THIS_MODULE, }, .id_table = max11801_ts_id, .probe = max11801_ts_probe, diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 67c0d31613d8..6b69f461733c 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -577,7 +577,6 @@ static const struct of_device_id mms114_dt_match[] = { static struct i2c_driver mms114_driver = { .driver = { .name = "mms114", - .owner = THIS_MODULE, .pm = &mms114_pm_ops, .of_match_table = of_match_ptr(mms114_dt_match), }, diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 68d0d549797c..4c71d631cbae 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -604,7 +604,6 @@ MODULE_DEVICE_TABLE(of, pixcir_of_match); static struct i2c_driver pixcir_i2c_ts_driver = { .driver = { - .owner = THIS_MODULE, .name = "pixcir_ts", .pm = &pixcir_dev_pm_ops, .of_match_table = of_match_ptr(pixcir_of_match), diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 697e26e52d54..e943678ce54c 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -296,7 +296,6 @@ static struct i2c_driver st1232_ts_driver = { .id_table = st1232_ts_id, .driver = { .name = ST1232_TS_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(st1232_ts_dt_ids), .pm = &st1232_ts_pm_ops, }, diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index ccc8aa615709..5d0cd51c6f41 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -482,7 +482,6 @@ MODULE_DEVICE_TABLE(of, tsc2007_of_match); static struct i2c_driver tsc2007_driver = { .driver = { - .owner = THIS_MODULE, .name = "tsc2007", .of_match_table = of_match_ptr(tsc2007_of_match), }, diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index 32f8ac003936..8d7a2852caef 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -271,7 +271,6 @@ MODULE_DEVICE_TABLE(i2c, wacom_i2c_id); static struct i2c_driver wacom_i2c_driver = { .driver = { .name = "wacom_i2c", - .owner = THIS_MODULE, .pm = &wacom_i2c_pm, }, diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index c4cffcfb03d3..d00e1e33b657 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -919,7 +919,6 @@ MODULE_DEVICE_TABLE(of, zforce_dt_idtable); 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), -- cgit v1.3-6-gb490 From def56bba7a5c623fd887d1f4b4c864521d615a76 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Wed, 15 Jul 2015 10:36:37 +0800 Subject: input: snvs_pwrkey: use "wakeup-source" as deivce tree property name Instead of inventing a new property name, let's use "wakeup-source" to be consistent with other driver and subsystem bindings. Signed-off-by: Shawn Guo Acked-by: Dmitry Torokhov --- Documentation/devicetree/bindings/crypto/fsl-sec4.txt | 2 +- drivers/input/keyboard/snvs_pwrkey.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt index 71a39c5bd486..f16bbd6644b8 100644 --- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -408,7 +408,7 @@ System ON/OFF key driver Value type: Definition: Keycode to emit, KEY_POWER by default. - - wakeup: + - wakeup-source: Usage: option Value type: Definition: Button can wake-up the system. diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c index 512a1fc2a864..78fd24ca3813 100644 --- a/drivers/input/keyboard/snvs_pwrkey.c +++ b/drivers/input/keyboard/snvs_pwrkey.c @@ -122,7 +122,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n"); } - pdata->wakeup = of_property_read_bool(np, "wakeup"); + pdata->wakeup = of_property_read_bool(np, "wakeup-source"); pdata->irq = platform_get_irq(pdev, 0); if (pdata->irq < 0) { -- cgit v1.3-6-gb490 From 1c3b8c2fe71a5052270167a1c5786aaf0d86cf19 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:31 -0700 Subject: freescale: remove incorrect copied comment The comment in question is word-for-word copied from ixgbe, and clearly has no meaning in freescale's driver. (it even says 'return an error' when the code clearly does not). Remove the comment as it is obviously incorrect and not applicable to the code as it is today. CC: Pantelis Antoniou CC: Vitaly Bordug CC: Signed-off-by: Jacob Keller Acked-by: Richard Cochran Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/freescale/fec_ptp.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index a15663ad7f5e..7a8386a8244d 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -506,12 +506,6 @@ int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr) break; default: - /* - * register RXMTRL must be set in order to do V1 packets, - * therefore it is not possible to time stamp both V1 Sync and - * Delay_Req messages and hardware does not support - * timestamping all packets => return error - */ fep->hwts_rx_en = 1; config.rx_filter = HWTSTAMP_FILTER_ALL; break; -- cgit v1.3-6-gb490 From dd3950c6d7185fbf9ec78a451b18d8807f35c6f7 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:32 -0700 Subject: bnx2x: only report most generic filters in get_ts_info CC: Ariel Elior Signed-off-by: Jacob Keller Acked-by: Richard Cochran Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 76b9052a961c..c783b57b2c9b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -3562,17 +3562,8 @@ static int bnx2x_get_ts_info(struct net_device *dev, info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ); + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); info->tx_types = (1 << HWTSTAMP_TX_OFF)|(1 << HWTSTAMP_TX_ON); -- cgit v1.3-6-gb490 From c583cc430cf6942548fe658aac5a39eb9f371faf Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:33 -0700 Subject: i40e: only report generic filters in get_ts_info Signed-off-by: Jacob Keller Acked-by: Richard Cochran Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 0b68f61eeb0c..f2075d5b800c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1467,17 +1467,8 @@ static int i40e_get_ts_info(struct net_device *dev, info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ); + (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); return 0; } -- cgit v1.3-6-gb490 From 97aebc1b3cdfd445a0a051090f0dcc6018b6df2c Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:34 -0700 Subject: igb: only report generic filters in get_ts_info Signed-off-by: Jacob Keller Acked-by: Richard Cochran Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_ethtool.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index d5673eb90c54..109cad928e71 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -2396,10 +2396,6 @@ static int igb_get_ts_info(struct net_device *dev, info->rx_filters |= (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); return 0; -- cgit v1.3-6-gb490 From 044651f58536f209f1efdcdd1ae20788cf6d05c2 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:35 -0700 Subject: ixgbe: only report generic filters in get_ts_info Signed-off-by: Jacob Keller Acked-by: Richard Cochran Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index ec7b2324b77b..f7aeb560a504 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -2938,14 +2938,6 @@ static int ixgbe_get_ts_info(struct net_device *dev, (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); break; default: -- cgit v1.3-6-gb490 From 7415991ead78de1d340fb55d5b94d5b3287ab785 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:36 -0700 Subject: siena: only report generic filters in get_ts_info CC: Solarflare linux maintainers CC: Shradha Shah Signed-off-by: Jacob Keller Acked-by: Richard Cochran Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/sfc/siena.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index b323b9167526..b2f886d90429 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -1042,9 +1042,5 @@ const struct efx_nic_type siena_a0_nic_type = { .max_rx_ip_filters = FR_BZ_RX_FILTER_TBL0_ROWS, .hwtstamp_filters = (1 << HWTSTAMP_FILTER_NONE | 1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT | - 1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC | - 1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ | - 1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT | - 1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC | - 1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ), + 1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT), }; -- cgit v1.3-6-gb490 From 11b1544b5cfcc8c1ff01d1757397a6ce3c8aa85e Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:37 -0700 Subject: dp83640: only report generic filters in ts_info Signed-off-by: Jacob Keller Acked-by: Richard Cochran Signed-off-by: Jeff Kirsher --- drivers/net/phy/dp83640.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 00cb41e71312..185b03c08e16 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1449,17 +1449,9 @@ static int dp83640_ts_info(struct phy_device *dev, struct ethtool_ts_info *info) info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ); + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); return 0; } -- cgit v1.3-6-gb490 From f56e7bba22fad16c0d4fac996623ce1c13244f8f Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 22 Apr 2015 21:49:17 -0700 Subject: igb: Pull timestamp from fragment before adding it to skb This change makes it so that we pull the timestamp from the fragment before we add it to the skb. By doing this we can avoid a possible issue in which the fragment can possibly be less than IGB_RX_HDR_LEN due to the timestamp being pulled after the copybreak check. While making this change I realized we could also pull the rest of the igb_pull_tail function into igb_add_rx_frag since in the case of igb, unlike ixgbe, we are able to unmap the entire buffer before calling add_rx_frag so merging the two allows for sharing of code between the two merged functions. Reported-by: Cong Wang Signed-off-by: Alexander Duyck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 94 ++++++++----------------------- 1 file changed, 25 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 2f70a9b152bd..fc7729e78f3d 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6621,22 +6621,25 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring, struct sk_buff *skb) { struct page *page = rx_buffer->page; + unsigned char *va = page_address(page) + rx_buffer->page_offset; unsigned int size = le16_to_cpu(rx_desc->wb.upper.length); #if (PAGE_SIZE < 8192) unsigned int truesize = IGB_RX_BUFSZ; #else - unsigned int truesize = ALIGN(size, L1_CACHE_BYTES); + unsigned int truesize = SKB_DATA_ALIGN(size); #endif + unsigned int pull_len; - if ((size <= IGB_RX_HDR_LEN) && !skb_is_nonlinear(skb)) { - unsigned char *va = page_address(page) + rx_buffer->page_offset; + if (unlikely(skb_is_nonlinear(skb))) + goto add_tail_frag; - if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) { - igb_ptp_rx_pktstamp(rx_ring->q_vector, va, skb); - va += IGB_TS_HDR_LEN; - size -= IGB_TS_HDR_LEN; - } + if (unlikely(igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP))) { + igb_ptp_rx_pktstamp(rx_ring->q_vector, va, skb); + va += IGB_TS_HDR_LEN; + size -= IGB_TS_HDR_LEN; + } + if (likely(size <= IGB_RX_HDR_LEN)) { memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long))); /* page is not reserved, we can reuse buffer as-is */ @@ -6648,8 +6651,21 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring, return false; } + /* we need the header to contain the greater of either ETH_HLEN or + * 60 bytes if the skb->len is less than 60 for skb_pad. + */ + pull_len = eth_get_headlen(va, IGB_RX_HDR_LEN); + + /* align pull length to size of long to optimize memcpy performance */ + memcpy(__skb_put(skb, pull_len), va, ALIGN(pull_len, sizeof(long))); + + /* update all of the pointers */ + va += pull_len; + size -= pull_len; + +add_tail_frag: skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, - rx_buffer->page_offset, size, truesize); + (unsigned long)va & ~PAGE_MASK, size, truesize); return igb_can_reuse_rx_page(rx_buffer, page, truesize); } @@ -6790,62 +6806,6 @@ static bool igb_is_non_eop(struct igb_ring *rx_ring, return true; } -/** - * igb_pull_tail - igb specific version of skb_pull_tail - * @rx_ring: rx descriptor ring packet is being transacted on - * @rx_desc: pointer to the EOP Rx descriptor - * @skb: pointer to current skb being adjusted - * - * This function is an igb specific version of __pskb_pull_tail. The - * main difference between this version and the original function is that - * this function can make several assumptions about the state of things - * that allow for significant optimizations versus the standard function. - * As a result we can do things like drop a frag and maintain an accurate - * truesize for the skb. - */ -static void igb_pull_tail(struct igb_ring *rx_ring, - union e1000_adv_rx_desc *rx_desc, - struct sk_buff *skb) -{ - struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0]; - unsigned char *va; - unsigned int pull_len; - - /* it is valid to use page_address instead of kmap since we are - * working with pages allocated out of the lomem pool per - * alloc_page(GFP_ATOMIC) - */ - va = skb_frag_address(frag); - - if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) { - /* retrieve timestamp from buffer */ - igb_ptp_rx_pktstamp(rx_ring->q_vector, va, skb); - - /* update pointers to remove timestamp header */ - skb_frag_size_sub(frag, IGB_TS_HDR_LEN); - frag->page_offset += IGB_TS_HDR_LEN; - skb->data_len -= IGB_TS_HDR_LEN; - skb->len -= IGB_TS_HDR_LEN; - - /* move va to start of packet data */ - va += IGB_TS_HDR_LEN; - } - - /* we need the header to contain the greater of either ETH_HLEN or - * 60 bytes if the skb->len is less than 60 for skb_pad. - */ - pull_len = eth_get_headlen(va, IGB_RX_HDR_LEN); - - /* align pull length to size of long to optimize memcpy performance */ - skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long))); - - /* update all of the pointers */ - skb_frag_size_sub(frag, pull_len); - frag->page_offset += pull_len; - skb->data_len -= pull_len; - skb->tail += pull_len; -} - /** * igb_cleanup_headers - Correct corrupted or empty headers * @rx_ring: rx descriptor ring packet is being transacted on @@ -6873,10 +6833,6 @@ static bool igb_cleanup_headers(struct igb_ring *rx_ring, } } - /* place header in linear portion of buffer */ - if (skb_is_nonlinear(skb)) - igb_pull_tail(rx_ring, rx_desc, skb); - /* if eth_skb_pad returns an error the skb was freed */ if (eth_skb_pad(skb)) return true; -- cgit v1.3-6-gb490 From 5505bdb54d92267a5b6f092c337bd84d247bcf49 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 22 Apr 2015 21:49:32 -0700 Subject: ixgbevf: fold ixgbevf_pull_tail into ixgbevf_add_rx_frag This change folds the ixgbevf_pull_tail call into ixgbevf_add_rx_frag. The advantage to doing this is that the fragment doesn't have to be modified after it is added to the skb. Signed-off-by: Alexander Duyck Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 66 +++++++---------------- 1 file changed, 19 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index e71cdde9cb01..acfa05154436 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -648,46 +648,6 @@ static void ixgbevf_alloc_rx_buffers(struct ixgbevf_ring *rx_ring, } } -/** - * ixgbevf_pull_tail - ixgbevf specific version of skb_pull_tail - * @rx_ring: rx descriptor ring packet is being transacted on - * @skb: pointer to current skb being adjusted - * - * This function is an ixgbevf specific version of __pskb_pull_tail. The - * main difference between this version and the original function is that - * this function can make several assumptions about the state of things - * that allow for significant optimizations versus the standard function. - * As a result we can do things like drop a frag and maintain an accurate - * truesize for the skb. - **/ -static void ixgbevf_pull_tail(struct ixgbevf_ring *rx_ring, - struct sk_buff *skb) -{ - struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0]; - unsigned char *va; - unsigned int pull_len; - - /* it is valid to use page_address instead of kmap since we are - * working with pages allocated out of the lomem pool per - * alloc_page(GFP_ATOMIC) - */ - va = skb_frag_address(frag); - - /* we need the header to contain the greater of either ETH_HLEN or - * 60 bytes if the skb->len is less than 60 for skb_pad. - */ - pull_len = eth_get_headlen(va, IXGBEVF_RX_HDR_SIZE); - - /* align pull length to size of long to optimize memcpy performance */ - skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long))); - - /* update all of the pointers */ - skb_frag_size_sub(frag, pull_len); - frag->page_offset += pull_len; - skb->data_len -= pull_len; - skb->tail += pull_len; -} - /** * ixgbevf_cleanup_headers - Correct corrupted or empty headers * @rx_ring: rx descriptor ring packet is being transacted on @@ -721,10 +681,6 @@ static bool ixgbevf_cleanup_headers(struct ixgbevf_ring *rx_ring, } } - /* place header in linear portion of buffer */ - if (skb_is_nonlinear(skb)) - ixgbevf_pull_tail(rx_ring, skb); - /* if eth_skb_pad returns an error the skb was freed */ if (eth_skb_pad(skb)) return true; @@ -789,16 +745,19 @@ static bool ixgbevf_add_rx_frag(struct ixgbevf_ring *rx_ring, struct sk_buff *skb) { struct page *page = rx_buffer->page; + unsigned char *va = page_address(page) + rx_buffer->page_offset; unsigned int size = le16_to_cpu(rx_desc->wb.upper.length); #if (PAGE_SIZE < 8192) unsigned int truesize = IXGBEVF_RX_BUFSZ; #else unsigned int truesize = ALIGN(size, L1_CACHE_BYTES); #endif + unsigned int pull_len; - if ((size <= IXGBEVF_RX_HDR_SIZE) && !skb_is_nonlinear(skb)) { - unsigned char *va = page_address(page) + rx_buffer->page_offset; + if (unlikely(skb_is_nonlinear(skb))) + goto add_tail_frag; + if (likely(size <= IXGBEVF_RX_HDR_SIZE)) { memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long))); /* page is not reserved, we can reuse buffer as is */ @@ -810,8 +769,21 @@ static bool ixgbevf_add_rx_frag(struct ixgbevf_ring *rx_ring, return false; } + /* we need the header to contain the greater of either ETH_HLEN or + * 60 bytes if the skb->len is less than 60 for skb_pad. + */ + pull_len = eth_get_headlen(va, IXGBEVF_RX_HDR_SIZE); + + /* align pull length to size of long to optimize memcpy performance */ + memcpy(__skb_put(skb, pull_len), va, ALIGN(pull_len, sizeof(long))); + + /* update all of the pointers */ + va += pull_len; + size -= pull_len; + +add_tail_frag: skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, - rx_buffer->page_offset, size, truesize); + (unsigned long)va & ~PAGE_MASK, size, truesize); /* avoid re-using remote pages */ if (unlikely(ixgbevf_page_is_reserved(page))) -- cgit v1.3-6-gb490 From 7edda4b8711d58dabb55e6afec03e8177647f266 Mon Sep 17 00:00:00 2001 From: Fan Du Date: Wed, 29 Apr 2015 10:57:39 +0800 Subject: ixgbe: Specify Rx hash type WRT Rx desc RSS type RSS could be leveraged by taking account L4 src/dst ports as ingredients, thus ingress skb Rx hash type should honor such the real configuration. Signed-off-by: Fan Du Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 9aa6104e34ea..3e6a9319c718 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1360,14 +1360,31 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) } #endif /* CONFIG_IXGBE_DCA */ + +#define IXGBE_RSS_L4_TYPES_MASK \ + ((1ul << IXGBE_RXDADV_RSSTYPE_IPV4_TCP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV4_UDP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV6_TCP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV6_UDP)) + static inline void ixgbe_rx_hash(struct ixgbe_ring *ring, union ixgbe_adv_rx_desc *rx_desc, struct sk_buff *skb) { - if (ring->netdev->features & NETIF_F_RXHASH) - skb_set_hash(skb, - le32_to_cpu(rx_desc->wb.lower.hi_dword.rss), - PKT_HASH_TYPE_L3); + u16 rss_type; + + if (!(ring->netdev->features & NETIF_F_RXHASH)) + return; + + rss_type = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info) & + IXGBE_RXDADV_RSSTYPE_MASK; + + if (!rss_type) + return; + + skb_set_hash(skb, le32_to_cpu(rx_desc->wb.lower.hi_dword.rss), + (IXGBE_RSS_L4_TYPES_MASK & (1ul << rss_type)) ? + PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3); } #ifdef IXGBE_FCOE -- cgit v1.3-6-gb490 From 1e1429d6ce6e6fe38e45c960133e9c9b3c62cbc6 Mon Sep 17 00:00:00 2001 From: Fan Du Date: Wed, 29 Apr 2015 10:57:40 +0800 Subject: ixgbevf: Set Rx hash type for ingress packets Set hash type for ingress packets according to NIC advanced receive descriptors RSS type part. Signed-off-by: Fan Du Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/defines.h | 12 ++++++++++ drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 27 +++++++++++++++++++++++ 2 files changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbevf/defines.h b/drivers/net/ethernet/intel/ixgbevf/defines.h index 770e21a64388..58434584b16d 100644 --- a/drivers/net/ethernet/intel/ixgbevf/defines.h +++ b/drivers/net/ethernet/intel/ixgbevf/defines.h @@ -161,6 +161,18 @@ typedef u32 ixgbe_link_speed; #define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000 #define IXGBE_RXDADV_SPH 0x8000 +/* RSS Hash results */ +#define IXGBE_RXDADV_RSSTYPE_NONE 0x00000000 +#define IXGBE_RXDADV_RSSTYPE_IPV4_TCP 0x00000001 +#define IXGBE_RXDADV_RSSTYPE_IPV4 0x00000002 +#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP 0x00000003 +#define IXGBE_RXDADV_RSSTYPE_IPV6_EX 0x00000004 +#define IXGBE_RXDADV_RSSTYPE_IPV6 0x00000005 +#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006 +#define IXGBE_RXDADV_RSSTYPE_IPV4_UDP 0x00000007 +#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP 0x00000008 +#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009 + #define IXGBE_RXD_ERR_FRAME_ERR_MASK ( \ IXGBE_RXD_ERR_CE | \ IXGBE_RXD_ERR_LE | \ diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index acfa05154436..b2c86f1b8a9f 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -457,6 +457,32 @@ static void ixgbevf_rx_skb(struct ixgbevf_q_vector *q_vector, napi_gro_receive(&q_vector->napi, skb); } +#define IXGBE_RSS_L4_TYPES_MASK \ + ((1ul << IXGBE_RXDADV_RSSTYPE_IPV4_TCP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV4_UDP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV6_TCP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV6_UDP)) + +static inline void ixgbevf_rx_hash(struct ixgbevf_ring *ring, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb) +{ + u16 rss_type; + + if (!(ring->netdev->features & NETIF_F_RXHASH)) + return; + + rss_type = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info) & + IXGBE_RXDADV_RSSTYPE_MASK; + + if (!rss_type) + return; + + skb_set_hash(skb, le32_to_cpu(rx_desc->wb.lower.hi_dword.rss), + (IXGBE_RSS_L4_TYPES_MASK & (1ul << rss_type)) ? + PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3); +} + /** * ixgbevf_rx_checksum - indicate in skb if hw indicated a good cksum * @ring: structure containig ring specific data @@ -506,6 +532,7 @@ static void ixgbevf_process_skb_fields(struct ixgbevf_ring *rx_ring, union ixgbe_adv_rx_desc *rx_desc, struct sk_buff *skb) { + ixgbevf_rx_hash(rx_ring, rx_desc, skb); ixgbevf_rx_checksum(rx_ring, rx_desc, skb); if (ixgbevf_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) { -- cgit v1.3-6-gb490 From 3b7884f75f3d3f0a0191c00a083535a1dd01a5a4 Mon Sep 17 00:00:00 2001 From: Fan Du Date: Wed, 29 Apr 2015 10:57:41 +0800 Subject: ixgbe: Don't report flow director filter's status For two reasons I want to disable this: 1. Not any part actually check the report status(Alexander Duyck) 2. To report hash value of a packet to stack, RSS -> 32bits hash value Perfect match fdir filter -> 13bits hash value Hashed-based fdir filter -> 31bits hash value fdir filter might hash on masked tuples for IP address, so it's still not desirable for usage. So for now, just stick to RSS 32bits hash value. Signed-off-by: Fan Du Suggested-by: Alexander Duyck Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 6b87d9634614..b1e364d26aa7 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -1394,14 +1394,12 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 fdirctrl) /* * Continue setup of fdirctrl register bits: * Turn perfect match filtering on - * Report hash in RSS field of Rx wb descriptor * Initialize the drop queue * Move the flexible bytes to use the ethertype - shift 6 words * Set the maximum length per hash bucket to 0xA filters * Send interrupt when 64 (0x4 * 16) filters are left */ fdirctrl |= IXGBE_FDIRCTRL_PERFECT_MATCH | - IXGBE_FDIRCTRL_REPORT_STATUS | (IXGBE_FDIR_DROP_QUEUE << IXGBE_FDIRCTRL_DROP_Q_SHIFT) | (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT) | (0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT) | -- cgit v1.3-6-gb490 From 2ba6c0797c8b5a9f945345ef2b9193bd47e5f18e Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Wed, 29 Apr 2015 15:23:28 -0700 Subject: igb: Fix i354 88E1112 PHY on RCC boards using AutoMediaDetect e1000_check_for_link_media_swap() checks PHY page 0 for copper and PHY page 1 for "other" (fiber) link. The switch back from page 1 to page 0 happened too soon, before e1000_check_for_link_82575() is executed, and link on fiber (other) was never detected. Check for link while still on the proper PHY page. Signed-off-by: Todd Fujinaka Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_82575.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index b0182dd31346..d19256994e5c 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -139,10 +139,6 @@ static s32 igb_check_for_link_media_swap(struct e1000_hw *hw) if (ret_val) return ret_val; - /* reset page to 0 */ - ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0); - if (ret_val) - return ret_val; if (data & E1000_M88E1112_STATUS_LINK) port = E1000_MEDIA_PORT_OTHER; @@ -151,8 +147,20 @@ static s32 igb_check_for_link_media_swap(struct e1000_hw *hw) if (port && (hw->dev_spec._82575.media_port != port)) { hw->dev_spec._82575.media_port = port; hw->dev_spec._82575.media_changed = true; + } + + if (port == E1000_MEDIA_PORT_COPPER) { + /* reset page to 0 */ + ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0); + if (ret_val) + return ret_val; + igb_check_for_link_82575(hw); } else { - ret_val = igb_check_for_link_82575(hw); + igb_check_for_link_82575(hw); + /* reset page to 0 */ + ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0); + if (ret_val) + return ret_val; } return 0; -- cgit v1.3-6-gb490 From 07a4257e3d758af96cf98b1e9baadeb627475b03 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:41 +0000 Subject: iio: mxs-lradc: clarify supported devices At the beginning the driver supported only i.MX28 SoC, but now the whole MXS platform. So remove any confusing comments which apply only to i.MX28. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/staging/iio/adc/mxs-lradc.txt | 2 +- drivers/staging/iio/adc/mxs-lradc.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt index 307537787574..555fb117d4fa 100644 --- a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt +++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt @@ -1,4 +1,4 @@ -* Freescale i.MX28 LRADC device driver +* Freescale MXS LRADC device driver Required properties: - compatible: Should be "fsl,imx23-lradc" for i.MX23 SoC and "fsl,imx28-lradc" diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index d7c5223f1c3e..1ccb3676f2e5 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -1,5 +1,5 @@ /* - * Freescale i.MX28 LRADC driver + * Freescale MXS LRADC driver * * Copyright (c) 2012 DENX Software Engineering, GmbH. * Marek Vasut @@ -1392,7 +1392,7 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { MXS_ADC_CHAN(4, IIO_VOLTAGE), MXS_ADC_CHAN(5, IIO_VOLTAGE), MXS_ADC_CHAN(6, IIO_VOLTAGE), - MXS_ADC_CHAN(7, IIO_VOLTAGE), /* VBATT */ + MXS_ADC_CHAN(7, IIO_VOLTAGE), /* Combined Temperature sensors */ { .type = IIO_TEMP, @@ -1411,12 +1411,12 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { .scan_index = -1, .channel = 9, }, - MXS_ADC_CHAN(10, IIO_VOLTAGE), /* VDDIO */ - MXS_ADC_CHAN(11, IIO_VOLTAGE), /* VTH */ - MXS_ADC_CHAN(12, IIO_VOLTAGE), /* VDDA */ - MXS_ADC_CHAN(13, IIO_VOLTAGE), /* VDDD */ - MXS_ADC_CHAN(14, IIO_VOLTAGE), /* VBG */ - MXS_ADC_CHAN(15, IIO_VOLTAGE), /* VDD5V */ + MXS_ADC_CHAN(10, IIO_VOLTAGE), + MXS_ADC_CHAN(11, IIO_VOLTAGE), + MXS_ADC_CHAN(12, IIO_VOLTAGE), + MXS_ADC_CHAN(13, IIO_VOLTAGE), + MXS_ADC_CHAN(14, IIO_VOLTAGE), + MXS_ADC_CHAN(15, IIO_VOLTAGE), }; static int mxs_lradc_hw_init(struct mxs_lradc *lradc) @@ -1707,6 +1707,6 @@ static struct platform_driver mxs_lradc_driver = { module_platform_driver(mxs_lradc_driver); MODULE_AUTHOR("Marek Vasut "); -MODULE_DESCRIPTION("Freescale i.MX28 LRADC driver"); +MODULE_DESCRIPTION("Freescale MXS LRADC driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRIVER_NAME); -- cgit v1.3-6-gb490 From 66926d11f326355abbd4e290047a67f17731b404 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:42 +0000 Subject: iio: mxs-lradc: fix some spelling errors This patch fix some spelling errors in the comments. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 1ccb3676f2e5..386a44da7248 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -65,14 +65,14 @@ * Once the pen touches the touchscreen, the touchscreen switches from * IRQ-driven mode to polling mode to prevent interrupt storm. The polling * is realized by worker thread, which is called every 20 or so milliseconds. - * This gives the touchscreen enough fluence and does not strain the system + * This gives the touchscreen enough fluency and does not strain the system * too much. */ #define LRADC_TS_SAMPLE_DELAY_MS 5 /* * The LRADC reads the following amount of samples from each touchscreen - * channel and the driver then computes avarage of these. + * channel and the driver then computes average of these. */ #define LRADC_TS_SAMPLE_AMOUNT 4 @@ -238,7 +238,7 @@ struct mxs_lradc { * CH5 -- Touch screen YNLR * CH6 -- Touch screen WIPER (5-wire only) * - * The bitfields below represents which parts of the LRADC block are + * The bit fields below represents which parts of the LRADC block are * switched into special mode of operation. These channels can not * be sampled as regular LRADC channels. The driver will refuse any * attempt to sample these channels. @@ -252,7 +252,7 @@ struct mxs_lradc { struct input_dev *ts_input; enum mxs_lradc_id soc; - enum lradc_ts_plate cur_plate; /* statemachine */ + enum lradc_ts_plate cur_plate; /* state machine */ bool ts_valid; unsigned ts_x_pos; unsigned ts_y_pos; @@ -812,7 +812,7 @@ static int mxs_lradc_read_single(struct iio_dev *iio_dev, int chan, int *val) int ret; /* - * See if there is no buffered operation in progess. If there is, simply + * See if there is no buffered operation in progress. If there is, simply * bail out. This can be improved to support both buffered and raw IO at * the same time, yet the code becomes horribly complicated. Therefore I * applied KISS principle here. -- cgit v1.3-6-gb490 From 5723dde958582483501fc2307cf2258060151339 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:43 +0000 Subject: iio: mxs-lradc: add missing include This patch adds the missing include for mutex handling. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 386a44da7248..763075ba3423 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include -- cgit v1.3-6-gb490 From 3eaf20288c9e0e5a2620c4908ac215655ebf0a00 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:44 +0000 Subject: iio: mxs-lradc: remove unnecessary header includes This patch removes the unnecessary header includes. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 763075ba3423..21b0ccfe5603 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -23,18 +23,13 @@ #include #include #include -#include #include #include #include #include -#include -#include -#include #include #include #include -#include #include #include -- cgit v1.3-6-gb490 From ae5896d48180520629655a9356737fe6dbc5e9e5 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:45 +0000 Subject: iio: mxs-lradc: reorder header includes This patch reorder the header includes alphabetically. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 21b0ccfe5603..3a549eff7e71 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -15,30 +15,30 @@ * 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 #include -#include -#include -#include -#include +#include -#include -#include #include +#include #include #include #include +#include #define DRIVER_NAME "mxs-lradc" -- cgit v1.3-6-gb490 From 829aed1a6e2cbceb2d2fe0f7557dea71fb38cec6 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jul 2015 12:30:46 +0000 Subject: iio: mxs-lradc: add datasheet name for every usable channel In order to provide a channel name to in kernel consumers add the datasheet names for every usable AD channel. Since the channel names differ between i.MX23 and i.MX28, we need to separate the channel specs. Signed-off-by: Stefan Wahren Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 80 ++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 3a549eff7e71..3f7715c9968b 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -1365,7 +1365,7 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = { * Driver initialization */ -#define MXS_ADC_CHAN(idx, chan_type) { \ +#define MXS_ADC_CHAN(idx, chan_type, name) { \ .type = (chan_type), \ .indexed = 1, \ .scan_index = (idx), \ @@ -1378,17 +1378,18 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = { .realbits = LRADC_RESOLUTION, \ .storagebits = 32, \ }, \ + .datasheet_name = (name), \ } -static const struct iio_chan_spec mxs_lradc_chan_spec[] = { - MXS_ADC_CHAN(0, IIO_VOLTAGE), - MXS_ADC_CHAN(1, IIO_VOLTAGE), - MXS_ADC_CHAN(2, IIO_VOLTAGE), - MXS_ADC_CHAN(3, IIO_VOLTAGE), - MXS_ADC_CHAN(4, IIO_VOLTAGE), - MXS_ADC_CHAN(5, IIO_VOLTAGE), - MXS_ADC_CHAN(6, IIO_VOLTAGE), - MXS_ADC_CHAN(7, IIO_VOLTAGE), +static const struct iio_chan_spec mx23_lradc_chan_spec[] = { + MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"), + MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"), + MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"), + MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"), + MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"), + MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"), + MXS_ADC_CHAN(6, IIO_VOLTAGE, "VDDIO"), + MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"), /* Combined Temperature sensors */ { .type = IIO_TEMP, @@ -1399,6 +1400,7 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { BIT(IIO_CHAN_INFO_SCALE), .channel = 8, .scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,}, + .datasheet_name = "TEMP_DIE", }, /* Hidden channel to keep indexes */ { @@ -1407,12 +1409,48 @@ static const struct iio_chan_spec mxs_lradc_chan_spec[] = { .scan_index = -1, .channel = 9, }, - MXS_ADC_CHAN(10, IIO_VOLTAGE), - MXS_ADC_CHAN(11, IIO_VOLTAGE), - MXS_ADC_CHAN(12, IIO_VOLTAGE), - MXS_ADC_CHAN(13, IIO_VOLTAGE), - MXS_ADC_CHAN(14, IIO_VOLTAGE), - MXS_ADC_CHAN(15, IIO_VOLTAGE), + MXS_ADC_CHAN(10, IIO_VOLTAGE, NULL), + MXS_ADC_CHAN(11, IIO_VOLTAGE, NULL), + MXS_ADC_CHAN(12, IIO_VOLTAGE, "USB_DP"), + MXS_ADC_CHAN(13, IIO_VOLTAGE, "USB_DN"), + MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"), + MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"), +}; + +static const struct iio_chan_spec mx28_lradc_chan_spec[] = { + MXS_ADC_CHAN(0, IIO_VOLTAGE, "LRADC0"), + MXS_ADC_CHAN(1, IIO_VOLTAGE, "LRADC1"), + MXS_ADC_CHAN(2, IIO_VOLTAGE, "LRADC2"), + MXS_ADC_CHAN(3, IIO_VOLTAGE, "LRADC3"), + MXS_ADC_CHAN(4, IIO_VOLTAGE, "LRADC4"), + MXS_ADC_CHAN(5, IIO_VOLTAGE, "LRADC5"), + MXS_ADC_CHAN(6, IIO_VOLTAGE, "LRADC6"), + MXS_ADC_CHAN(7, IIO_VOLTAGE, "VBATT"), + /* Combined Temperature sensors */ + { + .type = IIO_TEMP, + .indexed = 1, + .scan_index = 8, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE), + .channel = 8, + .scan_type = {.sign = 'u', .realbits = 18, .storagebits = 32,}, + .datasheet_name = "TEMP_DIE", + }, + /* Hidden channel to keep indexes */ + { + .type = IIO_TEMP, + .indexed = 1, + .scan_index = -1, + .channel = 9, + }, + MXS_ADC_CHAN(10, IIO_VOLTAGE, "VDDIO"), + MXS_ADC_CHAN(11, IIO_VOLTAGE, "VTH"), + MXS_ADC_CHAN(12, IIO_VOLTAGE, "VDDA"), + MXS_ADC_CHAN(13, IIO_VOLTAGE, "VDDD"), + MXS_ADC_CHAN(14, IIO_VOLTAGE, "VBG"), + MXS_ADC_CHAN(15, IIO_VOLTAGE, "VDD5V"), }; static int mxs_lradc_hw_init(struct mxs_lradc *lradc) @@ -1608,10 +1646,16 @@ static int mxs_lradc_probe(struct platform_device *pdev) iio->dev.parent = &pdev->dev; iio->info = &mxs_lradc_iio_info; iio->modes = INDIO_DIRECT_MODE; - iio->channels = mxs_lradc_chan_spec; - iio->num_channels = ARRAY_SIZE(mxs_lradc_chan_spec); iio->masklength = LRADC_MAX_TOTAL_CHANS; + if (lradc->soc == IMX23_LRADC) { + iio->channels = mx23_lradc_chan_spec; + iio->num_channels = ARRAY_SIZE(mx23_lradc_chan_spec); + } else { + iio->channels = mx28_lradc_chan_spec; + iio->num_channels = ARRAY_SIZE(mx28_lradc_chan_spec); + } + ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time, &mxs_lradc_trigger_handler, &mxs_lradc_buffer_ops); -- cgit v1.3-6-gb490 From 23633314e60796f860d5a0484b722557061cde7c Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sat, 18 Jul 2015 00:56:57 +0200 Subject: iio:light:acpi-als: add missing prefixes Some macros and a function were missing the acpi_als_ prefix, so add it. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/light/acpi-als.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index 1dafa0756bfa..60537ec0c923 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -65,20 +65,20 @@ static const struct iio_chan_spec acpi_als_channels[] = { * to acpi_als_channels[], the evt_buffer below will grow * automatically. */ -#define EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels) -#define EVT_BUFFER_SIZE \ - (sizeof(s64) + (EVT_NR_SOURCES * sizeof(s32))) +#define ACPI_ALS_EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels) +#define ACPI_ALS_EVT_BUFFER_SIZE \ + (sizeof(s64) + (ACPI_ALS_EVT_NR_SOURCES * sizeof(s32))) struct acpi_als { struct acpi_device *device; struct mutex lock; - s32 evt_buffer[EVT_BUFFER_SIZE]; + s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE]; }; /* * All types of properties the ACPI0008 block can report. The ALI, ALC, ALT - * and ALP can all be handled by als_read_value() below, while the ALR is + * and ALP can all be handled by acpi_als_read_value() below, while the ALR is * special. * * The _ALR property returns tables that can be used to fine-tune the values @@ -93,7 +93,7 @@ struct acpi_als { #define ACPI_ALS_POLLING "_ALP" #define ACPI_ALS_TABLES "_ALR" -static int als_read_value(struct acpi_als *als, char *prop, s32 *val) +static int acpi_als_read_value(struct acpi_als *als, char *prop, s32 *val) { unsigned long long temp_val; acpi_status status; @@ -122,11 +122,11 @@ static void acpi_als_notify(struct acpi_device *device, u32 event) mutex_lock(&als->lock); - memset(buffer, 0, EVT_BUFFER_SIZE); + memset(buffer, 0, ACPI_ALS_EVT_BUFFER_SIZE); switch (event) { case ACPI_ALS_NOTIFY_ILLUMINANCE: - ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &val); + ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val); if (ret < 0) goto out; *buffer++ = val; @@ -159,7 +159,7 @@ static int acpi_als_read_raw(struct iio_dev *indio_dev, if (chan->type != IIO_LIGHT) return -EINVAL; - ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val); + ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val); if (ret < 0) return ret; -- cgit v1.3-6-gb490 From 7dbf1ea8aade8c3b2759acc96e5e709016e6ae28 Mon Sep 17 00:00:00 2001 From: Jandy Gou Date: Fri, 17 Jul 2015 16:34:35 +0800 Subject: iio: magnetometer: mmc35240: Add DT binding Signed-off-by: Jandy Gou Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/mmc35240.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index 7a2ea71c659a..9bc542daa732 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -550,6 +550,12 @@ static const struct dev_pm_ops mmc35240_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mmc35240_suspend, mmc35240_resume) }; +static const struct of_device_id mmc35240_of_match[] = { + { .compatible = "memsic,mmc35240", }, + { } +}; +MODULE_DEVICE_TABLE(of, mmc35240_of_match); + static const struct acpi_device_id mmc35240_acpi_match[] = { {"MMC35240", 0}, { }, @@ -565,6 +571,7 @@ MODULE_DEVICE_TABLE(i2c, mmc35240_id); static struct i2c_driver mmc35240_driver = { .driver = { .name = MMC35240_DRV_NAME, + .of_match_table = mmc35240_of_match, .pm = &mmc35240_pm_ops, .acpi_match_table = ACPI_PTR(mmc35240_acpi_match), }, -- cgit v1.3-6-gb490 From 47764c7918f5dd648ae8f6f61db1aaab1b9c09dd Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Fri, 17 Jul 2015 10:52:27 +0200 Subject: iio:magnetometer:bmc150_magn: replace magic value Construct the scanmask using its descriptive axis names (as used in iio_chan_spec) instead of a 'magic' value. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index cd002710dd02..074a99da7367 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -651,7 +651,9 @@ static const struct iio_info bmc150_magn_info = { .driver_module = THIS_MODULE, }; -static const unsigned long bmc150_magn_scan_masks[] = {0x07, 0}; +static const unsigned long bmc150_magn_scan_masks[] = { + BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), + 0}; static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) { -- cgit v1.3-6-gb490 From 22801f76fa59870aed2c0b8a4eb6c8d6993347ae Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 19 Jan 2015 16:20:21 +0200 Subject: drm/radeon: Modify kgd_engine_type enum to match CZ This patch splits the KGD_ENGINE_SDMA to KGD_ENGINE_SDMA1 and KGD_ENGINE_SDMA2 to match CZ definitions. Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 3 ++- drivers/gpu/drm/radeon/radeon_kfd.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 9080daa116b6..888250b33ea8 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -52,7 +52,8 @@ enum kgd_engine_type { KGD_ENGINE_MEC1, KGD_ENGINE_MEC2, KGD_ENGINE_RLC, - KGD_ENGINE_SDMA, + KGD_ENGINE_SDMA1, + KGD_ENGINE_SDMA2, KGD_ENGINE_MAX }; diff --git a/drivers/gpu/drm/radeon/radeon_kfd.c b/drivers/gpu/drm/radeon/radeon_kfd.c index e476c331f3fa..9a4d69e59401 100644 --- a/drivers/gpu/drm/radeon/radeon_kfd.c +++ b/drivers/gpu/drm/radeon/radeon_kfd.c @@ -845,7 +845,8 @@ static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) hdr = (const union radeon_firmware_header *) rdev->rlc_fw->data; break; - case KGD_ENGINE_SDMA: + case KGD_ENGINE_SDMA1: + case KGD_ENGINE_SDMA2: hdr = (const union radeon_firmware_header *) rdev->sdma_fw->data; break; -- cgit v1.3-6-gb490 From 130e0371b7d454bb4a861253c822b9f911ad5d19 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 12 Jun 2015 21:35:14 +0300 Subject: drm/amdgpu: Add H/W agnostic amdgpu <--> amdkfd interface This patch adds an interface file between amdgpu and amdkfd. This interface file is H/W agnostic, thus containing functions that operate the same for any AMD APU/GPU H/W generation. The functions in this interface mirror (some) of the functions in radeon_kfd.c (the radeon<-->amdkfd interface file). The main functions are: - amdgpu_amdkfd_init - initialize the amdkfd module - amdgpu_amdkfd_load_interface - load the H/W interface according to the currently probed device - amdgpu_amdkfd_device_probe - probe the device in amdkfd - amdgpu_amdkfd_device_init - initialize the device in amdkfd - amdgpu_amdkfd_interrupt - call the ISR of amdkfd - amdgpu_amdkfd_suspend - suspend callback from amdgpu - amdgpu_amdkfd_resume - resume callback from amdgpu This patch also modifies the relevant amdgpu files, to use this new interface. Signed-off-by: Oded Gabbay --- MAINTAINERS | 2 + drivers/gpu/drm/amd/amdgpu/Makefile | 4 + drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 262 +++++++++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 64 +++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 5 + drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c | 7 + drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 7 + drivers/gpu/drm/amd/amdgpu/cik.c | 11 +- 9 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index a2264167791a..8012189d358f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -636,6 +636,8 @@ M: Oded Gabbay L: dri-devel@lists.freedesktop.org T: git git://people.freedesktop.org/~gabbayo/linux.git S: Supported +F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h F: drivers/gpu/drm/amd/amdkfd/ F: drivers/gpu/drm/amd/include/cik_structs.h F: drivers/gpu/drm/amd/include/kgd_kfd_interface.h diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 616dfd4a1398..891f02c21de6 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -71,6 +71,10 @@ amdgpu-y += \ amdgpu_vce.o \ vce_v3_0.o +# add amdkfd interfaces +amdgpu-y += \ + amdgpu_amdkfd.o + amdgpu-$(CONFIG_COMPAT) += amdgpu_ioc32.o amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 01657830b470..f3791e0d27d4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -2011,6 +2011,9 @@ struct amdgpu_device { /* tracking pinned memory */ u64 vram_pin_size; u64 gart_pin_size; + + /* amdkfd interface */ + struct kfd_dev *kfd; }; bool amdgpu_device_is_px(struct drm_device *dev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c new file mode 100644 index 000000000000..2071a9b757f7 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -0,0 +1,262 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "amdgpu_amdkfd.h" +#include "amdgpu_family.h" +#include +#include "amdgpu.h" +#include + +const struct kfd2kgd_calls *kfd2kgd; +const struct kgd2kfd_calls *kgd2kfd; +bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**); + +bool amdgpu_amdkfd_init(void) +{ +#if defined(CONFIG_HSA_AMD_MODULE) + bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**); + + kgd2kfd_init_p = symbol_request(kgd2kfd_init); + + if (kgd2kfd_init_p == NULL) + return false; +#endif + return true; +} + +bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev) +{ +#if defined(CONFIG_HSA_AMD_MODULE) + bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**); +#endif + + switch (rdev->asic_type) { + case CHIP_KAVERI: + default: + return false; + } + +#if defined(CONFIG_HSA_AMD_MODULE) + kgd2kfd_init_p = symbol_request(kgd2kfd_init); + + if (kgd2kfd_init_p == NULL) { + kfd2kgd = NULL; + return false; + } + + if (!kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kgd2kfd)) { + symbol_put(kgd2kfd_init); + kfd2kgd = NULL; + kgd2kfd = NULL; + + return false; + } + + return true; +#elif defined(CONFIG_HSA_AMD) + if (!kgd2kfd_init(KFD_INTERFACE_VERSION, &kgd2kfd)) { + kfd2kgd = NULL; + kgd2kfd = NULL; + return false; + } + + return true; +#else + kfd2kgd = NULL; + return false; +#endif +} + +void amdgpu_amdkfd_fini(void) +{ + if (kgd2kfd) { + kgd2kfd->exit(); + symbol_put(kgd2kfd_init); + } +} + +void amdgpu_amdkfd_device_probe(struct amdgpu_device *rdev) +{ + if (kgd2kfd) + rdev->kfd = kgd2kfd->probe((struct kgd_dev *)rdev, + rdev->pdev, kfd2kgd); +} + +void amdgpu_amdkfd_device_init(struct amdgpu_device *rdev) +{ + if (rdev->kfd) { + struct kgd2kfd_shared_resources gpu_resources = { + .compute_vmid_bitmap = 0xFF00, + + .first_compute_pipe = 1, + .compute_pipe_count = 4 - 1, + }; + + amdgpu_doorbell_get_kfd_info(rdev, + &gpu_resources.doorbell_physical_address, + &gpu_resources.doorbell_aperture_size, + &gpu_resources.doorbell_start_offset); + + kgd2kfd->device_init(rdev->kfd, &gpu_resources); + } +} + +void amdgpu_amdkfd_device_fini(struct amdgpu_device *rdev) +{ + if (rdev->kfd) { + kgd2kfd->device_exit(rdev->kfd); + rdev->kfd = NULL; + } +} + +void amdgpu_amdkfd_interrupt(struct amdgpu_device *rdev, + const void *ih_ring_entry) +{ + if (rdev->kfd) + kgd2kfd->interrupt(rdev->kfd, ih_ring_entry); +} + +void amdgpu_amdkfd_suspend(struct amdgpu_device *rdev) +{ + if (rdev->kfd) + kgd2kfd->suspend(rdev->kfd); +} + +int amdgpu_amdkfd_resume(struct amdgpu_device *rdev) +{ + int r = 0; + + if (rdev->kfd) + r = kgd2kfd->resume(rdev->kfd); + + return r; +} + +u32 pool_to_domain(enum kgd_memory_pool p) +{ + switch (p) { + case KGD_POOL_FRAMEBUFFER: return AMDGPU_GEM_DOMAIN_VRAM; + default: return AMDGPU_GEM_DOMAIN_GTT; + } +} + +int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, + void **mem_obj, uint64_t *gpu_addr, + void **cpu_ptr) +{ + struct amdgpu_device *rdev = (struct amdgpu_device *)kgd; + struct kgd_mem **mem = (struct kgd_mem **) mem_obj; + int r; + + BUG_ON(kgd == NULL); + BUG_ON(gpu_addr == NULL); + BUG_ON(cpu_ptr == NULL); + + *mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL); + if ((*mem) == NULL) + return -ENOMEM; + + r = amdgpu_bo_create(rdev, size, PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_GTT, + AMDGPU_GEM_CREATE_CPU_GTT_USWC, NULL, &(*mem)->bo); + if (r) { + dev_err(rdev->dev, + "failed to allocate BO for amdkfd (%d)\n", r); + return r; + } + + /* map the buffer */ + r = amdgpu_bo_reserve((*mem)->bo, true); + if (r) { + dev_err(rdev->dev, "(%d) failed to reserve bo for amdkfd\n", r); + goto allocate_mem_reserve_bo_failed; + } + + r = amdgpu_bo_pin((*mem)->bo, AMDGPU_GEM_DOMAIN_GTT, + &(*mem)->gpu_addr); + if (r) { + dev_err(rdev->dev, "(%d) failed to pin bo for amdkfd\n", r); + goto allocate_mem_pin_bo_failed; + } + *gpu_addr = (*mem)->gpu_addr; + + r = amdgpu_bo_kmap((*mem)->bo, &(*mem)->cpu_ptr); + if (r) { + dev_err(rdev->dev, + "(%d) failed to map bo to kernel for amdkfd\n", r); + goto allocate_mem_kmap_bo_failed; + } + *cpu_ptr = (*mem)->cpu_ptr; + + amdgpu_bo_unreserve((*mem)->bo); + + return 0; + +allocate_mem_kmap_bo_failed: + amdgpu_bo_unpin((*mem)->bo); +allocate_mem_pin_bo_failed: + amdgpu_bo_unreserve((*mem)->bo); +allocate_mem_reserve_bo_failed: + amdgpu_bo_unref(&(*mem)->bo); + + return r; +} + +void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj) +{ + struct kgd_mem *mem = (struct kgd_mem *) mem_obj; + + BUG_ON(mem == NULL); + + amdgpu_bo_reserve(mem->bo, true); + amdgpu_bo_kunmap(mem->bo); + amdgpu_bo_unpin(mem->bo); + amdgpu_bo_unreserve(mem->bo); + amdgpu_bo_unref(&(mem->bo)); + kfree(mem); +} + +uint64_t get_vmem_size(struct kgd_dev *kgd) +{ + struct amdgpu_device *rdev = + (struct amdgpu_device *)kgd; + + BUG_ON(kgd == NULL); + + return rdev->mc.real_vram_size; +} + +uint64_t get_gpu_clock_counter(struct kgd_dev *kgd) +{ + struct amdgpu_device *rdev = (struct amdgpu_device *)kgd; + + if (rdev->asic_funcs->get_gpu_clock_counter) + return rdev->asic_funcs->get_gpu_clock_counter(rdev); + return 0; +} + +uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd) +{ + struct amdgpu_device *rdev = (struct amdgpu_device *)kgd; + + /* The sclk is in quantas of 10kHz */ + return rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk / 100; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h new file mode 100644 index 000000000000..c81242e84aba --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -0,0 +1,64 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +/* amdgpu_amdkfd.h defines the private interface between amdgpu and amdkfd. */ + +#ifndef AMDGPU_AMDKFD_H_INCLUDED +#define AMDGPU_AMDKFD_H_INCLUDED + +#include +#include + +struct amdgpu_device; + +struct kgd_mem { + struct amdgpu_bo *bo; + uint64_t gpu_addr; + void *cpu_ptr; +}; + +bool amdgpu_amdkfd_init(void); +void amdgpu_amdkfd_fini(void); + +bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev); + +void amdgpu_amdkfd_suspend(struct amdgpu_device *rdev); +int amdgpu_amdkfd_resume(struct amdgpu_device *rdev); +void amdgpu_amdkfd_interrupt(struct amdgpu_device *rdev, + const void *ih_ring_entry); +void amdgpu_amdkfd_device_probe(struct amdgpu_device *rdev); +void amdgpu_amdkfd_device_init(struct amdgpu_device *rdev); +void amdgpu_amdkfd_device_fini(struct amdgpu_device *rdev); + +struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void); + +/* Shared API */ +int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, + void **mem_obj, uint64_t *gpu_addr, + void **cpu_ptr); +void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj); +uint64_t get_vmem_size(struct kgd_dev *kgd); +uint64_t get_gpu_clock_counter(struct kgd_dev *kgd); + +uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd); + +#endif /* AMDGPU_AMDKFD_H_INCLUDED */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 56da962231fc..115906f5fda0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -44,6 +44,8 @@ #include "amdgpu.h" #include "amdgpu_irq.h" +#include "amdgpu_amdkfd.h" + /* * KMS wrapper. * - 3.0.0 - initial driver @@ -527,12 +529,15 @@ static int __init amdgpu_init(void) driver->num_ioctls = amdgpu_max_kms_ioctl; amdgpu_register_atpx_handler(); + amdgpu_amdkfd_init(); + /* let modprobe override vga console setting */ return drm_pci_init(driver, pdriver); } static void __exit amdgpu_exit(void) { + amdgpu_amdkfd_fini(); drm_pci_exit(driver, pdriver); amdgpu_unregister_atpx_handler(); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c index db5422e65ec5..fb44dd2231b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c @@ -24,6 +24,7 @@ #include #include "amdgpu.h" #include "amdgpu_ih.h" +#include "amdgpu_amdkfd.h" /** * amdgpu_ih_ring_alloc - allocate memory for the IH ring @@ -199,6 +200,12 @@ restart_ih: rmb(); while (adev->irq.ih.rptr != wptr) { + u32 ring_index = adev->irq.ih.rptr >> 2; + + /* Before dispatching irq to IP blocks, send it to amdkfd */ + amdgpu_amdkfd_interrupt(adev, + (const void *) &adev->irq.ih.ring[ring_index]); + amdgpu_ih_decode_iv(adev, &entry); adev->irq.ih.rptr &= adev->irq.ih.ptr_mask; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 5533434c7a8f..8c40a9671b9f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -34,6 +34,7 @@ #include #include #include +#include "amdgpu_amdkfd.h" #if defined(CONFIG_VGA_SWITCHEROO) bool amdgpu_has_atpx(void); @@ -61,6 +62,8 @@ int amdgpu_driver_unload_kms(struct drm_device *dev) pm_runtime_get_sync(dev->dev); + amdgpu_amdkfd_device_fini(adev); + amdgpu_acpi_fini(adev); amdgpu_device_fini(adev); @@ -118,6 +121,10 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) "Error during ACPI methods call\n"); } + amdgpu_amdkfd_load_interface(adev); + amdgpu_amdkfd_device_probe(adev); + amdgpu_amdkfd_device_init(adev); + if (amdgpu_device_is_px(dev)) { pm_runtime_use_autosuspend(dev->dev); pm_runtime_set_autosuspend_delay(dev->dev, 5000); diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 341c56681841..b3b66a0d5ff7 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -64,6 +64,8 @@ #include "oss/oss_2_0_d.h" #include "oss/oss_2_0_sh_mask.h" +#include "amdgpu_amdkfd.h" + /* * Indirect registers accessor */ @@ -2448,14 +2450,21 @@ static int cik_common_suspend(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + amdgpu_amdkfd_suspend(adev); + return cik_common_hw_fini(adev); } static int cik_common_resume(void *handle) { + int r; struct amdgpu_device *adev = (struct amdgpu_device *)handle; - return cik_common_hw_init(adev); + r = cik_common_hw_init(adev); + if (r) + return r; + + return amdgpu_amdkfd_resume(adev); } static bool cik_common_is_idle(void *handle) -- cgit v1.3-6-gb490 From 32c22e994f44e7e5cc54b52375012311d1693b0d Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 12 Jun 2015 21:38:22 +0300 Subject: drm/amdgpu: add amdgpu <--> amdkfd gfx7 interface This patch adds the gfx7 interface file between amdgpu and amdkfd. This interface file mirrors (some) of the functions in radeon_kfd.c (the interface file between radeon and amdkfd). The gfx7 interface is used when it is run on a Kaveri-based system. This interface file was used for bring-up of amdkfd on amdgpu and for debugging purposes. For users who would like to run HSA on Kaveri, please use the radeon graphic driver. Note: CONFIG_DRM_AMDGPU_CIK must be selected for amdgpu to handle Kaveri. v2: removed MTYPE_NONCACHED enum definition as it is defined in another patch Signed-off-by: Oded Gabbay --- MAINTAINERS | 1 + drivers/gpu/drm/amd/amdgpu/Makefile | 3 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 670 ++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/cikd.h | 6 + 5 files changed, 681 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 8012189d358f..5cc07349b523 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -638,6 +638,7 @@ T: git git://people.freedesktop.org/~gabbayo/linux.git S: Supported F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c F: drivers/gpu/drm/amd/amdkfd/ F: drivers/gpu/drm/amd/include/cik_structs.h F: drivers/gpu/drm/amd/include/kgd_kfd_interface.h diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 891f02c21de6..af5397c40ea3 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -73,7 +73,8 @@ amdgpu-y += \ # add amdkfd interfaces amdgpu-y += \ - amdgpu_amdkfd.o + amdgpu_amdkfd.o \ + amdgpu_amdkfd_gfx_v7.o amdgpu-$(CONFIG_COMPAT) += amdgpu_ioc32.o amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 2071a9b757f7..7aa5ab09ed09 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -51,6 +51,8 @@ bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev) switch (rdev->asic_type) { case CHIP_KAVERI: + kfd2kgd = amdgpu_amdkfd_gfx_7_get_functions(); + break; default: return false; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c new file mode 100644 index 000000000000..2daad335b809 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -0,0 +1,670 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "amdgpu.h" +#include "amdgpu_amdkfd.h" +#include "cikd.h" +#include "cik_sdma.h" +#include "amdgpu_ucode.h" +#include "gca/gfx_7_2_d.h" +#include "gca/gfx_7_2_enum.h" +#include "gca/gfx_7_2_sh_mask.h" +#include "oss/oss_2_0_d.h" +#include "oss/oss_2_0_sh_mask.h" +#include "gmc/gmc_7_1_d.h" +#include "gmc/gmc_7_1_sh_mask.h" +#include "cik_structs.h" + +#define CIK_PIPE_PER_MEC (4) + +enum { + MAX_TRAPID = 8, /* 3 bits in the bitfield. */ + MAX_WATCH_ADDRESSES = 4 +}; + +enum { + ADDRESS_WATCH_REG_ADDR_HI = 0, + ADDRESS_WATCH_REG_ADDR_LO, + ADDRESS_WATCH_REG_CNTL, + ADDRESS_WATCH_REG_MAX +}; + +/* not defined in the CI/KV reg file */ +enum { + ADDRESS_WATCH_REG_CNTL_ATC_BIT = 0x10000000UL, + ADDRESS_WATCH_REG_CNTL_DEFAULT_MASK = 0x00FFFFFF, + ADDRESS_WATCH_REG_ADDLOW_MASK_EXTENSION = 0x03000000, + /* extend the mask to 26 bits to match the low address field */ + ADDRESS_WATCH_REG_ADDLOW_SHIFT = 6, + ADDRESS_WATCH_REG_ADDHIGH_MASK = 0xFFFF +}; + +static const uint32_t watchRegs[MAX_WATCH_ADDRESSES * ADDRESS_WATCH_REG_MAX] = { + mmTCP_WATCH0_ADDR_H, mmTCP_WATCH0_ADDR_L, mmTCP_WATCH0_CNTL, + mmTCP_WATCH1_ADDR_H, mmTCP_WATCH1_ADDR_L, mmTCP_WATCH1_CNTL, + mmTCP_WATCH2_ADDR_H, mmTCP_WATCH2_ADDR_L, mmTCP_WATCH2_CNTL, + mmTCP_WATCH3_ADDR_H, mmTCP_WATCH3_ADDR_L, mmTCP_WATCH3_CNTL +}; + +union TCP_WATCH_CNTL_BITS { + struct { + uint32_t mask:24; + uint32_t vmid:4; + uint32_t atc:1; + uint32_t mode:2; + uint32_t valid:1; + } bitfields, bits; + uint32_t u32All; + signed int i32All; + float f32All; +}; + +/* + * Register access functions + */ + +static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid, + uint32_t sh_mem_config, uint32_t sh_mem_ape1_base, + uint32_t sh_mem_ape1_limit, uint32_t sh_mem_bases); + +static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, + unsigned int vmid); + +static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t hpd_size, uint64_t hpd_gpu_addr); +static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id); +static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, + uint32_t queue_id, uint32_t __user *wptr); +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd); +static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address, + uint32_t pipe_id, uint32_t queue_id); + +static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id); +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd); +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, + unsigned int timeout); +static int kgd_address_watch_disable(struct kgd_dev *kgd); +static int kgd_address_watch_execute(struct kgd_dev *kgd, + unsigned int watch_point_id, + uint32_t cntl_val, + uint32_t addr_hi, + uint32_t addr_lo); +static int kgd_wave_control_execute(struct kgd_dev *kgd, + uint32_t gfx_index_val, + uint32_t sq_cmd); +static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd, + unsigned int watch_point_id, + unsigned int reg_offset); + +static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd, uint8_t vmid); +static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, + uint8_t vmid); +static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid); + +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type); + +static const struct kfd2kgd_calls kfd2kgd = { + .init_gtt_mem_allocation = alloc_gtt_mem, + .free_gtt_mem = free_gtt_mem, + .get_vmem_size = get_vmem_size, + .get_gpu_clock_counter = get_gpu_clock_counter, + .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz, + .program_sh_mem_settings = kgd_program_sh_mem_settings, + .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping, + .init_pipeline = kgd_init_pipeline, + .init_interrupts = kgd_init_interrupts, + .hqd_load = kgd_hqd_load, + .hqd_sdma_load = kgd_hqd_sdma_load, + .hqd_is_occupied = kgd_hqd_is_occupied, + .hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied, + .hqd_destroy = kgd_hqd_destroy, + .hqd_sdma_destroy = kgd_hqd_sdma_destroy, + .address_watch_disable = kgd_address_watch_disable, + .address_watch_execute = kgd_address_watch_execute, + .wave_control_execute = kgd_wave_control_execute, + .address_watch_get_offset = kgd_address_watch_get_offset, + .get_atc_vmid_pasid_mapping_pasid = get_atc_vmid_pasid_mapping_pasid, + .get_atc_vmid_pasid_mapping_valid = get_atc_vmid_pasid_mapping_valid, + .write_vmid_invalidate_request = write_vmid_invalidate_request, + .get_fw_version = get_fw_version +}; + +struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions() +{ + return (struct kfd2kgd_calls *)&kfd2kgd; +} + +static inline struct amdgpu_device *get_amdgpu_device(struct kgd_dev *kgd) +{ + return (struct amdgpu_device *)kgd; +} + +static void lock_srbm(struct kgd_dev *kgd, uint32_t mec, uint32_t pipe, + uint32_t queue, uint32_t vmid) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t value = PIPEID(pipe) | MEID(mec) | VMID(vmid) | QUEUEID(queue); + + mutex_lock(&adev->srbm_mutex); + WREG32(mmSRBM_GFX_CNTL, value); +} + +static void unlock_srbm(struct kgd_dev *kgd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + WREG32(mmSRBM_GFX_CNTL, 0); + mutex_unlock(&adev->srbm_mutex); +} + +static void acquire_queue(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t queue_id) +{ + uint32_t mec = (++pipe_id / CIK_PIPE_PER_MEC) + 1; + uint32_t pipe = (pipe_id % CIK_PIPE_PER_MEC); + + lock_srbm(kgd, mec, pipe, queue_id, 0); +} + +static void release_queue(struct kgd_dev *kgd) +{ + unlock_srbm(kgd); +} + +static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid, + uint32_t sh_mem_config, + uint32_t sh_mem_ape1_base, + uint32_t sh_mem_ape1_limit, + uint32_t sh_mem_bases) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + lock_srbm(kgd, 0, 0, 0, vmid); + + WREG32(mmSH_MEM_CONFIG, sh_mem_config); + WREG32(mmSH_MEM_APE1_BASE, sh_mem_ape1_base); + WREG32(mmSH_MEM_APE1_LIMIT, sh_mem_ape1_limit); + WREG32(mmSH_MEM_BASES, sh_mem_bases); + + unlock_srbm(kgd); +} + +static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, + unsigned int vmid) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + /* + * We have to assume that there is no outstanding mapping. + * The ATC_VMID_PASID_MAPPING_UPDATE_STATUS bit could be 0 because + * a mapping is in progress or because a mapping finished and the + * SW cleared it. So the protocol is to always wait & clear. + */ + uint32_t pasid_mapping = (pasid == 0) ? 0 : (uint32_t)pasid | + ATC_VMID0_PASID_MAPPING__VALID_MASK; + + WREG32(mmATC_VMID0_PASID_MAPPING + vmid, pasid_mapping); + + while (!(RREG32(mmATC_VMID_PASID_MAPPING_UPDATE_STATUS) & (1U << vmid))) + cpu_relax(); + WREG32(mmATC_VMID_PASID_MAPPING_UPDATE_STATUS, 1U << vmid); + + /* Mapping vmid to pasid also for IH block */ + WREG32(mmIH_VMID_0_LUT + vmid, pasid_mapping); + + return 0; +} + +static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t hpd_size, uint64_t hpd_gpu_addr) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + uint32_t mec = (++pipe_id / CIK_PIPE_PER_MEC) + 1; + uint32_t pipe = (pipe_id % CIK_PIPE_PER_MEC); + + lock_srbm(kgd, mec, pipe, 0, 0); + WREG32(mmCP_HPD_EOP_BASE_ADDR, lower_32_bits(hpd_gpu_addr >> 8)); + WREG32(mmCP_HPD_EOP_BASE_ADDR_HI, upper_32_bits(hpd_gpu_addr >> 8)); + WREG32(mmCP_HPD_EOP_VMID, 0); + WREG32(mmCP_HPD_EOP_CONTROL, hpd_size); + unlock_srbm(kgd); + + return 0; +} + +static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t mec; + uint32_t pipe; + + mec = (pipe_id / CIK_PIPE_PER_MEC) + 1; + pipe = (pipe_id % CIK_PIPE_PER_MEC); + + lock_srbm(kgd, mec, pipe, 0, 0); + + WREG32(mmCPC_INT_CNTL, CP_INT_CNTL_RING0__TIME_STAMP_INT_ENABLE_MASK | + CP_INT_CNTL_RING0__OPCODE_ERROR_INT_ENABLE_MASK); + + unlock_srbm(kgd); + + return 0; +} + +static inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m) +{ + uint32_t retval; + + retval = m->sdma_engine_id * SDMA1_REGISTER_OFFSET + + m->sdma_queue_id * KFD_CIK_SDMA_QUEUE_OFFSET; + + pr_debug("kfd: sdma base address: 0x%x\n", retval); + + return retval; +} + +static inline struct cik_mqd *get_mqd(void *mqd) +{ + return (struct cik_mqd *)mqd; +} + +static inline struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd) +{ + return (struct cik_sdma_rlc_registers *)mqd; +} + +static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, + uint32_t queue_id, uint32_t __user *wptr) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t wptr_shadow, is_wptr_shadow_valid; + struct cik_mqd *m; + + m = get_mqd(mqd); + + is_wptr_shadow_valid = !get_user(wptr_shadow, wptr); + + acquire_queue(kgd, pipe_id, queue_id); + WREG32(mmCP_MQD_BASE_ADDR, m->cp_mqd_base_addr_lo); + WREG32(mmCP_MQD_BASE_ADDR_HI, m->cp_mqd_base_addr_hi); + WREG32(mmCP_MQD_CONTROL, m->cp_mqd_control); + + WREG32(mmCP_HQD_PQ_BASE, m->cp_hqd_pq_base_lo); + WREG32(mmCP_HQD_PQ_BASE_HI, m->cp_hqd_pq_base_hi); + WREG32(mmCP_HQD_PQ_CONTROL, m->cp_hqd_pq_control); + + WREG32(mmCP_HQD_IB_CONTROL, m->cp_hqd_ib_control); + WREG32(mmCP_HQD_IB_BASE_ADDR, m->cp_hqd_ib_base_addr_lo); + WREG32(mmCP_HQD_IB_BASE_ADDR_HI, m->cp_hqd_ib_base_addr_hi); + + WREG32(mmCP_HQD_IB_RPTR, m->cp_hqd_ib_rptr); + + WREG32(mmCP_HQD_PERSISTENT_STATE, m->cp_hqd_persistent_state); + WREG32(mmCP_HQD_SEMA_CMD, m->cp_hqd_sema_cmd); + WREG32(mmCP_HQD_MSG_TYPE, m->cp_hqd_msg_type); + + WREG32(mmCP_HQD_ATOMIC0_PREOP_LO, m->cp_hqd_atomic0_preop_lo); + WREG32(mmCP_HQD_ATOMIC0_PREOP_HI, m->cp_hqd_atomic0_preop_hi); + WREG32(mmCP_HQD_ATOMIC1_PREOP_LO, m->cp_hqd_atomic1_preop_lo); + WREG32(mmCP_HQD_ATOMIC1_PREOP_HI, m->cp_hqd_atomic1_preop_hi); + + WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR, m->cp_hqd_pq_rptr_report_addr_lo); + WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR_HI, + m->cp_hqd_pq_rptr_report_addr_hi); + + WREG32(mmCP_HQD_PQ_RPTR, m->cp_hqd_pq_rptr); + + WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR, m->cp_hqd_pq_wptr_poll_addr_lo); + WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR_HI, m->cp_hqd_pq_wptr_poll_addr_hi); + + WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, m->cp_hqd_pq_doorbell_control); + + WREG32(mmCP_HQD_VMID, m->cp_hqd_vmid); + + WREG32(mmCP_HQD_QUANTUM, m->cp_hqd_quantum); + + WREG32(mmCP_HQD_PIPE_PRIORITY, m->cp_hqd_pipe_priority); + WREG32(mmCP_HQD_QUEUE_PRIORITY, m->cp_hqd_queue_priority); + + WREG32(mmCP_HQD_IQ_RPTR, m->cp_hqd_iq_rptr); + + if (is_wptr_shadow_valid) + WREG32(mmCP_HQD_PQ_WPTR, wptr_shadow); + + WREG32(mmCP_HQD_ACTIVE, m->cp_hqd_active); + release_queue(kgd); + + return 0; +} + +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_VIRTUAL_ADDR, + m->sdma_rlc_virtual_addr); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, + m->sdma_rlc_rb_base); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE_HI, + m->sdma_rlc_rb_base_hi); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_LO, + m->sdma_rlc_rb_rptr_addr_lo); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_HI, + m->sdma_rlc_rb_rptr_addr_hi); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, + m->sdma_rlc_doorbell); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL, + m->sdma_rlc_rb_cntl); + + return 0; +} + +static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address, + uint32_t pipe_id, uint32_t queue_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t act; + bool retval = false; + uint32_t low, high; + + acquire_queue(kgd, pipe_id, queue_id); + act = RREG32(mmCP_HQD_ACTIVE); + if (act) { + low = lower_32_bits(queue_address >> 8); + high = upper_32_bits(queue_address >> 8); + + if (low == RREG32(mmCP_HQD_PQ_BASE) && + high == RREG32(mmCP_HQD_PQ_BASE_HI)) + retval = true; + } + release_queue(kgd); + return retval; +} + +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + uint32_t sdma_rlc_rb_cntl; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + sdma_rlc_rb_cntl = RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL); + + if (sdma_rlc_rb_cntl & SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK) + return true; + + return false; +} + +static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t temp; + + acquire_queue(kgd, pipe_id, queue_id); + WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, 0); + + WREG32(mmCP_HQD_DEQUEUE_REQUEST, reset_type); + + while (true) { + temp = RREG32(mmCP_HQD_ACTIVE); + if (temp & CP_HQD_ACTIVE__ACTIVE__SHIFT) + break; + if (timeout == 0) { + pr_err("kfd: cp queue preemption time out (%dms)\n", + temp); + release_queue(kgd); + return -ETIME; + } + msleep(20); + timeout -= 20; + } + + release_queue(kgd); + return 0; +} + +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, + unsigned int timeout) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + uint32_t temp; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL); + temp = temp & ~SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK; + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL, temp); + + while (true) { + temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS); + if (temp & SDMA0_STATUS_REG__RB_CMD_IDLE__SHIFT) + break; + if (timeout == 0) + return -ETIME; + msleep(20); + timeout -= 20; + } + + WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, 0); + + return 0; +} + +static int kgd_address_watch_disable(struct kgd_dev *kgd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + union TCP_WATCH_CNTL_BITS cntl; + unsigned int i; + + cntl.u32All = 0; + + cntl.bitfields.valid = 0; + cntl.bitfields.mask = ADDRESS_WATCH_REG_CNTL_DEFAULT_MASK; + cntl.bitfields.atc = 1; + + /* Turning off this address until we set all the registers */ + for (i = 0; i < MAX_WATCH_ADDRESSES; i++) + WREG32(watchRegs[i * ADDRESS_WATCH_REG_MAX + + ADDRESS_WATCH_REG_CNTL], cntl.u32All); + + return 0; +} + +static int kgd_address_watch_execute(struct kgd_dev *kgd, + unsigned int watch_point_id, + uint32_t cntl_val, + uint32_t addr_hi, + uint32_t addr_lo) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + union TCP_WATCH_CNTL_BITS cntl; + + cntl.u32All = cntl_val; + + /* Turning off this watch point until we set all the registers */ + cntl.bitfields.valid = 0; + WREG32(watchRegs[watch_point_id * ADDRESS_WATCH_REG_MAX + + ADDRESS_WATCH_REG_CNTL], cntl.u32All); + + WREG32(watchRegs[watch_point_id * ADDRESS_WATCH_REG_MAX + + ADDRESS_WATCH_REG_ADDR_HI], addr_hi); + + WREG32(watchRegs[watch_point_id * ADDRESS_WATCH_REG_MAX + + ADDRESS_WATCH_REG_ADDR_LO], addr_lo); + + /* Enable the watch point */ + cntl.bitfields.valid = 1; + + WREG32(watchRegs[watch_point_id * ADDRESS_WATCH_REG_MAX + + ADDRESS_WATCH_REG_CNTL], cntl.u32All); + + return 0; +} + +static int kgd_wave_control_execute(struct kgd_dev *kgd, + uint32_t gfx_index_val, + uint32_t sq_cmd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t data; + + mutex_lock(&adev->grbm_idx_mutex); + + WREG32(mmGRBM_GFX_INDEX, gfx_index_val); + WREG32(mmSQ_CMD, sq_cmd); + + /* Restore the GRBM_GFX_INDEX register */ + + data = GRBM_GFX_INDEX__INSTANCE_BROADCAST_WRITES_MASK | + GRBM_GFX_INDEX__SH_BROADCAST_WRITES_MASK | + GRBM_GFX_INDEX__SE_BROADCAST_WRITES_MASK; + + WREG32(mmGRBM_GFX_INDEX, data); + + mutex_unlock(&adev->grbm_idx_mutex); + + return 0; +} + +static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd, + unsigned int watch_point_id, + unsigned int reg_offset) +{ + return watchRegs[watch_point_id * ADDRESS_WATCH_REG_MAX + reg_offset]; +} + +static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd, + uint8_t vmid) +{ + uint32_t reg; + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + reg = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); + return reg & ATC_VMID0_PASID_MAPPING__VALID_MASK; +} + +static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, + uint8_t vmid) +{ + uint32_t reg; + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + reg = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); + return reg & ATC_VMID0_PASID_MAPPING__VALID_MASK; +} + +static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); +} + +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + const union amdgpu_firmware_header *hdr; + + BUG_ON(kgd == NULL); + + switch (type) { + case KGD_ENGINE_PFP: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.pfp_fw->data; + break; + + case KGD_ENGINE_ME: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.me_fw->data; + break; + + case KGD_ENGINE_CE: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.ce_fw->data; + break; + + case KGD_ENGINE_MEC1: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.mec_fw->data; + break; + + case KGD_ENGINE_MEC2: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.mec2_fw->data; + break; + + case KGD_ENGINE_RLC: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.rlc_fw->data; + break; + + case KGD_ENGINE_SDMA1: + hdr = (const union amdgpu_firmware_header *) + adev->sdma[0].fw->data; + break; + + case KGD_ENGINE_SDMA2: + hdr = (const union amdgpu_firmware_header *) + adev->sdma[1].fw->data; + break; + + default: + return 0; + } + + if (hdr == NULL) + return 0; + + /* Only 12 bit in use*/ + return hdr->common.ucode_version; +} + diff --git a/drivers/gpu/drm/amd/amdgpu/cikd.h b/drivers/gpu/drm/amd/amdgpu/cikd.h index d19085a97064..a3e3dfaa01a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/cikd.h +++ b/drivers/gpu/drm/amd/amdgpu/cikd.h @@ -552,6 +552,12 @@ #define VCE_CMD_IB_AUTO 0x00000005 #define VCE_CMD_SEMAPHORE 0x00000006 +/* if PTR32, these are the bases for scratch and lds */ +#define PRIVATE_BASE(x) ((x) << 0) /* scratch */ +#define SHARED_BASE(x) ((x) << 16) /* LDS */ + +#define KFD_CIK_SDMA_QUEUE_OFFSET 0x200 + /* valid for both DEFAULT_MTYPE and APE1_MTYPE */ enum { MTYPE_CACHED = 0, -- cgit v1.3-6-gb490 From ff758a12b45b0513dbe9905deba2a29b20412138 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Tue, 7 Oct 2014 14:43:07 +0300 Subject: drm/amdgpu: Add amdgpu <--> amdkfd gfx8 interface This patch adds the gfx8 interface file between amdgpu and amdkfd. This interface file is currently in use when running on a Carrizo-based system. The interface itself is represented by a pointer to struct kfd_dev. The pointer is located inside amdgpu_device structure. All the register accesses that amdkfd need are done using this interface. This allows us to avoid direct register accesses in amdkfd proper, while also allows us to avoid locking between amdkfd and amdgpu. The single exception is the doorbells that are used in both of the drivers. However, because they are located in separate pci bar pages, the danger of sharing registers between the drivers is minimal. Having said that, we are planning to move the doorbells as well to amdgpu. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- MAINTAINERS | 2 + drivers/gpu/drm/amd/amdgpu/Makefile | 3 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 3 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 543 ++++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/vid.h | 5 + drivers/gpu/drm/amd/include/vi_structs.h | 417 +++++++++++++++++ 7 files changed, 973 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c create mode 100644 drivers/gpu/drm/amd/include/vi_structs.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 5cc07349b523..9c9dd5fc7aff 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -639,9 +639,11 @@ S: Supported F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c F: drivers/gpu/drm/amd/amdkfd/ F: drivers/gpu/drm/amd/include/cik_structs.h F: drivers/gpu/drm/amd/include/kgd_kfd_interface.h +F: drivers/gpu/drm/amd/include/vi_structs.h F: drivers/gpu/drm/radeon/radeon_kfd.c F: drivers/gpu/drm/radeon/radeon_kfd.h F: include/uapi/linux/kfd_ioctl.h diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index af5397c40ea3..908360584e4d 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -74,7 +74,8 @@ amdgpu-y += \ # add amdkfd interfaces amdgpu-y += \ amdgpu_amdkfd.o \ - amdgpu_amdkfd_gfx_v7.o + amdgpu_amdkfd_gfx_v7.o \ + amdgpu_amdkfd_gfx_v8.o amdgpu-$(CONFIG_COMPAT) += amdgpu_ioc32.o amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 7aa5ab09ed09..bc763e0c8f4c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -53,6 +53,9 @@ bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev) case CHIP_KAVERI: kfd2kgd = amdgpu_amdkfd_gfx_7_get_functions(); break; + case CHIP_CARRIZO: + kfd2kgd = amdgpu_amdkfd_gfx_8_0_get_functions(); + break; default: return false; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index c81242e84aba..a8be765542e6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -50,6 +50,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *rdev); void amdgpu_amdkfd_device_fini(struct amdgpu_device *rdev); struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void); +struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void); /* Shared API */ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c new file mode 100644 index 000000000000..dfd1d503bccf --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -0,0 +1,543 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 "amdgpu.h" +#include "amdgpu_amdkfd.h" +#include "amdgpu_ucode.h" +#include "gca/gfx_8_0_sh_mask.h" +#include "gca/gfx_8_0_d.h" +#include "gca/gfx_8_0_enum.h" +#include "oss/oss_3_0_sh_mask.h" +#include "oss/oss_3_0_d.h" +#include "gmc/gmc_8_1_sh_mask.h" +#include "gmc/gmc_8_1_d.h" +#include "vi_structs.h" +#include "vid.h" + +#define VI_PIPE_PER_MEC (4) + +struct cik_sdma_rlc_registers; + +/* + * Register access functions + */ + +static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid, + uint32_t sh_mem_config, + uint32_t sh_mem_ape1_base, uint32_t sh_mem_ape1_limit, + uint32_t sh_mem_bases); +static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, + unsigned int vmid); +static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t hpd_size, uint64_t hpd_gpu_addr); +static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id); +static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, + uint32_t queue_id, uint32_t __user *wptr); +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd); +static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address, + uint32_t pipe_id, uint32_t queue_id); +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd); +static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id); +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, + unsigned int timeout); +static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid); +static int kgd_address_watch_disable(struct kgd_dev *kgd); +static int kgd_address_watch_execute(struct kgd_dev *kgd, + unsigned int watch_point_id, + uint32_t cntl_val, + uint32_t addr_hi, + uint32_t addr_lo); +static int kgd_wave_control_execute(struct kgd_dev *kgd, + uint32_t gfx_index_val, + uint32_t sq_cmd); +static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd, + unsigned int watch_point_id, + unsigned int reg_offset); + +static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd, + uint8_t vmid); +static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, + uint8_t vmid); +static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid); +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type); + +static const struct kfd2kgd_calls kfd2kgd = { + .init_gtt_mem_allocation = alloc_gtt_mem, + .free_gtt_mem = free_gtt_mem, + .get_vmem_size = get_vmem_size, + .get_gpu_clock_counter = get_gpu_clock_counter, + .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz, + .program_sh_mem_settings = kgd_program_sh_mem_settings, + .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping, + .init_pipeline = kgd_init_pipeline, + .init_interrupts = kgd_init_interrupts, + .hqd_load = kgd_hqd_load, + .hqd_sdma_load = kgd_hqd_sdma_load, + .hqd_is_occupied = kgd_hqd_is_occupied, + .hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied, + .hqd_destroy = kgd_hqd_destroy, + .hqd_sdma_destroy = kgd_hqd_sdma_destroy, + .address_watch_disable = kgd_address_watch_disable, + .address_watch_execute = kgd_address_watch_execute, + .wave_control_execute = kgd_wave_control_execute, + .address_watch_get_offset = kgd_address_watch_get_offset, + .get_atc_vmid_pasid_mapping_pasid = + get_atc_vmid_pasid_mapping_pasid, + .get_atc_vmid_pasid_mapping_valid = + get_atc_vmid_pasid_mapping_valid, + .write_vmid_invalidate_request = write_vmid_invalidate_request, + .get_fw_version = get_fw_version +}; + +struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions() +{ + return (struct kfd2kgd_calls *)&kfd2kgd; +} + +static inline struct amdgpu_device *get_amdgpu_device(struct kgd_dev *kgd) +{ + return (struct amdgpu_device *)kgd; +} + +static void lock_srbm(struct kgd_dev *kgd, uint32_t mec, uint32_t pipe, + uint32_t queue, uint32_t vmid) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t value = PIPEID(pipe) | MEID(mec) | VMID(vmid) | QUEUEID(queue); + + mutex_lock(&adev->srbm_mutex); + WREG32(mmSRBM_GFX_CNTL, value); +} + +static void unlock_srbm(struct kgd_dev *kgd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + WREG32(mmSRBM_GFX_CNTL, 0); + mutex_unlock(&adev->srbm_mutex); +} + +static void acquire_queue(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t queue_id) +{ + uint32_t mec = (++pipe_id / VI_PIPE_PER_MEC) + 1; + uint32_t pipe = (pipe_id % VI_PIPE_PER_MEC); + + lock_srbm(kgd, mec, pipe, queue_id, 0); +} + +static void release_queue(struct kgd_dev *kgd) +{ + unlock_srbm(kgd); +} + +static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid, + uint32_t sh_mem_config, + uint32_t sh_mem_ape1_base, + uint32_t sh_mem_ape1_limit, + uint32_t sh_mem_bases) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + lock_srbm(kgd, 0, 0, 0, vmid); + + WREG32(mmSH_MEM_CONFIG, sh_mem_config); + WREG32(mmSH_MEM_APE1_BASE, sh_mem_ape1_base); + WREG32(mmSH_MEM_APE1_LIMIT, sh_mem_ape1_limit); + WREG32(mmSH_MEM_BASES, sh_mem_bases); + + unlock_srbm(kgd); +} + +static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, + unsigned int vmid) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + /* + * We have to assume that there is no outstanding mapping. + * The ATC_VMID_PASID_MAPPING_UPDATE_STATUS bit could be 0 because + * a mapping is in progress or because a mapping finished + * and the SW cleared it. + * So the protocol is to always wait & clear. + */ + uint32_t pasid_mapping = (pasid == 0) ? 0 : (uint32_t)pasid | + ATC_VMID0_PASID_MAPPING__VALID_MASK; + + WREG32(mmATC_VMID0_PASID_MAPPING + vmid, pasid_mapping); + + while (!(RREG32(mmATC_VMID_PASID_MAPPING_UPDATE_STATUS) & (1U << vmid))) + cpu_relax(); + WREG32(mmATC_VMID_PASID_MAPPING_UPDATE_STATUS, 1U << vmid); + + /* Mapping vmid to pasid also for IH block */ + WREG32(mmIH_VMID_0_LUT + vmid, pasid_mapping); + + return 0; +} + +static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t hpd_size, uint64_t hpd_gpu_addr) +{ + return 0; +} + +static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t mec; + uint32_t pipe; + + mec = (++pipe_id / VI_PIPE_PER_MEC) + 1; + pipe = (pipe_id % VI_PIPE_PER_MEC); + + lock_srbm(kgd, mec, pipe, 0, 0); + + WREG32(mmCPC_INT_CNTL, CP_INT_CNTL_RING0__TIME_STAMP_INT_ENABLE_MASK); + + unlock_srbm(kgd); + + return 0; +} + +static inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m) +{ + return 0; +} + +static inline struct vi_mqd *get_mqd(void *mqd) +{ + return (struct vi_mqd *)mqd; +} + +static inline struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd) +{ + return (struct cik_sdma_rlc_registers *)mqd; +} + +static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, + uint32_t queue_id, uint32_t __user *wptr) +{ + struct vi_mqd *m; + uint32_t shadow_wptr, valid_wptr; + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + m = get_mqd(mqd); + + valid_wptr = copy_from_user(&shadow_wptr, wptr, sizeof(shadow_wptr)); + acquire_queue(kgd, pipe_id, queue_id); + + WREG32(mmCP_MQD_CONTROL, m->cp_mqd_control); + WREG32(mmCP_MQD_BASE_ADDR, m->cp_mqd_base_addr_lo); + WREG32(mmCP_MQD_BASE_ADDR_HI, m->cp_mqd_base_addr_hi); + + WREG32(mmCP_HQD_VMID, m->cp_hqd_vmid); + WREG32(mmCP_HQD_PERSISTENT_STATE, m->cp_hqd_persistent_state); + WREG32(mmCP_HQD_PIPE_PRIORITY, m->cp_hqd_pipe_priority); + WREG32(mmCP_HQD_QUEUE_PRIORITY, m->cp_hqd_queue_priority); + WREG32(mmCP_HQD_QUANTUM, m->cp_hqd_quantum); + WREG32(mmCP_HQD_PQ_BASE, m->cp_hqd_pq_base_lo); + WREG32(mmCP_HQD_PQ_BASE_HI, m->cp_hqd_pq_base_hi); + WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR, m->cp_hqd_pq_rptr_report_addr_lo); + WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR_HI, + m->cp_hqd_pq_rptr_report_addr_hi); + + if (valid_wptr > 0) + WREG32(mmCP_HQD_PQ_WPTR, shadow_wptr); + + WREG32(mmCP_HQD_PQ_CONTROL, m->cp_hqd_pq_control); + WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, m->cp_hqd_pq_doorbell_control); + + WREG32(mmCP_HQD_EOP_BASE_ADDR, m->cp_hqd_eop_base_addr_lo); + WREG32(mmCP_HQD_EOP_BASE_ADDR_HI, m->cp_hqd_eop_base_addr_hi); + WREG32(mmCP_HQD_EOP_CONTROL, m->cp_hqd_eop_control); + WREG32(mmCP_HQD_EOP_RPTR, m->cp_hqd_eop_rptr); + WREG32(mmCP_HQD_EOP_WPTR, m->cp_hqd_eop_wptr); + WREG32(mmCP_HQD_EOP_EVENTS, m->cp_hqd_eop_done_events); + + WREG32(mmCP_HQD_CTX_SAVE_BASE_ADDR_LO, m->cp_hqd_ctx_save_base_addr_lo); + WREG32(mmCP_HQD_CTX_SAVE_BASE_ADDR_HI, m->cp_hqd_ctx_save_base_addr_hi); + WREG32(mmCP_HQD_CTX_SAVE_CONTROL, m->cp_hqd_ctx_save_control); + WREG32(mmCP_HQD_CNTL_STACK_OFFSET, m->cp_hqd_cntl_stack_offset); + WREG32(mmCP_HQD_CNTL_STACK_SIZE, m->cp_hqd_cntl_stack_size); + WREG32(mmCP_HQD_WG_STATE_OFFSET, m->cp_hqd_wg_state_offset); + WREG32(mmCP_HQD_CTX_SAVE_SIZE, m->cp_hqd_ctx_save_size); + + WREG32(mmCP_HQD_IB_CONTROL, m->cp_hqd_ib_control); + + WREG32(mmCP_HQD_DEQUEUE_REQUEST, m->cp_hqd_dequeue_request); + WREG32(mmCP_HQD_ERROR, m->cp_hqd_error); + WREG32(mmCP_HQD_EOP_WPTR_MEM, m->cp_hqd_eop_wptr_mem); + WREG32(mmCP_HQD_EOP_DONES, m->cp_hqd_eop_dones); + + WREG32(mmCP_HQD_ACTIVE, m->cp_hqd_active); + + release_queue(kgd); + + return 0; +} + +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd) +{ + return 0; +} + +static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address, + uint32_t pipe_id, uint32_t queue_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t act; + bool retval = false; + uint32_t low, high; + + acquire_queue(kgd, pipe_id, queue_id); + act = RREG32(mmCP_HQD_ACTIVE); + if (act) { + low = lower_32_bits(queue_address >> 8); + high = upper_32_bits(queue_address >> 8); + + if (low == RREG32(mmCP_HQD_PQ_BASE) && + high == RREG32(mmCP_HQD_PQ_BASE_HI)) + retval = true; + } + release_queue(kgd); + return retval; +} + +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + uint32_t sdma_rlc_rb_cntl; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + sdma_rlc_rb_cntl = RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL); + + if (sdma_rlc_rb_cntl & SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK) + return true; + + return false; +} + +static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t temp; + + acquire_queue(kgd, pipe_id, queue_id); + + WREG32(mmCP_HQD_DEQUEUE_REQUEST, reset_type); + + while (true) { + temp = RREG32(mmCP_HQD_ACTIVE); + if (temp & CP_HQD_ACTIVE__ACTIVE_MASK) + break; + if (timeout == 0) { + pr_err("kfd: cp queue preemption time out (%dms)\n", + temp); + release_queue(kgd); + return -ETIME; + } + msleep(20); + timeout -= 20; + } + + release_queue(kgd); + return 0; +} + +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, + unsigned int timeout) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + uint32_t temp; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL); + temp = temp & ~SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK; + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL, temp); + + while (true) { + temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS); + if (temp & SDMA0_STATUS_REG__RB_CMD_IDLE__SHIFT) + break; + if (timeout == 0) + return -ETIME; + msleep(20); + timeout -= 20; + } + + WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, 0); + + return 0; +} + +static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd, + uint8_t vmid) +{ + uint32_t reg; + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + reg = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); + return reg & ATC_VMID0_PASID_MAPPING__VALID_MASK; +} + +static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, + uint8_t vmid) +{ + uint32_t reg; + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + reg = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); + return reg & ATC_VMID0_PASID_MAPPING__VALID_MASK; +} + +static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); +} + +static int kgd_address_watch_disable(struct kgd_dev *kgd) +{ + return 0; +} + +static int kgd_address_watch_execute(struct kgd_dev *kgd, + unsigned int watch_point_id, + uint32_t cntl_val, + uint32_t addr_hi, + uint32_t addr_lo) +{ + return 0; +} + +static int kgd_wave_control_execute(struct kgd_dev *kgd, + uint32_t gfx_index_val, + uint32_t sq_cmd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t data = 0; + + mutex_lock(&adev->grbm_idx_mutex); + + WREG32(mmGRBM_GFX_INDEX, gfx_index_val); + WREG32(mmSQ_CMD, sq_cmd); + + data = REG_SET_FIELD(data, GRBM_GFX_INDEX, + INSTANCE_BROADCAST_WRITES, 1); + data = REG_SET_FIELD(data, GRBM_GFX_INDEX, + SH_BROADCAST_WRITES, 1); + data = REG_SET_FIELD(data, GRBM_GFX_INDEX, + SE_BROADCAST_WRITES, 1); + + WREG32(mmGRBM_GFX_INDEX, data); + mutex_unlock(&adev->grbm_idx_mutex); + + return 0; +} + +static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd, + unsigned int watch_point_id, + unsigned int reg_offset) +{ + return 0; +} + +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + const union amdgpu_firmware_header *hdr; + + BUG_ON(kgd == NULL); + + switch (type) { + case KGD_ENGINE_PFP: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.pfp_fw->data; + break; + + case KGD_ENGINE_ME: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.me_fw->data; + break; + + case KGD_ENGINE_CE: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.ce_fw->data; + break; + + case KGD_ENGINE_MEC1: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.mec_fw->data; + break; + + case KGD_ENGINE_MEC2: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.mec2_fw->data; + break; + + case KGD_ENGINE_RLC: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.rlc_fw->data; + break; + + case KGD_ENGINE_SDMA1: + hdr = (const union amdgpu_firmware_header *) + adev->sdma[0].fw->data; + break; + + case KGD_ENGINE_SDMA2: + hdr = (const union amdgpu_firmware_header *) + adev->sdma[1].fw->data; + break; + + default: + return 0; + } + + if (hdr == NULL) + return 0; + + /* Only 12 bit in use*/ + return hdr->common.ucode_version; +} diff --git a/drivers/gpu/drm/amd/amdgpu/vid.h b/drivers/gpu/drm/amd/amdgpu/vid.h index 31bb89452e12..d98aa9d82fa1 100644 --- a/drivers/gpu/drm/amd/amdgpu/vid.h +++ b/drivers/gpu/drm/amd/amdgpu/vid.h @@ -66,6 +66,11 @@ #define AMDGPU_NUM_OF_VMIDS 8 +#define PIPEID(x) ((x) << 0) +#define MEID(x) ((x) << 2) +#define VMID(x) ((x) << 4) +#define QUEUEID(x) ((x) << 8) + #define RB_BITMAP_WIDTH_PER_SH 2 #define MC_SEQ_MISC0__MT__MASK 0xf0000000 diff --git a/drivers/gpu/drm/amd/include/vi_structs.h b/drivers/gpu/drm/amd/include/vi_structs.h new file mode 100644 index 000000000000..65cfacd7a66c --- /dev/null +++ b/drivers/gpu/drm/amd/include/vi_structs.h @@ -0,0 +1,417 @@ +/* + * Copyright 2012 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#ifndef VI_STRUCTS_H_ +#define VI_STRUCTS_H_ + +struct vi_sdma_mqd { + uint32_t sdmax_rlcx_rb_cntl; + uint32_t sdmax_rlcx_rb_base; + uint32_t sdmax_rlcx_rb_base_hi; + uint32_t sdmax_rlcx_rb_rptr; + uint32_t sdmax_rlcx_rb_wptr; + uint32_t sdmax_rlcx_rb_wptr_poll_cntl; + uint32_t sdmax_rlcx_rb_wptr_poll_addr_hi; + uint32_t sdmax_rlcx_rb_wptr_poll_addr_lo; + uint32_t sdmax_rlcx_rb_rptr_addr_hi; + uint32_t sdmax_rlcx_rb_rptr_addr_lo; + uint32_t sdmax_rlcx_ib_cntl; + uint32_t sdmax_rlcx_ib_rptr; + uint32_t sdmax_rlcx_ib_offset; + uint32_t sdmax_rlcx_ib_base_lo; + uint32_t sdmax_rlcx_ib_base_hi; + uint32_t sdmax_rlcx_ib_size; + uint32_t sdmax_rlcx_skip_cntl; + uint32_t sdmax_rlcx_context_status; + uint32_t sdmax_rlcx_doorbell; + uint32_t sdmax_rlcx_virtual_addr; + uint32_t sdmax_rlcx_ape1_cntl; + uint32_t sdmax_rlcx_doorbell_log; + uint32_t reserved_22; + uint32_t reserved_23; + uint32_t reserved_24; + uint32_t reserved_25; + uint32_t reserved_26; + uint32_t reserved_27; + uint32_t reserved_28; + uint32_t reserved_29; + uint32_t reserved_30; + uint32_t reserved_31; + uint32_t reserved_32; + uint32_t reserved_33; + uint32_t reserved_34; + uint32_t reserved_35; + uint32_t reserved_36; + uint32_t reserved_37; + uint32_t reserved_38; + uint32_t reserved_39; + uint32_t reserved_40; + uint32_t reserved_41; + uint32_t reserved_42; + uint32_t reserved_43; + uint32_t reserved_44; + uint32_t reserved_45; + uint32_t reserved_46; + uint32_t reserved_47; + uint32_t reserved_48; + uint32_t reserved_49; + uint32_t reserved_50; + uint32_t reserved_51; + uint32_t reserved_52; + uint32_t reserved_53; + uint32_t reserved_54; + uint32_t reserved_55; + uint32_t reserved_56; + uint32_t reserved_57; + uint32_t reserved_58; + uint32_t reserved_59; + uint32_t reserved_60; + uint32_t reserved_61; + uint32_t reserved_62; + uint32_t reserved_63; + uint32_t reserved_64; + uint32_t reserved_65; + uint32_t reserved_66; + uint32_t reserved_67; + uint32_t reserved_68; + uint32_t reserved_69; + uint32_t reserved_70; + uint32_t reserved_71; + uint32_t reserved_72; + uint32_t reserved_73; + uint32_t reserved_74; + uint32_t reserved_75; + uint32_t reserved_76; + uint32_t reserved_77; + uint32_t reserved_78; + uint32_t reserved_79; + uint32_t reserved_80; + uint32_t reserved_81; + uint32_t reserved_82; + uint32_t reserved_83; + uint32_t reserved_84; + uint32_t reserved_85; + uint32_t reserved_86; + uint32_t reserved_87; + uint32_t reserved_88; + uint32_t reserved_89; + uint32_t reserved_90; + uint32_t reserved_91; + uint32_t reserved_92; + uint32_t reserved_93; + uint32_t reserved_94; + uint32_t reserved_95; + uint32_t reserved_96; + uint32_t reserved_97; + uint32_t reserved_98; + uint32_t reserved_99; + uint32_t reserved_100; + uint32_t reserved_101; + uint32_t reserved_102; + uint32_t reserved_103; + uint32_t reserved_104; + uint32_t reserved_105; + uint32_t reserved_106; + uint32_t reserved_107; + uint32_t reserved_108; + uint32_t reserved_109; + uint32_t reserved_110; + uint32_t reserved_111; + uint32_t reserved_112; + uint32_t reserved_113; + uint32_t reserved_114; + uint32_t reserved_115; + uint32_t reserved_116; + uint32_t reserved_117; + uint32_t reserved_118; + uint32_t reserved_119; + uint32_t reserved_120; + uint32_t reserved_121; + uint32_t reserved_122; + uint32_t reserved_123; + uint32_t reserved_124; + uint32_t reserved_125; + uint32_t reserved_126; + uint32_t reserved_127; +}; + +struct vi_mqd { + uint32_t header; + uint32_t compute_dispatch_initiator; + uint32_t compute_dim_x; + uint32_t compute_dim_y; + uint32_t compute_dim_z; + uint32_t compute_start_x; + uint32_t compute_start_y; + uint32_t compute_start_z; + uint32_t compute_num_thread_x; + uint32_t compute_num_thread_y; + uint32_t compute_num_thread_z; + uint32_t compute_pipelinestat_enable; + uint32_t compute_perfcount_enable; + uint32_t compute_pgm_lo; + uint32_t compute_pgm_hi; + uint32_t compute_tba_lo; + uint32_t compute_tba_hi; + uint32_t compute_tma_lo; + uint32_t compute_tma_hi; + uint32_t compute_pgm_rsrc1; + uint32_t compute_pgm_rsrc2; + uint32_t compute_vmid; + uint32_t compute_resource_limits; + uint32_t compute_static_thread_mgmt_se0; + uint32_t compute_static_thread_mgmt_se1; + uint32_t compute_tmpring_size; + uint32_t compute_static_thread_mgmt_se2; + uint32_t compute_static_thread_mgmt_se3; + uint32_t compute_restart_x; + uint32_t compute_restart_y; + uint32_t compute_restart_z; + uint32_t compute_thread_trace_enable; + uint32_t compute_misc_reserved; + uint32_t compute_dispatch_id; + uint32_t compute_threadgroup_id; + uint32_t compute_relaunch; + uint32_t compute_wave_restore_addr_lo; + uint32_t compute_wave_restore_addr_hi; + uint32_t compute_wave_restore_control; + uint32_t reserved_39; + uint32_t reserved_40; + uint32_t reserved_41; + uint32_t reserved_42; + uint32_t reserved_43; + uint32_t reserved_44; + uint32_t reserved_45; + uint32_t reserved_46; + uint32_t reserved_47; + uint32_t reserved_48; + uint32_t reserved_49; + uint32_t reserved_50; + uint32_t reserved_51; + uint32_t reserved_52; + uint32_t reserved_53; + uint32_t reserved_54; + uint32_t reserved_55; + uint32_t reserved_56; + uint32_t reserved_57; + uint32_t reserved_58; + uint32_t reserved_59; + uint32_t reserved_60; + uint32_t reserved_61; + uint32_t reserved_62; + uint32_t reserved_63; + uint32_t reserved_64; + uint32_t compute_user_data_0; + uint32_t compute_user_data_1; + uint32_t compute_user_data_2; + uint32_t compute_user_data_3; + uint32_t compute_user_data_4; + uint32_t compute_user_data_5; + uint32_t compute_user_data_6; + uint32_t compute_user_data_7; + uint32_t compute_user_data_8; + uint32_t compute_user_data_9; + uint32_t compute_user_data_10; + uint32_t compute_user_data_11; + uint32_t compute_user_data_12; + uint32_t compute_user_data_13; + uint32_t compute_user_data_14; + uint32_t compute_user_data_15; + uint32_t cp_compute_csinvoc_count_lo; + uint32_t cp_compute_csinvoc_count_hi; + uint32_t reserved_83; + uint32_t reserved_84; + uint32_t reserved_85; + uint32_t cp_mqd_query_time_lo; + uint32_t cp_mqd_query_time_hi; + uint32_t cp_mqd_connect_start_time_lo; + uint32_t cp_mqd_connect_start_time_hi; + uint32_t cp_mqd_connect_end_time_lo; + uint32_t cp_mqd_connect_end_time_hi; + uint32_t cp_mqd_connect_end_wf_count; + uint32_t cp_mqd_connect_end_pq_rptr; + uint32_t cp_mqd_connect_end_pq_wptr; + uint32_t cp_mqd_connect_end_ib_rptr; + uint32_t reserved_96; + uint32_t reserved_97; + uint32_t cp_mqd_save_start_time_lo; + uint32_t cp_mqd_save_start_time_hi; + uint32_t cp_mqd_save_end_time_lo; + uint32_t cp_mqd_save_end_time_hi; + uint32_t cp_mqd_restore_start_time_lo; + uint32_t cp_mqd_restore_start_time_hi; + uint32_t cp_mqd_restore_end_time_lo; + uint32_t cp_mqd_restore_end_time_hi; + uint32_t reserved_106; + uint32_t reserved_107; + uint32_t gds_cs_ctxsw_cnt0; + uint32_t gds_cs_ctxsw_cnt1; + uint32_t gds_cs_ctxsw_cnt2; + uint32_t gds_cs_ctxsw_cnt3; + uint32_t reserved_112; + uint32_t reserved_113; + uint32_t cp_pq_exe_status_lo; + uint32_t cp_pq_exe_status_hi; + uint32_t cp_packet_id_lo; + uint32_t cp_packet_id_hi; + uint32_t cp_packet_exe_status_lo; + uint32_t cp_packet_exe_status_hi; + uint32_t gds_save_base_addr_lo; + uint32_t gds_save_base_addr_hi; + uint32_t gds_save_mask_lo; + uint32_t gds_save_mask_hi; + uint32_t ctx_save_base_addr_lo; + uint32_t ctx_save_base_addr_hi; + uint32_t reserved_126; + uint32_t reserved_127; + uint32_t cp_mqd_base_addr_lo; + uint32_t cp_mqd_base_addr_hi; + uint32_t cp_hqd_active; + uint32_t cp_hqd_vmid; + uint32_t cp_hqd_persistent_state; + uint32_t cp_hqd_pipe_priority; + uint32_t cp_hqd_queue_priority; + uint32_t cp_hqd_quantum; + uint32_t cp_hqd_pq_base_lo; + uint32_t cp_hqd_pq_base_hi; + uint32_t cp_hqd_pq_rptr; + uint32_t cp_hqd_pq_rptr_report_addr_lo; + uint32_t cp_hqd_pq_rptr_report_addr_hi; + uint32_t cp_hqd_pq_wptr_poll_addr_lo; + uint32_t cp_hqd_pq_wptr_poll_addr_hi; + uint32_t cp_hqd_pq_doorbell_control; + uint32_t cp_hqd_pq_wptr; + uint32_t cp_hqd_pq_control; + uint32_t cp_hqd_ib_base_addr_lo; + uint32_t cp_hqd_ib_base_addr_hi; + uint32_t cp_hqd_ib_rptr; + uint32_t cp_hqd_ib_control; + uint32_t cp_hqd_iq_timer; + uint32_t cp_hqd_iq_rptr; + uint32_t cp_hqd_dequeue_request; + uint32_t cp_hqd_dma_offload; + uint32_t cp_hqd_sema_cmd; + uint32_t cp_hqd_msg_type; + uint32_t cp_hqd_atomic0_preop_lo; + uint32_t cp_hqd_atomic0_preop_hi; + uint32_t cp_hqd_atomic1_preop_lo; + uint32_t cp_hqd_atomic1_preop_hi; + uint32_t cp_hqd_hq_status0; + uint32_t cp_hqd_hq_control0; + uint32_t cp_mqd_control; + uint32_t cp_hqd_hq_status1; + uint32_t cp_hqd_hq_control1; + uint32_t cp_hqd_eop_base_addr_lo; + uint32_t cp_hqd_eop_base_addr_hi; + uint32_t cp_hqd_eop_control; + uint32_t cp_hqd_eop_rptr; + uint32_t cp_hqd_eop_wptr; + uint32_t cp_hqd_eop_done_events; + uint32_t cp_hqd_ctx_save_base_addr_lo; + uint32_t cp_hqd_ctx_save_base_addr_hi; + uint32_t cp_hqd_ctx_save_control; + uint32_t cp_hqd_cntl_stack_offset; + uint32_t cp_hqd_cntl_stack_size; + uint32_t cp_hqd_wg_state_offset; + uint32_t cp_hqd_ctx_save_size; + uint32_t cp_hqd_gds_resource_state; + uint32_t cp_hqd_error; + uint32_t cp_hqd_eop_wptr_mem; + uint32_t cp_hqd_eop_dones; + uint32_t reserved_182; + uint32_t reserved_183; + uint32_t reserved_184; + uint32_t reserved_185; + uint32_t reserved_186; + uint32_t reserved_187; + uint32_t reserved_188; + uint32_t reserved_189; + uint32_t reserved_190; + uint32_t reserved_191; + uint32_t iqtimer_pkt_header; + uint32_t iqtimer_pkt_dw0; + uint32_t iqtimer_pkt_dw1; + uint32_t iqtimer_pkt_dw2; + uint32_t iqtimer_pkt_dw3; + uint32_t iqtimer_pkt_dw4; + uint32_t iqtimer_pkt_dw5; + uint32_t iqtimer_pkt_dw6; + uint32_t iqtimer_pkt_dw7; + uint32_t iqtimer_pkt_dw8; + uint32_t iqtimer_pkt_dw9; + uint32_t iqtimer_pkt_dw10; + uint32_t iqtimer_pkt_dw11; + uint32_t iqtimer_pkt_dw12; + uint32_t iqtimer_pkt_dw13; + uint32_t iqtimer_pkt_dw14; + uint32_t iqtimer_pkt_dw15; + uint32_t iqtimer_pkt_dw16; + uint32_t iqtimer_pkt_dw17; + uint32_t iqtimer_pkt_dw18; + uint32_t iqtimer_pkt_dw19; + uint32_t iqtimer_pkt_dw20; + uint32_t iqtimer_pkt_dw21; + uint32_t iqtimer_pkt_dw22; + uint32_t iqtimer_pkt_dw23; + uint32_t iqtimer_pkt_dw24; + uint32_t iqtimer_pkt_dw25; + uint32_t iqtimer_pkt_dw26; + uint32_t iqtimer_pkt_dw27; + uint32_t iqtimer_pkt_dw28; + uint32_t iqtimer_pkt_dw29; + uint32_t iqtimer_pkt_dw30; + uint32_t iqtimer_pkt_dw31; + uint32_t reserved_225; + uint32_t reserved_226; + uint32_t reserved_227; + uint32_t set_resources_header; + uint32_t set_resources_dw1; + uint32_t set_resources_dw2; + uint32_t set_resources_dw3; + uint32_t set_resources_dw4; + uint32_t set_resources_dw5; + uint32_t set_resources_dw6; + uint32_t set_resources_dw7; + uint32_t reserved_236; + uint32_t reserved_237; + uint32_t reserved_238; + uint32_t reserved_239; + uint32_t queue_doorbell_id0; + uint32_t queue_doorbell_id1; + uint32_t queue_doorbell_id2; + uint32_t queue_doorbell_id3; + uint32_t queue_doorbell_id4; + uint32_t queue_doorbell_id5; + uint32_t queue_doorbell_id6; + uint32_t queue_doorbell_id7; + uint32_t queue_doorbell_id8; + uint32_t queue_doorbell_id9; + uint32_t queue_doorbell_id10; + uint32_t queue_doorbell_id11; + uint32_t queue_doorbell_id12; + uint32_t queue_doorbell_id13; + uint32_t queue_doorbell_id14; + uint32_t queue_doorbell_id15; +}; + +#endif /* VI_STRUCTS_H_ */ -- cgit v1.3-6-gb490 From bd72a72c3a0d3e188b08cdbbc54eb083d860e365 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 21 Nov 2014 23:27:30 +0200 Subject: drm/amdkfd: Add dependency of DRM_AMDGPU to Kconfig Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/Kconfig b/drivers/gpu/drm/amd/amdkfd/Kconfig index 8dfac37ff327..e13c67c8d2c0 100644 --- a/drivers/gpu/drm/amd/amdkfd/Kconfig +++ b/drivers/gpu/drm/amd/amdkfd/Kconfig @@ -4,6 +4,6 @@ config HSA_AMD tristate "HSA kernel driver for AMD GPU devices" - depends on DRM_RADEON && AMD_IOMMU_V2 && X86_64 + depends on (DRM_RADEON || DRM_AMDGPU) && AMD_IOMMU_V2 && X86_64 help Enable this if you want to use HSA features on AMD GPU devices. -- cgit v1.3-6-gb490 From 123576d1440df7bfa6e2188784e8cd9dc01eea6b Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Mon, 12 Jan 2015 14:37:24 +0200 Subject: drm/amdkfd: add supported CZ devices PCI IDs to amdkfd This patch adds the PCI IDs of supported CZ devices to the supported_devices structure in amdkfd. That structure is used during the amdkfd probing stage, to check if the currently probed device is eligible to be handled by amdkfd. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 75312c82969f..3f95f7cb4019 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -80,7 +80,12 @@ static const struct kfd_deviceid supported_devices[] = { { 0x1318, &kaveri_device_info }, /* Kaveri */ { 0x131B, &kaveri_device_info }, /* Kaveri */ { 0x131C, &kaveri_device_info }, /* Kaveri */ - { 0x131D, &kaveri_device_info } /* Kaveri */ + { 0x131D, &kaveri_device_info }, /* Kaveri */ + { 0x9870, &carrizo_device_info }, /* Carrizo */ + { 0x9874, &carrizo_device_info }, /* Carrizo */ + { 0x9875, &carrizo_device_info }, /* Carrizo */ + { 0x9876, &carrizo_device_info }, /* Carrizo */ + { 0x9877, &carrizo_device_info } /* Carrizo */ }; static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size, -- cgit v1.3-6-gb490 From 2d8f1f330356f4e22cbf860af78d715715595041 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Sun, 4 Jan 2015 10:48:26 +0200 Subject: drm/amdkfd: add CP HWS packet headers for VI Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_vi.h | 398 ++++++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_vi.h (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_vi.h b/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_vi.h new file mode 100644 index 000000000000..08c721922812 --- /dev/null +++ b/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_vi.h @@ -0,0 +1,398 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#ifndef F32_MES_PM4_PACKETS_H +#define F32_MES_PM4_PACKETS_H + +#ifndef PM4_MES_HEADER_DEFINED +#define PM4_MES_HEADER_DEFINED +union PM4_MES_TYPE_3_HEADER { + struct { + uint32_t reserved1 : 8; /* < reserved */ + uint32_t opcode : 8; /* < IT opcode */ + uint32_t count : 14;/* < number of DWORDs - 1 in the + information body. */ + uint32_t type : 2; /* < packet identifier. + It should be 3 for type 3 packets */ + }; + uint32_t u32All; +}; +#endif /* PM4_MES_HEADER_DEFINED */ + +/*--------------------MES_SET_RESOURCES--------------------*/ + +#ifndef PM4_MES_SET_RESOURCES_DEFINED +#define PM4_MES_SET_RESOURCES_DEFINED +enum mes_set_resources_queue_type_enum { + queue_type__mes_set_resources__kernel_interface_queue_kiq = 0, + queue_type__mes_set_resources__hsa_interface_queue_hiq = 1, + queue_type__mes_set_resources__hsa_debug_interface_queue = 4 +}; + + +struct pm4_mes_set_resources { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + uint32_t vmid_mask:16; + uint32_t unmap_latency:8; + uint32_t reserved1:5; + enum mes_set_resources_queue_type_enum queue_type:3; + } bitfields2; + uint32_t ordinal2; + }; + + uint32_t queue_mask_lo; + uint32_t queue_mask_hi; + uint32_t gws_mask_lo; + uint32_t gws_mask_hi; + + union { + struct { + uint32_t oac_mask:16; + uint32_t reserved2:16; + } bitfields7; + uint32_t ordinal7; + }; + + union { + struct { + uint32_t gds_heap_base:6; + uint32_t reserved3:5; + uint32_t gds_heap_size:6; + uint32_t reserved4:15; + } bitfields8; + uint32_t ordinal8; + }; + +}; +#endif + +/*--------------------MES_RUN_LIST--------------------*/ + +#ifndef PM4_MES_RUN_LIST_DEFINED +#define PM4_MES_RUN_LIST_DEFINED + +struct pm4_mes_runlist { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + uint32_t reserved1:2; + uint32_t ib_base_lo:30; + } bitfields2; + uint32_t ordinal2; + }; + + union { + struct { + uint32_t ib_base_hi:16; + uint32_t reserved2:16; + } bitfields3; + uint32_t ordinal3; + }; + + union { + struct { + uint32_t ib_size:20; + uint32_t chain:1; + uint32_t offload_polling:1; + uint32_t reserved3:1; + uint32_t valid:1; + uint32_t reserved4:8; + } bitfields4; + uint32_t ordinal4; + }; + +}; +#endif + +/*--------------------MES_MAP_PROCESS--------------------*/ + +#ifndef PM4_MES_MAP_PROCESS_DEFINED +#define PM4_MES_MAP_PROCESS_DEFINED + +struct pm4_mes_map_process { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + uint32_t pasid:16; + uint32_t reserved1:8; + uint32_t diq_enable:1; + uint32_t process_quantum:7; + } bitfields2; + uint32_t ordinal2; +}; + + union { + struct { + uint32_t page_table_base:28; + uint32_t reserved2:4; + } bitfields3; + uint32_t ordinal3; + }; + + uint32_t sh_mem_bases; + uint32_t sh_mem_ape1_base; + uint32_t sh_mem_ape1_limit; + uint32_t sh_mem_config; + uint32_t gds_addr_lo; + uint32_t gds_addr_hi; + + union { + struct { + uint32_t num_gws:6; + uint32_t reserved3:2; + uint32_t num_oac:4; + uint32_t reserved4:4; + uint32_t gds_size:6; + uint32_t num_queues:10; + } bitfields10; + uint32_t ordinal10; + }; + +}; +#endif + +/*--------------------MES_MAP_QUEUES--------------------*/ + +#ifndef PM4_MES_MAP_QUEUES_VI_DEFINED +#define PM4_MES_MAP_QUEUES_VI_DEFINED +enum mes_map_queues_queue_sel_vi_enum { + queue_sel__mes_map_queues__map_to_specified_queue_slots_vi = 0, +queue_sel__mes_map_queues__map_to_hws_determined_queue_slots_vi = 1 +}; + +enum mes_map_queues_queue_type_vi_enum { + queue_type__mes_map_queues__normal_compute_vi = 0, + queue_type__mes_map_queues__debug_interface_queue_vi = 1, + queue_type__mes_map_queues__normal_latency_static_queue_vi = 2, +queue_type__mes_map_queues__low_latency_static_queue_vi = 3 +}; + +enum mes_map_queues_alloc_format_vi_enum { + alloc_format__mes_map_queues__one_per_pipe_vi = 0, +alloc_format__mes_map_queues__all_on_one_pipe_vi = 1 +}; + +enum mes_map_queues_engine_sel_vi_enum { + engine_sel__mes_map_queues__compute_vi = 0, + engine_sel__mes_map_queues__sdma0_vi = 2, + engine_sel__mes_map_queues__sdma1_vi = 3 +}; + + +struct pm4_mes_map_queues { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + uint32_t reserved1:4; + enum mes_map_queues_queue_sel_vi_enum queue_sel:2; + uint32_t reserved2:15; + enum mes_map_queues_queue_type_vi_enum queue_type:3; + enum mes_map_queues_alloc_format_vi_enum alloc_format:2; + enum mes_map_queues_engine_sel_vi_enum engine_sel:3; + uint32_t num_queues:3; + } bitfields2; + uint32_t ordinal2; + }; + + union { + struct { + uint32_t reserved3:1; + uint32_t check_disable:1; + uint32_t doorbell_offset:21; + uint32_t reserved4:3; + uint32_t queue:6; + } bitfields3; + uint32_t ordinal3; + }; + + uint32_t mqd_addr_lo; + uint32_t mqd_addr_hi; + uint32_t wptr_addr_lo; + uint32_t wptr_addr_hi; +}; +#endif + +/*--------------------MES_QUERY_STATUS--------------------*/ + +#ifndef PM4_MES_QUERY_STATUS_DEFINED +#define PM4_MES_QUERY_STATUS_DEFINED +enum mes_query_status_interrupt_sel_enum { + interrupt_sel__mes_query_status__completion_status = 0, + interrupt_sel__mes_query_status__process_status = 1, + interrupt_sel__mes_query_status__queue_status = 2 +}; + +enum mes_query_status_command_enum { + command__mes_query_status__interrupt_only = 0, + command__mes_query_status__fence_only_immediate = 1, + command__mes_query_status__fence_only_after_write_ack = 2, + command__mes_query_status__fence_wait_for_write_ack_send_interrupt = 3 +}; + +enum mes_query_status_engine_sel_enum { + engine_sel__mes_query_status__compute = 0, + engine_sel__mes_query_status__sdma0_queue = 2, + engine_sel__mes_query_status__sdma1_queue = 3 +}; + +struct pm4_mes_query_status { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + uint32_t context_id:28; + enum mes_query_status_interrupt_sel_enum + interrupt_sel:2; + enum mes_query_status_command_enum command:2; + } bitfields2; + uint32_t ordinal2; + }; + + union { + struct { + uint32_t pasid:16; + uint32_t reserved1:16; + } bitfields3a; + struct { + uint32_t reserved2:2; + uint32_t doorbell_offset:21; + uint32_t reserved3:2; + enum mes_query_status_engine_sel_enum engine_sel:3; + uint32_t reserved4:4; + } bitfields3b; + uint32_t ordinal3; + }; + + uint32_t addr_lo; + uint32_t addr_hi; + uint32_t data_lo; + uint32_t data_hi; +}; +#endif + +/*--------------------MES_UNMAP_QUEUES--------------------*/ + +#ifndef PM4_MES_UNMAP_QUEUES_DEFINED +#define PM4_MES_UNMAP_QUEUES_DEFINED +enum mes_unmap_queues_action_enum { + action__mes_unmap_queues__preempt_queues = 0, + action__mes_unmap_queues__reset_queues = 1, + action__mes_unmap_queues__disable_process_queues = 2, + action__mes_unmap_queues__reserved = 3 +}; + +enum mes_unmap_queues_queue_sel_enum { + queue_sel__mes_unmap_queues__perform_request_on_specified_queues = 0, + queue_sel__mes_unmap_queues__perform_request_on_pasid_queues = 1, + queue_sel__mes_unmap_queues__unmap_all_queues = 2, + queue_sel__mes_unmap_queues__unmap_all_non_static_queues = 3 +}; + +enum mes_unmap_queues_engine_sel_enum { + engine_sel__mes_unmap_queues__compute = 0, + engine_sel__mes_unmap_queues__sdma0 = 2, + engine_sel__mes_unmap_queues__sdmal = 3 +}; + +struct PM4_MES_UNMAP_QUEUES { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + enum mes_unmap_queues_action_enum action:2; + uint32_t reserved1:2; + enum mes_unmap_queues_queue_sel_enum queue_sel:2; + uint32_t reserved2:20; + enum mes_unmap_queues_engine_sel_enum engine_sel:3; + uint32_t num_queues:3; + } bitfields2; + uint32_t ordinal2; + }; + + union { + struct { + uint32_t pasid:16; + uint32_t reserved3:16; + } bitfields3a; + struct { + uint32_t reserved4:2; + uint32_t doorbell_offset0:21; + uint32_t reserved5:9; + } bitfields3b; + uint32_t ordinal3; + }; + + union { + struct { + uint32_t reserved6:2; + uint32_t doorbell_offset1:21; + uint32_t reserved7:9; + } bitfields4; + uint32_t ordinal4; + }; + + union { + struct { + uint32_t reserved8:2; + uint32_t doorbell_offset2:21; + uint32_t reserved9:9; + } bitfields5; + uint32_t ordinal5; + }; + + union { + struct { + uint32_t reserved10:2; + uint32_t doorbell_offset3:21; + uint32_t reserved11:9; + } bitfields6; + uint32_t ordinal6; + }; +}; +#endif + +#endif -- cgit v1.3-6-gb490 From d696d536f0a97ac779d6176107ac4e96d0a2f8b9 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Mon, 12 Jan 2015 14:26:10 +0200 Subject: drm/amdkfd: add support for VI in MQD manager This patch implements all the VI MQD manager functions. This is done in a different file as the MQD format is different between CI and VI Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/Makefile | 3 +- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 249 +++++++++++++++++++++++- 2 files changed, 248 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile index 28551153ec6d..7fc9b0f444cb 100644 --- a/drivers/gpu/drm/amd/amdkfd/Makefile +++ b/drivers/gpu/drm/amd/amdkfd/Makefile @@ -2,7 +2,8 @@ # Makefile for Heterogenous System Architecture support for AMD GPU devices # -ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/ +ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/ \ + -Idrivers/gpu/drm/amd/include/asic_reg amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \ kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index b3a7e3ba1e38..fa32c32fa1c2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -22,12 +22,255 @@ */ #include +#include #include "kfd_priv.h" #include "kfd_mqd_manager.h" +#include "vi_structs.h" +#include "gca/gfx_8_0_sh_mask.h" +#include "gca/gfx_8_0_enum.h" + +#define CP_MQD_CONTROL__PRIV_STATE__SHIFT 0x8 + +static inline struct vi_mqd *get_mqd(void *mqd) +{ + return (struct vi_mqd *)mqd; +} + +static int init_mqd(struct mqd_manager *mm, void **mqd, + struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, + struct queue_properties *q) +{ + int retval; + uint64_t addr; + struct vi_mqd *m; + + retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct vi_mqd), + mqd_mem_obj); + if (retval != 0) + return -ENOMEM; + + m = (struct vi_mqd *) (*mqd_mem_obj)->cpu_ptr; + addr = (*mqd_mem_obj)->gpu_addr; + + memset(m, 0, sizeof(struct vi_mqd)); + + m->header = 0xC0310800; + m->compute_pipelinestat_enable = 1; + m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF; + + m->cp_hqd_persistent_state = CP_HQD_PERSISTENT_STATE__PRELOAD_REQ_MASK | + 0x53 << CP_HQD_PERSISTENT_STATE__PRELOAD_SIZE__SHIFT; + + m->cp_mqd_control = 1 << CP_MQD_CONTROL__PRIV_STATE__SHIFT | + MTYPE_UC << CP_MQD_CONTROL__MTYPE__SHIFT; + + m->cp_mqd_base_addr_lo = lower_32_bits(addr); + m->cp_mqd_base_addr_hi = upper_32_bits(addr); + + m->cp_hqd_quantum = 1 << CP_HQD_QUANTUM__QUANTUM_EN__SHIFT | + 1 << CP_HQD_QUANTUM__QUANTUM_SCALE__SHIFT | + 10 << CP_HQD_QUANTUM__QUANTUM_DURATION__SHIFT; + + m->cp_hqd_pipe_priority = 1; + m->cp_hqd_queue_priority = 15; + + m->cp_hqd_eop_rptr = 1 << CP_HQD_EOP_RPTR__INIT_FETCHER__SHIFT; + + if (q->format == KFD_QUEUE_FORMAT_AQL) + m->cp_hqd_iq_rptr = 1; + + *mqd = m; + if (gart_addr != NULL) + *gart_addr = addr; + retval = mm->update_mqd(mm, m, q); + + return retval; +} + +static int load_mqd(struct mqd_manager *mm, void *mqd, + uint32_t pipe_id, uint32_t queue_id, + uint32_t __user *wptr) +{ + return mm->dev->kfd2kgd->hqd_load + (mm->dev->kgd, mqd, pipe_id, queue_id, wptr); +} + +static int __update_mqd(struct mqd_manager *mm, void *mqd, + struct queue_properties *q, unsigned int mtype, + unsigned int atc_bit) +{ + struct vi_mqd *m; + + BUG_ON(!mm || !q || !mqd); + + pr_debug("kfd: In func %s\n", __func__); + + m = get_mqd(mqd); + + m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT | + atc_bit << CP_HQD_PQ_CONTROL__PQ_ATC__SHIFT | + mtype << CP_HQD_PQ_CONTROL__MTYPE__SHIFT; + m->cp_hqd_pq_control |= + ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1; + pr_debug("kfd: cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control); + + m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); + m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8); + + m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr); + m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr); + + m->cp_hqd_pq_doorbell_control = + 1 << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_EN__SHIFT | + q->doorbell_off << + CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT; + pr_debug("kfd: cp_hqd_pq_doorbell_control 0x%x\n", + m->cp_hqd_pq_doorbell_control); + + m->cp_hqd_eop_control = atc_bit << CP_HQD_EOP_CONTROL__EOP_ATC__SHIFT | + mtype << CP_HQD_EOP_CONTROL__MTYPE__SHIFT; + + m->cp_hqd_ib_control = atc_bit << CP_HQD_IB_CONTROL__IB_ATC__SHIFT | + 3 << CP_HQD_IB_CONTROL__MIN_IB_AVAIL_SIZE__SHIFT | + mtype << CP_HQD_IB_CONTROL__MTYPE__SHIFT; + + m->cp_hqd_eop_control |= + ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1; + m->cp_hqd_eop_base_addr_lo = + lower_32_bits(q->eop_ring_buffer_address >> 8); + m->cp_hqd_eop_base_addr_hi = + upper_32_bits(q->eop_ring_buffer_address >> 8); + + m->cp_hqd_iq_timer = atc_bit << CP_HQD_IQ_TIMER__IQ_ATC__SHIFT | + mtype << CP_HQD_IQ_TIMER__MTYPE__SHIFT; + + m->cp_hqd_vmid = q->vmid; + + if (q->format == KFD_QUEUE_FORMAT_AQL) { + m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__NO_UPDATE_RPTR_MASK | + 2 << CP_HQD_PQ_CONTROL__SLOT_BASED_WPTR__SHIFT; + } + + m->cp_hqd_active = 0; + q->is_active = false; + if (q->queue_size > 0 && + q->queue_address != 0 && + q->queue_percent > 0) { + m->cp_hqd_active = 1; + q->is_active = true; + } + + return 0; +} + + +static int update_mqd(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + return __update_mqd(mm, mqd, q, MTYPE_CC, 1); +} + +static int destroy_mqd(struct mqd_manager *mm, void *mqd, + enum kfd_preempt_type type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id) +{ + return mm->dev->kfd2kgd->hqd_destroy + (mm->dev->kgd, type, timeout, + pipe_id, queue_id); +} + +static void uninit_mqd(struct mqd_manager *mm, void *mqd, + struct kfd_mem_obj *mqd_mem_obj) +{ + BUG_ON(!mm || !mqd); + kfd_gtt_sa_free(mm->dev, mqd_mem_obj); +} + +static bool is_occupied(struct mqd_manager *mm, void *mqd, + uint64_t queue_address, uint32_t pipe_id, + uint32_t queue_id) +{ + return mm->dev->kfd2kgd->hqd_is_occupied( + mm->dev->kgd, queue_address, + pipe_id, queue_id); +} + +static int init_mqd_hiq(struct mqd_manager *mm, void **mqd, + struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, + struct queue_properties *q) +{ + struct vi_mqd *m; + int retval = init_mqd(mm, mqd, mqd_mem_obj, gart_addr, q); + + if (retval != 0) + return retval; + + m = get_mqd(*mqd); + + m->cp_hqd_pq_control |= 1 << CP_HQD_PQ_CONTROL__PRIV_STATE__SHIFT | + 1 << CP_HQD_PQ_CONTROL__KMD_QUEUE__SHIFT; + + return retval; +} + +static int update_mqd_hiq(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + struct vi_mqd *m; + int retval = __update_mqd(mm, mqd, q, MTYPE_UC, 0); + + if (retval != 0) + return retval; + + m = get_mqd(mqd); + m->cp_hqd_vmid = q->vmid; + return retval; +} struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type, - struct kfd_dev *dev) + struct kfd_dev *dev) { - pr_warn("amdkfd: VI MQD is not currently supported\n"); - return NULL; + struct mqd_manager *mqd; + + BUG_ON(!dev); + BUG_ON(type >= KFD_MQD_TYPE_MAX); + + pr_debug("kfd: In func %s\n", __func__); + + mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL); + if (!mqd) + return NULL; + + mqd->dev = dev; + + switch (type) { + case KFD_MQD_TYPE_CP: + case KFD_MQD_TYPE_COMPUTE: + mqd->init_mqd = init_mqd; + mqd->uninit_mqd = uninit_mqd; + mqd->load_mqd = load_mqd; + mqd->update_mqd = update_mqd; + mqd->destroy_mqd = destroy_mqd; + mqd->is_occupied = is_occupied; + break; + case KFD_MQD_TYPE_HIQ: + mqd->init_mqd = init_mqd_hiq; + mqd->uninit_mqd = uninit_mqd; + mqd->load_mqd = load_mqd; + mqd->update_mqd = update_mqd_hiq; + mqd->destroy_mqd = destroy_mqd; + mqd->is_occupied = is_occupied; + break; + case KFD_MQD_TYPE_SDMA: + break; + default: + kfree(mqd); + return NULL; + } + + return mqd; } -- cgit v1.3-6-gb490 From 914bea6329b2cbbb3586a11f90ddf026bef44348 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Mon, 12 Jan 2015 14:28:46 +0200 Subject: drm/amdkfd: Add support for VI in DQM This patch adds support for the VI APU in the DQM module. Most of the functionality of DQM is shared between CI and VI. Therefore, only a handful of functions are required to be in the H/W-specific part of DQM. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- .../drm/amd/amdkfd/kfd_device_queue_manager_vi.c | 103 ++++++++++++++++++++- 1 file changed, 99 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c index 4c15212a3899..44c38e8e54d3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c @@ -22,6 +22,10 @@ */ #include "kfd_device_queue_manager.h" +#include "gca/gfx_8_0_enum.h" +#include "gca/gfx_8_0_sh_mask.h" +#include "gca/gfx_8_0_enum.h" +#include "oss/oss_3_0_sh_mask.h" static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, struct qcm_process_device *qpd, @@ -37,14 +41,40 @@ static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, void device_queue_manager_init_vi(struct device_queue_manager_asic_ops *ops) { - pr_warn("amdkfd: VI DQM is not currently supported\n"); - ops->set_cache_memory_policy = set_cache_memory_policy_vi; ops->register_process = register_process_vi; ops->initialize = initialize_cpsch_vi; ops->init_sdma_vm = init_sdma_vm; } +static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble) +{ + /* In 64-bit mode, we can only control the top 3 bits of the LDS, + * scratch and GPUVM apertures. + * The hardware fills in the remaining 59 bits according to the + * following pattern: + * LDS: X0000000'00000000 - X0000001'00000000 (4GB) + * Scratch: X0000001'00000000 - X0000002'00000000 (4GB) + * GPUVM: Y0010000'00000000 - Y0020000'00000000 (1TB) + * + * (where X/Y is the configurable nybble with the low-bit 0) + * + * LDS and scratch will have the same top nybble programmed in the + * top 3 bits of SH_MEM_BASES.PRIVATE_BASE. + * GPUVM can have a different top nybble programmed in the + * top 3 bits of SH_MEM_BASES.SHARED_BASE. + * We don't bother to support different top nybbles + * for LDS/Scratch and GPUVM. + */ + + BUG_ON((top_address_nybble & 1) || top_address_nybble > 0xE || + top_address_nybble == 0); + + return top_address_nybble << 12 | + (top_address_nybble << 12) << + SH_MEM_BASES__SHARED_BASE__SHIFT; +} + static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, struct qcm_process_device *qpd, enum cache_policy default_policy, @@ -52,18 +82,83 @@ static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, void __user *alternate_aperture_base, uint64_t alternate_aperture_size) { - return false; + uint32_t default_mtype; + uint32_t ape1_mtype; + + default_mtype = (default_policy == cache_policy_coherent) ? + MTYPE_CC : + MTYPE_NC; + + ape1_mtype = (alternate_policy == cache_policy_coherent) ? + MTYPE_CC : + MTYPE_NC; + + qpd->sh_mem_config = (qpd->sh_mem_config & + SH_MEM_CONFIG__ADDRESS_MODE_MASK) | + SH_MEM_ALIGNMENT_MODE_UNALIGNED << + SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT | + default_mtype << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | + ape1_mtype << SH_MEM_CONFIG__APE1_MTYPE__SHIFT | + SH_MEM_CONFIG__PRIVATE_ATC_MASK; + + return true; } static int register_process_vi(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { - return -1; + struct kfd_process_device *pdd; + unsigned int temp; + + BUG_ON(!dqm || !qpd); + + pdd = qpd_to_pdd(qpd); + + /* check if sh_mem_config register already configured */ + if (qpd->sh_mem_config == 0) { + qpd->sh_mem_config = + SH_MEM_ALIGNMENT_MODE_UNALIGNED << + SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT | + MTYPE_CC << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | + MTYPE_CC << SH_MEM_CONFIG__APE1_MTYPE__SHIFT | + SH_MEM_CONFIG__PRIVATE_ATC_MASK; + + qpd->sh_mem_ape1_limit = 0; + qpd->sh_mem_ape1_base = 0; + } + + if (qpd->pqm->process->is_32bit_user_mode) { + temp = get_sh_mem_bases_32(pdd); + qpd->sh_mem_bases = temp << SH_MEM_BASES__SHARED_BASE__SHIFT; + qpd->sh_mem_config |= SH_MEM_ADDRESS_MODE_HSA32 << + SH_MEM_CONFIG__ADDRESS_MODE__SHIFT; + } else { + temp = get_sh_mem_bases_nybble_64(pdd); + qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp); + qpd->sh_mem_config |= SH_MEM_ADDRESS_MODE_HSA64 << + SH_MEM_CONFIG__ADDRESS_MODE__SHIFT; + } + + pr_debug("kfd: is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n", + qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases); + + return 0; } static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd) { + uint32_t value = (1 << SDMA0_RLC0_VIRTUAL_ADDR__ATC__SHIFT); + + if (q->process->is_32bit_user_mode) + value |= (1 << SDMA0_RLC0_VIRTUAL_ADDR__PTR32__SHIFT) | + get_sh_mem_bases_32(qpd_to_pdd(qpd)); + else + value |= ((get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd))) << + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) && + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE_MASK; + + q->properties.sdma_vm_addr = value; } static int initialize_cpsch_vi(struct device_queue_manager *dqm) -- cgit v1.3-6-gb490 From e1940fa4bfa32d86a771e300a3fd116c46878bf4 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Tue, 6 Jan 2015 11:32:13 +0200 Subject: drm/amdkfd: fix runlist length calculation The MAP_QUEUES packet length for Carrizo is different than for Kaveri. Therefore, we now need to calculate the runlist length with regard to the underlying H/W. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c index 99b6d28a11c3..e3230ccc46c7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c @@ -27,6 +27,7 @@ #include "kfd_kernel_queue.h" #include "kfd_priv.h" #include "kfd_pm4_headers.h" +#include "kfd_pm4_headers_vi.h" #include "kfd_pm4_opcodes.h" static inline void inc_wptr(unsigned int *wptr, unsigned int increment_bytes, @@ -55,6 +56,7 @@ static void pm_calc_rlib_size(struct packet_manager *pm, bool *over_subscription) { unsigned int process_count, queue_count; + unsigned int map_queue_size; BUG_ON(!pm || !rlib_size || !over_subscription); @@ -69,9 +71,13 @@ static void pm_calc_rlib_size(struct packet_manager *pm, pr_debug("kfd: over subscribed runlist\n"); } + map_queue_size = + (pm->dqm->dev->device_info->asic_family == CHIP_CARRIZO) ? + sizeof(struct pm4_mes_map_queues) : + sizeof(struct pm4_map_queues); /* calculate run list ib allocation size */ *rlib_size = process_count * sizeof(struct pm4_map_process) + - queue_count * sizeof(struct pm4_map_queues); + queue_count * map_queue_size; /* * Increase the allocation size in case we need a chained run list -- cgit v1.3-6-gb490 From d7b8f73ea03923dbf7c61093743b9eb1842fa8d7 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Tue, 6 Jan 2015 11:35:50 +0200 Subject: drm/amdkfd: Implement create_map_queues() for Carrizo Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c | 91 +++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c index e3230ccc46c7..90f391434fa3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c @@ -182,6 +182,71 @@ static int pm_create_map_process(struct packet_manager *pm, uint32_t *buffer, return 0; } +static int pm_create_map_queue_vi(struct packet_manager *pm, uint32_t *buffer, + struct queue *q, bool is_static) +{ + struct pm4_mes_map_queues *packet; + bool use_static = is_static; + + BUG_ON(!pm || !buffer || !q); + + pr_debug("kfd: In func %s\n", __func__); + + packet = (struct pm4_mes_map_queues *)buffer; + memset(buffer, 0, sizeof(struct pm4_map_queues)); + + packet->header.u32all = build_pm4_header(IT_MAP_QUEUES, + sizeof(struct pm4_map_queues)); + packet->bitfields2.alloc_format = + alloc_format__mes_map_queues__one_per_pipe_vi; + packet->bitfields2.num_queues = 1; + packet->bitfields2.queue_sel = + queue_sel__mes_map_queues__map_to_hws_determined_queue_slots_vi; + + packet->bitfields2.engine_sel = + engine_sel__mes_map_queues__compute_vi; + packet->bitfields2.queue_type = + queue_type__mes_map_queues__normal_compute_vi; + + switch (q->properties.type) { + case KFD_QUEUE_TYPE_COMPUTE: + if (use_static) + packet->bitfields2.queue_type = + queue_type__mes_map_queues__normal_latency_static_queue_vi; + break; + case KFD_QUEUE_TYPE_DIQ: + packet->bitfields2.queue_type = + queue_type__mes_map_queues__debug_interface_queue_vi; + break; + case KFD_QUEUE_TYPE_SDMA: + packet->bitfields2.engine_sel = + engine_sel__mes_map_queues__sdma0_vi; + use_static = false; /* no static queues under SDMA */ + break; + default: + pr_err("kfd: in %s queue type %d\n", __func__, + q->properties.type); + BUG(); + break; + } + packet->bitfields3.doorbell_offset = + q->properties.doorbell_off; + + packet->mqd_addr_lo = + lower_32_bits(q->gart_mqd_addr); + + packet->mqd_addr_hi = + upper_32_bits(q->gart_mqd_addr); + + packet->wptr_addr_lo = + lower_32_bits((uint64_t)q->properties.write_ptr); + + packet->wptr_addr_hi = + upper_32_bits((uint64_t)q->properties.write_ptr); + + return 0; +} + static int pm_create_map_queue(struct packet_manager *pm, uint32_t *buffer, struct queue *q, bool is_static) { @@ -298,8 +363,17 @@ static int pm_create_runlist_ib(struct packet_manager *pm, pr_debug("kfd: static_queue, mapping kernel q %d, is debug status %d\n", kq->queue->queue, qpd->is_debug); - retval = pm_create_map_queue(pm, &rl_buffer[rl_wptr], - kq->queue, qpd->is_debug); + if (pm->dqm->dev->device_info->asic_family == + CHIP_CARRIZO) + retval = pm_create_map_queue_vi(pm, + &rl_buffer[rl_wptr], + kq->queue, + qpd->is_debug); + else + retval = pm_create_map_queue(pm, + &rl_buffer[rl_wptr], + kq->queue, + qpd->is_debug); if (retval != 0) return retval; @@ -315,8 +389,17 @@ static int pm_create_runlist_ib(struct packet_manager *pm, pr_debug("kfd: static_queue, mapping user queue %d, is debug status %d\n", q->queue, qpd->is_debug); - retval = pm_create_map_queue(pm, &rl_buffer[rl_wptr], - q, qpd->is_debug); + if (pm->dqm->dev->device_info->asic_family == + CHIP_CARRIZO) + retval = pm_create_map_queue_vi(pm, + &rl_buffer[rl_wptr], + q, + qpd->is_debug); + else + retval = pm_create_map_queue(pm, + &rl_buffer[rl_wptr], + q, + qpd->is_debug); if (retval != 0) return retval; -- cgit v1.3-6-gb490 From 3d30b28be811b0d7c0a113eab361d5e3029d6da4 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sat, 6 Jun 2015 21:47:01 +0300 Subject: drm/amdkfd: Use generic defines in new amd headers This patch makes use of the new amd headers (that are part of the new amdgpu driver), instead of private defines. Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/cik_regs.h | 11 ----------- .../drm/amd/amdkfd/kfd_device_queue_manager_cik.c | 12 ++++++++---- drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c | 20 +++++++++++++------- 3 files changed, 21 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/cik_regs.h b/drivers/gpu/drm/amd/amdkfd/cik_regs.h index 183be5b8414f..48769d12dd7b 100644 --- a/drivers/gpu/drm/amd/amdkfd/cik_regs.h +++ b/drivers/gpu/drm/amd/amdkfd/cik_regs.h @@ -65,17 +65,6 @@ #define AQL_ENABLE 1 -#define SDMA_RB_VMID(x) (x << 24) -#define SDMA_RB_ENABLE (1 << 0) -#define SDMA_RB_SIZE(x) ((x) << 1) /* log2 */ -#define SDMA_RPTR_WRITEBACK_ENABLE (1 << 12) -#define SDMA_RPTR_WRITEBACK_TIMER(x) ((x) << 16) /* log2 */ -#define SDMA_OFFSET(x) (x << 0) -#define SDMA_DB_ENABLE (1 << 28) -#define SDMA_ATC (1 << 0) -#define SDMA_VA_PTR32 (1 << 4) -#define SDMA_VA_SHARED_BASE(x) (x << 8) - #define GRBM_GFX_INDEX 0x30800 #define ATC_VMID_PASID_MAPPING_VALID (1U << 31) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c index 9ce8a20a7aff..23ce774ff09d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c @@ -23,6 +23,7 @@ #include "kfd_device_queue_manager.h" #include "cik_regs.h" +#include "oss/oss_2_4_sh_mask.h" static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm, struct qcm_process_device *qpd, @@ -135,13 +136,16 @@ static int register_process_cik(struct device_queue_manager *dqm, static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd) { - uint32_t value = SDMA_ATC; + uint32_t value = (1 << SDMA0_RLC0_VIRTUAL_ADDR__ATC__SHIFT); if (q->process->is_32bit_user_mode) - value |= SDMA_VA_PTR32 | get_sh_mem_bases_32(qpd_to_pdd(qpd)); + value |= (1 << SDMA0_RLC0_VIRTUAL_ADDR__PTR32__SHIFT) | + get_sh_mem_bases_32(qpd_to_pdd(qpd)); else - value |= SDMA_VA_SHARED_BASE(get_sh_mem_bases_nybble_64( - qpd_to_pdd(qpd))); + value |= ((get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd))) << + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) && + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE_MASK; + q->properties.sdma_vm_addr = value; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index 434979428fc0..d83de985e88c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -27,6 +27,7 @@ #include "kfd_mqd_manager.h" #include "cik_regs.h" #include "cik_structs.h" +#include "oss/oss_2_4_sh_mask.h" static inline struct cik_mqd *get_mqd(void *mqd) { @@ -214,17 +215,20 @@ static int update_mqd_sdma(struct mqd_manager *mm, void *mqd, BUG_ON(!mm || !mqd || !q); m = get_sdma_mqd(mqd); - m->sdma_rlc_rb_cntl = - SDMA_RB_SIZE((ffs(q->queue_size / sizeof(unsigned int)))) | - SDMA_RB_VMID(q->vmid) | - SDMA_RPTR_WRITEBACK_ENABLE | - SDMA_RPTR_WRITEBACK_TIMER(6); + m->sdma_rlc_rb_cntl = ffs(q->queue_size / sizeof(unsigned int)) << + SDMA0_RLC0_RB_CNTL__RB_SIZE__SHIFT | + q->vmid << SDMA0_RLC0_RB_CNTL__RB_VMID__SHIFT | + 1 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_ENABLE__SHIFT | + 6 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_TIMER__SHIFT; m->sdma_rlc_rb_base = lower_32_bits(q->queue_address >> 8); m->sdma_rlc_rb_base_hi = upper_32_bits(q->queue_address >> 8); m->sdma_rlc_rb_rptr_addr_lo = lower_32_bits((uint64_t)q->read_ptr); m->sdma_rlc_rb_rptr_addr_hi = upper_32_bits((uint64_t)q->read_ptr); - m->sdma_rlc_doorbell = SDMA_OFFSET(q->doorbell_off) | SDMA_DB_ENABLE; + m->sdma_rlc_doorbell = q->doorbell_off << + SDMA0_RLC0_DOORBELL__OFFSET__SHIFT | + 1 << SDMA0_RLC0_DOORBELL__ENABLE__SHIFT; + m->sdma_rlc_virtual_addr = q->sdma_vm_addr; m->sdma_engine_id = q->sdma_engine_id; @@ -234,7 +238,9 @@ static int update_mqd_sdma(struct mqd_manager *mm, void *mqd, if (q->queue_size > 0 && q->queue_address != 0 && q->queue_percent > 0) { - m->sdma_rlc_rb_cntl |= SDMA_RB_ENABLE; + m->sdma_rlc_rb_cntl |= + 1 << SDMA0_RLC0_RB_CNTL__RB_ENABLE__SHIFT; + q->is_active = true; } -- cgit v1.3-6-gb490 From 7639a8c420f04ca9be87974416efb2848b0962d9 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Sun, 7 Jun 2015 00:15:51 +0300 Subject: drm/amdkfd: Set correct doorbell packet type for Carrizo Signed-off-by: Ben Goz Reviewed-by: Yair Shachar Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 5 +++++ drivers/gpu/drm/amd/amdkfd/kfd_topology.h | 1 + 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index c25728bc388a..74909e72a009 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1186,6 +1186,11 @@ int kfd_topology_add_device(struct kfd_dev *gpu) * TODO: Retrieve max engine clock values from KGD */ + if (dev->gpu->device_info->asic_family == CHIP_CARRIZO) { + dev->node_props.capability |= HSA_CAP_DOORBELL_PACKET_TYPE; + pr_info("amdkfd: adding doorbell packet type capability\n"); + } + res = 0; err: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h index 989624b3cd14..c3ddb9b95ff8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h @@ -40,6 +40,7 @@ #define HSA_CAP_WATCH_POINTS_TOTALBITS_MASK 0x00000f00 #define HSA_CAP_WATCH_POINTS_TOTALBITS_SHIFT 8 #define HSA_CAP_RESERVED 0xfffff000 +#define HSA_CAP_DOORBELL_PACKET_TYPE 0x00001000 struct kfd_node_properties { uint32_t cpu_cores_count; -- cgit v1.3-6-gb490 From 5c31252c4a86dc591c23f1a951edd52ad791ef0e Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Jul 2015 10:21:47 +0200 Subject: pwm: Add the pwm_is_enabled() helper Some PWM drivers are testing the PWMF_ENABLED flag. Create a helper function to hide the logic behind enabled test. This will allow us to smoothly move from the current approach to an atomic PWM update approach. Signed-off-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 4 ++-- drivers/pwm/pwm-atmel-tcb.c | 2 +- drivers/pwm/pwm-atmel.c | 6 +++--- drivers/pwm/pwm-bcm-kona.c | 4 ++-- drivers/pwm/pwm-ep93xx.c | 4 ++-- drivers/pwm/pwm-imx.c | 2 +- drivers/pwm/pwm-mxs.c | 4 ++-- drivers/pwm/pwm-renesas-tpu.c | 2 +- drivers/pwm/pwm-tegra.c | 6 +++--- drivers/pwm/pwm-tiecap.c | 10 +++++----- drivers/pwm/pwm-tiehrpwm.c | 6 +++--- drivers/pwm/sysfs.c | 2 +- include/linux/pwm.h | 5 +++++ 13 files changed, 31 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 3a7769fe53de..f7c11d2dec37 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -455,7 +455,7 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity) if (!pwm->chip->ops->set_polarity) return -ENOSYS; - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) return -EBUSY; err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity); @@ -853,7 +853,7 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) if (test_bit(PWMF_REQUESTED, &pwm->flags)) seq_puts(s, " requested"); - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) seq_puts(s, " enabled"); seq_puts(s, "\n"); diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index d14e0677c92d..6da01b3bf6f4 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -347,7 +347,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, tcbpwm->duty = duty; /* If the PWM is enabled, call enable to apply the new conf */ - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) atmel_tcb_pwm_enable(chip, pwm); return 0; diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index a947c9095d9d..b3b294de88e0 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -114,7 +114,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, u32 val; int ret; - if (test_bit(PWMF_ENABLED, &pwm->flags) && (period_ns != pwm->period)) { + if (pwm_is_enabled(pwm) && (period_ns != pwm->period)) { dev_err(chip->dev, "cannot change PWM period while enabled\n"); return -EBUSY; } @@ -176,7 +176,7 @@ static void atmel_pwm_config_v1(struct pwm_chip *chip, struct pwm_device *pwm, * If the PWM channel is enabled, only update CDTY by using the update * register, it needs to set bit 10 of CMR to 0 */ - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) return; /* * If the PWM channel is disabled, write value to duty and period @@ -191,7 +191,7 @@ static void atmel_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm, { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); - if (test_bit(PWMF_ENABLED, &pwm->flags)) { + if (pwm_is_enabled(pwm)) { /* * If the PWM channel is enabled, using the duty update register * to update the value. diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c index 7af8fea2dc5b..dfdcf88279ae 100644 --- a/drivers/pwm/pwm-bcm-kona.c +++ b/drivers/pwm/pwm-bcm-kona.c @@ -134,7 +134,7 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm, } /* If the PWM channel is enabled, write the settings to the HW */ - if (test_bit(PWMF_ENABLED, &pwm->flags)) { + if (pwm_is_enabled(pwm)) { value = readl(kp->base + PRESCALE_OFFSET); value &= ~PRESCALE_MASK(chan); value |= prescale << PRESCALE_SHIFT(chan); @@ -287,7 +287,7 @@ static int kona_pwmc_remove(struct platform_device *pdev) unsigned int chan; for (chan = 0; chan < kp->chip.npwm; chan++) - if (test_bit(PWMF_ENABLED, &kp->chip.pwms[chan].flags)) + if (pwm_is_enabled(&kp->chip.pwms[chan])) clk_disable_unprepare(kp->clk); return pwmchip_remove(&kp->chip); diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c index e593e9c45c51..bbf10ae02f0e 100644 --- a/drivers/pwm/pwm-ep93xx.c +++ b/drivers/pwm/pwm-ep93xx.c @@ -82,7 +82,7 @@ static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * The clock needs to be enabled to access the PWM registers. * Configuration can be changed at any time. */ - if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + if (!pwm_is_enabled(pwm)) { ret = clk_enable(ep93xx_pwm->clk); if (ret) return ret; @@ -113,7 +113,7 @@ static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ret = -EINVAL; } - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) clk_disable(ep93xx_pwm->clk); return ret; diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 66d6f0c5c421..008dc646225e 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -114,7 +114,7 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, unsigned long long c; unsigned long period_cycles, duty_cycles, prescale; unsigned int period_ms; - bool enable = test_bit(PWMF_ENABLED, &pwm->flags); + bool enable = pwm_is_enabled(pwm); int wait_count = 0, fifoav; u32 cr, sr; diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index b430811e14f5..9a596324ebef 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -77,7 +77,7 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * If the PWM channel is disabled, make sure to turn on the clock * before writing the register. Otherwise, keep it enabled. */ - if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + if (!pwm_is_enabled(pwm)) { ret = clk_prepare_enable(mxs->clk); if (ret) return ret; @@ -92,7 +92,7 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, /* * If the PWM is not enabled, turn the clock off again to save power. */ - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) clk_disable_unprepare(mxs->clk); return 0; diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c index ee63f9e9d0fb..075c1a764ba2 100644 --- a/drivers/pwm/pwm-renesas-tpu.c +++ b/drivers/pwm/pwm-renesas-tpu.c @@ -301,7 +301,7 @@ static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm, pwm->duty = duty; /* If the channel is disabled we're done. */ - if (!test_bit(PWMF_ENABLED, &_pwm->flags)) + if (!pwm_is_enabled(_pwm)) return 0; if (duty_only && pwm->timer_on) { diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index cabd7d8e05cc..d4de0607b502 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -112,7 +112,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * If the PWM channel is disabled, make sure to turn on the clock * before writing the register. Otherwise, keep it enabled. */ - if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + if (!pwm_is_enabled(pwm)) { err = clk_prepare_enable(pc->clk); if (err < 0) return err; @@ -124,7 +124,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, /* * If the PWM is not enabled, turn the clock off again to save power. */ - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) clk_disable_unprepare(pc->clk); return 0; @@ -214,7 +214,7 @@ static int tegra_pwm_remove(struct platform_device *pdev) for (i = 0; i < NUM_PWM; i++) { struct pwm_device *pwm = &pc->chip.pwms[i]; - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) if (clk_prepare_enable(pc->clk) < 0) continue; diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index e557befdf4e6..616af764a276 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -97,7 +97,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, writew(reg_val, pc->mmio_base + ECCTL2); - if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + if (!pwm_is_enabled(pwm)) { /* Update active registers if not running */ writel(duty_cycles, pc->mmio_base + CAP2); writel(period_cycles, pc->mmio_base + CAP1); @@ -111,7 +111,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, writel(period_cycles, pc->mmio_base + CAP3); } - if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + if (!pwm_is_enabled(pwm)) { reg_val = readw(pc->mmio_base + ECCTL2); /* Disable APWM mode to put APWM output Low */ reg_val &= ~ECCTL2_APWM_MODE; @@ -179,7 +179,7 @@ static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { - if (test_bit(PWMF_ENABLED, &pwm->flags)) { + if (pwm_is_enabled(pwm)) { dev_warn(chip->dev, "Removing PWM device without disabling\n"); pm_runtime_put_sync(chip->dev); } @@ -306,7 +306,7 @@ static int ecap_pwm_suspend(struct device *dev) ecap_pwm_save_context(pc); /* Disable explicitly if PWM is running */ - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) pm_runtime_put_sync(dev); return 0; @@ -318,7 +318,7 @@ static int ecap_pwm_resume(struct device *dev) struct pwm_device *pwm = pc->chip.pwms; /* Enable explicitly if PWM was running */ - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) pm_runtime_get_sync(dev); ecap_pwm_restore_context(pc); diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 694b3cf7694b..6a41e66015b6 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -407,7 +407,7 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); - if (test_bit(PWMF_ENABLED, &pwm->flags)) { + if (pwm_is_enabled(pwm)) { dev_warn(chip->dev, "Removing PWM device without disabling\n"); pm_runtime_put_sync(chip->dev); } @@ -565,7 +565,7 @@ static int ehrpwm_pwm_suspend(struct device *dev) for (i = 0; i < pc->chip.npwm; i++) { struct pwm_device *pwm = &pc->chip.pwms[i]; - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) continue; /* Disable explicitly if PWM is running */ @@ -582,7 +582,7 @@ static int ehrpwm_pwm_resume(struct device *dev) for (i = 0; i < pc->chip.npwm; i++) { struct pwm_device *pwm = &pc->chip.pwms[i]; - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) continue; /* Enable explicitly if PWM was running */ diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index 4bd0c639e16d..eecf21d68108 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -97,7 +97,7 @@ static ssize_t pwm_enable_show(struct device *child, char *buf) { const struct pwm_device *pwm = child_to_pwm_device(child); - int enabled = test_bit(PWMF_ENABLED, &pwm->flags); + int enabled = pwm_is_enabled(pwm); return sprintf(buf, "%d\n", enabled); } diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 36262d08a9da..ec34f4d9a9ee 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -92,6 +92,11 @@ struct pwm_device { enum pwm_polarity polarity; }; +static inline bool pwm_is_enabled(const struct pwm_device *pwm) +{ + return test_bit(PWMF_ENABLED, &pwm->flags); +} + static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period) { if (pwm) -- cgit v1.3-6-gb490 From 15da7b5001e498fa7dc619d4d7951f9665b071e4 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Jul 2015 10:21:50 +0200 Subject: pwm: Make use of pwm_get_xxx() helpers where appropriate Use the pwm_get_xxx() helpers instead of directly accessing the fields in struct pwm_device. This will allow us to smoothly move to the atomic update approach. Signed-off-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel.c | 2 +- drivers/pwm/pwm-bcm-kona.c | 3 ++- drivers/pwm/pwm-imx.c | 3 ++- drivers/pwm/pwm-rockchip.c | 2 +- drivers/pwm/sysfs.c | 11 ++++++----- 5 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index b3b294de88e0..0e4bd4e8e582 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -114,7 +114,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, u32 val; int ret; - if (pwm_is_enabled(pwm) && (period_ns != pwm->period)) { + if (pwm_is_enabled(pwm) && (period_ns != pwm_get_period(pwm))) { dev_err(chip->dev, "cannot change PWM period while enabled\n"); return -EBUSY; } diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c index dfdcf88279ae..920cd1b5aa9d 100644 --- a/drivers/pwm/pwm-bcm-kona.c +++ b/drivers/pwm/pwm-bcm-kona.c @@ -194,7 +194,8 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm) return ret; } - ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period); + ret = kona_pwmc_config(chip, pwm, pwm_get_duty_cycle(pwm), + pwm_get_period(pwm)); if (ret < 0) { clk_disable_unprepare(kp->clk); return ret; diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 008dc646225e..d600fd5cd4ba 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -129,7 +129,8 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, sr = readl(imx->mmio_base + MX3_PWMSR); fifoav = sr & MX3_PWMSR_FIFOAV_MASK; if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) { - period_ms = DIV_ROUND_UP(pwm->period, NSEC_PER_MSEC); + period_ms = DIV_ROUND_UP(pwm_get_period(pwm), + NSEC_PER_MSEC); msleep(period_ms); sr = readl(imx->mmio_base + MX3_PWMSR); diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 9442df244101..7d9cc9049522 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -83,7 +83,7 @@ static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, PWM_CONTINUOUS; u32 val; - if (pwm->polarity == PWM_POLARITY_INVERSED) + if (pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED) enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE; else enable_conf |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE; diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index eecf21d68108..ac0abecfbaa0 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -46,7 +46,7 @@ static ssize_t pwm_period_show(struct device *child, { const struct pwm_device *pwm = child_to_pwm_device(child); - return sprintf(buf, "%u\n", pwm->period); + return sprintf(buf, "%u\n", pwm_get_period(pwm)); } static ssize_t pwm_period_store(struct device *child, @@ -61,7 +61,7 @@ static ssize_t pwm_period_store(struct device *child, if (ret) return ret; - ret = pwm_config(pwm, pwm->duty_cycle, val); + ret = pwm_config(pwm, pwm_get_duty_cycle(pwm), val); return ret ? : size; } @@ -72,7 +72,7 @@ static ssize_t pwm_duty_cycle_show(struct device *child, { const struct pwm_device *pwm = child_to_pwm_device(child); - return sprintf(buf, "%u\n", pwm->duty_cycle); + return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm)); } static ssize_t pwm_duty_cycle_store(struct device *child, @@ -87,7 +87,7 @@ static ssize_t pwm_duty_cycle_store(struct device *child, if (ret) return ret; - ret = pwm_config(pwm, val, pwm->period); + ret = pwm_config(pwm, val, pwm_get_period(pwm)); return ret ? : size; } @@ -134,7 +134,8 @@ static ssize_t pwm_polarity_show(struct device *child, { const struct pwm_device *pwm = child_to_pwm_device(child); - return sprintf(buf, "%s\n", pwm->polarity ? "inversed" : "normal"); + return sprintf(buf, "%s\n", + pwm_get_polarity(pwm) ? "inversed" : "normal"); } static ssize_t pwm_polarity_store(struct device *child, -- cgit v1.3-6-gb490 From e27513eb61bae759b7d5f340cf39d60f0d15a00b Mon Sep 17 00:00:00 2001 From: Alex Porosanu Date: Fri, 17 Jul 2015 16:54:51 +0300 Subject: crypto: caam - fix ERA property reading In order to ensure that the ERA property is properly read from DT on all platforms, of_property_read* function needs to be used. Signed-off-by: Alex Porosanu Signed-off-by: Horia Geant? Signed-off-by: Herbert Xu --- drivers/crypto/caam/ctrl.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index efacab7539ef..598823746a3b 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -370,14 +370,14 @@ static void kick_trng(struct platform_device *pdev, int ent_delay) int caam_get_era(void) { 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; - } + int ret; + u32 prop; + + caam_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); + ret = of_property_read_u32(caam_node, "fsl,sec-era", &prop); + of_node_put(caam_node); - return -ENOTSUPP; + return IS_ERR_VALUE(ret) ? -ENOTSUPP : prop; } EXPORT_SYMBOL(caam_get_era); -- cgit v1.3-6-gb490 From f109674951440912b645de2761d5d851e261af98 Mon Sep 17 00:00:00 2001 From: Horia Geant? Date: Fri, 17 Jul 2015 16:54:52 +0300 Subject: crypto: caam - fix snooping for write transactions HW coherency won't work properly for CAAM write transactions if AWCACHE is left to default (POR) value - 4'b0001. It has to be programmed to 4'b0010, i.e. AXI3 Cacheable bit set. For platforms that have HW coherency support: -PPC-based: the update has no effect; CAAM coherency already works due to the IOMMU (PAMU) driver setting the correct memory coherency attributes -ARM-based: the update fixes cache coherency issues, since IOMMU (SMMU) driver is not programmed to behave similar to PAMU Signed-off-by: Horia Geant? Signed-off-by: Herbert Xu --- drivers/crypto/caam/ctrl.c | 5 +++-- drivers/crypto/caam/regs.h | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 598823746a3b..b924477c0d83 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -444,8 +444,9 @@ static int caam_probe(struct platform_device *pdev) * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, * long pointers in master configuration register */ - setbits32(&ctrl->mcr, MCFGR_WDENABLE | - (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0)); + clrsetbits_be32(&ctrl->mcr, MCFGR_AWCACHE_MASK, MCFGR_AWCACHE_CACH | + MCFGR_WDENABLE | (sizeof(dma_addr_t) == sizeof(u64) ? + MCFGR_LONG_PTR : 0)); /* * Read the Compile Time paramters and SCFGR to determine diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h index 672c97489505..5e643523de15 100644 --- a/drivers/crypto/caam/regs.h +++ b/drivers/crypto/caam/regs.h @@ -395,10 +395,16 @@ struct caam_ctrl { /* AXI read cache control */ #define MCFGR_ARCACHE_SHIFT 12 #define MCFGR_ARCACHE_MASK (0xf << MCFGR_ARCACHE_SHIFT) +#define MCFGR_ARCACHE_BUFF (0x1 << MCFGR_ARCACHE_SHIFT) +#define MCFGR_ARCACHE_CACH (0x2 << MCFGR_ARCACHE_SHIFT) +#define MCFGR_ARCACHE_RALL (0x4 << MCFGR_ARCACHE_SHIFT) /* AXI write cache control */ #define MCFGR_AWCACHE_SHIFT 8 #define MCFGR_AWCACHE_MASK (0xf << MCFGR_AWCACHE_SHIFT) +#define MCFGR_AWCACHE_BUFF (0x1 << MCFGR_AWCACHE_SHIFT) +#define MCFGR_AWCACHE_CACH (0x2 << MCFGR_AWCACHE_SHIFT) +#define MCFGR_AWCACHE_WALL (0x8 << MCFGR_AWCACHE_SHIFT) /* AXI pipeline depth */ #define MCFGR_AXIPIPE_SHIFT 4 -- cgit v1.3-6-gb490 From 62743a4145bb9c3fe090a48e10ddc0ebae85bfbf Mon Sep 17 00:00:00 2001 From: Horia Geant? Date: Fri, 17 Jul 2015 16:54:53 +0300 Subject: crypto: caam - fix RNG init descriptor ret. code checking When successful, the descriptor that performs RNG initialization is allowed to return a status code of 7000_0000h, since last command in the descriptor is a JUMP HALT. Signed-off-by: Horia Geant? Signed-off-by: Herbert Xu --- drivers/crypto/caam/ctrl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index b924477c0d83..189180976167 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -175,7 +175,7 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask, { struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev); struct caam_ctrl __iomem *ctrl; - u32 *desc, status, rdsta_val; + u32 *desc, status = 0, rdsta_val; int ret = 0, sh_idx; ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; @@ -207,7 +207,8 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask, * CAAM eras), then try again. */ rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK; - if (status || !(rdsta_val & (1 << sh_idx))) + if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) || + !(rdsta_val & (1 << sh_idx))) ret = -EAGAIN; if (ret) break; -- cgit v1.3-6-gb490 From c1f2cd21ed5335bfcf5dd1d3a05a2a83bae14c3a Mon Sep 17 00:00:00 2001 From: Tudor Ambarus Date: Fri, 17 Jul 2015 16:54:54 +0300 Subject: crypto: caam - fix warning in APPEND_MATH_IMM_u64 An implicit truncation is done when using a variable of 64 bits in MATH command: warning: large integer implicitly truncated to unsigned type [-Woverflow] Silence the compiler by feeding it with an explicit truncated value. Signed-off-by: Tudor Ambarus Signed-off-by: Horia Geant? Signed-off-by: Herbert Xu --- drivers/crypto/caam/desc_constr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h index 9f79fd7bd4d7..98d07de24fc4 100644 --- a/drivers/crypto/caam/desc_constr.h +++ b/drivers/crypto/caam/desc_constr.h @@ -367,7 +367,7 @@ do { \ if (upper) \ append_u64(desc, data); \ else \ - append_u32(desc, data); \ + append_u32(desc, lower_32_bits(data)); \ } while (0) #define append_math_add_imm_u64(desc, dest, src0, src1, data) \ -- cgit v1.3-6-gb490 From 6298e948215f2a3eb8a9af5c490d025deb66f179 Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Fri, 17 Jul 2015 16:39:41 +0200 Subject: crypto: sunxi-ss - Add Allwinner Security System crypto accelerator Add support for the Security System included in Allwinner SoC A20. The Security System is a hardware cryptographic accelerator that support: - MD5 and SHA1 hash algorithms - AES block cipher in CBC/ECB mode with 128/196/256bits keys. - DES and 3DES block cipher in CBC/ECB mode Signed-off-by: LABBE Corentin Signed-off-by: Herbert Xu --- drivers/crypto/Kconfig | 17 + drivers/crypto/Makefile | 1 + drivers/crypto/sunxi-ss/Makefile | 2 + drivers/crypto/sunxi-ss/sun4i-ss-cipher.c | 542 ++++++++++++++++++++++++++++++ drivers/crypto/sunxi-ss/sun4i-ss-core.c | 403 ++++++++++++++++++++++ drivers/crypto/sunxi-ss/sun4i-ss-hash.c | 492 +++++++++++++++++++++++++++ drivers/crypto/sunxi-ss/sun4i-ss.h | 199 +++++++++++ 7 files changed, 1656 insertions(+) create mode 100644 drivers/crypto/sunxi-ss/Makefile create mode 100644 drivers/crypto/sunxi-ss/sun4i-ss-cipher.c create mode 100644 drivers/crypto/sunxi-ss/sun4i-ss-core.c create mode 100644 drivers/crypto/sunxi-ss/sun4i-ss-hash.c create mode 100644 drivers/crypto/sunxi-ss/sun4i-ss.h (limited to 'drivers') diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 4044125fb5d5..07bc7aa6b224 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -480,4 +480,21 @@ config CRYPTO_DEV_IMGTEC_HASH hardware hash accelerator. Supporting MD5/SHA1/SHA224/SHA256 hashing algorithms. +config CRYPTO_DEV_SUN4I_SS + tristate "Support for Allwinner Security System cryptographic accelerator" + depends on ARCH_SUNXI + select CRYPTO_MD5 + select CRYPTO_SHA1 + select CRYPTO_AES + select CRYPTO_DES + select CRYPTO_BLKCIPHER + help + Some Allwinner SoC have a crypto accelerator named + Security System. Select this if you want to use it. + The Security System handle AES/DES/3DES ciphers in CBC mode + and SHA1 and MD5 hash algorithms. + + To compile this driver as a module, choose M here: the module + will be called sun4i-ss. + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index e35c07a8da85..c3ced6fbd1b8 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -28,3 +28,4 @@ obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/ obj-$(CONFIG_CRYPTO_DEV_QAT) += qat/ obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/ obj-$(CONFIG_CRYPTO_DEV_VMX) += vmx/ +obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sunxi-ss/ diff --git a/drivers/crypto/sunxi-ss/Makefile b/drivers/crypto/sunxi-ss/Makefile new file mode 100644 index 000000000000..8f4c7a273141 --- /dev/null +++ b/drivers/crypto/sunxi-ss/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sun4i-ss.o +sun4i-ss-y += sun4i-ss-core.o sun4i-ss-hash.o sun4i-ss-cipher.o diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c new file mode 100644 index 000000000000..e070c316e8b7 --- /dev/null +++ b/drivers/crypto/sunxi-ss/sun4i-ss-cipher.c @@ -0,0 +1,542 @@ +/* + * sun4i-ss-cipher.c - hardware cryptographic accelerator for Allwinner A20 SoC + * + * Copyright (C) 2013-2015 Corentin LABBE + * + * This file add support for AES cipher with 128,192,256 bits + * keysize in CBC and ECB mode. + * Add support also for DES and 3DES in CBC and ECB mode. + * + * You could find the datasheet in Documentation/arm/sunxi/README + * + * 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 "sun4i-ss.h" + +static int sun4i_ss_opti_poll(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_ss_ctx *ss = op->ss; + unsigned int ivsize = crypto_ablkcipher_ivsize(tfm); + struct sun4i_cipher_req_ctx *ctx = ablkcipher_request_ctx(areq); + u32 mode = ctx->mode; + /* when activating SS, the default FIFO space is SS_RX_DEFAULT(32) */ + u32 rx_cnt = SS_RX_DEFAULT; + u32 tx_cnt = 0; + u32 spaces; + u32 v; + int i, err = 0; + unsigned int ileft = areq->nbytes; + unsigned int oleft = areq->nbytes; + unsigned int todo; + struct sg_mapping_iter mi, mo; + unsigned int oi, oo; /* offset for in and out */ + + if (areq->nbytes == 0) + return 0; + + if (!areq->info) { + dev_err_ratelimited(ss->dev, "ERROR: Empty IV\n"); + return -EINVAL; + } + + if (!areq->src || !areq->dst) { + dev_err_ratelimited(ss->dev, "ERROR: Some SGs are NULL\n"); + return -EINVAL; + } + + spin_lock_bh(&ss->slock); + + for (i = 0; i < op->keylen; i += 4) + writel(*(op->key + i / 4), ss->base + SS_KEY0 + i); + + if (areq->info) { + for (i = 0; i < 4 && i < ivsize / 4; i++) { + v = *(u32 *)(areq->info + i * 4); + writel(v, ss->base + SS_IV0 + i * 4); + } + } + writel(mode, ss->base + SS_CTL); + + sg_miter_start(&mi, areq->src, sg_nents(areq->src), + SG_MITER_FROM_SG | SG_MITER_ATOMIC); + sg_miter_start(&mo, areq->dst, sg_nents(areq->dst), + SG_MITER_TO_SG | SG_MITER_ATOMIC); + sg_miter_next(&mi); + sg_miter_next(&mo); + if (!mi.addr || !mo.addr) { + dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n"); + err = -EINVAL; + goto release_ss; + } + + ileft = areq->nbytes / 4; + oleft = areq->nbytes / 4; + oi = 0; + oo = 0; + do { + todo = min3(rx_cnt, ileft, (mi.length - oi) / 4); + if (todo > 0) { + ileft -= todo; + writesl(ss->base + SS_RXFIFO, mi.addr + oi, todo); + oi += todo * 4; + } + if (oi == mi.length) { + sg_miter_next(&mi); + oi = 0; + } + + spaces = readl(ss->base + SS_FCSR); + rx_cnt = SS_RXFIFO_SPACES(spaces); + tx_cnt = SS_TXFIFO_SPACES(spaces); + + todo = min3(tx_cnt, oleft, (mo.length - oo) / 4); + if (todo > 0) { + oleft -= todo; + readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo); + oo += todo * 4; + } + if (oo == mo.length) { + sg_miter_next(&mo); + oo = 0; + } + } while (mo.length > 0); + + if (areq->info) { + for (i = 0; i < 4 && i < ivsize / 4; i++) { + v = readl(ss->base + SS_IV0 + i * 4); + *(u32 *)(areq->info + i * 4) = v; + } + } + +release_ss: + sg_miter_stop(&mi); + sg_miter_stop(&mo); + writel(0, ss->base + SS_CTL); + spin_unlock_bh(&ss->slock); + return err; +} + +/* Generic function that support SG with size not multiple of 4 */ +static int sun4i_ss_cipher_poll(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_ss_ctx *ss = op->ss; + int no_chunk = 1; + struct scatterlist *in_sg = areq->src; + struct scatterlist *out_sg = areq->dst; + unsigned int ivsize = crypto_ablkcipher_ivsize(tfm); + struct sun4i_cipher_req_ctx *ctx = ablkcipher_request_ctx(areq); + u32 mode = ctx->mode; + /* when activating SS, the default FIFO space is SS_RX_DEFAULT(32) */ + u32 rx_cnt = SS_RX_DEFAULT; + u32 tx_cnt = 0; + u32 v; + u32 spaces; + int i, err = 0; + unsigned int ileft = areq->nbytes; + unsigned int oleft = areq->nbytes; + unsigned int todo; + struct sg_mapping_iter mi, mo; + unsigned int oi, oo; /* offset for in and out */ + char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */ + char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */ + unsigned int ob = 0; /* offset in buf */ + unsigned int obo = 0; /* offset in bufo*/ + unsigned int obl = 0; /* length of data in bufo */ + + if (areq->nbytes == 0) + return 0; + + if (!areq->info) { + dev_err_ratelimited(ss->dev, "ERROR: Empty IV\n"); + return -EINVAL; + } + + if (!areq->src || !areq->dst) { + dev_err_ratelimited(ss->dev, "ERROR: Some SGs are NULL\n"); + return -EINVAL; + } + + /* + * if we have only SGs with size multiple of 4, + * we can use the SS optimized function + */ + while (in_sg && no_chunk == 1) { + if ((in_sg->length % 4) != 0) + no_chunk = 0; + in_sg = sg_next(in_sg); + } + while (out_sg && no_chunk == 1) { + if ((out_sg->length % 4) != 0) + no_chunk = 0; + out_sg = sg_next(out_sg); + } + + if (no_chunk == 1) + return sun4i_ss_opti_poll(areq); + + spin_lock_bh(&ss->slock); + + for (i = 0; i < op->keylen; i += 4) + writel(*(op->key + i / 4), ss->base + SS_KEY0 + i); + + if (areq->info) { + for (i = 0; i < 4 && i < ivsize / 4; i++) { + v = *(u32 *)(areq->info + i * 4); + writel(v, ss->base + SS_IV0 + i * 4); + } + } + writel(mode, ss->base + SS_CTL); + + sg_miter_start(&mi, areq->src, sg_nents(areq->src), + SG_MITER_FROM_SG | SG_MITER_ATOMIC); + sg_miter_start(&mo, areq->dst, sg_nents(areq->dst), + SG_MITER_TO_SG | SG_MITER_ATOMIC); + sg_miter_next(&mi); + sg_miter_next(&mo); + if (!mi.addr || !mo.addr) { + dev_err_ratelimited(ss->dev, "ERROR: sg_miter return null\n"); + err = -EINVAL; + goto release_ss; + } + ileft = areq->nbytes; + oleft = areq->nbytes; + oi = 0; + oo = 0; + + while (oleft > 0) { + if (ileft > 0) { + /* + * todo is the number of consecutive 4byte word that we + * can read from current SG + */ + todo = min3(rx_cnt, ileft / 4, (mi.length - oi) / 4); + if (todo > 0 && ob == 0) { + writesl(ss->base + SS_RXFIFO, mi.addr + oi, + todo); + ileft -= todo * 4; + oi += todo * 4; + } else { + /* + * not enough consecutive bytes, so we need to + * linearize in buf. todo is in bytes + * After that copy, if we have a multiple of 4 + * we need to be able to write all buf in one + * pass, so it is why we min() with rx_cnt + */ + todo = min3(rx_cnt * 4 - ob, ileft, + mi.length - oi); + memcpy(buf + ob, mi.addr + oi, todo); + ileft -= todo; + oi += todo; + ob += todo; + if (ob % 4 == 0) { + writesl(ss->base + SS_RXFIFO, buf, + ob / 4); + ob = 0; + } + } + if (oi == mi.length) { + sg_miter_next(&mi); + oi = 0; + } + } + + spaces = readl(ss->base + SS_FCSR); + rx_cnt = SS_RXFIFO_SPACES(spaces); + tx_cnt = SS_TXFIFO_SPACES(spaces); + dev_dbg(ss->dev, "%x %u/%u %u/%u cnt=%u %u/%u %u/%u cnt=%u %u %u\n", + mode, + oi, mi.length, ileft, areq->nbytes, rx_cnt, + oo, mo.length, oleft, areq->nbytes, tx_cnt, + todo, ob); + + if (tx_cnt == 0) + continue; + /* todo in 4bytes word */ + todo = min3(tx_cnt, oleft / 4, (mo.length - oo) / 4); + if (todo > 0) { + readsl(ss->base + SS_TXFIFO, mo.addr + oo, todo); + oleft -= todo * 4; + oo += todo * 4; + if (oo == mo.length) { + sg_miter_next(&mo); + oo = 0; + } + } else { + /* + * read obl bytes in bufo, we read at maximum for + * emptying the device + */ + readsl(ss->base + SS_TXFIFO, bufo, tx_cnt); + obl = tx_cnt * 4; + obo = 0; + do { + /* + * how many bytes we can copy ? + * no more than remaining SG size + * no more than remaining buffer + * no need to test against oleft + */ + todo = min(mo.length - oo, obl - obo); + memcpy(mo.addr + oo, bufo + obo, todo); + oleft -= todo; + obo += todo; + oo += todo; + if (oo == mo.length) { + sg_miter_next(&mo); + oo = 0; + } + } while (obo < obl); + /* bufo must be fully used here */ + } + } + if (areq->info) { + for (i = 0; i < 4 && i < ivsize / 4; i++) { + v = readl(ss->base + SS_IV0 + i * 4); + *(u32 *)(areq->info + i * 4) = v; + } + } + +release_ss: + sg_miter_stop(&mi); + sg_miter_stop(&mo); + writel(0, ss->base + SS_CTL); + spin_unlock_bh(&ss->slock); + + return err; +} + +/* CBC AES */ +int sun4i_ss_cbc_aes_encrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_AES | SS_CBC | SS_ENABLED | SS_ENCRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +int sun4i_ss_cbc_aes_decrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_AES | SS_CBC | SS_ENABLED | SS_DECRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +/* ECB AES */ +int sun4i_ss_ecb_aes_encrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_AES | SS_ECB | SS_ENABLED | SS_ENCRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +int sun4i_ss_ecb_aes_decrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_AES | SS_ECB | SS_ENABLED | SS_DECRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +/* CBC DES */ +int sun4i_ss_cbc_des_encrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_DES | SS_CBC | SS_ENABLED | SS_ENCRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +int sun4i_ss_cbc_des_decrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_DES | SS_CBC | SS_ENABLED | SS_DECRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +/* ECB DES */ +int sun4i_ss_ecb_des_encrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_DES | SS_ECB | SS_ENABLED | SS_ENCRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +int sun4i_ss_ecb_des_decrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_DES | SS_ECB | SS_ENABLED | SS_DECRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +/* CBC 3DES */ +int sun4i_ss_cbc_des3_encrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_3DES | SS_CBC | SS_ENABLED | SS_ENCRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +int sun4i_ss_cbc_des3_decrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_3DES | SS_CBC | SS_ENABLED | SS_DECRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +/* ECB 3DES */ +int sun4i_ss_ecb_des3_encrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_3DES | SS_ECB | SS_ENABLED | SS_ENCRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +int sun4i_ss_ecb_des3_decrypt(struct ablkcipher_request *areq) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq); + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_cipher_req_ctx *rctx = ablkcipher_request_ctx(areq); + + rctx->mode = SS_OP_3DES | SS_ECB | SS_ENABLED | SS_DECRYPTION | + op->keymode; + return sun4i_ss_cipher_poll(areq); +} + +int sun4i_ss_cipher_init(struct crypto_tfm *tfm) +{ + struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm); + struct crypto_alg *alg = tfm->__crt_alg; + struct sun4i_ss_alg_template *algt; + + memset(op, 0, sizeof(struct sun4i_tfm_ctx)); + + algt = container_of(alg, struct sun4i_ss_alg_template, alg.crypto); + op->ss = algt->ss; + + tfm->crt_ablkcipher.reqsize = sizeof(struct sun4i_cipher_req_ctx); + + return 0; +} + +/* check and set the AES key, prepare the mode to be used */ +int sun4i_ss_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) +{ + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_ss_ctx *ss = op->ss; + + switch (keylen) { + case 128 / 8: + op->keymode = SS_AES_128BITS; + break; + case 192 / 8: + op->keymode = SS_AES_192BITS; + break; + case 256 / 8: + op->keymode = SS_AES_256BITS; + break; + default: + dev_err(ss->dev, "ERROR: Invalid keylen %u\n", keylen); + crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + op->keylen = keylen; + memcpy(op->key, key, keylen); + return 0; +} + +/* check and set the DES key, prepare the mode to be used */ +int sun4i_ss_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) +{ + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_ss_ctx *ss = op->ss; + u32 flags; + u32 tmp[DES_EXPKEY_WORDS]; + int ret; + + if (unlikely(keylen != DES_KEY_SIZE)) { + dev_err(ss->dev, "Invalid keylen %u\n", keylen); + crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + flags = crypto_ablkcipher_get_flags(tfm); + + ret = des_ekey(tmp, key); + if (unlikely(ret == 0) && (flags & CRYPTO_TFM_REQ_WEAK_KEY)) { + crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_WEAK_KEY); + dev_dbg(ss->dev, "Weak key %u\n", keylen); + return -EINVAL; + } + + op->keylen = keylen; + memcpy(op->key, key, keylen); + return 0; +} + +/* check and set the 3DES key, prepare the mode to be used */ +int sun4i_ss_des3_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) +{ + struct sun4i_tfm_ctx *op = crypto_ablkcipher_ctx(tfm); + struct sun4i_ss_ctx *ss = op->ss; + + if (unlikely(keylen != 3 * DES_KEY_SIZE)) { + dev_err(ss->dev, "Invalid keylen %u\n", keylen); + crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + op->keylen = keylen; + memcpy(op->key, key, keylen); + return 0; +} diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-core.c b/drivers/crypto/sunxi-ss/sun4i-ss-core.c new file mode 100644 index 000000000000..0b79b58c913b --- /dev/null +++ b/drivers/crypto/sunxi-ss/sun4i-ss-core.c @@ -0,0 +1,403 @@ +/* + * sun4i-ss-core.c - hardware cryptographic accelerator for Allwinner A20 SoC + * + * Copyright (C) 2013-2015 Corentin LABBE + * + * Core file which registers crypto algorithms supported by the SS. + * + * You could find a link for the datasheet in Documentation/arm/sunxi/README + * + * 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 + +#include "sun4i-ss.h" + +static struct sun4i_ss_alg_template ss_algs[] = { +{ .type = CRYPTO_ALG_TYPE_AHASH, + .mode = SS_OP_MD5, + .alg.hash = { + .init = sun4i_hash_init, + .update = sun4i_hash_update, + .final = sun4i_hash_final, + .finup = sun4i_hash_finup, + .digest = sun4i_hash_digest, + .export = sun4i_hash_export_md5, + .import = sun4i_hash_import_md5, + .halg = { + .digestsize = MD5_DIGEST_SIZE, + .base = { + .cra_name = "md5", + .cra_driver_name = "md5-sun4i-ss", + .cra_priority = 300, + .cra_alignmask = 3, + .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_blocksize = MD5_HMAC_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct sun4i_req_ctx), + .cra_module = THIS_MODULE, + .cra_type = &crypto_ahash_type, + .cra_init = sun4i_hash_crainit + } + } + } +}, +{ .type = CRYPTO_ALG_TYPE_AHASH, + .mode = SS_OP_SHA1, + .alg.hash = { + .init = sun4i_hash_init, + .update = sun4i_hash_update, + .final = sun4i_hash_final, + .finup = sun4i_hash_finup, + .digest = sun4i_hash_digest, + .export = sun4i_hash_export_sha1, + .import = sun4i_hash_import_sha1, + .halg = { + .digestsize = SHA1_DIGEST_SIZE, + .base = { + .cra_name = "sha1", + .cra_driver_name = "sha1-sun4i-ss", + .cra_priority = 300, + .cra_alignmask = 3, + .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct sun4i_req_ctx), + .cra_module = THIS_MODULE, + .cra_type = &crypto_ahash_type, + .cra_init = sun4i_hash_crainit + } + } + } +}, +{ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .alg.crypto = { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-sun4i-ss", + .cra_priority = 300, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER, + .cra_ctxsize = sizeof(struct sun4i_tfm_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_type = &crypto_ablkcipher_type, + .cra_init = sun4i_ss_cipher_init, + .cra_ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = sun4i_ss_aes_setkey, + .encrypt = sun4i_ss_cbc_aes_encrypt, + .decrypt = sun4i_ss_cbc_aes_decrypt, + } + } +}, +{ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .alg.crypto = { + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-sun4i-ss", + .cra_priority = 300, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER, + .cra_ctxsize = sizeof(struct sun4i_tfm_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_type = &crypto_ablkcipher_type, + .cra_init = sun4i_ss_cipher_init, + .cra_ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = sun4i_ss_aes_setkey, + .encrypt = sun4i_ss_ecb_aes_encrypt, + .decrypt = sun4i_ss_ecb_aes_decrypt, + } + } +}, +{ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .alg.crypto = { + .cra_name = "cbc(des)", + .cra_driver_name = "cbc-des-sun4i-ss", + .cra_priority = 300, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER, + .cra_ctxsize = sizeof(struct sun4i_req_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_type = &crypto_ablkcipher_type, + .cra_init = sun4i_ss_cipher_init, + .cra_u.ablkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = sun4i_ss_des_setkey, + .encrypt = sun4i_ss_cbc_des_encrypt, + .decrypt = sun4i_ss_cbc_des_decrypt, + } + } +}, +{ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .alg.crypto = { + .cra_name = "ecb(des)", + .cra_driver_name = "ecb-des-sun4i-ss", + .cra_priority = 300, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER, + .cra_ctxsize = sizeof(struct sun4i_req_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_type = &crypto_ablkcipher_type, + .cra_init = sun4i_ss_cipher_init, + .cra_u.ablkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .setkey = sun4i_ss_des_setkey, + .encrypt = sun4i_ss_ecb_des_encrypt, + .decrypt = sun4i_ss_ecb_des_decrypt, + } + } +}, +{ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .alg.crypto = { + .cra_name = "cbc(des3_ede)", + .cra_driver_name = "cbc-des3-sun4i-ss", + .cra_priority = 300, + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER, + .cra_ctxsize = sizeof(struct sun4i_req_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_type = &crypto_ablkcipher_type, + .cra_init = sun4i_ss_cipher_init, + .cra_u.ablkcipher = { + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES3_EDE_BLOCK_SIZE, + .setkey = sun4i_ss_des3_setkey, + .encrypt = sun4i_ss_cbc_des3_encrypt, + .decrypt = sun4i_ss_cbc_des3_decrypt, + } + } +}, +{ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .alg.crypto = { + .cra_name = "ecb(des3_ede)", + .cra_driver_name = "ecb-des3-sun4i-ss", + .cra_priority = 300, + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER, + .cra_ctxsize = sizeof(struct sun4i_req_ctx), + .cra_module = THIS_MODULE, + .cra_alignmask = 3, + .cra_type = &crypto_ablkcipher_type, + .cra_init = sun4i_ss_cipher_init, + .cra_u.ablkcipher = { + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES3_EDE_BLOCK_SIZE, + .setkey = sun4i_ss_des3_setkey, + .encrypt = sun4i_ss_ecb_des3_encrypt, + .decrypt = sun4i_ss_ecb_des3_decrypt, + } + } +}, +}; + +static int sun4i_ss_probe(struct platform_device *pdev) +{ + struct resource *res; + u32 v; + int err, i; + unsigned long cr; + const unsigned long cr_ahb = 24 * 1000 * 1000; + const unsigned long cr_mod = 150 * 1000 * 1000; + struct sun4i_ss_ctx *ss; + + if (!pdev->dev.of_node) + return -ENODEV; + + ss = devm_kzalloc(&pdev->dev, sizeof(*ss), GFP_KERNEL); + if (!ss) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ss->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ss->base)) { + dev_err(&pdev->dev, "Cannot request MMIO\n"); + return PTR_ERR(ss->base); + } + + ss->ssclk = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(ss->ssclk)) { + err = PTR_ERR(ss->ssclk); + dev_err(&pdev->dev, "Cannot get SS clock err=%d\n", err); + return err; + } + dev_dbg(&pdev->dev, "clock ss acquired\n"); + + ss->busclk = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(ss->busclk)) { + err = PTR_ERR(ss->busclk); + dev_err(&pdev->dev, "Cannot get AHB SS clock err=%d\n", err); + return err; + } + dev_dbg(&pdev->dev, "clock ahb_ss acquired\n"); + + /* Enable both clocks */ + err = clk_prepare_enable(ss->busclk); + if (err != 0) { + dev_err(&pdev->dev, "Cannot prepare_enable busclk\n"); + return err; + } + err = clk_prepare_enable(ss->ssclk); + if (err != 0) { + dev_err(&pdev->dev, "Cannot prepare_enable ssclk\n"); + goto error_ssclk; + } + + /* + * Check that clock have the correct rates given in the datasheet + * Try to set the clock to the maximum allowed + */ + err = clk_set_rate(ss->ssclk, cr_mod); + if (err != 0) { + dev_err(&pdev->dev, "Cannot set clock rate to ssclk\n"); + goto error_clk; + } + + /* + * The only impact on clocks below requirement are bad performance, + * so do not print "errors" + * warn on Overclocked clocks + */ + cr = clk_get_rate(ss->busclk); + if (cr >= cr_ahb) + dev_dbg(&pdev->dev, "Clock bus %lu (%lu MHz) (must be >= %lu)\n", + cr, cr / 1000000, cr_ahb); + else + dev_warn(&pdev->dev, "Clock bus %lu (%lu MHz) (must be >= %lu)\n", + cr, cr / 1000000, cr_ahb); + + cr = clk_get_rate(ss->ssclk); + if (cr <= cr_mod) + if (cr < cr_mod) + dev_warn(&pdev->dev, "Clock ss %lu (%lu MHz) (must be <= %lu)\n", + cr, cr / 1000000, cr_mod); + else + dev_dbg(&pdev->dev, "Clock ss %lu (%lu MHz) (must be <= %lu)\n", + cr, cr / 1000000, cr_mod); + else + dev_warn(&pdev->dev, "Clock ss is at %lu (%lu MHz) (must be <= %lu)\n", + cr, cr / 1000000, cr_mod); + + /* + * Datasheet named it "Die Bonding ID" + * I expect to be a sort of Security System Revision number. + * Since the A80 seems to have an other version of SS + * this info could be useful + */ + writel(SS_ENABLED, ss->base + SS_CTL); + v = readl(ss->base + SS_CTL); + v >>= 16; + v &= 0x07; + dev_info(&pdev->dev, "Die ID %d\n", v); + writel(0, ss->base + SS_CTL); + + ss->dev = &pdev->dev; + + spin_lock_init(&ss->slock); + + for (i = 0; i < ARRAY_SIZE(ss_algs); i++) { + ss_algs[i].ss = ss; + switch (ss_algs[i].type) { + case CRYPTO_ALG_TYPE_ABLKCIPHER: + err = crypto_register_alg(&ss_algs[i].alg.crypto); + if (err != 0) { + dev_err(ss->dev, "Fail to register %s\n", + ss_algs[i].alg.crypto.cra_name); + goto error_alg; + } + break; + case CRYPTO_ALG_TYPE_AHASH: + err = crypto_register_ahash(&ss_algs[i].alg.hash); + if (err != 0) { + dev_err(ss->dev, "Fail to register %s\n", + ss_algs[i].alg.hash.halg.base.cra_name); + goto error_alg; + } + break; + } + } + platform_set_drvdata(pdev, ss); + return 0; +error_alg: + i--; + for (; i >= 0; i--) { + switch (ss_algs[i].type) { + case CRYPTO_ALG_TYPE_ABLKCIPHER: + crypto_unregister_alg(&ss_algs[i].alg.crypto); + break; + case CRYPTO_ALG_TYPE_AHASH: + crypto_unregister_ahash(&ss_algs[i].alg.hash); + break; + } + } +error_clk: + clk_disable_unprepare(ss->ssclk); +error_ssclk: + clk_disable_unprepare(ss->busclk); + return err; +} + +static int sun4i_ss_remove(struct platform_device *pdev) +{ + int i; + struct sun4i_ss_ctx *ss = platform_get_drvdata(pdev); + + for (i = 0; i < ARRAY_SIZE(ss_algs); i++) { + switch (ss_algs[i].type) { + case CRYPTO_ALG_TYPE_ABLKCIPHER: + crypto_unregister_alg(&ss_algs[i].alg.crypto); + break; + case CRYPTO_ALG_TYPE_AHASH: + crypto_unregister_ahash(&ss_algs[i].alg.hash); + break; + } + } + + writel(0, ss->base + SS_CTL); + clk_disable_unprepare(ss->busclk); + clk_disable_unprepare(ss->ssclk); + return 0; +} + +static const struct of_device_id a20ss_crypto_of_match_table[] = { + { .compatible = "allwinner,sun4i-a10-crypto" }, + {} +}; +MODULE_DEVICE_TABLE(of, a20ss_crypto_of_match_table); + +static struct platform_driver sun4i_ss_driver = { + .probe = sun4i_ss_probe, + .remove = sun4i_ss_remove, + .driver = { + .name = "sun4i-ss", + .of_match_table = a20ss_crypto_of_match_table, + }, +}; + +module_platform_driver(sun4i_ss_driver); + +MODULE_DESCRIPTION("Allwinner Security System cryptographic accelerator"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Corentin LABBE "); diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c new file mode 100644 index 000000000000..ff8031498809 --- /dev/null +++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c @@ -0,0 +1,492 @@ +/* + * sun4i-ss-hash.c - hardware cryptographic accelerator for Allwinner A20 SoC + * + * Copyright (C) 2013-2015 Corentin LABBE + * + * This file add support for MD5 and SHA1. + * + * You could find the datasheet in Documentation/arm/sunxi/README + * + * 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 "sun4i-ss.h" +#include + +/* This is a totally arbitrary value */ +#define SS_TIMEOUT 100 + +int sun4i_hash_crainit(struct crypto_tfm *tfm) +{ + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), + sizeof(struct sun4i_req_ctx)); + return 0; +} + +/* sun4i_hash_init: initialize request context */ +int sun4i_hash_init(struct ahash_request *areq) +{ + struct sun4i_req_ctx *op = ahash_request_ctx(areq); + struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); + struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg); + struct sun4i_ss_alg_template *algt; + struct sun4i_ss_ctx *ss; + + memset(op, 0, sizeof(struct sun4i_req_ctx)); + + algt = container_of(alg, struct sun4i_ss_alg_template, alg.hash); + ss = algt->ss; + op->ss = algt->ss; + op->mode = algt->mode; + + return 0; +} + +int sun4i_hash_export_md5(struct ahash_request *areq, void *out) +{ + struct sun4i_req_ctx *op = ahash_request_ctx(areq); + struct md5_state *octx = out; + int i; + + octx->byte_count = op->byte_count + op->len; + + memcpy(octx->block, op->buf, op->len); + + if (op->byte_count > 0) { + for (i = 0; i < 4; i++) + octx->hash[i] = op->hash[i]; + } else { + octx->hash[0] = SHA1_H0; + octx->hash[1] = SHA1_H1; + octx->hash[2] = SHA1_H2; + octx->hash[3] = SHA1_H3; + } + + return 0; +} + +int sun4i_hash_import_md5(struct ahash_request *areq, const void *in) +{ + struct sun4i_req_ctx *op = ahash_request_ctx(areq); + const struct md5_state *ictx = in; + int i; + + sun4i_hash_init(areq); + + op->byte_count = ictx->byte_count & ~0x3F; + op->len = ictx->byte_count & 0x3F; + + memcpy(op->buf, ictx->block, op->len); + + for (i = 0; i < 4; i++) + op->hash[i] = ictx->hash[i]; + + return 0; +} + +int sun4i_hash_export_sha1(struct ahash_request *areq, void *out) +{ + struct sun4i_req_ctx *op = ahash_request_ctx(areq); + struct sha1_state *octx = out; + int i; + + octx->count = op->byte_count + op->len; + + memcpy(octx->buffer, op->buf, op->len); + + if (op->byte_count > 0) { + for (i = 0; i < 5; i++) + octx->state[i] = op->hash[i]; + } else { + octx->state[0] = SHA1_H0; + octx->state[1] = SHA1_H1; + octx->state[2] = SHA1_H2; + octx->state[3] = SHA1_H3; + octx->state[4] = SHA1_H4; + } + + return 0; +} + +int sun4i_hash_import_sha1(struct ahash_request *areq, const void *in) +{ + struct sun4i_req_ctx *op = ahash_request_ctx(areq); + const struct sha1_state *ictx = in; + int i; + + sun4i_hash_init(areq); + + op->byte_count = ictx->count & ~0x3F; + op->len = ictx->count & 0x3F; + + memcpy(op->buf, ictx->buffer, op->len); + + for (i = 0; i < 5; i++) + op->hash[i] = ictx->state[i]; + + return 0; +} + +/* + * sun4i_hash_update: update hash engine + * + * Could be used for both SHA1 and MD5 + * Write data by step of 32bits and put then in the SS. + * + * Since we cannot leave partial data and hash state in the engine, + * we need to get the hash state at the end of this function. + * We can get the hash state every 64 bytes + * + * So the first work is to get the number of bytes to write to SS modulo 64 + * The extra bytes will go to a temporary buffer op->buf storing op->len bytes + * + * So at the begin of update() + * if op->len + areq->nbytes < 64 + * => all data will be written to wait buffer (op->buf) and end=0 + * if not, write all data from op->buf to the device and position end to + * complete to 64bytes + * + * example 1: + * update1 60o => op->len=60 + * update2 60o => need one more word to have 64 bytes + * end=4 + * so write all data from op->buf and one word of SGs + * write remaining data in op->buf + * final state op->len=56 + */ +int sun4i_hash_update(struct ahash_request *areq) +{ + u32 v, ivmode = 0; + unsigned int i = 0; + /* + * i is the total bytes read from SGs, to be compared to areq->nbytes + * i is important because we cannot rely on SG length since the sum of + * SG->length could be greater than areq->nbytes + */ + + struct sun4i_req_ctx *op = ahash_request_ctx(areq); + struct sun4i_ss_ctx *ss = op->ss; + struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); + unsigned int in_i = 0; /* advancement in the current SG */ + unsigned int end; + /* + * end is the position when we need to stop writing to the device, + * to be compared to i + */ + int in_r, err = 0; + unsigned int todo; + u32 spaces, rx_cnt = SS_RX_DEFAULT; + size_t copied = 0; + struct sg_mapping_iter mi; + + dev_dbg(ss->dev, "%s %s bc=%llu len=%u mode=%x wl=%u h0=%0x", + __func__, crypto_tfm_alg_name(areq->base.tfm), + op->byte_count, areq->nbytes, op->mode, + op->len, op->hash[0]); + + if (areq->nbytes == 0) + return 0; + + /* protect against overflow */ + if (areq->nbytes > UINT_MAX - op->len) { + dev_err(ss->dev, "Cannot process too large request\n"); + return -EINVAL; + } + + if (op->len + areq->nbytes < 64) { + /* linearize data to op->buf */ + copied = sg_pcopy_to_buffer(areq->src, sg_nents(areq->src), + op->buf + op->len, areq->nbytes, 0); + op->len += copied; + return 0; + } + + end = ((areq->nbytes + op->len) / 64) * 64 - op->len; + + if (end > areq->nbytes || areq->nbytes - end > 63) { + dev_err(ss->dev, "ERROR: Bound error %u %u\n", + end, areq->nbytes); + return -EINVAL; + } + + spin_lock_bh(&ss->slock); + + /* + * if some data have been processed before, + * we need to restore the partial hash state + */ + if (op->byte_count > 0) { + ivmode = SS_IV_ARBITRARY; + for (i = 0; i < 5; i++) + writel(op->hash[i], ss->base + SS_IV0 + i * 4); + } + /* Enable the device */ + writel(op->mode | SS_ENABLED | ivmode, ss->base + SS_CTL); + + i = 0; + sg_miter_start(&mi, areq->src, sg_nents(areq->src), + SG_MITER_FROM_SG | SG_MITER_ATOMIC); + sg_miter_next(&mi); + in_i = 0; + + do { + /* + * we need to linearize in two case: + * - the buffer is already used + * - the SG does not have enough byte remaining ( < 4) + */ + if (op->len > 0 || (mi.length - in_i) < 4) { + /* + * if we have entered here we have two reason to stop + * - the buffer is full + * - reach the end + */ + while (op->len < 64 && i < end) { + /* how many bytes we can read from current SG */ + in_r = min3(mi.length - in_i, end - i, + 64 - op->len); + memcpy(op->buf + op->len, mi.addr + in_i, in_r); + op->len += in_r; + i += in_r; + in_i += in_r; + if (in_i == mi.length) { + sg_miter_next(&mi); + in_i = 0; + } + } + if (op->len > 3 && (op->len % 4) == 0) { + /* write buf to the device */ + writesl(ss->base + SS_RXFIFO, op->buf, + op->len / 4); + op->byte_count += op->len; + op->len = 0; + } + } + if (mi.length - in_i > 3 && i < end) { + /* how many bytes we can read from current SG */ + in_r = min3(mi.length - in_i, areq->nbytes - i, + ((mi.length - in_i) / 4) * 4); + /* how many bytes we can write in the device*/ + todo = min3((u32)(end - i) / 4, rx_cnt, (u32)in_r / 4); + writesl(ss->base + SS_RXFIFO, mi.addr + in_i, todo); + op->byte_count += todo * 4; + i += todo * 4; + in_i += todo * 4; + rx_cnt -= todo; + if (rx_cnt == 0) { + spaces = readl(ss->base + SS_FCSR); + rx_cnt = SS_RXFIFO_SPACES(spaces); + } + if (in_i == mi.length) { + sg_miter_next(&mi); + in_i = 0; + } + } + } while (i < end); + /* final linear */ + if ((areq->nbytes - i) < 64) { + while (i < areq->nbytes && in_i < mi.length && op->len < 64) { + /* how many bytes we can read from current SG */ + in_r = min3(mi.length - in_i, areq->nbytes - i, + 64 - op->len); + memcpy(op->buf + op->len, mi.addr + in_i, in_r); + op->len += in_r; + i += in_r; + in_i += in_r; + if (in_i == mi.length) { + sg_miter_next(&mi); + in_i = 0; + } + } + } + + sg_miter_stop(&mi); + + writel(op->mode | SS_ENABLED | SS_DATA_END, ss->base + SS_CTL); + i = 0; + do { + v = readl(ss->base + SS_CTL); + i++; + } while (i < SS_TIMEOUT && (v & SS_DATA_END) > 0); + if (i >= SS_TIMEOUT) { + dev_err_ratelimited(ss->dev, + "ERROR: hash end timeout %d>%d ctl=%x len=%u\n", + i, SS_TIMEOUT, v, areq->nbytes); + err = -EIO; + goto release_ss; + } + + /* get the partial hash only if something was written */ + for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++) + op->hash[i] = readl(ss->base + SS_MD0 + i * 4); + +release_ss: + writel(0, ss->base + SS_CTL); + spin_unlock_bh(&ss->slock); + return err; +} + +/* + * sun4i_hash_final: finalize hashing operation + * + * If we have some remaining bytes, we write them. + * Then ask the SS for finalizing the hashing operation + * + * I do not check RX FIFO size in this function since the size is 32 + * after each enabling and this function neither write more than 32 words. + */ +int sun4i_hash_final(struct ahash_request *areq) +{ + u32 v, ivmode = 0; + unsigned int i; + unsigned int j = 0; + int zeros, err = 0; + unsigned int index, padlen; + __be64 bits; + struct sun4i_req_ctx *op = ahash_request_ctx(areq); + struct sun4i_ss_ctx *ss = op->ss; + struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); + u32 bf[32]; + u32 wb = 0; + unsigned int nwait, nbw = 0; + + dev_dbg(ss->dev, "%s: byte=%llu len=%u mode=%x wl=%u h=%x", + __func__, op->byte_count, areq->nbytes, op->mode, + op->len, op->hash[0]); + + spin_lock_bh(&ss->slock); + + /* + * if we have already written something, + * restore the partial hash state + */ + if (op->byte_count > 0) { + ivmode = SS_IV_ARBITRARY; + for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++) + writel(op->hash[i], ss->base + SS_IV0 + i * 4); + } + writel(op->mode | SS_ENABLED | ivmode, ss->base + SS_CTL); + + /* write the remaining words of the wait buffer */ + if (op->len > 0) { + nwait = op->len / 4; + if (nwait > 0) { + writesl(ss->base + SS_RXFIFO, op->buf, nwait); + op->byte_count += 4 * nwait; + } + nbw = op->len - 4 * nwait; + wb = *(u32 *)(op->buf + nwait * 4); + wb &= (0xFFFFFFFF >> (4 - nbw) * 8); + } + + /* write the remaining bytes of the nbw buffer */ + if (nbw > 0) { + wb |= ((1 << 7) << (nbw * 8)); + bf[j++] = wb; + } else { + bf[j++] = 1 << 7; + } + + /* + * number of space to pad to obtain 64o minus 8(size) minus 4 (final 1) + * I take the operations from other MD5/SHA1 implementations + */ + + /* we have already send 4 more byte of which nbw data */ + if (op->mode == SS_OP_MD5) { + index = (op->byte_count + 4) & 0x3f; + op->byte_count += nbw; + if (index > 56) + zeros = (120 - index) / 4; + else + zeros = (56 - index) / 4; + } else { + op->byte_count += nbw; + index = op->byte_count & 0x3f; + padlen = (index < 56) ? (56 - index) : ((64 + 56) - index); + zeros = (padlen - 1) / 4; + } + + memset(bf + j, 0, 4 * zeros); + j += zeros; + + /* write the length of data */ + if (op->mode == SS_OP_SHA1) { + bits = cpu_to_be64(op->byte_count << 3); + bf[j++] = bits & 0xffffffff; + bf[j++] = (bits >> 32) & 0xffffffff; + } else { + bf[j++] = (op->byte_count << 3) & 0xffffffff; + bf[j++] = (op->byte_count >> 29) & 0xffffffff; + } + writesl(ss->base + SS_RXFIFO, bf, j); + + /* Tell the SS to stop the hashing */ + writel(op->mode | SS_ENABLED | SS_DATA_END, ss->base + SS_CTL); + + /* + * Wait for SS to finish the hash. + * The timeout could happen only in case of bad overcloking + * or driver bug. + */ + i = 0; + do { + v = readl(ss->base + SS_CTL); + i++; + } while (i < SS_TIMEOUT && (v & SS_DATA_END) > 0); + if (i >= SS_TIMEOUT) { + dev_err_ratelimited(ss->dev, + "ERROR: hash end timeout %d>%d ctl=%x len=%u\n", + i, SS_TIMEOUT, v, areq->nbytes); + err = -EIO; + goto release_ss; + } + + /* Get the hash from the device */ + if (op->mode == SS_OP_SHA1) { + for (i = 0; i < 5; i++) { + v = cpu_to_be32(readl(ss->base + SS_MD0 + i * 4)); + memcpy(areq->result + i * 4, &v, 4); + } + } else { + for (i = 0; i < 4; i++) { + v = readl(ss->base + SS_MD0 + i * 4); + memcpy(areq->result + i * 4, &v, 4); + } + } + +release_ss: + writel(0, ss->base + SS_CTL); + spin_unlock_bh(&ss->slock); + return err; +} + +/* sun4i_hash_finup: finalize hashing operation after an update */ +int sun4i_hash_finup(struct ahash_request *areq) +{ + int err; + + err = sun4i_hash_update(areq); + if (err != 0) + return err; + + return sun4i_hash_final(areq); +} + +/* combo of init/update/final functions */ +int sun4i_hash_digest(struct ahash_request *areq) +{ + int err; + + err = sun4i_hash_init(areq); + if (err != 0) + return err; + + err = sun4i_hash_update(areq); + if (err != 0) + return err; + + return sun4i_hash_final(areq); +} diff --git a/drivers/crypto/sunxi-ss/sun4i-ss.h b/drivers/crypto/sunxi-ss/sun4i-ss.h new file mode 100644 index 000000000000..db18b2554e6f --- /dev/null +++ b/drivers/crypto/sunxi-ss/sun4i-ss.h @@ -0,0 +1,199 @@ +/* + * sun4i-ss.h - hardware cryptographic accelerator for Allwinner A20 SoC + * + * Copyright (C) 2013-2015 Corentin LABBE + * + * Support AES cipher with 128,192,256 bits keysize. + * Support MD5 and SHA1 hash algorithms. + * Support DES and 3DES + * + * You could find the datasheet in Documentation/arm/sunxi/README + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SS_CTL 0x00 +#define SS_KEY0 0x04 +#define SS_KEY1 0x08 +#define SS_KEY2 0x0C +#define SS_KEY3 0x10 +#define SS_KEY4 0x14 +#define SS_KEY5 0x18 +#define SS_KEY6 0x1C +#define SS_KEY7 0x20 + +#define SS_IV0 0x24 +#define SS_IV1 0x28 +#define SS_IV2 0x2C +#define SS_IV3 0x30 + +#define SS_FCSR 0x44 + +#define SS_MD0 0x4C +#define SS_MD1 0x50 +#define SS_MD2 0x54 +#define SS_MD3 0x58 +#define SS_MD4 0x5C + +#define SS_RXFIFO 0x200 +#define SS_TXFIFO 0x204 + +/* SS_CTL configuration values */ + +/* PRNG generator mode - bit 15 */ +#define SS_PRNG_ONESHOT (0 << 15) +#define SS_PRNG_CONTINUE (1 << 15) + +/* IV mode for hash */ +#define SS_IV_ARBITRARY (1 << 14) + +/* SS operation mode - bits 12-13 */ +#define SS_ECB (0 << 12) +#define SS_CBC (1 << 12) +#define SS_CTS (3 << 12) + +/* Counter width for CNT mode - bits 10-11 */ +#define SS_CNT_16BITS (0 << 10) +#define SS_CNT_32BITS (1 << 10) +#define SS_CNT_64BITS (2 << 10) + +/* Key size for AES - bits 8-9 */ +#define SS_AES_128BITS (0 << 8) +#define SS_AES_192BITS (1 << 8) +#define SS_AES_256BITS (2 << 8) + +/* Operation direction - bit 7 */ +#define SS_ENCRYPTION (0 << 7) +#define SS_DECRYPTION (1 << 7) + +/* SS Method - bits 4-6 */ +#define SS_OP_AES (0 << 4) +#define SS_OP_DES (1 << 4) +#define SS_OP_3DES (2 << 4) +#define SS_OP_SHA1 (3 << 4) +#define SS_OP_MD5 (4 << 4) +#define SS_OP_PRNG (5 << 4) + +/* Data end bit - bit 2 */ +#define SS_DATA_END (1 << 2) + +/* PRNG start bit - bit 1 */ +#define SS_PRNG_START (1 << 1) + +/* SS Enable bit - bit 0 */ +#define SS_DISABLED (0 << 0) +#define SS_ENABLED (1 << 0) + +/* SS_FCSR configuration values */ +/* RX FIFO status - bit 30 */ +#define SS_RXFIFO_FREE (1 << 30) + +/* RX FIFO empty spaces - bits 24-29 */ +#define SS_RXFIFO_SPACES(val) (((val) >> 24) & 0x3f) + +/* TX FIFO status - bit 22 */ +#define SS_TXFIFO_AVAILABLE (1 << 22) + +/* TX FIFO available spaces - bits 16-21 */ +#define SS_TXFIFO_SPACES(val) (((val) >> 16) & 0x3f) + +#define SS_RX_MAX 32 +#define SS_RX_DEFAULT SS_RX_MAX +#define SS_TX_MAX 33 + +#define SS_RXFIFO_EMP_INT_PENDING (1 << 10) +#define SS_TXFIFO_AVA_INT_PENDING (1 << 8) +#define SS_RXFIFO_EMP_INT_ENABLE (1 << 2) +#define SS_TXFIFO_AVA_INT_ENABLE (1 << 0) + +struct sun4i_ss_ctx { + void __iomem *base; + int irq; + struct clk *busclk; + struct clk *ssclk; + struct device *dev; + struct resource *res; + spinlock_t slock; /* control the use of the device */ +}; + +struct sun4i_ss_alg_template { + u32 type; + u32 mode; + union { + struct crypto_alg crypto; + struct ahash_alg hash; + } alg; + struct sun4i_ss_ctx *ss; +}; + +struct sun4i_tfm_ctx { + u32 key[AES_MAX_KEY_SIZE / 4];/* divided by sizeof(u32) */ + u32 keylen; + u32 keymode; + struct sun4i_ss_ctx *ss; +}; + +struct sun4i_cipher_req_ctx { + u32 mode; +}; + +struct sun4i_req_ctx { + u32 mode; + u64 byte_count; /* number of bytes "uploaded" to the device */ + u32 hash[5]; /* for storing SS_IVx register */ + char buf[64]; + unsigned int len; + struct sun4i_ss_ctx *ss; +}; + +int sun4i_hash_crainit(struct crypto_tfm *tfm); +int sun4i_hash_init(struct ahash_request *areq); +int sun4i_hash_update(struct ahash_request *areq); +int sun4i_hash_final(struct ahash_request *areq); +int sun4i_hash_finup(struct ahash_request *areq); +int sun4i_hash_digest(struct ahash_request *areq); +int sun4i_hash_export_md5(struct ahash_request *areq, void *out); +int sun4i_hash_import_md5(struct ahash_request *areq, const void *in); +int sun4i_hash_export_sha1(struct ahash_request *areq, void *out); +int sun4i_hash_import_sha1(struct ahash_request *areq, const void *in); + +int sun4i_ss_cbc_aes_encrypt(struct ablkcipher_request *areq); +int sun4i_ss_cbc_aes_decrypt(struct ablkcipher_request *areq); +int sun4i_ss_ecb_aes_encrypt(struct ablkcipher_request *areq); +int sun4i_ss_ecb_aes_decrypt(struct ablkcipher_request *areq); + +int sun4i_ss_cbc_des_encrypt(struct ablkcipher_request *areq); +int sun4i_ss_cbc_des_decrypt(struct ablkcipher_request *areq); +int sun4i_ss_ecb_des_encrypt(struct ablkcipher_request *areq); +int sun4i_ss_ecb_des_decrypt(struct ablkcipher_request *areq); + +int sun4i_ss_cbc_des3_encrypt(struct ablkcipher_request *areq); +int sun4i_ss_cbc_des3_decrypt(struct ablkcipher_request *areq); +int sun4i_ss_ecb_des3_encrypt(struct ablkcipher_request *areq); +int sun4i_ss_ecb_des3_decrypt(struct ablkcipher_request *areq); + +int sun4i_ss_cipher_init(struct crypto_tfm *tfm); +int sun4i_ss_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen); +int sun4i_ss_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen); +int sun4i_ss_des3_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen); -- cgit v1.3-6-gb490 From f4c126ecaef1c08a906a2af51fb538022906f101 Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 6 Jul 2015 10:40:32 -0400 Subject: USB: serial: ftdi_sio: Fix broken URL in comment This fixes a typo in the URL: http://zeitcontrol.de/ Signed-off-by: Nik Nyby Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio_ids.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 792e054126de..cb12b319d008 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1365,7 +1365,7 @@ #define FTDI_CTI_NANO_PID 0xF60B /* - * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de + * ZeitControl cardsystems GmbH rfid-readers http://zeitcontrol.de */ /* TagTracer MIFARE*/ #define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0 -- cgit v1.3-6-gb490 From dd92d8de833613993b337cb4ff853587e1600aef Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 20 Jul 2015 10:58:21 +0200 Subject: Partially revert "drm/i915: s/mdelay/msleep/" in ilk rps code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6adfb1ef106bfe4b5ecb8bd75c4d037741d28a48. Ironlake RPS code runs under an irqsave spinlock and hence sleeping isn't allowed. Not a this long delay while blocking irqs isn't great at all, but fixing the locking scheme is a lot more involved. So just revert for now. Cc: Ville Syrjälä Reported-by: kernel test robot Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0d3e01434860..a1d92b7f3e35 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4266,7 +4266,7 @@ static void ironlake_enable_drps(struct drm_device *dev) if (wait_for_atomic((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10)) DRM_ERROR("stuck trying to change perf mode\n"); - msleep(1); + mdelay(1); ironlake_set_drps(dev, fstart); @@ -4297,10 +4297,10 @@ static void ironlake_disable_drps(struct drm_device *dev) /* Go back to the starting frequency */ ironlake_set_drps(dev, dev_priv->ips.fstart); - msleep(1); + mdelay(1); rgvswctl |= MEMCTL_CMD_STS; I915_WRITE(MEMSWCTL, rgvswctl); - msleep(1); + mdelay(1); spin_unlock_irq(&mchdev_lock); } -- cgit v1.3-6-gb490 From 5a447f09a8dffc0dd7569aec614ad3613a050098 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Apr 2015 21:02:25 +0000 Subject: staging: ozwpan: Fix hrtimer wreckage oz_timer_add() modifies the expiry value of an active timer, which results in data corruption. Use hrtimer_start() and remove the silly conditional. While at it use the proper helper function to convert milliseconds to ktime. Signed-off-by: Thomas Gleixner Cc: Peter Zijlstra Cc: Shigekatsu Tateno Acked-by: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Link: http://lkml.kernel.org/r/20150413210035.357448657@linutronix.de --- drivers/staging/ozwpan/ozproto.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c index 1ba24a2aef83..23aa8179c6fc 100644 --- a/drivers/staging/ozwpan/ozproto.c +++ b/drivers/staging/ozwpan/ozproto.c @@ -566,23 +566,14 @@ void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time) switch (type) { case OZ_TIMER_TOUT: case OZ_TIMER_STOP: - if (hrtimer_active(&pd->timeout)) { - hrtimer_set_expires(&pd->timeout, ktime_set(due_time / - MSEC_PER_SEC, (due_time % MSEC_PER_SEC) * - NSEC_PER_MSEC)); - hrtimer_start_expires(&pd->timeout, HRTIMER_MODE_REL); - } else { - hrtimer_start(&pd->timeout, ktime_set(due_time / - MSEC_PER_SEC, (due_time % MSEC_PER_SEC) * - NSEC_PER_MSEC), HRTIMER_MODE_REL); - } + hrtimer_start(&pd->timeout, ms_to_ktime(due_time), + HRTIMER_MODE_REL); pd->timeout_type = type; break; case OZ_TIMER_HEARTBEAT: if (!hrtimer_active(&pd->heartbeat)) - hrtimer_start(&pd->heartbeat, ktime_set(due_time / - MSEC_PER_SEC, (due_time % MSEC_PER_SEC) * - NSEC_PER_MSEC), HRTIMER_MODE_REL); + hrtimer_start(&pd->heartbeat, ms_to_ktime(due_time), + HRTIMER_MODE_REL); break; } spin_unlock_bh(&g_polling_lock); -- cgit v1.3-6-gb490 From 35c3f67f11849d80cc0e3cd3dd898977567c9c29 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 20 Jul 2015 19:06:14 +0900 Subject: irqchip/renesas-irqc: Get rid of IRQF_VALID IRQF_VALID is not needed on ARM anymore, so get rid of it. Signed-off-by: Magnus Damm Cc: jason@lakedaemon.net Cc: geert+renesas@glider.be Cc: horms@verge.net.au Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150720100614.2552.86867.sendpatchset@little-apple Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-renesas-irqc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 778bd076aeea..74e980fa7b4e 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -162,7 +162,6 @@ static int irqc_irq_domain_map(struct irq_domain *h, unsigned int virq, irqc_dbg(&p->irq[hw], "map"); irq_set_chip_data(virq, h->host_data); irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); /* kill me now */ return 0; } -- cgit v1.3-6-gb490 From 7d153751c79e84a88e8c80e82ee5293085b9081b Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 20 Jul 2015 19:06:25 +0900 Subject: irqchip/renesas-irqc: Use linear IRQ domain Use linear IRQ domain instead of irq_domain_add_simple() that also handles non-DT cases. This reduces the delta between the IRQC code and the generic chip implementation. Signed-off-by: Magnus Damm Cc: jason@lakedaemon.net Cc: geert+renesas@glider.be Cc: horms@verge.net.au Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150720100625.2552.63939.sendpatchset@little-apple Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-renesas-irqc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 74e980fa7b4e..7f750920ed90 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -242,8 +242,8 @@ static int irqc_probe(struct platform_device *pdev) irq_chip->irq_set_wake = irqc_irq_set_wake; irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND; - p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, - p->number_of_irqs, 0, + p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, + p->number_of_irqs, &irqc_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; -- cgit v1.3-6-gb490 From e10fc03c4f89e5191f0ad2a3885d476f498bf131 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 20 Jul 2015 19:06:35 +0900 Subject: irqchip/renesas-irqc: Make use of irq_find_mapping() Instead of locally caching the virq as domain_irq simply rely on the IRQ domain code and irq_find_mapping(). This reduces the delta between the IRQC driver and the generic chip implementation. Signed-off-by: Magnus Damm Cc: jason@lakedaemon.net Cc: geert+renesas@glider.be Cc: horms@verge.net.au Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150720100635.2552.20906.sendpatchset@little-apple Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-renesas-irqc.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 7f750920ed90..2aa3add711a6 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -53,7 +53,6 @@ struct irqc_irq { int hw_irq; int requested_irq; - int domain_irq; struct irqc_priv *p; }; @@ -70,8 +69,8 @@ struct irqc_priv { static void irqc_dbg(struct irqc_irq *i, char *str) { - dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)\n", - str, i->requested_irq, i->hw_irq, i->domain_irq); + dev_dbg(&i->p->pdev->dev, "%s (%d:%d)\n", + str, i->requested_irq, i->hw_irq); } static void irqc_irq_enable(struct irq_data *d) @@ -145,7 +144,7 @@ static irqreturn_t irqc_irq_handler(int irq, void *dev_id) if (ioread32(p->iomem + DETECT_STATUS) & bit) { iowrite32(bit, p->iomem + DETECT_STATUS); irqc_dbg(i, "demux2"); - generic_handle_irq(i->domain_irq); + generic_handle_irq(irq_find_mapping(p->irq_domain, i->hw_irq)); return IRQ_HANDLED; } return IRQ_NONE; @@ -156,9 +155,6 @@ static int irqc_irq_domain_map(struct irq_domain *h, unsigned int virq, { struct irqc_priv *p = h->host_data; - p->irq[hw].domain_irq = virq; - p->irq[hw].hw_irq = hw; - irqc_dbg(&p->irq[hw], "map"); irq_set_chip_data(virq, h->host_data); irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); @@ -214,6 +210,7 @@ static int irqc_probe(struct platform_device *pdev) break; p->irq[k].p = p; + p->irq[k].hw_irq = k; p->irq[k].requested_irq = irq->start; } -- cgit v1.3-6-gb490 From 1ae25d626cfe7e11adc2c3e71d0de1f882954ef3 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 20 Jul 2015 17:32:05 +0800 Subject: power: reset: at91: add sama5d3 reset function This patch introduces a new compatible string: "atmel,sama5d3-rstc" and new reset function for sama5d3 and later chips. As in sama5d3 or later chips, we don't have to shutdown the DDR controller before reset. Shutdown the DDR controller before reset is a workaround to avoid DDR signal driving the bus, but since sama5d3 and later chips there is no such a conflict. So in this patch: 1. the sama5d3 reset function only need to write the rstc register and return. 2. we can remove the code related with sama5d3 DDR controller as we don't use it at all. Signed-off-by: Josh Wu Acked-by: Nicolas Ferre Acked-by: Alexandre Belloni Reviewed-by: Guenter Roeck Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/arm/atmel-at91.txt | 2 +- drivers/power/reset/at91-reset.c | 26 ++++++++++++++++------ 2 files changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 424ac8cbfa08..dd998b9c0433 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -87,7 +87,7 @@ One interrupt per TC channel in a TC block: RSTC Reset Controller required properties: - compatible: Should be "atmel,-rstc". - can be "at91sam9260" or "at91sam9g45" + can be "at91sam9260" or "at91sam9g45" or "sama5d3" - reg: Should contain registers location and length Example: diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 36dc52fb2ec8..c378d4ec826f 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -123,6 +123,15 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, return NOTIFY_DONE; } +static int sama5d3_restart(struct notifier_block *this, unsigned long mode, + void *cmd) +{ + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), + at91_rstc_base); + + return NOTIFY_DONE; +} + static void __init at91_reset_status(struct platform_device *pdev) { u32 reg = readl(at91_rstc_base + AT91_RSTC_SR); @@ -155,13 +164,13 @@ static void __init at91_reset_status(struct platform_device *pdev) static const struct of_device_id at91_ramc_of_match[] = { { .compatible = "atmel,at91sam9260-sdramc", }, { .compatible = "atmel,at91sam9g45-ddramc", }, - { .compatible = "atmel,sama5d3-ddramc", }, { /* sentinel */ } }; static const struct of_device_id at91_reset_of_match[] = { { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart }, { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, + { .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart }, { /* sentinel */ } }; @@ -181,13 +190,16 @@ static int at91_reset_of_probe(struct platform_device *pdev) return -ENODEV; } - for_each_matching_node(np, at91_ramc_of_match) { - at91_ramc_base[idx] = of_iomap(np, 0); - if (!at91_ramc_base[idx]) { - dev_err(&pdev->dev, "Could not map ram controller address\n"); - return -ENODEV; + if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) { + /* we need to shutdown the ddr controller, so get ramc base */ + for_each_matching_node(np, at91_ramc_of_match) { + at91_ramc_base[idx] = of_iomap(np, 0); + if (!at91_ramc_base[idx]) { + dev_err(&pdev->dev, "Could not map ram controller address\n"); + return -ENODEV; + } + idx++; } - idx++; } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); -- cgit v1.3-6-gb490 From fb0cc3aa552642631c3a4e83deae2b5c1a1ef4fa Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 20 Jul 2015 09:10:36 -0500 Subject: iommu/vt-d: Cache PCI ATS state and Invalidate Queue Depth We check the ATS state (enabled/disabled) and fetch the PCI ATS Invalidate Queue Depth in performance-sensitive paths. It's easy to cache these, which removes dependencies on PCI. Remember the ATS enabled state. When enabling, read the queue depth once and cache it in the device_domain_info struct. This is similar to what amd_iommu.c does. Signed-off-by: Bjorn Helgaas Reviewed-by: Joerg Roedel Acked-by: Joerg Roedel --- drivers/iommu/intel-iommu.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index a98a7b27aca1..c22a5490eea7 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -408,6 +408,10 @@ struct device_domain_info { struct list_head global; /* link to global list */ u8 bus; /* PCI bus number */ u8 devfn; /* PCI devfn number */ + struct { + u8 enabled:1; + u8 qdep; + } ats; /* ATS state */ struct device *dev; /* it's NULL for PCIe-to-PCI bridge */ struct intel_iommu *iommu; /* IOMMU used by this device */ struct dmar_domain *domain; /* pointer to domain */ @@ -1391,19 +1395,26 @@ iommu_support_dev_iotlb (struct dmar_domain *domain, struct intel_iommu *iommu, static void iommu_enable_dev_iotlb(struct device_domain_info *info) { + struct pci_dev *pdev; + if (!info || !dev_is_pci(info->dev)) return; - pci_enable_ats(to_pci_dev(info->dev), VTD_PAGE_SHIFT); + pdev = to_pci_dev(info->dev); + if (pci_enable_ats(pdev, VTD_PAGE_SHIFT)) + return; + + info->ats.enabled = 1; + info->ats.qdep = pci_ats_queue_depth(pdev); } static void iommu_disable_dev_iotlb(struct device_domain_info *info) { - if (!info->dev || !dev_is_pci(info->dev) || - !pci_ats_enabled(to_pci_dev(info->dev))) + if (!info->ats.enabled) return; pci_disable_ats(to_pci_dev(info->dev)); + info->ats.enabled = 0; } static void iommu_flush_dev_iotlb(struct dmar_domain *domain, @@ -1415,16 +1426,11 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain, spin_lock_irqsave(&device_domain_lock, flags); list_for_each_entry(info, &domain->devices, link) { - struct pci_dev *pdev; - if (!info->dev || !dev_is_pci(info->dev)) - continue; - - pdev = to_pci_dev(info->dev); - if (!pci_ats_enabled(pdev)) + if (!info->ats.enabled) continue; sid = info->bus << 8 | info->devfn; - qdep = pci_ats_queue_depth(pdev); + qdep = info->ats.qdep; qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask); } spin_unlock_irqrestore(&device_domain_lock, flags); @@ -2272,6 +2278,8 @@ static struct dmar_domain *dmar_insert_dev_info(struct intel_iommu *iommu, info->bus = bus; info->devfn = devfn; + info->ats.enabled = 0; + info->ats.qdep = 0; info->dev = dev; info->domain = domain; info->iommu = iommu; -- cgit v1.3-6-gb490 From dd1b85dc446b7cfaeaa7e250d2ff2acc44a0d51d Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Mon, 20 Jul 2015 09:50:37 -0700 Subject: Input: zforce - don't invert the interrupt GPIO Commit 2d53809594af ("Input: zforce_ts - convert to use the gpiod interface") converted this driver to use the gpiod functions. These functions take the active low property into account, so we don't have to invert the result of gpiod_get_value_cansleep(). This has been missed in that commit. Fix it. Signed-off-by: Dirk Behme Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zforce_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index d00e1e33b657..0aa934c3540e 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -510,7 +510,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) if (!ts->suspending && device_may_wakeup(&client->dev)) pm_stay_awake(&client->dev); - while (!gpiod_get_value_cansleep(ts->gpio_int)) { + while (gpiod_get_value_cansleep(ts->gpio_int)) { ret = zforce_read_packet(ts, payload_buffer); if (ret < 0) { dev_err(&client->dev, -- cgit v1.3-6-gb490 From 6ccfe64c770139675a080ee5029ded7d89d9ea0d Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 20 Jul 2015 09:56:18 -0700 Subject: Input: elan_i2c - enable ELAN0600 acpi panels ELAN0600 seems to work just fine in mouse emulation mode through i2c-hid, but to have full raw touch support we need to register it in elan_i2c.ko Reported-and-tested-by: Alessio Treglia Signed-off-by: Benjamin Tissoires Acked-by: Jiri Kosina Signed-off-by: Dmitry Torokhov --- drivers/hid/hid-core.c | 1 + drivers/input/mouse/elan_i2c_core.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 56ce8c2b5530..f3133e49ba0c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2238,6 +2238,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) }, { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) }, { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) }, { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) }, diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index e7ef4ab1b37d..4a5d6ee5caaf 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1167,6 +1167,7 @@ MODULE_DEVICE_TABLE(i2c, elan_id); #ifdef CONFIG_ACPI static const struct acpi_device_id elan_acpi_id[] = { { "ELAN0000", 0 }, + { "ELAN0600", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, elan_acpi_id); -- cgit v1.3-6-gb490 From a11244c0b25b79d2a3b07df429268d66736e5b45 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Tue, 19 Aug 2014 15:31:54 +0300 Subject: nand: davinci: add support for 4K page size nand devices It is needed for k2l keystone2 EVM which uses NAND flash with 4K page size, hence add support for 4K page size nand devices. [Brian: similar work submitted by Murali Karicheri and Hao Zhang ] Signed-off-by: Sandeep Paulraj Signed-off-by: Ivan Khoronzhuk Signed-off-by: Brian Norris --- drivers/mtd/nand/davinci_nand.c | 42 ++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index feb6d18de78d..b90801302df4 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -520,6 +520,32 @@ static struct nand_ecclayout hwecc4_2048 = { }, }; +/* + * An ECC layout for using 4-bit ECC with large-page (4096bytes) flash, + * storing ten ECC bytes plus the manufacturer's bad block marker byte, + * and not overlapping the default BBT markers. + */ +static struct nand_ecclayout hwecc4_4096 = { + .eccbytes = 80, + .eccpos = { + /* at the end of spare sector */ + 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, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + }, + .oobfree = { + /* 2 bytes at offset 0 hold manufacturer badblock markers */ + {.offset = 2, .length = 46, }, + /* 5 bytes at offset 8 hold BBT markers */ + /* 8 bytes at offset 16 hold JFFS2 clean markers */ + }, +}; + #if defined(CONFIG_OF) static const struct of_device_id davinci_nand_of_match[] = { {.compatible = "ti,davinci-nand", }, @@ -796,18 +822,12 @@ static int nand_davinci_probe(struct platform_device *pdev) info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST; goto syndrome_done; } + if (chunks == 8) { + info->ecclayout = hwecc4_4096; + info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST; + goto syndrome_done; + } - /* 4KiB page chips are not yet supported. The eccpos from - * nand_ecclayout cannot hold 80 bytes and change to eccpos[] - * breaks userspace ioctl interface with mtd-utils. Once we - * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used - * for the 4KiB page chips. - * - * TODO: Note that nand_ecclayout has now been expanded and can - * hold plenty of OOB entries. - */ - dev_warn(&pdev->dev, "no 4-bit ECC support yet " - "for 4KiB-page NAND\n"); ret = -EIO; goto err; -- cgit v1.3-6-gb490 From cef1ed9c6bcf69245c0b9eb89b3f3a45049ba10c Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Sun, 5 Jul 2015 09:57:41 +0800 Subject: mtd: r852: make ecc_reg 32-bit in r852_ecc_correct r852_ecc_correct() reads a 32-bit register into a 16-bit variable, ecc_reg, but this variable is later used as if it was larger. This is reported by clang when building the kernel with many warnings: drivers/mtd/nand/r852.c:512:11: error: shift count >= width of type [-Werror,-Wshift-count-overflow] ecc_reg >>= 16; ^ ~~ Fix this by making ecc_reg 32-bit, like the return type of r852_read_reg_dword(). Signed-off-by: Nicolas Iooss Signed-off-by: Brian Norris --- drivers/mtd/nand/r852.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 77e96d2df96c..cc6bac537f5a 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -466,7 +466,7 @@ static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) { - uint16_t ecc_reg; + uint32_t ecc_reg; uint8_t ecc_status, err_byte; int i, error = 0; -- cgit v1.3-6-gb490 From bad47ad2eef341a79ff355734147efe933618033 Mon Sep 17 00:00:00 2001 From: Chris Zhong Date: Mon, 20 Jul 2015 17:23:53 +0800 Subject: regulator: rk808: fixed the overshoot when adjust voltage There is a overshoot in DCDC1/DCDC2, we have 2 method to workaround: 1st is use dvs pin to switch the voltage between value in BUCKn_ON_VSEL and BUCKn_DVS_VSEL. If DVS pin is inactive, the voltage of DCDC1/DCDC2 are controlled by BUCKn_ON_VSEL, when we pull dvs1/dvs2 pin to active, they would be controlled by BUCKn_DVS_VSEL. In this case, the ramp rate is same as the value programmed in BUCKn_RATE, and the fastest rate is 10mv/us. 2nd method is gradual adjustment, adjust the voltage to a target value step by step via i2c, each step is set to 100 mA. If you write the voltage directly using an i2c write the rk808 will always ramp as fast as it possibly can, about 100mv/us. Signed-off-by: Chris Zhong Reviewed-by: Doug Anderson Signed-off-by: Mark Brown --- drivers/regulator/rk808-regulator.c | 219 ++++++++++++++++++++++++++++++++++-- 1 file changed, 207 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index 3fd44353cc80..ca913fd15598 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -16,10 +16,13 @@ * more details. */ -#include +#include +#include #include -#include +#include #include +#include +#include #include #include @@ -36,12 +39,25 @@ #define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET) #define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET) +#define RK808_DVS2_POL BIT(2) +#define RK808_DVS1_POL BIT(1) + /* Offset from XXX_ON_VSEL to XXX_SLP_VSEL */ #define RK808_SLP_REG_OFFSET 1 +/* Offset from XXX_ON_VSEL to XXX_DVS_VSEL */ +#define RK808_DVS_REG_OFFSET 2 + /* Offset from XXX_EN_REG to SLEEP_SET_OFF_XXX */ #define RK808_SLP_SET_OFF_REG_OFFSET 2 +/* max steps for increase voltage of Buck1/2, equal 100mv*/ +#define MAX_STEPS_ONE_TIME 8 + +struct rk808_regulator_data { + struct gpio_desc *dvs_gpio[2]; +}; + static const int rk808_buck_config_regs[] = { RK808_BUCK1_CONFIG_REG, RK808_BUCK2_CONFIG_REG, @@ -70,6 +86,131 @@ static const struct regulator_linear_range rk808_ldo6_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(800000, 0, 17, 100000), }; +static int rk808_buck1_2_get_voltage_sel_regmap(struct regulator_dev *rdev) +{ + struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev); + int id = rdev->desc->id - RK808_ID_DCDC1; + struct gpio_desc *gpio = pdata->dvs_gpio[id]; + unsigned int val; + int ret; + + if (IS_ERR(gpio) || gpiod_get_value(gpio) == 0) + return regulator_get_voltage_sel_regmap(rdev); + + ret = regmap_read(rdev->regmap, + rdev->desc->vsel_reg + RK808_DVS_REG_OFFSET, + &val); + if (ret != 0) + return ret; + + val &= rdev->desc->vsel_mask; + val >>= ffs(rdev->desc->vsel_mask) - 1; + + return val; +} + +static int rk808_buck1_2_i2c_set_voltage_sel(struct regulator_dev *rdev, + unsigned sel) +{ + int ret, delta_sel; + unsigned int old_sel, tmp, val, mask = rdev->desc->vsel_mask; + + ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val); + if (ret != 0) + return ret; + + tmp = val & ~mask; + old_sel = val & mask; + old_sel >>= ffs(mask) - 1; + delta_sel = sel - old_sel; + + /* + * If directly modify the register to change the voltage, we will face + * the risk of overshoot. Put it into a multi-step, can effectively + * avoid this problem, a step is 100mv here. + */ + while (delta_sel > MAX_STEPS_ONE_TIME) { + old_sel += MAX_STEPS_ONE_TIME; + val = old_sel << (ffs(mask) - 1); + val |= tmp; + + /* + * i2c is 400kHz (2.5us per bit) and we must transmit _at least_ + * 3 bytes (24 bits) plus start and stop so 26 bits. So we've + * got more than 65 us between each voltage change and thus + * won't ramp faster than ~1500 uV / us. + */ + ret = regmap_write(rdev->regmap, rdev->desc->vsel_reg, val); + delta_sel = sel - old_sel; + } + + sel <<= ffs(mask) - 1; + val = tmp | sel; + ret = regmap_write(rdev->regmap, rdev->desc->vsel_reg, val); + + /* + * When we change the voltage register directly, the ramp rate is about + * 100000uv/us, wait 1us to make sure the target voltage to be stable, + * so we needn't wait extra time after that. + */ + udelay(1); + + return ret; +} + +static int rk808_buck1_2_set_voltage_sel(struct regulator_dev *rdev, + unsigned sel) +{ + struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev); + int id = rdev->desc->id - RK808_ID_DCDC1; + struct gpio_desc *gpio = pdata->dvs_gpio[id]; + unsigned int reg = rdev->desc->vsel_reg; + unsigned old_sel; + int ret, gpio_level; + + if (IS_ERR(gpio)) + return rk808_buck1_2_i2c_set_voltage_sel(rdev, sel); + + gpio_level = gpiod_get_value(gpio); + if (gpio_level == 0) { + reg += RK808_DVS_REG_OFFSET; + ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &old_sel); + } else { + ret = regmap_read(rdev->regmap, + reg + RK808_DVS_REG_OFFSET, + &old_sel); + } + + if (ret != 0) + return ret; + + sel <<= ffs(rdev->desc->vsel_mask) - 1; + sel |= old_sel & ~rdev->desc->vsel_mask; + + ret = regmap_write(rdev->regmap, reg, sel); + if (ret) + return ret; + + gpiod_set_value(gpio, !gpio_level); + + return ret; +} + +static int rk808_buck1_2_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev); + int id = rdev->desc->id - RK808_ID_DCDC1; + struct gpio_desc *gpio = pdata->dvs_gpio[id]; + + /* if there is no dvs1/2 pin, we don't need wait extra time here. */ + if (IS_ERR(gpio)) + return 0; + + return regulator_set_voltage_time_sel(rdev, old_selector, new_selector); +} + static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { unsigned int ramp_value = RK808_RAMP_RATE_10MV_PER_US; @@ -137,8 +278,9 @@ static int rk808_set_suspend_disable(struct regulator_dev *rdev) static struct regulator_ops rk808_buck1_2_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = rk808_buck1_2_get_voltage_sel_regmap, + .set_voltage_sel = rk808_buck1_2_set_voltage_sel, + .set_voltage_time_sel = rk808_buck1_2_set_voltage_time_sel, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -380,25 +522,76 @@ static struct of_regulator_match rk808_reg_matches[] = { [RK808_ID_SWITCH2] = { .name = "SWITCH_REG2" }, }; +static int rk808_regulator_dt_parse_pdata(struct device *dev, + struct device *client_dev, + struct regmap *map, + struct rk808_regulator_data *pdata) +{ + struct device_node *np; + int tmp, ret, i; + + np = of_get_child_by_name(client_dev->of_node, "regulators"); + if (!np) + return -ENXIO; + + ret = of_regulator_match(dev, np, rk808_reg_matches, + RK808_NUM_REGULATORS); + if (ret < 0) + goto dt_parse_end; + + for (i = 0; i < ARRAY_SIZE(pdata->dvs_gpio); i++) { + pdata->dvs_gpio[i] = gpiod_get_index(client_dev, "dvs", i); + if (IS_ERR(pdata->dvs_gpio[i])) { + dev_warn(dev, "there is no dvs%d gpio\n", i); + continue; + } + + gpiod_direction_output(pdata->dvs_gpio[i], 0); + + tmp = i ? RK808_DVS2_POL : RK808_DVS1_POL; + ret = regmap_update_bits(map, RK808_IO_POL_REG, tmp, + gpiod_is_active_low(pdata->dvs_gpio[i]) ? + 0 : tmp); + } + +dt_parse_end: + of_node_put(np); + return ret; +} + +static int rk808_regulator_remove(struct platform_device *pdev) +{ + struct rk808_regulator_data *pdata = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < ARRAY_SIZE(pdata->dvs_gpio); i++) { + if (!IS_ERR(pdata->dvs_gpio[i])) + gpiod_put(pdata->dvs_gpio[i]); + } + + return 0; +} + static int rk808_regulator_probe(struct platform_device *pdev) { struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); struct i2c_client *client = rk808->i2c; - struct device_node *reg_np; struct regulator_config config = {}; struct regulator_dev *rk808_rdev; + struct rk808_regulator_data *pdata; int ret, i; - reg_np = of_get_child_by_name(client->dev.of_node, "regulators"); - if (!reg_np) - return -ENXIO; + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; - ret = of_regulator_match(&pdev->dev, reg_np, rk808_reg_matches, - RK808_NUM_REGULATORS); - of_node_put(reg_np); + ret = rk808_regulator_dt_parse_pdata(&pdev->dev, &client->dev, + rk808->regmap, pdata); if (ret < 0) return ret; + platform_set_drvdata(pdev, pdata); + /* Instantiate the regulators */ for (i = 0; i < RK808_NUM_REGULATORS; i++) { if (!rk808_reg_matches[i].init_data || @@ -406,7 +599,7 @@ static int rk808_regulator_probe(struct platform_device *pdev) continue; config.dev = &client->dev; - config.driver_data = rk808; + config.driver_data = pdata; config.regmap = rk808->regmap; config.of_node = rk808_reg_matches[i].of_node; config.init_data = rk808_reg_matches[i].init_data; @@ -425,8 +618,10 @@ static int rk808_regulator_probe(struct platform_device *pdev) static struct platform_driver rk808_regulator_driver = { .probe = rk808_regulator_probe, + .remove = rk808_regulator_remove, .driver = { .name = "rk808-regulator", + .owner = THIS_MODULE, }, }; -- cgit v1.3-6-gb490 From f686a36b4b79782a94f07769fb1c0187d24ea8a8 Mon Sep 17 00:00:00 2001 From: Andrea Galbusera Date: Tue, 14 Jul 2015 15:36:21 +0200 Subject: iio: adc: mcp320x: Add support for mcp3301 This adds support for Microchip's 13 bit 1 channel AD converter MCP3301 Signed-off-by: Andrea Galbusera Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/mcp320x.txt | 1 + drivers/iio/adc/Kconfig | 4 ++-- drivers/iio/adc/mcp320x.c | 16 +++++++++++++++- 3 files changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt index b85184391b78..2a1f3af30155 100644 --- a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt +++ b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt @@ -18,6 +18,7 @@ Required properties: "mcp3202" "mcp3204" "mcp3208" + "mcp3301" Examples: diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index dace593b158b..2714f043fa6c 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -229,8 +229,8 @@ config MCP320X depends on SPI help Say yes here to build support for Microchip Technology's - MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204 or - MCP3208 analog to digital converter. + MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204, + MCP3208 or MCP3301 analog to digital converter. This driver can also be built as a module. If so, the module will be called mcp320x. diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index 8d9c9b9215dd..72969c8a0a51 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -25,6 +25,7 @@ * http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf mcp3201 * http://ww1.microchip.com/downloads/en/DeviceDoc/21034D.pdf mcp3202 * http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf mcp3204/08 + * http://ww1.microchip.com/downloads/en/DeviceDoc/21700E.pdf mcp3301 * * 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 @@ -47,6 +48,7 @@ enum { mcp3202, mcp3204, mcp3208, + mcp3301, }; struct mcp320x_chip_info { @@ -76,6 +78,7 @@ static int mcp320x_channel_to_tx_data(int device_index, switch (device_index) { case mcp3001: case mcp3201: + case mcp3301: return 0; case mcp3002: case mcp3202: @@ -102,7 +105,7 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel, adc->tx_buf = mcp320x_channel_to_tx_data(device_index, channel, differential); - if (device_index != mcp3001 && device_index != mcp3201) { + if (device_index != mcp3001 && device_index != mcp3201 && device_index != mcp3301) { ret = spi_sync(adc->spi, &adc->msg); if (ret < 0) return ret; @@ -125,6 +128,8 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel, case mcp3204: case mcp3208: return (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4); + case mcp3301: + return sign_extend32((adc->rx_buf[0] & 0x1f) << 8 | adc->rx_buf[1], 12); default: return -EINVAL; } @@ -274,6 +279,11 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = { .num_channels = ARRAY_SIZE(mcp3208_channels), .resolution = 12 }, + [mcp3301] = { + .channels = mcp3201_channels, + .num_channels = ARRAY_SIZE(mcp3201_channels), + .resolution = 13 + }, }; static int mcp320x_probe(struct spi_device *spi) @@ -366,6 +376,9 @@ static const struct of_device_id mcp320x_dt_ids[] = { }, { .compatible = "mcp3208", .data = &mcp320x_chip_infos[mcp3208], + }, { + .compatible = "mcp3301", + .data = &mcp320x_chip_infos[mcp3301], }, { } }; @@ -381,6 +394,7 @@ static const struct spi_device_id mcp320x_id[] = { { "mcp3202", mcp3202 }, { "mcp3204", mcp3204 }, { "mcp3208", mcp3208 }, + { "mcp3301", mcp3301 }, { } }; MODULE_DEVICE_TABLE(spi, mcp320x_id); -- cgit v1.3-6-gb490 From 5e9972cd6f1a69ee8a8ee8664d3e4c4ea59c0901 Mon Sep 17 00:00:00 2001 From: Sanchayan Maity Date: Tue, 14 Jul 2015 19:23:22 +0530 Subject: iio: adc: vf610: Determine sampling frequencies by using minimum sample time The driver currently does not take into account the minimum sample time as per the Figure 6-8 Chapter 9.1.1 12-bit ADC electrical characteristics. We set a static amount of cycles instead of considering the sample time as a given value, which depends on hardware characteristics. Determine sampling frequencies by first reading the device tree property node and then calculating the required Long Sample Time Adder (LSTAdder) value, based on the ADC clock frequency and sample time value obtained from the device tree. This LSTAdder value is then used for calculating the sampling frequencies possible. In case the sample time property is not specified through the device tree, a safe default value of 1000ns is assumed. Signed-off-by: Sanchayan Maity Acked-by: Stefan Agner Acked-by: Fugang Duan Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/vf610-adc.txt | 5 ++ drivers/iio/adc/vf610_adc.c | 79 ++++++++++++++++++++-- 2 files changed, 80 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt index 3eb40e20c143..1aad0514e647 100644 --- a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt @@ -17,6 +17,11 @@ Recommended properties: - Frequency in normal mode (ADLPC=0, ADHSC=0) - Frequency in high-speed mode (ADLPC=0, ADHSC=1) - Frequency in low-power mode (ADLPC=1, ADHSC=0) +- min-sample-time: Minimum sampling time in nanoseconds. This value has + to be chosen according to the conversion mode and the connected analog + source resistance (R_as) and capacitance (C_as). Refer the datasheet's + operating requirements. A safe default across a wide range of R_as and + C_as as well as conversion modes is 1000ns. Example: adc0: adc@4003b000 { diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 480f335a0f9f..23b8fb94ec09 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -68,6 +68,9 @@ #define VF610_ADC_CLK_DIV8 0x60 #define VF610_ADC_CLK_MASK 0x60 #define VF610_ADC_ADLSMP_LONG 0x10 +#define VF610_ADC_ADSTS_SHORT 0x100 +#define VF610_ADC_ADSTS_NORMAL 0x200 +#define VF610_ADC_ADSTS_LONG 0x300 #define VF610_ADC_ADSTS_MASK 0x300 #define VF610_ADC_ADLPC_EN 0x80 #define VF610_ADC_ADHSC_EN 0x400 @@ -98,6 +101,8 @@ #define VF610_ADC_CALF 0x2 #define VF610_ADC_TIMEOUT msecs_to_jiffies(100) +#define DEFAULT_SAMPLE_TIME 1000 + enum clk_sel { VF610_ADCIOC_BUSCLK_SET, VF610_ADCIOC_ALTCLK_SET, @@ -124,6 +129,17 @@ enum conversion_mode_sel { VF610_ADC_CONV_LOW_POWER, }; +enum lst_adder_sel { + VF610_ADCK_CYCLES_3, + VF610_ADCK_CYCLES_5, + VF610_ADCK_CYCLES_7, + VF610_ADCK_CYCLES_9, + VF610_ADCK_CYCLES_13, + VF610_ADCK_CYCLES_17, + VF610_ADCK_CYCLES_21, + VF610_ADCK_CYCLES_25, +}; + struct vf610_adc_feature { enum clk_sel clk_sel; enum vol_ref vol_ref; @@ -132,6 +148,8 @@ struct vf610_adc_feature { int clk_div; int sample_rate; int res_mode; + u32 lst_adder_index; + u32 default_sample_time; bool calibration; bool ovwren; @@ -155,11 +173,13 @@ struct vf610_adc { }; static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; +static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 }; static inline void vf610_adc_calculate_rates(struct vf610_adc *info) { struct vf610_adc_feature *adc_feature = &info->adc_feature; unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk); + u32 adck_period, lst_addr_min; int divisor, i; adck_rate = info->max_adck_rate[adc_feature->conv_mode]; @@ -173,6 +193,19 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info) adc_feature->clk_div = 8; } + /* + * Determine the long sample time adder value to be used based + * on the default minimum sample time provided. + */ + adck_period = NSEC_PER_SEC / adck_rate; + lst_addr_min = adc_feature->default_sample_time / adck_period; + for (i = 0; i < ARRAY_SIZE(vf610_lst_adder); i++) { + if (vf610_lst_adder[i] > lst_addr_min) { + adc_feature->lst_adder_index = i; + break; + } + } + /* * Calculate ADC sample frequencies * Sample time unit is ADCK cycles. ADCK clk source is ipg clock, @@ -182,12 +215,13 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info) * SFCAdder: fixed to 6 ADCK cycles * AverageNum: 1, 4, 8, 16, 32 samples for hardware average. * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode - * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles + * LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles */ adck_rate = ipg_rate / info->adc_feature.clk_div; for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++) info->sample_freq_avail[i] = - adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3)); + adck_rate / (6 + vf610_hw_avgs[i] * + (25 + vf610_lst_adder[adc_feature->lst_adder_index])); } static inline void vf610_adc_cfg_init(struct vf610_adc *info) @@ -347,8 +381,40 @@ static void vf610_adc_sample_set(struct vf610_adc *info) break; } - /* Use the short sample mode */ - cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK); + /* + * Set ADLSMP and ADSTS based on the Long Sample Time Adder value + * determined. + */ + switch (adc_feature->lst_adder_index) { + case VF610_ADCK_CYCLES_3: + break; + case VF610_ADCK_CYCLES_5: + cfg_data |= VF610_ADC_ADSTS_SHORT; + break; + case VF610_ADCK_CYCLES_7: + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + case VF610_ADCK_CYCLES_9: + cfg_data |= VF610_ADC_ADSTS_LONG; + break; + case VF610_ADCK_CYCLES_13: + cfg_data |= VF610_ADC_ADLSMP_LONG; + break; + case VF610_ADCK_CYCLES_17: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_SHORT; + break; + case VF610_ADCK_CYCLES_21: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + case VF610_ADCK_CYCLES_25: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + default: + dev_err(info->dev, "error in sample time select\n"); + } /* update hardware average selection */ cfg_data &= ~VF610_ADC_AVGS_MASK; @@ -713,6 +779,11 @@ static int vf610_adc_probe(struct platform_device *pdev) of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency", info->max_adck_rate, 3); + ret = of_property_read_u32(pdev->dev.of_node, "min-sample-time", + &info->adc_feature.default_sample_time); + if (ret) + info->adc_feature.default_sample_time = DEFAULT_SAMPLE_TIME; + platform_set_drvdata(pdev, indio_dev); init_completion(&info->completion); -- cgit v1.3-6-gb490 From 889c5e9b668670c91dcd3a8f2b15a0b2086f4827 Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Tue, 7 Jul 2015 13:39:28 +0000 Subject: iio: dht11: whitespace changes to make checkpatch.pl --strict happy * add spaces around binary operators in cases where it reduces readability * align multiline statements around opening parenthesis Reported-by: Hartmut Knaack in Message-ID: <55919E72.3010807@gmx.de> Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 7d79a1ac5f5f..343d26af1dd8 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -46,7 +46,8 @@ * Note that when reading the sensor actually 84 edges are detected, but * since the last edge is not significant, we only store 83: */ -#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1) +#define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \ + DHT11_EDGES_PREAMBLE + 1) /* Data transmission timing (nano seconds) */ #define DHT11_START_TRANSMISSION 18 /* ms */ @@ -95,24 +96,24 @@ static int dht11_decode(struct dht11 *dht11, int offset) /* Calculate timestamp resolution */ for (i = 1; i < dht11->num_edges; ++i) { - t = dht11->edges[i].ts - dht11->edges[i-1].ts; + t = dht11->edges[i].ts - dht11->edges[i - 1].ts; if (t > 0 && t < timeres) timeres = t; } - if (2*timeres > DHT11_DATA_BIT_HIGH) { + if (2 * timeres > DHT11_DATA_BIT_HIGH) { pr_err("dht11: timeresolution %d too bad for decoding\n", - timeres); + timeres); return -EIO; } threshold = DHT11_DATA_BIT_HIGH / timeres; - if (DHT11_DATA_BIT_LOW/timeres + 1 >= threshold) + if (DHT11_DATA_BIT_LOW / timeres + 1 >= threshold) pr_err("dht11: WARNING: decoding ambiguous\n"); /* scale down with timeres and check validity */ for (i = 0; i < DHT11_BITS_PER_READ; ++i) { - t = dht11->edges[offset + 2*i + 2].ts - - dht11->edges[offset + 2*i + 1].ts; - if (!dht11->edges[offset + 2*i + 1].value) + t = dht11->edges[offset + 2 * i + 2].ts - + dht11->edges[offset + 2 * i + 1].ts; + if (!dht11->edges[offset + 2 * i + 1].value) return -EIO; /* lost synchronisation */ timing[i] = t / timeres; } @@ -166,7 +167,7 @@ static irqreturn_t dht11_handle_irq(int irq, void *data) } static int dht11_read_raw(struct iio_dev *iio_dev, - const struct iio_chan_spec *chan, + const struct iio_chan_spec *chan, int *val, int *val2, long m) { struct dht11 *dht11 = iio_priv(iio_dev); @@ -192,13 +193,13 @@ static int dht11_read_raw(struct iio_dev *iio_dev, goto err; ret = wait_for_completion_killable_timeout(&dht11->completion, - HZ); + HZ); free_irq(dht11->irq, iio_dev); if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) { dev_err(&iio_dev->dev, - "Only %d signal edges detected\n", + "Only %d signal edges detected\n", dht11->num_edges); ret = -ETIMEDOUT; } @@ -206,7 +207,7 @@ static int dht11_read_raw(struct iio_dev *iio_dev, goto err; ret = dht11_decode(dht11, - dht11->num_edges == DHT11_EDGES_PER_READ ? + dht11->num_edges == DHT11_EDGES_PER_READ ? DHT11_EDGES_PREAMBLE : DHT11_EDGES_PREAMBLE - 2); if (ret) -- cgit v1.3-6-gb490 From a7126003b6dd47c0088d952734379ef471156c5f Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Tue, 7 Jul 2015 13:39:29 +0000 Subject: iio: dht11: add comment to make checkpatch.pl --strict happy Explain why the driver needs a mutex. Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 343d26af1dd8..bb5ad57ed2a2 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -63,6 +63,7 @@ struct dht11 { int irq; struct completion completion; + /* The iio sysfs interface doesn't prevent concurrent reads: */ struct mutex lock; s64 timestamp; -- cgit v1.3-6-gb490 From 5fbb0bc466b7b43036b1dd8c9e9166ca9e69e07a Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Tue, 7 Jul 2015 13:39:30 +0000 Subject: iio: dht11: avoid multiple assignments to make checkpatch.pl --strict happy We just do the assignments in two steps. Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index bb5ad57ed2a2..91976e06f1c6 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -263,9 +263,10 @@ static int dht11_probe(struct platform_device *pdev) dht11 = iio_priv(iio); dht11->dev = dev; - dht11->gpio = ret = of_get_gpio(node, 0); + ret = of_get_gpio(node, 0); if (ret < 0) return ret; + dht11->gpio = ret; ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name); if (ret) return ret; -- cgit v1.3-6-gb490 From 081d974031bafb204d64de3e82f398daf1d0b899 Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Tue, 7 Jul 2015 13:39:31 +0000 Subject: iio: dht11: Use new function ktime_get_resolution_ns() This cleans up the most ugly workaround in this driver. There are no functional changes yet in the decoding algorithm, but we improve the following things: * Get rid of spurious warning messages on systems with fast HRTIMER. * If the clock is not fast enough for decoding to work, we give up immediately. * In that case we return EAGAIN instead of EIO, so it's easier to discriminate causes of failure. Returning EAGAIN is somewhat controversial: It's technically correct as a faster clock might become available. OTOH once all clocks are enabled this is a permanent error. There is no ECLOCKTOOSLOW error code. Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/dht11.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 91976e06f1c6..1165b1c4f9d6 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -89,23 +90,11 @@ static unsigned char dht11_decode_byte(int *timing, int threshold) return ret; } -static int dht11_decode(struct dht11 *dht11, int offset) +static int dht11_decode(struct dht11 *dht11, int offset, int timeres) { - int i, t, timing[DHT11_BITS_PER_READ], threshold, - timeres = DHT11_SENSOR_RESPONSE; + int i, t, timing[DHT11_BITS_PER_READ], threshold; unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum; - /* Calculate timestamp resolution */ - for (i = 1; i < dht11->num_edges; ++i) { - t = dht11->edges[i].ts - dht11->edges[i - 1].ts; - if (t > 0 && t < timeres) - timeres = t; - } - if (2 * timeres > DHT11_DATA_BIT_HIGH) { - pr_err("dht11: timeresolution %d too bad for decoding\n", - timeres); - return -EIO; - } threshold = DHT11_DATA_BIT_HIGH / timeres; if (DHT11_DATA_BIT_LOW / timeres + 1 >= threshold) pr_err("dht11: WARNING: decoding ambiguous\n"); @@ -128,7 +117,7 @@ static int dht11_decode(struct dht11 *dht11, int offset) if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum) return -EIO; - dht11->timestamp = iio_get_time_ns(); + dht11->timestamp = ktime_get_real_ns(); if (hum_int < 20) { /* DHT22 */ dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) * ((temp_int & 0x80) ? -100 : 100); @@ -156,7 +145,7 @@ static irqreturn_t dht11_handle_irq(int irq, void *data) /* TODO: Consider making the handler safe for IRQ sharing */ if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) { - dht11->edges[dht11->num_edges].ts = iio_get_time_ns(); + dht11->edges[dht11->num_edges].ts = ktime_get_real_ns(); dht11->edges[dht11->num_edges++].value = gpio_get_value(dht11->gpio); @@ -172,10 +161,22 @@ static int dht11_read_raw(struct iio_dev *iio_dev, int *val, int *val2, long m) { struct dht11 *dht11 = iio_priv(iio_dev); - int ret; + int ret, timeres; mutex_lock(&dht11->lock); - if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) { + if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_real_ns()) { + timeres = ktime_get_resolution_ns(); + if (DHT11_DATA_BIT_HIGH < 2 * timeres) { + dev_err(dht11->dev, "timeresolution %dns too low\n", + timeres); + /* In theory a better clock could become available + * at some point ... and there is no error code + * that really fits better. + */ + ret = -EAGAIN; + goto err; + } + reinit_completion(&dht11->completion); dht11->num_edges = 0; @@ -210,7 +211,8 @@ static int dht11_read_raw(struct iio_dev *iio_dev, ret = dht11_decode(dht11, dht11->num_edges == DHT11_EDGES_PER_READ ? DHT11_EDGES_PREAMBLE : - DHT11_EDGES_PREAMBLE - 2); + DHT11_EDGES_PREAMBLE - 2, + timeres); if (ret) goto err; } @@ -277,7 +279,7 @@ static int dht11_probe(struct platform_device *pdev) return -EINVAL; } - dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1; + dht11->timestamp = ktime_get_real_ns() - DHT11_DATA_VALID_TIME - 1; dht11->num_edges = -1; platform_set_drvdata(pdev, iio); -- cgit v1.3-6-gb490 From 94a9b7b1809f56cfaa080e70ec49b6979563a237 Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Thu, 2 Jul 2015 17:27:58 -0500 Subject: iio: light: add support for TI's opt3001 light sensor TI's opt3001 light sensor is a simple and yet powerful little device. The device provides 99% IR rejection, automatic full-scale, very low power consumption and measurements from 0.01 to 83k lux. This patch adds support for that device using the IIO framework. See http://www.ti.com/product/opt3001 for more information. Signed-off-by: Felipe Balbi Signed-off-by: Andreas Dannenberg Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 10 + drivers/iio/light/Makefile | 1 + drivers/iio/light/opt3001.c | 804 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 815 insertions(+) create mode 100644 drivers/iio/light/opt3001.c (limited to 'drivers') diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 730fa80c83ea..5c0854a7e3e0 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -209,6 +209,16 @@ config LTR501 This driver can also be built as a module. If so, the module will be called ltr501. +config OPT3001 + tristate "Texas Instruments OPT3001 Light Sensor" + depends on I2C + help + If you say Y or M here, you get support for Texas Instruments + OPT3001 Ambient Light Sensor. + + If built as a dynamically linked module, it will be called + opt3001. + config STK3310 tristate "STK3310 ALS and proximity sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index adf97237db72..5345969f7000 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_ISL29125) += isl29125.o obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_LTR501) += ltr501.o +obj-$(CONFIG_OPT3001) += opt3001.o obj-$(CONFIG_RPR0521) += rpr0521.o obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_STK3310) += stk3310.o diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c new file mode 100644 index 000000000000..923aa6aef0ed --- /dev/null +++ b/drivers/iio/light/opt3001.c @@ -0,0 +1,804 @@ +/** + * opt3001.c - Texas Instruments OPT3001 Light Sensor + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Andreas Dannenberg + * Based on previous work from: Felipe Balbi + * + * 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. + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#define OPT3001_RESULT 0x00 +#define OPT3001_CONFIGURATION 0x01 +#define OPT3001_LOW_LIMIT 0x02 +#define OPT3001_HIGH_LIMIT 0x03 +#define OPT3001_MANUFACTURER_ID 0x7e +#define OPT3001_DEVICE_ID 0x7f + +#define OPT3001_CONFIGURATION_RN_MASK (0xf << 12) +#define OPT3001_CONFIGURATION_RN_AUTO (0xc << 12) + +#define OPT3001_CONFIGURATION_CT BIT(11) + +#define OPT3001_CONFIGURATION_M_MASK (3 << 9) +#define OPT3001_CONFIGURATION_M_SHUTDOWN (0 << 9) +#define OPT3001_CONFIGURATION_M_SINGLE (1 << 9) +#define OPT3001_CONFIGURATION_M_CONTINUOUS (2 << 9) /* also 3 << 9 */ + +#define OPT3001_CONFIGURATION_OVF BIT(8) +#define OPT3001_CONFIGURATION_CRF BIT(7) +#define OPT3001_CONFIGURATION_FH BIT(6) +#define OPT3001_CONFIGURATION_FL BIT(5) +#define OPT3001_CONFIGURATION_L BIT(4) +#define OPT3001_CONFIGURATION_POL BIT(3) +#define OPT3001_CONFIGURATION_ME BIT(2) + +#define OPT3001_CONFIGURATION_FC_MASK (3 << 0) + +/* The end-of-conversion enable is located in the low-limit register */ +#define OPT3001_LOW_LIMIT_EOC_ENABLE 0xc000 + +#define OPT3001_REG_EXPONENT(n) ((n) >> 12) +#define OPT3001_REG_MANTISSA(n) ((n) & 0xfff) + +/* + * Time to wait for conversion result to be ready. The device datasheet + * worst-case max value is 880ms. Add some slack to be on the safe side. + */ +#define OPT3001_RESULT_READY_TIMEOUT msecs_to_jiffies(1000) + +struct opt3001 { + struct i2c_client *client; + struct device *dev; + + struct mutex lock; + u16 ok_to_ignore_lock:1; + u16 result_ready:1; + wait_queue_head_t result_ready_queue; + u16 result; + + u32 int_time; + u32 mode; + + u16 high_thresh_mantissa; + u16 low_thresh_mantissa; + + u8 high_thresh_exp; + u8 low_thresh_exp; +}; + +struct opt3001_scale { + int val; + int val2; +}; + +static const struct opt3001_scale opt3001_scales[] = { + { + .val = 40, + .val2 = 950000, + }, + { + .val = 81, + .val2 = 900000, + }, + { + .val = 163, + .val2 = 800000, + }, + { + .val = 327, + .val2 = 600000, + }, + { + .val = 655, + .val2 = 200000, + }, + { + .val = 1310, + .val2 = 400000, + }, + { + .val = 2620, + .val2 = 800000, + }, + { + .val = 5241, + .val2 = 600000, + }, + { + .val = 10483, + .val2 = 200000, + }, + { + .val = 20966, + .val2 = 400000, + }, + { + .val = 83865, + .val2 = 600000, + }, +}; + +static int opt3001_find_scale(const struct opt3001 *opt, int val, + int val2, u8 *exponent) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(opt3001_scales); i++) { + const struct opt3001_scale *scale = &opt3001_scales[i]; + + /* + * Combine the integer and micro parts for comparison + * purposes. Use milli lux precision to avoid 32-bit integer + * overflows. + */ + if ((val * 1000 + val2 / 1000) <= + (scale->val * 1000 + scale->val2 / 1000)) { + *exponent = i; + return 0; + } + } + + return -EINVAL; +} + +static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent, + u16 mantissa, int *val, int *val2) +{ + int lux; + + lux = 10 * (mantissa << exponent); + *val = lux / 1000; + *val2 = (lux - (*val * 1000)) * 1000; +} + +static void opt3001_set_mode(struct opt3001 *opt, u16 *reg, u16 mode) +{ + *reg &= ~OPT3001_CONFIGURATION_M_MASK; + *reg |= mode; + opt->mode = mode; +} + +static IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.8"); + +static struct attribute *opt3001_attributes[] = { + &iio_const_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group opt3001_attribute_group = { + .attrs = opt3001_attributes, +}; + +static const struct iio_event_spec opt3001_event_spec[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct iio_chan_spec opt3001_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_INT_TIME), + .event_spec = opt3001_event_spec, + .num_event_specs = ARRAY_SIZE(opt3001_event_spec), + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static int opt3001_get_lux(struct opt3001 *opt, int *val, int *val2) +{ + int ret; + u16 mantissa; + u16 reg; + u8 exponent; + u16 value; + + /* + * Enable the end-of-conversion interrupt mechanism. Note that doing + * so will overwrite the low-level limit value however we will restore + * this value later on. + */ + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT, + OPT3001_LOW_LIMIT_EOC_ENABLE); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_LOW_LIMIT); + return ret; + } + + /* Reset data-ready indicator flag (will be set in the IRQ routine) */ + opt->result_ready = false; + + /* Allow IRQ to access the device despite lock being set */ + opt->ok_to_ignore_lock = true; + + /* Configure for single-conversion mode and start a new conversion */ + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + + reg = ret; + opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SINGLE); + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + + /* Wait for the IRQ to indicate the conversion is complete */ + ret = wait_event_timeout(opt->result_ready_queue, opt->result_ready, + OPT3001_RESULT_READY_TIMEOUT); + +err: + /* Disallow IRQ to access the device while lock is active */ + opt->ok_to_ignore_lock = false; + + if (ret == 0) + return -ETIMEDOUT; + else if (ret < 0) + return ret; + + /* + * Disable the end-of-conversion interrupt mechanism by restoring the + * low-level limit value (clearing OPT3001_LOW_LIMIT_EOC_ENABLE). Note + * that selectively clearing those enable bits would affect the actual + * limit value due to bit-overlap and therefore can't be done. + */ + value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa; + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT, + value); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_LOW_LIMIT); + return ret; + } + + exponent = OPT3001_REG_EXPONENT(opt->result); + mantissa = OPT3001_REG_MANTISSA(opt->result); + + opt3001_to_iio_ret(opt, exponent, mantissa, val, val2); + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int opt3001_get_int_time(struct opt3001 *opt, int *val, int *val2) +{ + *val = 0; + *val2 = opt->int_time; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int opt3001_set_int_time(struct opt3001 *opt, int time) +{ + int ret; + u16 reg; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + reg = ret; + + switch (time) { + case 100000: + reg &= ~OPT3001_CONFIGURATION_CT; + opt->int_time = 100000; + break; + case 800000: + reg |= OPT3001_CONFIGURATION_CT; + opt->int_time = 800000; + break; + default: + return -EINVAL; + } + + return i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); +} + +static int opt3001_read_raw(struct iio_dev *iio, + struct iio_chan_spec const *chan, int *val, int *val2, + long mask) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + + if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) + return -EBUSY; + + if (chan->type != IIO_LIGHT) + return -EINVAL; + + mutex_lock(&opt->lock); + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + ret = opt3001_get_lux(opt, val, val2); + break; + case IIO_CHAN_INFO_INT_TIME: + ret = opt3001_get_int_time(opt, val, val2); + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_write_raw(struct iio_dev *iio, + struct iio_chan_spec const *chan, int val, int val2, + long mask) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + + if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) + return -EBUSY; + + if (chan->type != IIO_LIGHT) + return -EINVAL; + + if (mask != IIO_CHAN_INFO_INT_TIME) + return -EINVAL; + + if (val != 0) + return -EINVAL; + + mutex_lock(&opt->lock); + ret = opt3001_set_int_time(opt, val2); + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_read_event_value(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int *val, int *val2) +{ + struct opt3001 *opt = iio_priv(iio); + int ret = IIO_VAL_INT_PLUS_MICRO; + + mutex_lock(&opt->lock); + + switch (dir) { + case IIO_EV_DIR_RISING: + opt3001_to_iio_ret(opt, opt->high_thresh_exp, + opt->high_thresh_mantissa, val, val2); + break; + case IIO_EV_DIR_FALLING: + opt3001_to_iio_ret(opt, opt->low_thresh_exp, + opt->low_thresh_mantissa, val, val2); + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_write_event_value(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int val, int val2) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + + u16 mantissa; + u16 value; + u16 reg; + + u8 exponent; + + if (val < 0) + return -EINVAL; + + mutex_lock(&opt->lock); + + ret = opt3001_find_scale(opt, val, val2, &exponent); + if (ret < 0) { + dev_err(opt->dev, "can't find scale for %d.%06u\n", val, val2); + goto err; + } + + mantissa = (((val * 1000) + (val2 / 1000)) / 10) >> exponent; + value = (exponent << 12) | mantissa; + + switch (dir) { + case IIO_EV_DIR_RISING: + reg = OPT3001_HIGH_LIMIT; + opt->high_thresh_mantissa = mantissa; + opt->high_thresh_exp = exponent; + break; + case IIO_EV_DIR_FALLING: + reg = OPT3001_LOW_LIMIT; + opt->low_thresh_mantissa = mantissa; + opt->low_thresh_exp = exponent; + break; + default: + ret = -EINVAL; + goto err; + } + + ret = i2c_smbus_write_word_swapped(opt->client, reg, value); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", reg); + goto err; + } + +err: + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_read_event_config(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir) +{ + struct opt3001 *opt = iio_priv(iio); + + return opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS; +} + +static int opt3001_write_event_config(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + u16 mode; + u16 reg; + + if (state && opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) + return 0; + + if (!state && opt->mode == OPT3001_CONFIGURATION_M_SHUTDOWN) + return 0; + + mutex_lock(&opt->lock); + + mode = state ? OPT3001_CONFIGURATION_M_CONTINUOUS + : OPT3001_CONFIGURATION_M_SHUTDOWN; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + + reg = ret; + opt3001_set_mode(opt, ®, mode); + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + +err: + mutex_unlock(&opt->lock); + + return ret; +} + +static const struct iio_info opt3001_info = { + .driver_module = THIS_MODULE, + .attrs = &opt3001_attribute_group, + .read_raw = opt3001_read_raw, + .write_raw = opt3001_write_raw, + .read_event_value = opt3001_read_event_value, + .write_event_value = opt3001_write_event_value, + .read_event_config = opt3001_read_event_config, + .write_event_config = opt3001_write_event_config, +}; + +static int opt3001_read_id(struct opt3001 *opt) +{ + char manufacturer[2]; + u16 device_id; + int ret; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_MANUFACTURER_ID); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_MANUFACTURER_ID); + return ret; + } + + manufacturer[0] = ret >> 8; + manufacturer[1] = ret & 0xff; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_DEVICE_ID); + return ret; + } + + device_id = ret; + + dev_info(opt->dev, "Found %c%c OPT%04x\n", manufacturer[0], + manufacturer[1], device_id); + + return 0; +} + +static int opt3001_configure(struct opt3001 *opt) +{ + int ret; + u16 reg; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + reg = ret; + + /* Enable automatic full-scale setting mode */ + reg &= ~OPT3001_CONFIGURATION_RN_MASK; + reg |= OPT3001_CONFIGURATION_RN_AUTO; + + /* Reflect status of the device's integration time setting */ + if (reg & OPT3001_CONFIGURATION_CT) + opt->int_time = 800000; + else + opt->int_time = 100000; + + /* Ensure device is in shutdown initially */ + opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SHUTDOWN); + + /* Configure for latched window-style comparison operation */ + reg |= OPT3001_CONFIGURATION_L; + reg &= ~OPT3001_CONFIGURATION_POL; + reg &= ~OPT3001_CONFIGURATION_ME; + reg &= ~OPT3001_CONFIGURATION_FC_MASK; + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_LOW_LIMIT); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_LOW_LIMIT); + return ret; + } + + opt->low_thresh_mantissa = OPT3001_REG_MANTISSA(ret); + opt->low_thresh_exp = OPT3001_REG_EXPONENT(ret); + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_HIGH_LIMIT); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_HIGH_LIMIT); + return ret; + } + + opt->high_thresh_mantissa = OPT3001_REG_MANTISSA(ret); + opt->high_thresh_exp = OPT3001_REG_EXPONENT(ret); + + return 0; +} + +static irqreturn_t opt3001_irq(int irq, void *_iio) +{ + struct iio_dev *iio = _iio; + struct opt3001 *opt = iio_priv(iio); + int ret; + + if (!opt->ok_to_ignore_lock) + mutex_lock(&opt->lock); + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + goto out; + } + + if ((ret & OPT3001_CONFIGURATION_M_MASK) == + OPT3001_CONFIGURATION_M_CONTINUOUS) { + if (ret & OPT3001_CONFIGURATION_FH) + iio_push_event(iio, + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns()); + if (ret & OPT3001_CONFIGURATION_FL) + iio_push_event(iio, + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns()); + } else if (ret & OPT3001_CONFIGURATION_CRF) { + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_RESULT); + goto out; + } + opt->result = ret; + opt->result_ready = true; + wake_up(&opt->result_ready_queue); + } + +out: + if (!opt->ok_to_ignore_lock) + mutex_unlock(&opt->lock); + + return IRQ_HANDLED; +} + +static int opt3001_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + + struct iio_dev *iio; + struct opt3001 *opt; + int irq = client->irq; + int ret; + + iio = devm_iio_device_alloc(dev, sizeof(*opt)); + if (!iio) + return -ENOMEM; + + opt = iio_priv(iio); + opt->client = client; + opt->dev = dev; + + mutex_init(&opt->lock); + init_waitqueue_head(&opt->result_ready_queue); + i2c_set_clientdata(client, iio); + + ret = opt3001_read_id(opt); + if (ret) + return ret; + + ret = opt3001_configure(opt); + if (ret) + return ret; + + iio->name = client->name; + iio->channels = opt3001_channels; + iio->num_channels = ARRAY_SIZE(opt3001_channels); + iio->dev.parent = dev; + iio->modes = INDIO_DIRECT_MODE; + iio->info = &opt3001_info; + + ret = devm_iio_device_register(dev, iio); + if (ret) { + dev_err(dev, "failed to register IIO device\n"); + return ret; + } + + ret = request_threaded_irq(irq, NULL, opt3001_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "opt3001", iio); + if (ret) { + dev_err(dev, "failed to request IRQ #%d\n", irq); + return ret; + } + + return 0; +} + +static int opt3001_remove(struct i2c_client *client) +{ + struct iio_dev *iio = i2c_get_clientdata(client); + struct opt3001 *opt = iio_priv(iio); + int ret; + u16 reg; + + free_irq(client->irq, iio); + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + reg = ret; + opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SHUTDOWN); + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + return 0; +} + +static const struct i2c_device_id opt3001_id[] = { + { "opt3001", 0 }, + { } /* Terminating Entry */ +}; +MODULE_DEVICE_TABLE(i2c, opt3001_id); + +static const struct of_device_id opt3001_of_match[] = { + { .compatible = "ti,opt3001" }, + { } +}; + +static struct i2c_driver opt3001_driver = { + .probe = opt3001_probe, + .remove = opt3001_remove, + .id_table = opt3001_id, + + .driver = { + .name = "opt3001", + .of_match_table = of_match_ptr(opt3001_of_match), + .owner = THIS_MODULE, + }, +}; + +module_i2c_driver(opt3001_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Andreas Dannenberg "); +MODULE_DESCRIPTION("Texas Instruments OPT3001 Light Sensor Driver"); -- cgit v1.3-6-gb490 From 8ab6abfca09c1800dccb753775f6ce8ee82f50dd Mon Sep 17 00:00:00 2001 From: Adriana Reus Date: Tue, 7 Jul 2015 14:07:13 +0300 Subject: iio: light: Add support for TXC PA12 als and proximity sensor Add support for TXC PA12203001 als and proximity sensor. Support for raw illuminance and proximity readings. Signed-off-by: Adriana Reus Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 11 + drivers/iio/light/Makefile | 1 + drivers/iio/light/pa12203001.c | 483 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 495 insertions(+) create mode 100644 drivers/iio/light/pa12203001.c (limited to 'drivers') diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 5c0854a7e3e0..a459341a79f9 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -219,6 +219,17 @@ config OPT3001 If built as a dynamically linked module, it will be called opt3001. +config PA12203001 + tristate "TXC PA12203001 light and proximity sensor" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the TXC PA12203001 + ambient light and proximity sensor. + + This driver can also be built as a module. If so, the module + will be called pa12203001. + config STK3310 tristate "STK3310 ALS and proximity sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 5345969f7000..91c74c014b6f 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_LTR501) += ltr501.o obj-$(CONFIG_OPT3001) += opt3001.o +obj-$(CONFIG_PA12203001) += pa12203001.o obj-$(CONFIG_RPR0521) += rpr0521.o obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_STK3310) += stk3310.o diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c new file mode 100644 index 000000000000..45f7bde02bbf --- /dev/null +++ b/drivers/iio/light/pa12203001.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2015 Intel Corporation + * + * Driver for TXC PA12203001 Proximity and Ambient Light Sensor. + * + * 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. + * To do: Interrupt support. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PA12203001_DRIVER_NAME "pa12203001" + +#define PA12203001_REG_CFG0 0x00 +#define PA12203001_REG_CFG1 0x01 +#define PA12203001_REG_CFG2 0x02 +#define PA12203001_REG_CFG3 0x03 + +#define PA12203001_REG_ADL 0x0b +#define PA12203001_REG_PDH 0x0e + +#define PA12203001_REG_POFS 0x10 +#define PA12203001_REG_PSET 0x11 + +#define PA12203001_ALS_EN_MASK BIT(0) +#define PA12203001_PX_EN_MASK BIT(1) +#define PA12203001_PX_NORMAL_MODE_MASK GENMASK(7, 6) +#define PA12203001_AFSR_MASK GENMASK(5, 4) +#define PA12203001_AFSR_SHIFT 4 + +#define PA12203001_PSCAN 0x03 + +/* als range 31000, ps, als disabled */ +#define PA12203001_REG_CFG0_DEFAULT 0x30 + +/* led current: 100 mA */ +#define PA12203001_REG_CFG1_DEFAULT 0x20 + +/* ps mode: normal, interrupts not active */ +#define PA12203001_REG_CFG2_DEFAULT 0xcc + +#define PA12203001_REG_CFG3_DEFAULT 0x00 + +#define PA12203001_SLEEP_DELAY_MS 3000 + +#define PA12203001_CHIP_ENABLE 0xff +#define PA12203001_CHIP_DISABLE 0x00 + +/* available scales: corresponding to [500, 4000, 7000, 31000] lux */ +static const int pa12203001_scales[] = { 7629, 61036, 106813, 473029}; + +struct pa12203001_data { + struct i2c_client *client; + + /* protect device states */ + struct mutex lock; + + bool als_enabled; + bool px_enabled; + bool als_needs_enable; + bool px_needs_enable; + + struct regmap *map; +}; + +static const struct { + u8 reg; + u8 val; +} regvals[] = { + {PA12203001_REG_CFG0, PA12203001_REG_CFG0_DEFAULT}, + {PA12203001_REG_CFG1, PA12203001_REG_CFG1_DEFAULT}, + {PA12203001_REG_CFG2, PA12203001_REG_CFG2_DEFAULT}, + {PA12203001_REG_CFG3, PA12203001_REG_CFG3_DEFAULT}, + {PA12203001_REG_PSET, PA12203001_PSCAN}, +}; + +static IIO_CONST_ATTR(in_illuminance_scale_available, + "0.007629 0.061036 0.106813 0.473029"); + +static struct attribute *pa12203001_attrs[] = { + &iio_const_attr_in_illuminance_scale_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group pa12203001_attr_group = { + .attrs = pa12203001_attrs, +}; + +static const struct iio_chan_spec pa12203001_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_PROXIMITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + } +}; + +static const struct regmap_range pa12203001_volatile_regs_ranges[] = { + regmap_reg_range(PA12203001_REG_ADL, PA12203001_REG_ADL + 1), + regmap_reg_range(PA12203001_REG_PDH, PA12203001_REG_PDH), +}; + +static const struct regmap_access_table pa12203001_volatile_regs = { + .yes_ranges = pa12203001_volatile_regs_ranges, + .n_yes_ranges = ARRAY_SIZE(pa12203001_volatile_regs_ranges), +}; + +static const struct regmap_config pa12203001_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = PA12203001_REG_PSET, + .cache_type = REGCACHE_RBTREE, + .volatile_table = &pa12203001_volatile_regs, +}; + +static inline int pa12203001_als_enable(struct pa12203001_data *data, u8 enable) +{ + int ret; + + ret = regmap_update_bits(data->map, PA12203001_REG_CFG0, + PA12203001_ALS_EN_MASK, enable); + if (ret < 0) + return ret; + + data->als_enabled = !!enable; + + return 0; +} + +static inline int pa12203001_px_enable(struct pa12203001_data *data, u8 enable) +{ + int ret; + + ret = regmap_update_bits(data->map, PA12203001_REG_CFG0, + PA12203001_PX_EN_MASK, enable); + if (ret < 0) + return ret; + + data->px_enabled = !!enable; + + return 0; +} + +static int pa12203001_set_power_state(struct pa12203001_data *data, bool on, + u8 mask) +{ +#ifdef CONFIG_PM + int ret; + + if (on && (mask & PA12203001_ALS_EN_MASK)) { + mutex_lock(&data->lock); + if (data->px_enabled) { + ret = pa12203001_als_enable(data, + PA12203001_ALS_EN_MASK); + if (ret < 0) + goto err; + } else { + data->als_needs_enable = true; + } + mutex_unlock(&data->lock); + } + + if (on && (mask & PA12203001_PX_EN_MASK)) { + mutex_lock(&data->lock); + if (data->als_enabled) { + ret = pa12203001_px_enable(data, PA12203001_PX_EN_MASK); + if (ret < 0) + goto err; + } else { + data->px_needs_enable = true; + } + mutex_unlock(&data->lock); + } + + if (on) { + ret = pm_runtime_get_sync(&data->client->dev); + if (ret < 0) + pm_runtime_put_noidle(&data->client->dev); + + } else { + pm_runtime_mark_last_busy(&data->client->dev); + ret = pm_runtime_put_autosuspend(&data->client->dev); + } + + return ret; + +err: + mutex_unlock(&data->lock); + return ret; + +#endif + return 0; +} + +static int pa12203001_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int ret; + u8 dev_mask; + unsigned int reg_byte; + __le16 reg_word; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_LIGHT: + dev_mask = PA12203001_ALS_EN_MASK; + ret = pa12203001_set_power_state(data, true, dev_mask); + if (ret < 0) + return ret; + /* + * ALS ADC value is stored in registers + * PA12203001_REG_ADL and in PA12203001_REG_ADL + 1. + */ + ret = regmap_bulk_read(data->map, PA12203001_REG_ADL, + ®_word, 2); + if (ret < 0) + goto reg_err; + + *val = le16_to_cpu(reg_word); + ret = pa12203001_set_power_state(data, false, dev_mask); + if (ret < 0) + return ret; + break; + case IIO_PROXIMITY: + dev_mask = PA12203001_PX_EN_MASK; + ret = pa12203001_set_power_state(data, true, dev_mask); + if (ret < 0) + return ret; + ret = regmap_read(data->map, PA12203001_REG_PDH, + ®_byte); + if (ret < 0) + goto reg_err; + + *val = reg_byte; + ret = pa12203001_set_power_state(data, false, dev_mask); + if (ret < 0) + return ret; + break; + default: + return -EINVAL; + } + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = regmap_read(data->map, PA12203001_REG_CFG0, ®_byte); + if (ret < 0) + return ret; + *val = 0; + reg_byte = (reg_byte & PA12203001_AFSR_MASK); + *val2 = pa12203001_scales[reg_byte >> 4]; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + +reg_err: + pa12203001_set_power_state(data, false, dev_mask); + return ret; +} + +static int pa12203001_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int i, ret, new_val; + unsigned int reg_byte; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + ret = regmap_read(data->map, PA12203001_REG_CFG0, ®_byte); + if (val != 0 || ret < 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(pa12203001_scales); i++) { + if (val2 == pa12203001_scales[i]) { + new_val = i << PA12203001_AFSR_SHIFT; + return regmap_update_bits(data->map, + PA12203001_REG_CFG0, + PA12203001_AFSR_MASK, + new_val); + } + } + break; + default: + break; + } + + return -EINVAL; +} + +static const struct iio_info pa12203001_info = { + .driver_module = THIS_MODULE, + .read_raw = pa12203001_read_raw, + .write_raw = pa12203001_write_raw, + .attrs = &pa12203001_attr_group, +}; + +static int pa12203001_init(struct iio_dev *indio_dev) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int i, ret; + + for (i = 0; i < ARRAY_SIZE(regvals); i++) { + ret = regmap_write(data->map, regvals[i].reg, regvals[i].val); + if (ret < 0) + return ret; + } + + return 0; +} + +static int pa12203001_power_chip(struct iio_dev *indio_dev, u8 state) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->lock); + ret = pa12203001_als_enable(data, state); + if (ret < 0) + goto out; + + ret = pa12203001_px_enable(data, state); + +out: + mutex_unlock(&data->lock); + return ret; +} + +static int pa12203001_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pa12203001_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, + sizeof(struct pa12203001_data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + data->map = devm_regmap_init_i2c(client, &pa12203001_regmap_config); + if (IS_ERR(data->map)) + return PTR_ERR(data->map); + + mutex_init(&data->lock); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &pa12203001_info; + indio_dev->name = PA12203001_DRIVER_NAME; + indio_dev->channels = pa12203001_channels; + indio_dev->num_channels = ARRAY_SIZE(pa12203001_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = pa12203001_init(indio_dev); + if (ret < 0) + return ret; + + ret = pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE); + if (ret < 0) + return ret; + + ret = pm_runtime_set_active(&client->dev); + if (ret < 0) { + pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE); + return ret; + } + + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, + PA12203001_SLEEP_DELAY_MS); + pm_runtime_use_autosuspend(&client->dev); + + return iio_device_register(indio_dev); +} + +static int pa12203001_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + + return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE); +} + +#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM) +static int pa12203001_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + + return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE); +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int pa12203001_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + + return pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE); +} +#endif + +#ifdef CONFIG_PM +static int pa12203001_runtime_resume(struct device *dev) +{ + struct pa12203001_data *data; + + data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); + + mutex_lock(&data->lock); + if (data->als_needs_enable) { + pa12203001_als_enable(data, PA12203001_ALS_EN_MASK); + data->als_needs_enable = false; + } + if (data->px_needs_enable) { + pa12203001_px_enable(data, PA12203001_PX_EN_MASK); + data->px_needs_enable = false; + } + mutex_unlock(&data->lock); + + return 0; +} +#endif + +static const struct dev_pm_ops pa12203001_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pa12203001_suspend, pa12203001_resume) + SET_RUNTIME_PM_OPS(pa12203001_suspend, pa12203001_runtime_resume, NULL) +}; + +static const struct acpi_device_id pa12203001_acpi_match[] = { + { "TXCPA122", 0}, + {} +}; + +MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match); + +static const struct i2c_device_id pa12203001_id[] = { + {"txcpa122", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pa12203001_id); + +static struct i2c_driver pa12203001_driver = { + .driver = { + .name = PA12203001_DRIVER_NAME, + .pm = &pa12203001_pm_ops, + .acpi_match_table = ACPI_PTR(pa12203001_acpi_match), + }, + .probe = pa12203001_probe, + .remove = pa12203001_remove, + .id_table = pa12203001_id, + +}; +module_i2c_driver(pa12203001_driver); + +MODULE_AUTHOR("Adriana Reus "); +MODULE_DESCRIPTION("Driver for TXC PA12203001 Proximity and Light Sensor"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From 038761dfe4ce145f0f080cc08ee43f6e0ab3ae2f Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 2 Jul 2015 11:37:56 +0200 Subject: mtd: fsl-quadspi: Actually clear TX FIFO upon write QUADSPI_MCR_CLR_TXF_MASK is the correct mask for clearing the TX FIFO. Signed-off-by: Alexander Stein Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 4fe13dd535f8..1946c6da76cd 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -539,7 +539,7 @@ static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, /* clear the TX FIFO. */ tmp = readl(q->iobase + QUADSPI_MCR); - writel(tmp | QUADSPI_MCR_CLR_RXF_MASK, q->iobase + QUADSPI_MCR); + writel(tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR); /* fill the TX data to the FIFO */ for (j = 0, i = ((count + 3) / 4); j < i; j++) { -- cgit v1.3-6-gb490 From 0db7fae2736d0db920905c1fb576ec7eab2660c8 Mon Sep 17 00:00:00 2001 From: Alexey Firago Date: Tue, 30 Jun 2015 12:53:46 +0300 Subject: mtd: spi-nor: set SECT_4K for n25q064 SPI flash Micron n25q064 flash supports 4 KiB erase sectors. Signed-off-by: Alexey Firago Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d78831b4422b..b2e8c3b72ea1 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -589,7 +589,7 @@ static const struct spi_device_id spi_nor_ids[] = { /* Micron */ { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, - { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SPI_NOR_QUAD_READ) }, + { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, -- cgit v1.3-6-gb490 From d3dc5430d68fb91a62d971648170b34d46ab85bc Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 23 Jun 2015 14:32:55 +0100 Subject: regmap: debugfs: Allow writes to cache state settings Allow the user to write the cache_only and cache_bypass settings. This can be useful for debugging. Since this can lead to the hardware getting out-of-sync with the cache, at least for the period that the cache state is forced, the kernel is tainted and the action is recorded in the kernel log. When disabling cache_only through debugfs a cache sync will be performed. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-debugfs.c | 90 ++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 5799a0b9e6cc..6a61e4fa73a2 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -469,6 +469,87 @@ static const struct file_operations regmap_access_fops = { .llseek = default_llseek, }; +static ssize_t regmap_cache_only_write_file(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct regmap *map = container_of(file->private_data, + struct regmap, cache_only); + ssize_t result; + bool was_enabled, require_sync = false; + int err; + + map->lock(map->lock_arg); + + was_enabled = map->cache_only; + + result = debugfs_write_file_bool(file, user_buf, count, ppos); + if (result < 0) { + map->unlock(map->lock_arg); + return result; + } + + if (map->cache_only && !was_enabled) { + dev_warn(map->dev, "debugfs cache_only=Y forced\n"); + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + } else if (!map->cache_only && was_enabled) { + dev_warn(map->dev, "debugfs cache_only=N forced: syncing cache\n"); + require_sync = true; + } + + map->unlock(map->lock_arg); + + if (require_sync) { + err = regcache_sync(map); + if (err) + dev_err(map->dev, "Failed to sync cache %d\n", err); + } + + return result; +} + +static const struct file_operations regmap_cache_only_fops = { + .open = simple_open, + .read = debugfs_read_file_bool, + .write = regmap_cache_only_write_file, +}; + +static ssize_t regmap_cache_bypass_write_file(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct regmap *map = container_of(file->private_data, + struct regmap, cache_bypass); + ssize_t result; + bool was_enabled; + + map->lock(map->lock_arg); + + was_enabled = map->cache_bypass; + + result = debugfs_write_file_bool(file, user_buf, count, ppos); + if (result < 0) + goto out; + + if (map->cache_bypass && !was_enabled) { + dev_warn(map->dev, "debugfs cache_bypass=Y forced\n"); + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + } else if (!map->cache_bypass && was_enabled) { + dev_warn(map->dev, "debugfs cache_bypass=N forced\n"); + } + +out: + map->unlock(map->lock_arg); + + return result; +} + +static const struct file_operations regmap_cache_bypass_fops = { + .open = simple_open, + .read = debugfs_read_file_bool, + .write = regmap_cache_bypass_write_file, +}; + void regmap_debugfs_init(struct regmap *map, const char *name) { struct rb_node *next; @@ -530,12 +611,13 @@ void regmap_debugfs_init(struct regmap *map, const char *name) } if (map->cache_type) { - debugfs_create_bool("cache_only", 0400, map->debugfs, - &map->cache_only); + debugfs_create_file("cache_only", 0600, map->debugfs, + &map->cache_only, ®map_cache_only_fops); debugfs_create_bool("cache_dirty", 0400, map->debugfs, &map->cache_dirty); - debugfs_create_bool("cache_bypass", 0400, map->debugfs, - &map->cache_bypass); + debugfs_create_file("cache_bypass", 0600, map->debugfs, + &map->cache_bypass, + ®map_cache_bypass_fops); } next = rb_first(&map->range_tree); -- cgit v1.3-6-gb490 From 9c618292dba6aa9b82e8a2e4e6fe70f54bd87a81 Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Fri, 26 Jun 2015 11:00:10 +0200 Subject: mtd: nand: sunxi: Replace failsafe timing cfg with calculated value The TIMING_CFG register was previously statically set to a magic value (extracted from Allwinner's BSP) when initializing the NAND controller. Now that we have more details about the TIMING_CFG register layout (extracted from the A83 user manual) we can dynamically calculate the appropriate value for each NAND chip and set it when selecting the chip. Signed-off-by: Roy Spliet Acked-by: Boris Brezillon Signed-off-by: Brian Norris --- drivers/mtd/nand/sunxi_nand.c | 73 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index 6f93b2990d25..663e3314bb83 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -99,6 +99,12 @@ NFC_CMD_INT_ENABLE | \ NFC_DMA_INT_ENABLE) +/* define NFC_TIMING_CFG register layout */ +#define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD) \ + (((tWB) & 0x3) | (((tADL) & 0x3) << 2) | \ + (((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) | \ + (((tCAD) & 0x7) << 8)) + /* define bit use in NFC_CMD */ #define NFC_CMD_LOW_BYTE GENMASK(7, 0) #define NFC_CMD_HIGH_BYTE GENMASK(15, 8) @@ -208,6 +214,7 @@ struct sunxi_nand_hw_ecc { * @nand: base NAND chip structure * @mtd: base MTD structure * @clk_rate: clk_rate required for this NAND chip + * @timing_cfg TIMING_CFG register value for this NAND chip * @selected: current active CS * @nsels: number of CS lines required by the NAND chip * @sels: array of CS lines descriptions @@ -217,6 +224,7 @@ struct sunxi_nand_chip { struct nand_chip nand; struct mtd_info mtd; unsigned long clk_rate; + u32 timing_cfg; int selected; int nsels; struct sunxi_nand_chip_sel sels[0]; @@ -403,6 +411,7 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) } } + writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG); writel(ctl, nfc->regs + NFC_REG_CTL); sunxi_nand->selected = chip; @@ -807,10 +816,33 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, return 0; } +static const s32 tWB_lut[] = {6, 12, 16, 20}; +static const s32 tRHW_lut[] = {4, 8, 12, 20}; + +static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, + u32 clk_period) +{ + u32 clk_cycles = DIV_ROUND_UP(duration, clk_period); + int i; + + for (i = 0; i < lut_size; i++) { + if (clk_cycles <= lut[i]) + return i; + } + + /* Doesn't fit */ + return -EINVAL; +} + +#define sunxi_nand_lookup_timing(l, p, c) \ + _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) + static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, const struct nand_sdr_timings *timings) { + struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller); u32 min_clk_period = 0; + s32 tWB, tADL, tWHR, tRHW, tCAD; /* T1 <=> tCLS */ if (timings->tCLS_min > min_clk_period) @@ -872,6 +904,41 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, if (timings->tWC_min > (min_clk_period * 2)) min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2); + /* T16 - T19 + tCAD */ + tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max, + min_clk_period); + if (tWB < 0) { + dev_err(nfc->dev, "unsupported tWB\n"); + return tWB; + } + + tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3; + if (tADL > 3) { + dev_err(nfc->dev, "unsupported tADL\n"); + return -EINVAL; + } + + tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3; + if (tWHR > 3) { + dev_err(nfc->dev, "unsupported tWHR\n"); + return -EINVAL; + } + + tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min, + min_clk_period); + if (tRHW < 0) { + dev_err(nfc->dev, "unsupported tRHW\n"); + return tRHW; + } + + /* + * TODO: according to ONFI specs this value only applies for DDR NAND, + * but Allwinner seems to set this to 0x7. Mimic them for now. + */ + tCAD = 0x7; + + /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */ + chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); /* Convert min_clk_period from picoseconds to nanoseconds */ min_clk_period = DIV_ROUND_UP(min_clk_period, 1000); @@ -884,8 +951,6 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, */ chip->clk_rate = (2 * NSEC_PER_SEC) / min_clk_period; - /* TODO: configure T16-T19 */ - return 0; } @@ -1377,11 +1442,9 @@ static int sunxi_nfc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, nfc); /* - * TODO: replace these magic values with proper flags as soon as we - * know what they are encoding. + * TODO: replace this magic value with EDO flag */ writel(0x100, nfc->regs + NFC_REG_TIMING_CTL); - writel(0x7ff, nfc->regs + NFC_REG_TIMING_CFG); ret = sunxi_nand_chips_init(dev, nfc); if (ret) { -- cgit v1.3-6-gb490 From d052e508a4069f0711ea68156f4b1565bf14c41c Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Fri, 26 Jun 2015 11:00:11 +0200 Subject: mtd: nand: sunxi: Set serial access mode correctly Replaces the hard coded "always use EDO" policy with that prescribed by the ONFI 3.1 specification that EDO mode should always be used if tRC is below 30ns. Signed-off-by: Roy Spliet Acked-by: Boris Brezillon Signed-off-by: Brian Norris --- drivers/mtd/nand/sunxi_nand.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index 663e3314bb83..f97a58d6aae1 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -99,6 +99,9 @@ NFC_CMD_INT_ENABLE | \ NFC_DMA_INT_ENABLE) +/* define bit use in NFC_TIMING_CTL */ +#define NFC_TIMING_CTL_EDO BIT(8) + /* define NFC_TIMING_CFG register layout */ #define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD) \ (((tWB) & 0x3) | (((tADL) & 0x3) << 2) | \ @@ -225,6 +228,7 @@ struct sunxi_nand_chip { struct mtd_info mtd; unsigned long clk_rate; u32 timing_cfg; + u32 timing_ctl; int selected; int nsels; struct sunxi_nand_chip_sel sels[0]; @@ -411,6 +415,7 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) } } + writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL); writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG); writel(ctl, nfc->regs + NFC_REG_CTL); @@ -940,6 +945,13 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */ chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); + /* + * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data + * output cycle timings shall be used if the host drives tRC less than + * 30 ns. + */ + chip->timing_ctl = (timings->tRC_min < 30000) ? NFC_TIMING_CTL_EDO : 0; + /* Convert min_clk_period from picoseconds to nanoseconds */ min_clk_period = DIV_ROUND_UP(min_clk_period, 1000); @@ -1441,11 +1453,6 @@ static int sunxi_nfc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, nfc); - /* - * TODO: replace this magic value with EDO flag - */ - writel(0x100, nfc->regs + NFC_REG_TIMING_CTL); - ret = sunxi_nand_chips_init(dev, nfc); if (ret) { dev_err(dev, "failed to init nand chips\n"); -- cgit v1.3-6-gb490 From 10a3402415d7f6e32ca20ebb088e153fe45f807d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: staging: clocking-wizard: Include clk.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This clock provider uses the consumer API, so include clk.h explicitly. Acked-by: Sören Brinkmann Acked-by: Greg Kroah-Hartman Signed-off-by: Stephen Boyd --- drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c index 5455bf3d5a91..b8e2f611fd47 100644 --- a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c +++ b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include -- cgit v1.3-6-gb490 From 0dab7ddeea12243a7bc6753d5360d46f237f76ea Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: spi: spi-pxa2xx: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Cc: Daniel Mack Cc: Haojian Zhuang Cc: Robert Jarzmik Cc: Mark Brown Signed-off-by: Stephen Boyd --- drivers/spi/spi-pxa2xx-pci.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 3cfd4357489a..d19d7f28aecb 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include -- cgit v1.3-6-gb490 From c0cc72efd839acd555d918febe08d91786dbea8d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clocksource: cadence_ttc: Remove clk-provider.h include This file doesn't use the clk provider APIs. Remove the include. Cc: Michal Simek Cc: Daniel Lezcano Signed-off-by: Stephen Boyd --- drivers/clocksource/cadence_ttc_timer.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index 510c8a1d37b3..5ea91e3818d0 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -16,7 +16,6 @@ */ #include -#include #include #include #include -- cgit v1.3-6-gb490 From 887e5a91ac17927f68455d059da2f175b6fbf9d3 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: ACPI: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the includes here because these are a provider drivers. Cc: Ken Xue Cc: Mika Westerberg Cc: Rafael J. Wysocki Signed-off-by: Stephen Boyd --- drivers/acpi/acpi_apd.c | 1 - drivers/acpi/acpi_lpss.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index 3984ea96e5f7..a450e7af877c 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include "internal.h" diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 569ee090343f..6817b18ed722 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include -- cgit v1.3-6-gb490 From d49c699344735507a10ded79713cc5f9fa8bacf0 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: simplefb: Include clk.h This driver uses the consumer API, so include clk.h explicitly instead of impliclty through the provider API. Cc: Luc Verhaegen Cc: Hans de Goede Acked-by: Geert Uytterhoeven Cc: Maxime Ripard Cc: David Herrmann Cc: Tomi Valkeinen Signed-off-by: Stephen Boyd --- drivers/video/fbdev/simplefb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c index 1085c0432158..52c5c7e63b52 100644 --- a/drivers/video/fbdev/simplefb.c +++ b/drivers/video/fbdev/simplefb.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include -- cgit v1.3-6-gb490 From 663724f9905818c261f0262b1a64b141dad5e3cd Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: i.MX: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Cc: Alexander Shiyan Cc: Sascha Hauer Cc: Shawn Guo Signed-off-by: Stephen Boyd --- drivers/clk/imx/clk-imx1.c | 1 - drivers/clk/imx/clk-imx21.c | 1 - drivers/clk/imx/clk-pfd.c | 1 - drivers/clk/imx/clk-pllv1.c | 1 - drivers/clk/imx/clk-pllv3.c | 1 - 5 files changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx1.c b/drivers/clk/imx/clk-imx1.c index c2647fa19f28..99cf802fa51f 100644 --- a/drivers/clk/imx/clk-imx1.c +++ b/drivers/clk/imx/clk-imx1.c @@ -15,7 +15,6 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include #include #include #include diff --git a/drivers/clk/imx/clk-imx21.c b/drivers/clk/imx/clk-imx21.c index dba987e3b89f..e63188eb08ac 100644 --- a/drivers/clk/imx/clk-imx21.c +++ b/drivers/clk/imx/clk-imx21.c @@ -9,7 +9,6 @@ * of the License, or (at your option) any later version. */ -#include #include #include #include diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c index 0b0f6f66ec56..04a3e78ea1bc 100644 --- a/drivers/clk/imx/clk-pfd.c +++ b/drivers/clk/imx/clk-pfd.c @@ -10,7 +10,6 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include #include #include #include diff --git a/drivers/clk/imx/clk-pllv1.c b/drivers/clk/imx/clk-pllv1.c index c34ad8a611dd..8564e4342c7d 100644 --- a/drivers/clk/imx/clk-pllv1.c +++ b/drivers/clk/imx/clk-pllv1.c @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index f0d15fb9d783..6addf8f58b97 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -10,7 +10,6 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include #include #include #include -- cgit v1.3-6-gb490 From a1ff4588d7b225fdf96ba65f11ce33ef00ada9ac Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 14:59:11 -0700 Subject: clk: axi-clkgen: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Cc: Lars-Peter Clausen Signed-off-by: Stephen Boyd --- drivers/clk/clk-axi-clkgen.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index e619285c6def..3bcd42fbb55e 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include -- cgit v1.3-6-gb490 From fc1699c802d316d3a8fa0d4d6a09ec8e108652ce Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: cdce706: Include clk.h This clock provider uses the consumer API, so include clk.h explicitly. Cc: Max Filippov Signed-off-by: Stephen Boyd --- drivers/clk/clk-cdce706.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c index f01164fada5d..21830526fd8e 100644 --- a/drivers/clk/clk-cdce706.c +++ b/drivers/clk/clk-cdce706.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include -- cgit v1.3-6-gb490 From a87b6866a0ecaa88379d1eeb194f218fbfd0eaf5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: clps711x: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Cc: Alexander Shiyan Signed-off-by: Stephen Boyd --- drivers/clk/clk-clps711x.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c index 715eec1a9902..ff4ef4f1df62 100644 --- a/drivers/clk/clk-clps711x.c +++ b/drivers/clk/clk-clps711x.c @@ -9,7 +9,6 @@ * (at your option) any later version. */ -#include #include #include #include -- cgit v1.3-6-gb490 From 893418e40768251c62e282bcfe25ebf24c6bcb7a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: efm32gg: Remove clk.h include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Acked-by: Uwe Kleine-König Signed-off-by: Stephen Boyd --- drivers/clk/clk-efm32gg.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-efm32gg.c b/drivers/clk/clk-efm32gg.c index 73a8d0ff530c..bac4553f04b8 100644 --- a/drivers/clk/clk-efm32gg.c +++ b/drivers/clk/clk-efm32gg.c @@ -6,7 +6,6 @@ * the terms of the GNU General Public License version 2 as published by the * Free Software Foundation. */ -#include #include #include #include -- cgit v1.3-6-gb490 From e715e2b1a67be39c8026cb6d77563774f989ba90 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: mux: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Signed-off-by: Stephen Boyd --- drivers/clk/clk-mux.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 6066a01b20ea..c705cf573569 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -10,7 +10,6 @@ * Simple multiplexer clock implementation */ -#include #include #include #include -- cgit v1.3-6-gb490 From aa1a7fc4a9203d4b53d41d0e60ac774d83c666fb Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: nomadik: Remove clk.h and clkdev.h includes Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. This driver also includes clkdev.h even though it isn't used, so drop it too and add slab.h to make sure everything still compiles. Reviewed-by: Linus Walleij Signed-off-by: Stephen Boyd --- drivers/clk/clk-nomadik.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c index c9487179f25f..e4d8a991c58f 100644 --- a/drivers/clk/clk-nomadik.c +++ b/drivers/clk/clk-nomadik.c @@ -8,8 +8,7 @@ #define pr_fmt(fmt) "Nomadik SRC clocks: " fmt #include -#include -#include +#include #include #include #include -- cgit v1.3-6-gb490 From 39a3891576496ff8e772306a9d06cbaed019dbee Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: palmas: Remove clkdev.h includes This driver includes clkdev.h even though it isn't used, so drop it. Cc: Peter Ujfalusi Cc: Nishanth Menon Signed-off-by: Stephen Boyd --- drivers/clk/clk-palmas.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-palmas.c b/drivers/clk/clk-palmas.c index 45a535ab48aa..8e3039f0c3f9 100644 --- a/drivers/clk/clk-palmas.c +++ b/drivers/clk/clk-palmas.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include -- cgit v1.3-6-gb490 From d74f864fec313868abadf8a31a4c585ec26389ca Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: rk808: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Cc: Chris Zhong Signed-off-by: Stephen Boyd --- drivers/clk/clk-rk808.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-rk808.c b/drivers/clk/clk-rk808.c index 83902b9cd49e..0fee2f4ca258 100644 --- a/drivers/clk/clk-rk808.c +++ b/drivers/clk/clk-rk808.c @@ -15,7 +15,6 @@ * more details. */ -#include #include #include #include -- cgit v1.3-6-gb490 From 608f9b6e15e70535695996c6a9cde0f3dcd02251 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: si5351: Include clk.h This clock provider uses the consumer API, so include clk.h explicitly. Cc: Sebastian Hesselbarth Signed-off-by: Stephen Boyd --- drivers/clk/clk-si5351.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index e39e1e680b3c..9e6de57eae3b 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include -- cgit v1.3-6-gb490 From e873473cbcb570360889415e4a5680e09fe6d031 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: twl6040: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Cc: Peter Ujfalusi Signed-off-by: Stephen Boyd --- drivers/clk/clk-twl6040.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index 4a755135bcd3..3094b10c6149 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -20,7 +20,6 @@ * */ -#include #include #include #include -- cgit v1.3-6-gb490 From e26684701388db6406e640ad05cbe84e5232ddb7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: u300: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Also add in slab.h because without clkdev.h compilation of this file would fail. Reviewed-by: Linus Walleij Signed-off-by: Stephen Boyd --- drivers/clk/clk-u300.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-u300.c b/drivers/clk/clk-u300.c index 18bf5e576b93..95d1742dac30 100644 --- a/drivers/clk/clk-u300.c +++ b/drivers/clk/clk-u300.c @@ -5,8 +5,8 @@ * Author: Linus Walleij * Author: Jonas Aaberg */ -#include #include +#include #include #include #include -- cgit v1.3-6-gb490 From 6063b663e872faa005669d1379439dfba805a1ea Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: wm831x: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Cc: Mark Brown Signed-off-by: Stephen Boyd --- drivers/clk/clk-wm831x.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index ef67719f4e52..43f9d15255f4 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c @@ -12,7 +12,6 @@ * */ -#include #include #include #include -- cgit v1.3-6-gb490 From 593438e44c8e01d3098d69d30353be655c3b27f1 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: hisilicon: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Also drop the clkdev.h include in files that aren't using it. Cc: Bintian Wang Cc: Zhangfei Gao Cc: Haojian Zhuang Signed-off-by: Stephen Boyd --- drivers/clk/hisilicon/clk-hi3620.c | 2 -- drivers/clk/hisilicon/clk-hip04.c | 2 -- drivers/clk/hisilicon/clk.c | 3 +-- drivers/clk/hisilicon/clkgate-separated.c | 2 -- 4 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c index 715d34a5ef9b..5502803a391e 100644 --- a/drivers/clk/hisilicon/clk-hi3620.c +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -25,13 +25,11 @@ #include #include -#include #include #include #include #include #include -#include #include diff --git a/drivers/clk/hisilicon/clk-hip04.c b/drivers/clk/hisilicon/clk-hip04.c index 132b57a0ce09..8ca967308343 100644 --- a/drivers/clk/hisilicon/clk-hip04.c +++ b/drivers/clk/hisilicon/clk-hip04.c @@ -24,13 +24,11 @@ #include #include -#include #include #include #include #include #include -#include #include diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c index c90a89739b03..155e2e6c8316 100644 --- a/drivers/clk/hisilicon/clk.c +++ b/drivers/clk/hisilicon/clk.c @@ -24,15 +24,14 @@ */ #include -#include #include +#include #include #include #include #include #include #include -#include #include "clk.h" diff --git a/drivers/clk/hisilicon/clkgate-separated.c b/drivers/clk/hisilicon/clkgate-separated.c index b03d5a7246f9..a47812f56a17 100644 --- a/drivers/clk/hisilicon/clkgate-separated.c +++ b/drivers/clk/hisilicon/clkgate-separated.c @@ -25,10 +25,8 @@ #include #include -#include #include #include -#include #include "clk.h" -- cgit v1.3-6-gb490 From 059a1aa7eb1de2ccbc41a708e892c080d9e26c60 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: keystone: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Cc: Ivan Khoronzhuk Cc: Murali Karicheri Signed-off-by: Stephen Boyd --- drivers/clk/keystone/gate.c | 1 - drivers/clk/keystone/pll.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/keystone/gate.c b/drivers/clk/keystone/gate.c index 86f1e362eafb..aed5af23895b 100644 --- a/drivers/clk/keystone/gate.c +++ b/drivers/clk/keystone/gate.c @@ -10,7 +10,6 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ -#include #include #include #include diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c index 4a375ead70e9..25443e4d139f 100644 --- a/drivers/clk/keystone/pll.c +++ b/drivers/clk/keystone/pll.c @@ -10,7 +10,6 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ -#include #include #include #include -- cgit v1.3-6-gb490 From c726639bbe23ddbfaa6ee1dd7d27175ee4488661 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: mediatek: Properly include clk.h We don't need to include clk.h in header files, just forward declare struct clk here. This leads us to a few places where the include of clk.h was missing in C files. Add them. Cc: James Liao Cc: Henry Chen Cc: Sascha Hauer Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-gate.h | 3 ++- drivers/clk/mediatek/clk-mt8135.c | 1 + drivers/clk/mediatek/clk-mt8173.c | 1 + drivers/clk/mediatek/clk-mtk.h | 3 ++- 4 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h index 6b6780b1e9c5..11e25c992948 100644 --- a/drivers/clk/mediatek/clk-gate.h +++ b/drivers/clk/mediatek/clk-gate.h @@ -16,9 +16,10 @@ #define __DRV_CLK_GATE_H #include -#include #include +struct clk; + struct mtk_clk_gate { struct clk_hw hw; struct regmap *regmap; diff --git a/drivers/clk/mediatek/clk-mt8135.c b/drivers/clk/mediatek/clk-mt8135.c index 08b4b849b491..07c21e44b4b3 100644 --- a/drivers/clk/mediatek/clk-mt8135.c +++ b/drivers/clk/mediatek/clk-mt8135.c @@ -12,6 +12,7 @@ * GNU General Public License for more details. */ +#include #include #include #include diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c index 4b9e04cdf7e8..2e0f17be9ea0 100644 --- a/drivers/clk/mediatek/clk-mt8173.c +++ b/drivers/clk/mediatek/clk-mt8173.c @@ -12,6 +12,7 @@ * GNU General Public License for more details. */ +#include #include #include #include diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index 9dda9d8ad10b..624716c4776b 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -17,9 +17,10 @@ #include #include -#include #include +struct clk; + #define MAX_MUX_GATE_BIT 31 #define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1) -- cgit v1.3-6-gb490 From c0eb1dfffc74d34277116842001e7677787c04cf Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: meson8b: Properly include clk.h Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Only include clk.h if it's actually used. Cc: Carlo Caione Signed-off-by: Stephen Boyd --- drivers/clk/meson/clk-cpu.c | 1 + drivers/clk/meson/clkc.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/meson/clk-cpu.c b/drivers/clk/meson/clk-cpu.c index 71ad493b94df..f7c30ea54ca8 100644 --- a/drivers/clk/meson/clk-cpu.c +++ b/drivers/clk/meson/clk-cpu.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #define MESON_CPU_CLK_CNTL1 0x00 diff --git a/drivers/clk/meson/clkc.c b/drivers/clk/meson/clkc.c index b8c511c5e7a7..c83ae1367abc 100644 --- a/drivers/clk/meson/clkc.c +++ b/drivers/clk/meson/clkc.c @@ -15,7 +15,6 @@ * this program. If not, see . */ -#include #include #include #include -- cgit v1.3-6-gb490 From 528b76976fd22d65a07e244ec8996de492941408 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: mmp: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. The clkdev.h include isn't used either, so drop it and add in slab.h to keep things compiling. Cc: Chao Xie Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-apbc.c | 1 - drivers/clk/mmp/clk-apmu.c | 1 - drivers/clk/mmp/clk.c | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mmp/clk-apbc.c b/drivers/clk/mmp/clk-apbc.c index 09d41c717c52..4c717db05f2d 100644 --- a/drivers/clk/mmp/clk-apbc.c +++ b/drivers/clk/mmp/clk-apbc.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/mmp/clk-apmu.c b/drivers/clk/mmp/clk-apmu.c index cdcf2d7f321e..47b5542ce50f 100644 --- a/drivers/clk/mmp/clk-apmu.c +++ b/drivers/clk/mmp/clk-apmu.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/mmp/clk.c b/drivers/clk/mmp/clk.c index cf038ef54c59..61893fe73251 100644 --- a/drivers/clk/mmp/clk.c +++ b/drivers/clk/mmp/clk.c @@ -1,7 +1,6 @@ #include -#include #include -#include +#include #include #include -- cgit v1.3-6-gb490 From db00c3e5953f5ff7e781d85feef1b3ae9ef13297 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: mvebu: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Only include the header if necessary. The clkdev.h include isn't used here either, so drop it and add in slab.h to keep things compiling. Cc: Boris Brezillon Cc: Thomas Petazzoni Cc: Gregory CLEMENT Cc: Jason Cooper Cc: Sebastian Hesselbarth Cc: Andrew Lunn Signed-off-by: Stephen Boyd --- drivers/clk/mvebu/clk-cpu.c | 3 ++- drivers/clk/mvebu/common.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c index 3821a88077ea..86888a658d4c 100644 --- a/drivers/clk/mvebu/clk-cpu.c +++ b/drivers/clk/mvebu/clk-cpu.c @@ -10,7 +10,8 @@ * warranty of any kind, whether express or implied. */ #include -#include +#include +#include #include #include #include diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c index 15b370ff3748..4a22429cd7a2 100644 --- a/drivers/clk/mvebu/common.c +++ b/drivers/clk/mvebu/common.c @@ -13,8 +13,8 @@ */ #include +#include #include -#include #include #include #include -- cgit v1.3-6-gb490 From bb0bf354524d10097271fb26bd92a55c67c0304d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: mxs: Include clk.h in C files that use it Clock provider drivers generally shouldn't include clk.h because it's the consumer API. The clk.h include is being included in all mxs files because it's part of mxs/clk.h even though nothing actually requires it in that file. Move the clk.h include to the C files that are actually using it and remove the clk.h include from the header file. The clkdev.h include isn't used either, so drop it too. Acked-by: Shawn Guo Signed-off-by: Stephen Boyd --- drivers/clk/mxs/clk-div.c | 1 - drivers/clk/mxs/clk-frac.c | 1 - drivers/clk/mxs/clk-imx23.c | 3 +-- drivers/clk/mxs/clk-imx28.c | 2 +- drivers/clk/mxs/clk-pll.c | 1 - drivers/clk/mxs/clk-ref.c | 1 - drivers/clk/mxs/clk.h | 3 ++- 7 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mxs/clk-div.c b/drivers/clk/mxs/clk-div.c index 90e1da93877e..049ee27d5a22 100644 --- a/drivers/clk/mxs/clk-div.c +++ b/drivers/clk/mxs/clk-div.c @@ -9,7 +9,6 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include #include #include #include diff --git a/drivers/clk/mxs/clk-frac.c b/drivers/clk/mxs/clk-frac.c index e6aa6b567d68..73f0240569ac 100644 --- a/drivers/clk/mxs/clk-frac.c +++ b/drivers/clk/mxs/clk-frac.c @@ -9,7 +9,6 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include #include #include #include diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c index 32216f9b7f03..f01876af6bb8 100644 --- a/drivers/clk/mxs/clk-imx23.c +++ b/drivers/clk/mxs/clk-imx23.c @@ -9,9 +9,8 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include #include -#include +#include #include #include #include diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index a68670868baa..6b572b759f9a 100644 --- a/drivers/clk/mxs/clk-imx28.c +++ b/drivers/clk/mxs/clk-imx28.c @@ -9,9 +9,9 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include #include #include +#include #include #include #include diff --git a/drivers/clk/mxs/clk-pll.c b/drivers/clk/mxs/clk-pll.c index fadae41833ec..d4ca79a868e0 100644 --- a/drivers/clk/mxs/clk-pll.c +++ b/drivers/clk/mxs/clk-pll.c @@ -9,7 +9,6 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include #include #include #include diff --git a/drivers/clk/mxs/clk-ref.c b/drivers/clk/mxs/clk-ref.c index 4adeed6c2f94..495f99b7965e 100644 --- a/drivers/clk/mxs/clk-ref.c +++ b/drivers/clk/mxs/clk-ref.c @@ -9,7 +9,6 @@ * http://www.gnu.org/copyleft/gpl.html */ -#include #include #include #include diff --git a/drivers/clk/mxs/clk.h b/drivers/clk/mxs/clk.h index f07d821dd75d..a4590956d2a2 100644 --- a/drivers/clk/mxs/clk.h +++ b/drivers/clk/mxs/clk.h @@ -12,7 +12,8 @@ #ifndef __MXS_CLK_H #define __MXS_CLK_H -#include +struct clk; + #include #include -- cgit v1.3-6-gb490 From 39482a1331ca70184145456df4206405b5b729e3 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: nxp: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Acked-by: Joachim Eastwood Signed-off-by: Stephen Boyd --- drivers/clk/nxp/clk-lpc18xx-cgu.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c index 81e9e1c788f4..e0a3cb8970ab 100644 --- a/drivers/clk/nxp/clk-lpc18xx-cgu.c +++ b/drivers/clk/nxp/clk-lpc18xx-cgu.c @@ -8,7 +8,6 @@ * warranty of any kind, whether express or implied. */ -#include #include #include #include -- cgit v1.3-6-gb490 From f684ff8b67ec19f003cc894477afb20442064692 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: rockchip: Properly include clk.h Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Only include clk.h if it's actually used. Cc: Heiko Stuebner Signed-off-by: Stephen Boyd --- drivers/clk/rockchip/clk-cpu.c | 1 + drivers/clk/rockchip/clk-mmc-phase.c | 1 + drivers/clk/rockchip/clk-pll.c | 1 - drivers/clk/rockchip/clk-rk3188.c | 1 + drivers/clk/rockchip/clk.h | 4 ++-- 5 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c index fb7721bd37e6..330870a6d8bf 100644 --- a/drivers/clk/rockchip/clk-cpu.c +++ b/drivers/clk/rockchip/clk-cpu.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "clk.h" diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index e9f8df324e7c..3244c6e391d7 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -14,6 +14,7 @@ */ #include +#include #include #include "clk.h" diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 76027261f7ed..1f88dd158b93 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include "clk.h" diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index e4f9d472f1ff..91ea848c9d18 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ +#include #include #include #include diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 6b092673048a..1b16781b67c5 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -24,8 +24,8 @@ #define CLK_ROCKCHIP_CLK_H #include -#include -#include + +struct clk; #define HIWORD_UPDATE(val, mask, shift) \ ((val) << (shift) | (mask) << ((shift) + 16)) -- cgit v1.3-6-gb490 From 6f1ed07a14a1ace5facba1e2b3995a2ef3b610cc Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: samsung: Properly include clk.h and clkdev.h Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Only include clk.h in files that are using it. The clkdev.h header isn't always used either, so remove it and add in slab.h where files were relying on it to include slab for them. Cc: Chanwoo Choi Cc: Sylwester Nawrocki Cc: Krzysztof Kozlowski Cc: Kukjin Kim Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk-cpu.c | 3 +++ drivers/clk/samsung/clk-exynos-audss.c | 3 ++- drivers/clk/samsung/clk-exynos-clkout.c | 2 +- drivers/clk/samsung/clk-exynos3250.c | 2 -- drivers/clk/samsung/clk-exynos4.c | 2 +- drivers/clk/samsung/clk-exynos4415.c | 2 -- drivers/clk/samsung/clk-exynos5250.c | 2 -- drivers/clk/samsung/clk-exynos5260.c | 2 -- drivers/clk/samsung/clk-exynos5410.c | 2 -- drivers/clk/samsung/clk-exynos5420.c | 3 +-- drivers/clk/samsung/clk-exynos5433.c | 2 -- drivers/clk/samsung/clk-exynos5440.c | 2 -- drivers/clk/samsung/clk-exynos7.c | 2 -- drivers/clk/samsung/clk-pll.c | 2 ++ drivers/clk/samsung/clk-s3c2410-dclk.c | 4 ++++ drivers/clk/samsung/clk-s3c2410.c | 2 -- drivers/clk/samsung/clk-s3c2412.c | 2 -- drivers/clk/samsung/clk-s3c2443.c | 2 -- drivers/clk/samsung/clk-s3c64xx.c | 3 +-- drivers/clk/samsung/clk-s5pv210-audss.c | 2 +- drivers/clk/samsung/clk-s5pv210.c | 2 -- drivers/clk/samsung/clk.c | 4 ++++ drivers/clk/samsung/clk.h | 3 ++- 23 files changed, 22 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c index 3a1fe07cfe9e..8e7f36f105c1 100644 --- a/drivers/clk/samsung/clk-cpu.c +++ b/drivers/clk/samsung/clk-cpu.c @@ -33,6 +33,9 @@ */ #include +#include +#include +#include #include "clk-cpu.h" #define E4210_SRC_CPU 0x0 diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 454b02ae486a..4e9584d79089 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -9,8 +9,9 @@ * Common Clock Framework support for Audio Subsystem Clock Controller. */ -#include +#include #include +#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c index 03a52228b6d1..7cd02ff37a1f 100644 --- a/drivers/clk/samsung/clk-exynos-clkout.c +++ b/drivers/clk/samsung/clk-exynos-clkout.c @@ -9,8 +9,8 @@ * Clock driver for Exynos clock output */ +#include #include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 538de66a759e..c940fddb0847 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -8,8 +8,6 @@ * Common Clock Framework support for Exynos3250 SoC. */ -#include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index cae2c048488d..65e20eb6356e 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -11,8 +11,8 @@ */ #include +#include #include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos4415.c b/drivers/clk/samsung/clk-exynos4415.c index 6c78b09c829f..92c39f6efec8 100644 --- a/drivers/clk/samsung/clk-exynos4415.c +++ b/drivers/clk/samsung/clk-exynos4415.c @@ -9,8 +9,6 @@ * Common Clock Framework support for Exynos4415 SoC. */ -#include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 70ec3d2608a1..aa356db587df 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -11,8 +11,6 @@ */ #include -#include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos5260.c b/drivers/clk/samsung/clk-exynos5260.c index 06f96eb7cf93..d1a29f6c1084 100644 --- a/drivers/clk/samsung/clk-exynos5260.c +++ b/drivers/clk/samsung/clk-exynos5260.c @@ -9,8 +9,6 @@ * Common Clock Framework support for Exynos5260 SoC. */ -#include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynos5410.c b/drivers/clk/samsung/clk-exynos5410.c index 231475bc2b99..d5d5dcabc4a9 100644 --- a/drivers/clk/samsung/clk-exynos5410.c +++ b/drivers/clk/samsung/clk-exynos5410.c @@ -11,8 +11,6 @@ #include -#include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index a1d731ca8f48..389af3c15ec4 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -11,8 +11,7 @@ */ #include -#include -#include +#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 39c95649d3d0..cee062c588de 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -9,8 +9,6 @@ * Common Clock Framework support for Exynos5443 SoC. */ -#include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c index 979e81389cdd..590813871ffe 100644 --- a/drivers/clk/samsung/clk-exynos5440.c +++ b/drivers/clk/samsung/clk-exynos5440.c @@ -10,8 +10,6 @@ */ #include -#include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c index 03d36e847b78..8524e667097e 100644 --- a/drivers/clk/samsung/clk-exynos7.c +++ b/drivers/clk/samsung/clk-exynos7.c @@ -8,8 +8,6 @@ * */ -#include -#include #include #include diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index bebc61b5fce1..e9394261f80f 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include "clk.h" #include "clk-pll.h" diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c index e56df5064889..71ebad941f86 100644 --- a/drivers/clk/samsung/clk-s3c2410-dclk.c +++ b/drivers/clk/samsung/clk-s3c2410-dclk.c @@ -8,6 +8,10 @@ * Common Clock Framework support for s3c24xx external clock output. */ +#include +#include +#include +#include #include #include #include "clk.h" diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index 5d2f03461bc5..0945a8852299 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -8,8 +8,6 @@ * Common Clock Framework support for S3C2410 and following SoCs. */ -#include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c index 2ceedaf8ce18..44d6a9f4f5b2 100644 --- a/drivers/clk/samsung/clk-s3c2412.c +++ b/drivers/clk/samsung/clk-s3c2412.c @@ -8,8 +8,6 @@ * Common Clock Framework support for S3C2412 and S3C2413. */ -#include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index 0c3c182b902a..2c0a1ea3c80c 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c @@ -8,8 +8,6 @@ * Common Clock Framework support for S3C2443 and following SoCs. */ -#include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index 0f590e5550cb..d325ed1e196b 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -8,8 +8,7 @@ * Common Clock Framework support for all S3C64xx SoCs. */ -#include -#include +#include #include #include #include diff --git a/drivers/clk/samsung/clk-s5pv210-audss.c b/drivers/clk/samsung/clk-s5pv210-audss.c index de4455b75e8a..eefb84b22566 100644 --- a/drivers/clk/samsung/clk-s5pv210-audss.c +++ b/drivers/clk/samsung/clk-s5pv210-audss.c @@ -13,8 +13,8 @@ * Driver for Audio Subsystem Clock Controller of S5PV210-compatible SoCs. */ -#include #include +#include #include #include #include diff --git a/drivers/clk/samsung/clk-s5pv210.c b/drivers/clk/samsung/clk-s5pv210.c index cf7e8fa7b624..67bf813809c6 100644 --- a/drivers/clk/samsung/clk-s5pv210.c +++ b/drivers/clk/samsung/clk-s5pv210.c @@ -11,8 +11,6 @@ * Common Clock Framework support for all S5PC110/S5PV210 SoCs. */ -#include -#include #include #include #include diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index 0117238391d6..f38a6c49f744 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -11,6 +11,10 @@ * clock framework for Samsung platforms. */ +#include +#include +#include +#include #include #include diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index b775fc29caa5..aa872d2c5105 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -13,10 +13,11 @@ #ifndef __SAMSUNG_CLK_H #define __SAMSUNG_CLK_H -#include #include #include "clk-pll.h" +struct clk; + /** * struct samsung_clk_provider: information about clock provider * @reg_base: virtual address for the register base. -- cgit v1.3-6-gb490 From fdb94059d89aab102b4debc30e77f0b5521f8148 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: sirf: Properly include clk.h Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Move the include of clk.h into clk-common.c because that's the only file that's really using clk.h, even if it's included into the atlas6 and prima2 files. Cc: Barry Song Signed-off-by: Stephen Boyd --- drivers/clk/sirf/clk-atlas6.c | 1 - drivers/clk/sirf/clk-common.c | 2 ++ drivers/clk/sirf/clk-prima2.c | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/sirf/clk-atlas6.c b/drivers/clk/sirf/clk-atlas6.c index d63b76ca60c3..c5eaa9d16247 100644 --- a/drivers/clk/sirf/clk-atlas6.c +++ b/drivers/clk/sirf/clk-atlas6.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/sirf/clk-common.c b/drivers/clk/sirf/clk-common.c index 9fc285d784d3..2f64d4beeb52 100644 --- a/drivers/clk/sirf/clk-common.c +++ b/drivers/clk/sirf/clk-common.c @@ -7,6 +7,8 @@ * Licensed under GPLv2 or later. */ +#include + #define KHZ 1000 #define MHZ (KHZ * KHZ) diff --git a/drivers/clk/sirf/clk-prima2.c b/drivers/clk/sirf/clk-prima2.c index 6968e2ebcd8a..f92c40264342 100644 --- a/drivers/clk/sirf/clk-prima2.c +++ b/drivers/clk/sirf/clk-prima2.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include -- cgit v1.3-6-gb490 From b0af24b523c21c918eb64541df4450b9da7ed195 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: socfpga: Remove clk.h and clkdev.h includes Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. The clkdev.h include isn't used either, remove it and add in slab.h to make sure things keep compiling. Acked-by: Dinh Nguyen Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-gate-a10.c | 1 + drivers/clk/socfpga/clk-gate.c | 3 +-- drivers/clk/socfpga/clk-periph-a10.c | 1 + drivers/clk/socfpga/clk-periph.c | 3 +-- drivers/clk/socfpga/clk-pll-a10.c | 1 + drivers/clk/socfpga/clk-pll.c | 3 +-- drivers/clk/socfpga/clk.h | 1 - 7 files changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/socfpga/clk-gate-a10.c b/drivers/clk/socfpga/clk-gate-a10.c index 83c6780ff4b2..538ca504dea1 100644 --- a/drivers/clk/socfpga/clk-gate-a10.c +++ b/drivers/clk/socfpga/clk-gate-a10.c @@ -13,6 +13,7 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ +#include #include #include #include diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c index 82449cd76fd7..37e0bb60ac68 100644 --- a/drivers/clk/socfpga/clk-gate.c +++ b/drivers/clk/socfpga/clk-gate.c @@ -15,8 +15,7 @@ * Based from clk-highbank.c * */ -#include -#include +#include #include #include #include diff --git a/drivers/clk/socfpga/clk-periph-a10.c b/drivers/clk/socfpga/clk-periph-a10.c index 9d0181b5a6a4..64f93acbbd25 100644 --- a/drivers/clk/socfpga/clk-periph-a10.c +++ b/drivers/clk/socfpga/clk-periph-a10.c @@ -13,6 +13,7 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ +#include #include #include #include diff --git a/drivers/clk/socfpga/clk-periph.c b/drivers/clk/socfpga/clk-periph.c index 83aeaa219d14..ab9c8164a98f 100644 --- a/drivers/clk/socfpga/clk-periph.c +++ b/drivers/clk/socfpga/clk-periph.c @@ -15,8 +15,7 @@ * Based from clk-highbank.c * */ -#include -#include +#include #include #include #include diff --git a/drivers/clk/socfpga/clk-pll-a10.c b/drivers/clk/socfpga/clk-pll-a10.c index 1178b11babca..402d630bd531 100644 --- a/drivers/clk/socfpga/clk-pll-a10.c +++ b/drivers/clk/socfpga/clk-pll-a10.c @@ -13,6 +13,7 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ +#include #include #include #include diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c index 8f26b5234947..c7f463172e4b 100644 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -15,8 +15,7 @@ * Based from clk-highbank.c * */ -#include -#include +#include #include #include #include diff --git a/drivers/clk/socfpga/clk.h b/drivers/clk/socfpga/clk.h index 603973ab7e29..f4219202844a 100644 --- a/drivers/clk/socfpga/clk.h +++ b/drivers/clk/socfpga/clk.h @@ -18,7 +18,6 @@ #define __SOCFPGA_CLK_H #include -#include /* Clock Manager offsets */ #define CLKMGR_CTRL 0x0 -- cgit v1.3-6-gb490 From c302e1e28078fbb31e179c48d9a990fb0e9334e4 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: spear: Remove clk.h include Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Acked-by: Viresh Kumar Signed-off-by: Stephen Boyd --- drivers/clk/spear/spear1310_clock.c | 1 - drivers/clk/spear/spear1340_clock.c | 1 - drivers/clk/spear/spear6xx_clock.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/spear/spear1310_clock.c b/drivers/clk/spear/spear1310_clock.c index 4daa5977793a..7cd010f6e12d 100644 --- a/drivers/clk/spear/spear1310_clock.c +++ b/drivers/clk/spear/spear1310_clock.c @@ -11,7 +11,6 @@ * warranty of any kind, whether express or implied. */ -#include #include #include #include diff --git a/drivers/clk/spear/spear1340_clock.c b/drivers/clk/spear/spear1340_clock.c index 5a5c6648308d..eef57a2e39ee 100644 --- a/drivers/clk/spear/spear1340_clock.c +++ b/drivers/clk/spear/spear1340_clock.c @@ -11,7 +11,6 @@ * warranty of any kind, whether express or implied. */ -#include #include #include #include diff --git a/drivers/clk/spear/spear6xx_clock.c b/drivers/clk/spear/spear6xx_clock.c index 4f649c9cb094..46a4dafe46a7 100644 --- a/drivers/clk/spear/spear6xx_clock.c +++ b/drivers/clk/spear/spear6xx_clock.c @@ -9,7 +9,6 @@ * warranty of any kind, whether express or implied. */ -#include #include #include #include -- cgit v1.3-6-gb490 From 584ac4e935a1f905d67c8fa3fbe8e32d384721f1 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: tegra: Properly include clk.h Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Only include clk.h in files that are using it. Also add in a clkdev.h include that was missing in a file using clkdev APIs. Cc: Peter De Schrijver Cc: Thierry Reding Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-divider.c | 1 - drivers/clk/tegra/clk-periph-gate.c | 1 - drivers/clk/tegra/clk-periph.c | 1 - drivers/clk/tegra/clk-pll-out.c | 1 - drivers/clk/tegra/clk-pll.c | 2 +- drivers/clk/tegra/clk-super.c | 1 - drivers/clk/tegra/clk-tegra-audio.c | 1 - drivers/clk/tegra/clk-tegra-fixed.c | 1 - drivers/clk/tegra/clk-tegra-periph.c | 1 - drivers/clk/tegra/clk-tegra-pmc.c | 1 - drivers/clk/tegra/clk-tegra-super-gen4.c | 1 - drivers/clk/tegra/clk-tegra114.c | 2 -- drivers/clk/tegra/clk-tegra124.c | 1 - drivers/clk/tegra/clk-tegra20.c | 1 - drivers/clk/tegra/clk-tegra30.c | 1 - drivers/clk/tegra/clk.c | 1 + include/linux/clk/tegra.h | 3 ++- 17 files changed, 4 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c index 59a5714dfe18..48c83efda4cf 100644 --- a/drivers/clk/tegra/clk-divider.c +++ b/drivers/clk/tegra/clk-divider.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "clk.h" diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c index 0aa8830ae7cc..d28d6e95020f 100644 --- a/drivers/clk/tegra/clk-periph-gate.c +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -14,7 +14,6 @@ * along with this program. If not, see . */ -#include #include #include #include diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index d84ae49d0e05..ec5b6113b012 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -14,7 +14,6 @@ * along with this program. If not, see . */ -#include #include #include #include diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c index 3598987a451d..257cae0c1488 100644 --- a/drivers/clk/tegra/clk-pll-out.c +++ b/drivers/clk/tegra/clk-pll-out.c @@ -20,7 +20,6 @@ #include #include #include -#include #include "clk.h" diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 05c6d08a6695..63499c461482 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -18,8 +18,8 @@ #include #include #include -#include #include +#include #include "clk.h" diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c index 2fd924d38606..131d1b5085e2 100644 --- a/drivers/clk/tegra/clk-super.c +++ b/drivers/clk/tegra/clk-super.c @@ -20,7 +20,6 @@ #include #include #include -#include #include "clk.h" diff --git a/drivers/clk/tegra/clk-tegra-audio.c b/drivers/clk/tegra/clk-tegra-audio.c index 5c38aab2c5b8..11e3ad7ad7a3 100644 --- a/drivers/clk/tegra/clk-tegra-audio.c +++ b/drivers/clk/tegra/clk-tegra-audio.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c index 605676d368eb..da0b5941c89f 100644 --- a/drivers/clk/tegra/clk-tegra-fixed.c +++ b/drivers/clk/tegra/clk-tegra-fixed.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index 46af9244ba74..cb6ab830941d 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/tegra/clk-tegra-pmc.c b/drivers/clk/tegra/clk-tegra-pmc.c index 08b21c1ee867..91377abfefa1 100644 --- a/drivers/clk/tegra/clk-tegra-pmc.c +++ b/drivers/clk/tegra/clk-tegra-pmc.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c index feb3201c85ce..ecd7ff736b74 100644 --- a/drivers/clk/tegra/clk-tegra-super-gen4.c +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 8237d16b4075..db5871519bf5 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -15,9 +15,7 @@ */ #include -#include #include -#include #include #include #include diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index e8cca3eac007..0c44cc7f8558 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 41272dcc9e22..bf004f0e4f65 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index 0af3e834dd24..fad561a5896b 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -16,7 +16,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index 41cd87c67be6..22aa8b18c840 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -14,6 +14,7 @@ * along with this program. If not, see . */ +#include #include #include #include diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 19c4208f4752..57bf7aab4516 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -17,7 +17,8 @@ #ifndef __LINUX_CLK_TEGRA_H_ #define __LINUX_CLK_TEGRA_H_ -#include +#include +#include /* * Tegra CPU clock and reset control ops -- cgit v1.3-6-gb490 From a162ca912cf792073b0b2450377fd1cd5d5c6cb5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: ux500: Remove clk.h and clkdev.h includes Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Also remove clkdev.h in files that aren't using it. Acked-by: Linus Walleij Acked-by: Ulf Hansson Signed-off-by: Stephen Boyd --- drivers/clk/ux500/abx500-clk.c | 1 - drivers/clk/ux500/clk.h | 3 ++- drivers/clk/ux500/u8500_clk.c | 1 - drivers/clk/ux500/u8500_of_clk.c | 2 -- drivers/clk/ux500/u8540_clk.c | 1 - drivers/clk/ux500/u9540_clk.c | 2 -- 6 files changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/ux500/abx500-clk.c b/drivers/clk/ux500/abx500-clk.c index 3e5e05101302..222425d08ab6 100644 --- a/drivers/clk/ux500/abx500-clk.c +++ b/drivers/clk/ux500/abx500-clk.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h index a2bb92d85ee0..b42485da704e 100644 --- a/drivers/clk/ux500/clk.h +++ b/drivers/clk/ux500/clk.h @@ -10,10 +10,11 @@ #ifndef __UX500_CLK_H #define __UX500_CLK_H -#include #include #include +struct clk; + struct clk *clk_reg_prcc_pclk(const char *name, const char *parent_name, resource_size_t phy_base, diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c index 4626b97b7d83..1c7b639d9222 100644 --- a/drivers/clk/ux500/u8500_clk.c +++ b/drivers/clk/ux500/u8500_clk.c @@ -7,7 +7,6 @@ * License terms: GNU General Public License (GPL) version 2 */ -#include #include #include #include diff --git a/drivers/clk/ux500/u8500_of_clk.c b/drivers/clk/ux500/u8500_of_clk.c index e319ef912dc6..c3e3b20e4b43 100644 --- a/drivers/clk/ux500/u8500_of_clk.c +++ b/drivers/clk/ux500/u8500_of_clk.c @@ -8,8 +8,6 @@ */ #include -#include -#include #include #include #include diff --git a/drivers/clk/ux500/u8540_clk.c b/drivers/clk/ux500/u8540_clk.c index 20c8add90d11..d0de335ea1e9 100644 --- a/drivers/clk/ux500/u8540_clk.c +++ b/drivers/clk/ux500/u8540_clk.c @@ -7,7 +7,6 @@ * License terms: GNU General Public License (GPL) version 2 */ -#include #include #include #include diff --git a/drivers/clk/ux500/u9540_clk.c b/drivers/clk/ux500/u9540_clk.c index 44794782e7e0..179bd3871b34 100644 --- a/drivers/clk/ux500/u9540_clk.c +++ b/drivers/clk/ux500/u9540_clk.c @@ -7,8 +7,6 @@ * License terms: GNU General Public License (GPL) version 2 */ -#include -#include #include #include #include -- cgit v1.3-6-gb490 From 6d31e3b22e131f5aa5c9d6407ea46fec2134f986 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: versatile: Remove clk.h and clkdev.h includes Clock provider drivers generally shouldn't include clk.h because it's the consumer API. Remove the include here because this is a provider driver. Also remove clkdev.h in files that aren't using it and replace them with slab.h in files that were relying on the implicit include of slab.h in clkdev.h. Reviewed-by: Linus Walleij Signed-off-by: Stephen Boyd --- drivers/clk/versatile/clk-icst.c | 5 +++-- drivers/clk/versatile/clk-impd1.c | 1 - drivers/clk/versatile/clk-realview.c | 1 - drivers/clk/versatile/clk-sp810.c | 3 ++- drivers/clk/versatile/clk-versatile.c | 2 -- 5 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index bc96f103bd7c..a3893ea2199d 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -13,8 +13,9 @@ * ICST clock code from the ARM tree should probably be merged into this * file. */ -#include -#include +#include +#include +#include #include #include #include diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c index 1cc1330dc570..65c842a21c62 100644 --- a/drivers/clk/versatile/clk-impd1.c +++ b/drivers/clk/versatile/clk-impd1.c @@ -7,7 +7,6 @@ * published by the Free Software Foundation. */ #include -#include #include #include #include diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c index c8b523117fb7..940cc6f14578 100644 --- a/drivers/clk/versatile/clk-realview.c +++ b/drivers/clk/versatile/clk-realview.c @@ -6,7 +6,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include #include #include #include diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c index a96dd8e53fdb..64b0129a0216 100644 --- a/drivers/clk/versatile/clk-sp810.c +++ b/drivers/clk/versatile/clk-sp810.c @@ -12,7 +12,8 @@ */ #include -#include +#include +#include #include #include #include diff --git a/drivers/clk/versatile/clk-versatile.c b/drivers/clk/versatile/clk-versatile.c index 7a4f8635bd1e..71fa5da89afd 100644 --- a/drivers/clk/versatile/clk-versatile.c +++ b/drivers/clk/versatile/clk-versatile.c @@ -8,8 +8,6 @@ * published by the Free Software Foundation. */ #include -#include -#include #include #include #include -- cgit v1.3-6-gb490 From d4945ab6472968f1a429ae89bf52e88676c47991 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: bcm: Include clk.h This clock provider uses the consumer API, so include clk.h explicitly. Acked-by: Alex Elder Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-kona.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index 79a98506c433..5638de8c6489 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c @@ -16,6 +16,7 @@ #include #include +#include /* * "Policies" affect the frequencies of bus clocks provided by a -- cgit v1.3-6-gb490 From 9bd6314c2ee4a117abb8a4ad4d5f359a6b34c664 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: highbank: Include clk.h This clock provider uses the consumer API, so include clk.h explicitly. Cc: Rob Herring Signed-off-by: Stephen Boyd --- drivers/clk/clk-highbank.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c index 2e7e9d9798cb..be3a21abb185 100644 --- a/drivers/clk/clk-highbank.c +++ b/drivers/clk/clk-highbank.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include -- cgit v1.3-6-gb490 From 8803609082349d97311da2e43042ed3780d53fdf Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: qcom: Include clk.h This clock provider uses the consumer API, so include clk.h explicitly. Signed-off-by: Stephen Boyd --- drivers/clk/qcom/mmcc-msm8960.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index 9711bca9cc06..2de05e321ad0 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include -- cgit v1.3-6-gb490 From d5f728acd90e864251139ffc59294b336cf4b382 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: st: Include clk.h This clock provider uses the consumer API, so include clk.h explicitly. Cc: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/st/clk-flexgen.c | 1 + drivers/clk/st/clkgen-fsyn.c | 1 + drivers/clk/st/clkgen-mux.c | 1 + drivers/clk/st/clkgen-pll.c | 1 + 4 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c index 657ca14ba709..8e0dbb1f81f8 100644 --- a/drivers/clk/st/clk-flexgen.c +++ b/drivers/clk/st/clk-flexgen.c @@ -5,6 +5,7 @@ * Author: Maxime Coquelin for ST-Microelectronics. * License terms: GNU General Public License (GPL), version 2 */ +#include #include #include #include diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index e94197f04b0b..90c20717a6bb 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -15,6 +15,7 @@ #include #include +#include #include #include "clkgen.h" diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c index 4fbe6e099587..4fc95d5332e2 100644 --- a/drivers/clk/st/clkgen-mux.c +++ b/drivers/clk/st/clkgen-mux.c @@ -15,6 +15,7 @@ #include #include +#include #include static DEFINE_SPINLOCK(clkgena_divmux_lock); diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c index 106532207213..cdb14b9bb942 100644 --- a/drivers/clk/st/clkgen-pll.c +++ b/drivers/clk/st/clkgen-pll.c @@ -16,6 +16,7 @@ #include #include +#include #include #include "clkgen.h" -- cgit v1.3-6-gb490 From 9dfefe8c766ee2abc724e1e275ab0b32431fcd25 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: sunxi: Include clk.h and remove unused clkdev.h includes This clock provider uses the consumer API, so include clk.h explicitly. Also remove clkdev.h in files that aren't using it and include slab.h when clkdev.h was being used to implicitly include it. Cc: Chen-Yu Tsai Cc: Maxime Ripard Signed-off-by: Stephen Boyd --- drivers/clk/sunxi/clk-mod0.c | 3 ++- drivers/clk/sunxi/clk-sun8i-mbus.c | 2 +- drivers/clk/sunxi/clk-sun9i-core.c | 2 +- drivers/clk/sunxi/clk-sun9i-mmc.c | 3 ++- drivers/clk/sunxi/clk-sunxi.c | 2 ++ drivers/clk/sunxi/clk-usb.c | 3 ++- 6 files changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c index 9d028aec58e5..d167e1efb927 100644 --- a/drivers/clk/sunxi/clk-mod0.c +++ b/drivers/clk/sunxi/clk-mod0.c @@ -14,10 +14,11 @@ * GNU General Public License for more details. */ +#include #include -#include #include #include +#include #include "clk-factors.h" diff --git a/drivers/clk/sunxi/clk-sun8i-mbus.c b/drivers/clk/sunxi/clk-sun8i-mbus.c index 14cd026064bf..bf117a636d23 100644 --- a/drivers/clk/sunxi/clk-sun8i-mbus.c +++ b/drivers/clk/sunxi/clk-sun8i-mbus.c @@ -14,8 +14,8 @@ * GNU General Public License for more details. */ +#include #include -#include #include #include "clk-factors.h" diff --git a/drivers/clk/sunxi/clk-sun9i-core.c b/drivers/clk/sunxi/clk-sun9i-core.c index 887f4ea161bb..6c4c98324d3c 100644 --- a/drivers/clk/sunxi/clk-sun9i-core.c +++ b/drivers/clk/sunxi/clk-sun9i-core.c @@ -14,8 +14,8 @@ * GNU General Public License for more details. */ +#include #include -#include #include #include #include diff --git a/drivers/clk/sunxi/clk-sun9i-mmc.c b/drivers/clk/sunxi/clk-sun9i-mmc.c index 710c273648d7..3436a948b796 100644 --- a/drivers/clk/sunxi/clk-sun9i-mmc.c +++ b/drivers/clk/sunxi/clk-sun9i-mmc.c @@ -14,14 +14,15 @@ * GNU General Public License for more details. */ +#include #include -#include #include #include #include #include #include #include +#include #include #define SUN9I_MMC_WIDTH 4 diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 9a82f17d2d73..4ac26122a7c6 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -14,11 +14,13 @@ * GNU General Public License for more details. */ +#include #include #include #include #include #include +#include #include #include diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c index 3a25f9588e67..1a72cd672839 100644 --- a/drivers/clk/sunxi/clk-usb.c +++ b/drivers/clk/sunxi/clk-usb.c @@ -14,11 +14,12 @@ * GNU General Public License for more details. */ +#include #include -#include #include #include #include +#include #include -- cgit v1.3-6-gb490 From 1b29e60157e845869abb867df6c7164eaace88b6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: ti: Include clk.h This clock provider uses the consumer API, so include clk.h explicitly. Acked-by: Tero Kristo Signed-off-by: Stephen Boyd --- drivers/clk/ti/apll.c | 1 + drivers/clk/ti/clk-33xx.c | 1 + drivers/clk/ti/clk-3xxx-legacy.c | 1 + drivers/clk/ti/clk-3xxx.c | 1 + drivers/clk/ti/clk-43xx.c | 1 + drivers/clk/ti/clk-dra7-atl.c | 1 + drivers/clk/ti/clk.c | 1 + drivers/clk/ti/clockdomain.c | 1 + drivers/clk/ti/dpll.c | 1 + drivers/clk/ti/fapll.c | 1 + 10 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index 49baf3831546..671f4d89db93 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. */ +#include #include #include #include diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c index 028b33783d38..9616bcdba220 100644 --- a/drivers/clk/ti/clk-33xx.c +++ b/drivers/clk/ti/clk-33xx.c @@ -16,6 +16,7 @@ #include #include +#include #include #include diff --git a/drivers/clk/ti/clk-3xxx-legacy.c b/drivers/clk/ti/clk-3xxx-legacy.c index 0b61548d569b..0fbf8a917955 100644 --- a/drivers/clk/ti/clk-3xxx-legacy.c +++ b/drivers/clk/ti/clk-3xxx-legacy.c @@ -15,6 +15,7 @@ */ #include +#include #include #include diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c index 757636d166cf..5df21b258658 100644 --- a/drivers/clk/ti/clk-3xxx.c +++ b/drivers/clk/ti/clk-3xxx.c @@ -16,6 +16,7 @@ #include #include +#include #include #include diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c index 3795fce8a830..39a594c0d100 100644 --- a/drivers/clk/ti/clk-43xx.c +++ b/drivers/clk/ti/clk-43xx.c @@ -16,6 +16,7 @@ #include #include +#include #include #include diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index 19e543a32e2b..2e14dfb588f4 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 64bb5e8a3b8c..7132cec33f00 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. */ +#include #include #include #include diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index b82ef07f3403..41eb5d105846 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. */ +#include #include #include #include diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 2aacf7a3bcae..74e94b9bae55 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. */ +#include #include #include #include diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c index 730aa62454a2..f158c2ab019d 100644 --- a/drivers/clk/ti/fapll.c +++ b/drivers/clk/ti/fapll.c @@ -9,6 +9,7 @@ * GNU General Public License for more details. */ +#include #include #include #include -- cgit v1.3-6-gb490 From 5402494f9b13da6d4210489d544a01fa7dc9ee14 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: zynq: Include clk.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This clock provider uses the consumer API, so include clk.h explicitly. Acked-by: Sören Brinkmann Signed-off-by: Stephen Boyd --- drivers/clk/zynq/clkc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index de614384bb44..38a65c3e62fc 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include -- cgit v1.3-6-gb490 From 3c37311730efec287b323e0928c9cf3737ab93e2 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: Include clk.h in clk.c This file implements the clk API and so it should include clk.h directly instead of indirectly including it through clk-provider.h. Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ddb4b541016f..89e531a3f384 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -9,6 +9,7 @@ * Standard functionality for the common clock API. See Documentation/clk.txt */ +#include #include #include #include -- cgit v1.3-6-gb490 From a826a1a4217e207b794a0fd2bd7d1f62db240e0e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 10 Jun 2015 14:14:28 -0700 Subject: clk: cdce925: Include clk.h This clock provider uses the consumer API, so include clk.h explicitly. Cc: Mike Looijmans Signed-off-by: Stephen Boyd --- drivers/clk/clk-cdce925.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index 85fafb41e6ca..089bf88ffa8d 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -10,6 +10,7 @@ * Copyright (C) 2014, Topic Embedded Products * Licenced under GPL */ +#include #include #include #include -- cgit v1.3-6-gb490 From 67bb5408a8cf5a76a820b49bba4ab6da7acd313b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 1 May 2015 16:09:33 -0700 Subject: clk: moxart: Include clk.h This clock provider uses the consumer API, so include clk.h explicitly. Cc: Jonas Jensen Signed-off-by: Stephen Boyd --- drivers/clk/clk-moxart.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/clk-moxart.c b/drivers/clk/clk-moxart.c index 5181b89c3cb2..f37f719643ec 100644 --- a/drivers/clk/clk-moxart.c +++ b/drivers/clk/clk-moxart.c @@ -10,6 +10,7 @@ * warranty of any kind, whether express or implied. */ +#include #include #include #include -- cgit v1.3-6-gb490 From 530b544ebfa5d0039eed9a1cd4714807629fbe84 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 1 May 2015 16:09:33 -0700 Subject: clk: si570: Include clk.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This clock provider uses the consumer API, so include clk.h explicitly. Cc: Guenter Roeck Acked-by: Sören Brinkmann Signed-off-by: Stephen Boyd --- drivers/clk/clk-si570.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c index 20a5aec98b1a..cf478aa9fa5d 100644 --- a/drivers/clk/clk-si570.c +++ b/drivers/clk/clk-si570.c @@ -19,6 +19,7 @@ * GNU General Public License for more details. */ +#include #include #include #include -- cgit v1.3-6-gb490 From e2a657090a0b7f804f3b9f1a7735e79c62baa636 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 1 May 2015 16:09:33 -0700 Subject: clk: ingenic: Include clk.h This clock provider uses the consumer API, so include clk.h explicitly. Cc: Paul Burton Cc: Paul Cercueil Cc: Ralf Baechle Signed-off-by: Stephen Boyd --- drivers/clk/ingenic/cgu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c index b936cdd1a13c..7cfb7b2a2ed6 100644 --- a/drivers/clk/ingenic/cgu.c +++ b/drivers/clk/ingenic/cgu.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include -- cgit v1.3-6-gb490 From cb58e14efbc4d72542b9d62f5ee0522fe0147259 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 9 Jul 2015 15:24:51 -0700 Subject: clk: pistachio: Include clk.h This clock provider uses the consumer API, so include clk.h explicitly. Cc: Andrew Bresticker Cc: Ralf Baechle Signed-off-by: Stephen Boyd --- drivers/clk/pistachio/clk.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/clk/pistachio/clk.c b/drivers/clk/pistachio/clk.c index 85faa83e1bd7..698cad4f509e 100644 --- a/drivers/clk/pistachio/clk.c +++ b/drivers/clk/pistachio/clk.c @@ -6,6 +6,7 @@ * version 2, as published by the Free Software Foundation. */ +#include #include #include #include -- cgit v1.3-6-gb490 From 27df3ee27813e2f78ddd8c895d949d44102150c3 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 9 Jul 2015 15:24:51 -0700 Subject: clk: ti: Switch clk-provider.h include to clk.h This file isn't a clock provider but uses the consumer API, so include clk.h instead of clk-provider.h. Acked-by: Tero Kristo Signed-off-by: Stephen Boyd --- drivers/clk/ti/clk-2xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/ti/clk-2xxx.c b/drivers/clk/ti/clk-2xxx.c index c808ab3d2bb2..20cf5eed8c3d 100644 --- a/drivers/clk/ti/clk-2xxx.c +++ b/drivers/clk/ti/clk-2xxx.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include static struct ti_dt_clk omap2xxx_clks[] = { -- cgit v1.3-6-gb490 From 6a8ce8c96c1b2fce0a275b5858c3508ca419d8cb Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 19 Jun 2015 15:00:46 -0700 Subject: clk: at91: Include clk.h and slab.h This clock provider uses the consumer API, so include clk.h explicitly. Also include slab.h instead of relying on clkdev.h for it. Acked-by: Boris Brezillon Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-slow.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c index 98a84a865fe1..0a7aef39ab5b 100644 --- a/drivers/clk/at91/clk-slow.c +++ b/drivers/clk/at91/clk-slow.c @@ -10,8 +10,10 @@ * */ +#include #include #include +#include #include #include #include -- cgit v1.3-6-gb490 From 6acc63b5023cbd03d2e04e24cc8d979a69a8ab27 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 13 Jul 2015 16:47:44 -0700 Subject: clk: h8300: Remove clk.h and clkdev.h includes Neither of these includes are used in these files, remove them. Cc: Yoshinori Sato Signed-off-by: Stephen Boyd --- drivers/clk/h8300/clk-div.c | 2 -- drivers/clk/h8300/clk-h8s2678.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/h8300/clk-div.c b/drivers/clk/h8300/clk-div.c index 56f9eba91b83..1aaf75edf097 100644 --- a/drivers/clk/h8300/clk-div.c +++ b/drivers/clk/h8300/clk-div.c @@ -4,8 +4,6 @@ * Copyright 2015 Yoshinori Sato */ -#include -#include #include #include #include diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c index 4701b093e497..44aa45f71f1b 100644 --- a/drivers/clk/h8300/clk-h8s2678.c +++ b/drivers/clk/h8300/clk-h8s2678.c @@ -4,8 +4,6 @@ * Copyright 2015 Yoshinori Sato */ -#include -#include #include #include #include -- cgit v1.3-6-gb490 From fc865d6b4a6b58db8497ac2cf188ad20a5cec00c Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Wed, 15 Jul 2015 15:34:39 +0530 Subject: enic: add adaptive coalescing intr for intx and msi poll Adaptive interrupt coalescing is available for msix. This patch adds the support for msi poll. Interface for adaptive interrupt coalescing is already added in driver. We just did not enable it for legacy intr & msi. enic_calc_int_moderation() & enic_set_int_moderation() are defined as static after enic_poll. Since enic_poll needs it, move both of these function definitions above enic_poll. No change in functionality. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_main.c | 135 ++++++++++++++-------------- 1 file changed, 67 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 918a8e42139b..8f646e4e968b 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1149,6 +1149,64 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, return 0; } +static void enic_set_int_moderation(struct enic *enic, struct vnic_rq *rq) +{ + unsigned int intr = enic_msix_rq_intr(enic, rq->index); + struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)]; + u32 timer = cq->tobe_rx_coal_timeval; + + if (cq->tobe_rx_coal_timeval != cq->cur_rx_coal_timeval) { + vnic_intr_coalescing_timer_set(&enic->intr[intr], timer); + cq->cur_rx_coal_timeval = cq->tobe_rx_coal_timeval; + } +} + +static void enic_calc_int_moderation(struct enic *enic, struct vnic_rq *rq) +{ + struct enic_rx_coal *rx_coal = &enic->rx_coalesce_setting; + struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)]; + struct vnic_rx_bytes_counter *pkt_size_counter = &cq->pkt_size_counter; + int index; + u32 timer; + u32 range_start; + u32 traffic; + u64 delta; + ktime_t now = ktime_get(); + + delta = ktime_us_delta(now, cq->prev_ts); + if (delta < ENIC_AIC_TS_BREAK) + return; + cq->prev_ts = now; + + traffic = pkt_size_counter->large_pkt_bytes_cnt + + pkt_size_counter->small_pkt_bytes_cnt; + /* The table takes Mbps + * traffic *= 8 => bits + * traffic *= (10^6 / delta) => bps + * traffic /= 10^6 => Mbps + * + * Combining, traffic *= (8 / delta) + */ + + traffic <<= 3; + traffic = delta > UINT_MAX ? 0 : traffic / (u32)delta; + + for (index = 0; index < ENIC_MAX_COALESCE_TIMERS; index++) + if (traffic < mod_table[index].rx_rate) + break; + range_start = (pkt_size_counter->small_pkt_bytes_cnt > + pkt_size_counter->large_pkt_bytes_cnt << 1) ? + rx_coal->small_pkt_range_start : + rx_coal->large_pkt_range_start; + timer = range_start + ((rx_coal->range_end - range_start) * + mod_table[index].range_percent / 100); + /* Damping */ + cq->tobe_rx_coal_timeval = (timer + cq->tobe_rx_coal_timeval) >> 1; + + pkt_size_counter->large_pkt_bytes_cnt = 0; + pkt_size_counter->small_pkt_bytes_cnt = 0; +} + static int enic_poll(struct napi_struct *napi, int budget) { struct net_device *netdev = napi->dev; @@ -1199,6 +1257,11 @@ static int enic_poll(struct napi_struct *napi, int budget) if (err) rq_work_done = rq_work_to_do; + if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) + /* Call the function which refreshes the intr coalescing timer + * value based on the traffic. + */ + enic_calc_int_moderation(enic, &enic->rq[0]); if (rq_work_done < rq_work_to_do) { @@ -1207,70 +1270,14 @@ static int enic_poll(struct napi_struct *napi, int budget) */ napi_complete(napi); + if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) + enic_set_int_moderation(enic, &enic->rq[0]); vnic_intr_unmask(&enic->intr[intr]); } return rq_work_done; } -static void enic_set_int_moderation(struct enic *enic, struct vnic_rq *rq) -{ - unsigned int intr = enic_msix_rq_intr(enic, rq->index); - struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)]; - u32 timer = cq->tobe_rx_coal_timeval; - - if (cq->tobe_rx_coal_timeval != cq->cur_rx_coal_timeval) { - vnic_intr_coalescing_timer_set(&enic->intr[intr], timer); - cq->cur_rx_coal_timeval = cq->tobe_rx_coal_timeval; - } -} - -static void enic_calc_int_moderation(struct enic *enic, struct vnic_rq *rq) -{ - struct enic_rx_coal *rx_coal = &enic->rx_coalesce_setting; - struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)]; - struct vnic_rx_bytes_counter *pkt_size_counter = &cq->pkt_size_counter; - int index; - u32 timer; - u32 range_start; - u32 traffic; - u64 delta; - ktime_t now = ktime_get(); - - delta = ktime_us_delta(now, cq->prev_ts); - if (delta < ENIC_AIC_TS_BREAK) - return; - cq->prev_ts = now; - - traffic = pkt_size_counter->large_pkt_bytes_cnt + - pkt_size_counter->small_pkt_bytes_cnt; - /* The table takes Mbps - * traffic *= 8 => bits - * traffic *= (10^6 / delta) => bps - * traffic /= 10^6 => Mbps - * - * Combining, traffic *= (8 / delta) - */ - - traffic <<= 3; - traffic = delta > UINT_MAX ? 0 : traffic / (u32)delta; - - for (index = 0; index < ENIC_MAX_COALESCE_TIMERS; index++) - if (traffic < mod_table[index].rx_rate) - break; - range_start = (pkt_size_counter->small_pkt_bytes_cnt > - pkt_size_counter->large_pkt_bytes_cnt << 1) ? - rx_coal->small_pkt_range_start : - rx_coal->large_pkt_range_start; - timer = range_start + ((rx_coal->range_end - range_start) * - mod_table[index].range_percent / 100); - /* Damping */ - cq->tobe_rx_coal_timeval = (timer + cq->tobe_rx_coal_timeval) >> 1; - - pkt_size_counter->large_pkt_bytes_cnt = 0; - pkt_size_counter->small_pkt_bytes_cnt = 0; -} - #ifdef CONFIG_RFS_ACCEL static void enic_free_rx_cpu_rmap(struct enic *enic) { @@ -1407,10 +1414,8 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget) if (err) work_done = work_to_do; if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) - /* Call the function which refreshes - * the intr coalescing timer value based on - * the traffic. This is supported only in - * the case of MSI-x mode + /* Call the function which refreshes the intr coalescing timer + * value based on the traffic. */ enic_calc_int_moderation(enic, &enic->rq[rq]); @@ -1569,12 +1574,6 @@ static void enic_set_rx_coal_setting(struct enic *enic) int index = -1; struct enic_rx_coal *rx_coal = &enic->rx_coalesce_setting; - /* If intr mode is not MSIX, do not do adaptive coalescing */ - if (VNIC_DEV_INTR_MODE_MSIX != vnic_dev_get_intr_mode(enic->vdev)) { - netdev_info(enic->netdev, "INTR mode is not MSIX, Not initializing adaptive coalescing"); - return; - } - /* 1. Read the link speed from fw * 2. Pick the default range for the speed * 3. Update it in enic->rx_coalesce_setting -- cgit v1.3-6-gb490 From d9382bda4ef97d73c77ecaed7a8d5df20da8b8dd Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Wed, 15 Jul 2015 15:34:40 +0530 Subject: enic: allow adaptive coalesce setting for msi/legacy intr * Allow setting of adaptive coalescing setting for all types of interrupt. * In msi & legacy intr, we use single interrupt for rx & tx. In this case tx_coalesce_usecs is invalid. We should use only rx_coalesce_usecs. Do not display tx_coal values for msi/intx. And do not allow user to set this as well. * Driver supports only tx/rx_coalesce_usec and adaptive coalesce settings. For other values, driver does not return error. So ethtool succeeds for unsupported values. Introduce enic_coalesce_valid() function to validate the coalescing values. * If user requests for coalesce value greater than what adaptor supports, driver uses the max value. We should at least log this. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_ethtool.c | 113 ++++++++++++++----------- 1 file changed, 65 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index f3f1601a76f3..f44a39c40642 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -224,7 +224,8 @@ static int enic_get_coalesce(struct net_device *netdev, struct enic *enic = netdev_priv(netdev); struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting; - ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs; + if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) + ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs; ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs; if (rxcoal->use_adaptive_rx_coalesce) ecmd->use_adaptive_rx_coalesce = 1; @@ -234,6 +235,53 @@ static int enic_get_coalesce(struct net_device *netdev, return 0; } +static int enic_coalesce_valid(struct enic *enic, + struct ethtool_coalesce *ec) +{ + u32 coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev); + u32 rx_coalesce_usecs_high = min_t(u32, coalesce_usecs_max, + ec->rx_coalesce_usecs_high); + u32 rx_coalesce_usecs_low = min_t(u32, coalesce_usecs_max, + ec->rx_coalesce_usecs_low); + + if (ec->rx_max_coalesced_frames || + ec->rx_coalesce_usecs_irq || + ec->rx_max_coalesced_frames_irq || + ec->tx_max_coalesced_frames || + ec->tx_coalesce_usecs_irq || + ec->tx_max_coalesced_frames_irq || + ec->stats_block_coalesce_usecs || + ec->use_adaptive_tx_coalesce || + ec->pkt_rate_low || + ec->rx_max_coalesced_frames_low || + ec->tx_coalesce_usecs_low || + ec->tx_max_coalesced_frames_low || + ec->pkt_rate_high || + ec->rx_max_coalesced_frames_high || + ec->tx_coalesce_usecs_high || + ec->tx_max_coalesced_frames_high || + ec->rate_sample_interval) + return -EINVAL; + + if ((vnic_dev_get_intr_mode(enic->vdev) != VNIC_DEV_INTR_MODE_MSIX) && + ec->tx_coalesce_usecs) + return -EINVAL; + + if ((ec->tx_coalesce_usecs > coalesce_usecs_max) || + (ec->rx_coalesce_usecs > coalesce_usecs_max) || + (ec->rx_coalesce_usecs_low > coalesce_usecs_max) || + (ec->rx_coalesce_usecs_high > coalesce_usecs_max)) + netdev_info(enic->netdev, "ethtool_set_coalesce: adaptor supports max coalesce value of %d. Setting max value.\n", + coalesce_usecs_max); + + if (ec->rx_coalesce_usecs_high && + (rx_coalesce_usecs_high < + rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF)) + return -EINVAL; + + return 0; +} + static int enic_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd) { @@ -244,8 +292,12 @@ static int enic_set_coalesce(struct net_device *netdev, u32 rx_coalesce_usecs_high; u32 coalesce_usecs_max; unsigned int i, intr; + int ret; struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting; + ret = enic_coalesce_valid(enic, ecmd); + if (ret) + return ret; coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev); tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs, coalesce_usecs_max); @@ -257,59 +309,24 @@ static int enic_set_coalesce(struct net_device *netdev, rx_coalesce_usecs_high = min_t(u32, ecmd->rx_coalesce_usecs_high, coalesce_usecs_max); - switch (vnic_dev_get_intr_mode(enic->vdev)) { - case VNIC_DEV_INTR_MODE_INTX: - if (tx_coalesce_usecs != rx_coalesce_usecs) - return -EINVAL; - if (ecmd->use_adaptive_rx_coalesce || - ecmd->rx_coalesce_usecs_low || - ecmd->rx_coalesce_usecs_high) - return -EINVAL; - - intr = enic_legacy_io_intr(); - vnic_intr_coalescing_timer_set(&enic->intr[intr], - tx_coalesce_usecs); - break; - case VNIC_DEV_INTR_MODE_MSI: - if (tx_coalesce_usecs != rx_coalesce_usecs) - return -EINVAL; - if (ecmd->use_adaptive_rx_coalesce || - ecmd->rx_coalesce_usecs_low || - ecmd->rx_coalesce_usecs_high) - return -EINVAL; - - vnic_intr_coalescing_timer_set(&enic->intr[0], - tx_coalesce_usecs); - break; - case VNIC_DEV_INTR_MODE_MSIX: - if (ecmd->rx_coalesce_usecs_high && - (rx_coalesce_usecs_high < - rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF)) - return -EINVAL; - + if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) { for (i = 0; i < enic->wq_count; i++) { intr = enic_msix_wq_intr(enic, i); vnic_intr_coalescing_timer_set(&enic->intr[intr], - tx_coalesce_usecs); - } - - rxcoal->use_adaptive_rx_coalesce = - !!ecmd->use_adaptive_rx_coalesce; - if (!rxcoal->use_adaptive_rx_coalesce) - enic_intr_coal_set_rx(enic, rx_coalesce_usecs); - - if (ecmd->rx_coalesce_usecs_high) { - rxcoal->range_end = rx_coalesce_usecs_high; - rxcoal->small_pkt_range_start = rx_coalesce_usecs_low; - rxcoal->large_pkt_range_start = rx_coalesce_usecs_low + - ENIC_AIC_LARGE_PKT_DIFF; + tx_coalesce_usecs); } - break; - default: - break; + enic->tx_coalesce_usecs = tx_coalesce_usecs; + } + rxcoal->use_adaptive_rx_coalesce = !!ecmd->use_adaptive_rx_coalesce; + if (!rxcoal->use_adaptive_rx_coalesce) + enic_intr_coal_set_rx(enic, rx_coalesce_usecs); + if (ecmd->rx_coalesce_usecs_high) { + rxcoal->range_end = rx_coalesce_usecs_high; + rxcoal->small_pkt_range_start = rx_coalesce_usecs_low; + rxcoal->large_pkt_range_start = rx_coalesce_usecs_low + + ENIC_AIC_LARGE_PKT_DIFF; } - enic->tx_coalesce_usecs = tx_coalesce_usecs; enic->rx_coalesce_usecs = rx_coalesce_usecs; return 0; -- cgit v1.3-6-gb490 From 22f94e625635fb8555f5e7361745ea780a3853e4 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 15 Jul 2015 16:31:09 +0200 Subject: bonding: trivial: remove unused variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of these: drivers/net/bonding//bond_main.c: In function ‘bond_update_slave_arr’: drivers/net/bonding//bond_main.c:3754:6: warning: variable ‘slaves_in_agg’ set but not used [-Wunused-but-set-variable] int slaves_in_agg; ^ CC [M] drivers/net/bonding//bond_3ad.o drivers/net/bonding//bond_3ad.c: In function ‘ad_marker_response_received’: drivers/net/bonding//bond_3ad.c:1870:61: warning: parameter ‘marker’ set but not used [-Wunused-but-set-parameter] static void ad_marker_response_received(struct bond_marker *marker, ^ drivers/net/bonding//bond_3ad.c:1871:19: warning: parameter ‘port’ set but not used [-Wunused-but-set-parameter] struct port *port) ^ Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 2 -- drivers/net/bonding/bond_main.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 7fde4d5c2b28..3c45358844eb 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1870,8 +1870,6 @@ static void ad_marker_info_received(struct bond_marker *marker_info, static void ad_marker_response_received(struct bond_marker *marker, struct port *port) { - marker = NULL; - port = NULL; /* DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW */ } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 317a49480475..1c6a773c87ea 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3751,7 +3751,6 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) struct slave *slave; struct list_head *iter; struct bond_up_slave *new_arr, *old_arr; - int slaves_in_agg; int agg_id = 0; int ret = 0; @@ -3782,7 +3781,6 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) } goto out; } - slaves_in_agg = ad_info.ports; agg_id = ad_info.aggregator_id; } bond_for_each_slave(bond, slave, iter) { -- cgit v1.3-6-gb490 From 8ce344c66e3ce122585cfe68be1ef0ffd176380d Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sun, 19 Jul 2015 18:50:38 +0200 Subject: ACPI / processor: remove leftover __refdata annotations The processor_handler structure does not reference any __init / __exit code or data. Therefore the __refdata annotation is not needed. It used to be prior to commit fe7bf106ebc2 ("acpi: delete __cpuinit usage from all acpi files") due to the __cpuinit annotation of acpi_processor_add(). But with that commit in place that requirement has gone. The same is true for the acpi_cpu_notifier notifier block. acpi_cpu_soft_notify() used to be marked __cpuinit but lost its annotation in the above mentioned commit as well. Therefore the __refdata annotation isn't needed there either. Just drop the unneded __refdata annotations to be able to catch future section mismatches. Signed-off-by: Mathias Krause Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_processor.c | 2 +- drivers/acpi/processor_driver.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 92a5f738e370..985b8a83184e 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -485,7 +485,7 @@ static const struct acpi_device_id processor_device_ids[] = { { } }; -static struct acpi_scan_handler __refdata processor_handler = { +static struct acpi_scan_handler processor_handler = { .ids = processor_device_ids, .attach = acpi_processor_add, #ifdef CONFIG_ACPI_HOTPLUG_CPU diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index d9f71581b79b..cc820d840c61 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -159,7 +159,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block __refdata acpi_cpu_notifier = { +static struct notifier_block acpi_cpu_notifier = { .notifier_call = acpi_cpu_soft_notify, }; -- cgit v1.3-6-gb490 From 44152cb82d1ad6ae6f8b47c5437f6f1e65ca82c4 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 18 Jul 2015 11:30:59 +0530 Subject: cpufreq: governor: Keep single copy of information common to policy->cpus Some information is common to all CPUs belonging to a policy, but are kept on per-cpu basis. Lets keep that in another structure common to all policy->cpus. That will make updates/reads to that less complex and less error prone. The memory for cpu_common_dbs_info is allocated/freed at INIT/EXIT, so that it we don't reallocate it for STOP/START sequence. It will be also be used (in next patch) while the governor is stopped and so must not be freed that early. Reviewed-and-tested-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_conservative.c | 18 ++++--- drivers/cpufreq/cpufreq_governor.c | 92 +++++++++++++++++++++++++--------- drivers/cpufreq/cpufreq_governor.h | 24 +++++---- drivers/cpufreq/cpufreq_ondemand.c | 38 +++++++------- 4 files changed, 114 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index af47d322679e..d21c3cff9056 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -47,7 +47,7 @@ static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners, static void cs_check_cpu(int cpu, unsigned int load) { struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); - struct cpufreq_policy *policy = dbs_info->cdbs.policy; + struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; struct dbs_data *dbs_data = policy->governor_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; @@ -106,22 +106,24 @@ static void cs_dbs_timer(struct work_struct *work) { struct cs_cpu_dbs_info_s *dbs_info = container_of(work, struct cs_cpu_dbs_info_s, cdbs.dwork.work); - unsigned int cpu = dbs_info->cdbs.policy->cpu; + struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; + unsigned int cpu = policy->cpu; struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); - struct dbs_data *dbs_data = dbs_info->cdbs.policy->governor_data; + struct dbs_data *dbs_data = policy->governor_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; int delay = delay_for_sampling_rate(cs_tuners->sampling_rate); bool modify_all = true; - mutex_lock(&core_dbs_info->cdbs.timer_mutex); - if (!need_load_eval(&core_dbs_info->cdbs, cs_tuners->sampling_rate)) + mutex_lock(&core_dbs_info->cdbs.shared->timer_mutex); + if (!need_load_eval(core_dbs_info->cdbs.shared, + cs_tuners->sampling_rate)) modify_all = false; else dbs_check_cpu(dbs_data, cpu); - gov_queue_work(dbs_data, dbs_info->cdbs.policy, delay, modify_all); - mutex_unlock(&core_dbs_info->cdbs.timer_mutex); + gov_queue_work(dbs_data, policy, delay, modify_all); + mutex_unlock(&core_dbs_info->cdbs.shared->timer_mutex); } static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, @@ -135,7 +137,7 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, if (!dbs_info->enable) return 0; - policy = dbs_info->cdbs.policy; + policy = dbs_info->cdbs.shared->policy; /* * we only care if our internally tracked freq moves outside the 'valid' diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index c0566f86caed..b01cb729104b 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -35,7 +35,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) struct cpu_dbs_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); struct od_dbs_tuners *od_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; - struct cpufreq_policy *policy; + struct cpufreq_policy *policy = cdbs->shared->policy; unsigned int sampling_rate; unsigned int max_load = 0; unsigned int ignore_nice; @@ -60,8 +60,6 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) ignore_nice = cs_tuners->ignore_nice_load; } - policy = cdbs->policy; - /* Get Absolute Load */ for_each_cpu(j, policy->cpus) { struct cpu_dbs_info *j_cdbs; @@ -209,17 +207,18 @@ static inline void gov_cancel_work(struct dbs_data *dbs_data, } /* Will return if we need to evaluate cpu load again or not */ -bool need_load_eval(struct cpu_dbs_info *cdbs, unsigned int sampling_rate) +bool need_load_eval(struct cpu_common_dbs_info *shared, + unsigned int sampling_rate) { - if (policy_is_shared(cdbs->policy)) { + if (policy_is_shared(shared->policy)) { ktime_t time_now = ktime_get(); - s64 delta_us = ktime_us_delta(time_now, cdbs->time_stamp); + s64 delta_us = ktime_us_delta(time_now, shared->time_stamp); /* Do nothing if we recently have sampled */ if (delta_us < (s64)(sampling_rate / 2)) return false; else - cdbs->time_stamp = time_now; + shared->time_stamp = time_now; } return true; @@ -238,6 +237,37 @@ static void set_sampling_rate(struct dbs_data *dbs_data, } } +static int alloc_common_dbs_info(struct cpufreq_policy *policy, + struct common_dbs_data *cdata) +{ + struct cpu_common_dbs_info *shared; + int j; + + /* Allocate memory for the common information for policy->cpus */ + shared = kzalloc(sizeof(*shared), GFP_KERNEL); + if (!shared) + return -ENOMEM; + + /* Set shared for all CPUs, online+offline */ + for_each_cpu(j, policy->related_cpus) + cdata->get_cpu_cdbs(j)->shared = shared; + + return 0; +} + +static void free_common_dbs_info(struct cpufreq_policy *policy, + struct common_dbs_data *cdata) +{ + struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(policy->cpu); + struct cpu_common_dbs_info *shared = cdbs->shared; + int j; + + for_each_cpu(j, policy->cpus) + cdata->get_cpu_cdbs(j)->shared = NULL; + + kfree(shared); +} + static int cpufreq_governor_init(struct cpufreq_policy *policy, struct dbs_data *dbs_data, struct common_dbs_data *cdata) @@ -248,6 +278,11 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy, if (dbs_data) { if (WARN_ON(have_governor_per_policy())) return -EINVAL; + + ret = alloc_common_dbs_info(policy, cdata); + if (ret) + return ret; + dbs_data->usage_count++; policy->governor_data = dbs_data; return 0; @@ -257,12 +292,16 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy, if (!dbs_data) return -ENOMEM; + ret = alloc_common_dbs_info(policy, cdata); + if (ret) + goto free_dbs_data; + dbs_data->cdata = cdata; dbs_data->usage_count = 1; ret = cdata->init(dbs_data, !policy->governor->initialized); if (ret) - goto free_dbs_data; + goto free_common_dbs_info; /* policy latency is in ns. Convert it to us first */ latency = policy->cpuinfo.transition_latency / 1000; @@ -299,6 +338,8 @@ put_kobj: } cdata_exit: cdata->exit(dbs_data, !policy->governor->initialized); +free_common_dbs_info: + free_common_dbs_info(policy, cdata); free_dbs_data: kfree(dbs_data); return ret; @@ -322,6 +363,8 @@ static void cpufreq_governor_exit(struct cpufreq_policy *policy, cdata->exit(dbs_data, policy->governor->initialized == 1); kfree(dbs_data); } + + free_common_dbs_info(policy, cdata); } static int cpufreq_governor_start(struct cpufreq_policy *policy, @@ -330,6 +373,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, struct common_dbs_data *cdata = dbs_data->cdata; unsigned int sampling_rate, ignore_nice, j, cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_common_dbs_info *shared = cdbs->shared; int io_busy = 0; if (!policy->cur) @@ -348,11 +392,14 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, io_busy = od_tuners->io_is_busy; } + shared->policy = policy; + shared->time_stamp = ktime_get(); + mutex_init(&shared->timer_mutex); + for_each_cpu(j, policy->cpus) { struct cpu_dbs_info *j_cdbs = cdata->get_cpu_cdbs(j); unsigned int prev_load; - j_cdbs->policy = policy; j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy); @@ -364,7 +411,6 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, if (ignore_nice) j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - mutex_init(&j_cdbs->timer_mutex); INIT_DEFERRABLE_WORK(&j_cdbs->dwork, cdata->gov_dbs_timer); } @@ -384,9 +430,6 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, od_ops->powersave_bias_init_cpu(cpu); } - /* Initiate timer time stamp */ - cdbs->time_stamp = ktime_get(); - gov_queue_work(dbs_data, policy, delay_for_sampling_rate(sampling_rate), true); return 0; @@ -398,6 +441,9 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_common_dbs_info *shared = cdbs->shared; + + gov_cancel_work(dbs_data, policy); if (cdata->governor == GOV_CONSERVATIVE) { struct cs_cpu_dbs_info_s *cs_dbs_info = @@ -406,10 +452,8 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, cs_dbs_info->enable = 0; } - gov_cancel_work(dbs_data, policy); - - mutex_destroy(&cdbs->timer_mutex); - cdbs->policy = NULL; + shared->policy = NULL; + mutex_destroy(&shared->timer_mutex); } static void cpufreq_governor_limits(struct cpufreq_policy *policy, @@ -419,18 +463,18 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy, unsigned int cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); - if (!cdbs->policy) + if (!cdbs->shared || !cdbs->shared->policy) return; - mutex_lock(&cdbs->timer_mutex); - if (policy->max < cdbs->policy->cur) - __cpufreq_driver_target(cdbs->policy, policy->max, + mutex_lock(&cdbs->shared->timer_mutex); + if (policy->max < cdbs->shared->policy->cur) + __cpufreq_driver_target(cdbs->shared->policy, policy->max, CPUFREQ_RELATION_H); - else if (policy->min > cdbs->policy->cur) - __cpufreq_driver_target(cdbs->policy, policy->min, + else if (policy->min > cdbs->shared->policy->cur) + __cpufreq_driver_target(cdbs->shared->policy, policy->min, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); - mutex_unlock(&cdbs->timer_mutex); + mutex_unlock(&cdbs->shared->timer_mutex); } int cpufreq_governor_dbs(struct cpufreq_policy *policy, diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index a0f8eb79ee6d..8e4a25f0730c 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -128,6 +128,18 @@ static void *get_cpu_dbs_info_s(int cpu) \ * cs_*: Conservative governor */ +/* Common to all CPUs of a policy */ +struct cpu_common_dbs_info { + struct cpufreq_policy *policy; + /* + * percpu mutex that serializes governor limit change with gov_dbs_timer + * invocation. We do not want gov_dbs_timer to run when user is changing + * the governor or limits. + */ + struct mutex timer_mutex; + ktime_t time_stamp; +}; + /* Per cpu structures */ struct cpu_dbs_info { u64 prev_cpu_idle; @@ -140,15 +152,8 @@ struct cpu_dbs_info { * wake-up from idle. */ unsigned int prev_load; - struct cpufreq_policy *policy; struct delayed_work dwork; - /* - * percpu mutex that serializes governor limit change with gov_dbs_timer - * invocation. We do not want gov_dbs_timer to run when user is changing - * the governor or limits. - */ - struct mutex timer_mutex; - ktime_t time_stamp; + struct cpu_common_dbs_info *shared; }; struct od_cpu_dbs_info_s { @@ -264,7 +269,8 @@ static ssize_t show_sampling_rate_min_gov_pol \ extern struct mutex cpufreq_governor_lock; void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); -bool need_load_eval(struct cpu_dbs_info *cdbs, unsigned int sampling_rate); +bool need_load_eval(struct cpu_common_dbs_info *shared, + unsigned int sampling_rate); int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct common_dbs_data *cdata, unsigned int event); void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index d29c6f9c6e3e..14d7e86e7f94 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -155,7 +155,7 @@ static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq) static void od_check_cpu(int cpu, unsigned int load) { struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - struct cpufreq_policy *policy = dbs_info->cdbs.policy; + struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; struct dbs_data *dbs_data = policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; @@ -195,16 +195,18 @@ static void od_dbs_timer(struct work_struct *work) { struct od_cpu_dbs_info_s *dbs_info = container_of(work, struct od_cpu_dbs_info_s, cdbs.dwork.work); - unsigned int cpu = dbs_info->cdbs.policy->cpu; + struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; + unsigned int cpu = policy->cpu; struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - struct dbs_data *dbs_data = dbs_info->cdbs.policy->governor_data; + struct dbs_data *dbs_data = policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; int delay = 0, sample_type = core_dbs_info->sample_type; bool modify_all = true; - mutex_lock(&core_dbs_info->cdbs.timer_mutex); - if (!need_load_eval(&core_dbs_info->cdbs, od_tuners->sampling_rate)) { + mutex_lock(&core_dbs_info->cdbs.shared->timer_mutex); + if (!need_load_eval(core_dbs_info->cdbs.shared, + od_tuners->sampling_rate)) { modify_all = false; goto max_delay; } @@ -213,8 +215,7 @@ static void od_dbs_timer(struct work_struct *work) core_dbs_info->sample_type = OD_NORMAL_SAMPLE; if (sample_type == OD_SUB_SAMPLE) { delay = core_dbs_info->freq_lo_jiffies; - __cpufreq_driver_target(core_dbs_info->cdbs.policy, - core_dbs_info->freq_lo, + __cpufreq_driver_target(policy, core_dbs_info->freq_lo, CPUFREQ_RELATION_H); } else { dbs_check_cpu(dbs_data, cpu); @@ -230,8 +231,8 @@ max_delay: delay = delay_for_sampling_rate(od_tuners->sampling_rate * core_dbs_info->rate_mult); - gov_queue_work(dbs_data, dbs_info->cdbs.policy, delay, modify_all); - mutex_unlock(&core_dbs_info->cdbs.timer_mutex); + gov_queue_work(dbs_data, policy, delay, modify_all); + mutex_unlock(&core_dbs_info->cdbs.shared->timer_mutex); } /************************** sysfs interface ************************/ @@ -274,10 +275,10 @@ static void update_sampling_rate(struct dbs_data *dbs_data, dbs_info = &per_cpu(od_cpu_dbs_info, cpu); cpufreq_cpu_put(policy); - mutex_lock(&dbs_info->cdbs.timer_mutex); + mutex_lock(&dbs_info->cdbs.shared->timer_mutex); if (!delayed_work_pending(&dbs_info->cdbs.dwork)) { - mutex_unlock(&dbs_info->cdbs.timer_mutex); + mutex_unlock(&dbs_info->cdbs.shared->timer_mutex); continue; } @@ -286,15 +287,15 @@ static void update_sampling_rate(struct dbs_data *dbs_data, if (time_before(next_sampling, appointed_at)) { - mutex_unlock(&dbs_info->cdbs.timer_mutex); + mutex_unlock(&dbs_info->cdbs.shared->timer_mutex); cancel_delayed_work_sync(&dbs_info->cdbs.dwork); - mutex_lock(&dbs_info->cdbs.timer_mutex); + mutex_lock(&dbs_info->cdbs.shared->timer_mutex); - gov_queue_work(dbs_data, dbs_info->cdbs.policy, + gov_queue_work(dbs_data, policy, usecs_to_jiffies(new_rate), true); } - mutex_unlock(&dbs_info->cdbs.timer_mutex); + mutex_unlock(&dbs_info->cdbs.shared->timer_mutex); } } @@ -557,13 +558,16 @@ static void od_set_powersave_bias(unsigned int powersave_bias) get_online_cpus(); for_each_online_cpu(cpu) { + struct cpu_common_dbs_info *shared; + if (cpumask_test_cpu(cpu, &done)) continue; - policy = per_cpu(od_cpu_dbs_info, cpu).cdbs.policy; - if (!policy) + shared = per_cpu(od_cpu_dbs_info, cpu).cdbs.shared; + if (!shared) continue; + policy = shared->policy; cpumask_or(&done, &done, policy->cpus); if (policy->governor != &cpufreq_gov_ondemand) -- cgit v1.3-6-gb490 From 43e0ee361e96229959c2ce1eda1ad9d6b3c191b2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 18 Jul 2015 11:31:00 +0530 Subject: cpufreq: governor: split out common part of {cs|od}_dbs_timer() Some part of cs_dbs_timer() and od_dbs_timer() is exactly same and is unnecessarily duplicated. Create the real work-handler in cpufreq_governor.c and put the common code in this routine (dbs_timer()). Shouldn't make any functional change. Reviewed-and-tested-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_conservative.c | 27 +++++++----------------- drivers/cpufreq/cpufreq_governor.c | 38 ++++++++++++++++++++++++++++++---- drivers/cpufreq/cpufreq_governor.h | 10 ++++----- drivers/cpufreq/cpufreq_ondemand.c | 36 +++++++++++++------------------- 4 files changed, 60 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index d21c3cff9056..84a1506950a7 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -102,28 +102,15 @@ static void cs_check_cpu(int cpu, unsigned int load) } } -static void cs_dbs_timer(struct work_struct *work) +static unsigned int cs_dbs_timer(struct cpu_dbs_info *cdbs, + struct dbs_data *dbs_data, bool modify_all) { - struct cs_cpu_dbs_info_s *dbs_info = container_of(work, - struct cs_cpu_dbs_info_s, cdbs.dwork.work); - struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; - unsigned int cpu = policy->cpu; - struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info, - cpu); - struct dbs_data *dbs_data = policy->governor_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; - int delay = delay_for_sampling_rate(cs_tuners->sampling_rate); - bool modify_all = true; - - mutex_lock(&core_dbs_info->cdbs.shared->timer_mutex); - if (!need_load_eval(core_dbs_info->cdbs.shared, - cs_tuners->sampling_rate)) - modify_all = false; - else - dbs_check_cpu(dbs_data, cpu); - - gov_queue_work(dbs_data, policy, delay, modify_all); - mutex_unlock(&core_dbs_info->cdbs.shared->timer_mutex); + + if (modify_all) + dbs_check_cpu(dbs_data, cdbs->shared->policy->cpu); + + return delay_for_sampling_rate(cs_tuners->sampling_rate); } static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index b01cb729104b..7ed0ec2ac853 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -207,8 +207,8 @@ static inline void gov_cancel_work(struct dbs_data *dbs_data, } /* Will return if we need to evaluate cpu load again or not */ -bool need_load_eval(struct cpu_common_dbs_info *shared, - unsigned int sampling_rate) +static bool need_load_eval(struct cpu_common_dbs_info *shared, + unsigned int sampling_rate) { if (policy_is_shared(shared->policy)) { ktime_t time_now = ktime_get(); @@ -223,7 +223,37 @@ bool need_load_eval(struct cpu_common_dbs_info *shared, return true; } -EXPORT_SYMBOL_GPL(need_load_eval); + +static void dbs_timer(struct work_struct *work) +{ + struct cpu_dbs_info *cdbs = container_of(work, struct cpu_dbs_info, + dwork.work); + struct cpu_common_dbs_info *shared = cdbs->shared; + struct cpufreq_policy *policy = shared->policy; + struct dbs_data *dbs_data = policy->governor_data; + unsigned int sampling_rate, delay; + bool modify_all = true; + + mutex_lock(&shared->timer_mutex); + + if (dbs_data->cdata->governor == GOV_CONSERVATIVE) { + struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + + sampling_rate = cs_tuners->sampling_rate; + } else { + struct od_dbs_tuners *od_tuners = dbs_data->tuners; + + sampling_rate = od_tuners->sampling_rate; + } + + if (!need_load_eval(cdbs->shared, sampling_rate)) + modify_all = false; + + delay = dbs_data->cdata->gov_dbs_timer(cdbs, dbs_data, modify_all); + gov_queue_work(dbs_data, policy, delay, modify_all); + + mutex_unlock(&shared->timer_mutex); +} static void set_sampling_rate(struct dbs_data *dbs_data, unsigned int sampling_rate) @@ -411,7 +441,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, if (ignore_nice) j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - INIT_DEFERRABLE_WORK(&j_cdbs->dwork, cdata->gov_dbs_timer); + INIT_DEFERRABLE_WORK(&j_cdbs->dwork, dbs_timer); } if (cdata->governor == GOV_CONSERVATIVE) { diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 8e4a25f0730c..50f171796632 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -132,8 +132,8 @@ static void *get_cpu_dbs_info_s(int cpu) \ struct cpu_common_dbs_info { struct cpufreq_policy *policy; /* - * percpu mutex that serializes governor limit change with gov_dbs_timer - * invocation. We do not want gov_dbs_timer to run when user is changing + * percpu mutex that serializes governor limit change with dbs_timer + * invocation. We do not want dbs_timer to run when user is changing * the governor or limits. */ struct mutex timer_mutex; @@ -210,7 +210,9 @@ struct common_dbs_data { struct cpu_dbs_info *(*get_cpu_cdbs)(int cpu); void *(*get_cpu_dbs_info_s)(int cpu); - void (*gov_dbs_timer)(struct work_struct *work); + unsigned int (*gov_dbs_timer)(struct cpu_dbs_info *cdbs, + struct dbs_data *dbs_data, + bool modify_all); void (*gov_check_cpu)(int cpu, unsigned int load); int (*init)(struct dbs_data *dbs_data, bool notify); void (*exit)(struct dbs_data *dbs_data, bool notify); @@ -269,8 +271,6 @@ static ssize_t show_sampling_rate_min_gov_pol \ extern struct mutex cpufreq_governor_lock; void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); -bool need_load_eval(struct cpu_common_dbs_info *shared, - unsigned int sampling_rate); int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct common_dbs_data *cdata, unsigned int event); void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 14d7e86e7f94..1fa9088c84a8 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -191,48 +191,40 @@ static void od_check_cpu(int cpu, unsigned int load) } } -static void od_dbs_timer(struct work_struct *work) +static unsigned int od_dbs_timer(struct cpu_dbs_info *cdbs, + struct dbs_data *dbs_data, bool modify_all) { - struct od_cpu_dbs_info_s *dbs_info = - container_of(work, struct od_cpu_dbs_info_s, cdbs.dwork.work); - struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; + struct cpufreq_policy *policy = cdbs->shared->policy; unsigned int cpu = policy->cpu; - struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info, + struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - struct dbs_data *dbs_data = policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; - int delay = 0, sample_type = core_dbs_info->sample_type; - bool modify_all = true; + int delay = 0, sample_type = dbs_info->sample_type; - mutex_lock(&core_dbs_info->cdbs.shared->timer_mutex); - if (!need_load_eval(core_dbs_info->cdbs.shared, - od_tuners->sampling_rate)) { - modify_all = false; + if (!modify_all) goto max_delay; - } /* Common NORMAL_SAMPLE setup */ - core_dbs_info->sample_type = OD_NORMAL_SAMPLE; + dbs_info->sample_type = OD_NORMAL_SAMPLE; if (sample_type == OD_SUB_SAMPLE) { - delay = core_dbs_info->freq_lo_jiffies; - __cpufreq_driver_target(policy, core_dbs_info->freq_lo, + delay = dbs_info->freq_lo_jiffies; + __cpufreq_driver_target(policy, dbs_info->freq_lo, CPUFREQ_RELATION_H); } else { dbs_check_cpu(dbs_data, cpu); - if (core_dbs_info->freq_lo) { + if (dbs_info->freq_lo) { /* Setup timer for SUB_SAMPLE */ - core_dbs_info->sample_type = OD_SUB_SAMPLE; - delay = core_dbs_info->freq_hi_jiffies; + dbs_info->sample_type = OD_SUB_SAMPLE; + delay = dbs_info->freq_hi_jiffies; } } max_delay: if (!delay) delay = delay_for_sampling_rate(od_tuners->sampling_rate - * core_dbs_info->rate_mult); + * dbs_info->rate_mult); - gov_queue_work(dbs_data, policy, delay, modify_all); - mutex_unlock(&core_dbs_info->cdbs.shared->timer_mutex); + return delay; } /************************** sysfs interface ************************/ -- cgit v1.3-6-gb490 From a72c49590a1f9e5d26a71c3f807dbb8958c93513 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 18 Jul 2015 11:31:01 +0530 Subject: cpufreq: governor: Avoid invalid states with additional checks There can be races where the request has come to a wrong state. For example INIT followed by STOP (instead of START) or START followed by EXIT (instead of STOP). Address these races by making sure the state-machine never gets into any invalid state. Also return an error if an invalid state-transition is requested. Reviewed-and-tested-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 46 +++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 7ed0ec2ac853..f225dc975415 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -305,6 +305,10 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy, unsigned int latency; int ret; + /* State should be equivalent to EXIT */ + if (policy->governor_data) + return -EBUSY; + if (dbs_data) { if (WARN_ON(have_governor_per_policy())) return -EINVAL; @@ -375,10 +379,15 @@ free_dbs_data: return ret; } -static void cpufreq_governor_exit(struct cpufreq_policy *policy, - struct dbs_data *dbs_data) +static int cpufreq_governor_exit(struct cpufreq_policy *policy, + struct dbs_data *dbs_data) { struct common_dbs_data *cdata = dbs_data->cdata; + struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(policy->cpu); + + /* State should be equivalent to INIT */ + if (!cdbs->shared || cdbs->shared->policy) + return -EBUSY; policy->governor_data = NULL; if (!--dbs_data->usage_count) { @@ -395,6 +404,7 @@ static void cpufreq_governor_exit(struct cpufreq_policy *policy, } free_common_dbs_info(policy, cdata); + return 0; } static int cpufreq_governor_start(struct cpufreq_policy *policy, @@ -409,6 +419,10 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, if (!policy->cur) return -EINVAL; + /* State should be equivalent to INIT */ + if (!shared || shared->policy) + return -EBUSY; + if (cdata->governor == GOV_CONSERVATIVE) { struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; @@ -465,14 +479,18 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, return 0; } -static void cpufreq_governor_stop(struct cpufreq_policy *policy, - struct dbs_data *dbs_data) +static int cpufreq_governor_stop(struct cpufreq_policy *policy, + struct dbs_data *dbs_data) { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); struct cpu_common_dbs_info *shared = cdbs->shared; + /* State should be equivalent to START */ + if (!shared || !shared->policy) + return -EBUSY; + gov_cancel_work(dbs_data, policy); if (cdata->governor == GOV_CONSERVATIVE) { @@ -484,17 +502,19 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, shared->policy = NULL; mutex_destroy(&shared->timer_mutex); + return 0; } -static void cpufreq_governor_limits(struct cpufreq_policy *policy, - struct dbs_data *dbs_data) +static int cpufreq_governor_limits(struct cpufreq_policy *policy, + struct dbs_data *dbs_data) { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); + /* State should be equivalent to START */ if (!cdbs->shared || !cdbs->shared->policy) - return; + return -EBUSY; mutex_lock(&cdbs->shared->timer_mutex); if (policy->max < cdbs->shared->policy->cur) @@ -505,13 +525,15 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); mutex_unlock(&cdbs->shared->timer_mutex); + + return 0; } int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct common_dbs_data *cdata, unsigned int event) { struct dbs_data *dbs_data; - int ret = 0; + int ret; /* Lock governor to block concurrent initialization of governor */ mutex_lock(&cdata->mutex); @@ -531,17 +553,19 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, ret = cpufreq_governor_init(policy, dbs_data, cdata); break; case CPUFREQ_GOV_POLICY_EXIT: - cpufreq_governor_exit(policy, dbs_data); + ret = cpufreq_governor_exit(policy, dbs_data); break; case CPUFREQ_GOV_START: ret = cpufreq_governor_start(policy, dbs_data); break; case CPUFREQ_GOV_STOP: - cpufreq_governor_stop(policy, dbs_data); + ret = cpufreq_governor_stop(policy, dbs_data); break; case CPUFREQ_GOV_LIMITS: - cpufreq_governor_limits(policy, dbs_data); + ret = cpufreq_governor_limits(policy, dbs_data); break; + default: + ret = -EINVAL; } unlock: -- cgit v1.3-6-gb490 From 871ef3b53a2f4dd9be348c07b77df3c4bd74a37f Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 18 Jul 2015 11:31:02 +0530 Subject: cpufreq: governor: Don't WARN on invalid states With previous commit, governors have started to return errors on invalid state-transition requests. We already have a WARN for an invalid state-transition request in cpufreq_governor_dbs(). This does trigger today, as the sequence of events isn't guaranteed by cpufreq core. Lets stop warning on that for now, and make sure we don't enter an invalid state. Reviewed-and-tested-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index f225dc975415..939197ffa4ac 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -543,7 +543,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, else dbs_data = cdata->gdbs_data; - if (WARN_ON(!dbs_data && (event != CPUFREQ_GOV_POLICY_INIT))) { + if (!dbs_data && (event != CPUFREQ_GOV_POLICY_INIT)) { ret = -EINVAL; goto unlock; } -- cgit v1.3-6-gb490 From 4bc384ae6299d3f3a948efabda2a423e2a293ee0 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 18 Jul 2015 11:31:03 +0530 Subject: cpufreq: propagate errors returned from __cpufreq_governor() Return codes aren't honored properly in cpufreq_set_policy(). This can lead to two problems: - wrong errors propagated to sysfs - we try to do next state-change even if the previous one failed cpufreq_governor_dbs() now returns proper errors on all invalid state-transition requests and this code should honor that. Reviewed-and-tested-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a7b6ac6e048e..a3e8fb61cbcc 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2295,16 +2295,31 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, old_gov = policy->governor; /* end old governor */ if (old_gov) { - __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + if (ret) { + /* This can happen due to race with other operations */ + pr_debug("%s: Failed to Stop Governor: %s (%d)\n", + __func__, old_gov->name, ret); + return ret; + } + up_write(&policy->rwsem); - __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); + ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); down_write(&policy->rwsem); + + if (ret) { + pr_err("%s: Failed to Exit Governor: %s (%d)\n", + __func__, old_gov->name, ret); + return ret; + } } /* start new governor */ policy->governor = new_policy->governor; - if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) { - if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) + ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT); + if (!ret) { + ret = __cpufreq_governor(policy, CPUFREQ_GOV_START); + if (!ret) goto out; up_write(&policy->rwsem); @@ -2316,11 +2331,13 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, pr_debug("starting governor %s failed\n", policy->governor->name); if (old_gov) { policy->governor = old_gov; - __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT); - __cpufreq_governor(policy, CPUFREQ_GOV_START); + if (__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) + policy->governor = NULL; + else + __cpufreq_governor(policy, CPUFREQ_GOV_START); } - return -EINVAL; + return ret; out: pr_debug("governor: change or update limits\n"); -- cgit v1.3-6-gb490 From 8254973fa3459b512b6c0cd5b0e4641e4d7c048c Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 16 Jul 2015 10:39:14 +0900 Subject: rocker: forward packets to CPU when port is joined to openvswitch Teach rocker to forward packets to CPU when a port is joined to Open vSwitch. There is scope to later refine what is passed up as per Open vSwitch flows on a port. This does not change the behaviour of rocker ports that are not joined to Open vSwitch. Signed-off-by: Simon Horman Acked-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 62 +++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 932428314b80..4ccde93cd07a 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -202,6 +202,7 @@ enum { ROCKER_CTRL_IPV4_MCAST, ROCKER_CTRL_IPV6_MCAST, ROCKER_CTRL_DFLT_BRIDGING, + ROCKER_CTRL_DFLT_OVS, ROCKER_CTRL_MAX, }; @@ -321,9 +322,21 @@ static u16 rocker_port_vlan_to_vid(const struct rocker_port *rocker_port, return ntohs(vlan_id); } +static bool rocker_port_is_slave(const struct rocker_port *rocker_port, + const char *kind) +{ + return rocker_port->bridge_dev && + !strcmp(rocker_port->bridge_dev->rtnl_link_ops->kind, kind); +} + static bool rocker_port_is_bridged(const struct rocker_port *rocker_port) { - return !!rocker_port->bridge_dev; + return rocker_port_is_slave(rocker_port, "bridge"); +} + +static bool rocker_port_is_ovsed(const struct rocker_port *rocker_port) +{ + return rocker_port_is_slave(rocker_port, "openvswitch"); } #define ROCKER_OP_FLAG_REMOVE BIT(0) @@ -3275,6 +3288,12 @@ static struct rocker_ctrl { .bridge = true, .copy_to_cpu = true, }, + [ROCKER_CTRL_DFLT_OVS] = { + /* pass all pkts up to CPU */ + .eth_dst = zero_mac, + .eth_dst_mask = zero_mac, + .acl = true, + }, }; static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port, @@ -3787,11 +3806,14 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port, break; case BR_STATE_LEARNING: case BR_STATE_FORWARDING: - want[ROCKER_CTRL_LINK_LOCAL_MCAST] = true; + if (!rocker_port_is_ovsed(rocker_port)) + want[ROCKER_CTRL_LINK_LOCAL_MCAST] = true; want[ROCKER_CTRL_IPV4_MCAST] = true; want[ROCKER_CTRL_IPV6_MCAST] = true; if (rocker_port_is_bridged(rocker_port)) want[ROCKER_CTRL_DFLT_BRIDGING] = true; + else if (rocker_port_is_ovsed(rocker_port)) + want[ROCKER_CTRL_DFLT_OVS] = true; else want[ROCKER_CTRL_LOCAL_ARP] = true; break; @@ -5264,23 +5286,39 @@ static int rocker_port_bridge_leave(struct rocker_port *rocker_port) return err; } + +static int rocker_port_ovs_changed(struct rocker_port *rocker_port, + struct net_device *master) +{ + int err; + + rocker_port->bridge_dev = master; + + err = rocker_port_fwd_disable(rocker_port, SWITCHDEV_TRANS_NONE, 0); + if (err) + return err; + err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE, 0); + + return err; +} + static int rocker_port_master_changed(struct net_device *dev) { struct rocker_port *rocker_port = netdev_priv(dev); struct net_device *master = netdev_master_upper_dev_get(dev); int err = 0; - /* There are currently three cases handled here: - * 1. Joining a bridge - * 2. Leaving a previously joined bridge - * 3. Other, e.g. being added to or removed from a bond or openvswitch, - * in which case nothing is done - */ - if (master && master->rtnl_link_ops && - !strcmp(master->rtnl_link_ops->kind, "bridge")) - err = rocker_port_bridge_join(rocker_port, master); - else if (rocker_port_is_bridged(rocker_port)) + /* N.B: Do nothing if the type of master is not supported */ + if (master && master->rtnl_link_ops) { + if (!strcmp(master->rtnl_link_ops->kind, "bridge")) + err = rocker_port_bridge_join(rocker_port, master); + else if (!strcmp(master->rtnl_link_ops->kind, "openvswitch")) + err = rocker_port_ovs_changed(rocker_port, master); + } else if (rocker_port_is_bridged(rocker_port)) { err = rocker_port_bridge_leave(rocker_port); + } else if (rocker_port_is_ovsed(rocker_port)) { + err = rocker_port_ovs_changed(rocker_port, NULL); + } return err; } -- cgit v1.3-6-gb490 From 3f98a8e636757ce404f305d65dc93e9366112886 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sat, 18 Jul 2015 18:24:51 -0700 Subject: rocker: add offload_fwd_mark support If device flags ingress packet as "fwd offload", mark the skb->offlaod_fwd_mark using the ingress port's dev->offlaod_fwd_mark. This will be the hint to the kernel that this packet has already been forwarded by device to egress ports matching skb->offlaod_fwd_mark. For rocker, derive port dev->offlaod_fwd_mark based on device switch ID and port ifindex. If port is bridged, use the bridge ifindex rather than the port ifindex. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 11 +++++++++++ drivers/net/ethernet/rocker/rocker.h | 1 + 2 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 4ccde93cd07a..7b4c3474acfe 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4822,6 +4822,7 @@ static int rocker_port_rx_proc(const struct rocker *rocker, const struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1]; struct sk_buff *skb = rocker_desc_cookie_ptr_get(desc_info); size_t rx_len; + u16 rx_flags = 0; if (!skb) return -ENOENT; @@ -4829,6 +4830,8 @@ static int rocker_port_rx_proc(const struct rocker *rocker, rocker_tlv_parse_desc(attrs, ROCKER_TLV_RX_MAX, desc_info); if (!attrs[ROCKER_TLV_RX_FRAG_LEN]) return -EINVAL; + if (attrs[ROCKER_TLV_RX_FLAGS]) + rx_flags = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FLAGS]); rocker_dma_rx_ring_skb_unmap(rocker, attrs); @@ -4836,6 +4839,9 @@ static int rocker_port_rx_proc(const struct rocker *rocker, skb_put(skb, rx_len); skb->protocol = eth_type_trans(skb, rocker_port->dev); + if (rx_flags & ROCKER_RX_FLAGS_FWD_OFFLOAD) + skb->offload_fwd_mark = rocker_port->dev->offload_fwd_mark; + rocker_port->dev->stats.rx_packets++; rocker_port->dev->stats.rx_bytes += skb->len; @@ -4973,6 +4979,8 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) } rocker->ports[port_number] = rocker_port; + switchdev_port_fwd_mark_set(rocker_port->dev, NULL, false); + rocker_port_set_learning(rocker_port, SWITCHDEV_TRANS_NONE); err = rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, 0); @@ -5252,6 +5260,7 @@ static int rocker_port_bridge_join(struct rocker_port *rocker_port, rocker_port_internal_vlan_id_get(rocker_port, bridge->ifindex); rocker_port->bridge_dev = bridge; + switchdev_port_fwd_mark_set(rocker_port->dev, bridge, true); return rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE, untagged_vid, 0); @@ -5272,6 +5281,8 @@ static int rocker_port_bridge_leave(struct rocker_port *rocker_port) rocker_port_internal_vlan_id_get(rocker_port, rocker_port->dev->ifindex); + switchdev_port_fwd_mark_set(rocker_port->dev, rocker_port->bridge_dev, + false); rocker_port->bridge_dev = NULL; err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE, diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h index 08b2c3d96188..12490b2f6504 100644 --- a/drivers/net/ethernet/rocker/rocker.h +++ b/drivers/net/ethernet/rocker/rocker.h @@ -246,6 +246,7 @@ enum { #define ROCKER_RX_FLAGS_TCP BIT(5) #define ROCKER_RX_FLAGS_UDP BIT(6) #define ROCKER_RX_FLAGS_TCP_UDP_CSUM_GOOD BIT(7) +#define ROCKER_RX_FLAGS_FWD_OFFLOAD BIT(8) enum { ROCKER_TLV_TX_UNSPEC, -- cgit v1.3-6-gb490 From 0dacf3f664818ab1e3e0af8ef22a86c89f34d125 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:05 +0200 Subject: stmmac: use of_device_get_match_data to retrieve of match data By using of_device_get_match_data() the code that retrieve match data can be simplified quite a bit. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index f3918c7e7eeb..89e40ddc0391 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -109,13 +109,11 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { struct device_node *np = pdev->dev.of_node; + const struct stmmac_of_data *data; struct stmmac_dma_cfg *dma_cfg; - const struct of_device_id *device; - struct device *dev = &pdev->dev; - device = of_match_device(dev->driver->of_match_table, dev); - if (device->data) { - const struct stmmac_of_data *data = device->data; + data = of_device_get_match_data(&pdev->dev); + if (data) { plat->has_gmac = data->has_gmac; plat->enh_desc = data->enh_desc; plat->tx_coe = data->tx_coe; -- cgit v1.3-6-gb490 From 4ed2d8fca7979ad82d56b67ac83a50bba2dd3419 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:06 +0200 Subject: stmmac: clean up platform/of_match data retrieval Refactor code to clearly separate probing non-dt versus dt. In the non-dt case platform data must be supplied to probe successfully. For dt the platform data structure is created and match data is copied into it. Note that support for supplying platform data in dt from AUXDATA is dropped as no users in mainline does this. This change will allow dt dwmac-* drivers to call the config_dt() function from probe to create the needed platform data struct and retrieve common dt properties. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 50 +++++++++++++--------- 1 file changed, 29 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 89e40ddc0391..6e6ef859f58a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -105,13 +105,20 @@ static int dwmac1000_validate_ucast_entries(int ucast_entries) * set some private fields that will be used by the main at runtime. */ static int stmmac_probe_config_dt(struct platform_device *pdev, - struct plat_stmmacenet_data *plat, + struct plat_stmmacenet_data **plat_dat, const char **mac) { struct device_node *np = pdev->dev.of_node; + struct plat_stmmacenet_data *plat; const struct stmmac_of_data *data; struct stmmac_dma_cfg *dma_cfg; + plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); + if (!plat) + return -ENOMEM; + + *plat_dat = plat; + data = of_device_get_match_data(&pdev->dev); if (data) { plat->has_gmac = data->has_gmac; @@ -180,6 +187,12 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, */ plat->maxmtu = JUMBO_LEN; + /* Set default value for multicast hash bins */ + plat->multicast_filter_bins = HASH_TABLE_SIZE; + + /* Set default value for unicast filter entries */ + plat->unicast_filter_entries = 1; + /* * Currently only the properties needed on SPEAr600 * are provided. All other properties should be added @@ -242,7 +255,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, } #else static int stmmac_probe_config_dt(struct platform_device *pdev, - struct plat_stmmacenet_data *plat, + struct plat_stmmacenet_data **plat, const char **mac) { return -ENOSYS; @@ -301,29 +314,24 @@ int stmmac_pltfr_probe(struct platform_device *pdev) if (IS_ERR(stmmac_res.addr)) return PTR_ERR(stmmac_res.addr); - plat_dat = dev_get_platdata(&pdev->dev); - - if (!plat_dat) - plat_dat = devm_kzalloc(&pdev->dev, - sizeof(struct plat_stmmacenet_data), - GFP_KERNEL); - if (!plat_dat) { - pr_err("%s: ERROR: no memory", __func__); - return -ENOMEM; - } - - /* Set default value for multicast hash bins */ - plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; - - /* Set default value for unicast filter entries */ - plat_dat->unicast_filter_entries = 1; - if (pdev->dev.of_node) { - ret = stmmac_probe_config_dt(pdev, plat_dat, &stmmac_res.mac); + ret = stmmac_probe_config_dt(pdev, &plat_dat, &stmmac_res.mac); if (ret) { - pr_err("%s: main dt probe failed", __func__); + dev_err(&pdev->dev, "dt configuration failed\n"); return ret; } + } else { + plat_dat = dev_get_platdata(&pdev->dev); + if (!plat_dat) { + dev_err(&pdev->dev, "no platform data provided\n"); + return -EINVAL; + } + + /* Set default value for multicast hash bins */ + plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; + + /* Set default value for unicast filter entries */ + plat_dat->unicast_filter_entries = 1; } /* Custom setup (if needed) */ -- cgit v1.3-6-gb490 From f396cb01210909ab2de0b50b76677892c1bfeb5a Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:07 +0200 Subject: stmmac: introduce stmmac_get_platform_resources() Refactor all code that deals with platform resources into it's own get function. This function will later be used in the probe function in dwmac-* drivers. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 64 +++++++++++++--------- 1 file changed, 37 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 6e6ef859f58a..94962d75b99a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -262,33 +262,23 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, } #endif /* CONFIG_OF */ -/** - * stmmac_pltfr_probe - platform driver probe. - * @pdev: platform device pointer - * Description: platform_device probe function. It is to allocate - * the necessary platform resources, invoke custom helper (if required) and - * invoke the main probe function. - */ -int stmmac_pltfr_probe(struct platform_device *pdev) +static int stmmac_get_platform_resources(struct platform_device *pdev, + struct stmmac_resources *stmmac_res) { - struct stmmac_resources stmmac_res; - int ret = 0; struct resource *res; - struct device *dev = &pdev->dev; - struct plat_stmmacenet_data *plat_dat = NULL; - memset(&stmmac_res, 0, sizeof(stmmac_res)); + memset(stmmac_res, 0, sizeof(*stmmac_res)); /* Get IRQ information early to have an ability to ask for deferred * probe if needed before we went too far with resource allocation. */ - stmmac_res.irq = platform_get_irq_byname(pdev, "macirq"); - if (stmmac_res.irq < 0) { - if (stmmac_res.irq != -EPROBE_DEFER) { - dev_err(dev, + stmmac_res->irq = platform_get_irq_byname(pdev, "macirq"); + if (stmmac_res->irq < 0) { + if (stmmac_res->irq != -EPROBE_DEFER) { + dev_err(&pdev->dev, "MAC IRQ configuration information not found\n"); } - return stmmac_res.irq; + return stmmac_res->irq; } /* On some platforms e.g. SPEAr the wake up irq differs from the mac irq @@ -298,21 +288,41 @@ int stmmac_pltfr_probe(struct platform_device *pdev) * In case the wake up interrupt is not passed from the platform * so the driver will continue to use the mac irq (ndev->irq) */ - stmmac_res.wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq"); - if (stmmac_res.wol_irq < 0) { - if (stmmac_res.wol_irq == -EPROBE_DEFER) + stmmac_res->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq"); + if (stmmac_res->wol_irq < 0) { + if (stmmac_res->wol_irq == -EPROBE_DEFER) return -EPROBE_DEFER; - stmmac_res.wol_irq = stmmac_res.irq; + stmmac_res->wol_irq = stmmac_res->irq; } - stmmac_res.lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); - if (stmmac_res.lpi_irq == -EPROBE_DEFER) + stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); + if (stmmac_res->lpi_irq == -EPROBE_DEFER) return -EPROBE_DEFER; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - stmmac_res.addr = devm_ioremap_resource(dev, res); - if (IS_ERR(stmmac_res.addr)) - return PTR_ERR(stmmac_res.addr); + stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(stmmac_res->addr)) + return PTR_ERR(stmmac_res->addr); + + return 0; +} + +/** + * stmmac_pltfr_probe - platform driver probe. + * @pdev: platform device pointer + * Description: platform_device probe function. It is to allocate + * the necessary platform resources, invoke custom helper (if required) and + * invoke the main probe function. + */ +int stmmac_pltfr_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; if (pdev->dev.of_node) { ret = stmmac_probe_config_dt(pdev, &plat_dat, &stmmac_res.mac); -- cgit v1.3-6-gb490 From b0003ead75f394f1c6f3b704be5da8e9eb029f8c Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:08 +0200 Subject: stmmac: make stmmac_probe_config_dt return the platform data struct Since stmmac_probe_config_dt() allocates the platform data structure it is cleaner if it just returned this structure directly. This function will later be used in the probe function in dwmac-* drivers. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 28 ++++++++++------------ 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 94962d75b99a..ea467be93673 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -104,9 +104,8 @@ static int dwmac1000_validate_ucast_entries(int ucast_entries) * this function is to read the driver parameters from device-tree and * set some private fields that will be used by the main at runtime. */ -static int stmmac_probe_config_dt(struct platform_device *pdev, - struct plat_stmmacenet_data **plat_dat, - const char **mac) +static struct plat_stmmacenet_data * +stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { struct device_node *np = pdev->dev.of_node; struct plat_stmmacenet_data *plat; @@ -115,9 +114,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); if (!plat) - return -ENOMEM; - - *plat_dat = plat; + return ERR_PTR(-ENOMEM); data = of_device_get_match_data(&pdev->dev); if (data) { @@ -156,7 +153,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, /* If phy-handle is not specified, check if we have a fixed-phy */ if (!plat->phy_node && of_phy_is_fixed_link(np)) { if ((of_phy_register_fixed_link(np) < 0)) - return -ENODEV; + return ERR_PTR(-ENODEV); plat->phy_node = of_node_get(np); } @@ -233,7 +230,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, GFP_KERNEL); if (!dma_cfg) { of_node_put(np); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } plat->dma_cfg = dma_cfg; of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl); @@ -251,14 +248,13 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set."); } - return 0; + return plat; } #else -static int stmmac_probe_config_dt(struct platform_device *pdev, - struct plat_stmmacenet_data **plat, - const char **mac) +static struct plat_stmmacenet_data * +stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { - return -ENOSYS; + return ERR_PTR(-ENOSYS); } #endif /* CONFIG_OF */ @@ -325,10 +321,10 @@ int stmmac_pltfr_probe(struct platform_device *pdev) return ret; if (pdev->dev.of_node) { - ret = stmmac_probe_config_dt(pdev, &plat_dat, &stmmac_res.mac); - if (ret) { + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) { dev_err(&pdev->dev, "dt configuration failed\n"); - return ret; + return PTR_ERR(plat_dat); } } else { plat_dat = dev_get_platdata(&pdev->dev); -- cgit v1.3-6-gb490 From 402dae0bed98dd41c5d6ab321135e8568a54819e Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:09 +0200 Subject: stmmac: export probe_config_dt() and get_platform_resources() Export stmmac_probe_config_dt() and stmmac_get_platform_resources() so they can be used in the dwmac-* drivers themselves. This will allow us to build more flexible and standalone drivers which just use stmmac_platform as a library for setup functions. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 10 ++++++---- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h | 8 ++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index ea467be93673..eca0eb845241 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -104,7 +104,7 @@ static int dwmac1000_validate_ucast_entries(int ucast_entries) * this function is to read the driver parameters from device-tree and * set some private fields that will be used by the main at runtime. */ -static struct plat_stmmacenet_data * +struct plat_stmmacenet_data * stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { struct device_node *np = pdev->dev.of_node; @@ -251,15 +251,16 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) return plat; } #else -static struct plat_stmmacenet_data * +struct plat_stmmacenet_data * stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { return ERR_PTR(-ENOSYS); } #endif /* CONFIG_OF */ +EXPORT_SYMBOL_GPL(stmmac_probe_config_dt); -static int stmmac_get_platform_resources(struct platform_device *pdev, - struct stmmac_resources *stmmac_res) +int stmmac_get_platform_resources(struct platform_device *pdev, + struct stmmac_resources *stmmac_res) { struct resource *res; @@ -302,6 +303,7 @@ static int stmmac_get_platform_resources(struct platform_device *pdev, return 0; } +EXPORT_SYMBOL_GPL(stmmac_get_platform_resources); /** * stmmac_pltfr_probe - platform driver probe. diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index 71da86d7bd00..84ceb5342686 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -19,6 +19,14 @@ #ifndef __STMMAC_PLATFORM_H__ #define __STMMAC_PLATFORM_H__ +#include "stmmac.h" + +struct plat_stmmacenet_data * +stmmac_probe_config_dt(struct platform_device *pdev, const char **mac); + +int stmmac_get_platform_resources(struct platform_device *pdev, + struct stmmac_resources *stmmac_res); + int stmmac_pltfr_probe(struct platform_device *pdev); int stmmac_pltfr_remove(struct platform_device *pdev); extern const struct dev_pm_ops stmmac_pltfr_pm_ops; -- cgit v1.3-6-gb490 From f4f8dfdedf1b1ff34a5e6ff71c9e80a1643a0622 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:10 +0200 Subject: stmmac: add proper probe function to dwmac-lpc18xx By using a few functions from stmmac_platform we can now create a proper probe function in this driver. By doing so we can drop the OF match data and simplify the overall driver. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c | 59 +++++++++------------- 1 file changed, 23 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c index cb888d3ebbdc..78e9d1861896 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c @@ -25,66 +25,53 @@ # define LPC18XX_CREG_CREG6_ETHMODE_MII 0x0 # define LPC18XX_CREG_CREG6_ETHMODE_RMII 0x4 -struct lpc18xx_dwmac_priv_data { +static int lpc18xx_dwmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; struct regmap *reg; - int interface; -}; + u8 ethmode; + int ret; -static void *lpc18xx_dwmac_setup(struct platform_device *pdev) -{ - struct lpc18xx_dwmac_priv_data *dwmac; + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; - dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); - if (!dwmac) - return ERR_PTR(-ENOMEM); + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); - dwmac->interface = of_get_phy_mode(pdev->dev.of_node); - if (dwmac->interface < 0) - return ERR_PTR(dwmac->interface); + plat_dat->has_gmac = true; - dwmac->reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); - if (IS_ERR(dwmac->reg)) { - dev_err(&pdev->dev, "Syscon lookup failed\n"); - return dwmac->reg; + reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); + if (IS_ERR(reg)) { + dev_err(&pdev->dev, "syscon lookup failed\n"); + return PTR_ERR(reg); } - return dwmac; -} - -static int lpc18xx_dwmac_init(struct platform_device *pdev, void *priv) -{ - struct lpc18xx_dwmac_priv_data *dwmac = priv; - u8 ethmode; - - if (dwmac->interface == PHY_INTERFACE_MODE_MII) { + if (plat_dat->interface == PHY_INTERFACE_MODE_MII) { ethmode = LPC18XX_CREG_CREG6_ETHMODE_MII; - } else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) { + } else if (plat_dat->interface == PHY_INTERFACE_MODE_RMII) { ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII; } else { dev_err(&pdev->dev, "Only MII and RMII mode supported\n"); return -EINVAL; } - regmap_update_bits(dwmac->reg, LPC18XX_CREG_CREG6, + regmap_update_bits(reg, LPC18XX_CREG_CREG6, LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode); - return 0; + return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); } -static const struct stmmac_of_data lpc18xx_dwmac_data = { - .has_gmac = 1, - .setup = lpc18xx_dwmac_setup, - .init = lpc18xx_dwmac_init, -}; - static const struct of_device_id lpc18xx_dwmac_match[] = { - { .compatible = "nxp,lpc1850-dwmac", .data = &lpc18xx_dwmac_data }, + { .compatible = "nxp,lpc1850-dwmac" }, { } }; MODULE_DEVICE_TABLE(of, lpc18xx_dwmac_match); static struct platform_driver lpc18xx_dwmac_driver = { - .probe = stmmac_pltfr_probe, + .probe = lpc18xx_dwmac_probe, .remove = stmmac_pltfr_remove, .driver = { .name = "lpc18xx-dwmac", -- cgit v1.3-6-gb490 From 1734befd0694c9e430d2c84445eceb6a7bbe1008 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:11 +0200 Subject: stmmac: add proper probe function to dwmac-meson By using a few functions from stmmac_platform we can now create a proper probe function in this driver. By doing so we can drop the OF match data and simplify the overall driver. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c | 31 +++++++++++++++-------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c index 61a324a87d09..c1bac1912b37 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c @@ -47,36 +47,45 @@ static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed) writel(val, dwmac->reg); } -static void *meson6_dwmac_setup(struct platform_device *pdev) +static int meson6_dwmac_probe(struct platform_device *pdev) { + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; struct meson_dwmac *dwmac; struct resource *res; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); if (!dwmac) - return ERR_PTR(-ENOMEM); + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 1); dwmac->reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dwmac->reg)) - return ERR_CAST(dwmac->reg); + return PTR_ERR(dwmac->reg); - return dwmac; -} + plat_dat->bsp_priv = dwmac; + plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed; -static const struct stmmac_of_data meson6_dwmac_data = { - .setup = meson6_dwmac_setup, - .fix_mac_speed = meson6_dwmac_fix_mac_speed, -}; + return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); +} static const struct of_device_id meson6_dwmac_match[] = { - { .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data}, + { .compatible = "amlogic,meson6-dwmac" }, { } }; MODULE_DEVICE_TABLE(of, meson6_dwmac_match); static struct platform_driver meson6_dwmac_driver = { - .probe = stmmac_pltfr_probe, + .probe = meson6_dwmac_probe, .remove = stmmac_pltfr_remove, .driver = { .name = "meson6-dwmac", -- cgit v1.3-6-gb490 From 6ac3ce8295e6763b86e5a7bfd61275f51e0a3fd3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:14 -0700 Subject: net: bcmgenet: Remove excessive PHY reset We are currently issuing multiple PHY resets during a suspend/resume, first during bcmgenet_power_up() which does a hardware reset, then a software reset by calling bcmgenet_mii_reset(). This is both unnecessary and can take as long as 10ms per MDIO transactions while we re-apply workarounds because we do not yet have MDIO interrupts enabled. phy_resume() takes care of re-apply our workarounds in case we need any, and bcmgenet_power_up() does a PHY hardware reset, all of this is more than enough to guarantee that the PHY operates correctly. Fixes: 1c1008c793fa4 ("net: bcmgenet: add main driver file") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 3 --- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 1 - drivers/net/ethernet/broadcom/genet/bcmmii.c | 11 ----------- 3 files changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 64c1e9db6b0b..674f374dceee 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -907,9 +907,6 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, } bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); - - if (mode == GENET_POWER_PASSIVE) - bcmgenet_mii_reset(priv->dev); } /* ioctl handle special commands that are not present in ethtool. */ diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 6159deab8c98..9f9ac0089d4d 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -672,7 +672,6 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF); int bcmgenet_mii_init(struct net_device *dev); int bcmgenet_mii_config(struct net_device *dev, bool init); void bcmgenet_mii_exit(struct net_device *dev); -void bcmgenet_mii_reset(struct net_device *dev); void bcmgenet_phy_power_set(struct net_device *dev, bool enable); void bcmgenet_mii_setup(struct net_device *dev); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index adf23d2ac488..c5f9c7b5d9e7 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -163,16 +163,6 @@ void bcmgenet_mii_setup(struct net_device *dev) phy_print_status(phydev); } -void bcmgenet_mii_reset(struct net_device *dev) -{ - struct bcmgenet_priv *priv = netdev_priv(dev); - - if (priv->phydev) { - phy_init_hw(priv->phydev); - phy_start_aneg(priv->phydev); - } -} - void bcmgenet_phy_power_set(struct net_device *dev, bool enable) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -215,7 +205,6 @@ static void bcmgenet_internal_phy_setup(struct net_device *dev) reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); reg |= EXT_PWR_DN_EN_LD; bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); - bcmgenet_mii_reset(dev); } static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) -- cgit v1.3-6-gb490 From 978ffac4189e8bb7e74bce6463e501a7b92555af Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:15 -0700 Subject: net: bcmgenet: Use correct dev_id for free_irq bcmgenet_open()'s error path call free_irq() with a dev_id argument different from the one we used to call request_irq() with, this will make us trip over the warning in kernel/irq/manage.c:__free_irq() Fixes: 1c1008c793fa4 ("net: bcmgenet: add main driver file") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 674f374dceee..c634ddbbd21d 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2695,7 +2695,7 @@ static int bcmgenet_open(struct net_device *dev) return 0; err_irq0: - free_irq(priv->irq0, dev); + free_irq(priv->irq0, priv); err_fini_dma: bcmgenet_fini_dma(priv); err_clk_disable: -- cgit v1.3-6-gb490 From bd4060a6108befd1110a4c6be5544c932895d18d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:16 -0700 Subject: net: bcmgenet: Power on integrated GPHY in bcmgenet_power_up() We are currently disabling the GPHY interface during bcmgenet_close(), and attempting to power it back on during bcmgenet_open(). This works fine for the first time, because we called bcmgenet_mii_config() which took care of enabling the interface, however, bcmgenet_power_up() really needs to power on the GPHY for correctness. This will be particularly important as we want to move bcmgenet_mii_probe() down to bcmgenet_open() to avoid seeing the "PHY already attached" message. Fixes: a642c4f7906f36 ("net: bcmgenet: power up and down integrated GPHY when unused") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index c634ddbbd21d..2efe72f94869 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -907,6 +907,8 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, } bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); + if (mode == GENET_POWER_PASSIVE) + bcmgenet_phy_power_set(priv->dev, true); } /* ioctl handle special commands that are not present in ethtool. */ -- cgit v1.3-6-gb490 From c624f89121020882b3db0a33cac8daf151d2930f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:17 -0700 Subject: net: bcmgenet: Determine PHY type before scanning MDIO bus Our internal GPHY might be powered off before we attempt scanning the MDIO bus and bind a driver to it. The way we are currently determining whether a PHY is internal or not is done *after* we have successfully matched its driver. If the PHY is powered down, it will not respond to the MDIO bus, so we will not be able to bind a driver to it. Our Device Tree for GENET interfaces specifies a "phy-mode" value: "internal" which tells if this internal uses an internal PHY or not. If of_get_phy_mode() fails to parse the 'phy-mode' property, do an additional manual lookup, and if we find "internal" set the corresponding internal variable accordingly. Replace all uses of phy_is_internal() with a check against priv->internal_phy to avoid having to rely on whether or not priv->phydev is set correctly. Fixes: 1c1008c793fa4 ("net: bcmgenet: add main driver file") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 14 ++++++------- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 1 + drivers/net/ethernet/broadcom/genet/bcmmii.c | 29 +++++++++++++++++++++----- 3 files changed, 32 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 2efe72f94869..076565463226 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1724,7 +1724,7 @@ static int init_umac(struct bcmgenet_priv *priv) int0_enable |= UMAC_IRQ_TXDMA_DONE; /* Monitor cable plug/unplugged event for internal PHY */ - if (phy_is_internal(priv->phydev)) { + if (priv->internal_phy) { int0_enable |= UMAC_IRQ_LINK_EVENT; } else if (priv->ext_phy) { int0_enable |= UMAC_IRQ_LINK_EVENT; @@ -2631,7 +2631,7 @@ static int bcmgenet_open(struct net_device *dev) /* If this is an internal GPHY, power it back on now, before UniMAC is * brought out of reset as absolutely no UniMAC activity is allowed */ - if (phy_is_internal(priv->phydev)) + if (priv->internal_phy) bcmgenet_power_up(priv, GENET_POWER_PASSIVE); /* take MAC out of reset */ @@ -2650,7 +2650,7 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_set_hw_addr(priv, dev->dev_addr); - if (phy_is_internal(priv->phydev)) { + if (priv->internal_phy) { reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); reg |= EXT_ENERGY_DET_MASK; bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); @@ -2756,7 +2756,7 @@ static int bcmgenet_close(struct net_device *dev) free_irq(priv->irq0, priv); free_irq(priv->irq1, priv); - if (phy_is_internal(priv->phydev)) + if (priv->internal_phy) ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE); if (!IS_ERR(priv->clk)) @@ -3318,7 +3318,7 @@ static int bcmgenet_suspend(struct device *d) if (device_may_wakeup(d) && priv->wolopts) { ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC); clk_prepare_enable(priv->clk_wol); - } else if (phy_is_internal(priv->phydev)) { + } else if (priv->internal_phy) { ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE); } @@ -3347,7 +3347,7 @@ static int bcmgenet_resume(struct device *d) /* If this is an internal GPHY, power it back on now, before UniMAC is * brought out of reset as absolutely no UniMAC activity is allowed */ - if (phy_is_internal(priv->phydev)) + if (priv->internal_phy) bcmgenet_power_up(priv, GENET_POWER_PASSIVE); bcmgenet_umac_reset(priv); @@ -3369,7 +3369,7 @@ static int bcmgenet_resume(struct device *d) bcmgenet_set_hw_addr(priv, dev->dev_addr); - if (phy_is_internal(priv->phydev)) { + if (priv->internal_phy) { reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); reg |= EXT_ENERGY_DET_MASK; bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 9f9ac0089d4d..84274de83670 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -593,6 +593,7 @@ struct bcmgenet_priv { /* MDIO bus variables */ wait_queue_head_t wq; struct phy_device *phydev; + bool internal_phy; struct device_node *phy_dn; struct device_node *mdio_dn; struct mii_bus *mii_bus; diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index c5f9c7b5d9e7..35df947e738c 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -227,10 +227,10 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) u32 port_ctrl; u32 reg; - priv->ext_phy = !phy_is_internal(priv->phydev) && + priv->ext_phy = !priv->internal_phy && (priv->phy_interface != PHY_INTERFACE_MODE_MOCA); - if (phy_is_internal(priv->phydev)) + if (priv->internal_phy) priv->phy_interface = PHY_INTERFACE_MODE_NA; switch (priv->phy_interface) { @@ -248,7 +248,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL); - if (phy_is_internal(priv->phydev)) { + if (priv->internal_phy) { phy_name = "internal PHY"; bcmgenet_internal_phy_setup(dev); } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { @@ -386,7 +386,7 @@ static int bcmgenet_mii_probe(struct net_device *dev) /* The internal PHY has its link interrupts routed to the * Ethernet MAC ISRs */ - if (phy_is_internal(priv->phydev)) + if (priv->internal_phy) priv->mii_bus->irq[phydev->addr] = PHY_IGNORE_INTERRUPT; else priv->mii_bus->irq[phydev->addr] = PHY_POLL; @@ -479,7 +479,9 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) { struct device_node *dn = priv->pdev->dev.of_node; struct device *kdev = &priv->pdev->dev; + const char *phy_mode_str = NULL; char *compat; + int phy_mode; int ret; compat = kasprintf(GFP_KERNEL, "brcm,genet-mdio-v%d", priv->version); @@ -503,7 +505,24 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0); /* Get the link mode */ - priv->phy_interface = of_get_phy_mode(dn); + phy_mode = of_get_phy_mode(dn); + priv->phy_interface = phy_mode; + + /* We need to specifically look up whether this PHY interface is internal + * or not *before* we even try to probe the PHY driver over MDIO as we + * may have shut down the internal PHY for power saving purposes. + */ + if (phy_mode < 0) { + ret = of_property_read_string(dn, "phy-mode", &phy_mode_str); + if (ret < 0) { + dev_err(kdev, "invalid PHY mode property\n"); + return ret; + } + + priv->phy_interface = PHY_INTERFACE_MODE_NA; + if (!strcasecmp(phy_mode_str, "internal")) + priv->internal_phy = true; + } return 0; } -- cgit v1.3-6-gb490 From 6cc8e6d4dcb3651eea9b01db3e195fffb19fb24f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:18 -0700 Subject: net: bcmgenet: Delay PHY initialization to bcmgenet_open() We are currently doing a full PHY initialization and even starting the pHY state machine during bcmgenet_mii_init() which is executed in the driver's probe function. This is convenient to determine whether we can attach to a proper PHY device but comes at the expense of spending up to 10ms per MDIO transactions (to reach the waitqueue timeout), which slows things down. This also creates a sitaution where we end-up attaching twice to the PHY, which is not quite correct either. Fix this by moving bcmgenet_mii_probe() into bcmgenet_open() and update its error path accordingly. Avoid printing the message "attached PHY at address 1 [...]" every time we bring up/down the interface and remove this print since it duplicates what the PHY driver already does for us. Fixes: 1c1008c793fa4 ("net: bcmgenet: add main driver file") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 12 +++++---- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 1 + drivers/net/ethernet/broadcom/genet/bcmmii.c | 37 +++++++++----------------- 3 files changed, 20 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 076565463226..fbab7757adfa 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2686,16 +2686,18 @@ static int bcmgenet_open(struct net_device *dev) goto err_irq0; } - /* Re-configure the port multiplexer towards the PHY device */ - bcmgenet_mii_config(priv->dev, false); - - phy_connect_direct(dev, priv->phydev, bcmgenet_mii_setup, - priv->phy_interface); + ret = bcmgenet_mii_probe(dev); + if (ret) { + netdev_err(dev, "failed to connect to PHY\n"); + goto err_irq1; + } bcmgenet_netif_start(dev); return 0; +err_irq1: + free_irq(priv->irq1, priv); err_irq0: free_irq(priv->irq0, priv); err_fini_dma: diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 84274de83670..e25b5327cc40 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -672,6 +672,7 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF); /* MDIO routines */ int bcmgenet_mii_init(struct net_device *dev); int bcmgenet_mii_config(struct net_device *dev, bool init); +int bcmgenet_mii_probe(struct net_device *dev); void bcmgenet_mii_exit(struct net_device *dev); void bcmgenet_phy_power_set(struct net_device *dev, bool enable); void bcmgenet_mii_setup(struct net_device *dev); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 35df947e738c..b503897a0da3 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -316,7 +316,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) return 0; } -static int bcmgenet_mii_probe(struct net_device *dev) +int bcmgenet_mii_probe(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); struct device_node *dn = priv->pdev->dev.of_node; @@ -334,22 +334,6 @@ static int bcmgenet_mii_probe(struct net_device *dev) priv->old_pause = -1; if (dn) { - if (priv->phydev) { - pr_info("PHY already attached\n"); - return 0; - } - - /* In the case of a fixed PHY, the DT node associated - * to the PHY is the Ethernet MAC DT node. - */ - if (!priv->phy_dn && of_phy_is_fixed_link(dn)) { - ret = of_phy_register_fixed_link(dn); - if (ret) - return ret; - - priv->phy_dn = of_node_get(dn); - } - phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup, phy_flags, priv->phy_interface); if (!phydev) { @@ -391,9 +375,6 @@ static int bcmgenet_mii_probe(struct net_device *dev) else priv->mii_bus->irq[phydev->addr] = PHY_POLL; - pr_info("attached PHY at address %d [%s]\n", - phydev->addr, phydev->drv->name); - return 0; } @@ -504,6 +485,17 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) /* Fetch the PHY phandle */ priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0); + /* In the case of a fixed PHY, the DT node associated + * to the PHY is the Ethernet MAC DT node. + */ + if (!priv->phy_dn && of_phy_is_fixed_link(dn)) { + ret = of_phy_register_fixed_link(dn); + if (ret) + return ret; + + priv->phy_dn = of_node_get(dn); + } + /* Get the link mode */ phy_mode = of_get_phy_mode(dn); priv->phy_interface = phy_mode; @@ -622,10 +614,6 @@ int bcmgenet_mii_init(struct net_device *dev) return ret; ret = bcmgenet_mii_bus_init(priv); - if (ret) - goto out_free; - - ret = bcmgenet_mii_probe(dev); if (ret) goto out; @@ -634,7 +622,6 @@ int bcmgenet_mii_init(struct net_device *dev) out: of_node_put(priv->phy_dn); mdiobus_unregister(priv->mii_bus); -out_free: kfree(priv->mii_bus->irq); mdiobus_free(priv->mii_bus); return ret; -- cgit v1.3-6-gb490 From 28b45910ccda7b3e4de61b24a6f34d5fb1da90d2 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:19 -0700 Subject: net: bcmgenet: Remove init parameter from bcmgenet_mii_config Now that we have reworked the way we perform the PHY initialization, we no longer need to differentiate between init time vs. non-init time calls, just use a dev_info_once() print to print the PHY type. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +- drivers/net/ethernet/broadcom/genet/bcmmii.c | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index fbab7757adfa..5bf7ce0ae221 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -3364,7 +3364,7 @@ static int bcmgenet_resume(struct device *d) phy_init_hw(priv->phydev); /* Speed settings must be restored */ - bcmgenet_mii_config(priv->dev, false); + bcmgenet_mii_config(priv->dev); /* disable ethernet MAC while updating its registers */ umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index e25b5327cc40..7299d1075422 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -671,7 +671,7 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF); /* MDIO routines */ int bcmgenet_mii_init(struct net_device *dev); -int bcmgenet_mii_config(struct net_device *dev, bool init); +int bcmgenet_mii_config(struct net_device *dev); int bcmgenet_mii_probe(struct net_device *dev); void bcmgenet_mii_exit(struct net_device *dev); void bcmgenet_phy_power_set(struct net_device *dev, bool enable); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index b503897a0da3..0802cd9d2424 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -217,7 +217,7 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL); } -int bcmgenet_mii_config(struct net_device *dev, bool init) +int bcmgenet_mii_config(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); struct phy_device *phydev = priv->phydev; @@ -310,8 +310,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); } - if (init) - dev_info(kdev, "configuring instance for %s\n", phy_name); + dev_info_once(kdev, "configuring instance for %s\n", phy_name); return 0; } @@ -359,7 +358,7 @@ int bcmgenet_mii_probe(struct net_device *dev) * PHY speed which is needed for bcmgenet_mii_config() to configure * things appropriately. */ - ret = bcmgenet_mii_config(dev, true); + ret = bcmgenet_mii_config(dev); if (ret) { phy_disconnect(priv->phydev); return ret; -- cgit v1.3-6-gb490 From 63caae8480921773b46adec0b6ddac9a844a042f Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 20 Jul 2015 18:34:50 +0200 Subject: sched/idle: Move latency tracing stop/start calls deeper inside the idle loop Make sure to stop tracing only once we are past a point where all latency tracing events have been processed (irqs are not enabled again). This has the slight advantage of capturing more latency related events in the idle path, but most importantly it makes sure that latency tracing doesn't get re-enabled inadvertently when new events are coming in. This makes the irqsoff latency tracer useful again, as we stop capturing CPU sleep time as IRQ latency. Signed-off-by: Lucas Stach Cc: Daniel Lezcano Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Rafael J. Wysocki Cc: Steven Rostedt Cc: Thomas Gleixner Cc: kernel@pengutronix.de Cc: patchwork-lst@pengutronix.de Link: http://lkml.kernel.org/r/1437410090-3747-1-git-send-email-l.stach@pengutronix.de Signed-off-by: Ingo Molnar --- drivers/cpuidle/cpuidle.c | 4 ++++ kernel/sched/idle.c | 14 +++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index e8e2775c3821..a5d9f2e470ea 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -118,6 +118,7 @@ static void enter_freeze_proper(struct cpuidle_driver *drv, * cpuidle mechanism enables interrupts and doing that with timekeeping * suspended is generally unsafe. */ + stop_critical_timings(); drv->states[index].enter_freeze(dev, drv, index); WARN_ON(!irqs_disabled()); /* @@ -126,6 +127,7 @@ static void enter_freeze_proper(struct cpuidle_driver *drv, * critical sections, so tell RCU about that. */ RCU_NONIDLE(tick_unfreeze()); + start_critical_timings(); } /** @@ -190,7 +192,9 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, trace_cpu_idle_rcuidle(index, dev->cpu); time_start = ktime_get(); + stop_critical_timings(); entered_state = target_state->enter(dev, drv, index); + start_critical_timings(); time_end = ktime_get(); trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu); diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 594275ed2620..8f177c73ae19 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c @@ -83,10 +83,13 @@ void __weak arch_cpu_idle(void) */ void default_idle_call(void) { - if (current_clr_polling_and_test()) + if (current_clr_polling_and_test()) { local_irq_enable(); - else + } else { + stop_critical_timings(); arch_cpu_idle(); + start_critical_timings(); + } } static int call_cpuidle(struct cpuidle_driver *drv, struct cpuidle_device *dev, @@ -140,12 +143,6 @@ static void cpuidle_idle_call(void) return; } - /* - * During the idle period, stop measuring the disabled irqs - * critical sections latencies - */ - stop_critical_timings(); - /* * Tell the RCU framework we are entering an idle section, * so no more rcu read side critical sections and one more @@ -198,7 +195,6 @@ exit_idle: local_irq_enable(); rcu_idle_exit(); - start_critical_timings(); } DEFINE_PER_CPU(bool, cpu_dead_idle); -- cgit v1.3-6-gb490 From ea70299d6e6961dd6adce2cbdf64e6e8a7ea97c0 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 9 Jul 2015 19:29:02 +0100 Subject: drm/i915: Add i915_gem_object_create_from_data() i915_gem_object_create_from_data() is a generic function to save data from a plain linear buffer in a new pageable gem object that can later be accessed by the CPU and/or GPU. We will need this for the microcontroller firmware loading support code. Derived from i915_gem_object_write(), originally by Alex Dai v2: Change of function: now allocates & fills a new object, rather than writing to an existing object New name courtesy of Chris Wilson Explicit domain-setting and other improvements per review comments by Chris Wilson & Daniel Vetter v4: Rebased Issue: VIZ-4884 Signed-off-by: Alex Dai Signed-off-by: Dave Gordon Reviewed-by: Tom O'Rourke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 23ce125e0298..77c23796f119 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2758,6 +2758,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); +struct drm_i915_gem_object *i915_gem_object_create_from_data( + struct drm_device *dev, const void *data, 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); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d9f2701b4593..322bbefafbc3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5477,3 +5477,43 @@ bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) return false; } + +/* Allocate a new GEM object and fill it with the supplied data */ +struct drm_i915_gem_object * +i915_gem_object_create_from_data(struct drm_device *dev, + const void *data, size_t size) +{ + struct drm_i915_gem_object *obj; + struct sg_table *sg; + size_t bytes; + int ret; + + obj = i915_gem_alloc_object(dev, round_up(size, PAGE_SIZE)); + if (IS_ERR_OR_NULL(obj)) + return obj; + + ret = i915_gem_object_set_to_cpu_domain(obj, true); + if (ret) + goto fail; + + ret = i915_gem_object_get_pages(obj); + if (ret) + goto fail; + + i915_gem_object_pin_pages(obj); + sg = obj->pages; + bytes = sg_copy_from_buffer(sg->sgl, sg->nents, (void *)data, size); + i915_gem_object_unpin_pages(obj); + + if (WARN_ON(bytes != size)) { + DRM_ERROR("Incomplete copy, wrote %zu of %zu", bytes, size); + ret = -EFAULT; + goto fail; + } + + return obj; + +fail: + drm_gem_object_unreference(&obj->base); + return ERR_PTR(ret); +} -- cgit v1.3-6-gb490 From 63dc04498ace9cb657174e77373d6fcc85d6c492 Mon Sep 17 00:00:00 2001 From: Alex Dai Date: Thu, 9 Jul 2015 19:29:03 +0100 Subject: drm/i915: Add GuC-related module parameters Two new module parameters: "enable_guc_submission" which will turn on submission of batchbuffers via the GuC (when implemented), and "guc_log_level" which controls the level of debugging logged by the GuC and captured by the host. Signed-off-by: Alex Dai v4: Mark "enable_guc_submission" unsafe [Daniel Vetter] Signed-off-by: Dave Gordon Reviewed-by: Tom O'Rourke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_params.c | 9 +++++++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 77c23796f119..b876e788e2f8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2610,6 +2610,8 @@ struct i915_params { bool reset; bool disable_display; bool disable_vtd_wa; + bool enable_guc_submission; + int guc_log_level; int use_mmio_flip; int mmio_debug; bool verbose_state_checks; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 5f4e7295295f..5ae4b0aba564 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -52,6 +52,8 @@ struct i915_params i915 __read_mostly = { .mmio_debug = 0, .verbose_state_checks = 1, .edp_vswing = 0, + .enable_guc_submission = false, + .guc_log_level = -1, }; module_param_named(modeset, i915.modeset, int, 0400); @@ -181,3 +183,10 @@ MODULE_PARM_DESC(edp_vswing, "Ignore/Override vswing pre-emph table selection from VBT " "(0=use value from vbt [default], 1=low power swing(200mV)," "2=default swing(400mV))"); + +module_param_named_unsafe(enable_guc_submission, i915.enable_guc_submission, bool, 0400); +MODULE_PARM_DESC(enable_guc_submission, "Enable GuC submission (default:false)"); + +module_param_named(guc_log_level, i915.guc_log_level, int, 0400); +MODULE_PARM_DESC(guc_log_level, + "GuC firmware logging level (-1:disabled (default), 0-3:enabled)"); -- cgit v1.3-6-gb490 From 2617268ff9d8f8b6901a07962c985d774b999e58 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 9 Jul 2015 19:29:04 +0100 Subject: drm/i915: Add GuC-related header files intel_guc_fwif.h contains the subset of the GuC interface that we will need for submission of commands through the GuC. These MUST be kept in sync with the definitions used by the GuC firmware, and updates to this file will (or should) be autogenerated from the source files used to build the firmware. Editing this file is therefore not recommended. i915_guc_reg.h contains definitions of GuC-related hardware: registers, bitmasks, etc. These should match the BSpec. v2: Files renamed & resliced per review comments by Chris Wilson v4: Added DON'T-EDIT-ME warning [Tom O'Rourke] Issue: VIZ-4884 Signed-off-by: Alex Dai Signed-off-by: Dave Gordon Reviewed-by: Tom O'Rourke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_guc_reg.h | 102 ++++++++++++++ drivers/gpu/drm/i915/intel_guc_fwif.h | 245 ++++++++++++++++++++++++++++++++++ 2 files changed, 347 insertions(+) create mode 100644 drivers/gpu/drm/i915/i915_guc_reg.h create mode 100644 drivers/gpu/drm/i915/intel_guc_fwif.h (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_guc_reg.h b/drivers/gpu/drm/i915/i915_guc_reg.h new file mode 100644 index 000000000000..ccdc6c8ac20b --- /dev/null +++ b/drivers/gpu/drm/i915/i915_guc_reg.h @@ -0,0 +1,102 @@ +/* + * 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, 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. + * + */ +#ifndef _I915_GUC_REG_H_ +#define _I915_GUC_REG_H_ + +/* Definitions of GuC H/W registers, bits, etc */ + +#define GUC_STATUS 0xc000 +#define GS_BOOTROM_SHIFT 1 +#define GS_BOOTROM_MASK (0x7F << GS_BOOTROM_SHIFT) +#define GS_BOOTROM_RSA_FAILED (0x50 << GS_BOOTROM_SHIFT) +#define GS_UKERNEL_SHIFT 8 +#define GS_UKERNEL_MASK (0xFF << GS_UKERNEL_SHIFT) +#define GS_UKERNEL_LAPIC_DONE (0x30 << GS_UKERNEL_SHIFT) +#define GS_UKERNEL_DPC_ERROR (0x60 << GS_UKERNEL_SHIFT) +#define GS_UKERNEL_READY (0xF0 << GS_UKERNEL_SHIFT) +#define GS_MIA_SHIFT 16 +#define GS_MIA_MASK (0x07 << GS_MIA_SHIFT) + +#define GUC_WOPCM_SIZE 0xc050 +#define GUC_WOPCM_SIZE_VALUE (0x80 << 12) /* 512KB */ +#define GUC_WOPCM_OFFSET 0x80000 /* 512KB */ + +#define SOFT_SCRATCH(n) (0xc180 + ((n) * 4)) + +#define UOS_RSA_SCRATCH_0 0xc200 +#define DMA_ADDR_0_LOW 0xc300 +#define DMA_ADDR_0_HIGH 0xc304 +#define DMA_ADDR_1_LOW 0xc308 +#define DMA_ADDR_1_HIGH 0xc30c +#define DMA_ADDRESS_SPACE_WOPCM (7 << 16) +#define DMA_ADDRESS_SPACE_GTT (8 << 16) +#define DMA_COPY_SIZE 0xc310 +#define DMA_CTRL 0xc314 +#define UOS_MOVE (1<<4) +#define START_DMA (1<<0) +#define DMA_GUC_WOPCM_OFFSET 0xc340 + +#define GEN8_GT_PM_CONFIG 0x138140 +#define GEN9_GT_PM_CONFIG 0x13816c +#define GEN8_GT_DOORBELL_ENABLE (1<<0) + +#define GEN8_GTCR 0x4274 +#define GEN8_GTCR_INVALIDATE (1<<0) + +#define GUC_ARAT_C6DIS 0xA178 + +#define GUC_SHIM_CONTROL 0xc064 +#define GUC_DISABLE_SRAM_INIT_TO_ZEROES (1<<0) +#define GUC_ENABLE_READ_CACHE_LOGIC (1<<1) +#define GUC_ENABLE_MIA_CACHING (1<<2) +#define GUC_GEN10_MSGCH_ENABLE (1<<4) +#define GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA (1<<9) +#define GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA (1<<10) +#define GUC_ENABLE_MIA_CLOCK_GATING (1<<15) +#define GUC_GEN10_SHIM_WC_ENABLE (1<<21) + +#define GUC_SHIM_CONTROL_VALUE (GUC_DISABLE_SRAM_INIT_TO_ZEROES | \ + GUC_ENABLE_READ_CACHE_LOGIC | \ + GUC_ENABLE_MIA_CACHING | \ + GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA | \ + GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA) + +#define HOST2GUC_INTERRUPT 0xc4c8 +#define HOST2GUC_TRIGGER (1<<0) + +#define DRBMISC1 0x1984 +#define DOORBELL_ENABLE (1<<0) + +#define GEN8_DRBREGL(x) (0x1000 + (x) * 8) +#define GEN8_DRB_VALID (1<<0) +#define GEN8_DRBREGU(x) (GEN8_DRBREGL(x) + 4) + +#define DE_GUCRMR 0x44054 + +#define GUC_BCS_RCS_IER 0xC550 +#define GUC_VCS2_VCS1_IER 0xC554 +#define GUC_WD_VECS_IER 0xC558 +#define GUC_PM_P24C_IER 0xC55C + +#endif diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h new file mode 100644 index 000000000000..18d7f20936c8 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -0,0 +1,245 @@ +/* + * 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, 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. + */ +#ifndef _INTEL_GUC_FWIF_H +#define _INTEL_GUC_FWIF_H + +/* + * This file is partially autogenerated, although currently with some manual + * fixups afterwards. In future, it should be entirely autogenerated, in order + * to ensure that the definitions herein remain in sync with those used by the + * GuC's own firmware. + * + * EDITING THIS FILE IS THEREFORE NOT RECOMMENDED - YOUR CHANGES MAY BE LOST. + */ + +#define GFXCORE_FAMILY_GEN8 11 +#define GFXCORE_FAMILY_GEN9 12 +#define GFXCORE_FAMILY_FORCE_ULONG 0x7fffffff + +#define GUC_CTX_PRIORITY_CRITICAL 0 +#define GUC_CTX_PRIORITY_HIGH 1 +#define GUC_CTX_PRIORITY_NORMAL 2 +#define GUC_CTX_PRIORITY_LOW 3 + +#define GUC_MAX_GPU_CONTEXTS 1024 +#define GUC_INVALID_CTX_ID (GUC_MAX_GPU_CONTEXTS + 1) + +/* Work queue item header definitions */ +#define WQ_STATUS_ACTIVE 1 +#define WQ_STATUS_SUSPENDED 2 +#define WQ_STATUS_CMD_ERROR 3 +#define WQ_STATUS_ENGINE_ID_NOT_USED 4 +#define WQ_STATUS_SUSPENDED_FROM_RESET 5 +#define WQ_TYPE_SHIFT 0 +#define WQ_TYPE_BATCH_BUF (0x1 << WQ_TYPE_SHIFT) +#define WQ_TYPE_PSEUDO (0x2 << WQ_TYPE_SHIFT) +#define WQ_TYPE_INORDER (0x3 << WQ_TYPE_SHIFT) +#define WQ_TARGET_SHIFT 10 +#define WQ_LEN_SHIFT 16 +#define WQ_NO_WCFLUSH_WAIT (1 << 27) +#define WQ_PRESENT_WORKLOAD (1 << 28) +#define WQ_WORKLOAD_SHIFT 29 +#define WQ_WORKLOAD_GENERAL (0 << WQ_WORKLOAD_SHIFT) +#define WQ_WORKLOAD_GPGPU (1 << WQ_WORKLOAD_SHIFT) +#define WQ_WORKLOAD_TOUCH (2 << WQ_WORKLOAD_SHIFT) + +#define WQ_RING_TAIL_SHIFT 20 +#define WQ_RING_TAIL_MASK (0x7FF << WQ_RING_TAIL_SHIFT) + +#define GUC_DOORBELL_ENABLED 1 +#define GUC_DOORBELL_DISABLED 0 + +#define GUC_CTX_DESC_ATTR_ACTIVE (1 << 0) +#define GUC_CTX_DESC_ATTR_PENDING_DB (1 << 1) +#define GUC_CTX_DESC_ATTR_KERNEL (1 << 2) +#define GUC_CTX_DESC_ATTR_PREEMPT (1 << 3) +#define GUC_CTX_DESC_ATTR_RESET (1 << 4) +#define GUC_CTX_DESC_ATTR_WQLOCKED (1 << 5) +#define GUC_CTX_DESC_ATTR_PCH (1 << 6) + +/* The guc control data is 10 DWORDs */ +#define GUC_CTL_CTXINFO 0 +#define GUC_CTL_CTXNUM_IN16_SHIFT 0 +#define GUC_CTL_BASE_ADDR_SHIFT 12 +#define GUC_CTL_ARAT_HIGH 1 +#define GUC_CTL_ARAT_LOW 2 +#define GUC_CTL_DEVICE_INFO 3 +#define GUC_CTL_GTTYPE_SHIFT 0 +#define GUC_CTL_COREFAMILY_SHIFT 7 +#define GUC_CTL_LOG_PARAMS 4 +#define GUC_LOG_VALID (1 << 0) +#define GUC_LOG_NOTIFY_ON_HALF_FULL (1 << 1) +#define GUC_LOG_ALLOC_IN_MEGABYTE (1 << 3) +#define GUC_LOG_CRASH_PAGES 1 +#define GUC_LOG_CRASH_SHIFT 4 +#define GUC_LOG_DPC_PAGES 3 +#define GUC_LOG_DPC_SHIFT 6 +#define GUC_LOG_ISR_PAGES 3 +#define GUC_LOG_ISR_SHIFT 9 +#define GUC_LOG_BUF_ADDR_SHIFT 12 +#define GUC_CTL_PAGE_FAULT_CONTROL 5 +#define GUC_CTL_WA 6 +#define GUC_CTL_WA_UK_BY_DRIVER (1 << 3) +#define GUC_CTL_FEATURE 7 +#define GUC_CTL_VCS2_ENABLED (1 << 0) +#define GUC_CTL_KERNEL_SUBMISSIONS (1 << 1) +#define GUC_CTL_FEATURE2 (1 << 2) +#define GUC_CTL_POWER_GATING (1 << 3) +#define GUC_CTL_DISABLE_SCHEDULER (1 << 4) +#define GUC_CTL_PREEMPTION_LOG (1 << 5) +#define GUC_CTL_ENABLE_SLPC (1 << 7) +#define GUC_CTL_DEBUG 8 +#define GUC_LOG_VERBOSITY_SHIFT 0 +#define GUC_LOG_VERBOSITY_LOW (0 << GUC_LOG_VERBOSITY_SHIFT) +#define GUC_LOG_VERBOSITY_MED (1 << GUC_LOG_VERBOSITY_SHIFT) +#define GUC_LOG_VERBOSITY_HIGH (2 << GUC_LOG_VERBOSITY_SHIFT) +#define GUC_LOG_VERBOSITY_ULTRA (3 << GUC_LOG_VERBOSITY_SHIFT) +/* Verbosity range-check limits, without the shift */ +#define GUC_LOG_VERBOSITY_MIN 0 +#define GUC_LOG_VERBOSITY_MAX 3 + +#define GUC_CTL_MAX_DWORDS (GUC_CTL_DEBUG + 1) + +struct guc_doorbell_info { + u32 db_status; + u32 cookie; + u32 reserved[14]; +} __packed; + +union guc_doorbell_qw { + struct { + u32 db_status; + u32 cookie; + }; + u64 value_qw; +} __packed; + +#define GUC_MAX_DOORBELLS 256 +#define GUC_INVALID_DOORBELL_ID (GUC_MAX_DOORBELLS) + +#define GUC_DB_SIZE (PAGE_SIZE) +#define GUC_WQ_SIZE (PAGE_SIZE * 2) + +/* Work item for submitting workloads into work queue of GuC. */ +struct guc_wq_item { + u32 header; + u32 context_desc; + u32 ring_tail; + u32 fence_id; +} __packed; + +struct guc_process_desc { + u32 context_id; + u64 db_base_addr; + u32 head; + u32 tail; + u32 error_offset; + u64 wq_base_addr; + u32 wq_size_bytes; + u32 wq_status; + u32 engine_presence; + u32 priority; + u32 reserved[30]; +} __packed; + +/* engine id and context id is packed into guc_execlist_context.context_id*/ +#define GUC_ELC_CTXID_OFFSET 0 +#define GUC_ELC_ENGINE_OFFSET 29 + +/* The execlist context including software and HW information */ +struct guc_execlist_context { + u32 context_desc; + u32 context_id; + u32 ring_status; + u32 ring_lcra; + u32 ring_begin; + u32 ring_end; + u32 ring_next_free_location; + u32 ring_current_tail_pointer_value; + u8 engine_state_submit_value; + u8 engine_state_wait_value; + u16 pagefault_count; + u16 engine_submit_queue_count; +} __packed; + +/*Context descriptor for communicating between uKernel and Driver*/ +struct guc_context_desc { + u32 sched_common_area; + u32 context_id; + u32 pas_id; + u8 engines_used; + u64 db_trigger_cpu; + u32 db_trigger_uk; + u64 db_trigger_phy; + u16 db_id; + + struct guc_execlist_context lrc[I915_NUM_RINGS]; + + u8 attribute; + + u32 priority; + + u32 wq_sampled_tail_offset; + u32 wq_total_submit_enqueues; + + u32 process_desc; + u32 wq_addr; + u32 wq_size; + + u32 engine_presence; + + u32 reserved0[1]; + u64 reserved1[1]; + + u64 desc_private; +} __packed; + +/* This Action will be programmed in C180 - SOFT_SCRATCH_O_REG */ +enum host2guc_action { + HOST2GUC_ACTION_DEFAULT = 0x0, + HOST2GUC_ACTION_SAMPLE_FORCEWAKE = 0x6, + HOST2GUC_ACTION_ALLOCATE_DOORBELL = 0x10, + HOST2GUC_ACTION_DEALLOCATE_DOORBELL = 0x20, + HOST2GUC_ACTION_SLPC_REQUEST = 0x3003, + HOST2GUC_ACTION_LIMIT +}; + +/* + * The GuC sends its response to a command by overwriting the + * command in SS0. The response is distinguishable from a command + * by the fact that all the MASK bits are set. The remaining bits + * give more detail. + */ +#define GUC2HOST_RESPONSE_MASK ((u32)0xF0000000) +#define GUC2HOST_IS_RESPONSE(x) ((u32)(x) >= GUC2HOST_RESPONSE_MASK) +#define GUC2HOST_STATUS(x) (GUC2HOST_RESPONSE_MASK | (x)) + +/* GUC will return status back to SOFT_SCRATCH_O_REG */ +enum guc2host_status { + GUC2HOST_STATUS_SUCCESS = GUC2HOST_STATUS(0x0), + GUC2HOST_STATUS_ALLOCATE_DOORBELL_FAIL = GUC2HOST_STATUS(0x10), + GUC2HOST_STATUS_DEALLOCATE_DOORBELL_FAIL = GUC2HOST_STATUS(0x20), + GUC2HOST_STATUS_GENERIC_FAIL = GUC2HOST_STATUS(0x0000F000) +}; + +#endif -- cgit v1.3-6-gb490 From f61687c01917946d2274dd8736bb8f9e2691ee5b Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Fri, 17 Jul 2015 11:19:46 +0800 Subject: phylib: add driver for Teranetics TN2020 Teranetics TN2020 is compliant with IEEE 802.3an 10 Gigabit. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 5 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/teranetics.c | 128 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 drivers/net/phy/teranetics.c (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index cb86d7a01542..d6aff873803c 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -54,6 +54,11 @@ config VITESSE_PHY ---help--- Currently supports the vsc8244 +config TERANETICS_PHY + tristate "Drivers for the Teranetics PHYs" + ---help--- + Currently supports the Teranetics TN2020 + config SMSC_PHY tristate "Drivers for SMSC PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index fcc25a0c45cd..16aac1c3e703 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_CICADA_PHY) += cicada.o obj-$(CONFIG_LXT_PHY) += lxt.o obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_SMSC_PHY) += smsc.o +obj-$(CONFIG_TERANETICS_PHY) += teranetics.o obj-$(CONFIG_VITESSE_PHY) += vitesse.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c new file mode 100644 index 000000000000..7dcb5aada1c4 --- /dev/null +++ b/drivers/net/phy/teranetics.c @@ -0,0 +1,128 @@ +/* + * Driver for Teranetics PHY + * + * Author: Shaohui Xie + * + * Copyright 2015 Freescale Semiconductor, 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. + */ + +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Teranetics PHY driver"); +MODULE_AUTHOR("Shaohui Xie "); +MODULE_LICENSE("GPL v2"); + +#define PHY_ID_TN2020 0x00a19410 +#define MDIO_PHYXS_LNSTAT_SYNC0 0x0001 +#define MDIO_PHYXS_LNSTAT_SYNC1 0x0002 +#define MDIO_PHYXS_LNSTAT_SYNC2 0x0004 +#define MDIO_PHYXS_LNSTAT_SYNC3 0x0008 +#define MDIO_PHYXS_LNSTAT_ALIGN 0x1000 + +#define MDIO_PHYXS_LANE_READY (MDIO_PHYXS_LNSTAT_SYNC0 | \ + MDIO_PHYXS_LNSTAT_SYNC1 | \ + MDIO_PHYXS_LNSTAT_SYNC2 | \ + MDIO_PHYXS_LNSTAT_SYNC3 | \ + MDIO_PHYXS_LNSTAT_ALIGN) + +static int teranetics_config_init(struct phy_device *phydev) +{ + phydev->supported = SUPPORTED_10000baseT_Full; + phydev->advertising = SUPPORTED_10000baseT_Full; + + return 0; +} + +static int teranetics_soft_reset(struct phy_device *phydev) +{ + return 0; +} + +static int teranetics_aneg_done(struct phy_device *phydev) +{ + int reg; + + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + return (reg < 0) ? reg : (reg & BMSR_ANEGCOMPLETE); +} + +static int teranetics_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int teranetics_read_status(struct phy_device *phydev) +{ + int reg; + + phydev->link = 1; + + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + + if (!phy_read_mmd(phydev, MDIO_MMD_VEND1, 93)) { + reg = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_LNSTAT); + if (reg < 0 || + !((reg & MDIO_PHYXS_LANE_READY) == MDIO_PHYXS_LANE_READY)) { + phydev->link = 0; + return 0; + } + + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) + phydev->link = 0; + } + + return 0; +} + +static int teranetics_match_phy_device(struct phy_device *phydev) +{ + return phydev->c45_ids.device_ids[3] == PHY_ID_TN2020; +} + +static struct phy_driver teranetics_driver[] = { +{ + .phy_id = PHY_ID_TN2020, + .phy_id_mask = 0xffffffff, + .name = "Teranetics TN2020", + .soft_reset = teranetics_soft_reset, + .aneg_done = teranetics_aneg_done, + .config_init = teranetics_config_init, + .config_aneg = teranetics_config_aneg, + .read_status = teranetics_read_status, + .match_phy_device = teranetics_match_phy_device, + .driver = { .owner = THIS_MODULE,}, +}, +}; + +static int __init teranetics_init(void) +{ + return phy_drivers_register(teranetics_driver, + ARRAY_SIZE(teranetics_driver)); +} + +static void __exit teranetics_exit(void) +{ + return phy_drivers_unregister(teranetics_driver, + ARRAY_SIZE(teranetics_driver)); +} + +module_init(teranetics_init); +module_exit(teranetics_exit); + +static struct mdio_device_id __maybe_unused teranetics_tbl[] = { + { PHY_ID_TN2020, 0xffffffff }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, teranetics_tbl); -- cgit v1.3-6-gb490 From 7177a3b037c7569c137c2703efe8187fdc4352b8 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Mon, 20 Jul 2015 09:54:50 +0200 Subject: net/vxlan: Fix kernel unaligned access in __vxlan_find_mac __vxlan_find_mac invokes ether_addr_equal on the eth_addr field, which triggers unaligned access messages, so rearrange vxlan_fdb to avoid this in the most non-intrusive way. Signed-off-by: Sowmini Varadhan Reviewed-by: Jiri Pirko Reviewed-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 34c519eb1db5..ec86a11743fd 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -106,9 +106,9 @@ struct vxlan_fdb { unsigned long updated; /* jiffies */ unsigned long used; struct list_head remotes; + u8 eth_addr[ETH_ALEN]; u16 state; /* see ndm_state */ u8 flags; /* see ndm_flags */ - u8 eth_addr[ETH_ALEN]; }; /* Pseudo network device */ -- cgit v1.3-6-gb490 From be9015abb8296d8dc72cef4da75fa30e88ab7c81 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:04 +0530 Subject: gpiolib: Add support for removing registered consumer lookup table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case we unload and load a driver module again that is registering a lookup table, without this it will result in multiple entries. Provide an option to remove the lookup table on driver unload Cc: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Reviewed-by: Alexandre Courbot Reviewed-by: Linus Walleij Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Acked-by: Lee Jones Signed-off-by: Daniel Vetter --- drivers/gpio/gpiolib.c | 13 +++++++++++++ include/linux/gpio/machine.h | 1 + 2 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bf4bd1d120c3..f25dc880b007 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1672,6 +1672,19 @@ void gpiod_add_lookup_table(struct gpiod_lookup_table *table) mutex_unlock(&gpio_lookup_lock); } +/** + * gpiod_remove_lookup_table() - unregister GPIO device consumers + * @table: table of consumers to unregister + */ +void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) +{ + mutex_lock(&gpio_lookup_lock); + + list_del(&table->list); + + mutex_unlock(&gpio_lookup_lock); +} + static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h index e2706140eaff..c0d712d22b07 100644 --- a/include/linux/gpio/machine.h +++ b/include/linux/gpio/machine.h @@ -57,5 +57,6 @@ struct gpiod_lookup_table { } void gpiod_add_lookup_table(struct gpiod_lookup_table *table); +void gpiod_remove_lookup_table(struct gpiod_lookup_table *table); #endif /* __LINUX_GPIO_MACHINE_H */ -- cgit v1.3-6-gb490 From 61dd2ca2d44e493b050adbbb75bc50db11c367dd Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:05 +0530 Subject: mfd: intel_soc_pmic_core: Add lookup table for Panel Control as GPIO signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some Intel SoC platforms, the panel enable/disable signals are controlled by CRC PMIC. Add those control as a new GPIO in a lookup table for gpio-crystalcove chip during CRC driver load CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Acked-by: Lee Jones Acked-by: Linus Walleij Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/mfd/intel_soc_pmic_core.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index 7b50b6b208a5..f3d918e9ca02 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -24,8 +24,19 @@ #include #include #include +#include #include "intel_soc_pmic_core.h" +/* Lookup table for the Panel Enable/Disable line as GPIO signals */ +static struct gpiod_lookup_table panel_gpio_table = { + /* Intel GFX is consumer */ + .dev_id = "0000:00:02.0", + .table = { + /* Panel EN/DISABLE */ + GPIO_LOOKUP("gpio_crystalcove", 94, "panel", GPIO_ACTIVE_HIGH), + }, +}; + static int intel_soc_pmic_find_gpio_irq(struct device *dev) { struct gpio_desc *desc; @@ -85,6 +96,9 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c, if (ret) dev_warn(dev, "Can't enable IRQ as wake source: %d\n", ret); + /* Add lookup table binding for Panel Control to the GPIO Chip */ + gpiod_add_lookup_table(&panel_gpio_table); + ret = mfd_add_devices(dev, -1, config->cell_dev, config->n_cell_devs, NULL, 0, regmap_irq_get_domain(pmic->irq_chip_data)); @@ -104,6 +118,9 @@ static int intel_soc_pmic_i2c_remove(struct i2c_client *i2c) regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); + /* Remove lookup table for Panel Control from the GPIO Chip */ + gpiod_remove_lookup_table(&panel_gpio_table); + mfd_remove_devices(&i2c->dev); return 0; -- cgit v1.3-6-gb490 From 3d5e10ec50f80bc433916ee0cefbc8dfd16acb0c Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:06 +0530 Subject: mfd: intel_soc_pmic_crc: Add PWM cell device for Crystalcove PMIC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for PWM control suuported by the PMIC CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Acked-by: Lee Jones Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/mfd/intel_soc_pmic_crc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index 7436075e8983..4a7494872da2 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -109,6 +109,9 @@ static struct mfd_cell crystal_cove_dev[] = { { .name = "crystal_cove_pmic", }, + { + .name = "crystal_cove_pwm", + }, }; static const struct regmap_config crystal_cove_regmap_config = { -- cgit v1.3-6-gb490 From a3aa9a93df9fc8a0c54485e4144fdb81591e2175 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:07 +0530 Subject: mfd: intel_soc_pmic_core: ADD PWM lookup table for CRC PMIC based PWM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some BYT PLatform the PWM is controlled using CRC PMIC. Add a lookup entry for the same to be used by the consumer (Intel GFX) CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Acked-by: Lee Jones Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/mfd/intel_soc_pmic_core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index f3d918e9ca02..a00ddd93dc15 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "intel_soc_pmic_core.h" /* Lookup table for the Panel Enable/Disable line as GPIO signals */ @@ -37,6 +38,11 @@ static struct gpiod_lookup_table panel_gpio_table = { }, }; +/* PWM consumed by the Intel GFX */ +static struct pwm_lookup crc_pwm_lookup[] = { + PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_backlight", 0, PWM_POLARITY_NORMAL), +}; + static int intel_soc_pmic_find_gpio_irq(struct device *dev) { struct gpio_desc *desc; @@ -99,6 +105,9 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c, /* Add lookup table binding for Panel Control to the GPIO Chip */ gpiod_add_lookup_table(&panel_gpio_table); + /* Add lookup table for crc-pwm */ + pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); + ret = mfd_add_devices(dev, -1, config->cell_dev, config->n_cell_devs, NULL, 0, regmap_irq_get_domain(pmic->irq_chip_data)); @@ -121,6 +130,9 @@ static int intel_soc_pmic_i2c_remove(struct i2c_client *i2c) /* Remove lookup table for Panel Control from the GPIO Chip */ gpiod_remove_lookup_table(&panel_gpio_table); + /* remove crc-pwm lookup table */ + pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); + mfd_remove_devices(&i2c->dev); return 0; -- cgit v1.3-6-gb490 From a3f37a104bc42f19ceb74e3e06752b6e3a269745 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:08 +0530 Subject: pwm: crc: Add Crystalcove (CRC) PWM driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Crystalcove PMIC provides three PWM signals and this driver exports one of them on the BYT platform which is used to control backlight for DSI panel. This is platform device implementation of the drivers/mfd cell device for CRC PMIC. CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Cc: Paul Bolle Cc: Paul Gortmaker Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Reviewed-by: Varka Bhadram Signed-off-by: Daniel Vetter --- drivers/pwm/Kconfig | 7 +++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-crc.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 drivers/pwm/pwm-crc.c (limited to 'drivers') diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index b1541f40fd8d..948d9abd27f1 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -111,6 +111,13 @@ config PWM_CLPS711X To compile this driver as a module, choose M here: the module will be called pwm-clps711x. +config PWM_CRC + bool "Intel Crystalcove (CRC) PWM support" + depends on X86 && INTEL_SOC_PMIC + help + Generic PWM framework driver for Crystalcove (CRC) PMIC based PWM + control. + config PWM_EP93XX tristate "Cirrus Logic EP93xx PWM support" depends on ARCH_EP93XX diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index ec50eb5b5a8f..d186f35a6538 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o obj-$(CONFIG_PWM_BCM2835) += pwm-bcm2835.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o +obj-$(CONFIG_PWM_CRC) += pwm-crc.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o obj-$(CONFIG_PWM_IMG) += pwm-img.o diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c new file mode 100644 index 000000000000..7101c7020bf4 --- /dev/null +++ b/drivers/pwm/pwm-crc.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2015 Intel 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 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. + * + * Author: Shobhit Kumar + */ + +#include +#include +#include +#include + +#define PWM0_CLK_DIV 0x4B +#define PWM_OUTPUT_ENABLE BIT(7) +#define PWM_DIV_CLK_0 0x00 /* DIVIDECLK = BASECLK */ +#define PWM_DIV_CLK_100 0x63 /* DIVIDECLK = BASECLK/100 */ +#define PWM_DIV_CLK_128 0x7F /* DIVIDECLK = BASECLK/128 */ + +#define PWM0_DUTY_CYCLE 0x4E +#define BACKLIGHT_EN 0x51 + +#define PWM_MAX_LEVEL 0xFF + +#define PWM_BASE_CLK 6000000 /* 6 MHz */ +#define PWM_MAX_PERIOD_NS 21333 /* 46.875KHz */ + +/** + * struct crystalcove_pwm - Crystal Cove PWM controller + * @chip: the abstract pwm_chip structure. + * @regmap: the regmap from the parent device. + */ +struct crystalcove_pwm { + struct pwm_chip chip; + struct regmap *regmap; +}; + +static inline struct crystalcove_pwm *to_crc_pwm(struct pwm_chip *pc) +{ + return container_of(pc, struct crystalcove_pwm, chip); +} + +static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm) +{ + struct crystalcove_pwm *crc_pwm = to_crc_pwm(c); + + regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1); + + return 0; +} + +static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm) +{ + struct crystalcove_pwm *crc_pwm = to_crc_pwm(c); + + regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0); +} + +static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct crystalcove_pwm *crc_pwm = to_crc_pwm(c); + struct device *dev = crc_pwm->chip.dev; + int level; + + if (period_ns > PWM_MAX_PERIOD_NS) { + dev_err(dev, "un-supported period_ns\n"); + return -EINVAL; + } + + if (pwm->period != period_ns) { + int clk_div; + + /* changing the clk divisor, need to disable fisrt */ + crc_pwm_disable(c, pwm); + clk_div = PWM_BASE_CLK * period_ns / NSEC_PER_SEC; + + regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, + clk_div | PWM_OUTPUT_ENABLE); + + /* enable back */ + crc_pwm_enable(c, pwm); + } + + /* change the pwm duty cycle */ + level = duty_ns * PWM_MAX_LEVEL / period_ns; + regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level); + + return 0; +} + +static const struct pwm_ops crc_pwm_ops = { + .config = crc_pwm_config, + .enable = crc_pwm_enable, + .disable = crc_pwm_disable, +}; + +static int crystalcove_pwm_probe(struct platform_device *pdev) +{ + struct crystalcove_pwm *pwm; + struct device *dev = pdev->dev.parent; + struct intel_soc_pmic *pmic = dev_get_drvdata(dev); + + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); + if (!pwm) + return -ENOMEM; + + pwm->chip.dev = &pdev->dev; + pwm->chip.ops = &crc_pwm_ops; + pwm->chip.base = -1; + pwm->chip.npwm = 1; + + /* get the PMIC regmap */ + pwm->regmap = pmic->regmap; + + platform_set_drvdata(pdev, pwm); + + return pwmchip_add(&pwm->chip); +} + +static int crystalcove_pwm_remove(struct platform_device *pdev) +{ + struct crystalcove_pwm *pwm = platform_get_drvdata(pdev); + + return pwmchip_remove(&pwm->chip); +} + +static struct platform_driver crystalcove_pwm_driver = { + .probe = crystalcove_pwm_probe, + .remove = crystalcove_pwm_remove, + .driver = { + .name = "crystal_cove_pwm", + }, +}; + +builtin_platform_driver(crystalcove_pwm_driver); -- cgit v1.3-6-gb490 From fc45e821990781c13dba10e3aef1c9f11af8af08 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:09 +0530 Subject: drm/i915: Use the CRC gpio for panel enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CRC (Crystal Cove) PMIC, controls the panel enable and disable signals for BYT for dsi panels. This is indicated in the VBT fields. Use that to initialize and use GPIO based control for these signals. v2: Use the newer gpiod interface(Alexandre) v3: Remove the redundant checks and unused code (Ville) v4: Moved PWM vs SoC backlight #defines to intel_bios.h (Jani) CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Acked-by: Linus Walleij Reviewed-by: Jani Nikula Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.h | 7 +++++++ drivers/gpu/drm/i915/intel_dsi.c | 32 ++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_dsi.h | 3 +++ 3 files changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index af0b47652752..f7ad6a585129 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -778,6 +778,13 @@ int intel_parse_bios(struct drm_device *dev); #define MIPI_DSI_UNDEFINED_PANEL_ID 0 #define MIPI_DSI_GENERIC_PANEL_ID 1 +/* + * PMIC vs SoC Backlight support specified in pwm_blc + * field in mipi_config block below. +*/ +#define PPS_BLC_PMIC 0 +#define PPS_BLC_SOC 1 + struct mipi_config { u16 panel_id; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index b5a5558ecd63..c4db74a5e4e7 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "i915_drv.h" #include "intel_drv.h" #include "intel_dsi.h" @@ -415,6 +416,12 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); + /* Panel Enable over CRC PMIC */ + if (intel_dsi->gpio_panel) + gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1); + + msleep(intel_dsi->panel_on_delay); + /* Disable DPOunit clock gating, can stall pipe * and we need DPLL REFA always enabled */ tmp = I915_READ(DPLL(pipe)); @@ -432,8 +439,6 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) /* put device in ready state */ intel_dsi_device_ready(encoder); - msleep(intel_dsi->panel_on_delay); - drm_panel_prepare(intel_dsi->panel); for_each_dsi_port(port, intel_dsi->ports) @@ -576,6 +581,10 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder) msleep(intel_dsi->panel_off_delay); msleep(intel_dsi->panel_pwr_cycle_delay); + + /* Panel Disable over CRC PMIC */ + if (intel_dsi->gpio_panel) + gpiod_set_value_cansleep(intel_dsi->gpio_panel, 0); } static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, @@ -955,6 +964,11 @@ static void intel_dsi_encoder_destroy(struct drm_encoder *encoder) /* XXX: Logically this call belongs in the panel driver. */ drm_panel_remove(intel_dsi->panel); } + + /* dispose of the gpios */ + if (intel_dsi->gpio_panel) + gpiod_put(intel_dsi->gpio_panel); + intel_encoder_destroy(encoder); } @@ -1071,6 +1085,20 @@ void intel_dsi_init(struct drm_device *dev) goto err; } + /* + * In case of BYT with CRC PMIC, we need to use GPIO for + * Panel control. + */ + if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) { + intel_dsi->gpio_panel = + gpiod_get(dev->dev, "panel", GPIOD_OUT_HIGH); + + if (IS_ERR(intel_dsi->gpio_panel)) { + DRM_ERROR("Failed to own gpio for panel control\n"); + intel_dsi->gpio_panel = NULL; + } + } + intel_encoder->type = INTEL_OUTPUT_DSI; intel_encoder->cloneable = 0; drm_connector_init(dev, connector, &intel_dsi_connector_funcs, diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 2784ac442368..42a68593e32a 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -42,6 +42,9 @@ struct intel_dsi { struct drm_panel *panel; struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS]; + /* GPIO Desc for CRC based Panel control */ + struct gpio_desc *gpio_panel; + struct intel_connector *attached_connector; /* bit mask of ports being driven */ -- cgit v1.3-6-gb490 From b029e66fa8e39ba10dcc47b114be8da8b082493b Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:10 +0530 Subject: drm/i915: Backlight control using CRC PMIC based PWM driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the CRC PWM device in intel_panel.c and add new MIPI backlight specififc callbacks v2: Modify to use pwm_config callback v3: Addressed Jani's comments - Renamed all function as pwm_* instead of vlv_* - Call intel_panel_actually_set_backlight in enable function - Return -ENODEV in case pwm_get fails - in case pwm_config error return error cdoe from pwm_config - Cleanup pwm in intel_panel_destroy_backlight v4: Removed unused #defines and initialized backlight with INVALID_PIPE (Ville) CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Reviewed-by: Ville Syrjälä Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 4 ++ drivers/gpu/drm/i915/intel_dsi.c | 5 ++ drivers/gpu/drm/i915/intel_panel.c | 94 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 98 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 105928382e21..286127001c43 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -182,6 +182,10 @@ struct intel_panel { bool enabled; bool combination_mode; /* gen 2/4 only */ bool active_low_pwm; + + /* PWM chip */ + struct pwm_device *pwm; + struct backlight_device *device; } backlight; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index c4db74a5e4e7..892b936e14d4 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -402,6 +402,8 @@ static void intel_dsi_enable(struct intel_encoder *encoder) intel_dsi_port_enable(encoder); } + + intel_panel_enable_backlight(intel_dsi->attached_connector); } static void intel_dsi_pre_enable(struct intel_encoder *encoder) @@ -466,6 +468,8 @@ static void intel_dsi_pre_disable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); + intel_panel_disable_backlight(intel_dsi->attached_connector); + if (is_vid_mode(intel_dsi)) { /* Send Shutdown command to the panel in LP mode */ for_each_dsi_port(port, intel_dsi->ports) @@ -1132,6 +1136,7 @@ void intel_dsi_init(struct drm_device *dev) } intel_panel_init(&intel_connector->panel, fixed_mode, NULL); + intel_panel_setup_backlight(connector, INVALID_PIPE); return; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 55aad2322e10..e2ab3f6ed022 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -32,8 +32,11 @@ #include #include +#include #include "intel_drv.h" +#define CRC_PMIC_PWM_PERIOD_NS 21333 + void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode) @@ -544,6 +547,15 @@ static u32 bxt_get_backlight(struct intel_connector *connector) return I915_READ(BXT_BLC_PWM_DUTY1); } +static u32 pwm_get_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + int duty_ns; + + duty_ns = pwm_get_duty_cycle(panel->backlight.pwm); + return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS); +} + static u32 intel_panel_get_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -632,6 +644,14 @@ static void bxt_set_backlight(struct intel_connector *connector, u32 level) I915_WRITE(BXT_BLC_PWM_DUTY1, level); } +static void pwm_set_backlight(struct intel_connector *connector, u32 level) +{ + struct intel_panel *panel = &connector->panel; + int duty_ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100); + + pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS); +} + static void intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) { @@ -769,6 +789,16 @@ static void bxt_disable_backlight(struct intel_connector *connector) I915_WRITE(BXT_BLC_PWM_CTL1, tmp & ~BXT_BLC_PWM_ENABLE); } +static void pwm_disable_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + + /* Disable the backlight */ + pwm_config(panel->backlight.pwm, 0, CRC_PMIC_PWM_PERIOD_NS); + usleep_range(2000, 3000); + pwm_disable(panel->backlight.pwm); +} + void intel_panel_disable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -1010,6 +1040,14 @@ static void bxt_enable_backlight(struct intel_connector *connector) I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl | BXT_BLC_PWM_ENABLE); } +static void pwm_enable_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + + pwm_enable(panel->backlight.pwm); + intel_panel_actually_set_backlight(connector, panel->backlight.level); +} + void intel_panel_enable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -1386,6 +1424,40 @@ bxt_setup_backlight(struct intel_connector *connector, enum pipe unused) return 0; } +static int pwm_setup_backlight(struct intel_connector *connector, + enum pipe pipe) +{ + struct drm_device *dev = connector->base.dev; + struct intel_panel *panel = &connector->panel; + int retval; + + /* Get the PWM chip for backlight control */ + panel->backlight.pwm = pwm_get(dev->dev, "pwm_backlight"); + if (IS_ERR(panel->backlight.pwm)) { + DRM_ERROR("Failed to own the pwm chip\n"); + panel->backlight.pwm = NULL; + return -ENODEV; + } + + retval = pwm_config(panel->backlight.pwm, CRC_PMIC_PWM_PERIOD_NS, + CRC_PMIC_PWM_PERIOD_NS); + if (retval < 0) { + DRM_ERROR("Failed to configure the pwm chip\n"); + pwm_put(panel->backlight.pwm); + panel->backlight.pwm = NULL; + return retval; + } + + panel->backlight.min = 0; /* 0% */ + panel->backlight.max = 100; /* 100% */ + panel->backlight.level = DIV_ROUND_UP( + pwm_get_duty_cycle(panel->backlight.pwm) * 100, + CRC_PMIC_PWM_PERIOD_NS); + panel->backlight.enabled = panel->backlight.level != 0; + + return 0; +} + int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) { struct drm_device *dev = connector->dev; @@ -1429,6 +1501,10 @@ void intel_panel_destroy_backlight(struct drm_connector *connector) struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_panel *panel = &intel_connector->panel; + /* dispose of the pwm */ + if (panel->backlight.pwm) + pwm_put(panel->backlight.pwm); + panel->backlight.present = false; } @@ -1456,11 +1532,19 @@ void intel_panel_init_backlight_funcs(struct drm_device *dev) dev_priv->display.set_backlight = pch_set_backlight; dev_priv->display.get_backlight = pch_get_backlight; } else if (IS_VALLEYVIEW(dev)) { - dev_priv->display.setup_backlight = vlv_setup_backlight; - dev_priv->display.enable_backlight = vlv_enable_backlight; - dev_priv->display.disable_backlight = vlv_disable_backlight; - dev_priv->display.set_backlight = vlv_set_backlight; - dev_priv->display.get_backlight = vlv_get_backlight; + if (dev_priv->vbt.has_mipi) { + dev_priv->display.setup_backlight = pwm_setup_backlight; + dev_priv->display.enable_backlight = pwm_enable_backlight; + dev_priv->display.disable_backlight = pwm_disable_backlight; + dev_priv->display.set_backlight = pwm_set_backlight; + dev_priv->display.get_backlight = pwm_get_backlight; + } else { + dev_priv->display.setup_backlight = vlv_setup_backlight; + dev_priv->display.enable_backlight = vlv_enable_backlight; + dev_priv->display.disable_backlight = vlv_disable_backlight; + dev_priv->display.set_backlight = vlv_set_backlight; + dev_priv->display.get_backlight = vlv_get_backlight; + } } else if (IS_GEN4(dev)) { dev_priv->display.setup_backlight = i965_setup_backlight; dev_priv->display.enable_backlight = i965_enable_backlight; -- cgit v1.3-6-gb490 From a44e7b73118b21176bdf6376c620d778a0ff0ee2 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Fri, 17 Jul 2015 13:12:30 -0700 Subject: cxgb4 : Only pass app selector of 0 or 3 to firmware This keeps app format passed to firmware the same irrespective of DCBx version in use. Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index 6074680bc985..7f7c4ba0d4f4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -794,7 +794,9 @@ static int __cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id, */ static int cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id) { - return __cxgb4_getapp(dev, app_idtype, app_id, 0); + /* Convert app_idtype to firmware format before querying */ + return __cxgb4_getapp(dev, app_idtype == DCB_APP_IDTYPE_ETHTYPE ? + app_idtype : 3, app_id, 0); } /* Write a new Application User Priority Map for the specified Application ID @@ -1133,7 +1135,7 @@ static int cxgb4_getpeerapp_tbl(struct net_device *dev, struct dcb_app *table) if (!pcmd.u.dcb.app_priority.protocolid) break; - table[i].selector = pcmd.u.dcb.app_priority.sel_field; + table[i].selector = (pcmd.u.dcb.app_priority.sel_field + 1); table[i].protocol = be16_to_cpu(pcmd.u.dcb.app_priority.protocolid); table[i].priority = -- cgit v1.3-6-gb490 From a85c2eb3113299b8d55936a49e70c5b63c72617f Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Fri, 17 Jul 2015 13:12:31 -0700 Subject: cxgb4 : Allow firmware DCB info to be queried in host state Since finally DCB traffic management is still handled by firmware, allow firmware to be fully programmed and queried even in host managed state for the cases where this was previously rejected. Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 32 +++++++++++++++++--------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index 7f7c4ba0d4f4..56a81b8f7c54 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -31,6 +31,15 @@ static const char * const dcb_ver_array[] = { "Auto Negotiated" }; +static inline bool cxgb4_dcb_state_synced(enum cxgb4_dcb_state state) +{ + if (state == CXGB4_DCB_STATE_FW_ALLSYNCED || + state == CXGB4_DCB_STATE_HOST) + return true; + else + return false; +} + /* Initialize a port's Data Center Bridging state. Typically used after a * Link Down event. */ @@ -603,7 +612,7 @@ static void cxgb4_getpfccfg(struct net_device *dev, int priority, u8 *pfccfg) struct port_info *pi = netdev2pinfo(dev); struct port_dcb_info *dcb = &pi->dcb; - if (dcb->state != CXGB4_DCB_STATE_FW_ALLSYNCED || + if (!cxgb4_dcb_state_synced(dcb->state) || priority >= CXGB4_MAX_PRIORITY) *pfccfg = 0; else @@ -620,7 +629,7 @@ static void cxgb4_setpfccfg(struct net_device *dev, int priority, u8 pfccfg) struct adapter *adap = pi->adapter; int err; - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED || + if (!cxgb4_dcb_state_synced(pi->dcb.state) || priority >= CXGB4_MAX_PRIORITY) return; @@ -732,7 +741,7 @@ static u8 cxgb4_getpfcstate(struct net_device *dev) { struct port_info *pi = netdev2pinfo(dev); - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return false; return pi->dcb.pfcen != 0; @@ -756,7 +765,7 @@ static int __cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id, struct adapter *adap = pi->adapter; int i; - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return 0; for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) { @@ -810,7 +819,7 @@ static int __cxgb4_setapp(struct net_device *dev, u8 app_idtype, u16 app_id, int i, err; - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return -EINVAL; /* DCB info gets thrown away on link up */ @@ -898,10 +907,11 @@ cxgb4_ieee_negotiation_complete(struct net_device *dev, struct port_info *pi = netdev2pinfo(dev); struct port_dcb_info *dcb = &pi->dcb; - if (dcb_subtype && !(dcb->msgs & dcb_subtype)) - return 0; + if (dcb->state == CXGB4_DCB_STATE_FW_ALLSYNCED) + if (dcb_subtype && !(dcb->msgs & dcb_subtype)) + return 0; - return (dcb->state == CXGB4_DCB_STATE_FW_ALLSYNCED && + return (cxgb4_dcb_state_synced(dcb->state) && (dcb->supported & DCB_CAP_DCBX_VER_IEEE)); } @@ -1059,7 +1069,7 @@ static u8 cxgb4_setdcbx(struct net_device *dev, u8 dcb_request) /* Can't enable DCB if we haven't successfully negotiated it. */ - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return 1; /* There's currently no mechanism to allow for the firmware DCBX @@ -1082,7 +1092,7 @@ static int cxgb4_getpeer_app(struct net_device *dev, struct adapter *adap = pi->adapter; int i, err = 0; - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return 1; info->willing = 0; @@ -1116,7 +1126,7 @@ static int cxgb4_getpeerapp_tbl(struct net_device *dev, struct dcb_app *table) struct adapter *adap = pi->adapter; int i, err = 0; - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return 1; for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) { -- cgit v1.3-6-gb490 From 8d6541b7bc0a56020ffc9fab7d740e47addd609d Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Fri, 17 Jul 2015 13:12:32 -0700 Subject: cxgb4 : Fill in number of DCB traffic classes supported Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index 56a81b8f7c54..052c660aca80 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -1193,6 +1193,8 @@ static int cxgb4_cee_peer_getpg(struct net_device *dev, struct cee_pg *pg) for (i = 0; i < CXGB4_MAX_PRIORITY; i++) pg->pg_bw[i] = pcmd.u.dcb.pgrate.pgrate[i]; + pg->tcs_supported = pcmd.u.dcb.pgrate.num_tcs_supported; + return 0; } @@ -1210,6 +1212,8 @@ static int cxgb4_cee_peer_getpfc(struct net_device *dev, struct cee_pfc *pfc) */ pfc->pfc_en = bitswap_1(pi->dcb.pfcen); + pfc->tcs_supported = pi->dcb.pfc_num_tcs_supported; + return 0; } -- cgit v1.3-6-gb490 From 397665dab58415d648f03e2893627f4f7abf0fba Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Fri, 17 Jul 2015 13:12:33 -0700 Subject: cxgb4 : Fill DCB priority in vlan control headers Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sge.c | 14 ++++++++++---- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 942db078f33a..d4248d74f560 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -1137,7 +1137,7 @@ cxgb_fcoe_offload(struct sk_buff *skb, struct adapter *adap, */ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) { - u32 wr_mid; + u32 wr_mid, ctrl0; u64 cntrl, *end; int qidx, credits; unsigned int flits, ndesc; @@ -1274,9 +1274,15 @@ out_free: dev_kfree_skb_any(skb); #endif /* CONFIG_CHELSIO_T4_FCOE */ } - cpl->ctrl0 = htonl(TXPKT_OPCODE_V(CPL_TX_PKT_XT) | - TXPKT_INTF_V(pi->tx_chan) | - TXPKT_PF_V(adap->pf)); + ctrl0 = TXPKT_OPCODE_V(CPL_TX_PKT_XT) | TXPKT_INTF_V(pi->tx_chan) | + TXPKT_PF_V(adap->pf); +#ifdef CONFIG_CHELSIO_T4_DCB + if (is_t4(adap->params.chip)) + ctrl0 |= TXPKT_OVLAN_IDX_V(q->dcb_prio); + else + ctrl0 |= TXPKT_T5_OVLAN_IDX_V(q->dcb_prio); +#endif + cpl->ctrl0 = htonl(ctrl0); cpl->pack = htons(0); cpl->len = htons(skb->len); cpl->ctrl1 = cpu_to_be64(cntrl); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 132cb8fc0bf7..b99144afd4ec 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -660,6 +660,9 @@ struct cpl_tx_pkt { #define TXPKT_OVLAN_IDX_S 12 #define TXPKT_OVLAN_IDX_V(x) ((x) << TXPKT_OVLAN_IDX_S) +#define TXPKT_T5_OVLAN_IDX_S 12 +#define TXPKT_T5_OVLAN_IDX_V(x) ((x) << TXPKT_T5_OVLAN_IDX_S) + #define TXPKT_INTF_S 16 #define TXPKT_INTF_V(x) ((x) << TXPKT_INTF_S) -- cgit v1.3-6-gb490 From dd72bde05de5d68d56e59698f7f2c102afce904b Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 17 Jul 2015 17:08:51 +0100 Subject: drm/i915: Do kunmap if renderstate parsing fails Kunmap the renderstate page on error path. Reviewed-by: Arun Siluvery Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_render_state.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index a0201fc94d25..b6492fe3722b 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -96,8 +96,10 @@ static int render_state_setup(struct render_state *so) s = lower_32_bits(r); if (so->gen >= 8) { if (i + 1 >= rodata->batch_items || - rodata->batch[i + 1] != 0) - return -EINVAL; + rodata->batch[i + 1] != 0) { + ret = -EINVAL; + goto err_out; + } d[i++] = s; s = upper_32_bits(r); @@ -120,6 +122,10 @@ static int render_state_setup(struct render_state *so) } return 0; + +err_out: + kunmap(page); + return ret; } void i915_gem_render_state_fini(struct render_state *so) -- cgit v1.3-6-gb490 From 84e81020ee237df8af359c552b503db476b776ea Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Mon, 20 Jul 2015 10:46:10 +0100 Subject: drm/i915: Add provision to extend Golden context batch The Golden batch carries 3D state at the beginning so that HW starts with a known state. It is carried as a binary blob which is auto-generated from source. The idea was it would be easier to maintain and keep the complexity out of the kernel which makes sense as we don't really touch it. However if you really need to update it then you need to update generator source and keep the binary blob in sync with it. There is a need to patch this in bxt to send one additional command to enable a feature. A solution was to patch the binary data with some additional data structures (included as part of auto-generator source) but it was unnecessarily complicated. Chris suggested the idea of having a secondary batch and execute two batch buffers. It has clear advantages as we needn't touch the base golden batch, can customize secondary/auxiliary batch depending on Gen and can be carried in the driver with no dependencies. This patch adds support for this auxiliary batch which is inserted at the end of golden batch and is completely independent from it. Thanks to Mika for the preliminary review. v2: Strictly conform to the batch size requirements to cover Gen2 and add comments to clarify overflow check in macro (Chris, Mika). v3: aux_batch_offset was declared as u64, change it to u32 (Chris) Reviewed-by: Chris Wilson Cc: Mika Kuoppala Cc: Chris Wilson Cc: Armin Reese Signed-off-by: Arun Siluvery Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_render_state.c | 45 ++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_gem_render_state.h | 2 ++ drivers/gpu/drm/i915/intel_lrc.c | 6 ++++ 3 files changed, 53 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index b6492fe3722b..5026a6267a88 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -73,6 +73,24 @@ free_gem: return ret; } +/* + * Macro to add commands to auxiliary batch. + * This macro only checks for page overflow before inserting the commands, + * this is sufficient as the null state generator makes the final batch + * with two passes to build command and state separately. At this point + * the size of both are known and it compacts them by relocating the state + * right after the commands taking care of aligment so we should sufficient + * space below them for adding new commands. + */ +#define OUT_BATCH(batch, i, val) \ + do { \ + if (WARN_ON((i) >= PAGE_SIZE / sizeof(u32))) { \ + ret = -ENOSPC; \ + goto err_out; \ + } \ + (batch)[(i)++] = (val); \ + } while(0) + static int render_state_setup(struct render_state *so) { const struct intel_renderstate_rodata *rodata = so->rodata; @@ -110,6 +128,21 @@ static int render_state_setup(struct render_state *so) d[i++] = s; } + + while (i % CACHELINE_DWORDS) + OUT_BATCH(d, i, MI_NOOP); + + so->aux_batch_offset = i * sizeof(u32); + + OUT_BATCH(d, i, MI_BATCH_BUFFER_END); + so->aux_batch_size = (i * sizeof(u32)) - so->aux_batch_offset; + + /* + * Since we are sending length, we need to strictly conform to + * all requirements. For Gen2 this must be a multiple of 8. + */ + so->aux_batch_size = ALIGN(so->aux_batch_size, 8); + kunmap(page); ret = i915_gem_object_set_to_gtt_domain(so->obj, false); @@ -128,6 +161,8 @@ err_out: return ret; } +#undef OUT_BATCH + void i915_gem_render_state_fini(struct render_state *so) { i915_gem_object_ggtt_unpin(so->obj); @@ -176,6 +211,16 @@ int i915_gem_render_state_init(struct drm_i915_gem_request *req) if (ret) goto out; + if (so.aux_batch_size > 8) { + ret = req->ring->dispatch_execbuffer(req, + (so.ggtt_offset + + so.aux_batch_offset), + so.aux_batch_size, + I915_DISPATCH_SECURE); + if (ret) + goto out; + } + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req); out: diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.h b/drivers/gpu/drm/i915/i915_gem_render_state.h index 7aa73728178a..e641bb093a90 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.h +++ b/drivers/gpu/drm/i915/i915_gem_render_state.h @@ -37,6 +37,8 @@ struct render_state { struct drm_i915_gem_object *obj; u64 ggtt_offset; int gen; + u32 aux_batch_size; + u32 aux_batch_offset; }; int i915_gem_render_state_init(struct drm_i915_gem_request *req); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9faad82c42ec..99bba8ece464 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1740,6 +1740,12 @@ static int intel_lr_context_render_state_init(struct drm_i915_gem_request *req) if (ret) goto out; + ret = req->ring->emit_bb_start(req, + (so.ggtt_offset + so.aux_batch_offset), + I915_DISPATCH_SECURE); + if (ret) + goto out; + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req); out: -- cgit v1.3-6-gb490 From 2070c48cf2b78af89ba529c00992eaaa18df8ef7 Mon Sep 17 00:00:00 2001 From: Pieter Hollants Date: Mon, 20 Jul 2015 10:14:13 +0200 Subject: qmi_wwan: Add support for Dell Wireless 5809e 4G Modem Added the USB IDs 0x413c:0x81b1 for the "Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card", a Dell-branded Sierra Wireless EM7305 LTE card in M.2 form factor, used eg. in Dell's Latitude E7540 Notebook series. Signed-off-by: Pieter Hollants Signed-off-by: David S. Miller --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index f603f362504b..f06c687c5429 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -784,6 +784,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x413c, 0x81a4, 8)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a8, 8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */ + {QMI_FIXED_INTF(0x413c, 0x81b1, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */ {QMI_FIXED_INTF(0x03f0, 0x581d, 4)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */ /* 4. Gobi 1000 devices */ -- cgit v1.3-6-gb490 From eacd2d542610e55cad0be445966ac8ae79124c6e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 9 Jul 2015 18:24:56 -0700 Subject: drivers/video/fbdev/atyfb: Carve out framebuffer length fudging into a helper The size of the framebuffer to be used needs to be fudged to account for the different type of devices that are out there. This captures what is required to do well, we'll reuse this later. This has no functional changes. Signed-off-by: Luis R. Rodriguez Signed-off-by: Borislav Petkov Cc: H. Peter Anvin Cc: Jean-Christophe Plagniol-Villard Cc: Linus Torvalds Cc: Mathias Krause Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tomi Valkeinen Cc: airlied@redhat.com Cc: arnd@arndb.de Cc: benh@kernel.crashing.org Cc: dan.j.williams@intel.com Cc: geert@linux-m68k.org Cc: hch@lst.de Cc: hmh@hmh.eng.br Cc: jgross@suse.com Cc: linux-fbdev@vger.kernel.org Cc: linux-mm@kvack.org Cc: luto@amacapital.net Cc: mpe@ellerman.id.au Cc: mst@redhat.com Cc: ralf@linux-mips.org Cc: ross.zwisler@linux.intel.com Cc: stefan.bader@canonical.com Cc: syrjala@sci.fi Cc: tj@kernel.org Cc: toshi.kani@hp.com Cc: ville.syrjala@linux.intel.com Link: http://lkml.kernel.org/r/1435251019-32421-1-git-send-email-mcgrof@do-not-panic.com Link: http://lkml.kernel.org/r/1436491499-3289-2-git-send-email-mcgrof@do-not-panic.com Signed-off-by: Ingo Molnar --- drivers/video/fbdev/aty/atyfb_base.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index 8789e487b96e..16936bb1f865 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -427,6 +427,20 @@ static struct { #endif /* CONFIG_FB_ATY_CT */ }; +/* + * Last page of 8 MB (4 MB on ISA) aperture is MMIO, + * unless the auxiliary register aperture is used. + */ +static void aty_fudge_framebuffer_len(struct fb_info *info) +{ + struct atyfb_par *par = (struct atyfb_par *) info->par; + + if (!par->aux_start && + (info->fix.smem_len == 0x800000 || + (par->bus_type == ISA && info->fix.smem_len == 0x400000))) + info->fix.smem_len -= GUI_RESERVE; +} + static int correct_chipset(struct atyfb_par *par) { u8 rev; @@ -2603,14 +2617,7 @@ static int aty_init(struct fb_info *info) if (par->pll_ops->resume_pll) par->pll_ops->resume_pll(info, &par->pll); - /* - * Last page of 8 MB (4 MB on ISA) aperture is MMIO, - * unless the auxiliary register aperture is used. - */ - if (!par->aux_start && - (info->fix.smem_len == 0x800000 || - (par->bus_type == ISA && info->fix.smem_len == 0x400000))) - info->fix.smem_len -= GUI_RESERVE; + aty_fudge_framebuffer_len(info); /* * Disable register access through the linear aperture -- cgit v1.3-6-gb490 From f55de6ec375da89f89f1a76e1b998e5f14878c06 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 9 Jul 2015 18:24:57 -0700 Subject: drivers/video/fbdev/atyfb: Clarify ioremap() base and length used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjust the ioremap() call for the framebuffer to use the same values we later use for the framebuffer. This will make it easier to review the next change. The size of the framebuffer varies but since this is for PCI we *know* this defaults to 0x800000. atyfb_setup_generic() is *only* used on PCI probe. No functional change. Signed-off-by: Luis R. Rodriguez Signed-off-by: Borislav Petkov Cc: Andrew Morton Cc: Andrzej Hajda Cc: Andy Lutomirski Cc: Antonino Daplas Cc: Daniel Vetter Cc: Dave Airlie Cc: Davidlohr Bueso Cc: H. Peter Anvin Cc: Jean-Christophe Plagniol-Villard Cc: Juergen Gross Cc: Linus Torvalds Cc: Mathias Krause Cc: Mel Gorman Cc: Peter Zijlstra Cc: Rob Clark Cc: Suresh Siddha Cc: Thomas Gleixner Cc: Tomi Valkeinen Cc: Toshi Kani Cc: Ville Syrjälä Cc: Vlastimil Babka Cc: arnd@arndb.de Cc: benh@kernel.crashing.org Cc: dan.j.williams@intel.com Cc: geert@linux-m68k.org Cc: hch@lst.de Cc: hmh@hmh.eng.br Cc: linux-fbdev@vger.kernel.org Cc: linux-mm@kvack.org Cc: linux-pci@vger.kernel.org Cc: mpe@ellerman.id.au Cc: mst@redhat.com Cc: ralf@linux-mips.org Cc: ross.zwisler@linux.intel.com Cc: stefan.bader@canonical.com Cc: tj@kernel.org Cc: ville.syrjala@linux.intel.com Link: http://lkml.kernel.org/r/1436491499-3289-3-git-send-email-mcgrof@do-not-panic.com Signed-off-by: Ingo Molnar --- drivers/video/fbdev/aty/atyfb_base.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index 16936bb1f865..de8f7e082c87 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -3489,7 +3489,21 @@ static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info, /* Map in frame buffer */ info->fix.smem_start = addr; - info->screen_base = ioremap(addr, 0x800000); + + /* + * The framebuffer is not always 8 MiB, that's just the size of the + * PCI BAR. We temporarily abuse smem_len here to store the size + * of the BAR. aty_init() will later correct it to match the actual + * framebuffer size. + * + * On devices that don't have the auxiliary register aperture, the + * registers are housed at the top end of the framebuffer PCI BAR. + * aty_fudge_framebuffer_len() is used to reduce smem_len to not + * overlap with the registers. + */ + info->fix.smem_len = 0x800000; + + info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); if (info->screen_base == NULL) { ret = -ENOMEM; goto atyfb_setup_generic_fail; -- cgit v1.3-6-gb490 From 3cc2dac5be3f23414a4efdee0b26d79bed297cac Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 9 Jul 2015 18:24:58 -0700 Subject: drivers/video/fbdev/atyfb: Replace MTRR UC hole with strong UC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace a WC MTRR call followed by a UC MTRR "hole" call with a single WC MTRR call and use strong UC to protect the MMIO region and account for the device's architecture and MTRR size requirements. The atyfb driver relies on two overlapping MTRRs. It does this to account for the fact that, on some devices, it has the MMIO region bundled together with the framebuffer on the same PCI BAR and the hardware requirement on MTRRs on both base and size to be powers of two. In the worst case, the PCI BAR is of 16 MiB while the MMIO region is on the last 4 KiB of the same PCI BAR. If we use just one MTRR for WC, we can only end up with an 8 MiB or 16 MiB framebuffer. Using a 16 MiB WC framebuffer area is unacceptable since we need the MMIO region to not be write-combined. An 8 MiB WC framebuffer option does not let use quite a bit of framebuffer space, it would reduce the resolution capability of the device considerably. An alternative is to use many MTRRs but on some systems that could mean not having enough MTRRs to cover the framebuffer. The current solution is to issue a 16 MiB WC MTRR followed by a 4 KiB UC MTRR on the last 4 KiB. Its worth mentioning and documenting that the current ioremap*() strategy as well: the first ioremap() is used only for the MMIO region, a second ioremap() call is used for the framebuffer *and* the MMIO region, the MMIO region then ends up mmapped twice. Two ioremap() calls are used since in some situations the framebuffer actually ends up on a separate auxiliary PCI BAR, but this is not always true. In the worst case, the PCI BAR is shared for both MMIO and the framebuffer. By allowing overlapping ioremap() calls, the driver enables two types of devices with one simple ioremap() strategy. See also: 2f9e897353fc ("x86/mm/mtrr, pat: Document Write Combining MTRR type effects on PAT / non-PAT pages") By default, Linux today defaults both pci_mmap_page_range() and ioremap_nocache() to use _PAGE_CACHE_MODE_UC_MINUS. On x86, ioremap() aliases ioremap_nocache(). The preferred value for Linux may soon change, however, the goal is to use _PAGE_CACHE_MODE_UC by default in the future. We can use ioremap_uc() to set PCD=1, PWT=1 on non-PAT systems and use a PAT value of UC for PAT systems. This will ensure the same settings are in place regardless of what Linux decides to use by default later and to not regress our MTRR strategy since the effective memory type will differ depending on the value used. Using a WC MTRR on such an area will be nullified. This technique can be used to protect the MMIO region in this driver's case and address the restrictions of the device's architecture as well as restrictions set upon us by powers of 2 when using MTRRs. This allows us to replace the two MTRR calls with a single 16 MiB WC MTRR and use page-attribute settings for non-PAT and PAT entry values for PAT systems to ensure the appropriate effective memory type won't have a write-combining effect on the MMIO region on both non-PAT and PAT systems. The framebuffer area will be sure to get the write-combined effective memory type by white-listing it with ioremap_wc(). We ensure the desired effective memory types are set by: 0) Using one ioremap_uc() for the MMIO region alone. This will set the page attribute settings for the MMIO region to PCD=1, PWT=1 for non-PAT systems while using a strong UC value on PAT systems. 1) Fixing the framebuffer ioremapped area to exclude the MMIO region and using ioremap_wc() instead to whitelist the area we want for write-combining. In both cases, an implementation defined (as per 2f9e897353fc) effective memory type of WC is used for the framebuffer for non-PAT systems. Signed-off-by: Luis R. Rodriguez Signed-off-by: Borislav Petkov Cc: Andrew Morton Cc: Andrzej Hajda Cc: Andy Lutomirski Cc: Antonino Daplas Cc: Daniel Vetter Cc: Dave Airlie Cc: Davidlohr Bueso Cc: H. Peter Anvin Cc: Jean-Christophe Plagniol-Villard Cc: Juergen Gross Cc: Linus Torvalds Cc: Mathias Krause Cc: Mel Gorman Cc: Peter Zijlstra Cc: Rob Clark Cc: Suresh Siddha Cc: Thomas Gleixner Cc: Tomi Valkeinen Cc: Toshi Kani Cc: Ville Syrjälä Cc: Vlastimil Babka Cc: arnd@arndb.de Cc: benh@kernel.crashing.org Cc: dan.j.williams@intel.com Cc: geert@linux-m68k.org Cc: hch@lst.de Cc: hmh@hmh.eng.br Cc: linux-fbdev@vger.kernel.org Cc: linux-mm@kvack.org Cc: linux-pci@vger.kernel.org Cc: mpe@ellerman.id.au Cc: mst@redhat.com Cc: ralf@linux-mips.org Cc: ross.zwisler@linux.intel.com Cc: stefan.bader@canonical.com Cc: tj@kernel.org Cc: ville.syrjala@linux.intel.com Link: http://lkml.kernel.org/r/1435196060-27350-3-git-send-email-mcgrof@do-not-panic.com Link: http://lkml.kernel.org/r/1436491499-3289-4-git-send-email-mcgrof@do-not-panic.com Signed-off-by: Ingo Molnar --- drivers/video/fbdev/aty/atyfb.h | 1 - drivers/video/fbdev/aty/atyfb_base.c | 36 ++++++++++++++---------------------- 2 files changed, 14 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbdev/aty/atyfb.h b/drivers/video/fbdev/aty/atyfb.h index 1f39a62f899b..89ec4398d201 100644 --- a/drivers/video/fbdev/aty/atyfb.h +++ b/drivers/video/fbdev/aty/atyfb.h @@ -184,7 +184,6 @@ struct atyfb_par { spinlock_t int_lock; #ifdef CONFIG_MTRR int mtrr_aper; - int mtrr_reg; #endif u32 mem_cntl; struct crtc saved_crtc; diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index de8f7e082c87..7770a8485fb5 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -2630,21 +2630,13 @@ static int aty_init(struct fb_info *info) #ifdef CONFIG_MTRR par->mtrr_aper = -1; - par->mtrr_reg = -1; if (!nomtrr) { - /* Cover the whole resource. */ + /* + * Only the ioremap_wc()'d area will get WC here + * since ioremap_uc() was used on the entire PCI BAR. + */ par->mtrr_aper = mtrr_add(par->res_start, par->res_size, MTRR_TYPE_WRCOMB, 1); - if (par->mtrr_aper >= 0 && !par->aux_start) { - /* Make a hole for mmio. */ - par->mtrr_reg = mtrr_add(par->res_start + 0x800000 - - GUI_RESERVE, GUI_RESERVE, - MTRR_TYPE_UNCACHABLE, 1); - if (par->mtrr_reg < 0) { - mtrr_del(par->mtrr_aper, 0, 0); - par->mtrr_aper = -1; - } - } } #endif @@ -2776,10 +2768,6 @@ aty_init_exit: par->pll_ops->set_pll(info, &par->saved_pll); #ifdef CONFIG_MTRR - if (par->mtrr_reg >= 0) { - mtrr_del(par->mtrr_reg, 0, 0); - par->mtrr_reg = -1; - } if (par->mtrr_aper >= 0) { mtrr_del(par->mtrr_aper, 0, 0); par->mtrr_aper = -1; @@ -3466,7 +3454,11 @@ static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info, } info->fix.mmio_start = raddr; - par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000); + /* + * By using strong UC we force the MTRR to never have an + * effect on the MMIO region on both non-PAT and PAT systems. + */ + par->ati_regbase = ioremap_uc(info->fix.mmio_start, 0x1000); if (par->ati_regbase == NULL) return -ENOMEM; @@ -3503,7 +3495,10 @@ static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info, */ info->fix.smem_len = 0x800000; - info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); + aty_fudge_framebuffer_len(info); + + info->screen_base = ioremap_wc(info->fix.smem_start, + info->fix.smem_len); if (info->screen_base == NULL) { ret = -ENOMEM; goto atyfb_setup_generic_fail; @@ -3575,6 +3570,7 @@ static int atyfb_pci_probe(struct pci_dev *pdev, return -ENOMEM; } par = info->par; + par->bus_type = PCI; info->fix = atyfb_fix; info->device = &pdev->dev; par->pci_id = pdev->device; @@ -3744,10 +3740,6 @@ static void atyfb_remove(struct fb_info *info) #endif #ifdef CONFIG_MTRR - if (par->mtrr_reg >= 0) { - mtrr_del(par->mtrr_reg, 0, 0); - par->mtrr_reg = -1; - } if (par->mtrr_aper >= 0) { mtrr_del(par->mtrr_aper, 0, 0); par->mtrr_aper = -1; -- cgit v1.3-6-gb490 From 7d89a3cb159aecb1b363ea50cb14c967ff83b5a6 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 9 Jul 2015 18:24:59 -0700 Subject: drivers/video/fbdev/atyfb: Use arch_phys_wc_add() and ioremap_wc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver uses strong UC for the MMIO region, and ioremap_wc() for the framebuffer to whitelist for the WC MTRR that can be changed to WC. On PAT systems we don't need the MTRR call so just use arch_phys_wc_add() there, this lets us remove all those ifdefs. Let's also be consistent and use ioremap_wc() for ATARI as well. There are a few motivations for this: a) Take advantage of PAT when available. b) Help bury MTRR code away, MTRR is architecture specific and on x86 it is being replaced by PAT. c) Help with the goal of eventually using _PAGE_CACHE_UC over _PAGE_CACHE_UC_MINUS on x86 on ioremap_nocache() (see commit de33c442e titled "x86 PAT: fix performance drop for glx, use UC minus for ioremap(), ioremap_nocache() and pci_mmap_page_range()"). The conversion done is expressed by the following Coccinelle SmPL patch, it additionally required manual intervention to address all the ifdeffery and removal of redundant things which arch_phys_wc_add() already addresses such as verbose message about when MTRR fails and doing nothing when we didn't get an MTRR: @ mtrr_found @ expression index, base, size; @@ -index = mtrr_add(base, size, MTRR_TYPE_WRCOMB, 1); +index = arch_phys_wc_add(base, size); @ mtrr_rm depends on mtrr_found @ expression mtrr_found.index, mtrr_found.base, mtrr_found.size; @@ -mtrr_del(index, base, size); +arch_phys_wc_del(index); @ mtrr_rm_zero_arg depends on mtrr_found @ expression mtrr_found.index; @@ -mtrr_del(index, 0, 0); +arch_phys_wc_del(index); @ mtrr_rm_fb_info depends on mtrr_found @ struct fb_info *info; expression mtrr_found.index; @@ -mtrr_del(index, info->fix.smem_start, info->fix.smem_len); +arch_phys_wc_del(index); @ ioremap_replace_nocache depends on mtrr_found @ struct fb_info *info; expression base, size; @@ -info->screen_base = ioremap_nocache(base, size); +info->screen_base = ioremap_wc(base, size); @ ioremap_replace_default depends on mtrr_found @ struct fb_info *info; expression base, size; @@ -info->screen_base = ioremap(base, size); +info->screen_base = ioremap_wc(base, size); Signed-off-by: Luis R. Rodriguez Signed-off-by: Borislav Petkov Cc: Andrew Morton Cc: Andrzej Hajda Cc: Andy Lutomirski Cc: Antonino Daplas Cc: Daniel Vetter Cc: Dave Airlie Cc: Davidlohr Bueso Cc: H. Peter Anvin Cc: Jean-Christophe Plagniol-Villard Cc: Juergen Gross Cc: Linus Torvalds Cc: Mathias Krause Cc: Mel Gorman Cc: Peter Zijlstra Cc: Rob Clark Cc: Suresh Siddha Cc: Thomas Gleixner Cc: Tomi Valkeinen Cc: Toshi Kani Cc: Ville Syrjälä Cc: Vlastimil Babka Cc: arnd@arndb.de Cc: benh@kernel.crashing.org Cc: dan.j.williams@intel.com Cc: geert@linux-m68k.org Cc: hch@lst.de Cc: hmh@hmh.eng.br Cc: linux-fbdev@vger.kernel.org Cc: linux-mm@kvack.org Cc: linux-pci@vger.kernel.org Cc: mpe@ellerman.id.au Cc: mst@redhat.com Cc: ralf@linux-mips.org Cc: ross.zwisler@linux.intel.com Cc: stefan.bader@canonical.com Cc: tj@kernel.org Cc: ville.syrjala@linux.intel.com Link: http://lkml.kernel.org/r/1436491499-3289-5-git-send-email-mcgrof@do-not-panic.com Signed-off-by: Ingo Molnar --- drivers/video/fbdev/aty/atyfb.h | 4 +--- drivers/video/fbdev/aty/atyfb_base.c | 36 +++++++----------------------------- 2 files changed, 8 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbdev/aty/atyfb.h b/drivers/video/fbdev/aty/atyfb.h index 89ec4398d201..63c4842eb224 100644 --- a/drivers/video/fbdev/aty/atyfb.h +++ b/drivers/video/fbdev/aty/atyfb.h @@ -182,9 +182,7 @@ struct atyfb_par { unsigned long irq_flags; unsigned int irq; spinlock_t int_lock; -#ifdef CONFIG_MTRR - int mtrr_aper; -#endif + int wc_cookie; u32 mem_cntl; struct crtc saved_crtc; union aty_pll saved_pll; diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c index 7770a8485fb5..f34ed47fcaf8 100644 --- a/drivers/video/fbdev/aty/atyfb_base.c +++ b/drivers/video/fbdev/aty/atyfb_base.c @@ -98,9 +98,6 @@ #ifdef CONFIG_PMAC_BACKLIGHT #include #endif -#ifdef CONFIG_MTRR -#include -#endif /* * Debug flags. @@ -303,9 +300,7 @@ static struct fb_ops atyfb_ops = { }; static bool noaccel; -#ifdef CONFIG_MTRR static bool nomtrr; -#endif static int vram; static int pll; static int mclk; @@ -2628,17 +2623,13 @@ static int aty_init(struct fb_info *info) aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par); -#ifdef CONFIG_MTRR - par->mtrr_aper = -1; - if (!nomtrr) { + if (!nomtrr) /* * Only the ioremap_wc()'d area will get WC here * since ioremap_uc() was used on the entire PCI BAR. */ - par->mtrr_aper = mtrr_add(par->res_start, par->res_size, - MTRR_TYPE_WRCOMB, 1); - } -#endif + par->wc_cookie = arch_phys_wc_add(par->res_start, + par->res_size); info->fbops = &atyfb_ops; info->pseudo_palette = par->pseudo_palette; @@ -2766,13 +2757,8 @@ aty_init_exit: /* restore video mode */ aty_set_crtc(par, &par->saved_crtc); par->pll_ops->set_pll(info, &par->saved_pll); + arch_phys_wc_del(par->wc_cookie); -#ifdef CONFIG_MTRR - if (par->mtrr_aper >= 0) { - mtrr_del(par->mtrr_aper, 0, 0); - par->mtrr_aper = -1; - } -#endif return ret; } @@ -3672,7 +3658,8 @@ static int __init atyfb_atari_probe(void) * Map the video memory (physical address given) * to somewhere in the kernel address space. */ - info->screen_base = ioremap(phys_vmembase[m64_num], phys_size[m64_num]); + info->screen_base = ioremap_wc(phys_vmembase[m64_num], + phys_size[m64_num]); info->fix.smem_start = (unsigned long)info->screen_base; /* Fake! */ par->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000) + 0xFC00ul; @@ -3738,13 +3725,8 @@ static void atyfb_remove(struct fb_info *info) if (M64_HAS(MOBIL_BUS)) aty_bl_exit(info->bl_dev); #endif + arch_phys_wc_del(par->wc_cookie); -#ifdef CONFIG_MTRR - if (par->mtrr_aper >= 0) { - mtrr_del(par->mtrr_aper, 0, 0); - par->mtrr_aper = -1; - } -#endif #ifndef __sparc__ if (par->ati_regbase) iounmap(par->ati_regbase); @@ -3860,10 +3842,8 @@ static int __init atyfb_setup(char *options) while ((this_opt = strsep(&options, ",")) != NULL) { if (!strncmp(this_opt, "noaccel", 7)) { noaccel = 1; -#ifdef CONFIG_MTRR } else if (!strncmp(this_opt, "nomtrr", 6)) { nomtrr = 1; -#endif } else if (!strncmp(this_opt, "vram:", 5)) vram = simple_strtoul(this_opt + 5, NULL, 0); else if (!strncmp(this_opt, "pll:", 4)) @@ -4033,7 +4013,5 @@ module_param(comp_sync, int, 0); MODULE_PARM_DESC(comp_sync, "Set composite sync signal to low (0) or high (1)"); module_param(mode, charp, 0); MODULE_PARM_DESC(mode, "Specify resolution as \"x[-][@]\" "); -#ifdef CONFIG_MTRR module_param(nomtrr, bool, 0); MODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers"); -#endif -- cgit v1.3-6-gb490 From 1f2112af11e4c330cd070464e95ba9f546b8959b Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Jul 2015 10:30:42 +0200 Subject: spi: mpc512x-psc: fix compiler warning about uninitialized variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes several warnings like: drivers/spi/spi-mpc512x-psc.c: In function 'mpc512x_psc_spi_prep_xfer_hw': arch/powerpc/include/asm/io.h:163:2: warning: '__ret' may be used uninitialized in this function [-Wmaybe-uninitialized] introduced in commit 8bf960985dfc for some build configurations. Fixes: 8bf960985dfc ("spi: mpc512x-psc: add support for Freescale MPC5125") Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown --- drivers/spi/spi-mpc512x-psc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 280794dd248a..1e75341689a6 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -40,8 +40,8 @@ enum { * MPC5121 (which uses a struct mpc52xx_psc) and MPC5125 (using mpc5125_psc). */ #define psc_addr(mps, regname) ({ \ - void *__ret; \ - switch(mps->type) { \ + void *__ret = NULL; \ + switch (mps->type) { \ case TYPE_MPC5121: { \ struct mpc52xx_psc __iomem *psc = mps->psc; \ __ret = &psc->regname; \ -- cgit v1.3-6-gb490 From 3cf080a7b747d800efc231d29bd3a07659c6aeb6 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Mon, 20 Jul 2015 17:18:27 -0700 Subject: crypto: qat - fix invalid check for RSA keylen in fips mode The condition checking allowed key length was invalid. Reported-by: Dan Carpenter Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/qat_asym_algs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c index 13a76a0325ed..557a7408710d 100644 --- a/drivers/crypto/qat/qat_common/qat_asym_algs.c +++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c @@ -443,7 +443,7 @@ int qat_rsa_get_n(void *context, size_t hdrlen, unsigned char tag, ctx->key_sz = vlen; ret = -EINVAL; /* In FIPS mode only allow key size 2K & 3K */ - if (fips_enabled && (ctx->key_sz != 256 || ctx->key_sz != 384)) { + if (fips_enabled && (ctx->key_sz != 256 && ctx->key_sz != 384)) { pr_err("QAT: RSA: key size not allowed in FIPS mode\n"); goto err; } @@ -510,7 +510,7 @@ int qat_rsa_get_d(void *context, size_t hdrlen, unsigned char tag, goto err; /* In FIPS mode only allow key size 2K & 3K */ - if (fips_enabled && (vlen != 256 || vlen != 384)) { + if (fips_enabled && (vlen != 256 && vlen != 384)) { pr_err("QAT: RSA: key size not allowed in FIPS mode\n"); goto err; } -- cgit v1.3-6-gb490 From 80b2089b4a0b08ff34619a8e07fc74a63b4e2d24 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sat, 20 Jun 2015 03:28:15 +0900 Subject: rtlwifi: rtl8192cu: Remove rtl8723 code In the rtlwifi/rtl8192cu, rtl8723 code is dead code. So I remove it. Signed-off-by: Taehee Yoo Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/def.h | 9 --------- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 16 +--------------- drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | 12 ------------ 3 files changed, 1 insertion(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h index c940a87175ca..74a479ac323d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h @@ -32,24 +32,15 @@ /*------------------------------------------------------------------------- * Chip specific *-------------------------------------------------------------------------*/ -#define CHIP_8723 BIT(2) /* RTL8723 With BT feature */ -#define CHIP_8723_DRV_REV BIT(3) /* RTL8723 Driver Revised */ #define NORMAL_CHIP BIT(4) #define CHIP_VENDOR_UMC BIT(5) #define CHIP_VENDOR_UMC_B_CUT BIT(6) -#define IS_8723_SERIES(version) \ - (((version) & CHIP_8723) ? true : false) - #define IS_92C_1T2R(version) \ (((version) & CHIP_92C) && ((version) & CHIP_92C_1T2R)) #define IS_VENDOR_UMC(version) \ (((version) & CHIP_VENDOR_UMC) ? true : false) -#define IS_VENDOR_8723_A_CUT(version) \ - (((version) & CHIP_VENDOR_UMC) ? (((version) & (BIT(6))) ? \ - false : true) : false) - #define CHIP_BONDING_92C_1T2R 0x1 #define CHIP_BONDING_IDENTIFIER(_value) (((_value) >> 22) & 0x3) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 767358a553fb..7cf36619f250 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -2280,7 +2280,6 @@ bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate; u8 u1tmp = 0; bool actuallyset = false; @@ -2357,20 +2356,7 @@ bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) if (ppsc->pwrdown_mode && e_rfpowerstate_toset == ERFOFF) { /* Enable register area 0x0-0xc. */ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0); - if (IS_HARDWARE_TYPE_8723U(rtlhal)) { - /* - * We should configure HW PDn source for WiFi - * ONLY, and then our HW will be set in - * power-down mode if PDn source from all - * functions are configured. - */ - u1tmp = rtl_read_byte(rtlpriv, - REG_MULTI_FUNC_CTRL); - rtl_write_byte(rtlpriv, REG_MULTI_FUNC_CTRL, - (u1tmp|WL_HWPDN_EN)); - } else { - rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x8812); - } + rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x8812); } if (e_rfpowerstate_toset == ERFOFF) { if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 490a7cf7c702..1c55a002d4bd 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -69,8 +69,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) chip_version = NORMAL_CHIP; chip_version |= ((value32 & TYPE_ID) ? CHIP_92C : 0); chip_version |= ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0); - /* RTL8723 with BT function. */ - chip_version |= ((value32 & BT_FUNC) ? CHIP_8723 : 0); if (IS_VENDOR_UMC(chip_version)) chip_version |= ((value32 & CHIP_VER_RTL_MASK) ? CHIP_VENDOR_UMC_B_CUT : 0); @@ -78,10 +76,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) value32 = rtl_read_dword(rtlpriv, REG_HPON_FSM); chip_version |= ((CHIP_BONDING_IDENTIFIER(value32) == CHIP_BONDING_92C_1T2R) ? CHIP_92C_1T2R : 0); - } else if (IS_8723_SERIES(chip_version)) { - value32 = rtl_read_dword(rtlpriv, REG_GPIO_OUTSTS); - chip_version |= ((value32 & RF_RL_ID) ? - CHIP_8723_DRV_REV : 0); } } rtlhal->version = (enum version_8192c)chip_version; @@ -114,12 +108,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) case VERSION_NORMAL_UMC_CHIP_88C_B_CUT: versionid = "NORMAL_UMC_CHIP_88C_B_CUT"; break; - case VERSION_NORMA_UMC_CHIP_8723_1T1R_A_CUT: - versionid = "NORMAL_UMC_CHIP_8723_1T1R_A_CUT"; - break; - case VERSION_NORMA_UMC_CHIP_8723_1T1R_B_CUT: - versionid = "NORMAL_UMC_CHIP_8723_1T1R_B_CUT"; - break; case VERSION_TEST_CHIP_92C: versionid = "TEST_CHIP_92C"; break; -- cgit v1.3-6-gb490 From 4e6ee91bb728a268b37c74e2dd083481bf5ebb98 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:07 +0530 Subject: mwifiex: add tx data pause support This patch adds support to enable TX data pause feature for mwifiex. Whenever FW TX buffers reach threshold, FW would send TX pause event to driver. Driver in turn would block data traffic to that particular receiver address. Signed-off-by: Avinash Patil Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 9 +++++ drivers/net/wireless/mwifiex/main.h | 3 ++ drivers/net/wireless/mwifiex/sta_event.c | 66 ++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.c | 38 ++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.h | 2 + 5 files changed, 118 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index cd09051710e6..8ab0d81e6437 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -169,6 +169,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_UAP_PS_AO_TIMER (PROPRIETARY_TLV_BASE_ID + 123) #define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145) #define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146) +#define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 148) #define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) #define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194) @@ -509,6 +510,7 @@ enum P2P_MODES { #define EVENT_TDLS_GENERIC_EVENT 0x00000052 #define EVENT_RADAR_DETECTED 0x00000053 #define EVENT_CHANNEL_REPORT_RDY 0x00000054 +#define EVENT_TX_DATA_PAUSE 0x00000055 #define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f #define EVENT_TX_STATUS_REPORT 0x00000074 @@ -1131,6 +1133,13 @@ struct host_cmd_ds_tx_rate_query { u8 ht_info; } __packed; +struct mwifiex_tx_pause_tlv { + struct mwifiex_ie_types_header header; + u8 peermac[ETH_ALEN]; + u8 tx_pause; + u8 pkt_cnt; +} __packed; + enum Host_Sleep_Action { HS_CONFIGURE = 0x0001, HS_ACTIVATE = 0x0002, diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index ae98b5b83b1f..2106a5c24692 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -281,6 +281,7 @@ struct mwifiex_ra_list_tbl { u8 amsdu_in_ampdu; u16 total_pkt_count; bool tdls_link; + bool tx_paused; }; struct mwifiex_tid_tbl { @@ -294,6 +295,7 @@ struct mwifiex_tid_tbl { struct mwifiex_wmm_desc { struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; u32 packets_out[MAX_NUM_TID]; + u32 pkts_paused[MAX_NUM_TID]; /* spin lock to protect ra_list */ spinlock_t ra_list_spinlock; struct mwifiex_wmm_ac_status ac_status[IEEE80211_NUM_ACS]; @@ -768,6 +770,7 @@ struct mwifiex_sta_node { u8 tdls_status; struct mwifiex_tdls_capab tdls_cap; struct mwifiex_station_stats stats; + u8 tx_pause; }; struct mwifiex_auto_tdls_peer { diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 848de2621958..0a80814ddbb0 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -182,6 +182,67 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, return ret; } +static void +mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_ie_types_header *tlv; + struct mwifiex_tx_pause_tlv *tp_tlv; + struct mwifiex_sta_node *sta_ptr; + unsigned long flags; + u16 tlv_type, tlv_len; + int tlv_buf_left, status; + + if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return; + + if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) + return; + + tlv_buf_left = event_skb->len - sizeof(u32); + tlv = (void *)event_skb->data + sizeof(u32); + while (tlv_buf_left >= (int)sizeof(struct mwifiex_ie_types_header)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_len = le16_to_cpu(tlv->len); + if ((sizeof(struct mwifiex_ie_types_header) + tlv_len) > + tlv_buf_left) { + mwifiex_dbg(priv->adapter, ERROR, + "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", + tlv_len, tlv_buf_left); + break; + } + if (tlv_type == TLV_TYPE_TX_PAUSE) { + tp_tlv = (void *)tlv; + mwifiex_dbg(priv->adapter, ERROR, + "TxPause: %pM pause=%d, pkts=%d\n", + tp_tlv->peermac, tp_tlv->tx_pause, + tp_tlv->pkt_cnt); + status = mwifiex_get_tdls_link_status + (priv, tp_tlv->peermac); + if (status == TDLS_SETUP_COMPLETE) { + spin_lock_irqsave(&priv->sta_list_spinlock, + flags); + sta_ptr = mwifiex_get_sta_entry + (priv, tp_tlv->peermac); + spin_unlock_irqrestore(&priv->sta_list_spinlock, + flags); + if (sta_ptr && sta_ptr->tx_pause != + tp_tlv->tx_pause) { + sta_ptr->tx_pause = tp_tlv->tx_pause; + mwifiex_update_ralist_tx_pause + (priv, tp_tlv->peermac, + tp_tlv->tx_pause); + } + } + } + + tlv_buf_left -= sizeof(struct mwifiex_ie_types_header) + + tlv_len; + tlv = (void *)((u8 *)tlv + tlv_len + + sizeof(struct mwifiex_ie_types_header)); + } +} + /* * This function handles coex events generated by firmware */ @@ -573,6 +634,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) ret = mwifiex_parse_tdls_event(priv, adapter->event_skb); break; + case EVENT_TX_DATA_PAUSE: + mwifiex_process_sta_tx_pause_event(priv, adapter->event_skb); + mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); + break; + case EVENT_TX_STATUS_REPORT: mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n"); mwifiex_parse_tx_status_event(priv, adapter->event_body); diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index a8ea21c3340c..bc920a5a947c 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -160,6 +160,7 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra) ra_list->tdls_link = false; ra_list->ba_status = BA_SETUP_NONE; ra_list->amsdu_in_ampdu = false; + ra_list->tx_paused = false; if (!mwifiex_queuing_ra_based(priv)) { if (mwifiex_get_tdls_link_status(priv, ra) == TDLS_SETUP_COMPLETE) { @@ -603,6 +604,43 @@ mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, return NULL; } +void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, + u8 tx_pause) +{ + struct mwifiex_ra_list_tbl *ra_list; + u32 pkt_cnt = 0, tx_pkts_queued; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + for (i = 0; i < MAX_NUM_TID; ++i) { + ra_list = mwifiex_wmm_get_ralist_node(priv, i, mac); + if (ra_list && ra_list->tx_paused != tx_pause) { + pkt_cnt += ra_list->total_pkt_count; + ra_list->tx_paused = tx_pause; + if (tx_pause) + priv->wmm.pkts_paused[i] += + ra_list->total_pkt_count; + else + priv->wmm.pkts_paused[i] -= + ra_list->total_pkt_count; + } + } + + if (pkt_cnt) { + tx_pkts_queued = atomic_read(&priv->wmm.tx_pkts_queued); + if (tx_pause) + tx_pkts_queued -= pkt_cnt; + else + tx_pkts_queued += pkt_cnt; + + atomic_set(&priv->wmm.tx_pkts_queued, tx_pkts_queued); + atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); + } + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + /* * This function retrieves an RA list node for a given TID and * RA address pair. diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index 48ece0b35591..90edb8fc337d 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -126,6 +126,8 @@ struct mwifiex_ra_list_tbl * mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr); u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid); +void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, + u8 tx_pause); struct mwifiex_ra_list_tbl *mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr); -- cgit v1.3-6-gb490 From b5b0f272d618a470c34619b25f15ca4aa9d3b395 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:08 +0530 Subject: mwifiex: block data traffic to tx paused receive address Data traffic to tx paused receive address should be blocked. Signed-off-by: Xinming Hu Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/wmm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index bc920a5a947c..8a4dd248ff01 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1025,7 +1025,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, list_for_each_entry(ptr, &tid_ptr->ra_list, list) { - if (!skb_queue_empty(&ptr->skb_head)) + if (!ptr->tx_paused && + !skb_queue_empty(&ptr->skb_head)) /* holds both locks */ goto found; } -- cgit v1.3-6-gb490 From 9186a1f37d190f433c64558a4efeac7ed776b571 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:09 +0530 Subject: mwifiex: do not increase tx_pkts_queued if receive address tx paused If tx_pkts_queued is increased for tx paused receive address, tx process will be triggered for this packet. But since RA list was tx paused, there will be an infinite loop in mwifiex_wmm_process_tx waiting for the event(tx pause, tdls cs) to cancel tx pause. This will be an dead loop, since main_process was locked at this time, there will be no opportunity to process event. So do not increase tx_pkts_queued if receive address tx paused, this will be restored RA list is unpaused. Signed-off-by: Xinming Hu Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/wmm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 8a4dd248ff01..8e343b3f60e9 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -803,7 +803,10 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, atomic_set(&priv->wmm.highest_queued_prio, priv->tos_to_tid_inv[tid_down]); - atomic_inc(&priv->wmm.tx_pkts_queued); + if (ra_list->tx_paused) + priv->wmm.pkts_paused[tid_down]++; + else + atomic_inc(&priv->wmm.tx_pkts_queued); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } -- cgit v1.3-6-gb490 From ba101ad50a5024978f3f5007b4a6c20b304cdcbe Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:10 +0530 Subject: mwifiex: add tdls channel switch status This patch add new tdls status used for tdls channel switch. Driver in turn would block cmd path and data path if tdls channel switching. Data path to non tdls peer should be blocked if tdls channel switch to off-channel. Signed-off-by: Xinming Hu Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/decl.h | 3 ++ drivers/net/wireless/mwifiex/main.c | 14 +++++++-- drivers/net/wireless/mwifiex/main.h | 3 ++ drivers/net/wireless/mwifiex/util.c | 59 +++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 51e344789ba2..098e1f14dc9a 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -141,6 +141,9 @@ enum mwifiex_tdls_status { TDLS_SETUP_COMPLETE, TDLS_SETUP_FAILURE, TDLS_LINK_TEARDOWN, + TDLS_CHAN_SWITCHING, + TDLS_IN_BASE_CHAN, + TDLS_IN_OFF_CHAN, }; enum mwifiex_tdls_error_code { diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 3ba4e0e04223..2a2e5dbab8dd 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -299,9 +299,15 @@ process_start: if ((!adapter->scan_chan_gap_enabled && adapter->scan_processing) || adapter->data_sent || + mwifiex_is_tdls_chan_switching + (mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA)) || (mwifiex_wmm_lists_empty(adapter) && skb_queue_empty(&adapter->tx_data_q))) { if (adapter->cmd_sent || adapter->curr_cmd || + !mwifiex_is_send_cmd_allowed + (mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA)) || (!is_command_pending(adapter))) break; } @@ -342,7 +348,9 @@ process_start: continue; } - if (!adapter->cmd_sent && !adapter->curr_cmd) { + if (!adapter->cmd_sent && !adapter->curr_cmd && + mwifiex_is_send_cmd_allowed + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { if (mwifiex_exec_next_cmd(adapter) == -1) { ret = -1; break; @@ -365,7 +373,9 @@ process_start: if ((adapter->scan_chan_gap_enabled || !adapter->scan_processing) && - !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { + !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter) && + !mwifiex_is_tdls_chan_switching + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { mwifiex_wmm_process_tx(adapter); if (adapter->hs_activated) { adapter->is_hs_configured = false; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 2106a5c24692..d27e6aa63446 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1461,6 +1461,9 @@ struct mwifiex_sta_node * mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac); struct mwifiex_sta_node * mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac); +u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv); +u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv); +u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv); int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *extra_ies, diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 790e61953abf..2504e422364a 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -531,6 +531,65 @@ mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac) return NULL; } +static struct mwifiex_sta_node * +mwifiex_get_tdls_sta_entry(struct mwifiex_private *priv, u8 status) +{ + struct mwifiex_sta_node *node; + + list_for_each_entry(node, &priv->sta_list, list) { + if (node->tdls_status == status) + return node; + } + + return NULL; +} + +/* If tdls channel switching is on-going, tx data traffic should be + * blocked until the switching stage completed. + */ +u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv) +{ + struct mwifiex_sta_node *sta_ptr; + + if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return false; + + sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_CHAN_SWITCHING); + if (sta_ptr) + return true; + + return false; +} + +u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv) +{ + struct mwifiex_sta_node *sta_ptr; + + if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return false; + + sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_IN_OFF_CHAN); + if (sta_ptr) + return true; + + return false; +} + +/* If tdls channel switching is on-going or tdls operate on off-channel, + * cmd path should be blocked until tdls switched to base-channel. + */ +u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv) +{ + if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return true; + + if (mwifiex_is_tdls_chan_switching(priv) || + mwifiex_is_tdls_off_chan(priv)) + return false; + + return true; +} + /* This function will add a sta_node entry to associated station list * table with the given mac address. * If entry exist already, existing entry is returned. -- cgit v1.3-6-gb490 From f7669877e7ab1c5c7fddf268d57f016d97e48198 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:11 +0530 Subject: mwifiex: process tdls channel switch event This patch add support for tdls channel switch event process. We block TX queues for particular RA list depending upon channel switch state. If channel switch state is moving to base channel, we unblock RA lists for AP. If channel switch state is moving to off channel, we unblock TDLS peer RA lists. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 17 +++++++++- drivers/net/wireless/mwifiex/sta_event.c | 54 ++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.c | 45 ++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.h | 2 ++ 4 files changed, 117 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 8ab0d81e6437..0785e645341f 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -547,7 +547,14 @@ enum P2P_MODES { #define ACT_TDLS_DELETE 0x00 #define ACT_TDLS_CREATE 0x01 #define ACT_TDLS_CONFIG 0x02 -#define TDLS_EVENT_LINK_TEAR_DOWN 3 + +#define TDLS_EVENT_LINK_TEAR_DOWN 3 +#define TDLS_EVENT_CHAN_SWITCH_RESULT 7 +#define TDLS_EVENT_START_CHAN_SWITCH 8 +#define TDLS_EVENT_CHAN_SWITCH_STOPPED 9 + +#define TDLS_BASE_CHANNEL 0 +#define TDLS_OFF_CHANNEL 1 #define MWIFIEX_FW_V15 15 @@ -1936,10 +1943,18 @@ struct host_cmd_ds_802_11_subsc_evt { __le16 events; } __packed; +struct chan_switch_result { + u8 cur_chan; + u8 status; + u8 reason; +} __packed; + struct mwifiex_tdls_generic_event { __le16 type; u8 peer_mac[ETH_ALEN]; union { + struct chan_switch_result switch_result; + u8 cs_stop_reason; __le16 reason_code; __le16 reserved; } u; diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 0a80814ddbb0..0529b9a602d8 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -153,6 +153,7 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, struct mwifiex_sta_node *sta_ptr; struct mwifiex_tdls_generic_event *tdls_evt = (void *)event_skb->data + sizeof(adapter->event_cause); + u8 *mac = tdls_evt->peer_mac; /* reserved 2 bytes are not mandatory in tdls event */ if (event_skb->len < (sizeof(struct mwifiex_tdls_generic_event) - @@ -175,6 +176,59 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, le16_to_cpu(tdls_evt->u.reason_code), GFP_KERNEL); break; + case TDLS_EVENT_CHAN_SWITCH_RESULT: + mwifiex_dbg(adapter, EVENT, "tdls channel switch result :\n"); + mwifiex_dbg(adapter, EVENT, + "status=0x%x, reason=0x%x cur_chan=%d\n", + tdls_evt->u.switch_result.status, + tdls_evt->u.switch_result.reason, + tdls_evt->u.switch_result.cur_chan); + + /* tdls channel switch failed */ + if (tdls_evt->u.switch_result.status != 0) { + switch (tdls_evt->u.switch_result.cur_chan) { + case TDLS_BASE_CHANNEL: + sta_ptr->tdls_status = TDLS_IN_BASE_CHAN; + break; + case TDLS_OFF_CHANNEL: + sta_ptr->tdls_status = TDLS_IN_OFF_CHAN; + break; + default: + break; + } + return ret; + } + + /* tdls channel switch success */ + switch (tdls_evt->u.switch_result.cur_chan) { + case TDLS_BASE_CHANNEL: + if (sta_ptr->tdls_status == TDLS_IN_BASE_CHAN) + break; + mwifiex_update_ralist_tx_pause_in_tdls_cs(priv, mac, + false); + sta_ptr->tdls_status = TDLS_IN_BASE_CHAN; + break; + case TDLS_OFF_CHANNEL: + if (sta_ptr->tdls_status == TDLS_IN_OFF_CHAN) + break; + mwifiex_update_ralist_tx_pause_in_tdls_cs(priv, mac, + true); + sta_ptr->tdls_status = TDLS_IN_OFF_CHAN; + break; + default: + break; + } + + break; + case TDLS_EVENT_START_CHAN_SWITCH: + mwifiex_dbg(adapter, EVENT, "tdls start channel switch...\n"); + sta_ptr->tdls_status = TDLS_CHAN_SWITCHING; + break; + case TDLS_EVENT_CHAN_SWITCH_STOPPED: + mwifiex_dbg(adapter, EVENT, + "tdls chan switch stopped, reason=%d\n", + tdls_evt->u.cs_stop_reason); + break; default: break; } diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 8e343b3f60e9..21712cdcd95a 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -641,6 +641,51 @@ void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } +/* This function update non-tdls peer ralist tx_pause while + * tdls channel swithing + */ +void mwifiex_update_ralist_tx_pause_in_tdls_cs(struct mwifiex_private *priv, + u8 *mac, u8 tx_pause) +{ + struct mwifiex_ra_list_tbl *ra_list; + u32 pkt_cnt = 0, tx_pkts_queued; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + for (i = 0; i < MAX_NUM_TID; ++i) { + list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[i].ra_list, + list) { + if (!memcmp(ra_list->ra, mac, ETH_ALEN)) + continue; + + if (ra_list && ra_list->tx_paused != tx_pause) { + pkt_cnt += ra_list->total_pkt_count; + ra_list->tx_paused = tx_pause; + if (tx_pause) + priv->wmm.pkts_paused[i] += + ra_list->total_pkt_count; + else + priv->wmm.pkts_paused[i] -= + ra_list->total_pkt_count; + } + } + } + + if (pkt_cnt) { + tx_pkts_queued = atomic_read(&priv->wmm.tx_pkts_queued); + if (tx_pause) + tx_pkts_queued -= pkt_cnt; + else + tx_pkts_queued += pkt_cnt; + + atomic_set(&priv->wmm.tx_pkts_queued, tx_pkts_queued); + atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); + } + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + /* * This function retrieves an RA list node for a given TID and * RA address pair. diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index 90edb8fc337d..c12dd0e9f008 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -128,6 +128,8 @@ mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid); void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, u8 tx_pause); +void mwifiex_update_ralist_tx_pause_in_tdls_cs(struct mwifiex_private *priv, + u8 *mac, u8 tx_pause); struct mwifiex_ra_list_tbl *mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr); -- cgit v1.3-6-gb490 From 449b8bbf45e636a684c287f3008d13939aeac58b Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:12 +0530 Subject: mwifiex: add tdls config command This patch add support for a new tdls configuration command which is used for configuration of tdls channel switch parameters. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 45 +++++++++++++++++++++ drivers/net/wireless/mwifiex/main.h | 7 ++++ drivers/net/wireless/mwifiex/sta_cmd.c | 48 ++++++++++++++++++++++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 + drivers/net/wireless/mwifiex/tdls.c | 64 ++++++++++++++++++++++++++++++ 5 files changed, 166 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 0785e645341f..427e36357519 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -360,6 +360,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_MGMT_FRAME_REG 0x010c #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d #define HostCmd_CMD_11AC_CFG 0x0112 +#define HostCmd_CMD_TDLS_CONFIG 0x0100 #define HostCmd_CMD_TDLS_OPER 0x0122 #define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 @@ -556,6 +557,19 @@ enum P2P_MODES { #define TDLS_BASE_CHANNEL 0 #define TDLS_OFF_CHANNEL 1 +#define ACT_TDLS_CS_ENABLE_CONFIG 0x00 +#define ACT_TDLS_CS_INIT 0x06 +#define ACT_TDLS_CS_STOP 0x07 +#define ACT_TDLS_CS_PARAMS 0x08 + +#define MWIFIEX_DEF_CS_UNIT_TIME 2 +#define MWIFIEX_DEF_CS_THR_OTHERLINK 10 +#define MWIFIEX_DEF_THR_DIRECTLINK 0 +#define MWIFIEX_DEF_CS_TIME 10 +#define MWIFIEX_DEF_CS_TIMEOUT 16 +#define MWIFIEX_DEF_CS_REG_CLASS 12 +#define MWIFIEX_DEF_CS_PERIODICITY 1 + #define MWIFIEX_FW_V15 15 #define MWIFIEX_MASTER_RADAR_DET_MASK BIT(1) @@ -1265,6 +1279,36 @@ struct host_cmd_ds_tdls_oper { u8 peer_mac[ETH_ALEN]; } __packed; +struct mwifiex_tdls_config { + __le16 enable; +}; + +struct mwifiex_tdls_config_cs_params { + u8 unit_time; + u8 thr_otherlink; + u8 thr_directlink; +}; + +struct mwifiex_tdls_init_cs_params { + u8 peer_mac[ETH_ALEN]; + u8 primary_chan; + u8 second_chan_offset; + u8 band; + __le16 switch_time; + __le16 switch_timeout; + u8 reg_class; + u8 periodicity; +} __packed; + +struct mwifiex_tdls_stop_cs_params { + u8 peer_mac[ETH_ALEN]; +}; + +struct host_cmd_ds_tdls_config { + __le16 tdls_action; + u8 tdls_data[1]; +} __packed; + struct mwifiex_chan_desc { __le16 start_freq; u8 chan_width; @@ -2059,6 +2103,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_sta_list sta_list; struct host_cmd_11ac_vht_cfg vht_cfg; struct host_cmd_ds_coalesce_cfg coalesce_cfg; + struct host_cmd_ds_tdls_config tdls_config; struct host_cmd_ds_tdls_oper tdls_oper; struct host_cmd_ds_chan_rpt_req chan_rpt_req; struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index d27e6aa63446..da2275221c03 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1494,6 +1494,13 @@ void mwifiex_check_auto_tdls(unsigned long context); void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac); void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv); void mwifiex_clean_auto_tdls(struct mwifiex_private *priv); +int mwifiex_config_tdls_enable(struct mwifiex_private *priv); +int mwifiex_config_tdls_disable(struct mwifiex_private *priv); +int mwifiex_config_tdls_cs_params(struct mwifiex_private *priv); +int mwifiex_stop_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac); +int mwifiex_start_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac, + u8 primary_chan, u8 second_chan_offset, u8 band); + int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf); diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 037adcd1f484..82e6c6ec0b73 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1575,6 +1575,50 @@ mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv, return 0; } +static int +mwifiex_cmd_tdls_config(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_tdls_config *tdls_config = &cmd->params.tdls_config; + struct mwifiex_tdls_init_cs_params *config; + struct mwifiex_tdls_config *init_config; + u16 len; + + cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_CONFIG); + cmd->size = cpu_to_le16(S_DS_GEN); + tdls_config->tdls_action = cpu_to_le16(cmd_action); + le16_add_cpu(&cmd->size, sizeof(tdls_config->tdls_action)); + + switch (cmd_action) { + case ACT_TDLS_CS_ENABLE_CONFIG: + init_config = data_buf; + len = sizeof(*init_config); + memcpy(tdls_config->tdls_data, init_config, len); + break; + case ACT_TDLS_CS_INIT: + config = data_buf; + len = sizeof(*config); + memcpy(tdls_config->tdls_data, config, len); + break; + case ACT_TDLS_CS_STOP: + len = sizeof(struct mwifiex_tdls_stop_cs_params); + memcpy(tdls_config->tdls_data, data_buf, len); + break; + case ACT_TDLS_CS_PARAMS: + len = sizeof(struct mwifiex_tdls_config_cs_params); + memcpy(tdls_config->tdls_data, data_buf, len); + break; + default: + mwifiex_dbg(priv->adapter, ERROR, + "Unknown TDLS configuration\n"); + return -ENOTSUPP; + } + + le16_add_cpu(&cmd->size, len); + return 0; +} + static int mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, @@ -1958,6 +2002,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_TDLS_OPER: ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf); break; + case HostCmd_CMD_TDLS_CONFIG: + ret = mwifiex_cmd_tdls_config(priv, cmd_ptr, cmd_action, + data_buf); + break; case HostCmd_CMD_CHAN_REPORT_REQUEST: ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr, data_buf); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index b645884b3b97..6a85c774587a 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -1197,6 +1197,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp); break; + case HostCmd_CMD_TDLS_CONFIG: + break; default: mwifiex_dbg(adapter, ERROR, "CMD_RESP: unknown cmd response %#x\n", diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 2faa1bc42abe..03eabd705abe 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -1416,3 +1416,67 @@ void mwifiex_clean_auto_tdls(struct mwifiex_private *priv) mwifiex_flush_auto_tdls_list(priv); } } + +static int mwifiex_config_tdls(struct mwifiex_private *priv, u8 enable) +{ + struct mwifiex_tdls_config config; + + config.enable = cpu_to_le16(enable); + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_ENABLE_CONFIG, 0, &config, true); +} + +int mwifiex_config_tdls_enable(struct mwifiex_private *priv) +{ + return mwifiex_config_tdls(priv, true); +} + +int mwifiex_config_tdls_disable(struct mwifiex_private *priv) +{ + return mwifiex_config_tdls(priv, false); +} + +int mwifiex_config_tdls_cs_params(struct mwifiex_private *priv) +{ + struct mwifiex_tdls_config_cs_params config_tdls_cs_params; + + config_tdls_cs_params.unit_time = MWIFIEX_DEF_CS_UNIT_TIME; + config_tdls_cs_params.thr_otherlink = MWIFIEX_DEF_CS_THR_OTHERLINK; + config_tdls_cs_params.thr_directlink = MWIFIEX_DEF_THR_DIRECTLINK; + + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_PARAMS, 0, + &config_tdls_cs_params, true); +} + +int mwifiex_stop_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac) +{ + struct mwifiex_tdls_stop_cs_params stop_tdls_cs_params; + + ether_addr_copy(stop_tdls_cs_params.peer_mac, peer_mac); + + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_STOP, 0, + &stop_tdls_cs_params, true); +} + +int mwifiex_start_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac, + u8 primary_chan, u8 second_chan_offset, u8 band) +{ + struct mwifiex_tdls_init_cs_params start_tdls_cs_params; + + ether_addr_copy(start_tdls_cs_params.peer_mac, peer_mac); + start_tdls_cs_params.primary_chan = primary_chan; + start_tdls_cs_params.second_chan_offset = second_chan_offset; + start_tdls_cs_params.band = band; + + start_tdls_cs_params.switch_time = cpu_to_le16(MWIFIEX_DEF_CS_TIME); + start_tdls_cs_params.switch_timeout = + cpu_to_le16(MWIFIEX_DEF_CS_TIMEOUT); + start_tdls_cs_params.reg_class = MWIFIEX_DEF_CS_REG_CLASS; + start_tdls_cs_params.periodicity = MWIFIEX_DEF_CS_PERIODICITY; + + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_INIT, 0, + &start_tdls_cs_params, true); +} -- cgit v1.3-6-gb490 From 20834343a8e6a9a1e90d47810f6fe991f1e3362a Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:13 +0530 Subject: mwifiex: enable tdls channel switch ext_cap This patch enable tdls channel switch ext capability in tdls action frame, and also configure basic tdls channel switch parameters while tdls setup completed and tdls link is enabled.. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/tdls.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 03eabd705abe..f862ca63506c 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -355,6 +355,7 @@ static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv, extcap->ieee_hdr.len = 8; memset(extcap->ext_capab, 0, 8); extcap->ext_capab[4] |= WLAN_EXT_CAPA5_TDLS_ENABLED; + extcap->ext_capab[3] |= WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH; if (priv->adapter->is_hw_11ac_capable) extcap->ext_capab[7] |= WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED; @@ -1071,6 +1072,11 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer) for (i = 0; i < MAX_NUM_TID; i++) sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED; } + if (sta_ptr->tdls_cap.extcap.ext_capab[3] & + WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) { + mwifiex_config_tdls_enable(priv); + mwifiex_config_tdls_cs_params(priv); + } memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq)); mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE); -- cgit v1.3-6-gb490 From 55a2c0770634a08009229aaf23cda885d2e4359e Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:14 +0530 Subject: mwifiex: enhance tdls link setup condition TDLS link status - channel switching, off channel or base channel itself indicates that TDLS link is setup. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.h | 15 +++++++++++++++ drivers/net/wireless/mwifiex/sta_event.c | 2 +- drivers/net/wireless/mwifiex/tdls.c | 8 ++++---- drivers/net/wireless/mwifiex/wmm.c | 7 +++++-- 4 files changed, 25 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index da2275221c03..0e6ebc9001c3 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1333,6 +1333,21 @@ static inline u8 mwifiex_is_any_intf_active(struct mwifiex_private *priv) return 0; } +static inline u8 mwifiex_is_tdls_link_setup(u8 status) +{ + switch (status) { + case TDLS_SETUP_COMPLETE: + case TDLS_CHAN_SWITCHING: + case TDLS_IN_BASE_CHAN: + case TDLS_IN_OFF_CHAN: + return true; + default: + break; + } + + return false; +} + int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, u32 func_init_shutdown); int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 0529b9a602d8..f1045d41abee 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -273,7 +273,7 @@ mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, tp_tlv->pkt_cnt); status = mwifiex_get_tdls_link_status (priv, tp_tlv->peermac); - if (status == TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup(status)) { spin_lock_irqsave(&priv->sta_list_spinlock, flags); sta_ptr = mwifiex_get_sta_entry diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index f862ca63506c..aa3d3c5ed07b 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -49,7 +49,7 @@ static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv, tid = skb->priority; tid_down = mwifiex_wmm_downgrade_tid(priv, tid); - if (status == TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup(status)) { ra_list = mwifiex_wmm_get_queue_raptr(priv, tid, mac); ra_list->tdls_link = true; tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; @@ -1147,7 +1147,7 @@ int mwifiex_get_tdls_list(struct mwifiex_private *priv, spin_lock_irqsave(&priv->sta_list_spinlock, flags); list_for_each_entry(sta_ptr, &priv->sta_list, list) { - if (sta_ptr->tdls_status == TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup(sta_ptr->tdls_status)) { ether_addr_copy(peer->peer_addr, sta_ptr->mac_addr); peer++; count++; @@ -1301,7 +1301,7 @@ void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv, if ((link_status == TDLS_NOT_SETUP) && (peer->tdls_status == TDLS_SETUP_INPROGRESS)) peer->failure_count++; - else if (link_status == TDLS_SETUP_COMPLETE) + else if (mwifiex_is_tdls_link_setup(link_status)) peer->failure_count = 0; peer->tdls_status = link_status; @@ -1373,7 +1373,7 @@ void mwifiex_check_auto_tdls(unsigned long context) if (((tdls_peer->rssi >= MWIFIEX_TDLS_RSSI_LOW) || !tdls_peer->rssi) && - tdls_peer->tdls_status == TDLS_SETUP_COMPLETE) { + mwifiex_is_tdls_link_setup(tdls_peer->tdls_status)) { tdls_peer->tdls_status = TDLS_LINK_TEARDOWN; mwifiex_dbg(priv->adapter, MSG, "teardown TDLS link,peer=%pM rssi=%d\n", diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 21712cdcd95a..6196daad5a61 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -162,8 +162,8 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra) ra_list->amsdu_in_ampdu = false; ra_list->tx_paused = false; if (!mwifiex_queuing_ra_based(priv)) { - if (mwifiex_get_tdls_link_status(priv, ra) == - TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup + (mwifiex_get_tdls_link_status(priv, ra))) { ra_list->tdls_link = true; ra_list->is_11n_enabled = mwifiex_tdls_peer_11n_enabled(priv, ra); @@ -806,6 +806,9 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, !mwifiex_is_skb_mgmt_frame(skb)) { switch (tdls_status) { case TDLS_SETUP_COMPLETE: + case TDLS_CHAN_SWITCHING: + case TDLS_IN_BASE_CHAN: + case TDLS_IN_OFF_CHAN: ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; -- cgit v1.3-6-gb490 From b04975970676d797dec434755a14285420a4189f Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:15 +0530 Subject: mwifiex: add cfg80211 tdls channel switch handler This patch add cfg80211 tdls_chan_switch and tdls_cancel_chan_switch handler. With this handlers, mwifiex would support TDLS channel switch feature. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 72 +++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b15e4c7acbec..ecc8278a8cfe 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -19,6 +19,7 @@ #include "cfg80211.h" #include "main.h" +#include "11n.h" static char *reg_alpha2; module_param(reg_alpha2, charp, 0); @@ -3359,6 +3360,72 @@ mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, return mwifiex_tdls_oper(priv, peer, action); } +static int +mwifiex_cfg80211_tdls_chan_switch(struct wiphy *wiphy, struct net_device *dev, + const u8 *addr, u8 oper_class, + struct cfg80211_chan_def *chandef) +{ + struct mwifiex_sta_node *sta_ptr; + unsigned long flags; + u16 chan; + u8 second_chan_offset, band; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, addr); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (!sta_ptr) { + wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n", + __func__, addr); + return -ENOENT; + } + + if (!(sta_ptr->tdls_cap.extcap.ext_capab[3] & + WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH)) { + wiphy_err(wiphy, "%pM do not support tdls cs\n", addr); + return -ENOENT; + } + + if (sta_ptr->tdls_status == TDLS_CHAN_SWITCHING || + sta_ptr->tdls_status == TDLS_IN_OFF_CHAN) { + wiphy_err(wiphy, "channel switch is running, abort request\n"); + return -EALREADY; + } + + chan = chandef->chan->hw_value; + second_chan_offset = mwifiex_get_sec_chan_offset(chan); + band = chandef->chan->band; + mwifiex_start_tdls_cs(priv, addr, chan, second_chan_offset, band); + + return 0; +} + +static void +mwifiex_cfg80211_tdls_cancel_chan_switch(struct wiphy *wiphy, + struct net_device *dev, + const u8 *addr) +{ + struct mwifiex_sta_node *sta_ptr; + unsigned long flags; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, addr); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (!sta_ptr) { + wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n", + __func__, addr); + } else if (!(sta_ptr->tdls_status == TDLS_CHAN_SWITCHING || + sta_ptr->tdls_status == TDLS_IN_BASE_CHAN || + sta_ptr->tdls_status == TDLS_IN_OFF_CHAN)) { + wiphy_err(wiphy, "tdls chan switch not initialize by %pM\n", + addr); + } else + mwifiex_stop_tdls_cs(priv, addr); +} + static int mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac, struct station_parameters *params) @@ -3575,6 +3642,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .set_coalesce = mwifiex_cfg80211_set_coalesce, .tdls_mgmt = mwifiex_cfg80211_tdls_mgmt, .tdls_oper = mwifiex_cfg80211_tdls_oper, + .tdls_channel_switch = mwifiex_cfg80211_tdls_chan_switch, + .tdls_cancel_channel_switch = mwifiex_cfg80211_tdls_cancel_chan_switch, .add_station = mwifiex_cfg80211_add_station, .change_station = mwifiex_cfg80211_change_station, .get_channel = mwifiex_cfg80211_get_channel, @@ -3709,6 +3778,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) NL80211_FEATURE_INACTIVITY_TIMER | NL80211_FEATURE_NEED_OBSS_SCAN; + if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) + wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH; + if (adapter->fw_api_ver == MWIFIEX_FW_V15) wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; -- cgit v1.3-6-gb490 From 65d48e5971065ccb831a93232d60deb7caa9d7cb Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:16 +0530 Subject: mwifiex: update domain_info upon band change in start_ap It was observed that AP beacons would not reflect correct regulatory information upon starting AP in A band. This was because of missing AP config band update in set_channel of start_ap. Also we configure 11D settings info FW only for specific band. So we need to download domain info to FW even if domain remains unchanged but band is changed. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 2 +- drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/uap_cmd.c | 7 ++++++- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index ecc8278a8cfe..1d445cbbb31b 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -442,7 +442,7 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, * - Country codes * - Sub bands (first channel, number of channels, maximum Tx power) */ -static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) +int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) { u8 no_of_triplet = 0; struct ieee80211_country_ie_triplet *t; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 0e6ebc9001c3..d74ef2dd21bc 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1550,6 +1550,8 @@ void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags); void mwifiex_queue_main_work(struct mwifiex_adapter *adapter); void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter); void mwifiex_11n_delba(struct mwifiex_private *priv, int tid); +int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy); + #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); void mwifiex_debugfs_remove(void); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index b74930054b8c..4d5a6e3b6361 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -808,7 +808,7 @@ void mwifiex_uap_set_channel(struct mwifiex_private *priv, struct mwifiex_uap_bss_param *bss_cfg, struct cfg80211_chan_def chandef) { - u8 config_bands = 0; + u8 config_bands = 0, old_bands = priv->adapter->config_bands; priv->bss_chandef = chandef; @@ -834,6 +834,11 @@ void mwifiex_uap_set_channel(struct mwifiex_private *priv, } priv->adapter->config_bands = config_bands; + + if (old_bands != config_bands) { + mwifiex_send_domain_info_cmd_fw(priv->adapter->wiphy); + mwifiex_dnld_txpwr_table(priv); + } } int mwifiex_config_start_uap(struct mwifiex_private *priv, -- cgit v1.3-6-gb490 From a1777327126e184518e17e3c571540be72c73dce Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:17 +0530 Subject: mwifiex: support for bypass tx queue This patch adds support for another TX queue in driver- bypass TX queue. This queue is used for sending data/mgmt packets while in disconnected state i.e. when port is yet not unblocked. TDLS setup packets would also be queued in this queue. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 4 +++ drivers/net/wireless/mwifiex/init.c | 1 + drivers/net/wireless/mwifiex/main.c | 49 ++++++++++++++++++++++++++++-- drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/wmm.c | 53 +++++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.h | 4 +++ 6 files changed, 111 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 1d445cbbb31b..46f9dc2b1736 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2789,6 +2789,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); struct mwifiex_adapter *adapter = priv->adapter; + struct sk_buff *skb, *tmp; #ifdef CONFIG_DEBUG_FS mwifiex_dev_debugfs_remove(priv); @@ -2796,6 +2797,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) mwifiex_stop_net_dev_queue(priv->netdev, adapter); + skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) + mwifiex_write_data_complete(priv->adapter, skb, 0, -1); + if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index df7fdc09d38c..e1b62bf0f7b4 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -499,6 +499,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) INIT_LIST_HEAD(&priv->sta_list); INIT_LIST_HEAD(&priv->auto_tdls_list); skb_queue_head_init(&priv->tdls_txq); + skb_queue_head_init(&priv->bypass_txq); spin_lock_init(&priv->tx_ba_stream_tbl_lock); spin_lock_init(&priv->rx_reorder_tbl_lock); diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 2a2e5dbab8dd..278dc94eaecb 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -276,6 +276,7 @@ process_start: !adapter->pm_wakeup_fw_try) && (is_command_pending(adapter) || !skb_queue_empty(&adapter->tx_data_q) || + !mwifiex_bypass_txlist_empty(adapter) || !mwifiex_wmm_lists_empty(adapter))) { adapter->pm_wakeup_fw_try = true; mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3)); @@ -303,6 +304,7 @@ process_start: (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA)) || (mwifiex_wmm_lists_empty(adapter) && + mwifiex_bypass_txlist_empty(adapter) && skb_queue_empty(&adapter->tx_data_q))) { if (adapter->cmd_sent || adapter->curr_cmd || !mwifiex_is_send_cmd_allowed @@ -371,6 +373,22 @@ process_start: } } + if ((adapter->scan_chan_gap_enabled || + !adapter->scan_processing) && + !adapter->data_sent && + !mwifiex_bypass_txlist_empty(adapter) && + !mwifiex_is_tdls_chan_switching + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { + mwifiex_process_bypass_tx(adapter); + if (adapter->hs_activated) { + adapter->is_hs_configured = false; + mwifiex_hs_activated_event + (mwifiex_get_priv + (adapter, MWIFIEX_BSS_ROLE_ANY), + false); + } + } + if ((adapter->scan_chan_gap_enabled || !adapter->scan_processing) && !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter) && @@ -389,6 +407,7 @@ process_start: if (adapter->delay_null_pkt && !adapter->cmd_sent && !adapter->curr_cmd && !is_command_pending(adapter) && (mwifiex_wmm_lists_empty(adapter) && + mwifiex_bypass_txlist_empty(adapter) && skb_queue_empty(&adapter->tx_data_q))) { if (!mwifiex_send_null_packet (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), @@ -659,6 +678,26 @@ mwifiex_close(struct net_device *dev) return 0; } +static bool +mwifiex_bypass_tx_queue(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct ethhdr *eth_hdr = (struct ethhdr *)skb->data; + + if (ntohs(eth_hdr->h_proto) == ETH_P_PAE || + mwifiex_is_skb_mgmt_frame(skb) || + (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA && + ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && + (ntohs(eth_hdr->h_proto) == ETH_P_TDLS))) { + mwifiex_dbg(priv->adapter, DATA, + "bypass txqueue; eth type %#x, mgmt %d\n", + ntohs(eth_hdr->h_proto), + mwifiex_is_skb_mgmt_frame(skb)); + return true; + } + + return false; +} /* * Add buffer into wmm tx queue and queue work to transmit it. */ @@ -676,8 +715,14 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) } } - atomic_inc(&priv->adapter->tx_pending); - mwifiex_wmm_add_buf_txqueue(priv, skb); + if (mwifiex_bypass_tx_queue(priv, skb)) { + atomic_inc(&priv->adapter->tx_pending); + atomic_inc(&priv->adapter->bypass_tx_pending); + mwifiex_wmm_add_buf_bypass_txqueue(priv, skb); + } else { + atomic_inc(&priv->adapter->tx_pending); + mwifiex_wmm_add_buf_txqueue(priv, skb); + } mwifiex_queue_main_work(priv->adapter); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index d74ef2dd21bc..c59430e906ae 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -664,6 +664,7 @@ struct mwifiex_private { struct cfg80211_beacon_data beacon_after; struct mwifiex_11h_intf_state state_11h; struct mwifiex_ds_mem_rw mem_rw; + struct sk_buff_head bypass_txq; }; @@ -834,6 +835,7 @@ struct mwifiex_adapter { wait_queue_head_t init_wait_q; void *card; struct mwifiex_if_ops if_ops; + atomic_t bypass_tx_pending; atomic_t rx_pending; atomic_t tx_pending; atomic_t cmd_pending; diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 6196daad5a61..7995f92bc2d4 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -449,6 +449,11 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) } } +int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter) +{ + return atomic_read(&adapter->bypass_tx_pending) ? false : true; +} + /* * This function checks if WMM Tx queue is empty. */ @@ -581,6 +586,10 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) mwifiex_write_data_complete(priv->adapter, skb, 0, -1); + skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) + mwifiex_write_data_complete(priv->adapter, skb, 0, -1); + atomic_set(&priv->adapter->bypass_tx_pending, 0); + idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL); idr_destroy(&priv->ack_status_frames); } @@ -752,6 +761,18 @@ mwifiex_is_ralist_valid(struct mwifiex_private *priv, return false; } +/* + * This function adds a packet to bypass TX queue. + * This is special TX queue for packets which can be sent even when port_open + * is false. + */ +void +mwifiex_wmm_add_buf_bypass_txqueue(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + skb_queue_tail(&priv->bypass_txq, skb); +} + /* * This function adds a packet to WMM queue. * @@ -1429,6 +1450,38 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) return 0; } +void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter) +{ + struct mwifiex_tx_param tx_param; + struct sk_buff *skb; + struct mwifiex_txinfo *tx_info; + struct mwifiex_private *priv; + int i; + + if (adapter->data_sent || adapter->tx_lock_flag) + return; + + for (i = 0; i < adapter->priv_num; ++i) { + priv = adapter->priv[i]; + + if (skb_queue_empty(&priv->bypass_txq)) + continue; + + skb = skb_dequeue(&priv->bypass_txq); + tx_info = MWIFIEX_SKB_TXCB(skb); + + /* no aggregation for bypass packets */ + tx_param.next_pkt_len = 0; + + if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) { + skb_queue_head(&priv->bypass_txq, skb); + tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + } else { + atomic_dec(&adapter->bypass_tx_pending); + } + } +} + /* * This function transmits the highest priority packet awaiting in the * WMM Queues. diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index c12dd0e9f008..38f09762bd2f 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -99,12 +99,16 @@ mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead) void mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, struct sk_buff *skb); +void mwifiex_wmm_add_buf_bypass_txqueue(struct mwifiex_private *priv, + struct sk_buff *skb); void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra); void mwifiex_rotate_priolists(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ra, int tid); int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter); +int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter); void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter); +void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter); int mwifiex_is_ralist_valid(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ra_list, int tid); -- cgit v1.3-6-gb490 From 5c8946330abfa4c0476b94070d8833cfbbca5b28 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:18 +0530 Subject: mwifiex: enable traffic only when port is open This patch adds support to enable data traffic only when port is open. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/init.c | 2 +- drivers/net/wireless/mwifiex/join.c | 2 ++ drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 ++ drivers/net/wireless/mwifiex/sta_event.c | 4 +++- drivers/net/wireless/mwifiex/uap_event.c | 3 +++ drivers/net/wireless/mwifiex/wmm.c | 5 ++++- 7 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index e1b62bf0f7b4..8fa363add970 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -77,7 +77,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv) priv->media_connected = false; eth_broadcast_addr(priv->curr_addr); - + priv->port_open = false; priv->pkt_tx_ctrl = 0; priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; priv->data_rate = 0; /* Initially indicate the rate as auto */ diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 56b024a6aaa5..3cda1f956f0b 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -783,6 +783,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) priv->scan_block = true; + else + priv->port_open = true; done: /* Need to indicate IOCTL complete */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index c59430e906ae..6f98d7ea9338 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -519,6 +519,7 @@ struct mwifiex_private { u8 frame_type; u8 curr_addr[ETH_ALEN]; u8 media_connected; + u8 port_open; u32 num_tx_timeout; /* track consecutive timeout */ u8 tx_timeout_cnt; diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 6a85c774587a..18f269eaed60 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -599,6 +599,7 @@ static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv, "info: key: GTK is set\n"); priv->wpa_is_gtk_set = true; priv->scan_block = false; + priv->port_open = true; } } @@ -629,6 +630,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv, mwifiex_dbg(priv->adapter, INFO, "info: key: GTK is set\n"); priv->wpa_is_gtk_set = true; priv->scan_block = false; + priv->port_open = true; } } diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index f1045d41abee..72be16eca758 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -54,6 +54,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) priv->media_connected = false; priv->scan_block = false; + priv->port_open = false; if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) { @@ -474,7 +475,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_PS_AWAKE: mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n"); - if (!adapter->pps_uapsd_mode && + if (!adapter->pps_uapsd_mode && priv->port_open && priv->media_connected && adapter->sleep_period.period) { adapter->pps_uapsd_mode = true; mwifiex_dbg(adapter, EVENT, @@ -553,6 +554,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_PORT_RELEASE: mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n"); + priv->port_open = true; break; case EVENT_EXT_SCAN_REPORT: diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 7bc1f850e3b7..a412c3d4c365 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -176,6 +176,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) break; case EVENT_UAP_BSS_IDLE: priv->media_connected = false; + priv->port_open = false; if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); mwifiex_stop_net_dev_queue(priv->netdev, adapter); @@ -185,6 +186,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) break; case EVENT_UAP_BSS_ACTIVE: priv->media_connected = true; + priv->port_open = true; if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); @@ -192,6 +194,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) case EVENT_UAP_BSS_START: mwifiex_dbg(adapter, EVENT, "AP EVENT: event id: %#x\n", eventcause); + priv->port_open = false; memcpy(priv->netdev->dev_addr, adapter->event_body + 2, ETH_ALEN); if (priv->hist_data) diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 7995f92bc2d4..173d3663c2e0 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -465,6 +465,8 @@ mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; ++i) { priv = adapter->priv[i]; + if (priv && !priv->port_open) + continue; if (priv && atomic_read(&priv->wmm.tx_pkts_queued)) return false; } @@ -1080,7 +1082,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, priv_tmp = adapter->bss_prio_tbl[j].bss_prio_cur->priv; - if (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0) + if (!priv_tmp->port_open || + (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0)) continue; /* iterate over the WMM queues of the BSS */ -- cgit v1.3-6-gb490 From ddd7ceb3f6dd9071fd0e2058252d1fc4645313db Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:19 +0530 Subject: mwifiex: extend tx_data pause to AP interface as well This patch adds support to extend TX Data pause for AP intefaces. Also for station role, support for pausing/unpausing all traffic when mac address parameter is BSSID is added. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.h | 2 + drivers/net/wireless/mwifiex/sta_event.c | 121 ++++++++++++++++++++++--------- drivers/net/wireless/mwifiex/uap_event.c | 4 + 3 files changed, 93 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 6f98d7ea9338..6e82058c0eab 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1554,6 +1554,8 @@ void mwifiex_queue_main_work(struct mwifiex_adapter *adapter); void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter); void mwifiex_11n_delba(struct mwifiex_private *priv, int tid); int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy); +void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, + struct sk_buff *event); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 72be16eca758..a2777d16c98f 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -237,58 +237,110 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, return ret; } -static void -mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, - struct sk_buff *event_skb) +static void mwifiex_process_uap_tx_pause(struct mwifiex_private *priv, + struct mwifiex_ie_types_header *tlv) { - struct mwifiex_ie_types_header *tlv; - struct mwifiex_tx_pause_tlv *tp_tlv; + struct mwifiex_tx_pause_tlv *tp; struct mwifiex_sta_node *sta_ptr; unsigned long flags; - u16 tlv_type, tlv_len; - int tlv_buf_left, status; - if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) - return; + tp = (void *)tlv; + mwifiex_dbg(priv->adapter, EVENT, + "uap tx_pause: %pM pause=%d, pkts=%d\n", + tp->peermac, tp->tx_pause, + tp->pkt_cnt); + + if (ether_addr_equal(tp->peermac, priv->netdev->dev_addr)) { + if (tp->tx_pause) + priv->port_open = false; + else + priv->port_open = true; + } else if (is_multicast_ether_addr(tp->peermac)) { + mwifiex_update_ralist_tx_pause(priv, tp->peermac, tp->tx_pause); + } else { + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) { + sta_ptr->tx_pause = tp->tx_pause; + mwifiex_update_ralist_tx_pause(priv, tp->peermac, + tp->tx_pause); + } + } +} + +static void mwifiex_process_sta_tx_pause(struct mwifiex_private *priv, + struct mwifiex_ie_types_header *tlv) +{ + struct mwifiex_tx_pause_tlv *tp; + struct mwifiex_sta_node *sta_ptr; + int status; + unsigned long flags; + + tp = (void *)tlv; + mwifiex_dbg(priv->adapter, EVENT, + "sta tx_pause: %pM pause=%d, pkts=%d\n", + tp->peermac, tp->tx_pause, + tp->pkt_cnt); + + if (ether_addr_equal(tp->peermac, priv->cfg_bssid)) { + if (tp->tx_pause) + priv->port_open = false; + else + priv->port_open = true; + } else { + if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return; + + status = mwifiex_get_tdls_link_status(priv, tp->peermac); + if (mwifiex_is_tdls_link_setup(status)) { + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) { + sta_ptr->tx_pause = tp->tx_pause; + mwifiex_update_ralist_tx_pause(priv, + tp->peermac, + tp->tx_pause); + } + } + } +} + +void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_ie_types_header *tlv; + u16 tlv_type, tlv_len; + int tlv_buf_left; - if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) + if (!priv->media_connected) { + mwifiex_dbg(priv->adapter, ERROR, + "tx_pause event while disconnected; bss_role=%d\n", + priv->bss_role); return; + } tlv_buf_left = event_skb->len - sizeof(u32); tlv = (void *)event_skb->data + sizeof(u32); + while (tlv_buf_left >= (int)sizeof(struct mwifiex_ie_types_header)) { tlv_type = le16_to_cpu(tlv->type); tlv_len = le16_to_cpu(tlv->len); if ((sizeof(struct mwifiex_ie_types_header) + tlv_len) > - tlv_buf_left) { + tlv_buf_left) { mwifiex_dbg(priv->adapter, ERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len, tlv_buf_left); break; } if (tlv_type == TLV_TYPE_TX_PAUSE) { - tp_tlv = (void *)tlv; - mwifiex_dbg(priv->adapter, ERROR, - "TxPause: %pM pause=%d, pkts=%d\n", - tp_tlv->peermac, tp_tlv->tx_pause, - tp_tlv->pkt_cnt); - status = mwifiex_get_tdls_link_status - (priv, tp_tlv->peermac); - if (mwifiex_is_tdls_link_setup(status)) { - spin_lock_irqsave(&priv->sta_list_spinlock, - flags); - sta_ptr = mwifiex_get_sta_entry - (priv, tp_tlv->peermac); - spin_unlock_irqrestore(&priv->sta_list_spinlock, - flags); - if (sta_ptr && sta_ptr->tx_pause != - tp_tlv->tx_pause) { - sta_ptr->tx_pause = tp_tlv->tx_pause; - mwifiex_update_ralist_tx_pause - (priv, tp_tlv->peermac, - tp_tlv->tx_pause); - } - } + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) + mwifiex_process_sta_tx_pause(priv, tlv); + else + mwifiex_process_uap_tx_pause(priv, tlv); } tlv_buf_left -= sizeof(struct mwifiex_ie_types_header) + @@ -296,6 +348,7 @@ mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, tlv = (void *)((u8 *)tlv + tlv_len + sizeof(struct mwifiex_ie_types_header)); } + } /* @@ -691,8 +744,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) break; case EVENT_TX_DATA_PAUSE: - mwifiex_process_sta_tx_pause_event(priv, adapter->event_skb); mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); + mwifiex_process_tx_pause_event(priv, adapter->event_skb); break; case EVENT_TX_STATUS_REPORT: diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index a412c3d4c365..a9d34c619181 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -300,6 +300,10 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) mwifiex_bt_coex_wlan_param_update_event(priv, adapter->event_skb); break; + case EVENT_TX_DATA_PAUSE: + mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); + mwifiex_process_tx_pause_event(priv, adapter->event_skb); + break; default: mwifiex_dbg(adapter, EVENT, "event: unknown event id: %#x\n", eventcause); -- cgit v1.3-6-gb490 From d5b036c403f811c6d1856b8e6891a6438cf56f61 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:20 +0530 Subject: mwifiex: support to set multichannel policy to FW This patch adds support for setting multichannel policy as module parameter to FW. Value of 1 indicates Multichannel support is enabled and value of 0 disables it. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 8 ++++++++ drivers/net/wireless/mwifiex/sta_cmd.c | 31 ++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 1 + 3 files changed, 40 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 427e36357519..976b58587c27 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -201,6 +201,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) #define ISSUPP_TDLS_ENABLED(FwCapInfo) (FwCapInfo & BIT(14)) +#define ISSUPP_DRCS_ENABLED(FwCapInfo) (FwCapInfo & BIT(15)) #define ISSUPP_SDIO_SPA_ENABLED(FwCapInfo) (FwCapInfo & BIT(16)) #define MWIFIEX_DEF_HT_CAP (IEEE80211_HT_CAP_DSSSCCK40 | \ @@ -361,6 +362,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d #define HostCmd_CMD_11AC_CFG 0x0112 #define HostCmd_CMD_TDLS_CONFIG 0x0100 +#define HostCmd_CMD_MC_POLICY 0x0121 #define HostCmd_CMD_TDLS_OPER 0x0122 #define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 @@ -2039,6 +2041,11 @@ struct host_cmd_ds_coalesce_cfg { struct coalesce_receive_filt_rule rule[0]; } __packed; +struct host_cmd_ds_multi_chan_policy { + __le16 action; + __le16 policy; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -2107,6 +2114,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_tdls_oper tdls_oper; struct host_cmd_ds_chan_rpt_req chan_rpt_req; struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg; + struct host_cmd_ds_multi_chan_policy mc_policy; } params; } __packed; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 82e6c6ec0b73..f250b61a9ff7 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -26,6 +26,10 @@ #include "11n.h" #include "11ac.h" +static bool drcs; +module_param(drcs, bool, 0644); +MODULE_PARM_DESC(drcs, "multi-channel operation:1, single-channel operation:0"); + static bool disable_auto_ds; module_param(disable_auto_ds, bool, 0); MODULE_PARM_DESC(disable_auto_ds, @@ -1511,6 +1515,22 @@ static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv, return 0; } +static int +mwifiex_cmd_set_mc_policy(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_multi_chan_policy *mc_pol = &cmd->params.mc_policy; + const u16 *drcs_info = data_buf; + + mc_pol->action = cpu_to_le16(cmd_action); + mc_pol->policy = cpu_to_le16(*drcs_info); + cmd->command = cpu_to_le16(HostCmd_CMD_MC_POLICY); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_multi_chan_policy) + + S_DS_GEN); + return 0; +} + static int mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, @@ -2014,6 +2034,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action, data_buf); break; + case HostCmd_CMD_MC_POLICY: + ret = mwifiex_cmd_set_mc_policy(priv, cmd_ptr, cmd_action, + data_buf); + break; default: mwifiex_dbg(priv->adapter, ERROR, "PREP_CMD: unknown cmd- %#x\n", cmd_no); @@ -2130,6 +2154,13 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) if (ret) return -1; } + + if (ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) + ret = mwifiex_send_cmd(priv, HostCmd_CMD_MC_POLICY, + HostCmd_ACT_GEN_SET, 0, &drcs, + true); + if (ret) + return -1; } /* get tx rate */ diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 18f269eaed60..89e8dafb4738 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -1193,6 +1193,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_TDLS_OPER: ret = mwifiex_ret_tdls_oper(priv, resp); + case HostCmd_CMD_MC_POLICY: break; case HostCmd_CMD_CHAN_REPORT_REQUEST: break; -- cgit v1.3-6-gb490 From de9e9932b76d5458edabd2692d8ad6504501edf1 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:21 +0530 Subject: mwifiex: advertise multichannel support to cfg80211 This patch adds support to advetise mwifiex multichannel support to cfg80211. If module parameter drcs is enabled and FW supports multichannel operation we advertise this support to cfg80211. As of now 2 simultaneous channels are supported. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 14 +++++++++++++- drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/sta_cmd.c | 13 +++++++++---- 3 files changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 46f9dc2b1736..bc863e951140 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -43,6 +43,15 @@ static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = { .beacon_int_infra_match = true, }; +static const struct +ieee80211_iface_combination mwifiex_drcs_iface_comb_ap_sta = { + .limits = mwifiex_ap_sta_limits, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), + .max_interfaces = MWIFIEX_MAX_BSS_NUM, + .beacon_int_infra_match = true, +}; + /* * This function maps the nl802.11 channel type into driver channel type. * @@ -3745,7 +3754,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) else wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; - wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; + if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) + wiphy->iface_combinations = &mwifiex_drcs_iface_comb_ap_sta; + else + wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; wiphy->n_iface_combinations = 1; /* Initialize cipher suits */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 6e82058c0eab..f3264f2231d3 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -985,6 +985,7 @@ struct mwifiex_adapter { u8 coex_win_size; u8 coex_tx_win_size; u8 coex_rx_win_size; + bool drcs_enabled; }; void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index f250b61a9ff7..36cb6bdbe49b 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -2155,12 +2155,17 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) return -1; } - if (ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) - ret = mwifiex_send_cmd(priv, HostCmd_CMD_MC_POLICY, - HostCmd_ACT_GEN_SET, 0, &drcs, - true); + if (drcs) { + adapter->drcs_enabled = true; + if (ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) + ret = mwifiex_send_cmd(priv, + HostCmd_CMD_MC_POLICY, + HostCmd_ACT_GEN_SET, 0, + &adapter->drcs_enabled, + true); if (ret) return -1; + } } /* get tx rate */ -- cgit v1.3-6-gb490 From cc7359b5c82f67a1a19a0cf66f84f465403edb5d Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:22 +0530 Subject: mwifiex: separate interface combination for multichannel and DFS Multichannel and DFS cannot be supported at same time. So when multichannel operation is enabled by module parameter, we enable number of channel as 2 while registering wiphy. For all other cases we advertise DFS support to cfg80211. Patch also adds support for radar detect widths parameter. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index bc863e951140..93e40d0e9086 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -35,16 +35,33 @@ static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { }, }; -static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = { +static const struct ieee80211_iface_combination +mwifiex_iface_comb_ap_sta = { .limits = mwifiex_ap_sta_limits, .num_different_channels = 1, .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), .max_interfaces = MWIFIEX_MAX_BSS_NUM, .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40), +}; + +static const struct ieee80211_iface_combination +mwifiex_iface_comb_ap_sta_vht = { + .limits = mwifiex_ap_sta_limits, + .num_different_channels = 1, + .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), + .max_interfaces = MWIFIEX_MAX_BSS_NUM, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), }; static const struct -ieee80211_iface_combination mwifiex_drcs_iface_comb_ap_sta = { +ieee80211_iface_combination mwifiex_iface_comb_ap_sta_drcs = { .limits = mwifiex_ap_sta_limits, .num_different_channels = 2, .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), @@ -3755,7 +3772,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) - wiphy->iface_combinations = &mwifiex_drcs_iface_comb_ap_sta; + wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_drcs; + else if (adapter->is_hw_11ac_capable) + wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_vht; else wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; wiphy->n_iface_combinations = 1; -- cgit v1.3-6-gb490 From 8d6b538a5eac1fec259d22ffa5b47ac585582432 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:23 +0530 Subject: mwifiex: handle multichannel event This patch adds support to handle multichannel event from FW. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 8 ++++++++ drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/sta_event.c | 30 ++++++++++++++++++++++++++++++ drivers/net/wireless/mwifiex/uap_event.c | 6 ++++++ 4 files changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 976b58587c27..98269bfd2b31 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -172,6 +172,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 148) #define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) +#define TLV_TYPE_MULTI_CHAN_INFO (PROPRIETARY_TLV_BASE_ID + 183) #define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194) #define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197) #define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199) @@ -516,6 +517,7 @@ enum P2P_MODES { #define EVENT_TX_DATA_PAUSE 0x00000055 #define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f +#define EVENT_MULTI_CHAN_INFO 0x0000006a #define EVENT_TX_STATUS_REPORT 0x00000074 #define EVENT_BT_COEX_WLAN_PARA_CHANGE 0X00000076 @@ -1970,6 +1972,12 @@ struct mwifiex_radar_det_event { __le32 passed; } __packed; +struct mwifiex_ie_types_multi_chan_info { + struct mwifiex_ie_types_header header; + __le16 status; + u8 tlv_buffer[0]; +} __packed; + struct meas_rpt_map { u8 rssi:3; u8 unmeasured:1; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index f3264f2231d3..face7478937f 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1557,6 +1557,8 @@ void mwifiex_11n_delba(struct mwifiex_private *priv, int tid); int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy); void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, struct sk_buff *event); +void mwifiex_process_multi_chan_event(struct mwifiex_private *priv, + struct sk_buff *event_skb); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index a2777d16c98f..3d18c585e543 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -309,6 +309,31 @@ static void mwifiex_process_sta_tx_pause(struct mwifiex_private *priv, } } +void mwifiex_process_multi_chan_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_ie_types_multi_chan_info *chan_info; + u16 status; + + chan_info = (void *)event_skb->data + sizeof(u32); + + if (le16_to_cpu(chan_info->header.type) != TLV_TYPE_MULTI_CHAN_INFO) { + mwifiex_dbg(priv->adapter, ERROR, + "unknown TLV in chan_info event\n"); + return; + } + + status = le16_to_cpu(chan_info->status); + + if (status) { + mwifiex_dbg(priv->adapter, EVENT, + "multi-channel operation started\n"); + } else { + mwifiex_dbg(priv->adapter, EVENT, + "multi-channel operation over\n"); + } +} + void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, struct sk_buff *event_skb) { @@ -748,6 +773,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) mwifiex_process_tx_pause_event(priv, adapter->event_skb); break; + case EVENT_MULTI_CHAN_INFO: + mwifiex_dbg(adapter, EVENT, "event: multi-chan info\n"); + mwifiex_process_multi_chan_event(priv, adapter->event_skb); + break; + case EVENT_TX_STATUS_REPORT: mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n"); mwifiex_parse_tx_status_event(priv, adapter->event_body); diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index a9d34c619181..492a8b3c636e 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -304,6 +304,12 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); mwifiex_process_tx_pause_event(priv, adapter->event_skb); break; + + case EVENT_MULTI_CHAN_INFO: + mwifiex_dbg(adapter, EVENT, "event: multi-chan info\n"); + mwifiex_process_multi_chan_event(priv, adapter->event_skb); + break; + default: mwifiex_dbg(adapter, EVENT, "event: unknown event id: %#x\n", eventcause); -- cgit v1.3-6-gb490 From 9030d52cfb340f57d86e1b5d995a463eaddb977b Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 23 Jun 2015 22:53:05 +0800 Subject: wireless: cw1200: Remove redundant spi driver bus initialization In ancient times it was necessary to manually initialize the bus field of an spi_driver to spi_bus_type. These days this is done in spi_register_driver(), so we can drop the manual assignment. Signed-off-by: Antonio Borneo To: Solomon Peachy To: Kalle Valo To: linux-wireless@vger.kernel.org To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Kalle Valo --- drivers/net/wireless/cw1200/cw1200_spi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c index 7603546d2de3..29185aeccba8 100644 --- a/drivers/net/wireless/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/cw1200/cw1200_spi.c @@ -467,7 +467,6 @@ static struct spi_driver spi_driver = { .remove = cw1200_spi_disconnect, .driver = { .name = "cw1200_wlan_spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &cw1200_pm_ops, -- cgit v1.3-6-gb490 From 722d26680af10bd128b5228ba23e5d11ef2256c4 Mon Sep 17 00:00:00 2001 From: John Linville Date: Tue, 23 Jun 2015 14:45:45 -0400 Subject: mwifiex: avoid freeing improper pointer in mwifiex_set_wowlan_mef_entry mwifiex_set_wowlan_mef_entry attempts to free a passed-in pointer in case of an error. The only caller (mwifiex_set_mef_filter) passes that pointer as an offset into allocated memory, so any attempt to free that will not be the actual allocated pointer. Address this by changing mwifiex_set_wowlan_mef_entry to not do any free, and to cause mwifiex_set_mef_filter to do the appropriate free if the call to mwifiex_set_wowlan_mef_entry fails. Coverity CID #1295879 Signed-off-by: John W. Linville Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 93e40d0e9086..69ee6dbafd61 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2985,7 +2985,6 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv, MWIFIEX_MEF_MAX_BYTESEQ)) { mwifiex_dbg(priv->adapter, ERROR, "Pattern not supported\n"); - kfree(mef_entry); return -EOPNOTSUPP; } @@ -3067,9 +3066,12 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, mwifiex_set_auto_arp_mef_entry(priv, &mef_entry[0]); - if (wowlan->n_patterns || wowlan->magic_pkt) + if (wowlan->n_patterns || wowlan->magic_pkt) { ret = mwifiex_set_wowlan_mef_entry(priv, &mef_cfg, &mef_entry[1], wowlan); + if (ret) + goto err; + } if (!mef_cfg.criteria) mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST | @@ -3079,6 +3081,8 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); + +err: kfree(mef_entry); return ret; } -- cgit v1.3-6-gb490 From 8b2c621c9f6f6240edaf4359c3148068fff8b1c7 Mon Sep 17 00:00:00 2001 From: John Linville Date: Tue, 23 Jun 2015 15:04:03 -0400 Subject: mwifiex: do not short circuit exit from mwifiex_set_mgmt_ies Without this change, the code simply exits after calling mwifiex_uap_set_head_tail_ies, leving the call to mwifiex_set_mgmt_beacon_data_ies as dead code. Coverity CID #1271292 Signed-off-by: John W. Linville Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/ie.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 0ba894509413..23e368c77c08 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -409,6 +409,8 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, int ret; ret = mwifiex_uap_parse_tail_ies(priv, info); + + if (ret) return ret; return mwifiex_set_mgmt_beacon_data_ies(priv, info); -- cgit v1.3-6-gb490 From b5c103f20f0fdd736c51c996b07a42594d683b1c Mon Sep 17 00:00:00 2001 From: John Linville Date: Fri, 26 Jun 2015 15:29:36 -0400 Subject: mwifiex: fix leak of gen_ie storage on exit from mwifiex_del_mgmt_ies Storage pointed to by gen_ie is allocated with kmalloc, but was never freed. Coverity CID #1271251 Signed-off-by: John W. Linville Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/ie.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 23e368c77c08..abf52d25b981 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -479,6 +479,7 @@ int mwifiex_del_mgmt_ies(struct mwifiex_private *priv) ar_ie, &priv->assocresp_idx); done: + kfree(gen_ie); kfree(beacon_ie); kfree(pr_ie); kfree(ar_ie); -- cgit v1.3-6-gb490 From 9aaffa340add31aeb4449667da8779df448b7987 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 21 Jul 2015 17:36:45 +0530 Subject: drm/i915: remove unnecessary null test While creating the debugfs file we are setting the inode->i_private to dev. That same dev is passed to these functions as private of struct seq_file via single_open(). Moreover single_open is setting file->private_data->private to dev. So at this point it can never be NULL. This check was added by commit eb3394faeb97 ("drm/i915: Add debugfs test control files for Displayport compliance testing") Signed-off-by: Sudip Mukherjee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index bc817da9fef7..ffce62e33dc9 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4028,24 +4028,14 @@ static ssize_t i915_displayport_test_active_write(struct file *file, { char *input_buffer; int status = 0; - struct seq_file *m; struct drm_device *dev; struct drm_connector *connector; struct list_head *connector_list; struct intel_dp *intel_dp; int val = 0; - m = file->private_data; - if (!m) { - status = -ENODEV; - return status; - } - dev = m->private; + dev = ((struct seq_file *)file->private_data)->private; - if (!dev) { - status = -ENODEV; - return status; - } connector_list = &dev->mode_config.connector_list; if (len == 0) @@ -4103,9 +4093,6 @@ static int i915_displayport_test_active_show(struct seq_file *m, void *data) struct list_head *connector_list = &dev->mode_config.connector_list; struct intel_dp *intel_dp; - if (!dev) - return -ENODEV; - list_for_each_entry(connector, connector_list, head) { if (connector->connector_type != @@ -4150,9 +4137,6 @@ static int i915_displayport_test_data_show(struct seq_file *m, void *data) struct list_head *connector_list = &dev->mode_config.connector_list; struct intel_dp *intel_dp; - if (!dev) - return -ENODEV; - list_for_each_entry(connector, connector_list, head) { if (connector->connector_type != @@ -4192,9 +4176,6 @@ static int i915_displayport_test_type_show(struct seq_file *m, void *data) struct list_head *connector_list = &dev->mode_config.connector_list; struct intel_dp *intel_dp; - if (!dev) - return -ENODEV; - list_for_each_entry(connector, connector_list, head) { if (connector->connector_type != -- cgit v1.3-6-gb490 From b8bb08ec48fb4eafefbc7899b50ec5c6216465b1 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 21 Jul 2015 17:36:46 +0530 Subject: drm/i915: remove redundant if check The extra check for connector_type is not required as we are already checking for connector_type != DRM_MODE_CONNECTOR_DisplayPort. The check was added by commit eb3394faeb97 ("drm/i915: Add debugfs test control files for Displayport compliance testing") Signed-off-by: Sudip Mukherjee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index ffce62e33dc9..caf1382116de 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4059,9 +4059,7 @@ static ssize_t i915_displayport_test_active_write(struct file *file, DRM_MODE_CONNECTOR_DisplayPort) continue; - if (connector->connector_type == - DRM_MODE_CONNECTOR_DisplayPort && - connector->status == connector_status_connected && + if (connector->status == connector_status_connected && connector->encoder != NULL) { intel_dp = enc_to_intel_dp(connector->encoder); status = kstrtoint(input_buffer, 10, &val); -- cgit v1.3-6-gb490 From 11bdc44093555829eb4a5d9318eece469e2873e8 Mon Sep 17 00:00:00 2001 From: Reyad Attiyat Date: Sun, 28 Jun 2015 20:07:38 -0500 Subject: mwifiex: usb: Fix double add error when submitting rx urb There is an error that can occur where the driver adds the same URB to USB submission list twice. This happens since mwifiex_usb_submit_rem_rx can submit packets at same time as an rx urb complete callback. This causes list corruption and is fixed by not setting the skb to NULL when submitting an rx packet. [ 84.461242] WARNING: CPU: 1 PID: 748 at lib/list_debug.c:36 __list_add+0xcb/0xd0() [ 84.461245] list_add double add: new=ffff8800c92b0c50, prev=ffff8800c92b0c50, next=ffff8800ced6c430. [ 84.461247] Modules linked in: rfcomm fuse cmac nf_conntrack_netbios_ns nf_conntrack_broadcast ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack bnep iptable_mangle iptable_security iptable_raw btusb btintel bluetooth mwifiex_usb mwifiex x86_pkg_temp_thermal cfg80211 coretemp r8712u(C) kvm_intel kvm hid_sensor_als hid_sensor_incl_3d hid_sensor_rotation hid_sensor_magn_3d hid_sensor_accel_3d hid_sensor_gyro_3d hid_sensor_trigger hid_sensor_iio_common industrialio_triggered_buffer kfifo_buf rfkill iTCO_wdt industrialio iTCO_vendor_support [ 84.461316] crc32_pclmul crc32c_intel ghash_clmulni_intel microcode snd_hda_codec_realtek vfat snd_hda_codec_generic fat snd_hda_codec_hdmi snd_hda_intel snd_hda_controller uvcvideo snd_hda_codec videobuf2_vmalloc videobuf2_memops snd_hwdep videobuf2_core snd_hda_core joydev v4l2_common videodev hid_sensor_hub snd_seq hid_multitouch media snd_seq_device snd_pcm snd_timer mei_me snd i2c_i801 lpc_ich mei soundcore tpm_infineon tpm_tis tpm i2c_hid i2c_designware_platform i2c_designware_core nfsd auth_rpcgss nfs_acl lockd grace sunrpc sch_fq_codel i915 i2c_algo_bit drm_kms_helper drm xhci_pci xhci_hcd ehci_pci sd_mod ehci_hcd video [ 84.461383] CPU: 1 PID: 748 Comm: kworker/u9:0 Tainted: G C 4.1.0-rc5+ #163 [ 84.461386] Hardware name: Microsoft Corporation Surface Pro 2/Surface Pro 2, BIOS 2.05.0250 04/10/2015 [ 84.461396] Workqueue: MWIFIEX_RX_WORK_QUEUE mwifiex_rx_work_queue [mwifiex] [ 84.461399] ffffffff81a8150e ffff8801174cf8e8 ffffffff817df830 0000000000000000 [ 84.461405] ffff8801174cf938 ffff8801174cf928 ffffffff810a54ba ffff8800c86bd750 [ 84.461410] ffff8800c92b0c50 ffff8800c92b0c50 ffff8800ced6c430 ffff88010c057178 [ 84.461416] Call Trace: [ 84.461421] [] dump_stack+0x4f/0x7b [ 84.461428] [] warn_slowpath_common+0x8a/0xc0 [ 84.461432] [] warn_slowpath_fmt+0x46/0x50 [ 84.461436] [] __list_add+0xcb/0xd0 [ 84.461442] [] ? usb_hcd_link_urb_to_ep+0x2a/0xa0 [ 84.461446] [] usb_hcd_link_urb_to_ep+0x80/0xa0 [ 84.461459] [] prepare_transfer+0xaa/0x130 [xhci_hcd] [ 84.461470] [] xhci_queue_bulk_tx+0xb7/0x7a0 [xhci_hcd] [ 84.461480] [] ? xhci_urb_enqueue+0x50f/0x660 [xhci_hcd] [ 84.461489] [] ? xhci_urb_enqueue+0x50f/0x660 [xhci_hcd] [ 84.461498] [] xhci_urb_enqueue+0x5c5/0x660 [xhci_hcd] [ 84.461503] [] usb_hcd_submit_urb+0x93/0xa70 [ 84.461507] [] ? __alloc_skb+0x78/0x1f0 [ 84.461511] [] ? __kmalloc_reserve.isra.26+0x31/0x90 [ 84.461515] [] ? __alloc_skb+0x4c/0x1f0 [ 84.461519] [] ? __alloc_skb+0x8c/0x1f0 [ 84.461523] [] ? skb_dequeue+0x5d/0x80 [ 84.461527] [] usb_submit_urb+0x42e/0x5f0 [ 84.461531] [] ? __alloc_rx_skb+0x39/0x100 [ 84.461536] [] mwifiex_usb_submit_rx_urb+0xb2/0x170 [mwifiex_usb] [ 84.461542] [] mwifiex_usb_submit_rem_rx_urbs+0x45/0x50 [mwifiex_usb] [ 84.461550] [] mwifiex_rx_work_queue+0x10e/0x140 [mwifiex] [ 84.461556] [] process_one_work+0x229/0x890 [ 84.461559] [] ? process_one_work+0x18c/0x890 [ 84.461565] [] worker_thread+0x53/0x470 [ 84.461569] [] ? process_one_work+0x890/0x890 [ 84.461572] [] kthread+0xf2/0x110 [ 84.461577] [] ? trace_hardirqs_on+0xd/0x10 [ 84.461581] [] ? kthread_create_on_node+0x230/0x230 [ 84.461586] [] ret_from_fork+0x42/0x70 [ 84.461590] [] ? kthread_create_on_node+0x230/0x230 [ 84.461593] ---[ end trace 65103af5e6fb3444 ]--- Signed-off-by: Reyad Attiyat Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index aada93425f80..fbad99c50307 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -244,9 +244,11 @@ setup_for_next: if (card->rx_cmd_ep == context->ep) { mwifiex_usb_submit_rx_urb(context, size); } else { - context->skb = NULL; - if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING) + if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING){ mwifiex_usb_submit_rx_urb(context, size); + }else{ + context->skb = NULL; + } } return; -- cgit v1.3-6-gb490 From 33b8261e0e1c6d95901d62808d65141d4df525bd Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 29 Jun 2015 20:17:55 -0400 Subject: rtlwifi: fix typo in comments This fixes a typo in two comments: "paht" -> "path". Signed-off-by: Nik Nyby Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192de/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 1961b8e28dc1..bb06fe836fe7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -3515,14 +3515,14 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; rfpath++) { if (rtlhal->current_bandtype == BAND_ON_2_4G) { - /* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ + /* MOD_AG for RF path_A 0x18 BIT8,BIT16 */ rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) | BIT(16) | BIT(18), 0); /* RF0x0b[16:14] =3b'111 */ rtl_set_rfreg(hw, (enum radio_path)rfpath, 0x0B, 0x1c000, 0x07); } else { - /* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ + /* MOD_AG for RF path_A 0x18 BIT8,BIT16 */ rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) | BIT(16) | BIT(18), (BIT(16) | BIT(8)) >> 8); -- cgit v1.3-6-gb490 From 277bf09e8be9fa35d6bc0175c2c5a1e6bdb0626e Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 29 Jun 2015 20:45:47 -0400 Subject: b43: Fix typo in function name This fixes a typo in the "b43_lo_g_maintenance_work" function name. Signed-off-by: Nik Nyby Acked-by: Larry Finger Acked-by: Michael Buesch Signed-off-by: Kalle Valo --- drivers/net/wireless/b43/lo.c | 4 ++-- drivers/net/wireless/b43/lo.h | 2 +- drivers/net/wireless/b43/phy_g.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 916123a3d74e..a335f94c72ff 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -929,8 +929,8 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, b43_lo_write(dev, &cal->ctl); } -/* Periodic LO maintanance work */ -void b43_lo_g_maintanance_work(struct b43_wldev *dev) +/* Periodic LO maintenance work */ +void b43_lo_g_maintenance_work(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h index 3b27e20eff80..7b4df3883bc2 100644 --- a/drivers/net/wireless/b43/lo.h +++ b/drivers/net/wireless/b43/lo.h @@ -80,7 +80,7 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all); -void b43_lo_g_maintanance_work(struct b43_wldev *dev); +void b43_lo_g_maintenance_work(struct b43_wldev *dev); void b43_lo_g_cleanup(struct b43_wldev *dev); void b43_lo_g_init(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 727ce6edb4b3..462310e6e88f 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -3004,7 +3004,7 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) phy->rev == 1) { //TODO: implement rev1 workaround } - b43_lo_g_maintanance_work(dev); + b43_lo_g_maintenance_work(dev); b43_mac_enable(dev); } -- cgit v1.3-6-gb490 From cf7d5a80201066daac467d57a47b0826c2e88354 Mon Sep 17 00:00:00 2001 From: Raphaël Poggi Date: Thu, 2 Jul 2015 10:34:49 +0200 Subject: wlcore: sdio: return correct error code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When wlcore_probe_of failed, return the correct error code instead of ENOMEM Signed-off-by: Raphaël Poggi Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/sdio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index ea7e07abca4e..c172da56b550 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -293,7 +293,8 @@ static int wl1271_probe(struct sdio_func *func, /* Use block mode for transferring over one block size of data */ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; - if (wlcore_probe_of(&func->dev, &irq, &pdev_data)) + ret = wlcore_probe_of(&func->dev, &irq, &pdev_data); + if (ret) goto out_free_glue; /* if sdio can keep power while host is suspended, enable wow */ -- cgit v1.3-6-gb490 From e60ac9c7a4c8776b2503892dfd01f1b4d651245d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jul 2015 13:40:29 +0200 Subject: ath9k: make DMA stop related messages debug-only A long time ago, ath9k had issues during reset where the DMA engine would stay active and could potentially corrupt memory. To debug those issues, the driver would print warnings whenever they occur. Nowadays, these issues are gone and the primary cause of these messages is if the MAC is stuck during reset or busy processing a long transmission. This is fairly harmless, yet these messages continue to worry users. To reduce the number of bogus bug reports, turn these messages into debug messages and count their occurence in the "reset" debugfs file. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/debug.c | 2 ++ drivers/net/wireless/ath/ath9k/debug.h | 2 ++ drivers/net/wireless/ath/ath9k/recv.c | 7 +++---- drivers/net/wireless/ath/ath9k/xmit.c | 7 +++++-- 4 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index dbf8f4959642..da32c8faad94 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -765,6 +765,8 @@ static int read_file_reset(struct seq_file *file, void *data) [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon", [RESET_TYPE_MCI] = "MCI Reset", [RESET_TYPE_CALIBRATION] = "Calibration error", + [RESET_TX_DMA_ERROR] = "Tx DMA stop error", + [RESET_RX_DMA_ERROR] = "Rx DMA stop error", }; int i; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index a8e9319958e6..cd68c5f0e751 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -50,6 +50,8 @@ enum ath_reset_type { RESET_TYPE_BEACON_STUCK, RESET_TYPE_MCI, RESET_TYPE_CALIBRATION, + RESET_TX_DMA_ERROR, + RESET_RX_DMA_ERROR, __RESET_TYPE_MAX }; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6c75fb1ab77d..d3189daf9996 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -491,10 +491,9 @@ bool ath_stoprecv(struct ath_softc *sc) if (!(ah->ah_flags & AH_UNPLUGGED) && unlikely(!stopped)) { - ath_err(ath9k_hw_common(sc->sc_ah), - "Could not stop RX, we could be " - "confusing the DMA engine when we start RX up\n"); - ATH_DBG_WARN_ON_ONCE(!stopped); + ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, + "Failed to stop Rx DMA\n"); + RESET_STAT_INC(sc, RESET_RX_DMA_ERROR); } return stopped && !reset; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3ad79bb4f2c2..2c627f1233da 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1883,8 +1883,11 @@ bool ath_drain_all_txq(struct ath_softc *sc) npend |= BIT(i); } - if (npend) - ath_err(common, "Failed to stop TX DMA, queues=0x%03x!\n", npend); + if (npend) { + RESET_STAT_INC(sc, RESET_TX_DMA_ERROR); + ath_dbg(common, RESET, + "Failed to stop TX DMA, queues=0x%03x!\n", npend); + } for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (!ATH_TXQ_SETUP(sc, i)) -- cgit v1.3-6-gb490 From ae86c587b5b53da4f7859f236f6c22ff9941cff9 Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 2 Jul 2015 06:07:02 -0700 Subject: mwifiex: fix for p2p broken link This patch fixes following issues in p2p code paths. 1) bss role, bss type and connection type was not set correctly for p2p GO and p2p client at couple of places. 2) Driver appends a proprietary header to management frames which will be parsed by our firmware. Later while informing TX status to cfg80211, modified frame buffer was passed to cfg80211_mgmt_tx_status() instead of original one. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 5 ++++- drivers/net/wireless/mwifiex/sta_cmd.c | 6 ++++-- drivers/net/wireless/mwifiex/txrx.c | 22 +++++++++++++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 69ee6dbafd61..d4b327752a5e 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -831,10 +831,13 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, priv->bss_type = MWIFIEX_BSS_TYPE_STA; break; case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_P2P_GO: priv->bss_role = MWIFIEX_BSS_ROLE_STA; priv->bss_type = MWIFIEX_BSS_TYPE_P2P; break; + case NL80211_IFTYPE_P2P_GO: + priv->bss_role = MWIFIEX_BSS_ROLE_UAP; + priv->bss_type = MWIFIEX_BSS_TYPE_P2P; + break; case NL80211_IFTYPE_AP: priv->bss_type = MWIFIEX_BSS_TYPE_UAP; priv->bss_role = MWIFIEX_BSS_ROLE_UAP; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 36cb6bdbe49b..a49a80dd773e 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1997,10 +1997,12 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, if (priv->bss_mode == NL80211_IFTYPE_ADHOC) cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_ADHOC; - else if (priv->bss_mode == NL80211_IFTYPE_STATION) + else if (priv->bss_mode == NL80211_IFTYPE_STATION || + priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_INFRA; - else if (priv->bss_mode == NL80211_IFTYPE_AP) + else if (priv->bss_mode == NL80211_IFTYPE_AP || + priv->bss_mode == NL80211_IFTYPE_P2P_GO) cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_AP; cmd_ptr->size = cpu_to_le16(sizeof(struct host_cmd_ds_set_bss_mode) + S_DS_GEN); diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 5ed9b794053e..8b1e5b5d47fe 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -370,8 +370,28 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, /* consumes ack_skb */ skb_complete_wifi_ack(ack_skb, !tx_status->status); } else { + /* Remove broadcast address which was added by driver */ + memmove(ack_skb->data + + sizeof(struct ieee80211_hdr_3addr) + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16), + ack_skb->data + + sizeof(struct ieee80211_hdr_3addr) + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + + ETH_ALEN, ack_skb->len - + (sizeof(struct ieee80211_hdr_3addr) + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + + ETH_ALEN)); + ack_skb->len = ack_skb->len - ETH_ALEN; + /* Remove driver's proprietary header including 2 bytes + * of packet length and pass actual management frame buffer + * to cfg80211. + */ cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie, - ack_skb->data, ack_skb->len, + ack_skb->data + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + + sizeof(u16), ack_skb->len - + (MWIFIEX_MGMT_FRAME_HEADER_SIZE + + sizeof(u16)), !tx_status->status, GFP_ATOMIC); dev_kfree_skb_any(ack_skb); } -- cgit v1.3-6-gb490 From cae761b5a6bdc597ba476a040fdcd5b4bc559b85 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Sun, 28 Jun 2015 17:17:13 +0200 Subject: bcma: populate bus DT subnodes as platform_device-s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our bus should allow defining children nodes as we may want to specify devices attached to the bus. This is required e.g. to specify NAND or ChipCommon cores and use bus's address and IRQ mappings. Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/bcma/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 9635f1033ce5..59128478a90f 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -12,6 +12,7 @@ #include #include #include +#include MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); MODULE_LICENSE("GPL"); @@ -409,6 +410,13 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_pci_early_init(&bus->drv_pci[0]); } + if (bus->host_pdev) { + struct device *dev = &bus->host_pdev->dev; + + of_platform_populate(dev->of_node, of_default_bus_match_table, + NULL, dev); + } + /* Cores providing flash access go before SPROM init */ list_for_each_entry(core, &bus->cores, list) { if (bcma_is_core_needed_early(core->id.id)) -- cgit v1.3-6-gb490 From 251086f588720277a6f5782020a648ce32c4e00b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 8 Jul 2015 10:18:50 -0500 Subject: rtlwifi: rtl8821ae: Fix an expression that is always false In routine _rtl8821ae_set_media_status(), an incorrect mask results in a test for AP status to always be false. Similar bugs were fixed in rtl8192cu and rtl8192de, but this instance was missed at that time. Reported-by: David Binderman Signed-off-by: Larry Finger Cc: Stable [3.18+] Cc: David Binderman Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8821ae/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8821ae/reg.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c index 3236d44b459d..b7f18e2155eb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c @@ -2180,7 +2180,7 @@ static int _rtl8821ae_set_media_status(struct ieee80211_hw *hw, rtl_write_byte(rtlpriv, MSR, bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); - if ((bt_msr & 0xfc) == MSR_AP) + if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h index 53668fc8f23e..1d6110f9c1fb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h @@ -429,6 +429,7 @@ #define MSR_ADHOC 0x01 #define MSR_INFRA 0x02 #define MSR_AP 0x03 +#define MSR_MASK 0x03 #define RRSR_RSC_OFFSET 21 #define RRSR_SHORT_OFFSET 23 -- cgit v1.3-6-gb490 From 77661208a87b458f353fd0b7a4729cf2887449a6 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Wed, 8 Jul 2015 22:22:46 +0200 Subject: brcmsmac: Use kstrdup to simplify code Replace a kmalloc+strcpy by an equivalent kstrdup in order to improve readability. Signed-off-by: Christophe JAILLET Acked-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index ab775a5d5b33..d2c5747e3ac9 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -1472,9 +1472,7 @@ struct brcms_timer *brcms_init_timer(struct brcms_info *wl, wl->timers = t; #ifdef DEBUG - t->name = kmalloc(strlen(name) + 1, GFP_ATOMIC); - if (t->name) - strcpy(t->name, name); + t->name = kstrdup(name, GFP_ATOMIC); #endif return t; -- cgit v1.3-6-gb490 From 92cd40322848a12f1f3ef2d7804233b93030c532 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 12:27:22 +0200 Subject: ath9k: fix moredata flag endianness in cabq tx While compiling ath9k with some extra flags I've found that: ath9k/xmit.c +2473 ## 16: warning: restricted __le16 degrades to integer ath9k/xmit.c +2474 ## 36: warning: invalid assignment: &= ath9k/xmit.c +2474 ## 36: left side has type restricted __le16 ath9k/xmit.c +2474 ## 36: right side has type int There's no way for frame ftype/stype to be mistreated as the offending 'moredata' flag when considering cab queue. This could've however theoretically led sometimes to increased power consumption on connected stations as they would keep their Rx active waiting for frames that would never come. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/xmit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2c627f1233da..b766a7fc60aa 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2473,8 +2473,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, bf = list_first_entry(&bf_q, struct ath_buf, list); hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; - if (hdr->frame_control & IEEE80211_FCTL_MOREDATA) { - hdr->frame_control &= ~IEEE80211_FCTL_MOREDATA; + if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA)) { + hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA); dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, sizeof(*hdr), DMA_TO_DEVICE); } -- cgit v1.3-6-gb490 From e3faa866d5e4d6199b45f821343ee24510881823 Mon Sep 17 00:00:00 2001 From: Rafa? Mi?ecki Date: Thu, 9 Jul 2015 17:07:08 +0200 Subject: brcmfmac: set wiphy's addresses to provide valid MACs Broadcom's firmware requires every BSS to use MAC address with unique last few bits. The amount of bits may depend on a particular firmware, it was verified to be 2 for BCM43602 one. If this condition won't be fulfilled firmware will reject such MAC: brcmfmac: _brcmf_set_mac_address: Setting cur_etheraddr failed, -52 We don't want to simply set addr_mask as it would also disallow using locally administrated bit. Instead let's build a list of addresses manually enabling 0x2 bit for extra interfaces. Signed-off-by: Rafa? Mi?ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 14 ++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/core.h | 3 +++ 2 files changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index d86d1f1f1c91..ffe526070d6f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -5785,6 +5785,7 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy) static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) { + struct brcmf_pub *drvr = ifp->drvr; struct ieee80211_supported_band *band; __le32 bandlist[3]; u32 n_bands; @@ -5798,6 +5799,19 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) if (err) return err; + for (i = 0; i < wiphy->iface_combinations->max_interfaces && + i < ARRAY_SIZE(drvr->addresses); i++) { + u8 *addr = drvr->addresses[i].addr; + + memcpy(addr, drvr->mac, ETH_ALEN); + if (i) { + addr[0] |= BIT(1); + addr[ETH_ALEN - 1] ^= i; + } + } + wiphy->addresses = drvr->addresses; + wiphy->n_addresses = i; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->cipher_suites = __wl_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h index fd74a9c6e9ac..746304121cdb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h @@ -21,6 +21,7 @@ #ifndef BRCMFMAC_CORE_H #define BRCMFMAC_CORE_H +#include #include "fweh.h" #define TOE_TX_CSUM_OL 0x00000001 @@ -118,6 +119,8 @@ struct brcmf_pub { /* Multicast data packets sent to dongle */ unsigned long tx_multicast; + struct mac_address addresses[BRCMF_MAX_IFS]; + struct brcmf_if *iflist[BRCMF_MAX_IFS]; struct mutex proto_block; -- cgit v1.3-6-gb490 From fa5b8c8a5ae4088a590d59fffb022da3ea17bd15 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Wed, 15 Jul 2015 15:54:06 +0800 Subject: ath9k: Fix register definitions for QCA956x Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index fc595b92ac56..c5f8bc4b5595 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -455,7 +455,7 @@ #define AR_PHY_MODE (AR_SM_BASE + 0x8) #define AR_PHY_ACTIVE (AR_SM_BASE + 0xc) #define AR_PHY_SPUR_MASK_A (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x18 : 0x20)) -#define AR_PHY_SPUR_MASK_B (AR_SM_BASE + 0x24) +#define AR_PHY_SPUR_MASK_B (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x1c : 0x24)) #define AR_PHY_SPECTRAL_SCAN (AR_SM_BASE + 0x28) #define AR_PHY_RADAR_BW_FILTER (AR_SM_BASE + 0x2c) #define AR_PHY_SEARCH_START_DELAY (AR_SM_BASE + 0x30) @@ -495,7 +495,7 @@ #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A 0x3FF #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A_S 0 -#define AR_PHY_TEST (AR_SM_BASE + 0x160) +#define AR_PHY_TEST (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x15c : 0x160)) #define AR_PHY_TEST_BBB_OBS_SEL 0x780000 #define AR_PHY_TEST_BBB_OBS_SEL_S 19 @@ -521,24 +521,29 @@ #define AR_PHY_TEST_CTL_DEBUGPORT_SEL_S 29 -#define AR_PHY_TSTDAC (AR_SM_BASE + 0x168) +#define AR_PHY_TSTDAC (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x164 : 0x168)) -#define AR_PHY_CHAN_STATUS (AR_SM_BASE + 0x16c) +#define AR_PHY_CHAN_STATUS (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x168 : 0x16c)) #define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x16c : 0x170)) #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ 0x00000008 #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S 3 -#define AR_PHY_CHNINFO_NOISEPWR (AR_SM_BASE + 0x174) -#define AR_PHY_CHNINFO_GAINDIFF (AR_SM_BASE + 0x178) -#define AR_PHY_CHNINFO_FINETIM (AR_SM_BASE + 0x17c) -#define AR_PHY_CHAN_INFO_GAIN_0 (AR_SM_BASE + 0x180) -#define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + 0x190) -#define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + 0x194) +#define AR_PHY_CHNINFO_NOISEPWR (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x170 : 0x174)) +#define AR_PHY_CHNINFO_GAINDIFF (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x174 : 0x178)) +#define AR_PHY_CHNINFO_FINETIM (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x178 : 0x17c)) +#define AR_PHY_CHAN_INFO_GAIN_0 (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x17c : 0x180)) +#define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x184 : 0x190)) +#define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x188 : 0x194)) #define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x198 : 0x1a4)) #define AR_PHY_HEAVYCLIP_20 (AR_SM_BASE + 0x1a8) #define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac) +#define AR_PHY_HEAVYCLIP_1 (AR_SM_BASE + 0x19c) +#define AR_PHY_HEAVYCLIP_2 (AR_SM_BASE + 0x1a0) +#define AR_PHY_HEAVYCLIP_3 (AR_SM_BASE + 0x1a4) +#define AR_PHY_HEAVYCLIP_4 (AR_SM_BASE + 0x1a8) +#define AR_PHY_HEAVYCLIP_5 (AR_SM_BASE + 0x1ac) #define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0) #define AR_PHY_POWER_TX_RATE(_d) (AR_SM_BASE + 0x1c0 + ((_d) << 2)) -- cgit v1.3-6-gb490 From 6301566e0b2dafa7d6779598621bca867962a0a2 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Wed, 15 Jul 2015 15:54:07 +0800 Subject: ath9k: export HW random number generator We measured the FFT-based entropy in 3 ways, Shannon entropy, collision entropy, and directly measured min-entropy. Just to be conservative, we recommend the estimated min-Entropy to be 10 bits per 16-bit value. Analysis was done by Jacobson,David(djacobso@qti.qualcomm.com). Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/Kconfig | 7 +++ drivers/net/wireless/ath/ath9k/Makefile | 1 + drivers/net/wireless/ath/ath9k/ath9k.h | 23 ++++++++++ drivers/net/wireless/ath/ath9k/main.c | 4 ++ drivers/net/wireless/ath/ath9k/rng.c | 75 +++++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+) create mode 100644 drivers/net/wireless/ath/ath9k/rng.c (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index fee0cadb0f5e..bde62ec98bc7 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -176,3 +176,10 @@ config ATH9K_HTC_DEBUGFS depends on ATH9K_HTC && DEBUG_FS ---help--- Say Y, if you need access to ath9k_htc's statistics. + +config ATH9K_HWRNG + bool "Random number generator support" + depends on ATH9K && (HW_RANDOM = y || HW_RANDOM = ATH9K) + default y + ---help--- + Provides a hardware random number generator to the kernel. diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index ecda613c2d54..76f9dc37500b 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -15,6 +15,7 @@ ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o ath9k-$(CONFIG_ATH9K_TX99) += tx99.o ath9k-$(CONFIG_ATH9K_WOW) += wow.o +ath9k-$(CONFIG_ATH9K_HWRNG) += rng.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a7a81b3969ce..45596e5ae4db 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "common.h" #include "debug.h" @@ -1041,6 +1042,12 @@ struct ath_softc { u32 wow_intr_before_sleep; bool force_wow; #endif + +#ifdef CONFIG_ATH9K_HWRNG + struct hwrng rng; + bool rng_initialized; + u32 rng_last; +#endif }; /********/ @@ -1063,6 +1070,22 @@ static inline int ath9k_tx99_send(struct ath_softc *sc, } #endif /* CONFIG_ATH9K_TX99 */ +/***************************/ +/* Random Number Generator */ +/***************************/ +#ifdef CONFIG_ATH9K_HWRNG +void ath9k_rng_register(struct ath_softc *sc); +void ath9k_rng_unregister(struct ath_softc *sc); +#else +static inline void ath9k_rng_register(struct ath_softc *sc) +{ +} + +static inline void ath9k_rng_unregister(struct ath_softc *sc) +{ +} +#endif + static inline void ath_read_cachesize(struct ath_common *common, int *csz) { common->bus_ops->read_cachesize(common, csz); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cfd45cb8ccfc..5916ab2f4a3d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -739,6 +739,8 @@ static int ath9k_start(struct ieee80211_hw *hw) ath9k_ps_restore(sc); + ath9k_rng_register(sc); + return 0; } @@ -828,6 +830,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_deinit_channel_context(sc); + ath9k_rng_unregister(sc); + mutex_lock(&sc->mutex); ath_cancel_work(sc); diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c new file mode 100644 index 000000000000..d8fa7a535ab8 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/rng.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, 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 "ath9k.h" +#include "hw.h" +#include "ar9003_phy.h" + +static int ath9k_rng_data_read(struct hwrng *rng, u32 *data) +{ + u32 v1, v2; + struct ath_softc *sc = (struct ath_softc *)rng->priv; + struct ath_hw *ah = sc->sc_ah; + + ath9k_ps_wakeup(sc); + + REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 5); + REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5); + REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0); + + v1 = REG_READ(ah, AR_PHY_TST_ADC); + v2 = REG_READ(ah, AR_PHY_TST_ADC); + + ath9k_ps_restore(sc); + + /* wait for data ready */ + if (v1 && v2 && sc->rng_last != v1 && v1 != v2) { + *data = (v1 & 0xffff) | (v2 << 16); + sc->rng_last = v2; + + return sizeof(u32); + } + + sc->rng_last = v2; + + return 0; +} + +void ath9k_rng_register(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + if (WARN_ON(sc->rng_initialized)) + return; + + if (!AR_SREV_9300_20_OR_LATER(ah)) + return; + + sc->rng.name = "ath9k"; + sc->rng.data_read = ath9k_rng_data_read; + sc->rng.priv = (unsigned long)sc; + + if (!hwrng_register(&sc->rng)) + sc->rng_initialized = true; +} + +void ath9k_rng_unregister(struct ath_softc *sc) +{ + if (sc->rng_initialized) { + hwrng_unregister(&sc->rng); + sc->rng_initialized = false; + } +} -- cgit v1.3-6-gb490 From 5d6af28a2d240602a594cea236406a9d29bc719a Mon Sep 17 00:00:00 2001 From: Guy Mishol Date: Thu, 16 Jul 2015 11:22:47 +0300 Subject: wlcore: add antenna diversity reading update the rssi reading on rx_status to read both RSSI level (7 bits) and antenna diversity (msb) Signed-off-by: Guy Mishol Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/rx.c | 3 ++- drivers/net/wireless/ti/wlcore/rx.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index e125974285cc..7df672a84530 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -74,7 +74,8 @@ static void wl1271_rx_status(struct wl1271 *wl, if (desc->rate <= wl->hw_min_ht_rate) status->flag |= RX_FLAG_HT; - status->signal = desc->rssi; + status->signal = ((desc->rssi & RSSI_LEVEL_BITMASK) | BIT(7)); + status->antenna = ((desc->rssi & ANT_DIVERSITY_BITMASK) >> 7); /* * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h index a3b1618db27c..f5a7087cfb97 100644 --- a/drivers/net/wireless/ti/wlcore/rx.h +++ b/drivers/net/wireless/ti/wlcore/rx.h @@ -30,6 +30,9 @@ #define WL1271_RX_MAX_RSSI -30 #define WL1271_RX_MIN_RSSI -95 +#define RSSI_LEVEL_BITMASK 0x7F +#define ANT_DIVERSITY_BITMASK BIT(7) + #define SHORT_PREAMBLE_BIT BIT(0) #define OFDM_RATE_BIT BIT(6) #define PBCC_RATE_BIT BIT(7) -- cgit v1.3-6-gb490 From 8358491d893e08d4b82af0d6012e078158f57ed9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 16 Jul 2015 15:42:15 +0300 Subject: iwlegacy: convert hex_dump_to_buffer() to %*ph There is no need to use hex_dump_to_buffer() in the cases like this: hexdump_to_buffer(buf, len, 16, 1, outbuf, outlen, false); /* len <= 16 */ sprintf("%s\n", outbuf); since it maybe easily converted to simple: sprintf("%*ph\n", len, buf); Note: it seems in the case the output is groupped by 2 bytes and looks like a typo. Thus, patch changes that to plain byte stream. Signed-off-by: Andy Shevchenko Signed-off-by: Kalle Valo --- drivers/net/wireless/iwlegacy/3945-mac.c | 2 +- drivers/net/wireless/iwlegacy/debug.c | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 7f4cb692cc57..af1b3e6839fa 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -3259,7 +3259,7 @@ il3945_show_measurement(struct device *d, struct device_attribute *attr, while (size && PAGE_SIZE - len) { hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, - PAGE_SIZE - len, 1); + PAGE_SIZE - len, true); len = strlen(buf); if (PAGE_SIZE - len) buf[len++] = '\n'; diff --git a/drivers/net/wireless/iwlegacy/debug.c b/drivers/net/wireless/iwlegacy/debug.c index 344010153196..908b9f4fef6f 100644 --- a/drivers/net/wireless/iwlegacy/debug.c +++ b/drivers/net/wireless/iwlegacy/debug.c @@ -515,12 +515,8 @@ il_dbgfs_nvm_read(struct file *file, char __user *user_buf, size_t count, scnprintf(buf + pos, buf_size - pos, "EEPROM " "version: 0x%x\n", eeprom_ver); for (ofs = 0; ofs < eeprom_len; ofs += 16) { - pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); - hex_dump_to_buffer(ptr + ofs, 16, 16, 2, buf + pos, - buf_size - pos, 0); - pos += strlen(buf + pos); - if (buf_size - pos > 0) - buf[pos++] = '\n'; + pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x %16ph\n", + ofs, ptr + ofs); } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); -- cgit v1.3-6-gb490 From 40d7412b56f02160291a5153551c4ada8e76f6ed Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 16 Jul 2015 08:05:21 -0700 Subject: mwifiex: add bss mode TLV to extended scan command We are setting BSS mode as ANY so that firmware will provide all types of scan entries. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 6 ++++++ drivers/net/wireless/mwifiex/scan.c | 10 ++++++++++ 2 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 98269bfd2b31..cff38ad129aa 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -179,6 +179,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_CHANNEL_STATS (PROPRIETARY_TLV_BASE_ID + 198) #define TLV_BTCOEX_WL_AGGR_WINSIZE (PROPRIETARY_TLV_BASE_ID + 202) #define TLV_BTCOEX_WL_SCANTIME (PROPRIETARY_TLV_BASE_ID + 203) +#define TLV_TYPE_BSS_MODE (PROPRIETARY_TLV_BASE_ID + 206) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -1434,6 +1435,11 @@ struct host_cmd_ds_802_11_scan_ext { u8 tlv_buffer[1]; } __packed; +struct mwifiex_ie_types_bss_mode { + struct mwifiex_ie_types_header header; + u8 bss_mode; +} __packed; + struct mwifiex_ie_types_bss_scan_rsp { struct mwifiex_ie_types_header header; u8 bssid[ETH_ALEN]; diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index baf9715ddc10..ef2bef8399c2 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -823,6 +823,7 @@ mwifiex_config_scan(struct mwifiex_private *priv, int i; u8 ssid_filter; struct mwifiex_ie_types_htcap *ht_cap; + struct mwifiex_ie_types_bss_mode *bss_mode; /* The tlv_buf_len is calculated for each scan command. The TLVs added in this routine will be preserved since the routine that sends the @@ -968,6 +969,15 @@ mwifiex_config_scan(struct mwifiex_private *priv, else *max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD; + if (adapter->ext_scan) { + bss_mode = (struct mwifiex_ie_types_bss_mode *)tlv_pos; + bss_mode->header.type = cpu_to_le16(TLV_TYPE_BSS_MODE); + bss_mode->header.len = cpu_to_le16(sizeof(bss_mode->bss_mode)); + bss_mode->bss_mode = scan_cfg_out->bss_mode; + tlv_pos += sizeof(bss_mode->header) + + le16_to_cpu(bss_mode->header.len); + } + /* If the input config or adapter has the number of Probes set, add tlv */ if (num_probes) { -- cgit v1.3-6-gb490 From 0c6303cc06954c336a8221522e9ddf056125afab Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 16 Jul 2015 08:05:22 -0700 Subject: mwifiex: use maximum ssid length as 0xfe for p2p 0xfe is basically a magic number used to ask firmware match provided string in a SSID. In this case, firmware will return scan results containing"DIRECT-" string. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/scan.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index ef2bef8399c2..ef8da8ebcbab 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -909,6 +909,10 @@ mwifiex_config_scan(struct mwifiex_private *priv, wildcard_ssid_tlv->max_ssid_length = IEEE80211_MAX_SSID_LEN; + if (!memcmp(user_scan_in->ssid_list[i].ssid, + "DIRECT-", 7)) + wildcard_ssid_tlv->max_ssid_length = 0xfe; + memcpy(wildcard_ssid_tlv->ssid, user_scan_in->ssid_list[i].ssid, ssid_len); -- cgit v1.3-6-gb490 From e79801ffe9c862597750359b8c6825f3a3bfaa4f Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 16 Jul 2015 08:48:43 -0700 Subject: mwifiex: correct p2p and station interface counters While changing interface type from p2p client or p2p go to station, we should update counters for p2p interface and station interface. Also calling mwifiex_cfg80211_deinit_p2p method instead of mwifiex_cfg80211_init_p2p_client method to deinit p2p interface. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index d4b327752a5e..ff63cb5632eb 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1145,8 +1145,10 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_P2P_GO: switch (type) { case NL80211_IFTYPE_STATION: - if (mwifiex_cfg80211_init_p2p_client(priv)) + if (mwifiex_cfg80211_deinit_p2p(priv)) return -EFAULT; + priv->adapter->curr_iface_comb.p2p_intf--; + priv->adapter->curr_iface_comb.sta_intf++; dev->ieee80211_ptr->iftype = type; break; case NL80211_IFTYPE_ADHOC: -- cgit v1.3-6-gb490 From e4a8f8ee89ed15eb7849bc064c2defe76cc085cf Mon Sep 17 00:00:00 2001 From: Russell Joyce Date: Tue, 7 Jul 2015 17:54:19 +0100 Subject: PCI: xilinx: Check for MSI interrupt flag before handling as INTx Occasionally both MSI and INTx bits in the interrupt decode register are set at once by the Xilinx AXI PCIe Bridge, so the MSI flag in the interrupt message should be checked to ensure that the correct handler is used. If this check is not in place and the interrupt message type is MSI, the INTx handler will be used erroneously when both type bits are set. This will also be followed by a second read of the message FIFO, which can result in the function returning early and the interrupt decode register not being cleared if the FIFO is now empty. Signed-off-by: Russell Joyce Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-xilinx.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index f1a06a091ccb..dcb9b57ed7ea 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c @@ -449,14 +449,17 @@ static irqreturn_t xilinx_pcie_intr_handler(int irq, void *data) return IRQ_HANDLED; } - /* Clear interrupt FIFO register 1 */ - pcie_write(port, XILINX_PCIE_RPIFR1_ALL_MASK, - XILINX_PCIE_REG_RPIFR1); - - /* Handle INTx Interrupt */ - val = ((val & XILINX_PCIE_RPIFR1_INTR_MASK) >> - XILINX_PCIE_RPIFR1_INTR_SHIFT) + 1; - generic_handle_irq(irq_find_mapping(port->irq_domain, val)); + if (!(val & XILINX_PCIE_RPIFR1_MSI_INTR)) { + /* Clear interrupt FIFO register 1 */ + pcie_write(port, XILINX_PCIE_RPIFR1_ALL_MASK, + XILINX_PCIE_REG_RPIFR1); + + /* Handle INTx Interrupt */ + val = ((val & XILINX_PCIE_RPIFR1_INTR_MASK) >> + XILINX_PCIE_RPIFR1_INTR_SHIFT) + 1; + generic_handle_irq(irq_find_mapping(port->irq_domain, + val)); + } } if (status & XILINX_PCIE_INTR_MSI) { -- cgit v1.3-6-gb490 From 498c43949c7b8f57e0afb8195019cf5a7ba72de0 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Mon, 20 Jul 2015 10:14:08 -0600 Subject: NVMe: Unify SQ entry writing and doorbell ringing This patch changes sq_cmd writers to instead create their command on the stack. __nvme_submit_cmd copies the sq entry to the queue and writes the doorbell. Signed-off-by: Jon Derrick Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/block/nvme-core.c | 80 +++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index d844ec4a2b85..e09ad6cc6dec 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -730,18 +730,16 @@ static int nvme_setup_prps(struct nvme_dev *dev, struct nvme_iod *iod, static void nvme_submit_priv(struct nvme_queue *nvmeq, struct request *req, struct nvme_iod *iod) { - struct nvme_command *cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail]; + struct nvme_command cmnd; - memcpy(cmnd, req->cmd, sizeof(struct nvme_command)); - cmnd->rw.command_id = req->tag; + memcpy(&cmnd, req->cmd, sizeof(cmnd)); + cmnd.rw.command_id = req->tag; if (req->nr_phys_segments) { - cmnd->rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); - cmnd->rw.prp2 = cpu_to_le64(iod->first_dma); + cmnd.rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); + cmnd.rw.prp2 = cpu_to_le64(iod->first_dma); } - if (++nvmeq->sq_tail == nvmeq->q_depth) - nvmeq->sq_tail = 0; - writel(nvmeq->sq_tail, nvmeq->q_db); + __nvme_submit_cmd(nvmeq, &cmnd); } /* @@ -754,45 +752,41 @@ static void nvme_submit_discard(struct nvme_queue *nvmeq, struct nvme_ns *ns, { struct nvme_dsm_range *range = (struct nvme_dsm_range *)iod_list(iod)[0]; - struct nvme_command *cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail]; + struct nvme_command cmnd; range->cattr = cpu_to_le32(0); range->nlb = cpu_to_le32(blk_rq_bytes(req) >> ns->lba_shift); range->slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req))); - memset(cmnd, 0, sizeof(*cmnd)); - cmnd->dsm.opcode = nvme_cmd_dsm; - cmnd->dsm.command_id = req->tag; - cmnd->dsm.nsid = cpu_to_le32(ns->ns_id); - cmnd->dsm.prp1 = cpu_to_le64(iod->first_dma); - cmnd->dsm.nr = 0; - cmnd->dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD); + memset(&cmnd, 0, sizeof(cmnd)); + cmnd.dsm.opcode = nvme_cmd_dsm; + cmnd.dsm.command_id = req->tag; + cmnd.dsm.nsid = cpu_to_le32(ns->ns_id); + cmnd.dsm.prp1 = cpu_to_le64(iod->first_dma); + cmnd.dsm.nr = 0; + cmnd.dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD); - if (++nvmeq->sq_tail == nvmeq->q_depth) - nvmeq->sq_tail = 0; - writel(nvmeq->sq_tail, nvmeq->q_db); + __nvme_submit_cmd(nvmeq, &cmnd); } static void nvme_submit_flush(struct nvme_queue *nvmeq, struct nvme_ns *ns, int cmdid) { - struct nvme_command *cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail]; + struct nvme_command cmnd; - memset(cmnd, 0, sizeof(*cmnd)); - cmnd->common.opcode = nvme_cmd_flush; - cmnd->common.command_id = cmdid; - cmnd->common.nsid = cpu_to_le32(ns->ns_id); + memset(&cmnd, 0, sizeof(cmnd)); + cmnd.common.opcode = nvme_cmd_flush; + cmnd.common.command_id = cmdid; + cmnd.common.nsid = cpu_to_le32(ns->ns_id); - if (++nvmeq->sq_tail == nvmeq->q_depth) - nvmeq->sq_tail = 0; - writel(nvmeq->sq_tail, nvmeq->q_db); + __nvme_submit_cmd(nvmeq, &cmnd); } static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod, struct nvme_ns *ns) { struct request *req = iod_get_private(iod); - struct nvme_command *cmnd; + struct nvme_command cmnd; u16 control = 0; u32 dsmgmt = 0; @@ -804,19 +798,17 @@ static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod, if (req->cmd_flags & REQ_RAHEAD) dsmgmt |= NVME_RW_DSM_FREQ_PREFETCH; - cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail]; - memset(cmnd, 0, sizeof(*cmnd)); - - cmnd->rw.opcode = (rq_data_dir(req) ? nvme_cmd_write : nvme_cmd_read); - cmnd->rw.command_id = req->tag; - cmnd->rw.nsid = cpu_to_le32(ns->ns_id); - cmnd->rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); - cmnd->rw.prp2 = cpu_to_le64(iod->first_dma); - cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req))); - cmnd->rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1); + memset(&cmnd, 0, sizeof(cmnd)); + cmnd.rw.opcode = (rq_data_dir(req) ? nvme_cmd_write : nvme_cmd_read); + cmnd.rw.command_id = req->tag; + cmnd.rw.nsid = cpu_to_le32(ns->ns_id); + cmnd.rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); + cmnd.rw.prp2 = cpu_to_le64(iod->first_dma); + cmnd.rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req))); + cmnd.rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1); if (blk_integrity_rq(req)) { - cmnd->rw.metadata = cpu_to_le64(sg_dma_address(iod->meta_sg)); + cmnd.rw.metadata = cpu_to_le64(sg_dma_address(iod->meta_sg)); switch (ns->pi_type) { case NVME_NS_DPS_PI_TYPE3: control |= NVME_RW_PRINFO_PRCHK_GUARD; @@ -825,19 +817,17 @@ static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod, case NVME_NS_DPS_PI_TYPE2: control |= NVME_RW_PRINFO_PRCHK_GUARD | NVME_RW_PRINFO_PRCHK_REF; - cmnd->rw.reftag = cpu_to_le32( + cmnd.rw.reftag = cpu_to_le32( nvme_block_nr(ns, blk_rq_pos(req))); break; } } else if (ns->ms) control |= NVME_RW_PRINFO_PRACT; - cmnd->rw.control = cpu_to_le16(control); - cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt); + cmnd.rw.control = cpu_to_le16(control); + cmnd.rw.dsmgmt = cpu_to_le32(dsmgmt); - if (++nvmeq->sq_tail == nvmeq->q_depth) - nvmeq->sq_tail = 0; - writel(nvmeq->sq_tail, nvmeq->q_db); + __nvme_submit_cmd(nvmeq, &cmnd); return 0; } -- cgit v1.3-6-gb490 From 8ffaadf7429270914b8f146ec13cf305e01df20d Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Mon, 20 Jul 2015 10:14:09 -0600 Subject: NVMe: Use CMB for the IO SQes if available Some controllers have a controller-side memory buffer available for use for submissions, completions, lists, or data. If a CMB is available, the entire CMB will be ioremapped and it will attempt to map the IO SQes onto the CMB. The queues will be shrunk as needed. The CMB will not be used if the queue depth is shrunk below some threshold where it may have reduced performance over a larger queue in system memory. Signed-off-by: Jon Derrick Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/block/nvme-core.c | 122 ++++++++++++++++++++++++++++++++++++++++++++-- include/linux/nvme.h | 17 +++++++ 2 files changed, 134 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index e09ad6cc6dec..82b4ffb6eefa 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -72,6 +72,10 @@ module_param(nvme_char_major, int, 0); static int use_threaded_interrupts; module_param(use_threaded_interrupts, int, 0); +static bool use_cmb_sqes = true; +module_param(use_cmb_sqes, bool, 0644); +MODULE_PARM_DESC(use_cmb_sqes, "use controller's memory buffer for I/O SQes"); + static DEFINE_SPINLOCK(dev_list_lock); static LIST_HEAD(dev_list); static struct task_struct *nvme_thread; @@ -103,6 +107,7 @@ struct nvme_queue { char irqname[24]; /* nvme4294967295-65535\0 */ spinlock_t q_lock; struct nvme_command *sq_cmds; + struct nvme_command __iomem *sq_cmds_io; volatile struct nvme_completion *cqes; struct blk_mq_tags **tags; dma_addr_t sq_dma_addr; @@ -383,7 +388,11 @@ static int __nvme_submit_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd) { u16 tail = nvmeq->sq_tail; - memcpy(&nvmeq->sq_cmds[tail], cmd, sizeof(*cmd)); + if (nvmeq->sq_cmds_io) + memcpy_toio(&nvmeq->sq_cmds_io[tail], cmd, sizeof(*cmd)); + else + memcpy(&nvmeq->sq_cmds[tail], cmd, sizeof(*cmd)); + if (++tail == nvmeq->q_depth) tail = 0; writel(tail, nvmeq->q_db); @@ -1364,7 +1373,8 @@ static void nvme_free_queue(struct nvme_queue *nvmeq) { dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth), (void *)nvmeq->cqes, nvmeq->cq_dma_addr); - dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), + if (nvmeq->sq_cmds) + dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), nvmeq->sq_cmds, nvmeq->sq_dma_addr); kfree(nvmeq); } @@ -1437,6 +1447,46 @@ static void nvme_disable_queue(struct nvme_dev *dev, int qid) spin_unlock_irq(&nvmeq->q_lock); } +static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues, + int entry_size) +{ + int q_depth = dev->q_depth; + unsigned q_size_aligned = roundup(q_depth * entry_size, dev->page_size); + + if (q_size_aligned * nr_io_queues > dev->cmb_size) { + q_depth = rounddown(dev->cmb_size / nr_io_queues, + dev->page_size) / entry_size; + + /* + * Ensure the reduced q_depth is above some threshold where it + * would be better to map queues in system memory with the + * original depth + */ + if (q_depth < 64) + return -ENOMEM; + } + + return q_depth; +} + +static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq, + int qid, int depth) +{ + if (qid && dev->cmb && use_cmb_sqes && NVME_CMB_SQS(dev->cmbsz)) { + unsigned offset = (qid - 1) * + roundup(SQ_SIZE(depth), dev->page_size); + nvmeq->sq_dma_addr = dev->cmb_dma_addr + offset; + nvmeq->sq_cmds_io = dev->cmb + offset; + } else { + nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth), + &nvmeq->sq_dma_addr, GFP_KERNEL); + if (!nvmeq->sq_cmds) + return -ENOMEM; + } + + return 0; +} + static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, int depth) { @@ -1449,9 +1499,7 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, if (!nvmeq->cqes) goto free_nvmeq; - nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth), - &nvmeq->sq_dma_addr, GFP_KERNEL); - if (!nvmeq->sq_cmds) + if (nvme_alloc_sq_cmds(dev, nvmeq, qid, depth)) goto free_cqdma; nvmeq->q_dmadev = dev->dev; @@ -2149,6 +2197,58 @@ static int set_queue_count(struct nvme_dev *dev, int count) return min(result & 0xffff, result >> 16) + 1; } +static void __iomem *nvme_map_cmb(struct nvme_dev *dev) +{ + u64 szu, size, offset; + u32 cmbloc; + resource_size_t bar_size; + struct pci_dev *pdev = to_pci_dev(dev->dev); + void __iomem *cmb; + dma_addr_t dma_addr; + + if (!use_cmb_sqes) + return NULL; + + dev->cmbsz = readl(&dev->bar->cmbsz); + if (!(NVME_CMB_SZ(dev->cmbsz))) + return NULL; + + cmbloc = readl(&dev->bar->cmbloc); + + szu = (u64)1 << (12 + 4 * NVME_CMB_SZU(dev->cmbsz)); + size = szu * NVME_CMB_SZ(dev->cmbsz); + offset = szu * NVME_CMB_OFST(cmbloc); + bar_size = pci_resource_len(pdev, NVME_CMB_BIR(cmbloc)); + + if (offset > bar_size) + return NULL; + + /* + * Controllers may support a CMB size larger than their BAR, + * for example, due to being behind a bridge. Reduce the CMB to + * the reported size of the BAR + */ + if (size > bar_size - offset) + size = bar_size - offset; + + dma_addr = pci_resource_start(pdev, NVME_CMB_BIR(cmbloc)) + offset; + cmb = ioremap_wc(dma_addr, size); + if (!cmb) + return NULL; + + dev->cmb_dma_addr = dma_addr; + dev->cmb_size = size; + return cmb; +} + +static inline void nvme_release_cmb(struct nvme_dev *dev) +{ + if (dev->cmb) { + iounmap(dev->cmb); + dev->cmb = NULL; + } +} + static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues) { return 4096 + ((nr_io_queues + 1) * 8 * dev->db_stride); @@ -2167,6 +2267,15 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) if (result < nr_io_queues) nr_io_queues = result; + if (dev->cmb && NVME_CMB_SQS(dev->cmbsz)) { + result = nvme_cmb_qdepth(dev, nr_io_queues, + sizeof(struct nvme_command)); + if (result > 0) + dev->q_depth = result; + else + nvme_release_cmb(dev); + } + size = db_bar_size(dev, nr_io_queues); if (size > 8192) { iounmap(dev->bar); @@ -2430,6 +2539,8 @@ static int nvme_dev_map(struct nvme_dev *dev) dev->q_depth = min_t(int, NVME_CAP_MQES(cap) + 1, NVME_Q_DEPTH); dev->db_stride = 1 << NVME_CAP_STRIDE(cap); dev->dbs = ((void __iomem *)dev->bar) + 4096; + if (readl(&dev->bar->vs) >= NVME_VS(1, 2)) + dev->cmb = nvme_map_cmb(dev); return 0; @@ -3135,6 +3246,7 @@ static void nvme_remove(struct pci_dev *pdev) nvme_dev_remove_admin(dev); device_destroy(nvme_class, MKDEV(nvme_char_major, dev->instance)); nvme_free_queues(dev, 0); + nvme_release_cmb(dev); nvme_release_prp_pools(dev); kref_put(&dev->kref, nvme_free_dev); } diff --git a/include/linux/nvme.h b/include/linux/nvme.h index c0d94ed8ce9a..fa3fe160c6cb 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -32,6 +32,8 @@ struct nvme_bar { __u32 aqa; /* Admin Queue Attributes */ __u64 asq; /* Admin SQ Base Address */ __u64 acq; /* Admin CQ Base Address */ + __u32 cmbloc; /* Controller Memory Buffer Location */ + __u32 cmbsz; /* Controller Memory Buffer Size */ }; #define NVME_CAP_MQES(cap) ((cap) & 0xffff) @@ -40,6 +42,17 @@ struct nvme_bar { #define NVME_CAP_MPSMIN(cap) (((cap) >> 48) & 0xf) #define NVME_CAP_MPSMAX(cap) (((cap) >> 52) & 0xf) +#define NVME_CMB_BIR(cmbloc) ((cmbloc) & 0x7) +#define NVME_CMB_OFST(cmbloc) (((cmbloc) >> 12) & 0xfffff) +#define NVME_CMB_SZ(cmbsz) (((cmbsz) >> 12) & 0xfffff) +#define NVME_CMB_SZU(cmbsz) (((cmbsz) >> 8) & 0xf) + +#define NVME_CMB_WDS(cmbsz) ((cmbsz) & 0x10) +#define NVME_CMB_RDS(cmbsz) ((cmbsz) & 0x8) +#define NVME_CMB_LISTS(cmbsz) ((cmbsz) & 0x4) +#define NVME_CMB_CQS(cmbsz) ((cmbsz) & 0x2) +#define NVME_CMB_SQS(cmbsz) ((cmbsz) & 0x1) + enum { NVME_CC_ENABLE = 1 << 0, NVME_CC_CSS_NVM = 0 << 4, @@ -100,6 +113,10 @@ struct nvme_dev { u32 max_hw_sectors; u32 stripe_size; u32 page_size; + void __iomem *cmb; + dma_addr_t cmb_dma_addr; + u64 cmb_size; + u32 cmbsz; u16 oncs; u16 abort_limit; u8 event_limit; -- cgit v1.3-6-gb490 From ccbc175aad819e1d4b6af6246b12d55b13d97815 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 7 Jul 2015 12:24:35 -0700 Subject: PCI: Restore ACS configuration as part of pci_restore_state() Previously we did not restore ACS state after a PCIe reset. This meant that we could not reassign interfaces after a system suspend because the D0->D3 transition disabled ACS, and we didn't restore it when going back to D0. Restore ACS configuration in pci_restore_state(). [bhelgaas: changelog] Signed-off-by: Alexander Duyck Signed-off-by: Bjorn Helgaas CC: Allen Kay CC: Chris Wright CC: Alex Williamson --- drivers/pci/pci.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0008c950452c..9bd9526f3388 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1092,6 +1092,9 @@ void pci_restore_state(struct pci_dev *dev) pci_restore_pcix_state(dev); pci_restore_msi_state(dev); + + /* Restore ACS and IOV configuration state */ + pci_enable_acs(dev); pci_restore_iov_state(dev); dev->state_saved = false; -- cgit v1.3-6-gb490 From 604d4994277f3526c8ec7ba16f32e236d5ca3e78 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Jul 2015 16:46:24 +0200 Subject: regulator: rk808: add #include for gpiod functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a build problem on mips found by the kbuild test robot: drivers/regulator/rk808-regulator.c: In function 'rk808_buck1_2_get_voltage_sel_regmap': drivers/regulator/rk808-regulator.c:97:2: error: implicit declaration of function 'gpiod_get_value' [-Werror=implicit-function-declaration] if (IS_ERR(gpio) || gpiod_get_value(gpio) == 0) ^ Fixes: bad47ad2eef3 ("regulator: rk808: fixed the overshoot when adjust voltage") Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown --- drivers/regulator/rk808-regulator.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index ca913fd15598..ac9436d2ea8d 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -25,6 +25,7 @@ #include #include #include +#include /* Field Definitions */ #define RK808_BUCK_VSEL_MASK 0x3f -- cgit v1.3-6-gb490 From a13eaf02e2d6326a59f142db329faf4efb527e79 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 21 Jul 2015 16:46:25 +0200 Subject: regulator: rk808: make better use of the gpiod API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gpiod functions include variants for managed gpiod resources. Use it to simplify the remove function. As the driver handles a device node without a specification of dvs gpios just fine, additionally use the variant of gpiod_get exactly for this use case. This makes error checking more strict. As a third benefit this patch makes the driver use the flags parameter of gpiod_get* which will not be optional any more after 4.2 and so prevents a build failure when the respective gpiod commit is merged. Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown --- drivers/regulator/rk808-regulator.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index ac9436d2ea8d..d86a3dcd61e2 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -95,7 +95,7 @@ static int rk808_buck1_2_get_voltage_sel_regmap(struct regulator_dev *rdev) unsigned int val; int ret; - if (IS_ERR(gpio) || gpiod_get_value(gpio) == 0) + if (!gpio || gpiod_get_value(gpio) == 0) return regulator_get_voltage_sel_regmap(rdev); ret = regmap_read(rdev->regmap, @@ -169,7 +169,7 @@ static int rk808_buck1_2_set_voltage_sel(struct regulator_dev *rdev, unsigned old_sel; int ret, gpio_level; - if (IS_ERR(gpio)) + if (!gpio) return rk808_buck1_2_i2c_set_voltage_sel(rdev, sel); gpio_level = gpiod_get_value(gpio); @@ -206,7 +206,7 @@ static int rk808_buck1_2_set_voltage_time_sel(struct regulator_dev *rdev, struct gpio_desc *gpio = pdata->dvs_gpio[id]; /* if there is no dvs1/2 pin, we don't need wait extra time here. */ - if (IS_ERR(gpio)) + if (!gpio) return 0; return regulator_set_voltage_time_sel(rdev, old_selector, new_selector); @@ -541,14 +541,20 @@ static int rk808_regulator_dt_parse_pdata(struct device *dev, goto dt_parse_end; for (i = 0; i < ARRAY_SIZE(pdata->dvs_gpio); i++) { - pdata->dvs_gpio[i] = gpiod_get_index(client_dev, "dvs", i); + pdata->dvs_gpio[i] = + devm_gpiod_get_index_optional(client_dev, "dvs", i, + GPIOD_OUT_LOW); if (IS_ERR(pdata->dvs_gpio[i])) { + ret = PTR_ERR(pdata->dvs_gpio[i]); + dev_err(dev, "failed to get dvs%d gpio (%d)\n", i, ret); + goto dt_parse_end; + } + + if (!pdata->dvs_gpio[i]) { dev_warn(dev, "there is no dvs%d gpio\n", i); continue; } - gpiod_direction_output(pdata->dvs_gpio[i], 0); - tmp = i ? RK808_DVS2_POL : RK808_DVS1_POL; ret = regmap_update_bits(map, RK808_IO_POL_REG, tmp, gpiod_is_active_low(pdata->dvs_gpio[i]) ? @@ -560,19 +566,6 @@ dt_parse_end: return ret; } -static int rk808_regulator_remove(struct platform_device *pdev) -{ - struct rk808_regulator_data *pdata = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < ARRAY_SIZE(pdata->dvs_gpio); i++) { - if (!IS_ERR(pdata->dvs_gpio[i])) - gpiod_put(pdata->dvs_gpio[i]); - } - - return 0; -} - static int rk808_regulator_probe(struct platform_device *pdev) { struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); @@ -619,7 +612,6 @@ static int rk808_regulator_probe(struct platform_device *pdev) static struct platform_driver rk808_regulator_driver = { .probe = rk808_regulator_probe, - .remove = rk808_regulator_remove, .driver = { .name = "rk808-regulator", .owner = THIS_MODULE, -- cgit v1.3-6-gb490 From 8ef54f27f6f425fa8deedc237d99b9daf41d68d2 Mon Sep 17 00:00:00 2001 From: Duc Dang Date: Thu, 9 Jul 2015 14:20:12 -0700 Subject: PCI: xgene: Add support for a 64-bit prefetchable memory window X-Gene PCIe controller has registers to support multiple memory ranges. Add support for a 64-bit prefetchable memory window. [bhelgaas: changelog] Signed-off-by: Duc Dang Signed-off-by: Tanmay Inamdar Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pci-xgene.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index a9dfb70d623a..55fe86548d77 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c @@ -321,8 +321,16 @@ static int xgene_pcie_map_ranges(struct xgene_pcie_port *port, return ret; break; case IORESOURCE_MEM: - xgene_pcie_setup_ob_reg(port, res, OMR1BARL, res->start, - res->start - window->offset); + if (res->flags & IORESOURCE_PREFETCH) + xgene_pcie_setup_ob_reg(port, res, OMR2BARL, + res->start, + res->start - + window->offset); + else + xgene_pcie_setup_ob_reg(port, res, OMR1BARL, + res->start, + res->start - + window->offset); break; case IORESOURCE_BUS: break; -- cgit v1.3-6-gb490 From 43163022927b6e7d202a7e6f939c3f392465494d Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 19 May 2015 14:38:22 -0700 Subject: mtd: m25p80: allow arbitrary OF matching for "jedec,spi-nor" When we added the "jedec,spi-nor" compatible string for use in this driver, we added it as a modalias option. The modalias can be derived in different ways for platform devices vs. device tree (of_*) matching. But for device tree matching (the primary target of this identifier string), the modalias is determined from the first entry in the 'compatible' property. IOW, the following properties would bind to this driver: // Option (a), modalias = "spi-nor" compatible = "jedec,spi-nor"; // Option (b), modalias = "spi-nor" compatible = "idontknowwhatimdoing,spi-nor"; But the following would not: // Option (c), modalias = "shinynewdevice" compatible = "myvendor,shinynewdevice", "jedec,spi-nor"; So, we'd like to match (a) and (c) (even when we don't have an explicit entry for "shinynewdevice"), and we'd rather not allow (b). To do this, we (1) always (for devices without specific platform data) pass the modalias to the spi-nor library; (2) rework the spi-nor library to not reject "bad" names, and instead just fall back to autodetection; and (3) add the .of_match_table to properly catch all "jedec,spi-nor". This allows (a) and (c) without warnings, and rejects (b). Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 18 +++++++++++------- drivers/mtd/spi-nor/spi-nor.c | 8 ++++---- 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index d313f948b96c..9cd3631170ef 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -223,8 +223,6 @@ static int m25p_probe(struct spi_device *spi) */ if (data && data->type) flash_name = data->type; - else if (!strcmp(spi->modalias, "spi-nor")) - flash_name = NULL; /* auto-detect */ else flash_name = spi->modalias; @@ -289,19 +287,25 @@ static const struct spi_device_id m25p_ids[] = { {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, - /* - * Generic support for SPI NOR that can be identified by the JEDEC READ - * ID opcode (0x9F). Use this, if possible. - */ - {"spi-nor"}, { }, }; MODULE_DEVICE_TABLE(spi, m25p_ids); +static const struct of_device_id m25p_of_table[] = { + /* + * Generic compatibility for SPI NOR that can be identified by the + * JEDEC READ ID opcode (0x9F). Use this, if possible. + */ + { .compatible = "jedec,spi-nor" }, + {} +}; +MODULE_DEVICE_TABLE(of, m25p_of_table); + static struct spi_driver m25p80_driver = { .driver = { .name = "m25p80", .owner = THIS_MODULE, + .of_match_table = m25p_of_table, }, .id_table = m25p_ids, .probe = m25p_probe, diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b2e8c3b72ea1..47516d3af015 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1015,11 +1015,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) if (ret) return ret; - /* Try to auto-detect if chip name wasn't specified */ - if (!name) - id = spi_nor_read_id(nor); - else + if (name) id = spi_nor_match_id(name); + /* Try to auto-detect if chip name wasn't specified or not found */ + if (!id) + id = spi_nor_read_id(nor); if (IS_ERR_OR_NULL(id)) return -ENOENT; -- cgit v1.3-6-gb490 From ee122c79d4227f6ec642157834b6a90fcffa4382 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:43:58 +0200 Subject: vxlan: Flow based tunneling Allows putting a VXLAN device into a new flow-based mode in which skbs with a ip_tunnel_info dst metadata attached will be encapsulated according to the instructions stored in there with the VXLAN device defaults taken into consideration. Similar on the receive side, if the VXLAN_F_COLLECT_METADATA flag is set, the packet processing will populate a ip_tunnel_info struct for each packet received and attach it to the skb using the new metadata dst. The metadata structure will contain the outer header and tunnel header fields which have been stripped off. Layers further up in the stack such as routing, tc or netfitler can later match on these fields and perform forwarding. It is the responsibility of upper layers to ensure that the flag is set if the metadata is needed. The flag limits the additional cost of metadata collecting based on demand. This prepares the VXLAN device to be steered by the routing and other subsystems which allows to support encapsulation for a large number of tunnel endpoints and tunnel ids through a single net_device which improves the scalability. It also allows for OVS to leverage this mode which in turn allows for the removal of the OVS specific VXLAN code. Because the skb is currently scrubed in vxlan_rcv(), the attachment of the new dst metadata is postponed until after scrubing which requires the temporary addition of a new member to vxlan_metadata. This member is removed again in a later commit after the indirect VXLAN receive API has been removed. Signed-off-by: Thomas Graf Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 149 ++++++++++++++++++++++++++++++++++++------- include/linux/skbuff.h | 1 + include/net/dst_metadata.h | 13 ++++ include/net/ip_tunnels.h | 14 ++++ include/net/vxlan.h | 10 ++- include/uapi/linux/if_link.h | 1 + 6 files changed, 165 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index ec86a11743fd..06c092b05a51 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -49,6 +49,7 @@ #include #include #endif +#include #define VXLAN_VERSION "0.1" @@ -140,6 +141,11 @@ struct vxlan_dev { static u32 vxlan_salt __read_mostly; static struct workqueue_struct *vxlan_wq; +static inline bool vxlan_collect_metadata(struct vxlan_sock *vs) +{ + return vs->flags & VXLAN_F_COLLECT_METADATA; +} + #if IS_ENABLED(CONFIG_IPV6) static inline bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b) @@ -1164,10 +1170,13 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, /* Callback from net/ipv4/udp.c to receive packets */ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) { + struct metadata_dst *tun_dst = NULL; + struct ip_tunnel_info *info; struct vxlan_sock *vs; struct vxlanhdr *vxh; u32 flags, vni; - struct vxlan_metadata md = {0}; + struct vxlan_metadata _md; + struct vxlan_metadata *md = &_md; /* Need Vxlan and inner Ethernet header to be present */ if (!pskb_may_pull(skb, VXLAN_HLEN)) @@ -1202,6 +1211,33 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) vni &= VXLAN_VNI_MASK; } + if (vxlan_collect_metadata(vs)) { + const struct iphdr *iph = ip_hdr(skb); + + tun_dst = metadata_dst_alloc(sizeof(*md), GFP_ATOMIC); + if (!tun_dst) + goto drop; + + info = &tun_dst->u.tun_info; + info->key.ipv4_src = iph->saddr; + info->key.ipv4_dst = iph->daddr; + info->key.ipv4_tos = iph->tos; + info->key.ipv4_ttl = iph->ttl; + info->key.tp_src = udp_hdr(skb)->source; + info->key.tp_dst = udp_hdr(skb)->dest; + + info->mode = IP_TUNNEL_INFO_RX; + info->key.tun_flags = TUNNEL_KEY; + info->key.tun_id = cpu_to_be64(vni >> 8); + if (udp_hdr(skb)->check != 0) + info->key.tun_flags |= TUNNEL_CSUM; + + md = ip_tunnel_info_opts(info, sizeof(*md)); + md->tun_dst = tun_dst; + } else { + memset(md, 0, sizeof(*md)); + } + /* For backwards compatibility, only allow reserved fields to be * used by VXLAN extensions if explicitly requested. */ @@ -1209,13 +1245,16 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) struct vxlanhdr_gbp *gbp; gbp = (struct vxlanhdr_gbp *)vxh; - md.gbp = ntohs(gbp->policy_id); + md->gbp = ntohs(gbp->policy_id); + + if (tun_dst) + info->key.tun_flags |= TUNNEL_VXLAN_OPT; if (gbp->dont_learn) - md.gbp |= VXLAN_GBP_DONT_LEARN; + md->gbp |= VXLAN_GBP_DONT_LEARN; if (gbp->policy_applied) - md.gbp |= VXLAN_GBP_POLICY_APPLIED; + md->gbp |= VXLAN_GBP_POLICY_APPLIED; flags &= ~VXLAN_GBP_USED_BITS; } @@ -1233,8 +1272,8 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) goto bad_flags; } - md.vni = vxh->vx_vni; - vs->rcv(vs, skb, &md); + md->vni = vxh->vx_vni; + vs->rcv(vs, skb, md); return 0; drop: @@ -1247,6 +1286,9 @@ bad_flags: ntohl(vxh->vx_flags), ntohl(vxh->vx_vni)); error: + if (tun_dst) + dst_release((struct dst_entry *)tun_dst); + /* Return non vxlan pkt */ return 1; } @@ -1263,7 +1305,12 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, int err = 0; union vxlan_addr *remote_ip; - vni = ntohl(md->vni) >> 8; + /* For flow based devices, map all packets to VNI 0 */ + if (vs->flags & VXLAN_F_FLOW_BASED) + vni = 0; + else + vni = ntohl(md->vni) >> 8; + /* Is this VNI defined? */ vxlan = vxlan_vs_find_vni(vs, vni); if (!vxlan) @@ -1292,12 +1339,19 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, #endif } + if (md->tun_dst) { + skb_dst_set(skb, (struct dst_entry *)md->tun_dst); + md->tun_dst = NULL; + } + if ((vxlan->flags & VXLAN_F_LEARN) && vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source)) goto drop; skb_reset_network_header(skb); - skb->mark = md->gbp; + /* In flow-based mode, GBP is carried in dst_metadata */ + if (!(vs->flags & VXLAN_F_FLOW_BASED)) + skb->mark = md->gbp; if (oip6) err = IP6_ECN_decapsulate(oip6, skb); @@ -1330,6 +1384,9 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, return; drop: + if (md->tun_dst) + dst_release((struct dst_entry *)md->tun_dst); + /* Consume bad packet */ kfree_skb(skb); } @@ -1878,22 +1935,40 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct vxlan_rdst *rdst, bool did_rsc) { + struct ip_tunnel_info *info = skb_tunnel_info(skb); struct vxlan_dev *vxlan = netdev_priv(dev); struct sock *sk = vxlan->vn_sock->sock->sk; struct rtable *rt = NULL; const struct iphdr *old_iph; struct flowi4 fl4; union vxlan_addr *dst; - struct vxlan_metadata md; + union vxlan_addr remote_ip; + struct vxlan_metadata _md; + struct vxlan_metadata *md = &_md; __be16 src_port = 0, dst_port; u32 vni; __be16 df = 0; __u8 tos, ttl; int err; + u32 flags = vxlan->flags; - dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port; - vni = rdst->remote_vni; - dst = &rdst->remote_ip; + if (rdst) { + dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port; + vni = rdst->remote_vni; + dst = &rdst->remote_ip; + } else { + if (!info) { + WARN_ONCE(1, "%s: Missing encapsulation instructions\n", + dev->name); + goto drop; + } + + dst_port = info->key.tp_dst ? : vxlan->dst_port; + vni = be64_to_cpu(info->key.tun_id); + remote_ip.sin.sin_family = AF_INET; + remote_ip.sin.sin_addr.s_addr = info->key.ipv4_dst; + dst = &remote_ip; + } if (vxlan_addr_any(dst)) { if (did_rsc) { @@ -1918,8 +1993,25 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, vxlan->port_max, true); if (dst->sa.sa_family == AF_INET) { + if (info) { + if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT) + df = htons(IP_DF); + if (info->key.tun_flags & TUNNEL_CSUM) + flags |= VXLAN_F_UDP_CSUM; + else + flags &= ~VXLAN_F_UDP_CSUM; + + ttl = info->key.ipv4_ttl; + tos = info->key.ipv4_tos; + + if (info->options_len) + md = ip_tunnel_info_opts(info, sizeof(*md)); + } else { + md->gbp = skb->mark; + } + memset(&fl4, 0, sizeof(fl4)); - fl4.flowi4_oif = rdst->remote_ifindex; + fl4.flowi4_oif = rdst ? rdst->remote_ifindex : 0; fl4.flowi4_tos = RT_TOS(tos); fl4.flowi4_mark = skb->mark; fl4.flowi4_proto = IPPROTO_UDP; @@ -1958,14 +2050,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); - md.vni = htonl(vni << 8); - md.gbp = skb->mark; - + md->vni = htonl(vni << 8); err = vxlan_xmit_skb(rt, sk, skb, fl4.saddr, dst->sin.sin_addr.s_addr, tos, ttl, df, - src_port, dst_port, &md, + src_port, dst_port, md, !net_eq(vxlan->net, dev_net(vxlan->dev)), - vxlan->flags); + flags); if (err < 0) { /* skb is already freed. */ skb = NULL; @@ -1980,7 +2070,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, u32 flags; memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_oif = rdst->remote_ifindex; + fl6.flowi6_oif = rdst ? rdst->remote_ifindex : 0; fl6.daddr = dst->sin6.sin6_addr; fl6.saddr = vxlan->saddr.sin6.sin6_addr; fl6.flowi6_mark = skb->mark; @@ -2018,11 +2108,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } ttl = ttl ? : ip6_dst_hoplimit(ndst); - md.vni = htonl(vni << 8); - md.gbp = skb->mark; + md->vni = htonl(vni << 8); + md->gbp = skb->mark; err = vxlan6_xmit_skb(ndst, sk, skb, dev, &fl6.saddr, &fl6.daddr, - 0, ttl, src_port, dst_port, &md, + 0, ttl, src_port, dst_port, md, !net_eq(vxlan->net, dev_net(vxlan->dev)), vxlan->flags); #endif @@ -2051,6 +2141,7 @@ tx_free: static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); + const struct ip_tunnel_info *info = skb_tunnel_info(skb); struct ethhdr *eth; bool did_rsc = false; struct vxlan_rdst *rdst, *fdst = NULL; @@ -2078,6 +2169,12 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) #endif } + if (vxlan->flags & VXLAN_F_FLOW_BASED && + info && info->mode == IP_TUNNEL_INFO_TX) { + vxlan_xmit_one(skb, dev, NULL, false); + return NETDEV_TX_OK; + } + f = vxlan_find_mac(vxlan, eth->h_dest); did_rsc = false; @@ -2405,6 +2502,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_RSC] = { .type = NLA_U8 }, [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 }, [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 }, + [IFLA_VXLAN_FLOWBASED] = { .type = NLA_U8 }, [IFLA_VXLAN_PORT] = { .type = NLA_U16 }, [IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 }, [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 }, @@ -2681,6 +2779,10 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, if (data[IFLA_VXLAN_LIMIT]) vxlan->addrmax = nla_get_u32(data[IFLA_VXLAN_LIMIT]); + if (data[IFLA_VXLAN_FLOWBASED] && + nla_get_u8(data[IFLA_VXLAN_FLOWBASED])) + vxlan->flags |= VXLAN_F_FLOW_BASED; + if (data[IFLA_VXLAN_PORT_RANGE]) { const struct ifla_vxlan_port_range *p = nla_data(data[IFLA_VXLAN_PORT_RANGE]); @@ -2777,6 +2879,7 @@ static size_t vxlan_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_RSC */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_L2MISS */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_L3MISS */ + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_FLOWBASED */ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_AGEING */ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LIMIT */ nla_total_size(sizeof(struct ifla_vxlan_port_range)) + @@ -2843,6 +2946,8 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) !!(vxlan->flags & VXLAN_F_L2MISS)) || nla_put_u8(skb, IFLA_VXLAN_L3MISS, !!(vxlan->flags & VXLAN_F_L3MISS)) || + nla_put_u8(skb, IFLA_VXLAN_FLOWBASED, + !!(vxlan->flags & VXLAN_F_FLOW_BASED)) || nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->age_interval) || nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax) || nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->dst_port) || diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 6bd96fe9416a..648a2c241993 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3469,5 +3469,6 @@ static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb) skb_network_header(skb); return hdr_len + skb_gso_transport_seglen(skb); } + #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index 4f7694f3c7d0..e843937fb30a 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -8,6 +8,9 @@ struct metadata_dst { struct dst_entry dst; size_t opts_len; + union { + struct ip_tunnel_info tun_info; + } u; }; static inline struct metadata_dst *skb_metadata_dst(struct sk_buff *skb) @@ -20,6 +23,16 @@ static inline struct metadata_dst *skb_metadata_dst(struct sk_buff *skb) return NULL; } +static inline struct ip_tunnel_info *skb_tunnel_info(struct sk_buff *skb) +{ + struct metadata_dst *md_dst = skb_metadata_dst(skb); + + if (md_dst) + return &md_dst->u.tun_info; + + return NULL; +} + static inline bool skb_valid_dst(const struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 6b9d559ce5f5..d11530f1c1e2 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -38,10 +38,19 @@ struct ip_tunnel_key { __be16 tp_dst; } __packed __aligned(4); /* Minimize padding. */ +/* Indicates whether the tunnel info structure represents receive + * or transmit tunnel parameters. + */ +enum { + IP_TUNNEL_INFO_RX, + IP_TUNNEL_INFO_TX, +}; + struct ip_tunnel_info { struct ip_tunnel_key key; const void *options; u8 options_len; + u8 mode; }; /* 6rd prefix/relay information */ @@ -284,6 +293,11 @@ static inline void iptunnel_xmit_stats(int err, } } +static inline void *ip_tunnel_info_opts(struct ip_tunnel_info *info, size_t n) +{ + return info + 1; +} + #endif /* CONFIG_INET */ #endif /* __NET_IP_TUNNELS_H */ diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 0082b5d33d7d..80a2da29e088 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -7,6 +7,7 @@ #include #include #include +#include #define VNI_HASH_BITS 10 #define VNI_HASH_SIZE (1< Date: Tue, 21 Jul 2015 10:44:00 +0200 Subject: route: Per route IP tunnel metadata via lightweight tunnel This introduces a new IP tunnel lightweight tunnel type which allows to specify IP tunnel instructions per route. Only IPv4 is supported at this point. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 10 +++- include/net/dst_metadata.h | 12 ++++- include/net/ip_tunnels.h | 7 ++- include/uapi/linux/lwtunnel.h | 1 + include/uapi/linux/rtnetlink.h | 15 ++++++ net/ipv4/ip_tunnel_core.c | 114 +++++++++++++++++++++++++++++++++++++++++ net/ipv4/route.c | 2 +- net/openvswitch/vport.h | 1 + 8 files changed, 157 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 06c092b05a51..9486d7ec128c 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1935,7 +1935,7 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct vxlan_rdst *rdst, bool did_rsc) { - struct ip_tunnel_info *info = skb_tunnel_info(skb); + struct ip_tunnel_info *info; struct vxlan_dev *vxlan = netdev_priv(dev); struct sock *sk = vxlan->vn_sock->sock->sk; struct rtable *rt = NULL; @@ -1952,6 +1952,9 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, int err; u32 flags = vxlan->flags; + /* FIXME: Support IPv6 */ + info = skb_tunnel_info(skb, AF_INET); + if (rdst) { dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port; vni = rdst->remote_vni; @@ -2141,12 +2144,15 @@ tx_free: static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); - const struct ip_tunnel_info *info = skb_tunnel_info(skb); + const struct ip_tunnel_info *info; struct ethhdr *eth; bool did_rsc = false; struct vxlan_rdst *rdst, *fdst = NULL; struct vxlan_fdb *f; + /* FIXME: Support IPv6 */ + info = skb_tunnel_info(skb, AF_INET); + skb_reset_mac_header(skb); eth = eth_hdr(skb); diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index e843937fb30a..7b0306894663 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -23,13 +23,23 @@ static inline struct metadata_dst *skb_metadata_dst(struct sk_buff *skb) return NULL; } -static inline struct ip_tunnel_info *skb_tunnel_info(struct sk_buff *skb) +static inline struct ip_tunnel_info *skb_tunnel_info(struct sk_buff *skb, + int family) { struct metadata_dst *md_dst = skb_metadata_dst(skb); + struct rtable *rt; if (md_dst) return &md_dst->u.tun_info; + switch (family) { + case AF_INET: + rt = (struct rtable *)skb_dst(skb); + if (rt && rt->rt_lwtstate) + return lwt_tun_info(rt->rt_lwtstate); + break; + } + return NULL; } diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index d11530f1c1e2..0b7e18cfa0b4 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -9,9 +9,9 @@ #include #include #include -#include #include #include +#include #if IS_ENABLED(CONFIG_IPV6) #include @@ -298,6 +298,11 @@ static inline void *ip_tunnel_info_opts(struct ip_tunnel_info *info, size_t n) return info + 1; } +static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstate) +{ + return (struct ip_tunnel_info *)lwtstate->data; +} + #endif /* CONFIG_INET */ #endif /* __NET_IP_TUNNELS_H */ diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h index aa611d931a31..31377bbea3f8 100644 --- a/include/uapi/linux/lwtunnel.h +++ b/include/uapi/linux/lwtunnel.h @@ -6,6 +6,7 @@ enum lwtunnel_encap_types { LWTUNNEL_ENCAP_NONE, LWTUNNEL_ENCAP_MPLS, + LWTUNNEL_ENCAP_IP, __LWTUNNEL_ENCAP_MAX, }; diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 0d3d3cc43356..47d24cb3fbc1 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -286,6 +286,21 @@ enum rt_class_t { /* Routing message attributes */ +enum ip_tunnel_t { + IP_TUN_UNSPEC, + IP_TUN_ID, + IP_TUN_DST, + IP_TUN_SRC, + IP_TUN_TTL, + IP_TUN_TOS, + IP_TUN_SPORT, + IP_TUN_DPORT, + IP_TUN_FLAGS, + __IP_TUN_MAX, +}; + +#define IP_TUN_MAX (__IP_TUN_MAX - 1) + enum rtattr_type_t { RTA_UNSPEC, RTA_DST, diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 6a51a71a6c67..025b76e803fd 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -190,3 +190,117 @@ struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, return tot; } EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64); + +static const struct nla_policy ip_tun_policy[IP_TUN_MAX + 1] = { + [IP_TUN_ID] = { .type = NLA_U64 }, + [IP_TUN_DST] = { .type = NLA_U32 }, + [IP_TUN_SRC] = { .type = NLA_U32 }, + [IP_TUN_TTL] = { .type = NLA_U8 }, + [IP_TUN_TOS] = { .type = NLA_U8 }, + [IP_TUN_SPORT] = { .type = NLA_U16 }, + [IP_TUN_DPORT] = { .type = NLA_U16 }, + [IP_TUN_FLAGS] = { .type = NLA_U16 }, +}; + +static int ip_tun_build_state(struct net_device *dev, struct nlattr *attr, + struct lwtunnel_state **ts) +{ + struct ip_tunnel_info *tun_info; + struct lwtunnel_state *new_state; + struct nlattr *tb[IP_TUN_MAX + 1]; + int err; + + err = nla_parse_nested(tb, IP_TUN_MAX, attr, ip_tun_policy); + if (err < 0) + return err; + + new_state = lwtunnel_state_alloc(sizeof(*tun_info)); + if (!new_state) + return -ENOMEM; + + new_state->type = LWTUNNEL_ENCAP_IP; + + tun_info = lwt_tun_info(new_state); + + if (tb[IP_TUN_ID]) + tun_info->key.tun_id = nla_get_u64(tb[IP_TUN_ID]); + + if (tb[IP_TUN_DST]) + tun_info->key.ipv4_dst = nla_get_be32(tb[IP_TUN_DST]); + + if (tb[IP_TUN_SRC]) + tun_info->key.ipv4_src = nla_get_be32(tb[IP_TUN_SRC]); + + if (tb[IP_TUN_TTL]) + tun_info->key.ipv4_ttl = nla_get_u8(tb[IP_TUN_TTL]); + + if (tb[IP_TUN_TOS]) + tun_info->key.ipv4_tos = nla_get_u8(tb[IP_TUN_TOS]); + + if (tb[IP_TUN_SPORT]) + tun_info->key.tp_src = nla_get_be16(tb[IP_TUN_SPORT]); + + if (tb[IP_TUN_DPORT]) + tun_info->key.tp_dst = nla_get_be16(tb[IP_TUN_DPORT]); + + if (tb[IP_TUN_FLAGS]) + tun_info->key.tun_flags = nla_get_u16(tb[IP_TUN_FLAGS]); + + tun_info->mode = IP_TUNNEL_INFO_TX; + tun_info->options = NULL; + tun_info->options_len = 0; + + *ts = new_state; + + return 0; +} + +static int ip_tun_fill_encap_info(struct sk_buff *skb, + struct lwtunnel_state *lwtstate) +{ + struct ip_tunnel_info *tun_info = lwt_tun_info(lwtstate); + + if (nla_put_u64(skb, IP_TUN_ID, tun_info->key.tun_id) || + nla_put_be32(skb, IP_TUN_DST, tun_info->key.ipv4_dst) || + nla_put_be32(skb, IP_TUN_SRC, tun_info->key.ipv4_src) || + nla_put_u8(skb, IP_TUN_TOS, tun_info->key.ipv4_tos) || + nla_put_u8(skb, IP_TUN_TTL, tun_info->key.ipv4_ttl) || + nla_put_u16(skb, IP_TUN_SPORT, tun_info->key.tp_src) || + nla_put_u16(skb, IP_TUN_DPORT, tun_info->key.tp_dst) || + nla_put_u16(skb, IP_TUN_FLAGS, tun_info->key.tun_flags)) + return -ENOMEM; + + return 0; +} + +static int ip_tun_encap_nlsize(struct lwtunnel_state *lwtstate) +{ + return nla_total_size(8) /* IP_TUN_ID */ + + nla_total_size(4) /* IP_TUN_DST */ + + nla_total_size(4) /* IP_TUN_SRC */ + + nla_total_size(1) /* IP_TUN_TOS */ + + nla_total_size(1) /* IP_TUN_TTL */ + + nla_total_size(2) /* IP_TUN_SPORT */ + + nla_total_size(2) /* IP_TUN_DPORT */ + + nla_total_size(2); /* IP_TUN_FLAGS */ +} + +static const struct lwtunnel_encap_ops ip_tun_lwt_ops = { + .build_state = ip_tun_build_state, + .fill_encap = ip_tun_fill_encap_info, + .get_encap_size = ip_tun_encap_nlsize, +}; + +static int __init ip_tunnel_core_init(void) +{ + lwtunnel_encap_add_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); + + return 0; +} +module_init(ip_tunnel_core_init); + +static void __exit ip_tunnel_core_exit(void) +{ + lwtunnel_encap_del_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); +} +module_exit(ip_tunnel_core_exit); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 91da18be0a71..519ec232818d 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1693,7 +1693,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, by fib_lookup. */ - tun_info = skb_tunnel_info(skb); + tun_info = skb_tunnel_info(skb, AF_INET); if (tun_info && tun_info->mode == IP_TUNNEL_INFO_RX) fl4.flowi4_tun_key.tun_id = tun_info->key.tun_id; else diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 4750fb673a9f..75d68248ba69 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "datapath.h" -- cgit v1.3-6-gb490 From e7030878fc8448492b6e5cecd574043f63271298 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:44:01 +0200 Subject: fib: Add fib rule match on tunnel id This add the ability to select a routing table based on the tunnel id which allows to maintain separate routing tables for each virtual tunnel network. ip rule add from all tunnel-id 100 lookup 100 ip rule add from all tunnel-id 200 lookup 200 A new static key controls the collection of metadata at tunnel level upon demand. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 3 ++- include/net/fib_rules.h | 1 + include/net/ip_tunnels.h | 11 +++++++++++ include/uapi/linux/fib_rules.h | 2 +- net/core/fib_rules.c | 24 ++++++++++++++++++++++-- net/ipv4/ip_tunnel_core.c | 16 ++++++++++++++++ 6 files changed, 53 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 9486d7ec128c..2587ac84f71a 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -143,7 +143,8 @@ static struct workqueue_struct *vxlan_wq; static inline bool vxlan_collect_metadata(struct vxlan_sock *vs) { - return vs->flags & VXLAN_F_COLLECT_METADATA; + return vs->flags & VXLAN_F_COLLECT_METADATA || + ip_tunnel_collect_metadata(); } #if IS_ENABLED(CONFIG_IPV6) diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 903a55efbffe..4e8f804f4589 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -19,6 +19,7 @@ struct fib_rule { u8 action; /* 3 bytes hole, try to use */ u32 target; + __be64 tun_id; struct fib_rule __rcu *ctarget; struct net *fr_net; diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 0b7e18cfa0b4..0a5a7763eec2 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -303,6 +303,17 @@ static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstat return (struct ip_tunnel_info *)lwtstate->data; } +extern struct static_key ip_tunnel_metadata_cnt; + +/* Returns > 0 if metadata should be collected */ +static inline int ip_tunnel_collect_metadata(void) +{ + return static_key_false(&ip_tunnel_metadata_cnt); +} + +void ip_tunnel_need_metadata(void); +void ip_tunnel_unneed_metadata(void); + #endif /* CONFIG_INET */ #endif /* __NET_IP_TUNNELS_H */ diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h index 2b82d7e30974..96161b8202b5 100644 --- a/include/uapi/linux/fib_rules.h +++ b/include/uapi/linux/fib_rules.h @@ -43,7 +43,7 @@ enum { FRA_UNUSED5, FRA_FWMARK, /* mark */ FRA_FLOW, /* flow/class id */ - FRA_UNUSED6, + FRA_TUN_ID, FRA_SUPPRESS_IFGROUP, FRA_SUPPRESS_PREFIXLEN, FRA_TABLE, /* Extended table id */ diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 9a12668f7d62..ae8306e7c56f 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -16,6 +16,7 @@ #include #include #include +#include int fib_default_rule_add(struct fib_rules_ops *ops, u32 pref, u32 table, u32 flags) @@ -186,6 +187,9 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, if ((rule->mark ^ fl->flowi_mark) & rule->mark_mask) goto out; + if (rule->tun_id && (rule->tun_id != fl->flowi_tun_key.tun_id)) + goto out; + ret = ops->match(rule, fl, flags); out: return (rule->flags & FIB_RULE_INVERT) ? !ret : ret; @@ -330,6 +334,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh) if (tb[FRA_FWMASK]) rule->mark_mask = nla_get_u32(tb[FRA_FWMASK]); + if (tb[FRA_TUN_ID]) + rule->tun_id = nla_get_be64(tb[FRA_TUN_ID]); + rule->action = frh->action; rule->flags = frh->flags; rule->table = frh_get_table(frh, tb); @@ -407,6 +414,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh) if (unresolved) ops->unresolved_rules++; + if (rule->tun_id) + ip_tunnel_need_metadata(); + notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).portid); flush_route_cache(ops); rules_ops_put(ops); @@ -473,6 +483,10 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh) (rule->mark_mask != nla_get_u32(tb[FRA_FWMASK]))) continue; + if (tb[FRA_TUN_ID] && + (rule->tun_id != nla_get_be64(tb[FRA_TUN_ID]))) + continue; + if (!ops->compare(rule, frh, tb)) continue; @@ -487,6 +501,9 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh) goto errout; } + if (rule->tun_id) + ip_tunnel_unneed_metadata(); + list_del_rcu(&rule->list); if (rule->action == FR_ACT_GOTO) { @@ -535,7 +552,8 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, + nla_total_size(4) /* FRA_SUPPRESS_PREFIXLEN */ + nla_total_size(4) /* FRA_SUPPRESS_IFGROUP */ + nla_total_size(4) /* FRA_FWMARK */ - + nla_total_size(4); /* FRA_FWMASK */ + + nla_total_size(4) /* FRA_FWMASK */ + + nla_total_size(8); /* FRA_TUN_ID */ if (ops->nlmsg_payload) payload += ops->nlmsg_payload(rule); @@ -591,7 +609,9 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, ((rule->mark_mask || rule->mark) && nla_put_u32(skb, FRA_FWMASK, rule->mark_mask)) || (rule->target && - nla_put_u32(skb, FRA_GOTO, rule->target))) + nla_put_u32(skb, FRA_GOTO, rule->target)) || + (rule->tun_id && + nla_put_be64(skb, FRA_TUN_ID, rule->tun_id))) goto nla_put_failure; if (rule->suppress_ifgroup != -1) { diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 025b76e803fd..630e6d5712e8 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -304,3 +305,18 @@ static void __exit ip_tunnel_core_exit(void) lwtunnel_encap_del_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); } module_exit(ip_tunnel_core_exit); + +struct static_key ip_tunnel_metadata_cnt = STATIC_KEY_INIT_FALSE; +EXPORT_SYMBOL(ip_tunnel_metadata_cnt); + +void ip_tunnel_need_metadata(void) +{ + static_key_slow_inc(&ip_tunnel_metadata_cnt); +} +EXPORT_SYMBOL_GPL(ip_tunnel_need_metadata); + +void ip_tunnel_unneed_metadata(void) +{ + static_key_slow_dec(&ip_tunnel_metadata_cnt); +} +EXPORT_SYMBOL_GPL(ip_tunnel_unneed_metadata); -- cgit v1.3-6-gb490 From 0dfbdf4102b9303d3ddf2177c0220098ff99f6de Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:44:02 +0200 Subject: vxlan: Factor out device configuration This factors out the device configuration out of the RTNL newlink API which allows for in-kernel creation of VXLAN net_devices. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 332 ++++++++++++++++++++++++++++------------------------ include/net/vxlan.h | 59 ++++++++++ 2 files changed, 236 insertions(+), 155 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 2587ac84f71a..30e1f215af73 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -55,10 +55,6 @@ #define PORT_HASH_BITS 8 #define PORT_HASH_SIZE (1<remote_ip)) goto nla_put_failure; - if (rdst->remote_port && rdst->remote_port != vxlan->dst_port && + if (rdst->remote_port && rdst->remote_port != vxlan->cfg.dst_port && nla_put_be16(skb, NDA_PORT, rdst->remote_port)) goto nla_put_failure; if (rdst->remote_vni != vxlan->default_dst.remote_vni && @@ -756,7 +713,8 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan, if (!(flags & NLM_F_CREATE)) return -ENOENT; - if (vxlan->addrmax && vxlan->addrcnt >= vxlan->addrmax) + if (vxlan->cfg.addrmax && + vxlan->addrcnt >= vxlan->cfg.addrmax) return -ENOSPC; /* Disallow replace to add a multicast entry */ @@ -842,7 +800,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, return -EINVAL; *port = nla_get_be16(tb[NDA_PORT]); } else { - *port = vxlan->dst_port; + *port = vxlan->cfg.dst_port; } if (tb[NDA_VNI]) { @@ -1028,7 +986,7 @@ static bool vxlan_snoop(struct net_device *dev, vxlan_fdb_create(vxlan, src_mac, src_ip, NUD_REACHABLE, NLM_F_EXCL|NLM_F_CREATE, - vxlan->dst_port, + vxlan->cfg.dst_port, vxlan->default_dst.remote_vni, 0, NTF_SELF); spin_unlock(&vxlan->hash_lock); @@ -1957,7 +1915,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, info = skb_tunnel_info(skb, AF_INET); if (rdst) { - dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port; + dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port; vni = rdst->remote_vni; dst = &rdst->remote_ip; } else { @@ -1967,7 +1925,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, goto drop; } - dst_port = info->key.tp_dst ? : vxlan->dst_port; + dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port; vni = be64_to_cpu(info->key.tun_id); remote_ip.sin.sin_family = AF_INET; remote_ip.sin.sin_addr.s_addr = info->key.ipv4_dst; @@ -1985,16 +1943,16 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, old_iph = ip_hdr(skb); - ttl = vxlan->ttl; + ttl = vxlan->cfg.ttl; if (!ttl && vxlan_addr_multicast(dst)) ttl = 1; - tos = vxlan->tos; + tos = vxlan->cfg.tos; if (tos == 1) tos = ip_tunnel_get_dsfield(old_iph, skb); - src_port = udp_flow_src_port(dev_net(dev), skb, vxlan->port_min, - vxlan->port_max, true); + src_port = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min, + vxlan->cfg.port_max, true); if (dst->sa.sa_family == AF_INET) { if (info) { @@ -2020,7 +1978,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, fl4.flowi4_mark = skb->mark; fl4.flowi4_proto = IPPROTO_UDP; fl4.daddr = dst->sin.sin_addr.s_addr; - fl4.saddr = vxlan->saddr.sin.sin_addr.s_addr; + fl4.saddr = vxlan->cfg.saddr.sin.sin_addr.s_addr; rt = ip_route_output_key(vxlan->net, &fl4); if (IS_ERR(rt)) { @@ -2076,7 +2034,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_oif = rdst ? rdst->remote_ifindex : 0; fl6.daddr = dst->sin6.sin6_addr; - fl6.saddr = vxlan->saddr.sin6.sin6_addr; + fl6.saddr = vxlan->cfg.saddr.sin6.sin6_addr; fl6.flowi6_mark = skb->mark; fl6.flowi6_proto = IPPROTO_UDP; @@ -2247,7 +2205,7 @@ static void vxlan_cleanup(unsigned long arg) if (f->state & NUD_PERMANENT) continue; - timeout = f->used + vxlan->age_interval * HZ; + timeout = f->used + vxlan->cfg.age_interval * HZ; if (time_before_eq(timeout, jiffies)) { netdev_dbg(vxlan->dev, "garbage collect %pM\n", @@ -2311,8 +2269,8 @@ static int vxlan_open(struct net_device *dev) struct vxlan_sock *vs; int ret = 0; - vs = vxlan_sock_add(vxlan->net, vxlan->dst_port, vxlan_rcv, NULL, - false, vxlan->flags); + vs = vxlan_sock_add(vxlan->net, vxlan->cfg.dst_port, vxlan_rcv, + NULL, vxlan->cfg.no_share, vxlan->flags); if (IS_ERR(vs)) return PTR_ERR(vs); @@ -2326,7 +2284,7 @@ static int vxlan_open(struct net_device *dev) } } - if (vxlan->age_interval) + if (vxlan->cfg.age_interval) mod_timer(&vxlan->age_timer, jiffies + FDB_AGE_INTERVAL); return ret; @@ -2484,7 +2442,7 @@ static void vxlan_setup(struct net_device *dev) vxlan->age_timer.function = vxlan_cleanup; vxlan->age_timer.data = (unsigned long) vxlan; - vxlan->dst_port = htons(vxlan_port); + vxlan->cfg.dst_port = htons(vxlan_port); vxlan->dev = dev; @@ -2684,54 +2642,35 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, } EXPORT_SYMBOL_GPL(vxlan_sock_add); -static int vxlan_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) +static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, + struct vxlan_config *conf) { struct vxlan_net *vn = net_generic(src_net, vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_rdst *dst = &vxlan->default_dst; - __u32 vni; int err; bool use_ipv6 = false; - - if (!data[IFLA_VXLAN_ID]) - return -EINVAL; + __be16 default_port = vxlan->cfg.dst_port; vxlan->net = src_net; - vni = nla_get_u32(data[IFLA_VXLAN_ID]); - dst->remote_vni = vni; + dst->remote_vni = conf->vni; - /* Unless IPv6 is explicitly requested, assume IPv4 */ - dst->remote_ip.sa.sa_family = AF_INET; - if (data[IFLA_VXLAN_GROUP]) { - dst->remote_ip.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]); - } else if (data[IFLA_VXLAN_GROUP6]) { - if (!IS_ENABLED(CONFIG_IPV6)) - return -EPFNOSUPPORT; - - dst->remote_ip.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]); - dst->remote_ip.sa.sa_family = AF_INET6; - use_ipv6 = true; - } + memcpy(&dst->remote_ip, &conf->remote_ip, sizeof(conf->remote_ip)); - if (data[IFLA_VXLAN_LOCAL]) { - vxlan->saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]); - vxlan->saddr.sa.sa_family = AF_INET; - } else if (data[IFLA_VXLAN_LOCAL6]) { - if (!IS_ENABLED(CONFIG_IPV6)) - return -EPFNOSUPPORT; + /* Unless IPv6 is explicitly requested, assume IPv4 */ + if (!dst->remote_ip.sa.sa_family) + dst->remote_ip.sa.sa_family = AF_INET; - /* TODO: respect scope id */ - vxlan->saddr.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_LOCAL6]); - vxlan->saddr.sa.sa_family = AF_INET6; + if (dst->remote_ip.sa.sa_family == AF_INET6 || + vxlan->cfg.saddr.sa.sa_family == AF_INET6) use_ipv6 = true; - } - if (data[IFLA_VXLAN_LINK] && - (dst->remote_ifindex = nla_get_u32(data[IFLA_VXLAN_LINK]))) { + if (conf->remote_ifindex) { struct net_device *lowerdev - = __dev_get_by_index(src_net, dst->remote_ifindex); + = __dev_get_by_index(src_net, conf->remote_ifindex); + + dst->remote_ifindex = conf->remote_ifindex; if (!lowerdev) { pr_info("ifindex %d does not exist\n", dst->remote_ifindex); @@ -2749,7 +2688,7 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, } #endif - if (!tb[IFLA_MTU]) + if (!conf->mtu) dev->mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM); dev->needed_headroom = lowerdev->hard_header_len + @@ -2757,105 +2696,188 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, } else if (use_ipv6) vxlan->flags |= VXLAN_F_IPV6; + memcpy(&vxlan->cfg, conf, sizeof(*conf)); + if (!vxlan->cfg.dst_port) + vxlan->cfg.dst_port = default_port; + vxlan->flags |= conf->flags; + + if (!vxlan->cfg.age_interval) + vxlan->cfg.age_interval = FDB_AGE_DEFAULT; + + if (vxlan_find_vni(src_net, conf->vni, use_ipv6 ? AF_INET6 : AF_INET, + vxlan->cfg.dst_port, vxlan->flags)) + return -EEXIST; + + dev->ethtool_ops = &vxlan_ethtool_ops; + + /* create an fdb entry for a valid default destination */ + if (!vxlan_addr_any(&vxlan->default_dst.remote_ip)) { + err = vxlan_fdb_create(vxlan, all_zeros_mac, + &vxlan->default_dst.remote_ip, + NUD_REACHABLE|NUD_PERMANENT, + NLM_F_EXCL|NLM_F_CREATE, + vxlan->cfg.dst_port, + vxlan->default_dst.remote_vni, + vxlan->default_dst.remote_ifindex, + NTF_SELF); + if (err) + return err; + } + + err = register_netdevice(dev); + if (err) { + vxlan_fdb_delete_default(vxlan); + return err; + } + + list_add(&vxlan->next, &vn->vxlan_list); + + return 0; +} + +struct net_device *vxlan_dev_create(struct net *net, const char *name, + u8 name_assign_type, struct vxlan_config *conf) +{ + struct nlattr *tb[IFLA_MAX+1]; + struct net_device *dev; + int err; + + memset(&tb, 0, sizeof(tb)); + + dev = rtnl_create_link(net, name, name_assign_type, + &vxlan_link_ops, tb); + if (IS_ERR(dev)) + return dev; + + err = vxlan_dev_configure(net, dev, conf); + if (err < 0) { + free_netdev(dev); + return ERR_PTR(err); + } + + return dev; +} +EXPORT_SYMBOL_GPL(vxlan_dev_create); + +static int vxlan_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + struct vxlan_config conf; + int err; + + if (!data[IFLA_VXLAN_ID]) + return -EINVAL; + + memset(&conf, 0, sizeof(conf)); + conf.vni = nla_get_u32(data[IFLA_VXLAN_ID]); + + if (data[IFLA_VXLAN_GROUP]) { + conf.remote_ip.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]); + } else if (data[IFLA_VXLAN_GROUP6]) { + if (!IS_ENABLED(CONFIG_IPV6)) + return -EPFNOSUPPORT; + + conf.remote_ip.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]); + conf.remote_ip.sa.sa_family = AF_INET6; + } + + if (data[IFLA_VXLAN_LOCAL]) { + conf.saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]); + conf.saddr.sa.sa_family = AF_INET; + } else if (data[IFLA_VXLAN_LOCAL6]) { + if (!IS_ENABLED(CONFIG_IPV6)) + return -EPFNOSUPPORT; + + /* TODO: respect scope id */ + conf.saddr.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_LOCAL6]); + conf.saddr.sa.sa_family = AF_INET6; + } + + if (data[IFLA_VXLAN_LINK]) + conf.remote_ifindex = nla_get_u32(data[IFLA_VXLAN_LINK]); + if (data[IFLA_VXLAN_TOS]) - vxlan->tos = nla_get_u8(data[IFLA_VXLAN_TOS]); + conf.tos = nla_get_u8(data[IFLA_VXLAN_TOS]); if (data[IFLA_VXLAN_TTL]) - vxlan->ttl = nla_get_u8(data[IFLA_VXLAN_TTL]); + conf.ttl = nla_get_u8(data[IFLA_VXLAN_TTL]); if (!data[IFLA_VXLAN_LEARNING] || nla_get_u8(data[IFLA_VXLAN_LEARNING])) - vxlan->flags |= VXLAN_F_LEARN; + conf.flags |= VXLAN_F_LEARN; if (data[IFLA_VXLAN_AGEING]) - vxlan->age_interval = nla_get_u32(data[IFLA_VXLAN_AGEING]); - else - vxlan->age_interval = FDB_AGE_DEFAULT; + conf.age_interval = nla_get_u32(data[IFLA_VXLAN_AGEING]); if (data[IFLA_VXLAN_PROXY] && nla_get_u8(data[IFLA_VXLAN_PROXY])) - vxlan->flags |= VXLAN_F_PROXY; + conf.flags |= VXLAN_F_PROXY; if (data[IFLA_VXLAN_RSC] && nla_get_u8(data[IFLA_VXLAN_RSC])) - vxlan->flags |= VXLAN_F_RSC; + conf.flags |= VXLAN_F_RSC; if (data[IFLA_VXLAN_L2MISS] && nla_get_u8(data[IFLA_VXLAN_L2MISS])) - vxlan->flags |= VXLAN_F_L2MISS; + conf.flags |= VXLAN_F_L2MISS; if (data[IFLA_VXLAN_L3MISS] && nla_get_u8(data[IFLA_VXLAN_L3MISS])) - vxlan->flags |= VXLAN_F_L3MISS; + conf.flags |= VXLAN_F_L3MISS; if (data[IFLA_VXLAN_LIMIT]) - vxlan->addrmax = nla_get_u32(data[IFLA_VXLAN_LIMIT]); + conf.addrmax = nla_get_u32(data[IFLA_VXLAN_LIMIT]); if (data[IFLA_VXLAN_FLOWBASED] && nla_get_u8(data[IFLA_VXLAN_FLOWBASED])) - vxlan->flags |= VXLAN_F_FLOW_BASED; + conf.flags |= VXLAN_F_FLOW_BASED; if (data[IFLA_VXLAN_PORT_RANGE]) { const struct ifla_vxlan_port_range *p = nla_data(data[IFLA_VXLAN_PORT_RANGE]); - vxlan->port_min = ntohs(p->low); - vxlan->port_max = ntohs(p->high); + conf.port_min = ntohs(p->low); + conf.port_max = ntohs(p->high); } if (data[IFLA_VXLAN_PORT]) - vxlan->dst_port = nla_get_be16(data[IFLA_VXLAN_PORT]); + conf.dst_port = nla_get_be16(data[IFLA_VXLAN_PORT]); if (data[IFLA_VXLAN_UDP_CSUM] && nla_get_u8(data[IFLA_VXLAN_UDP_CSUM])) - vxlan->flags |= VXLAN_F_UDP_CSUM; + conf.flags |= VXLAN_F_UDP_CSUM; if (data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX] && nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX])) - vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_TX; + conf.flags |= VXLAN_F_UDP_ZERO_CSUM6_TX; if (data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] && nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX])) - vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_RX; + conf.flags |= VXLAN_F_UDP_ZERO_CSUM6_RX; if (data[IFLA_VXLAN_REMCSUM_TX] && nla_get_u8(data[IFLA_VXLAN_REMCSUM_TX])) - vxlan->flags |= VXLAN_F_REMCSUM_TX; + conf.flags |= VXLAN_F_REMCSUM_TX; if (data[IFLA_VXLAN_REMCSUM_RX] && nla_get_u8(data[IFLA_VXLAN_REMCSUM_RX])) - vxlan->flags |= VXLAN_F_REMCSUM_RX; + conf.flags |= VXLAN_F_REMCSUM_RX; if (data[IFLA_VXLAN_GBP]) - vxlan->flags |= VXLAN_F_GBP; + conf.flags |= VXLAN_F_GBP; if (data[IFLA_VXLAN_REMCSUM_NOPARTIAL]) - vxlan->flags |= VXLAN_F_REMCSUM_NOPARTIAL; + conf.flags |= VXLAN_F_REMCSUM_NOPARTIAL; - if (vxlan_find_vni(src_net, vni, use_ipv6 ? AF_INET6 : AF_INET, - vxlan->dst_port, vxlan->flags)) { - pr_info("duplicate VNI %u\n", vni); - return -EEXIST; - } - - dev->ethtool_ops = &vxlan_ethtool_ops; + err = vxlan_dev_configure(src_net, dev, &conf); + switch (err) { + case -ENODEV: + pr_info("ifindex %d does not exist\n", conf.remote_ifindex); + break; - /* create an fdb entry for a valid default destination */ - if (!vxlan_addr_any(&vxlan->default_dst.remote_ip)) { - err = vxlan_fdb_create(vxlan, all_zeros_mac, - &vxlan->default_dst.remote_ip, - NUD_REACHABLE|NUD_PERMANENT, - NLM_F_EXCL|NLM_F_CREATE, - vxlan->dst_port, - vxlan->default_dst.remote_vni, - vxlan->default_dst.remote_ifindex, - NTF_SELF); - if (err) - return err; - } + case -EPERM: + pr_info("IPv6 is disabled via sysctl\n"); + break; - err = register_netdevice(dev); - if (err) { - vxlan_fdb_delete_default(vxlan); - return err; + case -EEXIST: + pr_info("duplicate VNI %u\n", conf.vni); + break; } - list_add(&vxlan->next, &vn->vxlan_list); - - return 0; + return err; } static void vxlan_dellink(struct net_device *dev, struct list_head *head) @@ -2904,8 +2926,8 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) const struct vxlan_dev *vxlan = netdev_priv(dev); const struct vxlan_rdst *dst = &vxlan->default_dst; struct ifla_vxlan_port_range ports = { - .low = htons(vxlan->port_min), - .high = htons(vxlan->port_max), + .low = htons(vxlan->cfg.port_min), + .high = htons(vxlan->cfg.port_max), }; if (nla_put_u32(skb, IFLA_VXLAN_ID, dst->remote_vni)) @@ -2928,22 +2950,22 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) if (dst->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, dst->remote_ifindex)) goto nla_put_failure; - if (!vxlan_addr_any(&vxlan->saddr)) { - if (vxlan->saddr.sa.sa_family == AF_INET) { + if (!vxlan_addr_any(&vxlan->cfg.saddr)) { + if (vxlan->cfg.saddr.sa.sa_family == AF_INET) { if (nla_put_in_addr(skb, IFLA_VXLAN_LOCAL, - vxlan->saddr.sin.sin_addr.s_addr)) + vxlan->cfg.saddr.sin.sin_addr.s_addr)) goto nla_put_failure; #if IS_ENABLED(CONFIG_IPV6) } else { if (nla_put_in6_addr(skb, IFLA_VXLAN_LOCAL6, - &vxlan->saddr.sin6.sin6_addr)) + &vxlan->cfg.saddr.sin6.sin6_addr)) goto nla_put_failure; #endif } } - if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->ttl) || - nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->tos) || + if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->cfg.ttl) || + nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->cfg.tos) || nla_put_u8(skb, IFLA_VXLAN_LEARNING, !!(vxlan->flags & VXLAN_F_LEARN)) || nla_put_u8(skb, IFLA_VXLAN_PROXY, @@ -2955,9 +2977,9 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) !!(vxlan->flags & VXLAN_F_L3MISS)) || nla_put_u8(skb, IFLA_VXLAN_FLOWBASED, !!(vxlan->flags & VXLAN_F_FLOW_BASED)) || - nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->age_interval) || - nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax) || - nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->dst_port) || + nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->cfg.age_interval) || + nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->cfg.addrmax) || + nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->cfg.dst_port) || nla_put_u8(skb, IFLA_VXLAN_UDP_CSUM, !!(vxlan->flags & VXLAN_F_UDP_CSUM)) || nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 80a2da29e088..19535f85eb2c 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -95,6 +95,11 @@ struct vxlanhdr { #define VXLAN_VNI_MASK (VXLAN_VID_MASK << 8) #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr)) +#define VNI_HASH_BITS 10 +#define VNI_HASH_SIZE (1< Date: Tue, 21 Jul 2015 10:44:06 +0200 Subject: openvswitch: Use regular VXLAN net_device device This gets rid of all OVS specific VXLAN code in the receive and transmit path by using a VXLAN net_device to represent the vport. Only a small shim layer remains which takes care of handling the VXLAN specific OVS Netlink configuration. Unexports vxlan_sock_add(), vxlan_sock_release(), vxlan_xmit_skb() since they are no longer needed. Signed-off-by: Thomas Graf Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 242 +++++++++++++++---------------- include/net/rtnetlink.h | 1 + include/net/vxlan.h | 24 +-- net/core/rtnetlink.c | 26 ++-- net/openvswitch/Kconfig | 12 -- net/openvswitch/Makefile | 1 - net/openvswitch/flow_netlink.c | 6 +- net/openvswitch/vport-netdev.c | 201 ++++++++++++++++++++++++- net/openvswitch/vport-vxlan.c | 322 ----------------------------------------- net/openvswitch/vport-vxlan.h | 11 -- 10 files changed, 339 insertions(+), 507 deletions(-) delete mode 100644 net/openvswitch/vport-vxlan.c delete mode 100644 net/openvswitch/vport-vxlan.h (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 30e1f215af73..e9feefb41f0b 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -75,6 +75,9 @@ static struct rtnl_link_ops vxlan_link_ops; static const u8 all_zeros_mac[ETH_ALEN]; +static struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, + bool no_share, u32 flags); + /* per-network namespace private data for this module */ struct vxlan_net { struct list_head vxlan_list; @@ -1027,7 +1030,7 @@ static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev) return false; } -void vxlan_sock_release(struct vxlan_sock *vs) +static void vxlan_sock_release(struct vxlan_sock *vs) { struct sock *sk = vs->sock->sk; struct net *net = sock_net(sk); @@ -1043,7 +1046,6 @@ void vxlan_sock_release(struct vxlan_sock *vs) queue_work(vxlan_wq, &vs->del_work); } -EXPORT_SYMBOL_GPL(vxlan_sock_release); /* Update multicast group membership when first VNI on * multicast address is brought up @@ -1126,6 +1128,102 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, return vh; } +static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, + struct vxlan_metadata *md, u32 vni, + struct metadata_dst *tun_dst) +{ + struct iphdr *oip = NULL; + struct ipv6hdr *oip6 = NULL; + struct vxlan_dev *vxlan; + struct pcpu_sw_netstats *stats; + union vxlan_addr saddr; + int err = 0; + union vxlan_addr *remote_ip; + + /* For flow based devices, map all packets to VNI 0 */ + if (vs->flags & VXLAN_F_FLOW_BASED) + vni = 0; + + /* Is this VNI defined? */ + vxlan = vxlan_vs_find_vni(vs, vni); + if (!vxlan) + goto drop; + + remote_ip = &vxlan->default_dst.remote_ip; + skb_reset_mac_header(skb); + skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev))); + skb->protocol = eth_type_trans(skb, vxlan->dev); + skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); + + /* Ignore packet loops (and multicast echo) */ + if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr)) + goto drop; + + /* Re-examine inner Ethernet packet */ + if (remote_ip->sa.sa_family == AF_INET) { + oip = ip_hdr(skb); + saddr.sin.sin_addr.s_addr = oip->saddr; + saddr.sa.sa_family = AF_INET; +#if IS_ENABLED(CONFIG_IPV6) + } else { + oip6 = ipv6_hdr(skb); + saddr.sin6.sin6_addr = oip6->saddr; + saddr.sa.sa_family = AF_INET6; +#endif + } + + if (tun_dst) { + skb_dst_set(skb, (struct dst_entry *)tun_dst); + tun_dst = NULL; + } + + if ((vxlan->flags & VXLAN_F_LEARN) && + vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source)) + goto drop; + + skb_reset_network_header(skb); + /* In flow-based mode, GBP is carried in dst_metadata */ + if (!(vs->flags & VXLAN_F_FLOW_BASED)) + skb->mark = md->gbp; + + if (oip6) + err = IP6_ECN_decapsulate(oip6, skb); + if (oip) + err = IP_ECN_decapsulate(oip, skb); + + if (unlikely(err)) { + if (log_ecn_error) { + if (oip6) + net_info_ratelimited("non-ECT from %pI6\n", + &oip6->saddr); + if (oip) + net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", + &oip->saddr, oip->tos); + } + if (err > 1) { + ++vxlan->dev->stats.rx_frame_errors; + ++vxlan->dev->stats.rx_errors; + goto drop; + } + } + + stats = this_cpu_ptr(vxlan->dev->tstats); + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += skb->len; + u64_stats_update_end(&stats->syncp); + + netif_rx(skb); + + return; +drop: + if (tun_dst) + dst_release((struct dst_entry *)tun_dst); + + /* Consume bad packet */ + kfree_skb(skb); +} + /* Callback from net/ipv4/udp.c to receive packets */ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) { @@ -1192,7 +1290,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) info->key.tun_flags |= TUNNEL_CSUM; md = ip_tunnel_info_opts(info, sizeof(*md)); - md->tun_dst = tun_dst; } else { memset(md, 0, sizeof(*md)); } @@ -1231,8 +1328,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) goto bad_flags; } - md->vni = vxh->vx_vni; - vs->rcv(vs, skb, md); + vxlan_rcv(vs, skb, md, vni >> 8, tun_dst); return 0; drop: @@ -1252,104 +1348,6 @@ error: return 1; } -static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, - struct vxlan_metadata *md) -{ - struct iphdr *oip = NULL; - struct ipv6hdr *oip6 = NULL; - struct vxlan_dev *vxlan; - struct pcpu_sw_netstats *stats; - union vxlan_addr saddr; - __u32 vni; - int err = 0; - union vxlan_addr *remote_ip; - - /* For flow based devices, map all packets to VNI 0 */ - if (vs->flags & VXLAN_F_FLOW_BASED) - vni = 0; - else - vni = ntohl(md->vni) >> 8; - - /* Is this VNI defined? */ - vxlan = vxlan_vs_find_vni(vs, vni); - if (!vxlan) - goto drop; - - remote_ip = &vxlan->default_dst.remote_ip; - skb_reset_mac_header(skb); - skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev))); - skb->protocol = eth_type_trans(skb, vxlan->dev); - skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); - - /* Ignore packet loops (and multicast echo) */ - if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr)) - goto drop; - - /* Re-examine inner Ethernet packet */ - if (remote_ip->sa.sa_family == AF_INET) { - oip = ip_hdr(skb); - saddr.sin.sin_addr.s_addr = oip->saddr; - saddr.sa.sa_family = AF_INET; -#if IS_ENABLED(CONFIG_IPV6) - } else { - oip6 = ipv6_hdr(skb); - saddr.sin6.sin6_addr = oip6->saddr; - saddr.sa.sa_family = AF_INET6; -#endif - } - - if (md->tun_dst) { - skb_dst_set(skb, (struct dst_entry *)md->tun_dst); - md->tun_dst = NULL; - } - - if ((vxlan->flags & VXLAN_F_LEARN) && - vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source)) - goto drop; - - skb_reset_network_header(skb); - /* In flow-based mode, GBP is carried in dst_metadata */ - if (!(vs->flags & VXLAN_F_FLOW_BASED)) - skb->mark = md->gbp; - - if (oip6) - err = IP6_ECN_decapsulate(oip6, skb); - if (oip) - err = IP_ECN_decapsulate(oip, skb); - - if (unlikely(err)) { - if (log_ecn_error) { - if (oip6) - net_info_ratelimited("non-ECT from %pI6\n", - &oip6->saddr); - if (oip) - net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", - &oip->saddr, oip->tos); - } - if (err > 1) { - ++vxlan->dev->stats.rx_frame_errors; - ++vxlan->dev->stats.rx_errors; - goto drop; - } - } - - stats = this_cpu_ptr(vxlan->dev->tstats); - u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += skb->len; - u64_stats_update_end(&stats->syncp); - - netif_rx(skb); - - return; -drop: - if (md->tun_dst) - dst_release((struct dst_entry *)md->tun_dst); - - /* Consume bad packet */ - kfree_skb(skb); -} - static int arp_reduce(struct net_device *dev, struct sk_buff *skb) { struct vxlan_dev *vxlan = netdev_priv(dev); @@ -1688,7 +1686,7 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, - __be16 src_port, __be16 dst_port, + __be16 src_port, __be16 dst_port, __u32 vni, struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; @@ -1738,7 +1736,7 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk, vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_HF_VNI); - vxh->vx_vni = md->vni; + vxh->vx_vni = vni; if (type & SKB_GSO_TUNNEL_REMCSUM) { u32 data = (skb_checksum_start_offset(skb) - hdrlen) >> @@ -1771,10 +1769,10 @@ err: } #endif -int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, - __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, - __be16 src_port, __be16 dst_port, - struct vxlan_metadata *md, bool xnet, u32 vxflags) +static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, + __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, + __be16 src_port, __be16 dst_port, __u32 vni, + struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; int min_headroom; @@ -1817,7 +1815,7 @@ int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_HF_VNI); - vxh->vx_vni = md->vni; + vxh->vx_vni = vni; if (type & SKB_GSO_TUNNEL_REMCSUM) { u32 data = (skb_checksum_start_offset(skb) - hdrlen) >> @@ -1844,7 +1842,6 @@ int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, ttl, df, src_port, dst_port, xnet, !(vxflags & VXLAN_F_UDP_CSUM)); } -EXPORT_SYMBOL_GPL(vxlan_xmit_skb); /* Bypass encapsulation if the destination is local */ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, @@ -2012,10 +2009,9 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); - md->vni = htonl(vni << 8); err = vxlan_xmit_skb(rt, sk, skb, fl4.saddr, dst->sin.sin_addr.s_addr, tos, ttl, df, - src_port, dst_port, md, + src_port, dst_port, htonl(vni << 8), md, !net_eq(vxlan->net, dev_net(vxlan->dev)), flags); if (err < 0) { @@ -2070,11 +2066,10 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } ttl = ttl ? : ip6_dst_hoplimit(ndst); - md->vni = htonl(vni << 8); md->gbp = skb->mark; err = vxlan6_xmit_skb(ndst, sk, skb, dev, &fl6.saddr, &fl6.daddr, - 0, ttl, src_port, dst_port, md, + 0, ttl, src_port, dst_port, htonl(vni << 8), md, !net_eq(vxlan->net, dev_net(vxlan->dev)), vxlan->flags); #endif @@ -2269,8 +2264,8 @@ static int vxlan_open(struct net_device *dev) struct vxlan_sock *vs; int ret = 0; - vs = vxlan_sock_add(vxlan->net, vxlan->cfg.dst_port, vxlan_rcv, - NULL, vxlan->cfg.no_share, vxlan->flags); + vs = vxlan_sock_add(vxlan->net, vxlan->cfg.dst_port, + vxlan->cfg.no_share, vxlan->flags); if (IS_ERR(vs)) return PTR_ERR(vs); @@ -2563,7 +2558,6 @@ static struct socket *vxlan_create_sock(struct net *net, bool ipv6, /* Create new listen socket if needed */ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, - vxlan_rcv_t *rcv, void *data, u32 flags) { struct vxlan_net *vn = net_generic(net, vxlan_net_id); @@ -2592,8 +2586,6 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, vs->sock = sock; atomic_set(&vs->refcnt, 1); - vs->rcv = rcv; - vs->data = data; vs->flags = (flags & VXLAN_F_RCV_FLAGS); /* Initialize the vxlan udp offloads structure */ @@ -2617,9 +2609,8 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, return vs; } -struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, - vxlan_rcv_t *rcv, void *data, - bool no_share, u32 flags) +static struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, + bool no_share, u32 flags) { struct vxlan_net *vn = net_generic(net, vxlan_net_id); struct vxlan_sock *vs; @@ -2629,7 +2620,7 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, spin_lock(&vn->sock_lock); vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port, flags); - if (vs && vs->rcv == rcv) { + if (vs) { if (!atomic_add_unless(&vs->refcnt, 1, 0)) vs = ERR_PTR(-EBUSY); spin_unlock(&vn->sock_lock); @@ -2638,9 +2629,8 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, spin_unlock(&vn->sock_lock); } - return vxlan_socket_create(net, port, rcv, data, flags); + return vxlan_socket_create(net, port, flags); } -EXPORT_SYMBOL_GPL(vxlan_sock_add); static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, struct vxlan_config *conf) diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 343d922d15c2..18fdb98185ab 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -141,6 +141,7 @@ struct net_device *rtnl_create_link(struct net *net, const char *ifname, unsigned char name_assign_type, const struct rtnl_link_ops *ops, struct nlattr *tb[]); +int rtnl_delete_link(struct net_device *dev); int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm); int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len); diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 19535f85eb2c..eb8d721cdb67 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -101,22 +101,12 @@ struct vxlanhdr { #define FDB_HASH_SIZE (1<vn_sock->sock->sk)->inet_sport; +} static inline netdev_features_t vxlan_features_check(struct sk_buff *skb, netdev_features_t features) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 03d61b54aac0..5fb4af20c6dd 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1960,16 +1960,30 @@ static int rtnl_group_dellink(const struct net *net, int group) return 0; } +int rtnl_delete_link(struct net_device *dev) +{ + const struct rtnl_link_ops *ops; + LIST_HEAD(list_kill); + + ops = dev->rtnl_link_ops; + if (!ops || !ops->dellink) + return -EOPNOTSUPP; + + ops->dellink(dev, &list_kill); + unregister_netdevice_many(&list_kill); + + return 0; +} +EXPORT_SYMBOL_GPL(rtnl_delete_link); + static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) { struct net *net = sock_net(skb->sk); - const struct rtnl_link_ops *ops; struct net_device *dev; struct ifinfomsg *ifm; char ifname[IFNAMSIZ]; struct nlattr *tb[IFLA_MAX+1]; int err; - LIST_HEAD(list_kill); err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); if (err < 0) @@ -1991,13 +2005,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) if (!dev) return -ENODEV; - ops = dev->rtnl_link_ops; - if (!ops || !ops->dellink) - return -EOPNOTSUPP; - - ops->dellink(dev, &list_kill); - unregister_netdevice_many(&list_kill); - return 0; + return rtnl_delete_link(dev); } int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig index 15840401a2ce..1119f46b80b4 100644 --- a/net/openvswitch/Kconfig +++ b/net/openvswitch/Kconfig @@ -44,18 +44,6 @@ config OPENVSWITCH_GRE If unsure, say Y. -config OPENVSWITCH_VXLAN - tristate "Open vSwitch VXLAN tunneling support" - depends on OPENVSWITCH - depends on VXLAN - default OPENVSWITCH - ---help--- - If you say Y here, then the Open vSwitch will be able create vxlan vport. - - Say N to exclude this support and reduce the binary size. - - If unsure, say Y. - config OPENVSWITCH_GENEVE tristate "Open vSwitch Geneve tunneling support" depends on OPENVSWITCH diff --git a/net/openvswitch/Makefile b/net/openvswitch/Makefile index 91b9478413ef..38e0e149c55e 100644 --- a/net/openvswitch/Makefile +++ b/net/openvswitch/Makefile @@ -16,5 +16,4 @@ openvswitch-y := \ vport-netdev.o obj-$(CONFIG_OPENVSWITCH_GENEVE)+= vport-geneve.o -obj-$(CONFIG_OPENVSWITCH_VXLAN) += vport-vxlan.o obj-$(CONFIG_OPENVSWITCH_GRE) += vport-gre.o diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index e7906dfb8814..a6eb77ab1a64 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -47,9 +47,9 @@ #include #include #include +#include #include "flow_netlink.h" -#include "vport-vxlan.h" struct ovs_len_tbl { int len; @@ -475,7 +475,7 @@ static int vxlan_tun_opt_from_nlattr(const struct nlattr *a, { struct nlattr *tb[OVS_VXLAN_EXT_MAX+1]; unsigned long opt_key_offset; - struct ovs_vxlan_opts opts; + struct vxlan_metadata opts; int err; BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts)); @@ -626,7 +626,7 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, static int vxlan_opt_to_nlattr(struct sk_buff *skb, const void *tun_opts, int swkey_tun_opts_len) { - const struct ovs_vxlan_opts *opts = tun_opts; + const struct vxlan_metadata *opts = tun_opts; struct nlattr *nla; nla = nla_nest_start(skb, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS); diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index e682bdc34a5c..68d0582fc001 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -27,9 +27,13 @@ #include #include -#include +#include +#include +#include +#include #include "datapath.h" +#include "vport.h" #include "vport-internal_dev.h" #include "vport-netdev.h" @@ -147,7 +151,8 @@ static void free_port_rcu(struct rcu_head *rcu) { struct vport *vport = container_of(rcu, struct vport, rcu); - dev_put(vport->dev); + if (vport->dev) + dev_put(vport->dev); ovs_vport_free(vport); } @@ -221,12 +226,202 @@ static struct vport_ops ovs_netdev_vport_ops = { .send = netdev_send, }; +/* Compat code for old userspace. */ +#if IS_ENABLED(CONFIG_VXLAN) +static struct vport_ops ovs_vxlan_netdev_vport_ops; + +static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) +{ + struct vxlan_dev *vxlan = netdev_priv(vport->dev); + __be16 dst_port = vxlan->cfg.dst_port; + + if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port))) + return -EMSGSIZE; + + if (vxlan->flags & VXLAN_F_GBP) { + struct nlattr *exts; + + exts = nla_nest_start(skb, OVS_TUNNEL_ATTR_EXTENSION); + if (!exts) + return -EMSGSIZE; + + if (vxlan->flags & VXLAN_F_GBP && + nla_put_flag(skb, OVS_VXLAN_EXT_GBP)) + return -EMSGSIZE; + + nla_nest_end(skb, exts); + } + + return 0; +} + +static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX + 1] = { + [OVS_VXLAN_EXT_GBP] = { .type = NLA_FLAG, }, +}; + +static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr, + struct vxlan_config *conf) +{ + struct nlattr *exts[OVS_VXLAN_EXT_MAX + 1]; + int err; + + if (nla_len(attr) < sizeof(struct nlattr)) + return -EINVAL; + + err = nla_parse_nested(exts, OVS_VXLAN_EXT_MAX, attr, exts_policy); + if (err < 0) + return err; + + if (exts[OVS_VXLAN_EXT_GBP]) + conf->flags |= VXLAN_F_GBP; + + return 0; +} + +static struct vport *vxlan_tnl_create(const struct vport_parms *parms) +{ + struct net *net = ovs_dp_get_net(parms->dp); + struct nlattr *options = parms->options; + struct net_device *dev; + struct vport *vport; + struct nlattr *a; + int err; + struct vxlan_config conf = { + .no_share = true, + .flags = VXLAN_F_FLOW_BASED | VXLAN_F_COLLECT_METADATA, + }; + + if (!options) { + err = -EINVAL; + goto error; + } + + a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); + if (a && nla_len(a) == sizeof(u16)) { + conf.dst_port = htons(nla_get_u16(a)); + } else { + /* Require destination port from userspace. */ + err = -EINVAL; + goto error; + } + + vport = ovs_vport_alloc(0, &ovs_vxlan_netdev_vport_ops, parms); + if (IS_ERR(vport)) + return vport; + + a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION); + if (a) { + err = vxlan_configure_exts(vport, a, &conf); + if (err) { + ovs_vport_free(vport); + goto error; + } + } + + rtnl_lock(); + dev = vxlan_dev_create(net, parms->name, NET_NAME_USER, &conf); + if (IS_ERR(dev)) { + rtnl_unlock(); + ovs_vport_free(vport); + return ERR_CAST(dev); + } + + dev_change_flags(dev, dev->flags | IFF_UP); + rtnl_unlock(); + return vport; +error: + return ERR_PTR(err); +} + +static struct vport *vxlan_create(const struct vport_parms *parms) +{ + struct vport *vport; + + vport = vxlan_tnl_create(parms); + if (IS_ERR(vport)) + return vport; + + return netdev_link(vport, parms->name); +} + +static void vxlan_destroy(struct vport *vport) +{ + rtnl_lock(); + if (vport->dev->priv_flags & IFF_OVS_DATAPATH) + ovs_netdev_detach_dev(vport); + + /* Early release so we can unregister the device */ + dev_put(vport->dev); + rtnl_delete_link(vport->dev); + vport->dev = NULL; + rtnl_unlock(); + + call_rcu(&vport->rcu, free_port_rcu); +} + +static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, + struct ip_tunnel_info *egress_tun_info) +{ + struct vxlan_dev *vxlan = netdev_priv(vport->dev); + struct net *net = ovs_dp_get_net(vport->dp); + __be16 dst_port = vxlan_dev_dst_port(vxlan); + __be16 src_port; + int port_min; + int port_max; + + inet_get_local_port_range(net, &port_min, &port_max); + src_port = udp_flow_src_port(net, skb, 0, 0, true); + + return ovs_tunnel_get_egress_info(egress_tun_info, net, + OVS_CB(skb)->egress_tun_info, + IPPROTO_UDP, skb->mark, + src_port, dst_port); +} + +static struct vport_ops ovs_vxlan_netdev_vport_ops = { + .type = OVS_VPORT_TYPE_VXLAN, + .create = vxlan_create, + .destroy = vxlan_destroy, + .get_options = vxlan_get_options, + .send = netdev_send, + .get_egress_tun_info = vxlan_get_egress_tun_info, +}; + +static int vxlan_compat_init(void) +{ + return ovs_vport_ops_register(&ovs_vxlan_netdev_vport_ops); +} + +static void vxlan_compat_exit(void) +{ + ovs_vport_ops_unregister(&ovs_vxlan_netdev_vport_ops); +} +#else +static int vxlan_compat_init(void) +{ + return 0; +} + +static void vxlan_compat_exit(void) +{ +} +#endif + int __init ovs_netdev_init(void) { - return ovs_vport_ops_register(&ovs_netdev_vport_ops); + int err; + + err = ovs_vport_ops_register(&ovs_netdev_vport_ops); + if (err) + return err; + err = vxlan_compat_init(); + if (err) + vxlan_compat_exit(); + return err; } void ovs_netdev_exit(void) { ovs_vport_ops_unregister(&ovs_netdev_vport_ops); + vxlan_compat_exit(); } diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c deleted file mode 100644 index 6f7986fabb70..000000000000 --- a/net/openvswitch/vport-vxlan.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (c) 2014 Nicira, Inc. - * Copyright (c) 2013 Cisco Systems, Inc. - * - * 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-1301, USA - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "datapath.h" -#include "vport.h" -#include "vport-vxlan.h" - -/** - * struct vxlan_port - Keeps track of open UDP ports - * @vs: vxlan_sock created for the port. - * @name: vport name. - */ -struct vxlan_port { - struct vxlan_sock *vs; - char name[IFNAMSIZ]; - u32 exts; /* VXLAN_F_* in */ -}; - -static struct vport_ops ovs_vxlan_vport_ops; - -static inline struct vxlan_port *vxlan_vport(const struct vport *vport) -{ - return vport_priv(vport); -} - -/* Called with rcu_read_lock and BH disabled. */ -static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, - struct vxlan_metadata *md) -{ - struct ip_tunnel_info tun_info; - struct vxlan_port *vxlan_port; - struct vport *vport = vs->data; - struct iphdr *iph; - struct ovs_vxlan_opts opts = { - .gbp = md->gbp, - }; - __be64 key; - __be16 flags; - - flags = TUNNEL_KEY | (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0); - vxlan_port = vxlan_vport(vport); - if (vxlan_port->exts & VXLAN_F_GBP && md->gbp) - flags |= TUNNEL_VXLAN_OPT; - - /* Save outer tunnel values */ - iph = ip_hdr(skb); - key = cpu_to_be64(ntohl(md->vni) >> 8); - ip_tunnel_info_init(&tun_info, iph, - udp_hdr(skb)->source, udp_hdr(skb)->dest, - key, flags, &opts, sizeof(opts)); - - ovs_vport_receive(vport, skb, &tun_info); -} - -static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) -{ - struct vxlan_port *vxlan_port = vxlan_vport(vport); - __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport; - - if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port))) - return -EMSGSIZE; - - if (vxlan_port->exts) { - struct nlattr *exts; - - exts = nla_nest_start(skb, OVS_TUNNEL_ATTR_EXTENSION); - if (!exts) - return -EMSGSIZE; - - if (vxlan_port->exts & VXLAN_F_GBP && - nla_put_flag(skb, OVS_VXLAN_EXT_GBP)) - return -EMSGSIZE; - - nla_nest_end(skb, exts); - } - - return 0; -} - -static void vxlan_tnl_destroy(struct vport *vport) -{ - struct vxlan_port *vxlan_port = vxlan_vport(vport); - - vxlan_sock_release(vxlan_port->vs); - - ovs_vport_deferred_free(vport); -} - -static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX+1] = { - [OVS_VXLAN_EXT_GBP] = { .type = NLA_FLAG, }, -}; - -static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr) -{ - struct nlattr *exts[OVS_VXLAN_EXT_MAX+1]; - struct vxlan_port *vxlan_port; - int err; - - if (nla_len(attr) < sizeof(struct nlattr)) - return -EINVAL; - - err = nla_parse_nested(exts, OVS_VXLAN_EXT_MAX, attr, exts_policy); - if (err < 0) - return err; - - vxlan_port = vxlan_vport(vport); - - if (exts[OVS_VXLAN_EXT_GBP]) - vxlan_port->exts |= VXLAN_F_GBP; - - return 0; -} - -static struct vport *vxlan_tnl_create(const struct vport_parms *parms) -{ - struct net *net = ovs_dp_get_net(parms->dp); - struct nlattr *options = parms->options; - struct vxlan_port *vxlan_port; - struct vxlan_sock *vs; - struct vport *vport; - struct nlattr *a; - u16 dst_port; - int err; - - if (!options) { - err = -EINVAL; - goto error; - } - a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); - if (a && nla_len(a) == sizeof(u16)) { - dst_port = nla_get_u16(a); - } else { - /* Require destination port from userspace. */ - err = -EINVAL; - goto error; - } - - vport = ovs_vport_alloc(sizeof(struct vxlan_port), - &ovs_vxlan_vport_ops, parms); - if (IS_ERR(vport)) - return vport; - - vxlan_port = vxlan_vport(vport); - strncpy(vxlan_port->name, parms->name, IFNAMSIZ); - - a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION); - if (a) { - err = vxlan_configure_exts(vport, a); - if (err) { - ovs_vport_free(vport); - goto error; - } - } - - vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true, - vxlan_port->exts); - if (IS_ERR(vs)) { - ovs_vport_free(vport); - return (void *)vs; - } - vxlan_port->vs = vs; - - return vport; - -error: - return ERR_PTR(err); -} - -static int vxlan_ext_gbp(struct sk_buff *skb) -{ - const struct ip_tunnel_info *tun_info; - const struct ovs_vxlan_opts *opts; - - tun_info = OVS_CB(skb)->egress_tun_info; - opts = tun_info->options; - - if (tun_info->key.tun_flags & TUNNEL_VXLAN_OPT && - tun_info->options_len >= sizeof(*opts)) - return opts->gbp; - else - return 0; -} - -static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) -{ - struct net *net = ovs_dp_get_net(vport->dp); - struct vxlan_port *vxlan_port = vxlan_vport(vport); - struct sock *sk = vxlan_port->vs->sock->sk; - __be16 dst_port = inet_sk(sk)->inet_sport; - const struct ip_tunnel_key *tun_key; - struct vxlan_metadata md = {0}; - struct rtable *rt; - struct flowi4 fl; - __be16 src_port; - __be16 df; - int err; - u32 vxflags; - - if (unlikely(!OVS_CB(skb)->egress_tun_info)) { - err = -EINVAL; - goto error; - } - - tun_key = &OVS_CB(skb)->egress_tun_info->key; - rt = ovs_tunnel_route_lookup(net, tun_key, skb->mark, &fl, IPPROTO_UDP); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - goto error; - } - - df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? - htons(IP_DF) : 0; - - skb->ignore_df = 1; - - src_port = udp_flow_src_port(net, skb, 0, 0, true); - md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8); - md.gbp = vxlan_ext_gbp(skb); - vxflags = vxlan_port->exts | - (tun_key->tun_flags & TUNNEL_CSUM ? VXLAN_F_UDP_CSUM : 0); - - err = vxlan_xmit_skb(rt, sk, skb, fl.saddr, tun_key->ipv4_dst, - tun_key->ipv4_tos, tun_key->ipv4_ttl, df, - src_port, dst_port, - &md, false, vxflags); - if (err < 0) - ip_rt_put(rt); - return err; -error: - kfree_skb(skb); - return err; -} - -static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ip_tunnel_info *egress_tun_info) -{ - struct net *net = ovs_dp_get_net(vport->dp); - struct vxlan_port *vxlan_port = vxlan_vport(vport); - __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport; - __be16 src_port; - int port_min; - int port_max; - - inet_get_local_port_range(net, &port_min, &port_max); - src_port = udp_flow_src_port(net, skb, 0, 0, true); - - return ovs_tunnel_get_egress_info(egress_tun_info, net, - OVS_CB(skb)->egress_tun_info, - IPPROTO_UDP, skb->mark, - src_port, dst_port); -} - -static const char *vxlan_get_name(const struct vport *vport) -{ - struct vxlan_port *vxlan_port = vxlan_vport(vport); - return vxlan_port->name; -} - -static struct vport_ops ovs_vxlan_vport_ops = { - .type = OVS_VPORT_TYPE_VXLAN, - .create = vxlan_tnl_create, - .destroy = vxlan_tnl_destroy, - .get_name = vxlan_get_name, - .get_options = vxlan_get_options, - .send = vxlan_tnl_send, - .get_egress_tun_info = vxlan_get_egress_tun_info, - .owner = THIS_MODULE, -}; - -static int __init ovs_vxlan_tnl_init(void) -{ - return ovs_vport_ops_register(&ovs_vxlan_vport_ops); -} - -static void __exit ovs_vxlan_tnl_exit(void) -{ - ovs_vport_ops_unregister(&ovs_vxlan_vport_ops); -} - -module_init(ovs_vxlan_tnl_init); -module_exit(ovs_vxlan_tnl_exit); - -MODULE_DESCRIPTION("OVS: VXLAN switching port"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("vport-type-4"); diff --git a/net/openvswitch/vport-vxlan.h b/net/openvswitch/vport-vxlan.h deleted file mode 100644 index 4b08233e73d5..000000000000 --- a/net/openvswitch/vport-vxlan.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef VPORT_VXLAN_H -#define VPORT_VXLAN_H 1 - -#include -#include - -struct ovs_vxlan_opts { - __u32 gbp; -}; - -#endif -- cgit v1.3-6-gb490 From 932c435caba8a2ce473a91753bad0173269ef334 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Mon, 13 Jul 2015 11:40:02 -0700 Subject: PCI: Add dev_flags bit to access VPD through function 0 Add a dev_flags bit, PCI_DEV_FLAGS_VPD_REF_F0, to access VPD through function 0 to provide VPD access on other functions. This is for hardware devices that provide copies of the same VPD capability registers in multiple functions. Because the kernel expects that each function has its own registers, both the locking and the state tracking are affected by VPD accesses to different functions. On such devices for example, if a VPD write is performed on function 0, *any* later attempt to read VPD from any other function of that device will hang. This has to do with how the kernel tracks the expected value of the F bit per function. Concurrent accesses to different functions of the same device can not only hang but also corrupt both read and write VPD data. When hangs occur, typically the error message: vpd r/w failed. This is likely a firmware bug on this device. will be seen. Never set this bit on function 0 or there will be an infinite recursion. Signed-off-by: Mark Rustad Signed-off-by: Bjorn Helgaas Acked-by: Alexander Duyck CC: stable@vger.kernel.org --- drivers/pci/access.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/pci.h | 2 ++ 2 files changed, 62 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 5465b005220c..769f7e35f1a2 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -439,6 +439,56 @@ static const struct pci_vpd_ops pci_vpd_pci22_ops = { .release = pci_vpd_pci22_release, }; +static ssize_t pci_vpd_f0_read(struct pci_dev *dev, loff_t pos, size_t count, + void *arg) +{ + struct pci_dev *tdev = pci_get_slot(dev->bus, PCI_SLOT(dev->devfn)); + ssize_t ret; + + if (!tdev) + return -ENODEV; + + ret = pci_read_vpd(tdev, pos, count, arg); + pci_dev_put(tdev); + return ret; +} + +static ssize_t pci_vpd_f0_write(struct pci_dev *dev, loff_t pos, size_t count, + const void *arg) +{ + struct pci_dev *tdev = pci_get_slot(dev->bus, PCI_SLOT(dev->devfn)); + ssize_t ret; + + if (!tdev) + return -ENODEV; + + ret = pci_write_vpd(tdev, pos, count, arg); + pci_dev_put(tdev); + return ret; +} + +static const struct pci_vpd_ops pci_vpd_f0_ops = { + .read = pci_vpd_f0_read, + .write = pci_vpd_f0_write, + .release = pci_vpd_pci22_release, +}; + +static int pci_vpd_f0_dev_check(struct pci_dev *dev) +{ + struct pci_dev *tdev = pci_get_slot(dev->bus, PCI_SLOT(dev->devfn)); + int ret = 0; + + if (!tdev) + return -ENODEV; + if (!tdev->vpd || !tdev->multifunction || + dev->class != tdev->class || dev->vendor != tdev->vendor || + dev->device != tdev->device) + ret = -ENODEV; + + pci_dev_put(tdev); + return ret; +} + int pci_vpd_pci22_init(struct pci_dev *dev) { struct pci_vpd_pci22 *vpd; @@ -447,12 +497,21 @@ int pci_vpd_pci22_init(struct pci_dev *dev) cap = pci_find_capability(dev, PCI_CAP_ID_VPD); if (!cap) return -ENODEV; + if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) { + int ret = pci_vpd_f0_dev_check(dev); + + if (ret) + return ret; + } vpd = kzalloc(sizeof(*vpd), GFP_ATOMIC); if (!vpd) return -ENOMEM; vpd->base.len = PCI_VPD_PCI22_SIZE; - vpd->base.ops = &pci_vpd_pci22_ops; + if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) + vpd->base.ops = &pci_vpd_f0_ops; + else + vpd->base.ops = &pci_vpd_pci22_ops; mutex_init(&vpd->lock); vpd->cap = cap; vpd->busy = false; diff --git a/include/linux/pci.h b/include/linux/pci.h index 8a0321a8fb59..8edb125db13a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -180,6 +180,8 @@ enum pci_dev_flags { PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 6), /* Do not use PM reset even if device advertises NoSoftRst- */ PCI_DEV_FLAGS_NO_PM_RESET = (__force pci_dev_flags_t) (1 << 7), + /* Get VPD from function 0 VPD */ + PCI_DEV_FLAGS_VPD_REF_F0 = (__force pci_dev_flags_t) (1 << 8), }; enum pci_irq_reroute_variant { -- cgit v1.3-6-gb490 From 7aa6ca4d39edf01f997b9e02cf6d2fdeb224f351 Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Mon, 13 Jul 2015 11:40:07 -0700 Subject: PCI: Add VPD function 0 quirk for Intel Ethernet devices Set the PCI_DEV_FLAGS_VPD_REF_F0 flag on all Intel Ethernet device functions other than function 0, so that on multi-function devices, we will always read VPD from function 0 instead of from the other functions. [bhelgaas: changelog] Signed-off-by: Mark Rustad Signed-off-by: Bjorn Helgaas Acked-by: Alexander Duyck CC: stable@vger.kernel.org --- drivers/pci/quirks.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 96b354814cb7..b6af4b0192b8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1895,6 +1895,15 @@ static void quirk_netmos(struct pci_dev *dev) DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_SERIAL, 8, quirk_netmos); +static void quirk_f0_vpd_link(struct pci_dev *dev) +{ + if (!dev->multifunction || !PCI_FUNC(dev->devfn)) + return; + dev->dev_flags |= PCI_DEV_FLAGS_VPD_REF_F0; +} +DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, + PCI_CLASS_NETWORK_ETHERNET, 8, quirk_f0_vpd_link); + static void quirk_e100_interrupt(struct pci_dev *dev) { u16 command, pmcsr; -- cgit v1.3-6-gb490 From 019d8817b1b064c2bacfbcf40fc68184438ad05a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 15 Jul 2015 14:40:06 +0200 Subject: PM / sleep: Allow devices without runtime PM to do direct-complete Don't unset the direct_complete flag on devices that have runtime PM disabled, if they are runtime suspended. This is needed because otherwise ancestor devices wouldn't be able to do direct_complete without adding runtime PM support to all its descendants. Also removes pm_runtime_suspended_if_enabled() because it's now unused. Signed-off-by: Tomeu Vizoso Signed-off-by: Alan Stern Signed-off-by: Rafael J. Wysocki --- Documentation/power/devices.txt | 7 +++++++ Documentation/power/runtime_pm.txt | 4 ---- drivers/base/power/main.c | 2 +- include/linux/pm_runtime.h | 6 ------ 4 files changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index d172bce0fd49..8ba6625fdd63 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -341,6 +341,13 @@ the phases are: and is entirely responsible for bringing the device back to the functional state as appropriate. + Note that this direct-complete procedure applies even if the device is + disabled for runtime PM; only the runtime-PM status matters. It follows + that if a device has system-sleep callbacks but does not support runtime + PM, then its prepare callback must never return a positive value. This + is because all devices are initially set to runtime-suspended with + runtime PM disabled. + 2. The suspend methods should quiesce the device to stop it from performing I/O. They also may save the device registers and put it into the appropriate low-power state, depending on the bus type the device is on, diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index e76dc0ad4d2b..0784bc3a2ab5 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -445,10 +445,6 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: bool pm_runtime_status_suspended(struct device *dev); - return true if the device's runtime PM status is 'suspended' - bool pm_runtime_suspended_if_enabled(struct device *dev); - - return true if the device's runtime PM status is 'suspended' and its - 'power.disable_depth' field is equal to 1 - void pm_runtime_allow(struct device *dev); - set the power.runtime_auto flag for the device and decrease its usage counter (used by the /sys/devices/.../power/control interface to diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 30b7bbfdc558..1710c26ba097 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1377,7 +1377,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) if (dev->power.direct_complete) { if (pm_runtime_status_suspended(dev)) { pm_runtime_disable(dev); - if (pm_runtime_suspended_if_enabled(dev)) + if (pm_runtime_status_suspended(dev)) goto Complete; pm_runtime_enable(dev); diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 30e84d48bfea..3bdbb4189780 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -98,11 +98,6 @@ static inline bool pm_runtime_status_suspended(struct device *dev) return dev->power.runtime_status == RPM_SUSPENDED; } -static inline bool pm_runtime_suspended_if_enabled(struct device *dev) -{ - return pm_runtime_status_suspended(dev) && dev->power.disable_depth == 1; -} - static inline bool pm_runtime_enabled(struct device *dev) { return !dev->power.disable_depth; @@ -164,7 +159,6 @@ static inline void device_set_run_wake(struct device *dev, bool enable) {} static inline bool pm_runtime_suspended(struct device *dev) { return false; } static inline bool pm_runtime_active(struct device *dev) { return true; } static inline bool pm_runtime_status_suspended(struct device *dev) { return false; } -static inline bool pm_runtime_suspended_if_enabled(struct device *dev) { return false; } static inline bool pm_runtime_enabled(struct device *dev) { return false; } static inline void pm_runtime_no_callbacks(struct device *dev) {} -- cgit v1.3-6-gb490 From c45f5c9943ce0b16b299b543c2aae12408039027 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Tue, 21 Jul 2015 15:08:13 -0600 Subject: nvme: Fixes u64 division which breaks i386 builds Uses div_u64 for u64 division and round_down, a bitwise operation, instead of rounddown, which uses a modulus. Signed-off-by: Jon Derrick Signed-off-by: Jens Axboe --- drivers/block/nvme-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 82b4ffb6eefa..666e994fd622 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1454,8 +1454,9 @@ static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues, unsigned q_size_aligned = roundup(q_depth * entry_size, dev->page_size); if (q_size_aligned * nr_io_queues > dev->cmb_size) { - q_depth = rounddown(dev->cmb_size / nr_io_queues, - dev->page_size) / entry_size; + u64 mem_per_q = div_u64(dev->cmb_size, nr_io_queues); + mem_per_q = round_down(mem_per_q, dev->page_size); + q_depth = div_u64(mem_per_q, entry_size); /* * Ensure the reduced q_depth is above some threshold where it -- cgit v1.3-6-gb490 From d2eac98f7d1b950b762a7eca05a9ce0ea1d878d2 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 20 Jul 2015 17:49:55 -0700 Subject: net: dsa: bcm_sf2: Do not override speed settings The SF2 driver currently overrides speed settings for its port configured using a fixed PHY, this is both unnecessary and incorrect, because we keep feedback to the hardware parameters that we read from the PHY device, which in the case of a fixed PHY cannot possibly change speed. This is a required change to allow the fixed PHY code to allow registering a PHY with a link configured as DOWN by default and avoid some sort of circular dependency where we require the link_update callback to run to program the hardware, and we then utilize the fixed PHY parameters to program the hardware with the same settings. Fixes: 246d7f773c13 ("net: dsa: add Broadcom SF2 switch driver") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 972982f8bea7..3297604f8216 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -890,15 +890,11 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port, struct fixed_phy_status *status) { struct bcm_sf2_priv *priv = ds_to_priv(ds); - u32 duplex, pause, speed; + u32 duplex, pause; u32 reg; duplex = core_readl(priv, CORE_DUPSTS); pause = core_readl(priv, CORE_PAUSESTS); - speed = core_readl(priv, CORE_SPDSTS); - - speed >>= (port * SPDSTS_SHIFT); - speed &= SPDSTS_MASK; status->link = 0; @@ -933,18 +929,6 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port, reg &= ~LINK_STS; core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port)); - switch (speed) { - case SPDSTS_10: - status->speed = SPEED_10; - break; - case SPDSTS_100: - status->speed = SPEED_100; - break; - case SPDSTS_1000: - status->speed = SPEED_1000; - break; - } - if ((pause & (1 << port)) && (pause & (1 << (port + PAUSESTS_TX_PAUSE_SHIFT)))) { status->asym_pause = 1; -- cgit v1.3-6-gb490 From 868a4215be9a6d80548ccb74763b883dc99d32a2 Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Mon, 20 Jul 2015 17:49:56 -0700 Subject: net: phy: fixed_phy: handle link-down case fixed_phy_register() currently hardcodes the fixed PHY link to 1, and expects to find a "speed" parameter to provide correct information towards the fixed PHY consumer. In a subsequent change, where we allow "managed" (e.g: (RS)GMII in-band status auto-negotiation) fixed PHYs, none of these parameters can be provided since they will be auto-negotiated, hence, we just provide a zero-initialized fixed_phy_status to fixed_phy_register() which makes it fail when we call fixed_phy_update_regs() since status.speed = 0 which makes us hit the "default" label and error out. Without this change, we would also see potentially inconsistent speed/duplex parameters for fixed PHYs when the link is DOWN. CC: netdev@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Stas Sergeev [florian: add more background to why this is correct and desirable] Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/fixed_phy.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 1960b46add65..479b93f9581c 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -52,6 +52,10 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) u16 lpagb = 0; u16 lpa = 0; + if (!fp->status.link) + goto done; + bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; + if (fp->status.duplex) { bmcr |= BMCR_FULLDPLX; @@ -96,15 +100,13 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) } } - if (fp->status.link) - bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; - if (fp->status.pause) lpa |= LPA_PAUSE_CAP; if (fp->status.asym_pause) lpa |= LPA_PAUSE_ASYM; +done: fp->regs[MII_PHYSID1] = 0; fp->regs[MII_PHYSID2] = 0; -- cgit v1.3-6-gb490 From 4cba5c2103657d43d0886e4cff8004d95a3d0def Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Mon, 20 Jul 2015 17:49:57 -0700 Subject: of_mdio: add new DT property 'managed' to specify the PHY management type Currently the PHY management type is selected by the MAC driver arbitrary. The decision is based on the presence of the "fixed-link" node and on a will of the driver's authors. This caused a regression recently, when mvneta driver suddenly started to use the in-band status for auto-negotiation on fixed links. It appears the auto-negotiation may not work when expected by the MAC driver. Sebastien Rannou explains: << Yes, I confirm that my HW does not generate an in-band status. AFAIK, it's a PHY that aggregates 4xSGMIIs to 1xQSGMII ; the MAC side of the PHY (with inband status) is connected to the switch through QSGMII, and in this context we are on the media side of the PHY. >> https://lkml.org/lkml/2015/7/10/206 This patch introduces the new string property 'managed' that allows the user to set the management type explicitly. The supported values are: "auto" - default. Uses either MDIO or nothing, depending on the presence of the fixed-link node "in-band-status" - use in-band status Signed-off-by: Stas Sergeev CC: Rob Herring CC: Pawel Moll CC: Mark Rutland CC: Ian Campbell CC: Kumar Gala CC: Florian Fainelli CC: Grant Likely CC: devicetree@vger.kernel.org CC: linux-kernel@vger.kernel.org CC: netdev@vger.kernel.org Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/ethernet.txt | 4 ++++ drivers/of/of_mdio.c | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/net/ethernet.txt b/Documentation/devicetree/bindings/net/ethernet.txt index 41b3f3f864e8..5d88f37480b6 100644 --- a/Documentation/devicetree/bindings/net/ethernet.txt +++ b/Documentation/devicetree/bindings/net/ethernet.txt @@ -25,7 +25,11 @@ The following properties are common to the Ethernet controllers: flow control thresholds. - tx-fifo-depth: the size of the controller's transmit fifo in bytes. This is used for components that can have configurable fifo sizes. +- managed: string, specifies the PHY management type. Supported values are: + "auto", "in-band-status". "auto" is the default, it usess MDIO for + management if fixed-link is not specified. Child nodes of the Ethernet controller are typically the individual PHY devices connected via the MDIO bus (sometimes the MDIO bus controller is separate). They are described in the phy.txt file in this same directory. +For non-MDIO PHY management see fixed-link.txt. diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index fdc60db60829..7c8c23cc6896 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -266,7 +266,8 @@ EXPORT_SYMBOL(of_phy_attach); bool of_phy_is_fixed_link(struct device_node *np) { struct device_node *dn; - int len; + int len, err; + const char *managed; /* New binding */ dn = of_get_child_by_name(np, "fixed-link"); @@ -275,6 +276,10 @@ bool of_phy_is_fixed_link(struct device_node *np) return true; } + err = of_property_read_string(np, "managed", &managed); + if (err == 0 && strcmp(managed, "auto") != 0) + return true; + /* Old binding */ if (of_get_property(np, "fixed-link", &len) && len == (5 * sizeof(__be32))) @@ -289,8 +294,18 @@ int of_phy_register_fixed_link(struct device_node *np) struct fixed_phy_status status = {}; struct device_node *fixed_link_node; const __be32 *fixed_link_prop; - int len; + int len, err; struct phy_device *phy; + const char *managed; + + err = of_property_read_string(np, "managed", &managed); + if (err == 0) { + if (strcmp(managed, "in-band-status") == 0) { + /* status is zeroed, namely its .link member */ + phy = fixed_phy_register(PHY_POLL, &status, np); + return IS_ERR(phy) ? PTR_ERR(phy) : 0; + } + } /* New binding */ fixed_link_node = of_get_child_by_name(np, "fixed-link"); -- cgit v1.3-6-gb490 From f8af8e6eb95093d5ce5ebcc52bd1929b0433e172 Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Mon, 20 Jul 2015 17:49:58 -0700 Subject: mvneta: use inband status only when explicitly enabled The commit 898b2970e2c9 ("mvneta: implement SGMII-based in-band link state signaling") implemented the link parameters auto-negotiation unconditionally. Unfortunately it appears that some HW that implements SGMII protocol, doesn't generate the inband status, so it is not possible to auto-negotiate anything with such HW. This patch enables the auto-negotiation only if explicitly requested with the 'managed' DT property. This patch fixes the following regression: https://lkml.org/lkml/2015/7/8/865 Signed-off-by: Stas Sergeev CC: Thomas Petazzoni CC: netdev@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 370e20ed224c..e4fb172d91a6 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -3029,8 +3029,8 @@ static int mvneta_probe(struct platform_device *pdev) const char *dt_mac_addr; char hw_mac_addr[ETH_ALEN]; const char *mac_from; + const char *managed; int phy_mode; - int fixed_phy = 0; int err; /* Our multiqueue support is not complete, so for now, only @@ -3064,7 +3064,6 @@ static int mvneta_probe(struct platform_device *pdev) dev_err(&pdev->dev, "cannot register fixed PHY\n"); goto err_free_irq; } - fixed_phy = 1; /* In the case of a fixed PHY, the DT node associated * to the PHY is the Ethernet MAC DT node. @@ -3088,8 +3087,10 @@ static int mvneta_probe(struct platform_device *pdev) pp = netdev_priv(dev); pp->phy_node = phy_node; pp->phy_interface = phy_mode; - pp->use_inband_status = (phy_mode == PHY_INTERFACE_MODE_SGMII) && - fixed_phy; + + err = of_property_read_string(dn, "managed", &managed); + pp->use_inband_status = (err == 0 && + strcmp(managed, "in-band-status") == 0); pp->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pp->clk)) { -- cgit v1.3-6-gb490 From a9196bb048a78936d097600fb47b0b5ab9cc00d5 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Tue, 21 Jul 2015 15:08:56 +0100 Subject: sfc: update MCDI protocol definitions Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mcdi_pcol.h | 3463 +++++++++++++++++++++++++--------- 1 file changed, 2600 insertions(+), 863 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/mcdi_pcol.h b/drivers/net/ethernet/sfc/mcdi_pcol.h index 45fca9fc66b7..4cc772164a79 100644 --- a/drivers/net/ethernet/sfc/mcdi_pcol.h +++ b/drivers/net/ethernet/sfc/mcdi_pcol.h @@ -26,6 +26,10 @@ * Unlike a warm boot, assume DMEM has been reloaded, so that * the MC persistent data must be reinitialised. */ #define MC_FW_TEPID_BOOT_OK (16) +/* We have entered the main firmware via recovery mode. This + * means that MC persistent data must be reinitialised, but that + * we shouldn't touch PCIe config. */ +#define MC_FW_RECOVERY_MODE_PCIE_INIT_OK (32) /* BIST state has been initialized */ #define MC_FW_BIST_INIT_OK (128) @@ -169,6 +173,8 @@ #define MC_CMD_ERR_EINTR 4 /* I/O failure */ #define MC_CMD_ERR_EIO 5 +/* Already exists */ +#define MC_CMD_ERR_EEXIST 6 /* Try again */ #define MC_CMD_ERR_EAGAIN 11 /* Out of memory */ @@ -181,6 +187,10 @@ #define MC_CMD_ERR_ENODEV 19 /* Invalid argument to target */ #define MC_CMD_ERR_EINVAL 22 +/* Broken pipe */ +#define MC_CMD_ERR_EPIPE 32 +/* Read-only */ +#define MC_CMD_ERR_EROFS 30 /* Out of range */ #define MC_CMD_ERR_ERANGE 34 /* Non-recursive resource is already acquired */ @@ -226,6 +236,43 @@ #define MC_CMD_ERR_SLAVE_NOT_PRESENT 0x100a /* The datapath is disabled. */ #define MC_CMD_ERR_DATAPATH_DISABLED 0x100b +/* The requesting client is not a function */ +#define MC_CMD_ERR_CLIENT_NOT_FN 0x100c +/* The requested operation might require the + command to be passed between MCs, and the + transport doesn't support that. Should + only ever been seen over the UART. */ +#define MC_CMD_ERR_TRANSPORT_NOPROXY 0x100d +/* VLAN tag(s) exists */ +#define MC_CMD_ERR_VLAN_EXIST 0x100e +/* No MAC address assigned to an EVB port */ +#define MC_CMD_ERR_NO_MAC_ADDR 0x100f +/* Notifies the driver that the request has been relayed + * to an admin function for authorization. The driver should + * wait for a PROXY_RESPONSE event and then resend its request. + * This error code is followed by a 32-bit handle that + * helps matching it with the respective PROXY_RESPONSE event. */ +#define MC_CMD_ERR_PROXY_PENDING 0x1010 +#define MC_CMD_ERR_PROXY_PENDING_HANDLE_OFST 4 +/* The request cannot be passed for authorization because + * another request from the same function is currently being + * authorized. The drvier should try again later. */ +#define MC_CMD_ERR_PROXY_INPROGRESS 0x1011 +/* Returned by MC_CMD_PROXY_COMPLETE if the caller is not the function + * that has enabled proxying or BLOCK_INDEX points to a function that + * doesn't await an authorization. */ +#define MC_CMD_ERR_PROXY_UNEXPECTED 0x1012 +/* This code is currently only used internally in FW. Its meaning is that + * an operation failed due to lack of SR-IOV privilege. + * Normally it is translated to EPERM by send_cmd_err(), + * but it may also be used to trigger some special mechanism + * for handling such case, e.g. to relay the failed request + * to a designated admin function for authorization. */ +#define MC_CMD_ERR_NO_PRIVILEGE 0x1013 +/* Workaround 26807 could not be turned on/off because some functions + * have already installed filters. See the comment at + * MC_CMD_WORKAROUND_BUG26807. */ +#define MC_CMD_ERR_FILTERS_PRESENT 0x1014 #define MC_CMD_ERR_CODE_OFST 0 @@ -275,6 +322,11 @@ MC_CMD_DBIWROP_TYPEDEF_VALUE_OFST + \ (n) * MC_CMD_DBIWROP_TYPEDEF_LEN) +/* This may be ORed with an EVB_PORT_ID_xxx constant to pass a non-default + * stack ID (which must be in the range 1-255) along with an EVB port ID. + */ +#define EVB_STACK_ID(n) (((n) & 0xff) << 16) + /* Version 2 adds an optional argument to error returns: the errno value * may be followed by the (0-based) number of the first argument that @@ -394,6 +446,8 @@ #define MCDI_EVENT_AOE_BYTEBLASTER 0x9 /* enum: DDR ECC status update */ #define MCDI_EVENT_AOE_DDR_ECC_STATUS 0xa +/* enum: PTP status update */ +#define MCDI_EVENT_AOE_PTP_STATUS 0xb #define MCDI_EVENT_AOE_ERR_DATA_LBN 8 #define MCDI_EVENT_AOE_ERR_DATA_WIDTH 8 #define MCDI_EVENT_RX_ERR_RXQ_LBN 0 @@ -408,6 +462,16 @@ #define MCDI_EVENT_RX_FLUSH_RXQ_WIDTH 12 #define MCDI_EVENT_MC_REBOOT_COUNT_LBN 0 #define MCDI_EVENT_MC_REBOOT_COUNT_WIDTH 16 +#define MCDI_EVENT_MUM_ERR_TYPE_LBN 0 +#define MCDI_EVENT_MUM_ERR_TYPE_WIDTH 8 +/* enum: MUM failed to load - no valid image? */ +#define MCDI_EVENT_MUM_NO_LOAD 0x1 +/* enum: MUM f/w reported an exception */ +#define MCDI_EVENT_MUM_ASSERT 0x2 +/* enum: MUM not kicking watchdog */ +#define MCDI_EVENT_MUM_WATCHDOG 0x3 +#define MCDI_EVENT_MUM_ERR_DATA_LBN 8 +#define MCDI_EVENT_MUM_ERR_DATA_WIDTH 8 #define MCDI_EVENT_DATA_LBN 0 #define MCDI_EVENT_DATA_WIDTH 32 #define MCDI_EVENT_SRC_LBN 36 @@ -416,6 +480,8 @@ #define MCDI_EVENT_EV_CODE_WIDTH 4 #define MCDI_EVENT_CODE_LBN 44 #define MCDI_EVENT_CODE_WIDTH 8 +/* enum: Event generated by host software */ +#define MCDI_EVENT_SW_EVENT 0x0 /* enum: Bad assert. */ #define MCDI_EVENT_CODE_BADSSERT 0x1 /* enum: PM Notice. */ @@ -470,6 +536,14 @@ #define MCDI_EVENT_CODE_MC_BIST 0x19 /* enum: PTP tick event providing current NIC time */ #define MCDI_EVENT_CODE_PTP_TIME 0x1a +/* enum: MUM fault */ +#define MCDI_EVENT_CODE_MUM 0x1b +/* enum: notify the designated PF of a new authorization request */ +#define MCDI_EVENT_CODE_PROXY_REQUEST 0x1c +/* enum: notify a function that awaits an authorization that its request has + * been processed and it may now resend the command + */ +#define MCDI_EVENT_CODE_PROXY_RESPONSE 0x1d /* enum: Artificial event generated by host and posted via MC for test * purposes. */ @@ -537,6 +611,33 @@ /* For CODE_PTP_TIME events, bits 19-26 of the minor value of the PTP clock */ #define MCDI_EVENT_PTP_TIME_MINOR_26_19_LBN 36 #define MCDI_EVENT_PTP_TIME_MINOR_26_19_WIDTH 8 +/* For CODE_PTP_TIME events where report sync status is enabled, indicates + * whether the NIC clock has ever been set + */ +#define MCDI_EVENT_PTP_TIME_NIC_CLOCK_VALID_LBN 36 +#define MCDI_EVENT_PTP_TIME_NIC_CLOCK_VALID_WIDTH 1 +/* For CODE_PTP_TIME events where report sync status is enabled, indicates + * whether the NIC and System clocks are in sync + */ +#define MCDI_EVENT_PTP_TIME_HOST_NIC_IN_SYNC_LBN 37 +#define MCDI_EVENT_PTP_TIME_HOST_NIC_IN_SYNC_WIDTH 1 +/* For CODE_PTP_TIME events where report sync status is enabled, bits 21-26 of + * the minor value of the PTP clock + */ +#define MCDI_EVENT_PTP_TIME_MINOR_26_21_LBN 38 +#define MCDI_EVENT_PTP_TIME_MINOR_26_21_WIDTH 6 +#define MCDI_EVENT_PROXY_REQUEST_BUFF_INDEX_OFST 0 +#define MCDI_EVENT_PROXY_REQUEST_BUFF_INDEX_LBN 0 +#define MCDI_EVENT_PROXY_REQUEST_BUFF_INDEX_WIDTH 32 +#define MCDI_EVENT_PROXY_RESPONSE_HANDLE_OFST 0 +#define MCDI_EVENT_PROXY_RESPONSE_HANDLE_LBN 0 +#define MCDI_EVENT_PROXY_RESPONSE_HANDLE_WIDTH 32 +/* Zero means that the request has been completed or authorized, and the driver + * should resend it. A non-zero value means that the authorization has been + * denied, and gives the reason. Typically it will be EPERM. + */ +#define MCDI_EVENT_PROXY_RESPONSE_RC_LBN 36 +#define MCDI_EVENT_PROXY_RESPONSE_RC_WIDTH 8 /* FCDI_EVENT structuredef */ #define FCDI_EVENT_LEN 8 @@ -581,6 +682,10 @@ #define FCDI_EVENT_CODE_PTP_TICK 0x7 /* enum: ECC error counters */ #define FCDI_EVENT_CODE_DDR_ECC_STATUS 0x8 +/* enum: Current status of PTP */ +#define FCDI_EVENT_CODE_PTP_STATUS 0x9 +/* enum: Port id config to map MC-FC port idx */ +#define FCDI_EVENT_CODE_PORT_CONFIG 0xa #define FCDI_EVENT_ASSERT_INSTR_ADDRESS_OFST 0 #define FCDI_EVENT_ASSERT_INSTR_ADDRESS_LBN 0 #define FCDI_EVENT_ASSERT_INSTR_ADDRESS_WIDTH 32 @@ -594,11 +699,24 @@ #define FCDI_EVENT_LINK_STATE_DATA_OFST 0 #define FCDI_EVENT_LINK_STATE_DATA_LBN 0 #define FCDI_EVENT_LINK_STATE_DATA_WIDTH 32 +#define FCDI_EVENT_PTP_STATE_OFST 0 +#define FCDI_EVENT_PTP_UNDEFINED 0x0 /* enum */ +#define FCDI_EVENT_PTP_SETUP_FAILED 0x1 /* enum */ +#define FCDI_EVENT_PTP_OPERATIONAL 0x2 /* enum */ +#define FCDI_EVENT_PTP_STATE_LBN 0 +#define FCDI_EVENT_PTP_STATE_WIDTH 32 #define FCDI_EVENT_DDR_ECC_STATUS_BANK_ID_LBN 36 #define FCDI_EVENT_DDR_ECC_STATUS_BANK_ID_WIDTH 8 #define FCDI_EVENT_DDR_ECC_STATUS_STATUS_OFST 0 #define FCDI_EVENT_DDR_ECC_STATUS_STATUS_LBN 0 #define FCDI_EVENT_DDR_ECC_STATUS_STATUS_WIDTH 32 +/* Index of MC port being referred to */ +#define FCDI_EVENT_PORT_CONFIG_SRC_LBN 36 +#define FCDI_EVENT_PORT_CONFIG_SRC_WIDTH 8 +/* FC Port index that matches the MC port index in SRC */ +#define FCDI_EVENT_PORT_CONFIG_DATA_OFST 0 +#define FCDI_EVENT_PORT_CONFIG_DATA_LBN 0 +#define FCDI_EVENT_PORT_CONFIG_DATA_WIDTH 32 /* FCDI_EXTENDED_EVENT_PPS structuredef: Extended FCDI event to send PPS events * to the MC. Note that this structure | is overlayed over a normal FCDI event @@ -631,6 +749,90 @@ #define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_LBN 64 #define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_WIDTH 64 +/* MUM_EVENT structuredef */ +#define MUM_EVENT_LEN 8 +#define MUM_EVENT_CONT_LBN 32 +#define MUM_EVENT_CONT_WIDTH 1 +#define MUM_EVENT_LEVEL_LBN 33 +#define MUM_EVENT_LEVEL_WIDTH 3 +/* enum: Info. */ +#define MUM_EVENT_LEVEL_INFO 0x0 +/* enum: Warning. */ +#define MUM_EVENT_LEVEL_WARN 0x1 +/* enum: Error. */ +#define MUM_EVENT_LEVEL_ERR 0x2 +/* enum: Fatal. */ +#define MUM_EVENT_LEVEL_FATAL 0x3 +#define MUM_EVENT_DATA_OFST 0 +#define MUM_EVENT_SENSOR_ID_LBN 0 +#define MUM_EVENT_SENSOR_ID_WIDTH 8 +/* Enum values, see field(s): */ +/* MC_CMD_SENSOR_INFO/MC_CMD_SENSOR_INFO_OUT/MASK */ +#define MUM_EVENT_SENSOR_STATE_LBN 8 +#define MUM_EVENT_SENSOR_STATE_WIDTH 8 +#define MUM_EVENT_PORT_PHY_READY_LBN 0 +#define MUM_EVENT_PORT_PHY_READY_WIDTH 1 +#define MUM_EVENT_PORT_PHY_LINK_UP_LBN 1 +#define MUM_EVENT_PORT_PHY_LINK_UP_WIDTH 1 +#define MUM_EVENT_PORT_PHY_TX_LOL_LBN 2 +#define MUM_EVENT_PORT_PHY_TX_LOL_WIDTH 1 +#define MUM_EVENT_PORT_PHY_RX_LOL_LBN 3 +#define MUM_EVENT_PORT_PHY_RX_LOL_WIDTH 1 +#define MUM_EVENT_PORT_PHY_TX_LOS_LBN 4 +#define MUM_EVENT_PORT_PHY_TX_LOS_WIDTH 1 +#define MUM_EVENT_PORT_PHY_RX_LOS_LBN 5 +#define MUM_EVENT_PORT_PHY_RX_LOS_WIDTH 1 +#define MUM_EVENT_PORT_PHY_TX_FAULT_LBN 6 +#define MUM_EVENT_PORT_PHY_TX_FAULT_WIDTH 1 +#define MUM_EVENT_DATA_LBN 0 +#define MUM_EVENT_DATA_WIDTH 32 +#define MUM_EVENT_SRC_LBN 36 +#define MUM_EVENT_SRC_WIDTH 8 +#define MUM_EVENT_EV_CODE_LBN 60 +#define MUM_EVENT_EV_CODE_WIDTH 4 +#define MUM_EVENT_CODE_LBN 44 +#define MUM_EVENT_CODE_WIDTH 8 +/* enum: The MUM was rebooted. */ +#define MUM_EVENT_CODE_REBOOT 0x1 +/* enum: Bad assert. */ +#define MUM_EVENT_CODE_ASSERT 0x2 +/* enum: Sensor failure. */ +#define MUM_EVENT_CODE_SENSOR 0x3 +/* enum: Link fault has been asserted, or has cleared. */ +#define MUM_EVENT_CODE_QSFP_LASI_INTERRUPT 0x4 +#define MUM_EVENT_SENSOR_DATA_OFST 0 +#define MUM_EVENT_SENSOR_DATA_LBN 0 +#define MUM_EVENT_SENSOR_DATA_WIDTH 32 +#define MUM_EVENT_PORT_PHY_FLAGS_OFST 0 +#define MUM_EVENT_PORT_PHY_FLAGS_LBN 0 +#define MUM_EVENT_PORT_PHY_FLAGS_WIDTH 32 +#define MUM_EVENT_PORT_PHY_COPPER_LEN_OFST 0 +#define MUM_EVENT_PORT_PHY_COPPER_LEN_LBN 0 +#define MUM_EVENT_PORT_PHY_COPPER_LEN_WIDTH 32 +#define MUM_EVENT_PORT_PHY_CAPS_OFST 0 +#define MUM_EVENT_PORT_PHY_CAPS_LBN 0 +#define MUM_EVENT_PORT_PHY_CAPS_WIDTH 32 +#define MUM_EVENT_PORT_PHY_TECH_OFST 0 +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_UNKNOWN 0x0 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_OPTICAL 0x1 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_COPPER_PASSIVE 0x2 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_COPPER_PASSIVE_EQUALIZED 0x3 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_COPPER_ACTIVE_LIMITING 0x4 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_COPPER_ACTIVE_LINEAR 0x5 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_BASE_T 0x6 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_LOOPBACK_PASSIVE 0x7 /* enum */ +#define MUM_EVENT_PORT_PHY_TECH_LBN 0 +#define MUM_EVENT_PORT_PHY_TECH_WIDTH 32 +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_LBN 36 +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_WIDTH 4 +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_FLAGS 0x0 /* enum */ +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_COPPER_LEN 0x1 /* enum */ +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_CAPS 0x2 /* enum */ +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_TECH 0x3 /* enum */ +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_MAX 0x4 /* enum */ +#define MUM_EVENT_PORT_PHY_SRC_PORT_NO_LBN 40 +#define MUM_EVENT_PORT_PHY_SRC_PORT_NO_WIDTH 4 + /***********************************/ /* MC_CMD_READ32 @@ -687,24 +889,34 @@ /* MC_CMD_COPYCODE_IN msgrequest */ #define MC_CMD_COPYCODE_IN_LEN 16 -/* Source address */ -#define MC_CMD_COPYCODE_IN_SRC_ADDR_OFST 0 -/* enum: The main image should be entered via a copy of a single word from and - * to this address when none of the other magic behaviours are required. +/* Source address + * + * The main image should be entered via a copy of a single word from and to a + * magic address, which controls various aspects of the boot. The magic address + * is a bitfield, with each bit as documented below. */ +#define MC_CMD_COPYCODE_IN_SRC_ADDR_OFST 0 +/* enum: Deprecated; equivalent to setting BOOT_MAGIC_PRESENT (see below) */ #define MC_CMD_COPYCODE_HUNT_NO_MAGIC_ADDR 0x10000 -/* enum: Entering the main image via a copy of a single word from and to this - * address indicates that it should not attempt to start the datapath CPUs. - * This is useful for certain soft rebooting scenarios. (Huntington only) +/* enum: Deprecated; equivalent to setting BOOT_MAGIC_PRESENT and + * BOOT_MAGIC_SATELLITE_CPUS_NOT_LOADED (see below) */ #define MC_CMD_COPYCODE_HUNT_NO_DATAPATH_MAGIC_ADDR 0x1d0d0 -/* enum: Entering the main image via a copy of a single word from and to this - * address indicates that it should not attempt to parse any configuration from - * flash. (In addition, the datapath CPUs will not be started, as for - * MC_CMD_COPYCODE_HUNT_NO_DATAPATH_MAGIC_ADDR above.) This is useful for - * certain soft rebooting scenarios. (Huntington only) +/* enum: Deprecated; equivalent to setting BOOT_MAGIC_PRESENT, + * BOOT_MAGIC_SATELLITE_CPUS_NOT_LOADED and BOOT_MAGIC_IGNORE_CONFIG (see + * below) */ #define MC_CMD_COPYCODE_HUNT_IGNORE_CONFIG_MAGIC_ADDR 0x1badc +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_PRESENT_LBN 17 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_PRESENT_WIDTH 1 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_SATELLITE_CPUS_NOT_LOADED_LBN 2 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_SATELLITE_CPUS_NOT_LOADED_WIDTH 1 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_IGNORE_CONFIG_LBN 3 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_IGNORE_CONFIG_WIDTH 1 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_SKIP_BOOT_ICORE_SYNC_LBN 4 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_SKIP_BOOT_ICORE_SYNC_WIDTH 1 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_FORCE_STANDALONE_LBN 5 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_FORCE_STANDALONE_WIDTH 1 /* Destination address */ #define MC_CMD_COPYCODE_IN_DEST_ADDR_OFST 4 #define MC_CMD_COPYCODE_IN_NUMWORDS_OFST 8 @@ -795,6 +1007,10 @@ #define MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST 8 #define MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_LEN 4 #define MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM 31 +/* enum: A magic value hinting that the value in this register at the time of + * the failure has likely been lost. + */ +#define MC_CMD_GET_ASSERTS_REG_NO_DATA 0xda7a1057 /* Failing thread address */ #define MC_CMD_GET_ASSERTS_OUT_THREAD_OFFS_OFST 132 #define MC_CMD_GET_ASSERTS_OUT_RESERVED_OFST 136 @@ -802,7 +1018,8 @@ /***********************************/ /* MC_CMD_LOG_CTRL - * Configure the output stream for various events and messages. + * Configure the output stream for log events such as link state changes, + * sensor notifications and MCDI completions */ #define MC_CMD_LOG_CTRL 0x7 @@ -816,6 +1033,7 @@ #define MC_CMD_LOG_CTRL_IN_LOG_DEST_UART 0x1 /* enum: Event queue. */ #define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ 0x2 +/* Legacy argument. Must be zero. */ #define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ_OFST 4 /* MC_CMD_LOG_CTRL_OUT msgresponse */ @@ -955,8 +1173,12 @@ * input on the same NIC. */ #define MC_CMD_PTP_OP_MANFTEST_PPS 0x1a +/* enum: Set the PTP sync status. Status is used by firmware to report to event + * subscribers. + */ +#define MC_CMD_PTP_OP_SET_SYNC_STATUS 0x1b /* enum: Above this for future use. */ -#define MC_CMD_PTP_OP_MAX 0x1b +#define MC_CMD_PTP_OP_MAX 0x1c /* MC_CMD_PTP_IN_ENABLE msgrequest */ #define MC_CMD_PTP_IN_ENABLE_LEN 16 @@ -1191,8 +1413,12 @@ #define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_LEN 12 /* MC_CMD_PTP_IN_CMD_OFST 0 */ /* MC_CMD_PTP_IN_PERIPH_ID_OFST 4 */ -/* Event queue to send PTP time events to */ +/* Original field containing queue ID. Now extended to include flags. */ #define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_QUEUE_OFST 8 +#define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_QUEUE_ID_LBN 0 +#define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_QUEUE_ID_WIDTH 16 +#define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_REPORT_SYNC_STATUS_LBN 31 +#define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_REPORT_SYNC_STATUS_WIDTH 1 /* MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE msgrequest */ #define MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE_LEN 16 @@ -1214,6 +1440,23 @@ /* 1 to enable PPS test mode, 0 to disable and return result. */ #define MC_CMD_PTP_IN_MANFTEST_PPS_TEST_ENABLE_OFST 8 +/* MC_CMD_PTP_IN_SET_SYNC_STATUS msgrequest */ +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_LEN 24 +/* MC_CMD_PTP_IN_CMD_OFST 0 */ +/* MC_CMD_PTP_IN_PERIPH_ID_OFST 4 */ +/* NIC - Host System Clock Synchronization status */ +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_STATUS_OFST 8 +/* enum: Host System clock and NIC clock are not in sync */ +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_NOT_IN_SYNC 0x0 +/* enum: Host System clock and NIC clock are synchronized */ +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_IN_SYNC 0x1 +/* If synchronized, number of seconds until clocks should be considered to be + * no longer in sync. + */ +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_TIMEOUT_OFST 12 +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_RESERVED0_OFST 16 +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_RESERVED1_OFST 20 + /* MC_CMD_PTP_OUT msgresponse */ #define MC_CMD_PTP_OUT_LEN 0 @@ -1375,7 +1618,7 @@ #define MC_CMD_PTP_OUT_GET_TIME_FORMAT_SECONDS_27FRACTION 0x2 /* MC_CMD_PTP_OUT_GET_ATTRIBUTES msgresponse */ -#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_LEN 8 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_LEN 24 /* Time format required/used by for this NIC. Applies to all PTP MCDI * operations that pass times between the host and firmware. If this operation * is not supported (older firmware) a format of seconds and nanoseconds should @@ -1396,6 +1639,13 @@ * end and start times minus the time that the MC waited for host end. */ #define MC_CMD_PTP_OUT_GET_ATTRIBUTES_SYNC_WINDOW_MIN_OFST 4 +/* Various PTP capabilities */ +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_CAPABILITIES_OFST 8 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_REPORT_SYNC_STATUS_LBN 0 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_REPORT_SYNC_STATUS_WIDTH 1 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_RESERVED0_OFST 12 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_RESERVED1_OFST 16 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_RESERVED2_OFST 20 /* MC_CMD_PTP_OUT_GET_TIMESTAMP_CORRECTIONS msgresponse */ #define MC_CMD_PTP_OUT_GET_TIMESTAMP_CORRECTIONS_LEN 16 @@ -1415,6 +1665,9 @@ /* Enum values, see field(s): */ /* MC_CMD_PTP_OUT_MANFTEST_BASIC/TEST_RESULT */ +/* MC_CMD_PTP_OUT_SET_SYNC_STATUS msgresponse */ +#define MC_CMD_PTP_OUT_SET_SYNC_STATUS_LEN 0 + /***********************************/ /* MC_CMD_CSR_READ32 @@ -1915,6 +2168,14 @@ #define MC_CMD_FW_FULL_FEATURED 0x0 /* enum: Prefer to use firmware with fewer features but lower latency */ #define MC_CMD_FW_LOW_LATENCY 0x1 +/* enum: Prefer to use firmware for SolarCapture packed stream mode */ +#define MC_CMD_FW_PACKED_STREAM 0x2 +/* enum: Prefer to use firmware with fewer features and simpler TX event + * batching but higher TX packet rate + */ +#define MC_CMD_FW_HIGH_TX_RATE 0x3 +/* enum: Reserved value */ +#define MC_CMD_FW_PACKED_STREAM_HASH_MODE_1 0x4 /* enum: Only this option is allowed for non-admin functions */ #define MC_CMD_FW_DONT_CARE 0xffffffff @@ -2481,6 +2742,12 @@ #define MC_CMD_LOOPBACK_SD_FES_WS 0x22 /* enum: Near side of AOE Siena side port */ #define MC_CMD_LOOPBACK_AOE_INT_NEAR 0x23 +/* enum: Medford Wireside datapath loopback */ +#define MC_CMD_LOOPBACK_DATA_WS 0x24 +/* enum: Force link up without setting up any physical loopback (snapper use + * only) + */ +#define MC_CMD_LOOPBACK_FORCE_EXT_LINK 0x25 /* Supported loopbacks. */ #define MC_CMD_GET_LOOPBACK_MODES_OUT_1G_OFST 8 #define MC_CMD_GET_LOOPBACK_MODES_OUT_1G_LEN 8 @@ -2552,12 +2819,8 @@ #define MC_CMD_GET_LINK_OUT_LINK_FAULT_TX_WIDTH 1 /* This returns the negotiated flow control value. */ #define MC_CMD_GET_LINK_OUT_FCNTL_OFST 20 -/* enum: Flow control is off. */ -#define MC_CMD_FCNTL_OFF 0x0 -/* enum: Respond to flow control. */ -#define MC_CMD_FCNTL_RESPOND 0x1 -/* enum: Respond to and Issue flow control. */ -#define MC_CMD_FCNTL_BIDIR 0x2 +/* Enum values, see field(s): */ +/* MC_CMD_SET_MAC/MC_CMD_SET_MAC_IN/FCNTL */ #define MC_CMD_GET_LINK_OUT_MAC_FAULT_OFST 24 #define MC_CMD_MAC_FAULT_XGMII_LOCAL_LBN 0 #define MC_CMD_MAC_FAULT_XGMII_LOCAL_WIDTH 1 @@ -2632,7 +2895,7 @@ #define MC_CMD_0x2c_PRIVILEGE_CTG SRIOV_CTG_LINK /* MC_CMD_SET_MAC_IN msgrequest */ -#define MC_CMD_SET_MAC_IN_LEN 24 +#define MC_CMD_SET_MAC_IN_LEN 28 /* The MTU is the MTU programmed directly into the XMAC/GMAC (inclusive of * EtherII, VLAN, bug16011 padding). */ @@ -2649,13 +2912,20 @@ #define MC_CMD_SET_MAC_IN_REJECT_BRDCST_WIDTH 1 #define MC_CMD_SET_MAC_IN_FCNTL_OFST 20 /* enum: Flow control is off. */ -/* MC_CMD_FCNTL_OFF 0x0 */ +#define MC_CMD_FCNTL_OFF 0x0 /* enum: Respond to flow control. */ -/* MC_CMD_FCNTL_RESPOND 0x1 */ +#define MC_CMD_FCNTL_RESPOND 0x1 /* enum: Respond to and Issue flow control. */ -/* MC_CMD_FCNTL_BIDIR 0x2 */ +#define MC_CMD_FCNTL_BIDIR 0x2 /* enum: Auto neg flow control. */ #define MC_CMD_FCNTL_AUTO 0x3 +/* enum: Priority flow control (eftest builds only). */ +#define MC_CMD_FCNTL_QBB 0x4 +/* enum: Issue flow control. */ +#define MC_CMD_FCNTL_GENERATE 0x5 +#define MC_CMD_SET_MAC_IN_FLAGS_OFST 24 +#define MC_CMD_SET_MAC_IN_FLAG_INCLUDE_FCS_LBN 0 +#define MC_CMD_SET_MAC_IN_FLAG_INCLUDE_FCS_WIDTH 1 /* MC_CMD_SET_MAC_OUT msgresponse */ #define MC_CMD_SET_MAC_OUT_LEN 0 @@ -2748,7 +3018,8 @@ * guarantee consistent results. If the DMA_ADDR is 0, then no DMA is * performed, and the statistics may be read from the message response. If * DMA_ADDR != 0, then the statistics are dmad to that (page-aligned location). - * Locks required: None. Returns: 0, ETIME + * Locks required: None. The PERIODIC_CLEAR option is not used and now has no + * effect. Returns: 0, ETIME */ #define MC_CMD_MAC_STATS 0x2e @@ -2791,6 +3062,7 @@ #define MC_CMD_MAC_STATS_OUT_NO_DMA_STATISTICS_HI_OFST 4 #define MC_CMD_MAC_STATS_OUT_NO_DMA_STATISTICS_NUM MC_CMD_MAC_NSTATS #define MC_CMD_MAC_GENERATION_START 0x0 /* enum */ +#define MC_CMD_MAC_DMABUF_START 0x1 /* enum */ #define MC_CMD_MAC_TX_PKTS 0x1 /* enum */ #define MC_CMD_MAC_TX_PAUSE_PKTS 0x2 /* enum */ #define MC_CMD_MAC_TX_CONTROL_PKTS 0x3 /* enum */ @@ -2890,8 +3162,8 @@ * PM_AND_RXDP_COUNTERS capability only. */ #define MC_CMD_MAC_RXDP_STREAMING_PKTS 0x46 -/* enum: RXDP counter: Number of times an emergency descriptor fetch was - * performed. Valid for EF10 with PM_AND_RXDP_COUNTERS capability only. +/* enum: RXDP counter: Number of times an hlb descriptor fetch was performed. + * Valid for EF10 with PM_AND_RXDP_COUNTERS capability only. */ #define MC_CMD_MAC_RXDP_HLB_FETCH_CONDITIONS 0x47 /* enum: RXDP counter: Number of times the DPCPU waited for an existing @@ -3213,6 +3485,8 @@ #define MC_CMD_NVRAM_TYPE_LICENSE 0x12 /* enum: FC Log. */ #define MC_CMD_NVRAM_TYPE_FC_LOG 0x13 +/* enum: Additional flash on FPGA. */ +#define MC_CMD_NVRAM_TYPE_FC_EXTRA 0x14 /***********************************/ @@ -3407,6 +3681,8 @@ */ #define MC_CMD_SCHEDINFO 0x3e +#define MC_CMD_0x3e_PRIVILEGE_CTG SRIOV_CTG_ADMIN + /* MC_CMD_SCHEDINFO_IN msgrequest */ #define MC_CMD_SCHEDINFO_IN_LEN 0 @@ -3593,6 +3869,68 @@ #define MC_CMD_SENSOR_VDD08D_VSS08D_CSR_EXTADC 0x2c /* enum: Hotpoint temperature: degC */ #define MC_CMD_SENSOR_HOTPOINT_TEMP 0x2d +/* enum: Port 0 PHY power switch over-current: bool */ +#define MC_CMD_SENSOR_PHY_POWER_PORT0 0x2e +/* enum: Port 1 PHY power switch over-current: bool */ +#define MC_CMD_SENSOR_PHY_POWER_PORT1 0x2f +/* enum: Mop-up microcontroller reference voltage (millivolts) */ +#define MC_CMD_SENSOR_MUM_VCC 0x30 +/* enum: 0.9v power phase A voltage: mV */ +#define MC_CMD_SENSOR_IN_0V9_A 0x31 +/* enum: 0.9v power phase A current: mA */ +#define MC_CMD_SENSOR_IN_I0V9_A 0x32 +/* enum: 0.9V voltage regulator phase A temperature: degC */ +#define MC_CMD_SENSOR_VREG_0V9_A_TEMP 0x33 +/* enum: 0.9v power phase B voltage: mV */ +#define MC_CMD_SENSOR_IN_0V9_B 0x34 +/* enum: 0.9v power phase B current: mA */ +#define MC_CMD_SENSOR_IN_I0V9_B 0x35 +/* enum: 0.9V voltage regulator phase B temperature: degC */ +#define MC_CMD_SENSOR_VREG_0V9_B_TEMP 0x36 +/* enum: CCOM AVREG 1v2 supply (interval ADC): mV */ +#define MC_CMD_SENSOR_CCOM_AVREG_1V2_SUPPLY 0x37 +/* enum: CCOM AVREG 1v2 supply (external ADC): mV */ +#define MC_CMD_SENSOR_CCOM_AVREG_1V2_SUPPLY_EXTADC 0x38 +/* enum: CCOM AVREG 1v8 supply (interval ADC): mV */ +#define MC_CMD_SENSOR_CCOM_AVREG_1V8_SUPPLY 0x39 +/* enum: CCOM AVREG 1v8 supply (external ADC): mV */ +#define MC_CMD_SENSOR_CCOM_AVREG_1V8_SUPPLY_EXTADC 0x3a +/* enum: Not a sensor: reserved for the next page flag */ +#define MC_CMD_SENSOR_PAGE1_NEXT 0x3f +/* enum: controller internal temperature sensor voltage on master core + * (internal ADC): mV + */ +#define MC_CMD_SENSOR_CONTROLLER_MASTER_VPTAT 0x40 +/* enum: controller internal temperature on master core (internal ADC): degC */ +#define MC_CMD_SENSOR_CONTROLLER_MASTER_INTERNAL_TEMP 0x41 +/* enum: controller internal temperature sensor voltage on master core + * (external ADC): mV + */ +#define MC_CMD_SENSOR_CONTROLLER_MASTER_VPTAT_EXTADC 0x42 +/* enum: controller internal temperature on master core (external ADC): degC */ +#define MC_CMD_SENSOR_CONTROLLER_MASTER_INTERNAL_TEMP_EXTADC 0x43 +/* enum: controller internal temperature on slave core sensor voltage (internal + * ADC): mV + */ +#define MC_CMD_SENSOR_CONTROLLER_SLAVE_VPTAT 0x44 +/* enum: controller internal temperature on slave core (internal ADC): degC */ +#define MC_CMD_SENSOR_CONTROLLER_SLAVE_INTERNAL_TEMP 0x45 +/* enum: controller internal temperature on slave core sensor voltage (external + * ADC): mV + */ +#define MC_CMD_SENSOR_CONTROLLER_SLAVE_VPTAT_EXTADC 0x46 +/* enum: controller internal temperature on slave core (external ADC): degC */ +#define MC_CMD_SENSOR_CONTROLLER_SLAVE_INTERNAL_TEMP_EXTADC 0x47 +/* enum: Voltage supplied to the SODIMMs from their power supply: mV */ +#define MC_CMD_SENSOR_SODIMM_VOUT 0x49 +/* enum: Temperature of SODIMM 0 (if installed): degC */ +#define MC_CMD_SENSOR_SODIMM_0_TEMP 0x4a +/* enum: Temperature of SODIMM 1 (if installed): degC */ +#define MC_CMD_SENSOR_SODIMM_1_TEMP 0x4b +/* enum: Voltage supplied to the QSFP #0 from their power supply: mV */ +#define MC_CMD_SENSOR_PHY0_VCC 0x4c +/* enum: Voltage supplied to the QSFP #1 from their power supply: mV */ +#define MC_CMD_SENSOR_PHY1_VCC 0x4d /* MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF */ #define MC_CMD_SENSOR_ENTRY_OFST 4 #define MC_CMD_SENSOR_ENTRY_LEN 8 @@ -3701,6 +4039,8 @@ #define MC_CMD_SENSOR_STATE_BROKEN 0x3 /* enum: Sensor is working but does not currently have a reading. */ #define MC_CMD_SENSOR_STATE_NO_READING 0x4 +/* enum: Sensor initialisation failed. */ +#define MC_CMD_SENSOR_STATE_INIT_FAILED 0x5 #define MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE_LBN 16 #define MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE_WIDTH 8 #define MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_TYPE_OFST 3 @@ -3870,6 +4210,7 @@ /* MC_CMD_WORKAROUND_IN msgrequest */ #define MC_CMD_WORKAROUND_IN_LEN 8 +/* The enums here must correspond with those in MC_CMD_GET_WORKAROUND. */ #define MC_CMD_WORKAROUND_IN_TYPE_OFST 0 /* enum: Bug 17230 work around. */ #define MC_CMD_WORKAROUND_BUG17230 0x1 @@ -3877,11 +4218,38 @@ #define MC_CMD_WORKAROUND_BUG35388 0x2 /* enum: Bug35017 workaround (A64 tables must be identity map) */ #define MC_CMD_WORKAROUND_BUG35017 0x3 +/* enum: Bug 41750 present (MC_CMD_TRIGGER_INTERRUPT won't work) */ +#define MC_CMD_WORKAROUND_BUG41750 0x4 +/* enum: Bug 42008 present (Interrupts can overtake associated events). Caution + * - before adding code that queries this workaround, remember that there's + * released Monza firmware that doesn't understand MC_CMD_WORKAROUND_BUG42008, + * and will hence (incorrectly) report that the bug doesn't exist. + */ +#define MC_CMD_WORKAROUND_BUG42008 0x5 +/* enum: Bug 26807 features present in firmware (multicast filter chaining) + * This feature cannot be turned on/off while there are any filters already + * present. The behaviour in such case depends on the acting client's privilege + * level. If the client has the admin privilege, then all functions that have + * filters installed will be FLRed and the FLR_DONE flag will be set. Otherwise + * the command will fail with MC_CMD_ERR_FILTERS_PRESENT. + */ +#define MC_CMD_WORKAROUND_BUG26807 0x6 +/* 0 = disable the workaround indicated by TYPE; any non-zero value = enable + * the workaround + */ #define MC_CMD_WORKAROUND_IN_ENABLED_OFST 4 /* MC_CMD_WORKAROUND_OUT msgresponse */ #define MC_CMD_WORKAROUND_OUT_LEN 0 +/* MC_CMD_WORKAROUND_EXT_OUT msgresponse: This response format will be used + * when (TYPE == MC_CMD_WORKAROUND_BUG26807) + */ +#define MC_CMD_WORKAROUND_EXT_OUT_LEN 4 +#define MC_CMD_WORKAROUND_EXT_OUT_FLAGS_OFST 0 +#define MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN 0 +#define MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_WIDTH 1 + /***********************************/ /* MC_CMD_GET_PHY_MEDIA_INFO @@ -4093,7 +4461,7 @@ /***********************************/ /* MC_CMD_GET_MAC_ADDRESSES - * Returns the base MAC, count and stride for the requestiong function + * Returns the base MAC, count and stride for the requesting function */ #define MC_CMD_GET_MAC_ADDRESSES 0x55 @@ -4115,6 +4483,527 @@ /* Spacing of allocated MAC addresses */ #define MC_CMD_GET_MAC_ADDRESSES_OUT_MAC_STRIDE_OFST 12 + +/***********************************/ +/* MC_CMD_CLP + * Perform a CLP related operation + */ +#define MC_CMD_CLP 0x56 + +#define MC_CMD_0x56_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_CLP_IN msgrequest */ +#define MC_CMD_CLP_IN_LEN 4 +/* Sub operation */ +#define MC_CMD_CLP_IN_OP_OFST 0 +/* enum: Return to factory default settings */ +#define MC_CMD_CLP_OP_DEFAULT 0x1 +/* enum: Set MAC address */ +#define MC_CMD_CLP_OP_SET_MAC 0x2 +/* enum: Get MAC address */ +#define MC_CMD_CLP_OP_GET_MAC 0x3 +/* enum: Set UEFI/GPXE boot mode */ +#define MC_CMD_CLP_OP_SET_BOOT 0x4 +/* enum: Get UEFI/GPXE boot mode */ +#define MC_CMD_CLP_OP_GET_BOOT 0x5 + +/* MC_CMD_CLP_OUT msgresponse */ +#define MC_CMD_CLP_OUT_LEN 0 + +/* MC_CMD_CLP_IN_DEFAULT msgrequest */ +#define MC_CMD_CLP_IN_DEFAULT_LEN 4 +/* MC_CMD_CLP_IN_OP_OFST 0 */ + +/* MC_CMD_CLP_OUT_DEFAULT msgresponse */ +#define MC_CMD_CLP_OUT_DEFAULT_LEN 0 + +/* MC_CMD_CLP_IN_SET_MAC msgrequest */ +#define MC_CMD_CLP_IN_SET_MAC_LEN 12 +/* MC_CMD_CLP_IN_OP_OFST 0 */ +/* MAC address assigned to port */ +#define MC_CMD_CLP_IN_SET_MAC_ADDR_OFST 4 +#define MC_CMD_CLP_IN_SET_MAC_ADDR_LEN 6 +/* Padding */ +#define MC_CMD_CLP_IN_SET_MAC_RESERVED_OFST 10 +#define MC_CMD_CLP_IN_SET_MAC_RESERVED_LEN 2 + +/* MC_CMD_CLP_OUT_SET_MAC msgresponse */ +#define MC_CMD_CLP_OUT_SET_MAC_LEN 0 + +/* MC_CMD_CLP_IN_GET_MAC msgrequest */ +#define MC_CMD_CLP_IN_GET_MAC_LEN 4 +/* MC_CMD_CLP_IN_OP_OFST 0 */ + +/* MC_CMD_CLP_OUT_GET_MAC msgresponse */ +#define MC_CMD_CLP_OUT_GET_MAC_LEN 8 +/* MAC address assigned to port */ +#define MC_CMD_CLP_OUT_GET_MAC_ADDR_OFST 0 +#define MC_CMD_CLP_OUT_GET_MAC_ADDR_LEN 6 +/* Padding */ +#define MC_CMD_CLP_OUT_GET_MAC_RESERVED_OFST 6 +#define MC_CMD_CLP_OUT_GET_MAC_RESERVED_LEN 2 + +/* MC_CMD_CLP_IN_SET_BOOT msgrequest */ +#define MC_CMD_CLP_IN_SET_BOOT_LEN 5 +/* MC_CMD_CLP_IN_OP_OFST 0 */ +/* Boot flag */ +#define MC_CMD_CLP_IN_SET_BOOT_FLAG_OFST 4 +#define MC_CMD_CLP_IN_SET_BOOT_FLAG_LEN 1 + +/* MC_CMD_CLP_OUT_SET_BOOT msgresponse */ +#define MC_CMD_CLP_OUT_SET_BOOT_LEN 0 + +/* MC_CMD_CLP_IN_GET_BOOT msgrequest */ +#define MC_CMD_CLP_IN_GET_BOOT_LEN 4 +/* MC_CMD_CLP_IN_OP_OFST 0 */ + +/* MC_CMD_CLP_OUT_GET_BOOT msgresponse */ +#define MC_CMD_CLP_OUT_GET_BOOT_LEN 4 +/* Boot flag */ +#define MC_CMD_CLP_OUT_GET_BOOT_FLAG_OFST 0 +#define MC_CMD_CLP_OUT_GET_BOOT_FLAG_LEN 1 +/* Padding */ +#define MC_CMD_CLP_OUT_GET_BOOT_RESERVED_OFST 1 +#define MC_CMD_CLP_OUT_GET_BOOT_RESERVED_LEN 3 + + +/***********************************/ +/* MC_CMD_MUM + * Perform a MUM operation + */ +#define MC_CMD_MUM 0x57 + +#define MC_CMD_0x57_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_MUM_IN msgrequest */ +#define MC_CMD_MUM_IN_LEN 4 +#define MC_CMD_MUM_IN_OP_HDR_OFST 0 +#define MC_CMD_MUM_IN_OP_LBN 0 +#define MC_CMD_MUM_IN_OP_WIDTH 8 +/* enum: NULL MCDI command to MUM */ +#define MC_CMD_MUM_OP_NULL 0x1 +/* enum: Get MUM version */ +#define MC_CMD_MUM_OP_GET_VERSION 0x2 +/* enum: Issue raw I2C command to MUM */ +#define MC_CMD_MUM_OP_RAW_CMD 0x3 +/* enum: Read from registers on devices connected to MUM. */ +#define MC_CMD_MUM_OP_READ 0x4 +/* enum: Write to registers on devices connected to MUM. */ +#define MC_CMD_MUM_OP_WRITE 0x5 +/* enum: Control UART logging. */ +#define MC_CMD_MUM_OP_LOG 0x6 +/* enum: Operations on MUM GPIO lines */ +#define MC_CMD_MUM_OP_GPIO 0x7 +/* enum: Get sensor readings from MUM */ +#define MC_CMD_MUM_OP_READ_SENSORS 0x8 +/* enum: Initiate clock programming on the MUM */ +#define MC_CMD_MUM_OP_PROGRAM_CLOCKS 0x9 +/* enum: Initiate FPGA load from flash on the MUM */ +#define MC_CMD_MUM_OP_FPGA_LOAD 0xa +/* enum: Request sensor reading from MUM ADC resulting from earlier request via + * MUM ATB + */ +#define MC_CMD_MUM_OP_READ_ATB_SENSOR 0xb +/* enum: Send commands relating to the QSFP ports via the MUM for PHY + * operations + */ +#define MC_CMD_MUM_OP_QSFP 0xc + +/* MC_CMD_MUM_IN_NULL msgrequest */ +#define MC_CMD_MUM_IN_NULL_LEN 4 +/* MUM cmd header */ +#define MC_CMD_MUM_IN_CMD_OFST 0 + +/* MC_CMD_MUM_IN_GET_VERSION msgrequest */ +#define MC_CMD_MUM_IN_GET_VERSION_LEN 4 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ + +/* MC_CMD_MUM_IN_READ msgrequest */ +#define MC_CMD_MUM_IN_READ_LEN 16 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* ID of (device connected to MUM) to read from registers of */ +#define MC_CMD_MUM_IN_READ_DEVICE_OFST 4 +/* enum: Hittite HMC1035 clock generator on Sorrento board */ +#define MC_CMD_MUM_DEV_HITTITE 0x1 +/* enum: Hittite HMC1035 clock generator for NIC-side on Sorrento board */ +#define MC_CMD_MUM_DEV_HITTITE_NIC 0x2 +/* 32-bit address to read from */ +#define MC_CMD_MUM_IN_READ_ADDR_OFST 8 +/* Number of words to read. */ +#define MC_CMD_MUM_IN_READ_NUMWORDS_OFST 12 + +/* MC_CMD_MUM_IN_WRITE msgrequest */ +#define MC_CMD_MUM_IN_WRITE_LENMIN 16 +#define MC_CMD_MUM_IN_WRITE_LENMAX 252 +#define MC_CMD_MUM_IN_WRITE_LEN(num) (12+4*(num)) +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* ID of (device connected to MUM) to write to registers of */ +#define MC_CMD_MUM_IN_WRITE_DEVICE_OFST 4 +/* enum: Hittite HMC1035 clock generator on Sorrento board */ +/* MC_CMD_MUM_DEV_HITTITE 0x1 */ +/* 32-bit address to write to */ +#define MC_CMD_MUM_IN_WRITE_ADDR_OFST 8 +/* Words to write */ +#define MC_CMD_MUM_IN_WRITE_BUFFER_OFST 12 +#define MC_CMD_MUM_IN_WRITE_BUFFER_LEN 4 +#define MC_CMD_MUM_IN_WRITE_BUFFER_MINNUM 1 +#define MC_CMD_MUM_IN_WRITE_BUFFER_MAXNUM 60 + +/* MC_CMD_MUM_IN_RAW_CMD msgrequest */ +#define MC_CMD_MUM_IN_RAW_CMD_LENMIN 17 +#define MC_CMD_MUM_IN_RAW_CMD_LENMAX 252 +#define MC_CMD_MUM_IN_RAW_CMD_LEN(num) (16+1*(num)) +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* MUM I2C cmd code */ +#define MC_CMD_MUM_IN_RAW_CMD_CMD_CODE_OFST 4 +/* Number of bytes to write */ +#define MC_CMD_MUM_IN_RAW_CMD_NUM_WRITE_OFST 8 +/* Number of bytes to read */ +#define MC_CMD_MUM_IN_RAW_CMD_NUM_READ_OFST 12 +/* Bytes to write */ +#define MC_CMD_MUM_IN_RAW_CMD_WRITE_DATA_OFST 16 +#define MC_CMD_MUM_IN_RAW_CMD_WRITE_DATA_LEN 1 +#define MC_CMD_MUM_IN_RAW_CMD_WRITE_DATA_MINNUM 1 +#define MC_CMD_MUM_IN_RAW_CMD_WRITE_DATA_MAXNUM 236 + +/* MC_CMD_MUM_IN_LOG msgrequest */ +#define MC_CMD_MUM_IN_LOG_LEN 8 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_LOG_OP_OFST 4 +#define MC_CMD_MUM_IN_LOG_OP_UART 0x1 /* enum */ + +/* MC_CMD_MUM_IN_LOG_OP_UART msgrequest */ +#define MC_CMD_MUM_IN_LOG_OP_UART_LEN 12 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* MC_CMD_MUM_IN_LOG_OP_OFST 4 */ +/* Enable/disable debug output to UART */ +#define MC_CMD_MUM_IN_LOG_OP_UART_ENABLE_OFST 8 + +/* MC_CMD_MUM_IN_GPIO msgrequest */ +#define MC_CMD_MUM_IN_GPIO_LEN 8 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_HDR_OFST 4 +#define MC_CMD_MUM_IN_GPIO_OPCODE_LBN 0 +#define MC_CMD_MUM_IN_GPIO_OPCODE_WIDTH 8 +#define MC_CMD_MUM_IN_GPIO_IN_READ 0x0 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OUT_WRITE 0x1 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OUT_READ 0x2 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE 0x3 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_READ 0x4 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OP 0x5 /* enum */ + +/* MC_CMD_MUM_IN_GPIO_IN_READ msgrequest */ +#define MC_CMD_MUM_IN_GPIO_IN_READ_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_IN_READ_HDR_OFST 4 + +/* MC_CMD_MUM_IN_GPIO_OUT_WRITE msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OUT_WRITE_LEN 16 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OUT_WRITE_HDR_OFST 4 +/* The first 32-bit word to be written to the GPIO OUT register. */ +#define MC_CMD_MUM_IN_GPIO_OUT_WRITE_GPIOMASK1_OFST 8 +/* The second 32-bit word to be written to the GPIO OUT register. */ +#define MC_CMD_MUM_IN_GPIO_OUT_WRITE_GPIOMASK2_OFST 12 + +/* MC_CMD_MUM_IN_GPIO_OUT_READ msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OUT_READ_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OUT_READ_HDR_OFST 4 + +/* MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE_LEN 16 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE_HDR_OFST 4 +/* The first 32-bit word to be written to the GPIO OUT ENABLE register. */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE_GPIOMASK1_OFST 8 +/* The second 32-bit word to be written to the GPIO OUT ENABLE register. */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE_GPIOMASK2_OFST 12 + +/* MC_CMD_MUM_IN_GPIO_OUT_ENABLE_READ msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_READ_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_READ_HDR_OFST 4 + +/* MC_CMD_MUM_IN_GPIO_OP msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OP_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OP_HDR_OFST 4 +#define MC_CMD_MUM_IN_GPIO_OP_BITWISE_OP_LBN 8 +#define MC_CMD_MUM_IN_GPIO_OP_BITWISE_OP_WIDTH 8 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_READ 0x0 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE 0x1 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG 0x2 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE 0x3 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OP_GPIO_NUMBER_LBN 16 +#define MC_CMD_MUM_IN_GPIO_OP_GPIO_NUMBER_WIDTH 8 + +/* MC_CMD_MUM_IN_GPIO_OP_OUT_READ msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_READ_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_READ_HDR_OFST 4 + +/* MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE_HDR_OFST 4 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE_WRITEBIT_LBN 24 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE_WRITEBIT_WIDTH 8 + +/* MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG_HDR_OFST 4 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG_CFG_LBN 24 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG_CFG_WIDTH 8 + +/* MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE_HDR_OFST 4 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE_ENABLEBIT_LBN 24 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE_ENABLEBIT_WIDTH 8 + +/* MC_CMD_MUM_IN_READ_SENSORS msgrequest */ +#define MC_CMD_MUM_IN_READ_SENSORS_LEN 8 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_READ_SENSORS_PARAMS_OFST 4 +#define MC_CMD_MUM_IN_READ_SENSORS_SENSOR_ID_LBN 0 +#define MC_CMD_MUM_IN_READ_SENSORS_SENSOR_ID_WIDTH 8 +#define MC_CMD_MUM_IN_READ_SENSORS_NUM_SENSORS_LBN 8 +#define MC_CMD_MUM_IN_READ_SENSORS_NUM_SENSORS_WIDTH 8 + +/* MC_CMD_MUM_IN_PROGRAM_CLOCKS msgrequest */ +#define MC_CMD_MUM_IN_PROGRAM_CLOCKS_LEN 12 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* Bit-mask of clocks to be programmed */ +#define MC_CMD_MUM_IN_PROGRAM_CLOCKS_MASK_OFST 4 +#define MC_CMD_MUM_CLOCK_ID_FPGA 0x0 /* enum */ +#define MC_CMD_MUM_CLOCK_ID_DDR 0x1 /* enum */ +#define MC_CMD_MUM_CLOCK_ID_NIC 0x2 /* enum */ +/* Control flags for clock programming */ +#define MC_CMD_MUM_IN_PROGRAM_CLOCKS_FLAGS_OFST 8 +#define MC_CMD_MUM_IN_PROGRAM_CLOCKS_OVERCLOCK_110_LBN 0 +#define MC_CMD_MUM_IN_PROGRAM_CLOCKS_OVERCLOCK_110_WIDTH 1 + +/* MC_CMD_MUM_IN_FPGA_LOAD msgrequest */ +#define MC_CMD_MUM_IN_FPGA_LOAD_LEN 8 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* Enable/Disable FPGA config from flash */ +#define MC_CMD_MUM_IN_FPGA_LOAD_ENABLE_OFST 4 + +/* MC_CMD_MUM_IN_READ_ATB_SENSOR msgrequest */ +#define MC_CMD_MUM_IN_READ_ATB_SENSOR_LEN 4 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ + +/* MC_CMD_MUM_IN_QSFP msgrequest */ +#define MC_CMD_MUM_IN_QSFP_LEN 12 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_OPCODE_LBN 0 +#define MC_CMD_MUM_IN_QSFP_OPCODE_WIDTH 4 +#define MC_CMD_MUM_IN_QSFP_INIT 0x0 /* enum */ +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE 0x1 /* enum */ +#define MC_CMD_MUM_IN_QSFP_GET_SUPPORTED_CAP 0x2 /* enum */ +#define MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO 0x3 /* enum */ +#define MC_CMD_MUM_IN_QSFP_FILL_STATS 0x4 /* enum */ +#define MC_CMD_MUM_IN_QSFP_POLL_BIST 0x5 /* enum */ +#define MC_CMD_MUM_IN_QSFP_IDX_OFST 8 + +/* MC_CMD_MUM_IN_QSFP_INIT msgrequest */ +#define MC_CMD_MUM_IN_QSFP_INIT_LEN 16 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_INIT_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_INIT_IDX_OFST 8 +#define MC_CMD_MUM_IN_QSFP_INIT_CAGE_OFST 12 + +/* MC_CMD_MUM_IN_QSFP_RECONFIGURE msgrequest */ +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_LEN 24 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_IDX_OFST 8 +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_TX_DISABLE_OFST 12 +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_PORT_LANES_OFST 16 +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_PORT_LINK_SPEED_OFST 20 + +/* MC_CMD_MUM_IN_QSFP_GET_SUPPORTED_CAP msgrequest */ +#define MC_CMD_MUM_IN_QSFP_GET_SUPPORTED_CAP_LEN 12 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_GET_SUPPORTED_CAP_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_GET_SUPPORTED_CAP_IDX_OFST 8 + +/* MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO msgrequest */ +#define MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO_LEN 16 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO_IDX_OFST 8 +#define MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO_PAGE_OFST 12 + +/* MC_CMD_MUM_IN_QSFP_FILL_STATS msgrequest */ +#define MC_CMD_MUM_IN_QSFP_FILL_STATS_LEN 12 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_FILL_STATS_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_FILL_STATS_IDX_OFST 8 + +/* MC_CMD_MUM_IN_QSFP_POLL_BIST msgrequest */ +#define MC_CMD_MUM_IN_QSFP_POLL_BIST_LEN 12 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_POLL_BIST_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_POLL_BIST_IDX_OFST 8 + +/* MC_CMD_MUM_OUT msgresponse */ +#define MC_CMD_MUM_OUT_LEN 0 + +/* MC_CMD_MUM_OUT_NULL msgresponse */ +#define MC_CMD_MUM_OUT_NULL_LEN 0 + +/* MC_CMD_MUM_OUT_GET_VERSION msgresponse */ +#define MC_CMD_MUM_OUT_GET_VERSION_LEN 12 +#define MC_CMD_MUM_OUT_GET_VERSION_FIRMWARE_OFST 0 +#define MC_CMD_MUM_OUT_GET_VERSION_VERSION_OFST 4 +#define MC_CMD_MUM_OUT_GET_VERSION_VERSION_LEN 8 +#define MC_CMD_MUM_OUT_GET_VERSION_VERSION_LO_OFST 4 +#define MC_CMD_MUM_OUT_GET_VERSION_VERSION_HI_OFST 8 + +/* MC_CMD_MUM_OUT_RAW_CMD msgresponse */ +#define MC_CMD_MUM_OUT_RAW_CMD_LENMIN 1 +#define MC_CMD_MUM_OUT_RAW_CMD_LENMAX 252 +#define MC_CMD_MUM_OUT_RAW_CMD_LEN(num) (0+1*(num)) +/* returned data */ +#define MC_CMD_MUM_OUT_RAW_CMD_DATA_OFST 0 +#define MC_CMD_MUM_OUT_RAW_CMD_DATA_LEN 1 +#define MC_CMD_MUM_OUT_RAW_CMD_DATA_MINNUM 1 +#define MC_CMD_MUM_OUT_RAW_CMD_DATA_MAXNUM 252 + +/* MC_CMD_MUM_OUT_READ msgresponse */ +#define MC_CMD_MUM_OUT_READ_LENMIN 4 +#define MC_CMD_MUM_OUT_READ_LENMAX 252 +#define MC_CMD_MUM_OUT_READ_LEN(num) (0+4*(num)) +#define MC_CMD_MUM_OUT_READ_BUFFER_OFST 0 +#define MC_CMD_MUM_OUT_READ_BUFFER_LEN 4 +#define MC_CMD_MUM_OUT_READ_BUFFER_MINNUM 1 +#define MC_CMD_MUM_OUT_READ_BUFFER_MAXNUM 63 + +/* MC_CMD_MUM_OUT_WRITE msgresponse */ +#define MC_CMD_MUM_OUT_WRITE_LEN 0 + +/* MC_CMD_MUM_OUT_LOG msgresponse */ +#define MC_CMD_MUM_OUT_LOG_LEN 0 + +/* MC_CMD_MUM_OUT_LOG_OP_UART msgresponse */ +#define MC_CMD_MUM_OUT_LOG_OP_UART_LEN 0 + +/* MC_CMD_MUM_OUT_GPIO_IN_READ msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_IN_READ_LEN 8 +/* The first 32-bit word read from the GPIO IN register. */ +#define MC_CMD_MUM_OUT_GPIO_IN_READ_GPIOMASK1_OFST 0 +/* The second 32-bit word read from the GPIO IN register. */ +#define MC_CMD_MUM_OUT_GPIO_IN_READ_GPIOMASK2_OFST 4 + +/* MC_CMD_MUM_OUT_GPIO_OUT_WRITE msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OUT_WRITE_LEN 0 + +/* MC_CMD_MUM_OUT_GPIO_OUT_READ msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OUT_READ_LEN 8 +/* The first 32-bit word read from the GPIO OUT register. */ +#define MC_CMD_MUM_OUT_GPIO_OUT_READ_GPIOMASK1_OFST 0 +/* The second 32-bit word read from the GPIO OUT register. */ +#define MC_CMD_MUM_OUT_GPIO_OUT_READ_GPIOMASK2_OFST 4 + +/* MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_WRITE msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_WRITE_LEN 0 + +/* MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_READ msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_READ_LEN 8 +#define MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_READ_GPIOMASK1_OFST 0 +#define MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_READ_GPIOMASK2_OFST 4 + +/* MC_CMD_MUM_OUT_GPIO_OP_OUT_READ msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OP_OUT_READ_LEN 4 +#define MC_CMD_MUM_OUT_GPIO_OP_OUT_READ_BIT_READ_OFST 0 + +/* MC_CMD_MUM_OUT_GPIO_OP_OUT_WRITE msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OP_OUT_WRITE_LEN 0 + +/* MC_CMD_MUM_OUT_GPIO_OP_OUT_CONFIG msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OP_OUT_CONFIG_LEN 0 + +/* MC_CMD_MUM_OUT_GPIO_OP_OUT_ENABLE msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OP_OUT_ENABLE_LEN 0 + +/* MC_CMD_MUM_OUT_READ_SENSORS msgresponse */ +#define MC_CMD_MUM_OUT_READ_SENSORS_LENMIN 4 +#define MC_CMD_MUM_OUT_READ_SENSORS_LENMAX 252 +#define MC_CMD_MUM_OUT_READ_SENSORS_LEN(num) (0+4*(num)) +#define MC_CMD_MUM_OUT_READ_SENSORS_DATA_OFST 0 +#define MC_CMD_MUM_OUT_READ_SENSORS_DATA_LEN 4 +#define MC_CMD_MUM_OUT_READ_SENSORS_DATA_MINNUM 1 +#define MC_CMD_MUM_OUT_READ_SENSORS_DATA_MAXNUM 63 +#define MC_CMD_MUM_OUT_READ_SENSORS_READING_LBN 0 +#define MC_CMD_MUM_OUT_READ_SENSORS_READING_WIDTH 16 +#define MC_CMD_MUM_OUT_READ_SENSORS_STATE_LBN 16 +#define MC_CMD_MUM_OUT_READ_SENSORS_STATE_WIDTH 8 +#define MC_CMD_MUM_OUT_READ_SENSORS_TYPE_LBN 24 +#define MC_CMD_MUM_OUT_READ_SENSORS_TYPE_WIDTH 8 + +/* MC_CMD_MUM_OUT_PROGRAM_CLOCKS msgresponse */ +#define MC_CMD_MUM_OUT_PROGRAM_CLOCKS_LEN 4 +#define MC_CMD_MUM_OUT_PROGRAM_CLOCKS_OK_MASK_OFST 0 + +/* MC_CMD_MUM_OUT_FPGA_LOAD msgresponse */ +#define MC_CMD_MUM_OUT_FPGA_LOAD_LEN 0 + +/* MC_CMD_MUM_OUT_READ_ATB_SENSOR msgresponse */ +#define MC_CMD_MUM_OUT_READ_ATB_SENSOR_LEN 4 +#define MC_CMD_MUM_OUT_READ_ATB_SENSOR_RESULT_OFST 0 + +/* MC_CMD_MUM_OUT_QSFP_INIT msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_INIT_LEN 0 + +/* MC_CMD_MUM_OUT_QSFP_RECONFIGURE msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_LEN 8 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_LP_CAP_OFST 0 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_FLAGS_OFST 4 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_READY_LBN 0 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_READY_WIDTH 1 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_LINK_UP_LBN 1 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_LINK_UP_WIDTH 1 + +/* MC_CMD_MUM_OUT_QSFP_GET_SUPPORTED_CAP msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_GET_SUPPORTED_CAP_LEN 4 +#define MC_CMD_MUM_OUT_QSFP_GET_SUPPORTED_CAP_PORT_PHY_LP_CAP_OFST 0 + +/* MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_LENMIN 5 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_LENMAX 252 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_LEN(num) (4+1*(num)) +/* in bytes */ +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_DATALEN_OFST 0 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_DATA_OFST 4 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_DATA_LEN 1 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_DATA_MINNUM 1 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_DATA_MAXNUM 248 + +/* MC_CMD_MUM_OUT_QSFP_FILL_STATS msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_FILL_STATS_LEN 8 +#define MC_CMD_MUM_OUT_QSFP_FILL_STATS_PORT_PHY_STATS_PMA_PMD_LINK_UP_OFST 0 +#define MC_CMD_MUM_OUT_QSFP_FILL_STATS_PORT_PHY_STATS_PCS_LINK_UP_OFST 4 + +/* MC_CMD_MUM_OUT_QSFP_POLL_BIST msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_POLL_BIST_LEN 4 +#define MC_CMD_MUM_OUT_QSFP_POLL_BIST_TEST_OFST 0 + /* MC_CMD_RESOURCE_SPECIFIER enum */ /* enum: Any */ #define MC_CMD_RESOURCE_INSTANCE_ANY 0xffffffff @@ -4203,6 +5092,30 @@ #define NVRAM_PARTITION_TYPE_PHY_MIN 0xa00 /* enum: End of range used for PHY partitions (low 8 bits are the PHY ID) */ #define NVRAM_PARTITION_TYPE_PHY_MAX 0xaff +/* enum: Primary FPGA partition */ +#define NVRAM_PARTITION_TYPE_FPGA 0xb00 +/* enum: Secondary FPGA partition */ +#define NVRAM_PARTITION_TYPE_FPGA_BACKUP 0xb01 +/* enum: FC firmware partition */ +#define NVRAM_PARTITION_TYPE_FC_FIRMWARE 0xb02 +/* enum: FC License partition */ +#define NVRAM_PARTITION_TYPE_FC_LICENSE 0xb03 +/* enum: Non-volatile log output partition for FC */ +#define NVRAM_PARTITION_TYPE_FC_LOG 0xb04 +/* enum: MUM firmware partition */ +#define NVRAM_PARTITION_TYPE_MUM_FIRMWARE 0xc00 +/* enum: MUM Non-volatile log output partition. */ +#define NVRAM_PARTITION_TYPE_MUM_LOG 0xc01 +/* enum: MUM Application table partition. */ +#define NVRAM_PARTITION_TYPE_MUM_APPTABLE 0xc02 +/* enum: MUM boot rom partition. */ +#define NVRAM_PARTITION_TYPE_MUM_BOOT_ROM 0xc03 +/* enum: MUM production signatures & calibration rom partition. */ +#define NVRAM_PARTITION_TYPE_MUM_PROD_ROM 0xc04 +/* enum: MUM user signatures & calibration rom partition. */ +#define NVRAM_PARTITION_TYPE_MUM_USER_ROM 0xc05 +/* enum: MUM fuses and lockbits partition. */ +#define NVRAM_PARTITION_TYPE_MUM_FUSELOCK 0xc06 /* enum: Start of reserved value range (firmware may use for any purpose) */ #define NVRAM_PARTITION_TYPE_RESERVED_VALUES_MIN 0xff00 /* enum: End of reserved value range (firmware may use for any purpose) */ @@ -4218,66 +5131,69 @@ #define LICENSED_APP_ID_LEN 4 #define LICENSED_APP_ID_ID_OFST 0 /* enum: OpenOnload */ -#define LICENSED_APP_ID_ONLOAD 0x1 +#define LICENSED_APP_ID_ONLOAD 0x1 /* enum: PTP timestamping */ -#define LICENSED_APP_ID_PTP 0x2 +#define LICENSED_APP_ID_PTP 0x2 /* enum: SolarCapture Pro */ -#define LICENSED_APP_ID_SOLARCAPTURE_PRO 0x4 +#define LICENSED_APP_ID_SOLARCAPTURE_PRO 0x4 +/* enum: SolarSecure filter engine */ +#define LICENSED_APP_ID_SOLARSECURE 0x8 +/* enum: Performance monitor */ +#define LICENSED_APP_ID_PERF_MONITOR 0x10 +/* enum: SolarCapture Live */ +#define LICENSED_APP_ID_SOLARCAPTURE_LIVE 0x20 +/* enum: Capture SolarSystem */ +#define LICENSED_APP_ID_CAPTURE_SOLARSYSTEM 0x40 +/* enum: Network Access Control */ +#define LICENSED_APP_ID_NETWORK_ACCESS_CONTROL 0x80 #define LICENSED_APP_ID_ID_LBN 0 #define LICENSED_APP_ID_ID_WIDTH 32 - -/***********************************/ -/* MC_CMD_GET_WORKAROUNDS - * Read the list of all implemented and all currently enabled workarounds. The - * enums here must correspond with those in MC_CMD_WORKAROUND. - */ -#define MC_CMD_GET_WORKAROUNDS 0x59 - -/* MC_CMD_GET_WORKAROUNDS_OUT msgresponse */ -#define MC_CMD_GET_WORKAROUNDS_OUT_LEN 8 -/* Each workaround is represented by a single bit according to the enums below. - */ -#define MC_CMD_GET_WORKAROUNDS_OUT_IMPLEMENTED_OFST 0 -#define MC_CMD_GET_WORKAROUNDS_OUT_ENABLED_OFST 4 -/* enum: Bug 17230 work around. */ -#define MC_CMD_GET_WORKAROUNDS_OUT_BUG17230 0x2 -/* enum: Bug 35388 work around (unsafe EVQ writes). */ -#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35388 0x4 -/* enum: Bug35017 workaround (A64 tables must be identity map) */ -#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35017 0x8 - - -/***********************************/ -/* MC_CMD_LINK_STATE_MODE - * Read/set link state mode of a VF - */ -#define MC_CMD_LINK_STATE_MODE 0x5c - -#define MC_CMD_0x5c_PRIVILEGE_CTG SRIOV_CTG_GENERAL - -/* MC_CMD_LINK_STATE_MODE_IN msgrequest */ -#define MC_CMD_LINK_STATE_MODE_IN_LEN 8 -/* The target function to have its link state mode read or set, must be a VF - * e.g. VF 1,3 = 0x00030001 - */ -#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_OFST 0 -#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_PF_LBN 0 -#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_PF_WIDTH 16 -#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_VF_LBN 16 -#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_VF_WIDTH 16 -/* New link state mode to be set */ -#define MC_CMD_LINK_STATE_MODE_IN_NEW_MODE_OFST 4 -#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_AUTO 0x0 /* enum */ -#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_UP 0x1 /* enum */ -#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_DOWN 0x2 /* enum */ -/* enum: Use this value to just read the existing setting without modifying it. - */ -#define MC_CMD_LINK_STATE_MODE_IN_DO_NOT_CHANGE 0xffffffff - -/* MC_CMD_LINK_STATE_MODE_OUT msgresponse */ -#define MC_CMD_LINK_STATE_MODE_OUT_LEN 4 -#define MC_CMD_LINK_STATE_MODE_OUT_OLD_MODE_OFST 0 +/* TX_TIMESTAMP_EVENT structuredef */ +#define TX_TIMESTAMP_EVENT_LEN 6 +/* lower 16 bits of timestamp data */ +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_LO_OFST 0 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_LO_LEN 2 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_LO_LBN 0 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_LO_WIDTH 16 +/* Type of TX event, ordinary TX completion, low or high part of TX timestamp + */ +#define TX_TIMESTAMP_EVENT_TX_EV_TYPE_OFST 3 +#define TX_TIMESTAMP_EVENT_TX_EV_TYPE_LEN 1 +/* enum: This is a TX completion event, not a timestamp */ +#define TX_TIMESTAMP_EVENT_TX_EV_COMPLETION 0x0 +/* enum: This is the low part of a TX timestamp event */ +#define TX_TIMESTAMP_EVENT_TX_EV_TSTAMP_LO 0x51 +/* enum: This is the high part of a TX timestamp event */ +#define TX_TIMESTAMP_EVENT_TX_EV_TSTAMP_HI 0x52 +#define TX_TIMESTAMP_EVENT_TX_EV_TYPE_LBN 24 +#define TX_TIMESTAMP_EVENT_TX_EV_TYPE_WIDTH 8 +/* upper 16 bits of timestamp data */ +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_HI_OFST 4 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_HI_LEN 2 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_HI_LBN 32 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_HI_WIDTH 16 + +/* RSS_MODE structuredef */ +#define RSS_MODE_LEN 1 +/* The RSS mode for a particular packet type is a value from 0 - 15 which can + * be considered as 4 bits selecting which fields are included in the hash. (A + * value 0 effectively disables RSS spreading for the packet type.) The YAML + * generation tools require this structure to be a whole number of bytes wide, + * but only 4 bits are relevant. + */ +#define RSS_MODE_HASH_SELECTOR_OFST 0 +#define RSS_MODE_HASH_SELECTOR_LEN 1 +#define RSS_MODE_HASH_SRC_ADDR_LBN 0 +#define RSS_MODE_HASH_SRC_ADDR_WIDTH 1 +#define RSS_MODE_HASH_DST_ADDR_LBN 1 +#define RSS_MODE_HASH_DST_ADDR_WIDTH 1 +#define RSS_MODE_HASH_SRC_PORT_LBN 2 +#define RSS_MODE_HASH_SRC_PORT_WIDTH 1 +#define RSS_MODE_HASH_DST_PORT_LBN 3 +#define RSS_MODE_HASH_DST_PORT_WIDTH 1 +#define RSS_MODE_HASH_SELECTOR_LBN 0 +#define RSS_MODE_HASH_SELECTOR_WIDTH 8 /***********************************/ @@ -4413,7 +5329,9 @@ #define MC_CMD_0x81_PRIVILEGE_CTG SRIOV_CTG_GENERAL -/* MC_CMD_INIT_RXQ_IN msgrequest */ +/* MC_CMD_INIT_RXQ_IN msgrequest: Legacy RXQ_INIT request. Use extended version + * in new code. + */ #define MC_CMD_INIT_RXQ_IN_LENMIN 36 #define MC_CMD_INIT_RXQ_IN_LENMAX 252 #define MC_CMD_INIT_RXQ_IN_LEN(num) (28+8*(num)) @@ -4456,9 +5374,73 @@ #define MC_CMD_INIT_RXQ_IN_DMA_ADDR_MINNUM 1 #define MC_CMD_INIT_RXQ_IN_DMA_ADDR_MAXNUM 28 +/* MC_CMD_INIT_RXQ_EXT_IN msgrequest: Extended RXQ_INIT with additional mode + * flags + */ +#define MC_CMD_INIT_RXQ_EXT_IN_LEN 544 +/* Size, in entries */ +#define MC_CMD_INIT_RXQ_EXT_IN_SIZE_OFST 0 +/* The EVQ to send events to. This is an index originally specified to INIT_EVQ + */ +#define MC_CMD_INIT_RXQ_EXT_IN_TARGET_EVQ_OFST 4 +/* The value to put in the event data. Check hardware spec. for valid range. */ +#define MC_CMD_INIT_RXQ_EXT_IN_LABEL_OFST 8 +/* Desired instance. Must be set to a specific instance, which is a function + * local queue index. + */ +#define MC_CMD_INIT_RXQ_EXT_IN_INSTANCE_OFST 12 +/* There will be more flags here. */ +#define MC_CMD_INIT_RXQ_EXT_IN_FLAGS_OFST 16 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_BUFF_MODE_LBN 0 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_BUFF_MODE_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_HDR_SPLIT_LBN 1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_HDR_SPLIT_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_TIMESTAMP_LBN 2 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_TIMESTAMP_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_CRC_MODE_LBN 3 +#define MC_CMD_INIT_RXQ_EXT_IN_CRC_MODE_WIDTH 4 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_CHAIN_LBN 7 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_CHAIN_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_PREFIX_LBN 8 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_PREFIX_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_DISABLE_SCATTER_LBN 9 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_DISABLE_SCATTER_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_MODE_LBN 10 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_MODE_WIDTH 4 +/* enum: One packet per descriptor (for normal networking) */ +#define MC_CMD_INIT_RXQ_EXT_IN_SINGLE_PACKET 0x0 +/* enum: Pack multiple packets into large descriptors (for SolarCapture) */ +#define MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM 0x1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_SNAPSHOT_MODE_LBN 14 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_SNAPSHOT_MODE_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM_BUFF_SIZE_LBN 15 +#define MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM_BUFF_SIZE_WIDTH 3 +#define MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_1M 0x0 /* enum */ +#define MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_512K 0x1 /* enum */ +#define MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_256K 0x2 /* enum */ +#define MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_128K 0x3 /* enum */ +#define MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_64K 0x4 /* enum */ +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_WANT_OUTER_CLASSES_LBN 18 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_WANT_OUTER_CLASSES_WIDTH 1 +/* Owner ID to use if in buffer mode (zero if physical) */ +#define MC_CMD_INIT_RXQ_EXT_IN_OWNER_ID_OFST 20 +/* The port ID associated with the v-adaptor which should contain this DMAQ. */ +#define MC_CMD_INIT_RXQ_EXT_IN_PORT_ID_OFST 24 +/* 64-bit address of 4k of 4k-aligned host memory buffer */ +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_ADDR_OFST 28 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_ADDR_LEN 8 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_ADDR_LO_OFST 28 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_ADDR_HI_OFST 32 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_ADDR_NUM 64 +/* Maximum length of packet to receive, if SNAPSHOT_MODE flag is set */ +#define MC_CMD_INIT_RXQ_EXT_IN_SNAPSHOT_LENGTH_OFST 540 + /* MC_CMD_INIT_RXQ_OUT msgresponse */ #define MC_CMD_INIT_RXQ_OUT_LEN 0 +/* MC_CMD_INIT_RXQ_EXT_OUT msgresponse */ +#define MC_CMD_INIT_RXQ_EXT_OUT_LEN 0 + /***********************************/ /* MC_CMD_INIT_TXQ @@ -4467,7 +5449,9 @@ #define MC_CMD_0x82_PRIVILEGE_CTG SRIOV_CTG_GENERAL -/* MC_CMD_INIT_TXQ_IN msgrequest */ +/* MC_CMD_INIT_TXQ_IN msgrequest: Legacy INIT_TXQ request. Use extended version + * in new code. + */ #define MC_CMD_INIT_TXQ_IN_LENMIN 36 #define MC_CMD_INIT_TXQ_IN_LENMAX 252 #define MC_CMD_INIT_TXQ_IN_LEN(num) (28+8*(num)) @@ -4499,6 +5483,10 @@ #define MC_CMD_INIT_TXQ_IN_FLAG_TIMESTAMP_WIDTH 1 #define MC_CMD_INIT_TXQ_IN_FLAG_PACER_BYPASS_LBN 9 #define MC_CMD_INIT_TXQ_IN_FLAG_PACER_BYPASS_WIDTH 1 +#define MC_CMD_INIT_TXQ_IN_FLAG_INNER_IP_CSUM_EN_LBN 10 +#define MC_CMD_INIT_TXQ_IN_FLAG_INNER_IP_CSUM_EN_WIDTH 1 +#define MC_CMD_INIT_TXQ_IN_FLAG_INNER_TCP_CSUM_EN_LBN 11 +#define MC_CMD_INIT_TXQ_IN_FLAG_INNER_TCP_CSUM_EN_WIDTH 1 /* Owner ID to use if in buffer mode (zero if physical) */ #define MC_CMD_INIT_TXQ_IN_OWNER_ID_OFST 20 /* The port ID associated with the v-adaptor which should contain this DMAQ. */ @@ -4511,6 +5499,60 @@ #define MC_CMD_INIT_TXQ_IN_DMA_ADDR_MINNUM 1 #define MC_CMD_INIT_TXQ_IN_DMA_ADDR_MAXNUM 28 +/* MC_CMD_INIT_TXQ_EXT_IN msgrequest: Extended INIT_TXQ with additional mode + * flags + */ +#define MC_CMD_INIT_TXQ_EXT_IN_LEN 544 +/* Size, in entries */ +#define MC_CMD_INIT_TXQ_EXT_IN_SIZE_OFST 0 +/* The EVQ to send events to. This is an index originally specified to + * INIT_EVQ. + */ +#define MC_CMD_INIT_TXQ_EXT_IN_TARGET_EVQ_OFST 4 +/* The value to put in the event data. Check hardware spec. for valid range. */ +#define MC_CMD_INIT_TXQ_EXT_IN_LABEL_OFST 8 +/* Desired instance. Must be set to a specific instance, which is a function + * local queue index. + */ +#define MC_CMD_INIT_TXQ_EXT_IN_INSTANCE_OFST 12 +/* There will be more flags here. */ +#define MC_CMD_INIT_TXQ_EXT_IN_FLAGS_OFST 16 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_BUFF_MODE_LBN 0 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_BUFF_MODE_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_IP_CSUM_DIS_LBN 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_IP_CSUM_DIS_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TCP_CSUM_DIS_LBN 2 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TCP_CSUM_DIS_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TCP_UDP_ONLY_LBN 3 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TCP_UDP_ONLY_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_CRC_MODE_LBN 4 +#define MC_CMD_INIT_TXQ_EXT_IN_CRC_MODE_WIDTH 4 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TIMESTAMP_LBN 8 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TIMESTAMP_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_PACER_BYPASS_LBN 9 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_PACER_BYPASS_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_INNER_IP_CSUM_EN_LBN 10 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_INNER_IP_CSUM_EN_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_INNER_TCP_CSUM_EN_LBN 11 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_INNER_TCP_CSUM_EN_WIDTH 1 +/* Owner ID to use if in buffer mode (zero if physical) */ +#define MC_CMD_INIT_TXQ_EXT_IN_OWNER_ID_OFST 20 +/* The port ID associated with the v-adaptor which should contain this DMAQ. */ +#define MC_CMD_INIT_TXQ_EXT_IN_PORT_ID_OFST 24 +/* 64-bit address of 4k of 4k-aligned host memory buffer */ +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_OFST 28 +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_LEN 8 +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_LO_OFST 28 +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_HI_OFST 32 +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_MINNUM 1 +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_MAXNUM 64 +/* Flags related to Qbb flow control mode. */ +#define MC_CMD_INIT_TXQ_EXT_IN_QBB_FLAGS_OFST 540 +#define MC_CMD_INIT_TXQ_EXT_IN_QBB_ENABLE_LBN 0 +#define MC_CMD_INIT_TXQ_EXT_IN_QBB_ENABLE_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_QBB_PRIORITY_LBN 1 +#define MC_CMD_INIT_TXQ_EXT_IN_QBB_PRIORITY_WIDTH 3 + /* MC_CMD_INIT_TXQ_OUT msgresponse */ #define MC_CMD_INIT_TXQ_OUT_LEN 0 @@ -4617,6 +5659,132 @@ /* MC_CMD_PROXY_CMD_OUT msgresponse */ #define MC_CMD_PROXY_CMD_OUT_LEN 0 +/* MC_PROXY_STATUS_BUFFER structuredef: Host memory status buffer used to + * manage proxied requests + */ +#define MC_PROXY_STATUS_BUFFER_LEN 16 +/* Handle allocated by the firmware for this proxy transaction */ +#define MC_PROXY_STATUS_BUFFER_HANDLE_OFST 0 +/* enum: An invalid handle. */ +#define MC_PROXY_STATUS_BUFFER_HANDLE_INVALID 0x0 +#define MC_PROXY_STATUS_BUFFER_HANDLE_LBN 0 +#define MC_PROXY_STATUS_BUFFER_HANDLE_WIDTH 32 +/* The requesting physical function number */ +#define MC_PROXY_STATUS_BUFFER_PF_OFST 4 +#define MC_PROXY_STATUS_BUFFER_PF_LEN 2 +#define MC_PROXY_STATUS_BUFFER_PF_LBN 32 +#define MC_PROXY_STATUS_BUFFER_PF_WIDTH 16 +/* The requesting virtual function number. Set to VF_NULL if the target is a + * PF. + */ +#define MC_PROXY_STATUS_BUFFER_VF_OFST 6 +#define MC_PROXY_STATUS_BUFFER_VF_LEN 2 +#define MC_PROXY_STATUS_BUFFER_VF_LBN 48 +#define MC_PROXY_STATUS_BUFFER_VF_WIDTH 16 +/* The target function RID. */ +#define MC_PROXY_STATUS_BUFFER_RID_OFST 8 +#define MC_PROXY_STATUS_BUFFER_RID_LEN 2 +#define MC_PROXY_STATUS_BUFFER_RID_LBN 64 +#define MC_PROXY_STATUS_BUFFER_RID_WIDTH 16 +/* The status of the proxy as described in MC_CMD_PROXY_COMPLETE. */ +#define MC_PROXY_STATUS_BUFFER_STATUS_OFST 10 +#define MC_PROXY_STATUS_BUFFER_STATUS_LEN 2 +#define MC_PROXY_STATUS_BUFFER_STATUS_LBN 80 +#define MC_PROXY_STATUS_BUFFER_STATUS_WIDTH 16 +/* If a request is authorized rather than carried out by the host, this is the + * elevated privilege mask granted to the requesting function. + */ +#define MC_PROXY_STATUS_BUFFER_GRANTED_PRIVILEGES_OFST 12 +#define MC_PROXY_STATUS_BUFFER_GRANTED_PRIVILEGES_LBN 96 +#define MC_PROXY_STATUS_BUFFER_GRANTED_PRIVILEGES_WIDTH 32 + + +/***********************************/ +/* MC_CMD_PROXY_CONFIGURE + * Enable/disable authorization of MCDI requests from unprivileged functions by + * a designated admin function + */ +#define MC_CMD_PROXY_CONFIGURE 0x58 + +#define MC_CMD_0x58_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_PROXY_CONFIGURE_IN msgrequest */ +#define MC_CMD_PROXY_CONFIGURE_IN_LEN 108 +#define MC_CMD_PROXY_CONFIGURE_IN_FLAGS_OFST 0 +#define MC_CMD_PROXY_CONFIGURE_IN_ENABLE_LBN 0 +#define MC_CMD_PROXY_CONFIGURE_IN_ENABLE_WIDTH 1 +/* Host provides a contiguous memory buffer that contains at least NUM_BLOCKS + * of blocks, each of the size REQUEST_BLOCK_SIZE. + */ +#define MC_CMD_PROXY_CONFIGURE_IN_STATUS_BUFF_ADDR_OFST 4 +#define MC_CMD_PROXY_CONFIGURE_IN_STATUS_BUFF_ADDR_LEN 8 +#define MC_CMD_PROXY_CONFIGURE_IN_STATUS_BUFF_ADDR_LO_OFST 4 +#define MC_CMD_PROXY_CONFIGURE_IN_STATUS_BUFF_ADDR_HI_OFST 8 +/* Must be a power of 2 */ +#define MC_CMD_PROXY_CONFIGURE_IN_STATUS_BLOCK_SIZE_OFST 12 +/* Host provides a contiguous memory buffer that contains at least NUM_BLOCKS + * of blocks, each of the size REPLY_BLOCK_SIZE. + */ +#define MC_CMD_PROXY_CONFIGURE_IN_REQUEST_BUFF_ADDR_OFST 16 +#define MC_CMD_PROXY_CONFIGURE_IN_REQUEST_BUFF_ADDR_LEN 8 +#define MC_CMD_PROXY_CONFIGURE_IN_REQUEST_BUFF_ADDR_LO_OFST 16 +#define MC_CMD_PROXY_CONFIGURE_IN_REQUEST_BUFF_ADDR_HI_OFST 20 +/* Must be a power of 2 */ +#define MC_CMD_PROXY_CONFIGURE_IN_REQUEST_BLOCK_SIZE_OFST 24 +/* Host provides a contiguous memory buffer that contains at least NUM_BLOCKS + * of blocks, each of the size STATUS_BLOCK_SIZE. This buffer is only needed if + * host intends to complete proxied operations by using MC_CMD_PROXY_CMD. + */ +#define MC_CMD_PROXY_CONFIGURE_IN_REPLY_BUFF_ADDR_OFST 28 +#define MC_CMD_PROXY_CONFIGURE_IN_REPLY_BUFF_ADDR_LEN 8 +#define MC_CMD_PROXY_CONFIGURE_IN_REPLY_BUFF_ADDR_LO_OFST 28 +#define MC_CMD_PROXY_CONFIGURE_IN_REPLY_BUFF_ADDR_HI_OFST 32 +/* Must be a power of 2, or zero if this buffer is not provided */ +#define MC_CMD_PROXY_CONFIGURE_IN_REPLY_BLOCK_SIZE_OFST 36 +/* Applies to all three buffers */ +#define MC_CMD_PROXY_CONFIGURE_IN_NUM_BLOCKS_OFST 40 +/* A bit mask defining which MCDI operations may be proxied */ +#define MC_CMD_PROXY_CONFIGURE_IN_ALLOWED_MCDI_MASK_OFST 44 +#define MC_CMD_PROXY_CONFIGURE_IN_ALLOWED_MCDI_MASK_LEN 64 + +/* MC_CMD_PROXY_CONFIGURE_OUT msgresponse */ +#define MC_CMD_PROXY_CONFIGURE_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_PROXY_COMPLETE + * Tells FW that a requested proxy operation has either been completed (by + * using MC_CMD_PROXY_CMD) or authorized/declined. May only be sent by the + * function that enabled proxying/authorization (by using + * MC_CMD_PROXY_CONFIGURE). + */ +#define MC_CMD_PROXY_COMPLETE 0x5f + +#define MC_CMD_0x5f_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_PROXY_COMPLETE_IN msgrequest */ +#define MC_CMD_PROXY_COMPLETE_IN_LEN 12 +#define MC_CMD_PROXY_COMPLETE_IN_BLOCK_INDEX_OFST 0 +#define MC_CMD_PROXY_COMPLETE_IN_STATUS_OFST 4 +/* enum: The operation has been completed by using MC_CMD_PROXY_CMD, the reply + * is stored in the REPLY_BUFF. + */ +#define MC_CMD_PROXY_COMPLETE_IN_COMPLETE 0x0 +/* enum: The operation has been authorized. The originating function may now + * try again. + */ +#define MC_CMD_PROXY_COMPLETE_IN_AUTHORIZED 0x1 +/* enum: The operation has been declined. */ +#define MC_CMD_PROXY_COMPLETE_IN_DECLINED 0x2 +/* enum: The authorization failed because the relevant application did not + * respond in time. + */ +#define MC_CMD_PROXY_COMPLETE_IN_TIMEDOUT 0x3 +#define MC_CMD_PROXY_COMPLETE_IN_HANDLE_OFST 8 + +/* MC_CMD_PROXY_COMPLETE_OUT msgresponse */ +#define MC_CMD_PROXY_COMPLETE_OUT_LEN 0 + /***********************************/ /* MC_CMD_ALLOC_BUFTBL_CHUNK @@ -4688,6 +5856,44 @@ /* MC_CMD_FREE_BUFTBL_CHUNK_OUT msgresponse */ #define MC_CMD_FREE_BUFTBL_CHUNK_OUT_LEN 0 +/* PORT_CONFIG_ENTRY structuredef */ +#define PORT_CONFIG_ENTRY_LEN 16 +/* External port number (label) */ +#define PORT_CONFIG_ENTRY_EXT_NUMBER_OFST 0 +#define PORT_CONFIG_ENTRY_EXT_NUMBER_LEN 1 +#define PORT_CONFIG_ENTRY_EXT_NUMBER_LBN 0 +#define PORT_CONFIG_ENTRY_EXT_NUMBER_WIDTH 8 +/* Port core location */ +#define PORT_CONFIG_ENTRY_CORE_OFST 1 +#define PORT_CONFIG_ENTRY_CORE_LEN 1 +#define PORT_CONFIG_ENTRY_STANDALONE 0x0 /* enum */ +#define PORT_CONFIG_ENTRY_MASTER 0x1 /* enum */ +#define PORT_CONFIG_ENTRY_SLAVE 0x2 /* enum */ +#define PORT_CONFIG_ENTRY_CORE_LBN 8 +#define PORT_CONFIG_ENTRY_CORE_WIDTH 8 +/* Internal number (HW resource) relative to the core */ +#define PORT_CONFIG_ENTRY_INT_NUMBER_OFST 2 +#define PORT_CONFIG_ENTRY_INT_NUMBER_LEN 1 +#define PORT_CONFIG_ENTRY_INT_NUMBER_LBN 16 +#define PORT_CONFIG_ENTRY_INT_NUMBER_WIDTH 8 +/* Reserved */ +#define PORT_CONFIG_ENTRY_RSVD_OFST 3 +#define PORT_CONFIG_ENTRY_RSVD_LEN 1 +#define PORT_CONFIG_ENTRY_RSVD_LBN 24 +#define PORT_CONFIG_ENTRY_RSVD_WIDTH 8 +/* Bitmask of KR lanes used by the port */ +#define PORT_CONFIG_ENTRY_LANES_OFST 4 +#define PORT_CONFIG_ENTRY_LANES_LBN 32 +#define PORT_CONFIG_ENTRY_LANES_WIDTH 32 +/* Port capabilities (MC_CMD_PHY_CAP_*) */ +#define PORT_CONFIG_ENTRY_SUPPORTED_CAPS_OFST 8 +#define PORT_CONFIG_ENTRY_SUPPORTED_CAPS_LBN 64 +#define PORT_CONFIG_ENTRY_SUPPORTED_CAPS_WIDTH 32 +/* Reserved (align to 16 bytes) */ +#define PORT_CONFIG_ENTRY_RSVD2_OFST 12 +#define PORT_CONFIG_ENTRY_RSVD2_LBN 96 +#define PORT_CONFIG_ENTRY_RSVD2_WIDTH 32 + /***********************************/ /* MC_CMD_FILTER_OP @@ -4759,9 +5965,9 @@ #define MC_CMD_FILTER_OP_IN_RX_DEST_HOST 0x1 /* enum: receive to MC */ #define MC_CMD_FILTER_OP_IN_RX_DEST_MC 0x2 -/* enum: loop back to port 0 TX MAC */ +/* enum: loop back to TXDP 0 */ #define MC_CMD_FILTER_OP_IN_RX_DEST_TX0 0x3 -/* enum: loop back to port 1 TX MAC */ +/* enum: loop back to TXDP 1 */ #define MC_CMD_FILTER_OP_IN_RX_DEST_TX1 0x4 /* receive queue handle (for multiple queue modes, this is the base queue) */ #define MC_CMD_FILTER_OP_IN_RX_QUEUE_OFST 24 @@ -4778,9 +5984,7 @@ #define MC_CMD_FILTER_OP_IN_RX_MODE_TEST_NEVER_MATCH 0x80000000 /* RSS context (for RX_MODE_RSS) or .1p mapping handle (for * RX_MODE_DOT1P_MAPPING), as returned by MC_CMD_RSS_CONTEXT_ALLOC or - * MC_CMD_DOT1P_MAPPING_ALLOC. Note that these handles should be considered - * opaque to the host, although a value of 0xFFFFFFFF is guaranteed never to be - * a valid handle. + * MC_CMD_DOT1P_MAPPING_ALLOC. */ #define MC_CMD_FILTER_OP_IN_RX_CONTEXT_OFST 32 /* transmit domain (reserved; set to 0) */ @@ -4835,6 +6039,235 @@ #define MC_CMD_FILTER_OP_IN_DST_IP_OFST 92 #define MC_CMD_FILTER_OP_IN_DST_IP_LEN 16 +/* MC_CMD_FILTER_OP_EXT_IN msgrequest: Extension to MC_CMD_FILTER_OP_IN to + * include handling of VXLAN/NVGRE encapsulated frame filtering (which is + * supported on Medford only). + */ +#define MC_CMD_FILTER_OP_EXT_IN_LEN 172 +/* identifies the type of operation requested */ +#define MC_CMD_FILTER_OP_EXT_IN_OP_OFST 0 +/* Enum values, see field(s): */ +/* MC_CMD_FILTER_OP_IN/OP */ +/* filter handle (for remove / unsubscribe operations) */ +#define MC_CMD_FILTER_OP_EXT_IN_HANDLE_OFST 4 +#define MC_CMD_FILTER_OP_EXT_IN_HANDLE_LEN 8 +#define MC_CMD_FILTER_OP_EXT_IN_HANDLE_LO_OFST 4 +#define MC_CMD_FILTER_OP_EXT_IN_HANDLE_HI_OFST 8 +/* The port ID associated with the v-adaptor which should contain this filter. + */ +#define MC_CMD_FILTER_OP_EXT_IN_PORT_ID_OFST 12 +/* fields to include in match criteria */ +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_FIELDS_OFST 16 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_IP_LBN 0 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_IP_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_IP_LBN 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_IP_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_MAC_LBN 2 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_MAC_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_PORT_LBN 3 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_PORT_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_MAC_LBN 4 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_MAC_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_PORT_LBN 5 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_PORT_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_ETHER_TYPE_LBN 6 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_ETHER_TYPE_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_INNER_VLAN_LBN 7 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_INNER_VLAN_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN_LBN 8 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO_LBN 9 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_FWDEF0_LBN 10 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_FWDEF0_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_VNI_OR_VSID_LBN 11 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_VNI_OR_VSID_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_IP_LBN 12 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_IP_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_IP_LBN 13 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_IP_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_MAC_LBN 14 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_MAC_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_PORT_LBN 15 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_PORT_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_MAC_LBN 16 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_MAC_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_PORT_LBN 17 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_PORT_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_ETHER_TYPE_LBN 18 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_ETHER_TYPE_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_INNER_VLAN_LBN 19 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_INNER_VLAN_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_OUTER_VLAN_LBN 20 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_OUTER_VLAN_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_IP_PROTO_LBN 21 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_IP_PROTO_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_FWDEF0_LBN 22 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_FWDEF0_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_FWDEF1_LBN 23 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_FWDEF1_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST_LBN 24 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST_LBN 25 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST_LBN 30 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_UCAST_DST_LBN 31 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_UCAST_DST_WIDTH 1 +/* receive destination */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_OFST 20 +/* enum: drop packets */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_DROP 0x0 +/* enum: receive to host */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST 0x1 +/* enum: receive to MC */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_MC 0x2 +/* enum: loop back to TXDP 0 */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_TX0 0x3 +/* enum: loop back to TXDP 1 */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_TX1 0x4 +/* receive queue handle (for multiple queue modes, this is the base queue) */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_QUEUE_OFST 24 +/* receive mode */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_MODE_OFST 28 +/* enum: receive to just the specified queue */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_MODE_SIMPLE 0x0 +/* enum: receive to multiple queues using RSS context */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_MODE_RSS 0x1 +/* enum: receive to multiple queues using .1p mapping */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_MODE_DOT1P_MAPPING 0x2 +/* enum: install a filter entry that will never match; for test purposes only + */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_MODE_TEST_NEVER_MATCH 0x80000000 +/* RSS context (for RX_MODE_RSS) or .1p mapping handle (for + * RX_MODE_DOT1P_MAPPING), as returned by MC_CMD_RSS_CONTEXT_ALLOC or + * MC_CMD_DOT1P_MAPPING_ALLOC. + */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_CONTEXT_OFST 32 +/* transmit domain (reserved; set to 0) */ +#define MC_CMD_FILTER_OP_EXT_IN_TX_DOMAIN_OFST 36 +/* transmit destination (either set the MAC and/or PM bits for explicit + * control, or set this field to TX_DEST_DEFAULT for sensible default + * behaviour) + */ +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_OFST 40 +/* enum: request default behaviour (based on filter type) */ +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_DEFAULT 0xffffffff +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_MAC_LBN 0 +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_MAC_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_PM_LBN 1 +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_PM_WIDTH 1 +/* source MAC address to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_SRC_MAC_OFST 44 +#define MC_CMD_FILTER_OP_EXT_IN_SRC_MAC_LEN 6 +/* source port to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_SRC_PORT_OFST 50 +#define MC_CMD_FILTER_OP_EXT_IN_SRC_PORT_LEN 2 +/* destination MAC address to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_DST_MAC_OFST 52 +#define MC_CMD_FILTER_OP_EXT_IN_DST_MAC_LEN 6 +/* destination port to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_DST_PORT_OFST 58 +#define MC_CMD_FILTER_OP_EXT_IN_DST_PORT_LEN 2 +/* Ethernet type to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_ETHER_TYPE_OFST 60 +#define MC_CMD_FILTER_OP_EXT_IN_ETHER_TYPE_LEN 2 +/* Inner VLAN tag to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_INNER_VLAN_OFST 62 +#define MC_CMD_FILTER_OP_EXT_IN_INNER_VLAN_LEN 2 +/* Outer VLAN tag to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_OUTER_VLAN_OFST 64 +#define MC_CMD_FILTER_OP_EXT_IN_OUTER_VLAN_LEN 2 +/* IP protocol to match (in low byte; set high byte to 0) */ +#define MC_CMD_FILTER_OP_EXT_IN_IP_PROTO_OFST 66 +#define MC_CMD_FILTER_OP_EXT_IN_IP_PROTO_LEN 2 +/* Firmware defined register 0 to match (reserved; set to 0) */ +#define MC_CMD_FILTER_OP_EXT_IN_FWDEF0_OFST 68 +/* VNI (for VXLAN/Geneve, when IP protocol is UDP) or VSID (for NVGRE, when IP + * protocol is GRE) to match (as bytes in network order; set last byte to 0 for + * VXLAN/NVGRE, or 1 for Geneve) + */ +#define MC_CMD_FILTER_OP_EXT_IN_VNI_OR_VSID_OFST 72 +#define MC_CMD_FILTER_OP_EXT_IN_VNI_VALUE_LBN 0 +#define MC_CMD_FILTER_OP_EXT_IN_VNI_VALUE_WIDTH 24 +#define MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_LBN 24 +#define MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_WIDTH 8 +/* enum: Match VXLAN traffic with this VNI */ +#define MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_VXLAN 0x0 +/* enum: Match Geneve traffic with this VNI */ +#define MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_GENEVE 0x1 +/* enum: Reserved for experimental development use */ +#define MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_EXPERIMENTAL 0xfe +#define MC_CMD_FILTER_OP_EXT_IN_VSID_VALUE_LBN 0 +#define MC_CMD_FILTER_OP_EXT_IN_VSID_VALUE_WIDTH 24 +#define MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_LBN 24 +#define MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_WIDTH 8 +/* enum: Match NVGRE traffic with this VSID */ +#define MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_NVGRE 0x0 +/* source IP address to match (as bytes in network order; set last 12 bytes to + * 0 for IPv4 address) + */ +#define MC_CMD_FILTER_OP_EXT_IN_SRC_IP_OFST 76 +#define MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN 16 +/* destination IP address to match (as bytes in network order; set last 12 + * bytes to 0 for IPv4 address) + */ +#define MC_CMD_FILTER_OP_EXT_IN_DST_IP_OFST 92 +#define MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN 16 +/* VXLAN/NVGRE inner frame source MAC address to match (as bytes in network + * order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_MAC_OFST 108 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_MAC_LEN 6 +/* VXLAN/NVGRE inner frame source port to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_PORT_OFST 114 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_PORT_LEN 2 +/* VXLAN/NVGRE inner frame destination MAC address to match (as bytes in + * network order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_MAC_OFST 116 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_MAC_LEN 6 +/* VXLAN/NVGRE inner frame destination port to match (as bytes in network + * order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_PORT_OFST 122 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_PORT_LEN 2 +/* VXLAN/NVGRE inner frame Ethernet type to match (as bytes in network order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_ETHER_TYPE_OFST 124 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_ETHER_TYPE_LEN 2 +/* VXLAN/NVGRE inner frame Inner VLAN tag to match (as bytes in network order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_INNER_VLAN_OFST 126 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_INNER_VLAN_LEN 2 +/* VXLAN/NVGRE inner frame Outer VLAN tag to match (as bytes in network order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_OUTER_VLAN_OFST 128 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_OUTER_VLAN_LEN 2 +/* VXLAN/NVGRE inner frame IP protocol to match (in low byte; set high byte to + * 0) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_IP_PROTO_OFST 130 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_IP_PROTO_LEN 2 +/* VXLAN/NVGRE inner frame Firmware defined register 0 to match (reserved; set + * to 0) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_FWDEF0_OFST 132 +/* VXLAN/NVGRE inner frame Firmware defined register 1 to match (reserved; set + * to 0) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_FWDEF1_OFST 136 +/* VXLAN/NVGRE inner frame source IP address to match (as bytes in network + * order; set last 12 bytes to 0 for IPv4 address) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_IP_OFST 140 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_IP_LEN 16 +/* VXLAN/NVGRE inner frame destination IP address to match (as bytes in network + * order; set last 12 bytes to 0 for IPv4 address) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_IP_OFST 156 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_IP_LEN 16 + /* MC_CMD_FILTER_OP_OUT msgresponse */ #define MC_CMD_FILTER_OP_OUT_LEN 12 /* identifies the type of operation requested */ @@ -4849,6 +6282,27 @@ #define MC_CMD_FILTER_OP_OUT_HANDLE_LEN 8 #define MC_CMD_FILTER_OP_OUT_HANDLE_LO_OFST 4 #define MC_CMD_FILTER_OP_OUT_HANDLE_HI_OFST 8 +/* enum: guaranteed invalid filter handle (low 32 bits) */ +#define MC_CMD_FILTER_OP_OUT_HANDLE_LO_INVALID 0xffffffff +/* enum: guaranteed invalid filter handle (high 32 bits) */ +#define MC_CMD_FILTER_OP_OUT_HANDLE_HI_INVALID 0xffffffff + +/* MC_CMD_FILTER_OP_EXT_OUT msgresponse */ +#define MC_CMD_FILTER_OP_EXT_OUT_LEN 12 +/* identifies the type of operation requested */ +#define MC_CMD_FILTER_OP_EXT_OUT_OP_OFST 0 +/* Enum values, see field(s): */ +/* MC_CMD_FILTER_OP_EXT_IN/OP */ +/* Returned filter handle (for insert / subscribe operations). Note that these + * handles should be considered opaque to the host, although a value of + * 0xFFFFFFFF_FFFFFFFF is guaranteed never to be a valid handle. + */ +#define MC_CMD_FILTER_OP_EXT_OUT_HANDLE_OFST 4 +#define MC_CMD_FILTER_OP_EXT_OUT_HANDLE_LEN 8 +#define MC_CMD_FILTER_OP_EXT_OUT_HANDLE_LO_OFST 4 +#define MC_CMD_FILTER_OP_EXT_OUT_HANDLE_HI_OFST 8 +/* Enum values, see field(s): */ +/* MC_CMD_FILTER_OP_OUT/HANDLE */ /***********************************/ @@ -4865,6 +6319,10 @@ #define MC_CMD_GET_PARSER_DISP_INFO_IN_OP_OFST 0 /* enum: read the list of supported RX filter matches */ #define MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES 0x1 +/* enum: read flags indicating restrictions on filter insertion for the calling + * client + */ +#define MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_RESTRICTIONS 0x2 /* MC_CMD_GET_PARSER_DISP_INFO_OUT msgresponse */ #define MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMIN 8 @@ -4884,6 +6342,17 @@ #define MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_MINNUM 0 #define MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_MAXNUM 61 +/* MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT msgresponse */ +#define MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT_LEN 8 +/* identifies the type of operation requested */ +#define MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT_OP_OFST 0 +/* Enum values, see field(s): */ +/* MC_CMD_GET_PARSER_DISP_INFO_IN/OP */ +/* bitfield of filter insertion restrictions */ +#define MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT_RESTRICTION_FLAGS_OFST 4 +#define MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT_DST_IP_MCAST_ONLY_LBN 0 +#define MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT_DST_IP_MCAST_ONLY_WIDTH 1 + /***********************************/ /* MC_CMD_PARSER_DISP_RW @@ -4901,8 +6370,10 @@ #define MC_CMD_PARSER_DISP_RW_IN_RX_DICPU 0x0 /* enum: TX dispatcher CPU */ #define MC_CMD_PARSER_DISP_RW_IN_TX_DICPU 0x1 -/* enum: Lookup engine */ +/* enum: Lookup engine (with original metadata format) */ #define MC_CMD_PARSER_DISP_RW_IN_LUE 0x2 +/* enum: Lookup engine (with requested metadata format) */ +#define MC_CMD_PARSER_DISP_RW_IN_LUE_VERSIONED_METADATA 0x3 /* identifies the type of operation requested */ #define MC_CMD_PARSER_DISP_RW_IN_OP_OFST 4 /* enum: read a word of DICPU DMEM or a LUE entry */ @@ -4919,6 +6390,8 @@ #define MC_CMD_PARSER_DISP_RW_IN_DMEM_RMW_XOR_VALUE_OFST 12 /* AND mask (for DMEM read-modify-writes: new = (old & mask) ^ value) */ #define MC_CMD_PARSER_DISP_RW_IN_DMEM_RMW_AND_MASK_OFST 16 +/* metadata format (for LUE reads using LUE_VERSIONED_METADATA) */ +#define MC_CMD_PARSER_DISP_RW_IN_LUE_READ_METADATA_VERSION_OFST 12 /* value to write (for LUE writes) */ #define MC_CMD_PARSER_DISP_RW_IN_LUE_WRITE_VALUE_OFST 12 #define MC_CMD_PARSER_DISP_RW_IN_LUE_WRITE_VALUE_LEN 20 @@ -5019,7 +6492,9 @@ /* The maximum number of VIs that would be useful */ #define MC_CMD_ALLOC_VIS_IN_MAX_VI_COUNT_OFST 4 -/* MC_CMD_ALLOC_VIS_OUT msgresponse */ +/* MC_CMD_ALLOC_VIS_OUT msgresponse: Huntington-compatible VI_ALLOC request. + * Use extended version in new code. + */ #define MC_CMD_ALLOC_VIS_OUT_LEN 8 /* The number of VIs allocated on this function */ #define MC_CMD_ALLOC_VIS_OUT_VI_COUNT_OFST 0 @@ -5028,6 +6503,17 @@ */ #define MC_CMD_ALLOC_VIS_OUT_VI_BASE_OFST 4 +/* MC_CMD_ALLOC_VIS_EXT_OUT msgresponse */ +#define MC_CMD_ALLOC_VIS_EXT_OUT_LEN 12 +/* The number of VIs allocated on this function */ +#define MC_CMD_ALLOC_VIS_EXT_OUT_VI_COUNT_OFST 0 +/* The base absolute VI number allocated to this function. Required to + * correctly interpret wakeup events. + */ +#define MC_CMD_ALLOC_VIS_EXT_OUT_VI_BASE_OFST 4 +/* Function's port vi_shift value (always 0 on Huntington) */ +#define MC_CMD_ALLOC_VIS_EXT_OUT_VI_SHIFT_OFST 8 + /***********************************/ /* MC_CMD_FREE_VIS @@ -5114,13 +6600,15 @@ #define MC_CMD_GET_VI_ALLOC_INFO_IN_LEN 0 /* MC_CMD_GET_VI_ALLOC_INFO_OUT msgresponse */ -#define MC_CMD_GET_VI_ALLOC_INFO_OUT_LEN 8 +#define MC_CMD_GET_VI_ALLOC_INFO_OUT_LEN 12 /* The number of VIs allocated on this function */ #define MC_CMD_GET_VI_ALLOC_INFO_OUT_VI_COUNT_OFST 0 /* The base absolute VI number allocated to this function. Required to * correctly interpret wakeup events. */ #define MC_CMD_GET_VI_ALLOC_INFO_OUT_VI_BASE_OFST 4 +/* Function's port vi_shift value (always 0 on Huntington) */ +#define MC_CMD_GET_VI_ALLOC_INFO_OUT_VI_SHIFT_OFST 8 /***********************************/ @@ -5575,6 +7063,7 @@ #define MC_CMD_GET_CAPABILITIES 0xbe #define MC_CMD_0xbe_PRIVILEGE_CTG SRIOV_CTG_GENERAL + /* MC_CMD_GET_CAPABILITIES_IN msgrequest */ #define MC_CMD_GET_CAPABILITIES_IN_LEN 0 @@ -5582,6 +7071,20 @@ #define MC_CMD_GET_CAPABILITIES_OUT_LEN 20 /* First word of flags. */ #define MC_CMD_GET_CAPABILITIES_OUT_FLAGS1_OFST 0 +#define MC_CMD_GET_CAPABILITIES_OUT_TX_MAC_SECURITY_FILTERING_LBN 12 +#define MC_CMD_GET_CAPABILITIES_OUT_TX_MAC_SECURITY_FILTERING_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_ADDITIONAL_RSS_MODES_LBN 13 +#define MC_CMD_GET_CAPABILITIES_OUT_ADDITIONAL_RSS_MODES_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_QBB_LBN 14 +#define MC_CMD_GET_CAPABILITIES_OUT_QBB_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_PACKED_STREAM_VAR_BUFFERS_LBN 15 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_PACKED_STREAM_VAR_BUFFERS_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_RSS_LIMITED_LBN 16 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_RSS_LIMITED_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_PACKED_STREAM_LBN 17 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_PACKED_STREAM_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_INCLUDE_FCS_LBN 18 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_INCLUDE_FCS_WIDTH 1 #define MC_CMD_GET_CAPABILITIES_OUT_TX_VLAN_INSERTION_LBN 19 #define MC_CMD_GET_CAPABILITIES_OUT_TX_VLAN_INSERTION_WIDTH 1 #define MC_CMD_GET_CAPABILITIES_OUT_RX_VLAN_STRIPPING_LBN 20 @@ -5600,8 +7103,14 @@ #define MC_CMD_GET_CAPABILITIES_OUT_MCAST_FILTER_CHAINING_WIDTH 1 #define MC_CMD_GET_CAPABILITIES_OUT_PM_AND_RXDP_COUNTERS_LBN 27 #define MC_CMD_GET_CAPABILITIES_OUT_PM_AND_RXDP_COUNTERS_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_DISABLE_SCATTER_LBN 28 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_DISABLE_SCATTER_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_TX_MCAST_UDP_LOOPBACK_LBN 29 +#define MC_CMD_GET_CAPABILITIES_OUT_TX_MCAST_UDP_LOOPBACK_WIDTH 1 #define MC_CMD_GET_CAPABILITIES_OUT_EVB_LBN 30 #define MC_CMD_GET_CAPABILITIES_OUT_EVB_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_LBN 31 +#define MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_WIDTH 1 /* RxDPCPU firmware id. */ #define MC_CMD_GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID_OFST 4 #define MC_CMD_GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID_LEN 2 @@ -5609,6 +7118,10 @@ #define MC_CMD_GET_CAPABILITIES_OUT_RXDP 0x0 /* enum: Low latency RXDP firmware */ #define MC_CMD_GET_CAPABILITIES_OUT_RXDP_LOW_LATENCY 0x1 +/* enum: Packed stream RXDP firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXDP_PACKED_STREAM 0x2 +/* enum: BIST RXDP firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXDP_BIST 0x10a /* enum: RXDP Test firmware image 1 */ #define MC_CMD_GET_CAPABILITIES_OUT_RXDP_TEST_FW_TO_MC_CUT_THROUGH 0x101 /* enum: RXDP Test firmware image 2 */ @@ -5632,6 +7145,10 @@ #define MC_CMD_GET_CAPABILITIES_OUT_TXDP 0x0 /* enum: Low latency TXDP firmware */ #define MC_CMD_GET_CAPABILITIES_OUT_TXDP_LOW_LATENCY 0x1 +/* enum: High packet rate TXDP firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXDP_HIGH_PACKET_RATE 0x3 +/* enum: BIST TXDP firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXDP_BIST 0x12d /* enum: TXDP Test firmware image 1 */ #define MC_CMD_GET_CAPABILITIES_OUT_TXDP_TEST_FW_TSO_EDIT 0x101 /* enum: TXDP Test firmware image 2 */ @@ -5642,22 +7159,69 @@ #define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_VERSION_REV_WIDTH 12 #define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_VERSION_TYPE_LBN 12 #define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_VERSION_TYPE_WIDTH 4 -#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_FIRST_PKT 0x1 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_SIENA_COMPAT 0x2 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_VSWITCH 0x3 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_SIENA_COMPAT_PM 0x4 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_LOW_LATENCY 0x5 /* enum */ +/* enum: reserved value - do not use (may indicate alternative interpretation + * of REV field in future) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_RESERVED 0x0 +/* enum: Trivial RX PD firmware for early Huntington development (Huntington + * development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_FIRST_PKT 0x1 +/* enum: RX PD firmware with approximately Siena-compatible behaviour + * (Huntington development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_SIENA_COMPAT 0x2 +/* enum: Virtual switching (full feature) RX PD production firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_VSWITCH 0x3 +/* enum: siena_compat variant RX PD firmware using PM rather than MAC + * (Huntington development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_SIENA_COMPAT_PM 0x4 +/* enum: Low latency RX PD production firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_LOW_LATENCY 0x5 +/* enum: Packed stream RX PD production firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_PACKED_STREAM 0x6 +/* enum: RX PD firmware handling layer 2 only for high packet rate performance + * tests (Medford development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_LAYER2_PERF 0x7 +/* enum: RX PD firmware for GUE parsing prototype (Medford development only) */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_TESTFW_GUE_PROTOTYPE 0xe +/* enum: RX PD firmware parsing but not filtering network overlay tunnel + * encapsulations (Medford development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_TESTFW_ENCAP_PARSING_ONLY 0xf #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_OFST 10 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_LEN 2 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_REV_LBN 0 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_REV_WIDTH 12 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_TYPE_LBN 12 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_TYPE_WIDTH 4 -#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_FIRST_PKT 0x1 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_SIENA_COMPAT 0x2 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_VSWITCH 0x3 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_SIENA_COMPAT_PM 0x4 /* enum */ +/* enum: reserved value - do not use (may indicate alternative interpretation + * of REV field in future) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_RESERVED 0x0 +/* enum: Trivial TX PD firmware for early Huntington development (Huntington + * development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_FIRST_PKT 0x1 +/* enum: TX PD firmware with approximately Siena-compatible behaviour + * (Huntington development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_SIENA_COMPAT 0x2 +/* enum: Virtual switching (full feature) TX PD production firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_VSWITCH 0x3 +/* enum: siena_compat variant TX PD firmware using PM rather than MAC + * (Huntington development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_SIENA_COMPAT_PM 0x4 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_LOW_LATENCY 0x5 /* enum */ +/* enum: TX PD firmware handling layer 2 only for high packet rate performance + * tests (Medford development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_LAYER2_PERF 0x7 +/* enum: RX PD firmware for GUE parsing prototype (Medford development only) */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_TESTFW_GUE_PROTOTYPE 0xe /* Hardware capabilities of NIC */ #define MC_CMD_GET_CAPABILITIES_OUT_HW_CAPABILITIES_OFST 12 /* Licensed capabilities */ @@ -5735,6 +7299,15 @@ /* the rate in mbps */ #define MC_CMD_TCM_BUCKET_INIT_IN_RATE_OFST 4 +/* MC_CMD_TCM_BUCKET_INIT_EXT_IN msgrequest */ +#define MC_CMD_TCM_BUCKET_INIT_EXT_IN_LEN 12 +/* the bucket id */ +#define MC_CMD_TCM_BUCKET_INIT_EXT_IN_BUCKET_OFST 0 +/* the rate in mbps */ +#define MC_CMD_TCM_BUCKET_INIT_EXT_IN_RATE_OFST 4 +/* the desired maximum fill level */ +#define MC_CMD_TCM_BUCKET_INIT_EXT_IN_MAX_FILL_OFST 8 + /* MC_CMD_TCM_BUCKET_INIT_OUT msgresponse */ #define MC_CMD_TCM_BUCKET_INIT_OUT_LEN 0 @@ -5753,8 +7326,14 @@ #define MC_CMD_TCM_TXQ_INIT_IN_QID_OFST 0 /* the static priority associated with the txq */ #define MC_CMD_TCM_TXQ_INIT_IN_LABEL_OFST 4 -/* bitmask of the priority queues this txq is inserted into */ +/* bitmask of the priority queues this txq is inserted into when inserted. */ #define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAGS_OFST 8 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_GUARANTEED_LBN 0 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_GUARANTEED_WIDTH 1 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_NORMAL_LBN 1 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_NORMAL_WIDTH 1 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_LOW_LBN 2 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_LOW_WIDTH 1 /* the reaction point (RP) bucket */ #define MC_CMD_TCM_TXQ_INIT_IN_RP_BKT_OFST 12 /* an already reserved bucket (typically set to bucket associated with outer @@ -5768,6 +7347,35 @@ /* the min bucket (typically for ETS/minimum bandwidth) */ #define MC_CMD_TCM_TXQ_INIT_IN_MIN_BKT_OFST 24 +/* MC_CMD_TCM_TXQ_INIT_EXT_IN msgrequest */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_LEN 32 +/* the txq id */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_QID_OFST 0 +/* the static priority associated with the txq */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_LABEL_NORMAL_OFST 4 +/* bitmask of the priority queues this txq is inserted into when inserted. */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAGS_OFST 8 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_GUARANTEED_LBN 0 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_GUARANTEED_WIDTH 1 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_NORMAL_LBN 1 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_NORMAL_WIDTH 1 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_LOW_LBN 2 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_LOW_WIDTH 1 +/* the reaction point (RP) bucket */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_RP_BKT_OFST 12 +/* an already reserved bucket (typically set to bucket associated with outer + * vswitch) + */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_MAX_BKT1_OFST 16 +/* an already reserved bucket (typically set to bucket associated with inner + * vswitch) + */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_MAX_BKT2_OFST 20 +/* the min bucket (typically for ETS/minimum bandwidth) */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_MIN_BKT_OFST 24 +/* the static priority associated with the txq */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_LABEL_GUARANTEED_OFST 28 + /* MC_CMD_TCM_TXQ_INIT_OUT msgresponse */ #define MC_CMD_TCM_TXQ_INIT_OUT_LEN 0 @@ -5826,13 +7434,23 @@ #define MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VLAN 0x1 /* enum: VEB */ #define MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB 0x2 -/* enum: VEPA */ +/* enum: VEPA (obsolete) */ #define MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEPA 0x3 +/* enum: MUX */ +#define MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_MUX 0x4 +/* enum: Snapper specific; semantics TBD */ +#define MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_TEST 0x5 /* Flags controlling v-port creation */ #define MC_CMD_VSWITCH_ALLOC_IN_FLAGS_OFST 8 #define MC_CMD_VSWITCH_ALLOC_IN_FLAG_AUTO_PORT_LBN 0 #define MC_CMD_VSWITCH_ALLOC_IN_FLAG_AUTO_PORT_WIDTH 1 -/* The number of VLAN tags to support. */ +/* The number of VLAN tags to allow for attached v-ports. For VLAN aggregators, + * this must be one or greated, and the attached v-ports must have exactly this + * number of tags. For other v-switch types, this must be zero of greater, and + * is an upper limit on the number of VLAN tags for attached v-ports. An error + * will be returned if existing configuration means we can't support attached + * v-ports with this number of tags. + */ #define MC_CMD_VSWITCH_ALLOC_IN_NUM_VLAN_TAGS_OFST 12 /* MC_CMD_VSWITCH_ALLOC_OUT msgresponse */ @@ -5892,7 +7510,10 @@ #define MC_CMD_VPORT_ALLOC_IN_FLAGS_OFST 8 #define MC_CMD_VPORT_ALLOC_IN_FLAG_AUTO_PORT_LBN 0 #define MC_CMD_VPORT_ALLOC_IN_FLAG_AUTO_PORT_WIDTH 1 -/* The number of VLAN tags to insert/remove. */ +/* The number of VLAN tags to insert/remove. An error will be returned if + * incompatible with the number of VLAN tags specified for the upstream + * v-switch. + */ #define MC_CMD_VPORT_ALLOC_IN_NUM_VLAN_TAGS_OFST 12 /* The actual VLAN tags to insert/remove */ #define MC_CMD_VPORT_ALLOC_IN_VLAN_TAGS_OFST 16 @@ -6136,8 +7757,13 @@ /* MC_CMD_RSS_CONTEXT_ALLOC_OUT msgresponse */ #define MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN 4 -/* The handle of the new RSS context */ +/* The handle of the new RSS context. This should be considered opaque to the + * host, although a value of 0xFFFFFFFF is guaranteed never to be a valid + * handle. + */ #define MC_CMD_RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID_OFST 0 +/* enum: guaranteed invalid RSS context handle value */ +#define MC_CMD_RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID_INVALID 0xffffffff /***********************************/ @@ -6249,7 +7875,11 @@ #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN 8 /* The handle of the RSS context */ #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID_OFST 0 -/* Hash control flags */ +/* Hash control flags. The _EN bits are always supported. The _MODE bits only + * work when the firmware reports ADDITIONAL_RSS_MODES in + * MC_CMD_GET_CAPABILITIES and override the _EN bits if any of them are not 0. + * See the RSS_MODE structure for the meaning of the mode bits. + */ #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_FLAGS_OFST 4 #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN_LBN 0 #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN_WIDTH 1 @@ -6259,6 +7889,20 @@ #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN_WIDTH 1 #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN_LBN 3 #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN_WIDTH 1 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_RESERVED_LBN 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_RESERVED_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE_LBN 8 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV4_RSS_MODE_LBN 12 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE_LBN 16 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE_LBN 20 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV6_RSS_MODE_LBN 24 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV6_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE_LBN 28 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE_WIDTH 4 /* MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT msgresponse */ #define MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN 0 @@ -6279,7 +7923,12 @@ /* MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT msgresponse */ #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_LEN 8 -/* Hash control flags */ +/* Hash control flags. If any _MODE bits are non-zero (which will only be true + * when the firmware reports ADDITIONAL_RSS_MODES) then the _EN bits should be + * disregarded (but are guaranteed to be consistent with the _MODE bits if + * RSS_CONTEXT_SET_FLAGS has never been called for this context since it was + * allocated). + */ #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_FLAGS_OFST 4 #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_IPV4_EN_LBN 0 #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_IPV4_EN_WIDTH 1 @@ -6289,6 +7938,20 @@ #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_IPV6_EN_WIDTH 1 #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_TCPV6_EN_LBN 3 #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_TCPV6_EN_WIDTH 1 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_RESERVED_LBN 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_RESERVED_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TCP_IPV4_RSS_MODE_LBN 8 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TCP_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV4_RSS_MODE_LBN 12 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV4_RSS_MODE_LBN 16 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TCP_IPV6_RSS_MODE_LBN 20 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TCP_IPV6_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV6_RSS_MODE_LBN 24 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV6_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV6_RSS_MODE_LBN 28 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV6_RSS_MODE_WIDTH 4 /***********************************/ @@ -6311,8 +7974,13 @@ /* MC_CMD_DOT1P_MAPPING_ALLOC_OUT msgresponse */ #define MC_CMD_DOT1P_MAPPING_ALLOC_OUT_LEN 4 -/* The handle of the new .1p mapping */ +/* The handle of the new .1p mapping. This should be considered opaque to the + * host, although a value of 0xFFFFFFFF is guaranteed never to be a valid + * handle. + */ #define MC_CMD_DOT1P_MAPPING_ALLOC_OUT_DOT1P_MAPPING_ID_OFST 0 +/* enum: guaranteed invalid .1p mapping handle value */ +#define MC_CMD_DOT1P_MAPPING_ALLOC_OUT_DOT1P_MAPPING_ID_INVALID 0xffffffff /***********************************/ @@ -6421,401 +8089,32 @@ /***********************************/ -/* MC_CMD_RMON_RX_CLASS_STATS - * Retrieve rmon rx class statistics +/* MC_CMD_VPORT_ADD_MAC_ADDRESS + * Add a MAC address to a v-port */ -#define MC_CMD_RMON_RX_CLASS_STATS 0xc3 - -/* MC_CMD_RMON_RX_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_CLASS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_CLASS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_CLASS_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_RX_CLASS_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_RX_CLASS_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_RX_CLASS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_BUFFER_MAXNUM 63 - +#define MC_CMD_VPORT_ADD_MAC_ADDRESS 0xa8 -/***********************************/ -/* MC_CMD_RMON_TX_CLASS_STATS - * Retrieve rmon tx class statistics - */ -#define MC_CMD_RMON_TX_CLASS_STATS 0xc4 +#define MC_CMD_0xa8_PRIVILEGE_CTG SRIOV_CTG_GENERAL -/* MC_CMD_RMON_TX_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_CLASS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_CLASS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_CLASS_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_TX_CLASS_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_TX_CLASS_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_TX_CLASS_STATS_IN_RST_WIDTH 1 +/* MC_CMD_VPORT_ADD_MAC_ADDRESS_IN msgrequest */ +#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN 10 +/* The handle of the v-port */ +#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID_OFST 0 +/* MAC address to add */ +#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_MACADDR_OFST 4 +#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_MACADDR_LEN 6 -/* MC_CMD_RMON_TX_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_BUFFER_MAXNUM 63 +/* MC_CMD_VPORT_ADD_MAC_ADDRESS_OUT msgresponse */ +#define MC_CMD_VPORT_ADD_MAC_ADDRESS_OUT_LEN 0 /***********************************/ -/* MC_CMD_RMON_RX_SUPER_CLASS_STATS - * Retrieve rmon rx super_class statistics +/* MC_CMD_VPORT_DEL_MAC_ADDRESS + * Delete a MAC address from a v-port */ -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS 0xc5 - -/* MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_RST_LBN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_BUFFER_MAXNUM 63 +#define MC_CMD_VPORT_DEL_MAC_ADDRESS 0xa9 - -/***********************************/ -/* MC_CMD_RMON_TX_SUPER_CLASS_STATS - * Retrieve rmon tx super_class statistics - */ -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS 0xc6 - -/* MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_RST_LBN 4 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_ADD_QID_TO_CLASS - * Add qid to class for statistics collection - */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS 0xc7 - -/* MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN msgrequest */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_LEN 12 -/* class */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_CLASS_OFST 0 -/* qid */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_QID_OFST 4 -/* flags */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_FLAGS_OFST 8 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_PE_DELTA_LBN 4 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_PE_DELTA_WIDTH 4 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_MTU_LBN 8 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_MTU_WIDTH 14 - -/* MC_CMD_RMON_RX_ADD_QID_TO_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_RMON_TX_ADD_QID_TO_CLASS - * Add qid to class for statistics collection - */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS 0xc8 - -/* MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN msgrequest */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_LEN 12 -/* class */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_CLASS_OFST 0 -/* qid */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_QID_OFST 4 -/* flags */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_FLAGS_OFST 8 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_PE_DELTA_LBN 4 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_PE_DELTA_WIDTH 4 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_MTU_LBN 8 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_MTU_WIDTH 14 - -/* MC_CMD_RMON_TX_ADD_QID_TO_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_RMON_MC_ADD_QID_TO_CLASS - * Add qid to class for statistics collection - */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS 0xc9 - -/* MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN msgrequest */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_LEN 12 -/* class */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_CLASS_OFST 0 -/* qid */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_QID_OFST 4 -/* flags */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_FLAGS_OFST 8 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_PE_DELTA_LBN 4 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_PE_DELTA_WIDTH 4 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_MTU_LBN 8 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_MTU_WIDTH 14 - -/* MC_CMD_RMON_MC_ADD_QID_TO_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_RMON_ALLOC_CLASS - * Allocate an rmon class - */ -#define MC_CMD_RMON_ALLOC_CLASS 0xca - -/* MC_CMD_RMON_ALLOC_CLASS_IN msgrequest */ -#define MC_CMD_RMON_ALLOC_CLASS_IN_LEN 0 - -/* MC_CMD_RMON_ALLOC_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_ALLOC_CLASS_OUT_LEN 4 -/* class */ -#define MC_CMD_RMON_ALLOC_CLASS_OUT_CLASS_OFST 0 - - -/***********************************/ -/* MC_CMD_RMON_DEALLOC_CLASS - * Deallocate an rmon class - */ -#define MC_CMD_RMON_DEALLOC_CLASS 0xcb - -/* MC_CMD_RMON_DEALLOC_CLASS_IN msgrequest */ -#define MC_CMD_RMON_DEALLOC_CLASS_IN_LEN 4 -/* class */ -#define MC_CMD_RMON_DEALLOC_CLASS_IN_CLASS_OFST 0 - -/* MC_CMD_RMON_DEALLOC_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_DEALLOC_CLASS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_RMON_ALLOC_SUPER_CLASS - * Allocate an rmon super_class - */ -#define MC_CMD_RMON_ALLOC_SUPER_CLASS 0xcc - -/* MC_CMD_RMON_ALLOC_SUPER_CLASS_IN msgrequest */ -#define MC_CMD_RMON_ALLOC_SUPER_CLASS_IN_LEN 0 - -/* MC_CMD_RMON_ALLOC_SUPER_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_ALLOC_SUPER_CLASS_OUT_LEN 4 -/* super_class */ -#define MC_CMD_RMON_ALLOC_SUPER_CLASS_OUT_SUPER_CLASS_OFST 0 - - -/***********************************/ -/* MC_CMD_RMON_DEALLOC_SUPER_CLASS - * Deallocate an rmon tx super_class - */ -#define MC_CMD_RMON_DEALLOC_SUPER_CLASS 0xcd - -/* MC_CMD_RMON_DEALLOC_SUPER_CLASS_IN msgrequest */ -#define MC_CMD_RMON_DEALLOC_SUPER_CLASS_IN_LEN 4 -/* super_class */ -#define MC_CMD_RMON_DEALLOC_SUPER_CLASS_IN_SUPER_CLASS_OFST 0 - -/* MC_CMD_RMON_DEALLOC_SUPER_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_DEALLOC_SUPER_CLASS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_RMON_RX_UP_CONV_STATS - * Retrieve up converter statistics - */ -#define MC_CMD_RMON_RX_UP_CONV_STATS 0xce - -/* MC_CMD_RMON_RX_UP_CONV_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_PORT_LBN 0 -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_PORT_WIDTH 2 -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_RST_LBN 2 -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_UP_CONV_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_IPI_STATS - * Retrieve rx ipi stats - */ -#define MC_CMD_RMON_RX_IPI_STATS 0xcf - -/* MC_CMD_RMON_RX_IPI_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_IPI_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_IPI_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_IPI_STATS_IN_VFIFO_LBN 0 -#define MC_CMD_RMON_RX_IPI_STATS_IN_VFIFO_WIDTH 5 -#define MC_CMD_RMON_RX_IPI_STATS_IN_RST_LBN 5 -#define MC_CMD_RMON_RX_IPI_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_IPI_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_IPI_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_IPI_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_IPI_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_IPI_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_IPI_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_IPI_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_IPI_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS - * Retrieve rx ipsec cntxt_ptr indexed stats - */ -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS 0xd0 - -/* MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_CNTXT_PTR_LBN 0 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_CNTXT_PTR_WIDTH 9 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_RST_LBN 9 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_IPSEC_PORT_STATS - * Retrieve rx ipsec port indexed stats - */ -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS 0xd1 - -/* MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_PORT_LBN 0 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_PORT_WIDTH 2 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_RST_LBN 2 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_IPSEC_OFLOW_STATS - * Retrieve tx ipsec overflow - */ -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS 0xd2 - -/* MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_PORT_LBN 0 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_PORT_WIDTH 2 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_RST_LBN 2 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_VPORT_ADD_MAC_ADDRESS - * Add a MAC address to a v-port - */ -#define MC_CMD_VPORT_ADD_MAC_ADDRESS 0xa8 - -#define MC_CMD_0xa8_PRIVILEGE_CTG SRIOV_CTG_GENERAL - -/* MC_CMD_VPORT_ADD_MAC_ADDRESS_IN msgrequest */ -#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN 10 -/* The handle of the v-port */ -#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID_OFST 0 -/* MAC address to add */ -#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_MACADDR_OFST 4 -#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_MACADDR_LEN 6 - -/* MC_CMD_VPORT_ADD_MAC_ADDRESS_OUT msgresponse */ -#define MC_CMD_VPORT_ADD_MAC_ADDRESS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_VPORT_DEL_MAC_ADDRESS - * Delete a MAC address from a v-port - */ -#define MC_CMD_VPORT_DEL_MAC_ADDRESS 0xa9 - -#define MC_CMD_0xa9_PRIVILEGE_CTG SRIOV_CTG_GENERAL +#define MC_CMD_0xa9_PRIVILEGE_CTG SRIOV_CTG_GENERAL /* MC_CMD_VPORT_DEL_MAC_ADDRESS_IN msgrequest */ #define MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN 10 @@ -6877,7 +8176,7 @@ #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_LENMIN 12 #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_LENMAX 252 #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_LEN(num) (0+12*(num)) -/* Raw buffer table entries, laid out as BUFTBL_ENTRY. */ +/* Raw buffer table entries, layed out as BUFTBL_ENTRY. */ #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_ENTRY_OFST 0 #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_ENTRY_LEN 12 #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_ENTRY_MINNUM 1 @@ -6920,354 +8219,6 @@ #define MC_CMD_GET_RXDP_CONFIG_OUT_PAD_HOST_DMA_WIDTH 1 -/***********************************/ -/* MC_CMD_RMON_RX_CLASS_DROPS_STATS - * Retrieve rx class drop stats - */ -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS 0xd3 - -/* MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS - * Retrieve rx super class drop stats - */ -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS 0xd4 - -/* MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_RST_LBN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_ERRORS_STATS - * Retrieve rxdp errors - */ -#define MC_CMD_RMON_RX_ERRORS_STATS 0xd5 - -/* MC_CMD_RMON_RX_ERRORS_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_QID_LBN 0 -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_QID_WIDTH 11 -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_RST_LBN 11 -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_ERRORS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_OVERFLOW_STATS - * Retrieve rxdp overflow - */ -#define MC_CMD_RMON_RX_OVERFLOW_STATS 0xd6 - -/* MC_CMD_RMON_RX_OVERFLOW_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_OVERFLOW_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_IPI_STATS - * Retrieve tx ipi stats - */ -#define MC_CMD_RMON_TX_IPI_STATS 0xd7 - -/* MC_CMD_RMON_TX_IPI_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_IPI_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_IPI_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_IPI_STATS_IN_VFIFO_LBN 0 -#define MC_CMD_RMON_TX_IPI_STATS_IN_VFIFO_WIDTH 5 -#define MC_CMD_RMON_TX_IPI_STATS_IN_RST_LBN 5 -#define MC_CMD_RMON_TX_IPI_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_IPI_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_IPI_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_IPI_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_IPI_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_IPI_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_IPI_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_IPI_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_IPI_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS - * Retrieve tx ipsec counters by cntxt_ptr - */ -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS 0xd8 - -/* MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_CNTXT_PTR_LBN 0 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_CNTXT_PTR_WIDTH 9 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_RST_LBN 9 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_IPSEC_PORT_STATS - * Retrieve tx ipsec counters by port - */ -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS 0xd9 - -/* MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_PORT_LBN 0 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_PORT_WIDTH 2 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_RST_LBN 2 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_IPSEC_OFLOW_STATS - * Retrieve tx ipsec overflow - */ -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS 0xda - -/* MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_PORT_LBN 0 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_PORT_WIDTH 2 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_RST_LBN 2 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_NOWHERE_STATS - * Retrieve tx nowhere stats - */ -#define MC_CMD_RMON_TX_NOWHERE_STATS 0xdb - -/* MC_CMD_RMON_TX_NOWHERE_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_NOWHERE_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_NOWHERE_QBB_STATS - * Retrieve tx nowhere qbb stats - */ -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS 0xdc - -/* MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_PRIORITY_LBN 0 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_PRIORITY_WIDTH 3 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_RST_LBN 3 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_ERRORS_STATS - * Retrieve rxdp errors - */ -#define MC_CMD_RMON_TX_ERRORS_STATS 0xdd - -/* MC_CMD_RMON_TX_ERRORS_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_QID_LBN 0 -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_QID_WIDTH 11 -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_RST_LBN 11 -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_ERRORS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_OVERFLOW_STATS - * Retrieve rxdp overflow - */ -#define MC_CMD_RMON_TX_OVERFLOW_STATS 0xde - -/* MC_CMD_RMON_TX_OVERFLOW_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_OVERFLOW_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_COLLECT_CLASS_STATS - * Explicitly collect class stats at the specified evb port - */ -#define MC_CMD_RMON_COLLECT_CLASS_STATS 0xdf - -/* MC_CMD_RMON_COLLECT_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_COLLECT_CLASS_STATS_IN_LEN 4 -/* The port id associated with the vport/pport at which to collect class stats - */ -#define MC_CMD_RMON_COLLECT_CLASS_STATS_IN_PORT_ID_OFST 0 - -/* MC_CMD_RMON_COLLECT_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_COLLECT_CLASS_STATS_OUT_LEN 4 -/* class */ -#define MC_CMD_RMON_COLLECT_CLASS_STATS_OUT_CLASS_OFST 0 - - -/***********************************/ -/* MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS - * Explicitly collect class stats at the specified evb port - */ -#define MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS 0xe0 - -/* MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_IN_LEN 4 -/* The port id associated with the vport/pport at which to collect class stats - */ -#define MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_IN_PORT_ID_OFST 0 - -/* MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_OUT_LEN 4 -/* super_class */ -#define MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_OUT_SUPER_CLASS_OFST 0 - - /***********************************/ /* MC_CMD_GET_CLOCK * Return the system and PDCPU clock frequencies. @@ -7296,22 +8247,66 @@ #define MC_CMD_0xad_PRIVILEGE_CTG SRIOV_CTG_ADMIN /* MC_CMD_SET_CLOCK_IN msgrequest */ -#define MC_CMD_SET_CLOCK_IN_LEN 12 -/* Requested system frequency in MHz; 0 leaves unchanged. */ +#define MC_CMD_SET_CLOCK_IN_LEN 28 +/* Requested frequency in MHz for system clock domain */ #define MC_CMD_SET_CLOCK_IN_SYS_FREQ_OFST 0 -/* Requested inter-core frequency in MHz; 0 leaves unchanged. */ +/* enum: Leave the system clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_SYS_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for inter-core clock domain */ #define MC_CMD_SET_CLOCK_IN_ICORE_FREQ_OFST 4 -/* Request DPCPU frequency in MHz; 0 leaves unchanged. */ +/* enum: Leave the inter-core clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_ICORE_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for DPCPU clock domain */ #define MC_CMD_SET_CLOCK_IN_DPCPU_FREQ_OFST 8 +/* enum: Leave the DPCPU clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_DPCPU_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for PCS clock domain */ +#define MC_CMD_SET_CLOCK_IN_PCS_FREQ_OFST 12 +/* enum: Leave the PCS clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_PCS_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for MC clock domain */ +#define MC_CMD_SET_CLOCK_IN_MC_FREQ_OFST 16 +/* enum: Leave the MC clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_MC_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for rmon clock domain */ +#define MC_CMD_SET_CLOCK_IN_RMON_FREQ_OFST 20 +/* enum: Leave the rmon clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_RMON_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for vswitch clock domain */ +#define MC_CMD_SET_CLOCK_IN_VSWITCH_FREQ_OFST 24 +/* enum: Leave the vswitch clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_VSWITCH_DOMAIN_DONT_CHANGE 0x0 /* MC_CMD_SET_CLOCK_OUT msgresponse */ -#define MC_CMD_SET_CLOCK_OUT_LEN 12 +#define MC_CMD_SET_CLOCK_OUT_LEN 28 /* Resulting system frequency in MHz */ #define MC_CMD_SET_CLOCK_OUT_SYS_FREQ_OFST 0 +/* enum: The system clock domain doesn't exist */ +#define MC_CMD_SET_CLOCK_OUT_SYS_DOMAIN_UNSUPPORTED 0x0 /* Resulting inter-core frequency in MHz */ #define MC_CMD_SET_CLOCK_OUT_ICORE_FREQ_OFST 4 +/* enum: The inter-core clock domain doesn't exist / isn't used */ +#define MC_CMD_SET_CLOCK_OUT_ICORE_DOMAIN_UNSUPPORTED 0x0 /* Resulting DPCPU frequency in MHz */ #define MC_CMD_SET_CLOCK_OUT_DPCPU_FREQ_OFST 8 +/* enum: The dpcpu clock domain doesn't exist */ +#define MC_CMD_SET_CLOCK_OUT_DPCPU_DOMAIN_UNSUPPORTED 0x0 +/* Resulting PCS frequency in MHz */ +#define MC_CMD_SET_CLOCK_OUT_PCS_FREQ_OFST 12 +/* enum: The PCS clock domain doesn't exist / isn't controlled */ +#define MC_CMD_SET_CLOCK_OUT_PCS_DOMAIN_UNSUPPORTED 0x0 +/* Resulting MC frequency in MHz */ +#define MC_CMD_SET_CLOCK_OUT_MC_FREQ_OFST 16 +/* enum: The MC clock domain doesn't exist / isn't controlled */ +#define MC_CMD_SET_CLOCK_OUT_MC_DOMAIN_UNSUPPORTED 0x0 +/* Resulting rmon frequency in MHz */ +#define MC_CMD_SET_CLOCK_OUT_RMON_FREQ_OFST 20 +/* enum: The rmon clock domain doesn't exist / isn't controlled */ +#define MC_CMD_SET_CLOCK_OUT_RMON_DOMAIN_UNSUPPORTED 0x0 +/* Resulting vswitch frequency in MHz */ +#define MC_CMD_SET_CLOCK_OUT_VSWITCH_FREQ_OFST 24 +/* enum: The vswitch clock domain doesn't exist / isn't controlled */ +#define MC_CMD_SET_CLOCK_OUT_VSWITCH_DOMAIN_UNSUPPORTED 0x0 /***********************************/ @@ -7325,12 +8320,22 @@ /* MC_CMD_DPCPU_RPC_IN msgrequest */ #define MC_CMD_DPCPU_RPC_IN_LEN 36 #define MC_CMD_DPCPU_RPC_IN_CPU_OFST 0 -/* enum: RxDPCPU */ -#define MC_CMD_DPCPU_RPC_IN_DPCPU_RX 0x0 +/* enum: RxDPCPU0 */ +#define MC_CMD_DPCPU_RPC_IN_DPCPU_RX0 0x0 /* enum: TxDPCPU0 */ #define MC_CMD_DPCPU_RPC_IN_DPCPU_TX0 0x1 /* enum: TxDPCPU1 */ #define MC_CMD_DPCPU_RPC_IN_DPCPU_TX1 0x2 +/* enum: RxDPCPU1 (Medford only) */ +#define MC_CMD_DPCPU_RPC_IN_DPCPU_RX1 0x3 +/* enum: RxDPCPU (will be for the calling function; for now, just an alias of + * DPCPU_RX0) + */ +#define MC_CMD_DPCPU_RPC_IN_DPCPU_RX 0x80 +/* enum: TxDPCPU (will be for the calling function; for now, just an alias of + * DPCPU_TX0) + */ +#define MC_CMD_DPCPU_RPC_IN_DPCPU_TX 0x81 /* First 8 bits [39:32] of DATA are consumed by MC-DPCPU protocol and must be * initialised to zero */ @@ -7417,6 +8422,25 @@ #define MC_CMD_TRIGGER_INTERRUPT_OUT_LEN 0 +/***********************************/ +/* MC_CMD_SHMBOOT_OP + * Special operations to support (for now) shmboot. + */ +#define MC_CMD_SHMBOOT_OP 0xe6 + +#define MC_CMD_0xe6_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_SHMBOOT_OP_IN msgrequest */ +#define MC_CMD_SHMBOOT_OP_IN_LEN 4 +/* Identifies the operation to perform */ +#define MC_CMD_SHMBOOT_OP_IN_SHMBOOT_OP_OFST 0 +/* enum: Copy slave_data section to the slave core. (Greenport only) */ +#define MC_CMD_SHMBOOT_OP_IN_PUSH_SLAVE_DATA 0x0 + +/* MC_CMD_SHMBOOT_OP_OUT msgresponse */ +#define MC_CMD_SHMBOOT_OP_OUT_LEN 0 + + /***********************************/ /* MC_CMD_CAP_BLK_READ * Read multiple 64bit words from capture block memory @@ -7730,6 +8754,8 @@ * more data is returned. */ #define MC_CMD_KR_TUNE_IN_POLL_EYE_PLOT 0x6 +/* enum: Read Figure Of Merit (eye quality, higher is better). */ +#define MC_CMD_KR_TUNE_IN_READ_FOM 0x7 /* Align the arguments to 32 bits */ #define MC_CMD_KR_TUNE_IN_KR_TUNE_RSVD_OFST 1 #define MC_CMD_KR_TUNE_IN_KR_TUNE_RSVD_LEN 3 @@ -7762,20 +8788,32 @@ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_PARAM_MAXNUM 63 #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_PARAM_ID_LBN 0 #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_PARAM_ID_WIDTH 8 -/* enum: Attenuation (0-15) */ +/* enum: Attenuation (0-15, TBD for Medford) */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_ATT 0x0 -/* enum: CTLE Boost (0-15) */ +/* enum: CTLE Boost (0-15, TBD for Medford) */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_BOOST 0x1 -/* enum: Edge DFE Tap1 (0 - max negative, 64 - zero, 127 - max positive) */ +/* enum: Edge DFE Tap1 (0 - max negative, 64 - zero, 127 - max positive, TBD + * for Medford) + */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_TAP1 0x2 -/* enum: Edge DFE Tap2 (0 - max negative, 32 - zero, 63 - max positive) */ +/* enum: Edge DFE Tap2 (0 - max negative, 32 - zero, 63 - max positive, TBD for + * Medford) + */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_TAP2 0x3 -/* enum: Edge DFE Tap3 (0 - max negative, 32 - zero, 63 - max positive) */ +/* enum: Edge DFE Tap3 (0 - max negative, 32 - zero, 63 - max positive, TBD for + * Medford) + */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_TAP3 0x4 -/* enum: Edge DFE Tap4 (0 - max negative, 32 - zero, 63 - max positive) */ +/* enum: Edge DFE Tap4 (0 - max negative, 32 - zero, 63 - max positive, TBD for + * Medford) + */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_TAP4 0x5 -/* enum: Edge DFE Tap5 (0 - max negative, 32 - zero, 63 - max positive) */ +/* enum: Edge DFE Tap5 (0 - max negative, 32 - zero, 63 - max positive, TBD for + * Medford) + */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_TAP5 0x6 +/* enum: Edge DFE DLEV (TBD for Medford) */ +#define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_DLEV 0x7 #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_PARAM_LANE_LBN 8 #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_PARAM_LANE_WIDTH 3 #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_LANE_0 0x0 /* enum */ @@ -7865,6 +8903,8 @@ #define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_PREDRV_DLY 0x7 /* enum: TX Slew Rate Fine control */ #define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_SR_SET 0x8 +/* enum: TX Termination Impedance control */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_RT_SET 0x9 #define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_LANE_LBN 8 #define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_LANE_WIDTH 3 #define MC_CMD_KR_TUNE_TXEQ_GET_OUT_LANE_0 0x0 /* enum */ @@ -7955,6 +8995,20 @@ #define MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_MINNUM 0 #define MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_MAXNUM 126 +/* MC_CMD_KR_TUNE_READ_FOM_IN msgrequest */ +#define MC_CMD_KR_TUNE_READ_FOM_IN_LEN 8 +/* Requested operation */ +#define MC_CMD_KR_TUNE_READ_FOM_IN_KR_TUNE_OP_OFST 0 +#define MC_CMD_KR_TUNE_READ_FOM_IN_KR_TUNE_OP_LEN 1 +/* Align the arguments to 32 bits */ +#define MC_CMD_KR_TUNE_READ_FOM_IN_KR_TUNE_RSVD_OFST 1 +#define MC_CMD_KR_TUNE_READ_FOM_IN_KR_TUNE_RSVD_LEN 3 +#define MC_CMD_KR_TUNE_READ_FOM_IN_LANE_OFST 4 + +/* MC_CMD_KR_TUNE_READ_FOM_OUT msgresponse */ +#define MC_CMD_KR_TUNE_READ_FOM_OUT_LEN 4 +#define MC_CMD_KR_TUNE_READ_FOM_OUT_FOM_OFST 0 + /***********************************/ /* MC_CMD_PCIE_TUNE @@ -8224,6 +9278,8 @@ #define MC_CMD_LICENSED_APP_OP_IN_OP_OFST 4 /* enum: validate application */ #define MC_CMD_LICENSED_APP_OP_IN_OP_VALIDATE 0x0 +/* enum: mask application */ +#define MC_CMD_LICENSED_APP_OP_IN_OP_MASK 0x1 /* arguments specific to this particular operation */ #define MC_CMD_LICENSED_APP_OP_IN_ARGS_OFST 8 #define MC_CMD_LICENSED_APP_OP_IN_ARGS_LEN 4 @@ -8258,10 +9314,22 @@ #define MC_CMD_LICENSED_APP_OP_VALIDATE_OUT_RESPONSE_OFST 4 #define MC_CMD_LICENSED_APP_OP_VALIDATE_OUT_RESPONSE_LEN 64 +/* MC_CMD_LICENSED_APP_OP_MASK_IN msgrequest */ +#define MC_CMD_LICENSED_APP_OP_MASK_IN_LEN 12 +/* application ID */ +#define MC_CMD_LICENSED_APP_OP_MASK_IN_APP_ID_OFST 0 +/* the type of operation requested */ +#define MC_CMD_LICENSED_APP_OP_MASK_IN_OP_OFST 4 +/* flag */ +#define MC_CMD_LICENSED_APP_OP_MASK_IN_FLAG_OFST 8 + +/* MC_CMD_LICENSED_APP_OP_MASK_OUT msgresponse */ +#define MC_CMD_LICENSED_APP_OP_MASK_OUT_LEN 0 + /***********************************/ /* MC_CMD_SET_PORT_SNIFF_CONFIG - * Configure port sniffing for the physical port associated with the calling + * Configure RX port sniffing for the physical port associated with the calling * function. Only a privileged function may change the port sniffing * configuration. A copy of all traffic delivered to the host (non-promiscuous * mode) or all traffic arriving at the port (promiscuous mode) may be @@ -8299,7 +9367,7 @@ /***********************************/ /* MC_CMD_GET_PORT_SNIFF_CONFIG - * Obtain the current port sniffing configuration for the physical port + * Obtain the current RX port sniffing configuration for the physical port * associated with the calling function. Only a privileged function may read * the configuration. */ @@ -8330,4 +9398,673 @@ #define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_RX_CONTEXT_OFST 12 +/***********************************/ +/* MC_CMD_SET_PARSER_DISP_CONFIG + * Change configuration related to the parser-dispatcher subsystem. + */ +#define MC_CMD_SET_PARSER_DISP_CONFIG 0xf9 + +#define MC_CMD_0xf9_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_SET_PARSER_DISP_CONFIG_IN msgrequest */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_LENMIN 12 +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_LENMAX 252 +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_LEN(num) (8+4*(num)) +/* the type of configuration setting to change */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_TYPE_OFST 0 +/* enum: Per-TXQ enable for multicast UDP destination lookup for possible + * internal loopback. (ENTITY is a queue handle, VALUE is a single boolean.) + */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_TXQ_MCAST_UDP_DST_LOOKUP_EN 0x0 +/* enum: Per-v-adaptor enable for suppression of self-transmissions on the + * internal loopback path. (ENTITY is an EVB_PORT_ID, VALUE is a single + * boolean.) + */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_VADAPTOR_SUPPRESS_SELF_TX 0x1 +/* handle for the entity to update: queue handle, EVB port ID, etc. depending + * on the type of configuration setting being changed + */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_ENTITY_OFST 4 +/* new value: the details depend on the type of configuration setting being + * changed + */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_VALUE_OFST 8 +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_VALUE_LEN 4 +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_VALUE_MINNUM 1 +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_VALUE_MAXNUM 61 + +/* MC_CMD_SET_PARSER_DISP_CONFIG_OUT msgresponse */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_GET_PARSER_DISP_CONFIG + * Read configuration related to the parser-dispatcher subsystem. + */ +#define MC_CMD_GET_PARSER_DISP_CONFIG 0xfa + +#define MC_CMD_0xfa_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_GET_PARSER_DISP_CONFIG_IN msgrequest */ +#define MC_CMD_GET_PARSER_DISP_CONFIG_IN_LEN 8 +/* the type of configuration setting to read */ +#define MC_CMD_GET_PARSER_DISP_CONFIG_IN_TYPE_OFST 0 +/* Enum values, see field(s): */ +/* MC_CMD_SET_PARSER_DISP_CONFIG/MC_CMD_SET_PARSER_DISP_CONFIG_IN/TYPE */ +/* handle for the entity to query: queue handle, EVB port ID, etc. depending on + * the type of configuration setting being read + */ +#define MC_CMD_GET_PARSER_DISP_CONFIG_IN_ENTITY_OFST 4 + +/* MC_CMD_GET_PARSER_DISP_CONFIG_OUT msgresponse */ +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_LENMIN 4 +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_LENMAX 252 +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_LEN(num) (0+4*(num)) +/* current value: the details depend on the type of configuration setting being + * read + */ +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_VALUE_OFST 0 +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_VALUE_LEN 4 +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_VALUE_MINNUM 1 +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_VALUE_MAXNUM 63 + + +/***********************************/ +/* MC_CMD_SET_TX_PORT_SNIFF_CONFIG + * Configure TX port sniffing for the physical port associated with the calling + * function. Only a privileged function may change the port sniffing + * configuration. A copy of all traffic transmitted through the port may be + * delivered to a specific queue, or a set of queues with RSS. Note that these + * packets are delivered with transmit timestamps in the packet prefix, not + * receive timestamps, so it is likely that the queue(s) will need to be + * dedicated as TX sniff receivers. + */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG 0xfb + +#define MC_CMD_0xfb_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN msgrequest */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_LEN 16 +/* configuration flags */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_FLAGS_OFST 0 +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_ENABLE_LBN 0 +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_ENABLE_WIDTH 1 +/* receive queue handle (for RSS mode, this is the base queue) */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_RX_QUEUE_OFST 4 +/* receive mode */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_RX_MODE_OFST 8 +/* enum: receive to just the specified queue */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_RX_MODE_SIMPLE 0x0 +/* enum: receive to multiple queues using RSS context */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_RX_MODE_RSS 0x1 +/* RSS context (for RX_MODE_RSS) as returned by MC_CMD_RSS_CONTEXT_ALLOC. Note + * that these handles should be considered opaque to the host, although a value + * of 0xFFFFFFFF is guaranteed never to be a valid handle. + */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_RX_CONTEXT_OFST 12 + +/* MC_CMD_SET_TX_PORT_SNIFF_CONFIG_OUT msgresponse */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_GET_TX_PORT_SNIFF_CONFIG + * Obtain the current TX port sniffing configuration for the physical port + * associated with the calling function. Only a privileged function may read + * the configuration. + */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG 0xfc + +#define MC_CMD_0xfc_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_GET_TX_PORT_SNIFF_CONFIG_IN msgrequest */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_IN_LEN 0 + +/* MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT msgresponse */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_LEN 16 +/* configuration flags */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_FLAGS_OFST 0 +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_ENABLE_LBN 0 +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_ENABLE_WIDTH 1 +/* receiving queue handle (for RSS mode, this is the base queue) */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_RX_QUEUE_OFST 4 +/* receive mode */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_RX_MODE_OFST 8 +/* enum: receiving to just the specified queue */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_RX_MODE_SIMPLE 0x0 +/* enum: receiving to multiple queues using RSS context */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_RX_MODE_RSS 0x1 +/* RSS context (for RX_MODE_RSS) */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_RX_CONTEXT_OFST 12 + + +/***********************************/ +/* MC_CMD_RMON_STATS_RX_ERRORS + * Per queue rx error stats. + */ +#define MC_CMD_RMON_STATS_RX_ERRORS 0xfe + +#define MC_CMD_0xfe_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_RMON_STATS_RX_ERRORS_IN msgrequest */ +#define MC_CMD_RMON_STATS_RX_ERRORS_IN_LEN 8 +/* The rx queue to get stats for. */ +#define MC_CMD_RMON_STATS_RX_ERRORS_IN_RX_QUEUE_OFST 0 +#define MC_CMD_RMON_STATS_RX_ERRORS_IN_FLAGS_OFST 4 +#define MC_CMD_RMON_STATS_RX_ERRORS_IN_RST_LBN 0 +#define MC_CMD_RMON_STATS_RX_ERRORS_IN_RST_WIDTH 1 + +/* MC_CMD_RMON_STATS_RX_ERRORS_OUT msgresponse */ +#define MC_CMD_RMON_STATS_RX_ERRORS_OUT_LEN 16 +#define MC_CMD_RMON_STATS_RX_ERRORS_OUT_CRC_ERRORS_OFST 0 +#define MC_CMD_RMON_STATS_RX_ERRORS_OUT_TRUNC_ERRORS_OFST 4 +#define MC_CMD_RMON_STATS_RX_ERRORS_OUT_RX_NO_DESC_DROPS_OFST 8 +#define MC_CMD_RMON_STATS_RX_ERRORS_OUT_RX_ABORT_OFST 12 + + +/***********************************/ +/* MC_CMD_GET_PCIE_RESOURCE_INFO + * Find out about available PCIE resources + */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO 0xfd + +/* MC_CMD_GET_PCIE_RESOURCE_INFO_IN msgrequest */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_IN_LEN 0 + +/* MC_CMD_GET_PCIE_RESOURCE_INFO_OUT msgresponse */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_LEN 28 +/* The maximum number of PFs the device can expose */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_MAX_PFS_OFST 0 +/* The maximum number of VFs the device can expose in total */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_MAX_VFS_OFST 4 +/* The maximum number of MSI-X vectors the device can provide in total */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_MAX_VECTORS_OFST 8 +/* the number of MSI-X vectors the device will allocate by default to each PF + */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_DEFAULT_PF_VECTORS_OFST 12 +/* the number of MSI-X vectors the device will allocate by default to each VF + */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_DEFAULT_VF_VECTORS_OFST 16 +/* the maximum number of MSI-X vectors the device can allocate to any one PF */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_MAX_PF_VECTORS_OFST 20 +/* the maximum number of MSI-X vectors the device can allocate to any one VF */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_MAX_VF_VECTORS_OFST 24 + + +/***********************************/ +/* MC_CMD_GET_PORT_MODES + * Find out about available port modes + */ +#define MC_CMD_GET_PORT_MODES 0xff + +#define MC_CMD_0xff_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_GET_PORT_MODES_IN msgrequest */ +#define MC_CMD_GET_PORT_MODES_IN_LEN 0 + +/* MC_CMD_GET_PORT_MODES_OUT msgresponse */ +#define MC_CMD_GET_PORT_MODES_OUT_LEN 12 +/* Bitmask of port modes available on the board (indexed by TLV_PORT_MODE_*) */ +#define MC_CMD_GET_PORT_MODES_OUT_MODES_OFST 0 +/* Default (canonical) board mode */ +#define MC_CMD_GET_PORT_MODES_OUT_DEFAULT_MODE_OFST 4 +/* Current board mode */ +#define MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST 8 + + +/***********************************/ +/* MC_CMD_READ_ATB + * Sample voltages on the ATB + */ +#define MC_CMD_READ_ATB 0x100 + +#define MC_CMD_0x100_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_READ_ATB_IN msgrequest */ +#define MC_CMD_READ_ATB_IN_LEN 16 +#define MC_CMD_READ_ATB_IN_SIGNAL_BUS_OFST 0 +#define MC_CMD_READ_ATB_IN_BUS_CCOM 0x0 /* enum */ +#define MC_CMD_READ_ATB_IN_BUS_CKR 0x1 /* enum */ +#define MC_CMD_READ_ATB_IN_BUS_CPCIE 0x8 /* enum */ +#define MC_CMD_READ_ATB_IN_SIGNAL_EN_BITNO_OFST 4 +#define MC_CMD_READ_ATB_IN_SIGNAL_SEL_OFST 8 +#define MC_CMD_READ_ATB_IN_SETTLING_TIME_US_OFST 12 + +/* MC_CMD_READ_ATB_OUT msgresponse */ +#define MC_CMD_READ_ATB_OUT_LEN 4 +#define MC_CMD_READ_ATB_OUT_SAMPLE_MV_OFST 0 + + +/***********************************/ +/* MC_CMD_GET_WORKAROUNDS + * Read the list of all implemented and all currently enabled workarounds. The + * enums here must correspond with those in MC_CMD_WORKAROUND. + */ +#define MC_CMD_GET_WORKAROUNDS 0x59 + +#define MC_CMD_0x59_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_GET_WORKAROUNDS_OUT msgresponse */ +#define MC_CMD_GET_WORKAROUNDS_OUT_LEN 8 +/* Each workaround is represented by a single bit according to the enums below. + */ +#define MC_CMD_GET_WORKAROUNDS_OUT_IMPLEMENTED_OFST 0 +#define MC_CMD_GET_WORKAROUNDS_OUT_ENABLED_OFST 4 +/* enum: Bug 17230 work around. */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG17230 0x2 +/* enum: Bug 35388 work around (unsafe EVQ writes). */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35388 0x4 +/* enum: Bug35017 workaround (A64 tables must be identity map) */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35017 0x8 +/* enum: Bug 41750 present (MC_CMD_TRIGGER_INTERRUPT won't work) */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG41750 0x10 +/* enum: Bug 42008 present (Interrupts can overtake associated events). Caution + * - before adding code that queries this workaround, remember that there's + * released Monza firmware that doesn't understand MC_CMD_WORKAROUND_BUG42008, + * and will hence (incorrectly) report that the bug doesn't exist. + */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG42008 0x20 +/* enum: Bug 26807 features present in firmware (multicast filter chaining) */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 0x40 + + +/***********************************/ +/* MC_CMD_PRIVILEGE_MASK + * Read/set privileges of an arbitrary PCIe function + */ +#define MC_CMD_PRIVILEGE_MASK 0x5a + +#define MC_CMD_0x5a_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_PRIVILEGE_MASK_IN msgrequest */ +#define MC_CMD_PRIVILEGE_MASK_IN_LEN 8 +/* The target function to have its mask read or set e.g. PF 0 = 0xFFFF0000, VF + * 1,3 = 0x00030001 + */ +#define MC_CMD_PRIVILEGE_MASK_IN_FUNCTION_OFST 0 +#define MC_CMD_PRIVILEGE_MASK_IN_FUNCTION_PF_LBN 0 +#define MC_CMD_PRIVILEGE_MASK_IN_FUNCTION_PF_WIDTH 16 +#define MC_CMD_PRIVILEGE_MASK_IN_FUNCTION_VF_LBN 16 +#define MC_CMD_PRIVILEGE_MASK_IN_FUNCTION_VF_WIDTH 16 +#define MC_CMD_PRIVILEGE_MASK_IN_VF_NULL 0xffff /* enum */ +/* New privilege mask to be set. The mask will only be changed if the MSB is + * set to 1. + */ +#define MC_CMD_PRIVILEGE_MASK_IN_NEW_MASK_OFST 4 +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN 0x1 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_LINK 0x2 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_ONLOAD 0x4 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_PTP 0x8 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_INSECURE_FILTERS 0x10 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING 0x20 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_UNICAST 0x40 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_MULTICAST 0x80 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_BROADCAST 0x100 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_ALL_MULTICAST 0x200 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_PROMISCUOUS 0x400 /* enum */ +/* enum: Set this bit to indicate that a new privilege mask is to be set, + * otherwise the command will only read the existing mask. + */ +#define MC_CMD_PRIVILEGE_MASK_IN_DO_CHANGE 0x80000000 + +/* MC_CMD_PRIVILEGE_MASK_OUT msgresponse */ +#define MC_CMD_PRIVILEGE_MASK_OUT_LEN 4 +/* For an admin function, always all the privileges are reported. */ +#define MC_CMD_PRIVILEGE_MASK_OUT_OLD_MASK_OFST 0 + + +/***********************************/ +/* MC_CMD_LINK_STATE_MODE + * Read/set link state mode of a VF + */ +#define MC_CMD_LINK_STATE_MODE 0x5c + +#define MC_CMD_0x5c_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_LINK_STATE_MODE_IN msgrequest */ +#define MC_CMD_LINK_STATE_MODE_IN_LEN 8 +/* The target function to have its link state mode read or set, must be a VF + * e.g. VF 1,3 = 0x00030001 + */ +#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_OFST 0 +#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_PF_LBN 0 +#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_PF_WIDTH 16 +#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_VF_LBN 16 +#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_VF_WIDTH 16 +/* New link state mode to be set */ +#define MC_CMD_LINK_STATE_MODE_IN_NEW_MODE_OFST 4 +#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_AUTO 0x0 /* enum */ +#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_UP 0x1 /* enum */ +#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_DOWN 0x2 /* enum */ +/* enum: Use this value to just read the existing setting without modifying it. + */ +#define MC_CMD_LINK_STATE_MODE_IN_DO_NOT_CHANGE 0xffffffff + +/* MC_CMD_LINK_STATE_MODE_OUT msgresponse */ +#define MC_CMD_LINK_STATE_MODE_OUT_LEN 4 +#define MC_CMD_LINK_STATE_MODE_OUT_OLD_MODE_OFST 0 + + +/***********************************/ +/* MC_CMD_GET_SNAPSHOT_LENGTH + * Obtain the curent range of allowable values for the SNAPSHOT_LENGTH + * parameter to MC_CMD_INIT_RXQ. + */ +#define MC_CMD_GET_SNAPSHOT_LENGTH 0x101 + +#define MC_CMD_0x101_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_GET_SNAPSHOT_LENGTH_IN msgrequest */ +#define MC_CMD_GET_SNAPSHOT_LENGTH_IN_LEN 0 + +/* MC_CMD_GET_SNAPSHOT_LENGTH_OUT msgresponse */ +#define MC_CMD_GET_SNAPSHOT_LENGTH_OUT_LEN 8 +/* Minimum acceptable snapshot length. */ +#define MC_CMD_GET_SNAPSHOT_LENGTH_OUT_RX_SNAPLEN_MIN_OFST 0 +/* Maximum acceptable snapshot length. */ +#define MC_CMD_GET_SNAPSHOT_LENGTH_OUT_RX_SNAPLEN_MAX_OFST 4 + + +/***********************************/ +/* MC_CMD_FUSE_DIAGS + * Additional fuse diagnostics + */ +#define MC_CMD_FUSE_DIAGS 0x102 + +#define MC_CMD_0x102_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_FUSE_DIAGS_IN msgrequest */ +#define MC_CMD_FUSE_DIAGS_IN_LEN 0 + +/* MC_CMD_FUSE_DIAGS_OUT msgresponse */ +#define MC_CMD_FUSE_DIAGS_OUT_LEN 48 +/* Total number of mismatched bits between pairs in area 0 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA0_MISMATCH_BITS_OFST 0 +/* Total number of unexpectedly clear (set in B but not A) bits in area 0 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA0_PAIR_A_BAD_BITS_OFST 4 +/* Total number of unexpectedly clear (set in A but not B) bits in area 0 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA0_PAIR_B_BAD_BITS_OFST 8 +/* Checksum of data after logical OR of pairs in area 0 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA0_CHECKSUM_OFST 12 +/* Total number of mismatched bits between pairs in area 1 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA1_MISMATCH_BITS_OFST 16 +/* Total number of unexpectedly clear (set in B but not A) bits in area 1 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA1_PAIR_A_BAD_BITS_OFST 20 +/* Total number of unexpectedly clear (set in A but not B) bits in area 1 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA1_PAIR_B_BAD_BITS_OFST 24 +/* Checksum of data after logical OR of pairs in area 1 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA1_CHECKSUM_OFST 28 +/* Total number of mismatched bits between pairs in area 2 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA2_MISMATCH_BITS_OFST 32 +/* Total number of unexpectedly clear (set in B but not A) bits in area 2 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA2_PAIR_A_BAD_BITS_OFST 36 +/* Total number of unexpectedly clear (set in A but not B) bits in area 2 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA2_PAIR_B_BAD_BITS_OFST 40 +/* Checksum of data after logical OR of pairs in area 2 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA2_CHECKSUM_OFST 44 + + +/***********************************/ +/* MC_CMD_PRIVILEGE_MODIFY + * Modify the privileges of a set of PCIe functions. Note that this operation + * only effects non-admin functions unless the admin privilege itself is + * included in one of the masks provided. + */ +#define MC_CMD_PRIVILEGE_MODIFY 0x60 + +#define MC_CMD_0x60_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_PRIVILEGE_MODIFY_IN msgrequest */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_LEN 16 +/* The groups of functions to have their privilege masks modified. */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_FN_GROUP_OFST 0 +#define MC_CMD_PRIVILEGE_MODIFY_IN_NONE 0x0 /* enum */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_ALL 0x1 /* enum */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_PFS_ONLY 0x2 /* enum */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_VFS_ONLY 0x3 /* enum */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_VFS_OF_PF 0x4 /* enum */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_ONE 0x5 /* enum */ +/* For VFS_OF_PF specify the PF, for ONE specify the target function */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_FUNCTION_OFST 4 +#define MC_CMD_PRIVILEGE_MODIFY_IN_FUNCTION_PF_LBN 0 +#define MC_CMD_PRIVILEGE_MODIFY_IN_FUNCTION_PF_WIDTH 16 +#define MC_CMD_PRIVILEGE_MODIFY_IN_FUNCTION_VF_LBN 16 +#define MC_CMD_PRIVILEGE_MODIFY_IN_FUNCTION_VF_WIDTH 16 +/* Privileges to be added to the target functions. For privilege definitions + * refer to the command MC_CMD_PRIVILEGE_MASK + */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_ADD_MASK_OFST 8 +/* Privileges to be removed from the target functions. For privilege + * definitions refer to the command MC_CMD_PRIVILEGE_MASK + */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_REMOVE_MASK_OFST 12 + +/* MC_CMD_PRIVILEGE_MODIFY_OUT msgresponse */ +#define MC_CMD_PRIVILEGE_MODIFY_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_XPM_READ_BYTES + * Read XPM memory + */ +#define MC_CMD_XPM_READ_BYTES 0x103 + +#define MC_CMD_0x103_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_READ_BYTES_IN msgrequest */ +#define MC_CMD_XPM_READ_BYTES_IN_LEN 8 +/* Start address (byte) */ +#define MC_CMD_XPM_READ_BYTES_IN_ADDR_OFST 0 +/* Count (bytes) */ +#define MC_CMD_XPM_READ_BYTES_IN_COUNT_OFST 4 + +/* MC_CMD_XPM_READ_BYTES_OUT msgresponse */ +#define MC_CMD_XPM_READ_BYTES_OUT_LENMIN 0 +#define MC_CMD_XPM_READ_BYTES_OUT_LENMAX 252 +#define MC_CMD_XPM_READ_BYTES_OUT_LEN(num) (0+1*(num)) +/* Data */ +#define MC_CMD_XPM_READ_BYTES_OUT_DATA_OFST 0 +#define MC_CMD_XPM_READ_BYTES_OUT_DATA_LEN 1 +#define MC_CMD_XPM_READ_BYTES_OUT_DATA_MINNUM 0 +#define MC_CMD_XPM_READ_BYTES_OUT_DATA_MAXNUM 252 + + +/***********************************/ +/* MC_CMD_XPM_WRITE_BYTES + * Write XPM memory + */ +#define MC_CMD_XPM_WRITE_BYTES 0x104 + +#define MC_CMD_0x104_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_WRITE_BYTES_IN msgrequest */ +#define MC_CMD_XPM_WRITE_BYTES_IN_LENMIN 8 +#define MC_CMD_XPM_WRITE_BYTES_IN_LENMAX 252 +#define MC_CMD_XPM_WRITE_BYTES_IN_LEN(num) (8+1*(num)) +/* Start address (byte) */ +#define MC_CMD_XPM_WRITE_BYTES_IN_ADDR_OFST 0 +/* Count (bytes) */ +#define MC_CMD_XPM_WRITE_BYTES_IN_COUNT_OFST 4 +/* Data */ +#define MC_CMD_XPM_WRITE_BYTES_IN_DATA_OFST 8 +#define MC_CMD_XPM_WRITE_BYTES_IN_DATA_LEN 1 +#define MC_CMD_XPM_WRITE_BYTES_IN_DATA_MINNUM 0 +#define MC_CMD_XPM_WRITE_BYTES_IN_DATA_MAXNUM 244 + +/* MC_CMD_XPM_WRITE_BYTES_OUT msgresponse */ +#define MC_CMD_XPM_WRITE_BYTES_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_XPM_READ_SECTOR + * Read XPM sector + */ +#define MC_CMD_XPM_READ_SECTOR 0x105 + +#define MC_CMD_0x105_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_READ_SECTOR_IN msgrequest */ +#define MC_CMD_XPM_READ_SECTOR_IN_LEN 8 +/* Sector index */ +#define MC_CMD_XPM_READ_SECTOR_IN_INDEX_OFST 0 +/* Sector size */ +#define MC_CMD_XPM_READ_SECTOR_IN_SIZE_OFST 4 + +/* MC_CMD_XPM_READ_SECTOR_OUT msgresponse */ +#define MC_CMD_XPM_READ_SECTOR_OUT_LENMIN 4 +#define MC_CMD_XPM_READ_SECTOR_OUT_LENMAX 36 +#define MC_CMD_XPM_READ_SECTOR_OUT_LEN(num) (4+1*(num)) +/* Sector type */ +#define MC_CMD_XPM_READ_SECTOR_OUT_TYPE_OFST 0 +#define MC_CMD_XPM_READ_SECTOR_OUT_BLANK 0x0 /* enum */ +#define MC_CMD_XPM_READ_SECTOR_OUT_CRYPTO_KEY_128 0x1 /* enum */ +#define MC_CMD_XPM_READ_SECTOR_OUT_CRYPTO_KEY_256 0x2 /* enum */ +#define MC_CMD_XPM_READ_SECTOR_OUT_INVALID 0xff /* enum */ +/* Sector data */ +#define MC_CMD_XPM_READ_SECTOR_OUT_DATA_OFST 4 +#define MC_CMD_XPM_READ_SECTOR_OUT_DATA_LEN 1 +#define MC_CMD_XPM_READ_SECTOR_OUT_DATA_MINNUM 0 +#define MC_CMD_XPM_READ_SECTOR_OUT_DATA_MAXNUM 32 + + +/***********************************/ +/* MC_CMD_XPM_WRITE_SECTOR + * Write XPM sector + */ +#define MC_CMD_XPM_WRITE_SECTOR 0x106 + +#define MC_CMD_0x106_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_WRITE_SECTOR_IN msgrequest */ +#define MC_CMD_XPM_WRITE_SECTOR_IN_LENMIN 12 +#define MC_CMD_XPM_WRITE_SECTOR_IN_LENMAX 44 +#define MC_CMD_XPM_WRITE_SECTOR_IN_LEN(num) (12+1*(num)) +/* If writing fails due to an uncorrectable error, try up to RETRIES following + * sectors (or until no more space available). If 0, only one write attempt is + * made. Note that uncorrectable errors are unlikely, thanks to XPM self-repair + * mechanism. + */ +#define MC_CMD_XPM_WRITE_SECTOR_IN_RETRIES_OFST 0 +#define MC_CMD_XPM_WRITE_SECTOR_IN_RETRIES_LEN 1 +#define MC_CMD_XPM_WRITE_SECTOR_IN_RESERVED_OFST 1 +#define MC_CMD_XPM_WRITE_SECTOR_IN_RESERVED_LEN 3 +/* Sector type */ +#define MC_CMD_XPM_WRITE_SECTOR_IN_TYPE_OFST 4 +/* Enum values, see field(s): */ +/* MC_CMD_XPM_READ_SECTOR_OUT/TYPE */ +/* Sector size */ +#define MC_CMD_XPM_WRITE_SECTOR_IN_SIZE_OFST 8 +/* Sector data */ +#define MC_CMD_XPM_WRITE_SECTOR_IN_DATA_OFST 12 +#define MC_CMD_XPM_WRITE_SECTOR_IN_DATA_LEN 1 +#define MC_CMD_XPM_WRITE_SECTOR_IN_DATA_MINNUM 0 +#define MC_CMD_XPM_WRITE_SECTOR_IN_DATA_MAXNUM 32 + +/* MC_CMD_XPM_WRITE_SECTOR_OUT msgresponse */ +#define MC_CMD_XPM_WRITE_SECTOR_OUT_LEN 4 +/* New sector index */ +#define MC_CMD_XPM_WRITE_SECTOR_OUT_INDEX_OFST 0 + + +/***********************************/ +/* MC_CMD_XPM_INVALIDATE_SECTOR + * Invalidate XPM sector + */ +#define MC_CMD_XPM_INVALIDATE_SECTOR 0x107 + +#define MC_CMD_0x107_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_INVALIDATE_SECTOR_IN msgrequest */ +#define MC_CMD_XPM_INVALIDATE_SECTOR_IN_LEN 4 +/* Sector index */ +#define MC_CMD_XPM_INVALIDATE_SECTOR_IN_INDEX_OFST 0 + +/* MC_CMD_XPM_INVALIDATE_SECTOR_OUT msgresponse */ +#define MC_CMD_XPM_INVALIDATE_SECTOR_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_XPM_BLANK_CHECK + * Blank-check XPM memory and report bad locations + */ +#define MC_CMD_XPM_BLANK_CHECK 0x108 + +#define MC_CMD_0x108_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_BLANK_CHECK_IN msgrequest */ +#define MC_CMD_XPM_BLANK_CHECK_IN_LEN 8 +/* Start address (byte) */ +#define MC_CMD_XPM_BLANK_CHECK_IN_ADDR_OFST 0 +/* Count (bytes) */ +#define MC_CMD_XPM_BLANK_CHECK_IN_COUNT_OFST 4 + +/* MC_CMD_XPM_BLANK_CHECK_OUT msgresponse */ +#define MC_CMD_XPM_BLANK_CHECK_OUT_LENMIN 4 +#define MC_CMD_XPM_BLANK_CHECK_OUT_LENMAX 252 +#define MC_CMD_XPM_BLANK_CHECK_OUT_LEN(num) (4+2*(num)) +/* Total number of bad (non-blank) locations */ +#define MC_CMD_XPM_BLANK_CHECK_OUT_BAD_COUNT_OFST 0 +/* Addresses of bad locations (may be less than BAD_COUNT, if all cannot fit + * into MCDI response) + */ +#define MC_CMD_XPM_BLANK_CHECK_OUT_BAD_ADDR_OFST 4 +#define MC_CMD_XPM_BLANK_CHECK_OUT_BAD_ADDR_LEN 2 +#define MC_CMD_XPM_BLANK_CHECK_OUT_BAD_ADDR_MINNUM 0 +#define MC_CMD_XPM_BLANK_CHECK_OUT_BAD_ADDR_MAXNUM 124 + + +/***********************************/ +/* MC_CMD_XPM_REPAIR + * Blank-check and repair XPM memory + */ +#define MC_CMD_XPM_REPAIR 0x109 + +#define MC_CMD_0x109_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_REPAIR_IN msgrequest */ +#define MC_CMD_XPM_REPAIR_IN_LEN 8 +/* Start address (byte) */ +#define MC_CMD_XPM_REPAIR_IN_ADDR_OFST 0 +/* Count (bytes) */ +#define MC_CMD_XPM_REPAIR_IN_COUNT_OFST 4 + +/* MC_CMD_XPM_REPAIR_OUT msgresponse */ +#define MC_CMD_XPM_REPAIR_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_XPM_DECODER_TEST + * Test XPM memory address decoders for gross manufacturing defects. Can only + * be performed on an unprogrammed part. + */ +#define MC_CMD_XPM_DECODER_TEST 0x10a + +#define MC_CMD_0x10a_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_DECODER_TEST_IN msgrequest */ +#define MC_CMD_XPM_DECODER_TEST_IN_LEN 0 + +/* MC_CMD_XPM_DECODER_TEST_OUT msgresponse */ +#define MC_CMD_XPM_DECODER_TEST_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_XPM_WRITE_TEST + * XPM memory write test. Test XPM write logic for gross manufacturing defects + * by writing to a dedicated test row. There are 16 locations in the test row + * and the test can only be performed on locations that have not been + * previously used (i.e. can be run at most 16 times). The test will pick the + * first available location to use, or fail with ENOSPC if none left. + */ +#define MC_CMD_XPM_WRITE_TEST 0x10b + +#define MC_CMD_0x10b_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_WRITE_TEST_IN msgrequest */ +#define MC_CMD_XPM_WRITE_TEST_IN_LEN 0 + +/* MC_CMD_XPM_WRITE_TEST_OUT msgresponse */ +#define MC_CMD_XPM_WRITE_TEST_OUT_LEN 0 + + #endif /* MCDI_PCOL_H */ -- cgit v1.3-6-gb490 From 46e612b0fcefb7a3381933135f386523dedb4159 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 21 Jul 2015 15:09:18 +0100 Subject: sfc: enable cascaded multicast filters in MCFW After creating event queue 0, check to see if the workaround is enabled, and enable it if necessary. This will be called during PCI probe and also when coming back up after a reset. The nic_data->workaround_26807 will be used in the future to control the filter insertion behaviour based on this workaround. Only the primary PF can enable this workaround, so tolerate an EPERM error and continue. Otherwise, if any step in the checking and enabling of the workaround fails, the event queue must be removed. We check that workaround is implemented before trying to enable it, and store the current workaround setting before trying to change it. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 63 +++++++++++++++++++++++++++++------------ drivers/net/ethernet/sfc/nic.h | 2 ++ 2 files changed, 47 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 605cc8948594..119301769dda 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -2197,6 +2197,29 @@ static int efx_ef10_ev_probe(struct efx_channel *channel) GFP_KERNEL); } +static void efx_ef10_ev_fini(struct efx_channel *channel) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_FINI_EVQ_IN_LEN); + MCDI_DECLARE_BUF_ERR(outbuf); + struct efx_nic *efx = channel->efx; + size_t outlen; + int rc; + + MCDI_SET_DWORD(inbuf, FINI_EVQ_IN_INSTANCE, channel->channel); + + rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FINI_EVQ, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + + if (rc && rc != -EALREADY) + goto fail; + + return; + +fail: + efx_mcdi_display_error(efx, MC_CMD_FINI_EVQ, MC_CMD_FINI_EVQ_IN_LEN, + outbuf, outlen, rc); +} + static int efx_ef10_ev_init(struct efx_channel *channel) { MCDI_DECLARE_BUF(inbuf, @@ -2208,6 +2231,7 @@ static int efx_ef10_ev_init(struct efx_channel *channel) struct efx_ef10_nic_data *nic_data; bool supports_rx_merge; size_t inlen, outlen; + unsigned int enabled, implemented; dma_addr_t dma_addr; int rc; int i; @@ -2248,30 +2272,33 @@ static int efx_ef10_ev_init(struct efx_channel *channel) rc = efx_mcdi_rpc(efx, MC_CMD_INIT_EVQ, inbuf, inlen, outbuf, sizeof(outbuf), &outlen); /* IRQ return is ignored */ - return rc; -} - -static void efx_ef10_ev_fini(struct efx_channel *channel) -{ - MCDI_DECLARE_BUF(inbuf, MC_CMD_FINI_EVQ_IN_LEN); - MCDI_DECLARE_BUF_ERR(outbuf); - struct efx_nic *efx = channel->efx; - size_t outlen; - int rc; + if (channel->channel || rc) + return rc; - MCDI_SET_DWORD(inbuf, FINI_EVQ_IN_INSTANCE, channel->channel); + /* Successfully created event queue on channel 0 */ + rc = efx_mcdi_get_workarounds(efx, &implemented, &enabled); + if (rc) + goto fail; - rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FINI_EVQ, inbuf, sizeof(inbuf), - outbuf, sizeof(outbuf), &outlen); + nic_data->workaround_26807 = + !!(enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807); - if (rc && rc != -EALREADY) - goto fail; + if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 && + !nic_data->workaround_26807) { + rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG26807, + true); + if (!rc) + nic_data->workaround_26807 = true; + else if (rc == -EPERM) + rc = 0; + } - return; + if (!rc) + return 0; fail: - efx_mcdi_display_error(efx, MC_CMD_FINI_EVQ, MC_CMD_FINI_EVQ_IN_LEN, - outbuf, outlen, rc); + efx_ef10_ev_fini(channel); + return rc; } static void efx_ef10_ev_remove(struct efx_channel *channel) diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 31ff9084d9a4..0b536e27d3b2 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -506,6 +506,7 @@ enum { * @rx_rss_context_exclusive: Whether our RSS context is exclusive or shared * @stats: Hardware statistics * @workaround_35388: Flag: firmware supports workaround for bug 35388 + * @workaround_26807: Flag: firmware supports workaround for bug 26807 * @must_check_datapath_caps: Flag: @datapath_caps needs to be revalidated * after MC reboot * @datapath_caps: Capabilities of datapath firmware (FLAGS1 field of @@ -535,6 +536,7 @@ struct efx_ef10_nic_data { bool rx_rss_context_exclusive; u64 stats[EF10_STAT_COUNT]; bool workaround_35388; + bool workaround_26807; bool must_check_datapath_caps; u32 datapath_caps; unsigned int rx_dpcpu_fw_id; -- cgit v1.3-6-gb490 From 832dc9ed43da8eb2033d90b46c1041e1d6947907 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Tue, 21 Jul 2015 15:09:31 +0100 Subject: sfc: cope with ENOSYS from efx_mcdi_get_workarounds() GET_WORKAROUNDS was only introduced in May 2014, not all firmware will have it. So call sites need to handle ENOSYS. In this case we're probing the bug26807 workaround, which is not implemented in any firmware that doesn't have GET_WORKAROUNDS. So interpret ENOSYS as 'false'. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 33 ++++++++++++++++++++------------- drivers/net/ethernet/sfc/mcdi.c | 6 +++++- 2 files changed, 25 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 119301769dda..44071176859d 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -2277,20 +2277,27 @@ static int efx_ef10_ev_init(struct efx_channel *channel) /* Successfully created event queue on channel 0 */ rc = efx_mcdi_get_workarounds(efx, &implemented, &enabled); - if (rc) + if (rc == -ENOSYS) { + /* GET_WORKAROUNDS was implemented before the bug26807 + * workaround, thus the latter must be unavailable in this fw + */ + nic_data->workaround_26807 = false; + rc = 0; + } else if (rc) { goto fail; - - nic_data->workaround_26807 = - !!(enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807); - - if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 && - !nic_data->workaround_26807) { - rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG26807, - true); - if (!rc) - nic_data->workaround_26807 = true; - else if (rc == -EPERM) - rc = 0; + } else { + nic_data->workaround_26807 = + !!(enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807); + + if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 && + !nic_data->workaround_26807) { + rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG26807, + true); + if (!rc) + nic_data->workaround_26807 = true; + else if (rc == -EPERM) + rc = 0; + } } if (!rc) diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 81640f8bb811..58232e78feaa 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1816,7 +1816,11 @@ int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out, return 0; fail: - netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); + /* Older firmware lacks GET_WORKAROUNDS and this isn't especially + * terrifying. The call site will have to deal with it though. + */ + netif_printk(efx, hw, rc == -ENOSYS ? KERN_DEBUG : KERN_ERR, + efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return rc; } -- cgit v1.3-6-gb490 From 34ccfe6f8abd9ce7ea70e68f130cc6618737269f Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 21 Jul 2015 15:09:43 +0100 Subject: sfc: add output flag decoding to efx_mcdi_set_workaround The initial use of this will be to check a flag reporting if an FLR was performed on other functions when enabling cascaded multicast filters. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 7 ++++--- drivers/net/ethernet/sfc/mcdi.c | 22 +++++++++++++++++++--- drivers/net/ethernet/sfc/mcdi.h | 3 ++- 3 files changed, 25 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 44071176859d..2b93f63a0421 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -387,7 +387,7 @@ static int efx_ef10_probe(struct efx_nic *efx) * First try to enable it, then if we get EPERM, just * ask if it's already enabled */ - rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG35388, true); + rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG35388, true, NULL); if (rc == 0) { nic_data->workaround_35388 = true; } else if (rc == -EPERM) { @@ -2291,8 +2291,9 @@ static int efx_ef10_ev_init(struct efx_channel *channel) if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 && !nic_data->workaround_26807) { - rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG26807, - true); + rc = efx_mcdi_set_workaround(efx, + MC_CMD_WORKAROUND_BUG26807, + true, NULL); if (!rc) nic_data->workaround_26807 = true; else if (rc == -EPERM) diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 58232e78feaa..98d172b04f71 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1779,15 +1779,31 @@ int efx_mcdi_wol_filter_reset(struct efx_nic *efx) return rc; } -int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled) +int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled, + unsigned int *flags) { MCDI_DECLARE_BUF(inbuf, MC_CMD_WORKAROUND_IN_LEN); + MCDI_DECLARE_BUF(outbuf, MC_CMD_WORKAROUND_EXT_OUT_LEN); + size_t outlen; + int rc; BUILD_BUG_ON(MC_CMD_WORKAROUND_OUT_LEN != 0); MCDI_SET_DWORD(inbuf, WORKAROUND_IN_TYPE, type); MCDI_SET_DWORD(inbuf, WORKAROUND_IN_ENABLED, enabled); - return efx_mcdi_rpc(efx, MC_CMD_WORKAROUND, inbuf, sizeof(inbuf), - NULL, 0, NULL); + rc = efx_mcdi_rpc(efx, MC_CMD_WORKAROUND, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (rc) + return rc; + + if (!flags) + return 0; + + if (outlen >= MC_CMD_WORKAROUND_EXT_OUT_LEN) + *flags = MCDI_DWORD(outbuf, WORKAROUND_EXT_OUT_FLAGS); + else + *flags = 0; + + return 0; } int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out, diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h index 1838afe2da92..025d504c472b 100644 --- a/drivers/net/ethernet/sfc/mcdi.h +++ b/drivers/net/ethernet/sfc/mcdi.h @@ -346,7 +346,8 @@ void efx_mcdi_mac_pull_stats(struct efx_nic *efx); bool efx_mcdi_mac_check_fault(struct efx_nic *efx); enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason); int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method); -int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled); +int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled, + unsigned int *flags); int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out, unsigned int *enabled_out); -- cgit v1.3-6-gb490 From 5a55a72abe48e5d6c0ec86e7b06cd73ab7d517c8 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 21 Jul 2015 15:10:02 +0100 Subject: sfc: warn if other functions have been reset by MCFW When enabling the workaround for cascaded multicast filters, the MC can reset other functions if they have already inserted filters. In that case, the workaround has been enabled, but print an info message in the log recording that other functions had to be reset. As other functions were reset, the MC will have incremented its boot count, so also increment the warm_boot_count on the function which enabled the workaround, as that function won't have received an MC reboot event and does not need to reset. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 2b93f63a0421..18d6388fb5da 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -2291,13 +2291,24 @@ static int efx_ef10_ev_init(struct efx_channel *channel) if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 && !nic_data->workaround_26807) { + unsigned int flags; + rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG26807, - true, NULL); - if (!rc) + true, &flags); + + if (!rc) { + if (flags & + 1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN) { + netif_info(efx, drv, efx->net_dev, + "other functions on NIC have been reset\n"); + /* MC's boot count has incremented */ + ++nic_data->warm_boot_count; + } nic_data->workaround_26807 = true; - else if (rc == -EPERM) + } else if (rc == -EPERM) { rc = 0; + } } } -- cgit v1.3-6-gb490 From b6f568e27b6b214beaa0d57ddb4fcc446fcd5555 Mon Sep 17 00:00:00 2001 From: Jon Cooper Date: Tue, 21 Jul 2015 15:10:15 +0100 Subject: sfc: Insert multicast filters as well as mismatch filters in promiscuous mode If a function is in promiscuous mode and another function has a broadcast or multicast filter inserted, the function in promiscuous mode won't see that broadcast or multicast traffic. Most notably this breaks broadcast, which means ARP doesn't work. Less show-stoppingly, a function listening on a multicast address that's also in promiscuous mode will not see that multicast traffic if another function is also listening on that multicast address. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 104 ++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 18d6388fb5da..784b46fb039a 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3758,7 +3758,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) struct netdev_hw_addr *uc; struct netdev_hw_addr *mc; unsigned int filter_idx; - int i, n, rc; + int i, rc; + bool uc_promisc = false, mc_promisc = false; if (!efx_dev_registered(efx)) return; @@ -3768,13 +3769,11 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) /* Mark old filters that may need to be removed */ spin_lock_bh(&efx->filter_lock); - n = table->dev_uc_count < 0 ? 1 : table->dev_uc_count; - for (i = 0; i < n; i++) { + for (i = 0; i < table->dev_uc_count; i++) { filter_idx = table->dev_uc_list[i].id % HUNT_FILTER_TBL_ROWS; table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; } - n = table->dev_mc_count < 0 ? 1 : table->dev_mc_count; - for (i = 0; i < n; i++) { + for (i = 0; i < table->dev_mc_count; i++) { filter_idx = table->dev_mc_list[i].id % HUNT_FILTER_TBL_ROWS; table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; } @@ -3786,7 +3785,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) netif_addr_lock_bh(net_dev); if (net_dev->flags & IFF_PROMISC || netdev_uc_count(net_dev) >= EFX_EF10_FILTER_DEV_UC_MAX) { - table->dev_uc_count = -1; + table->dev_uc_count = 0; + uc_promisc = true; } else { table->dev_uc_count = 1 + netdev_uc_count(net_dev); ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr); @@ -3796,9 +3796,11 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) i++; } } - if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI) || - netdev_mc_count(net_dev) >= EFX_EF10_FILTER_DEV_MC_MAX) { - table->dev_mc_count = -1; + if (netdev_mc_count(net_dev) + 2 /* room for broadcast and promisc */ + >= EFX_EF10_FILTER_DEV_MC_MAX) { + table->dev_mc_count = 1; + eth_broadcast_addr(table->dev_mc_list[0].addr); + mc_promisc = true; } else { table->dev_mc_count = 1 + netdev_mc_count(net_dev); eth_broadcast_addr(table->dev_mc_list[0].addr); @@ -3807,31 +3809,32 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); i++; } + if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) + mc_promisc = true; } netif_addr_unlock_bh(net_dev); /* Insert/renew unicast filters */ - if (table->dev_uc_count >= 0) { - for (i = 0; i < table->dev_uc_count; i++) { - efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); - efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, - table->dev_uc_list[i].addr); - rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) { - /* Fall back to unicast-promisc */ - while (i--) - efx_ef10_filter_remove_safe( - efx, EFX_FILTER_PRI_AUTO, - table->dev_uc_list[i].id); - table->dev_uc_count = -1; - break; - } - table->dev_uc_list[i].id = rc; + for (i = 0; i < table->dev_uc_count; i++) { + efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, + EFX_FILTER_FLAG_RX_RSS, + 0); + efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, + table->dev_uc_list[i].addr); + rc = efx_ef10_filter_insert(efx, &spec, true); + if (rc < 0) { + /* Fall back to unicast-promisc */ + while (i--) + efx_ef10_filter_remove_safe( + efx, EFX_FILTER_PRI_AUTO, + table->dev_uc_list[i].id); + table->dev_uc_count = 0; + uc_promisc = true; + break; } + table->dev_uc_list[i].id = rc; } - if (table->dev_uc_count < 0) { + if (uc_promisc) { efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); @@ -3839,34 +3842,34 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) rc = efx_ef10_filter_insert(efx, &spec, true); if (rc < 0) { WARN_ON(1); - table->dev_uc_count = 0; } else { - table->dev_uc_list[0].id = rc; + table->dev_uc_list[table->dev_uc_count++].id = rc; } } /* Insert/renew multicast filters */ - if (table->dev_mc_count >= 0) { - for (i = 0; i < table->dev_mc_count; i++) { - efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); - efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, - table->dev_mc_list[i].addr); - rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) { - /* Fall back to multicast-promisc */ - while (i--) - efx_ef10_filter_remove_safe( - efx, EFX_FILTER_PRI_AUTO, - table->dev_mc_list[i].id); - table->dev_mc_count = -1; - break; - } - table->dev_mc_list[i].id = rc; + for (i = 0; i < table->dev_mc_count; i++) { + efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, + EFX_FILTER_FLAG_RX_RSS, + 0); + efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, + table->dev_mc_list[i].addr); + rc = efx_ef10_filter_insert(efx, &spec, true); + if (rc < 0) { + /* Fall back to multicast-promisc. + * Leave the broadcast filter. + */ + while (i > 1) + efx_ef10_filter_remove_safe( + efx, EFX_FILTER_PRI_AUTO, + table->dev_mc_list[--i].id); + table->dev_mc_count = i; + mc_promisc = true; + break; } + table->dev_mc_list[i].id = rc; } - if (table->dev_mc_count < 0) { + if (mc_promisc) { efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); @@ -3874,9 +3877,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) rc = efx_ef10_filter_insert(efx, &spec, true); if (rc < 0) { WARN_ON(1); - table->dev_mc_count = 0; } else { - table->dev_mc_list[0].id = rc; + table->dev_mc_list[table->dev_mc_count++].id = rc; } } -- cgit v1.3-6-gb490 From 822b96f87f1b47ac0c73417284879ef610500173 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 21 Jul 2015 15:10:27 +0100 Subject: sfc: re-factor efx_ef10_filter_sync_rx_mode() This change is only re-factoring; there are no changes to functionality except for a slight elaboration of an error message (on mismatch filter insertion failure). Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 217 +++++++++++++++++++++++----------------- 1 file changed, 126 insertions(+), 91 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 784b46fb039a..1704f71c7250 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -49,6 +49,11 @@ enum { */ #define HUNT_FILTER_TBL_ROWS 8192 +struct efx_ef10_dev_addr { + u8 addr[ETH_ALEN]; + u16 id; +}; + struct efx_ef10_filter_table { /* The RX match field masks supported by this fw & hw, in order of priority */ enum efx_filter_match_flags rx_match_flags[ @@ -69,11 +74,8 @@ struct efx_ef10_filter_table { /* Shadow of net_device address lists, guarded by mac_lock */ #define EFX_EF10_FILTER_DEV_UC_MAX 32 #define EFX_EF10_FILTER_DEV_MC_MAX 256 - struct { - u8 addr[ETH_ALEN]; - u16 id; - } dev_uc_list[EFX_EF10_FILTER_DEV_UC_MAX], - dev_mc_list[EFX_EF10_FILTER_DEV_MC_MAX]; + struct efx_ef10_dev_addr dev_uc_list[EFX_EF10_FILTER_DEV_UC_MAX]; + struct efx_ef10_dev_addr dev_mc_list[EFX_EF10_FILTER_DEV_MC_MAX]; int dev_uc_count; /* negative for PROMISC */ int dev_mc_count; /* negative for PROMISC/ALLMULTI */ }; @@ -3746,23 +3748,10 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx) kfree(table); } -/* Caller must hold efx->filter_sem for read if race against - * efx_ef10_filter_table_remove() is possible - */ -static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) +static void efx_ef10_filter_mark_old(struct efx_nic *efx) { struct efx_ef10_filter_table *table = efx->filter_state; - struct net_device *net_dev = efx->net_dev; - struct efx_filter_spec spec; - bool remove_failed = false; - struct netdev_hw_addr *uc; - struct netdev_hw_addr *mc; - unsigned int filter_idx; - int i, rc; - bool uc_promisc = false, mc_promisc = false; - - if (!efx_dev_registered(efx)) - return; + unsigned int filter_idx, i; if (!table) return; @@ -3778,29 +3767,40 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; } spin_unlock_bh(&efx->filter_lock); +} + +static void efx_ef10_filter_uc_addr_list(struct efx_nic *efx, bool *promisc) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + struct net_device *net_dev = efx->net_dev; + struct netdev_hw_addr *uc; + unsigned int i; - /* Copy/convert the address lists; add the primary station - * address and broadcast address - */ - netif_addr_lock_bh(net_dev); if (net_dev->flags & IFF_PROMISC || netdev_uc_count(net_dev) >= EFX_EF10_FILTER_DEV_UC_MAX) { - table->dev_uc_count = 0; - uc_promisc = true; - } else { - table->dev_uc_count = 1 + netdev_uc_count(net_dev); - ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr); - i = 1; - netdev_for_each_uc_addr(uc, net_dev) { - ether_addr_copy(table->dev_uc_list[i].addr, uc->addr); - i++; - } + *promisc = true; } + table->dev_uc_count = 1 + netdev_uc_count(net_dev); + ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr); + i = 1; + netdev_for_each_uc_addr(uc, net_dev) { + ether_addr_copy(table->dev_uc_list[i].addr, uc->addr); + i++; + } +} + +static void efx_ef10_filter_mc_addr_list(struct efx_nic *efx, bool *promisc) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + struct net_device *net_dev = efx->net_dev; + struct netdev_hw_addr *mc; + unsigned int i; + if (netdev_mc_count(net_dev) + 2 /* room for broadcast and promisc */ - >= EFX_EF10_FILTER_DEV_MC_MAX) { + >= EFX_EF10_FILTER_DEV_MC_MAX) { table->dev_mc_count = 1; eth_broadcast_addr(table->dev_mc_list[0].addr); - mc_promisc = true; + *promisc = true; } else { table->dev_mc_count = 1 + netdev_mc_count(net_dev); eth_broadcast_addr(table->dev_mc_list[0].addr); @@ -3809,84 +3809,87 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); i++; } + if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) - mc_promisc = true; + *promisc = true; } - netif_addr_unlock_bh(net_dev); +} - /* Insert/renew unicast filters */ - for (i = 0; i < table->dev_uc_count; i++) { - efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); - efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, - table->dev_uc_list[i].addr); - rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) { - /* Fall back to unicast-promisc */ - while (i--) - efx_ef10_filter_remove_safe( - efx, EFX_FILTER_PRI_AUTO, - table->dev_uc_list[i].id); - table->dev_uc_count = 0; - uc_promisc = true; - break; - } - table->dev_uc_list[i].id = rc; - } - if (uc_promisc) { - efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); - efx_filter_set_uc_def(&spec); - rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) { - WARN_ON(1); - } else { - table->dev_uc_list[table->dev_uc_count++].id = rc; - } +static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx, + bool multicast, bool *promisc) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + struct efx_ef10_dev_addr *addr_list; + struct efx_filter_spec spec; + int *addr_count; + unsigned int i; + int rc; + + if (multicast) { + addr_list = table->dev_mc_list; + addr_count = &table->dev_mc_count; + } else { + addr_list = table->dev_uc_list; + addr_count = &table->dev_uc_count; } - /* Insert/renew multicast filters */ - for (i = 0; i < table->dev_mc_count; i++) { + /* Insert/renew filters */ + for (i = 0; i < *addr_count; i++) { efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, - table->dev_mc_list[i].addr); + addr_list[i].addr); rc = efx_ef10_filter_insert(efx, &spec, true); if (rc < 0) { - /* Fall back to multicast-promisc. - * Leave the broadcast filter. + /* Fall back to promiscuous, but leave the broadcast + * filter for multicast */ - while (i > 1) + while (i--) { + if (multicast && i == 1) + break; + efx_ef10_filter_remove_safe( efx, EFX_FILTER_PRI_AUTO, - table->dev_mc_list[--i].id); - table->dev_mc_count = i; - mc_promisc = true; + addr_list[i].id); + } + *addr_count = i; + *promisc = true; break; } - table->dev_mc_list[i].id = rc; + addr_list[i].id = rc; } - if (mc_promisc) { + + if (*promisc) { efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); - efx_filter_set_mc_def(&spec); + + if (multicast) + efx_filter_set_mc_def(&spec); + else + efx_filter_set_uc_def(&spec); + rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) { - WARN_ON(1); - } else { - table->dev_mc_list[table->dev_mc_count++].id = rc; - } + if (rc < 0) + netif_warn(efx, drv, efx->net_dev, + "%scast mismatch filter insert failed.", + multicast ? "Multi" : "Uni"); + else + addr_list[(*addr_count)++].id = rc; } +} + +/* Remove filters that weren't renewed. Since nothing else changes the AUTO_OLD + * flag or removes these filters, we don't need to hold the filter_lock while + * scanning for these filters. + */ +static void efx_ef10_filter_remove_old(struct efx_nic *efx) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + bool remove_failed = false; + int i; - /* Remove filters that weren't renewed. Since nothing else - * changes the AUTO_OLD flag or removes these filters, we - * don't need to hold the filter_lock while scanning for - * these filters. - */ for (i = 0; i < HUNT_FILTER_TBL_ROWS; i++) { if (ACCESS_ONCE(table->entry[i].spec) & EFX_EF10_FILTER_FLAG_AUTO_OLD) { @@ -3965,6 +3968,38 @@ reset_nic: return rc ? rc : rc2; } +/* Caller must hold efx->filter_sem for read if race against + * efx_ef10_filter_table_remove() is possible + */ +static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + struct net_device *net_dev = efx->net_dev; + bool uc_promisc = false, mc_promisc = false; + + if (!efx_dev_registered(efx)) + return; + + if (!table) + return; + + efx_ef10_filter_mark_old(efx); + + /* Copy/convert the address lists; add the primary station + * address and broadcast address + */ + netif_addr_lock_bh(net_dev); + efx_ef10_filter_uc_addr_list(efx, &uc_promisc); + efx_ef10_filter_mc_addr_list(efx, &mc_promisc); + netif_addr_unlock_bh(net_dev); + + /* Insert/renew filters */ + efx_ef10_filter_insert_addr_list(efx, false, &uc_promisc); + efx_ef10_filter_insert_addr_list(efx, true, &mc_promisc); + + efx_ef10_filter_remove_old(efx); +} + static int efx_ef10_set_mac_address(struct efx_nic *efx) { MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN); -- cgit v1.3-6-gb490 From ab8b1f7cf83a3016dcdeae874a469e2c8894fcd9 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 21 Jul 2015 15:10:44 +0100 Subject: sfc: support cascaded multicast filters If the workaround to support cascaded multicast filters ("workaround_26807") is enabled, the broadcast filter and individual multicast filters are not inserted when in promiscuous or allmulti mode. There is a race while inserting and removing filters when entering and leaving promiscuous mode. When changing promiscuous state with cascaded multicast filters, the old multicast filters are removed before inserting the new filters to avoid duplicating packets; this can lead to dropped packets until all filters have been inserted. The efx_nic:mc_promisc flag is added to record the presence of a multicast promiscuous filter; this gives a simple way to tell if the promiscuous state is changing. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 56 ++++++++++++++++++++++++++--------- drivers/net/ethernet/sfc/net_driver.h | 2 ++ 2 files changed, 44 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 1704f71c7250..0a7cf432adf3 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3792,26 +3792,42 @@ static void efx_ef10_filter_uc_addr_list(struct efx_nic *efx, bool *promisc) static void efx_ef10_filter_mc_addr_list(struct efx_nic *efx, bool *promisc) { struct efx_ef10_filter_table *table = efx->filter_state; + struct efx_ef10_nic_data *nic_data = efx->nic_data; struct net_device *net_dev = efx->net_dev; struct netdev_hw_addr *mc; - unsigned int i; + unsigned int i, addr_count; - if (netdev_mc_count(net_dev) + 2 /* room for broadcast and promisc */ - >= EFX_EF10_FILTER_DEV_MC_MAX) { - table->dev_mc_count = 1; - eth_broadcast_addr(table->dev_mc_list[0].addr); + if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) *promisc = true; + + if (nic_data->workaround_26807) { + if (*promisc) { + table->dev_mc_count = 0; + return; + } + addr_count = netdev_mc_count(net_dev); } else { - table->dev_mc_count = 1 + netdev_mc_count(net_dev); - eth_broadcast_addr(table->dev_mc_list[0].addr); - i = 1; - netdev_for_each_mc_addr(mc, net_dev) { - ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); - i++; + /* Allow room for broadcast and promiscuous */ + addr_count = netdev_mc_count(net_dev) + 2; + } + + if (addr_count >= EFX_EF10_FILTER_DEV_MC_MAX) { + if (nic_data->workaround_26807) { + table->dev_mc_count = 0; + } else { + table->dev_mc_count = 1; + eth_broadcast_addr(table->dev_mc_list[0].addr); } + *promisc = true; + return; + } - if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) - *promisc = true; + table->dev_mc_count = 1 + netdev_mc_count(net_dev); + eth_broadcast_addr(table->dev_mc_list[0].addr); + i = 1; + netdev_for_each_mc_addr(mc, net_dev) { + ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); + i++; } } @@ -3846,7 +3862,11 @@ static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx, * filter for multicast */ while (i--) { - if (multicast && i == 1) + struct efx_ef10_nic_data *nic_data = + efx->nic_data; + + if (multicast && i == 1 && + !nic_data->workaround_26807) break; efx_ef10_filter_remove_safe( @@ -3974,6 +3994,7 @@ reset_nic: static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) { struct efx_ef10_filter_table *table = efx->filter_state; + struct efx_ef10_nic_data *nic_data = efx->nic_data; struct net_device *net_dev = efx->net_dev; bool uc_promisc = false, mc_promisc = false; @@ -3995,9 +4016,16 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) /* Insert/renew filters */ efx_ef10_filter_insert_addr_list(efx, false, &uc_promisc); + + /* If changing promiscuous state with cascaded multicast filters, remove + * old filters first, so that packets are dropped rather than duplicated + */ + if (nic_data->workaround_26807 && efx->mc_promisc != mc_promisc) + efx_ef10_filter_remove_old(efx); efx_ef10_filter_insert_addr_list(efx, true, &mc_promisc); efx_ef10_filter_remove_old(efx); + efx->mc_promisc = mc_promisc; } static int efx_ef10_set_mac_address(struct efx_nic *efx) diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 47d1e3a96522..4d35313a239d 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -925,6 +925,7 @@ struct vfdi_status; * @stats_lock: Statistics update lock. Must be held when calling * efx_nic_type::{update,start,stop}_stats. * @n_rx_noskb_drops: Count of RX packets dropped due to failure to allocate an skb + * @mc_promisc: Whether in multicast promiscuous mode when last changed * * This is stored in the private area of the &struct net_device. */ @@ -1072,6 +1073,7 @@ struct efx_nic { int last_irq_cpu; spinlock_t stats_lock; atomic_t n_rx_noskb_drops; + bool mc_promisc; }; static inline int efx_dev_registered(struct efx_nic *efx) -- cgit v1.3-6-gb490 From 12fb0da45c9a077dd76d9848f791fbdd4b8d4050 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Tue, 21 Jul 2015 15:11:00 +0100 Subject: sfc: clean fallbacks between promisc/normal in efx_ef10_filter_sync_rx_mode Separate functions for inserting individual and promisc filters; explicit fallback logic in efx_ef10_filter_sync_rx_mode(), in order not to overload the 'promisc' flag as also meaning "fall back to promisc". Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 288 +++++++++++++++++++++++++++++----------- 1 file changed, 208 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 0a7cf432adf3..8505d82290cb 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -49,6 +49,7 @@ enum { */ #define HUNT_FILTER_TBL_ROWS 8192 +#define EFX_EF10_FILTER_ID_INVALID 0xffff struct efx_ef10_dev_addr { u8 addr[ETH_ALEN]; u16 id; @@ -76,8 +77,12 @@ struct efx_ef10_filter_table { #define EFX_EF10_FILTER_DEV_MC_MAX 256 struct efx_ef10_dev_addr dev_uc_list[EFX_EF10_FILTER_DEV_UC_MAX]; struct efx_ef10_dev_addr dev_mc_list[EFX_EF10_FILTER_DEV_MC_MAX]; - int dev_uc_count; /* negative for PROMISC */ - int dev_mc_count; /* negative for PROMISC/ALLMULTI */ + int dev_uc_count; + int dev_mc_count; +/* Indices (like efx_ef10_dev_addr.id) for promisc/allmulti filters */ + u16 ucdef_id; + u16 bcast_id; + u16 mcdef_id; }; /* An arbitrary search limit for the software hash table */ @@ -3273,6 +3278,19 @@ static int efx_ef10_filter_remove_safe(struct efx_nic *efx, filter_id, false); } +static u32 efx_ef10_filter_get_unsafe_id(struct efx_nic *efx, u32 filter_id) +{ + return filter_id % HUNT_FILTER_TBL_ROWS; +} + +static int efx_ef10_filter_remove_unsafe(struct efx_nic *efx, + enum efx_filter_priority priority, + u32 filter_id) +{ + return efx_ef10_filter_remove_internal(efx, 1U << priority, + filter_id, true); +} + static int efx_ef10_filter_get_safe(struct efx_nic *efx, enum efx_filter_priority priority, u32 filter_id, struct efx_filter_spec *spec) @@ -3646,6 +3664,10 @@ static int efx_ef10_filter_table_probe(struct efx_nic *efx) goto fail; } + table->ucdef_id = EFX_EF10_FILTER_ID_INVALID; + table->bcast_id = EFX_EF10_FILTER_ID_INVALID; + table->mcdef_id = EFX_EF10_FILTER_ID_INVALID; + efx->filter_state = table; init_waitqueue_head(&table->waitq); return 0; @@ -3748,6 +3770,12 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx) kfree(table); } +#define EFX_EF10_FILTER_DO_MARK_OLD(id) \ + if (id != EFX_EF10_FILTER_ID_INVALID) { \ + filter_idx = efx_ef10_filter_get_unsafe_id(efx, id); \ + WARN_ON(!table->entry[filter_idx].spec); \ + table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; \ + } static void efx_ef10_filter_mark_old(struct efx_nic *efx) { struct efx_ef10_filter_table *table = efx->filter_state; @@ -3758,33 +3786,39 @@ static void efx_ef10_filter_mark_old(struct efx_nic *efx) /* Mark old filters that may need to be removed */ spin_lock_bh(&efx->filter_lock); - for (i = 0; i < table->dev_uc_count; i++) { - filter_idx = table->dev_uc_list[i].id % HUNT_FILTER_TBL_ROWS; - table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; - } - for (i = 0; i < table->dev_mc_count; i++) { - filter_idx = table->dev_mc_list[i].id % HUNT_FILTER_TBL_ROWS; - table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; - } + for (i = 0; i < table->dev_uc_count; i++) + EFX_EF10_FILTER_DO_MARK_OLD(table->dev_uc_list[i].id); + for (i = 0; i < table->dev_mc_count; i++) + EFX_EF10_FILTER_DO_MARK_OLD(table->dev_mc_list[i].id); + EFX_EF10_FILTER_DO_MARK_OLD(table->ucdef_id); + EFX_EF10_FILTER_DO_MARK_OLD(table->bcast_id); + EFX_EF10_FILTER_DO_MARK_OLD(table->mcdef_id); spin_unlock_bh(&efx->filter_lock); } +#undef EFX_EF10_FILTER_DO_MARK_OLD static void efx_ef10_filter_uc_addr_list(struct efx_nic *efx, bool *promisc) { struct efx_ef10_filter_table *table = efx->filter_state; struct net_device *net_dev = efx->net_dev; struct netdev_hw_addr *uc; + int addr_count; unsigned int i; - if (net_dev->flags & IFF_PROMISC || - netdev_uc_count(net_dev) >= EFX_EF10_FILTER_DEV_UC_MAX) { + table->ucdef_id = EFX_EF10_FILTER_ID_INVALID; + addr_count = netdev_uc_count(net_dev); + if (net_dev->flags & IFF_PROMISC) *promisc = true; - } - table->dev_uc_count = 1 + netdev_uc_count(net_dev); + table->dev_uc_count = 1 + addr_count; ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr); i = 1; netdev_for_each_uc_addr(uc, net_dev) { + if (i >= EFX_EF10_FILTER_DEV_UC_MAX) { + *promisc = true; + break; + } ether_addr_copy(table->dev_uc_list[i].addr, uc->addr); + table->dev_uc_list[i].id = EFX_EF10_FILTER_ID_INVALID; i++; } } @@ -3792,65 +3826,51 @@ static void efx_ef10_filter_uc_addr_list(struct efx_nic *efx, bool *promisc) static void efx_ef10_filter_mc_addr_list(struct efx_nic *efx, bool *promisc) { struct efx_ef10_filter_table *table = efx->filter_state; - struct efx_ef10_nic_data *nic_data = efx->nic_data; struct net_device *net_dev = efx->net_dev; struct netdev_hw_addr *mc; unsigned int i, addr_count; + table->mcdef_id = EFX_EF10_FILTER_ID_INVALID; + table->bcast_id = EFX_EF10_FILTER_ID_INVALID; if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) *promisc = true; - if (nic_data->workaround_26807) { - if (*promisc) { - table->dev_mc_count = 0; - return; - } - addr_count = netdev_mc_count(net_dev); - } else { - /* Allow room for broadcast and promiscuous */ - addr_count = netdev_mc_count(net_dev) + 2; - } - - if (addr_count >= EFX_EF10_FILTER_DEV_MC_MAX) { - if (nic_data->workaround_26807) { - table->dev_mc_count = 0; - } else { - table->dev_mc_count = 1; - eth_broadcast_addr(table->dev_mc_list[0].addr); - } - *promisc = true; - return; - } - - table->dev_mc_count = 1 + netdev_mc_count(net_dev); - eth_broadcast_addr(table->dev_mc_list[0].addr); - i = 1; + addr_count = netdev_mc_count(net_dev); + i = 0; netdev_for_each_mc_addr(mc, net_dev) { + if (i >= EFX_EF10_FILTER_DEV_MC_MAX) { + *promisc = true; + break; + } ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); + table->dev_mc_list[i].id = EFX_EF10_FILTER_ID_INVALID; i++; } + + table->dev_mc_count = i; } -static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx, - bool multicast, bool *promisc) +static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx, + bool multicast, bool rollback) { struct efx_ef10_filter_table *table = efx->filter_state; struct efx_ef10_dev_addr *addr_list; struct efx_filter_spec spec; - int *addr_count; - unsigned int i; + u8 baddr[ETH_ALEN]; + unsigned int i, j; + int addr_count; int rc; if (multicast) { addr_list = table->dev_mc_list; - addr_count = &table->dev_mc_count; + addr_count = table->dev_mc_count; } else { addr_list = table->dev_uc_list; - addr_count = &table->dev_uc_count; + addr_count = table->dev_uc_count; } /* Insert/renew filters */ - for (i = 0; i < *addr_count; i++) { + for (i = 0; i < addr_count; i++) { efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); @@ -3858,46 +3878,113 @@ static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx, addr_list[i].addr); rc = efx_ef10_filter_insert(efx, &spec, true); if (rc < 0) { - /* Fall back to promiscuous, but leave the broadcast - * filter for multicast - */ - while (i--) { - struct efx_ef10_nic_data *nic_data = - efx->nic_data; - - if (multicast && i == 1 && - !nic_data->workaround_26807) - break; - - efx_ef10_filter_remove_safe( - efx, EFX_FILTER_PRI_AUTO, - addr_list[i].id); + if (rollback) { + netif_info(efx, drv, efx->net_dev, + "efx_ef10_filter_insert failed rc=%d\n", + rc); + /* Fall back to promiscuous */ + for (j = 0; j < i; j++) { + if (addr_list[j].id == EFX_EF10_FILTER_ID_INVALID) + continue; + efx_ef10_filter_remove_unsafe( + efx, EFX_FILTER_PRI_AUTO, + addr_list[j].id); + addr_list[j].id = EFX_EF10_FILTER_ID_INVALID; + } + return rc; + } else { + /* mark as not inserted, and carry on */ + rc = EFX_EF10_FILTER_ID_INVALID; } - *addr_count = i; - *promisc = true; - break; } - addr_list[i].id = rc; + addr_list[i].id = efx_ef10_filter_get_unsafe_id(efx, rc); } - if (*promisc) { + if (multicast && rollback) { + /* Also need an Ethernet broadcast filter */ efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); - - if (multicast) - efx_filter_set_mc_def(&spec); - else - efx_filter_set_uc_def(&spec); - + eth_broadcast_addr(baddr); + efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, baddr); rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) + if (rc < 0) { netif_warn(efx, drv, efx->net_dev, - "%scast mismatch filter insert failed.", - multicast ? "Multi" : "Uni"); - else - addr_list[(*addr_count)++].id = rc; + "Broadcast filter insert failed rc=%d\n", rc); + /* Fall back to promiscuous */ + for (j = 0; j < i; j++) { + if (addr_list[j].id == EFX_EF10_FILTER_ID_INVALID) + continue; + efx_ef10_filter_remove_unsafe( + efx, EFX_FILTER_PRI_AUTO, + addr_list[j].id); + addr_list[j].id = EFX_EF10_FILTER_ID_INVALID; + } + return rc; + } else { + table->bcast_id = efx_ef10_filter_get_unsafe_id(efx, rc); + } } + + return 0; +} + +static int efx_ef10_filter_insert_def(struct efx_nic *efx, bool multicast, + bool rollback) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + struct efx_ef10_nic_data *nic_data = efx->nic_data; + struct efx_filter_spec spec; + u8 baddr[ETH_ALEN]; + int rc; + + efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, + EFX_FILTER_FLAG_RX_RSS, + 0); + + if (multicast) + efx_filter_set_mc_def(&spec); + else + efx_filter_set_uc_def(&spec); + + rc = efx_ef10_filter_insert(efx, &spec, true); + if (rc < 0) { + netif_warn(efx, drv, efx->net_dev, + "%scast mismatch filter insert failed rc=%d\n", + multicast ? "Multi" : "Uni", rc); + } else if (multicast) { + table->mcdef_id = efx_ef10_filter_get_unsafe_id(efx, rc); + if (!nic_data->workaround_26807) { + /* Also need an Ethernet broadcast filter */ + efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, + EFX_FILTER_FLAG_RX_RSS, + 0); + eth_broadcast_addr(baddr); + efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, + baddr); + rc = efx_ef10_filter_insert(efx, &spec, true); + if (rc < 0) { + netif_warn(efx, drv, efx->net_dev, + "Broadcast filter insert failed rc=%d\n", + rc); + if (rollback) { + /* Roll back the mc_def filter */ + efx_ef10_filter_remove_unsafe( + efx, EFX_FILTER_PRI_AUTO, + table->mcdef_id); + table->mcdef_id = EFX_EF10_FILTER_ID_INVALID; + return rc; + } + } else { + table->bcast_id = efx_ef10_filter_get_unsafe_id(efx, rc); + } + } + rc = 0; + } else { + table->ucdef_id = rc; + rc = 0; + } + return rc; } /* Remove filters that weren't renewed. Since nothing else changes the AUTO_OLD @@ -4014,15 +4101,56 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) efx_ef10_filter_mc_addr_list(efx, &mc_promisc); netif_addr_unlock_bh(net_dev); - /* Insert/renew filters */ - efx_ef10_filter_insert_addr_list(efx, false, &uc_promisc); + /* Insert/renew unicast filters */ + if (uc_promisc) { + efx_ef10_filter_insert_def(efx, false, false); + efx_ef10_filter_insert_addr_list(efx, false, false); + } else { + /* If any of the filters failed to insert, fall back to + * promiscuous mode - add in the uc_def filter. But keep + * our individual unicast filters. + */ + if (efx_ef10_filter_insert_addr_list(efx, false, false)) + efx_ef10_filter_insert_def(efx, false, false); + } + /* Insert/renew multicast filters */ /* If changing promiscuous state with cascaded multicast filters, remove * old filters first, so that packets are dropped rather than duplicated */ if (nic_data->workaround_26807 && efx->mc_promisc != mc_promisc) efx_ef10_filter_remove_old(efx); - efx_ef10_filter_insert_addr_list(efx, true, &mc_promisc); + if (mc_promisc) { + if (nic_data->workaround_26807) { + /* If we failed to insert promiscuous filters, rollback + * and fall back to individual multicast filters + */ + if (efx_ef10_filter_insert_def(efx, true, true)) { + /* Changing promisc state, so remove old filters */ + efx_ef10_filter_remove_old(efx); + efx_ef10_filter_insert_addr_list(efx, true, false); + } + } else { + /* If we failed to insert promiscuous filters, don't + * rollback. Regardless, also insert the mc_list + */ + efx_ef10_filter_insert_def(efx, true, false); + efx_ef10_filter_insert_addr_list(efx, true, false); + } + } else { + /* If any filters failed to insert, rollback and fall back to + * promiscuous mode - mc_def filter and maybe broadcast. If + * that fails, roll back again and insert as many of our + * individual multicast filters as we can. + */ + if (efx_ef10_filter_insert_addr_list(efx, true, true)) { + /* Changing promisc state, so remove old filters */ + if (nic_data->workaround_26807) + efx_ef10_filter_remove_old(efx); + if (efx_ef10_filter_insert_def(efx, true, true)) + efx_ef10_filter_insert_addr_list(efx, true, false); + } + } efx_ef10_filter_remove_old(efx); efx->mc_promisc = mc_promisc; -- cgit v1.3-6-gb490 From 0b2c2a931a051e75f9df429b520bb2c2f2bb056b Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 21 Jul 2015 22:39:40 +0530 Subject: cxgb4: Add debugfs entry to enable backdoor access Add debugfs entry 'use_backdoor' to enable backdoor access to read sge context. By default, we read sge context's via firmware. In case of FW issues, one can enable backdoor access via debugfs to dump sge context for debugging purpose. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 2 ++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 19 ++++++++++++------- 3 files changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 629f75d70353..58de4443eac0 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -767,6 +767,7 @@ struct adapter { bool tid_release_task_busy; struct dentry *debugfs_root; + u32 use_bd; /* Use SGE Back Door intfc for reading SGE Contexts */ spinlock_t stats_lock; spinlock_t win0_lock ____cacheline_aligned_in_smp; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index b135d05c9984..f701a6f20c6a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -2388,6 +2388,8 @@ int t4_setup_debugfs(struct adapter *adap) de = debugfs_create_file_size("flash", S_IRUSR, adap->debugfs_root, adap, &flash_debugfs_fops, adap->params.sf_size); + debugfs_create_bool("use_backdoor", S_IWUSR | S_IRUSR, + adap->debugfs_root, &adap->use_bd); return 0; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 1e6597dc8736..800bd489dd75 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3689,6 +3689,11 @@ int t4_read_rss(struct adapter *adapter, u16 *map) return 0; } +static unsigned int t4_use_ldst(struct adapter *adap) +{ + return (adap->flags & FW_OK) || !adap->use_bd; +} + /** * t4_fw_tp_pio_rw - Access TP PIO through LDST * @adap: the adapter @@ -3732,7 +3737,7 @@ static void t4_fw_tp_pio_rw(struct adapter *adap, u32 *vals, unsigned int nregs, */ void t4_read_rss_key(struct adapter *adap, u32 *key) { - if (adap->flags & FW_OK) + if (t4_use_ldst(adap)) t4_fw_tp_pio_rw(adap, key, 10, TP_RSS_SECRET_KEY0_A, 1); else t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10, @@ -3762,7 +3767,7 @@ void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx) (vrt & KEYEXTEND_F) && (KEYMODE_G(vrt) == 3)) rss_key_addr_cnt = 32; - if (adap->flags & FW_OK) + if (t4_use_ldst(adap)) t4_fw_tp_pio_rw(adap, (void *)key, 10, TP_RSS_SECRET_KEY0_A, 0); else t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10, @@ -3791,7 +3796,7 @@ void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx) void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, u32 *valp) { - if (adapter->flags & FW_OK) + if (t4_use_ldst(adapter)) t4_fw_tp_pio_rw(adapter, valp, 1, TP_RSS_PF0_CONFIG_A + index, 1); else @@ -3831,7 +3836,7 @@ void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index, /* Grab the VFL/VFH values ... */ - if (adapter->flags & FW_OK) { + if (t4_use_ldst(adapter)) { t4_fw_tp_pio_rw(adapter, vfl, 1, TP_RSS_VFL_CONFIG_A, 1); t4_fw_tp_pio_rw(adapter, vfh, 1, TP_RSS_VFH_CONFIG_A, 1); } else { @@ -3852,7 +3857,7 @@ u32 t4_read_rss_pf_map(struct adapter *adapter) { u32 pfmap; - if (adapter->flags & FW_OK) + if (t4_use_ldst(adapter)) t4_fw_tp_pio_rw(adapter, &pfmap, 1, TP_RSS_PF_MAP_A, 1); else t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, @@ -3870,7 +3875,7 @@ u32 t4_read_rss_pf_mask(struct adapter *adapter) { u32 pfmask; - if (adapter->flags & FW_OK) + if (t4_use_ldst(adapter)) t4_fw_tp_pio_rw(adapter, &pfmask, 1, TP_RSS_PF_MSK_A, 1); else t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, @@ -6275,7 +6280,7 @@ int t4_init_tp_params(struct adapter *adap) /* Cache the adapter's Compressed Filter Mode and global Incress * Configuration. */ - if (adap->flags & FW_OK) { + if (t4_use_ldst(adap)) { t4_fw_tp_pio_rw(adap, &adap->params.tp.vlan_pri_map, 1, TP_VLAN_PRI_MAP_A, 1); t4_fw_tp_pio_rw(adap, &adap->params.tp.ingress_config, 1, -- cgit v1.3-6-gb490 From 00fd2cb0ec4208a32272b4c2f1063ab99a76473c Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Thu, 2 Jul 2015 09:06:55 +0200 Subject: s390/sclp: Change SCLP console default buffer-full behavior Dropping kernel messages during a console-buffer-full condition is preferable to halting the system until console messages are delivered, especially for production systems. Update default for sclp_console_drop kernel parameter accordingly. Signed-off-by: Peter Oberparleiter Acked-by: Martin Schwidefsky Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 5e20513c0587..f58bf4c6c3ee 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -53,7 +53,7 @@ static DECLARE_COMPLETION(sclp_request_queue_flushed); /* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */ int sclp_console_pages = SCLP_CONSOLE_PAGES; /* Flag to indicate if buffer pages are dropped on buffer full condition */ -int sclp_console_drop = 0; +int sclp_console_drop = 1; /* Number of times the console dropped buffer pages */ unsigned long sclp_console_full; @@ -79,8 +79,8 @@ static int __init sclp_setup_console_drop(char *str) int drop, rc; rc = kstrtoint(str, 0, &drop); - if (!rc && drop) - sclp_console_drop = 1; + if (!rc) + sclp_console_drop = drop; return 1; } -- cgit v1.3-6-gb490 From b1865401cf54c7ce06bccccb917f57c46a83b399 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Thu, 2 Jul 2015 14:00:30 +0200 Subject: s390/cio: Fix comma After dutifully acting as statement separator for 6 long years, this comma has finally grown into a full semicolon. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index f3c417943dad..6acd0b577694 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -540,7 +540,7 @@ int ccw_device_stlck(struct ccw_device *cdev) if (rc) goto out_unlock; /* Perform operation. */ - cdev->private->state = DEV_STATE_STEAL_LOCK, + cdev->private->state = DEV_STATE_STEAL_LOCK; ccw_device_stlck_start(cdev, &data, &buffer[0], &buffer[32]); spin_unlock_irq(sch->lock); /* Wait for operation to finish. */ -- cgit v1.3-6-gb490 From 1d2334cb7da37e4b0005ca1d194d4e10ca7119f4 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Wed, 15 Jul 2015 14:04:18 +0200 Subject: s390/cio: Implement proper Link Incident Record handling A hardware problem on a FICON link is reported by the Channel Subsystem to the operating system via a Link Incident Record (LIR). In response, the operating system should issue a message that enables hardware service personnel to identify and repair the failing component. Current Linux LIR handling is broken because LIR data is incorrectly interpreted and no log message is generated. This patch fixes Linux LIR handling by implementing a new log message for LIRs indicating a degraded or non-operational link. Also LIRs are no longer used to deactivate channel paths because the available data does not reliably allow to determine the affected channel path. Signed-off-by: Peter Oberparleiter Reviewed-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 165 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 123 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index e3bf885f4a6c..548a18916a31 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "css.h" #include "cio.h" @@ -272,36 +273,6 @@ static void s390_process_res_acc(struct chp_link *link) css_schedule_reprobe(); } -static int -__get_chpid_from_lir(void *data) -{ - struct lir { - u8 iq; - u8 ic; - u16 sci; - /* incident-node descriptor */ - u32 indesc[28]; - /* attached-node descriptor */ - u32 andesc[28]; - /* incident-specific information */ - u32 isinfo[28]; - } __attribute__ ((packed)) *lir; - - lir = data; - if (!(lir->iq&0x80)) - /* NULL link incident record */ - return -EINVAL; - if (!(lir->indesc[0]&0xc0000000)) - /* node descriptor not valid */ - return -EINVAL; - if (!(lir->indesc[0]&0x10000000)) - /* don't handle device-type nodes - FIXME */ - return -EINVAL; - /* Byte 3 contains the chpid. Could also be CTCA, but we don't care */ - - return (u16) (lir->indesc[0]&0x000000ff); -} - struct chsc_sei_nt0_area { u8 flags; u8 vf; /* validity flags */ @@ -341,22 +312,132 @@ struct chsc_sei { } u; } __packed; +/* + * Node Descriptor as defined in SA22-7204, "Common I/O-Device Commands" + */ + +#define ND_VALIDITY_VALID 0 +#define ND_VALIDITY_OUTDATED 1 +#define ND_VALIDITY_INVALID 2 + +struct node_descriptor { + /* Flags. */ + union { + struct { + u32 validity:3; + u32 reserved:5; + } __packed; + u8 byte0; + } __packed; + + /* Node parameters. */ + u32 params:24; + + /* Node ID. */ + char type[6]; + char model[3]; + char manufacturer[3]; + char plant[2]; + char seq[12]; + u16 tag; +} __packed; + +/* + * Link Incident Record as defined in SA22-7202, "ESCON I/O Interface" + */ + +#define LIR_IQ_CLASS_INFO 0 +#define LIR_IQ_CLASS_DEGRADED 1 +#define LIR_IQ_CLASS_NOT_OPERATIONAL 2 + +struct lir { + struct { + u32 null:1; + u32 reserved:3; + u32 class:2; + u32 reserved2:2; + } __packed iq; + u32 ic:8; + u32 reserved:16; + struct node_descriptor incident_node; + struct node_descriptor attached_node; + u8 reserved2[32]; +} __packed; + +#define PARAMS_LEN 10 /* PARAMS=xx,xxxxxx */ +#define NODEID_LEN 35 /* NODEID=tttttt/mdl,mmm.ppssssssssssss,xxxx */ + +/* Copy EBCIDC text, convert to ASCII and optionally add delimiter. */ +static char *store_ebcdic(char *dest, const char *src, unsigned long len, + char delim) +{ + memcpy(dest, src, len); + EBCASC(dest, len); + + if (delim) + dest[len++] = delim; + + return dest + len; +} + +/* Format node ID and parameters for output in LIR log message. */ +static void format_node_data(char *params, char *id, struct node_descriptor *nd) +{ + memset(params, 0, PARAMS_LEN); + memset(id, 0, NODEID_LEN); + + if (nd->validity != ND_VALIDITY_VALID) { + strncpy(params, "n/a", PARAMS_LEN - 1); + strncpy(id, "n/a", NODEID_LEN - 1); + return; + } + + /* PARAMS=xx,xxxxxx */ + snprintf(params, PARAMS_LEN, "%02x,%06x", nd->byte0, nd->params); + /* NODEID=tttttt/mdl,mmm.ppssssssssssss,xxxx */ + id = store_ebcdic(id, nd->type, sizeof(nd->type), '/'); + id = store_ebcdic(id, nd->model, sizeof(nd->model), ','); + id = store_ebcdic(id, nd->manufacturer, sizeof(nd->manufacturer), '.'); + id = store_ebcdic(id, nd->plant, sizeof(nd->plant), 0); + id = store_ebcdic(id, nd->seq, sizeof(nd->seq), ','); + sprintf(id, "%04X", nd->tag); +} + static void chsc_process_sei_link_incident(struct chsc_sei_nt0_area *sei_area) { - struct chp_id chpid; - int id; + struct lir *lir = (struct lir *) &sei_area->ccdf; + char iuparams[PARAMS_LEN], iunodeid[NODEID_LEN], auparams[PARAMS_LEN], + aunodeid[NODEID_LEN]; - CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n", - sei_area->rs, sei_area->rsid); - if (sei_area->rs != 4) + CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x, iq=%02x)\n", + sei_area->rs, sei_area->rsid, sei_area->ccdf[0]); + + /* Ignore NULL Link Incident Records. */ + if (lir->iq.null) return; - id = __get_chpid_from_lir(sei_area->ccdf); - if (id < 0) - CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n"); - else { - chp_id_init(&chpid); - chpid.id = id; - chsc_chp_offline(chpid); + + /* Inform user that a link requires maintenance actions because it has + * become degraded or not operational. Note that this log message is + * the primary intention behind a Link Incident Record. */ + + format_node_data(iuparams, iunodeid, &lir->incident_node); + format_node_data(auparams, aunodeid, &lir->attached_node); + + switch (lir->iq.class) { + case LIR_IQ_CLASS_DEGRADED: + pr_warn("Link degraded: RS=%02x RSID=%04x IC=%02x " + "IUPARAMS=%s IUNODEID=%s AUPARAMS=%s AUNODEID=%s\n", + sei_area->rs, sei_area->rsid, lir->ic, iuparams, + iunodeid, auparams, aunodeid); + break; + case LIR_IQ_CLASS_NOT_OPERATIONAL: + pr_err("Link stopped: RS=%02x RSID=%04x IC=%02x " + "IUPARAMS=%s IUNODEID=%s AUPARAMS=%s AUNODEID=%s\n", + sei_area->rs, sei_area->rsid, lir->ic, iuparams, + iunodeid, auparams, aunodeid); + break; + default: + break; } } -- cgit v1.3-6-gb490 From fd63e2a972c670887e5e8a08440111d3812c0996 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 21 Jul 2015 15:32:44 -0700 Subject: drm/i915: combine i9xx_get_hpd_pins and pch_get_hpd_pins These functions are quite similar, so combine them with the use of a new argument for a function that detects long pulses. This will be also needed by an upcoming patch adding support for BXT long pulse detection. No functional change. v2: - rebase on top -nightly (Daniel) Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 57 ++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d87f173a0179..9410aaba01d4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1256,9 +1256,10 @@ static bool i9xx_port_hotplug_long_detect(enum port port, u32 val) } /* Get a bit mask of pins that have triggered, and which ones may be long. */ -static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, +static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask, u32 hotplug_trigger, u32 dig_hotplug_reg, - const u32 hpd[HPD_NUM_PINS]) + const u32 hpd[HPD_NUM_PINS], + bool long_pulse_detect(enum port port, u32 val)) { enum port port; int i; @@ -1273,7 +1274,7 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, *pin_mask |= BIT(i); port = intel_hpd_pin_to_port(i); - if (pch_port_hotplug_long_detect(port, dig_hotplug_reg)) + if (long_pulse_detect(port, dig_hotplug_reg)) *long_mask |= BIT(i); } @@ -1282,34 +1283,6 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, } -/* Get a bit mask of pins that have triggered, and which ones may be long. */ -static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, - u32 hotplug_trigger, const u32 hpd[HPD_NUM_PINS]) -{ - enum port port; - int i; - - *pin_mask = 0; - *long_mask = 0; - - if (!hotplug_trigger) - return; - - for_each_hpd_pin(i) { - if ((hpd[i] & hotplug_trigger) == 0) - continue; - - *pin_mask |= BIT(i); - - port = intel_hpd_pin_to_port(i); - if (i9xx_port_hotplug_long_detect(port, hotplug_trigger)) - *long_mask |= BIT(i); - } - - DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, pins 0x%08x\n", - hotplug_trigger, *pin_mask); -} - static void gmbus_irq_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1547,7 +1520,9 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; - i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_g4x); + intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + hotplug_trigger, hpd_status_g4x, + i9xx_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) @@ -1555,7 +1530,9 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) } else { u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; - i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_i915); + intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + hotplug_trigger, hpd_status_g4x, + i9xx_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); } } @@ -1662,8 +1639,9 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); - pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, - dig_hotplug_reg, hpd_ibx); + intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + dig_hotplug_reg, hpd_ibx, + pch_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); } @@ -1763,8 +1741,10 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); - pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, - dig_hotplug_reg, hpd_cpt); + + intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + dig_hotplug_reg, hpd_cpt, + pch_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); } @@ -1981,7 +1961,8 @@ static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status) /* Clear sticky bits in hpd status */ I915_WRITE(BXT_HOTPLUG_CTL, hp_control); - pch_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, hpd_bxt); + intel_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, + hpd_bxt, pch_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); } -- cgit v1.3-6-gb490 From cc24fcdcea74844145f0f7683d4626be27dec221 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 21 Jul 2015 15:32:45 -0700 Subject: drm/i915: don't use HPD_PORT_A as an alias for HPD_NONE Currently HPD_PORT_A is used as an alias for HPD_NONE to mean that the given port doesn't support long/short HPD pulse detection. SDVO and CRT ports are like this and for these ports we only want to know whether an hot plug event was detected on the corresponding pin. Since at least on BXT we need long/short pulse detection on PORT A as well (added by the next patch) remove this aliasing of HPD_PORT_A/HPD_NONE and let the return value of intel_hpd_pin_to_port() show whether long/short pulse detection is supported on the passed in pin. No functional change. v2: - rebase on top of -nightly (Daniel) - make the check for intel_hpd_pin_to_port() return value more readable (Sivakumar) Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- drivers/gpu/drm/i915/i915_irq.c | 4 +++- drivers/gpu/drm/i915/intel_hotplug.c | 20 +++++++++++++------- 3 files changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b876e788e2f8..b94ada96b348 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -206,11 +206,11 @@ enum intel_display_power_domain { enum hpd_pin { HPD_NONE = 0, - HPD_PORT_A = HPD_NONE, /* PORT_A is internal */ HPD_TV = HPD_NONE, /* TV is known to be unreliable */ HPD_CRT, HPD_SDVO_B, HPD_SDVO_C, + HPD_PORT_A, HPD_PORT_B, HPD_PORT_C, HPD_PORT_D, @@ -2648,7 +2648,7 @@ void intel_hpd_irq_handler(struct drm_device *dev, u32 pin_mask, u32 long_mask); void intel_hpd_init(struct drm_i915_private *dev_priv); void intel_hpd_init_work(struct drm_i915_private *dev_priv); void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); -enum port intel_hpd_pin_to_port(enum hpd_pin pin); +bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port); /* i915_irq.c */ void i915_queue_hangcheck(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9410aaba01d4..f08ec9cf46e6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1273,7 +1273,9 @@ static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask, *pin_mask |= BIT(i); - port = intel_hpd_pin_to_port(i); + if (!intel_hpd_pin_to_port(i, &port)) + continue; + if (long_pulse_detect(port, dig_hotplug_reg)) *long_mask |= BIT(i); } diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 3c9171f11531..032a0bf75f3b 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -76,17 +76,23 @@ * it will use i915_hotplug_work_func where this logic is handled. */ -enum port intel_hpd_pin_to_port(enum hpd_pin pin) +bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port) { switch (pin) { + case HPD_PORT_A: + *port = PORT_A; + return true; case HPD_PORT_B: - return PORT_B; + *port = PORT_B; + return true; case HPD_PORT_C: - return PORT_C; + *port = PORT_C; + return true; case HPD_PORT_D: - return PORT_D; + *port = PORT_D; + return true; default: - return PORT_A; /* no hpd */ + return false; /* no hpd */ } } @@ -369,8 +375,8 @@ void intel_hpd_irq_handler(struct drm_device *dev, if (!(BIT(i) & pin_mask)) continue; - port = intel_hpd_pin_to_port(i); - is_dig_port = port && dev_priv->hotplug.irq_port[port]; + is_dig_port = intel_hpd_pin_to_port(i, &port) && + dev_priv->hotplug.irq_port[port]; if (is_dig_port) { bool long_hpd = long_mask & BIT(i); -- cgit v1.3-6-gb490 From 63c88d2204bb33d060e22318b3d50162b7019add Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 20 Jul 2015 14:43:39 -0700 Subject: drm/i915/bxt: add support for HPD long/short pulse detection on HPD_PORT_A pin This is a requirement for enabling display port HPD support on the port A HPD pin. This support is to be added by follow-up patches. Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 18 +++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 5 +++++ 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f08ec9cf46e6..1118c39281f9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1227,6 +1227,22 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, return ret; } +static bool bxt_port_hotplug_long_detect(enum port port, u32 val) +{ + switch (port) { + case PORT_A: + return val & BXT_PORTA_HOTPLUG_LONG_DETECT; + case PORT_B: + return val & PORTB_HOTPLUG_LONG_DETECT; + case PORT_C: + return val & PORTC_HOTPLUG_LONG_DETECT; + case PORT_D: + return val & PORTD_HOTPLUG_LONG_DETECT; + default: + return false; + } +} + static bool pch_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { @@ -1964,7 +1980,7 @@ static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status) I915_WRITE(BXT_HOTPLUG_CTL, hp_control); intel_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, - hpd_bxt, pch_port_hotplug_long_detect); + hpd_bxt, bxt_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e9a95df639f0..8cf77568f7e1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5985,6 +5985,11 @@ enum skl_disp_power_wells { /* digital port hotplug */ #define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */ +#define BXT_PORTA_HOTPLUG_ENABLE (1 << 28) +#define BXT_PORTA_HOTPLUG_STATUS_MASK (0x3 << 24) +#define BXT_PORTA_HOTPLUG_NO_DETECT (0 << 24) +#define BXT_PORTA_HOTPLUG_SHORT_DETECT (1 << 24) +#define BXT_PORTA_HOTPLUG_LONG_DETECT (2 << 24) #define PORTD_HOTPLUG_ENABLE (1 << 20) #define PORTD_PULSE_DURATION_2ms (0) #define PORTD_PULSE_DURATION_4_5ms (1 << 18) -- cgit v1.3-6-gb490 From 04cbfe68c3190f23bcfec230bfd832b533f35554 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Wed, 22 Jul 2015 14:01:44 +0530 Subject: mfd: Add GPIOLIB dependency if INTEL_SOC_PMIC is to be enabled This is needed as the CRC PMIC has support for Panel enable/diable as gpio which needs 'gpiod_add_lookup_table' and 'gpiod_remove_lookup_table' from gpiolib. This patch can be squashed with below commit in topic/crc-pmic branch commit 61dd2ca2d44e493b050adbbb75bc50db11c367dd Author: Shobhit Kumar Date: Fri Jun 26 14:32:05 2015 +0530 mfd: intel_soc_pmic_core: Add lookup table for Panel Control as GPIO signal On some Intel SoC platforms, the panel enable/disable signals are controlled by CRC PMIC. Add those control as a new GPIO in a lookup table for gpio-crystalcove chip during CRC driver load Cc: Lee Jones Cc: Linus Walleij Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/mfd/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 653815950aa2..379a420245ea 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -318,6 +318,7 @@ config LPC_SCH config INTEL_SOC_PMIC bool "Support for Intel Atom SoC PMIC" + depends on GPIOLIB depends on I2C=y select MFD_CORE select REGMAP_I2C -- cgit v1.3-6-gb490 From c99235fa3ef833c3c23926085f2bb68851c8460a Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Wed, 15 Jul 2015 18:00:06 -0300 Subject: [media] media: am437x-vpfe: Fix a race condition during release There was a race condition where during cleanup/release operation on-going streaming would cause a kernel panic because the hardware module was disabled prematurely with IRQ still pending. Fixes: 417d2e507edc ("[media] media: platform: add VPFE capture driver support for AM437X") Cc: # v4.0+ Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/am437x/am437x-vpfe.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 1fed7a56c8ae..c8447fa3fd91 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1186,14 +1186,24 @@ static int vpfe_initialize_device(struct vpfe_device *vpfe) static int vpfe_release(struct file *file) { struct vpfe_device *vpfe = video_drvdata(file); + bool fh_singular; int ret; mutex_lock(&vpfe->lock); - if (v4l2_fh_is_singular_file(file)) - vpfe_ccdc_close(&vpfe->ccdc, vpfe->pdev); + /* Save the singular status before we call the clean-up helper */ + fh_singular = v4l2_fh_is_singular_file(file); + + /* the release helper will cleanup any on-going streaming */ ret = _vb2_fop_release(file, NULL); + /* + * If this was the last open file. + * Then de-initialize hw module. + */ + if (fh_singular) + vpfe_ccdc_close(&vpfe->ccdc, vpfe->pdev); + mutex_unlock(&vpfe->lock); return ret; -- cgit v1.3-6-gb490 From 810c168c233fc531ecd3e7a6d9e0b5a3ffe85da7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 17 Jul 2015 08:29:40 -0300 Subject: [media] cobalt: accept unchanged timings when vb2_is_busy() When vb2_is_busy() it should still be possible to call S_DV_TIMINGS provided the new timings are the same as the current timings. For input 1 (test generator) the size is always 1080p, so just return that. Fixes a v4l2-compliance issue. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cobalt/cobalt-v4l2.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index b40c2d141b58..9756fd3e8af5 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -641,13 +642,17 @@ static int cobalt_s_dv_timings(struct file *file, void *priv_fh, struct cobalt_stream *s = video_drvdata(file); int err; - if (vb2_is_busy(&s->q)) - return -EBUSY; - if (s->input == 1) { *timings = cea1080p60; return 0; } + + if (v4l2_match_dv_timings(timings, &s->timings, 0)) + return 0; + + if (vb2_is_busy(&s->q)) + return -EBUSY; + err = v4l2_subdev_call(s->sd, video, s_dv_timings, timings); if (!err) { -- cgit v1.3-6-gb490 From 55b858b4e5f46e71f9e5089cb63602697a49a211 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 17 Jul 2015 08:45:22 -0300 Subject: [media] cobalt: allow fewer than 8 PCIe lanes Currently the cobalt driver refuses to load if fewer than 8 PCIe lanes are assigned. This patch changes this and just issues a warning. The only time it will refuse to load is if the number of assigned lanes is less than what the PCIe host is capable of since this suggests that the card isn't seated correctly in the slot. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cobalt/cobalt-driver.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index b994b8efdc99..8fed61ec712e 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -339,15 +339,16 @@ static int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev, } if (pcie_link_get_lanes(cobalt) != 8) { - cobalt_err("PCI Express link width is not 8 lanes (%d)\n", + cobalt_warn("PCI Express link width is %d lanes.\n", pcie_link_get_lanes(cobalt)); if (pcie_bus_link_get_lanes(cobalt) < 8) - cobalt_err("The current slot only supports %d lanes, at least 8 are needed\n", + cobalt_warn("The current slot only supports %d lanes, for best performance 8 are needed\n", pcie_bus_link_get_lanes(cobalt)); - else + if (pcie_link_get_lanes(cobalt) != pcie_bus_link_get_lanes(cobalt)) { cobalt_err("The card is most likely not seated correctly in the PCIe slot\n"); - ret = -EIO; - goto err_disable; + ret = -EIO; + goto err_disable; + } } if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64))) { -- cgit v1.3-6-gb490 From 4c5211a100399c3823563193dd881dcb3b7d24fc Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 17 Jul 2015 11:02:53 -0300 Subject: [media] tc358743: register v4l2 asynchronous subdevice Add support for registering the sensor subdevice using the v4l2-async API. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 4e8811c3e771..7278435048ed 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1710,6 +1710,16 @@ static int tc358743_probe(struct i2c_client *client, goto err_hdl; } + state->pad.flags = MEDIA_PAD_FL_SOURCE; + err = media_entity_init(&sd->entity, 1, &state->pad, 0); + if (err < 0) + goto err_hdl; + + sd->dev = &client->dev; + err = v4l2_async_register_subdev(sd); + if (err < 0) + goto err_hdl; + mutex_init(&state->confctl_mutex); INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, @@ -1740,6 +1750,7 @@ err_work_queues: destroy_workqueue(state->work_queues); mutex_destroy(&state->confctl_mutex); err_hdl: + media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(&state->hdl); return err; } @@ -1751,8 +1762,10 @@ static int tc358743_remove(struct i2c_client *client) cancel_delayed_work(&state->delayed_work_enable_hotplug); destroy_workqueue(state->work_queues); + v4l2_async_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); mutex_destroy(&state->confctl_mutex); + media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(&state->hdl); return 0; -- cgit v1.3-6-gb490 From 8ec23da73599848a5a5ecbab50f17a570b60c096 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 17 Jul 2015 11:02:54 -0300 Subject: [media] tc358743: enable v4l2 subdevice devnode Add V4L2_SUBDEV_FL_HAS_DEVNODE to subdev flags, in order to enable a subdev device node. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 7278435048ed..0ccae3308b68 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1668,7 +1668,7 @@ static int tc358743_probe(struct i2c_client *client, state->i2c_client = client; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &tc358743_ops); - sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; /* i2c access */ if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) { -- cgit v1.3-6-gb490 From 4ea50e99bd3501aea394aa7a9e9bd3115faabf37 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:24 +0200 Subject: drm: Simplify drm_for_each_legacy_plane arguments No need to pass the planelist when everyone just uses dev->mode_config.plane_list anyway. I want to add a pile more of iterators with unified (obj, dev) arguments. This is just prep. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 2 +- include/drm/drm_crtc.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0d3e01434860..5004c4a46a9e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2356,7 +2356,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc, p->pri.horiz_pixels = intel_crtc->config->pipe_src_w; p->cur.horiz_pixels = intel_crtc->base.cursor->state->crtc_w; - drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { + drm_for_each_legacy_plane(plane, dev) { struct intel_plane *intel_plane = to_intel_plane(plane); if (intel_plane->pipe == pipe) { diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 859ccb658601..e9272b0a8592 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -248,7 +248,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) lcdc_write(sdev, LDDDSR, value); /* Setup planes. */ - drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { + drm_for_each_legacy_plane(plane, dev) { if (plane->crtc == crtc) shmob_drm_plane_setup(plane); } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 57ca8cc383a6..5cf0e6c3fc41 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1579,8 +1579,8 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev, } /* Plane list iterator for legacy (overlay only) planes. */ -#define drm_for_each_legacy_plane(plane, planelist) \ - list_for_each_entry(plane, planelist, head) \ +#define drm_for_each_legacy_plane(plane, dev) \ + list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \ if (plane->type == DRM_PLANE_TYPE_OVERLAY) #endif /* __DRM_CRTC_H__ */ -- cgit v1.3-6-gb490 From 6295d607ad34ee4e43aab3f20714c2ef7a6adea1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:25 +0200 Subject: drm: Add modeset object iterators And roll them out across drm_* files. The point here isn't code prettification (it helps with that too) but that some of these lists aren't static any more. And having macros will gives us a convenient place to put locking checks into. I didn't add an iterator for props since that's only used by a list_for_each_entry_safe in the driver teardown code. Search&replace was done with the below cocci spatch. Note that there's a bunch more places that didn't match and which would need some manual changes, but I've intentially left these out for this mostly automated patch. iterator name drm_for_each_crtc; struct drm_crtc *crtc; struct drm_device *dev; expression head; @@ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc (crtc, dev) { ... } @@ iterator name drm_for_each_encoder; struct drm_encoder *encoder; struct drm_device *dev; expression head; @@ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder (encoder, dev) { ... } @@ iterator name drm_for_each_fb; struct drm_framebuffer *fb; struct drm_device *dev; expression head; @@ - list_for_each_entry(fb, &dev->mode_config.fb_list, head) { + drm_for_each_fb (fb, dev) { ... } @@ iterator name drm_for_each_connector; struct drm_connector *connector; struct drm_device *dev; expression head; @@ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector (connector, dev) { ... } Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 21 ++++++++------------- drivers/gpu/drm/drm_crtc_helper.c | 34 +++++++++++++++++----------------- drivers/gpu/drm/drm_fb_helper.c | 10 +++++----- drivers/gpu/drm/drm_of.c | 2 +- drivers/gpu/drm/drm_probe_helper.c | 6 +++--- include/drm/drm_crtc.h | 15 +++++++++++++++ 6 files changed, 49 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 9c978d9de3b8..9b05dc76379e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -615,7 +615,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) if (atomic_read(&fb->refcount.refcount) > 1) { drm_modeset_lock_all(dev); /* remove from any CRTC */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(crtc, dev) { if (crtc->primary->fb == fb) { /* should turn off the crtc */ memset(&set, 0, sizeof(struct drm_mode_set)); @@ -627,7 +627,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) } } - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + drm_for_each_plane(plane, dev) { if (plane->fb == fb) drm_plane_force_disable(plane); } @@ -1305,7 +1305,7 @@ drm_plane_from_index(struct drm_device *dev, int idx) struct drm_plane *plane; unsigned int i = 0; - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + drm_for_each_plane(plane, dev) { if (i == idx) return plane; i++; @@ -1838,8 +1838,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, copied = 0; crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; if (!mode_group) { - list_for_each_entry(crtc, &dev->mode_config.crtc_list, - head) { + drm_for_each_crtc(crtc, dev) { DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); if (put_user(crtc->base.id, crtc_id + copied)) { ret = -EFAULT; @@ -1865,9 +1864,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, copied = 0; encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; if (!mode_group) { - list_for_each_entry(encoder, - &dev->mode_config.encoder_list, - head) { + drm_for_each_encoder(encoder, dev) { DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, encoder->name); if (put_user(encoder->base.id, encoder_id + @@ -1896,9 +1893,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, copied = 0; connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; if (!mode_group) { - list_for_each_entry(connector, - &dev->mode_config.connector_list, - head) { + drm_for_each_connector(connector, dev) { DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -2187,7 +2182,7 @@ static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) /* For atomic drivers only state objects are synchronously updated and * protected by modeset locks, so check those first. */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { if (!connector->state) continue; @@ -5393,7 +5388,7 @@ void drm_mode_config_reset(struct drm_device *dev) if (encoder->funcs->reset) encoder->funcs->reset(encoder); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { connector->status = connector_status_unknown; if (connector->funcs->reset) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 393114df88a3..30254fb249fe 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -180,7 +180,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) drm_warn_on_modeset_not_all_locked(dev); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (!drm_helper_encoder_in_use(encoder)) { drm_encoder_disable(encoder); /* disconnect encoder from any connector */ @@ -188,7 +188,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) } } - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(crtc, dev) { const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; crtc->enabled = drm_helper_crtc_in_use(crtc); if (!crtc->enabled) { @@ -230,7 +230,7 @@ drm_crtc_prepare_encoders(struct drm_device *dev) const struct drm_encoder_helper_funcs *encoder_funcs; struct drm_encoder *encoder; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { encoder_funcs = encoder->helper_private; /* Disable unused encoders */ if (encoder->crtc == NULL) @@ -305,7 +305,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) continue; @@ -334,7 +334,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, crtc->hwmode = *adjusted_mode; /* Prepare the encoders and CRTCs before setting the mode. */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) continue; @@ -359,7 +359,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, if (!ret) goto done; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) continue; @@ -376,7 +376,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, /* Now enable the clocks, plane, pipe, and connectors that we set up. */ crtc_funcs->commit(crtc); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) continue; @@ -418,11 +418,11 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) struct drm_encoder *encoder; /* Decouple all encoders and their attached connectors from this crtc */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) continue; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { if (connector->encoder != encoder) continue; @@ -519,12 +519,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) * restored, not the drivers personal bookkeeping. */ count = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { save_encoders[count++] = *encoder; } count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { save_connectors[count++] = *connector; } @@ -562,7 +562,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) /* a) traverse passed in connector list and get encoders for them */ count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; new_encoder = connector->encoder; @@ -602,7 +602,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) } count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { if (!connector->encoder) continue; @@ -685,12 +685,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) fail: /* Restore all previous data. */ count = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { *encoder = save_encoders[count++]; } count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { *connector = save_connectors[count++]; } @@ -862,7 +862,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev) bool ret; drm_modeset_lock_all(dev); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(crtc, dev) { if (!crtc->enabled) continue; @@ -876,7 +876,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev) /* Turn off outputs that were already powered off */ if (drm_helper_choose_crtc_dpms(crtc)) { - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if(encoder->crtc != crtc) continue; diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index cac422916c7a..3630d92c9738 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -98,7 +98,7 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) struct drm_connector *connector; int i; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { struct drm_fb_helper_connector *fb_helper_connector; fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); @@ -269,7 +269,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_crtc *c; - list_for_each_entry(c, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(c, dev) { if (crtc->base.id == c->base.id) return c->primary->fb; } @@ -321,7 +321,7 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper) drm_warn_on_modeset_not_all_locked(dev); - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + drm_for_each_plane(plane, dev) { if (plane->type != DRM_PLANE_TYPE_PRIMARY) drm_plane_force_disable(plane); @@ -458,7 +458,7 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) if (dev->primary->master) return false; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(crtc, dev) { if (crtc->primary->fb) crtcs_bound++; if (crtc->primary->fb == fb_helper->fb) @@ -655,7 +655,7 @@ int drm_fb_helper_init(struct drm_device *dev, } i = 0; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(crtc, dev) { fb_helper->crtc_info[i].mode_set.crtc = crtc; i++; } diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index aaa130736bf8..be3884073ea4 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -19,7 +19,7 @@ static uint32_t drm_crtc_port_mask(struct drm_device *dev, unsigned int index = 0; struct drm_crtc *tmp; - list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(tmp, dev) { if (tmp->port == port) return 1 << index; diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 04203c0d2ecb..64d85c1bd18b 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -312,7 +312,7 @@ static void output_poll_execute(struct work_struct *work) goto out; mutex_lock(&dev->mode_config.mutex); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { /* Ignore forced connectors. */ if (connector->force) @@ -413,7 +413,7 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) return; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT)) poll = true; @@ -495,7 +495,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) return false; mutex_lock(&dev->mode_config.mutex); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { /* Only handle HPD capable connectors. */ if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 5cf0e6c3fc41..7c95a7df6065 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1583,4 +1583,19 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev, list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \ if (plane->type == DRM_PLANE_TYPE_OVERLAY) +#define drm_for_each_plane(plane, dev) \ + list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) + +#define drm_for_each_crtc(crtc, dev) \ + list_for_each_entry(crtc, &(dev)->mode_config.crtc_list, head) + +#define drm_for_each_connector(connector, dev) \ + list_for_each_entry(connector, &(dev)->mode_config.connector_list, head) + +#define drm_for_each_encoder(encoder, dev) \ + list_for_each_entry(encoder, &(dev)->mode_config.encoder_list, head) + +#define drm_for_each_fb(fb, dev) \ + list_for_each_entry(fb, &(dev)->mode_config.fb_list, head) + #endif /* __DRM_CRTC_H__ */ -- cgit v1.3-6-gb490 From 8c4ccc4ab6f64e859d4ff8d7c02c2ed2e956e07f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:26 +0200 Subject: drm/probe-helper: Grab mode_config.mutex in poll_init/enable So on first looks this seems superflous since drivers should ensure correct ordering to not make this a problem. Otoh ordering constraints between hdp, fbdev load and enabling polling are already tricky on some hardware and it helps to be more robust. But the real goal is to just shut up a locking WARN_ON I'd like to add, which means init code gets some additional locks just for uniformity. v2: Also grab the lock for the public poll_enable, not just poll_init which is used for resume, with the same justification. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_probe_helper.c | 41 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 64d85c1bd18b..d734780b31c0 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -93,6 +93,27 @@ static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector) return 1; } +#define DRM_OUTPUT_POLL_PERIOD (10*HZ) +static void __drm_kms_helper_poll_enable(struct drm_device *dev) +{ + bool poll = false; + struct drm_connector *connector; + + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + + if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) + return; + + drm_for_each_connector(connector, dev) { + if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT)) + poll = true; + } + + if (poll) + schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); +} + static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, uint32_t maxX, uint32_t maxY, bool merge_type_bits) { @@ -153,7 +174,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect /* Re-enable polling in case the global poll config changed. */ if (drm_kms_helper_poll != dev->mode_config.poll_running) - drm_kms_helper_poll_enable(dev); + __drm_kms_helper_poll_enable(dev); dev->mode_config.poll_running = drm_kms_helper_poll; @@ -295,7 +316,6 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev) } EXPORT_SYMBOL(drm_kms_helper_hotplug_event); -#define DRM_OUTPUT_POLL_PERIOD (10*HZ) static void output_poll_execute(struct work_struct *work) { struct delayed_work *delayed_work = to_delayed_work(work); @@ -407,20 +427,9 @@ EXPORT_SYMBOL(drm_kms_helper_poll_disable); */ void drm_kms_helper_poll_enable(struct drm_device *dev) { - bool poll = false; - struct drm_connector *connector; - - if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) - return; - - drm_for_each_connector(connector, dev) { - if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT)) - poll = true; - } - - if (poll) - schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); + mutex_lock(&dev->mode_config.mutex); + __drm_kms_helper_poll_enable(dev); + mutex_unlock(&dev->mode_config.mutex); } EXPORT_SYMBOL(drm_kms_helper_poll_enable); -- cgit v1.3-6-gb490 From 169faecadd2444fc295c724c0a2f622b99e6bf19 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:27 +0200 Subject: drm/fbdev-helper: Grab mode_config.mutex in drm_fb_helper_single_add_all_connectors This is now truly only duct-tape to keep locking checks happy since calling this function when hpd or polling are already enabled is a bug. The fbdev helper can't cope with hotplug changes yet at this point, only after that. Otoh a bit more robustness in this function can't hurt, and with this fbdev can actually cope with hotplug changes. And it's also more consistent with the connector hotadd/remove dp mst needs to do. Therefore document this as new official behavior. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 3630d92c9738..329d08167b77 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -89,8 +89,9 @@ static LIST_HEAD(kernel_fb_helper_list); * connectors to the fbdev, e.g. if some are reserved for special purposes or * not adequate to be used for the fbcon. * - * Since this is part of the initial setup before the fbdev is published, no - * locking is required. + * This function is protected against concurrent connector hotadds/removals + * using drm_fb_helper_add_one_connector() and + * drm_fb_helper_remove_one_connector(). */ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) { @@ -98,6 +99,7 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) struct drm_connector *connector; int i; + mutex_lock(&dev->mode_config.mutex); drm_for_each_connector(connector, dev) { struct drm_fb_helper_connector *fb_helper_connector; @@ -108,6 +110,7 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) fb_helper_connector->connector = connector; fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; } + mutex_unlock(&dev->mode_config.mutex); return 0; fail: for (i = 0; i < fb_helper->connector_count; i++) { @@ -115,6 +118,8 @@ fail: fb_helper->connector_info[i] = NULL; } fb_helper->connector_count = 0; + mutex_unlock(&dev->mode_config.mutex); + return -ENOMEM; } EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); -- cgit v1.3-6-gb490 From 3a58ee106529ebea5710087e9b77bc11365665ae Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 10 Jul 2015 19:02:51 +0200 Subject: drm/i915: Use drm_for_each_fb in i915_debugfs.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just so I have a user for this macro. v2: Use the right macro - somehow I thought gcc should scream at me, but list_for_each isn't really typesafe unfortunately. Spotted by Ville. Cc: Ville Syrjälä Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index bc817da9fef7..51580bdd587f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1866,6 +1866,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct intel_fbdev *ifbdev = NULL; struct intel_framebuffer *fb; + struct drm_framebuffer *drm_fb; #ifdef CONFIG_DRM_I915_FBDEV struct drm_i915_private *dev_priv = dev->dev_private; @@ -1885,7 +1886,8 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) #endif mutex_lock(&dev->mode_config.fb_lock); - list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) { + drm_for_each_fb(drm_fb, dev) { + fb = to_intel_framebuffer(drm_fb); if (ifbdev && &fb->base == ifbdev->helper.fb) continue; -- cgit v1.3-6-gb490 From 8bb4da1df54a20d68c34427356e34315ba122c0f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:31 +0200 Subject: drm/i915: Take all modeset locks for DP MST hotplug While auditing various users of the connector/encoder lists I realized that the atomic code is a very prolific user of them. And it only ever grabs the mode_config->connection_mutex, but not the mode_config->mutex like all the other code walking encoder/connector lists. The problem is that we can't grab the mode_config.mutex late in atomic code since that would lead to locking inversions. And we don't want to grab it unconditionally like the legacy set_config modeset path since that would render all the fine-grained locking moot. Instead just grab more locks in the dp mst hotplug code. Note that drm_connector_init (which is the one adding the connector to these lists) already uses drm_modeset_lock_all. The other reason for grabbing all locks is that the dpms off in the unplug function amounts to a modeset, so better to take all required locks for that. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp_mst.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 6e4cc5334f47..d0b2569c6241 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -442,9 +442,9 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo drm_mode_connector_set_path_property(connector, pathprop); drm_reinit_primary_mode_group(dev); - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); intel_connector_add_to_fbdev(intel_connector); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); drm_connector_register(&intel_connector->base); return connector; } @@ -455,16 +455,16 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_device *dev = connector->dev; /* need to nuke the connector */ - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); intel_connector_dpms(connector, DRM_MODE_DPMS_OFF); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); intel_connector->unregister(intel_connector); - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); intel_connector_remove_from_fbdev(intel_connector); drm_connector_cleanup(connector); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); drm_reinit_primary_mode_group(dev); -- cgit v1.3-6-gb490 From 2ee6bcdcfa4d8b56b20bc6308cd5f9bced5b5324 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:32 +0200 Subject: drm/radeon: Take all modeset locks for DP MST hotplug Similar with the i915 take all modeset locks for mst hotplug. This is needed to make sure radeon holds both mode_config.mutex and mode_config.connection_mutex when updating the connector_list, which is the new (interim) locking regime we want for that. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/radeon/radeon_dp_mst.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 257b10be5cda..e649c8ff20a0 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -286,9 +286,9 @@ static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topol drm_mode_connector_set_path_property(connector, pathprop); drm_reinit_primary_mode_group(dev); - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); radeon_fb_add_connector(rdev, connector); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); drm_connector_register(connector); return connector; @@ -303,12 +303,12 @@ static void radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, drm_connector_unregister(connector); /* need to nuke the connector */ - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); /* dpms off */ radeon_fb_remove_connector(rdev, connector); drm_connector_cleanup(connector); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); drm_reinit_primary_mode_group(dev); -- cgit v1.3-6-gb490 From 9a9f5ce8db176499a7f3f93172bf34176aa460f5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:34 +0200 Subject: drm: Roll out drm_for_each_connector more Now that we also grab the connection_mutex and so fixed the race with atomic modeset we can use the iterator there too. The other special case is drm_connector_unplug_all which would have a locking inversion with the sysfs store/show functions if we'd grab the mode_config.mutex around the unplug. We could just grab connection_mutex instead, but that's a bit too much a dirty trick for my taste. Also it's only used by udl, which doesn't do any other kind of connector hotplugging, so should be race-free. Hence just stick with a comment for now. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 2 +- drivers/gpu/drm/drm_atomic_helper.c | 4 ++-- drivers/gpu/drm/drm_crtc.c | 9 +++++---- drivers/gpu/drm/drm_crtc_helper.c | 6 +++--- drivers/gpu/drm/drm_edid.c | 2 +- drivers/gpu/drm/drm_plane_helper.c | 3 ++- 6 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f6f2fb58eb37..dfc8aaa1457e 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1063,7 +1063,7 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state, * Changed connectors are already in @state, so only need to look at the * current configuration. */ - list_for_each_entry(connector, &config->connector_list, head) { + drm_for_each_connector(connector, state->dev) { if (connector->state->crtc != crtc) continue; diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 5b59d5ad7d1c..4ff334ba0382 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -89,7 +89,7 @@ get_current_crtc_for_encoder(struct drm_device *dev, WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); - list_for_each_entry(connector, &config->connector_list, head) { + drm_for_each_connector(connector, dev) { if (connector->state->best_encoder != encoder) continue; @@ -1986,7 +1986,7 @@ retry: WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); - list_for_each_entry(tmp_connector, &config->connector_list, head) { + drm_for_each_connector(tmp_connector, connector->dev) { if (tmp_connector->state->crtc != crtc) continue; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 9b05dc76379e..d928bf7ef221 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -988,7 +988,7 @@ unsigned int drm_connector_index(struct drm_connector *connector) WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); - list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) { + drm_for_each_connector(tmp, connector->dev) { if (tmp == connector) return index; @@ -1054,7 +1054,7 @@ void drm_connector_unplug_all(struct drm_device *dev) { struct drm_connector *connector; - /* taking the mode config mutex ends up in a clash with sysfs */ + /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) drm_connector_unregister(connector); @@ -1726,7 +1726,7 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, group->id_list[group->num_crtcs + group->num_encoders++] = encoder->base.id; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) group->id_list[group->num_crtcs + group->num_encoders + group->num_connectors++] = connector->base.id; @@ -1810,12 +1810,13 @@ int drm_mode_getresources(struct drm_device *dev, void *data, * connector hot-adding. CRTC/Plane lists are invariant. */ mutex_lock(&dev->mode_config.mutex); if (!drm_is_primary_client(file_priv)) { + struct drm_connector *connector; mode_group = NULL; list_for_each(lh, &dev->mode_config.crtc_list) crtc_count++; - list_for_each(lh, &dev->mode_config.connector_list) + drm_for_each_connector(connector, dev) connector_count++; list_for_each(lh, &dev->mode_config.encoder_list) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 30254fb249fe..4a83c22f5e61 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -121,7 +121,7 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder) WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); } - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) if (connector->encoder == encoder) return true; return false; @@ -712,7 +712,7 @@ static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) struct drm_connector *connector; struct drm_device *dev = encoder->dev; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) if (connector->encoder == encoder) if (connector->dpms < dpms) dpms = connector->dpms; @@ -746,7 +746,7 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc) struct drm_connector *connector; struct drm_device *dev = crtc->dev; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) if (connector->encoder && connector->encoder->crtc == crtc) if (connector->dpms < dpms) dpms = connector->dpms; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 7087da37dae0..e6e05bb75a77 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3413,7 +3413,7 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder, WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) if (connector->encoder == encoder && connector->eld[0]) return connector; diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 2f0ed11024eb..7e1cde803bf3 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -91,13 +91,14 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc, */ WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) { if (connector->encoder && connector->encoder->crtc == crtc) { if (connector_list != NULL && count < num_connectors) *(connector_list++) = connector; count++; } + } return count; } -- cgit v1.3-6-gb490 From be559daabfaac74a7acd8cb56fae86fca7349f10 Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Wed, 22 Jul 2015 11:48:09 +0300 Subject: dmaengine: ti-dma-crossbar: Make idr xbar instance-specific In preparation for supporting multiple DMA crossbar instances, make the idr xbar instance specific. Signed-off-by: Misael Lopez Cruz Signed-off-by: Peter Ujfalusi Signed-off-by: Vinod Koul --- drivers/dma/ti-dma-crossbar.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c index 24f5ca2356bf..1fd3fb73d6e8 100644 --- a/drivers/dma/ti-dma-crossbar.c +++ b/drivers/dma/ti-dma-crossbar.c @@ -20,12 +20,11 @@ #define TI_XBAR_OUTPUTS 127 #define TI_XBAR_INPUTS 256 -static DEFINE_IDR(map_idr); - struct ti_dma_xbar_data { void __iomem *iomem; struct dma_router dmarouter; + struct idr map_idr; u16 safe_val; /* Value to rest the crossbar lines */ u32 xbar_requests; /* number of DMA requests connected to XBAR */ @@ -51,7 +50,7 @@ static void ti_dma_xbar_free(struct device *dev, void *route_data) map->xbar_in, map->xbar_out); ti_dma_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val); - idr_remove(&map_idr, map->xbar_out); + idr_remove(&xbar->map_idr, map->xbar_out); kfree(map); } @@ -81,7 +80,7 @@ static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec, return ERR_PTR(-ENOMEM); } - map->xbar_out = idr_alloc(&map_idr, NULL, 0, xbar->dma_requests, + map->xbar_out = idr_alloc(&xbar->map_idr, NULL, 0, xbar->dma_requests, GFP_KERNEL); map->xbar_in = (u16)dma_spec->args[0]; @@ -113,6 +112,8 @@ static int ti_dma_xbar_probe(struct platform_device *pdev) if (!xbar) return -ENOMEM; + idr_init(&xbar->map_idr); + dma_node = of_parse_phandle(node, "dma-masters", 0); if (!dma_node) { dev_err(&pdev->dev, "Can't get DMA master node\n"); -- cgit v1.3-6-gb490 From 1eb995bbf7a85e18f54fb162eade381320a3fcea Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 22 Jul 2015 11:48:10 +0300 Subject: dmaengine: ti-dma-crossbar: Add support for eDMA The crossbar for eDMA works exactly the same way as sDMA, but sDMA requires an offset of 1, while no offset is needed for eDMA. Based on the patch from Misael Lopez Cruz Signed-off-by: Peter Ujfalusi CC: Misael Lopez Cruz Signed-off-by: Vinod Koul --- drivers/dma/ti-dma-crossbar.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c index 1fd3fb73d6e8..10487d91e60d 100644 --- a/drivers/dma/ti-dma-crossbar.c +++ b/drivers/dma/ti-dma-crossbar.c @@ -20,6 +20,9 @@ #define TI_XBAR_OUTPUTS 127 #define TI_XBAR_INPUTS 256 +#define TI_XBAR_EDMA_OFFSET 0 +#define TI_XBAR_SDMA_OFFSET 1 + struct ti_dma_xbar_data { void __iomem *iomem; @@ -29,6 +32,7 @@ struct ti_dma_xbar_data { u16 safe_val; /* Value to rest the crossbar lines */ u32 xbar_requests; /* number of DMA requests connected to XBAR */ u32 dma_requests; /* number of DMA requests forwarded to DMA */ + u32 dma_offset; }; struct ti_dma_xbar_map { @@ -84,8 +88,7 @@ static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec, GFP_KERNEL); map->xbar_in = (u16)dma_spec->args[0]; - /* The DMA request is 1 based in sDMA */ - dma_spec->args[0] = map->xbar_out + 1; + dma_spec->args[0] = map->xbar_out + xbar->dma_offset; dev_dbg(&pdev->dev, "Mapping XBAR%u to DMA%d\n", map->xbar_in, map->xbar_out); @@ -95,9 +98,22 @@ static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec, return map; } +static const struct of_device_id ti_dma_master_match[] = { + { + .compatible = "ti,omap4430-sdma", + .data = (void *)TI_XBAR_SDMA_OFFSET, + }, + { + .compatible = "ti,edma3", + .data = (void *)TI_XBAR_EDMA_OFFSET, + }, + {}, +}; + static int ti_dma_xbar_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; + const struct of_device_id *match; struct device_node *dma_node; struct ti_dma_xbar_data *xbar; struct resource *res; @@ -120,6 +136,12 @@ static int ti_dma_xbar_probe(struct platform_device *pdev) return -ENODEV; } + match = of_match_node(ti_dma_master_match, dma_node); + if (!match) { + dev_err(&pdev->dev, "DMA master is not supported\n"); + return -EINVAL; + } + if (of_property_read_u32(dma_node, "dma-requests", &xbar->dma_requests)) { dev_info(&pdev->dev, @@ -151,6 +173,7 @@ static int ti_dma_xbar_probe(struct platform_device *pdev) xbar->dmarouter.dev = &pdev->dev; xbar->dmarouter.route_free = ti_dma_xbar_free; + xbar->dma_offset = (u32)match->data; platform_set_drvdata(pdev, xbar); -- cgit v1.3-6-gb490 From 25614824685247e00b786032a504f10bfab347b1 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 17 Jul 2015 11:02:55 -0300 Subject: [media] tc358743: support probe from device tree Add support for probing the TC358743 subdevice from device tree. The reference clock must be supplied using the common clock bindings. MIPI CSI-2 specific properties are parsed from the OF graph endpoint node and support for a non-continuous MIPI CSI-2 clock is added. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/tc358743.txt | 48 +++++++ drivers/media/i2c/tc358743.c | 155 ++++++++++++++++++++- 2 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/i2c/tc358743.txt (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/media/i2c/tc358743.txt b/Documentation/devicetree/bindings/media/i2c/tc358743.txt new file mode 100644 index 000000000000..5218921629ed --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/tc358743.txt @@ -0,0 +1,48 @@ +* Toshiba TC358743 HDMI-RX to MIPI CSI2-TX Bridge + +The Toshiba TC358743 HDMI-RX to MIPI CSI2-TX (H2C) is a bridge that converts +a HDMI stream to MIPI CSI-2 TX. It is programmable through I2C. + +Required Properties: + +- compatible: value should be "toshiba,tc358743" +- clocks, clock-names: should contain a phandle link to the reference clock + source, the clock input is named "refclk". + +Optional Properties: + +- reset-gpios: gpio phandle GPIO connected to the reset pin +- interrupts, interrupt-parent: GPIO connected to the interrupt pin +- data-lanes: should be <1 2 3 4> for four-lane operation, + or <1 2> for two-lane operation +- clock-lanes: should be <0> +- clock-noncontinuous: Presence of this boolean property decides whether the + MIPI CSI-2 clock is continuous or non-continuous. +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is + expressed as a 64-bit big-endian integer. The frequency + is half of the bps per lane due to DDR transmission. + +For further information on the MIPI CSI-2 endpoint node properties, see +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + tc358743@0f { + compatible = "toshiba,tc358743"; + reg = <0x0f>; + clocks = <&hdmi_osc>; + clock-names = "refclk"; + reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; + interrupt-parent = <&gpio2>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + + port { + tc358743_out: endpoint { + remote-endpoint = <&mipi_csi2_in>; + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + clock-noncontinuous; + link-frequencies = /bits/ 64 <297000000>; + }; + }; + }; diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 0ccae3308b68..76d0aaa19493 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -29,7 +29,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -37,6 +39,7 @@ #include #include #include +#include #include #include "tc358743_regs.h" @@ -69,6 +72,7 @@ static const struct v4l2_dv_timings_cap tc358743_timings_cap = { struct tc358743_state { struct tc358743_platform_data pdata; + struct v4l2_of_bus_mipi_csi2 bus; struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler hdl; @@ -90,6 +94,8 @@ struct tc358743_state { struct v4l2_dv_timings timings; u32 mbus_fmt_code; + + struct gpio_desc *reset_gpio; }; static void tc358743_enable_interrupts(struct v4l2_subdev *sd, @@ -700,7 +706,8 @@ static void tc358743_set_csi(struct v4l2_subdev *sd) ((lanes > 2) ? MASK_D2M_HSTXVREGEN : 0x0) | ((lanes > 3) ? MASK_D3M_HSTXVREGEN : 0x0)); - i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE); + i2c_wr32(sd, TXOPTIONCNTRL, (state->bus.flags & + V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) ? MASK_CONTCLKMODE : 0); i2c_wr32(sd, STARTCNTRL, MASK_START); i2c_wr32(sd, CSI_START, MASK_STRT); @@ -1638,6 +1645,136 @@ static const struct v4l2_ctrl_config tc358743_ctrl_audio_present = { /* --------------- PROBE / REMOVE --------------- */ +#ifdef CONFIG_OF +static void tc358743_gpio_reset(struct tc358743_state *state) +{ + gpiod_set_value(state->reset_gpio, 0); + usleep_range(5000, 10000); + gpiod_set_value(state->reset_gpio, 1); + usleep_range(1000, 2000); + gpiod_set_value(state->reset_gpio, 0); + msleep(20); +} + +static int tc358743_probe_of(struct tc358743_state *state) +{ + struct device *dev = &state->i2c_client->dev; + struct v4l2_of_endpoint *endpoint; + struct device_node *ep; + struct clk *refclk; + u32 bps_pr_lane; + int ret = -EINVAL; + + refclk = devm_clk_get(dev, "refclk"); + if (IS_ERR(refclk)) { + if (PTR_ERR(refclk) != -EPROBE_DEFER) + dev_err(dev, "failed to get refclk: %ld\n", + PTR_ERR(refclk)); + return PTR_ERR(refclk); + } + + ep = of_graph_get_next_endpoint(dev->of_node, NULL); + if (!ep) { + dev_err(dev, "missing endpoint node\n"); + return -EINVAL; + } + + endpoint = v4l2_of_alloc_parse_endpoint(ep); + if (IS_ERR(endpoint)) { + dev_err(dev, "failed to parse endpoint\n"); + return PTR_ERR(endpoint); + } + + if (endpoint->bus_type != V4L2_MBUS_CSI2 || + endpoint->bus.mipi_csi2.num_data_lanes == 0 || + endpoint->nr_of_link_frequencies == 0) { + dev_err(dev, "missing CSI-2 properties in endpoint\n"); + goto free_endpoint; + } + + state->bus = endpoint->bus.mipi_csi2; + + clk_prepare_enable(refclk); + + state->pdata.refclk_hz = clk_get_rate(refclk); + state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS; + state->pdata.enable_hdcp = false; + /* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */ + state->pdata.fifo_level = 16; + /* + * The PLL input clock is obtained by dividing refclk by pll_prd. + * It must be between 6 MHz and 40 MHz, lower frequency is better. + */ + switch (state->pdata.refclk_hz) { + case 26000000: + case 27000000: + case 42000000: + state->pdata.pll_prd = state->pdata.refclk_hz / 6000000; + break; + default: + dev_err(dev, "unsupported refclk rate: %u Hz\n", + state->pdata.refclk_hz); + goto disable_clk; + } + + /* + * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. + * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60. + */ + bps_pr_lane = 2 * endpoint->link_frequencies[0]; + if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { + dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane); + goto disable_clk; + } + + /* The CSI speed per lane is refclk / pll_prd * pll_fbd */ + state->pdata.pll_fbd = bps_pr_lane / + state->pdata.refclk_hz * state->pdata.pll_prd; + + /* + * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz + * link frequency). In principle it should be possible to calculate + * them based on link frequency and resolution. + */ + if (bps_pr_lane != 594000000U) + dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane); + state->pdata.lineinitcnt = 0xe80; + state->pdata.lptxtimecnt = 0x003; + /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ + state->pdata.tclk_headercnt = 0x1403; + state->pdata.tclk_trailcnt = 0x00; + /* ths-preparecnt: 3, ths-zerocnt: 1 */ + state->pdata.ths_headercnt = 0x0103; + state->pdata.twakeup = 0x4882; + state->pdata.tclk_postcnt = 0x008; + state->pdata.ths_trailcnt = 0x2; + state->pdata.hstxvregcnt = 0; + + state->reset_gpio = devm_gpiod_get(dev, "reset"); + if (IS_ERR(state->reset_gpio)) { + dev_err(dev, "failed to get reset gpio\n"); + ret = PTR_ERR(state->reset_gpio); + goto disable_clk; + } + + tc358743_gpio_reset(state); + + ret = 0; + goto free_endpoint; + +disable_clk: + clk_disable_unprepare(refclk); +free_endpoint: + v4l2_of_free_endpoint(endpoint); + return ret; +} +#else +static inline int tc358743_probe_of(struct tc358743_state *state) +{ + return -ENODEV; +} +#endif + static int tc358743_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1658,14 +1795,20 @@ static int tc358743_probe(struct i2c_client *client, if (!state) return -ENOMEM; + state->i2c_client = client; + /* platform data */ - if (!pdata) { - v4l_err(client, "No platform data!\n"); - return -ENODEV; + if (pdata) { + state->pdata = *pdata; + state->bus.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + } else { + err = tc358743_probe_of(state); + if (err == -ENODEV) + v4l_err(client, "No platform data!\n"); + if (err) + return err; } - state->pdata = *pdata; - state->i2c_client = client; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &tc358743_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; -- cgit v1.3-6-gb490 From d747b806abf41f037f7d2a076131adf8c7971a89 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 17 Jul 2015 11:02:56 -0300 Subject: [media] tc358743: add direct interrupt handling When probed from device tree, the i2c client driver can handle the interrupt on its own. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 76d0aaa19493..934f6e17e06d 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1306,6 +1307,16 @@ static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled) return 0; } +static irqreturn_t tc358743_irq_handler(int irq, void *dev_id) +{ + struct tc358743_state *state = dev_id; + bool handled; + + tc358743_isr(&state->sd, 0, &handled); + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + /* --------------- VIDEO OPS --------------- */ static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) @@ -1876,6 +1887,17 @@ static int tc358743_probe(struct i2c_client *client, tc358743_set_csi_color_space(sd); tc358743_init_interrupts(sd); + + if (state->i2c_client->irq) { + err = devm_request_threaded_irq(&client->dev, + state->i2c_client->irq, + NULL, tc358743_irq_handler, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "tc358743", state); + if (err) + goto err_work_queues; + } + tc358743_enable_interrupts(sd, tx_5v_power_present(sd)); i2c_wr16(sd, INTMASK, ~(MASK_HDMI_MSK | MASK_CSI_MSK) & 0xffff); -- cgit v1.3-6-gb490 From 1140f919f807b6d5a259ecfca88022da0e5340cb Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 17 Jul 2015 12:26:45 -0300 Subject: [media] tc358743: allow event subscription This is useful to subscribe to HDMI hotplug events via the V4L2_CID_DV_RX_POWER_PRESENT control. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 934f6e17e06d..d0dd83d7a38e 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -859,8 +860,7 @@ static void tc358743_format_change(struct v4l2_subdev *sd) &timings, false); } - v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, - (void *)&tc358743_ev_fmt); + v4l2_subdev_notify_event(sd, &tc358743_ev_fmt); } static void tc358743_init_interrupts(struct v4l2_subdev *sd) @@ -1317,6 +1317,19 @@ static irqreturn_t tc358743_irq_handler(int irq, void *dev_id) return handled ? IRQ_HANDLED : IRQ_NONE; } +static int tc358743_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); + default: + return -EINVAL; + } +} + /* --------------- VIDEO OPS --------------- */ static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) @@ -1604,6 +1617,8 @@ static const struct v4l2_subdev_core_ops tc358743_core_ops = { .s_register = tc358743_s_register, #endif .interrupt_service_routine = tc358743_isr, + .subscribe_event = tc358743_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops tc358743_video_ops = { -- cgit v1.3-6-gb490 From 9e75c0ef1428ae8a6bfb340ba2402471752c4af5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:32:34 +0200 Subject: drm/cma-helper: Fix locking in drm_fb_cma_debugfs_show This function takes two locks, both of them the wrong ones. This wasn't an oversight from my fb locking rework since both patches landed in parallel. We really only need fb_lock when walking that list, since everything we can reach from that is refcounted properly already. v2: Drop unused dev spotted by 0day. Cc: Rob Clark Cc: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_cma_helper.c | 16 ++-------------- drivers/gpu/drm/drm_gem_cma_helper.c | 3 --- 2 files changed, 2 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 5c1aca443e54..46c4e6ee1cb1 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -209,23 +209,11 @@ int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; struct drm_framebuffer *fb; - int ret; - - ret = mutex_lock_interruptible(&dev->mode_config.mutex); - if (ret) - return ret; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) { - mutex_unlock(&dev->mode_config.mutex); - return ret; - } + mutex_lock(&dev->mode_config.fb_lock); list_for_each_entry(fb, &dev->mode_config.fb_list, head) drm_fb_cma_describe(fb, m); - - mutex_unlock(&dev->struct_mutex); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev->mode_config.fb_lock); return 0; } diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index bd75f303da63..9edad11dca98 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -381,11 +381,8 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m) { struct drm_gem_object *obj = &cma_obj->base; - struct drm_device *dev = obj->dev; uint64_t off; - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - off = drm_vma_node_start(&obj->vma_node); seq_printf(m, "%2d (%2d) %08llx %pad %p %zu", -- cgit v1.3-6-gb490 From e4f62546325724168e0b7ee7180762cb07859ca7 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:35 +0200 Subject: drm: Roll out drm_for_each_{plane,crtc,encoder} Remaining manual work in the drm core&helpers. Nothing special here, no surprises. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 26 ++++++++++++++------------ drivers/gpu/drm/drm_crtc_helper.c | 2 +- drivers/gpu/drm/drm_fb_cma_helper.c | 2 +- drivers/gpu/drm/drm_modeset_lock.c | 7 +++---- 4 files changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d928bf7ef221..138ef22078d9 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -736,7 +736,7 @@ unsigned int drm_crtc_index(struct drm_crtc *crtc) unsigned int index = 0; struct drm_crtc *tmp; - list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { + drm_for_each_crtc(tmp, crtc->dev) { if (tmp == crtc) return index; @@ -1280,7 +1280,7 @@ unsigned int drm_plane_index(struct drm_plane *plane) unsigned int index = 0; struct drm_plane *tmp; - list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) { + drm_for_each_plane(tmp, plane->dev) { if (tmp == plane) return index; @@ -1719,10 +1719,10 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, if (ret) return ret; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + drm_for_each_crtc(crtc, dev) group->id_list[group->num_crtcs++] = crtc->base.id; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + drm_for_each_encoder(encoder, dev) group->id_list[group->num_crtcs + group->num_encoders++] = encoder->base.id; @@ -1811,15 +1811,17 @@ int drm_mode_getresources(struct drm_device *dev, void *data, mutex_lock(&dev->mode_config.mutex); if (!drm_is_primary_client(file_priv)) { struct drm_connector *connector; + struct drm_encoder *encoder; + struct drm_crtc *crtc; mode_group = NULL; - list_for_each(lh, &dev->mode_config.crtc_list) + drm_for_each_crtc(crtc, dev) crtc_count++; drm_for_each_connector(connector, dev) connector_count++; - list_for_each(lh, &dev->mode_config.encoder_list) + drm_for_each_encoder(encoder, dev) encoder_count++; } else { @@ -2287,7 +2289,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; /* Plane lists are invariant, no locking needed. */ - list_for_each_entry(plane, &config->plane_list, head) { + drm_for_each_plane(plane, dev) { /* * Unless userspace set the 'universal planes' * capability bit, only advertise overlays. @@ -2592,7 +2594,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) * connectors from it), hence we need to refcount the fbs across all * crtcs. Atomic modeset will have saner semantics ... */ - list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) + drm_for_each_crtc(tmp, crtc->dev) tmp->primary->old_fb = tmp->primary->fb; fb = set->fb; @@ -2603,7 +2605,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) crtc->primary->fb = fb; } - list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { + drm_for_each_crtc(tmp, crtc->dev) { if (tmp->primary->fb) drm_framebuffer_reference(tmp->primary->fb); if (tmp->primary->old_fb) @@ -5377,15 +5379,15 @@ void drm_mode_config_reset(struct drm_device *dev) struct drm_encoder *encoder; struct drm_connector *connector; - list_for_each_entry(plane, &dev->mode_config.plane_list, head) + drm_for_each_plane(plane, dev) if (plane->funcs->reset) plane->funcs->reset(plane); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + drm_for_each_crtc(crtc, dev) if (crtc->funcs->reset) crtc->funcs->reset(crtc); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + drm_for_each_encoder(encoder, dev) if (encoder->funcs->reset) encoder->funcs->reset(encoder); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 4a83c22f5e61..2e89d8b7de18 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -151,7 +151,7 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) if (!oops_in_progress) WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + drm_for_each_encoder(encoder, dev) if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder)) return true; return false; diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 46c4e6ee1cb1..f01dc25df2dc 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -211,7 +211,7 @@ int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg) struct drm_framebuffer *fb; mutex_lock(&dev->mode_config.fb_lock); - list_for_each_entry(fb, &dev->mode_config.fb_list, head) + drm_for_each_fb(fb, dev) drm_fb_cma_describe(fb, m); mutex_unlock(&dev->mode_config.fb_lock); diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index c0a5cd8c5262..744dfbc6a329 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -276,7 +276,7 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) if (oops_in_progress) return; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + drm_for_each_crtc(crtc, dev) WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); @@ -464,18 +464,17 @@ EXPORT_SYMBOL(drm_modeset_unlock); int drm_modeset_lock_all_crtcs(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx) { - struct drm_mode_config *config = &dev->mode_config; struct drm_crtc *crtc; struct drm_plane *plane; int ret = 0; - list_for_each_entry(crtc, &config->crtc_list, head) { + drm_for_each_crtc(crtc, dev) { ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) return ret; } - list_for_each_entry(plane, &config->plane_list, head) { + drm_for_each_plane(plane, dev) { ret = drm_modeset_lock(&plane->mutex, ctx); if (ret) return ret; -- cgit v1.3-6-gb490 From 9c7060f7e3b09837621f93bd8666cf4cfac45001 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:36 +0200 Subject: drm: Stop filtering according to mode_group in getresources It's been dead code since forever since mode groups haven't ever been implemented. On top of that it's also been non-functional since we only ever filtered the getresources ioctl and not any of the others nor the mode object lookup code. Given overwhelming evidence it looks like this isn't a feature we need, hence remove it. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 110 +++++++++++++-------------------------------- 1 file changed, 30 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 138ef22078d9..805ef2f408a7 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1771,12 +1771,11 @@ int drm_mode_getresources(struct drm_device *dev, void *data, int crtc_count = 0; int fb_count = 0; int encoder_count = 0; - int copied = 0, i; + int copied = 0; uint32_t __user *fb_id; uint32_t __user *crtc_id; uint32_t __user *connector_id; uint32_t __user *encoder_id; - struct drm_mode_group *mode_group; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -1809,27 +1808,14 @@ int drm_mode_getresources(struct drm_device *dev, void *data, /* mode_config.mutex protects the connector list against e.g. DP MST * connector hot-adding. CRTC/Plane lists are invariant. */ mutex_lock(&dev->mode_config.mutex); - if (!drm_is_primary_client(file_priv)) { - struct drm_connector *connector; - struct drm_encoder *encoder; - struct drm_crtc *crtc; - - mode_group = NULL; - drm_for_each_crtc(crtc, dev) - crtc_count++; - - drm_for_each_connector(connector, dev) - connector_count++; + drm_for_each_crtc(crtc, dev) + crtc_count++; - drm_for_each_encoder(encoder, dev) - encoder_count++; - } else { + drm_for_each_connector(connector, dev) + connector_count++; - mode_group = &file_priv->master->minor->mode_group; - crtc_count = mode_group->num_crtcs; - connector_count = mode_group->num_connectors; - encoder_count = mode_group->num_encoders; - } + drm_for_each_encoder(encoder, dev) + encoder_count++; card_res->max_height = dev->mode_config.max_height; card_res->min_height = dev->mode_config.min_height; @@ -1840,24 +1826,13 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (card_res->count_crtcs >= crtc_count) { copied = 0; crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; - if (!mode_group) { - drm_for_each_crtc(crtc, dev) { - DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); - if (put_user(crtc->base.id, crtc_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } else { - for (i = 0; i < mode_group->num_crtcs; i++) { - if (put_user(mode_group->id_list[i], - crtc_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; + drm_for_each_crtc(crtc, dev) { + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); + if (put_user(crtc->base.id, crtc_id + copied)) { + ret = -EFAULT; + goto out; } + copied++; } } card_res->count_crtcs = crtc_count; @@ -1866,27 +1841,15 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (card_res->count_encoders >= encoder_count) { copied = 0; encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; - if (!mode_group) { - drm_for_each_encoder(encoder, dev) { - DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, - encoder->name); - if (put_user(encoder->base.id, encoder_id + - copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } else { - for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) { - if (put_user(mode_group->id_list[i], - encoder_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; + drm_for_each_encoder(encoder, dev) { + DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, + encoder->name); + if (put_user(encoder->base.id, encoder_id + + copied)) { + ret = -EFAULT; + goto out; } - + copied++; } } card_res->count_encoders = encoder_count; @@ -1895,29 +1858,16 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (card_res->count_connectors >= connector_count) { copied = 0; connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; - if (!mode_group) { - drm_for_each_connector(connector, dev) { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", - connector->base.id, - connector->name); - if (put_user(connector->base.id, - connector_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } else { - int start = mode_group->num_crtcs + - mode_group->num_encoders; - for (i = start; i < start + mode_group->num_connectors; i++) { - if (put_user(mode_group->id_list[i], - connector_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; + drm_for_each_connector(connector, dev) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); + if (put_user(connector->base.id, + connector_id + copied)) { + ret = -EFAULT; + goto out; } + copied++; } } card_res->count_connectors = connector_count; -- cgit v1.3-6-gb490 From 3fdefa399e4644399ce3e74e65a75122d52dba6a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:37 +0200 Subject: drm: gc now dead mode_group code Two nice things here: - drm_dev_register will truly register everything in the right order if the driver doesn't have a ->load callback. Before this we had to init the primary mode_group after the device nodes where already registered. - Less things to keep track of when reworking the connector locking, yay! Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 64 ---------------------------------- drivers/gpu/drm/drm_drv.c | 12 ------- drivers/gpu/drm/i915/intel_dp_mst.c | 3 -- drivers/gpu/drm/radeon/radeon_dp_mst.c | 3 -- include/drm/drmP.h | 1 - include/drm/drm_crtc.h | 26 -------------- 6 files changed, 109 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 805ef2f408a7..e385014ed616 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1679,70 +1679,6 @@ int drm_mode_create_suggested_offset_properties(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); -static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) -{ - uint32_t total_objects = 0; - - total_objects += dev->mode_config.num_crtc; - total_objects += dev->mode_config.num_connector; - total_objects += dev->mode_config.num_encoder; - - group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL); - if (!group->id_list) - return -ENOMEM; - - group->num_crtcs = 0; - group->num_connectors = 0; - group->num_encoders = 0; - return 0; -} - -void drm_mode_group_destroy(struct drm_mode_group *group) -{ - kfree(group->id_list); - group->id_list = NULL; -} - -/* - * 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) -{ - struct drm_crtc *crtc; - struct drm_encoder *encoder; - struct drm_connector *connector; - int ret; - - ret = drm_mode_group_init(dev, group); - if (ret) - return ret; - - drm_for_each_crtc(crtc, dev) - group->id_list[group->num_crtcs++] = crtc->base.id; - - drm_for_each_encoder(encoder, dev) - group->id_list[group->num_crtcs + group->num_encoders++] = - encoder->base.id; - - drm_for_each_connector(connector, dev) - group->id_list[group->num_crtcs + group->num_encoders + - group->num_connectors++] = connector->base.id; - - return 0; -} -EXPORT_SYMBOL(drm_mode_group_init_legacy_group); - -void drm_reinit_primary_mode_group(struct drm_device *dev) -{ - drm_modeset_lock_all(dev); - drm_mode_group_destroy(&dev->primary->mode_group); - drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group); - drm_modeset_unlock_all(dev); -} -EXPORT_SYMBOL(drm_reinit_primary_mode_group); - /** * drm_mode_getresources - get graphics configuration * @dev: drm device for the ioctl diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index b7bf4ce8c012..f7798c3b543e 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -285,7 +285,6 @@ static void drm_minor_free(struct drm_device *dev, unsigned int type) if (!minor) return; - drm_mode_group_destroy(&minor->mode_group); put_device(minor->kdev); spin_lock_irqsave(&drm_minor_lock, flags); @@ -705,20 +704,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) goto err_minors; } - /* setup grouping for legacy outputs */ - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = drm_mode_group_init_legacy_group(dev, - &dev->primary->mode_group); - if (ret) - goto err_unload; - } - ret = 0; goto out_unlock; -err_unload: - if (dev->driver->unload) - dev->driver->unload(dev); err_minors: drm_minor_unregister(dev, DRM_MINOR_LEGACY); drm_minor_unregister(dev, DRM_MINOR_RENDER); diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index d0b2569c6241..585f0a45b3f1 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -441,7 +441,6 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); drm_mode_connector_set_path_property(connector, pathprop); - drm_reinit_primary_mode_group(dev); drm_modeset_lock_all(dev); intel_connector_add_to_fbdev(intel_connector); drm_modeset_unlock_all(dev); @@ -466,8 +465,6 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, drm_connector_cleanup(connector); drm_modeset_unlock_all(dev); - drm_reinit_primary_mode_group(dev); - kfree(intel_connector); DRM_DEBUG_KMS("\n"); } diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index e649c8ff20a0..e4fc8f3bf58b 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -284,7 +284,6 @@ static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topol drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); drm_mode_connector_set_path_property(connector, pathprop); - drm_reinit_primary_mode_group(dev); drm_modeset_lock_all(dev); radeon_fb_add_connector(rdev, connector); @@ -309,8 +308,6 @@ static void radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, drm_connector_cleanup(connector); drm_modeset_unlock_all(dev); - drm_reinit_primary_mode_group(dev); - kfree(connector); DRM_DEBUG_KMS("\n"); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 48db6a56975f..c89351ede92c 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -675,7 +675,6 @@ struct drm_minor { /* currently active master for this node. Protected by master_mutex */ struct drm_master *master; - struct drm_mode_group mode_group; }; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index fe3100115a41..3071319ea194 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1017,29 +1017,6 @@ struct drm_mode_config_funcs { void (*atomic_state_free)(struct drm_atomic_state *state); }; -/** - * struct drm_mode_group - group of mode setting resources for potential sub-grouping - * @num_crtcs: CRTC count - * @num_encoders: encoder count - * @num_connectors: connector count - * @num_bridges: bridge count - * @id_list: list of KMS object IDs in this group - * - * Currently this simply tracks the global mode setting state. But in the - * future it could allow groups of objects to be set aside into independent - * control groups for use by different user level processes (e.g. two X servers - * running simultaneously on different heads, each with their own mode - * configuration and freedom of mode setting). - */ -struct drm_mode_group { - uint32_t num_crtcs; - uint32_t num_encoders; - uint32_t num_connectors; - - /* list of object IDs for this group */ - uint32_t *id_list; -}; - /** * struct drm_mode_config - Mode configuration control structure * @mutex: mutex protecting KMS related lists and structures @@ -1324,9 +1301,6 @@ extern const char *drm_get_tv_select_name(int val); extern void drm_fb_release(struct drm_file *file_priv); extern void drm_property_destroy_user_blobs(struct drm_device *dev, struct drm_file *file_priv); -extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); -extern void drm_mode_group_destroy(struct drm_mode_group *group); -extern void drm_reinit_primary_mode_group(struct drm_device *dev); extern bool drm_probe_ddc(struct i2c_adapter *adapter); extern struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); -- cgit v1.3-6-gb490 From dd70b27eecdd4e13378a5e253dbd426058e164ef Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Jun 2015 23:01:45 -0300 Subject: [media] media: ttpci: Use vsprintf %pM extension Format mac addresses with the normal kernel extension. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/ttpci-eeprom.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.c b/drivers/media/pci/ttpci/ttpci-eeprom.c index 32d43156c548..c6f31f2712bc 100644 --- a/drivers/media/pci/ttpci/ttpci-eeprom.c +++ b/drivers/media/pci/ttpci/ttpci-eeprom.c @@ -162,9 +162,7 @@ int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) } memcpy(proposed_mac, decodedMAC, 6); - dprintk("adapter has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - decodedMAC[0], decodedMAC[1], decodedMAC[2], - decodedMAC[3], decodedMAC[4], decodedMAC[5]); + dprintk("adapter has MAC addr = %pM\n", decodedMAC); return 0; } -- cgit v1.3-6-gb490 From 17a705e4a99bc6d810f2d64efe9368e221302f7a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 15 Jun 2015 08:33:29 -0300 Subject: [media] sh-veu: don't use COLORSPACE_JPEG COLORSPACE_JPEG should only be used for JPEGs. Use SMPTE170M instead, which is how YCbCr images are usually encoded. Signed-off-by: Hans Verkuil Acked-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_veu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 2554f3719b9e..7bb249cd19b8 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -211,7 +211,7 @@ static enum v4l2_colorspace sh_veu_4cc2cspace(u32 fourcc) case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV24: - return V4L2_COLORSPACE_JPEG; + return V4L2_COLORSPACE_SMPTE170M; case V4L2_PIX_FMT_RGB332: case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_RGB565: -- cgit v1.3-6-gb490 From a4c4f95eb64640ec31cf0661b1a863151c744827 Mon Sep 17 00:00:00 2001 From: Sunil Shahu Date: Sat, 20 Jun 2015 05:53:50 -0300 Subject: [media] staging: media: lirc: fix coding style error Fix code indentation error by replacing tab in place of spaces. Signed-off-by: Sunil Shahu Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/lirc/lirc_sasem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c index 9e5674341abe..b247649a99eb 100644 --- a/drivers/staging/media/lirc/lirc_sasem.c +++ b/drivers/staging/media/lirc/lirc_sasem.c @@ -184,7 +184,7 @@ static void deregister_from_lirc(struct sasem_context *context) __func__, retval); else dev_info(&context->dev->dev, - "Deregistered Sasem driver (minor:%d)\n", minor); + "Deregistered Sasem driver (minor:%d)\n", minor); } -- cgit v1.3-6-gb490 From 4dc102b2f53d63207fa12a6ad49c7b6448bc3301 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Fri, 19 Jun 2015 23:58:17 -0300 Subject: [media] dvb_core: Replace memset with eth_zero_addr Use eth_zero_addr to assign the zero address to the given address array instead of memset when second argument is address of zero. The Coccinelle semantic patch that makes this change is as follows: // @eth_zero_addr@ expression e; @@ -memset(e,0x00,ETH_ALEN); +eth_zero_addr(e); // Signed-off-by: Vaishali Thakkar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index a694fb1ea228..b81e026edab3 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -709,7 +709,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (!priv->ule_dbit) { /* dest_addr buffer is only valid if priv->ule_dbit == 0 */ memcpy(ethh->h_dest, dest_addr, ETH_ALEN); - memset(ethh->h_source, 0, ETH_ALEN); + eth_zero_addr(ethh->h_source); } else /* zeroize source and dest */ memset( ethh, 0, ETH_ALEN*2 ); -- cgit v1.3-6-gb490 From 6ed3464897cc825a75218653c710d673282dfcf8 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 2 Jan 2015 16:18:54 -0600 Subject: irqchip: omap-intc: Improve IRQ handler As it turns out the current IRQ number will *always* be available from SIR register which renders the reads of PENDING registers as plain unnecessary overhead. In order to catch any situation where SIR reads as zero, we're adding a WARN() to turn it into a very verbose error and users actually report it. With this patch average running time of omap_intc_handle_irq() reduced from about 28.5us to 19.8us as measured by the kernel function profiler. Tested with BeagleBoneBlack Rev A5C. Tested-by: Tony Lindgren Signed-off-by: Felipe Balbi Cc: Linux ARM Kernel Mailing List Link: http://lkml.kernel.org/r/20150720204910.GH5394@saruman.tx.rr.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-omap-intc.c | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c index 6cc0ad57ffab..8587d0f8d8c0 100644 --- a/drivers/irqchip/irq-omap-intc.c +++ b/drivers/irqchip/irq-omap-intc.c @@ -330,37 +330,12 @@ static int __init omap_init_irq(u32 base, struct device_node *node) static asmlinkage void __exception_irq_entry omap_intc_handle_irq(struct pt_regs *regs) { - u32 irqnr = 0; - int handled_irq = 0; - int i; - - do { - for (i = 0; i < omap_nr_pending; i++) { - irqnr = intc_readl(INTC_PENDING_IRQ0 + (0x20 * i)); - if (irqnr) - goto out; - } - -out: - if (!irqnr) - break; - - irqnr = intc_readl(INTC_SIR); - irqnr &= ACTIVEIRQ_MASK; + u32 irqnr; - if (irqnr) { - handle_domain_irq(domain, 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); + irqnr = intc_readl(INTC_SIR); + irqnr &= ACTIVEIRQ_MASK; + WARN_ONCE(!irqnr, "Spurious IRQ ?\n"); + handle_domain_irq(domain, irqnr, regs); } void __init omap3_init_irq(void) -- cgit v1.3-6-gb490 From faca10b9e63e880c81388fbbedf7ede6dcd77c70 Mon Sep 17 00:00:00 2001 From: Wang Long Date: Tue, 21 Jul 2015 08:11:01 +0000 Subject: drivers/irqchip: Replace pr_warning by pr_warn Update the last pr_warning callsite in drivers/irqchip. Signed-off-by: Wang Long Cc: Cc: Cc: Cc: Cc: Cc: Link: http://lkml.kernel.org/r/1437466261-147373-1-git-send-email-long.wanglong@huawei.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/exynos-combiner.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 04e0892d2511..e9c6f2a5b52d 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -185,14 +185,14 @@ static void __init combiner_init(void __iomem *combiner_base, combiner_data = kcalloc(max_nr, sizeof (*combiner_data), GFP_KERNEL); if (!combiner_data) { - pr_warning("%s: could not allocate combiner data\n", __func__); + pr_warn("%s: could not allocate combiner data\n", __func__); return; } combiner_irq_domain = irq_domain_add_linear(np, nr_irq, &combiner_irq_domain_ops, combiner_data); if (WARN_ON(!combiner_irq_domain)) { - pr_warning("%s: irq domain init failed\n", __func__); + pr_warn("%s: irq domain init failed\n", __func__); return; } -- cgit v1.3-6-gb490 From c179c9b978b90bdf9cb39f5b5716dede157f1eaf Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:36 +0800 Subject: PCI: Add helper function msi_desc_to_pci_sysdata() Add helper function msi_desc_to_pci_sysdata() to retrieve sysdata from an MSI descriptor. To avoid pulling include/linux/pci.h into include/linux/msi.h, msi_desc_to_pci_sysdata() is implemented as a normal function instead of an inline function. Signed-off-by: Jiang Liu Reviewed-by: Yijing Wang Acked-by: Bjorn Helgaas Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Borislav Petkov Cc: Alexander Gordeev Link: http://lkml.kernel.org/r/1436428847-8886-2-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/pci/msi.c | 8 ++++++++ include/linux/msi.h | 7 +++++++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 157eb8817fb8..ab4174243962 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1137,6 +1137,14 @@ int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, } EXPORT_SYMBOL(pci_enable_msix_range); +void *msi_desc_to_pci_sysdata(struct msi_desc *desc) +{ + struct pci_dev *dev = msi_desc_to_pci_dev(desc); + + return dev->bus->sysdata; +} +EXPORT_SYMBOL_GPL(msi_desc_to_pci_sysdata); + #ifdef CONFIG_PCI_MSI_IRQ_DOMAIN /** * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space diff --git a/include/linux/msi.h b/include/linux/msi.h index 8ac4a68ffae2..cfbd2afeaf64 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -60,6 +60,13 @@ static inline struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc) { return desc->dev; } + +void *msi_desc_to_pci_sysdata(struct msi_desc *desc); +#else /* CONFIG_PCI_MSI */ +static inline void *msi_desc_to_pci_sysdata(struct msi_desc *desc) +{ + return NULL; +} #endif /* CONFIG_PCI_MSI */ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg); -- cgit v1.3-6-gb490 From 5004e98a91e8ad600f5b00872e9ddad810258f08 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:41 +0800 Subject: PCI: Use for_each_pci_msi_entry() to access MSI device list Use accessor for_each_pci_msi_entry() to access MSI device list, so we could easily move msi_list from struct pci_dev into struct device later. Signed-off-by: Jiang Liu Reviewed-by: Yijing Wang Acked-by: Bjorn Helgaas Acked-by: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: xen-devel@lists.xenproject.org Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Borislav Petkov Cc: Boris Ostrovsky Cc: David Vrabel Link: http://lkml.kernel.org/r/1436428847-8886-7-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/pci/msi.c | 39 ++++++++++++++++++++------------------- drivers/pci/xen-pcifront.c | 2 +- 2 files changed, 21 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index ab4174243962..540613e5560a 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -131,7 +131,7 @@ int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) if (type == PCI_CAP_ID_MSI && nvec > 1) return 1; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { ret = arch_setup_msi_irq(dev, entry); if (ret < 0) return ret; @@ -151,7 +151,7 @@ void default_teardown_msi_irqs(struct pci_dev *dev) int i; struct msi_desc *entry; - list_for_each_entry(entry, &dev->msi_list, list) + for_each_pci_msi_entry(entry, dev) if (entry->irq) for (i = 0; i < entry->nvec_used; i++) arch_teardown_msi_irq(entry->irq + i); @@ -168,7 +168,7 @@ static void default_restore_msi_irq(struct pci_dev *dev, int irq) entry = NULL; if (dev->msix_enabled) { - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { if (irq == entry->irq) break; } @@ -282,7 +282,7 @@ void default_restore_msi_irqs(struct pci_dev *dev) { struct msi_desc *entry; - list_for_each_entry(entry, &dev->msi_list, list) + for_each_pci_msi_entry(entry, dev) default_restore_msi_irq(dev, entry->irq); } @@ -363,21 +363,22 @@ EXPORT_SYMBOL_GPL(pci_write_msi_msg); static void free_msi_irqs(struct pci_dev *dev) { + struct list_head *msi_list = dev_to_msi_list(&dev->dev); struct msi_desc *entry, *tmp; struct attribute **msi_attrs; struct device_attribute *dev_attr; int i, count = 0; - list_for_each_entry(entry, &dev->msi_list, list) + for_each_pci_msi_entry(entry, dev) if (entry->irq) for (i = 0; i < entry->nvec_used; i++) BUG_ON(irq_has_action(entry->irq + i)); pci_msi_teardown_msi_irqs(dev); - list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { + list_for_each_entry_safe(entry, tmp, msi_list, list) { if (entry->msi_attrib.is_msix) { - if (list_is_last(&entry->list, &dev->msi_list)) + if (list_is_last(&entry->list, msi_list)) iounmap(entry->mask_base); } @@ -448,7 +449,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) if (!dev->msix_enabled) return; - BUG_ON(list_empty(&dev->msi_list)); + BUG_ON(list_empty(dev_to_msi_list(&dev->dev))); /* route the table */ pci_intx_for_msi(dev, 0); @@ -456,7 +457,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL); arch_restore_msi_irqs(dev); - list_for_each_entry(entry, &dev->msi_list, list) + for_each_pci_msi_entry(entry, dev) msix_mask_irq(entry, entry->masked); pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0); @@ -501,7 +502,7 @@ static int populate_msi_sysfs(struct pci_dev *pdev) int count = 0; /* Determine how many msi entries we have */ - list_for_each_entry(entry, &pdev->msi_list, list) + for_each_pci_msi_entry(entry, pdev) ++num_msi; if (!num_msi) return 0; @@ -510,7 +511,7 @@ static int populate_msi_sysfs(struct pci_dev *pdev) msi_attrs = kzalloc(sizeof(void *) * (num_msi + 1), GFP_KERNEL); if (!msi_attrs) return -ENOMEM; - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL); if (!msi_dev_attr) goto error_attrs; @@ -599,7 +600,7 @@ static int msi_verify_entries(struct pci_dev *dev) { struct msi_desc *entry; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { if (!dev->no_64bit_msi || !entry->msg.address_hi) continue; dev_err(&dev->dev, "Device has broken 64-bit MSI but arch" @@ -636,7 +637,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) mask = msi_mask(entry->msi_attrib.multi_cap); msi_mask_irq(entry, mask, mask); - list_add_tail(&entry->list, &dev->msi_list); + list_add_tail(&entry->list, dev_to_msi_list(&dev->dev)); /* Configure MSI capability structure */ ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI); @@ -713,7 +714,7 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, entry->mask_base = base; entry->nvec_used = 1; - list_add_tail(&entry->list, &dev->msi_list); + list_add_tail(&entry->list, dev_to_msi_list(&dev->dev)); } return 0; @@ -725,7 +726,7 @@ static void msix_program_entries(struct pci_dev *dev, struct msi_desc *entry; int i = 0; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { int offset = entries[i].entry * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; @@ -806,7 +807,7 @@ out_avail: struct msi_desc *entry; int avail = 0; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { if (entry->irq != 0) avail++; } @@ -895,8 +896,8 @@ void pci_msi_shutdown(struct pci_dev *dev) if (!pci_msi_enable || !dev || !dev->msi_enabled) return; - BUG_ON(list_empty(&dev->msi_list)); - desc = list_first_entry(&dev->msi_list, struct msi_desc, list); + BUG_ON(list_empty(dev_to_msi_list(&dev->dev))); + desc = first_msi_entry(dev); pci_msi_set_enable(dev, 0); pci_intx_for_msi(dev, 1); @@ -1001,7 +1002,7 @@ void pci_msix_shutdown(struct pci_dev *dev) return; /* Return the device with MSI-X masked as initial states */ - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { /* Keep cached states to be restored */ __pci_msix_desc_mask_irq(entry, 1); } diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 8b7a900cd28b..c777b97207d5 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -265,7 +265,7 @@ static int pci_frontend_enable_msix(struct pci_dev *dev, } i = 0; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { op.msix_entries[i].entry = entry->msi_attrib.entry_nr; /* Vector is useless at this point. */ op.msix_entries[i].vector = -1; -- cgit v1.3-6-gb490 From e39758e0ea769e632e5e3c9f314160e55c2153ff Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:43 +0800 Subject: PCI: Use helper functions to access fields in struct msi_desc Use helper functions to access fields in struct msi_desc, so we could easily refine msi_desc later. Signed-off-by: Jiang Liu Reviewed-by: Yijing Wang Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Bjorn Helgaas Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Borislav Petkov Cc: Murali Karicheri Cc: Jingoo Han Cc: Pratyush Anand Cc: Michal Simek Cc: Soeren Brinkmann Cc: Srikanth Thokala Cc: Rob Herring Link: http://lkml.kernel.org/r/1436428847-8886-9-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/pci/host/pci-keystone-dw.c | 6 +++--- drivers/pci/host/pcie-designware.c | 4 ++-- drivers/pci/host/pcie-xilinx.c | 12 +++++------- drivers/pci/msi.c | 13 ++++++++----- 4 files changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c index e42d077039d3..6f3abc2c7316 100644 --- a/drivers/pci/host/pci-keystone-dw.c +++ b/drivers/pci/host/pci-keystone-dw.c @@ -108,7 +108,7 @@ static void ks_dw_pcie_msi_irq_ack(struct irq_data *d) struct pcie_port *pp; msi = irq_data_get_msi_desc(d); - pp = sys_to_pcie(msi->dev->bus->sysdata); + pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); ks_pcie = to_keystone_pcie(pp); offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); update_reg_offset_bit_pos(offset, ®_offset, &bit_pos); @@ -146,7 +146,7 @@ static void ks_dw_pcie_msi_irq_mask(struct irq_data *d) u32 offset; msi = irq_data_get_msi_desc(d); - pp = sys_to_pcie(msi->dev->bus->sysdata); + pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); ks_pcie = to_keystone_pcie(pp); offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); @@ -167,7 +167,7 @@ static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d) u32 offset; msi = irq_data_get_msi_desc(d); - pp = sys_to_pcie(msi->dev->bus->sysdata); + pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); ks_pcie = to_keystone_pcie(pp); offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 85c7735d7511..aae6dcb528c1 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -255,7 +255,7 @@ static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) { int irq, pos0, i; - struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata); + struct pcie_port *pp = sys_to_pcie(msi_desc_to_pci_sysdata(desc)); pos0 = bitmap_find_free_region(pp->msi_irq_in_use, MAX_MSI_IRQS, order_base_2(no_irqs)); @@ -327,7 +327,7 @@ static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq) { struct irq_data *data = irq_get_irq_data(irq); struct msi_desc *msi = irq_data_get_msi_desc(data); - struct pcie_port *pp = sys_to_pcie(msi->dev->bus->sysdata); + struct pcie_port *pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); clear_irq_range(pp, irq, 1, data->hwirq); } diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index f1a06a091ccb..64454f416639 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c @@ -227,18 +227,16 @@ static struct pci_ops xilinx_pcie_ops = { */ static void xilinx_pcie_destroy_msi(unsigned int irq) { - struct irq_desc *desc; struct msi_desc *msi; struct xilinx_pcie_port *port; - desc = irq_to_desc(irq); - msi = irq_desc_get_msi_desc(desc); - port = sys_to_pcie(msi->dev->bus->sysdata); - - if (!test_bit(irq, msi_irq_in_use)) + if (!test_bit(irq, msi_irq_in_use)) { + msi = irq_get_msi_desc(irq); + port = sys_to_pcie(msi_desc_to_pci_sys_data(msi)); dev_err(port->dev, "Trying to free unused MSI#%d\n", irq); - else + } else { clear_bit(irq, msi_irq_in_use); + } } /** diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 540613e5560a..f0714c3fd315 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -208,7 +208,8 @@ u32 __pci_msi_desc_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) mask_bits &= ~mask; mask_bits |= flag; - pci_write_config_dword(desc->dev, desc->mask_pos, mask_bits); + pci_write_config_dword(msi_desc_to_pci_dev(desc), desc->mask_pos, + mask_bits); return mask_bits; } @@ -288,7 +289,9 @@ void default_restore_msi_irqs(struct pci_dev *dev) void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { - BUG_ON(entry->dev->current_state != PCI_D0); + struct pci_dev *dev = msi_desc_to_pci_dev(entry); + + BUG_ON(dev->current_state != PCI_D0); if (entry->msi_attrib.is_msix) { void __iomem *base = entry->mask_base + @@ -298,7 +301,6 @@ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR); msg->data = readl(base + PCI_MSIX_ENTRY_DATA); } else { - struct pci_dev *dev = entry->dev; int pos = dev->msi_cap; u16 data; @@ -318,7 +320,9 @@ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { - if (entry->dev->current_state != PCI_D0) { + struct pci_dev *dev = msi_desc_to_pci_dev(entry); + + if (dev->current_state != PCI_D0) { /* Don't touch the hardware now */ } else if (entry->msi_attrib.is_msix) { void __iomem *base; @@ -329,7 +333,6 @@ void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR); writel(msg->data, base + PCI_MSIX_ENTRY_DATA); } else { - struct pci_dev *dev = entry->dev; int pos = dev->msi_cap; u16 msgctl; -- cgit v1.3-6-gb490 From 4a7cc831670550e6b48ef5760e7213f89935ff0d Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:44 +0800 Subject: genirq/MSI: Move msi_list from struct pci_dev to struct device Move msi_list from struct pci_dev into struct device, so we can support non-PCI-device based generic MSI interrupts. msi_list is now conditional under CONFIG_GENERIC_MSI_IRQ, which is selected from CONFIG_PCI_MSI, so no functional change for PCI MSI users. Signed-off-by: Jiang Liu Reviewed-by: Yijing Wang Acked-by: Bjorn Helgaas Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Borislav Petkov Cc: Greg Kroah-Hartman Cc: Joe Perches Cc: Dmitry Torokhov Cc: Paul Gortmaker Cc: Luis R. Rodriguez Cc: Rafael J. Wysocki Cc: Joerg Roedel Cc: Alexander Gordeev Link: http://lkml.kernel.org/r/1436428847-8886-10-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/base/core.c | 3 +++ drivers/pci/msi.c | 3 +-- include/linux/device.h | 4 ++++ include/linux/msi.h | 2 +- include/linux/pci.h | 1 - 5 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/base/core.c b/drivers/base/core.c index dafae6d2f7ac..18e2a89aa138 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -662,6 +662,9 @@ void device_initialize(struct device *dev) INIT_LIST_HEAD(&dev->devres_head); device_pm_init(dev); set_dev_node(dev, -1); +#ifdef CONFIG_GENERIC_MSI_IRQ + INIT_LIST_HEAD(&dev->msi_list); +#endif } EXPORT_SYMBOL_GPL(device_initialize); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f0714c3fd315..4ef5021a084d 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -900,7 +900,7 @@ void pci_msi_shutdown(struct pci_dev *dev) return; BUG_ON(list_empty(dev_to_msi_list(&dev->dev))); - desc = first_msi_entry(dev); + desc = first_pci_msi_entry(dev); pci_msi_set_enable(dev, 0); pci_intx_for_msi(dev, 1); @@ -1044,7 +1044,6 @@ EXPORT_SYMBOL(pci_msi_enabled); void pci_msi_init_pci_dev(struct pci_dev *dev) { - INIT_LIST_HEAD(&dev->msi_list); } /** diff --git a/include/linux/device.h b/include/linux/device.h index 5a31bf3a4024..22227e7fe463 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -713,6 +713,7 @@ struct device_dma_parameters { * along with subsystem-level and driver-level callbacks. * @pins: For device pin management. * See Documentation/pinctrl.txt for details. + * @msi_list: Hosts MSI descriptors * @numa_node: NUMA node this device is close to. * @dma_mask: Dma mask (if dma'ble device). * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all @@ -776,6 +777,9 @@ struct device { #ifdef CONFIG_PINCTRL struct dev_pin_info *pins; #endif +#ifdef CONFIG_GENERIC_MSI_IRQ + struct list_head msi_list; +#endif #ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ diff --git a/include/linux/msi.h b/include/linux/msi.h index cfbd2afeaf64..57fe766a14bf 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -45,7 +45,7 @@ struct msi_desc { /* Helpers to hide struct msi_desc implementation details */ #define msi_desc_to_dev(desc) (&(desc)->dev.dev) -#define dev_to_msi_list(dev) (&to_pci_dev((dev))->msi_list) +#define dev_to_msi_list(dev) (&(dev)->msi_list) #define first_msi_entry(dev) \ list_first_entry(dev_to_msi_list((dev)), struct msi_desc, list) #define for_each_msi_entry(desc, dev) \ diff --git a/include/linux/pci.h b/include/linux/pci.h index 8a0321a8fb59..fbf245f5eba7 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -366,7 +366,6 @@ struct pci_dev { struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ #ifdef CONFIG_PCI_MSI - struct list_head msi_list; const struct attribute_group **msi_irq_groups; #endif struct pci_vpd *vpd; -- cgit v1.3-6-gb490 From 25a98bd4ff9355a218d2e7aa4d6e3c9bc2c27d6f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:45 +0800 Subject: genirq/MSI: Store 'struct device' instead of 'struct pci_dev' in struct msi_desc Store 'struct device *' instead of 'struct pci_dev *' in struct msi_desc, so struct msi_desc can be reused by non PCI based MSI drivers. Signed-off-by: Jiang Liu Reviewed-by: Yijing Wang Reviewed-by: Marc Zyngier Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Bjorn Helgaas Cc: Grant Likely Cc: Stuart Yoder Cc: Borislav Petkov Cc: Alexander Gordeev Link: http://lkml.kernel.org/r/1436428847-8886-11-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/pci/msi.c | 7 ++++++- include/linux/msi.h | 11 ++++------- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 4ef5021a084d..897e1a4bce06 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -413,7 +413,7 @@ static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) return NULL; INIT_LIST_HEAD(&desc->list); - desc->dev = dev; + desc->dev = &dev->dev; return desc; } @@ -1140,6 +1140,11 @@ int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, } EXPORT_SYMBOL(pci_enable_msix_range); +struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc) +{ + return to_pci_dev(desc->dev); +} + void *msi_desc_to_pci_sysdata(struct msi_desc *desc) { struct pci_dev *dev = msi_desc_to_pci_dev(desc); diff --git a/include/linux/msi.h b/include/linux/msi.h index 57fe766a14bf..5f77e231f515 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -14,6 +14,7 @@ extern int pci_msi_ignore_mask; /* Helper functions */ struct irq_data; struct msi_desc; +struct pci_dev; void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg); void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg); @@ -37,14 +38,14 @@ struct msi_desc { void __iomem *mask_base; u8 mask_pos; }; - struct pci_dev *dev; + struct device *dev; /* Last set MSI message */ struct msi_msg msg; }; /* Helpers to hide struct msi_desc implementation details */ -#define msi_desc_to_dev(desc) (&(desc)->dev.dev) +#define msi_desc_to_dev(desc) ((desc)->dev) #define dev_to_msi_list(dev) (&(dev)->msi_list) #define first_msi_entry(dev) \ list_first_entry(dev_to_msi_list((dev)), struct msi_desc, list) @@ -56,11 +57,7 @@ struct msi_desc { #define for_each_pci_msi_entry(desc, pdev) \ for_each_msi_entry((desc), &(pdev)->dev) -static inline struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc) -{ - return desc->dev; -} - +struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc); void *msi_desc_to_pci_sysdata(struct msi_desc *desc); #else /* CONFIG_PCI_MSI */ static inline void *msi_desc_to_pci_sysdata(struct msi_desc *desc) -- cgit v1.3-6-gb490 From aa48b6f708868ab9c22ca737f27a0da832bf7f08 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:47 +0800 Subject: genirq/MSI: Move alloc_msi_entry() from PCI into generic MSI code Move alloc_msi_entry() from PCI MSI code into generic MSI code, so it can be reused by other generic MSI drivers. Also introduce free_msi_entry() for completeness. Suggested-by: Stuart Yoder . Signed-off-by: Jiang Liu Reviewed-by: Marc Zyngier Reviewed-by: Yijing Wang Acked-by: Bjorn Helgaas Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Grant Likely Cc: Borislav Petkov Cc: Alexander Gordeev Link: http://lkml.kernel.org/r/1436428847-8886-13-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- drivers/pci/msi.c | 16 ++-------------- include/linux/msi.h | 2 ++ kernel/irq/msi.c | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 897e1a4bce06..cd4c78c193de 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -406,18 +406,6 @@ static void free_msi_irqs(struct pci_dev *dev) } } -static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) -{ - struct msi_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL); - if (!desc) - return NULL; - - INIT_LIST_HEAD(&desc->list); - desc->dev = &dev->dev; - - return desc; -} - static void pci_intx_for_msi(struct pci_dev *dev, int enable) { if (!(dev->dev_flags & PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG)) @@ -572,7 +560,7 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev, int nvec) struct msi_desc *entry; /* MSI Entry Initialization */ - entry = alloc_msi_entry(dev); + entry = alloc_msi_entry(&dev->dev); if (!entry) return NULL; @@ -700,7 +688,7 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, int i; for (i = 0; i < nvec; i++) { - entry = alloc_msi_entry(dev); + entry = alloc_msi_entry(&dev->dev); if (!entry) { if (!i) iounmap(base); diff --git a/include/linux/msi.h b/include/linux/msi.h index 518e8c4a4064..f83c87e447bc 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -96,6 +96,8 @@ static inline void *msi_desc_to_pci_sysdata(struct msi_desc *desc) } #endif /* CONFIG_PCI_MSI */ +struct msi_desc *alloc_msi_entry(struct device *dev); +void free_msi_entry(struct msi_desc *entry); void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg); void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg); void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg); diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 7bf1f1bbb7fa..7e6512b9dc1f 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -18,6 +18,23 @@ /* Temparory solution for building, will be removed later */ #include +struct msi_desc *alloc_msi_entry(struct device *dev) +{ + struct msi_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return NULL; + + INIT_LIST_HEAD(&desc->list); + desc->dev = dev; + + return desc; +} + +void free_msi_entry(struct msi_desc *entry) +{ + kfree(entry); +} + void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { *msg = entry->msg; -- cgit v1.3-6-gb490 From 28311f8e7c3f52a810c0e0d2aa62deb549c9687d Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 22 Jul 2015 09:16:22 +0300 Subject: bnx2x: Utilize FW 7.12.30 This moves bnx2x into using 7.12.30 FW. Said firmware fixes the following: - Packets from a VF with pvid configured which were sent with a different vlan were transmitted instead of being discarded. - FCoE traffic might not recover after a failue while there's traffic to another function. In addition, this FW opens the door for the driver to implement several new features; Specifically, this enhances the device's support for encapsulated packets and will allow vxlan/geneve offloads to be added in the future, as well as vlan filtering offload. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 11 ++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 4 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c | 2 + .../net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h | 2 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 87 +++++++++++++--------- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 2 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 53 +++++++++---- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h | 45 +++++++---- 8 files changed, 136 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index a90d7364334f..fc32821c2e4d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2103,9 +2103,14 @@ int bnx2x_rss(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj, if (rss_obj->udp_rss_v6) __set_bit(BNX2X_RSS_IPV6_UDP, ¶ms.rss_flags); - if (!CHIP_IS_E1x(bp)) + if (!CHIP_IS_E1x(bp)) { + /* valid only for TUNN_MODE_VXLAN tunnel mode */ + __set_bit(BNX2X_RSS_IPV4_VXLAN, ¶ms.rss_flags); + __set_bit(BNX2X_RSS_IPV6_VXLAN, ¶ms.rss_flags); + /* valid only for TUNN_MODE_GRE tunnel mode */ - __set_bit(BNX2X_RSS_GRE_INNER_HDRS, ¶ms.rss_flags); + __set_bit(BNX2X_RSS_TUNN_INNER_HDRS, ¶ms.rss_flags); + } } else { __set_bit(BNX2X_RSS_MODE_DISABLED, ¶ms.rss_flags); } @@ -3677,7 +3682,7 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb, pbd2->fw_ip_hdr_to_payload_w = hlen_w - ((sizeof(struct ipv6hdr)) >> 1); pbd_e2->data.tunnel_data.flags |= - ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER; + ETH_TUNNEL_DATA_IPV6_OUTER; } pbd2->tcp_send_seq = bswab32(inner_tcp_hdr(skb)->seq); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 03b7404d5b9b..ec50d12d3198 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -936,9 +936,7 @@ static inline int bnx2x_func_start(struct bnx2x *bp) else /* CHIP_IS_E1X */ start_params->network_cos_mode = FW_WRR; - start_params->tunnel_mode = TUNN_MODE_GRE; - start_params->gre_tunnel_type = IPGRE_TUNNEL; - start_params->inner_gre_rss_en = 1; + start_params->inner_rss = 1; if (IS_MF_UFP(bp) && BNX2X_IS_MF_SD_PROTOCOL_FCOE(bp)) { start_params->class_fail_ethtype = ETH_P_FIP; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c index 6e4294ed1fc9..b50f15496427 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c @@ -1850,6 +1850,8 @@ static void bnx2x_dcbx_fw_struct(struct bnx2x *bp, if (bp->dcbx_port_params.ets.cos_params[cos]. pri_bitmask & pri_bit) tt2cos[pri].cos = cos; + + pfc_fw_cfg->dcb_outer_pri[pri] = ttp[pri]; } /* we never want the FW to add a 0 vlan tag */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h index 7636e3c18771..bfda526ffeee 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h @@ -372,7 +372,7 @@ #define MAX_COS_NUMBER 4 #define MAX_TRAFFIC_TYPES 8 #define MAX_PFC_PRIORITIES 8 - +#define MAX_VLAN_PRIORITIES 8 /* used by array traffic_type_to_priority[] to mark traffic type \ that is not mapped to priority*/ #define LLFC_TRAFFIC_TYPE_TO_PRIORITY_UNMAPPED 0xFF diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 058bc7328220..2b6f97bc780b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -2898,8 +2898,8 @@ struct afex_stats { }; #define BCM_5710_FW_MAJOR_VERSION 7 -#define BCM_5710_FW_MINOR_VERSION 10 -#define BCM_5710_FW_REVISION_VERSION 51 +#define BCM_5710_FW_MINOR_VERSION 12 +#define BCM_5710_FW_REVISION_VERSION 30 #define BCM_5710_FW_ENGINEERING_VERSION 0 #define BCM_5710_FW_COMPILE_FLAGS 1 @@ -3901,7 +3901,11 @@ struct eth_fast_path_rx_cqe { __le16 len_on_bd; struct parsing_flags pars_flags; union eth_sgl_or_raw_data sgl_or_raw_data; - __le32 reserved1[7]; + u8 tunn_type; + u8 tunn_inner_hdrs_offset; + __le16 reserved1; + __le32 tunn_tenant_id; + __le32 padding[5]; u32 marker; }; @@ -4012,8 +4016,8 @@ struct eth_tunnel_data { __le16 pseudo_csum; u8 ip_hdr_start_inner_w; u8 flags; -#define ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER (0x1<<0) -#define ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER_SHIFT 0 +#define ETH_TUNNEL_DATA_IPV6_OUTER (0x1<<0) +#define ETH_TUNNEL_DATA_IPV6_OUTER_SHIFT 0 #define ETH_TUNNEL_DATA_RESERVED (0x7F<<1) #define ETH_TUNNEL_DATA_RESERVED_SHIFT 1 }; @@ -4120,16 +4124,12 @@ struct eth_rss_update_ramrod_data { #define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY_SHIFT 6 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY (0x1<<7) #define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY_SHIFT 7 -#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY (0x1<<8) -#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY_SHIFT 8 -#define ETH_RSS_UPDATE_RAMROD_DATA_NVGRE_KEY_ENTROPY_CAPABILITY (0x1<<9) -#define ETH_RSS_UPDATE_RAMROD_DATA_NVGRE_KEY_ENTROPY_CAPABILITY_SHIFT 9 -#define ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY (0x1<<10) -#define ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY_SHIFT 10 -#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY (0x1<<11) -#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY_SHIFT 11 -#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED (0xF<<12) -#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED_SHIFT 12 +#define ETH_RSS_UPDATE_RAMROD_DATA_TUNN_INNER_HDRS_CAPABILITY (0x1<<8) +#define ETH_RSS_UPDATE_RAMROD_DATA_TUNN_INNER_HDRS_CAPABILITY_SHIFT 8 +#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY (0x1<<9) +#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY_SHIFT 9 +#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED (0x3F<<10) +#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED_SHIFT 10 u8 rss_result_mask; u8 reserved3; __le16 reserved4; @@ -4314,6 +4314,18 @@ enum eth_tunnel_non_lso_csum_location { MAX_ETH_TUNNEL_NON_LSO_CSUM_LOCATION }; +enum eth_tunn_type { + TUNN_TYPE_NONE, + TUNN_TYPE_VXLAN, + TUNN_TYPE_L2_GRE, + TUNN_TYPE_IPV4_GRE, + TUNN_TYPE_IPV6_GRE, + TUNN_TYPE_L2_GENEVE, + TUNN_TYPE_IPV4_GENEVE, + TUNN_TYPE_IPV6_GENEVE, + MAX_ETH_TUNN_TYPE +}; + /* * Tx regular BD structure */ @@ -4758,6 +4770,9 @@ struct afex_vif_list_ramrod_data { __le16 reserved1; }; +struct c2s_pri_trans_table_entry { + u8 val[MAX_VLAN_PRIORITIES]; +}; /* * cfc delete event data @@ -5246,6 +5261,7 @@ struct flow_control_configuration { u8 dont_add_pri_0_en; u8 reserved1; __le32 reserved2; + u8 dcb_outer_pri[MAX_TRAFFIC_TYPES]; }; @@ -5260,18 +5276,25 @@ struct function_start_data { u8 path_id; u8 network_cos_mode; u8 dmae_cmd_id; - u8 tunnel_mode; - u8 gre_tunnel_type; - u8 tunn_clss_en; - u8 inner_gre_rss_en; - u8 sd_accept_mf_clss_fail; + u8 no_added_tags; + __le16 reserved0; + __le32 reserved1; + u8 inner_clss_vxlan; + u8 inner_clss_l2gre; + u8 inner_clss_l2geneve; + u8 inner_rss; __le16 vxlan_dst_port; + __le16 geneve_dst_port; + u8 sd_accept_mf_clss_fail; + u8 sd_accept_mf_clss_fail_match_ethtype; __le16 sd_accept_mf_clss_fail_ethtype; __le16 sd_vlan_eth_type; u8 sd_vlan_force_pri_flg; u8 sd_vlan_force_pri_val; - u8 sd_accept_mf_clss_fail_match_ethtype; - u8 no_added_tags; + u8 c2s_pri_tt_valid; + u8 c2s_pri_default; + u8 reserved2[6]; + struct c2s_pri_trans_table_entry c2s_pri_trans_table; }; struct function_update_data { @@ -5289,11 +5312,12 @@ struct function_update_data { u8 tx_switch_suspend; u8 echo; u8 update_tunn_cfg_flg; - u8 tunnel_mode; - u8 gre_tunnel_type; - u8 tunn_clss_en; - u8 inner_gre_rss_en; + u8 inner_clss_vxlan; + u8 inner_clss_l2gre; + u8 inner_clss_l2geneve; + u8 inner_rss; __le16 vxlan_dst_port; + __le16 geneve_dst_port; u8 sd_vlan_force_pri_change_flg; u8 sd_vlan_force_pri_flg; u8 sd_vlan_force_pri_val; @@ -5302,6 +5326,8 @@ struct function_update_data { u8 reserved1; __le16 sd_vlan_tag; __le16 sd_vlan_eth_type; + __le16 reserved0; + __le32 reserved2; }; /* @@ -5330,15 +5356,6 @@ struct fw_version { #define __FW_VERSION_RESERVED_SHIFT 4 }; - -/* GRE Tunnel Mode */ -enum gre_tunnel_type { - NVGRE_TUNNEL, - L2GRE_TUNNEL, - IPGRE_TUNNEL, - MAX_GRE_TUNNEL_TYPE -}; - /* * Dynamic Host-Coalescing - Driver(host) counters */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index c27af12314ed..845471b6093f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -5568,6 +5568,8 @@ static void bnx2x_eq_int(struct bnx2x *bp) BNX2X_STATE_OPEN): case (EVENT_RING_OPCODE_RSS_UPDATE_RULES | BNX2X_STATE_OPENING_WAIT4_PORT): + case (EVENT_RING_OPCODE_RSS_UPDATE_RULES | + BNX2X_STATE_CLOSING_WAIT4_HALT): cid = elem->message.data.eth_event.echo & BNX2X_SWCID_MASK; DP(BNX2X_MSG_SP, "got RSS_UPDATE ramrod. CID %d\n", diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 4ad415ac8cfe..7d3f85eee63f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -4060,8 +4060,14 @@ static int bnx2x_setup_rss(struct bnx2x *bp, if (test_bit(BNX2X_RSS_IPV6_UDP, &p->rss_flags)) caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY; - if (test_bit(BNX2X_RSS_GRE_INNER_HDRS, &p->rss_flags)) - caps |= ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY; + if (test_bit(BNX2X_RSS_IPV4_VXLAN, &p->rss_flags)) + caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_VXLAN_CAPABILITY; + + if (test_bit(BNX2X_RSS_IPV6_VXLAN, &p->rss_flags)) + caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY; + + if (test_bit(BNX2X_RSS_TUNN_INNER_HDRS, &p->rss_flags)) + caps |= ETH_RSS_UPDATE_RAMROD_DATA_TUNN_INNER_HDRS_CAPABILITY; /* RSS keys */ if (test_bit(BNX2X_RSS_SET_SRCH, &p->rss_flags)) { @@ -5669,10 +5675,14 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp, rdata->sd_vlan_tag = cpu_to_le16(start_params->sd_vlan_tag); rdata->path_id = BP_PATH(bp); rdata->network_cos_mode = start_params->network_cos_mode; - rdata->tunnel_mode = start_params->tunnel_mode; - rdata->gre_tunnel_type = start_params->gre_tunnel_type; - rdata->inner_gre_rss_en = start_params->inner_gre_rss_en; - rdata->vxlan_dst_port = cpu_to_le16(4789); + + rdata->vxlan_dst_port = cpu_to_le16(start_params->vxlan_dst_port); + rdata->geneve_dst_port = cpu_to_le16(start_params->geneve_dst_port); + rdata->inner_clss_l2gre = start_params->inner_clss_l2gre; + rdata->inner_clss_l2geneve = start_params->inner_clss_l2geneve; + rdata->inner_clss_vxlan = start_params->inner_clss_vxlan; + rdata->inner_rss = start_params->inner_rss; + rdata->sd_accept_mf_clss_fail = start_params->class_fail; if (start_params->class_fail_ethtype) { rdata->sd_accept_mf_clss_fail_match_ethtype = 1; @@ -5690,6 +5700,14 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp, cpu_to_le16(0x8100); rdata->no_added_tags = start_params->no_added_tags; + + rdata->c2s_pri_tt_valid = start_params->c2s_pri_valid; + if (rdata->c2s_pri_tt_valid) { + memcpy(rdata->c2s_pri_trans_table.val, + start_params->c2s_pri, + MAX_VLAN_PRIORITIES); + rdata->c2s_pri_default = start_params->c2s_pri_default; + } /* No need for an explicit memory barrier here as long we would * need to ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory @@ -5750,15 +5768,22 @@ static inline int bnx2x_func_send_switch_update(struct bnx2x *bp, if (test_bit(BNX2X_F_UPDATE_TUNNEL_CFG_CHNG, &switch_update_params->changes)) { rdata->update_tunn_cfg_flg = 1; - if (test_bit(BNX2X_F_UPDATE_TUNNEL_CLSS_EN, + if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GRE, + &switch_update_params->changes)) + rdata->inner_clss_l2gre = 1; + if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_VXLAN, + &switch_update_params->changes)) + rdata->inner_clss_vxlan = 1; + if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GENEVE, &switch_update_params->changes)) - rdata->tunn_clss_en = 1; - if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_GRE_RSS_EN, + rdata->inner_clss_l2geneve = 1; + if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_RSS, &switch_update_params->changes)) - rdata->inner_gre_rss_en = 1; - rdata->tunnel_mode = switch_update_params->tunnel_mode; - rdata->gre_tunnel_type = switch_update_params->gre_tunnel_type; - rdata->vxlan_dst_port = cpu_to_le16(4789); + rdata->inner_rss = 1; + rdata->vxlan_dst_port = + cpu_to_le16(switch_update_params->vxlan_dst_port); + rdata->geneve_dst_port = + cpu_to_le16(switch_update_params->geneve_dst_port); } rdata->echo = SWITCH_UPDATE; @@ -5885,6 +5910,8 @@ static inline int bnx2x_func_send_tx_start(struct bnx2x *bp, rdata->traffic_type_to_priority_cos[i] = tx_start_params->traffic_type_to_priority_cos[i]; + for (i = 0; i < MAX_TRAFFIC_TYPES; i++) + rdata->dcb_outer_pri[i] = tx_start_params->dcb_outer_pri[i]; /* No need for an explicit memory barrier here as long as we * ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h index 86baecb7c60c..df27bb8dce18 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h @@ -711,7 +711,10 @@ enum { BNX2X_RSS_IPV6, BNX2X_RSS_IPV6_TCP, BNX2X_RSS_IPV6_UDP, - BNX2X_RSS_GRE_INNER_HDRS, + + BNX2X_RSS_IPV4_VXLAN, + BNX2X_RSS_IPV6_VXLAN, + BNX2X_RSS_TUNN_INNER_HDRS, }; struct bnx2x_config_rss_params { @@ -1105,8 +1108,10 @@ enum { BNX2X_F_UPDATE_VLAN_FORCE_PRIO_CHNG, BNX2X_F_UPDATE_VLAN_FORCE_PRIO_FLAG, BNX2X_F_UPDATE_TUNNEL_CFG_CHNG, - BNX2X_F_UPDATE_TUNNEL_CLSS_EN, - BNX2X_F_UPDATE_TUNNEL_INNER_GRE_RSS_EN, + BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GRE, + BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_VXLAN, + BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GENEVE, + BNX2X_F_UPDATE_TUNNEL_INNER_RSS, }; /* Allowed Function states */ @@ -1171,19 +1176,23 @@ struct bnx2x_func_start_params { /* Function cos mode */ u8 network_cos_mode; - /* TUNN_MODE_NONE/TUNN_MODE_VXLAN/TUNN_MODE_GRE */ - u8 tunnel_mode; + /* UDP dest port for VXLAN */ + u16 vxlan_dst_port; - /* tunneling classification enablement */ - u8 tunn_clss_en; + /* UDP dest port for Geneve */ + u16 geneve_dst_port; - /* NVGRE_TUNNEL/L2GRE_TUNNEL/IPGRE_TUNNEL */ - u8 gre_tunnel_type; + /* Enable inner Rx classifications for L2GRE packets */ + u8 inner_clss_l2gre; - /* Enables Inner GRE RSS on the function, depends on the client RSS - * capailities - */ - u8 inner_gre_rss_en; + /* Enable inner Rx classifications for L2-Geneve packets */ + u8 inner_clss_l2geneve; + + /* Enable inner Rx classification for vxlan packets */ + u8 inner_clss_vxlan; + + /* Enable RSS according to inner header */ + u8 inner_rss; /* Allows accepting of packets failing MF classification, possibly * only matching a given ethertype @@ -1200,6 +1209,11 @@ struct bnx2x_func_start_params { /* Prevent inner vlans from being added by FW */ u8 no_added_tags; + + /* Inner-to-Outer vlan priority mapping */ + u8 c2s_pri[MAX_VLAN_PRIORITIES]; + u8 c2s_pri_default; + u8 c2s_pri_valid; }; struct bnx2x_func_switch_update_params { @@ -1207,8 +1221,8 @@ struct bnx2x_func_switch_update_params { u16 vlan; u16 vlan_eth_type; u8 vlan_force_prio; - u8 tunnel_mode; - u8 gre_tunnel_type; + u16 vxlan_dst_port; + u16 geneve_dst_port; }; struct bnx2x_func_afex_update_params { @@ -1229,6 +1243,7 @@ struct bnx2x_func_tx_start_params { u8 dcb_enabled; u8 dcb_version; u8 dont_add_pri_0_en; + u8 dcb_outer_pri[MAX_TRAFFIC_TYPES]; }; struct bnx2x_func_set_timesync_params { -- cgit v1.3-6-gb490 From 4ad79e1301f48b8c4ed2cc71c85e9b224a16b3e3 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 22 Jul 2015 09:16:23 +0300 Subject: bnx2x: Rebrand from 'broadcom' into 'qlogic' bnx2x still appears as a Broadcom driver even though the devices it utilizes belong to Qlogic for more than a year. This patch changes the various headers and the device strings to indicate the correct ownership of the device. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 4 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 4 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 4 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c | 10 +++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h | 10 +++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h | 10 +++-- .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h | 4 +- .../ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h | 2 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 4 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h | 4 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 10 +++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h | 10 +++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 50 +++++++++++----------- .../net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h | 4 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 4 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 14 +++--- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h | 14 +++--- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 10 +++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h | 10 +++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c | 4 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h | 4 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c | 10 +++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h | 22 ++++++---- 25 files changed, 142 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index cd4ae76bbff2..a59f0b952038 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1,6 +1,8 @@ -/* bnx2x.h: Broadcom Everest network driver. +/* bnx2x.h: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index fc32821c2e4d..e395ae994307 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1,6 +1,8 @@ -/* bnx2x_cmn.c: Broadcom Everest network driver. +/* bnx2x_cmn.c: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index ec50d12d3198..77693d34acc9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -1,6 +1,8 @@ -/* bnx2x_cmn.h: Broadcom Everest network driver. +/* bnx2x_cmn.h: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c index b50f15496427..7ccf6684e0a3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c @@ -1,15 +1,17 @@ -/* bnx2x_dcb.c: Broadcom Everest network driver. +/* bnx2x_dcb.c: QLogic Everest network driver. * * Copyright 2009-2013 Broadcom Corporation + * Copyright 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h index c6939ecb02c5..9a9517c0f703 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h @@ -1,15 +1,17 @@ -/* bnx2x_dcb.h: Broadcom Everest network driver. +/* bnx2x_dcb.h: QLogic Everest network driver. * * Copyright 2009-2013 Broadcom Corporation + * Copyright 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h index 741aa130c19f..eccfa13b0f2d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h @@ -1,15 +1,17 @@ -/* bnx2x_dump.h: Broadcom Everest network driver. +/* bnx2x_dump.h: QLogic Everest network driver. * * Copyright (c) 2012-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index c783b57b2c9b..fd3631b1a378 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1,6 +1,8 @@ -/* bnx2x_ethtool.c: Broadcom Everest network driver. +/* bnx2x_ethtool.c: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h index bfda526ffeee..226ab29f4cb6 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h @@ -1,6 +1,8 @@ -/* bnx2x_fw_defs.h: Broadcom Everest network driver. +/* bnx2x_fw_defs.h: Qlogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h index 8aafd9b5d6a2..9e3b5a1e9f4f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h @@ -1,6 +1,8 @@ /* bnx2x_fw_file_hdr.h: FW binary file header structure. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 2b6f97bc780b..a838b6e8f159 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -1,6 +1,8 @@ -/* bnx2x_hsi.h: Broadcom Everest network driver. +/* bnx2x_hsi.h: Qlogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h index d6e1975b7b69..46ee2c01f4c5 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h @@ -1,7 +1,9 @@ -/* bnx2x_init.h: Broadcom Everest network driver. +/* bnx2x_init.h: Qlogic Everest network driver. * Structures and macroes needed during the initialization. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h index 5669ed2e87d0..1835d2e451c0 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h @@ -1,8 +1,10 @@ -/* bnx2x_init_ops.h: Broadcom Everest network driver. +/* bnx2x_init_ops.h: Qlogic Everest network driver. * Static functions needed during the initialization. * This file is "included" in bnx2x_main.c. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index a0b03c27e0a3..7f9ec51cfe69 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -1,13 +1,15 @@ /* Copyright 2008-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available - * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * at http://www.gnu.org/licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other Qlogic software provided under a + * license other than the GPL, without Qlogic's express prior written * consent. * * Written by Yaniv Rosner diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h index d9cce4c3899b..b7d251108c19 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h @@ -1,13 +1,15 @@ /* Copyright 2008-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available - * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * at http://www.gnu.org/licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other Qlogic software provided under a + * license other than the GPL, without Qlogic's express prior written * consent. * * Written by Yaniv Rosner diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 845471b6093f..e85e6ffa4e61 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -1,6 +1,8 @@ -/* bnx2x_main.c: Broadcom Everest network driver. +/* bnx2x_main.c: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 @@ -81,11 +83,11 @@ #define TX_TIMEOUT (5*HZ) static char version[] = - "Broadcom NetXtreme II 5771x/578xx 10/20-Gigabit Ethernet Driver " + "QLogic 5771x/578xx 10/20-Gigabit Ethernet Driver " DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Eliezer Tamir"); -MODULE_DESCRIPTION("Broadcom NetXtreme II " +MODULE_DESCRIPTION("QLogic " "BCM57710/57711/57711E/" "57712/57712_MF/57800/57800_MF/57810/57810_MF/" "57840/57840_MF Driver"); @@ -163,27 +165,27 @@ enum bnx2x_board_type { static struct { char *name; } board_info[] = { - [BCM57710] = { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" }, - [BCM57711] = { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" }, - [BCM57711E] = { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" }, - [BCM57712] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" }, - [BCM57712_MF] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" }, - [BCM57712_VF] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Virtual Function" }, - [BCM57800] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" }, - [BCM57800_MF] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" }, - [BCM57800_VF] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Virtual Function" }, - [BCM57810] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" }, - [BCM57810_MF] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" }, - [BCM57810_VF] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Virtual Function" }, - [BCM57840_4_10] = { "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" }, - [BCM57840_2_20] = { "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" }, - [BCM57840_MF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" }, - [BCM57840_VF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" }, - [BCM57811] = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet" }, - [BCM57811_MF] = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function" }, - [BCM57840_O] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" }, - [BCM57840_MFO] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" }, - [BCM57811_VF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" } + [BCM57710] = { "QLogic BCM57710 10 Gigabit PCIe [Everest]" }, + [BCM57711] = { "QLogic BCM57711 10 Gigabit PCIe" }, + [BCM57711E] = { "QLogic BCM57711E 10 Gigabit PCIe" }, + [BCM57712] = { "QLogic BCM57712 10 Gigabit Ethernet" }, + [BCM57712_MF] = { "QLogic BCM57712 10 Gigabit Ethernet Multi Function" }, + [BCM57712_VF] = { "QLogic BCM57712 10 Gigabit Ethernet Virtual Function" }, + [BCM57800] = { "QLogic BCM57800 10 Gigabit Ethernet" }, + [BCM57800_MF] = { "QLogic BCM57800 10 Gigabit Ethernet Multi Function" }, + [BCM57800_VF] = { "QLogic BCM57800 10 Gigabit Ethernet Virtual Function" }, + [BCM57810] = { "QLogic BCM57810 10 Gigabit Ethernet" }, + [BCM57810_MF] = { "QLogic BCM57810 10 Gigabit Ethernet Multi Function" }, + [BCM57810_VF] = { "QLogic BCM57810 10 Gigabit Ethernet Virtual Function" }, + [BCM57840_4_10] = { "QLogic BCM57840 10 Gigabit Ethernet" }, + [BCM57840_2_20] = { "QLogic BCM57840 20 Gigabit Ethernet" }, + [BCM57840_MF] = { "QLogic BCM57840 10/20 Gigabit Ethernet Multi Function" }, + [BCM57840_VF] = { "QLogic BCM57840 10/20 Gigabit Ethernet Virtual Function" }, + [BCM57811] = { "QLogic BCM57811 10 Gigabit Ethernet" }, + [BCM57811_MF] = { "QLogic BCM57811 10 Gigabit Ethernet Multi Function" }, + [BCM57840_O] = { "QLogic BCM57840 10/20 Gigabit Ethernet" }, + [BCM57840_MFO] = { "QLogic BCM57840 10/20 Gigabit Ethernet Multi Function" }, + [BCM57811_VF] = { "QLogic BCM57840 10/20 Gigabit Ethernet Virtual Function" } }; #ifndef PCI_DEVICE_ID_NX2_57710 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h index caf1aef651eb..a91ccbf36345 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h @@ -1,6 +1,8 @@ -/* bnx2x_mfw_req.h: Broadcom Everest network driver. +/* bnx2x_mfw_req.h: Qlogic Everest network driver. * * Copyright (c) 2012-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index 49d511092c82..b7d33a1deb77 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -1,6 +1,8 @@ -/* bnx2x_reg.h: Broadcom Everest network driver. +/* bnx2x_reg.h: Qlogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 7d3f85eee63f..265fe0a90adc 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -1,15 +1,17 @@ -/* bnx2x_sp.c: Broadcom Everest network driver. +/* bnx2x_sp.c: Qlogic Everest network driver. * - * Copyright (c) 2011-2013 Broadcom Corporation + * Copyright 2011-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and Qlogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available - * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * at http://www.gnu.org/licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other Qlogic software provided under a + * license other than the GPL, without Qlogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h index df27bb8dce18..324e9f986314 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h @@ -1,15 +1,17 @@ -/* bnx2x_sp.h: Broadcom Everest network driver. +/* bnx2x_sp.h: Qlogic Everest network driver. * - * Copyright (c) 2011-2013 Broadcom Corporation + * Copyright 2011-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and Qlogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available - * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * at http://www.gnu.org/licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other Qlogic software provided under a + * license other than the GPL, without Qlogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index f67348d16966..4d5c7b3d3a32 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -1,15 +1,17 @@ -/* bnx2x_sriov.c: Broadcom Everest network driver. +/* bnx2x_sriov.c: QLogic Everest network driver. * * Copyright 2009-2013 Broadcom Corporation + * Copyright 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h index 66ee62a0401a..2011205ec8d4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h @@ -1,15 +1,17 @@ -/* bnx2x_sriov.h: Broadcom Everest network driver. +/* bnx2x_sriov.h: QLogic Everest network driver. * * Copyright 2009-2013 Broadcom Corporation + * Copyright 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c index 69d699f0730a..7e0919aa450e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c @@ -1,6 +1,8 @@ -/* bnx2x_stats.c: Broadcom Everest network driver. +/* bnx2x_stats.c: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h index 965539a9dabe..b2644ed13d06 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h @@ -1,6 +1,8 @@ -/* bnx2x_stats.h: Broadcom Everest network driver. +/* bnx2x_stats.h: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index 06b8c0d8fd3b..31b79bd13292 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -1,15 +1,17 @@ -/* bnx2x_vfpf.c: Broadcom Everest network driver. +/* bnx2x_vfpf.c: QLogic Everest network driver. * * Copyright 2009-2013 Broadcom Corporation + * Copyright 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h index b86479fc0d2f..f0110f4bd0a3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h @@ -1,16 +1,22 @@ -/* bnx2x_vfpf.h: Broadcom Everest network driver. +/* bnx2x_vfpf.h: Qlogic Everest network driver. * * Copyright (c) 2011-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and Qlogic execute a separate written software license * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2, available - * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * under the terms of the GNU General Public License version 2 (the “GPL”), + * available at http://www.gnu.org/licenses/gpl-2.0.html, with the following + * added to such license: * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written - * consent. + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module which is + * not derived from this software. The special exception does not apply to any + * modifications of the software. * * Maintained by: Ariel Elior * Written by: Ariel Elior -- cgit v1.3-6-gb490 From 924c6216f88172050a519639722e949b838529cc Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 22 Jul 2015 09:16:24 +0300 Subject: bnx2x: Add 84858 phy support This adds support to a new copper phy. Signed-off-by: Yaniv Rosner Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 3 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 244 ++++++++++++++++++----- drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 58 +++--- 3 files changed, 232 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index a838b6e8f159..5425de059aae 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -731,6 +731,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8722 0x00000f00 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM54616 0x00001000 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84834 0x00001100 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84858 0x00001200 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_FAILURE 0x0000fd00 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_NOT_CONN 0x0000ff00 @@ -788,6 +789,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722 0x00000f00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54616 0x00001000 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834 0x00001100 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858 0x00001200 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT_WC 0x0000fc00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00 @@ -2253,6 +2255,7 @@ struct shmem2_region { u32 reserved4; /* Offset 0x150 */ u32 link_attr_sync[PORT_MAX]; /* Offset 0x154 */ #define LINK_ATTR_SYNC_KR2_ENABLE 0x00000001 + #define LINK_ATTR_84858 0x00000002 #define LINK_SFP_EEPROM_COMP_CODE_MASK 0x0000ff00 #define LINK_SFP_EEPROM_COMP_CODE_SHIFT 8 #define LINK_SFP_EEPROM_COMP_CODE_SR 0x00001000 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 7f9ec51cfe69..d946bba43726 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -9654,6 +9654,13 @@ static void bnx2x_8727_link_reset(struct bnx2x_phy *phy, /******************************************************************/ /* BCM8481/BCM84823/BCM84833 PHY SECTION */ /******************************************************************/ +static int bnx2x_is_8483x_8485x(struct bnx2x_phy *phy) +{ + return ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || + (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) || + (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858)); +} + static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy, struct bnx2x *bp, u8 port) @@ -9668,8 +9675,7 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy, }; u16 fw_ver1; - if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) { + if (bnx2x_is_8483x_8485x(phy)) { bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &fw_ver1); bnx2x_save_spirom_version(bp, port, fw_ver1 & 0xfff, phy->ver_addr); @@ -9751,8 +9757,7 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp, bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg, reg_set[i].val); - if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) + if (bnx2x_is_8483x_8485x(phy)) offset = MDIO_PMA_REG_84833_CTL_LED_CTL_1; else offset = MDIO_PMA_REG_84823_CTL_LED_CTL_1; @@ -9770,8 +9775,7 @@ static void bnx2x_848xx_specific_func(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; switch (action) { case PHY_INIT: - if ((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) && - (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) { + if (!bnx2x_is_8483x_8485x(phy)) { /* Save spirom version */ bnx2x_save_848xx_spirom_version(phy, bp, params->port); } @@ -9903,8 +9907,7 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, /* Always write this if this is not 84833/4. * For 84833/4, write it only when it's a forced speed. */ - if (((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) && - (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) || + if (!bnx2x_is_8483x_8485x(phy) || ((autoneg_val & (1<<12)) == 0)) bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, @@ -9951,8 +9954,86 @@ static int bnx2x_8481_config_init(struct bnx2x_phy *phy, return bnx2x_848xx_cmn_config_init(phy, params, vars); } -#define PHY84833_CMDHDLR_WAIT 300 -#define PHY84833_CMDHDLR_MAX_ARGS 5 +#define PHY848xx_CMDHDLR_WAIT 300 +#define PHY848xx_CMDHDLR_MAX_ARGS 5 + +static int bnx2x_84858_cmd_hdlr(struct bnx2x_phy *phy, + struct link_params *params, + u16 fw_cmd, + u16 cmd_args[], int argc) +{ + int idx; + u16 val; + struct bnx2x *bp = params->bp; + + /* Step 1: Poll the STATUS register to see whether the previous command + * is in progress or the system is busy (CMD_IN_PROGRESS or + * SYSTEM_BUSY). If previous command is in progress or system is busy, + * check again until the previous command finishes execution and the + * system is available for taking command + */ + + for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_848xx_CMD_HDLR_STATUS, &val); + if ((val != PHY84858_STATUS_CMD_IN_PROGRESS) && + (val != PHY84858_STATUS_CMD_SYSTEM_BUSY)) + break; + usleep_range(1000, 2000); + } + if (idx >= PHY848xx_CMDHDLR_WAIT) { + DP(NETIF_MSG_LINK, "FW cmd: FW not ready.\n"); + return -EINVAL; + } + + /* Step2: If any parameters are required for the function, write them + * to the required DATA registers + */ + + for (idx = 0; idx < argc; idx++) { + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_848xx_CMD_HDLR_DATA1 + idx, + cmd_args[idx]); + } + + /* Step3: When the firmware is ready for commands, write the 'Command + * code' to the CMD register + */ + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_848xx_CMD_HDLR_COMMAND, fw_cmd); + + /* Step4: Once the command has been written, poll the STATUS register + * to check whether the command has completed (CMD_COMPLETED_PASS/ + * CMD_FOR_CMDS or CMD_COMPLETED_ERROR). + */ + + for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_848xx_CMD_HDLR_STATUS, &val); + if ((val == PHY84858_STATUS_CMD_COMPLETE_PASS) || + (val == PHY84858_STATUS_CMD_COMPLETE_ERROR)) + break; + usleep_range(1000, 2000); + } + if ((idx >= PHY848xx_CMDHDLR_WAIT) || + (val == PHY84858_STATUS_CMD_COMPLETE_ERROR)) { + DP(NETIF_MSG_LINK, "FW cmd failed.\n"); + return -EINVAL; + } + /* Step5: Once the command has completed, read the specficied DATA + * registers for any saved results for the command, if applicable + */ + + /* Gather returning data */ + for (idx = 0; idx < argc; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_848xx_CMD_HDLR_DATA1 + idx, + &cmd_args[idx]); + } + + return 0; +} + static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy, struct link_params *params, u16 fw_cmd, u16 cmd_args[], int argc) @@ -9962,16 +10043,16 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; /* Write CMD_OPEN_OVERRIDE to STATUS reg */ bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_STATUS, + MDIO_848xx_CMD_HDLR_STATUS, PHY84833_STATUS_CMD_OPEN_OVERRIDE); - for (idx = 0; idx < PHY84833_CMDHDLR_WAIT; idx++) { + for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) { bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_STATUS, &val); + MDIO_848xx_CMD_HDLR_STATUS, &val); if (val == PHY84833_STATUS_CMD_OPEN_FOR_CMDS) break; usleep_range(1000, 2000); } - if (idx >= PHY84833_CMDHDLR_WAIT) { + if (idx >= PHY848xx_CMDHDLR_WAIT) { DP(NETIF_MSG_LINK, "FW cmd: FW not ready.\n"); return -EINVAL; } @@ -9979,42 +10060,62 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy, /* Prepare argument(s) and issue command */ for (idx = 0; idx < argc; idx++) { bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_DATA1 + idx, + MDIO_848xx_CMD_HDLR_DATA1 + idx, cmd_args[idx]); } bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_COMMAND, fw_cmd); - for (idx = 0; idx < PHY84833_CMDHDLR_WAIT; idx++) { + MDIO_848xx_CMD_HDLR_COMMAND, fw_cmd); + for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) { bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_STATUS, &val); + MDIO_848xx_CMD_HDLR_STATUS, &val); if ((val == PHY84833_STATUS_CMD_COMPLETE_PASS) || - (val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) + (val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) break; usleep_range(1000, 2000); } - if ((idx >= PHY84833_CMDHDLR_WAIT) || - (val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) { + if ((idx >= PHY848xx_CMDHDLR_WAIT) || + (val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) { DP(NETIF_MSG_LINK, "FW cmd failed.\n"); return -EINVAL; } /* Gather returning data */ for (idx = 0; idx < argc; idx++) { bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_DATA1 + idx, + MDIO_848xx_CMD_HDLR_DATA1 + idx, &cmd_args[idx]); } bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_STATUS, + MDIO_848xx_CMD_HDLR_STATUS, PHY84833_STATUS_CMD_CLEAR_COMPLETE); return 0; } -static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static int bnx2x_848xx_cmd_hdlr(struct bnx2x_phy *phy, + struct link_params *params, + u16 fw_cmd, + u16 cmd_args[], int argc) +{ + struct bnx2x *bp = params->bp; + + if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) || + (REG_RD(bp, params->shmem2_base + + offsetof(struct shmem2_region, + link_attr_sync[params->port])) & + LINK_ATTR_84858)) { + return bnx2x_84858_cmd_hdlr(phy, params, fw_cmd, cmd_args, + argc); + } else { + return bnx2x_84833_cmd_hdlr(phy, params, fw_cmd, cmd_args, + argc); + } +} + +static int bnx2x_848xx_pair_swap_cfg(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { u32 pair_swap; - u16 data[PHY84833_CMDHDLR_MAX_ARGS]; + u16 data[PHY848xx_CMDHDLR_MAX_ARGS]; int status; struct bnx2x *bp = params->bp; @@ -10030,8 +10131,9 @@ static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy, /* Only the second argument is used for this command */ data[1] = (u16)pair_swap; - status = bnx2x_84833_cmd_hdlr(phy, params, - PHY84833_CMD_SET_PAIR_SWAP, data, PHY84833_CMDHDLR_MAX_ARGS); + status = bnx2x_848xx_cmd_hdlr(phy, params, + PHY848xx_CMD_SET_PAIR_SWAP, data, + PHY848xx_CMDHDLR_MAX_ARGS); if (status == 0) DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data[1]); @@ -10120,8 +10222,8 @@ static int bnx2x_8483x_disable_eee(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "Don't Advertise 10GBase-T EEE\n"); /* Prevent Phy from working in EEE and advertising it */ - rc = bnx2x_84833_cmd_hdlr(phy, params, - PHY84833_CMD_SET_EEE_MODE, &cmd_args, 1); + rc = bnx2x_848xx_cmd_hdlr(phy, params, + PHY848xx_CMD_SET_EEE_MODE, &cmd_args, 1); if (rc) { DP(NETIF_MSG_LINK, "EEE disable failed.\n"); return rc; @@ -10138,8 +10240,8 @@ static int bnx2x_8483x_enable_eee(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; u16 cmd_args = 1; - rc = bnx2x_84833_cmd_hdlr(phy, params, - PHY84833_CMD_SET_EEE_MODE, &cmd_args, 1); + rc = bnx2x_848xx_cmd_hdlr(phy, params, + PHY848xx_CMD_SET_EEE_MODE, &cmd_args, 1); if (rc) { DP(NETIF_MSG_LINK, "EEE enable failed.\n"); return rc; @@ -10157,7 +10259,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, u8 port, initialize = 1; u16 val; u32 actual_phy_selection; - u16 cmd_args[PHY84833_CMDHDLR_MAX_ARGS]; + u16 cmd_args[PHY848xx_CMDHDLR_MAX_ARGS]; int rc = 0; usleep_range(1000, 2000); @@ -10182,8 +10284,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, /* Wait for GPHY to come out of reset */ msleep(50); - if ((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) && - (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) { + if (!bnx2x_is_8483x_8485x(phy)) { /* BCM84823 requires that XGXS links up first @ 10G for normal * behavior. */ @@ -10194,7 +10295,19 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, bnx2x_program_serdes(¶ms->phy[INT_PHY], params, vars); vars->line_speed = temp; } + /* Check if this is actually BCM84858 */ + if (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) { + u16 hw_rev; + bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, + MDIO_AN_REG_848xx_ID_MSB, &hw_rev); + if (hw_rev == BCM84858_PHY_ID) { + params->link_attr_sync |= LINK_ATTR_84858; + bnx2x_update_link_attr(params, params->link_attr_sync); + } + } + + /* Set dual-media configuration according to configuration */ bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, MDIO_CTL_REG_84823_MEDIA, &val); val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK | @@ -10239,18 +10352,17 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n", params->multi_phy_config, val); - if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) { - bnx2x_84833_pair_swap_cfg(phy, params, vars); + if (bnx2x_is_8483x_8485x(phy)) { + bnx2x_848xx_pair_swap_cfg(phy, params, vars); /* Keep AutogrEEEn disabled. */ cmd_args[0] = 0x0; cmd_args[1] = 0x0; cmd_args[2] = PHY84833_CONSTANT_LATENCY + 1; cmd_args[3] = PHY84833_CONSTANT_LATENCY; - rc = bnx2x_84833_cmd_hdlr(phy, params, - PHY84833_CMD_SET_EEE_MODE, cmd_args, - PHY84833_CMDHDLR_MAX_ARGS); + rc = bnx2x_848xx_cmd_hdlr(phy, params, + PHY848xx_CMD_SET_EEE_MODE, cmd_args, + PHY848xx_CMDHDLR_MAX_ARGS); if (rc) DP(NETIF_MSG_LINK, "Cfg AutogrEEEn failed.\n"); } @@ -10304,8 +10416,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, vars->eee_status &= ~SHMEM_EEE_SUPPORTED_MASK; } - if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) { + if (bnx2x_is_8483x_8485x(phy)) { /* Bring PHY out of super isolate mode as the final step. */ bnx2x_cl45_read_and_write(bp, phy, MDIO_CTL_DEVAD, @@ -10437,8 +10548,7 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy, LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE; /* Determine if EEE was negotiated */ - if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) + if (bnx2x_is_8483x_8485x(phy)) bnx2x_eee_an_resolve(phy, params, vars); } @@ -11844,6 +11954,40 @@ static const struct bnx2x_phy phy_84834 = { .phy_specific_func = (phy_specific_func_t)bnx2x_848xx_specific_func }; +static const struct bnx2x_phy phy_84858 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858, + .addr = 0xff, + .def_md_devad = 0, + .flags = FLAGS_FAN_FAILURE_DET_REQ | + FLAGS_REARM_LATCH_SIGNAL, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_BASE_T, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_848x3_config_init, + .read_status = (read_status_t)bnx2x_848xx_read_status, + .link_reset = (link_reset_t)bnx2x_848x3_link_reset, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, + .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, + .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led, + .phy_specific_func = (phy_specific_func_t)bnx2x_848xx_specific_func +}; + static const struct bnx2x_phy phy_54618se = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE, .addr = 0xff, @@ -12130,6 +12274,9 @@ static int bnx2x_populate_ext_phy(struct bnx2x *bp, case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834: *phy = phy_84834; break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858: + *phy = phy_84858; + break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54616: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE: *phy = phy_54618se; @@ -12186,9 +12333,7 @@ static int bnx2x_populate_ext_phy(struct bnx2x *bp, } phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port); - if (((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) && - (phy->ver_addr)) { + if (bnx2x_is_8483x_8485x(phy) && (phy->ver_addr)) { /* Remove 100Mb link supported for BCM84833/4 when phy fw * version lower than or equal to 1.39 */ @@ -13283,6 +13428,7 @@ static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[], break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858: /* GPIO3's are linked, and so both need to be toggled * to obtain required 2us pulse. */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index b7d33a1deb77..f18bf511d854 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -7242,6 +7242,9 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_AN_REG_8481_LEGACY_MII_CTRL 0xffe0 #define MDIO_AN_REG_8481_MII_CTRL_FORCE_1G 0x40 #define MDIO_AN_REG_8481_LEGACY_MII_STATUS 0xffe1 +#define MDIO_AN_REG_848xx_ID_MSB 0xffe2 +#define BCM84858_PHY_ID 0x600d +#define MDIO_AN_REG_848xx_ID_LSB 0xffe3 #define MDIO_AN_REG_8481_LEGACY_AN_ADV 0xffe4 #define MDIO_AN_REG_8481_LEGACY_AN_EXPANSION 0xffe6 #define MDIO_AN_REG_8481_1000T_CTRL 0xffe9 @@ -7285,31 +7288,31 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_84833_TOP_CFG_FW_NO_EEE 0x1f81 #define MDIO_84833_TOP_CFG_XGPHY_STRAP1 0x401a #define MDIO_84833_SUPER_ISOLATE 0x8000 -/* These are mailbox register set used by 84833. */ -#define MDIO_84833_TOP_CFG_SCRATCH_REG0 0x4005 -#define MDIO_84833_TOP_CFG_SCRATCH_REG1 0x4006 -#define MDIO_84833_TOP_CFG_SCRATCH_REG2 0x4007 -#define MDIO_84833_TOP_CFG_SCRATCH_REG3 0x4008 -#define MDIO_84833_TOP_CFG_SCRATCH_REG4 0x4009 -#define MDIO_84833_TOP_CFG_SCRATCH_REG26 0x4037 -#define MDIO_84833_TOP_CFG_SCRATCH_REG27 0x4038 -#define MDIO_84833_TOP_CFG_SCRATCH_REG28 0x4039 -#define MDIO_84833_TOP_CFG_SCRATCH_REG29 0x403a -#define MDIO_84833_TOP_CFG_SCRATCH_REG30 0x403b -#define MDIO_84833_TOP_CFG_SCRATCH_REG31 0x403c -#define MDIO_84833_CMD_HDLR_COMMAND MDIO_84833_TOP_CFG_SCRATCH_REG0 -#define MDIO_84833_CMD_HDLR_STATUS MDIO_84833_TOP_CFG_SCRATCH_REG26 -#define MDIO_84833_CMD_HDLR_DATA1 MDIO_84833_TOP_CFG_SCRATCH_REG27 -#define MDIO_84833_CMD_HDLR_DATA2 MDIO_84833_TOP_CFG_SCRATCH_REG28 -#define MDIO_84833_CMD_HDLR_DATA3 MDIO_84833_TOP_CFG_SCRATCH_REG29 -#define MDIO_84833_CMD_HDLR_DATA4 MDIO_84833_TOP_CFG_SCRATCH_REG30 -#define MDIO_84833_CMD_HDLR_DATA5 MDIO_84833_TOP_CFG_SCRATCH_REG31 +/* These are mailbox register set used by 84833/84858. */ +#define MDIO_848xx_TOP_CFG_SCRATCH_REG0 0x4005 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG1 0x4006 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG2 0x4007 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG3 0x4008 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG4 0x4009 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG26 0x4037 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG27 0x4038 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG28 0x4039 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG29 0x403a +#define MDIO_848xx_TOP_CFG_SCRATCH_REG30 0x403b +#define MDIO_848xx_TOP_CFG_SCRATCH_REG31 0x403c +#define MDIO_848xx_CMD_HDLR_COMMAND (MDIO_848xx_TOP_CFG_SCRATCH_REG0) +#define MDIO_848xx_CMD_HDLR_STATUS (MDIO_848xx_TOP_CFG_SCRATCH_REG26) +#define MDIO_848xx_CMD_HDLR_DATA1 (MDIO_848xx_TOP_CFG_SCRATCH_REG27) +#define MDIO_848xx_CMD_HDLR_DATA2 (MDIO_848xx_TOP_CFG_SCRATCH_REG28) +#define MDIO_848xx_CMD_HDLR_DATA3 (MDIO_848xx_TOP_CFG_SCRATCH_REG29) +#define MDIO_848xx_CMD_HDLR_DATA4 (MDIO_848xx_TOP_CFG_SCRATCH_REG30) +#define MDIO_848xx_CMD_HDLR_DATA5 (MDIO_848xx_TOP_CFG_SCRATCH_REG31) -/* Mailbox command set used by 84833. */ -#define PHY84833_CMD_SET_PAIR_SWAP 0x8001 -#define PHY84833_CMD_GET_EEE_MODE 0x8008 -#define PHY84833_CMD_SET_EEE_MODE 0x8009 -/* Mailbox status set used by 84833. */ +/* Mailbox command set used by 84833/84858 */ +#define PHY848xx_CMD_SET_PAIR_SWAP 0x8001 +#define PHY848xx_CMD_GET_EEE_MODE 0x8008 +#define PHY848xx_CMD_SET_EEE_MODE 0x8009 +/* Mailbox status set used by 84833 only */ #define PHY84833_STATUS_CMD_RECEIVED 0x0001 #define PHY84833_STATUS_CMD_IN_PROGRESS 0x0002 #define PHY84833_STATUS_CMD_COMPLETE_PASS 0x0004 @@ -7320,6 +7323,13 @@ Theotherbitsarereservedandshouldbezero*/ #define PHY84833_STATUS_CMD_CLEAR_COMPLETE 0x0080 #define PHY84833_STATUS_CMD_OPEN_OVERRIDE 0xa5a5 +/* Mailbox status set used by 84858 only */ +#define PHY84858_STATUS_CMD_RECEIVED 0x0001 +#define PHY84858_STATUS_CMD_IN_PROGRESS 0x0002 +#define PHY84858_STATUS_CMD_COMPLETE_PASS 0x0004 +#define PHY84858_STATUS_CMD_COMPLETE_ERROR 0x0008 +#define PHY84858_STATUS_CMD_SYSTEM_BUSY 0xbbbb + /* Warpcore clause 45 addressing */ #define MDIO_WC_DEVAD 0x3 -- cgit v1.3-6-gb490 From 230d00eb4bfe0ddc88b848fd953f7b871ee2ecd7 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 22 Jul 2015 09:16:25 +0300 Subject: bnx2x: new Multi-function mode - BD This adds support to a new multi-function mode, enabling driver to initialize such devices and correctly interacting with management FW for fully utilizing their features. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 3 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 74 +++++++++++++++++++++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 36 +++++++++++ .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 3 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 74 ++++++++++++++++++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 56 ++++++++++++---- drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 17 ++++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 3 + 8 files changed, 251 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index a59f0b952038..ecf1d7f6ab27 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1424,6 +1424,7 @@ enum { SUB_MF_MODE_UNKNOWN = 0, SUB_MF_MODE_UFP, SUB_MF_MODE_NPAR1_DOT_5, + SUB_MF_MODE_BD, }; struct bnx2x { @@ -1638,6 +1639,8 @@ struct bnx2x { u8 mf_sub_mode; #define IS_MF_UFP(bp) (IS_MF_SD(bp) && \ bp->mf_sub_mode == SUB_MF_MODE_UFP) +#define IS_MF_BD(bp) (IS_MF_SD(bp) && \ + bp->mf_sub_mode == SUB_MF_MODE_BD) u8 wol; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index e395ae994307..b1d16d34551d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2517,6 +2517,20 @@ static void bnx2x_bz_fp(struct bnx2x *bp, int index) fp->mode = TPA_MODE_DISABLED; } +void bnx2x_set_os_driver_state(struct bnx2x *bp, u32 state) +{ + u32 cur; + + if (!IS_MF_BD(bp) || !SHMEM2_HAS(bp, os_driver_state) || IS_VF(bp)) + return; + + cur = SHMEM2_RD(bp, os_driver_state[BP_FW_MB_IDX(bp)]); + DP(NETIF_MSG_IFUP, "Driver state %08x-->%08x\n", + cur, state); + + SHMEM2_WR(bp, os_driver_state[BP_FW_MB_IDX(bp)], state); +} + int bnx2x_load_cnic(struct bnx2x *bp) { int i, rc, port = BP_PORT(bp); @@ -2880,6 +2894,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* mark driver is loaded in shmem2 */ u32 val; val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]); + val &= ~DRV_FLAGS_MTU_MASK; + val |= (bp->dev->mtu << DRV_FLAGS_MTU_SHIFT); SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)], val | DRV_FLAGS_CAPABILITIES_LOADED_SUPPORTED | DRV_FLAGS_CAPABILITIES_LOADED_L2); @@ -2896,6 +2912,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) if (bp->port.pmf && (bp->state != BNX2X_STATE_DIAG)) bnx2x_dcbx_init(bp, false); + if (!IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp)) + bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_ACTIVE); + DP(NETIF_MSG_IFUP, "Ending successfully NIC load\n"); return 0; @@ -2963,6 +2982,9 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link) DP(NETIF_MSG_IFUP, "Starting NIC unload\n"); + if (!IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp)) + bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_DISABLED); + /* mark driver is unloaded in shmem2 */ if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) { u32 val; @@ -4191,6 +4213,41 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +void bnx2x_get_c2s_mapping(struct bnx2x *bp, u8 *c2s_map, u8 *c2s_default) +{ + int mfw_vn = BP_FW_MB_IDX(bp); + u32 tmp; + + /* If the shmem shouldn't affect configuration, reflect */ + if (!IS_MF_BD(bp)) { + int i; + + for (i = 0; i < BNX2X_MAX_PRIORITY; i++) + c2s_map[i] = i; + *c2s_default = 0; + + return; + } + + tmp = SHMEM2_RD(bp, c2s_pcp_map_lower[mfw_vn]); + tmp = (__force u32)be32_to_cpu((__force __be32)tmp); + c2s_map[0] = tmp & 0xff; + c2s_map[1] = (tmp >> 8) & 0xff; + c2s_map[2] = (tmp >> 16) & 0xff; + c2s_map[3] = (tmp >> 24) & 0xff; + + tmp = SHMEM2_RD(bp, c2s_pcp_map_upper[mfw_vn]); + tmp = (__force u32)be32_to_cpu((__force __be32)tmp); + c2s_map[4] = tmp & 0xff; + c2s_map[5] = (tmp >> 8) & 0xff; + c2s_map[6] = (tmp >> 16) & 0xff; + c2s_map[7] = (tmp >> 24) & 0xff; + + tmp = SHMEM2_RD(bp, c2s_pcp_map_default[mfw_vn]); + tmp = (__force u32)be32_to_cpu((__force __be32)tmp); + *c2s_default = (tmp >> (8 * mfw_vn)) & 0xff; +} + /** * bnx2x_setup_tc - routine to configure net_device for multi tc * @@ -4201,8 +4258,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) */ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc) { - int cos, prio, count, offset; struct bnx2x *bp = netdev_priv(dev); + u8 c2s_map[BNX2X_MAX_PRIORITY], c2s_def; + int cos, prio, count, offset; /* setup tc must be called under rtnl lock */ ASSERT_RTNL(); @@ -4226,12 +4284,16 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc) return -EINVAL; } + bnx2x_get_c2s_mapping(bp, c2s_map, &c2s_def); + /* configure priority to traffic class mapping */ for (prio = 0; prio < BNX2X_MAX_PRIORITY; prio++) { - netdev_set_prio_tc_map(dev, prio, bp->prio_to_cos[prio]); + int outer_prio = c2s_map[prio]; + + netdev_set_prio_tc_map(dev, prio, bp->prio_to_cos[outer_prio]); DP(BNX2X_MSG_SP | NETIF_MSG_IFUP, "mapping priority %d to tc %d\n", - prio, bp->prio_to_cos[prio]); + outer_prio, bp->prio_to_cos[outer_prio]); } /* Use this configuration to differentiate tc0 from other COSes @@ -4285,6 +4347,9 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p) if (netif_running(dev)) rc = bnx2x_set_eth_mac(bp, true); + if (IS_PF(bp) && SHMEM2_HAS(bp, curr_cfg)) + SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS); + return rc; } @@ -4838,6 +4903,9 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) */ dev->mtu = new_mtu; + if (IS_PF(bp) && SHMEM2_HAS(bp, curr_cfg)) + SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS); + return bnx2x_reload_if_running(dev); } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 77693d34acc9..821346ce50eb 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -622,6 +622,14 @@ int bnx2x_set_features(struct net_device *dev, netdev_features_t features); */ void bnx2x_tx_timeout(struct net_device *dev); +/** bnx2x_get_c2s_mapping - read inner-to-outer vlan configuration + * c2s_map should have BNX2X_MAX_PRIORITY entries. + * @bp: driver handle + * @c2s_map: should have BNX2X_MAX_PRIORITY entries for mapping + * @c2s_default: entry for non-tagged configuration + */ +void bnx2x_get_c2s_mapping(struct bnx2x *bp, u8 *c2s_map, u8 *c2s_default); + /*********************** Inlines **********************************/ /*********************** Fast path ********************************/ static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp) @@ -933,6 +941,27 @@ static inline int bnx2x_func_start(struct bnx2x *bp) start_params->mf_mode = bp->mf_mode; start_params->sd_vlan_tag = bp->mf_ov; + /* Configure Ethertype for BD mode */ + if (IS_MF_BD(bp)) { + DP(NETIF_MSG_IFUP, "Configuring ethertype 0x88a8 for BD\n"); + start_params->sd_vlan_eth_type = ETH_P_8021AD; + REG_WR(bp, PRS_REG_VLAN_TYPE_0, ETH_P_8021AD); + REG_WR(bp, PBF_REG_VLAN_TYPE_0, ETH_P_8021AD); + REG_WR(bp, NIG_REG_LLH_E1HOV_TYPE_1, ETH_P_8021AD); + + bnx2x_get_c2s_mapping(bp, start_params->c2s_pri, + &start_params->c2s_pri_default); + start_params->c2s_pri_valid = 1; + + DP(NETIF_MSG_IFUP, + "Inner-to-Outer priority: %02x %02x %02x %02x %02x %02x %02x %02x [Default %02x]\n", + start_params->c2s_pri[0], start_params->c2s_pri[1], + start_params->c2s_pri[2], start_params->c2s_pri[3], + start_params->c2s_pri[4], start_params->c2s_pri[5], + start_params->c2s_pri[6], start_params->c2s_pri[7], + start_params->c2s_pri_default); + } + if (CHIP_IS_E2(bp) || CHIP_IS_E3(bp)) start_params->network_cos_mode = STATIC_COS; else /* CHIP_IS_E1X */ @@ -1339,4 +1368,11 @@ void bnx2x_squeeze_objects(struct bnx2x *bp); void bnx2x_schedule_sp_rtnl(struct bnx2x*, enum sp_rtnl_flag, u32 verbose); +/** + * bnx2x_set_os_driver_state - write driver state for management FW usage + * + * @bp: driver handle + * @state: OS_DRIVER_STATE_* value reflecting current driver state + */ +void bnx2x_set_os_driver_state(struct bnx2x *bp, u32 state); #endif /* BNX2X_CMN_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index fd3631b1a378..6b2050a198df 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1131,6 +1131,9 @@ static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } else bp->wol = 0; + if (SHMEM2_HAS(bp, curr_cfg)) + SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS); + return 0; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 5425de059aae..23960df7e595 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -868,6 +868,7 @@ struct shared_feat_cfg { /* NVRAM Offset */ #define SHARED_FEAT_CFG_FORCE_SF_MODE_SPIO4 0x00000200 #define SHARED_FEAT_CFG_FORCE_SF_MODE_SWITCH_INDEPT 0x00000300 #define SHARED_FEAT_CFG_FORCE_SF_MODE_AFEX_MODE 0x00000400 + #define SHARED_FEAT_CFG_FORCE_SF_MODE_BD_MODE 0x00000500 #define SHARED_FEAT_CFG_FORCE_SF_MODE_UFP_MODE 0x00000600 #define SHARED_FEAT_CFG_FORCE_SF_MODE_EXTENDED_MODE 0x00000700 @@ -2068,6 +2069,12 @@ struct ncsi_oem_fcoe_features { #define FCOE_FEATURES4_FEATURE_SETTINGS_OFFSET 0 }; +enum curr_cfg_method_e { + CURR_CFG_MET_NONE = 0, /* default config */ + CURR_CFG_MET_OS = 1, + CURR_CFG_MET_VENDOR_SPEC = 2,/* e.g. Option ROM, NPAR, O/S Cfg Utils */ +}; + struct ncsi_oem_data { u32 driver_version[4]; struct ncsi_oem_fcoe_features ncsi_oem_fcoe_features; @@ -2191,6 +2198,8 @@ struct shmem2_region { #define DRV_FLAGS_CAPABILITIES_LOADED_L2 0x00000002 #define DRV_FLAGS_CAPABILITIES_LOADED_FCOE 0x00000004 #define DRV_FLAGS_CAPABILITIES_LOADED_ISCSI 0x00000008 +#define DRV_FLAGS_MTU_MASK 0xffff0000 +#define DRV_FLAGS_MTU_SHIFT 16 u32 extended_dev_info_shared_cfg_size; @@ -2273,6 +2282,71 @@ struct shmem2_region { /* We use indication for each PF (0..3) */ #define MFW_DRV_IND_READ_DONE_OFFSET(_pf_) (1 << (_pf_)) + union { /* For various OEMs */ /* Offset 0x1a0 */ + u8 storage_boot_prog[E2_FUNC_MAX]; + #define STORAGE_BOOT_PROG_MASK 0x000000FF + #define STORAGE_BOOT_PROG_NONE 0x00000000 + #define STORAGE_BOOT_PROG_ISCSI_IP_ACQUIRED 0x00000002 + #define STORAGE_BOOT_PROG_FCOE_FABRIC_LOGIN_SUCCESS 0x00000002 + #define STORAGE_BOOT_PROG_TARGET_FOUND 0x00000004 + #define STORAGE_BOOT_PROG_ISCSI_CHAP_SUCCESS 0x00000008 + #define STORAGE_BOOT_PROG_FCOE_LUN_FOUND 0x00000008 + #define STORAGE_BOOT_PROG_LOGGED_INTO_TGT 0x00000010 + #define STORAGE_BOOT_PROG_IMG_DOWNLOADED 0x00000020 + #define STORAGE_BOOT_PROG_OS_HANDOFF 0x00000040 + #define STORAGE_BOOT_PROG_COMPLETED 0x00000080 + + u32 oem_i2c_data_addr; + }; + + /* 9 entires for the C2S PCP map for each inner VLAN PCP + 1 default */ + /* For PCP values 0-3 use the map lower */ + /* 0xFF000000 - PCP 0, 0x00FF0000 - PCP 1, + * 0x0000FF00 - PCP 2, 0x000000FF PCP 3 + */ + u32 c2s_pcp_map_lower[E2_FUNC_MAX]; /* 0x1a4 */ + + /* For PCP values 4-7 use the map upper */ + /* 0xFF000000 - PCP 4, 0x00FF0000 - PCP 5, + * 0x0000FF00 - PCP 6, 0x000000FF PCP 7 + */ + u32 c2s_pcp_map_upper[E2_FUNC_MAX]; /* 0x1b4 */ + + /* For PCP default value get the MSB byte of the map default */ + u32 c2s_pcp_map_default[E2_FUNC_MAX]; /* 0x1c4 */ + + /* FC_NPIV table offset in NVRAM */ + u32 fc_npiv_nvram_tbl_addr[PORT_MAX]; /* 0x1d4 */ + + /* Shows last method that changed configuration of this device */ + enum curr_cfg_method_e curr_cfg; /* 0x1dc */ + + /* Storm FW version, shold be kept in the format 0xMMmmbbdd: + * MM - Major, mm - Minor, bb - Build ,dd - Drop + */ + u32 netproc_fw_ver; /* 0x1e0 */ + + /* Option ROM SMASH CLP version */ + u32 clp_ver; /* 0x1e4 */ + + u32 pcie_bus_num; /* 0x1e8 */ + + u32 sriov_switch_mode; /* 0x1ec */ + #define SRIOV_SWITCH_MODE_NONE 0x0 + #define SRIOV_SWITCH_MODE_VEB 0x1 + #define SRIOV_SWITCH_MODE_VEPA 0x2 + + u8 rsrv2[E2_FUNC_MAX]; /* 0x1f0 */ + + u32 img_inv_table_addr; /* Address to INV_TABLE_P */ /* 0x1f4 */ + + u32 mtu_size[E2_FUNC_MAX]; /* 0x1f8 */ + + u32 os_driver_state[E2_FUNC_MAX]; /* 0x208 */ + #define OS_DRIVER_STATE_NOT_LOADED 0 /* not installed */ + #define OS_DRIVER_STATE_LOADING 1 /* transition state */ + #define OS_DRIVER_STATE_DISABLED 2 /* installed but disabled */ + #define OS_DRIVER_STATE_ACTIVE 3 /* installed and active */ }; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index e85e6ffa4e61..0a069fa8e1fb 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -2918,7 +2918,7 @@ static void bnx2x_handle_update_svid_cmd(struct bnx2x *bp) func_params.f_obj = &bp->func_obj; func_params.cmd = BNX2X_F_CMD_SWITCH_UPDATE; - if (IS_MF_UFP(bp)) { + if (IS_MF_UFP(bp) || IS_MF_BD(bp)) { int func = BP_ABS_FUNC(bp); u32 val; @@ -2945,16 +2945,16 @@ static void bnx2x_handle_update_svid_cmd(struct bnx2x *bp) BNX2X_ERR("Failed to configure FW of S-tag Change to %02x\n", bp->mf_ov); goto fail; + } else { + DP(BNX2X_MSG_MCP, "Configured S-tag %02x\n", + bp->mf_ov); } - - DP(BNX2X_MSG_MCP, "Configured S-tag %02x\n", bp->mf_ov); - - bnx2x_fw_command(bp, DRV_MSG_CODE_OEM_UPDATE_SVID_OK, 0); - - return; + } else { + goto fail; } - /* not supported by SW yet */ + bnx2x_fw_command(bp, DRV_MSG_CODE_OEM_UPDATE_SVID_OK, 0); + return; fail: bnx2x_fw_command(bp, DRV_MSG_CODE_OEM_UPDATE_SVID_FAILURE, 0); } @@ -7433,6 +7433,9 @@ static int bnx2x_init_hw_common(struct bnx2x *bp) } else BNX2X_ERR("Bootcode is missing - can not initialize link\n"); + if (SHMEM2_HAS(bp, netproc_fw_ver)) + SHMEM2_WR(bp, netproc_fw_ver, REG_RD(bp, XSEM_REG_PRAM)); + return 0; } @@ -11682,7 +11685,7 @@ static void validate_set_si_mode(struct bnx2x *bp) static int bnx2x_get_hwinfo(struct bnx2x *bp) { int /*abs*/func = BP_ABS_FUNC(bp); - int vn; + int vn, mfw_vn; u32 val = 0, val2 = 0; int rc = 0; @@ -11772,6 +11775,7 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp) bp->mf_mode = 0; bp->mf_sub_mode = 0; vn = BP_VN(bp); + mfw_vn = BP_FW_MB_IDX(bp); if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) { BNX2X_DEV_INFO("shmem2base 0x%x, size %d, mfcfg offset %d\n", @@ -11828,6 +11832,31 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp) } else BNX2X_DEV_INFO("illegal OV for SD\n"); break; + case SHARED_FEAT_CFG_FORCE_SF_MODE_BD_MODE: + bp->mf_mode = MULTI_FUNCTION_SD; + bp->mf_sub_mode = SUB_MF_MODE_BD; + bp->mf_config[vn] = + MF_CFG_RD(bp, + func_mf_config[func].config); + + if (SHMEM2_HAS(bp, mtu_size)) { + int mtu_idx = BP_FW_MB_IDX(bp); + u16 mtu_size; + u32 mtu; + + mtu = SHMEM2_RD(bp, mtu_size[mtu_idx]); + mtu_size = (u16)mtu; + DP(NETIF_MSG_IFUP, "Read MTU size %04x [%08x]\n", + mtu_size, mtu); + + /* if valid: update device mtu */ + if (((mtu_size + ETH_HLEN) >= + ETH_MIN_PACKET_SIZE) && + (mtu_size <= + ETH_MAX_JUMBO_PACKET_SIZE)) + bp->dev->mtu = mtu_size; + } + break; case SHARED_FEAT_CFG_FORCE_SF_MODE_UFP_MODE: bp->mf_mode = MULTI_FUNCTION_SD; bp->mf_sub_mode = SUB_MF_MODE_UFP; @@ -11875,9 +11904,10 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp) BNX2X_DEV_INFO("MF OV for func %d is %d (0x%04x)\n", func, bp->mf_ov, bp->mf_ov); - } else if (bp->mf_sub_mode == SUB_MF_MODE_UFP) { + } else if ((bp->mf_sub_mode == SUB_MF_MODE_UFP) || + (bp->mf_sub_mode == SUB_MF_MODE_BD)) { dev_err(&bp->pdev->dev, - "Unexpected - no valid MF OV for func %d in UFP mode\n", + "Unexpected - no valid MF OV for func %d in UFP/BD mode\n", func); bp->path_has_ovlan = true; } else { @@ -13565,6 +13595,9 @@ static int bnx2x_init_one(struct pci_dev *pdev, bnx2x_register_phc(bp); + if (!IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp)) + bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_DISABLED); + return 0; init_one_exit: @@ -13627,6 +13660,7 @@ static void __bnx2x_remove(struct pci_dev *pdev, /* Power on: we can't let PCI layer write to us while we are in D3 */ if (IS_PF(bp)) { bnx2x_set_power_state(bp, PCI_D0); + bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_NOT_LOADED); /* Set endianity registers to reset values in case next driver * boots in different endianty environment. diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index f18bf511d854..4dead49bd5cb 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -2139,6 +2139,10 @@ /* [RW 1] When this bit is set; the LLH will expect all packets to be with e1hov */ #define NIG_REG_LLH_E1HOV_MODE 0x160d8 +/* [RW 16] Outer VLAN type identifier for multi-function mode. In non + * multi-function mode; it will hold the inner VLAN type. Typically 0x8100. + */ +#define NIG_REG_LLH_E1HOV_TYPE_1 0x16028 /* [RW 1] When this bit is set; the LLH will classify the packet before sending it to the BRB or calculating WoL on it. */ #define NIG_REG_LLH_MF_MODE 0x16024 @@ -2955,7 +2959,12 @@ #define PBF_REG_TQ_OCCUPANCY_Q0 0x1403ac /* [R 13] Number of 8 bytes lines occupied in the task queue of queue 1. */ #define PBF_REG_TQ_OCCUPANCY_Q1 0x1403b0 -#define PB_REG_CONTROL 0 +/* [RW 16] One of 8 values that should be compared to type in Ethernet + * parsing. If there is a match; the field after Ethernet is the first VLAN. + * Reset value is 0x8100 which is the standard VLAN type. Note that when + * checking second VLAN; type is compared only to 0x8100. + */ +#define PBF_REG_VLAN_TYPE_0 0x15c06c /* [RW 2] Interrupt mask register #0 read/write */ #define PB_REG_PB_INT_MASK 0x28 /* [R 2] Interrupt register #0 read */ @@ -3374,6 +3383,12 @@ #define PRS_REG_TCM_CURRENT_CREDIT 0x40160 /* [R 8] debug only: TSDM current credit. Transaction based. */ #define PRS_REG_TSDM_CURRENT_CREDIT 0x4015c +/* [RW 16] One of 8 values that should be compared to type in Ethernet + * parsing. If there is a match; the field after Ethernet is the first VLAN. + * Reset value is 0x8100 which is the standard VLAN type. Note that when + * checking second VLAN; type is compared only to 0x8100. + */ +#define PRS_REG_VLAN_TYPE_0 0x401a8 #define PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_AFT (0x1<<19) #define PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_OF (0x1<<20) #define PXP2_PXP2_INT_MASK_0_REG_PGL_PCIE_ATTN (0x1<<22) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 4d5c7b3d3a32..5b243bcec3fa 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -1340,6 +1340,9 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param, mutex_init(&bp->vfdb->bulletin_mutex); + if (SHMEM2_HAS(bp, sriov_switch_mode)) + SHMEM2_WR(bp, sriov_switch_mode, SRIOV_SWITCH_MODE_VEB); + return 0; failed: DP(BNX2X_MSG_IOV, "Failed err=%d\n", err); -- cgit v1.3-6-gb490 From c48f350ff5e75abae2627c2531780264f9e49130 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 22 Jul 2015 09:16:26 +0300 Subject: bnx2x: Add MFW dump support Devices with up-to-date management FW will be able to store register dumps on their persistent storage - in case management FW identifies a fatal error it would gather and store such dumps, which could later be retrieved using specific debug tools. This patch adds the necessary part in the driver in order to make the feature operational, as well as update users [under debug] during load in case their device contains a dump of a previous crash. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 2 ++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 4 ++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 17 ++++++++++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 28 ++++++++++++++++++++++++ 4 files changed, 51 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index ecf1d7f6ab27..2fe3563d2528 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -2582,6 +2582,8 @@ void bnx2x_set_local_cmng(struct bnx2x *bp); void bnx2x_update_mng_version(struct bnx2x *bp); +void bnx2x_update_mfw_dump(struct bnx2x *bp); + #define MCPR_SCRATCH_BASE(bp) \ (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index b1d16d34551d..6088c86c4872 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2908,6 +2908,10 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) return -EBUSY; } + /* Update driver data for On-Chip MFW dump. */ + if (IS_PF(bp)) + bnx2x_update_mfw_dump(bp); + /* If PMF - send ADMIN DCBX msg to MFW to initiate DCBX FSM */ if (bp->port.pmf && (bp->state != BNX2X_STATE_DIAG)) bnx2x_dcbx_init(bp, false); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 23960df7e595..08a08fa49caa 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -2075,6 +2075,20 @@ enum curr_cfg_method_e { CURR_CFG_MET_VENDOR_SPEC = 2,/* e.g. Option ROM, NPAR, O/S Cfg Utils */ }; +struct mdump_driver_info { + u32 epoc; + u32 drv_ver; + u32 fw_ver; + + u32 valid_dump; + #define FIRST_DUMP_VALID (1 << 0) + #define SECOND_DUMP_VALID (1 << 1) + + u32 flags; + #define ENABLE_ALL_TRIGGERS (0x7fffffff) + #define TRIGGER_MDUMP_ONCE (1 << 31) +}; + struct ncsi_oem_data { u32 driver_version[4]; struct ncsi_oem_fcoe_features ncsi_oem_fcoe_features; @@ -2347,6 +2361,9 @@ struct shmem2_region { #define OS_DRIVER_STATE_LOADING 1 /* transition state */ #define OS_DRIVER_STATE_DISABLED 2 /* installed but disabled */ #define OS_DRIVER_STATE_ACTIVE 3 /* installed and active */ + + /* mini dump driver info */ + struct mdump_driver_info drv_info; /* 0x218 */ }; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 0a069fa8e1fb..78e55fe616e3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -3709,6 +3709,34 @@ out: ethver, iscsiver, fcoever); } +void bnx2x_update_mfw_dump(struct bnx2x *bp) +{ + struct timeval epoc; + u32 drv_ver; + u32 valid_dump; + + if (!SHMEM2_HAS(bp, drv_info)) + return; + + /* Update Driver load time */ + do_gettimeofday(&epoc); + SHMEM2_WR(bp, drv_info.epoc, epoc.tv_sec); + + drv_ver = bnx2x_update_mng_version_utility(DRV_MODULE_VERSION, true); + SHMEM2_WR(bp, drv_info.drv_ver, drv_ver); + + SHMEM2_WR(bp, drv_info.fw_ver, REG_RD(bp, XSEM_REG_PRAM)); + + /* Check & notify On-Chip dump. */ + valid_dump = SHMEM2_RD(bp, drv_info.valid_dump); + + if (valid_dump & FIRST_DUMP_VALID) + DP(NETIF_MSG_IFUP, "A valid On-Chip MFW dump found on 1st partition\n"); + + if (valid_dump & SECOND_DUMP_VALID) + DP(NETIF_MSG_IFUP, "A valid On-Chip MFW dump found on 2nd partition\n"); +} + static void bnx2x_oem_event(struct bnx2x *bp, u32 event) { u32 cmd_ok, cmd_fail; -- cgit v1.3-6-gb490 From 3a375e3caf2b424386f9e32d0c55f8907c52981d Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 22 Jul 2015 09:16:27 +0300 Subject: bnx2x: Bump up driver version to 1.712.30 Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 2fe3563d2528..a1f9785f0209 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -32,7 +32,7 @@ * (you will need to reboot afterwards) */ /* #define BNX2X_STOP_ON_ERROR */ -#define DRV_MODULE_VERSION "1.710.51-0" +#define DRV_MODULE_VERSION "1.712.30-0" #define DRV_MODULE_RELDATE "2014/02/10" #define BNX2X_BC_VER 0x040200 -- cgit v1.3-6-gb490 From fb02eb4a29303295f2fed8a69d9aa703792c834b Mon Sep 17 00:00:00 2001 From: hayeswang Date: Wed, 22 Jul 2015 15:27:41 +0800 Subject: r8152: support the new RTL8153 chip Support the new USB gigabit ethernet. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 7f6419ebb5e1..57b72ecb5455 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -622,6 +622,7 @@ enum rtl_version { RTL_VER_03, RTL_VER_04, RTL_VER_05, + RTL_VER_06, RTL_VER_MAX }; @@ -2560,7 +2561,10 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) u32 ocp_data; u16 data; - ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); + if (tp->version == RTL_VER_03 || tp->version == RTL_VER_04 || + tp->version == RTL_VER_05) + ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); + data = r8152_mdio_read(tp, MII_BMCR); if (data & BMCR_PDOWN) { data &= ~BMCR_PDOWN; @@ -3268,6 +3272,13 @@ static void r8153_init(struct r8152 *tp) ocp_data &= ~ECM_ALDPS; ocp_write_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0, ocp_data); + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1); + if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0) + ocp_data &= ~DYNAMIC_BURST; + else + ocp_data |= DYNAMIC_BURST; + ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data); + } else if (tp->version == RTL_VER_06) { ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1); if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0) ocp_data &= ~DYNAMIC_BURST; @@ -3908,6 +3919,10 @@ static void r8152b_get_version(struct r8152 *tp) tp->version = RTL_VER_05; tp->mii.supports_gmii = 1; break; + case 0x5c30: + tp->version = RTL_VER_06; + tp->mii.supports_gmii = 1; + break; default: netif_info(tp, probe, tp->netdev, "Unknown version 0x%04x\n", version); @@ -3953,6 +3968,7 @@ static int rtl_ops_init(struct r8152 *tp) case RTL_VER_03: case RTL_VER_04: case RTL_VER_05: + case RTL_VER_06: ops->init = r8153_init; ops->enable = rtl8153_enable; ops->disable = rtl8153_disable; -- cgit v1.3-6-gb490 From 8d9bfe3702aaea457b3d59b09b86e9f03c322605 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Tue, 21 Jul 2015 18:29:40 -0700 Subject: PCI: iproc: Add arm64 support Add arm64 support to the iProc PCIe driver. Note that on arm32, bus->sysdata points to the arm32-specific pci_sys_data struct, and pci_sys_data.private_data contains the iproc_pcie pointer. For arm64, there's nothing corresponding to pci_sys_data, so we keep the iproc_pcie pointer directly in bus->sysdata. In addition, arm64 does IRQ mapping in pcibios_add_device(), so it doesn't need pci_fixup_irqs() as arm32 does. Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas Reviewed-by: Scott Branden --- drivers/pci/host/pcie-iproc.c | 26 ++++++++++++++++++++------ drivers/pci/host/pcie-iproc.h | 4 +++- 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index 9a00dca5e453..fe2efb141a9b 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -58,9 +58,17 @@ #define SYS_RC_INTX_EN 0x330 #define SYS_RC_INTX_MASK 0xf -static inline struct iproc_pcie *sys_to_pcie(struct pci_sys_data *sys) +static inline struct iproc_pcie *iproc_data(struct pci_bus *bus) { - return sys->private_data; + struct iproc_pcie *pcie; +#ifdef CONFIG_ARM + struct pci_sys_data *sys = bus->sysdata; + + pcie = sys->private_data; +#else + pcie = bus->sysdata; +#endif + return pcie; } /** @@ -71,8 +79,7 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct pci_bus *bus, unsigned int devfn, int where) { - struct pci_sys_data *sys = bus->sysdata; - struct iproc_pcie *pcie = sys_to_pcie(sys); + struct iproc_pcie *pcie = iproc_data(bus); unsigned slot = PCI_SLOT(devfn); unsigned fn = PCI_FUNC(devfn); unsigned busno = bus->number; @@ -186,6 +193,7 @@ static void iproc_pcie_enable(struct iproc_pcie *pcie) int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) { int ret; + void *sysdata; struct pci_bus *bus; if (!pcie || !pcie->dev || !pcie->base) @@ -205,10 +213,14 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) iproc_pcie_reset(pcie); +#ifdef CONFIG_ARM pcie->sysdata.private_data = pcie; + sysdata = &pcie->sysdata; +#else + sysdata = pcie; +#endif - bus = pci_create_root_bus(pcie->dev, 0, &iproc_pcie_ops, - &pcie->sysdata, res); + bus = pci_create_root_bus(pcie->dev, 0, &iproc_pcie_ops, sysdata, res); if (!bus) { dev_err(pcie->dev, "unable to create PCI root bus\n"); ret = -ENOMEM; @@ -226,7 +238,9 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) pci_scan_child_bus(bus); pci_assign_unassigned_bus_resources(bus); +#ifdef CONFIG_ARM pci_fixup_irqs(pci_common_swizzle, pcie->map_irq); +#endif pci_bus_add_devices(bus); return 0; diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index ba0a108309cc..c9e4c10a462e 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h @@ -21,7 +21,7 @@ * @dev: pointer to device data structure * @base: PCIe host controller I/O register base * @resources: linked list of all PCI resources - * @sysdata: Per PCI controller data + * @sysdata: Per PCI controller data (ARM-specific) * @root_bus: pointer to root bus * @phy: optional PHY device that controls the Serdes * @irqs: interrupt IDs @@ -29,7 +29,9 @@ struct iproc_pcie { struct device *dev; void __iomem *base; +#ifdef CONFIG_ARM struct pci_sys_data sysdata; +#endif struct pci_bus *root_bus; struct phy *phy; int irqs[IPROC_PCIE_MAX_NUM_IRQS]; -- cgit v1.3-6-gb490 From b2f8dc4ce6626e25b164e29cf72b70230a1f1711 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 22 Jul 2015 22:11:16 +0200 Subject: ACPI / processor: Drop an unused argument of a cleanup routine acpi_processor_unregister_performance() actually doesn't use its first argument, so drop it and update the callers accordingly. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/acpi/processor_perflib.c | 4 +--- drivers/cpufreq/acpi-cpufreq.c | 5 ++--- drivers/cpufreq/e_powersaver.c | 2 +- drivers/cpufreq/ia64-acpi-cpufreq.c | 5 ++--- drivers/cpufreq/powernow-k7.c | 4 ++-- drivers/cpufreq/powernow-k8.c | 5 ++--- drivers/xen/xen-acpi-processor.c | 16 ++++++---------- include/acpi/processor.h | 5 +---- 8 files changed, 17 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index cfc8aba72f86..36b6da2918a6 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -784,9 +784,7 @@ acpi_processor_register_performance(struct acpi_processor_performance EXPORT_SYMBOL(acpi_processor_register_performance); -void -acpi_processor_unregister_performance(struct acpi_processor_performance - *performance, unsigned int cpu) +void acpi_processor_unregister_performance(unsigned int cpu) { struct acpi_processor *pr; diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index de54ce14eb39..ca9d0f6edf08 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -844,7 +844,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) err_freqfree: kfree(data->freq_table); err_unreg: - acpi_processor_unregister_performance(perf, cpu); + acpi_processor_unregister_performance(cpu); err_free_mask: free_cpumask_var(data->freqdomain_cpus); err_free: @@ -862,8 +862,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) if (data) { policy->driver_data = NULL; - acpi_processor_unregister_performance(data->acpi_data, - data->acpi_perf_cpu); + acpi_processor_unregister_performance(data->acpi_perf_cpu); free_cpumask_var(data->freqdomain_cpus); kfree(data->freq_table); kfree(data); diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c index a0d2a423cea9..4085244c8a67 100644 --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c @@ -78,7 +78,7 @@ static int eps_acpi_init(void) static int eps_acpi_exit(struct cpufreq_policy *policy) { if (eps_acpi_cpu_perf) { - acpi_processor_unregister_performance(eps_acpi_cpu_perf, 0); + acpi_processor_unregister_performance(0); free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map); kfree(eps_acpi_cpu_perf); eps_acpi_cpu_perf = NULL; diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index c30aaa6a54e8..a9c193286ef4 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -313,7 +313,7 @@ acpi_cpufreq_cpu_init ( err_freqfree: kfree(data->freq_table); err_unreg: - acpi_processor_unregister_performance(&data->acpi_data, cpu); + acpi_processor_unregister_performance(cpu); err_free: kfree(data); acpi_io_data[cpu] = NULL; @@ -332,8 +332,7 @@ acpi_cpufreq_cpu_exit ( if (data) { acpi_io_data[policy->cpu] = NULL; - acpi_processor_unregister_performance(&data->acpi_data, - policy->cpu); + acpi_processor_unregister_performance(policy->cpu); kfree(data); } diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c index 37c5742482d8..c1ae1999770a 100644 --- a/drivers/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -421,7 +421,7 @@ static int powernow_acpi_init(void) return 0; err2: - acpi_processor_unregister_performance(acpi_processor_perf, 0); + acpi_processor_unregister_performance(0); err1: free_cpumask_var(acpi_processor_perf->shared_cpu_map); err05: @@ -661,7 +661,7 @@ static int powernow_cpu_exit(struct cpufreq_policy *policy) { #ifdef CONFIG_X86_POWERNOW_K7_ACPI if (acpi_processor_perf) { - acpi_processor_unregister_performance(acpi_processor_perf, 0); + acpi_processor_unregister_performance(0); free_cpumask_var(acpi_processor_perf->shared_cpu_map); kfree(acpi_processor_perf); } diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 5c035d04d827..0b5bf135b090 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -795,7 +795,7 @@ err_out_mem: kfree(powernow_table); err_out: - acpi_processor_unregister_performance(&data->acpi_data, data->cpu); + acpi_processor_unregister_performance(data->cpu); /* data->acpi_data.state_count informs us at ->exit() * whether ACPI was used */ @@ -863,8 +863,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) { if (data->acpi_data.state_count) - acpi_processor_unregister_performance(&data->acpi_data, - data->cpu); + acpi_processor_unregister_performance(data->cpu); free_cpumask_var(data->acpi_data.shared_cpu_map); } diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index 59fc190f1e92..70fa438000af 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -560,11 +560,9 @@ static int __init xen_acpi_processor_init(void) return 0; err_unregister: - for_each_possible_cpu(i) { - struct acpi_processor_performance *perf; - perf = per_cpu_ptr(acpi_perf_data, i); - acpi_processor_unregister_performance(perf, i); - } + for_each_possible_cpu(i) + acpi_processor_unregister_performance(i); + err_out: /* Freeing a NULL pointer is OK: alloc_percpu zeroes. */ free_acpi_perf_data(); @@ -579,11 +577,9 @@ static void __exit xen_acpi_processor_exit(void) kfree(acpi_ids_done); kfree(acpi_id_present); kfree(acpi_id_cst_present); - for_each_possible_cpu(i) { - struct acpi_processor_performance *perf; - perf = per_cpu_ptr(acpi_perf_data, i); - acpi_processor_unregister_performance(perf, i); - } + for_each_possible_cpu(i) + acpi_processor_unregister_performance(i); + free_acpi_perf_data(); } diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 4188a4d3b597..aad1f2a3cd2b 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -228,10 +228,7 @@ extern int acpi_processor_preregister_performance(struct extern int acpi_processor_register_performance(struct acpi_processor_performance *performance, unsigned int cpu); -extern void acpi_processor_unregister_performance(struct - acpi_processor_performance - *performance, - unsigned int cpu); +extern void acpi_processor_unregister_performance(unsigned int cpu); /* note: this locks both the calling module and the processor module if a _PPC object exists, rmmod is disallowed then */ -- cgit v1.3-6-gb490 From 3427616b2a5aa7f34716278aa6a140378a00a36e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 22 Jul 2015 22:11:56 +0200 Subject: cpufreq: acpi-cpufreq: Drop acpi_data from struct acpi_cpufreq_data After commit 8cfcfd39000d (acpi-cpufreq: Fix an ACPI perf unregister issue) we store both a pointer to per-CPU data of the first policy CPU and the number of that CPU which are redundant. Since the CPU number has to be stored anyway for the unregistration, the pointer to the CPU's per-CPU data may be dropped and we can access the data in question via per_cpu_ptr(). Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/acpi-cpufreq.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index ca9d0f6edf08..af2bb8883d96 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -65,7 +65,6 @@ enum { #define MSR_K7_HWCR_CPB_DIS (1ULL << 25) struct acpi_cpufreq_data { - struct acpi_processor_performance *acpi_data; struct cpufreq_frequency_table *freq_table; unsigned int resume; unsigned int cpu_feature; @@ -76,6 +75,11 @@ struct acpi_cpufreq_data { /* acpi_perf_data is a pointer to percpu data. */ static struct acpi_processor_performance __percpu *acpi_perf_data; +static inline struct acpi_processor_performance *to_perf_data(struct acpi_cpufreq_data *data) +{ + return per_cpu_ptr(acpi_perf_data, data->acpi_perf_cpu); +} + static struct cpufreq_driver acpi_cpufreq_driver; static unsigned int acpi_pstate_strict; @@ -201,7 +205,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data) struct acpi_processor_performance *perf; int i; - perf = data->acpi_data; + perf = to_perf_data(data); for (i = 0; i < perf->state_count; i++) { if (value == perf->states[i].status) @@ -220,7 +224,7 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) else msr &= INTEL_MSR_RANGE; - perf = data->acpi_data; + perf = to_perf_data(data); cpufreq_for_each_entry(pos, data->freq_table) if (msr == perf->states[pos->driver_data].status) @@ -346,7 +350,7 @@ get_cur_val(const struct cpumask *mask, struct acpi_cpufreq_data *data) break; case SYSTEM_IO_CAPABLE: cmd.type = SYSTEM_IO_CAPABLE; - perf = data->acpi_data; + perf = to_perf_data(data); cmd.addr.io.port = perf->control_register.address; cmd.addr.io.bit_width = perf->control_register.bit_width; break; @@ -377,10 +381,10 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) data = policy->driver_data; cpufreq_cpu_put(policy); - if (unlikely(!data || !data->acpi_data || !data->freq_table)) + if (unlikely(!data || !data->freq_table)) return 0; - cached_freq = data->freq_table[data->acpi_data->state].frequency; + cached_freq = data->freq_table[to_perf_data(data)->state].frequency; freq = extract_freq(get_cur_val(cpumask_of(cpu), data), data); if (freq != cached_freq) { /* @@ -419,12 +423,11 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, unsigned int next_perf_state = 0; /* Index into perf table */ int result = 0; - if (unlikely(data == NULL || - data->acpi_data == NULL || data->freq_table == NULL)) { + if (unlikely(data == NULL || data->freq_table == NULL)) { return -ENODEV; } - perf = data->acpi_data; + perf = to_perf_data(data); next_perf_state = data->freq_table[index].driver_data; if (perf->state == next_perf_state) { if (unlikely(data->resume)) { @@ -487,8 +490,9 @@ out: static unsigned long acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu) { - struct acpi_processor_performance *perf = data->acpi_data; + struct acpi_processor_performance *perf; + perf = to_perf_data(data); if (cpu_khz) { /* search the closest match to cpu_khz */ unsigned int i; @@ -677,18 +681,17 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) goto err_free; } - data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu); + perf = per_cpu_ptr(acpi_perf_data, cpu); data->acpi_perf_cpu = cpu; policy->driver_data = data; if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; - result = acpi_processor_register_performance(data->acpi_data, cpu); + result = acpi_processor_register_performance(perf, cpu); if (result) goto err_free_mask; - perf = data->acpi_data; policy->shared_type = perf->shared_type; /* -- cgit v1.3-6-gb490 From f56c50e322eed07526a08edefa29fc8bab1e93df Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 22 Jul 2015 22:12:10 +0200 Subject: cpufreq: acpi-cpufreq: Fix up the handling of cpb sysfs attribute The cpb sysfs attribute is only exposed by the ACPI cpufreq driver after a runtime check. For this purpose, the driver keeps a NULL placeholder in its table of sysfs attributes and replaces the NULL with a pointer to an attribute structure if it decides to expose cpb. That is confusing, so make the driver set the pointer to the cpb attribute structure upfront and replace it with NULL if the attribute should not be exposed instead. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/acpi-cpufreq.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index af2bb8883d96..15b921a9248c 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -888,7 +888,9 @@ static int acpi_cpufreq_resume(struct cpufreq_policy *policy) static struct freq_attr *acpi_cpufreq_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, &freqdomain_cpus, - NULL, /* this is a placeholder for cpb, do not remove */ +#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB + &cpb, +#endif NULL, }; @@ -961,17 +963,16 @@ static int __init acpi_cpufreq_init(void) * only if configured. This is considered legacy code, which * will probably be removed at some point in the future. */ - if (check_amd_hwpstate_cpu(0)) { - struct freq_attr **iter; + if (!check_amd_hwpstate_cpu(0)) { + struct freq_attr **attr; - pr_debug("adding sysfs entry for cpb\n"); + pr_debug("CPB unsupported, do not expose it\n"); - for (iter = acpi_cpufreq_attr; *iter != NULL; iter++) - ; - - /* make sure there is a terminator behind it */ - if (iter[1] == NULL) - *iter = &cpb; + for (attr = acpi_cpufreq_attr; *attr; attr++) + if (*attr == &cpb) { + *attr = NULL; + break; + } } #endif acpi_cpufreq_boost_init(); -- cgit v1.3-6-gb490 From 946c14f812bfff18e6fd6357d06b6e8fa8793fec Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Mon, 20 Jul 2015 14:22:46 +0800 Subject: cpufreq: ia64: remove redundant freq_table of acpi_cpufreq_data freq_table is now stored as policy->freq_table, so drop the redundant freq_table from struct cpufreq_acpi_io. Signed-off-by: Pan Xinhui Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/ia64-acpi-cpufreq.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index a9c193286ef4..cab8ab675bbc 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -29,7 +29,6 @@ MODULE_LICENSE("GPL"); struct cpufreq_acpi_io { struct acpi_processor_performance acpi_data; - struct cpufreq_frequency_table *freq_table; unsigned int resume; }; @@ -221,6 +220,7 @@ acpi_cpufreq_cpu_init ( unsigned int cpu = policy->cpu; struct cpufreq_acpi_io *data; unsigned int result = 0; + struct cpufreq_frequency_table *freq_table; pr_debug("acpi_cpufreq_cpu_init\n"); @@ -254,10 +254,10 @@ acpi_cpufreq_cpu_init ( } /* alloc freq_table */ - data->freq_table = kzalloc(sizeof(*data->freq_table) * + freq_table = kzalloc(sizeof(*freq_table) * (data->acpi_data.state_count + 1), GFP_KERNEL); - if (!data->freq_table) { + if (!freq_table) { result = -ENOMEM; goto err_unreg; } @@ -276,14 +276,14 @@ acpi_cpufreq_cpu_init ( for (i = 0; i <= data->acpi_data.state_count; i++) { if (i < data->acpi_data.state_count) { - data->freq_table[i].frequency = + freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000; } else { - data->freq_table[i].frequency = CPUFREQ_TABLE_END; + freq_table[i].frequency = CPUFREQ_TABLE_END; } } - result = cpufreq_table_validate_and_show(policy, data->freq_table); + result = cpufreq_table_validate_and_show(policy, freq_table); if (result) { goto err_freqfree; } @@ -311,7 +311,7 @@ acpi_cpufreq_cpu_init ( return (result); err_freqfree: - kfree(data->freq_table); + kfree(freq_table); err_unreg: acpi_processor_unregister_performance(cpu); err_free: -- cgit v1.3-6-gb490 From 555f3fe957b5bd763d49719cc68c6435c9c8dcf1 Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Mon, 20 Jul 2015 14:24:36 +0800 Subject: cpufreq: ia64: Fix a memory leak in acpi_cpufreq_cpu_exit() freq_table should be alloced in ->init and freed in ->exit, but it it is not freed. Fix this memory leak in acpi_cpufreq_cpu_exit(). Signed-off-by: Pan Xinhui Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/ia64-acpi-cpufreq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index cab8ab675bbc..0202429f1c5b 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -333,6 +333,7 @@ acpi_cpufreq_cpu_exit ( if (data) { acpi_io_data[policy->cpu] = NULL; acpi_processor_unregister_performance(policy->cpu); + kfree(policy->freq_table); kfree(data); } -- cgit v1.3-6-gb490 From 79a02744bc5a2993d6c5b8dd1a790f7ea12f4e0b Mon Sep 17 00:00:00 2001 From: Kris Borer Date: Tue, 16 Jun 2015 13:24:53 -0400 Subject: usb: fix coding style issue Fixed coding style issue: newline after declaration Signed-off-by: Kris Borer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 818369afff63..6b5063e7943f 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -160,6 +160,7 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf, spin_lock(&usb_driver->dynids.lock); list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) { struct usb_device_id *id = &dynid->id; + if ((id->idVendor == idVendor) && (id->idProduct == idProduct)) { list_del(&dynid->node); -- cgit v1.3-6-gb490 From 298b992fdb7536f0f347935d253ce31479b1fb43 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Mon, 22 Jun 2015 15:50:22 +0200 Subject: usb: class: Use USB_CLASS_PRINTER instead of number 7 Kernel provides very nice defines for USB device class so it's a good idea to use them in suitable places. It is much easier to grep for such define instead of 7. Signed-off-by: Krzysztof Opasiak Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 66 ++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index f38e875a3fb1..433bbc34a8a4 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -57,6 +57,7 @@ #include #undef DEBUG #include +#include #include /* @@ -79,12 +80,20 @@ #define IOCNR_SOFT_RESET 7 /* Get device_id string: */ #define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) -/* The following ioctls were added for http://hpoj.sourceforge.net: */ -/* Get two-int array: - * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3), - * [1]=supported protocol mask (mask&(1<num_altsetting; i++) { ifd = &if_alt->altsetting[i]; - if (ifd->desc.bInterfaceClass != 7 || ifd->desc.bInterfaceSubClass != 1) + if (ifd->desc.bInterfaceClass != USB_CLASS_PRINTER || + ifd->desc.bInterfaceSubClass != 1) if (!(usblp->quirks & USBLP_QUIRK_BAD_CLASS)) continue; @@ -1262,8 +1278,10 @@ static int usblp_select_alts(struct usblp *usblp) if (!epwrite || (ifd->desc.bInterfaceProtocol > 1 && !epread)) continue; - /* Turn off reads for 7/1/1 (unidirectional) interfaces - * and buggy bidirectional printers. */ + /* + * Turn off reads for USB_CLASS_PRINTER/1/1 (unidirectional) + * interfaces and buggy bidirectional printers. + */ if (ifd->desc.bInterfaceProtocol == 1) { epread = NULL; } else if (usblp->quirks & USBLP_QUIRK_BIDIR) { @@ -1406,12 +1424,12 @@ static int usblp_resume(struct usb_interface *intf) } static const struct usb_device_id usblp_ids[] = { - { USB_DEVICE_INFO(7, 1, 1) }, - { USB_DEVICE_INFO(7, 1, 2) }, - { USB_DEVICE_INFO(7, 1, 3) }, - { USB_INTERFACE_INFO(7, 1, 1) }, - { USB_INTERFACE_INFO(7, 1, 2) }, - { USB_INTERFACE_INFO(7, 1, 3) }, + { USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 1) }, + { USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 2) }, + { USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 3) }, + { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 1) }, + { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 2) }, + { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 3) }, { USB_DEVICE(0x04b8, 0x0202) }, /* Seiko Epson Receipt Printer M129C */ { } /* Terminating entry */ }; -- cgit v1.3-6-gb490 From cd32fbad6e3dfb26ae12babe07771f92b417af6b Mon Sep 17 00:00:00 2001 From: Aaron Raimist Date: Mon, 22 Jun 2015 21:05:27 -0500 Subject: USB: atm: cxacru: fix blank line after declaration Fixed a coding style issue. Adds blank lines after declarations. Signed-off-by: Aaron Raimist Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/cxacru.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 813d4d3a51c6..1173f9cbc137 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -270,6 +270,7 @@ static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf) static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf) { static char *str[] = { "no", "yes" }; + if (unlikely(value >= ARRAY_SIZE(str))) return snprintf(buf, PAGE_SIZE, "%u\n", value); return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); @@ -278,6 +279,7 @@ static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf) static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf) { static char *str[] = { NULL, "not connected", "connected", "lost" }; + if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL)) return snprintf(buf, PAGE_SIZE, "%u\n", value); return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); @@ -702,6 +704,7 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ len = ret / 4; for (offb = 0; offb < len; ) { int l = le32_to_cpu(buf[offb++]); + if (l < 0 || l > stride || l > (len - offb) / 2) { if (printk_ratelimit()) usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n", @@ -732,6 +735,7 @@ cleanup: static int cxacru_card_status(struct cxacru_data *instance) { int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); + if (ret < 0) { /* firmware not loaded */ usb_dbg(instance->usbatm, "cxacru_adsl_start: CARD_GET_STATUS returned %d\n", ret); return ret; @@ -945,6 +949,7 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw, offb = offd = 0; do { int l = min_t(int, stride, size - offd); + buf[offb++] = fw; buf[offb++] = l; buf[offb++] = code1; @@ -1091,8 +1096,8 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, { const struct firmware *fw, *bp; struct cxacru_data *instance = usbatm_instance->driver_data; - int ret = cxacru_find_firmware(instance, "fw", &fw); + if (ret) { usb_warn(usbatm_instance, "firmware (cxacru-fw.bin) unavailable (system misconfigured?)\n"); return ret; -- cgit v1.3-6-gb490 From c2a298d96628803586f1ca2027b6387f4e4b5a31 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Tue, 30 Jun 2015 16:48:54 +0200 Subject: usb: host: xhci: remove typo in function documentation Fix "though" to "through" in documentation of xhci_alloc_streams(). Signed-off-by: Luis de Bethencourt Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7da0d6043d33..e66857f0a3bb 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3117,7 +3117,7 @@ static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci, } /* - * The USB device drivers use this function (though the HCD interface in USB + * The USB device drivers use this function (through the HCD interface in USB * core) to prepare a set of bulk endpoints to use streams. Streams are used to * coordinate mass storage command queueing across multiple endpoints (basically * a stream ID == a task ID). -- cgit v1.3-6-gb490 From f78f5b90c4ffa559e400c3919a02236101f29f3f Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 18 Jun 2015 15:50:02 -0700 Subject: rcu: Rename rcu_lockdep_assert() to RCU_LOCKDEP_WARN() This commit renames rcu_lockdep_assert() to RCU_LOCKDEP_WARN() for consistency with the WARN() series of macros. This also requires inverting the sense of the conditional, which this commit also does. Reported-by: Ingo Molnar Signed-off-by: Paul E. McKenney Reviewed-by: Ingo Molnar --- Documentation/RCU/whatisRCU.txt | 2 +- arch/x86/kernel/cpu/mcheck/mce.c | 6 ++-- arch/x86/kernel/traps.c | 2 +- drivers/base/power/opp.c | 4 +-- include/linux/fdtable.h | 4 +-- include/linux/rcupdate.h | 63 ++++++++++++++++++++++++++-------------- kernel/cgroup.c | 4 +-- kernel/pid.c | 5 ++-- kernel/rcu/srcu.c | 10 +++---- kernel/rcu/tiny.c | 8 ++--- kernel/rcu/tree.c | 28 +++++++++--------- kernel/rcu/tree_plugin.h | 8 ++--- kernel/rcu/update.c | 4 +-- kernel/sched/core.c | 8 ++--- kernel/workqueue.c | 20 ++++++------- security/device_cgroup.c | 6 ++-- 16 files changed, 101 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 5746b0c77f3e..adc2184009c5 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -883,7 +883,7 @@ All: lockdep-checked RCU-protected pointer access rcu_access_pointer rcu_dereference_raw - rcu_lockdep_assert + RCU_LOCKDEP_WARN rcu_sleep_check RCU_NONIDLE diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index df919ff103c3..3d6b5269fb2e 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -54,9 +54,9 @@ static DEFINE_MUTEX(mce_chrdev_read_mutex); #define rcu_dereference_check_mce(p) \ ({ \ - rcu_lockdep_assert(rcu_read_lock_sched_held() || \ - lockdep_is_held(&mce_chrdev_read_mutex), \ - "suspicious rcu_dereference_check_mce() usage"); \ + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \ + !lockdep_is_held(&mce_chrdev_read_mutex), \ + "suspicious rcu_dereference_check_mce() usage"); \ smp_load_acquire(&(p)); \ }) diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index f5791927aa64..c5a5231d1d11 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -136,7 +136,7 @@ enum ctx_state ist_enter(struct pt_regs *regs) preempt_count_add(HARDIRQ_OFFSET); /* This code is a bit fragile. Test it. */ - rcu_lockdep_assert(rcu_is_watching(), "ist_enter didn't work"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), "ist_enter didn't work"); return prev_state; } diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 677fb2843553..3b188f20b43f 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -110,8 +110,8 @@ static DEFINE_MUTEX(dev_opp_list_lock); #define opp_rcu_lockdep_assert() \ do { \ - rcu_lockdep_assert(rcu_read_lock_held() || \ - lockdep_is_held(&dev_opp_list_lock), \ + RCU_LOCKDEP_WARN(!rcu_read_lock_held() && \ + !lockdep_is_held(&dev_opp_list_lock), \ "Missing rcu_read_lock() or " \ "dev_opp_list_lock protection"); \ } while (0) diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index fbb88740634a..674e3e226465 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h @@ -86,8 +86,8 @@ static inline struct file *__fcheck_files(struct files_struct *files, unsigned i static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd) { - rcu_lockdep_assert(rcu_read_lock_held() || - lockdep_is_held(&files->file_lock), + RCU_LOCKDEP_WARN(!rcu_read_lock_held() && + !lockdep_is_held(&files->file_lock), "suspicious rcu_dereference_check() usage"); return __fcheck_files(files, fd); } diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 33ec16b9c2ee..ff476515f716 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -536,6 +536,11 @@ static inline int rcu_read_lock_sched_held(void) #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ +/* Deprecate rcu_lockdep_assert(): Use RCU_LOCKDEP_WARN() instead. */ +static inline void __attribute((deprecated)) deprecate_rcu_lockdep_assert(void) +{ +} + #ifdef CONFIG_PROVE_RCU /** @@ -546,17 +551,32 @@ static inline int rcu_read_lock_sched_held(void) #define rcu_lockdep_assert(c, s) \ do { \ static bool __section(.data.unlikely) __warned; \ + deprecate_rcu_lockdep_assert(); \ if (debug_lockdep_rcu_enabled() && !__warned && !(c)) { \ __warned = true; \ lockdep_rcu_suspicious(__FILE__, __LINE__, s); \ } \ } while (0) +/** + * RCU_LOCKDEP_WARN - emit lockdep splat if specified condition is met + * @c: condition to check + * @s: informative message + */ +#define RCU_LOCKDEP_WARN(c, s) \ + do { \ + static bool __section(.data.unlikely) __warned; \ + if (debug_lockdep_rcu_enabled() && !__warned && (c)) { \ + __warned = true; \ + lockdep_rcu_suspicious(__FILE__, __LINE__, s); \ + } \ + } while (0) + #if defined(CONFIG_PROVE_RCU) && !defined(CONFIG_PREEMPT_RCU) static inline void rcu_preempt_sleep_check(void) { - rcu_lockdep_assert(!lock_is_held(&rcu_lock_map), - "Illegal context switch in RCU read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_lock_map), + "Illegal context switch in RCU read-side critical section"); } #else /* #ifdef CONFIG_PROVE_RCU */ static inline void rcu_preempt_sleep_check(void) @@ -567,15 +587,16 @@ static inline void rcu_preempt_sleep_check(void) #define rcu_sleep_check() \ do { \ rcu_preempt_sleep_check(); \ - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map), \ - "Illegal context switch in RCU-bh read-side critical section"); \ - rcu_lockdep_assert(!lock_is_held(&rcu_sched_lock_map), \ - "Illegal context switch in RCU-sched read-side critical section"); \ + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map), \ + "Illegal context switch in RCU-bh read-side critical section"); \ + RCU_LOCKDEP_WARN(lock_is_held(&rcu_sched_lock_map), \ + "Illegal context switch in RCU-sched read-side critical section"); \ } while (0) #else /* #ifdef CONFIG_PROVE_RCU */ -#define rcu_lockdep_assert(c, s) do { } while (0) +#define rcu_lockdep_assert(c, s) deprecate_rcu_lockdep_assert() +#define RCU_LOCKDEP_WARN(c, s) do { } while (0) #define rcu_sleep_check() do { } while (0) #endif /* #else #ifdef CONFIG_PROVE_RCU */ @@ -606,13 +627,13 @@ static inline void rcu_preempt_sleep_check(void) ({ \ /* Dependency order vs. p above. */ \ typeof(*p) *________p1 = (typeof(*p) *__force)lockless_dereference(p); \ - rcu_lockdep_assert(c, "suspicious rcu_dereference_check() usage"); \ + RCU_LOCKDEP_WARN(!(c), "suspicious rcu_dereference_check() usage"); \ rcu_dereference_sparse(p, space); \ ((typeof(*p) __force __kernel *)(________p1)); \ }) #define __rcu_dereference_protected(p, c, space) \ ({ \ - rcu_lockdep_assert(c, "suspicious rcu_dereference_protected() usage"); \ + RCU_LOCKDEP_WARN(!(c), "suspicious rcu_dereference_protected() usage"); \ rcu_dereference_sparse(p, space); \ ((typeof(*p) __force __kernel *)(p)); \ }) @@ -836,8 +857,8 @@ static inline void rcu_read_lock(void) __rcu_read_lock(); __acquire(RCU); rcu_lock_acquire(&rcu_lock_map); - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_lock() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_lock() used illegally while idle"); } /* @@ -887,8 +908,8 @@ static inline void rcu_read_lock(void) */ static inline void rcu_read_unlock(void) { - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_unlock() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_unlock() used illegally while idle"); __release(RCU); __rcu_read_unlock(); rcu_lock_release(&rcu_lock_map); /* Keep acq info for rls diags. */ @@ -916,8 +937,8 @@ static inline void rcu_read_lock_bh(void) local_bh_disable(); __acquire(RCU_BH); rcu_lock_acquire(&rcu_bh_lock_map); - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_lock_bh() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_lock_bh() used illegally while idle"); } /* @@ -927,8 +948,8 @@ static inline void rcu_read_lock_bh(void) */ static inline void rcu_read_unlock_bh(void) { - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_unlock_bh() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_unlock_bh() used illegally while idle"); rcu_lock_release(&rcu_bh_lock_map); __release(RCU_BH); local_bh_enable(); @@ -952,8 +973,8 @@ static inline void rcu_read_lock_sched(void) preempt_disable(); __acquire(RCU_SCHED); rcu_lock_acquire(&rcu_sched_lock_map); - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_lock_sched() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_lock_sched() used illegally while idle"); } /* Used by lockdep and tracing: cannot be traced, cannot call lockdep. */ @@ -970,8 +991,8 @@ static inline notrace void rcu_read_lock_sched_notrace(void) */ static inline void rcu_read_unlock_sched(void) { - rcu_lockdep_assert(rcu_is_watching(), - "rcu_read_unlock_sched() used illegally while idle"); + RCU_LOCKDEP_WARN(!rcu_is_watching(), + "rcu_read_unlock_sched() used illegally while idle"); rcu_lock_release(&rcu_sched_lock_map); __release(RCU_SCHED); preempt_enable(); diff --git a/kernel/cgroup.c b/kernel/cgroup.c index f89d9292eee6..b89f3168411b 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -107,8 +107,8 @@ static DEFINE_SPINLOCK(release_agent_path_lock); struct percpu_rw_semaphore cgroup_threadgroup_rwsem; #define cgroup_assert_mutex_or_rcu_locked() \ - rcu_lockdep_assert(rcu_read_lock_held() || \ - lockdep_is_held(&cgroup_mutex), \ + RCU_LOCKDEP_WARN(!rcu_read_lock_held() && \ + !lockdep_is_held(&cgroup_mutex), \ "cgroup_mutex or RCU read lock required"); /* diff --git a/kernel/pid.c b/kernel/pid.c index 4fd07d5b7baf..ca368793808e 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -451,9 +451,8 @@ EXPORT_SYMBOL(pid_task); */ struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns) { - rcu_lockdep_assert(rcu_read_lock_held(), - "find_task_by_pid_ns() needs rcu_read_lock()" - " protection"); + RCU_LOCKDEP_WARN(!rcu_read_lock_held(), + "find_task_by_pid_ns() needs rcu_read_lock() protection"); return pid_task(find_pid_ns(nr, ns), PIDTYPE_PID); } diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c index de35087c92a5..d3fcb2ec8536 100644 --- a/kernel/rcu/srcu.c +++ b/kernel/rcu/srcu.c @@ -415,11 +415,11 @@ static void __synchronize_srcu(struct srcu_struct *sp, int trycount) struct rcu_head *head = &rcu.head; bool done = false; - rcu_lockdep_assert(!lock_is_held(&sp->dep_map) && - !lock_is_held(&rcu_bh_lock_map) && - !lock_is_held(&rcu_lock_map) && - !lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_srcu() in same-type SRCU (or RCU) read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&sp->dep_map) || + lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_srcu() in same-type SRCU (or in RCU) read-side critical section"); might_sleep(); init_completion(&rcu.completion); diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index c291bd65d2cb..d0471056d0af 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c @@ -191,10 +191,10 @@ static void rcu_process_callbacks(struct softirq_action *unused) */ void synchronize_sched(void) { - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) && - !lock_is_held(&rcu_lock_map) && - !lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_sched() in RCU read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_sched() in RCU read-side critical section"); cond_resched(); } EXPORT_SYMBOL_GPL(synchronize_sched); diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index cb64d7e13d24..0a73d26357a2 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -649,12 +649,12 @@ static void rcu_eqs_enter_common(long long oldval, bool user) * It is illegal to enter an extended quiescent state while * in an RCU read-side critical section. */ - rcu_lockdep_assert(!lock_is_held(&rcu_lock_map), - "Illegal idle entry in RCU read-side critical section."); - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map), - "Illegal idle entry in RCU-bh read-side critical section."); - rcu_lockdep_assert(!lock_is_held(&rcu_sched_lock_map), - "Illegal idle entry in RCU-sched read-side critical section."); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_lock_map), + "Illegal idle entry in RCU read-side critical section."); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map), + "Illegal idle entry in RCU-bh read-side critical section."); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_sched_lock_map), + "Illegal idle entry in RCU-sched read-side critical section."); } /* @@ -3161,10 +3161,10 @@ static inline int rcu_blocking_is_gp(void) */ void synchronize_sched(void) { - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) && - !lock_is_held(&rcu_lock_map) && - !lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_sched() in RCU-sched read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_sched() in RCU-sched read-side critical section"); if (rcu_blocking_is_gp()) return; if (rcu_gp_is_expedited()) @@ -3188,10 +3188,10 @@ EXPORT_SYMBOL_GPL(synchronize_sched); */ void synchronize_rcu_bh(void) { - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) && - !lock_is_held(&rcu_lock_map) && - !lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_rcu_bh() in RCU-bh read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_rcu_bh() in RCU-bh read-side critical section"); if (rcu_blocking_is_gp()) return; if (rcu_gp_is_expedited()) diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index a983bc68a146..9e922f111d63 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h @@ -538,10 +538,10 @@ EXPORT_SYMBOL_GPL(call_rcu); */ void synchronize_rcu(void) { - rcu_lockdep_assert(!lock_is_held(&rcu_bh_lock_map) && - !lock_is_held(&rcu_lock_map) && - !lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_rcu() in RCU read-side critical section"); + RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) || + lock_is_held(&rcu_lock_map) || + lock_is_held(&rcu_sched_lock_map), + "Illegal synchronize_rcu() in RCU read-side critical section"); if (!rcu_scheduler_active) return; if (rcu_gp_is_expedited()) diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index a0a0dd03c73a..47268fb1d27b 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -589,8 +589,8 @@ EXPORT_SYMBOL_GPL(call_rcu_tasks); void synchronize_rcu_tasks(void) { /* Complain if the scheduler has not started. */ - rcu_lockdep_assert(!rcu_scheduler_active, - "synchronize_rcu_tasks called too soon"); + RCU_LOCKDEP_WARN(rcu_scheduler_active, + "synchronize_rcu_tasks called too soon"); /* Wait for the grace period. */ wait_rcu_gp(call_rcu_tasks); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 78b4bad10081..5e73c79fadd0 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2200,8 +2200,8 @@ unsigned long to_ratio(u64 period, u64 runtime) #ifdef CONFIG_SMP inline struct dl_bw *dl_bw_of(int i) { - rcu_lockdep_assert(rcu_read_lock_sched_held(), - "sched RCU must be held"); + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), + "sched RCU must be held"); return &cpu_rq(i)->rd->dl_bw; } @@ -2210,8 +2210,8 @@ static inline int dl_bw_cpus(int i) struct root_domain *rd = cpu_rq(i)->rd; int cpus = 0; - rcu_lockdep_assert(rcu_read_lock_sched_held(), - "sched RCU must be held"); + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), + "sched RCU must be held"); for_each_cpu_and(i, rd->span, cpu_active_mask) cpus++; diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 4c4f06176f74..cb91c63b4f4a 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -338,20 +338,20 @@ static void workqueue_sysfs_unregister(struct workqueue_struct *wq); #include #define assert_rcu_or_pool_mutex() \ - rcu_lockdep_assert(rcu_read_lock_sched_held() || \ - lockdep_is_held(&wq_pool_mutex), \ - "sched RCU or wq_pool_mutex should be held") + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \ + !lockdep_is_held(&wq_pool_mutex), \ + "sched RCU or wq_pool_mutex should be held") #define assert_rcu_or_wq_mutex(wq) \ - rcu_lockdep_assert(rcu_read_lock_sched_held() || \ - lockdep_is_held(&wq->mutex), \ - "sched RCU or wq->mutex should be held") + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \ + !lockdep_is_held(&wq->mutex), \ + "sched RCU or wq->mutex should be held") #define assert_rcu_or_wq_mutex_or_pool_mutex(wq) \ - rcu_lockdep_assert(rcu_read_lock_sched_held() || \ - lockdep_is_held(&wq->mutex) || \ - lockdep_is_held(&wq_pool_mutex), \ - "sched RCU, wq->mutex or wq_pool_mutex should be held") + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \ + !lockdep_is_held(&wq->mutex) && \ + !lockdep_is_held(&wq_pool_mutex), \ + "sched RCU, wq->mutex or wq_pool_mutex should be held") #define for_each_cpu_worker_pool(pool, cpu) \ for ((pool) = &per_cpu(cpu_worker_pools, cpu)[0]; \ diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 188c1d26393b..73455089feef 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -400,9 +400,9 @@ static bool verify_new_ex(struct dev_cgroup *dev_cgroup, { bool match = false; - rcu_lockdep_assert(rcu_read_lock_held() || - lockdep_is_held(&devcgroup_mutex), - "device_cgroup:verify_new_ex called without proper synchronization"); + RCU_LOCKDEP_WARN(!rcu_read_lock_held() && + lockdep_is_held(&devcgroup_mutex), + "device_cgroup:verify_new_ex called without proper synchronization"); if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) { if (behavior == DEVCG_DEFAULT_ALLOW) { -- cgit v1.3-6-gb490 From 0faaad461547e2412e9b519cd757a99b3ebc1302 Mon Sep 17 00:00:00 2001 From: Kris Borer Date: Tue, 14 Jul 2015 09:28:30 -0400 Subject: usb: move assignment out of if condition Fix four occurrences of checkpatch.pl error: ERROR: do not use assignment in if condition The semantic patch that makes this change is: // @@ identifier i; expression E; statement S; constant c; binary operator b; @@ + i = E; if ( - (i = E) + i b c ) S @@ identifier i, i2; expression E1, E2; constant c; @@ + if( E1->i ) { + i2 = E2; + if (i2 < c) { - if( E1->i && (i2 = E2) < c ) { ... - } + } + } // Signed-off-by: Kris Borer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index be5b2074f906..3204a4dcfeb4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2683,12 +2683,14 @@ int usb_add_hcd(struct usb_hcd *hcd, * bottom up so that hcds can customize the root hubs before hub_wq * starts talking to them. (Note, bus id is assigned early too.) */ - if ((retval = hcd_buffer_create(hcd)) != 0) { + retval = hcd_buffer_create(hcd); + if (retval != 0) { dev_dbg(hcd->self.controller, "pool alloc failed\n"); goto err_create_buf; } - if ((retval = usb_register_bus(&hcd->self)) < 0) + retval = usb_register_bus(&hcd->self); + if (retval < 0) goto err_register_bus; rhdev = usb_alloc_dev(NULL, &hcd->self, 0); @@ -2734,9 +2736,13 @@ int usb_add_hcd(struct usb_hcd *hcd, /* "reset" is misnamed; its role is now one-time init. the controller * should already have been reset (and boot firmware kicked off etc). */ - if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { - dev_err(hcd->self.controller, "can't setup: %d\n", retval); - goto err_hcd_driver_setup; + if (hcd->driver->reset) { + retval = hcd->driver->reset(hcd); + if (retval < 0) { + dev_err(hcd->self.controller, "can't setup: %d\n", + retval); + goto err_hcd_driver_setup; + } } hcd->rh_pollable = 1; @@ -2766,7 +2772,8 @@ int usb_add_hcd(struct usb_hcd *hcd, } /* starting here, usbcore will pay attention to this root hub */ - if ((retval = register_root_hub(hcd)) != 0) + retval = register_root_hub(hcd); + if (retval != 0) goto err_register_root_hub; retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); -- cgit v1.3-6-gb490 From 7e4a4da67255d92620ba59b461b5bc295db28dae Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:35 +0200 Subject: USB: bcma: remove chip id check I have never seen any bcma device with an USB host core which was not a SoC, the bcma devices have an USB device core with a different core id. Some SoC have IDs with 47XX and 53XX in decimal form which would be rejected by this check. Instead of fixing this check just remove it. Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/bcma-hcd.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 526cfab41d5f..976b4e10ee65 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -214,16 +214,11 @@ err_alloc: static int bcma_hcd_probe(struct bcma_device *dev) { int err; - u16 chipid_top; u32 ohci_addr; struct bcma_hcd_device *usb_dev; struct bcma_chipinfo *chipinfo; chipinfo = &dev->bus->chipinfo; - /* USBcores are only connected on embedded devices. */ - chipid_top = (chipinfo->id & 0xFF00); - if (chipid_top != 0x4700 && chipid_top != 0x5300) - return -ENODEV; /* TODO: Probably need checks here; is the core connected? */ -- cgit v1.3-6-gb490 From 98e13e05a1bab82c3bec1d867159bc8384acbe5b Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:36 +0200 Subject: USB: bcma: replace numbers with constants The constants for these numbers were added long time ago, use them. Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/bcma-hcd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 976b4e10ee65..b4ec4ec35680 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -233,7 +233,8 @@ static int bcma_hcd_probe(struct bcma_device *dev) /* In AI chips EHCI is addrspace 0, OHCI is 1 */ ohci_addr = dev->addr_s[0]; - if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749) + if ((chipinfo->id == BCMA_CHIP_ID_BCM5357 || + chipinfo->id == BCMA_CHIP_ID_BCM4749) && chipinfo->rev == 0) ohci_addr = 0x18009000; -- cgit v1.3-6-gb490 From c27da2b22b558390acc515e71e47b1b307f85d5a Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:37 +0200 Subject: USB: bcma: use devm_kzalloc Instead of manually handling the frees use devm. There was also a free missing in the unregister call which is not needed with devm. Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/bcma-hcd.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index b4ec4ec35680..34ab0a43e033 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -225,7 +225,8 @@ static int bcma_hcd_probe(struct bcma_device *dev) if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32))) return -EOPNOTSUPP; - usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL); + usb_dev = devm_kzalloc(&dev->dev, sizeof(struct bcma_hcd_device), + GFP_KERNEL); if (!usb_dev) return -ENOMEM; @@ -239,10 +240,8 @@ static int bcma_hcd_probe(struct bcma_device *dev) ohci_addr = 0x18009000; usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr); - if (IS_ERR(usb_dev->ohci_dev)) { - err = PTR_ERR(usb_dev->ohci_dev); - goto err_free_usb_dev; - } + if (IS_ERR(usb_dev->ohci_dev)) + return PTR_ERR(usb_dev->ohci_dev); usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr); if (IS_ERR(usb_dev->ehci_dev)) { @@ -255,8 +254,6 @@ static int bcma_hcd_probe(struct bcma_device *dev) err_unregister_ohci_dev: platform_device_unregister(usb_dev->ohci_dev); -err_free_usb_dev: - kfree(usb_dev); return err; } -- cgit v1.3-6-gb490 From ab2de5793080dfb9f191ca71068b9f476a55a0f4 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:38 +0200 Subject: USB: bcma: fix error handling in bcma_hcd_create_pdev() This patch makes bcma_hcd_create_pdev() not return NULL, but a prober error code in case of an error. Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/bcma-hcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 34ab0a43e033..35d45a9f9940 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -169,7 +169,7 @@ static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, boo { struct platform_device *hci_dev; struct resource hci_res[2]; - int ret = -ENOMEM; + int ret; memset(hci_res, 0, sizeof(hci_res)); @@ -183,7 +183,7 @@ static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, boo hci_dev = platform_device_alloc(ohci ? "ohci-platform" : "ehci-platform" , 0); if (!hci_dev) - return NULL; + return ERR_PTR(-ENOMEM); hci_dev->dev.parent = &dev->dev; hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask; -- cgit v1.3-6-gb490 From 10bc04b744c69f253dfe47bc143325349ce8becc Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:39 +0200 Subject: USB: bcma: add bcm53xx support The Broadcom ARM SoCs with this usb core need a different initialization and they have a different core id. This patch adds support for these USB 2.0 core. Signed-off-by: Felix Fietkau Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/bcma-hcd.c | 81 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 35d45a9f9940..96f172581a85 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -2,7 +2,8 @@ * Broadcom specific Advanced Microcontroller Bus * Broadcom USB-core driver (BCMA bus glue) * - * Copyright 2011-2012 Hauke Mehrtens + * Copyright 2011-2015 Hauke Mehrtens + * Copyright 2015 Felix Fietkau * * Based on ssb-ohci driver * Copyright 2007 Michael Buesch @@ -88,7 +89,7 @@ static void bcma_hcd_4716wa(struct bcma_device *dev) } /* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */ -static void bcma_hcd_init_chip(struct bcma_device *dev) +static void bcma_hcd_init_chip_mips(struct bcma_device *dev) { u32 tmp; @@ -159,6 +160,70 @@ static void bcma_hcd_init_chip(struct bcma_device *dev) } } +static void bcma_hcd_init_chip_arm_phy(struct bcma_device *dev) +{ + struct bcma_device *arm_core; + void __iomem *dmu; + + arm_core = bcma_find_core(dev->bus, BCMA_CORE_ARMCA9); + if (!arm_core) { + dev_err(&dev->dev, "can not find ARM Cortex A9 ihost core\n"); + return; + } + + dmu = ioremap_nocache(arm_core->addr_s[0], 0x1000); + if (!dmu) { + dev_err(&dev->dev, "can not map ARM Cortex A9 ihost core\n"); + return; + } + + /* Unlock DMU PLL settings */ + iowrite32(0x0000ea68, dmu + 0x180); + + /* Write USB 2.0 PLL control setting */ + iowrite32(0x00dd10c3, dmu + 0x164); + + /* Lock DMU PLL settings */ + iowrite32(0x00000000, dmu + 0x180); + + iounmap(dmu); +} + +static void bcma_hcd_init_chip_arm_hc(struct bcma_device *dev) +{ + u32 val; + + /* + * Delay after PHY initialized to ensure HC is ready to be configured + */ + usleep_range(1000, 2000); + + /* Set packet buffer OUT threshold */ + val = bcma_read32(dev, 0x94); + val &= 0xffff; + val |= 0x80 << 16; + bcma_write32(dev, 0x94, val); + + /* Enable break memory transfer */ + val = bcma_read32(dev, 0x9c); + val |= 1; + bcma_write32(dev, 0x9c, val); +} + +static void bcma_hcd_init_chip_arm(struct bcma_device *dev) +{ + bcma_core_enable(dev, 0); + + if (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4707 || + dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM53018) { + if (dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4707 || + dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4708) + bcma_hcd_init_chip_arm_phy(dev); + + bcma_hcd_init_chip_arm_hc(dev); + } +} + static const struct usb_ehci_pdata ehci_pdata = { }; @@ -230,7 +295,16 @@ static int bcma_hcd_probe(struct bcma_device *dev) if (!usb_dev) return -ENOMEM; - bcma_hcd_init_chip(dev); + switch (dev->id.id) { + case BCMA_CORE_NS_USB20: + bcma_hcd_init_chip_arm(dev); + break; + case BCMA_CORE_USB20_HOST: + bcma_hcd_init_chip_mips(dev); + break; + default: + return -ENODEV; + } /* In AI chips EHCI is addrspace 0, OHCI is 1 */ ohci_addr = dev->addr_s[0]; @@ -299,6 +373,7 @@ static int bcma_hcd_resume(struct bcma_device *dev) static const struct bcma_device_id bcma_hcd_table[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS), + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS), {}, }; MODULE_DEVICE_TABLE(bcma, bcma_hcd_table); -- cgit v1.3-6-gb490 From eb4861c3cef7f745df0d2a26b0f4287da0190424 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 11 Jun 2015 22:57:40 +0200 Subject: USB: bcma: add support for controlling bus power through GPIO On some boards a GPIO is needed to activate USB controller. Make it possible to specify such a GPIO in device tree. Signed-off-by: Felix Fietkau Signed-off-by: Hauke Mehrtens Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/bcma-hcd.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 96f172581a85..5398e3d42822 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -224,6 +226,23 @@ static void bcma_hcd_init_chip_arm(struct bcma_device *dev) } } +static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val) +{ + int gpio; + + gpio = of_get_named_gpio(dev->dev.of_node, "vcc-gpio", 0); + if (!gpio_is_valid(gpio)) + return; + + if (val) { + gpio_request(gpio, "bcma-hcd-gpio"); + gpio_set_value(gpio, 1); + } else { + gpio_set_value(gpio, 0); + gpio_free(gpio); + } +} + static const struct usb_ehci_pdata ehci_pdata = { }; @@ -295,6 +314,8 @@ static int bcma_hcd_probe(struct bcma_device *dev) if (!usb_dev) return -ENOMEM; + bcma_hci_platform_power_gpio(dev, true); + switch (dev->id.id) { case BCMA_CORE_NS_USB20: bcma_hcd_init_chip_arm(dev); @@ -347,6 +368,7 @@ static void bcma_hcd_remove(struct bcma_device *dev) static void bcma_hcd_shutdown(struct bcma_device *dev) { + bcma_hci_platform_power_gpio(dev, false); bcma_core_disable(dev, 0); } @@ -354,6 +376,7 @@ static void bcma_hcd_shutdown(struct bcma_device *dev) static int bcma_hcd_suspend(struct bcma_device *dev) { + bcma_hci_platform_power_gpio(dev, false); bcma_core_disable(dev, 0); return 0; @@ -361,6 +384,7 @@ static int bcma_hcd_suspend(struct bcma_device *dev) static int bcma_hcd_resume(struct bcma_device *dev) { + bcma_hci_platform_power_gpio(dev, true); bcma_core_enable(dev, 0); return 0; -- cgit v1.3-6-gb490 From 655fe4effe0f1f40e4f6ca6b3cc64a7fe0032183 Mon Sep 17 00:00:00 2001 From: Kevin Strasser Date: Tue, 16 Jun 2015 10:35:30 -0700 Subject: usbcore: add sysfs support to xHCI usb3 hardware LPM Add a sysfs node to make it easier to verify if LPM is supported and being enabled for USB 3.0 devices. Signed-off-by: Kevin Strasser Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-usb | 14 ++++++++++++++ Documentation/usb/power-management.txt | 15 +++++++++++++-- drivers/usb/core/hub.c | 4 ++++ drivers/usb/core/sysfs.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index e5cc7633d013..e935625f5995 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -114,6 +114,20 @@ Description: enabled for the device. Developer can write y/Y/1 or n/N/0 to the file to enable/disable the feature. +What: /sys/bus/usb/devices/.../power/usb3_hardware_lpm +Date: June 2015 +Contact: Kevin Strasser +Description: + If CONFIG_PM_RUNTIME is set and a USB 3.0 lpm-capable device is + plugged in to a xHCI host which supports link PM, it will check + if U1 and U2 exit latencies have been set in the BOS + descriptor; if the check is is passed and the host supports + USB3 hardware LPM, USB3 hardware LPM will be enabled for the + device and the USB device directory will contain a file named + power/usb3_hardware_lpm. The file holds a string value (enable + or disable) indicating whether or not USB3 hardware LPM is + enabled for the device. + What: /sys/bus/usb/devices/.../removable Date: February 2012 Contact: Matthew Garrett diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt index b5f83911732a..4a15c90bc11d 100644 --- a/Documentation/usb/power-management.txt +++ b/Documentation/usb/power-management.txt @@ -521,10 +521,10 @@ enabling hardware LPM, the host can automatically put the device into lower power state(L1 for usb2.0 devices, or U1/U2 for usb3.0 devices), which state device can enter and resume very quickly. -The user interface for controlling USB2 hardware LPM is located in the +The user interface for controlling hardware LPM is located in the power/ subdirectory of each USB device's sysfs directory, that is, in /sys/bus/usb/devices/.../power/ where "..." is the device's ID. The -relevant attribute files is usb2_hardware_lpm. +relevant attribute files are usb2_hardware_lpm and usb3_hardware_lpm. power/usb2_hardware_lpm @@ -537,6 +537,17 @@ relevant attribute files is usb2_hardware_lpm. can write y/Y/1 or n/N/0 to the file to enable/disable USB2 hardware LPM manually. This is for test purpose mainly. + power/usb3_hardware_lpm + + When a USB 3.0 lpm-capable device is plugged in to a + xHCI host which supports link PM, it will check if U1 + and U2 exit latencies have been set in the BOS + descriptor; if the check is is passed and the host + supports USB3 hardware LPM, USB3 hardware LPM will be + enabled for the device and this file will be created. + The file holds a string value (enable or disable) + indicating whether or not USB3 hardware LPM is + enabled for the device. USB Port Power Control ---------------------- diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 43cb2f2e3b43..d9ce8f9d9acc 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3950,6 +3950,8 @@ int usb_disable_lpm(struct usb_device *udev) if (usb_disable_link_state(hcd, udev, USB3_LPM_U2)) goto enable_lpm; + udev->usb3_lpm_enabled = 0; + return 0; enable_lpm: @@ -4007,6 +4009,8 @@ void usb_enable_lpm(struct usb_device *udev) usb_enable_link_state(hcd, udev, USB3_LPM_U1); usb_enable_link_state(hcd, udev, USB3_LPM_U2); + + udev->usb3_lpm_enabled = 1; } EXPORT_SYMBOL_GPL(usb_enable_lpm); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index d26973844a4d..cfc68c11c3f5 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -531,6 +531,25 @@ static ssize_t usb2_lpm_besl_store(struct device *dev, } static DEVICE_ATTR_RW(usb2_lpm_besl); +static ssize_t usb3_hardware_lpm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + const char *p; + + usb_lock_device(udev); + + if (udev->usb3_lpm_enabled) + p = "enabled"; + else + p = "disabled"; + + usb_unlock_device(udev); + + return sprintf(buf, "%s\n", p); +} +static DEVICE_ATTR_RO(usb3_hardware_lpm); + static struct attribute *usb2_hardware_lpm_attr[] = { &dev_attr_usb2_hardware_lpm.attr, &dev_attr_usb2_lpm_l1_timeout.attr, @@ -542,6 +561,15 @@ static struct attribute_group usb2_hardware_lpm_attr_group = { .attrs = usb2_hardware_lpm_attr, }; +static struct attribute *usb3_hardware_lpm_attr[] = { + &dev_attr_usb3_hardware_lpm.attr, + NULL, +}; +static struct attribute_group usb3_hardware_lpm_attr_group = { + .name = power_group_name, + .attrs = usb3_hardware_lpm_attr, +}; + static struct attribute *power_attrs[] = { &dev_attr_autosuspend.attr, &dev_attr_level.attr, @@ -564,6 +592,9 @@ static int add_power_attributes(struct device *dev) if (udev->usb2_hw_lpm_capable == 1) rc = sysfs_merge_group(&dev->kobj, &usb2_hardware_lpm_attr_group); + if (udev->lpm_capable == 1) + rc = sysfs_merge_group(&dev->kobj, + &usb3_hardware_lpm_attr_group); } return rc; -- cgit v1.3-6-gb490 From e616b39a16d4458224d91697b0a2599336f0c38c Mon Sep 17 00:00:00 2001 From: Sunny Kumar Date: Tue, 7 Jul 2015 12:27:03 +0530 Subject: usb: usleep_range is preferred over udelay where wakeup is flexible According to Documentation/timers/timers-howto.txt" udelay() is only called once from a place where sleeping is allowed. We can replace it with a call to usleep_range() with a reasonable upper limit. Signed-off-by: Sunny Kumar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 540add24a12f..5e67f63b2e46 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1111,7 +1111,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) * command phase and the data phase. Some devices need a little * more than that, probably because of clock rate inaccuracies. */ if (unlikely(us->fflags & US_FL_GO_SLOW)) - udelay(125); + usleep_range(125, 150); if (transfer_length) { unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? -- cgit v1.3-6-gb490 From 0ff818eff55aa80cb00bb3d89e824dd568d5a7f8 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Thu, 23 Jul 2015 00:10:37 +0200 Subject: memory: pl172: fix modular build Building pl172 as a module fails with: > ERROR: "of_default_bus_match_table" [drivers/memory/pl172.ko] undefined! Because the symbol of_default_bus_match_table isn't exported by the OF core code so can't be referenced from modules. Fix this by removing the usage of of_default_bus_match_table for now. The side effect of this is that child nodes can't use "simple-bus" or "simple-mfd". Reported-by: Mark Brown Signed-off-by: Joachim Eastwood Signed-off-by: Olof Johansson --- drivers/memory/pl172.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/pl172.c b/drivers/memory/pl172.c index 3a8e57ee96f0..b2ef6072fbf4 100644 --- a/drivers/memory/pl172.c +++ b/drivers/memory/pl172.c @@ -255,8 +255,7 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id) if (ret) continue; - of_platform_populate(child_np, of_default_bus_match_table, - NULL, dev); + of_platform_populate(child_np, NULL, NULL, dev); } return 0; -- cgit v1.3-6-gb490 From 5fd3fc1c5384fe420ead51f41662ba563336fbea Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 13 Jul 2015 16:30:18 +0100 Subject: usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS These changes allow a PHY driver to trigger a VBUS interrupt and to provide the value of VBUS. Signed-off-by: Phil Edworthy Reviewed-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/mod_gadget.c | 62 ++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa3261202..54f916fa238d 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "common.h" /* @@ -50,6 +51,8 @@ struct usbhsg_gpriv { int uep_size; struct usb_gadget_driver *driver; + struct usb_phy *transceiver; + bool vbus_active; u32 status; #define USBHSG_STATUS_STARTED (1 << 0) @@ -872,6 +875,27 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) return 0; } +/* + * VBUS provided by the PHY + */ +static int usbhsm_phy_get_vbus(struct platform_device *pdev) +{ + struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + + return gpriv->vbus_active; +} + +static void usbhs_mod_phy_mode(struct usbhs_priv *priv) +{ + struct usbhs_mod_info *info = &priv->mod_info; + + info->irq_vbus = NULL; + priv->pfunc.get_vbus = usbhsm_phy_get_vbus; + + usbhs_irq_callback_update(priv, NULL); +} + /* * * linux usb function @@ -882,12 +906,28 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget, { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + struct device *dev = usbhs_priv_to_dev(priv); + int ret; if (!driver || !driver->setup || driver->max_speed < USB_SPEED_FULL) return -EINVAL; + /* connect to bus through transceiver */ + if (!IS_ERR_OR_NULL(gpriv->transceiver)) { + ret = otg_set_peripheral(gpriv->transceiver->otg, + &gpriv->gadget); + if (ret) { + dev_err(dev, "%s: can't bind to transceiver\n", + gpriv->gadget.name); + return ret; + } + + /* get vbus using phy versions */ + usbhs_mod_phy_mode(priv); + } + /* first hook up the driver ... */ gpriv->driver = driver; @@ -900,6 +940,10 @@ static int usbhsg_gadget_stop(struct usb_gadget *gadget) struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD); + + if (!IS_ERR_OR_NULL(gpriv->transceiver)) + otg_set_peripheral(gpriv->transceiver->otg, NULL); + gpriv->driver = NULL; return 0; @@ -947,12 +991,26 @@ static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self) return 0; } +static int usbhsg_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + struct platform_device *pdev = usbhs_priv_to_pdev(priv); + + gpriv->vbus_active = !!is_active; + + renesas_usbhs_call_notify_hotplug(pdev); + + return 0; +} + static const struct usb_gadget_ops usbhsg_gadget_ops = { .get_frame = usbhsg_get_frame, .set_selfpowered = usbhsg_set_selfpowered, .udc_start = usbhsg_gadget_start, .udc_stop = usbhsg_gadget_stop, .pullup = usbhsg_pullup, + .vbus_session = usbhsg_vbus_session, }; static int usbhsg_start(struct usbhs_priv *priv) @@ -994,6 +1052,10 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) goto usbhs_mod_gadget_probe_err_gpriv; } + gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED); + dev_info(dev, "%stransceiver found\n", + gpriv->transceiver ? "" : "no "); + /* * CAUTION * -- cgit v1.3-6-gb490 From 38aa420096e565fe9c98f9d9475fd168114501a9 Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Mon, 15 Jun 2015 15:46:37 +0530 Subject: drivers:usb:fsl: Replace macros with enumerated type Replace macros with enumerated type to represent usb ip controller version Signed-off-by: Nikhil Badola Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fsl-mph-dr-of.c | 8 ++++---- include/linux/fsl_devices.h | 16 ++++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 5e0d60035216..219595637cb1 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -119,9 +119,9 @@ error: static const struct of_device_id fsl_usb2_mph_dr_of_match[]; -static int usb_get_ver_info(struct device_node *np) +static enum fsl_usb2_controller_ver usb_get_ver_info(struct device_node *np) { - int ver = -1; + enum fsl_usb2_controller_ver ver = FSL_USB_VER_NONE; /* * returns 1 for usb controller version 1.6 @@ -142,7 +142,7 @@ static int usb_get_ver_info(struct device_node *np) else /* for previous controller versions */ ver = FSL_USB_VER_OLD; - if (ver > -1) + if (ver > FSL_USB_VER_NONE) return ver; } @@ -215,7 +215,7 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->controller_ver = usb_get_ver_info(np); if (pdata->have_sysif_regs) { - if (pdata->controller_ver < 0) { + if (pdata->controller_ver == FSL_USB_VER_NONE) { dev_warn(&ofdev->dev, "Could not get controller version\n"); return -ENODEV; } diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 2a2f56b292c1..0d4855cd5330 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -20,11 +20,6 @@ #define FSL_UTMI_PHY_DLY 10 /*As per P1010RM, delay for UTMI PHY CLK to become stable - 10ms*/ #define FSL_USB_PHY_CLK_TIMEOUT 10000 /* uSec */ -#define FSL_USB_VER_OLD 0 -#define FSL_USB_VER_1_6 1 -#define FSL_USB_VER_2_2 2 -#define FSL_USB_VER_2_4 3 -#define FSL_USB_VER_2_5 4 #include @@ -52,6 +47,15 @@ * */ +enum fsl_usb2_controller_ver { + FSL_USB_VER_NONE = -1, + FSL_USB_VER_OLD = 0, + FSL_USB_VER_1_6 = 1, + FSL_USB_VER_2_2 = 2, + FSL_USB_VER_2_4 = 3, + FSL_USB_VER_2_5 = 4, +}; + enum fsl_usb2_operating_modes { FSL_USB2_MPH_HOST, FSL_USB2_DR_HOST, @@ -72,7 +76,7 @@ struct platform_device; struct fsl_usb2_platform_data { /* board specific information */ - int controller_ver; + enum fsl_usb2_controller_ver controller_ver; enum fsl_usb2_operating_modes operating_mode; enum fsl_usb2_phy_modes phy_mode; unsigned int port_enables; -- cgit v1.3-6-gb490 From 523f1dec58408b36e7683a3d61a0286eed1fc1c8 Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Mon, 15 Jun 2015 15:47:29 +0530 Subject: drivers: usb :fsl: Implement Workaround for USB Erratum A007792 USB controller version-2.5 requires to enable internal UTMI phy and program PTS field in PORTSC register before asserting controller reset. This is must for successful resetting of the controller and subsequent enumeration of usb devices Signed-off-by: Nikhil Badola Signed-off-by: Suresh Gupta Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 9 +++++++++ drivers/usb/host/fsl-mph-dr-of.c | 6 ++++++ include/linux/fsl_devices.h | 1 + 3 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 5352e74b92e2..716aa8be1d6f 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -129,6 +129,15 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4); + /* + * Enable UTMI phy and program PTS field in UTMI mode before asserting + * controller reset for USB Controller version 2.5 + */ + if (pdata->has_fsl_erratum_a007792) { + writel_be(CTRL_UTMI_PHY_EN, hcd->regs + FSL_SOC_USB_CTRL); + writel(PORT_PTS_UTMI, hcd->regs + FSL_SOC_USB_PORTSC1); + } + /* Don't need to set host mode here. It will be done by tdi_reset() */ retval = usb_add_hcd(hcd, irq, IRQF_SHARED); diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 219595637cb1..17e1e6b7a035 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -214,6 +214,12 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) pdata->phy_mode = determine_usb_phy(prop); pdata->controller_ver = usb_get_ver_info(np); + /* Activate Erratum by reading property in device tree */ + if (of_get_property(np, "fsl,usb-erratum-a007792", NULL)) + pdata->has_fsl_erratum_a007792 = 1; + else + pdata->has_fsl_erratum_a007792 = 0; + if (pdata->have_sysif_regs) { if (pdata->controller_ver == FSL_USB_VER_NONE) { dev_warn(&ofdev->dev, "Could not get controller version\n"); diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 0d4855cd5330..bdb40f67180c 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -97,6 +97,7 @@ struct fsl_usb2_platform_data { unsigned suspended:1; unsigned already_suspended:1; + unsigned has_fsl_erratum_a007792:1; /* register save area for suspend/resume */ u32 pm_command; -- cgit v1.3-6-gb490 From 6009d95e04cf74c6f80db56fddca21fea476ad24 Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Mon, 15 Jun 2015 15:48:22 +0530 Subject: drivers:usb:fsl: Introduce FSL_USB2_PHY_UTMI_DUAL macro Introduce FSL_USB2_PHY_UTMI_DUAL macro for setting phy mode in SOCs such has T4240, T1040, T2080 which have utmi dual-phy Signed-off-by: Ramneek Mehresh Signed-off-by: Nikhil Badola Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 1 + drivers/usb/host/fsl-mph-dr-of.c | 2 ++ include/linux/fsl_devices.h | 1 + 3 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 716aa8be1d6f..b04c9dbd5c7d 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -213,6 +213,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, portsc |= PORT_PTS_PTW; /* fall through */ case FSL_USB2_PHY_UTMI: + case FSL_USB2_PHY_UTMI_DUAL: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 17e1e6b7a035..631fc504afda 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -69,6 +69,8 @@ static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) return FSL_USB2_PHY_UTMI; if (!strcasecmp(phy_type, "utmi_wide")) return FSL_USB2_PHY_UTMI_WIDE; + if (!strcasecmp(phy_type, "utmi_dual")) + return FSL_USB2_PHY_UTMI_DUAL; if (!strcasecmp(phy_type, "serial")) return FSL_USB2_PHY_SERIAL; diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index bdb40f67180c..070d9aef90a7 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -69,6 +69,7 @@ enum fsl_usb2_phy_modes { FSL_USB2_PHY_UTMI, FSL_USB2_PHY_UTMI_WIDE, FSL_USB2_PHY_SERIAL, + FSL_USB2_PHY_UTMI_DUAL, }; struct clk; -- cgit v1.3-6-gb490 From f4fdfaa280a284be8a056d6840cdbbf42c05bf95 Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Tue, 14 Jul 2015 17:28:10 +0530 Subject: drivers: usb: fsl: Modify phy clk valid bit checking Phy_clk_valid bit is checked only when the boolean property phy-clk-valid in present in usb node device tree. This property is added to the usb node via device tree fixup. Signed-off-by: Nikhil Badola Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 16 ++++++++-------- drivers/usb/host/fsl-mph-dr-of.c | 9 +++++++++ include/linux/fsl_devices.h | 1 + 3 files changed, 18 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index b04c9dbd5c7d..05ebe3dcd618 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -230,14 +230,14 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, break; } - if (pdata->have_sysif_regs && - pdata->controller_ver > FSL_USB_VER_1_6 && - (phy_mode == FSL_USB2_PHY_ULPI)) { - /* check PHY_CLK_VALID to get phy clk valid */ - if (!(spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & - PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0) || - in_be32(non_ehci + FSL_SOC_USB_PRICTRL))) { - dev_warn(hcd->self.controller, "USB PHY clock invalid\n"); + /* + * check PHY_CLK_VALID to determine phy clock presence before writing + * to portsc + */ + if (pdata->check_phy_clk_valid) { + if (!(in_be32(non_ehci + FSL_SOC_USB_CTRL) & PHY_CLK_VALID)) { + dev_warn(hcd->self.controller, + "USB PHY clock invalid\n"); return -EINVAL; } } diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 631fc504afda..9f731413ab3e 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -222,6 +222,15 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) else pdata->has_fsl_erratum_a007792 = 0; + /* + * Determine whether phy_clk_valid needs to be checked + * by reading property in device tree + */ + if (of_get_property(np, "phy-clk-valid", NULL)) + pdata->check_phy_clk_valid = 1; + else + pdata->check_phy_clk_valid = 0; + if (pdata->have_sysif_regs) { if (pdata->controller_ver == FSL_USB_VER_NONE) { dev_warn(&ofdev->dev, "Could not get controller version\n"); diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 070d9aef90a7..cebdbbb4aa69 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -99,6 +99,7 @@ struct fsl_usb2_platform_data { unsigned suspended:1; unsigned already_suspended:1; unsigned has_fsl_erratum_a007792:1; + unsigned check_phy_clk_valid:1; /* register save area for suspend/resume */ u32 pm_command; -- cgit v1.3-6-gb490 From 4e02bea82b4e6c1eebeac6e6f4ecb93e9c2aa8c0 Mon Sep 17 00:00:00 2001 From: Nikhil Badola Date: Tue, 14 Jul 2015 17:28:47 +0530 Subject: drivers: usb: fsl: Define usb control register mask for w1c bits Define and use CONTROL_REGISTER_W1C_MASK to make sure that w1c bits of usb control register do not get reset while writing any other bit Signed-off-by: Nikhil Badola Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 25 ++++++++++++++++--------- drivers/usb/host/ehci-fsl.h | 1 + 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 05ebe3dcd618..202dafb7d0cb 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -127,14 +127,16 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) /* Enable USB controller, 83xx or 8536 */ if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6) - setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4); + clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, 0x4); /* * Enable UTMI phy and program PTS field in UTMI mode before asserting * controller reset for USB Controller version 2.5 */ if (pdata->has_fsl_erratum_a007792) { - writel_be(CTRL_UTMI_PHY_EN, hcd->regs + FSL_SOC_USB_CTRL); + clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, CTRL_UTMI_PHY_EN); writel(PORT_PTS_UTMI, hcd->regs + FSL_SOC_USB_PORTSC1); } @@ -200,9 +202,11 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_ULPI: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - clrbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); - setbits32(non_ehci + FSL_SOC_USB_CTRL, - ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); + clrbits32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK | UTMI_PHY_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, + ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN); } portsc |= PORT_PTS_ULPI; break; @@ -216,14 +220,16 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, case FSL_USB2_PHY_UTMI_DUAL: if (pdata->have_sysif_regs && pdata->controller_ver) { /* controller version 1.6 or above */ - setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, UTMI_PHY_EN); mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to become stable - 10ms*/ } /* enable UTMI PHY */ if (pdata->have_sysif_regs) - setbits32(non_ehci + FSL_SOC_USB_CTRL, - CTRL_UTMI_PHY_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, + CTRL_UTMI_PHY_EN); portsc |= PORT_PTS_UTMI; break; case FSL_USB2_PHY_NONE: @@ -245,7 +251,8 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs) - setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN); + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, USB_CTRL_USB_EN); return 0; } diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h index dbd292e9f0a7..1a8a60a57cf2 100644 --- a/drivers/usb/host/ehci-fsl.h +++ b/drivers/usb/host/ehci-fsl.h @@ -52,6 +52,7 @@ #define SNOOP_SIZE_2GB 0x1e /* control Register Bit Masks */ +#define CONTROL_REGISTER_W1C_MASK 0x00020000 /* W1C: PHY_CLK_VALID */ #define ULPI_INT_EN (1<<0) #define WU_INT_EN (1<<1) #define USB_CTRL_USB_EN (1<<2) -- cgit v1.3-6-gb490 From e5c2f7b56e9e37e3b54910164ce73b11f207f19d Mon Sep 17 00:00:00 2001 From: Miguel Bernabeu Diaz Date: Fri, 17 Jul 2015 01:39:21 +0200 Subject: staging: lustre: Fix style error with decorator Fixed checkpatch.pl error: ERROR: "(foo*)" should be "(foo *)" Signed-off-by: Miguel Bernabeu Diaz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index f5d1d9f8f1ed..0d8fa3a62c83 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -120,7 +120,7 @@ extern kib_tunables_t kiblnd_tunables; #define IBLND_CREDIT_HIGHWATER_V1 7 /* V1 only : when eagerly to return credits */ #define IBLND_CREDITS_DEFAULT 8 /* default # of peer credits */ -#define IBLND_CREDITS_MAX ((typeof(((kib_msg_t*) 0)->ibm_credits)) - 1) /* Max # of peer credits */ +#define IBLND_CREDITS_MAX ((typeof(((kib_msg_t *) 0)->ibm_credits)) - 1) /* Max # of peer credits */ #define IBLND_MSG_QUEUE_SIZE(v) ((v) == IBLND_MSG_VERSION_1 ? \ IBLND_MSG_QUEUE_SIZE_V1 : \ -- cgit v1.3-6-gb490 From 9a2477c2cabddf6fa52eda49502017191b34acb6 Mon Sep 17 00:00:00 2001 From: Kolbeinn Karlsson Date: Sun, 19 Jul 2015 16:23:19 -0400 Subject: staging: lustre: make functions only used locally static Add a static modifier to two functions that have no separate declaration and are only used within the file they are defined in. This problem was reported by sparse. Signed-off-by: Kolbeinn Karlsson Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ptlrpc/events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/ptlrpc/events.c b/drivers/staging/lustre/lustre/ptlrpc/events.c index 8cb1929fd31d..c8ef9e578263 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/events.c +++ b/drivers/staging/lustre/lustre/ptlrpc/events.c @@ -485,7 +485,7 @@ int ptlrpc_uuid_to_peer(struct obd_uuid *uuid, return rc; } -void ptlrpc_ni_fini(void) +static void ptlrpc_ni_fini(void) { wait_queue_head_t waitq; struct l_wait_info lwi; @@ -529,7 +529,7 @@ lnet_pid_t ptl_get_pid(void) return pid; } -int ptlrpc_ni_init(void) +static int ptlrpc_ni_init(void) { int rc; lnet_pid_t pid; -- cgit v1.3-6-gb490 From 3377bad9c7ea427c002173ffcee6fc6a14833739 Mon Sep 17 00:00:00 2001 From: Cihangir Akturk Date: Tue, 21 Jul 2015 10:22:52 +0300 Subject: staging: lustre: ldlm: Make function static. target_send_reply_msg function is not referenced outside of ldlm_lib.c file, so make it static. Signed-off-by: Cihangir Akturk Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ldlm/ldlm_lib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c index 764f98684d74..badd227e4f67 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c @@ -656,7 +656,8 @@ int target_pack_pool_reply(struct ptlrpc_request *req) } EXPORT_SYMBOL(target_pack_pool_reply); -int target_send_reply_msg(struct ptlrpc_request *req, int rc, int fail_id) +static int +target_send_reply_msg(struct ptlrpc_request *req, int rc, int fail_id) { if (OBD_FAIL_CHECK_ORSET(fail_id & ~OBD_FAIL_ONCE, OBD_FAIL_ONCE)) { DEBUG_REQ(D_ERROR, req, "dropping reply"); -- cgit v1.3-6-gb490 From 83aa2ac65a36e77f5651ef8946003b856cab49bc Mon Sep 17 00:00:00 2001 From: Cihangir Akturk Date: Wed, 22 Jul 2015 15:59:32 +0300 Subject: staging: lustre: obdclass: Make structure declerations static const obd_device_list_sops and obd_device_list_fops are not referenced outside of linux-module.c, and in the general use case struct file_operations and struct seq_operations should be a const object, so make them static and const. This patch fixes the following sparse warnings: WARNING: struct seq_operations should normally be const WARNING: struct file_operations should normally be const Signed-off-by: Cihangir Akturk Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/linux/linux-module.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c index b618c0bd7e09..6218ef34ee80 100644 --- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c +++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c @@ -385,7 +385,7 @@ static int obd_device_list_seq_show(struct seq_file *p, void *v) return 0; } -struct seq_operations obd_device_list_sops = { +static const struct seq_operations obd_device_list_sops = { .start = obd_device_list_seq_start, .stop = obd_device_list_seq_stop, .next = obd_device_list_seq_next, @@ -406,7 +406,7 @@ static int obd_device_list_open(struct inode *inode, struct file *file) return 0; } -struct file_operations obd_device_list_fops = { +static const struct file_operations obd_device_list_fops = { .owner = THIS_MODULE, .open = obd_device_list_open, .read = seq_read, -- cgit v1.3-6-gb490 From 217ed3abf1510747590aaa5da93217e559fd8e19 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:33 +0100 Subject: staging: vt6655: Remove ununsed macro ASSERT VIAWET_DEBUG is not defined so macro is empty. Remove the macro. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/baseband.c | 4 +--- drivers/staging/vt6655/card.c | 1 - drivers/staging/vt6655/device_cfg.h | 9 --------- drivers/staging/vt6655/device_main.c | 9 ++++----- drivers/staging/vt6655/mac.c | 1 - drivers/staging/vt6655/rxtx.c | 1 - 6 files changed, 5 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c index b0ea38f1911c..befaa4259fbf 100644 --- a/drivers/staging/vt6655/baseband.c +++ b/drivers/staging/vt6655/baseband.c @@ -1728,10 +1728,8 @@ BBuGetFrameTime( unsigned int uRateIdx = (unsigned int) wRate; unsigned int uRate = 0; - if (uRateIdx > RATE_54M) { - ASSERT(0); + if (uRateIdx > RATE_54M) return 0; - } uRate = (unsigned int)awcFrameTime[uRateIdx]; diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index e00c0605d154..df62bdc44108 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -847,7 +847,6 @@ void CARDvSetLoopbackMode(struct vnt_private *priv, unsigned short wLoopbackMode case CARD_LB_PHY: break; default: - ASSERT(false); break; } /* set MAC loopback */ diff --git a/drivers/staging/vt6655/device_cfg.h b/drivers/staging/vt6655/device_cfg.h index a4a8a8489e0b..c7f21716b4f0 100644 --- a/drivers/staging/vt6655/device_cfg.h +++ b/drivers/staging/vt6655/device_cfg.h @@ -70,17 +70,8 @@ typedef enum _chip_type { } CHIP_TYPE, *PCHIP_TYPE; #ifdef VIAWET_DEBUG -#define ASSERT(x) \ -do { \ - if (!(x)) { \ - pr_err("assertion %s failed: file %s line %d\n", \ - #x, __func__, __LINE__); \ - *(int *)0 = 0; \ - } \ -} while (0) #define DBG_PORT80(value) outb(value, 0x80) #else -#define ASSERT(x) #define DBG_PORT80(value) #endif diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 23ad16eb1d2a..053291a8e844 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -623,7 +623,7 @@ static void device_init_rd0_ring(struct vnt_private *pDevice) for (i = 0; i < pDevice->sOpts.nRxDescs0; i ++, curr += sizeof(SRxDesc)) { pDesc = &(pDevice->aRD0Ring[i]); pDesc->pRDInfo = alloc_rd_info(); - ASSERT(pDesc->pRDInfo); + if (!device_alloc_rx_buf(pDevice, pDesc)) dev_err(&pDevice->pcid->dev, "can not alloc rx bufs\n"); @@ -647,7 +647,7 @@ static void device_init_rd1_ring(struct vnt_private *pDevice) for (i = 0; i < pDevice->sOpts.nRxDescs1; i ++, curr += sizeof(SRxDesc)) { pDesc = &(pDevice->aRD1Ring[i]); pDesc->pRDInfo = alloc_rd_info(); - ASSERT(pDesc->pRDInfo); + if (!device_alloc_rx_buf(pDevice, pDesc)) dev_err(&pDevice->pcid->dev, "can not alloc rx bufs\n"); @@ -705,7 +705,7 @@ static void device_init_td0_ring(struct vnt_private *pDevice) for (i = 0; i < pDevice->sOpts.nTxDescs[0]; i++, curr += sizeof(STxDesc)) { pDesc = &(pDevice->apTD0Rings[i]); pDesc->pTDInfo = alloc_td_info(); - ASSERT(pDesc->pTDInfo); + if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) { pDesc->pTDInfo->buf = pDevice->tx0_bufs + (i)*PKT_BUF_SZ; pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma0 + (i)*PKT_BUF_SZ; @@ -731,7 +731,7 @@ static void device_init_td1_ring(struct vnt_private *pDevice) for (i = 0; i < pDevice->sOpts.nTxDescs[1]; i++, curr += sizeof(STxDesc)) { pDesc = &(pDevice->apTD1Rings[i]); pDesc->pTDInfo = alloc_td_info(); - ASSERT(pDesc->pTDInfo); + if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) { pDesc->pTDInfo->buf = pDevice->tx1_bufs + (i) * PKT_BUF_SZ; pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma1 + (i) * PKT_BUF_SZ; @@ -818,7 +818,6 @@ static bool device_alloc_rx_buf(struct vnt_private *pDevice, PSRxDesc pRD) pRDInfo->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); if (pRDInfo->skb == NULL) return false; - ASSERT(pRDInfo->skb); pRDInfo->skb_dma = dma_map_single(&pDevice->pcid->dev, diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index aed530f022b8..65dd49cda333 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -186,7 +186,6 @@ void MACvSetLoopbackMode(void __iomem *dwIoBase, unsigned char byLoopbackMode) { unsigned char byOrgValue; - ASSERT(byLoopbackMode < 3); byLoopbackMode <<= 6; /* set TCR */ VNSvInPortB(dwIoBase + MAC_REG_TEST, &byOrgValue); diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 534338c46619..0ffa9bf712be 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -387,7 +387,6 @@ s_uGetDataDuration( break; } - ASSERT(false); return 0; } -- cgit v1.3-6-gb490 From fd43585b6405a0b7c6e5ad3c1bcbb32cf186a5a9 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:34 +0100 Subject: staging: vt6655: remove unused DBG_PORT80 and VIAWET_DEBUG VIAWET_DEBUG is never defined so DBG_PORT80 is empty and never used. Remove both macros. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/baseband.c | 2 -- drivers/staging/vt6655/device_cfg.h | 6 ------ drivers/staging/vt6655/mac.c | 17 ----------------- 3 files changed, 25 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c index befaa4259fbf..9e61f2df3a00 100644 --- a/drivers/staging/vt6655/baseband.c +++ b/drivers/staging/vt6655/baseband.c @@ -1943,7 +1943,6 @@ bool BBbReadEmbedded(struct vnt_private *priv, VNSvInPortB(dwIoBase + MAC_REG_BBREGDATA, pbyData); if (ww == W_MAX_TIMEOUT) { - DBG_PORT80(0x30); pr_debug(" DBG_PORT80(0x30)\n"); return false; } @@ -1986,7 +1985,6 @@ bool BBbWriteEmbedded(struct vnt_private *priv, } if (ww == W_MAX_TIMEOUT) { - DBG_PORT80(0x31); pr_debug(" DBG_PORT80(0x31)\n"); return false; } diff --git a/drivers/staging/vt6655/device_cfg.h b/drivers/staging/vt6655/device_cfg.h index c7f21716b4f0..b4c9547d3138 100644 --- a/drivers/staging/vt6655/device_cfg.h +++ b/drivers/staging/vt6655/device_cfg.h @@ -69,10 +69,4 @@ typedef enum _chip_type { VT3253 = 1 } CHIP_TYPE, *PCHIP_TYPE; -#ifdef VIAWET_DEBUG -#define DBG_PORT80(value) outb(value, 0x80) -#else -#define DBG_PORT80(value) -#endif - #endif diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index 65dd49cda333..3dfd333475c0 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -373,7 +373,6 @@ bool MACbSafeRxOff(void __iomem *dwIoBase) break; } if (ww == W_MAX_TIMEOUT) { - DBG_PORT80(0x10); pr_debug(" DBG_PORT80(0x10)\n"); return false; } @@ -383,7 +382,6 @@ bool MACbSafeRxOff(void __iomem *dwIoBase) break; } if (ww == W_MAX_TIMEOUT) { - DBG_PORT80(0x11); pr_debug(" DBG_PORT80(0x11)\n"); return false; } @@ -397,7 +395,6 @@ bool MACbSafeRxOff(void __iomem *dwIoBase) break; } if (ww == W_MAX_TIMEOUT) { - DBG_PORT80(0x12); pr_debug(" DBG_PORT80(0x12)\n"); return false; } @@ -435,7 +432,6 @@ bool MACbSafeTxOff(void __iomem *dwIoBase) break; } if (ww == W_MAX_TIMEOUT) { - DBG_PORT80(0x20); pr_debug(" DBG_PORT80(0x20)\n"); return false; } @@ -445,7 +441,6 @@ bool MACbSafeTxOff(void __iomem *dwIoBase) break; } if (ww == W_MAX_TIMEOUT) { - DBG_PORT80(0x21); pr_debug(" DBG_PORT80(0x21)\n"); return false; } @@ -460,7 +455,6 @@ bool MACbSafeTxOff(void __iomem *dwIoBase) break; } if (ww == W_MAX_TIMEOUT) { - DBG_PORT80(0x24); pr_debug(" DBG_PORT80(0x24)\n"); return false; } @@ -485,13 +479,11 @@ bool MACbSafeStop(void __iomem *dwIoBase) MACvRegBitsOff(dwIoBase, MAC_REG_TCR, TCR_AUTOBCNTX); if (!MACbSafeRxOff(dwIoBase)) { - DBG_PORT80(0xA1); pr_debug(" MACbSafeRxOff == false)\n"); MACbSafeSoftwareReset(dwIoBase); return false; } if (!MACbSafeTxOff(dwIoBase)) { - DBG_PORT80(0xA2); pr_debug(" MACbSafeTxOff == false)\n"); MACbSafeSoftwareReset(dwIoBase); return false; @@ -589,9 +581,6 @@ void MACvSetCurrRx0DescAddr(void __iomem *dwIoBase, unsigned long dwCurrDescAddr break; } - if (ww == W_MAX_TIMEOUT) - DBG_PORT80(0x13); - VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR0, dwCurrDescAddr); if (byOrgDMACtl & DMACTL_RUN) VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_RUN); @@ -626,8 +615,6 @@ void MACvSetCurrRx1DescAddr(void __iomem *dwIoBase, unsigned long dwCurrDescAddr if (!(byData & DMACTL_RUN)) break; } - if (ww == W_MAX_TIMEOUT) - DBG_PORT80(0x14); VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR1, dwCurrDescAddr); if (byOrgDMACtl & DMACTL_RUN) @@ -665,8 +652,6 @@ void MACvSetCurrTx0DescAddrEx(void __iomem *dwIoBase, if (!(byData & DMACTL_RUN)) break; } - if (ww == W_MAX_TIMEOUT) - DBG_PORT80(0x25); VNSvOutPortD(dwIoBase + MAC_REG_TXDMAPTR0, dwCurrDescAddr); if (byOrgDMACtl & DMACTL_RUN) @@ -705,7 +690,6 @@ void MACvSetCurrAC0DescAddrEx(void __iomem *dwIoBase, break; } if (ww == W_MAX_TIMEOUT) { - DBG_PORT80(0x26); pr_debug(" DBG_PORT80(0x26)\n"); } VNSvOutPortD(dwIoBase + MAC_REG_AC0DMAPTR, dwCurrDescAddr); @@ -806,7 +790,6 @@ bool MACbPSWakeup(void __iomem *dwIoBase) break; } if (ww == W_MAX_TIMEOUT) { - DBG_PORT80(0x36); pr_debug(" DBG_PORT80(0x33)\n"); return false; } -- cgit v1.3-6-gb490 From 3a00033ee8697e2e0acf07d03dbea55c4b7236ca Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:35 +0100 Subject: staging: vt6655: dead code tx path remove dma_unmap_single When pTDInfo->skb_dma not equal to pTDInfo->buf_dma, pTDInfo->skb_dma equals zero. as mentioned in comment pre-allocated buf_dma can't be unmapped so remove dead code. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 053291a8e844..695aa25e819d 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -754,10 +754,6 @@ static void device_free_td0_ring(struct vnt_private *pDevice) PSTxDesc pDesc = &(pDevice->apTD0Rings[i]); PDEVICE_TD_INFO pTDInfo = pDesc->pTDInfo; - if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) - dma_unmap_single(&pDevice->pcid->dev, pTDInfo->skb_dma, - pTDInfo->skb->len, DMA_TO_DEVICE); - dev_kfree_skb(pTDInfo->skb); kfree(pDesc->pTDInfo); } @@ -771,10 +767,6 @@ static void device_free_td1_ring(struct vnt_private *pDevice) PSTxDesc pDesc = &(pDevice->apTD1Rings[i]); PDEVICE_TD_INFO pTDInfo = pDesc->pTDInfo; - if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) - dma_unmap_single(&pDevice->pcid->dev, pTDInfo->skb_dma, - pTDInfo->skb->len, DMA_TO_DEVICE); - dev_kfree_skb(pTDInfo->skb); kfree(pDesc->pTDInfo); } @@ -975,12 +967,6 @@ static void device_free_tx_buf(struct vnt_private *pDevice, PSTxDesc pDesc) PDEVICE_TD_INFO pTDInfo = pDesc->pTDInfo; struct sk_buff *skb = pTDInfo->skb; - /* pre-allocated buf_dma can't be unmapped. */ - if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) { - dma_unmap_single(&pDevice->pcid->dev, pTDInfo->skb_dma, - skb->len, DMA_TO_DEVICE); - } - if (skb) ieee80211_tx_status_irqsafe(pDevice->hw, skb); -- cgit v1.3-6-gb490 From 06f716a57e6d7dc8f7638ea8c19a9a4cdf46ed23 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:36 +0100 Subject: staging: vt6655: remove unnecessary variable skb_dma skb_dma flips from 0 to the contents buf_dma. This is nolonger necessary so use buf_dma directly and remove skb_dma altogether. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/desc.h | 1 - drivers/staging/vt6655/device_main.c | 3 +-- drivers/staging/vt6655/rxtx.c | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h index 758eeb2afd51..d56810133da4 100644 --- a/drivers/staging/vt6655/desc.h +++ b/drivers/staging/vt6655/desc.h @@ -256,7 +256,6 @@ typedef struct tagDEVICE_TD_INFO { void *mic_hdr; struct sk_buff *skb; unsigned char *buf; - dma_addr_t skb_dma; dma_addr_t buf_dma; dma_addr_t curr_desc; unsigned long dwReqCount; diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 695aa25e819d..89611a70d785 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -970,7 +970,6 @@ static void device_free_tx_buf(struct vnt_private *pDevice, PSTxDesc pDesc) if (skb) ieee80211_tx_status_irqsafe(pDevice->hw, skb); - pTDInfo->skb_dma = 0; pTDInfo->skb = NULL; pTDInfo->byFlags = 0; } @@ -1201,7 +1200,7 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) head_td->m_td1TD1.wReqCount = cpu_to_le16((u16)head_td->pTDInfo->dwReqCount); - head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->skb_dma); + head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->buf_dma); /* Poll Transmit the adapter */ wmb(); diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 0ffa9bf712be..82380f3ed05b 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -1202,7 +1202,6 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType, ptdCurr->pTDInfo->dwReqCount = cbReqCount; ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength; - ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma; return cbHeaderLength; } -- cgit v1.3-6-gb490 From eae6377eb01d6b8a6cb3f1047ae35829e22e4e04 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:37 +0100 Subject: staging: vt6655: Remove unused tagDEVICE_TD_INFO curr_desc The variable is assigned a value that is never used. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/desc.h | 1 - drivers/staging/vt6655/device_main.c | 2 -- 2 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h index d56810133da4..485c6fd05713 100644 --- a/drivers/staging/vt6655/desc.h +++ b/drivers/staging/vt6655/desc.h @@ -257,7 +257,6 @@ typedef struct tagDEVICE_TD_INFO { struct sk_buff *skb; unsigned char *buf; dma_addr_t buf_dma; - dma_addr_t curr_desc; unsigned long dwReqCount; unsigned long dwHeaderLength; unsigned char byFlags; diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 89611a70d785..7409ed2f3a95 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -711,7 +711,6 @@ static void device_init_td0_ring(struct vnt_private *pDevice) pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma0 + (i)*PKT_BUF_SZ; } pDesc->next = &(pDevice->apTD0Rings[(i+1) % pDevice->sOpts.nTxDescs[0]]); - pDesc->pTDInfo->curr_desc = cpu_to_le32(curr); pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc)); } @@ -737,7 +736,6 @@ static void device_init_td1_ring(struct vnt_private *pDevice) pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma1 + (i) * PKT_BUF_SZ; } pDesc->next = &(pDevice->apTD1Rings[(i + 1) % pDevice->sOpts.nTxDescs[1]]); - pDesc->pTDInfo->curr_desc = cpu_to_le32(curr); pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc)); } -- cgit v1.3-6-gb490 From 75a8eee2d71e6abe9e25a20c8e3c16c53489c90e Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:38 +0100 Subject: staging: vt6655: fix tagDEVICE_TD_INFO -> buff_addr type Should always be __le32 type Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/desc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h index 485c6fd05713..8dc53bd72983 100644 --- a/drivers/staging/vt6655/desc.h +++ b/drivers/staging/vt6655/desc.h @@ -266,7 +266,7 @@ typedef struct tagDEVICE_TD_INFO { typedef struct tagSTxDesc { volatile STDES0 m_td0TD0; volatile STDES1 m_td1TD1; - volatile u32 buff_addr; + volatile __le32 buff_addr; volatile u32 next_desc; struct tagSTxDesc *next __aligned(8); volatile PDEVICE_TD_INFO pTDInfo __aligned(8); -- cgit v1.3-6-gb490 From 5fa9d9898d370789f12af420c118159a23f166e8 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:39 +0100 Subject: staging: vt6655: fix tagSTxDesc -> next_desc type Should always be __le32 type Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/desc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h index 8dc53bd72983..26cd3e1af430 100644 --- a/drivers/staging/vt6655/desc.h +++ b/drivers/staging/vt6655/desc.h @@ -267,7 +267,7 @@ typedef struct tagSTxDesc { volatile STDES0 m_td0TD0; volatile STDES1 m_td1TD1; volatile __le32 buff_addr; - volatile u32 next_desc; + volatile __le32 next_desc; struct tagSTxDesc *next __aligned(8); volatile PDEVICE_TD_INFO pTDInfo __aligned(8); } __attribute__ ((__packed__)) -- cgit v1.3-6-gb490 From db1ade7cee35a2d22653811c67cd4d9c60c8a4ad Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:40 +0100 Subject: staging: vt6655: remove unused tagDEVICE_RD_INFO -> curr_desc variable is assigned a value that is never used. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/desc.h | 1 - drivers/staging/vt6655/device_main.c | 2 -- 2 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h index 26cd3e1af430..3302d01821a8 100644 --- a/drivers/staging/vt6655/desc.h +++ b/drivers/staging/vt6655/desc.h @@ -170,7 +170,6 @@ typedef struct tagDEVICE_RD_INFO { struct sk_buff *skb; dma_addr_t skb_dma; - dma_addr_t curr_desc; } DEVICE_RD_INFO, *PDEVICE_RD_INFO; #ifdef __BIG_ENDIAN diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 7409ed2f3a95..c82bf48499f0 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -628,7 +628,6 @@ static void device_init_rd0_ring(struct vnt_private *pDevice) dev_err(&pDevice->pcid->dev, "can not alloc rx bufs\n"); pDesc->next = &(pDevice->aRD0Ring[(i+1) % pDevice->sOpts.nRxDescs0]); - pDesc->pRDInfo->curr_desc = cpu_to_le32(curr); pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc)); } @@ -652,7 +651,6 @@ static void device_init_rd1_ring(struct vnt_private *pDevice) dev_err(&pDevice->pcid->dev, "can not alloc rx bufs\n"); pDesc->next = &(pDevice->aRD1Ring[(i+1) % pDevice->sOpts.nRxDescs1]); - pDesc->pRDInfo->curr_desc = cpu_to_le32(curr); pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc)); } -- cgit v1.3-6-gb490 From f0fb87fba09473e6b39e351c7da59b4faa9a4fcf Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:41 +0100 Subject: staging: vt6655: Fix tagSRxDesc -> buff_addr type Should always be __le32. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/desc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h index 3302d01821a8..42e005a5de9b 100644 --- a/drivers/staging/vt6655/desc.h +++ b/drivers/staging/vt6655/desc.h @@ -208,7 +208,7 @@ SRDES1; typedef struct tagSRxDesc { volatile SRDES0 m_rd0RD0; volatile SRDES1 m_rd1RD1; - volatile u32 buff_addr; + volatile __le32 buff_addr; volatile u32 next_desc; struct tagSRxDesc *next __aligned(8); volatile PDEVICE_RD_INFO pRDInfo __aligned(8); -- cgit v1.3-6-gb490 From f1e3e92135202ff3d95195393ee62808c109208c Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:42 +0100 Subject: staging: vt6655: fix tagSRxDesc -> next_desc type Should always be __le32 Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/desc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h index 42e005a5de9b..251f7bcb9bad 100644 --- a/drivers/staging/vt6655/desc.h +++ b/drivers/staging/vt6655/desc.h @@ -209,7 +209,7 @@ typedef struct tagSRxDesc { volatile SRDES0 m_rd0RD0; volatile SRDES1 m_rd1RD1; volatile __le32 buff_addr; - volatile u32 next_desc; + volatile __le32 next_desc; struct tagSRxDesc *next __aligned(8); volatile PDEVICE_RD_INFO pRDInfo __aligned(8); } __attribute__ ((__packed__)) -- cgit v1.3-6-gb490 From 7135d9a76f787f089faad0e08bdef259cb019d64 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:43 +0100 Subject: staging: vt6655: Fix wReqCount to __le16 Should be __le16 and do and correct endian conversion. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/card.c | 8 ++++---- drivers/staging/vt6655/desc.h | 6 +++--- drivers/staging/vt6655/dpc.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index df62bdc44108..ae8fd7f491a3 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -573,17 +573,17 @@ CARDvSafeResetRx( /* init state, all RD is chip's */ for (uu = 0; uu < pDevice->sOpts.nRxDescs0; uu++) { pDesc = &(pDevice->aRD0Ring[uu]); - pDesc->m_rd0RD0.wResCount = (unsigned short)(pDevice->rx_buf_sz); + pDesc->m_rd0RD0.wResCount = cpu_to_le16(pDevice->rx_buf_sz); pDesc->m_rd0RD0.f1Owner = OWNED_BY_NIC; - pDesc->m_rd1RD1.wReqCount = (unsigned short)(pDevice->rx_buf_sz); + pDesc->m_rd1RD1.wReqCount = cpu_to_le16(pDevice->rx_buf_sz); } /* init state, all RD is chip's */ for (uu = 0; uu < pDevice->sOpts.nRxDescs1; uu++) { pDesc = &(pDevice->aRD1Ring[uu]); - pDesc->m_rd0RD0.wResCount = (unsigned short)(pDevice->rx_buf_sz); + pDesc->m_rd0RD0.wResCount = cpu_to_le16(pDevice->rx_buf_sz); pDesc->m_rd0RD0.f1Owner = OWNED_BY_NIC; - pDesc->m_rd1RD1.wReqCount = (unsigned short)(pDevice->rx_buf_sz); + pDesc->m_rd1RD1.wReqCount = cpu_to_le16(pDevice->rx_buf_sz); } /* set perPkt mode */ diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h index 251f7bcb9bad..f6563d3684cd 100644 --- a/drivers/staging/vt6655/desc.h +++ b/drivers/staging/vt6655/desc.h @@ -175,7 +175,7 @@ typedef struct tagDEVICE_RD_INFO { #ifdef __BIG_ENDIAN typedef struct tagRDES0 { - volatile unsigned short wResCount; + volatile __le16 wResCount; union { volatile u16 f15Reserved; struct { @@ -190,7 +190,7 @@ SRDES0, *PSRDES0; #else typedef struct tagRDES0 { - unsigned short wResCount; + __le16 wResCount; unsigned short f15Reserved:15; unsigned short f1Owner:1; } __attribute__ ((__packed__)) @@ -199,7 +199,7 @@ SRDES0; #endif typedef struct tagRDES1 { - unsigned short wReqCount; + __le16 wReqCount; unsigned short wReserved; } __attribute__ ((__packed__)) SRDES1; diff --git a/drivers/staging/vt6655/dpc.c b/drivers/staging/vt6655/dpc.c index b25ee962558d..e14eed160a19 100644 --- a/drivers/staging/vt6655/dpc.c +++ b/drivers/staging/vt6655/dpc.c @@ -144,7 +144,7 @@ bool vnt_receive_frame(struct vnt_private *priv, PSRxDesc curr_rd) priv->rx_buf_sz, DMA_FROM_DEVICE); frame_size = le16_to_cpu(curr_rd->m_rd1RD1.wReqCount) - - cpu_to_le16(curr_rd->m_rd0RD0.wResCount); + - le16_to_cpu(curr_rd->m_rd0RD0.wResCount); if ((frame_size > 2364) || (frame_size < 33)) { /* Frame Size error drop this packet.*/ -- cgit v1.3-6-gb490 From 1cf0a47c8c4986b8fa946156a19f7b02dc303a43 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:44 +0100 Subject: staging: vt6655: fix tagTDES1 -> wReqCount type should be __le16 Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/desc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h index f6563d3684cd..2374fa5d381f 100644 --- a/drivers/staging/vt6655/desc.h +++ b/drivers/staging/vt6655/desc.h @@ -245,7 +245,7 @@ STDES0; #endif typedef struct tagTDES1 { - volatile unsigned short wReqCount; + volatile __le16 wReqCount; volatile unsigned char byTCR; volatile unsigned char byReserved; } __attribute__ ((__packed__)) -- cgit v1.3-6-gb490 From d5806c53fe7805ebf4934debbe21fc42f78840f4 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:45 +0100 Subject: staging: vt6655: always set 32 bit dma mask The device is limited to 32 bit address space. Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index c82bf48499f0..c97353bfab72 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1747,6 +1747,12 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent) return -ENODEV; } + if (dma_set_mask(&pcid->dev, DMA_BIT_MASK(32))) { + dev_err(&pcid->dev, ": Failed to set dma 32 bit mask\n"); + device_free_info(priv); + return -ENODEV; + } + INIT_WORK(&priv->interrupt_work, vnt_interrupt_work); /* do reset */ -- cgit v1.3-6-gb490 From c5c7bd269d52d1d6708053d1a8521779e98b4989 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:46 +0100 Subject: staging: vt6655: s_cbFillTxBufHead replace STxBufHead vnt_tx_fifo_head has now replaced STxBufHead Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/rxtx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 82380f3ed05b..380b879c05db 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -1088,7 +1088,7 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType, /* Set RrvTime/RTS/CTS Buffer */ - wTxBufSize = sizeof(STxBufHead); + wTxBufSize = sizeof(struct vnt_tx_fifo_head); if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {/* 802.11g packet */ if (byFBOption == AUTO_FB_NONE) { -- cgit v1.3-6-gb490 From 03c44dd62e4f947516929c3ba0734027c3a26708 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 22 Jul 2015 19:16:47 +0100 Subject: staging: vt6655: desc.h remove dead strctures Remove these unsed structures. typedef struct tagSTxSyncDesc typedef struct tagSRrvTime_atim typedef struct tagSTxBufHead typedef struct tagSBEACONCtl typedef struct tagSSecretKey typedef struct tagSKeyEntry Signed-off-by: Malcolm Priestley Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/desc.h | 59 ------------------------------------------- 1 file changed, 59 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h index 2374fa5d381f..c9162149eb61 100644 --- a/drivers/staging/vt6655/desc.h +++ b/drivers/staging/vt6655/desc.h @@ -273,27 +273,6 @@ typedef struct tagSTxDesc { STxDesc, *PSTxDesc; typedef const STxDesc *PCSTxDesc; -typedef struct tagSTxSyncDesc { - volatile STDES0 m_td0TD0; - volatile STDES1 m_td1TD1; - volatile u32 buff_addr; /* pointer to logical buffer */ - volatile u32 next_desc; /* pointer to next logical descriptor */ - volatile unsigned short m_wFIFOCtl; - volatile unsigned short m_wTimeStamp; - struct tagSTxSyncDesc *next __aligned(8); - volatile PDEVICE_TD_INFO pTDInfo __aligned(8); -} __attribute__ ((__packed__)) -STxSyncDesc, *PSTxSyncDesc; -typedef const STxSyncDesc *PCSTxSyncDesc; - -/* RsvTime buffer header */ -typedef struct tagSRrvTime_atim { - unsigned short wCTSTxRrvTime_ba; - unsigned short wTxRrvTime_a; -} __attribute__ ((__packed__)) -SRrvTime_atim, *PSRrvTime_atim; -typedef const SRrvTime_atim *PCSRrvTime_atim; - /* Length, Service, and Signal fields of Phy for Tx */ struct vnt_phy_field { u8 signal; @@ -307,42 +286,4 @@ union vnt_phy_field_swap { u32 field_write; }; -/* Tx FIFO header */ -typedef struct tagSTxBufHead { - u32 adwTxKey[4]; - unsigned short wFIFOCtl; - unsigned short wTimeStamp; - unsigned short wFragCtl; - unsigned char byTxPower; - unsigned char wReserved; -} __attribute__ ((__packed__)) -STxBufHead, *PSTxBufHead; -typedef const STxBufHead *PCSTxBufHead; - -typedef struct tagSBEACONCtl { - u32 BufReady:1; - u32 TSF:15; - u32 BufLen:11; - u32 Reserved:5; -} __attribute__ ((__packed__)) -SBEACONCtl; - -typedef struct tagSSecretKey { - u32 dwLowDword; - unsigned char byHighByte; -} __attribute__ ((__packed__)) -SSecretKey; - -typedef struct tagSKeyEntry { - unsigned char abyAddrHi[2]; - unsigned short wKCTL; - unsigned char abyAddrLo[4]; - u32 dwKey0[4]; - u32 dwKey1[4]; - u32 dwKey2[4]; - u32 dwKey3[4]; - u32 dwKey4[4]; -} __attribute__ ((__packed__)) -SKeyEntry; - #endif /* __DESC_H__ */ -- cgit v1.3-6-gb490 From d258bf054a446c77a9cb7fa31dc4518ba2f1861d Mon Sep 17 00:00:00 2001 From: Chandra S Gorentla Date: Mon, 20 Jul 2015 16:53:15 +0530 Subject: staging: comedi: drivers: pcl816.c remove leading space Checkpatch.pl warning - suspect code indent for conditional statements - is corrected Signed-off-by: Chandra S Gorentla Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/pcl816.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index 781b321587dc..a353d1b155bb 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -305,7 +305,7 @@ static int check_channel_list(struct comedi_device *dev, chansegment[0] = chanlist[0]; for (i = 1, seglen = 1; i < chanlen; i++, seglen++) { /* we detect loop, this must by finish */ - if (chanlist[0] == chanlist[i]) + if (chanlist[0] == chanlist[i]) break; nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % chanlen; -- cgit v1.3-6-gb490 From e73063c5407b6ffe09dc0f7c11970113bf55e6fc Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 22 Jul 2015 18:45:55 +0100 Subject: staging/comedi/drivers/usbduxsigma.c: updated address details Changed my e-mail address to mail@berndporr.me.uk. The old one is no longer used. Signed-off-by: Bernd Porr Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbduxsigma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index eaa9add491df..2c27eb2bc2f5 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -1653,7 +1653,7 @@ static struct usb_driver usbduxsigma_usb_driver = { }; module_comedi_usb_driver(usbduxsigma_driver, usbduxsigma_usb_driver); -MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com"); -MODULE_DESCRIPTION("Stirling/ITL USB-DUX SIGMA -- Bernd.Porr@f2s.com"); +MODULE_AUTHOR("Bernd Porr, mail@berndporr.me.uk"); +MODULE_DESCRIPTION("Stirling/ITL USB-DUX SIGMA -- mail@berndporr.me.uk"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(FIRMWARE); -- cgit v1.3-6-gb490 From d5a372df8661113b8aa36f4eb29d4b969d1d3db4 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 22 Jul 2015 18:46:39 +0100 Subject: staging/comedi/drivers/usbduxsigma.c: added support for ehci drivers urb->interval is deprecated and thus I've changed the driver that it now always assumes interval=1 which means every frame in USB 1.1 and every uframe in USB 2.0. However we still need to have different sampling rates which are still multiples of the interval which is now transmitted to the firmware. The firmware transmits either zero length packets or none every (u)frame. This is checked in the completion handler and any packet at zero length is discarded so that comedi again sees the data coming in at the interval specified. This also then gives the ADC the necessary time to convert. For example 16 channels require about 700us and in this period no packet could be transmitted. In this case this is padded up to 1ms so that we have then 7 zero length packets and one packet with the ADC data. Signed-off-by: Bernd Porr Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbduxsigma.c | 71 ++++++++++++++-------------- 1 file changed, 35 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 2c27eb2bc2f5..51846adf8340 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -1,6 +1,6 @@ /* * usbduxsigma.c - * Copyright (C) 2011-2014 Bernd Porr, mail@berndporr.me.uk + * Copyright (C) 2011-2015 Bernd Porr, mail@berndporr.me.uk * * 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 @@ -18,7 +18,7 @@ * Description: University of Stirling USB DAQ & INCITE Technology Limited * Devices: [ITL] USB-DUX-SIGMA (usbduxsigma) * Author: Bernd Porr - * Updated: 10 Oct 2014 + * Updated: 20 July 2015 * Status: stable */ @@ -39,6 +39,7 @@ * 0.4: fixed D/A voltage range * 0.5: various bug fixes, health check at startup * 0.6: corrected wrong input range + * 0.7: rewrite code that urb->interval is always 1 */ #include @@ -122,7 +123,7 @@ #define RETRIES 10 /* bulk transfer commands to usbduxsigma */ -#define USBBUXSIGMA_AD_CMD 0 +#define USBBUXSIGMA_AD_CMD 9 #define USBDUXSIGMA_DA_CMD 1 #define USBDUXSIGMA_DIO_CFG_CMD 2 #define USBDUXSIGMA_DIO_BITS_CMD 3 @@ -217,24 +218,28 @@ static void usbduxsigma_ai_handle_urb(struct comedi_device *dev, int ret; int i; - devpriv->ai_counter--; - if (devpriv->ai_counter == 0) { - devpriv->ai_counter = devpriv->ai_timer; - - /* get the data from the USB bus and hand it over to comedi */ - for (i = 0; i < cmd->chanlist_len; i++) { - /* transfer data, note first byte is the DIO state */ - val = be32_to_cpu(devpriv->in_buf[i+1]); - val &= 0x00ffffff; /* strip status byte */ - val ^= 0x00800000; /* convert to unsigned */ + if ((urb->actual_length > 0) && (urb->status != -EXDEV)) { + devpriv->ai_counter--; + if (devpriv->ai_counter == 0) { + devpriv->ai_counter = devpriv->ai_timer; + + /* get the data from the USB bus + and hand it over to comedi */ + for (i = 0; i < cmd->chanlist_len; i++) { + /* transfer data, + note first byte is the DIO state */ + val = be32_to_cpu(devpriv->in_buf[i+1]); + val &= 0x00ffffff; /* strip status byte */ + val ^= 0x00800000; /* convert to unsigned */ + + if (!comedi_buf_write_samples(s, &val, 1)) + return; + } - if (!comedi_buf_write_samples(s, &val, 1)) - return; + if (cmd->stop_src == TRIG_COUNT && + async->scans_done >= cmd->stop_arg) + async->events |= COMEDI_CB_EOA; } - - if (cmd->stop_src == TRIG_COUNT && - async->scans_done >= cmd->stop_arg) - async->events |= COMEDI_CB_EOA; } /* if command is still running, resubmit urb */ @@ -374,10 +379,7 @@ static void usbduxsigma_ao_handle_urb(struct comedi_device *dev, urb->transfer_buffer_length = SIZEOUTBUF; urb->dev = comedi_to_usb_dev(dev); urb->status = 0; - if (devpriv->high_speed) - urb->interval = 8; /* uframes */ - else - urb->interval = 1; /* frames */ + urb->interval = 1; /* (u)frames */ urb->number_of_packets = 1; urb->iso_frame_desc[0].offset = 0; urb->iso_frame_desc[0].length = SIZEOUTBUF; @@ -441,7 +443,6 @@ static int usbduxsigma_submit_urbs(struct comedi_device *dev, int input_urb) { struct usb_device *usb = comedi_to_usb_dev(dev); - struct usbduxsigma_private *devpriv = dev->private; struct urb *urb; int ret; int i; @@ -452,7 +453,7 @@ static int usbduxsigma_submit_urbs(struct comedi_device *dev, /* in case of a resubmission after an unlink... */ if (input_urb) - urb->interval = devpriv->ai_interval; + urb->interval = 1; urb->context = dev; urb->dev = usb; urb->status = 0; @@ -674,13 +675,14 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev, create_adc_command(chan, &muxsg0, &muxsg1); } - devpriv->dux_commands[1] = len; /* num channels per time step */ - devpriv->dux_commands[2] = 0x12; /* CONFIG0 */ - devpriv->dux_commands[3] = 0x03; /* CONFIG1: 23kHz sample, delay 0us */ - devpriv->dux_commands[4] = 0x00; /* CONFIG3: diff. channels off */ - devpriv->dux_commands[5] = muxsg0; - devpriv->dux_commands[6] = muxsg1; - devpriv->dux_commands[7] = sysred; + devpriv->dux_commands[1] = devpriv->ai_interval; + devpriv->dux_commands[2] = len; /* num channels per time step */ + devpriv->dux_commands[3] = 0x12; /* CONFIG0 */ + devpriv->dux_commands[4] = 0x03; /* CONFIG1: 23kHz sample, delay 0us */ + devpriv->dux_commands[5] = 0x00; /* CONFIG3: diff. channels off */ + devpriv->dux_commands[6] = muxsg0; + devpriv->dux_commands[7] = muxsg1; + devpriv->dux_commands[8] = sysred; ret = usbbuxsigma_send_cmd(dev, USBBUXSIGMA_AD_CMD); if (ret < 0) { @@ -1427,10 +1429,7 @@ static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev) urb->transfer_buffer_length = SIZEOUTBUF; urb->iso_frame_desc[0].offset = 0; urb->iso_frame_desc[0].length = SIZEOUTBUF; - if (devpriv->high_speed) - urb->interval = 8; /* uframes */ - else - urb->interval = 1; /* frames */ + urb->interval = 1; /* (u)frames */ } if (devpriv->pwm_buf_sz) { -- cgit v1.3-6-gb490 From 9d7a0ffe6d83fcafac7825fe589f856a772f7389 Mon Sep 17 00:00:00 2001 From: Aaron Ouellette Date: Thu, 16 Jul 2015 21:21:16 -0400 Subject: staging: sm750fb: removed extra parentheses fixed checkpatch.pl error: ERROR: return is not a function, parentheses are not needed Signed-off-by: Aaron Ouellette Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_power.c b/drivers/staging/sm750fb/ddk750_power.c index c8c51be53d68..3c04447f0283 100644 --- a/drivers/staging/sm750fb/ddk750_power.c +++ b/drivers/staging/sm750fb/ddk750_power.c @@ -20,7 +20,7 @@ unsigned int getPowerMode(void) { if (getChipType() == SM750LE) return 0; - return (FIELD_GET(PEEK32(POWER_MODE_CTRL), POWER_MODE_CTRL, MODE)); + return FIELD_GET(PEEK32(POWER_MODE_CTRL), POWER_MODE_CTRL, MODE); } -- cgit v1.3-6-gb490 From 9a2c874c51df5ed29d482b5294541f06a6f24328 Mon Sep 17 00:00:00 2001 From: Antoine BLIN Date: Fri, 17 Jul 2015 15:04:34 +0200 Subject: staging: sm750fb: ddk750_power.c: Split lines over 80 characters. Fix up "line over 80 characters" warning found by the checkpatch.pl script. Signed-off-by: Antoine BLIN Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_power.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/ddk750_power.c b/drivers/staging/sm750fb/ddk750_power.c index 3c04447f0283..e580dab2b625 100644 --- a/drivers/staging/sm750fb/ddk750_power.c +++ b/drivers/staging/sm750fb/ddk750_power.c @@ -8,7 +8,8 @@ void ddk750_setDPMS(DPMS_t state) if (getChipType() == SM750LE) { value = PEEK32(CRT_DISPLAY_CTRL); - POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(value, CRT_DISPLAY_CTRL, DPMS, state)); + POKE32(CRT_DISPLAY_CTRL, FIELD_VALUE(value, CRT_DISPLAY_CTRL, + DPMS, state)); } else { value = PEEK32(SYSTEM_CTRL); value = FIELD_VALUE(value, SYSTEM_CTRL, DPMS, state); @@ -39,15 +40,18 @@ void setPowerMode(unsigned int powerMode) switch (powerMode) { case POWER_MODE_CTRL_MODE_MODE0: - control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE0); + control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, + MODE0); break; case POWER_MODE_CTRL_MODE_MODE1: - control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, MODE1); + control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, + MODE1); break; case POWER_MODE_CTRL_MODE_SLEEP: - control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, SLEEP); + control_value = FIELD_SET(control_value, POWER_MODE_CTRL, MODE, + SLEEP); break; default: @@ -138,8 +142,9 @@ void enableZVPort(unsigned int enable) gate = FIELD_SET(gate, CURRENT_GATE, I2C, ON); #endif } else { - /* Disable ZV Port Gate. There is no way to know whether the GPIO pins are being used - or not. Therefore, do not disable the GPIO gate. */ + /* Disable ZV Port Gate. There is no way to know whether the + GPIO pins are being used or not. Therefore, do not disable the + GPIO gate. */ gate = FIELD_SET(gate, CURRENT_GATE, ZVPORT, OFF); } -- cgit v1.3-6-gb490 From 8da24c93327037a6fb1f760f5fc70e33c9abaefb Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 21 Jul 2015 18:57:24 +0530 Subject: staging: rtl8188eu: remove unused define _HCI_INTF_C_ was only defined here but not being used anywhere. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 5490b2905075..f6c6f4a9982c 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -17,7 +17,6 @@ * * ******************************************************************************/ -#define _HCI_INTF_C_ #define pr_fmt(fmt) "R8188EU: " fmt #include -- cgit v1.3-6-gb490 From 586b06328c16c04a7040c92b7a13aea0447e35ec Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 21 Jul 2015 18:57:25 +0530 Subject: staging: rtl8188eu: remove label Directly return NULL instead of using another label and goto. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index f6c6f4a9982c..09a918ec6e10 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -66,7 +66,7 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) pdvobjpriv = kzalloc(sizeof(*pdvobjpriv), GFP_KERNEL); if (pdvobjpriv == NULL) - goto exit; + return NULL; pdvobjpriv->pusbintf = usb_intf; pusbd = interface_to_usbdev(usb_intf); @@ -121,7 +121,7 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) kfree(pdvobjpriv); pdvobjpriv = NULL; } -exit: + return pdvobjpriv; } -- cgit v1.3-6-gb490 From 705a31369845d7ad522dc9bce6ca430831ff0454 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 21 Jul 2015 18:57:26 +0530 Subject: staging: rtl8188eu: check for kzalloc failure Check for kzalloc failure and directly return from the error patch thus simplifying the success path. Suggested-by: Dan Carpenter Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 09a918ec6e10..1c9558ff1c19 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -114,13 +114,12 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) mutex_init(&pdvobjpriv->usb_vendor_req_mutex); pdvobjpriv->usb_vendor_req_buf = kzalloc(MAX_USB_IO_CTL_SIZE, GFP_KERNEL); - if (pdvobjpriv->usb_vendor_req_buf) { - usb_get_dev(pusbd); - } else { + if (!pdvobjpriv->usb_vendor_req_buf) { usb_set_intfdata(usb_intf, NULL); kfree(pdvobjpriv); - pdvobjpriv = NULL; + return NULL; } + usb_get_dev(pusbd); return pdvobjpriv; } -- cgit v1.3-6-gb490 From e0732f84b40bc7219d077ddd69b5cc03ec6e7838 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 21 Jul 2015 18:57:27 +0530 Subject: staging: rtl8188eu: dont mix success and error path Success and error path was mixed. Separate them by directly returning 0 from the success path. In the process remove the variable which became unused. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 1c9558ff1c19..29b7ea6dc16d 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -474,7 +474,6 @@ static void rtw_usb_if1_deinit(struct adapter *if1) static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *pdid) { struct adapter *if1 = NULL; - int status = _FAIL; struct dvobj_priv *dvobj; RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_init\n")); @@ -495,13 +494,12 @@ static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-871x_drv - drv_init, success!\n")); - status = _SUCCESS; + return 0; free_dvobj: - if (status != _SUCCESS) - usb_dvobj_deinit(pusb_intf); + usb_dvobj_deinit(pusb_intf); exit: - return status == _SUCCESS ? 0 : -ENODEV; + return -ENODEV; } /* -- cgit v1.3-6-gb490 From 0a32bd33ed3e03258e255a5b580ce7b3f514763e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 21 Jul 2015 18:57:28 +0530 Subject: staging: rtl8188eu: remove multiple blank line Multiple blank lines should be avoided. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 29b7ea6dc16d..5f44c6a5b777 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -63,7 +63,6 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf) struct usb_endpoint_descriptor *pendp_desc; struct usb_device *pusbd; - pdvobjpriv = kzalloc(sizeof(*pdvobjpriv), GFP_KERNEL); if (pdvobjpriv == NULL) return NULL; @@ -128,7 +127,6 @@ static void usb_dvobj_deinit(struct usb_interface *usb_intf) { struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf); - usb_set_intfdata(usb_intf, NULL); if (dvobj) { /* Modify condition for 92DU DMDP 2010.11.18, by Thomas */ @@ -326,7 +324,6 @@ exit: pr_debug("<=== %s return %d.............. in %dms\n", __func__, ret, rtw_get_passing_time_ms(start_time)); - return ret; } @@ -511,7 +508,6 @@ static void rtw_dev_remove(struct usb_interface *pusb_intf) struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf); struct adapter *padapter = dvobj->if1; - pr_debug("+rtw_dev_remove\n"); RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+dev_remove()\n")); -- cgit v1.3-6-gb490 From 047db9915ed576e817eb02c1d1cf037c49856b59 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 19 Jul 2015 13:52:17 +0300 Subject: Staging: rtl8192u: pointer math bug in ieee80211_rx_DELBA() Smatch complains because "delba" is a pointer to struct rtl_80211_hdr_3addr so the "delba += sizeof(struct rtl_80211_hdr_3addr);" is clearly wrong. We are reading nonsense data from beyond the end of the buffer and could oops if that memory isn't mapped. It turns out the next two statements are also wrong. We should delete the += sizeof() statement and "delba+2" should be "&delba->payload[2]". "pReasonCode" isn't used so I deleted that. With-Fix-From: Mateusz Kulikowski Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c index 9ff8e056ab7f..d4215fd5a856 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c @@ -571,7 +571,6 @@ int ieee80211_rx_DELBA(struct ieee80211_device *ieee, struct sk_buff *skb) { struct rtl_80211_hdr_3addr *delba = NULL; PDELBA_PARAM_SET pDelBaParamSet = NULL; - u16 *pReasonCode = NULL; u8 *dst = NULL; if (skb->len < sizeof(struct rtl_80211_hdr_3addr) + 6) { @@ -592,9 +591,7 @@ int ieee80211_rx_DELBA(struct ieee80211_device *ieee, struct sk_buff *skb) IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len); delba = (struct rtl_80211_hdr_3addr *)skb->data; dst = (u8 *)(&delba->addr2[0]); - delba += sizeof(struct rtl_80211_hdr_3addr); - pDelBaParamSet = (PDELBA_PARAM_SET)(delba+2); - pReasonCode = (u16 *)(delba+4); + pDelBaParamSet = (PDELBA_PARAM_SET)&delba->payload[2]; if(pDelBaParamSet->field.Initiator == 1) { -- cgit v1.3-6-gb490 From f9bd549aa99a12e42b8811efa3cb7d8c3d084a20 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 20 Jul 2015 18:35:42 +0200 Subject: staging: rtl8192u: remove bool comparisons Remove explicit true/false comparisons to bool variables. Signed-off-by: Luis de Bethencourt Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c | 4 ++-- drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c | 2 +- drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c | 4 ++-- drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c | 12 ++++++------ drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c | 14 +++++++------- drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c | 2 +- drivers/staging/rtl8192u/r8192U_core.c | 7 ++++--- drivers/staging/rtl8192u/r8192U_dm.c | 8 ++++---- 8 files changed, 27 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index b374088c5ff8..0aa9021cb95e 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -1014,7 +1014,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, goto rx_dropped; // if QoS enabled, should check the sequence for each of the AC - if( (ieee->pHTInfo->bCurRxReorderEnable == false) || !ieee->current_network.qos_data.active|| !IsDataFrame(skb->data) || IsLegacyDataFrame(skb->data)){ + if ((!ieee->pHTInfo->bCurRxReorderEnable) || !ieee->current_network.qos_data.active|| !IsDataFrame(skb->data) || IsLegacyDataFrame(skb->data)) { if (is_duplicate_packet(ieee, hdr)) goto rx_dropped; @@ -1307,7 +1307,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, } //added by amy for reorder - if(ieee->pHTInfo->bCurRxReorderEnable == false ||pTS == NULL){ + if (!ieee->pHTInfo->bCurRxReorderEnable || pTS == NULL){ //added by amy for reorder for(i = 0; inr_subframes; i++) { struct sk_buff *sub_skb = rxb->subframes[i]; diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index a1f9d42833e0..39e9892c3fa6 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -1964,7 +1964,7 @@ static void ieee80211_check_auth_response(struct ieee80211_device *ieee, } if (ieee->current_network.mode == IEEE_N_24G && - bHalfSupportNmode == true) { + bHalfSupportNmode) { netdev_dbg(ieee->dev, "enter half N mode\n"); ieee->bHalfWirelessN24GMode = true; } else diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c index 5353a45ffdff..fff8d583c62f 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c @@ -336,12 +336,12 @@ static void ieee80211_tx_query_agg_cap(struct ieee80211_device *ieee, printk("===>can't get TS\n"); return; } - if (pTxTs->TxAdmittedBARecord.bValid == false) + if (!pTxTs->TxAdmittedBARecord.bValid) { TsStartAddBaProcess(ieee, pTxTs); goto FORCED_AGG_SETTING; } - else if (pTxTs->bUsingBa == false) + else if (!pTxTs->bUsingBa) { if (SN_LESS(pTxTs->TxAdmittedBARecord.BaStartSeqCtrl.field.SeqNum, (pTxTs->TxCurSeq+1)%4096)) pTxTs->bUsingBa = true; diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c index d4215fd5a856..3bde744604c2 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c @@ -364,8 +364,8 @@ int ieee80211_rx_ADDBAReq(struct ieee80211_device *ieee, struct sk_buff *skb) printk("====================>rx ADDBAREQ from :%pM\n", dst); //some other capability is not ready now. if ((ieee->current_network.qos_data.active == 0) || - (ieee->pHTInfo->bCurrentHTSupport == false)) //|| - // (ieee->pStaQos->bEnableRxImmBA == false) ) + (!ieee->pHTInfo->bCurrentHTSupport)) //|| + // (!ieee->pStaQos->bEnableRxImmBA) ) { rc = ADDBA_STATUS_REFUSED; IEEE80211_DEBUG(IEEE80211_DL_ERR, "Failed to reply on ADDBA_REQ as some capability is not ready(%d, %d)\n", ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport); @@ -462,8 +462,8 @@ int ieee80211_rx_ADDBARsp(struct ieee80211_device *ieee, struct sk_buff *skb) // Check the capability // Since we can always receive A-MPDU, we just check if it is under HT mode. if (ieee->current_network.qos_data.active == 0 || - ieee->pHTInfo->bCurrentHTSupport == false || - ieee->pHTInfo->bCurrentAMPDUEnable == false) { + !ieee->pHTInfo->bCurrentHTSupport || + !ieee->pHTInfo->bCurrentAMPDUEnable) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "reject to ADDBA_RSP as some capability is not ready(%d, %d, %d)\n",ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport, ieee->pHTInfo->bCurrentAMPDUEnable); ReasonCode = DELBA_REASON_UNKNOWN_BA; goto OnADDBARsp_Reject; @@ -502,7 +502,7 @@ int ieee80211_rx_ADDBARsp(struct ieee80211_device *ieee, struct sk_buff *skb) IEEE80211_DEBUG(IEEE80211_DL_BA, "OnADDBARsp(): Recv ADDBA Rsp. Drop because already admit it! \n"); return -1; } - else if((pPendingBA->bValid == false) ||(*pDialogToken != pPendingBA->DialogToken)) + else if((!pPendingBA->bValid) ||(*pDialogToken != pPendingBA->DialogToken)) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "OnADDBARsp(): Recv ADDBA Rsp. BA invalid, DELBA! \n"); ReasonCode = DELBA_REASON_UNKNOWN_BA; @@ -582,7 +582,7 @@ int ieee80211_rx_DELBA(struct ieee80211_device *ieee, struct sk_buff *skb) } if (ieee->current_network.qos_data.active == 0 || - ieee->pHTInfo->bCurrentHTSupport == false ) + !ieee->pHTInfo->bCurrentHTSupport) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "received DELBA while QOS or HT is not supported(%d, %d)\n",ieee->current_network.qos_data.active, ieee->pHTInfo->bCurrentHTSupport); return -1; diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c index 80411c93d8fa..c27397b14adb 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c @@ -224,9 +224,9 @@ static bool IsHTHalfNmode40Bandwidth(struct ieee80211_device *ieee) bool retValue = false; PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; - if(pHTInfo->bCurrentHTSupport == false ) // wireless is n mode + if(!pHTInfo->bCurrentHTSupport) // wireless is n mode retValue = false; - else if(pHTInfo->bRegBW40MHz == false) // station supports 40 bw + else if(!pHTInfo->bRegBW40MHz) // station supports 40 bw retValue = false; else if(!ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) // station in half n mode retValue = false; @@ -243,7 +243,7 @@ static bool IsHTHalfNmodeSGI(struct ieee80211_device *ieee, bool is40MHz) bool retValue = false; PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; - if(pHTInfo->bCurrentHTSupport == false ) // wireless is n mode + if(!pHTInfo->bCurrentHTSupport) // wireless is n mode retValue = false; else if(!ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) // station in half n mode retValue = false; @@ -675,7 +675,7 @@ void HTConstructInfoElement(struct ieee80211_device *ieee, u8 *posHTInfo, u8 *le if ( (ieee->iw_mode == IW_MODE_ADHOC) || (ieee->iw_mode == IW_MODE_MASTER)) //ap mode is not currently supported { pHTInfoEle->ControlChl = ieee->current_network.channel; - pHTInfoEle->ExtChlOffset = ((pHT->bRegBW40MHz == false)?HT_EXTCHNL_OFFSET_NO_EXT: + pHTInfoEle->ExtChlOffset = ((!pHT->bRegBW40MHz)?HT_EXTCHNL_OFFSET_NO_EXT: (ieee->current_network.channel<=6)? HT_EXTCHNL_OFFSET_UPPER:HT_EXTCHNL_OFFSET_LOWER); pHTInfoEle->RecommemdedTxWidth = pHT->bRegBW40MHz; @@ -945,7 +945,7 @@ void HTOnAssocRsp(struct ieee80211_device *ieee) static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33}; // For 11n EWC definition, 2007.07.17, by Emily static u8 EWC11NHTInfo[] = {0x00, 0x90, 0x4c, 0x34}; // For 11n EWC definition, 2007.07.17, by Emily - if (pHTInfo->bCurrentHTSupport == false) { + if (!pHTInfo->bCurrentHTSupport) { IEEE80211_DEBUG(IEEE80211_DL_ERR, "<=== HTOnAssocRsp(): HT_DISABLE\n"); return; } @@ -976,7 +976,7 @@ void HTOnAssocRsp(struct ieee80211_device *ieee) // HTSetConnectBwMode(ieee, (HT_CHANNEL_WIDTH)(pPeerHTCap->ChlWidth), (HT_EXTCHNL_OFFSET)(pPeerHTInfo->ExtChlOffset)); -// if(pHTInfo->bCurBW40MHz == true) +// if (pHTInfo->bCurBW40MHz) pHTInfo->bCurTxBW40MHz = ((pPeerHTInfo->RecommemdedTxWidth == 1)?true:false); // @@ -1341,7 +1341,7 @@ void HTSetConnectBwMode(struct ieee80211_device *ieee, HT_CHANNEL_WIDTH Bandwidt PRT_HIGH_THROUGHPUT pHTInfo = ieee->pHTInfo; // u32 flags = 0; - if(pHTInfo->bRegBW40MHz == false) + if(!pHTInfo->bRegBW40MHz) return; diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c index b89105dbcbba..f33c74342cf3 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c @@ -584,7 +584,7 @@ void RemoveAllTS(struct ieee80211_device *ieee) void TsStartAddBaProcess(struct ieee80211_device *ieee, PTX_TS_RECORD pTxTS) { - if(pTxTS->bAddBaReqInProgress == false) + if(!pTxTS->bAddBaReqInProgress) { pTxTS->bAddBaReqInProgress = true; if(pTxTS->bAddBaReqDelayed) diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index b852396d21e6..dd74813d48f3 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -2047,7 +2047,7 @@ static bool GetHalfNmodeSupportByAPs819xUsb(struct net_device *dev) struct r8192_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee80211; - if (ieee->bHalfWirelessN24GMode == true) + if (ieee->bHalfWirelessN24GMode) Reval = true; else Reval = false; @@ -2762,7 +2762,7 @@ static bool rtl8192_adapter_start(struct net_device *dev) // #ifdef TO_DO_LIST if (Adapter->ResetProgress == RESET_TYPE_NORESET) { - if (pMgntInfo->RegRfOff == true) { /* User disable RF via registry. */ + if (pMgntInfo->RegRfOff) { /* User disable RF via registry. */ RT_TRACE((COMP_INIT|COMP_RF), DBG_LOUD, ("InitializeAdapter819xUsb(): Turn off RF for RegRfOff ----------\n")); MgntActSet_RF_State(Adapter, eRfOff, RF_CHANGE_BY_SW); // Those actions will be discard in MgntActSet_RF_State because of the same state @@ -4406,7 +4406,8 @@ static void query_rxdesc_status(struct sk_buff *skb, /* RTL8190 set this bit to indicate that Hw does not decrypt packet */ stats->Decrypted = !desc->SWDec; - if ((priv->ieee80211->pHTInfo->bCurrentHTSupport == true) && (priv->ieee80211->pairwise_key_type == KEY_TYPE_CCMP)) + if ((priv->ieee80211->pHTInfo->bCurrentHTSupport) && + (priv->ieee80211->pairwise_key_type == KEY_TYPE_CCMP)) stats->bHwError = false; else stats->bHwError = stats->bCRC|stats->bICV; diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c index 7ca5d8fbc57f..5277f2eec033 100644 --- a/drivers/staging/rtl8192u/r8192U_dm.c +++ b/drivers/staging/rtl8192u/r8192U_dm.c @@ -438,7 +438,7 @@ static void dm_bandwidth_autoswitch(struct net_device *dev) if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 || !priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable) return; - if (priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz == false) { /* If send packets in 40 Mhz in 20/40 */ + if (!priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz) { /* If send packets in 40 Mhz in 20/40 */ if (priv->undecorated_smoothed_pwdb <= priv->ieee80211->bandwidth_auto_switch.threshold_40Mhzto20Mhz) priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = true; } else { /* in force send packets in 20 Mhz in 20/40 */ @@ -1731,7 +1731,7 @@ static void dm_dig_init(struct net_device *dev) *---------------------------------------------------------------------------*/ static void dm_ctrl_initgain_byrssi(struct net_device *dev) { - if (dm_digtable.dig_enable_flag == false) + if (!dm_digtable.dig_enable_flag) return; if (dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) @@ -1750,7 +1750,7 @@ static void dm_ctrl_initgain_byrssi_by_driverrssi( u8 i; static u8 fw_dig; - if (dm_digtable.dig_enable_flag == false) + if (!dm_digtable.dig_enable_flag) return; /*DbgPrint("Dig by Sw Rssi\n");*/ @@ -1792,7 +1792,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( static u32 reset_cnt; u8 i; - if (dm_digtable.dig_enable_flag == false) + if (!dm_digtable.dig_enable_flag) return; if (dm_digtable.dig_algorithm_switch) { -- cgit v1.3-6-gb490 From 2ee4c3dc55f6b83934cdf53c8563f5667d91ff91 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 20 Jul 2015 18:36:18 +0200 Subject: staging: rtl8192u: remove unneeded bool bool Reval is set to match the value of bHalfWirelessN24GMode just to this. The value can be returned directly. Removing uneeded bool. Signed-off-by: Luis de Bethencourt Suggested-by: Joe Perches Suggested-by: Franks Klaver Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/r8192U_core.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index dd74813d48f3..6f6fe38081bc 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -2043,16 +2043,9 @@ static bool GetNmodeSupportBySecCfg8192(struct net_device *dev) static bool GetHalfNmodeSupportByAPs819xUsb(struct net_device *dev) { - bool Reval; struct r8192_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee80211; - - if (ieee->bHalfWirelessN24GMode) - Reval = true; - else - Reval = false; - return Reval; + return priv->ieee80211->bHalfWirelessN24GMode; } static void rtl8192_refresh_supportrate(struct r8192_priv *priv) -- cgit v1.3-6-gb490 From d0dcaa8d4eff40b2999d5265f2218c29e82e24cc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 19 Jul 2015 13:52:33 +0300 Subject: Staging: rtl8192e: pointer math bug in rtllib_rx_DELBA() The pointer math here was totally wrong so we were reading nonsense information from beyond the end of the buffer. It could lead to an oops if that memory wasn't mapped. The "pReasonCode" pointer is assigned but never used so I deleted it. With-Fix-From: Mateusz Kulikowski Signed-off-by: Dan Carpenter Acked-by: Mateusz Kulikowski Tested-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl819x_BAProc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl819x_BAProc.c b/drivers/staging/rtl8192e/rtl819x_BAProc.c index 60f536c295ab..78ede4a817fc 100644 --- a/drivers/staging/rtl8192e/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192e/rtl819x_BAProc.c @@ -428,7 +428,6 @@ int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb) { struct rtllib_hdr_3addr *delba = NULL; union delba_param_set *pDelBaParamSet = NULL; - u16 *pReasonCode = NULL; u8 *dst = NULL; if (skb->len < sizeof(struct rtllib_hdr_3addr) + 6) { @@ -453,9 +452,7 @@ int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb) #endif delba = (struct rtllib_hdr_3addr *)skb->data; dst = (u8 *)(&delba->addr2[0]); - delba += sizeof(struct rtllib_hdr_3addr); - pDelBaParamSet = (union delba_param_set *)(delba+2); - pReasonCode = (u16 *)(delba+4); + pDelBaParamSet = (union delba_param_set *)&delba->payload[2]; if (pDelBaParamSet->field.Initiator == 1) { struct rx_ts_record *pRxTs; -- cgit v1.3-6-gb490 From b20691652b8c09992096490d9dd11319c1e7ce5e Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Thu, 16 Jul 2015 12:50:50 -0500 Subject: staging: fsl-mc: update TODO list update TODO list to provide more detail on remaining work Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fsl-mc/TODO | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/fsl-mc/TODO b/drivers/staging/fsl-mc/TODO index d78288b4e721..c29516b4b9b6 100644 --- a/drivers/staging/fsl-mc/TODO +++ b/drivers/staging/fsl-mc/TODO @@ -6,8 +6,30 @@ and if so add support for this. * Add at least one device driver for a DPAA2 object (child device of the - fsl-mc bus). + fsl-mc bus). Most likely candidate for this is adding DPAA2 Ethernet + driver support, which depends on drivers for several objects: DPNI, + DPIO, DPMAC. Other pre-requisites include: + + * interrupt support. for meaningful driver support we need + interrupts, and thus need message interrupt support by the bus + driver. + -Note: this has dependencies on generic MSI support work + in process upstream, see [1] and [2]. + + * Management Complex (MC) command serialization. locking mechanisms + are needed by drivers to serialize commands sent to the MC, including + from atomic context. + + * MC firmware uprev. The MC firmware upon which the fsl-mc + bus driver and DPAA2 object drivers are based is continuing + to evolve, so minor updates are needed to keep in sync with binary + interface changes to the MC. + +* Cleanup Please send any patches to Greg Kroah-Hartman , german.rivera@freescale.com, devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org + +[1] https://lkml.org/lkml/2015/7/9/93 +[2] https://lkml.org/lkml/2015/7/7/712 -- cgit v1.3-6-gb490 From 56fa2ece881348d314800b858581f2ae950f8e20 Mon Sep 17 00:00:00 2001 From: "Jon Medhurst (Tixy)" Date: Fri, 17 Jul 2015 12:01:29 +0100 Subject: staging: ion: ion_cma_heap: Don't directly use dma_common_get_sgtable Use dma_get_sgtable rather than dma_common_get_sgtable so a device's dma_ops aren't bypassed. This is essential in situations where a device uses an IOMMU and the physical memory is not contiguous (as the common function assumes). Signed-off-by: Jon Medhurst Reviewed-by: Robin Murphy Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion_cma_heap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index f4211f1be488..86b91fd53852 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -73,8 +73,7 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, if (!info->table) goto free_mem; - if (dma_common_get_sgtable - (dev, info->table, info->cpu_addr, info->handle, len)) + if (dma_get_sgtable(dev, info->table, info->cpu_addr, info->handle, len)) goto free_table; /* keep this for memory release */ buffer->priv_virt = info; -- cgit v1.3-6-gb490 From 80a60777d7e60e59e4deb756dc0e3989fe520f84 Mon Sep 17 00:00:00 2001 From: Steve Pennington Date: Wed, 22 Jul 2015 12:50:11 -0500 Subject: staging: rtl8723au: fix incorrect type in assignment warning Repaced calls to htons and memcpy with a single call to put_unaligned_be16 to fix the following sparse warning: drivers/staging/rtl8723au/core/rtw_recv.c:1557:21: warning: incorrect type in assignment (different base types) drivers/staging/rtl8723au/core/rtw_recv.c:1557:21: expected unsigned short [unsigned] [assigned] [usertype] len drivers/staging/rtl8723au/core/rtw_recv.c:1557:21: got restricted __be16 [usertype] Signed-off-by: Steve Pennington Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/core/rtw_recv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/core/rtw_recv.c b/drivers/staging/rtl8723au/core/rtw_recv.c index 274a4b65c022..ad0549c66529 100644 --- a/drivers/staging/rtl8723au/core/rtw_recv.c +++ b/drivers/staging/rtl8723au/core/rtw_recv.c @@ -1554,8 +1554,7 @@ static int wlanhdr_to_ethhdr (struct recv_frame *precvframe) ether_addr_copy(ptr + ETH_ALEN, pattrib->src); if (!bsnaphdr) { - len = htons(len); - memcpy(ptr + 12, &len, 2); + put_unaligned_be16(len, ptr + 12); } -- cgit v1.3-6-gb490 From 52b1660d3b3a7fc967ba9d9b641b594fa1ac33d7 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:35 -0400 Subject: staging: unisys: Remove num_visornic_open array As pointed out in a recent review, the num_visornic_open array didn't do anything useful, and it exposed a potential race in the visornic code that could arise while taking down a net interface while reading from the debugfs files. Fix that by removing the array entirely, and just iterating over all the registered netdevs in a given namespace, filtering on them having visornic ops (to identify which are ours), and having their queues not be stopped (identifying that they are up). This should prevent any oops conditions happening due to changing state in that array, and save us a bunch of code too. Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Acked-by: Neil Horman Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 341 +++++++++++------------- 1 file changed, 154 insertions(+), 187 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index c28a34767552..5bb6cf461b25 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -196,8 +196,6 @@ struct visornic_devdata { struct chanstat chstat; }; -/* array of open devices maintained by open() and close() */ -static struct net_device *num_visornic_open[VISORNICSOPENMAX]; /* List of all visornic_devdata structs, * linked via the list_all member @@ -325,178 +323,15 @@ static void visor_thread_stop(struct visor_thread_info *thrinfo) thrinfo->id = 0; } -/* DebugFS code */ -static ssize_t info_debugfs_read(struct file *file, char __user *buf, - size_t len, loff_t *offset) -{ - int i; - ssize_t bytes_read = 0; - int str_pos = 0; - struct visornic_devdata *devdata; - char *vbuf; - - if (len > MAX_BUF) - len = MAX_BUF; - vbuf = kzalloc(len, GFP_KERNEL); - if (!vbuf) - return -ENOMEM; - - /* for each vnic channel - * dump out channel specific data - */ - for (i = 0; i < VISORNICSOPENMAX; i++) { - if (!num_visornic_open[i]) - continue; - - devdata = netdev_priv(num_visornic_open[i]); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - "Vnic i = %d\n", i); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - "netdev = %s (0x%p), MAC Addr %pM\n", - num_visornic_open[i]->name, - num_visornic_open[i], - num_visornic_open[i]->dev_addr); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - "VisorNic Dev Info = 0x%p\n", devdata); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " num_rcv_bufs = %d\n", - devdata->num_rcv_bufs); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " max_oustanding_next_xmits = %d\n", - devdata->max_outstanding_net_xmits); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " upper_threshold_net_xmits = %d\n", - devdata->upper_threshold_net_xmits); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " lower_threshold_net_xmits = %d\n", - devdata->lower_threshold_net_xmits); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " queuefullmsg_logged = %d\n", - devdata->queuefullmsg_logged); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.got_rcv = %lu\n", - devdata->chstat.got_rcv); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.got_enbdisack = %lu\n", - devdata->chstat.got_enbdisack); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.got_xmit_done = %lu\n", - devdata->chstat.got_xmit_done); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.xmit_fail = %lu\n", - devdata->chstat.xmit_fail); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.sent_enbdis = %lu\n", - devdata->chstat.sent_enbdis); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.sent_promisc = %lu\n", - devdata->chstat.sent_promisc); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.sent_post = %lu\n", - devdata->chstat.sent_post); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.sent_xmit = %lu\n", - devdata->chstat.sent_xmit); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.reject_count = %lu\n", - devdata->chstat.reject_count); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " chstat.extra_rcvbufs_sent = %lu\n", - devdata->chstat.extra_rcvbufs_sent); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_rcv0 = %lu\n", devdata->n_rcv0); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_rcv1 = %lu\n", devdata->n_rcv1); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_rcv2 = %lu\n", devdata->n_rcv2); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_rcvx = %lu\n", devdata->n_rcvx); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " num_rcvbuf_in_iovm = %d\n", - atomic_read(&devdata->num_rcvbuf_in_iovm)); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " alloc_failed_in_if_needed_cnt = %lu\n", - devdata->alloc_failed_in_if_needed_cnt); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " alloc_failed_in_repost_rtn_cnt = %lu\n", - devdata->alloc_failed_in_repost_rtn_cnt); - /* str_pos += scnprintf(vbuf + str_pos, len - str_pos, - * " inner_loop_limit_reached_cnt = %lu\n", - * devdata->inner_loop_limit_reached_cnt); - */ - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " found_repost_rcvbuf_cnt = %lu\n", - devdata->found_repost_rcvbuf_cnt); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " repost_found_skb_cnt = %lu\n", - devdata->repost_found_skb_cnt); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_repost_deficit = %lu\n", - devdata->n_repost_deficit); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " bad_rcv_buf = %lu\n", - devdata->bad_rcv_buf); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " n_rcv_packets_not_accepted = %lu\n", - devdata->n_rcv_packets_not_accepted); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " interrupts_rcvd = %llu\n", - devdata->interrupts_rcvd); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " interrupts_notme = %llu\n", - devdata->interrupts_notme); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " interrupts_disabled = %llu\n", - devdata->interrupts_disabled); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " busy_cnt = %llu\n", - devdata->busy_cnt); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " flow_control_upper_hits = %llu\n", - devdata->flow_control_upper_hits); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " flow_control_lower_hits = %llu\n", - devdata->flow_control_lower_hits); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " thread_wait_ms = %d\n", - devdata->thread_wait_ms); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " netif_queue = %s\n", - netif_queue_stopped(devdata->netdev) ? - "stopped" : "running"); - } - bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos); - kfree(vbuf); - return bytes_read; -} - static ssize_t enable_ints_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { - char buf[4]; - int i, new_value; - struct visornic_devdata *devdata; - - if (count >= ARRAY_SIZE(buf)) - return -EINVAL; - - buf[count] = '\0'; - if (copy_from_user(buf, buffer, count)) - return -EFAULT; - - i = kstrtoint(buf, 10, &new_value); - if (i != 0) - return -EFAULT; - - /* set all counts to new_value usually 0 */ - for (i = 0; i < VISORNICSOPENMAX; i++) { - if (num_visornic_open[i]) { - devdata = netdev_priv(num_visornic_open[i]); - /* TODO update features bit in channel */ - } - } - + /* + * Don't want to break ABI here by having a debugfs + * file that no longer exists or is writable, so + * lets just make this a vestigual function + */ return count; } @@ -760,13 +595,6 @@ visornic_disable_with_timeout(struct net_device *netdev, const int timeout) } } - /* remove references from array */ - for (i = 0; i < VISORNICSOPENMAX; i++) - if (num_visornic_open[i] == netdev) { - num_visornic_open[i] = NULL; - break; - } - return 0; } @@ -882,16 +710,6 @@ visornic_enable_with_timeout(struct net_device *netdev, const int timeout) return -EIO; } - /* find an open slot in the array to save off VisorNic references - * for debug - */ - for (i = 0; i < VISORNICSOPENMAX; i++) { - if (!num_visornic_open[i]) { - num_visornic_open[i] = netdev; - break; - } - } - return 0; } @@ -1642,6 +1460,155 @@ static const struct net_device_ops visornic_dev_ops = { .ndo_set_rx_mode = visornic_set_multi, }; +/* DebugFS code */ +static ssize_t info_debugfs_read(struct file *file, char __user *buf, + size_t len, loff_t *offset) +{ + ssize_t bytes_read = 0; + int str_pos = 0; + struct visornic_devdata *devdata; + struct net_device *dev; + char *vbuf; + + if (len > MAX_BUF) + len = MAX_BUF; + vbuf = kzalloc(len, GFP_KERNEL); + if (!vbuf) + return -ENOMEM; + + /* for each vnic channel + * dump out channel specific data + */ + rcu_read_lock(); + for_each_netdev_rcu(current->nsproxy->net_ns, dev) { + /* + * Only consider netdevs that are visornic, and are open + */ + if ((dev->netdev_ops != &visornic_dev_ops) || + (!netif_queue_stopped(dev))) + continue; + + devdata = netdev_priv(dev); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + "netdev = %s (0x%p), MAC Addr %pM\n", + dev->name, + dev, + dev->dev_addr); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + "VisorNic Dev Info = 0x%p\n", devdata); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " num_rcv_bufs = %d\n", + devdata->num_rcv_bufs); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " max_oustanding_next_xmits = %d\n", + devdata->max_outstanding_net_xmits); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " upper_threshold_net_xmits = %d\n", + devdata->upper_threshold_net_xmits); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " lower_threshold_net_xmits = %d\n", + devdata->lower_threshold_net_xmits); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " queuefullmsg_logged = %d\n", + devdata->queuefullmsg_logged); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " chstat.got_rcv = %lu\n", + devdata->chstat.got_rcv); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " chstat.got_enbdisack = %lu\n", + devdata->chstat.got_enbdisack); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " chstat.got_xmit_done = %lu\n", + devdata->chstat.got_xmit_done); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " chstat.xmit_fail = %lu\n", + devdata->chstat.xmit_fail); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " chstat.sent_enbdis = %lu\n", + devdata->chstat.sent_enbdis); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " chstat.sent_promisc = %lu\n", + devdata->chstat.sent_promisc); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " chstat.sent_post = %lu\n", + devdata->chstat.sent_post); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " chstat.sent_xmit = %lu\n", + devdata->chstat.sent_xmit); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " chstat.reject_count = %lu\n", + devdata->chstat.reject_count); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " chstat.extra_rcvbufs_sent = %lu\n", + devdata->chstat.extra_rcvbufs_sent); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " n_rcv0 = %lu\n", devdata->n_rcv0); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " n_rcv1 = %lu\n", devdata->n_rcv1); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " n_rcv2 = %lu\n", devdata->n_rcv2); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " n_rcvx = %lu\n", devdata->n_rcvx); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " num_rcvbuf_in_iovm = %d\n", + atomic_read(&devdata->num_rcvbuf_in_iovm)); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " alloc_failed_in_if_needed_cnt = %lu\n", + devdata->alloc_failed_in_if_needed_cnt); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " alloc_failed_in_repost_rtn_cnt = %lu\n", + devdata->alloc_failed_in_repost_rtn_cnt); + /* str_pos += scnprintf(vbuf + str_pos, len - str_pos, + * " inner_loop_limit_reached_cnt = %lu\n", + * devdata->inner_loop_limit_reached_cnt); + */ + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " found_repost_rcvbuf_cnt = %lu\n", + devdata->found_repost_rcvbuf_cnt); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " repost_found_skb_cnt = %lu\n", + devdata->repost_found_skb_cnt); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " n_repost_deficit = %lu\n", + devdata->n_repost_deficit); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " bad_rcv_buf = %lu\n", + devdata->bad_rcv_buf); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " n_rcv_packets_not_accepted = %lu\n", + devdata->n_rcv_packets_not_accepted); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " interrupts_rcvd = %llu\n", + devdata->interrupts_rcvd); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " interrupts_notme = %llu\n", + devdata->interrupts_notme); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " interrupts_disabled = %llu\n", + devdata->interrupts_disabled); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " busy_cnt = %llu\n", + devdata->busy_cnt); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " flow_control_upper_hits = %llu\n", + devdata->flow_control_upper_hits); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " flow_control_lower_hits = %llu\n", + devdata->flow_control_lower_hits); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " thread_wait_ms = %d\n", + devdata->thread_wait_ms); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " netif_queue = %s\n", + netif_queue_stopped(devdata->netdev) ? + "stopped" : "running"); + } + rcu_read_unlock(); + bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos); + kfree(vbuf); + return bytes_read; +} + /** * send_rcv_posts_if_needed * @devdata: visornic device -- cgit v1.3-6-gb490 From ce657aa81005ddfbdd9c89ec9de31ff713c05ea6 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:36 -0400 Subject: staging: unisys: Check return code properly on visor_copy_fragsinfo_from_skb One call site for visor_copy_fragsinfo_from_skb was checking for an rc of -1, but thhe function doesn't return that, it returns -errno. Correct it Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 5bb6cf461b25..1a0efe25f929 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -912,7 +912,7 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) visor_copy_fragsinfo_from_skb(skb, firstfraglen, MAX_PHYS_INFO, cmdrsp->net.xmt.frags); - if (cmdrsp->net.xmt.num_frags == -1) { + if (cmdrsp->net.xmt.num_frags < 0) { spin_unlock_irqrestore(&devdata->priv_lock, flags); devdata->busy_cnt++; dev_err(&netdev->dev, -- cgit v1.3-6-gb490 From 998ff7f85d2a4923cf8e49319957bb2a70f8b881 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:37 -0400 Subject: staging: unisys: BUG halt on error in I/O channel We precheck that we have enough space in an iochannel prior to writing to it when we send in a fragmented skb. Given that there is no recovery from this condition that I can see, turn it into a BUG halt Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 1a0efe25f929..f7363925f4a1 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -254,8 +254,16 @@ visor_copy_fragsinfo_from_skb(struct sk_buff *skb, unsigned int firstfraglen, page_offset, skb_shinfo(skb)->frags[ii]. size, count, frags_max, frags); - if (!count) - return -EIO; + /* + * add_physinfo_entries only returns + * zero if the frags array is out of room + * That should never happen because we + * fail above, if count+numfrags > frags_max. + * Given that theres no recovery mechanism from putting + * half a packet in the I/O channel, panic here as this + * should never happen + */ + BUG_ON(!count); } } if (skb_shinfo(skb)->frag_list) { -- cgit v1.3-6-gb490 From 513e1cbda230c626bc01492f440805c4a88632d7 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:38 -0400 Subject: staging: unisys: Linarize skbs If we can't fit an skb into a frag array, linaraize it so we don't have to Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index f7363925f4a1..a421a5bea343 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -221,9 +221,25 @@ visor_copy_fragsinfo_from_skb(struct sk_buff *skb, unsigned int firstfraglen, struct phys_info frags[]) { unsigned int count = 0, ii, size, offset = 0, numfrags; + unsigned int total_count; numfrags = skb_shinfo(skb)->nr_frags; + /* + * Compute the number of fragments this skb has, and if its more than + * frag array can hold, linearize the skb + */ + total_count = numfrags + (firstfraglen / PI_PAGE_SIZE); + if (firstfraglen % PI_PAGE_SIZE) + total_count++; + + if (total_count > frags_max) { + if (skb_linearize(skb)) + return -EINVAL; + numfrags = skb_shinfo(skb)->nr_frags; + firstfraglen = 0; + } + while (firstfraglen) { if (count == frags_max) return -EINVAL; -- cgit v1.3-6-gb490 From 87a9404ef0be2aac949fdb8854e71d100859f6f5 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:39 -0400 Subject: staging: unisys: Clean up kthread usage Remove the has_stopped completion as theres already one available internally. Correct the while loops Remove the while loop in drain_queue as it already exists in the top level loop Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 182 +++++++++++------------- 1 file changed, 86 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index a421a5bea343..923c580b9a5d 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -91,7 +91,6 @@ static struct visor_driver visornic_driver = { struct visor_thread_info { struct task_struct *task; - struct completion has_stopped; int id; }; @@ -317,7 +316,6 @@ static int visor_thread_start(struct visor_thread_info *thrinfo, void *thrcontext, char *name) { /* used to stop the thread */ - init_completion(&thrinfo->has_stopped); thrinfo->task = kthread_run(threadfn, thrcontext, name); if (IS_ERR(thrinfo->task)) { pr_debug("%s failed (%ld)\n", @@ -341,10 +339,8 @@ static void visor_thread_stop(struct visor_thread_info *thrinfo) if (!thrinfo->id) return; /* thread not running */ - kthread_stop(thrinfo->task); - /* give up if the thread has NOT died in 1 minute */ - if (wait_for_completion_timeout(&thrinfo->has_stopped, 60 * HZ)) - thrinfo->id = 0; + BUG_ON(kthread_stop(thrinfo->task)); + thrinfo->id = 0; } static ssize_t enable_ints_write(struct file *file, @@ -1691,99 +1687,95 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata) unsigned long flags; struct net_device *netdev; - /* drain queue */ - while (1) { - /* TODO: CLIENT ACQUIRE -- Don't really need this at the - * moment */ - if (!visorchannel_signalremove(devdata->dev->visorchannel, - IOCHAN_FROM_IOPART, - cmdrsp)) - break; /* queue empty */ - - switch (cmdrsp->net.type) { - case NET_RCV: - devdata->chstat.got_rcv++; - /* process incoming packet */ - visornic_rx(cmdrsp); - break; - case NET_XMIT_DONE: - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->chstat.got_xmit_done++; - if (cmdrsp->net.xmtdone.xmt_done_result) - devdata->chstat.xmit_fail++; - /* only call queue wake if we stopped it */ - netdev = ((struct sk_buff *)cmdrsp->net.buf)->dev; - /* ASSERT netdev == vnicinfo->netdev; */ - if ((netdev == devdata->netdev) && - netif_queue_stopped(netdev)) { - /* check to see if we have crossed - * the lower watermark for - * netif_wake_queue() + /* TODO: CLIENT ACQUIRE -- Don't really need this at the + * moment */ + if (!visorchannel_signalremove(devdata->dev->visorchannel, + IOCHAN_FROM_IOPART, + cmdrsp)) + return; /* queue empty */ + + switch (cmdrsp->net.type) { + case NET_RCV: + devdata->chstat.got_rcv++; + /* process incoming packet */ + visornic_rx(cmdrsp); + break; + case NET_XMIT_DONE: + spin_lock_irqsave(&devdata->priv_lock, flags); + devdata->chstat.got_xmit_done++; + if (cmdrsp->net.xmtdone.xmt_done_result) + devdata->chstat.xmit_fail++; + /* only call queue wake if we stopped it */ + netdev = ((struct sk_buff *)cmdrsp->net.buf)->dev; + /* ASSERT netdev == vnicinfo->netdev; */ + if ((netdev == devdata->netdev) && + netif_queue_stopped(netdev)) { + /* check to see if we have crossed + * the lower watermark for + * netif_wake_queue() + */ + if (((devdata->chstat.sent_xmit >= + devdata->chstat.got_xmit_done) && + (devdata->chstat.sent_xmit - + devdata->chstat.got_xmit_done <= + devdata->lower_threshold_net_xmits)) || + ((devdata->chstat.sent_xmit < + devdata->chstat.got_xmit_done) && + (ULONG_MAX - devdata->chstat.got_xmit_done + + devdata->chstat.sent_xmit <= + devdata->lower_threshold_net_xmits))) { + /* enough NET_XMITs completed + * so can restart netif queue */ - if (((devdata->chstat.sent_xmit >= - devdata->chstat.got_xmit_done) && - (devdata->chstat.sent_xmit - - devdata->chstat.got_xmit_done <= - devdata->lower_threshold_net_xmits)) || - ((devdata->chstat.sent_xmit < - devdata->chstat.got_xmit_done) && - (ULONG_MAX - devdata->chstat.got_xmit_done - + devdata->chstat.sent_xmit <= - devdata->lower_threshold_net_xmits))) { - /* enough NET_XMITs completed - * so can restart netif queue - */ - netif_wake_queue(netdev); - devdata->flow_control_lower_hits++; - } - } - skb_unlink(cmdrsp->net.buf, &devdata->xmitbufhead); - spin_unlock_irqrestore(&devdata->priv_lock, flags); - kfree_skb(cmdrsp->net.buf); - break; - case NET_RCV_ENBDIS_ACK: - devdata->chstat.got_enbdisack++; - netdev = (struct net_device *) - cmdrsp->net.enbdis.context; - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enab_dis_acked = 1; - spin_unlock_irqrestore(&devdata->priv_lock, flags); - - if (devdata->server_down && - devdata->server_change_state) { - /* Inform Linux that the link is up */ - devdata->server_down = false; - devdata->server_change_state = false; netif_wake_queue(netdev); - netif_carrier_on(netdev); + devdata->flow_control_lower_hits++; } - break; - case NET_CONNECT_STATUS: - netdev = devdata->netdev; - if (cmdrsp->net.enbdis.enable == 1) { - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enabled = cmdrsp->net.enbdis.enable; - spin_unlock_irqrestore(&devdata->priv_lock, - flags); - netif_wake_queue(netdev); - netif_carrier_on(netdev); - } else { - netif_stop_queue(netdev); - netif_carrier_off(netdev); - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enabled = cmdrsp->net.enbdis.enable; - spin_unlock_irqrestore(&devdata->priv_lock, - flags); - } - break; - default: - break; } - /* cmdrsp is now available for reuse */ + skb_unlink(cmdrsp->net.buf, &devdata->xmitbufhead); + spin_unlock_irqrestore(&devdata->priv_lock, flags); + kfree_skb(cmdrsp->net.buf); + break; + case NET_RCV_ENBDIS_ACK: + devdata->chstat.got_enbdisack++; + netdev = (struct net_device *) + cmdrsp->net.enbdis.context; + spin_lock_irqsave(&devdata->priv_lock, flags); + devdata->enab_dis_acked = 1; + spin_unlock_irqrestore(&devdata->priv_lock, flags); if (kthread_should_stop()) break; + if (devdata->server_down && + devdata->server_change_state) { + /* Inform Linux that the link is up */ + devdata->server_down = false; + devdata->server_change_state = false; + netif_wake_queue(netdev); + netif_carrier_on(netdev); + } + break; + case NET_CONNECT_STATUS: + netdev = devdata->netdev; + if (cmdrsp->net.enbdis.enable == 1) { + spin_lock_irqsave(&devdata->priv_lock, flags); + devdata->enabled = cmdrsp->net.enbdis.enable; + spin_unlock_irqrestore(&devdata->priv_lock, + flags); + netif_wake_queue(netdev); + netif_carrier_on(netdev); + } else { + netif_stop_queue(netdev); + netif_carrier_off(netdev); + spin_lock_irqsave(&devdata->priv_lock, flags); + devdata->enabled = cmdrsp->net.enbdis.enable; + spin_unlock_irqrestore(&devdata->priv_lock, + flags); + } + break; + default: + break; } + /* cmdrsp is now available for reuse */ } /** @@ -1803,9 +1795,9 @@ process_incoming_rsps(void *v) cmdrsp = kmalloc(SZ, GFP_ATOMIC); if (!cmdrsp) - complete_and_exit(&devdata->threadinfo.has_stopped, 0); + return 0; - while (1) { + while (!kthread_should_stop()) { wait_event_interruptible_timeout( devdata->rsp_queue, (atomic_read( &devdata->interrupt_rcvd) == 1), @@ -1818,12 +1810,10 @@ process_incoming_rsps(void *v) atomic_set(&devdata->interrupt_rcvd, 0); send_rcv_posts_if_needed(devdata); drain_queue(cmdrsp, devdata); - if (kthread_should_stop()) - break; } kfree(cmdrsp); - complete_and_exit(&devdata->threadinfo.has_stopped, 0); + return 0; } /** -- cgit v1.3-6-gb490 From 8cf12de41bb772fccd2807780ad23639e4fcce89 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:40 -0400 Subject: staging: unisys: Guard against task leakage Its possible to overwrite the old task pointer in visornic_resume. Add a check to guard against that and a warning if we find that its already running Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 923c580b9a5d..6c60e18b3be4 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -2118,8 +2118,13 @@ static int visornic_resume(struct visor_device *dev, * we can start using the device again. * TODO: State transitions */ - visor_thread_start(&devdata->threadinfo, process_incoming_rsps, - devdata, "vnic_incoming"); + if (!devdata->threadinfo.id) + visor_thread_start(&devdata->threadinfo, + process_incoming_rsps, + devdata, "vnic_incoming"); + else + pr_warn("vnic_incoming already running!\n"); + init_rcv_bufs(netdev, devdata); spin_lock_irqsave(&devdata->priv_lock, flags); devdata->enabled = 1; -- cgit v1.3-6-gb490 From 0d5073935a662564d46dff071874fe2cab11c651 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:41 -0400 Subject: staging: unisys: simplify visornic_serverdown_complete Theres a lot of code duplication going on in visornic_serverdown_complete. We should just be able to send it through the dev_close path and have it do the right things. Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 36 ++++++------------------- 1 file changed, 8 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 6c60e18b3be4..aeb379e169da 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -19,10 +19,11 @@ */ #include -#include #include -#include +#include #include +#include +#include #include "visorbus.h" #include "iochannel.h" @@ -370,8 +371,6 @@ visornic_serverdown_complete(struct work_struct *work) { struct visornic_devdata *devdata; struct net_device *netdev; - unsigned long flags; - int i = 0, count = 0; devdata = container_of(work, struct visornic_devdata, serverdown_completion); @@ -380,27 +379,11 @@ visornic_serverdown_complete(struct work_struct *work) /* Stop using datachan */ visor_thread_stop(&devdata->threadinfo); - /* Inform Linux that the link is down */ - netif_carrier_off(netdev); - netif_stop_queue(netdev); + rtnl_lock(); + dev_close(netdev); + rtnl_unlock(); - /* Free the skb for XMITs that haven't been serviced by the server - * We shouldn't have to inform Linux about these IOs because they - * are "lost in the ethernet" - */ - skb_queue_purge(&devdata->xmitbufhead); - - spin_lock_irqsave(&devdata->priv_lock, flags); - /* free rcv buffers */ - for (i = 0; i < devdata->num_rcv_bufs; i++) { - if (devdata->rcvbuf[i]) { - kfree_skb(devdata->rcvbuf[i]); - devdata->rcvbuf[i] = NULL; - count++; - } - } atomic_set(&devdata->num_rcvbuf_in_iovm, 0); - spin_unlock_irqrestore(&devdata->priv_lock, flags); if (devdata->server_down_complete_func) (*devdata->server_down_complete_func)(devdata->dev, 0); @@ -605,6 +588,8 @@ visornic_disable_with_timeout(struct net_device *netdev, const int timeout) /* we've set enabled to 0, so we can give up the lock. */ spin_unlock_irqrestore(&devdata->priv_lock, flags); + skb_queue_purge(&devdata->xmitbufhead); + /* Free rcv buffers - other end has automatically unposed them on * disable */ @@ -1174,7 +1159,6 @@ repost_return(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata, devdata->bad_rcv_buf++; } } - atomic_dec(&devdata->usage); return status; } @@ -1228,10 +1212,6 @@ visornic_rx(struct uiscmdrsp *cmdrsp) devdata->net_stats.rx_packets++; devdata->net_stats.rx_bytes = skb->len; - atomic_inc(&devdata->usage); /* don't want a close to happen before - * we're done here - */ - /* set length to how much was ACTUALLY received - * NOTE: rcv_done_len includes actual length of data rcvd * including ethhdr -- cgit v1.3-6-gb490 From ace72eef40e8b5f0e3b3916e2dee2d146711ca2e Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:42 -0400 Subject: staging: unisys: Make serverdown synchronous I don't see why serverdown should be async on a workqueue. Just make it synchronous, and remove some code in the process Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index aeb379e169da..316f9ac71600 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -61,7 +61,6 @@ static const struct file_operations debugfs_enable_ints_fops = { .write = enable_ints_write, }; -static struct workqueue_struct *visornic_serverdown_workqueue; static struct workqueue_struct *visornic_timeout_reset_workqueue; /* GUIDS for director channel type supported by this driver. */ @@ -148,7 +147,6 @@ struct visornic_devdata { * xmit buffer list that have been * sent to the IOPART end */ - struct work_struct serverdown_completion; visorbus_state_complete_func server_down_complete_func; struct work_struct timeout_reset; struct uiscmdrsp *cmdrsp_rcv; /* cmdrsp_rcv is used for @@ -367,13 +365,10 @@ static ssize_t enable_ints_write(struct file *file, * Returns void. */ static void -visornic_serverdown_complete(struct work_struct *work) +visornic_serverdown_complete(struct visornic_devdata *devdata) { - struct visornic_devdata *devdata; struct net_device *netdev; - devdata = container_of(work, struct visornic_devdata, - serverdown_completion); netdev = devdata->netdev; /* Stop using datachan */ @@ -418,8 +413,7 @@ visornic_serverdown(struct visornic_devdata *devdata, } devdata->server_change_state = true; devdata->server_down_complete_func = complete_func; - queue_work(visornic_serverdown_workqueue, - &devdata->serverdown_completion); + visornic_serverdown_complete(devdata); } else if (devdata->server_change_state) { dev_dbg(&devdata->dev->device, "%s changing state\n", __func__); @@ -1892,8 +1886,6 @@ static int visornic_probe(struct visor_device *dev) err = -ENOMEM; goto cleanup_xmit_cmdrsp; } - INIT_WORK(&devdata->serverdown_completion, - visornic_serverdown_complete); INIT_WORK(&devdata->timeout_reset, visornic_timeout_reset); devdata->server_down = false; devdata->server_change_state = false; @@ -2019,7 +2011,6 @@ static void visornic_remove(struct visor_device *dev) } /* going_away prevents new items being added to the workqueues */ - flush_workqueue(visornic_serverdown_workqueue); flush_workqueue(visornic_timeout_reset_workqueue); debugfs_remove_recursive(devdata->eth_debugfs_dir); @@ -2155,12 +2146,6 @@ static int visornic_init(void) if (!ret) goto cleanup_debugfs; - /* create workqueue for serverdown completion */ - visornic_serverdown_workqueue = - create_singlethread_workqueue("visornic_serverdown"); - if (!visornic_serverdown_workqueue) - goto cleanup_debugfs; - /* create workqueue for tx timeout reset */ visornic_timeout_reset_workqueue = create_singlethread_workqueue("visornic_timeout_reset"); @@ -2176,8 +2161,6 @@ static int visornic_init(void) return 0; cleanup_workqueue: - flush_workqueue(visornic_serverdown_workqueue); - destroy_workqueue(visornic_serverdown_workqueue); if (visornic_timeout_reset_workqueue) { flush_workqueue(visornic_timeout_reset_workqueue); destroy_workqueue(visornic_timeout_reset_workqueue); @@ -2197,10 +2180,6 @@ static void visornic_cleanup(void) { visorbus_unregister_visor_driver(&visornic_driver); - if (visornic_serverdown_workqueue) { - flush_workqueue(visornic_serverdown_workqueue); - destroy_workqueue(visornic_serverdown_workqueue); - } if (visornic_timeout_reset_workqueue) { flush_workqueue(visornic_timeout_reset_workqueue); destroy_workqueue(visornic_timeout_reset_workqueue); -- cgit v1.3-6-gb490 From 0c677e9c24935bdca8ed72b96f7e762c95fc8bd3 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:43 -0400 Subject: staging: unisys: Change enable/disable to wait forever I don't see why the server should stop responding, or that we should just give up if it does. Wait forever when enabling/disabling the visornic Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 316f9ac71600..12318365ec7f 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -28,7 +28,7 @@ #include "visorbus.h" #include "iochannel.h" -#define VISORNIC_INFINITE_RESPONSE_WAIT 0 +#define VISORNIC_INFINITE_RSP_WAIT 0 #define VISORNICSOPENMAX 32 #define MAXDEVICES 16384 @@ -549,7 +549,7 @@ visornic_disable_with_timeout(struct net_device *netdev, const int timeout) * when it gets a disable. */ spin_lock_irqsave(&devdata->priv_lock, flags); - while ((timeout == VISORNIC_INFINITE_RESPONSE_WAIT) || + while ((timeout == VISORNIC_INFINITE_RSP_WAIT) || (wait < timeout)) { if (devdata->enab_dis_acked) break; @@ -686,7 +686,7 @@ visornic_enable_with_timeout(struct net_device *netdev, const int timeout) send_enbdis(netdev, 1, devdata); spin_lock_irqsave(&devdata->priv_lock, flags); - while ((timeout == VISORNIC_INFINITE_RESPONSE_WAIT) || + while ((timeout == VISORNIC_INFINITE_RSP_WAIT) || (wait < timeout)) { if (devdata->enab_dis_acked) break; @@ -731,11 +731,13 @@ visornic_timeout_reset(struct work_struct *work) netdev = devdata->netdev; netif_stop_queue(netdev); - response = visornic_disable_with_timeout(netdev, 100); + response = visornic_disable_with_timeout(netdev, + VISORNIC_INFINITE_RSP_WAIT); if (response) goto call_serverdown; - response = visornic_enable_with_timeout(netdev, 100); + response = visornic_enable_with_timeout(netdev, + VISORNIC_INFINITE_RSP_WAIT); if (response) goto call_serverdown; netif_wake_queue(netdev); @@ -756,7 +758,7 @@ call_serverdown: static int visornic_open(struct net_device *netdev) { - visornic_enable_with_timeout(netdev, VISORNIC_INFINITE_RESPONSE_WAIT); + visornic_enable_with_timeout(netdev, VISORNIC_INFINITE_RSP_WAIT); /* start the interface's transmit queue, allowing it to accept * packets for transmission @@ -777,7 +779,7 @@ static int visornic_close(struct net_device *netdev) { netif_stop_queue(netdev); - visornic_disable_with_timeout(netdev, VISORNIC_INFINITE_RESPONSE_WAIT); + visornic_disable_with_timeout(netdev, VISORNIC_INFINITE_RSP_WAIT); return 0; } -- cgit v1.3-6-gb490 From 35a8dd310efbbcec37de2da6301f9bdaf83b2632 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:44 -0400 Subject: staging: unisys: Remove some extraneous start/stop queue operations If we put them in the enable and disable paths, we don't need them in several other places Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 12318365ec7f..338ca8c29915 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -709,6 +709,7 @@ visornic_enable_with_timeout(struct net_device *netdev, const int timeout) return -EIO; } + netif_start_queue(netdev); return 0; } @@ -730,7 +731,6 @@ visornic_timeout_reset(struct work_struct *work) devdata = container_of(work, struct visornic_devdata, timeout_reset); netdev = devdata->netdev; - netif_stop_queue(netdev); response = visornic_disable_with_timeout(netdev, VISORNIC_INFINITE_RSP_WAIT); if (response) @@ -740,7 +740,6 @@ visornic_timeout_reset(struct work_struct *work) VISORNIC_INFINITE_RSP_WAIT); if (response) goto call_serverdown; - netif_wake_queue(netdev); return; @@ -760,11 +759,6 @@ visornic_open(struct net_device *netdev) { visornic_enable_with_timeout(netdev, VISORNIC_INFINITE_RSP_WAIT); - /* start the interface's transmit queue, allowing it to accept - * packets for transmission - */ - netif_start_queue(netdev); - return 0; } @@ -778,7 +772,6 @@ visornic_open(struct net_device *netdev) static int visornic_close(struct net_device *netdev) { - netif_stop_queue(netdev); visornic_disable_with_timeout(netdev, VISORNIC_INFINITE_RSP_WAIT); return 0; -- cgit v1.3-6-gb490 From f6346ad662e44d7086bc3c18fc19a33f0b95b576 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:45 -0400 Subject: staging: unisys: Fix improper use of NETDEV_TX_BUSY Using NETDEV_TX_BUSY is tricky. Its meant for situations where the error in question is transient and quickly resolved. But the driver rarely is able to know that to a certainty. And in the case of visornic, it just uses it without any care for that, in the hopes that it won't loose frames, even if the problem is that the skb is somehow malformed for the hardware. If we get one of those kinds of skbs, NETDEV_TX_BUSY will just cause us to spin, processing the same error over and over. Fix it by dropping the frame, stopping the queue where appropriate, and returning NETDEV_TX_OK Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 338ca8c29915..8cc9017a67a1 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -787,7 +787,7 @@ visornic_close(struct net_device *netdev) * function is protected from concurrent calls by a spinlock xmit_lock * in the net_device struct, but as soon as the function returns it * can be called again. - * Returns NETDEV_TX_OK for success, NETDEV_TX_BUSY for error. + * Returns NETDEV_TX_OK. */ static int visornic_xmit(struct sk_buff *skb, struct net_device *netdev) @@ -806,7 +806,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) devdata->busy_cnt++; dev_dbg(&netdev->dev, "%s busy - queue stopped\n", __func__); - return NETDEV_TX_BUSY; + kfree_skb(skb); + return NETDEV_TX_OK; } /* sk_buff struct is used to host network data throughout all the @@ -827,7 +828,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) dev_err(&netdev->dev, "%s busy - first frag too small (%d)\n", __func__, firstfraglen); - return NETDEV_TX_BUSY; + kfree_skb(skb); + return NETDEV_TX_OK; } if ((len < ETH_MIN_PACKET_SIZE) && @@ -869,7 +871,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) dev_dbg(&netdev->dev, "%s busy - waiting for iovm to catch up\n", __func__); - return NETDEV_TX_BUSY; + kfree_skb(skb); + return NETDEV_TX_OK; } if (devdata->queuefullmsg_logged) devdata->queuefullmsg_logged = 0; @@ -911,7 +914,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) devdata->busy_cnt++; dev_err(&netdev->dev, "%s busy - copy frags failed\n", __func__); - return NETDEV_TX_BUSY; + kfree_skb(skb); + return NETDEV_TX_OK; } if (!visorchannel_signalinsert(devdata->dev->visorchannel, @@ -921,7 +925,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) devdata->busy_cnt++; dev_dbg(&netdev->dev, "%s busy - signalinsert failed\n", __func__); - return NETDEV_TX_BUSY; + kfree_skb(skb); + return NETDEV_TX_OK; } /* Track the skbs that have been sent to the IOVM for XMIT */ -- cgit v1.3-6-gb490 From a42ba26cca4ed183362d5adb5dad227f908b4ddb Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:46 -0400 Subject: staging: unisys: Remove trans_start dev_trans_start does this for us now Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 8cc9017a67a1..37f3e277285b 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -932,12 +932,6 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) /* Track the skbs that have been sent to the IOVM for XMIT */ skb_queue_head(&devdata->xmitbufhead, skb); - /* set the last transmission start time - * linux doc says: Do not forget to update netdev->trans_start to - * jiffies after each new tx packet is given to the hardware. - */ - netdev->trans_start = jiffies; - /* update xmt stats */ devdata->net_stats.tx_packets++; devdata->net_stats.tx_bytes += skb->len; -- cgit v1.3-6-gb490 From 15a4d2137077296e22fce2127f8056d6d7f9e785 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:47 -0400 Subject: staging: unisys: remove visornic_ioctl All it does is return no supported. Removing the function entirely accomplishes the same thing Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 37f3e277285b..a5da40066bc7 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -977,21 +977,6 @@ visornic_get_stats(struct net_device *netdev) return &devdata->net_stats; } -/** - * visornic_ioctl - ioctl function for netdevice. - * @netdev: netdevice - * @ifr: ignored - * @cmd: ignored - * - * Currently not supported. - * Returns EOPNOTSUPP - */ -static int -visornic_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) -{ - return -EOPNOTSUPP; -} - /** * visornic_change_mtu - changes mtu of device. * @netdev: netdevice @@ -1442,7 +1427,6 @@ static const struct net_device_ops visornic_dev_ops = { .ndo_stop = visornic_close, .ndo_start_xmit = visornic_xmit, .ndo_get_stats = visornic_get_stats, - .ndo_do_ioctl = visornic_ioctl, .ndo_change_mtu = visornic_change_mtu, .ndo_tx_timeout = visornic_xmit_timeout, .ndo_set_rx_mode = visornic_set_multi, -- cgit v1.3-6-gb490 From 547e4c90aee5f4ecfed23a16b621629071e41f05 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 21 Jul 2015 09:55:48 -0400 Subject: staging: unisys: remove bogus error checking The netdev we're testing for can't be removed, because its never unregistered, so don't bother checking for it Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index a5da40066bc7..4d49937d3856 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1164,18 +1164,6 @@ visornic_rx(struct uiscmdrsp *cmdrsp) skb = cmdrsp->net.buf; netdev = skb->dev; - if (!netdev) { - /* We must have previously downed this network device and - * this skb and device is no longer valid. This also means - * the skb reference was removed from devdata->rcvbuf so no - * need to search for it. - * All we can do is free the skb and return. - * Note: We crash if we try to log this here. - */ - kfree_skb(skb); - return; - } - devdata = netdev_priv(netdev); spin_lock_irqsave(&devdata->priv_lock, flags); -- cgit v1.3-6-gb490 From e4a143392686432d147e055e45f09049c09f6755 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:14 +0200 Subject: staging: rtl8192e: Rename PHY_RF8256_Config Use naming schema found in other rtlwifi devices. Rename PHY_RF8256_Config to rtl92e_config_rf. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index f3eb1dc3da73..3b8240becd10 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -232,7 +232,7 @@ phy_RF8256_Config_ParaFile_Fail: return false; } -bool PHY_RF8256_Config(struct net_device *dev) +bool rtl92e_config_rf(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h index d9348d92af26..6cd0c2ef63de 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h @@ -23,7 +23,7 @@ #define RTL819X_TOTAL_RF_PATH 2 extern void PHY_SetRF8256Bandwidth(struct net_device *dev, enum ht_channel_width Bandwidth); -extern bool PHY_RF8256_Config(struct net_device *dev); +extern bool rtl92e_config_rf(struct net_device *dev); extern void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel); extern void PHY_SetRF8256OFDMTxPower(struct net_device *dev, u8 powerlevel); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 32135235f3e2..032b7dd2ef54 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -568,7 +568,7 @@ static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) (enum rf90_radio_path)0); if (!rtStatus) { RT_TRACE((COMP_ERR | COMP_PHY), - "PHY_RF8256_Config():Check PHY%d Fail!!\n", + "rtl92e_config_rf():Check PHY%d Fail!!\n", eCheckItem-1); return rtStatus; } @@ -699,7 +699,7 @@ bool rtl8192_phy_RFConfig(struct net_device *dev) case RF_8225: break; case RF_8256: - rtStatus = PHY_RF8256_Config(dev); + rtStatus = rtl92e_config_rf(dev); break; case RF_8258: -- cgit v1.3-6-gb490 From 766b0128266a264395f07830dfad078e1e83d57c Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:15 +0200 Subject: staging: rtl8192e: Rename PHY_SetRF8256Bandwidth Use naming schema found in other rtlwifi devices. Rename PHY_SetRF8256Bandwidth to rtl92e_set_bandwidth. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index 3b8240becd10..53d845f25028 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -22,8 +22,8 @@ #include "r8192E_phy.h" #include "r8190P_rtl8256.h" -void PHY_SetRF8256Bandwidth(struct net_device *dev, - enum ht_channel_width Bandwidth) +void rtl92e_set_bandwidth(struct net_device *dev, + enum ht_channel_width Bandwidth) { u8 eRFPath; struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h index 6cd0c2ef63de..37b336310543 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h @@ -21,8 +21,8 @@ #define RTL8225H #define RTL819X_TOTAL_RF_PATH 2 -extern void PHY_SetRF8256Bandwidth(struct net_device *dev, - enum ht_channel_width Bandwidth); +extern void rtl92e_set_bandwidth(struct net_device *dev, + enum ht_channel_width Bandwidth); extern bool rtl92e_config_rf(struct net_device *dev); extern void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel); extern void PHY_SetRF8256OFDMTxPower(struct net_device *dev, u8 powerlevel); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 032b7dd2ef54..f48f2e2d2566 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -1249,7 +1249,7 @@ static void rtl8192_SetBWModeWorkItem(struct net_device *dev) break; case RF_8256: - PHY_SetRF8256Bandwidth(dev, priv->CurrentChannelBW); + rtl92e_set_bandwidth(dev, priv->CurrentChannelBW); break; case RF_8258: -- cgit v1.3-6-gb490 From abfda5886b8bd3569330fae5b1224488375a5c48 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:16 +0200 Subject: staging: rtl8192e: Rename PHY_SetRF8256CCKTxPower Use naming schema found in other rtlwifi devices. Rename PHY_SetRF8256CCKTxPower to rtl92e_set_cck_tx_power. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index 53d845f25028..daa0619cd7dc 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -240,7 +240,7 @@ bool rtl92e_config_rf(struct net_device *dev) return phy_RF8256_Config_ParaFile(dev); } -void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel) +void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel) { u32 TxAGC = 0; struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h index 37b336310543..1f39799683d9 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h @@ -24,7 +24,7 @@ extern void rtl92e_set_bandwidth(struct net_device *dev, enum ht_channel_width Bandwidth); extern bool rtl92e_config_rf(struct net_device *dev); -extern void PHY_SetRF8256CCKTxPower(struct net_device *dev, u8 powerlevel); +extern void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel); extern void PHY_SetRF8256OFDMTxPower(struct net_device *dev, u8 powerlevel); #endif diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index f48f2e2d2566..f05a88402855 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -679,7 +679,7 @@ void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel) case RF_8225: break; case RF_8256: - PHY_SetRF8256CCKTxPower(dev, powerlevel); + rtl92e_set_cck_tx_power(dev, powerlevel); PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G); break; case RF_8258: @@ -794,7 +794,7 @@ static void rtl8192_SetTxPowerLevel(struct net_device *dev, u8 channel) break; case RF_8256: - PHY_SetRF8256CCKTxPower(dev, powerlevel); + rtl92e_set_cck_tx_power(dev, powerlevel); PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G); break; -- cgit v1.3-6-gb490 From 2497ef5b54914d0e90a7a308e442b81d42b0e373 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:17 +0200 Subject: staging: rtl8192e: Rename PHY_SetRF8256OFDMTxPower Use naming schema found in other rtlwifi devices. Rename PHY_SetRF8256OFDMTxPower to rtl92e_set_ofdm_tx_power. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index daa0619cd7dc..b3b72e59d366 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -258,7 +258,7 @@ void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel) } -void PHY_SetRF8256OFDMTxPower(struct net_device *dev, u8 powerlevel) +void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel) { struct r8192_priv *priv = rtllib_priv(dev); u32 writeVal, powerBase0, powerBase1, writeVal_tmp; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h index 1f39799683d9..5af837f969b8 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.h @@ -25,6 +25,6 @@ extern void rtl92e_set_bandwidth(struct net_device *dev, enum ht_channel_width Bandwidth); extern bool rtl92e_config_rf(struct net_device *dev); extern void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel); -extern void PHY_SetRF8256OFDMTxPower(struct net_device *dev, u8 powerlevel); +extern void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel); #endif diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index f05a88402855..5d493c6b56ea 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -680,7 +680,7 @@ void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel) break; case RF_8256: rtl92e_set_cck_tx_power(dev, powerlevel); - PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G); + rtl92e_set_ofdm_tx_power(dev, powerlevelOFDM24G); break; case RF_8258: break; @@ -795,7 +795,7 @@ static void rtl8192_SetTxPowerLevel(struct net_device *dev, u8 channel) case RF_8256: rtl92e_set_cck_tx_power(dev, powerlevel); - PHY_SetRF8256OFDMTxPower(dev, powerlevelOFDM24G); + rtl92e_set_ofdm_tx_power(dev, powerlevelOFDM24G); break; case RF_8258: -- cgit v1.3-6-gb490 From 12656e2b8c308d86dbb3b9167db0309f27f90d4f Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:18 +0200 Subject: staging: rtl8192e: Rename cmpk_message_handle_tx Use naming schema found in other rtlwifi devices. Rename cmpk_message_handle_tx to rtl92e_send_cmd_pkt. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c | 7 ++----- drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h | 5 ++--- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 5 ++--- 3 files changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c index ebd08a16685e..0d9c74d86b15 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c @@ -21,11 +21,8 @@ #include "r8192E_hw.h" #include "r8192E_cmdpkt.h" -bool cmpk_message_handle_tx( - struct net_device *dev, - u8 *code_virtual_address, - u32 packettype, - u32 buffer_len) +bool rtl92e_send_cmd_pkt(struct net_device *dev, u8 *code_virtual_address, + u32 packettype, u32 buffer_len) { bool rt_status = true; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h index f714d5100059..5718fd8fd118 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.h @@ -19,7 +19,6 @@ #ifndef R819XUSB_CMDPKT_H #define R819XUSB_CMDPKT_H -extern bool cmpk_message_handle_tx(struct net_device *dev, - u8 *codevirtualaddress, u32 packettype, - u32 buffer_len); +extern bool rtl92e_send_cmd_pkt(struct net_device *dev, u8 *codevirtualaddress, + u32 packettype, u32 buffer_len); #endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index c2367128c594..47ead3732a2b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -674,9 +674,8 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) tx_cmd.Op = TXCMD_SET_TX_PWR_TRACKING; tx_cmd.Length = 4; tx_cmd.Value = Value; - cmpk_message_handle_tx(dev, (u8 *)&tx_cmd, - DESC_PACKET_TYPE_INIT, - sizeof(struct dcmd_txcmd)); + rtl92e_send_cmd_pkt(dev, (u8 *)&tx_cmd, DESC_PACKET_TYPE_INIT, + sizeof(struct dcmd_txcmd)); mdelay(1); for (i = 0; i <= 30; i++) { Pwr_Flag = read_nic_byte(dev, Pw_Track_Flag); -- cgit v1.3-6-gb490 From 460266292de1c3770bad54f48e5b33a5fed342e1 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:19 +0200 Subject: staging: rtl8192e: Rename rtl8192_adapter_start Use naming schema found in other rtlwifi devices. Rename rtl8192_adapter_start to rtl92e_start_adapter. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index eb919b634e3c..2bc53ad2b4c7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -702,7 +702,7 @@ static void rtl8192_hwconfig(struct net_device *dev) priv->LongRetryLimit << RETRY_LIMIT_LONG_SHIFT); } -bool rtl8192_adapter_start(struct net_device *dev) +bool rtl92e_start_adapter(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); u32 ulRegRead; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 4f1b312e90f4..48fbd4e516f6 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -42,7 +42,7 @@ void rtl8192_InitializeVariables(struct net_device *dev); void rtl8192e_start_beacon(struct net_device *dev); void rtl8192e_SetHwReg(struct net_device *dev, u8 variable, u8 *val); void rtl8192_get_eeprom_size(struct net_device *dev); -bool rtl8192_adapter_start(struct net_device *dev); +bool rtl92e_start_adapter(struct net_device *dev); void rtl8192_link_change(struct net_device *dev); void rtl8192_AllowAllDestAddr(struct net_device *dev, bool bAllowAllDA, bool WriteIntoReg); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index ca8406bba26d..c5028cc01f34 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -46,7 +46,7 @@ static struct rtl819x_ops rtl819xp_ops = { .nic_type = NIC_8192E, .get_eeprom_size = rtl8192_get_eeprom_size, .init_adapter_variable = rtl8192_InitializeVariables, - .initialize_adapter = rtl8192_adapter_start, + .initialize_adapter = rtl92e_start_adapter, .link_change = rtl8192_link_change, .tx_fill_descriptor = rtl8192_tx_fill_desc, .tx_fill_cmd_descriptor = rtl8192_tx_fill_cmd_desc, -- cgit v1.3-6-gb490 From 33e1748d8f10b2b4d84a18431999cdf2830ccc71 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:20 +0200 Subject: staging: rtl8192e: Rename rtl8192_AllowAllDestAddr Use naming schema found in other rtlwifi devices. Rename rtl8192_AllowAllDestAddr to rtl92e_set_monitor_mode. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 2bc53ad2b4c7..008782ec5447 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1023,8 +1023,8 @@ void rtl8192_link_change(struct net_device *dev) } } -void rtl8192_AllowAllDestAddr(struct net_device *dev, - bool bAllowAllDA, bool WriteIntoReg) +void rtl92e_set_monitor_mode(struct net_device *dev, bool bAllowAllDA, + bool WriteIntoReg) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 48fbd4e516f6..262f3b233a48 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -44,8 +44,8 @@ void rtl8192e_SetHwReg(struct net_device *dev, u8 variable, u8 *val); void rtl8192_get_eeprom_size(struct net_device *dev); bool rtl92e_start_adapter(struct net_device *dev); void rtl8192_link_change(struct net_device *dev); -void rtl8192_AllowAllDestAddr(struct net_device *dev, bool bAllowAllDA, - bool WriteIntoReg); +void rtl92e_set_monitor_mode(struct net_device *dev, bool bAllowAllDA, + bool WriteIntoReg); void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, struct cb_desc *cb_desc, struct sk_buff *skb); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index c5028cc01f34..2ec43b503124 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -891,7 +891,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) rtl8192_GetHalfNmodeSupportByAPs; priv->rtllib->SetHwRegHandler = rtl8192e_SetHwReg; - priv->rtllib->AllowAllDestAddrHandler = rtl8192_AllowAllDestAddr; + priv->rtllib->AllowAllDestAddrHandler = rtl92e_set_monitor_mode; priv->rtllib->SetFwCmdHandler = NULL; priv->rtllib->InitialGainHandler = InitialGain819xPci; priv->rtllib->rtllib_ips_leave_wq = rtllib_ips_leave_wq; -- cgit v1.3-6-gb490 From dc578b417facaef65f3e73ba7f97394979cc64a2 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:21 +0200 Subject: staging: rtl8192e: Rename rtl8192_ClearInterrupt Use naming schema found in other rtlwifi devices. Rename rtl8192_ClearInterrupt to rtl92e_clear_irq. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 008782ec5447..0a60b0718ec2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2246,7 +2246,7 @@ void rtl8192_DisableInterrupt(struct net_device *dev) priv->irq_enabled = 0; } -void rtl8192_ClearInterrupt(struct net_device *dev) +void rtl92e_clear_irq(struct net_device *dev) { u32 tmp = 0; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 262f3b233a48..ed38b5711656 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -37,7 +37,7 @@ void rtl8192_enable_rx(struct net_device *dev); void rtl8192_enable_tx(struct net_device *dev); void rtl8192_EnableInterrupt(struct net_device *dev); void rtl8192_DisableInterrupt(struct net_device *dev); -void rtl8192_ClearInterrupt(struct net_device *dev); +void rtl92e_clear_irq(struct net_device *dev); void rtl8192_InitializeVariables(struct net_device *dev); void rtl8192e_start_beacon(struct net_device *dev); void rtl8192e_SetHwReg(struct net_device *dev, u8 variable, u8 *val); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 2ec43b503124..708f7331de34 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -56,7 +56,7 @@ static struct rtl819x_ops rtl819xp_ops = { .update_ratr_table = rtl8192_update_ratr_table, .irq_enable = rtl8192_EnableInterrupt, .irq_disable = rtl8192_DisableInterrupt, - .irq_clear = rtl8192_ClearInterrupt, + .irq_clear = rtl92e_clear_irq, .rx_enable = rtl8192_enable_rx, .tx_enable = rtl8192_enable_tx, .interrupt_recognized = rtl8192_interrupt_recognized, -- cgit v1.3-6-gb490 From baadea565daae4cfaa46e0764bef3541c949616c Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:22 +0200 Subject: staging: rtl8192e: Rename rtl8192_DisableInterrupt Use naming schema found in other rtlwifi devices. Rename rtl8192_DisableInterrupt to rtl92e_disable_irq. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 0a60b0718ec2..d4f6e1048dcc 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2237,7 +2237,7 @@ void rtl8192_EnableInterrupt(struct net_device *dev) } -void rtl8192_DisableInterrupt(struct net_device *dev) +void rtl92e_disable_irq(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index ed38b5711656..cb900f68a259 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -36,7 +36,7 @@ void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, void rtl8192_enable_rx(struct net_device *dev); void rtl8192_enable_tx(struct net_device *dev); void rtl8192_EnableInterrupt(struct net_device *dev); -void rtl8192_DisableInterrupt(struct net_device *dev); +void rtl92e_disable_irq(struct net_device *dev); void rtl92e_clear_irq(struct net_device *dev); void rtl8192_InitializeVariables(struct net_device *dev); void rtl8192e_start_beacon(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 708f7331de34..998ebf9fc150 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -55,7 +55,7 @@ static struct rtl819x_ops rtl819xp_ops = { .stop_adapter = rtl8192_halt_adapter, .update_ratr_table = rtl8192_update_ratr_table, .irq_enable = rtl8192_EnableInterrupt, - .irq_disable = rtl8192_DisableInterrupt, + .irq_disable = rtl92e_disable_irq, .irq_clear = rtl92e_clear_irq, .rx_enable = rtl8192_enable_rx, .tx_enable = rtl8192_enable_tx, -- cgit v1.3-6-gb490 From 6d99c68e6f50241fe400b744b515dcfac6341239 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:23 +0200 Subject: staging: rtl8192e: Rename rtl8192_EnableInterrupt Use naming schema found in other rtlwifi devices. Rename rtl8192_EnableInterrupt to rtl92e_enable_irq. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index d4f6e1048dcc..b2bf58e73434 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2227,7 +2227,7 @@ rtl8192_InitializeVariables(struct net_device *dev) priv->bfirst_after_down = false; } -void rtl8192_EnableInterrupt(struct net_device *dev) +void rtl92e_enable_irq(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index cb900f68a259..3d717a40bf8b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -35,7 +35,7 @@ void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, u32 *p_intb); void rtl8192_enable_rx(struct net_device *dev); void rtl8192_enable_tx(struct net_device *dev); -void rtl8192_EnableInterrupt(struct net_device *dev); +void rtl92e_enable_irq(struct net_device *dev); void rtl92e_disable_irq(struct net_device *dev); void rtl92e_clear_irq(struct net_device *dev); void rtl8192_InitializeVariables(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 998ebf9fc150..dd7b0dc258b1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -54,7 +54,7 @@ static struct rtl819x_ops rtl819xp_ops = { .rx_command_packet_handler = NULL, .stop_adapter = rtl8192_halt_adapter, .update_ratr_table = rtl8192_update_ratr_table, - .irq_enable = rtl8192_EnableInterrupt, + .irq_enable = rtl92e_enable_irq, .irq_disable = rtl92e_disable_irq, .irq_clear = rtl92e_clear_irq, .rx_enable = rtl8192_enable_rx, -- cgit v1.3-6-gb490 From 78c352b2b22348f28edda51fae2d61928fae4450 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:24 +0200 Subject: staging: rtl8192e: Rename rtl8192_enable_rx Use naming schema found in other rtlwifi devices. Rename rtl8192_enable_rx to rtl92e_enable_rx. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index b2bf58e73434..7aa566705308 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2255,7 +2255,7 @@ void rtl92e_clear_irq(struct net_device *dev) } -void rtl8192_enable_rx(struct net_device *dev) +void rtl92e_enable_rx(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 3d717a40bf8b..94755c425357 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -33,7 +33,7 @@ bool rtl8192_HalTxCheckStuck(struct net_device *dev); bool rtl8192_HalRxCheckStuck(struct net_device *dev); void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, u32 *p_intb); -void rtl8192_enable_rx(struct net_device *dev); +void rtl92e_enable_rx(struct net_device *dev); void rtl8192_enable_tx(struct net_device *dev); void rtl92e_enable_irq(struct net_device *dev); void rtl92e_disable_irq(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index dd7b0dc258b1..1352c98ed454 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -57,7 +57,7 @@ static struct rtl819x_ops rtl819xp_ops = { .irq_enable = rtl92e_enable_irq, .irq_disable = rtl92e_disable_irq, .irq_clear = rtl92e_clear_irq, - .rx_enable = rtl8192_enable_rx, + .rx_enable = rtl92e_enable_rx, .tx_enable = rtl8192_enable_tx, .interrupt_recognized = rtl8192_interrupt_recognized, .TxCheckStuckHandler = rtl8192_HalTxCheckStuck, -- cgit v1.3-6-gb490 From 6af7a8b662f6bb5498d6a59b9dbb2b26855add8b Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:25 +0200 Subject: staging: rtl8192e: Rename rtl8192_enable_tx Use naming schema found in other rtlwifi devices. Rename rtl8192_enable_tx to rtl92e_enable_tx. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 7aa566705308..c779ee781a27 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2266,7 +2266,7 @@ static const u32 TX_DESC_BASE[] = { BKQDA, BEQDA, VIQDA, VOQDA, HCCAQDA, CQDA, MQDA, HQDA, BQDA }; -void rtl8192_enable_tx(struct net_device *dev) +void rtl92e_enable_tx(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); u32 i; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 94755c425357..75f500a8633e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -34,7 +34,7 @@ bool rtl8192_HalRxCheckStuck(struct net_device *dev); void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, u32 *p_intb); void rtl92e_enable_rx(struct net_device *dev); -void rtl8192_enable_tx(struct net_device *dev); +void rtl92e_enable_tx(struct net_device *dev); void rtl92e_enable_irq(struct net_device *dev); void rtl92e_disable_irq(struct net_device *dev); void rtl92e_clear_irq(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 1352c98ed454..eb0be6d64ca3 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -58,7 +58,7 @@ static struct rtl819x_ops rtl819xp_ops = { .irq_disable = rtl92e_disable_irq, .irq_clear = rtl92e_clear_irq, .rx_enable = rtl92e_enable_rx, - .tx_enable = rtl8192_enable_tx, + .tx_enable = rtl92e_enable_tx, .interrupt_recognized = rtl8192_interrupt_recognized, .TxCheckStuckHandler = rtl8192_HalTxCheckStuck, .RxCheckStuckHandler = rtl8192_HalRxCheckStuck, -- cgit v1.3-6-gb490 From 61fea239c818631d6f8252c00ffdde60e92c3ad0 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:26 +0200 Subject: staging: rtl8192e: Rename rtl8192e_SetHwReg Use naming schema found in other rtlwifi devices. Rename rtl8192e_SetHwReg to rtl92e_set_reg. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index c779ee781a27..95e7b28e8929 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -95,7 +95,7 @@ static void rtl8192e_update_msr(struct net_device *dev) priv->rtllib->LedControlHandler(dev, LedAction); } -void rtl8192e_SetHwReg(struct net_device *dev, u8 variable, u8 *val) +void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 75f500a8633e..436d9d7d50ff 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -40,7 +40,7 @@ void rtl92e_disable_irq(struct net_device *dev); void rtl92e_clear_irq(struct net_device *dev); void rtl8192_InitializeVariables(struct net_device *dev); void rtl8192e_start_beacon(struct net_device *dev); -void rtl8192e_SetHwReg(struct net_device *dev, u8 variable, u8 *val); +void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val); void rtl8192_get_eeprom_size(struct net_device *dev); bool rtl92e_start_adapter(struct net_device *dev); void rtl8192_link_change(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index eb0be6d64ca3..83b0cea26f25 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -890,7 +890,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->GetHalfNmodeSupportByAPsHandler = rtl8192_GetHalfNmodeSupportByAPs; - priv->rtllib->SetHwRegHandler = rtl8192e_SetHwReg; + priv->rtllib->SetHwRegHandler = rtl92e_set_reg; priv->rtllib->AllowAllDestAddrHandler = rtl92e_set_monitor_mode; priv->rtllib->SetFwCmdHandler = NULL; priv->rtllib->InitialGainHandler = InitialGain819xPci; -- cgit v1.3-6-gb490 From 89d4a8be6294b8ab7ef218034f5b52f045b31876 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:27 +0200 Subject: staging: rtl8192e: Rename rtl8192e_start_beacon Use naming schema found in other rtlwifi devices. Rename rtl8192e_start_beacon to rtl92e_start_beacon. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 95e7b28e8929..f96923ca278b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -33,7 +33,7 @@ static int WDCAPARA_ADD[] = {EDCAPARA_BE, EDCAPARA_BK, EDCAPARA_VI, EDCAPARA_VO}; -void rtl8192e_start_beacon(struct net_device *dev) +void rtl92e_start_beacon(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); struct rtllib_network *net = &priv->rtllib->current_network; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 436d9d7d50ff..5b9b4dfa55ce 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -39,7 +39,7 @@ void rtl92e_enable_irq(struct net_device *dev); void rtl92e_disable_irq(struct net_device *dev); void rtl92e_clear_irq(struct net_device *dev); void rtl8192_InitializeVariables(struct net_device *dev); -void rtl8192e_start_beacon(struct net_device *dev); +void rtl92e_start_beacon(struct net_device *dev); void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val); void rtl8192_get_eeprom_size(struct net_device *dev); bool rtl92e_start_adapter(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 83b0cea26f25..3a824b4d23e8 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -879,7 +879,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->SetBWModeHandler = rtl8192_SetBWMode; priv->rf_set_chan = rtl8192_phy_SwChnl; - priv->rtllib->start_send_beacons = rtl8192e_start_beacon; + priv->rtllib->start_send_beacons = rtl92e_start_beacon; priv->rtllib->stop_send_beacons = rtl8192_stop_beacon; priv->rtllib->sta_wake_up = rtl8192_hw_wakeup; -- cgit v1.3-6-gb490 From b095be37004f91f6eecb70cd62da6cc2c2483b87 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:28 +0200 Subject: staging: rtl8192e: Rename rtl8192_get_eeprom_size Use naming schema found in other rtlwifi devices. Rename rtl8192_get_eeprom_size to rtl92e_get_eeprom_size. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index f96923ca278b..5fd414e8a984 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -625,7 +625,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) RT_TRACE(COMP_TRACE, "<==== ReadAdapterInfo\n"); } -void rtl8192_get_eeprom_size(struct net_device *dev) +void rtl92e_get_eeprom_size(struct net_device *dev) { u16 curCR; struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 5b9b4dfa55ce..8551f1938114 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -41,7 +41,7 @@ void rtl92e_clear_irq(struct net_device *dev); void rtl8192_InitializeVariables(struct net_device *dev); void rtl92e_start_beacon(struct net_device *dev); void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val); -void rtl8192_get_eeprom_size(struct net_device *dev); +void rtl92e_get_eeprom_size(struct net_device *dev); bool rtl92e_start_adapter(struct net_device *dev); void rtl8192_link_change(struct net_device *dev); void rtl92e_set_monitor_mode(struct net_device *dev, bool bAllowAllDA, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 3a824b4d23e8..04c2f38312b2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -44,7 +44,7 @@ static char *ifname = "wlan%d"; static struct rtl819x_ops rtl819xp_ops = { .nic_type = NIC_8192E, - .get_eeprom_size = rtl8192_get_eeprom_size, + .get_eeprom_size = rtl92e_get_eeprom_size, .init_adapter_variable = rtl8192_InitializeVariables, .initialize_adapter = rtl92e_start_adapter, .link_change = rtl8192_link_change, -- cgit v1.3-6-gb490 From 86534a29bb68273a98b1e1c739ea58bf9a93e64a Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:29 +0200 Subject: staging: rtl8192e: Rename rtl8192_GetHalfNmodeSupportByAPs Use naming schema found in other rtlwifi devices. Rename rtl8192_GetHalfNmodeSupportByAPs to rtl92e_is_halfn_supported_by_ap. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 5fd414e8a984..301e7504e3fc 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2378,7 +2378,7 @@ bool rtl8192_GetNmodeSupportBySecCfg(struct net_device *dev) } } -bool rtl8192_GetHalfNmodeSupportByAPs(struct net_device *dev) +bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev) { bool Reval; struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 8551f1938114..5ad14afdc2a7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -27,7 +27,7 @@ #include "r8190P_def.h" -bool rtl8192_GetHalfNmodeSupportByAPs(struct net_device *dev); +bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev); bool rtl8192_GetNmodeSupportBySecCfg(struct net_device *dev); bool rtl8192_HalTxCheckStuck(struct net_device *dev); bool rtl8192_HalRxCheckStuck(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 04c2f38312b2..df9e4cf9cc30 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -888,7 +888,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->GetNmodeSupportBySecCfg = rtl8192_GetNmodeSupportBySecCfg; priv->rtllib->GetHalfNmodeSupportByAPsHandler = - rtl8192_GetHalfNmodeSupportByAPs; + rtl92e_is_halfn_supported_by_ap; priv->rtllib->SetHwRegHandler = rtl92e_set_reg; priv->rtllib->AllowAllDestAddrHandler = rtl92e_set_monitor_mode; -- cgit v1.3-6-gb490 From 56a5b5af61ac1d55cc3e0b19557e0c774338cf44 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:30 +0200 Subject: staging: rtl8192e: Rename rtl8192_GetNmodeSupportBySecCfg Use naming schema found in other rtlwifi devices. Rename rtl8192_GetNmodeSupportBySecCfg to rtl92e_get_nmode_support_by_sec. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 301e7504e3fc..7129110eb7a4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2364,7 +2364,7 @@ bool rtl8192_HalTxCheckStuck(struct net_device *dev) return bStuck; } -bool rtl8192_GetNmodeSupportBySecCfg(struct net_device *dev) +bool rtl92e_get_nmode_support_by_sec(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); struct rtllib_device *ieee = priv->rtllib; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 5ad14afdc2a7..a77da0a08e8e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -28,7 +28,7 @@ #include "r8190P_def.h" bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev); -bool rtl8192_GetNmodeSupportBySecCfg(struct net_device *dev); +bool rtl92e_get_nmode_support_by_sec(struct net_device *dev); bool rtl8192_HalTxCheckStuck(struct net_device *dev); bool rtl8192_HalRxCheckStuck(struct net_device *dev); void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index df9e4cf9cc30..87d4e46f5a1e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -886,7 +886,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->enter_sleep_state = rtl8192_hw_to_sleep; priv->rtllib->ps_is_queue_empty = rtl8192_is_tx_queue_empty; - priv->rtllib->GetNmodeSupportBySecCfg = rtl8192_GetNmodeSupportBySecCfg; + priv->rtllib->GetNmodeSupportBySecCfg = rtl92e_get_nmode_support_by_sec; priv->rtllib->GetHalfNmodeSupportByAPsHandler = rtl92e_is_halfn_supported_by_ap; -- cgit v1.3-6-gb490 From 4d73bd2636f51aee9c541b2294518af11d5396e4 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:31 +0200 Subject: staging: rtl8192e: Rename rtl8192_HalRxCheckStuck Use naming schema found in other rtlwifi devices. Rename rtl8192_HalRxCheckStuck to rtl92e_is_rx_stuck. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 7129110eb7a4..c015bea2db5c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2283,7 +2283,7 @@ void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, write_nic_dword(dev, ISR, *p_inta); } -bool rtl8192_HalRxCheckStuck(struct net_device *dev) +bool rtl92e_is_rx_stuck(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); u16 RegRxCounter = read_nic_word(dev, 0x130); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index a77da0a08e8e..1182c9c08f18 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -30,7 +30,7 @@ bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev); bool rtl92e_get_nmode_support_by_sec(struct net_device *dev); bool rtl8192_HalTxCheckStuck(struct net_device *dev); -bool rtl8192_HalRxCheckStuck(struct net_device *dev); +bool rtl92e_is_rx_stuck(struct net_device *dev); void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, u32 *p_intb); void rtl92e_enable_rx(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 87d4e46f5a1e..5cf8de937d45 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -61,7 +61,7 @@ static struct rtl819x_ops rtl819xp_ops = { .tx_enable = rtl92e_enable_tx, .interrupt_recognized = rtl8192_interrupt_recognized, .TxCheckStuckHandler = rtl8192_HalTxCheckStuck, - .RxCheckStuckHandler = rtl8192_HalRxCheckStuck, + .RxCheckStuckHandler = rtl92e_is_rx_stuck, }; static struct pci_device_id rtl8192_pci_id_tbl[] = { -- cgit v1.3-6-gb490 From fe99c77b44e41c64c65ca2d558b26311ae4e6bf3 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:32 +0200 Subject: staging: rtl8192e: Rename rtl8192_halt_adapter Use naming schema found in other rtlwifi devices. Rename rtl8192_halt_adapter to rtl92e_stop_adapter. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index c015bea2db5c..01059ef5eeaa 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2098,7 +2098,7 @@ bool rtl8192_rx_query_status_desc(struct net_device *dev, return true; } -void rtl8192_halt_adapter(struct net_device *dev, bool reset) +void rtl92e_stop_adapter(struct net_device *dev, bool reset) { struct r8192_priv *priv = rtllib_priv(dev); int i; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 1182c9c08f18..455eed397e82 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -56,6 +56,6 @@ bool rtl8192_rx_query_status_desc(struct net_device *dev, struct rtllib_rx_stats *stats, struct rx_desc *pdesc, struct sk_buff *skb); -void rtl8192_halt_adapter(struct net_device *dev, bool reset); +void rtl92e_stop_adapter(struct net_device *dev, bool reset); void rtl8192_update_ratr_table(struct net_device *dev); #endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 5cf8de937d45..181c2840223e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -52,7 +52,7 @@ static struct rtl819x_ops rtl819xp_ops = { .tx_fill_cmd_descriptor = rtl8192_tx_fill_cmd_desc, .rx_query_status_descriptor = rtl8192_rx_query_status_desc, .rx_command_packet_handler = NULL, - .stop_adapter = rtl8192_halt_adapter, + .stop_adapter = rtl92e_stop_adapter, .update_ratr_table = rtl8192_update_ratr_table, .irq_enable = rtl92e_enable_irq, .irq_disable = rtl92e_disable_irq, -- cgit v1.3-6-gb490 From c9cf5e78f3b28e9a1358951a37f2bd844d46641f Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:33 +0200 Subject: staging: rtl8192e: Rename rtl8192_HalTxCheckStuck Use naming schema found in other rtlwifi devices. Rename rtl8192_HalTxCheckStuck to rtl92e_is_tx_stuck. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 01059ef5eeaa..8e50128bb1d9 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2347,7 +2347,7 @@ bool rtl92e_is_rx_stuck(struct net_device *dev) return bStuck; } -bool rtl8192_HalTxCheckStuck(struct net_device *dev) +bool rtl92e_is_tx_stuck(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); bool bStuck = false; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 455eed397e82..6c37c4051157 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -29,7 +29,7 @@ bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev); bool rtl92e_get_nmode_support_by_sec(struct net_device *dev); -bool rtl8192_HalTxCheckStuck(struct net_device *dev); +bool rtl92e_is_tx_stuck(struct net_device *dev); bool rtl92e_is_rx_stuck(struct net_device *dev); void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, u32 *p_intb); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 181c2840223e..960131306925 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -60,7 +60,7 @@ static struct rtl819x_ops rtl819xp_ops = { .rx_enable = rtl92e_enable_rx, .tx_enable = rtl92e_enable_tx, .interrupt_recognized = rtl8192_interrupt_recognized, - .TxCheckStuckHandler = rtl8192_HalTxCheckStuck, + .TxCheckStuckHandler = rtl92e_is_tx_stuck, .RxCheckStuckHandler = rtl92e_is_rx_stuck, }; -- cgit v1.3-6-gb490 From df85a1313fee7d15db8100cd9a681d484c0c0b7b Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:34 +0200 Subject: staging: rtl8192e: Rename rtl8192_InitializeVariables Use naming schema found in other rtlwifi devices. Rename rtl8192_InitializeVariables to rtl92e_init_variables. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 8e50128bb1d9..9424909bebcb 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2193,7 +2193,7 @@ void rtl8192_update_ratr_table(struct net_device *dev) } void -rtl8192_InitializeVariables(struct net_device *dev) +rtl92e_init_variables(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 6c37c4051157..a943ae260291 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -38,7 +38,7 @@ void rtl92e_enable_tx(struct net_device *dev); void rtl92e_enable_irq(struct net_device *dev); void rtl92e_disable_irq(struct net_device *dev); void rtl92e_clear_irq(struct net_device *dev); -void rtl8192_InitializeVariables(struct net_device *dev); +void rtl92e_init_variables(struct net_device *dev); void rtl92e_start_beacon(struct net_device *dev); void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val); void rtl92e_get_eeprom_size(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 960131306925..4bcb88b0e798 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -45,7 +45,7 @@ static char *ifname = "wlan%d"; static struct rtl819x_ops rtl819xp_ops = { .nic_type = NIC_8192E, .get_eeprom_size = rtl92e_get_eeprom_size, - .init_adapter_variable = rtl8192_InitializeVariables, + .init_adapter_variable = rtl92e_init_variables, .initialize_adapter = rtl92e_start_adapter, .link_change = rtl8192_link_change, .tx_fill_descriptor = rtl8192_tx_fill_desc, -- cgit v1.3-6-gb490 From a57165d15dae6fc6a3fb6b8d9d15075816bfbbd3 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:35 +0200 Subject: staging: rtl8192e: Rename rtl8192_interrupt_recognized Use naming schema found in other rtlwifi devices. Rename rtl8192_interrupt_recognized to rtl92e_ack_irq. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 3 +-- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 3 +-- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 9424909bebcb..a8f1521f1293 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2276,8 +2276,7 @@ void rtl92e_enable_tx(struct net_device *dev) } -void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, - u32 *p_intb) +void rtl92e_ack_irq(struct net_device *dev, u32 *p_inta, u32 *p_intb) { *p_inta = read_nic_dword(dev, ISR); write_nic_dword(dev, ISR, *p_inta); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index a943ae260291..35a9d3a8dfae 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -31,8 +31,7 @@ bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev); bool rtl92e_get_nmode_support_by_sec(struct net_device *dev); bool rtl92e_is_tx_stuck(struct net_device *dev); bool rtl92e_is_rx_stuck(struct net_device *dev); -void rtl8192_interrupt_recognized(struct net_device *dev, u32 *p_inta, - u32 *p_intb); +void rtl92e_ack_irq(struct net_device *dev, u32 *p_inta, u32 *p_intb); void rtl92e_enable_rx(struct net_device *dev); void rtl92e_enable_tx(struct net_device *dev); void rtl92e_enable_irq(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 4bcb88b0e798..5256595d4614 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -59,7 +59,7 @@ static struct rtl819x_ops rtl819xp_ops = { .irq_clear = rtl92e_clear_irq, .rx_enable = rtl92e_enable_rx, .tx_enable = rtl92e_enable_tx, - .interrupt_recognized = rtl8192_interrupt_recognized, + .interrupt_recognized = rtl92e_ack_irq, .TxCheckStuckHandler = rtl92e_is_tx_stuck, .RxCheckStuckHandler = rtl92e_is_rx_stuck, }; -- cgit v1.3-6-gb490 From b974b289c4cb8a63b92749ec0c32094609ea571c Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:36 +0200 Subject: staging: rtl8192e: Rename rtl8192_link_change Use naming schema found in other rtlwifi devices. Rename rtl8192_link_change to rtl92e_link_change. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index a8f1521f1293..7ae21d18e96d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -988,7 +988,7 @@ static void rtl8192_net_update(struct net_device *dev) } } -void rtl8192_link_change(struct net_device *dev) +void rtl92e_link_change(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); struct rtllib_device *ieee = priv->rtllib; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 35a9d3a8dfae..4957824131bc 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -42,7 +42,7 @@ void rtl92e_start_beacon(struct net_device *dev); void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val); void rtl92e_get_eeprom_size(struct net_device *dev); bool rtl92e_start_adapter(struct net_device *dev); -void rtl8192_link_change(struct net_device *dev); +void rtl92e_link_change(struct net_device *dev); void rtl92e_set_monitor_mode(struct net_device *dev, bool bAllowAllDA, bool WriteIntoReg); void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 5256595d4614..2149e4de8396 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -47,7 +47,7 @@ static struct rtl819x_ops rtl819xp_ops = { .get_eeprom_size = rtl92e_get_eeprom_size, .init_adapter_variable = rtl92e_init_variables, .initialize_adapter = rtl92e_start_adapter, - .link_change = rtl8192_link_change, + .link_change = rtl92e_link_change, .tx_fill_descriptor = rtl8192_tx_fill_desc, .tx_fill_cmd_descriptor = rtl8192_tx_fill_cmd_desc, .rx_query_status_descriptor = rtl8192_rx_query_status_desc, -- cgit v1.3-6-gb490 From 7897285ceb2864b2073fa3c0526d54187b38a2ec Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:37 +0200 Subject: staging: rtl8192e: Rename rtl8192_rx_query_status_desc Use naming schema found in other rtlwifi devices. Rename rtl8192_rx_query_status_desc to rtl92e_get_rx_stats. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 6 ++---- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 6 ++---- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 7ae21d18e96d..62fff60754a5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2025,10 +2025,8 @@ static void rtl8192_UpdateReceivedRateHistogramStatistics( priv->stats.received_rate_histogram[rcvType][rateIndex]++; } -bool rtl8192_rx_query_status_desc(struct net_device *dev, - struct rtllib_rx_stats *stats, - struct rx_desc *pdesc, - struct sk_buff *skb) +bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats, + struct rx_desc *pdesc, struct sk_buff *skb) { struct r8192_priv *priv = rtllib_priv(dev); struct rx_fwinfo *pDrvInfo = NULL; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 4957824131bc..404125eac358 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -51,10 +51,8 @@ void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, void rtl8192_tx_fill_cmd_desc(struct net_device *dev, struct tx_desc_cmd *entry, struct cb_desc *cb_desc, struct sk_buff *skb); -bool rtl8192_rx_query_status_desc(struct net_device *dev, - struct rtllib_rx_stats *stats, - struct rx_desc *pdesc, - struct sk_buff *skb); +bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats, + struct rx_desc *pdesc, struct sk_buff *skb); void rtl92e_stop_adapter(struct net_device *dev, bool reset); void rtl8192_update_ratr_table(struct net_device *dev); #endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 2149e4de8396..e364f2a927d3 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -50,7 +50,7 @@ static struct rtl819x_ops rtl819xp_ops = { .link_change = rtl92e_link_change, .tx_fill_descriptor = rtl8192_tx_fill_desc, .tx_fill_cmd_descriptor = rtl8192_tx_fill_cmd_desc, - .rx_query_status_descriptor = rtl8192_rx_query_status_desc, + .rx_query_status_descriptor = rtl92e_get_rx_stats, .rx_command_packet_handler = NULL, .stop_adapter = rtl92e_stop_adapter, .update_ratr_table = rtl8192_update_ratr_table, -- cgit v1.3-6-gb490 From 63b544a17c63c0d79cd1e5f1bde1e1df06c1d761 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:38 +0200 Subject: staging: rtl8192e: Rename rtl8192_tx_fill_cmd_desc Use naming schema found in other rtlwifi devices. Rename rtl8192_tx_fill_cmd_desc to rtl92e_fill_tx_cmd_desc. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 5 ++--- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 5 ++--- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 62fff60754a5..bb4a8e62cc95 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1297,9 +1297,8 @@ void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, pdesc->TxBuffAddr = mapping; } -void rtl8192_tx_fill_cmd_desc(struct net_device *dev, - struct tx_desc_cmd *entry, - struct cb_desc *cb_desc, struct sk_buff *skb) +void rtl92e_fill_tx_cmd_desc(struct net_device *dev, struct tx_desc_cmd *entry, + struct cb_desc *cb_desc, struct sk_buff *skb) { struct r8192_priv *priv = rtllib_priv(dev); dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len, diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 404125eac358..a848fcda1324 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -48,9 +48,8 @@ void rtl92e_set_monitor_mode(struct net_device *dev, bool bAllowAllDA, void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, struct cb_desc *cb_desc, struct sk_buff *skb); -void rtl8192_tx_fill_cmd_desc(struct net_device *dev, - struct tx_desc_cmd *entry, - struct cb_desc *cb_desc, struct sk_buff *skb); +void rtl92e_fill_tx_cmd_desc(struct net_device *dev, struct tx_desc_cmd *entry, + struct cb_desc *cb_desc, struct sk_buff *skb); bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats, struct rx_desc *pdesc, struct sk_buff *skb); void rtl92e_stop_adapter(struct net_device *dev, bool reset); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index e364f2a927d3..298d7bd17513 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -49,7 +49,7 @@ static struct rtl819x_ops rtl819xp_ops = { .initialize_adapter = rtl92e_start_adapter, .link_change = rtl92e_link_change, .tx_fill_descriptor = rtl8192_tx_fill_desc, - .tx_fill_cmd_descriptor = rtl8192_tx_fill_cmd_desc, + .tx_fill_cmd_descriptor = rtl92e_fill_tx_cmd_desc, .rx_query_status_descriptor = rtl92e_get_rx_stats, .rx_command_packet_handler = NULL, .stop_adapter = rtl92e_stop_adapter, -- cgit v1.3-6-gb490 From 072b3948d473f8c4602b8aa51cec54bcbd0ecddb Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:39 +0200 Subject: staging: rtl8192e: Rename rtl8192_tx_fill_desc Use naming schema found in other rtlwifi devices. Rename rtl8192_tx_fill_desc to rtl92e_fill_tx_desc. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 5 ++--- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index bb4a8e62cc95..f511fde62202 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1188,8 +1188,8 @@ static u8 rtl8192_QueryIsShort(u8 TxHT, u8 TxRate, struct cb_desc *tcb_desc) return tmp_Short; } -void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, - struct cb_desc *cb_desc, struct sk_buff *skb) +void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc, + struct cb_desc *cb_desc, struct sk_buff *skb) { struct r8192_priv *priv = rtllib_priv(dev); dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len, diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index a848fcda1324..10a16b6935d1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -45,9 +45,8 @@ bool rtl92e_start_adapter(struct net_device *dev); void rtl92e_link_change(struct net_device *dev); void rtl92e_set_monitor_mode(struct net_device *dev, bool bAllowAllDA, bool WriteIntoReg); -void rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc, - struct cb_desc *cb_desc, - struct sk_buff *skb); +void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc, + struct cb_desc *cb_desc, struct sk_buff *skb); void rtl92e_fill_tx_cmd_desc(struct net_device *dev, struct tx_desc_cmd *entry, struct cb_desc *cb_desc, struct sk_buff *skb); bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 298d7bd17513..d7625bac16be 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -48,7 +48,7 @@ static struct rtl819x_ops rtl819xp_ops = { .init_adapter_variable = rtl92e_init_variables, .initialize_adapter = rtl92e_start_adapter, .link_change = rtl92e_link_change, - .tx_fill_descriptor = rtl8192_tx_fill_desc, + .tx_fill_descriptor = rtl92e_fill_tx_desc, .tx_fill_cmd_descriptor = rtl92e_fill_tx_cmd_desc, .rx_query_status_descriptor = rtl92e_get_rx_stats, .rx_command_packet_handler = NULL, -- cgit v1.3-6-gb490 From 575d48c57532465cc0a2c34ebb6ebccdaf1be783 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:40 +0200 Subject: staging: rtl8192e: Rename rtl8192_update_ratr_table Use naming schema found in other rtlwifi devices. Rename rtl8192_update_ratr_table to rtl92e_update_ratr_table. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index f511fde62202..2b2660ad88d7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2142,7 +2142,7 @@ void rtl92e_stop_adapter(struct net_device *dev, bool reset) skb_queue_purge(&priv->skb_queue); } -void rtl8192_update_ratr_table(struct net_device *dev) +void rtl92e_update_ratr_table(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); struct rtllib_device *ieee = priv->rtllib; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h index 10a16b6935d1..6bd6b3a4fcea 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.h @@ -52,5 +52,5 @@ void rtl92e_fill_tx_cmd_desc(struct net_device *dev, struct tx_desc_cmd *entry, bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats, struct rx_desc *pdesc, struct sk_buff *skb); void rtl92e_stop_adapter(struct net_device *dev, bool reset); -void rtl8192_update_ratr_table(struct net_device *dev); +void rtl92e_update_ratr_table(struct net_device *dev); #endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index d7625bac16be..08f2d727dc0f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -53,7 +53,7 @@ static struct rtl819x_ops rtl819xp_ops = { .rx_query_status_descriptor = rtl92e_get_rx_stats, .rx_command_packet_handler = NULL, .stop_adapter = rtl92e_stop_adapter, - .update_ratr_table = rtl8192_update_ratr_table, + .update_ratr_table = rtl92e_update_ratr_table, .irq_enable = rtl92e_enable_irq, .irq_disable = rtl92e_disable_irq, .irq_clear = rtl92e_clear_irq, -- cgit v1.3-6-gb490 From 16362f45166d027d2b488314aa2e99acf6073f30 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:41 +0200 Subject: staging: rtl8192e: Rename firmware_init_param Use naming schema found in other rtlwifi devices. Rename firmware_init_param to rtl92e_init_fw_param. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c index 0d9c74d86b15..28cb9dd7b73c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c @@ -38,7 +38,7 @@ bool rtl92e_send_cmd_pkt(struct net_device *dev, u8 *code_virtual_address, struct tx_fwinfo_8190pci *pTxFwInfo = NULL; RT_TRACE(COMP_CMDPKT, "%s(),buffer_len is %d\n", __func__, buffer_len); - firmware_init_param(dev); + rtl92e_init_fw_param(dev); frag_threshold = pfirmware->cmdpacket_frag_thresold; do { diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c index 17d2a1540cc8..6c11d19c4668 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c @@ -23,7 +23,7 @@ #include "r8192E_firmware.h" #include -void firmware_init_param(struct net_device *dev) +void rtl92e_init_fw_param(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); struct rt_firmware *pfirmware = priv->pFirmware; @@ -46,7 +46,7 @@ static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, struct cb_desc *tcb_desc; u8 bLastIniPkt; - firmware_init_param(dev); + rtl92e_init_fw_param(dev); frag_threshold = pfirmware->cmdpacket_frag_thresold; do { if ((buffer_len - frag_offset) > frag_threshold) { diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h index ef232d2c34e6..131ea005edff 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h @@ -60,6 +60,6 @@ struct rt_firmware { }; bool init_firmware(struct net_device *dev); -extern void firmware_init_param(struct net_device *dev); +extern void rtl92e_init_fw_param(struct net_device *dev); #endif -- cgit v1.3-6-gb490 From dfb7a12773fb81ef0b15bc8f33297fbd6586fd0c Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:42 +0200 Subject: staging: rtl8192e: Rename InitialGain819xPci Use naming schema found in other rtlwifi devices. Rename InitialGain819xPci to rtl92e_init_gain. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 5d493c6b56ea..7a3e34f1c857 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -1295,7 +1295,7 @@ void rtl8192_SetBWMode(struct net_device *dev, enum ht_channel_width Bandwidth, } -void InitialGain819xPci(struct net_device *dev, u8 Operation) +void rtl92e_init_gain(struct net_device *dev, u8 Operation) { #define SCAN_RX_INITIAL_GAIN 0x17 #define POWER_DETECTION_TH 0x08 diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index ef85587c6a12..f4bf9748a28c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -95,7 +95,7 @@ extern u8 rtl8192_phy_SwChnl(struct net_device *dev, u8 channel); extern void rtl8192_SetBWMode(struct net_device *dev, enum ht_channel_width Bandwidth, enum ht_extchnl_offset Offset); -extern void InitialGain819xPci(struct net_device *dev, u8 Operation); +extern void rtl92e_init_gain(struct net_device *dev, u8 Operation); extern void PHY_SetRtl8192eRfOff(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 08f2d727dc0f..c3c578dfe6a6 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -893,7 +893,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->SetHwRegHandler = rtl92e_set_reg; priv->rtllib->AllowAllDestAddrHandler = rtl92e_set_monitor_mode; priv->rtllib->SetFwCmdHandler = NULL; - priv->rtllib->InitialGainHandler = InitialGain819xPci; + priv->rtllib->InitialGainHandler = rtl92e_init_gain; priv->rtllib->rtllib_ips_leave_wq = rtllib_ips_leave_wq; priv->rtllib->rtllib_ips_leave = rtllib_ips_leave; -- cgit v1.3-6-gb490 From 9a44c6e6731d32e0a6efd3f2ddfbc81e4936d8b6 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:43 +0200 Subject: staging: rtl8192e: Rename PHY_ScanOperationBackup8192 Use naming schema found in other rtlwifi devices. Rename PHY_ScanOperationBackup8192 to rtl92e_scan_op_backup. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 7a3e34f1c857..593b5b5b655d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -1611,7 +1611,7 @@ bool SetRFPowerState(struct net_device *dev, return bResult; } -void PHY_ScanOperationBackup8192(struct net_device *dev, u8 Operation) +void rtl92e_scan_op_backup(struct net_device *dev, u8 Operation) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index f4bf9748a28c..58d8463057df 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -106,6 +106,6 @@ SetRFPowerState( ); #define PHY_SetRFPowerState SetRFPowerState -extern void PHY_ScanOperationBackup8192(struct net_device *dev, u8 Operation); +extern void rtl92e_scan_op_backup(struct net_device *dev, u8 Operation); #endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index c3c578dfe6a6..87a53d136bbe 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -900,7 +900,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->LedControlHandler = NULL; priv->rtllib->UpdateBeaconInterruptHandler = NULL; - priv->rtllib->ScanOperationBackupHandler = PHY_ScanOperationBackup8192; + priv->rtllib->ScanOperationBackupHandler = rtl92e_scan_op_backup; } static void rtl8192_init_priv_constant(struct net_device *dev) -- cgit v1.3-6-gb490 From 3803cb215ba6933ca461598ff5ba9a2d629e1d84 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:44 +0200 Subject: staging: rtl8192e: Rename PHY_SetRtl8192eRfOff Use naming schema found in other rtlwifi devices. Rename PHY_SetRtl8192eRfOff to rtl92e_set_rf_off. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 6 +++--- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 2b2660ad88d7..9a8bd1955f74 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2119,7 +2119,7 @@ void rtl92e_stop_adapter(struct net_device *dev, bool reset) priv->bHwRfOffAction = 2; if (!priv->rtllib->bSupportRemoteWakeUp) { - PHY_SetRtl8192eRfOff(dev); + rtl92e_set_rf_off(dev); ulRegRead = read_nic_dword(dev, CPU_GEN); ulRegRead |= CPU_GEN_SYSTEM_RESET; write_nic_dword(dev, CPU_GEN, ulRegRead); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 593b5b5b655d..c674932e2fe8 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -1405,7 +1405,7 @@ void rtl92e_init_gain(struct net_device *dev, u8 Operation) } } -void PHY_SetRtl8192eRfOff(struct net_device *dev) +void rtl92e_set_rf_off(struct net_device *dev) { rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x0); @@ -1511,7 +1511,7 @@ static bool SetRFPowerState8190(struct net_device *dev, break; } } - PHY_SetRtl8192eRfOff(dev); + rtl92e_set_rf_off(dev); break; case eRfOff: @@ -1547,7 +1547,7 @@ static bool SetRFPowerState8190(struct net_device *dev, RT_SET_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC); } else if (!(pPSC->RegRfPsLevel & RT_RF_OFF_LEVL_HALT_NIC)) { - PHY_SetRtl8192eRfOff(dev); + rtl92e_set_rf_off(dev); } break; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 58d8463057df..2f1db77e6aa9 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -97,7 +97,7 @@ extern void rtl8192_SetBWMode(struct net_device *dev, enum ht_extchnl_offset Offset); extern void rtl92e_init_gain(struct net_device *dev, u8 Operation); -extern void PHY_SetRtl8192eRfOff(struct net_device *dev); +extern void rtl92e_set_rf_off(struct net_device *dev); bool SetRFPowerState( -- cgit v1.3-6-gb490 From 2949353dde018594063d20b6dc38cc86b1846729 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:45 +0200 Subject: staging: rtl8192e: Rename rtl8192_BBConfig Use naming schema found in other rtlwifi devices. Rename rtl8192_BBConfig to rtl92e_config_bb. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 9a8bd1955f74..22625950706b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -750,7 +750,7 @@ start: } } RT_TRACE(COMP_INIT, "BB Config Start!\n"); - rtStatus = rtl8192_BBConfig(dev); + rtStatus = rtl92e_config_bb(dev); if (!rtStatus) { netdev_warn(dev, "%s(): Failed to configure BB\n", __func__); return rtStatus; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index c674932e2fe8..3c6916bcea59 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -599,7 +599,7 @@ static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) return rtStatus; } -bool rtl8192_BBConfig(struct net_device *dev) +bool rtl92e_config_bb(struct net_device *dev) { rtl8192_InitBBRFRegDef(dev); return rtl8192_BB_Config_ParaFile(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 2f1db77e6aa9..cd4b242e18e4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -83,7 +83,7 @@ extern void rtl8192_phy_configmac(struct net_device *dev); extern bool rtl8192_phy_checkBBAndRF(struct net_device *dev, enum hw90_block CheckBlock, enum rf90_radio_path eRFPath); -extern bool rtl8192_BBConfig(struct net_device *dev); +extern bool rtl92e_config_bb(struct net_device *dev); extern void rtl8192_phy_getTxPower(struct net_device *dev); extern void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel); extern bool rtl8192_phy_RFConfig(struct net_device *dev); -- cgit v1.3-6-gb490 From e21d14d805bb77b83c100c2df3209909febd379d Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:46 +0200 Subject: staging: rtl8192e: Rename rtl8192_phy_checkBBAndRF Use naming schema found in other rtlwifi devices. Rename rtl8192_phy_checkBBAndRF to rtl92e_check_bb_and_rf. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 11 +++++------ drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 6 +++--- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index b3b72e59d366..0f8bb4833ba1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -127,8 +127,8 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) rtl8192_phy_SetRFReg(dev, (enum rf90_radio_path) eRFPath, 0x0, bMask12Bits, 0xbf); - rtStatus = rtl8192_phy_checkBBAndRF(dev, HW90_BLOCK_RF, - (enum rf90_radio_path)eRFPath); + rtStatus = rtl92e_check_bb_and_rf(dev, HW90_BLOCK_RF, + (enum rf90_radio_path)eRFPath); if (!rtStatus) { netdev_err(dev, "%s(): Failed to check RF Path %d.\n", __func__, eRFPath); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 3c6916bcea59..57bba6121b37 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -489,9 +489,8 @@ static void rtl8192_InitBBRFRegDef(struct net_device *dev) } -bool rtl8192_phy_checkBBAndRF(struct net_device *dev, - enum hw90_block CheckBlock, - enum rf90_radio_path eRFPath) +bool rtl92e_check_bb_and_rf(struct net_device *dev, enum hw90_block CheckBlock, + enum rf90_radio_path eRFPath) { bool ret = true; u32 i, CheckTimes = 4, dwRegRead = 0; @@ -563,9 +562,9 @@ static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) for (eCheckItem = (enum hw90_block)HW90_BLOCK_PHY0; eCheckItem <= HW90_BLOCK_PHY1; eCheckItem++) { - rtStatus = rtl8192_phy_checkBBAndRF(dev, - (enum hw90_block)eCheckItem, - (enum rf90_radio_path)0); + rtStatus = rtl92e_check_bb_and_rf(dev, + (enum hw90_block)eCheckItem, + (enum rf90_radio_path)0); if (!rtStatus) { RT_TRACE((COMP_ERR | COMP_PHY), "rtl92e_config_rf():Check PHY%d Fail!!\n", diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index cd4b242e18e4..8d4ea09c048f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -80,9 +80,9 @@ extern u32 rtl8192_phy_QueryRFReg(struct net_device *dev, enum rf90_radio_path eRFPath, u32 RegAddr, u32 BitMask); extern void rtl8192_phy_configmac(struct net_device *dev); -extern bool rtl8192_phy_checkBBAndRF(struct net_device *dev, - enum hw90_block CheckBlock, - enum rf90_radio_path eRFPath); +extern bool rtl92e_check_bb_and_rf(struct net_device *dev, + enum hw90_block CheckBlock, + enum rf90_radio_path eRFPath); extern bool rtl92e_config_bb(struct net_device *dev); extern void rtl8192_phy_getTxPower(struct net_device *dev); extern void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel); -- cgit v1.3-6-gb490 From 5948d1feb7b98d557967760e4dc0b4a253b6e5e3 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:47 +0200 Subject: staging: rtl8192e: Rename rtl8192_phy_CheckIsLegalRFPath Use naming schema found in other rtlwifi devices. Rename rtl8192_phy_CheckIsLegalRFPath to rtl92e_is_legal_rf_path. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 3 +-- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 6 +++--- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 3 +-- 4 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index 0f8bb4833ba1..1482a286a2d6 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -29,7 +29,7 @@ void rtl92e_set_bandwidth(struct net_device *dev, struct r8192_priv *priv = rtllib_priv(dev); for (eRFPath = 0; eRFPath < priv->NumTotalRFPath; eRFPath++) { - if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + if (!rtl92e_is_legal_rf_path(dev, eRFPath)) continue; switch (Bandwidth) { @@ -96,7 +96,7 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) for (eRFPath = (enum rf90_radio_path)RF90_PATH_A; eRFPath < priv->NumTotalRFPath; eRFPath++) { - if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + if (!rtl92e_is_legal_rf_path(dev, eRFPath)) continue; pPhyReg = &priv->PHYRegDef[eRFPath]; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 22625950706b..d81fa9463bf5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1745,8 +1745,7 @@ static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer, priv->stats.num_process_phyinfo++; if (!prev_st->bIsCCK && prev_st->bPacketToSelf) { for (rfpath = RF90_PATH_A; rfpath < RF90_PATH_C; rfpath++) { - if (!rtl8192_phy_CheckIsLegalRFPath(priv->rtllib->dev, - rfpath)) + if (!rtl92e_is_legal_rf_path(priv->rtllib->dev, rfpath)) continue; RT_TRACE(COMP_DBG, "Jacken -> pPreviousstats->RxMIMOSignalStrength[rfpath] = %d\n", diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 57bba6121b37..1d9ea05c6b56 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -64,7 +64,7 @@ static u32 rtl8192_CalculateBitShift(u32 dwBitMask) return i; } -u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device *dev, u32 eRFPath) +u8 rtl92e_is_legal_rf_path(struct net_device *dev, u32 eRFPath) { u8 ret = 1; struct r8192_priv *priv = rtllib_priv(dev); @@ -222,7 +222,7 @@ void rtl8192_phy_SetRFReg(struct net_device *dev, enum rf90_radio_path eRFPath, struct r8192_priv *priv = rtllib_priv(dev); u32 Original_Value, BitShift, New_Value; - if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + if (!rtl92e_is_legal_rf_path(dev, eRFPath)) return; if (priv->rtllib->eRFPowerState != eRfOn && !priv->being_init_adapter) return; @@ -262,7 +262,7 @@ u32 rtl8192_phy_QueryRFReg(struct net_device *dev, enum rf90_radio_path eRFPath, u32 Original_Value, Readback_Value, BitShift; struct r8192_priv *priv = rtllib_priv(dev); - if (!rtl8192_phy_CheckIsLegalRFPath(dev, eRFPath)) + if (!rtl92e_is_legal_rf_path(dev, eRFPath)) return 0; if (priv->rtllib->eRFPowerState != eRfOn && !priv->being_init_adapter) return 0; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 8d4ea09c048f..536a3a2ce05c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -67,8 +67,7 @@ enum rf90_radio_path { #define bMaskLWord 0x0000ffff #define bMaskDWord 0xffffffff -extern u8 rtl8192_phy_CheckIsLegalRFPath(struct net_device *dev, - u32 eRFPath); +extern u8 rtl92e_is_legal_rf_path(struct net_device *dev, u32 eRFPath); extern void rtl8192_setBBreg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, u32 dwData); extern u32 rtl8192_QueryBBReg(struct net_device *dev, u32 dwRegAddr, -- cgit v1.3-6-gb490 From 0efe7104ea2a1e50947fd6272d6efb2c8911fc31 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:48 +0200 Subject: staging: rtl8192e: Rename rtl8192_phy_configmac Use naming schema found in other rtlwifi devices. Rename rtl8192_phy_configmac to rtl92e_config_mac. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index d81fa9463bf5..bdb37c7a4685 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -828,7 +828,7 @@ start: } write_nic_byte(dev, 0xbe, 0xc0); - rtl8192_phy_configmac(dev); + rtl92e_config_mac(dev); if (priv->card_8192_version > (u8) VERSION_8190_BD) { rtl8192_phy_getTxPower(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 1d9ea05c6b56..36090f7879fb 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -328,7 +328,7 @@ static void phy_FwRFSerialWrite(struct net_device *dev, } -void rtl8192_phy_configmac(struct net_device *dev) +void rtl92e_config_mac(struct net_device *dev) { u32 dwArrayLen = 0, i = 0; u32 *pdwArray = NULL; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 536a3a2ce05c..4cfd4cb3d5b2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -78,7 +78,7 @@ extern void rtl8192_phy_SetRFReg(struct net_device *dev, extern u32 rtl8192_phy_QueryRFReg(struct net_device *dev, enum rf90_radio_path eRFPath, u32 RegAddr, u32 BitMask); -extern void rtl8192_phy_configmac(struct net_device *dev); +extern void rtl92e_config_mac(struct net_device *dev); extern bool rtl92e_check_bb_and_rf(struct net_device *dev, enum hw90_block CheckBlock, enum rf90_radio_path eRFPath); -- cgit v1.3-6-gb490 From 2504c113d85d2679993ffa00bdf5e1a087409b0c Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:49 +0200 Subject: staging: rtl8192e: Rename rtl8192_phy_ConfigRFWithHeaderFile Use naming schema found in other rtlwifi devices. Rename rtl8192_phy_ConfigRFWithHeaderFile to rtl92e_config_rf_path. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 8 ++++---- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 3 +-- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index 1482a286a2d6..9ed8637c7249 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -141,7 +141,7 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) case RF90_PATH_A: while (RF3_Final_Value != RegValueToBeCheck && RetryTimes != 0) { - ret = rtl8192_phy_ConfigRFWithHeaderFile(dev, + ret = rtl92e_config_rf_path(dev, (enum rf90_radio_path)eRFPath); RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (enum rf90_radio_path)eRFPath, @@ -157,7 +157,7 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) case RF90_PATH_B: while (RF3_Final_Value != RegValueToBeCheck && RetryTimes != 0) { - ret = rtl8192_phy_ConfigRFWithHeaderFile(dev, + ret = rtl92e_config_rf_path(dev, (enum rf90_radio_path)eRFPath); RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (enum rf90_radio_path)eRFPath, @@ -173,7 +173,7 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) case RF90_PATH_C: while (RF3_Final_Value != RegValueToBeCheck && RetryTimes != 0) { - ret = rtl8192_phy_ConfigRFWithHeaderFile(dev, + ret = rtl92e_config_rf_path(dev, (enum rf90_radio_path)eRFPath); RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (enum rf90_radio_path)eRFPath, @@ -189,7 +189,7 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) case RF90_PATH_D: while (RF3_Final_Value != RegValueToBeCheck && RetryTimes != 0) { - ret = rtl8192_phy_ConfigRFWithHeaderFile(dev, + ret = rtl92e_config_rf_path(dev, (enum rf90_radio_path)eRFPath); RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, (enum rf90_radio_path)eRFPath, diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 36090f7879fb..cc39cb5cbfc7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -717,8 +717,7 @@ void rtl8192_phy_updateInitGain(struct net_device *dev) { } -u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device *dev, - enum rf90_radio_path eRFPath) +u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath) { int i; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 4cfd4cb3d5b2..94218038a316 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -87,8 +87,8 @@ extern void rtl8192_phy_getTxPower(struct net_device *dev); extern void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel); extern bool rtl8192_phy_RFConfig(struct net_device *dev); extern void rtl8192_phy_updateInitGain(struct net_device *dev); -extern u8 rtl8192_phy_ConfigRFWithHeaderFile(struct net_device *dev, - enum rf90_radio_path eRFPath); +extern u8 rtl92e_config_rf_path(struct net_device *dev, + enum rf90_radio_path eRFPath); extern u8 rtl8192_phy_SwChnl(struct net_device *dev, u8 channel); extern void rtl8192_SetBWMode(struct net_device *dev, -- cgit v1.3-6-gb490 From 78cc16fa40f731ff1eef2ea9806d70afdf8220c7 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:50 +0200 Subject: staging: rtl8192e: Rename rtl8192_phy_getTxPower Use naming schema found in other rtlwifi devices. Rename rtl8192_phy_getTxPower to rtl92e_get_tx_power. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index bdb37c7a4685..6479d619ae2a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -831,7 +831,7 @@ start: rtl92e_config_mac(dev); if (priv->card_8192_version > (u8) VERSION_8190_BD) { - rtl8192_phy_getTxPower(dev); + rtl92e_get_tx_power(dev); rtl8192_phy_setTxPower(dev, priv->chan); } diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index cc39cb5cbfc7..8800c82e7ceb 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -604,7 +604,7 @@ bool rtl92e_config_bb(struct net_device *dev) return rtl8192_BB_Config_ParaFile(dev); } -void rtl8192_phy_getTxPower(struct net_device *dev) +void rtl92e_get_tx_power(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 94218038a316..67a7be9c8d30 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -83,7 +83,7 @@ extern bool rtl92e_check_bb_and_rf(struct net_device *dev, enum hw90_block CheckBlock, enum rf90_radio_path eRFPath); extern bool rtl92e_config_bb(struct net_device *dev); -extern void rtl8192_phy_getTxPower(struct net_device *dev); +extern void rtl92e_get_tx_power(struct net_device *dev); extern void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel); extern bool rtl8192_phy_RFConfig(struct net_device *dev); extern void rtl8192_phy_updateInitGain(struct net_device *dev); -- cgit v1.3-6-gb490 From 4d415decee9229b09fa6c800f5e2b00bf6c8988e Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:51 +0200 Subject: staging: rtl8192e: Rename rtl8192_phy_QueryRFReg Use naming schema found in other rtlwifi devices. Rename rtl8192_phy_QueryRFReg to rtl92e_get_rf_reg. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 8 ++++---- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 10 +++++----- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 6 +++--- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index 9ed8637c7249..510dfb22949e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -143,7 +143,7 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) RetryTimes != 0) { ret = rtl92e_config_rf_path(dev, (enum rf90_radio_path)eRFPath); - RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, + RF3_Final_Value = rtl92e_get_rf_reg(dev, (enum rf90_radio_path)eRFPath, RegOffSetToBeCheck, bMask12Bits); @@ -159,7 +159,7 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) RetryTimes != 0) { ret = rtl92e_config_rf_path(dev, (enum rf90_radio_path)eRFPath); - RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, + RF3_Final_Value = rtl92e_get_rf_reg(dev, (enum rf90_radio_path)eRFPath, RegOffSetToBeCheck, bMask12Bits); @@ -175,7 +175,7 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) RetryTimes != 0) { ret = rtl92e_config_rf_path(dev, (enum rf90_radio_path)eRFPath); - RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, + RF3_Final_Value = rtl92e_get_rf_reg(dev, (enum rf90_radio_path)eRFPath, RegOffSetToBeCheck, bMask12Bits); @@ -191,7 +191,7 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) RetryTimes != 0) { ret = rtl92e_config_rf_path(dev, (enum rf90_radio_path)eRFPath); - RF3_Final_Value = rtl8192_phy_QueryRFReg(dev, + RF3_Final_Value = rtl92e_get_rf_reg(dev, (enum rf90_radio_path)eRFPath, RegOffSetToBeCheck, bMask12Bits); RT_TRACE(COMP_RF, diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 8800c82e7ceb..c245f9537138 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -256,8 +256,8 @@ void rtl8192_phy_SetRFReg(struct net_device *dev, enum rf90_radio_path eRFPath, } } -u32 rtl8192_phy_QueryRFReg(struct net_device *dev, enum rf90_radio_path eRFPath, - u32 RegAddr, u32 BitMask) +u32 rtl92e_get_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath, + u32 RegAddr, u32 BitMask) { u32 Original_Value, Readback_Value, BitShift; struct r8192_priv *priv = rtllib_priv(dev); @@ -525,9 +525,9 @@ bool rtl92e_check_bb_and_rf(struct net_device *dev, enum hw90_block CheckBlock, WriteAddr[HW90_BLOCK_RF], bMask12Bits, WriteData[i]); mdelay(10); - dwRegRead = rtl8192_phy_QueryRFReg(dev, eRFPath, - WriteAddr[HW90_BLOCK_RF], - bMaskDWord); + dwRegRead = rtl92e_get_rf_reg(dev, eRFPath, + WriteAddr[HW90_BLOCK_RF], + bMaskDWord); mdelay(10); break; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 67a7be9c8d30..2dd947466756 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -75,9 +75,9 @@ extern u32 rtl8192_QueryBBReg(struct net_device *dev, u32 dwRegAddr, extern void rtl8192_phy_SetRFReg(struct net_device *dev, enum rf90_radio_path eRFPath, u32 RegAddr, u32 BitMask, u32 Data); -extern u32 rtl8192_phy_QueryRFReg(struct net_device *dev, - enum rf90_radio_path eRFPath, - u32 RegAddr, u32 BitMask); +extern u32 rtl92e_get_rf_reg(struct net_device *dev, + enum rf90_radio_path eRFPath, u32 RegAddr, + u32 BitMask); extern void rtl92e_config_mac(struct net_device *dev); extern bool rtl92e_check_bb_and_rf(struct net_device *dev, enum hw90_block CheckBlock, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 47ead3732a2b..54ec25f5d16d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -883,7 +883,7 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev) return; } - tmpRegA = rtl8192_phy_QueryRFReg(dev, RF90_PATH_A, 0x12, 0x078); + tmpRegA = rtl92e_get_rf_reg(dev, RF90_PATH_A, 0x12, 0x078); RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d\n", tmpRegA); if (tmpRegA < 3 || tmpRegA > 13) return; -- cgit v1.3-6-gb490 From 31aebbe2226cdcb17ee9cd9ed6f66c072604f8d9 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:52 +0200 Subject: staging: rtl8192e: Rename rtl8192_phy_RFConfig Use naming schema found in other rtlwifi devices. Rename rtl8192_phy_RFConfig to rtl92e_config_phy. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 6479d619ae2a..b389041db5bb 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -863,7 +863,7 @@ start: RT_TRACE(COMP_INIT, "Load Firmware finished!\n"); if (priv->ResetProgress == RESET_TYPE_NORESET) { RT_TRACE(COMP_INIT, "RF Config Started!\n"); - rtStatus = rtl8192_phy_RFConfig(dev); + rtStatus = rtl92e_config_phy(dev); if (!rtStatus) { netdev_info(dev, "RF Config failed\n"); return rtStatus; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index c245f9537138..19d954781385 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -689,7 +689,7 @@ void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel) } } -bool rtl8192_phy_RFConfig(struct net_device *dev) +bool rtl92e_config_phy(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); bool rtStatus = true; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 2dd947466756..66a2f2f45671 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -85,7 +85,7 @@ extern bool rtl92e_check_bb_and_rf(struct net_device *dev, extern bool rtl92e_config_bb(struct net_device *dev); extern void rtl92e_get_tx_power(struct net_device *dev); extern void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel); -extern bool rtl8192_phy_RFConfig(struct net_device *dev); +extern bool rtl92e_config_phy(struct net_device *dev); extern void rtl8192_phy_updateInitGain(struct net_device *dev); extern u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath); -- cgit v1.3-6-gb490 From b0e044feec65d1f71956672ea2b7a1ea5e6d2ec6 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:53 +0200 Subject: staging: rtl8192e: Rename rtl8192_phy_SetRFReg Use naming schema found in other rtlwifi devices. Rename rtl8192_phy_SetRFReg to rtl92e_set_rf_reg. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 40 +++++++++++----------- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 39 ++++++++++----------- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 6 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 8 ++--- 4 files changed, 45 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index 510dfb22949e..92bac867f832 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -36,15 +36,15 @@ void rtl92e_set_bandwidth(struct net_device *dev, case HT_CHANNEL_WIDTH_20: if (priv->card_8192_version == VERSION_8190_BD || priv->card_8192_version == VERSION_8190_BE) { - rtl8192_phy_SetRFReg(dev, - (enum rf90_radio_path)eRFPath, - 0x0b, bMask12Bits, 0x100); - rtl8192_phy_SetRFReg(dev, - (enum rf90_radio_path)eRFPath, - 0x2c, bMask12Bits, 0x3d7); - rtl8192_phy_SetRFReg(dev, - (enum rf90_radio_path)eRFPath, - 0x0e, bMask12Bits, 0x021); + rtl92e_set_rf_reg(dev, + (enum rf90_radio_path)eRFPath, + 0x0b, bMask12Bits, 0x100); + rtl92e_set_rf_reg(dev, + (enum rf90_radio_path)eRFPath, + 0x2c, bMask12Bits, 0x3d7); + rtl92e_set_rf_reg(dev, + (enum rf90_radio_path)eRFPath, + 0x0e, bMask12Bits, 0x021); } else { netdev_warn(dev, "%s(): Unknown HW version.\n", @@ -55,15 +55,15 @@ void rtl92e_set_bandwidth(struct net_device *dev, case HT_CHANNEL_WIDTH_20_40: if (priv->card_8192_version == VERSION_8190_BD || priv->card_8192_version == VERSION_8190_BE) { - rtl8192_phy_SetRFReg(dev, - (enum rf90_radio_path)eRFPath, - 0x0b, bMask12Bits, 0x300); - rtl8192_phy_SetRFReg(dev, - (enum rf90_radio_path)eRFPath, - 0x2c, bMask12Bits, 0x3ff); - rtl8192_phy_SetRFReg(dev, - (enum rf90_radio_path)eRFPath, - 0x0e, bMask12Bits, 0x0e1); + rtl92e_set_rf_reg(dev, + (enum rf90_radio_path)eRFPath, + 0x0b, bMask12Bits, 0x300); + rtl92e_set_rf_reg(dev, + (enum rf90_radio_path)eRFPath, + 0x2c, bMask12Bits, 0x3ff); + rtl92e_set_rf_reg(dev, + (enum rf90_radio_path)eRFPath, + 0x0e, bMask12Bits, 0x0e1); } else { netdev_warn(dev, "%s(): Unknown HW version.\n", @@ -124,8 +124,8 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0); - rtl8192_phy_SetRFReg(dev, (enum rf90_radio_path) eRFPath, 0x0, - bMask12Bits, 0xbf); + rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, 0x0, + bMask12Bits, 0xbf); rtStatus = rtl92e_check_bb_and_rf(dev, HW90_BLOCK_RF, (enum rf90_radio_path)eRFPath); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 19d954781385..6ddbbfc29f4f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -216,8 +216,8 @@ static void rtl8192_phy_RFSerialWrite(struct net_device *dev, } } -void rtl8192_phy_SetRFReg(struct net_device *dev, enum rf90_radio_path eRFPath, - u32 RegAddr, u32 BitMask, u32 Data) +void rtl92e_set_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath, + u32 RegAddr, u32 BitMask, u32 Data) { struct r8192_priv *priv = rtllib_priv(dev); u32 Original_Value, BitShift, New_Value; @@ -521,9 +521,9 @@ bool rtl92e_check_bb_and_rf(struct net_device *dev, enum hw90_block CheckBlock, case HW90_BLOCK_RF: WriteData[i] &= 0xfff; - rtl8192_phy_SetRFReg(dev, eRFPath, - WriteAddr[HW90_BLOCK_RF], - bMask12Bits, WriteData[i]); + rtl92e_set_rf_reg(dev, eRFPath, + WriteAddr[HW90_BLOCK_RF], + bMask12Bits, WriteData[i]); mdelay(10); dwRegRead = rtl92e_get_rf_reg(dev, eRFPath, WriteAddr[HW90_BLOCK_RF], @@ -729,10 +729,9 @@ u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath) msleep(100); continue; } - rtl8192_phy_SetRFReg(dev, eRFPath, - Rtl819XRadioA_Array[i], - bMask12Bits, - Rtl819XRadioA_Array[i+1]); + rtl92e_set_rf_reg(dev, eRFPath, Rtl819XRadioA_Array[i], + bMask12Bits, + Rtl819XRadioA_Array[i+1]); } break; @@ -742,10 +741,9 @@ u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath) msleep(100); continue; } - rtl8192_phy_SetRFReg(dev, eRFPath, - Rtl819XRadioB_Array[i], - bMask12Bits, - Rtl819XRadioB_Array[i+1]); + rtl92e_set_rf_reg(dev, eRFPath, Rtl819XRadioB_Array[i], + bMask12Bits, + Rtl819XRadioB_Array[i+1]); } break; @@ -755,10 +753,9 @@ u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath) msleep(100); continue; } - rtl8192_phy_SetRFReg(dev, eRFPath, - Rtl819XRadioC_Array[i], - bMask12Bits, - Rtl819XRadioC_Array[i+1]); + rtl92e_set_rf_reg(dev, eRFPath, Rtl819XRadioC_Array[i], + bMask12Bits, + Rtl819XRadioC_Array[i+1]); } break; @@ -768,9 +765,9 @@ u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath) msleep(100); continue; } - rtl8192_phy_SetRFReg(dev, eRFPath, - Rtl819XRadioD_Array[i], bMask12Bits, - Rtl819XRadioD_Array[i+1]); + rtl92e_set_rf_reg(dev, eRFPath, Rtl819XRadioD_Array[i], + bMask12Bits, + Rtl819XRadioD_Array[i+1]); } break; @@ -953,7 +950,7 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, case CmdID_RF_WriteReg: for (eRFPath = 0; eRFPath < priv->NumTotalRFPath; eRFPath++) - rtl8192_phy_SetRFReg(dev, + rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, CurrentCmd->Para1, bMask12Bits, CurrentCmd->Para2<<7); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 66a2f2f45671..33aa78a375d9 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -72,9 +72,9 @@ extern void rtl8192_setBBreg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, u32 dwData); extern u32 rtl8192_QueryBBReg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask); -extern void rtl8192_phy_SetRFReg(struct net_device *dev, - enum rf90_radio_path eRFPath, - u32 RegAddr, u32 BitMask, u32 Data); +extern void rtl92e_set_rf_reg(struct net_device *dev, + enum rf90_radio_path eRFPath, u32 RegAddr, + u32 BitMask, u32 Data); extern u32 rtl92e_get_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath, u32 RegAddr, u32 BitMask); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 54ec25f5d16d..de085477f2f6 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -1038,10 +1038,10 @@ static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev) if (!TM_Trigger) { { - rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); - rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); - rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); - rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); + rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); + rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); + rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d); + rtl92e_set_rf_reg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f); } TM_Trigger = 1; return; -- cgit v1.3-6-gb490 From 5aa1b9cad7a352e2e4a72f553689fe03c629f65c Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:54 +0200 Subject: staging: rtl8192e: Rename rtl8192_phy_setTxPower Use naming schema found in other rtlwifi devices. Rename rtl8192_phy_setTxPower to rtl92e_set_tx_power. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 3 +-- 4 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index b389041db5bb..8f3172e908d4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -832,7 +832,7 @@ start: if (priv->card_8192_version > (u8) VERSION_8190_BD) { rtl92e_get_tx_power(dev); - rtl8192_phy_setTxPower(dev, priv->chan); + rtl92e_set_tx_power(dev, priv->chan); } tmpvalue = read_nic_byte(dev, IC_VERRSION); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 6ddbbfc29f4f..fbbf5346d76a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -637,7 +637,7 @@ void rtl92e_get_tx_power(struct net_device *dev) priv->SifsTime = read_nic_word(dev, SIFS); } -void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel) +void rtl92e_set_tx_power(struct net_device *dev, u8 channel) { struct r8192_priv *priv = rtllib_priv(dev); u8 powerlevel = 0, powerlevelOFDM24G = 0; @@ -1386,7 +1386,7 @@ void rtl92e_init_gain(struct net_device *dev, u8 Operation) "Scan BBInitialGainRestore 0xa0a is %x\n", priv->initgain_backup.cca); - rtl8192_phy_setTxPower(dev, + rtl92e_set_tx_power(dev, priv->rtllib->current_network.channel); if (dm_digtable.dig_algorithm == diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 33aa78a375d9..b474a2b1e01a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -84,7 +84,7 @@ extern bool rtl92e_check_bb_and_rf(struct net_device *dev, enum rf90_radio_path eRFPath); extern bool rtl92e_config_bb(struct net_device *dev); extern void rtl92e_get_tx_power(struct net_device *dev); -extern void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel); +extern void rtl92e_set_tx_power(struct net_device *dev, u8 channel); extern bool rtl92e_config_phy(struct net_device *dev); extern void rtl8192_phy_updateInitGain(struct net_device *dev); extern u8 rtl92e_config_rf_path(struct net_device *dev, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index de085477f2f6..fe8f29153ef5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -2555,8 +2555,7 @@ static void dm_dynamic_txpower(struct net_device *dev) RT_TRACE(COMP_TXAGC, "SetTxPowerLevel8190() channel = %d\n", priv->rtllib->current_network.channel); - rtl8192_phy_setTxPower(dev, - priv->rtllib->current_network.channel); + rtl92e_set_tx_power(dev, priv->rtllib->current_network.channel); } priv->bLastDTPFlag_High = priv->bDynamicTxHighPower; priv->bLastDTPFlag_Low = priv->bDynamicTxLowPower; -- cgit v1.3-6-gb490 From 68a5143c812d13d6a30c5863511cb2ee92635123 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:55 +0200 Subject: staging: rtl8192e: Rename rtl8192_phy_SwChnl Use naming schema found in other rtlwifi devices. Rename rtl8192_phy_SwChnl to rtl92e_set_channel. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index fbbf5346d76a..f575ee1511fa 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -996,7 +996,7 @@ static void rtl8192_SwChnl_WorkItem(struct net_device *dev) RT_TRACE(COMP_TRACE, "<== SwChnlCallback819xUsbWorkItem()\n"); } -u8 rtl8192_phy_SwChnl(struct net_device *dev, u8 channel) +u8 rtl92e_set_channel(struct net_device *dev, u8 channel) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index b474a2b1e01a..3bfde0d60434 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -90,7 +90,7 @@ extern void rtl8192_phy_updateInitGain(struct net_device *dev); extern u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath); -extern u8 rtl8192_phy_SwChnl(struct net_device *dev, u8 channel); +extern u8 rtl92e_set_channel(struct net_device *dev, u8 channel); extern void rtl8192_SetBWMode(struct net_device *dev, enum ht_channel_width Bandwidth, enum ht_extchnl_offset Offset); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 87a53d136bbe..99b36f8b5c79 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -877,7 +877,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->SetWirelessMode = rtl8192_SetWirelessMode; priv->rtllib->LeisurePSLeave = LeisurePSLeave; priv->rtllib->SetBWModeHandler = rtl8192_SetBWMode; - priv->rf_set_chan = rtl8192_phy_SwChnl; + priv->rf_set_chan = rtl92e_set_channel; priv->rtllib->start_send_beacons = rtl92e_start_beacon; priv->rtllib->stop_send_beacons = rtl8192_stop_beacon; -- cgit v1.3-6-gb490 From 3c351feca929e142574b1f904a42475e4056de45 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:56 +0200 Subject: staging: rtl8192e: Rename rtl8192_QueryBBReg Use naming schema found in other rtlwifi devices. Rename rtl8192_QueryBBReg to rtl92e_get_bb_reg. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 8 ++++---- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 17 +++++++-------- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 24 +++++++++++----------- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 16 +++++++-------- 5 files changed, 35 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index 92bac867f832..c3abd296e847 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -105,13 +105,13 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) switch (eRFPath) { case RF90_PATH_A: case RF90_PATH_C: - u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, - bRFSI_RFENV); + u4RegValue = rtl92e_get_bb_reg(dev, pPhyReg->rfintfs, + bRFSI_RFENV); break; case RF90_PATH_B: case RF90_PATH_D: - u4RegValue = rtl8192_QueryBBReg(dev, pPhyReg->rfintfs, - bRFSI_RFENV<<16); + u4RegValue = rtl92e_get_bb_reg(dev, pPhyReg->rfintfs, + bRFSI_RFENV<<16); break; } diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 8f3172e908d4..4e0ce871bc61 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -910,10 +910,10 @@ start: dm_initialize_txpower_tracking(dev); if (priv->IC_Cut >= IC_VersionCut_D) { - tmpRegA = rtl8192_QueryBBReg(dev, - rOFDM0_XATxIQImbalance, bMaskDWord); - tmpRegC = rtl8192_QueryBBReg(dev, - rOFDM0_XCTxIQImbalance, bMaskDWord); + tmpRegA = rtl92e_get_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord); + tmpRegC = rtl92e_get_bb_reg(dev, rOFDM0_XCTxIQImbalance, + bMaskDWord); for (i = 0; i < TxBBGainTableLength; i++) { if (tmpRegA == dm_tx_bb_gain[i]) { priv->rfa_txpowertrackingindex = (u8)i; @@ -925,8 +925,8 @@ start: } } - TempCCk = rtl8192_QueryBBReg(dev, - rCCK0_TxFilter1, bMaskByte2); + TempCCk = rtl92e_get_bb_reg(dev, rCCK0_TxFilter1, + bMaskByte2); for (i = 0; i < CCKTxBBGainTableLength; i++) { if (TempCCk == dm_cck_tx_bb_gain[i][0]) { @@ -1516,8 +1516,9 @@ static void rtl8192_query_rxphystatus( pstats->bPacketBeacon = precord_stats->bPacketBeacon = bPacketBeacon; pstats->bToSelfBA = precord_stats->bToSelfBA = bToSelfBA; if (check_reg824 == 0) { - reg824_bit9 = rtl8192_QueryBBReg(priv->rtllib->dev, - rFPGA0_XA_HSSIParameter2, 0x200); + reg824_bit9 = rtl92e_get_bb_reg(priv->rtllib->dev, + rFPGA0_XA_HSSIParameter2, + 0x200); check_reg824 = 1; } diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index f575ee1511fa..a993cc746e47 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -96,7 +96,7 @@ void rtl8192_setBBreg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, write_nic_dword(dev, dwRegAddr, dwData); } -u32 rtl8192_QueryBBReg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask) +u32 rtl92e_get_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask) { u32 Ret = 0, OriginalValue, BitShift; @@ -146,8 +146,8 @@ static u32 rtl8192_phy_RFSerialRead(struct net_device *dev, mdelay(1); - ret = rtl8192_QueryBBReg(dev, pPhyReg->rfLSSIReadBack, - bLSSIReadBackData); + ret = rtl92e_get_bb_reg(dev, pPhyReg->rfLSSIReadBack, + bLSSIReadBackData); if (priv->rf_chip == RF_8256) { priv->RfReg0Value[eRFPath] &= 0xebf; @@ -1309,19 +1309,19 @@ void rtl92e_init_gain(struct net_device *dev, u8 Operation) DIG_ALGO_BY_FALSE_ALARM) rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); priv->initgain_backup.xaagccore1 = - (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, - BitMask); + (u8)rtl92e_get_bb_reg(dev, rOFDM0_XAAGCCore1, + BitMask); priv->initgain_backup.xbagccore1 = - (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, - BitMask); + (u8)rtl92e_get_bb_reg(dev, rOFDM0_XBAGCCore1, + BitMask); priv->initgain_backup.xcagccore1 = - (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, - BitMask); + (u8)rtl92e_get_bb_reg(dev, rOFDM0_XCAGCCore1, + BitMask); priv->initgain_backup.xdagccore1 = - (u8)rtl8192_QueryBBReg(dev, rOFDM0_XDAGCCore1, - BitMask); + (u8)rtl92e_get_bb_reg(dev, rOFDM0_XDAGCCore1, + BitMask); BitMask = bMaskByte2; - priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(dev, + priv->initgain_backup.cca = (u8)rtl92e_get_bb_reg(dev, rCCK0_CCA, BitMask); RT_TRACE(COMP_SCAN, diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 3bfde0d60434..7a147ecfb2d5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -70,8 +70,8 @@ enum rf90_radio_path { extern u8 rtl92e_is_legal_rf_path(struct net_device *dev, u32 eRFPath); extern void rtl8192_setBBreg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, u32 dwData); -extern u32 rtl8192_QueryBBReg(struct net_device *dev, u32 dwRegAddr, - u32 dwBitMask); +extern u32 rtl92e_get_bb_reg(struct net_device *dev, u32 dwRegAddr, + u32 dwBitMask); extern void rtl92e_set_rf_reg(struct net_device *dev, enum rf90_radio_path eRFPath, u32 RegAddr, u32 BitMask, u32 Data); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index fe8f29153ef5..2137252a5267 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -856,8 +856,8 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev) int i = 0, CCKSwingNeedUpdate = 0; if (!priv->btxpower_trackingInit) { - tmpRegA = rtl8192_QueryBBReg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord); + tmpRegA = rtl92e_get_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord); for (i = 0; i < OFDM_Table_Length; i++) { if (tmpRegA == OFDMSwingTable[i]) { priv->OFDM_index[0] = (u8)i; @@ -868,7 +868,7 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev) } } - TempCCk = rtl8192_QueryBBReg(dev, rCCK0_TxFilter1, bMaskByte2); + TempCCk = rtl92e_get_bb_reg(dev, rCCK0_TxFilter1, bMaskByte2); for (i = 0; i < CCK_Table_length; i++) { if (TempCCk == (u32)CCKSwingTable_Ch1_Ch13[i][0]) { priv->CCK_index = (u8) i; @@ -1279,12 +1279,12 @@ static void dm_bb_initialgain_backup(struct net_device *dev) return; rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); - priv->initgain_backup.xaagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, bit_mask); - priv->initgain_backup.xbagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, bit_mask); - priv->initgain_backup.xcagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, bit_mask); - priv->initgain_backup.xdagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XDAGCCore1, bit_mask); + priv->initgain_backup.xaagccore1 = (u8)rtl92e_get_bb_reg(dev, rOFDM0_XAAGCCore1, bit_mask); + priv->initgain_backup.xbagccore1 = (u8)rtl92e_get_bb_reg(dev, rOFDM0_XBAGCCore1, bit_mask); + priv->initgain_backup.xcagccore1 = (u8)rtl92e_get_bb_reg(dev, rOFDM0_XCAGCCore1, bit_mask); + priv->initgain_backup.xdagccore1 = (u8)rtl92e_get_bb_reg(dev, rOFDM0_XDAGCCore1, bit_mask); bit_mask = bMaskByte2; - priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(dev, rCCK0_CCA, bit_mask); + priv->initgain_backup.cca = (u8)rtl92e_get_bb_reg(dev, rCCK0_CCA, bit_mask); RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc50 is %x\n", priv->initgain_backup.xaagccore1); -- cgit v1.3-6-gb490 From 153f9ddbe97828e9cb3428bc6698da49deb3c574 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:57 +0200 Subject: staging: rtl8192e: Rename rtl8192_setBBreg Use naming schema found in other rtlwifi devices. Rename rtl8192_setBBreg to rtl92e_set_bb_reg. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 24 +-- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 4 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 165 ++++++++++---------- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 4 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 171 ++++++++++----------- 5 files changed, 182 insertions(+), 186 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index c3abd296e847..e5f4c2df69fd 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -115,14 +115,14 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) break; } - rtl8192_setBBreg(dev, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); + rtl92e_set_bb_reg(dev, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1); - rtl8192_setBBreg(dev, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); + rtl92e_set_bb_reg(dev, pPhyReg->rfintfo, bRFSI_RFENV, 0x1); - rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, - b3WireAddressLength, 0x0); - rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, - b3WireDataLength, 0x0); + rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, + b3WireAddressLength, 0x0); + rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, + b3WireDataLength, 0x0); rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, 0x0, bMask12Bits, 0xbf); @@ -206,13 +206,13 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) switch (eRFPath) { case RF90_PATH_A: case RF90_PATH_C: - rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV, - u4RegValue); + rtl92e_set_bb_reg(dev, pPhyReg->rfintfs, bRFSI_RFENV, + u4RegValue); break; case RF90_PATH_B: case RF90_PATH_D: - rtl8192_setBBreg(dev, pPhyReg->rfintfs, bRFSI_RFENV<<16, - u4RegValue); + rtl92e_set_bb_reg(dev, pPhyReg->rfintfs, + bRFSI_RFENV<<16, u4RegValue); break; } @@ -254,7 +254,7 @@ void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel) } if (TxAGC > 0x24) TxAGC = 0x24; - rtl8192_setBBreg(dev, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC); + rtl92e_set_bb_reg(dev, rTxAGC_CCK_Mcs32, bTxAGCRateCCK, TxAGC); } @@ -300,7 +300,7 @@ void rtl92e_set_ofdm_tx_power(struct net_device *dev, u8 powerlevel) else writeVal = (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0; - rtl8192_setBBreg(dev, RegOffset[index], 0x7f7f7f7f, writeVal); + rtl92e_set_bb_reg(dev, RegOffset[index], 0x7f7f7f7f, writeVal); } } diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 4e0ce871bc61..b6d26fa4e2ee 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -872,8 +872,8 @@ start: } rtl8192_phy_updateInitGain(dev); - rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn, 0x1); - rtl8192_setBBreg(dev, rFPGA0_RFMOD, bOFDMEn, 0x1); + rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bCCKEn, 0x1); + rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bOFDMEn, 0x1); write_nic_byte(dev, 0x87, 0x0); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index a993cc746e47..7bbbe7be6f60 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -80,8 +80,8 @@ u8 rtl92e_is_legal_rf_path(struct net_device *dev, u32 eRFPath) return ret; } -void rtl8192_setBBreg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, - u32 dwData) +void rtl92e_set_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, + u32 dwData) { u32 OriginalValue, BitShift, NewValue; @@ -117,19 +117,19 @@ static u32 rtl8192_phy_RFSerialRead(struct net_device *dev, Offset &= 0x3f; if (priv->rf_chip == RF_8256) { - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0); if (Offset >= 31) { priv->RfReg0Value[eRFPath] |= 0x140; - rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, - bMaskDWord, - (priv->RfReg0Value[eRFPath]<<16)); + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath]<<16)); NewOffset = Offset - 30; } else if (Offset >= 16) { priv->RfReg0Value[eRFPath] |= 0x100; priv->RfReg0Value[eRFPath] &= (~0x40); - rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, - bMaskDWord, - (priv->RfReg0Value[eRFPath]<<16)); + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath]<<16)); NewOffset = Offset - 15; } else @@ -139,10 +139,10 @@ static u32 rtl8192_phy_RFSerialRead(struct net_device *dev, "check RF type here, need to be 8256\n"); NewOffset = Offset; } - rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadAddress, - NewOffset); - rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x0); - rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1); + rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, bLSSIReadAddress, + NewOffset); + rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x0); + rtl92e_set_bb_reg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1); mdelay(1); @@ -152,10 +152,10 @@ static u32 rtl8192_phy_RFSerialRead(struct net_device *dev, if (priv->rf_chip == RF_8256) { priv->RfReg0Value[eRFPath] &= 0xebf; - rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, - (priv->RfReg0Value[eRFPath] << 16)); + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16)); - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3); } @@ -173,20 +173,20 @@ static void rtl8192_phy_RFSerialWrite(struct net_device *dev, Offset &= 0x3f; if (priv->rf_chip == RF_8256) { - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0xf00, 0x0); if (Offset >= 31) { priv->RfReg0Value[eRFPath] |= 0x140; - rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, - bMaskDWord, - (priv->RfReg0Value[eRFPath] << 16)); + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16)); NewOffset = Offset - 30; } else if (Offset >= 16) { priv->RfReg0Value[eRFPath] |= 0x100; priv->RfReg0Value[eRFPath] &= (~0x40); - rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, - bMaskDWord, - (priv->RfReg0Value[eRFPath] << 16)); + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16)); NewOffset = Offset - 15; } else NewOffset = Offset; @@ -198,7 +198,7 @@ static void rtl8192_phy_RFSerialWrite(struct net_device *dev, DataAndAddr = (Data<<16) | (NewOffset&0x3f); - rtl8192_setBBreg(dev, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr); if (Offset == 0x0) priv->RfReg0Value[eRFPath] = Data; @@ -206,13 +206,11 @@ static void rtl8192_phy_RFSerialWrite(struct net_device *dev, if (priv->rf_chip == RF_8256) { if (Offset != 0) { priv->RfReg0Value[eRFPath] &= 0xebf; - rtl8192_setBBreg( - dev, - pPhyReg->rf3wireOffset, - bMaskDWord, - (priv->RfReg0Value[eRFPath] << 16)); + rtl92e_set_bb_reg(dev, pPhyReg->rf3wireOffset, + bMaskDWord, + (priv->RfReg0Value[eRFPath] << 16)); } - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x3); } } @@ -350,8 +348,8 @@ void rtl92e_config_mac(struct net_device *dev) pdwArray[i], pdwArray[i+1], pdwArray[i+2]); if (pdwArray[i] == 0x318) pdwArray[i+2] = 0x00000800; - rtl8192_setBBreg(dev, pdwArray[i], pdwArray[i+1], - pdwArray[i+2]); + rtl92e_set_bb_reg(dev, pdwArray[i], pdwArray[i+1], + pdwArray[i+2]); } return; @@ -377,9 +375,9 @@ static void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType) if (ConfigType == BaseBand_Config_PHY_REG) { for (i = 0; i < PHY_REGArrayLen; i += 2) { - rtl8192_setBBreg(dev, Rtl819XPHY_REGArray_Table[i], - bMaskDWord, - Rtl819XPHY_REGArray_Table[i+1]); + rtl92e_set_bb_reg(dev, Rtl819XPHY_REGArray_Table[i], + bMaskDWord, + Rtl819XPHY_REGArray_Table[i+1]); RT_TRACE(COMP_DBG, "i: %x, The Rtl819xUsbPHY_REGArray[0] is %x Rtl819xUsbPHY_REGArray[1] is %x\n", i, Rtl819XPHY_REGArray_Table[i], @@ -387,9 +385,9 @@ static void rtl8192_phyConfigBB(struct net_device *dev, u8 ConfigType) } } else if (ConfigType == BaseBand_Config_AGC_TAB) { for (i = 0; i < AGCTAB_ArrayLen; i += 2) { - rtl8192_setBBreg(dev, Rtl819XAGCTAB_Array_Table[i], - bMaskDWord, - Rtl819XAGCTAB_Array_Table[i+1]); + rtl92e_set_bb_reg(dev, Rtl819XAGCTAB_Array_Table[i], + bMaskDWord, + Rtl819XAGCTAB_Array_Table[i+1]); RT_TRACE(COMP_DBG, "i:%x, The rtl819XAGCTAB_Array[0] is %x rtl819XAGCTAB_Array[1] is %x\n", i, Rtl819XAGCTAB_Array_Table[i], @@ -572,7 +570,7 @@ static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) return rtStatus; } } - rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0x0); + rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0x0); rtl8192_phyConfigBB(dev, BaseBand_Config_PHY_REG); dwRegValue = read_nic_dword(dev, CPU_GEN); @@ -587,13 +585,13 @@ static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) priv->AntennaTxPwDiff[0]); else dwRegValue = 0x0; - rtl8192_setBBreg(dev, rFPGA0_TxGainStage, - (bXBTxAGC|bXCTxAGC|bXDTxAGC), dwRegValue); + rtl92e_set_bb_reg(dev, rFPGA0_TxGainStage, + (bXBTxAGC|bXCTxAGC|bXDTxAGC), dwRegValue); dwRegValue = priv->CrystalCap; - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, bXtalCap92x, - dwRegValue); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, bXtalCap92x, + dwRegValue); } return rtStatus; @@ -670,8 +668,9 @@ void rtl92e_set_tx_power(struct net_device *dev, u8 channel) priv->AntennaTxPwDiff[1]<<4 | priv->AntennaTxPwDiff[0]); - rtl8192_setBBreg(dev, rFPGA0_TxGainStage, - (bXBTxAGC|bXCTxAGC|bXDTxAGC), u4RegValue); + rtl92e_set_bb_reg(dev, rFPGA0_TxGainStage, + (bXBTxAGC|bXCTxAGC|bXDTxAGC), + u4RegValue); } } switch (priv->rf_chip) { @@ -1199,8 +1198,8 @@ static void rtl8192_SetBWModeWorkItem(struct net_device *dev) switch (priv->CurrentChannelBW) { case HT_CHANNEL_WIDTH_20: - rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x0); - rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x0); + rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bRFMOD, 0x0); + rtl92e_set_bb_reg(dev, rFPGA1_RFMOD, bRFMOD, 0x0); if (!priv->btxpower_tracking) { write_nic_dword(dev, rCCK0_TxFilter1, 0x1a1b0000); @@ -1210,12 +1209,12 @@ static void rtl8192_SetBWModeWorkItem(struct net_device *dev) CCK_Tx_Power_Track_BW_Switch(dev); } - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 1); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x00100000, 1); break; case HT_CHANNEL_WIDTH_20_40: - rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x1); - rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x1); + rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bRFMOD, 0x1); + rtl92e_set_bb_reg(dev, rFPGA1_RFMOD, bRFMOD, 0x1); if (!priv->btxpower_tracking) { write_nic_dword(dev, rCCK0_TxFilter1, 0x35360000); @@ -1225,12 +1224,12 @@ static void rtl8192_SetBWModeWorkItem(struct net_device *dev) CCK_Tx_Power_Track_BW_Switch(dev); } - rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand, - (priv->nCur40MhzPrimeSC>>1)); - rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00, - priv->nCur40MhzPrimeSC); + rtl92e_set_bb_reg(dev, rCCK0_System, bCCKSideBand, + (priv->nCur40MhzPrimeSC>>1)); + rtl92e_set_bb_reg(dev, rOFDM1_LSTF, 0xC00, + priv->nCur40MhzPrimeSC); - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 0); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x00100000, 0); break; default: netdev_err(dev, "%s(): unknown Bandwidth: %#X\n", __func__, @@ -1307,7 +1306,7 @@ void rtl92e_init_gain(struct net_device *dev, u8 Operation) BitMask = bMaskByte0; if (dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) - rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); + rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x8); priv->initgain_backup.xaagccore1 = (u8)rtl92e_get_bb_reg(dev, rOFDM0_XAAGCCore1, BitMask); @@ -1356,18 +1355,18 @@ void rtl92e_init_gain(struct net_device *dev, u8 Operation) BitMask = 0x7f; if (dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) - rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); + rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x8); - rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, BitMask, + rtl92e_set_bb_reg(dev, rOFDM0_XAAGCCore1, BitMask, (u32)priv->initgain_backup.xaagccore1); - rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, BitMask, + rtl92e_set_bb_reg(dev, rOFDM0_XBAGCCore1, BitMask, (u32)priv->initgain_backup.xbagccore1); - rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, BitMask, + rtl92e_set_bb_reg(dev, rOFDM0_XCAGCCore1, BitMask, (u32)priv->initgain_backup.xcagccore1); - rtl8192_setBBreg(dev, rOFDM0_XDAGCCore1, BitMask, + rtl92e_set_bb_reg(dev, rOFDM0_XDAGCCore1, BitMask, (u32)priv->initgain_backup.xdagccore1); BitMask = bMaskByte2; - rtl8192_setBBreg(dev, rCCK0_CCA, BitMask, + rtl92e_set_bb_reg(dev, rCCK0_CCA, BitMask, (u32)priv->initgain_backup.cca); RT_TRACE(COMP_SCAN, @@ -1391,7 +1390,7 @@ void rtl92e_init_gain(struct net_device *dev, u8 Operation) if (dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM) - rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); + rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x1); break; default: RT_TRACE(COMP_SCAN, "Unknown IG Operation.\n"); @@ -1403,13 +1402,13 @@ void rtl92e_init_gain(struct net_device *dev, u8 Operation) void rtl92e_set_rf_off(struct net_device *dev) { - rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x0); - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, 0x300, 0x0); - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x18, 0x0); - rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0xf, 0x0); - rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0); - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0); - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x4, 0x0); + rtl92e_set_bb_reg(dev, rFPGA0_XA_RFInterfaceOE, BIT4, 0x0); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, 0x300, 0x0); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x18, 0x0); + rtl92e_set_bb_reg(dev, rOFDM0_TRxPathEnable, 0xf, 0x0); + rtl92e_set_bb_reg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x4, 0x0); write_nic_byte(dev, ANAPAR_FOR_8192PciE, 0x07); } @@ -1458,22 +1457,22 @@ static bool SetRFPowerState8190(struct net_device *dev, } else { write_nic_byte(dev, ANAPAR, 0x37); mdelay(1); - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x4, 0x1); priv->bHwRfOffAction = 0; - rtl8192_setBBreg(dev, rFPGA0_XA_RFInterfaceOE, - BIT4, 0x1); - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter4, - 0x300, 0x3); - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, - 0x18, 0x3); - rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x3, - 0x3); - rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x3, - 0x3); - rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, - 0x60, 0x3); + rtl92e_set_bb_reg(dev, rFPGA0_XA_RFInterfaceOE, + BIT4, 0x1); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter4, + 0x300, 0x3); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, + 0x18, 0x3); + rtl92e_set_bb_reg(dev, rOFDM0_TRxPathEnable, + 0x3, 0x3); + rtl92e_set_bb_reg(dev, rOFDM1_TRxPathEnable, + 0x3, 0x3); + rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, + 0x60, 0x3); } diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 7a147ecfb2d5..1d961cfa51c0 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -68,8 +68,8 @@ enum rf90_radio_path { #define bMaskDWord 0xffffffff extern u8 rtl92e_is_legal_rf_path(struct net_device *dev, u32 eRFPath); -extern void rtl8192_setBBreg(struct net_device *dev, u32 dwRegAddr, - u32 dwBitMask, u32 dwData); +extern void rtl92e_set_bb_reg(struct net_device *dev, u32 dwRegAddr, + u32 dwBitMask, u32 dwData); extern u32 rtl92e_get_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask); extern void rtl92e_set_rf_reg(struct net_device *dev, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 2137252a5267..e967ba0a88ef 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -561,40 +561,40 @@ static void dm_tx_update_tssi_weak_signal(struct net_device *dev, u8 RF_Type) p->rfa_txpowertrackingindex--; if (p->rfa_txpowertrackingindex_real > 4) { p->rfa_txpowertrackingindex_real--; - rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); } p->rfc_txpowertrackingindex--; if (p->rfc_txpowertrackingindex_real > 4) { p->rfc_txpowertrackingindex_real--; - rtl8192_setBBreg(dev, - rOFDM0_XCTxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfc_txpowertrackingindex_real]); + rtl92e_set_bb_reg(dev, + rOFDM0_XCTxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[p->rfc_txpowertrackingindex_real]); } } else { - rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[4]); - rtl8192_setBBreg(dev, - rOFDM0_XCTxIQImbalance, - bMaskDWord, dm_tx_bb_gain[4]); + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[4]); + rtl92e_set_bb_reg(dev, + rOFDM0_XCTxIQImbalance, + bMaskDWord, dm_tx_bb_gain[4]); } } else { if (p->rfa_txpowertrackingindex > 0) { p->rfa_txpowertrackingindex--; if (p->rfa_txpowertrackingindex_real > 4) { p->rfa_txpowertrackingindex_real--; - rtl8192_setBBreg(dev, - rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); + rtl92e_set_bb_reg(dev, + rOFDM0_XATxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); } } else { - rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, dm_tx_bb_gain[4]); + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, dm_tx_bb_gain[4]); } } } @@ -608,36 +608,33 @@ static void dm_tx_update_tssi_strong_signal(struct net_device *dev, u8 RF_Type) (p->rfc_txpowertrackingindex < TxBBGainTableLength - 1)) { p->rfa_txpowertrackingindex++; p->rfa_txpowertrackingindex_real++; - rtl8192_setBBreg(dev, - rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); p->rfc_txpowertrackingindex++; p->rfc_txpowertrackingindex_real++; - rtl8192_setBBreg(dev, - rOFDM0_XCTxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfc_txpowertrackingindex_real]); + rtl92e_set_bb_reg(dev, rOFDM0_XCTxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[p->rfc_txpowertrackingindex_real]); } else { - rtl8192_setBBreg(dev, - rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[TxBBGainTableLength - 1]); - rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[TxBBGainTableLength - 1]); + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[TxBBGainTableLength - 1]); + rtl92e_set_bb_reg(dev, rOFDM0_XCTxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[TxBBGainTableLength - 1]); } } else { if (p->rfa_txpowertrackingindex < (TxBBGainTableLength - 1)) { p->rfa_txpowertrackingindex++; p->rfa_txpowertrackingindex_real++; - rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[p->rfa_txpowertrackingindex_real]); } else { - rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, - bMaskDWord, - dm_tx_bb_gain[TxBBGainTableLength - 1]); + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, + bMaskDWord, + dm_tx_bb_gain[TxBBGainTableLength - 1]); } } } @@ -941,8 +938,8 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev) dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); if (priv->OFDM_index[0] != tmpOFDMindex) { priv->OFDM_index[0] = tmpOFDMindex; - rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, - OFDMSwingTable[priv->OFDM_index[0]]); + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, + OFDMSwingTable[priv->OFDM_index[0]]); RT_TRACE(COMP_POWER_TRACKING, "Update OFDMSwing[%d] = 0x%x\n", priv->OFDM_index[0], OFDMSwingTable[priv->OFDM_index[0]]); @@ -1073,30 +1070,30 @@ static void dm_CCKTxPowerAdjust_TSSI(struct net_device *dev, bool bInCH14) TempVal = (u32)(dm_cck_tx_bb_gain[attenuation][0] + (dm_cck_tx_bb_gain[attenuation][1] << 8)); - rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); TempVal = (u32)((dm_cck_tx_bb_gain[attenuation][2]) + (dm_cck_tx_bb_gain[attenuation][3] << 8) + (dm_cck_tx_bb_gain[attenuation][4] << 16)+ (dm_cck_tx_bb_gain[attenuation][5] << 24)); - rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); TempVal = (u32)(dm_cck_tx_bb_gain[attenuation][6] + (dm_cck_tx_bb_gain[attenuation][7] << 8)); - rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); } else { TempVal = (u32)((dm_cck_tx_bb_gain_ch14[attenuation][0]) + (dm_cck_tx_bb_gain_ch14[attenuation][1] << 8)); - rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); TempVal = (u32)((dm_cck_tx_bb_gain_ch14[attenuation][2]) + (dm_cck_tx_bb_gain_ch14[attenuation][3] << 8) + (dm_cck_tx_bb_gain_ch14[attenuation][4] << 16)+ (dm_cck_tx_bb_gain_ch14[attenuation][5] << 24)); - rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); TempVal = (u32)((dm_cck_tx_bb_gain_ch14[attenuation][6]) + (dm_cck_tx_bb_gain_ch14[attenuation][7] << 8)); - rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); } } @@ -1110,7 +1107,7 @@ static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, if (!bInCH14) { TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][0] + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][1] << 8); - rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", rCCK0_TxFilter1, TempVal); @@ -1118,14 +1115,14 @@ static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, (CCKSwingTable_Ch1_Ch13[priv->CCK_index][3] << 8) + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][4] << 16)+ (CCKSwingTable_Ch1_Ch13[priv->CCK_index][5] << 24); - rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", rCCK0_TxFilter2, TempVal); TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][6] + (CCKSwingTable_Ch1_Ch13[priv->CCK_index][7] << 8); - rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n", rCCK0_DebugPort, TempVal); @@ -1133,20 +1130,20 @@ static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, TempVal = CCKSwingTable_Ch14[priv->CCK_index][0] + (CCKSwingTable_Ch14[priv->CCK_index][1] << 8); - rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal); RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n", rCCK0_TxFilter1, TempVal); TempVal = CCKSwingTable_Ch14[priv->CCK_index][2] + (CCKSwingTable_Ch14[priv->CCK_index][3] << 8) + (CCKSwingTable_Ch14[priv->CCK_index][4] << 16)+ (CCKSwingTable_Ch14[priv->CCK_index][5] << 24); - rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal); RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n", rCCK0_TxFilter2, TempVal); TempVal = CCKSwingTable_Ch14[priv->CCK_index][6] + (CCKSwingTable_Ch14[priv->CCK_index][7]<<8); - rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); + rtl92e_set_bb_reg(dev, rCCK0_DebugPort, bMaskLWord, TempVal); RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n", rCCK0_DebugPort, TempVal); } @@ -1167,8 +1164,8 @@ static void dm_txpower_reset_recovery(struct net_device *dev) struct r8192_priv *priv = rtllib_priv(dev); RT_TRACE(COMP_POWER_TRACKING, "Start Reset Recovery ==>\n"); - rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, - dm_tx_bb_gain[priv->rfa_txpowertrackingindex]); + rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, + dm_tx_bb_gain[priv->rfa_txpowertrackingindex]); RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc80 is %08x\n", dm_tx_bb_gain[priv->rfa_txpowertrackingindex]); RT_TRACE(COMP_POWER_TRACKING, @@ -1182,8 +1179,8 @@ static void dm_txpower_reset_recovery(struct net_device *dev) priv->CCKPresentAttentuation); dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); - rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, - dm_tx_bb_gain[priv->rfc_txpowertrackingindex]); + rtl92e_set_bb_reg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, + dm_tx_bb_gain[priv->rfc_txpowertrackingindex]); RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc90 is %08x\n", dm_tx_bb_gain[priv->rfc_txpowertrackingindex]); RT_TRACE(COMP_POWER_TRACKING, @@ -1231,18 +1228,18 @@ static void dm_bb_initialgain_restore(struct net_device *dev) if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) return; - rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); - rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bit_mask, - (u32)priv->initgain_backup.xaagccore1); - rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bit_mask, - (u32)priv->initgain_backup.xbagccore1); - rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, bit_mask, - (u32)priv->initgain_backup.xcagccore1); - rtl8192_setBBreg(dev, rOFDM0_XDAGCCore1, bit_mask, - (u32)priv->initgain_backup.xdagccore1); + rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x8); + rtl92e_set_bb_reg(dev, rOFDM0_XAAGCCore1, bit_mask, + (u32)priv->initgain_backup.xaagccore1); + rtl92e_set_bb_reg(dev, rOFDM0_XBAGCCore1, bit_mask, + (u32)priv->initgain_backup.xbagccore1); + rtl92e_set_bb_reg(dev, rOFDM0_XCAGCCore1, bit_mask, + (u32)priv->initgain_backup.xcagccore1); + rtl92e_set_bb_reg(dev, rOFDM0_XDAGCCore1, bit_mask, + (u32)priv->initgain_backup.xdagccore1); bit_mask = bMaskByte2; - rtl8192_setBBreg(dev, rCCK0_CCA, bit_mask, - (u32)priv->initgain_backup.cca); + rtl92e_set_bb_reg(dev, rCCK0_CCA, bit_mask, + (u32)priv->initgain_backup.cca); RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc50 is %x\n", priv->initgain_backup.xaagccore1); @@ -1254,7 +1251,7 @@ static void dm_bb_initialgain_restore(struct net_device *dev) priv->initgain_backup.xdagccore1); RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xa0a is %x\n", priv->initgain_backup.cca); - rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); + rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x1); } @@ -1278,7 +1275,7 @@ static void dm_bb_initialgain_backup(struct net_device *dev) if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI) return; - rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); + rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x8); priv->initgain_backup.xaagccore1 = (u8)rtl92e_get_bb_reg(dev, rOFDM0_XAAGCCore1, bit_mask); priv->initgain_backup.xbagccore1 = (u8)rtl92e_get_bb_reg(dev, rOFDM0_XBAGCCore1, bit_mask); priv->initgain_backup.xcagccore1 = (u8)rtl92e_get_bb_reg(dev, rOFDM0_XCAGCCore1, bit_mask); @@ -1375,7 +1372,7 @@ static void dm_ctrl_initgain_byrssi_by_driverrssi( fw_dig = 0; if (fw_dig <= 3) { for (i = 0; i < 3; i++) - rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); + rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x8); fw_dig++; dm_digtable.dig_state = DM_STA_DIG_OFF; } @@ -1409,7 +1406,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( if (dm_digtable.dig_algorithm_switch) { dm_digtable.dig_state = DM_STA_DIG_MAX; for (i = 0; i < 3; i++) - rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); + rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x1); dm_digtable.dig_algorithm_switch = 0; } @@ -1428,7 +1425,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX; dm_digtable.dig_state = DM_STA_DIG_OFF; - rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); + rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x8); write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x17); write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x17); @@ -1479,7 +1476,7 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( write_nic_byte(dev, 0xa0a, 0xcd); - rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); + rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x1); } dm_ctrl_initgain_byrssi_highpwr(dev); } @@ -2115,10 +2112,10 @@ static void dm_rxpath_sel_byrssi(struct net_device *dev) DM_RxPathSelTable.diff_TH) { DM_RxPathSelTable.rf_enable_rssi_th[min_rssi_index] = tmp_max_rssi+5; - rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, - 0x1<>i) & 0x1) { if (tmp_max_rssi >= DM_RxPathSelTable.rf_enable_rssi_th[i]) { - rtl8192_setBBreg(dev, - rOFDM0_TRxPathEnable, 0x1 << i, - 0x1); - rtl8192_setBBreg(dev, - rOFDM1_TRxPathEnable, - 0x1 << i, 0x1); + rtl92e_set_bb_reg(dev, + rOFDM0_TRxPathEnable, + 0x1 << i, 0x1); + rtl92e_set_bb_reg(dev, + rOFDM1_TRxPathEnable, + 0x1 << i, 0x1); DM_RxPathSelTable.rf_enable_rssi_th[i] = 100; disabled_rf_cnt--; -- cgit v1.3-6-gb490 From ae924acdaedd0b17b9dc29a3e61814d9cc98fdb0 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:58 +0200 Subject: staging: rtl8192e: Rename rtl8192_SetBWMode Use naming schema found in other rtlwifi devices. Rename rtl8192_SetBWMode to rtl92e_set_bw_mode. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 6 +++--- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 7bbbe7be6f60..08eaa951c70b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -1264,8 +1264,8 @@ static void rtl8192_SetBWModeWorkItem(struct net_device *dev) RT_TRACE(COMP_SWBW, "<==SetBWMode819xUsb()"); } -void rtl8192_SetBWMode(struct net_device *dev, enum ht_channel_width Bandwidth, - enum ht_extchnl_offset Offset) +void rtl92e_set_bw_mode(struct net_device *dev, enum ht_channel_width Bandwidth, + enum ht_extchnl_offset Offset) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index 1d961cfa51c0..ac4d2c94e2c6 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -91,9 +91,9 @@ extern u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath); extern u8 rtl92e_set_channel(struct net_device *dev, u8 channel); -extern void rtl8192_SetBWMode(struct net_device *dev, - enum ht_channel_width Bandwidth, - enum ht_extchnl_offset Offset); +extern void rtl92e_set_bw_mode(struct net_device *dev, + enum ht_channel_width Bandwidth, + enum ht_extchnl_offset Offset); extern void rtl92e_init_gain(struct net_device *dev, u8 Operation); extern void rtl92e_set_rf_off(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 99b36f8b5c79..c206e1dc1014 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -876,7 +876,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->handle_beacon = rtl8192_handle_beacon; priv->rtllib->SetWirelessMode = rtl8192_SetWirelessMode; priv->rtllib->LeisurePSLeave = LeisurePSLeave; - priv->rtllib->SetBWModeHandler = rtl8192_SetBWMode; + priv->rtllib->SetBWModeHandler = rtl92e_set_bw_mode; priv->rf_set_chan = rtl92e_set_channel; priv->rtllib->start_send_beacons = rtl92e_start_beacon; -- cgit v1.3-6-gb490 From ad8d51615c61cbb257cedfe86b11d13b8c9a08a4 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:27:59 +0200 Subject: staging: rtl8192e: Rename SetRFPowerState Use naming schema found in other rtlwifi devices. Rename SetRFPowerState to rtl92e_set_rf_power_state. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 12 +++++++----- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 9 +++------ 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 08eaa951c70b..817cd62f28b8 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -1580,26 +1580,28 @@ static bool SetRFPowerState8190(struct net_device *dev, return bResult; } -bool SetRFPowerState(struct net_device *dev, - enum rt_rf_power_state eRFPowerState) +bool rtl92e_set_rf_power_state(struct net_device *dev, + enum rt_rf_power_state eRFPowerState) { struct r8192_priv *priv = rtllib_priv(dev); bool bResult = false; - RT_TRACE(COMP_PS, "---------> SetRFPowerState(): eRFPowerState(%d)\n", + RT_TRACE(COMP_PS, + "---------> rtl92e_set_rf_power_state(): eRFPowerState(%d)\n", eRFPowerState); if (eRFPowerState == priv->rtllib->eRFPowerState && priv->bHwRfOffAction == 0) { RT_TRACE(COMP_PS, - "<--------- SetRFPowerState(): discard the request for eRFPowerState(%d) is the same.\n", + "<--------- rtl92e_set_rf_power_state(): discard the request for eRFPowerState(%d) is the same.\n", eRFPowerState); return bResult; } bResult = SetRFPowerState8190(dev, eRFPowerState); - RT_TRACE(COMP_PS, "<--------- SetRFPowerState(): bResult(%d)\n", + RT_TRACE(COMP_PS, + "<--------- rtl92e_set_rf_power_state(): bResult(%d)\n", bResult); return bResult; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index ac4d2c94e2c6..da25cba6aeb6 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -98,12 +98,9 @@ extern void rtl92e_init_gain(struct net_device *dev, u8 Operation); extern void rtl92e_set_rf_off(struct net_device *dev); -bool -SetRFPowerState( - struct net_device *dev, - enum rt_rf_power_state eRFPowerState - ); -#define PHY_SetRFPowerState SetRFPowerState +bool rtl92e_set_rf_power_state(struct net_device *dev, + enum rt_rf_power_state eRFPowerState); +#define PHY_SetRFPowerState rtl92e_set_rf_power_state extern void rtl92e_scan_op_backup(struct net_device *dev, u8 Operation); -- cgit v1.3-6-gb490 From 358e4ee166b7c7d7550c46b57000cd628c9001de Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:00 +0200 Subject: staging: rtl8192e: Rename CamResetAllEntry Use naming schema found in other rtlwifi devices. Rename CamResetAllEntry to rtl92e_cam_reset. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_cam.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index b6d26fa4e2ee..c7260ef80b76 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -809,7 +809,7 @@ start: if (priv->ResetProgress == RESET_TYPE_NORESET) rtl8192_SetWirelessMode(dev, priv->rtllib->mode); - CamResetAllEntry(dev); + rtl92e_cam_reset(dev); { u8 SECR_value = 0x0; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index f246222e5fc9..4c47dd969254 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -28,7 +28,7 @@ #include "r8190P_rtl8256.h" /* RTL8225 Radio frontend */ #include "r8192E_cmdpkt.h" -void CamResetAllEntry(struct net_device *dev) +void rtl92e_cam_reset(struct net_device *dev) { u32 ulcommand = 0; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h index f23ab46c77e7..9ef80ec3a672 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h @@ -28,7 +28,7 @@ #include struct net_device; -void CamResetAllEntry(struct net_device *dev); +void rtl92e_cam_reset(struct net_device *dev); void EnableHWSecurityConfig8192(struct net_device *dev); void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index c206e1dc1014..65d6043ffdf2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -824,7 +824,7 @@ static int rtl8192_sta_down(struct net_device *dev, bool shutdownrf) priv->rtllib->wpa_ie_len = 0; kfree(priv->rtllib->wpa_ie); priv->rtllib->wpa_ie = NULL; - CamResetAllEntry(dev); + rtl92e_cam_reset(dev); memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32); rtl8192_irq_disable(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index 15fc48440cdc..df7cf084a76b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -711,7 +711,7 @@ static int r8192_wx_set_enc(struct net_device *dev, if (wrqu->encoding.flags & IW_ENCODE_DISABLED) { ieee->pairwise_key_type = ieee->group_key_type = KEY_TYPE_NA; - CamResetAllEntry(dev); + rtl92e_cam_reset(dev); memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32); goto end_hw_sec; @@ -926,7 +926,7 @@ static int r8192_wx_set_enc_ext(struct net_device *dev, ext->alg == IW_ENCODE_ALG_NONE) { ieee->pairwise_key_type = ieee->group_key_type = KEY_TYPE_NA; - CamResetAllEntry(dev); + rtl92e_cam_reset(dev); memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32); goto end_hw_sec; -- cgit v1.3-6-gb490 From 66497f0223cb23b572e360d32ad5473f618c5e57 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:01 +0200 Subject: staging: rtl8192e: Rename CamRestoreAllEntry Use naming schema found in other rtlwifi devices. Rename CamRestoreAllEntry to rtl92e_cam_restore. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_cam.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index 4c47dd969254..66e06bea21d3 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -154,7 +154,7 @@ void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, RT_TRACE(COMP_SEC, "=========>after set key, usconfig:%x\n", usConfig); } -void CamRestoreAllEntry(struct net_device *dev) +void rtl92e_cam_restore(struct net_device *dev) { u8 EntryId = 0; struct r8192_priv *priv = rtllib_priv(dev); @@ -170,7 +170,7 @@ void CamRestoreAllEntry(struct net_device *dev) 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - RT_TRACE(COMP_SEC, "CamRestoreAllEntry:\n"); + RT_TRACE(COMP_SEC, "rtl92e_cam_restore:\n"); if ((priv->rtllib->pairwise_key_type == KEY_TYPE_WEP40) || diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h index 9ef80ec3a672..001ff4021a60 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h @@ -34,6 +34,6 @@ void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent); void set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent, u8 is_mesh); -void CamRestoreAllEntry(struct net_device *dev); +void rtl92e_cam_restore(struct net_device *dev); #endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 65d6043ffdf2..b12256ce44b4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1376,7 +1376,7 @@ RESET_START: rtl819x_silentreset_mesh_bk(dev, IsPortal); } - CamRestoreAllEntry(dev); + rtl92e_cam_restore(dev); dm_restore_dynamic_mechanism_state(dev); END: priv->ResetProgress = RESET_TYPE_NORESET; -- cgit v1.3-6-gb490 From 3742093268faec364254966286b69fa4801bbc01 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:02 +0200 Subject: staging: rtl8192e: Rename EnableHWSecurityConfig8192 Use naming schema found in other rtlwifi devices. Rename EnableHWSecurityConfig8192 to rtl92e_enable_hw_security_config. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_cam.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index c7260ef80b76..ead3e2208fb7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1001,7 +1001,7 @@ void rtl92e_link_change(struct net_device *dev) priv->ops->update_ratr_table(dev); if ((KEY_TYPE_WEP40 == ieee->pairwise_key_type) || (KEY_TYPE_WEP104 == ieee->pairwise_key_type)) - EnableHWSecurityConfig8192(dev); + rtl92e_enable_hw_security_config(dev); } else { write_nic_byte(dev, 0x173, 0); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index 66e06bea21d3..39640dda4acf 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -36,7 +36,7 @@ void rtl92e_cam_reset(struct net_device *dev) write_nic_dword(dev, RWCAM, ulcommand); } -void EnableHWSecurityConfig8192(struct net_device *dev) +void rtl92e_enable_hw_security_config(struct net_device *dev) { u8 SECR_value = 0x0; struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h index 001ff4021a60..b0619b77b1f0 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h @@ -29,7 +29,7 @@ struct net_device; void rtl92e_cam_reset(struct net_device *dev); -void EnableHWSecurityConfig8192(struct net_device *dev); +void rtl92e_enable_hw_security_config(struct net_device *dev); void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent); void set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index b12256ce44b4..df3b846aefa3 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1350,7 +1350,7 @@ RESET_START: priv->RFChangeInProgress = false; spin_unlock_irqrestore(&priv->rf_ps_lock, flag); - EnableHWSecurityConfig8192(dev); + rtl92e_enable_hw_security_config(dev); if (ieee->state == RTLLIB_LINKED && ieee->iw_mode == IW_MODE_INFRA) { @@ -2375,7 +2375,7 @@ static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (is_zero_ether_addr(ieee->ap_mac_addr)) ieee->iw_mode = IW_MODE_ADHOC; memcpy((u8 *)key, ipw->u.crypt.key, 16); - EnableHWSecurityConfig8192(dev); + rtl92e_enable_hw_security_config(dev); set_swcam(dev, 4, ipw->u.crypt.idx, ieee->pairwise_key_type, (u8 *)ieee->ap_mac_addr, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index df7cf084a76b..4795c727bb5b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -750,12 +750,12 @@ static int r8192_wx_set_enc(struct net_device *dev, } if (wrqu->encoding.length == 0x5) { ieee->pairwise_key_type = KEY_TYPE_WEP40; - EnableHWSecurityConfig8192(dev); + rtl92e_enable_hw_security_config(dev); } else if (wrqu->encoding.length == 0xd) { ieee->pairwise_key_type = KEY_TYPE_WEP104; - EnableHWSecurityConfig8192(dev); + rtl92e_enable_hw_security_config(dev); setKey(dev, key_idx, key_idx, KEY_TYPE_WEP104, zero_addr[key_idx], 0, hwkey); set_swcam(dev, key_idx, key_idx, KEY_TYPE_WEP104, @@ -943,7 +943,7 @@ static int r8192_wx_set_enc_ext(struct net_device *dev, if ((ext->key_len == 13) && (alg == KEY_TYPE_WEP40)) alg = KEY_TYPE_WEP104; ieee->pairwise_key_type = alg; - EnableHWSecurityConfig8192(dev); + rtl92e_enable_hw_security_config(dev); } memcpy((u8 *)key, ext->key, 16); -- cgit v1.3-6-gb490 From 408bd7b7b244c23a78deb41cadbeb070c794da94 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:03 +0200 Subject: staging: rtl8192e: Rename setKey Use naming schema found in other rtlwifi devices. Rename setKey to rtl92e_set_key. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 84 +++++++++++++++------------- drivers/staging/rtl8192e/rtl8192e/rtl_cam.h | 5 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 26 +++++---- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 13 +++-- 4 files changed, 68 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index 39640dda4acf..8e4da40793bd 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -87,8 +87,9 @@ void set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, } } -void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, - const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent) +void rtl92e_set_key(struct net_device *dev, u8 EntryNo, u8 KeyIndex, + u16 KeyType, const u8 *MacAddr, u8 DefaultKey, + u32 *KeyContent) { u32 TargetCommand = 0; u32 TargetContent = 0; @@ -115,7 +116,7 @@ void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, netdev_info(dev, "%s(): Invalid CAM entry\n", __func__); RT_TRACE(COMP_SEC, - "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d,KeyType:%d, MacAddr %pM\n", + "====>to rtl92e_set_key(), dev:%p, EntryNo:%d, KeyIndex:%d,KeyType:%d, MacAddr %pM\n", dev, EntryNo, KeyIndex, KeyType, MacAddr); if (DefaultKey) @@ -179,36 +180,41 @@ void rtl92e_cam_restore(struct net_device *dev) for (EntryId = 0; EntryId < 4; EntryId++) { MacAddr = CAM_CONST_ADDR[EntryId]; if (priv->rtllib->swcamtable[EntryId].bused) { - setKey(dev, EntryId, EntryId, - priv->rtllib->pairwise_key_type, MacAddr, - 0, (u32 *)(&priv->rtllib->swcamtable - [EntryId].key_buf[0])); + rtl92e_set_key(dev, EntryId, EntryId, + priv->rtllib->pairwise_key_type, + MacAddr, 0, + (u32 *)(&priv->rtllib->swcamtable + [EntryId].key_buf[0])); } } } else if (priv->rtllib->pairwise_key_type == KEY_TYPE_TKIP) { if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { - setKey(dev, 4, 0, priv->rtllib->pairwise_key_type, - (u8 *)dev->dev_addr, 0, - (u32 *)(&priv->rtllib->swcamtable[4].key_buf[0])); + rtl92e_set_key(dev, 4, 0, + priv->rtllib->pairwise_key_type, + (u8 *)dev->dev_addr, 0, + (u32 *)(&priv->rtllib->swcamtable[4]. + key_buf[0])); } else { - setKey(dev, 4, 0, priv->rtllib->pairwise_key_type, - MacAddr, 0, - (u32 *)(&priv->rtllib->swcamtable[4].key_buf[0])); + rtl92e_set_key(dev, 4, 0, + priv->rtllib->pairwise_key_type, + MacAddr, 0, + (u32 *)(&priv->rtllib->swcamtable[4]. + key_buf[0])); } } else if (priv->rtllib->pairwise_key_type == KEY_TYPE_CCMP) { if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { - setKey(dev, 4, 0, - priv->rtllib->pairwise_key_type, - (u8 *)dev->dev_addr, 0, - (u32 *)(&priv->rtllib->swcamtable[4]. - key_buf[0])); + rtl92e_set_key(dev, 4, 0, + priv->rtllib->pairwise_key_type, + (u8 *)dev->dev_addr, 0, + (u32 *)(&priv->rtllib->swcamtable[4]. + key_buf[0])); } else { - setKey(dev, 4, 0, - priv->rtllib->pairwise_key_type, MacAddr, - 0, (u32 *)(&priv->rtllib->swcamtable[4]. - key_buf[0])); + rtl92e_set_key(dev, 4, 0, + priv->rtllib->pairwise_key_type, MacAddr, + 0, (u32 *)(&priv->rtllib->swcamtable[4]. + key_buf[0])); } } @@ -216,20 +222,18 @@ void rtl92e_cam_restore(struct net_device *dev) MacAddr = CAM_CONST_BROAD; for (EntryId = 1; EntryId < 4; EntryId++) { if (priv->rtllib->swcamtable[EntryId].bused) { - setKey(dev, EntryId, EntryId, - priv->rtllib->group_key_type, - MacAddr, 0, - (u32 *)(&priv->rtllib->swcamtable[EntryId].key_buf[0]) - ); + rtl92e_set_key(dev, EntryId, EntryId, + priv->rtllib->group_key_type, + MacAddr, 0, + (u32 *)(&priv->rtllib->swcamtable[EntryId].key_buf[0])); } } if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { if (priv->rtllib->swcamtable[0].bused) { - setKey(dev, 0, 0, - priv->rtllib->group_key_type, - CAM_CONST_ADDR[0], 0, - (u32 *)(&priv->rtllib->swcamtable[0].key_buf[0]) - ); + rtl92e_set_key(dev, 0, 0, + priv->rtllib->group_key_type, + CAM_CONST_ADDR[0], 0, + (u32 *)(&priv->rtllib->swcamtable[0].key_buf[0])); } else { netdev_warn(dev, "%s(): ADHOC TKIP: missing key entry.\n", @@ -241,19 +245,19 @@ void rtl92e_cam_restore(struct net_device *dev) MacAddr = CAM_CONST_BROAD; for (EntryId = 1; EntryId < 4; EntryId++) { if (priv->rtllib->swcamtable[EntryId].bused) { - setKey(dev, EntryId, EntryId, - priv->rtllib->group_key_type, - MacAddr, 0, - (u32 *)(&priv->rtllib->swcamtable[EntryId].key_buf[0])); + rtl92e_set_key(dev, EntryId, EntryId, + priv->rtllib->group_key_type, + MacAddr, 0, + (u32 *)(&priv->rtllib->swcamtable[EntryId].key_buf[0])); } } if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { if (priv->rtllib->swcamtable[0].bused) { - setKey(dev, 0, 0, - priv->rtllib->group_key_type, - CAM_CONST_ADDR[0], 0, - (u32 *)(&priv->rtllib->swcamtable[0].key_buf[0])); + rtl92e_set_key(dev, 0, 0, + priv->rtllib->group_key_type, + CAM_CONST_ADDR[0], 0, + (u32 *)(&priv->rtllib->swcamtable[0].key_buf[0])); } else { netdev_warn(dev, "%s(): ADHOC CCMP: missing key entry.\n", diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h index b0619b77b1f0..a26f3f5254b5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h @@ -30,8 +30,9 @@ struct net_device; void rtl92e_cam_reset(struct net_device *dev); void rtl92e_enable_hw_security_config(struct net_device *dev); -void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, - const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent); +void rtl92e_set_key(struct net_device *dev, u8 EntryNo, u8 KeyIndex, + u16 KeyType, const u8 *MacAddr, u8 DefaultKey, + u32 *KeyContent); void set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent, u8 is_mesh); void rtl92e_cam_restore(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index df3b846aefa3..00f38ebac190 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2380,20 +2380,22 @@ static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ieee->pairwise_key_type, (u8 *)ieee->ap_mac_addr, 0, key, 0); - setKey(dev, 4, ipw->u.crypt.idx, - ieee->pairwise_key_type, - (u8 *)ieee->ap_mac_addr, 0, key); + rtl92e_set_key(dev, 4, ipw->u.crypt.idx, + ieee->pairwise_key_type, + (u8 *)ieee->ap_mac_addr, + 0, key); if (ieee->iw_mode == IW_MODE_ADHOC) { set_swcam(dev, ipw->u.crypt.idx, ipw->u.crypt.idx, ieee->pairwise_key_type, (u8 *)ieee->ap_mac_addr, 0, key, 0); - setKey(dev, ipw->u.crypt.idx, - ipw->u.crypt.idx, - ieee->pairwise_key_type, - (u8 *)ieee->ap_mac_addr, - 0, key); + rtl92e_set_key(dev, + ipw->u.crypt.idx, + ipw->u.crypt.idx, + ieee->pairwise_key_type, + (u8 *)ieee->ap_mac_addr, + 0, key); } } if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) @@ -2422,10 +2424,10 @@ static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ipw->u.crypt.idx, ieee->group_key_type, broadcast_addr, 0, key, 0); - setKey(dev, ipw->u.crypt.idx, - ipw->u.crypt.idx, - ieee->group_key_type, - broadcast_addr, 0, key); + rtl92e_set_key(dev, ipw->u.crypt.idx, + ipw->u.crypt.idx, + ieee->group_key_type, + broadcast_addr, 0, key); } } } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index 4795c727bb5b..b2a4bf16d8bc 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -756,8 +756,8 @@ static int r8192_wx_set_enc(struct net_device *dev, else if (wrqu->encoding.length == 0xd) { ieee->pairwise_key_type = KEY_TYPE_WEP104; rtl92e_enable_hw_security_config(dev); - setKey(dev, key_idx, key_idx, KEY_TYPE_WEP104, - zero_addr[key_idx], 0, hwkey); + rtl92e_set_key(dev, key_idx, key_idx, KEY_TYPE_WEP104, + zero_addr[key_idx], 0, hwkey); set_swcam(dev, key_idx, key_idx, KEY_TYPE_WEP104, zero_addr[key_idx], 0, hwkey, 0); } else { @@ -950,19 +950,20 @@ static int r8192_wx_set_enc_ext(struct net_device *dev, if ((alg & KEY_TYPE_WEP40) && (ieee->auth_mode != 2)) { if (ext->key_len == 13) ieee->pairwise_key_type = alg = KEY_TYPE_WEP104; - setKey(dev, idx, idx, alg, zero, 0, key); + rtl92e_set_key(dev, idx, idx, alg, zero, 0, key); set_swcam(dev, idx, idx, alg, zero, 0, key, 0); } else if (group) { ieee->group_key_type = alg; - setKey(dev, idx, idx, alg, broadcast_addr, 0, key); + rtl92e_set_key(dev, idx, idx, alg, broadcast_addr, 0, + key); set_swcam(dev, idx, idx, alg, broadcast_addr, 0, key, 0); } else { if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) && ieee->pHTInfo->bCurrentHTSupport) write_nic_byte(dev, 0x173, 1); - setKey(dev, 4, idx, alg, (u8 *)ieee->ap_mac_addr, - 0, key); + rtl92e_set_key(dev, 4, idx, alg, + (u8 *)ieee->ap_mac_addr, 0, key); set_swcam(dev, 4, idx, alg, (u8 *)ieee->ap_mac_addr, 0, key, 0); } -- cgit v1.3-6-gb490 From aae7e72e1d4dce958f5ba26c7037546bd846a89d Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:04 +0200 Subject: staging: rtl8192e: Rename set_swcam Use naming schema found in other rtlwifi devices. Rename set_swcam to rtl92e_set_swcam. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 5 +++-- drivers/staging/rtl8192e/rtl8192e/rtl_cam.h | 5 +++-- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 29 +++++++++++++++------------- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 14 +++++++------- 4 files changed, 29 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index 8e4da40793bd..9c14286146a2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -68,8 +68,9 @@ void rtl92e_enable_hw_security_config(struct net_device *dev) write_nic_byte(dev, SECR, SECR_value); } -void set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, - const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent, u8 is_mesh) +void rtl92e_set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, + u16 KeyType, const u8 *MacAddr, u8 DefaultKey, + u32 *KeyContent, u8 is_mesh) { struct r8192_priv *priv = rtllib_priv(dev); struct rtllib_device *ieee = priv->rtllib; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h index a26f3f5254b5..9ef8b36fc6b5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h @@ -33,8 +33,9 @@ void rtl92e_enable_hw_security_config(struct net_device *dev); void rtl92e_set_key(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent); -void set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, - const u8 *MacAddr, u8 DefaultKey, u32 *KeyContent, u8 is_mesh); +void rtl92e_set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, + u16 KeyType, const u8 *MacAddr, u8 DefaultKey, + u32 *KeyContent, u8 is_mesh); void rtl92e_cam_restore(struct net_device *dev); #endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 00f38ebac190..2a34e4d2e3ff 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2376,20 +2376,22 @@ static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ieee->iw_mode = IW_MODE_ADHOC; memcpy((u8 *)key, ipw->u.crypt.key, 16); rtl92e_enable_hw_security_config(dev); - set_swcam(dev, 4, ipw->u.crypt.idx, - ieee->pairwise_key_type, - (u8 *)ieee->ap_mac_addr, - 0, key, 0); + rtl92e_set_swcam(dev, 4, + ipw->u.crypt.idx, + ieee->pairwise_key_type, + (u8 *)ieee->ap_mac_addr, + 0, key, 0); rtl92e_set_key(dev, 4, ipw->u.crypt.idx, ieee->pairwise_key_type, (u8 *)ieee->ap_mac_addr, 0, key); if (ieee->iw_mode == IW_MODE_ADHOC) { - set_swcam(dev, ipw->u.crypt.idx, - ipw->u.crypt.idx, - ieee->pairwise_key_type, - (u8 *)ieee->ap_mac_addr, - 0, key, 0); + rtl92e_set_swcam(dev, + ipw->u.crypt.idx, + ipw->u.crypt.idx, + ieee->pairwise_key_type, + (u8 *)ieee->ap_mac_addr, + 0, key, 0); rtl92e_set_key(dev, ipw->u.crypt.idx, ipw->u.crypt.idx, @@ -2420,10 +2422,11 @@ static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ieee->group_key_type = KEY_TYPE_NA; if (ieee->group_key_type) { - set_swcam(dev, ipw->u.crypt.idx, - ipw->u.crypt.idx, - ieee->group_key_type, - broadcast_addr, 0, key, 0); + rtl92e_set_swcam(dev, ipw->u.crypt.idx, + ipw->u.crypt.idx, + ieee->group_key_type, + broadcast_addr, 0, key, + 0); rtl92e_set_key(dev, ipw->u.crypt.idx, ipw->u.crypt.idx, ieee->group_key_type, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index b2a4bf16d8bc..1b29f14dd2b2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -758,8 +758,8 @@ static int r8192_wx_set_enc(struct net_device *dev, rtl92e_enable_hw_security_config(dev); rtl92e_set_key(dev, key_idx, key_idx, KEY_TYPE_WEP104, zero_addr[key_idx], 0, hwkey); - set_swcam(dev, key_idx, key_idx, KEY_TYPE_WEP104, - zero_addr[key_idx], 0, hwkey, 0); + rtl92e_set_swcam(dev, key_idx, key_idx, KEY_TYPE_WEP104, + zero_addr[key_idx], 0, hwkey, 0); } else { netdev_info(dev, "wrong type in WEP, not WEP40 and WEP104\n"); @@ -951,21 +951,21 @@ static int r8192_wx_set_enc_ext(struct net_device *dev, if (ext->key_len == 13) ieee->pairwise_key_type = alg = KEY_TYPE_WEP104; rtl92e_set_key(dev, idx, idx, alg, zero, 0, key); - set_swcam(dev, idx, idx, alg, zero, 0, key, 0); + rtl92e_set_swcam(dev, idx, idx, alg, zero, 0, key, 0); } else if (group) { ieee->group_key_type = alg; rtl92e_set_key(dev, idx, idx, alg, broadcast_addr, 0, key); - set_swcam(dev, idx, idx, alg, broadcast_addr, 0, - key, 0); + rtl92e_set_swcam(dev, idx, idx, alg, broadcast_addr, 0, + key, 0); } else { if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) && ieee->pHTInfo->bCurrentHTSupport) write_nic_byte(dev, 0x173, 1); rtl92e_set_key(dev, 4, idx, alg, (u8 *)ieee->ap_mac_addr, 0, key); - set_swcam(dev, 4, idx, alg, (u8 *)ieee->ap_mac_addr, - 0, key, 0); + rtl92e_set_swcam(dev, 4, idx, alg, + (u8 *)ieee->ap_mac_addr, 0, key, 0); } -- cgit v1.3-6-gb490 From a643d927c2ec9210d07b8e9aa20d598675dc2aef Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:05 +0200 Subject: staging: rtl8192e: Rename check_rfctrl_gpio_timer Use naming schema found in other rtlwifi devices. Rename check_rfctrl_gpio_timer to rtl92e_check_rfctrl_gpio_timer. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 8 ++++---- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_pm.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 2a34e4d2e3ff..035946dd09b0 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -783,7 +783,7 @@ static int _rtl8192_sta_up(struct net_device *dev, bool is_silent_reset) priv->bfirst_init = false; if (priv->polling_timer_on == 0) - check_rfctrl_gpio_timer((unsigned long)dev); + rtl92e_check_rfctrl_gpio_timer((unsigned long)dev); if (priv->rtllib->state != RTLLIB_LINKED) rtllib_softmac_start_protocol(priv->rtllib, 0); @@ -1099,7 +1099,7 @@ static short rtl8192_init(struct net_device *dev) (unsigned long) dev); setup_timer(&priv->gpio_polling_timer, - check_rfctrl_gpio_timer, + rtl92e_check_rfctrl_gpio_timer, (unsigned long)dev); rtl8192_irq_disable(dev); @@ -2713,7 +2713,7 @@ static int rtl8192_pci_probe(struct pci_dev *pdev, RT_TRACE(COMP_INIT, "dev name: %s\n", dev->name); if (priv->polling_timer_on == 0) - check_rfctrl_gpio_timer((unsigned long)dev); + rtl92e_check_rfctrl_gpio_timer((unsigned long)dev); RT_TRACE(COMP_INIT, "Driver probe completed\n"); return 0; @@ -2843,7 +2843,7 @@ static void __exit rtl8192_pci_module_exit(void) RT_TRACE(COMP_DOWN, "Exiting"); } -void check_rfctrl_gpio_timer(unsigned long data) +void rtl92e_check_rfctrl_gpio_timer(unsigned long data) { struct r8192_priv *priv = rtllib_priv((struct net_device *)data); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 26e54e41ced6..95dad7d6dbe1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -593,7 +593,7 @@ void rtl8192_tx_enable(struct net_device *); void rtl8192_hw_sleep_wq(void *data); void rtl8192_commit(struct net_device *dev); -void check_rfctrl_gpio_timer(unsigned long data); +void rtl92e_check_rfctrl_gpio_timer(unsigned long data); void rtl8192_hw_wakeup_wq(void *data); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c index e4908672421c..297a28b6057a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c @@ -95,7 +95,7 @@ int rtl8192E_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D0, 0); if (priv->polling_timer_on == 0) - check_rfctrl_gpio_timer((unsigned long)dev); + rtl92e_check_rfctrl_gpio_timer((unsigned long)dev); if (!netif_running(dev)) { netdev_info(dev, -- cgit v1.3-6-gb490 From f434f9d5c60825f3a426a9ac5c5222b0eab8c82d Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:06 +0200 Subject: staging: rtl8192e: Rename MgntActSet_RF_State Use naming schema found in other rtlwifi devices. Rename MgntActSet_RF_State to rtl92e_set_rf_state. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 6 +++--- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 16 ++++++++-------- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_pm.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 6 +++--- 6 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index ead3e2208fb7..38c3ed6165de 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -881,18 +881,18 @@ start: RT_TRACE((COMP_INIT | COMP_RF | COMP_POWER), "%s(): Turn off RF for RegRfOff ----------\n", __func__); - MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_SW, true); + rtl92e_set_rf_state(dev, eRfOff, RF_CHANGE_BY_SW, true); } else if (priv->rtllib->RfOffReason > RF_CHANGE_BY_PS) { RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), "%s(): Turn off RF for RfOffReason(%d) ----------\n", __func__, priv->rtllib->RfOffReason); - MgntActSet_RF_State(dev, eRfOff, priv->rtllib->RfOffReason, + rtl92e_set_rf_state(dev, eRfOff, priv->rtllib->RfOffReason, true); } else if (priv->rtllib->RfOffReason >= RF_CHANGE_BY_IPS) { RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), "%s(): Turn off RF for RfOffReason(%d) ----------\n", __func__, priv->rtllib->RfOffReason); - MgntActSet_RF_State(dev, eRfOff, priv->rtllib->RfOffReason, + rtl92e_set_rf_state(dev, eRfOff, priv->rtllib->RfOffReason, true); } else { RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), "%s(): RF-ON\n", diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 035946dd09b0..5a0217128e8d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -149,7 +149,7 @@ void write_nic_word(struct net_device *dev, int x, u16 y) /**************************************************************************** -----------------------------GENERAL FUNCTION------------------------- *****************************************************************************/ -bool MgntActSet_RF_State(struct net_device *dev, +bool rtl92e_set_rf_state(struct net_device *dev, enum rt_rf_power_state StateToSet, RT_RF_CHANGE_SOURCE ChangeSource, bool ProtectOrNot) @@ -163,7 +163,7 @@ bool MgntActSet_RF_State(struct net_device *dev, unsigned long flag; RT_TRACE((COMP_PS | COMP_RF), - "===>MgntActSet_RF_State(): StateToSet(%d)\n", StateToSet); + "===>rtl92e_set_rf_state(): StateToSet(%d)\n", StateToSet); ProtectOrNot = false; @@ -174,13 +174,13 @@ bool MgntActSet_RF_State(struct net_device *dev, if (priv->RFChangeInProgress) { spin_unlock_irqrestore(&priv->rf_ps_lock, flag); RT_TRACE((COMP_PS | COMP_RF), - "MgntActSet_RF_State(): RF Change in progress! Wait to set..StateToSet(%d).\n", + "rtl92e_set_rf_state(): RF Change in progress! Wait to set..StateToSet(%d).\n", StateToSet); while (priv->RFChangeInProgress) { RFWaitCounter++; RT_TRACE((COMP_PS | COMP_RF), - "MgntActSet_RF_State(): Wait 1 ms (%d times)...\n", + "rtl92e_set_rf_state(): Wait 1 ms (%d times)...\n", RFWaitCounter); mdelay(1); @@ -218,7 +218,7 @@ bool MgntActSet_RF_State(struct net_device *dev, bConnectBySSID = true; } else { RT_TRACE((COMP_PS | COMP_RF), - "MgntActSet_RF_State - eRfon reject pMgntInfo->RfOffReason= 0x%x, ChangeSource=0x%X\n", + "rtl92e_set_rf_state - eRfon reject pMgntInfo->RfOffReason= 0x%x, ChangeSource=0x%X\n", priv->rtllib->RfOffReason, ChangeSource); } @@ -255,7 +255,7 @@ bool MgntActSet_RF_State(struct net_device *dev, if (bActionAllowed) { RT_TRACE((COMP_PS | COMP_RF), - "MgntActSet_RF_State(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", + "rtl92e_set_rf_state(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n", StateToSet, priv->rtllib->RfOffReason); PHY_SetRFPowerState(dev, StateToSet); if (StateToSet == eRfOn) { @@ -268,7 +268,7 @@ bool MgntActSet_RF_State(struct net_device *dev, } } else { RT_TRACE((COMP_PS | COMP_RF), - "MgntActSet_RF_State(): Action is rejected.... StateToSet(%d), ChangeSource(%#X), RfOffReason(%#X)\n", + "rtl92e_set_rf_state(): Action is rejected.... StateToSet(%d), ChangeSource(%#X), RfOffReason(%#X)\n", StateToSet, ChangeSource, priv->rtllib->RfOffReason); } @@ -278,7 +278,7 @@ bool MgntActSet_RF_State(struct net_device *dev, spin_unlock_irqrestore(&priv->rf_ps_lock, flag); } - RT_TRACE((COMP_PS | COMP_RF), "<===MgntActSet_RF_State()\n"); + RT_TRACE((COMP_PS | COMP_RF), "<===rtl92e_set_rf_state()\n"); return bActionAllowed; } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 95dad7d6dbe1..622ce202842a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -617,7 +617,7 @@ void rtl8192_record_rxdesc_forlateruse(struct rtllib_rx_stats *psrc_stats, bool NicIFEnableNIC(struct net_device *dev); bool NicIFDisableNIC(struct net_device *dev); -bool MgntActSet_RF_State(struct net_device *dev, +bool rtl92e_set_rf_state(struct net_device *dev, enum rt_rf_power_state StateToSet, RT_RF_CHANGE_SOURCE ChangeSource, bool ProtectOrNot); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index e967ba0a88ef..d993ec7a51de 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -1892,7 +1892,7 @@ static void dm_CheckRfCtrlGPIO(void *data) if (bActuallySet) { mdelay(1000); priv->bHwRfOffAction = 1; - MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW, + rtl92e_set_rf_state(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW, true); if (priv->bHwRadioOff) argv[1] = "RFOFF"; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c index 297a28b6057a..c92d6df135fc 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c @@ -45,7 +45,7 @@ int rtl8192E_suspend(struct pci_dev *pdev, pm_message_t state) netif_device_detach(dev); if (!priv->rtllib->bSupportRemoteWakeUp) { - MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_INIT, true); + rtl92e_set_rf_state(dev, eRfOff, RF_CHANGE_BY_INIT, true); ulRegRead = read_nic_dword(dev, CPU_GEN); ulRegRead |= CPU_GEN_SYSTEM_RESET; write_nic_dword(dev, CPU_GEN, ulRegRead); @@ -108,7 +108,7 @@ int rtl8192E_resume(struct pci_dev *pdev) dev->netdev_ops->ndo_open(dev); if (!priv->rtllib->bSupportRemoteWakeUp) - MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_INIT, true); + rtl92e_set_rf_state(dev, eRfOn, RF_CHANGE_BY_INIT, true); out: RT_TRACE(COMP_POWER, "<================r8192E resume call.\n"); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index 404cb83153d9..fc4503f2a82e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -45,7 +45,7 @@ static void rtl8192_hw_sleep_down(struct net_device *dev) spin_unlock_irqrestore(&priv->rf_ps_lock, flags); RT_TRACE(COMP_DBG, "%s()============>come to sleep down\n", __func__); - MgntActSet_RF_State(dev, eRfSleep, RF_CHANGE_BY_PS, false); + rtl92e_set_rf_state(dev, eRfSleep, RF_CHANGE_BY_PS, false); } void rtl8192_hw_sleep_wq(void *data) @@ -74,7 +74,7 @@ void rtl8192_hw_wakeup(struct net_device *dev) } spin_unlock_irqrestore(&priv->rf_ps_lock, flags); RT_TRACE(COMP_PS, "%s()============>come to wake up\n", __func__); - MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_PS, false); + rtl92e_set_rf_state(dev, eRfOn, RF_CHANGE_BY_PS, false); } void rtl8192_hw_wakeup_wq(void *data) @@ -133,7 +133,7 @@ static void InactivePsWorkItemCallback(struct net_device *dev) RT_TRACE(COMP_PS, "InactivePsWorkItemCallback(): Set RF to %s.\n", pPSC->eInactivePowerState == eRfOff ? "OFF" : "ON"); - MgntActSet_RF_State(dev, pPSC->eInactivePowerState, RF_CHANGE_BY_IPS, + rtl92e_set_rf_state(dev, pPSC->eInactivePowerState, RF_CHANGE_BY_IPS, false); pPSC->bSwRfProcessing = false; -- cgit v1.3-6-gb490 From af002dc63731fb8f31bdac5b53af80bec4a3f776 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:07 +0200 Subject: staging: rtl8192e: Rename NicIFDisableNIC Use naming schema found in other rtlwifi devices. Rename NicIFDisableNIC to rtl92e_disable_nic. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 817cd62f28b8..a8c62b040d9d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -1537,7 +1537,7 @@ static bool SetRFPowerState8190(struct net_device *dev, if (pPSC->RegRfPsLevel & RT_RF_OFF_LEVL_HALT_NIC && !RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC)) { - NicIFDisableNIC(dev); + rtl92e_disable_nic(dev); RT_SET_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC); } else if (!(pPSC->RegRfPsLevel & RT_RF_OFF_LEVL_HALT_NIC)) { diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 5a0217128e8d..9a10a48d1757 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2805,7 +2805,7 @@ bool NicIFEnableNIC(struct net_device *dev) RT_TRACE(COMP_PS, "<===========%s()\n", __func__); return init_status; } -bool NicIFDisableNIC(struct net_device *dev) +bool rtl92e_disable_nic(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); u8 tmp_state = 0; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 622ce202842a..788170f8913f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -615,7 +615,7 @@ u8 rtl819x_query_rxpwrpercentage(char antpower); void rtl8192_record_rxdesc_forlateruse(struct rtllib_rx_stats *psrc_stats, struct rtllib_rx_stats *ptarget_stats); bool NicIFEnableNIC(struct net_device *dev); -bool NicIFDisableNIC(struct net_device *dev); +bool rtl92e_disable_nic(struct net_device *dev); bool rtl92e_set_rf_state(struct net_device *dev, enum rt_rf_power_state StateToSet, -- cgit v1.3-6-gb490 From 502bd1d7c35fad9ab3806f2b6597fa92a2f6c132 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:08 +0200 Subject: staging: rtl8192e: Rename NicIFEnableNIC Use naming schema found in other rtlwifi devices. Rename NicIFEnableNIC to rtl92e_enable_nic. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index a8c62b040d9d..3efa84d89955 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -1441,7 +1441,7 @@ static bool SetRFPowerState8190(struct net_device *dev, do { InitilizeCount--; priv->RegRfOff = false; - rtstatus = NicIFEnableNIC(dev); + rtstatus = rtl92e_enable_nic(dev); } while (!rtstatus && (InitilizeCount > 0)); if (!rtstatus) { diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 9a10a48d1757..a1b6e1db4dd7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2775,7 +2775,7 @@ static void rtl8192_pci_disconnect(struct pci_dev *pdev) RT_TRACE(COMP_DOWN, "wlan driver removed\n"); } -bool NicIFEnableNIC(struct net_device *dev) +bool rtl92e_enable_nic(struct net_device *dev) { bool init_status = true; struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 788170f8913f..ce71270a62d4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -614,7 +614,7 @@ u8 rtl819x_evm_dbtopercentage(char value); u8 rtl819x_query_rxpwrpercentage(char antpower); void rtl8192_record_rxdesc_forlateruse(struct rtllib_rx_stats *psrc_stats, struct rtllib_rx_stats *ptarget_stats); -bool NicIFEnableNIC(struct net_device *dev); +bool rtl92e_enable_nic(struct net_device *dev); bool rtl92e_disable_nic(struct net_device *dev); bool rtl92e_set_rf_state(struct net_device *dev, -- cgit v1.3-6-gb490 From b59a4ca3d4421866cc7f49135ab6f7b7c84fdb48 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:09 +0200 Subject: staging: rtl8192e: Rename read_nic_byte Use naming schema found in other rtlwifi devices. Rename read_nic_byte to rtl92e_readb. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 14 +++++++------- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 14 +++++++------- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 22 +++++++++++----------- drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c | 14 +++++++------- 6 files changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 38c3ed6165de..93c44b160b3e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -63,7 +63,7 @@ static void rtl8192e_update_msr(struct net_device *dev) u8 msr; enum led_ctl_mode LedAction = LED_CTL_NO_LINK; - msr = read_nic_byte(dev, MSR); + msr = rtl92e_readb(dev, MSR); msr &= ~MSR_LINK_MASK; switch (priv->rtllib->iw_mode) { @@ -109,7 +109,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) { enum rt_op_mode OpMode = *((enum rt_op_mode *)(val)); enum led_ctl_mode LedAction = LED_CTL_NO_LINK; - u8 btMsr = read_nic_byte(dev, MSR); + u8 btMsr = rtl92e_readb(dev, MSR); btMsr &= 0xfc; @@ -241,7 +241,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) union aci_aifsn *pAciAifsn = (union aci_aifsn *) & (qos_parameters->aifs[0]); u8 acm = pAciAifsn->f.acm; - u8 AcmCtrl = read_nic_byte(dev, AcmHwCtrl); + u8 AcmCtrl = rtl92e_readb(dev, AcmHwCtrl); RT_TRACE(COMP_DBG, "===========>%s():HW_VAR_ACM_CTRL:%x\n", __func__, eACI); @@ -693,7 +693,7 @@ static void rtl8192_hwconfig(struct net_device *dev) write_nic_dword(dev, RATR0, ratr_value); write_nic_byte(dev, UFWP, 1); } - regTmp = read_nic_byte(dev, 0x313); + regTmp = rtl92e_readb(dev, 0x313); regRRSR = ((regTmp) << 24) | (regRRSR & 0x00ffffff); write_nic_dword(dev, RRSR, regRRSR); @@ -740,9 +740,9 @@ start: write_nic_dword(dev, CPU_GEN, ulRegRead); - ICVersion = read_nic_byte(dev, IC_VERRSION); + ICVersion = rtl92e_readb(dev, IC_VERRSION); if (ICVersion >= 0x4) { - SwitchingRegulatorOutput = read_nic_byte(dev, SWREGULATOR); + SwitchingRegulatorOutput = rtl92e_readb(dev, SWREGULATOR); if (SwitchingRegulatorOutput != 0xb8) { write_nic_byte(dev, SWREGULATOR, 0xa8); mdelay(1); @@ -835,7 +835,7 @@ start: rtl92e_set_tx_power(dev, priv->chan); } - tmpvalue = read_nic_byte(dev, IC_VERRSION); + tmpvalue = rtl92e_readb(dev, IC_VERRSION); priv->IC_Cut = tmpvalue; RT_TRACE(COMP_INIT, "priv->IC_Cut= 0x%x\n", priv->IC_Cut); if (priv->IC_Cut >= IC_VersionCut_D) { diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 3efa84d89955..74c06929118e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -552,7 +552,7 @@ static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) u8 bRegValue = 0, eCheckItem = 0; u32 dwRegValue = 0; - bRegValue = read_nic_byte(dev, BB_GLOBAL_RESET); + bRegValue = rtl92e_readb(dev, BB_GLOBAL_RESET); write_nic_byte(dev, BB_GLOBAL_RESET, (bRegValue|BB_GLOBAL_RESET_BIT)); dwRegValue = read_nic_dword(dev, CPU_GEN); @@ -619,16 +619,16 @@ void rtl92e_get_tx_power(struct net_device *dev) priv->MCSTxPowerLevelOriginalOffset[5] = read_nic_dword(dev, rTxAGC_Mcs15_Mcs12); - priv->DefaultInitialGain[0] = read_nic_byte(dev, rOFDM0_XAAGCCore1); - priv->DefaultInitialGain[1] = read_nic_byte(dev, rOFDM0_XBAGCCore1); - priv->DefaultInitialGain[2] = read_nic_byte(dev, rOFDM0_XCAGCCore1); - priv->DefaultInitialGain[3] = read_nic_byte(dev, rOFDM0_XDAGCCore1); + priv->DefaultInitialGain[0] = rtl92e_readb(dev, rOFDM0_XAAGCCore1); + priv->DefaultInitialGain[1] = rtl92e_readb(dev, rOFDM0_XBAGCCore1); + priv->DefaultInitialGain[2] = rtl92e_readb(dev, rOFDM0_XCAGCCore1); + priv->DefaultInitialGain[3] = rtl92e_readb(dev, rOFDM0_XDAGCCore1); RT_TRACE(COMP_INIT, "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x)\n", priv->DefaultInitialGain[0], priv->DefaultInitialGain[1], priv->DefaultInitialGain[2], priv->DefaultInitialGain[3]); - priv->framesync = read_nic_byte(dev, rOFDM0_RxDetector3); + priv->framesync = rtl92e_readb(dev, rOFDM0_RxDetector3); priv->framesyncC34 = read_nic_dword(dev, rOFDM0_RxDetector2); RT_TRACE(COMP_INIT, "Default framesync (0x%x) = 0x%x\n", rOFDM0_RxDetector3, priv->framesync); @@ -1177,7 +1177,7 @@ static void rtl8192_SetBWModeWorkItem(struct net_device *dev) netdev_err(dev, "%s(): Driver is not initialized\n", __func__); return; } - regBwOpMode = read_nic_byte(dev, BW_OPMODE); + regBwOpMode = rtl92e_readb(dev, BW_OPMODE); switch (priv->CurrentChannelBW) { case HT_CHANNEL_WIDTH_20: diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index a1b6e1db4dd7..6460402fa98a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -110,7 +110,7 @@ static void rtl8192_restart(void *data); -----------------------------IO STUFF------------------------- *****************************************************************************/ -u8 read_nic_byte(struct net_device *dev, int x) +u8 rtl92e_readb(struct net_device *dev, int x) { return 0xff & readb((u8 __iomem *)dev->mem_start + x); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index ce71270a62d4..3e6d0a5e9155 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -578,7 +578,7 @@ struct r8192_priv { extern const struct ethtool_ops rtl819x_ethtool_ops; -u8 read_nic_byte(struct net_device *dev, int x); +u8 rtl92e_readb(struct net_device *dev, int x); u32 read_nic_dword(struct net_device *dev, int x); u16 read_nic_word(struct net_device *dev, int x); void write_nic_byte(struct net_device *dev, int x, u8 y); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index d993ec7a51de..08af7f621930 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -675,7 +675,7 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) sizeof(struct dcmd_txcmd)); mdelay(1); for (i = 0; i <= 30; i++) { - Pwr_Flag = read_nic_byte(dev, Pw_Track_Flag); + Pwr_Flag = rtl92e_readb(dev, Pw_Track_Flag); if (Pwr_Flag == 0) { mdelay(1); @@ -708,10 +708,10 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) for (k = 0; k < 5; k++) { if (k != 4) - tmp_report[k] = read_nic_byte(dev, + tmp_report[k] = rtl92e_readb(dev, Tssi_Report_Value1+k); else - tmp_report[k] = read_nic_byte(dev, + tmp_report[k] = rtl92e_readb(dev, Tssi_Report_Value2); RT_TRACE(COMP_POWER_TRACKING, @@ -1001,7 +1001,7 @@ static void dm_CheckTXPowerTracking_TSSI(struct net_device *dev) static u32 tx_power_track_counter; RT_TRACE(COMP_POWER_TRACKING, "%s()\n", __func__); - if (read_nic_byte(dev, 0x11e) == 1) + if (rtl92e_readb(dev, 0x11e) == 1) return; if (!priv->btxpower_tracking) return; @@ -1564,7 +1564,7 @@ static void dm_initial_gain(struct net_device *dev) reset_cnt = priv->reset_count; } - if (dm_digtable.pre_ig_value != read_nic_byte(dev, rOFDM0_XAAGCCore1)) + if (dm_digtable.pre_ig_value != rtl92e_readb(dev, rOFDM0_XAAGCCore1)) force_write = 1; if ((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value) @@ -1873,7 +1873,7 @@ static void dm_CheckRfCtrlGPIO(void *data) return; } - tmp1byte = read_nic_byte(dev, GPI); + tmp1byte = rtl92e_readb(dev, GPI); eRfPowerStateToSet = (tmp1byte&BIT1) ? eRfOn : eRfOff; @@ -1913,7 +1913,7 @@ void dm_rf_pathcheck_workitemcallback(void *data) struct net_device *dev = priv->rtllib->dev; u8 rfpath = 0, i; - rfpath = read_nic_byte(dev, 0xc04); + rfpath = rtl92e_readb(dev, 0xc04); for (i = 0; i < RF90_PATH_MAX; i++) { if (rfpath & (0x01<rtllib->mode == WIRELESS_MODE_B) DM_RxPathSelTable.cck_method = CCK_Rx_Version_2; @@ -2564,10 +2564,10 @@ static void dm_check_txrateandretrycount(struct net_device *dev) struct r8192_priv *priv = rtllib_priv(dev); struct rtllib_device *ieee = priv->rtllib; - ieee->softmac_stats.CurrentShowTxate = read_nic_byte(dev, + ieee->softmac_stats.CurrentShowTxate = rtl92e_readb(dev, Current_Tx_Rate_Reg); - ieee->softmac_stats.last_packet_rate = read_nic_byte(dev, + ieee->softmac_stats.last_packet_rate = rtl92e_readb(dev, Initial_Tx_Rate_Reg); ieee->softmac_stats.txretrycount = read_nic_dword(dev, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c index a6778e0853c7..61d462063fa7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c @@ -30,9 +30,9 @@ static void eprom_cs(struct net_device *dev, short bit) if (bit) write_nic_byte(dev, EPROM_CMD, (1 << EPROM_CS_SHIFT) | - read_nic_byte(dev, EPROM_CMD)); + rtl92e_readb(dev, EPROM_CMD)); else - write_nic_byte(dev, EPROM_CMD, read_nic_byte(dev, EPROM_CMD) + write_nic_byte(dev, EPROM_CMD, rtl92e_readb(dev, EPROM_CMD) & ~(1< Date: Sun, 19 Jul 2015 19:28:10 +0200 Subject: staging: rtl8192e: Rename read_nic_dword Use naming schema found in other rtlwifi devices. Rename read_nic_dword to rtl92e_readl. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 20 +++++++------- .../staging/rtl8192e/rtl8192e/r8192E_firmware.c | 8 +++--- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 32 +++++++++++----------- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 6 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 4 +-- drivers/staging/rtl8192e/rtl8192e/rtl_pm.c | 2 +- 7 files changed, 37 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 93c44b160b3e..4fa5f303ae36 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -143,7 +143,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) u32 RegRCR, Type; Type = ((u8 *)(val))[0]; - RegRCR = read_nic_dword(dev, RCR); + RegRCR = rtl92e_readl(dev, RCR); priv->ReceiveConfig = RegRCR; if (Type == true) @@ -631,7 +631,7 @@ void rtl92e_get_eeprom_size(struct net_device *dev) struct r8192_priv *priv = rtllib_priv(dev); RT_TRACE(COMP_INIT, "===========>%s()\n", __func__); - curCR = read_nic_dword(dev, EPROM_CMD); + curCR = rtl92e_readl(dev, EPROM_CMD); RT_TRACE(COMP_INIT, "read from Reg Cmd9346CR(%x):%x\n", EPROM_CMD, curCR); priv->epromtype = (curCR & EPROM_CMD_9356SEL) ? EEPROM_93C56 : @@ -729,7 +729,7 @@ start: if (priv->RegRfOff) priv->rtllib->eRFPowerState = eRfOff; - ulRegRead = read_nic_dword(dev, CPU_GEN); + ulRegRead = rtl92e_readl(dev, CPU_GEN); if (priv->pFirmware->firmware_status == FW_STATUS_0_INIT) ulRegRead |= CPU_GEN_SYSTEM_RESET; else if (priv->pFirmware->firmware_status == FW_STATUS_5_READY) @@ -759,7 +759,7 @@ start: priv->LoopbackMode = RTL819X_NO_LOOPBACK; if (priv->ResetProgress == RESET_TYPE_NORESET) { - ulRegRead = read_nic_dword(dev, CPU_GEN); + ulRegRead = rtl92e_readl(dev, CPU_GEN); if (priv->LoopbackMode == RTL819X_NO_LOOPBACK) ulRegRead = ((ulRegRead & CPU_GEN_NO_LOOPBACK_MSK) | CPU_GEN_NO_LOOPBACK_SET); @@ -800,7 +800,7 @@ start: rtl8192_tx_enable(dev); rtl8192_rx_enable(dev); - ulRegRead = (0xFFF00000 & read_nic_dword(dev, RRSR)) | + ulRegRead = (0xFFF00000 & rtl92e_readl(dev, RRSR)) | RATE_ALL_OFDM_AG | RATE_ALL_CCK; write_nic_dword(dev, RRSR, ulRegRead); write_nic_dword(dev, RATR0+4*7, (RATE_ALL_OFDM_AG | RATE_ALL_CCK)); @@ -1010,7 +1010,7 @@ void rtl92e_link_change(struct net_device *dev) if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC) { u32 reg = 0; - reg = read_nic_dword(dev, RCR); + reg = rtl92e_readl(dev, RCR); if (priv->rtllib->state == RTLLIB_LINKED) { if (ieee->IntelPromiscuousModeInfo.bPromiscuousOn) ; @@ -2069,7 +2069,7 @@ bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats, (pDrvInfo->FirstAGGR == 1); stats->TimeStampLow = pDrvInfo->TSFL; - stats->TimeStampHigh = read_nic_dword(dev, TSFR+4); + stats->TimeStampHigh = rtl92e_readl(dev, TSFR+4); rtl819x_UpdateRxPktTimeStamp(dev, stats); @@ -2120,7 +2120,7 @@ void rtl92e_stop_adapter(struct net_device *dev, bool reset) if (!priv->rtllib->bSupportRemoteWakeUp) { rtl92e_set_rf_off(dev); - ulRegRead = read_nic_dword(dev, CPU_GEN); + ulRegRead = rtl92e_readl(dev, CPU_GEN); ulRegRead |= CPU_GEN_SYSTEM_RESET; write_nic_dword(dev, CPU_GEN, ulRegRead); } else { @@ -2247,7 +2247,7 @@ void rtl92e_clear_irq(struct net_device *dev) { u32 tmp = 0; - tmp = read_nic_dword(dev, ISR); + tmp = rtl92e_readl(dev, ISR); write_nic_dword(dev, ISR, tmp); } @@ -2275,7 +2275,7 @@ void rtl92e_enable_tx(struct net_device *dev) void rtl92e_ack_irq(struct net_device *dev, u32 *p_inta, u32 *p_intb) { - *p_inta = read_nic_dword(dev, ISR); + *p_inta = rtl92e_readl(dev, ISR); write_nic_dword(dev, ISR, *p_inta); } diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c index 6c11d19c4668..7e59f5c6b951 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c @@ -109,7 +109,7 @@ static bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) timeout = jiffies + msecs_to_jiffies(200); while (time_before(jiffies, timeout)) { - CPU_status = read_nic_dword(dev, CPU_GEN); + CPU_status = rtl92e_readl(dev, CPU_GEN); if (CPU_status & CPU_GEN_PUT_CODE_OK) break; mdelay(2); @@ -122,14 +122,14 @@ static bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) RT_TRACE(COMP_FIRMWARE, "Download Firmware: Put code ok!\n"); } - CPU_status = read_nic_dword(dev, CPU_GEN); + CPU_status = rtl92e_readl(dev, CPU_GEN); write_nic_byte(dev, CPU_GEN, (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff)); mdelay(1); timeout = jiffies + msecs_to_jiffies(200); while (time_before(jiffies, timeout)) { - CPU_status = read_nic_dword(dev, CPU_GEN); + CPU_status = rtl92e_readl(dev, CPU_GEN); if (CPU_status&CPU_GEN_BOOT_RDY) break; mdelay(2); @@ -158,7 +158,7 @@ static bool CPUcheck_firmware_ready(struct net_device *dev) timeout = jiffies + msecs_to_jiffies(20); while (time_before(jiffies, timeout)) { - CPU_status = read_nic_dword(dev, CPU_GEN); + CPU_status = rtl92e_readl(dev, CPU_GEN); if (CPU_status&CPU_GEN_FIRM_RDY) break; mdelay(2); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 74c06929118e..42dd7ae70a46 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -87,7 +87,7 @@ void rtl92e_set_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, u32 OriginalValue, BitShift, NewValue; if (dwBitMask != bMaskDWord) { - OriginalValue = read_nic_dword(dev, dwRegAddr); + OriginalValue = rtl92e_readl(dev, dwRegAddr); BitShift = rtl8192_CalculateBitShift(dwBitMask); NewValue = (((OriginalValue) & (~dwBitMask)) | (dwData << BitShift)); @@ -100,7 +100,7 @@ u32 rtl92e_get_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask) { u32 Ret = 0, OriginalValue, BitShift; - OriginalValue = read_nic_dword(dev, dwRegAddr); + OriginalValue = rtl92e_readl(dev, dwRegAddr); BitShift = rtl8192_CalculateBitShift(dwBitMask); Ret = (OriginalValue & dwBitMask) >> BitShift; @@ -287,20 +287,20 @@ static u32 phy_FwRFSerialRead(struct net_device *dev, Data |= ((Offset & 0xFF) << 12); Data |= ((eRFPath & 0x3) << 20); Data |= 0x80000000; - while (read_nic_dword(dev, QPNR)&0x80000000) { + while (rtl92e_readl(dev, QPNR) & 0x80000000) { if (time++ < 100) udelay(10); else break; } write_nic_dword(dev, QPNR, Data); - while (read_nic_dword(dev, QPNR) & 0x80000000) { + while (rtl92e_readl(dev, QPNR) & 0x80000000) { if (time++ < 100) udelay(10); else return 0; } - return read_nic_dword(dev, RF_DATA); + return rtl92e_readl(dev, RF_DATA); } @@ -315,7 +315,7 @@ static void phy_FwRFSerialWrite(struct net_device *dev, Data |= 0x400000; Data |= 0x80000000; - while (read_nic_dword(dev, QPNR) & 0x80000000) { + while (rtl92e_readl(dev, QPNR) & 0x80000000) { if (time++ < 100) udelay(10); else @@ -514,7 +514,7 @@ bool rtl92e_check_bb_and_rf(struct net_device *dev, enum hw90_block CheckBlock, case HW90_BLOCK_PHY1: write_nic_dword(dev, WriteAddr[CheckBlock], WriteData[i]); - dwRegRead = read_nic_dword(dev, WriteAddr[CheckBlock]); + dwRegRead = rtl92e_readl(dev, WriteAddr[CheckBlock]); break; case HW90_BLOCK_RF: @@ -555,7 +555,7 @@ static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) bRegValue = rtl92e_readb(dev, BB_GLOBAL_RESET); write_nic_byte(dev, BB_GLOBAL_RESET, (bRegValue|BB_GLOBAL_RESET_BIT)); - dwRegValue = read_nic_dword(dev, CPU_GEN); + dwRegValue = rtl92e_readl(dev, CPU_GEN); write_nic_dword(dev, CPU_GEN, (dwRegValue&(~CPU_GEN_BB_RST))); for (eCheckItem = (enum hw90_block)HW90_BLOCK_PHY0; @@ -573,7 +573,7 @@ static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bCCKEn|bOFDMEn, 0x0); rtl8192_phyConfigBB(dev, BaseBand_Config_PHY_REG); - dwRegValue = read_nic_dword(dev, CPU_GEN); + dwRegValue = rtl92e_readl(dev, CPU_GEN); write_nic_dword(dev, CPU_GEN, (dwRegValue|CPU_GEN_BB_RST)); rtl8192_phyConfigBB(dev, BaseBand_Config_AGC_TAB); @@ -607,17 +607,17 @@ void rtl92e_get_tx_power(struct net_device *dev) struct r8192_priv *priv = rtllib_priv(dev); priv->MCSTxPowerLevelOriginalOffset[0] = - read_nic_dword(dev, rTxAGC_Rate18_06); + rtl92e_readl(dev, rTxAGC_Rate18_06); priv->MCSTxPowerLevelOriginalOffset[1] = - read_nic_dword(dev, rTxAGC_Rate54_24); + rtl92e_readl(dev, rTxAGC_Rate54_24); priv->MCSTxPowerLevelOriginalOffset[2] = - read_nic_dword(dev, rTxAGC_Mcs03_Mcs00); + rtl92e_readl(dev, rTxAGC_Mcs03_Mcs00); priv->MCSTxPowerLevelOriginalOffset[3] = - read_nic_dword(dev, rTxAGC_Mcs07_Mcs04); + rtl92e_readl(dev, rTxAGC_Mcs07_Mcs04); priv->MCSTxPowerLevelOriginalOffset[4] = - read_nic_dword(dev, rTxAGC_Mcs11_Mcs08); + rtl92e_readl(dev, rTxAGC_Mcs11_Mcs08); priv->MCSTxPowerLevelOriginalOffset[5] = - read_nic_dword(dev, rTxAGC_Mcs15_Mcs12); + rtl92e_readl(dev, rTxAGC_Mcs15_Mcs12); priv->DefaultInitialGain[0] = rtl92e_readb(dev, rOFDM0_XAAGCCore1); priv->DefaultInitialGain[1] = rtl92e_readb(dev, rOFDM0_XBAGCCore1); @@ -629,7 +629,7 @@ void rtl92e_get_tx_power(struct net_device *dev) priv->DefaultInitialGain[2], priv->DefaultInitialGain[3]); priv->framesync = rtl92e_readb(dev, rOFDM0_RxDetector3); - priv->framesyncC34 = read_nic_dword(dev, rOFDM0_RxDetector2); + priv->framesyncC34 = rtl92e_readl(dev, rOFDM0_RxDetector2); RT_TRACE(COMP_INIT, "Default framesync (0x%x) = 0x%x\n", rOFDM0_RxDetector3, priv->framesync); priv->SifsTime = read_nic_word(dev, SIFS); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 6460402fa98a..f75597f3f01a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -115,7 +115,7 @@ u8 rtl92e_readb(struct net_device *dev, int x) return 0xff & readb((u8 __iomem *)dev->mem_start + x); } -u32 read_nic_dword(struct net_device *dev, int x) +u32 rtl92e_readl(struct net_device *dev, int x) { return readl((u8 __iomem *)dev->mem_start + x); } @@ -2204,7 +2204,7 @@ static void rtl8192_irq_rx_tasklet(struct r8192_priv *priv) rtl8192_rx_normal(priv->rtllib->dev); write_nic_dword(priv->rtllib->dev, INTA_MASK, - read_nic_dword(priv->rtllib->dev, INTA_MASK) | IMR_RDU); + rtl92e_readl(priv->rtllib->dev, INTA_MASK) | IMR_RDU); } /**************************************************************************** @@ -2536,7 +2536,7 @@ static irqreturn_t rtl8192_interrupt(int irq, void *netdev) RT_TRACE(COMP_INTR, "rx descriptor unavailable!\n"); priv->stats.rxrdu++; write_nic_dword(dev, INTA_MASK, - read_nic_dword(dev, INTA_MASK) & ~IMR_RDU); + rtl92e_readl(dev, INTA_MASK) & ~IMR_RDU); tasklet_schedule(&priv->irq_rx_tasklet); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 3e6d0a5e9155..895a66fde689 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -579,7 +579,7 @@ struct r8192_priv { extern const struct ethtool_ops rtl819x_ethtool_ops; u8 rtl92e_readb(struct net_device *dev, int x); -u32 read_nic_dword(struct net_device *dev, int x); +u32 rtl92e_readl(struct net_device *dev, int x); u16 read_nic_word(struct net_device *dev, int x); void write_nic_byte(struct net_device *dev, int x, u8 y); void write_nic_word(struct net_device *dev, int x, u16 y); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 08af7f621930..614bf1387e40 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -444,7 +444,7 @@ static void dm_check_rate_adaptive(struct net_device *dev) if (priv->rtllib->GetHalfNmodeSupportByAPsHandler(dev)) targetRATR &= 0xf00fffff; - currentRATR = read_nic_dword(dev, RATR0); + currentRATR = rtl92e_readl(dev, RATR0); if (targetRATR != currentRATR) { u32 ratr_value; @@ -2570,7 +2570,7 @@ static void dm_check_txrateandretrycount(struct net_device *dev) ieee->softmac_stats.last_packet_rate = rtl92e_readb(dev, Initial_Tx_Rate_Reg); - ieee->softmac_stats.txretrycount = read_nic_dword(dev, + ieee->softmac_stats.txretrycount = rtl92e_readl(dev, Tx_Retry_Count_Reg); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c index c92d6df135fc..c915e19e8870 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c @@ -46,7 +46,7 @@ int rtl8192E_suspend(struct pci_dev *pdev, pm_message_t state) if (!priv->rtllib->bSupportRemoteWakeUp) { rtl92e_set_rf_state(dev, eRfOff, RF_CHANGE_BY_INIT, true); - ulRegRead = read_nic_dword(dev, CPU_GEN); + ulRegRead = rtl92e_readl(dev, CPU_GEN); ulRegRead |= CPU_GEN_SYSTEM_RESET; write_nic_dword(dev, CPU_GEN, ulRegRead); } else { -- cgit v1.3-6-gb490 From 1c0a7c0e622a94eeb2da1d249757753f903eb79b Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:11 +0200 Subject: staging: rtl8192e: Rename read_nic_word Use naming schema found in other rtlwifi devices. Rename read_nic_word to rtl92e_readw. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 4fa5f303ae36..61b10694f4c7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2282,7 +2282,7 @@ void rtl92e_ack_irq(struct net_device *dev, u32 *p_inta, u32 *p_intb) bool rtl92e_is_rx_stuck(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); - u16 RegRxCounter = read_nic_word(dev, 0x130); + u16 RegRxCounter = rtl92e_readw(dev, 0x130); bool bStuck = false; static u8 rx_chk_cnt; u32 SlotIndex = 0, TotalRxStuckCount = 0; @@ -2347,7 +2347,7 @@ bool rtl92e_is_tx_stuck(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); bool bStuck = false; - u16 RegTxCounter = read_nic_word(dev, 0x128); + u16 RegTxCounter = rtl92e_readw(dev, 0x128); RT_TRACE(COMP_RESET, "%s():RegTxCounter is %d,TxCounter is %d\n", __func__, RegTxCounter, priv->TxCounter); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 42dd7ae70a46..667f44f01c53 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -632,7 +632,7 @@ void rtl92e_get_tx_power(struct net_device *dev) priv->framesyncC34 = rtl92e_readl(dev, rOFDM0_RxDetector2); RT_TRACE(COMP_INIT, "Default framesync (0x%x) = 0x%x\n", rOFDM0_RxDetector3, priv->framesync); - priv->SifsTime = read_nic_word(dev, SIFS); + priv->SifsTime = rtl92e_readw(dev, SIFS); } void rtl92e_set_tx_power(struct net_device *dev, u8 channel) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index f75597f3f01a..64a03f314b43 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -120,7 +120,7 @@ u32 rtl92e_readl(struct net_device *dev, int x) return readl((u8 __iomem *)dev->mem_start + x); } -u16 read_nic_word(struct net_device *dev, int x) +u16 rtl92e_readw(struct net_device *dev, int x) { return readw((u8 __iomem *)dev->mem_start + x); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 895a66fde689..5a7a54f9dc9b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -580,7 +580,7 @@ extern const struct ethtool_ops rtl819x_ethtool_ops; u8 rtl92e_readb(struct net_device *dev, int x); u32 rtl92e_readl(struct net_device *dev, int x); -u16 read_nic_word(struct net_device *dev, int x); +u16 rtl92e_readw(struct net_device *dev, int x); void write_nic_byte(struct net_device *dev, int x, u8 y); void write_nic_word(struct net_device *dev, int x, u16 y); void write_nic_dword(struct net_device *dev, int x, u32 y); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 614bf1387e40..5bbb390334aa 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -698,7 +698,7 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) continue; } - Avg_TSSI_Meas = read_nic_word(dev, Tssi_Mea_Value); + Avg_TSSI_Meas = rtl92e_readw(dev, Tssi_Mea_Value); if (Avg_TSSI_Meas == 0) { write_nic_byte(dev, Pw_Track_Flag, 0); -- cgit v1.3-6-gb490 From bc4f2cc90d214e81bb75c5b63a8c919779f32a6a Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:12 +0200 Subject: staging: rtl8192e: Rename rtl8192_commit Use naming schema found in other rtlwifi devices. Rename rtl8192_commit to rtl92e_commit. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 64a03f314b43..a6937aa84cf0 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2276,7 +2276,7 @@ static int rtl8192_down(struct net_device *dev, bool shutdownrf) return 0; } -void rtl8192_commit(struct net_device *dev) +void rtl92e_commit(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); @@ -2296,7 +2296,7 @@ static void rtl8192_restart(void *data) down(&priv->wx_sem); - rtl8192_commit(dev); + rtl92e_commit(dev); up(&priv->wx_sem); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 5a7a54f9dc9b..65679846484c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -591,7 +591,7 @@ void rtl8192_rx_enable(struct net_device *); void rtl8192_tx_enable(struct net_device *); void rtl8192_hw_sleep_wq(void *data); -void rtl8192_commit(struct net_device *dev); +void rtl92e_commit(struct net_device *dev); void rtl92e_check_rfctrl_gpio_timer(unsigned long data); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index 1b29f14dd2b2..29400eeda968 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -824,7 +824,7 @@ static int r8192_wx_set_retry(struct net_device *dev, } - rtl8192_commit(dev); + rtl92e_commit(dev); exit: up(&priv->wx_sem); -- cgit v1.3-6-gb490 From 122fe9f1dfa2aeacceda2d32a8e496168744c3de Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:13 +0200 Subject: staging: rtl8192e: Rename rtl8192_config_rate Use naming schema found in other rtlwifi devices. Rename rtl8192_config_rate to rtl92e_config_rate. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 61b10694f4c7..a21da2f17774 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -968,7 +968,7 @@ static void rtl8192_net_update(struct net_device *dev) u16 rate_config = 0; net = &priv->rtllib->current_network; - rtl8192_config_rate(dev, &rate_config); + rtl92e_config_rate(dev, &rate_config); priv->dot11CurrentPreambleMode = PREAMBLE_AUTO; priv->basic_rate = rate_config &= 0x15f; write_nic_dword(dev, BSSIDR, ((u32 *)net->bssid)[0]); @@ -2151,7 +2151,7 @@ void rtl92e_update_ratr_table(struct net_device *dev) u16 rate_config = 0; u8 rate_index = 0; - rtl8192_config_rate(dev, &rate_config); + rtl92e_config_rate(dev, &rate_config); ratr_value = rate_config | *pMcsRate << 12; switch (ieee->mode) { case IEEE_A: diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index a6937aa84cf0..b13014a91f76 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -575,7 +575,7 @@ static void rtl8192_stop_beacon(struct net_device *dev) { } -void rtl8192_config_rate(struct net_device *dev, u16 *rate_config) +void rtl92e_config_rate(struct net_device *dev, u16 *rate_config) { struct r8192_priv *priv = rtllib_priv(dev); struct rtllib_network *net; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 65679846484c..fe70e39a6b4d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -602,7 +602,7 @@ void rtl8192_irq_disable(struct net_device *dev); void rtl8192_pci_resetdescring(struct net_device *dev); void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode); void rtl8192_irq_enable(struct net_device *dev); -void rtl8192_config_rate(struct net_device *dev, u16 *rate_config); +void rtl92e_config_rate(struct net_device *dev, u16 *rate_config); void rtl8192_irq_disable(struct net_device *dev); void rtl819x_UpdateRxPktTimeStamp(struct net_device *dev, -- cgit v1.3-6-gb490 From b7b50d654c47eaf86711465aed3cd6888efbe204 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:14 +0200 Subject: staging: rtl8192e: Rename rtl8192_irq_disable Use naming schema found in other rtlwifi devices. Rename rtl8192_irq_disable to rtl92e_irq_disable. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 12 ++++++------ drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 4 +--- 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index a21da2f17774..65769013f677 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -41,7 +41,7 @@ void rtl92e_start_beacon(struct net_device *dev) u16 BcnCW = 6; u16 BcnIFS = 0xf; - rtl8192_irq_disable(dev); + rtl92e_irq_disable(dev); write_nic_word(dev, ATIMWND, 2); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index b13014a91f76..d131c02566b9 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -309,7 +309,7 @@ void rtl8192_irq_enable(struct net_device *dev) priv->ops->irq_enable(dev); } -void rtl8192_irq_disable(struct net_device *dev) +void rtl92e_irq_disable(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); @@ -826,7 +826,7 @@ static int rtl8192_sta_down(struct net_device *dev, bool shutdownrf) priv->rtllib->wpa_ie = NULL; rtl92e_cam_reset(dev); memset(priv->rtllib->swcamtable, 0, sizeof(struct sw_cam_table) * 32); - rtl8192_irq_disable(dev); + rtl92e_irq_disable(dev); del_timer_sync(&priv->watch_dog_timer); rtl8192_cancel_deferred_work(priv); @@ -1102,7 +1102,7 @@ static short rtl8192_init(struct net_device *dev) rtl92e_check_rfctrl_gpio_timer, (unsigned long)dev); - rtl8192_irq_disable(dev); + rtl92e_irq_disable(dev); if (request_irq(dev->irq, rtl8192_interrupt, IRQF_SHARED, dev->name, dev)) { netdev_err(dev, "Error allocating IRQ %d", dev->irq); @@ -1301,7 +1301,7 @@ RESET_START: if (!netif_queue_stopped(dev)) netif_stop_queue(dev); - rtl8192_irq_disable(dev); + rtl92e_irq_disable(dev); del_timer_sync(&priv->watch_dog_timer); rtl8192_cancel_deferred_work(priv); deinit_hal_dm(dev); @@ -2283,7 +2283,7 @@ void rtl92e_commit(struct net_device *dev) if (priv->up == 0) return; rtllib_softmac_stop_protocol(priv->rtllib, 0, true); - rtl8192_irq_disable(dev); + rtl92e_irq_disable(dev); priv->ops->stop_adapter(dev, true); _rtl8192_up(dev, false); } @@ -2816,7 +2816,7 @@ bool rtl92e_disable_nic(struct net_device *dev) rtllib_softmac_stop_protocol(priv->rtllib, 0, false); priv->rtllib->state = tmp_state; rtl8192_cancel_deferred_work(priv); - rtl8192_irq_disable(dev); + rtl92e_irq_disable(dev); priv->ops->stop_adapter(dev, false); RT_TRACE(COMP_PS, "<=========%s()\n", __func__); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index fe70e39a6b4d..1017a063cdd1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -597,13 +597,11 @@ void rtl92e_check_rfctrl_gpio_timer(unsigned long data); void rtl8192_hw_wakeup_wq(void *data); -void rtl8192_irq_disable(struct net_device *dev); - void rtl8192_pci_resetdescring(struct net_device *dev); void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode); void rtl8192_irq_enable(struct net_device *dev); void rtl92e_config_rate(struct net_device *dev, u16 *rate_config); -void rtl8192_irq_disable(struct net_device *dev); +void rtl92e_irq_disable(struct net_device *dev); void rtl819x_UpdateRxPktTimeStamp(struct net_device *dev, struct rtllib_rx_stats *stats); -- cgit v1.3-6-gb490 From b74299cde425f0b20c37fa6dfed2ecdf0c8853b2 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:15 +0200 Subject: staging: rtl8192e: Rename rtl8192_irq_enable Use naming schema found in other rtlwifi devices. Rename rtl8192_irq_enable to rtl92e_irq_enable. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 65769013f677..50067bb4e04e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -54,7 +54,7 @@ void rtl92e_start_beacon(struct net_device *dev) BcnTimeCfg |= BcnCW<btxpower_tracking = false; } } - rtl8192_irq_enable(dev); + rtl92e_irq_enable(dev); end: priv->being_init_adapter = false; return rtStatus; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index d131c02566b9..aeb6b90aef91 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -300,7 +300,7 @@ static void rtl8192_tx_timeout(struct net_device *dev) netdev_info(dev, "TXTIMEOUT"); } -void rtl8192_irq_enable(struct net_device *dev) +void rtl92e_irq_enable(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); @@ -2800,7 +2800,7 @@ bool rtl92e_enable_nic(struct net_device *dev) RT_CLEAR_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC); priv->bfirst_init = false; - rtl8192_irq_enable(dev); + rtl92e_irq_enable(dev); priv->bdisable_nic = false; RT_TRACE(COMP_PS, "<===========%s()\n", __func__); return init_status; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 1017a063cdd1..f11fe8c7044d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -599,7 +599,7 @@ void rtl8192_hw_wakeup_wq(void *data); void rtl8192_pci_resetdescring(struct net_device *dev); void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode); -void rtl8192_irq_enable(struct net_device *dev); +void rtl92e_irq_enable(struct net_device *dev); void rtl92e_config_rate(struct net_device *dev, u16 *rate_config); void rtl92e_irq_disable(struct net_device *dev); -- cgit v1.3-6-gb490 From 36154dc3deea461eec4c8428336387192fe6e2ce Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:16 +0200 Subject: staging: rtl8192e: Rename rtl8192_pci_resetdescring Use naming schema found in other rtlwifi devices. Rename rtl8192_pci_resetdescring to rtl92e_reset_desc_ring. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 50067bb4e04e..21aa7c876f67 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -718,7 +718,7 @@ bool rtl92e_start_adapter(struct net_device *dev) priv->being_init_adapter = true; start: - rtl8192_pci_resetdescring(dev); + rtl92e_reset_desc_ring(dev); priv->Rf_Mode = RF_OP_By_SW_3wire; if (priv->ResetProgress == RESET_TYPE_NORESET) { write_nic_byte(dev, ANAPAR, 0x37); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index aeb6b90aef91..9e5b3525ca01 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1943,7 +1943,7 @@ err_free_rings: return 1; } -void rtl8192_pci_resetdescring(struct net_device *dev) +void rtl92e_reset_desc_ring(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); int i, rx_queue_idx; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index f11fe8c7044d..577185e7e8ac 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -597,7 +597,7 @@ void rtl92e_check_rfctrl_gpio_timer(unsigned long data); void rtl8192_hw_wakeup_wq(void *data); -void rtl8192_pci_resetdescring(struct net_device *dev); +void rtl92e_reset_desc_ring(struct net_device *dev); void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode); void rtl92e_irq_enable(struct net_device *dev); void rtl92e_config_rate(struct net_device *dev, u16 *rate_config); -- cgit v1.3-6-gb490 From e58701dae05c041d443178a3a78bed9438cc21e7 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:17 +0200 Subject: staging: rtl8192e: Rename rtl8192_record_rxdesc_forlateruse Use naming schema found in other rtlwifi devices. Rename rtl8192_record_rxdesc_forlateruse to rtl92e_copy_mpdu_stats. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 7 ++----- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 21aa7c876f67..8e00ee77184b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1908,7 +1908,7 @@ static void rtl8192_TranslateRxSignalStuff(struct net_device *dev, rtl8192_query_rxphystatus(priv, pstats, pdesc, pdrvinfo, &previous_stats, bpacket_match_bssid, bpacket_toself, bPacketBeacon, bToSelfBA); - rtl8192_record_rxdesc_forlateruse(pstats, &previous_stats); + rtl92e_copy_mpdu_stats(pstats, &previous_stats); } static void rtl8192_UpdateReceivedRateHistogramStatistics( diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 9e5b3525ca01..1faf9508416e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2059,11 +2059,8 @@ rtl819x_evm_dbtopercentage( return ret_val; } -void -rtl8192_record_rxdesc_forlateruse( - struct rtllib_rx_stats *psrc_stats, - struct rtllib_rx_stats *ptarget_stats -) +void rtl92e_copy_mpdu_stats(struct rtllib_rx_stats *psrc_stats, + struct rtllib_rx_stats *ptarget_stats) { ptarget_stats->bIsAMPDU = psrc_stats->bIsAMPDU; ptarget_stats->bFirstMPDU = psrc_stats->bFirstMPDU; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 577185e7e8ac..df0f2bb3ba1a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -610,8 +610,8 @@ void rtl819x_update_rxsignalstatistics8190pci(struct r8192_priv *priv, struct rtllib_rx_stats *pprevious_stats); u8 rtl819x_evm_dbtopercentage(char value); u8 rtl819x_query_rxpwrpercentage(char antpower); -void rtl8192_record_rxdesc_forlateruse(struct rtllib_rx_stats *psrc_stats, - struct rtllib_rx_stats *ptarget_stats); +void rtl92e_copy_mpdu_stats(struct rtllib_rx_stats *psrc_stats, + struct rtllib_rx_stats *ptarget_stats); bool rtl92e_enable_nic(struct net_device *dev); bool rtl92e_disable_nic(struct net_device *dev); -- cgit v1.3-6-gb490 From 630268b75726785b9709b47afb10bcaed4fa0e35 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:18 +0200 Subject: staging: rtl8192e: Rename rtl8192_rx_enable Use naming schema found in other rtlwifi devices. Rename rtl8192_rx_enable to rtl92e_rx_enable. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 8e00ee77184b..f0828f813fa3 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -799,7 +799,7 @@ start: RSVD_FW_QUEUE_PAGE_PUB_SHIFT); rtl8192_tx_enable(dev); - rtl8192_rx_enable(dev); + rtl92e_rx_enable(dev); ulRegRead = (0xFFF00000 & rtl92e_readl(dev, RRSR)) | RATE_ALL_OFDM_AG | RATE_ALL_CCK; write_nic_dword(dev, RRSR, ulRegRead); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 1faf9508416e..025afdfb5cd2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1578,7 +1578,7 @@ static void watch_dog_timer_callback(unsigned long data) /**************************************************************************** ---------------------------- NIC TX/RX STUFF--------------------------- *****************************************************************************/ -void rtl8192_rx_enable(struct net_device *dev) +void rtl92e_rx_enable(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index df0f2bb3ba1a..10fb43117336 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -587,7 +587,7 @@ void write_nic_dword(struct net_device *dev, int x, u32 y); void force_pci_posting(struct net_device *dev); -void rtl8192_rx_enable(struct net_device *); +void rtl92e_rx_enable(struct net_device *); void rtl8192_tx_enable(struct net_device *); void rtl8192_hw_sleep_wq(void *data); -- cgit v1.3-6-gb490 From 35bf848f0662a923416d1e92120067d555f5706a Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:19 +0200 Subject: staging: rtl8192e: Rename rtl8192_SetWirelessMode Use naming schema found in other rtlwifi devices. Rename rtl8192_SetWirelessMode to rtl92e_set_wireless_mode. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index f0828f813fa3..2fc591f47b06 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -808,7 +808,7 @@ start: write_nic_byte(dev, ACK_TIMEOUT, 0x30); if (priv->ResetProgress == RESET_TYPE_NORESET) - rtl8192_SetWirelessMode(dev, priv->rtllib->mode); + rtl92e_set_wireless_mode(dev, priv->rtllib->mode); rtl92e_cam_reset(dev); { u8 SECR_value = 0x0; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 025afdfb5cd2..b644ef0150e4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -706,7 +706,7 @@ static u8 rtl8192_getSupportedWireleeMode(struct net_device *dev) return ret; } -void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode) +void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode) { struct r8192_priv *priv = rtllib_priv(dev); u8 bSupportMode = rtl8192_getSupportedWireleeMode(dev); @@ -874,7 +874,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->check_nic_enough_desc = rtl8192_check_nic_enough_desc; priv->rtllib->handle_assoc_response = rtl8192_handle_assoc_response; priv->rtllib->handle_beacon = rtl8192_handle_beacon; - priv->rtllib->SetWirelessMode = rtl8192_SetWirelessMode; + priv->rtllib->SetWirelessMode = rtl92e_set_wireless_mode; priv->rtllib->LeisurePSLeave = LeisurePSLeave; priv->rtllib->SetBWModeHandler = rtl92e_set_bw_mode; priv->rf_set_chan = rtl92e_set_channel; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 10fb43117336..ea8c6281c211 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -598,7 +598,7 @@ void rtl92e_check_rfctrl_gpio_timer(unsigned long data); void rtl8192_hw_wakeup_wq(void *data); void rtl92e_reset_desc_ring(struct net_device *dev); -void rtl8192_SetWirelessMode(struct net_device *dev, u8 wireless_mode); +void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode); void rtl92e_irq_enable(struct net_device *dev); void rtl92e_config_rate(struct net_device *dev, u16 *rate_config); void rtl92e_irq_disable(struct net_device *dev); -- cgit v1.3-6-gb490 From 94199b35ff28093bb94f26a7a668e33becec092d Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:20 +0200 Subject: staging: rtl8192e: Rename rtl8192_tx_enable Use naming schema found in other rtlwifi devices. Rename rtl8192_tx_enable to rtl92e_tx_enable. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 2fc591f47b06..0e1b25ddc7d4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -798,7 +798,7 @@ start: NUM_OF_PAGE_IN_FW_QUEUE_PUB << RSVD_FW_QUEUE_PAGE_PUB_SHIFT); - rtl8192_tx_enable(dev); + rtl92e_tx_enable(dev); rtl92e_rx_enable(dev); ulRegRead = (0xFFF00000 & rtl92e_readl(dev, RRSR)) | RATE_ALL_OFDM_AG | RATE_ALL_CCK; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index b644ef0150e4..edb5943442e8 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1585,7 +1585,7 @@ void rtl92e_rx_enable(struct net_device *dev) priv->ops->rx_enable(dev); } -void rtl8192_tx_enable(struct net_device *dev) +void rtl92e_tx_enable(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index ea8c6281c211..0decf6b9213f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -588,7 +588,7 @@ void write_nic_dword(struct net_device *dev, int x, u32 y); void force_pci_posting(struct net_device *dev); void rtl92e_rx_enable(struct net_device *); -void rtl8192_tx_enable(struct net_device *); +void rtl92e_tx_enable(struct net_device *); void rtl8192_hw_sleep_wq(void *data); void rtl92e_commit(struct net_device *dev); -- cgit v1.3-6-gb490 From 6b89d0e7ceb733501e7203ca52ed9e294bd46a0d Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:21 +0200 Subject: staging: rtl8192e: Rename rtl819x_evm_dbtopercentage Use naming schema found in other rtlwifi devices. Rename rtl819x_evm_dbtopercentage to rtl92e_evm_db_to_percent. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 5 +---- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 0e1b25ddc7d4..e763b3689069 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1656,7 +1656,7 @@ static void rtl8192_query_rxphystatus( rx_evmX /= 2; - evm = rtl819x_evm_dbtopercentage(rx_evmX); + evm = rtl92e_evm_db_to_percent(rx_evmX); if (bpacket_match_bssid) { if (i == 0) { pstats->SignalQuality = (u8)(evm & diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index edb5943442e8..e136fabc8a80 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2039,10 +2039,7 @@ u8 rtl819x_query_rxpwrpercentage(char antpower) } /* QueryRxPwrPercentage */ -u8 -rtl819x_evm_dbtopercentage( - char value - ) +u8 rtl92e_evm_db_to_percent(char value) { char ret_val; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 0decf6b9213f..d99513b5b62b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -608,7 +608,7 @@ void rtl819x_UpdateRxPktTimeStamp(struct net_device *dev, long rtl819x_translate_todbm(struct r8192_priv *priv, u8 signal_strength_index); void rtl819x_update_rxsignalstatistics8190pci(struct r8192_priv *priv, struct rtllib_rx_stats *pprevious_stats); -u8 rtl819x_evm_dbtopercentage(char value); +u8 rtl92e_evm_db_to_percent(char value); u8 rtl819x_query_rxpwrpercentage(char antpower); void rtl92e_copy_mpdu_stats(struct rtllib_rx_stats *psrc_stats, struct rtllib_rx_stats *ptarget_stats); -- cgit v1.3-6-gb490 From aa804031831cfcff16811717bd46c1c6deee168a Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:22 +0200 Subject: staging: rtl8192e: Rename rtl819x_query_rxpwrpercentage Use naming schema found in other rtlwifi devices. Rename rtl819x_query_rxpwrpercentage to rtl92e_rx_db_to_percent. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 6 +++--- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index e763b3689069..bddfc6ccd9f3 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1586,7 +1586,7 @@ static void rtl8192_query_rxphystatus( } } - pwdb_all = rtl819x_query_rxpwrpercentage(rx_pwr_all); + pwdb_all = rtl92e_rx_db_to_percent(rx_pwr_all); pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; pstats->RecvSignalPower = rx_pwr_all; @@ -1626,7 +1626,7 @@ static void rtl8192_query_rxphystatus( rx_snrX /= 2; priv->stats.rxSNRdB[i] = (long)rx_snrX; - RSSI = rtl819x_query_rxpwrpercentage(rx_pwr[i]); + RSSI = rtl92e_rx_db_to_percent(rx_pwr[i]); if (priv->brfpath_rxenable[i]) total_rssi += RSSI; @@ -1639,7 +1639,7 @@ static void rtl8192_query_rxphystatus( rx_pwr_all = (((pofdm_buf->pwdb_all) >> 1) & 0x7f) - 106; - pwdb_all = rtl819x_query_rxpwrpercentage(rx_pwr_all); + pwdb_all = rtl92e_rx_db_to_percent(rx_pwr_all); pstats->RxPWDBAll = precord_stats->RxPWDBAll = pwdb_all; pstats->RxPower = precord_stats->RxPower = rx_pwr_all; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index e136fabc8a80..e6ca7baf783c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2028,7 +2028,7 @@ rtl819x_update_rxsignalstatistics8190pci( weighting) / 6; } -u8 rtl819x_query_rxpwrpercentage(char antpower) +u8 rtl92e_rx_db_to_percent(char antpower) { if ((antpower <= -100) || (antpower >= 20)) return 0; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index d99513b5b62b..d31bb3409136 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -609,7 +609,7 @@ long rtl819x_translate_todbm(struct r8192_priv *priv, u8 signal_strength_index); void rtl819x_update_rxsignalstatistics8190pci(struct r8192_priv *priv, struct rtllib_rx_stats *pprevious_stats); u8 rtl92e_evm_db_to_percent(char value); -u8 rtl819x_query_rxpwrpercentage(char antpower); +u8 rtl92e_rx_db_to_percent(char antpower); void rtl92e_copy_mpdu_stats(struct rtllib_rx_stats *psrc_stats, struct rtllib_rx_stats *ptarget_stats); bool rtl92e_enable_nic(struct net_device *dev); -- cgit v1.3-6-gb490 From f54f10bfa1617feb7aaaad61ddc8e9afb50a87e4 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:23 +0200 Subject: staging: rtl8192e: Rename rtl819x_translate_todbm Use naming schema found in other rtlwifi devices. Rename rtl819x_translate_todbm to rtl92e_translate_to_dbm. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index bddfc6ccd9f3..2f64a0fa512c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1732,8 +1732,8 @@ static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer, slide_rssi_index = 0; tmp_val = priv->stats.slide_rssi_total/slide_rssi_statistics; - priv->stats.signal_strength = rtl819x_translate_todbm(priv, - (u8)tmp_val); + priv->stats.signal_strength = rtl92e_translate_to_dbm(priv, + (u8)tmp_val); curr_st->rssi = priv->stats.signal_strength; if (!prev_st->bPacketMatchBSSID) { if (!prev_st->bToSelfBA) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index e6ca7baf783c..f9bf923cf8c7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1994,7 +1994,7 @@ void rtl819x_UpdateRxPktTimeStamp(struct net_device *dev, priv->LastRxDescTSF = stats->mac_time; } -long rtl819x_translate_todbm(struct r8192_priv *priv, u8 signal_strength_index) +long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index) { long signal_power; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index d31bb3409136..c9599a9852ee 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -605,7 +605,7 @@ void rtl92e_irq_disable(struct net_device *dev); void rtl819x_UpdateRxPktTimeStamp(struct net_device *dev, struct rtllib_rx_stats *stats); -long rtl819x_translate_todbm(struct r8192_priv *priv, u8 signal_strength_index); +long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index); void rtl819x_update_rxsignalstatistics8190pci(struct r8192_priv *priv, struct rtllib_rx_stats *pprevious_stats); u8 rtl92e_evm_db_to_percent(char value); -- cgit v1.3-6-gb490 From 7879efc5a6a072eb27c14a74b45676a5cdfd26a1 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:24 +0200 Subject: staging: rtl8192e: Rename rtl819x_UpdateRxPktTimeStamp Use naming schema found in other rtlwifi devices. Rename rtl819x_UpdateRxPktTimeStamp to rtl92e_update_rx_pkt_timestamp. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 2f64a0fa512c..84f02befc8e8 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2071,7 +2071,7 @@ bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats, stats->TimeStampLow = pDrvInfo->TSFL; stats->TimeStampHigh = rtl92e_readl(dev, TSFR+4); - rtl819x_UpdateRxPktTimeStamp(dev, stats); + rtl92e_update_rx_pkt_timestamp(dev, stats); if ((stats->RxBufShift + stats->RxDrvInfoSize) > 0) stats->bShift = 1; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index f9bf923cf8c7..0ca62edca3d1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1983,8 +1983,8 @@ void rtl92e_reset_desc_ring(struct net_device *dev) spin_unlock_irqrestore(&priv->irq_th_lock, flags); } -void rtl819x_UpdateRxPktTimeStamp(struct net_device *dev, - struct rtllib_rx_stats *stats) +void rtl92e_update_rx_pkt_timestamp(struct net_device *dev, + struct rtllib_rx_stats *stats) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index c9599a9852ee..793013df8478 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -603,8 +603,8 @@ void rtl92e_irq_enable(struct net_device *dev); void rtl92e_config_rate(struct net_device *dev, u16 *rate_config); void rtl92e_irq_disable(struct net_device *dev); -void rtl819x_UpdateRxPktTimeStamp(struct net_device *dev, - struct rtllib_rx_stats *stats); +void rtl92e_update_rx_pkt_timestamp(struct net_device *dev, + struct rtllib_rx_stats *stats); long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index); void rtl819x_update_rxsignalstatistics8190pci(struct r8192_priv *priv, struct rtllib_rx_stats *pprevious_stats); -- cgit v1.3-6-gb490 From 97ef450b860065fe3b7c657382af889c6ed00c79 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:25 +0200 Subject: staging: rtl8192e: Rename rtl819x_update_rxsignalstatistics8190pci Use naming schema found in other rtlwifi devices. Rename rtl819x_update_rxsignalstatistics8190pci to rtl92e_update_rx_statistics. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 7 ++----- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 84f02befc8e8..22b30536beb2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -1821,7 +1821,7 @@ static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer, (RX_SMOOTH-1)) + (prev_st->RxPWDBAll)) / (RX_SMOOTH); } - rtl819x_update_rxsignalstatistics8190pci(priv, prev_st); + rtl92e_update_rx_statistics(priv, prev_st); } if (prev_st->SignalQuality != 0) { diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 0ca62edca3d1..9c8c63d6a81c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2005,11 +2005,8 @@ long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index) } -void -rtl819x_update_rxsignalstatistics8190pci( - struct r8192_priv *priv, - struct rtllib_rx_stats *pprevious_stats - ) +void rtl92e_update_rx_statistics(struct r8192_priv *priv, + struct rtllib_rx_stats *pprevious_stats) { int weighting = 0; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 793013df8478..b5f582735cad 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -606,8 +606,8 @@ void rtl92e_irq_disable(struct net_device *dev); void rtl92e_update_rx_pkt_timestamp(struct net_device *dev, struct rtllib_rx_stats *stats); long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index); -void rtl819x_update_rxsignalstatistics8190pci(struct r8192_priv *priv, - struct rtllib_rx_stats *pprevious_stats); +void rtl92e_update_rx_statistics(struct r8192_priv *priv, + struct rtllib_rx_stats *pprevious_stats); u8 rtl92e_evm_db_to_percent(char value); u8 rtl92e_rx_db_to_percent(char antpower); void rtl92e_copy_mpdu_stats(struct rtllib_rx_stats *psrc_stats, -- cgit v1.3-6-gb490 From d8ae1967694aca45edf9a9d559aa904c433b4bbe Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:26 +0200 Subject: staging: rtl8192e: Rename write_nic_byte Use naming schema found in other rtlwifi devices. Rename write_nic_byte to rtl92e_writeb. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 52 ++++---- .../staging/rtl8192e/rtl8192e/r8192E_firmware.c | 6 +- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 24 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 6 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 144 ++++++++++----------- drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c | 36 +++--- drivers/staging/rtl8192e/rtl8192e/rtl_pm.c | 4 +- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 2 +- 11 files changed, 141 insertions(+), 139 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c index 28cb9dd7b73c..9ddabf59784c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c @@ -81,7 +81,7 @@ bool rtl92e_send_cmd_pkt(struct net_device *dev, u8 *code_virtual_address, } while (frag_offset < buffer_len); - write_nic_byte(dev, TPPoll, TPPoll_CQ); + rtl92e_writeb(dev, TPPoll, TPPoll_CQ); Failed: return rt_status; } diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 22b30536beb2..371ee63d521f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -49,7 +49,7 @@ void rtl92e_start_beacon(struct net_device *dev) write_nic_word(dev, BCN_DRV_EARLY_INT, 10); write_nic_word(dev, BCN_DMATIME, 256); - write_nic_byte(dev, BCN_ERR_THRESH, 100); + rtl92e_writeb(dev, BCN_ERR_THRESH, 100); BcnTimeCfg |= BcnCW<rtllib->LedControlHandler) priv->rtllib->LedControlHandler(dev, LedAction); } @@ -133,7 +133,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) break; } - write_nic_byte(dev, MSR, btMsr); + rtl92e_writeb(dev, MSR, btMsr); } break; @@ -160,7 +160,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) case HW_VAR_SLOT_TIME: priv->slot_time = val[0]; - write_nic_byte(dev, SLOT_TIME, val[0]); + rtl92e_writeb(dev, SLOT_TIME, val[0]); break; @@ -289,20 +289,20 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) RT_TRACE(COMP_QOS, "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl); - write_nic_byte(dev, AcmHwCtrl, AcmCtrl); + rtl92e_writeb(dev, AcmHwCtrl, AcmCtrl); break; } case HW_VAR_SIFS: - write_nic_byte(dev, SIFS, val[0]); - write_nic_byte(dev, SIFS+1, val[0]); + rtl92e_writeb(dev, SIFS, val[0]); + rtl92e_writeb(dev, SIFS+1, val[0]); break; case HW_VAR_RF_TIMING: { u8 Rf_Timing = *((u8 *)val); - write_nic_byte(dev, rFPGA0_RFTiming1, Rf_Timing); + rtl92e_writeb(dev, rFPGA0_RFTiming1, Rf_Timing); break; } @@ -683,7 +683,7 @@ static void rtl8192_hwconfig(struct net_device *dev) break; } - write_nic_byte(dev, BW_OPMODE, regBwOpMode); + rtl92e_writeb(dev, BW_OPMODE, regBwOpMode); { u32 ratr_value = 0; @@ -691,7 +691,7 @@ static void rtl8192_hwconfig(struct net_device *dev) if (priv->rf_type == RF_1T2R) ratr_value &= ~(RATE_ALL_OFDM_2SS); write_nic_dword(dev, RATR0, ratr_value); - write_nic_byte(dev, UFWP, 1); + rtl92e_writeb(dev, UFWP, 1); } regTmp = rtl92e_readb(dev, 0x313); regRRSR = ((regTmp) << 24) | (regRRSR & 0x00ffffff); @@ -721,7 +721,7 @@ start: rtl92e_reset_desc_ring(dev); priv->Rf_Mode = RF_OP_By_SW_3wire; if (priv->ResetProgress == RESET_TYPE_NORESET) { - write_nic_byte(dev, ANAPAR, 0x37); + rtl92e_writeb(dev, ANAPAR, 0x37); mdelay(500); } priv->pFirmware->firmware_status = FW_STATUS_0_INIT; @@ -744,9 +744,9 @@ start: if (ICVersion >= 0x4) { SwitchingRegulatorOutput = rtl92e_readb(dev, SWREGULATOR); if (SwitchingRegulatorOutput != 0xb8) { - write_nic_byte(dev, SWREGULATOR, 0xa8); + rtl92e_writeb(dev, SWREGULATOR, 0xa8); mdelay(1); - write_nic_byte(dev, SWREGULATOR, 0xb8); + rtl92e_writeb(dev, SWREGULATOR, 0xb8); } } RT_TRACE(COMP_INIT, "BB Config Start!\n"); @@ -774,10 +774,10 @@ start: udelay(500); } rtl8192_hwconfig(dev); - write_nic_byte(dev, CMDR, CR_RE | CR_TE); + rtl92e_writeb(dev, CMDR, CR_RE | CR_TE); - write_nic_byte(dev, PCIF, ((MXDMA2_NoLimit<dev_addr)[0]); write_nic_word(dev, MAC4, ((u16 *)(dev->dev_addr + 4))[0]); write_nic_dword(dev, RCR, priv->ReceiveConfig); @@ -805,7 +805,7 @@ start: write_nic_dword(dev, RRSR, ulRegRead); write_nic_dword(dev, RATR0+4*7, (RATE_ALL_OFDM_AG | RATE_ALL_CCK)); - write_nic_byte(dev, ACK_TIMEOUT, 0x30); + rtl92e_writeb(dev, ACK_TIMEOUT, 0x30); if (priv->ResetProgress == RESET_TYPE_NORESET) rtl92e_set_wireless_mode(dev, priv->rtllib->mode); @@ -816,7 +816,7 @@ start: SECR_value |= SCR_TxEncEnable; SECR_value |= SCR_RxDecEnable; SECR_value |= SCR_NoSKMC; - write_nic_byte(dev, SECR, SECR_value); + rtl92e_writeb(dev, SECR, SECR_value); } write_nic_word(dev, ATIMWND, 2); write_nic_word(dev, BCN_INTERVAL, 100); @@ -826,7 +826,7 @@ start: for (i = 0; i < QOS_QUEUE_NUM; i++) write_nic_dword(dev, WDCAPARA_ADD[i], 0x005e4332); } - write_nic_byte(dev, 0xbe, 0xc0); + rtl92e_writeb(dev, 0xbe, 0xc0); rtl92e_config_mac(dev); @@ -875,7 +875,7 @@ start: rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bCCKEn, 0x1); rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bOFDMEn, 0x1); - write_nic_byte(dev, 0x87, 0x0); + rtl92e_writeb(dev, 0x87, 0x0); if (priv->RegRfOff) { RT_TRACE((COMP_INIT | COMP_RF | COMP_POWER), @@ -979,7 +979,7 @@ static void rtl8192_net_update(struct net_device *dev) write_nic_word(dev, BCN_DMATIME, 256); write_nic_word(dev, BCN_INTERVAL, net->beacon_interval); write_nic_word(dev, BCN_DRV_EARLY_INT, 10); - write_nic_byte(dev, BCN_ERR_THRESH, 100); + rtl92e_writeb(dev, BCN_ERR_THRESH, 100); BcnTimeCfg |= (BcnCW<pairwise_key_type)) rtl92e_enable_hw_security_config(dev); } else { - write_nic_byte(dev, 0x173, 0); + rtl92e_writeb(dev, 0x173, 0); } rtl8192e_update_msr(dev); @@ -2108,7 +2108,7 @@ void rtl92e_stop_adapter(struct net_device *dev, bool reset) if (!priv->rtllib->bSupportRemoteWakeUp) { u1bTmp = 0x0; - write_nic_byte(dev, CMDR, u1bTmp); + rtl92e_writeb(dev, CMDR, u1bTmp); } mdelay(20); @@ -2129,8 +2129,8 @@ void rtl92e_stop_adapter(struct net_device *dev, bool reset) write_nic_dword(dev, WFCRC2, 0xffffffff); - write_nic_byte(dev, PMR, 0x5); - write_nic_byte(dev, MacBlkCtrl, 0xa); + rtl92e_writeb(dev, PMR, 0x5); + rtl92e_writeb(dev, MacBlkCtrl, 0xa); } } @@ -2186,7 +2186,7 @@ void rtl92e_update_ratr_table(struct net_device *dev) ieee->pHTInfo->bCurShortGI20MHz) ratr_value |= 0x80000000; write_nic_dword(dev, RATR0+rate_index*4, ratr_value); - write_nic_byte(dev, UFWP, 1); + rtl92e_writeb(dev, UFWP, 1); } void diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c index 7e59f5c6b951..37e5c1403a7e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c @@ -96,7 +96,7 @@ static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, } while (frag_offset < buffer_len); - write_nic_byte(dev, TPPoll, TPPoll_CQ); + rtl92e_writeb(dev, TPPoll, TPPoll_CQ); return true; } @@ -123,8 +123,8 @@ static bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) } CPU_status = rtl92e_readl(dev, CPU_GEN); - write_nic_byte(dev, CPU_GEN, - (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff)); + rtl92e_writeb(dev, CPU_GEN, + (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff)); mdelay(1); timeout = jiffies + msecs_to_jiffies(200); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 667f44f01c53..d2868d76c52a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -553,7 +553,7 @@ static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) u32 dwRegValue = 0; bRegValue = rtl92e_readb(dev, BB_GLOBAL_RESET); - write_nic_byte(dev, BB_GLOBAL_RESET, (bRegValue|BB_GLOBAL_RESET_BIT)); + rtl92e_writeb(dev, BB_GLOBAL_RESET, (bRegValue|BB_GLOBAL_RESET_BIT)); dwRegValue = rtl92e_readl(dev, CPU_GEN); write_nic_dword(dev, CPU_GEN, (dwRegValue&(~CPU_GEN_BB_RST))); @@ -943,8 +943,8 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, (u16)CurrentCmd->Para2); break; case CmdID_WritePortUchar: - write_nic_byte(dev, CurrentCmd->Para1, - (u8)CurrentCmd->Para2); + rtl92e_writeb(dev, CurrentCmd->Para1, + (u8)CurrentCmd->Para2); break; case CmdID_RF_WriteReg: for (eRFPath = 0; eRFPath < @@ -1182,12 +1182,12 @@ static void rtl8192_SetBWModeWorkItem(struct net_device *dev) switch (priv->CurrentChannelBW) { case HT_CHANNEL_WIDTH_20: regBwOpMode |= BW_OPMODE_20MHZ; - write_nic_byte(dev, BW_OPMODE, regBwOpMode); + rtl92e_writeb(dev, BW_OPMODE, regBwOpMode); break; case HT_CHANNEL_WIDTH_20_40: regBwOpMode &= ~BW_OPMODE_20MHZ; - write_nic_byte(dev, BW_OPMODE, regBwOpMode); + rtl92e_writeb(dev, BW_OPMODE, regBwOpMode); break; default: @@ -1341,13 +1341,13 @@ void rtl92e_init_gain(struct net_device *dev, u8 Operation) RT_TRACE(COMP_SCAN, "Write scan initial gain = 0x%x\n", initial_gain); - write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain); - write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain); - write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain); - write_nic_byte(dev, rOFDM0_XDAGCCore1, initial_gain); + rtl92e_writeb(dev, rOFDM0_XAAGCCore1, initial_gain); + rtl92e_writeb(dev, rOFDM0_XBAGCCore1, initial_gain); + rtl92e_writeb(dev, rOFDM0_XCAGCCore1, initial_gain); + rtl92e_writeb(dev, rOFDM0_XDAGCCore1, initial_gain); RT_TRACE(COMP_SCAN, "Write scan 0xa0a = 0x%x\n", POWER_DETECTION_TH); - write_nic_byte(dev, 0xa0a, POWER_DETECTION_TH); + rtl92e_writeb(dev, 0xa0a, POWER_DETECTION_TH); break; case IG_Restore: RT_TRACE(COMP_SCAN, @@ -1409,7 +1409,7 @@ void rtl92e_set_rf_off(struct net_device *dev) rtl92e_set_bb_reg(dev, rOFDM1_TRxPathEnable, 0xf, 0x0); rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x60, 0x0); rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x4, 0x0); - write_nic_byte(dev, ANAPAR_FOR_8192PciE, 0x07); + rtl92e_writeb(dev, ANAPAR_FOR_8192PciE, 0x07); } @@ -1455,7 +1455,7 @@ static bool SetRFPowerState8190(struct net_device *dev, RT_CLEAR_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC); } else { - write_nic_byte(dev, ANAPAR, 0x37); + rtl92e_writeb(dev, ANAPAR, 0x37); mdelay(1); rtl92e_set_bb_reg(dev, rFPGA0_AnalogParameter1, 0x4, 0x1); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index 9c14286146a2..cba71585a321 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -65,7 +65,7 @@ void rtl92e_enable_hw_security_config(struct net_device *dev) RT_TRACE(COMP_SEC, "%s:, hwsec:%d, pairwise_key:%d, SECR_value:%x\n", __func__, ieee->hwsec_active, ieee->pairwise_key_type, SECR_value); - write_nic_byte(dev, SECR, SECR_value); + rtl92e_writeb(dev, SECR, SECR_value); } void rtl92e_set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 9c8c63d6a81c..65d6418b24db 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -125,7 +125,7 @@ u16 rtl92e_readw(struct net_device *dev, int x) return readw((u8 __iomem *)dev->mem_start + x); } -void write_nic_byte(struct net_device *dev, int x, u8 y) +void rtl92e_writeb(struct net_device *dev, int x, u8 y) { writeb(y, (u8 __iomem *)dev->mem_start + x); @@ -1385,7 +1385,7 @@ END: priv->bForcedSilentReset = false; priv->bResetInProgress = false; - write_nic_byte(dev, UFWP, 1); + rtl92e_writeb(dev, UFWP, 1); RT_TRACE(COMP_RESET, "Reset finished!! ====>[%d]\n", priv->reset_count); } @@ -2393,7 +2393,7 @@ static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) && ieee->pHTInfo->bCurrentHTSupport) { - write_nic_byte(dev, 0x173, 1); + rtl92e_writeb(dev, 0x173, 1); } } else { diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index b5f582735cad..21b6d01ee6a5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -581,7 +581,7 @@ extern const struct ethtool_ops rtl819x_ethtool_ops; u8 rtl92e_readb(struct net_device *dev, int x); u32 rtl92e_readl(struct net_device *dev, int x); u16 rtl92e_readw(struct net_device *dev, int x); -void write_nic_byte(struct net_device *dev, int x, u8 y); +void rtl92e_writeb(struct net_device *dev, int x, u8 y); void write_nic_word(struct net_device *dev, int x, u16 y); void write_nic_dword(struct net_device *dev, int x, u32 y); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 5bbb390334aa..1690f6f764ed 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -455,7 +455,7 @@ static void dm_check_rate_adaptive(struct net_device *dev) if (priv->rf_type == RF_1T2R) ratr_value &= ~(RATE_ALL_OFDM_2SS); write_nic_dword(dev, RATR0, ratr_value); - write_nic_byte(dev, UFWP, 1); + rtl92e_writeb(dev, UFWP, 1); pra->last_ratr = targetRATR; } @@ -653,8 +653,8 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) u32 delta = 0; RT_TRACE(COMP_POWER_TRACKING, "%s()\n", __func__); - write_nic_byte(dev, Pw_Track_Flag, 0); - write_nic_byte(dev, FW_Busy_Flag, 0); + rtl92e_writeb(dev, Pw_Track_Flag, 0); + rtl92e_writeb(dev, FW_Busy_Flag, 0); priv->rtllib->bdynamic_txpower_enable = false; bHighpowerstate = priv->bDynamicTxHighPower; @@ -683,15 +683,15 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) if (priv->bResetInProgress) { RT_TRACE(COMP_POWER_TRACKING, "we are in silent reset progress, so return\n"); - write_nic_byte(dev, Pw_Track_Flag, 0); - write_nic_byte(dev, FW_Busy_Flag, 0); + rtl92e_writeb(dev, Pw_Track_Flag, 0); + rtl92e_writeb(dev, FW_Busy_Flag, 0); return; } if (priv->rtllib->eRFPowerState != eRfOn) { RT_TRACE(COMP_POWER_TRACKING, "we are in power save, so return\n"); - write_nic_byte(dev, Pw_Track_Flag, 0); - write_nic_byte(dev, FW_Busy_Flag, 0); + rtl92e_writeb(dev, Pw_Track_Flag, 0); + rtl92e_writeb(dev, FW_Busy_Flag, 0); return; } @@ -701,8 +701,8 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) Avg_TSSI_Meas = rtl92e_readw(dev, Tssi_Mea_Value); if (Avg_TSSI_Meas == 0) { - write_nic_byte(dev, Pw_Track_Flag, 0); - write_nic_byte(dev, FW_Busy_Flag, 0); + rtl92e_writeb(dev, Pw_Track_Flag, 0); + rtl92e_writeb(dev, FW_Busy_Flag, 0); return; } @@ -725,7 +725,7 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) } if (viviflag) { - write_nic_byte(dev, Pw_Track_Flag, 0); + rtl92e_writeb(dev, Pw_Track_Flag, 0); viviflag = false; RT_TRACE(COMP_POWER_TRACKING, "we filted this data\n"); @@ -752,8 +752,8 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) if (delta <= E_FOR_TX_POWER_TRACK) { priv->rtllib->bdynamic_txpower_enable = true; - write_nic_byte(dev, Pw_Track_Flag, 0); - write_nic_byte(dev, FW_Busy_Flag, 0); + rtl92e_writeb(dev, Pw_Track_Flag, 0); + rtl92e_writeb(dev, FW_Busy_Flag, 0); RT_TRACE(COMP_POWER_TRACKING, "tx power track is done\n"); RT_TRACE(COMP_POWER_TRACKING, @@ -825,23 +825,23 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) if (priv->CCKPresentAttentuation_difference <= -12 || priv->CCKPresentAttentuation_difference >= 24) { priv->rtllib->bdynamic_txpower_enable = true; - write_nic_byte(dev, Pw_Track_Flag, 0); - write_nic_byte(dev, FW_Busy_Flag, 0); + rtl92e_writeb(dev, Pw_Track_Flag, 0); + rtl92e_writeb(dev, FW_Busy_Flag, 0); RT_TRACE(COMP_POWER_TRACKING, "tx power track--->limited\n"); return; } - write_nic_byte(dev, Pw_Track_Flag, 0); + rtl92e_writeb(dev, Pw_Track_Flag, 0); Avg_TSSI_Meas_from_driver = 0; for (k = 0; k < 5; k++) tmp_report[k] = 0; break; } - write_nic_byte(dev, FW_Busy_Flag, 0); + rtl92e_writeb(dev, FW_Busy_Flag, 0); } priv->rtllib->bdynamic_txpower_enable = true; - write_nic_byte(dev, Pw_Track_Flag, 0); + rtl92e_writeb(dev, Pw_Track_Flag, 0); } static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev) @@ -1212,7 +1212,7 @@ void dm_restore_dynamic_mechanism_state(struct net_device *dev) if (priv->rf_type == RF_1T2R) ratr_value &= ~(RATE_ALL_OFDM_2SS); write_nic_dword(dev, RATR0, ratr_value); - write_nic_byte(dev, UFWP, 1); + rtl92e_writeb(dev, UFWP, 1); if (priv->btxpower_trackingInit && priv->btxpower_tracking) dm_txpower_reset_recovery(dev); @@ -1427,17 +1427,17 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x8); - write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x17); - write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x17); - write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x17); - write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x17); + rtl92e_writeb(dev, rOFDM0_XAAGCCore1, 0x17); + rtl92e_writeb(dev, rOFDM0_XBAGCCore1, 0x17); + rtl92e_writeb(dev, rOFDM0_XCAGCCore1, 0x17); + rtl92e_writeb(dev, rOFDM0_XDAGCCore1, 0x17); if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); + rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x00); else - write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x42); - write_nic_byte(dev, 0xa0a, 0x08); + rtl92e_writeb(dev, 0xa0a, 0x08); return; } @@ -1458,23 +1458,23 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm( dm_digtable.dig_state = DM_STA_DIG_ON; if (reset_flag == 1) { - write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x2c); - write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x2c); - write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x2c); - write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x2c); + rtl92e_writeb(dev, rOFDM0_XAAGCCore1, 0x2c); + rtl92e_writeb(dev, rOFDM0_XBAGCCore1, 0x2c); + rtl92e_writeb(dev, rOFDM0_XCAGCCore1, 0x2c); + rtl92e_writeb(dev, rOFDM0_XDAGCCore1, 0x2c); } else { - write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x20); - write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x20); - write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x20); - write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x20); + rtl92e_writeb(dev, rOFDM0_XAAGCCore1, 0x20); + rtl92e_writeb(dev, rOFDM0_XBAGCCore1, 0x20); + rtl92e_writeb(dev, rOFDM0_XCAGCCore1, 0x20); + rtl92e_writeb(dev, rOFDM0_XDAGCCore1, 0x20); } if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); + rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x20); else - write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); + rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x44); - write_nic_byte(dev, 0xa0a, 0xcd); + rtl92e_writeb(dev, 0xa0a, 0xcd); rtl92e_set_bb_reg(dev, UFWP, bMaskByte1, 0x1); } @@ -1501,9 +1501,9 @@ static void dm_ctrl_initgain_byrssi_highpwr(struct net_device *dev) dm_digtable.dig_highpwr_state = DM_STA_DIG_ON; if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); + rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x10); else - write_nic_byte(dev, rOFDM0_RxDetector1, 0x43); + rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x43); } else { if (dm_digtable.dig_highpwr_state == DM_STA_DIG_OFF && (priv->reset_count == reset_cnt_highpwr)) @@ -1515,9 +1515,9 @@ static void dm_ctrl_initgain_byrssi_highpwr(struct net_device *dev) (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh)) { if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); + rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x20); else - write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); + rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x44); } } reset_cnt_highpwr = priv->reset_count; @@ -1570,10 +1570,10 @@ static void dm_initial_gain(struct net_device *dev) if ((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value) || !initialized || force_write) { initial_gain = (u8)dm_digtable.cur_ig_value; - write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain); - write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain); - write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain); - write_nic_byte(dev, rOFDM0_XDAGCCore1, initial_gain); + rtl92e_writeb(dev, rOFDM0_XAAGCCore1, initial_gain); + rtl92e_writeb(dev, rOFDM0_XBAGCCore1, initial_gain); + rtl92e_writeb(dev, rOFDM0_XCAGCCore1, initial_gain); + rtl92e_writeb(dev, rOFDM0_XDAGCCore1, initial_gain); dm_digtable.pre_ig_value = dm_digtable.cur_ig_value; initialized = 1; force_write = 0; @@ -1626,20 +1626,20 @@ static void dm_pd_th(struct net_device *dev) (initialized <= 3) || force_write) { if (dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) { if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00); + rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x00); else - write_nic_byte(dev, rOFDM0_RxDetector1, 0x42); + rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x42); } else if (dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER) { if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20); + rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x20); else - write_nic_byte(dev, rOFDM0_RxDetector1, 0x44); + rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x44); } else if (dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER) { if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) - write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10); + rtl92e_writeb(dev, (rOFDM0_XATxAFE+3), 0x10); else - write_nic_byte(dev, rOFDM0_RxDetector1, 0x43); + rtl92e_writeb(dev, rOFDM0_RxDetector1, 0x43); } dm_digtable.prepd_thstate = dm_digtable.curpd_thstate; if (initialized <= 3) @@ -1683,9 +1683,9 @@ static void dm_cs_ratio(struct net_device *dev) if ((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) || !initialized || force_write) { if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER) - write_nic_byte(dev, 0xa0a, 0x08); + rtl92e_writeb(dev, 0xa0a, 0x08); else if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_HIGHER) - write_nic_byte(dev, 0xa0a, 0xcd); + rtl92e_writeb(dev, 0xa0a, 0xcd); dm_digtable.precs_ratio_state = dm_digtable.curcs_ratio_state; initialized = 1; force_write = 0; @@ -2248,18 +2248,18 @@ static void dm_fsync_timer_callback(unsigned long data) bDoubleTimeInterval = true; priv->bswitch_fsync = !priv->bswitch_fsync; if (priv->bswitch_fsync) { - write_nic_byte(dev, 0xC36, 0x1c); - write_nic_byte(dev, 0xC3e, 0x90); + rtl92e_writeb(dev, 0xC36, 0x1c); + rtl92e_writeb(dev, 0xC3e, 0x90); } else { - write_nic_byte(dev, 0xC36, 0x5c); - write_nic_byte(dev, 0xC3e, 0x96); + rtl92e_writeb(dev, 0xC36, 0x5c); + rtl92e_writeb(dev, 0xC3e, 0x96); } } else if (priv->undecorated_smoothed_pwdb <= priv->rtllib->fsync_rssi_threshold) { if (priv->bswitch_fsync) { priv->bswitch_fsync = false; - write_nic_byte(dev, 0xC36, 0x5c); - write_nic_byte(dev, 0xC3e, 0x96); + rtl92e_writeb(dev, 0xC36, 0x5c); + rtl92e_writeb(dev, 0xC3e, 0x96); } } if (bDoubleTimeInterval) { @@ -2279,8 +2279,8 @@ static void dm_fsync_timer_callback(unsigned long data) } else { if (priv->bswitch_fsync) { priv->bswitch_fsync = false; - write_nic_byte(dev, 0xC36, 0x5c); - write_nic_byte(dev, 0xC3e, 0x96); + rtl92e_writeb(dev, 0xC36, 0x5c); + rtl92e_writeb(dev, 0xC3e, 0x96); } priv->ContinueDiffCount = 0; write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); @@ -2301,7 +2301,7 @@ static void dm_StartHWFsync(struct net_device *dev) write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cf); priv->rtllib->SetHwRegHandler(dev, HW_VAR_RF_TIMING, (u8 *)(&rf_timing)); - write_nic_byte(dev, 0xc3b, 0x41); + rtl92e_writeb(dev, 0xc3b, 0x41); } static void dm_EndHWFsync(struct net_device *dev) @@ -2313,7 +2313,7 @@ static void dm_EndHWFsync(struct net_device *dev) write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); priv->rtllib->SetHwRegHandler(dev, HW_VAR_RF_TIMING, (u8 *) (&rf_timing)); - write_nic_byte(dev, 0xc3b, 0x49); + rtl92e_writeb(dev, 0xc3b, 0x49); } static void dm_EndSWFsync(struct net_device *dev) @@ -2326,9 +2326,9 @@ static void dm_EndSWFsync(struct net_device *dev) if (priv->bswitch_fsync) { priv->bswitch_fsync = false; - write_nic_byte(dev, 0xC36, 0x5c); + rtl92e_writeb(dev, 0xC36, 0x5c); - write_nic_byte(dev, 0xC3e, 0x96); + rtl92e_writeb(dev, 0xC3e, 0x96); } priv->ContinueDiffCount = 0; @@ -2427,7 +2427,7 @@ static void dm_check_fsync(struct net_device *dev) } if (priv->framesyncMonitor) { if (reg_c38_State != RegC38_Fsync_AP_BCM) { - write_nic_byte(dev, rOFDM0_RxDetector3, 0x95); + rtl92e_writeb(dev, rOFDM0_RxDetector3, 0x95); reg_c38_State = RegC38_Fsync_AP_BCM; } @@ -2453,7 +2453,7 @@ static void dm_check_fsync(struct net_device *dev) RegC38_TH) { if (reg_c38_State != RegC38_NonFsync_Other_AP) { - write_nic_byte(dev, + rtl92e_writeb(dev, rOFDM0_RxDetector3, 0x90); @@ -2463,7 +2463,7 @@ static void dm_check_fsync(struct net_device *dev) } else if (priv->undecorated_smoothed_pwdb >= (RegC38_TH+5)) { if (reg_c38_State) { - write_nic_byte(dev, + rtl92e_writeb(dev, rOFDM0_RxDetector3, priv->framesync); reg_c38_State = RegC38_Default; @@ -2471,8 +2471,8 @@ static void dm_check_fsync(struct net_device *dev) } } else { if (reg_c38_State) { - write_nic_byte(dev, rOFDM0_RxDetector3, - priv->framesync); + rtl92e_writeb(dev, rOFDM0_RxDetector3, + priv->framesync); reg_c38_State = RegC38_Default; } } @@ -2480,14 +2480,14 @@ static void dm_check_fsync(struct net_device *dev) } if (priv->framesyncMonitor) { if (priv->reset_count != reset_cnt) { - write_nic_byte(dev, rOFDM0_RxDetector3, + rtl92e_writeb(dev, rOFDM0_RxDetector3, priv->framesync); reg_c38_State = RegC38_Default; reset_cnt = priv->reset_count; } } else { if (reg_c38_State) { - write_nic_byte(dev, rOFDM0_RxDetector3, + rtl92e_writeb(dev, rOFDM0_RxDetector3, priv->framesync); reg_c38_State = RegC38_Default; } @@ -2578,5 +2578,5 @@ static void dm_send_rssi_tofw(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); - write_nic_byte(dev, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb); + rtl92e_writeb(dev, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c index 61d462063fa7..f58534609691 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c @@ -28,12 +28,13 @@ static void eprom_cs(struct net_device *dev, short bit) { if (bit) - write_nic_byte(dev, EPROM_CMD, - (1 << EPROM_CS_SHIFT) | - rtl92e_readb(dev, EPROM_CMD)); + rtl92e_writeb(dev, EPROM_CMD, + (1 << EPROM_CS_SHIFT) | + rtl92e_readb(dev, EPROM_CMD)); else - write_nic_byte(dev, EPROM_CMD, rtl92e_readb(dev, EPROM_CMD) - & ~(1<epromtype == EEPROM_93C56) { @@ -133,7 +135,7 @@ u32 eprom_read(struct net_device *dev, u32 addr) eprom_cs(dev, 0); eprom_ck_cycle(dev); - write_nic_byte(dev, EPROM_CMD, - (EPROM_CMD_NORMAL<rtllib->bSupportRemoteWakeUp ? diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index 29400eeda968..ebed99b3d637 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -961,7 +961,7 @@ static int r8192_wx_set_enc_ext(struct net_device *dev, } else { if ((ieee->pairwise_key_type == KEY_TYPE_CCMP) && ieee->pHTInfo->bCurrentHTSupport) - write_nic_byte(dev, 0x173, 1); + rtl92e_writeb(dev, 0x173, 1); rtl92e_set_key(dev, 4, idx, alg, (u8 *)ieee->ap_mac_addr, 0, key); rtl92e_set_swcam(dev, 4, idx, alg, -- cgit v1.3-6-gb490 From 8ea541001bf7b0a2bbffa447ccfa834354c9f1dc Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:27 +0200 Subject: staging: rtl8192e: Rename write_nic_dword Use naming schema found in other rtlwifi devices. Rename write_nic_dword to rtl92e_writel. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 94 +++++++++++++------------- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 32 ++++----- drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 16 ++--- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 10 +-- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 42 ++++++------ drivers/staging/rtl8192e/rtl8192e/rtl_pm.c | 8 +-- 7 files changed, 100 insertions(+), 104 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 371ee63d521f..896d2ab07f16 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -101,7 +101,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) switch (variable) { case HW_VAR_BSSID: - write_nic_dword(dev, BSSIDR, ((u32 *)(val))[0]); + rtl92e_writel(dev, BSSIDR, ((u32 *)(val))[0]); write_nic_word(dev, BSSIDR+2, ((u16 *)(val+2))[0]); break; @@ -151,7 +151,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) else if (Type == false) RegRCR &= (~RCR_CBSSID); - write_nic_dword(dev, RCR, RegRCR); + rtl92e_writel(dev, RCR, RegRCR); priv->ReceiveConfig = RegRCR; } @@ -172,12 +172,12 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) regTmp = priv->basic_rate; if (priv->short_preamble) regTmp |= BRSR_AckShortPmb; - write_nic_dword(dev, RRSR, regTmp); + rtl92e_writel(dev, RRSR, regTmp); break; } case HW_VAR_CPU_RST: - write_nic_dword(dev, CPU_GEN, ((u32 *)(val))[0]); + rtl92e_writel(dev, CPU_GEN, ((u32 *)(val))[0]); break; case HW_VAR_AC_PARAM: @@ -207,19 +207,19 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) __func__, eACI, u4bAcParam); switch (eACI) { case AC1_BK: - write_nic_dword(dev, EDCAPARA_BK, u4bAcParam); + rtl92e_writel(dev, EDCAPARA_BK, u4bAcParam); break; case AC0_BE: - write_nic_dword(dev, EDCAPARA_BE, u4bAcParam); + rtl92e_writel(dev, EDCAPARA_BE, u4bAcParam); break; case AC2_VI: - write_nic_dword(dev, EDCAPARA_VI, u4bAcParam); + rtl92e_writel(dev, EDCAPARA_VI, u4bAcParam); break; case AC3_VO: - write_nic_dword(dev, EDCAPARA_VO, u4bAcParam); + rtl92e_writel(dev, EDCAPARA_VO, u4bAcParam); break; default: @@ -690,12 +690,12 @@ static void rtl8192_hwconfig(struct net_device *dev) ratr_value = regRATR; if (priv->rf_type == RF_1T2R) ratr_value &= ~(RATE_ALL_OFDM_2SS); - write_nic_dword(dev, RATR0, ratr_value); + rtl92e_writel(dev, RATR0, ratr_value); rtl92e_writeb(dev, UFWP, 1); } regTmp = rtl92e_readb(dev, 0x313); regRRSR = ((regTmp) << 24) | (regRRSR & 0x00ffffff); - write_nic_dword(dev, RRSR, regRRSR); + rtl92e_writel(dev, RRSR, regRRSR); write_nic_word(dev, RETRY_LIMIT, priv->ShortRetryLimit << RETRY_LIMIT_SHORT_SHIFT | @@ -738,7 +738,7 @@ start: netdev_err(dev, "%s(): undefined firmware state: %d.\n", __func__, priv->pFirmware->firmware_status); - write_nic_dword(dev, CPU_GEN, ulRegRead); + rtl92e_writel(dev, CPU_GEN, ulRegRead); ICVersion = rtl92e_readb(dev, IC_VERRSION); if (ICVersion >= 0x4) { @@ -769,7 +769,7 @@ start: netdev_err(dev, "%s: Invalid loopback mode setting.\n", __func__); - write_nic_dword(dev, CPU_GEN, ulRegRead); + rtl92e_writel(dev, CPU_GEN, ulRegRead); udelay(500); } @@ -778,32 +778,32 @@ start: rtl92e_writeb(dev, PCIF, ((MXDMA2_NoLimit<dev_addr)[0]); + rtl92e_writel(dev, MAC0, ((u32 *)dev->dev_addr)[0]); write_nic_word(dev, MAC4, ((u16 *)(dev->dev_addr + 4))[0]); - write_nic_dword(dev, RCR, priv->ReceiveConfig); - - write_nic_dword(dev, RQPN1, NUM_OF_PAGE_IN_FW_QUEUE_BK << - RSVD_FW_QUEUE_PAGE_BK_SHIFT | - NUM_OF_PAGE_IN_FW_QUEUE_BE << - RSVD_FW_QUEUE_PAGE_BE_SHIFT | - NUM_OF_PAGE_IN_FW_QUEUE_VI << - RSVD_FW_QUEUE_PAGE_VI_SHIFT | - NUM_OF_PAGE_IN_FW_QUEUE_VO << - RSVD_FW_QUEUE_PAGE_VO_SHIFT); - write_nic_dword(dev, RQPN2, NUM_OF_PAGE_IN_FW_QUEUE_MGNT << - RSVD_FW_QUEUE_PAGE_MGNT_SHIFT); - write_nic_dword(dev, RQPN3, APPLIED_RESERVED_QUEUE_IN_FW | - NUM_OF_PAGE_IN_FW_QUEUE_BCN << - RSVD_FW_QUEUE_PAGE_BCN_SHIFT| - NUM_OF_PAGE_IN_FW_QUEUE_PUB << - RSVD_FW_QUEUE_PAGE_PUB_SHIFT); + rtl92e_writel(dev, RCR, priv->ReceiveConfig); + + rtl92e_writel(dev, RQPN1, NUM_OF_PAGE_IN_FW_QUEUE_BK << + RSVD_FW_QUEUE_PAGE_BK_SHIFT | + NUM_OF_PAGE_IN_FW_QUEUE_BE << + RSVD_FW_QUEUE_PAGE_BE_SHIFT | + NUM_OF_PAGE_IN_FW_QUEUE_VI << + RSVD_FW_QUEUE_PAGE_VI_SHIFT | + NUM_OF_PAGE_IN_FW_QUEUE_VO << + RSVD_FW_QUEUE_PAGE_VO_SHIFT); + rtl92e_writel(dev, RQPN2, NUM_OF_PAGE_IN_FW_QUEUE_MGNT << + RSVD_FW_QUEUE_PAGE_MGNT_SHIFT); + rtl92e_writel(dev, RQPN3, APPLIED_RESERVED_QUEUE_IN_FW | + NUM_OF_PAGE_IN_FW_QUEUE_BCN << + RSVD_FW_QUEUE_PAGE_BCN_SHIFT| + NUM_OF_PAGE_IN_FW_QUEUE_PUB << + RSVD_FW_QUEUE_PAGE_PUB_SHIFT); rtl92e_tx_enable(dev); rtl92e_rx_enable(dev); ulRegRead = (0xFFF00000 & rtl92e_readl(dev, RRSR)) | RATE_ALL_OFDM_AG | RATE_ALL_CCK; - write_nic_dword(dev, RRSR, ulRegRead); - write_nic_dword(dev, RATR0+4*7, (RATE_ALL_OFDM_AG | RATE_ALL_CCK)); + rtl92e_writel(dev, RRSR, ulRegRead); + rtl92e_writel(dev, RATR0+4*7, (RATE_ALL_OFDM_AG | RATE_ALL_CCK)); rtl92e_writeb(dev, ACK_TIMEOUT, 0x30); @@ -824,7 +824,7 @@ start: int i; for (i = 0; i < QOS_QUEUE_NUM; i++) - write_nic_dword(dev, WDCAPARA_ADD[i], 0x005e4332); + rtl92e_writel(dev, WDCAPARA_ADD[i], 0x005e4332); } rtl92e_writeb(dev, 0xbe, 0xc0); @@ -971,7 +971,7 @@ static void rtl8192_net_update(struct net_device *dev) rtl92e_config_rate(dev, &rate_config); priv->dot11CurrentPreambleMode = PREAMBLE_AUTO; priv->basic_rate = rate_config &= 0x15f; - write_nic_dword(dev, BSSIDR, ((u32 *)net->bssid)[0]); + rtl92e_writel(dev, BSSIDR, ((u32 *)net->bssid)[0]); write_nic_word(dev, BSSIDR+4, ((u16 *)net->bssid)[2]); if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { @@ -1019,7 +1019,7 @@ void rtl92e_link_change(struct net_device *dev) } else priv->ReceiveConfig = reg &= ~RCR_CBSSID; - write_nic_dword(dev, RCR, reg); + rtl92e_writel(dev, RCR, reg); } } @@ -1034,7 +1034,7 @@ void rtl92e_set_monitor_mode(struct net_device *dev, bool bAllowAllDA, priv->ReceiveConfig &= ~RCR_AAP; if (WriteIntoReg) - write_nic_dword(dev, RCR, priv->ReceiveConfig); + rtl92e_writel(dev, RCR, priv->ReceiveConfig); } static u8 MRateToHwRate8190Pci(u8 rate) @@ -2122,11 +2122,11 @@ void rtl92e_stop_adapter(struct net_device *dev, bool reset) rtl92e_set_rf_off(dev); ulRegRead = rtl92e_readl(dev, CPU_GEN); ulRegRead |= CPU_GEN_SYSTEM_RESET; - write_nic_dword(dev, CPU_GEN, ulRegRead); + rtl92e_writel(dev, CPU_GEN, ulRegRead); } else { - write_nic_dword(dev, WFCRC0, 0xffffffff); - write_nic_dword(dev, WFCRC1, 0xffffffff); - write_nic_dword(dev, WFCRC2, 0xffffffff); + rtl92e_writel(dev, WFCRC0, 0xffffffff); + rtl92e_writel(dev, WFCRC1, 0xffffffff); + rtl92e_writel(dev, WFCRC2, 0xffffffff); rtl92e_writeb(dev, PMR, 0x5); @@ -2185,7 +2185,7 @@ void rtl92e_update_ratr_table(struct net_device *dev) else if (!ieee->pHTInfo->bCurTxBW40MHz && ieee->pHTInfo->bCurShortGI20MHz) ratr_value |= 0x80000000; - write_nic_dword(dev, RATR0+rate_index*4, ratr_value); + rtl92e_writel(dev, RATR0+rate_index*4, ratr_value); rtl92e_writeb(dev, UFWP, 1); } @@ -2230,7 +2230,7 @@ void rtl92e_enable_irq(struct net_device *dev) priv->irq_enabled = 1; - write_nic_dword(dev, INTA_MASK, priv->irq_mask[0]); + rtl92e_writel(dev, INTA_MASK, priv->irq_mask[0]); } @@ -2238,7 +2238,7 @@ void rtl92e_disable_irq(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - write_nic_dword(dev, INTA_MASK, 0); + rtl92e_writel(dev, INTA_MASK, 0); priv->irq_enabled = 0; } @@ -2248,7 +2248,7 @@ void rtl92e_clear_irq(struct net_device *dev) u32 tmp = 0; tmp = rtl92e_readl(dev, ISR); - write_nic_dword(dev, ISR, tmp); + rtl92e_writel(dev, ISR, tmp); } @@ -2256,7 +2256,7 @@ void rtl92e_enable_rx(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); - write_nic_dword(dev, RDQDA, priv->rx_ring_dma[RX_MPDU_QUEUE]); + rtl92e_writel(dev, RDQDA, priv->rx_ring_dma[RX_MPDU_QUEUE]); } static const u32 TX_DESC_BASE[] = { @@ -2269,14 +2269,14 @@ void rtl92e_enable_tx(struct net_device *dev) u32 i; for (i = 0; i < MAX_TX_QUEUE_COUNT; i++) - write_nic_dword(dev, TX_DESC_BASE[i], priv->tx_ring[i].dma); + rtl92e_writel(dev, TX_DESC_BASE[i], priv->tx_ring[i].dma); } void rtl92e_ack_irq(struct net_device *dev, u32 *p_inta, u32 *p_intb) { *p_inta = rtl92e_readl(dev, ISR); - write_nic_dword(dev, ISR, *p_inta); + rtl92e_writel(dev, ISR, *p_inta); } bool rtl92e_is_rx_stuck(struct net_device *dev) diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index d2868d76c52a..fde03472933c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -91,9 +91,9 @@ void rtl92e_set_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask, BitShift = rtl8192_CalculateBitShift(dwBitMask); NewValue = (((OriginalValue) & (~dwBitMask)) | (dwData << BitShift)); - write_nic_dword(dev, dwRegAddr, NewValue); + rtl92e_writel(dev, dwRegAddr, NewValue); } else - write_nic_dword(dev, dwRegAddr, dwData); + rtl92e_writel(dev, dwRegAddr, dwData); } u32 rtl92e_get_bb_reg(struct net_device *dev, u32 dwRegAddr, u32 dwBitMask) @@ -293,7 +293,7 @@ static u32 phy_FwRFSerialRead(struct net_device *dev, else break; } - write_nic_dword(dev, QPNR, Data); + rtl92e_writel(dev, QPNR, Data); while (rtl92e_readl(dev, QPNR) & 0x80000000) { if (time++ < 100) udelay(10); @@ -321,7 +321,7 @@ static void phy_FwRFSerialWrite(struct net_device *dev, else break; } - write_nic_dword(dev, QPNR, Data); + rtl92e_writel(dev, QPNR, Data); } @@ -512,8 +512,8 @@ bool rtl92e_check_bb_and_rf(struct net_device *dev, enum hw90_block CheckBlock, switch (CheckBlock) { case HW90_BLOCK_PHY0: case HW90_BLOCK_PHY1: - write_nic_dword(dev, WriteAddr[CheckBlock], - WriteData[i]); + rtl92e_writel(dev, WriteAddr[CheckBlock], + WriteData[i]); dwRegRead = rtl92e_readl(dev, WriteAddr[CheckBlock]); break; @@ -556,7 +556,7 @@ static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) rtl92e_writeb(dev, BB_GLOBAL_RESET, (bRegValue|BB_GLOBAL_RESET_BIT)); dwRegValue = rtl92e_readl(dev, CPU_GEN); - write_nic_dword(dev, CPU_GEN, (dwRegValue&(~CPU_GEN_BB_RST))); + rtl92e_writel(dev, CPU_GEN, (dwRegValue&(~CPU_GEN_BB_RST))); for (eCheckItem = (enum hw90_block)HW90_BLOCK_PHY0; eCheckItem <= HW90_BLOCK_PHY1; eCheckItem++) { @@ -574,7 +574,7 @@ static bool rtl8192_BB_Config_ParaFile(struct net_device *dev) rtl8192_phyConfigBB(dev, BaseBand_Config_PHY_REG); dwRegValue = rtl92e_readl(dev, CPU_GEN); - write_nic_dword(dev, CPU_GEN, (dwRegValue|CPU_GEN_BB_RST)); + rtl92e_writel(dev, CPU_GEN, (dwRegValue|CPU_GEN_BB_RST)); rtl8192_phyConfigBB(dev, BaseBand_Config_AGC_TAB); @@ -935,8 +935,8 @@ static u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, rtl8192_SetTxPowerLevel(dev, channel); break; case CmdID_WritePortUlong: - write_nic_dword(dev, CurrentCmd->Para1, - CurrentCmd->Para2); + rtl92e_writel(dev, CurrentCmd->Para1, + CurrentCmd->Para2); break; case CmdID_WritePortUshort: write_nic_word(dev, CurrentCmd->Para1, @@ -1202,9 +1202,9 @@ static void rtl8192_SetBWModeWorkItem(struct net_device *dev) rtl92e_set_bb_reg(dev, rFPGA1_RFMOD, bRFMOD, 0x0); if (!priv->btxpower_tracking) { - write_nic_dword(dev, rCCK0_TxFilter1, 0x1a1b0000); - write_nic_dword(dev, rCCK0_TxFilter2, 0x090e1317); - write_nic_dword(dev, rCCK0_DebugPort, 0x00000204); + rtl92e_writel(dev, rCCK0_TxFilter1, 0x1a1b0000); + rtl92e_writel(dev, rCCK0_TxFilter2, 0x090e1317); + rtl92e_writel(dev, rCCK0_DebugPort, 0x00000204); } else { CCK_Tx_Power_Track_BW_Switch(dev); } @@ -1217,9 +1217,9 @@ static void rtl8192_SetBWModeWorkItem(struct net_device *dev) rtl92e_set_bb_reg(dev, rFPGA1_RFMOD, bRFMOD, 0x1); if (!priv->btxpower_tracking) { - write_nic_dword(dev, rCCK0_TxFilter1, 0x35360000); - write_nic_dword(dev, rCCK0_TxFilter2, 0x121c252e); - write_nic_dword(dev, rCCK0_DebugPort, 0x00000409); + rtl92e_writel(dev, rCCK0_TxFilter1, 0x35360000); + rtl92e_writel(dev, rCCK0_TxFilter2, 0x121c252e); + rtl92e_writel(dev, rCCK0_DebugPort, 0x00000409); } else { CCK_Tx_Power_Track_BW_Switch(dev); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index cba71585a321..749b5ce1b7ed 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -33,7 +33,7 @@ void rtl92e_cam_reset(struct net_device *dev) u32 ulcommand = 0; ulcommand |= BIT31|BIT30; - write_nic_dword(dev, RWCAM, ulcommand); + rtl92e_writel(dev, RWCAM, ulcommand); } void rtl92e_enable_hw_security_config(struct net_device *dev) @@ -135,20 +135,20 @@ void rtl92e_set_key(struct net_device *dev, u8 EntryNo, u8 KeyIndex, (u32)(*(MacAddr+1)) << 24 | (u32)usConfig; - write_nic_dword(dev, WCAMI, TargetContent); - write_nic_dword(dev, RWCAM, TargetCommand); + rtl92e_writel(dev, WCAMI, TargetContent); + rtl92e_writel(dev, RWCAM, TargetCommand); } else if (i == 1) { TargetContent = (u32)(*(MacAddr+2)) | (u32)(*(MacAddr+3)) << 8 | (u32)(*(MacAddr+4)) << 16 | (u32)(*(MacAddr+5)) << 24; - write_nic_dword(dev, WCAMI, TargetContent); - write_nic_dword(dev, RWCAM, TargetCommand); + rtl92e_writel(dev, WCAMI, TargetContent); + rtl92e_writel(dev, RWCAM, TargetCommand); } else { if (KeyContent != NULL) { - write_nic_dword(dev, WCAMI, - (u32)(*(KeyContent+i-2))); - write_nic_dword(dev, RWCAM, TargetCommand); + rtl92e_writel(dev, WCAMI, + (u32)(*(KeyContent+i-2))); + rtl92e_writel(dev, RWCAM, TargetCommand); udelay(100); } } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 65d6418b24db..ef1ea4acc72a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -132,7 +132,7 @@ void rtl92e_writeb(struct net_device *dev, int x, u8 y) udelay(20); } -void write_nic_dword(struct net_device *dev, int x, u32 y) +void rtl92e_writel(struct net_device *dev, int x, u32 y) { writel(y, (u8 __iomem *)dev->mem_start + x); @@ -2194,8 +2194,8 @@ static void rtl8192_irq_rx_tasklet(struct r8192_priv *priv) { rtl8192_rx_normal(priv->rtllib->dev); - write_nic_dword(priv->rtllib->dev, INTA_MASK, - rtl92e_readl(priv->rtllib->dev, INTA_MASK) | IMR_RDU); + rtl92e_writel(priv->rtllib->dev, INTA_MASK, + rtl92e_readl(priv->rtllib->dev, INTA_MASK) | IMR_RDU); } /**************************************************************************** @@ -2526,8 +2526,8 @@ static irqreturn_t rtl8192_interrupt(int irq, void *netdev) if (inta & IMR_RDU) { RT_TRACE(COMP_INTR, "rx descriptor unavailable!\n"); priv->stats.rxrdu++; - write_nic_dword(dev, INTA_MASK, - rtl92e_readl(dev, INTA_MASK) & ~IMR_RDU); + rtl92e_writel(dev, INTA_MASK, + rtl92e_readl(dev, INTA_MASK) & ~IMR_RDU); tasklet_schedule(&priv->irq_rx_tasklet); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 21b6d01ee6a5..9792445405de 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -583,7 +583,7 @@ u32 rtl92e_readl(struct net_device *dev, int x); u16 rtl92e_readw(struct net_device *dev, int x); void rtl92e_writeb(struct net_device *dev, int x, u8 y); void write_nic_word(struct net_device *dev, int x, u16 y); -void write_nic_dword(struct net_device *dev, int x, u32 y); +void rtl92e_writel(struct net_device *dev, int x, u32 y); void force_pci_posting(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 1690f6f764ed..342777d6764a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -454,7 +454,7 @@ static void dm_check_rate_adaptive(struct net_device *dev) currentRATR, targetRATR); if (priv->rf_type == RF_1T2R) ratr_value &= ~(RATE_ALL_OFDM_2SS); - write_nic_dword(dev, RATR0, ratr_value); + rtl92e_writel(dev, RATR0, ratr_value); rtl92e_writeb(dev, UFWP, 1); pra->last_ratr = targetRATR; @@ -1211,7 +1211,7 @@ void dm_restore_dynamic_mechanism_state(struct net_device *dev) ratr_value = reg_ratr; if (priv->rf_type == RF_1T2R) ratr_value &= ~(RATE_ALL_OFDM_2SS); - write_nic_dword(dev, RATR0, ratr_value); + rtl92e_writel(dev, RATR0, ratr_value); rtl92e_writeb(dev, UFWP, 1); if (priv->btxpower_trackingInit && priv->btxpower_tracking) dm_txpower_reset_recovery(dev); @@ -1741,21 +1741,19 @@ static void dm_check_edca_turbo(struct net_device *dev) if (curTxOkCnt > 4*curRxOkCnt) { if (priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) { - write_nic_dword(dev, EDCAPARA_BE, - edca_setting_UL[pHTInfo->IOTPeer]); + rtl92e_writel(dev, EDCAPARA_BE, + edca_setting_UL[pHTInfo->IOTPeer]); priv->bis_cur_rdlstate = false; } } else { if (!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) { if (priv->rtllib->mode == WIRELESS_MODE_G) - write_nic_dword(dev, - EDCAPARA_BE, - edca_setting_DL_GMode[pHTInfo->IOTPeer]); + rtl92e_writel(dev, EDCAPARA_BE, + edca_setting_DL_GMode[pHTInfo->IOTPeer]); else - write_nic_dword(dev, - EDCAPARA_BE, - edca_setting_DL[pHTInfo->IOTPeer]); + rtl92e_writel(dev, EDCAPARA_BE, + edca_setting_DL[pHTInfo->IOTPeer]); priv->bis_cur_rdlstate = true; } } @@ -1765,20 +1763,18 @@ static void dm_check_edca_turbo(struct net_device *dev) if (!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) { if (priv->rtllib->mode == WIRELESS_MODE_G) - write_nic_dword(dev, - EDCAPARA_BE, - edca_setting_DL_GMode[pHTInfo->IOTPeer]); + rtl92e_writel(dev, EDCAPARA_BE, + edca_setting_DL_GMode[pHTInfo->IOTPeer]); else - write_nic_dword(dev, - EDCAPARA_BE, - edca_setting_DL[pHTInfo->IOTPeer]); + rtl92e_writel(dev, EDCAPARA_BE, + edca_setting_DL[pHTInfo->IOTPeer]); priv->bis_cur_rdlstate = true; } } else { if (priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) { - write_nic_dword(dev, EDCAPARA_BE, - edca_setting_UL[pHTInfo->IOTPeer]); + rtl92e_writel(dev, EDCAPARA_BE, + edca_setting_UL[pHTInfo->IOTPeer]); priv->bis_cur_rdlstate = false; } @@ -2283,7 +2279,7 @@ static void dm_fsync_timer_callback(unsigned long data) rtl92e_writeb(dev, 0xC3e, 0x96); } priv->ContinueDiffCount = 0; - write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); + rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd); } RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount); RT_TRACE(COMP_HALDM, @@ -2298,7 +2294,7 @@ static void dm_StartHWFsync(struct net_device *dev) struct r8192_priv *priv = rtllib_priv(dev); RT_TRACE(COMP_HALDM, "%s\n", __func__); - write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cf); + rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c12cf); priv->rtllib->SetHwRegHandler(dev, HW_VAR_RF_TIMING, (u8 *)(&rf_timing)); rtl92e_writeb(dev, 0xc3b, 0x41); @@ -2310,7 +2306,7 @@ static void dm_EndHWFsync(struct net_device *dev) struct r8192_priv *priv = rtllib_priv(dev); RT_TRACE(COMP_HALDM, "%s\n", __func__); - write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); + rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd); priv->rtllib->SetHwRegHandler(dev, HW_VAR_RF_TIMING, (u8 *) (&rf_timing)); rtl92e_writeb(dev, 0xc3b, 0x49); @@ -2332,7 +2328,7 @@ static void dm_EndSWFsync(struct net_device *dev) } priv->ContinueDiffCount = 0; - write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd); + rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c52cd); } static void dm_StartSWFsync(struct net_device *dev) @@ -2367,7 +2363,7 @@ static void dm_StartSWFsync(struct net_device *dev) msecs_to_jiffies(priv->rtllib->fsync_time_interval); add_timer(&priv->fsync_timer); - write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cd); + rtl92e_writel(dev, rOFDM0_RxDetector2, 0x465c12cd); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c index 3c87398b5b48..d4d489c35e93 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c @@ -48,11 +48,11 @@ int rtl8192E_suspend(struct pci_dev *pdev, pm_message_t state) rtl92e_set_rf_state(dev, eRfOff, RF_CHANGE_BY_INIT, true); ulRegRead = rtl92e_readl(dev, CPU_GEN); ulRegRead |= CPU_GEN_SYSTEM_RESET; - write_nic_dword(dev, CPU_GEN, ulRegRead); + rtl92e_writel(dev, CPU_GEN, ulRegRead); } else { - write_nic_dword(dev, WFCRC0, 0xffffffff); - write_nic_dword(dev, WFCRC1, 0xffffffff); - write_nic_dword(dev, WFCRC2, 0xffffffff); + rtl92e_writel(dev, WFCRC0, 0xffffffff); + rtl92e_writel(dev, WFCRC1, 0xffffffff); + rtl92e_writel(dev, WFCRC2, 0xffffffff); rtl92e_writeb(dev, PMR, 0x5); rtl92e_writeb(dev, MacBlkCtrl, 0xa); } -- cgit v1.3-6-gb490 From 6dee0c884a24074ad9de3150e6c527bb4a148277 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:28 +0200 Subject: staging: rtl8192e: Rename write_nic_word Use naming schema found in other rtlwifi devices. Rename write_nic_word to rtl92e_writew. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 36 +++++++++++++------------- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 4 +-- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 4 +-- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 896d2ab07f16..c7ffe9760c37 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -43,17 +43,17 @@ void rtl92e_start_beacon(struct net_device *dev) rtl92e_irq_disable(dev); - write_nic_word(dev, ATIMWND, 2); + rtl92e_writew(dev, ATIMWND, 2); - write_nic_word(dev, BCN_INTERVAL, net->beacon_interval); - write_nic_word(dev, BCN_DRV_EARLY_INT, 10); - write_nic_word(dev, BCN_DMATIME, 256); + rtl92e_writew(dev, BCN_INTERVAL, net->beacon_interval); + rtl92e_writew(dev, BCN_DRV_EARLY_INT, 10); + rtl92e_writew(dev, BCN_DMATIME, 256); rtl92e_writeb(dev, BCN_ERR_THRESH, 100); BcnTimeCfg |= BcnCW<ShortRetryLimit << RETRY_LIMIT_SHORT_SHIFT | - priv->LongRetryLimit << RETRY_LIMIT_LONG_SHIFT); + rtl92e_writew(dev, RETRY_LIMIT, + priv->ShortRetryLimit << RETRY_LIMIT_SHORT_SHIFT | + priv->LongRetryLimit << RETRY_LIMIT_LONG_SHIFT); } bool rtl92e_start_adapter(struct net_device *dev) @@ -779,7 +779,7 @@ start: rtl92e_writeb(dev, PCIF, ((MXDMA2_NoLimit<dev_addr)[0]); - write_nic_word(dev, MAC4, ((u16 *)(dev->dev_addr + 4))[0]); + rtl92e_writew(dev, MAC4, ((u16 *)(dev->dev_addr + 4))[0]); rtl92e_writel(dev, RCR, priv->ReceiveConfig); rtl92e_writel(dev, RQPN1, NUM_OF_PAGE_IN_FW_QUEUE_BK << @@ -818,8 +818,8 @@ start: SECR_value |= SCR_NoSKMC; rtl92e_writeb(dev, SECR, SECR_value); } - write_nic_word(dev, ATIMWND, 2); - write_nic_word(dev, BCN_INTERVAL, 100); + rtl92e_writew(dev, ATIMWND, 2); + rtl92e_writew(dev, BCN_INTERVAL, 100); { int i; @@ -972,19 +972,19 @@ static void rtl8192_net_update(struct net_device *dev) priv->dot11CurrentPreambleMode = PREAMBLE_AUTO; priv->basic_rate = rate_config &= 0x15f; rtl92e_writel(dev, BSSIDR, ((u32 *)net->bssid)[0]); - write_nic_word(dev, BSSIDR+4, ((u16 *)net->bssid)[2]); + rtl92e_writew(dev, BSSIDR+4, ((u16 *)net->bssid)[2]); if (priv->rtllib->iw_mode == IW_MODE_ADHOC) { - write_nic_word(dev, ATIMWND, 2); - write_nic_word(dev, BCN_DMATIME, 256); - write_nic_word(dev, BCN_INTERVAL, net->beacon_interval); - write_nic_word(dev, BCN_DRV_EARLY_INT, 10); + rtl92e_writew(dev, ATIMWND, 2); + rtl92e_writew(dev, BCN_DMATIME, 256); + rtl92e_writew(dev, BCN_INTERVAL, net->beacon_interval); + rtl92e_writew(dev, BCN_DRV_EARLY_INT, 10); rtl92e_writeb(dev, BCN_ERR_THRESH, 100); BcnTimeCfg |= (BcnCW<Para2); break; case CmdID_WritePortUshort: - write_nic_word(dev, CurrentCmd->Para1, - (u16)CurrentCmd->Para2); + rtl92e_writew(dev, CurrentCmd->Para1, + (u16)CurrentCmd->Para2); break; case CmdID_WritePortUchar: rtl92e_writeb(dev, CurrentCmd->Para1, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index ef1ea4acc72a..85def08be69a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -139,7 +139,7 @@ void rtl92e_writel(struct net_device *dev, int x, u32 y) udelay(20); } -void write_nic_word(struct net_device *dev, int x, u16 y) +void rtl92e_writew(struct net_device *dev, int x, u16 y) { writew(y, (u8 __iomem *)dev->mem_start + x); @@ -1837,7 +1837,7 @@ static short rtl8192_tx(struct net_device *dev, struct sk_buff *skb) spin_unlock_irqrestore(&priv->irq_th_lock, flags); dev->trans_start = jiffies; - write_nic_word(dev, TPPoll, 0x01 << tcb_desc->queue_index); + rtl92e_writew(dev, TPPoll, 0x01 << tcb_desc->queue_index); return 0; } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 9792445405de..4938be77c7b1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -582,7 +582,7 @@ u8 rtl92e_readb(struct net_device *dev, int x); u32 rtl92e_readl(struct net_device *dev, int x); u16 rtl92e_readw(struct net_device *dev, int x); void rtl92e_writeb(struct net_device *dev, int x, u8 y); -void write_nic_word(struct net_device *dev, int x, u16 y); +void rtl92e_writew(struct net_device *dev, int x, u16 y); void rtl92e_writel(struct net_device *dev, int x, u32 y); void force_pci_posting(struct net_device *dev); -- cgit v1.3-6-gb490 From fd9e3171844891b510adf125d820a91d212f359c Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:29 +0200 Subject: staging: rtl8192e: Rename deinit_hal_dm Use naming schema found in other rtlwifi devices. Rename deinit_hal_dm to rtl92e_dm_deinit. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 85def08be69a..8091f79337da 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1304,7 +1304,7 @@ RESET_START: rtl92e_irq_disable(dev); del_timer_sync(&priv->watch_dog_timer); rtl8192_cancel_deferred_work(priv); - deinit_hal_dm(dev); + rtl92e_dm_deinit(dev); rtllib_stop_scan_syncro(ieee); if (ieee->state == RTLLIB_LINKED) { @@ -2736,7 +2736,7 @@ static void rtl8192_pci_disconnect(struct pci_dev *pdev) cancel_delayed_work(&priv->gpio_change_rf_wq); priv->polling_timer_on = 0; rtl8192_down(dev, true); - deinit_hal_dm(dev); + rtl92e_dm_deinit(dev); if (priv->pFirmware) { vfree(priv->pFirmware); priv->pFirmware = NULL; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 342777d6764a..9d0b633dd7cd 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -249,7 +249,7 @@ void init_hal_dm(struct net_device *dev) (void *)dm_CheckRfCtrlGPIO, dev); } -void deinit_hal_dm(struct net_device *dev) +void rtl92e_dm_deinit(struct net_device *dev) { dm_deInit_fsync(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index 95b8a8fd0556..647a569d7787 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -189,7 +189,7 @@ extern const u8 dm_cck_tx_bb_gain_ch14[CCKTxBBGainTableLength][8]; /*--------------------------Exported Function prototype---------------------*/ extern void init_hal_dm(struct net_device *dev); -extern void deinit_hal_dm(struct net_device *dev); +extern void rtl92e_dm_deinit(struct net_device *dev); extern void hal_dm_watchdog(struct net_device *dev); -- cgit v1.3-6-gb490 From 090e8a4d99339f66971b9e2b3b13a62fa115b1d0 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:30 +0200 Subject: staging: rtl8192e: Rename dm_backup_dynamic_mechanism_state Use naming schema found in other rtlwifi devices. Rename dm_backup_dynamic_mechanism_state to rtl92e_dm_backup_state. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 8091f79337da..04fe6dcbf2de 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1321,7 +1321,7 @@ RESET_START: rtllib_softmac_stop_protocol(priv->rtllib, 0, true); } - dm_backup_dynamic_mechanism_state(dev); + rtl92e_dm_backup_state(dev); up(&priv->wx_sem); RT_TRACE(COMP_RESET, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 9d0b633dd7cd..848d6ee74962 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -1256,7 +1256,7 @@ static void dm_bb_initialgain_restore(struct net_device *dev) } -void dm_backup_dynamic_mechanism_state(struct net_device *dev) +void rtl92e_dm_backup_state(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index 647a569d7787..f138c90ccaa5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -200,7 +200,7 @@ extern void dm_txpower_trackingcallback(void *data); extern void dm_cck_txpower_adjust(struct net_device *dev, bool binch14); extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); -extern void dm_backup_dynamic_mechanism_state(struct net_device *dev); +extern void rtl92e_dm_backup_state(struct net_device *dev); extern void dm_init_edca_turbo(struct net_device *dev); extern void dm_rf_pathcheck_workitemcallback(void *data); extern void dm_initialize_txpower_tracking(struct net_device *dev); -- cgit v1.3-6-gb490 From 59e84dc363bfaa675db8da94113d3250170ebb70 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:31 +0200 Subject: staging: rtl8192e: Rename dm_cck_txpower_adjust Use naming schema found in other rtlwifi devices. Rename dm_cck_txpower_adjust to rtl92e_dm_cck_txpower_adjust. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 14 +++++++------- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 12 ++++++------ drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 674c529df4a4..7acae7d49c91 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -1076,13 +1076,13 @@ static void CCK_Tx_Power_Track_BW_Switch_TSSI(struct net_device *dev) if (priv->rtllib->current_network.channel == 14 && !priv->bcck_in_ch14) { priv->bcck_in_ch14 = true; - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); } else if (priv->rtllib->current_network.channel != 14 && priv->bcck_in_ch14) { priv->bcck_in_ch14 = false; - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); } else { - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); } break; @@ -1104,13 +1104,13 @@ static void CCK_Tx_Power_Track_BW_Switch_TSSI(struct net_device *dev) if (priv->rtllib->current_network.channel == 14 && !priv->bcck_in_ch14) { priv->bcck_in_ch14 = true; - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); } else if (priv->rtllib->current_network.channel != 14 && priv->bcck_in_ch14) { priv->bcck_in_ch14 = false; - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); } else { - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); } break; } @@ -1144,7 +1144,7 @@ static void CCK_Tx_Power_Track_BW_Switch_ThermalMeter(struct net_device *dev) priv->CCK_index); break; } - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); } static void CCK_Tx_Power_Track_BW_Switch(struct net_device *dev) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 848d6ee74962..c947b62a1732 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -802,12 +802,12 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev) if (priv->rtllib->current_network.channel == 14 && !priv->bcck_in_ch14) { priv->bcck_in_ch14 = true; - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); } else if (priv->rtllib->current_network.channel != 14 && priv->bcck_in_ch14) { priv->bcck_in_ch14 = false; - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); } else - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); } RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", @@ -935,7 +935,7 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev) } if (CCKSwingNeedUpdate) - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); if (priv->OFDM_index[0] != tmpOFDMindex) { priv->OFDM_index[0] = tmpOFDMindex; rtl92e_set_bb_reg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, @@ -1149,7 +1149,7 @@ static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, } } -void dm_cck_txpower_adjust(struct net_device *dev, bool binch14) +void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14) { struct r8192_priv *priv = rtllib_priv(dev); @@ -1177,7 +1177,7 @@ static void dm_txpower_reset_recovery(struct net_device *dev) RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: CCK Attenuation is %d dB\n", priv->CCKPresentAttentuation); - dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); + rtl92e_dm_cck_txpower_adjust(dev, priv->bcck_in_ch14); rtl92e_set_bb_reg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, dm_tx_bb_gain[priv->rfc_txpowertrackingindex]); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index f138c90ccaa5..f7e74825c716 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -197,7 +197,7 @@ extern void hal_dm_watchdog(struct net_device *dev); extern void init_rate_adaptive(struct net_device *dev); extern void dm_txpower_trackingcallback(void *data); -extern void dm_cck_txpower_adjust(struct net_device *dev, bool binch14); +extern void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14); extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); extern void rtl92e_dm_backup_state(struct net_device *dev); -- cgit v1.3-6-gb490 From 7842c2d58d4dc8b5e96d87aa61d619bd6f094ca7 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:32 +0200 Subject: staging: rtl8192e: Rename dm_init_edca_turbo Use naming schema found in other rtlwifi devices. Rename dm_init_edca_turbo to rtl92e_dm_init_edca_turbo. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index c7ffe9760c37..8a8a1fd06503 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -193,7 +193,7 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val) u1bAIFS = qop->aifs[pAcParam] * ((mode&(IEEE_G|IEEE_N_24G)) ? 9 : 20) + aSifsTime; - dm_init_edca_turbo(dev); + rtl92e_dm_init_edca_turbo(dev); u4bAcParam = (le16_to_cpu(qop->tx_op_limit[pAcParam]) << AC_PARAM_TXOP_LIMIT_OFFSET) | diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 04fe6dcbf2de..ae8a82066f32 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -525,7 +525,7 @@ static int rtl8192_qos_association_resp(struct r8192_priv *priv, RT_TRACE(COMP_QOS, "%s: network->flags = %d,%d\n", __func__, network->flags, priv->rtllib->current_network.qos_data.active); if (set_qos_param == 1) { - dm_init_edca_turbo(priv->rtllib->dev); + rtl92e_dm_init_edca_turbo(priv->rtllib->dev); queue_work_rsl(priv->priv_wq, &priv->qos_activate); } return 0; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index c947b62a1732..28e0d1f5fdc2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -237,7 +237,7 @@ void init_hal_dm(struct net_device *dev) init_rate_adaptive(dev); dm_dig_init(dev); - dm_init_edca_turbo(dev); + rtl92e_dm_init_edca_turbo(dev); dm_init_bandwidth_autoswitch(dev); dm_init_fsync(dev); dm_init_rxpath_selection(dev); @@ -1692,7 +1692,7 @@ static void dm_cs_ratio(struct net_device *dev) } } -void dm_init_edca_turbo(struct net_device *dev) +void rtl92e_dm_init_edca_turbo(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index f7e74825c716..132b6dd6a942 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -201,7 +201,7 @@ extern void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14); extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); extern void rtl92e_dm_backup_state(struct net_device *dev); -extern void dm_init_edca_turbo(struct net_device *dev); +extern void rtl92e_dm_init_edca_turbo(struct net_device *dev); extern void dm_rf_pathcheck_workitemcallback(void *data); extern void dm_initialize_txpower_tracking(struct net_device *dev); #endif /*__R8192UDM_H__ */ -- cgit v1.3-6-gb490 From 5a9f18cfeda0b73d2fafdab6eb1c4457ddd34b76 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:33 +0200 Subject: staging: rtl8192e: Rename dm_initialize_txpower_tracking Use naming schema found in other rtlwifi devices. Rename dm_initialize_txpower_tracking to rtl92e_dm_init_txpower_tracking. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 8a8a1fd06503..f72b0654c7d7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -907,7 +907,7 @@ start: priv->Rf_Mode = RF_OP_By_SW_3wire; if (priv->ResetProgress == RESET_TYPE_NORESET) { - dm_initialize_txpower_tracking(dev); + rtl92e_dm_init_txpower_tracking(dev); if (priv->IC_Cut >= IC_VersionCut_D) { tmpRegA = rtl92e_get_bb_reg(dev, rOFDM0_XATxIQImbalance, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 28e0d1f5fdc2..c96ab6ee1a14 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -985,7 +985,7 @@ static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev) priv->btxpower_tracking); } -void dm_initialize_txpower_tracking(struct net_device *dev) +void rtl92e_dm_init_txpower_tracking(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index 132b6dd6a942..0b9f0852dce7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -203,5 +203,5 @@ extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); extern void rtl92e_dm_backup_state(struct net_device *dev); extern void rtl92e_dm_init_edca_turbo(struct net_device *dev); extern void dm_rf_pathcheck_workitemcallback(void *data); -extern void dm_initialize_txpower_tracking(struct net_device *dev); +extern void rtl92e_dm_init_txpower_tracking(struct net_device *dev); #endif /*__R8192UDM_H__ */ -- cgit v1.3-6-gb490 From 25c01ec36eafb4096edaae0607b0dc7e4762cb38 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:34 +0200 Subject: staging: rtl8192e: Rename dm_restore_dynamic_mechanism_state Use naming schema found in other rtlwifi devices. Rename dm_restore_dynamic_mechanism_state to rtl92e_dm_restore_state. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index ae8a82066f32..bdbd4bef606e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1377,7 +1377,7 @@ RESET_START: } rtl92e_cam_restore(dev); - dm_restore_dynamic_mechanism_state(dev); + rtl92e_dm_restore_state(dev); END: priv->ResetProgress = RESET_TYPE_NORESET; priv->reset_count++; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index c96ab6ee1a14..fbbeca11a7d3 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -1191,7 +1191,7 @@ static void dm_txpower_reset_recovery(struct net_device *dev) dm_tx_bb_gain_idx_to_amplify(priv->rfc_txpowertrackingindex)); } -void dm_restore_dynamic_mechanism_state(struct net_device *dev) +void rtl92e_dm_restore_state(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); u32 reg_ratr = priv->rate_adaptive.last_ratr; @@ -1199,7 +1199,7 @@ void dm_restore_dynamic_mechanism_state(struct net_device *dev) if (!priv->up) { RT_TRACE(COMP_RATE, - "<---- dm_restore_dynamic_mechanism_state(): driver is going to unload\n"); + "<---- rtl92e_dm_restore_state(): driver is going to unload\n"); return; } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index 0b9f0852dce7..7904a11acab5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -199,7 +199,7 @@ extern void dm_txpower_trackingcallback(void *data); extern void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14); -extern void dm_restore_dynamic_mechanism_state(struct net_device *dev); +extern void rtl92e_dm_restore_state(struct net_device *dev); extern void rtl92e_dm_backup_state(struct net_device *dev); extern void rtl92e_dm_init_edca_turbo(struct net_device *dev); extern void dm_rf_pathcheck_workitemcallback(void *data); -- cgit v1.3-6-gb490 From 3cd4db70c6f8748c868dac83bad49426d5e31486 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:35 +0200 Subject: staging: rtl8192e: Rename dm_rf_pathcheck_workitemcallback Use naming schema found in other rtlwifi devices. Rename dm_rf_pathcheck_workitemcallback to rtl92e_dm_rf_pathcheck_wq. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index bdbd4bef606e..43b5e90fa12a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1029,7 +1029,7 @@ static void rtl8192_init_priv_task(struct net_device *dev) INIT_DELAYED_WORK_RSL(&priv->txpower_tracking_wq, (void *)dm_txpower_trackingcallback, dev); INIT_DELAYED_WORK_RSL(&priv->rfpath_check_wq, - (void *)dm_rf_pathcheck_workitemcallback, dev); + (void *)rtl92e_dm_rf_pathcheck_wq, dev); INIT_DELAYED_WORK_RSL(&priv->update_beacon_wq, (void *)rtl8192_update_beacon, dev); INIT_WORK_RSL(&priv->qos_activate, (void *)rtl8192_qos_activate, dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index fbbeca11a7d3..04887324bfa1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -1901,7 +1901,7 @@ static void dm_CheckRfCtrlGPIO(void *data) } } -void dm_rf_pathcheck_workitemcallback(void *data) +void rtl92e_dm_rf_pathcheck_wq(void *data) { struct r8192_priv *priv = container_of_dwork_rsl(data, struct r8192_priv, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index 7904a11acab5..0184cdf51fe7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -202,6 +202,6 @@ extern void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14); extern void rtl92e_dm_restore_state(struct net_device *dev); extern void rtl92e_dm_backup_state(struct net_device *dev); extern void rtl92e_dm_init_edca_turbo(struct net_device *dev); -extern void dm_rf_pathcheck_workitemcallback(void *data); +extern void rtl92e_dm_rf_pathcheck_wq(void *data); extern void rtl92e_dm_init_txpower_tracking(struct net_device *dev); #endif /*__R8192UDM_H__ */ -- cgit v1.3-6-gb490 From 33059f5435ea4a172dc61c8f09c09ee06e5f14d7 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:36 +0200 Subject: staging: rtl8192e: Rename dm_txpower_trackingcallback Use naming schema found in other rtlwifi devices. Rename dm_txpower_trackingcallback to rtl92e_dm_txpower_tracking_wq. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 43b5e90fa12a..9dc05caef4a7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1027,7 +1027,7 @@ static void rtl8192_init_priv_task(struct net_device *dev) INIT_DELAYED_WORK_RSL(&priv->watch_dog_wq, (void *)rtl819x_watchdog_wqcallback, dev); INIT_DELAYED_WORK_RSL(&priv->txpower_tracking_wq, - (void *)dm_txpower_trackingcallback, dev); + (void *)rtl92e_dm_txpower_tracking_wq, dev); INIT_DELAYED_WORK_RSL(&priv->rfpath_check_wq, (void *)rtl92e_dm_rf_pathcheck_wq, dev); INIT_DELAYED_WORK_RSL(&priv->update_beacon_wq, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 04887324bfa1..c79f8ab1f2c8 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -947,7 +947,7 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev) priv->txpower_count = 0; } -void dm_txpower_trackingcallback(void *data) +void rtl92e_dm_txpower_tracking_wq(void *data) { struct r8192_priv *priv = container_of_dwork_rsl(data, struct r8192_priv, txpower_tracking_wq); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index 0184cdf51fe7..1fa0ff88896a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -195,7 +195,7 @@ extern void hal_dm_watchdog(struct net_device *dev); extern void init_rate_adaptive(struct net_device *dev); -extern void dm_txpower_trackingcallback(void *data); +extern void rtl92e_dm_txpower_tracking_wq(void *data); extern void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14); -- cgit v1.3-6-gb490 From 8e1e64bb66c5236153255a4ec2de77f21569c537 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:37 +0200 Subject: staging: rtl8192e: Rename hal_dm_watchdog Use naming schema found in other rtlwifi devices. Rename hal_dm_watchdog to rtl92e_dm_watchdog. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 9dc05caef4a7..2214e6d353c1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1438,7 +1438,7 @@ static void rtl819x_watchdog_wqcallback(void *data) priv->rtllib->CntAfterLink = 0; } - hal_dm_watchdog(dev); + rtl92e_dm_watchdog(dev); if (rtllib_act_scanning(priv->rtllib, false) == false) { if ((ieee->iw_mode == IW_MODE_INFRA) && (ieee->state == diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index c79f8ab1f2c8..564b17c05d91 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -256,7 +256,7 @@ void rtl92e_dm_deinit(struct net_device *dev) } -void hal_dm_watchdog(struct net_device *dev) +void rtl92e_dm_watchdog(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index 1fa0ff88896a..7147886e830f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -191,7 +191,7 @@ extern const u8 dm_cck_tx_bb_gain_ch14[CCKTxBBGainTableLength][8]; extern void init_hal_dm(struct net_device *dev); extern void rtl92e_dm_deinit(struct net_device *dev); -extern void hal_dm_watchdog(struct net_device *dev); +extern void rtl92e_dm_watchdog(struct net_device *dev); extern void init_rate_adaptive(struct net_device *dev); -- cgit v1.3-6-gb490 From 2e3ba83a4996721b44c9cb2bcebad4e12d072416 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:38 +0200 Subject: staging: rtl8192e: Rename init_rate_adaptive Use naming schema found in other rtlwifi devices. Rename init_rate_adaptive to rtl92e_init_adaptive_rate. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index f72b0654c7d7..6f1dcd3fe054 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -560,7 +560,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) RT_TRACE(COMP_INIT, "\n2T4R config\n"); } - init_rate_adaptive(dev); + rtl92e_init_adaptive_rate(dev); priv->rf_chip = RF_8256; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 564b17c05d91..b60003518d69 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -234,7 +234,7 @@ void init_hal_dm(struct net_device *dev) dm_init_dynamic_txpower(dev); - init_rate_adaptive(dev); + rtl92e_init_adaptive_rate(dev); dm_dig_init(dev); rtl92e_dm_init_edca_turbo(dev); @@ -307,7 +307,7 @@ static void dm_check_ac_dc_power(struct net_device *dev) }; -void init_rate_adaptive(struct net_device *dev) +void rtl92e_init_adaptive_rate(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index 7147886e830f..e7a2dcf1785a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -194,7 +194,7 @@ extern void rtl92e_dm_deinit(struct net_device *dev); extern void rtl92e_dm_watchdog(struct net_device *dev); -extern void init_rate_adaptive(struct net_device *dev); +extern void rtl92e_init_adaptive_rate(struct net_device *dev); extern void rtl92e_dm_txpower_tracking_wq(void *data); extern void rtl92e_dm_cck_txpower_adjust(struct net_device *dev, bool binch14); -- cgit v1.3-6-gb490 From 68cb7b7a5918114cf9712d2bb5dc8aad7300dd58 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:39 +0200 Subject: staging: rtl8192e: Rename eprom_read Use naming schema found in other rtlwifi devices. Rename eprom_read to rtl92e_eeprom_read. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 26 ++++++++++++++------------ drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 6f1dcd3fe054..e347facda94f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -323,7 +323,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) RT_TRACE(COMP_INIT, "====> rtl8192_read_eeprom_info\n"); - EEPROMId = eprom_read(dev, 0); + EEPROMId = rtl92e_eeprom_read(dev, 0); if (EEPROMId != RTL8190_EEPROM_ID) { netdev_err(dev, "%s(): Invalid EEPROM ID: %x\n", __func__, EEPROMId); @@ -333,12 +333,14 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) } if (!priv->AutoloadFailFlag) { - priv->eeprom_vid = eprom_read(dev, EEPROM_VID >> 1); - priv->eeprom_did = eprom_read(dev, EEPROM_DID >> 1); + priv->eeprom_vid = rtl92e_eeprom_read(dev, EEPROM_VID >> 1); + priv->eeprom_did = rtl92e_eeprom_read(dev, EEPROM_DID >> 1); - usValue = eprom_read(dev, (u16)(EEPROM_Customer_ID>>1)) >> 8; + usValue = rtl92e_eeprom_read(dev, + (u16)(EEPROM_Customer_ID>>1)) >> 8; priv->eeprom_CustomerID = (u8)(usValue & 0xff); - usValue = eprom_read(dev, EEPROM_ICVersion_ChannelPlan>>1); + usValue = rtl92e_eeprom_read(dev, + EEPROM_ICVersion_ChannelPlan>>1); priv->eeprom_ChannelPlan = usValue&0xff; IC_Version = (usValue & 0xff00)>>8; @@ -376,7 +378,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (!priv->AutoloadFailFlag) { for (i = 0; i < 6; i += 2) { - usValue = eprom_read(dev, + usValue = rtl92e_eeprom_read(dev, (u16)((EEPROM_NODE_ADDRESS_BYTE_0 + i) >> 1)); *(u16 *)(&dev->dev_addr[i]) = usValue; } @@ -396,8 +398,8 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (priv->card_8192_version > VERSION_8190_BD) { if (!priv->AutoloadFailFlag) { - tempval = (eprom_read(dev, (EEPROM_RFInd_PowerDiff >> - 1))) & 0xff; + tempval = (rtl92e_eeprom_read(dev, + (EEPROM_RFInd_PowerDiff >> 1))) & 0xff; priv->EEPROMLegacyHTTxPowerDiff = tempval & 0xf; if (tempval&0x80) @@ -411,7 +413,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) priv->EEPROMLegacyHTTxPowerDiff); if (!priv->AutoloadFailFlag) - priv->EEPROMThermalMeter = (u8)(((eprom_read(dev, + priv->EEPROMThermalMeter = (u8)(((rtl92e_eeprom_read(dev, (EEPROM_ThermalMeter>>1))) & 0xff00)>>8); else @@ -422,7 +424,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) if (priv->epromtype == EEPROM_93C46) { if (!priv->AutoloadFailFlag) { - usValue = eprom_read(dev, + usValue = rtl92e_eeprom_read(dev, EEPROM_TxPwDiff_CrystalCap >> 1); priv->EEPROMAntPwDiff = (usValue&0x0fff); priv->EEPROMCrystalCap = (u8)((usValue & 0xf000) @@ -440,7 +442,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) for (i = 0; i < 14; i += 2) { if (!priv->AutoloadFailFlag) - usValue = eprom_read(dev, + usValue = rtl92e_eeprom_read(dev, (u16)((EEPROM_TxPwIndex_CCK + i) >> 1)); else @@ -456,7 +458,7 @@ static void rtl8192_read_eeprom_info(struct net_device *dev) } for (i = 0; i < 14; i += 2) { if (!priv->AutoloadFailFlag) - usValue = eprom_read(dev, + usValue = rtl92e_eeprom_read(dev, (u16)((EEPROM_TxPwIndex_OFDM_24G + i) >> 1)); else diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c index f58534609691..ed54193b019a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c @@ -87,7 +87,7 @@ static void eprom_send_bits_string(struct net_device *dev, short b[], int len) } } -u32 eprom_read(struct net_device *dev, u32 addr) +u32 rtl92e_eeprom_read(struct net_device *dev, u32 addr) { struct r8192_priv *priv = rtllib_priv(dev); short read_cmd[] = {1, 1, 0}; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h index adea2b4c7a44..8d23aea5fb4f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.h @@ -26,4 +26,4 @@ #define EPROM_DELAY 10 -u32 eprom_read(struct net_device *dev, u32 addr); +u32 rtl92e_eeprom_read(struct net_device *dev, u32 addr); -- cgit v1.3-6-gb490 From e250592ed93a12eecc42ed590f5a8245a20ab994 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:40 +0200 Subject: staging: rtl8192e: Rename rtl8192_pci_findadapter Use naming schema found in other rtlwifi devices. Rename rtl8192_pci_findadapter to rtl92e_check_adapter. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_pci.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_pci.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 2214e6d353c1..06f8d84f9112 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2670,7 +2670,7 @@ static int rtl8192_pci_probe(struct pci_dev *pdev, priv->ops = ops; - if (rtl8192_pci_findadapter(pdev, dev) == false) + if (rtl92e_check_adapter(pdev, dev) == false) goto err_rel_mem; dev->irq = pdev->irq; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c index 6bbd1c626e24..9fcb099e6edd 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.c @@ -45,7 +45,7 @@ static void rtl8192_parse_pci_configuration(struct pci_dev *pdev, pci_write_config_byte(pdev, 0x70f, tmp); } -bool rtl8192_pci_findadapter(struct pci_dev *pdev, struct net_device *dev) +bool rtl92e_check_adapter(struct pci_dev *pdev, struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); u16 VenderID; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h index e8d5527a5f04..6246841bde15 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h @@ -29,6 +29,6 @@ #include struct net_device; -bool rtl8192_pci_findadapter(struct pci_dev *pdev, struct net_device *dev); +bool rtl92e_check_adapter(struct pci_dev *pdev, struct net_device *dev); #endif -- cgit v1.3-6-gb490 From 0ba6623df9e2d349586b592b809e26b12d3da416 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:41 +0200 Subject: staging: rtl8192e: Rename rtl8192E_resume Use naming schema found in other rtlwifi devices. Rename rtl8192E_resume to rtl92e_resume. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_pm.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_pm.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 06f8d84f9112..1e3d646c0f39 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -84,7 +84,7 @@ static struct pci_driver rtl8192_pci_driver = { .probe = rtl8192_pci_probe, /* probe fn */ .remove = rtl8192_pci_disconnect, /* remove fn */ .suspend = rtl8192E_suspend, /* PM suspend fn */ - .resume = rtl8192E_resume, /* PM resume fn */ + .resume = rtl92e_resume, /* PM resume fn */ }; static short rtl8192_is_tx_queue_empty(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c index d4d489c35e93..52b3617a4b02 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c @@ -70,7 +70,7 @@ out_pci_suspend: return 0; } -int rtl8192E_resume(struct pci_dev *pdev) +int rtl92e_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h index 7bfe44817f23..90ca080c07fd 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h @@ -24,6 +24,6 @@ #include int rtl8192E_suspend(struct pci_dev *dev, pm_message_t state); -int rtl8192E_resume(struct pci_dev *dev); +int rtl92e_resume(struct pci_dev *dev); #endif -- cgit v1.3-6-gb490 From 3683dc1f08f81ce69d5f405bf78c55775996dcf4 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:42 +0200 Subject: staging: rtl8192e: Rename rtl8192E_suspend Use naming schema found in other rtlwifi devices. Rename rtl8192E_suspend to rtl92e_suspend. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_pm.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_pm.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 1e3d646c0f39..c1af8adda20c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -83,7 +83,7 @@ static struct pci_driver rtl8192_pci_driver = { .id_table = rtl8192_pci_id_tbl, /* PCI_ID table */ .probe = rtl8192_pci_probe, /* probe fn */ .remove = rtl8192_pci_disconnect, /* remove fn */ - .suspend = rtl8192E_suspend, /* PM suspend fn */ + .suspend = rtl92e_suspend, /* PM suspend fn */ .resume = rtl92e_resume, /* PM resume fn */ }; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c index 52b3617a4b02..c224adedaf62 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c @@ -23,7 +23,7 @@ #include "rtl_pm.h" -int rtl8192E_suspend(struct pci_dev *pdev, pm_message_t state) +int rtl92e_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h index 90ca080c07fd..cdc45f7fb339 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h @@ -23,7 +23,7 @@ #include #include -int rtl8192E_suspend(struct pci_dev *dev, pm_message_t state); +int rtl92e_suspend(struct pci_dev *dev, pm_message_t state); int rtl92e_resume(struct pci_dev *dev); #endif -- cgit v1.3-6-gb490 From 410d6fc983a61dec4a514b3426e8368b2fd3fd17 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:28:43 +0200 Subject: staging: rtl8192e: Rename IPSEnter Use naming schema found in other rtlwifi devices. Rename IPSEnter to rtl92e_ips_enter. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 4 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index c1af8adda20c..34b1db2b2217 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1449,8 +1449,8 @@ static void rtl819x_watchdog_wqcallback(void *data) IPS_CALLBACK_NONE) && (!ieee->bNetPromiscuousMode)) { RT_TRACE(COMP_PS, - "====================>haha: IPSEnter()\n"); - IPSEnter(dev); + "====================>haha: rtl92e_ips_enter()\n"); + rtl92e_ips_enter(dev); } } } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index fc4503f2a82e..5b0dbe76ea78 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -140,7 +140,7 @@ static void InactivePsWorkItemCallback(struct net_device *dev) RT_TRACE(COMP_PS, "InactivePsWorkItemCallback() <---------\n"); } -void IPSEnter(struct net_device *dev) +void rtl92e_ips_enter(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) @@ -152,7 +152,7 @@ void IPSEnter(struct net_device *dev) if (rtState == eRfOn && !pPSC->bSwRfProcessing && (priv->rtllib->state != RTLLIB_LINKED) && (priv->rtllib->iw_mode != IW_MODE_MASTER)) { - RT_TRACE(COMP_PS, "IPSEnter(): Turn off RF.\n"); + RT_TRACE(COMP_PS, "rtl92e_ips_enter(): Turn off RF.\n"); pPSC->eInactivePowerState = eRfOff; priv->isRFOff = true; priv->bInPowerSaveMode = true; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index d23c0f1d76f5..e29c57f53a18 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -37,7 +37,7 @@ void rtllib_ips_leave_wq(struct net_device *dev); void rtllib_ips_leave(struct net_device *dev); void IPSLeave_wq(void *data); -void IPSEnter(struct net_device *dev); +void rtl92e_ips_enter(struct net_device *dev); void IPSLeave(struct net_device *dev); void LeisurePSEnter(struct net_device *dev); -- cgit v1.3-6-gb490 From 2ab2aba29e1d28ecb1a211f3edbce6d65e92e05c Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:47 +0200 Subject: staging: rtl8192e: Rename IPSLeave Use naming schema found in other rtlwifi devices. Rename IPSLeave to rtl92e_ips_leave. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 10 +++++----- drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 14 ++++++++------ 4 files changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index 749b5ce1b7ed..dc8c7a86bf93 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -108,7 +108,7 @@ void rtl92e_set_key(struct net_device *dev, u8 EntryNo, u8 KeyIndex, return; } down(&priv->rtllib->ips_sem); - IPSLeave(dev); + rtl92e_ips_leave(dev); up(&priv->rtllib->ips_sem); } } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index 5b0dbe76ea78..bf93bf80977f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -161,7 +161,7 @@ void rtl92e_ips_enter(struct net_device *dev) } } -void IPSLeave(struct net_device *dev) +void rtl92e_ips_leave(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) @@ -172,7 +172,7 @@ void IPSLeave(struct net_device *dev) rtState = priv->rtllib->eRFPowerState; if (rtState != eRfOn && !pPSC->bSwRfProcessing && priv->rtllib->RfOffReason <= RF_CHANGE_BY_IPS) { - RT_TRACE(COMP_PS, "IPSLeave(): Turn on RF.\n"); + RT_TRACE(COMP_PS, "rtl92e_ips_leave(): Turn on RF.\n"); pPSC->eInactivePowerState = eRfOn; priv->bInPowerSaveMode = false; InactivePsWorkItemCallback(dev); @@ -188,7 +188,7 @@ void IPSLeave_wq(void *data) struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); down(&priv->rtllib->ips_sem); - IPSLeave(dev); + rtl92e_ips_leave(dev); up(&priv->rtllib->ips_sem); } @@ -206,7 +206,7 @@ void rtllib_ips_leave_wq(struct net_device *dev) __func__); return; } - netdev_info(dev, "=========>%s(): IPSLeave\n", + netdev_info(dev, "=========>%s(): rtl92e_ips_leave\n", __func__); queue_work_rsl(priv->rtllib->wq, &priv->rtllib->ips_leave_wq); @@ -219,7 +219,7 @@ void rtllib_ips_leave(struct net_device *dev) struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); down(&priv->rtllib->ips_sem); - IPSLeave(dev); + rtl92e_ips_leave(dev); up(&priv->rtllib->ips_sem); } diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index e29c57f53a18..b1b480ffa59f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -38,7 +38,7 @@ void rtllib_ips_leave(struct net_device *dev); void IPSLeave_wq(void *data); void rtl92e_ips_enter(struct net_device *dev); -void IPSLeave(struct net_device *dev); +void rtl92e_ips_leave(struct net_device *dev); void LeisurePSEnter(struct net_device *dev); void LeisurePSLeave(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index ebed99b3d637..dc2d7ecd7d6a 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -282,10 +282,11 @@ static int r8192_wx_set_mode(struct net_device *dev, struct iw_request_info *a, up(&priv->wx_sem); return -1; } - netdev_info(dev, "=========>%s(): IPSLeave\n", + netdev_info(dev, + "=========>%s(): rtl92e_ips_leave\n", __func__); down(&priv->rtllib->ips_sem); - IPSLeave(dev); + rtl92e_ips_leave(dev); up(&priv->rtllib->ips_sem); } } @@ -442,10 +443,11 @@ static int r8192_wx_set_scan(struct net_device *dev, struct iw_request_info *a, up(&priv->wx_sem); return -1; } - RT_TRACE(COMP_PS, "=========>%s(): IPSLeave\n", + RT_TRACE(COMP_PS, + "=========>%s(): rtl92e_ips_leave\n", __func__); down(&priv->rtllib->ips_sem); - IPSLeave(dev); + rtl92e_ips_leave(dev); up(&priv->rtllib->ips_sem); } } @@ -700,7 +702,7 @@ static int r8192_wx_set_enc(struct net_device *dev, priv->rtllib->wx_set_enc = 1; down(&priv->rtllib->ips_sem); - IPSLeave(dev); + rtl92e_ips_leave(dev); up(&priv->rtllib->ips_sem); down(&priv->wx_sem); @@ -910,7 +912,7 @@ static int r8192_wx_set_enc_ext(struct net_device *dev, priv->rtllib->wx_set_enc = 1; down(&priv->rtllib->ips_sem); - IPSLeave(dev); + rtl92e_ips_leave(dev); up(&priv->rtllib->ips_sem); ret = rtllib_wx_set_encode_ext(ieee, info, wrqu, extra); -- cgit v1.3-6-gb490 From a514c798ee57d82d8332b0315dba00c6e4cb0c3e Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:48 +0200 Subject: staging: rtl8192e: Rename IPSLeave_wq Use naming schema found in other rtlwifi devices. Rename IPSLeave_wq to rtl92e_ips_leave_wq. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 3 ++- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 34b1db2b2217..f89e7be71fa2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1023,7 +1023,8 @@ static void rtl8192_init_priv_task(struct net_device *dev) priv->priv_wq = create_workqueue(DRV_NAME); INIT_WORK_RSL(&priv->reset_wq, (void *)rtl8192_restart, dev); - INIT_WORK_RSL(&priv->rtllib->ips_leave_wq, (void *)IPSLeave_wq, dev); + INIT_WORK_RSL(&priv->rtllib->ips_leave_wq, (void *)rtl92e_ips_leave_wq, + dev); INIT_DELAYED_WORK_RSL(&priv->watch_dog_wq, (void *)rtl819x_watchdog_wqcallback, dev); INIT_DELAYED_WORK_RSL(&priv->txpower_tracking_wq, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index bf93bf80977f..bc86df356933 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -180,7 +180,7 @@ void rtl92e_ips_leave(struct net_device *dev) } } -void IPSLeave_wq(void *data) +void rtl92e_ips_leave_wq(void *data) { struct rtllib_device *ieee = container_of_work_rsl(data, struct rtllib_device, ips_leave_wq); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index b1b480ffa59f..eae0c8637bb2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -35,7 +35,7 @@ void rtl8192_hw_wakeup(struct net_device *dev); void rtl8192_hw_to_sleep(struct net_device *dev, u64 time); void rtllib_ips_leave_wq(struct net_device *dev); void rtllib_ips_leave(struct net_device *dev); -void IPSLeave_wq(void *data); +void rtl92e_ips_leave_wq(void *data); void rtl92e_ips_enter(struct net_device *dev); void rtl92e_ips_leave(struct net_device *dev); -- cgit v1.3-6-gb490 From 04197ef2bdfbb334de18a5d5f105acb71eef1db5 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:49 +0200 Subject: staging: rtl8192e: Rename LeisurePSEnter Use naming schema found in other rtlwifi devices. Rename LeisurePSEnter to rtl92e_leisure_ps_enter. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 6 +++--- drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index f89e7be71fa2..bf41950117f1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1482,7 +1482,7 @@ static void rtl819x_watchdog_wqcallback(void *data) bEnterPS = false; if (bEnterPS) - LeisurePSEnter(dev); + rtl92e_leisure_ps_enter(dev); else LeisurePSLeave(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index bc86df356933..232e4fa488ce 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -251,13 +251,13 @@ static bool MgntActSet_802_11_PowerSaveMode(struct net_device *dev, return true; } -void LeisurePSEnter(struct net_device *dev) +void rtl92e_leisure_ps_enter(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) &(priv->rtllib->PowerSaveControl); - RT_TRACE(COMP_PS, "LeisurePSEnter()...\n"); + RT_TRACE(COMP_PS, "rtl92e_leisure_ps_enter()...\n"); RT_TRACE(COMP_PS, "pPSC->bLeisurePs = %d, ieee->ps = %d,pPSC->LpsIdleCount is %d,RT_CHECK_FOR_HANG_PERIOD is %d\n", pPSC->bLeisurePs, priv->rtllib->ps, pPSC->LpsIdleCount, @@ -275,7 +275,7 @@ void LeisurePSEnter(struct net_device *dev) if (priv->rtllib->ps == RTLLIB_PS_DISABLED) { RT_TRACE(COMP_LPS, - "LeisurePSEnter(): Enter 802.11 power save mode...\n"); + "rtl92e_leisure_ps_enter(): Enter 802.11 power save mode...\n"); if (!pPSC->bFwCtrlLPS) { if (priv->rtllib->SetFwCmdHandler) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index eae0c8637bb2..dd4ca28c84be 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -40,7 +40,7 @@ void rtl92e_ips_leave_wq(void *data); void rtl92e_ips_enter(struct net_device *dev); void rtl92e_ips_leave(struct net_device *dev); -void LeisurePSEnter(struct net_device *dev); +void rtl92e_leisure_ps_enter(struct net_device *dev); void LeisurePSLeave(struct net_device *dev); #endif -- cgit v1.3-6-gb490 From 9c4a55d1dac3cd17aad9944f1647e2ade5a6345f Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:50 +0200 Subject: staging: rtl8192e: Rename LeisurePSLeave Use naming schema found in other rtlwifi devices. Rename LeisurePSLeave to rtl92e_leisure_ps_leave. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 10 +++++----- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 6 +++--- drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index bf41950117f1..f5dcd026c7d4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -811,7 +811,7 @@ static int rtl8192_sta_down(struct net_device *dev, bool shutdownrf) priv->rtllib->rtllib_ips_leave(dev); if (priv->rtllib->state == RTLLIB_LINKED) - LeisurePSLeave(dev); + rtl92e_leisure_ps_leave(dev); priv->bDriverIsGoingToUnload = true; priv->up = 0; @@ -875,7 +875,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->handle_assoc_response = rtl8192_handle_assoc_response; priv->rtllib->handle_beacon = rtl8192_handle_beacon; priv->rtllib->SetWirelessMode = rtl92e_set_wireless_mode; - priv->rtllib->LeisurePSLeave = LeisurePSLeave; + priv->rtllib->LeisurePSLeave = rtl92e_leisure_ps_leave; priv->rtllib->SetBWModeHandler = rtl92e_set_bw_mode; priv->rf_set_chan = rtl92e_set_channel; @@ -1282,7 +1282,7 @@ RESET_START: down(&priv->wx_sem); if (priv->rtllib->state == RTLLIB_LINKED) - LeisurePSLeave(dev); + rtl92e_leisure_ps_leave(dev); if (priv->up) { netdev_info(dev, "%s():the driver is not up.\n", @@ -1484,11 +1484,11 @@ static void rtl819x_watchdog_wqcallback(void *data) if (bEnterPS) rtl92e_leisure_ps_enter(dev); else - LeisurePSLeave(dev); + rtl92e_leisure_ps_leave(dev); } else { RT_TRACE(COMP_LPS, "====>no link LPS leave\n"); - LeisurePSLeave(dev); + rtl92e_leisure_ps_leave(dev); } ieee->LinkDetectInfo.NumRxOkInPeriod = 0; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index 232e4fa488ce..cd117f549387 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -291,21 +291,21 @@ void rtl92e_leisure_ps_enter(struct net_device *dev) } } -void LeisurePSLeave(struct net_device *dev) +void rtl92e_leisure_ps_leave(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *) &(priv->rtllib->PowerSaveControl); - RT_TRACE(COMP_PS, "LeisurePSLeave()...\n"); + RT_TRACE(COMP_PS, "rtl92e_leisure_ps_leave()...\n"); RT_TRACE(COMP_PS, "pPSC->bLeisurePs = %d, ieee->ps = %d\n", pPSC->bLeisurePs, priv->rtllib->ps); if (pPSC->bLeisurePs) { if (priv->rtllib->ps != RTLLIB_PS_DISABLED) { RT_TRACE(COMP_LPS, - "LeisurePSLeave(): Busy Traffic , Leave 802.11 power save..\n"); + "rtl92e_leisure_ps_leave(): Busy Traffic , Leave 802.11 power save..\n"); MgntActSet_802_11_PowerSaveMode(dev, RTLLIB_PS_DISABLED); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index dd4ca28c84be..250d5245e5c5 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -41,6 +41,6 @@ void rtl92e_ips_enter(struct net_device *dev); void rtl92e_ips_leave(struct net_device *dev); void rtl92e_leisure_ps_enter(struct net_device *dev); -void LeisurePSLeave(struct net_device *dev); +void rtl92e_leisure_ps_leave(struct net_device *dev); #endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index dc2d7ecd7d6a..183d1b2e64f1 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -192,7 +192,7 @@ static int r8192_wx_adapter_power_status(struct net_device *dev, pPSC->bLeisurePs = true; } else { if (priv->rtllib->state == RTLLIB_LINKED) - LeisurePSLeave(dev); + rtl92e_leisure_ps_leave(dev); priv->ps_force = true; pPSC->bLeisurePs = false; -- cgit v1.3-6-gb490 From bcdcc1ea06be6851c5dfd885e9ac3b1388bbd36b Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:51 +0200 Subject: staging: rtl8192e: Rename rtl8192_hw_sleep_wq Use naming schema found in other rtlwifi devices. Rename rtl8192_hw_sleep_wq to rtl92e_hw_sleep_wq. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index f5dcd026c7d4..5fc2103a0352 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1037,7 +1037,7 @@ static void rtl8192_init_priv_task(struct net_device *dev) INIT_DELAYED_WORK_RSL(&priv->rtllib->hw_wakeup_wq, (void *) rtl8192_hw_wakeup_wq, dev); INIT_DELAYED_WORK_RSL(&priv->rtllib->hw_sleep_wq, - (void *) rtl8192_hw_sleep_wq, dev); + (void *) rtl92e_hw_sleep_wq, dev); tasklet_init(&priv->irq_rx_tasklet, (void(*)(unsigned long))rtl8192_irq_rx_tasklet, (unsigned long)priv); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 4938be77c7b1..397e93c3e224 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -590,7 +590,7 @@ void force_pci_posting(struct net_device *dev); void rtl92e_rx_enable(struct net_device *); void rtl92e_tx_enable(struct net_device *); -void rtl8192_hw_sleep_wq(void *data); +void rtl92e_hw_sleep_wq(void *data); void rtl92e_commit(struct net_device *dev); void rtl92e_check_rfctrl_gpio_timer(unsigned long data); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index cd117f549387..6bdd0f2ff741 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -48,7 +48,7 @@ static void rtl8192_hw_sleep_down(struct net_device *dev) rtl92e_set_rf_state(dev, eRfSleep, RF_CHANGE_BY_PS, false); } -void rtl8192_hw_sleep_wq(void *data) +void rtl92e_hw_sleep_wq(void *data) { struct rtllib_device *ieee = container_of_dwork_rsl(data, struct rtllib_device, hw_sleep_wq); -- cgit v1.3-6-gb490 From feb257e5f9982821dcafe7f190d810a418cd2076 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:52 +0200 Subject: staging: rtl8192e: Rename rtl8192_hw_to_sleep Use naming schema found in other rtlwifi devices. Rename rtl8192_hw_to_sleep to rtl92e_enter_sleep. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 5fc2103a0352..ca18640009a9 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -883,7 +883,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->stop_send_beacons = rtl8192_stop_beacon; priv->rtllib->sta_wake_up = rtl8192_hw_wakeup; - priv->rtllib->enter_sleep_state = rtl8192_hw_to_sleep; + priv->rtllib->enter_sleep_state = rtl92e_enter_sleep; priv->rtllib->ps_is_queue_empty = rtl8192_is_tx_queue_empty; priv->rtllib->GetNmodeSupportBySecCfg = rtl92e_get_nmode_support_by_sec; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index 6bdd0f2ff741..327b2b83ed3c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -88,7 +88,7 @@ void rtl8192_hw_wakeup_wq(void *data) #define MIN_SLEEP_TIME 50 #define MAX_SLEEP_TIME 10000 -void rtl8192_hw_to_sleep(struct net_device *dev, u64 time) +void rtl92e_enter_sleep(struct net_device *dev, u64 time) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index 250d5245e5c5..a962e7f5833c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -32,7 +32,7 @@ struct net_device; #define RT_CHECK_FOR_HANG_PERIOD 2 void rtl8192_hw_wakeup(struct net_device *dev); -void rtl8192_hw_to_sleep(struct net_device *dev, u64 time); +void rtl92e_enter_sleep(struct net_device *dev, u64 time); void rtllib_ips_leave_wq(struct net_device *dev); void rtllib_ips_leave(struct net_device *dev); void rtl92e_ips_leave_wq(void *data); -- cgit v1.3-6-gb490 From 43bcb3b4c78585a9cd7741b49e272fae989074ba Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:53 +0200 Subject: staging: rtl8192e: Rename rtl8192_hw_wakeup Use naming schema found in other rtlwifi devices. Rename rtl8192_hw_wakeup to rtl92e_hw_wakeup. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 8 ++++---- drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index ca18640009a9..0dc401e5e3dd 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -882,7 +882,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->start_send_beacons = rtl92e_start_beacon; priv->rtllib->stop_send_beacons = rtl8192_stop_beacon; - priv->rtllib->sta_wake_up = rtl8192_hw_wakeup; + priv->rtllib->sta_wake_up = rtl92e_hw_wakeup; priv->rtllib->enter_sleep_state = rtl92e_enter_sleep; priv->rtllib->ps_is_queue_empty = rtl8192_is_tx_queue_empty; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index 327b2b83ed3c..6ea7e7acd6a9 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -57,7 +57,7 @@ void rtl92e_hw_sleep_wq(void *data) rtl8192_hw_sleep_down(dev); } -void rtl8192_hw_wakeup(struct net_device *dev) +void rtl92e_hw_wakeup(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); unsigned long flags = 0; @@ -66,7 +66,7 @@ void rtl8192_hw_wakeup(struct net_device *dev) if (priv->RFChangeInProgress) { spin_unlock_irqrestore(&priv->rf_ps_lock, flags); RT_TRACE(COMP_DBG, - "rtl8192_hw_wakeup(): RF Change in progress!\n"); + "rtl92e_hw_wakeup(): RF Change in progress!\n"); queue_delayed_work_rsl(priv->rtllib->wq, &priv->rtllib->hw_wakeup_wq, msecs_to_jiffies(10)); @@ -83,7 +83,7 @@ void rtl8192_hw_wakeup_wq(void *data) struct rtllib_device, hw_wakeup_wq); struct net_device *dev = ieee->dev; - rtl8192_hw_wakeup(dev); + rtl92e_hw_wakeup(dev); } #define MIN_SLEEP_TIME 50 @@ -238,7 +238,7 @@ static bool MgntActSet_802_11_PowerSaveMode(struct net_device *dev, rtPsMode == RTLLIB_PS_DISABLED) { unsigned long flags; - rtl8192_hw_wakeup(dev); + rtl92e_hw_wakeup(dev); priv->rtllib->sta_sleep = LPS_IS_WAKE; spin_lock_irqsave(&(priv->rtllib->mgmt_tx_lock), flags); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index a962e7f5833c..1a8d1bfa3745 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -31,7 +31,7 @@ struct net_device; #define RT_CHECK_FOR_HANG_PERIOD 2 -void rtl8192_hw_wakeup(struct net_device *dev); +void rtl92e_hw_wakeup(struct net_device *dev); void rtl92e_enter_sleep(struct net_device *dev, u64 time); void rtllib_ips_leave_wq(struct net_device *dev); void rtllib_ips_leave(struct net_device *dev); -- cgit v1.3-6-gb490 From c34b29f7c8dcaabc42eae8b4ce81a8ec82d9d1f9 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:54 +0200 Subject: staging: rtl8192e: Rename rtl8192_hw_wakeup_wq Use naming schema found in other rtlwifi devices. Rename rtl8192_hw_wakeup_wq to rtl92e_hw_wakeup_wq. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 0dc401e5e3dd..d8729071d5de 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1035,7 +1035,7 @@ static void rtl8192_init_priv_task(struct net_device *dev) (void *)rtl8192_update_beacon, dev); INIT_WORK_RSL(&priv->qos_activate, (void *)rtl8192_qos_activate, dev); INIT_DELAYED_WORK_RSL(&priv->rtllib->hw_wakeup_wq, - (void *) rtl8192_hw_wakeup_wq, dev); + (void *) rtl92e_hw_wakeup_wq, dev); INIT_DELAYED_WORK_RSL(&priv->rtllib->hw_sleep_wq, (void *) rtl92e_hw_sleep_wq, dev); tasklet_init(&priv->irq_rx_tasklet, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 397e93c3e224..20df4e20edf2 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -595,7 +595,7 @@ void rtl92e_commit(struct net_device *dev); void rtl92e_check_rfctrl_gpio_timer(unsigned long data); -void rtl8192_hw_wakeup_wq(void *data); +void rtl92e_hw_wakeup_wq(void *data); void rtl92e_reset_desc_ring(struct net_device *dev); void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index 6ea7e7acd6a9..be5961d7c1ab 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -77,7 +77,7 @@ void rtl92e_hw_wakeup(struct net_device *dev) rtl92e_set_rf_state(dev, eRfOn, RF_CHANGE_BY_PS, false); } -void rtl8192_hw_wakeup_wq(void *data) +void rtl92e_hw_wakeup_wq(void *data) { struct rtllib_device *ieee = container_of_dwork_rsl(data, struct rtllib_device, hw_wakeup_wq); -- cgit v1.3-6-gb490 From bf135a16c5babbf51674431c7c7f73761c846f43 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:55 +0200 Subject: staging: rtl8192e: Rename rtllib_ips_leave Use naming schema found in other rtlwifi devices. Rename rtllib_ips_leave to rtl92e_rtllib_ips_leave. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index d8729071d5de..d5dbf4f5c7be 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -895,7 +895,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->SetFwCmdHandler = NULL; priv->rtllib->InitialGainHandler = rtl92e_init_gain; priv->rtllib->rtllib_ips_leave_wq = rtllib_ips_leave_wq; - priv->rtllib->rtllib_ips_leave = rtllib_ips_leave; + priv->rtllib->rtllib_ips_leave = rtl92e_rtllib_ips_leave; priv->rtllib->LedControlHandler = NULL; priv->rtllib->UpdateBeaconInterruptHandler = NULL; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index be5961d7c1ab..3dff7dbad259 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -214,7 +214,7 @@ void rtllib_ips_leave_wq(struct net_device *dev) } } -void rtllib_ips_leave(struct net_device *dev) +void rtl92e_rtllib_ips_leave(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index 1a8d1bfa3745..f789af79be21 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -34,7 +34,7 @@ struct net_device; void rtl92e_hw_wakeup(struct net_device *dev); void rtl92e_enter_sleep(struct net_device *dev, u64 time); void rtllib_ips_leave_wq(struct net_device *dev); -void rtllib_ips_leave(struct net_device *dev); +void rtl92e_rtllib_ips_leave(struct net_device *dev); void rtl92e_ips_leave_wq(void *data); void rtl92e_ips_enter(struct net_device *dev); -- cgit v1.3-6-gb490 From d66e938e1b5b40dc0d9f8f47d66f737e386b44ee Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:56 +0200 Subject: staging: rtl8192e: Rename rtllib_ips_leave_wq Use naming schema found in other rtlwifi devices. Rename rtllib_ips_leave_wq to rtl92e_rtllib_ips_leave_wq. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index d5dbf4f5c7be..1a7b6c7c2a0e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -894,7 +894,7 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->AllowAllDestAddrHandler = rtl92e_set_monitor_mode; priv->rtllib->SetFwCmdHandler = NULL; priv->rtllib->InitialGainHandler = rtl92e_init_gain; - priv->rtllib->rtllib_ips_leave_wq = rtllib_ips_leave_wq; + priv->rtllib->rtllib_ips_leave_wq = rtl92e_rtllib_ips_leave_wq; priv->rtllib->rtllib_ips_leave = rtl92e_rtllib_ips_leave; priv->rtllib->LedControlHandler = NULL; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index 3dff7dbad259..38addad24f18 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -192,7 +192,7 @@ void rtl92e_ips_leave_wq(void *data) up(&priv->rtllib->ips_sem); } -void rtllib_ips_leave_wq(struct net_device *dev) +void rtl92e_rtllib_ips_leave_wq(struct net_device *dev) { struct r8192_priv *priv = (struct r8192_priv *)rtllib_priv(dev); enum rt_rf_power_state rtState; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h index f789af79be21..35fc9e2a3365 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.h @@ -33,7 +33,7 @@ struct net_device; void rtl92e_hw_wakeup(struct net_device *dev); void rtl92e_enter_sleep(struct net_device *dev, u64 time); -void rtllib_ips_leave_wq(struct net_device *dev); +void rtl92e_rtllib_ips_leave_wq(struct net_device *dev); void rtl92e_rtllib_ips_leave(struct net_device *dev); void rtl92e_ips_leave_wq(void *data); -- cgit v1.3-6-gb490 From b8216b690d52f3cde4ab94c05f8772d0acdab57d Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:57 +0200 Subject: staging: rtl8192e: Rename init_firmware Use naming schema found in other rtlwifi devices. Rename init_firmware to rtl92e_init_fw. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c | 2 +- drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index e347facda94f..1013101309e8 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -852,7 +852,7 @@ start: } RT_TRACE(COMP_INIT, "Load Firmware!\n"); - bfirmwareok = init_firmware(dev); + bfirmwareok = rtl92e_init_fw(dev); if (!bfirmwareok) { if (retry_times < 10) { retry_times++; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c index 37e5c1403a7e..5c527c419bc9 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c @@ -223,7 +223,7 @@ static bool firmware_check_ready(struct net_device *dev, return rt_status; } -bool init_firmware(struct net_device *dev) +bool rtl92e_init_fw(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); bool rt_status = true; diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h index 131ea005edff..4c464eaee69f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h @@ -59,7 +59,7 @@ struct rt_firmware { u16 firmware_buf_size[MAX_FW_INIT_STEP]; }; -bool init_firmware(struct net_device *dev); +bool rtl92e_init_fw(struct net_device *dev); extern void rtl92e_init_fw_param(struct net_device *dev); #endif -- cgit v1.3-6-gb490 From ab7435982254d26cbc9af225065e0a6a94566269 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Sun, 19 Jul 2015 19:33:58 +0200 Subject: staging: rtl8192e: Rename init_hal_dm Use naming schema found in other rtlwifi devices. Rename init_hal_dm to rtl92e_dm_init. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 2 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 1a7b6c7c2a0e..f0e175def6a4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -1093,7 +1093,7 @@ static short rtl8192_init(struct net_device *dev) priv->ops->init_adapter_variable(dev); rtl8192_get_channel_map(dev); - init_hal_dm(dev); + rtl92e_dm_init(dev); setup_timer(&priv->watch_dog_timer, watch_dog_timer_callback, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index b60003518d69..458097ee09e7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -224,7 +224,7 @@ static void dm_send_rssi_tofw(struct net_device *dev); static void dm_ctstoself(struct net_device *dev); /*---------------------------Define function prototype------------------------*/ -void init_hal_dm(struct net_device *dev) +void rtl92e_dm_init(struct net_device *dev) { struct r8192_priv *priv = rtllib_priv(dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h index e7a2dcf1785a..e16502d12cdc 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.h @@ -188,7 +188,7 @@ extern const u8 dm_cck_tx_bb_gain_ch14[CCKTxBBGainTableLength][8]; /*--------------------------Exported Function prototype---------------------*/ /*--------------------------Exported Function prototype---------------------*/ -extern void init_hal_dm(struct net_device *dev); +extern void rtl92e_dm_init(struct net_device *dev); extern void rtl92e_dm_deinit(struct net_device *dev); extern void rtl92e_dm_watchdog(struct net_device *dev); -- cgit v1.3-6-gb490 From bc222ef4f79fa0003ef5a0af8090372e3bd8a783 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Jun 2015 15:45:41 +0200 Subject: pinctrl: nomadik: break out state container allocator Break out the function that allocates the nomadik GPIO chip state container to its own function. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 106 ++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 56e79c12562e..ceed731d4a2d 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -203,6 +203,7 @@ typedef unsigned long pin_cfg_t; #define GPIO_BLOCK_SHIFT 5 #define NMK_GPIO_PER_CHIP (1 << GPIO_BLOCK_SHIFT) +#define NMK_MAX_BANKS DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP) /* Register in the logic block */ #define NMK_GPIO_DAT 0x00 @@ -282,8 +283,7 @@ struct nmk_pinctrl { void __iomem *prcm_base; }; -static struct nmk_gpio_chip * -nmk_gpio_chips[DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP)]; +static struct nmk_gpio_chip *nmk_gpio_chips[NMK_MAX_BANKS]; static DEFINE_SPINLOCK(nmk_gpio_slpm_lock); @@ -1160,29 +1160,90 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up) } } +/* + * We will allocate memory for the state container using devm* allocators + * binding to the first device reaching this point, it doesn't matter if + * it is the pin controller or GPIO driver. However we need to use the right + * platform device when looking up resources so pay attention to pdev. + */ +static struct nmk_gpio_chip *nmk_gpio_populate_chip(struct device_node *np, + struct platform_device *pdev) +{ + struct nmk_gpio_chip *nmk_chip; + struct platform_device *gpio_pdev; + struct gpio_chip *chip; + struct resource *res; + struct clk *clk; + void __iomem *base; + u32 id; + + gpio_pdev = of_find_device_by_node(np); + if (!gpio_pdev) { + pr_err("populate \"%s\": device not found\n", np->name); + return ERR_PTR(-ENODEV); + } + if (of_property_read_u32(np, "gpio-bank", &id)) { + dev_err(&pdev->dev, "populate: gpio-bank property not found\n"); + return ERR_PTR(-EINVAL); + } + + /* Already populated? */ + nmk_chip = nmk_gpio_chips[id]; + if (nmk_chip) + return nmk_chip; + + nmk_chip = devm_kzalloc(&pdev->dev, sizeof(*nmk_chip), GFP_KERNEL); + if (!nmk_chip) + return ERR_PTR(-ENOMEM); + + nmk_chip->bank = id; + chip = &nmk_chip->chip; + chip->base = id * NMK_GPIO_PER_CHIP; + chip->ngpio = NMK_GPIO_PER_CHIP; + chip->label = dev_name(&gpio_pdev->dev); + chip->dev = &gpio_pdev->dev; + + res = platform_get_resource(gpio_pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return base; + nmk_chip->addr = base; + + clk = clk_get(&gpio_pdev->dev, NULL); + if (IS_ERR(clk)) + return (void *) clk; + clk_prepare(clk); + nmk_chip->clk = clk; + + BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips)); + nmk_gpio_chips[id] = nmk_chip; + return nmk_chip; +} + static int nmk_gpio_probe(struct platform_device *dev) { struct device_node *np = dev->dev.of_node; struct nmk_gpio_chip *nmk_chip; struct gpio_chip *chip; struct irq_chip *irqchip; - struct resource *res; - struct clk *clk; int latent_irq; bool supports_sleepmode; - void __iomem *base; int irq; int ret; + nmk_chip = nmk_gpio_populate_chip(np, dev); + if (IS_ERR(nmk_chip)) { + dev_err(&dev->dev, "could not populate nmk chip struct\n"); + return PTR_ERR(nmk_chip); + } + if (of_get_property(np, "st,supports-sleepmode", NULL)) supports_sleepmode = true; else supports_sleepmode = false; - if (of_property_read_u32(np, "gpio-bank", &dev->id)) { - dev_err(&dev->dev, "gpio-bank property not found\n"); - return -EINVAL; - } + /* Correct platform device ID */ + dev->id = nmk_chip->bank; irq = platform_get_irq(dev, 0); if (irq < 0) @@ -1191,27 +1252,10 @@ static int nmk_gpio_probe(struct platform_device *dev) /* It's OK for this IRQ not to be present */ latent_irq = platform_get_irq(dev, 1); - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&dev->dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - clk = devm_clk_get(&dev->dev, NULL); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clk_prepare(clk); - - nmk_chip = devm_kzalloc(&dev->dev, sizeof(*nmk_chip), GFP_KERNEL); - if (!nmk_chip) - return -ENOMEM; - /* * The virt address in nmk_chip->addr is in the nomadik register space, * so we can simply convert the resource address, without remapping */ - nmk_chip->bank = dev->id; - nmk_chip->clk = clk; - nmk_chip->addr = base; nmk_chip->parent_irq = irq; nmk_chip->latent_parent_irq = latent_irq; nmk_chip->sleepmode = supports_sleepmode; @@ -1226,10 +1270,6 @@ static int nmk_gpio_probe(struct platform_device *dev) chip->set = nmk_gpio_set_output; chip->dbg_show = nmk_gpio_dbg_show; chip->can_sleep = false; - chip->base = dev->id * NMK_GPIO_PER_CHIP; - chip->ngpio = NMK_GPIO_PER_CHIP; - chip->label = dev_name(&dev->dev); - chip->dev = &dev->dev; chip->owner = THIS_MODULE; irqchip = &nmk_chip->irqchip; @@ -1251,14 +1291,10 @@ static int nmk_gpio_probe(struct platform_device *dev) clk_disable(nmk_chip->clk); chip->of_node = np; - ret = gpiochip_add(&nmk_chip->chip); + ret = gpiochip_add(chip); if (ret) return ret; - BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips)); - - nmk_gpio_chips[nmk_chip->bank] = nmk_chip; - platform_set_drvdata(dev, nmk_chip); /* -- cgit v1.3-6-gb490 From 6ca7d2e352545132923bfdfcd17a4ceee80f5ce9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Jun 2015 16:05:47 +0200 Subject: pinctrl: nomadik: find chip from local array Instead of indexing around the GPIO ranges to find a chip, look directly in the local array of state containers for nmk_gpio_chip:s. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 64 +++++++++++++------------------ 1 file changed, 26 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index ceed731d4a2d..7b1160def285 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -1354,35 +1354,40 @@ static int nmk_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, return 0; } -static struct pinctrl_gpio_range * -nmk_match_gpio_range(struct pinctrl_dev *pctldev, unsigned offset) +static struct nmk_gpio_chip *find_nmk_gpio_from_pin(unsigned pin) { - struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); int i; + struct nmk_gpio_chip *nmk_gpio; - for (i = 0; i < npct->soc->gpio_num_ranges; i++) { - struct pinctrl_gpio_range *range; - - range = &npct->soc->gpio_ranges[i]; - if (offset >= range->pin_base && - offset <= (range->pin_base + range->npins - 1)) - return range; + for(i = 0; i < NMK_MAX_BANKS; i++) { + nmk_gpio = nmk_gpio_chips[i]; + if (!nmk_gpio) + continue; + if (pin >= nmk_gpio->chip.base && + pin < nmk_gpio->chip.base + nmk_gpio->chip.ngpio) + return nmk_gpio; } return NULL; } +static struct gpio_chip *find_gc_from_pin(unsigned pin) +{ + struct nmk_gpio_chip *nmk_gpio = find_nmk_gpio_from_pin(pin); + + if (nmk_gpio) + return &nmk_gpio->chip; + return NULL; +} + static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset) { - struct pinctrl_gpio_range *range; - struct gpio_chip *chip; + struct gpio_chip *chip = find_gc_from_pin(offset); - range = nmk_match_gpio_range(pctldev, offset); - if (!range || !range->gc) { + if (!chip) { seq_printf(s, "invalid pin offset"); return; } - chip = range->gc; nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset); } @@ -1727,25 +1732,16 @@ static int nmk_pmx_set(struct pinctrl_dev *pctldev, unsigned function, } for (i = 0; i < g->npins; i++) { - struct pinctrl_gpio_range *range; struct nmk_gpio_chip *nmk_chip; - struct gpio_chip *chip; unsigned bit; - range = nmk_match_gpio_range(pctldev, g->pins[i]); - if (!range) { + nmk_chip = find_nmk_gpio_from_pin(g->pins[i]); + if (!nmk_chip) { dev_err(npct->dev, "invalid pin offset %d in group %s at index %d\n", g->pins[i], g->name, i); goto out_glitch; } - if (!range->gc) { - dev_err(npct->dev, "GPIO chip missing in range for pin offset %d in group %s at index %d\n", - g->pins[i], g->name, i); - goto out_glitch; - } - chip = range->gc; - nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); dev_dbg(npct->dev, "setting pin %d to altsetting %d\n", g->pins[i], g->altsetting); clk_enable(nmk_chip->clk); @@ -1861,25 +1857,17 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, }; struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); struct nmk_gpio_chip *nmk_chip; - struct pinctrl_gpio_range *range; - struct gpio_chip *chip; unsigned bit; pin_cfg_t cfg; int pull, slpm, output, val, i; bool lowemi, gpiomode, sleep; - range = nmk_match_gpio_range(pctldev, pin); - if (!range) { - dev_err(npct->dev, "invalid pin offset %d\n", pin); + nmk_chip = find_nmk_gpio_from_pin(pin); + if (!nmk_chip) { + dev_err(npct->dev, + "invalid pin offset %d\n", pin); return -EINVAL; } - if (!range->gc) { - dev_err(npct->dev, "GPIO chip missing in range for pin %d\n", - pin); - return -EINVAL; - } - chip = range->gc; - nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); for (i = 0; i < num_configs; i++) { /* -- cgit v1.3-6-gb490 From ab4a936247561cd998913bab5f15e3d3eaed1f9e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Jun 2015 23:10:21 +0200 Subject: pinctrl: nomadik: assure GPIO chips are populated If the pin controller probes before the GPIO driver it needs to populate the GPIO driver state containers ahead of the actual driver probe as the addresses are used by both halves of the driver. Signed-off-by: Linus Walleij --- .../devicetree/bindings/pinctrl/ste,nomadik.txt | 7 ++++-- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 25 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt b/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt index f63fcb3ed352..2213802435e0 100644 --- a/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt +++ b/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt @@ -3,7 +3,9 @@ ST Ericsson Nomadik pinmux controller Required properties: - compatible: "stericsson,db8500-pinctrl", "stericsson,db8540-pinctrl", "stericsson,stn8815-pinctrl" -- reg: Should contain the register physical address and length of the PRCMU. +- nomadik-gpio-chips: array of phandles to the corresponding GPIO chips + (these have the register ranges used by the pin controller). +- prcm: phandle to the PRCMU managing the back end of this pin controller Please refer to pinctrl-bindings.txt in this directory for details of the common pinctrl bindings used by client devices, including the meaning of the @@ -74,7 +76,8 @@ Example board file extract: pinctrl@80157000 { compatible = "stericsson,db8500-pinctrl"; - reg = <0x80157000 0x2000>; + nomadik-gpio-chips = <&gpio0>, <&gpio1>, <&gpio2>, <&gpio3>; + prcm = <&prcmu>; pinctrl-names = "default"; diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 7b1160def285..143d1c06078c 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -2019,6 +2019,31 @@ static int nmk_pinctrl_probe(struct platform_device *pdev) if (version == PINCTRL_NMK_DB8540) nmk_pinctrl_db8540_init(&npct->soc); + /* + * Since we depend on the GPIO chips to provide clock and register base + * for the pin control operations, make sure that we have these + * populated before we continue. Follow the phandles to instantiate + * them. The GPIO portion of the actual hardware may be probed before + * or after this point: it shouldn't matter as the APIs are orthogonal. + */ + for (i = 0; i < NMK_MAX_BANKS; i++) { + struct device_node *gpio_np; + struct nmk_gpio_chip *nmk_chip; + + gpio_np = of_parse_phandle(np, "nomadik-gpio-chips", i); + if (gpio_np) { + dev_info(&pdev->dev, + "populate NMK GPIO %d \"%s\"\n", + i, gpio_np->name); + nmk_chip = nmk_gpio_populate_chip(gpio_np, pdev); + if (IS_ERR(nmk_chip)) + dev_err(&pdev->dev, + "could not populate nmk chip struct " + "- continue anyway\n"); + of_node_put(gpio_np); + } + } + prcm_np = of_parse_phandle(np, "prcm", 0); if (prcm_np) npct->prcm_base = of_iomap(prcm_np, 0); -- cgit v1.3-6-gb490 From 8f5ea2df02fb0a50d81701e0c5dc8a5f00381147 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Tue, 21 Jul 2015 22:07:47 -0700 Subject: crypto: qat - Don't attempt to register algorithm multiple times When multiple devices are present in the system the driver attempts to register the same algorithm many times. Changes in v2: - use proper synchronization mechanizm between register and unregister Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/qat_asym_algs.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c index 557a7408710d..fe352a6a1630 100644 --- a/drivers/crypto/qat/qat_common/qat_asym_algs.c +++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c @@ -58,6 +58,9 @@ #include "adf_common_drv.h" #include "qat_crypto.h" +static DEFINE_MUTEX(algs_lock); +static unsigned int active_devs; + struct qat_rsa_input_params { union { struct { @@ -629,11 +632,21 @@ static struct akcipher_alg rsa = { int qat_asym_algs_register(void) { - rsa.base.cra_flags = 0; - return crypto_register_akcipher(&rsa); + int ret = 0; + + mutex_lock(&algs_lock); + if (++active_devs == 1) { + rsa.base.cra_flags = 0; + ret = crypto_register_akcipher(&rsa); + } + mutex_unlock(&algs_lock); + return ret; } void qat_asym_algs_unregister(void) { - crypto_unregister_akcipher(&rsa); + mutex_lock(&algs_lock); + if (--active_devs == 0) + crypto_unregister_akcipher(&rsa); + mutex_unlock(&algs_lock); } -- cgit v1.3-6-gb490 From 039af9675fd9ce2bc1d0b02b9cb10ca9fd7a5445 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 22 Jul 2015 14:26:31 -0400 Subject: crypto: nx - remove __init/__exit from VIO functions Remove the __init and __exit modifiers from the VIO driver probe and remove functions. The driver functions should not be marked __init/__exit because they can/will be called during runtime, not only at module init and exit. Signed-off-by: Dan Streetman Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-pseries.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index d44524da6589..fc5952000357 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c @@ -977,8 +977,8 @@ static struct nx842_driver nx842_pseries_driver = { .decompress = nx842_pseries_decompress, }; -static int __init nx842_probe(struct vio_dev *viodev, - const struct vio_device_id *id) +static int nx842_probe(struct vio_dev *viodev, + const struct vio_device_id *id) { struct nx842_devdata *old_devdata, *new_devdata = NULL; unsigned long flags; @@ -1050,7 +1050,7 @@ error: return ret; } -static int __exit nx842_remove(struct vio_dev *viodev) +static int nx842_remove(struct vio_dev *viodev) { struct nx842_devdata *old_devdata; unsigned long flags; @@ -1081,7 +1081,7 @@ static struct vio_device_id nx842_vio_driver_ids[] = { static struct vio_driver nx842_vio_driver = { .name = KBUILD_MODNAME, .probe = nx842_probe, - .remove = __exit_p(nx842_remove), + .remove = nx842_remove, .get_desired_dma = nx842_get_desired_dma, .id_table = nx842_vio_driver_ids, }; -- cgit v1.3-6-gb490 From 90fd73f912f0897bc22351b55925a4962c045086 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 22 Jul 2015 14:26:32 -0400 Subject: crypto: nx - remove pSeries NX 'status' field Remove the 'status' field from the pSeries NX driver data. The 'status' field isn't used by the driver at all; it simply checks the devicetree status node at initialization, and returns success if 'okay' and failure otherwise. Signed-off-by: Dan Streetman Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-pseries.c | 39 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index fc5952000357..b3758779dc3e 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c @@ -99,11 +99,6 @@ struct nx842_workmem { #define NX842_HW_PAGE_SIZE (4096) #define NX842_HW_PAGE_MASK (~(NX842_HW_PAGE_SIZE-1)) -enum nx842_status { - UNAVAILABLE, - AVAILABLE -}; - struct ibm_nx842_counters { atomic64_t comp_complete; atomic64_t comp_failed; @@ -121,7 +116,6 @@ static struct nx842_devdata { unsigned int max_sg_len; unsigned int max_sync_size; unsigned int max_sync_sg; - enum nx842_status status; } __rcu *devdata; static DEFINE_SPINLOCK(devdata_mutex); @@ -537,48 +531,36 @@ static int nx842_OF_set_defaults(struct nx842_devdata *devdata) devdata->max_sync_size = 0; devdata->max_sync_sg = 0; devdata->max_sg_len = 0; - devdata->status = UNAVAILABLE; return 0; } else return -ENOENT; } /** - * nx842_OF_upd_status -- Update the device info from OF status prop + * nx842_OF_upd_status -- Check the device info from OF status prop * * The status property indicates if the accelerator is enabled. If the * device is in the OF tree it indicates that the hardware is present. * The status field indicates if the device is enabled when the status * is 'okay'. Otherwise the device driver will be disabled. * - * @devdata - struct nx842_devdata to update * @prop - struct property point containing the maxsyncop for the update * * Returns: * 0 - Device is available * -ENODEV - Device is not available */ -static int nx842_OF_upd_status(struct nx842_devdata *devdata, - struct property *prop) { - int ret = 0; +static int nx842_OF_upd_status(struct property *prop) +{ const char *status = (const char *)prop->value; - if (!strncmp(status, "okay", (size_t)prop->length)) { - devdata->status = AVAILABLE; - } else { - /* - * Caller will log that the device is disabled, so only - * output if there is an unexpected status. - */ - if (strncmp(status, "disabled", (size_t)prop->length)) { - dev_info(devdata->dev, "%s: status '%s' is not 'okay'\n", - __func__, status); - } - devdata->status = UNAVAILABLE; - ret = -ENODEV; - } + if (!strncmp(status, "okay", (size_t)prop->length)) + return 0; + if (!strncmp(status, "disabled", (size_t)prop->length)) + return -ENODEV; + dev_info(devdata->dev, "%s: unknown status '%s'\n", __func__, status); - return ret; + return -EINVAL; } /** @@ -784,7 +766,7 @@ static int nx842_OF_upd(struct property *new_prop) goto out; /* Perform property updates */ - ret = nx842_OF_upd_status(new_devdata, status); + ret = nx842_OF_upd_status(status); if (ret) goto error_out; @@ -1100,7 +1082,6 @@ static int __init nx842_pseries_init(void) pr_err("Could not allocate memory for device data\n"); return -ENOMEM; } - new_devdata->status = UNAVAILABLE; RCU_INIT_POINTER(devdata, new_devdata); ret = vio_register_driver(&nx842_vio_driver); -- cgit v1.3-6-gb490 From 7f6e3aad5ab31c310b36bf0edcd305305b20e2a8 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 22 Jul 2015 14:26:33 -0400 Subject: crypto: nx - move kzalloc() out of spinlock Move the kzalloc() calls in nx842_probe() and nx842_OF_upd() to the top of the functions, before taking the devdata spinlock. Since kzalloc() without GFP_ATOMIC can sleep, it can't be called while holding a spinlock. Move the calls to before taking the lock. Signed-off-by: Dan Streetman Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-pseries.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index b3758779dc3e..74c53a119b0b 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c @@ -724,6 +724,10 @@ static int nx842_OF_upd(struct property *new_prop) int ret = 0; unsigned long flags; + new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS); + if (!new_devdata) + return -ENOMEM; + spin_lock_irqsave(&devdata_mutex, flags); old_devdata = rcu_dereference_check(devdata, lockdep_is_held(&devdata_mutex)); @@ -733,16 +737,10 @@ static int nx842_OF_upd(struct property *new_prop) if (!old_devdata || !of_node) { pr_err("%s: device is not available\n", __func__); spin_unlock_irqrestore(&devdata_mutex, flags); + kfree(new_devdata); return -ENODEV; } - new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS); - if (!new_devdata) { - dev_err(old_devdata->dev, "%s: Could not allocate memory for device data\n", __func__); - ret = -ENOMEM; - goto error_out; - } - memcpy(new_devdata, old_devdata, sizeof(*old_devdata)); new_devdata->counters = old_devdata->counters; @@ -966,6 +964,17 @@ static int nx842_probe(struct vio_dev *viodev, unsigned long flags; int ret = 0; + new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS); + if (!new_devdata) + return -ENOMEM; + + new_devdata->counters = kzalloc(sizeof(*new_devdata->counters), + GFP_NOFS); + if (!new_devdata->counters) { + kfree(new_devdata); + return -ENOMEM; + } + spin_lock_irqsave(&devdata_mutex, flags); old_devdata = rcu_dereference_check(devdata, lockdep_is_held(&devdata_mutex)); @@ -978,21 +987,6 @@ static int nx842_probe(struct vio_dev *viodev, dev_set_drvdata(&viodev->dev, NULL); - new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS); - if (!new_devdata) { - dev_err(&viodev->dev, "%s: Could not allocate memory for device data\n", __func__); - ret = -ENOMEM; - goto error_unlock; - } - - new_devdata->counters = kzalloc(sizeof(*new_devdata->counters), - GFP_NOFS); - if (!new_devdata->counters) { - dev_err(&viodev->dev, "%s: Could not allocate memory for performance counters\n", __func__); - ret = -ENOMEM; - goto error_unlock; - } - new_devdata->vdev = viodev; new_devdata->dev = &viodev->dev; nx842_OF_set_defaults(new_devdata); -- cgit v1.3-6-gb490 From ee781b7ff3d8ab93bf99b1c3e1f0a29dda2a63e5 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 22 Jul 2015 14:26:34 -0400 Subject: crypto: nx - don't register pSeries driver if ENODEV Don't register the pSeries driver when parsing the device tree returns ENODEV. The nx842_probe() function in the pSeries driver returns error instead of registering as a crypto compression driver, when it receives an error return value from the nx842_OF_upd() function that probes the device tree nodes, except when ENODEV is returned. However ENODEV should not be a special case and the driver should not register when there is no hw device, or the hw device is disabled. Signed-off-by: Dan Streetman Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-pseries.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index 74c53a119b0b..4b7bd8fb6a6b 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c @@ -999,11 +999,8 @@ static int nx842_probe(struct vio_dev *viodev, of_reconfig_notifier_register(&nx842_of_nb); ret = nx842_OF_upd(NULL); - if (ret && ret != -ENODEV) { - dev_err(&viodev->dev, "could not parse device tree. %d\n", ret); - ret = -1; + if (ret) goto error; - } rcu_read_lock(); dev_set_drvdata(&viodev->dev, rcu_dereference(devdata)); -- cgit v1.3-6-gb490 From 20fc311fc0e14d9f5ef72cfe785fd2b3f6339ab8 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 22 Jul 2015 14:26:35 -0400 Subject: crypto: nx - use common code for both NX decompress success cases Replace the duplicated finishing code (set destination buffer length and set return code to 0) in the case of decompressing a buffer with no header with a goto to the success case of decompressing a buffer with a header. This is a trivial change that allows both success cases to use common code, and includes the pr_debug() msg in both cases as well. Signed-off-by: Dan Streetman Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-crypto.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-crypto.c b/drivers/crypto/nx/nx-842-crypto.c index 3288a701c91b..51ca168a82e9 100644 --- a/drivers/crypto/nx/nx-842-crypto.c +++ b/drivers/crypto/nx/nx-842-crypto.c @@ -520,10 +520,7 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, if (ret) goto unlock; - *dlen = p.ototal; - - ret = 0; - goto unlock; + goto success; } if (!hdr->groups) { @@ -557,6 +554,7 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, goto unlock; } +success: *dlen = p.ototal; pr_debug("decompress total slen %x dlen %x\n", slen, *dlen); -- cgit v1.3-6-gb490 From d31581a6e31f1c954704f081376e19c2014c45d3 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 22 Jul 2015 14:26:36 -0400 Subject: crypto: nx - merge nx-compress and nx-compress-crypto Merge the nx-842.c code into nx-842-crypto.c. This allows later patches to remove the 'platform' driver, and instead allow each platform driver to directly register with the crypto compression api. Signed-off-by: Dan Streetman Signed-off-by: Herbert Xu --- drivers/crypto/nx/Kconfig | 17 ++----- drivers/crypto/nx/Makefile | 4 +- drivers/crypto/nx/nx-842-crypto.c | 70 +++++++++++++------------- drivers/crypto/nx/nx-842.c | 103 -------------------------------------- drivers/crypto/nx/nx-842.h | 28 +++++++---- 5 files changed, 60 insertions(+), 162 deletions(-) delete mode 100644 drivers/crypto/nx/nx-842.c (limited to 'drivers') diff --git a/drivers/crypto/nx/Kconfig b/drivers/crypto/nx/Kconfig index e421c96c763a..ad7552a6998c 100644 --- a/drivers/crypto/nx/Kconfig +++ b/drivers/crypto/nx/Kconfig @@ -14,11 +14,14 @@ config CRYPTO_DEV_NX_ENCRYPT config CRYPTO_DEV_NX_COMPRESS tristate "Compression acceleration support" default y + select CRYPTO_ALGAPI + select 842_DECOMPRESS help Support for PowerPC Nest (NX) compression acceleration. This module supports acceleration for compressing memory with the 842 - algorithm. One of the platform drivers must be selected also. - If you choose 'M' here, this module will be called nx_compress. + algorithm using the cryptographic API. One of the platform + drivers must be selected also. If you choose 'M' here, this + module will be called nx_compress. if CRYPTO_DEV_NX_COMPRESS @@ -42,14 +45,4 @@ config CRYPTO_DEV_NX_COMPRESS_POWERNV algorithm. This supports NX hardware on the PowerNV platform. If you choose 'M' here, this module will be called nx_compress_powernv. -config CRYPTO_DEV_NX_COMPRESS_CRYPTO - tristate "Compression acceleration cryptographic interface" - select CRYPTO_ALGAPI - select 842_DECOMPRESS - default y - help - Support for PowerPC Nest (NX) accelerators using the cryptographic - API. If you choose 'M' here, this module will be called - nx_compress_crypto. - endif diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile index e1684f5adb11..e29ee85b2431 100644 --- a/drivers/crypto/nx/Makefile +++ b/drivers/crypto/nx/Makefile @@ -13,9 +13,7 @@ nx-crypto-objs := nx.o \ obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o nx-compress-platform.o obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_PSERIES) += nx-compress-pseries.o obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_POWERNV) += nx-compress-powernv.o -obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_CRYPTO) += nx-compress-crypto.o -nx-compress-objs := nx-842.o +nx-compress-objs := nx-842-crypto.o nx-compress-platform-objs := nx-842-platform.o nx-compress-pseries-objs := nx-842-pseries.o nx-compress-powernv-objs := nx-842-powernv.o -nx-compress-crypto-objs := nx-842-crypto.o diff --git a/drivers/crypto/nx/nx-842-crypto.c b/drivers/crypto/nx/nx-842-crypto.c index 51ca168a82e9..4472e2001e79 100644 --- a/drivers/crypto/nx/nx-842-crypto.c +++ b/drivers/crypto/nx/nx-842-crypto.c @@ -13,6 +13,9 @@ * * Copyright (C) IBM Corporation, 2011-2015 * + * Designer of the Power data compression engine: + * Bulent Abali + * * Original Authors: Robert Jennings * Seth Jennings * @@ -162,24 +165,11 @@ static void nx842_crypto_exit(struct crypto_tfm *tfm) free_page((unsigned long)ctx->dbounce); } -static int read_constraints(struct nx842_constraints *c) +static void check_constraints(struct nx842_constraints *c) { - int ret; - - ret = nx842_constraints(c); - if (ret) { - pr_err_ratelimited("could not get nx842 constraints : %d\n", - ret); - return ret; - } - /* limit maximum, to always have enough bounce buffer to decompress */ - if (c->maximum > BOUNCE_BUFFER_SIZE) { + if (c->maximum > BOUNCE_BUFFER_SIZE) c->maximum = BOUNCE_BUFFER_SIZE; - pr_info_once("limiting nx842 maximum to %x\n", c->maximum); - } - - return 0; } static int nx842_crypto_add_header(struct nx842_crypto_header *hdr, u8 *buf) @@ -260,7 +250,9 @@ nospc: timeout = ktime_add_ms(ktime_get(), COMP_BUSY_TIMEOUT); do { dlen = tmplen; /* reset dlen, if we're retrying */ - ret = nx842_compress(src, slen, dst, &dlen, ctx->wmem); + ret = nx842_platform_driver()->compress(src, slen, + dst, &dlen, + ctx->wmem); /* possibly we should reduce the slen here, instead of * retrying with the dbounce buffer? */ @@ -297,12 +289,14 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm, struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); struct nx842_crypto_header *hdr = &ctx->header; struct nx842_crypto_param p; - struct nx842_constraints c; + struct nx842_constraints c = *nx842_platform_driver()->constraints; unsigned int groups, hdrsize, h; int ret, n; bool add_header; u16 ignore = 0; + check_constraints(&c); + p.in = (u8 *)src; p.iremain = slen; p.out = dst; @@ -311,10 +305,6 @@ static int nx842_crypto_compress(struct crypto_tfm *tfm, *dlen = 0; - ret = read_constraints(&c); - if (ret) - return ret; - groups = min_t(unsigned int, NX842_CRYPTO_GROUP_MAX, DIV_ROUND_UP(p.iremain, c.maximum)); hdrsize = NX842_CRYPTO_HEADER_SIZE(groups); @@ -381,8 +371,7 @@ static int decompress(struct nx842_crypto_ctx *ctx, struct nx842_crypto_param *p, struct nx842_crypto_header_group *g, struct nx842_constraints *c, - u16 ignore, - bool usehw) + u16 ignore) { unsigned int slen = be32_to_cpu(g->compressed_length); unsigned int required_len = be32_to_cpu(g->uncompressed_length); @@ -404,9 +393,6 @@ static int decompress(struct nx842_crypto_ctx *ctx, src += padding; - if (!usehw) - goto usesw; - if (slen % c->multiple) adj_slen = round_up(slen, c->multiple); if (slen < c->minimum) @@ -443,7 +429,9 @@ static int decompress(struct nx842_crypto_ctx *ctx, timeout = ktime_add_ms(ktime_get(), DECOMP_BUSY_TIMEOUT); do { dlen = tmplen; /* reset dlen, if we're retrying */ - ret = nx842_decompress(src, slen, dst, &dlen, ctx->wmem); + ret = nx842_platform_driver()->decompress(src, slen, + dst, &dlen, + ctx->wmem); } while (ret == -EBUSY && ktime_before(ktime_get(), timeout)); if (ret) { usesw: @@ -486,10 +474,11 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); struct nx842_crypto_header *hdr; struct nx842_crypto_param p; - struct nx842_constraints c; + struct nx842_constraints c = *nx842_platform_driver()->constraints; int n, ret, hdr_len; u16 ignore = 0; - bool usehw = true; + + check_constraints(&c); p.in = (u8 *)src; p.iremain = slen; @@ -499,9 +488,6 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, *dlen = 0; - if (read_constraints(&c)) - usehw = false; - hdr = (struct nx842_crypto_header *)src; spin_lock_bh(&ctx->lock); @@ -516,7 +502,7 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, .uncompressed_length = cpu_to_be32(p.oremain), }; - ret = decompress(ctx, &p, &g, &c, 0, usehw); + ret = decompress(ctx, &p, &g, &c, 0); if (ret) goto unlock; @@ -549,7 +535,7 @@ static int nx842_crypto_decompress(struct crypto_tfm *tfm, if (n + 1 == hdr->groups) ignore = be16_to_cpu(hdr->ignore); - ret = decompress(ctx, &p, &hdr->group[n], &c, ignore, usehw); + ret = decompress(ctx, &p, &hdr->group[n], &c, ignore); if (ret) goto unlock; } @@ -583,6 +569,18 @@ static struct crypto_alg alg = { static int __init nx842_crypto_mod_init(void) { + request_module("nx-compress-powernv"); + request_module("nx-compress-pseries"); + + /* we prevent loading/registering if there's no platform driver, + * and we get the platform module that set it so it won't unload, + * so we don't need to check if it's set in any of our functions + */ + if (!nx842_platform_driver_get()) { + pr_err("no nx842 platform driver found.\n"); + return -ENODEV; + } + return crypto_register_alg(&alg); } module_init(nx842_crypto_mod_init); @@ -590,11 +588,13 @@ module_init(nx842_crypto_mod_init); static void __exit nx842_crypto_mod_exit(void) { crypto_unregister_alg(&alg); + + nx842_platform_driver_put(); } module_exit(nx842_crypto_mod_exit); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("IBM PowerPC Nest (NX) 842 Hardware Compression Interface"); +MODULE_DESCRIPTION("IBM PowerPC Nest (NX) 842 Hardware Compression Driver"); MODULE_ALIAS_CRYPTO("842"); MODULE_ALIAS_CRYPTO("842-nx"); MODULE_AUTHOR("Dan Streetman "); diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c deleted file mode 100644 index 6e5e0d60d0c8..000000000000 --- a/drivers/crypto/nx/nx-842.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Driver frontend for IBM Power 842 compression accelerator - * - * Copyright (C) 2015 Dan Streetman, IBM Corp - * - * Designer of the Power data compression engine: - * Bulent Abali - * - * 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "nx-842.h" - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Dan Streetman "); -MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors"); - -/** - * nx842_constraints - * - * This provides the driver's constraints. Different nx842 implementations - * may have varying requirements. The constraints are: - * @alignment: All buffers should be aligned to this - * @multiple: All buffer lengths should be a multiple of this - * @minimum: Buffer lengths must not be less than this amount - * @maximum: Buffer lengths must not be more than this amount - * - * The constraints apply to all buffers and lengths, both input and output, - * for both compression and decompression, except for the minimum which - * only applies to compression input and decompression output; the - * compressed data can be less than the minimum constraint. It can be - * assumed that compressed data will always adhere to the multiple - * constraint. - * - * The driver may succeed even if these constraints are violated; - * however the driver can return failure or suffer reduced performance - * if any constraint is not met. - */ -int nx842_constraints(struct nx842_constraints *c) -{ - memcpy(c, nx842_platform_driver()->constraints, sizeof(*c)); - return 0; -} -EXPORT_SYMBOL_GPL(nx842_constraints); - -/** - * nx842_workmem_size - * - * Get the amount of working memory the driver requires. - */ -size_t nx842_workmem_size(void) -{ - return nx842_platform_driver()->workmem_size; -} -EXPORT_SYMBOL_GPL(nx842_workmem_size); - -int nx842_compress(const unsigned char *in, unsigned int ilen, - unsigned char *out, unsigned int *olen, void *wmem) -{ - return nx842_platform_driver()->compress(in, ilen, out, olen, wmem); -} -EXPORT_SYMBOL_GPL(nx842_compress); - -int nx842_decompress(const unsigned char *in, unsigned int ilen, - unsigned char *out, unsigned int *olen, void *wmem) -{ - return nx842_platform_driver()->decompress(in, ilen, out, olen, wmem); -} -EXPORT_SYMBOL_GPL(nx842_decompress); - -static __init int nx842_init(void) -{ - request_module("nx-compress-powernv"); - request_module("nx-compress-pseries"); - - /* we prevent loading if there's no platform driver, and we get the - * module that set it so it won't unload, so we don't need to check - * if it's set in any of the above functions - */ - if (!nx842_platform_driver_get()) { - pr_err("no nx842 driver found.\n"); - return -ENODEV; - } - - return 0; -} -module_init(nx842_init); - -static void __exit nx842_exit(void) -{ - nx842_platform_driver_put(); -} -module_exit(nx842_exit); diff --git a/drivers/crypto/nx/nx-842.h b/drivers/crypto/nx/nx-842.h index ac0ea79d0f8b..c7dd0a4391e0 100644 --- a/drivers/crypto/nx/nx-842.h +++ b/drivers/crypto/nx/nx-842.h @@ -104,6 +104,25 @@ static inline unsigned long nx842_get_pa(void *addr) #define GET_FIELD(v, m) (((v) & (m)) >> MASK_LSH(m)) #define SET_FIELD(v, m, val) (((v) & ~(m)) | (((val) << MASK_LSH(m)) & (m))) +/** + * This provides the driver's constraints. Different nx842 implementations + * may have varying requirements. The constraints are: + * @alignment: All buffers should be aligned to this + * @multiple: All buffer lengths should be a multiple of this + * @minimum: Buffer lengths must not be less than this amount + * @maximum: Buffer lengths must not be more than this amount + * + * The constraints apply to all buffers and lengths, both input and output, + * for both compression and decompression, except for the minimum which + * only applies to compression input and decompression output; the + * compressed data can be less than the minimum constraint. It can be + * assumed that compressed data will always adhere to the multiple + * constraint. + * + * The driver may succeed even if these constraints are violated; + * however the driver can return failure or suffer reduced performance + * if any constraint is not met. + */ struct nx842_constraints { int alignment; int multiple; @@ -132,13 +151,4 @@ void nx842_platform_driver_unset(struct nx842_driver *driver); bool nx842_platform_driver_get(void); void nx842_platform_driver_put(void); -size_t nx842_workmem_size(void); - -int nx842_constraints(struct nx842_constraints *constraints); - -int nx842_compress(const unsigned char *in, unsigned int in_len, - unsigned char *out, unsigned int *out_len, void *wrkmem); -int nx842_decompress(const unsigned char *in, unsigned int in_len, - unsigned char *out, unsigned int *out_len, void *wrkmem); - #endif /* __NX_842_H__ */ -- cgit v1.3-6-gb490 From 174d66d4725879b80f8af0bda2b218c2892a9ddb Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 22 Jul 2015 14:26:37 -0400 Subject: crypto: nx - rename nx-842-crypto.c to nx-842.c The last commit merged nx-842.c's code into nx-842-crypto.c. It did not rename nx-842-crypto.c to nx-842.c, in order to let the patch more clearly show what was merged. This just renames nx-842-crypto.c to nx-842.c, with no changes to its code. Signed-off-by: Dan Streetman Signed-off-by: Herbert Xu --- drivers/crypto/nx/Makefile | 2 +- drivers/crypto/nx/nx-842-crypto.c | 600 -------------------------------------- drivers/crypto/nx/nx-842.c | 600 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 601 insertions(+), 601 deletions(-) delete mode 100644 drivers/crypto/nx/nx-842-crypto.c create mode 100644 drivers/crypto/nx/nx-842.c (limited to 'drivers') diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile index e29ee85b2431..ffcc86c44e15 100644 --- a/drivers/crypto/nx/Makefile +++ b/drivers/crypto/nx/Makefile @@ -13,7 +13,7 @@ nx-crypto-objs := nx.o \ obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o nx-compress-platform.o obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_PSERIES) += nx-compress-pseries.o obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_POWERNV) += nx-compress-powernv.o -nx-compress-objs := nx-842-crypto.o +nx-compress-objs := nx-842.o nx-compress-platform-objs := nx-842-platform.o nx-compress-pseries-objs := nx-842-pseries.o nx-compress-powernv-objs := nx-842-powernv.o diff --git a/drivers/crypto/nx/nx-842-crypto.c b/drivers/crypto/nx/nx-842-crypto.c deleted file mode 100644 index 4472e2001e79..000000000000 --- a/drivers/crypto/nx/nx-842-crypto.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * Cryptographic API for the NX-842 hardware compression. - * - * 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. - * - * Copyright (C) IBM Corporation, 2011-2015 - * - * Designer of the Power data compression engine: - * Bulent Abali - * - * Original Authors: Robert Jennings - * Seth Jennings - * - * Rewrite: Dan Streetman - * - * This is an interface to the NX-842 compression hardware in PowerPC - * processors. Most of the complexity of this drvier is due to the fact that - * the NX-842 compression hardware requires the input and output data buffers - * to be specifically aligned, to be a specific multiple in length, and within - * specific minimum and maximum lengths. Those restrictions, provided by the - * nx-842 driver via nx842_constraints, mean this driver must use bounce - * buffers and headers to correct misaligned in or out buffers, and to split - * input buffers that are too large. - * - * This driver will fall back to software decompression if the hardware - * decompression fails, so this driver's decompression should never fail as - * long as the provided compressed buffer is valid. Any compressed buffer - * created by this driver will have a header (except ones where the input - * perfectly matches the constraints); so users of this driver cannot simply - * pass a compressed buffer created by this driver over to the 842 software - * decompression library. Instead, users must use this driver to decompress; - * if the hardware fails or is unavailable, the compressed buffer will be - * parsed and the header removed, and the raw 842 buffer(s) passed to the 842 - * software decompression library. - * - * This does not fall back to software compression, however, since the caller - * of this function is specifically requesting hardware compression; if the - * hardware compression fails, the caller can fall back to software - * compression, and the raw 842 compressed buffer that the software compressor - * creates can be passed to this driver for hardware decompression; any - * buffer without our specific header magic is assumed to be a raw 842 buffer - * and passed directly to the hardware. Note that the software compression - * library will produce a compressed buffer that is incompatible with the - * hardware decompressor if the original input buffer length is not a multiple - * of 8; if such a compressed buffer is passed to this driver for - * decompression, the hardware will reject it and this driver will then pass - * it over to the software library for decompression. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include - -#include "nx-842.h" - -/* The first 5 bits of this magic are 0x1f, which is an invalid 842 5-bit - * template (see lib/842/842.h), so this magic number will never appear at - * the start of a raw 842 compressed buffer. That is important, as any buffer - * passed to us without this magic is assumed to be a raw 842 compressed - * buffer, and passed directly to the hardware to decompress. - */ -#define NX842_CRYPTO_MAGIC (0xf842) -#define NX842_CRYPTO_GROUP_MAX (0x20) -#define NX842_CRYPTO_HEADER_SIZE(g) \ - (sizeof(struct nx842_crypto_header) + \ - sizeof(struct nx842_crypto_header_group) * (g)) -#define NX842_CRYPTO_HEADER_MAX_SIZE \ - NX842_CRYPTO_HEADER_SIZE(NX842_CRYPTO_GROUP_MAX) - -/* bounce buffer size */ -#define BOUNCE_BUFFER_ORDER (2) -#define BOUNCE_BUFFER_SIZE \ - ((unsigned int)(PAGE_SIZE << BOUNCE_BUFFER_ORDER)) - -/* try longer on comp because we can fallback to sw decomp if hw is busy */ -#define COMP_BUSY_TIMEOUT (250) /* ms */ -#define DECOMP_BUSY_TIMEOUT (50) /* ms */ - -struct nx842_crypto_header_group { - __be16 padding; /* unused bytes at start of group */ - __be32 compressed_length; /* compressed bytes in group */ - __be32 uncompressed_length; /* bytes after decompression */ -} __packed; - -struct nx842_crypto_header { - __be16 magic; /* NX842_CRYPTO_MAGIC */ - __be16 ignore; /* decompressed end bytes to ignore */ - u8 groups; /* total groups in this header */ - struct nx842_crypto_header_group group[]; -} __packed; - -struct nx842_crypto_param { - u8 *in; - unsigned int iremain; - u8 *out; - unsigned int oremain; - unsigned int ototal; -}; - -static int update_param(struct nx842_crypto_param *p, - unsigned int slen, unsigned int dlen) -{ - if (p->iremain < slen) - return -EOVERFLOW; - if (p->oremain < dlen) - return -ENOSPC; - - p->in += slen; - p->iremain -= slen; - p->out += dlen; - p->oremain -= dlen; - p->ototal += dlen; - - return 0; -} - -struct nx842_crypto_ctx { - spinlock_t lock; - - u8 *wmem; - u8 *sbounce, *dbounce; - - struct nx842_crypto_header header; - struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX]; -}; - -static int nx842_crypto_init(struct crypto_tfm *tfm) -{ - struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); - - spin_lock_init(&ctx->lock); - ctx->wmem = kmalloc(nx842_workmem_size(), GFP_KERNEL); - ctx->sbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); - ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); - if (!ctx->wmem || !ctx->sbounce || !ctx->dbounce) { - kfree(ctx->wmem); - free_page((unsigned long)ctx->sbounce); - free_page((unsigned long)ctx->dbounce); - return -ENOMEM; - } - - return 0; -} - -static void nx842_crypto_exit(struct crypto_tfm *tfm) -{ - struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); - - kfree(ctx->wmem); - free_page((unsigned long)ctx->sbounce); - free_page((unsigned long)ctx->dbounce); -} - -static void check_constraints(struct nx842_constraints *c) -{ - /* limit maximum, to always have enough bounce buffer to decompress */ - if (c->maximum > BOUNCE_BUFFER_SIZE) - c->maximum = BOUNCE_BUFFER_SIZE; -} - -static int nx842_crypto_add_header(struct nx842_crypto_header *hdr, u8 *buf) -{ - int s = NX842_CRYPTO_HEADER_SIZE(hdr->groups); - - /* compress should have added space for header */ - if (s > be16_to_cpu(hdr->group[0].padding)) { - pr_err("Internal error: no space for header\n"); - return -EINVAL; - } - - memcpy(buf, hdr, s); - - print_hex_dump_debug("header ", DUMP_PREFIX_OFFSET, 16, 1, buf, s, 0); - - return 0; -} - -static int compress(struct nx842_crypto_ctx *ctx, - struct nx842_crypto_param *p, - struct nx842_crypto_header_group *g, - struct nx842_constraints *c, - u16 *ignore, - unsigned int hdrsize) -{ - unsigned int slen = p->iremain, dlen = p->oremain, tmplen; - unsigned int adj_slen = slen; - u8 *src = p->in, *dst = p->out; - int ret, dskip = 0; - ktime_t timeout; - - if (p->iremain == 0) - return -EOVERFLOW; - - if (p->oremain == 0 || hdrsize + c->minimum > dlen) - return -ENOSPC; - - if (slen % c->multiple) - adj_slen = round_up(slen, c->multiple); - if (slen < c->minimum) - adj_slen = c->minimum; - if (slen > c->maximum) - adj_slen = slen = c->maximum; - if (adj_slen > slen || (u64)src % c->alignment) { - adj_slen = min(adj_slen, BOUNCE_BUFFER_SIZE); - slen = min(slen, BOUNCE_BUFFER_SIZE); - if (adj_slen > slen) - memset(ctx->sbounce + slen, 0, adj_slen - slen); - memcpy(ctx->sbounce, src, slen); - src = ctx->sbounce; - slen = adj_slen; - pr_debug("using comp sbounce buffer, len %x\n", slen); - } - - dst += hdrsize; - dlen -= hdrsize; - - if ((u64)dst % c->alignment) { - dskip = (int)(PTR_ALIGN(dst, c->alignment) - dst); - dst += dskip; - dlen -= dskip; - } - if (dlen % c->multiple) - dlen = round_down(dlen, c->multiple); - if (dlen < c->minimum) { -nospc: - dst = ctx->dbounce; - dlen = min(p->oremain, BOUNCE_BUFFER_SIZE); - dlen = round_down(dlen, c->multiple); - dskip = 0; - pr_debug("using comp dbounce buffer, len %x\n", dlen); - } - if (dlen > c->maximum) - dlen = c->maximum; - - tmplen = dlen; - timeout = ktime_add_ms(ktime_get(), COMP_BUSY_TIMEOUT); - do { - dlen = tmplen; /* reset dlen, if we're retrying */ - ret = nx842_platform_driver()->compress(src, slen, - dst, &dlen, - ctx->wmem); - /* possibly we should reduce the slen here, instead of - * retrying with the dbounce buffer? - */ - if (ret == -ENOSPC && dst != ctx->dbounce) - goto nospc; - } while (ret == -EBUSY && ktime_before(ktime_get(), timeout)); - if (ret) - return ret; - - dskip += hdrsize; - - if (dst == ctx->dbounce) - memcpy(p->out + dskip, dst, dlen); - - g->padding = cpu_to_be16(dskip); - g->compressed_length = cpu_to_be32(dlen); - g->uncompressed_length = cpu_to_be32(slen); - - if (p->iremain < slen) { - *ignore = slen - p->iremain; - slen = p->iremain; - } - - pr_debug("compress slen %x ignore %x dlen %x padding %x\n", - slen, *ignore, dlen, dskip); - - return update_param(p, slen, dskip + dlen); -} - -static int nx842_crypto_compress(struct crypto_tfm *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen) -{ - struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); - struct nx842_crypto_header *hdr = &ctx->header; - struct nx842_crypto_param p; - struct nx842_constraints c = *nx842_platform_driver()->constraints; - unsigned int groups, hdrsize, h; - int ret, n; - bool add_header; - u16 ignore = 0; - - check_constraints(&c); - - p.in = (u8 *)src; - p.iremain = slen; - p.out = dst; - p.oremain = *dlen; - p.ototal = 0; - - *dlen = 0; - - groups = min_t(unsigned int, NX842_CRYPTO_GROUP_MAX, - DIV_ROUND_UP(p.iremain, c.maximum)); - hdrsize = NX842_CRYPTO_HEADER_SIZE(groups); - - spin_lock_bh(&ctx->lock); - - /* skip adding header if the buffers meet all constraints */ - add_header = (p.iremain % c.multiple || - p.iremain < c.minimum || - p.iremain > c.maximum || - (u64)p.in % c.alignment || - p.oremain % c.multiple || - p.oremain < c.minimum || - p.oremain > c.maximum || - (u64)p.out % c.alignment); - - hdr->magic = cpu_to_be16(NX842_CRYPTO_MAGIC); - hdr->groups = 0; - hdr->ignore = 0; - - while (p.iremain > 0) { - n = hdr->groups++; - ret = -ENOSPC; - if (hdr->groups > NX842_CRYPTO_GROUP_MAX) - goto unlock; - - /* header goes before first group */ - h = !n && add_header ? hdrsize : 0; - - if (ignore) - pr_warn("interal error, ignore is set %x\n", ignore); - - ret = compress(ctx, &p, &hdr->group[n], &c, &ignore, h); - if (ret) - goto unlock; - } - - if (!add_header && hdr->groups > 1) { - pr_err("Internal error: No header but multiple groups\n"); - ret = -EINVAL; - goto unlock; - } - - /* ignore indicates the input stream needed to be padded */ - hdr->ignore = cpu_to_be16(ignore); - if (ignore) - pr_debug("marked %d bytes as ignore\n", ignore); - - if (add_header) - ret = nx842_crypto_add_header(hdr, dst); - if (ret) - goto unlock; - - *dlen = p.ototal; - - pr_debug("compress total slen %x dlen %x\n", slen, *dlen); - -unlock: - spin_unlock_bh(&ctx->lock); - return ret; -} - -static int decompress(struct nx842_crypto_ctx *ctx, - struct nx842_crypto_param *p, - struct nx842_crypto_header_group *g, - struct nx842_constraints *c, - u16 ignore) -{ - unsigned int slen = be32_to_cpu(g->compressed_length); - unsigned int required_len = be32_to_cpu(g->uncompressed_length); - unsigned int dlen = p->oremain, tmplen; - unsigned int adj_slen = slen; - u8 *src = p->in, *dst = p->out; - u16 padding = be16_to_cpu(g->padding); - int ret, spadding = 0, dpadding = 0; - ktime_t timeout; - - if (!slen || !required_len) - return -EINVAL; - - if (p->iremain <= 0 || padding + slen > p->iremain) - return -EOVERFLOW; - - if (p->oremain <= 0 || required_len - ignore > p->oremain) - return -ENOSPC; - - src += padding; - - if (slen % c->multiple) - adj_slen = round_up(slen, c->multiple); - if (slen < c->minimum) - adj_slen = c->minimum; - if (slen > c->maximum) - goto usesw; - if (slen < adj_slen || (u64)src % c->alignment) { - /* we can append padding bytes because the 842 format defines - * an "end" template (see lib/842/842_decompress.c) and will - * ignore any bytes following it. - */ - if (slen < adj_slen) - memset(ctx->sbounce + slen, 0, adj_slen - slen); - memcpy(ctx->sbounce, src, slen); - src = ctx->sbounce; - spadding = adj_slen - slen; - slen = adj_slen; - pr_debug("using decomp sbounce buffer, len %x\n", slen); - } - - if (dlen % c->multiple) - dlen = round_down(dlen, c->multiple); - if (dlen < required_len || (u64)dst % c->alignment) { - dst = ctx->dbounce; - dlen = min(required_len, BOUNCE_BUFFER_SIZE); - pr_debug("using decomp dbounce buffer, len %x\n", dlen); - } - if (dlen < c->minimum) - goto usesw; - if (dlen > c->maximum) - dlen = c->maximum; - - tmplen = dlen; - timeout = ktime_add_ms(ktime_get(), DECOMP_BUSY_TIMEOUT); - do { - dlen = tmplen; /* reset dlen, if we're retrying */ - ret = nx842_platform_driver()->decompress(src, slen, - dst, &dlen, - ctx->wmem); - } while (ret == -EBUSY && ktime_before(ktime_get(), timeout)); - if (ret) { -usesw: - /* reset everything, sw doesn't have constraints */ - src = p->in + padding; - slen = be32_to_cpu(g->compressed_length); - spadding = 0; - dst = p->out; - dlen = p->oremain; - dpadding = 0; - if (dlen < required_len) { /* have ignore bytes */ - dst = ctx->dbounce; - dlen = BOUNCE_BUFFER_SIZE; - } - pr_info_ratelimited("using software 842 decompression\n"); - ret = sw842_decompress(src, slen, dst, &dlen); - } - if (ret) - return ret; - - slen -= spadding; - - dlen -= ignore; - if (ignore) - pr_debug("ignoring last %x bytes\n", ignore); - - if (dst == ctx->dbounce) - memcpy(p->out, dst, dlen); - - pr_debug("decompress slen %x padding %x dlen %x ignore %x\n", - slen, padding, dlen, ignore); - - return update_param(p, slen + padding, dlen); -} - -static int nx842_crypto_decompress(struct crypto_tfm *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen) -{ - struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); - struct nx842_crypto_header *hdr; - struct nx842_crypto_param p; - struct nx842_constraints c = *nx842_platform_driver()->constraints; - int n, ret, hdr_len; - u16 ignore = 0; - - check_constraints(&c); - - p.in = (u8 *)src; - p.iremain = slen; - p.out = dst; - p.oremain = *dlen; - p.ototal = 0; - - *dlen = 0; - - hdr = (struct nx842_crypto_header *)src; - - spin_lock_bh(&ctx->lock); - - /* If it doesn't start with our header magic number, assume it's a raw - * 842 compressed buffer and pass it directly to the hardware driver - */ - if (be16_to_cpu(hdr->magic) != NX842_CRYPTO_MAGIC) { - struct nx842_crypto_header_group g = { - .padding = 0, - .compressed_length = cpu_to_be32(p.iremain), - .uncompressed_length = cpu_to_be32(p.oremain), - }; - - ret = decompress(ctx, &p, &g, &c, 0); - if (ret) - goto unlock; - - goto success; - } - - if (!hdr->groups) { - pr_err("header has no groups\n"); - ret = -EINVAL; - goto unlock; - } - if (hdr->groups > NX842_CRYPTO_GROUP_MAX) { - pr_err("header has too many groups %x, max %x\n", - hdr->groups, NX842_CRYPTO_GROUP_MAX); - ret = -EINVAL; - goto unlock; - } - - hdr_len = NX842_CRYPTO_HEADER_SIZE(hdr->groups); - if (hdr_len > slen) { - ret = -EOVERFLOW; - goto unlock; - } - - memcpy(&ctx->header, src, hdr_len); - hdr = &ctx->header; - - for (n = 0; n < hdr->groups; n++) { - /* ignore applies to last group */ - if (n + 1 == hdr->groups) - ignore = be16_to_cpu(hdr->ignore); - - ret = decompress(ctx, &p, &hdr->group[n], &c, ignore); - if (ret) - goto unlock; - } - -success: - *dlen = p.ototal; - - pr_debug("decompress total slen %x dlen %x\n", slen, *dlen); - - ret = 0; - -unlock: - spin_unlock_bh(&ctx->lock); - - return ret; -} - -static struct crypto_alg alg = { - .cra_name = "842", - .cra_driver_name = "842-nx", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, - .cra_ctxsize = sizeof(struct nx842_crypto_ctx), - .cra_module = THIS_MODULE, - .cra_init = nx842_crypto_init, - .cra_exit = nx842_crypto_exit, - .cra_u = { .compress = { - .coa_compress = nx842_crypto_compress, - .coa_decompress = nx842_crypto_decompress } } -}; - -static int __init nx842_crypto_mod_init(void) -{ - request_module("nx-compress-powernv"); - request_module("nx-compress-pseries"); - - /* we prevent loading/registering if there's no platform driver, - * and we get the platform module that set it so it won't unload, - * so we don't need to check if it's set in any of our functions - */ - if (!nx842_platform_driver_get()) { - pr_err("no nx842 platform driver found.\n"); - return -ENODEV; - } - - return crypto_register_alg(&alg); -} -module_init(nx842_crypto_mod_init); - -static void __exit nx842_crypto_mod_exit(void) -{ - crypto_unregister_alg(&alg); - - nx842_platform_driver_put(); -} -module_exit(nx842_crypto_mod_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("IBM PowerPC Nest (NX) 842 Hardware Compression Driver"); -MODULE_ALIAS_CRYPTO("842"); -MODULE_ALIAS_CRYPTO("842-nx"); -MODULE_AUTHOR("Dan Streetman "); diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c new file mode 100644 index 000000000000..4472e2001e79 --- /dev/null +++ b/drivers/crypto/nx/nx-842.c @@ -0,0 +1,600 @@ +/* + * Cryptographic API for the NX-842 hardware compression. + * + * 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. + * + * Copyright (C) IBM Corporation, 2011-2015 + * + * Designer of the Power data compression engine: + * Bulent Abali + * + * Original Authors: Robert Jennings + * Seth Jennings + * + * Rewrite: Dan Streetman + * + * This is an interface to the NX-842 compression hardware in PowerPC + * processors. Most of the complexity of this drvier is due to the fact that + * the NX-842 compression hardware requires the input and output data buffers + * to be specifically aligned, to be a specific multiple in length, and within + * specific minimum and maximum lengths. Those restrictions, provided by the + * nx-842 driver via nx842_constraints, mean this driver must use bounce + * buffers and headers to correct misaligned in or out buffers, and to split + * input buffers that are too large. + * + * This driver will fall back to software decompression if the hardware + * decompression fails, so this driver's decompression should never fail as + * long as the provided compressed buffer is valid. Any compressed buffer + * created by this driver will have a header (except ones where the input + * perfectly matches the constraints); so users of this driver cannot simply + * pass a compressed buffer created by this driver over to the 842 software + * decompression library. Instead, users must use this driver to decompress; + * if the hardware fails or is unavailable, the compressed buffer will be + * parsed and the header removed, and the raw 842 buffer(s) passed to the 842 + * software decompression library. + * + * This does not fall back to software compression, however, since the caller + * of this function is specifically requesting hardware compression; if the + * hardware compression fails, the caller can fall back to software + * compression, and the raw 842 compressed buffer that the software compressor + * creates can be passed to this driver for hardware decompression; any + * buffer without our specific header magic is assumed to be a raw 842 buffer + * and passed directly to the hardware. Note that the software compression + * library will produce a compressed buffer that is incompatible with the + * hardware decompressor if the original input buffer length is not a multiple + * of 8; if such a compressed buffer is passed to this driver for + * decompression, the hardware will reject it and this driver will then pass + * it over to the software library for decompression. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "nx-842.h" + +/* The first 5 bits of this magic are 0x1f, which is an invalid 842 5-bit + * template (see lib/842/842.h), so this magic number will never appear at + * the start of a raw 842 compressed buffer. That is important, as any buffer + * passed to us without this magic is assumed to be a raw 842 compressed + * buffer, and passed directly to the hardware to decompress. + */ +#define NX842_CRYPTO_MAGIC (0xf842) +#define NX842_CRYPTO_GROUP_MAX (0x20) +#define NX842_CRYPTO_HEADER_SIZE(g) \ + (sizeof(struct nx842_crypto_header) + \ + sizeof(struct nx842_crypto_header_group) * (g)) +#define NX842_CRYPTO_HEADER_MAX_SIZE \ + NX842_CRYPTO_HEADER_SIZE(NX842_CRYPTO_GROUP_MAX) + +/* bounce buffer size */ +#define BOUNCE_BUFFER_ORDER (2) +#define BOUNCE_BUFFER_SIZE \ + ((unsigned int)(PAGE_SIZE << BOUNCE_BUFFER_ORDER)) + +/* try longer on comp because we can fallback to sw decomp if hw is busy */ +#define COMP_BUSY_TIMEOUT (250) /* ms */ +#define DECOMP_BUSY_TIMEOUT (50) /* ms */ + +struct nx842_crypto_header_group { + __be16 padding; /* unused bytes at start of group */ + __be32 compressed_length; /* compressed bytes in group */ + __be32 uncompressed_length; /* bytes after decompression */ +} __packed; + +struct nx842_crypto_header { + __be16 magic; /* NX842_CRYPTO_MAGIC */ + __be16 ignore; /* decompressed end bytes to ignore */ + u8 groups; /* total groups in this header */ + struct nx842_crypto_header_group group[]; +} __packed; + +struct nx842_crypto_param { + u8 *in; + unsigned int iremain; + u8 *out; + unsigned int oremain; + unsigned int ototal; +}; + +static int update_param(struct nx842_crypto_param *p, + unsigned int slen, unsigned int dlen) +{ + if (p->iremain < slen) + return -EOVERFLOW; + if (p->oremain < dlen) + return -ENOSPC; + + p->in += slen; + p->iremain -= slen; + p->out += dlen; + p->oremain -= dlen; + p->ototal += dlen; + + return 0; +} + +struct nx842_crypto_ctx { + spinlock_t lock; + + u8 *wmem; + u8 *sbounce, *dbounce; + + struct nx842_crypto_header header; + struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX]; +}; + +static int nx842_crypto_init(struct crypto_tfm *tfm) +{ + struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); + + spin_lock_init(&ctx->lock); + ctx->wmem = kmalloc(nx842_workmem_size(), GFP_KERNEL); + ctx->sbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); + ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); + if (!ctx->wmem || !ctx->sbounce || !ctx->dbounce) { + kfree(ctx->wmem); + free_page((unsigned long)ctx->sbounce); + free_page((unsigned long)ctx->dbounce); + return -ENOMEM; + } + + return 0; +} + +static void nx842_crypto_exit(struct crypto_tfm *tfm) +{ + struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); + + kfree(ctx->wmem); + free_page((unsigned long)ctx->sbounce); + free_page((unsigned long)ctx->dbounce); +} + +static void check_constraints(struct nx842_constraints *c) +{ + /* limit maximum, to always have enough bounce buffer to decompress */ + if (c->maximum > BOUNCE_BUFFER_SIZE) + c->maximum = BOUNCE_BUFFER_SIZE; +} + +static int nx842_crypto_add_header(struct nx842_crypto_header *hdr, u8 *buf) +{ + int s = NX842_CRYPTO_HEADER_SIZE(hdr->groups); + + /* compress should have added space for header */ + if (s > be16_to_cpu(hdr->group[0].padding)) { + pr_err("Internal error: no space for header\n"); + return -EINVAL; + } + + memcpy(buf, hdr, s); + + print_hex_dump_debug("header ", DUMP_PREFIX_OFFSET, 16, 1, buf, s, 0); + + return 0; +} + +static int compress(struct nx842_crypto_ctx *ctx, + struct nx842_crypto_param *p, + struct nx842_crypto_header_group *g, + struct nx842_constraints *c, + u16 *ignore, + unsigned int hdrsize) +{ + unsigned int slen = p->iremain, dlen = p->oremain, tmplen; + unsigned int adj_slen = slen; + u8 *src = p->in, *dst = p->out; + int ret, dskip = 0; + ktime_t timeout; + + if (p->iremain == 0) + return -EOVERFLOW; + + if (p->oremain == 0 || hdrsize + c->minimum > dlen) + return -ENOSPC; + + if (slen % c->multiple) + adj_slen = round_up(slen, c->multiple); + if (slen < c->minimum) + adj_slen = c->minimum; + if (slen > c->maximum) + adj_slen = slen = c->maximum; + if (adj_slen > slen || (u64)src % c->alignment) { + adj_slen = min(adj_slen, BOUNCE_BUFFER_SIZE); + slen = min(slen, BOUNCE_BUFFER_SIZE); + if (adj_slen > slen) + memset(ctx->sbounce + slen, 0, adj_slen - slen); + memcpy(ctx->sbounce, src, slen); + src = ctx->sbounce; + slen = adj_slen; + pr_debug("using comp sbounce buffer, len %x\n", slen); + } + + dst += hdrsize; + dlen -= hdrsize; + + if ((u64)dst % c->alignment) { + dskip = (int)(PTR_ALIGN(dst, c->alignment) - dst); + dst += dskip; + dlen -= dskip; + } + if (dlen % c->multiple) + dlen = round_down(dlen, c->multiple); + if (dlen < c->minimum) { +nospc: + dst = ctx->dbounce; + dlen = min(p->oremain, BOUNCE_BUFFER_SIZE); + dlen = round_down(dlen, c->multiple); + dskip = 0; + pr_debug("using comp dbounce buffer, len %x\n", dlen); + } + if (dlen > c->maximum) + dlen = c->maximum; + + tmplen = dlen; + timeout = ktime_add_ms(ktime_get(), COMP_BUSY_TIMEOUT); + do { + dlen = tmplen; /* reset dlen, if we're retrying */ + ret = nx842_platform_driver()->compress(src, slen, + dst, &dlen, + ctx->wmem); + /* possibly we should reduce the slen here, instead of + * retrying with the dbounce buffer? + */ + if (ret == -ENOSPC && dst != ctx->dbounce) + goto nospc; + } while (ret == -EBUSY && ktime_before(ktime_get(), timeout)); + if (ret) + return ret; + + dskip += hdrsize; + + if (dst == ctx->dbounce) + memcpy(p->out + dskip, dst, dlen); + + g->padding = cpu_to_be16(dskip); + g->compressed_length = cpu_to_be32(dlen); + g->uncompressed_length = cpu_to_be32(slen); + + if (p->iremain < slen) { + *ignore = slen - p->iremain; + slen = p->iremain; + } + + pr_debug("compress slen %x ignore %x dlen %x padding %x\n", + slen, *ignore, dlen, dskip); + + return update_param(p, slen, dskip + dlen); +} + +static int nx842_crypto_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); + struct nx842_crypto_header *hdr = &ctx->header; + struct nx842_crypto_param p; + struct nx842_constraints c = *nx842_platform_driver()->constraints; + unsigned int groups, hdrsize, h; + int ret, n; + bool add_header; + u16 ignore = 0; + + check_constraints(&c); + + p.in = (u8 *)src; + p.iremain = slen; + p.out = dst; + p.oremain = *dlen; + p.ototal = 0; + + *dlen = 0; + + groups = min_t(unsigned int, NX842_CRYPTO_GROUP_MAX, + DIV_ROUND_UP(p.iremain, c.maximum)); + hdrsize = NX842_CRYPTO_HEADER_SIZE(groups); + + spin_lock_bh(&ctx->lock); + + /* skip adding header if the buffers meet all constraints */ + add_header = (p.iremain % c.multiple || + p.iremain < c.minimum || + p.iremain > c.maximum || + (u64)p.in % c.alignment || + p.oremain % c.multiple || + p.oremain < c.minimum || + p.oremain > c.maximum || + (u64)p.out % c.alignment); + + hdr->magic = cpu_to_be16(NX842_CRYPTO_MAGIC); + hdr->groups = 0; + hdr->ignore = 0; + + while (p.iremain > 0) { + n = hdr->groups++; + ret = -ENOSPC; + if (hdr->groups > NX842_CRYPTO_GROUP_MAX) + goto unlock; + + /* header goes before first group */ + h = !n && add_header ? hdrsize : 0; + + if (ignore) + pr_warn("interal error, ignore is set %x\n", ignore); + + ret = compress(ctx, &p, &hdr->group[n], &c, &ignore, h); + if (ret) + goto unlock; + } + + if (!add_header && hdr->groups > 1) { + pr_err("Internal error: No header but multiple groups\n"); + ret = -EINVAL; + goto unlock; + } + + /* ignore indicates the input stream needed to be padded */ + hdr->ignore = cpu_to_be16(ignore); + if (ignore) + pr_debug("marked %d bytes as ignore\n", ignore); + + if (add_header) + ret = nx842_crypto_add_header(hdr, dst); + if (ret) + goto unlock; + + *dlen = p.ototal; + + pr_debug("compress total slen %x dlen %x\n", slen, *dlen); + +unlock: + spin_unlock_bh(&ctx->lock); + return ret; +} + +static int decompress(struct nx842_crypto_ctx *ctx, + struct nx842_crypto_param *p, + struct nx842_crypto_header_group *g, + struct nx842_constraints *c, + u16 ignore) +{ + unsigned int slen = be32_to_cpu(g->compressed_length); + unsigned int required_len = be32_to_cpu(g->uncompressed_length); + unsigned int dlen = p->oremain, tmplen; + unsigned int adj_slen = slen; + u8 *src = p->in, *dst = p->out; + u16 padding = be16_to_cpu(g->padding); + int ret, spadding = 0, dpadding = 0; + ktime_t timeout; + + if (!slen || !required_len) + return -EINVAL; + + if (p->iremain <= 0 || padding + slen > p->iremain) + return -EOVERFLOW; + + if (p->oremain <= 0 || required_len - ignore > p->oremain) + return -ENOSPC; + + src += padding; + + if (slen % c->multiple) + adj_slen = round_up(slen, c->multiple); + if (slen < c->minimum) + adj_slen = c->minimum; + if (slen > c->maximum) + goto usesw; + if (slen < adj_slen || (u64)src % c->alignment) { + /* we can append padding bytes because the 842 format defines + * an "end" template (see lib/842/842_decompress.c) and will + * ignore any bytes following it. + */ + if (slen < adj_slen) + memset(ctx->sbounce + slen, 0, adj_slen - slen); + memcpy(ctx->sbounce, src, slen); + src = ctx->sbounce; + spadding = adj_slen - slen; + slen = adj_slen; + pr_debug("using decomp sbounce buffer, len %x\n", slen); + } + + if (dlen % c->multiple) + dlen = round_down(dlen, c->multiple); + if (dlen < required_len || (u64)dst % c->alignment) { + dst = ctx->dbounce; + dlen = min(required_len, BOUNCE_BUFFER_SIZE); + pr_debug("using decomp dbounce buffer, len %x\n", dlen); + } + if (dlen < c->minimum) + goto usesw; + if (dlen > c->maximum) + dlen = c->maximum; + + tmplen = dlen; + timeout = ktime_add_ms(ktime_get(), DECOMP_BUSY_TIMEOUT); + do { + dlen = tmplen; /* reset dlen, if we're retrying */ + ret = nx842_platform_driver()->decompress(src, slen, + dst, &dlen, + ctx->wmem); + } while (ret == -EBUSY && ktime_before(ktime_get(), timeout)); + if (ret) { +usesw: + /* reset everything, sw doesn't have constraints */ + src = p->in + padding; + slen = be32_to_cpu(g->compressed_length); + spadding = 0; + dst = p->out; + dlen = p->oremain; + dpadding = 0; + if (dlen < required_len) { /* have ignore bytes */ + dst = ctx->dbounce; + dlen = BOUNCE_BUFFER_SIZE; + } + pr_info_ratelimited("using software 842 decompression\n"); + ret = sw842_decompress(src, slen, dst, &dlen); + } + if (ret) + return ret; + + slen -= spadding; + + dlen -= ignore; + if (ignore) + pr_debug("ignoring last %x bytes\n", ignore); + + if (dst == ctx->dbounce) + memcpy(p->out, dst, dlen); + + pr_debug("decompress slen %x padding %x dlen %x ignore %x\n", + slen, padding, dlen, ignore); + + return update_param(p, slen + padding, dlen); +} + +static int nx842_crypto_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); + struct nx842_crypto_header *hdr; + struct nx842_crypto_param p; + struct nx842_constraints c = *nx842_platform_driver()->constraints; + int n, ret, hdr_len; + u16 ignore = 0; + + check_constraints(&c); + + p.in = (u8 *)src; + p.iremain = slen; + p.out = dst; + p.oremain = *dlen; + p.ototal = 0; + + *dlen = 0; + + hdr = (struct nx842_crypto_header *)src; + + spin_lock_bh(&ctx->lock); + + /* If it doesn't start with our header magic number, assume it's a raw + * 842 compressed buffer and pass it directly to the hardware driver + */ + if (be16_to_cpu(hdr->magic) != NX842_CRYPTO_MAGIC) { + struct nx842_crypto_header_group g = { + .padding = 0, + .compressed_length = cpu_to_be32(p.iremain), + .uncompressed_length = cpu_to_be32(p.oremain), + }; + + ret = decompress(ctx, &p, &g, &c, 0); + if (ret) + goto unlock; + + goto success; + } + + if (!hdr->groups) { + pr_err("header has no groups\n"); + ret = -EINVAL; + goto unlock; + } + if (hdr->groups > NX842_CRYPTO_GROUP_MAX) { + pr_err("header has too many groups %x, max %x\n", + hdr->groups, NX842_CRYPTO_GROUP_MAX); + ret = -EINVAL; + goto unlock; + } + + hdr_len = NX842_CRYPTO_HEADER_SIZE(hdr->groups); + if (hdr_len > slen) { + ret = -EOVERFLOW; + goto unlock; + } + + memcpy(&ctx->header, src, hdr_len); + hdr = &ctx->header; + + for (n = 0; n < hdr->groups; n++) { + /* ignore applies to last group */ + if (n + 1 == hdr->groups) + ignore = be16_to_cpu(hdr->ignore); + + ret = decompress(ctx, &p, &hdr->group[n], &c, ignore); + if (ret) + goto unlock; + } + +success: + *dlen = p.ototal; + + pr_debug("decompress total slen %x dlen %x\n", slen, *dlen); + + ret = 0; + +unlock: + spin_unlock_bh(&ctx->lock); + + return ret; +} + +static struct crypto_alg alg = { + .cra_name = "842", + .cra_driver_name = "842-nx", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct nx842_crypto_ctx), + .cra_module = THIS_MODULE, + .cra_init = nx842_crypto_init, + .cra_exit = nx842_crypto_exit, + .cra_u = { .compress = { + .coa_compress = nx842_crypto_compress, + .coa_decompress = nx842_crypto_decompress } } +}; + +static int __init nx842_crypto_mod_init(void) +{ + request_module("nx-compress-powernv"); + request_module("nx-compress-pseries"); + + /* we prevent loading/registering if there's no platform driver, + * and we get the platform module that set it so it won't unload, + * so we don't need to check if it's set in any of our functions + */ + if (!nx842_platform_driver_get()) { + pr_err("no nx842 platform driver found.\n"); + return -ENODEV; + } + + return crypto_register_alg(&alg); +} +module_init(nx842_crypto_mod_init); + +static void __exit nx842_crypto_mod_exit(void) +{ + crypto_unregister_alg(&alg); + + nx842_platform_driver_put(); +} +module_exit(nx842_crypto_mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("IBM PowerPC Nest (NX) 842 Hardware Compression Driver"); +MODULE_ALIAS_CRYPTO("842"); +MODULE_ALIAS_CRYPTO("842-nx"); +MODULE_AUTHOR("Dan Streetman "); -- cgit v1.3-6-gb490 From 03952d98015326a07ae1cf7adb4c43265ec4058f Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 22 Jul 2015 14:26:38 -0400 Subject: crypto: nx - make platform drivers directly register with crypto Remove the common 'platform' registration module, and move the crypto compression driver registration into each of the pSeries and PowerNV platform NX 842 drivers. Change the nx-842.c code into simple common functions that each platform driver uses to perform constraints-based buffer changes, i.e. realigning and/or resizing buffers to match the driver's hardware requirements. The common 'platform' module was my mistake to create - since each platform driver will only load/operate when running on its own platform (i.e. a pSeries platform or a PowerNV platform), they can directly register with the crypto subsystem, using the same alg and driver name. This removes unneeded complexity. Signed-off-by: Dan Streetman Signed-off-by: Herbert Xu --- drivers/crypto/nx/Makefile | 6 +-- drivers/crypto/nx/nx-842-platform.c | 84 ----------------------------- drivers/crypto/nx/nx-842-powernv.c | 29 ++++++++-- drivers/crypto/nx/nx-842-pseries.c | 38 ++++++++++--- drivers/crypto/nx/nx-842.c | 105 +++++++----------------------------- drivers/crypto/nx/nx-842.h | 43 ++++++++++++--- 6 files changed, 114 insertions(+), 191 deletions(-) delete mode 100644 drivers/crypto/nx/nx-842-platform.c (limited to 'drivers') diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile index ffcc86c44e15..b727821c8ed4 100644 --- a/drivers/crypto/nx/Makefile +++ b/drivers/crypto/nx/Makefile @@ -10,10 +10,8 @@ nx-crypto-objs := nx.o \ nx-sha256.o \ nx-sha512.o -obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o nx-compress-platform.o -obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_PSERIES) += nx-compress-pseries.o -obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_POWERNV) += nx-compress-powernv.o +obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_PSERIES) += nx-compress-pseries.o nx-compress.o +obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS_POWERNV) += nx-compress-powernv.o nx-compress.o nx-compress-objs := nx-842.o -nx-compress-platform-objs := nx-842-platform.o nx-compress-pseries-objs := nx-842-pseries.o nx-compress-powernv-objs := nx-842-powernv.o diff --git a/drivers/crypto/nx/nx-842-platform.c b/drivers/crypto/nx/nx-842-platform.c deleted file mode 100644 index 664f13dd06ed..000000000000 --- a/drivers/crypto/nx/nx-842-platform.c +++ /dev/null @@ -1,84 +0,0 @@ - -#include "nx-842.h" - -/* this is needed, separate from the main nx-842.c driver, because that main - * driver loads the platform drivers during its init(), and it expects one - * (or none) of the platform drivers to set this pointer to its driver. - * That means this pointer can't be in the main nx-842 driver, because it - * wouldn't be accessible until after the main driver loaded, which wouldn't - * be possible as it's waiting for the platform driver to load. So place it - * here. - */ -static struct nx842_driver *driver; -static DEFINE_SPINLOCK(driver_lock); - -struct nx842_driver *nx842_platform_driver(void) -{ - return driver; -} -EXPORT_SYMBOL_GPL(nx842_platform_driver); - -bool nx842_platform_driver_set(struct nx842_driver *_driver) -{ - bool ret = false; - - spin_lock(&driver_lock); - - if (!driver) { - driver = _driver; - ret = true; - } else - WARN(1, "can't set platform driver, already set to %s\n", - driver->name); - - spin_unlock(&driver_lock); - return ret; -} -EXPORT_SYMBOL_GPL(nx842_platform_driver_set); - -/* only call this from the platform driver exit function */ -void nx842_platform_driver_unset(struct nx842_driver *_driver) -{ - spin_lock(&driver_lock); - - if (driver == _driver) - driver = NULL; - else if (driver) - WARN(1, "can't unset platform driver %s, currently set to %s\n", - _driver->name, driver->name); - else - WARN(1, "can't unset platform driver, already unset\n"); - - spin_unlock(&driver_lock); -} -EXPORT_SYMBOL_GPL(nx842_platform_driver_unset); - -bool nx842_platform_driver_get(void) -{ - bool ret = false; - - spin_lock(&driver_lock); - - if (driver) - ret = try_module_get(driver->owner); - - spin_unlock(&driver_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(nx842_platform_driver_get); - -void nx842_platform_driver_put(void) -{ - spin_lock(&driver_lock); - - if (driver) - module_put(driver->owner); - - spin_unlock(&driver_lock); -} -EXPORT_SYMBOL_GPL(nx842_platform_driver_put); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Dan Streetman "); -MODULE_DESCRIPTION("842 H/W Compression platform driver"); diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c index 7e474562058d..684ce51d2d68 100644 --- a/drivers/crypto/nx/nx-842-powernv.c +++ b/drivers/crypto/nx/nx-842-powernv.c @@ -26,6 +26,8 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dan Streetman "); MODULE_DESCRIPTION("842 H/W Compression driver for IBM PowerNV processors"); +MODULE_ALIAS_CRYPTO("842"); +MODULE_ALIAS_CRYPTO("842-nx"); #define WORKMEM_ALIGN (CRB_ALIGN) #define CSB_WAIT_MAX (5000) /* ms */ @@ -581,9 +583,29 @@ static struct nx842_driver nx842_powernv_driver = { .decompress = nx842_powernv_decompress, }; +static int nx842_powernv_crypto_init(struct crypto_tfm *tfm) +{ + return nx842_crypto_init(tfm, &nx842_powernv_driver); +} + +static struct crypto_alg nx842_powernv_alg = { + .cra_name = "842", + .cra_driver_name = "842-nx", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct nx842_crypto_ctx), + .cra_module = THIS_MODULE, + .cra_init = nx842_powernv_crypto_init, + .cra_exit = nx842_crypto_exit, + .cra_u = { .compress = { + .coa_compress = nx842_crypto_compress, + .coa_decompress = nx842_crypto_decompress } } +}; + static __init int nx842_powernv_init(void) { struct device_node *dn; + int ret; /* verify workmem size/align restrictions */ BUILD_BUG_ON(WORKMEM_ALIGN % CRB_ALIGN); @@ -600,7 +622,8 @@ static __init int nx842_powernv_init(void) if (!nx842_ct) return -ENODEV; - if (!nx842_platform_driver_set(&nx842_powernv_driver)) { + ret = crypto_register_alg(&nx842_powernv_alg); + if (ret) { struct nx842_coproc *coproc, *n; list_for_each_entry_safe(coproc, n, &nx842_coprocs, list) { @@ -608,7 +631,7 @@ static __init int nx842_powernv_init(void) kfree(coproc); } - return -EEXIST; + return ret; } return 0; @@ -619,7 +642,7 @@ static void __exit nx842_powernv_exit(void) { struct nx842_coproc *coproc, *n; - nx842_platform_driver_unset(&nx842_powernv_driver); + crypto_unregister_alg(&nx842_powernv_alg); list_for_each_entry_safe(coproc, n, &nx842_coprocs, list) { list_del(&coproc->list); diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index 4b7bd8fb6a6b..b6a26907e11f 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c @@ -29,6 +29,8 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Robert Jennings "); MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors"); +MODULE_ALIAS_CRYPTO("842"); +MODULE_ALIAS_CRYPTO("842-nx"); static struct nx842_constraints nx842_pseries_constraints = { .alignment = DDE_BUFFER_ALIGN, @@ -957,6 +959,25 @@ static struct nx842_driver nx842_pseries_driver = { .decompress = nx842_pseries_decompress, }; +static int nx842_pseries_crypto_init(struct crypto_tfm *tfm) +{ + return nx842_crypto_init(tfm, &nx842_pseries_driver); +} + +static struct crypto_alg nx842_pseries_alg = { + .cra_name = "842", + .cra_driver_name = "842-nx", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct nx842_crypto_ctx), + .cra_module = THIS_MODULE, + .cra_init = nx842_pseries_crypto_init, + .cra_exit = nx842_crypto_exit, + .cra_u = { .compress = { + .coa_compress = nx842_crypto_compress, + .coa_decompress = nx842_crypto_decompress } } +}; + static int nx842_probe(struct vio_dev *viodev, const struct vio_device_id *id) { @@ -1002,6 +1023,12 @@ static int nx842_probe(struct vio_dev *viodev, if (ret) goto error; + ret = crypto_register_alg(&nx842_pseries_alg); + if (ret) { + dev_err(&viodev->dev, "could not register comp alg: %d\n", ret); + goto error; + } + rcu_read_lock(); dev_set_drvdata(&viodev->dev, rcu_dereference(devdata)); rcu_read_unlock(); @@ -1031,6 +1058,8 @@ static int nx842_remove(struct vio_dev *viodev) pr_info("Removing IBM Power 842 compression device\n"); sysfs_remove_group(&viodev->dev.kobj, &nx842_attribute_group); + crypto_unregister_alg(&nx842_pseries_alg); + spin_lock_irqsave(&devdata_mutex, flags); old_devdata = rcu_dereference_check(devdata, lockdep_is_held(&devdata_mutex)); @@ -1083,12 +1112,6 @@ static int __init nx842_pseries_init(void) return ret; } - if (!nx842_platform_driver_set(&nx842_pseries_driver)) { - vio_unregister_driver(&nx842_vio_driver); - kfree(new_devdata); - return -EEXIST; - } - return 0; } @@ -1099,7 +1122,8 @@ static void __exit nx842_pseries_exit(void) struct nx842_devdata *old_devdata; unsigned long flags; - nx842_platform_driver_unset(&nx842_pseries_driver); + crypto_unregister_alg(&nx842_pseries_alg); + spin_lock_irqsave(&devdata_mutex, flags); old_devdata = rcu_dereference_check(devdata, lockdep_is_held(&devdata_mutex)); diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 4472e2001e79..046c1c45411b 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c @@ -57,12 +57,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include #include #include -#include #include #include "nx-842.h" @@ -74,7 +70,6 @@ * buffer, and passed directly to the hardware to decompress. */ #define NX842_CRYPTO_MAGIC (0xf842) -#define NX842_CRYPTO_GROUP_MAX (0x20) #define NX842_CRYPTO_HEADER_SIZE(g) \ (sizeof(struct nx842_crypto_header) + \ sizeof(struct nx842_crypto_header_group) * (g)) @@ -90,19 +85,6 @@ #define COMP_BUSY_TIMEOUT (250) /* ms */ #define DECOMP_BUSY_TIMEOUT (50) /* ms */ -struct nx842_crypto_header_group { - __be16 padding; /* unused bytes at start of group */ - __be32 compressed_length; /* compressed bytes in group */ - __be32 uncompressed_length; /* bytes after decompression */ -} __packed; - -struct nx842_crypto_header { - __be16 magic; /* NX842_CRYPTO_MAGIC */ - __be16 ignore; /* decompressed end bytes to ignore */ - u8 groups; /* total groups in this header */ - struct nx842_crypto_header_group group[]; -} __packed; - struct nx842_crypto_param { u8 *in; unsigned int iremain; @@ -128,22 +110,13 @@ static int update_param(struct nx842_crypto_param *p, return 0; } -struct nx842_crypto_ctx { - spinlock_t lock; - - u8 *wmem; - u8 *sbounce, *dbounce; - - struct nx842_crypto_header header; - struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX]; -}; - -static int nx842_crypto_init(struct crypto_tfm *tfm) +int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver) { struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); spin_lock_init(&ctx->lock); - ctx->wmem = kmalloc(nx842_workmem_size(), GFP_KERNEL); + ctx->driver = driver; + ctx->wmem = kmalloc(driver->workmem_size, GFP_KERNEL); ctx->sbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); ctx->dbounce = (u8 *)__get_free_pages(GFP_KERNEL, BOUNCE_BUFFER_ORDER); if (!ctx->wmem || !ctx->sbounce || !ctx->dbounce) { @@ -155,8 +128,9 @@ static int nx842_crypto_init(struct crypto_tfm *tfm) return 0; } +EXPORT_SYMBOL_GPL(nx842_crypto_init); -static void nx842_crypto_exit(struct crypto_tfm *tfm) +void nx842_crypto_exit(struct crypto_tfm *tfm) { struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); @@ -164,6 +138,7 @@ static void nx842_crypto_exit(struct crypto_tfm *tfm) free_page((unsigned long)ctx->sbounce); free_page((unsigned long)ctx->dbounce); } +EXPORT_SYMBOL_GPL(nx842_crypto_exit); static void check_constraints(struct nx842_constraints *c) { @@ -250,9 +225,7 @@ nospc: timeout = ktime_add_ms(ktime_get(), COMP_BUSY_TIMEOUT); do { dlen = tmplen; /* reset dlen, if we're retrying */ - ret = nx842_platform_driver()->compress(src, slen, - dst, &dlen, - ctx->wmem); + ret = ctx->driver->compress(src, slen, dst, &dlen, ctx->wmem); /* possibly we should reduce the slen here, instead of * retrying with the dbounce buffer? */ @@ -282,14 +255,14 @@ nospc: return update_param(p, slen, dskip + dlen); } -static int nx842_crypto_compress(struct crypto_tfm *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen) +int nx842_crypto_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) { struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); struct nx842_crypto_header *hdr = &ctx->header; struct nx842_crypto_param p; - struct nx842_constraints c = *nx842_platform_driver()->constraints; + struct nx842_constraints c = *ctx->driver->constraints; unsigned int groups, hdrsize, h; int ret, n; bool add_header; @@ -366,6 +339,7 @@ unlock: spin_unlock_bh(&ctx->lock); return ret; } +EXPORT_SYMBOL_GPL(nx842_crypto_compress); static int decompress(struct nx842_crypto_ctx *ctx, struct nx842_crypto_param *p, @@ -429,9 +403,7 @@ static int decompress(struct nx842_crypto_ctx *ctx, timeout = ktime_add_ms(ktime_get(), DECOMP_BUSY_TIMEOUT); do { dlen = tmplen; /* reset dlen, if we're retrying */ - ret = nx842_platform_driver()->decompress(src, slen, - dst, &dlen, - ctx->wmem); + ret = ctx->driver->decompress(src, slen, dst, &dlen, ctx->wmem); } while (ret == -EBUSY && ktime_before(ktime_get(), timeout)); if (ret) { usesw: @@ -467,14 +439,14 @@ usesw: return update_param(p, slen + padding, dlen); } -static int nx842_crypto_decompress(struct crypto_tfm *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen) +int nx842_crypto_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) { struct nx842_crypto_ctx *ctx = crypto_tfm_ctx(tfm); struct nx842_crypto_header *hdr; struct nx842_crypto_param p; - struct nx842_constraints c = *nx842_platform_driver()->constraints; + struct nx842_constraints c = *ctx->driver->constraints; int n, ret, hdr_len; u16 ignore = 0; @@ -552,49 +524,8 @@ unlock: return ret; } - -static struct crypto_alg alg = { - .cra_name = "842", - .cra_driver_name = "842-nx", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, - .cra_ctxsize = sizeof(struct nx842_crypto_ctx), - .cra_module = THIS_MODULE, - .cra_init = nx842_crypto_init, - .cra_exit = nx842_crypto_exit, - .cra_u = { .compress = { - .coa_compress = nx842_crypto_compress, - .coa_decompress = nx842_crypto_decompress } } -}; - -static int __init nx842_crypto_mod_init(void) -{ - request_module("nx-compress-powernv"); - request_module("nx-compress-pseries"); - - /* we prevent loading/registering if there's no platform driver, - * and we get the platform module that set it so it won't unload, - * so we don't need to check if it's set in any of our functions - */ - if (!nx842_platform_driver_get()) { - pr_err("no nx842 platform driver found.\n"); - return -ENODEV; - } - - return crypto_register_alg(&alg); -} -module_init(nx842_crypto_mod_init); - -static void __exit nx842_crypto_mod_exit(void) -{ - crypto_unregister_alg(&alg); - - nx842_platform_driver_put(); -} -module_exit(nx842_crypto_mod_exit); +EXPORT_SYMBOL_GPL(nx842_crypto_decompress); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("IBM PowerPC Nest (NX) 842 Hardware Compression Driver"); -MODULE_ALIAS_CRYPTO("842"); -MODULE_ALIAS_CRYPTO("842-nx"); MODULE_AUTHOR("Dan Streetman "); diff --git a/drivers/crypto/nx/nx-842.h b/drivers/crypto/nx/nx-842.h index c7dd0a4391e0..a4eee3bba937 100644 --- a/drivers/crypto/nx/nx-842.h +++ b/drivers/crypto/nx/nx-842.h @@ -3,8 +3,9 @@ #define __NX_842_H__ #include +#include #include -#include +#include #include #include #include @@ -145,10 +146,40 @@ struct nx842_driver { void *wrkmem); }; -struct nx842_driver *nx842_platform_driver(void); -bool nx842_platform_driver_set(struct nx842_driver *driver); -void nx842_platform_driver_unset(struct nx842_driver *driver); -bool nx842_platform_driver_get(void); -void nx842_platform_driver_put(void); +struct nx842_crypto_header_group { + __be16 padding; /* unused bytes at start of group */ + __be32 compressed_length; /* compressed bytes in group */ + __be32 uncompressed_length; /* bytes after decompression */ +} __packed; + +struct nx842_crypto_header { + __be16 magic; /* NX842_CRYPTO_MAGIC */ + __be16 ignore; /* decompressed end bytes to ignore */ + u8 groups; /* total groups in this header */ + struct nx842_crypto_header_group group[]; +} __packed; + +#define NX842_CRYPTO_GROUP_MAX (0x20) + +struct nx842_crypto_ctx { + spinlock_t lock; + + u8 *wmem; + u8 *sbounce, *dbounce; + + struct nx842_crypto_header header; + struct nx842_crypto_header_group group[NX842_CRYPTO_GROUP_MAX]; + + struct nx842_driver *driver; +}; + +int nx842_crypto_init(struct crypto_tfm *tfm, struct nx842_driver *driver); +void nx842_crypto_exit(struct crypto_tfm *tfm); +int nx842_crypto_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); +int nx842_crypto_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen); #endif /* __NX_842_H__ */ -- cgit v1.3-6-gb490 From 9cba434f630a972b47327ae3d014445033166206 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 30 Apr 2015 11:50:55 -0700 Subject: ixgbevf: add support for reporting RSS key and hash table for X550 This patch extends the reporting of the RSS key and hash table by adding support for X550 VFs. The difference is that X550 VFs have their own registers for RSS key and indirection table, so there is no need to query the PF. The RSS key and indirection table are stored in the adapter structure during the configuration of VFRSSRK and VFRETA which in turn can be used in ethtool for reporting. The logic for writing VFRETA is also changed to make sure that the indirection table is reported correctly. In addition this patch adds defines for the VFRETA entries and number of VFRSSRK registers as well as some whitespace cleanups. Reported-by: Vlad Zolotarov Signed-off-by: Emil Tantilov Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ethtool.c | 51 +++++++++++++---------- drivers/net/ethernet/intel/ixgbevf/ixgbevf.h | 9 +++- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 21 ++++++---- 3 files changed, 47 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c index b2f5b161d792..d3e5f5b37999 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c +++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c @@ -813,22 +813,15 @@ static u32 ixgbevf_get_rxfh_indir_size(struct net_device *netdev) { struct ixgbevf_adapter *adapter = netdev_priv(netdev); - /* We support this operation only for 82599 and x540 at the moment */ - if (adapter->hw.mac.type < ixgbe_mac_X550_vf) - return IXGBEVF_82599_RETA_SIZE; + if (adapter->hw.mac.type >= ixgbe_mac_X550_vf) + return IXGBEVF_X550_VFRETA_SIZE; - return 0; + return IXGBEVF_82599_RETA_SIZE; } static u32 ixgbevf_get_rxfh_key_size(struct net_device *netdev) { - struct ixgbevf_adapter *adapter = netdev_priv(netdev); - - /* We support this operation only for 82599 and x540 at the moment */ - if (adapter->hw.mac.type < ixgbe_mac_X550_vf) - return IXGBEVF_RSS_HASH_KEY_SIZE; - - return 0; + return IXGBEVF_RSS_HASH_KEY_SIZE; } static int ixgbevf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, @@ -840,21 +833,33 @@ static int ixgbevf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, if (hfunc) *hfunc = ETH_RSS_HASH_TOP; - /* If neither indirection table nor hash key was requested - just - * return a success avoiding taking any locks. - */ - if (!indir && !key) - return 0; + if (adapter->hw.mac.type >= ixgbe_mac_X550_vf) { + if (key) + memcpy(key, adapter->rss_key, sizeof(adapter->rss_key)); - spin_lock_bh(&adapter->mbx_lock); - if (indir) - err = ixgbevf_get_reta_locked(&adapter->hw, indir, - adapter->num_rx_queues); + if (indir) { + int i; - if (!err && key) - err = ixgbevf_get_rss_key_locked(&adapter->hw, key); + for (i = 0; i < IXGBEVF_X550_VFRETA_SIZE; i++) + indir[i] = adapter->rss_indir_tbl[i]; + } + } else { + /* If neither indirection table nor hash key was requested + * - just return a success avoiding taking any locks. + */ + if (!indir && !key) + return 0; - spin_unlock_bh(&adapter->mbx_lock); + spin_lock_bh(&adapter->mbx_lock); + if (indir) + err = ixgbevf_get_reta_locked(&adapter->hw, indir, + adapter->num_rx_queues); + + if (!err && key) + err = ixgbevf_get_rss_key_locked(&adapter->hw, key); + + spin_unlock_bh(&adapter->mbx_lock); + } return err; } diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index 775d08900949..04c7ec8446e0 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -144,9 +144,11 @@ struct ixgbevf_ring { #define MAX_RX_QUEUES IXGBE_VF_MAX_RX_QUEUES #define MAX_TX_QUEUES IXGBE_VF_MAX_TX_QUEUES -#define IXGBEVF_MAX_RSS_QUEUES 2 -#define IXGBEVF_82599_RETA_SIZE 128 +#define IXGBEVF_MAX_RSS_QUEUES 2 +#define IXGBEVF_82599_RETA_SIZE 128 /* 128 entries */ +#define IXGBEVF_X550_VFRETA_SIZE 64 /* 64 entries */ #define IXGBEVF_RSS_HASH_KEY_SIZE 40 +#define IXGBEVF_VFRSSRK_REGS 10 /* 10 registers for RSS key */ #define IXGBEVF_DEFAULT_TXD 1024 #define IXGBEVF_DEFAULT_RXD 512 @@ -447,6 +449,9 @@ struct ixgbevf_adapter { spinlock_t mbx_lock; unsigned long last_reset; + + u32 rss_key[IXGBEVF_VFRSSRK_REGS]; + u8 rss_indir_tbl[IXGBEVF_X550_VFRETA_SIZE]; }; enum ixbgevf_state_t { diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index b2c86f1b8a9f..88298a3ef942 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -1696,22 +1696,25 @@ static void ixgbevf_setup_vfmrqc(struct ixgbevf_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; u32 vfmrqc = 0, vfreta = 0; - u32 rss_key[10]; u16 rss_i = adapter->num_rx_queues; - int i, j; + u8 i, j; /* Fill out hash function seeds */ - netdev_rss_key_fill(rss_key, sizeof(rss_key)); - for (i = 0; i < 10; i++) - IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), rss_key[i]); + netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key)); + for (i = 0; i < IXGBEVF_VFRSSRK_REGS; i++) + IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), adapter->rss_key[i]); - /* Fill out redirection table */ - for (i = 0, j = 0; i < 64; i++, j++) { + for (i = 0, j = 0; i < IXGBEVF_X550_VFRETA_SIZE; i++, j++) { if (j == rss_i) j = 0; - vfreta = (vfreta << 8) | (j * 0x1); - if ((i & 3) == 3) + + adapter->rss_indir_tbl[i] = j; + + vfreta |= j << (i & 0x3) * 8; + if ((i & 3) == 3) { IXGBE_WRITE_REG(hw, IXGBE_VFRETA(i >> 2), vfreta); + vfreta = 0; + } } /* Perform hash on these packet types */ -- cgit v1.3-6-gb490 From 06324e0cb28e06cd7cf609d7c3099b12841a5dd6 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 21 Jul 2015 11:07:23 -0700 Subject: HID: wacom: Perform all event processing as part of report processing In some cases, we need access to information before it becomes available to the 'event' handler. In particular, for some devices we cannot properly process the finger data without first knowing the "contact count" at the very end of the report (e.g. the Cintiq 24HDT touch screen, when forced through the GENERIC codepath). Since the HID subsystem doesn't provide a way to take action before 'event' is called, we take a cue from hid-multitouch.c and add a pre-process step within the 'report' handler that performs the same function. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 1 - drivers/hid/wacom_wac.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 2a221630d8dc..d932349277cd 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1690,7 +1690,6 @@ static struct hid_driver wacom_driver = { .id_table = wacom_ids, .probe = wacom_probe, .remove = wacom_remove, - .event = wacom_wac_event, .report = wacom_wac_report, #ifdef CONFIG_PM .resume = wacom_resume, diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index f5a0d3c64520..1d9d5d1d800d 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1437,6 +1437,12 @@ static int wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field, return 0; } +static void wacom_wac_pen_pre_report(struct hid_device *hdev, + struct hid_report *report) +{ + return; +} + static void wacom_wac_pen_report(struct hid_device *hdev, struct hid_report *report) { @@ -1564,6 +1570,12 @@ static int wacom_wac_finger_event(struct hid_device *hdev, return 0; } +static void wacom_wac_finger_pre_report(struct hid_device *hdev, + struct hid_report *report) +{ + return; +} + static void wacom_wac_finger_report(struct hid_device *hdev, struct hid_report *report) { @@ -1615,6 +1627,25 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, return 0; } +static void wacom_report_events(struct hid_device *hdev, struct hid_report *report) +{ + int r; + + for (r = 0; r < report->maxfield; r++) { + struct hid_field *field; + unsigned count, n; + + field = report->field[r]; + count = field->report_count; + + if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) + continue; + + for (n = 0; n < count; n++) + wacom_wac_event(hdev, field, &field->usage[n], field->value[n]); + } +} + void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) { struct wacom *wacom = hid_get_drvdata(hdev); @@ -1624,6 +1655,14 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) if (wacom_wac->features.type != HID_GENERIC) return; + if (WACOM_PEN_FIELD(field)) + wacom_wac_pen_pre_report(hdev, report); + + if (WACOM_FINGER_FIELD(field)) + wacom_wac_finger_pre_report(hdev, report); + + wacom_report_events(hdev, report); + if (WACOM_PEN_FIELD(field)) return wacom_wac_pen_report(hdev, report); -- cgit v1.3-6-gb490 From 1b5d514a3d24996ddbe7c75685af9dfdeff125b5 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 21 Jul 2015 11:07:24 -0700 Subject: HID: wacom: Ignore contacts in excess of declared contact count The reports sent from some touch devices (e.g. the Cintiq 24HDT) contain junk data in the contact slots which follow the final "valid" contact. To avoid forwarding it to usrspace, we store the reported contact count during the pre-process phase and then only process that many contacts. If a device sends its contacts across multiple reports (what Microsoft refers to as "hybrid" mode) then the contact count will be zero for reports other than the first. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 30 +++++++++++++++++++++++++++++- drivers/hid/wacom_wac.h | 4 ++++ 2 files changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 1d9d5d1d800d..09fe5d604c97 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1510,6 +1510,10 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, features->last_slot_field = usage->hid; wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0); break; + case HID_DG_CONTACTCOUNT: + wacom_wac->hid_data.cc_index = field->index; + wacom_wac->hid_data.cc_value_index = usage->usage_index; + break; } } @@ -1521,6 +1525,10 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac, bool prox = hid_data->tipswitch && !wacom_wac->shared->stylus_in_proximity; + wacom_wac->hid_data.num_received++; + if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected) + return; + if (mt) { int slot; @@ -1573,7 +1581,19 @@ static int wacom_wac_finger_event(struct hid_device *hdev, static void wacom_wac_finger_pre_report(struct hid_device *hdev, struct hid_report *report) { - return; + struct wacom *wacom = hid_get_drvdata(hdev); + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + struct hid_data* hid_data = &wacom_wac->hid_data; + + if (hid_data->cc_index >= 0) { + struct hid_field *field = report->field[hid_data->cc_index]; + int value = field->value[hid_data->cc_value_index]; + if (value) + hid_data->num_expected = value; + } + else { + hid_data->num_expected = wacom_wac->features.touch_max; + } } static void wacom_wac_finger_report(struct hid_device *hdev, @@ -1584,10 +1604,18 @@ static void wacom_wac_finger_report(struct hid_device *hdev, struct input_dev *input = wacom_wac->touch_input; unsigned touch_max = wacom_wac->features.touch_max; + /* If more packets of data are expected, give us a chance to + * process them rather than immediately syncing a partial + * update. + */ + if (wacom_wac->hid_data.num_received < wacom_wac->hid_data.num_expected) + return; + if (touch_max > 1) input_mt_sync_frame(input); input_sync(input); + wacom_wac->hid_data.num_received = 0; /* keep touch state for pen event */ wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac); diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 2978c303909d..c245a6628224 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -193,6 +193,10 @@ struct hid_data { int width; int height; int id; + int cc_index; + int cc_value_index; + int num_expected; + int num_received; }; struct wacom_wac { -- cgit v1.3-6-gb490 From 488abb5c70c19fd37264101d2b6ebee507e1f265 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 21 Jul 2015 11:07:25 -0700 Subject: HID: wacom: Report touch width/height/orientation for GENERIC devices The HID_DG_WIDTH and HID_DG_HEIGHT usages report with width and height of contacts. From this information, a crude determination of orientation is also possible. This patch reports all three to userspace if a device reports this usage. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 09fe5d604c97..280deb293ae2 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1497,6 +1497,13 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_POSITION_Y, 4); break; + case HID_DG_WIDTH: + case HID_DG_HEIGHT: + features->last_slot_field = usage->hid; + wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0); + wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0); + input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); + break; case HID_DG_CONTACTID: features->last_slot_field = usage->hid; break; @@ -1545,6 +1552,13 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac, hid_data->x); input_report_abs(input, mt ? ABS_MT_POSITION_Y : ABS_Y, hid_data->y); + + if (test_bit(ABS_MT_TOUCH_MAJOR, input->absbit)) { + input_report_abs(input, ABS_MT_TOUCH_MAJOR, max(hid_data->width, hid_data->height)); + input_report_abs(input, ABS_MT_TOUCH_MINOR, min(hid_data->width, hid_data->height)); + if (hid_data->width != hid_data->height) + input_report_abs(input, ABS_MT_ORIENTATION, hid_data->width <= hid_data->height ? 0 : 1); + } } } @@ -1561,6 +1575,12 @@ static int wacom_wac_finger_event(struct hid_device *hdev, case HID_GD_Y: wacom_wac->hid_data.y = value; break; + case HID_DG_WIDTH: + wacom_wac->hid_data.width = value; + break; + case HID_DG_HEIGHT: + wacom_wac->hid_data.height = value; + break; case HID_DG_CONTACTID: wacom_wac->hid_data.id = value; break; -- cgit v1.3-6-gb490 From 7faae96421870ed990b0a84797c6b2377e81d079 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Thu, 4 Jun 2015 21:07:27 +0800 Subject: e1000e: Cleanup qos request in error handling of e1000_open The driver lacks pm_qos_remove_request in error handling (err_req_irq) of e1000_open, and qos request inserted by pm_qos_add_request is not removed. This patch add pm_qos_remove_request in error handling to fix it. Signed-off-by: Jia-Ju Bai Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 89d788d8f263..fea1601f32a3 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -4588,6 +4588,7 @@ static int e1000_open(struct net_device *netdev) return 0; err_req_irq: + pm_qos_remove_request(&adapter->pm_qos_req); e1000e_release_hw_control(adapter); e1000_power_down_phy(adapter); e1000e_free_rx_resources(adapter->rx_ring); -- cgit v1.3-6-gb490 From 0c5bbeb8839172990e3b8aa82ae3c166e85a09bc Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Thu, 4 Jun 2015 14:26:56 -0700 Subject: igb: report unsupported ethtool settings in set_coalesce There are many settings possible using ethtool -C/--coalesce, but not all of them are supported in igb. Report failure when an unsupported option is set. Signed-off-by: Todd Fujinaka Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_ethtool.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 109cad928e71..b7b9c670bb3c 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -2159,6 +2159,27 @@ static int igb_set_coalesce(struct net_device *netdev, struct igb_adapter *adapter = netdev_priv(netdev); int i; + if (ec->rx_max_coalesced_frames || + ec->rx_coalesce_usecs_irq || + ec->rx_max_coalesced_frames_irq || + ec->tx_max_coalesced_frames || + ec->tx_coalesce_usecs_irq || + ec->stats_block_coalesce_usecs || + ec->use_adaptive_rx_coalesce || + ec->use_adaptive_tx_coalesce || + ec->pkt_rate_low || + ec->rx_coalesce_usecs_low || + ec->rx_max_coalesced_frames_low || + ec->tx_coalesce_usecs_low || + ec->tx_max_coalesced_frames_low || + ec->pkt_rate_high || + ec->rx_coalesce_usecs_high || + ec->rx_max_coalesced_frames_high || + ec->tx_coalesce_usecs_high || + ec->tx_max_coalesced_frames_high || + ec->rate_sample_interval) + return -ENOTSUPP; + if ((ec->rx_coalesce_usecs > IGB_MAX_ITR_USECS) || ((ec->rx_coalesce_usecs > 3) && (ec->rx_coalesce_usecs < IGB_MIN_ITR_USECS)) || -- cgit v1.3-6-gb490 From 9fa0452b645efdff439948a5cf448b8e497340e9 Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Tue, 30 Jun 2015 15:16:55 -0700 Subject: igb: use ARRAY_SIZE to replace calculating sizeof(a)/sizeof(a[0]) Use the ARRAY_SIZE macro rather than calculating sizeof(a)/sizeof(a[0]). Also directly replace the code rather than using an unnecessary define. Reported-by: Maninder Singh Reported-by: Joe Perches Signed-off-by: Todd Fujinaka Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_phy.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c index c1bb64d8366f..987c9de24764 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.c +++ b/drivers/net/ethernet/intel/igb/e1000_phy.c @@ -1,5 +1,5 @@ /* Intel(R) Gigabit Ethernet Linux driver - * Copyright(c) 2007-2014 Intel Corporation. + * Copyright(c) 2007-2015 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, @@ -36,9 +36,6 @@ static s32 igb_set_master_slave_mode(struct e1000_hw *hw); /* Cable length tables */ static const u16 e1000_m88_cable_length_table[] = { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; -#define M88E1000_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_m88_cable_length_table) / \ - sizeof(e1000_m88_cable_length_table[0])) static const u16 e1000_igp_2_cable_length_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, @@ -49,9 +46,6 @@ static const u16 e1000_igp_2_cable_length_table[] = { 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121, 124}; -#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_igp_2_cable_length_table) / \ - sizeof(e1000_igp_2_cable_length_table[0])) /** * igb_check_reset_block - Check if PHY reset is blocked @@ -1700,7 +1694,7 @@ s32 igb_get_cable_length_m88(struct e1000_hw *hw) index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> M88E1000_PSSR_CABLE_LENGTH_SHIFT; - if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) { + if (index >= ARRAY_SIZE(e1000_m88_cable_length_table) - 1) { ret_val = -E1000_ERR_PHY; goto out; } @@ -1796,7 +1790,7 @@ s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw) index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> M88E1000_PSSR_CABLE_LENGTH_SHIFT; - if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) { + if (index >= ARRAY_SIZE(e1000_m88_cable_length_table) - 1) { ret_val = -E1000_ERR_PHY; goto out; } @@ -1840,7 +1834,7 @@ s32 igb_get_cable_length_igp_2(struct e1000_hw *hw) s32 ret_val = 0; u16 phy_data, i, agc_value = 0; u16 cur_agc_index, max_agc_index = 0; - u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; + u16 min_agc_index = ARRAY_SIZE(e1000_igp_2_cable_length_table) - 1; static const u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = { IGP02E1000_PHY_AGC_A, IGP02E1000_PHY_AGC_B, @@ -1863,7 +1857,7 @@ s32 igb_get_cable_length_igp_2(struct e1000_hw *hw) IGP02E1000_AGC_LENGTH_MASK; /* Array index bound check. */ - if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || + if ((cur_agc_index >= ARRAY_SIZE(e1000_igp_2_cable_length_table)) || (cur_agc_index == 0)) { ret_val = -E1000_ERR_PHY; goto out; -- cgit v1.3-6-gb490 From 6fb469023cd995d7be5ab3bf12b79387710382ff Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Wed, 20 May 2015 15:40:20 -0700 Subject: igb: bump version to igb-5.3.0 Signed-off-by: Todd Fujinaka Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index fc7729e78f3d..41e274046896 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -57,8 +57,8 @@ #include "igb.h" #define MAJ 5 -#define MIN 2 -#define BUILD 18 +#define MIN 3 +#define BUILD 0 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ __stringify(BUILD) "-k" char igb_driver_name[] = "igb"; -- cgit v1.3-6-gb490 From de32e3efd58e9e6754e911618ac7941979ceb6b1 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Wed, 10 Jun 2015 13:42:07 -0400 Subject: i40e/i40evf: Fix and refactor dynamic ITR code This patch changes the switch statement for dynamic interrupt throttling and adds a default case. With this patch, we check the latency setting instead of the current ITR settings and the included refactor improves performance. Without this patch, the ITR setting would never change dynamically, and there was no default. Change-ID: Idb5a8a14c7109ec47c90f6e94bd43baa17d7ee37 Signed-off-by: Carolyn Wyborny Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 146 ++++++++++++++++---------- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 113 +++++++++++++------- 2 files changed, 161 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 1fe230d2be5d..a72278c265c2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -892,7 +892,7 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) * 20-1249MB/s bulk (8000 ints/s) */ bytes_per_int = rc->total_bytes / rc->itr; - switch (rc->itr) { + switch (new_latency_range) { case I40E_LOWEST_LATENCY: if (bytes_per_int > 10) new_latency_range = I40E_LOW_LATENCY; @@ -905,9 +905,14 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) break; case I40E_BULK_LATENCY: if (bytes_per_int <= 20) - rc->latency_range = I40E_LOW_LATENCY; + new_latency_range = I40E_LOW_LATENCY; + break; + default: + if (bytes_per_int <= 20) + new_latency_range = I40E_LOW_LATENCY; break; } + rc->latency_range = new_latency_range; switch (new_latency_range) { case I40E_LOWEST_LATENCY: @@ -923,41 +928,13 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) break; } - if (new_itr != rc->itr) { - /* do an exponential smoothing */ - new_itr = (10 * new_itr * rc->itr) / - ((9 * new_itr) + rc->itr); - rc->itr = new_itr & I40E_MAX_ITR; - } + if (new_itr != rc->itr) + rc->itr = new_itr; rc->total_bytes = 0; rc->total_packets = 0; } -/** - * i40e_update_dynamic_itr - Adjust ITR based on bytes per int - * @q_vector: the vector to adjust - **/ -static void i40e_update_dynamic_itr(struct i40e_q_vector *q_vector) -{ - u16 vector = q_vector->vsi->base_vector + q_vector->v_idx; - struct i40e_hw *hw = &q_vector->vsi->back->hw; - u32 reg_addr; - u16 old_itr; - - reg_addr = I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1); - old_itr = q_vector->rx.itr; - i40e_set_new_dynamic_itr(&q_vector->rx); - if (old_itr != q_vector->rx.itr) - wr32(hw, reg_addr, q_vector->rx.itr); - - reg_addr = I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1); - old_itr = q_vector->tx.itr; - i40e_set_new_dynamic_itr(&q_vector->tx); - if (old_itr != q_vector->tx.itr) - wr32(hw, reg_addr, q_vector->tx.itr); -} - /** * i40e_clean_programming_status - clean the programming status descriptor * @rx_ring: the rx ring that has this descriptor @@ -1826,6 +1803,68 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) return total_rx_packets; } +/** + * i40e_update_enable_itr - Update itr and re-enable MSIX interrupt + * @vsi: the VSI we care about + * @q_vector: q_vector for which itr is being updated and interrupt enabled + * + **/ +static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, + struct i40e_q_vector *q_vector) +{ + struct i40e_hw *hw = &vsi->back->hw; + u16 old_itr; + int vector; + u32 val; + + vector = (q_vector->v_idx + vsi->base_vector); + if (ITR_IS_DYNAMIC(vsi->rx_itr_setting)) { + old_itr = q_vector->rx.itr; + i40e_set_new_dynamic_itr(&q_vector->rx); + if (old_itr != q_vector->rx.itr) { + val = I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_RX_ITR << + I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) | + (q_vector->rx.itr << + I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT); + } else { + val = I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_ITR_NONE << + I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); + } + if (!test_bit(__I40E_DOWN, &vsi->state)) + wr32(hw, I40E_PFINT_DYN_CTLN(vector - 1), val); + } else { + i40e_irq_dynamic_enable(vsi, + q_vector->v_idx + vsi->base_vector); + } + if (ITR_IS_DYNAMIC(vsi->tx_itr_setting)) { + old_itr = q_vector->tx.itr; + i40e_set_new_dynamic_itr(&q_vector->tx); + if (old_itr != q_vector->tx.itr) { + val = I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_TX_ITR << + I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) | + (q_vector->tx.itr << + I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT); + } else { + val = I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_ITR_NONE << + I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); + } + if (!test_bit(__I40E_DOWN, &vsi->state)) + wr32(hw, I40E_PFINT_DYN_CTLN(q_vector->v_idx + + vsi->base_vector - 1), val); + } else { + i40e_irq_dynamic_enable(vsi, + q_vector->v_idx + vsi->base_vector); + } +} + /** * i40e_napi_poll - NAPI polling Rx/Tx cleanup routine * @napi: napi struct with our devices info in it @@ -1882,33 +1921,24 @@ int i40e_napi_poll(struct napi_struct *napi, int budget) /* Work is done so exit the polling mode and re-enable the interrupt */ napi_complete(napi); - if (ITR_IS_DYNAMIC(vsi->rx_itr_setting) || - ITR_IS_DYNAMIC(vsi->tx_itr_setting)) - i40e_update_dynamic_itr(q_vector); - - if (!test_bit(__I40E_DOWN, &vsi->state)) { - if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) { - i40e_irq_dynamic_enable(vsi, - q_vector->v_idx + vsi->base_vector); - } else { - struct i40e_hw *hw = &vsi->back->hw; - /* We re-enable the queue 0 cause, but - * don't worry about dynamic_enable - * because we left it on for the other - * possible interrupts during napi - */ - u32 qval = rd32(hw, I40E_QINT_RQCTL(0)); - qval |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; - wr32(hw, I40E_QINT_RQCTL(0), qval); - - qval = rd32(hw, I40E_QINT_TQCTL(0)); - qval |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; - wr32(hw, I40E_QINT_TQCTL(0), qval); - - i40e_irq_dynamic_enable_icr0(vsi->back); - } + if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) { + i40e_update_enable_itr(vsi, q_vector); + } else { /* Legacy mode */ + struct i40e_hw *hw = &vsi->back->hw; + /* We re-enable the queue 0 cause, but + * don't worry about dynamic_enable + * because we left it on for the other + * possible interrupts during napi + */ + u32 qval = rd32(hw, I40E_QINT_RQCTL(0)) | + I40E_QINT_RQCTL_CAUSE_ENA_MASK; + + wr32(hw, I40E_QINT_RQCTL(0), qval); + qval = rd32(hw, I40E_QINT_TQCTL(0)) | + I40E_QINT_TQCTL_CAUSE_ENA_MASK; + wr32(hw, I40E_QINT_TQCTL(0), qval); + i40e_irq_dynamic_enable_icr0(vsi->back); } - return 0; } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 0f0e185b5c66..cf3530335c68 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -404,7 +404,7 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) * 20-1249MB/s bulk (8000 ints/s) */ bytes_per_int = rc->total_bytes / rc->itr; - switch (rc->itr) { + switch (new_latency_range) { case I40E_LOWEST_LATENCY: if (bytes_per_int > 10) new_latency_range = I40E_LOW_LATENCY; @@ -417,9 +417,14 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) break; case I40E_BULK_LATENCY: if (bytes_per_int <= 20) - rc->latency_range = I40E_LOW_LATENCY; + new_latency_range = I40E_LOW_LATENCY; + break; + default: + if (bytes_per_int <= 20) + new_latency_range = I40E_LOW_LATENCY; break; } + rc->latency_range = new_latency_range; switch (new_latency_range) { case I40E_LOWEST_LATENCY: @@ -435,42 +440,14 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) break; } - if (new_itr != rc->itr) { - /* do an exponential smoothing */ - new_itr = (10 * new_itr * rc->itr) / - ((9 * new_itr) + rc->itr); - rc->itr = new_itr & I40E_MAX_ITR; - } + if (new_itr != rc->itr) + rc->itr = new_itr; rc->total_bytes = 0; rc->total_packets = 0; } -/** - * i40e_update_dynamic_itr - Adjust ITR based on bytes per int - * @q_vector: the vector to adjust - **/ -static void i40e_update_dynamic_itr(struct i40e_q_vector *q_vector) -{ - u16 vector = q_vector->vsi->base_vector + q_vector->v_idx; - struct i40e_hw *hw = &q_vector->vsi->back->hw; - u32 reg_addr; - u16 old_itr; - - reg_addr = I40E_VFINT_ITRN1(I40E_RX_ITR, vector - 1); - old_itr = q_vector->rx.itr; - i40e_set_new_dynamic_itr(&q_vector->rx); - if (old_itr != q_vector->rx.itr) - wr32(hw, reg_addr, q_vector->rx.itr); - - reg_addr = I40E_VFINT_ITRN1(I40E_TX_ITR, vector - 1); - old_itr = q_vector->tx.itr; - i40e_set_new_dynamic_itr(&q_vector->tx); - if (old_itr != q_vector->tx.itr) - wr32(hw, reg_addr, q_vector->tx.itr); -} - -/** +/* * i40evf_setup_tx_descriptors - Allocate the Tx descriptors * @tx_ring: the tx ring to set up * @@ -1280,6 +1257,68 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) return total_rx_packets; } +/** + * i40e_update_enable_itr - Update itr and re-enable MSIX interrupt + * @vsi: the VSI we care about + * @q_vector: q_vector for which itr is being updated and interrupt enabled + * + **/ +static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, + struct i40e_q_vector *q_vector) +{ + struct i40e_hw *hw = &vsi->back->hw; + u16 old_itr; + int vector; + u32 val; + + vector = (q_vector->v_idx + vsi->base_vector); + if (ITR_IS_DYNAMIC(vsi->rx_itr_setting)) { + old_itr = q_vector->rx.itr; + i40e_set_new_dynamic_itr(&q_vector->rx); + if (old_itr != q_vector->rx.itr) { + val = I40E_VFINT_DYN_CTLN_INTENA_MASK | + I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_RX_ITR << + I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT) | + (q_vector->rx.itr << + I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT); + } else { + val = I40E_VFINT_DYN_CTLN_INTENA_MASK | + I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_ITR_NONE << + I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT); + } + if (!test_bit(__I40E_DOWN, &vsi->state)) + wr32(hw, I40E_VFINT_DYN_CTLN1(vector - 1), val); + } else { + i40evf_irq_enable_queues(vsi->back, 1 + << q_vector->v_idx); + } + if (ITR_IS_DYNAMIC(vsi->tx_itr_setting)) { + old_itr = q_vector->tx.itr; + i40e_set_new_dynamic_itr(&q_vector->tx); + if (old_itr != q_vector->tx.itr) { + val = I40E_VFINT_DYN_CTLN_INTENA_MASK | + I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_TX_ITR << + I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT) | + (q_vector->tx.itr << + I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT); + + } else { + val = I40E_VFINT_DYN_CTLN_INTENA_MASK | + I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_ITR_NONE << + I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT); + } + if (!test_bit(__I40E_DOWN, &vsi->state)) + wr32(hw, I40E_VFINT_DYN_CTLN1(vector - 1), val); + } else { + i40evf_irq_enable_queues(vsi->back, + 1 << q_vector->v_idx); + } +} + /** * i40evf_napi_poll - NAPI polling Rx/Tx cleanup routine * @napi: napi struct with our devices info in it @@ -1336,13 +1375,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget) /* Work is done so exit the polling mode and re-enable the interrupt */ napi_complete(napi); - if (ITR_IS_DYNAMIC(vsi->rx_itr_setting) || - ITR_IS_DYNAMIC(vsi->tx_itr_setting)) - i40e_update_dynamic_itr(q_vector); - - if (!test_bit(__I40E_DOWN, &vsi->state)) - i40evf_irq_enable_queues(vsi->back, 1 << q_vector->v_idx); - + i40e_update_enable_itr(vsi, q_vector); return 0; } -- cgit v1.3-6-gb490 From 3b104be39e4a9ed2c0f6be56ceed4235262369b6 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 1 Jun 2015 19:33:03 +0000 Subject: i40e: clean up unneeded gotos With a little work we can clean up some unnecessary logic jumping and drop a variable. Signed-off-by: Shannon Nelson Cc: Laurent Navet Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_hmc.c | 37 ++++++++++-------------------- 1 file changed, 12 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_hmc.c index b89856a5e313..5ebe12d56ebf 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.c @@ -297,21 +297,15 @@ i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw, u32 idx, bool is_pf) { struct i40e_hmc_sd_entry *sd_entry; - i40e_status ret_code = 0; + + if (!is_pf) + return I40E_NOT_SUPPORTED; /* get the entry and decrease its ref counter */ sd_entry = &hmc_info->sd_table.sd_entry[idx]; - if (is_pf) { - I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT); - } else { - ret_code = I40E_NOT_SUPPORTED; - goto exit; - } - ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr)); - if (ret_code) - goto exit; -exit: - return ret_code; + I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT); + + return i40e_free_dma_mem(hw, &sd_entry->u.bp.addr); } /** @@ -351,20 +345,13 @@ i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, u32 idx, bool is_pf) { - i40e_status ret_code = 0; struct i40e_hmc_sd_entry *sd_entry; + if (!is_pf) + return I40E_NOT_SUPPORTED; + sd_entry = &hmc_info->sd_table.sd_entry[idx]; - if (is_pf) { - I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED); - } else { - ret_code = I40E_NOT_SUPPORTED; - goto exit; - } - /* free memory here */ - ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.pd_table.pd_page_addr)); - if (ret_code) - goto exit; -exit: - return ret_code; + I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED); + + return i40e_free_dma_mem(hw, &sd_entry->u.pd_table.pd_page_addr); } -- cgit v1.3-6-gb490 From 1b53c2fb43a0f03f7bb8a179d910e98a2fe68674 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:23:55 -0400 Subject: i40e: add VF capabilities to virtual channel interface To prepare for the changes coming up in the X722 device and future devices, the virtual channel interface has to change slightly. The VF driver can now report what its capable of supporting, which then informs the PF driver when it sends the configuration information back to the VF. A 1.1 VF driver on a 1.0 PF driver should not send its capabilities. Likewise, a 1.1 PF driver controlling a 1.0 VF driver should not expect or depend upon receiving the VF capabilities. All other aspects of the API are unchanged. Change-ID: I530cc55f107edd1ee8bdf95830aa90b87854058a Signed-off-by: Mitch Williams Acked-by: Shannon Nelson Acked-by: Anjali Singhai Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl.h | 16 +++++++++++----- drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h | 16 +++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h index 2d20af290fbf..a7ab463b4474 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h @@ -110,7 +110,9 @@ struct i40e_virtchnl_msg { * error regardless of version mismatch. */ #define I40E_VIRTCHNL_VERSION_MAJOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR 0 +#define I40E_VIRTCHNL_VERSION_MINOR 1 +#define I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS 0 + struct i40e_virtchnl_version_info { u32 major; u32 minor; @@ -129,7 +131,8 @@ struct i40e_virtchnl_version_info { */ /* I40E_VIRTCHNL_OP_GET_VF_RESOURCES - * VF sends this request to PF with no parameters + * Version 1.0 VF sends this request to PF with no parameters + * Version 1.1 VF sends this request to PF with u32 bitmap of its capabilities * PF responds with an indirect message containing * i40e_virtchnl_vf_resource and one or more * i40e_virtchnl_vsi_resource structures. @@ -143,9 +146,12 @@ struct i40e_virtchnl_vsi_resource { u8 default_mac_addr[ETH_ALEN]; }; /* VF offload flags */ -#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 -#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 -#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 +#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 +#define I40E_VIRTCHNL_VF_OFFLOAD_IWARP 0x00000002 +#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 +#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008 +#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010 +#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 struct i40e_virtchnl_vf_resource { u16 num_vsis; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h index 59f62f0e65dd..1e89dea0d529 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h @@ -110,7 +110,9 @@ struct i40e_virtchnl_msg { * error regardless of version mismatch. */ #define I40E_VIRTCHNL_VERSION_MAJOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR 0 +#define I40E_VIRTCHNL_VERSION_MINOR 1 +#define I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS 0 + struct i40e_virtchnl_version_info { u32 major; u32 minor; @@ -129,7 +131,8 @@ struct i40e_virtchnl_version_info { */ /* I40E_VIRTCHNL_OP_GET_VF_RESOURCES - * VF sends this request to PF with no parameters + * Version 1.0 VF sends this request to PF with no parameters + * Version 1.1 VF sends this request to PF with u32 bitmap of its capabilities * PF responds with an indirect message containing * i40e_virtchnl_vf_resource and one or more * i40e_virtchnl_vsi_resource structures. @@ -143,9 +146,12 @@ struct i40e_virtchnl_vsi_resource { u8 default_mac_addr[ETH_ALEN]; }; /* VF offload flags */ -#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 -#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 -#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 +#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 +#define I40E_VIRTCHNL_VF_OFFLOAD_IWARP 0x00000002 +#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 +#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008 +#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010 +#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 struct i40e_virtchnl_vf_resource { u16 num_vsis; -- cgit v1.3-6-gb490 From 17a65a7f8030c467193a6b774b6bbbbfc9d01f5c Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:23:56 -0400 Subject: i40e/i40evf: add macros for virtual channel API version and device capability Now that we've rolled the virtual channel API version to 1.1, add some macros to test what version is being used by our partner in crime. For the VF, add some macros to determine what our device capabilities are. Change-ID: I79f6683d4c23bd76a8ad9fd492776fcc1208e1dc Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 3 +++ drivers/net/ethernet/intel/i40evf/i40evf.h | 9 +++++++++ 2 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index 09043c1aae54..d254a5e4abf1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -42,6 +42,9 @@ #define I40E_VLAN_MASK 0xFFF #define I40E_PRIORITY_MASK 0x7000 +#define VF_IS_V10(_v) (((_v)->vf_ver.major == 1) && ((_v)->vf_ver.minor == 0)) +#define VF_IS_V11(_v) (((_v)->vf_ver.major == 1) && ((_v)->vf_ver.minor == 1)) + /* Various queue ctrls */ enum i40e_queue_ctrl { I40E_QUEUE_CTRL_UNKNOWN = 0, diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index fea3b75a9a35..f3bcd05f7ecf 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -249,8 +249,17 @@ struct i40evf_adapter { bool netdev_registered; bool link_up; enum i40e_virtchnl_ops current_op; +#define CLIENT_ENABLED(_a) ((_a)->vf_res->vf_offload_flags & \ + I40E_VIRTCHNL_VF_OFFLOAD_IWARP) +#define RSS_AQ(_a) ((_a)->vf_res->vf_offload_flags & \ + I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ) +#define VLAN_ALLOWED(_a) ((_a)->vf_res->vf_offload_flags & \ + I40E_VIRTCHNL_VF_OFFLOAD_VLAN) struct i40e_virtchnl_vf_resource *vf_res; /* incl. all VSIs */ struct i40e_virtchnl_vsi_resource *vsi_res; /* our LAN VSI */ + struct i40e_virtchnl_version_info pf_version; +#define PF_IS_V11(_a) (((_a)->pf_version.major == 1) && \ + ((_a)->pf_version.minor == 1)) u16 msg_enable; struct i40e_eth_stats current_stats; struct i40e_vsi vsi; -- cgit v1.3-6-gb490 From f4ca1a229535f1e7eb8253504c66e01e4623c278 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:23:57 -0400 Subject: i40e: support virtual channel API 1.1 Store off the VF API version for use when figuring out the VF driver capabilities. Add support for the VF driver handing its capabilities to the PF driver and then use this information when sending VF resource information back to the VF driver. Change-ID: Ic00d0eeeb5b8118085e12f068ef857089a8f7c2d Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 25 ++++++++++++++++------ drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 2 ++ 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index fdd7f5e3a66b..176a2898f1ad 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1121,12 +1121,13 @@ static int i40e_vc_send_resp_to_vf(struct i40e_vf *vf, * * called from the VF to request the API version used by the PF **/ -static int i40e_vc_get_version_msg(struct i40e_vf *vf) +static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg) { struct i40e_virtchnl_version_info info = { I40E_VIRTCHNL_VERSION_MAJOR, I40E_VIRTCHNL_VERSION_MINOR }; + vf->vf_ver = *(struct i40e_virtchnl_version_info *)msg; return i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, (u8 *)&info, sizeof(struct @@ -1141,7 +1142,7 @@ static int i40e_vc_get_version_msg(struct i40e_vf *vf) * * called from the VF to request its resources **/ -static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf) +static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) { struct i40e_virtchnl_vf_resource *vfres = NULL; struct i40e_pf *pf = vf->pf; @@ -1165,11 +1166,18 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf) len = 0; goto err; } + if (VF_IS_V11(vf)) + vf->driver_caps = *(u32 *)msg; + else + vf->driver_caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 | + I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | + I40E_VIRTCHNL_VF_OFFLOAD_VLAN; vfres->vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2; vsi = pf->vsi[vf->lan_vsi_idx]; if (!vsi->info.pvid) - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN; + vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN | + I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG; vfres->num_vsis = num_vsis; vfres->num_queue_pairs = vf->num_queue_pairs; @@ -1771,9 +1779,14 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, valid_len = sizeof(struct i40e_virtchnl_version_info); break; case I40E_VIRTCHNL_OP_RESET_VF: - case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: valid_len = 0; break; + case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: + if (VF_IS_V11(vf)) + valid_len = sizeof(u32); + else + valid_len = 0; + break; case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: valid_len = sizeof(struct i40e_virtchnl_txq_info); break; @@ -1886,10 +1899,10 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode, switch (v_opcode) { case I40E_VIRTCHNL_OP_VERSION: - ret = i40e_vc_get_version_msg(vf); + ret = i40e_vc_get_version_msg(vf, msg); break; case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: - ret = i40e_vc_get_vf_resources_msg(vf); + ret = i40e_vc_get_vf_resources_msg(vf, msg); break; case I40E_VIRTCHNL_OP_RESET_VF: i40e_vc_reset_vf_msg(vf); diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index d254a5e4abf1..736f6f08b4f2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -78,6 +78,8 @@ struct i40e_vf { u16 vf_id; /* all VF vsis connect to the same parent */ enum i40e_switch_element_types parent_type; + struct i40e_virtchnl_version_info vf_ver; + u32 driver_caps; /* reported by VF driver */ /* VF Port Extender (PE) stag if used */ u16 stag; -- cgit v1.3-6-gb490 From e6d038de13c82f8446d9db5b3d9bb7788344b2bd Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:23:58 -0400 Subject: i40evf: handle big resets The most common type of reset that the VF will encounter is a PF reset that cascades down into a VF reset for each VF. In this case, the VF will always be assigned the same VSI and recovery is fairly simple. However, in the case of 'bigger' resets, such as a Core or EMP reset, when the device is reinitialized, it's probable that the VF will NOT get the same VSI. When this happens, the VF will not be able to recover, as it will continue to request resources for its original VSI. Add an extra state to the admin queue state machine so that the driver can re-request its configuration information at runtime. During reset recovery, set this bit in the aq_required field, and fetch the (possibly new) configuration information before attempting to bring the driver back up. Since the driver doesn't know what kind of reset it has encountered, this step is done even for a PF reset, but it doesn't hurt anything - it just gets the same VSI back. Change-ID: I915d59ffb40375215117362f4ac7a37811aba748 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf.h | 2 + drivers/net/ethernet/intel/i40evf/i40evf_main.c | 109 +++++++++++++-------- .../net/ethernet/intel/i40evf/i40evf_virtchnl.c | 30 +++++- 3 files changed, 95 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index f3bcd05f7ecf..dfc5bc539890 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -234,6 +234,7 @@ struct i40evf_adapter { #define I40EVF_FLAG_AQ_CONFIGURE_QUEUES (u32)(1 << 6) #define I40EVF_FLAG_AQ_MAP_VECTORS (u32)(1 << 7) #define I40EVF_FLAG_AQ_HANDLE_RESET (u32)(1 << 8) +#define I40EVF_FLAG_AQ_GET_CONFIG (u32)(1 << 10) /* OS defined structs */ struct net_device *netdev; @@ -273,6 +274,7 @@ extern const char i40evf_driver_version[]; int i40evf_up(struct i40evf_adapter *adapter); void i40evf_down(struct i40evf_adapter *adapter); +int i40evf_process_config(struct i40evf_adapter *adapter); void i40evf_reset(struct i40evf_adapter *adapter); void i40evf_set_ethtool_ops(struct net_device *netdev); void i40evf_update_stats(struct i40evf_adapter *adapter); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index c698523923e4..7b9037123fe7 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1371,6 +1371,10 @@ static void i40evf_watchdog_task(struct work_struct *work) } goto watchdog_done; } + if (adapter->aq_required & I40EVF_FLAG_AQ_GET_CONFIG) { + i40evf_send_vf_config_msg(adapter); + goto watchdog_done; + } if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_QUEUES) { i40evf_disable_queues(adapter); @@ -1606,7 +1610,8 @@ continue_reset: dev_info(&adapter->pdev->dev, "Failed to init adminq: %d\n", err); - i40evf_map_queues(adapter); + adapter->aq_required = I40EVF_FLAG_AQ_GET_CONFIG; + adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS; /* re-add all MAC filters */ list_for_each_entry(f, &adapter->mac_filter_list, list) { @@ -1616,7 +1621,7 @@ continue_reset: list_for_each_entry(f, &adapter->vlan_filter_list, list) { f->add = true; } - adapter->aq_required = I40EVF_FLAG_AQ_ADD_MAC_FILTER; + adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER; clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); i40evf_misc_irq_enable(adapter); @@ -1981,6 +1986,62 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw) return -EBUSY; } +/** + * i40evf_process_config - Process the config information we got from the PF + * @adapter: board private structure + * + * Verify that we have a valid config struct, and set up our netdev features + * and our VSI struct. + **/ +int i40evf_process_config(struct i40evf_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i; + + /* got VF config message back from PF, now we can parse it */ + for (i = 0; i < adapter->vf_res->num_vsis; i++) { + if (adapter->vf_res->vsi_res[i].vsi_type == I40E_VSI_SRIOV) + adapter->vsi_res = &adapter->vf_res->vsi_res[i]; + } + if (!adapter->vsi_res) { + dev_err(&adapter->pdev->dev, "No LAN VSI found\n"); + return -ENODEV; + } + + if (adapter->vf_res->vf_offload_flags + & I40E_VIRTCHNL_VF_OFFLOAD_VLAN) { + netdev->vlan_features = netdev->features; + netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_HW_VLAN_CTAG_FILTER; + } + netdev->features |= NETIF_F_HIGHDMA | + NETIF_F_SG | + NETIF_F_IP_CSUM | + NETIF_F_SCTP_CSUM | + NETIF_F_IPV6_CSUM | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_RXCSUM | + NETIF_F_GRO; + + /* copy netdev features into list of user selectable features */ + netdev->hw_features |= netdev->features; + netdev->hw_features &= ~NETIF_F_RXCSUM; + + adapter->vsi.id = adapter->vsi_res->vsi_id; + + adapter->vsi.back = adapter; + adapter->vsi.base_vector = 1; + adapter->vsi.work_limit = I40E_DEFAULT_IRQ_WORK; + adapter->vsi.rx_itr_setting = (I40E_ITR_DYNAMIC | + ITR_REG_TO_USEC(I40E_ITR_RX_DEF)); + adapter->vsi.tx_itr_setting = (I40E_ITR_DYNAMIC | + ITR_REG_TO_USEC(I40E_ITR_TX_DEF)); + adapter->vsi.netdev = adapter->netdev; + return 0; +} + /** * i40evf_init_task - worker thread to perform delayed initialization * @work: pointer to work_struct containing our data @@ -2001,7 +2062,7 @@ static void i40evf_init_task(struct work_struct *work) struct net_device *netdev = adapter->netdev; struct i40e_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; - int i, err, bufsz; + int err, bufsz; switch (adapter->state) { case __I40EVF_STARTUP: @@ -2087,42 +2148,15 @@ static void i40evf_init_task(struct work_struct *work) default: goto err_alloc; } - /* got VF config message back from PF, now we can parse it */ - for (i = 0; i < adapter->vf_res->num_vsis; i++) { - if (adapter->vf_res->vsi_res[i].vsi_type == I40E_VSI_SRIOV) - adapter->vsi_res = &adapter->vf_res->vsi_res[i]; - } - if (!adapter->vsi_res) { - dev_err(&pdev->dev, "No LAN VSI found\n"); + if (i40evf_process_config(adapter)) goto err_alloc; - } + adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED; netdev->netdev_ops = &i40evf_netdev_ops; i40evf_set_ethtool_ops(netdev); netdev->watchdog_timeo = 5 * HZ; - netdev->features |= NETIF_F_HIGHDMA | - NETIF_F_SG | - NETIF_F_IP_CSUM | - NETIF_F_SCTP_CSUM | - NETIF_F_IPV6_CSUM | - NETIF_F_TSO | - NETIF_F_TSO6 | - NETIF_F_RXCSUM | - NETIF_F_GRO; - - if (adapter->vf_res->vf_offload_flags - & I40E_VIRTCHNL_VF_OFFLOAD_VLAN) { - netdev->vlan_features = netdev->features; - netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | - NETIF_F_HW_VLAN_CTAG_RX | - 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 %pM, using random\n", @@ -2153,17 +2187,6 @@ static void i40evf_init_task(struct work_struct *work) netif_carrier_off(netdev); - adapter->vsi.id = adapter->vsi_res->vsi_id; - adapter->vsi.seid = adapter->vsi_res->vsi_id; /* dummy */ - adapter->vsi.back = adapter; - adapter->vsi.base_vector = 1; - adapter->vsi.work_limit = I40E_DEFAULT_IRQ_WORK; - adapter->vsi.rx_itr_setting = (I40E_ITR_DYNAMIC | - ITR_REG_TO_USEC(I40E_ITR_RX_DEF)); - adapter->vsi.tx_itr_setting = (I40E_ITR_DYNAMIC | - ITR_REG_TO_USEC(I40E_ITR_TX_DEF)); - adapter->vsi.netdev = adapter->netdev; - if (!adapter->netdev_registered) { err = register_netdev(netdev); if (err) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 61e090558f31..a37d56b275c1 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -145,8 +145,24 @@ out: **/ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter) { - return i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, - NULL, 0); + u32 caps; + + adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES; + adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG; + caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 | + I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ | + I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | + I40E_VIRTCHNL_VF_OFFLOAD_VLAN; + adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES; + adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG; + if (PF_IS_V11(adapter)) + return i40evf_send_pf_msg(adapter, + I40E_VIRTCHNL_OP_GET_VF_RESOURCES, + (u8 *)&caps, sizeof(caps)); + else + return i40evf_send_pf_msg(adapter, + I40E_VIRTCHNL_OP_GET_VF_RESOURCES, + NULL, 0); } /** @@ -729,6 +745,15 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, adapter->current_stats = *stats; } break; + case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: { + u16 len = sizeof(struct i40e_virtchnl_vf_resource) + + I40E_MAX_VF_VSI * + sizeof(struct i40e_virtchnl_vsi_resource); + memcpy(adapter->vf_res, msg, min(msglen, len)); + i40e_vf_parse_hw_config(&adapter->hw, adapter->vf_res); + i40evf_process_config(adapter); + } + break; case I40E_VIRTCHNL_OP_ENABLE_QUEUES: /* enable transmits */ i40evf_irq_enable(adapter, true); @@ -740,7 +765,6 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, i40evf_free_all_rx_resources(adapter); break; case I40E_VIRTCHNL_OP_VERSION: - case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: /* Don't display an error if we get these out of sequence. * If the firmware needed to get kicked, we'll get these and -- cgit v1.3-6-gb490 From ee1693e5a5ad6cfd701381a1d04cc1878bb90724 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:23:59 -0400 Subject: i40evf: support virtual channel API version 1.1 Store off the PF's API version, then use it to determine whether or not to send it our capabilities. Change the version checking to allow for PF drivers with lower API versions than our current version, so we can still talk to PF drivers over the 1.0 API. Change-ID: I8edc55d1229c7decf0ed3f285a63032694007c2e Signed-off-by: Mitch Williams Tested-by: Jim young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 6 ++++++ drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 7b9037123fe7..f43ac9c7e826 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2113,6 +2113,12 @@ static void i40evf_init_task(struct work_struct *work) if (err) { if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) err = i40evf_send_api_ver(adapter); + else + dev_err(&pdev->dev, "Unsupported PF API version %d.%d, expected %d.%d\n", + adapter->pf_version.major, + adapter->pf_version.minor, + I40E_VIRTCHNL_VERSION_MAJOR, + I40E_VIRTCHNL_VERSION_MINOR); goto err; } err = i40evf_send_vf_config_msg(adapter); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index a37d56b275c1..52c695939319 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -125,8 +125,11 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) } pf_vvi = (struct i40e_virtchnl_version_info *)event.msg_buf; - if ((pf_vvi->major != I40E_VIRTCHNL_VERSION_MAJOR) || - (pf_vvi->minor != I40E_VIRTCHNL_VERSION_MINOR)) + adapter->pf_version = *pf_vvi; + + if ((pf_vvi->major > I40E_VIRTCHNL_VERSION_MAJOR) || + ((pf_vvi->major == I40E_VIRTCHNL_VERSION_MAJOR) && + (pf_vvi->minor > I40E_VIRTCHNL_VERSION_MINOR))) err = -EIO; out_alloc: -- cgit v1.3-6-gb490 From 606a5488a18788c374e797643678a3c82621bf59 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:24:00 -0400 Subject: i40e: provide correct API version to older VF drivers This driver fully supports VF drivers using both the 1.0 and 1.1 versions of the virtual channel API. However, VF drivers using version 1.0 get upset if we provide them with a version other than that, and refuse to play with us. Correct this by checking the VFs API version at the time that we store it off, and provide the correct version number back to the VF so we can all get along. Change-ID: I86dfe02e67b2bef336b4b49a1bb072f3e7229abc Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 176a2898f1ad..51aff7072195 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1128,6 +1128,9 @@ static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg) }; vf->vf_ver = *(struct i40e_virtchnl_version_info *)msg; + /* VFs running the 1.0 API expect to get 1.0 back or they will cry. */ + if (VF_IS_V10(vf)) + info.minor = I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS; return i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, (u8 *)&info, sizeof(struct -- cgit v1.3-6-gb490 From f1c7e72e3903910d7cc25ed8f45b9ef42b96037d Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Thu, 4 Jun 2015 16:24:01 -0400 Subject: i40e: clean up error status messages Clean up a little confusion in reporting error status in phy and fcoe setup error reports by separating the return status from the AQ error. Add two decoder functions to make this easier. Change-ID: I960bcdeef3978a15fec1cdb5eff781d5cbae42fb Signed-off-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 206 +++++++++++ drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 30 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 392 ++++++++++++--------- drivers/net/ethernet/intel/i40e/i40e_prototype.h | 2 + drivers/net/ethernet/intel/i40e/i40e_type.h | 1 + drivers/net/ethernet/intel/i40evf/i40e_common.c | 206 +++++++++++ drivers/net/ethernet/intel/i40evf/i40e_prototype.h | 2 + drivers/net/ethernet/intel/i40evf/i40e_type.h | 1 + .../net/ethernet/intel/i40evf/i40evf_virtchnl.c | 10 +- 9 files changed, 673 insertions(+), 177 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 07032229ee60..8f2ecbe5e62c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -71,6 +71,212 @@ static i40e_status i40e_set_mac_type(struct i40e_hw *hw) return status; } +/** + * i40e_aq_str - convert AQ err code to a string + * @hw: pointer to the HW structure + * @aq_err: the AQ error code to convert + **/ +char *i40e_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err) +{ + switch (aq_err) { + case I40E_AQ_RC_OK: + return "OK"; + case I40E_AQ_RC_EPERM: + return "I40E_AQ_RC_EPERM"; + case I40E_AQ_RC_ENOENT: + return "I40E_AQ_RC_ENOENT"; + case I40E_AQ_RC_ESRCH: + return "I40E_AQ_RC_ESRCH"; + case I40E_AQ_RC_EINTR: + return "I40E_AQ_RC_EINTR"; + case I40E_AQ_RC_EIO: + return "I40E_AQ_RC_EIO"; + case I40E_AQ_RC_ENXIO: + return "I40E_AQ_RC_ENXIO"; + case I40E_AQ_RC_E2BIG: + return "I40E_AQ_RC_E2BIG"; + case I40E_AQ_RC_EAGAIN: + return "I40E_AQ_RC_EAGAIN"; + case I40E_AQ_RC_ENOMEM: + return "I40E_AQ_RC_ENOMEM"; + case I40E_AQ_RC_EACCES: + return "I40E_AQ_RC_EACCES"; + case I40E_AQ_RC_EFAULT: + return "I40E_AQ_RC_EFAULT"; + case I40E_AQ_RC_EBUSY: + return "I40E_AQ_RC_EBUSY"; + case I40E_AQ_RC_EEXIST: + return "I40E_AQ_RC_EEXIST"; + case I40E_AQ_RC_EINVAL: + return "I40E_AQ_RC_EINVAL"; + case I40E_AQ_RC_ENOTTY: + return "I40E_AQ_RC_ENOTTY"; + case I40E_AQ_RC_ENOSPC: + return "I40E_AQ_RC_ENOSPC"; + case I40E_AQ_RC_ENOSYS: + return "I40E_AQ_RC_ENOSYS"; + case I40E_AQ_RC_ERANGE: + return "I40E_AQ_RC_ERANGE"; + case I40E_AQ_RC_EFLUSHED: + return "I40E_AQ_RC_EFLUSHED"; + case I40E_AQ_RC_BAD_ADDR: + return "I40E_AQ_RC_BAD_ADDR"; + case I40E_AQ_RC_EMODE: + return "I40E_AQ_RC_EMODE"; + case I40E_AQ_RC_EFBIG: + return "I40E_AQ_RC_EFBIG"; + } + + snprintf(hw->err_str, sizeof(hw->err_str), "%d", aq_err); + return hw->err_str; +} + +/** + * i40e_stat_str - convert status err code to a string + * @hw: pointer to the HW structure + * @stat_err: the status error code to convert + **/ +char *i40e_stat_str(struct i40e_hw *hw, i40e_status stat_err) +{ + switch (stat_err) { + case 0: + return "OK"; + case I40E_ERR_NVM: + return "I40E_ERR_NVM"; + case I40E_ERR_NVM_CHECKSUM: + return "I40E_ERR_NVM_CHECKSUM"; + case I40E_ERR_PHY: + return "I40E_ERR_PHY"; + case I40E_ERR_CONFIG: + return "I40E_ERR_CONFIG"; + case I40E_ERR_PARAM: + return "I40E_ERR_PARAM"; + case I40E_ERR_MAC_TYPE: + return "I40E_ERR_MAC_TYPE"; + case I40E_ERR_UNKNOWN_PHY: + return "I40E_ERR_UNKNOWN_PHY"; + case I40E_ERR_LINK_SETUP: + return "I40E_ERR_LINK_SETUP"; + case I40E_ERR_ADAPTER_STOPPED: + return "I40E_ERR_ADAPTER_STOPPED"; + case I40E_ERR_INVALID_MAC_ADDR: + return "I40E_ERR_INVALID_MAC_ADDR"; + case I40E_ERR_DEVICE_NOT_SUPPORTED: + return "I40E_ERR_DEVICE_NOT_SUPPORTED"; + case I40E_ERR_MASTER_REQUESTS_PENDING: + return "I40E_ERR_MASTER_REQUESTS_PENDING"; + case I40E_ERR_INVALID_LINK_SETTINGS: + return "I40E_ERR_INVALID_LINK_SETTINGS"; + case I40E_ERR_AUTONEG_NOT_COMPLETE: + return "I40E_ERR_AUTONEG_NOT_COMPLETE"; + case I40E_ERR_RESET_FAILED: + return "I40E_ERR_RESET_FAILED"; + case I40E_ERR_SWFW_SYNC: + return "I40E_ERR_SWFW_SYNC"; + case I40E_ERR_NO_AVAILABLE_VSI: + return "I40E_ERR_NO_AVAILABLE_VSI"; + case I40E_ERR_NO_MEMORY: + return "I40E_ERR_NO_MEMORY"; + case I40E_ERR_BAD_PTR: + return "I40E_ERR_BAD_PTR"; + case I40E_ERR_RING_FULL: + return "I40E_ERR_RING_FULL"; + case I40E_ERR_INVALID_PD_ID: + return "I40E_ERR_INVALID_PD_ID"; + case I40E_ERR_INVALID_QP_ID: + return "I40E_ERR_INVALID_QP_ID"; + case I40E_ERR_INVALID_CQ_ID: + return "I40E_ERR_INVALID_CQ_ID"; + case I40E_ERR_INVALID_CEQ_ID: + return "I40E_ERR_INVALID_CEQ_ID"; + case I40E_ERR_INVALID_AEQ_ID: + return "I40E_ERR_INVALID_AEQ_ID"; + case I40E_ERR_INVALID_SIZE: + return "I40E_ERR_INVALID_SIZE"; + case I40E_ERR_INVALID_ARP_INDEX: + return "I40E_ERR_INVALID_ARP_INDEX"; + case I40E_ERR_INVALID_FPM_FUNC_ID: + return "I40E_ERR_INVALID_FPM_FUNC_ID"; + case I40E_ERR_QP_INVALID_MSG_SIZE: + return "I40E_ERR_QP_INVALID_MSG_SIZE"; + case I40E_ERR_QP_TOOMANY_WRS_POSTED: + return "I40E_ERR_QP_TOOMANY_WRS_POSTED"; + case I40E_ERR_INVALID_FRAG_COUNT: + return "I40E_ERR_INVALID_FRAG_COUNT"; + case I40E_ERR_QUEUE_EMPTY: + return "I40E_ERR_QUEUE_EMPTY"; + case I40E_ERR_INVALID_ALIGNMENT: + return "I40E_ERR_INVALID_ALIGNMENT"; + case I40E_ERR_FLUSHED_QUEUE: + return "I40E_ERR_FLUSHED_QUEUE"; + case I40E_ERR_INVALID_PUSH_PAGE_INDEX: + return "I40E_ERR_INVALID_PUSH_PAGE_INDEX"; + case I40E_ERR_INVALID_IMM_DATA_SIZE: + return "I40E_ERR_INVALID_IMM_DATA_SIZE"; + case I40E_ERR_TIMEOUT: + return "I40E_ERR_TIMEOUT"; + case I40E_ERR_OPCODE_MISMATCH: + return "I40E_ERR_OPCODE_MISMATCH"; + case I40E_ERR_CQP_COMPL_ERROR: + return "I40E_ERR_CQP_COMPL_ERROR"; + case I40E_ERR_INVALID_VF_ID: + return "I40E_ERR_INVALID_VF_ID"; + case I40E_ERR_INVALID_HMCFN_ID: + return "I40E_ERR_INVALID_HMCFN_ID"; + case I40E_ERR_BACKING_PAGE_ERROR: + return "I40E_ERR_BACKING_PAGE_ERROR"; + case I40E_ERR_NO_PBLCHUNKS_AVAILABLE: + return "I40E_ERR_NO_PBLCHUNKS_AVAILABLE"; + case I40E_ERR_INVALID_PBLE_INDEX: + return "I40E_ERR_INVALID_PBLE_INDEX"; + case I40E_ERR_INVALID_SD_INDEX: + return "I40E_ERR_INVALID_SD_INDEX"; + case I40E_ERR_INVALID_PAGE_DESC_INDEX: + return "I40E_ERR_INVALID_PAGE_DESC_INDEX"; + case I40E_ERR_INVALID_SD_TYPE: + return "I40E_ERR_INVALID_SD_TYPE"; + case I40E_ERR_MEMCPY_FAILED: + return "I40E_ERR_MEMCPY_FAILED"; + case I40E_ERR_INVALID_HMC_OBJ_INDEX: + return "I40E_ERR_INVALID_HMC_OBJ_INDEX"; + case I40E_ERR_INVALID_HMC_OBJ_COUNT: + return "I40E_ERR_INVALID_HMC_OBJ_COUNT"; + case I40E_ERR_INVALID_SRQ_ARM_LIMIT: + return "I40E_ERR_INVALID_SRQ_ARM_LIMIT"; + case I40E_ERR_SRQ_ENABLED: + return "I40E_ERR_SRQ_ENABLED"; + case I40E_ERR_ADMIN_QUEUE_ERROR: + return "I40E_ERR_ADMIN_QUEUE_ERROR"; + case I40E_ERR_ADMIN_QUEUE_TIMEOUT: + return "I40E_ERR_ADMIN_QUEUE_TIMEOUT"; + case I40E_ERR_BUF_TOO_SHORT: + return "I40E_ERR_BUF_TOO_SHORT"; + case I40E_ERR_ADMIN_QUEUE_FULL: + return "I40E_ERR_ADMIN_QUEUE_FULL"; + case I40E_ERR_ADMIN_QUEUE_NO_WORK: + return "I40E_ERR_ADMIN_QUEUE_NO_WORK"; + case I40E_ERR_BAD_IWARP_CQE: + return "I40E_ERR_BAD_IWARP_CQE"; + case I40E_ERR_NVM_BLANK_MODE: + return "I40E_ERR_NVM_BLANK_MODE"; + case I40E_ERR_NOT_IMPLEMENTED: + return "I40E_ERR_NOT_IMPLEMENTED"; + case I40E_ERR_PE_DOORBELL_NOT_ENABLED: + return "I40E_ERR_PE_DOORBELL_NOT_ENABLED"; + case I40E_ERR_DIAG_TEST_FAILED: + return "I40E_ERR_DIAG_TEST_FAILED"; + case I40E_ERR_NOT_READY: + return "I40E_ERR_NOT_READY"; + case I40E_NOT_SUPPORTED: + return "I40E_NOT_SUPPORTED"; + case I40E_ERR_FIRMWARE_API_VERSION: + return "I40E_ERR_FIRMWARE_API_VERSION"; + } + + snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err); + return hw->err_str; +} + /** * i40e_debug_aq * @hw: debug mask related to admin queue diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index f2075d5b800c..4b06a27ab799 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -681,15 +681,17 @@ static int i40e_set_settings(struct net_device *netdev, /* make the aq call */ status = i40e_aq_set_phy_config(hw, &config, NULL); if (status) { - netdev_info(netdev, "Set phy config failed with error %d.\n", - status); + netdev_info(netdev, "Set phy config failed, err %s aq_err %s\n", + i40e_stat_str(hw, status), + i40e_aq_str(hw, hw->aq.asq_last_status)); return -EAGAIN; } status = i40e_aq_get_link_info(hw, true, NULL, NULL); if (status) - netdev_info(netdev, "Updating link info failed with error %d\n", - status); + netdev_info(netdev, "Updating link info failed with err %s aq_err %s\n", + i40e_stat_str(hw, status), + i40e_aq_str(hw, hw->aq.asq_last_status)); } else { netdev_info(netdev, "Nothing changed, exiting without setting anything.\n"); @@ -709,8 +711,9 @@ static int i40e_nway_reset(struct net_device *netdev) ret = i40e_aq_set_link_restart_an(hw, link_up, NULL); if (ret) { - netdev_info(netdev, "link restart failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); + netdev_info(netdev, "link restart failed, err %s aq_err %s\n", + i40e_stat_str(hw, ret), + i40e_aq_str(hw, hw->aq.asq_last_status)); return -EIO; } @@ -822,18 +825,21 @@ static int i40e_set_pauseparam(struct net_device *netdev, status = i40e_set_fc(hw, &aq_failures, link_up); if (aq_failures & I40E_SET_FC_AQ_FAIL_GET) { - netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with error %d and status %d\n", - status, hw->aq.asq_last_status); + netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with err %s aq_err %s\n", + i40e_stat_str(hw, status), + i40e_aq_str(hw, hw->aq.asq_last_status)); err = -EAGAIN; } if (aq_failures & I40E_SET_FC_AQ_FAIL_SET) { - netdev_info(netdev, "Set fc failed on the set_phy_config call with error %d and status %d\n", - status, hw->aq.asq_last_status); + netdev_info(netdev, "Set fc failed on the set_phy_config call with err %s aq_err %s\n", + i40e_stat_str(hw, status), + i40e_aq_str(hw, hw->aq.asq_last_status)); err = -EAGAIN; } if (aq_failures & I40E_SET_FC_AQ_FAIL_UPDATE) { - netdev_info(netdev, "Set fc failed on the get_link_info call with error %d and status %d\n", - status, hw->aq.asq_last_status); + netdev_info(netdev, "Set fc failed on the get_link_info call with err %s aq_err %s\n", + i40e_stat_str(hw, status), + i40e_aq_str(hw, hw->aq.asq_last_status)); err = -EAGAIN; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6ce9086e558a..7646297e0981 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1276,7 +1276,7 @@ static int i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr) { struct i40e_aqc_remove_macvlan_element_data element; struct i40e_pf *pf = vsi->back; - i40e_status aq_ret; + i40e_status ret; /* Only appropriate for the PF main VSI */ if (vsi->type != I40E_VSI_MAIN) @@ -1287,8 +1287,8 @@ static int i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr) element.vlan_tag = 0; element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH | I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; - aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL); - if (aq_ret) + ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL); + if (ret) return -ENOENT; return 0; @@ -1728,10 +1728,11 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) bool add_happened = false; int filter_list_len = 0; u32 changed_flags = 0; - i40e_status aq_ret = 0; + i40e_status ret = 0; struct i40e_pf *pf; int num_add = 0; int num_del = 0; + int aq_err = 0; u16 cmd_flags; /* empty array typed pointers, kcalloc later */ @@ -1783,31 +1784,31 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) /* flush a full buffer */ if (num_del == filter_list_len) { - aq_ret = i40e_aq_remove_macvlan(&pf->hw, - vsi->seid, del_list, num_del, - NULL); + ret = i40e_aq_remove_macvlan(&pf->hw, + vsi->seid, del_list, num_del, + NULL); + aq_err = pf->hw.aq.asq_last_status; num_del = 0; memset(del_list, 0, sizeof(*del_list)); - if (aq_ret && - pf->hw.aq.asq_last_status != - I40E_AQ_RC_ENOENT) + if (ret && aq_err != I40E_AQ_RC_ENOENT) dev_info(&pf->pdev->dev, - "ignoring delete macvlan error, err %d, aq_err %d while flushing a full buffer\n", - aq_ret, - pf->hw.aq.asq_last_status); + "ignoring delete macvlan error, err %s, aq_err %s while flushing a full buffer\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, aq_err)); } } if (num_del) { - aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, + ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, del_list, num_del, NULL); + aq_err = pf->hw.aq.asq_last_status; num_del = 0; - if (aq_ret && - pf->hw.aq.asq_last_status != I40E_AQ_RC_ENOENT) + if (ret && aq_err != I40E_AQ_RC_ENOENT) dev_info(&pf->pdev->dev, - "ignoring delete macvlan error, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "ignoring delete macvlan error, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, aq_err)); } kfree(del_list); @@ -1845,29 +1846,31 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) /* flush a full buffer */ if (num_add == filter_list_len) { - aq_ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid, - add_list, num_add, - NULL); + ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid, + add_list, num_add, + NULL); + aq_err = pf->hw.aq.asq_last_status; num_add = 0; - if (aq_ret) + if (ret) break; memset(add_list, 0, sizeof(*add_list)); } } if (num_add) { - aq_ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid, - add_list, num_add, NULL); + ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid, + add_list, num_add, NULL); + aq_err = pf->hw.aq.asq_last_status; num_add = 0; } kfree(add_list); add_list = NULL; - if (add_happened && aq_ret && - pf->hw.aq.asq_last_status != I40E_AQ_RC_EINVAL) { + if (add_happened && ret && aq_err != I40E_AQ_RC_EINVAL) { dev_info(&pf->pdev->dev, - "add filter failed, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "add filter failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, aq_err)); if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOSPC) && !test_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state)) { @@ -1883,34 +1886,40 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) if (changed_flags & IFF_ALLMULTI) { bool cur_multipromisc; cur_multipromisc = !!(vsi->current_netdev_flags & IFF_ALLMULTI); - aq_ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw, - vsi->seid, - cur_multipromisc, - NULL); - if (aq_ret) + ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw, + vsi->seid, + cur_multipromisc, + NULL); + if (ret) dev_info(&pf->pdev->dev, - "set multi promisc failed, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "set multi promisc failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); } if ((changed_flags & IFF_PROMISC) || promisc_forced_on) { bool cur_promisc; cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) || test_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state)); - aq_ret = i40e_aq_set_vsi_unicast_promiscuous(&vsi->back->hw, - vsi->seid, - cur_promisc, NULL); - if (aq_ret) + ret = i40e_aq_set_vsi_unicast_promiscuous(&vsi->back->hw, + vsi->seid, + cur_promisc, NULL); + if (ret) dev_info(&pf->pdev->dev, - "set uni promisc failed, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); - aq_ret = i40e_aq_set_vsi_broadcast(&vsi->back->hw, - vsi->seid, - cur_promisc, NULL); - if (aq_ret) + "set uni promisc failed, err %s, aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); + ret = i40e_aq_set_vsi_broadcast(&vsi->back->hw, + vsi->seid, + cur_promisc, NULL); + if (ret) dev_info(&pf->pdev->dev, - "set brdcast promisc failed, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "set brdcast promisc failed, err %s, aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); } clear_bit(__I40E_CONFIG_BUSY, &vsi->state); @@ -2006,8 +2015,10 @@ void i40e_vlan_stripping_enable(struct i40e_vsi *vsi) ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); if (ret) { dev_info(&vsi->back->pdev->dev, - "%s: update vsi failed, aq_err=%d\n", - __func__, vsi->back->hw.aq.asq_last_status); + "update vlan stripping failed, err %s aq_err %s\n", + i40e_stat_str(&vsi->back->hw, ret), + i40e_aq_str(&vsi->back->hw, + vsi->back->hw.aq.asq_last_status)); } } @@ -2035,8 +2046,10 @@ void i40e_vlan_stripping_disable(struct i40e_vsi *vsi) ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); if (ret) { dev_info(&vsi->back->pdev->dev, - "%s: update vsi failed, aq_err=%d\n", - __func__, vsi->back->hw.aq.asq_last_status); + "update vlan stripping failed, err %s aq_err %s\n", + i40e_stat_str(&vsi->back->hw, ret), + i40e_aq_str(&vsi->back->hw, + vsi->back->hw.aq.asq_last_status)); } } @@ -2306,7 +2319,7 @@ static void i40e_restore_vlan(struct i40e_vsi *vsi) int i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid) { struct i40e_vsi_context ctxt; - i40e_status aq_ret; + i40e_status ret; vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID); vsi->info.pvid = cpu_to_le16(vid); @@ -2316,11 +2329,13 @@ int i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid) ctxt.seid = vsi->seid; ctxt.info = vsi->info; - aq_ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); - if (aq_ret) { + ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); + if (ret) { dev_info(&vsi->back->pdev->dev, - "%s: update vsi failed, aq_err=%d\n", - __func__, vsi->back->hw.aq.asq_last_status); + "add pvid failed, err %s aq_err %s\n", + i40e_stat_str(&vsi->back->hw, ret), + i40e_aq_str(&vsi->back->hw, + vsi->back->hw.aq.asq_last_status)); return -ENOENT; } @@ -4233,26 +4248,28 @@ static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi) struct i40e_aqc_query_vsi_bw_config_resp bw_config = {0}; struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; - i40e_status aq_ret; + i40e_status ret; u32 tc_bw_max; int i; /* Get the VSI level BW configuration */ - aq_ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL); - if (aq_ret) { + ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL); + if (ret) { dev_info(&pf->pdev->dev, - "couldn't get PF vsi bw config, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "couldn't get PF vsi bw config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return -EINVAL; } /* Get the VSI level BW configuration per TC */ - aq_ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, &bw_ets_config, - NULL); - if (aq_ret) { + ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, &bw_ets_config, + NULL); + if (ret) { dev_info(&pf->pdev->dev, - "couldn't get PF vsi ets bw config, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "couldn't get PF vsi ets bw config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return -EINVAL; } @@ -4291,16 +4308,16 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc, u8 *bw_share) { struct i40e_aqc_configure_vsi_tc_bw_data bw_data; - i40e_status aq_ret; + i40e_status ret; int i; bw_data.tc_valid_bits = enabled_tc; for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) bw_data.tc_bw_credits[i] = bw_share[i]; - aq_ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid, &bw_data, - NULL); - if (aq_ret) { + ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid, &bw_data, + NULL); + if (ret) { dev_info(&vsi->back->pdev->dev, "AQ command Config VSI BW allocation per TC failed = %d\n", vsi->back->hw.aq.asq_last_status); @@ -4435,8 +4452,10 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc) ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); if (ret) { dev_info(&vsi->back->pdev->dev, - "update vsi failed, aq_err=%d\n", - vsi->back->hw.aq.asq_last_status); + "Update vsi tc config failed, err %s aq_err %s\n", + i40e_stat_str(&vsi->back->hw, ret), + i40e_aq_str(&vsi->back->hw, + vsi->back->hw.aq.asq_last_status)); goto out; } /* update the local VSI info with updated queue map */ @@ -4447,8 +4466,10 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc) ret = i40e_vsi_get_bw_info(vsi); if (ret) { dev_info(&vsi->back->pdev->dev, - "Failed updating vsi bw info, aq_err=%d\n", - vsi->back->hw.aq.asq_last_status); + "Failed updating vsi bw info, err %s aq_err %s\n", + i40e_stat_str(&vsi->back->hw, ret), + i40e_aq_str(&vsi->back->hw, + vsi->back->hw.aq.asq_last_status)); goto out; } @@ -4489,8 +4510,9 @@ int i40e_veb_config_tc(struct i40e_veb *veb, u8 enabled_tc) &bw_data, NULL); if (ret) { dev_info(&pf->pdev->dev, - "veb bw config failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); + "VEB bw config failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); goto out; } @@ -4498,8 +4520,9 @@ int i40e_veb_config_tc(struct i40e_veb *veb, u8 enabled_tc) ret = i40e_veb_get_bw_info(veb); if (ret) { dev_info(&pf->pdev->dev, - "Failed getting veb bw config, aq_err=%d\n", - pf->hw.aq.asq_last_status); + "Failed getting veb bw config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); } out: @@ -4586,8 +4609,9 @@ static int i40e_resume_port_tx(struct i40e_pf *pf) ret = i40e_aq_resume_port_tx(hw, NULL); if (ret) { dev_info(&pf->pdev->dev, - "AQ command Resume Port Tx failed = %d\n", - pf->hw.aq.asq_last_status); + "Resume Port Tx failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); /* Schedule PF reset to recover */ set_bit(__I40E_PF_RESET_REQUESTED, &pf->state); i40e_service_event_schedule(pf); @@ -4639,8 +4663,9 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) } } else { dev_info(&pf->pdev->dev, - "AQ Querying DCB configuration failed: aq_err %d\n", - pf->hw.aq.asq_last_status); + "Query for DCB configuration failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); } out: @@ -5265,7 +5290,10 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf, /* Get updated DCBX data from firmware */ ret = i40e_get_dcb_config(&pf->hw); if (ret) { - dev_info(&pf->pdev->dev, "Failed querying DCB configuration data from firmware.\n"); + dev_info(&pf->pdev->dev, + "Failed querying DCB configuration data from firmware, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); goto exit; } @@ -5995,27 +6023,29 @@ static void i40e_enable_pf_switch_lb(struct i40e_pf *pf) { struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; struct i40e_vsi_context ctxt; - int aq_ret; + int ret; ctxt.seid = pf->main_vsi_seid; ctxt.pf_num = pf->hw.pf_id; ctxt.vf_num = 0; - aq_ret = i40e_aq_get_vsi_params(&pf->hw, &ctxt, NULL); - if (aq_ret) { + ret = i40e_aq_get_vsi_params(&pf->hw, &ctxt, NULL); + if (ret) { dev_info(&pf->pdev->dev, - "%s couldn't get PF vsi config, err %d, aq_err %d\n", - __func__, aq_ret, pf->hw.aq.asq_last_status); + "couldn't get PF vsi config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return; } ctxt.flags = I40E_AQ_VSI_TYPE_PF; ctxt.info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID); ctxt.info.switch_id |= cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB); - aq_ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); - if (aq_ret) { + ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); + if (ret) { dev_info(&pf->pdev->dev, - "%s: update vsi switch failed, aq_err=%d\n", - __func__, vsi->back->hw.aq.asq_last_status); + "update vsi switch failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); } } @@ -6029,27 +6059,29 @@ static void i40e_disable_pf_switch_lb(struct i40e_pf *pf) { struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; struct i40e_vsi_context ctxt; - int aq_ret; + int ret; ctxt.seid = pf->main_vsi_seid; ctxt.pf_num = pf->hw.pf_id; ctxt.vf_num = 0; - aq_ret = i40e_aq_get_vsi_params(&pf->hw, &ctxt, NULL); - if (aq_ret) { + ret = i40e_aq_get_vsi_params(&pf->hw, &ctxt, NULL); + if (ret) { dev_info(&pf->pdev->dev, - "%s couldn't get PF vsi config, err %d, aq_err %d\n", - __func__, aq_ret, pf->hw.aq.asq_last_status); + "couldn't get PF vsi config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return; } ctxt.flags = I40E_AQ_VSI_TYPE_PF; ctxt.info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID); ctxt.info.switch_id &= ~cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB); - aq_ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); - if (aq_ret) { + ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); + if (ret) { dev_info(&pf->pdev->dev, - "%s: update vsi switch failed, aq_err=%d\n", - __func__, vsi->back->hw.aq.asq_last_status); + "update vsi switch failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); } } @@ -6109,7 +6141,8 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb) ret = i40e_add_vsi(ctl_vsi); if (ret) { dev_info(&pf->pdev->dev, - "rebuild of owner VSI failed: %d\n", ret); + "rebuild of veb_idx %d owner VSI failed: %d\n", + veb->idx, ret); goto end_reconstitute; } i40e_vsi_reset_stats(ctl_vsi); @@ -6188,8 +6221,10 @@ static int i40e_get_capabilities(struct i40e_pf *pf) buf_len = data_size; } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { dev_info(&pf->pdev->dev, - "capability discovery failed: aq=%d\n", - pf->hw.aq.asq_last_status); + "capability discovery failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); return -ENODEV; } } while (err); @@ -6375,7 +6410,9 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) /* rebuild the basics for the AdminQ, HMC, and initial HW switch */ ret = i40e_init_adminq(&pf->hw); if (ret) { - dev_info(&pf->pdev->dev, "Rebuild AdminQ failed, %d\n", ret); + dev_info(&pf->pdev->dev, "Rebuild AdminQ failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); goto clear_recovery; } @@ -6385,11 +6422,8 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) i40e_clear_pxe_mode(hw); ret = i40e_get_capabilities(pf); - if (ret) { - dev_info(&pf->pdev->dev, "i40e_get_capabilities failed, %d\n", - ret); + if (ret) goto end_core_reset; - } ret = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, hw->func_caps.num_rx_qp, @@ -6430,12 +6464,16 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL); if (ret) - dev_info(&pf->pdev->dev, "set phy mask fail, aq_err %d\n", ret); + dev_info(&pf->pdev->dev, "set phy mask fail, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); /* make sure our flow control settings are restored */ ret = i40e_set_fc(&pf->hw, &set_fc_aq_fail, true); if (ret) - dev_info(&pf->pdev->dev, "set fc fail, aq_err %d\n", ret); + dev_info(&pf->pdev->dev, "set fc fail, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); /* Rebuild the VSIs and VEBs that existed before reset. * They are still in our local switch element arrays, so only @@ -6496,8 +6534,10 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) msleep(75); ret = i40e_aq_set_link_restart_an(&pf->hw, true, NULL); if (ret) - dev_info(&pf->pdev->dev, "link restart failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); + dev_info(&pf->pdev->dev, "link restart failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); } /* reinit the misc interrupt */ if (pf->flags & I40E_FLAG_MSIX_ENABLED) @@ -6671,10 +6711,12 @@ static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf) if (ret) { dev_info(&pf->pdev->dev, - "%s vxlan port %d, index %d failed, err %d, aq_err %d\n", + "%s vxlan port %d, index %d failed, err %s aq_err %s\n", port ? "add" : "delete", - ntohs(port), i, ret, - pf->hw.aq.asq_last_status); + ntohs(port), i, + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); pf->vxlan_ports[i] = 0; } } @@ -7579,8 +7621,9 @@ i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf) last_aq_status = pf->hw.aq.asq_last_status; if (ret) { dev_info(&pf->pdev->dev, - "Cannot acquire NVM for read access, err %d: aq_err %d\n", - ret, last_aq_status); + "Cannot acquire NVM for read access, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, last_aq_status)); goto bw_commit_out; } @@ -7595,8 +7638,9 @@ i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf) last_aq_status = pf->hw.aq.asq_last_status; i40e_release_nvm(&pf->hw); if (ret) { - dev_info(&pf->pdev->dev, "NVM read error, err %d aq_err %d\n", - ret, last_aq_status); + dev_info(&pf->pdev->dev, "NVM read error, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, last_aq_status)); goto bw_commit_out; } @@ -7608,8 +7652,9 @@ i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf) last_aq_status = pf->hw.aq.asq_last_status; if (ret) { dev_info(&pf->pdev->dev, - "Cannot acquire NVM for write access, err %d: aq_err %d\n", - ret, last_aq_status); + "Cannot acquire NVM for write access, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, last_aq_status)); goto bw_commit_out; } /* Write it back out unchanged to initiate update NVM, @@ -7627,8 +7672,9 @@ i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf) i40e_release_nvm(&pf->hw); if (ret) dev_info(&pf->pdev->dev, - "BW settings NOT SAVED, err %d aq_err %d\n", - ret, last_aq_status); + "BW settings NOT SAVED, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, last_aq_status)); bw_commit_out: return ret; @@ -8328,8 +8374,10 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ctxt.flags = I40E_AQ_VSI_TYPE_PF; if (ret) { dev_info(&pf->pdev->dev, - "couldn't get PF vsi config, err %d, aq_err %d\n", - ret, pf->hw.aq.asq_last_status); + "couldn't get PF vsi config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); return -ENOENT; } vsi->info = ctxt.info; @@ -8351,8 +8399,10 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); if (ret) { dev_info(&pf->pdev->dev, - "update vsi failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); + "update vsi failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); ret = -ENOENT; goto err; } @@ -8369,9 +8419,11 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ret = i40e_vsi_config_tc(vsi, enabled_tc); if (ret) { dev_info(&pf->pdev->dev, - "failed to configure TCs for main VSI tc_map 0x%08x, err %d, aq_err %d\n", - enabled_tc, ret, - pf->hw.aq.asq_last_status); + "failed to configure TCs for main VSI tc_map 0x%08x, err %s aq_err %s\n", + enabled_tc, + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); ret = -ENOENT; } } @@ -8462,8 +8514,10 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ret = i40e_aq_add_vsi(hw, &ctxt, NULL); if (ret) { dev_info(&vsi->back->pdev->dev, - "add vsi failed, aq_err=%d\n", - vsi->back->hw.aq.asq_last_status); + "add vsi failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); ret = -ENOENT; goto err; } @@ -8508,8 +8562,9 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ret = i40e_vsi_get_bw_info(vsi); if (ret) { dev_info(&pf->pdev->dev, - "couldn't get vsi bw info, err %d, aq_err %d\n", - ret, pf->hw.aq.asq_last_status); + "couldn't get vsi bw info, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); /* VSI is already added so not tearing that up */ ret = 0; } @@ -8682,7 +8737,7 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi) ret = i40e_get_lump(pf, pf->qp_pile, vsi->alloc_queue_pairs, vsi->idx); if (ret < 0) { dev_info(&pf->pdev->dev, - "failed to get tracking for %d queues for VSI %d err=%d\n", + "failed to get tracking for %d queues for VSI %d err %d\n", vsi->alloc_queue_pairs, vsi->seid, ret); goto err_vsi; } @@ -8920,8 +8975,9 @@ static int i40e_veb_get_bw_info(struct i40e_veb *veb) &bw_data, NULL); if (ret) { dev_info(&pf->pdev->dev, - "query veb bw config failed, aq_err=%d\n", - hw->aq.asq_last_status); + "query veb bw config failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, hw->aq.asq_last_status)); goto out; } @@ -8929,8 +8985,9 @@ static int i40e_veb_get_bw_info(struct i40e_veb *veb) &ets_data, NULL); if (ret) { dev_info(&pf->pdev->dev, - "query veb bw ets config failed, aq_err=%d\n", - hw->aq.asq_last_status); + "query veb bw ets config failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, hw->aq.asq_last_status)); goto out; } @@ -9114,36 +9171,40 @@ void i40e_veb_release(struct i40e_veb *veb) **/ static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi) { + struct i40e_pf *pf = veb->pf; bool is_default = false; bool is_cloud = false; int ret; /* get a VEB from the hardware */ - ret = i40e_aq_add_veb(&veb->pf->hw, veb->uplink_seid, vsi->seid, + ret = i40e_aq_add_veb(&pf->hw, veb->uplink_seid, vsi->seid, veb->enabled_tc, is_default, is_cloud, &veb->seid, NULL); if (ret) { - dev_info(&veb->pf->pdev->dev, - "couldn't add VEB, err %d, aq_err %d\n", - ret, veb->pf->hw.aq.asq_last_status); + dev_info(&pf->pdev->dev, + "couldn't add VEB, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return -EPERM; } /* get statistics counter */ - ret = i40e_aq_get_veb_parameters(&veb->pf->hw, veb->seid, NULL, NULL, + ret = i40e_aq_get_veb_parameters(&pf->hw, veb->seid, NULL, NULL, &veb->stats_idx, NULL, NULL, NULL); if (ret) { - dev_info(&veb->pf->pdev->dev, - "couldn't get VEB statistics idx, err %d, aq_err %d\n", - ret, veb->pf->hw.aq.asq_last_status); + dev_info(&pf->pdev->dev, + "couldn't get VEB statistics idx, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return -EPERM; } ret = i40e_veb_get_bw_info(veb); if (ret) { - dev_info(&veb->pf->pdev->dev, - "couldn't get VEB bw info, err %d, aq_err %d\n", - ret, veb->pf->hw.aq.asq_last_status); - i40e_aq_delete_element(&veb->pf->hw, veb->seid, NULL); + dev_info(&pf->pdev->dev, + "couldn't get VEB bw info, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); + i40e_aq_delete_element(&pf->hw, veb->seid, NULL); return -ENOENT; } @@ -9349,8 +9410,10 @@ int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig) &next_seid, NULL); if (ret) { dev_info(&pf->pdev->dev, - "get switch config failed %d aq_err=%x\n", - ret, pf->hw.aq.asq_last_status); + "get switch config failed err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); kfree(aq_buf); return -ENOENT; } @@ -9391,8 +9454,9 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) ret = i40e_fetch_switch_configuration(pf, false); if (ret) { dev_info(&pf->pdev->dev, - "couldn't fetch switch config, err %d, aq_err %d\n", - ret, pf->hw.aq.asq_last_status); + "couldn't fetch switch config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return ret; } i40e_pf_reset_stats(pf); @@ -9935,15 +9999,19 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL); if (err) - dev_info(&pf->pdev->dev, "set phy mask fail, aq_err %d\n", err); + dev_info(&pf->pdev->dev, "set phy mask fail, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) || (pf->hw.aq.fw_maj_ver < 4)) { msleep(75); err = i40e_aq_set_link_restart_an(&pf->hw, true, NULL); if (err) - dev_info(&pf->pdev->dev, "link restart failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); + dev_info(&pf->pdev->dev, "link restart failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); } /* The main driver is (mostly) up and happy. We need to set this state * before setting up the misc vector or we get a race and the vector @@ -10031,8 +10099,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* get the requested speeds from the fw */ err = i40e_aq_get_phy_capabilities(hw, false, false, &abilities, NULL); if (err) - dev_info(&pf->pdev->dev, "get phy abilities failed, aq_err %d, advertised speed settings may not be correct\n", - err); + dev_info(&pf->pdev->dev, + "get phy capabilities failed, err %s aq_err %s, advertised speed settings may not be correct\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); pf->hw.phy.link_info.requested_speeds = abilities.link_speed; /* print a string summarizing features */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 7b34f1e660ea..d52a9f7873b0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -58,6 +58,8 @@ void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void i40e_idle_aq(struct i40e_hw *hw); bool i40e_check_asq_alive(struct i40e_hw *hw); i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw, bool unloading); +char *i40e_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err); +char *i40e_stat_str(struct i40e_hw *hw, i40e_status stat_err); u32 i40e_led_get(struct i40e_hw *hw); void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink); diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 220371ece7c4..0cabf04cf23b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -497,6 +497,7 @@ struct i40e_hw { /* debug mask */ u32 debug_mask; + char err_str[16]; }; static inline bool i40e_is_vf(struct i40e_hw *hw) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 39fcb1dc4ea6..56c7e751149b 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -71,6 +71,212 @@ i40e_status i40e_set_mac_type(struct i40e_hw *hw) return status; } +/** + * i40evf_aq_str - convert AQ err code to a string + * @hw: pointer to the HW structure + * @aq_err: the AQ error code to convert + **/ +char *i40evf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err) +{ + switch (aq_err) { + case I40E_AQ_RC_OK: + return "OK"; + case I40E_AQ_RC_EPERM: + return "I40E_AQ_RC_EPERM"; + case I40E_AQ_RC_ENOENT: + return "I40E_AQ_RC_ENOENT"; + case I40E_AQ_RC_ESRCH: + return "I40E_AQ_RC_ESRCH"; + case I40E_AQ_RC_EINTR: + return "I40E_AQ_RC_EINTR"; + case I40E_AQ_RC_EIO: + return "I40E_AQ_RC_EIO"; + case I40E_AQ_RC_ENXIO: + return "I40E_AQ_RC_ENXIO"; + case I40E_AQ_RC_E2BIG: + return "I40E_AQ_RC_E2BIG"; + case I40E_AQ_RC_EAGAIN: + return "I40E_AQ_RC_EAGAIN"; + case I40E_AQ_RC_ENOMEM: + return "I40E_AQ_RC_ENOMEM"; + case I40E_AQ_RC_EACCES: + return "I40E_AQ_RC_EACCES"; + case I40E_AQ_RC_EFAULT: + return "I40E_AQ_RC_EFAULT"; + case I40E_AQ_RC_EBUSY: + return "I40E_AQ_RC_EBUSY"; + case I40E_AQ_RC_EEXIST: + return "I40E_AQ_RC_EEXIST"; + case I40E_AQ_RC_EINVAL: + return "I40E_AQ_RC_EINVAL"; + case I40E_AQ_RC_ENOTTY: + return "I40E_AQ_RC_ENOTTY"; + case I40E_AQ_RC_ENOSPC: + return "I40E_AQ_RC_ENOSPC"; + case I40E_AQ_RC_ENOSYS: + return "I40E_AQ_RC_ENOSYS"; + case I40E_AQ_RC_ERANGE: + return "I40E_AQ_RC_ERANGE"; + case I40E_AQ_RC_EFLUSHED: + return "I40E_AQ_RC_EFLUSHED"; + case I40E_AQ_RC_BAD_ADDR: + return "I40E_AQ_RC_BAD_ADDR"; + case I40E_AQ_RC_EMODE: + return "I40E_AQ_RC_EMODE"; + case I40E_AQ_RC_EFBIG: + return "I40E_AQ_RC_EFBIG"; + } + + snprintf(hw->err_str, sizeof(hw->err_str), "%d", aq_err); + return hw->err_str; +} + +/** + * i40evf_stat_str - convert status err code to a string + * @hw: pointer to the HW structure + * @stat_err: the status error code to convert + **/ +char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err) +{ + switch (stat_err) { + case 0: + return "OK"; + case I40E_ERR_NVM: + return "I40E_ERR_NVM"; + case I40E_ERR_NVM_CHECKSUM: + return "I40E_ERR_NVM_CHECKSUM"; + case I40E_ERR_PHY: + return "I40E_ERR_PHY"; + case I40E_ERR_CONFIG: + return "I40E_ERR_CONFIG"; + case I40E_ERR_PARAM: + return "I40E_ERR_PARAM"; + case I40E_ERR_MAC_TYPE: + return "I40E_ERR_MAC_TYPE"; + case I40E_ERR_UNKNOWN_PHY: + return "I40E_ERR_UNKNOWN_PHY"; + case I40E_ERR_LINK_SETUP: + return "I40E_ERR_LINK_SETUP"; + case I40E_ERR_ADAPTER_STOPPED: + return "I40E_ERR_ADAPTER_STOPPED"; + case I40E_ERR_INVALID_MAC_ADDR: + return "I40E_ERR_INVALID_MAC_ADDR"; + case I40E_ERR_DEVICE_NOT_SUPPORTED: + return "I40E_ERR_DEVICE_NOT_SUPPORTED"; + case I40E_ERR_MASTER_REQUESTS_PENDING: + return "I40E_ERR_MASTER_REQUESTS_PENDING"; + case I40E_ERR_INVALID_LINK_SETTINGS: + return "I40E_ERR_INVALID_LINK_SETTINGS"; + case I40E_ERR_AUTONEG_NOT_COMPLETE: + return "I40E_ERR_AUTONEG_NOT_COMPLETE"; + case I40E_ERR_RESET_FAILED: + return "I40E_ERR_RESET_FAILED"; + case I40E_ERR_SWFW_SYNC: + return "I40E_ERR_SWFW_SYNC"; + case I40E_ERR_NO_AVAILABLE_VSI: + return "I40E_ERR_NO_AVAILABLE_VSI"; + case I40E_ERR_NO_MEMORY: + return "I40E_ERR_NO_MEMORY"; + case I40E_ERR_BAD_PTR: + return "I40E_ERR_BAD_PTR"; + case I40E_ERR_RING_FULL: + return "I40E_ERR_RING_FULL"; + case I40E_ERR_INVALID_PD_ID: + return "I40E_ERR_INVALID_PD_ID"; + case I40E_ERR_INVALID_QP_ID: + return "I40E_ERR_INVALID_QP_ID"; + case I40E_ERR_INVALID_CQ_ID: + return "I40E_ERR_INVALID_CQ_ID"; + case I40E_ERR_INVALID_CEQ_ID: + return "I40E_ERR_INVALID_CEQ_ID"; + case I40E_ERR_INVALID_AEQ_ID: + return "I40E_ERR_INVALID_AEQ_ID"; + case I40E_ERR_INVALID_SIZE: + return "I40E_ERR_INVALID_SIZE"; + case I40E_ERR_INVALID_ARP_INDEX: + return "I40E_ERR_INVALID_ARP_INDEX"; + case I40E_ERR_INVALID_FPM_FUNC_ID: + return "I40E_ERR_INVALID_FPM_FUNC_ID"; + case I40E_ERR_QP_INVALID_MSG_SIZE: + return "I40E_ERR_QP_INVALID_MSG_SIZE"; + case I40E_ERR_QP_TOOMANY_WRS_POSTED: + return "I40E_ERR_QP_TOOMANY_WRS_POSTED"; + case I40E_ERR_INVALID_FRAG_COUNT: + return "I40E_ERR_INVALID_FRAG_COUNT"; + case I40E_ERR_QUEUE_EMPTY: + return "I40E_ERR_QUEUE_EMPTY"; + case I40E_ERR_INVALID_ALIGNMENT: + return "I40E_ERR_INVALID_ALIGNMENT"; + case I40E_ERR_FLUSHED_QUEUE: + return "I40E_ERR_FLUSHED_QUEUE"; + case I40E_ERR_INVALID_PUSH_PAGE_INDEX: + return "I40E_ERR_INVALID_PUSH_PAGE_INDEX"; + case I40E_ERR_INVALID_IMM_DATA_SIZE: + return "I40E_ERR_INVALID_IMM_DATA_SIZE"; + case I40E_ERR_TIMEOUT: + return "I40E_ERR_TIMEOUT"; + case I40E_ERR_OPCODE_MISMATCH: + return "I40E_ERR_OPCODE_MISMATCH"; + case I40E_ERR_CQP_COMPL_ERROR: + return "I40E_ERR_CQP_COMPL_ERROR"; + case I40E_ERR_INVALID_VF_ID: + return "I40E_ERR_INVALID_VF_ID"; + case I40E_ERR_INVALID_HMCFN_ID: + return "I40E_ERR_INVALID_HMCFN_ID"; + case I40E_ERR_BACKING_PAGE_ERROR: + return "I40E_ERR_BACKING_PAGE_ERROR"; + case I40E_ERR_NO_PBLCHUNKS_AVAILABLE: + return "I40E_ERR_NO_PBLCHUNKS_AVAILABLE"; + case I40E_ERR_INVALID_PBLE_INDEX: + return "I40E_ERR_INVALID_PBLE_INDEX"; + case I40E_ERR_INVALID_SD_INDEX: + return "I40E_ERR_INVALID_SD_INDEX"; + case I40E_ERR_INVALID_PAGE_DESC_INDEX: + return "I40E_ERR_INVALID_PAGE_DESC_INDEX"; + case I40E_ERR_INVALID_SD_TYPE: + return "I40E_ERR_INVALID_SD_TYPE"; + case I40E_ERR_MEMCPY_FAILED: + return "I40E_ERR_MEMCPY_FAILED"; + case I40E_ERR_INVALID_HMC_OBJ_INDEX: + return "I40E_ERR_INVALID_HMC_OBJ_INDEX"; + case I40E_ERR_INVALID_HMC_OBJ_COUNT: + return "I40E_ERR_INVALID_HMC_OBJ_COUNT"; + case I40E_ERR_INVALID_SRQ_ARM_LIMIT: + return "I40E_ERR_INVALID_SRQ_ARM_LIMIT"; + case I40E_ERR_SRQ_ENABLED: + return "I40E_ERR_SRQ_ENABLED"; + case I40E_ERR_ADMIN_QUEUE_ERROR: + return "I40E_ERR_ADMIN_QUEUE_ERROR"; + case I40E_ERR_ADMIN_QUEUE_TIMEOUT: + return "I40E_ERR_ADMIN_QUEUE_TIMEOUT"; + case I40E_ERR_BUF_TOO_SHORT: + return "I40E_ERR_BUF_TOO_SHORT"; + case I40E_ERR_ADMIN_QUEUE_FULL: + return "I40E_ERR_ADMIN_QUEUE_FULL"; + case I40E_ERR_ADMIN_QUEUE_NO_WORK: + return "I40E_ERR_ADMIN_QUEUE_NO_WORK"; + case I40E_ERR_BAD_IWARP_CQE: + return "I40E_ERR_BAD_IWARP_CQE"; + case I40E_ERR_NVM_BLANK_MODE: + return "I40E_ERR_NVM_BLANK_MODE"; + case I40E_ERR_NOT_IMPLEMENTED: + return "I40E_ERR_NOT_IMPLEMENTED"; + case I40E_ERR_PE_DOORBELL_NOT_ENABLED: + return "I40E_ERR_PE_DOORBELL_NOT_ENABLED"; + case I40E_ERR_DIAG_TEST_FAILED: + return "I40E_ERR_DIAG_TEST_FAILED"; + case I40E_ERR_NOT_READY: + return "I40E_ERR_NOT_READY"; + case I40E_NOT_SUPPORTED: + return "I40E_NOT_SUPPORTED"; + case I40E_ERR_FIRMWARE_API_VERSION: + return "I40E_ERR_FIRMWARE_API_VERSION"; + } + + snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err); + return hw->err_str; +} + /** * i40evf_debug_aq * @hw: debug mask related to admin queue diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h index 58e37a44b80a..856eb9d06595 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h @@ -60,6 +60,8 @@ void i40e_idle_aq(struct i40e_hw *hw); void i40evf_resume_aq(struct i40e_hw *hw); bool i40evf_check_asq_alive(struct i40e_hw *hw); i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading); +char *i40evf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err); +char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err); i40e_status i40e_set_mac_type(struct i40e_hw *hw); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 3969c6548af0..cbf94bd4f2bf 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -491,6 +491,7 @@ struct i40e_hw { /* debug mask */ u32 debug_mask; + char err_str[16]; }; static inline bool i40e_is_vf(struct i40e_hw *hw) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 52c695939319..becd300fca7c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -51,8 +51,9 @@ static int i40evf_send_pf_msg(struct i40evf_adapter *adapter, err = i40e_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL); if (err) - dev_err(&adapter->pdev->dev, "Unable to send opcode %d to PF, error %d, aq status %d\n", - op, err, hw->aq.asq_last_status); + dev_err(&adapter->pdev->dev, "Unable to send opcode %d to PF, err %s, aq_err %s\n", + op, i40evf_stat_str(hw, err), + i40evf_aq_str(hw, hw->aq.asq_last_status)); return err; } @@ -727,8 +728,9 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, return; } if (v_retval) { - dev_err(&adapter->pdev->dev, "%s: PF returned error %d to our request %d\n", - __func__, v_retval, v_opcode); + dev_err(&adapter->pdev->dev, "%s: PF returned error %d (%s) to our request %d\n", + __func__, v_retval, + i40evf_stat_str(&adapter->hw, v_retval), v_opcode); } switch (v_opcode) { case I40E_VIRTCHNL_OP_GET_STATS: { -- cgit v1.3-6-gb490 From 41a1d04b9d2006fdac5cab7680cff89915610944 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 4 Jun 2015 16:24:02 -0400 Subject: i40e: use BIT and BIT_ULL macros Use macros for abstracting (1 << foo) to BIT(foo) and (1ULL << foo64) to BIT_ULL(foo64) in order to match better with kernel requirements. NOTE: the adminq_cmd.h file was not modified on purpose because of the dependency upon firmware for that file. Change-ID: I73ee2e48c880d671948aad19bd53ca6b2ac558fc Signed-off-by: Jesse Brandeburg Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 56 ++++++++--------- drivers/net/ethernet/intel/i40e/i40e_common.c | 4 +- drivers/net/ethernet/intel/i40e/i40e_dcb.h | 8 +-- drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_debugfs.c | 10 +-- drivers/net/ethernet/intel/i40e/i40e_diag.c | 11 ++-- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 54 ++++++++-------- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 12 ++-- drivers/net/ethernet/intel/i40e/i40e_fcoe.h | 4 +- drivers/net/ethernet/intel/i40e/i40e_hmc.h | 6 +- drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c | 16 ++--- drivers/net/ethernet/intel/i40e/i40e_main.c | 73 +++++++++++----------- drivers/net/ethernet/intel/i40e/i40e_nvm.c | 6 +- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 7 +-- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 39 ++++++------ drivers/net/ethernet/intel/i40e/i40e_txrx.h | 44 ++++++------- drivers/net/ethernet/intel/i40e/i40e_type.h | 22 +++---- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 18 +++--- drivers/net/ethernet/intel/i40evf/i40e_hmc.h | 6 +- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 37 ++++++----- drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 42 ++++++------- drivers/net/ethernet/intel/i40evf/i40e_type.h | 22 +++---- drivers/net/ethernet/intel/i40evf/i40evf.h | 42 ++++++------- drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | 44 ++++++------- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 8 +-- .../net/ethernet/intel/i40evf/i40evf_virtchnl.c | 4 +- 26 files changed, 293 insertions(+), 304 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index ec76c3fa3a04..281fd8456146 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -98,7 +98,7 @@ #define I40E_INT_NAME_STR_LEN (IFNAMSIZ + 9) /* Ethtool Private Flags */ -#define I40E_PRIV_FLAGS_NPAR_FLAG (1 << 0) +#define I40E_PRIV_FLAGS_NPAR_FLAG BIT(0) #define I40E_NVM_VERSION_LO_SHIFT 0 #define I40E_NVM_VERSION_LO_MASK (0xff << I40E_NVM_VERSION_LO_SHIFT) @@ -289,35 +289,35 @@ struct i40e_pf { struct work_struct service_task; u64 flags; -#define I40E_FLAG_RX_CSUM_ENABLED (u64)(1 << 1) -#define I40E_FLAG_MSI_ENABLED (u64)(1 << 2) -#define I40E_FLAG_MSIX_ENABLED (u64)(1 << 3) -#define I40E_FLAG_RX_1BUF_ENABLED (u64)(1 << 4) -#define I40E_FLAG_RX_PS_ENABLED (u64)(1 << 5) -#define I40E_FLAG_RSS_ENABLED (u64)(1 << 6) -#define I40E_FLAG_VMDQ_ENABLED (u64)(1 << 7) -#define I40E_FLAG_FDIR_REQUIRES_REINIT (u64)(1 << 8) -#define I40E_FLAG_NEED_LINK_UPDATE (u64)(1 << 9) +#define I40E_FLAG_RX_CSUM_ENABLED BIT_ULL(1) +#define I40E_FLAG_MSI_ENABLED BIT_ULL(2) +#define I40E_FLAG_MSIX_ENABLED BIT_ULL(3) +#define I40E_FLAG_RX_1BUF_ENABLED BIT_ULL(4) +#define I40E_FLAG_RX_PS_ENABLED BIT_ULL(5) +#define I40E_FLAG_RSS_ENABLED BIT_ULL(6) +#define I40E_FLAG_VMDQ_ENABLED BIT_ULL(7) +#define I40E_FLAG_FDIR_REQUIRES_REINIT BIT_ULL(8) +#define I40E_FLAG_NEED_LINK_UPDATE BIT_ULL(9) #ifdef I40E_FCOE -#define I40E_FLAG_FCOE_ENABLED (u64)(1 << 11) +#define I40E_FLAG_FCOE_ENABLED BIT_ULL(11) #endif /* I40E_FCOE */ -#define I40E_FLAG_IN_NETPOLL (u64)(1 << 12) -#define I40E_FLAG_16BYTE_RX_DESC_ENABLED (u64)(1 << 13) -#define I40E_FLAG_CLEAN_ADMINQ (u64)(1 << 14) -#define I40E_FLAG_FILTER_SYNC (u64)(1 << 15) -#define I40E_FLAG_PROCESS_MDD_EVENT (u64)(1 << 17) -#define I40E_FLAG_PROCESS_VFLR_EVENT (u64)(1 << 18) -#define I40E_FLAG_SRIOV_ENABLED (u64)(1 << 19) -#define I40E_FLAG_DCB_ENABLED (u64)(1 << 20) -#define I40E_FLAG_FD_SB_ENABLED (u64)(1 << 21) -#define I40E_FLAG_FD_ATR_ENABLED (u64)(1 << 22) -#define I40E_FLAG_PTP (u64)(1 << 25) -#define I40E_FLAG_MFP_ENABLED (u64)(1 << 26) +#define I40E_FLAG_IN_NETPOLL BIT_ULL(12) +#define I40E_FLAG_16BYTE_RX_DESC_ENABLED BIT_ULL(13) +#define I40E_FLAG_CLEAN_ADMINQ BIT_ULL(14) +#define I40E_FLAG_FILTER_SYNC BIT_ULL(15) +#define I40E_FLAG_PROCESS_MDD_EVENT BIT_ULL(17) +#define I40E_FLAG_PROCESS_VFLR_EVENT BIT_ULL(18) +#define I40E_FLAG_SRIOV_ENABLED BIT_ULL(19) +#define I40E_FLAG_DCB_ENABLED BIT_ULL(20) +#define I40E_FLAG_FD_SB_ENABLED BIT_ULL(21) +#define I40E_FLAG_FD_ATR_ENABLED BIT_ULL(22) +#define I40E_FLAG_PTP BIT_ULL(25) +#define I40E_FLAG_MFP_ENABLED BIT_ULL(26) #ifdef CONFIG_I40E_VXLAN -#define I40E_FLAG_VXLAN_FILTER_SYNC (u64)(1 << 27) +#define I40E_FLAG_VXLAN_FILTER_SYNC BIT_ULL(27) #endif -#define I40E_FLAG_PORT_ID_VALID (u64)(1 << 28) -#define I40E_FLAG_DCB_CAPABLE (u64)(1 << 29) +#define I40E_FLAG_PORT_ID_VALID BIT_ULL(28) +#define I40E_FLAG_DCB_CAPABLE BIT_ULL(29) #define I40E_FLAG_VEB_MODE_ENABLED BIT_ULL(40) /* tracks features that get auto disabled by errors */ @@ -443,8 +443,8 @@ struct i40e_vsi { u32 current_netdev_flags; unsigned long state; -#define I40E_VSI_FLAG_FILTER_CHANGED (1<<0) -#define I40E_VSI_FLAG_VEB_OWNER (1<<1) +#define I40E_VSI_FLAG_FILTER_CHANGED BIT(0) +#define I40E_VSI_FLAG_VEB_OWNER BIT(1) unsigned long flags; struct list_head mac_filter_list; diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 8f2ecbe5e62c..167ca0d752ea 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1393,9 +1393,9 @@ void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink) blink = false; if (blink) - gpio_val |= (1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); + gpio_val |= BIT(I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); else - gpio_val &= ~(1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); + gpio_val &= ~BIT(I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); wr32(hw, I40E_GLGEN_GPIO_CTL(i), gpio_val); break; diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.h b/drivers/net/ethernet/intel/i40e/i40e_dcb.h index e137e3fac8ee..50fc894a4cde 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.h +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.h @@ -58,9 +58,9 @@ #define I40E_IEEE_ETS_MAXTC_SHIFT 0 #define I40E_IEEE_ETS_MAXTC_MASK (0x7 << I40E_IEEE_ETS_MAXTC_SHIFT) #define I40E_IEEE_ETS_CBS_SHIFT 6 -#define I40E_IEEE_ETS_CBS_MASK (0x1 << I40E_IEEE_ETS_CBS_SHIFT) +#define I40E_IEEE_ETS_CBS_MASK BIT(I40E_IEEE_ETS_CBS_SHIFT) #define I40E_IEEE_ETS_WILLING_SHIFT 7 -#define I40E_IEEE_ETS_WILLING_MASK (0x1 << I40E_IEEE_ETS_WILLING_SHIFT) +#define I40E_IEEE_ETS_WILLING_MASK BIT(I40E_IEEE_ETS_WILLING_SHIFT) #define I40E_IEEE_ETS_PRIO_0_SHIFT 0 #define I40E_IEEE_ETS_PRIO_0_MASK (0x7 << I40E_IEEE_ETS_PRIO_0_SHIFT) #define I40E_IEEE_ETS_PRIO_1_SHIFT 4 @@ -79,9 +79,9 @@ #define I40E_IEEE_PFC_CAP_SHIFT 0 #define I40E_IEEE_PFC_CAP_MASK (0xF << I40E_IEEE_PFC_CAP_SHIFT) #define I40E_IEEE_PFC_MBC_SHIFT 6 -#define I40E_IEEE_PFC_MBC_MASK (0x1 << I40E_IEEE_PFC_MBC_SHIFT) +#define I40E_IEEE_PFC_MBC_MASK BIT(I40E_IEEE_PFC_MBC_SHIFT) #define I40E_IEEE_PFC_WILLING_SHIFT 7 -#define I40E_IEEE_PFC_WILLING_MASK (0x1 << I40E_IEEE_PFC_WILLING_SHIFT) +#define I40E_IEEE_PFC_WILLING_MASK BIT(I40E_IEEE_PFC_WILLING_SHIFT) /* Defines for IEEE APP TLV */ #define I40E_IEEE_APP_SEL_SHIFT 0 diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c index bd5079d5c1b6..1c51f736a8d0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c @@ -187,7 +187,7 @@ void i40e_dcbnl_set_all(struct i40e_vsi *vsi) /* Set up all the App TLVs if DCBx is negotiated */ for (i = 0; i < dcbxcfg->numapps; i++) { prio = dcbxcfg->app[i].priority; - tc_map = (1 << dcbxcfg->etscfg.prioritytable[prio]); + tc_map = BIT(dcbxcfg->etscfg.prioritytable[prio]); /* Add APP only if the TC is enabled for this VSI */ if (tc_map & vsi->tc_config.enabled_tc) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index da0faf478af0..d7c15d17faa6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -964,7 +964,7 @@ static void i40e_dbg_cmd_fd_ctrl(struct i40e_pf *pf, u64 flag, bool enable) 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)); + i40e_do_reset_safe(pf, BIT(__I40E_PF_RESET_REQUESTED)); } #define I40E_MAX_DEBUG_OUT_BUFFER (4096*4) @@ -1471,19 +1471,19 @@ static ssize_t i40e_dbg_command_write(struct file *filp, } } else if (strncmp(cmd_buf, "pfr", 3) == 0) { dev_info(&pf->pdev->dev, "debugfs: forcing PFR\n"); - i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset_safe(pf, BIT(__I40E_PF_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "corer", 5) == 0) { dev_info(&pf->pdev->dev, "debugfs: forcing CoreR\n"); - i40e_do_reset_safe(pf, (1 << __I40E_CORE_RESET_REQUESTED)); + i40e_do_reset_safe(pf, BIT(__I40E_CORE_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "globr", 5) == 0) { dev_info(&pf->pdev->dev, "debugfs: forcing GlobR\n"); - i40e_do_reset_safe(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED)); + i40e_do_reset_safe(pf, BIT(__I40E_GLOBAL_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "empr", 4) == 0) { dev_info(&pf->pdev->dev, "debugfs: forcing EMPR\n"); - i40e_do_reset_safe(pf, (1 << __I40E_EMP_RESET_REQUESTED)); + i40e_do_reset_safe(pf, BIT(__I40E_EMP_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "read", 4) == 0) { u32 address; diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.c b/drivers/net/ethernet/intel/i40e/i40e_diag.c index 56438bd579e6..f141e78d409e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_diag.c +++ b/drivers/net/ethernet/intel/i40e/i40e_diag.c @@ -144,11 +144,8 @@ i40e_status i40e_diag_eeprom_test(struct i40e_hw *hw) ret_code = i40e_read_nvm_word(hw, I40E_SR_NVM_CONTROL_WORD, ®_val); if (!ret_code && ((reg_val & I40E_SR_CONTROL_WORD_1_MASK) == - (0x01 << I40E_SR_CONTROL_WORD_1_SHIFT))) { - ret_code = i40e_validate_nvm_checksum(hw, NULL); - } else { - ret_code = I40E_ERR_DIAG_TEST_FAILED; - } - - return ret_code; + BIT(I40E_SR_CONTROL_WORD_1_SHIFT))) + return i40e_validate_nvm_checksum(hw, NULL); + else + return I40E_ERR_DIAG_TEST_FAILED; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 4b06a27ab799..83d41c2cb02d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1017,7 +1017,7 @@ static int i40e_get_eeprom_len(struct net_device *netdev) & I40E_GLPCI_LBARCTRL_FL_SIZE_MASK) >> I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT; /* register returns value in power of 2, 64Kbyte chunks. */ - val = (64 * 1024) * (1 << val); + val = (64 * 1024) * BIT(val); return val; } @@ -1470,11 +1470,11 @@ static int i40e_get_ts_info(struct net_device *dev, else info->phc_index = -1; - info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); + info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); - info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | + BIT(HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT); return 0; } @@ -1590,7 +1590,7 @@ static void i40e_diag_test(struct net_device *netdev, /* indicate we're in test mode */ dev_close(netdev); else - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset(pf, BIT(__I40E_PF_RESET_REQUESTED)); /* Link test performed before hardware reset * so autoneg doesn't interfere with test result @@ -1612,7 +1612,7 @@ static void i40e_diag_test(struct net_device *netdev, eth_test->flags |= ETH_TEST_FL_FAILED; clear_bit(__I40E_TESTING, &pf->state); - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset(pf, BIT(__I40E_PF_RESET_REQUESTED)); if (if_running) dev_open(netdev); @@ -1645,7 +1645,7 @@ static void i40e_get_wol(struct net_device *netdev, /* NVM bit on means WoL disabled for the port */ i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits); - if ((1 << hw->port) & wol_nvm_bits || hw->partition_id != 1) { + if ((BIT(hw->port) & wol_nvm_bits) || (hw->partition_id != 1)) { wol->supported = 0; wol->wolopts = 0; } else { @@ -1678,7 +1678,7 @@ static int i40e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) /* NVM bit on means WoL disabled for the port */ i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits); - if (((1 << hw->port) & wol_nvm_bits)) + if (BIT(hw->port) & wol_nvm_bits) return -EOPNOTSUPP; /* only magic packet is supported */ @@ -2024,10 +2024,10 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) case TCP_V4_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); + hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP); break; default: return -EINVAL; @@ -2036,10 +2036,10 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) case TCP_V6_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); + hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP); break; default: return -EINVAL; @@ -2048,12 +2048,12 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) case UDP_V4_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); + hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4)); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4)); break; default: return -EINVAL; @@ -2062,12 +2062,12 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) case UDP_V6_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); + hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6)); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6)); break; default: return -EINVAL; @@ -2080,7 +2080,7 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) if ((nfc->data & RXH_L4_B_0_1) || (nfc->data & RXH_L4_B_2_3)) return -EINVAL; - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); break; case AH_ESP_V6_FLOW: case AH_V6_FLOW: @@ -2089,15 +2089,15 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) if ((nfc->data & RXH_L4_B_0_1) || (nfc->data & RXH_L4_B_2_3)) return -EINVAL; - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); break; case IPV4_FLOW: - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4); break; case IPV6_FLOW: - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6); break; default: return -EINVAL; diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c index c8b621e0e7cd..5ea75dd537d6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c @@ -298,8 +298,8 @@ int i40e_init_pf_fcoe(struct i40e_pf *pf) /* enable FCoE hash filter */ val = rd32(hw, I40E_PFQF_HENA(1)); - val |= 1 << (I40E_FILTER_PCTYPE_FCOE_OX - 32); - val |= 1 << (I40E_FILTER_PCTYPE_FCOE_RX - 32); + val |= BIT(I40E_FILTER_PCTYPE_FCOE_OX - 32); + val |= BIT(I40E_FILTER_PCTYPE_FCOE_RX - 32); val &= I40E_PFQF_HENA_PTYPE_ENA_MASK; wr32(hw, I40E_PFQF_HENA(1), val); @@ -308,10 +308,10 @@ int i40e_init_pf_fcoe(struct i40e_pf *pf) pf->num_fcoe_qps = I40E_DEFAULT_FCOE; /* Reserve 4K DDP contexts and 20K filter size for FCoE */ - pf->fcoe_hmc_cntx_num = (1 << I40E_DMA_CNTX_SIZE_4K) * - I40E_DMA_CNTX_BASE_SIZE; + pf->fcoe_hmc_cntx_num = BIT(I40E_DMA_CNTX_SIZE_4K) * + I40E_DMA_CNTX_BASE_SIZE; pf->fcoe_hmc_filt_num = pf->fcoe_hmc_cntx_num + - (1 << I40E_HASH_FILTER_SIZE_16K) * + BIT(I40E_HASH_FILTER_SIZE_16K) * I40E_HASH_FILTER_BASE_SIZE; /* FCoE object: max 16K filter buckets and 4K DMA contexts */ @@ -348,7 +348,7 @@ u8 i40e_get_fcoe_tc_map(struct i40e_pf *pf) if (app.selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && app.protocolid == ETH_P_FCOE) { tc = dcbcfg->etscfg.prioritytable[app.priority]; - enabled_tc |= (1 << tc); + enabled_tc |= BIT(tc); break; } } diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.h b/drivers/net/ethernet/intel/i40e/i40e_fcoe.h index 0d49e2d15d40..a93174ddeaba 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.h +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.h @@ -59,9 +59,9 @@ (((e) >> I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT) & 0x1) #define I40E_RX_PROG_FCOE_ERROR_TBL_FULL_BIT \ - (1 << I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT) + BIT(I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT) #define I40E_RX_PROG_FCOE_ERROR_CONFLICT_BIT \ - (1 << I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT) + BIT(I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT) #define I40E_RX_PROG_FCOE_ERROR_INVLFAIL(e) \ I40E_RX_PROG_FCOE_ERROR_CONFLICT(e) diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_hmc.h index 386416bf7267..d90669211392 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.h @@ -127,8 +127,8 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) | \ - (1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ - val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + BIT(I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ + val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, val1); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ @@ -147,7 +147,7 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT); \ - val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, 0); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c index d399eaf5aad5..fa371a2a40c6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c @@ -129,7 +129,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num, obj->cnt = txq_num; obj->base = 0; size_exp = rd32(hw, I40E_GLHMC_LANTXOBJSZ); - obj->size = (u64)1 << size_exp; + obj->size = BIT_ULL(size_exp); /* validate values requested by driver don't exceed HMC capacity */ if (txq_num > obj->max_cnt) { @@ -152,7 +152,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num, hw->hmc.hmc_obj[I40E_HMC_LAN_TX].size); obj->base = i40e_align_l2obj_base(obj->base); size_exp = rd32(hw, I40E_GLHMC_LANRXOBJSZ); - obj->size = (u64)1 << size_exp; + obj->size = BIT_ULL(size_exp); /* validate values requested by driver don't exceed HMC capacity */ if (rxq_num > obj->max_cnt) { @@ -175,7 +175,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num, hw->hmc.hmc_obj[I40E_HMC_LAN_RX].size); obj->base = i40e_align_l2obj_base(obj->base); size_exp = rd32(hw, I40E_GLHMC_FCOEDDPOBJSZ); - obj->size = (u64)1 << size_exp; + obj->size = BIT_ULL(size_exp); /* validate values requested by driver don't exceed HMC capacity */ if (fcoe_cntx_num > obj->max_cnt) { @@ -198,7 +198,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num, hw->hmc.hmc_obj[I40E_HMC_FCOE_CTX].size); obj->base = i40e_align_l2obj_base(obj->base); size_exp = rd32(hw, I40E_GLHMC_FCOEFOBJSZ); - obj->size = (u64)1 << size_exp; + obj->size = BIT_ULL(size_exp); /* validate values requested by driver don't exceed HMC capacity */ if (fcoe_filt_num > obj->max_cnt) { @@ -763,7 +763,7 @@ static void i40e_write_byte(u8 *hmc_bits, /* prepare the bits and mask */ shift_width = ce_info->lsb % 8; - mask = ((u8)1 << ce_info->width) - 1; + mask = BIT(ce_info->width) - 1; src_byte = *from; src_byte &= mask; @@ -804,7 +804,7 @@ static void i40e_write_word(u8 *hmc_bits, /* prepare the bits and mask */ shift_width = ce_info->lsb % 8; - mask = ((u16)1 << ce_info->width) - 1; + mask = BIT(ce_info->width) - 1; /* don't swizzle the bits until after the mask because the mask bits * will be in a different bit position on big endian machines @@ -854,7 +854,7 @@ static void i40e_write_dword(u8 *hmc_bits, * to 5 bits so the shift will do nothing */ if (ce_info->width < 32) - mask = ((u32)1 << ce_info->width) - 1; + mask = BIT(ce_info->width) - 1; else mask = ~(u32)0; @@ -906,7 +906,7 @@ static void i40e_write_qword(u8 *hmc_bits, * to 6 bits so the shift will do nothing */ if (ce_info->width < 64) - mask = ((u64)1 << ce_info->width) - 1; + mask = BIT_ULL(ce_info->width) - 1; else mask = ~(u64)0; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 7646297e0981..857d294d2a45 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -520,7 +520,7 @@ static void i40e_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg, if (likely(new_data >= *offset)) *stat = new_data - *offset; else - *stat = (new_data + ((u64)1 << 48)) - *offset; + *stat = (new_data + BIT_ULL(48)) - *offset; *stat &= 0xFFFFFFFFFFFFULL; } @@ -543,7 +543,7 @@ static void i40e_stat_update32(struct i40e_hw *hw, u32 reg, if (likely(new_data >= *offset)) *stat = (u32)(new_data - *offset); else - *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); + *stat = (u32)((new_data + BIT_ULL(32)) - *offset); } /** @@ -1526,7 +1526,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, if (enabled_tc && (vsi->back->flags & I40E_FLAG_DCB_ENABLED)) { /* Find numtc from enabled TC bitmap */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) /* TC is enabled */ + if (enabled_tc & BIT_ULL(i)) /* TC is enabled */ numtc++; } if (!numtc) { @@ -1552,7 +1552,8 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, /* Setup queue offset/count for all TCs for given VSI */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { /* See if the given TC is enabled for the given VSI */ - if (vsi->tc_config.enabled_tc & (1 << i)) { /* TC is enabled */ + if (vsi->tc_config.enabled_tc & BIT_ULL(i)) { + /* TC is enabled */ int pow, num_qps; switch (vsi->type) { @@ -1578,7 +1579,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, /* find the next higher power-of-2 of num queue pairs */ num_qps = qcount; pow = 0; - while (num_qps && ((1 << pow) < qcount)) { + while (num_qps && (BIT_ULL(pow) < qcount)) { pow++; num_qps >>= 1; } @@ -2723,9 +2724,9 @@ static int i40e_vsi_configure_rx(struct i40e_vsi *vsi) #endif /* I40E_FCOE */ /* round up for the chip's needs */ vsi->rx_hdr_len = ALIGN(vsi->rx_hdr_len, - (1 << I40E_RXQ_CTX_HBUFF_SHIFT)); + BIT_ULL(I40E_RXQ_CTX_HBUFF_SHIFT)); vsi->rx_buf_len = ALIGN(vsi->rx_buf_len, - (1 << I40E_RXQ_CTX_DBUFF_SHIFT)); + BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT)); /* set up individual rings */ for (i = 0; i < vsi->num_queue_pairs && !err; i++) @@ -2755,7 +2756,7 @@ static void i40e_vsi_config_dcb_rings(struct i40e_vsi *vsi) } for (n = 0; n < I40E_MAX_TRAFFIC_CLASS; n++) { - if (!(vsi->tc_config.enabled_tc & (1 << n))) + if (!(vsi->tc_config.enabled_tc & BIT_ULL(n))) continue; qoffset = vsi->tc_config.tc_info[n].qoffset; @@ -4100,7 +4101,7 @@ static u8 i40e_get_iscsi_tc_map(struct i40e_pf *pf) if (app.selector == I40E_APP_SEL_TCPIP && app.protocolid == I40E_APP_PROTOID_ISCSI) { tc = dcbcfg->etscfg.prioritytable[app.priority]; - enabled_tc |= (1 << tc); + enabled_tc |= BIT_ULL(tc); break; } } @@ -4149,7 +4150,7 @@ static u8 i40e_dcb_get_enabled_tc(struct i40e_dcbx_config *dcbcfg) u8 i; for (i = 0; i < num_tc; i++) - enabled_tc |= 1 << i; + enabled_tc |= BIT(i); return enabled_tc; } @@ -4184,7 +4185,7 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf) /* At least have TC0 */ enabled_tc = (enabled_tc ? enabled_tc : 0x1); for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) + if (enabled_tc & BIT_ULL(i)) num_tc++; } return num_tc; @@ -4206,11 +4207,11 @@ static u8 i40e_pf_get_default_tc(struct i40e_pf *pf) /* Find the first enabled TC */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) + if (enabled_tc & BIT_ULL(i)) break; } - return 1 << i; + return BIT(i); } /** @@ -4366,7 +4367,7 @@ static void i40e_vsi_config_netdev_tc(struct i40e_vsi *vsi, u8 enabled_tc) * will set the numtc for netdev as 2 that will be * referenced by the netdev layer as TC 0 and 1. */ - if (vsi->tc_config.enabled_tc & (1 << i)) + if (vsi->tc_config.enabled_tc & BIT_ULL(i)) netdev_set_tc_queue(netdev, vsi->tc_config.tc_info[i].netdev_tc, vsi->tc_config.tc_info[i].qcount, @@ -4428,7 +4429,7 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc) /* Enable ETS TCs with equal BW Share for now across all VSIs */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) + if (enabled_tc & BIT_ULL(i)) bw_share[i] = 1; } @@ -4502,7 +4503,7 @@ int i40e_veb_config_tc(struct i40e_veb *veb, u8 enabled_tc) /* Enable ETS TCs with equal BW Share for now */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) + if (enabled_tc & BIT_ULL(i)) bw_data.tc_bw_share_credits[i] = 1; } @@ -4896,7 +4897,7 @@ static int i40e_setup_tc(struct net_device *netdev, u8 tc) /* Generate TC map for number of tc requested */ for (i = 0; i < tc; i++) - enabled_tc |= (1 << i); + enabled_tc |= BIT_ULL(i); /* Requesting same TC configuration as already enabled */ if (enabled_tc == vsi->tc_config.enabled_tc) @@ -5035,7 +5036,7 @@ err_setup_rx: err_setup_tx: i40e_vsi_free_tx_resources(vsi); if (vsi == pf->vsi[pf->lan_vsi]) - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED)); return err; } @@ -5103,7 +5104,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) i40e_vc_notify_reset(pf); /* do the biggest reset indicated */ - if (reset_flags & (1 << __I40E_GLOBAL_RESET_REQUESTED)) { + if (reset_flags & BIT_ULL(__I40E_GLOBAL_RESET_REQUESTED)) { /* Request a Global Reset * @@ -5118,7 +5119,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) val |= I40E_GLGEN_RTRIG_GLOBR_MASK; wr32(&pf->hw, I40E_GLGEN_RTRIG, val); - } else if (reset_flags & (1 << __I40E_CORE_RESET_REQUESTED)) { + } else if (reset_flags & BIT_ULL(__I40E_CORE_RESET_REQUESTED)) { /* Request a Core Reset * @@ -5130,7 +5131,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) wr32(&pf->hw, I40E_GLGEN_RTRIG, val); i40e_flush(&pf->hw); - } else if (reset_flags & (1 << __I40E_PF_RESET_REQUESTED)) { + } else if (reset_flags & BIT_ULL(__I40E_PF_RESET_REQUESTED)) { /* Request a PF Reset * @@ -5143,7 +5144,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) dev_dbg(&pf->pdev->dev, "PFR requested\n"); i40e_handle_reset_warning(pf); - } else if (reset_flags & (1 << __I40E_REINIT_REQUESTED)) { + } else if (reset_flags & BIT_ULL(__I40E_REINIT_REQUESTED)) { int v; /* Find the VSI(s) that requested a re-init */ @@ -5160,7 +5161,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) /* no further action needed, so return now */ return; - } else if (reset_flags & (1 << __I40E_DOWN_REQUESTED)) { + } else if (reset_flags & BIT_ULL(__I40E_DOWN_REQUESTED)) { int v; /* Find the VSI(s) that needs to be brought down */ @@ -5801,23 +5802,23 @@ static void i40e_reset_subtask(struct i40e_pf *pf) rtnl_lock(); if (test_bit(__I40E_REINIT_REQUESTED, &pf->state)) { - reset_flags |= (1 << __I40E_REINIT_REQUESTED); + reset_flags |= BIT_ULL(__I40E_REINIT_REQUESTED); clear_bit(__I40E_REINIT_REQUESTED, &pf->state); } if (test_bit(__I40E_PF_RESET_REQUESTED, &pf->state)) { - reset_flags |= (1 << __I40E_PF_RESET_REQUESTED); + reset_flags |= BIT_ULL(__I40E_PF_RESET_REQUESTED); clear_bit(__I40E_PF_RESET_REQUESTED, &pf->state); } if (test_bit(__I40E_CORE_RESET_REQUESTED, &pf->state)) { - reset_flags |= (1 << __I40E_CORE_RESET_REQUESTED); + reset_flags |= BIT_ULL(__I40E_CORE_RESET_REQUESTED); clear_bit(__I40E_CORE_RESET_REQUESTED, &pf->state); } if (test_bit(__I40E_GLOBAL_RESET_REQUESTED, &pf->state)) { - reset_flags |= (1 << __I40E_GLOBAL_RESET_REQUESTED); + reset_flags |= BIT_ULL(__I40E_GLOBAL_RESET_REQUESTED); clear_bit(__I40E_GLOBAL_RESET_REQUESTED, &pf->state); } if (test_bit(__I40E_DOWN_REQUESTED, &pf->state)) { - reset_flags |= (1 << __I40E_DOWN_REQUESTED); + reset_flags |= BIT_ULL(__I40E_DOWN_REQUESTED); clear_bit(__I40E_DOWN_REQUESTED, &pf->state); } @@ -6699,8 +6700,8 @@ static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf) pf->flags &= ~I40E_FLAG_VXLAN_FILTER_SYNC; for (i = 0; i < I40E_MAX_PF_UDP_OFFLOAD_PORTS; i++) { - if (pf->pending_vxlan_bitmap & (1 << i)) { - pf->pending_vxlan_bitmap &= ~(1 << i); + if (pf->pending_vxlan_bitmap & BIT_ULL(i)) { + pf->pending_vxlan_bitmap &= ~BIT_ULL(i); port = pf->vxlan_ports[i]; if (port) ret = i40e_aq_add_udp_tunnel(hw, ntohs(port), @@ -7513,7 +7514,7 @@ static int i40e_config_rss(struct i40e_pf *pf) j = 0; /* lut = 4-byte sliding window of 4 lut entries */ lut = (lut << 8) | (j & - ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1)); + (BIT(pf->hw.func_caps.rss_table_entry_width) - 1)); /* On i = 3, we have 4 entries in lut; write to the register */ if ((i & 3) == 3) wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); @@ -7587,7 +7588,7 @@ i40e_status i40e_set_npar_bw_setting(struct i40e_pf *pf) i40e_status status; /* Set the valid bit for this PF */ - bw_data.pf_valid_bits = cpu_to_le16(1 << pf->hw.pf_id); + bw_data.pf_valid_bits = cpu_to_le16(BIT(pf->hw.pf_id)); bw_data.max_bw[pf->hw.pf_id] = pf->npar_max_bw & I40E_ALT_BW_VALUE_MASK; bw_data.min_bw[pf->hw.pf_id] = pf->npar_min_bw & I40E_ALT_BW_VALUE_MASK; @@ -7720,7 +7721,7 @@ static int i40e_sw_init(struct i40e_pf *pf) /* Depending on PF configurations, it is possible that the RSS * maximum might end up larger than the available queues */ - pf->rss_size_max = 0x1 << pf->hw.func_caps.rss_table_entry_width; + pf->rss_size_max = BIT(pf->hw.func_caps.rss_table_entry_width); pf->rss_size = 1; pf->rss_table_size = pf->hw.func_caps.rss_table_size; pf->rss_size_max = min_t(int, pf->rss_size_max, @@ -7870,7 +7871,7 @@ static int i40e_set_features(struct net_device *netdev, need_reset = i40e_set_ntuple(pf, features); if (need_reset) - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED)); return 0; } @@ -7933,7 +7934,7 @@ static void i40e_add_vxlan_port(struct net_device *netdev, /* New port: add it and mark its index in the bitmap */ pf->vxlan_ports[next_idx] = port; - pf->pending_vxlan_bitmap |= (1 << next_idx); + pf->pending_vxlan_bitmap |= BIT_ULL(next_idx); pf->flags |= I40E_FLAG_VXLAN_FILTER_SYNC; dev_info(&pf->pdev->dev, "adding vxlan port %d\n", ntohs(port)); @@ -7964,7 +7965,7 @@ static void i40e_del_vxlan_port(struct net_device *netdev, * and make it pending */ pf->vxlan_ports[idx] = 0; - pf->pending_vxlan_bitmap |= (1 << idx); + pf->pending_vxlan_bitmap |= BIT_ULL(idx); pf->flags |= I40E_FLAG_VXLAN_FILTER_SYNC; dev_info(&pf->pdev->dev, "deleting vxlan port %d\n", diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index 554e49d02683..ce986af213d2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -50,7 +50,7 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw) sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >> I40E_GLNVM_GENS_SR_SIZE_SHIFT); /* Switching to words (sr_size contains power of 2KB) */ - nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB; + nvm->sr_size = BIT(sr_size) * I40E_SR_WORDS_IN_1KB; /* Check if we are in the normal or blank NVM programming mode */ fla = rd32(hw, I40E_GLNVM_FLA); @@ -189,8 +189,8 @@ static i40e_status i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset, ret_code = i40e_poll_sr_srctl_done_bit(hw); if (!ret_code) { /* Write the address and start reading */ - sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | - (1 << I40E_GLNVM_SRCTL_START_SHIFT); + sr_reg = ((u32)offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | + BIT(I40E_GLNVM_SRCTL_START_SHIFT); wr32(hw, I40E_GLNVM_SRCTL, sr_reg); /* Poll I40E_GLNVM_SRCTL until the done bit is set */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index a92b7725dec3..8c40d6ea15fd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -43,9 +43,8 @@ #define I40E_PTP_10GB_INCVAL 0x0333333333ULL #define I40E_PTP_1GB_INCVAL 0x2000000000ULL -#define I40E_PRTTSYN_CTL1_TSYNTYPE_V1 (0x1 << \ - I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) -#define I40E_PRTTSYN_CTL1_TSYNTYPE_V2 (0x2 << \ +#define I40E_PRTTSYN_CTL1_TSYNTYPE_V1 BIT(I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) +#define I40E_PRTTSYN_CTL1_TSYNTYPE_V2 (2 << \ I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) /** @@ -357,7 +356,7 @@ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1); - if (!(prttsyn_stat & (1 << index))) + if (!(prttsyn_stat & BIT(index))) return; lo = rd32(hw, I40E_PRTTSYN_RXTIME_L(index)); diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index a72278c265c2..330e4ef43cd8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -464,7 +464,7 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, error = (qw & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >> I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT; - if (error == (0x1 << I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) { + if (error == BIT(I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) { if ((rx_desc->wb.qword0.hi_dword.fd_id != 0) || (I40E_DEBUG_FD & pf->hw.debug_mask)) dev_warn(&pdev->dev, "ntuple filter loc = %d, could not be added\n", @@ -509,8 +509,7 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, dev_info(&pdev->dev, "FD filter programming failed due to incorrect filter parameters\n"); } - } else if (error == - (0x1 << I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) { + } else if (error == BIT(I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) { if (I40E_DEBUG_FD & pf->hw.debug_mask) dev_info(&pdev->dev, "ntuple filter fd_id = %d, could not be removed\n", rx_desc->wb.qword0.hi_dword.fd_id); @@ -1363,7 +1362,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, return; /* did the hardware decode the packet and checksum? */ - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_L3L4P_SHIFT))) return; /* both known and outer_ip must be set for the below code to work */ @@ -1378,25 +1377,25 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ipv6 = true; if (ipv4 && - (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | - (1 << I40E_RX_DESC_ERROR_EIPE_SHIFT)))) + (rx_error & (BIT(I40E_RX_DESC_ERROR_IPE_SHIFT) | + BIT(I40E_RX_DESC_ERROR_EIPE_SHIFT)))) goto checksum_fail; /* likely incorrect csum if alternate IP extension headers found */ if (ipv6 && - rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) + rx_status & BIT(I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) /* don't increment checksum err here, non-fatal err */ return; /* there was some L4 error, count error and punt packet to the stack */ - if (rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT)) + if (rx_error & BIT(I40E_RX_DESC_ERROR_L4E_SHIFT)) goto checksum_fail; /* handle packets that were not able to be checksummed due * to arrival speed, in this case the stack can compute * the csum. */ - if (rx_error & (1 << I40E_RX_DESC_ERROR_PPRS_SHIFT)) + if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT)) return; /* If VXLAN traffic has an outer UDPv4 checksum we need to check @@ -1520,7 +1519,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_DD_SHIFT))) break; /* This memory barrier is needed to keep us from reading @@ -1561,8 +1560,8 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >> I40E_RXD_QW1_ERROR_SHIFT; - rx_hbo = rx_error & (1 << I40E_RX_DESC_ERROR_HBO_SHIFT); - rx_error &= ~(1 << I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_hbo = rx_error & BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_error &= ~BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; @@ -1614,7 +1613,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) I40E_RX_INCREMENT(rx_ring, i); if (unlikely( - !(rx_status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)))) { + !(rx_status & BIT(I40E_RX_DESC_STATUS_EOF_SHIFT)))) { struct i40e_rx_buffer *next_buffer; next_buffer = &rx_ring->rx_bi[i]; @@ -1624,7 +1623,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) } /* ERR_MASK will only have valid bits if EOP set */ - if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { + if (unlikely(rx_error & BIT(I40E_RX_DESC_ERROR_RXE_SHIFT))) { dev_kfree_skb_any(skb); continue; } @@ -1646,7 +1645,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) i40e_rx_checksum(vsi, skb, rx_status, rx_error, rx_ptype); - vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) + vlan_tag = rx_status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; #ifdef I40E_FCOE @@ -1707,7 +1706,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_DD_SHIFT))) break; /* This memory barrier is needed to keep us from reading @@ -1730,7 +1729,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >> I40E_RXD_QW1_ERROR_SHIFT; - rx_error &= ~(1 << I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_error &= ~BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; @@ -1748,13 +1747,13 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) I40E_RX_INCREMENT(rx_ring, i); if (unlikely( - !(rx_status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)))) { + !(rx_status & BIT(I40E_RX_DESC_STATUS_EOF_SHIFT)))) { rx_ring->rx_stats.non_eop_descs++; continue; } /* ERR_MASK will only have valid bits if EOP set */ - if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { + if (unlikely(rx_error & BIT(I40E_RX_DESC_ERROR_RXE_SHIFT))) { dev_kfree_skb_any(skb); /* TODO: shouldn't we increment a counter indicating the * drop? @@ -1779,7 +1778,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) i40e_rx_checksum(vsi, skb, rx_status, rx_error, rx_ptype); - vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) + vlan_tag = rx_status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; #ifdef I40E_FCOE diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 0dc48dc9ca61..429833c47245 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -66,17 +66,17 @@ enum i40e_dyn_idx_t { /* Supported RSS offloads */ #define I40E_DEFAULT_RSS_HENA ( \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | \ - ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD)) + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6) | \ + BIT_ULL(I40E_FILTER_PCTYPE_L2_PAYLOAD)) /* Supported Rx Buffer Sizes */ #define I40E_RXBUFFER_512 512 /* Used for packet split */ @@ -129,17 +129,17 @@ enum i40e_dyn_idx_t { #define DESC_NEEDED (MAX_SKB_FRAGS + 4) #define I40E_MIN_DESC_PENDING 4 -#define I40E_TX_FLAGS_CSUM (u32)(1) -#define I40E_TX_FLAGS_HW_VLAN (u32)(1 << 1) -#define I40E_TX_FLAGS_SW_VLAN (u32)(1 << 2) -#define I40E_TX_FLAGS_TSO (u32)(1 << 3) -#define I40E_TX_FLAGS_IPV4 (u32)(1 << 4) -#define I40E_TX_FLAGS_IPV6 (u32)(1 << 5) -#define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) -#define I40E_TX_FLAGS_FSO (u32)(1 << 7) -#define I40E_TX_FLAGS_TSYN (u32)(1 << 8) -#define I40E_TX_FLAGS_FD_SB (u32)(1 << 9) -#define I40E_TX_FLAGS_VXLAN_TUNNEL (u32)(1 << 10) +#define I40E_TX_FLAGS_CSUM BIT(0) +#define I40E_TX_FLAGS_HW_VLAN BIT(1) +#define I40E_TX_FLAGS_SW_VLAN BIT(2) +#define I40E_TX_FLAGS_TSO BIT(3) +#define I40E_TX_FLAGS_IPV4 BIT(4) +#define I40E_TX_FLAGS_IPV6 BIT(5) +#define I40E_TX_FLAGS_FCCRC BIT(6) +#define I40E_TX_FLAGS_FSO BIT(7) +#define I40E_TX_FLAGS_TSYN BIT(8) +#define I40E_TX_FLAGS_FD_SB BIT(9) +#define I40E_TX_FLAGS_VXLAN_TUNNEL BIT(10) #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 0cabf04cf23b..a20128b82b62 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -611,7 +611,7 @@ enum i40e_rx_desc_status_bits { }; #define I40E_RXD_QW1_STATUS_SHIFT 0 -#define I40E_RXD_QW1_STATUS_MASK (((1 << I40E_RX_DESC_STATUS_LAST) - 1) \ +#define I40E_RXD_QW1_STATUS_MASK ((BIT(I40E_RX_DESC_STATUS_LAST) - 1) \ << I40E_RXD_QW1_STATUS_SHIFT) #define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT I40E_RX_DESC_STATUS_TSYNINDX_SHIFT @@ -619,8 +619,8 @@ enum i40e_rx_desc_status_bits { I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT) #define I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT I40E_RX_DESC_STATUS_TSYNVALID_SHIFT -#define I40E_RXD_QW1_STATUS_TSYNVALID_MASK (0x1UL << \ - I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT) +#define I40E_RXD_QW1_STATUS_TSYNVALID_MASK \ + BIT_ULL(I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT) enum i40e_rx_desc_fltstat_values { I40E_RX_DESC_FLTSTAT_NO_DATA = 0, @@ -754,8 +754,7 @@ enum i40e_rx_ptype_payload_layer { I40E_RXD_QW1_LENGTH_HBUF_SHIFT) #define I40E_RXD_QW1_LENGTH_SPH_SHIFT 63 -#define I40E_RXD_QW1_LENGTH_SPH_MASK (0x1ULL << \ - I40E_RXD_QW1_LENGTH_SPH_SHIFT) +#define I40E_RXD_QW1_LENGTH_SPH_MASK BIT_ULL(I40E_RXD_QW1_LENGTH_SPH_SHIFT) enum i40e_rx_desc_ext_status_bits { /* Note: These are predefined bit offsets */ @@ -931,12 +930,12 @@ enum i40e_tx_ctx_desc_eipt_offload { #define I40E_TXD_CTX_QW0_NATT_SHIFT 9 #define I40E_TXD_CTX_QW0_NATT_MASK (0x3ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) -#define I40E_TXD_CTX_UDP_TUNNELING (0x1ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) +#define I40E_TXD_CTX_UDP_TUNNELING BIT_ULL(I40E_TXD_CTX_QW0_NATT_SHIFT) #define I40E_TXD_CTX_GRE_TUNNELING (0x2ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) #define I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT 11 -#define I40E_TXD_CTX_QW0_EIP_NOINC_MASK (0x1ULL << \ - I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT) +#define I40E_TXD_CTX_QW0_EIP_NOINC_MASK \ + BIT_ULL(I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT) #define I40E_TXD_CTX_EIP_NOINC_IPID_CONST I40E_TXD_CTX_QW0_EIP_NOINC_MASK @@ -1001,8 +1000,8 @@ enum i40e_filter_program_desc_fd_status { }; #define I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT 23 -#define I40E_TXD_FLTR_QW0_DEST_VSI_MASK (0x1FFUL << \ - I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) +#define I40E_TXD_FLTR_QW0_DEST_VSI_MASK \ + BIT_ULL(I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) #define I40E_TXD_FLTR_QW1_CMD_SHIFT 4 #define I40E_TXD_FLTR_QW1_CMD_MASK (0xFFFFULL << \ @@ -1020,8 +1019,7 @@ enum i40e_filter_program_desc_pcmd { #define I40E_TXD_FLTR_QW1_DEST_MASK (0x3ULL << I40E_TXD_FLTR_QW1_DEST_SHIFT) #define I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT (0x7ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT) -#define I40E_TXD_FLTR_QW1_CNT_ENA_MASK (0x1ULL << \ - I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT) +#define I40E_TXD_FLTR_QW1_CNT_ENA_MASK BIT_ULL(I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT) #define I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT (0x9ULL + \ I40E_TXD_FLTR_QW1_CMD_SHIFT) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 51aff7072195..d29d4062addf 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -277,16 +277,14 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id, } tempmap = vecmap->rxq_map; for_each_set_bit(vsi_queue_id, &tempmap, I40E_MAX_VSI_QP) { - linklistmap |= (1 << - (I40E_VIRTCHNL_SUPPORTED_QTYPES * - vsi_queue_id)); + linklistmap |= (BIT(I40E_VIRTCHNL_SUPPORTED_QTYPES * + vsi_queue_id)); } tempmap = vecmap->txq_map; for_each_set_bit(vsi_queue_id, &tempmap, I40E_MAX_VSI_QP) { - linklistmap |= (1 << - (I40E_VIRTCHNL_SUPPORTED_QTYPES * vsi_queue_id - + 1)); + linklistmap |= (BIT(I40E_VIRTCHNL_SUPPORTED_QTYPES * + vsi_queue_id + 1)); } next_q = find_first_bit(&linklistmap, @@ -332,7 +330,7 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id, reg = (vector_id) | (qtype << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) | (pf_queue_id << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | - (1 << I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) | + BIT(I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) | (itr_idx << I40E_QINT_RQCTL_ITR_INDX_SHIFT); wr32(hw, reg_idx, reg); } @@ -897,7 +895,7 @@ void i40e_free_vfs(struct i40e_pf *pf) for (vf_id = 0; vf_id < tmp; vf_id++) { reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32; bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32; - wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx)); + wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx)); } } clear_bit(__I40E_VF_DISABLE, &pf->state); @@ -1983,9 +1981,9 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf) /* read GLGEN_VFLRSTAT register to find out the flr VFs */ vf = &pf->vf[vf_id]; reg = rd32(hw, I40E_GLGEN_VFLRSTAT(reg_idx)); - if (reg & (1 << bit_idx)) { + if (reg & BIT(bit_idx)) { /* clear the bit in GLGEN_VFLRSTAT */ - wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx)); + wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx)); if (!test_bit(__I40E_DOWN, &pf->state)) i40e_reset_vf(vf, true); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h index adc6f71f40a8..00ed24bfce13 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h @@ -127,8 +127,8 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) | \ - (1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ - val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + BIT(I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ + val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, val1); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ @@ -147,7 +147,7 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT); \ - val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, 0); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index cf3530335c68..60f88e4ad065 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -850,7 +850,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, return; /* did the hardware decode the packet and checksum? */ - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_L3L4P_SHIFT))) return; /* both known and outer_ip must be set for the below code to work */ @@ -865,25 +865,25 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ipv6 = true; if (ipv4 && - (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | - (1 << I40E_RX_DESC_ERROR_EIPE_SHIFT)))) + (rx_error & (BIT(I40E_RX_DESC_ERROR_IPE_SHIFT) | + BIT(I40E_RX_DESC_ERROR_EIPE_SHIFT)))) goto checksum_fail; /* likely incorrect csum if alternate IP extension headers found */ if (ipv6 && - rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) + rx_status & BIT(I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) /* don't increment checksum err here, non-fatal err */ return; /* there was some L4 error, count error and punt packet to the stack */ - if (rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT)) + if (rx_error & BIT(I40E_RX_DESC_ERROR_L4E_SHIFT)) goto checksum_fail; /* handle packets that were not able to be checksummed due * to arrival speed, in this case the stack can compute * the csum. */ - if (rx_error & (1 << I40E_RX_DESC_ERROR_PPRS_SHIFT)) + if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT)) return; /* If VXLAN traffic has an outer UDPv4 checksum we need to check @@ -1004,7 +1004,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_DD_SHIFT))) break; /* This memory barrier is needed to keep us from reading @@ -1040,8 +1040,8 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >> I40E_RXD_QW1_ERROR_SHIFT; - rx_hbo = rx_error & (1 << I40E_RX_DESC_ERROR_HBO_SHIFT); - rx_error &= ~(1 << I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_hbo = rx_error & BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_error &= ~BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; @@ -1093,7 +1093,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) I40E_RX_INCREMENT(rx_ring, i); if (unlikely( - !(rx_status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)))) { + !(rx_status & BIT(I40E_RX_DESC_STATUS_EOF_SHIFT)))) { struct i40e_rx_buffer *next_buffer; next_buffer = &rx_ring->rx_bi[i]; @@ -1103,7 +1103,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) } /* ERR_MASK will only have valid bits if EOP set */ - if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { + if (unlikely(rx_error & BIT(I40E_RX_DESC_ERROR_RXE_SHIFT))) { dev_kfree_skb_any(skb); continue; } @@ -1118,7 +1118,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) i40e_rx_checksum(vsi, skb, rx_status, rx_error, rx_ptype); - vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) + vlan_tag = rx_status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; #ifdef I40E_FCOE @@ -1179,7 +1179,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_DD_SHIFT))) break; /* This memory barrier is needed to keep us from reading @@ -1197,7 +1197,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >> I40E_RXD_QW1_ERROR_SHIFT; - rx_error &= ~(1 << I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_error &= ~BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; @@ -1215,13 +1215,13 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) I40E_RX_INCREMENT(rx_ring, i); if (unlikely( - !(rx_status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)))) { + !(rx_status & BIT(I40E_RX_DESC_STATUS_EOF_SHIFT)))) { rx_ring->rx_stats.non_eop_descs++; continue; } /* ERR_MASK will only have valid bits if EOP set */ - if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { + if (unlikely(rx_error & BIT(I40E_RX_DESC_ERROR_RXE_SHIFT))) { dev_kfree_skb_any(skb); /* TODO: shouldn't we increment a counter indicating the * drop? @@ -1239,7 +1239,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) i40e_rx_checksum(vsi, skb, rx_status, rx_error, rx_ptype); - vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) + vlan_tag = rx_status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; i40e_receive_skb(rx_ring, skb, vlan_tag); @@ -1314,8 +1314,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, if (!test_bit(__I40E_DOWN, &vsi->state)) wr32(hw, I40E_VFINT_DYN_CTLN1(vector - 1), val); } else { - i40evf_irq_enable_queues(vsi->back, - 1 << q_vector->v_idx); + i40evf_irq_enable_queues(vsi->back, BIT(q_vector->v_idx)); } } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h index e7a34f899f2c..6b47c818d1f0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h @@ -66,17 +66,17 @@ enum i40e_dyn_idx_t { /* Supported RSS offloads */ #define I40E_DEFAULT_RSS_HENA ( \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | \ - ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD)) + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6) | \ + BIT_ULL(I40E_FILTER_PCTYPE_L2_PAYLOAD)) /* Supported Rx Buffer Sizes */ #define I40E_RXBUFFER_512 512 /* Used for packet split */ @@ -129,16 +129,16 @@ enum i40e_dyn_idx_t { #define DESC_NEEDED (MAX_SKB_FRAGS + 4) #define I40E_MIN_DESC_PENDING 4 -#define I40E_TX_FLAGS_CSUM (u32)(1) -#define I40E_TX_FLAGS_HW_VLAN (u32)(1 << 1) -#define I40E_TX_FLAGS_SW_VLAN (u32)(1 << 2) -#define I40E_TX_FLAGS_TSO (u32)(1 << 3) -#define I40E_TX_FLAGS_IPV4 (u32)(1 << 4) -#define I40E_TX_FLAGS_IPV6 (u32)(1 << 5) -#define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) -#define I40E_TX_FLAGS_FSO (u32)(1 << 7) -#define I40E_TX_FLAGS_FD_SB (u32)(1 << 9) -#define I40E_TX_FLAGS_VXLAN_TUNNEL (u32)(1 << 10) +#define I40E_TX_FLAGS_CSUM BIT(0) +#define I40E_TX_FLAGS_HW_VLAN BIT(1) +#define I40E_TX_FLAGS_SW_VLAN BIT(2) +#define I40E_TX_FLAGS_TSO BIT(3) +#define I40E_TX_FLAGS_IPV4 BIT(4) +#define I40E_TX_FLAGS_IPV6 BIT(5) +#define I40E_TX_FLAGS_FCCRC BIT(6) +#define I40E_TX_FLAGS_FSO BIT(7) +#define I40E_TX_FLAGS_FD_SB BIT(9) +#define I40E_TX_FLAGS_VXLAN_TUNNEL BIT(10) #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index cbf94bd4f2bf..4ba9a012dcba 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -605,7 +605,7 @@ enum i40e_rx_desc_status_bits { }; #define I40E_RXD_QW1_STATUS_SHIFT 0 -#define I40E_RXD_QW1_STATUS_MASK (((1 << I40E_RX_DESC_STATUS_LAST) - 1) \ +#define I40E_RXD_QW1_STATUS_MASK ((BIT(I40E_RX_DESC_STATUS_LAST) - 1) \ << I40E_RXD_QW1_STATUS_SHIFT) #define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT I40E_RX_DESC_STATUS_TSYNINDX_SHIFT @@ -613,8 +613,8 @@ enum i40e_rx_desc_status_bits { I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT) #define I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT I40E_RX_DESC_STATUS_TSYNVALID_SHIFT -#define I40E_RXD_QW1_STATUS_TSYNVALID_MASK (0x1UL << \ - I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT) +#define I40E_RXD_QW1_STATUS_TSYNVALID_MASK \ + BIT_ULL(I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT) enum i40e_rx_desc_fltstat_values { I40E_RX_DESC_FLTSTAT_NO_DATA = 0, @@ -748,8 +748,7 @@ enum i40e_rx_ptype_payload_layer { I40E_RXD_QW1_LENGTH_HBUF_SHIFT) #define I40E_RXD_QW1_LENGTH_SPH_SHIFT 63 -#define I40E_RXD_QW1_LENGTH_SPH_MASK (0x1ULL << \ - I40E_RXD_QW1_LENGTH_SPH_SHIFT) +#define I40E_RXD_QW1_LENGTH_SPH_MASK BIT_ULL(I40E_RXD_QW1_LENGTH_SPH_SHIFT) enum i40e_rx_desc_ext_status_bits { /* Note: These are predefined bit offsets */ @@ -925,12 +924,12 @@ enum i40e_tx_ctx_desc_eipt_offload { #define I40E_TXD_CTX_QW0_NATT_SHIFT 9 #define I40E_TXD_CTX_QW0_NATT_MASK (0x3ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) -#define I40E_TXD_CTX_UDP_TUNNELING (0x1ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) +#define I40E_TXD_CTX_UDP_TUNNELING BIT_ULL(I40E_TXD_CTX_QW0_NATT_SHIFT) #define I40E_TXD_CTX_GRE_TUNNELING (0x2ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) #define I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT 11 -#define I40E_TXD_CTX_QW0_EIP_NOINC_MASK (0x1ULL << \ - I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT) +#define I40E_TXD_CTX_QW0_EIP_NOINC_MASK \ + BIT_ULL(I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT) #define I40E_TXD_CTX_EIP_NOINC_IPID_CONST I40E_TXD_CTX_QW0_EIP_NOINC_MASK @@ -995,8 +994,8 @@ enum i40e_filter_program_desc_fd_status { }; #define I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT 23 -#define I40E_TXD_FLTR_QW0_DEST_VSI_MASK (0x1FFUL << \ - I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) +#define I40E_TXD_FLTR_QW0_DEST_VSI_MASK \ + BIT_ULL(I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) #define I40E_TXD_FLTR_QW1_CMD_SHIFT 4 #define I40E_TXD_FLTR_QW1_CMD_MASK (0xFFFFULL << \ @@ -1014,8 +1013,7 @@ enum i40e_filter_program_desc_pcmd { #define I40E_TXD_FLTR_QW1_DEST_MASK (0x3ULL << I40E_TXD_FLTR_QW1_DEST_SHIFT) #define I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT (0x7ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT) -#define I40E_TXD_FLTR_QW1_CNT_ENA_MASK (0x1ULL << \ - I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT) +#define I40E_TXD_FLTR_QW1_CNT_ENA_MASK BIT_ULL(I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT) #define I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT (0x9ULL + \ I40E_TXD_FLTR_QW1_CMD_SHIFT) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index dfc5bc539890..c33c7cce52fe 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -207,17 +207,17 @@ struct i40evf_adapter { struct msix_entry *msix_entries; u32 flags; -#define I40EVF_FLAG_RX_CSUM_ENABLED (u32)(1) -#define I40EVF_FLAG_RX_1BUF_CAPABLE (u32)(1 << 1) -#define I40EVF_FLAG_RX_PS_CAPABLE (u32)(1 << 2) -#define I40EVF_FLAG_RX_PS_ENABLED (u32)(1 << 3) -#define I40EVF_FLAG_IN_NETPOLL (u32)(1 << 4) -#define I40EVF_FLAG_IMIR_ENABLED (u32)(1 << 5) -#define I40EVF_FLAG_MQ_CAPABLE (u32)(1 << 6) -#define I40EVF_FLAG_NEED_LINK_UPDATE (u32)(1 << 7) -#define I40EVF_FLAG_PF_COMMS_FAILED (u32)(1 << 8) -#define I40EVF_FLAG_RESET_PENDING (u32)(1 << 9) -#define I40EVF_FLAG_RESET_NEEDED (u32)(1 << 10) +#define I40EVF_FLAG_RX_CSUM_ENABLED BIT(0) +#define I40EVF_FLAG_RX_1BUF_CAPABLE BIT(1) +#define I40EVF_FLAG_RX_PS_CAPABLE BIT(2) +#define I40EVF_FLAG_RX_PS_ENABLED BIT(3) +#define I40EVF_FLAG_IN_NETPOLL BIT(4) +#define I40EVF_FLAG_IMIR_ENABLED BIT(5) +#define I40EVF_FLAG_MQ_CAPABLE BIT(6) +#define I40EVF_FLAG_NEED_LINK_UPDATE BIT(7) +#define I40EVF_FLAG_PF_COMMS_FAILED BIT(8) +#define I40EVF_FLAG_RESET_PENDING BIT(9) +#define I40EVF_FLAG_RESET_NEEDED BIT(10) /* duplcates for common code */ #define I40E_FLAG_FDIR_ATR_ENABLED 0 #define I40E_FLAG_DCB_ENABLED 0 @@ -225,16 +225,16 @@ struct i40evf_adapter { #define I40E_FLAG_RX_CSUM_ENABLED I40EVF_FLAG_RX_CSUM_ENABLED /* flags for admin queue service task */ u32 aq_required; -#define I40EVF_FLAG_AQ_ENABLE_QUEUES (u32)(1) -#define I40EVF_FLAG_AQ_DISABLE_QUEUES (u32)(1 << 1) -#define I40EVF_FLAG_AQ_ADD_MAC_FILTER (u32)(1 << 2) -#define I40EVF_FLAG_AQ_ADD_VLAN_FILTER (u32)(1 << 3) -#define I40EVF_FLAG_AQ_DEL_MAC_FILTER (u32)(1 << 4) -#define I40EVF_FLAG_AQ_DEL_VLAN_FILTER (u32)(1 << 5) -#define I40EVF_FLAG_AQ_CONFIGURE_QUEUES (u32)(1 << 6) -#define I40EVF_FLAG_AQ_MAP_VECTORS (u32)(1 << 7) -#define I40EVF_FLAG_AQ_HANDLE_RESET (u32)(1 << 8) -#define I40EVF_FLAG_AQ_GET_CONFIG (u32)(1 << 10) +#define I40EVF_FLAG_AQ_ENABLE_QUEUES BIT(0) +#define I40EVF_FLAG_AQ_DISABLE_QUEUES BIT(1) +#define I40EVF_FLAG_AQ_ADD_MAC_FILTER BIT(2) +#define I40EVF_FLAG_AQ_ADD_VLAN_FILTER BIT(3) +#define I40EVF_FLAG_AQ_DEL_MAC_FILTER BIT(4) +#define I40EVF_FLAG_AQ_DEL_VLAN_FILTER BIT(5) +#define I40EVF_FLAG_AQ_CONFIGURE_QUEUES BIT(6) +#define I40EVF_FLAG_AQ_MAP_VECTORS BIT(7) +#define I40EVF_FLAG_AQ_HANDLE_RESET BIT(8) +#define I40EVF_FLAG_AQ_GET_CONFIG BIT(10) /* OS defined structs */ struct net_device *netdev; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c index 2b53c870e7f1..4790437a50ac 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c @@ -381,11 +381,11 @@ static int i40evf_get_rss_hash_opts(struct i40evf_adapter *adapter, switch (cmd->flow_type) { case TCP_V4_FLOW: - if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP)) + if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP)) cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; case UDP_V4_FLOW: - if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP)) + if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP)) cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; @@ -397,11 +397,11 @@ static int i40evf_get_rss_hash_opts(struct i40evf_adapter *adapter, break; case TCP_V6_FLOW: - if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP)) + if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP)) cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; case UDP_V6_FLOW: - if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP)) + if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP)) cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; @@ -479,10 +479,10 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, case TCP_V4_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); + hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP); break; default: return -EINVAL; @@ -491,10 +491,10 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, case TCP_V6_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); + hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP); break; default: return -EINVAL; @@ -503,12 +503,12 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, case UDP_V4_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); + hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4)); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4)); break; default: return -EINVAL; @@ -517,12 +517,12 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, case UDP_V6_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); + hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6)); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6)); break; default: return -EINVAL; @@ -535,7 +535,7 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, if ((nfc->data & RXH_L4_B_0_1) || (nfc->data & RXH_L4_B_2_3)) return -EINVAL; - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); break; case AH_ESP_V6_FLOW: case AH_V6_FLOW: @@ -544,15 +544,15 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, if ((nfc->data & RXH_L4_B_0_1) || (nfc->data & RXH_L4_B_2_3)) return -EINVAL; - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); break; case IPV4_FLOW: - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4)); break; case IPV6_FLOW: - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6)); break; default: return -EINVAL; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index f43ac9c7e826..1503cad918d8 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -240,7 +240,7 @@ void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask) int i; for (i = 1; i < adapter->num_msix_vectors; i++) { - if (mask & (1 << (i - 1))) { + if (mask & BIT(i - 1)) { wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), I40E_VFINT_DYN_CTLN1_INTENA_MASK | I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | @@ -268,7 +268,7 @@ static void i40evf_fire_sw_int(struct i40evf_adapter *adapter, u32 mask) wr32(hw, I40E_VFINT_DYN_CTL01, dyn_ctl); } for (i = 1; i < adapter->num_msix_vectors; i++) { - if (mask & (1 << i)) { + if (mask & BIT(i)) { dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTLN1(i - 1)); dyn_ctl |= I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK | I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | @@ -377,7 +377,7 @@ i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx) q_vector->tx.count++; q_vector->tx.latency_range = I40E_LOW_LATENCY; q_vector->num_ringpairs++; - q_vector->ring_mask |= (1 << t_idx); + q_vector->ring_mask |= BIT(t_idx); } /** @@ -2320,7 +2320,7 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw = &adapter->hw; hw->back = adapter; - adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1; + adapter->msg_enable = BIT(DEFAULT_DEBUG_LEVEL_SHIFT) - 1; adapter->state = __I40EVF_STARTUP; /* Call save state here because it relies on the adapter struct. */ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index becd300fca7c..d4eb1a5e7d42 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -294,7 +294,7 @@ void i40evf_enable_queues(struct i40evf_adapter *adapter) } adapter->current_op = I40E_VIRTCHNL_OP_ENABLE_QUEUES; vqs.vsi_id = adapter->vsi_res->vsi_id; - vqs.tx_queues = (1 << adapter->num_active_queues) - 1; + vqs.tx_queues = BIT(adapter->num_active_queues) - 1; vqs.rx_queues = vqs.tx_queues; adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_QUEUES; i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ENABLE_QUEUES, @@ -319,7 +319,7 @@ void i40evf_disable_queues(struct i40evf_adapter *adapter) } adapter->current_op = I40E_VIRTCHNL_OP_DISABLE_QUEUES; vqs.vsi_id = adapter->vsi_res->vsi_id; - vqs.tx_queues = (1 << adapter->num_active_queues) - 1; + vqs.tx_queues = BIT(adapter->num_active_queues) - 1; vqs.rx_queues = vqs.tx_queues; adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_QUEUES; i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DISABLE_QUEUES, -- cgit v1.3-6-gb490 From a70f0d027c83350ad46ca3e86e4c781bfed7fcc2 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Wed, 22 Jul 2015 18:23:26 +0800 Subject: regulator: tps6586x: silence pointer-to-int-cast of_regulator_match.driver_data is (void *). tps6586x uses it to store an anonymous enum value (those TPS6586X_ID_ values). Later, it tries to extract the ID by casting directly to an int, which is a no-no ([-Wpointer-to-int-cast]): drivers/regulator/tps6586x-regulator.c: In function 'tps6586x_parse_regulator_dt': drivers/regulator/tps6586x-regulator.c:430:8: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] id = (int)tps6586x_matches[i].driver_data; ^ Instead of casting to int, uintptr_t is better suited for receiving and comparing integers extracted from void *. This is especially true on 64-bit systems where sizeof(void *) != sizeof(int). Signed-off-by: Daniel Kurtz Signed-off-by: Mark Brown --- drivers/regulator/tps6586x-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 2852de05d64d..9e9d22038017 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -422,12 +422,12 @@ static struct tps6586x_platform_data *tps6586x_parse_regulator_dt( return NULL; for (i = 0; i < num; i++) { - int id; + uintptr_t id; if (!tps6586x_matches[i].init_data) continue; pdata->reg_init_data[i] = tps6586x_matches[i].init_data; - id = (int)tps6586x_matches[i].driver_data; + id = (uintptr_t)tps6586x_matches[i].driver_data; if (id == TPS6586X_ID_SYS) sys_rail = pdata->reg_init_data[i]->constraints.name; -- cgit v1.3-6-gb490 From 0f41421256afdfcadf0ae2d8bf83ecb7ff3ac49e Mon Sep 17 00:00:00 2001 From: Murali Karicheri Date: Tue, 21 Jul 2015 17:54:11 -0400 Subject: PCI: designware: Don't complain missing *config* reg space if va_cfg0 is set Currently on Keystone SoCs, we always complain: keystone-pcie 21021000.pcie: missing *config* reg space Keystone uses an older version of DesignWare hardware that doesn't have ATU support. So va_cfg0_base and va_cfg1_base are already set up in ks_dw_pcie_host_init() before calling dw_pcie_host_init(), and they point to the remote config space address va (both same for Keystone). Add a check to avoid this boot noise on Keystone. Signed-off-by: Murali Karicheri Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-designware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 69486be7181e..b48b8a2c50b9 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -388,7 +388,7 @@ int dw_pcie_host_init(struct pcie_port *pp) addrp = of_get_address(np, index, NULL, NULL); pp->cfg0_mod_base = of_read_number(addrp, ns); pp->cfg1_mod_base = pp->cfg0_mod_base + pp->cfg0_size; - } else { + } else if (!pp->va_cfg0_base) { dev_err(pp->dev, "missing *config* reg space\n"); } -- cgit v1.3-6-gb490 From fac5e5b912bd1b42bad292e0b03956967229b45b Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Fri, 19 Jun 2015 08:46:15 +0000 Subject: Bluetooth: dtl1_cs: Fix coding style -- clean up Braces {} are not necessary for single statement blocks reported by checkpatch Signed-off-by: Prasanna Karthik Signed-off-by: Marcel Holtmann --- drivers/bluetooth/dtl1_cs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 78e10f0c65b2..09c130d73ba3 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -182,9 +182,9 @@ static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb) int i; printk(KERN_INFO "Bluetooth: Nokia control data ="); - for (i = 0; i < skb->len; i++) { + for (i = 0; i < skb->len; i++) printk(" %02x", skb->data[i]); - } + printk("\n"); /* transition to active state */ -- cgit v1.3-6-gb490 From ca93cee5a56e5199622bea8bff24c0a96e70c8f1 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Wed, 1 Jul 2015 12:20:26 +0200 Subject: Bluetooth: hci_uart: Add basic support for Intel Lightning Peak devices The Intel Lightning Peak devices do not come with Bluetooth firmware loaded and thus require a full download of the operational Bluetooth firmware when the device is attached via the Bluetooth line discipline. Lightning Peak devices start with a bootloader mode that only accepts a very limited set of HCI commands. The supported commands are enough to identify the hardware and select the right firmware to load. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 1 + drivers/bluetooth/hci_intel.c | 604 ++++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 5 + 4 files changed, 616 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 2e777071e1dc..79e8234b1aa5 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -132,6 +132,7 @@ config BT_HCIUART_3WIRE config BT_HCIUART_INTEL bool "Intel protocol support" depends on BT_HCIUART + select BT_HCIUART_H4 select BT_INTEL help The Intel protocol support enables Bluetooth HCI over serial diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 5dd07bf05236..ade19aaeb5c5 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -24,8 +24,612 @@ #include #include #include +#include +#include #include #include #include "hci_uart.h" +#include "btintel.h" + +#define STATE_BOOTLOADER 0 +#define STATE_DOWNLOADING 1 +#define STATE_FIRMWARE_LOADED 2 +#define STATE_FIRMWARE_FAILED 3 +#define STATE_BOOTING 4 + +struct intel_data { + struct sk_buff *rx_skb; + struct sk_buff_head txq; + unsigned long flags; +}; + +static int intel_open(struct hci_uart *hu) +{ + struct intel_data *intel; + + BT_DBG("hu %p", hu); + + intel = kzalloc(sizeof(*intel), GFP_KERNEL); + if (!intel) + return -ENOMEM; + + skb_queue_head_init(&intel->txq); + + hu->priv = intel; + return 0; +} + +static int intel_close(struct hci_uart *hu) +{ + struct intel_data *intel = hu->priv; + + BT_DBG("hu %p", hu); + + skb_queue_purge(&intel->txq); + kfree_skb(intel->rx_skb); + kfree(intel); + + hu->priv = NULL; + return 0; +} + +static int intel_flush(struct hci_uart *hu) +{ + struct intel_data *intel = hu->priv; + + BT_DBG("hu %p", hu); + + skb_queue_purge(&intel->txq); + + return 0; +} + +static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) +{ + struct sk_buff *skb; + struct hci_event_hdr *hdr; + struct hci_ev_cmd_complete *evt; + + skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hdr = (struct hci_event_hdr *)skb_put(skb, sizeof(*hdr)); + hdr->evt = HCI_EV_CMD_COMPLETE; + hdr->plen = sizeof(*evt) + 1; + + evt = (struct hci_ev_cmd_complete *)skb_put(skb, sizeof(*evt)); + evt->ncmd = 0x01; + evt->opcode = cpu_to_le16(opcode); + + *skb_put(skb, 1) = 0x00; + + bt_cb(skb)->pkt_type = HCI_EVENT_PKT; + + return hci_recv_frame(hdev, skb); +} + +static int intel_secure_send(struct hci_dev *hdev, u8 fragment_type, + u32 plen, const void *param) +{ + while (plen > 0) { + struct sk_buff *skb; + u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; + + cmd_param[0] = fragment_type; + memcpy(cmd_param + 1, param, fragment_len); + + skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1, + cmd_param, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + + plen -= fragment_len; + param += fragment_len; + } + + return 0; +} + +static void intel_version_info(struct hci_dev *hdev, + struct intel_version *ver) +{ + const char *variant; + + switch (ver->fw_variant) { + case 0x06: + variant = "Bootloader"; + break; + case 0x23: + variant = "Firmware"; + break; + default: + return; + } + + BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name, + variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, + ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy); +} + +static int intel_setup(struct hci_uart *hu) +{ + static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01, + 0x00, 0x08, 0x04, 0x00 }; + struct intel_data *intel = hu->priv; + struct hci_dev *hdev = hu->hdev; + struct sk_buff *skb; + struct intel_version *ver; + struct intel_boot_params *params; + const struct firmware *fw; + const u8 *fw_ptr; + char fwname[64]; + u32 frag_len; + ktime_t calltime, delta, rettime; + unsigned long long duration; + int err; + + BT_DBG("%s", hdev->name); + + calltime = ktime_get(); + + set_bit(STATE_BOOTLOADER, &intel->flags); + + /* Read the Intel version information to determine if the device + * is in bootloader mode or if it already has operational firmware + * loaded. + */ + skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reading Intel version information failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*ver)) { + BT_ERR("%s: Intel version event size mismatch", hdev->name); + kfree_skb(skb); + return -EILSEQ; + } + + ver = (struct intel_version *)skb->data; + if (ver->status) { + BT_ERR("%s: Intel version command failure (%02x)", + hdev->name, ver->status); + err = -bt_to_errno(ver->status); + kfree_skb(skb); + return err; + } + + /* The hardware platform number has a fixed value of 0x37 and + * for now only accept this single value. + */ + if (ver->hw_platform != 0x37) { + BT_ERR("%s: Unsupported Intel hardware platform (%u)", + hdev->name, ver->hw_platform); + kfree_skb(skb); + return -EINVAL; + } + + /* At the moment only the hardware variant iBT 3.0 (LnP/SfP) is + * supported by this firmware loading method. This check has been + * put in place to ensure correct forward compatibility options + * when newer hardware variants come along. + */ + if (ver->hw_variant != 0x0b) { + BT_ERR("%s: Unsupported Intel hardware variant (%u)", + hdev->name, ver->hw_variant); + kfree_skb(skb); + return -EINVAL; + } + + intel_version_info(hdev, ver); + + /* The firmware variant determines if the device is in bootloader + * mode or is running operational firmware. The value 0x06 identifies + * the bootloader and the value 0x23 identifies the operational + * firmware. + * + * When the operational firmware is already present, then only + * the check for valid Bluetooth device address is needed. This + * determines if the device will be added as configured or + * unconfigured controller. + * + * It is not possible to use the Secure Boot Parameters in this + * case since that command is only available in bootloader mode. + */ + if (ver->fw_variant == 0x23) { + kfree_skb(skb); + clear_bit(STATE_BOOTLOADER, &intel->flags); + btintel_check_bdaddr(hdev); + return 0; + } + + /* If the device is not in bootloader mode, then the only possible + * choice is to return an error and abort the device initialization. + */ + if (ver->fw_variant != 0x06) { + BT_ERR("%s: Unsupported Intel firmware variant (%u)", + hdev->name, ver->fw_variant); + kfree_skb(skb); + return -ENODEV; + } + + kfree_skb(skb); + + /* Read the secure boot parameters to identify the operating + * details of the bootloader. + */ + skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reading Intel boot parameters failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*params)) { + BT_ERR("%s: Intel boot parameters size mismatch", hdev->name); + kfree_skb(skb); + return -EILSEQ; + } + + params = (struct intel_boot_params *)skb->data; + if (params->status) { + BT_ERR("%s: Intel boot parameters command failure (%02x)", + hdev->name, params->status); + err = -bt_to_errno(params->status); + kfree_skb(skb); + return err; + } + + BT_INFO("%s: Device revision is %u", hdev->name, + le16_to_cpu(params->dev_revid)); + + BT_INFO("%s: Secure boot is %s", hdev->name, + params->secure_boot ? "enabled" : "disabled"); + + BT_INFO("%s: Minimum firmware build %u week %u %u", hdev->name, + params->min_fw_build_nn, params->min_fw_build_cw, + 2000 + params->min_fw_build_yy); + + /* It is required that every single firmware fragment is acknowledged + * with a command complete event. If the boot parameters indicate + * that this bootloader does not send them, then abort the setup. + */ + if (params->limited_cce != 0x00) { + BT_ERR("%s: Unsupported Intel firmware loading method (%u)", + hdev->name, params->limited_cce); + kfree_skb(skb); + return -EINVAL; + } + + /* If the OTP has no valid Bluetooth device address, then there will + * also be no valid address for the operational firmware. + */ + if (!bacmp(¶ms->otp_bdaddr, BDADDR_ANY)) { + BT_INFO("%s: No device address configured", hdev->name); + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + } + + /* With this Intel bootloader only the hardware variant and device + * revision information are used to select the right firmware. + * + * Currently this bootloader support is limited to hardware variant + * iBT 3.0 (LnP/SfP) which is identified by the value 11 (0x0b). + */ + snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.sfi", + le16_to_cpu(params->dev_revid)); + + err = request_firmware(&fw, fwname, &hdev->dev); + if (err < 0) { + BT_ERR("%s: Failed to load Intel firmware file (%d)", + hdev->name, err); + kfree_skb(skb); + return err; + } + + BT_INFO("%s: Found device firmware: %s", hdev->name, fwname); + + kfree_skb(skb); + + if (fw->size < 644) { + BT_ERR("%s: Invalid size of firmware file (%zu)", + hdev->name, fw->size); + err = -EBADF; + goto done; + } + + set_bit(STATE_DOWNLOADING, &intel->flags); + + /* Start the firmware download transaction with the Init fragment + * represented by the 128 bytes of CSS header. + */ + err = intel_secure_send(hdev, 0x00, 128, fw->data); + if (err < 0) { + BT_ERR("%s: Failed to send firmware header (%d)", + hdev->name, err); + goto done; + } + + /* Send the 256 bytes of public key information from the firmware + * as the PKey fragment. + */ + err = intel_secure_send(hdev, 0x03, 256, fw->data + 128); + if (err < 0) { + BT_ERR("%s: Failed to send firmware public key (%d)", + hdev->name, err); + goto done; + } + + /* Send the 256 bytes of signature information from the firmware + * as the Sign fragment. + */ + err = intel_secure_send(hdev, 0x02, 256, fw->data + 388); + if (err < 0) { + BT_ERR("%s: Failed to send firmware signature (%d)", + hdev->name, err); + goto done; + } + + fw_ptr = fw->data + 644; + frag_len = 0; + + while (fw_ptr - fw->data < fw->size) { + struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len); + + frag_len += sizeof(*cmd) + cmd->plen; + + BT_DBG("%s: patching %td/%zu", hdev->name, + (fw_ptr - fw->data), fw->size); + + /* The parameter length of the secure send command requires + * a 4 byte alignment. It happens so that the firmware file + * contains proper Intel_NOP commands to align the fragments + * as needed. + * + * Send set of commands with 4 byte alignment from the + * firmware data buffer as a single Data fragement. + */ + if (frag_len % 4) + continue; + + /* Send each command from the firmware data buffer as + * a single Data fragment. + */ + err = intel_secure_send(hdev, 0x01, frag_len, fw_ptr); + if (err < 0) { + BT_ERR("%s: Failed to send firmware data (%d)", + hdev->name, err); + goto done; + } + + fw_ptr += frag_len; + frag_len = 0; + } + + set_bit(STATE_FIRMWARE_LOADED, &intel->flags); + + BT_INFO("%s: Waiting for firmware download to complete", hdev->name); + + /* Before switching the device into operational mode and with that + * booting the loaded firmware, wait for the bootloader notification + * that all fragments have been successfully received. + * + * When the event processing receives the notification, then the + * STATE_DOWNLOADING flag will be cleared. + * + * The firmware loading should not take longer than 5 seconds + * and thus just timeout if that happens and fail the setup + * of this device. + */ + err = wait_on_bit_timeout(&intel->flags, STATE_DOWNLOADING, + TASK_INTERRUPTIBLE, + msecs_to_jiffies(5000)); + if (err == 1) { + BT_ERR("%s: Firmware loading interrupted", hdev->name); + err = -EINTR; + goto done; + } + + if (err) { + BT_ERR("%s: Firmware loading timeout", hdev->name); + err = -ETIMEDOUT; + goto done; + } + + if (test_bit(STATE_FIRMWARE_FAILED, &intel->flags)) { + BT_ERR("%s: Firmware loading failed", hdev->name); + err = -ENOEXEC; + goto done; + } + + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = (unsigned long long) ktime_to_ns(delta) >> 10; + + BT_INFO("%s: Firmware loaded in %llu usecs", hdev->name, duration); + +done: + release_firmware(fw); + + if (err < 0) + return err; + + calltime = ktime_get(); + + set_bit(STATE_BOOTING, &intel->flags); + + skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(reset_param), reset_param, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + + /* The bootloader will not indicate when the device is ready. This + * is done by the operational firmware sending bootup notification. + * + * Booting into operational firmware should not take longer than + * 1 second. However if that happens, then just fail the setup + * since something went wrong. + */ + BT_INFO("%s: Waiting for device to boot", hdev->name); + + err = wait_on_bit_timeout(&intel->flags, STATE_BOOTING, + TASK_INTERRUPTIBLE, + msecs_to_jiffies(1000)); + + if (err == 1) { + BT_ERR("%s: Device boot interrupted", hdev->name); + return -EINTR; + } + + if (err) { + BT_ERR("%s: Device boot timeout", hdev->name); + return -ETIMEDOUT; + } + + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = (unsigned long long) ktime_to_ns(delta) >> 10; + + BT_INFO("%s: Device booted in %llu usecs", hdev->name, duration); + + clear_bit(STATE_BOOTLOADER, &intel->flags); + + return 0; +} + +static int intel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + struct intel_data *intel = hu->priv; + struct hci_event_hdr *hdr; + + if (!test_bit(STATE_BOOTLOADER, &intel->flags)) + goto recv; + + hdr = (void *)skb->data; + + /* When the firmware loading completes the device sends + * out a vendor specific event indicating the result of + * the firmware loading. + */ + if (skb->len == 7 && hdr->evt == 0xff && hdr->plen == 0x05 && + skb->data[2] == 0x06) { + if (skb->data[3] != 0x00) + set_bit(STATE_FIRMWARE_FAILED, &intel->flags); + + if (test_and_clear_bit(STATE_DOWNLOADING, &intel->flags) && + test_bit(STATE_FIRMWARE_LOADED, &intel->flags)) { + smp_mb__after_atomic(); + wake_up_bit(&intel->flags, STATE_DOWNLOADING); + } + + /* When switching to the operational firmware the device + * sends a vendor specific event indicating that the bootup + * completed. + */ + } else if (skb->len == 9 && hdr->evt == 0xff && hdr->plen == 0x07 && + skb->data[2] == 0x02) { + if (test_and_clear_bit(STATE_BOOTING, &intel->flags)) { + smp_mb__after_atomic(); + wake_up_bit(&intel->flags, STATE_BOOTING); + } + } +recv: + return hci_recv_frame(hdev, skb); +} + +static const struct h4_recv_pkt intel_recv_pkts[] = { + { H4_RECV_ACL, .recv = hci_recv_frame }, + { H4_RECV_SCO, .recv = hci_recv_frame }, + { H4_RECV_EVENT, .recv = intel_recv_event }, +}; + +static int intel_recv(struct hci_uart *hu, const void *data, int count) +{ + struct intel_data *intel = hu->priv; + + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) + return -EUNATCH; + + intel->rx_skb = h4_recv_buf(hu->hdev, intel->rx_skb, data, count, + intel_recv_pkts, + ARRAY_SIZE(intel_recv_pkts)); + if (IS_ERR(intel->rx_skb)) { + int err = PTR_ERR(intel->rx_skb); + BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + intel->rx_skb = NULL; + return err; + } + + return count; +} + +static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb) +{ + struct intel_data *intel = hu->priv; + + BT_DBG("hu %p skb %p", hu, skb); + + skb_queue_tail(&intel->txq, skb); + + return 0; +} + +static struct sk_buff *intel_dequeue(struct hci_uart *hu) +{ + struct intel_data *intel = hu->priv; + struct sk_buff *skb; + + skb = skb_dequeue(&intel->txq); + if (!skb) + return skb; + + if (test_bit(STATE_BOOTLOADER, &intel->flags) && + (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT)) { + struct hci_command_hdr *cmd = (void *)skb->data; + __u16 opcode = le16_to_cpu(cmd->opcode); + + /* When the 0xfc01 command is issued to boot into + * the operational firmware, it will actually not + * send a command complete event. To keep the flow + * control working inject that event here. + */ + if (opcode == 0xfc01) + inject_cmd_complete(hu->hdev, opcode); + } + + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); + + return skb; +} + +static const struct hci_uart_proto intel_proto = { + .id = HCI_UART_INTEL, + .name = "Intel", + .init_speed = 115200, + .open = intel_open, + .close = intel_close, + .flush = intel_flush, + .setup = intel_setup, + .recv = intel_recv, + .enqueue = intel_enqueue, + .dequeue = intel_dequeue, +}; + +int __init intel_init(void) +{ + return hci_uart_register_proto(&intel_proto); +} + +int __exit intel_deinit(void) +{ + return hci_uart_unregister_proto(&intel_proto); +} diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 177dd69fdd95..051f8213697d 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -804,6 +804,9 @@ static int __init hci_uart_init(void) #ifdef CONFIG_BT_HCIUART_3WIRE h5_init(); #endif +#ifdef CONFIG_BT_HCIUART_INTEL + intel_init(); +#endif #ifdef CONFIG_BT_HCIUART_BCM bcm_init(); #endif @@ -830,6 +833,9 @@ static void __exit hci_uart_exit(void) #ifdef CONFIG_BT_HCIUART_3WIRE h5_deinit(); #endif +#ifdef CONFIG_BT_HCIUART_INTEL + intel_deinit(); +#endif #ifdef CONFIG_BT_HCIUART_BCM bcm_deinit(); #endif diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index ce9c670956f5..496587a73a9d 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -167,6 +167,11 @@ int h5_init(void); int h5_deinit(void); #endif +#ifdef CONFIG_BT_HCIUART_INTEL +int intel_init(void); +int intel_deinit(void); +#endif + #ifdef CONFIG_BT_HCIUART_BCM int bcm_init(void); int bcm_deinit(void); -- cgit v1.3-6-gb490 From a03e33da5f1f10cc93bd5de140a131dac1db97f0 Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Sun, 5 Jul 2015 09:49:27 +0000 Subject: Bluetooth: bfusb: Coding style fix reported by coccinelle Removed semicolon at the end of switch case statement Signed-off-by: Prasanna Karthik Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bfusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index fcfb72e9e0ee..a5c4d0584389 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -492,7 +492,7 @@ static int bfusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) case HCI_SCODATA_PKT: hdev->stat.sco_tx++; break; - }; + } /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); -- cgit v1.3-6-gb490 From 20a7e25f4ee173785fded331d2af4b68b1ef5921 Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Sun, 5 Jul 2015 09:56:36 +0000 Subject: Bluetooth: dtl1_cs: Fixed coding style Removed semicolon at end of switch statement,error reported by Coccinelle Signed-off-by: Prasanna Karthik Signed-off-by: Marcel Holtmann --- drivers/bluetooth/dtl1_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 09c130d73ba3..84135c54ed2e 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -406,7 +406,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) break; default: return -EILSEQ; - }; + } nsh.zero = 0; nsh.len = skb->len; -- cgit v1.3-6-gb490 From 973bb97e5aee56edddaae3d5c96877101ad509c0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Jul 2015 14:37:38 +0200 Subject: Bluetooth: btintel: Add generic function for handling hardware errors The handling of hardware error has support for providing a vendor specific callback to deal with the error. Move the Intel specific function out of the USB driver into the generic module so that it can also be utilized by the UART driver. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btintel.c | 34 ++++++++++++++++++++++++++++++++++ drivers/bluetooth/btintel.h | 5 +++++ 2 files changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 828f2f8d1568..8b160858f7e8 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -89,6 +89,40 @@ int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) } EXPORT_SYMBOL_GPL(btintel_set_bdaddr); +void btintel_hw_error(struct hci_dev *hdev, u8 code) +{ + struct sk_buff *skb; + u8 type = 0x00; + + BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code); + + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reset after hardware error failed (%ld)", + hdev->name, PTR_ERR(skb)); + return; + } + kfree_skb(skb); + + skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Retrieving Intel exception info failed (%ld)", + hdev->name, PTR_ERR(skb)); + return; + } + + if (skb->len != 13) { + BT_ERR("%s: Exception info size mismatch", hdev->name); + kfree_skb(skb); + return; + } + + BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1)); + + kfree_skb(skb); +} +EXPORT_SYMBOL_GPL(btintel_hw_error); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 4bda6ab34f60..c4680cd44011 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -73,6 +73,7 @@ struct intel_secure_send_result { int btintel_check_bdaddr(struct hci_dev *hdev); int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); +void btintel_hw_error(struct hci_dev *hdev, u8 code); #else @@ -86,4 +87,8 @@ static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdadd return -EOPNOTSUPP; } +static inline void btintel_hw_error(struct hci_dev *hdev, u8 code) +{ +} + #endif -- cgit v1.3-6-gb490 From eeb6abe97390c579d9ed9da27bd98fbf07c641ed Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Jul 2015 14:37:39 +0200 Subject: Bluetooth: btusb: Use hardware error handler from Intel module The Intel specific Bluetooth module provides now an exported function for the hardware error. Use that instead of duplicating it inside the driver. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 35 +---------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b4cf8d9c9dac..21bdb89da6eb 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2291,39 +2291,6 @@ done: return 0; } -static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code) -{ - struct sk_buff *skb; - u8 type = 0x00; - - BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code); - - skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("%s: Reset after hardware error failed (%ld)", - hdev->name, PTR_ERR(skb)); - return; - } - kfree_skb(skb); - - skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("%s: Retrieving Intel exception info failed (%ld)", - hdev->name, PTR_ERR(skb)); - return; - } - - if (skb->len != 13) { - BT_ERR("%s: Exception info size mismatch", hdev->name); - kfree_skb(skb); - return; - } - - BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1)); - - kfree_skb(skb); -} - static int btusb_shutdown_intel(struct hci_dev *hdev) { struct sk_buff *skb; @@ -2783,7 +2750,7 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_INTEL_NEW) { hdev->send = btusb_send_frame_intel; hdev->setup = btusb_setup_intel_new; - hdev->hw_error = btusb_hw_error_intel; + hdev->hw_error = btintel_hw_error; hdev->set_bdaddr = btintel_set_bdaddr; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); } -- cgit v1.3-6-gb490 From 35ab8150ee9df8c8a47a57617d7ccbd74cb45bcf Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Jul 2015 14:37:40 +0200 Subject: Bluetooth: hci_uart: Add Intel address configuration support The Intel specific Bluetooth module provides support for pubic address configuration. So make sure that it is enabled for Intel UART devices. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_intel.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index ade19aaeb5c5..06398cc0d95c 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -175,6 +175,8 @@ static int intel_setup(struct hci_uart *hu) BT_DBG("%s", hdev->name); + hu->hdev->set_bdaddr = btintel_set_bdaddr; + calltime = ktime_get(); set_bit(STATE_BOOTLOADER, &intel->flags); -- cgit v1.3-6-gb490 From 09df123d2d128c52987f11c85397cdbc9ffc89c6 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Jul 2015 14:55:36 +0200 Subject: Bluetooth: btintel: Create common Intel Secure Send function The Intel Secure Send command is used the same in USB and UART drivers and with that move a generic version into the Intel module. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btintel.c | 25 +++++++++++++++++++++++++ drivers/bluetooth/btintel.h | 9 +++++++++ drivers/bluetooth/btusb.c | 33 ++++----------------------------- drivers/bluetooth/hci_intel.c | 32 ++++---------------------------- 4 files changed, 42 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 8b160858f7e8..d3b0fb55e340 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -123,6 +123,31 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code) } EXPORT_SYMBOL_GPL(btintel_hw_error); +int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, + const void *param) +{ + while (plen > 0) { + struct sk_buff *skb; + u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; + + cmd_param[0] = fragment_type; + memcpy(cmd_param + 1, param, fragment_len); + + skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1, + cmd_param, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + + plen -= fragment_len; + param += fragment_len; + } + + return 0; +} +EXPORT_SYMBOL_GPL(btintel_secure_send); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index c4680cd44011..ec89e3cb645f 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -75,6 +75,9 @@ int btintel_check_bdaddr(struct hci_dev *hdev); int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); void btintel_hw_error(struct hci_dev *hdev, u8 code); +int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, + const void *param); + #else static inline int btintel_check_bdaddr(struct hci_dev *hdev) @@ -91,4 +94,10 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code) { } +static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, + u32 plen, const void *param) +{ + return -EOPNOTSUPP; +} + #endif diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 21bdb89da6eb..de7395fe938c 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1878,30 +1878,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) return -EILSEQ; } -static int btusb_intel_secure_send(struct hci_dev *hdev, u8 fragment_type, - u32 plen, const void *param) -{ - while (plen > 0) { - struct sk_buff *skb; - u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; - - cmd_param[0] = fragment_type; - memcpy(cmd_param + 1, param, fragment_len); - - skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1, - cmd_param, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - kfree_skb(skb); - - plen -= fragment_len; - param += fragment_len; - } - - return 0; -} - static void btusb_intel_version_info(struct hci_dev *hdev, struct intel_version *ver) { @@ -2104,7 +2080,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) /* Start the firmware download transaction with the Init fragment * represented by the 128 bytes of CSS header. */ - err = btusb_intel_secure_send(hdev, 0x00, 128, fw->data); + err = btintel_secure_send(hdev, 0x00, 128, fw->data); if (err < 0) { BT_ERR("%s: Failed to send firmware header (%d)", hdev->name, err); @@ -2114,7 +2090,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) /* Send the 256 bytes of public key information from the firmware * as the PKey fragment. */ - err = btusb_intel_secure_send(hdev, 0x03, 256, fw->data + 128); + err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128); if (err < 0) { BT_ERR("%s: Failed to send firmware public key (%d)", hdev->name, err); @@ -2124,7 +2100,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) /* Send the 256 bytes of signature information from the firmware * as the Sign fragment. */ - err = btusb_intel_secure_send(hdev, 0x02, 256, fw->data + 388); + err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388); if (err < 0) { BT_ERR("%s: Failed to send firmware signature (%d)", hdev->name, err); @@ -2148,8 +2124,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) * firmware data buffer as a single Data fragement. */ if (!(frag_len % 4)) { - err = btusb_intel_secure_send(hdev, 0x01, frag_len, - fw_ptr); + err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr); if (err < 0) { BT_ERR("%s: Failed to send firmware data (%d)", hdev->name, err); diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 06398cc0d95c..bc66a9baf532 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -111,30 +111,6 @@ static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) return hci_recv_frame(hdev, skb); } -static int intel_secure_send(struct hci_dev *hdev, u8 fragment_type, - u32 plen, const void *param) -{ - while (plen > 0) { - struct sk_buff *skb; - u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; - - cmd_param[0] = fragment_type; - memcpy(cmd_param + 1, param, fragment_len); - - skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1, - cmd_param, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - kfree_skb(skb); - - plen -= fragment_len; - param += fragment_len; - } - - return 0; -} - static void intel_version_info(struct hci_dev *hdev, struct intel_version *ver) { @@ -350,7 +326,7 @@ static int intel_setup(struct hci_uart *hu) /* Start the firmware download transaction with the Init fragment * represented by the 128 bytes of CSS header. */ - err = intel_secure_send(hdev, 0x00, 128, fw->data); + err = btintel_secure_send(hdev, 0x00, 128, fw->data); if (err < 0) { BT_ERR("%s: Failed to send firmware header (%d)", hdev->name, err); @@ -360,7 +336,7 @@ static int intel_setup(struct hci_uart *hu) /* Send the 256 bytes of public key information from the firmware * as the PKey fragment. */ - err = intel_secure_send(hdev, 0x03, 256, fw->data + 128); + err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128); if (err < 0) { BT_ERR("%s: Failed to send firmware public key (%d)", hdev->name, err); @@ -370,7 +346,7 @@ static int intel_setup(struct hci_uart *hu) /* Send the 256 bytes of signature information from the firmware * as the Sign fragment. */ - err = intel_secure_send(hdev, 0x02, 256, fw->data + 388); + err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388); if (err < 0) { BT_ERR("%s: Failed to send firmware signature (%d)", hdev->name, err); @@ -402,7 +378,7 @@ static int intel_setup(struct hci_uart *hu) /* Send each command from the firmware data buffer as * a single Data fragment. */ - err = intel_secure_send(hdev, 0x01, frag_len, fw_ptr); + err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr); if (err < 0) { BT_ERR("%s: Failed to send firmware data (%d)", hdev->name, err); -- cgit v1.3-6-gb490 From 7feb99e1308204e4d849dada3443bc410ce5026b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Jul 2015 15:02:07 +0200 Subject: Bluetooth: btintel: Create common function for Intel version info The Intel version information is shared between USB and UART drivers and with that move it into a generic function of the Intel module. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btintel.c | 21 +++++++++++++++++++++ drivers/bluetooth/btintel.h | 5 +++++ drivers/bluetooth/btusb.c | 23 +---------------------- drivers/bluetooth/hci_intel.c | 23 +---------------------- 4 files changed, 28 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index d3b0fb55e340..1ce4ac16c7fa 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -123,6 +123,27 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code) } EXPORT_SYMBOL_GPL(btintel_hw_error); +void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver) +{ + const char *variant; + + switch (ver->fw_variant) { + case 0x06: + variant = "Bootloader"; + break; + case 0x23: + variant = "Firmware"; + break; + default: + return; + } + + BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name, + variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, + ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy); +} +EXPORT_SYMBOL_GPL(btintel_version_info); + int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, const void *param) { diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index ec89e3cb645f..b278d14758d5 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -75,6 +75,7 @@ int btintel_check_bdaddr(struct hci_dev *hdev); int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); void btintel_hw_error(struct hci_dev *hdev, u8 code); +void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver); int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, const void *param); @@ -94,6 +95,10 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code) { } +static void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver) +{ +} + static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, const void *param) { diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index de7395fe938c..93339a4f25f1 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1878,27 +1878,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) return -EILSEQ; } -static void btusb_intel_version_info(struct hci_dev *hdev, - struct intel_version *ver) -{ - const char *variant; - - switch (ver->fw_variant) { - case 0x06: - variant = "Bootloader"; - break; - case 0x23: - variant = "Firmware"; - break; - default: - return; - } - - BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name, - variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, - ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy); -} - static int btusb_setup_intel_new(struct hci_dev *hdev) { static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01, @@ -1960,7 +1939,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) return -EINVAL; } - btusb_intel_version_info(hdev, ver); + btintel_version_info(hdev, ver); /* The firmware variant determines if the device is in bootloader * mode or is running operational firmware. The value 0x06 identifies diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index bc66a9baf532..21dfa89751df 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -111,27 +111,6 @@ static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) return hci_recv_frame(hdev, skb); } -static void intel_version_info(struct hci_dev *hdev, - struct intel_version *ver) -{ - const char *variant; - - switch (ver->fw_variant) { - case 0x06: - variant = "Bootloader"; - break; - case 0x23: - variant = "Firmware"; - break; - default: - return; - } - - BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name, - variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, - ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy); -} - static int intel_setup(struct hci_uart *hu) { static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01, @@ -205,7 +184,7 @@ static int intel_setup(struct hci_uart *hu) return -EINVAL; } - intel_version_info(hdev, ver); + btintel_version_info(hdev, ver); /* The firmware variant determines if the device is in bootloader * mode or is running operational firmware. The value 0x06 identifies -- cgit v1.3-6-gb490 From f104f06c1b0c93a7c087609e6ab0005e359afab9 Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Mon, 6 Jul 2015 05:40:16 +0000 Subject: Bluetooth: bt3c_cs: Fix coding style Remove semicolon in switch statement, reported by coccinelle Signed-off-by: Prasanna Karthik Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bt3c_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 7aab65427d38..a00bb82eb7c6 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -427,7 +427,7 @@ static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) case HCI_SCODATA_PKT: hdev->stat.sco_tx++; break; - }; + } /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); -- cgit v1.3-6-gb490 From fc586c41117117baf22d1088dad3a771e51e35f7 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 23 Jun 2015 22:52:52 +0800 Subject: net: ieee802154: Remove redundant spi driver bus initialization In ancient times it was necessary to manually initialize the bus field of an spi_driver to spi_bus_type. These days this is done in spi_register_driver(), so we can drop the manual assignment. Signed-off-by: Antonio Borneo Acked-by: Varka Bhadram Acked-by: Alan Ott Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 1 - drivers/net/ieee802154/mrf24j40.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index b6fc29579667..613dae559925 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -1151,7 +1151,6 @@ MODULE_DEVICE_TABLE(of, cc2520_of_ids); static struct spi_driver cc2520_driver = { .driver = { .name = "cc2520", - .bus = &spi_bus_type, .owner = THIS_MODULE, .of_match_table = of_match_ptr(cc2520_of_ids), }, diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index 2549760e039f..997724b8e434 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -812,7 +812,6 @@ MODULE_DEVICE_TABLE(spi, mrf24j40_ids); static struct spi_driver mrf24j40_driver = { .driver = { .name = "mrf24j40", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .id_table = mrf24j40_ids, -- cgit v1.3-6-gb490 From dff22d2054b5dbb1889f20c03959dd0c494fab8c Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Thu, 9 Jul 2015 11:59:16 +0100 Subject: PCI: Call pci_read_bridge_bases() from core instead of arch code When we scan a PCI bus, we read PCI-PCI bridge window registers with pci_read_bridge_bases() so we can validate the resource hierarchy. Most architectures call pci_read_bridge_bases() from pcibios_fixup_bus(), but PCI-PCI bridges are not arch-specific, so this doesn't need to be in arch-specific code. Call pci_read_bridge_bases() directly from the PCI core instead of from arch code. For alpha and mips, we now call pci_read_bridge_bases() always; previously we only called it if PCI_PROBE_ONLY was set. [bhelgaas: changelog] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas CC: Ralf Baechle CC: James E.J. Bottomley CC: Michael Ellerman CC: Bjorn Helgaas CC: Richard Henderson CC: Benjamin Herrenschmidt CC: David Howells CC: Russell King CC: Tony Luck CC: David S. Miller CC: Ingo Molnar CC: Guenter Roeck CC: Michal Simek CC: Chris Zankel --- arch/alpha/kernel/pci.c | 7 +------ arch/frv/mb93090-mb00/pci-vdk.c | 2 -- arch/ia64/pci/pci.c | 5 ++--- arch/microblaze/pci/pci-common.c | 9 +-------- arch/mips/pci/pci.c | 6 ------ arch/mn10300/unit-asb2305/pci.c | 1 - arch/powerpc/kernel/pci-common.c | 8 +------- arch/x86/pci/common.c | 1 - arch/xtensa/kernel/pci.c | 4 ---- drivers/parisc/dino.c | 3 --- drivers/parisc/lba_pci.c | 1 - drivers/pci/probe.c | 6 ++++++ 12 files changed, 11 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 82f738e5d54c..cded02c890aa 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -242,12 +242,7 @@ pci_restore_srm_config(void) void pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_dev *dev = bus->self; - - if (pci_has_flag(PCI_PROBE_ONLY) && dev && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - pci_read_bridge_bases(bus); - } + struct pci_dev *dev; list_for_each_entry(dev, &bus->devices, bus_list) { pdev_save_srm_config(dev); diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c index f211839e2cae..f9c86c475bbd 100644 --- a/arch/frv/mb93090-mb00/pci-vdk.c +++ b/arch/frv/mb93090-mb00/pci-vdk.c @@ -294,8 +294,6 @@ void pcibios_fixup_bus(struct pci_bus *bus) printk("### PCIBIOS_FIXUP_BUS(%d)\n",bus->number); #endif - pci_read_bridge_bases(bus); - if (bus->number == 0) { struct pci_dev *dev; list_for_each_entry(dev, &bus->devices, bus_list) { diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 7cc3be9fa7c6..d89b6013c941 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -533,10 +533,9 @@ void pcibios_fixup_bus(struct pci_bus *b) { struct pci_dev *dev; - if (b->self) { - pci_read_bridge_bases(b); + if (b->self) pcibios_fixup_bridge_resources(b->self); - } + list_for_each_entry(dev, &b->devices, bus_list) pcibios_fixup_device_resources(dev); platform_pci_fixup_bus(b); diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index ae838ed5fcf2..6b8b75266801 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -863,14 +863,7 @@ void pcibios_setup_bus_devices(struct pci_bus *bus) void pcibios_fixup_bus(struct pci_bus *bus) { - /* When called from the generic PCI probe, read PCI<->PCI bridge - * bases. This is -not- called when generating the PCI tree from - * the OF device-tree. - */ - if (bus->self != NULL) - pci_read_bridge_bases(bus); - - /* Now fixup the bus bus */ + /* Fixup the bus */ pcibios_setup_bus_self(bus); /* Now fixup devices on that bus */ diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index b8a0bf5766f2..c6996cf67a5c 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -311,12 +311,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) void pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_dev *dev = bus->self; - - if (pci_has_flag(PCI_PROBE_ONLY) && dev && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - pci_read_bridge_bases(bus); - } } EXPORT_SYMBOL(PCIBIOS_MIN_IO); diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c index 3dfe2d31c67b..deaa893efba5 100644 --- a/arch/mn10300/unit-asb2305/pci.c +++ b/arch/mn10300/unit-asb2305/pci.c @@ -324,7 +324,6 @@ void pcibios_fixup_bus(struct pci_bus *bus) struct pci_dev *dev; if (bus->self) { - pci_read_bridge_bases(bus); pcibios_fixup_bridge_resources(bus->self); } diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index b9de34d44fcb..02c1d5dcee4d 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1044,13 +1044,7 @@ void pcibios_set_master(struct pci_dev *dev) void pcibios_fixup_bus(struct pci_bus *bus) { - /* When called from the generic PCI probe, read PCI<->PCI bridge - * bases. This is -not- called when generating the PCI tree from - * the OF device-tree. - */ - pci_read_bridge_bases(bus); - - /* Now fixup the bus bus */ + /* Fixup the bus */ pcibios_setup_bus_self(bus); /* Now fixup devices on that bus */ diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 8fd6f44aee83..3bff24438b00 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -166,7 +166,6 @@ void pcibios_fixup_bus(struct pci_bus *b) { struct pci_dev *dev; - pci_read_bridge_bases(b); list_for_each_entry(dev, &b->devices, bus_list) pcibios_fixup_device_resources(dev); } diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c index b848cc3dc913..d27b4dcf221f 100644 --- a/arch/xtensa/kernel/pci.c +++ b/arch/xtensa/kernel/pci.c @@ -210,10 +210,6 @@ subsys_initcall(pcibios_init); void pcibios_fixup_bus(struct pci_bus *bus) { - if (bus->parent) { - /* This is a subordinate bridge */ - pci_read_bridge_bases(bus); - } } void pcibios_set_master(struct pci_dev *dev) diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index a0580afe1713..baec33c4e698 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -560,9 +560,6 @@ dino_fixup_bus(struct pci_bus *bus) } else if (bus->parent) { int i; - pci_read_bridge_bases(bus); - - for(i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { if((bus->self->resource[i].flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index dceb9ddfd99a..901e1a3fa4e2 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -693,7 +693,6 @@ lba_fixup_bus(struct pci_bus *bus) if (bus->parent) { int i; /* PCI-PCI Bridge */ - pci_read_bridge_bases(bus); for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) pci_claim_bridge_resource(bus->self, i); } else { diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cefd636681b6..b996aefc1092 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -826,6 +826,9 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) child->bridge_ctl = bctl; } + /* Read and initialize bridge resources */ + pci_read_bridge_bases(child); + cmax = pci_scan_child_bus(child); if (cmax > subordinate) dev_warn(&dev->dev, "bridge has subordinate %02x but max busn %02x\n", @@ -886,6 +889,9 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) if (!is_cardbus) { child->bridge_ctl = bctl; + + /* Read and initialize bridge resources */ + pci_read_bridge_bases(child); max = pci_scan_child_bus(child); } else { /* -- cgit v1.3-6-gb490 From 70bef01c0f1c9a55b54b625be3f82ff7ee1e8c05 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 26 May 2015 13:39:43 +0100 Subject: clocksource: sti: Provide support for the ST LPC Clocksource IP This IP is shared with Watchdog and RTC functionality. All 3 of these devices are mutually exclusive from one another i.e. Only 1 IP can be used at any given time. We use the device-driver model combined with a DT 'mode' property to enforce this. The ST LPC Clocksource IP can be used as the system (tick) timer. Acked-by: Daniel Lezcano Signed-off-by: Lee Jones --- drivers/clocksource/Kconfig | 8 +++ drivers/clocksource/Makefile | 1 + drivers/clocksource/clksrc_st_lpc.c | 123 ++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 drivers/clocksource/clksrc_st_lpc.c (limited to 'drivers') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4e57730e0be4..ae3ec9da0d15 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -293,4 +293,12 @@ config CLKSRC_IMX_GPT depends on ARM && CLKDEV_LOOKUP select CLKSRC_MMIO +config CLKSRC_ST_LPC + bool + depends on ARCH_STI + select CLKSRC_OF if OF + help + Enable this option to use the Low Power controller timer + as clocksource. + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index f228354961ca..1c2c9d2cd859 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -60,3 +60,4 @@ obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o obj-$(CONFIG_H8300) += h8300_timer8.o obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o obj-$(CONFIG_H8300_TPU) += h8300_tpu.o +obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o diff --git a/drivers/clocksource/clksrc_st_lpc.c b/drivers/clocksource/clksrc_st_lpc.c new file mode 100644 index 000000000000..f38cf33281a2 --- /dev/null +++ b/drivers/clocksource/clksrc_st_lpc.c @@ -0,0 +1,123 @@ +/* + * Clocksource using the Low Power Timer found in the Low Power Controller (LPC) + * + * Copyright (C) 2015 STMicroelectronics – All Rights Reserved + * + * Author(s): Francesco Virlinzi + * Ajit Pal Singh + * + * 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 + +/* Low Power Timer */ +#define LPC_LPT_LSB_OFF 0x400 +#define LPC_LPT_MSB_OFF 0x404 +#define LPC_LPT_START_OFF 0x408 + +static struct st_clksrc_ddata { + struct clk *clk; + void __iomem *base; +} ddata; + +static void __init st_clksrc_reset(void) +{ + writel_relaxed(0, ddata.base + LPC_LPT_START_OFF); + writel_relaxed(0, ddata.base + LPC_LPT_MSB_OFF); + writel_relaxed(0, ddata.base + LPC_LPT_LSB_OFF); + writel_relaxed(1, ddata.base + LPC_LPT_START_OFF); +} + +static int __init st_clksrc_init(void) +{ + unsigned long rate; + int ret; + + st_clksrc_reset(); + + rate = clk_get_rate(ddata.clk); + + ret = clocksource_mmio_init(ddata.base + LPC_LPT_LSB_OFF, + "clksrc-st-lpc", rate, 300, 32, + clocksource_mmio_readl_up); + if (ret) { + pr_err("clksrc-st-lpc: Failed to register clocksource\n"); + return ret; + } + + return 0; +} + +static int __init st_clksrc_setup_clk(struct device_node *np) +{ + struct clk *clk; + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("clksrc-st-lpc: Failed to get LPC clock\n"); + return PTR_ERR(clk); + } + + if (clk_prepare_enable(clk)) { + pr_err("clksrc-st-lpc: Failed to enable LPC clock\n"); + return -EINVAL; + } + + if (!clk_get_rate(clk)) { + pr_err("clksrc-st-lpc: Failed to get LPC clock rate\n"); + clk_disable_unprepare(clk); + return -EINVAL; + } + + ddata.clk = clk; + + return 0; +} + +static void __init st_clksrc_of_register(struct device_node *np) +{ + int ret; + uint32_t mode; + + ret = of_property_read_u32(np, "st,lpc-mode", &mode); + if (ret) { + pr_err("clksrc-st-lpc: An LPC mode must be provided\n"); + return; + } + + /* LPC can either run as a Clocksource or in RTC or WDT mode */ + if (mode != ST_LPC_MODE_CLKSRC) + return; + + ddata.base = of_iomap(np, 0); + if (!ddata.base) { + pr_err("clksrc-st-lpc: Unable to map iomem\n"); + return; + } + + if (st_clksrc_setup_clk(np)) { + iounmap(ddata.base); + return; + } + + if (st_clksrc_init()) { + clk_disable_unprepare(ddata.clk); + clk_put(ddata.clk); + iounmap(ddata.base); + return; + } + + pr_info("clksrc-st-lpc: clocksource initialised - running @ %luHz\n", + clk_get_rate(ddata.clk)); +} +CLOCKSOURCE_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register); -- cgit v1.3-6-gb490 From ff45d8dd84dbb6e674e3757a07ef9471568c2e94 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 May 2015 13:58:11 +0100 Subject: clocksource: sti: Provide 'use timer as sched clock' capability Acked-by: Daniel Lezcano Signed-off-by: Lee Jones --- drivers/clocksource/clksrc_st_lpc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/clocksource/clksrc_st_lpc.c b/drivers/clocksource/clksrc_st_lpc.c index f38cf33281a2..65ec4674416d 100644 --- a/drivers/clocksource/clksrc_st_lpc.c +++ b/drivers/clocksource/clksrc_st_lpc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,11 @@ static void __init st_clksrc_reset(void) writel_relaxed(1, ddata.base + LPC_LPT_START_OFF); } +static u64 notrace st_clksrc_sched_clock_read(void) +{ + return (u64)readl_relaxed(ddata.base + LPC_LPT_LSB_OFF); +} + static int __init st_clksrc_init(void) { unsigned long rate; @@ -47,6 +53,8 @@ static int __init st_clksrc_init(void) rate = clk_get_rate(ddata.clk); + sched_clock_register(st_clksrc_sched_clock_read, 32, rate); + ret = clocksource_mmio_init(ddata.base + LPC_LPT_LSB_OFF, "clksrc-st-lpc", rate, 300, 32, clocksource_mmio_readl_up); -- cgit v1.3-6-gb490 From 742e40978ff79cc92ba982a27a55b957226f9dbe Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 May 2015 13:58:15 +0100 Subject: rtc: st: Update IP layout information to include Clocksource Initial submission adding support for this IP only included Watchdog and the Real-Time Clock. Now the third (and final) device is enabled this trivial patch is required to update the comment in the RTC driver to encompass Clocksource. Acked-by: Alexandre Belloni Signed-off-by: Lee Jones --- drivers/rtc/rtc-st-lpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-st-lpc.c b/drivers/rtc/rtc-st-lpc.c index 3f9d0acb81c7..74c0a336ceea 100644 --- a/drivers/rtc/rtc-st-lpc.c +++ b/drivers/rtc/rtc-st-lpc.c @@ -208,7 +208,7 @@ static int st_rtc_probe(struct platform_device *pdev) return -EINVAL; } - /* LPC can either run in RTC or WDT mode */ + /* LPC can either run as a Clocksource or in RTC or WDT mode */ if (mode != ST_LPC_MODE_RTC) return -ENODEV; -- cgit v1.3-6-gb490 From c176becd81843426eb8ab3b03aeeb19e387345fe Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 5 Jun 2015 16:59:42 +0300 Subject: iio: fix drivers that consider 0 as a valid IRQ in client->irq Since patch "i2c / ACPI: Use 0 to indicate that device does not have interrupt assigned" [1], 0 is not a valid i2c client irq anymore, so change all driver's checks accordingly. The same issue occurs when the device is instantiated via device tree with no IRQ, or from the i2c sysfs interface, even before the patch above. [1] http://lkml.kernel.org/g/<1430908148-201129-3-git-send-email-mika.westerberg@linux.intel.com> Signed-off-by: Octavian Purdila Reviewed-by: Mika Westerberg Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 2 +- drivers/iio/accel/kxcjk-1013.c | 2 +- drivers/iio/accel/mma9553.c | 2 +- drivers/iio/imu/kmx61.c | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 47c6013ab376..21b665fc0739 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -1670,7 +1670,7 @@ static int bmc150_accel_probe(struct i2c_client *client, if (client->irq < 0) client->irq = bmc150_accel_gpio_probe(client, data); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq( &client->dev, client->irq, bmc150_accel_irq_handler, diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 8128579bff79..3292bc0c1d0e 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1240,7 +1240,7 @@ static int kxcjk1013_probe(struct i2c_client *client, if (client->irq < 0) client->irq = kxcjk1013_gpio_probe(client, data); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, kxcjk1013_data_rdy_trig_poll, kxcjk1013_event_handler, diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index a605280637e9..771858cb67a1 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1149,7 +1149,7 @@ static int mma9553_probe(struct i2c_client *client, if (client->irq < 0) client->irq = mma9553_gpio_probe(client); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, mma9553_irq_handler, mma9553_event_handler, diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 462a010628cd..82cdf5090fa7 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1363,7 +1363,7 @@ static int kmx61_probe(struct i2c_client *client, if (client->irq < 0) client->irq = kmx61_gpio_probe(client, data); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, kmx61_data_rdy_trig_poll, kmx61_event_handler, @@ -1445,10 +1445,10 @@ err_iio_unregister_mag: err_iio_unregister_acc: iio_device_unregister(data->acc_indio_dev); err_buffer_cleanup_mag: - if (client->irq >= 0) + if (client->irq > 0) iio_triggered_buffer_cleanup(data->mag_indio_dev); err_buffer_cleanup_acc: - if (client->irq >= 0) + if (client->irq > 0) iio_triggered_buffer_cleanup(data->acc_indio_dev); err_trigger_unregister_motion: iio_trigger_unregister(data->motion_trig); @@ -1472,7 +1472,7 @@ static int kmx61_remove(struct i2c_client *client) iio_device_unregister(data->acc_indio_dev); iio_device_unregister(data->mag_indio_dev); - if (client->irq >= 0) { + if (client->irq > 0) { iio_triggered_buffer_cleanup(data->acc_indio_dev); iio_triggered_buffer_cleanup(data->mag_indio_dev); iio_trigger_unregister(data->acc_dready_trig); -- cgit v1.3-6-gb490 From bc27381edbeb654d819b7e1464091c456a0d3e64 Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:41 +0200 Subject: iio: st-sensors: add configuration for WhoAmI address This patch permits to configure the WhoAmI register address because some device could have not a standard address for this register. Signed-off-by: Giuseppe Barba Reviewed-by: Denis Ciocca Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- drivers/iio/accel/st_accel_core.c | 5 +++ drivers/iio/common/st_sensors/st_sensors_core.c | 49 ++++++++++++------------- drivers/iio/gyro/st_gyro_core.c | 3 ++ drivers/iio/magnetometer/st_magn_core.c | 3 ++ drivers/iio/pressure/st_pressure_core.c | 3 ++ include/linux/iio/common/st_sensors.h | 2 + 6 files changed, 39 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 4002e6410444..12b42f6e70ab 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -226,6 +226,7 @@ static const struct iio_chan_spec st_accel_16bit_channels[] = { static const struct st_sensor_settings st_accel_sensors_settings[] = { { .wai = ST_ACCEL_1_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS3DH_ACCEL_DEV_NAME, [1] = LSM303DLHC_ACCEL_DEV_NAME, @@ -297,6 +298,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_2_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS331DLH_ACCEL_DEV_NAME, [1] = LSM303DL_ACCEL_DEV_NAME, @@ -359,6 +361,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_3_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM330_ACCEL_DEV_NAME, }, @@ -437,6 +440,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_4_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS3LV02DL_ACCEL_DEV_NAME, }, @@ -494,6 +498,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_5_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS331DL_ACCEL_DEV_NAME, }, diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 8086cbcff87d..d44bf1680859 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -479,46 +479,43 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev, int num_sensors_list, const struct st_sensor_settings *sensor_settings) { - u8 wai; int i, n, err; + u8 wai; struct st_sensor_data *sdata = iio_priv(indio_dev); - err = sdata->tf->read_byte(&sdata->tb, sdata->dev, - ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai); - if (err < 0) { - dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n"); - goto read_wai_error; - } - for (i = 0; i < num_sensors_list; i++) { - if (sensor_settings[i].wai == wai) + for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) { + if (strcmp(indio_dev->name, + sensor_settings[i].sensors_supported[n]) == 0) { + break; + } + } + if (n < ST_SENSORS_MAX_4WAI) break; } - if (i == num_sensors_list) - goto device_not_supported; + if (i == num_sensors_list) { + dev_err(&indio_dev->dev, "device name %s not recognized.\n", + indio_dev->name); + return -ENODEV; + } - for (n = 0; n < ARRAY_SIZE(sensor_settings[i].sensors_supported); n++) { - if (strcmp(indio_dev->name, - &sensor_settings[i].sensors_supported[n][0]) == 0) - break; + err = sdata->tf->read_byte(&sdata->tb, sdata->dev, + sensor_settings[i].wai_addr, &wai); + if (err < 0) { + dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n"); + return err; } - if (n == ARRAY_SIZE(sensor_settings[i].sensors_supported)) { - dev_err(&indio_dev->dev, "device name \"%s\" and WhoAmI (0x%02x) mismatch", - indio_dev->name, wai); - goto sensor_name_mismatch; + + if (sensor_settings[i].wai != wai) { + dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n", + indio_dev->name, wai); + return -EINVAL; } sdata->sensor_settings = (struct st_sensor_settings *)&sensor_settings[i]; return i; - -device_not_supported: - dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai); -sensor_name_mismatch: - err = -ENODEV; -read_wai_error: - return err; } EXPORT_SYMBOL(st_sensors_check_device_support); diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index ffe96642b6d0..4b993a5bc9a1 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -131,6 +131,7 @@ static const struct iio_chan_spec st_gyro_16bit_channels[] = { static const struct st_sensor_settings st_gyro_sensors_settings[] = { { .wai = ST_GYRO_1_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = L3G4200D_GYRO_DEV_NAME, [1] = LSM330DL_GYRO_DEV_NAME, @@ -190,6 +191,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { }, { .wai = ST_GYRO_2_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = L3GD20_GYRO_DEV_NAME, [1] = LSM330D_GYRO_DEV_NAME, @@ -252,6 +254,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { }, { .wai = ST_GYRO_3_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = L3GD20_GYRO_DEV_NAME, }, diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index b4bcfb790f49..8d7d3a172874 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -192,6 +192,7 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = { static const struct st_sensor_settings st_magn_sensors_settings[] = { { .wai = 0, /* This sensor has no valid WhoAmI report 0 */ + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM303DLH_MAGN_DEV_NAME, }, @@ -268,6 +269,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { }, { .wai = ST_MAGN_1_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM303DLHC_MAGN_DEV_NAME, [1] = LSM303DLM_MAGN_DEV_NAME, @@ -346,6 +348,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { }, { .wai = ST_MAGN_2_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS3MDL_MAGN_DEV_NAME, }, diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index e881fa6291e9..eb41d2b92c24 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -178,6 +178,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { static const struct st_sensor_settings st_press_sensors_settings[] = { { .wai = ST_PRESS_LPS331AP_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LPS331AP_PRESS_DEV_NAME, }, @@ -225,6 +226,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { }, { .wai = ST_PRESS_LPS001WP_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LPS001WP_PRESS_DEV_NAME, }, @@ -260,6 +262,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { }, { .wai = ST_PRESS_LPS25H_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LPS25H_PRESS_DEV_NAME, }, diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h index 2c476acb87d9..3c17cd7fdf06 100644 --- a/include/linux/iio/common/st_sensors.h +++ b/include/linux/iio/common/st_sensors.h @@ -166,6 +166,7 @@ struct st_sensor_transfer_function { /** * struct st_sensor_settings - ST specific sensor settings * @wai: Contents of WhoAmI register. + * @wai_addr: The address of WhoAmI register. * @sensors_supported: List of supported sensors by struct itself. * @ch: IIO channels for the sensor. * @odr: Output data rate register and ODR list available. @@ -179,6 +180,7 @@ struct st_sensor_transfer_function { */ struct st_sensor_settings { u8 wai; + u8 wai_addr; char sensors_supported[ST_SENSORS_MAX_4WAI][ST_SENSORS_MAX_NAME]; struct iio_chan_spec *ch; int num_ch; -- cgit v1.3-6-gb490 From bb602f8c61e289389e7c2af1b577303a841f6d34 Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:42 +0200 Subject: iio: st-sensors: add support for single full scale device Some sensors could have only one full scale value. This means that the sensor hasn't a full scale register. This commit add a check on the configured full scale address to support such kind of sensors. Signed-off-by: Giuseppe Barba Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index d44bf1680859..2e7fdb502645 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -126,6 +126,9 @@ static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs) int err, i = 0; struct st_sensor_data *sdata = iio_priv(indio_dev); + if (sdata->sensor_settings->fs.addr == 0) + return 0; + err = st_sensors_match_fs(sdata->sensor_settings, fs, &i); if (err < 0) goto st_accel_set_fullscale_error; -- cgit v1.3-6-gb490 From 74f5683f35fe6feae33b96815c1d40f13468d614 Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:43 +0200 Subject: iio: st_magn: Add irq trigger handling Add irq trigger handling for magnetometer also Signed-off-by: Giuseppe Barba Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/st_magn.h | 2 ++ drivers/iio/magnetometer/st_magn_buffer.c | 7 +++++++ drivers/iio/magnetometer/st_magn_core.c | 13 ++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index 287691ca56c1..604410236d99 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -25,6 +25,8 @@ void st_magn_common_remove(struct iio_dev *indio_dev); #ifdef CONFIG_IIO_BUFFER int st_magn_allocate_ring(struct iio_dev *indio_dev); void st_magn_deallocate_ring(struct iio_dev *indio_dev); +int st_magn_trig_set_state(struct iio_trigger *trig, bool state); +#define ST_MAGN_TRIGGER_SET_STATE (&st_magn_trig_set_state) #else /* CONFIG_IIO_BUFFER */ static inline int st_magn_probe_trigger(struct iio_dev *indio_dev, int irq) { diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c index bf427dc0d226..ecd3bd0a9769 100644 --- a/drivers/iio/magnetometer/st_magn_buffer.c +++ b/drivers/iio/magnetometer/st_magn_buffer.c @@ -23,6 +23,13 @@ #include #include "st_magn.h" +int st_magn_trig_set_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + + return st_sensors_set_dataready_irq(indio_dev, state); +} + static int st_magn_buffer_preenable(struct iio_dev *indio_dev) { return st_sensors_set_enable(indio_dev, true); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 8d7d3a172874..4c0cef865517 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -480,6 +480,16 @@ static const struct iio_info magn_info = { .write_raw = &st_magn_write_raw, }; +#ifdef CONFIG_IIO_TRIGGER +static const struct iio_trigger_ops st_magn_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = ST_MAGN_TRIGGER_SET_STATE, +}; +#define ST_MAGN_TRIGGER_OPS (&st_magn_trigger_ops) +#else +#define ST_MAGN_TRIGGER_OPS NULL +#endif + int st_magn_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *mdata = iio_priv(indio_dev); @@ -516,7 +526,8 @@ int st_magn_common_probe(struct iio_dev *indio_dev) return err; if (irq > 0) { - err = st_sensors_allocate_trigger(indio_dev, NULL); + err = st_sensors_allocate_trigger(indio_dev, + ST_MAGN_TRIGGER_OPS); if (err < 0) goto st_magn_probe_trigger_error; } -- cgit v1.3-6-gb490 From ddc05fa286068a2d0cf87a47739b155806d46670 Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:44 +0200 Subject: iio: st-accel: add support for lsm303agr accelerometer This adds support for the lsm303agr accelerometer. Signed-off-by: Giuseppe Barba Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/st-sensors.txt | 1 + drivers/iio/accel/st_accel.h | 1 + drivers/iio/accel/st_accel_core.c | 1 + drivers/iio/accel/st_accel_i2c.c | 5 +++++ drivers/iio/accel/st_accel_spi.c | 1 + 5 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt index 8a6be3bdf267..d80bdaa75754 100644 --- a/Documentation/devicetree/bindings/iio/st-sensors.txt +++ b/Documentation/devicetree/bindings/iio/st-sensors.txt @@ -35,6 +35,7 @@ Accelerometers: - st,lsm303dl-accel - st,lsm303dlm-accel - st,lsm330-accel +- st,lsm303agr-accel Gyroscopes: - st,l3g4200d-gyro diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index aa1001931d0c..468f21fa2950 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -26,6 +26,7 @@ #define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel" #define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel" #define LSM330_ACCEL_DEV_NAME "lsm330_accel" +#define LSM303AGR_ACCEL_DEV_NAME "lsm303agr_accel" /** * struct st_sensors_platform_data - default accel platform data diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 12b42f6e70ab..ff30f8806880 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -233,6 +233,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { [2] = LSM330D_ACCEL_DEV_NAME, [3] = LSM330DL_ACCEL_DEV_NAME, [4] = LSM330DLC_ACCEL_DEV_NAME, + [5] = LSM303AGR_ACCEL_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_accel_12bit_channels, .odr = { diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index a2f1c20319eb..8b9cc84fd44f 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -68,6 +68,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,lsm330-accel", .data = LSM330_ACCEL_DEV_NAME, }, + { + .compatible = "st,lsm303agr-accel", + .data = LSM303AGR_ACCEL_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -116,6 +120,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LSM303DL_ACCEL_DEV_NAME }, { LSM303DLM_ACCEL_DEV_NAME }, { LSM330_ACCEL_DEV_NAME }, + { LSM303AGR_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 12ec29389e4b..54b61a3961c3 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -57,6 +57,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LSM303DL_ACCEL_DEV_NAME }, { LSM303DLM_ACCEL_DEV_NAME }, { LSM330_ACCEL_DEV_NAME }, + { LSM303AGR_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_accel_id_table); -- cgit v1.3-6-gb490 From 1e9676a8474b657b6a793f0abff2205783a1ce6f Mon Sep 17 00:00:00 2001 From: Giuseppe Barba Date: Tue, 21 Jul 2015 10:35:45 +0200 Subject: iio: st-magn: add support for lsm303agr magnetometer This adds support for the lsm303agr magnetometer. Signed-off-by: Giuseppe Barba Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/st-sensors.txt | 1 + drivers/iio/magnetometer/st_magn.h | 1 + drivers/iio/magnetometer/st_magn_core.c | 82 ++++++++++++++++++++++ drivers/iio/magnetometer/st_magn_i2c.c | 5 ++ drivers/iio/magnetometer/st_magn_spi.c | 1 + 5 files changed, 90 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt index d80bdaa75754..d3ccdb190c53 100644 --- a/Documentation/devicetree/bindings/iio/st-sensors.txt +++ b/Documentation/devicetree/bindings/iio/st-sensors.txt @@ -47,6 +47,7 @@ Gyroscopes: - st,lsm330-gyro Magnetometers: +- st,lsm303agr-magn - st,lsm303dlh-magn - st,lsm303dlhc-magn - st,lsm303dlm-magn diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index 604410236d99..06a4d9c35581 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -18,6 +18,7 @@ #define LSM303DLHC_MAGN_DEV_NAME "lsm303dlhc_magn" #define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn" #define LIS3MDL_MAGN_DEV_NAME "lis3mdl" +#define LSM303AGR_MAGN_DEV_NAME "lsm303agr_magn" int st_magn_common_probe(struct iio_dev *indio_dev); void st_magn_common_remove(struct iio_dev *indio_dev); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 4c0cef865517..f8dc4b85d70c 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -43,6 +43,7 @@ #define ST_MAGN_FS_AVL_8000MG 8000 #define ST_MAGN_FS_AVL_8100MG 8100 #define ST_MAGN_FS_AVL_12000MG 12000 +#define ST_MAGN_FS_AVL_15000MG 15000 #define ST_MAGN_FS_AVL_16000MG 16000 /* CUSTOM VALUES FOR SENSOR 0 */ @@ -157,6 +158,29 @@ #define ST_MAGN_2_OUT_Y_L_ADDR 0x2a #define ST_MAGN_2_OUT_Z_L_ADDR 0x2c +/* CUSTOM VALUES FOR SENSOR 3 */ +#define ST_MAGN_3_WAI_ADDR 0x4f +#define ST_MAGN_3_WAI_EXP 0x40 +#define ST_MAGN_3_ODR_ADDR 0x60 +#define ST_MAGN_3_ODR_MASK 0x0c +#define ST_MAGN_3_ODR_AVL_10HZ_VAL 0x00 +#define ST_MAGN_3_ODR_AVL_20HZ_VAL 0x01 +#define ST_MAGN_3_ODR_AVL_50HZ_VAL 0x02 +#define ST_MAGN_3_ODR_AVL_100HZ_VAL 0x03 +#define ST_MAGN_3_PW_ADDR 0x60 +#define ST_MAGN_3_PW_MASK 0x03 +#define ST_MAGN_3_PW_ON 0x00 +#define ST_MAGN_3_PW_OFF 0x03 +#define ST_MAGN_3_BDU_ADDR 0x62 +#define ST_MAGN_3_BDU_MASK 0x10 +#define ST_MAGN_3_DRDY_IRQ_ADDR 0x62 +#define ST_MAGN_3_DRDY_INT_MASK 0x01 +#define ST_MAGN_3_FS_AVL_15000_GAIN 1500 +#define ST_MAGN_3_MULTIREAD_BIT false +#define ST_MAGN_3_OUT_X_L_ADDR 0x68 +#define ST_MAGN_3_OUT_Y_L_ADDR 0x6a +#define ST_MAGN_3_OUT_Z_L_ADDR 0x6c + static const struct iio_chan_spec st_magn_16bit_channels[] = { ST_SENSORS_LSM_CHANNELS(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), @@ -189,6 +213,22 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(3) }; +static const struct iio_chan_spec st_magn_3_16bit_channels[] = { + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_X_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_Y_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_Z_L_ADDR), + IIO_CHAN_SOFT_TIMESTAMP(3) +}; + static const struct st_sensor_settings st_magn_sensors_settings[] = { { .wai = 0, /* This sensor has no valid WhoAmI report 0 */ @@ -402,6 +442,48 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { .multi_read_bit = ST_MAGN_2_MULTIREAD_BIT, .bootime = 2, }, + { + .wai = ST_MAGN_3_WAI_EXP, + .wai_addr = ST_MAGN_3_WAI_ADDR, + .sensors_supported = { + [0] = LSM303AGR_MAGN_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_magn_3_16bit_channels, + .odr = { + .addr = ST_MAGN_3_ODR_ADDR, + .mask = ST_MAGN_3_ODR_MASK, + .odr_avl = { + { 10, ST_MAGN_3_ODR_AVL_10HZ_VAL, }, + { 20, ST_MAGN_3_ODR_AVL_20HZ_VAL, }, + { 50, ST_MAGN_3_ODR_AVL_50HZ_VAL, }, + { 100, ST_MAGN_3_ODR_AVL_100HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_MAGN_3_PW_ADDR, + .mask = ST_MAGN_3_PW_MASK, + .value_on = ST_MAGN_3_PW_ON, + .value_off = ST_MAGN_3_PW_OFF, + }, + .fs = { + .fs_avl = { + [0] = { + .num = ST_MAGN_FS_AVL_15000MG, + .gain = ST_MAGN_3_FS_AVL_15000_GAIN, + }, + }, + }, + .bdu = { + .addr = ST_MAGN_3_BDU_ADDR, + .mask = ST_MAGN_3_BDU_MASK, + }, + .drdy_irq = { + .addr = ST_MAGN_3_DRDY_IRQ_ADDR, + .mask_int1 = ST_MAGN_3_DRDY_INT_MASK, + }, + .multi_read_bit = ST_MAGN_3_MULTIREAD_BIT, + .bootime = 2, + }, }; static int st_magn_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 28aa80731cea..8aa37af306ed 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -36,6 +36,10 @@ static const struct of_device_id st_magn_of_match[] = { .compatible = "st,lis3mdl-magn", .data = LIS3MDL_MAGN_DEV_NAME, }, + { + .compatible = "st,lsm303agr-magn", + .data = LSM303AGR_MAGN_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_magn_of_match); @@ -79,6 +83,7 @@ static const struct i2c_device_id st_magn_id_table[] = { { LSM303DLHC_MAGN_DEV_NAME }, { LSM303DLM_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME }, + { LSM303AGR_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_magn_id_table); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 7adacf160146..0abca2c6afa6 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -51,6 +51,7 @@ static const struct spi_device_id st_magn_id_table[] = { { LSM303DLHC_MAGN_DEV_NAME }, { LSM303DLM_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME }, + { LSM303AGR_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_magn_id_table); -- cgit v1.3-6-gb490 From eb87a05223293a915dc97e6966cbbb1baa43cd5f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:05 +0800 Subject: ACPICA: Parser: Reduce parser/namespace divergences for tracer support This patch reduces divergences in parser/namespace components so that the follow-up linuxized ACPICA upstream commits can be directly merged. Including the fix to an indent issue reported and fixed by Zhouyi Zhou. Signed-off-by: Lv Zheng Signed-off-by: Zhouyi Zhou Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsnames.c | 2 +- drivers/acpi/acpica/nsparse.c | 6 +++--- drivers/acpi/acpica/psloop.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index d293d9748036..2e37888f6abe 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -108,7 +108,7 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node, if (index != 0) { ACPI_ERROR((AE_INFO, "Could not construct external pathname; index=%u, size=%u, Path=%s", - (u32) index, (u32) size, &name_buffer[size])); + (u32)index, (u32)size, &name_buffer[size])); return (AE_BAD_PARAMETER); } diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 57a4cfe547e4..9926a67ca6d7 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -70,7 +70,7 @@ acpi_ns_one_complete_parse(u32 pass_number, { union acpi_parse_object *parse_root; acpi_status status; - u32 aml_length; + u32 aml_length; u8 *aml_start; struct acpi_walk_state *walk_state; struct acpi_table_header *table; @@ -110,11 +110,11 @@ acpi_ns_one_complete_parse(u32 pass_number, if (table->length < sizeof(struct acpi_table_header)) { status = AE_BAD_HEADER; } else { - aml_start = (u8 *) table + sizeof(struct acpi_table_header); + aml_start = (u8 *)table + sizeof(struct acpi_table_header); aml_length = table->length - sizeof(struct acpi_table_header); status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, aml_start, aml_length, NULL, - (u8) pass_number); + (u8)pass_number); } /* Found OSDT table, enable the namespace override feature */ diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 90437227d790..6136458d65d2 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -126,9 +126,9 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && !walk_state->arg_count) { walk_state->aml_offset = - (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, - walk_state->parser_state. - aml_start); + (u32)ACPI_PTR_DIFF(walk_state->parser_state.aml, + walk_state->parser_state. + aml_start); status = acpi_ps_get_next_arg(walk_state, @@ -499,7 +499,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) if (walk_state->op_info) { ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n", - (u32) op->common.aml_opcode, + (u32)op->common.aml_opcode, walk_state->op_info->name, op, parser_state->aml, op->common.aml_offset)); -- cgit v1.3-6-gb490 From 83482f758b0d2d6a20a10be88399da44aa186aed Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:11 +0800 Subject: ACPICA: Parser: Cleanup aml_offset in struct acpi_walk_state ACPICA commit d254405814495058276c0c2f9d96794d15a6c91c This patch converts aml_offset in struct acpi_walk_state to AML address. AML offset is actually only used by the debugger, using AML address is more direct and efficient during the parsing stage so that we don't need to calculate it during the parsing stage. On the other hand, we can see several issues in the current parser logic around the aml_offset: 1. union acpi_operand_object.Common.aml_offset is redundantly assigned in acpi_ps_parse_loop(). 2. aml_offset is not an indication of the offset from the table header but the offset from the entry of a list of objects. Sometimes, it indicates an entry for a Method/Package/Buffer, which makes it difficult to be reversely calculated to a table header offset. 3. When being used with method tracers (for example, Linux function trace), it's better to have AML address logged instead of the AML offset because the address is the only attribute that can uniquely identify the opcode. This patch is required to solve the above issues. Lv Zheng. Link: https://github.com/acpica/acpica/commit/d2544058 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acstruct.h | 2 +- drivers/acpi/acpica/dsmethod.c | 9 +++++++-- drivers/acpi/acpica/psloop.c | 15 +++++++++------ drivers/acpi/acpica/psobject.c | 15 +++++++++------ 4 files changed, 26 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index 44997ca02ae2..f9992dced1f9 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -85,7 +85,7 @@ struct acpi_walk_state { u8 namespace_override; /* Override existing objects */ u8 result_size; /* Total elements for the result stack */ u8 result_count; /* Current number of occupied elements of result stack */ - u32 aml_offset; + u8 *aml; u32 arg_types; u32 method_breakpoint; /* For single stepping */ u32 user_breakpoint; /* User AML breakpoint */ diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 85bb951430d9..bf8c16e379fb 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -214,6 +214,8 @@ acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, acpi_status acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state) { + u32 aml_offset; + ACPI_FUNCTION_ENTRY(); /* Ignore AE_OK and control exception codes */ @@ -234,13 +236,16 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state) * Handler can map the exception code to anything it wants, including * AE_OK, in which case the executing method will not be aborted. */ + aml_offset = (u32)ACPI_PTR_DIFF(walk_state->aml, + walk_state->parser_state. + aml_start); + status = acpi_gbl_exception_handler(status, walk_state->method_node ? walk_state->method_node-> name.integer : 0, walk_state->opcode, - walk_state->aml_offset, - NULL); + aml_offset, NULL); acpi_ex_enter_interpreter(); } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 6136458d65d2..ce66e73f1f60 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -125,10 +125,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, */ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && !walk_state->arg_count) { - walk_state->aml_offset = - (u32)ACPI_PTR_DIFF(walk_state->parser_state.aml, - walk_state->parser_state. - aml_start); + walk_state->aml = walk_state->parser_state.aml; status = acpi_ps_get_next_arg(walk_state, @@ -140,7 +137,10 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, } if (arg) { - arg->common.aml_offset = walk_state->aml_offset; + arg->common.aml_offset = + (u32)ACPI_PTR_DIFF(walk_state->aml, + walk_state->parser_state. + aml_start); acpi_ps_append_arg(op, arg); } @@ -494,7 +494,10 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) continue; } - op->common.aml_offset = walk_state->aml_offset; + op->common.aml_offset = + (u32)ACPI_PTR_DIFF(walk_state->aml, + walk_state->parser_state. + aml_start); if (walk_state->op_info) { ACPI_DEBUG_PRINT((ACPI_DB_PARSE, diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index 2f5ddd806c58..6ba3bb7402a9 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -66,12 +66,11 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state); static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) { + u32 aml_offset; ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state); - walk_state->aml_offset = - (u32)ACPI_PTR_DIFF(walk_state->parser_state.aml, - walk_state->parser_state.aml_start); + walk_state->aml = walk_state->parser_state.aml; walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state)); /* @@ -98,10 +97,14 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) /* The opcode is unrecognized. Complain and skip unknown opcodes */ if (walk_state->pass_number == 2) { + aml_offset = (u32)ACPI_PTR_DIFF(walk_state->aml, + walk_state-> + parser_state.aml_start); + ACPI_ERROR((AE_INFO, "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring", walk_state->opcode, - (u32)(walk_state->aml_offset + + (u32)(aml_offset + sizeof(struct acpi_table_header)))); ACPI_DUMP_BUFFER((walk_state->parser_state.aml - 16), @@ -115,14 +118,14 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) acpi_os_printf ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n", walk_state->opcode, - (u32)(walk_state->aml_offset + + (u32)(aml_offset + sizeof(struct acpi_table_header))); /* Dump the context surrounding the invalid opcode */ acpi_ut_dump_buffer(((u8 *)walk_state->parser_state. aml - 16), 48, DB_BYTE_DISPLAY, - (walk_state->aml_offset + + (aml_offset + sizeof(struct acpi_table_header) - 16)); acpi_os_printf(" */\n"); -- cgit v1.3-6-gb490 From 950a429cd21638b0c076d135ed279518b21f452b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:18 +0800 Subject: ACPICA: Parser: Cleanup aml_offset in union acpi_operand_object ACPICA commit 61b360074fde2bb8282722579410f5d1fb12f84d This patch converts aml_offset in union acpi_operand_object to AML address. AML offset is actually only used by the debugger, using AML address is more direct and efficient during the parsing stage so that we don't need to calculate the offset during the parsing stage and will not have difficulities in converting it into other offset attributes. Sometimes, aml_offset is not an indication of the offset from the table header but the offset from the entry of a list of terms, which requires additional efforts to convert it into an offset from the table header. By using AML address directly, there is no such difficulty. Thus this patch also deletes a logic in disassembler that is trying to convert the aml_offset from "offset from the start address of Method/Package/Buffer" into the "offset from the start address of the ACPI table" (Sample code deletion can be seen in acpi_dm_deferred_parse(), but the function is not in the Linux kernel). Lv Zheng. Link: https://github.com/acpica/acpica/commit/61b36007 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 2 +- drivers/acpi/acpica/psargs.c | 7 +++---- drivers/acpi/acpica/psloop.c | 15 ++++----------- 3 files changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index bc600969c6a1..607e62897aff 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -726,7 +726,7 @@ union acpi_parse_value { u8 descriptor_type; /* To differentiate various internal objs */\ u8 flags; /* Type of Op */\ u16 aml_opcode; /* AML opcode */\ - u32 aml_offset; /* Offset of declaration in AML */\ + u8 *aml; /* Address of declaration in AML */\ union acpi_parse_object *next; /* Next op */\ struct acpi_namespace_node *node; /* For use by interpreter */\ union acpi_parse_value value; /* Value or args associated with the opcode */\ diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 6d038770577b..0bee9466d149 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -484,7 +484,7 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state, static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state *parser_state) { - u32 aml_offset; + u8 *aml; union acpi_parse_object *field; union acpi_parse_object *arg = NULL; u16 opcode; @@ -498,8 +498,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state ACPI_FUNCTION_TRACE(ps_get_next_field); - aml_offset = - (u32)ACPI_PTR_DIFF(parser_state->aml, parser_state->aml_start); + aml = parser_state->aml; /* Determine field type */ @@ -541,7 +540,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state return_PTR(NULL); } - field->common.aml_offset = aml_offset; + field->common.aml = aml; /* Decode the field type */ diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index ce66e73f1f60..d5843830fef8 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -137,10 +137,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, } if (arg) { - arg->common.aml_offset = - (u32)ACPI_PTR_DIFF(walk_state->aml, - walk_state->parser_state. - aml_start); + arg->common.aml = walk_state->aml; acpi_ps_append_arg(op, arg); } @@ -494,18 +491,14 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) continue; } - op->common.aml_offset = - (u32)ACPI_PTR_DIFF(walk_state->aml, - walk_state->parser_state. - aml_start); + op->common.aml = walk_state->aml; if (walk_state->op_info) { ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n", + "Opcode %4.4X [%s] Op %p Aml %p\n", (u32)op->common.aml_opcode, walk_state->op_info->name, op, - parser_state->aml, - op->common.aml_offset)); + op->common.aml)); } } -- cgit v1.3-6-gb490 From 62eb935b77818a5e4ff3c8d9b97036b59944f649 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:24 +0800 Subject: ACPICA: Dispatcher: Cleanup union acpi_operand_object's AML address assignments ACPICA commit afb52611dbe7403551f93504d3798534f5c343f4 This patch cleans up the code of assigning the AML address to the union acpi_operand_object. The idea behind this cleanup is: The AML address of the union acpi_operand_object should always be determined at the point where the object is encountered. It should be started from the first byte of the object. For example, the opcode of the object, the name string of the user_term object, or the first byte of the packaged object (where a pkg_length is prefixed). So it's not cleaner to have it assigned here and there in the entire ACPICA source tree. There are some special cases for the internal opcodes, before cleaning up the internal opcodes, we should also determine the rules for the AML addresses of the internal opcodes: 1. INT_NAMEPATH_OP: the address of the first byte for the name_string. 2. INT_METHODCALL_OP: the address of the first byte for the name_string. 3. INT_BYTELIST_OP: the address of the first byte for the byte_data list. 4. INT_EVAL_SUBTREE_OP: the address of the first byte for the Region/Package/Buffer/bank_field/Field arguments. 5. INT_NAMEDFIELD_OP: the address to the name_seg. 6. INT_RESERVEDFIELD_OP: the address to the 0x00 prefix. 7. INT_ACCESSFIELD_OP: the address to the 0x01 prefix. 8. INT_CONNECTION_OP: the address to the 0x02 prefix. 9: INT_EXTACCESSFIELD_OP: the address to the 0x03 prefix. 10.INT_RETURN_VALUE_OP: the address of the replaced operand. 11.computational_data: the address to the Byte/Word/Dword/Qword/string_prefix. Before cleaning up the internal root scope of the aml_walk, turning it into the term_list, we need to remember the aml_start address as the "Aml" attribute for the union acpi_operand_object created by acpi_ps_create_scope_op(). Finally, we can delete some redundant AML address assignment in psloop.c. Link: https://github.com/acpica/acpica/commit/afb52611 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acparser.h | 4 ++-- drivers/acpi/acpica/dsargs.c | 4 ++-- drivers/acpi/acpica/dsmethod.c | 2 +- drivers/acpi/acpica/dswload.c | 2 +- drivers/acpi/acpica/dswload2.c | 2 +- drivers/acpi/acpica/nsparse.c | 40 +++++++++++++++++++--------------------- drivers/acpi/acpica/psargs.c | 21 ++++++++++++--------- drivers/acpi/acpica/psloop.c | 3 --- drivers/acpi/acpica/psobject.c | 2 +- drivers/acpi/acpica/psparse.c | 12 ++++++++---- drivers/acpi/acpica/psutils.c | 8 +++++--- drivers/acpi/acpica/psxface.c | 2 +- 12 files changed, 53 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index 0cdd2fce493a..6021ccfb0b1c 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -225,11 +225,11 @@ void acpi_ps_delete_parse_tree(union acpi_parse_object *root); /* * psutils - parser utilities */ -union acpi_parse_object *acpi_ps_create_scope_op(void); +union acpi_parse_object *acpi_ps_create_scope_op(u8 *aml); void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode); -union acpi_parse_object *acpi_ps_alloc_op(u16 opcode); +union acpi_parse_object *acpi_ps_alloc_op(u16 opcode, u8 *aml); void acpi_ps_free_op(union acpi_parse_object *op); diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index 3e6989738e85..e2ab59e39162 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -86,7 +86,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node, /* Allocate a new parser op to be the root of the parsed tree */ - op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP); + op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP, aml_start); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -129,7 +129,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node, /* Evaluate the deferred arguments */ - op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP); + op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP, aml_start); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index bf8c16e379fb..4abc2425de4b 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -103,7 +103,7 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, /* Create/Init a root op for the method parse tree */ - op = acpi_ps_alloc_op(AML_METHOD_OP); + op = acpi_ps_alloc_op(AML_METHOD_OP, obj_desc->method.aml_start); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 845ff44919c3..097188a6b1c1 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -388,7 +388,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, /* Create a new op */ - op = acpi_ps_alloc_op(walk_state->opcode); + op = acpi_ps_alloc_op(walk_state->opcode, walk_state->aml); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index fcaa30c611fb..e2c08cd79aca 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -335,7 +335,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, /* Create a new op */ - op = acpi_ps_alloc_op(walk_state->opcode); + op = acpi_ps_alloc_op(walk_state->opcode, walk_state->aml); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 9926a67ca6d7..3736d43b18b9 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -78,6 +78,20 @@ acpi_ns_one_complete_parse(u32 pass_number, ACPI_FUNCTION_TRACE(ns_one_complete_parse); + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Table must consist of at least a complete header */ + + if (table->length < sizeof(struct acpi_table_header)) { + return_ACPI_STATUS(AE_BAD_HEADER); + } + + aml_start = (u8 *)table + sizeof(struct acpi_table_header); + aml_length = table->length - sizeof(struct acpi_table_header); + status = acpi_tb_get_owner_id(table_index, &owner_id); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -85,7 +99,7 @@ acpi_ns_one_complete_parse(u32 pass_number, /* Create and init a Root Node */ - parse_root = acpi_ps_create_scope_op(); + parse_root = acpi_ps_create_scope_op(aml_start); if (!parse_root) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -98,23 +112,12 @@ acpi_ns_one_complete_parse(u32 pass_number, return_ACPI_STATUS(AE_NO_MEMORY); } - status = acpi_get_table_by_index(table_index, &table); + status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, + aml_start, aml_length, NULL, + (u8)pass_number); if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); - acpi_ps_free_op(parse_root); - return_ACPI_STATUS(status); - } - - /* Table must consist of at least a complete header */ - - if (table->length < sizeof(struct acpi_table_header)) { - status = AE_BAD_HEADER; - } else { - aml_start = (u8 *)table + sizeof(struct acpi_table_header); - aml_length = table->length - sizeof(struct acpi_table_header); - status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, - aml_start, aml_length, NULL, - (u8)pass_number); + goto cleanup; } /* Found OSDT table, enable the namespace override feature */ @@ -124,11 +127,6 @@ acpi_ns_one_complete_parse(u32 pass_number, walk_state->namespace_override = TRUE; } - if (ACPI_FAILURE(status)) { - acpi_ds_delete_walk_state(walk_state); - goto cleanup; - } - /* start_node is the default location to load the table */ if (start_node && start_node != acpi_gbl_root_node) { diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 0bee9466d149..29d8b7b01dca 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -287,7 +287,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, "Control Method - %p Desc %p Path=%p\n", node, method_desc, path)); - name_op = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP); + name_op = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, start); if (!name_op) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -535,13 +535,11 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state /* Allocate a new field op */ - field = acpi_ps_alloc_op(opcode); + field = acpi_ps_alloc_op(opcode, aml); if (!field) { return_PTR(NULL); } - field->common.aml = aml; - /* Decode the field type */ switch (opcode) { @@ -603,6 +601,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state * Argument for Connection operator can be either a Buffer * (resource descriptor), or a name_string. */ + aml = parser_state->aml; if (ACPI_GET8(parser_state->aml) == AML_BUFFER_OP) { parser_state->aml++; @@ -615,7 +614,8 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state /* Non-empty list */ - arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP); + arg = + acpi_ps_alloc_op(AML_INT_BYTELIST_OP, aml); if (!arg) { acpi_ps_free_op(field); return_PTR(NULL); @@ -664,7 +664,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state parser_state->aml = pkg_end; } else { - arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP); + arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, aml); if (!arg) { acpi_ps_free_op(field); return_PTR(NULL); @@ -729,7 +729,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, /* Constants, strings, and namestrings are all the same size */ - arg = acpi_ps_alloc_op(AML_BYTE_OP); + arg = acpi_ps_alloc_op(AML_BYTE_OP, parser_state->aml); if (!arg) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -776,7 +776,8 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, /* Non-empty list */ - arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP); + arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP, + parser_state->aml); if (!arg) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -806,7 +807,9 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, /* null_name or name_string */ - arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP); + arg = + acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, + parser_state->aml); if (!arg) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index d5843830fef8..49c60c2671ef 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -137,7 +137,6 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, } if (arg) { - arg->common.aml = walk_state->aml; acpi_ps_append_arg(op, arg); } @@ -491,8 +490,6 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) continue; } - op->common.aml = walk_state->aml; - if (walk_state->op_info) { ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Opcode %4.4X [%s] Op %p Aml %p\n", diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index 6ba3bb7402a9..e54bc2aa7a88 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -297,7 +297,7 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, /* Create Op structure and append to parent's argument list */ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); - op = acpi_ps_alloc_op(walk_state->opcode); + op = acpi_ps_alloc_op(walk_state->opcode, aml_op_start); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index a555f7f7b9a2..b857ad58022a 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -185,7 +185,8 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, * op must be replaced by a placeholder return op */ replacement_op = - acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); + acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP, + op->common.aml); if (!replacement_op) { status = AE_NO_MEMORY; } @@ -209,7 +210,8 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, || (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { replacement_op = - acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); + acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP, + op->common.aml); if (!replacement_op) { status = AE_NO_MEMORY; } @@ -224,7 +226,8 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, AML_VAR_PACKAGE_OP)) { replacement_op = acpi_ps_alloc_op(op->common. - aml_opcode); + aml_opcode, + op->common.aml); if (!replacement_op) { status = AE_NO_MEMORY; } else { @@ -240,7 +243,8 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, default: replacement_op = - acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); + acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP, + op->common.aml); if (!replacement_op) { status = AE_NO_MEMORY; } diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 32440912023a..183cc1efbc51 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -60,11 +60,11 @@ ACPI_MODULE_NAME("psutils") * DESCRIPTION: Create a Scope and associated namepath op with the root name * ******************************************************************************/ -union acpi_parse_object *acpi_ps_create_scope_op(void) +union acpi_parse_object *acpi_ps_create_scope_op(u8 *aml) { union acpi_parse_object *scope_op; - scope_op = acpi_ps_alloc_op(AML_SCOPE_OP); + scope_op = acpi_ps_alloc_op(AML_SCOPE_OP, aml); if (!scope_op) { return (NULL); } @@ -103,6 +103,7 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) * FUNCTION: acpi_ps_alloc_op * * PARAMETERS: opcode - Opcode that will be stored in the new Op + * aml - Address of the opcode * * RETURN: Pointer to the new Op, null on failure * @@ -112,7 +113,7 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) * ******************************************************************************/ -union acpi_parse_object *acpi_ps_alloc_op(u16 opcode) +union acpi_parse_object *acpi_ps_alloc_op(u16 opcode, u8 *aml) { union acpi_parse_object *op; const struct acpi_opcode_info *op_info; @@ -149,6 +150,7 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode) if (op) { acpi_ps_init_op(op, opcode); + op->common.aml = aml; op->common.flags = flags; } diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index 841a5ea06094..1f3f46d44312 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -256,7 +256,7 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) /* Create and init a Root Node */ - op = acpi_ps_create_scope_op(); + op = acpi_ps_create_scope_op(info->obj_desc->method.aml_start); if (!op) { status = AE_NO_MEMORY; goto cleanup; -- cgit v1.3-6-gb490 From 07b9c91225055afeb2d75942fc36dd51c5553d90 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:31 +0800 Subject: ACPICA: Executer: Add back pointing reference of method operand ACPICA commit 9dcd124e914e87495fbd1786d9484b962e0823e0 This patch adds back pointing reference of the namespace node for a method operand. The namespace node then can be used in acpi_ds_terminate_control_method() to obtain method full path to be used by tracing facilities. Lv Zheng. Link: https://github.com/acpica/acpica/commit/9dcd124e Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acobject.h | 1 + drivers/acpi/acpica/excreate.c | 1 + drivers/acpi/acpica/utdelete.c | 3 +++ 3 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index c81d98d09cac..0bd02c4a5f75 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -176,6 +176,7 @@ struct acpi_object_method { u8 param_count; u8 sync_level; union acpi_operand_object *mutex; + union acpi_operand_object *node; u8 *aml_start; union { acpi_internal_method implementation; diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index aaeea4840aaa..ccb7219bdcee 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -486,6 +486,7 @@ acpi_ex_create_method(u8 * aml_start, obj_desc->method.aml_start = aml_start; obj_desc->method.aml_length = aml_length; + obj_desc->method.node = operand[0]; /* * Disassemble the method flags. Split off the arg_count, Serialized diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index 71fce389fd48..1638312e3d8f 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -209,6 +209,9 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) acpi_ut_delete_object_desc(object->method.mutex); object->method.mutex = NULL; } + if (object->method.node) { + object->method.node = NULL; + } break; case ACPI_TYPE_REGION: -- cgit v1.3-6-gb490 From d1e7ffe50ba588ddf7de520990815c37f31776d8 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:39 +0800 Subject: ACPICA: Namespace: Add function to directly return normalized full path ACPICA commit 6e0229bb156d71675f2e07dc7960adb7ec0a60ea This patch adds functions to return normalized full path instead of "external path". The external path contains trailing "_" for each name segment while the normalized full path doesn't contain the trailing "_". Currently this function is used by the method tracing users to specify a none trailing "_" attached name path. Lv Zheng. Note that we need to validate and switch all Linux kernel acpi_get_name() users to use the new name type before removing the old name type from ACPICA. Link: https://github.com/acpica/acpica/commit/6e0229bb Signed-off-by: Lv Zheng Reviewed-by: Ruiyi Zhang Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acnamesp.h | 13 +- drivers/acpi/acpica/exdump.c | 5 +- drivers/acpi/acpica/nsnames.c | 275 +++++++++++++++++++++++------------------ drivers/acpi/acpica/nsutils.c | 2 +- drivers/acpi/acpica/nsxfname.c | 8 +- drivers/acpi/acpica/rscreate.c | 3 +- drivers/acpi/acpica/utmisc.c | 2 +- include/acpi/actypes.h | 3 +- 8 files changed, 178 insertions(+), 133 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 0dd088290d80..ea0d9076d408 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -272,17 +272,20 @@ acpi_ns_check_package(struct acpi_evaluate_info *info, */ u32 acpi_ns_opens_scope(acpi_object_type type); -acpi_status -acpi_ns_build_external_path(struct acpi_namespace_node *node, - acpi_size size, char *name_buffer); - char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node); +u32 +acpi_ns_build_normalized_path(struct acpi_namespace_node *node, + char *full_path, u32 path_size, u8 no_trailing); + +char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, + u8 no_trailing); + char *acpi_ns_name_of_current_scope(struct acpi_walk_state *walk_state); acpi_status acpi_ns_handle_to_pathname(acpi_handle target_handle, - struct acpi_buffer *buffer); + struct acpi_buffer *buffer, u8 no_trailing); u8 acpi_ns_pattern_match(struct acpi_namespace_node *obj_node, char *search_for); diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 401e7edcd419..b6495fb552f0 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -995,9 +995,8 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc) if (obj_desc->reference.class == ACPI_REFCLASS_NAME) { acpi_os_printf(" %p ", obj_desc->reference.node); - status = - acpi_ns_handle_to_pathname(obj_desc->reference.node, - &ret_buf); + status = acpi_ns_handle_to_pathname(obj_desc->reference.node, + &ret_buf, FALSE); if (ACPI_FAILURE(status)) { acpi_os_printf(" Could not convert name to pathname\n"); } else { diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index 2e37888f6abe..8934b4eddb73 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -49,73 +49,6 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsnames") -/******************************************************************************* - * - * FUNCTION: acpi_ns_build_external_path - * - * PARAMETERS: node - NS node whose pathname is needed - * size - Size of the pathname - * *name_buffer - Where to return the pathname - * - * RETURN: Status - * Places the pathname into the name_buffer, in external format - * (name segments separated by path separators) - * - * DESCRIPTION: Generate a full pathaname - * - ******************************************************************************/ -acpi_status -acpi_ns_build_external_path(struct acpi_namespace_node *node, - acpi_size size, char *name_buffer) -{ - acpi_size index; - struct acpi_namespace_node *parent_node; - - ACPI_FUNCTION_ENTRY(); - - /* Special case for root */ - - index = size - 1; - if (index < ACPI_NAME_SIZE) { - name_buffer[0] = AML_ROOT_PREFIX; - name_buffer[1] = 0; - return (AE_OK); - } - - /* Store terminator byte, then build name backwards */ - - parent_node = node; - name_buffer[index] = 0; - - while ((index > ACPI_NAME_SIZE) && (parent_node != acpi_gbl_root_node)) { - index -= ACPI_NAME_SIZE; - - /* Put the name into the buffer */ - - ACPI_MOVE_32_TO_32((name_buffer + index), &parent_node->name); - parent_node = parent_node->parent; - - /* Prefix name with the path separator */ - - index--; - name_buffer[index] = ACPI_PATH_SEPARATOR; - } - - /* Overwrite final separator with the root prefix character */ - - name_buffer[index] = AML_ROOT_PREFIX; - - if (index != 0) { - ACPI_ERROR((AE_INFO, - "Could not construct external pathname; index=%u, size=%u, Path=%s", - (u32)index, (u32)size, &name_buffer[size])); - - return (AE_BAD_PARAMETER); - } - - return (AE_OK); -} - /******************************************************************************* * * FUNCTION: acpi_ns_get_external_pathname @@ -130,37 +63,13 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node, * for error and debug statements. * ******************************************************************************/ - char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) { - acpi_status status; char *name_buffer; - acpi_size size; ACPI_FUNCTION_TRACE_PTR(ns_get_external_pathname, node); - /* Calculate required buffer size based on depth below root */ - - size = acpi_ns_get_pathname_length(node); - if (!size) { - return_PTR(NULL); - } - - /* Allocate a buffer to be returned to caller */ - - name_buffer = ACPI_ALLOCATE_ZEROED(size); - if (!name_buffer) { - ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size)); - return_PTR(NULL); - } - - /* Build the path in the allocated buffer */ - - status = acpi_ns_build_external_path(node, size, name_buffer); - if (ACPI_FAILURE(status)) { - ACPI_FREE(name_buffer); - return_PTR(NULL); - } + name_buffer = acpi_ns_get_normalized_pathname(node, FALSE); return_PTR(name_buffer); } @@ -180,33 +89,12 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) { acpi_size size; - struct acpi_namespace_node *next_node; ACPI_FUNCTION_ENTRY(); - /* - * Compute length of pathname as 5 * number of name segments. - * Go back up the parent tree to the root - */ - size = 0; - next_node = node; + size = acpi_ns_build_normalized_path(node, NULL, 0, FALSE); - while (next_node && (next_node != acpi_gbl_root_node)) { - if (ACPI_GET_DESCRIPTOR_TYPE(next_node) != ACPI_DESC_TYPE_NAMED) { - ACPI_ERROR((AE_INFO, - "Invalid Namespace Node (%p) while traversing namespace", - next_node)); - return (0); - } - size += ACPI_PATH_SEGMENT_LENGTH; - next_node = next_node->parent; - } - - if (!size) { - size = 1; /* Root node case */ - } - - return (size + 1); /* +1 for null string terminator */ + return (size); } /******************************************************************************* @@ -216,6 +104,8 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) * PARAMETERS: target_handle - Handle of named object whose name is * to be found * buffer - Where the pathname is returned + * no_trailing - Remove trailing '_' for each name + * segment * * RETURN: Status, Buffer is filled with pathname if status is AE_OK * @@ -225,7 +115,7 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) acpi_status acpi_ns_handle_to_pathname(acpi_handle target_handle, - struct acpi_buffer * buffer) + struct acpi_buffer * buffer, u8 no_trailing) { acpi_status status; struct acpi_namespace_node *node; @@ -240,7 +130,8 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, /* Determine size required for the caller buffer */ - required_size = acpi_ns_get_pathname_length(node); + required_size = + acpi_ns_build_normalized_path(node, NULL, 0, no_trailing); if (!required_size) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -254,8 +145,8 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, /* Build the path in the caller buffer */ - status = - acpi_ns_build_external_path(node, required_size, buffer->pointer); + (void)acpi_ns_build_normalized_path(node, buffer->pointer, + required_size, no_trailing); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -264,3 +155,149 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, (char *)buffer->pointer, (u32) required_size)); return_ACPI_STATUS(AE_OK); } + +/******************************************************************************* + * + * FUNCTION: acpi_ns_build_normalized_path + * + * PARAMETERS: node - Namespace node + * full_path - Where the path name is returned + * path_size - Size of returned path name buffer + * no_trailing - Remove trailing '_' from each name segment + * + * RETURN: Return 1 if the AML path is empty, otherwise returning (length + * of pathname + 1) which means the 'FullPath' contains a trailing + * null. + * + * DESCRIPTION: Build and return a full namespace pathname. + * Note that if the size of 'FullPath' isn't large enough to + * contain the namespace node's path name, the actual required + * buffer length is returned, and it should be greater than + * 'PathSize'. So callers are able to check the returning value + * to determine the buffer size of 'FullPath'. + * + ******************************************************************************/ + +u32 +acpi_ns_build_normalized_path(struct acpi_namespace_node *node, + char *full_path, u32 path_size, u8 no_trailing) +{ + u32 length = 0, i; + char name[ACPI_NAME_SIZE]; + u8 do_no_trailing; + char c, *left, *right; + struct acpi_namespace_node *next_node; + + ACPI_FUNCTION_TRACE_PTR(ns_build_normalized_path, node); + +#define ACPI_PATH_PUT8(path, size, byte, length) \ + do { \ + if ((length) < (size)) \ + { \ + (path)[(length)] = (byte); \ + } \ + (length)++; \ + } while (0) + + /* + * Make sure the path_size is correct, so that we don't need to + * validate both full_path and path_size. + */ + if (!full_path) { + path_size = 0; + } + + if (!node) { + goto build_trailing_null; + } + + next_node = node; + while (next_node && next_node != acpi_gbl_root_node) { + if (next_node != node) { + ACPI_PATH_PUT8(full_path, path_size, + AML_DUAL_NAME_PREFIX, length); + } + ACPI_MOVE_32_TO_32(name, &next_node->name); + do_no_trailing = no_trailing; + for (i = 0; i < 4; i++) { + c = name[4 - i - 1]; + if (do_no_trailing && c != '_') { + do_no_trailing = FALSE; + } + if (!do_no_trailing) { + ACPI_PATH_PUT8(full_path, path_size, c, length); + } + } + next_node = next_node->parent; + } + ACPI_PATH_PUT8(full_path, path_size, AML_ROOT_PREFIX, length); + + /* Reverse the path string */ + + if (length <= path_size) { + left = full_path; + right = full_path + length - 1; + while (left < right) { + c = *left; + *left++ = *right; + *right-- = c; + } + } + + /* Append the trailing null */ + +build_trailing_null: + ACPI_PATH_PUT8(full_path, path_size, '\0', length); + +#undef ACPI_PATH_PUT8 + + return_UINT32(length); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_normalized_pathname + * + * PARAMETERS: node - Namespace node whose pathname is needed + * no_trailing - Remove trailing '_' from each name segment + * + * RETURN: Pointer to storage containing the fully qualified name of + * the node, In external format (name segments separated by path + * separators.) + * + * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually + * for error and debug statements. All trailing '_' will be + * removed from the full pathname if 'NoTrailing' is specified.. + * + ******************************************************************************/ + +char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, + u8 no_trailing) +{ + char *name_buffer; + acpi_size size; + + ACPI_FUNCTION_TRACE_PTR(ns_get_normalized_pathname, node); + + /* Calculate required buffer size based on depth below root */ + + size = acpi_ns_build_normalized_path(node, NULL, 0, no_trailing); + if (!size) { + return_PTR(NULL); + } + + /* Allocate a buffer to be returned to caller */ + + name_buffer = ACPI_ALLOCATE_ZEROED(size); + if (!name_buffer) { + ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size)); + return_PTR(NULL); + } + + /* Build the path in the allocated buffer */ + + (void)acpi_ns_build_normalized_path(node, name_buffer, size, + no_trailing); + + return_PTR(name_buffer); +} diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 8d8104b8bd28..9a34c5f04075 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -83,7 +83,7 @@ acpi_ns_print_node_pathname(struct acpi_namespace_node *node, buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_ns_handle_to_pathname(node, &buffer); + status = acpi_ns_handle_to_pathname(node, &buffer, FALSE); if (ACPI_SUCCESS(status)) { if (message) { acpi_os_printf("%s ", message); diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 9ff643b9553f..4b4d2f43d406 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -172,11 +172,15 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) return (status); } - if (name_type == ACPI_FULL_PATHNAME) { + if (name_type == ACPI_FULL_PATHNAME || + name_type == ACPI_FULL_PATHNAME_NO_TRAILING) { /* Get the full pathname (From the namespace root) */ - status = acpi_ns_handle_to_pathname(handle, buffer); + status = acpi_ns_handle_to_pathname(handle, buffer, + name_type == + ACPI_FULL_PATHNAME ? FALSE : + TRUE); return (status); } diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 3fa829e96c2a..a5344428f3ae 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -348,7 +348,8 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, status = acpi_ns_handle_to_pathname((acpi_handle) node, - &path_buffer); + &path_buffer, + FALSE); /* +1 to include null terminator */ diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 71b66537f826..98087ea1cdb3 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -376,7 +376,7 @@ acpi_ut_display_init_pathname(u8 type, /* Get the full pathname to the node */ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_ns_handle_to_pathname(obj_handle, &buffer); + status = acpi_ns_handle_to_pathname(obj_handle, &buffer, FALSE); if (ACPI_FAILURE(status)) { return; } diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index c2a41d223162..0f3913f9a377 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -985,7 +985,8 @@ struct acpi_buffer { */ #define ACPI_FULL_PATHNAME 0 #define ACPI_SINGLE_NAME 1 -#define ACPI_NAME_TYPE_MAX 1 +#define ACPI_FULL_PATHNAME_NO_TRAILING 2 +#define ACPI_NAME_TYPE_MAX 2 /* * Predefined Namespace items -- cgit v1.3-6-gb490 From 0bac4295526c67e87ec24b29762140c38de7c86a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:46 +0800 Subject: ACPICA: Dispatcher: Move stack traversal code to dispatcher ACPICA commit c8275e243b58fd4adfc0362bd704af41ed14bc75 This patch moves parts of acpi_dm_dump_method_info() to the dispatcher component. This patch also makes the new function dependent on ACPI_DEBUG_OUTPUT compile-stage definition so that it can be used by the trace facility. acpi_dm_dump_method_info() traverses method stack when an exception is encountered. Such traversal is needed to support method tracing for the exceptions. When an exception is encountered, the end indications of the aborted methods should be logged in order not to break the user space analysis tool. Lv Zheng. Link: https://github.com/acpica/acpica/commit/c8275e24 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/Makefile | 1 + drivers/acpi/acpica/acdispat.h | 8 ++ drivers/acpi/acpica/dsdebug.c | 222 +++++++++++++++++++++++++++++++++++++++++ drivers/acpi/acpica/dsmethod.c | 7 +- 4 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 drivers/acpi/acpica/dsdebug.c (limited to 'drivers') diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index c1a963581dc0..9f30ed7b1a07 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -11,6 +11,7 @@ obj-y += acpi.o acpi-y := \ dsargs.o \ dscontrol.o \ + dsdebug.o \ dsfield.o \ dsinit.o \ dsmethod.o \ diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index 408f04bcaab4..7094dc89eb81 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -354,4 +354,12 @@ acpi_status acpi_ds_result_push(union acpi_operand_object *object, struct acpi_walk_state *walk_state); +/* + * dsdebug - parser debugging routines + */ +void +acpi_ds_dump_method_stack(acpi_status status, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + #endif /* _ACDISPAT_H_ */ diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c new file mode 100644 index 000000000000..21c6cefd267e --- /dev/null +++ b/drivers/acpi/acpica/dsdebug.c @@ -0,0 +1,222 @@ +/****************************************************************************** + * + * Module Name: dsdebug - Parser/Interpreter interface - debugging + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2015, Intel Corp. + * 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, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any 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. + * + * NO WARRANTY + * 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 MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#include +#include "accommon.h" +#include "acdispat.h" +#include "acnamesp.h" +#ifdef ACPI_DISASSEMBLER +#include "acdisasm.h" +#endif + +#define _COMPONENT ACPI_DISPATCHER +ACPI_MODULE_NAME("dsdebug") + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +/* Local prototypes */ +static void +acpi_ds_print_node_pathname(struct acpi_namespace_node *node, + const char *message); + +/******************************************************************************* + * + * FUNCTION: acpi_ds_print_node_pathname + * + * PARAMETERS: node - Object + * message - Prefix message + * + * DESCRIPTION: Print an object's full namespace pathname + * Manages allocation/freeing of a pathname buffer + * + ******************************************************************************/ + +static void +acpi_ds_print_node_pathname(struct acpi_namespace_node *node, + const char *message) +{ + struct acpi_buffer buffer; + acpi_status status; + + ACPI_FUNCTION_TRACE(ds_print_node_pathname); + + if (!node) { + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[NULL NAME]")); + return_VOID; + } + + /* Convert handle to full pathname and print it (with supplied message) */ + + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + + status = acpi_ns_handle_to_pathname(node, &buffer, FALSE); + if (ACPI_SUCCESS(status)) { + if (message) { + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "%s ", + message)); + } + + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[%s] (Node %p)", + (char *)buffer.pointer, node)); + ACPI_FREE(buffer.pointer); + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_dump_method_stack + * + * PARAMETERS: status - Method execution status + * walk_state - Current state of the parse tree walk + * op - Executing parse op + * + * RETURN: None + * + * DESCRIPTION: Called when a method has been aborted because of an error. + * Dumps the method execution stack. + * + ******************************************************************************/ + +void +acpi_ds_dump_method_stack(acpi_status status, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + union acpi_parse_object *next; + struct acpi_thread_state *thread; + struct acpi_walk_state *next_walk_state; + struct acpi_namespace_node *previous_method = NULL; + + ACPI_FUNCTION_TRACE(ds_dump_method_stack); + + /* Ignore control codes, they are not errors */ + + if ((status & AE_CODE_MASK) == AE_CODE_CONTROL) { + return_VOID; + } + + /* We may be executing a deferred opcode */ + + if (walk_state->deferred_node) { + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "Executing subtree for Buffer/Package/Region\n")); + return_VOID; + } + + /* + * If there is no Thread, we are not actually executing a method. + * This can happen when the iASL compiler calls the interpreter + * to perform constant folding. + */ + thread = walk_state->thread; + if (!thread) { + return_VOID; + } + + /* Display exception and method name */ + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "\n**** Exception %s during execution of method ", + acpi_format_exception(status))); + acpi_ds_print_node_pathname(walk_state->method_node, NULL); + + /* Display stack of executing methods */ + + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, + "\n\nMethod Execution Stack:\n")); + next_walk_state = thread->walk_state_list; + + /* Walk list of linked walk states */ + + while (next_walk_state) { + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + " Method [%4.4s] executing: ", + acpi_ut_get_node_name(next_walk_state-> + method_node))); + + /* First method is the currently executing method */ + + if (next_walk_state == walk_state) { + if (op) { + + /* Display currently executing ASL statement */ + + next = op->common.next; + op->common.next = NULL; + +#ifdef ACPI_DISASSEMBLER + acpi_dm_disassemble(next_walk_state, op, + ACPI_UINT32_MAX); +#endif + op->common.next = next; + } + } else { + /* + * This method has called another method + * NOTE: the method call parse subtree is already deleted at this + * point, so we cannot disassemble the method invocation. + */ + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, + "Call to method ")); + acpi_ds_print_node_pathname(previous_method, NULL); + } + + previous_method = next_walk_state->method_node; + next_walk_state = next_walk_state->next; + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "\n")); + } + + return_VOID; +} + +#else +void +acpi_ds_dump_method_stack(acpi_status status, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + return; +} + +#endif diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 4abc2425de4b..e0ae8f4e9b35 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -251,14 +251,15 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state) acpi_ds_clear_implicit_return(walk_state); -#ifdef ACPI_DISASSEMBLER if (ACPI_FAILURE(status)) { + acpi_ds_dump_method_stack(status, walk_state, walk_state->op); /* Display method locals/args if disassembler is present */ - acpi_dm_dump_method_info(status, walk_state, walk_state->op); - } +#ifdef ACPI_DISASSEMBLER + acpi_dm_dump_method_info(status, walk_state); #endif + } return (status); } -- cgit v1.3-6-gb490 From a616dc2fe50270f1fa5050fb9cd88a08531a3f25 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:53 +0800 Subject: ACPICA: Dispatcher: Add trace support for interpreter ACPICA commit 71299ec8b49054daace0df50268e8e055654ca37 This patch adds trace point at the following point: 1. Begin/end of a control method execution; 2. Begin/end of an opcode execution. The trace point feature can be enabled by defining ACPI_DEBUG_OUTPUT and specifying a debug level that includes ACPI_LV_TRACDE_POINT and the debug layers that include ACPI_PARSER and ACPI_DISPACTCHER. In order to make aml_op_name of union acpi_parse_object usable for tracer, it is enabled for ACPI_DEBUG_OUTPUT in this patch. Lv Zheng. Link: https://github.com/acpica/acpica/commit/71299ec8 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 2 +- drivers/acpi/acpica/dsdebug.c | 24 ++++++++++++++++++++++++ drivers/acpi/acpica/dsmethod.c | 31 +++++++++++++++++++++++++++++++ drivers/acpi/acpica/psloop.c | 15 +++++++++++++++ drivers/acpi/acpica/psparse.c | 4 ++++ include/acpi/acoutput.h | 4 +++- 6 files changed, 78 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 607e62897aff..610d001fbb31 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -715,7 +715,7 @@ union acpi_parse_value { union acpi_parse_object *arg; /* arguments and contained ops */ }; -#ifdef ACPI_DISASSEMBLER +#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG_OUTPUT) #define ACPI_DISASM_ONLY_MEMBERS(a) a; #else #define ACPI_DISASM_ONLY_MEMBERS(a) diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index 21c6cefd267e..7df9b50e17a7 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -127,6 +127,8 @@ acpi_ds_dump_method_stack(acpi_status status, struct acpi_thread_state *thread; struct acpi_walk_state *next_walk_state; struct acpi_namespace_node *previous_method = NULL; + union acpi_operand_object *method_desc; + char *pathname = NULL; ACPI_FUNCTION_TRACE(ds_dump_method_stack); @@ -170,6 +172,28 @@ acpi_ds_dump_method_stack(acpi_status status, /* Walk list of linked walk states */ while (next_walk_state) { + method_desc = next_walk_state->method_desc; + if (method_desc && method_desc->method.node) { + pathname = acpi_ns_get_normalized_pathname((struct + acpi_namespace_node + *) + method_desc-> + method.node, + TRUE); + } + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p:%s] execution.\n", + method_desc->method.aml_start, + pathname)); + ACPI_FREE(pathname); + pathname = NULL; + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p] execution.\n", + method_desc->method.aml_start)); + } + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, " Method [%4.4s] executing: ", acpi_ut_get_node_name(next_walk_state-> diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index e0ae8f4e9b35..0fa6f19aab3a 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -327,6 +327,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; + char *pathname = NULL; ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node); @@ -334,6 +335,18 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, return_ACPI_STATUS(AE_NULL_ENTRY); } + pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin method [0x%p:%s] execution.\n", + obj_desc->method.aml_start, pathname)); + ACPI_FREE(pathname); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin method [0x%p] execution.\n", + obj_desc->method.aml_start)); + } + /* Prevent wraparound of thread count */ if (obj_desc->method.thread_count == ACPI_UINT8_MAX) { @@ -695,6 +708,7 @@ void acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, struct acpi_walk_state *walk_state) { + char *pathname = NULL; ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); @@ -832,5 +846,22 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, } } + if (method_desc->method.node) { + pathname = acpi_ns_get_normalized_pathname((struct + acpi_namespace_node + *)method_desc-> + method.node, TRUE); + } + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p:%s] execution.\n", + method_desc->method.aml_start, pathname)); + ACPI_FREE(pathname); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p] execution.\n", + method_desc->method.aml_start)); + } + return_VOID; } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 49c60c2671ef..80339ba56cad 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -497,6 +497,21 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) walk_state->op_info->name, op, op->common.aml)); } + + if (walk_state->op_info) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin opcode: %s[0x%p] Class=0x%02x, Type=0x%02x, Flags=0x%04x.\n", + op->common.aml_op_name, + op->common.aml, + walk_state->op_info->class, + walk_state->op_info->type, + walk_state->op_info->flags)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin opcode: %s[0x%p].\n", + op->common.aml_op_name, + op->common.aml)); + } } /* diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index b857ad58022a..97ea0e5360f1 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -147,6 +147,10 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, return_ACPI_STATUS(AE_OK); /* OK for now */ } + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End opcode: %s[0x%p].\n", + op->common.aml_op_name, op->common.aml)); + /* Delete this op and the subtree below it if asked to */ if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) != diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index f56de8c5d844..8f89df9c7295 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -88,7 +88,8 @@ #define ACPI_LV_DEBUG_OBJECT 0x00000002 #define ACPI_LV_INFO 0x00000004 #define ACPI_LV_REPAIR 0x00000008 -#define ACPI_LV_ALL_EXCEPTIONS 0x0000000F +#define ACPI_LV_TRACE_POINT 0x00000010 +#define ACPI_LV_ALL_EXCEPTIONS 0x0000001F /* Trace verbosity level 1 [Standard Trace Level] */ @@ -147,6 +148,7 @@ #define ACPI_DB_DEBUG_OBJECT ACPI_DEBUG_LEVEL (ACPI_LV_DEBUG_OBJECT) #define ACPI_DB_INFO ACPI_DEBUG_LEVEL (ACPI_LV_INFO) #define ACPI_DB_REPAIR ACPI_DEBUG_LEVEL (ACPI_LV_REPAIR) +#define ACPI_DB_TRACE_POINT ACPI_DEBUG_LEVEL (ACPI_LV_TRACE_POINT) #define ACPI_DB_ALL_EXCEPTIONS ACPI_DEBUG_LEVEL (ACPI_LV_ALL_EXCEPTIONS) /* Trace level -- also used in the global "DebugLevel" */ -- cgit v1.3-6-gb490 From ab6c573320768c36ac629be3db79ad62445aae64 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:59 +0800 Subject: ACPICA: Executer: Add interpreter tracing mode for method tracing facility ACPICA commit 07fffd02607685b655ed92ee15c160e6a810b60b The acpi_debug_trace() is the mechanism known as ACPI method tracing that is used by Linux as ACPICA debugging message reducer. This facility can be controlled through Linux ACPI subsystem - /sys/module/acpi/parameters. This facility requires CONFIG_ACPI_DEBUG to be enabled to see ACPICA trace logs in the kernel dmesg output. This patch enhances acpi_debug_trace() to make it not only a message reducer, but a real tracer to trace AML interpreter execution. Note that in addition to the AML tracer enabling, this patch also updates the facility with the following enhancements: 1. Allow a full path to be specified by the acpi_debug_trace() API. 2. Allow any method rather than just the entrance of acpi_evaluate_object() to be traced. 3. All interpreter ACPI_LV_TRACE_POINT messages are collected for ACPI_EXECUTER layer. The Makefile of drivers/acpi/acpica is also updated to include exdebug.o and the duplicated stubs are removed after that. Note that since this patch has enhanced the method tracing facility, Linux need also be updated after applying this patch. Lv Zheng. Link: https://github.com/acpica/acpica/commit/07fffd02 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acdebug.h | 2 + drivers/acpi/acpica/acglobal.h | 2 - drivers/acpi/acpica/acinterp.h | 18 +++ drivers/acpi/acpica/dsdebug.c | 25 +--- drivers/acpi/acpica/dsmethod.c | 32 +---- drivers/acpi/acpica/exdebug.c | 271 +++++++++++++++++++++++++++++++++++++++++ drivers/acpi/acpica/psloop.c | 16 +-- drivers/acpi/acpica/psparse.c | 4 +- drivers/acpi/acpica/psxface.c | 121 ++---------------- drivers/acpi/acpica/utinit.c | 2 - include/acpi/acoutput.h | 13 ++ include/acpi/acpixf.h | 6 +- 12 files changed, 327 insertions(+), 185 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 43685dd36c77..88482f75e941 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -102,6 +102,8 @@ void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg); acpi_status acpi_db_sleep(char *object_arg); +void acpi_db_trace(char *enable_arg, char *method_arg, char *once_arg); + void acpi_db_display_locks(void); void acpi_db_display_resources(char *object_arg); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 53f96a370762..5342300719ee 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -290,8 +290,6 @@ ACPI_GLOBAL(u32, acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]); ACPI_GLOBAL(u32, acpi_gbl_original_dbg_level); ACPI_GLOBAL(u32, acpi_gbl_original_dbg_layer); -ACPI_GLOBAL(u32, acpi_gbl_trace_dbg_level); -ACPI_GLOBAL(u32, acpi_gbl_trace_dbg_layer); /***************************************************************************** * diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index 7ac98000b46b..a3c6e2ab93bb 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -131,6 +131,24 @@ void acpi_ex_do_debug_object(union acpi_operand_object *source_desc, u32 level, u32 index); +void +acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state); + +void +acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state); + +void +acpi_ex_start_trace_opcode(union acpi_parse_object *op, + struct acpi_walk_state *walk_state); + +void +acpi_ex_stop_trace_opcode(union acpi_parse_object *op, + struct acpi_walk_state *walk_state); + /* * exfield - ACPI AML (p-code) execution - field manipulation */ diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index 7df9b50e17a7..a651d30133d0 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -48,6 +48,7 @@ #ifdef ACPI_DISASSEMBLER #include "acdisasm.h" #endif +#include "acinterp.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsdebug") @@ -128,7 +129,6 @@ acpi_ds_dump_method_stack(acpi_status status, struct acpi_walk_state *next_walk_state; struct acpi_namespace_node *previous_method = NULL; union acpi_operand_object *method_desc; - char *pathname = NULL; ACPI_FUNCTION_TRACE(ds_dump_method_stack); @@ -173,25 +173,10 @@ acpi_ds_dump_method_stack(acpi_status status, while (next_walk_state) { method_desc = next_walk_state->method_desc; - if (method_desc && method_desc->method.node) { - pathname = acpi_ns_get_normalized_pathname((struct - acpi_namespace_node - *) - method_desc-> - method.node, - TRUE); - } - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p:%s] execution.\n", - method_desc->method.aml_start, - pathname)); - ACPI_FREE(pathname); - pathname = NULL; - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p] execution.\n", - method_desc->method.aml_start)); + if (method_desc) { + acpi_ex_stop_trace_method((struct acpi_namespace_node *) + method_desc->method.node, + method_desc, walk_state); } ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 0fa6f19aab3a..ea2bdde1227e 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -327,7 +327,6 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; - char *pathname = NULL; ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node); @@ -335,17 +334,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, return_ACPI_STATUS(AE_NULL_ENTRY); } - pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin method [0x%p:%s] execution.\n", - obj_desc->method.aml_start, pathname)); - ACPI_FREE(pathname); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin method [0x%p] execution.\n", - obj_desc->method.aml_start)); - } + acpi_ex_start_trace_method(method_node, obj_desc, walk_state); /* Prevent wraparound of thread count */ @@ -708,7 +697,6 @@ void acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, struct acpi_walk_state *walk_state) { - char *pathname = NULL; ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); @@ -846,22 +834,8 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, } } - if (method_desc->method.node) { - pathname = acpi_ns_get_normalized_pathname((struct - acpi_namespace_node - *)method_desc-> - method.node, TRUE); - } - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p:%s] execution.\n", - method_desc->method.aml_start, pathname)); - ACPI_FREE(pathname); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p] execution.\n", - method_desc->method.aml_start)); - } + acpi_ex_stop_trace_method((struct acpi_namespace_node *)method_desc-> + method.node, method_desc, walk_state); return_VOID; } diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index 815442bbd051..00ba9fc85f47 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -43,11 +43,15 @@ #include #include "accommon.h" +#include "acnamesp.h" #include "acinterp.h" +#include "acparser.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exdebug") +static union acpi_operand_object *acpi_gbl_trace_method_object = NULL; + #ifndef ACPI_NO_ERROR_MESSAGES /******************************************************************************* * @@ -70,6 +74,7 @@ ACPI_MODULE_NAME("exdebug") * enabled if necessary. * ******************************************************************************/ + void acpi_ex_do_debug_object(union acpi_operand_object *source_desc, u32 level, u32 index) @@ -308,3 +313,269 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, return_VOID; } #endif + +/******************************************************************************* + * + * FUNCTION: acpi_ex_interpreter_trace_enabled + * + * PARAMETERS: name - Whether method name should be matched, + * this should be checked before starting + * the tracer + * + * RETURN: TRUE if interpreter trace is enabled. + * + * DESCRIPTION: Check whether interpreter trace is enabled + * + ******************************************************************************/ + +static u8 acpi_ex_interpreter_trace_enabled(char *name) +{ + + /* Check if tracing is enabled */ + + if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED)) { + return (FALSE); + } + + /* + * Check if tracing is filtered: + * + * 1. If the tracer is started, acpi_gbl_trace_method_object should have + * been filled by the trace starter + * 2. If the tracer is not started, acpi_gbl_trace_method_name should be + * matched if it is specified + * 3. If the tracer is oneshot style, acpi_gbl_trace_method_name should + * not be cleared by the trace stopper during the first match + */ + if (acpi_gbl_trace_method_object) { + return (TRUE); + } + if (name && + (acpi_gbl_trace_method_name && + strcmp(acpi_gbl_trace_method_name, name))) { + return (FALSE); + } + if ((acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) && + !acpi_gbl_trace_method_name) { + return (FALSE); + } + + return (TRUE); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_start_trace_method + * + * PARAMETERS: method_node - Node of the method + * obj_desc - The method object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Start control method execution trace + * + ******************************************************************************/ + +void +acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + char *pathname = NULL; + u8 enabled = FALSE; + + ACPI_FUNCTION_NAME(ex_start_trace_method); + + if (method_node) { + pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto exit; + } + + enabled = acpi_ex_interpreter_trace_enabled(pathname); + if (enabled && !acpi_gbl_trace_method_object) { + acpi_gbl_trace_method_object = obj_desc; + acpi_gbl_original_dbg_level = acpi_dbg_level; + acpi_gbl_original_dbg_layer = acpi_dbg_layer; + acpi_dbg_level = ACPI_TRACE_LEVEL_ALL; + acpi_dbg_layer = ACPI_TRACE_LAYER_ALL; + + if (acpi_gbl_trace_dbg_level) { + acpi_dbg_level = acpi_gbl_trace_dbg_level; + } + if (acpi_gbl_trace_dbg_layer) { + acpi_dbg_layer = acpi_gbl_trace_dbg_layer; + } + } + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + +exit: + if (enabled) { + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin method [0x%p:%s] execution.\n", + obj_desc->method.aml_start, + pathname)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin method [0x%p] execution.\n", + obj_desc->method.aml_start)); + } + } + if (pathname) { + ACPI_FREE(pathname); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_stop_trace_method + * + * PARAMETERS: method_node - Node of the method + * obj_desc - The method object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Stop control method execution trace + * + ******************************************************************************/ + +void +acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + char *pathname = NULL; + u8 enabled; + + ACPI_FUNCTION_NAME(ex_stop_trace_method); + + if (method_node) { + pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto exit_path; + } + + enabled = acpi_ex_interpreter_trace_enabled(NULL); + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + + if (enabled) { + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p:%s] execution.\n", + obj_desc->method.aml_start, + pathname)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p] execution.\n", + obj_desc->method.aml_start)); + } + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto exit_path; + } + + /* Check whether the tracer should be stopped */ + + if (acpi_gbl_trace_method_object == obj_desc) { + + /* Disable further tracing if type is one-shot */ + + if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) { + acpi_gbl_trace_method_name = NULL; + } + + acpi_dbg_level = acpi_gbl_original_dbg_level; + acpi_dbg_layer = acpi_gbl_original_dbg_layer; + acpi_gbl_trace_method_object = NULL; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + +exit_path: + if (pathname) { + ACPI_FREE(pathname); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_start_trace_opcode + * + * PARAMETERS: op - The parser opcode object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Start opcode execution trace + * + ******************************************************************************/ + +void +acpi_ex_start_trace_opcode(union acpi_parse_object *op, + struct acpi_walk_state *walk_state) +{ + + ACPI_FUNCTION_NAME(ex_start_trace_opcode); + + if (acpi_ex_interpreter_trace_enabled(NULL)) { + if (walk_state->op_info) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin opcode: %s[0x%p] Class=0x%02x, Type=0x%02x, Flags=0x%04x.\n", + op->common.aml_op_name, + op->common.aml, + walk_state->op_info->class, + walk_state->op_info->type, + walk_state->op_info->flags)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin opcode: %s[0x%p].\n", + op->common.aml_op_name, + op->common.aml)); + } + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_stop_trace_opcode + * + * PARAMETERS: op - The parser opcode object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Stop opcode execution trace + * + ******************************************************************************/ + +void +acpi_ex_stop_trace_opcode(union acpi_parse_object *op, + struct acpi_walk_state *walk_state) +{ + + ACPI_FUNCTION_NAME(ex_stop_trace_opcode); + + if (acpi_ex_interpreter_trace_enabled(NULL)) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End opcode: %s[0x%p].\n", + op->common.aml_op_name, op->common.aml)); + } +} diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 80339ba56cad..a7de52ee1538 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -51,6 +51,7 @@ #include #include "accommon.h" +#include "acinterp.h" #include "acparser.h" #include "acdispat.h" #include "amlcode.h" @@ -498,20 +499,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) op->common.aml)); } - if (walk_state->op_info) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin opcode: %s[0x%p] Class=0x%02x, Type=0x%02x, Flags=0x%04x.\n", - op->common.aml_op_name, - op->common.aml, - walk_state->op_info->class, - walk_state->op_info->type, - walk_state->op_info->flags)); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin opcode: %s[0x%p].\n", - op->common.aml_op_name, - op->common.aml)); - } + acpi_ex_start_trace_opcode(op, walk_state); } /* diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 97ea0e5360f1..98001d7f6f80 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -147,9 +147,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, return_ACPI_STATUS(AE_OK); /* OK for now */ } - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End opcode: %s[0x%p].\n", - op->common.aml_op_name, op->common.aml)); + acpi_ex_stop_trace_opcode(op, walk_state); /* Delete this op and the subtree below it if asked to */ diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index 1f3f46d44312..4254805dd319 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -47,15 +47,12 @@ #include "acdispat.h" #include "acinterp.h" #include "actables.h" +#include "acnamesp.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psxface") /* Local Prototypes */ -static void acpi_ps_start_trace(struct acpi_evaluate_info *info); - -static void acpi_ps_stop_trace(struct acpi_evaluate_info *info); - static void acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action); @@ -76,7 +73,7 @@ acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action); ******************************************************************************/ acpi_status -acpi_debug_trace(char *name, u32 debug_level, u32 debug_layer, u32 flags) +acpi_debug_trace(const char *name, u32 debug_level, u32 debug_layer, u32 flags) { acpi_status status; @@ -85,108 +82,14 @@ acpi_debug_trace(char *name, u32 debug_level, u32 debug_layer, u32 flags) return (status); } - /* TBDs: Validate name, allow full path or just nameseg */ - - acpi_gbl_trace_method_name = *ACPI_CAST_PTR(u32, name); + acpi_gbl_trace_method_name = name; acpi_gbl_trace_flags = flags; - - if (debug_level) { - acpi_gbl_trace_dbg_level = debug_level; - } - if (debug_layer) { - acpi_gbl_trace_dbg_layer = debug_layer; - } + acpi_gbl_trace_dbg_level = debug_level; + acpi_gbl_trace_dbg_layer = debug_layer; + status = AE_OK; (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ps_start_trace - * - * PARAMETERS: info - Method info struct - * - * RETURN: None - * - * DESCRIPTION: Start control method execution trace - * - ******************************************************************************/ - -static void acpi_ps_start_trace(struct acpi_evaluate_info *info) -{ - acpi_status status; - - ACPI_FUNCTION_ENTRY(); - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return; - } - - if ((!acpi_gbl_trace_method_name) || - (acpi_gbl_trace_method_name != info->node->name.integer)) { - goto exit; - } - - acpi_gbl_original_dbg_level = acpi_dbg_level; - acpi_gbl_original_dbg_layer = acpi_dbg_layer; - - acpi_dbg_level = 0x00FFFFFF; - acpi_dbg_layer = ACPI_UINT32_MAX; - - if (acpi_gbl_trace_dbg_level) { - acpi_dbg_level = acpi_gbl_trace_dbg_level; - } - if (acpi_gbl_trace_dbg_layer) { - acpi_dbg_layer = acpi_gbl_trace_dbg_layer; - } - -exit: - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ps_stop_trace - * - * PARAMETERS: info - Method info struct - * - * RETURN: None - * - * DESCRIPTION: Stop control method execution trace - * - ******************************************************************************/ - -static void acpi_ps_stop_trace(struct acpi_evaluate_info *info) -{ - acpi_status status; - - ACPI_FUNCTION_ENTRY(); - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return; - } - - if ((!acpi_gbl_trace_method_name) || - (acpi_gbl_trace_method_name != info->node->name.integer)) { - goto exit; - } - - /* Disable further tracing if type is one-shot */ - - if (acpi_gbl_trace_flags & 1) { - acpi_gbl_trace_method_name = 0; - acpi_gbl_trace_dbg_level = 0; - acpi_gbl_trace_dbg_layer = 0; - } - - acpi_dbg_level = acpi_gbl_original_dbg_level; - acpi_dbg_layer = acpi_gbl_original_dbg_layer; - -exit: - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return (status); } /******************************************************************************* @@ -212,7 +115,7 @@ exit: * ******************************************************************************/ -acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) +acpi_status acpi_ps_execute_method(struct acpi_evaluate_info * info) { acpi_status status; union acpi_parse_object *op; @@ -243,10 +146,6 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) */ acpi_ps_update_parameter_list(info, REF_INCREMENT); - /* Begin tracing if requested */ - - acpi_ps_start_trace(info); - /* * Execute the method. Performs parse simultaneously */ @@ -326,10 +225,6 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) cleanup: acpi_ps_delete_parse_tree(op); - /* End optional tracing */ - - acpi_ps_stop_trace(info); - /* Take away the extra reference that we gave the parameters above */ acpi_ps_update_parameter_list(info, REF_DECREMENT); diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index e402e07b4846..7f897c63aa5b 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -204,8 +204,6 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_acpi_hardware_present = TRUE; acpi_gbl_last_owner_id_index = 0; acpi_gbl_next_owner_id_offset = 0; - acpi_gbl_trace_dbg_level = 0; - acpi_gbl_trace_dbg_layer = 0; acpi_gbl_debugger_configuration = DEBUGGER_THREADING; acpi_gbl_osi_mutex = NULL; acpi_gbl_reg_methods_executed = FALSE; diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index 8f89df9c7295..37f46d49a74a 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -184,6 +184,19 @@ #define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT | ACPI_LV_REPAIR) #define ACPI_DEBUG_ALL (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL) +/* + * Global trace flags + */ +#define ACPI_TRACE_ENABLED ((u32) 2) +#define ACPI_TRACE_ONESHOT ((u32) 1) + +/* Defaults for trace debugging level/layer */ + +#define ACPI_TRACE_LEVEL_ALL ACPI_LV_ALL +#define ACPI_TRACE_LAYER_ALL 0x000001FF +#define ACPI_TRACE_LEVEL_DEFAULT ACPI_LV_TRACE_POINT +#define ACPI_TRACE_LAYER_DEFAULT ACPI_EXECUTER + #if defined (ACPI_DEBUG_OUTPUT) || !defined (ACPI_NO_ERROR_MESSAGES) /* * The module name is used primarily for error and debug messages. diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index e8ec18a4a634..9c362cf14264 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -251,7 +251,9 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_reduced_hardware, FALSE); * traced each time it is executed. */ ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_flags, 0); -ACPI_INIT_GLOBAL(acpi_name, acpi_gbl_trace_method_name, 0); +ACPI_INIT_GLOBAL(const char *, acpi_gbl_trace_method_name, NULL); +ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_dbg_level, ACPI_TRACE_LEVEL_DEFAULT); +ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_dbg_layer, ACPI_TRACE_LAYER_DEFAULT); /* * Runtime configuration of debug output control masks. We want the debug @@ -504,7 +506,7 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_object_handler handler, void **data)) ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_debug_trace(char *name, u32 debug_level, + acpi_debug_trace(const char *name, u32 debug_level, u32 debug_layer, u32 flags)) /* -- cgit v1.3-6-gb490 From bab0482418885627babfd1a6ca4e57a809712474 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:53:07 +0800 Subject: ACPICA: Executer: Add OSL trace hook support ACPICA commit e8e4a9b19d0b72a7b165398bdc961fc2f6f502ec This patch adds OSL trace hook support. OSPMs are encouraged to use acpi_os_trace_point() with ACPI_USE_SYSTEM_TRACER defined to implement platform specific trace facility. Lv Zheng. Link: https://github.com/acpica/acpica/commit/e8e4a9b1 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acinterp.h | 4 ++ drivers/acpi/acpica/exdebug.c | 125 +++++++++++++++++++++++++++++------------ drivers/acpi/acpica/utdebug.c | 31 +++++++++- include/acpi/acoutput.h | 3 + include/acpi/acpiosxf.h | 6 ++ include/acpi/acpixf.h | 5 ++ include/acpi/actypes.h | 8 +++ 7 files changed, 144 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index a3c6e2ab93bb..e820ed8f173f 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -149,6 +149,10 @@ void acpi_ex_stop_trace_opcode(union acpi_parse_object *op, struct acpi_walk_state *walk_state); +void +acpi_ex_trace_point(acpi_trace_event_type type, + u8 begin, u8 *aml, char *pathname); + /* * exfield - ACPI AML (p-code) execution - field manipulation */ diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index 00ba9fc85f47..708b2aed0145 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -52,6 +52,12 @@ ACPI_MODULE_NAME("exdebug") static union acpi_operand_object *acpi_gbl_trace_method_object = NULL; +/* Local prototypes */ + +#ifdef ACPI_DEBUG_OUTPUT +static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type); +#endif + #ifndef ACPI_NO_ERROR_MESSAGES /******************************************************************************* * @@ -363,6 +369,78 @@ static u8 acpi_ex_interpreter_trace_enabled(char *name) return (TRUE); } +/******************************************************************************* + * + * FUNCTION: acpi_ex_get_trace_event_name + * + * PARAMETERS: type - Trace event type + * + * RETURN: Trace event name. + * + * DESCRIPTION: Used to obtain the full trace event name. + * + ******************************************************************************/ + +#ifdef ACPI_DEBUG_OUTPUT + +static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type) +{ + switch (type) { + case ACPI_TRACE_AML_METHOD: + + return "Method"; + + case ACPI_TRACE_AML_OPCODE: + + return "Opcode"; + + case ACPI_TRACE_AML_REGION: + + return "Region"; + + default: + + return ""; + } +} + +#endif + +/******************************************************************************* + * + * FUNCTION: acpi_ex_trace_point + * + * PARAMETERS: type - Trace event type + * begin - TRUE if before execution + * aml - Executed AML address + * pathname - Object path + * + * RETURN: None + * + * DESCRIPTION: Internal interpreter execution trace. + * + ******************************************************************************/ + +void +acpi_ex_trace_point(acpi_trace_event_type type, + u8 begin, u8 *aml, char *pathname) +{ + + ACPI_FUNCTION_NAME(ex_trace_point); + + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "%s %s [0x%p:%s] execution.\n", + acpi_ex_get_trace_event_name(type), + begin ? "Begin" : "End", aml, pathname)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "%s %s [0x%p] execution.\n", + acpi_ex_get_trace_event_name(type), + begin ? "Begin" : "End", aml)); + } +} + /******************************************************************************* * * FUNCTION: acpi_ex_start_trace_method @@ -417,16 +495,9 @@ acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, exit: if (enabled) { - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin method [0x%p:%s] execution.\n", - obj_desc->method.aml_start, - pathname)); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin method [0x%p] execution.\n", - obj_desc->method.aml_start)); - } + ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, TRUE, + obj_desc ? obj_desc->method.aml_start : NULL, + pathname); } if (pathname) { ACPI_FREE(pathname); @@ -473,16 +544,9 @@ acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node, (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (enabled) { - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p:%s] execution.\n", - obj_desc->method.aml_start, - pathname)); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p] execution.\n", - obj_desc->method.aml_start)); - } + ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, FALSE, + obj_desc ? obj_desc->method.aml_start : NULL, + pathname); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); @@ -535,20 +599,8 @@ acpi_ex_start_trace_opcode(union acpi_parse_object *op, ACPI_FUNCTION_NAME(ex_start_trace_opcode); if (acpi_ex_interpreter_trace_enabled(NULL)) { - if (walk_state->op_info) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin opcode: %s[0x%p] Class=0x%02x, Type=0x%02x, Flags=0x%04x.\n", - op->common.aml_op_name, - op->common.aml, - walk_state->op_info->class, - walk_state->op_info->type, - walk_state->op_info->flags)); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin opcode: %s[0x%p].\n", - op->common.aml_op_name, - op->common.aml)); - } + ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, TRUE, + op->common.aml, op->common.aml_op_name); } } @@ -574,8 +626,7 @@ acpi_ex_stop_trace_opcode(union acpi_parse_object *op, ACPI_FUNCTION_NAME(ex_stop_trace_opcode); if (acpi_ex_interpreter_trace_enabled(NULL)) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End opcode: %s[0x%p].\n", - op->common.aml_op_name, op->common.aml)); + ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, FALSE, + op->common.aml, op->common.aml_op_name); } } diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index cd02693841db..4146229103c8 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -45,6 +45,7 @@ #include #include "accommon.h" +#include "acinterp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utdebug") @@ -560,8 +561,37 @@ acpi_ut_ptr_exit(u32 line_number, } } +/******************************************************************************* + * + * FUNCTION: acpi_trace_point + * + * PARAMETERS: type - Trace event type + * begin - TRUE if before execution + * aml - Executed AML address + * pathname - Object path + * pointer - Pointer to the related object + * + * RETURN: None + * + * DESCRIPTION: Interpreter execution trace. + * + ******************************************************************************/ + +void +acpi_trace_point(acpi_trace_event_type type, u8 begin, u8 *aml, char *pathname) +{ + + ACPI_FUNCTION_ENTRY(); + + acpi_ex_trace_point(type, begin, aml, pathname); + +#ifdef ACPI_USE_SYSTEM_TRACER + acpi_os_trace_point(type, begin, aml, pathname); #endif +} +ACPI_EXPORT_SYMBOL(acpi_trace_point) +#endif #ifdef ACPI_APPLICATION /******************************************************************************* * @@ -575,7 +605,6 @@ acpi_ut_ptr_exit(u32 line_number, * DESCRIPTION: Print error message to the console, used by applications. * ******************************************************************************/ - void ACPI_INTERNAL_VAR_XFACE acpi_log_error(const char *format, ...) { va_list args; diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index 37f46d49a74a..c3f0ac135f68 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -447,6 +447,8 @@ #define ACPI_DUMP_PATHNAME(a, b, c, d) acpi_ns_dump_pathname(a, b, c, d) #define ACPI_DUMP_BUFFER(a, b) acpi_ut_debug_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) +#define ACPI_TRACE_POINT(a, b, c, d) acpi_trace_point (a, b, c, d) + #else /* ACPI_DEBUG_OUTPUT */ /* * This is the non-debug case -- make everything go away, @@ -468,6 +470,7 @@ #define ACPI_DUMP_PATHNAME(a, b, c, d) #define ACPI_DUMP_BUFFER(a, b) #define ACPI_IS_DEBUG_ENABLED(level, component) 0 +#define ACPI_TRACE_POINT(a, b, c, d) /* Return macros must have a return statement at the minimum */ diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index d02df0a49d98..a54ad1cc990c 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -430,4 +430,10 @@ long acpi_os_get_file_offset(ACPI_FILE file); acpi_status acpi_os_set_file_offset(ACPI_FILE file, long offset, u8 from); #endif +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_trace_point +void +acpi_os_trace_point(acpi_trace_event_type type, + u8 begin, u8 *aml, char *pathname); +#endif + #endif /* __ACPIOSXF_H__ */ diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 9c362cf14264..9aa27a3e3716 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -909,6 +909,11 @@ ACPI_DBG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(6) const char *module_name, u32 component_id, const char *format, ...)) + +ACPI_DBG_DEPENDENT_RETURN_VOID(void + acpi_trace_point(acpi_trace_event_type type, + u8 begin, + u8 *aml, char *pathname)) ACPI_APP_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(1) void ACPI_INTERNAL_VAR_XFACE acpi_log_error(const char *format, ...)) diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 0f3913f9a377..531eca49edd4 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -1247,6 +1247,14 @@ struct acpi_memory_list { #endif }; +/* Definitions of trace event types */ + +typedef enum { + ACPI_TRACE_AML_METHOD, + ACPI_TRACE_AML_OPCODE, + ACPI_TRACE_AML_REGION +} acpi_trace_event_type; + /* Definitions of _OSI support */ #define ACPI_VENDOR_STRINGS 0x01 -- cgit v1.3-6-gb490 From fb18e8fd08862f5509f3c79e168b24512c7065aa Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:53:15 +0800 Subject: ACPICA: Executer: Add option to bypass opcode tracing ACPICA commit 61e9e20aadfaa03184d0959fbdc1fa5cdfea2551 This patch adds option to bypass opcode tracing. The option can be used to reduce the trace message output. Lv Zheng. Link: https://github.com/acpica/acpica/commit/61e9e20a Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/exdebug.c | 6 ++++-- include/acpi/acoutput.h | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index 708b2aed0145..de92458236f5 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -598,7 +598,8 @@ acpi_ex_start_trace_opcode(union acpi_parse_object *op, ACPI_FUNCTION_NAME(ex_start_trace_opcode); - if (acpi_ex_interpreter_trace_enabled(NULL)) { + if (acpi_ex_interpreter_trace_enabled(NULL) && + (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, TRUE, op->common.aml, op->common.aml_op_name); } @@ -625,7 +626,8 @@ acpi_ex_stop_trace_opcode(union acpi_parse_object *op, ACPI_FUNCTION_NAME(ex_stop_trace_opcode); - if (acpi_ex_interpreter_trace_enabled(NULL)) { + if (acpi_ex_interpreter_trace_enabled(NULL) && + (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, FALSE, op->common.aml, op->common.aml_op_name); } diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index c3f0ac135f68..908d4f9c348c 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -187,8 +187,9 @@ /* * Global trace flags */ -#define ACPI_TRACE_ENABLED ((u32) 2) -#define ACPI_TRACE_ONESHOT ((u32) 1) +#define ACPI_TRACE_ENABLED ((u32) 4) +#define ACPI_TRACE_ONESHOT ((u32) 2) +#define ACPI_TRACE_OPCODE ((u32) 1) /* Defaults for trace debugging level/layer */ -- cgit v1.3-6-gb490 From ec4252a66b1a2cd2fc6fbdbf3d3279640500fb75 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:53:22 +0800 Subject: ACPICA: Parser: Remove redundant opcode execution debugging output ACPICA commit c832b0a9263c560b3ae3ae31d7298ef33988f8d5 This patch removes one redundant debugging output of opcode execution which has already been covered by acpi_ex_start_trace_opcode(). Lv Zheng. Link: https://github.com/acpica/acpica/commit/c832b0a9 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/psloop.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index a7de52ee1538..6b11fd7a93dc 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -491,14 +491,6 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) continue; } - if (walk_state->op_info) { - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Opcode %4.4X [%s] Op %p Aml %p\n", - (u32)op->common.aml_opcode, - walk_state->op_info->name, op, - op->common.aml)); - } - acpi_ex_start_trace_opcode(op, walk_state); } -- cgit v1.3-6-gb490 From dc67d0fa8612ad49a8ec36040c5d22a9091bdbf6 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 23 Jul 2015 12:53:28 +0800 Subject: ACPICA: Remove extraneous check for null walk_state ACPICA commit f9fd6e8bad0f16ce2b436c5cda36ced0c2d85302 Reported by Markus Elfring. Link: https://github.com/acpica/acpica/commit/f9fd6e8b Signed-off-by: Markus Elfring Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsmethod.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index ea2bdde1227e..cb53c44c9644 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -582,9 +582,7 @@ cleanup: /* On error, we must terminate the method properly */ acpi_ds_terminate_control_method(obj_desc, next_walk_state); - if (next_walk_state) { - acpi_ds_delete_walk_state(next_walk_state); - } + acpi_ds_delete_walk_state(next_walk_state); return_ACPI_STATUS(status); } -- cgit v1.3-6-gb490 From 53d9edce56de3eb495a3eef77e973e3ea014d999 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 23 Jul 2015 12:53:35 +0800 Subject: ACPICA: iASL: Add new warnings for method local_x and arg_x variables ACPICA commit eb9f8cb9fd65f1149dd335d05944c31cbca41af3 1) Warn if a Local is set but never used 2) Warn if a arg_x is never used (for non-predefined method names) 3) Warn if a arg_x that is used as a local is never used This patch only affects iASL which is not in the kernel source tree. Link: https://github.com/acpica/acpica/commit/eb9f8cb9 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 610d001fbb31..4758185b2b0b 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -174,8 +174,12 @@ struct acpi_namespace_node { */ #ifdef ACPI_LARGE_NAMESPACE_NODE union acpi_parse_object *op; + void *method_locals; + void *method_args; u32 value; u32 length; + u8 arg_count; + #endif }; -- cgit v1.3-6-gb490 From 276291962ebf43abebb491ddcd922009de9fde4b Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 23 Jul 2015 12:53:49 +0800 Subject: ACPICA: Cleanup use of all non-ANSI local C library functions ACPICA commit 7c490c28a18b435c543c6b410e7e7c2131fccc78 ACPICA implements all non-ANSI functions locally. However, there are sometimes two or more versions of the same function throughout the ACPICA code. This change fixes this. Adds a new file, utilities/utnonansi.c Link: https://github.com/acpica/acpica/commit/7c490c28 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/Makefile | 1 + drivers/acpi/acpica/acmacros.h | 4 + drivers/acpi/acpica/acutils.h | 23 ++- drivers/acpi/acpica/utnonansi.c | 380 ++++++++++++++++++++++++++++++++++++++++ drivers/acpi/acpica/utstring.c | 342 ------------------------------------ 5 files changed, 396 insertions(+), 354 deletions(-) create mode 100644 drivers/acpi/acpica/utnonansi.c (limited to 'drivers') diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 9f30ed7b1a07..fedcc16b56cc 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -165,6 +165,7 @@ acpi-y += \ utmath.o \ utmisc.o \ utmutex.o \ + utnonansi.o \ utobject.o \ utosi.o \ utownerid.o \ diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index c240bdf824f2..19d40c6c1f32 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -220,6 +220,10 @@ #define ACPI_MUL_32(a) _ACPI_MUL(a, 5) #define ACPI_MOD_32(a) _ACPI_MOD(a, 32) +/* Test for ASCII character */ + +#define ACPI_IS_ASCII(c) ((c) < 0x80) + /* * Rounding macros (Power of two boundaries only) */ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 6de0d3573037..566ff4df02fd 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -166,6 +166,17 @@ struct acpi_pkg_info { #define DB_DWORD_DISPLAY 4 #define DB_QWORD_DISPLAY 8 +/* + * utnonansi - Non-ANSI C library functions + */ +void acpi_ut_strupr(char *src_string); + +void acpi_ut_strlwr(char *src_string); + +int acpi_ut_stricmp(char *string1, char *string2); + +acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer); + /* * utglobal - Global data structures and procedures */ @@ -205,8 +216,6 @@ acpi_status acpi_ut_hardware_initialize(void); void acpi_ut_subsystem_shutdown(void); -#define ACPI_IS_ASCII(c) ((c) < 0x80) - /* * utcopy - Object construction and conversion interfaces */ @@ -567,16 +576,6 @@ acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag); /* * utstring - String and character utilities */ -void acpi_ut_strupr(char *src_string); - -#ifdef ACPI_ASL_COMPILER -void acpi_ut_strlwr(char *src_string); - -int acpi_ut_stricmp(char *string1, char *string2); -#endif - -acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer); - void acpi_ut_print_string(char *string, u16 max_length); #if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP diff --git a/drivers/acpi/acpica/utnonansi.c b/drivers/acpi/acpica/utnonansi.c new file mode 100644 index 000000000000..1d5f6b17b766 --- /dev/null +++ b/drivers/acpi/acpica/utnonansi.c @@ -0,0 +1,380 @@ +/******************************************************************************* + * + * Module Name: utnonansi - Non-ansi C library functions + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2015, Intel Corp. + * 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, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any 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. + * + * NO WARRANTY + * 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 MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#include +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utnonansi") + +/* + * Non-ANSI C library functions - strlwr, strupr, stricmp, and a 64-bit + * version of strtoul. + */ +/******************************************************************************* + * + * FUNCTION: acpi_ut_strlwr (strlwr) + * + * PARAMETERS: src_string - The source string to convert + * + * RETURN: None + * + * DESCRIPTION: Convert a string to lowercase + * + ******************************************************************************/ +void acpi_ut_strlwr(char *src_string) +{ + char *string; + + ACPI_FUNCTION_ENTRY(); + + if (!src_string) { + return; + } + + /* Walk entire string, lowercasing the letters */ + + for (string = src_string; *string; string++) { + *string = (char)tolower((int)*string); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strupr (strupr) + * + * PARAMETERS: src_string - The source string to convert + * + * RETURN: None + * + * DESCRIPTION: Convert a string to uppercase + * + ******************************************************************************/ + +void acpi_ut_strupr(char *src_string) +{ + char *string; + + ACPI_FUNCTION_ENTRY(); + + if (!src_string) { + return; + } + + /* Walk entire string, uppercasing the letters */ + + for (string = src_string; *string; string++) { + *string = (char)toupper((int)*string); + } +} + +/****************************************************************************** + * + * FUNCTION: acpi_ut_stricmp (stricmp) + * + * PARAMETERS: string1 - first string to compare + * string2 - second string to compare + * + * RETURN: int that signifies string relationship. Zero means strings + * are equal. + * + * DESCRIPTION: Case-insensitive string compare. Implementation of the + * non-ANSI stricmp function. + * + ******************************************************************************/ + +int acpi_ut_stricmp(char *string1, char *string2) +{ + int c1; + int c2; + + do { + c1 = tolower((int)*string1); + c2 = tolower((int)*string2); + + string1++; + string2++; + } + while ((c1 == c2) && (c1)); + + return (c1 - c2); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strtoul64 + * + * PARAMETERS: string - Null terminated string + * base - Radix of the string: 16 or ACPI_ANY_BASE; + * ACPI_ANY_BASE means 'in behalf of to_integer' + * ret_integer - Where the converted integer is returned + * + * RETURN: Status and Converted value + * + * DESCRIPTION: Convert a string into an unsigned value. Performs either a + * 32-bit or 64-bit conversion, depending on the current mode + * of the interpreter. + * + * NOTE: Does not support Octal strings, not needed. + * + ******************************************************************************/ + +acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) +{ + u32 this_digit = 0; + u64 return_value = 0; + u64 quotient; + u64 dividend; + u32 to_integer_op = (base == ACPI_ANY_BASE); + u32 mode32 = (acpi_gbl_integer_byte_width == 4); + u8 valid_digits = 0; + u8 sign_of0x = 0; + u8 term = 0; + + ACPI_FUNCTION_TRACE_STR(ut_stroul64, string); + + switch (base) { + case ACPI_ANY_BASE: + case 16: + + break; + + default: + + /* Invalid Base */ + + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + if (!string) { + goto error_exit; + } + + /* Skip over any white space in the buffer */ + + while ((*string) && (isspace((int)*string) || *string == '\t')) { + string++; + } + + if (to_integer_op) { + /* + * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'. + * We need to determine if it is decimal or hexadecimal. + */ + if ((*string == '0') && (tolower((int)*(string + 1)) == 'x')) { + sign_of0x = 1; + base = 16; + + /* Skip over the leading '0x' */ + string += 2; + } else { + base = 10; + } + } + + /* Any string left? Check that '0x' is not followed by white space. */ + + if (!(*string) || isspace((int)*string) || *string == '\t') { + if (to_integer_op) { + goto error_exit; + } else { + goto all_done; + } + } + + /* + * Perform a 32-bit or 64-bit conversion, depending upon the current + * execution mode of the interpreter + */ + dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX; + + /* Main loop: convert the string to a 32- or 64-bit integer */ + + while (*string) { + if (isdigit((int)*string)) { + + /* Convert ASCII 0-9 to Decimal value */ + + this_digit = ((u8)*string) - '0'; + } else if (base == 10) { + + /* Digit is out of range; possible in to_integer case only */ + + term = 1; + } else { + this_digit = (u8)toupper((int)*string); + if (isxdigit((int)this_digit)) { + + /* Convert ASCII Hex char to value */ + + this_digit = this_digit - 'A' + 10; + } else { + term = 1; + } + } + + if (term) { + if (to_integer_op) { + goto error_exit; + } else { + break; + } + } else if ((valid_digits == 0) && (this_digit == 0) + && !sign_of0x) { + + /* Skip zeros */ + string++; + continue; + } + + valid_digits++; + + if (sign_of0x + && ((valid_digits > 16) + || ((valid_digits > 8) && mode32))) { + /* + * This is to_integer operation case. + * No any restrictions for string-to-integer conversion, + * see ACPI spec. + */ + goto error_exit; + } + + /* Divide the digit into the correct position */ + + (void)acpi_ut_short_divide((dividend - (u64)this_digit), + base, "ient, NULL); + + if (return_value > quotient) { + if (to_integer_op) { + goto error_exit; + } else { + break; + } + } + + return_value *= base; + return_value += this_digit; + string++; + } + + /* All done, normal exit */ + +all_done: + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", + ACPI_FORMAT_UINT64(return_value))); + + *ret_integer = return_value; + return_ACPI_STATUS(AE_OK); + +error_exit: + /* Base was set/validated above */ + + if (base == 10) { + return_ACPI_STATUS(AE_BAD_DECIMAL_CONSTANT); + } else { + return_ACPI_STATUS(AE_BAD_HEX_CONSTANT); + } +} + +#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) +/******************************************************************************* + * + * FUNCTION: acpi_ut_safe_strcpy, acpi_ut_safe_strcat, acpi_ut_safe_strncat + * + * PARAMETERS: Adds a "DestSize" parameter to each of the standard string + * functions. This is the size of the Destination buffer. + * + * RETURN: TRUE if the operation would overflow the destination buffer. + * + * DESCRIPTION: Safe versions of standard Clib string functions. Ensure that + * the result of the operation will not overflow the output string + * buffer. + * + * NOTE: These functions are typically only helpful for processing + * user input and command lines. For most ACPICA code, the + * required buffer length is precisely calculated before buffer + * allocation, so the use of these functions is unnecessary. + * + ******************************************************************************/ + +u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source) +{ + + if (strlen(source) >= dest_size) { + return (TRUE); + } + + strcpy(dest, source); + return (FALSE); +} + +u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source) +{ + + if ((strlen(dest) + strlen(source)) >= dest_size) { + return (TRUE); + } + + strcat(dest, source); + return (FALSE); +} + +u8 +acpi_ut_safe_strncat(char *dest, + acpi_size dest_size, + char *source, acpi_size max_transfer_length) +{ + acpi_size actual_transfer_length; + + actual_transfer_length = ACPI_MIN(max_transfer_length, strlen(source)); + + if ((strlen(dest) + actual_transfer_length) >= dest_size) { + return (TRUE); + } + + strncat(dest, source, max_transfer_length); + return (FALSE); +} +#endif diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 8f3c883dfe0e..4ddd105d9741 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -48,286 +48,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utstring") -/* - * Non-ANSI C library functions - strlwr, strupr, stricmp, and a 64-bit - * version of strtoul. - */ -#ifdef ACPI_ASL_COMPILER -/******************************************************************************* - * - * FUNCTION: acpi_ut_strlwr (strlwr) - * - * PARAMETERS: src_string - The source string to convert - * - * RETURN: None - * - * DESCRIPTION: Convert string to lowercase - * - * NOTE: This is not a POSIX function, so it appears here, not in utclib.c - * - ******************************************************************************/ -void acpi_ut_strlwr(char *src_string) -{ - char *string; - - ACPI_FUNCTION_ENTRY(); - - if (!src_string) { - return; - } - - /* Walk entire string, lowercasing the letters */ - - for (string = src_string; *string; string++) { - *string = (char)tolower((int)*string); - } - - return; -} - -/****************************************************************************** - * - * FUNCTION: acpi_ut_stricmp (stricmp) - * - * PARAMETERS: string1 - first string to compare - * string2 - second string to compare - * - * RETURN: int that signifies string relationship. Zero means strings - * are equal. - * - * DESCRIPTION: Implementation of the non-ANSI stricmp function (compare - * strings with no case sensitivity) - * - ******************************************************************************/ - -int acpi_ut_stricmp(char *string1, char *string2) -{ - int c1; - int c2; - - do { - c1 = tolower((int)*string1); - c2 = tolower((int)*string2); - - string1++; - string2++; - } - while ((c1 == c2) && (c1)); - - return (c1 - c2); -} -#endif - -/******************************************************************************* - * - * FUNCTION: acpi_ut_strupr (strupr) - * - * PARAMETERS: src_string - The source string to convert - * - * RETURN: None - * - * DESCRIPTION: Convert string to uppercase - * - * NOTE: This is not a POSIX function, so it appears here, not in utclib.c - * - ******************************************************************************/ - -void acpi_ut_strupr(char *src_string) -{ - char *string; - - ACPI_FUNCTION_ENTRY(); - - if (!src_string) { - return; - } - - /* Walk entire string, uppercasing the letters */ - - for (string = src_string; *string; string++) { - *string = (char)toupper((int)*string); - } - - return; -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_strtoul64 - * - * PARAMETERS: string - Null terminated string - * base - Radix of the string: 16 or ACPI_ANY_BASE; - * ACPI_ANY_BASE means 'in behalf of to_integer' - * ret_integer - Where the converted integer is returned - * - * RETURN: Status and Converted value - * - * DESCRIPTION: Convert a string into an unsigned value. Performs either a - * 32-bit or 64-bit conversion, depending on the current mode - * of the interpreter. - * NOTE: Does not support Octal strings, not needed. - * - ******************************************************************************/ - -acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) -{ - u32 this_digit = 0; - u64 return_value = 0; - u64 quotient; - u64 dividend; - u32 to_integer_op = (base == ACPI_ANY_BASE); - u32 mode32 = (acpi_gbl_integer_byte_width == 4); - u8 valid_digits = 0; - u8 sign_of0x = 0; - u8 term = 0; - - ACPI_FUNCTION_TRACE_STR(ut_stroul64, string); - - switch (base) { - case ACPI_ANY_BASE: - case 16: - - break; - - default: - - /* Invalid Base */ - - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (!string) { - goto error_exit; - } - - /* Skip over any white space in the buffer */ - - while ((*string) && (isspace((int)*string) || *string == '\t')) { - string++; - } - - if (to_integer_op) { - /* - * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'. - * We need to determine if it is decimal or hexadecimal. - */ - if ((*string == '0') && (tolower((int)*(string + 1)) == 'x')) { - sign_of0x = 1; - base = 16; - - /* Skip over the leading '0x' */ - string += 2; - } else { - base = 10; - } - } - - /* Any string left? Check that '0x' is not followed by white space. */ - - if (!(*string) || isspace((int)*string) || *string == '\t') { - if (to_integer_op) { - goto error_exit; - } else { - goto all_done; - } - } - - /* - * Perform a 32-bit or 64-bit conversion, depending upon the current - * execution mode of the interpreter - */ - dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX; - - /* Main loop: convert the string to a 32- or 64-bit integer */ - - while (*string) { - if (isdigit((int)*string)) { - - /* Convert ASCII 0-9 to Decimal value */ - - this_digit = ((u8)*string) - '0'; - } else if (base == 10) { - - /* Digit is out of range; possible in to_integer case only */ - - term = 1; - } else { - this_digit = (u8)toupper((int)*string); - if (isxdigit((int)this_digit)) { - - /* Convert ASCII Hex char to value */ - - this_digit = this_digit - 'A' + 10; - } else { - term = 1; - } - } - - if (term) { - if (to_integer_op) { - goto error_exit; - } else { - break; - } - } else if ((valid_digits == 0) && (this_digit == 0) - && !sign_of0x) { - - /* Skip zeros */ - string++; - continue; - } - - valid_digits++; - - if (sign_of0x - && ((valid_digits > 16) - || ((valid_digits > 8) && mode32))) { - /* - * This is to_integer operation case. - * No any restrictions for string-to-integer conversion, - * see ACPI spec. - */ - goto error_exit; - } - - /* Divide the digit into the correct position */ - - (void)acpi_ut_short_divide((dividend - (u64)this_digit), - base, "ient, NULL); - - if (return_value > quotient) { - if (to_integer_op) { - goto error_exit; - } else { - break; - } - } - - return_value *= base; - return_value += this_digit; - string++; - } - - /* All done, normal exit */ - -all_done: - - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64(return_value))); - - *ret_integer = return_value; - return_ACPI_STATUS(AE_OK); - -error_exit: - /* Base was set/validated above */ - - if (base == 10) { - return_ACPI_STATUS(AE_BAD_DECIMAL_CONSTANT); - } else { - return_ACPI_STATUS(AE_BAD_HEX_CONSTANT); - } -} - /******************************************************************************* * * FUNCTION: acpi_ut_print_string @@ -342,7 +62,6 @@ error_exit: * sequences. * ******************************************************************************/ - void acpi_ut_print_string(char *string, u16 max_length) { u32 i; @@ -584,64 +303,3 @@ void ut_convert_backslashes(char *pathname) } } #endif - -#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) -/******************************************************************************* - * - * FUNCTION: acpi_ut_safe_strcpy, acpi_ut_safe_strcat, acpi_ut_safe_strncat - * - * PARAMETERS: Adds a "DestSize" parameter to each of the standard string - * functions. This is the size of the Destination buffer. - * - * RETURN: TRUE if the operation would overflow the destination buffer. - * - * DESCRIPTION: Safe versions of standard Clib string functions. Ensure that - * the result of the operation will not overflow the output string - * buffer. - * - * NOTE: These functions are typically only helpful for processing - * user input and command lines. For most ACPICA code, the - * required buffer length is precisely calculated before buffer - * allocation, so the use of these functions is unnecessary. - * - ******************************************************************************/ - -u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source) -{ - - if (strlen(source) >= dest_size) { - return (TRUE); - } - - strcpy(dest, source); - return (FALSE); -} - -u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source) -{ - - if ((strlen(dest) + strlen(source)) >= dest_size) { - return (TRUE); - } - - strcat(dest, source); - return (FALSE); -} - -u8 -acpi_ut_safe_strncat(char *dest, - acpi_size dest_size, - char *source, acpi_size max_transfer_length) -{ - acpi_size actual_transfer_length; - - actual_transfer_length = ACPI_MIN(max_transfer_length, strlen(source)); - - if ((strlen(dest) + actual_transfer_length) >= dest_size) { - return (TRUE); - } - - strncat(dest, source, max_transfer_length); - return (FALSE); -} -#endif -- cgit v1.3-6-gb490 From 88606a2b9020993a776df894941b3b07cc1374fe Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 23 Jul 2015 12:53:57 +0800 Subject: ACPICA: Cleanup use of NEGATIVE and POSITIVE defines ACPICA commit f88814201e01043a4f8caa69a69b799af11c44a3 These were defined in two places. Changed to ACPI_SIGN* names and define them once in acmacros.h This patch doesn't affect Linux kernel. Link: https://github.com/acpica/acpica/commit/f8881420 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acmacros.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index 19d40c6c1f32..e85366ceb15a 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -224,6 +224,11 @@ #define ACPI_IS_ASCII(c) ((c) < 0x80) +/* Signed integers */ + +#define ACPI_SIGN_POSITIVE 0 +#define ACPI_SIGN_NEGATIVE 1 + /* * Rounding macros (Power of two boundaries only) */ -- cgit v1.3-6-gb490 From 02ca26bef8f49a654026f56bedde2ab25e761380 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:54:11 +0800 Subject: ACPICA: Debugger: Reduce structure size for debugger ACPICA commit 310e0ae1c4730f4dadc80125125099ab76851499 arg_types in struct acpi_db_method_info is only referenced by ACPI_DEBUGGER. This patch only affects ACPICA debugger which is only used by a non-kernel tool - acpiexec, so Linux kernel is currently not affected by this patch. Link: https://github.com/acpica/acpica/commit/310e0ae1 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 4758185b2b0b..a6b68878cdbe 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -1107,6 +1107,9 @@ struct acpi_db_method_info { * Index of current thread inside all them created. */ char init_args; +#ifdef ACPI_DEBUGGER + acpi_object_type arg_types[4]; +#endif char *arguments[4]; char num_threads_str[11]; char id_of_thread_str[11]; -- cgit v1.3-6-gb490 From fdd8d831cf43761712d28e5d1ad812eab7dc1480 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:54:17 +0800 Subject: ACPICA: Debugger: Move debugger specific APIs to debugger component ACPICA commit 2164923d60429eea7cd5a4a8629b607af7325afa Some disassembler APIs should rather be debugger APIs. This patch moves them to the debugger folder to be ready for debugger porting. Since there is no in-kernel ACPICA debugger in the kernel source tree, this patch doesn't affect the Linux kernel. Link: https://github.com/acpica/acpica/commit/2164923d Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acdebug.h | 17 +++++++++++++++++ drivers/acpi/acpica/dsmethod.c | 12 +++++------- 2 files changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 88482f75e941..b5a9c5126209 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -263,6 +263,23 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op); char *acpi_db_get_next_token(char *string, char **next, acpi_object_type * return_type); +/* + * dbobject + */ +void acpi_db_decode_internal_object(union acpi_operand_object *obj_desc); + +void +acpi_db_display_internal_object(union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state); + +void acpi_db_decode_arguments(struct acpi_walk_state *walk_state); + +void acpi_db_decode_locals(struct acpi_walk_state *walk_state); + +void +acpi_db_dump_method_info(acpi_status status, + struct acpi_walk_state *walk_state); + /* * dbstats - Generation and display of ACPI table statistics */ diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index cb53c44c9644..bc32f3194afe 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -46,11 +46,9 @@ #include "acdispat.h" #include "acinterp.h" #include "acnamesp.h" -#ifdef ACPI_DISASSEMBLER -#include "acdisasm.h" -#endif #include "acparser.h" #include "amlcode.h" +#include "acdebug.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsmethod") @@ -205,7 +203,7 @@ acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, * RETURN: Status * * DESCRIPTION: Called on method error. Invoke the global exception handler if - * present, dump the method data if the disassembler is configured + * present, dump the method data if the debugger is configured * * Note: Allows the exception handler to change the status code * @@ -254,10 +252,10 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state) if (ACPI_FAILURE(status)) { acpi_ds_dump_method_stack(status, walk_state, walk_state->op); - /* Display method locals/args if disassembler is present */ + /* Display method locals/args if debugger is present */ -#ifdef ACPI_DISASSEMBLER - acpi_dm_dump_method_info(status, walk_state); +#ifdef ACPI_DEBUGGER + acpi_db_dump_method_info(status, walk_state); #endif } -- cgit v1.3-6-gb490 From 6d9be0a5c459ac30a5b3e7fbe51c55f65a5f4c7c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 23 Jul 2015 12:54:23 +0800 Subject: ACPICA: iASL/Disassembler: Add prototype verbose mode ACPICA commit add72dca18ab5d02f1bf9b08027570e58da520e8 This mode will emit AML byte code after each ASL statement. This is a prototype only and requires additional development. This patch only affects ACPICA disassembler which is not in the kernel source tree. Link: https://github.com/acpica/acpica/commit/add72dca Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 5342300719ee..79eb35d080a0 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -307,6 +307,7 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_cstyle_disassembly, TRUE); ACPI_INIT_GLOBAL(u8, acpi_gbl_force_aml_disassembly, FALSE); +ACPI_INIT_GLOBAL(union acpi_parse_object *, acpi_gbl_previous_op, NULL); ACPI_GLOBAL(u8, acpi_gbl_db_opt_disasm); ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose); -- cgit v1.3-6-gb490 From 02b0b79c30076aaa33ee9134546130eb62b88078 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 17 Jul 2015 14:59:18 -0700 Subject: Input: pmic8xxx-pwrkey - support shutdown On pm8xxx PMICs, shutdown and restart are signaled to the PMIC via a pin called PS_HOLD. When this pin goes low, the PMIC performs a configurable power sequence. Add a .shutdown hook so that we can properly configure this power sequence for shutdown or restart depending on the system state. Signed-off-by: Stephen Boyd Reviewed-by: Bjorn Andersson Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pmic8xxx-pwrkey.c | 268 ++++++++++++++++++++++++++++++++++- 1 file changed, 266 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index c4ca20e63221..3f02e0e03d12 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -20,17 +20,72 @@ #include #include #include +#include #define PON_CNTL_1 0x1C #define PON_CNTL_PULL_UP BIT(7) #define PON_CNTL_TRIG_DELAY_MASK (0x7) +#define PON_CNTL_1_PULL_UP_EN 0xe0 +#define PON_CNTL_1_USB_PWR_EN 0x10 +#define PON_CNTL_1_WD_EN_RESET 0x08 + +#define PM8058_SLEEP_CTRL 0x02b +#define PM8921_SLEEP_CTRL 0x10a + +#define SLEEP_CTRL_SMPL_EN_RESET 0x04 + +/* Regulator master enable addresses */ +#define REG_PM8058_VREG_EN_MSM 0x018 +#define REG_PM8058_VREG_EN_GRP_5_4 0x1c8 + +/* Regulator control registers for shutdown/reset */ +#define PM8058_S0_CTRL 0x004 +#define PM8058_S1_CTRL 0x005 +#define PM8058_S3_CTRL 0x111 +#define PM8058_L21_CTRL 0x120 +#define PM8058_L22_CTRL 0x121 + +#define PM8058_REGULATOR_ENABLE_MASK 0x80 +#define PM8058_REGULATOR_ENABLE 0x80 +#define PM8058_REGULATOR_DISABLE 0x00 +#define PM8058_REGULATOR_PULL_DOWN_MASK 0x40 +#define PM8058_REGULATOR_PULL_DOWN_EN 0x40 + +/* Buck CTRL register */ +#define PM8058_SMPS_LEGACY_VREF_SEL 0x20 +#define PM8058_SMPS_LEGACY_VPROG_MASK 0x1f +#define PM8058_SMPS_ADVANCED_BAND_MASK 0xC0 +#define PM8058_SMPS_ADVANCED_BAND_SHIFT 6 +#define PM8058_SMPS_ADVANCED_VPROG_MASK 0x3f + +/* Buck TEST2 registers for shutdown/reset */ +#define PM8058_S0_TEST2 0x084 +#define PM8058_S1_TEST2 0x085 +#define PM8058_S3_TEST2 0x11a + +#define PM8058_REGULATOR_BANK_WRITE 0x80 +#define PM8058_REGULATOR_BANK_MASK 0x70 +#define PM8058_REGULATOR_BANK_SHIFT 4 +#define PM8058_REGULATOR_BANK_SEL(n) ((n) << PM8058_REGULATOR_BANK_SHIFT) + +/* Buck TEST2 register bank 1 */ +#define PM8058_SMPS_LEGACY_VLOW_SEL 0x01 + +/* Buck TEST2 register bank 7 */ +#define PM8058_SMPS_ADVANCED_MODE_MASK 0x02 +#define PM8058_SMPS_ADVANCED_MODE 0x02 +#define PM8058_SMPS_LEGACY_MODE 0x00 /** * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information * @key_press_irq: key press irq number + * @regmap: device regmap + * @shutdown_fn: shutdown configuration function */ struct pmic8xxx_pwrkey { int key_press_irq; + struct regmap *regmap; + int (*shutdown_fn)(struct pmic8xxx_pwrkey *, bool); }; static irqreturn_t pwrkey_press_irq(int irq, void *_pwr) @@ -76,6 +131,212 @@ static int __maybe_unused pmic8xxx_pwrkey_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops, pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume); +static void pmic8xxx_pwrkey_shutdown(struct platform_device *pdev) +{ + struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev); + int error; + u8 mask, val; + bool reset = system_state == SYSTEM_RESTART; + + if (pwrkey->shutdown_fn) { + error = pwrkey->shutdown_fn(pwrkey, reset); + if (error) + return; + } + + /* + * Select action to perform (reset or shutdown) when PS_HOLD goes low. + * Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that + * USB charging is enabled. + */ + mask = PON_CNTL_1_PULL_UP_EN | PON_CNTL_1_USB_PWR_EN; + mask |= PON_CNTL_1_WD_EN_RESET; + val = mask; + if (!reset) + val &= ~PON_CNTL_1_WD_EN_RESET; + + regmap_update_bits(pwrkey->regmap, PON_CNTL_1, mask, val); +} + +/* + * Set an SMPS regulator to be disabled in its CTRL register, but enabled + * in the master enable register. Also set it's pull down enable bit. + * Take care to make sure that the output voltage doesn't change if switching + * from advanced mode to legacy mode. + */ +static int pm8058_disable_smps_locally_set_pull_down(struct regmap *regmap, + u16 ctrl_addr, u16 test2_addr, u16 master_enable_addr, + u8 master_enable_bit) +{ + int error; + u8 vref_sel, vlow_sel, band, vprog, bank; + unsigned int reg; + + bank = PM8058_REGULATOR_BANK_SEL(7); + error = regmap_write(regmap, test2_addr, bank); + if (error) + return error; + + error = regmap_read(regmap, test2_addr, ®); + if (error) + return error; + + reg &= PM8058_SMPS_ADVANCED_MODE_MASK; + /* Check if in advanced mode. */ + if (reg == PM8058_SMPS_ADVANCED_MODE) { + /* Determine current output voltage. */ + error = regmap_read(regmap, ctrl_addr, ®); + if (error) + return error; + + band = reg & PM8058_SMPS_ADVANCED_BAND_MASK; + band >>= PM8058_SMPS_ADVANCED_BAND_SHIFT; + switch (band) { + case 3: + vref_sel = 0; + vlow_sel = 0; + break; + case 2: + vref_sel = PM8058_SMPS_LEGACY_VREF_SEL; + vlow_sel = 0; + break; + case 1: + vref_sel = PM8058_SMPS_LEGACY_VREF_SEL; + vlow_sel = PM8058_SMPS_LEGACY_VLOW_SEL; + break; + default: + pr_err("%s: regulator already disabled\n", __func__); + return -EPERM; + } + vprog = reg & PM8058_SMPS_ADVANCED_VPROG_MASK; + /* Round up if fine step is in use. */ + vprog = (vprog + 1) >> 1; + if (vprog > PM8058_SMPS_LEGACY_VPROG_MASK) + vprog = PM8058_SMPS_LEGACY_VPROG_MASK; + + /* Set VLOW_SEL bit. */ + bank = PM8058_REGULATOR_BANK_SEL(1); + error = regmap_write(regmap, test2_addr, bank); + if (error) + return error; + + error = regmap_update_bits(regmap, test2_addr, + PM8058_REGULATOR_BANK_WRITE | PM8058_REGULATOR_BANK_MASK + | PM8058_SMPS_LEGACY_VLOW_SEL, + PM8058_REGULATOR_BANK_WRITE | + PM8058_REGULATOR_BANK_SEL(1) | vlow_sel); + if (error) + return error; + + /* Switch to legacy mode */ + bank = PM8058_REGULATOR_BANK_SEL(7); + error = regmap_write(regmap, test2_addr, bank); + if (error) + return error; + + error = regmap_update_bits(regmap, test2_addr, + PM8058_REGULATOR_BANK_WRITE | + PM8058_REGULATOR_BANK_MASK | + PM8058_SMPS_ADVANCED_MODE_MASK, + PM8058_REGULATOR_BANK_WRITE | + PM8058_REGULATOR_BANK_SEL(7) | + PM8058_SMPS_LEGACY_MODE); + if (error) + return error; + + /* Enable locally, enable pull down, keep voltage the same. */ + error = regmap_update_bits(regmap, ctrl_addr, + PM8058_REGULATOR_ENABLE_MASK | + PM8058_REGULATOR_PULL_DOWN_MASK | + PM8058_SMPS_LEGACY_VREF_SEL | + PM8058_SMPS_LEGACY_VPROG_MASK, + PM8058_REGULATOR_ENABLE | PM8058_REGULATOR_PULL_DOWN_EN + | vref_sel | vprog); + if (error) + return error; + } + + /* Enable in master control register. */ + error = regmap_update_bits(regmap, master_enable_addr, + master_enable_bit, master_enable_bit); + if (error) + return error; + + /* Disable locally and enable pull down. */ + return regmap_update_bits(regmap, ctrl_addr, + PM8058_REGULATOR_ENABLE_MASK | PM8058_REGULATOR_PULL_DOWN_MASK, + PM8058_REGULATOR_DISABLE | PM8058_REGULATOR_PULL_DOWN_EN); +} + +static int pm8058_disable_ldo_locally_set_pull_down(struct regmap *regmap, + u16 ctrl_addr, u16 master_enable_addr, u8 master_enable_bit) +{ + int error; + + /* Enable LDO in master control register. */ + error = regmap_update_bits(regmap, master_enable_addr, + master_enable_bit, master_enable_bit); + if (error) + return error; + + /* Disable LDO in CTRL register and set pull down */ + return regmap_update_bits(regmap, ctrl_addr, + PM8058_REGULATOR_ENABLE_MASK | PM8058_REGULATOR_PULL_DOWN_MASK, + PM8058_REGULATOR_DISABLE | PM8058_REGULATOR_PULL_DOWN_EN); +} + +static int pm8058_pwrkey_shutdown(struct pmic8xxx_pwrkey *pwrkey, bool reset) +{ + int error; + struct regmap *regmap = pwrkey->regmap; + u8 mask, val; + + /* When shutting down, enable active pulldowns on important rails. */ + if (!reset) { + /* Disable SMPS's 0,1,3 locally and set pulldown enable bits. */ + pm8058_disable_smps_locally_set_pull_down(regmap, + PM8058_S0_CTRL, PM8058_S0_TEST2, + REG_PM8058_VREG_EN_MSM, BIT(7)); + pm8058_disable_smps_locally_set_pull_down(regmap, + PM8058_S1_CTRL, PM8058_S1_TEST2, + REG_PM8058_VREG_EN_MSM, BIT(6)); + pm8058_disable_smps_locally_set_pull_down(regmap, + PM8058_S3_CTRL, PM8058_S3_TEST2, + REG_PM8058_VREG_EN_GRP_5_4, BIT(7) | BIT(4)); + /* Disable LDO 21 locally and set pulldown enable bit. */ + pm8058_disable_ldo_locally_set_pull_down(regmap, + PM8058_L21_CTRL, REG_PM8058_VREG_EN_GRP_5_4, + BIT(1)); + } + + /* + * Fix-up: Set regulator LDO22 to 1.225 V in high power mode. Leave its + * pull-down state intact. This ensures a safe shutdown. + */ + error = regmap_update_bits(regmap, PM8058_L22_CTRL, 0xbf, 0x93); + if (error) + return error; + + /* Enable SMPL if resetting is desired */ + mask = SLEEP_CTRL_SMPL_EN_RESET; + val = 0; + if (reset) + val = mask; + return regmap_update_bits(regmap, PM8058_SLEEP_CTRL, mask, val); +} + +static int pm8921_pwrkey_shutdown(struct pmic8xxx_pwrkey *pwrkey, bool reset) +{ + struct regmap *regmap = pwrkey->regmap; + u8 mask = SLEEP_CTRL_SMPL_EN_RESET; + u8 val = 0; + + /* Enable SMPL if resetting is desired */ + if (reset) + val = mask; + return regmap_update_bits(regmap, PM8921_SLEEP_CTRL, mask, val); +} + static int pmic8xxx_pwrkey_probe(struct platform_device *pdev) { struct input_dev *pwr; @@ -109,6 +370,8 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev) if (!pwrkey) return -ENOMEM; + pwrkey->shutdown_fn = of_device_get_match_data(&pdev->dev); + pwrkey->regmap = regmap; pwrkey->key_press_irq = key_press_irq; pwr = devm_input_allocate_device(&pdev->dev); @@ -182,8 +445,8 @@ static int pmic8xxx_pwrkey_remove(struct platform_device *pdev) } static const struct of_device_id pm8xxx_pwr_key_id_table[] = { - { .compatible = "qcom,pm8058-pwrkey" }, - { .compatible = "qcom,pm8921-pwrkey" }, + { .compatible = "qcom,pm8058-pwrkey", .data = &pm8058_pwrkey_shutdown }, + { .compatible = "qcom,pm8921-pwrkey", .data = &pm8921_pwrkey_shutdown }, { } }; MODULE_DEVICE_TABLE(of, pm8xxx_pwr_key_id_table); @@ -191,6 +454,7 @@ MODULE_DEVICE_TABLE(of, pm8xxx_pwr_key_id_table); static struct platform_driver pmic8xxx_pwrkey_driver = { .probe = pmic8xxx_pwrkey_probe, .remove = pmic8xxx_pwrkey_remove, + .shutdown = pmic8xxx_pwrkey_shutdown, .driver = { .name = "pm8xxx-pwrkey", .pm = &pm8xxx_pwr_key_pm_ops, -- cgit v1.3-6-gb490 From aeda5003d0b987085acef6ad4844f8e34851bb10 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 16 Jul 2015 11:54:14 -0700 Subject: Input: matrix_keypad - change name of wakeup property to "wakeup-source" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Cc: Lothar Waßmann Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt | 2 +- drivers/input/keyboard/matrix_keypad.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt index ead641c65e0a..4d86059c370c 100644 --- a/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt +++ b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt @@ -19,7 +19,7 @@ Required Properties: Optional Properties: - linux,no-autorepeat: do no enable autorepeat feature. -- linux,wakeup: use any event on keypad as wakeup event. +- wakeup-source: use any event on keypad as wakeup event. - debounce-delay-ms: debounce interval in milliseconds - col-scan-delay-us: delay, measured in microseconds, that is needed before we can scan keypad after activating column gpio diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index b370a59cb759..7f12b6579f82 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -425,8 +425,10 @@ matrix_keypad_parse_dt(struct device *dev) if (of_get_property(np, "linux,no-autorepeat", NULL)) pdata->no_autorepeat = true; - if (of_get_property(np, "linux,wakeup", NULL)) - pdata->wakeup = true; + + pdata->wakeup = of_property_read_bool(np, "wakeup-source") || + of_property_read_bool(np, "linux,wakeup"); /* legacy */ + if (of_get_property(np, "gpio-activelow", NULL)) pdata->active_low = true; -- cgit v1.3-6-gb490 From abf77a32288d4379dfede0b50be6a04be3cd1431 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 16 Jul 2015 12:03:39 -0700 Subject: Input: ads7846 - change name of wakeup property to "wakeup-source" Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/ads7846.txt | 2 +- drivers/input/touchscreen/ads7846.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/ads7846.txt b/Documentation/devicetree/bindings/input/ads7846.txt index 5f7619c22743..df8b1279491d 100644 --- a/Documentation/devicetree/bindings/input/ads7846.txt +++ b/Documentation/devicetree/bindings/input/ads7846.txt @@ -64,7 +64,7 @@ Optional properties: pendown-gpio (u32). pendown-gpio GPIO handle describing the pin the !PENIRQ line is connected to. - linux,wakeup use any event on touchscreen as wakeup event. + wakeup-source use any event on touchscreen as wakeup event. Example for a TSC2046 chip connected to an McSPI controller of an OMAP SoC:: diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index e4eb8a6c658f..0f5f968592bd 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -1234,7 +1234,8 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev) of_property_read_u32(node, "ti,pendown-gpio-debounce", &pdata->gpio_pendown_debounce); - pdata->wakeup = of_property_read_bool(node, "linux,wakeup"); + pdata->wakeup = of_property_read_bool(node, "wakeup-source") || + of_property_read_bool(node, "linux,wakeup"); pdata->gpio_pendown = of_get_named_gpio(dev->of_node, "pendown-gpio", 0); -- cgit v1.3-6-gb490 From 274696521254855ba03f2d4f4575ae048a409256 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 16 Jul 2015 12:15:24 -0700 Subject: Input: pmic8xxx-keypad - change name of wakeup property Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Acked-by: Stephen Boyd Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt | 2 +- drivers/input/keyboard/pmic8xxx-keypad.c | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt b/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt index 7d8cb92831d7..ee6215681182 100644 --- a/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt +++ b/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt @@ -33,7 +33,7 @@ PROPERTIES Value type: Definition: don't enable autorepeat feature. -- linux,keypad-wakeup: +- wakeup-source: Usage: optional Value type: Definition: use any event on keypad as wakeup event. diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 32580afecc26..5c68e3f096bc 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -507,6 +507,7 @@ static void pmic8xxx_kp_close(struct input_dev *dev) */ static int pmic8xxx_kp_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; unsigned int rows, cols; bool repeat; bool wakeup; @@ -524,10 +525,11 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev) return -EINVAL; } - repeat = !of_property_read_bool(pdev->dev.of_node, - "linux,input-no-autorepeat"); - wakeup = of_property_read_bool(pdev->dev.of_node, - "linux,keypad-wakeup"); + repeat = !of_property_read_bool(np, "linux,input-no-autorepeat"); + + wakeup = of_property_read_bool(np, "wakeup-source") || + /* legacy name */ + of_property_read_bool(np, "linux,keypad-wakeup"); kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); if (!kp) -- cgit v1.3-6-gb490 From 99b4ffbd84ea4191e0b8d1709230656a1c33b848 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 16 Jul 2015 12:10:05 -0700 Subject: Input: gpio_keys[_polled] - change name of wakeup property Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Reviewed-by: Linus Walleij Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/gpio-keys-polled.txt | 2 +- Documentation/devicetree/bindings/input/gpio-keys.txt | 2 +- drivers/input/keyboard/gpio_keys.c | 4 +++- drivers/input/keyboard/gpio_keys_polled.c | 5 ++++- 4 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt index 313abefa37cc..5b91f5a3bd5c 100644 --- a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt +++ b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt @@ -20,7 +20,7 @@ Optional subnode-properties: If not specified defaults to <1> == EV_KEY. - debounce-interval: Debouncing interval time in milliseconds. If not specified defaults to 5. - - gpio-key,wakeup: Boolean, button can wake-up the system. + - wakeup-source: Boolean, button can wake-up the system. Example nodes: diff --git a/Documentation/devicetree/bindings/input/gpio-keys.txt b/Documentation/devicetree/bindings/input/gpio-keys.txt index 44b705767aca..072bf7573c37 100644 --- a/Documentation/devicetree/bindings/input/gpio-keys.txt +++ b/Documentation/devicetree/bindings/input/gpio-keys.txt @@ -23,7 +23,7 @@ Optional subnode-properties: If not specified defaults to <1> == EV_KEY. - debounce-interval: Debouncing interval time in milliseconds. If not specified defaults to 5. - - gpio-key,wakeup: Boolean, button can wake-up the system. + - wakeup-source: Boolean, button can wake-up the system. - linux,can-disable: Boolean, indicates that button is connected to dedicated (not shared) interrupt which can be disabled to suppress events from the button. diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index ddf4045de084..1df4507c4c0b 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -655,7 +655,9 @@ gpio_keys_get_devtree_pdata(struct device *dev) if (of_property_read_u32(pp, "linux,input-type", &button->type)) button->type = EV_KEY; - button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); + button->wakeup = of_property_read_bool(pp, "wakeup-source") || + /* legacy name */ + of_property_read_bool(pp, "gpio-key,wakeup"); button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL); diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 097d7216d98e..5a0c99950659 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -152,7 +152,10 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct &button->type)) button->type = EV_KEY; - button->wakeup = fwnode_property_present(child, "gpio-key,wakeup"); + button->wakeup = + fwnode_property_read_bool(child, "wakeup-source") || + /* legacy name */ + fwnode_property_read_bool(child, "gpio-key,wakeup"); if (fwnode_property_read_u32(child, "debounce-interval", &button->debounce_interval)) -- cgit v1.3-6-gb490 From 75406b3b17ee5a107b361b4065ad83fe42fff5a8 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Sat, 6 Jun 2015 06:05:24 +0530 Subject: tty: Convert use of __constant_htons to htons In little endian cases, macro htons unfolds to __swab16 which provides special case for constants. In big endian cases, __constant_htons and htons expand directly to the same expression. So, replace __constant_htons with htons with the goal of getting rid of the definition of __constant_htons completely. The semantic patch that performs this transformation is as follows: @@expression x;@@ - __constant_htons(x) + htons(x) Signed-off-by: Vaishali Thakkar Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 382d3fcba6cc..c3fe026d3168 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2712,7 +2712,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, memcpy(skb_put(skb, size), in_buf, size); skb->dev = net; - skb->protocol = __constant_htons(ETH_P_IP); + skb->protocol = htons(ETH_P_IP); /* Ship it off to the kernel */ netif_rx(skb); -- cgit v1.3-6-gb490 From 92a5f11a1a3357964c30c34d55dc55152315b81b Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 16 Jun 2015 10:59:36 +0200 Subject: serial/8250_fintek: Use private data structure Save the port index and the line id in a private structure. Reported-by: Peter Hong Reviewed-by: Alan Cox Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_fintek.c | 48 ++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 5815e81b5fc6..76d739bb5d1f 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -39,6 +39,11 @@ #define DRIVER_NAME "8250_fintek" +struct fintek_8250 { + u8 index; + long line; +}; + static int fintek_8250_enter_key(void){ if (!request_muxed_region(ADDR_PORT, 2, DRIVER_NAME)) @@ -93,9 +98,9 @@ static int fintek_8250_rs485_config(struct uart_port *port, struct serial_rs485 *rs485) { uint8_t config = 0; - int index = fintek_8250_get_index(port->iobase); + struct fintek_8250 *pdata = port->private_data; - if (index < 0) + if (!pdata) return -EINVAL; if (rs485->flags & SER_RS485_ENABLED) @@ -129,7 +134,7 @@ static int fintek_8250_rs485_config(struct uart_port *port, return -EBUSY; outb(LDN, ADDR_PORT); - outb(index, DATA_PORT); + outb(pdata->index, DATA_PORT); outb(RS485, ADDR_PORT); outb(config, DATA_PORT); fintek_8250_exit_key(); @@ -142,14 +147,16 @@ static int fintek_8250_rs485_config(struct uart_port *port, static int fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { - int line; struct uart_8250_port uart; + struct fintek_8250 *pdata; int ret; + int index; if (!pnp_port_valid(dev, 0)) return -ENODEV; - if (fintek_8250_get_index(pnp_port_start(dev, 0)) < 0) + index = fintek_8250_get_index(pnp_port_start(dev, 0)); + if (index < 0) return -ENODEV; /* Enable configuration registers*/ @@ -163,6 +170,12 @@ fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) return ret; memset(&uart, 0, sizeof(uart)); + + pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + uart.port.private_data = pdata; + if (!pnp_irq_valid(dev, 0)) return -ENODEV; uart.port.irq = pnp_irq(dev, 0); @@ -176,40 +189,41 @@ fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) uart.port.uartclk = 1843200; uart.port.dev = &dev->dev; - line = serial8250_register_8250_port(&uart); - if (line < 0) + pdata->index = index; + pdata->line = serial8250_register_8250_port(&uart); + if (pdata->line < 0) return -ENODEV; - pnp_set_drvdata(dev, (void *)((long)line + 1)); + pnp_set_drvdata(dev, pdata); return 0; } static void fintek_8250_remove(struct pnp_dev *dev) { - long line = (long)pnp_get_drvdata(dev); + struct fintek_8250 *pdata = pnp_get_drvdata(dev); - if (line) - serial8250_unregister_port(line - 1); + if (pdata) + serial8250_unregister_port(pdata->line); } #ifdef CONFIG_PM static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state) { - long line = (long)pnp_get_drvdata(dev); + struct fintek_8250 *pdata = pnp_get_drvdata(dev); - if (!line) + if (!pdata) return -ENODEV; - serial8250_suspend_port(line - 1); + serial8250_suspend_port(pdata->line); return 0; } static int fintek_8250_resume(struct pnp_dev *dev) { - long line = (long)pnp_get_drvdata(dev); + struct fintek_8250 *pdata = pnp_get_drvdata(dev); - if (!line) + if (!pdata) return -ENODEV; - serial8250_resume_port(line - 1); + serial8250_resume_port(pdata->line); return 0; } #else -- cgit v1.3-6-gb490 From 017bec38c08fc954fb788fe69cf9e55f0d4910e7 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 16 Jun 2015 10:59:37 +0200 Subject: serial/8250_fintek: Support for multiple base_ports Fintek chip can be connected at address 0x4e and also 0x2e. Add some logic to find out the address of the chip. Reported-by: Peter Hong Reviewed-by: Alan Cox Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_fintek.c | 87 +++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 76d739bb5d1f..82b055b5a26d 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -17,8 +17,8 @@ #include #include "8250.h" -#define ADDR_PORT 0x4E -#define DATA_PORT 0x4F +#define ADDR_PORT 0 +#define DATA_PORT 1 #define ENTRY_KEY 0x77 #define EXIT_KEY 0xAA #define CHIP_ID1 0x20 @@ -40,24 +40,27 @@ #define DRIVER_NAME "8250_fintek" struct fintek_8250 { + u16 base_port; u8 index; long line; }; -static int fintek_8250_enter_key(void){ +static int fintek_8250_enter_key(u16 base_port) +{ - if (!request_muxed_region(ADDR_PORT, 2, DRIVER_NAME)) + if (!request_muxed_region(base_port, 2, DRIVER_NAME)) return -EBUSY; - outb(ENTRY_KEY, ADDR_PORT); - outb(ENTRY_KEY, ADDR_PORT); + outb(ENTRY_KEY, base_port + ADDR_PORT); + outb(ENTRY_KEY, base_port + ADDR_PORT); return 0; } -static void fintek_8250_exit_key(void){ +static void fintek_8250_exit_key(u16 base_port) +{ - outb(EXIT_KEY, ADDR_PORT); - release_region(ADDR_PORT, 2); + outb(EXIT_KEY, base_port + ADDR_PORT); + release_region(base_port + ADDR_PORT, 2); } static int fintek_8250_get_index(resource_size_t base_addr) @@ -72,23 +75,23 @@ static int fintek_8250_get_index(resource_size_t base_addr) return -ENODEV; } -static int fintek_8250_check_id(void) +static int fintek_8250_check_id(u16 base_port) { - outb(CHIP_ID1, ADDR_PORT); - if (inb(DATA_PORT) != CHIP_ID1_VAL) + outb(CHIP_ID1, base_port + ADDR_PORT); + if (inb(base_port + DATA_PORT) != CHIP_ID1_VAL) return -ENODEV; - outb(CHIP_ID2, ADDR_PORT); - if (inb(DATA_PORT) != CHIP_ID2_VAL) + outb(CHIP_ID2, base_port + ADDR_PORT); + if (inb(base_port + DATA_PORT) != CHIP_ID2_VAL) return -ENODEV; - outb(VENDOR_ID1, ADDR_PORT); - if (inb(DATA_PORT) != VENDOR_ID1_VAL) + outb(VENDOR_ID1, base_port + ADDR_PORT); + if (inb(base_port + DATA_PORT) != VENDOR_ID1_VAL) return -ENODEV; - outb(VENDOR_ID2, ADDR_PORT); - if (inb(DATA_PORT) != VENDOR_ID2_VAL) + outb(VENDOR_ID2, base_port + ADDR_PORT); + if (inb(base_port + DATA_PORT) != VENDOR_ID2_VAL) return -ENODEV; return 0; @@ -130,45 +133,58 @@ static int fintek_8250_rs485_config(struct uart_port *port, if (rs485->flags & SER_RS485_RTS_ON_SEND) config |= RTS_INVERT; - if (fintek_8250_enter_key()) + if (fintek_8250_enter_key(pdata->base_port)) return -EBUSY; - outb(LDN, ADDR_PORT); - outb(pdata->index, DATA_PORT); - outb(RS485, ADDR_PORT); - outb(config, DATA_PORT); - fintek_8250_exit_key(); + outb(LDN, pdata->base_port + ADDR_PORT); + outb(pdata->index, pdata->base_port + DATA_PORT); + outb(RS485, pdata->base_port + ADDR_PORT); + outb(config, pdata->base_port + DATA_PORT); + fintek_8250_exit_key(pdata->base_port); port->rs485 = *rs485; return 0; } +static int fintek_8250_base_port(void) +{ + static const u16 addr[] = {0x4e, 0x2e}; + int i; + + for (i = 0; i < ARRAY_SIZE(addr); i++) { + int ret; + + if (fintek_8250_enter_key(addr[i])) + continue; + ret = fintek_8250_check_id(addr[i]); + fintek_8250_exit_key(addr[i]); + if (!ret) + return addr[i]; + } + + return -ENODEV; +} + static int fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { struct uart_8250_port uart; struct fintek_8250 *pdata; - int ret; int index; + int base_port; if (!pnp_port_valid(dev, 0)) return -ENODEV; + base_port = fintek_8250_base_port(); + if (base_port < 0) + return -ENODEV; + index = fintek_8250_get_index(pnp_port_start(dev, 0)); if (index < 0) return -ENODEV; - /* Enable configuration registers*/ - if (fintek_8250_enter_key()) - return -EBUSY; - - /*Check ID*/ - ret = fintek_8250_check_id(); - fintek_8250_exit_key(); - if (ret) - return ret; - memset(&uart, 0, sizeof(uart)); pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); @@ -189,6 +205,7 @@ fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) uart.port.uartclk = 1843200; uart.port.dev = &dev->dev; + pdata->base_port = base_port; pdata->index = index; pdata->line = serial8250_register_8250_port(&uart); if (pdata->line < 0) -- cgit v1.3-6-gb490 From dae77f757950c273500cc72262a094f290578bef Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 16 Jun 2015 10:59:38 +0200 Subject: serial/8250_fintek: Support for chip_ip 0x0501 There are some chips with the same interface but different chip ip. Reported-by: Peter Hong Reviewed-by: Alan Cox Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_fintek.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 82b055b5a26d..2c3228e84a2e 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -22,9 +22,9 @@ #define ENTRY_KEY 0x77 #define EXIT_KEY 0xAA #define CHIP_ID1 0x20 -#define CHIP_ID1_VAL 0x02 #define CHIP_ID2 0x21 -#define CHIP_ID2_VAL 0x16 +#define CHIP_ID_0 0x1602 +#define CHIP_ID_1 0x0501 #define VENDOR_ID1 0x23 #define VENDOR_ID1_VAL 0x19 #define VENDOR_ID2 0x24 @@ -77,14 +77,7 @@ static int fintek_8250_get_index(resource_size_t base_addr) static int fintek_8250_check_id(u16 base_port) { - - outb(CHIP_ID1, base_port + ADDR_PORT); - if (inb(base_port + DATA_PORT) != CHIP_ID1_VAL) - return -ENODEV; - - outb(CHIP_ID2, base_port + ADDR_PORT); - if (inb(base_port + DATA_PORT) != CHIP_ID2_VAL) - return -ENODEV; + u16 chip; outb(VENDOR_ID1, base_port + ADDR_PORT); if (inb(base_port + DATA_PORT) != VENDOR_ID1_VAL) @@ -94,6 +87,14 @@ static int fintek_8250_check_id(u16 base_port) if (inb(base_port + DATA_PORT) != VENDOR_ID2_VAL) return -ENODEV; + outb(CHIP_ID1, base_port + ADDR_PORT); + chip = inb(base_port + DATA_PORT); + outb(CHIP_ID2, base_port + ADDR_PORT); + chip |= inb(base_port + DATA_PORT) << 8; + + if (chip != CHIP_ID_0 && chip != CHIP_ID_1) + return -ENODEV; + return 0; } -- cgit v1.3-6-gb490 From ce8c267e2ef9180d21f6915f21874898c2ac0ffb Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 16 Jun 2015 10:59:39 +0200 Subject: serial/8250_fintek: Support keys different than default Chip can be configured to use entry key different than 0x77. Try all the valid keys until one gives out the right chip id. Reported-by: Peter Hong Reviewed-by: Alan Cox Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_fintek.c | 39 +++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 2c3228e84a2e..5b916857671b 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -19,7 +19,6 @@ #define ADDR_PORT 0 #define DATA_PORT 1 -#define ENTRY_KEY 0x77 #define EXIT_KEY 0xAA #define CHIP_ID1 0x20 #define CHIP_ID2 0x21 @@ -42,17 +41,18 @@ struct fintek_8250 { u16 base_port; u8 index; + u8 key; long line; }; -static int fintek_8250_enter_key(u16 base_port) +static int fintek_8250_enter_key(u16 base_port, u8 key) { if (!request_muxed_region(base_port, 2, DRIVER_NAME)) return -EBUSY; - outb(ENTRY_KEY, base_port + ADDR_PORT); - outb(ENTRY_KEY, base_port + ADDR_PORT); + outb(key, base_port + ADDR_PORT); + outb(key, base_port + ADDR_PORT); return 0; } @@ -134,7 +134,7 @@ static int fintek_8250_rs485_config(struct uart_port *port, if (rs485->flags & SER_RS485_RTS_ON_SEND) config |= RTS_INVERT; - if (fintek_8250_enter_key(pdata->base_port)) + if (fintek_8250_enter_key(pdata->base_port, pdata->key)) return -EBUSY; outb(LDN, pdata->base_port + ADDR_PORT); @@ -148,20 +148,25 @@ static int fintek_8250_rs485_config(struct uart_port *port, return 0; } -static int fintek_8250_base_port(void) +static int fintek_8250_base_port(u8 *key) { static const u16 addr[] = {0x4e, 0x2e}; - int i; + static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67}; + int i, j; for (i = 0; i < ARRAY_SIZE(addr); i++) { - int ret; - - if (fintek_8250_enter_key(addr[i])) - continue; - ret = fintek_8250_check_id(addr[i]); - fintek_8250_exit_key(addr[i]); - if (!ret) - return addr[i]; + for (j = 0; j < ARRAY_SIZE(keys); j++) { + int ret; + + if (fintek_8250_enter_key(addr[i], keys[j])) + continue; + ret = fintek_8250_check_id(addr[i]); + fintek_8250_exit_key(addr[i]); + if (!ret) { + *key = keys[j]; + return addr[i]; + } + } } return -ENODEV; @@ -174,11 +179,12 @@ fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) struct fintek_8250 *pdata; int index; int base_port; + u8 key; if (!pnp_port_valid(dev, 0)) return -ENODEV; - base_port = fintek_8250_base_port(); + base_port = fintek_8250_base_port(&key); if (base_port < 0) return -ENODEV; @@ -206,6 +212,7 @@ fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) uart.port.uartclk = 1843200; uart.port.dev = &dev->dev; + pdata->key = key; pdata->base_port = base_port; pdata->index = index; pdata->line = serial8250_register_8250_port(&uart); -- cgit v1.3-6-gb490 From 29d58642f1a090ad574d14872b610b365b2d023b Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Tue, 16 Jun 2015 10:59:40 +0200 Subject: serial/8250_fintek: Support for any io address. Fintek chip can be configured for io addresses different than the standard. Query the chip for the configured addresses and try to match it with the pnp address. Reported-by: Peter Hong Reviewed-by: Alan Cox Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_fintek.c | 51 ++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 5b916857671b..89474399ab89 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -28,6 +28,8 @@ #define VENDOR_ID1_VAL 0x19 #define VENDOR_ID2 0x24 #define VENDOR_ID2_VAL 0x34 +#define IO_ADDR1 0x61 +#define IO_ADDR2 0x60 #define LDN 0x7 #define RS485 0xF0 @@ -63,18 +65,6 @@ static void fintek_8250_exit_key(u16 base_port) release_region(base_port + ADDR_PORT, 2); } -static int fintek_8250_get_index(resource_size_t base_addr) -{ - resource_size_t base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8}; - int i; - - for (i = 0; i < ARRAY_SIZE(base); i++) - if (base_addr == base[i]) - return i; - - return -ENODEV; -} - static int fintek_8250_check_id(u16 base_port) { u16 chip; @@ -148,24 +138,41 @@ static int fintek_8250_rs485_config(struct uart_port *port, return 0; } -static int fintek_8250_base_port(u8 *key) +static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index) { static const u16 addr[] = {0x4e, 0x2e}; static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67}; - int i, j; + int i, j, k; for (i = 0; i < ARRAY_SIZE(addr); i++) { for (j = 0; j < ARRAY_SIZE(keys); j++) { - int ret; if (fintek_8250_enter_key(addr[i], keys[j])) continue; - ret = fintek_8250_check_id(addr[i]); - fintek_8250_exit_key(addr[i]); - if (!ret) { + if (fintek_8250_check_id(addr[i])) { + fintek_8250_exit_key(addr[i]); + continue; + } + + for (k = 0; k < 4; k++) { + u16 aux; + + outb(LDN, addr[i] + ADDR_PORT); + outb(k, addr[i] + DATA_PORT); + + outb(IO_ADDR1, addr[i] + ADDR_PORT); + aux = inb(addr[i] + DATA_PORT); + outb(IO_ADDR2, addr[i] + ADDR_PORT); + aux |= inb(addr[i] + DATA_PORT) << 8; + if (aux != io_address) + continue; + + fintek_8250_exit_key(addr[i]); *key = keys[j]; + *index = k; return addr[i]; } + fintek_8250_exit_key(addr[i]); } } @@ -177,21 +184,17 @@ fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { struct uart_8250_port uart; struct fintek_8250 *pdata; - int index; int base_port; u8 key; + u8 index; if (!pnp_port_valid(dev, 0)) return -ENODEV; - base_port = fintek_8250_base_port(&key); + base_port = fintek_8250_base_port(pnp_port_start(dev, 0), &key, &index); if (base_port < 0) return -ENODEV; - index = fintek_8250_get_index(pnp_port_start(dev, 0)); - if (index < 0) - return -ENODEV; - memset(&uart, 0, sizeof(uart)); pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); -- cgit v1.3-6-gb490 From 727fd8ab7913421f3b60bcaaf31f1f5389c7cb5a Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 14 Jul 2015 13:32:03 +0530 Subject: serial: 8250_omap: fix kernel crash in suspend-to-ram omap_device infrastructure has a suspend_noirq hook which runtime suspends all devices late in the suspend cycle (see _od_suspend_noirq() in arch/arm/mach-omap2/omap_device.c) This leads to a NULL pointer exception in 8250_omap driver since by the time omap8250_runtime_suspend() is called, 8250_dma driver has already set rxchan to NULL via serial8250_release_dma(). Make an explicit check to see if rxchan is NULL in runtime_{suspend|resume} hooks to fix this. Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index d75a66c72750..20c5b9c4c288 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1285,7 +1285,7 @@ static int omap8250_runtime_suspend(struct device *dev) return -EBUSY; } - if (up->dma) + if (up->dma && up->dma->rxchan) omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT); priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; @@ -1310,7 +1310,7 @@ static int omap8250_runtime_resume(struct device *dev) if (loss_cntx) omap8250_restore_regs(up); - if (up->dma) + if (up->dma && up->dma->rxchan) omap_8250_rx_dma(up, 0); priv->latency = priv->calc_latency; -- cgit v1.3-6-gb490 From 6f03541f6bbd1b02f659099b171bd4b91d6f1a53 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 14 Jul 2015 13:32:05 +0530 Subject: serial: 8250_omap: refactor mdr1 update The silicon errata[1] workaround implemented in a follow-on patch, "serial: 8250_omap: workaround errata on disabling UART after using DMA", requires MDR1 register programming. Extract MDR1 register update into helper function, omap8250_update_mdr1() to help with that. [1] Advisory 21 in http://www.ti.com/lit/er/sprz408b/sprz408b.pdf Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 20c5b9c4c288..d9c96b993a84 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -232,6 +232,15 @@ static void omap8250_update_scr(struct uart_8250_port *up, serial_out(up, UART_OMAP_SCR, priv->scr); } +static void omap8250_update_mdr1(struct uart_8250_port *up, + struct omap8250_priv *priv) +{ + if (priv->habit & UART_ERRATA_i202_MDR1_ACCESS) + omap_8250_mdr1_errataset(up, priv); + else + serial_out(up, UART_OMAP_MDR1, priv->mdr1); +} + static void omap8250_restore_regs(struct uart_8250_port *up) { struct omap8250_priv *priv = up->port.private_data; @@ -282,11 +291,9 @@ static void omap8250_restore_regs(struct uart_8250_port *up) serial_out(up, UART_XOFF1, priv->xoff); serial_out(up, UART_LCR, up->lcr); - /* need mode A for FCR */ - if (priv->habit & UART_ERRATA_i202_MDR1_ACCESS) - omap_8250_mdr1_errataset(up, priv); - else - serial_out(up, UART_OMAP_MDR1, priv->mdr1); + + omap8250_update_mdr1(up, priv); + up->port.ops->set_mctrl(&up->port, up->port.mctrl); } -- cgit v1.3-6-gb490 From 4fcdff9bcabc135d72f69ed8723a14a9e514fe46 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 14 Jul 2015 13:32:06 +0530 Subject: serial: 8250_omap: introduce "ti,am3352-uart" compatible property Use of of_machine_is_compatible() for handling AM335x specific "DMA kick" quirk in 8250_omap driver makes it ugly to extend the quirk for other platforms. Instead use a new compatible. The new compatible will also make it easier to take care of other quirks on AM335x and like SoCs. In order to not break backward DTB compatibility for users of 8250_omap driver on AM335x based boards, existing use of of_machine_is_compatible() has not been removed. Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/omap_serial.txt | 1 + arch/arm/boot/dts/am33xx.dtsi | 12 ++++---- drivers/tty/serial/8250/8250_omap.c | 32 ++++++++++++++-------- 3 files changed, 28 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/serial/omap_serial.txt b/Documentation/devicetree/bindings/serial/omap_serial.txt index d3bd2b1ec401..0ee88209b341 100644 --- a/Documentation/devicetree/bindings/serial/omap_serial.txt +++ b/Documentation/devicetree/bindings/serial/omap_serial.txt @@ -5,6 +5,7 @@ Required properties: - compatible : should be "ti,omap3-uart" for OMAP3 controllers - compatible : should be "ti,omap4-uart" for OMAP4 controllers - compatible : should be "ti,am4372-uart" for AM437x controllers +- compatible : should be "ti,am3352-uart" for AM335x controllers - reg : address and length of the register space - interrupts or interrupts-extended : Should contain the uart interrupt specifier or both the interrupt diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index 21fcc440fc1a..b76f9a2ce05d 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -210,7 +210,7 @@ }; uart0: serial@44e09000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart1"; clock-frequency = <48000000>; reg = <0x44e09000 0x2000>; @@ -221,7 +221,7 @@ }; uart1: serial@48022000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart2"; clock-frequency = <48000000>; reg = <0x48022000 0x2000>; @@ -232,7 +232,7 @@ }; uart2: serial@48024000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart3"; clock-frequency = <48000000>; reg = <0x48024000 0x2000>; @@ -243,7 +243,7 @@ }; uart3: serial@481a6000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart4"; clock-frequency = <48000000>; reg = <0x481a6000 0x2000>; @@ -252,7 +252,7 @@ }; uart4: serial@481a8000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart5"; clock-frequency = <48000000>; reg = <0x481a8000 0x2000>; @@ -261,7 +261,7 @@ }; uart5: serial@481aa000 { - compatible = "ti,omap3-uart"; + compatible = "ti,am3352-uart", "ti,omap3-uart"; ti,hwmods = "uart6"; clock-frequency = <48000000>; reg = <0x481aa000 0x2000>; diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index d9c96b993a84..fff026f3d0bb 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -537,14 +538,14 @@ static void omap_serial_fill_features_erratas(struct uart_8250_port *up, switch (revision) { case OMAP_UART_REV_46: - priv->habit = UART_ERRATA_i202_MDR1_ACCESS; + priv->habit |= UART_ERRATA_i202_MDR1_ACCESS; break; case OMAP_UART_REV_52: - priv->habit = UART_ERRATA_i202_MDR1_ACCESS | + priv->habit |= UART_ERRATA_i202_MDR1_ACCESS | OMAP_UART_WER_HAS_TX_WAKEUP; break; case OMAP_UART_REV_63: - priv->habit = UART_ERRATA_i202_MDR1_ACCESS | + priv->habit |= UART_ERRATA_i202_MDR1_ACCESS | OMAP_UART_WER_HAS_TX_WAKEUP; break; default: @@ -1061,6 +1062,17 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } +static const u8 am3352_habit = OMAP_DMA_TX_KICK; + +static const struct of_device_id omap8250_dt_ids[] = { + { .compatible = "ti,omap2-uart" }, + { .compatible = "ti,omap3-uart" }, + { .compatible = "ti,omap4-uart" }, + { .compatible = "ti,am3352-uart", .data = &am3352_habit, }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap8250_dt_ids); + static int omap8250_probe(struct platform_device *pdev) { struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1125,11 +1137,17 @@ static int omap8250_probe(struct platform_device *pdev) up.port.unthrottle = omap_8250_unthrottle; if (pdev->dev.of_node) { + const struct of_device_id *id; + ret = of_alias_get_id(pdev->dev.of_node, "serial"); of_property_read_u32(pdev->dev.of_node, "clock-frequency", &up.port.uartclk); priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1); + + id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev); + if (id && id->data) + priv->habit |= *(u8 *)id->data; } else { ret = pdev->id; } @@ -1374,14 +1392,6 @@ static const struct dev_pm_ops omap8250_dev_pm_ops = { .complete = omap8250_complete, }; -static const struct of_device_id omap8250_dt_ids[] = { - { .compatible = "ti,omap2-uart" }, - { .compatible = "ti,omap3-uart" }, - { .compatible = "ti,omap4-uart" }, - {}, -}; -MODULE_DEVICE_TABLE(of, omap8250_dt_ids); - static struct platform_driver omap8250_platform_driver = { .driver = { .name = "omap8250", -- cgit v1.3-6-gb490 From cdb929e4452a8dab15daccc88e43d0f7e73b5500 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 14 Jul 2015 13:32:07 +0530 Subject: serial: 8250_omap: workaround errata around idling UART after using DMA AM335x, AM437x and DRA7x SoCs have an errata[1] due to which UART cannot be idled after it has been used with DMA. OMAP3 has a similar sounding errata which has been worked around in a2fc36613ac1af2e9 ("ARM: OMAP3: Use manual idle for UARTs because of DMA errata"). But the workaround used there does not apply to AM335x, AM437x SoCs. After using DMA, the UART module on these SoCs must be soft reset to go to idle. This patch implements that errata workaround. It is expected that UART will be used with DMA so no explicit check for DMA usage has been added for errata applicability. MDR1 register needs to be restored right after soft-reset because "UART mode" must be set in that register for module wake-up on AM335x to work. As a result, SCR register is now used to determine if context was lost during sleep. [1] See Advisory 21 in AM437x errata SPRZ408B, updated April 2015. http://www.ti.com/lit/er/sprz408b/sprz408b.pdf Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 65 +++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index fff026f3d0bb..a2ee75dee070 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -33,6 +33,11 @@ #define UART_ERRATA_i202_MDR1_ACCESS (1 << 0) #define OMAP_UART_WER_HAS_TX_WAKEUP (1 << 1) #define OMAP_DMA_TX_KICK (1 << 2) +/* + * See Advisory 21 in AM437x errata SPRZ408B, updated April 2015. + * The same errata is applicable to AM335x and DRA7x processors too. + */ +#define UART_ERRATA_CLOCK_DISABLE (1 << 3) #define OMAP_UART_FCR_RX_TRIG 6 #define OMAP_UART_FCR_TX_TRIG 4 @@ -54,6 +59,12 @@ #define OMAP_UART_MVR_MAJ_SHIFT 8 #define OMAP_UART_MVR_MIN_MASK 0x3f +/* SYSC register bitmasks */ +#define OMAP_UART_SYSC_SOFTRESET (1 << 1) + +/* SYSS register bitmasks */ +#define OMAP_UART_SYSS_RESETDONE (1 << 0) + #define UART_TI752_TLR_TX 0 #define UART_TI752_TLR_RX 4 @@ -1062,13 +1073,15 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } -static const u8 am3352_habit = OMAP_DMA_TX_KICK; +static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE; +static const u8 am4372_habit = UART_ERRATA_CLOCK_DISABLE; static const struct of_device_id omap8250_dt_ids[] = { { .compatible = "ti,omap2-uart" }, { .compatible = "ti,omap3-uart" }, { .compatible = "ti,omap4-uart" }, { .compatible = "ti,am3352-uart", .data = &am3352_habit, }, + { .compatible = "ti,am4372-uart", .data = &am4372_habit, }, {}, }; MODULE_DEVICE_TABLE(of, omap8250_dt_ids); @@ -1282,17 +1295,46 @@ static int omap8250_lost_context(struct uart_8250_port *up) { u32 val; - val = serial_in(up, UART_OMAP_MDR1); + val = serial_in(up, UART_OMAP_SCR); /* - * If we lose context, then MDR1 is set to its reset value which is - * UART_OMAP_MDR1_DISABLE. After set_termios() we set it either to 13x - * or 16x but never to disable again. + * If we lose context, then SCR is set to its reset value of zero. + * After set_termios() we set bit 3 of SCR (TX_EMPTY_CTL_IT) to 1, + * among other bits, to never set the register back to zero again. */ - if (val == UART_OMAP_MDR1_DISABLE) + if (!val) return 1; return 0; } +/* TODO: in future, this should happen via API in drivers/reset/ */ +static int omap8250_soft_reset(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(priv->line); + int timeout = 100; + int sysc; + int syss; + + sysc = serial_in(up, UART_OMAP_SYSC); + + /* softreset the UART */ + sysc |= OMAP_UART_SYSC_SOFTRESET; + serial_out(up, UART_OMAP_SYSC, sysc); + + /* By experiments, 1us enough for reset complete on AM335x */ + do { + udelay(1); + syss = serial_in(up, UART_OMAP_SYSS); + } while (--timeout && !(syss & OMAP_UART_SYSS_RESETDONE)); + + if (!timeout) { + dev_err(dev, "timed out waiting for reset done\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int omap8250_runtime_suspend(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); @@ -1310,6 +1352,17 @@ static int omap8250_runtime_suspend(struct device *dev) return -EBUSY; } + if (priv->habit & UART_ERRATA_CLOCK_DISABLE) { + int ret; + + ret = omap8250_soft_reset(dev); + if (ret) + return ret; + + /* Restore to UART mode after reset (for wakeup) */ + omap8250_update_mdr1(up, priv); + } + if (up->dma && up->dma->rxchan) omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT); -- cgit v1.3-6-gb490 From 27c93af7e7d9ccdfa28e26767c09106bf0721998 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 14 Jul 2015 13:32:08 +0530 Subject: serial: 8250_omap: workaround module disable errata on dra7x SoCs Due to Advisory 21 as documented in AM437x errata document, UART module cannot be disabled once DMA is used. The only workaround is to softreset the module before disabling it. DRA7x UARTs are compatible to AM437x UARTs in terms of this errata and prescribed workaround. Enable usage of workaround for this errata on DRA7x SoCs. Signed-off-by: Sekhar Nori Acked-by: Tony Lindgren Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/omap_serial.txt | 1 + drivers/tty/serial/8250/8250_omap.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/serial/omap_serial.txt b/Documentation/devicetree/bindings/serial/omap_serial.txt index 0ee88209b341..7a71b5de77d6 100644 --- a/Documentation/devicetree/bindings/serial/omap_serial.txt +++ b/Documentation/devicetree/bindings/serial/omap_serial.txt @@ -6,6 +6,7 @@ Required properties: - compatible : should be "ti,omap4-uart" for OMAP4 controllers - compatible : should be "ti,am4372-uart" for AM437x controllers - compatible : should be "ti,am3352-uart" for AM335x controllers +- compatible : should be "ti,dra742-uart" for DRA7x controllers - reg : address and length of the register space - interrupts or interrupts-extended : Should contain the uart interrupt specifier or both the interrupt diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index a2ee75dee070..d9a37191a1ae 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1082,6 +1082,7 @@ static const struct of_device_id omap8250_dt_ids[] = { { .compatible = "ti,omap4-uart" }, { .compatible = "ti,am3352-uart", .data = &am3352_habit, }, { .compatible = "ti,am4372-uart", .data = &am4372_habit, }, + { .compatible = "ti,dra742-uart", .data = &am4372_habit, }, {}, }; MODULE_DEVICE_TABLE(of, omap8250_dt_ids); -- cgit v1.3-6-gb490 From 5bac4b3d2592c281a9b2614070140b116bd0b0a9 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 27 Jun 2015 09:28:55 -0400 Subject: serial: 8250_omap: Remove auto-IXON flow control OMAP h/w-assisted IXON flow control is borked. The transmitter becomes stuck if XON is never received; clearing the fifos or resetting the rx flow control bits has no effect. Remove auto-IXANY as well, since without auto-IXON, it has no purpose. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index d9a37191a1ae..0340ee6ba970 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -447,12 +447,9 @@ static void omap_8250_set_termios(struct uart_port *port, priv->efr |= UART_EFR_CTS; } else if (up->port.flags & UPF_SOFT_FLOW) { /* - * IXON Flag: - * Enable XON/XOFF flow control on input. - * Receiver compares XON1, XOFF1. + * OMAP rx s/w flow control is borked; the transmitter remains + * stuck off even if rx flow control is subsequently disabled */ - if (termios->c_iflag & IXON) - priv->efr |= OMAP_UART_SW_RX; /* * IXOFF Flag: @@ -463,15 +460,6 @@ static void omap_8250_set_termios(struct uart_port *port, up->port.status |= UPSTAT_AUTOXOFF; priv->efr |= OMAP_UART_SW_TX; } - - /* - * IXANY Flag: - * Enable any character to restart output. - * Operation resumes after receiving any - * character after recognition of the XOFF character - */ - if (termios->c_iflag & IXANY) - up->mcr |= UART_MCR_XONANY; } omap8250_restore_regs(up); -- cgit v1.3-6-gb490 From e9bb4b510046d41e3e5a4adc56c76ec8d6812962 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 28 Jun 2015 09:46:43 +0800 Subject: serial: etraxfs-uart: Convert to uart_console_device instead of open-coded The implementation of cris_console_device() is exactly the same as uart_console_device(), so let's switch to use uart_console_device(). Signed-off-by: Axel Lin Acked-by: Niklas Cassel Acked-by: Jesper Nilsson Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/etraxfs-uart.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/etraxfs-uart.c b/drivers/tty/serial/etraxfs-uart.c index a57301a6fe42..7444ca3e616b 100644 --- a/drivers/tty/serial/etraxfs-uart.c +++ b/drivers/tty/serial/etraxfs-uart.c @@ -112,17 +112,10 @@ cris_console_setup(struct console *co, char *options) return 0; } -static struct tty_driver *cris_console_device(struct console *co, int *index) -{ - struct uart_driver *p = co->data; - *index = co->index; - return p->tty_driver; -} - static struct console cris_console = { .name = "ttyS", .write = cris_console_write, - .device = cris_console_device, + .device = uart_console_device, .setup = cris_console_setup, .flags = CON_PRINTBUFFER, .index = -1, -- cgit v1.3-6-gb490 From 1d26c9ff420f647df4a7a3e9a28736b9cff6359a Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Tue, 14 Jul 2015 00:52:22 +0000 Subject: serial: sirf: workaround rx process to avoid possible data loss when UART works in DMA mode and left bytes in rx fifo less than a dma transfer unit, DMA engine can't transfer the bytes out to rx DMA buffer. so it need a way to fetch them out and flush them into tty buffer in time. in the above case, we want UART switch from DMA mode to PIO mode and fetch && flush bytes into tty layer buffer until rxfifo become empty, after that done let UART switch from PIO mode back to DMA mode. (record as method1) method1 result in the next receive result wrong. for example in PIO part of method1, we fetched && pushed X1...X3 bytes, when UART rxfifo newly received Y1...Y4 bytes, UART trigger a DMA unit transfer, the DMA unit's content is X1...X3Y1 and rxfifo fifo status is empty, so X1X2X3 pushed twice by PIO way and DMA way also the bytes Y2Y3Y4 missed. add rxfifo reset operation before UART switch back to DMA mode would resolve the issue. ([method1 + do fifo reset] record as method2) before the commit, UART driver use method2. but methd2 have a risk of data loss, as if UART's shift register receive a complete byte and transfer it into rxfifo before rxfifo reset operation the byte will loss. UART and USP have the similar bits CLEAR_RX_ADDR_EN(uart)/FRADDR_CLR_EN(usp), When found UART controller changing I/O to DMA mode, UART controller clears the two low bits of read point (rx_fifo_addr[1:0]). when enable the bit + method1(record as method3), in above example the DMA unit's content is X1...X3Y1 and there are Y2Y3Y4 in rxfifo by experiment, we just push bytes in rx DMA buffer. BTW, the workaround works only for UART receive DMA channel use SINGLE DMA mode. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sirfsoc_uart.c | 80 ++++++++++++++++++++++++++++++--------- drivers/tty/serial/sirfsoc_uart.h | 4 ++ 2 files changed, 66 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 653cdd5fb508..8cac7ac497e8 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -886,9 +886,13 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, else wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE); if (sirfport->rx_dma_chan) - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE); + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & + ~SIRFUART_IO_MODE); else - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE); + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | + SIRFUART_IO_MODE); sirfport->rx_period_time = 20000000; /* Reset Rx/Tx FIFO Threshold level for proper baudrate */ if (set_baud < 1000000) @@ -958,9 +962,9 @@ static int sirfsoc_uart_startup(struct uart_port *port) wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port)); if (sirfport->rx_dma_chan) wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk, - SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) | - SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) | - SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b)); + SIRFUART_RX_FIFO_CHK_SC(port->line, 0x1) | + SIRFUART_RX_FIFO_CHK_LC(port->line, 0x2) | + SIRFUART_RX_FIFO_CHK_HC(port->line, 0x4)); if (sirfport->tx_dma_chan) { sirfport->tx_dma_state = TX_DMA_IDLE; wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk, @@ -981,10 +985,21 @@ static int sirfsoc_uart_startup(struct uart_port *port) goto init_rx_err; } } + if (sirfport->uart_reg->uart_type == SIRF_REAL_UART && + sirfport->rx_dma_chan) + wr_regl(port, ureg->sirfsoc_swh_dma_io, + SIRFUART_CLEAR_RX_ADDR_EN); + if (sirfport->uart_reg->uart_type == SIRF_USP_UART && + sirfport->rx_dma_chan) + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | + SIRFSOC_USP_FRADDR_CLR_EN); enable_irq(port->irq); if (sirfport->rx_dma_chan && !sirfport->is_hrt_enabled) { sirfport->is_hrt_enabled = true; sirfport->rx_period_time = 20000000; + sirfport->rx_last_pos = -1; + sirfport->pio_fetch_cnt = 0; sirfport->rx_dma_items.xmit.tail = sirfport->rx_dma_items.xmit.head = 0; hrtimer_start(&sirfport->hrt, @@ -1003,6 +1018,9 @@ static void sirfsoc_uart_shutdown(struct uart_port *port) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; + struct circ_buf *xmit; + + xmit = &sirfport->rx_dma_items.xmit; if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, 0); else @@ -1019,8 +1037,10 @@ static void sirfsoc_uart_shutdown(struct uart_port *port) if (sirfport->tx_dma_chan) sirfport->tx_dma_state = TX_DMA_IDLE; if (sirfport->rx_dma_chan && sirfport->is_hrt_enabled) { - while ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) & - SIRFUART_RX_FIFO_MASK) > 0) + while (((rd_regl(port, ureg->sirfsoc_rx_fifo_status) & + SIRFUART_RX_FIFO_MASK) > sirfport->pio_fetch_cnt) && + !CIRC_CNT(xmit->head, xmit->tail, + SIRFSOC_RX_DMA_BUF_SIZE)) ; sirfport->is_hrt_enabled = false; hrtimer_cancel(&sirfport->hrt); @@ -1169,6 +1189,8 @@ static enum hrtimer_restart struct tty_struct *tty; struct sirfsoc_register *ureg; struct circ_buf *xmit; + struct sirfsoc_fifo_status *ufifo_st; + int max_pio_cnt; sirfport = container_of(hrt, struct sirfsoc_uart_port, hrt); port = &sirfport->port; @@ -1176,9 +1198,16 @@ static enum hrtimer_restart tty = port->state->port.tty; ureg = &sirfport->uart_reg->uart_reg; xmit = &sirfport->rx_dma_items.xmit; + ufifo_st = &sirfport->uart_reg->fifo_status; + dmaengine_tx_status(sirfport->rx_dma_chan, - sirfport->rx_dma_items.cookie, &tx_state); - xmit->head = SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue; + sirfport->rx_dma_items.cookie, &tx_state); + if (SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue != + sirfport->rx_last_pos) { + xmit->head = SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue; + sirfport->rx_last_pos = xmit->head; + sirfport->pio_fetch_cnt = 0; + } count = CIRC_CNT_TO_END(xmit->head, xmit->tail, SIRFSOC_RX_DMA_BUF_SIZE); while (count > 0) { @@ -1200,23 +1229,38 @@ static enum hrtimer_restart */ if (!inserted && !count && ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) & - SIRFUART_RX_FIFO_MASK) > 0)) { + SIRFUART_RX_FIFO_MASK) > sirfport->pio_fetch_cnt)) { + dmaengine_pause(sirfport->rx_dma_chan); /* switch to pio mode */ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | SIRFUART_IO_MODE); - while ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) & - SIRFUART_RX_FIFO_MASK) > 0) { - if (sirfsoc_uart_pio_rx_chars(port, 16) > 0) - tty_flip_buffer_push(tty->port); + /* + * UART controller SWH_DMA_IO register have CLEAR_RX_ADDR_EN + * When found changing I/O to DMA mode, it clears + * two low bits of read point; + * USP have similar FRADDR_CLR_EN bit in USP_RX_DMA_IO_CTRL. + * Fetch data out from rxfifo into DMA buffer in PIO mode, + * while switch back to DMA mode, the data fetched will override + * by DMA, as hardware have a strange behaviour: + * after switch back to DMA mode, check rxfifo status it will + * be the number PIO fetched, so record the fetched data count + * to avoid the repeated fetch + */ + max_pio_cnt = 3; + while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) & + ufifo_st->ff_empty(port)) && max_pio_cnt--) { + xmit->buf[xmit->head] = + rd_regl(port, ureg->sirfsoc_rx_fifo_data); + xmit->head = (xmit->head + 1) & + (SIRFSOC_RX_DMA_BUF_SIZE - 1); + sirfport->pio_fetch_cnt++; } - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); /* switch back to dma mode */ wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & ~SIRFUART_IO_MODE); + dmaengine_resume(sirfport->rx_dma_chan); } next_hrt: hrtimer_forward_now(hrt, ns_to_ktime(sirfport->rx_period_time)); @@ -1239,7 +1283,7 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) struct resource *res; int ret; struct dma_slave_config slv_cfg = { - .src_maxburst = 2, + .src_maxburst = 1, }; struct dma_slave_config tx_slv_cfg = { .dst_maxburst = 2, diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index eb162b012eec..671a08dc5497 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -296,6 +296,7 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFUART_DMA_MODE 0x0 #define SIRFUART_RX_DMA_FLUSH 0x4 +#define SIRFUART_CLEAR_RX_ADDR_EN 0x2 /* Baud Rate Calculation */ #define SIRF_USP_MIN_SAMPLE_DIV 0x1 #define SIRF_MIN_SAMPLE_DIV 0xf @@ -325,6 +326,7 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFSOC_USP_ASYNC_DIV2_MASK 0x3f #define SIRFSOC_USP_ASYNC_DIV2_OFFSET 16 #define SIRFSOC_USP_LOOP_BACK_CTRL BIT(2) +#define SIRFSOC_USP_FRADDR_CLR_EN BIT(1) /* USP-UART Common */ #define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000) #define SIRFUART_RECV_TIMEOUT_VALUE(x) \ @@ -431,6 +433,8 @@ struct sirfsoc_uart_port { struct hrtimer hrt; bool is_hrt_enabled; unsigned long rx_period_time; + unsigned long rx_last_pos; + unsigned long pio_fetch_cnt; }; /* Register Access Control */ -- cgit v1.3-6-gb490 From 466e285b1f63e84a6ced5cd18c3c3d90bda73404 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Tue, 14 Jul 2015 00:52:23 +0000 Subject: serial: sirf: let uart's receive start in right place While UART work in DMA mode, function start_rx will request descriptor from DMA engine, if there is no left descriptor UART, driver will give err logs "DMA slave single fail". currently start_rx is called in set_termios function, so everytime, port setting will call start_rx once. Now put start_rx in startup, it will be called once while open the port. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sirfsoc_uart.c | 46 ++++++++++++++------------------------- drivers/tty/serial/sirfsoc_uart.h | 1 - 2 files changed, 16 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 8cac7ac497e8..c6657de78997 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -413,7 +413,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count) break; } - sirfport->rx_io_count += rx_count; port->icount.rx += rx_count; return rx_count; @@ -600,7 +599,6 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port) struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - sirfport->rx_io_count = 0; wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & ~SIRFUART_IO_MODE); @@ -632,31 +630,6 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port) sirfport->uart_reg->uart_type)); } -static void sirfsoc_uart_start_rx(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - - sirfport->rx_io_count = 0; - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); - if (sirfport->rx_dma_chan) - sirfsoc_uart_start_next_rx_dma(port); - else { - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) | - SIRFUART_RX_IO_INT_EN(uint_en, - sirfport->uart_reg->uart_type)); - else - wr_regl(port, ureg->sirfsoc_int_en_reg, - SIRFUART_RX_IO_INT_EN(uint_en, - sirfport->uart_reg->uart_type)); - } -} - static unsigned int sirfsoc_usp_calc_sample_div(unsigned long set_rate, unsigned long ioclk_rate, unsigned long *sample_reg) @@ -850,7 +823,6 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, rx_time_out = SIRFSOC_UART_RX_TIMEOUT(set_baud, 20000); rx_time_out = SIRFUART_RECV_TIMEOUT_VALUE(rx_time_out); txfifo_op_reg = rd_regl(port, ureg->sirfsoc_tx_fifo_op); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_STOP); wr_regl(port, ureg->sirfsoc_tx_fifo_op, (txfifo_op_reg & ~SIRFUART_FIFO_START)); if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { @@ -906,7 +878,6 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, txfifo_op_reg |= SIRFUART_FIFO_START; wr_regl(port, ureg->sirfsoc_tx_fifo_op, txfifo_op_reg); uart_update_timeout(port, termios->c_cflag, set_baud); - sirfsoc_uart_start_rx(port); wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_TX_EN | SIRFUART_RX_EN); spin_unlock_irqrestore(&port->lock, flags); } @@ -925,6 +896,7 @@ static int sirfsoc_uart_startup(struct uart_port *port) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; + struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; unsigned int index = port->line; int ret; irq_modify_status(port->irq, IRQ_NOREQUEST, IRQ_NOAUTOEN); @@ -994,7 +966,6 @@ static int sirfsoc_uart_startup(struct uart_port *port) wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | SIRFSOC_USP_FRADDR_CLR_EN); - enable_irq(port->irq); if (sirfport->rx_dma_chan && !sirfport->is_hrt_enabled) { sirfport->is_hrt_enabled = true; sirfport->rx_period_time = 20000000; @@ -1006,6 +977,21 @@ static int sirfsoc_uart_startup(struct uart_port *port) ns_to_ktime(sirfport->rx_period_time), HRTIMER_MODE_REL); } + wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); + if (sirfport->rx_dma_chan) + sirfsoc_uart_start_next_rx_dma(port); + else { + if (!sirfport->is_atlas7) + wr_regl(port, ureg->sirfsoc_int_en_reg, + rd_regl(port, ureg->sirfsoc_int_en_reg) | + SIRFUART_RX_IO_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); + else + wr_regl(port, ureg->sirfsoc_int_en_reg, + SIRFUART_RX_IO_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); + } + enable_irq(port->irq); return 0; init_rx_err: diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index 671a08dc5497..c3a885b4d76a 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -423,7 +423,6 @@ struct sirfsoc_uart_port { struct dma_chan *tx_dma_chan; dma_addr_t tx_dma_addr; struct dma_async_tx_descriptor *tx_dma_desc; - unsigned int rx_io_count; unsigned long transfer_size; enum sirfsoc_tx_state tx_dma_state; unsigned int cts_gpio; -- cgit v1.3-6-gb490 From 43b7be3b8c0457c35a124d8538372f82f355bd29 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 17 Jul 2015 17:04:10 -0700 Subject: Input: samsung-keypad - change name of wakeup property Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/samsung-keypad.txt | 4 +++- drivers/input/keyboard/samsung-keypad.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/samsung-keypad.txt b/Documentation/devicetree/bindings/input/samsung-keypad.txt index 942d071baaa5..863e77f619dc 100644 --- a/Documentation/devicetree/bindings/input/samsung-keypad.txt +++ b/Documentation/devicetree/bindings/input/samsung-keypad.txt @@ -36,9 +36,11 @@ Required Board Specific Properties: - pinctrl-0: Should specify pin control groups used for this controller. - pinctrl-names: Should contain only one value - "default". +Optional Properties: +- wakeup-source: use any event on keypad as wakeup event. + Optional Properties specific to linux: - linux,keypad-no-autorepeat: do no enable autorepeat feature. -- linux,keypad-wakeup: use any event on keypad as wakeup event. Example: diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 43e48dac7687..4e319eb9e19d 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -299,8 +299,10 @@ samsung_keypad_parse_dt(struct device *dev) if (of_get_property(np, "linux,input-no-autorepeat", NULL)) pdata->no_autorepeat = true; - if (of_get_property(np, "linux,input-wakeup", NULL)) - pdata->wakeup = true; + pdata->wakeup = of_property_read_bool(np, "wakeup-source") || + /* legacy name */ + of_property_read_bool(np, "linux,input-wakeup"); + return pdata; } -- cgit v1.3-6-gb490 From e571c73ee4836640d3019ac68b008f3662087e80 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 17 Jul 2015 17:08:02 -0700 Subject: Input: tc3589x-keypad - change name of wakeup property Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Reviewed-by: Linus Walleij Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/mfd/tc3589x.txt | 4 ++-- drivers/input/keyboard/tc3589x-keypad.c | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/mfd/tc3589x.txt b/Documentation/devicetree/bindings/mfd/tc3589x.txt index 6fcedba46ae9..37bf7f1aa70a 100644 --- a/Documentation/devicetree/bindings/mfd/tc3589x.txt +++ b/Documentation/devicetree/bindings/mfd/tc3589x.txt @@ -55,7 +55,7 @@ Optional nodes: - linux,keymap: the definition can be found in bindings/input/matrix-keymap.txt - linux,no-autorepeat: do no enable autorepeat feature. - - linux,wakeup: use any event on keypad as wakeup event. + - wakeup-source: use any event on keypad as wakeup event. Example: @@ -84,7 +84,6 @@ tc35893@44 { keypad,num-columns = <8>; keypad,num-rows = <8>; linux,no-autorepeat; - linux,wakeup; linux,keymap = <0x0301006b 0x04010066 0x06040072 @@ -103,5 +102,6 @@ tc35893@44 { 0x01030039 0x07060069 0x050500d9>; + wakeup-source; }; }; diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 31c606a4dd31..565805e1ff94 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -352,7 +352,10 @@ tc3589x_keypad_of_probe(struct device *dev) } plat->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat"); - plat->enable_wakeup = of_property_read_bool(np, "linux,wakeup"); + + plat->enable_wakeup = of_property_read_bool(np, "wakeup-source") || + /* legacy name */ + of_property_read_bool(np, "linux,wakeup"); /* The custom delay format is ms/16 */ of_property_read_u32(np, "debounce-delay-ms", &debounce_ms); -- cgit v1.3-6-gb490 From be972177797636a4c8958ff0a8feb314309850c3 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sun, 25 May 2014 22:33:13 -0700 Subject: Input: tc3589x-keypad - switch to using managed resources Let's switch the driver to use managed resources, this will simplify error handling and driver unbinding logic. Signed-off-by: Himangi Saraogi Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tc3589x-keypad.c | 58 ++++++++++++--------------------- 1 file changed, 20 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 565805e1ff94..e92dfd8889c2 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -17,6 +17,7 @@ #include #include #include +#include /* Maximum supported keypad matrix row/columns size */ #define TC3589x_MAX_KPROW 8 @@ -389,12 +390,15 @@ static int tc3589x_keypad_probe(struct platform_device *pdev) if (irq < 0) return irq; - keypad = kzalloc(sizeof(struct tc_keypad), GFP_KERNEL); - input = input_allocate_device(); - if (!keypad || !input) { - dev_err(&pdev->dev, "failed to allocate keypad memory\n"); - error = -ENOMEM; - goto err_free_mem; + keypad = devm_kzalloc(&pdev->dev, sizeof(struct tc_keypad), + GFP_KERNEL); + if (!keypad) + return -ENOMEM; + + input = devm_input_allocate_device(&pdev->dev); + if (!input) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + return -ENOMEM; } keypad->board = plat; @@ -413,7 +417,7 @@ static int tc3589x_keypad_probe(struct platform_device *pdev) NULL, input); if (error) { dev_err(&pdev->dev, "Failed to build keymap\n"); - goto err_free_mem; + return error; } keypad->keymap = input->keycode; @@ -424,20 +428,23 @@ static int tc3589x_keypad_probe(struct platform_device *pdev) input_set_drvdata(input, keypad); - error = request_threaded_irq(irq, NULL, tc3589x_keypad_irq, - plat->irqtype | IRQF_ONESHOT, - "tc3589x-keypad", keypad); - if (error < 0) { + tc3589x_keypad_disable(keypad); + + error = devm_request_threaded_irq(&pdev->dev, irq, + NULL, tc3589x_keypad_irq, + plat->irqtype | IRQF_ONESHOT, + "tc3589x-keypad", keypad); + if (error) { dev_err(&pdev->dev, "Could not allocate irq %d,error %d\n", irq, error); - goto err_free_mem; + return error; } error = input_register_device(input); if (error) { dev_err(&pdev->dev, "Could not register input device\n"); - goto err_free_irq; + return error; } /* let platform decide if keypad is a wakeup source or not */ @@ -446,30 +453,6 @@ static int tc3589x_keypad_probe(struct platform_device *pdev) platform_set_drvdata(pdev, keypad); - return 0; - -err_free_irq: - free_irq(irq, keypad); -err_free_mem: - input_free_device(input); - kfree(keypad); - return error; -} - -static int tc3589x_keypad_remove(struct platform_device *pdev) -{ - struct tc_keypad *keypad = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - - if (!keypad->keypad_stopped) - tc3589x_keypad_disable(keypad); - - free_irq(irq, keypad); - - input_unregister_device(keypad->input); - - kfree(keypad); - return 0; } @@ -521,7 +504,6 @@ static struct platform_driver tc3589x_keypad_driver = { .pm = &tc3589x_keypad_dev_pm_ops, }, .probe = tc3589x_keypad_probe, - .remove = tc3589x_keypad_remove, }; module_platform_driver(tc3589x_keypad_driver); -- cgit v1.3-6-gb490 From 94897619bf24aca6b37cfa847399a56cf40eab66 Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Mon, 20 Jul 2015 16:49:06 -0700 Subject: Input: cyapa - rename 'gen5' to 'pip' for chared code Change 'gen5' to 'pip' for all macros, variables and functions that are shared between gen5 and gen6 modules to make naming more clear and readable. Also fix a few spelling errors. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 34 +- drivers/input/mouse/cyapa.h | 136 ++++- drivers/input/mouse/cyapa_gen3.c | 4 +- drivers/input/mouse/cyapa_gen5.c | 1103 ++++++++++++++++++-------------------- 4 files changed, 673 insertions(+), 604 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index dfbfd494bb1f..4c4429598adb 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -6,7 +6,7 @@ * Daniel Kurtz * Benson Leung * - * Copyright (C) 2011-2014 Cypress Semiconductor, Inc. + * Copyright (C) 2011-2015 Cypress Semiconductor, Inc. * Copyright (C) 2011-2012 Google, Inc. * * This file is subject to the terms and conditions of the GNU General Public @@ -39,11 +39,27 @@ const char product_id[] = "CYTRA"; static int cyapa_reinitialize(struct cyapa *cyapa); -static inline bool cyapa_is_bootloader_mode(struct cyapa *cyapa) +bool cyapa_is_pip_bl_mode(struct cyapa *cyapa) { if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_BL) return true; + return false; +} + +bool cyapa_is_pip_app_mode(struct cyapa *cyapa) +{ + if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP) + return true; + + return false; +} + +static bool cyapa_is_bootloader_mode(struct cyapa *cyapa) +{ + if (cyapa_is_pip_bl_mode(cyapa)) + return true; + if (cyapa->gen == CYAPA_GEN3 && cyapa->state >= CYAPA_STATE_BL_BUSY && cyapa->state <= CYAPA_STATE_BL_ACTIVE) @@ -54,7 +70,7 @@ static inline bool cyapa_is_bootloader_mode(struct cyapa *cyapa) static inline bool cyapa_is_operational_mode(struct cyapa *cyapa) { - if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP) + if (cyapa_is_pip_app_mode(cyapa)) return true; if (cyapa->gen == CYAPA_GEN3 && cyapa->state == CYAPA_STATE_OP) @@ -306,7 +322,7 @@ static int cyapa_check_is_operational(struct cyapa *cyapa) /* * Returns 0 on device detected, negative errno on no device detected. - * And when the device is detected and opertaional, it will be reset to + * And when the device is detected and operational, it will be reset to * full power active mode automatically. */ static int cyapa_detect(struct cyapa *cyapa) @@ -629,15 +645,15 @@ static irqreturn_t cyapa_irq(int irq, void *dev_id) if (device_may_wakeup(dev)) pm_wakeup_event(dev, 0); - /* Interrupt event maybe cuased by host command to trackpad device. */ + /* Interrupt event can be caused by host command to trackpad device. */ if (cyapa->ops->irq_cmd_handler(cyapa)) { /* * Interrupt event maybe from trackpad device input reporting. */ if (!cyapa->input) { /* - * Still in probling or in firware image - * udpating or reading. + * Still in probing or in firmware image + * updating or reading. */ cyapa->ops->sort_empty_output_data(cyapa, NULL, NULL, NULL); @@ -1051,12 +1067,12 @@ static ssize_t cyapa_update_fw_store(struct device *dev, dev_dbg(dev, "firmware update successfully done.\n"); /* - * Redetect trackpad device states because firmware update process + * Re-detect trackpad device states because firmware update process * will reset trackpad device into bootloader mode. */ ret = cyapa_reinitialize(cyapa); if (ret) { - dev_err(dev, "failed to redetect after updated: %d\n", ret); + dev_err(dev, "failed to re-detect after updated: %d\n", ret); error = error ? error : ret; } diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h index adc9ed5dcb0e..d019d1d2d1e4 100644 --- a/drivers/input/mouse/cyapa.h +++ b/drivers/input/mouse/cyapa.h @@ -3,7 +3,7 @@ * * Author: Dudley Du * - * Copyright (C) 2014 Cypress Semiconductor, Inc. + * Copyright (C) 2014-2015 Cypress Semiconductor, Inc. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -25,7 +25,7 @@ /* * Macros for SMBus communication */ -#define SMBUS_READ 0x01 +#define SMBUS_READ 0x01 #define SMBUS_WRITE 0x00 #define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1)) #define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01)) @@ -159,12 +159,86 @@ #define AUTOSUSPEND_DELAY 2000 /* unit : ms */ -#define UNINIT_SLEEP_TIME 0xFFFF -#define UNINIT_PWR_MODE 0xFF - #define BTN_ONLY_MODE_NAME "buttononly" #define OFF_MODE_NAME "off" +/* Common macros for PIP interface. */ +#define PIP_HID_DESCRIPTOR_ADDR 0x0001 +#define PIP_REPORT_DESCRIPTOR_ADDR 0x0002 +#define PIP_INPUT_REPORT_ADDR 0x0003 +#define PIP_OUTPUT_REPORT_ADDR 0x0004 +#define PIP_CMD_DATA_ADDR 0x0006 + +#define PIP_RETRIEVE_DATA_STRUCTURE 0x24 +#define PIP_CMD_CALIBRATE 0x28 +#define PIP_BL_CMD_VERIFY_APP_INTEGRITY 0x31 +#define PIP_BL_CMD_GET_BL_INFO 0x38 +#define PIP_BL_CMD_PROGRAM_VERIFY_ROW 0x39 +#define PIP_BL_CMD_LAUNCH_APP 0x3b +#define PIP_BL_CMD_INITIATE_BL 0x48 +#define PIP_INVALID_CMD 0xff + +#define PIP_HID_DESCRIPTOR_SIZE 32 +#define PIP_HID_APP_REPORT_ID 0xf7 +#define PIP_HID_BL_REPORT_ID 0xff + +#define PIP_BL_CMD_REPORT_ID 0x40 +#define PIP_BL_RESP_REPORT_ID 0x30 +#define PIP_APP_CMD_REPORT_ID 0x2f +#define PIP_APP_RESP_REPORT_ID 0x1f + +#define PIP_READ_SYS_INFO_CMD_LENGTH 7 +#define PIP_BL_READ_APP_INFO_CMD_LENGTH 13 +#define PIP_MIN_BL_CMD_LENGTH 13 +#define PIP_MIN_BL_RESP_LENGTH 11 +#define PIP_MIN_APP_CMD_LENGTH 7 +#define PIP_MIN_APP_RESP_LENGTH 5 +#define PIP_UNSUPPORTED_CMD_RESP_LENGTH 6 +#define PIP_READ_SYS_INFO_RESP_LENGTH 71 +#define PIP_BL_APP_INFO_RESP_LENGTH 30 +#define PIP_BL_GET_INFO_RESP_LENGTH 19 + +#define PIP_PRODUCT_FAMILY_MASK 0xf000 +#define PIP_PRODUCT_FAMILY_TRACKPAD 0x1000 + +#define PIP_DEEP_SLEEP_STATE_ON 0x00 +#define PIP_DEEP_SLEEP_STATE_OFF 0x01 +#define PIP_DEEP_SLEEP_STATE_MASK 0x03 +#define PIP_APP_DEEP_SLEEP_REPORT_ID 0xf0 +#define PIP_DEEP_SLEEP_RESP_LENGTH 5 +#define PIP_DEEP_SLEEP_OPCODE 0x08 +#define PIP_DEEP_SLEEP_OPCODE_MASK 0x0f + +#define PIP_RESP_LENGTH_OFFSET 0 +#define PIP_RESP_LENGTH_SIZE 2 +#define PIP_RESP_REPORT_ID_OFFSET 2 +#define PIP_RESP_RSVD_OFFSET 3 +#define PIP_RESP_RSVD_KEY 0x00 +#define PIP_RESP_BL_SOP_OFFSET 4 +#define PIP_SOP_KEY 0x01 /* Start of Packet */ +#define PIP_EOP_KEY 0x17 /* End of Packet */ +#define PIP_RESP_APP_CMD_OFFSET 4 +#define GET_PIP_CMD_CODE(reg) ((reg) & 0x7f) +#define PIP_RESP_STATUS_OFFSET 5 + +#define VALID_CMD_RESP_HEADER(resp, cmd) \ + (((resp)[PIP_RESP_REPORT_ID_OFFSET] == PIP_APP_RESP_REPORT_ID) && \ + ((resp)[PIP_RESP_RSVD_OFFSET] == PIP_RESP_RSVD_KEY) && \ + (GET_PIP_CMD_CODE((resp)[PIP_RESP_APP_CMD_OFFSET]) == (cmd))) + +#define PIP_CMD_COMPLETE_SUCCESS(resp_data) \ + ((resp_data)[PIP_RESP_STATUS_OFFSET] == 0x00) + +/* Variables to record latest gen5 trackpad power states. */ +#define UNINIT_SLEEP_TIME 0xffff +#define UNINIT_PWR_MODE 0xff +#define PIP_DEV_SET_PWR_STATE(cyapa, s) ((cyapa)->dev_pwr_mode = (s)) +#define PIP_DEV_GET_PWR_STATE(cyapa) ((cyapa)->dev_pwr_mode) +#define PIP_DEV_SET_SLEEP_TIME(cyapa, t) ((cyapa)->dev_sleep_time = (t)) +#define PIP_DEV_GET_SLEEP_TIME(cyapa) ((cyapa)->dev_sleep_time) +#define PIP_DEV_UNINIT_SLEEP_TIME(cyapa) \ + (((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME) + /* The touch.id is used as the MT slot id, thus max MT slot is 15 */ #define CYAPA_MAX_MT_SLOTS 15 @@ -198,7 +272,7 @@ struct cyapa_dev_ops { int (*set_power_mode)(struct cyapa *, u8, u16); }; -struct cyapa_gen5_cmd_states { +struct cyapa_pip_cmd_states { struct mutex cmd_lock; struct completion cmd_ready; atomic_t cmd_issued; @@ -214,7 +288,7 @@ struct cyapa_gen5_cmd_states { }; union cyapa_cmd_states { - struct cyapa_gen5_cmd_states gen5; + struct cyapa_pip_cmd_states pip; }; enum cyapa_state { @@ -259,7 +333,7 @@ struct cyapa { int physical_size_y; /* Used in ttsp and truetouch based trackpad devices. */ - u8 x_origin; /* X Axis Origin: 0 = left side; 1 = rigth side. */ + u8 x_origin; /* X Axis Origin: 0 = left side; 1 = right side. */ u8 y_origin; /* Y Axis Origin: 0 = top; 1 = bottom. */ int electrodes_x; /* Number of electrodes on the X Axis*/ int electrodes_y; /* Number of electrodes on the Y Axis*/ @@ -282,9 +356,9 @@ struct cyapa { ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len, - u8 *values); + u8 *values); ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len, - u8 *values); + u8 *values); ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values); @@ -293,7 +367,47 @@ int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout); u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time); u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode); - +ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size); +ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size); +int cyapa_empty_pip_output_data(struct cyapa *cyapa, + u8 *buf, int *len, cb_sort func); +int cyapa_i2c_pip_cmd_irq_sync(struct cyapa *cyapa, + u8 *cmd, int cmd_len, + u8 *resp_data, int *resp_len, + unsigned long timeout, + cb_sort func, + bool irq_mode); +int cyapa_pip_state_parse(struct cyapa *cyapa, u8 *reg_data, int len); +bool cyapa_pip_sort_system_info_data(struct cyapa *cyapa, u8 *buf, int len); +bool cyapa_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa, u8 *data, int len); +int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state); +bool cyapa_sort_tsg_pip_app_resp_data(struct cyapa *cyapa, u8 *data, int len); +int cyapa_pip_bl_exit(struct cyapa *cyapa); +int cyapa_pip_bl_enter(struct cyapa *cyapa); + + +bool cyapa_is_pip_bl_mode(struct cyapa *cyapa); +bool cyapa_is_pip_app_mode(struct cyapa *cyapa); +int cyapa_pip_cmd_state_initialize(struct cyapa *cyapa); + +int cyapa_pip_resume_scanning(struct cyapa *cyapa); +int cyapa_pip_suspend_scanning(struct cyapa *cyapa); + +int cyapa_pip_check_fw(struct cyapa *cyapa, const struct firmware *fw); +int cyapa_pip_bl_initiate(struct cyapa *cyapa, const struct firmware *fw); +int cyapa_pip_do_fw_update(struct cyapa *cyapa, const struct firmware *fw); +int cyapa_pip_bl_activate(struct cyapa *cyapa); +int cyapa_pip_bl_deactivate(struct cyapa *cyapa); +ssize_t cyapa_pip_do_calibrate(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +bool cyapa_pip_irq_cmd_handler(struct cyapa *cyapa); +int cyapa_pip_irq_handler(struct cyapa *cyapa); + + +extern u8 pip_read_sys_info[]; +extern u8 pip_bl_read_app_info[]; extern const char product_id[]; extern const struct cyapa_dev_ops cyapa_gen3_ops; extern const struct cyapa_dev_ops cyapa_gen5_ops; diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c index 3faf01c1b191..3884311410f7 100644 --- a/drivers/input/mouse/cyapa_gen3.c +++ b/drivers/input/mouse/cyapa_gen3.c @@ -6,7 +6,7 @@ * Daniel Kurtz * Benson Leung * - * Copyright (C) 2011-2014 Cypress Semiconductor, Inc. + * Copyright (C) 2011-2015 Cypress Semiconductor, Inc. * Copyright (C) 2011-2012 Google, Inc. * * This file is subject to the terms and conditions of the GNU General Public @@ -1156,7 +1156,7 @@ static bool cyapa_gen3_irq_cmd_handler(struct cyapa *cyapa) * so, stop cyapa_gen3_irq_handler to continue process to * avoid unwanted to error detecting and processing. * - * And also, avoid the periodicly accerted interrupts to be processed + * And also, avoid the periodically asserted interrupts to be processed * as touch inputs when gen3 failed to launch into application mode, * which will cause gen3 stays in bootloader mode. */ diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index afc39e799da2..9d75c6f9f307 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -3,7 +3,7 @@ * * Author: Dudley Du * - * Copyright (C) 2014 Cypress Semiconductor, Inc. + * Copyright (C) 2014-2015 Cypress Semiconductor, Inc. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -22,12 +22,7 @@ #include "cyapa.h" -/* Macro of Gen5 */ -#define RECORD_EVENT_NONE 0 -#define RECORD_EVENT_TOUCHDOWN 1 -#define RECORD_EVENT_DISPLACE 2 -#define RECORD_EVENT_LIFTOFF 3 - +/* Macro of TSG firmware image */ #define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE 0x80 #define CYAPA_TSG_IMG_FW_HDR_SIZE 13 #define CYAPA_TSG_FW_ROW_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE) @@ -44,43 +39,48 @@ #define CYAPA_TSG_MAX_CMD_SIZE 256 -#define GEN5_BL_CMD_VERIFY_APP_INTEGRITY 0x31 -#define GEN5_BL_CMD_GET_BL_INFO 0x38 -#define GEN5_BL_CMD_PROGRAM_VERIFY_ROW 0x39 -#define GEN5_BL_CMD_LAUNCH_APP 0x3b -#define GEN5_BL_CMD_INITIATE_BL 0x48 - -#define GEN5_HID_DESCRIPTOR_ADDR 0x0001 -#define GEN5_REPORT_DESCRIPTOR_ADDR 0x0002 -#define GEN5_INPUT_REPORT_ADDR 0x0003 -#define GEN5_OUTPUT_REPORT_ADDR 0x0004 -#define GEN5_CMD_DATA_ADDR 0x0006 - -#define GEN5_TOUCH_REPORT_HEAD_SIZE 7 -#define GEN5_TOUCH_REPORT_MAX_SIZE 127 -#define GEN5_BTN_REPORT_HEAD_SIZE 6 -#define GEN5_BTN_REPORT_MAX_SIZE 14 -#define GEN5_WAKEUP_EVENT_SIZE 4 -#define GEN5_RAW_DATA_HEAD_SIZE 24 - -#define GEN5_BL_CMD_REPORT_ID 0x40 -#define GEN5_BL_RESP_REPORT_ID 0x30 -#define GEN5_APP_CMD_REPORT_ID 0x2f -#define GEN5_APP_RESP_REPORT_ID 0x1f - -#define GEN5_APP_DEEP_SLEEP_REPORT_ID 0xf0 -#define GEN5_DEEP_SLEEP_RESP_LENGTH 5 +/* Macro of PIP interface */ +#define PIP_BL_INITIATE_RESP_LEN 11 +#define PIP_BL_FAIL_EXIT_RESP_LEN 11 +#define PIP_BL_FAIL_EXIT_STATUS_CODE 0x0c +#define PIP_BL_VERIFY_INTEGRITY_RESP_LEN 12 +#define PIP_BL_INTEGRITY_CHEKC_PASS 0x00 +#define PIP_BL_BLOCK_WRITE_RESP_LEN 11 + +#define PIP_TOUCH_REPORT_ID 0x01 +#define PIP_BTN_REPORT_ID 0x03 +#define PIP_WAKEUP_EVENT_REPORT_ID 0x04 +#define PIP_PUSH_BTN_REPORT_ID 0x06 +#define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 /* Special for old Gen5 TP. */ + +#define PIP_TOUCH_REPORT_HEAD_SIZE 7 +#define PIP_TOUCH_REPORT_MAX_SIZE 127 +#define PIP_BTN_REPORT_HEAD_SIZE 6 +#define PIP_BTN_REPORT_MAX_SIZE 14 +#define PIP_WAKEUP_EVENT_SIZE 4 + +#define PIP_NUMBER_OF_TOUCH_OFFSET 5 +#define PIP_NUMBER_OF_TOUCH_MASK 0x1f +#define PIP_BUTTONS_OFFSET 5 +#define PIP_BUTTONS_MASK 0x0f +#define PIP_GET_EVENT_ID(reg) (((reg) >> 5) & 0x03) +#define PIP_GET_TOUCH_ID(reg) ((reg) & 0x1f) +#define PIP_TOUCH_TYPE_FINGER 0x00 +#define PIP_TOUCH_TYPE_PROXIMITY 0x01 +#define PIP_TOUCH_TYPE_HOVER 0x02 +#define PIP_GET_TOUCH_TYPE(reg) ((reg) & 0x07) -#define GEN5_CMD_GET_PARAMETER 0x05 -#define GEN5_CMD_SET_PARAMETER 0x06 -#define GEN5_PARAMETER_ACT_INTERVL_ID 0x4d -#define GEN5_PARAMETER_ACT_INTERVL_SIZE 1 -#define GEN5_PARAMETER_ACT_LFT_INTERVL_ID 0x4f -#define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE 2 -#define GEN5_PARAMETER_LP_INTRVL_ID 0x4c -#define GEN5_PARAMETER_LP_INTRVL_SIZE 2 +#define RECORD_EVENT_NONE 0 +#define RECORD_EVENT_TOUCHDOWN 1 +#define RECORD_EVENT_DISPLACE 2 +#define RECORD_EVENT_LIFTOFF 3 -#define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08 +#define PIP_SENSING_MODE_MUTUAL_CAP_FINE 0x00 +#define PIP_SENSING_MODE_SELF_CAP 0x02 + +/* Macro of Gen5 */ +#define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100 +#define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe #define GEN5_POWER_STATE_ACTIVE 0x01 #define GEN5_POWER_STATE_LOOK_FOR_TOUCH 0x02 @@ -89,46 +89,19 @@ #define GEN5_POWER_STATE_BTN_ONLY 0x05 #define GEN5_POWER_STATE_OFF 0x06 -#define GEN5_DEEP_SLEEP_STATE_MASK 0x03 -#define GEN5_DEEP_SLEEP_STATE_ON 0x00 -#define GEN5_DEEP_SLEEP_STATE_OFF 0x01 - -#define GEN5_DEEP_SLEEP_OPCODE 0x08 -#define GEN5_DEEP_SLEEP_OPCODE_MASK 0x0f - #define GEN5_POWER_READY_MAX_INTRVL_TIME 50 /* Unit: ms */ #define GEN5_POWER_IDLE_MAX_INTRVL_TIME 250 /* Unit: ms */ -#define GEN5_CMD_REPORT_ID_OFFSET 4 - -#define GEN5_RESP_REPORT_ID_OFFSET 2 -#define GEN5_RESP_RSVD_OFFSET 3 -#define GEN5_RESP_RSVD_KEY 0x00 -#define GEN5_RESP_BL_SOP_OFFSET 4 -#define GEN5_SOP_KEY 0x01 /* Start of Packet */ -#define GEN5_EOP_KEY 0x17 /* End of Packet */ -#define GEN5_RESP_APP_CMD_OFFSET 4 -#define GET_GEN5_CMD_CODE(reg) ((reg) & 0x7f) - -#define VALID_CMD_RESP_HEADER(resp, cmd) \ - (((resp)[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID) && \ - ((resp)[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) && \ - (GET_GEN5_CMD_CODE((resp)[GEN5_RESP_APP_CMD_OFFSET]) == (cmd))) - -#define GEN5_MIN_BL_CMD_LENGTH 13 -#define GEN5_MIN_BL_RESP_LENGTH 11 -#define GEN5_MIN_APP_CMD_LENGTH 7 -#define GEN5_MIN_APP_RESP_LENGTH 5 -#define GEN5_UNSUPPORTED_CMD_RESP_LENGTH 6 - -#define GEN5_RESP_LENGTH_OFFSET 0x00 -#define GEN5_RESP_LENGTH_SIZE 2 - -#define GEN5_HID_DESCRIPTOR_SIZE 32 -#define GEN5_BL_HID_REPORT_ID 0xff -#define GEN5_APP_HID_REPORT_ID 0xf7 -#define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100 -#define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe +#define GEN5_CMD_GET_PARAMETER 0x05 +#define GEN5_CMD_SET_PARAMETER 0x06 +#define GEN5_PARAMETER_ACT_INTERVL_ID 0x4d +#define GEN5_PARAMETER_ACT_INTERVL_SIZE 1 +#define GEN5_PARAMETER_ACT_LFT_INTERVL_ID 0x4f +#define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE 2 +#define GEN5_PARAMETER_LP_INTRVL_ID 0x4c +#define GEN5_PARAMETER_LP_INTRVL_SIZE 2 + +#define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08 #define GEN5_BL_REPORT_DESCRIPTOR_SIZE 0x1d #define GEN5_BL_REPORT_DESCRIPTOR_ID 0xfe @@ -136,26 +109,6 @@ #define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE 0xfa #define GEN5_APP_REPORT_DESCRIPTOR_ID 0xf6 -#define GEN5_TOUCH_REPORT_ID 0x01 -#define GEN5_BTN_REPORT_ID 0x03 -#define GEN5_WAKEUP_EVENT_REPORT_ID 0x04 -#define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 -#define GEN5_PUSH_BTN_REPORT_ID 0x06 - -#define GEN5_CMD_COMPLETE_SUCCESS(status) ((status) == 0x00) - -#define GEN5_BL_INITIATE_RESP_LEN 11 -#define GEN5_BL_FAIL_EXIT_RESP_LEN 11 -#define GEN5_BL_FAIL_EXIT_STATUS_CODE 0x0c -#define GEN5_BL_VERIFY_INTEGRITY_RESP_LEN 12 -#define GEN5_BL_INTEGRITY_CHEKC_PASS 0x00 -#define GEN5_BL_BLOCK_WRITE_RESP_LEN 11 -#define GEN5_BL_READ_APP_INFO_RESP_LEN 31 -#define GEN5_CMD_CALIBRATE 0x28 -#define CYAPA_SENSING_MODE_MUTUAL_CAP_FINE 0x00 -#define CYAPA_SENSING_MODE_SELF_CAP 0x02 - -#define GEN5_CMD_RETRIEVE_DATA_STRUCTURE 0x24 #define GEN5_RETRIEVE_MUTUAL_PWC_DATA 0x00 #define GEN5_RETRIEVE_SELF_CAP_PWC_DATA 0x01 @@ -170,23 +123,12 @@ #define GEN5_PANEL_SCAN_SELF_BASELINE 0x04 #define GEN5_PANEL_SCAN_SELF_DIFFCOUNT 0x05 -/* The offset only valid for reterive PWC and panel scan commands */ +/* The offset only valid for retrieve PWC and panel scan commands */ #define GEN5_RESP_DATA_STRUCTURE_OFFSET 10 #define GEN5_PWC_DATA_ELEMENT_SIZE_MASK 0x07 -#define GEN5_NUMBER_OF_TOUCH_OFFSET 5 -#define GEN5_NUMBER_OF_TOUCH_MASK 0x1f -#define GEN5_BUTTONS_OFFSET 5 -#define GEN5_BUTTONS_MASK 0x0f -#define GEN5_GET_EVENT_ID(reg) (((reg) >> 5) & 0x03) -#define GEN5_GET_TOUCH_ID(reg) ((reg) & 0x1f) - -#define GEN5_PRODUCT_FAMILY_MASK 0xf000 -#define GEN5_PRODUCT_FAMILY_TRACKPAD 0x1000 - -#define TSG_INVALID_CMD 0xff -struct cyapa_gen5_touch_record { +struct cyapa_pip_touch_record { /* * Bit 7 - 3: reserved * Bit 2 - 0: touch type; @@ -221,7 +163,11 @@ struct cyapa_gen5_touch_record { /* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */ u8 y_hi; - /* Touch intensity in counts, pressure value. */ + /* + * The meaning of this value is different when touch_type is different. + * For standard finger type: + * Touch intensity in counts, pressure value. + **/ u8 z; /* @@ -260,9 +206,9 @@ struct cyapa_gen5_touch_record { u8 orientation; } __packed; -struct cyapa_gen5_report_data { - u8 report_head[GEN5_TOUCH_REPORT_HEAD_SIZE]; - struct cyapa_gen5_touch_record touch_records[10]; +struct cyapa_pip_report_data { + u8 report_head[PIP_TOUCH_REPORT_HEAD_SIZE]; + struct cyapa_pip_touch_record touch_records[10]; } __packed; struct cyapa_tsg_bin_image_head { @@ -288,36 +234,36 @@ struct cyapa_tsg_bin_image { struct cyapa_tsg_bin_image_data_record records[0]; } __packed; -struct gen5_bl_packet_start { +struct pip_bl_packet_start { u8 sop; /* Start of packet, must be 01h */ u8 cmd_code; __le16 data_length; /* Size of data parameter start from data[0] */ } __packed; -struct gen5_bl_packet_end { +struct pip_bl_packet_end { __le16 crc; u8 eop; /* End of packet, must be 17h */ } __packed; -struct gen5_bl_cmd_head { +struct pip_bl_cmd_head { __le16 addr; /* Output report register address, must be 0004h */ /* Size of packet not including output report register address */ __le16 length; u8 report_id; /* Bootloader output report id, must be 40h */ u8 rsvd; /* Reserved, must be 0 */ - struct gen5_bl_packet_start packet_start; + struct pip_bl_packet_start packet_start; u8 data[0]; /* Command data variable based on commands */ } __packed; /* Initiate bootload command data structure. */ -struct gen5_bl_initiate_cmd_data { +struct pip_bl_initiate_cmd_data { /* Key must be "A5h 01h 02h 03h FFh FEh FDh 5Ah" */ u8 key[CYAPA_TSG_BL_KEY_SIZE]; u8 metadata_raw_parameter[CYAPA_TSG_FLASH_MAP_METADATA_SIZE]; __le16 metadata_crc; } __packed; -struct gen5_bl_metadata_row_params { +struct tsg_bl_metadata_row_params { __le16 size; __le16 maximum_size; __le32 app_start; @@ -332,13 +278,13 @@ struct gen5_bl_metadata_row_params { } __packed; /* Bootload program and verify row command data structure */ -struct gen5_bl_flash_row_head { +struct tsg_bl_flash_row_head { u8 flash_array_id; __le16 flash_row_id; u8 flash_data[0]; } __packed; -struct gen5_app_cmd_head { +struct pip_app_cmd_head { __le16 addr; /* Output report register address, must be 0004h */ /* Size of packet not including output report register address */ __le16 length; @@ -369,30 +315,26 @@ struct gen5_retrieve_panel_scan_data { u8 data_id; } __packed; -/* Variables to record latest gen5 trackpad power states. */ -#define GEN5_DEV_SET_PWR_STATE(cyapa, s) ((cyapa)->dev_pwr_mode = (s)) -#define GEN5_DEV_GET_PWR_STATE(cyapa) ((cyapa)->dev_pwr_mode) -#define GEN5_DEV_SET_SLEEP_TIME(cyapa, t) ((cyapa)->dev_sleep_time = (t)) -#define GEN5_DEV_GET_SLEEP_TIME(cyapa) ((cyapa)->dev_sleep_time) -#define GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) \ - (((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME) - +u8 pip_read_sys_info[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02 }; +u8 pip_bl_read_app_info[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00, + 0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17 + }; -static u8 cyapa_gen5_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03, +static u8 cyapa_pip_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03, 0xff, 0xfe, 0xfd, 0x5a }; -static int cyapa_gen5_initialize(struct cyapa *cyapa) +int cyapa_pip_cmd_state_initialize(struct cyapa *cyapa) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; - init_completion(&gen5_pip->cmd_ready); - atomic_set(&gen5_pip->cmd_issued, 0); - mutex_init(&gen5_pip->cmd_lock); + init_completion(&pip->cmd_ready); + atomic_set(&pip->cmd_issued, 0); + mutex_init(&pip->cmd_lock); - gen5_pip->resp_sort_func = NULL; - gen5_pip->in_progress_cmd = TSG_INVALID_CMD; - gen5_pip->resp_data = NULL; - gen5_pip->resp_len = NULL; + pip->resp_sort_func = NULL; + pip->in_progress_cmd = PIP_INVALID_CMD; + pip->resp_data = NULL; + pip->resp_len = NULL; cyapa->dev_pwr_mode = UNINIT_PWR_MODE; cyapa->dev_sleep_time = UNINIT_SLEEP_TIME; @@ -401,7 +343,7 @@ static int cyapa_gen5_initialize(struct cyapa *cyapa) } /* Return negative errno, or else the number of bytes read. */ -static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size) +ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size) { int ret; @@ -415,14 +357,13 @@ static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size) if (ret != size) return (ret < 0) ? ret : -EIO; - return size; } /** * Return a negative errno code else zero on success. */ -static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) +ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) { int ret; @@ -441,10 +382,10 @@ static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) * This function is aimed to dump all not read data in Gen5 trackpad * before send any command, otherwise, the interrupt line will be blocked. */ -static int cyapa_empty_pip_output_data(struct cyapa *cyapa, +int cyapa_empty_pip_output_data(struct cyapa *cyapa, u8 *buf, int *len, cb_sort func) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int length; int report_count; int empty_count; @@ -476,13 +417,13 @@ static int cyapa_empty_pip_output_data(struct cyapa *cyapa, if (empty_count > 5) return 0; - error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, - GEN5_RESP_LENGTH_SIZE); + error = cyapa_i2c_pip_read(cyapa, pip->empty_buf, + PIP_RESP_LENGTH_SIZE); if (error < 0) return error; - length = get_unaligned_le16(gen5_pip->empty_buf); - if (length == GEN5_RESP_LENGTH_SIZE) { + length = get_unaligned_le16(pip->empty_buf); + if (length == PIP_RESP_LENGTH_SIZE) { empty_count++; continue; } else if (length > CYAPA_REG_MAP_SIZE) { @@ -490,11 +431,11 @@ static int cyapa_empty_pip_output_data(struct cyapa *cyapa, return -EINVAL; } else if (length == 0) { /* Application or bootloader launch data polled out. */ - length = GEN5_RESP_LENGTH_SIZE; + length = PIP_RESP_LENGTH_SIZE; if (buf && buf_len && func && - func(cyapa, gen5_pip->empty_buf, length)) { + func(cyapa, pip->empty_buf, length)) { length = min(buf_len, length); - memcpy(buf, gen5_pip->empty_buf, length); + memcpy(buf, pip->empty_buf, length); *len = length; /* Response found, success. */ return 0; @@ -502,19 +443,19 @@ static int cyapa_empty_pip_output_data(struct cyapa *cyapa, continue; } - error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length); + error = cyapa_i2c_pip_read(cyapa, pip->empty_buf, length); if (error < 0) return error; report_count--; empty_count = 0; - length = get_unaligned_le16(gen5_pip->empty_buf); - if (length <= GEN5_RESP_LENGTH_SIZE) { + length = get_unaligned_le16(pip->empty_buf); + if (length <= PIP_RESP_LENGTH_SIZE) { empty_count++; } else if (buf && buf_len && func && - func(cyapa, gen5_pip->empty_buf, length)) { + func(cyapa, pip->empty_buf, length)) { length = min(buf_len, length); - memcpy(buf, gen5_pip->empty_buf, length); + memcpy(buf, pip->empty_buf, length); *len = length; /* Response found, success. */ return 0; @@ -531,24 +472,24 @@ static int cyapa_do_i2c_pip_cmd_irq_sync( u8 *cmd, size_t cmd_len, unsigned long timeout) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int error; /* Wait for interrupt to set ready completion */ - init_completion(&gen5_pip->cmd_ready); + init_completion(&pip->cmd_ready); - atomic_inc(&gen5_pip->cmd_issued); + atomic_inc(&pip->cmd_issued); error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len); if (error) { - atomic_dec(&gen5_pip->cmd_issued); + atomic_dec(&pip->cmd_issued); return (error < 0) ? error : -EIO; } /* Wait for interrupt to indicate command is completed. */ - timeout = wait_for_completion_timeout(&gen5_pip->cmd_ready, + timeout = wait_for_completion_timeout(&pip->cmd_ready, msecs_to_jiffies(timeout)); if (timeout == 0) { - atomic_dec(&gen5_pip->cmd_issued); + atomic_dec(&pip->cmd_issued); return -ETIMEDOUT; } @@ -562,15 +503,15 @@ static int cyapa_do_i2c_pip_cmd_polling( unsigned long timeout, cb_sort func) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int tries; int length; int error; - atomic_inc(&gen5_pip->cmd_issued); + atomic_inc(&pip->cmd_issued); error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len); if (error) { - atomic_dec(&gen5_pip->cmd_issued); + atomic_dec(&pip->cmd_issued); return error < 0 ? error : -EIO; } @@ -591,11 +532,11 @@ static int cyapa_do_i2c_pip_cmd_polling( error = error ? error : -ETIMEDOUT; } - atomic_dec(&gen5_pip->cmd_issued); + atomic_dec(&pip->cmd_issued); return error; } -static int cyapa_i2c_pip_cmd_irq_sync( +int cyapa_i2c_pip_cmd_irq_sync( struct cyapa *cyapa, u8 *cmd, int cmd_len, u8 *resp_data, int *resp_len, @@ -603,34 +544,34 @@ static int cyapa_i2c_pip_cmd_irq_sync( cb_sort func, bool irq_mode) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int error; if (!cmd || !cmd_len) return -EINVAL; /* Commands must be serialized. */ - error = mutex_lock_interruptible(&gen5_pip->cmd_lock); + error = mutex_lock_interruptible(&pip->cmd_lock); if (error) return error; - gen5_pip->resp_sort_func = func; - gen5_pip->resp_data = resp_data; - gen5_pip->resp_len = resp_len; + pip->resp_sort_func = func; + pip->resp_data = resp_data; + pip->resp_len = resp_len; - if (cmd_len >= GEN5_MIN_APP_CMD_LENGTH && - cmd[4] == GEN5_APP_CMD_REPORT_ID) { + if (cmd_len >= PIP_MIN_APP_CMD_LENGTH && + cmd[4] == PIP_APP_CMD_REPORT_ID) { /* Application command */ - gen5_pip->in_progress_cmd = cmd[6] & 0x7f; - } else if (cmd_len >= GEN5_MIN_BL_CMD_LENGTH && - cmd[4] == GEN5_BL_CMD_REPORT_ID) { + pip->in_progress_cmd = cmd[6] & 0x7f; + } else if (cmd_len >= PIP_MIN_BL_CMD_LENGTH && + cmd[4] == PIP_BL_CMD_REPORT_ID) { /* Bootloader command */ - gen5_pip->in_progress_cmd = cmd[7]; + pip->in_progress_cmd = cmd[7]; } /* Send command data, wait and read output response data's length. */ if (irq_mode) { - gen5_pip->is_irq_mode = true; + pip->is_irq_mode = true; error = cyapa_do_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, timeout); if (error == -ETIMEDOUT && resp_data && @@ -646,54 +587,54 @@ static int cyapa_i2c_pip_cmd_irq_sync( error = error ? error : -ETIMEDOUT; } } else { - gen5_pip->is_irq_mode = false; + pip->is_irq_mode = false; error = cyapa_do_i2c_pip_cmd_polling(cyapa, cmd, cmd_len, resp_data, resp_len, timeout, func); } - gen5_pip->resp_sort_func = NULL; - gen5_pip->resp_data = NULL; - gen5_pip->resp_len = NULL; - gen5_pip->in_progress_cmd = TSG_INVALID_CMD; + pip->resp_sort_func = NULL; + pip->resp_data = NULL; + pip->resp_len = NULL; + pip->in_progress_cmd = PIP_INVALID_CMD; - mutex_unlock(&gen5_pip->cmd_lock); + mutex_unlock(&pip->cmd_lock); return error; } -static bool cyapa_gen5_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa, +bool cyapa_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa, u8 *data, int len) { - if (!data || len < GEN5_MIN_BL_RESP_LENGTH) + if (!data || len < PIP_MIN_BL_RESP_LENGTH) return false; /* Bootloader input report id 30h */ - if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_RESP_REPORT_ID && - data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY && - data[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY) + if (data[PIP_RESP_REPORT_ID_OFFSET] == PIP_BL_RESP_REPORT_ID && + data[PIP_RESP_RSVD_OFFSET] == PIP_RESP_RSVD_KEY && + data[PIP_RESP_BL_SOP_OFFSET] == PIP_SOP_KEY) return true; return false; } -static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa, +bool cyapa_sort_tsg_pip_app_resp_data(struct cyapa *cyapa, u8 *data, int len) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int resp_len; - if (!data || len < GEN5_MIN_APP_RESP_LENGTH) + if (!data || len < PIP_MIN_APP_RESP_LENGTH) return false; - if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID && - data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) { - resp_len = get_unaligned_le16(&data[GEN5_RESP_LENGTH_OFFSET]); - if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == 0x00 && - resp_len == GEN5_UNSUPPORTED_CMD_RESP_LENGTH && - data[5] == gen5_pip->in_progress_cmd) { + if (data[PIP_RESP_REPORT_ID_OFFSET] == PIP_APP_RESP_REPORT_ID && + data[PIP_RESP_RSVD_OFFSET] == PIP_RESP_RSVD_KEY) { + resp_len = get_unaligned_le16(&data[PIP_RESP_LENGTH_OFFSET]); + if (GET_PIP_CMD_CODE(data[PIP_RESP_APP_CMD_OFFSET]) == 0x00 && + resp_len == PIP_UNSUPPORTED_CMD_RESP_LENGTH && + data[5] == pip->in_progress_cmd) { /* Unsupported command code */ return false; - } else if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == - gen5_pip->in_progress_cmd) { + } else if (GET_PIP_CMD_CODE(data[PIP_RESP_APP_CMD_OFFSET]) == + pip->in_progress_cmd) { /* Correct command response received */ return true; } @@ -702,10 +643,10 @@ static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa, return false; } -static bool cyapa_gen5_sort_application_launch_data(struct cyapa *cyapa, +static bool cyapa_sort_pip_application_launch_data(struct cyapa *cyapa, u8 *buf, int len) { - if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE) + if (buf == NULL || len < PIP_RESP_LENGTH_SIZE) return false; /* @@ -718,25 +659,25 @@ static bool cyapa_gen5_sort_application_launch_data(struct cyapa *cyapa, return false; } -static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa, +static bool cyapa_sort_gen5_hid_descriptor_data(struct cyapa *cyapa, u8 *buf, int len) { int resp_len; int max_output_len; /* Check hid descriptor. */ - if (len != GEN5_HID_DESCRIPTOR_SIZE) + if (len != PIP_HID_DESCRIPTOR_SIZE) return false; - resp_len = get_unaligned_le16(&buf[GEN5_RESP_LENGTH_OFFSET]); + resp_len = get_unaligned_le16(&buf[PIP_RESP_LENGTH_OFFSET]); max_output_len = get_unaligned_le16(&buf[16]); - if (resp_len == GEN5_HID_DESCRIPTOR_SIZE) { - if (buf[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_HID_REPORT_ID && + if (resp_len == PIP_HID_DESCRIPTOR_SIZE) { + if (buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID && max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { /* BL mode HID Descriptor */ return true; - } else if ((buf[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_APP_HID_REPORT_ID) && + } else if ((buf[PIP_RESP_REPORT_ID_OFFSET] == + PIP_HID_APP_REPORT_ID) && max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { /* APP mode HID Descriptor */ return true; @@ -746,21 +687,21 @@ static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa, return false; } -static bool cyapa_gen5_sort_deep_sleep_data(struct cyapa *cyapa, +static bool cyapa_sort_pip_deep_sleep_data(struct cyapa *cyapa, u8 *buf, int len) { - if (len == GEN5_DEEP_SLEEP_RESP_LENGTH && - buf[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_APP_DEEP_SLEEP_REPORT_ID && - (buf[4] & GEN5_DEEP_SLEEP_OPCODE_MASK) == - GEN5_DEEP_SLEEP_OPCODE) + if (len == PIP_DEEP_SLEEP_RESP_LENGTH && + buf[PIP_RESP_REPORT_ID_OFFSET] == + PIP_APP_DEEP_SLEEP_REPORT_ID && + (buf[4] & PIP_DEEP_SLEEP_OPCODE_MASK) == + PIP_DEEP_SLEEP_OPCODE) return true; return false; } static int gen5_idle_state_parse(struct cyapa *cyapa) { - u8 resp_data[GEN5_HID_DESCRIPTOR_SIZE]; + u8 resp_data[PIP_HID_DESCRIPTOR_SIZE]; int max_output_len; int length; u8 cmd[2]; @@ -778,9 +719,9 @@ static int gen5_idle_state_parse(struct cyapa *cyapa) if (ret != 3) return ret < 0 ? ret : -EIO; - length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]); - if (length == GEN5_RESP_LENGTH_SIZE) { - /* Normal state of Gen5 with no data to respose */ + length = get_unaligned_le16(&resp_data[PIP_RESP_LENGTH_OFFSET]); + if (length == PIP_RESP_LENGTH_SIZE) { + /* Normal state of Gen5 with no data to response */ cyapa->gen = CYAPA_GEN5; cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); @@ -788,30 +729,30 @@ static int gen5_idle_state_parse(struct cyapa *cyapa) /* Read description from trackpad device */ cmd[0] = 0x01; cmd[1] = 0x00; - length = GEN5_HID_DESCRIPTOR_SIZE; + length = PIP_HID_DESCRIPTOR_SIZE; error = cyapa_i2c_pip_cmd_irq_sync(cyapa, - cmd, GEN5_RESP_LENGTH_SIZE, + cmd, PIP_RESP_LENGTH_SIZE, resp_data, &length, 300, - cyapa_gen5_sort_hid_descriptor_data, + cyapa_sort_gen5_hid_descriptor_data, false); if (error) return error; length = get_unaligned_le16( - &resp_data[GEN5_RESP_LENGTH_OFFSET]); + &resp_data[PIP_RESP_LENGTH_OFFSET]); max_output_len = get_unaligned_le16(&resp_data[16]); - if ((length == GEN5_HID_DESCRIPTOR_SIZE || - length == GEN5_RESP_LENGTH_SIZE) && - (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_HID_REPORT_ID) && + if ((length == PIP_HID_DESCRIPTOR_SIZE || + length == PIP_RESP_LENGTH_SIZE) && + (resp_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_HID_BL_REPORT_ID) && max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { /* BL mode HID Description read */ cyapa->state = CYAPA_STATE_GEN5_BL; - } else if ((length == GEN5_HID_DESCRIPTOR_SIZE || - length == GEN5_RESP_LENGTH_SIZE) && - (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_APP_HID_REPORT_ID) && + } else if ((length == PIP_HID_DESCRIPTOR_SIZE || + length == PIP_RESP_LENGTH_SIZE) && + (resp_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_HID_APP_REPORT_ID) && max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { /* APP mode HID Description read */ cyapa->state = CYAPA_STATE_GEN5_APP; @@ -839,14 +780,14 @@ static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data) * or report any touch or button data. */ ret = cyapa_i2c_pip_read(cyapa, resp_data, - GEN5_HID_DESCRIPTOR_SIZE); - if (ret != GEN5_HID_DESCRIPTOR_SIZE) + PIP_HID_DESCRIPTOR_SIZE); + if (ret != PIP_HID_DESCRIPTOR_SIZE) return ret < 0 ? ret : -EIO; - length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]); + length = get_unaligned_le16(&resp_data[PIP_RESP_LENGTH_OFFSET]); max_output_len = get_unaligned_le16(&resp_data[16]); - if (length == GEN5_RESP_LENGTH_SIZE) { - if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_HID_REPORT_ID) { + if (length == PIP_RESP_LENGTH_SIZE) { + if (reg_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_HID_BL_REPORT_ID) { /* * BL mode HID Description has been previously * read out. @@ -861,15 +802,15 @@ static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data) cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_APP; } - } else if (length == GEN5_HID_DESCRIPTOR_SIZE && - resp_data[2] == GEN5_BL_HID_REPORT_ID && + } else if (length == PIP_HID_DESCRIPTOR_SIZE && + resp_data[2] == PIP_HID_BL_REPORT_ID && max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { /* BL mode HID Description read. */ cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_BL; - } else if (length == GEN5_HID_DESCRIPTOR_SIZE && - (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_APP_HID_REPORT_ID) && + } else if (length == PIP_HID_DESCRIPTOR_SIZE && + (resp_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_HID_APP_REPORT_ID) && max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { /* APP mode HID Description read. */ cyapa->gen = CYAPA_GEN5; @@ -886,22 +827,22 @@ static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data) { int length; - length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); - switch (reg_data[GEN5_RESP_REPORT_ID_OFFSET]) { - case GEN5_TOUCH_REPORT_ID: - if (length < GEN5_TOUCH_REPORT_HEAD_SIZE || - length > GEN5_TOUCH_REPORT_MAX_SIZE) + length = get_unaligned_le16(®_data[PIP_RESP_LENGTH_OFFSET]); + switch (reg_data[PIP_RESP_REPORT_ID_OFFSET]) { + case PIP_TOUCH_REPORT_ID: + if (length < PIP_TOUCH_REPORT_HEAD_SIZE || + length > PIP_TOUCH_REPORT_MAX_SIZE) return -EINVAL; break; - case GEN5_BTN_REPORT_ID: + case PIP_BTN_REPORT_ID: case GEN5_OLD_PUSH_BTN_REPORT_ID: - case GEN5_PUSH_BTN_REPORT_ID: - if (length < GEN5_BTN_REPORT_HEAD_SIZE || - length > GEN5_BTN_REPORT_MAX_SIZE) + case PIP_PUSH_BTN_REPORT_ID: + if (length < PIP_BTN_REPORT_HEAD_SIZE || + length > PIP_BTN_REPORT_MAX_SIZE) return -EINVAL; break; - case GEN5_WAKEUP_EVENT_REPORT_ID: - if (length != GEN5_WAKEUP_EVENT_SIZE) + case PIP_WAKEUP_EVENT_REPORT_ID: + if (length != PIP_WAKEUP_EVENT_SIZE) return -EINVAL; break; default: @@ -915,7 +856,7 @@ static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data) static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int length; int ret; @@ -924,15 +865,15 @@ static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data) * otherwise Gen5 trackpad cannot response next command * or report any touch or button data. */ - length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); - ret = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length); + length = get_unaligned_le16(®_data[PIP_RESP_LENGTH_OFFSET]); + ret = cyapa_i2c_pip_read(cyapa, pip->empty_buf, length); if (ret != length) return ret < 0 ? ret : -EIO; - if (length == GEN5_RESP_LENGTH_SIZE) { + if (length == PIP_RESP_LENGTH_SIZE) { /* Previous command has read the data through out. */ - if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_RESP_REPORT_ID) { + if (reg_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_BL_RESP_REPORT_ID) { /* Gen5 BL command response data detected */ cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_BL; @@ -941,21 +882,21 @@ static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data) cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_APP; } - } else if ((gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_RESP_REPORT_ID) && - (gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] == - GEN5_RESP_RSVD_KEY) && - (gen5_pip->empty_buf[GEN5_RESP_BL_SOP_OFFSET] == - GEN5_SOP_KEY) && - (gen5_pip->empty_buf[length - 1] == - GEN5_EOP_KEY)) { + } else if ((pip->empty_buf[PIP_RESP_REPORT_ID_OFFSET] == + PIP_BL_RESP_REPORT_ID) && + (pip->empty_buf[PIP_RESP_RSVD_OFFSET] == + PIP_RESP_RSVD_KEY) && + (pip->empty_buf[PIP_RESP_BL_SOP_OFFSET] == + PIP_SOP_KEY) && + (pip->empty_buf[length - 1] == + PIP_EOP_KEY)) { /* Gen5 BL command response data detected */ cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_BL; - } else if (gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_APP_RESP_REPORT_ID && - gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] == - GEN5_RESP_RSVD_KEY) { + } else if (pip->empty_buf[PIP_RESP_REPORT_ID_OFFSET] == + PIP_APP_RESP_REPORT_ID && + pip->empty_buf[PIP_RESP_RSVD_OFFSET] == + PIP_RESP_RSVD_KEY) { /* Gen5 APP command response data detected */ cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_APP; @@ -977,12 +918,12 @@ static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) cyapa->state = CYAPA_STATE_NO_DEVICE; /* Parse based on Gen5 characteristic registers and bits */ - length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); - if (length == 0 || length == GEN5_RESP_LENGTH_SIZE) { + length = get_unaligned_le16(®_data[PIP_RESP_LENGTH_OFFSET]); + if (length == 0 || length == PIP_RESP_LENGTH_SIZE) { gen5_idle_state_parse(cyapa); - } else if (length == GEN5_HID_DESCRIPTOR_SIZE && - (reg_data[2] == GEN5_BL_HID_REPORT_ID || - reg_data[2] == GEN5_APP_HID_REPORT_ID)) { + } else if (length == PIP_HID_DESCRIPTOR_SIZE && + (reg_data[2] == PIP_HID_BL_REPORT_ID || + reg_data[2] == PIP_HID_APP_REPORT_ID)) { gen5_hid_description_header_parse(cyapa, reg_data); } else if ((length == GEN5_APP_REPORT_DESCRIPTOR_SIZE || length == GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE) && @@ -992,17 +933,17 @@ static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) cyapa->state = CYAPA_STATE_GEN5_APP; } else if (length == GEN5_BL_REPORT_DESCRIPTOR_SIZE && reg_data[2] == GEN5_BL_REPORT_DESCRIPTOR_ID) { - /* 0x1D 0x00 0xFE is Gen5 BL report descriptior header. */ + /* 0x1D 0x00 0xFE is Gen5 BL report descriptor header. */ cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_BL; - } else if (reg_data[2] == GEN5_TOUCH_REPORT_ID || - reg_data[2] == GEN5_BTN_REPORT_ID || + } else if (reg_data[2] == PIP_TOUCH_REPORT_ID || + reg_data[2] == PIP_BTN_REPORT_ID || reg_data[2] == GEN5_OLD_PUSH_BTN_REPORT_ID || - reg_data[2] == GEN5_PUSH_BTN_REPORT_ID || - reg_data[2] == GEN5_WAKEUP_EVENT_REPORT_ID) { + reg_data[2] == PIP_PUSH_BTN_REPORT_ID || + reg_data[2] == PIP_WAKEUP_EVENT_REPORT_ID) { gen5_report_data_header_parse(cyapa, reg_data); - } else if (reg_data[2] == GEN5_BL_RESP_REPORT_ID || - reg_data[2] == GEN5_APP_RESP_REPORT_ID) { + } else if (reg_data[2] == PIP_BL_RESP_REPORT_ID || + reg_data[2] == PIP_APP_RESP_REPORT_ID) { gen5_cmd_resp_header_parse(cyapa, reg_data); } @@ -1023,14 +964,25 @@ static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) return -EAGAIN; } -static int cyapa_gen5_bl_initiate(struct cyapa *cyapa, - const struct firmware *fw) +static struct cyapa_tsg_bin_image_data_record * +cyapa_get_image_record_data_num(const struct firmware *fw, + int *record_num) +{ + int head_size; + + head_size = fw->data[0] + 1; + *record_num = (fw->size - head_size) / + sizeof(struct cyapa_tsg_bin_image_data_record); + return (struct cyapa_tsg_bin_image_data_record *)&fw->data[head_size]; +} + +int cyapa_pip_bl_initiate(struct cyapa *cyapa, const struct firmware *fw) { - struct cyapa_tsg_bin_image *image; - struct gen5_bl_cmd_head *bl_cmd_head; - struct gen5_bl_packet_start *bl_packet_start; - struct gen5_bl_initiate_cmd_data *cmd_data; - struct gen5_bl_packet_end *bl_packet_end; + struct cyapa_tsg_bin_image_data_record *image_records; + struct pip_bl_cmd_head *bl_cmd_head; + struct pip_bl_packet_start *bl_packet_start; + struct pip_bl_initiate_cmd_data *cmd_data; + struct pip_bl_packet_end *bl_packet_end; u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; int cmd_len; u16 cmd_data_len; @@ -1046,30 +998,28 @@ static int cyapa_gen5_bl_initiate(struct cyapa *cyapa, cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); - bl_cmd_head = (struct gen5_bl_cmd_head *)cmd; + bl_cmd_head = (struct pip_bl_cmd_head *)cmd; cmd_data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE; - cmd_len = sizeof(struct gen5_bl_cmd_head) + cmd_data_len + - sizeof(struct gen5_bl_packet_end); + cmd_len = sizeof(struct pip_bl_cmd_head) + cmd_data_len + + sizeof(struct pip_bl_packet_end); - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length); - bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID; + bl_cmd_head->report_id = PIP_BL_CMD_REPORT_ID; bl_packet_start = &bl_cmd_head->packet_start; - bl_packet_start->sop = GEN5_SOP_KEY; - bl_packet_start->cmd_code = GEN5_BL_CMD_INITIATE_BL; + bl_packet_start->sop = PIP_SOP_KEY; + bl_packet_start->cmd_code = PIP_BL_CMD_INITIATE_BL; /* 8 key bytes and 128 bytes block size */ put_unaligned_le16(cmd_data_len, &bl_packet_start->data_length); - cmd_data = (struct gen5_bl_initiate_cmd_data *)bl_cmd_head->data; - memcpy(cmd_data->key, cyapa_gen5_bl_cmd_key, CYAPA_TSG_BL_KEY_SIZE); + cmd_data = (struct pip_bl_initiate_cmd_data *)bl_cmd_head->data; + memcpy(cmd_data->key, cyapa_pip_bl_cmd_key, CYAPA_TSG_BL_KEY_SIZE); + + image_records = cyapa_get_image_record_data_num(fw, &records_num); - /* Copy 60 bytes Meta Data Row Parameters */ - image = (struct cyapa_tsg_bin_image *)fw->data; - records_num = (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) / - sizeof(struct cyapa_tsg_bin_image_data_record); /* APP_INTEGRITY row is always the last row block */ - data = image->records[records_num - 1].record_data; + data = image_records[records_num - 1].record_data; memcpy(cmd_data->metadata_raw_parameter, data, CYAPA_TSG_FLASH_MAP_METADATA_SIZE); @@ -1077,47 +1027,47 @@ static int cyapa_gen5_bl_initiate(struct cyapa *cyapa, CYAPA_TSG_FLASH_MAP_METADATA_SIZE); put_unaligned_le16(meta_data_crc, &cmd_data->metadata_crc); - bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data + + bl_packet_end = (struct pip_bl_packet_end *)(bl_cmd_head->data + cmd_data_len); cmd_crc = crc_itu_t(0xffff, (u8 *)bl_packet_start, - sizeof(struct gen5_bl_packet_start) + cmd_data_len); + sizeof(struct pip_bl_packet_start) + cmd_data_len); put_unaligned_le16(cmd_crc, &bl_packet_end->crc); - bl_packet_end->eop = GEN5_EOP_KEY; + bl_packet_end->eop = PIP_EOP_KEY; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, resp_data, &resp_len, 12000, - cyapa_gen5_sort_tsg_pip_bl_resp_data, true); - if (error || resp_len != GEN5_BL_INITIATE_RESP_LEN || - resp_data[2] != GEN5_BL_RESP_REPORT_ID || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + cyapa_sort_tsg_pip_bl_resp_data, true); + if (error || resp_len != PIP_BL_INITIATE_RESP_LEN || + resp_data[2] != PIP_BL_RESP_REPORT_ID || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error ? error : -EAGAIN; return 0; } -static bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len) +static bool cyapa_sort_pip_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len) { - if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE) + if (buf == NULL || len < PIP_RESP_LENGTH_SIZE) return false; if (buf[0] == 0 && buf[1] == 0) return true; /* Exit bootloader failed for some reason. */ - if (len == GEN5_BL_FAIL_EXIT_RESP_LEN && - buf[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_RESP_REPORT_ID && - buf[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY && - buf[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY && - buf[10] == GEN5_EOP_KEY) + if (len == PIP_BL_FAIL_EXIT_RESP_LEN && + buf[PIP_RESP_REPORT_ID_OFFSET] == + PIP_BL_RESP_REPORT_ID && + buf[PIP_RESP_RSVD_OFFSET] == PIP_RESP_RSVD_KEY && + buf[PIP_RESP_BL_SOP_OFFSET] == PIP_SOP_KEY && + buf[10] == PIP_EOP_KEY) return true; return false; } -static int cyapa_gen5_bl_exit(struct cyapa *cyapa) +int cyapa_pip_bl_exit(struct cyapa *cyapa) { u8 bl_gen5_bl_exit[] = { 0x04, 0x00, @@ -1132,13 +1082,13 @@ static int cyapa_gen5_bl_exit(struct cyapa *cyapa) error = cyapa_i2c_pip_cmd_irq_sync(cyapa, bl_gen5_bl_exit, sizeof(bl_gen5_bl_exit), resp_data, &resp_len, - 5000, cyapa_gen5_sort_bl_exit_data, false); + 5000, cyapa_sort_pip_bl_exit_data, false); if (error) return error; - if (resp_len == GEN5_BL_FAIL_EXIT_RESP_LEN || - resp_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_RESP_REPORT_ID) + if (resp_len == PIP_BL_FAIL_EXIT_RESP_LEN || + resp_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_BL_RESP_REPORT_ID) return -EAGAIN; if (resp_data[0] == 0x00 && resp_data[1] == 0x00) @@ -1147,7 +1097,7 @@ static int cyapa_gen5_bl_exit(struct cyapa *cyapa) return -ENODEV; } -static int cyapa_gen5_bl_enter(struct cyapa *cyapa) +int cyapa_pip_bl_enter(struct cyapa *cyapa) { u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 }; u8 resp_data[2]; @@ -1157,15 +1107,12 @@ static int cyapa_gen5_bl_enter(struct cyapa *cyapa) error = cyapa_poll_state(cyapa, 500); if (error < 0) return error; - if (cyapa->gen != CYAPA_GEN5) - return -EINVAL; - /* Already in Gen5 BL. Skipping exit. */ - if (cyapa->state == CYAPA_STATE_GEN5_BL) + /* Already in bootloader mode, Skipping exit. */ + if (cyapa_is_pip_bl_mode(cyapa)) return 0; - - if (cyapa->state != CYAPA_STATE_GEN5_APP) - return -EAGAIN; + else if (!cyapa_is_pip_app_mode(cyapa)) + return -EINVAL; /* Try to dump all buffered report data before any send command. */ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); @@ -1179,39 +1126,38 @@ static int cyapa_gen5_bl_enter(struct cyapa *cyapa) error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 5000, cyapa_gen5_sort_application_launch_data, + 5000, cyapa_sort_pip_application_launch_data, true); if (error || resp_data[0] != 0x00 || resp_data[1] != 0x00) return error < 0 ? error : -EAGAIN; cyapa->operational = false; - cyapa->state = CYAPA_STATE_GEN5_BL; + if (cyapa->gen == CYAPA_GEN5) + cyapa->state = CYAPA_STATE_GEN5_BL; return 0; } -static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw) +int cyapa_pip_check_fw(struct cyapa *cyapa, const struct firmware *fw) { struct device *dev = &cyapa->client->dev; - const struct cyapa_tsg_bin_image *image = (const void *)fw->data; + struct cyapa_tsg_bin_image_data_record *image_records; const struct cyapa_tsg_bin_image_data_record *app_integrity; - const struct gen5_bl_metadata_row_params *metadata; - size_t flash_records_count; + const struct tsg_bl_metadata_row_params *metadata; + int flash_records_count; u32 fw_app_start, fw_upgrade_start; u16 fw_app_len, fw_upgrade_len; u16 app_crc; u16 app_integrity_crc; - int record_index; int i; - flash_records_count = (fw->size - - sizeof(struct cyapa_tsg_bin_image_head)) / - sizeof(struct cyapa_tsg_bin_image_data_record); + image_records = + cyapa_get_image_record_data_num(fw, &flash_records_count); /* * APP_INTEGRITY row is always the last row block, * and the row id must be 0x01ff. */ - app_integrity = &image->records[flash_records_count - 1]; + app_integrity = &image_records[flash_records_count - 1]; if (app_integrity->flash_array_id != 0x00 || get_unaligned_be16(&app_integrity->row_number) != 0x01ff) { @@ -1242,14 +1188,11 @@ static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw) return -EINVAL; } - /* - * Verify application image CRC - */ - record_index = fw_app_start / CYAPA_TSG_FW_ROW_SIZE - - CYAPA_TSG_IMG_START_ROW_NUM; + /* Verify application image CRC. */ app_crc = 0xffffU; for (i = 0; i < fw_app_len / CYAPA_TSG_FW_ROW_SIZE; i++) { - const u8 *data = image->records[record_index + i].record_data; + const u8 *data = image_records[i].record_data; + app_crc = crc_itu_t(app_crc, data, CYAPA_TSG_FW_ROW_SIZE); } @@ -1261,13 +1204,13 @@ static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw) return 0; } -static int cyapa_gen5_write_fw_block(struct cyapa *cyapa, +static int cyapa_pip_write_fw_block(struct cyapa *cyapa, struct cyapa_tsg_bin_image_data_record *flash_record) { - struct gen5_bl_cmd_head *bl_cmd_head; - struct gen5_bl_packet_start *bl_packet_start; - struct gen5_bl_flash_row_head *flash_row_head; - struct gen5_bl_packet_end *bl_packet_end; + struct pip_bl_cmd_head *bl_cmd_head; + struct pip_bl_packet_start *bl_packet_start; + struct tsg_bl_flash_row_head *flash_row_head; + struct pip_bl_packet_end *bl_packet_end; u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; u16 cmd_len; u8 flash_array_id; @@ -1286,71 +1229,68 @@ static int cyapa_gen5_write_fw_block(struct cyapa *cyapa, record_data = flash_record->record_data; memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); - bl_cmd_head = (struct gen5_bl_cmd_head *)cmd; + bl_cmd_head = (struct pip_bl_cmd_head *)cmd; bl_packet_start = &bl_cmd_head->packet_start; - cmd_len = sizeof(struct gen5_bl_cmd_head) + - sizeof(struct gen5_bl_flash_row_head) + + cmd_len = sizeof(struct pip_bl_cmd_head) + + sizeof(struct tsg_bl_flash_row_head) + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE + - sizeof(struct gen5_bl_packet_end); + sizeof(struct pip_bl_packet_end); - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); /* Don't include 2 bytes register address */ put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length); - bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID; - bl_packet_start->sop = GEN5_SOP_KEY; - bl_packet_start->cmd_code = GEN5_BL_CMD_PROGRAM_VERIFY_ROW; + bl_cmd_head->report_id = PIP_BL_CMD_REPORT_ID; + bl_packet_start->sop = PIP_SOP_KEY; + bl_packet_start->cmd_code = PIP_BL_CMD_PROGRAM_VERIFY_ROW; /* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */ - data_len = sizeof(struct gen5_bl_flash_row_head) + record_len; + data_len = sizeof(struct tsg_bl_flash_row_head) + record_len; put_unaligned_le16(data_len, &bl_packet_start->data_length); - flash_row_head = (struct gen5_bl_flash_row_head *)bl_cmd_head->data; + flash_row_head = (struct tsg_bl_flash_row_head *)bl_cmd_head->data; flash_row_head->flash_array_id = flash_array_id; put_unaligned_le16(flash_row_id, &flash_row_head->flash_row_id); memcpy(flash_row_head->flash_data, record_data, record_len); - bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data + + bl_packet_end = (struct pip_bl_packet_end *)(bl_cmd_head->data + data_len); crc = crc_itu_t(0xffff, (u8 *)bl_packet_start, - sizeof(struct gen5_bl_packet_start) + data_len); + sizeof(struct pip_bl_packet_start) + data_len); put_unaligned_le16(crc, &bl_packet_end->crc); - bl_packet_end->eop = GEN5_EOP_KEY; + bl_packet_end->eop = PIP_EOP_KEY; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, true); - if (error || resp_len != GEN5_BL_BLOCK_WRITE_RESP_LEN || - resp_data[2] != GEN5_BL_RESP_REPORT_ID || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + 500, cyapa_sort_tsg_pip_bl_resp_data, true); + if (error || resp_len != PIP_BL_BLOCK_WRITE_RESP_LEN || + resp_data[2] != PIP_BL_RESP_REPORT_ID || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error < 0 ? error : -EAGAIN; return 0; } -static int cyapa_gen5_do_fw_update(struct cyapa *cyapa, +int cyapa_pip_do_fw_update(struct cyapa *cyapa, const struct firmware *fw) { struct device *dev = &cyapa->client->dev; - struct cyapa_tsg_bin_image_data_record *flash_record; - struct cyapa_tsg_bin_image *image = - (struct cyapa_tsg_bin_image *)fw->data; + struct cyapa_tsg_bin_image_data_record *image_records; int flash_records_count; int i; int error; cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); - flash_records_count = - (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) / - sizeof(struct cyapa_tsg_bin_image_data_record); + image_records = + cyapa_get_image_record_data_num(fw, &flash_records_count); + /* * The last flash row 0x01ff has been written through bl_initiate * command, so DO NOT write flash 0x01ff to trackpad device. */ for (i = 0; i < (flash_records_count - 1); i++) { - flash_record = &image->records[i]; - error = cyapa_gen5_write_fw_block(cyapa, flash_record); + error = cyapa_pip_write_fw_block(cyapa, &image_records[i]); if (error) { dev_err(dev, "%s: Gen5 FW update aborted: %d\n", __func__, error); @@ -1372,9 +1312,9 @@ static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state) resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + 500, cyapa_sort_tsg_pip_app_resp_data, false); if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x08) || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error < 0 ? error : -EINVAL; return 0; @@ -1383,7 +1323,7 @@ static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state) static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, u8 parameter_id, u16 interval_time) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; struct gen5_app_set_parameter_data *parameter_data; u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; int cmd_len; @@ -1393,10 +1333,10 @@ static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, int error; memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); - app_cmd_head = (struct gen5_app_cmd_head *)cmd; + app_cmd_head = (struct pip_app_cmd_head *)cmd; parameter_data = (struct gen5_app_set_parameter_data *) app_cmd_head->parameter_data; - cmd_len = sizeof(struct gen5_app_cmd_head) + + cmd_len = sizeof(struct pip_app_cmd_head) + sizeof(struct gen5_app_set_parameter_data); switch (parameter_id) { @@ -1413,14 +1353,14 @@ static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, return -EINVAL; } - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); /* * Don't include unused parameter value bytes and * 2 bytes register address. */ put_unaligned_le16(cmd_len - (4 - parameter_size) - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER; parameter_data->parameter_id = parameter_id; parameter_data->parameter_size = parameter_size; @@ -1428,7 +1368,7 @@ static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + 500, cyapa_sort_tsg_pip_app_resp_data, false); if (error || resp_data[5] != parameter_id || resp_data[6] != parameter_size || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER)) @@ -1440,7 +1380,7 @@ static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, static int cyapa_gen5_get_interval_time(struct cyapa *cyapa, u8 parameter_id, u16 *interval_time) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; struct gen5_app_get_parameter_data *parameter_data; u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; int cmd_len; @@ -1451,10 +1391,10 @@ static int cyapa_gen5_get_interval_time(struct cyapa *cyapa, int error; memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); - app_cmd_head = (struct gen5_app_cmd_head *)cmd; + app_cmd_head = (struct pip_app_cmd_head *)cmd; parameter_data = (struct gen5_app_get_parameter_data *) app_cmd_head->parameter_data; - cmd_len = sizeof(struct gen5_app_cmd_head) + + cmd_len = sizeof(struct pip_app_cmd_head) + sizeof(struct gen5_app_get_parameter_data); *interval_time = 0; @@ -1472,17 +1412,17 @@ static int cyapa_gen5_get_interval_time(struct cyapa *cyapa, return -EINVAL; } - put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); /* Don't include 2 bytes register address */ put_unaligned_le16(cmd_len - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; app_cmd_head->cmd_code = GEN5_CMD_GET_PARAMETER; parameter_data->parameter_id = parameter_id; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + 500, cyapa_sort_tsg_pip_app_resp_data, false); if (error || resp_data[5] != parameter_id || resp_data[6] == 0 || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_GET_PARAMETER)) return error < 0 ? error : -EINVAL; @@ -1497,18 +1437,18 @@ static int cyapa_gen5_get_interval_time(struct cyapa *cyapa, static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; u8 cmd[10]; u8 resp_data[7]; int resp_len; int error; memset(cmd, 0, sizeof(cmd)); - app_cmd_head = (struct gen5_app_cmd_head *)cmd; + app_cmd_head = (struct pip_app_cmd_head *)cmd; - put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER; app_cmd_head->parameter_data[0] = GEN5_PARAMETER_DISABLE_PIP_REPORT; app_cmd_head->parameter_data[1] = 0x01; @@ -1516,7 +1456,7 @@ static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + 500, cyapa_sort_tsg_pip_app_resp_data, false); if (error || resp_data[5] != GEN5_PARAMETER_DISABLE_PIP_REPORT || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER) || resp_data[6] != 0x01) @@ -1525,19 +1465,19 @@ static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) return 0; } -static int cyapa_gen5_deep_sleep(struct cyapa *cyapa, u8 state) +int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state) { u8 cmd[] = { 0x05, 0x00, 0x00, 0x08}; u8 resp_data[5]; int resp_len; int error; - cmd[2] = state & GEN5_DEEP_SLEEP_STATE_MASK; + cmd[2] = state & PIP_DEEP_SLEEP_STATE_MASK; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_deep_sleep_data, false); - if (error || ((resp_data[3] & GEN5_DEEP_SLEEP_STATE_MASK) != state)) + 500, cyapa_sort_pip_deep_sleep_data, false); + if (error || ((resp_data[3] & PIP_DEEP_SLEEP_STATE_MASK) != state)) return -EINVAL; return 0; @@ -1556,40 +1496,40 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, /* Dump all the report data before do power mode commmands. */ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); - if (GEN5_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { + if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { /* * Assume TP in deep sleep mode when driver is loaded, * avoid driver unload and reload command IO issue caused by TP * has been set into deep sleep mode when unloading. */ - GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); } - if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) && - GEN5_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF) + if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) && + PIP_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF) if (cyapa_gen5_get_interval_time(cyapa, GEN5_PARAMETER_LP_INTRVL_ID, &cyapa->dev_sleep_time) != 0) - GEN5_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME); + PIP_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME); - if (GEN5_DEV_GET_PWR_STATE(cyapa) == power_mode) { + if (PIP_DEV_GET_PWR_STATE(cyapa) == power_mode) { if (power_mode == PWR_MODE_OFF || power_mode == PWR_MODE_FULL_ACTIVE || power_mode == PWR_MODE_BTN_ONLY || - GEN5_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { + PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { /* Has in correct power mode state, early return. */ return 0; } } if (power_mode == PWR_MODE_OFF) { - error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_OFF); + error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF); if (error) { dev_err(dev, "enter deep sleep fail: %d\n", error); return error; } - GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); return 0; } @@ -1598,8 +1538,8 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, * state directly, must be wake up from sleep firstly, then * continue to do next power sate change. */ - if (GEN5_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) { - error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_ON); + if (PIP_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) { + error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON); if (error) { dev_err(dev, "deep sleep wake fail: %d\n", error); return error; @@ -1614,7 +1554,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, return error; } - GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE); + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE); } else if (power_mode == PWR_MODE_BTN_ONLY) { error = cyapa_gen5_change_power_state(cyapa, GEN5_POWER_STATE_BTN_ONLY); @@ -1623,19 +1563,19 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, return error; } - GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY); + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY); } else { /* * Continue to change power mode even failed to set * interval time, it won't affect the power mode change. * except the sleep interval time is not correct. */ - if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) || - sleep_time != GEN5_DEV_GET_SLEEP_TIME(cyapa)) + if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) || + sleep_time != PIP_DEV_GET_SLEEP_TIME(cyapa)) if (cyapa_gen5_set_interval_time(cyapa, GEN5_PARAMETER_LP_INTRVL_ID, sleep_time) == 0) - GEN5_DEV_SET_SLEEP_TIME(cyapa, sleep_time); + PIP_DEV_SET_SLEEP_TIME(cyapa, sleep_time); if (sleep_time <= GEN5_POWER_READY_MAX_INTRVL_TIME) power_state = GEN5_POWER_STATE_READY; @@ -1661,14 +1601,14 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); cyapa_gen5_disable_pip_report(cyapa); - GEN5_DEV_SET_PWR_STATE(cyapa, + PIP_DEV_SET_PWR_STATE(cyapa, cyapa_sleep_time_to_pwr_cmd(sleep_time)); } return 0; } -static int cyapa_gen5_resume_scanning(struct cyapa *cyapa) +int cyapa_pip_resume_scanning(struct cyapa *cyapa) { u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 }; u8 resp_data[6]; @@ -1682,7 +1622,7 @@ static int cyapa_gen5_resume_scanning(struct cyapa *cyapa) error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + 500, cyapa_sort_tsg_pip_app_resp_data, true); if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x04)) return -EINVAL; @@ -1692,7 +1632,7 @@ static int cyapa_gen5_resume_scanning(struct cyapa *cyapa) return 0; } -static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa) +int cyapa_pip_suspend_scanning(struct cyapa *cyapa) { u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 }; u8 resp_data[6]; @@ -1706,7 +1646,7 @@ static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa) error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + 500, cyapa_sort_tsg_pip_app_resp_data, true); if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x03)) return -EINVAL; @@ -1716,10 +1656,10 @@ static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa) return 0; } -static int cyapa_gen5_calibrate_pwcs(struct cyapa *cyapa, +static int cyapa_pip_calibrate_pwcs(struct cyapa *cyapa, u8 calibrate_sensing_mode_type) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; u8 cmd[8]; u8 resp_data[6]; int resp_len; @@ -1729,25 +1669,25 @@ static int cyapa_gen5_calibrate_pwcs(struct cyapa *cyapa, cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); memset(cmd, 0, sizeof(cmd)); - app_cmd_head = (struct gen5_app_cmd_head *)cmd; - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + app_cmd_head = (struct pip_app_cmd_head *)cmd; + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; - app_cmd_head->cmd_code = GEN5_CMD_CALIBRATE; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; + app_cmd_head->cmd_code = PIP_CMD_CALIBRATE; app_cmd_head->parameter_data[0] = calibrate_sensing_mode_type; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 5000, cyapa_gen5_sort_tsg_pip_app_resp_data, true); - if (error || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_CALIBRATE) || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + 5000, cyapa_sort_tsg_pip_app_resp_data, true); + if (error || !VALID_CMD_RESP_HEADER(resp_data, PIP_CMD_CALIBRATE) || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error < 0 ? error : -EAGAIN; return 0; } -static ssize_t cyapa_gen5_do_calibrate(struct device *dev, +ssize_t cyapa_pip_do_calibrate(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -1755,25 +1695,25 @@ static ssize_t cyapa_gen5_do_calibrate(struct device *dev, int error, calibrate_error; /* 1. Suspend Scanning*/ - error = cyapa_gen5_suspend_scanning(cyapa); + error = cyapa_pip_suspend_scanning(cyapa); if (error) return error; /* 2. Do mutual capacitance fine calibrate. */ - calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa, - CYAPA_SENSING_MODE_MUTUAL_CAP_FINE); + calibrate_error = cyapa_pip_calibrate_pwcs(cyapa, + PIP_SENSING_MODE_MUTUAL_CAP_FINE); if (calibrate_error) goto resume_scanning; /* 3. Do self capacitance calibrate. */ - calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa, - CYAPA_SENSING_MODE_SELF_CAP); + calibrate_error = cyapa_pip_calibrate_pwcs(cyapa, + PIP_SENSING_MODE_SELF_CAP); if (calibrate_error) goto resume_scanning; resume_scanning: /* 4. Resume Scanning*/ - error = cyapa_gen5_resume_scanning(cyapa); + error = cyapa_pip_resume_scanning(cyapa); if (error || calibrate_error) return error ? error : calibrate_error; @@ -1856,7 +1796,7 @@ static void cyapa_gen5_guess_electrodes(struct cyapa *cyapa, * If the input value of @data_size is not 0, than means read the mutual or * self local PWC data. The @idac_max, @idac_min and @idac_ave are used to * return the max, min and average value of the mutual or self local PWC data. - * Note, in order to raed mutual local PWC data, must read invoke this function + * Note, in order to read mutual local PWC data, must read invoke this function * to read the mutual global idac data firstly to set the correct Rx number * value, otherwise, the read mutual idac and PWC data may not correct. */ @@ -1864,7 +1804,7 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, u8 cmd_code, u8 idac_data_type, int *data_size, int *idac_max, int *idac_min, int *idac_ave) { - struct gen5_app_cmd_head *cmd_head; + struct pip_app_cmd_head *cmd_head; u8 cmd[12]; u8 resp_data[256]; int resp_len; @@ -1879,7 +1819,7 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, int i; int error; - if (cmd_code != GEN5_CMD_RETRIEVE_DATA_STRUCTURE || + if (cmd_code != PIP_RETRIEVE_DATA_STRUCTURE || (idac_data_type != GEN5_RETRIEVE_MUTUAL_PWC_DATA && idac_data_type != GEN5_RETRIEVE_SELF_CAP_PWC_DATA) || !data_size || !idac_max || !idac_min || !idac_ave) @@ -1935,10 +1875,10 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, } memset(cmd, 0, sizeof(cmd)); - cmd_head = (struct gen5_app_cmd_head *)cmd; - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &cmd_head->addr); + cmd_head = (struct pip_app_cmd_head *)cmd; + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &cmd_head->addr); put_unaligned_le16(sizeof(cmd) - 2, &cmd_head->length); - cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + cmd_head->report_id = PIP_APP_CMD_REPORT_ID; cmd_head->cmd_code = cmd_code; do { read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / @@ -1953,11 +1893,11 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, + 500, cyapa_sort_tsg_pip_app_resp_data, true); if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET || !VALID_CMD_RESP_HEADER(resp_data, cmd_code) || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) || + !PIP_CMD_COMPLETE_SUCCESS(resp_data) || resp_data[6] != idac_data_type) return (error < 0) ? error : -EAGAIN; read_len = get_unaligned_le16(&resp_data[7]); @@ -1997,7 +1937,7 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, tmp_count < cyapa->aligned_electrodes_rx && read_global_idac) { /* - * The value gap betwen global and local mutual + * The value gap between global and local mutual * idac data must bigger than 50%. * Normally, global value bigger than 50, * local values less than 10. @@ -2061,7 +2001,7 @@ static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa, data_size = 0; error = cyapa_gen5_read_idac_data(cyapa, - GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + PIP_RETRIEVE_DATA_STRUCTURE, GEN5_RETRIEVE_MUTUAL_PWC_DATA, &data_size, gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave); @@ -2069,7 +2009,7 @@ static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa, return error; error = cyapa_gen5_read_idac_data(cyapa, - GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + PIP_RETRIEVE_DATA_STRUCTURE, GEN5_RETRIEVE_MUTUAL_PWC_DATA, &data_size, lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave); @@ -2088,7 +2028,7 @@ static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa, data_size = 0; error = cyapa_gen5_read_idac_data(cyapa, - GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + PIP_RETRIEVE_DATA_STRUCTURE, GEN5_RETRIEVE_SELF_CAP_PWC_DATA, &data_size, lidac_self_max, lidac_self_min, lidac_self_ave); @@ -2098,7 +2038,7 @@ static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa, *gidac_self_tx = *lidac_self_min; error = cyapa_gen5_read_idac_data(cyapa, - GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + PIP_RETRIEVE_DATA_STRUCTURE, GEN5_RETRIEVE_SELF_CAP_PWC_DATA, &data_size, lidac_self_max, lidac_self_min, lidac_self_ave); @@ -2107,27 +2047,27 @@ static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa, static ssize_t cyapa_gen5_execute_panel_scan(struct cyapa *cyapa) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; u8 cmd[7]; u8 resp_data[6]; int resp_len; int error; memset(cmd, 0, sizeof(cmd)); - app_cmd_head = (struct gen5_app_cmd_head *)cmd; - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + app_cmd_head = (struct pip_app_cmd_head *)cmd; + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; app_cmd_head->cmd_code = GEN5_CMD_EXECUTE_PANEL_SCAN; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + 500, cyapa_sort_tsg_pip_app_resp_data, true); if (error || resp_len != sizeof(resp_data) || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_EXECUTE_PANEL_SCAN) || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error ? error : -EAGAIN; return 0; @@ -2138,7 +2078,7 @@ static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa, int *raw_data_max, int *raw_data_min, int *raw_data_ave, u8 *buffer) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; struct gen5_retrieve_panel_scan_data *panel_sacn_data; u8 cmd[12]; u8 resp_data[256]; /* Max bytes can transfer one time. */ @@ -2166,10 +2106,10 @@ static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa, /* Assume max element size is 4 currently. */ read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / 4; read_len = read_elements * 4; - app_cmd_head = (struct gen5_app_cmd_head *)cmd; - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + app_cmd_head = (struct pip_app_cmd_head *)cmd; + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; app_cmd_head->cmd_code = cmd_code; panel_sacn_data = (struct gen5_retrieve_panel_scan_data *) app_cmd_head->parameter_data; @@ -2183,10 +2123,10 @@ static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa, error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + 500, cyapa_sort_tsg_pip_app_resp_data, true); if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET || !VALID_CMD_RESP_HEADER(resp_data, cmd_code) || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) || + !PIP_CMD_COMPLETE_SUCCESS(resp_data) || resp_data[6] != raw_data_type) return error ? error : -EAGAIN; @@ -2245,11 +2185,11 @@ static ssize_t cyapa_gen5_show_baseline(struct device *dev, int error, resume_error; int size; - if (cyapa->state != CYAPA_STATE_GEN5_APP) + if (!cyapa_is_pip_app_mode(cyapa)) return -EBUSY; /* 1. Suspend Scanning*/ - error = cyapa_gen5_suspend_scanning(cyapa); + error = cyapa_pip_suspend_scanning(cyapa); if (error) return error; @@ -2270,7 +2210,7 @@ static ssize_t cyapa_gen5_show_baseline(struct device *dev, if (error) goto resume_scanning; - /* 4. Execuate panel scan. It must be executed before read data. */ + /* 4. Execute panel scan. It must be executed before read data. */ error = cyapa_gen5_execute_panel_scan(cyapa); if (error) goto resume_scanning; @@ -2343,7 +2283,7 @@ static ssize_t cyapa_gen5_show_baseline(struct device *dev, resume_scanning: /* 11. Resume Scanning*/ - resume_error = cyapa_gen5_resume_scanning(cyapa); + resume_error = cyapa_pip_resume_scanning(cyapa); if (resume_error || error) return resume_error ? resume_error : error; @@ -2364,7 +2304,7 @@ resume_scanning: return size; } -static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa, +bool cyapa_pip_sort_system_info_data(struct cyapa *cyapa, u8 *buf, int len) { /* Check the report id and command code */ @@ -2376,20 +2316,17 @@ static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa, static int cyapa_gen5_bl_query_data(struct cyapa *cyapa) { - u8 bl_query_data_cmd[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00, - 0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17 - }; - u8 resp_data[GEN5_BL_READ_APP_INFO_RESP_LEN]; + u8 resp_data[PIP_BL_APP_INFO_RESP_LENGTH]; int resp_len; int error; - resp_len = GEN5_BL_READ_APP_INFO_RESP_LEN; + resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, - bl_query_data_cmd, sizeof(bl_query_data_cmd), + pip_bl_read_app_info, PIP_BL_READ_APP_INFO_CMD_LENGTH, resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, false); - if (error || resp_len != GEN5_BL_READ_APP_INFO_RESP_LEN || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + 500, cyapa_sort_tsg_pip_bl_resp_data, false); + if (error || resp_len < PIP_BL_APP_INFO_RESP_LENGTH || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error ? error : -EIO; memcpy(&cyapa->product_id[0], &resp_data[8], 5); @@ -2407,25 +2344,22 @@ static int cyapa_gen5_bl_query_data(struct cyapa *cyapa) static int cyapa_gen5_get_query_data(struct cyapa *cyapa) { - u8 get_system_information[] = { - 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02 - }; - u8 resp_data[71]; + u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH]; int resp_len; u16 product_family; int error; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, - get_system_information, sizeof(get_system_information), + pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH, resp_data, &resp_len, - 2000, cyapa_gen5_sort_system_info_data, false); + 2000, cyapa_pip_sort_system_info_data, false); if (error || resp_len < sizeof(resp_data)) return error ? error : -EIO; product_family = get_unaligned_le16(&resp_data[7]); - if ((product_family & GEN5_PRODUCT_FAMILY_MASK) != - GEN5_PRODUCT_FAMILY_TRACKPAD) + if ((product_family & PIP_PRODUCT_FAMILY_MASK) != + PIP_PRODUCT_FAMILY_TRACKPAD) return -EINVAL; cyapa->fw_maj_ver = resp_data[15]; @@ -2472,9 +2406,9 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) switch (cyapa->state) { case CYAPA_STATE_GEN5_BL: - error = cyapa_gen5_bl_exit(cyapa); + error = cyapa_pip_bl_exit(cyapa); if (error) { - /* Rry to update trackpad product information. */ + /* Try to update trackpad product information. */ cyapa_gen5_bl_query_data(cyapa); goto out; } @@ -2486,7 +2420,7 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) * If trackpad device in deep sleep mode, * the app command will fail. * So always try to reset trackpad device to full active when - * the device state is requeried. + * the device state is required. */ error = cyapa_gen5_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0); @@ -2518,14 +2452,14 @@ out: * Return false, do not continue process * Return true, continue process. */ -static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa) +bool cyapa_pip_irq_cmd_handler(struct cyapa *cyapa) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int length; - if (atomic_read(&gen5_pip->cmd_issued)) { + if (atomic_read(&pip->cmd_issued)) { /* Polling command response data. */ - if (gen5_pip->is_irq_mode == false) + if (pip->is_irq_mode == false) return false; /* @@ -2533,59 +2467,64 @@ static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa) * these output data may caused by user put finger on * trackpad when host waiting the command response. */ - cyapa_i2c_pip_read(cyapa, gen5_pip->irq_cmd_buf, - GEN5_RESP_LENGTH_SIZE); - length = get_unaligned_le16(gen5_pip->irq_cmd_buf); - length = (length <= GEN5_RESP_LENGTH_SIZE) ? - GEN5_RESP_LENGTH_SIZE : length; - if (length > GEN5_RESP_LENGTH_SIZE) + cyapa_i2c_pip_read(cyapa, pip->irq_cmd_buf, + PIP_RESP_LENGTH_SIZE); + length = get_unaligned_le16(pip->irq_cmd_buf); + length = (length <= PIP_RESP_LENGTH_SIZE) ? + PIP_RESP_LENGTH_SIZE : length; + if (length > PIP_RESP_LENGTH_SIZE) cyapa_i2c_pip_read(cyapa, - gen5_pip->irq_cmd_buf, length); - - if (!(gen5_pip->resp_sort_func && - gen5_pip->resp_sort_func(cyapa, - gen5_pip->irq_cmd_buf, length))) { + pip->irq_cmd_buf, length); + if (!(pip->resp_sort_func && + pip->resp_sort_func(cyapa, + pip->irq_cmd_buf, length))) { /* - * Work around the Gen5 V1 firmware - * that does not assert interrupt signalling - * that command response is ready if user - * keeps touching the trackpad while command - * is sent to the device. + * Cover the Gen5 V1 firmware issue. + * The issue is no interrupt would be asserted from + * trackpad device to host for the command response + * ready event. Because when there was a finger touch + * on trackpad device, and the firmware output queue + * won't be empty (always with touch report data), so + * the interrupt signal won't be asserted again until + * the output queue was previous emptied. + * This issue would happen in the scenario that + * user always has his/her fingers touched on the + * trackpad device during system booting/rebooting. */ length = 0; - if (gen5_pip->resp_len) - length = *gen5_pip->resp_len; + if (pip->resp_len) + length = *pip->resp_len; cyapa_empty_pip_output_data(cyapa, - gen5_pip->resp_data, + pip->resp_data, &length, - gen5_pip->resp_sort_func); - if (gen5_pip->resp_len && length != 0) { - *gen5_pip->resp_len = length; - atomic_dec(&gen5_pip->cmd_issued); - complete(&gen5_pip->cmd_ready); + pip->resp_sort_func); + if (pip->resp_len && length != 0) { + *pip->resp_len = length; + atomic_dec(&pip->cmd_issued); + complete(&pip->cmd_ready); } return false; } - if (gen5_pip->resp_data && gen5_pip->resp_len) { - *gen5_pip->resp_len = (*gen5_pip->resp_len < length) ? - *gen5_pip->resp_len : length; - memcpy(gen5_pip->resp_data, gen5_pip->irq_cmd_buf, - *gen5_pip->resp_len); + if (pip->resp_data && pip->resp_len) { + *pip->resp_len = (*pip->resp_len < length) ? + *pip->resp_len : length; + memcpy(pip->resp_data, pip->irq_cmd_buf, + *pip->resp_len); } - atomic_dec(&gen5_pip->cmd_issued); - complete(&gen5_pip->cmd_ready); + atomic_dec(&pip->cmd_issued); + complete(&pip->cmd_ready); return false; } return true; } -static void cyapa_gen5_report_buttons(struct cyapa *cyapa, - const struct cyapa_gen5_report_data *report_data) +static void cyapa_pip_report_buttons(struct cyapa *cyapa, + const struct cyapa_pip_report_data *report_data) { struct input_dev *input = cyapa->input; - u8 buttons = report_data->report_head[GEN5_BUTTONS_OFFSET]; + u8 buttons = report_data->report_head[PIP_BUTTONS_OFFSET]; buttons = (buttons << CAPABILITY_BTN_SHIFT) & CAPABILITY_BTN_MASK; @@ -2605,12 +2544,12 @@ static void cyapa_gen5_report_buttons(struct cyapa *cyapa, input_sync(input); } -static void cyapa_gen5_report_slot_data(struct cyapa *cyapa, - const struct cyapa_gen5_touch_record *touch) +static void cyapa_pip_report_slot_data(struct cyapa *cyapa, + const struct cyapa_pip_touch_record *touch) { struct input_dev *input = cyapa->input; - u8 event_id = GEN5_GET_EVENT_ID(touch->touch_tip_event_id); - int slot = GEN5_GET_TOUCH_ID(touch->touch_tip_event_id); + u8 event_id = PIP_GET_EVENT_ID(touch->touch_tip_event_id); + int slot = PIP_GET_TOUCH_ID(touch->touch_tip_event_id); int x, y; if (event_id == RECORD_EVENT_LIFTOFF) @@ -2621,10 +2560,10 @@ static void cyapa_gen5_report_slot_data(struct cyapa *cyapa, x = (touch->x_hi << 8) | touch->x_lo; if (cyapa->x_origin) x = cyapa->max_abs_x - x; - input_report_abs(input, ABS_MT_POSITION_X, x); y = (touch->y_hi << 8) | touch->y_lo; if (cyapa->y_origin) y = cyapa->max_abs_y - y; + input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); input_report_abs(input, ABS_MT_PRESSURE, touch->z); @@ -2642,50 +2581,49 @@ static void cyapa_gen5_report_slot_data(struct cyapa *cyapa, touch->orientation); } -static void cyapa_gen5_report_touches(struct cyapa *cyapa, - const struct cyapa_gen5_report_data *report_data) +static void cyapa_pip_report_touches(struct cyapa *cyapa, + const struct cyapa_pip_report_data *report_data) { struct input_dev *input = cyapa->input; unsigned int touch_num; int i; - touch_num = report_data->report_head[GEN5_NUMBER_OF_TOUCH_OFFSET] & - GEN5_NUMBER_OF_TOUCH_MASK; + touch_num = report_data->report_head[PIP_NUMBER_OF_TOUCH_OFFSET] & + PIP_NUMBER_OF_TOUCH_MASK; for (i = 0; i < touch_num; i++) - cyapa_gen5_report_slot_data(cyapa, + cyapa_pip_report_slot_data(cyapa, &report_data->touch_records[i]); input_mt_sync_frame(input); input_sync(input); } -static int cyapa_gen5_irq_handler(struct cyapa *cyapa) +int cyapa_pip_irq_handler(struct cyapa *cyapa) { struct device *dev = &cyapa->client->dev; - struct cyapa_gen5_report_data report_data; - int ret; - u8 report_id; + struct cyapa_pip_report_data report_data; unsigned int report_len; + u8 report_id; + int ret; - if (cyapa->gen != CYAPA_GEN5 || - cyapa->state != CYAPA_STATE_GEN5_APP) { + if (!cyapa_is_pip_app_mode(cyapa)) { dev_err(dev, "invalid device state, gen=%d, state=0x%02x\n", cyapa->gen, cyapa->state); return -EINVAL; } ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, - GEN5_RESP_LENGTH_SIZE); - if (ret != GEN5_RESP_LENGTH_SIZE) { + PIP_RESP_LENGTH_SIZE); + if (ret != PIP_RESP_LENGTH_SIZE) { dev_err(dev, "failed to read length bytes, (%d)\n", ret); return -EINVAL; } report_len = get_unaligned_le16( - &report_data.report_head[GEN5_RESP_LENGTH_OFFSET]); - if (report_len < GEN5_RESP_LENGTH_SIZE) { - /* Invliad length or internal reset happened. */ + &report_data.report_head[PIP_RESP_LENGTH_OFFSET]); + if (report_len < PIP_RESP_LENGTH_SIZE) { + /* Invalid length or internal reset happened. */ dev_err(dev, "invalid report_len=%d. bytes: %02x %02x\n", report_len, report_data.report_head[0], report_data.report_head[1]); @@ -2693,7 +2631,7 @@ static int cyapa_gen5_irq_handler(struct cyapa *cyapa) } /* Idle, no data for report. */ - if (report_len == GEN5_RESP_LENGTH_SIZE) + if (report_len == PIP_RESP_LENGTH_SIZE) return 0; ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, report_len); @@ -2703,70 +2641,71 @@ static int cyapa_gen5_irq_handler(struct cyapa *cyapa) return -EINVAL; } - report_id = report_data.report_head[GEN5_RESP_REPORT_ID_OFFSET]; - if (report_id == GEN5_WAKEUP_EVENT_REPORT_ID && - report_len == GEN5_WAKEUP_EVENT_SIZE) { + report_id = report_data.report_head[PIP_RESP_REPORT_ID_OFFSET]; + if (report_id == PIP_WAKEUP_EVENT_REPORT_ID && + report_len == PIP_WAKEUP_EVENT_SIZE) { /* * Device wake event from deep sleep mode for touch. * This interrupt event is used to wake system up. */ return 0; - } else if (report_id != GEN5_TOUCH_REPORT_ID && - report_id != GEN5_BTN_REPORT_ID && + } else if (report_id != PIP_TOUCH_REPORT_ID && + report_id != PIP_BTN_REPORT_ID && report_id != GEN5_OLD_PUSH_BTN_REPORT_ID && - report_id != GEN5_PUSH_BTN_REPORT_ID) { + report_id != PIP_PUSH_BTN_REPORT_ID) { /* Running in BL mode or unknown response data read. */ dev_err(dev, "invalid report_id=0x%02x\n", report_id); return -EINVAL; } - if (report_id == GEN5_TOUCH_REPORT_ID && - (report_len < GEN5_TOUCH_REPORT_HEAD_SIZE || - report_len > GEN5_TOUCH_REPORT_MAX_SIZE)) { + if (report_id == PIP_TOUCH_REPORT_ID && + (report_len < PIP_TOUCH_REPORT_HEAD_SIZE || + report_len > PIP_TOUCH_REPORT_MAX_SIZE)) { /* Invalid report data length for finger packet. */ dev_err(dev, "invalid touch packet length=%d\n", report_len); return 0; } - if ((report_id == GEN5_BTN_REPORT_ID || + if ((report_id == PIP_BTN_REPORT_ID || report_id == GEN5_OLD_PUSH_BTN_REPORT_ID || - report_id == GEN5_PUSH_BTN_REPORT_ID) && - (report_len < GEN5_BTN_REPORT_HEAD_SIZE || - report_len > GEN5_BTN_REPORT_MAX_SIZE)) { + report_id == PIP_PUSH_BTN_REPORT_ID) && + (report_len < PIP_BTN_REPORT_HEAD_SIZE || + report_len > PIP_BTN_REPORT_MAX_SIZE)) { /* Invalid report data length of button packet. */ dev_err(dev, "invalid button packet length=%d\n", report_len); return 0; } - if (report_id == GEN5_TOUCH_REPORT_ID) - cyapa_gen5_report_touches(cyapa, &report_data); + if (report_id == PIP_TOUCH_REPORT_ID) + cyapa_pip_report_touches(cyapa, &report_data); else - cyapa_gen5_report_buttons(cyapa, &report_data); + cyapa_pip_report_buttons(cyapa, &report_data); return 0; } -static int cyapa_gen5_bl_activate(struct cyapa *cyapa) { return 0; } -static int cyapa_gen5_bl_deactivate(struct cyapa *cyapa) { return 0; } +int cyapa_pip_bl_activate(struct cyapa *cyapa) { return 0; } +int cyapa_pip_bl_deactivate(struct cyapa *cyapa) { return 0; } + const struct cyapa_dev_ops cyapa_gen5_ops = { - .check_fw = cyapa_gen5_check_fw, - .bl_enter = cyapa_gen5_bl_enter, - .bl_initiate = cyapa_gen5_bl_initiate, - .update_fw = cyapa_gen5_do_fw_update, - .bl_activate = cyapa_gen5_bl_activate, - .bl_deactivate = cyapa_gen5_bl_deactivate, + .check_fw = cyapa_pip_check_fw, + .bl_enter = cyapa_pip_bl_enter, + .bl_initiate = cyapa_pip_bl_initiate, + .update_fw = cyapa_pip_do_fw_update, + .bl_activate = cyapa_pip_bl_activate, + .bl_deactivate = cyapa_pip_bl_deactivate, .show_baseline = cyapa_gen5_show_baseline, - .calibrate_store = cyapa_gen5_do_calibrate, + .calibrate_store = cyapa_pip_do_calibrate, - .initialize = cyapa_gen5_initialize, + .initialize = cyapa_pip_cmd_state_initialize, .state_parse = cyapa_gen5_state_parse, .operational_check = cyapa_gen5_do_operational_check, - .irq_handler = cyapa_gen5_irq_handler, - .irq_cmd_handler = cyapa_gen5_irq_cmd_handler, + .irq_handler = cyapa_pip_irq_handler, + .irq_cmd_handler = cyapa_pip_irq_cmd_handler, .sort_empty_output_data = cyapa_empty_pip_output_data, .set_power_mode = cyapa_gen5_set_power_mode, }; -- cgit v1.3-6-gb490 From c2c06c41f700b544c9331caf71c67edb5d131257 Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Mon, 20 Jul 2015 16:53:30 -0700 Subject: Input: cyapa - add gen6 device module support Based on the cyapa core, add support for basic functionality of the gen6 trackpad devices. The driver can automatically determine what protocol (gen3, gen5, or gen6) should be used with the attached trackpad device. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/Makefile | 2 +- drivers/input/mouse/cyapa.c | 22 ++ drivers/input/mouse/cyapa.h | 15 + drivers/input/mouse/cyapa_gen5.c | 69 +++- drivers/input/mouse/cyapa_gen6.c | 730 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 834 insertions(+), 4 deletions(-) create mode 100644 drivers/input/mouse/cyapa_gen6.c (limited to 'drivers') diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 793300bfbddd..ee6a6e9563d4 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o -cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o +cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o cyapa_gen6.o psmouse-objs := psmouse-base.o synaptics.o focaltech.o psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 4c4429598adb..6952ed1c92c7 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -41,6 +41,9 @@ static int cyapa_reinitialize(struct cyapa *cyapa); bool cyapa_is_pip_bl_mode(struct cyapa *cyapa) { + if (cyapa->gen == CYAPA_GEN6 && cyapa->state == CYAPA_STATE_GEN6_BL) + return true; + if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_BL) return true; @@ -49,6 +52,9 @@ bool cyapa_is_pip_bl_mode(struct cyapa *cyapa) bool cyapa_is_pip_app_mode(struct cyapa *cyapa) { + if (cyapa->gen == CYAPA_GEN6 && cyapa->state == CYAPA_STATE_GEN6_APP) + return true; + if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP) return true; @@ -204,6 +210,15 @@ static int cyapa_get_state(struct cyapa *cyapa) if (!error) goto out_detected; } + if (cyapa->gen == CYAPA_GEN_UNKNOWN || + cyapa->gen == CYAPA_GEN6 || + cyapa->gen == CYAPA_GEN5) { + error = cyapa_pip_state_parse(cyapa, + status, BL_STATUS_SIZE); + if (!error) + goto out_detected; + } + /* For old Gen5 trackpads detecting. */ if ((cyapa->gen == CYAPA_GEN_UNKNOWN || cyapa->gen == CYAPA_GEN5) && !smbus && even_addr) { @@ -300,6 +315,9 @@ static int cyapa_check_is_operational(struct cyapa *cyapa) return error; switch (cyapa->gen) { + case CYAPA_GEN6: + cyapa->ops = &cyapa_gen6_ops; + break; case CYAPA_GEN5: cyapa->ops = &cyapa_gen5_ops; break; @@ -579,6 +597,8 @@ static int cyapa_initialize(struct cyapa *cyapa) error = cyapa_gen3_ops.initialize(cyapa); if (!error) error = cyapa_gen5_ops.initialize(cyapa); + if (!error) + error = cyapa_gen6_ops.initialize(cyapa); if (error) return error; @@ -1136,9 +1156,11 @@ static char *cyapa_state_to_string(struct cyapa *cyapa) case CYAPA_STATE_BL_ACTIVE: return "bootloader active"; case CYAPA_STATE_GEN5_BL: + case CYAPA_STATE_GEN6_BL: return "bootloader"; case CYAPA_STATE_OP: case CYAPA_STATE_GEN5_APP: + case CYAPA_STATE_GEN6_APP: return "operational"; /* Normal valid state. */ default: return "invalid mode"; diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h index d019d1d2d1e4..3a211c0769e9 100644 --- a/drivers/input/mouse/cyapa.h +++ b/drivers/input/mouse/cyapa.h @@ -19,6 +19,7 @@ #define CYAPA_GEN_UNKNOWN 0x00 /* unknown protocol. */ #define CYAPA_GEN3 0x03 /* support MT-protocol B with tracking ID. */ #define CYAPA_GEN5 0x05 /* support TrueTouch GEN5 trackpad device. */ +#define CYAPA_GEN6 0x06 /* support TrueTouch GEN6 trackpad device. */ #define CYAPA_NAME "Cypress APA Trackpad (cyapa)" @@ -198,6 +199,9 @@ #define PIP_BL_APP_INFO_RESP_LENGTH 30 #define PIP_BL_GET_INFO_RESP_LENGTH 19 +#define PIP_BL_PLATFORM_VER_SHIFT 4 +#define PIP_BL_PLATFORM_VER_MASK 0x0f + #define PIP_PRODUCT_FAMILY_MASK 0xf000 #define PIP_PRODUCT_FAMILY_TRACKPAD 0x1000 @@ -299,6 +303,14 @@ enum cyapa_state { CYAPA_STATE_OP, CYAPA_STATE_GEN5_BL, CYAPA_STATE_GEN5_APP, + CYAPA_STATE_GEN6_BL, + CYAPA_STATE_GEN6_APP, +}; + +struct gen6_interval_setting { + u16 active_interval; + u16 lp1_interval; + u16 lp2_interval; }; /* The main device structure */ @@ -320,9 +332,11 @@ struct cyapa { u16 runtime_suspend_sleep_time; u8 dev_pwr_mode; u16 dev_sleep_time; + struct gen6_interval_setting gen6_interval_setting; /* Read from query data region. */ char product_id[16]; + u8 platform_ver; /* Platform version. */ u8 fw_maj_ver; /* Firmware major version. */ u8 fw_min_ver; /* Firmware minor version. */ u8 btn_capability; @@ -411,5 +425,6 @@ extern u8 pip_bl_read_app_info[]; extern const char product_id[]; extern const struct cyapa_dev_ops cyapa_gen3_ops; extern const struct cyapa_dev_ops cyapa_gen5_ops; +extern const struct cyapa_dev_ops cyapa_gen6_ops; #endif diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index 9d75c6f9f307..4e19dce1dd62 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -133,7 +133,9 @@ struct cyapa_pip_touch_record { * Bit 7 - 3: reserved * Bit 2 - 0: touch type; * 0 : standard finger; - * 1 - 15 : reserved. + * 1 : proximity (Start supported in Gen5 TP). + * 2 : finger hover (defined, but not used yet.) + * 3 - 15 : reserved. */ u8 touch_type; @@ -167,6 +169,9 @@ struct cyapa_pip_touch_record { * The meaning of this value is different when touch_type is different. * For standard finger type: * Touch intensity in counts, pressure value. + * For proximity type (Start supported in Gen5 TP): + * The distance, in surface units, between the contact and + * the surface. **/ u8 z; @@ -218,6 +223,12 @@ struct cyapa_tsg_bin_image_head { u8 fw_major_version; u8 fw_minor_version; u8 fw_revision_control_number[8]; + u8 silicon_id_hi; + u8 silicon_id_lo; + u8 chip_revision; + u8 family_id; + u8 bl_ver_maj; + u8 bl_ver_min; } __packed; struct cyapa_tsg_bin_image_data_record { @@ -1134,6 +1145,39 @@ int cyapa_pip_bl_enter(struct cyapa *cyapa) cyapa->operational = false; if (cyapa->gen == CYAPA_GEN5) cyapa->state = CYAPA_STATE_GEN5_BL; + else if (cyapa->gen == CYAPA_GEN6) + cyapa->state = CYAPA_STATE_GEN6_BL; + return 0; +} + +static int cyapa_pip_fw_head_check(struct cyapa *cyapa, + struct cyapa_tsg_bin_image_head *image_head) +{ + if (image_head->head_size != 0x0C && image_head->head_size != 0x12) + return -EINVAL; + + switch (cyapa->gen) { + case CYAPA_GEN6: + if (image_head->family_id != 0x9B || + image_head->silicon_id_hi != 0x0B) + return -EINVAL; + break; + case CYAPA_GEN5: + /* Gen5 without proximity support. */ + if (cyapa->platform_ver < 2) { + if (image_head->head_size == 0x0C) + break; + return -EINVAL; + } + + if (image_head->family_id != 0x91 || + image_head->silicon_id_hi != 0x02) + return -EINVAL; + break; + default: + return -EINVAL; + } + return 0; } @@ -1150,6 +1194,14 @@ int cyapa_pip_check_fw(struct cyapa *cyapa, const struct firmware *fw) u16 app_integrity_crc; int i; + /* Verify the firmware image not miss-used for Gen5 and Gen6. */ + if (cyapa_pip_fw_head_check(cyapa, + (struct cyapa_tsg_bin_image_head *)fw->data)) { + dev_err(dev, "%s: firmware image not match TP device.\n", + __func__); + return -EINVAL; + } + image_records = cyapa_get_image_record_data_num(fw, &flash_records_count); @@ -2339,6 +2391,9 @@ static int cyapa_gen5_bl_query_data(struct cyapa *cyapa) cyapa->fw_maj_ver = resp_data[22]; cyapa->fw_min_ver = resp_data[23]; + cyapa->platform_ver = (resp_data[26] >> PIP_BL_PLATFORM_VER_SHIFT) & + PIP_BL_PLATFORM_VER_MASK; + return 0; } @@ -2362,8 +2417,16 @@ static int cyapa_gen5_get_query_data(struct cyapa *cyapa) PIP_PRODUCT_FAMILY_TRACKPAD) return -EINVAL; - cyapa->fw_maj_ver = resp_data[15]; - cyapa->fw_min_ver = resp_data[16]; + cyapa->platform_ver = (resp_data[49] >> PIP_BL_PLATFORM_VER_SHIFT) & + PIP_BL_PLATFORM_VER_MASK; + if (cyapa->gen == CYAPA_GEN5 && cyapa->platform_ver < 2) { + /* Gen5 firmware that does not support proximity. */ + cyapa->fw_maj_ver = resp_data[15]; + cyapa->fw_min_ver = resp_data[16]; + } else { + cyapa->fw_maj_ver = resp_data[9]; + cyapa->fw_min_ver = resp_data[10]; + } cyapa->electrodes_x = resp_data[52]; cyapa->electrodes_y = resp_data[53]; diff --git a/drivers/input/mouse/cyapa_gen6.c b/drivers/input/mouse/cyapa_gen6.c new file mode 100644 index 000000000000..8a6aa73b5373 --- /dev/null +++ b/drivers/input/mouse/cyapa_gen6.c @@ -0,0 +1,730 @@ +/* + * Cypress APA trackpad with I2C interface + * + * Author: Dudley Du + * + * Copyright (C) 2015 Cypress Semiconductor, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cyapa.h" + + +#define GEN6_ENABLE_CMD_IRQ 0x41 +#define GEN6_DISABLE_CMD_IRQ 0x42 +#define GEN6_ENABLE_DEV_IRQ 0x43 +#define GEN6_DISABLE_DEV_IRQ 0x44 + +#define GEN6_POWER_MODE_ACTIVE 0x01 +#define GEN6_POWER_MODE_LP_MODE1 0x02 +#define GEN6_POWER_MODE_LP_MODE2 0x03 +#define GEN6_POWER_MODE_BTN_ONLY 0x04 + +#define GEN6_SET_POWER_MODE_INTERVAL 0x47 +#define GEN6_GET_POWER_MODE_INTERVAL 0x48 + +#define GEN6_MAX_RX_NUM 14 +#define GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC 0x00 +#define GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM 0x12 + + +struct pip_app_cmd_head { + __le16 addr; + __le16 length; + u8 report_id; + u8 resv; /* Reserved, must be 0 */ + u8 cmd_code; /* bit7: resv, set to 0; bit6~0: command code.*/ +} __packed; + +struct pip_app_resp_head { + __le16 length; + u8 report_id; + u8 resv; /* Reserved, must be 0 */ + u8 cmd_code; /* bit7: TGL; bit6~0: command code.*/ + /* + * The value of data_status can be the first byte of data or + * the command status or the unsupported command code depending on the + * requested command code. + */ + u8 data_status; +} __packed; + +struct pip_fixed_info { + u8 silicon_id_high; + u8 silicon_id_low; + u8 family_id; +}; + +static u8 pip_get_bl_info[] = { + 0x04, 0x00, 0x0B, 0x00, 0x40, 0x00, 0x01, 0x38, + 0x00, 0x00, 0x70, 0x9E, 0x17 +}; + +static bool cyapa_sort_pip_hid_descriptor_data(struct cyapa *cyapa, + u8 *buf, int len) +{ + if (len != PIP_HID_DESCRIPTOR_SIZE) + return false; + + if (buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID || + buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID) + return true; + + return false; +} + +static int cyapa_get_pip_fixed_info(struct cyapa *cyapa, + struct pip_fixed_info *pip_info, bool is_bootloader) +{ + u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH]; + int resp_len; + u16 product_family; + int error; + + if (is_bootloader) { + /* Read Bootloader Information to determine Gen5 or Gen6. */ + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + pip_get_bl_info, sizeof(pip_get_bl_info), + resp_data, &resp_len, + 2000, cyapa_sort_tsg_pip_bl_resp_data, + false); + if (error || resp_len < PIP_BL_GET_INFO_RESP_LENGTH) + return error ? error : -EIO; + + pip_info->family_id = resp_data[8]; + pip_info->silicon_id_low = resp_data[10]; + pip_info->silicon_id_high = resp_data[11]; + + return 0; + } + + /* Get App System Information to determine Gen5 or Gen6. */ + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH, + resp_data, &resp_len, + 2000, cyapa_pip_sort_system_info_data, false); + if (error || resp_len < PIP_READ_SYS_INFO_RESP_LENGTH) + return error ? error : -EIO; + + product_family = get_unaligned_le16(&resp_data[7]); + if ((product_family & PIP_PRODUCT_FAMILY_MASK) != + PIP_PRODUCT_FAMILY_TRACKPAD) + return -EINVAL; + + pip_info->family_id = resp_data[19]; + pip_info->silicon_id_low = resp_data[21]; + pip_info->silicon_id_high = resp_data[22]; + + return 0; + +} + +int cyapa_pip_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) +{ + u8 cmd[] = { 0x01, 0x00}; + struct pip_fixed_info pip_info; + u8 resp_data[PIP_HID_DESCRIPTOR_SIZE]; + int resp_len; + bool is_bootloader; + int error; + + cyapa->state = CYAPA_STATE_NO_DEVICE; + + /* Try to wake from it deep sleep state if it is. */ + cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON); + + /* Empty the buffer queue to get fresh data with later commands. */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + /* + * Read description info from trackpad device to determine running in + * APP mode or Bootloader mode. + */ + resp_len = PIP_HID_DESCRIPTOR_SIZE; + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + cmd, sizeof(cmd), + resp_data, &resp_len, + 300, + cyapa_sort_pip_hid_descriptor_data, + false); + if (error) + return error; + + if (resp_data[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID) + is_bootloader = true; + else if (resp_data[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID) + is_bootloader = false; + else + return -EAGAIN; + + /* Get PIP fixed information to determine Gen5 or Gen6. */ + memset(&pip_info, 0, sizeof(struct pip_fixed_info)); + error = cyapa_get_pip_fixed_info(cyapa, &pip_info, is_bootloader); + if (error) + return error; + + if (pip_info.family_id == 0x9B && pip_info.silicon_id_high == 0x0B) { + cyapa->gen = CYAPA_GEN6; + cyapa->state = is_bootloader ? CYAPA_STATE_GEN6_BL + : CYAPA_STATE_GEN6_APP; + } else if (pip_info.family_id == 0x91 && + pip_info.silicon_id_high == 0x02) { + cyapa->gen = CYAPA_GEN5; + cyapa->state = is_bootloader ? CYAPA_STATE_GEN5_BL + : CYAPA_STATE_GEN5_APP; + } + + return 0; +} + +static int cyapa_gen6_read_sys_info(struct cyapa *cyapa) +{ + u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH]; + int resp_len; + u16 product_family; + u8 rotat_align; + int error; + + /* Get App System Information to determine Gen5 or Gen6. */ + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH, + resp_data, &resp_len, + 2000, cyapa_pip_sort_system_info_data, false); + if (error || resp_len < sizeof(resp_data)) + return error ? error : -EIO; + + product_family = get_unaligned_le16(&resp_data[7]); + if ((product_family & PIP_PRODUCT_FAMILY_MASK) != + PIP_PRODUCT_FAMILY_TRACKPAD) + return -EINVAL; + + cyapa->platform_ver = (resp_data[67] >> PIP_BL_PLATFORM_VER_SHIFT) & + PIP_BL_PLATFORM_VER_MASK; + cyapa->fw_maj_ver = resp_data[9]; + cyapa->fw_min_ver = resp_data[10]; + + cyapa->electrodes_x = resp_data[33]; + cyapa->electrodes_y = resp_data[34]; + + cyapa->physical_size_x = get_unaligned_le16(&resp_data[35]) / 100; + cyapa->physical_size_y = get_unaligned_le16(&resp_data[37]) / 100; + + cyapa->max_abs_x = get_unaligned_le16(&resp_data[39]); + cyapa->max_abs_y = get_unaligned_le16(&resp_data[41]); + + cyapa->max_z = get_unaligned_le16(&resp_data[43]); + + cyapa->x_origin = resp_data[45] & 0x01; + cyapa->y_origin = resp_data[46] & 0x01; + + cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK; + + memcpy(&cyapa->product_id[0], &resp_data[51], 5); + cyapa->product_id[5] = '-'; + memcpy(&cyapa->product_id[6], &resp_data[56], 6); + cyapa->product_id[12] = '-'; + memcpy(&cyapa->product_id[13], &resp_data[62], 2); + cyapa->product_id[15] = '\0'; + + rotat_align = resp_data[68]; + if (rotat_align) { + cyapa->electrodes_rx = cyapa->electrodes_y; + cyapa->electrodes_rx = cyapa->electrodes_y; + } else { + cyapa->electrodes_rx = cyapa->electrodes_x; + cyapa->electrodes_rx = cyapa->electrodes_y; + } + cyapa->aligned_electrodes_rx = (cyapa->electrodes_rx + 3) & ~3u; + + if (!cyapa->electrodes_x || !cyapa->electrodes_y || + !cyapa->physical_size_x || !cyapa->physical_size_y || + !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z) + return -EINVAL; + + return 0; +} + +static int cyapa_gen6_bl_read_app_info(struct cyapa *cyapa) +{ + u8 resp_data[PIP_BL_APP_INFO_RESP_LENGTH]; + int resp_len; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + pip_bl_read_app_info, PIP_BL_READ_APP_INFO_CMD_LENGTH, + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_bl_resp_data, false); + if (error || resp_len < PIP_BL_APP_INFO_RESP_LENGTH || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) + return error ? error : -EIO; + + cyapa->fw_maj_ver = resp_data[8]; + cyapa->fw_min_ver = resp_data[9]; + + cyapa->platform_ver = (resp_data[12] >> PIP_BL_PLATFORM_VER_SHIFT) & + PIP_BL_PLATFORM_VER_MASK; + + memcpy(&cyapa->product_id[0], &resp_data[13], 5); + cyapa->product_id[5] = '-'; + memcpy(&cyapa->product_id[6], &resp_data[18], 6); + cyapa->product_id[12] = '-'; + memcpy(&cyapa->product_id[13], &resp_data[24], 2); + cyapa->product_id[15] = '\0'; + + return 0; + +} + +static int cyapa_gen6_config_dev_irq(struct cyapa *cyapa, u8 cmd_code) +{ + u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, cmd_code }; + u8 resp_data[6]; + int resp_len; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, false); + if (error || !VALID_CMD_RESP_HEADER(resp_data, cmd_code) || + !PIP_CMD_COMPLETE_SUCCESS(resp_data) + ) + return error < 0 ? error : -EINVAL; + + return 0; +} + +static int cyapa_gen6_change_power_state(struct cyapa *cyapa, u8 power_mode) +{ + u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x46, power_mode }; + u8 resp_data[6]; + int resp_len; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, false); + if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x46)) + return error < 0 ? error : -EINVAL; + + /* New power state applied in device not match the set power state. */ + if (resp_data[5] != power_mode) + return -EAGAIN; + + return 0; +} + +static int cyapa_gen6_set_interval_setting(struct cyapa *cyapa, + struct gen6_interval_setting *interval_setting) +{ + struct gen6_set_interval_cmd { + __le16 addr; + __le16 length; + u8 report_id; + u8 rsvd; /* Reserved, must be 0 */ + u8 cmd_code; + __le16 active_interval; + __le16 lp1_interval; + __le16 lp2_interval; + } __packed set_interval_cmd; + u8 resp_data[11]; + int resp_len; + int error; + + memset(&set_interval_cmd, 0, sizeof(set_interval_cmd)); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &set_interval_cmd.addr); + put_unaligned_le16(sizeof(set_interval_cmd) - 2, + &set_interval_cmd.length); + set_interval_cmd.report_id = PIP_APP_CMD_REPORT_ID; + set_interval_cmd.cmd_code = GEN6_SET_POWER_MODE_INTERVAL; + put_unaligned_le16(interval_setting->active_interval, + &set_interval_cmd.active_interval); + put_unaligned_le16(interval_setting->lp1_interval, + &set_interval_cmd.lp1_interval); + put_unaligned_le16(interval_setting->lp2_interval, + &set_interval_cmd.lp2_interval); + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + (u8 *)&set_interval_cmd, sizeof(set_interval_cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, false); + if (error || + !VALID_CMD_RESP_HEADER(resp_data, GEN6_SET_POWER_MODE_INTERVAL)) + return error < 0 ? error : -EINVAL; + + /* Get the real set intervals from response. */ + interval_setting->active_interval = get_unaligned_le16(&resp_data[5]); + interval_setting->lp1_interval = get_unaligned_le16(&resp_data[7]); + interval_setting->lp2_interval = get_unaligned_le16(&resp_data[9]); + + return 0; +} + +static int cyapa_gen6_get_interval_setting(struct cyapa *cyapa, + struct gen6_interval_setting *interval_setting) +{ + u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, + GEN6_GET_POWER_MODE_INTERVAL }; + u8 resp_data[11]; + int resp_len; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, false); + if (error || + !VALID_CMD_RESP_HEADER(resp_data, GEN6_GET_POWER_MODE_INTERVAL)) + return error < 0 ? error : -EINVAL; + + interval_setting->active_interval = get_unaligned_le16(&resp_data[5]); + interval_setting->lp1_interval = get_unaligned_le16(&resp_data[7]); + interval_setting->lp2_interval = get_unaligned_le16(&resp_data[9]); + + return 0; +} + +static int cyapa_gen6_deep_sleep(struct cyapa *cyapa, u8 state) +{ + u8 ping[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x00 }; + + if (state == PIP_DEEP_SLEEP_STATE_ON) + /* + * Send ping command to notify device prepare for wake up + * when it's in deep sleep mode. At this time, device will + * response nothing except an I2C NAK. + */ + cyapa_i2c_pip_write(cyapa, ping, sizeof(ping)); + + return cyapa_pip_deep_sleep(cyapa, state); +} + +static int cyapa_gen6_set_power_mode(struct cyapa *cyapa, + u8 power_mode, u16 sleep_time) +{ + struct device *dev = &cyapa->client->dev; + struct gen6_interval_setting *interval_setting = + &cyapa->gen6_interval_setting; + u8 lp_mode; + int error; + + if (cyapa->state != CYAPA_STATE_GEN6_APP) + return 0; + + if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { + /* + * Assume TP in deep sleep mode when driver is loaded, + * avoid driver unload and reload command IO issue caused by TP + * has been set into deep sleep mode when unloading. + */ + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); + } + + if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) && + PIP_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF) + PIP_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME); + + if (PIP_DEV_GET_PWR_STATE(cyapa) == power_mode) { + if (power_mode == PWR_MODE_OFF || + power_mode == PWR_MODE_FULL_ACTIVE || + power_mode == PWR_MODE_BTN_ONLY || + PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { + /* Has in correct power mode state, early return. */ + return 0; + } + } + + if (power_mode == PWR_MODE_OFF) { + cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ); + + error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF); + if (error) { + dev_err(dev, "enter deep sleep fail: %d\n", error); + return error; + } + + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); + return 0; + } + + /* + * When trackpad in power off mode, it cannot change to other power + * state directly, must be wake up from sleep firstly, then + * continue to do next power sate change. + */ + if (PIP_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) { + error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON); + if (error) { + dev_err(dev, "deep sleep wake fail: %d\n", error); + return error; + } + } + + /* + * Disable device assert interrupts for command response to avoid + * disturbing system suspending or hibernating process. + */ + cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ); + + if (power_mode == PWR_MODE_FULL_ACTIVE) { + error = cyapa_gen6_change_power_state(cyapa, + GEN6_POWER_MODE_ACTIVE); + if (error) { + dev_err(dev, "change to active fail: %d\n", error); + goto out; + } + + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE); + + /* Sync the interval setting from device. */ + cyapa_gen6_get_interval_setting(cyapa, interval_setting); + + } else if (power_mode == PWR_MODE_BTN_ONLY) { + error = cyapa_gen6_change_power_state(cyapa, + GEN6_POWER_MODE_BTN_ONLY); + if (error) { + dev_err(dev, "fail to button only mode: %d\n", error); + goto out; + } + + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY); + } else { + /* + * Gen6 internally supports to 2 low power scan interval time, + * so can help to switch power mode quickly. + * such as runtime suspend and system suspend. + */ + if (interval_setting->lp1_interval == sleep_time) { + lp_mode = GEN6_POWER_MODE_LP_MODE1; + } else if (interval_setting->lp2_interval == sleep_time) { + lp_mode = GEN6_POWER_MODE_LP_MODE2; + } else { + if (interval_setting->lp1_interval == 0) { + interval_setting->lp1_interval = sleep_time; + lp_mode = GEN6_POWER_MODE_LP_MODE1; + } else { + interval_setting->lp2_interval = sleep_time; + lp_mode = GEN6_POWER_MODE_LP_MODE2; + } + cyapa_gen6_set_interval_setting(cyapa, + interval_setting); + } + + error = cyapa_gen6_change_power_state(cyapa, lp_mode); + if (error) { + dev_err(dev, "set power state to 0x%02x failed: %d\n", + lp_mode, error); + goto out; + } + + PIP_DEV_SET_SLEEP_TIME(cyapa, sleep_time); + PIP_DEV_SET_PWR_STATE(cyapa, + cyapa_sleep_time_to_pwr_cmd(sleep_time)); + } + +out: + cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ); + return error; +} + +static int cyapa_gen6_initialize(struct cyapa *cyapa) +{ + return 0; +} + +static int cyapa_pip_retrieve_data_structure(struct cyapa *cyapa, + u16 read_offset, u16 read_len, u8 data_id, + u8 *data, int *data_buf_lens) +{ + struct retrieve_data_struct_cmd { + struct pip_app_cmd_head head; + __le16 read_offset; + __le16 read_length; + u8 data_id; + } __packed cmd; + u8 resp_data[GEN6_MAX_RX_NUM + 10]; + int resp_len; + int error; + + memset(&cmd, 0, sizeof(cmd)); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &cmd.head.addr); + put_unaligned_le16(sizeof(cmd), &cmd.head.length - 2); + cmd.head.report_id = PIP_APP_CMD_REPORT_ID; + cmd.head.cmd_code = PIP_RETRIEVE_DATA_STRUCTURE; + put_unaligned_le16(read_offset, &cmd.read_offset); + put_unaligned_le16(read_len, &cmd.read_length); + cmd.data_id = data_id; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + (u8 *)&cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, + true); + if (error || !PIP_CMD_COMPLETE_SUCCESS(resp_data) || + resp_data[6] != data_id || + !VALID_CMD_RESP_HEADER(resp_data, PIP_RETRIEVE_DATA_STRUCTURE)) + return (error < 0) ? error : -EAGAIN; + + read_len = get_unaligned_le16(&resp_data[7]); + if (*data_buf_lens < read_len) { + *data_buf_lens = read_len; + return -ENOBUFS; + } + + memcpy(data, &resp_data[10], read_len); + *data_buf_lens = read_len; + return 0; +} + +static ssize_t cyapa_gen6_show_baseline(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + u8 data[GEN6_MAX_RX_NUM]; + int data_len; + int size = 0; + int i; + int error; + int resume_error; + + if (!cyapa_is_pip_app_mode(cyapa)) + return -EBUSY; + + /* 1. Suspend Scanning*/ + error = cyapa_pip_suspend_scanning(cyapa); + if (error) + return error; + + /* 2. IDAC and RX Attenuator Calibration Data (Center Frequency). */ + data_len = sizeof(data); + error = cyapa_pip_retrieve_data_structure(cyapa, 0, data_len, + GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC, + data, &data_len); + if (error) + goto resume_scanning; + + size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d ", + data[0], /* RX Attenuator Mutual */ + data[1], /* IDAC Mutual */ + data[2], /* RX Attenuator Self RX */ + data[3], /* IDAC Self RX */ + data[4], /* RX Attenuator Self TX */ + data[5] /* IDAC Self TX */ + ); + + /* 3. Read Attenuator Trim. */ + data_len = sizeof(data); + error = cyapa_pip_retrieve_data_structure(cyapa, 0, data_len, + GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM, + data, &data_len); + if (error) + goto resume_scanning; + + /* set attenuator trim values. */ + for (i = 0; i < data_len; i++) + size += scnprintf(buf + size, PAGE_SIZE - size, "%d ", data[i]); + size += scnprintf(buf + size, PAGE_SIZE - size, "\n"); + +resume_scanning: + /* 4. Resume Scanning*/ + resume_error = cyapa_pip_resume_scanning(cyapa); + if (resume_error || error) { + memset(buf, 0, PAGE_SIZE); + return resume_error ? resume_error : error; + } + + return size; +} + +static int cyapa_gen6_operational_check(struct cyapa *cyapa) +{ + struct device *dev = &cyapa->client->dev; + int error; + + if (cyapa->gen != CYAPA_GEN6) + return -ENODEV; + + switch (cyapa->state) { + case CYAPA_STATE_GEN6_BL: + error = cyapa_pip_bl_exit(cyapa); + if (error) { + /* Try to update trackpad product information. */ + cyapa_gen6_bl_read_app_info(cyapa); + goto out; + } + + cyapa->state = CYAPA_STATE_GEN6_APP; + + case CYAPA_STATE_GEN6_APP: + /* + * If trackpad device in deep sleep mode, + * the app command will fail. + * So always try to reset trackpad device to full active when + * the device state is required. + */ + error = cyapa_gen6_set_power_mode(cyapa, + PWR_MODE_FULL_ACTIVE, 0); + if (error) + dev_warn(dev, "%s: failed to set power active mode.\n", + __func__); + + /* Get trackpad product information. */ + error = cyapa_gen6_read_sys_info(cyapa); + if (error) + goto out; + /* Only support product ID starting with CYTRA */ + if (memcmp(cyapa->product_id, product_id, + strlen(product_id)) != 0) { + dev_err(dev, "%s: unknown product ID (%s)\n", + __func__, cyapa->product_id); + error = -EINVAL; + } + break; + default: + error = -EINVAL; + } + +out: + return error; +} + +const struct cyapa_dev_ops cyapa_gen6_ops = { + .check_fw = cyapa_pip_check_fw, + .bl_enter = cyapa_pip_bl_enter, + .bl_initiate = cyapa_pip_bl_initiate, + .update_fw = cyapa_pip_do_fw_update, + .bl_activate = cyapa_pip_bl_activate, + .bl_deactivate = cyapa_pip_bl_deactivate, + + .show_baseline = cyapa_gen6_show_baseline, + .calibrate_store = cyapa_pip_do_calibrate, + + .initialize = cyapa_gen6_initialize, + + .state_parse = cyapa_pip_state_parse, + .operational_check = cyapa_gen6_operational_check, + + .irq_handler = cyapa_pip_irq_handler, + .irq_cmd_handler = cyapa_pip_irq_cmd_handler, + .sort_empty_output_data = cyapa_empty_pip_output_data, + .set_power_mode = cyapa_gen6_set_power_mode, +}; -- cgit v1.3-6-gb490 From 945525ee607471630d07c309e036ae4a53abe37f Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Mon, 20 Jul 2015 16:57:53 -0700 Subject: Input: cyapa - add proximity support for gen5 and gen6 modules Gen5 and Gen6 trackpad devices are able to detect and report object proximity data/events, add this function support in the cyapa driver through the ABS_DISTANCE event. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 13 ++++++++- drivers/input/mouse/cyapa.h | 3 ++ drivers/input/mouse/cyapa_gen3.c | 7 +++++ drivers/input/mouse/cyapa_gen5.c | 61 +++++++++++++++++++++++++++++++++++++++- drivers/input/mouse/cyapa_gen6.c | 19 +++++++++++++ 5 files changed, 101 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 6952ed1c92c7..2541fbb43533 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -477,6 +477,7 @@ static int cyapa_create_input_dev(struct cyapa *cyapa) if (cyapa->gen >= CYAPA_GEN5) { input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 255, 0, 0); + input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0); } input_abs_set_res(input, ABS_MT_POSITION_X, @@ -1340,6 +1341,13 @@ static int __maybe_unused cyapa_suspend(struct device *dev) error); } + /* + * Disable proximity interrupt when system idle, want true touch to + * wake the system. + */ + if (cyapa->dev_pwr_mode != PWR_MODE_OFF) + cyapa->ops->set_proximity(cyapa, false); + if (device_may_wakeup(dev)) cyapa->irq_wake = (enable_irq_wake(client->irq) == 0); @@ -1360,7 +1368,10 @@ static int __maybe_unused cyapa_resume(struct device *dev) cyapa->irq_wake = false; } - /* Update device states and runtime PM states. */ + /* + * Update device states and runtime PM states. + * Re-Enable proximity interrupt after enter operational mode. + */ error = cyapa_reinitialize(cyapa); if (error) dev_warn(dev, "failed to reinitialize TP device: %d\n", error); diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h index 3a211c0769e9..f51deb69c370 100644 --- a/drivers/input/mouse/cyapa.h +++ b/drivers/input/mouse/cyapa.h @@ -274,6 +274,8 @@ struct cyapa_dev_ops { u8 *, int *, cb_sort); int (*set_power_mode)(struct cyapa *, u8, u16); + + int (*set_proximity)(struct cyapa *, bool); }; struct cyapa_pip_cmd_states { @@ -415,6 +417,7 @@ int cyapa_pip_bl_deactivate(struct cyapa *cyapa); ssize_t cyapa_pip_do_calibrate(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +int cyapa_pip_set_proximity(struct cyapa *cyapa, bool enable); bool cyapa_pip_irq_cmd_handler(struct cyapa *cyapa); int cyapa_pip_irq_handler(struct cyapa *cyapa); diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c index 3884311410f7..e7bbfee8b5d6 100644 --- a/drivers/input/mouse/cyapa_gen3.c +++ b/drivers/input/mouse/cyapa_gen3.c @@ -999,6 +999,11 @@ static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode, return ret; } +static int cyapa_gen3_set_proximity(struct cyapa *cyapa, bool enable) +{ + return -EOPNOTSUPP; +} + static int cyapa_gen3_get_query_data(struct cyapa *cyapa) { u8 query_data[QUERY_DATA_SIZE]; @@ -1243,4 +1248,6 @@ const struct cyapa_dev_ops cyapa_gen3_ops = { .irq_cmd_handler = cyapa_gen3_irq_cmd_handler, .sort_empty_output_data = cyapa_gen3_empty_output_data, .set_power_mode = cyapa_gen3_set_power_mode, + + .set_proximity = cyapa_gen3_set_proximity, }; diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index 4e19dce1dd62..fa135f855f34 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -52,6 +52,11 @@ #define PIP_WAKEUP_EVENT_REPORT_ID 0x04 #define PIP_PUSH_BTN_REPORT_ID 0x06 #define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 /* Special for old Gen5 TP. */ +#define PIP_PROXIMITY_REPORT_ID 0x07 + +#define PIP_PROXIMITY_REPORT_SIZE 6 +#define PIP_PROXIMITY_DISTANCE_OFFSET 0x05 +#define PIP_PROXIMITY_DISTANCE_MASK 0x01 #define PIP_TOUCH_REPORT_HEAD_SIZE 7 #define PIP_TOUCH_REPORT_MAX_SIZE 127 @@ -78,6 +83,8 @@ #define PIP_SENSING_MODE_MUTUAL_CAP_FINE 0x00 #define PIP_SENSING_MODE_SELF_CAP 0x02 +#define PIP_SET_PROXIMITY 0x49 + /* Macro of Gen5 */ #define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100 #define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe @@ -1517,6 +1524,28 @@ static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) return 0; } +int cyapa_pip_set_proximity(struct cyapa *cyapa, bool enable) +{ + u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, PIP_SET_PROXIMITY, + (u8)!!enable + }; + u8 resp_data[6]; + int resp_len; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, false); + if (error || !VALID_CMD_RESP_HEADER(resp_data, PIP_SET_PROXIMITY) || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) { + error = (error == -ETIMEDOUT) ? -EOPNOTSUPP : error; + return error < 0 ? error : -EINVAL; + } + + return 0; +} + int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state) { u8 cmd[] = { 0x05, 0x00, 0x00, 0x08}; @@ -2491,6 +2520,12 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) dev_warn(dev, "%s: failed to set power active mode.\n", __func__); + /* By default, the trackpad proximity function is enabled. */ + error = cyapa_pip_set_proximity(cyapa, true); + if (error) + dev_warn(dev, "%s: failed to enable proximity.\n", + __func__); + /* Get trackpad product information. */ error = cyapa_gen5_get_query_data(cyapa); if (error) @@ -2607,6 +2642,17 @@ static void cyapa_pip_report_buttons(struct cyapa *cyapa, input_sync(input); } +static void cyapa_pip_report_proximity(struct cyapa *cyapa, + const struct cyapa_pip_report_data *report_data) +{ + struct input_dev *input = cyapa->input; + u8 distance = report_data->report_head[PIP_PROXIMITY_DISTANCE_OFFSET] & + PIP_PROXIMITY_DISTANCE_MASK; + + input_report_abs(input, ABS_DISTANCE, distance); + input_sync(input); +} + static void cyapa_pip_report_slot_data(struct cyapa *cyapa, const struct cyapa_pip_touch_record *touch) { @@ -2628,6 +2674,7 @@ static void cyapa_pip_report_slot_data(struct cyapa *cyapa, y = cyapa->max_abs_y - y; input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); + input_report_abs(input, ABS_DISTANCE, 0); input_report_abs(input, ABS_MT_PRESSURE, touch->z); input_report_abs(input, ABS_MT_TOUCH_MAJOR, @@ -2715,7 +2762,8 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa) } else if (report_id != PIP_TOUCH_REPORT_ID && report_id != PIP_BTN_REPORT_ID && report_id != GEN5_OLD_PUSH_BTN_REPORT_ID && - report_id != PIP_PUSH_BTN_REPORT_ID) { + report_id != PIP_PUSH_BTN_REPORT_ID && + report_id != PIP_PROXIMITY_REPORT_ID) { /* Running in BL mode or unknown response data read. */ dev_err(dev, "invalid report_id=0x%02x\n", report_id); return -EINVAL; @@ -2739,8 +2787,17 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa) return 0; } + if (report_id == PIP_PROXIMITY_REPORT_ID && + report_len != PIP_PROXIMITY_REPORT_SIZE) { + /* Invalid report data length of proximity packet. */ + dev_err(dev, "invalid proximity data, length=%d\n", report_len); + return 0; + } + if (report_id == PIP_TOUCH_REPORT_ID) cyapa_pip_report_touches(cyapa, &report_data); + else if (report_id == PIP_PROXIMITY_REPORT_ID) + cyapa_pip_report_proximity(cyapa, &report_data); else cyapa_pip_report_buttons(cyapa, &report_data); @@ -2771,4 +2828,6 @@ const struct cyapa_dev_ops cyapa_gen5_ops = { .irq_cmd_handler = cyapa_pip_irq_cmd_handler, .sort_empty_output_data = cyapa_empty_pip_output_data, .set_power_mode = cyapa_gen5_set_power_mode, + + .set_proximity = cyapa_pip_set_proximity, }; diff --git a/drivers/input/mouse/cyapa_gen6.c b/drivers/input/mouse/cyapa_gen6.c index 8a6aa73b5373..61f04132eb65 100644 --- a/drivers/input/mouse/cyapa_gen6.c +++ b/drivers/input/mouse/cyapa_gen6.c @@ -310,6 +310,17 @@ static int cyapa_gen6_config_dev_irq(struct cyapa *cyapa, u8 cmd_code) return 0; } +static int cyapa_gen6_set_proximity(struct cyapa *cyapa, bool enable) +{ + int error; + + cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ); + error = cyapa_pip_set_proximity(cyapa, enable); + cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ); + + return error; +} + static int cyapa_gen6_change_power_state(struct cyapa *cyapa, u8 power_mode) { u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x46, power_mode }; @@ -687,6 +698,12 @@ static int cyapa_gen6_operational_check(struct cyapa *cyapa) dev_warn(dev, "%s: failed to set power active mode.\n", __func__); + /* By default, the trackpad proximity function is enabled. */ + error = cyapa_pip_set_proximity(cyapa, true); + if (error) + dev_warn(dev, "%s: failed to enable proximity.\n", + __func__); + /* Get trackpad product information. */ error = cyapa_gen6_read_sys_info(cyapa); if (error) @@ -727,4 +744,6 @@ const struct cyapa_dev_ops cyapa_gen6_ops = { .irq_cmd_handler = cyapa_pip_irq_cmd_handler, .sort_empty_output_data = cyapa_empty_pip_output_data, .set_power_mode = cyapa_gen6_set_power_mode, + + .set_proximity = cyapa_gen6_set_proximity, }; -- cgit v1.3-6-gb490 From 757cae5a6f0ac1c61ce149a066377a15d1ed881f Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Mon, 20 Jul 2015 17:09:59 -0700 Subject: Input: cyapa - fully support runtime suspend power management Fix the the runtime suspend power management not working issue when system starts up and before user touches the trackpad device. TEST=test on Chromebook. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 73 ++++++++++++++++++++++++++++------------ drivers/input/mouse/cyapa.h | 2 +- drivers/input/mouse/cyapa_gen3.c | 4 +-- drivers/input/mouse/cyapa_gen5.c | 21 ++++++++---- drivers/input/mouse/cyapa_gen6.c | 4 +-- 5 files changed, 70 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 2541fbb43533..5c08eeba6162 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -367,6 +367,7 @@ static int cyapa_open(struct input_dev *input) { struct cyapa *cyapa = input_get_drvdata(input); struct i2c_client *client = cyapa->client; + struct device *dev = &client->dev; int error; error = mutex_lock_interruptible(&cyapa->state_sync_lock); @@ -380,10 +381,9 @@ static int cyapa_open(struct input_dev *input) * when in operational mode. */ error = cyapa->ops->set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0); + PWR_MODE_FULL_ACTIVE, 0, false); if (error) { - dev_warn(&client->dev, - "set active power failed: %d\n", error); + dev_warn(dev, "set active power failed: %d\n", error); goto out; } } else { @@ -395,10 +395,14 @@ static int cyapa_open(struct input_dev *input) } enable_irq(client->irq); - if (!pm_runtime_enabled(&client->dev)) { - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + if (!pm_runtime_enabled(dev)) { + pm_runtime_set_active(dev); + pm_runtime_enable(dev); } + + pm_runtime_get_sync(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync_autosuspend(dev); out: mutex_unlock(&cyapa->state_sync_lock); return error; @@ -408,16 +412,17 @@ static void cyapa_close(struct input_dev *input) { struct cyapa *cyapa = input_get_drvdata(input); struct i2c_client *client = cyapa->client; + struct device *dev = &cyapa->client->dev; mutex_lock(&cyapa->state_sync_lock); disable_irq(client->irq); - if (pm_runtime_enabled(&client->dev)) - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); if (cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0, false); mutex_unlock(&cyapa->state_sync_lock); } @@ -527,7 +532,7 @@ static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa) */ if (!input || cyapa->operational) cyapa->ops->set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0); + PWR_MODE_FULL_ACTIVE, 0, false); /* Gen3 always using polling mode for command. */ if (cyapa->gen >= CYAPA_GEN5) enable_irq(cyapa->client->irq); @@ -542,7 +547,8 @@ static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa) if (cyapa->gen >= CYAPA_GEN5) disable_irq(cyapa->client->irq); if (!input || cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + cyapa->ops->set_power_mode(cyapa, + PWR_MODE_OFF, 0, false); } } @@ -609,7 +615,7 @@ static int cyapa_initialize(struct cyapa *cyapa) /* Power down the device until we need it. */ if (cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0, false); return 0; } @@ -625,7 +631,8 @@ static int cyapa_reinitialize(struct cyapa *cyapa) /* Avoid command failures when TP was in OFF state. */ if (cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0); + cyapa->ops->set_power_mode(cyapa, + PWR_MODE_FULL_ACTIVE, 0, false); error = cyapa_detect(cyapa); if (error) @@ -644,7 +651,8 @@ out: if (!input || !input->users) { /* Reset to power OFF state to save power when no user open. */ if (cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + cyapa->ops->set_power_mode(cyapa, + PWR_MODE_OFF, 0, false); } else if (!error && cyapa->operational) { /* * Make sure only enable runtime PM when device is @@ -652,6 +660,10 @@ out: */ pm_runtime_set_active(dev); pm_runtime_enable(dev); + + pm_runtime_get_sync(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync_autosuspend(dev); } return error; @@ -661,8 +673,8 @@ static irqreturn_t cyapa_irq(int irq, void *dev_id) { struct cyapa *cyapa = dev_id; struct device *dev = &cyapa->client->dev; + int error; - pm_runtime_get_sync(dev); if (device_may_wakeup(dev)) pm_wakeup_event(dev, 0); @@ -681,7 +693,24 @@ static irqreturn_t cyapa_irq(int irq, void *dev_id) goto out; } - if (!cyapa->operational || cyapa->ops->irq_handler(cyapa)) { + if (cyapa->operational) { + error = cyapa->ops->irq_handler(cyapa); + + /* + * Apply runtime power management to touch report event + * except the events caused by the command responses. + * Note: + * It will introduce about 20~40 ms additional delay + * time in receiving for first valid touch report data. + * The time is used to execute device runtime resume + * process. + */ + pm_runtime_get_sync(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync_autosuspend(dev); + } + + if (!cyapa->operational || error) { if (!mutex_trylock(&cyapa->state_sync_lock)) { cyapa->ops->sort_empty_output_data(cyapa, NULL, NULL, NULL); @@ -693,8 +722,6 @@ static irqreturn_t cyapa_irq(int irq, void *dev_id) } out: - pm_runtime_mark_last_busy(dev); - pm_runtime_put_sync_autosuspend(dev); return IRQ_HANDLED; } @@ -1335,7 +1362,7 @@ static int __maybe_unused cyapa_suspend(struct device *dev) power_mode = device_may_wakeup(dev) ? cyapa->suspend_power_mode : PWR_MODE_OFF; error = cyapa->ops->set_power_mode(cyapa, power_mode, - cyapa->suspend_sleep_time); + cyapa->suspend_sleep_time, true); if (error) dev_err(dev, "suspend set power mode failed: %d\n", error); @@ -1389,7 +1416,8 @@ static int __maybe_unused cyapa_runtime_suspend(struct device *dev) error = cyapa->ops->set_power_mode(cyapa, cyapa->runtime_suspend_power_mode, - cyapa->runtime_suspend_sleep_time); + cyapa->runtime_suspend_sleep_time, + false); if (error) dev_warn(dev, "runtime suspend failed: %d\n", error); @@ -1401,7 +1429,8 @@ static int __maybe_unused cyapa_runtime_resume(struct device *dev) struct cyapa *cyapa = dev_get_drvdata(dev); int error; - error = cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0); + error = cyapa->ops->set_power_mode(cyapa, + PWR_MODE_FULL_ACTIVE, 0, false); if (error) dev_warn(dev, "runtime resume failed: %d\n", error); diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h index f51deb69c370..af1253640590 100644 --- a/drivers/input/mouse/cyapa.h +++ b/drivers/input/mouse/cyapa.h @@ -273,7 +273,7 @@ struct cyapa_dev_ops { int (*sort_empty_output_data)(struct cyapa *, u8 *, int *, cb_sort); - int (*set_power_mode)(struct cyapa *, u8, u16); + int (*set_power_mode)(struct cyapa *, u8, u16, bool); int (*set_proximity)(struct cyapa *, bool); }; diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c index e7bbfee8b5d6..1a9d12ae7538 100644 --- a/drivers/input/mouse/cyapa_gen3.c +++ b/drivers/input/mouse/cyapa_gen3.c @@ -950,7 +950,7 @@ static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode) * Device power mode can only be set when device is in operational mode. */ static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode, - u16 always_unused) + u16 always_unused, bool is_suspend_unused) { int ret; u8 power; @@ -1112,7 +1112,7 @@ static int cyapa_gen3_do_operational_check(struct cyapa *cyapa) * may cause problems, so we set the power mode first here. */ error = cyapa_gen3_set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0); + PWR_MODE_FULL_ACTIVE, 0, false); if (error) dev_err(dev, "%s: set full power mode failed: %d\n", __func__, error); diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index fa135f855f34..6d7abbed67e4 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "cyapa.h" @@ -1565,7 +1566,7 @@ int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state) } static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, - u8 power_mode, u16 sleep_time) + u8 power_mode, u16 sleep_time, bool is_suspend) { struct device *dev = &cyapa->client->dev; u8 power_state; @@ -1574,9 +1575,6 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, if (cyapa->state != CYAPA_STATE_GEN5_APP) return 0; - /* Dump all the report data before do power mode commmands. */ - cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); - if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { /* * Assume TP in deep sleep mode when driver is loaded, @@ -1679,8 +1677,8 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, * is suspending which may cause interrupt line unable to be * asserted again. */ - cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); - cyapa_gen5_disable_pip_report(cyapa); + if (is_suspend) + cyapa_gen5_disable_pip_report(cyapa); PIP_DEV_SET_PWR_STATE(cyapa, cyapa_sleep_time_to_pwr_cmd(sleep_time)); @@ -2515,7 +2513,7 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) * the device state is required. */ error = cyapa_gen5_set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0); + PWR_MODE_FULL_ACTIVE, 0, false); if (error) dev_warn(dev, "%s: failed to set power active mode.\n", __func__); @@ -2757,7 +2755,16 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa) /* * Device wake event from deep sleep mode for touch. * This interrupt event is used to wake system up. + * + * Note: + * It will introduce about 20~40 ms additional delay + * time in receiving for first valid touch report data. + * The time is used to execute device runtime resume + * process. */ + pm_runtime_get_sync(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync_autosuspend(dev); return 0; } else if (report_id != PIP_TOUCH_REPORT_ID && report_id != PIP_BTN_REPORT_ID && diff --git a/drivers/input/mouse/cyapa_gen6.c b/drivers/input/mouse/cyapa_gen6.c index 61f04132eb65..5f191071d44a 100644 --- a/drivers/input/mouse/cyapa_gen6.c +++ b/drivers/input/mouse/cyapa_gen6.c @@ -429,7 +429,7 @@ static int cyapa_gen6_deep_sleep(struct cyapa *cyapa, u8 state) } static int cyapa_gen6_set_power_mode(struct cyapa *cyapa, - u8 power_mode, u16 sleep_time) + u8 power_mode, u16 sleep_time, bool is_suspend) { struct device *dev = &cyapa->client->dev; struct gen6_interval_setting *interval_setting = @@ -693,7 +693,7 @@ static int cyapa_gen6_operational_check(struct cyapa *cyapa) * the device state is required. */ error = cyapa_gen6_set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0); + PWR_MODE_FULL_ACTIVE, 0, false); if (error) dev_warn(dev, "%s: failed to set power active mode.\n", __func__); -- cgit v1.3-6-gb490 From ce2ae9e3e6a152866a33972c966f8315aab2cb1d Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Mon, 20 Jul 2015 17:15:46 -0700 Subject: Input: cyapa - add ACPI HID CYAP0002 for Gen6 devices Add CYTP0002 to the list of ACPI HIDs recognized by the driver. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 5c08eeba6162..6195ccb3cfde 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -1452,6 +1452,7 @@ MODULE_DEVICE_TABLE(i2c, cyapa_id_table); static const struct acpi_device_id cyapa_acpi_id[] = { { "CYAP0000", 0 }, /* Gen3 trackpad with 0x67 I2C address. */ { "CYAP0001", 0 }, /* Gen5 trackpad with 0x24 I2C address. */ + { "CYAP0002", 0 }, /* Gen6 trackpad with 0x24 I2C address. */ { } }; MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id); -- cgit v1.3-6-gb490 From e75ed3c47a2082fad87dd6d726ff7275d35e197c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 10:32:27 -0700 Subject: Input: arizona-haptic - convert to use managed input devices Using managed input device (via devm_input_allocate_device) simplifies error handling and driver removal paths and also silences CID# 712569. Reviewed-by: Joshua Clayton Signed-off-by: Dmitry Torokhov --- drivers/input/misc/arizona-haptics.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c index 4dbbed74c9e4..4bf678541496 100644 --- a/drivers/input/misc/arizona-haptics.c +++ b/drivers/input/misc/arizona-haptics.c @@ -170,8 +170,8 @@ static int arizona_haptics_probe(struct platform_device *pdev) INIT_WORK(&haptics->work, arizona_haptics_work); - haptics->input_dev = input_allocate_device(); - if (haptics->input_dev == NULL) { + haptics->input_dev = devm_input_allocate_device(&pdev->dev); + if (!haptics->input_dev) { dev_err(arizona->dev, "Failed to allocate input device\n"); return -ENOMEM; } @@ -188,41 +188,23 @@ static int arizona_haptics_probe(struct platform_device *pdev) if (ret < 0) { dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n", ret); - goto err_ialloc; + return ret; } ret = input_register_device(haptics->input_dev); if (ret < 0) { dev_err(arizona->dev, "couldn't register input device: %d\n", ret); - goto err_iff; + return ret; } platform_set_drvdata(pdev, haptics); - return 0; - -err_iff: - if (haptics->input_dev) - input_ff_destroy(haptics->input_dev); -err_ialloc: - input_free_device(haptics->input_dev); - - return ret; -} - -static int arizona_haptics_remove(struct platform_device *pdev) -{ - struct arizona_haptics *haptics = platform_get_drvdata(pdev); - - input_unregister_device(haptics->input_dev); - return 0; } static struct platform_driver arizona_haptics_driver = { .probe = arizona_haptics_probe, - .remove = arizona_haptics_remove, .driver = { .name = "arizona-haptics", }, -- cgit v1.3-6-gb490 From 6b596a834177f87846559f3f364b38cafdb13b61 Mon Sep 17 00:00:00 2001 From: Maxime Coquelin Date: Tue, 16 Jun 2015 11:12:19 +0200 Subject: serial: stm32-usart: Fix SysRq support SysRq support activation depends on CONFIG_SERIAL_STM32_USART_CONSOLE, but this config flag does not exists. This patch fix this by depending on the valid config flag, which is SERIAL_STM32_CONSOLE. Reported-by: Andreas Ruprecht Signed-off-by: Maxime Coquelin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 4a6eab6da63e..e3de9c6d2226 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -6,7 +6,7 @@ * Inspired by st-asc.c from STMicroelectronics (c) */ -#if defined(CONFIG_SERIAL_STM32_USART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#if defined(CONFIG_SERIAL_STM32_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif -- cgit v1.3-6-gb490 From 1eacbfb06df9d37b743d0eedbeb9fd4f71190c98 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Mon, 15 Jun 2015 16:36:07 +0200 Subject: serial/uartlite: Let it build on any arch with IOMEM Being a soft core, it can be located not only on PPC or Microblaze platforms. Since the driver already does endianness detection we only need to change the Kconfig to use it in other arches. This is also done in other softcores as xilinx-spi. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 76e65b714471..10a5f0a503e3 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -594,7 +594,7 @@ config SERIAL_IMX_CONSOLE config SERIAL_UARTLITE tristate "Xilinx uartlite serial port support" - depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE || ARCH_ZYNQ + depends on HAS_IOMEM select SERIAL_CORE help Say Y here if you want to use the Xilinx uartlite serial controller. -- cgit v1.3-6-gb490 From 8a61f0c70ae65c6b70d13228c3120c73d7425a60 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 17 Jun 2015 17:35:43 -0300 Subject: serial: imx: Disable irqs before requesting them Disable interrupts before requesting them in order to fix a kernel oops after lauching a kernel via kexec. Tested on a imx6sl-evk board. Signed-off-by: Fabio Estevam Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 2c90dc31bfaa..cddf9026a72b 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1902,7 +1902,7 @@ static int serial_imx_probe(struct platform_device *pdev) { struct imx_port *sport; void __iomem *base; - int ret = 0; + int ret = 0, reg; struct resource *res; int txirq, rxirq, rtsirq; @@ -1957,6 +1957,19 @@ static int serial_imx_probe(struct platform_device *pdev) sport->port.uartclk = clk_get_rate(sport->clk_per); + /* For register access, we only need to enable the ipg clock. */ + ret = clk_prepare_enable(sport->clk_ipg); + if (ret) + return ret; + + /* Disable interrupts before requesting them */ + reg = readl_relaxed(sport->port.membase + UCR1); + reg &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | + UCR1_TXMPTYEN | UCR1_RTSDEN); + writel_relaxed(reg, sport->port.membase + UCR1); + + clk_disable_unprepare(sport->clk_ipg); + /* * Allocate the IRQ(s) i.MX1 has three interrupts whereas later * chips only have one interrupt. -- cgit v1.3-6-gb490 From 9b289932610edff7d0c11228efbf7a6f81361298 Mon Sep 17 00:00:00 2001 From: Manfred Schlaegl Date: Sat, 20 Jun 2015 19:25:35 +0200 Subject: serial: imx: count tty buffer overruns As can be seen in function uart_insert_char (serial_core) the element buf_overrun of struct uart_icount is used to count overruns of tty-buffer. Added support for counting of overruns in imx driver analogue to serial_core. Signed-off-by: Manfred Schlaegl Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index cddf9026a72b..0628fc4841ca 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -700,7 +700,8 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) if (sport->port.ignore_status_mask & URXD_DUMMY_READ) goto out; - tty_insert_flip_char(port, rx, flg); + if (tty_insert_flip_char(port, rx, flg) == 0) + sport->port.icount.buf_overrun++; } out: @@ -921,8 +922,13 @@ static void dma_rx_callback(void *data) dev_dbg(sport->port.dev, "We get %d bytes.\n", count); if (count) { - if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) - tty_insert_flip_string(port, sport->rx_buf, count); + if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) { + int bytes = tty_insert_flip_string(port, sport->rx_buf, + count); + + if (bytes != count) + sport->port.icount.buf_overrun++; + } tty_flip_buffer_push(port); start_rx_dma(sport); -- cgit v1.3-6-gb490 From e9b5a9825f6b02a9cf86697bcffafd3d7898f9f6 Mon Sep 17 00:00:00 2001 From: Manfred Schlaegl Date: Sat, 20 Jun 2015 19:25:52 +0200 Subject: serial: imx: reduce irq-latency after rx overflow To prevent problems with interrupt latency, and due to the fact, that the error will be counted anyway (icount.overrun), the dev_err is simply removed. Background: If an rx-fifo overflow occurs a dev_err message was called in interrupt context. Since dev_err messages are written to console in a synchronous way (unbuffered), and console may be a serial terminal, this leads to a highly increased interrupt-latency (several milliseconds). As a result of the high latency more rx-fifo overflows will happen, and therefore a feedback loop of errors is created. Signed-off-by: Manfred Schlaegl Acked-By: Alexander Stein Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 0628fc4841ca..5b44d53f65b5 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -767,7 +767,6 @@ static irqreturn_t imx_int(int irq, void *dev_id) writel(USR1_AWAKE, sport->port.membase + USR1); if (sts2 & USR2_ORE) { - dev_err(sport->port.dev, "Rx FIFO overrun\n"); sport->port.icount.overrun++; writel(USR2_ORE, sport->port.membase + USR2); } -- cgit v1.3-6-gb490 From e95044ba4fee93f5ea8a1a24b2d921e148503833 Mon Sep 17 00:00:00 2001 From: David Jander Date: Thu, 2 Jul 2015 16:29:49 +0200 Subject: tty: serial: imx.c: Reset UART before activating interrupts If the UART has been in use before this driver was loaded, IRQs might be active and get fired as soon as we set the handler, which will crash in the spin_lock_irqsave(&sport->port.lock, flags) because port.lock is not initialized until the port is added at the end of probe. Signed-off-by: David Jander Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 5b44d53f65b5..83b02d494723 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1098,10 +1098,23 @@ static void imx_disable_dma(struct imx_port *sport) /* half the RX buffer size */ #define CTSTL 16 +static inline void imx_reset(struct imx_port *sport) +{ + int i = 100; + unsigned long temp; + + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_SRST; + writel(temp, sport->port.membase + UCR2); + + while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) + udelay(1); +} + static int imx_startup(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - int retval, i; + int retval; unsigned long flags, temp; retval = clk_prepare_enable(sport->clk_per); @@ -1133,14 +1146,7 @@ static int imx_startup(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); /* Reset fifo's and state machines */ - i = 100; - - temp = readl(sport->port.membase + UCR2); - temp &= ~UCR2_SRST; - writel(temp, sport->port.membase + UCR2); - - while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) - udelay(1); + imx_reset(sport); /* * Finally, clear and enable interrupts @@ -1975,6 +1981,14 @@ static int serial_imx_probe(struct platform_device *pdev) clk_disable_unprepare(sport->clk_ipg); + /* + * Perform a complete reset of the UART device. Needed if we don't + * come straight out of reset. + */ + writel(0, sport->port.membase + UCR2); + writel(0, sport->port.membase + UCR1); + imx_reset(sport); + /* * Allocate the IRQ(s) i.MX1 has three interrupts whereas later * chips only have one interrupt. -- cgit v1.3-6-gb490 From b6830f6df8914faae9561bb245860c21af9b9e9b Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 27 Jun 2015 09:19:00 -0400 Subject: serial: 8250: Split base port operations from universal driver Refactor base port operations into new file; 8250_port.c. Legacy irq handling, RSA port support, port storage for universal driver, driver definition, module parameters and linkage remain in 8250_core.c The source file split and resulting modules is diagrammed below: 8250_core.c ====> 8250_core.c __ \ \ \ +-- 8250.ko (alias 8250_core) \ 8250_pnp.c __/ (universal driver) \ => 8250_port.c __ \ +-- 8250_base.ko 8250_dma.c __/ (port operations) Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250.h | 11 + drivers/tty/serial/8250/8250_core.c | 3260 +++-------------------------------- drivers/tty/serial/8250/8250_port.c | 2898 +++++++++++++++++++++++++++++++ drivers/tty/serial/8250/Makefile | 5 +- include/linux/serial_8250.h | 5 + 5 files changed, 3116 insertions(+), 3063 deletions(-) create mode 100644 drivers/tty/serial/8250/8250_port.c (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index c43f74c53cd9..dd233108ec07 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -211,3 +211,14 @@ static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) } return 1; } + +static inline int serial_index(struct uart_port *port) +{ + return port->minor - 64; +} + +#if 0 +#define DEBUG_INTR(fmt...) printk(fmt) +#else +#define DEBUG_INTR(fmt...) do { } while (0) +#endif diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 37fff12dd4d0..cfbb9d728e31 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1,25 +1,23 @@ /* - * Driver for 8250/16550-type serial ports + * Universal/legacy driver for 8250/16550-type serial ports * * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * * Copyright (C) 2001 Russell King. * + * Supports: ISA-compatible 8250/16550 ports + * PNP 8250/16550 ports + * early_serial_setup() ports + * userspace-configurable "phantom" ports + * "serial8250" platform devices + * serial8250_register_8250_port() ports + * * 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. - * - * A note about mapbase / membase - * - * mapbase is the physical address of the IO port. - * membase is an 'ioremapped' cookie. */ -#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - #include #include #include @@ -58,33 +56,10 @@ static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; static struct uart_driver serial8250_reg; -static int serial_index(struct uart_port *port) -{ - return port->minor - 64; -} - static unsigned int skip_txen_test; /* force skip of txen test at init time */ -/* - * Debugging. - */ -#if 0 -#define DEBUG_AUTOCONF(fmt...) printk(fmt) -#else -#define DEBUG_AUTOCONF(fmt...) do { } while (0) -#endif - -#if 0 -#define DEBUG_INTR(fmt...) printk(fmt) -#else -#define DEBUG_INTR(fmt...) do { } while (0) -#endif - #define PASS_LIMIT 512 -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - - #include /* * SERIAL_PORT_DFNS tells us about built-in ports that have no @@ -120,2695 +95,268 @@ static struct hlist_head irq_lists[NR_IRQ_HASH]; static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */ /* - * Here we define the default xmit fifo size used for each type of UART. + * This is the serial driver's interrupt routine. + * + * Arjan thinks the old way was overly complex, so it got simplified. + * Alan disagrees, saying that need the complexity to handle the weird + * nature of ISA shared interrupts. (This is a special exception.) + * + * In order to handle ISA shared interrupts properly, we need to check + * that all ports have been serviced, and therefore the ISA interrupt + * line has been de-asserted. + * + * This means we need to loop through all ports. checking that they + * don't have an interrupt pending. */ -static const struct serial8250_config uart_config[] = { - [PORT_UNKNOWN] = { - .name = "unknown", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_8250] = { - .name = "8250", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16450] = { - .name = "16450", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16550] = { - .name = "16550", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16550A] = { - .name = "16550A", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .rxtrig_bytes = {1, 4, 8, 14}, - .flags = UART_CAP_FIFO, - }, - [PORT_CIRRUS] = { - .name = "Cirrus", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16650] = { - .name = "ST16650", - .fifo_size = 1, - .tx_loadsz = 1, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16650V2] = { - .name = "ST16650V2", - .fifo_size = 32, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | - UART_FCR_T_TRIG_00, - .rxtrig_bytes = {8, 16, 24, 28}, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16750] = { - .name = "TI16750", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | - UART_FCR7_64BYTE, - .rxtrig_bytes = {1, 16, 32, 56}, - .flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE, - }, - [PORT_STARTECH] = { - .name = "Startech", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16C950] = { - .name = "16C950/954", - .fifo_size = 128, - .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - /* UART_CAP_EFR breaks billionon CF bluetooth card. */ - .flags = UART_CAP_FIFO | UART_CAP_SLEEP, - }, - [PORT_16654] = { - .name = "ST16654", - .fifo_size = 64, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | - UART_FCR_T_TRIG_10, - .rxtrig_bytes = {8, 16, 56, 60}, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16850] = { - .name = "XR16850", - .fifo_size = 128, - .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_RSA] = { - .name = "RSA", - .fifo_size = 2048, - .tx_loadsz = 2048, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11, - .flags = UART_CAP_FIFO, - }, - [PORT_NS16550A] = { - .name = "NS16550A", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_NATSEMI, - }, - [PORT_XSCALE] = { - .name = "XScale", - .fifo_size = 32, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_UUE | UART_CAP_RTOIE, - }, - [PORT_OCTEON] = { - .name = "OCTEON", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO, - }, - [PORT_AR7] = { - .name = "AR7", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_U6_16550A] = { - .name = "U6_16550A", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_TEGRA] = { - .name = "Tegra", - .fifo_size = 32, - .tx_loadsz = 8, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | - UART_FCR_T_TRIG_01, - .rxtrig_bytes = {1, 4, 8, 14}, - .flags = UART_CAP_FIFO | UART_CAP_RTOIE, - }, - [PORT_XR17D15X] = { - .name = "XR17D15X", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP, - }, - [PORT_XR17V35X] = { - .name = "XR17V35X", - .fifo_size = 256, - .tx_loadsz = 256, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 | - UART_FCR_T_TRIG_11, - .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP, - }, - [PORT_LPC3220] = { - .name = "LPC3220", - .fifo_size = 64, - .tx_loadsz = 32, - .fcr = UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO | - UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00, - .flags = UART_CAP_FIFO, - }, - [PORT_BRCM_TRUMANAGE] = { - .name = "TruManage", - .fifo_size = 1, - .tx_loadsz = 1024, - .flags = UART_CAP_HFIFO, - }, - [PORT_8250_CIR] = { - .name = "CIR port" - }, - [PORT_ALTR_16550_F32] = { - .name = "Altera 16550 FIFO32", - .fifo_size = 32, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_ALTR_16550_F64] = { - .name = "Altera 16550 FIFO64", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_ALTR_16550_F128] = { - .name = "Altera 16550 FIFO128", - .fifo_size = 128, - .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, -/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement -workaround of errata A-008006 which states that tx_loadsz should be -configured less than Maximum supported fifo bytes */ - [PORT_16550A_FSL64] = { - .name = "16550A_FSL64", - .fifo_size = 64, - .tx_loadsz = 63, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | - UART_FCR7_64BYTE, - .flags = UART_CAP_FIFO, - }, -}; - -/* Uart divisor latch read */ -static int default_serial_dl_read(struct uart_8250_port *up) -{ - return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; -} - -/* Uart divisor latch write */ -static void default_serial_dl_write(struct uart_8250_port *up, int value) -{ - serial_out(up, UART_DLL, value & 0xff); - serial_out(up, UART_DLM, value >> 8 & 0xff); -} - -#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) - -/* Au1x00/RT288x UART hardware has a weird register layout */ -static const s8 au_io_in_map[8] = { - 0, /* UART_RX */ - 2, /* UART_IER */ - 3, /* UART_IIR */ - 5, /* UART_LCR */ - 6, /* UART_MCR */ - 7, /* UART_LSR */ - 8, /* UART_MSR */ - -1, /* UART_SCR (unmapped) */ -}; - -static const s8 au_io_out_map[8] = { - 1, /* UART_TX */ - 2, /* UART_IER */ - 4, /* UART_FCR */ - 5, /* UART_LCR */ - 6, /* UART_MCR */ - -1, /* UART_LSR (unmapped) */ - -1, /* UART_MSR (unmapped) */ - -1, /* UART_SCR (unmapped) */ -}; - -static unsigned int au_serial_in(struct uart_port *p, int offset) -{ - if (offset >= ARRAY_SIZE(au_io_in_map)) - return UINT_MAX; - offset = au_io_in_map[offset]; - if (offset < 0) - return UINT_MAX; - return __raw_readl(p->membase + (offset << p->regshift)); -} - -static void au_serial_out(struct uart_port *p, int offset, int value) -{ - if (offset >= ARRAY_SIZE(au_io_out_map)) - return; - offset = au_io_out_map[offset]; - if (offset < 0) - return; - __raw_writel(value, p->membase + (offset << p->regshift)); -} - -/* Au1x00 haven't got a standard divisor latch */ -static int au_serial_dl_read(struct uart_8250_port *up) +static irqreturn_t serial8250_interrupt(int irq, void *dev_id) { - return __raw_readl(up->port.membase + 0x28); -} + struct irq_info *i = dev_id; + struct list_head *l, *end = NULL; + int pass_counter = 0, handled = 0; -static void au_serial_dl_write(struct uart_8250_port *up, int value) -{ - __raw_writel(value, up->port.membase + 0x28); -} + DEBUG_INTR("serial8250_interrupt(%d)...", irq); -#endif + spin_lock(&i->lock); -static unsigned int hub6_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - outb(p->hub6 - 1 + offset, p->iobase); - return inb(p->iobase + 1); -} + l = i->head; + do { + struct uart_8250_port *up; + struct uart_port *port; -static void hub6_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - outb(p->hub6 - 1 + offset, p->iobase); - outb(value, p->iobase + 1); -} + up = list_entry(l, struct uart_8250_port, list); + port = &up->port; -static unsigned int mem_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - return readb(p->membase + offset); -} + if (port->handle_irq(port)) { + handled = 1; + end = NULL; + } else if (end == NULL) + end = l; -static void mem_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - writeb(value, p->membase + offset); -} + l = l->next; -static void mem32_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - writel(value, p->membase + offset); -} + if (l == i->head && pass_counter++ > PASS_LIMIT) { + /* If we hit this, we're dead. */ + printk_ratelimited(KERN_ERR + "serial8250: too much work for irq%d\n", irq); + break; + } + } while (l != end); -static unsigned int mem32_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - return readl(p->membase + offset); -} + spin_unlock(&i->lock); -static void mem32be_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - iowrite32be(value, p->membase + offset); -} + DEBUG_INTR("end.\n"); -static unsigned int mem32be_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - return ioread32be(p->membase + offset); + return IRQ_RETVAL(handled); } -static unsigned int io_serial_in(struct uart_port *p, int offset) +/* + * To support ISA shared interrupts, we need to have one interrupt + * handler that ensures that the IRQ line has been deasserted + * before returning. Failing to do this will result in the IRQ + * line being stuck active, and, since ISA irqs are edge triggered, + * no more IRQs will be seen. + */ +static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up) { - offset = offset << p->regshift; - return inb(p->iobase + offset); -} + spin_lock_irq(&i->lock); -static void io_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - outb(value, p->iobase + offset); + if (!list_empty(i->head)) { + if (i->head == &up->list) + i->head = i->head->next; + list_del(&up->list); + } else { + BUG_ON(i->head != &up->list); + i->head = NULL; + } + spin_unlock_irq(&i->lock); + /* List empty so throw away the hash node */ + if (i->head == NULL) { + hlist_del(&i->node); + kfree(i); + } } -static int serial8250_default_handle_irq(struct uart_port *port); -static int exar_handle_irq(struct uart_port *port); - -static void set_io_from_upio(struct uart_port *p) +static int serial_link_irq_chain(struct uart_8250_port *up) { - struct uart_8250_port *up = up_to_u8250p(p); - - up->dl_read = default_serial_dl_read; - up->dl_write = default_serial_dl_write; + struct hlist_head *h; + struct hlist_node *n; + struct irq_info *i; + int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; - switch (p->iotype) { - case UPIO_HUB6: - p->serial_in = hub6_serial_in; - p->serial_out = hub6_serial_out; - break; + mutex_lock(&hash_mutex); - case UPIO_MEM: - p->serial_in = mem_serial_in; - p->serial_out = mem_serial_out; - break; + h = &irq_lists[up->port.irq % NR_IRQ_HASH]; - case UPIO_MEM32: - p->serial_in = mem32_serial_in; - p->serial_out = mem32_serial_out; - break; + hlist_for_each(n, h) { + i = hlist_entry(n, struct irq_info, node); + if (i->irq == up->port.irq) + break; + } - case UPIO_MEM32BE: - p->serial_in = mem32be_serial_in; - p->serial_out = mem32be_serial_out; - break; + if (n == NULL) { + i = kzalloc(sizeof(struct irq_info), GFP_KERNEL); + if (i == NULL) { + mutex_unlock(&hash_mutex); + return -ENOMEM; + } + spin_lock_init(&i->lock); + i->irq = up->port.irq; + hlist_add_head(&i->node, h); + } + mutex_unlock(&hash_mutex); -#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) - case UPIO_AU: - p->serial_in = au_serial_in; - p->serial_out = au_serial_out; - up->dl_read = au_serial_dl_read; - up->dl_write = au_serial_dl_write; - break; -#endif + spin_lock_irq(&i->lock); - default: - p->serial_in = io_serial_in; - p->serial_out = io_serial_out; - break; - } - /* Remember loaded iotype */ - up->cur_iotype = p->iotype; - p->handle_irq = serial8250_default_handle_irq; -} + if (i->head) { + list_add(&up->list, i->head); + spin_unlock_irq(&i->lock); -static void -serial_port_out_sync(struct uart_port *p, int offset, int value) -{ - switch (p->iotype) { - case UPIO_MEM: - case UPIO_MEM32: - case UPIO_MEM32BE: - case UPIO_AU: - p->serial_out(p, offset, value); - p->serial_in(p, UART_LCR); /* safe, no side-effects */ - break; - default: - p->serial_out(p, offset, value); + ret = 0; + } else { + INIT_LIST_HEAD(&up->list); + i->head = &up->list; + spin_unlock_irq(&i->lock); + irq_flags |= up->port.irqflags; + ret = request_irq(up->port.irq, serial8250_interrupt, + irq_flags, "serial", i); + if (ret < 0) + serial_do_unlink(i, up); } -} -/* - * For the 16C950 - */ -static void serial_icr_write(struct uart_8250_port *up, int offset, int value) -{ - serial_out(up, UART_SCR, offset); - serial_out(up, UART_ICR, value); + return ret; } -static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) +static void serial_unlink_irq_chain(struct uart_8250_port *up) { - unsigned int value; + /* + * yes, some broken gcc emit "warning: 'i' may be used uninitialized" + * but no, we are not going to take a patch that assigns NULL below. + */ + struct irq_info *i; + struct hlist_node *n; + struct hlist_head *h; - serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); - serial_out(up, UART_SCR, offset); - value = serial_in(up, UART_ICR); - serial_icr_write(up, UART_ACR, up->acr); + mutex_lock(&hash_mutex); - return value; -} + h = &irq_lists[up->port.irq % NR_IRQ_HASH]; -/* - * FIFO support. - */ -static void serial8250_clear_fifos(struct uart_8250_port *p) -{ - if (p->capabilities & UART_CAP_FIFO) { - serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(p, UART_FCR, 0); + hlist_for_each(n, h) { + i = hlist_entry(n, struct irq_info, node); + if (i->irq == up->port.irq) + break; } -} -void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) -{ - serial8250_clear_fifos(p); - serial_out(p, UART_FCR, p->fcr); -} -EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); + BUG_ON(n == NULL); + BUG_ON(i->head == NULL); -void serial8250_rpm_get(struct uart_8250_port *p) -{ - if (!(p->capabilities & UART_CAP_RPM)) - return; - pm_runtime_get_sync(p->port.dev); -} -EXPORT_SYMBOL_GPL(serial8250_rpm_get); + if (list_empty(i->head)) + free_irq(up->port.irq, i); -void serial8250_rpm_put(struct uart_8250_port *p) -{ - if (!(p->capabilities & UART_CAP_RPM)) - return; - pm_runtime_mark_last_busy(p->port.dev); - pm_runtime_put_autosuspend(p->port.dev); + serial_do_unlink(i, up); + mutex_unlock(&hash_mutex); } -EXPORT_SYMBOL_GPL(serial8250_rpm_put); /* - * These two wrappers ensure that enable_runtime_pm_tx() can be called more than - * once and disable_runtime_pm_tx() will still disable RPM because the fifo is - * empty and the HW can idle again. + * This function is used to handle ports that do not have an + * interrupt. This doesn't work very well for 16450's, but gives + * barely passable results for a 16550A. (Although at the expense + * of much CPU overhead). */ -static void serial8250_rpm_get_tx(struct uart_8250_port *p) +static void serial8250_timeout(unsigned long data) { - unsigned char rpm_active; - - if (!(p->capabilities & UART_CAP_RPM)) - return; + struct uart_8250_port *up = (struct uart_8250_port *)data; - rpm_active = xchg(&p->rpm_tx_active, 1); - if (rpm_active) - return; - pm_runtime_get_sync(p->port.dev); + up->port.handle_irq(&up->port); + mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); } -static void serial8250_rpm_put_tx(struct uart_8250_port *p) +static void serial8250_backup_timeout(unsigned long data) { - unsigned char rpm_active; + struct uart_8250_port *up = (struct uart_8250_port *)data; + unsigned int iir, ier = 0, lsr; + unsigned long flags; - if (!(p->capabilities & UART_CAP_RPM)) - return; - - rpm_active = xchg(&p->rpm_tx_active, 0); - if (!rpm_active) - return; - pm_runtime_mark_last_busy(p->port.dev); - pm_runtime_put_autosuspend(p->port.dev); -} - -/* - * IER sleep support. UARTs which have EFRs need the "extended - * capability" bit enabled. Note that on XR16C850s, we need to - * reset LCR to write to IER. - */ -static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) -{ - unsigned char lcr = 0, efr = 0; - /* - * Exar UARTs have a SLEEP register that enables or disables - * each UART to enter sleep mode separately. On the XR17V35x the - * register is accessible to each UART at the UART_EXAR_SLEEP - * offset but the UART channel may only write to the corresponding - * bit. - */ - serial8250_rpm_get(p); - if ((p->port.type == PORT_XR17V35X) || - (p->port.type == PORT_XR17D15X)) { - serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0); - goto out; - } - - if (p->capabilities & UART_CAP_SLEEP) { - if (p->capabilities & UART_CAP_EFR) { - lcr = serial_in(p, UART_LCR); - efr = serial_in(p, UART_EFR); - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, UART_EFR_ECB); - serial_out(p, UART_LCR, 0); - } - serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); - if (p->capabilities & UART_CAP_EFR) { - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, efr); - serial_out(p, UART_LCR, lcr); - } - } -out: - serial8250_rpm_put(p); -} - -#ifdef CONFIG_SERIAL_8250_RSA -/* - * Attempts to turn on the RSA FIFO. Returns zero on failure. - * We set the port uart clock rate if we succeed. - */ -static int __enable_rsa(struct uart_8250_port *up) -{ - unsigned char mode; - int result; - - mode = serial_in(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - - if (!result) { - serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); - mode = serial_in(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; - - return result; -} - -static void enable_rsa(struct uart_8250_port *up) -{ - if (up->port.type == PORT_RSA) { - if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - __enable_rsa(up); - spin_unlock_irq(&up->port.lock); - } - if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) - serial_out(up, UART_RSA_FRR, 0); - } -} - -/* - * Attempts to turn off the RSA FIFO. Returns zero on failure. - * It is unknown why interrupts were disabled in here. However, - * the caller is expected to preserve this behaviour by grabbing - * the spinlock before calling this function. - */ -static void disable_rsa(struct uart_8250_port *up) -{ - unsigned char mode; - int result; - - if (up->port.type == PORT_RSA && - up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - - mode = serial_in(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - - if (!result) { - serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); - mode = serial_in(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; - spin_unlock_irq(&up->port.lock); - } -} -#endif /* CONFIG_SERIAL_8250_RSA */ - -/* - * This is a quickie test to see how big the FIFO is. - * It doesn't work at all the time, more's the pity. - */ -static int size_fifo(struct uart_8250_port *up) -{ - unsigned char old_fcr, old_mcr, old_lcr; - unsigned short old_dl; - int count; - - old_lcr = serial_in(up, UART_LCR); - serial_out(up, UART_LCR, 0); - old_fcr = serial_in(up, UART_FCR); - old_mcr = serial_in(up, UART_MCR); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(up, UART_MCR, UART_MCR_LOOP); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - old_dl = serial_dl_read(up); - serial_dl_write(up, 0x0001); - serial_out(up, UART_LCR, 0x03); - for (count = 0; count < 256; count++) - serial_out(up, UART_TX, count); - mdelay(20);/* FIXME - schedule_timeout */ - for (count = 0; (serial_in(up, UART_LSR) & UART_LSR_DR) && - (count < 256); count++) - serial_in(up, UART_RX); - serial_out(up, UART_FCR, old_fcr); - serial_out(up, UART_MCR, old_mcr); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_dl_write(up, old_dl); - serial_out(up, UART_LCR, old_lcr); - - return count; -} - -/* - * Read UART ID using the divisor method - set DLL and DLM to zero - * and the revision will be in DLL and device type in DLM. We - * preserve the device state across this. - */ -static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) -{ - unsigned char old_dll, old_dlm, old_lcr; - unsigned int id; - - old_lcr = serial_in(p, UART_LCR); - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A); - - old_dll = serial_in(p, UART_DLL); - old_dlm = serial_in(p, UART_DLM); - - serial_out(p, UART_DLL, 0); - serial_out(p, UART_DLM, 0); - - id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8; - - serial_out(p, UART_DLL, old_dll); - serial_out(p, UART_DLM, old_dlm); - serial_out(p, UART_LCR, old_lcr); - - return id; -} - -/* - * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. - * When this function is called we know it is at least a StarTech - * 16650 V2, but it might be one of several StarTech UARTs, or one of - * its clones. (We treat the broken original StarTech 16650 V1 as a - * 16550, and why not? Startech doesn't seem to even acknowledge its - * existence.) - * - * What evil have men's minds wrought... - */ -static void autoconfig_has_efr(struct uart_8250_port *up) -{ - unsigned int id1, id2, id3, rev; - - /* - * Everything with an EFR has SLEEP - */ - up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; - - /* - * First we check to see if it's an Oxford Semiconductor UART. - * - * If we have to do this here because some non-National - * Semiconductor clone chips lock up if you try writing to the - * LSR register (which serial_icr_read does) - */ - - /* - * Check for Oxford Semiconductor 16C950. - * - * EFR [4] must be set else this test fails. - * - * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca) - * claims that it's needed for 952 dual UART's (which are not - * recommended for new designs). - */ - up->acr = 0; - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, UART_EFR_ECB); - serial_out(up, UART_LCR, 0x00); - id1 = serial_icr_read(up, UART_ID1); - id2 = serial_icr_read(up, UART_ID2); - id3 = serial_icr_read(up, UART_ID3); - rev = serial_icr_read(up, UART_REV); - - DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); - - if (id1 == 0x16 && id2 == 0xC9 && - (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { - up->port.type = PORT_16C950; - - /* - * Enable work around for the Oxford Semiconductor 952 rev B - * chip which causes it to seriously miscalculate baud rates - * when DLL is 0. - */ - if (id3 == 0x52 && rev == 0x01) - up->bugs |= UART_BUG_QUOT; - return; - } - - /* - * We check for a XR16C850 by setting DLL and DLM to 0, and then - * reading back DLL and DLM. The chip type depends on the DLM - * value read back: - * 0x10 - XR16C850 and the DLL contains the chip revision. - * 0x12 - XR16C2850. - * 0x14 - XR16C854. - */ - id1 = autoconfig_read_divisor_id(up); - DEBUG_AUTOCONF("850id=%04x ", id1); - - id2 = id1 >> 8; - if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) { - up->port.type = PORT_16850; - return; - } - - /* - * It wasn't an XR16C850. - * - * We distinguish between the '654 and the '650 by counting - * how many bytes are in the FIFO. I'm using this for now, - * since that's the technique that was sent to me in the - * serial driver update, but I'm not convinced this works. - * I've had problems doing this in the past. -TYT - */ - if (size_fifo(up) == 64) - up->port.type = PORT_16654; - else - up->port.type = PORT_16650V2; -} - -/* - * We detected a chip without a FIFO. Only two fall into - * this category - the original 8250 and the 16450. The - * 16450 has a scratch register (accessible with LCR=0) - */ -static void autoconfig_8250(struct uart_8250_port *up) -{ - unsigned char scratch, status1, status2; - - up->port.type = PORT_8250; - - scratch = serial_in(up, UART_SCR); - serial_out(up, UART_SCR, 0xa5); - status1 = serial_in(up, UART_SCR); - serial_out(up, UART_SCR, 0x5a); - status2 = serial_in(up, UART_SCR); - serial_out(up, UART_SCR, scratch); - - if (status1 == 0xa5 && status2 == 0x5a) - up->port.type = PORT_16450; -} - -static int broken_efr(struct uart_8250_port *up) -{ - /* - * Exar ST16C2550 "A2" devices incorrectly detect as - * having an EFR, and report an ID of 0x0201. See - * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html - */ - if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) - return 1; - - return 0; -} - -/* - * We know that the chip has FIFOs. Does it have an EFR? The - * EFR is located in the same register position as the IIR and - * we know the top two bits of the IIR are currently set. The - * EFR should contain zero. Try to read the EFR. - */ -static void autoconfig_16550a(struct uart_8250_port *up) -{ - unsigned char status1, status2; - unsigned int iersave; - - up->port.type = PORT_16550A; - up->capabilities |= UART_CAP_FIFO; - - /* - * XR17V35x UARTs have an extra divisor register, DLD - * that gets enabled with when DLAB is set which will - * cause the device to incorrectly match and assign - * port type to PORT_16650. The EFR for this UART is - * found at offset 0x09. Instead check the Deice ID (DVID) - * register for a 2, 4 or 8 port UART. - */ - if (up->port.flags & UPF_EXAR_EFR) { - status1 = serial_in(up, UART_EXAR_DVID); - if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) { - DEBUG_AUTOCONF("Exar XR17V35x "); - up->port.type = PORT_XR17V35X; - up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP; - - return; - } - - } - - /* - * Check for presence of the EFR when DLAB is set. - * Only ST16C650V1 UARTs pass this test. - */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - if (serial_in(up, UART_EFR) == 0) { - serial_out(up, UART_EFR, 0xA8); - if (serial_in(up, UART_EFR) != 0) { - DEBUG_AUTOCONF("EFRv1 "); - up->port.type = PORT_16650; - up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; - } else { - serial_out(up, UART_LCR, 0); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR7_64BYTE); - status1 = serial_in(up, UART_IIR) >> 5; - serial_out(up, UART_FCR, 0); - serial_out(up, UART_LCR, 0); - - if (status1 == 7) - up->port.type = PORT_16550A_FSL64; - else - DEBUG_AUTOCONF("Motorola 8xxx DUART "); - } - serial_out(up, UART_EFR, 0); - return; - } - - /* - * Maybe it requires 0xbf to be written to the LCR. - * (other ST16C650V2 UARTs, TI16C752A, etc) - */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { - DEBUG_AUTOCONF("EFRv2 "); - autoconfig_has_efr(up); - return; - } - - /* - * Check for a National Semiconductor SuperIO chip. - * Attempt to switch to bank 2, read the value of the LOOP bit - * from EXCR1. Switch back to bank 0, change it in MCR. Then - * switch back to bank 2, read it from EXCR1 again and check - * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 - */ - serial_out(up, UART_LCR, 0); - status1 = serial_in(up, UART_MCR); - serial_out(up, UART_LCR, 0xE0); - status2 = serial_in(up, 0x02); /* EXCR1 */ - - if (!((status2 ^ status1) & UART_MCR_LOOP)) { - serial_out(up, UART_LCR, 0); - serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP); - serial_out(up, UART_LCR, 0xE0); - status2 = serial_in(up, 0x02); /* EXCR1 */ - serial_out(up, UART_LCR, 0); - serial_out(up, UART_MCR, status1); - - if ((status2 ^ status1) & UART_MCR_LOOP) { - unsigned short quot; - - serial_out(up, UART_LCR, 0xE0); - - quot = serial_dl_read(up); - quot <<= 3; - - if (ns16550a_goto_highspeed(up)) - serial_dl_write(up, quot); - - serial_out(up, UART_LCR, 0); - - up->port.uartclk = 921600*16; - up->port.type = PORT_NS16550A; - up->capabilities |= UART_NATSEMI; - return; - } - } - - /* - * No EFR. Try to detect a TI16750, which only sets bit 5 of - * the IIR when 64 byte FIFO mode is enabled when DLAB is set. - * Try setting it with and without DLAB set. Cheap clones - * set bit 5 without DLAB set. - */ - serial_out(up, UART_LCR, 0); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - status1 = serial_in(up, UART_IIR) >> 5; - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - status2 = serial_in(up, UART_IIR) >> 5; - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_LCR, 0); - - DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); - - if (status1 == 6 && status2 == 7) { - up->port.type = PORT_16750; - up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP; - return; - } - - /* - * Try writing and reading the UART_IER_UUE bit (b6). - * If it works, this is probably one of the Xscale platform's - * internal UARTs. - * We're going to explicitly set the UUE bit to 0 before - * trying to write and read a 1 just to make sure it's not - * already a 1 and maybe locked there before we even start start. - */ - iersave = serial_in(up, UART_IER); - serial_out(up, UART_IER, iersave & ~UART_IER_UUE); - if (!(serial_in(up, UART_IER) & UART_IER_UUE)) { - /* - * OK it's in a known zero state, try writing and reading - * without disturbing the current state of the other bits. - */ - serial_out(up, UART_IER, iersave | UART_IER_UUE); - if (serial_in(up, UART_IER) & UART_IER_UUE) { - /* - * It's an Xscale. - * We'll leave the UART_IER_UUE bit set to 1 (enabled). - */ - DEBUG_AUTOCONF("Xscale "); - up->port.type = PORT_XSCALE; - up->capabilities |= UART_CAP_UUE | UART_CAP_RTOIE; - return; - } - } else { - /* - * If we got here we couldn't force the IER_UUE bit to 0. - * Log it and continue. - */ - DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); - } - serial_out(up, UART_IER, iersave); - - /* - * Exar uarts have EFR in a weird location - */ - if (up->port.flags & UPF_EXAR_EFR) { - DEBUG_AUTOCONF("Exar XR17D15x "); - up->port.type = PORT_XR17D15X; - up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP; - - return; - } - - /* - * We distinguish between 16550A and U6 16550A by counting - * how many bytes are in the FIFO. - */ - if (up->port.type == PORT_16550A && size_fifo(up) == 64) { - up->port.type = PORT_U6_16550A; - up->capabilities |= UART_CAP_AFE; - } -} - -/* - * This routine is called by rs_init() to initialize a specific serial - * port. It determines what type of UART chip this serial port is - * using: 8250, 16450, 16550, 16550A. The important question is - * whether or not this UART is a 16550A or not, since this will - * determine whether or not we can use its FIFO features or not. - */ -static void autoconfig(struct uart_8250_port *up) -{ - unsigned char status1, scratch, scratch2, scratch3; - unsigned char save_lcr, save_mcr; - struct uart_port *port = &up->port; - unsigned long flags; - unsigned int old_capabilities; - - if (!port->iobase && !port->mapbase && !port->membase) - return; - - DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", - serial_index(port), port->iobase, port->membase); - - /* - * We really do need global IRQs disabled here - we're going to - * be frobbing the chips IRQ enable register to see if it exists. - */ - spin_lock_irqsave(&port->lock, flags); - - up->capabilities = 0; - up->bugs = 0; - - if (!(port->flags & UPF_BUGGY_UART)) { - /* - * Do a simple existence test first; if we fail this, - * there's no point trying anything else. - * - * 0x80 is used as a nonsense port to prevent against - * false positives due to ISA bus float. The - * assumption is that 0x80 is a non-existent port; - * which should be safe since include/asm/io.h also - * makes this assumption. - * - * Note: this is safe as long as MCR bit 4 is clear - * and the device is in "PC" mode. - */ - scratch = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); -#ifdef __i386__ - outb(0xff, 0x080); -#endif - /* - * Mask out IER[7:4] bits for test as some UARTs (e.g. TL - * 16C754B) allow only to modify them if an EFR bit is set. - */ - scratch2 = serial_in(up, UART_IER) & 0x0f; - serial_out(up, UART_IER, 0x0F); -#ifdef __i386__ - outb(0, 0x080); -#endif - scratch3 = serial_in(up, UART_IER) & 0x0f; - serial_out(up, UART_IER, scratch); - if (scratch2 != 0 || scratch3 != 0x0F) { - /* - * We failed; there's nothing here - */ - spin_unlock_irqrestore(&port->lock, flags); - DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", - scratch2, scratch3); - goto out; - } - } - - save_mcr = serial_in(up, UART_MCR); - save_lcr = serial_in(up, UART_LCR); - - /* - * Check to see if a UART is really there. Certain broken - * internal modems based on the Rockwell chipset fail this - * test, because they apparently don't implement the loopback - * test mode. So this test is skipped on the COM 1 through - * COM 4 ports. This *should* be safe, since no board - * manufacturer would be stupid enough to design a board - * that conflicts with COM 1-4 --- we hope! - */ - if (!(port->flags & UPF_SKIP_TEST)) { - serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = serial_in(up, UART_MSR) & 0xF0; - serial_out(up, UART_MCR, save_mcr); - if (status1 != 0x90) { - spin_unlock_irqrestore(&port->lock, flags); - DEBUG_AUTOCONF("LOOP test failed (%02x) ", - status1); - goto out; - } - } - - /* - * We're pretty sure there's a port here. Lets find out what - * type of port it is. The IIR top two bits allows us to find - * out if it's 8250 or 16450, 16550, 16550A or later. This - * determines what we test for next. - * - * We also initialise the EFR (if any) to zero for later. The - * EFR occupies the same register location as the FCR and IIR. - */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, 0); - serial_out(up, UART_LCR, 0); - - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = serial_in(up, UART_IIR) >> 6; - - switch (scratch) { - case 0: - autoconfig_8250(up); - break; - case 1: - port->type = PORT_UNKNOWN; - break; - case 2: - port->type = PORT_16550; - break; - case 3: - autoconfig_16550a(up); - break; - } - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * Only probe for RSA ports if we got the region. - */ - if (port->type == PORT_16550A && up->probe & UART_PROBE_RSA && - __enable_rsa(up)) - port->type = PORT_RSA; -#endif - - serial_out(up, UART_LCR, save_lcr); - - port->fifosize = uart_config[up->port.type].fifo_size; - old_capabilities = up->capabilities; - up->capabilities = uart_config[port->type].flags; - up->tx_loadsz = uart_config[port->type].tx_loadsz; - - if (port->type == PORT_UNKNOWN) - goto out_lock; - - /* - * Reset the UART. - */ -#ifdef CONFIG_SERIAL_8250_RSA - if (port->type == PORT_RSA) - serial_out(up, UART_RSA_FRR, 0); -#endif - serial_out(up, UART_MCR, save_mcr); - serial8250_clear_fifos(up); - serial_in(up, UART_RX); - if (up->capabilities & UART_CAP_UUE) - serial_out(up, UART_IER, UART_IER_UUE); - else - serial_out(up, UART_IER, 0); - -out_lock: - spin_unlock_irqrestore(&port->lock, flags); - if (up->capabilities != old_capabilities) { - printk(KERN_WARNING - "ttyS%d: detected caps %08x should be %08x\n", - serial_index(port), old_capabilities, - up->capabilities); - } -out: - DEBUG_AUTOCONF("iir=%d ", scratch); - DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name); -} - -static void autoconfig_irq(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - unsigned char save_mcr, save_ier; - unsigned char save_ICP = 0; - unsigned int ICP = 0; - unsigned long irqs; - int irq; - - if (port->flags & UPF_FOURPORT) { - ICP = (port->iobase & 0xfe0) | 0x1f; - save_ICP = inb_p(ICP); - outb_p(0x80, ICP); - inb_p(ICP); - } - - /* forget possible initially masked and pending IRQ */ - probe_irq_off(probe_irq_on()); - save_mcr = serial_in(up, UART_MCR); - save_ier = serial_in(up, UART_IER); - serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); - - irqs = probe_irq_on(); - serial_out(up, UART_MCR, 0); - udelay(10); - if (port->flags & UPF_FOURPORT) { - serial_out(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS); - } else { - serial_out(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); - } - serial_out(up, UART_IER, 0x0f); /* enable all intrs */ - serial_in(up, UART_LSR); - serial_in(up, UART_RX); - serial_in(up, UART_IIR); - serial_in(up, UART_MSR); - serial_out(up, UART_TX, 0xFF); - udelay(20); - irq = probe_irq_off(irqs); - - serial_out(up, UART_MCR, save_mcr); - serial_out(up, UART_IER, save_ier); - - if (port->flags & UPF_FOURPORT) - outb_p(save_ICP, ICP); - - port->irq = (irq > 0) ? irq : 0; -} - -static inline void __stop_tx(struct uart_8250_port *p) -{ - if (p->ier & UART_IER_THRI) { - p->ier &= ~UART_IER_THRI; - serial_out(p, UART_IER, p->ier); - serial8250_rpm_put_tx(p); - } -} - -static void serial8250_stop_tx(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - serial8250_rpm_get(up); - __stop_tx(up); - - /* - * We really want to stop the transmitter from sending. - */ - if (port->type == PORT_16C950) { - up->acr |= UART_ACR_TXDIS; - serial_icr_write(up, UART_ACR, up->acr); - } - serial8250_rpm_put(up); -} - -static void serial8250_start_tx(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - serial8250_rpm_get_tx(up); - - if (up->dma && !up->dma->tx_dma(up)) - return; - - if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_port_out(port, UART_IER, up->ier); - - if (up->bugs & UART_BUG_TXEN) { - unsigned char lsr; - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - if (lsr & UART_LSR_THRE) - serial8250_tx_chars(up); - } - } - - /* - * Re-enable the transmitter if we disabled it. - */ - if (port->type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { - up->acr &= ~UART_ACR_TXDIS; - serial_icr_write(up, UART_ACR, up->acr); - } -} - -static void serial8250_throttle(struct uart_port *port) -{ - port->throttle(port); -} - -static void serial8250_unthrottle(struct uart_port *port) -{ - port->unthrottle(port); -} - -static void serial8250_stop_rx(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - serial8250_rpm_get(up); - - up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); - up->port.read_status_mask &= ~UART_LSR_DR; - serial_port_out(port, UART_IER, up->ier); - - serial8250_rpm_put(up); -} - -static void serial8250_disable_ms(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - /* no MSR capabilities */ - if (up->bugs & UART_BUG_NOMSR) - return; - - up->ier &= ~UART_IER_MSI; - serial_port_out(port, UART_IER, up->ier); -} - -static void serial8250_enable_ms(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - /* no MSR capabilities */ - if (up->bugs & UART_BUG_NOMSR) - return; - - up->ier |= UART_IER_MSI; - - serial8250_rpm_get(up); - serial_port_out(port, UART_IER, up->ier); - serial8250_rpm_put(up); -} - -/* - * serial8250_rx_chars: processes according to the passed in LSR - * value, and returns the remaining LSR bits not handled - * by this Rx routine. - */ -unsigned char -serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) -{ - struct uart_port *port = &up->port; - unsigned char ch; - int max_count = 256; - char flag; - - do { - if (likely(lsr & UART_LSR_DR)) - ch = serial_in(up, UART_RX); - else - /* - * Intel 82571 has a Serial Over Lan device that will - * set UART_LSR_BI without setting UART_LSR_DR when - * it receives a break. To avoid reading from the - * receive buffer without UART_LSR_DR bit set, we - * just force the read character to be 0 - */ - ch = 0; - - flag = TTY_NORMAL; - port->icount.rx++; - - lsr |= up->lsr_saved_flags; - up->lsr_saved_flags = 0; - - if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { - if (lsr & UART_LSR_BI) { - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - port->icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(port)) - goto ignore_char; - } else if (lsr & UART_LSR_PE) - port->icount.parity++; - else if (lsr & UART_LSR_FE) - port->icount.frame++; - if (lsr & UART_LSR_OE) - port->icount.overrun++; - - /* - * Mask off conditions which should be ignored. - */ - lsr &= port->read_status_mask; - - if (lsr & UART_LSR_BI) { - DEBUG_INTR("handling break...."); - flag = TTY_BREAK; - } else if (lsr & UART_LSR_PE) - flag = TTY_PARITY; - else if (lsr & UART_LSR_FE) - flag = TTY_FRAME; - } - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); - -ignore_char: - lsr = serial_in(up, UART_LSR); - } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0)); - spin_unlock(&port->lock); - tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); - return lsr; -} -EXPORT_SYMBOL_GPL(serial8250_rx_chars); - -void serial8250_tx_chars(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - struct circ_buf *xmit = &port->state->xmit; - int count; - - if (port->x_char) { - serial_out(up, UART_TX, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - if (uart_tx_stopped(port)) { - serial8250_stop_tx(port); - return; - } - if (uart_circ_empty(xmit)) { - __stop_tx(up); - return; - } - - count = up->tx_loadsz; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - if (up->capabilities & UART_CAP_HFIFO) { - if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) != - BOTH_EMPTY) - break; - } - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - DEBUG_INTR("THRE..."); - - /* - * With RPM enabled, we have to wait until the FIFO is empty before the - * HW can go idle. So we get here once again with empty FIFO and disable - * the interrupt and RPM in __stop_tx() - */ - if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) - __stop_tx(up); -} -EXPORT_SYMBOL_GPL(serial8250_tx_chars); - -/* Caller holds uart port lock */ -unsigned int serial8250_modem_status(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - unsigned int status = serial_in(up, UART_MSR); - - status |= up->msr_saved_flags; - up->msr_saved_flags = 0; - if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && - port->state != NULL) { - if (status & UART_MSR_TERI) - port->icount.rng++; - if (status & UART_MSR_DDSR) - port->icount.dsr++; - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(port, status & UART_MSR_DCD); - if (status & UART_MSR_DCTS) - uart_handle_cts_change(port, status & UART_MSR_CTS); - - wake_up_interruptible(&port->state->port.delta_msr_wait); - } - - return status; -} -EXPORT_SYMBOL_GPL(serial8250_modem_status); - -/* - * This handles the interrupt from one port. - */ -int serial8250_handle_irq(struct uart_port *port, unsigned int iir) -{ - unsigned char status; - unsigned long flags; - struct uart_8250_port *up = up_to_u8250p(port); - int dma_err = 0; - - if (iir & UART_IIR_NO_INT) - return 0; - - spin_lock_irqsave(&port->lock, flags); - - status = serial_port_in(port, UART_LSR); - - DEBUG_INTR("status = %x...", status); - - if (status & (UART_LSR_DR | UART_LSR_BI)) { - if (up->dma) - dma_err = up->dma->rx_dma(up, iir); - - if (!up->dma || dma_err) - status = serial8250_rx_chars(up, status); - } - serial8250_modem_status(up); - if ((!up->dma || (up->dma && up->dma->tx_err)) && - (status & UART_LSR_THRE)) - serial8250_tx_chars(up); - - spin_unlock_irqrestore(&port->lock, flags); - return 1; -} -EXPORT_SYMBOL_GPL(serial8250_handle_irq); - -static int serial8250_default_handle_irq(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned int iir; - int ret; - - serial8250_rpm_get(up); - - iir = serial_port_in(port, UART_IIR); - ret = serial8250_handle_irq(port, iir); - - serial8250_rpm_put(up); - return ret; -} - -/* - * These Exar UARTs have an extra interrupt indicator that could - * fire for a few unimplemented interrupts. One of which is a - * wakeup event when coming out of sleep. Put this here just - * to be on the safe side that these interrupts don't go unhandled. - */ -static int exar_handle_irq(struct uart_port *port) -{ - unsigned char int0, int1, int2, int3; - unsigned int iir = serial_port_in(port, UART_IIR); - int ret; - - ret = serial8250_handle_irq(port, iir); - - if ((port->type == PORT_XR17V35X) || - (port->type == PORT_XR17D15X)) { - int0 = serial_port_in(port, 0x80); - int1 = serial_port_in(port, 0x81); - int2 = serial_port_in(port, 0x82); - int3 = serial_port_in(port, 0x83); - } - - return ret; -} - -/* - * This is the serial driver's interrupt routine. - * - * Arjan thinks the old way was overly complex, so it got simplified. - * Alan disagrees, saying that need the complexity to handle the weird - * nature of ISA shared interrupts. (This is a special exception.) - * - * In order to handle ISA shared interrupts properly, we need to check - * that all ports have been serviced, and therefore the ISA interrupt - * line has been de-asserted. - * - * This means we need to loop through all ports. checking that they - * don't have an interrupt pending. - */ -static irqreturn_t serial8250_interrupt(int irq, void *dev_id) -{ - struct irq_info *i = dev_id; - struct list_head *l, *end = NULL; - int pass_counter = 0, handled = 0; - - DEBUG_INTR("serial8250_interrupt(%d)...", irq); - - spin_lock(&i->lock); - - l = i->head; - do { - struct uart_8250_port *up; - struct uart_port *port; - - up = list_entry(l, struct uart_8250_port, list); - port = &up->port; - - if (port->handle_irq(port)) { - handled = 1; - end = NULL; - } else if (end == NULL) - end = l; - - l = l->next; - - if (l == i->head && pass_counter++ > PASS_LIMIT) { - /* If we hit this, we're dead. */ - printk_ratelimited(KERN_ERR - "serial8250: too much work for irq%d\n", irq); - break; - } - } while (l != end); - - spin_unlock(&i->lock); - - DEBUG_INTR("end.\n"); - - return IRQ_RETVAL(handled); -} - -/* - * To support ISA shared interrupts, we need to have one interrupt - * handler that ensures that the IRQ line has been deasserted - * before returning. Failing to do this will result in the IRQ - * line being stuck active, and, since ISA irqs are edge triggered, - * no more IRQs will be seen. - */ -static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up) -{ - spin_lock_irq(&i->lock); - - if (!list_empty(i->head)) { - if (i->head == &up->list) - i->head = i->head->next; - list_del(&up->list); - } else { - BUG_ON(i->head != &up->list); - i->head = NULL; - } - spin_unlock_irq(&i->lock); - /* List empty so throw away the hash node */ - if (i->head == NULL) { - hlist_del(&i->node); - kfree(i); - } -} - -static int serial_link_irq_chain(struct uart_8250_port *up) -{ - struct hlist_head *h; - struct hlist_node *n; - struct irq_info *i; - int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; - - mutex_lock(&hash_mutex); - - h = &irq_lists[up->port.irq % NR_IRQ_HASH]; - - hlist_for_each(n, h) { - i = hlist_entry(n, struct irq_info, node); - if (i->irq == up->port.irq) - break; - } - - if (n == NULL) { - i = kzalloc(sizeof(struct irq_info), GFP_KERNEL); - if (i == NULL) { - mutex_unlock(&hash_mutex); - return -ENOMEM; - } - spin_lock_init(&i->lock); - i->irq = up->port.irq; - hlist_add_head(&i->node, h); - } - mutex_unlock(&hash_mutex); - - spin_lock_irq(&i->lock); - - if (i->head) { - list_add(&up->list, i->head); - spin_unlock_irq(&i->lock); - - ret = 0; - } else { - INIT_LIST_HEAD(&up->list); - i->head = &up->list; - spin_unlock_irq(&i->lock); - irq_flags |= up->port.irqflags; - ret = request_irq(up->port.irq, serial8250_interrupt, - irq_flags, "serial", i); - if (ret < 0) - serial_do_unlink(i, up); - } - - return ret; -} - -static void serial_unlink_irq_chain(struct uart_8250_port *up) -{ - /* - * yes, some broken gcc emit "warning: 'i' may be used uninitialized" - * but no, we are not going to take a patch that assigns NULL below. - */ - struct irq_info *i; - struct hlist_node *n; - struct hlist_head *h; - - mutex_lock(&hash_mutex); - - h = &irq_lists[up->port.irq % NR_IRQ_HASH]; - - hlist_for_each(n, h) { - i = hlist_entry(n, struct irq_info, node); - if (i->irq == up->port.irq) - break; - } - - BUG_ON(n == NULL); - BUG_ON(i->head == NULL); - - if (list_empty(i->head)) - free_irq(up->port.irq, i); - - serial_do_unlink(i, up); - mutex_unlock(&hash_mutex); -} - -/* - * This function is used to handle ports that do not have an - * interrupt. This doesn't work very well for 16450's, but gives - * barely passable results for a 16550A. (Although at the expense - * of much CPU overhead). - */ -static void serial8250_timeout(unsigned long data) -{ - struct uart_8250_port *up = (struct uart_8250_port *)data; - - up->port.handle_irq(&up->port); - mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); -} - -static void serial8250_backup_timeout(unsigned long data) -{ - struct uart_8250_port *up = (struct uart_8250_port *)data; - unsigned int iir, ier = 0, lsr; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); - - /* - * Must disable interrupts or else we risk racing with the interrupt - * based handler. - */ - if (up->port.irq) { - ier = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); - } - - iir = serial_in(up, UART_IIR); - - /* - * This should be a safe test for anyone who doesn't trust the - * IIR bits on their UART, but it's specifically designed for - * the "Diva" UART used on the management processor on many HP - * ia64 and parisc boxes. - */ - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && - (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) && - (lsr & UART_LSR_THRE)) { - iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); - iir |= UART_IIR_THRI; - } - - if (!(iir & UART_IIR_NO_INT)) - serial8250_tx_chars(up); - - if (up->port.irq) - serial_out(up, UART_IER, ier); - - spin_unlock_irqrestore(&up->port.lock, flags); - - /* Standard timer interval plus 0.2s to keep the port running */ - mod_timer(&up->timer, - jiffies + uart_poll_timeout(&up->port) + HZ / 5); -} - -static int univ8250_setup_irq(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - int retval = 0; - - /* - * The above check will only give an accurate result the first time - * the port is opened so this value needs to be preserved. - */ - if (up->bugs & UART_BUG_THRE) { - pr_debug("ttyS%d - using backup timer\n", serial_index(port)); - - up->timer.function = serial8250_backup_timeout; - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + - uart_poll_timeout(port) + HZ / 5); - } - - /* - * If the "interrupt" for this port doesn't correspond with any - * hardware interrupt, we use a timer-based system. The original - * driver used to do this with IRQ0. - */ - if (!port->irq) { - up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); - } else - retval = serial_link_irq_chain(up); - - return retval; -} - -static void univ8250_release_irq(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - - del_timer_sync(&up->timer); - up->timer.function = serial8250_timeout; - if (port->irq) - serial_unlink_irq_chain(up); -} - -static unsigned int serial8250_tx_empty(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - unsigned int lsr; - - serial8250_rpm_get(up); - - spin_lock_irqsave(&port->lock, flags); - lsr = serial_port_in(port, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - spin_unlock_irqrestore(&port->lock, flags); - - serial8250_rpm_put(up); - - return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; -} - -static unsigned int serial8250_get_mctrl(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned int status; - unsigned int ret; - - serial8250_rpm_get(up); - status = serial8250_modem_status(up); - serial8250_rpm_put(up); - - ret = 0; - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned char mcr = 0; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; - - serial_port_out(port, UART_MCR, mcr); -} -EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); - -static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - if (port->set_mctrl) - port->set_mctrl(port, mctrl); - else - serial8250_do_set_mctrl(port, mctrl); -} - -static void serial8250_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - - serial8250_rpm_get(up); - spin_lock_irqsave(&port->lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - serial_port_out(port, UART_LCR, up->lcr); - spin_unlock_irqrestore(&port->lock, flags); - serial8250_rpm_put(up); -} - -/* - * Wait for transmitter & holding register to empty - */ -static void wait_for_xmitr(struct uart_8250_port *up, int bits) -{ - unsigned int status, tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - for (;;) { - status = serial_in(up, UART_LSR); - - up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; - - if ((status & bits) == bits) - break; - if (--tmout == 0) - break; - udelay(1); - } - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - unsigned int tmout; - for (tmout = 1000000; tmout; tmout--) { - unsigned int msr = serial_in(up, UART_MSR); - up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; - if (msr & UART_MSR_CTS) - break; - udelay(1); - touch_nmi_watchdog(); - } - } -} - -#ifdef CONFIG_CONSOLE_POLL -/* - * Console polling routines for writing and reading from the uart while - * in an interrupt or debug context. - */ - -static int serial8250_get_poll_char(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned char lsr; - int status; - - serial8250_rpm_get(up); - - lsr = serial_port_in(port, UART_LSR); - - if (!(lsr & UART_LSR_DR)) { - status = NO_POLL_CHAR; - goto out; - } - - status = serial_port_in(port, UART_RX); -out: - serial8250_rpm_put(up); - return status; -} - - -static void serial8250_put_poll_char(struct uart_port *port, - unsigned char c) -{ - unsigned int ier; - struct uart_8250_port *up = up_to_u8250p(port); - - serial8250_rpm_get(up); - /* - * First save the IER then disable the interrupts - */ - ier = serial_port_in(port, UART_IER); - if (up->capabilities & UART_CAP_UUE) - serial_port_out(port, UART_IER, UART_IER_UUE); - else - serial_port_out(port, UART_IER, 0); - - wait_for_xmitr(up, BOTH_EMPTY); - /* - * Send the character out. - */ - serial_port_out(port, UART_TX, c); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up, BOTH_EMPTY); - serial_port_out(port, UART_IER, ier); - serial8250_rpm_put(up); -} - -#endif /* CONFIG_CONSOLE_POLL */ - -int serial8250_do_startup(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - unsigned char lsr, iir; - int retval; - - if (port->type == PORT_8250_CIR) - return -ENODEV; - - if (!port->fifosize) - port->fifosize = uart_config[port->type].fifo_size; - if (!up->tx_loadsz) - up->tx_loadsz = uart_config[port->type].tx_loadsz; - if (!up->capabilities) - up->capabilities = uart_config[port->type].flags; - up->mcr = 0; - - if (port->iotype != up->cur_iotype) - set_io_from_upio(port); - - serial8250_rpm_get(up); - if (port->type == PORT_16C950) { - /* Wake up and initialize UART */ - up->acr = 0; - serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); - serial_port_out(port, UART_EFR, UART_EFR_ECB); - serial_port_out(port, UART_IER, 0); - serial_port_out(port, UART_LCR, 0); - serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ - serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); - serial_port_out(port, UART_EFR, UART_EFR_ECB); - serial_port_out(port, UART_LCR, 0); - } - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * If this is an RSA port, see if we can kick it up to the - * higher speed clock. - */ - enable_rsa(up); -#endif - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - serial8250_clear_fifos(up); - - /* - * Clear the interrupt registers. - */ - serial_port_in(port, UART_LSR); - serial_port_in(port, UART_RX); - serial_port_in(port, UART_IIR); - serial_port_in(port, UART_MSR); - - /* - * At this point, there's no way the LSR could still be 0xff; - * if it is, then bail out, because there's likely no UART - * here. - */ - if (!(port->flags & UPF_BUGGY_UART) && - (serial_port_in(port, UART_LSR) == 0xff)) { - printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", - serial_index(port)); - retval = -ENODEV; - goto out; - } - - /* - * For a XR16C850, we need to set the trigger levels - */ - if (port->type == PORT_16850) { - unsigned char fctr; - - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - - fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); - serial_port_out(port, UART_FCTR, - fctr | UART_FCTR_TRGD | UART_FCTR_RX); - serial_port_out(port, UART_TRG, UART_TRG_96); - serial_port_out(port, UART_FCTR, - fctr | UART_FCTR_TRGD | UART_FCTR_TX); - serial_port_out(port, UART_TRG, UART_TRG_96); - - serial_port_out(port, UART_LCR, 0); - } - - if (port->irq) { - unsigned char iir1; - /* - * Test for UARTs that do not reassert THRE when the - * transmitter is idle and the interrupt has already - * been cleared. Real 16550s should always reassert - * this interrupt whenever the transmitter is idle and - * the interrupt is enabled. Delays are necessary to - * allow register changes to become visible. - */ - spin_lock_irqsave(&port->lock, flags); - if (up->port.irqflags & IRQF_SHARED) - disable_irq_nosync(port->irq); - - wait_for_xmitr(up, UART_LSR_THRE); - serial_port_out_sync(port, UART_IER, UART_IER_THRI); - udelay(1); /* allow THRE to set */ - iir1 = serial_port_in(port, UART_IIR); - serial_port_out(port, UART_IER, 0); - serial_port_out_sync(port, UART_IER, UART_IER_THRI); - udelay(1); /* allow a working UART time to re-assert THRE */ - iir = serial_port_in(port, UART_IIR); - serial_port_out(port, UART_IER, 0); - - if (port->irqflags & IRQF_SHARED) - enable_irq(port->irq); - spin_unlock_irqrestore(&port->lock, flags); - - /* - * If the interrupt is not reasserted, or we otherwise - * don't trust the iir, setup a timer to kick the UART - * on a regular basis. - */ - if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || - up->port.flags & UPF_BUG_THRE) { - up->bugs |= UART_BUG_THRE; - } - } - - retval = up->ops->setup_irq(up); - if (retval) - goto out; - - /* - * Now, initialize the UART - */ - serial_port_out(port, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irqsave(&port->lock, flags); - if (up->port.flags & UPF_FOURPORT) { - if (!up->port.irq) - up->port.mctrl |= TIOCM_OUT1; - } else - /* - * Most PC uarts need OUT2 raised to enable interrupts. - */ - if (port->irq) - up->port.mctrl |= TIOCM_OUT2; - - serial8250_set_mctrl(port, port->mctrl); - - /* Serial over Lan (SoL) hack: - Intel 8257x Gigabit ethernet chips have a - 16550 emulation, to be used for Serial Over Lan. - Those chips take a longer time than a normal - serial device to signalize that a transmission - data was queued. Due to that, the above test generally - fails. One solution would be to delay the reading of - iir. However, this is not reliable, since the timeout - is variable. So, let's just don't test if we receive - TX irq. This way, we'll never enable UART_BUG_TXEN. - */ - if (up->port.flags & UPF_NO_TXEN_TEST) - goto dont_test_tx_en; - - /* - * Do a quick test to see if we receive an - * interrupt when we enable the TX irq. - */ - serial_port_out(port, UART_IER, UART_IER_THRI); - lsr = serial_port_in(port, UART_LSR); - iir = serial_port_in(port, UART_IIR); - serial_port_out(port, UART_IER, 0); - - if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { - if (!(up->bugs & UART_BUG_TXEN)) { - up->bugs |= UART_BUG_TXEN; - pr_debug("ttyS%d - enabling bad tx status workarounds\n", - serial_index(port)); - } - } else { - up->bugs &= ~UART_BUG_TXEN; - } - -dont_test_tx_en: - spin_unlock_irqrestore(&port->lock, flags); - - /* - * Clear the interrupt registers again for luck, and clear the - * saved flags to avoid getting false values from polling - * routines or the previous session. - */ - serial_port_in(port, UART_LSR); - serial_port_in(port, UART_RX); - serial_port_in(port, UART_IIR); - serial_port_in(port, UART_MSR); - up->lsr_saved_flags = 0; - up->msr_saved_flags = 0; - - /* - * Request DMA channels for both RX and TX. - */ - if (up->dma) { - retval = serial8250_request_dma(up); - if (retval) { - pr_warn_ratelimited("ttyS%d - failed to request DMA\n", - serial_index(port)); - up->dma = NULL; - } - } - - /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. - */ - up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_port_out(port, UART_IER, up->ier); - - if (port->flags & UPF_FOURPORT) { - unsigned int icp; - /* - * Enable interrupts on the AST Fourport board - */ - icp = (port->iobase & 0xfe0) | 0x01f; - outb_p(0x80, icp); - inb_p(icp); - } - retval = 0; -out: - serial8250_rpm_put(up); - return retval; -} -EXPORT_SYMBOL_GPL(serial8250_do_startup); - -static int serial8250_startup(struct uart_port *port) -{ - if (port->startup) - return port->startup(port); - return serial8250_do_startup(port); -} - -void serial8250_do_shutdown(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - - serial8250_rpm_get(up); - /* - * Disable interrupts from this port - */ - up->ier = 0; - serial_port_out(port, UART_IER, 0); - - if (up->dma) - serial8250_release_dma(up); - - spin_lock_irqsave(&port->lock, flags); - if (port->flags & UPF_FOURPORT) { - /* reset interrupts on the AST Fourport board */ - inb((port->iobase & 0xfe0) | 0x1f); - port->mctrl |= TIOCM_OUT1; - } else - port->mctrl &= ~TIOCM_OUT2; - - serial8250_set_mctrl(port, port->mctrl); - spin_unlock_irqrestore(&port->lock, flags); - - /* - * Disable break condition and FIFOs - */ - serial_port_out(port, UART_LCR, - serial_port_in(port, UART_LCR) & ~UART_LCR_SBC); - serial8250_clear_fifos(up); - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * Reset the RSA board back to 115kbps compat mode. - */ - disable_rsa(up); -#endif - - /* - * Read data port to reset things, and then unlink from - * the IRQ chain. - */ - serial_port_in(port, UART_RX); - serial8250_rpm_put(up); - - up->ops->release_irq(up); -} -EXPORT_SYMBOL_GPL(serial8250_do_shutdown); - -static void serial8250_shutdown(struct uart_port *port) -{ - if (port->shutdown) - port->shutdown(port); - else - serial8250_do_shutdown(port); -} - -/* - * XR17V35x UARTs have an extra fractional divisor register (DLD) - * Calculate divisor with extra 4-bit fractional portion - */ -static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up, - unsigned int baud, - unsigned int *frac) -{ - struct uart_port *port = &up->port; - unsigned int quot_16; - - quot_16 = DIV_ROUND_CLOSEST(port->uartclk, baud); - *frac = quot_16 & 0x0f; - - return quot_16 >> 4; -} - -static unsigned int serial8250_get_divisor(struct uart_8250_port *up, - unsigned int baud, - unsigned int *frac) -{ - struct uart_port *port = &up->port; - unsigned int quot; - - /* - * Handle magic divisors for baud rates above baud_base on - * SMSC SuperIO chips. - * - */ - if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/4)) - quot = 0x8001; - else if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/8)) - quot = 0x8002; - else if (up->port.type == PORT_XR17V35X) - quot = xr17v35x_get_divisor(up, baud, frac); - else - quot = uart_get_divisor(port, baud); - - /* - * Oxford Semi 952 rev B workaround - */ - if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) - quot++; - - return quot; -} - -static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, - tcflag_t c_cflag) -{ - unsigned char cval; - - switch (c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } - - if (c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (c_cflag & PARENB) { - cval |= UART_LCR_PARITY; - if (up->bugs & UART_BUG_PARITY) - up->fifo_bug = true; - } - if (!(c_cflag & PARODD)) - cval |= UART_LCR_EPAR; -#ifdef CMSPAR - if (c_cflag & CMSPAR) - cval |= UART_LCR_SPAR; -#endif - - return cval; -} - -static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, - unsigned int quot, unsigned int quot_frac) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - /* Workaround to enable 115200 baud on OMAP1510 internal ports */ - if (is_omap1510_8250(up)) { - if (baud == 115200) { - quot = 1; - serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1); - } else - serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0); - } - - /* - * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2, - * otherwise just set DLAB - */ - if (up->capabilities & UART_NATSEMI) - serial_port_out(port, UART_LCR, 0xe0); - else - serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); - - serial_dl_write(up, quot); - - /* XR17V35x UARTs have an extra fractional divisor register (DLD) */ - if (up->port.type == PORT_XR17V35X) - serial_port_out(port, 0x2, quot_frac); -} - -void -serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned char cval; - unsigned long flags; - unsigned int baud, quot, frac = 0; - - cval = serial8250_compute_lcr(up, termios->c_cflag); - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, - port->uartclk / 16 / 0xffff, - port->uartclk / 16); - quot = serial8250_get_divisor(up, baud, &frac); - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - serial8250_rpm_get(up); - spin_lock_irqsave(&port->lock, flags); - - up->lcr = cval; /* Save computed LCR */ - - if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { - /* NOTE: If fifo_bug is not set, a user can set RX_trigger. */ - if ((baud < 2400 && !up->dma) || up->fifo_bug) { - up->fcr &= ~UART_FCR_TRIGGER_MASK; - up->fcr |= UART_FCR_TRIGGER_1; - } - } - - /* - * MCR-based auto flow control. When AFE is enabled, RTS will be - * deasserted when the receive FIFO contains more characters than - * the trigger, or the MCR RTS bit is cleared. In the case where - * the remote UART is not using CTS auto flow control, we must - * have sufficient FIFO entries for the latency of the remote - * UART to respond. IOW, at least 32 bytes of FIFO. - */ - if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { - up->mcr &= ~UART_MCR_AFE; - if (termios->c_cflag & CRTSCTS) - up->mcr |= UART_MCR_AFE; - } - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= UART_LSR_BI; - - /* - * Characteres to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_OE; - } - - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_LSR_DR; - - /* - * CTS flow control flag and modem status interrupts - */ - up->ier &= ~UART_IER_MSI; - if (!(up->bugs & UART_BUG_NOMSR) && - UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; - if (up->capabilities & UART_CAP_UUE) - up->ier |= UART_IER_UUE; - if (up->capabilities & UART_CAP_RTOIE) - up->ier |= UART_IER_RTOIE; - - serial_port_out(port, UART_IER, up->ier); - - if (up->capabilities & UART_CAP_EFR) { - unsigned char efr = 0; - /* - * TI16C752/Startech hardware flow control. FIXME: - * - TI16C752 requires control thresholds to be set. - * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled. - */ - if (termios->c_cflag & CRTSCTS) - efr |= UART_EFR_CTS; - - serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); - if (port->flags & UPF_EXAR_EFR) - serial_port_out(port, UART_XR_EFR, efr); - else - serial_port_out(port, UART_EFR, efr); - } - - serial8250_set_divisor(port, baud, quot, frac); + spin_lock_irqsave(&up->port.lock, flags); /* - * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR - * is written without DLAB set, this mode will be disabled. + * Must disable interrupts or else we risk racing with the interrupt + * based handler. */ - if (port->type == PORT_16750) - serial_port_out(port, UART_FCR, up->fcr); - - serial_port_out(port, UART_LCR, up->lcr); /* reset DLAB */ - if (port->type != PORT_16750) { - /* emulated UARTs (Lucent Venus 167x) need two steps */ - if (up->fcr & UART_FCR_ENABLE_FIFO) - serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_port_out(port, UART_FCR, up->fcr); /* set fcr */ - } - serial8250_set_mctrl(port, port->mctrl); - spin_unlock_irqrestore(&port->lock, flags); - serial8250_rpm_put(up); - - /* Don't rewrite B0 */ - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, baud, baud); -} -EXPORT_SYMBOL(serial8250_do_set_termios); - -static void -serial8250_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - if (port->set_termios) - port->set_termios(port, termios, old); - else - serial8250_do_set_termios(port, termios, old); -} - -static void -serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios) -{ - if (termios->c_line == N_PPS) { - port->flags |= UPF_HARDPPS_CD; - spin_lock_irq(&port->lock); - serial8250_enable_ms(port); - spin_unlock_irq(&port->lock); - } else { - port->flags &= ~UPF_HARDPPS_CD; - if (!UART_ENABLE_MS(port, termios->c_cflag)) { - spin_lock_irq(&port->lock); - serial8250_disable_ms(port); - spin_unlock_irq(&port->lock); - } + if (up->port.irq) { + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); } -} + iir = serial_in(up, UART_IIR); -void serial8250_do_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - struct uart_8250_port *p = up_to_u8250p(port); + /* + * This should be a safe test for anyone who doesn't trust the + * IIR bits on their UART, but it's specifically designed for + * the "Diva" UART used on the management processor on many HP + * ia64 and parisc boxes. + */ + lsr = serial_in(up, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) && + (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) && + (lsr & UART_LSR_THRE)) { + iir &= ~(UART_IIR_ID | UART_IIR_NO_INT); + iir |= UART_IIR_THRI; + } - serial8250_set_sleep(p, state != 0); -} -EXPORT_SYMBOL(serial8250_do_pm); + if (!(iir & UART_IIR_NO_INT)) + serial8250_tx_chars(up); -static void -serial8250_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - if (port->pm) - port->pm(port, state, oldstate); - else - serial8250_do_pm(port, state, oldstate); -} + if (up->port.irq) + serial_out(up, UART_IER, ier); -static unsigned int serial8250_port_size(struct uart_8250_port *pt) -{ - if (pt->port.mapsize) - return pt->port.mapsize; - if (pt->port.iotype == UPIO_AU) { - if (pt->port.type == PORT_RT2880) - return 0x100; - return 0x1000; - } - if (is_omap1_8250(pt)) - return 0x16 << pt->port.regshift; + spin_unlock_irqrestore(&up->port.lock, flags); - return 8 << pt->port.regshift; + /* Standard timer interval plus 0.2s to keep the port running */ + mod_timer(&up->timer, + jiffies + uart_poll_timeout(&up->port) + HZ / 5); } -/* - * Resource handling. - */ -static int serial8250_request_std_resource(struct uart_8250_port *up) +static int univ8250_setup_irq(struct uart_8250_port *up) { - unsigned int size = serial8250_port_size(up); struct uart_port *port = &up->port; - int ret = 0; + int retval = 0; - switch (port->iotype) { - case UPIO_AU: - case UPIO_TSI: - case UPIO_MEM32: - case UPIO_MEM32BE: - case UPIO_MEM: - if (!port->mapbase) - break; + /* + * The above check will only give an accurate result the first time + * the port is opened so this value needs to be preserved. + */ + if (up->bugs & UART_BUG_THRE) { + pr_debug("ttyS%d - using backup timer\n", serial_index(port)); - if (!request_mem_region(port->mapbase, size, "serial")) { - ret = -EBUSY; - break; - } + up->timer.function = serial8250_backup_timeout; + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + + uart_poll_timeout(port) + HZ / 5); + } - if (port->flags & UPF_IOREMAP) { - port->membase = ioremap_nocache(port->mapbase, size); - if (!port->membase) { - release_mem_region(port->mapbase, size); - ret = -ENOMEM; - } - } - break; + /* + * If the "interrupt" for this port doesn't correspond with any + * hardware interrupt, we use a timer-based system. The original + * driver used to do this with IRQ0. + */ + if (!port->irq) { + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); + } else + retval = serial_link_irq_chain(up); - case UPIO_HUB6: - case UPIO_PORT: - if (!request_region(port->iobase, size, "serial")) - ret = -EBUSY; - break; - } - return ret; + return retval; } -static void serial8250_release_std_resource(struct uart_8250_port *up) +static void univ8250_release_irq(struct uart_8250_port *up) { - unsigned int size = serial8250_port_size(up); struct uart_port *port = &up->port; - switch (port->iotype) { - case UPIO_AU: - case UPIO_TSI: - case UPIO_MEM32: - case UPIO_MEM32BE: - case UPIO_MEM: - if (!port->mapbase) - break; - - if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); - port->membase = NULL; - } - - release_mem_region(port->mapbase, size); - break; - - case UPIO_HUB6: - case UPIO_PORT: - release_region(port->iobase, size); - break; - } + del_timer_sync(&up->timer); + up->timer.function = serial8250_timeout; + if (port->irq) + serial_unlink_irq_chain(up); } #ifdef CONFIG_SERIAL_8250_RSA @@ -2848,259 +396,6 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up) } #endif -static void serial8250_release_port(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - serial8250_release_std_resource(up); -} - -static int serial8250_request_port(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - int ret; - - if (port->type == PORT_8250_CIR) - return -ENODEV; - - ret = serial8250_request_std_resource(up); - - return ret; -} - -static int fcr_get_rxtrig_bytes(struct uart_8250_port *up) -{ - const struct serial8250_config *conf_type = &uart_config[up->port.type]; - unsigned char bytes; - - bytes = conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(up->fcr)]; - - return bytes ? bytes : -EOPNOTSUPP; -} - -static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, unsigned char bytes) -{ - const struct serial8250_config *conf_type = &uart_config[up->port.type]; - int i; - - if (!conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(UART_FCR_R_TRIG_00)]) - return -EOPNOTSUPP; - - for (i = 1; i < UART_FCR_R_TRIG_MAX_STATE; i++) { - if (bytes < conf_type->rxtrig_bytes[i]) - /* Use the nearest lower value */ - return (--i) << UART_FCR_R_TRIG_SHIFT; - } - - return UART_FCR_R_TRIG_11; -} - -static int do_get_rxtrig(struct tty_port *port) -{ - struct uart_state *state = container_of(port, struct uart_state, port); - struct uart_port *uport = state->uart_port; - struct uart_8250_port *up = - container_of(uport, struct uart_8250_port, port); - - if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1) - return -EINVAL; - - return fcr_get_rxtrig_bytes(up); -} - -static int do_serial8250_get_rxtrig(struct tty_port *port) -{ - int rxtrig_bytes; - - mutex_lock(&port->mutex); - rxtrig_bytes = do_get_rxtrig(port); - mutex_unlock(&port->mutex); - - return rxtrig_bytes; -} - -static ssize_t serial8250_get_attr_rx_trig_bytes(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct tty_port *port = dev_get_drvdata(dev); - int rxtrig_bytes; - - rxtrig_bytes = do_serial8250_get_rxtrig(port); - if (rxtrig_bytes < 0) - return rxtrig_bytes; - - return snprintf(buf, PAGE_SIZE, "%d\n", rxtrig_bytes); -} - -static int do_set_rxtrig(struct tty_port *port, unsigned char bytes) -{ - struct uart_state *state = container_of(port, struct uart_state, port); - struct uart_port *uport = state->uart_port; - struct uart_8250_port *up = - container_of(uport, struct uart_8250_port, port); - int rxtrig; - - if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 || - up->fifo_bug) - return -EINVAL; - - rxtrig = bytes_to_fcr_rxtrig(up, bytes); - if (rxtrig < 0) - return rxtrig; - - serial8250_clear_fifos(up); - up->fcr &= ~UART_FCR_TRIGGER_MASK; - up->fcr |= (unsigned char)rxtrig; - serial_out(up, UART_FCR, up->fcr); - return 0; -} - -static int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes) -{ - int ret; - - mutex_lock(&port->mutex); - ret = do_set_rxtrig(port, bytes); - mutex_unlock(&port->mutex); - - return ret; -} - -static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct tty_port *port = dev_get_drvdata(dev); - unsigned char bytes; - int ret; - - if (!count) - return -EINVAL; - - ret = kstrtou8(buf, 10, &bytes); - if (ret < 0) - return ret; - - ret = do_serial8250_set_rxtrig(port, bytes); - if (ret < 0) - return ret; - - return count; -} - -static DEVICE_ATTR(rx_trig_bytes, S_IRUSR | S_IWUSR | S_IRGRP, - serial8250_get_attr_rx_trig_bytes, - serial8250_set_attr_rx_trig_bytes); - -static struct attribute *serial8250_dev_attrs[] = { - &dev_attr_rx_trig_bytes.attr, - NULL, - }; - -static struct attribute_group serial8250_dev_attr_group = { - .attrs = serial8250_dev_attrs, - }; - -static void register_dev_spec_attr_grp(struct uart_8250_port *up) -{ - const struct serial8250_config *conf_type = &uart_config[up->port.type]; - - if (conf_type->rxtrig_bytes[0]) - up->port.attr_group = &serial8250_dev_attr_group; -} - -static void serial8250_config_port(struct uart_port *port, int flags) -{ - struct uart_8250_port *up = up_to_u8250p(port); - int ret; - - if (port->type == PORT_8250_CIR) - return; - - /* - * Find the region that we can probe for. This in turn - * tells us whether we can probe for the type of port. - */ - ret = serial8250_request_std_resource(up); - if (ret < 0) - return; - - if (port->iotype != up->cur_iotype) - set_io_from_upio(port); - - if (flags & UART_CONFIG_TYPE) - autoconfig(up); - - /* if access method is AU, it is a 16550 with a quirk */ - if (port->type == PORT_16550A && port->iotype == UPIO_AU) - up->bugs |= UART_BUG_NOMSR; - - /* HW bugs may trigger IRQ while IIR == NO_INT */ - if (port->type == PORT_TEGRA) - up->bugs |= UART_BUG_NOMSR; - - if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) - autoconfig_irq(up); - - if (port->type == PORT_UNKNOWN) - serial8250_release_std_resource(up); - - /* Fixme: probably not the best place for this */ - if ((port->type == PORT_XR17V35X) || - (port->type == PORT_XR17D15X)) - port->handle_irq = exar_handle_irq; - - register_dev_spec_attr_grp(up); - up->fcr = uart_config[up->port.type].fcr; -} - -static int -serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - if (ser->irq >= nr_irqs || ser->irq < 0 || - ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || - ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS || - ser->type == PORT_STARTECH) - return -EINVAL; - return 0; -} - -static const char * -serial8250_type(struct uart_port *port) -{ - int type = port->type; - - if (type >= ARRAY_SIZE(uart_config)) - type = 0; - return uart_config[type].name; -} - -static const struct uart_ops serial8250_pops = { - .tx_empty = serial8250_tx_empty, - .set_mctrl = serial8250_set_mctrl, - .get_mctrl = serial8250_get_mctrl, - .stop_tx = serial8250_stop_tx, - .start_tx = serial8250_start_tx, - .throttle = serial8250_throttle, - .unthrottle = serial8250_unthrottle, - .stop_rx = serial8250_stop_rx, - .enable_ms = serial8250_enable_ms, - .break_ctl = serial8250_break_ctl, - .startup = serial8250_startup, - .shutdown = serial8250_shutdown, - .set_termios = serial8250_set_termios, - .set_ldisc = serial8250_set_ldisc, - .pm = serial8250_pm, - .type = serial8250_type, - .release_port = serial8250_release_port, - .request_port = serial8250_request_port, - .config_port = serial8250_config_port, - .verify_port = serial8250_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = serial8250_get_poll_char, - .poll_put_char = serial8250_put_poll_char, -#endif -}; - static const struct uart_ops *base_ops; static struct uart_ops univ8250_port_ops; @@ -3139,42 +434,6 @@ void serial8250_set_isa_configurator( } EXPORT_SYMBOL(serial8250_set_isa_configurator); -static void serial8250_init_port(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - - spin_lock_init(&port->lock); - port->ops = &serial8250_pops; - - up->cur_iotype = 0xFF; -} - -static void serial8250_set_defaults(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - - if (up->port.flags & UPF_FIXED_TYPE) { - unsigned int type = up->port.type; - - if (!up->port.fifosize) - up->port.fifosize = uart_config[type].fifo_size; - if (!up->tx_loadsz) - up->tx_loadsz = uart_config[type].tx_loadsz; - if (!up->capabilities) - up->capabilities = uart_config[type].flags; - } - - set_io_from_upio(port); - - /* default dma handlers */ - if (up->dma) { - if (!up->dma->tx_dma) - up->dma->tx_dma = serial8250_tx_dma; - if (!up->dma->rx_dma) - up->dma->rx_dma = serial8250_rx_dma; - } -} - #ifdef CONFIG_SERIAL_8250_RSA static void univ8250_config_port(struct uart_port *port, int flags) @@ -3324,94 +583,6 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) #ifdef CONFIG_SERIAL_8250_CONSOLE -static void serial8250_console_putchar(struct uart_port *port, int ch) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - wait_for_xmitr(up, UART_LSR_THRE); - serial_port_out(port, UART_TX, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void serial8250_console_write(struct uart_8250_port *up, const char *s, - unsigned int count) -{ - struct uart_port *port = &up->port; - unsigned long flags; - unsigned int ier; - int locked = 1; - - touch_nmi_watchdog(); - - serial8250_rpm_get(up); - - if (port->sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock_irqsave(&port->lock, flags); - else - spin_lock_irqsave(&port->lock, flags); - - /* - * First save the IER then disable the interrupts - */ - ier = serial_port_in(port, UART_IER); - - if (up->capabilities & UART_CAP_UUE) - serial_port_out(port, UART_IER, UART_IER_UUE); - else - serial_port_out(port, UART_IER, 0); - - /* check scratch reg to see if port powered off during system sleep */ - if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { - struct ktermios termios; - unsigned int baud, quot, frac = 0; - - termios.c_cflag = port->cons->cflag; - if (port->state->port.tty && termios.c_cflag == 0) - termios.c_cflag = port->state->port.tty->termios.c_cflag; - - baud = uart_get_baud_rate(port, &termios, NULL, - port->uartclk / 16 / 0xffff, - port->uartclk / 16); - quot = serial8250_get_divisor(up, baud, &frac); - - serial8250_set_divisor(port, baud, quot, frac); - serial_port_out(port, UART_LCR, up->lcr); - serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); - - up->canary = 0; - } - - uart_console_write(port, s, count, serial8250_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up, BOTH_EMPTY); - serial_port_out(port, UART_IER, ier); - - /* - * The receive handling will happen properly because the - * receive ready bit will still be set; it is not cleared - * on read. However, modem control will not, we must - * call it if we have saved something in the saved flags - * while processing with interrupts off. - */ - if (up->msr_saved_flags) - serial8250_modem_status(up); - - if (locked) - spin_unlock_irqrestore(&port->lock, flags); - serial8250_rpm_put(up); -} - static void univ8250_console_write(struct console *co, const char *s, unsigned int count) { @@ -3420,39 +591,6 @@ static void univ8250_console_write(struct console *co, const char *s, serial8250_console_write(up, s, count); } -static unsigned int probe_baud(struct uart_port *port) -{ - unsigned char lcr, dll, dlm; - unsigned int quot; - - lcr = serial_port_in(port, UART_LCR); - serial_port_out(port, UART_LCR, lcr | UART_LCR_DLAB); - dll = serial_port_in(port, UART_DLL); - dlm = serial_port_in(port, UART_DLM); - serial_port_out(port, UART_LCR, lcr); - - quot = (dlm << 8) | dll; - return (port->uartclk / 16) / quot; -} - -static int serial8250_console_setup(struct uart_port *port, char *options, bool probe) -{ - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (!port->iobase && !port->membase) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else if (probe) - baud = probe_baud(port); - - return uart_set_options(port, port->cons, baud, parity, bits, flow); -} - static int univ8250_console_setup(struct console *co, char *options) { struct uart_port *port; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c new file mode 100644 index 000000000000..4dc143eee086 --- /dev/null +++ b/drivers/tty/serial/8250/8250_port.c @@ -0,0 +1,2898 @@ +/* + * Base port operations for 8250/16550-type serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Split from 8250_core.c, Copyright (C) 2001 Russell King. + * + * 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. + * + * A note about mapbase / membase + * + * mapbase is the physical address of the IO port. + * membase is an 'ioremapped' cookie. + */ + +#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "8250.h" + +/* + * Debugging. + */ +#if 0 +#define DEBUG_AUTOCONF(fmt...) printk(fmt) +#else +#define DEBUG_AUTOCONF(fmt...) do { } while (0) +#endif + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +/* + * Here we define the default xmit fifo size used for each type of UART. + */ +static const struct serial8250_config uart_config[] = { + [PORT_UNKNOWN] = { + .name = "unknown", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_8250] = { + .name = "8250", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16450] = { + .name = "16450", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16550] = { + .name = "16550", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16550A] = { + .name = "16550A", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .rxtrig_bytes = {1, 4, 8, 14}, + .flags = UART_CAP_FIFO, + }, + [PORT_CIRRUS] = { + .name = "Cirrus", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16650] = { + .name = "ST16650", + .fifo_size = 1, + .tx_loadsz = 1, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16650V2] = { + .name = "ST16650V2", + .fifo_size = 32, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_00, + .rxtrig_bytes = {8, 16, 24, 28}, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16750] = { + .name = "TI16750", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | + UART_FCR7_64BYTE, + .rxtrig_bytes = {1, 16, 32, 56}, + .flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE, + }, + [PORT_STARTECH] = { + .name = "Startech", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16C950] = { + .name = "16C950/954", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + /* UART_CAP_EFR breaks billionon CF bluetooth card. */ + .flags = UART_CAP_FIFO | UART_CAP_SLEEP, + }, + [PORT_16654] = { + .name = "ST16654", + .fifo_size = 64, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_10, + .rxtrig_bytes = {8, 16, 56, 60}, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16850] = { + .name = "XR16850", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_RSA] = { + .name = "RSA", + .fifo_size = 2048, + .tx_loadsz = 2048, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11, + .flags = UART_CAP_FIFO, + }, + [PORT_NS16550A] = { + .name = "NS16550A", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_NATSEMI, + }, + [PORT_XSCALE] = { + .name = "XScale", + .fifo_size = 32, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_UUE | UART_CAP_RTOIE, + }, + [PORT_OCTEON] = { + .name = "OCTEON", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO, + }, + [PORT_AR7] = { + .name = "AR7", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_U6_16550A] = { + .name = "U6_16550A", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_TEGRA] = { + .name = "Tegra", + .fifo_size = 32, + .tx_loadsz = 8, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_01, + .rxtrig_bytes = {1, 4, 8, 14}, + .flags = UART_CAP_FIFO | UART_CAP_RTOIE, + }, + [PORT_XR17D15X] = { + .name = "XR17D15X", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP, + }, + [PORT_XR17V35X] = { + .name = "XR17V35X", + .fifo_size = 256, + .tx_loadsz = 256, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 | + UART_FCR_T_TRIG_11, + .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP, + }, + [PORT_LPC3220] = { + .name = "LPC3220", + .fifo_size = 64, + .tx_loadsz = 32, + .fcr = UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO | + UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00, + .flags = UART_CAP_FIFO, + }, + [PORT_BRCM_TRUMANAGE] = { + .name = "TruManage", + .fifo_size = 1, + .tx_loadsz = 1024, + .flags = UART_CAP_HFIFO, + }, + [PORT_8250_CIR] = { + .name = "CIR port" + }, + [PORT_ALTR_16550_F32] = { + .name = "Altera 16550 FIFO32", + .fifo_size = 32, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_ALTR_16550_F64] = { + .name = "Altera 16550 FIFO64", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_ALTR_16550_F128] = { + .name = "Altera 16550 FIFO128", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, +/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement +workaround of errata A-008006 which states that tx_loadsz should be +configured less than Maximum supported fifo bytes */ + [PORT_16550A_FSL64] = { + .name = "16550A_FSL64", + .fifo_size = 64, + .tx_loadsz = 63, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | + UART_FCR7_64BYTE, + .flags = UART_CAP_FIFO, + }, +}; + +/* Uart divisor latch read */ +static int default_serial_dl_read(struct uart_8250_port *up) +{ + return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; +} + +/* Uart divisor latch write */ +static void default_serial_dl_write(struct uart_8250_port *up, int value) +{ + serial_out(up, UART_DLL, value & 0xff); + serial_out(up, UART_DLM, value >> 8 & 0xff); +} + +#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) + +/* Au1x00/RT288x UART hardware has a weird register layout */ +static const s8 au_io_in_map[8] = { + 0, /* UART_RX */ + 2, /* UART_IER */ + 3, /* UART_IIR */ + 5, /* UART_LCR */ + 6, /* UART_MCR */ + 7, /* UART_LSR */ + 8, /* UART_MSR */ + -1, /* UART_SCR (unmapped) */ +}; + +static const s8 au_io_out_map[8] = { + 1, /* UART_TX */ + 2, /* UART_IER */ + 4, /* UART_FCR */ + 5, /* UART_LCR */ + 6, /* UART_MCR */ + -1, /* UART_LSR (unmapped) */ + -1, /* UART_MSR (unmapped) */ + -1, /* UART_SCR (unmapped) */ +}; + +static unsigned int au_serial_in(struct uart_port *p, int offset) +{ + if (offset >= ARRAY_SIZE(au_io_in_map)) + return UINT_MAX; + offset = au_io_in_map[offset]; + if (offset < 0) + return UINT_MAX; + return __raw_readl(p->membase + (offset << p->regshift)); +} + +static void au_serial_out(struct uart_port *p, int offset, int value) +{ + if (offset >= ARRAY_SIZE(au_io_out_map)) + return; + offset = au_io_out_map[offset]; + if (offset < 0) + return; + __raw_writel(value, p->membase + (offset << p->regshift)); +} + +/* Au1x00 haven't got a standard divisor latch */ +static int au_serial_dl_read(struct uart_8250_port *up) +{ + return __raw_readl(up->port.membase + 0x28); +} + +static void au_serial_dl_write(struct uart_8250_port *up, int value) +{ + __raw_writel(value, up->port.membase + 0x28); +} + +#endif + +static unsigned int hub6_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + outb(p->hub6 - 1 + offset, p->iobase); + return inb(p->iobase + 1); +} + +static void hub6_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + outb(p->hub6 - 1 + offset, p->iobase); + outb(value, p->iobase + 1); +} + +static unsigned int mem_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return readb(p->membase + offset); +} + +static void mem_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + writeb(value, p->membase + offset); +} + +static void mem32_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + writel(value, p->membase + offset); +} + +static unsigned int mem32_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return readl(p->membase + offset); +} + +static void mem32be_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + iowrite32be(value, p->membase + offset); +} + +static unsigned int mem32be_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return ioread32be(p->membase + offset); +} + +static unsigned int io_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return inb(p->iobase + offset); +} + +static void io_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + outb(value, p->iobase + offset); +} + +static int serial8250_default_handle_irq(struct uart_port *port); +static int exar_handle_irq(struct uart_port *port); + +static void set_io_from_upio(struct uart_port *p) +{ + struct uart_8250_port *up = up_to_u8250p(p); + + up->dl_read = default_serial_dl_read; + up->dl_write = default_serial_dl_write; + + switch (p->iotype) { + case UPIO_HUB6: + p->serial_in = hub6_serial_in; + p->serial_out = hub6_serial_out; + break; + + case UPIO_MEM: + p->serial_in = mem_serial_in; + p->serial_out = mem_serial_out; + break; + + case UPIO_MEM32: + p->serial_in = mem32_serial_in; + p->serial_out = mem32_serial_out; + break; + + case UPIO_MEM32BE: + p->serial_in = mem32be_serial_in; + p->serial_out = mem32be_serial_out; + break; + +#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) + case UPIO_AU: + p->serial_in = au_serial_in; + p->serial_out = au_serial_out; + up->dl_read = au_serial_dl_read; + up->dl_write = au_serial_dl_write; + break; +#endif + + default: + p->serial_in = io_serial_in; + p->serial_out = io_serial_out; + break; + } + /* Remember loaded iotype */ + up->cur_iotype = p->iotype; + p->handle_irq = serial8250_default_handle_irq; +} + +static void +serial_port_out_sync(struct uart_port *p, int offset, int value) +{ + switch (p->iotype) { + case UPIO_MEM: + case UPIO_MEM32: + case UPIO_MEM32BE: + case UPIO_AU: + p->serial_out(p, offset, value); + p->serial_in(p, UART_LCR); /* safe, no side-effects */ + break; + default: + p->serial_out(p, offset, value); + } +} + +/* + * For the 16C950 + */ +static void serial_icr_write(struct uart_8250_port *up, int offset, int value) +{ + serial_out(up, UART_SCR, offset); + serial_out(up, UART_ICR, value); +} + +static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) +{ + unsigned int value; + + serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); + serial_out(up, UART_SCR, offset); + value = serial_in(up, UART_ICR); + serial_icr_write(up, UART_ACR, up->acr); + + return value; +} + +/* + * FIFO support. + */ +static void serial8250_clear_fifos(struct uart_8250_port *p) +{ + if (p->capabilities & UART_CAP_FIFO) { + serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_out(p, UART_FCR, 0); + } +} + +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) +{ + serial8250_clear_fifos(p); + serial_out(p, UART_FCR, p->fcr); +} +EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); + +void serial8250_rpm_get(struct uart_8250_port *p) +{ + if (!(p->capabilities & UART_CAP_RPM)) + return; + pm_runtime_get_sync(p->port.dev); +} +EXPORT_SYMBOL_GPL(serial8250_rpm_get); + +void serial8250_rpm_put(struct uart_8250_port *p) +{ + if (!(p->capabilities & UART_CAP_RPM)) + return; + pm_runtime_mark_last_busy(p->port.dev); + pm_runtime_put_autosuspend(p->port.dev); +} +EXPORT_SYMBOL_GPL(serial8250_rpm_put); + +/* + * These two wrappers ensure that enable_runtime_pm_tx() can be called more than + * once and disable_runtime_pm_tx() will still disable RPM because the fifo is + * empty and the HW can idle again. + */ +static void serial8250_rpm_get_tx(struct uart_8250_port *p) +{ + unsigned char rpm_active; + + if (!(p->capabilities & UART_CAP_RPM)) + return; + + rpm_active = xchg(&p->rpm_tx_active, 1); + if (rpm_active) + return; + pm_runtime_get_sync(p->port.dev); +} + +static void serial8250_rpm_put_tx(struct uart_8250_port *p) +{ + unsigned char rpm_active; + + if (!(p->capabilities & UART_CAP_RPM)) + return; + + rpm_active = xchg(&p->rpm_tx_active, 0); + if (!rpm_active) + return; + pm_runtime_mark_last_busy(p->port.dev); + pm_runtime_put_autosuspend(p->port.dev); +} + +/* + * IER sleep support. UARTs which have EFRs need the "extended + * capability" bit enabled. Note that on XR16C850s, we need to + * reset LCR to write to IER. + */ +static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) +{ + unsigned char lcr = 0, efr = 0; + /* + * Exar UARTs have a SLEEP register that enables or disables + * each UART to enter sleep mode separately. On the XR17V35x the + * register is accessible to each UART at the UART_EXAR_SLEEP + * offset but the UART channel may only write to the corresponding + * bit. + */ + serial8250_rpm_get(p); + if ((p->port.type == PORT_XR17V35X) || + (p->port.type == PORT_XR17D15X)) { + serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0); + goto out; + } + + if (p->capabilities & UART_CAP_SLEEP) { + if (p->capabilities & UART_CAP_EFR) { + lcr = serial_in(p, UART_LCR); + efr = serial_in(p, UART_EFR); + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, UART_EFR_ECB); + serial_out(p, UART_LCR, 0); + } + serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); + if (p->capabilities & UART_CAP_EFR) { + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, efr); + serial_out(p, UART_LCR, lcr); + } + } +out: + serial8250_rpm_put(p); +} + +#ifdef CONFIG_SERIAL_8250_RSA +/* + * Attempts to turn on the RSA FIFO. Returns zero on failure. + * We set the port uart clock rate if we succeed. + */ +static int __enable_rsa(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + mode = serial_in(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + + if (!result) { + serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; + + return result; +} + +static void enable_rsa(struct uart_8250_port *up) +{ + if (up->port.type == PORT_RSA) { + if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + __enable_rsa(up); + spin_unlock_irq(&up->port.lock); + } + if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) + serial_out(up, UART_RSA_FRR, 0); + } +} + +/* + * Attempts to turn off the RSA FIFO. Returns zero on failure. + * It is unknown why interrupts were disabled in here. However, + * the caller is expected to preserve this behaviour by grabbing + * the spinlock before calling this function. + */ +static void disable_rsa(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + if (up->port.type == PORT_RSA && + up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + + mode = serial_in(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + + if (!result) { + serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; + spin_unlock_irq(&up->port.lock); + } +} +#endif /* CONFIG_SERIAL_8250_RSA */ + +/* + * This is a quickie test to see how big the FIFO is. + * It doesn't work at all the time, more's the pity. + */ +static int size_fifo(struct uart_8250_port *up) +{ + unsigned char old_fcr, old_mcr, old_lcr; + unsigned short old_dl; + int count; + + old_lcr = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, 0); + old_fcr = serial_in(up, UART_FCR); + old_mcr = serial_in(up, UART_MCR); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_out(up, UART_MCR, UART_MCR_LOOP); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + old_dl = serial_dl_read(up); + serial_dl_write(up, 0x0001); + serial_out(up, UART_LCR, 0x03); + for (count = 0; count < 256; count++) + serial_out(up, UART_TX, count); + mdelay(20);/* FIXME - schedule_timeout */ + for (count = 0; (serial_in(up, UART_LSR) & UART_LSR_DR) && + (count < 256); count++) + serial_in(up, UART_RX); + serial_out(up, UART_FCR, old_fcr); + serial_out(up, UART_MCR, old_mcr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_dl_write(up, old_dl); + serial_out(up, UART_LCR, old_lcr); + + return count; +} + +/* + * Read UART ID using the divisor method - set DLL and DLM to zero + * and the revision will be in DLL and device type in DLM. We + * preserve the device state across this. + */ +static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) +{ + unsigned char old_dll, old_dlm, old_lcr; + unsigned int id; + + old_lcr = serial_in(p, UART_LCR); + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A); + + old_dll = serial_in(p, UART_DLL); + old_dlm = serial_in(p, UART_DLM); + + serial_out(p, UART_DLL, 0); + serial_out(p, UART_DLM, 0); + + id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8; + + serial_out(p, UART_DLL, old_dll); + serial_out(p, UART_DLM, old_dlm); + serial_out(p, UART_LCR, old_lcr); + + return id; +} + +/* + * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. + * When this function is called we know it is at least a StarTech + * 16650 V2, but it might be one of several StarTech UARTs, or one of + * its clones. (We treat the broken original StarTech 16650 V1 as a + * 16550, and why not? Startech doesn't seem to even acknowledge its + * existence.) + * + * What evil have men's minds wrought... + */ +static void autoconfig_has_efr(struct uart_8250_port *up) +{ + unsigned int id1, id2, id3, rev; + + /* + * Everything with an EFR has SLEEP + */ + up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; + + /* + * First we check to see if it's an Oxford Semiconductor UART. + * + * If we have to do this here because some non-National + * Semiconductor clone chips lock up if you try writing to the + * LSR register (which serial_icr_read does) + */ + + /* + * Check for Oxford Semiconductor 16C950. + * + * EFR [4] must be set else this test fails. + * + * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca) + * claims that it's needed for 952 dual UART's (which are not + * recommended for new designs). + */ + up->acr = 0; + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, UART_LCR, 0x00); + id1 = serial_icr_read(up, UART_ID1); + id2 = serial_icr_read(up, UART_ID2); + id3 = serial_icr_read(up, UART_ID3); + rev = serial_icr_read(up, UART_REV); + + DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); + + if (id1 == 0x16 && id2 == 0xC9 && + (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { + up->port.type = PORT_16C950; + + /* + * Enable work around for the Oxford Semiconductor 952 rev B + * chip which causes it to seriously miscalculate baud rates + * when DLL is 0. + */ + if (id3 == 0x52 && rev == 0x01) + up->bugs |= UART_BUG_QUOT; + return; + } + + /* + * We check for a XR16C850 by setting DLL and DLM to 0, and then + * reading back DLL and DLM. The chip type depends on the DLM + * value read back: + * 0x10 - XR16C850 and the DLL contains the chip revision. + * 0x12 - XR16C2850. + * 0x14 - XR16C854. + */ + id1 = autoconfig_read_divisor_id(up); + DEBUG_AUTOCONF("850id=%04x ", id1); + + id2 = id1 >> 8; + if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) { + up->port.type = PORT_16850; + return; + } + + /* + * It wasn't an XR16C850. + * + * We distinguish between the '654 and the '650 by counting + * how many bytes are in the FIFO. I'm using this for now, + * since that's the technique that was sent to me in the + * serial driver update, but I'm not convinced this works. + * I've had problems doing this in the past. -TYT + */ + if (size_fifo(up) == 64) + up->port.type = PORT_16654; + else + up->port.type = PORT_16650V2; +} + +/* + * We detected a chip without a FIFO. Only two fall into + * this category - the original 8250 and the 16450. The + * 16450 has a scratch register (accessible with LCR=0) + */ +static void autoconfig_8250(struct uart_8250_port *up) +{ + unsigned char scratch, status1, status2; + + up->port.type = PORT_8250; + + scratch = serial_in(up, UART_SCR); + serial_out(up, UART_SCR, 0xa5); + status1 = serial_in(up, UART_SCR); + serial_out(up, UART_SCR, 0x5a); + status2 = serial_in(up, UART_SCR); + serial_out(up, UART_SCR, scratch); + + if (status1 == 0xa5 && status2 == 0x5a) + up->port.type = PORT_16450; +} + +static int broken_efr(struct uart_8250_port *up) +{ + /* + * Exar ST16C2550 "A2" devices incorrectly detect as + * having an EFR, and report an ID of 0x0201. See + * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html + */ + if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) + return 1; + + return 0; +} + +/* + * We know that the chip has FIFOs. Does it have an EFR? The + * EFR is located in the same register position as the IIR and + * we know the top two bits of the IIR are currently set. The + * EFR should contain zero. Try to read the EFR. + */ +static void autoconfig_16550a(struct uart_8250_port *up) +{ + unsigned char status1, status2; + unsigned int iersave; + + up->port.type = PORT_16550A; + up->capabilities |= UART_CAP_FIFO; + + /* + * XR17V35x UARTs have an extra divisor register, DLD + * that gets enabled with when DLAB is set which will + * cause the device to incorrectly match and assign + * port type to PORT_16650. The EFR for this UART is + * found at offset 0x09. Instead check the Deice ID (DVID) + * register for a 2, 4 or 8 port UART. + */ + if (up->port.flags & UPF_EXAR_EFR) { + status1 = serial_in(up, UART_EXAR_DVID); + if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) { + DEBUG_AUTOCONF("Exar XR17V35x "); + up->port.type = PORT_XR17V35X; + up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP; + + return; + } + + } + + /* + * Check for presence of the EFR when DLAB is set. + * Only ST16C650V1 UARTs pass this test. + */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + if (serial_in(up, UART_EFR) == 0) { + serial_out(up, UART_EFR, 0xA8); + if (serial_in(up, UART_EFR) != 0) { + DEBUG_AUTOCONF("EFRv1 "); + up->port.type = PORT_16650; + up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; + } else { + serial_out(up, UART_LCR, 0); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR7_64BYTE); + status1 = serial_in(up, UART_IIR) >> 5; + serial_out(up, UART_FCR, 0); + serial_out(up, UART_LCR, 0); + + if (status1 == 7) + up->port.type = PORT_16550A_FSL64; + else + DEBUG_AUTOCONF("Motorola 8xxx DUART "); + } + serial_out(up, UART_EFR, 0); + return; + } + + /* + * Maybe it requires 0xbf to be written to the LCR. + * (other ST16C650V2 UARTs, TI16C752A, etc) + */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { + DEBUG_AUTOCONF("EFRv2 "); + autoconfig_has_efr(up); + return; + } + + /* + * Check for a National Semiconductor SuperIO chip. + * Attempt to switch to bank 2, read the value of the LOOP bit + * from EXCR1. Switch back to bank 0, change it in MCR. Then + * switch back to bank 2, read it from EXCR1 again and check + * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 + */ + serial_out(up, UART_LCR, 0); + status1 = serial_in(up, UART_MCR); + serial_out(up, UART_LCR, 0xE0); + status2 = serial_in(up, 0x02); /* EXCR1 */ + + if (!((status2 ^ status1) & UART_MCR_LOOP)) { + serial_out(up, UART_LCR, 0); + serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP); + serial_out(up, UART_LCR, 0xE0); + status2 = serial_in(up, 0x02); /* EXCR1 */ + serial_out(up, UART_LCR, 0); + serial_out(up, UART_MCR, status1); + + if ((status2 ^ status1) & UART_MCR_LOOP) { + unsigned short quot; + + serial_out(up, UART_LCR, 0xE0); + + quot = serial_dl_read(up); + quot <<= 3; + + if (ns16550a_goto_highspeed(up)) + serial_dl_write(up, quot); + + serial_out(up, UART_LCR, 0); + + up->port.uartclk = 921600*16; + up->port.type = PORT_NS16550A; + up->capabilities |= UART_NATSEMI; + return; + } + } + + /* + * No EFR. Try to detect a TI16750, which only sets bit 5 of + * the IIR when 64 byte FIFO mode is enabled when DLAB is set. + * Try setting it with and without DLAB set. Cheap clones + * set bit 5 without DLAB set. + */ + serial_out(up, UART_LCR, 0); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status1 = serial_in(up, UART_IIR) >> 5; + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status2 = serial_in(up, UART_IIR) >> 5; + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_LCR, 0); + + DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); + + if (status1 == 6 && status2 == 7) { + up->port.type = PORT_16750; + up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP; + return; + } + + /* + * Try writing and reading the UART_IER_UUE bit (b6). + * If it works, this is probably one of the Xscale platform's + * internal UARTs. + * We're going to explicitly set the UUE bit to 0 before + * trying to write and read a 1 just to make sure it's not + * already a 1 and maybe locked there before we even start start. + */ + iersave = serial_in(up, UART_IER); + serial_out(up, UART_IER, iersave & ~UART_IER_UUE); + if (!(serial_in(up, UART_IER) & UART_IER_UUE)) { + /* + * OK it's in a known zero state, try writing and reading + * without disturbing the current state of the other bits. + */ + serial_out(up, UART_IER, iersave | UART_IER_UUE); + if (serial_in(up, UART_IER) & UART_IER_UUE) { + /* + * It's an Xscale. + * We'll leave the UART_IER_UUE bit set to 1 (enabled). + */ + DEBUG_AUTOCONF("Xscale "); + up->port.type = PORT_XSCALE; + up->capabilities |= UART_CAP_UUE | UART_CAP_RTOIE; + return; + } + } else { + /* + * If we got here we couldn't force the IER_UUE bit to 0. + * Log it and continue. + */ + DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); + } + serial_out(up, UART_IER, iersave); + + /* + * Exar uarts have EFR in a weird location + */ + if (up->port.flags & UPF_EXAR_EFR) { + DEBUG_AUTOCONF("Exar XR17D15x "); + up->port.type = PORT_XR17D15X; + up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP; + + return; + } + + /* + * We distinguish between 16550A and U6 16550A by counting + * how many bytes are in the FIFO. + */ + if (up->port.type == PORT_16550A && size_fifo(up) == 64) { + up->port.type = PORT_U6_16550A; + up->capabilities |= UART_CAP_AFE; + } +} + +/* + * This routine is called by rs_init() to initialize a specific serial + * port. It determines what type of UART chip this serial port is + * using: 8250, 16450, 16550, 16550A. The important question is + * whether or not this UART is a 16550A or not, since this will + * determine whether or not we can use its FIFO features or not. + */ +static void autoconfig(struct uart_8250_port *up) +{ + unsigned char status1, scratch, scratch2, scratch3; + unsigned char save_lcr, save_mcr; + struct uart_port *port = &up->port; + unsigned long flags; + unsigned int old_capabilities; + + if (!port->iobase && !port->mapbase && !port->membase) + return; + + DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", + serial_index(port), port->iobase, port->membase); + + /* + * We really do need global IRQs disabled here - we're going to + * be frobbing the chips IRQ enable register to see if it exists. + */ + spin_lock_irqsave(&port->lock, flags); + + up->capabilities = 0; + up->bugs = 0; + + if (!(port->flags & UPF_BUGGY_UART)) { + /* + * Do a simple existence test first; if we fail this, + * there's no point trying anything else. + * + * 0x80 is used as a nonsense port to prevent against + * false positives due to ISA bus float. The + * assumption is that 0x80 is a non-existent port; + * which should be safe since include/asm/io.h also + * makes this assumption. + * + * Note: this is safe as long as MCR bit 4 is clear + * and the device is in "PC" mode. + */ + scratch = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); +#ifdef __i386__ + outb(0xff, 0x080); +#endif + /* + * Mask out IER[7:4] bits for test as some UARTs (e.g. TL + * 16C754B) allow only to modify them if an EFR bit is set. + */ + scratch2 = serial_in(up, UART_IER) & 0x0f; + serial_out(up, UART_IER, 0x0F); +#ifdef __i386__ + outb(0, 0x080); +#endif + scratch3 = serial_in(up, UART_IER) & 0x0f; + serial_out(up, UART_IER, scratch); + if (scratch2 != 0 || scratch3 != 0x0F) { + /* + * We failed; there's nothing here + */ + spin_unlock_irqrestore(&port->lock, flags); + DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", + scratch2, scratch3); + goto out; + } + } + + save_mcr = serial_in(up, UART_MCR); + save_lcr = serial_in(up, UART_LCR); + + /* + * Check to see if a UART is really there. Certain broken + * internal modems based on the Rockwell chipset fail this + * test, because they apparently don't implement the loopback + * test mode. So this test is skipped on the COM 1 through + * COM 4 ports. This *should* be safe, since no board + * manufacturer would be stupid enough to design a board + * that conflicts with COM 1-4 --- we hope! + */ + if (!(port->flags & UPF_SKIP_TEST)) { + serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_in(up, UART_MSR) & 0xF0; + serial_out(up, UART_MCR, save_mcr); + if (status1 != 0x90) { + spin_unlock_irqrestore(&port->lock, flags); + DEBUG_AUTOCONF("LOOP test failed (%02x) ", + status1); + goto out; + } + } + + /* + * We're pretty sure there's a port here. Lets find out what + * type of port it is. The IIR top two bits allows us to find + * out if it's 8250 or 16450, 16550, 16550A or later. This + * determines what we test for next. + * + * We also initialise the EFR (if any) to zero for later. The + * EFR occupies the same register location as the FCR and IIR. + */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, 0); + serial_out(up, UART_LCR, 0); + + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(up, UART_IIR) >> 6; + + switch (scratch) { + case 0: + autoconfig_8250(up); + break; + case 1: + port->type = PORT_UNKNOWN; + break; + case 2: + port->type = PORT_16550; + break; + case 3: + autoconfig_16550a(up); + break; + } + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * Only probe for RSA ports if we got the region. + */ + if (port->type == PORT_16550A && up->probe & UART_PROBE_RSA && + __enable_rsa(up)) + port->type = PORT_RSA; +#endif + + serial_out(up, UART_LCR, save_lcr); + + port->fifosize = uart_config[up->port.type].fifo_size; + old_capabilities = up->capabilities; + up->capabilities = uart_config[port->type].flags; + up->tx_loadsz = uart_config[port->type].tx_loadsz; + + if (port->type == PORT_UNKNOWN) + goto out_lock; + + /* + * Reset the UART. + */ +#ifdef CONFIG_SERIAL_8250_RSA + if (port->type == PORT_RSA) + serial_out(up, UART_RSA_FRR, 0); +#endif + serial_out(up, UART_MCR, save_mcr); + serial8250_clear_fifos(up); + serial_in(up, UART_RX); + if (up->capabilities & UART_CAP_UUE) + serial_out(up, UART_IER, UART_IER_UUE); + else + serial_out(up, UART_IER, 0); + +out_lock: + spin_unlock_irqrestore(&port->lock, flags); + if (up->capabilities != old_capabilities) { + printk(KERN_WARNING + "ttyS%d: detected caps %08x should be %08x\n", + serial_index(port), old_capabilities, + up->capabilities); + } +out: + DEBUG_AUTOCONF("iir=%d ", scratch); + DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name); +} + +static void autoconfig_irq(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + unsigned char save_mcr, save_ier; + unsigned char save_ICP = 0; + unsigned int ICP = 0; + unsigned long irqs; + int irq; + + if (port->flags & UPF_FOURPORT) { + ICP = (port->iobase & 0xfe0) | 0x1f; + save_ICP = inb_p(ICP); + outb_p(0x80, ICP); + inb_p(ICP); + } + + /* forget possible initially masked and pending IRQ */ + probe_irq_off(probe_irq_on()); + save_mcr = serial_in(up, UART_MCR); + save_ier = serial_in(up, UART_IER); + serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); + + irqs = probe_irq_on(); + serial_out(up, UART_MCR, 0); + udelay(10); + if (port->flags & UPF_FOURPORT) { + serial_out(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS); + } else { + serial_out(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + } + serial_out(up, UART_IER, 0x0f); /* enable all intrs */ + serial_in(up, UART_LSR); + serial_in(up, UART_RX); + serial_in(up, UART_IIR); + serial_in(up, UART_MSR); + serial_out(up, UART_TX, 0xFF); + udelay(20); + irq = probe_irq_off(irqs); + + serial_out(up, UART_MCR, save_mcr); + serial_out(up, UART_IER, save_ier); + + if (port->flags & UPF_FOURPORT) + outb_p(save_ICP, ICP); + + port->irq = (irq > 0) ? irq : 0; +} + +static inline void __stop_tx(struct uart_8250_port *p) +{ + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + serial8250_rpm_put_tx(p); + } +} + +static void serial8250_stop_tx(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + serial8250_rpm_get(up); + __stop_tx(up); + + /* + * We really want to stop the transmitter from sending. + */ + if (port->type == PORT_16C950) { + up->acr |= UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } + serial8250_rpm_put(up); +} + +static void serial8250_start_tx(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + serial8250_rpm_get_tx(up); + + if (up->dma && !up->dma->tx_dma(up)) + return; + + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_port_out(port, UART_IER, up->ier); + + if (up->bugs & UART_BUG_TXEN) { + unsigned char lsr; + lsr = serial_in(up, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + if (lsr & UART_LSR_THRE) + serial8250_tx_chars(up); + } + } + + /* + * Re-enable the transmitter if we disabled it. + */ + if (port->type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { + up->acr &= ~UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +} + +static void serial8250_throttle(struct uart_port *port) +{ + port->throttle(port); +} + +static void serial8250_unthrottle(struct uart_port *port) +{ + port->unthrottle(port); +} + +static void serial8250_stop_rx(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + serial8250_rpm_get(up); + + up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); + up->port.read_status_mask &= ~UART_LSR_DR; + serial_port_out(port, UART_IER, up->ier); + + serial8250_rpm_put(up); +} + +static void serial8250_disable_ms(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + /* no MSR capabilities */ + if (up->bugs & UART_BUG_NOMSR) + return; + + up->ier &= ~UART_IER_MSI; + serial_port_out(port, UART_IER, up->ier); +} + +static void serial8250_enable_ms(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + /* no MSR capabilities */ + if (up->bugs & UART_BUG_NOMSR) + return; + + up->ier |= UART_IER_MSI; + + serial8250_rpm_get(up); + serial_port_out(port, UART_IER, up->ier); + serial8250_rpm_put(up); +} + +/* + * serial8250_rx_chars: processes according to the passed in LSR + * value, and returns the remaining LSR bits not handled + * by this Rx routine. + */ +unsigned char +serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) +{ + struct uart_port *port = &up->port; + unsigned char ch; + int max_count = 256; + char flag; + + do { + if (likely(lsr & UART_LSR_DR)) + ch = serial_in(up, UART_RX); + else + /* + * Intel 82571 has a Serial Over Lan device that will + * set UART_LSR_BI without setting UART_LSR_DR when + * it receives a break. To avoid reading from the + * receive buffer without UART_LSR_DR bit set, we + * just force the read character to be 0 + */ + ch = 0; + + flag = TTY_NORMAL; + port->icount.rx++; + + lsr |= up->lsr_saved_flags; + up->lsr_saved_flags = 0; + + if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { + if (lsr & UART_LSR_BI) { + lsr &= ~(UART_LSR_FE | UART_LSR_PE); + port->icount.brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ + if (uart_handle_break(port)) + goto ignore_char; + } else if (lsr & UART_LSR_PE) + port->icount.parity++; + else if (lsr & UART_LSR_FE) + port->icount.frame++; + if (lsr & UART_LSR_OE) + port->icount.overrun++; + + /* + * Mask off conditions which should be ignored. + */ + lsr &= port->read_status_mask; + + if (lsr & UART_LSR_BI) { + DEBUG_INTR("handling break...."); + flag = TTY_BREAK; + } else if (lsr & UART_LSR_PE) + flag = TTY_PARITY; + else if (lsr & UART_LSR_FE) + flag = TTY_FRAME; + } + if (uart_handle_sysrq_char(port, ch)) + goto ignore_char; + + uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); + +ignore_char: + lsr = serial_in(up, UART_LSR); + } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0)); + spin_unlock(&port->lock); + tty_flip_buffer_push(&port->state->port); + spin_lock(&port->lock); + return lsr; +} +EXPORT_SYMBOL_GPL(serial8250_rx_chars); + +void serial8250_tx_chars(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + struct circ_buf *xmit = &port->state->xmit; + int count; + + if (port->x_char) { + serial_out(up, UART_TX, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + if (uart_tx_stopped(port)) { + serial8250_stop_tx(port); + return; + } + if (uart_circ_empty(xmit)) { + __stop_tx(up); + return; + } + + count = up->tx_loadsz; + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + if (up->capabilities & UART_CAP_HFIFO) { + if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) != + BOTH_EMPTY) + break; + } + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + DEBUG_INTR("THRE..."); + + /* + * With RPM enabled, we have to wait until the FIFO is empty before the + * HW can go idle. So we get here once again with empty FIFO and disable + * the interrupt and RPM in __stop_tx() + */ + if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM)) + __stop_tx(up); +} +EXPORT_SYMBOL_GPL(serial8250_tx_chars); + +/* Caller holds uart port lock */ +unsigned int serial8250_modem_status(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + unsigned int status = serial_in(up, UART_MSR); + + status |= up->msr_saved_flags; + up->msr_saved_flags = 0; + if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && + port->state != NULL) { + if (status & UART_MSR_TERI) + port->icount.rng++; + if (status & UART_MSR_DDSR) + port->icount.dsr++; + if (status & UART_MSR_DDCD) + uart_handle_dcd_change(port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) + uart_handle_cts_change(port, status & UART_MSR_CTS); + + wake_up_interruptible(&port->state->port.delta_msr_wait); + } + + return status; +} +EXPORT_SYMBOL_GPL(serial8250_modem_status); + +/* + * This handles the interrupt from one port. + */ +int serial8250_handle_irq(struct uart_port *port, unsigned int iir) +{ + unsigned char status; + unsigned long flags; + struct uart_8250_port *up = up_to_u8250p(port); + int dma_err = 0; + + if (iir & UART_IIR_NO_INT) + return 0; + + spin_lock_irqsave(&port->lock, flags); + + status = serial_port_in(port, UART_LSR); + + DEBUG_INTR("status = %x...", status); + + if (status & (UART_LSR_DR | UART_LSR_BI)) { + if (up->dma) + dma_err = up->dma->rx_dma(up, iir); + + if (!up->dma || dma_err) + status = serial8250_rx_chars(up, status); + } + serial8250_modem_status(up); + if ((!up->dma || (up->dma && up->dma->tx_err)) && + (status & UART_LSR_THRE)) + serial8250_tx_chars(up); + + spin_unlock_irqrestore(&port->lock, flags); + return 1; +} +EXPORT_SYMBOL_GPL(serial8250_handle_irq); + +static int serial8250_default_handle_irq(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned int iir; + int ret; + + serial8250_rpm_get(up); + + iir = serial_port_in(port, UART_IIR); + ret = serial8250_handle_irq(port, iir); + + serial8250_rpm_put(up); + return ret; +} + +/* + * These Exar UARTs have an extra interrupt indicator that could + * fire for a few unimplemented interrupts. One of which is a + * wakeup event when coming out of sleep. Put this here just + * to be on the safe side that these interrupts don't go unhandled. + */ +static int exar_handle_irq(struct uart_port *port) +{ + unsigned char int0, int1, int2, int3; + unsigned int iir = serial_port_in(port, UART_IIR); + int ret; + + ret = serial8250_handle_irq(port, iir); + + if ((port->type == PORT_XR17V35X) || + (port->type == PORT_XR17D15X)) { + int0 = serial_port_in(port, 0x80); + int1 = serial_port_in(port, 0x81); + int2 = serial_port_in(port, 0x82); + int3 = serial_port_in(port, 0x83); + } + + return ret; +} + +static unsigned int serial8250_tx_empty(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned long flags; + unsigned int lsr; + + serial8250_rpm_get(up); + + spin_lock_irqsave(&port->lock, flags); + lsr = serial_port_in(port, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + spin_unlock_irqrestore(&port->lock, flags); + + serial8250_rpm_put(up); + + return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; +} + +static unsigned int serial8250_get_mctrl(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned int status; + unsigned int ret; + + serial8250_rpm_get(up); + status = serial8250_modem_status(up); + serial8250_rpm_put(up); + + ret = 0; + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned char mcr = 0; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; + + serial_port_out(port, UART_MCR, mcr); +} +EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); + +static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + if (port->set_mctrl) + port->set_mctrl(port, mctrl); + else + serial8250_do_set_mctrl(port, mctrl); +} + +static void serial8250_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned long flags; + + serial8250_rpm_get(up); + spin_lock_irqsave(&port->lock, flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_port_out(port, UART_LCR, up->lcr); + spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); +} + +/* + * Wait for transmitter & holding register to empty + */ +static void wait_for_xmitr(struct uart_8250_port *up, int bits) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + for (;;) { + status = serial_in(up, UART_LSR); + + up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; + + if ((status & bits) == bits) + break; + if (--tmout == 0) + break; + udelay(1); + } + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + unsigned int tmout; + for (tmout = 1000000; tmout; tmout--) { + unsigned int msr = serial_in(up, UART_MSR); + up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; + if (msr & UART_MSR_CTS) + break; + udelay(1); + touch_nmi_watchdog(); + } + } +} + +#ifdef CONFIG_CONSOLE_POLL +/* + * Console polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +static int serial8250_get_poll_char(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned char lsr; + int status; + + serial8250_rpm_get(up); + + lsr = serial_port_in(port, UART_LSR); + + if (!(lsr & UART_LSR_DR)) { + status = NO_POLL_CHAR; + goto out; + } + + status = serial_port_in(port, UART_RX); +out: + serial8250_rpm_put(up); + return status; +} + + +static void serial8250_put_poll_char(struct uart_port *port, + unsigned char c) +{ + unsigned int ier; + struct uart_8250_port *up = up_to_u8250p(port); + + serial8250_rpm_get(up); + /* + * First save the IER then disable the interrupts + */ + ier = serial_port_in(port, UART_IER); + if (up->capabilities & UART_CAP_UUE) + serial_port_out(port, UART_IER, UART_IER_UUE); + else + serial_port_out(port, UART_IER, 0); + + wait_for_xmitr(up, BOTH_EMPTY); + /* + * Send the character out. + */ + serial_port_out(port, UART_TX, c); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); + serial_port_out(port, UART_IER, ier); + serial8250_rpm_put(up); +} + +#endif /* CONFIG_CONSOLE_POLL */ + +int serial8250_do_startup(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned long flags; + unsigned char lsr, iir; + int retval; + + if (port->type == PORT_8250_CIR) + return -ENODEV; + + if (!port->fifosize) + port->fifosize = uart_config[port->type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[port->type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[port->type].flags; + up->mcr = 0; + + if (port->iotype != up->cur_iotype) + set_io_from_upio(port); + + serial8250_rpm_get(up); + if (port->type == PORT_16C950) { + /* Wake up and initialize UART */ + up->acr = 0; + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, UART_EFR, UART_EFR_ECB); + serial_port_out(port, UART_IER, 0); + serial_port_out(port, UART_LCR, 0); + serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, UART_EFR, UART_EFR_ECB); + serial_port_out(port, UART_LCR, 0); + } + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * If this is an RSA port, see if we can kick it up to the + * higher speed clock. + */ + enable_rsa(up); +#endif + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in set_termios()) + */ + serial8250_clear_fifos(up); + + /* + * Clear the interrupt registers. + */ + serial_port_in(port, UART_LSR); + serial_port_in(port, UART_RX); + serial_port_in(port, UART_IIR); + serial_port_in(port, UART_MSR); + + /* + * At this point, there's no way the LSR could still be 0xff; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (!(port->flags & UPF_BUGGY_UART) && + (serial_port_in(port, UART_LSR) == 0xff)) { + printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", + serial_index(port)); + retval = -ENODEV; + goto out; + } + + /* + * For a XR16C850, we need to set the trigger levels + */ + if (port->type == PORT_16850) { + unsigned char fctr; + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); + serial_port_out(port, UART_FCTR, + fctr | UART_FCTR_TRGD | UART_FCTR_RX); + serial_port_out(port, UART_TRG, UART_TRG_96); + serial_port_out(port, UART_FCTR, + fctr | UART_FCTR_TRGD | UART_FCTR_TX); + serial_port_out(port, UART_TRG, UART_TRG_96); + + serial_port_out(port, UART_LCR, 0); + } + + if (port->irq) { + unsigned char iir1; + /* + * Test for UARTs that do not reassert THRE when the + * transmitter is idle and the interrupt has already + * been cleared. Real 16550s should always reassert + * this interrupt whenever the transmitter is idle and + * the interrupt is enabled. Delays are necessary to + * allow register changes to become visible. + */ + spin_lock_irqsave(&port->lock, flags); + if (up->port.irqflags & IRQF_SHARED) + disable_irq_nosync(port->irq); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); + udelay(1); /* allow THRE to set */ + iir1 = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); + udelay(1); /* allow a working UART time to re-assert THRE */ + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); + + if (port->irqflags & IRQF_SHARED) + enable_irq(port->irq); + spin_unlock_irqrestore(&port->lock, flags); + + /* + * If the interrupt is not reasserted, or we otherwise + * don't trust the iir, setup a timer to kick the UART + * on a regular basis. + */ + if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || + up->port.flags & UPF_BUG_THRE) { + up->bugs |= UART_BUG_THRE; + } + } + + retval = up->ops->setup_irq(up); + if (retval) + goto out; + + /* + * Now, initialize the UART + */ + serial_port_out(port, UART_LCR, UART_LCR_WLEN8); + + spin_lock_irqsave(&port->lock, flags); + if (up->port.flags & UPF_FOURPORT) { + if (!up->port.irq) + up->port.mctrl |= TIOCM_OUT1; + } else + /* + * Most PC uarts need OUT2 raised to enable interrupts. + */ + if (port->irq) + up->port.mctrl |= TIOCM_OUT2; + + serial8250_set_mctrl(port, port->mctrl); + + /* Serial over Lan (SoL) hack: + Intel 8257x Gigabit ethernet chips have a + 16550 emulation, to be used for Serial Over Lan. + Those chips take a longer time than a normal + serial device to signalize that a transmission + data was queued. Due to that, the above test generally + fails. One solution would be to delay the reading of + iir. However, this is not reliable, since the timeout + is variable. So, let's just don't test if we receive + TX irq. This way, we'll never enable UART_BUG_TXEN. + */ + if (up->port.flags & UPF_NO_TXEN_TEST) + goto dont_test_tx_en; + + /* + * Do a quick test to see if we receive an + * interrupt when we enable the TX irq. + */ + serial_port_out(port, UART_IER, UART_IER_THRI); + lsr = serial_port_in(port, UART_LSR); + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); + + if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { + if (!(up->bugs & UART_BUG_TXEN)) { + up->bugs |= UART_BUG_TXEN; + pr_debug("ttyS%d - enabling bad tx status workarounds\n", + serial_index(port)); + } + } else { + up->bugs &= ~UART_BUG_TXEN; + } + +dont_test_tx_en: + spin_unlock_irqrestore(&port->lock, flags); + + /* + * Clear the interrupt registers again for luck, and clear the + * saved flags to avoid getting false values from polling + * routines or the previous session. + */ + serial_port_in(port, UART_LSR); + serial_port_in(port, UART_RX); + serial_port_in(port, UART_IIR); + serial_port_in(port, UART_MSR); + up->lsr_saved_flags = 0; + up->msr_saved_flags = 0; + + /* + * Request DMA channels for both RX and TX. + */ + if (up->dma) { + retval = serial8250_request_dma(up); + if (retval) { + pr_warn_ratelimited("ttyS%d - failed to request DMA\n", + serial_index(port)); + up->dma = NULL; + } + } + + /* + * Finally, enable interrupts. Note: Modem status interrupts + * are set via set_termios(), which will be occurring imminently + * anyway, so we don't enable them here. + */ + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_port_out(port, UART_IER, up->ier); + + if (port->flags & UPF_FOURPORT) { + unsigned int icp; + /* + * Enable interrupts on the AST Fourport board + */ + icp = (port->iobase & 0xfe0) | 0x01f; + outb_p(0x80, icp); + inb_p(icp); + } + retval = 0; +out: + serial8250_rpm_put(up); + return retval; +} +EXPORT_SYMBOL_GPL(serial8250_do_startup); + +static int serial8250_startup(struct uart_port *port) +{ + if (port->startup) + return port->startup(port); + return serial8250_do_startup(port); +} + +void serial8250_do_shutdown(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned long flags; + + serial8250_rpm_get(up); + /* + * Disable interrupts from this port + */ + up->ier = 0; + serial_port_out(port, UART_IER, 0); + + if (up->dma) + serial8250_release_dma(up); + + spin_lock_irqsave(&port->lock, flags); + if (port->flags & UPF_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + inb((port->iobase & 0xfe0) | 0x1f); + port->mctrl |= TIOCM_OUT1; + } else + port->mctrl &= ~TIOCM_OUT2; + + serial8250_set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); + + /* + * Disable break condition and FIFOs + */ + serial_port_out(port, UART_LCR, + serial_port_in(port, UART_LCR) & ~UART_LCR_SBC); + serial8250_clear_fifos(up); + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * Reset the RSA board back to 115kbps compat mode. + */ + disable_rsa(up); +#endif + + /* + * Read data port to reset things, and then unlink from + * the IRQ chain. + */ + serial_port_in(port, UART_RX); + serial8250_rpm_put(up); + + up->ops->release_irq(up); +} +EXPORT_SYMBOL_GPL(serial8250_do_shutdown); + +static void serial8250_shutdown(struct uart_port *port) +{ + if (port->shutdown) + port->shutdown(port); + else + serial8250_do_shutdown(port); +} + +/* + * XR17V35x UARTs have an extra fractional divisor register (DLD) + * Calculate divisor with extra 4-bit fractional portion + */ +static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up, + unsigned int baud, + unsigned int *frac) +{ + struct uart_port *port = &up->port; + unsigned int quot_16; + + quot_16 = DIV_ROUND_CLOSEST(port->uartclk, baud); + *frac = quot_16 & 0x0f; + + return quot_16 >> 4; +} + +static unsigned int serial8250_get_divisor(struct uart_8250_port *up, + unsigned int baud, + unsigned int *frac) +{ + struct uart_port *port = &up->port; + unsigned int quot; + + /* + * Handle magic divisors for baud rates above baud_base on + * SMSC SuperIO chips. + * + */ + if ((port->flags & UPF_MAGIC_MULTIPLIER) && + baud == (port->uartclk/4)) + quot = 0x8001; + else if ((port->flags & UPF_MAGIC_MULTIPLIER) && + baud == (port->uartclk/8)) + quot = 0x8002; + else if (up->port.type == PORT_XR17V35X) + quot = xr17v35x_get_divisor(up, baud, frac); + else + quot = uart_get_divisor(port, baud); + + /* + * Oxford Semi 952 rev B workaround + */ + if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) + quot++; + + return quot; +} + +static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, + tcflag_t c_cflag) +{ + unsigned char cval; + + switch (c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (c_cflag & PARENB) { + cval |= UART_LCR_PARITY; + if (up->bugs & UART_BUG_PARITY) + up->fifo_bug = true; + } + if (!(c_cflag & PARODD)) + cval |= UART_LCR_EPAR; +#ifdef CMSPAR + if (c_cflag & CMSPAR) + cval |= UART_LCR_SPAR; +#endif + + return cval; +} + +static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + /* Workaround to enable 115200 baud on OMAP1510 internal ports */ + if (is_omap1510_8250(up)) { + if (baud == 115200) { + quot = 1; + serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1); + } else + serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0); + } + + /* + * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2, + * otherwise just set DLAB + */ + if (up->capabilities & UART_NATSEMI) + serial_port_out(port, UART_LCR, 0xe0); + else + serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); + + serial_dl_write(up, quot); + + /* XR17V35x UARTs have an extra fractional divisor register (DLD) */ + if (up->port.type == PORT_XR17V35X) + serial_port_out(port, 0x2, quot_frac); +} + +void +serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned char cval; + unsigned long flags; + unsigned int baud, quot, frac = 0; + + cval = serial8250_compute_lcr(up, termios->c_cflag); + + /* + * Ask the core to calculate the divisor for us. + */ + baud = uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + port->uartclk / 16); + quot = serial8250_get_divisor(up, baud, &frac); + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + serial8250_rpm_get(up); + spin_lock_irqsave(&port->lock, flags); + + up->lcr = cval; /* Save computed LCR */ + + if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { + /* NOTE: If fifo_bug is not set, a user can set RX_trigger. */ + if ((baud < 2400 && !up->dma) || up->fifo_bug) { + up->fcr &= ~UART_FCR_TRIGGER_MASK; + up->fcr |= UART_FCR_TRIGGER_1; + } + } + + /* + * MCR-based auto flow control. When AFE is enabled, RTS will be + * deasserted when the receive FIFO contains more characters than + * the trigger, or the MCR RTS bit is cleared. In the case where + * the remote UART is not using CTS auto flow control, we must + * have sufficient FIFO entries for the latency of the remote + * UART to respond. IOW, at least 32 bytes of FIFO. + */ + if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { + up->mcr &= ~UART_MCR_AFE; + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE; + } + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) + port->read_status_mask |= UART_LSR_BI; + + /* + * Characteres to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (!(up->bugs & UART_BUG_NOMSR) && + UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; + if (up->capabilities & UART_CAP_UUE) + up->ier |= UART_IER_UUE; + if (up->capabilities & UART_CAP_RTOIE) + up->ier |= UART_IER_RTOIE; + + serial_port_out(port, UART_IER, up->ier); + + if (up->capabilities & UART_CAP_EFR) { + unsigned char efr = 0; + /* + * TI16C752/Startech hardware flow control. FIXME: + * - TI16C752 requires control thresholds to be set. + * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled. + */ + if (termios->c_cflag & CRTSCTS) + efr |= UART_EFR_CTS; + + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + if (port->flags & UPF_EXAR_EFR) + serial_port_out(port, UART_XR_EFR, efr); + else + serial_port_out(port, UART_EFR, efr); + } + + serial8250_set_divisor(port, baud, quot, frac); + + /* + * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR + * is written without DLAB set, this mode will be disabled. + */ + if (port->type == PORT_16750) + serial_port_out(port, UART_FCR, up->fcr); + + serial_port_out(port, UART_LCR, up->lcr); /* reset DLAB */ + if (port->type != PORT_16750) { + /* emulated UARTs (Lucent Venus 167x) need two steps */ + if (up->fcr & UART_FCR_ENABLE_FIFO) + serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_port_out(port, UART_FCR, up->fcr); /* set fcr */ + } + serial8250_set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +} +EXPORT_SYMBOL(serial8250_do_set_termios); + +static void +serial8250_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + if (port->set_termios) + port->set_termios(port, termios, old); + else + serial8250_do_set_termios(port, termios, old); +} + +static void +serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios) +{ + if (termios->c_line == N_PPS) { + port->flags |= UPF_HARDPPS_CD; + spin_lock_irq(&port->lock); + serial8250_enable_ms(port); + spin_unlock_irq(&port->lock); + } else { + port->flags &= ~UPF_HARDPPS_CD; + if (!UART_ENABLE_MS(port, termios->c_cflag)) { + spin_lock_irq(&port->lock); + serial8250_disable_ms(port); + spin_unlock_irq(&port->lock); + } + } +} + + +void serial8250_do_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct uart_8250_port *p = up_to_u8250p(port); + + serial8250_set_sleep(p, state != 0); +} +EXPORT_SYMBOL(serial8250_do_pm); + +static void +serial8250_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + if (port->pm) + port->pm(port, state, oldstate); + else + serial8250_do_pm(port, state, oldstate); +} + +static unsigned int serial8250_port_size(struct uart_8250_port *pt) +{ + if (pt->port.mapsize) + return pt->port.mapsize; + if (pt->port.iotype == UPIO_AU) { + if (pt->port.type == PORT_RT2880) + return 0x100; + return 0x1000; + } + if (is_omap1_8250(pt)) + return 0x16 << pt->port.regshift; + + return 8 << pt->port.regshift; +} + +/* + * Resource handling. + */ +static int serial8250_request_std_resource(struct uart_8250_port *up) +{ + unsigned int size = serial8250_port_size(up); + struct uart_port *port = &up->port; + int ret = 0; + + switch (port->iotype) { + case UPIO_AU: + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM32BE: + case UPIO_MEM: + if (!port->mapbase) + break; + + if (!request_mem_region(port->mapbase, size, "serial")) { + ret = -EBUSY; + break; + } + + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap_nocache(port->mapbase, size); + if (!port->membase) { + release_mem_region(port->mapbase, size); + ret = -ENOMEM; + } + } + break; + + case UPIO_HUB6: + case UPIO_PORT: + if (!request_region(port->iobase, size, "serial")) + ret = -EBUSY; + break; + } + return ret; +} + +static void serial8250_release_std_resource(struct uart_8250_port *up) +{ + unsigned int size = serial8250_port_size(up); + struct uart_port *port = &up->port; + + switch (port->iotype) { + case UPIO_AU: + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM32BE: + case UPIO_MEM: + if (!port->mapbase) + break; + + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } + + release_mem_region(port->mapbase, size); + break; + + case UPIO_HUB6: + case UPIO_PORT: + release_region(port->iobase, size); + break; + } +} + +static void serial8250_release_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + serial8250_release_std_resource(up); +} + +static int serial8250_request_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + int ret; + + if (port->type == PORT_8250_CIR) + return -ENODEV; + + ret = serial8250_request_std_resource(up); + + return ret; +} + +static int fcr_get_rxtrig_bytes(struct uart_8250_port *up) +{ + const struct serial8250_config *conf_type = &uart_config[up->port.type]; + unsigned char bytes; + + bytes = conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(up->fcr)]; + + return bytes ? bytes : -EOPNOTSUPP; +} + +static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, unsigned char bytes) +{ + const struct serial8250_config *conf_type = &uart_config[up->port.type]; + int i; + + if (!conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(UART_FCR_R_TRIG_00)]) + return -EOPNOTSUPP; + + for (i = 1; i < UART_FCR_R_TRIG_MAX_STATE; i++) { + if (bytes < conf_type->rxtrig_bytes[i]) + /* Use the nearest lower value */ + return (--i) << UART_FCR_R_TRIG_SHIFT; + } + + return UART_FCR_R_TRIG_11; +} + +static int do_get_rxtrig(struct tty_port *port) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + struct uart_8250_port *up = + container_of(uport, struct uart_8250_port, port); + + if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1) + return -EINVAL; + + return fcr_get_rxtrig_bytes(up); +} + +static int do_serial8250_get_rxtrig(struct tty_port *port) +{ + int rxtrig_bytes; + + mutex_lock(&port->mutex); + rxtrig_bytes = do_get_rxtrig(port); + mutex_unlock(&port->mutex); + + return rxtrig_bytes; +} + +static ssize_t serial8250_get_attr_rx_trig_bytes(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tty_port *port = dev_get_drvdata(dev); + int rxtrig_bytes; + + rxtrig_bytes = do_serial8250_get_rxtrig(port); + if (rxtrig_bytes < 0) + return rxtrig_bytes; + + return snprintf(buf, PAGE_SIZE, "%d\n", rxtrig_bytes); +} + +static int do_set_rxtrig(struct tty_port *port, unsigned char bytes) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + struct uart_8250_port *up = + container_of(uport, struct uart_8250_port, port); + int rxtrig; + + if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 || + up->fifo_bug) + return -EINVAL; + + rxtrig = bytes_to_fcr_rxtrig(up, bytes); + if (rxtrig < 0) + return rxtrig; + + serial8250_clear_fifos(up); + up->fcr &= ~UART_FCR_TRIGGER_MASK; + up->fcr |= (unsigned char)rxtrig; + serial_out(up, UART_FCR, up->fcr); + return 0; +} + +static int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes) +{ + int ret; + + mutex_lock(&port->mutex); + ret = do_set_rxtrig(port, bytes); + mutex_unlock(&port->mutex); + + return ret; +} + +static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tty_port *port = dev_get_drvdata(dev); + unsigned char bytes; + int ret; + + if (!count) + return -EINVAL; + + ret = kstrtou8(buf, 10, &bytes); + if (ret < 0) + return ret; + + ret = do_serial8250_set_rxtrig(port, bytes); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(rx_trig_bytes, S_IRUSR | S_IWUSR | S_IRGRP, + serial8250_get_attr_rx_trig_bytes, + serial8250_set_attr_rx_trig_bytes); + +static struct attribute *serial8250_dev_attrs[] = { + &dev_attr_rx_trig_bytes.attr, + NULL, + }; + +static struct attribute_group serial8250_dev_attr_group = { + .attrs = serial8250_dev_attrs, + }; + +static void register_dev_spec_attr_grp(struct uart_8250_port *up) +{ + const struct serial8250_config *conf_type = &uart_config[up->port.type]; + + if (conf_type->rxtrig_bytes[0]) + up->port.attr_group = &serial8250_dev_attr_group; +} + +static void serial8250_config_port(struct uart_port *port, int flags) +{ + struct uart_8250_port *up = up_to_u8250p(port); + int ret; + + if (port->type == PORT_8250_CIR) + return; + + /* + * Find the region that we can probe for. This in turn + * tells us whether we can probe for the type of port. + */ + ret = serial8250_request_std_resource(up); + if (ret < 0) + return; + + if (port->iotype != up->cur_iotype) + set_io_from_upio(port); + + if (flags & UART_CONFIG_TYPE) + autoconfig(up); + + /* if access method is AU, it is a 16550 with a quirk */ + if (port->type == PORT_16550A && port->iotype == UPIO_AU) + up->bugs |= UART_BUG_NOMSR; + + /* HW bugs may trigger IRQ while IIR == NO_INT */ + if (port->type == PORT_TEGRA) + up->bugs |= UART_BUG_NOMSR; + + if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) + autoconfig_irq(up); + + if (port->type == PORT_UNKNOWN) + serial8250_release_std_resource(up); + + /* Fixme: probably not the best place for this */ + if ((port->type == PORT_XR17V35X) || + (port->type == PORT_XR17D15X)) + port->handle_irq = exar_handle_irq; + + register_dev_spec_attr_grp(up); + up->fcr = uart_config[up->port.type].fcr; +} + +static int +serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if (ser->irq >= nr_irqs || ser->irq < 0 || + ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || + ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS || + ser->type == PORT_STARTECH) + return -EINVAL; + return 0; +} + +static const char * +serial8250_type(struct uart_port *port) +{ + int type = port->type; + + if (type >= ARRAY_SIZE(uart_config)) + type = 0; + return uart_config[type].name; +} + +static const struct uart_ops serial8250_pops = { + .tx_empty = serial8250_tx_empty, + .set_mctrl = serial8250_set_mctrl, + .get_mctrl = serial8250_get_mctrl, + .stop_tx = serial8250_stop_tx, + .start_tx = serial8250_start_tx, + .throttle = serial8250_throttle, + .unthrottle = serial8250_unthrottle, + .stop_rx = serial8250_stop_rx, + .enable_ms = serial8250_enable_ms, + .break_ctl = serial8250_break_ctl, + .startup = serial8250_startup, + .shutdown = serial8250_shutdown, + .set_termios = serial8250_set_termios, + .set_ldisc = serial8250_set_ldisc, + .pm = serial8250_pm, + .type = serial8250_type, + .release_port = serial8250_release_port, + .request_port = serial8250_request_port, + .config_port = serial8250_config_port, + .verify_port = serial8250_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = serial8250_get_poll_char, + .poll_put_char = serial8250_put_poll_char, +#endif +}; + +void serial8250_init_port(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + spin_lock_init(&port->lock); + port->ops = &serial8250_pops; + + up->cur_iotype = 0xFF; +} +EXPORT_SYMBOL_GPL(serial8250_init_port); + +void serial8250_set_defaults(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + if (up->port.flags & UPF_FIXED_TYPE) { + unsigned int type = up->port.type; + + if (!up->port.fifosize) + up->port.fifosize = uart_config[type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[type].flags; + } + + set_io_from_upio(port); + + /* default dma handlers */ + if (up->dma) { + if (!up->dma->tx_dma) + up->dma->tx_dma = serial8250_tx_dma; + if (!up->dma->rx_dma) + up->dma->rx_dma = serial8250_rx_dma; + } +} +EXPORT_SYMBOL_GPL(serial8250_set_defaults); + +#ifdef CONFIG_SERIAL_8250_CONSOLE + +static void serial8250_console_putchar(struct uart_port *port, int ch) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_port_out(port, UART_TX, ch); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +void serial8250_console_write(struct uart_8250_port *up, const char *s, + unsigned int count) +{ + struct uart_port *port = &up->port; + unsigned long flags; + unsigned int ier; + int locked = 1; + + touch_nmi_watchdog(); + + serial8250_rpm_get(up); + + if (port->sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock_irqsave(&port->lock, flags); + else + spin_lock_irqsave(&port->lock, flags); + + /* + * First save the IER then disable the interrupts + */ + ier = serial_port_in(port, UART_IER); + + if (up->capabilities & UART_CAP_UUE) + serial_port_out(port, UART_IER, UART_IER_UUE); + else + serial_port_out(port, UART_IER, 0); + + /* check scratch reg to see if port powered off during system sleep */ + if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { + struct ktermios termios; + unsigned int baud, quot, frac = 0; + + termios.c_cflag = port->cons->cflag; + if (port->state->port.tty && termios.c_cflag == 0) + termios.c_cflag = port->state->port.tty->termios.c_cflag; + + baud = uart_get_baud_rate(port, &termios, NULL, + port->uartclk / 16 / 0xffff, + port->uartclk / 16); + quot = serial8250_get_divisor(up, baud, &frac); + + serial8250_set_divisor(port, baud, quot, frac); + serial_port_out(port, UART_LCR, up->lcr); + serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); + + up->canary = 0; + } + + uart_console_write(port, s, count, serial8250_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); + serial_port_out(port, UART_IER, ier); + + /* + * The receive handling will happen properly because the + * receive ready bit will still be set; it is not cleared + * on read. However, modem control will not, we must + * call it if we have saved something in the saved flags + * while processing with interrupts off. + */ + if (up->msr_saved_flags) + serial8250_modem_status(up); + + if (locked) + spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); +} + +static unsigned int probe_baud(struct uart_port *port) +{ + unsigned char lcr, dll, dlm; + unsigned int quot; + + lcr = serial_port_in(port, UART_LCR); + serial_port_out(port, UART_LCR, lcr | UART_LCR_DLAB); + dll = serial_port_in(port, UART_DLL); + dlm = serial_port_in(port, UART_DLM); + serial_port_out(port, UART_LCR, lcr); + + quot = (dlm << 8) | dll; + return (port->uartclk / 16) / quot; +} + +int serial8250_console_setup(struct uart_port *port, char *options, bool probe) +{ + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (!port->iobase && !port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else if (probe) + baud = probe_baud(port); + + return uart_set_options(port, port->cons, baud, parity, bits, flow); +} + +#endif /* CONFIG_SERIAL_8250_CONSOLE */ diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 706295913c34..39c6d2277570 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -2,10 +2,11 @@ # Makefile for the 8250 serial device drivers. # -obj-$(CONFIG_SERIAL_8250) += 8250.o +obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o 8250-y := 8250_core.o 8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o -8250-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o +8250_base-y := 8250_port.o +8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index ba82c07feb95..7f156bde38d9 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -152,6 +152,11 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir); unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr); void serial8250_tx_chars(struct uart_8250_port *up); unsigned int serial8250_modem_status(struct uart_8250_port *up); +void serial8250_init_port(struct uart_8250_port *up); +void serial8250_set_defaults(struct uart_8250_port *up); +void serial8250_console_write(struct uart_8250_port *up, const char *s, + unsigned int count); +int serial8250_console_setup(struct uart_port *port, char *options, bool probe); extern void serial8250_set_isa_configurator(void (*v) (int port, struct uart_port *up, -- cgit v1.3-6-gb490 From f3fb7ef3981abdca871d65e8c7d9a827225eb2ba Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 9 Jul 2015 11:50:38 +0530 Subject: tty/early: make serial8250_early_{in,out} static again Commit ed71871bed719 ("tty/8250_early: Turn serial_in/serial_out into weak symbols") made these routines weak to allow platform specific Big endian override However recent updates to core, specifically ebc5e20082 ("serial: of_serial: Support big-endian register accesses") and 6e63be3fee14 ("serial: earlycon: Add support for big-endian MMIO accesses") means that round about way to overide the early serial accessors is no longer needed. Cc: Jiri Slaby Cc: Peter Hurley Cc: Rob Herring Cc: Kevin Cernekee Acked-by: Noam Camus Signed-off-by: Vineet Gupta Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_early.c | 4 ++-- include/linux/serial_8250.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 771dda29a0f8..faed05f25bc2 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -35,7 +35,7 @@ #include #include -unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset) +static unsigned int __init serial8250_early_in(struct uart_port *port, int offset) { switch (port->iotype) { case UPIO_MEM: @@ -51,7 +51,7 @@ unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offse } } -void __weak __init serial8250_early_out(struct uart_port *port, int offset, int value) +static void __init serial8250_early_out(struct uart_port *port, int offset, int value) { switch (port->iotype) { case UPIO_MEM: diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 7f156bde38d9..faa0e0370ce7 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -136,8 +136,6 @@ void serial8250_resume_port(int line); extern int early_serial_setup(struct uart_port *port); -extern unsigned int serial8250_early_in(struct uart_port *port, int offset); -extern void serial8250_early_out(struct uart_port *port, int offset, int value); extern int early_serial8250_setup(struct earlycon_device *device, const char *options); extern void serial8250_do_set_termios(struct uart_port *port, -- cgit v1.3-6-gb490 From ee3ad90be5ec5e94a45aac597a23b1050cd4f1b0 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 12 Jul 2015 21:11:31 -0400 Subject: serial: 8250: Defer interrupt enable until fifos enabled An already-active sender can swamp the interrupt handler with "too much work" if the rx interrupts are enabled when the fifo is disabled and operating in single-byte mode. Defer rx and line status interrupt enable until after the fifos are enabled in set_termios(), but at least initialize the shadow IER value with the interrupts which will be enabled. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 4dc143eee086..de6655d50c37 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2002,12 +2002,11 @@ dont_test_tx_en: } /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. + * Set the IER shadow for rx interrupts but defer actual interrupt + * enable until after the FIFOs are enabled; otherwise, an already- + * active sender can swamp the interrupt handler with "too much work". */ up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_port_out(port, UART_IER, up->ier); if (port->flags & UPF_FOURPORT) { unsigned int icp; -- cgit v1.3-6-gb490 From da891641b6c92e260966dfce3dd93111d08656c8 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Thu, 16 Jul 2015 10:29:13 +0200 Subject: serial: 8250: Do XR17V35X specific wakeup in serial8250_do_startup The XR17V35X UART needs the ECB bit set in its XR_EFR register to enable access to IER [7:5], ISR [5:4], FCR[5:4], MCR[7:5], and MSR [7:0]. Also reset the IER register to mask interrupts after access to all bits of this register has been enabled. This makes my 8-port XR17V35X working with the in-kernel serial driver. Cc: Joe Schultz Signed-off-by: Joerg Roedel Reviewed-by: Peter Hurley Reviewed-by: Michael Welling Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index de6655d50c37..54e6c8ddef5d 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1834,6 +1834,21 @@ int serial8250_do_startup(struct uart_port *port) */ enable_rsa(up); #endif + + if (port->type == PORT_XR17V35X) { + /* + * First enable access to IER [7:5], ISR [5:4], FCR [5:4], + * MCR [7:5] and MSR [7:0] + */ + serial_port_out(port, UART_XR_EFR, UART_EFR_ECB); + + /* + * Make sure all interrups are masked until initialization is + * complete and the FIFOs are cleared + */ + serial_port_out(port, UART_IER, 0); + } + /* * Clear the FIFO buffers and disable them. * (they will be reenabled in set_termios()) -- cgit v1.3-6-gb490 From 6719693ca2efb0f04654d05768ee299e87e1694b Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Sun, 12 Jul 2015 18:51:52 -0400 Subject: tty: add missing rcu_read_lock for task_pgrp task_pgrp requires an rcu or tasklist lock to be obtained if the returned pid is to be dereferenced, which kill_pgrp does. Obtain an RCU lock for the duration of use. Signed-off-by: Patrick Donnelly Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 15 ++++++++++++--- drivers/tty/tty_io.c | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index c9c27f69e101..de67b2c88bfc 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2137,6 +2137,8 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *, static int job_control(struct tty_struct *tty, struct file *file) { + struct pid *pgrp; + /* Job control check -- must be done at start and after every sleep (POSIX.1 7.1.1.4). */ /* NOTE: not yet done after every sleep pending a thorough @@ -2146,18 +2148,25 @@ static int job_control(struct tty_struct *tty, struct file *file) current->signal->tty != tty) return 0; + rcu_read_lock(); + pgrp = task_pgrp(current); + spin_lock_irq(&tty->ctrl_lock); if (!tty->pgrp) printk(KERN_ERR "n_tty_read: no tty->pgrp!\n"); - else if (task_pgrp(current) != tty->pgrp) { + else if (pgrp != tty->pgrp) { spin_unlock_irq(&tty->ctrl_lock); - if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) + if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) { + rcu_read_unlock(); return -EIO; - kill_pgrp(task_pgrp(current), SIGTTIN, 1); + } + kill_pgrp(pgrp, SIGTTIN, 1); + rcu_read_unlock(); set_thread_flag(TIF_SIGPENDING); return -ERESTARTSYS; } spin_unlock_irq(&tty->ctrl_lock); + rcu_read_unlock(); return 0; } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 57fc6ee12332..6bdfb98bf020 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -388,33 +388,40 @@ EXPORT_SYMBOL_GPL(tty_find_polling_driver); int tty_check_change(struct tty_struct *tty) { unsigned long flags; + struct pid *pgrp; int ret = 0; if (current->signal->tty != tty) return 0; + rcu_read_lock(); + pgrp = task_pgrp(current); + spin_lock_irqsave(&tty->ctrl_lock, flags); if (!tty->pgrp) { printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n"); goto out_unlock; } - if (task_pgrp(current) == tty->pgrp) + if (pgrp == tty->pgrp) goto out_unlock; spin_unlock_irqrestore(&tty->ctrl_lock, flags); + if (is_ignored(SIGTTOU)) - goto out; + goto out_rcuunlock; if (is_current_pgrp_orphaned()) { ret = -EIO; - goto out; + goto out_rcuunlock; } - kill_pgrp(task_pgrp(current), SIGTTOU, 1); + kill_pgrp(pgrp, SIGTTOU, 1); + rcu_read_unlock(); set_thread_flag(TIF_SIGPENDING); ret = -ERESTARTSYS; -out: return ret; out_unlock: spin_unlock_irqrestore(&tty->ctrl_lock, flags); +out_rcuunlock: + rcu_read_unlock(); return ret; } -- cgit v1.3-6-gb490 From 4e7decdaaa67b287d6a13de8dedced68f1d7d716 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 2 Jul 2015 15:18:11 +0200 Subject: tty/serial: at91: remove bunch of macros to access UART registers This patch replaces the UART_PUT_*, resp. UART_GET_*, macros by atmel_uart_writel(), resp. atmel_uart_readl(), inline function calls. Signed-off-by: Cyrille Pitchen Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 313 +++++++++++++++++++------------------- 1 file changed, 159 insertions(+), 154 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 2a8f528153e7..e7c337de31d1 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -88,37 +88,6 @@ static void atmel_stop_rx(struct uart_port *port); #define ATMEL_ISR_PASS_LIMIT 256 -/* UART registers. CR is write-only, hence no GET macro */ -#define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR) -#define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR) -#define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR) -#define UART_PUT_IER(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IER) -#define UART_PUT_IDR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IDR) -#define UART_GET_IMR(port) __raw_readl((port)->membase + ATMEL_US_IMR) -#define UART_GET_CSR(port) __raw_readl((port)->membase + ATMEL_US_CSR) -#define UART_GET_CHAR(port) __raw_readl((port)->membase + ATMEL_US_RHR) -#define UART_PUT_CHAR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_THR) -#define UART_GET_BRGR(port) __raw_readl((port)->membase + ATMEL_US_BRGR) -#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR) -#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR) -#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR) -#define UART_GET_IP_NAME(port) __raw_readl((port)->membase + ATMEL_US_NAME) -#define UART_GET_IP_VERSION(port) __raw_readl((port)->membase + ATMEL_US_VERSION) - - /* PDC registers */ -#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) -#define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) - -#define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR) -#define UART_GET_RPR(port) __raw_readl((port)->membase + ATMEL_PDC_RPR) -#define UART_PUT_RCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RCR) -#define UART_PUT_RNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR) -#define UART_PUT_RNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR) - -#define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR) -#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) -#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR) - struct atmel_dma_buffer { unsigned char *buf; dma_addr_t dma_addr; @@ -212,6 +181,16 @@ to_atmel_uart_port(struct uart_port *uart) return container_of(uart, struct atmel_uart_port, uart); } +static inline u32 atmel_uart_readl(struct uart_port *port, u32 reg) +{ + return __raw_readl(port->membase + reg); +} + +static inline void atmel_uart_writel(struct uart_port *port, u32 reg, u32 value) +{ + __raw_writel(value, port->membase + reg); +} + #ifdef CONFIG_SERIAL_ATMEL_PDC static bool atmel_use_pdc_rx(struct uart_port *port) { @@ -257,7 +236,7 @@ static unsigned int atmel_get_lines_status(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int status, ret = 0; - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); mctrl_gpio_get(atmel_port->gpios, &ret); @@ -304,9 +283,9 @@ static int atmel_config_rs485(struct uart_port *port, unsigned int mode; /* Disable interrupts */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); - mode = UART_GET_MR(port); + mode = atmel_uart_readl(port, ATMEL_US_MR); /* Resetting serial mode to RS232 (0x0) */ mode &= ~ATMEL_US_USMODE; @@ -316,7 +295,8 @@ static int atmel_config_rs485(struct uart_port *port, if (rs485conf->flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; - UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); + atmel_uart_writel(port, ATMEL_US_TTGR, + rs485conf->delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else { dev_dbg(port->dev, "Setting UART to RS232\n"); @@ -326,10 +306,10 @@ static int atmel_config_rs485(struct uart_port *port, else atmel_port->tx_done_mask = ATMEL_US_TXRDY; } - UART_PUT_MR(port, mode); + atmel_uart_writel(port, ATMEL_US_MR, mode); /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); return 0; } @@ -339,7 +319,9 @@ static int atmel_config_rs485(struct uart_port *port, */ static u_int atmel_tx_empty(struct uart_port *port) { - return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0; + return (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXEMPTY) ? + TIOCSER_TEMT : + 0; } /* @@ -348,13 +330,14 @@ static u_int atmel_tx_empty(struct uart_port *port) static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) { unsigned int control = 0; - unsigned int mode = UART_GET_MR(port); + unsigned int mode = atmel_uart_readl(port, ATMEL_US_MR); unsigned int rts_paused, rts_ready; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); /* override mode to RS485 if needed, otherwise keep the current mode */ if (port->rs485.flags & SER_RS485_ENABLED) { - UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); + atmel_uart_writel(port, ATMEL_US_TTGR, + port->rs485.delay_rts_after_send); mode &= ~ATMEL_US_USMODE; mode |= ATMEL_US_USMODE_RS485; } @@ -384,7 +367,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) else control |= ATMEL_US_DTRDIS; - UART_PUT_CR(port, control); + atmel_uart_writel(port, ATMEL_US_CR, control); mctrl_gpio_set(atmel_port->gpios, mctrl); @@ -395,7 +378,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) else mode |= ATMEL_US_CHMODE_NORMAL; - UART_PUT_MR(port, mode); + atmel_uart_writel(port, ATMEL_US_MR, mode); } /* @@ -406,7 +389,7 @@ static u_int atmel_get_mctrl(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int ret = 0, status; - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); /* * The control signals are active low. @@ -432,10 +415,10 @@ static void atmel_stop_tx(struct uart_port *port) if (atmel_use_pdc_tx(port)) { /* disable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); } /* Disable interrupts */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); if ((port->rs485.flags & SER_RS485_ENABLED) && !(port->rs485.flags & SER_RS485_RX_DURING_TX)) @@ -450,7 +433,7 @@ static void atmel_start_tx(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (atmel_use_pdc_tx(port)) { - if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN) + if (atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN) /* The transmitter is already running. Yes, we really need this.*/ return; @@ -460,10 +443,10 @@ static void atmel_start_tx(struct uart_port *port) atmel_stop_rx(port); /* re-enable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); } /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); } /* @@ -471,17 +454,19 @@ static void atmel_start_tx(struct uart_port *port) */ static void atmel_start_rx(struct uart_port *port) { - UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */ + /* reset status and receiver */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); - UART_PUT_CR(port, ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXEN); if (atmel_use_pdc_rx(port)) { /* enable PDC controller */ - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | - port->read_status_mask); - UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | + port->read_status_mask); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); } else { - UART_PUT_IER(port, ATMEL_US_RXRDY); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_RXRDY); } } @@ -490,15 +475,16 @@ static void atmel_start_rx(struct uart_port *port) */ static void atmel_stop_rx(struct uart_port *port) { - UART_PUT_CR(port, ATMEL_US_RXDIS); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXDIS); if (atmel_use_pdc_rx(port)) { /* disable PDC receive */ - UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS); - UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | - port->read_status_mask); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | + port->read_status_mask); } else { - UART_PUT_IDR(port, ATMEL_US_RXRDY); + atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_RXRDY); } } @@ -538,7 +524,7 @@ static void atmel_enable_ms(struct uart_port *port) else ier |= ATMEL_US_DCDIC; - UART_PUT_IER(port, ier); + atmel_uart_writel(port, ATMEL_US_IER, ier); } /* @@ -577,7 +563,7 @@ static void atmel_disable_ms(struct uart_port *port) else idr |= ATMEL_US_DCDIC; - UART_PUT_IDR(port, idr); + atmel_uart_writel(port, ATMEL_US_IDR, idr); } /* @@ -586,9 +572,11 @@ static void atmel_disable_ms(struct uart_port *port) static void atmel_break_ctl(struct uart_port *port, int break_state) { if (break_state != 0) - UART_PUT_CR(port, ATMEL_US_STTBRK); /* start break */ + /* start break */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTBRK); else - UART_PUT_CR(port, ATMEL_US_STPBRK); /* stop break */ + /* stop break */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STPBRK); } /* @@ -622,7 +610,7 @@ atmel_buffer_rx_char(struct uart_port *port, unsigned int status, static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status) { /* clear error */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); if (status & ATMEL_US_RXBRK) { /* ignore side-effect */ @@ -645,9 +633,9 @@ static void atmel_rx_chars(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int status, ch; - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); while (status & ATMEL_US_RXRDY) { - ch = UART_GET_CHAR(port); + ch = atmel_uart_readl(port, ATMEL_US_RHR); /* * note that the error handling code is @@ -658,12 +646,13 @@ static void atmel_rx_chars(struct uart_port *port) || atmel_port->break_active)) { /* clear error */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); if (status & ATMEL_US_RXBRK && !atmel_port->break_active) { atmel_port->break_active = 1; - UART_PUT_IER(port, ATMEL_US_RXBRK); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_RXBRK); } else { /* * This is either the end-of-break @@ -672,14 +661,15 @@ static void atmel_rx_chars(struct uart_port *port) * being set. In both cases, the next * RXBRK will indicate start-of-break. */ - UART_PUT_IDR(port, ATMEL_US_RXBRK); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_RXBRK); status &= ~ATMEL_US_RXBRK; atmel_port->break_active = 0; } } atmel_buffer_rx_char(port, status, ch); - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); } tasklet_schedule(&atmel_port->tasklet); @@ -694,16 +684,18 @@ static void atmel_tx_chars(struct uart_port *port) struct circ_buf *xmit = &port->state->xmit; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) { - UART_PUT_CHAR(port, port->x_char); + if (port->x_char && + (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask)) { + atmel_uart_writel(port, ATMEL_US_THR, port->x_char); port->icount.tx++; port->x_char = 0; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return; - while (UART_GET_CSR(port) & atmel_port->tx_done_mask) { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); + while (atmel_uart_readl(port, ATMEL_US_CSR) & + atmel_port->tx_done_mask) { + atmel_uart_writel(port, ATMEL_US_THR, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) @@ -715,7 +707,8 @@ static void atmel_tx_chars(struct uart_port *port) if (!uart_circ_empty(xmit)) /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, + atmel_port->tx_done_mask); } static void atmel_complete_tx_dma(void *arg) @@ -935,14 +928,14 @@ static void atmel_rx_from_dma(struct uart_port *port) /* Reset the UART timeout early so that we don't miss one */ - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); dmastat = dmaengine_tx_status(chan, atmel_port->cookie_rx, &state); /* Restart a new tasklet if DMA status is error */ if (dmastat == DMA_ERROR) { dev_dbg(port->dev, "Get residue error, restart tasklet\n"); - UART_PUT_IER(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); tasklet_schedule(&atmel_port->tasklet); return; } @@ -1008,7 +1001,7 @@ static void atmel_rx_from_dma(struct uart_port *port) tty_flip_buffer_push(tport); spin_lock(&port->lock); - UART_PUT_IER(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); } static int atmel_prepare_rx_dma(struct uart_port *port) @@ -1118,8 +1111,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) * the moment. */ if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { - UART_PUT_IDR(port, (ATMEL_US_ENDRX - | ATMEL_US_TIMEOUT)); + atmel_uart_writel(port, ATMEL_US_IDR, + (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)); tasklet_schedule(&atmel_port->tasklet); } @@ -1130,7 +1123,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) if (atmel_use_dma_rx(port)) { if (pending & ATMEL_US_TIMEOUT) { - UART_PUT_IDR(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_TIMEOUT); tasklet_schedule(&atmel_port->tasklet); } } @@ -1143,8 +1137,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) * End of break detected. If it came along with a * character, atmel_rx_chars will handle it. */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, ATMEL_US_RXBRK); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_RXBRK); atmel_port->break_active = 0; } } @@ -1159,7 +1153,8 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending) if (pending & atmel_port->tx_done_mask) { /* Either PDC or interrupt transmission */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IDR, + atmel_port->tx_done_mask); tasklet_schedule(&atmel_port->tasklet); } } @@ -1197,7 +1192,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) do { status = atmel_get_lines_status(port); - mask = UART_GET_IMR(port); + mask = atmel_uart_readl(port, ATMEL_US_IMR); pending = status & mask; if (!gpio_handled) { /* @@ -1223,7 +1218,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) if (atmel_port->suspended) { atmel_port->pending |= pending; atmel_port->pending_status = status; - UART_PUT_IDR(port, mask); + atmel_uart_writel(port, ATMEL_US_IDR, mask); pm_system_wakeup(); break; } @@ -1260,7 +1255,7 @@ static void atmel_tx_pdc(struct uart_port *port) int count; /* nothing left to transmit? */ - if (UART_GET_TCR(port)) + if (atmel_uart_readl(port, ATMEL_PDC_TCR)) return; xmit->tail += pdc->ofs; @@ -1272,7 +1267,7 @@ static void atmel_tx_pdc(struct uart_port *port) /* more to transmit - setup next transfer */ /* disable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { dma_sync_single_for_device(port->dev, @@ -1283,12 +1278,14 @@ static void atmel_tx_pdc(struct uart_port *port) count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); pdc->ofs = count; - UART_PUT_TPR(port, pdc->dma_addr + xmit->tail); - UART_PUT_TCR(port, count); + atmel_uart_writel(port, ATMEL_PDC_TPR, + pdc->dma_addr + xmit->tail); + atmel_uart_writel(port, ATMEL_PDC_TCR, count); /* re-enable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, + atmel_port->tx_done_mask); } else { if ((port->rs485.flags & SER_RS485_ENABLED) && !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { @@ -1414,10 +1411,10 @@ static void atmel_rx_from_pdc(struct uart_port *port) do { /* Reset the UART timeout early so that we don't miss one */ - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); pdc = &atmel_port->pdc_rx[rx_idx]; - head = UART_GET_RPR(port) - pdc->dma_addr; + head = atmel_uart_readl(port, ATMEL_PDC_RPR) - pdc->dma_addr; tail = pdc->ofs; /* If the PDC has switched buffers, RPR won't contain @@ -1460,8 +1457,8 @@ static void atmel_rx_from_pdc(struct uart_port *port) */ if (head >= pdc->dma_size) { pdc->ofs = 0; - UART_PUT_RNPR(port, pdc->dma_addr); - UART_PUT_RNCR(port, pdc->dma_size); + atmel_uart_writel(port, ATMEL_PDC_RNPR, pdc->dma_addr); + atmel_uart_writel(port, ATMEL_PDC_RNCR, pdc->dma_size); rx_idx = !rx_idx; atmel_port->pdc_rx_idx = rx_idx; @@ -1476,7 +1473,8 @@ static void atmel_rx_from_pdc(struct uart_port *port) tty_flip_buffer_push(tport); spin_lock(&port->lock); - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); } static int atmel_prepare_rx_pdc(struct uart_port *port) @@ -1509,11 +1507,12 @@ static int atmel_prepare_rx_pdc(struct uart_port *port) atmel_port->pdc_rx_idx = 0; - UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr); - UART_PUT_RCR(port, PDC_BUFFER_SIZE); + atmel_uart_writel(port, ATMEL_PDC_RPR, atmel_port->pdc_rx[0].dma_addr); + atmel_uart_writel(port, ATMEL_PDC_RCR, PDC_BUFFER_SIZE); - UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr); - UART_PUT_RNCR(port, PDC_BUFFER_SIZE); + atmel_uart_writel(port, ATMEL_PDC_RNPR, + atmel_port->pdc_rx[1].dma_addr); + atmel_uart_writel(port, ATMEL_PDC_RNCR, PDC_BUFFER_SIZE); return 0; } @@ -1667,7 +1666,7 @@ static void atmel_set_ops(struct uart_port *port) static void atmel_get_ip_name(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - int name = UART_GET_IP_NAME(port); + int name = atmel_uart_readl(port, ATMEL_US_NAME); u32 version; int usart, uart; /* usart and uart ascii */ @@ -1684,7 +1683,7 @@ static void atmel_get_ip_name(struct uart_port *port) atmel_port->is_usart = false; } else { /* fallback for older SoCs: use version field */ - version = UART_GET_IP_VERSION(port); + version = atmel_uart_readl(port, ATMEL_US_VERSION); switch (version) { case 0x302: case 0x10213: @@ -1756,7 +1755,7 @@ static int atmel_startup(struct uart_port *port) * request_irq() is called we could get stuck trying to * handle an unexpected interrupt */ - UART_PUT_IDR(port, -1); + atmel_uart_writel(port, ATMEL_US_IDR, -1); atmel_port->ms_irq_enabled = false; /* @@ -1804,9 +1803,9 @@ static int atmel_startup(struct uart_port *port) /* * Finally, enable the serial port */ - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); /* enable xmit & rcvr */ - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); setup_timer(&atmel_port->uart_timer, atmel_uart_timer_callback, @@ -1819,13 +1818,14 @@ static int atmel_startup(struct uart_port *port) jiffies + uart_poll_timeout(port)); /* set USART timeout */ } else { - UART_PUT_RTOR(port, PDC_RX_TIMEOUT); - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); } /* enable PDC controller */ - UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); } else if (atmel_use_dma_rx(port)) { /* set UART timeout */ if (!atmel_port->is_usart) { @@ -1833,14 +1833,15 @@ static int atmel_startup(struct uart_port *port) jiffies + uart_poll_timeout(port)); /* set USART timeout */ } else { - UART_PUT_RTOR(port, PDC_RX_TIMEOUT); - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); - UART_PUT_IER(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_TIMEOUT); } } else { /* enable receive only */ - UART_PUT_IER(port, ATMEL_US_RXRDY); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_RXRDY); } return 0; @@ -1860,7 +1861,7 @@ static void atmel_flush_buffer(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (atmel_use_pdc_tx(port)) { - UART_PUT_TCR(port, 0); + atmel_uart_writel(port, ATMEL_PDC_TCR, 0); atmel_port->pdc_tx.ofs = 0; } } @@ -1892,8 +1893,8 @@ static void atmel_shutdown(struct uart_port *port) atmel_stop_rx(port); atmel_stop_tx(port); - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, -1); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_IDR, -1); /* @@ -1938,12 +1939,12 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, clk_prepare_enable(atmel_port->clk); /* re-enable interrupts if we disabled some on suspend */ - UART_PUT_IER(port, atmel_port->backup_imr); + atmel_uart_writel(port, ATMEL_US_IER, atmel_port->backup_imr); break; case 3: /* Back up the interrupt mask and disable all interrupts */ - atmel_port->backup_imr = UART_GET_IMR(port); - UART_PUT_IDR(port, -1); + atmel_port->backup_imr = atmel_uart_readl(port, ATMEL_US_IMR); + atmel_uart_writel(port, ATMEL_US_IDR, -1); /* * Disable the peripheral clock for this serial port. @@ -1966,7 +1967,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int old_mode, mode, imr, quot, baud; /* save the current mode register */ - mode = old_mode = UART_GET_MR(port); + mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR); /* reset the mode, clock divisor, parity, stop bits and data size */ mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | @@ -2025,7 +2026,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, if (atmel_use_pdc_rx(port)) /* need to enable error interrupts */ - UART_PUT_IER(port, port->read_status_mask); + atmel_uart_writel(port, ATMEL_US_IER, port->read_status_mask); /* * Characters to ignore @@ -2052,15 +2053,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, * transmitter is empty if requested by the caller, so there's * no need to wait for it here. */ - imr = UART_GET_IMR(port); - UART_PUT_IDR(port, -1); + imr = atmel_uart_readl(port, ATMEL_US_IMR); + atmel_uart_writel(port, ATMEL_US_IDR, -1); /* disable receiver and transmitter */ - UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXDIS); /* mode */ if (port->rs485.flags & SER_RS485_ENABLED) { - UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); + atmel_uart_writel(port, ATMEL_US_TTGR, + port->rs485.delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else if (termios->c_cflag & CRTSCTS) { /* RS232 with hardware handshake (RTS/CTS) */ @@ -2071,7 +2073,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, } /* set the mode, clock divisor, parity, stop bits and data size */ - UART_PUT_MR(port, mode); + atmel_uart_writel(port, ATMEL_US_MR, mode); /* * when switching the mode, set the RTS line state according to the @@ -2088,16 +2090,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, rts_state = ATMEL_US_RTSEN; } - UART_PUT_CR(port, rts_state); + atmel_uart_writel(port, ATMEL_US_CR, rts_state); } /* set the baud rate */ - UART_PUT_BRGR(port, quot); - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_BRGR, quot); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); /* restore interrupts */ - UART_PUT_IER(port, imr); + atmel_uart_writel(port, ATMEL_US_IER, imr); /* CTS flow-control and modem-status interrupts */ if (UART_ENABLE_MS(port, termios->c_cflag)) @@ -2208,18 +2210,18 @@ static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser) #ifdef CONFIG_CONSOLE_POLL static int atmel_poll_get_char(struct uart_port *port) { - while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_RXRDY)) cpu_relax(); - return UART_GET_CHAR(port); + return atmel_uart_readl(port, ATMEL_US_RHR); } static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) { - while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - UART_PUT_CHAR(port, ch); + atmel_uart_writel(port, ATMEL_US_THR, ch); } #endif @@ -2324,9 +2326,9 @@ struct platform_device *atmel_default_console_device; /* the serial console devi #ifdef CONFIG_SERIAL_ATMEL_CONSOLE static void atmel_console_putchar(struct uart_port *port, int ch) { - while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - UART_PUT_CHAR(port, ch); + atmel_uart_writel(port, ATMEL_US_THR, ch); } /* @@ -2342,12 +2344,13 @@ static void atmel_console_write(struct console *co, const char *s, u_int count) /* * First, save IMR and then disable interrupts */ - imr = UART_GET_IMR(port); - UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask); + imr = atmel_uart_readl(port, ATMEL_US_IMR); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_RXRDY | atmel_port->tx_done_mask); /* Store PDC transmit status and disable it */ - pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN; - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + pdc_tx = atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN; + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); uart_console_write(port, s, count, atmel_console_putchar); @@ -2356,15 +2359,15 @@ static void atmel_console_write(struct console *co, const char *s, u_int count) * and restore IMR */ do { - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); } while (!(status & ATMEL_US_TXRDY)); /* Restore PDC transmit status */ if (pdc_tx) - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); /* set interrupts back the way they were */ - UART_PUT_IER(port, imr); + atmel_uart_writel(port, ATMEL_US_IER, imr); } /* @@ -2380,17 +2383,17 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud, * If the baud rate generator isn't running, the port wasn't * initialized by the boot loader. */ - quot = UART_GET_BRGR(port) & ATMEL_US_CD; + quot = atmel_uart_readl(port, ATMEL_US_BRGR) & ATMEL_US_CD; if (!quot) return; - mr = UART_GET_MR(port) & ATMEL_US_CHRL; + mr = atmel_uart_readl(port, ATMEL_US_MR) & ATMEL_US_CHRL; if (mr == ATMEL_US_CHRL_8) *bits = 8; else *bits = 7; - mr = UART_GET_MR(port) & ATMEL_US_PAR; + mr = atmel_uart_readl(port, ATMEL_US_MR) & ATMEL_US_PAR; if (mr == ATMEL_US_PAR_EVEN) *parity = 'e'; else if (mr == ATMEL_US_PAR_ODD) @@ -2423,9 +2426,9 @@ static int __init atmel_console_setup(struct console *co, char *options) if (ret) return ret; - UART_PUT_IDR(port, -1); - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_IDR, -1); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -2532,7 +2535,8 @@ static int atmel_serial_suspend(struct platform_device *pdev, if (atmel_is_console_port(port) && console_suspend_enabled) { /* Drain the TX shifter */ - while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & + ATMEL_US_TXEMPTY)) cpu_relax(); } @@ -2684,8 +2688,9 @@ static int atmel_serial_probe(struct platform_device *pdev) clk_prepare_enable(port->clk); if (rs485_enabled) { - UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL); - UART_PUT_CR(&port->uart, ATMEL_US_RTSEN); + atmel_uart_writel(&port->uart, ATMEL_US_MR, + ATMEL_US_USMODE_NORMAL); + atmel_uart_writel(&port->uart, ATMEL_US_CR, ATMEL_US_RTSEN); } /* -- cgit v1.3-6-gb490 From b5199d46817766c95ef759684658cd8e359c6d27 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 2 Jul 2015 15:18:12 +0200 Subject: tty/serial: at91: add support to FIFOs Depending on the hardware, TX and RX FIFOs may be available. The RX FIFO can avoid receive overruns, especially when DMA transfers are not used to read data from the Receive Holding Register. For heavy system load, The CPU is likely not be able to fetch data fast enough from the RHR. In addition, the RX FIFO can supersede the DMA/PDC to control the RTS line when the Hardware Handshaking mode is enabled. Two thresholds are to be set for that purpose: - When the number of data in the RX FIFO crosses and becomes lower than or equal to the low threshold, the RTS line is set to low level: the remote peer is requested to send data. - When the number of data in the RX FIFO crosses and becomes greater than or equal to the high threshold, the RTS line is set to high level: the remote peer should stop sending new data. - low threshold <= high threshold Once these two thresholds are set properly, this new feature is enabled by setting the FIFO RTS Control bit of the FIFO Mode Register. FIFOs also introduce a new multiple data mode: the USART works either in multiple data mode or in single data (legacy) mode. If MODE9 bit is set into the Mode Register or if USMODE is set to either LIN_MASTER, LIN_SLAVE or LON_MODE, FIFOs operate in single data mode. Otherwise, they operate in multiple data mode. In this new multiple data mode, accesses to the Receive Holding Register or Transmit Holding Register slightly change. Since this driver implements neither the 9bit data feature (MODE9 bit set into the Mode Register) nor LIN modes, the USART works in multiple data mode whenever FIFOs are available and enabled. We also assume that data are 8bit wide. In single data mode, 32bit access CAN be used to read a single data from RHR or write a single data into THR. However in multiple data mode, a 32bit access to RHR now allows us to read four consecutive data from RX FIFO. Also a 32bit access to THR now allows to write four consecutive data into TX FIFO. So we MUST use 8bit access whenever only one data have to be read/written at a time. Signed-off-by: Cyrille Pitchen Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 100 +++++++++++++++++++++++++++++++++++--- include/linux/atmel_serial.h | 36 ++++++++++++++ 2 files changed, 130 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index e7c337de31d1..87de21f0c7a3 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -56,6 +56,15 @@ /* Revisit: We should calculate this based on the actual port settings */ #define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ +/* The minium number of data FIFOs should be able to contain */ +#define ATMEL_MIN_FIFO_SIZE 8 +/* + * These two offsets are substracted from the RX FIFO size to define the RTS + * high and low thresholds + */ +#define ATMEL_RTS_HIGH_OFFSET 16 +#define ATMEL_RTS_LOW_OFFSET 20 + #if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif @@ -141,6 +150,9 @@ struct atmel_uart_port { struct mctrl_gpios *gpios; int gpio_irq[UART_GPIO_MAX]; unsigned int tx_done_mask; + u32 fifo_size; + u32 rts_high; + u32 rts_low; bool ms_irq_enabled; bool is_usart; /* usart or uart */ struct timer_list uart_timer; /* uart timer */ @@ -191,6 +203,16 @@ static inline void atmel_uart_writel(struct uart_port *port, u32 reg, u32 value) __raw_writel(value, port->membase + reg); } +static inline u8 atmel_uart_readb(struct uart_port *port, u32 reg) +{ + return __raw_readb(port->membase + reg); +} + +static inline void atmel_uart_writeb(struct uart_port *port, u32 reg, u8 value) +{ + __raw_writeb(value, port->membase + reg); +} + #ifdef CONFIG_SERIAL_ATMEL_PDC static bool atmel_use_pdc_rx(struct uart_port *port) { @@ -635,7 +657,7 @@ static void atmel_rx_chars(struct uart_port *port) status = atmel_uart_readl(port, ATMEL_US_CSR); while (status & ATMEL_US_RXRDY) { - ch = atmel_uart_readl(port, ATMEL_US_RHR); + ch = atmel_uart_readb(port, ATMEL_US_RHR); /* * note that the error handling code is @@ -686,7 +708,7 @@ static void atmel_tx_chars(struct uart_port *port) if (port->x_char && (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask)) { - atmel_uart_writel(port, ATMEL_US_THR, port->x_char); + atmel_uart_writeb(port, ATMEL_US_THR, port->x_char); port->icount.tx++; port->x_char = 0; } @@ -695,7 +717,7 @@ static void atmel_tx_chars(struct uart_port *port) while (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask) { - atmel_uart_writel(port, ATMEL_US_THR, xmit->buf[xmit->tail]); + atmel_uart_writeb(port, ATMEL_US_THR, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) @@ -1796,6 +1818,29 @@ static int atmel_startup(struct uart_port *port) atmel_set_ops(port); } + /* + * Enable FIFO when available + */ + if (atmel_port->fifo_size) { + unsigned int txrdym = ATMEL_US_ONE_DATA; + unsigned int rxrdym = ATMEL_US_ONE_DATA; + unsigned int fmr; + + atmel_uart_writel(port, ATMEL_US_CR, + ATMEL_US_FIFOEN | + ATMEL_US_RXFCLR | + ATMEL_US_TXFLCLR); + + fmr = ATMEL_US_TXRDYM(txrdym) | ATMEL_US_RXRDYM(rxrdym); + if (atmel_port->rts_high && + atmel_port->rts_low) + fmr |= ATMEL_US_FRTSC | + ATMEL_US_RXFTHRES(atmel_port->rts_high) | + ATMEL_US_RXFTHRES2(atmel_port->rts_low); + + atmel_uart_writel(port, ATMEL_US_FMR, fmr); + } + /* Save current CSR for comparison in atmel_tasklet_func() */ atmel_port->irq_status_prev = atmel_get_lines_status(port); atmel_port->irq_status = atmel_port->irq_status_prev; @@ -2213,7 +2258,7 @@ static int atmel_poll_get_char(struct uart_port *port) while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_RXRDY)) cpu_relax(); - return atmel_uart_readl(port, ATMEL_US_RHR); + return atmel_uart_readb(port, ATMEL_US_RHR); } static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) @@ -2221,7 +2266,7 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - atmel_uart_writel(port, ATMEL_US_THR, ch); + atmel_uart_writeb(port, ATMEL_US_THR, ch); } #endif @@ -2328,7 +2373,7 @@ static void atmel_console_putchar(struct uart_port *port, int ch) { while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - atmel_uart_writel(port, ATMEL_US_THR, ch); + atmel_uart_writeb(port, ATMEL_US_THR, ch); } /* @@ -2603,6 +2648,48 @@ static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev) return 0; } +static void atmel_serial_probe_fifos(struct atmel_uart_port *port, + struct platform_device *pdev) +{ + port->fifo_size = 0; + port->rts_low = 0; + port->rts_high = 0; + + if (of_property_read_u32(pdev->dev.of_node, + "atmel,fifo-size", + &port->fifo_size)) + return; + + if (!port->fifo_size) + return; + + if (port->fifo_size < ATMEL_MIN_FIFO_SIZE) { + port->fifo_size = 0; + dev_err(&pdev->dev, "Invalid FIFO size\n"); + return; + } + + /* + * 0 <= rts_low <= rts_high <= fifo_size + * Once their CTS line asserted by the remote peer, some x86 UARTs tend + * to flush their internal TX FIFO, commonly up to 16 data, before + * actually stopping to send new data. So we try to set the RTS High + * Threshold to a reasonably high value respecting this 16 data + * empirical rule when possible. + */ + port->rts_high = max_t(int, port->fifo_size >> 1, + port->fifo_size - ATMEL_RTS_HIGH_OFFSET); + port->rts_low = max_t(int, port->fifo_size >> 2, + port->fifo_size - ATMEL_RTS_LOW_OFFSET); + + dev_info(&pdev->dev, "Using FIFO (%u data)\n", + port->fifo_size); + dev_dbg(&pdev->dev, "RTS High Threshold : %2u data\n", + port->rts_high); + dev_dbg(&pdev->dev, "RTS Low Threshold : %2u data\n", + port->rts_low); +} + static int atmel_serial_probe(struct platform_device *pdev) { struct atmel_uart_port *port; @@ -2639,6 +2726,7 @@ static int atmel_serial_probe(struct platform_device *pdev) port = &atmel_ports[ret]; port->backup_imr = 0; port->uart.line = ret; + atmel_serial_probe_fifos(port, pdev); spin_lock_init(&port->lock_suspended); diff --git a/include/linux/atmel_serial.h b/include/linux/atmel_serial.h index c384c21d65f0..ee696d7e8a43 100644 --- a/include/linux/atmel_serial.h +++ b/include/linux/atmel_serial.h @@ -35,6 +35,11 @@ #define ATMEL_US_DTRDIS BIT(17) /* Data Terminal Ready Disable */ #define ATMEL_US_RTSEN BIT(18) /* Request To Send Enable */ #define ATMEL_US_RTSDIS BIT(19) /* Request To Send Disable */ +#define ATMEL_US_TXFCLR BIT(24) /* Transmit FIFO Clear */ +#define ATMEL_US_RXFCLR BIT(25) /* Receive FIFO Clear */ +#define ATMEL_US_TXFLCLR BIT(26) /* Transmit FIFO Lock Clear */ +#define ATMEL_US_FIFOEN BIT(30) /* FIFO enable */ +#define ATMEL_US_FIFODIS BIT(31) /* FIFO disable */ #define ATMEL_US_MR 0x04 /* Mode Register */ #define ATMEL_US_USMODE GENMASK(3, 0) /* Mode of the USART */ @@ -124,6 +129,37 @@ #define ATMEL_US_NER 0x44 /* Number of Errors Register */ #define ATMEL_US_IF 0x4c /* IrDA Filter Register */ +#define ATMEL_US_CMPR 0x90 /* Comparaison Register */ +#define ATMEL_US_FMR 0xa0 /* FIFO Mode Register */ +#define ATMEL_US_TXRDYM(data) (((data) & 0x3) << 0) /* TX Ready Mode */ +#define ATMEL_US_RXRDYM(data) (((data) & 0x3) << 4) /* RX Ready Mode */ +#define ATMEL_US_ONE_DATA 0x0 +#define ATMEL_US_TWO_DATA 0x1 +#define ATMEL_US_FOUR_DATA 0x2 +#define ATMEL_US_FRTSC BIT(7) /* FIFO RTS pin Control */ +#define ATMEL_US_TXFTHRES(thr) (((thr) & 0x3f) << 8) /* TX FIFO Threshold */ +#define ATMEL_US_RXFTHRES(thr) (((thr) & 0x3f) << 16) /* RX FIFO Threshold */ +#define ATMEL_US_RXFTHRES2(thr) (((thr) & 0x3f) << 24) /* RX FIFO Threshold2 */ + +#define ATMEL_US_FLR 0xa4 /* FIFO Level Register */ +#define ATMEL_US_TXFL(reg) (((reg) >> 0) & 0x3f) /* TX FIFO Level */ +#define ATMEL_US_RXFL(reg) (((reg) >> 16) & 0x3f) /* RX FIFO Level */ + +#define ATMEL_US_FIER 0xa8 /* FIFO Interrupt Enable Register */ +#define ATMEL_US_FIDR 0xac /* FIFO Interrupt Disable Register */ +#define ATMEL_US_FIMR 0xb0 /* FIFO Interrupt Mask Register */ +#define ATMEL_US_FESR 0xb4 /* FIFO Event Status Register */ +#define ATMEL_US_TXFEF BIT(0) /* Transmit FIFO Empty Flag */ +#define ATMEL_US_TXFFF BIT(1) /* Transmit FIFO Full Flag */ +#define ATMEL_US_TXFTHF BIT(2) /* Transmit FIFO Threshold Flag */ +#define ATMEL_US_RXFEF BIT(3) /* Receive FIFO Empty Flag */ +#define ATMEL_US_RXFFF BIT(4) /* Receive FIFO Full Flag */ +#define ATMEL_US_RXFTHF BIT(5) /* Receive FIFO Threshold Flag */ +#define ATMEL_US_TXFPTEF BIT(6) /* Transmit FIFO Pointer Error Flag */ +#define ATMEL_US_RXFPTEF BIT(7) /* Receive FIFO Pointer Error Flag */ +#define ATMEL_US_TXFLOCK BIT(8) /* Transmit FIFO Lock (FESR only) */ +#define ATMEL_US_RXFTHF2 BIT(9) /* Receive FIFO Threshold Flag 2 */ + #define ATMEL_US_NAME 0xf0 /* Ip Name */ #define ATMEL_US_VERSION 0xfc /* Ip Version */ -- cgit v1.3-6-gb490 From 5f258b3e3d223b5cb6d1753b2f9b821ba4455f81 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 2 Jul 2015 15:18:13 +0200 Subject: tty/serial: at91: use 32bit writes into TX FIFO when DMA is enabled For now this improvement is only used with TX DMA transfers. The data width must be set properly when configuring the DMA controller. Also the FIFO configuration must be set to match the DMA transfer data width: TXRDYM (Transmitter Ready Mode) and RXRDYM (Receiver Ready Mode) must be set into the FIFO Mode Register. These values are used by the USART to trigger the DMA controller. In single data mode they are not used and should be reset to 0. So the TXRDYM bits are changed to FOUR_DATA; then USART triggers the DMA controller when at least 4 data can be written into the TX FIFO througth the THR. On the other hand the RXRDYM bits are left unchanged to ONE_DATA. Atmel eXtended DMA controller allows us to set a different data width for each part of a scatter-gather transfer. So when calling dmaengine_slave_config() to configure the TX path, we just need to set dst_addr_width to the maximum data width. Then DMA writes into THR are split into up to two parts. The first part carries the first data to be sent and has a length equal to the greatest multiple of 4 (bytes) lower than or equal to the total length of the TX DMA transfer. The second part carries the trailing data (up to 3 bytes). The first part is written by the DMA into THR using 32 bit accesses, whereas 8bit accesses are used for the second part. Signed-off-by: Cyrille Pitchen Acked-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 66 ++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 87de21f0c7a3..e91b3b2f0590 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -144,6 +144,7 @@ struct atmel_uart_port { unsigned int irq_status; unsigned int irq_status_prev; unsigned int status_change; + unsigned int tx_len; struct circ_buf rx_ring; @@ -745,10 +746,10 @@ static void atmel_complete_tx_dma(void *arg) if (chan) dmaengine_terminate_all(chan); - xmit->tail += sg_dma_len(&atmel_port->sg_tx); + xmit->tail += atmel_port->tx_len; xmit->tail &= UART_XMIT_SIZE - 1; - port->icount.tx += sg_dma_len(&atmel_port->sg_tx); + port->icount.tx += atmel_port->tx_len; spin_lock_irq(&atmel_port->lock_tx); async_tx_ack(atmel_port->desc_tx); @@ -796,7 +797,9 @@ static void atmel_tx_dma(struct uart_port *port) struct circ_buf *xmit = &port->state->xmit; struct dma_chan *chan = atmel_port->chan_tx; struct dma_async_tx_descriptor *desc; - struct scatterlist *sg = &atmel_port->sg_tx; + struct scatterlist sgl[2], *sg, *sg_tx = &atmel_port->sg_tx; + unsigned int tx_len, part1_len, part2_len, sg_len; + dma_addr_t phys_addr; /* Make sure we have an idle channel */ if (atmel_port->desc_tx != NULL) @@ -812,18 +815,46 @@ static void atmel_tx_dma(struct uart_port *port) * Take the port lock to get a * consistent xmit buffer state. */ - sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); - sg_dma_address(sg) = (sg_dma_address(sg) & - ~(UART_XMIT_SIZE - 1)) - + sg->offset; - sg_dma_len(sg) = CIRC_CNT_TO_END(xmit->head, - xmit->tail, - UART_XMIT_SIZE); - BUG_ON(!sg_dma_len(sg)); + tx_len = CIRC_CNT_TO_END(xmit->head, + xmit->tail, + UART_XMIT_SIZE); + + if (atmel_port->fifo_size) { + /* multi data mode */ + part1_len = (tx_len & ~0x3); /* DWORD access */ + part2_len = (tx_len & 0x3); /* BYTE access */ + } else { + /* single data (legacy) mode */ + part1_len = 0; + part2_len = tx_len; /* BYTE access only */ + } + + sg_init_table(sgl, 2); + sg_len = 0; + phys_addr = sg_dma_address(sg_tx) + xmit->tail; + if (part1_len) { + sg = &sgl[sg_len++]; + sg_dma_address(sg) = phys_addr; + sg_dma_len(sg) = part1_len; + + phys_addr += part1_len; + } + + if (part2_len) { + sg = &sgl[sg_len++]; + sg_dma_address(sg) = phys_addr; + sg_dma_len(sg) = part2_len; + } + + /* + * save tx_len so atmel_complete_tx_dma() will increase + * xmit->tail correctly + */ + atmel_port->tx_len = tx_len; desc = dmaengine_prep_slave_sg(chan, - sg, - 1, + sgl, + sg_len, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -832,7 +863,7 @@ static void atmel_tx_dma(struct uart_port *port) return; } - dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); + dma_sync_sg_for_device(port->dev, sg_tx, 1, DMA_TO_DEVICE); atmel_port->desc_tx = desc; desc->callback = atmel_complete_tx_dma; @@ -892,7 +923,9 @@ static int atmel_prepare_tx_dma(struct uart_port *port) /* Configure the slave DMA */ memset(&config, 0, sizeof(config)); config.direction = DMA_MEM_TO_DEV; - config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + config.dst_addr_width = (atmel_port->fifo_size) ? + DMA_SLAVE_BUSWIDTH_4_BYTES : + DMA_SLAVE_BUSWIDTH_1_BYTE; config.dst_addr = port->mapbase + ATMEL_US_THR; config.dst_maxburst = 1; @@ -1831,6 +1864,9 @@ static int atmel_startup(struct uart_port *port) ATMEL_US_RXFCLR | ATMEL_US_TXFLCLR); + if (atmel_use_dma_tx(port)) + txrdym = ATMEL_US_FOUR_DATA; + fmr = ATMEL_US_TXRDYM(txrdym) | ATMEL_US_RXRDYM(rxrdym); if (atmel_port->rts_high && atmel_port->rts_low) -- cgit v1.3-6-gb490 From 3bb2ccd0d12a26392bf884c2a305b15b622fc7a8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:36:19 +0900 Subject: tty: serial: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_ingenic.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 21bf81fe794f..7c1e4be48e7b 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -252,7 +252,6 @@ MODULE_DEVICE_TABLE(of, of_match); static struct platform_driver ingenic_uart_platform_driver = { .driver = { .name = "ingenic-uart", - .owner = THIS_MODULE, .of_match_table = of_match, }, .probe = ingenic_uart_probe, -- cgit v1.3-6-gb490 From 7e8af24fbe6160c1529ff7fe67bf8b72b73b67e4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:36:20 +0900 Subject: tty: serial: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 9e6576004a42..bbeb33561737 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1369,7 +1369,6 @@ MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table); static struct i2c_driver sc16is7xx_i2c_uart_driver = { .driver = { .name = SC16IS7XX_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(sc16is7xx_dt_ids), }, .probe = sc16is7xx_i2c_probe, -- cgit v1.3-6-gb490 From e5eb517dd80e4da3055895f8aa3547c2bfd5e675 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 9 Jul 2015 10:34:34 +0200 Subject: serial/uuc_uart: Support higher bitrates than 115200 Bit/s The maximum bitrate supported depends on the clock rate used in BRG. This is stored in port.uartclk during probe. Respecting the 16x oversampling higher bitrates can be supported. Signed-off-by: Alexander Stein Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ucc_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 7d2532b23969..73190f5d2832 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -950,7 +950,7 @@ static void qe_uart_set_termios(struct uart_port *port, if ((termios->c_cflag & CREAD) == 0) port->read_status_mask &= ~BD_SC_EMPTY; - baud = uart_get_baud_rate(port, termios, old, 0, 115200); + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); /* Do we really need a spinlock here? */ spin_lock_irqsave(&port->lock, flags); -- cgit v1.3-6-gb490 From 069f38b4983efaea92cbe7cc0cacc057af55739a Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 12 Jul 2015 20:50:49 -0400 Subject: tty: Replace smp_rmb/smp_wmb with smp_load_acquire/smp_store_release Clarify flip buffer producer/consumer operation; the use of smp_load_acquire() and smp_store_release() more clearly indicates which memory access requires a barrier. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 4cf263d7dffc..25ba5afbca13 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -291,12 +291,11 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size, n->flags = flags; buf->tail = n; b->commit = b->used; - /* paired w/ barrier in flush_to_ldisc(); ensures the + /* paired w/ acquire in flush_to_ldisc(); ensures the * latest commit value can be read before the head is * advanced to the next buffer */ - smp_wmb(); - b->next = n; + smp_store_release(&b->next, n); } else if (change) size = 0; else @@ -488,12 +487,11 @@ static void flush_to_ldisc(struct work_struct *work) if (atomic_read(&buf->priority)) break; - next = head->next; - /* paired w/ barrier in __tty_buffer_request_room(); + /* paired w/ release in __tty_buffer_request_room(); * ensures commit value read is not stale if the head * is advancing to the next buffer */ - smp_rmb(); + next = smp_load_acquire(&head->next); count = head->commit - head->read; if (!count) { if (next == NULL) { -- cgit v1.3-6-gb490 From af5554f957f8a7e28b9826a9c4ad2a7dedd15a78 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 12 Jul 2015 20:50:50 -0400 Subject: tty: buffers: Move hidden buffer index advance into outer loop The advance of the 'read' buffer index belongs in the outer flip buffer consume loop, with the other buffer index arithmetic. No functional change. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 25ba5afbca13..5a3fa8913880 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -444,7 +444,6 @@ receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count) if (count) disc->ops->receive_buf(tty, p, f, count); } - head->read += count; return count; } @@ -506,6 +505,7 @@ static void flush_to_ldisc(struct work_struct *work) count = receive_buf(tty, head, count); if (!count) break; + head->read += count; } mutex_unlock(&buf->lock); -- cgit v1.3-6-gb490 From 97d49add8befb522828200081388b2f21c1c4f8b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 13 Jul 2015 13:18:51 +0200 Subject: serial: samsung: Remove redundant DEBUG_LL check Commit 84f57d9e3685 ("tty: serial/samsung: fix modular build") fixed build issues when the driver was built as a module. One of those was that printascii is only accessible when the driver is built-in. But there is no need to check for defined(CONFIG_DEBUG_LL) since the SERIAL_SAMSUNG_DEBUG Kconfig symbol already depends on DEBUG_LL. Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Acked-by: Kukjin Kim Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 67d0c213b1c7..8c963d6d9074 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -53,7 +53,6 @@ #include "samsung.h" #if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \ - defined(CONFIG_DEBUG_LL) && \ !defined(MODULE) extern void printascii(const char *); -- cgit v1.3-6-gb490 From 4e62794bd8c8c249435a86e7a44c0ec0af86c3df Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 21 Jul 2015 22:02:15 -0400 Subject: drivers/tty: make serial/sn_console.c driver explicitly non-modular The Kconfig for this option is currently: config SERIAL_SGI_L1_CONSOLE bool "SGI Altix L1 serial console support" ...meaning that it currently is not being built as a module by anyone. Lets remove the orphaned module code, so that when reading the driver there is no doubt it is builtin-only. We could consider making it tristate, but the above bool has been there since before the start of git history, which isn't all that surprising, since consoles are typically critical to have at early boot. So adding tristate is really of no value here. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sn_console.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c index 33e94e56dcdb..d4692d888e9d 100644 --- a/drivers/tty/serial/sn_console.c +++ b/drivers/tty/serial/sn_console.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include @@ -659,7 +659,7 @@ static void sn_sal_timer_poll(unsigned long data) * @port: Our sn_cons_port (which contains the uart port) * * So this is used by sn_sal_serial_console_init (early on, before we're - * registered with serial core). It's also used by sn_sal_module_init + * registered with serial core). It's also used by sn_sal_init * right after we've registered with serial core. The later only happens * if we didn't already come through here via sn_sal_serial_console_init. * @@ -709,7 +709,7 @@ static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port) * sn_sal_switch_to_interrupts - Switch to interrupt driven mode * @port: Our sn_cons_port (which contains the uart port) * - * In sn_sal_module_init, after we're registered with serial core and + * In sn_sal_init, after we're registered with serial core and * the port is added, this function is called to switch us to interrupt * mode. We were previously in asynch/polling mode (using init_timer). * @@ -773,7 +773,7 @@ static struct uart_driver sal_console_uart = { }; /** - * sn_sal_module_init - When the kernel loads us, get us rolling w/ serial core + * sn_sal_init - When the kernel loads us, get us rolling w/ serial core * * Before this is called, we've been printing kernel messages in a special * early mode not making use of the serial core infrastructure. When our @@ -781,7 +781,7 @@ static struct uart_driver sal_console_uart = { * core and try to enable interrupt driven mode. * */ -static int __init sn_sal_module_init(void) +static int __init sn_sal_init(void) { int retval; @@ -811,7 +811,7 @@ static int __init sn_sal_module_init(void) if (uart_register_driver(&sal_console_uart) < 0) { printk - ("ERROR sn_sal_module_init failed uart_register_driver, line %d\n", + ("ERROR sn_sal_init failed uart_register_driver, line %d\n", __LINE__); return -ENODEV; } @@ -832,33 +832,19 @@ static int __init sn_sal_module_init(void) /* when this driver is compiled in, the console initialization * will have already switched us into asynchronous operation - * before we get here through the module initcalls */ + * before we get here through the initcalls */ if (!sal_console_port.sc_is_asynch) { sn_sal_switch_to_asynch(&sal_console_port); } - /* at this point (module_init) we can try to turn on interrupts */ + /* at this point (device_init) we can try to turn on interrupts */ if (!IS_RUNNING_ON_SIMULATOR()) { sn_sal_switch_to_interrupts(&sal_console_port); } sn_process_input = 1; return 0; } - -/** - * sn_sal_module_exit - When we're unloaded, remove the driver/port - * - */ -static void __exit sn_sal_module_exit(void) -{ - del_timer_sync(&sal_console_port.sc_timer); - uart_remove_one_port(&sal_console_uart, &sal_console_port.sc_port); - uart_unregister_driver(&sal_console_uart); - misc_deregister(&misc); -} - -module_init(sn_sal_module_init); -module_exit(sn_sal_module_exit); +device_initcall(sn_sal_init); /** * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required -- cgit v1.3-6-gb490 From 1106d2dbab29971c091055716fbf2b9011c894c0 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 21 Jul 2015 22:02:16 -0400 Subject: drivers/tty: make serial/lantic.c driver explicitly non-modular The Kconfig for this option is currently: config SERIAL_LANTIQ bool "Lantiq serial driver" ...meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modularity, so that when reading the driver there is no doubt it is builtin-only. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. We delete the MODULE_DESCRIPTION and LICENSE tags since they are not adding any new information above and beyond what is at the top of the file. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code, so we remove that as well. Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/lantiq.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 4ccc0397664c..b88832e8ee82 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -21,7 +21,6 @@ */ #include -#include #include #include #include @@ -740,7 +739,6 @@ static const struct of_device_id ltq_asc_match[] = { { .compatible = DRVNAME }, {}, }; -MODULE_DEVICE_TABLE(of, ltq_asc_match); static struct platform_driver lqasc_driver = { .driver = { @@ -764,8 +762,4 @@ init_lqasc(void) return ret; } - -module_init(init_lqasc); - -MODULE_DESCRIPTION("Lantiq serial port driver"); -MODULE_LICENSE("GPL"); +device_initcall(init_lqasc); -- cgit v1.3-6-gb490 From 37db22346739d986c2863e2c7b5580e5f376c5e6 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 21 Jul 2015 22:02:17 -0400 Subject: drivers/tty: make serial/suncore.c driver explicitly non-modular The Kconfig for this driver is currently: config SERIAL_SUNCORE bool ...meaning that it currently is not being built as a module by anyone. Lets remove the modular and unused code here, so that when reading the driver there is no doubt it is builtin-only. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. We don't swap module.h for init.h since this file has init.h already. We leave some tags like MODULE_LICENSE for documentation purposes, and for the "git blame" value. Cc: "David S. Miller" Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: sparclinux@vger.kernel.org Cc: linux-serial@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/suncore.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/suncore.c b/drivers/tty/serial/suncore.c index 6e4ac8db2d79..127472bd6a7c 100644 --- a/drivers/tty/serial/suncore.c +++ b/drivers/tty/serial/suncore.c @@ -10,7 +10,6 @@ * Copyright (C) 2002 David S. Miller (davem@redhat.com) */ -#include #include #include #include @@ -234,14 +233,10 @@ static int __init suncore_init(void) { return 0; } +device_initcall(suncore_init); -static void __exit suncore_exit(void) -{ -} - -module_init(suncore_init); -module_exit(suncore_exit); - +#if 0 /* ..def MODULE ; never supported as such */ MODULE_AUTHOR("Eddie C. Dost, David S. Miller"); MODULE_DESCRIPTION("Sun serial common layer"); MODULE_LICENSE("GPL"); +#endif -- cgit v1.3-6-gb490 From 4fef53518f9b4813043bdb48b70bd9fbf4ad2597 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 21 Jul 2015 22:02:18 -0400 Subject: drivers/tty: make serial/sunhv.c driver explicitly non-modular The Kconfig for this driver is currently: config SERIAL_SUNHV bool "Sun4v Hypervisor Console support" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular and unused code here, so that when reading the driver there is no doubt it is builtin-only. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. We don't swap module.h for init.h since this file has init.h already. We leave some tags like MODULE_LICENSE for documentation purposes, and for the "git blame" value. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code, so we remove that too. Cc: "David S. Miller" Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: sparclinux@vger.kernel.org Cc: linux-serial@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sunhv.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index 534754440fa8..064031870ba0 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -3,7 +3,6 @@ * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net) */ -#include #include #include #include @@ -621,7 +620,6 @@ static const struct of_device_id hv_match[] = { }, {}, }; -MODULE_DEVICE_TABLE(of, hv_match); static struct platform_driver hv_driver = { .driver = { @@ -639,16 +637,11 @@ static int __init sunhv_init(void) return platform_driver_register(&hv_driver); } +device_initcall(sunhv_init); -static void __exit sunhv_exit(void) -{ - platform_driver_unregister(&hv_driver); -} - -module_init(sunhv_init); -module_exit(sunhv_exit); - +#if 0 /* ...def MODULE ; never supported as such */ MODULE_AUTHOR("David S. Miller"); MODULE_DESCRIPTION("SUN4V Hypervisor console driver"); MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); +#endif -- cgit v1.3-6-gb490 From 3a6b02dc1f1b37fe2e9c86c00edf07c04bed9fab Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 12 Jul 2015 22:49:07 -0400 Subject: tty: core: Improve debug message content Output the function name, tty name, and invariant failure (if applicable). Add the tty count to the tty_open() message. Fix the disassociate_ctty() message, which printed the NULL pointer and the wrong message. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 6bdfb98bf020..1738fcaea891 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -531,7 +531,8 @@ static void __proc_set_tty(struct tty_struct *tty) spin_unlock_irqrestore(&tty->ctrl_lock, flags); tty->session = get_pid(task_session(current)); if (current->signal->tty) { - printk(KERN_DEBUG "tty not NULL!!\n"); + printk(KERN_DEBUG "%s: %s: current tty %s not NULL!!\n", + __func__, tty->name, current->signal->tty->name); tty_kref_put(current->signal->tty); } put_pid(current->signal->tty_old_pgrp); @@ -929,8 +930,7 @@ void disassociate_ctty(int on_exit) tty_kref_put(tty); } else { #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "error attempted to write to tty [0x%p]" - " = NULL", tty); + printk(KERN_DEBUG "%s: no current tty\n", __func__); #endif } @@ -1712,8 +1712,8 @@ static int tty_release_checks(struct tty_struct *tty, int idx) { #ifdef TTY_PARANOIA_CHECK if (idx < 0 || idx >= tty->driver->num) { - printk(KERN_DEBUG "%s: bad idx when trying to free (%s)\n", - __func__, tty->name); + printk(KERN_DEBUG "%s: %s: bad idx %d\n", + __func__, tty->name, idx); return -1; } @@ -1722,20 +1722,22 @@ static int tty_release_checks(struct tty_struct *tty, int idx) return 0; if (tty != tty->driver->ttys[idx]) { - printk(KERN_DEBUG "%s: driver.table[%d] not tty for (%s)\n", - __func__, idx, tty->name); + printk(KERN_DEBUG "%s: %s: bad driver table[%d] = %p\n", + __func__, tty->name, idx, tty->driver->ttys[idx]); return -1; } if (tty->driver->other) { struct tty_struct *o_tty = tty->link; if (o_tty != tty->driver->other->ttys[idx]) { - printk(KERN_DEBUG "%s: other->table[%d] not o_tty for (%s)\n", - __func__, idx, tty->name); + printk(KERN_DEBUG "%s: %s: bad other table[%d] = %p\n", + __func__, tty->name, idx, + tty->driver->other->ttys[idx]); return -1; } if (o_tty->link != tty) { - printk(KERN_DEBUG "%s: bad pty pointers\n", __func__); + printk(KERN_DEBUG "%s: %s: bad link = %p\n", + __func__, tty->name, o_tty->link); return -1; } } @@ -2106,7 +2108,8 @@ retry_open: tty->driver->subtype == PTY_TYPE_MASTER) noctty = 1; #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: opening %s...\n", __func__, tty->name); + printk(KERN_DEBUG "%s: %s: (tty count=%d)\n", __func__, tty->name, + tty->count); #endif if (tty->ops->open) retval = tty->ops->open(tty, filp); @@ -2116,8 +2119,8 @@ retry_open: if (retval) { #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__, - retval, tty->name); + printk(KERN_DEBUG "%s: %s: error %d, releasing...\n", __func__, + tty->name, retval); #endif tty_unlock(tty); /* need to call tty_release without BTM */ tty_release(inode, filp); -- cgit v1.3-6-gb490 From e2dfa3d38797058fa03478b08bab3d3c4b081615 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 12 Jul 2015 22:49:08 -0400 Subject: tty: core: Add tty_debug() for printk(KERN_DEBUG) messages Introduce tty_debug() macro to output uniform debug information for tty core debug messages (function name and tty name). Note: printk(KERN_DEBUG) is retained here over pr_debug() since messages can be enabled in non-DEBUG builds. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 41 +++++++++++++++++------------------------ include/linux/tty.h | 6 ++++++ 2 files changed, 23 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 1738fcaea891..9537979c9c51 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -531,8 +531,8 @@ static void __proc_set_tty(struct tty_struct *tty) spin_unlock_irqrestore(&tty->ctrl_lock, flags); tty->session = get_pid(task_session(current)); if (current->signal->tty) { - printk(KERN_DEBUG "%s: %s: current tty %s not NULL!!\n", - __func__, tty->name, current->signal->tty->name); + tty_debug(tty, "current tty %s not NULL!!\n", + current->signal->tty->name); tty_kref_put(current->signal->tty); } put_pid(current->signal->tty_old_pgrp); @@ -775,7 +775,7 @@ static void do_tty_hangup(struct work_struct *work) void tty_hangup(struct tty_struct *tty) { #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s hangup...\n", tty_name(tty)); + tty_debug(tty, "\n"); #endif schedule_work(&tty->hangup_work); } @@ -794,7 +794,7 @@ EXPORT_SYMBOL(tty_hangup); void tty_vhangup(struct tty_struct *tty) { #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty)); + tty_debug(tty, "\n") #endif __tty_hangup(tty, 0); } @@ -833,7 +833,7 @@ void tty_vhangup_self(void) static void tty_vhangup_session(struct tty_struct *tty) { #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty)); + tty_debug(tty, "\n"); #endif __tty_hangup(tty, 1); } @@ -930,7 +930,7 @@ void disassociate_ctty(int on_exit) tty_kref_put(tty); } else { #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: no current tty\n", __func__); + tty_debug(tty, "no current tty\n"); #endif } @@ -1712,8 +1712,7 @@ static int tty_release_checks(struct tty_struct *tty, int idx) { #ifdef TTY_PARANOIA_CHECK if (idx < 0 || idx >= tty->driver->num) { - printk(KERN_DEBUG "%s: %s: bad idx %d\n", - __func__, tty->name, idx); + tty_debug(tty, "bad idx %d\n", idx); return -1; } @@ -1722,22 +1721,20 @@ static int tty_release_checks(struct tty_struct *tty, int idx) return 0; if (tty != tty->driver->ttys[idx]) { - printk(KERN_DEBUG "%s: %s: bad driver table[%d] = %p\n", - __func__, tty->name, idx, tty->driver->ttys[idx]); + tty_debug(tty, "bad driver table[%d] = %p\n", + idx, tty->driver->ttys[idx]); return -1; } if (tty->driver->other) { struct tty_struct *o_tty = tty->link; if (o_tty != tty->driver->other->ttys[idx]) { - printk(KERN_DEBUG "%s: %s: bad other table[%d] = %p\n", - __func__, tty->name, idx, - tty->driver->other->ttys[idx]); + tty_debug(tty, "bad other table[%d] = %p\n", + idx, tty->driver->other->ttys[idx]); return -1; } if (o_tty->link != tty) { - printk(KERN_DEBUG "%s: %s: bad link = %p\n", - __func__, tty->name, o_tty->link); + tty_debug(tty, "bad link = %p\n", o_tty->link); return -1; } } @@ -1792,8 +1789,7 @@ int tty_release(struct inode *inode, struct file *filp) } #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s (tty count=%d)...\n", __func__, - tty_name(tty), tty->count); + tty_debug(tty, "(tty count=%d)...\n", tty->count); #endif if (tty->ops->close) @@ -1905,7 +1901,7 @@ int tty_release(struct inode *inode, struct file *filp) return 0; #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty)); + tty_debug(tty, "final close\n"); #endif /* * Ask the line discipline code to release its structures @@ -1916,8 +1912,7 @@ int tty_release(struct inode *inode, struct file *filp) tty_flush_works(tty); #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, - tty_name(tty)); + tty_debug(tty, "freeing structure...\n"); #endif /* * The release_tty function takes care of the details of clearing @@ -2108,8 +2103,7 @@ retry_open: tty->driver->subtype == PTY_TYPE_MASTER) noctty = 1; #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: (tty count=%d)\n", __func__, tty->name, - tty->count); + tty_debug(tty, "(tty count=%d)\n", tty->count); #endif if (tty->ops->open) retval = tty->ops->open(tty, filp); @@ -2119,8 +2113,7 @@ retry_open: if (retval) { #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: error %d, releasing...\n", __func__, - tty->name, retval); + tty_debug(tty, "error %d, releasing...\n", retval); #endif tty_unlock(tty); /* need to call tty_release without BTM */ tty_release(inode, filp); diff --git a/include/linux/tty.h b/include/linux/tty.h index ad6c8913aa3e..d072ded41678 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -709,4 +709,10 @@ static inline void proc_tty_register_driver(struct tty_driver *d) {} static inline void proc_tty_unregister_driver(struct tty_driver *d) {} #endif +#define tty_debug(tty, f, args...) \ + do { \ + printk(KERN_DEBUG "%s: %s: " f, __func__, \ + tty_name(tty), ##args); \ + } while (0) + #endif -- cgit v1.3-6-gb490 From accff793af81bc64e1b37398ef6bb1f0b06491de Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 12 Jul 2015 22:49:09 -0400 Subject: tty: Replace #ifdef TTY_DEBUG_HANGUP with tty_debug_hangup() Add tty_debug_hangup() macro which uses tty_debug to print the debug message; remove inlined #ifdefs. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 47 ++++++++++++++++++----------------------------- 1 file changed, 18 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 9537979c9c51..c37a215177c0 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -106,6 +106,11 @@ #include #undef TTY_DEBUG_HANGUP +#ifdef TTY_DEBUG_HANGUP +# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args) +#else +# define tty_debug_hangup(tty, f, args...) do { } while (0) +#endif #define TTY_PARANOIA_CHECK 1 #define CHECK_TTY_COUNT 1 @@ -774,9 +779,7 @@ static void do_tty_hangup(struct work_struct *work) void tty_hangup(struct tty_struct *tty) { -#ifdef TTY_DEBUG_HANGUP - tty_debug(tty, "\n"); -#endif + tty_debug_hangup(tty, "\n"); schedule_work(&tty->hangup_work); } @@ -793,9 +796,7 @@ EXPORT_SYMBOL(tty_hangup); void tty_vhangup(struct tty_struct *tty) { -#ifdef TTY_DEBUG_HANGUP - tty_debug(tty, "\n") -#endif + tty_debug_hangup(tty, "\n"); __tty_hangup(tty, 0); } @@ -832,9 +833,7 @@ void tty_vhangup_self(void) static void tty_vhangup_session(struct tty_struct *tty) { -#ifdef TTY_DEBUG_HANGUP - tty_debug(tty, "\n"); -#endif + tty_debug_hangup(tty, "\n"); __tty_hangup(tty, 1); } @@ -928,11 +927,8 @@ void disassociate_ctty(int on_exit) tty->pgrp = NULL; spin_unlock_irqrestore(&tty->ctrl_lock, flags); tty_kref_put(tty); - } else { -#ifdef TTY_DEBUG_HANGUP - tty_debug(tty, "no current tty\n"); -#endif - } + } else + tty_debug_hangup(tty, "no current tty\n"); spin_unlock_irq(¤t->sighand->siglock); /* Now clear signal->tty under the lock */ @@ -1788,9 +1784,7 @@ int tty_release(struct inode *inode, struct file *filp) return 0; } -#ifdef TTY_DEBUG_HANGUP - tty_debug(tty, "(tty count=%d)...\n", tty->count); -#endif + tty_debug_hangup(tty, "(tty count=%d)...\n", tty->count); if (tty->ops->close) tty->ops->close(tty, filp); @@ -1900,9 +1894,7 @@ int tty_release(struct inode *inode, struct file *filp) if (!final) return 0; -#ifdef TTY_DEBUG_HANGUP - tty_debug(tty, "final close\n"); -#endif + tty_debug_hangup(tty, "final close\n"); /* * Ask the line discipline code to release its structures */ @@ -1911,9 +1903,7 @@ int tty_release(struct inode *inode, struct file *filp) /* Wait for pending work before tty destruction commmences */ tty_flush_works(tty); -#ifdef TTY_DEBUG_HANGUP - tty_debug(tty, "freeing structure...\n"); -#endif + tty_debug_hangup(tty, "freeing structure...\n"); /* * The release_tty function takes care of the details of clearing * the slots and preserving the termios structure. The tty_unlock_pair @@ -2102,9 +2092,9 @@ retry_open: if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) noctty = 1; -#ifdef TTY_DEBUG_HANGUP - tty_debug(tty, "(tty count=%d)\n", tty->count); -#endif + + tty_debug_hangup(tty, "(tty count=%d)\n", tty->count); + if (tty->ops->open) retval = tty->ops->open(tty, filp); else @@ -2112,9 +2102,8 @@ retry_open: filp->f_flags = saved_flags; if (retval) { -#ifdef TTY_DEBUG_HANGUP - tty_debug(tty, "error %d, releasing...\n", retval); -#endif + tty_debug_hangup(tty, "error %d, releasing...\n", retval); + tty_unlock(tty); /* need to call tty_release without BTM */ tty_release(inode, filp); if (retval != -ERESTARTSYS) -- cgit v1.3-6-gb490 From 0a6adc131c9d0809682d72398d01099a7ea4168b Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 12 Jul 2015 22:49:10 -0400 Subject: tty: Use tty_debug() for tty_ldisc_debug() Replace tty_ldisc_debug() macro definition; substitute with equivalent tty_debug() invocation. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ldisc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index c07fb5d9bcf9..81916804019e 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -22,9 +22,7 @@ #undef LDISC_DEBUG_HANGUP #ifdef LDISC_DEBUG_HANGUP -#define tty_ldisc_debug(tty, f, args...) ({ \ - printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty), ##args); \ -}) +#define tty_ldisc_debug(tty, f, args...) tty_debug(tty, f, ##args) #else #define tty_ldisc_debug(tty, f, args...) #endif -- cgit v1.3-6-gb490 From ff8339dc164bb807cc67492ed9310335b7ed88ba Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 12 Jul 2015 22:49:11 -0400 Subject: tty: Replace inline #ifdef TTY_DEBUG_WAIT_UNTIL_SENT Add tty_debug_wait_until_sent() macro which uses tty_debug() to print the debug message; remove inlined #ifdef. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ioctl.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 5232fb60b0b1..9c5aebfe7053 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -26,6 +26,12 @@ #undef TTY_DEBUG_WAIT_UNTIL_SENT +#ifdef TTY_DEBUG_WAIT_UNTIL_SENT +# define tty_debug_wait_until_sent(tty, f, args...) tty_debug(tty, f, ##args) +#else +# define tty_debug_wait_until_sent(tty, f, args...) do {} while (0) +#endif + #undef DEBUG /* @@ -210,9 +216,8 @@ int tty_unthrottle_safe(struct tty_struct *tty) void tty_wait_until_sent(struct tty_struct *tty, long timeout) { -#ifdef TTY_DEBUG_WAIT_UNTIL_SENT - printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty)); -#endif + tty_debug_wait_until_sent(tty, "\n"); + if (!timeout) timeout = MAX_SCHEDULE_TIMEOUT; -- cgit v1.3-6-gb490 From fb6edc9115f7eb8265fb9282703e52738d397506 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 12 Jul 2015 22:49:12 -0400 Subject: tty: core: Improve ldisc debug messages Add debug messages for ldisc open and close, and remove "closing ldisc" message from tty_ldisc_release(), because a close message is now printed for both ldiscs; always print ldisc pointer first so ldisc changes are easier to identify. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ldisc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 81916804019e..71750cbac31f 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -447,6 +447,8 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) ret = ld->ops->open(tty); if (ret) clear_bit(TTY_LDISC_OPEN, &tty->flags); + + tty_ldisc_debug(tty, "%p: opened\n", tty->ldisc); return ret; } return 0; @@ -467,6 +469,7 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) clear_bit(TTY_LDISC_OPEN, &tty->flags); if (ld->ops->close) ld->ops->close(tty); + tty_ldisc_debug(tty, "%p: closed\n", tty->ldisc); } /** @@ -660,7 +663,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS; int err = 0; - tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc); + tty_ldisc_debug(tty, "%p: closing\n", tty->ldisc); ld = tty_ldisc_ref(tty); if (ld != NULL) { @@ -710,7 +713,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) if (reset) tty_reset_termios(tty); - tty_ldisc_debug(tty, "re-opened ldisc: %p\n", tty->ldisc); + tty_ldisc_debug(tty, "%p: re-opened\n", tty->ldisc); } /** @@ -774,8 +777,6 @@ void tty_ldisc_release(struct tty_struct *tty) * it does not race with the set_ldisc code path. */ - tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc); - tty_ldisc_lock_pair(tty, o_tty); tty_ldisc_kill(tty); if (o_tty) @@ -785,7 +786,7 @@ void tty_ldisc_release(struct tty_struct *tty) /* And the memory resources remaining (buffers, termios) will be disposed of when the kref hits zero */ - tty_ldisc_debug(tty, "ldisc closed\n"); + tty_ldisc_debug(tty, "released\n"); } /** -- cgit v1.3-6-gb490 From d684779335856d8177514b42a801d46088d897b0 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sun, 12 Jul 2015 22:49:13 -0400 Subject: pty: Add debug message for ptmx open Opens of /dev/ptmx don't use tty_open() so debug messages are not printed for those opens; print a debug message with the open count (which must always be 1) if TTY_DEBUG_HANGUP is defined. NB: Each tty core source file undefs support for debug messages. The relevant source file must be patched/edited to enable these messages. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 4d5e8409769c..4d5937c185c1 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -26,6 +26,12 @@ #include #include +#undef TTY_DEBUG_HANGUP +#ifdef TTY_DEBUG_HANGUP +# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args) +#else +# define tty_debug_hangup(tty, f, args...) do {} while (0) +#endif #ifdef CONFIG_UNIX98_PTYS static struct tty_driver *ptm_driver; @@ -779,6 +785,8 @@ static int ptmx_open(struct inode *inode, struct file *filp) if (retval) goto err_release; + tty_debug_hangup(tty, "(tty count=%d)\n", tty->count); + tty_unlock(tty); return 0; err_release: -- cgit v1.3-6-gb490 From ac4c90c82e4d38cee613f68d2fabd714338ecca7 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 1 Jul 2015 15:10:38 +0200 Subject: cpufreq: exynos: remove exynos5250 specific cpufreq driver support Exynos5250 based platforms have switched over to use generic cpufreq driver for cpufreq functionality. So the Exynos specific cpufreq support for these platforms can be removed. Cc: Thomas Abraham Signed-off-by: Bartlomiej Zolnierkiewicz Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Viresh Kumar [k.kozlowski: Rebased the patch around exynos-cpufreq.c] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Kukjin Kim --- drivers/cpufreq/Kconfig.arm | 11 -- drivers/cpufreq/Makefile | 1 - drivers/cpufreq/exynos-cpufreq.c | 3 - drivers/cpufreq/exynos-cpufreq.h | 17 --- drivers/cpufreq/exynos5250-cpufreq.c | 210 ----------------------------------- 5 files changed, 242 deletions(-) delete mode 100644 drivers/cpufreq/exynos5250-cpufreq.c (limited to 'drivers') diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index cc8a71c267b8..7a4c1820de8c 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -47,17 +47,6 @@ config ARM_EXYNOS4X12_CPUFREQ If in doubt, say N. -config ARM_EXYNOS5250_CPUFREQ - bool "SAMSUNG EXYNOS5250" - depends on SOC_EXYNOS5250 - depends on ARM_EXYNOS_CPUFREQ - default y - help - This adds the CPUFreq driver for Samsung EXYNOS5250 - SoC. - - If in doubt, say N. - config ARM_EXYNOS_CPU_FREQ_BOOST_SW bool "EXYNOS Frequency Overclocking - Software" depends on ARM_EXYNOS_CPUFREQ && THERMAL diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 2169bf792db7..06286bbace21 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -55,7 +55,6 @@ obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += arm-exynos-cpufreq.o arm-exynos-cpufreq-y := exynos-cpufreq.o arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o -arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ) += hisi-acpu-cpufreq.o diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index ae5b2bd3a978..71d889161218 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -175,9 +175,6 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) } else if (of_machine_is_compatible("samsung,exynos4412")) { exynos_info->type = EXYNOS_SOC_4412; ret = exynos4x12_cpufreq_init(exynos_info); - } else if (of_machine_is_compatible("samsung,exynos5250")) { - exynos_info->type = EXYNOS_SOC_5250; - ret = exynos5250_cpufreq_init(exynos_info); } else { pr_err("%s: Unknown SoC type\n", __func__); return -ENODEV; diff --git a/drivers/cpufreq/exynos-cpufreq.h b/drivers/cpufreq/exynos-cpufreq.h index a3855e4d913d..a359db792ac8 100644 --- a/drivers/cpufreq/exynos-cpufreq.h +++ b/drivers/cpufreq/exynos-cpufreq.h @@ -20,7 +20,6 @@ enum cpufreq_level_index { enum exynos_soc_type { EXYNOS_SOC_4212, EXYNOS_SOC_4412, - EXYNOS_SOC_5250, }; #define APLL_FREQ(f, a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, m, p, s) \ @@ -60,14 +59,6 @@ static inline int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info) return -EOPNOTSUPP; } #endif -#ifdef CONFIG_ARM_EXYNOS5250_CPUFREQ -extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *); -#else -static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info *info) -{ - return -EOPNOTSUPP; -} -#endif #define EXYNOS4_CLKSRC_CPU 0x14200 #define EXYNOS4_CLKMUX_STATCPU 0x14400 @@ -79,11 +70,3 @@ static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info *info) #define EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT (16) #define EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK (0x7 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT) - -#define EXYNOS5_APLL_LOCK 0x00000 -#define EXYNOS5_APLL_CON0 0x00100 -#define EXYNOS5_CLKMUX_STATCPU 0x00400 -#define EXYNOS5_CLKDIV_CPU0 0x00500 -#define EXYNOS5_CLKDIV_CPU1 0x00504 -#define EXYNOS5_CLKDIV_STATCPU0 0x00600 -#define EXYNOS5_CLKDIV_STATCPU1 0x00604 diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c deleted file mode 100644 index 3eafdc7ba787..000000000000 --- a/drivers/cpufreq/exynos5250-cpufreq.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2010-20122Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS5250 - CPU frequency scaling support - * - * 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 "exynos-cpufreq.h" - -static struct clk *cpu_clk; -static struct clk *moutcore; -static struct clk *mout_mpll; -static struct clk *mout_apll; -static struct exynos_dvfs_info *cpufreq; - -static unsigned int exynos5250_volt_table[] = { - 1300000, 1250000, 1225000, 1200000, 1150000, - 1125000, 1100000, 1075000, 1050000, 1025000, - 1012500, 1000000, 975000, 950000, 937500, - 925000 -}; - -static struct cpufreq_frequency_table exynos5250_freq_table[] = { - {0, L0, 1700 * 1000}, - {0, L1, 1600 * 1000}, - {0, L2, 1500 * 1000}, - {0, L3, 1400 * 1000}, - {0, L4, 1300 * 1000}, - {0, L5, 1200 * 1000}, - {0, L6, 1100 * 1000}, - {0, L7, 1000 * 1000}, - {0, L8, 900 * 1000}, - {0, L9, 800 * 1000}, - {0, L10, 700 * 1000}, - {0, L11, 600 * 1000}, - {0, L12, 500 * 1000}, - {0, L13, 400 * 1000}, - {0, L14, 300 * 1000}, - {0, L15, 200 * 1000}, - {0, 0, CPUFREQ_TABLE_END}, -}; - -static struct apll_freq apll_freq_5250[] = { - /* - * values: - * freq - * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2 - * clock divider for COPY, HPM, RESERVED - * PLL M, P, S - */ - APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0), - APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0), - APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0), - APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0), - APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0), - APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0), - APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0), - APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0), - APLL_FREQ(900, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0), - APLL_FREQ(800, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0), - APLL_FREQ(700, 0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1), - APLL_FREQ(600, 0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1), - APLL_FREQ(500, 0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1), - APLL_FREQ(400, 0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1), - APLL_FREQ(300, 0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2), - APLL_FREQ(200, 0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2), -}; - -static void set_clkdiv(unsigned int div_index) -{ - unsigned int tmp; - - /* Change Divider - CPU0 */ - - tmp = apll_freq_5250[div_index].clk_div_cpu0; - - __raw_writel(tmp, cpufreq->cmu_regs + EXYNOS5_CLKDIV_CPU0); - - while (__raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKDIV_STATCPU0) - & 0x11111111) - cpu_relax(); - - /* Change Divider - CPU1 */ - tmp = apll_freq_5250[div_index].clk_div_cpu1; - - __raw_writel(tmp, cpufreq->cmu_regs + EXYNOS5_CLKDIV_CPU1); - - while (__raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKDIV_STATCPU1) & 0x11) - cpu_relax(); -} - -static void set_apll(unsigned int index) -{ - unsigned int tmp; - unsigned int freq = apll_freq_5250[index].freq; - - /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */ - clk_set_parent(moutcore, mout_mpll); - - do { - cpu_relax(); - tmp = (__raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKMUX_STATCPU) - >> 16); - tmp &= 0x7; - } while (tmp != 0x2); - - clk_set_rate(mout_apll, freq * 1000); - - /* MUX_CORE_SEL = APLL */ - clk_set_parent(moutcore, mout_apll); - - do { - cpu_relax(); - tmp = __raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKMUX_STATCPU); - tmp &= (0x7 << 16); - } while (tmp != (0x1 << 16)); -} - -static void exynos5250_set_frequency(unsigned int old_index, - unsigned int new_index) -{ - if (old_index > new_index) { - set_clkdiv(new_index); - set_apll(new_index); - } else if (old_index < new_index) { - set_apll(new_index); - set_clkdiv(new_index); - } -} - -int exynos5250_cpufreq_init(struct exynos_dvfs_info *info) -{ - struct device_node *np; - unsigned long rate; - - /* - * HACK: This is a temporary workaround to get access to clock - * controller registers directly and remove static mappings and - * dependencies on platform headers. It is necessary to enable - * Exynos multi-platform support and will be removed together with - * this whole driver as soon as Exynos gets migrated to use - * cpufreq-dt driver. - */ - np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-clock"); - if (!np) { - pr_err("%s: failed to find clock controller DT node\n", - __func__); - return -ENODEV; - } - - info->cmu_regs = of_iomap(np, 0); - if (!info->cmu_regs) { - pr_err("%s: failed to map CMU registers\n", __func__); - return -EFAULT; - } - - cpu_clk = clk_get(NULL, "armclk"); - if (IS_ERR(cpu_clk)) - return PTR_ERR(cpu_clk); - - moutcore = clk_get(NULL, "mout_cpu"); - if (IS_ERR(moutcore)) - goto err_moutcore; - - mout_mpll = clk_get(NULL, "mout_mpll"); - if (IS_ERR(mout_mpll)) - goto err_mout_mpll; - - rate = clk_get_rate(mout_mpll) / 1000; - - mout_apll = clk_get(NULL, "mout_apll"); - if (IS_ERR(mout_apll)) - goto err_mout_apll; - - info->mpll_freq_khz = rate; - /* 800Mhz */ - info->pll_safe_idx = L9; - info->cpu_clk = cpu_clk; - info->volt_table = exynos5250_volt_table; - info->freq_table = exynos5250_freq_table; - info->set_freq = exynos5250_set_frequency; - - cpufreq = info; - - return 0; - -err_mout_apll: - clk_put(mout_mpll); -err_mout_mpll: - clk_put(moutcore); -err_moutcore: - clk_put(cpu_clk); - - pr_err("%s: failed initialization\n", __func__); - return -EINVAL; -} -- cgit v1.3-6-gb490 From d7cc4c8165e67ff2ba250d65c9e4939d7b8d36c7 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Wed, 1 Jul 2015 15:10:35 +0200 Subject: clk: exynos5250: add cpu clock configuration data and instantiate cpu clock With the addition of the new Samsung specific cpu-clock type, the arm clock can be represented as a cpu-clock type. Add the CPU clock configuration data and instantiate the CPU clock type for Exynos5250. Cc: Tomasz Figa Signed-off-by: Thomas Abraham [b.zolnierkie: split exynos5250 support from the original patch] [b.zolnierkie: moved E5250_CPU_DIV[0,1] macros to clk-exynos5250.c] Signed-off-by: Bartlomiej Zolnierkiewicz Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Sylwester Nawrocki Acked-by: Viresh Kumar Signed-off-by: Krzysztof Kozlowski Acked-by: Michael Turquette Signed-off-by: Kukjin Kim --- drivers/clk/samsung/clk-exynos5250.c | 31 +++++++++++++++++++++++++++++++ include/dt-bindings/clock/exynos5250.h | 1 + 2 files changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 70ec3d2608a1..d87f34de2152 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -19,6 +19,7 @@ #include #include "clk.h" +#include "clk-cpu.h" #define APLL_LOCK 0x0 #define APLL_CON0 0x100 @@ -748,6 +749,32 @@ static struct samsung_pll_clock exynos5250_plls[nr_plls] __initdata = { VPLL_LOCK, VPLL_CON0, NULL), }; +#define E5250_CPU_DIV0(apll, pclk_dbg, atb, periph, acp, cpud) \ + ((((apll) << 24) | ((pclk_dbg) << 20) | ((atb) << 16) | \ + ((periph) << 12) | ((acp) << 8) | ((cpud) << 4))) +#define E5250_CPU_DIV1(hpm, copy) \ + (((hpm) << 4) | (copy)) + +static const struct exynos_cpuclk_cfg_data exynos5250_armclk_d[] __initconst = { + { 1700000, E5250_CPU_DIV0(5, 3, 7, 7, 7, 3), E5250_CPU_DIV1(2, 0), }, + { 1600000, E5250_CPU_DIV0(4, 1, 7, 7, 7, 3), E5250_CPU_DIV1(2, 0), }, + { 1500000, E5250_CPU_DIV0(4, 1, 7, 7, 7, 2), E5250_CPU_DIV1(2, 0), }, + { 1400000, E5250_CPU_DIV0(4, 1, 6, 7, 7, 2), E5250_CPU_DIV1(2, 0), }, + { 1300000, E5250_CPU_DIV0(3, 1, 6, 7, 7, 2), E5250_CPU_DIV1(2, 0), }, + { 1200000, E5250_CPU_DIV0(3, 1, 5, 7, 7, 2), E5250_CPU_DIV1(2, 0), }, + { 1100000, E5250_CPU_DIV0(3, 1, 5, 7, 7, 3), E5250_CPU_DIV1(2, 0), }, + { 1000000, E5250_CPU_DIV0(2, 1, 4, 7, 7, 1), E5250_CPU_DIV1(2, 0), }, + { 900000, E5250_CPU_DIV0(2, 1, 4, 7, 7, 1), E5250_CPU_DIV1(2, 0), }, + { 800000, E5250_CPU_DIV0(2, 1, 4, 7, 7, 1), E5250_CPU_DIV1(2, 0), }, + { 700000, E5250_CPU_DIV0(1, 1, 3, 7, 7, 1), E5250_CPU_DIV1(2, 0), }, + { 600000, E5250_CPU_DIV0(1, 1, 3, 7, 7, 1), E5250_CPU_DIV1(2, 0), }, + { 500000, E5250_CPU_DIV0(1, 1, 2, 7, 7, 1), E5250_CPU_DIV1(2, 0), }, + { 400000, E5250_CPU_DIV0(1, 1, 2, 7, 7, 1), E5250_CPU_DIV1(2, 0), }, + { 300000, E5250_CPU_DIV0(1, 1, 1, 7, 7, 1), E5250_CPU_DIV1(2, 0), }, + { 200000, E5250_CPU_DIV0(1, 1, 1, 7, 7, 1), E5250_CPU_DIV1(2, 0), }, + { 0 }, +}; + static const struct of_device_id ext_clk_match[] __initconst = { { .compatible = "samsung,clock-xxti", .data = (void *)0, }, { }, @@ -797,6 +824,10 @@ static void __init exynos5250_clk_init(struct device_node *np) ARRAY_SIZE(exynos5250_div_clks)); samsung_clk_register_gate(ctx, exynos5250_gate_clks, ARRAY_SIZE(exynos5250_gate_clks)); + exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", + mout_cpu_p[0], mout_cpu_p[1], 0x200, + exynos5250_armclk_d, ARRAY_SIZE(exynos5250_armclk_d), + CLK_CPU_HAS_DIV1); /* * Enable arm clock down (in idle) and set arm divider diff --git a/include/dt-bindings/clock/exynos5250.h b/include/dt-bindings/clock/exynos5250.h index 4273891dc78e..8183d1c237d9 100644 --- a/include/dt-bindings/clock/exynos5250.h +++ b/include/dt-bindings/clock/exynos5250.h @@ -21,6 +21,7 @@ #define CLK_FOUT_CPLL 6 #define CLK_FOUT_EPLL 7 #define CLK_FOUT_VPLL 8 +#define CLK_ARM_CLK 9 /* gate for special clocks (sclk) */ #define CLK_SCLK_CAM_BAYER 128 -- cgit v1.3-6-gb490 From 7c9422ef553e8845c91b8fc5fa98452d934834f0 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 24 Jul 2015 12:42:40 +0900 Subject: clk: exynos3250: Add cpu clock configuration data and instaniate cpu clock This patch add CPU clock configuration data and instantiate the CPU clock type for Exynos3250 to support Samsung specific cpu-clock type. Cc: Sylwester Nawrocki Cc: Tomasz Figa Signed-off-by: Chanwoo Choi Acked-by: Kyungmin Park Reviewed-by: Krzysztof Kozlowski Reviewed-by: Bartlomiej Zolnierkiewicz Acked-by: Michael Turquette Signed-off-by: Kukjin Kim --- drivers/clk/samsung/clk-exynos3250.c | 32 ++++++++++++++++++++++++++++++-- include/dt-bindings/clock/exynos3250.h | 1 + 2 files changed, 31 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 538de66a759e..1880a90e2ebc 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -19,6 +19,7 @@ #include #include "clk.h" +#include "clk-cpu.h" #include "clk-pll.h" #define SRC_LEFTBUS 0x4200 @@ -319,8 +320,10 @@ static struct samsung_mux_clock mux_clks[] __initdata = { MUX(CLK_MOUT_MPLL_USER_C, "mout_mpll_user_c", mout_mpll_user_p, SRC_CPU, 24, 1), MUX(CLK_MOUT_HPM, "mout_hpm", mout_hpm_p, SRC_CPU, 20, 1), - MUX(CLK_MOUT_CORE, "mout_core", mout_core_p, SRC_CPU, 16, 1), - MUX(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1), + MUX_F(CLK_MOUT_CORE, "mout_core", mout_core_p, SRC_CPU, 16, 1, + CLK_SET_RATE_PARENT, 0), + MUX_F(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, + CLK_SET_RATE_PARENT, 0), }; static struct samsung_div_clock div_clks[] __initdata = { @@ -772,6 +775,26 @@ static struct samsung_cmu_info cmu_info __initdata = { .nr_clk_regs = ARRAY_SIZE(exynos3250_cmu_clk_regs), }; +#define E3250_CPU_DIV0(apll, pclk_dbg, atb, corem) \ + (((apll) << 24) | ((pclk_dbg) << 20) | ((atb) << 16) | \ + ((corem) << 4)) +#define E3250_CPU_DIV1(hpm, copy) \ + (((hpm) << 4) | ((copy) << 0)) + +static const struct exynos_cpuclk_cfg_data e3250_armclk_d[] __initconst = { + { 1000000, E3250_CPU_DIV0(1, 7, 4, 1), E3250_CPU_DIV1(7, 7), }, + { 900000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), }, + { 800000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), }, + { 700000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), }, + { 600000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), }, + { 500000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), }, + { 400000, E3250_CPU_DIV0(1, 7, 3, 1), E3250_CPU_DIV1(7, 7), }, + { 300000, E3250_CPU_DIV0(1, 5, 3, 1), E3250_CPU_DIV1(7, 7), }, + { 200000, E3250_CPU_DIV0(1, 3, 3, 1), E3250_CPU_DIV1(7, 7), }, + { 100000, E3250_CPU_DIV0(1, 1, 1, 1), E3250_CPU_DIV1(7, 7), }, + { 0 }, +}; + static void __init exynos3250_cmu_init(struct device_node *np) { struct samsung_clk_provider *ctx; @@ -780,6 +803,11 @@ static void __init exynos3250_cmu_init(struct device_node *np) if (!ctx) return; + exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", + mout_core_p[0], mout_core_p[1], 0x14200, + e3250_armclk_d, ARRAY_SIZE(e3250_armclk_d), + CLK_CPU_HAS_DIV1); + exynos3_core_down_clock(ctx->reg_base); } CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init); diff --git a/include/dt-bindings/clock/exynos3250.h b/include/dt-bindings/clock/exynos3250.h index aab088d30199..63d01c15d2b3 100644 --- a/include/dt-bindings/clock/exynos3250.h +++ b/include/dt-bindings/clock/exynos3250.h @@ -31,6 +31,7 @@ #define CLK_FOUT_VPLL 4 #define CLK_FOUT_UPLL 5 #define CLK_FOUT_MPLL 6 +#define CLK_ARM_CLK 7 /* Muxes */ #define CLK_MOUT_MPLL_USER_L 16 -- cgit v1.3-6-gb490 From b7446cacfb433f5e89ff94afecbc349e404aee21 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 18 Jun 2015 11:43:37 +0200 Subject: tcm_loop: Remove SAS vestigies tcm_loop is able to emulate several protocols, so remove last vestigies of the SAS protocol. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/loopback/tcm_loop.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index a556bdebd775..b179d934cee1 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -526,7 +526,7 @@ static inline struct tcm_loop_tpg *tl_tpg(struct se_portal_group *se_tpg) static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg) { /* - * Return the passed NAA identifier for the SAS Target Port + * Return the passed NAA identifier for the Target Port */ return &tl_tpg(se_tpg)->tl_hba->tl_wwn_address[0]; } @@ -845,7 +845,7 @@ static int tcm_loop_make_nexus( transport_free_session(tl_nexus->se_sess); goto out; } - /* Now, register the SAS I_T Nexus as active. */ + /* Now, register the I_T Nexus as active. */ transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl, tl_nexus->se_sess, tl_nexus); tl_tpg->tl_nexus = tl_nexus; @@ -884,7 +884,7 @@ static int tcm_loop_drop_nexus( " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tpg->tl_hba), tl_nexus->se_sess->se_node_acl->initiatorname); /* - * Release the SCSI I_T Nexus to the emulated SAS Target Port + * Release the SCSI I_T Nexus to the emulated Target Port */ transport_deregister_session(tl_nexus->se_sess); tpg->tl_nexus = NULL; @@ -1077,7 +1077,7 @@ static struct se_portal_group *tcm_loop_make_naa_tpg( tl_tpg->tl_hba = tl_hba; tl_tpg->tl_tpgt = tpgt; /* - * Register the tl_tpg as a emulated SAS TCM Target Endpoint + * Register the tl_tpg as a emulated TCM Target Endpoint */ ret = core_tpg_register(wwn, &tl_tpg->tl_se_tpg, tl_hba->tl_proto_id); if (ret < 0) @@ -1102,11 +1102,11 @@ static void tcm_loop_drop_naa_tpg( tl_hba = tl_tpg->tl_hba; tpgt = tl_tpg->tl_tpgt; /* - * Release the I_T Nexus for the Virtual SAS link if present + * Release the I_T Nexus for the Virtual target link if present */ tcm_loop_drop_nexus(tl_tpg); /* - * Deregister the tl_tpg as a emulated SAS TCM Target Endpoint + * Deregister the tl_tpg as a emulated TCM Target Endpoint */ core_tpg_deregister(se_tpg); @@ -1199,8 +1199,9 @@ static void tcm_loop_drop_scsi_hba( struct tcm_loop_hba, tl_hba_wwn); pr_debug("TCM_Loop_ConfigFS: Deallocating emulated Target" - " SAS Address: %s at Linux/SCSI Host ID: %d\n", - tl_hba->tl_wwn_address, tl_hba->sh->host_no); + " %s Address: %s at Linux/SCSI Host ID: %d\n", + tcm_loop_dump_proto_id(tl_hba), tl_hba->tl_wwn_address, + tl_hba->sh->host_no); /* * Call device_unregister() on the original tl_hba->dev. * tcm_loop_fabric_scsi.c:tcm_loop_release_adapter() will -- cgit v1.3-6-gb490 From e986a35aba67558381d5cec59a14c4d0b20f0d47 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 18 Jun 2015 11:43:38 +0200 Subject: tcm_loop: Send I_T_NEXUS_LOSS_OCCURRED UA If the virtual SAS link is set to 'offline' we should be queueing an I_T_NEXUS_LOSS_OCCURRED UA. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/loopback/tcm_loop.c | 5 +++++ drivers/target/target_core_tpg.c | 17 +++++++++++++++++ include/target/target_core_fabric.h | 1 + 3 files changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index b179d934cee1..5bc85ffed720 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -1034,6 +1034,11 @@ static ssize_t tcm_loop_tpg_store_transport_status( } if (!strncmp(page, "offline", 7)) { tl_tpg->tl_transport_status = TCM_TRANSPORT_OFFLINE; + if (tl_tpg->tl_nexus) { + struct se_session *tl_sess = tl_tpg->tl_nexus->se_sess; + + core_allocate_nexus_loss_ua(tl_sess->se_node_acl); + } return count; } return -EINVAL; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index babde4ad841f..2d0381dd105c 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -41,6 +41,7 @@ #include "target_core_internal.h" #include "target_core_alua.h" #include "target_core_pr.h" +#include "target_core_ua.h" extern struct se_device *g_lun0_dev; @@ -83,6 +84,22 @@ struct se_node_acl *core_tpg_get_initiator_node_acl( } EXPORT_SYMBOL(core_tpg_get_initiator_node_acl); +void core_allocate_nexus_loss_ua( + struct se_node_acl *nacl) +{ + struct se_dev_entry *deve; + + if (!nacl) + return; + + rcu_read_lock(); + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) + core_scsi3_ua_allocate(deve, 0x29, + ASCQ_29H_NEXUS_LOSS_OCCURRED); + rcu_read_unlock(); +} +EXPORT_SYMBOL(core_allocate_nexus_loss_ua); + /* core_tpg_add_node_to_devs(): * * diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 18afef91b447..69355feabd1d 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -152,6 +152,7 @@ int transport_generic_handle_tmr(struct se_cmd *); void transport_generic_request_failure(struct se_cmd *, sense_reason_t); void __target_execute_cmd(struct se_cmd *); int transport_lookup_tmr_lun(struct se_cmd *, u64); +void core_allocate_nexus_loss_ua(struct se_node_acl *acl); struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, unsigned char *); -- cgit v1.3-6-gb490 From 46d5bd62ef9e3d6e2018963cbb725c91f864922d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 8 Jul 2015 17:58:50 +0300 Subject: target: Inline transport_get_sense_codes() Inline this function in its call site since it performs a trivial task and since it is only called once. Signed-off-by: Bart Van Assche Signed-off-by: Sagi Grimberg Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ce8574b7220c..b6708d1b69b8 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2615,17 +2615,6 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) } EXPORT_SYMBOL(transport_wait_for_tasks); -static int transport_get_sense_codes( - struct se_cmd *cmd, - u8 *asc, - u8 *ascq) -{ - *asc = cmd->scsi_asc; - *ascq = cmd->scsi_ascq; - - return 0; -} - static void transport_err_sector_info(unsigned char *buffer, sector_t bad_sector) { @@ -2819,9 +2808,8 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* Not Ready */ buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; - transport_get_sense_codes(cmd, &asc, &ascq); - buffer[SPC_ASC_KEY_OFFSET] = asc; - buffer[SPC_ASCQ_KEY_OFFSET] = ascq; + buffer[SPC_ASC_KEY_OFFSET] = cmd->scsi_asc; + buffer[SPC_ASCQ_KEY_OFFSET] = cmd->scsi_ascq; break; case TCM_MISCOMPARE_VERIFY: /* CURRENT ERROR */ -- cgit v1.3-6-gb490 From ab78fef4d5f79134042ae0e1e2c259e1226aa5bd Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 8 Jul 2015 17:58:51 +0300 Subject: target: Split transport_send_check_condition_and_sense() Move the code for translating a sense_reason_t code into a SCSI status ASC and ASCQ codes from transport_send_check_condition_and_sense() into the new function translate_sense_reason(). Convert the switch statement that performs the translation into table-driven code. Signed-off-by: Bart Van Assche Signed-off-by: Sagi Grimberg Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 383 +++++++++++++-------------------- 1 file changed, 148 insertions(+), 235 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index b6708d1b69b8..6ef44c9db381 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2628,13 +2628,155 @@ void transport_err_sector_info(unsigned char *buffer, sector_t bad_sector) put_unaligned_be64(bad_sector, &buffer[12]); } +struct sense_info { + u8 key; + u8 asc; + u8 ascq; + bool add_sector_info; +}; + +static const struct sense_info sense_info_table[] = { + [TCM_NO_SENSE] = { + .key = NOT_READY + }, + [TCM_NON_EXISTENT_LUN] = { + .key = ILLEGAL_REQUEST, + .asc = 0x25 /* LOGICAL UNIT NOT SUPPORTED */ + }, + [TCM_UNSUPPORTED_SCSI_OPCODE] = { + .key = ILLEGAL_REQUEST, + .asc = 0x20, /* INVALID COMMAND OPERATION CODE */ + }, + [TCM_SECTOR_COUNT_TOO_MANY] = { + .key = ILLEGAL_REQUEST, + .asc = 0x20, /* INVALID COMMAND OPERATION CODE */ + }, + [TCM_UNKNOWN_MODE_PAGE] = { + .key = ILLEGAL_REQUEST, + .asc = 0x24, /* INVALID FIELD IN CDB */ + }, + [TCM_CHECK_CONDITION_ABORT_CMD] = { + .key = ABORTED_COMMAND, + .asc = 0x29, /* BUS DEVICE RESET FUNCTION OCCURRED */ + .ascq = 0x03, + }, + [TCM_INCORRECT_AMOUNT_OF_DATA] = { + .key = ABORTED_COMMAND, + .asc = 0x0c, /* WRITE ERROR */ + .ascq = 0x0d, /* NOT ENOUGH UNSOLICITED DATA */ + }, + [TCM_INVALID_CDB_FIELD] = { + .key = ILLEGAL_REQUEST, + .asc = 0x24, /* INVALID FIELD IN CDB */ + }, + [TCM_INVALID_PARAMETER_LIST] = { + .key = ILLEGAL_REQUEST, + .asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */ + }, + [TCM_PARAMETER_LIST_LENGTH_ERROR] = { + .key = ILLEGAL_REQUEST, + .asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */ + }, + [TCM_UNEXPECTED_UNSOLICITED_DATA] = { + .key = ILLEGAL_REQUEST, + .asc = 0x0c, /* WRITE ERROR */ + .ascq = 0x0c, /* UNEXPECTED_UNSOLICITED_DATA */ + }, + [TCM_SERVICE_CRC_ERROR] = { + .key = ABORTED_COMMAND, + .asc = 0x47, /* PROTOCOL SERVICE CRC ERROR */ + .ascq = 0x05, /* N/A */ + }, + [TCM_SNACK_REJECTED] = { + .key = ABORTED_COMMAND, + .asc = 0x11, /* READ ERROR */ + .ascq = 0x13, /* FAILED RETRANSMISSION REQUEST */ + }, + [TCM_WRITE_PROTECTED] = { + .key = DATA_PROTECT, + .asc = 0x27, /* WRITE PROTECTED */ + }, + [TCM_ADDRESS_OUT_OF_RANGE] = { + .key = ILLEGAL_REQUEST, + .asc = 0x21, /* LOGICAL BLOCK ADDRESS OUT OF RANGE */ + }, + [TCM_CHECK_CONDITION_UNIT_ATTENTION] = { + .key = UNIT_ATTENTION, + }, + [TCM_CHECK_CONDITION_NOT_READY] = { + .key = NOT_READY, + }, + [TCM_MISCOMPARE_VERIFY] = { + .key = MISCOMPARE, + .asc = 0x1d, /* MISCOMPARE DURING VERIFY OPERATION */ + .ascq = 0x00, + }, + [TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED] = { + .key = ILLEGAL_REQUEST, + .asc = 0x10, + .ascq = 0x01, /* LOGICAL BLOCK GUARD CHECK FAILED */ + .add_sector_info = true, + }, + [TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED] = { + .key = ILLEGAL_REQUEST, + .asc = 0x10, + .ascq = 0x02, /* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */ + .add_sector_info = true, + }, + [TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED] = { + .key = ILLEGAL_REQUEST, + .asc = 0x10, + .ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */ + .add_sector_info = true, + }, + [TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE] = { + /* + * Returning ILLEGAL REQUEST would cause immediate IO errors on + * Solaris initiators. Returning NOT READY instead means the + * operations will be retried a finite number of times and we + * can survive intermittent errors. + */ + .key = NOT_READY, + .asc = 0x08, /* LOGICAL UNIT COMMUNICATION FAILURE */ + }, +}; + +static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) +{ + const struct sense_info *si; + u8 *buffer = cmd->sense_buffer; + int r = (__force int)reason; + u8 asc, ascq; + + if (r < ARRAY_SIZE(sense_info_table) && sense_info_table[r].key) + si = &sense_info_table[r]; + else + si = &sense_info_table[(__force int) + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE]; + + buffer[SPC_SENSE_KEY_OFFSET] = si->key; + if (reason == TCM_CHECK_CONDITION_UNIT_ATTENTION) { + core_scsi3_ua_for_check_condition(cmd, &asc, &ascq); + WARN_ON_ONCE(asc == 0); + } else if (si->asc == 0) { + WARN_ON_ONCE(cmd->scsi_asc == 0); + asc = cmd->scsi_asc; + ascq = cmd->scsi_ascq; + } else { + asc = si->asc; + ascq = si->ascq; + } + buffer[SPC_ASC_KEY_OFFSET] = asc; + buffer[SPC_ASCQ_KEY_OFFSET] = ascq; + if (si->add_sector_info) + transport_err_sector_info(cmd->sense_buffer, cmd->bad_sector); +} + int transport_send_check_condition_and_sense(struct se_cmd *cmd, sense_reason_t reason, int from_transport) { - unsigned char *buffer = cmd->sense_buffer; unsigned long flags; - u8 asc = 0, ascq = 0; spin_lock_irqsave(&cmd->t_state_lock, flags); if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { @@ -2644,242 +2786,13 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, cmd->se_cmd_flags |= SCF_SENT_CHECK_CONDITION; spin_unlock_irqrestore(&cmd->t_state_lock, flags); - if (!reason && from_transport) - goto after_reason; - - if (!from_transport) + if (!from_transport) { cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; - - /* - * Actual SENSE DATA, see SPC-3 7.23.2 SPC_SENSE_KEY_OFFSET uses - * SENSE KEY values from include/scsi/scsi.h - */ - switch (reason) { - case TCM_NO_SENSE: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* Not Ready */ - buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; - /* NO ADDITIONAL SENSE INFORMATION */ - buffer[SPC_ASC_KEY_OFFSET] = 0; - buffer[SPC_ASCQ_KEY_OFFSET] = 0; - break; - case TCM_NON_EXISTENT_LUN: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* LOGICAL UNIT NOT SUPPORTED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x25; - break; - case TCM_UNSUPPORTED_SCSI_OPCODE: - case TCM_SECTOR_COUNT_TOO_MANY: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* INVALID COMMAND OPERATION CODE */ - buffer[SPC_ASC_KEY_OFFSET] = 0x20; - break; - case TCM_UNKNOWN_MODE_PAGE: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* INVALID FIELD IN CDB */ - buffer[SPC_ASC_KEY_OFFSET] = 0x24; - break; - case TCM_CHECK_CONDITION_ABORT_CMD: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; - /* BUS DEVICE RESET FUNCTION OCCURRED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x29; - buffer[SPC_ASCQ_KEY_OFFSET] = 0x03; - break; - case TCM_INCORRECT_AMOUNT_OF_DATA: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; - /* WRITE ERROR */ - buffer[SPC_ASC_KEY_OFFSET] = 0x0c; - /* NOT ENOUGH UNSOLICITED DATA */ - buffer[SPC_ASCQ_KEY_OFFSET] = 0x0d; - break; - case TCM_INVALID_CDB_FIELD: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* INVALID FIELD IN CDB */ - buffer[SPC_ASC_KEY_OFFSET] = 0x24; - break; - case TCM_INVALID_PARAMETER_LIST: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* INVALID FIELD IN PARAMETER LIST */ - buffer[SPC_ASC_KEY_OFFSET] = 0x26; - break; - case TCM_PARAMETER_LIST_LENGTH_ERROR: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* PARAMETER LIST LENGTH ERROR */ - buffer[SPC_ASC_KEY_OFFSET] = 0x1a; - break; - case TCM_UNEXPECTED_UNSOLICITED_DATA: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; - /* WRITE ERROR */ - buffer[SPC_ASC_KEY_OFFSET] = 0x0c; - /* UNEXPECTED_UNSOLICITED_DATA */ - buffer[SPC_ASCQ_KEY_OFFSET] = 0x0c; - break; - case TCM_SERVICE_CRC_ERROR: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; - /* PROTOCOL SERVICE CRC ERROR */ - buffer[SPC_ASC_KEY_OFFSET] = 0x47; - /* N/A */ - buffer[SPC_ASCQ_KEY_OFFSET] = 0x05; - break; - case TCM_SNACK_REJECTED: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; - /* READ ERROR */ - buffer[SPC_ASC_KEY_OFFSET] = 0x11; - /* FAILED RETRANSMISSION REQUEST */ - buffer[SPC_ASCQ_KEY_OFFSET] = 0x13; - break; - case TCM_WRITE_PROTECTED: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* DATA PROTECT */ - buffer[SPC_SENSE_KEY_OFFSET] = DATA_PROTECT; - /* WRITE PROTECTED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x27; - break; - case TCM_ADDRESS_OUT_OF_RANGE: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* LOGICAL BLOCK ADDRESS OUT OF RANGE */ - buffer[SPC_ASC_KEY_OFFSET] = 0x21; - break; - case TCM_CHECK_CONDITION_UNIT_ATTENTION: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* UNIT ATTENTION */ - buffer[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; - core_scsi3_ua_for_check_condition(cmd, &asc, &ascq); - buffer[SPC_ASC_KEY_OFFSET] = asc; - buffer[SPC_ASCQ_KEY_OFFSET] = ascq; - break; - case TCM_CHECK_CONDITION_NOT_READY: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* Not Ready */ - buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; - buffer[SPC_ASC_KEY_OFFSET] = cmd->scsi_asc; - buffer[SPC_ASCQ_KEY_OFFSET] = cmd->scsi_ascq; - break; - case TCM_MISCOMPARE_VERIFY: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - buffer[SPC_SENSE_KEY_OFFSET] = MISCOMPARE; - /* MISCOMPARE DURING VERIFY OPERATION */ - buffer[SPC_ASC_KEY_OFFSET] = 0x1d; - buffer[SPC_ASCQ_KEY_OFFSET] = 0x00; - break; - case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* LOGICAL BLOCK GUARD CHECK FAILED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x10; - buffer[SPC_ASCQ_KEY_OFFSET] = 0x01; - transport_err_sector_info(buffer, cmd->bad_sector); - break; - case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x10; - buffer[SPC_ASCQ_KEY_OFFSET] = 0x02; - transport_err_sector_info(buffer, cmd->bad_sector); - break; - case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x10; - buffer[SPC_ASCQ_KEY_OFFSET] = 0x03; - transport_err_sector_info(buffer, cmd->bad_sector); - break; - case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: - default: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* - * Returning ILLEGAL REQUEST would cause immediate IO errors on - * Solaris initiators. Returning NOT READY instead means the - * operations will be retried a finite number of times and we - * can survive intermittent errors. - */ - buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; - /* LOGICAL UNIT COMMUNICATION FAILURE */ - buffer[SPC_ASC_KEY_OFFSET] = 0x08; - break; + translate_sense_reason(cmd, reason); + cmd->scsi_status = SAM_STAT_CHECK_CONDITION; + cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; } - /* - * This code uses linux/include/scsi/scsi.h SAM status codes! - */ - cmd->scsi_status = SAM_STAT_CHECK_CONDITION; - /* - * Automatically padded, this value is encoded in the fabric's - * data_length response PDU containing the SCSI defined sense data. - */ - cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; -after_reason: trace_target_cmd_complete(cmd); return cmd->se_tfo->queue_status(cmd); } -- cgit v1.3-6-gb490 From 7708c1656552ddd60b9b9df3a9ee156acd1801ba Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 8 Jul 2015 17:58:52 +0300 Subject: scsi: Move sense handling routines to scsi_common Sense data handling is also done in the target stack. Hence, move sense handling routines to scsi_common so the target will be able to use them as well. Signed-off-by: Sagi Grimberg Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/scsi/scsi_common.c | 98 +++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/scsi_error.c | 99 +--------------------------------------------- include/scsi/scsi_common.h | 5 +++ include/scsi/scsi_eh.h | 7 +--- 4 files changed, 105 insertions(+), 104 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_common.c b/drivers/scsi/scsi_common.c index 2ff092252b76..41432c10dda2 100644 --- a/drivers/scsi/scsi_common.c +++ b/drivers/scsi/scsi_common.c @@ -5,6 +5,7 @@ #include #include #include +#include #include /* NB: These are exposed through /proc/scsi/scsi and form part of the ABI. @@ -176,3 +177,100 @@ bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len, return true; } EXPORT_SYMBOL(scsi_normalize_sense); + +/** + * scsi_sense_desc_find - search for a given descriptor type in descriptor sense data format. + * @sense_buffer: byte array of descriptor format sense data + * @sb_len: number of valid bytes in sense_buffer + * @desc_type: value of descriptor type to find + * (e.g. 0 -> information) + * + * Notes: + * only valid when sense data is in descriptor format + * + * Return value: + * pointer to start of (first) descriptor if found else NULL + */ +const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, + int desc_type) +{ + int add_sen_len, add_len, desc_len, k; + const u8 * descp; + + if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7]))) + return NULL; + if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73)) + return NULL; + add_sen_len = (add_sen_len < (sb_len - 8)) ? + add_sen_len : (sb_len - 8); + descp = &sense_buffer[8]; + for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) { + descp += desc_len; + add_len = (k < (add_sen_len - 1)) ? descp[1]: -1; + desc_len = add_len + 2; + if (descp[0] == desc_type) + return descp; + if (add_len < 0) // short descriptor ?? + break; + } + return NULL; +} +EXPORT_SYMBOL(scsi_sense_desc_find); + +/** + * scsi_build_sense_buffer - build sense data in a buffer + * @desc: Sense format (non zero == descriptor format, + * 0 == fixed format) + * @buf: Where to build sense data + * @key: Sense key + * @asc: Additional sense code + * @ascq: Additional sense code qualifier + * + **/ +void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq) +{ + if (desc) { + buf[0] = 0x72; /* descriptor, current */ + buf[1] = key; + buf[2] = asc; + buf[3] = ascq; + buf[7] = 0; + } else { + buf[0] = 0x70; /* fixed, current */ + buf[2] = key; + buf[7] = 0xa; + buf[12] = asc; + buf[13] = ascq; + } +} +EXPORT_SYMBOL(scsi_build_sense_buffer); + +/** + * scsi_set_sense_information - set the information field in a + * formatted sense data buffer + * @buf: Where to build sense data + * @info: 64-bit information value to be set + * + **/ +void scsi_set_sense_information(u8 *buf, u64 info) +{ + if ((buf[0] & 0x7f) == 0x72) { + u8 *ucp, len; + + len = buf[7]; + ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0); + if (!ucp) { + buf[7] = len + 0xa; + ucp = buf + 8 + len; + } + ucp[0] = 0; + ucp[1] = 0xa; + ucp[2] = 0x80; /* Valid bit */ + ucp[3] = 0; + put_unaligned_be64(info, &ucp[4]); + } else if ((buf[0] & 0x7f) == 0x70) { + buf[0] |= 0x80; + put_unaligned_be64(info, &buf[3]); + } +} +EXPORT_SYMBOL(scsi_set_sense_information); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 106884a5444e..6e6b2d26d3ce 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -34,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -2407,45 +2407,6 @@ bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd, } EXPORT_SYMBOL(scsi_command_normalize_sense); -/** - * scsi_sense_desc_find - search for a given descriptor type in descriptor sense data format. - * @sense_buffer: byte array of descriptor format sense data - * @sb_len: number of valid bytes in sense_buffer - * @desc_type: value of descriptor type to find - * (e.g. 0 -> information) - * - * Notes: - * only valid when sense data is in descriptor format - * - * Return value: - * pointer to start of (first) descriptor if found else NULL - */ -const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, - int desc_type) -{ - int add_sen_len, add_len, desc_len, k; - const u8 * descp; - - if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7]))) - return NULL; - if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73)) - return NULL; - add_sen_len = (add_sen_len < (sb_len - 8)) ? - add_sen_len : (sb_len - 8); - descp = &sense_buffer[8]; - for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) { - descp += desc_len; - add_len = (k < (add_sen_len - 1)) ? descp[1]: -1; - desc_len = add_len + 2; - if (descp[0] == desc_type) - return descp; - if (add_len < 0) // short descriptor ?? - break; - } - return NULL; -} -EXPORT_SYMBOL(scsi_sense_desc_find); - /** * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format) * @sense_buffer: byte array of sense data @@ -2495,61 +2456,3 @@ int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, } } EXPORT_SYMBOL(scsi_get_sense_info_fld); - -/** - * scsi_build_sense_buffer - build sense data in a buffer - * @desc: Sense format (non zero == descriptor format, - * 0 == fixed format) - * @buf: Where to build sense data - * @key: Sense key - * @asc: Additional sense code - * @ascq: Additional sense code qualifier - * - **/ -void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq) -{ - if (desc) { - buf[0] = 0x72; /* descriptor, current */ - buf[1] = key; - buf[2] = asc; - buf[3] = ascq; - buf[7] = 0; - } else { - buf[0] = 0x70; /* fixed, current */ - buf[2] = key; - buf[7] = 0xa; - buf[12] = asc; - buf[13] = ascq; - } -} -EXPORT_SYMBOL(scsi_build_sense_buffer); - -/** - * scsi_set_sense_information - set the information field in a - * formatted sense data buffer - * @buf: Where to build sense data - * @info: 64-bit information value to be set - * - **/ -void scsi_set_sense_information(u8 *buf, u64 info) -{ - if ((buf[0] & 0x7f) == 0x72) { - u8 *ucp, len; - - len = buf[7]; - ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0); - if (!ucp) { - buf[7] = len + 0xa; - ucp = buf + 8 + len; - } - ucp[0] = 0; - ucp[1] = 0xa; - ucp[2] = 0x80; /* Valid bit */ - ucp[3] = 0; - put_unaligned_be64(info, &ucp[4]); - } else if ((buf[0] & 0x7f) == 0x70) { - buf[0] |= 0x80; - put_unaligned_be64(info, &buf[3]); - } -} -EXPORT_SYMBOL(scsi_set_sense_information); diff --git a/include/scsi/scsi_common.h b/include/scsi/scsi_common.h index 676b03b78e57..156d673db900 100644 --- a/include/scsi/scsi_common.h +++ b/include/scsi/scsi_common.h @@ -61,4 +61,9 @@ static inline bool scsi_sense_valid(const struct scsi_sense_hdr *sshdr) extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len, struct scsi_sense_hdr *sshdr); +extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); +extern void scsi_set_sense_information(u8 *buf, u64 info); +extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, + int desc_type); + #endif /* _SCSI_COMMON_H_ */ diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index 4942710ef720..dbb8c640e26f 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -4,6 +4,7 @@ #include #include +#include struct scsi_device; struct Scsi_Host; @@ -21,15 +22,9 @@ static inline bool scsi_sense_is_deferred(const struct scsi_sense_hdr *sshdr) return ((sshdr->response_code >= 0x70) && (sshdr->response_code & 1)); } -extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, - int desc_type); - extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, u64 * info_out); -extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); -extern void scsi_set_sense_information(u8 *buf, u64 info); - extern int scsi_ioctl_reset(struct scsi_device *, int __user *); struct scsi_eh_save { -- cgit v1.3-6-gb490 From 9ec1e1ce3a0f854b9150e7888a373392fbbe7442 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 8 Jul 2015 17:58:53 +0300 Subject: target: Use scsi helpers to build the sense data correctly Instead of open coding the sense buffer construction, use scsi scsi_build_sense_buffer() and scsi_set_sense_information() helpers which moved to scsi_common. Signed-off-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_spc.c | 31 +++++-------------------------- drivers/target/target_core_transport.c | 21 ++++----------------- 2 files changed, 9 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index b0744433315a..c43dcbf2d48e 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1157,32 +1157,11 @@ static sense_reason_t spc_emulate_request_sense(struct se_cmd *cmd) if (!rbuf) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { - /* - * CURRENT ERROR, UNIT ATTENTION - */ - buf[0] = 0x70; - buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; - - /* - * The Additional Sense Code (ASC) from the UNIT ATTENTION - */ - buf[SPC_ASC_KEY_OFFSET] = ua_asc; - buf[SPC_ASCQ_KEY_OFFSET] = ua_ascq; - buf[7] = 0x0A; - } else { - /* - * CURRENT ERROR, NO SENSE - */ - buf[0] = 0x70; - buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE; - - /* - * NO ADDITIONAL SENSE INFORMATION - */ - buf[SPC_ASC_KEY_OFFSET] = 0x00; - buf[7] = 0x0A; - } + if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) + scsi_build_sense_buffer(0, buf, UNIT_ATTENTION, + ua_asc, ua_ascq); + else + scsi_build_sense_buffer(0, buf, NO_SENSE, 0x0, 0x0); memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); transport_kunmap_data_sg(cmd); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 6ef44c9db381..f528a9def65a 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -2615,19 +2616,6 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) } EXPORT_SYMBOL(transport_wait_for_tasks); -static -void transport_err_sector_info(unsigned char *buffer, sector_t bad_sector) -{ - /* Place failed LBA in sense data information descriptor 0. */ - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 0xc; - buffer[SPC_DESC_TYPE_OFFSET] = 0; /* Information */ - buffer[SPC_ADDITIONAL_DESC_LEN_OFFSET] = 0xa; - buffer[SPC_VALIDITY_OFFSET] = 0x80; - - /* Descriptor Information: failing sector */ - put_unaligned_be64(bad_sector, &buffer[12]); -} - struct sense_info { u8 key; u8 asc; @@ -2754,7 +2742,6 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) si = &sense_info_table[(__force int) TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE]; - buffer[SPC_SENSE_KEY_OFFSET] = si->key; if (reason == TCM_CHECK_CONDITION_UNIT_ATTENTION) { core_scsi3_ua_for_check_condition(cmd, &asc, &ascq); WARN_ON_ONCE(asc == 0); @@ -2766,10 +2753,10 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) asc = si->asc; ascq = si->ascq; } - buffer[SPC_ASC_KEY_OFFSET] = asc; - buffer[SPC_ASCQ_KEY_OFFSET] = ascq; + + scsi_build_sense_buffer(0, buffer, si->key, asc, ascq); if (si->add_sector_info) - transport_err_sector_info(cmd->sense_buffer, cmd->bad_sector); + scsi_set_sense_information(buffer, cmd->bad_sector); } int -- cgit v1.3-6-gb490 From 734ca5c467842186bf836d0b33379a51cfe259da Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 8 Jul 2015 17:58:54 +0300 Subject: target: Return ABORTED_COMMAND sense key for PI errors PI errors were reported with ILLEGAL_REQUEST sense key but there was actually no problem with the request. Target detected PI errors should be reported with aborted command sense key. Signed-off-by: Sagi Grimberg Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index f528a9def65a..2bece607ca0f 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2700,19 +2700,19 @@ static const struct sense_info sense_info_table[] = { .ascq = 0x00, }, [TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED] = { - .key = ILLEGAL_REQUEST, + .key = ABORTED_COMMAND, .asc = 0x10, .ascq = 0x01, /* LOGICAL BLOCK GUARD CHECK FAILED */ .add_sector_info = true, }, [TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED] = { - .key = ILLEGAL_REQUEST, + .key = ABORTED_COMMAND, .asc = 0x10, .ascq = 0x02, /* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */ .add_sector_info = true, }, [TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED] = { - .key = ILLEGAL_REQUEST, + .key = ABORTED_COMMAND, .asc = 0x10, .ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */ .add_sector_info = true, -- cgit v1.3-6-gb490 From 3e963b2d3c93e0546e911d681f37d35f0f79b54f Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:33:07 -0700 Subject: tcm_qla2xxx: Remove set-but-not-used variables Detected these by building with W=1. This patch does not change any functionality. Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Cc: Quinn Tran Cc: Saurav Kashyap Signed-off-by: Nicholas Bellinger --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index d9a8c6084346..474d0c0e6dba 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1367,9 +1367,7 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) struct qla_hw_data *ha = tgt->ha; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); struct se_session *se_sess; - struct se_node_acl *se_nacl; struct tcm_qla2xxx_lport *lport; - struct tcm_qla2xxx_nacl *nacl; BUG_ON(in_interrupt()); @@ -1379,8 +1377,6 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) dump_stack(); return; } - se_nacl = se_sess->se_node_acl; - nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); lport = vha->vha_tgt.target_lport_ptr; if (!lport) { @@ -1684,7 +1680,6 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha, (struct tcm_qla2xxx_lport *)target_lport_ptr; struct tcm_qla2xxx_lport *base_lport = (struct tcm_qla2xxx_lport *)base_vha->vha_tgt.target_lport_ptr; - struct tcm_qla2xxx_tpg *base_tpg; struct fc_vport_identifiers vport_id; if (!qla_tgt_mode_enabled(base_vha)) { @@ -1697,7 +1692,6 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha, pr_err("qla2xxx base_lport or tpg_1 not available\n"); return -EPERM; } - base_tpg = base_lport->tpg_1; memset(&vport_id, 0, sizeof(vport_id)); vport_id.port_name = npiv_wwpn; -- cgit v1.3-6-gb490 From 12306b425d0dbab7b60f54e02d67cf3dfae494d1 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 15 Jul 2015 10:55:36 +0300 Subject: scsi: Fix wrong additional sense length in descriptor format The sense header additional sense length should be the accumulated size of all the descriptors. Information descriptor size is 12 bytes. When setting the additional sense length we should add 0xc instead of 0xa. Signed-off-by: Sagi Grimberg Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Reviewed-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/scsi/scsi_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_common.c b/drivers/scsi/scsi_common.c index 41432c10dda2..ee6bdf43a8ea 100644 --- a/drivers/scsi/scsi_common.c +++ b/drivers/scsi/scsi_common.c @@ -260,7 +260,7 @@ void scsi_set_sense_information(u8 *buf, u64 info) len = buf[7]; ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0); if (!ucp) { - buf[7] = len + 0xa; + buf[7] = len + 0xc; ucp = buf + 8 + len; } ucp[0] = 0; -- cgit v1.3-6-gb490 From f5a8b3a796db01b639435515b3adc003b9f27387 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 15 Jul 2015 10:55:37 +0300 Subject: scsi: Protect against buffer possible overflow in scsi_set_sense_information Make sure that the input sense buffer has sufficient length to fit the information descriptor (12 additional bytes). Modify scsi_set_sense_information to receive the sense buffer length and adjust its callers scsi target and libata. (Fix patch fuzz in scsi_set_sense_information - nab) Reported-by: Hannes Reinecke Signed-off-by: Sagi Grimberg Reviewed-by: Martin K. Petersen Cc: Tejun Heo Reviewed-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/ata/libata-scsi.c | 4 +++- drivers/scsi/scsi_common.c | 13 ++++++++++++- drivers/target/target_core_transport.c | 14 +++++++++++--- include/scsi/scsi_common.h | 2 +- 4 files changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 3131adcc1f87..2fb7c79e727f 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -289,7 +289,9 @@ void ata_scsi_set_sense_information(struct scsi_cmnd *cmd, return; information = ata_tf_read_block(tf, NULL); - scsi_set_sense_information(cmd->sense_buffer, information); + scsi_set_sense_information(cmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE, + information); } static ssize_t diff --git a/drivers/scsi/scsi_common.c b/drivers/scsi/scsi_common.c index ee6bdf43a8ea..c126966130ab 100644 --- a/drivers/scsi/scsi_common.c +++ b/drivers/scsi/scsi_common.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -249,10 +250,13 @@ EXPORT_SYMBOL(scsi_build_sense_buffer); * scsi_set_sense_information - set the information field in a * formatted sense data buffer * @buf: Where to build sense data + * @buf_len: buffer length * @info: 64-bit information value to be set * + * Return value: + * 0 on success or EINVAL for invalid sense buffer length **/ -void scsi_set_sense_information(u8 *buf, u64 info) +int scsi_set_sense_information(u8 *buf, int buf_len, u64 info) { if ((buf[0] & 0x7f) == 0x72) { u8 *ucp, len; @@ -263,6 +267,11 @@ void scsi_set_sense_information(u8 *buf, u64 info) buf[7] = len + 0xc; ucp = buf + 8 + len; } + + if (buf_len < len + 0xc) + /* Not enough room for info */ + return -EINVAL; + ucp[0] = 0; ucp[1] = 0xa; ucp[2] = 0x80; /* Valid bit */ @@ -272,5 +281,7 @@ void scsi_set_sense_information(u8 *buf, u64 info) buf[0] |= 0x80; put_unaligned_be64(info, &buf[3]); } + + return 0; } EXPORT_SYMBOL(scsi_set_sense_information); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 2bece607ca0f..7fb031bbcc8d 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2729,7 +2729,7 @@ static const struct sense_info sense_info_table[] = { }, }; -static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) +static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) { const struct sense_info *si; u8 *buffer = cmd->sense_buffer; @@ -2756,7 +2756,11 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) scsi_build_sense_buffer(0, buffer, si->key, asc, ascq); if (si->add_sector_info) - scsi_set_sense_information(buffer, cmd->bad_sector); + return scsi_set_sense_information(buffer, + cmd->scsi_sense_length, + cmd->bad_sector); + + return 0; } int @@ -2774,10 +2778,14 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, spin_unlock_irqrestore(&cmd->t_state_lock, flags); if (!from_transport) { + int rc; + cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; - translate_sense_reason(cmd, reason); cmd->scsi_status = SAM_STAT_CHECK_CONDITION; cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; + rc = translate_sense_reason(cmd, reason); + if (rc) + return rc; } trace_target_cmd_complete(cmd); diff --git a/include/scsi/scsi_common.h b/include/scsi/scsi_common.h index 156d673db900..11571b2a831e 100644 --- a/include/scsi/scsi_common.h +++ b/include/scsi/scsi_common.h @@ -62,7 +62,7 @@ extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len, struct scsi_sense_hdr *sshdr); extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); -extern void scsi_set_sense_information(u8 *buf, u64 info); +int scsi_set_sense_information(u8 *buf, int buf_len, u64 info); extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, int desc_type); -- cgit v1.3-6-gb490 From 4e4937e8aefde8d49340e803ebbedcdf4b43e5f0 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 16 Jul 2015 10:28:05 +0300 Subject: target: Return descriptor format sense data in case the LU spans 64bit sectors In case a LU spans 64bit sectors, fixed size sense data information field is only 32 bits which means the sector information will be truncated. Thus, if the LU spans 64bit sectors, use descriptor format sense data to correctly report sector information. Reported-by: Christoph Hellwig Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_hba.c | 5 +++++ drivers/target/target_core_spc.c | 12 +++++++++--- drivers/target/target_core_transport.c | 3 ++- include/target/target_core_backend.h | 2 ++ 4 files changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index 62ea4e8e70a8..d746a3a4a623 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -176,3 +176,8 @@ core_delete_hba(struct se_hba *hba) kfree(hba); return 0; } + +bool target_sense_desc_format(struct se_device *dev) +{ + return dev->transport->get_blocks(dev) > U32_MAX; +} diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index c43dcbf2d48e..b949d335a6ba 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -761,7 +761,12 @@ static int spc_modesense_control(struct se_cmd *cmd, u8 pc, u8 *p) if (pc == 1) goto out; - p[2] = 2; + /* GLTSD: No implicit save of log parameters */ + p[2] = (1 << 1); + if (target_sense_desc_format(dev)) + /* D_SENSE: Descriptor format sense data for 64bit sectors */ + p[2] |= (1 << 2); + /* * From spc4r23, 7.4.7 Control mode page * @@ -1144,6 +1149,7 @@ static sense_reason_t spc_emulate_request_sense(struct se_cmd *cmd) unsigned char *rbuf; u8 ua_asc = 0, ua_ascq = 0; unsigned char buf[SE_SENSE_BUF]; + bool desc_format = target_sense_desc_format(cmd->se_dev); memset(buf, 0, SE_SENSE_BUF); @@ -1158,10 +1164,10 @@ static sense_reason_t spc_emulate_request_sense(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) - scsi_build_sense_buffer(0, buf, UNIT_ATTENTION, + scsi_build_sense_buffer(desc_format, buf, UNIT_ATTENTION, ua_asc, ua_ascq); else - scsi_build_sense_buffer(0, buf, NO_SENSE, 0x0, 0x0); + scsi_build_sense_buffer(desc_format, buf, NO_SENSE, 0x0, 0x0); memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); transport_kunmap_data_sg(cmd); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7fb031bbcc8d..98155db28365 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2735,6 +2735,7 @@ static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) u8 *buffer = cmd->sense_buffer; int r = (__force int)reason; u8 asc, ascq; + bool desc_format = target_sense_desc_format(cmd->se_dev); if (r < ARRAY_SIZE(sense_info_table) && sense_info_table[r].key) si = &sense_info_table[r]; @@ -2754,7 +2755,7 @@ static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) ascq = si->ascq; } - scsi_build_sense_buffer(0, buffer, si->key, asc, ascq); + scsi_build_sense_buffer(desc_format, buffer, si->key, asc, ascq); if (si->add_sector_info) return scsi_set_sense_information(buffer, cmd->scsi_sense_length, diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 1e5c8f949bae..56cf8e485ef2 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -93,4 +93,6 @@ bool target_lun_is_rdonly(struct se_cmd *); sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd, sense_reason_t (*exec_cmd)(struct se_cmd *cmd)); +bool target_sense_desc_format(struct se_device *dev); + #endif /* TARGET_CORE_BACKEND_H */ -- cgit v1.3-6-gb490 From a73c2a2f9123605022bedbd2b59ca7e76036f0b3 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 15 Jul 2015 10:55:39 +0300 Subject: libiscsi: Use scsi helper to set information descriptor In case encountered a PI error, use scsi_set_sense_information instead of open coding information descriptor format. Signed-off-by: Sagi Grimberg Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/scsi/libiscsi.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 8053f24f0349..bb5ca7f3d16d 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -853,12 +853,9 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 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]); + scsi_set_sense_information(sc->sense_buffer, + SCSI_SENSE_BUFFERSIZE, + sector); goto out; } } -- cgit v1.3-6-gb490 From acd195800ffca556e9c78c51d1efe534d71dd236 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 10 Jul 2015 14:31:20 +0530 Subject: ath10k: delay device access after cold reset It is observed that during cold reset pcie access right after a write operation to SOC_GLOBAL_RESET_ADDRESS causes Data Bus Error and system hard lockup. The reason for bus error is that pcie needs some time to get back to stable state for any transaction during cold reset. Add delay of 20 msecs after write of SOC_GLOBAL_RESET_ADDRESS to fix this issue. This patch is tested on QCA988X. This is also tested on QCA99X0 which is WIP. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 5778e5277823..a69bfa41c68b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2761,7 +2761,6 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) static int ath10k_pci_cold_reset(struct ath10k *ar) { - int i; u32 val; ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n"); @@ -2777,23 +2776,18 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) val |= 1; ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); - for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { - if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) & - RTC_STATE_COLD_RESET_MASK) - break; - msleep(1); - } + /* After writing into SOC_GLOBAL_RESET to put device into + * reset and pulling out of reset pcie may not be stable + * for any immediate pcie register access and cause bus error, + * add delay before any pcie access request to fix this issue. + */ + msleep(20); /* Pull Target, including PCIe, out of RESET. */ val &= ~1; ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); - for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { - if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) & - RTC_STATE_COLD_RESET_MASK)) - break; - msleep(1); - } + msleep(20); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n"); -- cgit v1.3-6-gb490 From fbc03a466fd48bc8be2e675be948001feea29e4d Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Wed, 15 Jul 2015 19:01:19 -0700 Subject: ath10k: update tx path to support QCA99X0 Since QCA99X0 uses fragmentation descriptor differently from other ones on tx path, we need to handle it separately. QCA99X0 is using 48 bits for address and 16 bits for length out of 2 dword and each values have to be programmed by frag desc base addr + msdu id, so that hardware can retrieve corresponding frag data. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 13 ++++++++++-- drivers/net/wireless/ath/ath10k/htt_tx.c | 35 +++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 8bdf1e7dd171..e31cd74dded6 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -83,8 +83,17 @@ struct htt_ver_req { * around the mask + shift defs. */ struct htt_data_tx_desc_frag { - __le32 paddr; - __le32 len; + union { + struct double_word_addr { + __le32 paddr; + __le32 len; + } __packed dword_addr; + struct triple_word_addr { + __le32 paddr_lo; + __le16 paddr_hi; + __le16 len_16; + } __packed tword_addr; + } __packed; } __packed; struct htt_msdu_ext_desc { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 148d5b607c3c..c49ecffc2905 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -63,7 +63,8 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb) lockdep_assert_held(&htt->tx_lock); - ret = idr_alloc(&htt->pending_tx, skb, 0, 0x10000, GFP_ATOMIC); + ret = idr_alloc(&htt->pending_tx, skb, 0, + htt->max_num_pending_tx, GFP_ATOMIC); ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret); @@ -259,6 +260,7 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt) cmd->frag_desc_bank_cfg.desc_size = sizeof(struct htt_msdu_ext_desc); cmd->frag_desc_bank_cfg.bank_base_addrs[0] = __cpu_to_le32(htt->frag_desc.paddr); + cmd->frag_desc_bank_cfg.bank_id[0].bank_min_id = 0; cmd->frag_desc_bank_cfg.bank_id[0].bank_max_id = __cpu_to_le16(htt->max_num_pending_tx - 1); @@ -537,16 +539,29 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; /* pass through */ case ATH10K_HW_TXRX_ETHERNET: - frags = skb_cb->htt.txbuf->frags; - - frags[0].paddr = __cpu_to_le32(skb_cb->paddr); - frags[0].len = __cpu_to_le32(msdu->len); - frags[1].paddr = 0; - frags[1].len = 0; - + if (ar->hw_params.continuous_frag_desc) { + frags = (struct htt_data_tx_desc_frag *) + &htt->frag_desc.vaddr[msdu_id].frags; + frags[0].tword_addr.paddr_lo = + __cpu_to_le32(skb_cb->paddr); + frags[0].tword_addr.paddr_hi = 0; + frags[0].tword_addr.len_16 = __cpu_to_le16(msdu->len); + frags[1].tword_addr.paddr_lo = 0; + frags[1].tword_addr.paddr_hi = 0; + + frags_paddr = htt->frag_desc.paddr + + (sizeof(struct htt_msdu_ext_desc) * msdu_id); + } else { + frags = skb_cb->htt.txbuf->frags; + frags[0].dword_addr.paddr = + __cpu_to_le32(skb_cb->paddr); + frags[0].dword_addr.len = __cpu_to_le32(msdu->len); + frags[1].dword_addr.paddr = 0; + frags[1].dword_addr.len = 0; + + frags_paddr = skb_cb->htt.txbuf_paddr; + } flags0 |= SM(skb_cb->txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - - frags_paddr = skb_cb->htt.txbuf_paddr; break; case ATH10K_HW_TXRX_MGMT: flags0 |= SM(ATH10K_HW_TXRX_MGMT, -- cgit v1.3-6-gb490 From 05a2cb0daa49af4e240834ff3736fd35ba83320f Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Wed, 15 Jul 2015 19:01:20 -0700 Subject: ath10k: redefine rx_ppdu_end_common structure to cover qca99x0 rx_ppdu_end_common structure is valid for both of qca998x and qca6174, but not for qca99x0 since it has new additional members. Hence update the common structure to cover qca99x0 as well. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/rx_desc.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 492b5a5af434..6cb078d6c3cc 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -891,13 +891,13 @@ struct rx_ppdu_end_common { __le32 evm_p15; __le32 tsf_timestamp; __le32 wb_timestamp; +} __packed; + +struct rx_ppdu_end_qca988x { u8 locationing_timestamp; u8 phy_err_code; __le16 flags; /* %RX_PPDU_END_FLAGS_ */ __le32 info0; /* %RX_PPDU_END_INFO0_ */ -} __packed; - -struct rx_ppdu_end_qca988x { __le16 bb_length; __le16 info1; /* %RX_PPDU_END_INFO1_ */ } __packed; @@ -909,6 +909,10 @@ struct rx_ppdu_end_qca988x { #define RX_PPDU_END_RTT_NORMAL_MODE BIT(31) struct rx_ppdu_end_qca6174 { + u8 locationing_timestamp; + u8 phy_err_code; + __le16 flags; /* %RX_PPDU_END_FLAGS_ */ + __le32 info0; /* %RX_PPDU_END_INFO0_ */ __le32 rtt; /* %RX_PPDU_END_RTT_ */ __le16 bb_length; __le16 info1; /* %RX_PPDU_END_INFO1_ */ -- cgit v1.3-6-gb490 From 1f5dbfbb64c92e1c22305ac2b3951d6e3cf7a9a7 Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Wed, 15 Jul 2015 19:01:21 -0700 Subject: ath10k: add support for qca99x0 Rx descriptors QCA99X0 chip has an extra 4 bytes in rx_msdu_start, 20 bytes in rx_msdu_end and 20 bytes in rx_ppdu_end structure which are used in htt_rx_desc and HTT Rx ring offset setup. This is necessary for correct Rx for QCA99X0 or Rx descriptors will be overwritten and corrupted. With this patch QCA988X and QCA6174 will have extra 44 bytes padding in Rx descriptor layout which is harmless. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 24 ++--- drivers/net/wireless/ath/ath10k/rx_desc.h | 163 +++++++++++++++++++++++++++++- 2 files changed, 172 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index d7d118328f31..61a26264728a 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -368,7 +368,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu_len_invalid = !!(__le32_to_cpu(rx_desc->attention.flags) & (RX_ATTENTION_FLAGS_MPDU_LENGTH_ERR | RX_ATTENTION_FLAGS_MSDU_LENGTH_ERR)); - msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0), + msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.common.info0), RX_MSDU_START_INFO0_MSDU_LENGTH); msdu_chained = rx_desc->frag_info.ring2_more_count; @@ -394,7 +394,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu_chaining = 1; } - last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & + last_msdu = __le32_to_cpu(rx_desc->msdu_end.common.info0) & RX_MSDU_END_INFO0_LAST_MSDU; trace_ath10k_htt_rx_desc(ar, &rx_desc->attention, @@ -740,7 +740,7 @@ ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd) __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID)) return NULL; - if (!(rxd->msdu_end.info0 & + if (!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU))) return NULL; @@ -991,9 +991,9 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar, bool is_last; rxd = (void *)msdu->data - sizeof(*rxd); - is_first = !!(rxd->msdu_end.info0 & + is_first = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); - is_last = !!(rxd->msdu_end.info0 & + is_last = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); /* Delivered decapped frame: @@ -1104,9 +1104,9 @@ static void *ath10k_htt_rx_h_find_rfc1042(struct ath10k *ar, rxd = (void *)msdu->data - sizeof(*rxd); hdr = (void *)rxd->rx_hdr_status; - is_first = !!(rxd->msdu_end.info0 & + is_first = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); - is_last = !!(rxd->msdu_end.info0 & + is_last = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); is_amsdu = !(is_first && is_last); @@ -1214,7 +1214,7 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar, */ rxd = (void *)msdu->data - sizeof(*rxd); - decap = MS(__le32_to_cpu(rxd->msdu_start.info1), + decap = MS(__le32_to_cpu(rxd->msdu_start.common.info1), RX_MSDU_START_INFO1_DECAP_FORMAT); switch (decap) { @@ -1244,7 +1244,7 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) rxd = (void *)skb->data - sizeof(*rxd); flags = __le32_to_cpu(rxd->attention.flags); - info = __le32_to_cpu(rxd->msdu_start.info1); + info = __le32_to_cpu(rxd->msdu_start.common.info1); is_ip4 = !!(info & RX_MSDU_START_INFO1_IPV4_PROTO); is_ip6 = !!(info & RX_MSDU_START_INFO1_IPV6_PROTO); @@ -1437,7 +1437,7 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar, first = skb_peek(amsdu); rxd = (void *)first->data - sizeof(*rxd); - decap = MS(__le32_to_cpu(rxd->msdu_start.info1), + decap = MS(__le32_to_cpu(rxd->msdu_start.common.info1), RX_MSDU_START_INFO1_DECAP_FORMAT); if (!chained) @@ -1757,14 +1757,14 @@ static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list, __skb_queue_tail(amsdu, msdu); rxd = (void *)msdu->data - sizeof(*rxd); - if (rxd->msdu_end.info0 & + if (rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)) break; } msdu = skb_peek_tail(amsdu); rxd = (void *)msdu->data - sizeof(*rxd); - if (!(rxd->msdu_end.info0 & + if (!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))) { skb_queue_splice_init(amsdu, list); return -EAGAIN; diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 6cb078d6c3cc..ca8d16884af1 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -422,6 +422,12 @@ struct rx_mpdu_end { #define RX_MSDU_START_INFO1_IP_FRAG (1 << 14) #define RX_MSDU_START_INFO1_TCP_ONLY_ACK (1 << 15) +#define RX_MSDU_START_INFO2_DA_IDX_MASK 0x000007ff +#define RX_MSDU_START_INFO2_DA_IDX_LSB 0 +#define RX_MSDU_START_INFO2_IP_PROTO_FIELD_MASK 0x00ff0000 +#define RX_MSDU_START_INFO2_IP_PROTO_FIELD_LSB 16 +#define RX_MSDU_START_INFO2_DA_BCAST_MCAST BIT(11) + /* The decapped header (rx_hdr_status) contains the following: * a) 802.11 header * [padding to 4 bytes] @@ -449,12 +455,23 @@ enum rx_msdu_decap_format { RX_MSDU_DECAP_8023_SNAP_LLC = 3 }; -struct rx_msdu_start { +struct rx_msdu_start_common { __le32 info0; /* %RX_MSDU_START_INFO0_ */ __le32 flow_id_crc; __le32 info1; /* %RX_MSDU_START_INFO1_ */ } __packed; +struct rx_msdu_start_qca99x0 { + __le32 info2; /* %RX_MSDU_START_INFO2_ */ +} __packed; + +struct rx_msdu_start { + struct rx_msdu_start_common common; + union { + struct rx_msdu_start_qca99x0 qca99x0; + } __packed; +} __packed; + /* * msdu_length * MSDU length in bytes after decapsulation. This field is @@ -540,7 +557,7 @@ struct rx_msdu_start { #define RX_MSDU_END_INFO0_PRE_DELIM_ERR (1 << 30) #define RX_MSDU_END_INFO0_RESERVED_3B (1 << 31) -struct rx_msdu_end { +struct rx_msdu_end_common { __le16 ip_hdr_cksum; __le16 tcp_hdr_cksum; u8 key_id_octet; @@ -549,6 +566,36 @@ struct rx_msdu_end { __le32 info0; } __packed; +#define RX_MSDU_END_INFO1_TCP_FLAG_MASK 0x000001ff +#define RX_MSDU_END_INFO1_TCP_FLAG_LSB 0 +#define RX_MSDU_END_INFO1_L3_HDR_PAD_MASK 0x00001c00 +#define RX_MSDU_END_INFO1_L3_HDR_PAD_LSB 10 +#define RX_MSDU_END_INFO1_WINDOW_SIZE_MASK 0xffff0000 +#define RX_MSDU_END_INFO1_WINDOW_SIZE_LSB 16 +#define RX_MSDU_END_INFO1_IRO_ELIGIBLE BIT(9) + +#define RX_MSDU_END_INFO2_DA_OFFSET_MASK 0x0000003f +#define RX_MSDU_END_INFO2_DA_OFFSET_LSB 0 +#define RX_MSDU_END_INFO2_SA_OFFSET_MASK 0x00000fc0 +#define RX_MSDU_END_INFO2_SA_OFFSET_LSB 6 +#define RX_MSDU_END_INFO2_TYPE_OFFSET_MASK 0x0003f000 +#define RX_MSDU_END_INFO2_TYPE_OFFSET_LSB 12 + +struct rx_msdu_end_qca99x0 { + __le32 ipv6_crc; + __le32 tcp_seq_no; + __le32 tcp_ack_no; + __le32 info1; + __le32 info2; +} __packed; + +struct rx_msdu_end { + struct rx_msdu_end_common common; + union { + struct rx_msdu_end_qca99x0 qca99x0; + } __packed; +} __packed; + /* *ip_hdr_chksum * This can include the IP header checksum or the pseudo header @@ -870,7 +917,11 @@ struct rx_ppdu_start { #define RX_PPDU_END_INFO0_FLAGS_TX_HT_VHT_ACK (1 << 24) #define RX_PPDU_END_INFO0_BB_CAPTURED_CHANNEL (1 << 25) -#define RX_PPDU_END_INFO1_PPDU_DONE (1 << 15) +#define RX_PPDU_END_INFO1_PEER_IDX_MASK 0x1ffc +#define RX_PPDU_END_INFO1_PEER_IDX_LSB 2 +#define RX_PPDU_END_INFO1_BB_DATA BIT(0) +#define RX_PPDU_END_INFO1_PEER_IDX_VALID BIT(1) +#define RX_PPDU_END_INFO1_PPDU_DONE BIT(15) struct rx_ppdu_end_common { __le32 evm_p0; @@ -918,11 +969,117 @@ struct rx_ppdu_end_qca6174 { __le16 info1; /* %RX_PPDU_END_INFO1_ */ } __packed; +#define RX_PKT_END_INFO0_RX_SUCCESS BIT(0) +#define RX_PKT_END_INFO0_ERR_TX_INTERRUPT_RX BIT(3) +#define RX_PKT_END_INFO0_ERR_OFDM_POWER_DROP BIT(4) +#define RX_PKT_END_INFO0_ERR_OFDM_RESTART BIT(5) +#define RX_PKT_END_INFO0_ERR_CCK_POWER_DROP BIT(6) +#define RX_PKT_END_INFO0_ERR_CCK_RESTART BIT(7) + +#define RX_LOCATION_INFO_RTT_CORR_VAL_MASK 0x0001ffff +#define RX_LOCATION_INFO_RTT_CORR_VAL_LSB 0 +#define RX_LOCATION_INFO_FAC_STATUS_MASK 0x000c0000 +#define RX_LOCATION_INFO_FAC_STATUS_LSB 18 +#define RX_LOCATION_INFO_PKT_BW_MASK 0x00700000 +#define RX_LOCATION_INFO_PKT_BW_LSB 20 +#define RX_LOCATION_INFO_RTT_TX_FRAME_PHASE_MASK 0x01800000 +#define RX_LOCATION_INFO_RTT_TX_FRAME_PHASE_LSB 23 +#define RX_LOCATION_INFO_CIR_STATUS BIT(17) +#define RX_LOCATION_INFO_RTT_MAC_PHY_PHASE BIT(25) +#define RX_LOCATION_INFO_RTT_TX_DATA_START_X BIT(26) +#define RX_LOCATION_INFO_HW_IFFT_MODE BIT(30) +#define RX_LOCATION_INFO_RX_LOCATION_VALID BIT(31) + +struct rx_pkt_end { + __le32 info0; /* %RX_PKT_END_INFO0_ */ + __le32 phy_timestamp_1; + __le32 phy_timestamp_2; + __le32 rx_location_info; /* %RX_LOCATION_INFO_ */ +} __packed; + +enum rx_phy_ppdu_end_info0 { + RX_PHY_PPDU_END_INFO0_ERR_RADAR = BIT(2), + RX_PHY_PPDU_END_INFO0_ERR_RX_ABORT = BIT(3), + RX_PHY_PPDU_END_INFO0_ERR_RX_NAP = BIT(4), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_TIMING = BIT(5), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_PARITY = BIT(6), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_RATE = BIT(7), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_LENGTH = BIT(8), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_RESTART = BIT(9), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_SERVICE = BIT(10), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_POWER_DROP = BIT(11), + RX_PHY_PPDU_END_INFO0_ERR_CCK_BLOCKER = BIT(12), + RX_PHY_PPDU_END_INFO0_ERR_CCK_TIMING = BIT(13), + RX_PHY_PPDU_END_INFO0_ERR_CCK_HEADER_CRC = BIT(14), + RX_PHY_PPDU_END_INFO0_ERR_CCK_RATE = BIT(15), + RX_PHY_PPDU_END_INFO0_ERR_CCK_LENGTH = BIT(16), + RX_PHY_PPDU_END_INFO0_ERR_CCK_RESTART = BIT(17), + RX_PHY_PPDU_END_INFO0_ERR_CCK_SERVICE = BIT(18), + RX_PHY_PPDU_END_INFO0_ERR_CCK_POWER_DROP = BIT(19), + RX_PHY_PPDU_END_INFO0_ERR_HT_CRC = BIT(20), + RX_PHY_PPDU_END_INFO0_ERR_HT_LENGTH = BIT(21), + RX_PHY_PPDU_END_INFO0_ERR_HT_RATE = BIT(22), + RX_PHY_PPDU_END_INFO0_ERR_HT_ZLF = BIT(23), + RX_PHY_PPDU_END_INFO0_ERR_FALSE_RADAR_EXT = BIT(24), + RX_PHY_PPDU_END_INFO0_ERR_GREEN_FIELD = BIT(25), + RX_PHY_PPDU_END_INFO0_ERR_SPECTRAL_SCAN = BIT(26), + RX_PHY_PPDU_END_INFO0_ERR_RX_DYN_BW = BIT(27), + RX_PHY_PPDU_END_INFO0_ERR_LEG_HT_MISMATCH = BIT(28), + RX_PHY_PPDU_END_INFO0_ERR_VHT_CRC = BIT(29), + RX_PHY_PPDU_END_INFO0_ERR_VHT_SIGA = BIT(30), + RX_PHY_PPDU_END_INFO0_ERR_VHT_LSIG = BIT(31), +}; + +enum rx_phy_ppdu_end_info1 { + RX_PHY_PPDU_END_INFO1_ERR_VHT_NDP = BIT(0), + RX_PHY_PPDU_END_INFO1_ERR_VHT_NSYM = BIT(1), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_EXT_SYM = BIT(2), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID0 = BIT(3), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID1_62 = BIT(4), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID63 = BIT(5), + RX_PHY_PPDU_END_INFO1_ERR_OFDM_LDPC_DECODER = BIT(6), + RX_PHY_PPDU_END_INFO1_ERR_DEFER_NAP = BIT(7), + RX_PHY_PPDU_END_INFO1_ERR_FDOMAIN_TIMEOUT = BIT(8), + RX_PHY_PPDU_END_INFO1_ERR_LSIG_REL_CHECK = BIT(9), + RX_PHY_PPDU_END_INFO1_ERR_BT_COLLISION = BIT(10), + RX_PHY_PPDU_END_INFO1_ERR_MU_FEEDBACK = BIT(11), + RX_PHY_PPDU_END_INFO1_ERR_TX_INTERRUPT_RX = BIT(12), + RX_PHY_PPDU_END_INFO1_ERR_RX_CBF = BIT(13), +}; + +struct rx_phy_ppdu_end { + __le32 info0; /* %RX_PHY_PPDU_END_INFO0_ */ + __le32 info1; /* %RX_PHY_PPDU_END_INFO1_ */ +} __packed; + +#define RX_PPDU_END_RX_TIMING_OFFSET_MASK 0x00000fff +#define RX_PPDU_END_RX_TIMING_OFFSET_LSB 0 + +#define RX_PPDU_END_RX_INFO_RX_ANTENNA_MASK 0x00ffffff +#define RX_PPDU_END_RX_INFO_RX_ANTENNA_LSB 0 +#define RX_PPDU_END_RX_INFO_TX_HT_VHT_ACK BIT(24) +#define RX_PPDU_END_RX_INFO_RX_PKT_END_VALID BIT(25) +#define RX_PPDU_END_RX_INFO_RX_PHY_PPDU_END_VALID BIT(26) +#define RX_PPDU_END_RX_INFO_RX_TIMING_OFFSET_VALID BIT(27) +#define RX_PPDU_END_RX_INFO_BB_CAPTURED_CHANNEL BIT(28) +#define RX_PPDU_END_RX_INFO_UNSUPPORTED_MU_NC BIT(29) +#define RX_PPDU_END_RX_INFO_OTP_TXBF_DISABLE BIT(30) + +struct rx_ppdu_end_qca99x0 { + struct rx_pkt_end rx_pkt_end; + struct rx_phy_ppdu_end rx_phy_ppdu_end; + __le32 rx_timing_offset; /* %RX_PPDU_END_RX_TIMING_OFFSET_ */ + __le32 rx_info; /* %RX_PPDU_END_RX_INFO_ */ + __le16 bb_length; + __le16 info1; /* %RX_PPDU_END_INFO1_ */ +} __packed; + struct rx_ppdu_end { struct rx_ppdu_end_common common; union { struct rx_ppdu_end_qca988x qca988x; struct rx_ppdu_end_qca6174 qca6174; + struct rx_ppdu_end_qca99x0 qca99x0; } __packed; } __packed; -- cgit v1.3-6-gb490 From 19be9e9a7ac7e6050eab426283d2a87593cf6e82 Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Thu, 16 Jul 2015 09:25:33 +0530 Subject: ath10k: fix wrong initialization of struct channel chandef is initialized with NULL and on the very next line, we are using it to get channel, which is not correct. Channel should be initialized after obtaining chandef. Found by cppcheck: ath/ath10k/mac.c:839]: (error) Possible null pointer dereference: chandef Signed-off-by: Maninder Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c9a7d5b5dffc..49a54a1f07a8 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -836,7 +836,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) { struct cfg80211_chan_def *chandef = NULL; - struct ieee80211_channel *channel = chandef->chan; + struct ieee80211_channel *channel = NULL; struct wmi_vdev_start_request_arg arg = {}; int ret = 0; -- cgit v1.3-6-gb490 From b963519509644f52eaaddcc1fa484e28ac74c750 Mon Sep 17 00:00:00 2001 From: Manikanta Pubbisetty Date: Mon, 20 Jul 2015 17:56:12 +0530 Subject: ath10k: add TCP/UDP Checksum offload support for QCA99x0 The patch adds support to offload TCP/UDP checksum calculations for QCA99x0. Signed-off-by: Manikanta Pubbisetty Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 17 ++++++++++++++++- drivers/net/wireless/ath/ath10k/htt_tx.c | 4 ++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index e31cd74dded6..551f64bf6457 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -97,10 +97,25 @@ struct htt_data_tx_desc_frag { } __packed; struct htt_msdu_ext_desc { - __le32 tso_flag[4]; + __le32 tso_flag[3]; + __le16 ip_identification; + u8 flags; + u8 reserved; struct htt_data_tx_desc_frag frags[6]; }; +#define HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE BIT(0) +#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE BIT(1) +#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE BIT(2) +#define HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE BIT(3) +#define HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE BIT(4) + +#define HTT_MSDU_CHECKSUM_ENABLE (HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE) + enum htt_data_tx_desc_flags0 { HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT = 1 << 0, HTT_DATA_TX_DESC_FLAGS0_NO_AGGR = 1 << 1, diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index c49ecffc2905..1b34c1350f63 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -496,6 +496,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) u16 msdu_id, flags1 = 0; dma_addr_t paddr = 0; u32 frags_paddr = 0; + struct htt_msdu_ext_desc *ext_desc = NULL; res = ath10k_htt_tx_inc_pending(htt); if (res) @@ -542,6 +543,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) if (ar->hw_params.continuous_frag_desc) { frags = (struct htt_data_tx_desc_frag *) &htt->frag_desc.vaddr[msdu_id].frags; + ext_desc = &htt->frag_desc.vaddr[msdu_id]; frags[0].tword_addr.paddr_lo = __cpu_to_le32(skb_cb->paddr); frags[0].tword_addr.paddr_hi = 0; @@ -603,6 +605,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) if (msdu->ip_summed == CHECKSUM_PARTIAL) { flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; + if (ar->hw_params.continuous_frag_desc) + ext_desc->flags |= HTT_MSDU_CHECKSUM_ENABLE; } /* Prevent firmware from sending up tx inspection requests. There's -- cgit v1.3-6-gb490 From 1d0088f8c1d8b9541ed01f2cc52606fbf8baf50c Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Tue, 21 Jul 2015 10:52:00 +0530 Subject: ath10k: extend struct htt_mgmt_tx_dec for qca99x0 HTT_H2T_MSG_TYPE_MGMT_TX msg in 10.4 firmware carries additional 4 byte in htt_mgmt_tx_desc where it tells to firmware that at what rate mgmt frame has to go out in the air. It's an optional parameter, setting this field to zero will force firmware to choose auto rate and send the frame out. Those 4 byte info is missed out in the current code and 10.4 firmware ended up reading some junk in those 4 byte and sometime malfunctioning. Fix it by adding 4 byte in struct htt_mgmt_tx_desc. Non 10.4 firmware will not process those four byte. So, adding 4 byte at the end of struct htt_mgmt_tx_desc will not create any impact on other chipset. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 6 ++++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 2 ++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 551f64bf6457..7583a126e879 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -284,6 +284,9 @@ struct htt_aggr_conf { } __packed; #define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32 +struct htt_mgmt_tx_desc_qca99x0 { + __le32 rate; +} __packed; struct htt_mgmt_tx_desc { u8 pad[sizeof(u32) - sizeof(struct htt_cmd_hdr)]; @@ -292,6 +295,9 @@ struct htt_mgmt_tx_desc { __le32 len; __le32 vdev_id; u8 hdr[HTT_MGMT_FRM_HDR_DOWNLOAD_LEN]; + union { + struct htt_mgmt_tx_desc_qca99x0 qca99x0; + } __packed; } __packed; enum htt_mgmt_tx_status { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 1b34c1350f63..a97dd9d4295b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -450,6 +450,8 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_put(txdesc, len); cmd = (struct htt_cmd *)txdesc->data; + memset(cmd, 0, len); + cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_MGMT_TX; cmd->mgmt_tx.msdu_paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr); cmd->mgmt_tx.len = __cpu_to_le32(msdu->len); -- cgit v1.3-6-gb490 From 8766018b6ef73ca124d13b0d0a06dec906726cc8 Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Fri, 24 Jul 2015 13:24:41 +0800 Subject: regulator: mt6311: Add support for mt6311 regulator Add regulator support for mt6311. It has 2 regulaotrs - Buck and LDO, provide the related buck/ldo voltage data to the driver, and creates the regulator_desc table. Supported operations for Buck are enabled/disabled and voltage change, only enabled/disabled for LDO. Signed-off-by: Henry Chen Reviewed-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 9 ++ drivers/regulator/Makefile | 1 + drivers/regulator/mt6311-regulator.c | 180 +++++++++++++++++++++++++++++++++++ drivers/regulator/mt6311-regulator.h | 65 +++++++++++++ include/linux/regulator/mt6311.h | 29 ++++++ 5 files changed, 284 insertions(+) create mode 100644 drivers/regulator/mt6311-regulator.c create mode 100644 drivers/regulator/mt6311-regulator.h create mode 100644 include/linux/regulator/mt6311.h (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index bef3bde6971b..aab09ac499a0 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -451,6 +451,15 @@ config REGULATOR_MC13892 Say y here to support the regulators found on the Freescale MC13892 PMIC. +config REGULATOR_MT6311 + tristate "MediaTek MT6311 PMIC" + depends on I2C + help + Say y here to select this option to enable the power regulator of + MediaTek MT6311 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + config REGULATOR_MT6397 tristate "MediaTek MT6397 PMIC" depends on MFD_MT6397 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 91bf76267404..45e790f92715 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_REGULATOR_MAX77843) += max77843.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o +obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c new file mode 100644 index 000000000000..096e6202be1c --- /dev/null +++ b/drivers/regulator/mt6311-regulator.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: Henry Chen + * + * 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 +#include +#include +#include +#include +#include +#include +#include "mt6311-regulator.h" + +static const struct regmap_config mt6311_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MT6311_FQMTR_CON4, +}; + +/* Default limits measured in millivolts and milliamps */ +#define MT6311_MIN_UV 600000 +#define MT6311_MAX_UV 1400000 +#define MT6311_STEP_UV 6250 + +static const struct regulator_linear_range buck_volt_range[] = { + REGULATOR_LINEAR_RANGE(MT6311_MIN_UV, 0, 0x7f, MT6311_STEP_UV), +}; + +static struct regulator_ops mt6311_buck_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static struct regulator_ops mt6311_ldo_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +#define MT6311_BUCK(_id) \ +{\ + .name = #_id,\ + .ops = &mt6311_buck_ops,\ + .of_match = of_match_ptr(#_id),\ + .regulators_node = of_match_ptr("regulators"),\ + .type = REGULATOR_VOLTAGE,\ + .id = MT6311_ID_##_id,\ + .n_voltages = (MT6311_MAX_UV - MT6311_MIN_UV) / MT6311_STEP_UV + 1,\ + .min_uV = MT6311_MIN_UV,\ + .uV_step = MT6311_STEP_UV,\ + .owner = THIS_MODULE,\ + .linear_ranges = buck_volt_range, \ + .n_linear_ranges = ARRAY_SIZE(buck_volt_range), \ + .enable_reg = MT6311_VDVFS11_CON9,\ + .enable_mask = MT6311_PMIC_VDVFS11_EN_MASK,\ + .vsel_reg = MT6311_VDVFS11_CON12,\ + .vsel_mask = MT6311_PMIC_VDVFS11_VOSEL_MASK,\ +} + +#define MT6311_LDO(_id) \ +{\ + .name = #_id,\ + .ops = &mt6311_ldo_ops,\ + .of_match = of_match_ptr(#_id),\ + .regulators_node = of_match_ptr("regulators"),\ + .type = REGULATOR_VOLTAGE,\ + .id = MT6311_ID_##_id,\ + .owner = THIS_MODULE,\ + .enable_reg = MT6311_LDO_CON3,\ + .enable_mask = MT6311_PMIC_RG_VBIASN_EN_MASK,\ +} + +static struct regulator_desc mt6311_regulators[] = { + MT6311_BUCK(VDVFS), + MT6311_LDO(VBIASN), +}; + +/* + * I2C driver interface functions + */ +static int mt6311_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct regmap *regmap; + int error, i, ret; + unsigned int data; + + regmap = devm_regmap_init_i2c(i2c, &mt6311_regmap_config); + if (IS_ERR(regmap)) { + error = PTR_ERR(regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + error); + return error; + } + + ret = regmap_read(regmap, MT6311_SWCID, &data); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read DEVICE_ID reg: %d\n", ret); + return ret; + } + + switch (data) { + case MT6311_E1_CID_CODE: + case MT6311_E2_CID_CODE: + case MT6311_E3_CID_CODE: + break; + default: + dev_err(&i2c->dev, "Unsupported device id = 0x%x.\n", data); + return -ENODEV; + } + + for (i = 0; i < MT6311_MAX_REGULATORS; i++) { + config.dev = &i2c->dev; + config.regmap = regmap; + + rdev = devm_regulator_register(&i2c->dev, + &mt6311_regulators[i], &config); + if (IS_ERR(rdev)) { + dev_err(&i2c->dev, + "Failed to register MT6311 regulator\n"); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct i2c_device_id mt6311_i2c_id[] = { + {"mt6311", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, mt6311_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id mt6311_dt_ids[] = { + { .compatible = "mediatek,mt6311-regulator", + .data = &mt6311_i2c_id[0] }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt6311_dt_ids); +#endif + +static struct i2c_driver mt6311_regulator_driver = { + .driver = { + .name = "mt6311", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mt6311_dt_ids), + }, + .probe = mt6311_i2c_probe, + .id_table = mt6311_i2c_id, +}; + +module_i2c_driver(mt6311_regulator_driver); + +MODULE_AUTHOR("Henry Chen "); +MODULE_DESCRIPTION("Regulator device driver for Mediatek MT6311"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/mt6311-regulator.h b/drivers/regulator/mt6311-regulator.h new file mode 100644 index 000000000000..5218db46a798 --- /dev/null +++ b/drivers/regulator/mt6311-regulator.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: Henry Chen + * + * 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 __MT6311_REGULATOR_H__ +#define __MT6311_REGULATOR_H__ + +#define MT6311_SWCID 0x01 + +#define MT6311_TOP_INT_CON 0x18 +#define MT6311_TOP_INT_MON 0x19 + +#define MT6311_VDVFS11_CON0 0x87 +#define MT6311_VDVFS11_CON7 0x88 +#define MT6311_VDVFS11_CON8 0x89 +#define MT6311_VDVFS11_CON9 0x8A +#define MT6311_VDVFS11_CON10 0x8B +#define MT6311_VDVFS11_CON11 0x8C +#define MT6311_VDVFS11_CON12 0x8D +#define MT6311_VDVFS11_CON13 0x8E +#define MT6311_VDVFS11_CON14 0x8F +#define MT6311_VDVFS11_CON15 0x90 +#define MT6311_VDVFS11_CON16 0x91 +#define MT6311_VDVFS11_CON17 0x92 +#define MT6311_VDVFS11_CON18 0x93 +#define MT6311_VDVFS11_CON19 0x94 + +#define MT6311_LDO_CON0 0xCC +#define MT6311_LDO_OCFB0 0xCD +#define MT6311_LDO_CON2 0xCE +#define MT6311_LDO_CON3 0xCF +#define MT6311_LDO_CON4 0xD0 +#define MT6311_FQMTR_CON0 0xD1 +#define MT6311_FQMTR_CON1 0xD2 +#define MT6311_FQMTR_CON2 0xD3 +#define MT6311_FQMTR_CON3 0xD4 +#define MT6311_FQMTR_CON4 0xD5 + +#define MT6311_PMIC_RG_INT_POL_MASK 0x1 +#define MT6311_PMIC_RG_INT_EN_MASK 0x2 +#define MT6311_PMIC_RG_BUCK_OC_INT_STATUS_MASK 0x10 + +#define MT6311_PMIC_VDVFS11_EN_CTRL_MASK 0x1 +#define MT6311_PMIC_VDVFS11_VOSEL_CTRL_MASK 0x2 +#define MT6311_PMIC_VDVFS11_EN_SEL_MASK 0x3 +#define MT6311_PMIC_VDVFS11_VOSEL_SEL_MASK 0xc +#define MT6311_PMIC_VDVFS11_EN_MASK 0x1 +#define MT6311_PMIC_VDVFS11_VOSEL_MASK 0x7F +#define MT6311_PMIC_VDVFS11_VOSEL_ON_MASK 0x7F +#define MT6311_PMIC_VDVFS11_VOSEL_SLEEP_MASK 0x7F +#define MT6311_PMIC_NI_VDVFS11_VOSEL_MASK 0x7F + +#define MT6311_PMIC_RG_VBIASN_EN_MASK 0x1 + +#endif diff --git a/include/linux/regulator/mt6311.h b/include/linux/regulator/mt6311.h new file mode 100644 index 000000000000..8473259395b6 --- /dev/null +++ b/include/linux/regulator/mt6311.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: Henry Chen + * + * 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 __LINUX_REGULATOR_MT6311_H +#define __LINUX_REGULATOR_MT6311_H + +#define MT6311_MAX_REGULATORS 2 + +enum { + MT6311_ID_VDVFS = 0, + MT6311_ID_VBIASN, +}; + +#define MT6311_E1_CID_CODE 0x10 +#define MT6311_E2_CID_CODE 0x20 +#define MT6311_E3_CID_CODE 0x30 + +#endif /* __LINUX_REGULATOR_MT6311_H */ -- cgit v1.3-6-gb490 From 0439de75d32c249bd9f5824ffd5e40c4c2109d77 Mon Sep 17 00:00:00 2001 From: Stephen Just Date: Wed, 22 Jul 2015 20:11:40 -0700 Subject: HID: microsoft: Add Surface 3 type cover Adding support for the Microsoft Surface 3 (non-pro) Type Cover. The existing definitions and quirks are actually for the Surface Pro 3 type covers. I've renamed the old constants to reflect that they belong to the Surface Pro 3, and added a new constant and matching code for the Surface 3. Signed-off-by: Stephen Just Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 8 +++++--- drivers/hid/hid-ids.h | 5 +++-- drivers/hid/hid-microsoft.c | 6 ++++-- drivers/hid/usbhid/hid-quirks.c | 3 ++- 4 files changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 157c62775053..d9c7cd971a52 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -705,8 +705,9 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) hid->group = HID_GROUP_SENSOR_HUB; if (hid->vendor == USB_VENDOR_ID_MICROSOFT && - (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP || + (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 || + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP || + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || hid->product == USB_DEVICE_ID_MS_POWER_COVER) && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; @@ -1902,8 +1903,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b04b0820d816..8dab4b2e9dfe 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -663,8 +663,9 @@ #define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799 #define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 -#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc -#define USB_DEVICE_ID_MS_TYPE_COVER_3_JP 0x07dd +#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc +#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd +#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de #define USB_DEVICE_ID_MS_POWER_COVER 0x07da #define USB_VENDOR_ID_MOJO 0x8282 diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 32a596f554af..9aa3515090a7 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -276,9 +276,11 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), .driver_data = MS_DUPLICATE_USAGES }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3), + .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP), .driver_data = MS_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP), + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), .driver_data = MS_HIDINPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), .driver_data = MS_HIDINPUT }, diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 53e7de7cb9e2..198e2665de44 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -87,8 +87,9 @@ static const struct hid_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, -- cgit v1.3-6-gb490 From 070f63b46ac893a5debf68c5751101b6f5f77230 Mon Sep 17 00:00:00 2001 From: Yang Bo Date: Mon, 20 Jul 2015 09:40:28 -0700 Subject: HID: multitouch: Add support for CJTouch MultiTouch Add device IDs for CJTouch 0020 and 0040 panels. Signed-off-by: Yang Bo Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-ids.h | 4 ++++ drivers/hid/hid-multitouch.c | 8 ++++++++ 3 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index cc4c6649d195..57c94d7d5834 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -480,6 +480,7 @@ config HID_MULTITOUCH - Atmel panels - Cando dual touch panels - Chunghwa panels + - CJTouch panels - CVTouch panels - Cypress TrueTouch panels - Elan Microelectronics touch panels diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b04b0820d816..591b7d06f54d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -236,6 +236,10 @@ #define USB_VENDOR_ID_CIDC 0x1677 +#define USB_VENDOR_ID_CJTOUCH 0x24b8 +#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020 +#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040 + #define USB_VENDOR_ID_CMEDIA 0x0d8c #define USB_DEVICE_ID_CM109 0x000e diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 6a9b05b328a9..ab0434f86f49 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1138,6 +1138,14 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, + /* CJTouch panels */ + { .driver_data = MT_CLS_NSMU, + MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, + USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020) }, + { .driver_data = MT_CLS_NSMU, + MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, + USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040) }, + /* CVTouch panels */ { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, -- cgit v1.3-6-gb490 From 8f5f0bc2766af7785161a4440bca1d0746eb3671 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Thu, 23 Jul 2015 19:01:16 -0400 Subject: HID: sony: Drop invalid Sixaxis input reports When connected via Bluetooth the sixaxis periodically sends reports with an ID of 1, the second byte 0xff and the rest zeroed. These reports are not related to the controller state and must be dropped to avoid generating false input events. Link: http://www.spinics.net/lists/linux-bluetooth/msg63028.html Signed-off-by: Frank Praznik Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 69586b316409..ed0496abf573 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1277,6 +1277,17 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, * has to be BYTE_SWAPPED before passing up to joystick interface */ if ((sc->quirks & SIXAXIS_CONTROLLER) && rd[0] == 0x01 && size == 49) { + /* + * When connected via Bluetooth the Sixaxis occasionally sends + * a report with the second byte 0xff and the rest zeroed. + * + * This report does not reflect the actual state of the + * controller must be ignored to avoid generating false input + * events. + */ + if (rd[1] == 0xff) + return -EINVAL; + swap(rd[41], rd[42]); swap(rd[43], rd[44]); swap(rd[45], rd[46]); -- cgit v1.3-6-gb490 From 1b7cac23419e1398eac4c28368da6671c9c4ce9d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 23 Mar 2015 10:20:28 +1100 Subject: twl4030_charger: use devm_request_threaded_irq This simplifies the error paths. Signed-off-by: NeilBrown Acked-by: Pavel Machek Signed-off-by: Sebastian Reichel --- drivers/power/twl4030_charger.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 022b8910e443..4c779aecd86b 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -619,21 +619,21 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) goto fail_register_usb; } - ret = request_threaded_irq(bci->irq_chg, NULL, + ret = devm_request_threaded_irq(&pdev->dev, bci->irq_chg, NULL, twl4030_charger_interrupt, IRQF_ONESHOT, pdev->name, bci); if (ret < 0) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", bci->irq_chg, ret); - goto fail_chg_irq; + goto fail; } - ret = request_threaded_irq(bci->irq_bci, NULL, + ret = devm_request_threaded_irq(&pdev->dev, bci->irq_bci, NULL, twl4030_bci_interrupt, IRQF_ONESHOT, pdev->name, bci); if (ret < 0) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", bci->irq_bci, ret); - goto fail_bci_irq; + goto fail; } INIT_WORK(&bci->work, twl4030_bci_usb_work); @@ -656,7 +656,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) TWL4030_INTERRUPTS_BCIIMR1A); if (ret < 0) { dev_err(&pdev->dev, "failed to unmask interrupts: %d\n", ret); - goto fail_unmask_interrupts; + goto fail; } reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV); @@ -675,11 +675,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) return 0; -fail_unmask_interrupts: - free_irq(bci->irq_bci, bci); -fail_bci_irq: - free_irq(bci->irq_chg, bci); -fail_chg_irq: +fail: power_supply_unregister(bci->usb); fail_register_usb: power_supply_unregister(bci->ac); @@ -704,8 +700,6 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, TWL4030_INTERRUPTS_BCIIMR2A); - free_irq(bci->irq_bci, bci); - free_irq(bci->irq_chg, bci); power_supply_unregister(bci->usb); power_supply_unregister(bci->ac); kfree(bci); -- cgit v1.3-6-gb490 From 325b50aa5d1c7dae57d1e44defdbacd1e2bcabde Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 23 Mar 2015 10:20:28 +1100 Subject: twl4030_charger: use devres for power_supply_register and kzalloc. Final allocations/registrations are now managed by devres. Signed-off-by: NeilBrown Acked-by: Pavel Machek Signed-off-by: Sebastian Reichel --- drivers/power/twl4030_charger.c | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 4c779aecd86b..709d90dc75f1 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -581,7 +581,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) int ret; u32 reg; - bci = kzalloc(sizeof(*bci), GFP_KERNEL); + bci = devm_kzalloc(&pdev->dev, sizeof(*bci), GFP_KERNEL); if (bci == NULL) return -ENOMEM; @@ -596,27 +596,27 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) ret = twl4030_is_battery_present(bci); if (ret) { dev_crit(&pdev->dev, "Battery was not detected:%d\n", ret); - goto fail_no_battery; + return ret; } platform_set_drvdata(pdev, bci); - bci->ac = power_supply_register(&pdev->dev, &twl4030_bci_ac_desc, - NULL); + bci->ac = devm_power_supply_register(&pdev->dev, &twl4030_bci_ac_desc, + NULL); if (IS_ERR(bci->ac)) { ret = PTR_ERR(bci->ac); dev_err(&pdev->dev, "failed to register ac: %d\n", ret); - goto fail_register_ac; + return ret; } bci->usb_reg = regulator_get(bci->dev, "bci3v1"); - bci->usb = power_supply_register(&pdev->dev, &twl4030_bci_usb_desc, - NULL); + bci->usb = devm_power_supply_register(&pdev->dev, &twl4030_bci_usb_desc, + NULL); if (IS_ERR(bci->usb)) { ret = PTR_ERR(bci->usb); dev_err(&pdev->dev, "failed to register usb: %d\n", ret); - goto fail_register_usb; + return ret; } ret = devm_request_threaded_irq(&pdev->dev, bci->irq_chg, NULL, @@ -625,7 +625,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", bci->irq_chg, ret); - goto fail; + return ret; } ret = devm_request_threaded_irq(&pdev->dev, bci->irq_bci, NULL, @@ -633,7 +633,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "could not request irq %d, status %d\n", bci->irq_bci, ret); - goto fail; + return ret; } INIT_WORK(&bci->work, twl4030_bci_usb_work); @@ -656,7 +656,7 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) TWL4030_INTERRUPTS_BCIIMR1A); if (ret < 0) { dev_err(&pdev->dev, "failed to unmask interrupts: %d\n", ret); - goto fail; + return ret; } reg = ~(u32)(TWL4030_VBATOV | TWL4030_VBUSOV | TWL4030_ACCHGOV); @@ -674,16 +674,6 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) twl4030_charger_enable_backup(0, 0); return 0; - -fail: - power_supply_unregister(bci->usb); -fail_register_usb: - power_supply_unregister(bci->ac); -fail_register_ac: -fail_no_battery: - kfree(bci); - - return ret; } static int __exit twl4030_bci_remove(struct platform_device *pdev) @@ -700,10 +690,6 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, TWL4030_INTERRUPTS_BCIIMR2A); - power_supply_unregister(bci->usb); - power_supply_unregister(bci->ac); - kfree(bci); - return 0; } -- cgit v1.3-6-gb490 From 377b641ac84c573bcea06aec47f7ad1ba4047e1c Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Wed, 1 Jul 2015 11:40:53 +0200 Subject: power/ltc2941-battery-gauge.c: Use the devicetree node name as supply name Make it possible to set the name of the supply from the devicetree. Like other power supply drivers just use the node name. This makes the code smaller as well, as it doesn't need to allocate memory to hold the name and allocate a unique ID. Signed-off-by: Mike Looijmans Signed-off-by: Sebastian Reichel --- drivers/power/ltc2941-battery-gauge.c | 54 ++++++----------------------------- 1 file changed, 8 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/power/ltc2941-battery-gauge.c b/drivers/power/ltc2941-battery-gauge.c index daeb0860736c..4adf2ba021ce 100644 --- a/drivers/power/ltc2941-battery-gauge.c +++ b/drivers/power/ltc2941-battery-gauge.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -63,15 +62,11 @@ struct ltc294x_info { struct power_supply_desc supply_desc; /* Supply description */ struct delayed_work work; /* Work scheduler */ int num_regs; /* Number of registers (chip type) */ - int id; /* Identifier of ltc294x chip */ int charge; /* Last charge register content */ int r_sense; /* mOhm */ int Qlsb; /* nAh */ }; -static DEFINE_IDR(ltc294x_id); -static DEFINE_MUTEX(ltc294x_lock); - static inline int convert_bin_to_uAh( const struct ltc294x_info *info, int Q) { @@ -371,10 +366,6 @@ static int ltc294x_i2c_remove(struct i2c_client *client) cancel_delayed_work(&info->work); power_supply_unregister(info->supply); - kfree(info->supply_desc.name); - mutex_lock(<c294x_lock); - idr_remove(<c294x_id, info->id); - mutex_unlock(<c294x_lock); return 0; } @@ -384,44 +375,28 @@ static int ltc294x_i2c_probe(struct i2c_client *client, struct power_supply_config psy_cfg = {}; struct ltc294x_info *info; int ret; - int num; u32 prescaler_exp; s32 r_sense; struct device_node *np; - mutex_lock(<c294x_lock); - ret = idr_alloc(<c294x_id, client, 0, 0, GFP_KERNEL); - mutex_unlock(<c294x_lock); - if (ret < 0) - goto fail_id; - - num = ret; - info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); - if (info == NULL) { - ret = -ENOMEM; - goto fail_info; - } + if (info == NULL) + return -ENOMEM; i2c_set_clientdata(client, info); - info->num_regs = id->driver_data; - info->supply_desc.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, - num); - if (!info->supply_desc.name) { - ret = -ENOMEM; - goto fail_name; - } - np = of_node_get(client->dev.of_node); + info->num_regs = id->driver_data; + info->supply_desc.name = np->name; + /* r_sense can be negative, when sense+ is connected to the battery * instead of the sense-. This results in reversed measurements. */ ret = of_property_read_u32(np, "lltc,resistor-sense", &r_sense); if (ret < 0) { dev_err(&client->dev, "Could not find lltc,resistor-sense in devicetree\n"); - goto fail_name; + return ret; } info->r_sense = r_sense; @@ -446,7 +421,6 @@ static int ltc294x_i2c_probe(struct i2c_client *client, } info->client = client; - info->id = num; info->supply_desc.type = POWER_SUPPLY_TYPE_BATTERY; info->supply_desc.properties = ltc294x_properties; if (info->num_regs >= LTC294X_REG_TEMPERATURE_LSB) @@ -473,31 +447,19 @@ static int ltc294x_i2c_probe(struct i2c_client *client, ret = ltc294x_reset(info, prescaler_exp); if (ret < 0) { dev_err(&client->dev, "Communication with chip failed\n"); - goto fail_comm; + return ret; } info->supply = power_supply_register(&client->dev, &info->supply_desc, &psy_cfg); if (IS_ERR(info->supply)) { dev_err(&client->dev, "failed to register ltc2941\n"); - ret = PTR_ERR(info->supply); - goto fail_register; + return PTR_ERR(info->supply); } else { schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ); } return 0; - -fail_register: - kfree(info->supply_desc.name); -fail_comm: -fail_name: -fail_info: - mutex_lock(<c294x_lock); - idr_remove(<c294x_id, num); - mutex_unlock(<c294x_lock); -fail_id: - return ret; } #ifdef CONFIG_PM_SLEEP -- cgit v1.3-6-gb490 From dd9f1486ae207cd947416f1bdc461edc4880f2df Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Wed, 15 Jul 2015 11:25:58 +0800 Subject: power/reset: zx: Register restart handler Register with kernel restart handler instead of setting arm_pm_restart directly. Signed-off-by: Jun Nie Signed-off-by: Sebastian Reichel --- drivers/power/reset/Kconfig | 7 ++++ drivers/power/reset/Makefile | 1 + drivers/power/reset/zx-reboot.c | 82 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 drivers/power/reset/zx-reboot.c (limited to 'drivers') diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 17d93a73c513..5a0189bf19bb 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -166,5 +166,12 @@ config POWER_RESET_RMOBILE help Reboot support for Renesas R-Mobile and SH-Mobile SoCs. +config POWER_RESET_ZX + tristate "ZTE SoCs reset driver" + depends on ARCH_ZX || COMPILE_TEST + depends on HAS_IOMEM + help + Reboot support for ZTE SoCs. + endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index dbe06c368743..096fa67047f6 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o obj-$(CONFIG_POWER_RESET_SYSCON_POWEROFF) += syscon-poweroff.o obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o +obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c new file mode 100644 index 000000000000..cf4b973dcedf --- /dev/null +++ b/drivers/power/reset/zx-reboot.c @@ -0,0 +1,82 @@ +/* + * ZTE zx296702 SoC reset code + * + * Copyright (c) 2015 Linaro Ltd. + * + * Author: Jun Nie + * + * 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 + +static void __iomem *base; +static void __iomem *pcu_base; + +static int zx_restart_handler(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + writel_relaxed(1, base + 0xb0); + writel_relaxed(1, pcu_base + 0x34); + + mdelay(50); + pr_emerg("Unable to restart system\n"); + + return NOTIFY_DONE; +} + +static struct notifier_block zx_restart_nb = { + .notifier_call = zx_restart_handler, + .priority = 128, +}; + +static int zx_reboot_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + int err; + + base = of_iomap(np, 0); + if (!base) { + WARN(1, "failed to map base address"); + return -ENODEV; + } + + np = of_find_compatible_node(NULL, NULL, "zte,zx296702-pcu"); + pcu_base = of_iomap(np, 0); + if (!pcu_base) { + iounmap(base); + WARN(1, "failed to map pcu_base address"); + return -ENODEV; + } + + err = register_restart_handler(&zx_restart_nb); + if (err) + dev_err(&pdev->dev, "Register restart handler failed(err=%d)\n", + err); + + return err; +} + +static const struct of_device_id zx_reboot_of_match[] = { + { .compatible = "zte,sysctrl" }, + {} +}; + +static struct platform_driver zx_reboot_driver = { + .probe = zx_reboot_probe, + .driver = { + .name = "zx-reboot", + .of_match_table = zx_reboot_of_match, + }, +}; +module_platform_driver(zx_reboot_driver); -- cgit v1.3-6-gb490 From db04fc5caa79260170a68d58db8fc401f1ab05f5 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 22 Jul 2015 16:51:53 -0500 Subject: power: bq27x00_battery: Add manufacturer property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the manufacturer property to the bq27x00 driver. Signed-off-by: Andrew F. Davis Acked-by: Dan Murphy Acked-by: Pali Rohár Signed-off-by: Sebastian Reichel --- drivers/power/bq27x00_battery.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index b6b98378faa3..2257bd4e7378 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -41,6 +41,8 @@ #define DRIVER_VERSION "1.2.0" +#define BQ27XXX_MANUFACTURER "Texas Instruments" + #define BQ27x00_REG_TEMP 0x06 #define BQ27x00_REG_VOLT 0x08 #define BQ27x00_REG_AI 0x14 @@ -142,6 +144,7 @@ static enum power_supply_property bq27x00_battery_props[] = { POWER_SUPPLY_PROP_ENERGY_NOW, POWER_SUPPLY_PROP_POWER_AVG, POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, }; static enum power_supply_property bq27425_battery_props[] = { @@ -156,6 +159,7 @@ static enum power_supply_property bq27425_battery_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_MANUFACTURER, }; static enum power_supply_property bq27742_battery_props[] = { @@ -174,6 +178,7 @@ static enum power_supply_property bq27742_battery_props[] = { POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_POWER_AVG, POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, }; static enum power_supply_property bq27510_battery_props[] = { @@ -192,6 +197,7 @@ static enum power_supply_property bq27510_battery_props[] = { POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_POWER_AVG, POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, }; static unsigned int poll_interval = 360; @@ -749,6 +755,9 @@ static int bq27x00_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_HEALTH: ret = bq27x00_simple_value(di->cache.health, val); break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = BQ27XXX_MANUFACTURER; + break; default: return -EINVAL; } -- cgit v1.3-6-gb490 From 6eb207f271478472195cfaa2e59646f7e5036ae8 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 22 Jul 2015 16:51:54 -0500 Subject: power: bq27x00_battery: Fix lines over 80 characters long MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shorted lines over 80 characters long by reducing tab count. Signed-off-by: Andrew F. Davis Acked-by: Pali Rohár Acked-by: Dan Murphy Signed-off-by: Sebastian Reichel --- drivers/power/bq27x00_battery.c | 74 ++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 2257bd4e7378..203cf613c559 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -39,49 +39,49 @@ #include -#define DRIVER_VERSION "1.2.0" +#define DRIVER_VERSION "1.2.0" #define BQ27XXX_MANUFACTURER "Texas Instruments" -#define BQ27x00_REG_TEMP 0x06 -#define BQ27x00_REG_VOLT 0x08 -#define BQ27x00_REG_AI 0x14 -#define BQ27x00_REG_FLAGS 0x0A -#define BQ27x00_REG_TTE 0x16 -#define BQ27x00_REG_TTF 0x18 -#define BQ27x00_REG_TTECP 0x26 -#define BQ27x00_REG_NAC 0x0C /* Nominal available capacity */ -#define BQ27x00_REG_LMD 0x12 /* Last measured discharge */ -#define BQ27x00_REG_CYCT 0x2A /* Cycle count total */ -#define BQ27x00_REG_AE 0x22 /* Available energy */ -#define BQ27x00_POWER_AVG 0x24 - -#define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ -#define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ -#define BQ27000_FLAG_EDVF BIT(0) /* Final End-of-Discharge-Voltage flag */ -#define BQ27000_FLAG_EDV1 BIT(1) /* First End-of-Discharge-Voltage flag */ -#define BQ27000_FLAG_CI BIT(4) /* Capacity Inaccurate flag */ -#define BQ27000_FLAG_FC BIT(5) -#define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */ - -#define BQ27500_REG_SOC 0x2C -#define BQ27500_REG_DCAP 0x3C /* Design capacity */ -#define BQ27500_FLAG_DSC BIT(0) -#define BQ27500_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ -#define BQ27500_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ -#define BQ27500_FLAG_FC BIT(9) -#define BQ27500_FLAG_OTC BIT(15) - -#define BQ27742_POWER_AVG 0x76 - -#define BQ27510_REG_SOC 0x20 -#define BQ27510_REG_DCAP 0x2E /* Design capacity */ -#define BQ27510_REG_CYCT 0x1E /* Cycle count total */ +#define BQ27x00_REG_TEMP 0x06 +#define BQ27x00_REG_VOLT 0x08 +#define BQ27x00_REG_AI 0x14 +#define BQ27x00_REG_FLAGS 0x0A +#define BQ27x00_REG_TTE 0x16 +#define BQ27x00_REG_TTF 0x18 +#define BQ27x00_REG_TTECP 0x26 +#define BQ27x00_REG_NAC 0x0C /* Nominal available capacity */ +#define BQ27x00_REG_LMD 0x12 /* Last measured discharge */ +#define BQ27x00_REG_CYCT 0x2A /* Cycle count total */ +#define BQ27x00_REG_AE 0x22 /* Available energy */ +#define BQ27x00_POWER_AVG 0x24 + +#define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ +#define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ +#define BQ27000_FLAG_EDVF BIT(0) /* Final End-of-Discharge-Voltage flag */ +#define BQ27000_FLAG_EDV1 BIT(1) /* First End-of-Discharge-Voltage flag */ +#define BQ27000_FLAG_CI BIT(4) /* Capacity Inaccurate flag */ +#define BQ27000_FLAG_FC BIT(5) +#define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */ + +#define BQ27500_REG_SOC 0x2C +#define BQ27500_REG_DCAP 0x3C /* Design capacity */ +#define BQ27500_FLAG_DSC BIT(0) +#define BQ27500_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ +#define BQ27500_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ +#define BQ27500_FLAG_FC BIT(9) +#define BQ27500_FLAG_OTC BIT(15) + +#define BQ27742_POWER_AVG 0x76 + +#define BQ27510_REG_SOC 0x20 +#define BQ27510_REG_DCAP 0x2E /* Design capacity */ +#define BQ27510_REG_CYCT 0x1E /* Cycle count total */ /* bq27425 register addresses are same as bq27x00 addresses minus 4 */ -#define BQ27425_REG_OFFSET 0x04 +#define BQ27425_REG_OFFSET 0x04 #define BQ27425_REG_SOC (0x1C + BQ27425_REG_OFFSET) -#define BQ27425_REG_DCAP (0x3C + BQ27425_REG_OFFSET) +#define BQ27425_REG_DCAP (0x3C + BQ27425_REG_OFFSET) #define BQ27000_RS 20 /* Resistor sense */ #define BQ27x00_POWER_CONSTANT (256 * 29200 / 1000) -- cgit v1.3-6-gb490 From ce33edfa4903d8b8ded2569e880489678f75a85b Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 22 Jul 2015 16:51:55 -0500 Subject: power: bq27x00_battery: Fix function parameter alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the alignment of function parameters on new lines. Signed-off-by: Andrew F. Davis Acked-by: Pali Rohár Acked-by: Dan Murphy Signed-off-by: Sebastian Reichel --- drivers/power/bq27x00_battery.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 203cf613c559..9cdad1992a2d 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -210,7 +210,7 @@ MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ */ static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, - bool single) + bool single) { if (di->chip == BQ27425) return di->bus.read(di, reg - BQ27425_REG_OFFSET, single); @@ -565,7 +565,7 @@ static void bq27x00_battery_poll(struct work_struct *work) * Or 0 if something fails. */ static int bq27x00_battery_current(struct bq27x00_device_info *di, - union power_supply_propval *val) + union power_supply_propval *val) { int curr; int flags; @@ -593,7 +593,7 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di, } static int bq27x00_battery_status(struct bq27x00_device_info *di, - union power_supply_propval *val) + union power_supply_propval *val) { int status; @@ -621,7 +621,7 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di, } static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di, - union power_supply_propval *val) + union power_supply_propval *val) { int level; @@ -655,7 +655,7 @@ static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di, * Or < 0 if something fails. */ static int bq27x00_battery_voltage(struct bq27x00_device_info *di, - union power_supply_propval *val) + union power_supply_propval *val) { int volt; @@ -671,7 +671,7 @@ static int bq27x00_battery_voltage(struct bq27x00_device_info *di, } static int bq27x00_simple_value(int value, - union power_supply_propval *val) + union power_supply_propval *val) { if (value < 0) return value; @@ -987,7 +987,7 @@ static inline void bq27x00_battery_i2c_exit(void) {}; #ifdef CONFIG_BATTERY_BQ27X00_PLATFORM static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg, - bool single) + bool single) { struct device *dev = di->dev; struct bq27000_platform_data *pdata = dev->platform_data; -- cgit v1.3-6-gb490 From 6d0a1815e814ee5eaa0cec17913d5e4abae99ef0 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 22 Jul 2015 16:51:56 -0500 Subject: power: bq27x00_battery: Checkpatch fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove space before tab. Remove unnecessary line continuations. Add braces to else statement. Remove unnecessary parentheses. Remove unneeded blank lines. Remove unnecessary 'out of memory' message. Add missing line after declarations. Change use of printk to pr_err. Signed-off-by: Andrew F. Davis Acked-by: Pali Rohár Acked-by: Dan Murphy Signed-off-by: Sebastian Reichel --- drivers/power/bq27x00_battery.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 9cdad1992a2d..8287261fd978 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -108,7 +108,7 @@ struct bq27x00_reg_cache { }; struct bq27x00_device_info { - struct device *dev; + struct device *dev; int id; enum bq27x00_chip chip; @@ -202,8 +202,8 @@ static enum power_supply_property bq27510_battery_props[] = { static unsigned int poll_interval = 360; module_param(poll_interval, uint, 0644); -MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ - "0 disables polling"); +MODULE_PARM_DESC(poll_interval, + "battery poll interval in seconds - 0 disables polling"); /* * Common code for BQ27x00 devices @@ -319,8 +319,9 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) ilmd = bq27x00_read(di, BQ27510_REG_DCAP, false); else ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); - } else + } else { ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); + } if (ilmd < 0) { dev_dbg(di->dev, "error reading initial last measured discharge\n"); @@ -451,7 +452,7 @@ static int bq27x00_battery_read_health(struct bq27x00_device_info *di) return tval; } - if ((di->chip == BQ27500)) { + if (di->chip == BQ27500) { if (tval & BQ27500_FLAG_SOCF) tval = POWER_SUPPLY_HEALTH_DEAD; else if (tval & BQ27500_FLAG_OTC) @@ -836,7 +837,6 @@ static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di) mutex_destroy(&di->lock); } - /* i2c specific code */ #ifdef CONFIG_BATTERY_BQ27X00_I2C @@ -897,14 +897,12 @@ static int bq27x00_battery_probe(struct i2c_client *client, name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%d", id->name, num); if (!name) { - dev_err(&client->dev, "failed to allocate device name\n"); retval = -ENOMEM; goto batt_failed; } di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL); if (!di) { - dev_err(&client->dev, "failed to allocate device info data\n"); retval = -ENOMEM; goto batt_failed; } @@ -965,8 +963,9 @@ static struct i2c_driver bq27x00_battery_driver = { static inline int bq27x00_battery_i2c_init(void) { int ret = i2c_add_driver(&bq27x00_battery_driver); + if (ret) - printk(KERN_ERR "Unable to register BQ27x00 i2c driver\n"); + pr_err("Unable to register BQ27x00 i2c driver\n"); return ret; } @@ -1037,10 +1036,8 @@ static int bq27000_battery_probe(struct platform_device *pdev) } di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); - if (!di) { - dev_err(&pdev->dev, "failed to allocate device info data\n"); + if (!di) return -ENOMEM; - } platform_set_drvdata(pdev, di); @@ -1073,8 +1070,9 @@ static struct platform_driver bq27000_battery_driver = { static inline int bq27x00_battery_platform_init(void) { int ret = platform_driver_register(&bq27000_battery_driver); + if (ret) - printk(KERN_ERR "Unable to register BQ27000 platform driver\n"); + pr_err("Unable to register BQ27000 platform driver\n"); return ret; } -- cgit v1.3-6-gb490 From bba732d86694f7217a41e83a2c1deb42ed9aa7fd Mon Sep 17 00:00:00 2001 From: Franklin S Cooper Jr Date: Wed, 22 Jul 2015 07:32:21 -0500 Subject: spi: davinci: Set prescale value based on register value Within davinci_spi_get_prescale() the prescale has two meanings. First one being the calculated prescale value and then at the end translates it to the prescale value that will be written to the SPI register. At first glance this can be confusing especially when comparing the minimum prescale value against what is seen in the TRM. To simplify things make it clear that the calculated prescale value will always be based on the value that will be written into the SPI register. Signed-off-by: Franklin S Cooper Jr Signed-off-by: Mark Brown --- drivers/spi/spi-davinci.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 987afebea093..b4605c4158f4 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -255,7 +255,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) * This function calculates the prescale value that generates a clock rate * less than or equal to the specified maximum. * - * Returns: calculated prescale - 1 for easy programming into SPI registers + * Returns: calculated prescale value for easy programming into SPI registers * or negative error number if valid prescalar cannot be updated. */ static inline int davinci_spi_get_prescale(struct davinci_spi *dspi, @@ -263,12 +263,13 @@ static inline int davinci_spi_get_prescale(struct davinci_spi *dspi, { int ret; - ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz); + /* Subtract 1 to match what will be programmed into SPI register. */ + ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz) - 1; - if (ret < 1 || ret > 256) + if (ret < 0 || ret > 255) return -EINVAL; - return ret - 1; + return ret; } /** -- cgit v1.3-6-gb490 From fa466c91970a0207d9384016cc7884a7f61834b6 Mon Sep 17 00:00:00 2001 From: Franklin S Cooper Jr Date: Wed, 22 Jul 2015 07:32:22 -0500 Subject: spi: davinci: Choose correct pre-scaler limit based on SOC Currently the pre-scaler limit is incorrect. The value differs slightly for various devices so a single value can't be used. Using the compatible field select the correct pre-scaler limit. Add new compatible field value for Keystone devices to support their unique pre-scaler limit value. Signed-off-by: Franklin S Cooper Jr Reviewed-by: Sekhar Nori Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-davinci.txt | 2 + drivers/spi/spi-davinci.c | 43 ++++++++++++++++++---- include/linux/platform_data/spi-davinci.h | 1 + 3 files changed, 39 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/spi/spi-davinci.txt b/Documentation/devicetree/bindings/spi/spi-davinci.txt index 12ecfe9e3599..d1e914adcf6e 100644 --- a/Documentation/devicetree/bindings/spi/spi-davinci.txt +++ b/Documentation/devicetree/bindings/spi/spi-davinci.txt @@ -12,6 +12,8 @@ Required properties: - compatible: - "ti,dm6441-spi" for SPI used similar to that on DM644x SoC family - "ti,da830-spi" for SPI used similar to that on DA8xx SoC family + - "ti,keystone-spi" for SPI used similar to that on Keystone2 SoC + family - reg: Offset and length of SPI controller register space - num-cs: Number of chip selects. This includes internal as well as GPIO chip selects. diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index b4605c4158f4..3cf9faa6cc3f 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -139,6 +139,8 @@ struct davinci_spi { u32 (*get_tx)(struct davinci_spi *); u8 *bytes_per_word; + + u8 prescaler_limit; }; static struct davinci_spi_config davinci_spi_default_cfg; @@ -266,7 +268,7 @@ static inline int davinci_spi_get_prescale(struct davinci_spi *dspi, /* Subtract 1 to match what will be programmed into SPI register. */ ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz) - 1; - if (ret < 0 || ret > 255) + if (ret < dspi->prescaler_limit || ret > 255) return -EINVAL; return ret; @@ -833,13 +835,40 @@ rx_dma_failed: } #if defined(CONFIG_OF) + +/* OF SPI data structure */ +struct davinci_spi_of_data { + u8 version; + u8 prescaler_limit; +}; + +static const struct davinci_spi_of_data dm6441_spi_data = { + .version = SPI_VERSION_1, + .prescaler_limit = 2, +}; + +static const struct davinci_spi_of_data da830_spi_data = { + .version = SPI_VERSION_2, + .prescaler_limit = 2, +}; + +static const struct davinci_spi_of_data keystone_spi_data = { + .version = SPI_VERSION_1, + .prescaler_limit = 0, +}; + static const struct of_device_id davinci_spi_of_match[] = { { .compatible = "ti,dm6441-spi", + .data = &dm6441_spi_data, }, { .compatible = "ti,da830-spi", - .data = (void *)SPI_VERSION_2, + .data = &da830_spi_data, + }, + { + .compatible = "ti,keystone-spi", + .data = &keystone_spi_data, }, { }, }; @@ -858,21 +887,21 @@ static int spi_davinci_get_pdata(struct platform_device *pdev, struct davinci_spi *dspi) { struct device_node *node = pdev->dev.of_node; + struct davinci_spi_of_data *spi_data; struct davinci_spi_platform_data *pdata; unsigned int num_cs, intr_line = 0; const struct of_device_id *match; pdata = &dspi->pdata; - pdata->version = SPI_VERSION_1; match = of_match_device(davinci_spi_of_match, &pdev->dev); if (!match) return -ENODEV; - /* match data has the SPI version number for SPI_VERSION_2 */ - if (match->data == (void *)SPI_VERSION_2) - pdata->version = SPI_VERSION_2; + spi_data = (struct davinci_spi_of_data *)match->data; + pdata->version = spi_data->version; + pdata->prescaler_limit = spi_data->prescaler_limit; /* * default num_cs is 1 and all chipsel are internal to the chip * indicated by chip_sel being NULL or cs_gpios being NULL or @@ -992,7 +1021,7 @@ static int davinci_spi_probe(struct platform_device *pdev) dspi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer; - + dspi->prescaler_limit = pdata->prescaler_limit; dspi->version = pdata->version; dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP; diff --git a/include/linux/platform_data/spi-davinci.h b/include/linux/platform_data/spi-davinci.h index 8dc2fa47a2aa..f4edcb03c40c 100644 --- a/include/linux/platform_data/spi-davinci.h +++ b/include/linux/platform_data/spi-davinci.h @@ -49,6 +49,7 @@ struct davinci_spi_platform_data { u8 num_chipselect; u8 intr_line; u8 *chip_sel; + u8 prescaler_limit; bool cshold_bug; enum dma_event_q dma_event_q; }; -- cgit v1.3-6-gb490 From 5f74db105b1c0980c9863e7a7d1bc0525e0316e8 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Wed, 22 Jul 2015 20:46:09 +0200 Subject: spi: omap2-mcspi: add runtime PM to set_cs() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ddcad7e9068eb omap2_mcspi_set_cs() is called without runtime power management requested. This patch fixes the problem by requesting runtime power management in omap2_mcspi_set_cs(). Reported-By: Pali Rohár Fixes: ddcad7e9068eb (spi: omap2-mcspi: Fix native cs with new set_cs) Tested-By: Pavel Machek Signed-off-by: Sebastian Reichel Acked-by: Michael Welling Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 58673841286c..3d09e0b69b73 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -245,6 +245,7 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) { + struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); u32 l; /* The controller handles the inverted chip selects @@ -255,6 +256,12 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) enable = !enable; if (spi->controller_state) { + int err = pm_runtime_get_sync(mcspi->dev); + if (err < 0) { + dev_err(mcspi->dev, "failed to get sync: %d\n", err); + return; + } + l = mcspi_cached_chconf0(spi); if (enable) @@ -263,6 +270,9 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) l |= OMAP2_MCSPI_CHCONF_FORCE; mcspi_write_chconf0(spi, l); + + pm_runtime_mark_last_busy(mcspi->dev); + pm_runtime_put_autosuspend(mcspi->dev); } } -- cgit v1.3-6-gb490 From 3a003baeec246f604ed1d2e0087560d7f15edcc6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 17 Jul 2015 14:41:54 -0700 Subject: regulator: Add over current protection (OCP) support Some regulators can automatically shut down when they detect an over current event. Add an op (set_over_current_protection) and a DT property + constraint to support this capability. Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/regulator.txt | 1 + drivers/regulator/core.c | 9 +++++++++ drivers/regulator/of_regulator.c | 3 +++ include/linux/regulator/driver.h | 1 + include/linux/regulator/machine.h | 1 + 5 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index db88feb28c03..24bd422cecd5 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -42,6 +42,7 @@ Optional properties: - regulator-system-load: Load in uA present on regulator that is not captured by any consumer request. - regulator-pull-down: Enable pull down resistor when the regulator is disabled. +- regulator-over-current-protection: Enable over current protection. Deprecated properties: - regulator-compatible: If a regulator chip contains multiple diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c9f72019bd68..520413e2bca0 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1081,6 +1081,15 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } + if (rdev->constraints->over_current_protection + && ops->set_over_current_protection) { + ret = ops->set_over_current_protection(rdev); + if (ret < 0) { + rdev_err(rdev, "failed to set over current protection\n"); + goto out; + } + } + print_constraints(rdev); return 0; out: diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index b1c485b24ab2..250700c853bf 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -107,6 +107,9 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(np, "regulator-system-load", &pval)) constraints->system_load = pval; + constraints->over_current_protection = of_property_read_bool(np, + "regulator-over-current-protection"); + for (i = 0; i < ARRAY_SIZE(regulator_states); i++) { switch (i) { case PM_SUSPEND_MEM: diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4db9fbe4889d..45932228cbf5 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -148,6 +148,7 @@ struct regulator_ops { int (*get_current_limit) (struct regulator_dev *); int (*set_input_current_limit) (struct regulator_dev *, int lim_uA); + int (*set_over_current_protection) (struct regulator_dev *); /* enable/disable regulator */ int (*enable) (struct regulator_dev *); diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index b11be1260129..a1067d0b3991 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -147,6 +147,7 @@ struct regulation_constraints { unsigned ramp_disable:1; /* disable ramp delay */ unsigned soft_start:1; /* ramp voltage slowly */ unsigned pull_down:1; /* pull down resistor when regulator off */ + unsigned over_current_protection:1; /* auto disable on over current */ }; /** -- cgit v1.3-6-gb490 From e2adfacde619d8e39dc8c02919bd2524d3c39588 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 17 Jul 2015 14:41:55 -0700 Subject: regulator: qcom-spmi: Add vendor specific configuration Add support for over current protection (OCP), pin control selection, soft start strength, and auto-mode. Cc: Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- .../bindings/regulator/qcom,spmi-regulator.txt | 60 ++++++- drivers/regulator/qcom_spmi-regulator.c | 200 ++++++++++++++++++++- 2 files changed, 251 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt index 75b4604bad07..d00bfd8624a5 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt @@ -91,13 +91,65 @@ see regulator.txt - with additional custom properties described below: - regulator-initial-mode: Usage: optional Value type: - Descrption: 1 = Set initial mode to high power mode (HPM), also referred - to as NPM. HPM consumes more ground current than LPM, but + Description: 2 = Set initial mode to auto mode (automatically select + between HPM and LPM); not available on boost type + regulators. + + 1 = Set initial mode to high power mode (HPM), also referred + to as NPM. HPM consumes more ground current than LPM, but it can source significantly higher load current. HPM is not available on boost type regulators. For voltage switch type regulators, HPM implies that over current protection and - soft start are active all the time. 0 = Set initial mode to - low power mode (LPM). + soft start are active all the time. + + 0 = Set initial mode to low power mode (LPM). + +- qcom,ocp-max-retries: + Usage: optional + Value type: + Description: Maximum number of times to try toggling a voltage switch + off and back on as a result of consecutive over current + events. + +- qcom,ocp-retry-delay: + Usage: optional + Value type: + Description: Time to delay in milliseconds between each voltage switch + toggle after an over current event takes place. + +- qcom,pin-ctrl-enable: + Usage: optional + Value type: + Description: Bit mask specifying which hardware pins should be used to + enable the regulator, if any; supported bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal + +- qcom,pin-ctrl-hpm: + Usage: optional + Value type: + Description: Bit mask specifying which hardware pins should be used to + force the regulator into high power mode, if any; + supported bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal + BIT(4) = follow PMIC awake state + +- qcom,vs-soft-start-strength: + Usage: optional + Value type: + Description: This property sets the soft start strength for voltage + switch type regulators; supported values are: + 0 = 0.05 uA + 1 = 0.25 uA + 2 = 0.55 uA + 3 = 0.75 uA Example: diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 9ef0e2f28ec4..88a5dc88badc 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -26,6 +26,70 @@ #include #include +/* Pin control enable input pins. */ +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_NONE 0x00 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN0 0x01 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN1 0x02 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN2 0x04 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_EN3 0x08 +#define SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT 0x10 + +/* Pin control high power mode input pins. */ +#define SPMI_REGULATOR_PIN_CTRL_HPM_NONE 0x00 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN0 0x01 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN1 0x02 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN2 0x04 +#define SPMI_REGULATOR_PIN_CTRL_HPM_EN3 0x08 +#define SPMI_REGULATOR_PIN_CTRL_HPM_SLEEP_B 0x10 +#define SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT 0x20 + +/* + * Used with enable parameters to specify that hardware default register values + * should be left unaltered. + */ +#define SPMI_REGULATOR_USE_HW_DEFAULT 2 + +/* Soft start strength of a voltage switch type regulator */ +enum spmi_vs_soft_start_str { + SPMI_VS_SOFT_START_STR_0P05_UA = 0, + SPMI_VS_SOFT_START_STR_0P25_UA, + SPMI_VS_SOFT_START_STR_0P55_UA, + SPMI_VS_SOFT_START_STR_0P75_UA, + SPMI_VS_SOFT_START_STR_HW_DEFAULT, +}; + +/** + * struct spmi_regulator_init_data - spmi-regulator initialization data + * @pin_ctrl_enable: Bit mask specifying which hardware pins should be + * used to enable the regulator, if any + * Value should be an ORing of + * SPMI_REGULATOR_PIN_CTRL_ENABLE_* constants. If + * the bit specified by + * SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT is + * set, then pin control enable hardware registers + * will not be modified. + * @pin_ctrl_hpm: Bit mask specifying which hardware pins should be + * used to force the regulator into high power + * mode, if any + * Value should be an ORing of + * SPMI_REGULATOR_PIN_CTRL_HPM_* constants. If + * the bit specified by + * SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT is + * set, then pin control mode hardware registers + * will not be modified. + * @vs_soft_start_strength: This parameter sets the soft start strength for + * voltage switch type regulators. Its value + * should be one of SPMI_VS_SOFT_START_STR_*. If + * its value is SPMI_VS_SOFT_START_STR_HW_DEFAULT, + * then the soft start strength will be left at its + * default hardware value. + */ +struct spmi_regulator_init_data { + unsigned pin_ctrl_enable; + unsigned pin_ctrl_hpm; + enum spmi_vs_soft_start_str vs_soft_start_strength; +}; + /* These types correspond to unique register layouts. */ enum spmi_regulator_logical_type { SPMI_REGULATOR_LOGICAL_TYPE_SMPS, @@ -458,6 +522,14 @@ static int spmi_regulator_vs_enable(struct regulator_dev *rdev) return spmi_regulator_common_enable(rdev); } +static int spmi_regulator_vs_ocp(struct regulator_dev *rdev) +{ + struct spmi_regulator *vreg = rdev_get_drvdata(rdev); + u8 reg = SPMI_VS_OCP_OVERRIDE; + + return spmi_vreg_write(vreg, SPMI_VS_REG_OCP, ®, 1); +} + static int spmi_regulator_common_disable(struct regulator_dev *rdev) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); @@ -791,6 +863,9 @@ static unsigned int spmi_regulator_common_get_mode(struct regulator_dev *rdev) if (reg & SPMI_COMMON_MODE_HPM_MASK) return REGULATOR_MODE_NORMAL; + if (reg & SPMI_COMMON_MODE_AUTO_MASK) + return REGULATOR_MODE_FAST; + return REGULATOR_MODE_IDLE; } @@ -798,11 +873,13 @@ static int spmi_regulator_common_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct spmi_regulator *vreg = rdev_get_drvdata(rdev); - u8 mask = SPMI_COMMON_MODE_HPM_MASK; + u8 mask = SPMI_COMMON_MODE_HPM_MASK | SPMI_COMMON_MODE_AUTO_MASK; u8 val = 0; if (mode == REGULATOR_MODE_NORMAL) - val = mask; + val = SPMI_COMMON_MODE_HPM_MASK; + else if (mode == REGULATOR_MODE_FAST) + val = SPMI_COMMON_MODE_AUTO_MASK; return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask); } @@ -972,6 +1049,7 @@ static struct regulator_ops spmi_vs_ops = { .is_enabled = spmi_regulator_common_is_enabled, .set_pull_down = spmi_regulator_common_set_pull_down, .set_soft_start = spmi_regulator_common_set_soft_start, + .set_over_current_protection = spmi_regulator_vs_ocp, }; static struct regulator_ops spmi_boost_ops = { @@ -1202,10 +1280,111 @@ static int spmi_regulator_ftsmps_init_slew_rate(struct spmi_regulator *vreg) return ret; } +static int spmi_regulator_init_registers(struct spmi_regulator *vreg, + const struct spmi_regulator_init_data *data) +{ + int ret; + enum spmi_regulator_logical_type type; + u8 ctrl_reg[8], reg, mask; + + type = vreg->logical_type; + + ret = spmi_vreg_read(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, ctrl_reg, 8); + if (ret) + return ret; + + /* Set up enable pin control. */ + if ((type == SPMI_REGULATOR_LOGICAL_TYPE_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_LDO + || type == SPMI_REGULATOR_LOGICAL_TYPE_VS) + && !(data->pin_ctrl_enable + & SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_ENABLE] &= + ~SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK; + ctrl_reg[SPMI_COMMON_IDX_ENABLE] |= + data->pin_ctrl_enable & SPMI_COMMON_ENABLE_FOLLOW_ALL_MASK; + } + + /* Set up mode pin control. */ + if ((type == SPMI_REGULATOR_LOGICAL_TYPE_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_LDO) + && !(data->pin_ctrl_hpm + & SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_MODE] &= + ~SPMI_COMMON_MODE_FOLLOW_ALL_MASK; + ctrl_reg[SPMI_COMMON_IDX_MODE] |= + data->pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_ALL_MASK; + } + + if (type == SPMI_REGULATOR_LOGICAL_TYPE_VS + && !(data->pin_ctrl_hpm & SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_MODE] &= + ~SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + ctrl_reg[SPMI_COMMON_IDX_MODE] |= + data->pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + } + + if ((type == SPMI_REGULATOR_LOGICAL_TYPE_ULT_LO_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_ULT_HO_SMPS + || type == SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO) + && !(data->pin_ctrl_hpm + & SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT)) { + ctrl_reg[SPMI_COMMON_IDX_MODE] &= + ~SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + ctrl_reg[SPMI_COMMON_IDX_MODE] |= + data->pin_ctrl_hpm & SPMI_COMMON_MODE_FOLLOW_AWAKE_MASK; + } + + /* Write back any control register values that were modified. */ + ret = spmi_vreg_write(vreg, SPMI_COMMON_REG_VOLTAGE_RANGE, ctrl_reg, 8); + if (ret) + return ret; + + /* Set soft start strength and over current protection for VS. */ + if (type == SPMI_REGULATOR_LOGICAL_TYPE_VS) { + if (data->vs_soft_start_strength + != SPMI_VS_SOFT_START_STR_HW_DEFAULT) { + reg = data->vs_soft_start_strength + & SPMI_VS_SOFT_START_SEL_MASK; + mask = SPMI_VS_SOFT_START_SEL_MASK; + return spmi_vreg_update_bits(vreg, + SPMI_VS_REG_SOFT_START, + reg, mask); + } + } + + return 0; +} + +static void spmi_regulator_get_dt_config(struct spmi_regulator *vreg, + struct device_node *node, struct spmi_regulator_init_data *data) +{ + /* + * Initialize configuration parameters to use hardware default in case + * no value is specified via device tree. + */ + data->pin_ctrl_enable = SPMI_REGULATOR_PIN_CTRL_ENABLE_HW_DEFAULT; + data->pin_ctrl_hpm = SPMI_REGULATOR_PIN_CTRL_HPM_HW_DEFAULT; + data->vs_soft_start_strength = SPMI_VS_SOFT_START_STR_HW_DEFAULT; + + /* These bindings are optional, so it is okay if they aren't found. */ + of_property_read_u32(node, "qcom,ocp-max-retries", + &vreg->ocp_max_retries); + of_property_read_u32(node, "qcom,ocp-retry-delay", + &vreg->ocp_retry_delay_ms); + of_property_read_u32(node, "qcom,pin-ctrl-enable", + &data->pin_ctrl_enable); + of_property_read_u32(node, "qcom,pin-ctrl-hpm", &data->pin_ctrl_hpm); + of_property_read_u32(node, "qcom,vs-soft-start-strength", + &data->vs_soft_start_strength); +} + static unsigned int spmi_regulator_of_map_mode(unsigned int mode) { - if (mode) + if (mode == 1) return REGULATOR_MODE_NORMAL; + if (mode == 2) + return REGULATOR_MODE_FAST; return REGULATOR_MODE_IDLE; } @@ -1214,12 +1393,23 @@ static int spmi_regulator_of_parse(struct device_node *node, const struct regulator_desc *desc, struct regulator_config *config) { + struct spmi_regulator_init_data data = { }; struct spmi_regulator *vreg = config->driver_data; struct device *dev = config->dev; int ret; - vreg->ocp_max_retries = SPMI_VS_OCP_DEFAULT_MAX_RETRIES; - vreg->ocp_retry_delay_ms = SPMI_VS_OCP_DEFAULT_RETRY_DELAY_MS; + spmi_regulator_get_dt_config(vreg, node, &data); + + if (!vreg->ocp_max_retries) + vreg->ocp_max_retries = SPMI_VS_OCP_DEFAULT_MAX_RETRIES; + if (!vreg->ocp_retry_delay_ms) + vreg->ocp_retry_delay_ms = SPMI_VS_OCP_DEFAULT_RETRY_DELAY_MS; + + ret = spmi_regulator_init_registers(vreg, &data); + if (ret) { + dev_err(dev, "common initialization failed, ret=%d\n", ret); + return ret; + } if (vreg->logical_type == SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS) { ret = spmi_regulator_ftsmps_init_slew_rate(vreg); -- cgit v1.3-6-gb490 From c37f45b5f1cdfcdc351d88950b32658c970582ca Mon Sep 17 00:00:00 2001 From: Leilk Liu Date: Thu, 23 Jul 2015 17:10:40 +0800 Subject: spi: support spi without dma channel to use can_dma() For spi without dma channel and use can_dma(), it can use master->dev for struct device. Signed-off-by: Leilk Liu Signed-off-by: Mark Brown --- drivers/spi/spi.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index cf8b91b23a76..f725085a5f07 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -539,8 +539,15 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg) if (!master->can_dma) return 0; - tx_dev = master->dma_tx->device->dev; - rx_dev = master->dma_rx->device->dev; + if (master->dma_tx) + tx_dev = master->dma_tx->device->dev; + else + tx_dev = &master->dev; + + if (master->dma_rx) + rx_dev = master->dma_rx->device->dev; + else + rx_dev = &master->dev; list_for_each_entry(xfer, &msg->transfers, transfer_list) { if (!master->can_dma(master, msg->spi, xfer)) @@ -579,8 +586,15 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg) if (!master->cur_msg_mapped || !master->can_dma) return 0; - tx_dev = master->dma_tx->device->dev; - rx_dev = master->dma_rx->device->dev; + if (master->dma_tx) + tx_dev = master->dma_tx->device->dev; + else + tx_dev = &master->dev; + + if (master->dma_rx) + rx_dev = master->dma_rx->device->dev; + else + rx_dev = &master->dev; list_for_each_entry(xfer, &msg->transfers, transfer_list) { if (!master->can_dma(master, msg->spi, xfer)) -- cgit v1.3-6-gb490 From 423b24c37dd5794a674c74b0ed56392003a69891 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 23 Jul 2015 16:46:57 +0100 Subject: staging: comedi: usbduxsigma: don't clobber ai_timer in command test `devpriv->ai_timer` is used while an asynchronous command is running on the AI subdevice. It also gets modified by the subdevice's `cmdtest` handler for checking new asynchronous commands (`usbduxsigma_ai_cmdtest()`), which is not correct as it's allowed to check new commands while an old command is still running. Fix it by moving the code which sets up `devpriv->ai_timer` and `devpriv->ai_interval` into the subdevice's `cmd` handler, `usbduxsigma_ai_cmd()`. Note that the removed code in `usbduxsigma_ai_cmdtest()` checked that `devpriv->ai_timer` did not end up less than than 1, but that could not happen because `cmd->scan_begin_arg` had already been checked to be at least the minimum required value (at least when `cmd->scan_begin_src == TRIG_TIMER`, which had also been checked to be the case). Fixes: b986be8527c7 ("staging: comedi: usbduxsigma: tidy up analog input command support) Signed-off-by: Ian Abbott Reviewed-by: Bernd Porr Reviewed-by: H Hartley Sweeten Cc: # 3.19 onwards Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbduxsigma.c | 37 ++++++++++++---------------- 1 file changed, 16 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 51846adf8340..2d684747a639 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -551,27 +551,6 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev, if (err) return 3; - /* Step 4: fix up any arguments */ - - if (high_speed) { - /* - * every 2 channels get a time window of 125us. Thus, if we - * sample all 16 channels we need 1ms. If we sample only one - * channel we need only 125us - */ - devpriv->ai_interval = interval; - devpriv->ai_timer = cmd->scan_begin_arg / (125000 * interval); - } else { - /* interval always 1ms */ - devpriv->ai_interval = 1; - devpriv->ai_timer = cmd->scan_begin_arg / 1000000; - } - if (devpriv->ai_timer < 1) - err |= -EINVAL; - - if (err) - return 4; - return 0; } @@ -669,6 +648,22 @@ static int usbduxsigma_ai_cmd(struct comedi_device *dev, down(&devpriv->sem); + if (devpriv->high_speed) { + /* + * every 2 channels get a time window of 125us. Thus, if we + * sample all 16 channels we need 1ms. If we sample only one + * channel we need only 125us + */ + unsigned int interval = usbduxsigma_chans_to_interval(len); + + devpriv->ai_interval = interval; + devpriv->ai_timer = cmd->scan_begin_arg / (125000 * interval); + } else { + /* interval always 1ms */ + devpriv->ai_interval = 1; + devpriv->ai_timer = cmd->scan_begin_arg / 1000000; + } + for (i = 0; i < len; i++) { unsigned int chan = CR_CHAN(cmd->chanlist[i]); -- cgit v1.3-6-gb490 From c04a1f17803e0d3eeada586ca34a6b436959bc20 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 23 Jul 2015 16:46:58 +0100 Subject: staging: comedi: usbduxsigma: don't clobber ao_timer in command test `devpriv->ao_timer` is used while an asynchronous command is running on the AO subdevice. It also gets modified by the subdevice's `cmdtest` handler for checking new asynchronous commands, `usbduxsigma_ao_cmdtest()`, which is not correct as it's allowed to check new commands while an old command is still running. Fix it by moving the code which sets up `devpriv->ao_timer` into the subdevice's `cmd` handler, `usbduxsigma_ao_cmd()`. Note that the removed code in `usbduxsigma_ao_cmdtest()` checked that `devpriv->ao_timer` did not end up less that 1, but that could not happen due because `cmd->scan_begin_arg` or `cmd->convert_arg` had already been range-checked. Also note that we tested the `high_speed` variable in the old code, but that is currently always 0 and means that we always use "scan" timing (`cmd->scan_begin_src == TRIG_TIMER` and `cmd->convert_src == TRIG_NOW`) and never "convert" (individual sample) timing (`cmd->scan_begin_src == TRIG_FOLLOW` and `cmd->convert_src == TRIG_TIMER`). The moved code tests `cmd->convert_src` instead to decide whether "scan" or "convert" timing is being used, although currently only "scan" timing is supported. Fixes: fb1ef622e7a3 ("staging: comedi: usbduxsigma: tidy up analog output command support") Signed-off-by: Ian Abbott Reviewed-by: Bernd Porr Reviewed-by: H Hartley Sweeten Cc: # 3.19 onwards Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbduxsigma.c | 33 ++++++++++++---------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 2d684747a639..dcb7f3037dea 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -914,25 +914,6 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev, if (err) return 3; - /* Step 4: fix up any arguments */ - - /* we count in timer steps */ - if (high_speed) { - /* timing of the conversion itself: every 125 us */ - devpriv->ao_timer = cmd->convert_arg / 125000; - } else { - /* - * timing of the scan: every 1ms - * we get all channels at once - */ - devpriv->ao_timer = cmd->scan_begin_arg / 1000000; - } - if (devpriv->ao_timer < 1) - err |= -EINVAL; - - if (err) - return 4; - return 0; } @@ -945,6 +926,20 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev, down(&devpriv->sem); + if (cmd->convert_src == TRIG_TIMER) { + /* + * timing of the conversion itself: every 125 us + * at high speed (not used yet) + */ + devpriv->ao_timer = cmd->convert_arg / 125000; + } else { + /* + * timing of the scan: every 1ms + * we get all channels at once + */ + devpriv->ao_timer = cmd->scan_begin_arg / 1000000; + } + devpriv->ao_counter = devpriv->ao_timer; if (cmd->start_src == TRIG_NOW) { -- cgit v1.3-6-gb490 From 12e1e6960130673aabbbe7f094c4690b00618881 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 23 Jul 2015 16:46:59 +0100 Subject: staging: comedi: usbduxsigma: remove AI scan_begin_src == TRIG_FOLLOW The AI subdevice `cmdtest` handler `usbduxsigma_ai_cmdtest()` ensures that `cmd->scan_begin_src == TRIG_TIMER` by the end of step 2 of the command checking code, so assume that this is the case for step 3 onwards and remove the redundant code. Signed-off-by: Ian Abbott Reviewed-by: Bernd Porr Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbduxsigma.c | 47 +++++++++++----------------- 1 file changed, 19 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index dcb7f3037dea..fdc880a4adaf 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -482,6 +482,7 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev, struct usbduxsigma_private *devpriv = dev->private; int high_speed = devpriv->high_speed; int interval = usbduxsigma_chans_to_interval(cmd->chanlist_len); + unsigned int tmp; int err = 0; /* Step 1 : check if triggers are trivially valid */ @@ -509,36 +510,26 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev, err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */ - err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + if (high_speed) { + /* + * In high speed mode microframes are possible. + * However, during one microframe we can roughly + * sample two channels. Thus, the more channels + * are in the channel list the more time we need. + */ + err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, + (125000 * interval)); - if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int tmp; - - if (high_speed) { - /* - * In high speed mode microframes are possible. - * However, during one microframe we can roughly - * sample two channels. Thus, the more channels - * are in the channel list the more time we need. - */ - err |= comedi_check_trigger_arg_min(&cmd-> - scan_begin_arg, - (1000000 / 8 * - interval)); - - tmp = (cmd->scan_begin_arg / 125000) * 125000; - } else { - /* full speed */ - /* 1kHz scans every USB frame */ - err |= comedi_check_trigger_arg_min(&cmd-> - scan_begin_arg, - 1000000); - - tmp = (cmd->scan_begin_arg / 1000000) * 1000000; - } - err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, tmp); + tmp = (cmd->scan_begin_arg / 125000) * 125000; + } else { + /* full speed */ + /* 1kHz scans every USB frame */ + err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, + 1000000); + + tmp = (cmd->scan_begin_arg / 1000000) * 1000000; } + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, tmp); err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); -- cgit v1.3-6-gb490 From 333e40aee3f2d0457e2cbadc742619a6f449b2e7 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 23 Jul 2015 16:47:00 +0100 Subject: staging: comedi: usbduxsigma: round down AI scan_begin_arg at step 4. The return value of the `cmdtest` handler for a subdevice checks the prospective new command in various steps and returns the step number at which any problem was detected, or 0 if no problem was detected. It is allowed to modify the command in various ways at each step. Corrections for out-of-range values are generally made at step 3, and minor adjustments such as rounding are generally made at step 4. The `cmdtest` handler for the AI subdevice (`usbduxsigma_ai_cmdtest()`) currently modifies `cmd->scan_begin_arg` to bring it into range and round it down at step 3. Move the rounding down part to step 4 to follow the usual Comedi convention. Signed-off-by: Ian Abbott Reviewed-by: Bernd Porr Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbduxsigma.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index fdc880a4adaf..535cf01bca07 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -519,17 +519,12 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev, */ err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, (125000 * interval)); - - tmp = (cmd->scan_begin_arg / 125000) * 125000; } else { /* full speed */ /* 1kHz scans every USB frame */ err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, 1000000); - - tmp = (cmd->scan_begin_arg / 1000000) * 1000000; } - err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, tmp); err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); @@ -542,6 +537,14 @@ static int usbduxsigma_ai_cmdtest(struct comedi_device *dev, if (err) return 3; + /* Step 4: fix up any arguments */ + + tmp = rounddown(cmd->scan_begin_arg, high_speed ? 125000 : 1000000); + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, tmp); + + if (err) + return 4; + return 0; } -- cgit v1.3-6-gb490 From 57befc33af0243e9b3835d46ab836406256f5dd4 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 23 Jul 2015 16:47:01 +0100 Subject: staging: comedi: usbduxsigma: remove unused "convert" timing for AO The `cmdtest` and `cmd` handlers for the AO subdevice (`usbduxsigma_ao_cmdtest()` and `usbduxsigma_ao_cmd()`) support "scan" timing of commands with all channels updated every "scan" period. There is some disabled code to use "convert" timing in high speed mode. That would allow channels to be updated sequentially every "convert" period. Since that code is incomplete and currently disabled, remove it to simplify the existing code. Signed-off-by: Ian Abbott Reviewed-by: Bernd Porr Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbduxsigma.c | 58 ++++++++-------------------- 1 file changed, 17 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 535cf01bca07..9f43e01b58c5 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -840,28 +840,20 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev, { struct usbduxsigma_private *devpriv = dev->private; int err = 0; - int high_speed; - unsigned int flags; - - /* high speed conversions are not used yet */ - high_speed = 0; /* (devpriv->high_speed) */ /* Step 1 : check if triggers are trivially valid */ err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); - if (high_speed) { - /* - * start immediately a new scan - * the sampling rate is set by the coversion rate - */ - flags = TRIG_FOLLOW; - } else { - /* start a new scan (output at once) with a timer */ - flags = TRIG_TIMER; - } - err |= comedi_check_trigger_src(&cmd->scan_begin_src, flags); - + /* + * For now, always use "scan" timing with all channels updated at once + * (cmd->scan_begin_src == TRIG_TIMER, cmd->convert_src == TRIG_NOW). + * + * In a future version, "convert" timing with channels updated + * indivually may be supported in high speed mode + * (cmd->scan_begin_src == TRIG_FOLLOW, cmd->convert_src == TRIG_TIMER). + */ + err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW); err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); @@ -885,17 +877,7 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev, err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */ - err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - - if (cmd->scan_begin_src == TRIG_TIMER) { - err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, - 1000000); - } - - /* not used now, is for later use */ - if (cmd->convert_src == TRIG_TIMER) - err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 125000); + err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, 1000000); err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); @@ -920,19 +902,13 @@ static int usbduxsigma_ao_cmd(struct comedi_device *dev, down(&devpriv->sem); - if (cmd->convert_src == TRIG_TIMER) { - /* - * timing of the conversion itself: every 125 us - * at high speed (not used yet) - */ - devpriv->ao_timer = cmd->convert_arg / 125000; - } else { - /* - * timing of the scan: every 1ms - * we get all channels at once - */ - devpriv->ao_timer = cmd->scan_begin_arg / 1000000; - } + /* + * For now, only "scan" timing is supported. A future version may + * support "convert" timing in high speed mode. + * + * Timing of the scan: every 1ms all channels updated at once. + */ + devpriv->ao_timer = cmd->scan_begin_arg / 1000000; devpriv->ao_counter = devpriv->ao_timer; -- cgit v1.3-6-gb490 From ed2c2e060b6c3cd5fc42993011aa41c765ff1b2f Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 23 Jul 2015 16:47:02 +0100 Subject: staging: comedi: usbduxsigma: round down AO scan_begin_arg at step 4. The return value of the `cmdtest` handler for a subdevice checks the prospective new command in various steps and returns the step number at which any problem was detected, or 0 if no problem was detected. It is allowed to modify the command in various ways at each step. Corrections for out-of-range values are generally made at step 3, and minor adjustments such as rounding are generally made at step 4. The `cmdtest` handler for the AO subdevice (`usbduxsigma_ao_cmdtest()`) currently range checks the timings at step 3. Since the running command will round down the timings, add code to round them down at step 4. Signed-off-by: Ian Abbott Reviewed-by: Bernd Porr Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbduxsigma.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 9f43e01b58c5..649cf47184a4 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -839,6 +839,7 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { struct usbduxsigma_private *devpriv = dev->private; + unsigned int tmp; int err = 0; /* Step 1 : check if triggers are trivially valid */ @@ -890,6 +891,14 @@ static int usbduxsigma_ao_cmdtest(struct comedi_device *dev, if (err) return 3; + /* Step 4: fix up any arguments */ + + tmp = rounddown(cmd->scan_begin_arg, 1000000); + err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, tmp); + + if (err) + return 4; + return 0; } -- cgit v1.3-6-gb490 From 5143f7a3e970a1d0b6659cf41a3b46dd48a9bc6f Mon Sep 17 00:00:00 2001 From: Ioan-Adrian Ratiu Date: Thu, 23 Jul 2015 16:24:10 +0300 Subject: staging: rtl8192e: rtllib: fix macro style issue Remove macro and use explicit case statements. Code is a little longer but clearer. Checkpatch.pl does not complain anymore. Signed-off-by: Ioan-Adrian Ratiu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib_rx.c | 80 +++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c index 54dfff61f485..09f0820fb340 100644 --- a/drivers/staging/rtl8192e/rtllib_rx.c +++ b/drivers/staging/rtl8192e/rtllib_rx.c @@ -1744,37 +1744,61 @@ static int rtllib_parse_qos_info_param_IE(struct rtllib_device *ieee, return rc; } -#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x - static const char *get_info_element_string(u16 id) { switch (id) { - MFIE_STRING(SSID); - MFIE_STRING(RATES); - MFIE_STRING(FH_SET); - MFIE_STRING(DS_SET); - MFIE_STRING(CF_SET); - MFIE_STRING(TIM); - MFIE_STRING(IBSS_SET); - MFIE_STRING(COUNTRY); - MFIE_STRING(HOP_PARAMS); - MFIE_STRING(HOP_TABLE); - MFIE_STRING(REQUEST); - MFIE_STRING(CHALLENGE); - MFIE_STRING(POWER_CONSTRAINT); - MFIE_STRING(POWER_CAPABILITY); - MFIE_STRING(TPC_REQUEST); - MFIE_STRING(TPC_REPORT); - MFIE_STRING(SUPP_CHANNELS); - MFIE_STRING(CSA); - MFIE_STRING(MEASURE_REQUEST); - MFIE_STRING(MEASURE_REPORT); - MFIE_STRING(QUIET); - MFIE_STRING(IBSS_DFS); - MFIE_STRING(RSN); - MFIE_STRING(RATES_EX); - MFIE_STRING(GENERIC); - MFIE_STRING(QOS_PARAMETER); + case MFIE_TYPE_SSID: + return "SSID"; + case MFIE_TYPE_RATES: + return "RATES"; + case MFIE_TYPE_FH_SET: + return "FH_SET"; + case MFIE_TYPE_DS_SET: + return "DS_SET"; + case MFIE_TYPE_CF_SET: + return "CF_SET"; + case MFIE_TYPE_TIM: + return "TIM"; + case MFIE_TYPE_IBSS_SET: + return "IBSS_SET"; + case MFIE_TYPE_COUNTRY: + return "COUNTRY"; + case MFIE_TYPE_HOP_PARAMS: + return "HOP_PARAMS"; + case MFIE_TYPE_HOP_TABLE: + return "HOP_TABLE"; + case MFIE_TYPE_REQUEST: + return "REQUEST"; + case MFIE_TYPE_CHALLENGE: + return "CHALLENGE"; + case MFIE_TYPE_POWER_CONSTRAINT: + return "POWER_CONSTRAINT"; + case MFIE_TYPE_POWER_CAPABILITY: + return "POWER_CAPABILITY"; + case MFIE_TYPE_TPC_REQUEST: + return "TPC_REQUEST"; + case MFIE_TYPE_TPC_REPORT: + return "TPC_REPORT"; + case MFIE_TYPE_SUPP_CHANNELS: + return "SUPP_CHANNELS"; + case MFIE_TYPE_CSA: + return "CSA"; + case MFIE_TYPE_MEASURE_REQUEST: + return "MEASURE_REQUEST"; + case MFIE_TYPE_MEASURE_REPORT: + return "MEASURE_REPORT"; + case MFIE_TYPE_QUIET: + return "QUIET"; + case MFIE_TYPE_IBSS_DFS: + return "IBSS_DFS"; + case MFIE_TYPE_RSN: + return "RSN"; + case MFIE_TYPE_RATES_EX: + return "RATES_EX"; + case MFIE_TYPE_GENERIC: + return "GENERIC"; + case MFIE_TYPE_QOS_PARAMETER: + return "QOS_PARAMETER"; default: return "UNKNOWN"; } -- cgit v1.3-6-gb490 From b4ba3b572b469684a3fc804bd2b93fbf848960ea Mon Sep 17 00:00:00 2001 From: Buţiu Alexandru Octavian Date: Fri, 24 Jul 2015 00:13:27 +0300 Subject: drivers: staging: rtl8188eu Refactored rtw_free_assoc_resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactored rtw_free_assoc_resources to avoid sparse warnings about different contexts for basic lock Signed-off-by: Buţiu Alexandru Octavian Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_ioctl_set.c | 10 +++++----- drivers/staging/rtl8188eu/core/rtw_mlme.c | 24 ++++++++++++++++-------- drivers/staging/rtl8188eu/core/rtw_pwrctrl.c | 2 +- drivers/staging/rtl8188eu/include/rtw_mlme.h | 3 ++- drivers/staging/rtl8188eu/os_dep/ioctl_linux.c | 2 +- drivers/staging/rtl8188eu/os_dep/os_intfs.c | 2 +- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 2 +- 7 files changed, 27 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c index 8c05cb021c46..22f5b45f5f7f 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c @@ -183,7 +183,7 @@ u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid) if (check_fwstate(pmlmepriv, _FW_LINKED) == true) rtw_indicate_disconnect(padapter); - rtw_free_assoc_resources(padapter, 1); + rtw_free_assoc_resources(padapter); if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); @@ -271,7 +271,7 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid) if (check_fwstate(pmlmepriv, _FW_LINKED) == true) rtw_indicate_disconnect(padapter); - rtw_free_assoc_resources(padapter, 1); + rtw_free_assoc_resources(padapter); if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) { _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); @@ -293,7 +293,7 @@ u8 rtw_set_802_11_ssid(struct adapter *padapter, struct ndis_802_11_ssid *ssid) if (check_fwstate(pmlmepriv, _FW_LINKED) == true) rtw_indicate_disconnect(padapter); - rtw_free_assoc_resources(padapter, 1); + rtw_free_assoc_resources(padapter); if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) { _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE); @@ -366,7 +366,7 @@ u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter, if ((check_fwstate(pmlmepriv, _FW_LINKED)) || (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))) - rtw_free_assoc_resources(padapter, 1); + rtw_free_assoc_resources(padapter); if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) { if (check_fwstate(pmlmepriv, _FW_LINKED) == true) @@ -415,7 +415,7 @@ u8 rtw_set_802_11_disassociate(struct adapter *padapter) rtw_disassoc_cmd(padapter, 0, true); rtw_indicate_disconnect(padapter); - rtw_free_assoc_resources(padapter, 1); + rtw_free_assoc_resources(padapter); rtw_pwr_wakeup(padapter); } diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index 2b599e3c0785..71a7a85571aa 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -704,7 +704,7 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) if (--pmlmepriv->to_roaming == 0 || _SUCCESS != rtw_sitesurvey_cmd(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0)) { pmlmepriv->to_roaming = 0; - rtw_free_assoc_resources(adapter, 1); + rtw_free_assoc_resources(adapter); rtw_indicate_disconnect(adapter); } else { pmlmepriv->to_join = true; @@ -758,7 +758,19 @@ static void free_scanqueue(struct mlme_priv *pmlmepriv) /* *rtw_free_assoc_resources: the caller has to lock pmlmepriv->lock */ -void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue) +void rtw_free_assoc_resources(struct adapter *adapter) +{ + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + + spin_lock_bh(&pmlmepriv->scanned_queue.lock); + rtw_free_assoc_resources_locked(adapter); + spin_unlock_bh(&pmlmepriv->scanned_queue.lock); +} + +/* +*rtw_free_assoc_resources_locked: the caller has to lock pmlmepriv->lock +*/ +void rtw_free_assoc_resources_locked(struct adapter *adapter) { struct wlan_network *pwlan = NULL; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; @@ -793,8 +805,6 @@ void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue) rtw_init_bcmc_stainfo(adapter); } - if (lock_scanned_queue) - spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); pwlan = rtw_find_network(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress); if (pwlan) @@ -805,8 +815,6 @@ void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue) if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1))) rtw_free_network_nolock(pmlmepriv, pwlan); - if (lock_scanned_queue) - spin_unlock_bh(&pmlmepriv->scanned_queue.lock); pmlmepriv->key_mask = 0; } @@ -1302,7 +1310,7 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) rtw_free_uc_swdec_pending_queue(adapter); - rtw_free_assoc_resources(adapter, 1); + rtw_free_assoc_resources(adapter); rtw_indicate_disconnect(adapter); spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); /* remove the network entry in scanned_queue */ @@ -1557,7 +1565,7 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) rtw_disassoc_cmd(adapter, 0, true); rtw_indicate_disconnect(adapter); - rtw_free_assoc_resources(adapter, 0); + rtw_free_assoc_resources_locked(adapter); } rtw_hal_get_def_var(adapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(supp_ant_div)); diff --git a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c index a2b54de21ed7..9765946466ab 100644 --- a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c @@ -70,7 +70,7 @@ static int rtw_hw_suspend(struct adapter *padapter) } } /* s2-3. */ - rtw_free_assoc_resources(padapter, 1); + rtw_free_assoc_resources(padapter); /* s2-4. */ rtw_free_network_queue(padapter, true); diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme.h b/drivers/staging/rtl8188eu/include/rtw_mlme.h index 8c7e8a36aa13..4c992573e3ca 100644 --- a/drivers/staging/rtl8188eu/include/rtw_mlme.h +++ b/drivers/staging/rtl8188eu/include/rtw_mlme.h @@ -535,7 +535,8 @@ void rtw_generate_random_ibss(u8 *pibss); struct wlan_network *rtw_find_network(struct __queue *scanned_queue, u8 *addr); struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue); -void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue); +void rtw_free_assoc_resources(struct adapter *adapter); +void rtw_free_assoc_resources_locked(struct adapter *adapter); void rtw_indicate_disconnect(struct adapter *adapter); void rtw_indicate_connect(struct adapter *adapter); void rtw_indicate_scan_done(struct adapter *padapter, bool aborted); diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index ce756cdb817b..2db86fbe29d2 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -1871,7 +1871,7 @@ static int rtw_wx_set_auth(struct net_device *dev, rtw_disassoc_cmd(padapter, 500, false); DBG_88E("%s...call rtw_indicate_disconnect\n ", __func__); rtw_indicate_disconnect(padapter); - rtw_free_assoc_resources(padapter, 1); + rtw_free_assoc_resources(padapter); } ret = wpa_set_auth_algs(dev, (u32)param->value); break; diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c index a14e79f31abf..2361bce480c3 100644 --- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c +++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c @@ -1175,7 +1175,7 @@ static int netdev_close(struct net_device *pnetdev) /* s2-2. indicate disconnect to os */ rtw_indicate_disconnect(padapter); /* s2-3. */ - rtw_free_assoc_resources(padapter, 1); + rtw_free_assoc_resources(padapter); /* s2-4. */ rtw_free_network_queue(padapter, true); /* Close LED */ diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 5f44c6a5b777..33bfe054f867 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -266,7 +266,7 @@ static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message) /* s2-2. indicate disconnect to os */ rtw_indicate_disconnect(padapter); /* s2-3. */ - rtw_free_assoc_resources(padapter, 1); + rtw_free_assoc_resources(padapter); /* s2-4. */ rtw_free_network_queue(padapter, true); -- cgit v1.3-6-gb490 From 3abf4f984adaa4e6fadf9d135ccb915c51bda057 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Fri, 24 Jul 2015 17:11:30 +0200 Subject: staging: rtl8188eu: kill unused hal_data_8188e::fw_ractrl flag Flag is never set. Remove it and the code that is dead because of it. Signed-off-by: Jakub Sitnicki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/hal/odm.c | 11 ++++------ drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c | 21 ------------------ drivers/staging/rtl8188eu/hal/usb_halinit.c | 27 ++---------------------- drivers/staging/rtl8188eu/include/rtl8188e_cmd.h | 1 - drivers/staging/rtl8188eu/include/rtl8188e_hal.h | 1 - drivers/staging/rtl8188eu/include/sta_info.h | 1 - 6 files changed, 6 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/hal/odm.c b/drivers/staging/rtl8188eu/hal/odm.c index 28b5e7bd4fc0..710fdc3449f8 100644 --- a/drivers/staging/rtl8188eu/hal/odm.c +++ b/drivers/staging/rtl8188eu/hal/odm.c @@ -1170,13 +1170,10 @@ void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm) } for (i = 0; i < sta_cnt; i++) { - if (PWDB_rssi[i] != (0)) { - if (pHalData->fw_ractrl) { - /* Report every sta's RSSI to FW */ - } else { - ODM_RA_SetRSSI_8188E( - &(pHalData->odmpriv), (PWDB_rssi[i]&0xFF), (u8)((PWDB_rssi[i]>>16) & 0xFF)); - } + if (PWDB_rssi[i] != 0) { + ODM_RA_SetRSSI_8188E(&pHalData->odmpriv, + PWDB_rssi[i] & 0xFF, + (PWDB_rssi[i] >> 16) & 0xFF); } } diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c index 86347f2ccdfd..0a62bfa210fe 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c @@ -127,27 +127,6 @@ exit: return ret; } -u8 rtl8188e_set_raid_cmd(struct adapter *adapt, u32 mask) -{ - u8 buf[3]; - u8 res = _SUCCESS; - struct hal_data_8188e *haldata = GET_HAL_DATA(adapt); - - if (haldata->fw_ractrl) { - - memset(buf, 0, 3); - put_unaligned_le32(mask, buf); - - FillH2CCmd_88E(adapt, H2C_DM_MACID_CFG, 3, buf); - } else { - DBG_88E("==>%s fw dont support RA\n", __func__); - res = _FAIL; - } - - - return res; -} - /* bitmap[0:27] = tx_rate_bitmap */ /* bitmap[28:31]= Rate Adaptive id */ /* arg[0:4] = macid */ diff --git a/drivers/staging/rtl8188eu/hal/usb_halinit.c b/drivers/staging/rtl8188eu/hal/usb_halinit.c index 6dc0869924ec..1ef878fd997b 100644 --- a/drivers/staging/rtl8188eu/hal/usb_halinit.c +++ b/drivers/staging/rtl8188eu/hal/usb_halinit.c @@ -743,19 +743,16 @@ static u32 rtl8188eu_hal_init(struct adapter *Adapter) if (Adapter->registrypriv.mp_mode == 1) { _InitRxSetting(Adapter); Adapter->bFWReady = false; - haldata->fw_ractrl = false; } else { status = rtl88eu_download_fw(Adapter); if (status) { DBG_88E("%s: Download Firmware failed!!\n", __func__); Adapter->bFWReady = false; - haldata->fw_ractrl = false; return status; } else { RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("Initializeadapt8192CSdio(): Download Firmware Success!!\n")); Adapter->bFWReady = true; - haldata->fw_ractrl = false; } } rtl8188e_InitializeFirmwareVars(Adapter); @@ -2016,28 +2013,9 @@ static void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_l init_rate = get_highest_rate_idx(mask)&0x3f; - if (haldata->fw_ractrl) { - u8 arg; + ODM_RA_UpdateRateInfo_8188E(&haldata->odmpriv, mac_id, + raid, mask, shortGIrate); - arg = mac_id & 0x1f;/* MACID */ - arg |= BIT(7); - if (shortGIrate) - arg |= BIT(5); - mask |= ((raid << 28) & 0xf0000000); - DBG_88E("update raid entry, mask=0x%x, arg=0x%x\n", mask, arg); - psta->ra_mask = mask; - mask |= ((raid << 28) & 0xf0000000); - - /* to do ,for 8188E-SMIC */ - rtl8188e_set_raid_cmd(adapt, mask); - } else { - ODM_RA_UpdateRateInfo_8188E(&(haldata->odmpriv), - mac_id, - raid, - mask, - shortGIrate - ); - } /* set ra_id */ psta->raid = raid; psta->init_rate = init_rate; @@ -2087,7 +2065,6 @@ static void rtl8188eu_init_default_value(struct adapter *adapt) pwrctrlpriv = &adapt->pwrctrlpriv; /* init default value */ - haldata->fw_ractrl = false; if (!pwrctrlpriv->bkeepfwalive) haldata->LastHMEBoxNum = 0; diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h b/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h index 42b1f22424eb..f813ce0563f8 100644 --- a/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h +++ b/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h @@ -107,7 +107,6 @@ struct P2P_PS_CTWPeriod_t { /* host message to firmware cmd */ void rtl8188e_set_FwPwrMode_cmd(struct adapter *padapter, u8 Mode); void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *padapter, u8 mstatus); -u8 rtl8188e_set_raid_cmd(struct adapter *padapter, u32 mask); void rtl8188e_Add_RateATid(struct adapter *padapter, u32 bitmap, u8 arg, u8 rssi_level); diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h index 5aa2adc1f013..cbad364f189c 100644 --- a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h +++ b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h @@ -294,7 +294,6 @@ struct hal_data_8188e { /* for host message to fw */ u8 LastHMEBoxNum; - u8 fw_ractrl; u8 RegTxPause; /* Beacon function related global variable. */ u32 RegBcnCtrlVal; diff --git a/drivers/staging/rtl8188eu/include/sta_info.h b/drivers/staging/rtl8188eu/include/sta_info.h index 9612490539b3..7bbeedfc49aa 100644 --- a/drivers/staging/rtl8188eu/include/sta_info.h +++ b/drivers/staging/rtl8188eu/include/sta_info.h @@ -113,7 +113,6 @@ struct sta_info { u8 raid; u8 init_rate; - u32 ra_mask; u8 wireless_mode; /* NETWORK_TYPE */ struct stainfo_stats sta_stats; -- cgit v1.3-6-gb490 From 7c03621a791499fdb47551693cd785f4fa5d03f8 Mon Sep 17 00:00:00 2001 From: David Kershner Date: Fri, 24 Jul 2015 12:00:21 -0400 Subject: staging: unisys: Process more than one response per check When s-Par is in polling mode it checks every 2 ms to see if there is a response from the IO service partition in the queue. Currently it just reads one entry per 2 ms, this needs to be changed so it drains the queue on each check. Signed-off-by: David Kershner Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 164 ++++++++++++------------ 1 file changed, 83 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 4d49937d3856..9d10b85ac7eb 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1629,93 +1629,95 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata) /* TODO: CLIENT ACQUIRE -- Don't really need this at the * moment */ - if (!visorchannel_signalremove(devdata->dev->visorchannel, - IOCHAN_FROM_IOPART, - cmdrsp)) - return; /* queue empty */ - - switch (cmdrsp->net.type) { - case NET_RCV: - devdata->chstat.got_rcv++; - /* process incoming packet */ - visornic_rx(cmdrsp); - break; - case NET_XMIT_DONE: - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->chstat.got_xmit_done++; - if (cmdrsp->net.xmtdone.xmt_done_result) - devdata->chstat.xmit_fail++; - /* only call queue wake if we stopped it */ - netdev = ((struct sk_buff *)cmdrsp->net.buf)->dev; - /* ASSERT netdev == vnicinfo->netdev; */ - if ((netdev == devdata->netdev) && - netif_queue_stopped(netdev)) { - /* check to see if we have crossed - * the lower watermark for - * netif_wake_queue() - */ - if (((devdata->chstat.sent_xmit >= - devdata->chstat.got_xmit_done) && - (devdata->chstat.sent_xmit - - devdata->chstat.got_xmit_done <= - devdata->lower_threshold_net_xmits)) || - ((devdata->chstat.sent_xmit < - devdata->chstat.got_xmit_done) && - (ULONG_MAX - devdata->chstat.got_xmit_done - + devdata->chstat.sent_xmit <= - devdata->lower_threshold_net_xmits))) { - /* enough NET_XMITs completed - * so can restart netif queue + for (;;) { + if (!visorchannel_signalremove(devdata->dev->visorchannel, + IOCHAN_FROM_IOPART, + cmdrsp)) + break; /* queue empty */ + + switch (cmdrsp->net.type) { + case NET_RCV: + devdata->chstat.got_rcv++; + /* process incoming packet */ + visornic_rx(cmdrsp); + break; + case NET_XMIT_DONE: + spin_lock_irqsave(&devdata->priv_lock, flags); + devdata->chstat.got_xmit_done++; + if (cmdrsp->net.xmtdone.xmt_done_result) + devdata->chstat.xmit_fail++; + /* only call queue wake if we stopped it */ + netdev = ((struct sk_buff *)cmdrsp->net.buf)->dev; + /* ASSERT netdev == vnicinfo->netdev; */ + if ((netdev == devdata->netdev) && + netif_queue_stopped(netdev)) { + /* check to see if we have crossed + * the lower watermark for + * netif_wake_queue() */ - netif_wake_queue(netdev); - devdata->flow_control_lower_hits++; + if (((devdata->chstat.sent_xmit >= + devdata->chstat.got_xmit_done) && + (devdata->chstat.sent_xmit - + devdata->chstat.got_xmit_done <= + devdata->lower_threshold_net_xmits)) || + ((devdata->chstat.sent_xmit < + devdata->chstat.got_xmit_done) && + (ULONG_MAX - devdata->chstat.got_xmit_done + + devdata->chstat.sent_xmit <= + devdata->lower_threshold_net_xmits))) { + /* enough NET_XMITs completed + * so can restart netif queue + */ + netif_wake_queue(netdev); + devdata->flow_control_lower_hits++; + } } - } - skb_unlink(cmdrsp->net.buf, &devdata->xmitbufhead); - spin_unlock_irqrestore(&devdata->priv_lock, flags); - kfree_skb(cmdrsp->net.buf); - break; - case NET_RCV_ENBDIS_ACK: - devdata->chstat.got_enbdisack++; - netdev = (struct net_device *) - cmdrsp->net.enbdis.context; - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enab_dis_acked = 1; - spin_unlock_irqrestore(&devdata->priv_lock, flags); - - if (kthread_should_stop()) + skb_unlink(cmdrsp->net.buf, &devdata->xmitbufhead); + spin_unlock_irqrestore(&devdata->priv_lock, flags); + kfree_skb(cmdrsp->net.buf); break; - if (devdata->server_down && - devdata->server_change_state) { - /* Inform Linux that the link is up */ - devdata->server_down = false; - devdata->server_change_state = false; - netif_wake_queue(netdev); - netif_carrier_on(netdev); - } - break; - case NET_CONNECT_STATUS: - netdev = devdata->netdev; - if (cmdrsp->net.enbdis.enable == 1) { - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enabled = cmdrsp->net.enbdis.enable; - spin_unlock_irqrestore(&devdata->priv_lock, - flags); - netif_wake_queue(netdev); - netif_carrier_on(netdev); - } else { - netif_stop_queue(netdev); - netif_carrier_off(netdev); + case NET_RCV_ENBDIS_ACK: + devdata->chstat.got_enbdisack++; + netdev = (struct net_device *) + cmdrsp->net.enbdis.context; spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enabled = cmdrsp->net.enbdis.enable; - spin_unlock_irqrestore(&devdata->priv_lock, - flags); + devdata->enab_dis_acked = 1; + spin_unlock_irqrestore(&devdata->priv_lock, flags); + + if (kthread_should_stop()) + break; + if (devdata->server_down && + devdata->server_change_state) { + /* Inform Linux that the link is up */ + devdata->server_down = false; + devdata->server_change_state = false; + netif_wake_queue(netdev); + netif_carrier_on(netdev); + } + break; + case NET_CONNECT_STATUS: + netdev = devdata->netdev; + if (cmdrsp->net.enbdis.enable == 1) { + spin_lock_irqsave(&devdata->priv_lock, flags); + devdata->enabled = cmdrsp->net.enbdis.enable; + spin_unlock_irqrestore(&devdata->priv_lock, + flags); + netif_wake_queue(netdev); + netif_carrier_on(netdev); + } else { + netif_stop_queue(netdev); + netif_carrier_off(netdev); + spin_lock_irqsave(&devdata->priv_lock, flags); + devdata->enabled = cmdrsp->net.enbdis.enable; + spin_unlock_irqrestore(&devdata->priv_lock, + flags); + } + break; + default: + break; } - break; - default: - break; + /* cmdrsp is now available for reuse */ } - /* cmdrsp is now available for reuse */ } /** -- cgit v1.3-6-gb490 From 4d79002e962466d455ae4933cd404cf5a1164894 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Fri, 24 Jul 2015 12:00:22 -0400 Subject: staging: unisys: visornic - ensure proper net locking in tx reset logic visornic tx reset handling is done asynchronously via a workqueue in visornic_timeout_reset(). As a result, it needs to use rtnl_lock() / rtnl_unlock() to lock against possible simultaneous close() of the network device. (I consulted the bnx2 driver as a model here, as that driver also does its tx reset handling asynchronously, just like visornic does. See bnx2_tx_timeout() and bnx2_reset_task().) Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 9d10b85ac7eb..ec38b51eca01 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -731,6 +731,12 @@ visornic_timeout_reset(struct work_struct *work) devdata = container_of(work, struct visornic_devdata, timeout_reset); netdev = devdata->netdev; + rtnl_lock(); + if (!netif_running(netdev)) { + rtnl_unlock(); + return; + } + response = visornic_disable_with_timeout(netdev, VISORNIC_INFINITE_RSP_WAIT); if (response) @@ -741,10 +747,13 @@ visornic_timeout_reset(struct work_struct *work) if (response) goto call_serverdown; + rtnl_unlock(); + return; call_serverdown: visornic_serverdown(devdata, NULL); + rtnl_unlock(); } /** -- cgit v1.3-6-gb490 From 81d275c6c37f075643fec3789ea3f3e4097cda41 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Fri, 24 Jul 2015 12:00:23 -0400 Subject: staging: unisys: visornic - check visorchannel_signalinsert/remove failures Logic to check for failures of visorchannel_signalinsert() and visorchannel_signalremove() were added, and a new sent_post_failed counter tracks the number of times we failed to post a rcv buffer to the IO partition. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index ec38b51eca01..a4aa8afd04dd 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -102,6 +102,7 @@ struct chanstat { unsigned long sent_enbdis; unsigned long sent_promisc; unsigned long sent_post; + unsigned long sent_post_failed; unsigned long sent_xmit; unsigned long reject_count; unsigned long extra_rcvbufs_sent; @@ -479,11 +480,14 @@ post_skb(struct uiscmdrsp *cmdrsp, if ((cmdrsp->net.rcvpost.frag.pi_off + skb->len) <= PI_PAGE_SIZE) { cmdrsp->net.type = NET_RCV_POST; cmdrsp->cmdtype = CMD_NET_TYPE; - visorchannel_signalinsert(devdata->dev->visorchannel, + if (visorchannel_signalinsert(devdata->dev->visorchannel, IOCHAN_TO_IOPART, - cmdrsp); - atomic_inc(&devdata->num_rcvbuf_in_iovm); - devdata->chstat.sent_post++; + cmdrsp)) { + atomic_inc(&devdata->num_rcvbuf_in_iovm); + devdata->chstat.sent_post++; + } else { + devdata->chstat.sent_post_failed++; + } } } @@ -505,10 +509,10 @@ send_enbdis(struct net_device *netdev, int state, devdata->cmdrsp_rcv->net.enbdis.context = netdev; devdata->cmdrsp_rcv->net.type = NET_RCV_ENBDIS; devdata->cmdrsp_rcv->cmdtype = CMD_NET_TYPE; - visorchannel_signalinsert(devdata->dev->visorchannel, + if (visorchannel_signalinsert(devdata->dev->visorchannel, IOCHAN_TO_IOPART, - devdata->cmdrsp_rcv); - devdata->chstat.sent_enbdis++; + devdata->cmdrsp_rcv)) + devdata->chstat.sent_enbdis++; } /** @@ -1501,6 +1505,9 @@ static ssize_t info_debugfs_read(struct file *file, char __user *buf, str_pos += scnprintf(vbuf + str_pos, len - str_pos, " chstat.sent_post = %lu\n", devdata->chstat.sent_post); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " chstat.sent_post_failed = %lu\n", + devdata->chstat.sent_post_failed); str_pos += scnprintf(vbuf + str_pos, len - str_pos, " chstat.sent_xmit = %lu\n", devdata->chstat.sent_xmit); -- cgit v1.3-6-gb490 From db8499273e0110b2285f9190dcde5e8492d46076 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Fri, 24 Jul 2015 12:00:25 -0400 Subject: staging: unisys: visornic - prevent NETDEV WATCHDOG timeouts after IO recovery After IO partition recovery, it was possible to get into a situation where a visornic device would repeatedly report: NETDEV WATCHDOG: eth0 (): transmit queue 0 timed out The actual problem would affect any visornic device that was rapidly transmitting at the same time the IO partition was being recovered. Once you hit the problem, the only way to resume use of the nic would be to reboot the Linux client partition. The problem was caused by chstat.sent_xmit and chstat.got_xmit_done NOT getting cleared during IO partition recovery. This is necessary because outstanding xmits would essentially be "abandoned" during such recovery. These fields are now cleared in virtnic_serverdown_complete(). Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index a4aa8afd04dd..2a9b055dcc51 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -380,6 +380,8 @@ visornic_serverdown_complete(struct visornic_devdata *devdata) rtnl_unlock(); atomic_set(&devdata->num_rcvbuf_in_iovm, 0); + devdata->chstat.sent_xmit = 0; + devdata->chstat.got_xmit_done = 0; if (devdata->server_down_complete_func) (*devdata->server_down_complete_func)(devdata->dev, 0); -- cgit v1.3-6-gb490 From 57562a72414ca35b2e614cfe0a1b1a7b7e7813dd Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Fri, 24 Jul 2015 16:11:48 +0200 Subject: Staging: most: add MOST driver's core module This patch adds the core module of the MOST driver to the kernel's driver staging area. This module is part of the MOST driver and handles the configuration interface in sysfs, the buffer management and the data routing. MOST defines the protocol, hardware and software layers necessary to allow for the efficient and low-cost transport of control, real-time and packet data using a single medium (physical layer). Media currently in use are fiber optics, unshielded twisted pair cables (UTP) and coax cables. MOST also supports various speed grades up to 150 Mbps. For more information on MOST, visit the MOST Cooperation website: www.mostcooperation.com. Cars continue to evolve into sophisticated consumer electronics platforms, increasing the demand for reliable and simple solutions to support audio, video and data communications. MOST can be used to connect multiple consumer devices via optical or electrical physical layers directly to one another or in a network configuration. As a synchronous network, MOST provides excellent Quality of Service and seamless connectivity for audio/video streaming. Therefore, the driver perfectly fits to the mission of Automotive Grade Linux to create open source software solutions for automotive applications. The driver consists basically of three layers. The hardware layer, the core layer and the application layer. The core layer consists of the core module only. This module handles the communication flow through all three layers, the configuration of the driver, the configuration interface representation in sysfs, and the buffer management. For each of the other two layers a selection of modules is provided. These modules can arbitrarily be combined to meet the needs of the desired system architecture. A module of the hardware layer is referred to as an HDM (hardware dependent module). Each module of this layer handles exactly one of the peripheral interfaces of a network interface controller (e.g. USB, MediaLB, I2C). A module of the application layer is referred to as an AIM (application interfacing module). The modules of this layer give access to MOST via one the following ways: character devices, ALSA, Networking or V4L2. To physically access MOST, an Intelligent Network Interface Controller (INIC) is needed. For more information on available controllers visit: www.microchip.com Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/most/Kconfig | 16 + drivers/staging/most/Makefile | 1 + drivers/staging/most/TODO | 8 + drivers/staging/most/mostcore/Kconfig | 13 + drivers/staging/most/mostcore/Makefile | 3 + drivers/staging/most/mostcore/core.c | 1931 ++++++++++++++++++++++++++++++ drivers/staging/most/mostcore/mostcore.h | 316 +++++ 9 files changed, 2291 insertions(+) create mode 100644 drivers/staging/most/Kconfig create mode 100644 drivers/staging/most/Makefile create mode 100644 drivers/staging/most/TODO create mode 100644 drivers/staging/most/mostcore/Kconfig create mode 100644 drivers/staging/most/mostcore/Makefile create mode 100644 drivers/staging/most/mostcore/core.c create mode 100644 drivers/staging/most/mostcore/mostcore.h (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 7f6cae5beb90..4f0b12d88fdc 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -112,4 +112,6 @@ source "drivers/staging/fsl-mc/Kconfig" source "drivers/staging/wilc1000/Kconfig" +source "drivers/staging/most/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 347f6477aa3e..37149ca6a331 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/ obj-$(CONFIG_FB_TFT) += fbtft/ obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/ obj-$(CONFIG_WILC1000) += wilc1000/ +obj-$(CONFIG_MOST) += most/ diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig new file mode 100644 index 000000000000..b7db320dbacc --- /dev/null +++ b/drivers/staging/most/Kconfig @@ -0,0 +1,16 @@ +menuconfig MOST + tristate "MOST driver" + select MOSTCORE + default n + ---help--- + This option allows you to enable support for MOST Network transceivers. + + If in doubt, say N here. + + + +if MOST + +source "drivers/staging/most/mostcore/Kconfig" + +endif diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile new file mode 100644 index 000000000000..0144be009337 --- /dev/null +++ b/drivers/staging/most/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MOSTCORE) += mostcore/ diff --git a/drivers/staging/most/TODO b/drivers/staging/most/TODO new file mode 100644 index 000000000000..4fa11a9d2cf7 --- /dev/null +++ b/drivers/staging/most/TODO @@ -0,0 +1,8 @@ +* Get through code review with Greg Kroah-Hartman + +Contact: +To: +Christian Gromm +Cc: +Michael Fabry +Christian Gromm diff --git a/drivers/staging/most/mostcore/Kconfig b/drivers/staging/most/mostcore/Kconfig new file mode 100644 index 000000000000..38abf1b21b66 --- /dev/null +++ b/drivers/staging/most/mostcore/Kconfig @@ -0,0 +1,13 @@ +# +# MOSTCore configuration +# + +config MOSTCORE + tristate "MOST Core" + + ---help--- + Say Y here if you want to enable MOST support. + This device driver needs at least an additional AIM and HDM to work. + + To compile this driver as a module, choose M here: the + module will be called mostcore. diff --git a/drivers/staging/most/mostcore/Makefile b/drivers/staging/most/mostcore/Makefile new file mode 100644 index 000000000000..a078f01cf7c2 --- /dev/null +++ b/drivers/staging/most/mostcore/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_MOSTCORE) += mostcore.o + +mostcore-objs := core.o diff --git a/drivers/staging/most/mostcore/core.c b/drivers/staging/most/mostcore/core.c new file mode 100644 index 000000000000..f4f903404f1b --- /dev/null +++ b/drivers/staging/most/mostcore/core.c @@ -0,0 +1,1931 @@ +/* + * core.c - Implementation of core module of MOST Linux driver stack + * + * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mostcore.h" + +#define MAX_CHANNELS 64 +#define STRING_SIZE 80 + +static struct class *most_class; +static struct device *class_glue_dir; +static struct ida mdev_id; +static int modref; + +struct most_c_obj { + struct kobject kobj; + struct completion cleanup; + atomic_t mbo_ref; + atomic_t mbo_nq_level; + uint16_t channel_id; + bool is_poisoned; + bool is_started; + int is_starving; + struct most_interface *iface; + struct most_inst_obj *inst; + struct most_channel_config cfg; + bool keep_mbo; + bool enqueue_halt; + struct list_head fifo; + spinlock_t fifo_lock; + struct list_head halt_fifo; + struct list_head list; + struct most_aim *first_aim; + struct most_aim *second_aim; + struct list_head trash_fifo; + struct task_struct *hdm_enqueue_task; + struct mutex stop_task_mutex; + wait_queue_head_t hdm_fifo_wq; +}; +#define to_c_obj(d) container_of(d, struct most_c_obj, kobj) + +struct most_inst_obj { + int dev_id; + atomic_t tainted; + struct most_interface *iface; + struct list_head channel_list; + struct most_c_obj *channel[MAX_CHANNELS]; + struct kobject kobj; + struct list_head list; +}; +#define to_inst_obj(d) container_of(d, struct most_inst_obj, kobj) + +/** + * list_pop_mbo - retrieves the first MBO of the list and removes it + * @ptr: the list head to grab the MBO from. + */ +#define list_pop_mbo(ptr) \ +({ \ + struct mbo *_mbo = list_first_entry(ptr, struct mbo, list); \ + list_del(&_mbo->list); \ + _mbo; \ +}) + +static struct mutex deregister_mutex; + +/* ___ ___ + * ___C H A N N E L___ + */ + +/** + * struct most_c_attr - to access the attributes of a channel object + * @attr: attributes of a channel + * @show: pointer to the show function + * @store: pointer to the store function + */ +struct most_c_attr { + struct attribute attr; + ssize_t (*show)(struct most_c_obj *d, + struct most_c_attr *attr, + char *buf); + ssize_t (*store)(struct most_c_obj *d, + struct most_c_attr *attr, + const char *buf, + size_t count); +}; +#define to_channel_attr(a) container_of(a, struct most_c_attr, attr) + +#define MOST_CHNL_ATTR(_name, _mode, _show, _store) \ + struct most_c_attr most_chnl_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + +/** + * channel_attr_show - show function of channel object + * @kobj: pointer to its kobject + * @attr: pointer to its attributes + * @buf: buffer + */ +static ssize_t channel_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct most_c_attr *channel_attr = to_channel_attr(attr); + struct most_c_obj *c_obj = to_c_obj(kobj); + + if (!channel_attr->show) + return -EIO; + + return channel_attr->show(c_obj, channel_attr, buf); +} + +/** + * channel_attr_store - store function of channel object + * @kobj: pointer to its kobject + * @attr: pointer to its attributes + * @buf: buffer + * @len: length of buffer + */ +static ssize_t channel_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, + size_t len) +{ + struct most_c_attr *channel_attr = to_channel_attr(attr); + struct most_c_obj *c_obj = to_c_obj(kobj); + + if (!channel_attr->store) + return -EIO; + return channel_attr->store(c_obj, channel_attr, buf, len); +} + +static const struct sysfs_ops most_channel_sysfs_ops = { + .show = channel_attr_show, + .store = channel_attr_store, +}; + +/** + * most_free_mbo_coherent - free an MBO and its coherent buffer + * @mbo: buffer to be released + * + */ +static void most_free_mbo_coherent(struct mbo *mbo) +{ + struct most_c_obj *c = mbo->context; + u16 const coherent_buf_size = c->cfg.buffer_size + c->cfg.extra_len; + + dma_free_coherent(NULL, coherent_buf_size, mbo->virt_address, + mbo->bus_address); + kfree(mbo); + if (atomic_sub_and_test(1, &c->mbo_ref)) + complete(&c->cleanup); +} + +/** + * flush_channel_fifos - clear the channel fifos + * @c: pointer to channel object + */ +void flush_channel_fifos(struct most_c_obj *c) +{ + unsigned long flags, hf_flags; + struct mbo *mbo, *tmp; + + if (list_empty(&c->fifo) && list_empty(&c->halt_fifo)) + return; + + spin_lock_irqsave(&c->fifo_lock, flags); + list_for_each_entry_safe(mbo, tmp, &c->fifo, list) { + list_del(&mbo->list); + spin_unlock_irqrestore(&c->fifo_lock, flags); + if (likely(mbo)) + most_free_mbo_coherent(mbo); + spin_lock_irqsave(&c->fifo_lock, flags); + } + spin_unlock_irqrestore(&c->fifo_lock, flags); + + spin_lock_irqsave(&c->fifo_lock, hf_flags); + list_for_each_entry_safe(mbo, tmp, &c->halt_fifo, list) { + list_del(&mbo->list); + spin_unlock_irqrestore(&c->fifo_lock, hf_flags); + if (likely(mbo)) + most_free_mbo_coherent(mbo); + spin_lock_irqsave(&c->fifo_lock, hf_flags); + } + spin_unlock_irqrestore(&c->fifo_lock, hf_flags); + + if (unlikely((!list_empty(&c->fifo) || !list_empty(&c->halt_fifo)))) + pr_info("WARN: fifo | trash fifo not empty\n"); +} + +/** + * flush_trash_fifo - clear the trash fifo + * @c: pointer to channel object + */ +static int flush_trash_fifo(struct most_c_obj *c) +{ + struct mbo *mbo, *tmp; + unsigned long flags; + + spin_lock_irqsave(&c->fifo_lock, flags); + list_for_each_entry_safe(mbo, tmp, &c->trash_fifo, list) { + list_del(&mbo->list); + spin_unlock_irqrestore(&c->fifo_lock, flags); + most_free_mbo_coherent(mbo); + spin_lock_irqsave(&c->fifo_lock, flags); + } + spin_unlock_irqrestore(&c->fifo_lock, flags); + return 0; +} + +/** + * most_channel_release - release function of channel object + * @kobj: pointer to channel's kobject + */ +static void most_channel_release(struct kobject *kobj) +{ + struct most_c_obj *c = to_c_obj(kobj); + + kfree(c); +} + +static ssize_t show_available_directions(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + unsigned int i = c->channel_id; + + strcpy(buf, ""); + if (c->iface->channel_vector[i].direction & MOST_CH_RX) + strcat(buf, "dir_rx "); + if (c->iface->channel_vector[i].direction & MOST_CH_TX) + strcat(buf, "dir_tx "); + strcat(buf, "\n"); + return strlen(buf) + 1; +} + +static ssize_t show_available_datatypes(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + unsigned int i = c->channel_id; + + strcpy(buf, ""); + if (c->iface->channel_vector[i].data_type & MOST_CH_CONTROL) + strcat(buf, "control "); + if (c->iface->channel_vector[i].data_type & MOST_CH_ASYNC) + strcat(buf, "async "); + if (c->iface->channel_vector[i].data_type & MOST_CH_SYNC) + strcat(buf, "sync "); + if (c->iface->channel_vector[i].data_type & MOST_CH_ISOC_AVP) + strcat(buf, "isoc_avp "); + strcat(buf, "\n"); + return strlen(buf) + 1; +} + +static +ssize_t show_number_of_packet_buffers(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + unsigned int i = c->channel_id; + + return snprintf(buf, PAGE_SIZE, "%d\n", + c->iface->channel_vector[i].num_buffers_packet); +} + +static +ssize_t show_number_of_stream_buffers(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + unsigned int i = c->channel_id; + + return snprintf(buf, PAGE_SIZE, "%d\n", + c->iface->channel_vector[i].num_buffers_streaming); +} + +static +ssize_t show_size_of_packet_buffer(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + unsigned int i = c->channel_id; + + return snprintf(buf, PAGE_SIZE, "%d\n", + c->iface->channel_vector[i].buffer_size_packet); +} + +static +ssize_t show_size_of_stream_buffer(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + unsigned int i = c->channel_id; + + return snprintf(buf, PAGE_SIZE, "%d\n", + c->iface->channel_vector[i].buffer_size_streaming); +} + +static ssize_t show_channel_starving(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", c->is_starving); +} + + +#define create_show_channel_attribute(val) \ + static MOST_CHNL_ATTR(val, S_IRUGO, show_##val, NULL); + +create_show_channel_attribute(available_directions); +create_show_channel_attribute(available_datatypes); +create_show_channel_attribute(number_of_packet_buffers); +create_show_channel_attribute(number_of_stream_buffers); +create_show_channel_attribute(size_of_stream_buffer); +create_show_channel_attribute(size_of_packet_buffer); +create_show_channel_attribute(channel_starving); + +static ssize_t show_set_number_of_buffers(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.num_buffers); +} + +static ssize_t store_set_number_of_buffers(struct most_c_obj *c, + struct most_c_attr *attr, + const char *buf, + size_t count) +{ + int ret = kstrtou16(buf, 0, &c->cfg.num_buffers); + + if (ret) + return ret; + return count; +} + +static ssize_t show_set_buffer_size(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.buffer_size); +} + +static ssize_t store_set_buffer_size(struct most_c_obj *c, + struct most_c_attr *attr, + const char *buf, + size_t count) +{ + int ret = kstrtou16(buf, 0, &c->cfg.buffer_size); + + if (ret) + return ret; + return count; +} + +static ssize_t show_set_direction(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + if (c->cfg.direction & MOST_CH_TX) + return snprintf(buf, PAGE_SIZE, "dir_tx\n"); + else if (c->cfg.direction & MOST_CH_RX) + return snprintf(buf, PAGE_SIZE, "dir_rx\n"); + return snprintf(buf, PAGE_SIZE, "unconfigured\n"); +} + +static ssize_t store_set_direction(struct most_c_obj *c, + struct most_c_attr *attr, + const char *buf, + size_t count) +{ + if (!strcmp(buf, "dir_rx\n")) + c->cfg.direction = MOST_CH_RX; + else if (!strcmp(buf, "dir_tx\n")) + c->cfg.direction = MOST_CH_TX; + else { + pr_info("WARN: invalid attribute settings\n"); + return -EINVAL; + } + return count; +} + +static ssize_t show_set_datatype(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + if (c->cfg.data_type & MOST_CH_CONTROL) + return snprintf(buf, PAGE_SIZE, "control\n"); + else if (c->cfg.data_type & MOST_CH_ASYNC) + return snprintf(buf, PAGE_SIZE, "async\n"); + else if (c->cfg.data_type & MOST_CH_SYNC) + return snprintf(buf, PAGE_SIZE, "sync\n"); + else if (c->cfg.data_type & MOST_CH_ISOC_AVP) + return snprintf(buf, PAGE_SIZE, "isoc_avp\n"); + return snprintf(buf, PAGE_SIZE, "unconfigured\n"); +} + +static ssize_t store_set_datatype(struct most_c_obj *c, + struct most_c_attr *attr, + const char *buf, + size_t count) +{ + if (!strcmp(buf, "control\n")) + c->cfg.data_type = MOST_CH_CONTROL; + else if (!strcmp(buf, "async\n")) + c->cfg.data_type = MOST_CH_ASYNC; + else if (!strcmp(buf, "sync\n")) + c->cfg.data_type = MOST_CH_SYNC; + else if (!strcmp(buf, "isoc_avp\n")) + c->cfg.data_type = MOST_CH_ISOC_AVP; + else { + pr_info("WARN: invalid attribute settings\n"); + return -EINVAL; + } + return count; +} + +static ssize_t show_set_subbuffer_size(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.subbuffer_size); +} + +static ssize_t store_set_subbuffer_size(struct most_c_obj *c, + struct most_c_attr *attr, + const char *buf, + size_t count) +{ + int ret = kstrtou16(buf, 0, &c->cfg.subbuffer_size); + + if (ret) + return ret; + return count; +} + +static ssize_t show_set_packets_per_xact(struct most_c_obj *c, + struct most_c_attr *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", c->cfg.packets_per_xact); +} + +static ssize_t store_set_packets_per_xact(struct most_c_obj *c, + struct most_c_attr *attr, + const char *buf, + size_t count) +{ + int ret = kstrtou16(buf, 0, &c->cfg.packets_per_xact); + + if (ret) + return ret; + return count; +} + +#define create_channel_attribute(value) \ + static MOST_CHNL_ATTR(value, S_IRUGO | S_IWUSR, \ + show_##value, \ + store_##value) + +create_channel_attribute(set_buffer_size); +create_channel_attribute(set_number_of_buffers); +create_channel_attribute(set_direction); +create_channel_attribute(set_datatype); +create_channel_attribute(set_subbuffer_size); +create_channel_attribute(set_packets_per_xact); + + +/** + * most_channel_def_attrs - array of default attributes of channel object + */ +static struct attribute *most_channel_def_attrs[] = { + &most_chnl_attr_available_directions.attr, + &most_chnl_attr_available_datatypes.attr, + &most_chnl_attr_number_of_packet_buffers.attr, + &most_chnl_attr_number_of_stream_buffers.attr, + &most_chnl_attr_size_of_packet_buffer.attr, + &most_chnl_attr_size_of_stream_buffer.attr, + &most_chnl_attr_set_number_of_buffers.attr, + &most_chnl_attr_set_buffer_size.attr, + &most_chnl_attr_set_direction.attr, + &most_chnl_attr_set_datatype.attr, + &most_chnl_attr_set_subbuffer_size.attr, + &most_chnl_attr_set_packets_per_xact.attr, + &most_chnl_attr_channel_starving.attr, + NULL, +}; + +static struct kobj_type most_channel_ktype = { + .sysfs_ops = &most_channel_sysfs_ops, + .release = most_channel_release, + .default_attrs = most_channel_def_attrs, +}; + +static struct kset *most_channel_kset; + +/** + * create_most_c_obj - allocates a channel object + * @name: name of the channel object + * @parent: parent kobject + * + * This create a channel object and registers it with sysfs. + * Returns a pointer to the object or NULL when something went wrong. + */ +static struct most_c_obj * +create_most_c_obj(const char *name, struct kobject *parent) +{ + struct most_c_obj *c; + int retval; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return NULL; + c->kobj.kset = most_channel_kset; + retval = kobject_init_and_add(&c->kobj, &most_channel_ktype, parent, + "%s", name); + if (retval) { + kobject_put(&c->kobj); + return NULL; + } + kobject_uevent(&c->kobj, KOBJ_ADD); + return c; +} + +/** + * destroy_most_c_obj - channel release function + * @c: pointer to channel object + * + * This decrements the reference counter of the channel object. + * If the reference count turns zero, its release function is called. + */ +static void destroy_most_c_obj(struct most_c_obj *c) +{ + if (c->first_aim) + c->first_aim->disconnect_channel(c->iface, c->channel_id); + if (c->second_aim) + c->second_aim->disconnect_channel(c->iface, c->channel_id); + c->first_aim = NULL; + c->second_aim = NULL; + + mutex_lock(&deregister_mutex); + flush_trash_fifo(c); + flush_channel_fifos(c); + mutex_unlock(&deregister_mutex); + kobject_put(&c->kobj); +} + +/* ___ ___ + * ___I N S T A N C E___ + */ +#define MOST_INST_ATTR(_name, _mode, _show, _store) \ + struct most_inst_attribute most_inst_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + +static struct list_head instance_list; + +/** + * struct most_inst_attribute - to access the attributes of instance object + * @attr: attributes of an instance + * @show: pointer to the show function + * @store: pointer to the store function + */ +struct most_inst_attribute { + struct attribute attr; + ssize_t (*show)(struct most_inst_obj *d, + struct most_inst_attribute *attr, + char *buf); + ssize_t (*store)(struct most_inst_obj *d, + struct most_inst_attribute *attr, + const char *buf, + size_t count); +}; +#define to_instance_attr(a) \ + container_of(a, struct most_inst_attribute, attr) + +/** + * instance_attr_show - show function for an instance object + * @kobj: pointer to kobject + * @attr: pointer to attribute struct + * @buf: buffer + */ +static ssize_t instance_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct most_inst_attribute *instance_attr; + struct most_inst_obj *instance_obj; + + instance_attr = to_instance_attr(attr); + instance_obj = to_inst_obj(kobj); + + if (!instance_attr->show) + return -EIO; + + return instance_attr->show(instance_obj, instance_attr, buf); +} + +/** + * instance_attr_store - store function for an instance object + * @kobj: pointer to kobject + * @attr: pointer to attribute struct + * @buf: buffer + * @len: length of buffer + */ +static ssize_t instance_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, + size_t len) +{ + struct most_inst_attribute *instance_attr; + struct most_inst_obj *instance_obj; + + instance_attr = to_instance_attr(attr); + instance_obj = to_inst_obj(kobj); + + if (!instance_attr->store) + return -EIO; + + return instance_attr->store(instance_obj, instance_attr, buf, len); +} + +static const struct sysfs_ops most_inst_sysfs_ops = { + .show = instance_attr_show, + .store = instance_attr_store, +}; + +/** + * most_inst_release - release function for instance object + * @kobj: pointer to instance's kobject + * + * This frees the allocated memory for the instance object + */ +static void most_inst_release(struct kobject *kobj) +{ + struct most_inst_obj *inst = to_inst_obj(kobj); + + kfree(inst); +} + +static ssize_t show_description(struct most_inst_obj *instance_obj, + struct most_inst_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", + instance_obj->iface->description); +} + +static ssize_t show_interface(struct most_inst_obj *instance_obj, + struct most_inst_attribute *attr, + char *buf) +{ + switch (instance_obj->iface->interface) { + case ITYPE_LOOPBACK: + return snprintf(buf, PAGE_SIZE, "loopback\n"); + case ITYPE_I2C: + return snprintf(buf, PAGE_SIZE, "i2c\n"); + case ITYPE_I2S: + return snprintf(buf, PAGE_SIZE, "i2s\n"); + case ITYPE_TSI: + return snprintf(buf, PAGE_SIZE, "tsi\n"); + case ITYPE_HBI: + return snprintf(buf, PAGE_SIZE, "hbi\n"); + case ITYPE_MEDIALB_DIM: + return snprintf(buf, PAGE_SIZE, "mlb_dim\n"); + case ITYPE_MEDIALB_DIM2: + return snprintf(buf, PAGE_SIZE, "mlb_dim2\n"); + case ITYPE_USB: + return snprintf(buf, PAGE_SIZE, "usb\n"); + case ITYPE_PCIE: + return snprintf(buf, PAGE_SIZE, "pcie\n"); + } + return snprintf(buf, PAGE_SIZE, "unknown\n"); +} + +#define create_inst_attribute(value) \ + static MOST_INST_ATTR(value, S_IRUGO, show_##value, NULL) + +create_inst_attribute(description); +create_inst_attribute(interface); + +static struct attribute *most_inst_def_attrs[] = { + &most_inst_attr_description.attr, + &most_inst_attr_interface.attr, + NULL, +}; + +static struct kobj_type most_inst_ktype = { + .sysfs_ops = &most_inst_sysfs_ops, + .release = most_inst_release, + .default_attrs = most_inst_def_attrs, +}; + +static struct kset *most_inst_kset; + + +/** + * create_most_inst_obj - creates an instance object + * @name: name of the object to be created + * + * This allocates memory for an instance structure, assigns the proper kset + * and registers it with sysfs. + * + * Returns a pointer to the instance object or NULL when something went wrong. + */ +static struct most_inst_obj *create_most_inst_obj(const char *name) +{ + struct most_inst_obj *inst; + int retval; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return NULL; + inst->kobj.kset = most_inst_kset; + retval = kobject_init_and_add(&inst->kobj, &most_inst_ktype, NULL, + "%s", name); + if (retval) { + kobject_put(&inst->kobj); + return NULL; + } + kobject_uevent(&inst->kobj, KOBJ_ADD); + return inst; +} + +/** + * destroy_most_inst_obj - MOST instance release function + * @inst: pointer to the instance object + * + * This decrements the reference counter of the instance object. + * If the reference count turns zero, its release function is called + */ +static void destroy_most_inst_obj(struct most_inst_obj *inst) +{ + struct most_c_obj *c, *tmp; + + /* need to destroy channels first, since + * each channel incremented the + * reference count of the inst->kobj + */ + list_for_each_entry_safe(c, tmp, &inst->channel_list, list) { + destroy_most_c_obj(c); + } + kobject_put(&inst->kobj); +} + +/* ___ ___ + * ___A I M___ + */ +struct most_aim_obj { + struct kobject kobj; + struct list_head list; + struct most_aim *driver; + char add_link[STRING_SIZE]; + char remove_link[STRING_SIZE]; +}; +#define to_aim_obj(d) container_of(d, struct most_aim_obj, kobj) + +static struct list_head aim_list; + + +/** + * struct most_aim_attribute - to access the attributes of AIM object + * @attr: attributes of an AIM + * @show: pointer to the show function + * @store: pointer to the store function + */ +struct most_aim_attribute { + struct attribute attr; + ssize_t (*show)(struct most_aim_obj *d, + struct most_aim_attribute *attr, + char *buf); + ssize_t (*store)(struct most_aim_obj *d, + struct most_aim_attribute *attr, + const char *buf, + size_t count); +}; +#define to_aim_attr(a) container_of(a, struct most_aim_attribute, attr) + +/** + * aim_attr_show - show function of an AIM object + * @kobj: pointer to kobject + * @attr: pointer to attribute struct + * @buf: buffer + */ +static ssize_t aim_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct most_aim_attribute *aim_attr; + struct most_aim_obj *aim_obj; + + aim_attr = to_aim_attr(attr); + aim_obj = to_aim_obj(kobj); + + if (!aim_attr->show) + return -EIO; + + return aim_attr->show(aim_obj, aim_attr, buf); +} + +/** + * aim_attr_store - store function of an AIM object + * @kobj: pointer to kobject + * @attr: pointer to attribute struct + * @buf: buffer + * @len: length of buffer + */ +static ssize_t aim_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, + size_t len) +{ + struct most_aim_attribute *aim_attr; + struct most_aim_obj *aim_obj; + + aim_attr = to_aim_attr(attr); + aim_obj = to_aim_obj(kobj); + + if (!aim_attr->store) + return -EIO; + return aim_attr->store(aim_obj, aim_attr, buf, len); +} + +static const struct sysfs_ops most_aim_sysfs_ops = { + .show = aim_attr_show, + .store = aim_attr_store, +}; + +/** + * most_aim_release - AIM release function + * @kobj: pointer to AIM's kobject + */ +static void most_aim_release(struct kobject *kobj) +{ + struct most_aim_obj *aim_obj = to_aim_obj(kobj); + + kfree(aim_obj); +} + +static ssize_t show_add_link(struct most_aim_obj *aim_obj, + struct most_aim_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", aim_obj->add_link); +} + +/** + * split_string - parses and changes string in the buffer buf and + * splits it into two mandatory and one optional substrings. + * + * @buf: complete string from attribute 'add_channel' + * @a: address of pointer to 1st substring (=instance name) + * @b: address of pointer to 2nd substring (=channel name) + * @c: optional address of pointer to 3rd substring (=user defined name) + * + * Examples: + * + * Input: "mdev0:ch0@ep_81:my_channel\n" or + * "mdev0:ch0@ep_81:my_channel" + * + * Output: *a -> "mdev0", *b -> "ch0@ep_81", *c -> "my_channel" + * + * Input: "mdev0:ch0@ep_81\n" + * Output: *a -> "mdev0", *b -> "ch0@ep_81", *c -> "" + * + * Input: "mdev0:ch0@ep_81" + * Output: *a -> "mdev0", *b -> "ch0@ep_81", *c == NULL + */ +int split_string(char *buf, char **a, char **b, char **c) +{ + *a = strsep(&buf, ":"); + if (!*a) + return -EIO; + + *b = strsep(&buf, ":\n"); + if (!*b) + return -EIO; + + if (c) + *c = strsep(&buf, ":\n"); + + return 0; +} + +/** + * get_channel_by_name - get pointer to channel object + * @mdev: name of the device instance + * @mdev_ch: name of the respective channel + * + * This retrieves the pointer to a channel object. + */ +static struct +most_c_obj *get_channel_by_name(char *mdev, char *mdev_ch) +{ + struct most_c_obj *c, *tmp; + struct most_inst_obj *i, *i_tmp; + int found = 0; + + list_for_each_entry_safe(i, i_tmp, &instance_list, list) { + if (!strcmp(kobject_name(&i->kobj), mdev)) { + found++; + break; + } + } + if (unlikely(!found)) + return ERR_PTR(-EIO); + + list_for_each_entry_safe(c, tmp, &i->channel_list, list) { + if (!strcmp(kobject_name(&c->kobj), mdev_ch)) { + found++; + break; + } + } + if (unlikely(2 > found)) + return ERR_PTR(-EIO); + return c; +} + +/** + * store_add_link - store() function for add_link attribute + * @aim_obj: pointer to AIM object + * @attr: its attributes + * @buf: buffer + * @len: buffer length + * + * This parses the string given by buf and splits it into + * three substrings. Note: third substring is optional. In case a cdev + * AIM is loaded the optional 3rd substring will make up the name of + * device node in the /dev directory. If omitted, the device node will + * inherit the channel's name within sysfs. + * + * Searches for a pair of device and channel and probes the AIM + * + * Example: + * (1) echo -n -e "mdev0:ch0@ep_81:my_rxchannel\n" >add_link + * (2) echo -n -e "mdev0:ch0@ep_81\n" >add_link + * + * (1) would create the device node /dev/my_rxchannel + * (2) would create the device node /dev/mdev0-ch0@ep_81 + */ +static ssize_t store_add_link(struct most_aim_obj *aim_obj, + struct most_aim_attribute *attr, + const char *buf, + size_t len) +{ + struct most_c_obj *c; + struct most_aim **aim_ptr; + char buffer[STRING_SIZE]; + char *mdev; + char *mdev_ch; + char *mdev_devnod; + char devnod_buf[STRING_SIZE]; + int ret; + unsigned int max_len = min((int)len + 1, STRING_SIZE); + + strlcpy(buffer, buf, max_len); + strlcpy(aim_obj->add_link, buf, max_len); + + ret = split_string(buffer, &mdev, &mdev_ch, &mdev_devnod); + if (ret) + return ret; + + if (mdev_devnod == 0 || *mdev_devnod == 0) { + snprintf(devnod_buf, PAGE_SIZE, "%s-%s", mdev, mdev_ch); + mdev_devnod = devnod_buf; + } + + c = get_channel_by_name(mdev, mdev_ch); + if (IS_ERR(c)) + return -ENODEV; + + if (!c->first_aim) + aim_ptr = &c->first_aim; + else if (!c->second_aim) + aim_ptr = &c->second_aim; + else + return -ENOSPC; + + ret = aim_obj->driver->probe_channel(c->iface, c->channel_id, + &c->cfg, &c->kobj, mdev_devnod); + if (ret) + return ret; + *aim_ptr = aim_obj->driver; + return len; +} + +struct most_aim_attribute most_aim_attr_add_link = + __ATTR(add_link, S_IRUGO | S_IWUSR, show_add_link, store_add_link); + +static ssize_t show_remove_link(struct most_aim_obj *aim_obj, + struct most_aim_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", aim_obj->remove_link); +} + +/** + * store_remove_link - store function for remove_link attribute + * @aim_obj: pointer to AIM object + * @attr: its attributes + * @buf: buffer + * @len: buffer length + * + * Example: + * echo -n -e "mdev0:ch0@ep_81\n" >remove_link + */ +static ssize_t store_remove_link(struct most_aim_obj *aim_obj, + struct most_aim_attribute *attr, + const char *buf, + size_t len) +{ + struct most_c_obj *c; + char buffer[STRING_SIZE]; + char *mdev; + char *mdev_ch; + int ret; + unsigned int max_len = min((int)len + 1, STRING_SIZE); + + strlcpy(buffer, buf, max_len); + strlcpy(aim_obj->remove_link, buf, max_len); + ret = split_string(buffer, &mdev, &mdev_ch, NULL); + if (ret) + return ret; + + c = get_channel_by_name(mdev, mdev_ch); + if (IS_ERR(c)) + return -ENODEV; + + if (c->first_aim == aim_obj->driver) + c->first_aim = NULL; + if (c->second_aim == aim_obj->driver) + c->second_aim = NULL; + if (aim_obj->driver->disconnect_channel(c->iface, c->channel_id)) + return -EIO; + return len; +} + +struct most_aim_attribute most_aim_attr_remove_link = + __ATTR(remove_link, S_IRUGO | S_IWUSR, show_remove_link, store_remove_link); + +static struct attribute *most_aim_def_attrs[] = { + &most_aim_attr_add_link.attr, + &most_aim_attr_remove_link.attr, + NULL, +}; + +static struct kobj_type most_aim_ktype = { + .sysfs_ops = &most_aim_sysfs_ops, + .release = most_aim_release, + .default_attrs = most_aim_def_attrs, +}; + +static struct kset *most_aim_kset; + +/** + * create_most_aim_obj - creates an AIM object + * @name: name of the AIM + * + * This creates an AIM object assigns the proper kset and registers + * it with sysfs. + * Returns a pointer to the object or NULL if something went wrong. + */ +static struct most_aim_obj *create_most_aim_obj(const char *name) +{ + struct most_aim_obj *most_aim; + int retval; + + most_aim = kzalloc(sizeof(*most_aim), GFP_KERNEL); + if (!most_aim) + return NULL; + most_aim->kobj.kset = most_aim_kset; + retval = kobject_init_and_add(&most_aim->kobj, &most_aim_ktype, + NULL, "%s", name); + if (retval) { + kobject_put(&most_aim->kobj); + return NULL; + } + kobject_uevent(&most_aim->kobj, KOBJ_ADD); + return most_aim; +} + +/** + * destroy_most_aim_obj - AIM release function + * @p: pointer to AIM object + * + * This decrements the reference counter of the AIM object. If the + * reference count turns zero, its release function will be called. + */ +static void destroy_most_aim_obj(struct most_aim_obj *p) +{ + kobject_put(&p->kobj); +} + + +/* ___ ___ + * ___C O R E___ + */ + +/** + * Instantiation of the MOST bus + */ +struct bus_type most_bus = { + .name = "most", +}; + +/** + * Instantiation of the core driver + */ +struct device_driver mostcore = { + .name = "mostcore", + .bus = &most_bus, +}; + +static inline void trash_mbo(struct mbo *mbo) +{ + unsigned long flags; + struct most_c_obj *c = mbo->context; + + spin_lock_irqsave(&c->fifo_lock, flags); + list_add(&mbo->list, &c->trash_fifo); + spin_unlock_irqrestore(&c->fifo_lock, flags); +} + +static struct mbo *get_hdm_mbo(struct most_c_obj *c) +{ + unsigned long flags; + struct mbo *mbo; + + spin_lock_irqsave(&c->fifo_lock, flags); + if (c->enqueue_halt || list_empty(&c->halt_fifo)) + mbo = NULL; + else + mbo = list_pop_mbo(&c->halt_fifo); + spin_unlock_irqrestore(&c->fifo_lock, flags); + return mbo; +} + +static void nq_hdm_mbo(struct mbo *mbo) +{ + unsigned long flags; + struct most_c_obj *c = mbo->context; + + spin_lock_irqsave(&c->fifo_lock, flags); + list_add_tail(&mbo->list, &c->halt_fifo); + spin_unlock_irqrestore(&c->fifo_lock, flags); + wake_up_interruptible(&c->hdm_fifo_wq); +} + +static int hdm_enqueue_thread(void *data) +{ + struct most_c_obj *c = data; + struct mbo *mbo; + typeof(c->iface->enqueue) enqueue = c->iface->enqueue; + + while (likely(!kthread_should_stop())) { + wait_event_interruptible(c->hdm_fifo_wq, + (mbo = get_hdm_mbo(c)) + || kthread_should_stop()); + + if (unlikely(!mbo)) + continue; + + if (c->cfg.direction == MOST_CH_RX) + mbo->buffer_length = c->cfg.buffer_size; + + if (unlikely(enqueue(mbo->ifp, mbo->hdm_channel_id, mbo))) { + pr_err("hdm enqueue failed\n"); + nq_hdm_mbo(mbo); + c->hdm_enqueue_task = NULL; + return 0; + } + } + + return 0; +} + +static int run_enqueue_thread(struct most_c_obj *c, int channel_id) +{ + struct task_struct *task = + kthread_run(&hdm_enqueue_thread, c, "hdm_fifo_%d", channel_id); + + if (IS_ERR(task)) + return PTR_ERR(task); + + c->hdm_enqueue_task = task; + return 0; +} + +/** + * arm_mbo - recycle MBO for further usage + * @mbo: buffer object + * + * This puts an MBO back to the list to have it ready for up coming + * tx transactions. + * + * In case the MBO belongs to a channel that recently has been + * poisoned, the MBO is scheduled to be trashed. + * Calls the completion handler of an attached AIM. + */ +static void arm_mbo(struct mbo *mbo) +{ + unsigned long flags; + struct most_c_obj *c; + + BUG_ON((!mbo) || (!mbo->context)); + c = mbo->context; + + if (c->is_poisoned) { + trash_mbo(mbo); + return; + } + + spin_lock_irqsave(&c->fifo_lock, flags); + list_add_tail(&mbo->list, &c->fifo); + spin_unlock_irqrestore(&c->fifo_lock, flags); + + if (c->second_aim && c->second_aim->tx_completion) + c->second_aim->tx_completion(c->iface, c->channel_id); + if (c->first_aim && c->first_aim->tx_completion) + c->first_aim->tx_completion(c->iface, c->channel_id); +} + +/** + * arm_mbo_chain - helper function that arms an MBO chain for the HDM + * @c: pointer to interface channel + * @dir: direction of the channel + * @compl: pointer to completion function + * + * This allocates buffer objects including the containing DMA coherent + * buffer and puts them in the fifo. + * Buffers of Rx channels are put in the kthread fifo, hence immediately + * submitted to the HDM. + * + * Returns the number of allocated and enqueued MBOs. + */ +int arm_mbo_chain(struct most_c_obj *c, int dir, void (*compl)(struct mbo *)) +{ + unsigned int i; + int retval; + struct mbo *mbo; + u16 coherent_buf_size = c->cfg.buffer_size + c->cfg.extra_len; + + atomic_set(&c->mbo_nq_level, 0); + + for (i = 0; i < c->cfg.num_buffers; i++) { + mbo = kzalloc(sizeof(*mbo), GFP_KERNEL); + if (!mbo) { + pr_info("WARN: Allocation of MBO failed.\n"); + retval = i; + goto _exit; + } + mbo->context = c; + mbo->ifp = c->iface; + mbo->hdm_channel_id = c->channel_id; + mbo->virt_address = dma_alloc_coherent(NULL, + coherent_buf_size, + &mbo->bus_address, + GFP_KERNEL); + if (!mbo->virt_address) { + pr_info("WARN: No DMA coherent buffer.\n"); + retval = i; + goto _error1; + } + mbo->complete = compl; + if (dir == MOST_CH_RX) { + nq_hdm_mbo(mbo); + atomic_inc(&c->mbo_nq_level); + } else { + arm_mbo(mbo); + } + } + return i; + +_error1: + kfree(mbo); +_exit: + return retval; +} + +/** + * most_submit_mbo - submits an MBO to fifo + * @mbo: pointer to the MBO + * + */ +int most_submit_mbo(struct mbo *mbo) +{ + struct most_c_obj *c; + struct most_inst_obj *i; + + if (unlikely((!mbo) || (!mbo->context))) { + pr_err("Bad MBO or missing channel reference\n"); + return -EINVAL; + } + c = mbo->context; + i = c->inst; + + if (unlikely(atomic_read(&i->tainted))) + return -ENODEV; + + nq_hdm_mbo(mbo); + return 0; +} +EXPORT_SYMBOL_GPL(most_submit_mbo); + +/** + * most_write_completion - write completion handler + * @mbo: pointer to MBO + * + * This recycles the MBO for further usage. In case the channel has been + * poisoned, the MBO is scheduled to be trashed. + */ +static void most_write_completion(struct mbo *mbo) +{ + struct most_c_obj *c; + + BUG_ON((!mbo) || (!mbo->context)); + + c = mbo->context; + if (mbo->status == MBO_E_INVAL) + pr_info("WARN: Tx MBO status: invalid\n"); + if (unlikely((c->is_poisoned == true) || (mbo->status == MBO_E_CLOSE))) + trash_mbo(mbo); + else + arm_mbo(mbo); +} + +/** + * get_channel_by_iface - get pointer to channel object + * @iface: pointer to interface instance + * @id: channel ID + * + * This retrieves a pointer to a channel of the given interface and channel ID. + */ +static struct +most_c_obj *get_channel_by_iface(struct most_interface *iface, int id) +{ + struct most_inst_obj *i; + + if (unlikely(!iface)) { + pr_err("Bad interface\n"); + return NULL; + } + if (unlikely((id < 0) || (id >= iface->num_channels))) { + pr_err("Channel index (%d) out of range\n", id); + return NULL; + } + i = iface->priv; + if (unlikely(!i)) { + pr_err("interface is not registered\n"); + return NULL; + } + return i->channel[id]; +} + +/** + * most_get_mbo - get pointer to an MBO of pool + * @iface: pointer to interface instance + * @id: channel ID + * + * This attempts to get a free buffer out of the channel fifo. + * Returns a pointer to MBO on success or NULL otherwise. + */ +struct mbo *most_get_mbo(struct most_interface *iface, int id) +{ + struct mbo *mbo; + struct most_c_obj *c; + unsigned long flags; + + c = get_channel_by_iface(iface, id); + if (unlikely(!c)) + return NULL; + spin_lock_irqsave(&c->fifo_lock, flags); + if (list_empty(&c->fifo)) { + spin_unlock_irqrestore(&c->fifo_lock, flags); + return NULL; + } + mbo = list_pop_mbo(&c->fifo); + spin_unlock_irqrestore(&c->fifo_lock, flags); + mbo->buffer_length = c->cfg.buffer_size; + return mbo; +} +EXPORT_SYMBOL_GPL(most_get_mbo); + + +/** + * most_put_mbo - return buffer to pool + * @mbo: buffer object + */ +void most_put_mbo(struct mbo *mbo) +{ + struct most_c_obj *c; + struct most_inst_obj *i; + + c = mbo->context; + i = c->inst; + + if (unlikely(atomic_read(&i->tainted))) { + mbo->status = MBO_E_CLOSE; + trash_mbo(mbo); + return; + } + if (c->cfg.direction == MOST_CH_TX) { + arm_mbo(mbo); + return; + } + nq_hdm_mbo(mbo); + atomic_inc(&c->mbo_nq_level); +} +EXPORT_SYMBOL_GPL(most_put_mbo); + +/** + * most_read_completion - read completion handler + * @mbo: pointer to MBO + * + * This function is called by the HDM when data has been received from the + * hardware and copied to the buffer of the MBO. + * + * In case the channel has been poisoned it puts the buffer in the trash queue. + * Otherwise, it passes the buffer to an AIM for further processing. + */ +static void most_read_completion(struct mbo *mbo) +{ + struct most_c_obj *c; + + c = mbo->context; + if (unlikely((c->is_poisoned == true) || (mbo->status == MBO_E_CLOSE))) + goto release_mbo; + + if (mbo->status == MBO_E_INVAL) { + nq_hdm_mbo(mbo); + atomic_inc(&c->mbo_nq_level); + return; + } + + if (atomic_sub_and_test(1, &c->mbo_nq_level)) { + pr_info("WARN: rx device out of buffers\n"); + c->is_starving = 1; + } + + if (c->first_aim && c->first_aim->rx_completion && + c->first_aim->rx_completion(mbo) == 0) + return; + if (c->second_aim && c->second_aim->rx_completion && + c->second_aim->rx_completion(mbo) == 0) + return; + pr_info("WARN: no driver linked with this channel\n"); + mbo->status = MBO_E_CLOSE; +release_mbo: + trash_mbo(mbo); +} + +/** + * most_start_channel - prepares a channel for communication + * @iface: pointer to interface instance + * @id: channel ID + * + * This prepares the channel for usage. Cross-checks whether the + * channel's been properly configured. + * + * Returns 0 on success or error code otherwise. + */ +int most_start_channel(struct most_interface *iface, int id) +{ + int num_buffer; + int ret; + struct most_c_obj *c = get_channel_by_iface(iface, id); + + if (unlikely(!c)) + return -EINVAL; + + if (c->is_started) + return -EBUSY; + + if (!try_module_get(iface->mod)) { + pr_info("failed to acquire HDM lock\n"); + return -ENOLCK; + } + modref++; + + c->cfg.extra_len = 0; + if (c->iface->configure(c->iface, c->channel_id, &c->cfg)) { + pr_info("channel configuration failed. Go check settings...\n"); + ret = -EINVAL; + goto error; + } + + init_waitqueue_head(&c->hdm_fifo_wq); + + if (c->cfg.direction == MOST_CH_RX) + num_buffer = arm_mbo_chain(c, c->cfg.direction, + most_read_completion); + else + num_buffer = arm_mbo_chain(c, c->cfg.direction, + most_write_completion); + if (unlikely(0 == num_buffer)) { + pr_info("failed to allocate memory\n"); + ret = -ENOMEM; + goto error; + } + + ret = run_enqueue_thread(c, id); + if (ret) + goto error; + + c->is_started = true; + c->is_starving = 0; + atomic_set(&c->mbo_ref, num_buffer); + return 0; +error: + if (iface->mod) + module_put(iface->mod); + modref--; + return ret; +} +EXPORT_SYMBOL_GPL(most_start_channel); + +/** + * most_stop_channel - stops a running channel + * @iface: pointer to interface instance + * @id: channel ID + */ +int most_stop_channel(struct most_interface *iface, int id) +{ + struct most_c_obj *c; + + if (unlikely((!iface) || (id >= iface->num_channels) || (id < 0))) { + pr_err("Bad interface or index out of range\n"); + return -EINVAL; + } + c = get_channel_by_iface(iface, id); + if (unlikely(!c)) + return -EINVAL; + + if (!c->is_started) + return 0; + + /* FIXME: we need to know calling AIM to reset only one link */ + c->first_aim = NULL; + c->second_aim = NULL; + /* do not go into recursion calling aim->disconnect_channel */ + + mutex_lock(&c->stop_task_mutex); + if (c->hdm_enqueue_task) + kthread_stop(c->hdm_enqueue_task); + c->hdm_enqueue_task = NULL; + mutex_unlock(&c->stop_task_mutex); + + mutex_lock(&deregister_mutex); + if (atomic_read(&c->inst->tainted)) { + mutex_unlock(&deregister_mutex); + return -ENODEV; + } + mutex_unlock(&deregister_mutex); + + if (iface->mod && modref) { + module_put(iface->mod); + modref--; + } + + c->is_poisoned = true; + if (c->iface->poison_channel(c->iface, c->channel_id)) { + pr_err("Cannot stop channel %d of mdev %s\n", c->channel_id, + c->iface->description); + return -EAGAIN; + } + flush_trash_fifo(c); + flush_channel_fifos(c); + +#ifdef CMPL_INTERRUPTIBLE + if (wait_for_completion_interruptible(&c->cleanup)) { + pr_info("Interrupted while clean up ch %d\n", c->channel_id); + return -EINTR; + } +#else + wait_for_completion(&c->cleanup); +#endif + c->is_poisoned = false; + c->is_started = false; + return 0; +} +EXPORT_SYMBOL_GPL(most_stop_channel); + +/** + * most_register_aim - registers an AIM (driver) with the core + * @aim: instance of AIM to be registered + */ +int most_register_aim(struct most_aim *aim) +{ + struct most_aim_obj *aim_obj; + + if (!aim) { + pr_err("Bad driver\n"); + return -EINVAL; + } + aim_obj = create_most_aim_obj(aim->name); + if (!aim_obj) { + pr_info("failed to alloc driver object\n"); + return -ENOMEM; + } + aim_obj->driver = aim; + aim->context = aim_obj; + pr_info("registered new application interfacing module %s\n", + aim->name); + list_add_tail(&aim_obj->list, &aim_list); + return 0; +} +EXPORT_SYMBOL_GPL(most_register_aim); + +/** + * most_deregister_aim - deregisters an AIM (driver) with the core + * @aim: AIM to be removed + */ +int most_deregister_aim(struct most_aim *aim) +{ + struct most_aim_obj *aim_obj; + struct most_c_obj *c, *tmp; + struct most_inst_obj *i, *i_tmp; + + if (!aim) { + pr_err("Bad driver\n"); + return -EINVAL; + } + + aim_obj = aim->context; + if (!aim_obj) { + pr_info("driver not registered.\n"); + return -EINVAL; + } + list_for_each_entry_safe(i, i_tmp, &instance_list, list) { + list_for_each_entry_safe(c, tmp, &i->channel_list, list) { + if (c->first_aim == aim || c->second_aim == aim) + aim->disconnect_channel( + c->iface, c->channel_id); + if (c->first_aim == aim) + c->first_aim = NULL; + if (c->second_aim == aim) + c->second_aim = NULL; + } + } + list_del(&aim_obj->list); + destroy_most_aim_obj(aim_obj); + pr_info("deregistering application interfacing module %s\n", aim->name); + return 0; +} +EXPORT_SYMBOL_GPL(most_deregister_aim); + +/** + * most_register_interface - registers an interface with core + * @iface: pointer to the instance of the interface description. + * + * Allocates and initializes a new interface instance and all of its channels. + * Returns a pointer to kobject or an error pointer. + */ +struct kobject *most_register_interface(struct most_interface *iface) +{ + unsigned int i; + int id; + char name[STRING_SIZE]; + char channel_name[STRING_SIZE]; + struct most_c_obj *c; + struct most_inst_obj *inst; + + if (!iface || !iface->enqueue || !iface->configure || + !iface->poison_channel || (iface->num_channels > MAX_CHANNELS)) { + pr_err("Bad interface or channel overflow\n"); + return ERR_PTR(-EINVAL); + } + + id = ida_simple_get(&mdev_id, 0, 0, GFP_KERNEL); + if (id < 0) { + pr_info("Failed to alloc mdev ID\n"); + return ERR_PTR(id); + } + snprintf(name, STRING_SIZE, "mdev%d", id); + + inst = create_most_inst_obj(name); + if (!inst) { + pr_info("Failed to allocate interface instance\n"); + return ERR_PTR(-ENOMEM); + } + + iface->priv = inst; + INIT_LIST_HEAD(&inst->channel_list); + inst->iface = iface; + inst->dev_id = id; + atomic_set(&inst->tainted, 0); + list_add_tail(&inst->list, &instance_list); + + for (i = 0; i < iface->num_channels; i++) { + const char *name_suffix = iface->channel_vector[i].name_suffix; + + if (!name_suffix) + snprintf(channel_name, STRING_SIZE, "ch%d", i); + else if (name_suffix[0] == '@') + snprintf(channel_name, STRING_SIZE, "ch%d%s", i, + name_suffix); + else + snprintf(channel_name, STRING_SIZE, "%s", name_suffix); + + /* this increments the reference count of this instance */ + c = create_most_c_obj(channel_name, &inst->kobj); + if (!c) + goto free_instance; + inst->channel[i] = c; + c->is_starving = 0; + c->iface = iface; + c->inst = inst; + c->channel_id = i; + c->keep_mbo = false; + c->enqueue_halt = false; + c->is_poisoned = false; + c->is_started = false; + c->cfg.direction = 0; + c->cfg.data_type = 0; + c->cfg.num_buffers = 0; + c->cfg.buffer_size = 0; + c->cfg.subbuffer_size = 0; + c->cfg.packets_per_xact = 0; + spin_lock_init(&c->fifo_lock); + INIT_LIST_HEAD(&c->fifo); + INIT_LIST_HEAD(&c->trash_fifo); + INIT_LIST_HEAD(&c->halt_fifo); + init_completion(&c->cleanup); + atomic_set(&c->mbo_ref, 0); + mutex_init(&c->stop_task_mutex); + list_add_tail(&c->list, &inst->channel_list); + } + pr_info("registered new MOST device mdev%d (%s)\n", + inst->dev_id, iface->description); + return &inst->kobj; + +free_instance: + pr_info("Failed allocate channel(s)\n"); + list_del(&inst->list); + destroy_most_inst_obj(inst); + return ERR_PTR(-ENOMEM); +} +EXPORT_SYMBOL_GPL(most_register_interface); + +/** + * most_deregister_interface - deregisters an interface with core + * @iface: pointer to the interface instance description. + * + * Before removing an interface instance from the list, all running + * channels are stopped and poisoned. + */ +void most_deregister_interface(struct most_interface *iface) +{ + struct most_inst_obj *i = iface->priv; + struct most_c_obj *c; + + mutex_lock(&deregister_mutex); + if (unlikely(!i)) { + pr_info("Bad Interface\n"); + mutex_unlock(&deregister_mutex); + return; + } + pr_info("deregistering MOST device %s (%s)\n", i->kobj.name, + iface->description); + + atomic_set(&i->tainted, 1); + mutex_unlock(&deregister_mutex); + + while (modref) { + if (iface->mod && modref) + module_put(iface->mod); + modref--; + } + + list_for_each_entry(c, &i->channel_list, list) { + if (!c->is_started) + continue; + + mutex_lock(&c->stop_task_mutex); + if (c->hdm_enqueue_task) + kthread_stop(c->hdm_enqueue_task); + c->hdm_enqueue_task = NULL; + mutex_unlock(&c->stop_task_mutex); + + if (iface->poison_channel(iface, c->channel_id)) + pr_err("Can't poison channel %d\n", c->channel_id); + } + ida_simple_remove(&mdev_id, i->dev_id); + list_del(&i->list); + destroy_most_inst_obj(i); +} +EXPORT_SYMBOL_GPL(most_deregister_interface); + +/** + * most_stop_enqueue - prevents core from enqueueing MBOs + * @iface: pointer to interface + * @id: channel id + * + * This is called by an HDM that _cannot_ attend to its duties and + * is imminent to get run over by the core. The core is not going to + * enqueue any further packets unless the flagging HDM calls + * most_resume enqueue(). + */ +void most_stop_enqueue(struct most_interface *iface, int id) +{ + struct most_c_obj *c = get_channel_by_iface(iface, id); + + if (likely(c)) + c->enqueue_halt = true; +} +EXPORT_SYMBOL_GPL(most_stop_enqueue); + +/** + * most_resume_enqueue - allow core to enqueue MBOs again + * @iface: pointer to interface + * @id: channel id + * + * This clears the enqueue halt flag and enqueues all MBOs currently + * sitting in the wait fifo. + */ +void most_resume_enqueue(struct most_interface *iface, int id) +{ + struct most_c_obj *c = get_channel_by_iface(iface, id); + + if (unlikely(!c)) + return; + c->enqueue_halt = false; + + wake_up_interruptible(&c->hdm_fifo_wq); +} +EXPORT_SYMBOL_GPL(most_resume_enqueue); + +static int __init most_init(void) +{ + pr_info("init()\n"); + INIT_LIST_HEAD(&instance_list); + INIT_LIST_HEAD(&aim_list); + mutex_init(&deregister_mutex); + ida_init(&mdev_id); + + if (bus_register(&most_bus)) { + pr_info("Cannot register most bus\n"); + goto exit; + } + + most_class = class_create(THIS_MODULE, "most"); + if (IS_ERR(most_class)) { + pr_info("No udev support.\n"); + goto exit_bus; + } + if (driver_register(&mostcore)) { + pr_info("Cannot register core driver\n"); + goto exit_class; + } + + class_glue_dir = + device_create(most_class, NULL, 0, NULL, "mostcore"); + if (!class_glue_dir) + goto exit_driver; + + most_aim_kset = + kset_create_and_add("aims", NULL, &class_glue_dir->kobj); + if (!most_aim_kset) + goto exit_class_container; + + most_inst_kset = + kset_create_and_add("devices", NULL, &class_glue_dir->kobj); + if (!most_inst_kset) + goto exit_driver_kset; + + return 0; + +exit_driver_kset: + kset_unregister(most_aim_kset); +exit_class_container: + device_destroy(most_class, 0); +exit_driver: + driver_unregister(&mostcore); +exit_class: + class_destroy(most_class); +exit_bus: + bus_unregister(&most_bus); +exit: + return -ENOMEM; +} + +static void __exit most_exit(void) +{ + struct most_inst_obj *i, *i_tmp; + struct most_aim_obj *d, *d_tmp; + + pr_info("exit core module\n"); + list_for_each_entry_safe(d, d_tmp, &aim_list, list) { + destroy_most_aim_obj(d); + } + + list_for_each_entry_safe(i, i_tmp, &instance_list, list) { + list_del(&i->list); + destroy_most_inst_obj(i); + } + kset_unregister(most_inst_kset); + kset_unregister(most_aim_kset); + device_destroy(most_class, 0); + driver_unregister(&mostcore); + class_destroy(most_class); + bus_unregister(&most_bus); + ida_destroy(&mdev_id); +} + +module_init(most_init); +module_exit(most_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Gromm "); +MODULE_DESCRIPTION("Core module of stacked MOST Linux driver"); diff --git a/drivers/staging/most/mostcore/mostcore.h b/drivers/staging/most/mostcore/mostcore.h new file mode 100644 index 000000000000..299c7d5aa73a --- /dev/null +++ b/drivers/staging/most/mostcore/mostcore.h @@ -0,0 +1,316 @@ +/* + * mostcore.h - Interface between MostCore, + * Hardware Dependent Module (HDM) and Application Interface Module (AIM). + * + * Copyright (C) 2013-2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +/* + * Authors: + * Andrey Shvetsov + * Christian Gromm + * Sebastian Graf + */ + +#ifndef __MOST_CORE_H__ +#define __MOST_CORE_H__ + +#include + +struct kobject; +struct module; + +/** + * Interface type + */ +enum most_interface_type { + ITYPE_LOOPBACK = 1, + ITYPE_I2C, + ITYPE_I2S, + ITYPE_TSI, + ITYPE_HBI, + ITYPE_MEDIALB_DIM, + ITYPE_MEDIALB_DIM2, + ITYPE_USB, + ITYPE_PCIE +}; + +/** + * Channel direction. + */ +enum most_channel_direction { + MOST_CH_RX = 1 << 0, + MOST_CH_TX = 1 << 1, +}; + +/** + * Channel data type. + */ +enum most_channel_data_type { + MOST_CH_CONTROL = 1 << 0, + MOST_CH_ASYNC = 1 << 1, + MOST_CH_ISOC_AVP = 1 << 2, + MOST_CH_SYNC = 1 << 5, +}; + + +enum mbo_status_flags { + /* MBO was processed successfully (data was send or received )*/ + MBO_SUCCESS = 0, + /* The MBO contains wrong or missing information. */ + MBO_E_INVAL, + /* MBO was completed as HDM Channel will be closed */ + MBO_E_CLOSE, +}; + +/** + * struct most_channel_capability - Channel capability + * @direction: Supported channel directions. + * The value is bitwise OR-combination of the values from the + * enumeration most_channel_direction. Zero is allowed value and means + * "channel may not be used". + * @data_type: Supported channel data types. + * The value is bitwise OR-combination of the values from the + * enumeration most_channel_data_type. Zero is allowed value and means + * "channel may not be used". + * @num_buffer_packet: Maximum number of buffers supported by this channel + * for packet data types (Async,Control,QoS) + * @buffer_size_packet: Maximum buffer size supported by this channel + * for packet data types (Async,Control,QoS) + * @num_buffer_streaming: Maximum number of buffers supported by this channel + * for streaming data types (Sync,AV Packetized) + * @buffer_size_streaming: Maximum buffer size supported by this channel + * for streaming data types (Sync,AV Packetized) + * @name_suffix: Optional suffix providean by an HDM that is attached to the + * regular channel name. + * + * Describes the capabilities of a MostCore channel like supported Data Types + * and directions. This information is provided by an HDM for the MostCore. + * + * The Core creates read only sysfs attribute files in + * /sys/devices/virtual/most/mostcore/devices/mdev-#/mdev#-ch#/ with the + * following attributes: + * -available_directions + * -available_datatypes + * -number_of_packet_buffers + * -number_of_stream_buffers + * -size_of_packet_buffer + * -size_of_stream_buffer + * where content of each file is a string with all supported properties of this + * very channel attribute. + */ +struct most_channel_capability { + u16 direction; + u16 data_type; + u16 num_buffers_packet; + u16 buffer_size_packet; + u16 num_buffers_streaming; + u16 buffer_size_streaming; + char *name_suffix; +}; + +/** + * struct most_channel_config - stores channel configuration + * @direction: direction of the channel + * @data_type: data type travelling over this channel + * @num_buffers: number of buffers + * @buffer_size: size of a buffer for AIM. + * Buffer size may be cutted down by HDM in a configure callback + * to match to a given interface and channel type. + * @extra_len: additional buffer space for internal HDM purposes like padding. + * May be set by HDM in a configure callback if needed. + * @subbuffer_size: size of a subbuffer + * @packets_per_xact: number of MOST frames that are packet inside one USB + * packet. This is USB specific + * + * Describes the configuration for a MostCore channel. This information is + * provided from the MostCore to a HDM (like the Medusa PCIe Interface) as a + * parameter of the "configure" function call. + */ +struct most_channel_config { + enum most_channel_direction direction; + enum most_channel_data_type data_type; + u16 num_buffers; + u16 buffer_size; + u16 extra_len; + u16 subbuffer_size; + u16 packets_per_xact; +}; + +/* + * struct mbo - MOST Buffer Object. + * @context: context for core completion handler + * @priv: private data for HDM + * + * public: documented fields that are used for the communications + * between MostCore and HDMs + * + * @list: list head for use by the mbo's current owner + * @ifp: (in) associated interface instance + * @hdm_channel_id: (in) HDM channel instance + * @virt_address: (in) kernel virtual address of the buffer + * @bus_address: (in) bus address of the buffer + * @buffer_length: (in) buffer payload length + * @processed_length: (out) processed length + * @status: (out) transfer status + * @complete: (in) completion routine + * + * The MostCore allocates and initializes the MBO. + * + * The HDM receives MBO for transfer from MostCore with the call to enqueue(). + * The HDM copies the data to- or from the buffer depending on configured + * channel direction, set "processed_length" and "status" and completes + * the transfer procedure by calling the completion routine. + * + * At the end the MostCore deallocates the MBO or recycles it for further + * transfers for the same or different HDM. + * + * Directions of usage: + * The core driver should never access any MBO fields (even if marked + * as "public") while the MBO is owned by an HDM. The ownership starts with + * the call of enqueue() and ends with the call of its complete() routine. + * + * II. + * Every HDM attached to the core driver _must_ ensure that it returns any MBO + * it owns (due to a previous call to enqueue() by the core driver) before it + * de-registers an interface or gets unloaded from the kernel. If this direction + * is violated memory leaks will occur, since the core driver does _not_ track + * MBOs it is currently not in control of. + * + */ +struct mbo { + void *context; + void *priv; + struct list_head list; + struct most_interface *ifp; + u16 hdm_channel_id; + void *virt_address; + dma_addr_t bus_address; + u16 buffer_length; + u16 processed_length; + enum mbo_status_flags status; + void (*complete)(struct mbo *); +}; + +/** + * Interface instance description. + * + * Describes one instance of an interface like Medusa PCIe or Vantage USB. + * This structure is allocated and initialized in the HDM. MostCore may not + * modify this structure. + * + * @interface Interface type. \sa most_interface_type. + * @description PRELIMINARY. + * Unique description of the device instance from point of view of the + * interface in free text form (ASCII). + * It may be a hexadecimal presentation of the memory address for the MediaLB + * IP or USB device ID with USB properties for USB interface, etc. + * @num_channels Number of channels and size of the channel_vector. + * @channel_vector Properties of the channels. + * Array index represents channel ID by the driver. + * @configure Callback to change data type for the channel of the + * interface instance. May be zero if the instance of the interface is not + * configurable. Parameter channel_config describes direction and data + * type for the channel, configured by the higher level. The content of + * @enqueue Delivers MBO to the HDM for processing. + * After HDM completes Rx- or Tx- operation the processed MBO shall + * be returned back to the MostCore using completion routine. + * The reason to get the MBO delivered from the MostCore after the channel + * is poisoned is the re-opening of the channel by the application. + * In this case the HDM shall hold MBOs and service the channel as usual. + * The HDM must be able to hold at least one MBO for each channel. + * The callback returns a negative value on error, otherwise 0. + * @poison_channel Informs HDM about closing the channel. The HDM shall + * cancel all transfers and synchronously or asynchronously return + * all enqueued for this channel MBOs using the completion routine. + * The callback returns a negative value on error, otherwise 0. + * @request_netinfo: triggers retrieving of network info from the HDM by + * means of "Message exchange over MDP/MEP" + * @priv Private field used by mostcore to store context information. + */ +struct most_interface { + struct module *mod; + enum most_interface_type interface; + const char *description; + int num_channels; + struct most_channel_capability *channel_vector; + int (*configure)(struct most_interface *iface, int channel_idx, + struct most_channel_config *channel_config); + int (*enqueue)(struct most_interface *iface, int channel_idx, + struct mbo *mbo); + int (*poison_channel)(struct most_interface *iface, int channel_idx); + void (*request_netinfo)(struct most_interface *iface, int channel_idx); + void *priv; +}; + +/** + * struct most_aim - identifies MOST device driver to mostcore + * @name: Driver name + * @probe_channel: function for core to notify driver about channel connection + * @disconnect_channel: notification that a certain channel isn't available anymore + * @rx_completion: completion handler for received packets + * @tx_completion: completion handler for transmitted packets + * @context: context pointer to be used by mostcore + */ +struct most_aim { + const char *name; + int (*probe_channel)(struct most_interface *iface, int channel_idx, + struct most_channel_config *cfg, + struct kobject *parent, char *name); + int (*disconnect_channel)(struct most_interface *iface, + int channel_idx); + int (*rx_completion)(struct mbo *mbo); + int (*tx_completion)(struct most_interface *iface, int channel_idx); + void *context; +}; + +/** + * most_register_interface - Registers instance of the interface. + * @iface: Pointer to the interface instance description. + * + * Returns a pointer to the kobject of the generated instance. + * + * Note: HDM has to ensure that any reference held on the kobj is + * released before deregistering the interface. + */ +struct kobject *most_register_interface(struct most_interface *iface); + +/** + * Deregisters instance of the interface. + * @intf_instance Pointer to the interface instance description. + */ +void most_deregister_interface(struct most_interface *iface); +int most_submit_mbo(struct mbo *mbo); + +/** + * most_stop_enqueue - prevents core from enqueing MBOs + * @iface: pointer to interface + * @channel_idx: channel index + */ +void most_stop_enqueue(struct most_interface *iface, int channel_idx); + +/** + * most_resume_enqueue - allow core to enqueue MBOs again + * @iface: pointer to interface + * @channel_idx: channel index + * + * This clears the enqueue halt flag and enqueues all MBOs currently + * in wait fifo. + */ +void most_resume_enqueue(struct most_interface *iface, int channel_idx); +int most_register_aim(struct most_aim *aim); +int most_deregister_aim(struct most_aim *aim); +struct mbo *most_get_mbo(struct most_interface *iface, int channel_idx); +void most_put_mbo(struct mbo *mbo); +int most_start_channel(struct most_interface *iface, int channel_idx); +int most_stop_channel(struct most_interface *iface, int channel_idx); + + +#endif /* MOST_CORE_H_ */ -- cgit v1.3-6-gb490 From 9bc79bbcd0c526e3ec7b98e08c5d34648bb3c158 Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Fri, 24 Jul 2015 16:11:49 +0200 Subject: Staging: most: add MOST driver's aim-cdev module This patch adds the aim-cdev module of the MOST driver to the kernel's driver staging area. This module is part of the MOST driver and handles user space interaction by means of character devices. This patch is needed in order to have access to MOST data through character devices. Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/Kconfig | 2 + drivers/staging/most/Makefile | 1 + drivers/staging/most/aim-cdev/Kconfig | 12 + drivers/staging/most/aim-cdev/Makefile | 4 + drivers/staging/most/aim-cdev/cdev.c | 527 +++++++++++++++++++++++++++++++++ 5 files changed, 546 insertions(+) create mode 100644 drivers/staging/most/aim-cdev/Kconfig create mode 100644 drivers/staging/most/aim-cdev/Makefile create mode 100644 drivers/staging/most/aim-cdev/cdev.c (limited to 'drivers') diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig index b7db320dbacc..e29bee569c77 100644 --- a/drivers/staging/most/Kconfig +++ b/drivers/staging/most/Kconfig @@ -13,4 +13,6 @@ if MOST source "drivers/staging/most/mostcore/Kconfig" +source "drivers/staging/most/aim-cdev/Kconfig" + endif diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile index 0144be009337..b7b319bd61a1 100644 --- a/drivers/staging/most/Makefile +++ b/drivers/staging/most/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_MOSTCORE) += mostcore/ +obj-$(CONFIG_AIM_CDEV) += aim-cdev/ diff --git a/drivers/staging/most/aim-cdev/Kconfig b/drivers/staging/most/aim-cdev/Kconfig new file mode 100644 index 000000000000..3c59f1bac127 --- /dev/null +++ b/drivers/staging/most/aim-cdev/Kconfig @@ -0,0 +1,12 @@ +# +# MOST Cdev configuration +# + +config AIM_CDEV + tristate "Cdev AIM" + + ---help--- + Say Y here if you want to commumicate via character devices. + + To compile this driver as a module, choose M here: the + module will be called aim_cdev. \ No newline at end of file diff --git a/drivers/staging/most/aim-cdev/Makefile b/drivers/staging/most/aim-cdev/Makefile new file mode 100644 index 000000000000..0bcc6c637b75 --- /dev/null +++ b/drivers/staging/most/aim-cdev/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_AIM_CDEV) += aim_cdev.o + +aim_cdev-objs := cdev.o +ccflags-y += -Idrivers/staging/most/mostcore/ \ No newline at end of file diff --git a/drivers/staging/most/aim-cdev/cdev.c b/drivers/staging/most/aim-cdev/cdev.c new file mode 100644 index 000000000000..d5fb4a0e0818 --- /dev/null +++ b/drivers/staging/most/aim-cdev/cdev.c @@ -0,0 +1,527 @@ +/* + * cdev.c - Application interfacing module for character devices + * + * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mostcore.h" + +static dev_t aim_devno; +static struct class *aim_class; +static struct ida minor_id; +static unsigned int major; + +struct aim_channel { + wait_queue_head_t wq; + struct cdev cdev; + struct device *dev; + struct mutex io_mutex; + struct most_interface *iface; + struct most_channel_config *cfg; + unsigned int channel_id; + dev_t devno; + bool keep_mbo; + unsigned int mbo_offs; + struct mbo *stacked_mbo; + DECLARE_KFIFO_PTR(fifo, typeof(struct mbo *)); + atomic_t access_ref; + struct list_head list; +}; +#define to_channel(d) container_of(d, struct aim_channel, cdev) +static struct list_head channel_list; +static spinlock_t ch_list_lock; + + +struct aim_channel *get_channel(struct most_interface *iface, int id) +{ + struct aim_channel *channel, *tmp; + unsigned long flags; + int found_channel = 0; + + spin_lock_irqsave(&ch_list_lock, flags); + list_for_each_entry_safe(channel, tmp, &channel_list, list) { + if ((channel->iface == iface) && (channel->channel_id == id)) { + found_channel = 1; + break; + } + } + spin_unlock_irqrestore(&ch_list_lock, flags); + if (!found_channel) + return NULL; + return channel; +} + +/** + * aim_open - implements the syscall to open the device + * @inode: inode pointer + * @filp: file pointer + * + * This stores the channel pointer in the private data field of + * the file structure and activates the channel within the core. + */ +static int aim_open(struct inode *inode, struct file *filp) +{ + struct aim_channel *channel; + int ret; + + channel = to_channel(inode->i_cdev); + filp->private_data = channel; + + if (((channel->cfg->direction == MOST_CH_RX) && + ((filp->f_flags & O_ACCMODE) != O_RDONLY)) + || ((channel->cfg->direction == MOST_CH_TX) && + ((filp->f_flags & O_ACCMODE) != O_WRONLY))) { + pr_info("WARN: Access flags mismatch\n"); + return -EACCES; + } + if (!atomic_inc_and_test(&channel->access_ref)) { + pr_info("WARN: Device is busy\n"); + atomic_dec(&channel->access_ref); + return -EBUSY; + } + + ret = most_start_channel(channel->iface, channel->channel_id); + if (ret) + atomic_dec(&channel->access_ref); + return ret; +} + +/** + * aim_close - implements the syscall to close the device + * @inode: inode pointer + * @filp: file pointer + * + * This stops the channel within the core. + */ +static int aim_close(struct inode *inode, struct file *filp) +{ + int ret; + struct mbo *mbo; + struct aim_channel *channel = to_channel(inode->i_cdev); + + mutex_lock(&channel->io_mutex); + if (!channel->dev) { + mutex_unlock(&channel->io_mutex); + atomic_dec(&channel->access_ref); + device_destroy(aim_class, channel->devno); + cdev_del(&channel->cdev); + kfifo_free(&channel->fifo); + list_del(&channel->list); + kfree(channel); + ida_simple_remove(&minor_id, MINOR(channel->devno)); + wake_up_interruptible(&channel->wq); + return 0; + } + mutex_unlock(&channel->io_mutex); + + while (0 != kfifo_out((struct kfifo *)&channel->fifo, &mbo, 1)) + most_put_mbo(mbo); + if (channel->keep_mbo == true) + most_put_mbo(channel->stacked_mbo); + ret = most_stop_channel(channel->iface, channel->channel_id); + atomic_dec(&channel->access_ref); + wake_up_interruptible(&channel->wq); + return ret; +} + +/** + * aim_write - implements the syscall to write to the device + * @filp: file pointer + * @buf: pointer to user buffer + * @count: number of bytes to write + * @offset: offset from where to start writing + */ +static ssize_t aim_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + int ret, err; + size_t actual_len = 0; + size_t max_len = 0; + ssize_t retval; + struct mbo *mbo; + struct aim_channel *channel = filp->private_data; + + mutex_lock(&channel->io_mutex); + if (unlikely(!channel->dev)) { + mutex_unlock(&channel->io_mutex); + return -EPIPE; + } + mutex_unlock(&channel->io_mutex); + + mbo = most_get_mbo(channel->iface, channel->channel_id); + + if (!mbo && channel->dev) { + if ((filp->f_flags & O_NONBLOCK)) + return -EAGAIN; + if (wait_event_interruptible( + channel->wq, + (mbo = most_get_mbo(channel->iface, + channel->channel_id)) || + (channel->dev == NULL))) + return -ERESTARTSYS; + } + + mutex_lock(&channel->io_mutex); + if (unlikely(!channel->dev)) { + mutex_unlock(&channel->io_mutex); + err = -EPIPE; + goto error; + } + mutex_unlock(&channel->io_mutex); + + max_len = channel->cfg->buffer_size; + actual_len = min(count, max_len); + mbo->buffer_length = actual_len; + + retval = copy_from_user(mbo->virt_address, buf, mbo->buffer_length); + if (retval) { + err = -EIO; + goto error; + } + + ret = most_submit_mbo(mbo); + if (ret) { + pr_info("submitting MBO to core failed\n"); + err = ret; + goto error; + } + return actual_len - retval; +error: + most_put_mbo(mbo); + return err; +} + +/** + * aim_read - implements the syscall to read from the device + * @filp: file pointer + * @buf: pointer to user buffer + * @count: number of bytes to read + * @offset: offset from where to start reading + */ +static ssize_t +aim_read(struct file *filp, char __user *buf, size_t count, loff_t *offset) +{ + ssize_t retval; + size_t not_copied, proc_len; + struct mbo *mbo; + struct aim_channel *channel = filp->private_data; + + if (channel->keep_mbo == true) { + mbo = channel->stacked_mbo; + channel->keep_mbo = false; + goto start_copy; + } + while ((0 == kfifo_out(&channel->fifo, &mbo, 1)) + && (channel->dev != NULL)) { + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + if (wait_event_interruptible(channel->wq, + (!kfifo_is_empty(&channel->fifo) || + (channel->dev == NULL)))) + return -ERESTARTSYS; + } + +start_copy: + /* make sure we don't submit to gone devices */ + mutex_lock(&channel->io_mutex); + if (unlikely(!channel->dev)) { + mutex_unlock(&channel->io_mutex); + return -EIO; + } + + if (count < mbo->processed_length) + channel->keep_mbo = true; + + proc_len = min((int)count, + (int)(mbo->processed_length - channel->mbo_offs)); + + not_copied = copy_to_user(buf, + mbo->virt_address + channel->mbo_offs, + proc_len); + + retval = not_copied ? proc_len - not_copied : proc_len; + + if (channel->keep_mbo == true) { + channel->mbo_offs = retval; + channel->stacked_mbo = mbo; + } else { + most_put_mbo(mbo); + channel->mbo_offs = 0; + } + mutex_unlock(&channel->io_mutex); + return retval; +} + +/** + * Initialization of struct file_operations + */ +static const struct file_operations channel_fops = { + .owner = THIS_MODULE, + .read = aim_read, + .write = aim_write, + .open = aim_open, + .release = aim_close, +}; + +/** + * aim_disconnect_channel - disconnect a channel + * @iface: pointer to interface instance + * @channel_id: channel index + * + * This frees allocated memory and removes the cdev that represents this + * channel in user space. + */ +int aim_disconnect_channel(struct most_interface *iface, int channel_id) +{ + struct aim_channel *channel; + unsigned long flags; + + if (!iface) { + pr_info("Bad interface pointer\n"); + return -EINVAL; + } + + channel = get_channel(iface, channel_id); + if (channel == NULL) + return -ENXIO; + + mutex_lock(&channel->io_mutex); + channel->dev = NULL; + mutex_unlock(&channel->io_mutex); + + if (atomic_read(&channel->access_ref)) { + device_destroy(aim_class, channel->devno); + cdev_del(&channel->cdev); + kfifo_free(&channel->fifo); + ida_simple_remove(&minor_id, MINOR(channel->devno)); + spin_lock_irqsave(&ch_list_lock, flags); + list_del(&channel->list); + spin_unlock_irqrestore(&ch_list_lock, flags); + kfree(channel); + } else { + wake_up_interruptible(&channel->wq); + } + return 0; +} + +/** + * aim_rx_completion - completion handler for rx channels + * @mbo: pointer to buffer object that has completed + * + * This searches for the channel linked to this MBO and stores it in the local + * fifo buffer. + */ +int aim_rx_completion(struct mbo *mbo) +{ + struct aim_channel *channel; + + if (!mbo) + return -EINVAL; + + channel = get_channel(mbo->ifp, mbo->hdm_channel_id); + if (channel == NULL) + return -ENXIO; + + kfifo_in(&channel->fifo, &mbo, 1); +#ifdef DEBUG_MESG + if (kfifo_is_full(&channel->fifo)) + pr_info("WARN: Fifo is full\n"); +#endif + wake_up_interruptible(&channel->wq); + return 0; +} + +/** + * aim_tx_completion - completion handler for tx channels + * @iface: pointer to interface instance + * @channel_id: channel index/ID + * + * This wakes sleeping processes in the wait-queue. + */ +int aim_tx_completion(struct most_interface *iface, int channel_id) +{ + struct aim_channel *channel; + + if (!iface) { + pr_info("Bad interface pointer\n"); + return -EINVAL; + } + if ((channel_id < 0) || (channel_id >= iface->num_channels)) { + pr_info("Channel ID out of range\n"); + return -EINVAL; + } + + channel = get_channel(iface, channel_id); + if (channel == NULL) + return -ENXIO; + wake_up_interruptible(&channel->wq); + return 0; +} + +struct most_aim cdev_aim; + +/** + * aim_probe - probe function of the driver module + * @iface: pointer to interface instance + * @channel_id: channel index/ID + * @cfg: pointer to actual channel configuration + * @parent: pointer to kobject (needed for sysfs hook-up) + * @name: name of the device to be created + * + * This allocates achannel object and creates the device node in /dev + * + * Returns 0 on success or error code otherwise. + */ +int aim_probe(struct most_interface *iface, int channel_id, + struct most_channel_config *cfg, + struct kobject *parent, char *name) +{ + struct aim_channel *channel; + unsigned long cl_flags; + int retval; + int current_minor; + + if ((!iface) || (!cfg) || (!parent) || (!name)) { + pr_info("Probing AIM with bad arguments"); + return -EINVAL; + } + channel = get_channel(iface, channel_id); + if (channel) + return -EEXIST; + + current_minor = ida_simple_get(&minor_id, 0, 0, GFP_KERNEL); + if (current_minor < 0) + return current_minor; + + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) { + pr_info("failed to alloc channel object\n"); + retval = -ENOMEM; + goto error_alloc_channel; + } + + channel->devno = MKDEV(major, current_minor); + cdev_init(&channel->cdev, &channel_fops); + channel->cdev.owner = THIS_MODULE; + cdev_add(&channel->cdev, channel->devno, 1); + channel->iface = iface; + channel->cfg = cfg; + channel->channel_id = channel_id; + channel->mbo_offs = 0; + atomic_set(&channel->access_ref, -1); + INIT_KFIFO(channel->fifo); + retval = kfifo_alloc(&channel->fifo, cfg->num_buffers, GFP_KERNEL); + if (retval) { + pr_info("failed to alloc channel kfifo"); + goto error_alloc_kfifo; + } + init_waitqueue_head(&channel->wq); + mutex_init(&channel->io_mutex); + spin_lock_irqsave(&ch_list_lock, cl_flags); + list_add_tail(&channel->list, &channel_list); + spin_unlock_irqrestore(&ch_list_lock, cl_flags); + channel->dev = device_create(aim_class, + NULL, + channel->devno, + NULL, + "%s", name); + + retval = IS_ERR(channel->dev); + if (retval) { + pr_info("failed to create new device node %s\n", name); + goto error_create_device; + } + kobject_uevent(&channel->dev->kobj, KOBJ_ADD); + return 0; + +error_create_device: + kfifo_free(&channel->fifo); + list_del(&channel->list); +error_alloc_kfifo: + cdev_del(&channel->cdev); + kfree(channel); +error_alloc_channel: + ida_simple_remove(&minor_id, current_minor); + return retval; +} + +struct most_aim cdev_aim = { + .name = "cdev", + .probe_channel = aim_probe, + .disconnect_channel = aim_disconnect_channel, + .rx_completion = aim_rx_completion, + .tx_completion = aim_tx_completion, +}; + +static int __init mod_init(void) +{ + pr_info("init()\n"); + + INIT_LIST_HEAD(&channel_list); + spin_lock_init(&ch_list_lock); + ida_init(&minor_id); + + if (alloc_chrdev_region(&aim_devno, 0, 50, "cdev") < 0) + return -EIO; + major = MAJOR(aim_devno); + + aim_class = class_create(THIS_MODULE, "most_cdev_aim"); + if (IS_ERR(aim_class)) { + pr_err("no udev support\n"); + goto free_cdev; + } + + if (most_register_aim(&cdev_aim)) + goto dest_class; + return 0; + +dest_class: + class_destroy(aim_class); +free_cdev: + unregister_chrdev_region(aim_devno, 1); + return -EIO; +} + +static void __exit mod_exit(void) +{ + struct aim_channel *channel, *tmp; + + pr_info("exit module\n"); + + most_deregister_aim(&cdev_aim); + + list_for_each_entry_safe(channel, tmp, &channel_list, list) { + device_destroy(aim_class, channel->devno); + cdev_del(&channel->cdev); + kfifo_free(&channel->fifo); + list_del(&channel->list); + ida_simple_remove(&minor_id, MINOR(channel->devno)); + kfree(channel); + } + class_destroy(aim_class); + unregister_chrdev_region(aim_devno, 1); + ida_destroy(&minor_id); +} + +module_init(mod_init); +module_exit(mod_exit); +MODULE_AUTHOR("Christian Gromm "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("character device AIM for mostcore"); -- cgit v1.3-6-gb490 From d4a8ce7f57fc6333e4e5a23980f5265e00ed44ef Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Fri, 24 Jul 2015 16:11:50 +0200 Subject: Staging: most: add MOST driver's aim-network module This patch adds the aim-network module of the MOST driver to the kernel's driver staging area. This module is part of the MOST driver and handles user space interaction by means of network devices. This patch is needed in order to have access to MOST Ethernet Packets (MEP) through a networking device. Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/Kconfig | 2 + drivers/staging/most/Makefile | 1 + drivers/staging/most/aim-network/Kconfig | 12 + drivers/staging/most/aim-network/Makefile | 4 + drivers/staging/most/aim-network/networking.c | 567 ++++++++++++++++++++++++++ drivers/staging/most/aim-network/networking.h | 23 ++ 6 files changed, 609 insertions(+) create mode 100644 drivers/staging/most/aim-network/Kconfig create mode 100644 drivers/staging/most/aim-network/Makefile create mode 100644 drivers/staging/most/aim-network/networking.c create mode 100644 drivers/staging/most/aim-network/networking.h (limited to 'drivers') diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig index e29bee569c77..34a0b7316fe8 100644 --- a/drivers/staging/most/Kconfig +++ b/drivers/staging/most/Kconfig @@ -15,4 +15,6 @@ source "drivers/staging/most/mostcore/Kconfig" source "drivers/staging/most/aim-cdev/Kconfig" +source "drivers/staging/most/aim-network/Kconfig" + endif diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile index b7b319bd61a1..61c1c965d622 100644 --- a/drivers/staging/most/Makefile +++ b/drivers/staging/most/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_MOSTCORE) += mostcore/ obj-$(CONFIG_AIM_CDEV) += aim-cdev/ +obj-$(CONFIG_AIM_NETWORK) += aim-network/ diff --git a/drivers/staging/most/aim-network/Kconfig b/drivers/staging/most/aim-network/Kconfig new file mode 100644 index 000000000000..507232a7f7ee --- /dev/null +++ b/drivers/staging/most/aim-network/Kconfig @@ -0,0 +1,12 @@ +# +# MOST Networking configuration +# + +config AIM_NETWORK + tristate "Networking AIM" + + ---help--- + Say Y here if you want to commumicate via a networking device. + + To compile this driver as a module, choose M here: the + module will be called aim_networking. diff --git a/drivers/staging/most/aim-network/Makefile b/drivers/staging/most/aim-network/Makefile new file mode 100644 index 000000000000..840c1dd94873 --- /dev/null +++ b/drivers/staging/most/aim-network/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_AIM_NETWORK) += aim_network.o + +aim_network-objs := networking.o +ccflags-y += -Idrivers/staging/most/mostcore/ diff --git a/drivers/staging/most/aim-network/networking.c b/drivers/staging/most/aim-network/networking.c new file mode 100644 index 000000000000..4639c49240f1 --- /dev/null +++ b/drivers/staging/most/aim-network/networking.c @@ -0,0 +1,567 @@ +/* + * Networking AIM - Networking Application Interface Module for MostCore + * + * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include "mostcore.h" +#include "networking.h" + + +#define MEP_HDR_LEN 8 +#define MDP_HDR_LEN 16 +#define MAMAC_DATA_LEN (1024 - MDP_HDR_LEN) + +#define PMHL 5 + +#define PMS_TELID_UNSEGM_MAMAC 0x0A +#define PMS_FIFONO_MDP 0x01 +#define PMS_FIFONO_MEP 0x04 +#define PMS_MSGTYPE_DATA 0x04 +#define PMS_DEF_PRIO 0 +#define MEP_DEF_RETRY 15 + +#define PMS_FIFONO_MASK 0x07 +#define PMS_FIFONO_SHIFT 3 +#define PMS_RETRY_SHIFT 4 +#define PMS_TELID_MASK 0x0F +#define PMS_TELID_SHIFT 4 + +#define HB(value) ((u8)((u16)(value) >> 8)) +#define LB(value) ((u8)(value)) + + + +#define EXTRACT_BIT_SET(bitset_name, value) \ + (((value) >> bitset_name##_SHIFT) & bitset_name##_MASK) + +#define PMS_IS_MEP(buf, len) \ + ((len) > MEP_HDR_LEN && \ + EXTRACT_BIT_SET(PMS_FIFONO, (buf)[3]) == PMS_FIFONO_MEP) + +#define PMS_IS_MAMAC(buf, len) \ + ((len) > MDP_HDR_LEN && \ + EXTRACT_BIT_SET(PMS_FIFONO, (buf)[3]) == PMS_FIFONO_MDP && \ + EXTRACT_BIT_SET(PMS_TELID, (buf)[14]) == PMS_TELID_UNSEGM_MAMAC) + +struct net_dev_channel { + bool linked; + int ch_id; +}; + +struct net_dev_context { + struct most_interface *iface; + bool channels_opened; + bool is_mamac; + unsigned char link_stat; + struct net_device *dev; + struct net_dev_channel rx; + struct net_dev_channel tx; + struct list_head list; +}; + +static struct list_head net_devices = LIST_HEAD_INIT(net_devices); +static struct spinlock list_lock; +static struct most_aim aim; + + +static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo) +{ + u8 *buff = mbo->virt_address; + const u8 broadcast[] = { 0x03, 0xFF }; + const u8 *dest_addr = skb->data + 4; + const u8 *eth_type = skb->data + 12; + unsigned int payload_len = skb->len - ETH_HLEN; + unsigned int mdp_len = payload_len + MDP_HDR_LEN; + + if (mbo->buffer_length < mdp_len) { + pr_err("drop: too small buffer! (%d for %d)\n", + mbo->buffer_length, mdp_len); + return -EINVAL; + } + + if (skb->len < ETH_HLEN) { + pr_err("drop: too small packet! (%d)\n", skb->len); + return -EINVAL; + } + + if (dest_addr[0] == 0xFF && dest_addr[1] == 0xFF) + dest_addr = broadcast; + + *buff++ = HB(mdp_len - 2); + *buff++ = LB(mdp_len - 2); + + *buff++ = PMHL; + *buff++ = (PMS_FIFONO_MDP << PMS_FIFONO_SHIFT) | PMS_MSGTYPE_DATA; + *buff++ = PMS_DEF_PRIO; + *buff++ = dest_addr[0]; + *buff++ = dest_addr[1]; + *buff++ = 0x00; + + *buff++ = HB(payload_len + 6); + *buff++ = LB(payload_len + 6); + + /* end of FPH here */ + + *buff++ = eth_type[0]; + *buff++ = eth_type[1]; + *buff++ = 0; + *buff++ = 0; + + *buff++ = PMS_TELID_UNSEGM_MAMAC << 4 | HB(payload_len); + *buff++ = LB(payload_len); + + memcpy(buff, skb->data + ETH_HLEN, payload_len); + mbo->buffer_length = mdp_len; + return 0; +} + +static int skb_to_mep(const struct sk_buff *skb, struct mbo *mbo) +{ + u8 *buff = mbo->virt_address; + unsigned int mep_len = skb->len + MEP_HDR_LEN; + + if (mbo->buffer_length < mep_len) { + pr_err("drop: too small buffer! (%d for %d)\n", + mbo->buffer_length, mep_len); + return -EINVAL; + } + + *buff++ = HB(mep_len - 2); + *buff++ = LB(mep_len - 2); + + *buff++ = PMHL; + *buff++ = (PMS_FIFONO_MEP << PMS_FIFONO_SHIFT) | PMS_MSGTYPE_DATA; + *buff++ = (MEP_DEF_RETRY << PMS_RETRY_SHIFT) | PMS_DEF_PRIO; + *buff++ = 0; + *buff++ = 0; + *buff++ = 0; + + memcpy(buff, skb->data, skb->len); + mbo->buffer_length = mep_len; + return 0; +} + +static int most_nd_set_mac_address(struct net_device *dev, void *p) +{ + struct net_dev_context *nd = dev->ml_priv; + int err = eth_mac_addr(dev, p); + + if (err) + return err; + + BUG_ON(nd->dev != dev); + + nd->is_mamac = + (dev->dev_addr[0] == 0 && dev->dev_addr[1] == 0 && + dev->dev_addr[2] == 0 && dev->dev_addr[3] == 0); + + /* + * Set default MTU for the given packet type. + * It is still possible to change MTU using ip tools afterwards. + */ + dev->mtu = nd->is_mamac ? MAMAC_DATA_LEN : ETH_DATA_LEN; + + return 0; +} + +static int most_nd_open(struct net_device *dev) +{ + struct net_dev_context *nd = dev->ml_priv; + + pr_info("open net device %s\n", dev->name); + + BUG_ON(nd->dev != dev); + + if (nd->channels_opened) + return -EFAULT; + + BUG_ON(!nd->tx.linked || !nd->rx.linked); + + if (most_start_channel(nd->iface, nd->rx.ch_id)) { + pr_err("most_start_channel() failed\n"); + return -EBUSY; + } + + if (most_start_channel(nd->iface, nd->tx.ch_id)) { + pr_err("most_start_channel() failed\n"); + most_stop_channel(nd->iface, nd->rx.ch_id); + return -EBUSY; + } + + nd->channels_opened = true; + + if (nd->is_mamac) { + nd->link_stat = 1; + netif_wake_queue(dev); + } else { + nd->iface->request_netinfo(nd->iface, nd->tx.ch_id); + } + + return 0; +} + +static int most_nd_stop(struct net_device *dev) +{ + struct net_dev_context *nd = dev->ml_priv; + + pr_info("stop net device %s\n", dev->name); + + BUG_ON(nd->dev != dev); + netif_stop_queue(dev); + + if (nd->channels_opened) { + most_stop_channel(nd->iface, nd->rx.ch_id); + most_stop_channel(nd->iface, nd->tx.ch_id); + nd->channels_opened = false; + } + + return 0; +} + +static netdev_tx_t most_nd_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct net_dev_context *nd = dev->ml_priv; + struct mbo *mbo; + int ret; + + BUG_ON(nd->dev != dev); + + mbo = most_get_mbo(nd->iface, nd->tx.ch_id); + + if (!mbo) { + netif_stop_queue(dev); + dev->stats.tx_fifo_errors++; + return NETDEV_TX_BUSY; + } + + if (nd->is_mamac) + ret = skb_to_mamac(skb, mbo); + else + ret = skb_to_mep(skb, mbo); + + if (ret) { + most_put_mbo(mbo); + dev->stats.tx_dropped++; + kfree_skb(skb); + return NETDEV_TX_OK; + } + + most_submit_mbo(mbo); + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + kfree_skb(skb); + return NETDEV_TX_OK; +} + +static const struct net_device_ops most_nd_ops = { + .ndo_open = most_nd_open, + .ndo_stop = most_nd_stop, + .ndo_start_xmit = most_nd_start_xmit, + .ndo_set_mac_address = most_nd_set_mac_address, +}; + +static void most_nd_setup(struct net_device *dev) +{ + pr_info("setup net device %s\n", dev->name); + ether_setup(dev); + dev->netdev_ops = &most_nd_ops; +} + +static void most_net_rm_netdev_safe(struct net_dev_context *nd) +{ + if (!nd->dev) + return; + + pr_info("remove net device %p\n", nd->dev); + + unregister_netdev(nd->dev); + free_netdev(nd->dev); + nd->dev = 0; +} + +static struct net_dev_context *get_net_dev_context( + struct most_interface *iface) +{ + struct net_dev_context *nd, *tmp; + + spin_lock(&list_lock); + list_for_each_entry_safe(nd, tmp, &net_devices, list) { + if (nd->iface == iface) { + spin_unlock(&list_lock); + return nd; + } + } + spin_unlock(&list_lock); + return 0; +} + +static int aim_probe_channel(struct most_interface *iface, int channel_idx, + struct most_channel_config *ccfg, + struct kobject *parent, char *name) +{ + struct net_dev_context *nd; + struct net_dev_channel *ch; + + if (!iface) + return -EINVAL; + + if (ccfg->data_type != MOST_CH_ASYNC) + return -EINVAL; + + nd = get_net_dev_context(iface); + + if (!nd) { + nd = kzalloc(sizeof(*nd), GFP_KERNEL); + if (!nd) + return -ENOMEM; + + nd->iface = iface; + + spin_lock(&list_lock); + list_add(&nd->list, &net_devices); + spin_unlock(&list_lock); + } + + ch = ccfg->direction == MOST_CH_TX ? &nd->tx : &nd->rx; + if (ch->linked) { + pr_err("only one channel per instance & direction allowed\n"); + return -EINVAL; + } + + if (nd->tx.linked || nd->rx.linked) { + struct net_device *dev = + alloc_netdev(0, "meth%d", NET_NAME_UNKNOWN, most_nd_setup); + + if (!dev) { + pr_err("no memory for net_device\n"); + return -ENOMEM; + } + + nd->dev = dev; + + dev->ml_priv = nd; + if (register_netdev(dev)) { + pr_err("registering net device failed\n"); + free_netdev(dev); + return -EINVAL; + } + } + + ch->ch_id = channel_idx; + ch->linked = true; + + return 0; +} + +static int aim_disconnect_channel(struct most_interface *iface, + int channel_idx) +{ + struct net_dev_context *nd; + struct net_dev_channel *ch; + + nd = get_net_dev_context(iface); + if (!nd) + return -EINVAL; + + if (nd->rx.linked && channel_idx == nd->rx.ch_id) + ch = &nd->rx; + else if (nd->tx.linked && channel_idx == nd->tx.ch_id) + ch = &nd->tx; + else + return -EINVAL; + + ch->linked = false; + + /* + * do not call most_stop_channel() here, because channels are + * going to be closed in ndo_stop() after unregister_netdev() + */ + most_net_rm_netdev_safe(nd); + + if (!nd->rx.linked && !nd->tx.linked) { + spin_lock(&list_lock); + list_del(&nd->list); + spin_unlock(&list_lock); + kfree(nd); + } + + return 0; +} + +static int aim_resume_tx_channel(struct most_interface *iface, + int channel_idx) +{ + struct net_dev_context *nd; + + nd = get_net_dev_context(iface); + if (!nd || !nd->channels_opened || nd->tx.ch_id != channel_idx) + return 0; + + if (!nd->dev) + return 0; + + netif_wake_queue(nd->dev); + return 0; +} + +static int aim_rx_data(struct mbo *mbo) +{ + const u32 zero = 0; + struct net_dev_context *nd; + char *buf = mbo->virt_address; + uint32_t len = mbo->processed_length; + struct sk_buff *skb; + struct net_device *dev; + + nd = get_net_dev_context(mbo->ifp); + if (!nd || !nd->channels_opened || nd->rx.ch_id != mbo->hdm_channel_id) + return -EIO; + + dev = nd->dev; + if (!dev) { + pr_err_once("drop packet: missing net_device\n"); + return -EIO; + } + + if (nd->is_mamac) { + if (!PMS_IS_MAMAC(buf, len)) + return -EIO; + + skb = dev_alloc_skb(len - MDP_HDR_LEN + 2 * ETH_ALEN + 2); + } else { + if (!PMS_IS_MEP(buf, len)) + return -EIO; + + skb = dev_alloc_skb(len - MEP_HDR_LEN); + } + + if (!skb) { + dev->stats.rx_dropped++; + pr_err_once("drop packet: no memory for skb\n"); + goto out; + } + + skb->dev = dev; + + if (nd->is_mamac) { + /* dest */ + memcpy(skb_put(skb, ETH_ALEN), dev->dev_addr, ETH_ALEN); + + /* src */ + memcpy(skb_put(skb, 4), &zero, 4); + memcpy(skb_put(skb, 2), buf + 5, 2); + + /* eth type */ + memcpy(skb_put(skb, 2), buf + 10, 2); + + buf += MDP_HDR_LEN; + len -= MDP_HDR_LEN; + } else { + buf += MEP_HDR_LEN; + len -= MEP_HDR_LEN; + } + + memcpy(skb_put(skb, len), buf, len); + skb->protocol = eth_type_trans(skb, dev); + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + netif_rx(skb); + +out: + most_put_mbo(mbo); + return 0; +} + +static int __init most_net_init(void) +{ + pr_info("most_net_init()\n"); + spin_lock_init(&list_lock); + aim.name = "networking"; + aim.probe_channel = aim_probe_channel; + aim.disconnect_channel = aim_disconnect_channel; + aim.tx_completion = aim_resume_tx_channel; + aim.rx_completion = aim_rx_data; + return most_register_aim(&aim); +} + +static void __exit most_net_exit(void) +{ + struct net_dev_context *nd, *tmp; + + spin_lock(&list_lock); + list_for_each_entry_safe(nd, tmp, &net_devices, list) { + list_del(&nd->list); + spin_unlock(&list_lock); + /* + * do not call most_stop_channel() here, because channels are + * going to be closed in ndo_stop() after unregister_netdev() + */ + most_net_rm_netdev_safe(nd); + kfree(nd); + spin_lock(&list_lock); + } + spin_unlock(&list_lock); + + most_deregister_aim(&aim); + pr_info("most_net_exit()\n"); +} + +/** + * most_deliver_netinfo - callback for HDM to be informed about HW's MAC + * @param iface - most interface instance + * @param link_stat - link status + * @param mac_addr - MAC address + */ +void most_deliver_netinfo(struct most_interface *iface, + unsigned char link_stat, unsigned char *mac_addr) +{ + struct net_dev_context *nd; + struct net_device *dev; + + pr_info("Received netinfo from %s\n", iface->description); + + nd = get_net_dev_context(iface); + if (!nd) + return; + + dev = nd->dev; + if (!dev) + return; + + if (mac_addr) + memcpy(dev->dev_addr, mac_addr, ETH_ALEN); + + if (nd->link_stat != link_stat) { + nd->link_stat = link_stat; + if (nd->link_stat) + netif_wake_queue(dev); + else + netif_stop_queue(dev); + } +} +EXPORT_SYMBOL(most_deliver_netinfo); + +module_init(most_net_init); +module_exit(most_net_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Andrey Shvetsov "); +MODULE_DESCRIPTION("Networking Application Interface Module for MostCore"); diff --git a/drivers/staging/most/aim-network/networking.h b/drivers/staging/most/aim-network/networking.h new file mode 100644 index 000000000000..1b8b434fabb0 --- /dev/null +++ b/drivers/staging/most/aim-network/networking.h @@ -0,0 +1,23 @@ +/* + * Networking AIM - Networking Application Interface Module for MostCore + * + * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ +#ifndef _NETWORKING_H_ +#define _NETWORKING_H_ + +#include "mostcore.h" + + +void most_deliver_netinfo(struct most_interface *iface, + unsigned char link_stat, unsigned char *mac_addr); + + +#endif -- cgit v1.3-6-gb490 From 54b4856fb3624609dd5d9ed013bfec7d67083622 Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Fri, 24 Jul 2015 16:11:51 +0200 Subject: Staging: most: add MOST driver's aim-sound module This patch adds the aim-sound module of the MOST driver to the kernel's driver staging area. This module is part of the MOST driver and handles user space interaction by means of ALSA devices. This patch is needed in order to have access to MOST synchronous data through ALSA devices. Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/Kconfig | 2 + drivers/staging/most/Makefile | 1 + drivers/staging/most/aim-sound/Kconfig | 12 + drivers/staging/most/aim-sound/Makefile | 4 + drivers/staging/most/aim-sound/sound.c | 758 ++++++++++++++++++++++++++++++++ 5 files changed, 777 insertions(+) create mode 100644 drivers/staging/most/aim-sound/Kconfig create mode 100644 drivers/staging/most/aim-sound/Makefile create mode 100644 drivers/staging/most/aim-sound/sound.c (limited to 'drivers') diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig index 34a0b7316fe8..050abbeed31d 100644 --- a/drivers/staging/most/Kconfig +++ b/drivers/staging/most/Kconfig @@ -17,4 +17,6 @@ source "drivers/staging/most/aim-cdev/Kconfig" source "drivers/staging/most/aim-network/Kconfig" +source "drivers/staging/most/aim-sound/Kconfig" + endif diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile index 61c1c965d622..c639bbd3b830 100644 --- a/drivers/staging/most/Makefile +++ b/drivers/staging/most/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_MOSTCORE) += mostcore/ obj-$(CONFIG_AIM_CDEV) += aim-cdev/ obj-$(CONFIG_AIM_NETWORK) += aim-network/ +obj-$(CONFIG_AIM_SOUND) += aim-sound/ diff --git a/drivers/staging/most/aim-sound/Kconfig b/drivers/staging/most/aim-sound/Kconfig new file mode 100644 index 000000000000..b9e499c77d00 --- /dev/null +++ b/drivers/staging/most/aim-sound/Kconfig @@ -0,0 +1,12 @@ +# +# MOST ALSA configuration +# + +config AIM_SOUND + tristate "ALSA AIM" + depends on SND + ---help--- + Say Y here if you want to commumicate via ALSA/sound devices. + + To compile this driver as a module, choose M here: the + module will be called aim_sound. diff --git a/drivers/staging/most/aim-sound/Makefile b/drivers/staging/most/aim-sound/Makefile new file mode 100644 index 000000000000..beba9586fd28 --- /dev/null +++ b/drivers/staging/most/aim-sound/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_AIM_SOUND) += aim_sound.o + +aim_sound-objs := sound.o +ccflags-y += -Idrivers/staging/most/mostcore/ diff --git a/drivers/staging/most/aim-sound/sound.c b/drivers/staging/most/aim-sound/sound.c new file mode 100644 index 000000000000..860302eebda7 --- /dev/null +++ b/drivers/staging/most/aim-sound/sound.c @@ -0,0 +1,758 @@ +/* + * sound.c - Audio Application Interface Module for Mostcore + * + * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "sound" + +static struct list_head dev_list; + +/** + * struct channel - private structure to keep channel specific data + * @substream: stores the substream structure + * @iface: interface for which the channel belongs to + * @cfg: channel configuration + * @card: registered sound card + * @list: list for private use + * @id: channel index + * @period_pos: current period position (ring buffer) + * @buffer_pos: current buffer position (ring buffer) + * @is_stream_running: identifies whether a stream is running or not + * @opened: set when the stream is opened + * @playback_task: playback thread + * @playback_waitq: waitq used by playback thread + */ +struct channel { + struct snd_pcm_substream *substream; + struct most_interface *iface; + struct most_channel_config *cfg; + struct snd_card *card; + struct list_head list; + int id; + unsigned int period_pos; + unsigned int buffer_pos; + bool is_stream_running; + + struct task_struct *playback_task; + wait_queue_head_t playback_waitq; + + void (*copy_fn)(void *alsa, void *most, unsigned int bytes); +}; + +#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ + SNDRV_PCM_INFO_MMAP_VALID | \ + SNDRV_PCM_INFO_BATCH | \ + SNDRV_PCM_INFO_INTERLEAVED | \ + SNDRV_PCM_INFO_BLOCK_TRANSFER) + +/** + * Initialization of struct snd_pcm_hardware + */ +static struct snd_pcm_hardware pcm_hardware_template = { + .info = MOST_PCM_INFO, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 8, +}; + +#define swap16(val) ( \ + (((u16)(val) << 8) & (u16)0xFF00) | \ + (((u16)(val) >> 8) & (u16)0x00FF)) + +#define swap32(val) ( \ + (((u32)(val) << 24) & (u32)0xFF000000) | \ + (((u32)(val) << 8) & (u32)0x00FF0000) | \ + (((u32)(val) >> 8) & (u32)0x0000FF00) | \ + (((u32)(val) >> 24) & (u32)0x000000FF)) + +static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) +{ + unsigned int i = 0; + + while (i < (bytes / 2)) { + dest[i] = swap16(source[i]); + i++; + } +} + +static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes) +{ + unsigned int i = 0; + + while (i < bytes - 2) { + dest[i] = source[i + 2]; + dest[i + 1] = source[i + 1]; + dest[i + 2] = source[i]; + i += 3; + } +} + +static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) +{ + unsigned int i = 0; + + while (i < bytes / 4) { + dest[i] = swap32(source[i]); + i++; + } +} + +static void alsa_to_most_memcpy(void *alsa, void *most, unsigned int bytes) +{ + memcpy(most, alsa, bytes); +} + +static void alsa_to_most_copy16(void *alsa, void *most, unsigned int bytes) +{ + swap_copy16(most, alsa, bytes); +} + +static void alsa_to_most_copy24(void *alsa, void *most, unsigned int bytes) +{ + swap_copy24(most, alsa, bytes); +} + +static void alsa_to_most_copy32(void *alsa, void *most, unsigned int bytes) +{ + swap_copy32(most, alsa, bytes); +} + +static void most_to_alsa_memcpy(void *alsa, void *most, unsigned int bytes) +{ + memcpy(alsa, most, bytes); +} + +static void most_to_alsa_copy16(void *alsa, void *most, unsigned int bytes) +{ + swap_copy16(alsa, most, bytes); +} + +static void most_to_alsa_copy24(void *alsa, void *most, unsigned int bytes) +{ + swap_copy24(alsa, most, bytes); +} + +static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes) +{ + swap_copy32(alsa, most, bytes); +} + +/** + * get_channel - get pointer to channel + * @iface: interface structure + * @channel_id: channel ID + * + * This traverses the channel list and returns the channel matching the + * ID and interface. + * + * Returns pointer to channel on success or NULL otherwise. + */ +static struct channel *get_channel(struct most_interface *iface, + int channel_id) +{ + struct channel *channel, *tmp; + + list_for_each_entry_safe(channel, tmp, &dev_list, list) { + if ((channel->iface == iface) && (channel->id == channel_id)) + return channel; + } + + return NULL; +} + +/** + * copy_data - implements data copying function + * @channel: channel + * @mbo: MBO from core + * + * Copy data from/to ring buffer to/from MBO and update the buffer position + */ +static bool copy_data(struct channel *channel, struct mbo *mbo) +{ + struct snd_pcm_runtime *const runtime = channel->substream->runtime; + unsigned int const frame_bytes = channel->cfg->subbuffer_size; + unsigned int const buffer_size = runtime->buffer_size; + unsigned int frames; + unsigned int fr0; + + if (channel->cfg->direction & MOST_CH_RX) + frames = mbo->processed_length / frame_bytes; + else + frames = mbo->buffer_length / frame_bytes; + fr0 = min(buffer_size - channel->buffer_pos, frames); + + channel->copy_fn(runtime->dma_area + channel->buffer_pos * frame_bytes, + mbo->virt_address, + fr0 * frame_bytes); + + if (frames > fr0) { + /* wrap around at end of ring buffer */ + channel->copy_fn(runtime->dma_area, + mbo->virt_address + fr0 * frame_bytes, + (frames - fr0) * frame_bytes); + } + + channel->buffer_pos += frames; + if (channel->buffer_pos >= buffer_size) + channel->buffer_pos -= buffer_size; + channel->period_pos += frames; + if (channel->period_pos >= runtime->period_size) { + channel->period_pos -= runtime->period_size; + return true; + } + + return false; +} + +/** + * playback_thread - function implements the playback thread + * @data: private data + * + * Thread which does the playback functionality in a loop. It waits for a free + * MBO from mostcore for a particular channel and copy the data from ring buffer + * to MBO. Submit the MBO back to mostcore, after copying the data. + * + * Returns 0 on success or error code otherwise. + */ +static int playback_thread(void *data) +{ + struct channel *const channel = data; + + pr_info("playback thread started\n"); + + while (!kthread_should_stop()) { + struct mbo *mbo = NULL; + bool period_elapsed = false; + int ret; + + wait_event_interruptible( + channel->playback_waitq, + kthread_should_stop() || + (mbo = most_get_mbo(channel->iface, channel->id))); + + if (!mbo) + continue; + + if (channel->is_stream_running) + period_elapsed = copy_data(channel, mbo); + else + memset(mbo->virt_address, 0, mbo->buffer_length); + + ret = most_submit_mbo(mbo); + if (ret) + channel->is_stream_running = false; + + if (period_elapsed) + snd_pcm_period_elapsed(channel->substream); + } + + return 0; +} + +/** + * pcm_open - implements open callback function for PCM middle layer + * @substream: pointer to ALSA PCM substream + * + * This is called when a PCM substream is opened. At least, the function should + * initialize the runtime->hw record. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_open(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct most_channel_config *cfg = channel->cfg; + + pr_info("pcm_open(), %s\n", substream->name); + + channel->substream = substream; + + if (cfg->direction == MOST_CH_TX) { + init_waitqueue_head(&channel->playback_waitq); + channel->playback_task = kthread_run(&playback_thread, channel, + "most_audio_playback"); + if (IS_ERR(channel->playback_task)) + return PTR_ERR(channel->playback_task); + } + + if (most_start_channel(channel->iface, channel->id)) { + pr_err("most_start_channel() failed!\n"); + if (cfg->direction == MOST_CH_TX) + kthread_stop(channel->playback_task); + return -EBUSY; + } + + runtime->hw = pcm_hardware_template; + runtime->hw.buffer_bytes_max = cfg->num_buffers * cfg->buffer_size; + runtime->hw.period_bytes_min = cfg->buffer_size; + runtime->hw.period_bytes_max = cfg->buffer_size; + runtime->hw.periods_min = 1; + runtime->hw.periods_max = cfg->num_buffers; + + return 0; +} + +/** + * pcm_close - implements close callback function for PCM middle layer + * @substream: sub-stream pointer + * + * Obviously, this is called when a PCM substream is closed. Any private + * instance for a PCM substream allocated in the open callback will be + * released here. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_close(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + + pr_info("pcm_close(), %s\n", substream->name); + + if (channel->cfg->direction == MOST_CH_TX) + kthread_stop(channel->playback_task); + most_stop_channel(channel->iface, channel->id); + + return 0; +} + +/** + * pcm_hw_params - implements hw_params callback function for PCM middle layer + * @substream: sub-stream pointer + * @hw_params: contains the hardware parameters set by the application + * + * This is called when the hardware parameters is set by the application, that + * is, once when the buffer size, the period size, the format, etc. are defined + * for the PCM substream. Many hardware setups should be done is this callback, + * including the allocation of buffers. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + pr_info("pcm_hw_params()\n"); + + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); +} + +/** + * pcm_hw_free - implements hw_free callback function for PCM middle layer + * @substream: substream pointer + * + * This is called to release the resources allocated via hw_params. + * This function will be always called before the close callback is called. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_hw_free(struct snd_pcm_substream *substream) +{ + pr_info("pcm_hw_free()\n"); + + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +/** + * pcm_prepare - implements prepare callback function for PCM middle layer + * @substream: substream pointer + * + * This callback is called when the PCM is "prepared". Format rate, sample rate, + * etc., can be set here. This callback can be called many times at each setup. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_prepare(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct most_channel_config *cfg = channel->cfg; + int width = snd_pcm_format_physical_width(runtime->format); + + channel->copy_fn = NULL; + + if (cfg->direction == MOST_CH_TX) { + if (snd_pcm_format_big_endian(runtime->format) || width == 8) + channel->copy_fn = alsa_to_most_memcpy; + else if (width == 16) + channel->copy_fn = alsa_to_most_copy16; + else if (width == 24) + channel->copy_fn = alsa_to_most_copy24; + else if (width == 32) + channel->copy_fn = alsa_to_most_copy32; + } else { + if (snd_pcm_format_big_endian(runtime->format) || width == 8) + channel->copy_fn = most_to_alsa_memcpy; + else if (width == 16) + channel->copy_fn = most_to_alsa_copy16; + else if (width == 24) + channel->copy_fn = most_to_alsa_copy24; + else if (width == 32) + channel->copy_fn = most_to_alsa_copy32; + } + + if (!channel->copy_fn) { + pr_err("unsupported format\n"); + return -EINVAL; + } + + channel->period_pos = 0; + channel->buffer_pos = 0; + + return 0; +} + +/** + * pcm_trigger - implements trigger callback function for PCM middle layer + * @substream: substream pointer + * @cmd: action to perform + * + * This is called when the PCM is started, stopped or paused. The action will be + * specified in the second argument, SNDRV_PCM_TRIGGER_XXX + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct channel *channel = substream->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + channel->is_stream_running = true; + return 0; + + case SNDRV_PCM_TRIGGER_STOP: + channel->is_stream_running = false; + return 0; + + default: + pr_info("pcm_trigger(), invalid\n"); + return -EINVAL; + } + return 0; +} + +/** + * pcm_pointer - implements pointer callback function for PCM middle layer + * @substream: substream pointer + * + * This callback is called when the PCM middle layer inquires the current + * hardware position on the buffer. The position must be returned in frames, + * ranging from 0 to buffer_size-1. + */ +static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + + return channel->buffer_pos; +} + +/** + * Initialization of struct snd_pcm_ops + */ +static struct snd_pcm_ops pcm_ops = { + .open = pcm_open, + .close = pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pcm_hw_params, + .hw_free = pcm_hw_free, + .prepare = pcm_prepare, + .trigger = pcm_trigger, + .pointer = pcm_pointer, + .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, +}; + + +int split_arg_list(char *buf, char **card_name, char **pcm_format) +{ + *card_name = strsep(&buf, "."); + if (!*card_name) + return -EIO; + *pcm_format = strsep(&buf, ".\n"); + if (!*pcm_format) + return -EIO; + return 0; +} + +int audio_set_pcm_format(char *pcm_format, struct most_channel_config *cfg) +{ + if (!strcmp(pcm_format, "1x8")) { + if (cfg->subbuffer_size != 1) + goto error; + pr_info("PCM format is 8-bit mono\n"); + pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S8; + } else if (!strcmp(pcm_format, "2x16")) { + if (cfg->subbuffer_size != 4) + goto error; + pr_info("PCM format is 16-bit stereo\n"); + pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S16_BE; + } else if (!strcmp(pcm_format, "2x24")) { + if (cfg->subbuffer_size != 6) + goto error; + pr_info("PCM format is 24-bit stereo\n"); + pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S24_3LE | + SNDRV_PCM_FMTBIT_S24_3BE; + } else if (!strcmp(pcm_format, "2x32")) { + if (cfg->subbuffer_size != 8) + goto error; + pr_info("PCM format is 32-bit stereo\n"); + pcm_hardware_template.formats = SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S32_BE; + } else { + pr_err("PCM format %s not supported\n", pcm_format); + return -EIO; + } + return 0; +error: + pr_err("Audio resolution doesn't fit subbuffer size\n"); + return -EINVAL; +} + +/** + * audio_probe_channel - probe function of the driver module + * @iface: pointer to interface instance + * @channel_id: channel index/ID + * @cfg: pointer to actual channel configuration + * @parent: pointer to kobject (needed for sysfs hook-up) + * @arg_list: string that provides the name of the device to be created in /dev + * plus the desired audio resolution + * + * Creates sound card, pcm device, sets pcm ops and registers sound card. + * + * Returns 0 on success or error code otherwise. + */ +static int audio_probe_channel(struct most_interface *iface, int channel_id, + struct most_channel_config *cfg, + struct kobject *parent, char *arg_list) +{ + struct channel *channel; + struct snd_card *card; + struct snd_pcm *pcm; + int playback_count = 0; + int capture_count = 0; + int ret; + int direction; + char *card_name; + char *pcm_format; + + pr_info("sound_probe_channel()\n"); + + if (!iface) + return -EINVAL; + + if (cfg->data_type != MOST_CH_SYNC) { + pr_err("Incompatible channel type\n"); + return -EINVAL; + } + + if (get_channel(iface, channel_id)) { + pr_err("channel (%s:%d) is already linked\n", + iface->description, channel_id); + return -EINVAL; + } + + if (cfg->direction == MOST_CH_TX) { + playback_count = 1; + direction = SNDRV_PCM_STREAM_PLAYBACK; + } else { + capture_count = 1; + direction = SNDRV_PCM_STREAM_CAPTURE; + } + + ret = split_arg_list(arg_list, &card_name, &pcm_format); + if (ret < 0) { + pr_info("PCM format missing\n"); + return ret; + } + if (audio_set_pcm_format(pcm_format, cfg)) + return ret; + + ret = snd_card_new(NULL, -1, card_name, THIS_MODULE, + sizeof(*channel), &card); + if (ret < 0) + return ret; + + channel = card->private_data; + channel->card = card; + channel->cfg = cfg; + channel->iface = iface; + channel->id = channel_id; + + snprintf(card->driver, sizeof(card->driver), "%s", DRIVER_NAME); + snprintf(card->shortname, sizeof(card->shortname), "MOST:%d", + card->number); + snprintf(card->longname, sizeof(card->longname), "%s at %s, ch %d", + card->shortname, iface->description, channel_id); + + ret = snd_pcm_new(card, card_name, 0, playback_count, + capture_count, &pcm); + if (ret < 0) + goto err_free_card; + + pcm->private_data = channel; + + snd_pcm_set_ops(pcm, direction, &pcm_ops); + + ret = snd_card_register(card); + if (ret < 0) + goto err_free_card; + + list_add_tail(&channel->list, &dev_list); + + return 0; + +err_free_card: + snd_card_free(card); + return ret; +} + +/** + * audio_disconnect_channel - function to disconnect a channel + * @iface: pointer to interface instance + * @channel_id: channel index + * + * This frees allocated memory and removes the sound card from ALSA + * + * Returns 0 on success or error code otherwise. + */ +static int audio_disconnect_channel(struct most_interface *iface, + int channel_id) +{ + struct channel *channel; + + pr_info("sound_disconnect_channel()\n"); + + channel = get_channel(iface, channel_id); + if (!channel) { + pr_err("sound_disconnect_channel(), invalid channel %d\n", + channel_id); + return -EINVAL; + } + + list_del(&channel->list); + snd_card_free(channel->card); + + return 0; +} + +/** + * audio_rx_completion - completion handler for rx channels + * @mbo: pointer to buffer object that has completed + * + * This searches for the channel this MBO belongs to and copy the data from MBO + * to ring buffer + * + * Returns 0 on success or error code otherwise. + */ +static int audio_rx_completion(struct mbo *mbo) +{ + struct channel *channel = get_channel(mbo->ifp, mbo->hdm_channel_id); + bool period_elapsed = false; + + if (!channel) { + pr_err("sound_rx_completion(), invalid channel %d\n", + mbo->hdm_channel_id); + return -EINVAL; + } + + if (channel->is_stream_running) + period_elapsed = copy_data(channel, mbo); + + most_put_mbo(mbo); + + if (period_elapsed) + snd_pcm_period_elapsed(channel->substream); + + return 0; +} + +/** + * audio_tx_completion - completion handler for tx channels + * @iface: pointer to interface instance + * @channel_id: channel index/ID + * + * This searches the channel that belongs to this combination of interface + * pointer and channel ID and wakes a process sitting in the wait queue of + * this channel. + * + * Returns 0 on success or error code otherwise. + */ +static int audio_tx_completion(struct most_interface *iface, int channel_id) +{ + struct channel *channel = get_channel(iface, channel_id); + + if (!channel) { + pr_err("sound_tx_completion(), invalid channel %d\n", + channel_id); + return -EINVAL; + } + + wake_up_interruptible(&channel->playback_waitq); + + return 0; +} + +/** + * Initialization of the struct most_aim + */ +static struct most_aim audio_aim = { + .name = DRIVER_NAME, + .probe_channel = audio_probe_channel, + .disconnect_channel = audio_disconnect_channel, + .rx_completion = audio_rx_completion, + .tx_completion = audio_tx_completion, +}; + +static int __init audio_init(void) +{ + pr_info("init()\n"); + + INIT_LIST_HEAD(&dev_list); + + return most_register_aim(&audio_aim); +} + +static void __exit audio_exit(void) +{ + struct channel *channel, *tmp; + + pr_info("exit()\n"); + + list_for_each_entry_safe(channel, tmp, &dev_list, list) { + list_del(&channel->list); + snd_card_free(channel->card); + } + + most_deregister_aim(&audio_aim); +} + +module_init(audio_init); +module_exit(audio_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Gromm "); +MODULE_DESCRIPTION("Audio Application Interface Module for MostCore"); -- cgit v1.3-6-gb490 From 3d31c0cb6c127b1d943b610065a05decf821998c Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Fri, 24 Jul 2015 16:11:52 +0200 Subject: Staging: most: add MOST driver's aim-v4l2 module This patch adds the aim-v4l2 module of the MOST driver to the kernel's driver staging area. This module is part of the MOST driver and handles user space interaction by means of V4L2. This patch is needed in order to have access to MOST isochronous AVP data through V4L2 devices. Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/Kconfig | 2 + drivers/staging/most/Makefile | 1 + drivers/staging/most/aim-v4l2/Kconfig | 12 + drivers/staging/most/aim-v4l2/Makefile | 6 + drivers/staging/most/aim-v4l2/video.c | 634 +++++++++++++++++++++++++++++++++ 5 files changed, 655 insertions(+) create mode 100644 drivers/staging/most/aim-v4l2/Kconfig create mode 100644 drivers/staging/most/aim-v4l2/Makefile create mode 100644 drivers/staging/most/aim-v4l2/video.c (limited to 'drivers') diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig index 050abbeed31d..458291841588 100644 --- a/drivers/staging/most/Kconfig +++ b/drivers/staging/most/Kconfig @@ -19,4 +19,6 @@ source "drivers/staging/most/aim-network/Kconfig" source "drivers/staging/most/aim-sound/Kconfig" +source "drivers/staging/most/aim-v4l2/Kconfig" + endif diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile index c639bbd3b830..6e319c499d19 100644 --- a/drivers/staging/most/Makefile +++ b/drivers/staging/most/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_MOSTCORE) += mostcore/ obj-$(CONFIG_AIM_CDEV) += aim-cdev/ obj-$(CONFIG_AIM_NETWORK) += aim-network/ obj-$(CONFIG_AIM_SOUND) += aim-sound/ +obj-$(CONFIG_AIM_V4L2) += aim-v4l2/ diff --git a/drivers/staging/most/aim-v4l2/Kconfig b/drivers/staging/most/aim-v4l2/Kconfig new file mode 100644 index 000000000000..d70eaaf0936c --- /dev/null +++ b/drivers/staging/most/aim-v4l2/Kconfig @@ -0,0 +1,12 @@ +# +# MOST V4L2 configuration +# + +config AIM_V4L2 + tristate "V4L2 AIM" + depends on VIDEO_V4L2 + ---help--- + Say Y here if you want to commumicate via Video 4 Linux. + + To compile this driver as a module, choose M here: the + module will be called aim_v4l2. \ No newline at end of file diff --git a/drivers/staging/most/aim-v4l2/Makefile b/drivers/staging/most/aim-v4l2/Makefile new file mode 100644 index 000000000000..28aa948d6609 --- /dev/null +++ b/drivers/staging/most/aim-v4l2/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_AIM_V4L2) += aim_v4l2.o + +aim_v4l2-objs := video.o + +ccflags-y += -Idrivers/staging/most/mostcore/ +ccflags-y += -Idrivers/media/video diff --git a/drivers/staging/most/aim-v4l2/video.c b/drivers/staging/most/aim-v4l2/video.c new file mode 100644 index 000000000000..a977b883ee36 --- /dev/null +++ b/drivers/staging/most/aim-v4l2/video.c @@ -0,0 +1,634 @@ +/* + * V4L2 AIM - V4L2 Application Interface Module for MostCore + * + * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mostcore.h" + + +#define V4L2_AIM_MAX_INPUT 1 + + +struct most_video_dev { + struct most_interface *iface; + int ch_idx; + struct list_head list; + bool mute; + + struct list_head pending_mbos; + spinlock_t list_lock; + + struct v4l2_device v4l2_dev; + atomic_t access_ref; + struct video_device *vdev; + unsigned int ctrl_input; + + struct mutex lock; + + wait_queue_head_t wait_data; +}; + +struct aim_fh { + /* must be the first field of this struct! */ + struct v4l2_fh fh; + struct most_video_dev *mdev; + u32 offs; +}; + + +static struct list_head video_devices = LIST_HEAD_INIT(video_devices); +static struct spinlock list_lock; +static struct most_aim aim_info; + + +static inline bool data_ready(struct most_video_dev *mdev) +{ + return !list_empty(&mdev->pending_mbos); +} + +static inline struct mbo *get_top_mbo(struct most_video_dev *mdev) +{ + return list_first_entry(&mdev->pending_mbos, struct mbo, list); +} + + +static int aim_vdev_open(struct file *filp) +{ + int ret; + struct video_device *vdev = video_devdata(filp); + struct most_video_dev *mdev = video_drvdata(filp); + struct aim_fh *fh; + + pr_info("aim_vdev_open()\n"); + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + break; + default: + return -EINVAL; + } + + fh = kzalloc(sizeof(struct aim_fh), GFP_KERNEL); + if (!fh) + return -ENOMEM; + + if (!atomic_inc_and_test(&mdev->access_ref)) { + pr_err("too many clients\n"); + ret = -EBUSY; + goto err_dec; + } + + fh->mdev = mdev; + v4l2_fh_init(&fh->fh, vdev); + filp->private_data = fh; + + v4l2_fh_add(&fh->fh); + + ret = most_start_channel(mdev->iface, mdev->ch_idx); + if (ret) { + pr_err("most_start_channel() failed\n"); + goto err_rm; + } + + return 0; + +err_rm: + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); + +err_dec: + atomic_dec(&mdev->access_ref); + kfree(fh); + return ret; +} + +static int aim_vdev_close(struct file *filp) +{ + struct aim_fh *fh = filp->private_data; + struct most_video_dev *mdev = fh->mdev; + struct mbo *mbo, *tmp; + + pr_info("aim_vdev_close()\n"); + + /* + * We need to put MBOs back before we call most_stop_channel() + * to deallocate MBOs. + * From the other hand mostcore still calling rx_completion() + * to deliver MBOs until most_stop_channel() is called. + * Use mute to work around this issue. + * This must be implemented in core. + */ + + spin_lock(&mdev->list_lock); + mdev->mute = true; + list_for_each_entry_safe(mbo, tmp, &mdev->pending_mbos, list) { + list_del(&mbo->list); + spin_unlock(&mdev->list_lock); + most_put_mbo(mbo); + spin_lock(&mdev->list_lock); + } + spin_unlock(&mdev->list_lock); + most_stop_channel(mdev->iface, mdev->ch_idx); + mdev->mute = false; + + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); + + atomic_dec(&mdev->access_ref); + kfree(fh); + return 0; +} + +static ssize_t aim_vdev_read(struct file *filp, char __user *buf, + size_t count, loff_t *pos) +{ + struct aim_fh *fh = filp->private_data; + struct most_video_dev *mdev = fh->mdev; + int ret = 0; + + if (*pos) + return -ESPIPE; + + if (!mdev) + return -ENODEV; + + /* wait for the first buffer */ + if (!(filp->f_flags & O_NONBLOCK)) { + if (wait_event_interruptible(mdev->wait_data, data_ready(mdev))) + return -ERESTARTSYS; + } + + if (!data_ready(mdev)) + return -EAGAIN; + + while (count > 0 && data_ready(mdev)) { + struct mbo *const mbo = get_top_mbo(mdev); + int const rem = mbo->processed_length - fh->offs; + int const cnt = rem < count ? rem : count; + + if (copy_to_user(buf, mbo->virt_address + fh->offs, cnt)) { + pr_err("read: copy_to_user failed\n"); + if (!ret) + ret = -EFAULT; + return ret; + } + + fh->offs += cnt; + count -= cnt; + buf += cnt; + ret += cnt; + + if (cnt >= rem) { + fh->offs = 0; + spin_lock(&mdev->list_lock); + list_del(&mbo->list); + spin_unlock(&mdev->list_lock); + most_put_mbo(mbo); + } + } + return ret; +} + +static unsigned int aim_vdev_poll(struct file *filp, poll_table *wait) +{ + struct aim_fh *fh = filp->private_data; + struct most_video_dev *mdev = fh->mdev; + unsigned int mask = 0; + + /* only wait if no data is available */ + if (!data_ready(mdev)) + poll_wait(filp, &mdev->wait_data, wait); + if (data_ready(mdev)) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + +static void aim_set_format_struct(struct v4l2_format *f) +{ + f->fmt.pix.width = 8; + f->fmt.pix.height = 8; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = 188 * 2; + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.priv = 0; +} + +static int aim_set_format(struct most_video_dev *mdev, unsigned int cmd, + struct v4l2_format *format) +{ +#if 0 + u32 const pixfmt = format->fmt.pix.pixelformat; + const char *fmt; + + if (pixfmt != V4L2_PIX_FMT_MPEG) { + if (cmd == VIDIOC_TRY_FMT) + fmt = KERN_ERR "try %c%c%c%c failed\n"; + else + fmt = KERN_ERR "set %c%c%c%c failed\n"; + } else { + if (cmd == VIDIOC_TRY_FMT) + fmt = KERN_ERR "try %c%c%c%c\n"; + else + fmt = KERN_ERR "set %c%c%c%c\n"; + } + printk(fmt, + (pixfmt) & 255, + (pixfmt >> 8) & 255, + (pixfmt >> 16) & 255, + (pixfmt >> 24) & 255); +#endif + + if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG) + return -EINVAL; + + if (cmd == VIDIOC_TRY_FMT) + return 0; + + aim_set_format_struct(format); + + return 0; +} + + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct aim_fh *fh = priv; + struct most_video_dev *mdev = fh->mdev; + + pr_info("vidioc_querycap()\n"); + + strlcpy(cap->driver, "v4l2_most_aim", sizeof(cap->driver)); + strlcpy(cap->card, "my_card", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "%s", mdev->iface->description); + + cap->capabilities = + V4L2_CAP_READWRITE | + V4L2_CAP_TUNER | + V4L2_CAP_VIDEO_CAPTURE; + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + pr_info("vidioc_enum_fmt_vid_cap() %d\n", f->index); + + if (f->index) + return -EINVAL; + + strcpy(f->description, "MPEG"); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + f->flags = V4L2_FMT_FLAG_COMPRESSED; + f->pixelformat = V4L2_PIX_FMT_MPEG; + + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + pr_info("vidioc_g_fmt_vid_cap()\n"); + + aim_set_format_struct(f); + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct aim_fh *fh = priv; + struct most_video_dev *mdev = fh->mdev; + + return aim_set_format(mdev, VIDIOC_TRY_FMT, f); +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct aim_fh *fh = priv; + struct most_video_dev *mdev = fh->mdev; + + return aim_set_format(mdev, VIDIOC_S_FMT, f); +} + +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) +{ + pr_info("vidioc_g_std()\n"); + + *norm = V4L2_STD_UNKNOWN; + return 0; +} + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + struct aim_fh *fh = priv; + struct most_video_dev *mdev = fh->mdev; + + if (input->index >= V4L2_AIM_MAX_INPUT) + return -EINVAL; + + strcpy(input->name, "MOST Video"); + input->type |= V4L2_INPUT_TYPE_CAMERA; + input->audioset = 0; + + input->std = mdev->vdev->tvnorms; + + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct aim_fh *fh = priv; + struct most_video_dev *mdev = fh->mdev; + *i = mdev->ctrl_input; + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int index) +{ + struct aim_fh *fh = priv; + struct most_video_dev *mdev = fh->mdev; + + pr_info("vidioc_s_input(%d)\n", index); + + if (index >= V4L2_AIM_MAX_INPUT) + return -EINVAL; + mdev->ctrl_input = index; + return 0; +} + +static struct v4l2_file_operations aim_fops = { + .owner = THIS_MODULE, + .open = aim_vdev_open, + .release = aim_vdev_close, + .read = aim_vdev_read, + .poll = aim_vdev_poll, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_g_std = vidioc_g_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, +}; + +static const struct video_device aim_videodev_template = { + .fops = &aim_fops, + .release = video_device_release, + .ioctl_ops = &video_ioctl_ops, + .tvnorms = V4L2_STD_UNKNOWN, +}; + +/**************************************************************************/ + +static struct most_video_dev *get_aim_dev( + struct most_interface *iface, int channel_idx) +{ + struct most_video_dev *mdev, *tmp; + + spin_lock(&list_lock); + list_for_each_entry_safe(mdev, tmp, &video_devices, list) { + if (mdev->iface == iface && mdev->ch_idx == channel_idx) { + spin_unlock(&list_lock); + return mdev; + } + } + spin_unlock(&list_lock); + return 0; +} + +static int aim_rx_data(struct mbo *mbo) +{ + struct most_video_dev *mdev = + get_aim_dev(mbo->ifp, mbo->hdm_channel_id); + + if (!mdev) + return -EIO; + + spin_lock(&mdev->list_lock); + if (unlikely(mdev->mute)) { + spin_unlock(&mdev->list_lock); + return -EIO; + } + + list_add_tail(&mbo->list, &mdev->pending_mbos); + spin_unlock(&mdev->list_lock); + wake_up_interruptible(&mdev->wait_data); + return 0; +} + +static int aim_register_videodev(struct most_video_dev *mdev) +{ + int retval = -ENOMEM; + int ret; + + pr_info("aim_register_videodev()\n"); + + init_waitqueue_head(&mdev->wait_data); + + /* allocate and fill v4l2 video struct */ + mdev->vdev = video_device_alloc(); + if (!mdev->vdev) + return -ENOMEM; + + /* Fill the video capture device struct */ + *mdev->vdev = aim_videodev_template; + mdev->vdev->v4l2_dev = &mdev->v4l2_dev; + mdev->vdev->lock = &mdev->lock; + strcpy(mdev->vdev->name, "most v4l2 aim video"); + + /* Register the v4l2 device */ + video_set_drvdata(mdev->vdev, mdev); + retval = video_register_device(mdev->vdev, VFL_TYPE_GRABBER, -1); + if (retval != 0) { + pr_err("video_register_device failed (%d)\n", retval); + ret = -ENODEV; + goto err_vbi_dev; + } + + return 0; + +err_vbi_dev: + video_device_release(mdev->vdev); + return ret; +} + +static void aim_unregister_videodev(struct most_video_dev *mdev) +{ + pr_info("aim_unregister_videodev()\n"); + + video_unregister_device(mdev->vdev); +} + + +static void aim_v4l2_dev_release(struct v4l2_device *v4l2_dev) +{ + struct most_video_dev *mdev = + container_of(v4l2_dev, struct most_video_dev, v4l2_dev); + + v4l2_device_unregister(v4l2_dev); + kfree(mdev); +} + +static int aim_probe_channel(struct most_interface *iface, int channel_idx, + struct most_channel_config *ccfg, + struct kobject *parent, char *name) +{ + int ret; + struct most_video_dev *mdev = get_aim_dev(iface, channel_idx); + + pr_info("aim_probe_channel()\n"); + + if (mdev) { + pr_err("channel already linked\n"); + return -EEXIST; + } + + if (ccfg->direction != MOST_CH_RX) { + pr_err("wrong direction, expect rx\n"); + return -EINVAL; + } + + if (ccfg->data_type != MOST_CH_SYNC && + ccfg->data_type != MOST_CH_ISOC_AVP) { + pr_err("wrong channel type, expect sync or isoc_avp\n"); + return -EINVAL; + } + + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + if (!mdev) + return -ENOMEM; + + mutex_init(&mdev->lock); + atomic_set(&mdev->access_ref, -1); + spin_lock_init(&mdev->list_lock); + INIT_LIST_HEAD(&mdev->pending_mbos); + mdev->iface = iface; + mdev->ch_idx = channel_idx; + mdev->v4l2_dev.release = aim_v4l2_dev_release; + + /* Create the v4l2_device */ + strlcpy(mdev->v4l2_dev.name, "most_video_device", + sizeof(mdev->v4l2_dev.name)); + ret = v4l2_device_register(NULL, &mdev->v4l2_dev); + if (ret) { + pr_err("v4l2_device_register() failed\n"); + kfree(mdev); + return ret; + } + + ret = aim_register_videodev(mdev); + if (ret) + goto err_unreg; + + spin_lock(&list_lock); + list_add(&mdev->list, &video_devices); + spin_unlock(&list_lock); + return 0; + +err_unreg: + v4l2_device_disconnect(&mdev->v4l2_dev); + v4l2_device_put(&mdev->v4l2_dev); + return ret; +} + +static int aim_disconnect_channel(struct most_interface *iface, + int channel_idx) +{ + struct most_video_dev *mdev = get_aim_dev(iface, channel_idx); + + pr_info("aim_disconnect_channel()\n"); + + if (!mdev) { + pr_err("no such channel is linked\n"); + return -ENOENT; + } + + spin_lock(&list_lock); + list_del(&mdev->list); + spin_unlock(&list_lock); + + aim_unregister_videodev(mdev); + v4l2_device_disconnect(&mdev->v4l2_dev); + v4l2_device_put(&mdev->v4l2_dev); + return 0; +} + +static int __init aim_init(void) +{ + spin_lock_init(&list_lock); + + aim_info.name = "v4l"; + aim_info.probe_channel = aim_probe_channel; + aim_info.disconnect_channel = aim_disconnect_channel; + aim_info.rx_completion = aim_rx_data; + return most_register_aim(&aim_info); +} + +static void __exit aim_exit(void) +{ + struct most_video_dev *mdev, *tmp; + + /* + * As the mostcore currently doesn't call disconnect_channel() + * for linked channels while we call most_deregister_aim() + * we simulate this call here. + * This must be fixed in core. + */ + spin_lock(&list_lock); + list_for_each_entry_safe(mdev, tmp, &video_devices, list) { + list_del(&mdev->list); + spin_unlock(&list_lock); + + aim_unregister_videodev(mdev); + v4l2_device_disconnect(&mdev->v4l2_dev); + v4l2_device_put(&mdev->v4l2_dev); + } + spin_unlock(&list_lock); + + most_deregister_aim(&aim_info); + BUG_ON(!list_empty(&video_devices)); +} + +module_init(aim_init); +module_exit(aim_exit); + +MODULE_DESCRIPTION("V4L2 Application Interface Module for MostCore"); +MODULE_AUTHOR("Andrey Shvetsov "); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From ba3d7ddfb5c6a2529155ac24d7964adba8777419 Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Fri, 24 Jul 2015 16:11:53 +0200 Subject: Staging: most: add MOST driver's hdm-dim2 module This patch adds the hdm-dim2 module of the MOST driver to the kernel's driver staging area. This module is part of the MOST driver and handles the MediaLB interface of the MOST network interface controller. This patch is needed in order to use the MediaLB peripheral interface of the network interface controller. Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/Kconfig | 2 + drivers/staging/most/Makefile | 1 + drivers/staging/most/hdm-dim2/Kconfig | 15 + drivers/staging/most/hdm-dim2/Makefile | 5 + drivers/staging/most/hdm-dim2/dim2_errors.h | 67 ++ drivers/staging/most/hdm-dim2/dim2_hal.c | 919 ++++++++++++++++++++++++++ drivers/staging/most/hdm-dim2/dim2_hal.h | 124 ++++ drivers/staging/most/hdm-dim2/dim2_hdm.c | 964 ++++++++++++++++++++++++++++ drivers/staging/most/hdm-dim2/dim2_hdm.h | 26 + drivers/staging/most/hdm-dim2/dim2_reg.h | 176 +++++ drivers/staging/most/hdm-dim2/dim2_sysfs.c | 116 ++++ drivers/staging/most/hdm-dim2/dim2_sysfs.h | 39 ++ 12 files changed, 2454 insertions(+) create mode 100644 drivers/staging/most/hdm-dim2/Kconfig create mode 100644 drivers/staging/most/hdm-dim2/Makefile create mode 100644 drivers/staging/most/hdm-dim2/dim2_errors.h create mode 100644 drivers/staging/most/hdm-dim2/dim2_hal.c create mode 100644 drivers/staging/most/hdm-dim2/dim2_hal.h create mode 100644 drivers/staging/most/hdm-dim2/dim2_hdm.c create mode 100644 drivers/staging/most/hdm-dim2/dim2_hdm.h create mode 100644 drivers/staging/most/hdm-dim2/dim2_reg.h create mode 100644 drivers/staging/most/hdm-dim2/dim2_sysfs.c create mode 100644 drivers/staging/most/hdm-dim2/dim2_sysfs.h (limited to 'drivers') diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig index 458291841588..659c40261720 100644 --- a/drivers/staging/most/Kconfig +++ b/drivers/staging/most/Kconfig @@ -21,4 +21,6 @@ source "drivers/staging/most/aim-sound/Kconfig" source "drivers/staging/most/aim-v4l2/Kconfig" +source "drivers/staging/most/hdm-dim2/Kconfig" + endif diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile index 6e319c499d19..7c68b3b50b10 100644 --- a/drivers/staging/most/Makefile +++ b/drivers/staging/most/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_AIM_CDEV) += aim-cdev/ obj-$(CONFIG_AIM_NETWORK) += aim-network/ obj-$(CONFIG_AIM_SOUND) += aim-sound/ obj-$(CONFIG_AIM_V4L2) += aim-v4l2/ +obj-$(CONFIG_HDM_DIM2) += hdm-dim2/ diff --git a/drivers/staging/most/hdm-dim2/Kconfig b/drivers/staging/most/hdm-dim2/Kconfig new file mode 100644 index 000000000000..4abeb545955e --- /dev/null +++ b/drivers/staging/most/hdm-dim2/Kconfig @@ -0,0 +1,15 @@ +# +# MediaLB configuration +# + +config HDM_DIM2 + tristate "DIM2 HDM" + + ---help--- + Say Y here if you want to connect via MediaLB to network tranceiver. + This device driver is platform dependent and needs an addtional + platform driver to be installed. For more information contact + maintainer of this driver. + + To compile this driver as a module, choose M here: the + module will be called hdm_dim2. diff --git a/drivers/staging/most/hdm-dim2/Makefile b/drivers/staging/most/hdm-dim2/Makefile new file mode 100644 index 000000000000..6bbee879a8ea --- /dev/null +++ b/drivers/staging/most/hdm-dim2/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_HDM_DIM2) += hdm_dim2.o + +hdm_dim2-objs := dim2_hdm.o dim2_hal.o dim2_sysfs.o +ccflags-y += -Idrivers/staging/most/mostcore/ +ccflags-y += -Idrivers/staging/most/aim-network/ diff --git a/drivers/staging/most/hdm-dim2/dim2_errors.h b/drivers/staging/most/hdm-dim2/dim2_errors.h new file mode 100644 index 000000000000..314f7de2be73 --- /dev/null +++ b/drivers/staging/most/hdm-dim2/dim2_errors.h @@ -0,0 +1,67 @@ +/* + * dim2_errors.h - Definitions of errors for DIM2 HAL API + * (MediaLB, Device Interface Macro IP, OS62420) + * + * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#ifndef _MOST_DIM_ERRORS_H +#define _MOST_DIM_ERRORS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * MOST DIM errors. + */ +enum dim_errors_t { + /** Not an error */ + DIM_NO_ERROR = 0, + + /** Bad base address for DIM2 IP */ + DIM_INIT_ERR_DIM_ADDR = 0x10, + + /**< Bad MediaLB clock */ + DIM_INIT_ERR_MLB_CLOCK, + + /** Bad channel address */ + DIM_INIT_ERR_CHANNEL_ADDRESS, + + /** Out of DBR memory */ + DIM_INIT_ERR_OUT_OF_MEMORY, + + /** DIM API is called while DIM is not initialized successfully */ + DIM_ERR_DRIVER_NOT_INITIALIZED = 0x20, + + /** + * Configuration does not respect hardware limitations + * for isochronous or synchronous channels + */ + DIM_ERR_BAD_CONFIG, + + /** + * Buffer size does not respect hardware limitations + * for isochronous or synchronous channels + */ + DIM_ERR_BAD_BUFFER_SIZE, + + DIM_ERR_UNDERFLOW, + + DIM_ERR_OVERFLOW, +}; + + +#ifdef __cplusplus +} +#endif + +#endif /* _MOST_DIM_ERRORS_H */ diff --git a/drivers/staging/most/hdm-dim2/dim2_hal.c b/drivers/staging/most/hdm-dim2/dim2_hal.c new file mode 100644 index 000000000000..01b748944ee4 --- /dev/null +++ b/drivers/staging/most/hdm-dim2/dim2_hal.c @@ -0,0 +1,919 @@ +/* + * dim2_hal.c - DIM2 HAL implementation + * (MediaLB, Device Interface Macro IP, OS62420) + * + * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +/* Author: Andrey Shvetsov */ + +#include "dim2_hal.h" +#include "dim2_errors.h" +#include "dim2_reg.h" +#include + + +/* + * The number of frames per sub-buffer for synchronous channels. + * Allowed values: 1, 2, 4, 8, 16, 32, 64. + */ +#define FRAMES_PER_SUBBUFF 16 + +/* + * Size factor for synchronous DBR buffer. + * Minimal value is 4*FRAMES_PER_SUBBUFF. + */ +#define SYNC_DBR_FACTOR (4u * (u16)FRAMES_PER_SUBBUFF) + +/* + * Size factor for isochronous DBR buffer. + * Minimal value is 3. + */ +#define ISOC_DBR_FACTOR 3u + +/* + * Number of 32-bit units for DBR map. + * + * 1: block size is 512, max allocation is 16K + * 2: block size is 256, max allocation is 8K + * 4: block size is 128, max allocation is 4K + * 8: block size is 64, max allocation is 2K + * + * Min allocated space is block size. + * Max possible allocated space is 32 blocks. + */ +#define DBR_MAP_SIZE 2 + + +/* -------------------------------------------------------------------------- */ +/* not configurable area */ + +#define CDT 0x00 +#define ADT 0x40 +#define MLB_CAT 0x80 +#define AHB_CAT 0x88 + +#define DBR_SIZE (16*1024) /* specified by IP */ +#define DBR_BLOCK_SIZE (DBR_SIZE / 32 / DBR_MAP_SIZE) + + +/* -------------------------------------------------------------------------- */ +/* generic helper functions and macros */ + +#define MLBC0_FCNT_VAL_MACRO(n) MLBC0_FCNT_VAL_ ## n ## FPSB +#define MLBC0_FCNT_VAL(fpsb) MLBC0_FCNT_VAL_MACRO(fpsb) + +static inline u32 bit_mask(u8 position) +{ + return (u32)1 << position; +} + +static inline bool dim_on_error(u8 error_id, const char *error_message) +{ + DIMCB_OnError(error_id, error_message); + return false; +} + + +/* -------------------------------------------------------------------------- */ +/* types and local variables */ + +struct lld_global_vars_t { + bool dim_is_initialized; + bool mcm_is_initialized; + struct dim2_regs *dim2; /* DIM2 core base address */ + u32 dbr_map[DBR_MAP_SIZE]; +}; + +static struct lld_global_vars_t g = { false }; + + +/* -------------------------------------------------------------------------- */ + +static int dbr_get_mask_size(u16 size) +{ + int i; + + for (i = 0; i < 6; i++) + if (size <= (DBR_BLOCK_SIZE << i)) + return 1 << i; + return 0; +} + +/** + * Allocates DBR memory. + * @param size Allocating memory size. + * @return Offset in DBR memory by success or DBR_SIZE if out of memory. + */ +static int alloc_dbr(u16 size) +{ + int mask_size; + int i, block_idx = 0; + + if (size <= 0) + return DBR_SIZE; /* out of memory */ + + mask_size = dbr_get_mask_size(size); + if (mask_size == 0) + return DBR_SIZE; /* out of memory */ + + for (i = 0; i < DBR_MAP_SIZE; i++) { + u32 const blocks = (size + DBR_BLOCK_SIZE - 1) / DBR_BLOCK_SIZE; + u32 mask = ~((~(u32)0) << blocks); + + do { + if ((g.dbr_map[i] & mask) == 0) { + g.dbr_map[i] |= mask; + return block_idx * DBR_BLOCK_SIZE; + } + block_idx += mask_size; + /* do shift left with 2 steps for case mask_size == 32 */ + mask <<= mask_size - 1; + } while ((mask <<= 1) != 0); + } + + return DBR_SIZE; /* out of memory */ +} + +static void free_dbr(int offs, int size) +{ + int block_idx = offs / DBR_BLOCK_SIZE; + u32 const blocks = (size + DBR_BLOCK_SIZE - 1) / DBR_BLOCK_SIZE; + u32 mask = ~((~(u32)0) << blocks); + + mask <<= block_idx % 32; + g.dbr_map[block_idx / 32] &= ~mask; +} + +/* -------------------------------------------------------------------------- */ + +static u32 dim2_read_ctr(u32 ctr_addr, u16 mdat_idx) +{ + DIMCB_IoWrite(&g.dim2->MADR, ctr_addr); + + /* wait till transfer is completed */ + while ((DIMCB_IoRead(&g.dim2->MCTL) & 1) != 1) + continue; + + DIMCB_IoWrite(&g.dim2->MCTL, 0); /* clear transfer complete */ + + return DIMCB_IoRead((&g.dim2->MDAT0) + mdat_idx); +} + +static void dim2_write_ctr_mask(u32 ctr_addr, const u32 *mask, const u32 *value) +{ + enum { MADR_WNR_BIT = 31 }; + + DIMCB_IoWrite(&g.dim2->MCTL, 0); /* clear transfer complete */ + + if (mask[0] != 0) + DIMCB_IoWrite(&g.dim2->MDAT0, value[0]); + if (mask[1] != 0) + DIMCB_IoWrite(&g.dim2->MDAT1, value[1]); + if (mask[2] != 0) + DIMCB_IoWrite(&g.dim2->MDAT2, value[2]); + if (mask[3] != 0) + DIMCB_IoWrite(&g.dim2->MDAT3, value[3]); + + DIMCB_IoWrite(&g.dim2->MDWE0, mask[0]); + DIMCB_IoWrite(&g.dim2->MDWE1, mask[1]); + DIMCB_IoWrite(&g.dim2->MDWE2, mask[2]); + DIMCB_IoWrite(&g.dim2->MDWE3, mask[3]); + + DIMCB_IoWrite(&g.dim2->MADR, bit_mask(MADR_WNR_BIT) | ctr_addr); + + /* wait till transfer is completed */ + while ((DIMCB_IoRead(&g.dim2->MCTL) & 1) != 1) + continue; + + DIMCB_IoWrite(&g.dim2->MCTL, 0); /* clear transfer complete */ +} + +static inline void dim2_write_ctr(u32 ctr_addr, const u32 *value) +{ + u32 const mask[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + + dim2_write_ctr_mask(ctr_addr, mask, value); +} + +static inline void dim2_clear_ctr(u32 ctr_addr) +{ + u32 const value[4] = { 0, 0, 0, 0 }; + + dim2_write_ctr(ctr_addr, value); +} + +static void dim2_configure_cat(u8 cat_base, u8 ch_addr, u8 ch_type, + bool read_not_write, bool sync_mfe) +{ + u16 const cat = + (read_not_write << CAT_RNW_BIT) | + (ch_type << CAT_CT_SHIFT) | + (ch_addr << CAT_CL_SHIFT) | + (sync_mfe << CAT_MFE_BIT) | + (false << CAT_MT_BIT) | + (true << CAT_CE_BIT); + u8 const ctr_addr = cat_base + ch_addr / 8; + u8 const idx = (ch_addr % 8) / 2; + u8 const shift = (ch_addr % 2) * 16; + u32 mask[4] = { 0, 0, 0, 0 }; + u32 value[4] = { 0, 0, 0, 0 }; + + mask[idx] = (u32)0xFFFF << shift; + value[idx] = cat << shift; + dim2_write_ctr_mask(ctr_addr, mask, value); +} + +static void dim2_clear_cat(u8 cat_base, u8 ch_addr) +{ + u8 const ctr_addr = cat_base + ch_addr / 8; + u8 const idx = (ch_addr % 8) / 2; + u8 const shift = (ch_addr % 2) * 16; + u32 mask[4] = { 0, 0, 0, 0 }; + u32 value[4] = { 0, 0, 0, 0 }; + + mask[idx] = (u32)0xFFFF << shift; + dim2_write_ctr_mask(ctr_addr, mask, value); +} + +static void dim2_configure_cdt(u8 ch_addr, u16 dbr_address, u16 hw_buffer_size, + u16 packet_length) +{ + u32 cdt[4] = { 0, 0, 0, 0 }; + + if (packet_length) + cdt[1] = ((packet_length - 1) << CDT1_BS_ISOC_SHIFT); + + cdt[3] = + ((hw_buffer_size - 1) << CDT3_BD_SHIFT) | + (dbr_address << CDT3_BA_SHIFT); + dim2_write_ctr(CDT + ch_addr, cdt); +} + +static void dim2_clear_cdt(u8 ch_addr) +{ + u32 cdt[4] = { 0, 0, 0, 0 }; + + dim2_write_ctr(CDT + ch_addr, cdt); +} + +static void dim2_configure_adt(u8 ch_addr) +{ + u32 adt[4] = { 0, 0, 0, 0 }; + + adt[0] = + (true << ADT0_CE_BIT) | + (true << ADT0_LE_BIT) | + (0 << ADT0_PG_BIT); + + dim2_write_ctr(ADT + ch_addr, adt); +} + +static void dim2_clear_adt(u8 ch_addr) +{ + u32 adt[4] = { 0, 0, 0, 0 }; + + dim2_write_ctr(ADT + ch_addr, adt); +} + +static void dim2_start_ctrl_async(u8 ch_addr, u8 idx, u32 buf_addr, + u16 buffer_size) +{ + u8 const shift = idx * 16; + + u32 mask[4] = { 0, 0, 0, 0 }; + u32 adt[4] = { 0, 0, 0, 0 }; + + mask[1] = + bit_mask(ADT1_PS_BIT + shift) | + bit_mask(ADT1_RDY_BIT + shift) | + (ADT1_CTRL_ASYNC_BD_MASK << (ADT1_BD_SHIFT + shift)); + adt[1] = + (true << (ADT1_PS_BIT + shift)) | + (true << (ADT1_RDY_BIT + shift)) | + ((buffer_size - 1) << (ADT1_BD_SHIFT + shift)); + + mask[idx + 2] = 0xFFFFFFFF; + adt[idx + 2] = buf_addr; + + dim2_write_ctr_mask(ADT + ch_addr, mask, adt); +} + +static void dim2_start_isoc_sync(u8 ch_addr, u8 idx, u32 buf_addr, + u16 buffer_size) +{ + u8 const shift = idx * 16; + + u32 mask[4] = { 0, 0, 0, 0 }; + u32 adt[4] = { 0, 0, 0, 0 }; + + mask[1] = + bit_mask(ADT1_RDY_BIT + shift) | + (ADT1_ISOC_SYNC_BD_MASK << (ADT1_BD_SHIFT + shift)); + adt[1] = + (true << (ADT1_RDY_BIT + shift)) | + ((buffer_size - 1) << (ADT1_BD_SHIFT + shift)); + + mask[idx + 2] = 0xFFFFFFFF; + adt[idx + 2] = buf_addr; + + dim2_write_ctr_mask(ADT + ch_addr, mask, adt); +} + + +static void dim2_clear_ctram(void) +{ + u32 ctr_addr; + + for (ctr_addr = 0; ctr_addr < 0x90; ctr_addr++) + dim2_clear_ctr(ctr_addr); +} + +static void dim2_configure_channel( + u8 ch_addr, u8 type, u8 is_tx, u16 dbr_address, u16 hw_buffer_size, + u16 packet_length, bool sync_mfe) +{ + dim2_configure_cdt(ch_addr, dbr_address, hw_buffer_size, packet_length); + dim2_configure_cat(MLB_CAT, ch_addr, type, is_tx ? 1 : 0, sync_mfe); + + dim2_configure_adt(ch_addr); + dim2_configure_cat(AHB_CAT, ch_addr, type, is_tx ? 0 : 1, sync_mfe); + + /* unmask interrupt for used channel, enable mlb_sys_int[0] interrupt */ + DIMCB_IoWrite(&g.dim2->ACMR0, + DIMCB_IoRead(&g.dim2->ACMR0) | bit_mask(ch_addr)); +} + +static void dim2_clear_channel(u8 ch_addr) +{ + /* mask interrupt for used channel, disable mlb_sys_int[0] interrupt */ + DIMCB_IoWrite(&g.dim2->ACMR0, + DIMCB_IoRead(&g.dim2->ACMR0) & ~bit_mask(ch_addr)); + + dim2_clear_cat(AHB_CAT, ch_addr); + dim2_clear_adt(ch_addr); + + dim2_clear_cat(MLB_CAT, ch_addr); + dim2_clear_cdt(ch_addr); +} + +/* -------------------------------------------------------------------------- */ +/* channel state helpers */ + +static void state_init(struct int_ch_state *state) +{ + state->request_counter = 0; + state->service_counter = 0; + + state->idx1 = 0; + state->idx2 = 0; + state->level = 0; +} + +/* -------------------------------------------------------------------------- */ +/* macro helper functions */ + +static inline bool check_channel_address(u32 ch_address) +{ + return ch_address > 0 && (ch_address % 2) == 0 && + (ch_address / 2) <= (u32)CAT_CL_MASK; +} + +static inline bool check_packet_length(u32 packet_length) +{ + u16 const max_size = ((u16)CDT3_BD_ISOC_MASK + 1u) / ISOC_DBR_FACTOR; + + if (packet_length <= 0) + return false; /* too small */ + + if (packet_length > max_size) + return false; /* too big */ + + if (packet_length - 1u > (u32)CDT1_BS_ISOC_MASK) + return false; /* too big */ + + return true; +} + +static inline bool check_bytes_per_frame(u32 bytes_per_frame) +{ + u16 const max_size = ((u16)CDT3_BD_MASK + 1u) / SYNC_DBR_FACTOR; + + if (bytes_per_frame <= 0) + return false; /* too small */ + + if (bytes_per_frame > max_size) + return false; /* too big */ + + return true; +} + +static inline u16 norm_ctrl_async_buffer_size(u16 buf_size) +{ + u16 const max_size = (u16)ADT1_CTRL_ASYNC_BD_MASK + 1u; + + if (buf_size > max_size) + return max_size; + + return buf_size; +} + +static inline u16 norm_isoc_buffer_size(u16 buf_size, u16 packet_length) +{ + u16 n; + u16 const max_size = (u16)ADT1_ISOC_SYNC_BD_MASK + 1u; + + if (buf_size > max_size) + buf_size = max_size; + + n = buf_size / packet_length; + + if (n < 2u) + return 0; /* too small buffer for given packet_length */ + + return packet_length * n; +} + +static inline u16 norm_sync_buffer_size(u16 buf_size, u16 bytes_per_frame) +{ + u16 n; + u16 const max_size = (u16)ADT1_ISOC_SYNC_BD_MASK + 1u; + u32 const unit = bytes_per_frame * (u16)FRAMES_PER_SUBBUFF; + + if (buf_size > max_size) + buf_size = max_size; + + n = buf_size / unit; + + if (n < 1u) + return 0; /* too small buffer for given bytes_per_frame */ + + return unit * n; +} + +static void dim2_cleanup(void) +{ + /* disable MediaLB */ + DIMCB_IoWrite(&g.dim2->MLBC0, false << MLBC0_MLBEN_BIT); + + dim2_clear_ctram(); + + /* disable mlb_int interrupt */ + DIMCB_IoWrite(&g.dim2->MIEN, 0); + + /* clear status for all dma channels */ + DIMCB_IoWrite(&g.dim2->ACSR0, 0xFFFFFFFF); + DIMCB_IoWrite(&g.dim2->ACSR1, 0xFFFFFFFF); + + /* mask interrupts for all channels */ + DIMCB_IoWrite(&g.dim2->ACMR0, 0); + DIMCB_IoWrite(&g.dim2->ACMR1, 0); +} + +static void dim2_initialize(bool enable_6pin, u8 mlb_clock) +{ + dim2_cleanup(); + + /* configure and enable MediaLB */ + DIMCB_IoWrite(&g.dim2->MLBC0, + enable_6pin << MLBC0_MLBPEN_BIT | + mlb_clock << MLBC0_MLBCLK_SHIFT | + MLBC0_FCNT_VAL(FRAMES_PER_SUBBUFF) << MLBC0_FCNT_SHIFT | + true << MLBC0_MLBEN_BIT); + + /* activate all HBI channels */ + DIMCB_IoWrite(&g.dim2->HCMR0, 0xFFFFFFFF); + DIMCB_IoWrite(&g.dim2->HCMR1, 0xFFFFFFFF); + + /* enable HBI */ + DIMCB_IoWrite(&g.dim2->HCTL, bit_mask(HCTL_EN_BIT)); + + /* configure DMA */ + DIMCB_IoWrite(&g.dim2->ACTL, + ACTL_DMA_MODE_VAL_DMA_MODE_1 << ACTL_DMA_MODE_BIT | + true << ACTL_SCE_BIT); + +#if 0 + DIMCB_IoWrite(&g.dim2->MIEN, + bit_mask(MIEN_CTX_BREAK_BIT) | + bit_mask(MIEN_CTX_PE_BIT) | + bit_mask(MIEN_CTX_DONE_BIT) | + bit_mask(MIEN_CRX_BREAK_BIT) | + bit_mask(MIEN_CRX_PE_BIT) | + bit_mask(MIEN_CRX_DONE_BIT) | + bit_mask(MIEN_ATX_BREAK_BIT) | + bit_mask(MIEN_ATX_PE_BIT) | + bit_mask(MIEN_ATX_DONE_BIT) | + bit_mask(MIEN_ARX_BREAK_BIT) | + bit_mask(MIEN_ARX_PE_BIT) | + bit_mask(MIEN_ARX_DONE_BIT)); +#endif +} + +static bool dim2_is_mlb_locked(void) +{ + u32 const mask0 = bit_mask(MLBC0_MLBLK_BIT); + u32 const mask1 = bit_mask(MLBC1_CLKMERR_BIT) | + bit_mask(MLBC1_LOCKERR_BIT); + u32 const c1 = DIMCB_IoRead(&g.dim2->MLBC1); + u32 const nda_mask = (u32)MLBC1_NDA_MASK << MLBC1_NDA_SHIFT; + + DIMCB_IoWrite(&g.dim2->MLBC1, c1 & nda_mask); + return (DIMCB_IoRead(&g.dim2->MLBC1) & mask1) == 0 && + (DIMCB_IoRead(&g.dim2->MLBC0) & mask0) != 0; +} + + +/* -------------------------------------------------------------------------- */ +/* channel help routines */ + +static inline bool service_channel(u8 ch_addr, u8 idx) +{ + u8 const shift = idx * 16; + u32 const adt1 = dim2_read_ctr(ADT + ch_addr, 1); + + if (((adt1 >> (ADT1_DNE_BIT + shift)) & 1) == 0) + return false; + + { + u32 mask[4] = { 0, 0, 0, 0 }; + u32 adt_w[4] = { 0, 0, 0, 0 }; + + mask[1] = + bit_mask(ADT1_DNE_BIT + shift) | + bit_mask(ADT1_ERR_BIT + shift) | + bit_mask(ADT1_RDY_BIT + shift); + dim2_write_ctr_mask(ADT + ch_addr, mask, adt_w); + } + + /* clear channel status bit */ + DIMCB_IoWrite(&g.dim2->ACSR0, bit_mask(ch_addr)); + + return true; +} + + +/* -------------------------------------------------------------------------- */ +/* channel init routines */ + +static void isoc_init(struct dim_channel *ch, u8 ch_addr, u16 packet_length) +{ + state_init(&ch->state); + + ch->addr = ch_addr; + + ch->packet_length = packet_length; + ch->bytes_per_frame = 0; + ch->done_sw_buffers_number = 0; +} + +static void sync_init(struct dim_channel *ch, u8 ch_addr, u16 bytes_per_frame) +{ + state_init(&ch->state); + + ch->addr = ch_addr; + + ch->packet_length = 0; + ch->bytes_per_frame = bytes_per_frame; + ch->done_sw_buffers_number = 0; +} + +static void channel_init(struct dim_channel *ch, u8 ch_addr) +{ + state_init(&ch->state); + + ch->addr = ch_addr; + + ch->packet_length = 0; + ch->bytes_per_frame = 0; + ch->done_sw_buffers_number = 0; +} + +/* returns true if channel interrupt state is cleared */ +static bool channel_service_interrupt(struct dim_channel *ch) +{ + struct int_ch_state *const state = &ch->state; + + if (!service_channel(ch->addr, state->idx2)) + return false; + + state->idx2 ^= 1; + state->request_counter++; + return true; +} + +static bool channel_start(struct dim_channel *ch, u32 buf_addr, u16 buf_size) +{ + struct int_ch_state *const state = &ch->state; + + if (buf_size <= 0) + return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE, "Bad buffer size"); + + if (ch->packet_length == 0 && ch->bytes_per_frame == 0 && + buf_size != norm_ctrl_async_buffer_size(buf_size)) + return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE, + "Bad control/async buffer size"); + + if (ch->packet_length && + buf_size != norm_isoc_buffer_size(buf_size, ch->packet_length)) + return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE, + "Bad isochronous buffer size"); + + if (ch->bytes_per_frame && + buf_size != norm_sync_buffer_size(buf_size, ch->bytes_per_frame)) + return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE, + "Bad synchronous buffer size"); + + if (state->level >= 2u) + return dim_on_error(DIM_ERR_OVERFLOW, "Channel overflow"); + + ++state->level; + + if (ch->packet_length || ch->bytes_per_frame) + dim2_start_isoc_sync(ch->addr, state->idx1, buf_addr, buf_size); + else + dim2_start_ctrl_async(ch->addr, state->idx1, buf_addr, buf_size); + state->idx1 ^= 1; + + return true; +} + +static u8 channel_service(struct dim_channel *ch) +{ + struct int_ch_state *const state = &ch->state; + + if (state->service_counter != state->request_counter) { + state->service_counter++; + if (state->level == 0) + return DIM_ERR_UNDERFLOW; + + --state->level; + ch->done_sw_buffers_number++; + } + + return DIM_NO_ERROR; +} + +static bool channel_detach_buffers(struct dim_channel *ch, u16 buffers_number) +{ + if (buffers_number > ch->done_sw_buffers_number) + return dim_on_error(DIM_ERR_UNDERFLOW, "Channel underflow"); + + ch->done_sw_buffers_number -= buffers_number; + return true; +} + + +/* -------------------------------------------------------------------------- */ +/* API */ + +u8 DIM_Startup(void *dim_base_address, u32 mlb_clock) +{ + g.dim_is_initialized = false; + + if (!dim_base_address) + return DIM_INIT_ERR_DIM_ADDR; + + /* MediaLB clock: 0 - 256 fs, 1 - 512 fs, 2 - 1024 fs, 3 - 2048 fs */ + /* MediaLB clock: 4 - 3072 fs, 5 - 4096 fs, 6 - 6144 fs, 7 - 8192 fs */ + if (mlb_clock >= 8) + return DIM_INIT_ERR_MLB_CLOCK; + + g.dim2 = dim_base_address; + g.dbr_map[0] = g.dbr_map[1] = 0; + + dim2_initialize(mlb_clock >= 3, mlb_clock); + + g.dim_is_initialized = true; + + return DIM_NO_ERROR; +} + +void DIM_Shutdown(void) +{ + g.dim_is_initialized = false; + dim2_cleanup(); +} + +bool DIM_GetLockState(void) +{ + return dim2_is_mlb_locked(); +} + +static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx, + u16 ch_address, u16 hw_buffer_size) +{ + if (!g.dim_is_initialized || !ch) + return DIM_ERR_DRIVER_NOT_INITIALIZED; + + if (!check_channel_address(ch_address)) + return DIM_INIT_ERR_CHANNEL_ADDRESS; + + ch->dbr_size = hw_buffer_size; + ch->dbr_addr = alloc_dbr(ch->dbr_size); + if (ch->dbr_addr >= DBR_SIZE) + return DIM_INIT_ERR_OUT_OF_MEMORY; + + channel_init(ch, ch_address / 2); + + dim2_configure_channel(ch->addr, type, is_tx, + ch->dbr_addr, ch->dbr_size, 0, false); + + return DIM_NO_ERROR; +} + +u16 DIM_NormCtrlAsyncBufferSize(u16 buf_size) +{ + return norm_ctrl_async_buffer_size(buf_size); +} + +/** + * Retrieves maximal possible correct buffer size for isochronous data type + * conform to given packet length and not bigger than given buffer size. + * + * Returns non-zero correct buffer size or zero by error. + */ +u16 DIM_NormIsocBufferSize(u16 buf_size, u16 packet_length) +{ + if (!check_packet_length(packet_length)) + return 0; + + return norm_isoc_buffer_size(buf_size, packet_length); +} + +/** + * Retrieves maximal possible correct buffer size for synchronous data type + * conform to given bytes per frame and not bigger than given buffer size. + * + * Returns non-zero correct buffer size or zero by error. + */ +u16 DIM_NormSyncBufferSize(u16 buf_size, u16 bytes_per_frame) +{ + if (!check_bytes_per_frame(bytes_per_frame)) + return 0; + + return norm_sync_buffer_size(buf_size, bytes_per_frame); +} + +u8 DIM_InitControl(struct dim_channel *ch, u8 is_tx, u16 ch_address, + u16 max_buffer_size) +{ + return init_ctrl_async(ch, CAT_CT_VAL_CONTROL, is_tx, ch_address, + max_buffer_size * 2); +} + +u8 DIM_InitAsync(struct dim_channel *ch, u8 is_tx, u16 ch_address, + u16 max_buffer_size) +{ + return init_ctrl_async(ch, CAT_CT_VAL_ASYNC, is_tx, ch_address, + max_buffer_size * 2); +} + +u8 DIM_InitIsoc(struct dim_channel *ch, u8 is_tx, u16 ch_address, + u16 packet_length) +{ + if (!g.dim_is_initialized || !ch) + return DIM_ERR_DRIVER_NOT_INITIALIZED; + + if (!check_channel_address(ch_address)) + return DIM_INIT_ERR_CHANNEL_ADDRESS; + + if (!check_packet_length(packet_length)) + return DIM_ERR_BAD_CONFIG; + + ch->dbr_size = packet_length * ISOC_DBR_FACTOR; + ch->dbr_addr = alloc_dbr(ch->dbr_size); + if (ch->dbr_addr >= DBR_SIZE) + return DIM_INIT_ERR_OUT_OF_MEMORY; + + isoc_init(ch, ch_address / 2, packet_length); + + dim2_configure_channel(ch->addr, CAT_CT_VAL_ISOC, is_tx, ch->dbr_addr, + ch->dbr_size, packet_length, false); + + return DIM_NO_ERROR; +} + +u8 DIM_InitSync(struct dim_channel *ch, u8 is_tx, u16 ch_address, + u16 bytes_per_frame) +{ + if (!g.dim_is_initialized || !ch) + return DIM_ERR_DRIVER_NOT_INITIALIZED; + + if (!check_channel_address(ch_address)) + return DIM_INIT_ERR_CHANNEL_ADDRESS; + + if (!check_bytes_per_frame(bytes_per_frame)) + return DIM_ERR_BAD_CONFIG; + + ch->dbr_size = bytes_per_frame * SYNC_DBR_FACTOR; + ch->dbr_addr = alloc_dbr(ch->dbr_size); + if (ch->dbr_addr >= DBR_SIZE) + return DIM_INIT_ERR_OUT_OF_MEMORY; + + sync_init(ch, ch_address / 2, bytes_per_frame); + + dim2_configure_channel(ch->addr, CAT_CT_VAL_SYNC, is_tx, + ch->dbr_addr, ch->dbr_size, 0, true); + + return DIM_NO_ERROR; +} + +u8 DIM_DestroyChannel(struct dim_channel *ch) +{ + if (!g.dim_is_initialized || !ch) + return DIM_ERR_DRIVER_NOT_INITIALIZED; + + dim2_clear_channel(ch->addr); + if (ch->dbr_addr < DBR_SIZE) + free_dbr(ch->dbr_addr, ch->dbr_size); + ch->dbr_addr = DBR_SIZE; + + return DIM_NO_ERROR; +} + +void DIM_ServiceIrq(struct dim_channel *const *channels) +{ + bool state_changed; + + if (!g.dim_is_initialized) { + dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED, + "DIM is not initialized"); + return; + } + + if (!channels) { + dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED, "Bad channels"); + return; + } + + /* + * Use while-loop and a flag to make sure the age is changed back at least once, + * otherwise the interrupt may never come if CPU generates interrupt on changing age. + * + * This cycle runs not more than number of channels, because service_interrupts + * routine doesn't start the channel again. + */ + do { + struct dim_channel *const *ch = channels; + + state_changed = false; + + while (*ch) { + state_changed |= channel_service_interrupt(*ch); + ++ch; + } + } while (state_changed); + + /* clear pending Interrupts */ + DIMCB_IoWrite(&g.dim2->MS0, 0); + DIMCB_IoWrite(&g.dim2->MS1, 0); +} + +u8 DIM_ServiceChannel(struct dim_channel *ch) +{ + if (!g.dim_is_initialized || !ch) + return DIM_ERR_DRIVER_NOT_INITIALIZED; + + return channel_service(ch); +} + +struct dim_ch_state_t *DIM_GetChannelState(struct dim_channel *ch, + struct dim_ch_state_t *state_ptr) +{ + if (!ch || !state_ptr) + return 0; + + state_ptr->ready = ch->state.level < 2; + state_ptr->done_buffers = ch->done_sw_buffers_number; + + return state_ptr; +} + +bool DIM_EnqueueBuffer(struct dim_channel *ch, u32 buffer_addr, u16 buffer_size) +{ + if (!ch) + return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED, "Bad channel"); + + return channel_start(ch, buffer_addr, buffer_size); +} + +bool DIM_DetachBuffers(struct dim_channel *ch, u16 buffers_number) +{ + if (!ch) + return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED, "Bad channel"); + + return channel_detach_buffers(ch, buffers_number); +} + +u32 DIM_ReadRegister(u8 register_index) +{ + return DIMCB_IoRead((u32 *)g.dim2 + register_index); +} diff --git a/drivers/staging/most/hdm-dim2/dim2_hal.h b/drivers/staging/most/hdm-dim2/dim2_hal.h new file mode 100644 index 000000000000..d88b5a0e3244 --- /dev/null +++ b/drivers/staging/most/hdm-dim2/dim2_hal.h @@ -0,0 +1,124 @@ +/* + * dim2_hal.h - DIM2 HAL interface + * (MediaLB, Device Interface Macro IP, OS62420) + * + * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#ifndef _DIM2_HAL_H +#define _DIM2_HAL_H + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The values below are specified in the hardware specification. + * So, they should not be changed until the hardware specification changes. + */ +enum mlb_clk_speed { + CLK_256FS = 0, + CLK_512FS = 1, + CLK_1024FS = 2, + CLK_2048FS = 3, + CLK_3072FS = 4, + CLK_4096FS = 5, + CLK_6144FS = 6, + CLK_8192FS = 7, +}; + +struct dim_ch_state_t { + bool ready; /* Shows readiness to enqueue next buffer */ + u16 done_buffers; /* Number of completed buffers */ +}; + +typedef int atomic_counter_t; + +struct int_ch_state { + /* changed only in interrupt context */ + volatile atomic_counter_t request_counter; + + /* changed only in task context */ + volatile atomic_counter_t service_counter; + + u8 idx1; + u8 idx2; + u8 level; /* [0..2], buffering level */ +}; + +struct dim_channel { + struct int_ch_state state; + u8 addr; + u16 dbr_addr; + u16 dbr_size; + u16 packet_length; /*< Isochronous packet length in bytes. */ + u16 bytes_per_frame; /*< Synchronous bytes per frame. */ + u16 done_sw_buffers_number; /*< Done software buffers number. */ +}; + + +u8 DIM_Startup(void *dim_base_address, u32 mlb_clock); + +void DIM_Shutdown(void); + +bool DIM_GetLockState(void); + +u16 DIM_NormCtrlAsyncBufferSize(u16 buf_size); + +u16 DIM_NormIsocBufferSize(u16 buf_size, u16 packet_length); + +u16 DIM_NormSyncBufferSize(u16 buf_size, u16 bytes_per_frame); + +u8 DIM_InitControl(struct dim_channel *ch, u8 is_tx, u16 ch_address, + u16 max_buffer_size); + +u8 DIM_InitAsync(struct dim_channel *ch, u8 is_tx, u16 ch_address, + u16 max_buffer_size); + +u8 DIM_InitIsoc(struct dim_channel *ch, u8 is_tx, u16 ch_address, + u16 packet_length); + +u8 DIM_InitSync(struct dim_channel *ch, u8 is_tx, u16 ch_address, + u16 bytes_per_frame); + +u8 DIM_DestroyChannel(struct dim_channel *ch); + +void DIM_ServiceIrq(struct dim_channel *const *channels); + +u8 DIM_ServiceChannel(struct dim_channel *ch); + +struct dim_ch_state_t *DIM_GetChannelState(struct dim_channel *ch, + struct dim_ch_state_t *dim_ch_state_ptr); + +bool DIM_EnqueueBuffer(struct dim_channel *ch, u32 buffer_addr, + u16 buffer_size); + +bool DIM_DetachBuffers(struct dim_channel *ch, u16 buffers_number); + +u32 DIM_ReadRegister(u8 register_index); + + +extern u32 DIMCB_IoRead(u32 *ptr32); + +extern void DIMCB_IoWrite(u32 *ptr32, u32 value); + +extern void DIMCB_OnError(u8 error_id, const char *error_message); + +extern void DIMCB_OnFail(const char *filename, int linenum); + + +#ifdef __cplusplus +} +#endif + +#endif /* _DIM2_HAL_H */ diff --git a/drivers/staging/most/hdm-dim2/dim2_hdm.c b/drivers/staging/most/hdm-dim2/dim2_hdm.c new file mode 100644 index 000000000000..6a5a3a2775f3 --- /dev/null +++ b/drivers/staging/most/hdm-dim2/dim2_hdm.c @@ -0,0 +1,964 @@ +/* + * dim2_hdm.c - MediaLB DIM2 Hardware Dependent Module + * + * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "dim2_hal.h" +#include "dim2_hdm.h" +#include "dim2_errors.h" +#include "dim2_sysfs.h" + +#define DMA_CHANNELS (32 - 1) /* channel 0 is a system channel */ + +#define MAX_BUFFERS_PACKET 32 +#define MAX_BUFFERS_STREAMING 32 +#define MAX_BUF_SIZE_PACKET 2048 +#define MAX_BUF_SIZE_STREAMING (8*1024) + +/* command line parameter to select clock speed */ +static char *clock_speed; +module_param(clock_speed, charp, 0); +MODULE_PARM_DESC(clock_speed, "MediaLB Clock Speed"); + +/* + * ############################################################################# + * + * The define below activates an utility function used by HAL-simu + * for calling DIM interrupt handler. + * It is used only for TEST PURPOSE and shall be commented before release. + * + * ############################################################################# + */ +/* #define ENABLE_HDM_TEST */ + +static DEFINE_SPINLOCK(dim_lock); + +static void dim2_tasklet_fn(unsigned long data); +static DECLARE_TASKLET(dim2_tasklet, dim2_tasklet_fn, 0); + +/** + * struct hdm_channel - private structure to keep channel specific data + * @is_initialized: identifier to know whether the channel is initialized + * @ch: HAL specific channel data + * @pending_list: list to keep MBO's before starting transfer + * @started_list: list to keep MBO's after starting transfer + * @direction: channel direction (TX or RX) + * @data_type: channel data type + */ +struct hdm_channel { + char name[sizeof "caNNN"]; + bool is_initialized; + struct dim_channel ch; + struct list_head pending_list; /* before DIM_EnqueueBuffer() */ + struct list_head started_list; /* after DIM_EnqueueBuffer() */ + enum most_channel_direction direction; + enum most_channel_data_type data_type; +}; + +/** + * struct dim2_hdm - private structure to keep interface specific data + * @hch: an array of channel specific data + * @most_iface: most interface structure + * @capabilities: an array of channel capability data + * @io_base: I/O register base address + * @irq_ahb0: dim2 AHB0 irq number + * @clk_speed: user selectable (through command line parameter) clock speed + * @netinfo_task: thread to deliver network status + * @netinfo_waitq: waitq for the thread to sleep + * @deliver_netinfo: to identify whether network status received + * @mac_addrs: INIC mac address + * @link_state: network link state + * @atx_idx: index of async tx channel + */ +struct dim2_hdm { + struct hdm_channel hch[DMA_CHANNELS]; + struct most_channel_capability capabilities[DMA_CHANNELS]; + struct most_interface most_iface; + char name[16 + sizeof "dim2-"]; + void *io_base; + unsigned int irq_ahb0; + int clk_speed; + struct task_struct *netinfo_task; + wait_queue_head_t netinfo_waitq; + int deliver_netinfo; + unsigned char mac_addrs[6]; + unsigned char link_state; + int atx_idx; + struct medialb_bus bus; +}; + +#define iface_to_hdm(iface) container_of(iface, struct dim2_hdm, most_iface) + +/* Macro to identify a network status message */ +#define PACKET_IS_NET_INFO(p) \ + (((p)[1] == 0x18) && ((p)[2] == 0x05) && ((p)[3] == 0x0C) && \ + ((p)[13] == 0x3C) && ((p)[14] == 0x00) && ((p)[15] == 0x0A)) + +#if defined(ENABLE_HDM_TEST) +static struct dim2_hdm *test_dev; +#endif + +bool dim2_sysfs_get_state_cb(void) +{ + bool state; + unsigned long flags; + + spin_lock_irqsave(&dim_lock, flags); + state = DIM_GetLockState(); + spin_unlock_irqrestore(&dim_lock, flags); + + return state; +} + +/** + * DIMCB_IoRead - callback from HAL to read an I/O register + * @ptr32: register address + */ +u32 DIMCB_IoRead(u32 *ptr32) +{ + return __raw_readl(ptr32); +} + +/** + * DIMCB_IoWrite - callback from HAL to write value to an I/O register + * @ptr32: register address + * @value: value to write + */ +void DIMCB_IoWrite(u32 *ptr32, u32 value) +{ + __raw_writel(value, ptr32); +} + +/** + * DIMCB_OnError - callback from HAL to report miscommunication between + * HDM and HAL + * @error_id: Error ID + * @error_message: Error message. Some text in a free format + */ +void DIMCB_OnError(u8 error_id, const char *error_message) +{ + pr_err("DIMCB_OnError: error_id - %d, error_message - %s\n", error_id, + error_message); +} + +/** + * DIMCB_OnFail - callback from HAL to report unrecoverable errors + * @filename: Source file where the error happened + * @linenum: Line number of the file where the error happened + */ +void DIMCB_OnFail(const char *filename, int linenum) +{ + pr_err("DIMCB_OnFail: file - %s, line no. - %d\n", filename, linenum); +} + +/** + * startup_dim - initialize the dim2 interface + * @pdev: platform device + * + * Get the value of command line parameter "clock_speed" if given or use the + * default value, enable the clock and PLL, and initialize the dim2 interface. + */ +static int startup_dim(struct platform_device *pdev) +{ + struct dim2_hdm *dev = platform_get_drvdata(pdev); + struct dim2_platform_data *pdata = pdev->dev.platform_data; + u8 hal_ret; + + dev->clk_speed = -1; + + if (clock_speed) { + if (!strcmp(clock_speed, "256fs")) + dev->clk_speed = CLK_256FS; + else if (!strcmp(clock_speed, "512fs")) + dev->clk_speed = CLK_512FS; + else if (!strcmp(clock_speed, "1024fs")) + dev->clk_speed = CLK_1024FS; + else if (!strcmp(clock_speed, "2048fs")) + dev->clk_speed = CLK_2048FS; + else if (!strcmp(clock_speed, "3072fs")) + dev->clk_speed = CLK_3072FS; + else if (!strcmp(clock_speed, "4096fs")) + dev->clk_speed = CLK_4096FS; + else if (!strcmp(clock_speed, "6144fs")) + dev->clk_speed = CLK_6144FS; + else if (!strcmp(clock_speed, "8192fs")) + dev->clk_speed = CLK_8192FS; + } + + if (dev->clk_speed == -1) { + pr_info("Bad or missing clock speed parameter," + " using default value: 3072fs\n"); + dev->clk_speed = CLK_3072FS; + } else + pr_info("Selected clock speed: %s\n", clock_speed); + + if (pdata && pdata->init) { + int ret = pdata->init(pdata, dev->io_base, dev->clk_speed); + + if (ret) + return ret; + } + + hal_ret = DIM_Startup(dev->io_base, dev->clk_speed); + if (hal_ret != DIM_NO_ERROR) { + pr_err("DIM_Startup failed: %d\n", hal_ret); + if (pdata && pdata->destroy) + pdata->destroy(pdata); + return -ENODEV; + } + + return 0; +} + +/** + * try_start_dim_transfer - try to transfer a buffer on a channel + * @hdm_ch: channel specific data + * + * Transfer a buffer from pending_list if the channel is ready + */ +static int try_start_dim_transfer(struct hdm_channel *hdm_ch) +{ + u16 buf_size; + struct list_head *head = &hdm_ch->pending_list; + struct mbo *mbo; + unsigned long flags; + struct dim_ch_state_t st; + + BUG_ON(hdm_ch == 0); + BUG_ON(!hdm_ch->is_initialized); + + spin_lock_irqsave(&dim_lock, flags); + if (list_empty(head)) { + spin_unlock_irqrestore(&dim_lock, flags); + return -EAGAIN; + } + + if (!DIM_GetChannelState(&hdm_ch->ch, &st)->ready) { + spin_unlock_irqrestore(&dim_lock, flags); + return -EAGAIN; + } + + mbo = list_entry(head->next, struct mbo, list); + buf_size = mbo->buffer_length; + + BUG_ON(mbo->bus_address == 0); + if (!DIM_EnqueueBuffer(&hdm_ch->ch, mbo->bus_address, buf_size)) { + list_del(head->next); + spin_unlock_irqrestore(&dim_lock, flags); + mbo->processed_length = 0; + mbo->status = MBO_E_INVAL; + mbo->complete(mbo); + return -EFAULT; + } + + list_move_tail(head->next, &hdm_ch->started_list); + spin_unlock_irqrestore(&dim_lock, flags); + + return 0; +} + +/** + * deliver_netinfo_thread - thread to deliver network status to mostcore + * @data: private data + * + * Wait for network status and deliver it to mostcore once it is received + */ +static int deliver_netinfo_thread(void *data) +{ + struct dim2_hdm *dev = (struct dim2_hdm *)data; + + while (!kthread_should_stop()) { + wait_event_interruptible(dev->netinfo_waitq, + dev->deliver_netinfo || + kthread_should_stop()); + + if (dev->deliver_netinfo) { + dev->deliver_netinfo--; + most_deliver_netinfo(&dev->most_iface, dev->link_state, + dev->mac_addrs); + } + } + + return 0; +} + +/** + * retrieve_netinfo - retrieve network status from received buffer + * @dev: private data + * @mbo: received MBO + * + * Parse the message in buffer and get node address, link state, MAC address. + * Wake up a thread to deliver this status to mostcore + */ +static void retrieve_netinfo(struct dim2_hdm *dev, struct mbo *mbo) +{ + u8 *data = mbo->virt_address; + u8 *mac = dev->mac_addrs; + + pr_info("Node Address: 0x%03x\n", (u16)data[16] << 8 | data[17]); + dev->link_state = data[18]; + pr_info("NIState: %d\n", dev->link_state); + memcpy(mac, data + 19, 6); + pr_info("MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + dev->deliver_netinfo++; + wake_up_interruptible(&dev->netinfo_waitq); +} + +/** + * service_done_flag - handle completed buffers + * @dev: private data + * @ch_idx: channel index + * + * Return back the completed buffers to mostcore, using completion callback + */ +static void service_done_flag(struct dim2_hdm *dev, int ch_idx) +{ + struct hdm_channel *hdm_ch = dev->hch + ch_idx; + struct dim_ch_state_t st; + struct list_head *head; + struct mbo *mbo; + int done_buffers; + unsigned long flags; + u8 *data; + + BUG_ON(hdm_ch == 0); + BUG_ON(!hdm_ch->is_initialized); + + spin_lock_irqsave(&dim_lock, flags); + + done_buffers = DIM_GetChannelState(&hdm_ch->ch, &st)->done_buffers; + if (!done_buffers) { + spin_unlock_irqrestore(&dim_lock, flags); + return; + } + + if (!DIM_DetachBuffers(&hdm_ch->ch, done_buffers)) { + spin_unlock_irqrestore(&dim_lock, flags); + return; + } + spin_unlock_irqrestore(&dim_lock, flags); + + head = &hdm_ch->started_list; + + while (done_buffers) { + spin_lock_irqsave(&dim_lock, flags); + if (list_empty(head)) { + spin_unlock_irqrestore(&dim_lock, flags); + pr_crit("hard error: started_mbo list is empty " + "whereas DIM2 has sent buffers\n"); + break; + } + + mbo = list_entry(head->next, struct mbo, list); + list_del(head->next); + spin_unlock_irqrestore(&dim_lock, flags); + + data = mbo->virt_address; + + if (hdm_ch->data_type == MOST_CH_ASYNC && + hdm_ch->direction == MOST_CH_RX && + PACKET_IS_NET_INFO(data)) { + + retrieve_netinfo(dev, mbo); + + spin_lock_irqsave(&dim_lock, flags); + list_add_tail(&mbo->list, &hdm_ch->pending_list); + spin_unlock_irqrestore(&dim_lock, flags); + } else { + if (hdm_ch->data_type == MOST_CH_CONTROL || + hdm_ch->data_type == MOST_CH_ASYNC) { + + u32 const data_size = + (u32)data[0] * 256 + data[1] + 2; + + mbo->processed_length = + min(data_size, (u32)mbo->buffer_length); + } else { + mbo->processed_length = mbo->buffer_length; + } + mbo->status = MBO_SUCCESS; + mbo->complete(mbo); + } + + done_buffers--; + } +} + +static struct dim_channel **get_active_channels(struct dim2_hdm *dev, + struct dim_channel **buffer) +{ + int idx = 0; + int ch_idx; + + for (ch_idx = 0; ch_idx < DMA_CHANNELS; ch_idx++) { + if (dev->hch[ch_idx].is_initialized) + buffer[idx++] = &dev->hch[ch_idx].ch; + } + buffer[idx++] = 0; + + return buffer; +} + +/** + * dim2_tasklet_fn - tasklet function + * @data: private data + * + * Service each initialized channel, if needed + */ +static void dim2_tasklet_fn(unsigned long data) +{ + struct dim2_hdm *dev = (struct dim2_hdm *)data; + unsigned long flags; + int ch_idx; + + for (ch_idx = 0; ch_idx < DMA_CHANNELS; ch_idx++) { + if (!dev->hch[ch_idx].is_initialized) + continue; + + spin_lock_irqsave(&dim_lock, flags); + DIM_ServiceChannel(&(dev->hch[ch_idx].ch)); + spin_unlock_irqrestore(&dim_lock, flags); + + service_done_flag(dev, ch_idx); + while (!try_start_dim_transfer(dev->hch + ch_idx)) + continue; + } +} + +/** + * dim2_ahb_isr - interrupt service routine + * @irq: irq number + * @_dev: private data + * + * Acknowledge the interrupt and schedule a tasklet to service channels. + * Return IRQ_HANDLED. + */ +static irqreturn_t dim2_ahb_isr(int irq, void *_dev) +{ + struct dim2_hdm *dev = (struct dim2_hdm *)_dev; + struct dim_channel *buffer[DMA_CHANNELS + 1]; + unsigned long flags; + + spin_lock_irqsave(&dim_lock, flags); + DIM_ServiceIrq(get_active_channels(dev, buffer)); + spin_unlock_irqrestore(&dim_lock, flags); + +#if !defined(ENABLE_HDM_TEST) + dim2_tasklet.data = (unsigned long)dev; + tasklet_schedule(&dim2_tasklet); +#else + dim2_tasklet_fn((unsigned long)dev); +#endif + return IRQ_HANDLED; +} + +#if defined(ENABLE_HDM_TEST) + +/* + * Utility function used by HAL-simu for calling DIM interrupt handler. + * It is used only for TEST PURPOSE. + */ +void raise_dim_interrupt(void) +{ + (void)dim2_ahb_isr(0, test_dev); +} +#endif + +/** + * complete_all_mbos - complete MBO's in a list + * @head: list head + * + * Delete all the entries in list and return back MBO's to mostcore using + * completion call back. + */ +static void complete_all_mbos(struct list_head *head) +{ + unsigned long flags; + struct mbo *mbo; + + for (;;) { + spin_lock_irqsave(&dim_lock, flags); + if (list_empty(head)) { + spin_unlock_irqrestore(&dim_lock, flags); + break; + } + + mbo = list_entry(head->next, struct mbo, list); + list_del(head->next); + spin_unlock_irqrestore(&dim_lock, flags); + + mbo->processed_length = 0; + mbo->status = MBO_E_CLOSE; + mbo->complete(mbo); + } +} + +/** + * configure_channel - initialize a channel + * @iface: interface the channel belongs to + * @channel: channel to be configured + * @channel_config: structure that holds the configuration information + * + * Receives configuration information from mostcore and initialize + * the corresponding channel. Return 0 on success, negative on failure. + */ +static int configure_channel(struct most_interface *most_iface, int ch_idx, + struct most_channel_config *ccfg) +{ + struct dim2_hdm *dev = iface_to_hdm(most_iface); + bool const is_tx = ccfg->direction == MOST_CH_TX; + u16 const sub_size = ccfg->subbuffer_size; + u16 const buf_size = ccfg->buffer_size; + u16 new_size; + unsigned long flags; + u8 hal_ret; + int const ch_addr = ch_idx * 2 + 2; + struct hdm_channel *const hdm_ch = dev->hch + ch_idx; + + BUG_ON(ch_idx < 0 || ch_idx >= DMA_CHANNELS); + + if (hdm_ch->is_initialized) + return -EPERM; + + switch (ccfg->data_type) { + case MOST_CH_CONTROL: + new_size = DIM_NormCtrlAsyncBufferSize(buf_size); + if (new_size == 0) { + pr_err("%s: too small buffer size\n", hdm_ch->name); + return -EINVAL; + } + ccfg->buffer_size = new_size; + if (new_size != buf_size) + pr_warn("%s: fixed buffer size (%d -> %d)\n", + hdm_ch->name, buf_size, new_size); + spin_lock_irqsave(&dim_lock, flags); + hal_ret = DIM_InitControl(&hdm_ch->ch, is_tx, ch_addr, buf_size); + break; + case MOST_CH_ASYNC: + new_size = DIM_NormCtrlAsyncBufferSize(buf_size); + if (new_size == 0) { + pr_err("%s: too small buffer size\n", hdm_ch->name); + return -EINVAL; + } + ccfg->buffer_size = new_size; + if (new_size != buf_size) + pr_warn("%s: fixed buffer size (%d -> %d)\n", + hdm_ch->name, buf_size, new_size); + spin_lock_irqsave(&dim_lock, flags); + hal_ret = DIM_InitAsync(&hdm_ch->ch, is_tx, ch_addr, buf_size); + break; + case MOST_CH_ISOC_AVP: + new_size = DIM_NormIsocBufferSize(buf_size, sub_size); + if (new_size == 0) { + pr_err("%s: invalid sub-buffer size or " + "too small buffer size\n", hdm_ch->name); + return -EINVAL; + } + ccfg->buffer_size = new_size; + if (new_size != buf_size) + pr_warn("%s: fixed buffer size (%d -> %d)\n", + hdm_ch->name, buf_size, new_size); + spin_lock_irqsave(&dim_lock, flags); + hal_ret = DIM_InitIsoc(&hdm_ch->ch, is_tx, ch_addr, sub_size); + break; + case MOST_CH_SYNC: + new_size = DIM_NormSyncBufferSize(buf_size, sub_size); + if (new_size == 0) { + pr_err("%s: invalid sub-buffer size or " + "too small buffer size\n", hdm_ch->name); + return -EINVAL; + } + ccfg->buffer_size = new_size; + if (new_size != buf_size) + pr_warn("%s: fixed buffer size (%d -> %d)\n", + hdm_ch->name, buf_size, new_size); + spin_lock_irqsave(&dim_lock, flags); + hal_ret = DIM_InitSync(&hdm_ch->ch, is_tx, ch_addr, sub_size); + break; + default: + pr_err("%s: configure failed, bad channel type: %d\n", + hdm_ch->name, ccfg->data_type); + return -EINVAL; + } + + if (hal_ret != DIM_NO_ERROR) { + spin_unlock_irqrestore(&dim_lock, flags); + pr_err("%s: configure failed (%d), type: %d, is_tx: %d\n", + hdm_ch->name, hal_ret, ccfg->data_type, (int)is_tx); + return -ENODEV; + } + + hdm_ch->data_type = ccfg->data_type; + hdm_ch->direction = ccfg->direction; + hdm_ch->is_initialized = true; + + if (hdm_ch->data_type == MOST_CH_ASYNC && + hdm_ch->direction == MOST_CH_TX && + dev->atx_idx < 0) + dev->atx_idx = ch_idx; + + spin_unlock_irqrestore(&dim_lock, flags); + + return 0; +} + +/** + * enqueue - enqueue a buffer for data transfer + * @iface: intended interface + * @channel: ID of the channel the buffer is intended for + * @mbo: pointer to the buffer object + * + * Push the buffer into pending_list and try to transfer one buffer from + * pending_list. Return 0 on success, negative on failure. + */ +static int enqueue(struct most_interface *most_iface, int ch_idx, + struct mbo *mbo) +{ + struct dim2_hdm *dev = iface_to_hdm(most_iface); + struct hdm_channel *hdm_ch = dev->hch + ch_idx; + unsigned long flags; + + BUG_ON(ch_idx < 0 || ch_idx >= DMA_CHANNELS); + + if (!hdm_ch->is_initialized) + return -EPERM; + + if (mbo->bus_address == 0) + return -EFAULT; + + spin_lock_irqsave(&dim_lock, flags); + list_add_tail(&mbo->list, &hdm_ch->pending_list); + spin_unlock_irqrestore(&dim_lock, flags); + + (void)try_start_dim_transfer(hdm_ch); + + return 0; +} + +/** + * request_netinfo - triggers retrieving of network info + * @iface: pointer to the interface + * @channel_id: corresponding channel ID + * + * Send a command to INIC which triggers retrieving of network info by means of + * "Message exchange over MDP/MEP". Return 0 on success, negative on failure. + */ +static void request_netinfo(struct most_interface *most_iface, int ch_idx) +{ + struct dim2_hdm *dev = iface_to_hdm(most_iface); + struct mbo *mbo; + u8 *data; + + if (dev->atx_idx < 0) { + pr_err("Async Tx Not initialized\n"); + return; + } + + mbo = most_get_mbo(&dev->most_iface, dev->atx_idx); + if (!mbo) + return; + + mbo->buffer_length = 5; + + data = mbo->virt_address; + + data[0] = 0x00; /* PML High byte */ + data[1] = 0x03; /* PML Low byte */ + data[2] = 0x02; /* PMHL */ + data[3] = 0x08; /* FPH */ + data[4] = 0x40; /* FMF (FIFO cmd msg - Triggers NAOverMDP) */ + + most_submit_mbo(mbo); +} + +/** + * poison_channel - poison buffers of a channel + * @iface: pointer to the interface the channel to be poisoned belongs to + * @channel_id: corresponding channel ID + * + * Destroy a channel and complete all the buffers in both started_list & + * pending_list. Return 0 on success, negative on failure. + */ +static int poison_channel(struct most_interface *most_iface, int ch_idx) +{ + struct dim2_hdm *dev = iface_to_hdm(most_iface); + struct hdm_channel *hdm_ch = dev->hch + ch_idx; + unsigned long flags; + u8 hal_ret; + int ret = 0; + + BUG_ON(ch_idx < 0 || ch_idx >= DMA_CHANNELS); + + if (!hdm_ch->is_initialized) + return -EPERM; + + spin_lock_irqsave(&dim_lock, flags); + hal_ret = DIM_DestroyChannel(&hdm_ch->ch); + hdm_ch->is_initialized = false; + if (ch_idx == dev->atx_idx) + dev->atx_idx = -1; + spin_unlock_irqrestore(&dim_lock, flags); + if (hal_ret != DIM_NO_ERROR) { + pr_err("HAL Failed to close channel %s\n", hdm_ch->name); + ret = -EFAULT; + } + + complete_all_mbos(&hdm_ch->started_list); + complete_all_mbos(&hdm_ch->pending_list); + + return ret; +} + +/* + * dim2_probe - dim2 probe handler + * @pdev: platform device structure + * + * Register the dim2 interface with mostcore and initialize it. + * Return 0 on success, negative on failure. + */ +static int dim2_probe(struct platform_device *pdev) +{ + struct dim2_hdm *dev; + struct resource *res; + int ret, i; + struct kobject *kobj; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->atx_idx = -1; + + platform_set_drvdata(pdev, dev); +#if defined(ENABLE_HDM_TEST) + test_dev = dev; +#else + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + pr_err("no memory region defined\n"); + ret = -ENOENT; + goto err_free_dev; + } + + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { + pr_err("failed to request mem region\n"); + ret = -EBUSY; + goto err_free_dev; + } + + dev->io_base = ioremap(res->start, resource_size(res)); + if (!dev->io_base) { + pr_err("failed to ioremap\n"); + ret = -ENOMEM; + goto err_release_mem; + } + + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + pr_err("failed to get irq\n"); + goto err_unmap_io; + } + dev->irq_ahb0 = ret; + + ret = request_irq(dev->irq_ahb0, dim2_ahb_isr, 0, "mlb_ahb0", dev); + if (ret) { + pr_err("failed to request IRQ: %d, err: %d\n", dev->irq_ahb0, ret); + goto err_unmap_io; + } +#endif + init_waitqueue_head(&dev->netinfo_waitq); + dev->deliver_netinfo = 0; + dev->netinfo_task = kthread_run(&deliver_netinfo_thread, (void *)dev, + "dim2_netinfo"); + if (IS_ERR(dev->netinfo_task)) { + ret = PTR_ERR(dev->netinfo_task); + goto err_free_irq; + } + + for (i = 0; i < DMA_CHANNELS; i++) { + struct most_channel_capability *cap = dev->capabilities + i; + struct hdm_channel *hdm_ch = dev->hch + i; + + INIT_LIST_HEAD(&hdm_ch->pending_list); + INIT_LIST_HEAD(&hdm_ch->started_list); + hdm_ch->is_initialized = false; + snprintf(hdm_ch->name, sizeof(hdm_ch->name), "ca%d", i * 2 + 2); + + cap->name_suffix = hdm_ch->name; + cap->direction = MOST_CH_RX | MOST_CH_TX; + cap->data_type = MOST_CH_CONTROL | MOST_CH_ASYNC | + MOST_CH_ISOC_AVP | MOST_CH_SYNC; + cap->num_buffers_packet = MAX_BUFFERS_PACKET; + cap->buffer_size_packet = MAX_BUF_SIZE_PACKET; + cap->num_buffers_streaming = MAX_BUFFERS_STREAMING; + cap->buffer_size_streaming = MAX_BUF_SIZE_STREAMING; + } + + { + const char *fmt; + + if (sizeof(res->start) == sizeof(long long)) + fmt = "dim2-%016llx"; + else if (sizeof(res->start) == sizeof(long)) + fmt = "dim2-%016lx"; + else + fmt = "dim2-%016x"; + + snprintf(dev->name, sizeof(dev->name), fmt, res->start); + } + + dev->most_iface.interface = ITYPE_MEDIALB_DIM2; + dev->most_iface.description = dev->name; + dev->most_iface.num_channels = DMA_CHANNELS; + dev->most_iface.channel_vector = dev->capabilities; + dev->most_iface.configure = configure_channel; + dev->most_iface.enqueue = enqueue; + dev->most_iface.poison_channel = poison_channel; + dev->most_iface.request_netinfo = request_netinfo; + + kobj = most_register_interface(&dev->most_iface); + if (IS_ERR(kobj)) { + ret = PTR_ERR(kobj); + pr_err("failed to register MOST interface\n"); + goto err_stop_thread; + } + + ret = dim2_sysfs_probe(&dev->bus, kobj); + if (ret) + goto err_unreg_iface; + + ret = startup_dim(pdev); + if (ret) { + pr_err("failed to initialize DIM2\n"); + goto err_destroy_bus; + } + + return 0; + +err_destroy_bus: + dim2_sysfs_destroy(&dev->bus); +err_unreg_iface: + most_deregister_interface(&dev->most_iface); +err_stop_thread: + kthread_stop(dev->netinfo_task); +err_free_irq: +#if !defined(ENABLE_HDM_TEST) + free_irq(dev->irq_ahb0, dev); +err_unmap_io: + iounmap(dev->io_base); +err_release_mem: + release_mem_region(res->start, resource_size(res)); +err_free_dev: +#endif + kfree(dev); + + return ret; +} + +/** + * dim2_remove - dim2 remove handler + * @pdev: platform device structure + * + * Unregister the interface from mostcore + */ +static int dim2_remove(struct platform_device *pdev) +{ + struct dim2_hdm *dev = platform_get_drvdata(pdev); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct dim2_platform_data *pdata = pdev->dev.platform_data; + unsigned long flags; + + spin_lock_irqsave(&dim_lock, flags); + DIM_Shutdown(); + spin_unlock_irqrestore(&dim_lock, flags); + + if (pdata && pdata->destroy) + pdata->destroy(pdata); + + dim2_sysfs_destroy(&dev->bus); + most_deregister_interface(&dev->most_iface); + kthread_stop(dev->netinfo_task); +#if !defined(ENABLE_HDM_TEST) + free_irq(dev->irq_ahb0, dev); + iounmap(dev->io_base); + release_mem_region(res->start, resource_size(res)); +#endif + kfree(dev); + platform_set_drvdata(pdev, NULL); + + /* + * break link to local platform_device_id struct + * to prevent crash by unload platform device module + */ + pdev->id_entry = 0; + + return 0; +} + +static struct platform_device_id dim2_id[] = { + { "medialb_dim2" }, + { }, /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(platform, dim2_id); + +static struct platform_driver dim2_driver = { + .probe = dim2_probe, + .remove = dim2_remove, + .id_table = dim2_id, + .driver = { + .name = "hdm_dim2", + .owner = THIS_MODULE, + }, +}; + +/** + * dim2_hdm_init - Driver Registration Routine + */ +static int __init dim2_hdm_init(void) +{ + pr_info("dim2_hdm_init()\n"); + return platform_driver_register(&dim2_driver); +} + +/** + * dim2_hdm_exit - Driver Cleanup Routine + **/ +static void __exit dim2_hdm_exit(void) +{ + pr_info("dim2_hdm_exit()\n"); + platform_driver_unregister(&dim2_driver); +} + +module_init(dim2_hdm_init); +module_exit(dim2_hdm_exit); + +MODULE_AUTHOR("Jain Roy Ambi "); +MODULE_AUTHOR("Andrey Shvetsov "); +MODULE_DESCRIPTION("MediaLB DIM2 Hardware Dependent Module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/most/hdm-dim2/dim2_hdm.h b/drivers/staging/most/hdm-dim2/dim2_hdm.h new file mode 100644 index 000000000000..6e6883232809 --- /dev/null +++ b/drivers/staging/most/hdm-dim2/dim2_hdm.h @@ -0,0 +1,26 @@ +/* + * dim2_hdm.h - MediaLB DIM2 HDM Header + * + * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#ifndef DIM2_HDM_H +#define DIM2_HDM_H + +struct device; + +/* platform dependent data for dim2 interface */ +struct dim2_platform_data { + int (*init)(struct dim2_platform_data *pd, void *io_base, int clk_speed); + void (*destroy)(struct dim2_platform_data *pd); + void *priv; +}; + +#endif /* DIM2_HDM_H */ diff --git a/drivers/staging/most/hdm-dim2/dim2_reg.h b/drivers/staging/most/hdm-dim2/dim2_reg.h new file mode 100644 index 000000000000..476f66f4c566 --- /dev/null +++ b/drivers/staging/most/hdm-dim2/dim2_reg.h @@ -0,0 +1,176 @@ +/* + * dim2_reg.h - Definitions for registers of DIM2 + * (MediaLB, Device Interface Macro IP, OS62420) + * + * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#ifndef DIM2_OS62420_H +#define DIM2_OS62420_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +struct dim2_regs { + /* 0x00 */ u32 MLBC0; + /* 0x01 */ u32 rsvd0[1]; + /* 0x02 */ u32 MLBPC0; + /* 0x03 */ u32 MS0; + /* 0x04 */ u32 rsvd1[1]; + /* 0x05 */ u32 MS1; + /* 0x06 */ u32 rsvd2[2]; + /* 0x08 */ u32 MSS; + /* 0x09 */ u32 MSD; + /* 0x0A */ u32 rsvd3[1]; + /* 0x0B */ u32 MIEN; + /* 0x0C */ u32 rsvd4[1]; + /* 0x0D */ u32 MLBPC2; + /* 0x0E */ u32 MLBPC1; + /* 0x0F */ u32 MLBC1; + /* 0x10 */ u32 rsvd5[0x10]; + /* 0x20 */ u32 HCTL; + /* 0x21 */ u32 rsvd6[1]; + /* 0x22 */ u32 HCMR0; + /* 0x23 */ u32 HCMR1; + /* 0x24 */ u32 HCER0; + /* 0x25 */ u32 HCER1; + /* 0x26 */ u32 HCBR0; + /* 0x27 */ u32 HCBR1; + /* 0x28 */ u32 rsvd7[8]; + /* 0x30 */ u32 MDAT0; + /* 0x31 */ u32 MDAT1; + /* 0x32 */ u32 MDAT2; + /* 0x33 */ u32 MDAT3; + /* 0x34 */ u32 MDWE0; + /* 0x35 */ u32 MDWE1; + /* 0x36 */ u32 MDWE2; + /* 0x37 */ u32 MDWE3; + /* 0x38 */ u32 MCTL; + /* 0x39 */ u32 MADR; + /* 0x3A */ u32 rsvd8[0xB6]; + /* 0xF0 */ u32 ACTL; + /* 0xF1 */ u32 rsvd9[3]; + /* 0xF4 */ u32 ACSR0; + /* 0xF5 */ u32 ACSR1; + /* 0xF6 */ u32 ACMR0; + /* 0xF7 */ u32 ACMR1; +}; + + +#define DIM2_MASK(n) (~((~(u32)0)<<(n))) + +enum { + MLBC0_MLBLK_BIT = 7, + + MLBC0_MLBPEN_BIT = 5, + + MLBC0_MLBCLK_SHIFT = 2, + MLBC0_MLBCLK_VAL_256FS = 0, + MLBC0_MLBCLK_VAL_512FS = 1, + MLBC0_MLBCLK_VAL_1024FS = 2, + MLBC0_MLBCLK_VAL_2048FS = 3, + + MLBC0_FCNT_SHIFT = 15, + MLBC0_FCNT_MASK = 7, + MLBC0_FCNT_VAL_1FPSB = 0, + MLBC0_FCNT_VAL_2FPSB = 1, + MLBC0_FCNT_VAL_4FPSB = 2, + MLBC0_FCNT_VAL_8FPSB = 3, + MLBC0_FCNT_VAL_16FPSB = 4, + MLBC0_FCNT_VAL_32FPSB = 5, + MLBC0_FCNT_VAL_64FPSB = 6, + + MLBC0_MLBEN_BIT = 0, + + MIEN_CTX_BREAK_BIT = 29, + MIEN_CTX_PE_BIT = 28, + MIEN_CTX_DONE_BIT = 27, + + MIEN_CRX_BREAK_BIT = 26, + MIEN_CRX_PE_BIT = 25, + MIEN_CRX_DONE_BIT = 24, + + MIEN_ATX_BREAK_BIT = 22, + MIEN_ATX_PE_BIT = 21, + MIEN_ATX_DONE_BIT = 20, + + MIEN_ARX_BREAK_BIT = 19, + MIEN_ARX_PE_BIT = 18, + MIEN_ARX_DONE_BIT = 17, + + MIEN_SYNC_PE_BIT = 16, + + MIEN_ISOC_BUFO_BIT = 1, + MIEN_ISOC_PE_BIT = 0, + + MLBC1_NDA_SHIFT = 8, + MLBC1_NDA_MASK = 0xFF, + + MLBC1_CLKMERR_BIT = 7, + MLBC1_LOCKERR_BIT = 6, + + ACTL_DMA_MODE_BIT = 2, + ACTL_DMA_MODE_VAL_DMA_MODE_0 = 0, + ACTL_DMA_MODE_VAL_DMA_MODE_1 = 1, + ACTL_SCE_BIT = 0, + + HCTL_EN_BIT = 15 +}; + +enum { + CDT1_BS_ISOC_SHIFT = 0, + CDT1_BS_ISOC_MASK = DIM2_MASK(9), + + CDT3_BD_SHIFT = 0, + CDT3_BD_MASK = DIM2_MASK(12), + CDT3_BD_ISOC_MASK = DIM2_MASK(13), + CDT3_BA_SHIFT = 16, + + ADT0_CE_BIT = 15, + ADT0_LE_BIT = 14, + ADT0_PG_BIT = 13, + + ADT1_RDY_BIT = 15, + ADT1_DNE_BIT = 14, + ADT1_ERR_BIT = 13, + ADT1_PS_BIT = 12, + ADT1_MEP_BIT = 11, + ADT1_BD_SHIFT = 0, + ADT1_CTRL_ASYNC_BD_MASK = DIM2_MASK(11), + ADT1_ISOC_SYNC_BD_MASK = DIM2_MASK(13), + + CAT_MFE_BIT = 14, + + CAT_MT_BIT = 13, + + CAT_RNW_BIT = 12, + + CAT_CE_BIT = 11, + + CAT_CT_SHIFT = 8, + CAT_CT_VAL_SYNC = 0, + CAT_CT_VAL_CONTROL = 1, + CAT_CT_VAL_ASYNC = 2, + CAT_CT_VAL_ISOC = 3, + + CAT_CL_SHIFT = 0, + CAT_CL_MASK = DIM2_MASK(6) +}; + + +#ifdef __cplusplus +} +#endif + +#endif /* DIM2_OS62420_H */ diff --git a/drivers/staging/most/hdm-dim2/dim2_sysfs.c b/drivers/staging/most/hdm-dim2/dim2_sysfs.c new file mode 100644 index 000000000000..8e331a286fc3 --- /dev/null +++ b/drivers/staging/most/hdm-dim2/dim2_sysfs.c @@ -0,0 +1,116 @@ +/* + * dim2_sysfs.c - MediaLB sysfs information + * + * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +/* Author: Andrey Shvetsov */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include "dim2_sysfs.h" + +struct bus_attr { + struct attribute attr; + ssize_t (*show)(struct medialb_bus *bus, char *buf); + ssize_t (*store)(struct medialb_bus *bus, const char *buf, size_t count); +}; + +static ssize_t state_show(struct medialb_bus *bus, char *buf) +{ + bool state = dim2_sysfs_get_state_cb(); + + return sprintf(buf, "%s\n", state ? "locked" : ""); +} + +static struct bus_attr state_attr = __ATTR_RO(state); + +static struct attribute *bus_default_attrs[] = { + &state_attr.attr, + NULL, +}; + +static struct attribute_group bus_attr_group = { + .attrs = bus_default_attrs, +}; + +static void bus_kobj_release(struct kobject *kobj) +{ +} + +static ssize_t bus_kobj_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct medialb_bus *bus = + container_of(kobj, struct medialb_bus, kobj_group); + struct bus_attr *xattr = container_of(attr, struct bus_attr, attr); + + if (!xattr->show) + return -EIO; + + return xattr->show(bus, buf); +} + +static ssize_t bus_kobj_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + ssize_t ret; + struct medialb_bus *bus = + container_of(kobj, struct medialb_bus, kobj_group); + struct bus_attr *xattr = container_of(attr, struct bus_attr, attr); + + if (!xattr->store) + return -EIO; + + ret = xattr->store(bus, buf, count); + return ret; +} + +static struct sysfs_ops const bus_kobj_sysfs_ops = { + .show = bus_kobj_attr_show, + .store = bus_kobj_attr_store, +}; + +static struct kobj_type bus_ktype = { + .release = bus_kobj_release, + .sysfs_ops = &bus_kobj_sysfs_ops, +}; + +int dim2_sysfs_probe(struct medialb_bus *bus, struct kobject *parent_kobj) +{ + int err; + + kobject_init(&bus->kobj_group, &bus_ktype); + err = kobject_add(&bus->kobj_group, parent_kobj, "bus"); + if (err) { + pr_err("kobject_add() failed: %d\n", err); + goto err_kobject_add; + } + + err = sysfs_create_group(&bus->kobj_group, &bus_attr_group); + if (err) { + pr_err("sysfs_create_group() failed: %d\n", err); + goto err_create_group; + } + + return 0; + +err_create_group: + kobject_put(&bus->kobj_group); + +err_kobject_add: + return err; +} + +void dim2_sysfs_destroy(struct medialb_bus *bus) +{ + kobject_put(&bus->kobj_group); +} diff --git a/drivers/staging/most/hdm-dim2/dim2_sysfs.h b/drivers/staging/most/hdm-dim2/dim2_sysfs.h new file mode 100644 index 000000000000..e719691035b0 --- /dev/null +++ b/drivers/staging/most/hdm-dim2/dim2_sysfs.h @@ -0,0 +1,39 @@ +/* + * dim2_sysfs.h - MediaLB sysfs information + * + * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +/* Author: Andrey Shvetsov */ + +#ifndef DIM2_SYSFS_H +#define DIM2_SYSFS_H + + +#include + + +struct medialb_bus { + struct kobject kobj_group; +}; + +struct dim2_hdm; + +int dim2_sysfs_probe(struct medialb_bus *bus, struct kobject *parent_kobj); +void dim2_sysfs_destroy(struct medialb_bus *bus); + +/* + * callback, + * must deliver MediaLB state as true if locked or false if unlocked + */ +bool dim2_sysfs_get_state_cb(void); + + +#endif /* DIM2_SYSFS_H */ -- cgit v1.3-6-gb490 From 91a450ada852f8cb5fc8b9c7242a856cc7b31643 Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Fri, 24 Jul 2015 16:11:54 +0200 Subject: Staging: most: add MOST driver's hdm-i2c module This patch adds the hdm-i2c module of the MOST driver to the kernel's driver staging area. This module is part of the MOST driver and handles the I2C interface of the MOST network interface controller. This patch is needed in order to use the I2C peripheral interface of the network interface controller. Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/Kconfig | 2 + drivers/staging/most/Makefile | 1 + drivers/staging/most/hdm-i2c/Kconfig | 12 + drivers/staging/most/hdm-i2c/Makefile | 3 + drivers/staging/most/hdm-i2c/hdm_i2c.c | 451 +++++++++++++++++++++++++++++++++ 5 files changed, 469 insertions(+) create mode 100644 drivers/staging/most/hdm-i2c/Kconfig create mode 100644 drivers/staging/most/hdm-i2c/Makefile create mode 100644 drivers/staging/most/hdm-i2c/hdm_i2c.c (limited to 'drivers') diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig index 659c40261720..2a9f92669161 100644 --- a/drivers/staging/most/Kconfig +++ b/drivers/staging/most/Kconfig @@ -23,4 +23,6 @@ source "drivers/staging/most/aim-v4l2/Kconfig" source "drivers/staging/most/hdm-dim2/Kconfig" +source "drivers/staging/most/hdm-i2c/Kconfig" + endif diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile index 7c68b3b50b10..5056f2c8672a 100644 --- a/drivers/staging/most/Makefile +++ b/drivers/staging/most/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_AIM_NETWORK) += aim-network/ obj-$(CONFIG_AIM_SOUND) += aim-sound/ obj-$(CONFIG_AIM_V4L2) += aim-v4l2/ obj-$(CONFIG_HDM_DIM2) += hdm-dim2/ +obj-$(CONFIG_HDM_I2C) += hdm-i2c/ diff --git a/drivers/staging/most/hdm-i2c/Kconfig b/drivers/staging/most/hdm-i2c/Kconfig new file mode 100644 index 000000000000..6fd7983668ad --- /dev/null +++ b/drivers/staging/most/hdm-i2c/Kconfig @@ -0,0 +1,12 @@ +# +# MOST I2C configuration +# + +config HDM_I2C + tristate "I2C HDM" + depends on I2C + ---help--- + Say Y here if you want to connect via I2C to network tranceiver. + + To compile this driver as a module, choose M here: the + module will be called hdm_i2c. diff --git a/drivers/staging/most/hdm-i2c/Makefile b/drivers/staging/most/hdm-i2c/Makefile new file mode 100644 index 000000000000..03a4a59b1f9f --- /dev/null +++ b/drivers/staging/most/hdm-i2c/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_HDM_I2C) += hdm_i2c.o + +ccflags-y += -Idrivers/staging/most/mostcore/ diff --git a/drivers/staging/most/hdm-i2c/hdm_i2c.c b/drivers/staging/most/hdm-i2c/hdm_i2c.c new file mode 100644 index 000000000000..029ded3f250b --- /dev/null +++ b/drivers/staging/most/hdm-i2c/hdm_i2c.c @@ -0,0 +1,451 @@ +/* + * hdm_i2c.c - Hardware Dependent Module for I2C Interface + * + * Copyright (C) 2013-2015, Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include + +enum { CH_RX, CH_TX, NUM_CHANNELS }; + +#define MAX_BUFFERS_CONTROL 32 +#define MAX_BUF_SIZE_CONTROL 256 + +/** + * list_first_mbo - get the first mbo from a list + * @ptr: the list head to take the mbo from. + */ +#define list_first_mbo(ptr) \ + list_first_entry(ptr, struct mbo, list) + + +/* IRQ / Polling option */ +static bool polling_req; +module_param(polling_req, bool, S_IRUGO); +MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)"); + +/* Polling Rate */ +static int scan_rate = 100; +module_param(scan_rate, int, 0644); +MODULE_PARM_DESC(scan_rate, "Polling rate in times/sec. Default = 100"); + +struct hdm_i2c { + bool is_open[NUM_CHANNELS]; + bool polling_mode; + struct most_interface most_iface; + struct most_channel_capability capabilities[NUM_CHANNELS]; + struct i2c_client *client; + struct rx { + struct delayed_work dwork; + wait_queue_head_t waitq; + struct list_head list; + struct mutex list_mutex; + } rx; + char name[64]; +}; + +#define to_hdm(iface) container_of(iface, struct hdm_i2c, most_iface) + +/** + * configure_channel - called from MOST core to configure a channel + * @iface: interface the channel belongs to + * @channel: channel to be configured + * @channel_config: structure that holds the configuration information + * + * Return 0 on success, negative on failure. + * + * Receives configuration information from MOST core and initialize the + * corresponding channel. + */ +static int configure_channel(struct most_interface *most_iface, + int ch_idx, + struct most_channel_config *channel_config) +{ + struct hdm_i2c *dev = to_hdm(most_iface); + + BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); + BUG_ON(dev->is_open[ch_idx]); + + if (channel_config->data_type != MOST_CH_CONTROL) { + pr_err("bad data type for channel %d\n", ch_idx); + return -EPERM; + } + + if (channel_config->direction != dev->capabilities[ch_idx].direction) { + pr_err("bad direction for channel %d\n", ch_idx); + return -EPERM; + } + + if (channel_config->direction == MOST_CH_RX) { + if (dev->polling_mode) + schedule_delayed_work(&dev->rx.dwork, + msecs_to_jiffies(MSEC_PER_SEC / 4)); + } + dev->is_open[ch_idx] = true; + + return 0; +} + +/** + * enqueue - called from MOST core to enqueue a buffer for data transfer + * @iface: intended interface + * @channel: ID of the channel the buffer is intended for + * @mbo: pointer to the buffer object + * + * Return 0 on success, negative on failure. + * + * Transmit the data over I2C if it is a "write" request or push the buffer into + * list if it is an "read" request + */ +static int enqueue(struct most_interface *most_iface, + int ch_idx, struct mbo *mbo) +{ + struct hdm_i2c *dev = to_hdm(most_iface); + int ret; + + BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); + BUG_ON(!dev->is_open[ch_idx]); + + if (ch_idx == CH_RX) { + /* RX */ + mutex_lock(&dev->rx.list_mutex); + list_add_tail(&mbo->list, &dev->rx.list); + mutex_unlock(&dev->rx.list_mutex); + wake_up_interruptible(&dev->rx.waitq); + } else { + /* TX */ + ret = i2c_master_send(dev->client, mbo->virt_address, + mbo->buffer_length); + if (ret <= 0) { + mbo->processed_length = 0; + mbo->status = MBO_E_INVAL; + } else { + mbo->processed_length = mbo->buffer_length; + mbo->status = MBO_SUCCESS; + } + mbo->complete(mbo); + } + + return 0; +} + +/** + * poison_channel - called from MOST core to poison buffers of a channel + * @iface: pointer to the interface the channel to be poisoned belongs to + * @channel_id: corresponding channel ID + * + * Return 0 on success, negative on failure. + * + * If channel direction is RX, complete the buffers in list with + * status MBO_E_CLOSE + */ +static int poison_channel(struct most_interface *most_iface, + int ch_idx) +{ + struct hdm_i2c *dev = to_hdm(most_iface); + struct mbo *mbo; + + BUG_ON(ch_idx < 0 || ch_idx >= NUM_CHANNELS); + BUG_ON(!dev->is_open[ch_idx]); + + dev->is_open[ch_idx] = false; + + if (ch_idx == CH_RX) { + mutex_lock(&dev->rx.list_mutex); + while (!list_empty(&dev->rx.list)) { + mbo = list_first_mbo(&dev->rx.list); + list_del(&mbo->list); + mutex_unlock(&dev->rx.list_mutex); + + mbo->processed_length = 0; + mbo->status = MBO_E_CLOSE; + mbo->complete(mbo); + + mutex_lock(&dev->rx.list_mutex); + } + mutex_unlock(&dev->rx.list_mutex); + wake_up_interruptible(&dev->rx.waitq); + } + + return 0; +} + +static void request_netinfo(struct most_interface *most_iface, + int ch_idx) +{ + pr_info("request_netinfo()\n"); +} + +static void do_rx_work(struct hdm_i2c *dev) +{ + struct mbo *mbo; + unsigned char msg[MAX_BUF_SIZE_CONTROL]; + int ret, ch_idx = CH_RX; + uint16_t pml, data_size; + + /* Read PML (2 bytes) */ + ret = i2c_master_recv(dev->client, msg, 2); + if (ret <= 0) { + pr_err("Failed to receive PML\n"); + return; + } + + pml = (msg[0] << 8) | msg[1]; + if (!pml) + return; + + data_size = pml + 2; + + /* Read the whole message, including PML */ + ret = i2c_master_recv(dev->client, msg, data_size); + if (ret <= 0) { + pr_err("Failed to receive a Port Message\n"); + return; + } + + for (;;) { + /* Conditions to wait for: poisoned channel or free buffer + available for reading */ + if (wait_event_interruptible(dev->rx.waitq, + !dev->is_open[ch_idx] || + !list_empty(&dev->rx.list))) { + pr_err("wait_event_interruptible() failed\n"); + return; + } + + if (!dev->is_open[ch_idx]) + return; + + mutex_lock(&dev->rx.list_mutex); + + /* list may be empty if poison or remove is called */ + if (!list_empty(&dev->rx.list)) + break; + + mutex_unlock(&dev->rx.list_mutex); + } + + mbo = list_first_mbo(&dev->rx.list); + list_del(&mbo->list); + mutex_unlock(&dev->rx.list_mutex); + + mbo->processed_length = min(data_size, mbo->buffer_length); + memcpy(mbo->virt_address, msg, mbo->processed_length); + mbo->status = MBO_SUCCESS; + mbo->complete(mbo); +} + +/** + * pending_rx_work - Read pending messages through I2C + * @work: definition of this work item + * + * Invoked by the Interrupt Service Routine, most_irq_handler() + */ +static void pending_rx_work(struct work_struct *work) +{ + struct hdm_i2c *dev = container_of(work, struct hdm_i2c, rx.dwork.work); + + do_rx_work(dev); + + if (dev->polling_mode) { + if (dev->is_open[CH_RX]) + schedule_delayed_work(&dev->rx.dwork, + msecs_to_jiffies(MSEC_PER_SEC + / scan_rate)); + } else + enable_irq(dev->client->irq); +} + +/* + * most_irq_handler - Interrupt Service Routine + * @irq: irq number + * @_dev: private data + * + * Schedules a delayed work + * + * By default the interrupt line behavior is Active Low. Once an interrupt is + * generated by the device, until driver clears the interrupt (by reading + * the PMP message), device keeps the interrupt line in low state. Since i2c + * read is done in work queue, the interrupt line must be disabled temporarily + * to avoid ISR being called repeatedly. Re-enable the interrupt in workqueue, + * after reading the message. + * + * Note: If we use the interrupt line in Falling edge mode, there is a + * possibility to miss interrupts when ISR is getting executed. + * + */ +static irqreturn_t most_irq_handler(int irq, void *_dev) +{ + struct hdm_i2c *dev = _dev; + + disable_irq_nosync(irq); + + schedule_delayed_work(&dev->rx.dwork, 0); + + return IRQ_HANDLED; +} + +/* + * i2c_probe - i2c probe handler + * @client: i2c client device structure + * @id: i2c client device id + * + * Return 0 on success, negative on failure. + * + * Register the i2c client device as a MOST interface + */ +static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct hdm_i2c *dev; + int ret, i; + struct kobject *kobj; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + /* ID format: i2c--
*/ + snprintf(dev->name, sizeof(dev->name), "i2c-%d-%04x", + client->adapter->nr, client->addr); + + for (i = 0; i < NUM_CHANNELS; i++) { + dev->is_open[i] = false; + dev->capabilities[i].data_type = MOST_CH_CONTROL; + dev->capabilities[i].num_buffers_packet = MAX_BUFFERS_CONTROL; + dev->capabilities[i].buffer_size_packet = MAX_BUF_SIZE_CONTROL; + } + dev->capabilities[CH_RX].direction = MOST_CH_RX; + dev->capabilities[CH_RX].name_suffix = "rx"; + dev->capabilities[CH_TX].direction = MOST_CH_TX; + dev->capabilities[CH_TX].name_suffix = "tx"; + + dev->most_iface.interface = ITYPE_I2C; + dev->most_iface.description = dev->name; + dev->most_iface.num_channels = NUM_CHANNELS; + dev->most_iface.channel_vector = dev->capabilities; + dev->most_iface.configure = configure_channel; + dev->most_iface.enqueue = enqueue; + dev->most_iface.poison_channel = poison_channel; + dev->most_iface.request_netinfo = request_netinfo; + + INIT_LIST_HEAD(&dev->rx.list); + mutex_init(&dev->rx.list_mutex); + init_waitqueue_head(&dev->rx.waitq); + + INIT_DELAYED_WORK(&dev->rx.dwork, pending_rx_work); + + dev->client = client; + i2c_set_clientdata(client, dev); + + kobj = most_register_interface(&dev->most_iface); + if (IS_ERR(kobj)) { + pr_err("Failed to register i2c as a MOST interface\n"); + kfree(dev); + return PTR_ERR(kobj); + } + + dev->polling_mode = polling_req || client->irq <= 0; + if (!dev->polling_mode) { + pr_info("Requesting IRQ: %d\n", client->irq); + ret = request_irq(client->irq, most_irq_handler, IRQF_SHARED, + client->name, dev); + if (ret) { + pr_info("IRQ request failed: %d, " + "falling back to polling\n", ret); + dev->polling_mode = true; + } + } + + if (dev->polling_mode) + pr_info("Using polling at rate: %d times/sec\n", scan_rate); + + return 0; +} + +/* + * i2c_remove - i2c remove handler + * @client: i2c client device structure + * + * Return 0 on success. + * + * Unregister the i2c client device as a MOST interface + */ +static int i2c_remove(struct i2c_client *client) +{ + struct hdm_i2c *dev = i2c_get_clientdata(client); + int i; + + if (!dev->polling_mode) + free_irq(client->irq, dev); + + most_deregister_interface(&dev->most_iface); + + for (i = 0 ; i < NUM_CHANNELS; i++) + if (dev->is_open[i]) + poison_channel(&dev->most_iface, i); + cancel_delayed_work_sync(&dev->rx.dwork); + kfree(dev); + + return 0; +} + +static const struct i2c_device_id i2c_id[] = { + { "most_i2c", 0 }, + { }, /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(i2c, i2c_id); + +static struct i2c_driver i2c_driver = { + .driver = { + .name = "hdm_i2c", + .owner = THIS_MODULE, + }, + .probe = i2c_probe, + .remove = i2c_remove, + .id_table = i2c_id, +}; + +/** + * hdm_i2c_init - Driver Registration Routine + */ +static int __init hdm_i2c_init(void) +{ + pr_info("hdm_i2c_init()\n"); + + return i2c_add_driver(&i2c_driver); +} + +/** + * hdm_i2c_exit - Driver Cleanup Routine + **/ +static void __exit hdm_i2c_exit(void) +{ + i2c_del_driver(&i2c_driver); + pr_info("hdm_i2c_exit()\n"); +} + +module_init(hdm_i2c_init); +module_exit(hdm_i2c_exit); + +MODULE_AUTHOR("Jain Roy Ambi "); +MODULE_AUTHOR("Andrey Shvetsov "); +MODULE_DESCRIPTION("I2C Hardware Dependent Module"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From a4198cdf0c3460d767d0d36979cd633021c127a2 Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Fri, 24 Jul 2015 16:11:55 +0200 Subject: Staging: most: add MOST driver's hdm-usb module This patch adds the hdm-usb module of the MOST driver to the kernel's driver staging area. This module is part of the MOST driver and handles the USB interface of the MOST network interface controller. This patch is needed in order to use the USB peripheral interface of the network interface controller. Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/Kconfig | 2 + drivers/staging/most/Makefile | 1 + drivers/staging/most/hdm-usb/Kconfig | 14 + drivers/staging/most/hdm-usb/Makefile | 4 + drivers/staging/most/hdm-usb/hdm_usb.c | 1442 ++++++++++++++++++++++++++++++++ 5 files changed, 1463 insertions(+) create mode 100644 drivers/staging/most/hdm-usb/Kconfig create mode 100644 drivers/staging/most/hdm-usb/Makefile create mode 100644 drivers/staging/most/hdm-usb/hdm_usb.c (limited to 'drivers') diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig index 2a9f92669161..d50de03de7b9 100644 --- a/drivers/staging/most/Kconfig +++ b/drivers/staging/most/Kconfig @@ -25,4 +25,6 @@ source "drivers/staging/most/hdm-dim2/Kconfig" source "drivers/staging/most/hdm-i2c/Kconfig" +source "drivers/staging/most/hdm-usb/Kconfig" + endif diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile index 5056f2c8672a..9ee981c7786b 100644 --- a/drivers/staging/most/Makefile +++ b/drivers/staging/most/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_AIM_SOUND) += aim-sound/ obj-$(CONFIG_AIM_V4L2) += aim-v4l2/ obj-$(CONFIG_HDM_DIM2) += hdm-dim2/ obj-$(CONFIG_HDM_I2C) += hdm-i2c/ +obj-$(CONFIG_HDM_USB) += hdm-usb/ diff --git a/drivers/staging/most/hdm-usb/Kconfig b/drivers/staging/most/hdm-usb/Kconfig new file mode 100644 index 000000000000..a482c3fdf34b --- /dev/null +++ b/drivers/staging/most/hdm-usb/Kconfig @@ -0,0 +1,14 @@ +# +# MOST USB configuration +# + +config HDM_USB + tristate "USB HDM" + depends on USB + select AIM_NETWORK + ---help--- + Say Y here if you want to connect via USB to network tranceiver. + This device driver depends on the networking AIM. + + To compile this driver as a module, choose M here: the + module will be called hdm_usb. diff --git a/drivers/staging/most/hdm-usb/Makefile b/drivers/staging/most/hdm-usb/Makefile new file mode 100644 index 000000000000..6bbacb41e94b --- /dev/null +++ b/drivers/staging/most/hdm-usb/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_HDM_USB) += hdm_usb.o + +ccflags-y += -Idrivers/staging/most/mostcore/ +ccflags-y += -Idrivers/staging/most/aim-network/ diff --git a/drivers/staging/most/hdm-usb/hdm_usb.c b/drivers/staging/most/hdm-usb/hdm_usb.c new file mode 100644 index 000000000000..a4a3e266b3ef --- /dev/null +++ b/drivers/staging/most/hdm-usb/hdm_usb.c @@ -0,0 +1,1442 @@ +/* + * hdm_usb.c - Hardware dependent module for USB + * + * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG + * + * 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. + * + * This file is licensed under GPLv2. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mostcore.h" +#include "networking.h" + +#define USB_MTU 512 +#define NO_ISOCHRONOUS_URB 0 +#define AV_PACKETS_PER_XACT 2 +#define BUF_CHAIN_SIZE 0xFFFF +#define MAX_NUM_ENDPOINTS 30 +#define MAX_SUFFIX_LEN 10 +#define MAX_STRING_LEN 80 +#define MAX_BUF_SIZE 0xFFFF +#define CEILING(x, y) (((x) + (y) - 1) / (y)) + +#define USB_VENDOR_ID_SMSC 0x0424 /* VID: SMSC */ +#define USB_DEV_ID_BRDG 0xC001 /* PID: USB Bridge */ +#define USB_DEV_ID_INIC 0xCF18 /* PID: USB INIC */ +/* DRCI Addresses */ +#define DRCI_REG_NI_STATE 0x0100 +#define DRCI_REG_PACKET_BW 0x0101 +#define DRCI_REG_NODE_ADDR 0x0102 +#define DRCI_REG_NODE_POS 0x0103 +#define DRCI_REG_MEP_FILTER 0x0140 +#define DRCI_REG_HASH_TBL0 0x0141 +#define DRCI_REG_HASH_TBL1 0x0142 +#define DRCI_REG_HASH_TBL2 0x0143 +#define DRCI_REG_HASH_TBL3 0x0144 +#define DRCI_REG_HW_ADDR_HI 0x0145 +#define DRCI_REG_HW_ADDR_MI 0x0146 +#define DRCI_REG_HW_ADDR_LO 0x0147 +#define DRCI_READ_REQ 0xA0 +#define DRCI_WRITE_REQ 0xA1 + +/** + * struct buf_anchor - used to create a list of pending URBs + * @urb: pointer to USB request block + * @clear_work_obj: + * @list: linked list + * @urb_completion: + */ +struct buf_anchor { + struct urb *urb; + struct work_struct clear_work_obj; + struct list_head list; + struct completion urb_compl; +}; +#define to_buf_anchor(w) container_of(w, struct buf_anchor, clear_work_obj) + +/** + * struct most_dci_obj - Direct Communication Interface + * @kobj:position in sysfs + * @usb_device: pointer to the usb device + */ +struct most_dci_obj { + struct kobject kobj; + struct usb_device *usb_device; +}; +#define to_dci_obj(p) container_of(p, struct most_dci_obj, kobj) + +/** + * struct most_dev - holds all usb interface specific stuff + * @parent: parent object in sysfs + * @usb_device: pointer to usb device + * @iface: hardware interface + * @cap: channel capabilities + * @conf: channel configuration + * @dci: direct communication interface of hardware + * @hw_addr: MAC address of hardware + * @ep_address: endpoint address table + * @link_stat: link status of hardware + * @description: device description + * @suffix: suffix for channel name + * @anchor_list_lock: locks list access + * @padding_active: indicates channel uses padding + * @is_channel_healthy: health status table of each channel + * @anchor_list: list of anchored items + * @io_mutex: synchronize I/O with disconnect + * @link_stat_timer: timer for link status reports + * @poll_work_obj: work for polling link status + */ +struct most_dev { + struct kobject *parent; + struct usb_device *usb_device; + struct most_interface iface; + struct most_channel_capability *cap; + struct most_channel_config *conf; + struct most_dci_obj *dci; + u8 hw_addr[6]; + u8 *ep_address; + u16 link_stat; + char description[MAX_STRING_LEN]; + char suffix[MAX_NUM_ENDPOINTS][MAX_SUFFIX_LEN]; + spinlock_t anchor_list_lock[MAX_NUM_ENDPOINTS]; + bool padding_active[MAX_NUM_ENDPOINTS]; + bool is_channel_healthy[MAX_NUM_ENDPOINTS]; + struct list_head *anchor_list; + struct mutex io_mutex; + struct timer_list link_stat_timer; + struct work_struct poll_work_obj; +}; +#define to_mdev(d) container_of(d, struct most_dev, iface) +#define to_mdev_from_work(w) container_of(w, struct most_dev, poll_work_obj) + +static struct workqueue_struct *schedule_usb_work; +static void wq_clear_halt(struct work_struct *wq_obj); +static void wq_netinfo(struct work_struct *wq_obj); + +/** + * trigger_resync_vr - Vendor request to trigger HW re-sync mechanism + * @dev: usb device + * + */ +static inline void trigger_resync_vr(struct usb_device *dev) +{ + int data = 0; + + if (0 > usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, + 0, + 0, + &data, + 0, + 5 * HZ)) + pr_info("Vendor request \"stall\" failed\n"); +} + +/** + * drci_rd_reg - read a DCI register + * @dev: usb device + * @reg: register address + * @buf: buffer to store data + * + * This is reads data from INIC's direct register communication interface + */ +static inline int drci_rd_reg(struct usb_device *dev, u16 reg, void *buf) +{ + return usb_control_msg(dev, + usb_rcvctrlpipe(dev, 0), + DRCI_READ_REQ, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x0000, + reg, + buf, + 2, + 5 * HZ); +} + +/** + * drci_wr_reg - write a DCI register + * @dev: usb device + * @reg: register address + * @data: data to write + * + * This is writes data to INIC's direct register communication interface + */ +static inline int drci_wr_reg(struct usb_device *dev, u16 reg, u16 data) +{ + return usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + DRCI_WRITE_REQ, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + data, + reg, + NULL, + 0, + 5 * HZ); +} + +/** + * free_anchored_buffers - free device's anchored items + * @mdev: the device + * @channel: channel ID + */ +static void free_anchored_buffers(struct most_dev *mdev, unsigned int channel) +{ + struct mbo *mbo; + struct buf_anchor *anchor, *tmp; + unsigned long flags; + + spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); + list_for_each_entry_safe(anchor, tmp, &mdev->anchor_list[channel], list) { + struct urb *urb = anchor->urb; + + spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); + if (likely(urb)) { + mbo = urb->context; + if (!irqs_disabled()) { + usb_kill_urb(urb); + } else { + usb_unlink_urb(urb); + wait_for_completion(&anchor->urb_compl); + } + if ((mbo) && (mbo->complete)) { + mbo->status = MBO_E_CLOSE; + mbo->processed_length = 0; + mbo->complete(mbo); + } + usb_free_urb(urb); + } + spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); + list_del(&anchor->list); + kfree(anchor); + } + spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); +} + +/** + * get_stream_frame_size - calculate frame size of current configuration + * @cfg: channel configuration + */ +static unsigned int get_stream_frame_size(struct most_channel_config *cfg) +{ + unsigned int frame_size = 0; + unsigned int sub_size = cfg->subbuffer_size; + + if (!sub_size) { + pr_info("Misconfig: Subbuffer size zero.\n"); + return frame_size; + } + switch (cfg->data_type) { + case MOST_CH_ISOC_AVP: + frame_size = AV_PACKETS_PER_XACT * sub_size; + break; + case MOST_CH_SYNC: + if (cfg->packets_per_xact == 0) { + pr_info("Misconfig: Packets per XACT zero\n"); + frame_size = 0; + } else if (cfg->packets_per_xact == 0xFF) + frame_size = (USB_MTU / sub_size) * sub_size; + else + frame_size = cfg->packets_per_xact * sub_size; + break; + default: + pr_warn("Query frame size of non-streaming channel\n"); + break; + } + return frame_size; +} + +/** + * hdm_poison_channel - mark buffers of this channel as invalid + * @iface: pointer to the interface + * @channel: channel ID + * + * This unlinks all URBs submitted to the HCD, + * calls the associated completion function of the core and removes + * them from the list. + * + * Returns 0 on success or error code otherwise. + */ +int hdm_poison_channel(struct most_interface *iface, int channel) +{ + struct most_dev *mdev; + + if (unlikely(!iface)) { + pr_info("Poison: Bad interface.\n"); + return -EIO; + } + if (unlikely((channel < 0) || (channel >= iface->num_channels))) { + pr_info("Channel ID out of range.\n"); + return -ECHRNG; + } + + mdev = to_mdev(iface); + mdev->is_channel_healthy[channel] = false; + + mutex_lock(&mdev->io_mutex); + free_anchored_buffers(mdev, channel); + if (mdev->padding_active[channel] == true) + mdev->padding_active[channel] = false; + + if (mdev->conf[channel].data_type == MOST_CH_ASYNC) { + del_timer_sync(&mdev->link_stat_timer); + cancel_work_sync(&mdev->poll_work_obj); + } + mutex_unlock(&mdev->io_mutex); + return 0; +} + +/** + * hdm_add_padding - add padding bytes + * @mdev: most device + * @channel: channel ID + * @mbo: buffer object + * + * This inserts the INIC hardware specific padding bytes into a streaming + * channel's buffer + */ +int hdm_add_padding(struct most_dev *mdev, int channel, struct mbo *mbo) +{ + struct most_channel_config *conf = &mdev->conf[channel]; + unsigned int j, num_frames, frame_size; + u16 rd_addr, wr_addr; + + frame_size = get_stream_frame_size(conf); + if (!frame_size) + return -EIO; + num_frames = mbo->buffer_length / frame_size; + + if (num_frames < 1) { + pr_err("Missed minimal transfer unit.\n"); + return -EIO; + } + + for (j = 1; j < num_frames; j++) { + wr_addr = (num_frames - j) * USB_MTU; + rd_addr = (num_frames - j) * frame_size; + memmove(mbo->virt_address + wr_addr, + mbo->virt_address + rd_addr, + frame_size); + } + mbo->buffer_length = num_frames * USB_MTU; + return 0; +} + +/** + * hdm_remove_padding - remove padding bytes + * @mdev: most device + * @channel: channel ID + * @mbo: buffer object + * + * This takes the INIC hardware specific padding bytes off a streaming + * channel's buffer. + */ +int hdm_remove_padding(struct most_dev *mdev, int channel, struct mbo *mbo) +{ + unsigned int j, num_frames, frame_size; + struct most_channel_config *const conf = &mdev->conf[channel]; + + frame_size = get_stream_frame_size(conf); + if (!frame_size) + return -EIO; + num_frames = mbo->processed_length / USB_MTU; + + for (j = 1; j < num_frames; j++) + memmove(mbo->virt_address + frame_size * j, + mbo->virt_address + USB_MTU * j, + frame_size); + + mbo->processed_length = frame_size * num_frames; + return 0; +} + +/** + * hdm_write_completion - completion function for submitted Tx URBs + * @urb: the URB that has been completed + * + * This checks the status of the completed URB. In case the URB has been + * unlinked before, it is immediately freed. On any other error the MBO + * transfer flag is set. On success it frees allocated resources and calls + * the completion function. + * + * Context: interrupt! + */ +static void hdm_write_completion(struct urb *urb) +{ + struct mbo *mbo; + struct buf_anchor *anchor; + struct most_dev *mdev; + unsigned int channel; + unsigned long flags; + + mbo = urb->context; + anchor = mbo->priv; + mdev = to_mdev(mbo->ifp); + channel = mbo->hdm_channel_id; + + if ((urb->status == -ENOENT) || (urb->status == -ECONNRESET) || + (mdev->is_channel_healthy[channel] == false)) { + complete(&anchor->urb_compl); + return; + } + + if (unlikely(urb->status && !(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN))) { + mbo->processed_length = 0; + switch (urb->status) { + case -EPIPE: + pr_info("Broken OUT pipe detected\n"); + most_stop_enqueue(&mdev->iface, channel); + mbo->status = MBO_E_INVAL; + usb_unlink_urb(urb); + INIT_WORK(&anchor->clear_work_obj, wq_clear_halt); + queue_work(schedule_usb_work, &anchor->clear_work_obj); + return; + case -ENODEV: + case -EPROTO: + mbo->status = MBO_E_CLOSE; + break; + default: + mbo->status = MBO_E_INVAL; + break; + } + } else { + mbo->status = MBO_SUCCESS; + mbo->processed_length = urb->actual_length; + } + + spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); + list_del(&anchor->list); + spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); + kfree(anchor); + + if (likely(mbo->complete)) + mbo->complete(mbo); + usb_free_urb(urb); +} + +/** + * hdm_read_completion - completion funciton for submitted Rx URBs + * @urb: the URB that has been completed + * + * This checks the status of the completed URB. In case the URB has been + * unlinked before it is immediately freed. On any other error the MBO transfer + * flag is set. On success it frees allocated resources, removes + * padding bytes -if necessary- and calls the completion function. + * + * Context: interrupt! + * + * ************************************************************************** + * Error codes returned by in urb->status + * or in iso_frame_desc[n].status (for ISO) + * ************************************************************************* + * + * USB device drivers may only test urb status values in completion handlers. + * This is because otherwise there would be a race between HCDs updating + * these values on one CPU, and device drivers testing them on another CPU. + * + * A transfer's actual_length may be positive even when an error has been + * reported. That's because transfers often involve several packets, so that + * one or more packets could finish before an error stops further endpoint I/O. + * + * For isochronous URBs, the urb status value is non-zero only if the URB is + * unlinked, the device is removed, the host controller is disabled or the total + * transferred length is less than the requested length and the URB_SHORT_NOT_OK + * flag is set. Completion handlers for isochronous URBs should only see + * urb->status set to zero, -ENOENT, -ECONNRESET, -ESHUTDOWN, or -EREMOTEIO. + * Individual frame descriptor status fields may report more status codes. + * + * + * 0 Transfer completed successfully + * + * -ENOENT URB was synchronously unlinked by usb_unlink_urb + * + * -EINPROGRESS URB still pending, no results yet + * (That is, if drivers see this it's a bug.) + * + * -EPROTO (*, **) a) bitstuff error + * b) no response packet received within the + * prescribed bus turn-around time + * c) unknown USB error + * + * -EILSEQ (*, **) a) CRC mismatch + * b) no response packet received within the + * prescribed bus turn-around time + * c) unknown USB error + * + * Note that often the controller hardware does not + * distinguish among cases a), b), and c), so a + * driver cannot tell whether there was a protocol + * error, a failure to respond (often caused by + * device disconnect), or some other fault. + * + * -ETIME (**) No response packet received within the prescribed + * bus turn-around time. This error may instead be + * reported as -EPROTO or -EILSEQ. + * + * -ETIMEDOUT Synchronous USB message functions use this code + * to indicate timeout expired before the transfer + * completed, and no other error was reported by HC. + * + * -EPIPE (**) Endpoint stalled. For non-control endpoints, + * reset this status with usb_clear_halt(). + * + * -ECOMM During an IN transfer, the host controller + * received data from an endpoint faster than it + * could be written to system memory + * + * -ENOSR During an OUT transfer, the host controller + * could not retrieve data from system memory fast + * enough to keep up with the USB data rate + * + * -EOVERFLOW (*) The amount of data returned by the endpoint was + * greater than either the max packet size of the + * endpoint or the remaining buffer size. "Babble". + * + * -EREMOTEIO The data read from the endpoint did not fill the + * specified buffer, and URB_SHORT_NOT_OK was set in + * urb->transfer_flags. + * + * -ENODEV Device was removed. Often preceded by a burst of + * other errors, since the hub driver doesn't detect + * device removal events immediately. + * + * -EXDEV ISO transfer only partially completed + * (only set in iso_frame_desc[n].status, not urb->status) + * + * -EINVAL ISO madness, if this happens: Log off and go home + * + * -ECONNRESET URB was asynchronously unlinked by usb_unlink_urb + * + * -ESHUTDOWN The device or host controller has been disabled due + * to some problem that could not be worked around, + * such as a physical disconnect. + * + * + * (*) Error codes like -EPROTO, -EILSEQ and -EOVERFLOW normally indicate + * hardware problems such as bad devices (including firmware) or cables. + * + * (**) This is also one of several codes that different kinds of host + * controller use to indicate a transfer has failed because of device + * disconnect. In the interval before the hub driver starts disconnect + * processing, devices may receive such fault reports for every request. + * + * See + */ +static void hdm_read_completion(struct urb *urb) +{ + struct mbo *mbo; + struct buf_anchor *anchor; + struct most_dev *mdev; + unsigned long flags; + unsigned int channel; + struct most_channel_config *conf; + + mbo = urb->context; + anchor = mbo->priv; + mdev = to_mdev(mbo->ifp); + channel = mbo->hdm_channel_id; + + if ((urb->status == -ENOENT) || (urb->status == -ECONNRESET) || + (mdev->is_channel_healthy[channel] == false)) { + complete(&anchor->urb_compl); + return; + } + + conf = &mdev->conf[channel]; + + if (unlikely(urb->status && !(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN))) { + mbo->processed_length = 0; + switch (urb->status) { + case -EPIPE: + pr_info("Broken IN pipe detected\n"); + mbo->status = MBO_E_INVAL; + usb_unlink_urb(urb); + INIT_WORK(&anchor->clear_work_obj, wq_clear_halt); + queue_work(schedule_usb_work, &anchor->clear_work_obj); + return; + case -ENODEV: + case -EPROTO: + mbo->status = MBO_E_CLOSE; + break; + case -EOVERFLOW: + pr_info("Babble on IN pipe detected\n"); + default: + mbo->status = MBO_E_INVAL; + break; + } + } else { + mbo->processed_length = urb->actual_length; + if (mdev->padding_active[channel] == false) { + mbo->status = MBO_SUCCESS; + } else { + if (hdm_remove_padding(mdev, channel, mbo)) { + mbo->processed_length = 0; + mbo->status = MBO_E_INVAL; + } else { + mbo->status = MBO_SUCCESS; + } + } + } + spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); + list_del(&anchor->list); + spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); + kfree(anchor); + + if (likely(mbo->complete)) + mbo->complete(mbo); + usb_free_urb(urb); +} + +/** + * hdm_enqueue - receive a buffer to be used for data transfer + * @iface: interface to enqueue to + * @channel: ID of the channel + * @mbo: pointer to the buffer object + * + * This allocates a new URB and fills it according to the channel + * that is being used for transmission of data. Before the URB is + * submitted it is stored in the private anchor list. + * + * Returns 0 on success. On any error the URB is freed and a error code + * is returned. + * + * Context: Could in _some_ cases be interrupt! + */ +int hdm_enqueue(struct most_interface *iface, int channel, struct mbo *mbo) +{ + struct most_dev *mdev; + struct buf_anchor *anchor; + struct most_channel_config *conf; + int retval = 0; + struct urb *urb; + unsigned long flags; + unsigned long length; + void *virt_address; + + if (unlikely(!iface || !mbo)) { + pr_info("Bad interface or MBO\n"); + return -EIO; + } + if (unlikely(iface->num_channels <= channel) || (channel < 0)) { + pr_info("Channel ID out of range\n"); + return -ECHRNG; + } + + mdev = to_mdev(iface); + conf = &mdev->conf[channel]; + + if (!mdev->usb_device) + return -ENODEV; + + urb = usb_alloc_urb(NO_ISOCHRONOUS_URB, GFP_ATOMIC); + if (!urb) { + pr_info("Failed to allocate URB\n"); + return -ENOMEM; + } + + anchor = kzalloc(sizeof(*anchor), GFP_ATOMIC); + if (!anchor) { + retval = -ENOMEM; + goto _error; + } + + anchor->urb = urb; + init_completion(&anchor->urb_compl); + mbo->priv = anchor; + + spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); + list_add_tail(&anchor->list, &mdev->anchor_list[channel]); + spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); + + if ((mdev->padding_active[channel] == true) && + (conf->direction & MOST_CH_TX)) + if (hdm_add_padding(mdev, channel, mbo)) { + retval = -EIO; + goto _error_1; + } + + urb->transfer_dma = mbo->bus_address; + virt_address = mbo->virt_address; + length = mbo->buffer_length; + + if (conf->direction & MOST_CH_TX) { + usb_fill_bulk_urb(urb, mdev->usb_device, + usb_sndbulkpipe(mdev->usb_device, + mdev->ep_address[channel]), + virt_address, + length, + hdm_write_completion, + mbo); + if (conf->data_type != MOST_CH_ISOC_AVP) + urb->transfer_flags |= URB_ZERO_PACKET; + } else { + usb_fill_bulk_urb(urb, mdev->usb_device, + usb_rcvbulkpipe(mdev->usb_device, + mdev->ep_address[channel]), + virt_address, + length, + hdm_read_completion, + mbo); + } + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + retval = usb_submit_urb(urb, GFP_KERNEL); + if (retval) { + pr_info("URB submit failed with error %d.\n", retval); + goto _error_1; + } + return 0; + +_error_1: + spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); + list_del(&anchor->list); + spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); + kfree(anchor); +_error: + usb_free_urb(urb); + return retval; +} + +/** + * hdm_configure_channel - receive channel configuration from core + * @iface: interface + * @channel: channel ID + * @conf: structure that holds the configuration information + */ +int hdm_configure_channel(struct most_interface *iface, int channel, + struct most_channel_config *conf) +{ + unsigned int num_frames; + unsigned int frame_size; + unsigned int temp_size; + unsigned int tail_space; + struct most_dev *mdev; + + if (unlikely(!iface || !conf)) { + pr_info("Bad interface or config pointer.\n"); + return -EINVAL; + } + if (unlikely((channel < 0) || (channel >= iface->num_channels))) { + pr_info("Channel ID out of range.\n"); + return -EINVAL; + } + if ((!conf->num_buffers) || (!conf->buffer_size)) { + pr_info("Misconfig: buffer size or number of buffers zero.\n"); + return -EINVAL; + } + + mdev = to_mdev(iface); + mdev->is_channel_healthy[channel] = true; + + if (!(conf->data_type == MOST_CH_SYNC) && + !((conf->data_type == MOST_CH_ISOC_AVP) && + (conf->packets_per_xact != 0xFF))) { + mdev->padding_active[channel] = false; + goto exit; + } + + mdev->padding_active[channel] = true; + temp_size = conf->buffer_size; + + if ((conf->data_type != MOST_CH_SYNC) && + (conf->data_type != MOST_CH_ISOC_AVP)) { + pr_info("Unsupported data type\n"); + return -EINVAL; + } + + frame_size = get_stream_frame_size(conf); + if ((frame_size == 0) || (frame_size > USB_MTU)) { + pr_info("Misconfig: frame size wrong\n"); + return -EINVAL; + } + + if (conf->buffer_size % frame_size) { + u16 tmp_val; + + tmp_val = conf->buffer_size / frame_size; + conf->buffer_size = tmp_val * frame_size; + pr_info("Channel %d - rouding buffer size to %d bytes," + " channel config says %d bytes", + channel, + conf->buffer_size, + temp_size); + } + + num_frames = conf->buffer_size / frame_size; + tail_space = num_frames * (USB_MTU - frame_size); + temp_size += tail_space; + + /* calculate extra length to comply w/ HW padding */ + conf->extra_len = (CEILING(temp_size, USB_MTU) * USB_MTU) + - conf->buffer_size; +exit: + mdev->conf[channel] = *conf; + return 0; +} + +/** + * hdm_update_netinfo - retrieve latest networking information + * @mdev: device interface + * + * This triggers the USB vendor requests to read the hardware address and + * the current link status of the attached device. + */ +int hdm_update_netinfo(struct most_dev *mdev) +{ + int i; + u16 link; + u8 addr[6]; + + if (!is_valid_ether_addr(mdev->hw_addr)) { + if (0 > drci_rd_reg(mdev->usb_device, + DRCI_REG_HW_ADDR_HI, addr)) { + pr_info("Vendor request \"hw_addr_hi\" failed\n"); + return -1; + } + if (0 > drci_rd_reg(mdev->usb_device, + DRCI_REG_HW_ADDR_MI, addr + 2)) { + pr_info("Vendor request \"hw_addr_mid\" failed\n"); + return -1; + } + if (0 > drci_rd_reg(mdev->usb_device, + DRCI_REG_HW_ADDR_LO, addr + 4)) { + pr_info("Vendor request \"hw_addr_low\" failed\n"); + return -1; + } + mutex_lock(&mdev->io_mutex); + for (i = 0; i < 6; i++) + mdev->hw_addr[i] = addr[i]; + mutex_unlock(&mdev->io_mutex); + + } + if (0 > drci_rd_reg(mdev->usb_device, DRCI_REG_NI_STATE, &link)) { + pr_info("Vendor request \"link status\" failed\n"); + return -1; + } + le16_to_cpus(&link); + mutex_lock(&mdev->io_mutex); + mdev->link_stat = link; + mutex_unlock(&mdev->io_mutex); + return 0; +} + +/** + * hdm_request_netinfo - request network information + * @iface: pointer to interface + * @channel: channel ID + * + * This is used as trigger to set up the link status timer that + * polls for the NI state of the INIC every 2 seconds. + * + */ +void hdm_request_netinfo(struct most_interface *iface, int channel) +{ + struct most_dev *mdev; + + BUG_ON(!iface); + mdev = to_mdev(iface); + mdev->link_stat_timer.expires = jiffies + HZ; + mod_timer(&mdev->link_stat_timer, mdev->link_stat_timer.expires); +} + +/** + * link_stat_timer_handler - add work to link_stat work queue + * @data: pointer to USB device instance + * + * The handler runs in interrupt context. That's why we need to defer the + * tasks to a work queue. + */ +static void link_stat_timer_handler(unsigned long data) +{ + struct most_dev *mdev = (struct most_dev *)data; + + queue_work(schedule_usb_work, &mdev->poll_work_obj); + mdev->link_stat_timer.expires = jiffies + (2 * HZ); + add_timer(&mdev->link_stat_timer); +} + +/** + * wq_netinfo - work queue function + * @wq_obj: object that holds data for our deferred work to do + * + * This retrieves the network interface status of the USB INIC + * and compares it with the current status. If the status has + * changed, it updates the status of the core. + */ +static void wq_netinfo(struct work_struct *wq_obj) +{ + struct most_dev *mdev; + int i, prev_link_stat; + u8 prev_hw_addr[6]; + + mdev = to_mdev_from_work(wq_obj); + prev_link_stat = mdev->link_stat; + + for (i = 0; i < 6; i++) + prev_hw_addr[i] = mdev->hw_addr[i]; + + if (0 > hdm_update_netinfo(mdev)) + return; + if ((prev_link_stat != mdev->link_stat) || + (prev_hw_addr[0] != mdev->hw_addr[0]) || + (prev_hw_addr[1] != mdev->hw_addr[1]) || + (prev_hw_addr[2] != mdev->hw_addr[2]) || + (prev_hw_addr[3] != mdev->hw_addr[3]) || + (prev_hw_addr[4] != mdev->hw_addr[4]) || + (prev_hw_addr[5] != mdev->hw_addr[5])) + most_deliver_netinfo(&mdev->iface, mdev->link_stat, + &mdev->hw_addr[0]); +} + +/** + * wq_clear_halt - work queue function + * @wq_obj: work_struct object to execute + * + * This sends a clear_halt to the given USB pipe. + */ +static void wq_clear_halt(struct work_struct *wq_obj) +{ + struct buf_anchor *anchor; + struct most_dev *mdev; + struct mbo *mbo; + struct urb *urb; + unsigned int channel; + unsigned long flags; + + anchor = to_buf_anchor(wq_obj); + urb = anchor->urb; + mbo = urb->context; + mdev = to_mdev(mbo->ifp); + channel = mbo->hdm_channel_id; + + if (usb_clear_halt(urb->dev, urb->pipe)) + pr_info("Failed to reset endpoint.\n"); + + usb_free_urb(urb); + spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); + list_del(&anchor->list); + spin_unlock_irqrestore(&mdev->anchor_list_lock[channel], flags); + + if (likely(mbo->complete)) + mbo->complete(mbo); + if (mdev->conf[channel].direction & MOST_CH_TX) + most_resume_enqueue(&mdev->iface, channel); + + kfree(anchor); +} + +/** + * hdm_usb_fops - file operation table for USB driver + */ +static const struct file_operations hdm_usb_fops = { + .owner = THIS_MODULE, +}; + +/** + * usb_device_id - ID table for HCD device probing + */ +static struct usb_device_id usbid[] = { + { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_BRDG), }, + { USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_INIC), }, + { } /* Terminating entry */ +}; + +#define MOST_DCI_RO_ATTR(_name) \ + struct most_dci_attribute most_dci_attr_##_name = \ + __ATTR(_name, S_IRUGO, show_value, NULL) + +#define MOST_DCI_ATTR(_name) \ + struct most_dci_attribute most_dci_attr_##_name = \ + __ATTR(_name, S_IRUGO | S_IWUSR, show_value, store_value) + +/** + * struct most_dci_attribute - to access the attributes of a dci object + * @attr: attributes of a dci object + * @show: pointer to the show function + * @store: pointer to the store function + */ +struct most_dci_attribute { + struct attribute attr; + ssize_t (*show)(struct most_dci_obj *d, + struct most_dci_attribute *attr, + char *buf); + ssize_t (*store)(struct most_dci_obj *d, + struct most_dci_attribute *attr, + const char *buf, + size_t count); +}; +#define to_dci_attr(a) container_of(a, struct most_dci_attribute, attr) + + +/** + * dci_attr_show - show function for dci object + * @kobj: pointer to kobject + * @attr: pointer to attribute struct + * @buf: buffer + */ +static ssize_t dci_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct most_dci_attribute *dci_attr = to_dci_attr(attr); + struct most_dci_obj *dci_obj = to_dci_obj(kobj); + + if (!dci_attr->show) + return -EIO; + + return dci_attr->show(dci_obj, dci_attr, buf); +} + +/** + * dci_attr_store - store function for dci object + * @kobj: pointer to kobject + * @attr: pointer to attribute struct + * @buf: buffer + * @len: length of buffer + */ +static ssize_t dci_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, + size_t len) +{ + struct most_dci_attribute *dci_attr = to_dci_attr(attr); + struct most_dci_obj *dci_obj = to_dci_obj(kobj); + + if (!dci_attr->store) + return -EIO; + + return dci_attr->store(dci_obj, dci_attr, buf, len); +} + +static const struct sysfs_ops most_dci_sysfs_ops = { + .show = dci_attr_show, + .store = dci_attr_store, +}; + +/** + * most_dci_release - release function for dci object + * @kobj: pointer to kobject + * + * This frees the memory allocated for the dci object + */ +static void most_dci_release(struct kobject *kobj) +{ + struct most_dci_obj *dci_obj = to_dci_obj(kobj); + + kfree(dci_obj); +} + +static ssize_t show_value(struct most_dci_obj *dci_obj, + struct most_dci_attribute *attr, char *buf) +{ + u16 tmp_val; + u16 reg_addr; + int err; + + if (!strcmp(attr->attr.name, "ni_state")) + reg_addr = DRCI_REG_NI_STATE; + else if (!strcmp(attr->attr.name, "packet_bandwidth")) + reg_addr = DRCI_REG_PACKET_BW; + else if (!strcmp(attr->attr.name, "node_address")) + reg_addr = DRCI_REG_NODE_ADDR; + else if (!strcmp(attr->attr.name, "node_position")) + reg_addr = DRCI_REG_NODE_POS; + else if (!strcmp(attr->attr.name, "mep_filter")) + reg_addr = DRCI_REG_MEP_FILTER; + else if (!strcmp(attr->attr.name, "mep_hash0")) + reg_addr = DRCI_REG_HASH_TBL0; + else if (!strcmp(attr->attr.name, "mep_hash1")) + reg_addr = DRCI_REG_HASH_TBL1; + else if (!strcmp(attr->attr.name, "mep_hash2")) + reg_addr = DRCI_REG_HASH_TBL2; + else if (!strcmp(attr->attr.name, "mep_hash3")) + reg_addr = DRCI_REG_HASH_TBL3; + else if (!strcmp(attr->attr.name, "mep_eui48_hi")) + reg_addr = DRCI_REG_HW_ADDR_HI; + else if (!strcmp(attr->attr.name, "mep_eui48_mi")) + reg_addr = DRCI_REG_HW_ADDR_MI; + else if (!strcmp(attr->attr.name, "mep_eui48_lo")) + reg_addr = DRCI_REG_HW_ADDR_LO; + else + return -EIO; + + err = drci_rd_reg(dci_obj->usb_device, reg_addr, &tmp_val); + if (err < 0) + return err; + + return snprintf(buf, PAGE_SIZE, "%04x\n", le16_to_cpu(tmp_val)); +} + +static ssize_t store_value(struct most_dci_obj *dci_obj, + struct most_dci_attribute *attr, + const char *buf, size_t count) +{ + u16 v16; + u16 reg_addr; + int err; + + if (!strcmp(attr->attr.name, "mep_filter")) + reg_addr = DRCI_REG_MEP_FILTER; + else if (!strcmp(attr->attr.name, "mep_hash0")) + reg_addr = DRCI_REG_HASH_TBL0; + else if (!strcmp(attr->attr.name, "mep_hash1")) + reg_addr = DRCI_REG_HASH_TBL1; + else if (!strcmp(attr->attr.name, "mep_hash2")) + reg_addr = DRCI_REG_HASH_TBL2; + else if (!strcmp(attr->attr.name, "mep_hash3")) + reg_addr = DRCI_REG_HASH_TBL3; + else if (!strcmp(attr->attr.name, "mep_eui48_hi")) + reg_addr = DRCI_REG_HW_ADDR_HI; + else if (!strcmp(attr->attr.name, "mep_eui48_mi")) + reg_addr = DRCI_REG_HW_ADDR_MI; + else if (!strcmp(attr->attr.name, "mep_eui48_lo")) + reg_addr = DRCI_REG_HW_ADDR_LO; + else + return -EIO; + + err = kstrtou16(buf, 16, &v16); + if (err) + return err; + + err = drci_wr_reg(dci_obj->usb_device, reg_addr, cpu_to_le16(v16)); + if (err < 0) + return err; + + return count; +} + +static MOST_DCI_RO_ATTR(ni_state); +static MOST_DCI_RO_ATTR(packet_bandwidth); +static MOST_DCI_RO_ATTR(node_address); +static MOST_DCI_RO_ATTR(node_position); +static MOST_DCI_ATTR(mep_filter); +static MOST_DCI_ATTR(mep_hash0); +static MOST_DCI_ATTR(mep_hash1); +static MOST_DCI_ATTR(mep_hash2); +static MOST_DCI_ATTR(mep_hash3); +static MOST_DCI_ATTR(mep_eui48_hi); +static MOST_DCI_ATTR(mep_eui48_mi); +static MOST_DCI_ATTR(mep_eui48_lo); + +/** + * most_dci_def_attrs - array of default attribute files of the dci object + */ +static struct attribute *most_dci_def_attrs[] = { + &most_dci_attr_ni_state.attr, + &most_dci_attr_packet_bandwidth.attr, + &most_dci_attr_node_address.attr, + &most_dci_attr_node_position.attr, + &most_dci_attr_mep_filter.attr, + &most_dci_attr_mep_hash0.attr, + &most_dci_attr_mep_hash1.attr, + &most_dci_attr_mep_hash2.attr, + &most_dci_attr_mep_hash3.attr, + &most_dci_attr_mep_eui48_hi.attr, + &most_dci_attr_mep_eui48_mi.attr, + &most_dci_attr_mep_eui48_lo.attr, + NULL, +}; + +/** + * DCI ktype + */ +static struct kobj_type most_dci_ktype = { + .sysfs_ops = &most_dci_sysfs_ops, + .release = most_dci_release, + .default_attrs = most_dci_def_attrs, +}; + +/** + * create_most_dci_obj - allocates a dci object + * @parent: parent kobject + * + * This creates a dci object and registers it with sysfs. + * Returns a pointer to the object or NULL when something went wrong. + */ +static struct +most_dci_obj *create_most_dci_obj(struct kobject *parent) +{ + struct most_dci_obj *most_dci; + int retval; + + most_dci = kzalloc(sizeof(*most_dci), GFP_KERNEL); + if (!most_dci) + return NULL; + + retval = kobject_init_and_add(&most_dci->kobj, &most_dci_ktype, parent, + "dci"); + if (retval) { + kobject_put(&most_dci->kobj); + return NULL; + } + return most_dci; +} + +/** + * destroy_most_dci_obj - DCI object release function + * @p: pointer to dci object + */ +static void destroy_most_dci_obj(struct most_dci_obj *p) +{ + kobject_put(&p->kobj); +} + +/** + * hdm_probe - probe function of USB device driver + * @interface: Interface of the attached USB device + * @id: Pointer to the USB ID table. + * + * This allocates and initializes the device instance, adds the new + * entry to the internal list, scans the USB descriptors and registers + * the interface with the core. + * Additionally, the DCI objects are created and the hardware is sync'd. + * + * Return 0 on success. In case of an error a negative number is returned. + */ +static int +hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) +{ + unsigned int i; + unsigned int num_endpoints; + struct most_channel_capability *tmp_cap; + struct most_dev *mdev; + struct usb_device *usb_dev; + struct usb_host_interface *usb_iface_desc; + struct usb_endpoint_descriptor *ep_desc; + int ret = 0; + + usb_iface_desc = interface->cur_altsetting; + usb_dev = interface_to_usbdev(interface); + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + if (!mdev) + goto exit_ENOMEM; + + usb_set_intfdata(interface, mdev); + num_endpoints = usb_iface_desc->desc.bNumEndpoints; + mutex_init(&mdev->io_mutex); + INIT_WORK(&mdev->poll_work_obj, wq_netinfo); + init_timer(&mdev->link_stat_timer); + + mdev->usb_device = usb_dev; + mdev->link_stat_timer.function = link_stat_timer_handler; + mdev->link_stat_timer.data = (unsigned long)mdev; + mdev->link_stat_timer.expires = jiffies + (2 * HZ); + + mdev->iface.mod = hdm_usb_fops.owner; + mdev->iface.interface = ITYPE_USB; + mdev->iface.configure = hdm_configure_channel; + mdev->iface.request_netinfo = hdm_request_netinfo; + mdev->iface.enqueue = hdm_enqueue; + mdev->iface.poison_channel = hdm_poison_channel; + mdev->iface.description = mdev->description; + mdev->iface.num_channels = num_endpoints; + + snprintf(mdev->description, sizeof(mdev->description), + "usb_device %d-%s:%d.%d", + usb_dev->bus->busnum, + usb_dev->devpath, + usb_dev->config->desc.bConfigurationValue, + usb_iface_desc->desc.bInterfaceNumber); + + mdev->conf = kcalloc(num_endpoints, sizeof(*mdev->conf), GFP_KERNEL); + if (!mdev->conf) + goto exit_free; + + mdev->cap = kcalloc(num_endpoints, sizeof(*mdev->cap), GFP_KERNEL); + if (!mdev->cap) + goto exit_free1; + + mdev->iface.channel_vector = mdev->cap; + mdev->iface.priv = NULL; + + mdev->ep_address = + kcalloc(num_endpoints, sizeof(*mdev->ep_address), GFP_KERNEL); + if (!mdev->ep_address) + goto exit_free2; + + mdev->anchor_list = + kcalloc(num_endpoints, sizeof(*mdev->anchor_list), GFP_KERNEL); + if (!mdev->anchor_list) + goto exit_free3; + + tmp_cap = mdev->cap; + for (i = 0; i < num_endpoints; i++) { + ep_desc = &usb_iface_desc->endpoint[i].desc; + mdev->ep_address[i] = ep_desc->bEndpointAddress; + mdev->padding_active[i] = false; + mdev->is_channel_healthy[i] = true; + + snprintf(&mdev->suffix[i][0], MAX_SUFFIX_LEN, "ep%02x", + mdev->ep_address[i]); + + tmp_cap->name_suffix = &mdev->suffix[i][0]; + tmp_cap->buffer_size_packet = MAX_BUF_SIZE; + tmp_cap->buffer_size_streaming = MAX_BUF_SIZE; + tmp_cap->num_buffers_packet = BUF_CHAIN_SIZE; + tmp_cap->num_buffers_streaming = BUF_CHAIN_SIZE; + tmp_cap->data_type = MOST_CH_CONTROL | MOST_CH_ASYNC | + MOST_CH_ISOC_AVP | MOST_CH_SYNC; + if (ep_desc->bEndpointAddress & USB_DIR_IN) + tmp_cap->direction = MOST_CH_RX; + else + tmp_cap->direction = MOST_CH_TX; + tmp_cap++; + INIT_LIST_HEAD(&mdev->anchor_list[i]); + spin_lock_init(&mdev->anchor_list_lock[i]); + } + pr_info("claimed gadget: Vendor=%4.4x ProdID=%4.4x Bus=%02x Device=%02x If#=%d Alt=%d\n", + le16_to_cpu(usb_dev->descriptor.idVendor), + le16_to_cpu(usb_dev->descriptor.idProduct), + usb_dev->bus->busnum, + usb_dev->devnum, + usb_iface_desc->desc.bInterfaceNumber, + usb_iface_desc->desc.bAlternateSetting); + + pr_info("device path: /sys/bus/usb/devices/%d-%s:%d.%d\n", + usb_dev->bus->busnum, + usb_dev->devpath, + usb_dev->config->desc.bConfigurationValue, + usb_iface_desc->desc.bInterfaceNumber); + + mdev->parent = most_register_interface(&mdev->iface); + if (IS_ERR(mdev->parent)) { + ret = PTR_ERR(mdev->parent); + goto exit_free4; + } + + mutex_lock(&mdev->io_mutex); + if (le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_INIC) { + /* this increments the reference count of the instance + * object of the core + */ + mdev->dci = create_most_dci_obj(mdev->parent); + if (!mdev->dci) { + mutex_unlock(&mdev->io_mutex); + most_deregister_interface(&mdev->iface); + ret = -ENOMEM; + goto exit_free4; + } + + kobject_uevent(&mdev->dci->kobj, KOBJ_ADD); + mdev->dci->usb_device = mdev->usb_device; + trigger_resync_vr(usb_dev); + } + mutex_unlock(&mdev->io_mutex); + return 0; + +exit_free4: + kfree(mdev->anchor_list); +exit_free3: + kfree(mdev->ep_address); +exit_free2: + kfree(mdev->cap); +exit_free1: + kfree(mdev->conf); +exit_free: + kfree(mdev); +exit_ENOMEM: + if (ret == 0 || ret == -ENOMEM) { + ret = -ENOMEM; + pr_info("out of memory\n"); + } + return ret; +} + +/** + * hdm_disconnect - disconnect function of USB device driver + * @interface: Interface of the attached USB device + * + * This deregisters the interface with the core, removes the kernel timer + * and frees resources. + * + * Context: hub kernel thread + */ +static void hdm_disconnect(struct usb_interface *interface) +{ + struct most_dev *mdev; + + mdev = usb_get_intfdata(interface); + if (unlikely(!mdev)) { + pr_info("failed to retrieve interface data\n"); + return; + } + + mutex_lock(&mdev->io_mutex); + usb_set_intfdata(interface, NULL); + mdev->usb_device = NULL; + mutex_unlock(&mdev->io_mutex); + + del_timer_sync(&mdev->link_stat_timer); + cancel_work_sync(&mdev->poll_work_obj); + + destroy_most_dci_obj(mdev->dci); + most_deregister_interface(&mdev->iface); + + kfree(mdev->anchor_list); + kfree(mdev->cap); + kfree(mdev->conf); + kfree(mdev->ep_address); + kfree(mdev); +} + +static struct usb_driver hdm_usb = { + .name = "hdm_usb", + .id_table = usbid, + .probe = hdm_probe, + .disconnect = hdm_disconnect, +}; + +static int __init hdm_usb_init(void) +{ + pr_info("hdm_usb_init()\n"); + if (usb_register(&hdm_usb)) { + pr_info("could not register hdm_usb driver\n"); + return -EIO; + } + schedule_usb_work = create_workqueue("hdmu_work"); + if (schedule_usb_work == NULL) { + pr_info("could not create workqueue\n"); + usb_deregister(&hdm_usb); + return -ENOMEM; + } + return 0; +} + +static void __exit hdm_usb_exit(void) +{ + pr_info("hdm_usb_exit()\n"); + destroy_workqueue(schedule_usb_work); + usb_deregister(&hdm_usb); +} + +module_init(hdm_usb_init); +module_exit(hdm_usb_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Gromm "); +MODULE_DESCRIPTION("HDM_4_USB"); -- cgit v1.3-6-gb490 From 59cc3399efd61fabb7f4aa23d4498bd9b01e5f6d Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Fri, 24 Jul 2015 16:11:56 +0200 Subject: Staging: most: add MOST driver's documentation This patch adds the documentation to the MOST driver that describes its ABI interface and the basic usage. Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- .../most/Documentation/ABI/sysfs-class-most.txt | 181 +++++++++++++++++++++ .../staging/most/Documentation/driver_usage.txt | 180 ++++++++++++++++++++ 2 files changed, 361 insertions(+) create mode 100644 drivers/staging/most/Documentation/ABI/sysfs-class-most.txt create mode 100644 drivers/staging/most/Documentation/driver_usage.txt (limited to 'drivers') diff --git a/drivers/staging/most/Documentation/ABI/sysfs-class-most.txt b/drivers/staging/most/Documentation/ABI/sysfs-class-most.txt new file mode 100644 index 000000000000..380c137089d0 --- /dev/null +++ b/drivers/staging/most/Documentation/ABI/sysfs-class-most.txt @@ -0,0 +1,181 @@ +What: /sys/class/most/mostcore/aims +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + List of AIMs that have been loaded. +Users: + +What: /sys/class/most/mostcore/aims//add_link +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + This is used to establish a connection of a channel and the + current AIM. +Users: + +What: /sys/class/most/mostcore/aims//remove_link +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + This is used to remove a connected channel from the + current AIM. +Users: + +What: /sys/class/most/mostcore/devices +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + List of attached MOST interfaces. +Users: + +What: /sys/class/most/mostcore/devices//description +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + Provides information about the interface type and the physical + location of the device. Hardware attached via USB, for instance, + might return +Users: + +What: /sys/class/most/mostcore/devices//interface +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + Indicates the type of peripherial interface the current device + uses. +Users: + +What: /sys/class/most/mostcore/devices/// +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + For every channel of the device a directory is created, whose + name is dictated by the HDM. This enables an application to + collect information about the channel's capabilities and + configure it. +Users: + +What: /sys/class/most/mostcore/devices///available_datatypes +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + Indicates the data types the current channel can transport. +Users: + +What: /sys/class/most/mostcore/devices///available_directions +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + Indicates the directions the current channel is capable of. +Users: + +What: /sys/class/most/mostcore/devices///number_of_packet_buffers +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + Indicates the number of packet buffers the current channel can + handle. +Users: + +What: /sys/class/most/mostcore/devices///number_of_stream_buffers +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + Indicates the number of streaming buffers the current channel can + handle. +Users: + +What: /sys/class/most/mostcore/devices///size_of_packet_buffer +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + Indicates the size of a packet buffer the current channel can + handle. +Users: + +What: /sys/class/most/mostcore/devices///size_of_stream_buffer +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + Indicates the size of a streaming buffer the current channel can + handle. +Users: + +What: /sys/class/most/mostcore/devices///set_number_of_buffers +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + This is to configure the number of buffers of the current channel. +Users: + +What: /sys/class/most/mostcore/devices///set_buffer_size +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + This is to configure the size of a buffer of the current channel. +Users: + +What: /sys/class/most/mostcore/devices///set_direction +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + This is to configure the direction of the current channel. + The following strings will be accepted: + 'dir_tx', + 'dir_rx' +Users: + +What: /sys/class/most/mostcore/devices///set_datatype +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + This is to configure the data type of the current channel. + The following strings will be accepted: + 'control', + 'async', + 'sync', + 'isoc_avp' +Users: + +What: /sys/class/most/mostcore/devices///set_subbuffer_size +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + This is to configure the subbuffer size of the current channel. +Users: + +What: /sys/class/most/mostcore/devices///set_packets_per_xact +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + This is to configure the number of packets per transaction of + the current channel. This is only needed network interface + controller is attached via USB. +Users: + +What: /sys/class/most/mostcore/devices///channel_starving +Date: June 2015 +KernelVersion: 4.3 +Contact: Christian Gromm +Description: + Indicates whether current channel ran out of buffers. +Users: diff --git a/drivers/staging/most/Documentation/driver_usage.txt b/drivers/staging/most/Documentation/driver_usage.txt new file mode 100644 index 000000000000..a4dc0c348fbc --- /dev/null +++ b/drivers/staging/most/Documentation/driver_usage.txt @@ -0,0 +1,180 @@ + + Section 1 Overview + +The Media Oriented Systems Transport (MOST) driver gives Linux applications +access a MOST network: The Automotive Information Backbone and the de-facto +standard for high-bandwidth automotive multimedia networking. + +MOST defines the protocol, hardware and software layers necessary to allow +for the efficient and low-cost transport of control, real-time and packet +data using a single medium (physical layer). Media currently in use are +fiber optics, unshielded twisted pair cables (UTP) and coax cables. MOST +also supports various speed grades up to 150 Mbps. +For more information on MOST, visit the MOST Cooperation website: +www.mostcooperation.com. + +Cars continue to evolve into sophisticated consumer electronics platforms, +increasing the demand for reliable and simple solutions to support audio, +video and data communications. MOST can be used to connect multiple +consumer devices via optical or electrical physical layers directly to one +another or in a network configuration. As a synchronous network, MOST +provides excellent Quality of Service and seamless connectivity for +audio/video streaming. Therefore, the driver perfectly fits to the mission +of Automotive Grade Linux to create open source software solutions for +automotive applications. + +The driver consists basically of three layers. The hardware layer, the +core layer and the application layer. The core layer consists of the core +module only. This module handles the communication flow through all three +layers, the configuration of the driver, the configuration interface +representation in sysfs, and the buffer management. +For each of the other two layers a selection of modules is provided. These +modules can arbitrarily be combined to meet the needs of the desired +system architecture. A module of the hardware layer is referred to as an +HDM (hardware dependent module). Each module of this layer handles exactly +one of the peripheral interfaces of a network interface controller (e.g. +USB, MediaLB, I2C). A module of the application layer is referred to as an +AIM (application interfacing module). The modules of this layer give access +to MOST via one the following ways: character devices, ALSA, Networking or +V4L2. + +To physically access MOST, an Intelligent Network Interface Controller +(INIC) is needed. For more information on available controllers visit: +www.microchip.com + + + + Section 1.1 Hardware Layer + +The hardware layer contains so called hardware dependent modules (HDM). For each +peripheral interface the hardware supports the driver has a suitable module +that handles the interface. + +The HDMs encapsulate the peripheral interface specific knowledge of the driver +and provides an easy way of extending the number of supported interfaces. +Currently the following HDMs are available: + + 1) MediaLB (DIM2) + Host wants to communicate with hardware via MediaLB. + + 2) I2C + Host wants to communicate with the hardware via I2C. + + 3) USB + Host wants to communicate with the hardware via USB. + + + Section 1.2 Core Layer + +The core layer contains the mostcore module only, which processes the driver +configuration via sysfs, buffer management and data forwarding. + + + + Section 1.2 Application Layer + +The application layer contains so called application interfacing modules (AIM). +Depending on how the driver should interface to the application, one or more +suitable modules can be selected. + +The AIMs encapsulate the application interface specific knowledge of the driver +and provides access to user space or other kernel subsystems. +Currently the following AIMs are available + + 1) Character Device + Applications can access the driver by means of character devices. + + 2) Networking + Standard networking applications (e.g. iperf) can by used to access + the driver via the networking subsystem. + + 3) Video4Linux (v4l2) + Standard video applications (e.g. VLC) can by used to access the + driver via the V4L subsystem. + + 4) Advanced Linux Sound Architecture (ALSA) + Standard sound applications (e.g. aplay, arecord, audacity) can by + used to access the driver via the ALSA subsystem. + + + + Section 2 Configuration + +See ABI/sysfs-class-most.txt + + + + Section 3 USB Padding + +When transceiving synchronous or isochronous data, the number of packets per USB +transaction and the sub-buffer size need to be configured. These values +are needed for the driver to process buffer padding, as expected by hardware, +which is for performance optimization purposes of the USB transmission. + +When transmitting synchronous data the allocated channel width needs to be +written to 'set_subbuffer_size'. Additionally, the number of MOST frames that +should travel to the host within one USB transaction need to be written to +'packets_per_xact'. + +Internally the synchronous threshold is calculated as follows: + + frame_size = set_subbuffer_size * packets_per_xact + +In case 'packets_per_xact' is set to 0xFF the maximum number of packets, +allocated within one MOST frame, is calculated that fit into _one_ 512 byte +USB full packet. + + frame_size = floor(MTU_USB / bandwidth_sync) * bandwidth_sync + +This frame_size is the number of synchronous data within an USB transaction, +which renders MTU_USB - frame_size bytes for padding. + +When transmitting isochronous AVP data the desired packet size needs to be +written to 'set_subbuffer_size' and hardware will always expect two isochronous +packets within one USB transaction. This renders + + MTU_USB - (2 * set_subbuffer_size) + +bytes for padding. + +Note that at least 2 times set_subbuffer_size bytes for isochronous data or +set_subbuffer_size times packts_per_xact bytes for synchronous data need to be +put in the transmission buffer and passed to the driver. + +Since HDMs are allowed to change a chosen configuration to best fit its +constraints, it is recommended to always double check the configuration and read +back the previously written files. + + + + Section 4 Routing Channels + +To connect a channel that has been configured as outlined above to an AIM and +make it accessible to user space applications, the attribute file 'add_link' is +used. To actually bind a channel to the AIM a string needs to be written to the +file that complies with the following syntax: + + "most_device:channel_name:link_name[.param]" + +The example above links the channel "channel_name" of the device "most_device" +to the AIM. In case the AIM interfaces the VFS this would also create a device +node "link_name" in the /dev directory. The parameter "param" is an AIM dependent +string, which can be omitted in case the used AIM does not make any use of it. + +Cdev AIM example: + $ echo "mdev0:ep_81:my_rx_channel" >add_link + $ echo "mdev0:ep_81" >add_link + + +Sound/ALSA AIM example: + +The sound/ALSA AIM needs an additional parameter to determine the audio resolution +that is going to be used. The following strings can be used: + + - "1x8" (Mono) + - "2x16" (16-bit stereo) + - "2x24" (24-bit stereo) + - "2x32" (32-bit stereo) + + $ echo "mdev0:ep_81:audio_rx.2x16" >add_link + $ echo "mdev0:ep_81" >add_link -- cgit v1.3-6-gb490 From 4ad2adc98f113d6c21d7bd365cd45ba88d4f7470 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 24 Jul 2015 09:37:14 -0700 Subject: staging: lustre: Replace strtoul with simple_strtoul Defining and using strtoul in lustre code results in the following compile warnings (arm64:allmodconfig). include/linux/libcfs/libcfs_string.h:105:0: warning: "strtoul" redefined #define strtoul(str, endp, base) simple_strtoul(str, endp, base) include/acpi/platform/aclinux.h:122:0: note: this is the location of the previous definition #define strtoul simple_strtoul Remove the definition and use simple_strtoul() directly. Note that we can not replace simple_strtoul with kstrtoul since the end pointer is used by the code. Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/include/linux/libcfs/libcfs_string.h | 2 -- drivers/staging/lustre/lustre/include/obd.h | 2 +- drivers/staging/lustre/lustre/libcfs/libcfs_string.c | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h index 509dc1e5c3b1..478e9582ff54 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_string.h @@ -102,6 +102,4 @@ int cfs_ip_addr_parse(char *str, int len, struct list_head *list); int cfs_ip_addr_match(__u32 addr, struct list_head *list); void cfs_ip_addr_free(struct list_head *list); -#define strtoul(str, endp, base) simple_strtoul(str, endp, base) - #endif diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 55452e562bd4..9ad8c268da10 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -1472,7 +1472,7 @@ static inline bool filename_is_volatile(const char *name, int namelen, int *idx) } /* we have an idx, read it */ start = name + LUSTRE_VOLATILE_HDR_LEN + 1; - *idx = strtoul(start, &end, 0); + *idx = simple_strtoul(start, &end, 0); /* error cases: * no digit, no trailing :, negative value */ diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c index 76d4392bd282..4dde8e08c0ba 100644 --- a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c +++ b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c @@ -231,7 +231,7 @@ cfs_str2num_check(char *str, int nob, unsigned *num, char *endp; str = cfs_trimwhite(str); - *num = strtoul(str, &endp, 0); + *num = simple_strtoul(str, &endp, 0); if (endp == str) return 0; -- cgit v1.3-6-gb490 From 7deef550f3a7d44c1d52a6d54f824e7e180c08ae Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 18:09:10 -0600 Subject: toshiba_acpi: Adapt /proc/acpi/toshiba/keys to TOS1900 devices Since the introduction of TOS1900 devices support to the driver, the "keys" entry under the proc directory was broken, given that it only handled TOS620X devices accordingly. This patch adapts the code to show the hotkey values of TOS1900 devices too, and in case some programs are still using that interface, hotkeys reporting should now work on these devices. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 56 +++++++++++++------------------------ 1 file changed, 20 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 3ad7b1fa24ce..c3a0c4d0c1dc 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1499,32 +1499,10 @@ static const struct file_operations fan_proc_fops = { static int keys_proc_show(struct seq_file *m, void *v) { struct toshiba_acpi_dev *dev = m->private; - u32 hci_result; - u32 value; - - if (!dev->key_event_valid && dev->system_event_supported) { - hci_result = hci_read(dev, HCI_SYSTEM_EVENT, &value); - if (hci_result == TOS_SUCCESS) { - dev->key_event_valid = 1; - dev->last_key_event = value; - } else if (hci_result == TOS_FIFO_EMPTY) { - /* Better luck next time */ - } else if (hci_result == TOS_NOT_SUPPORTED) { - /* - * This is a workaround for an unresolved issue on - * some machines where system events sporadically - * become disabled. - */ - hci_result = hci_write(dev, HCI_SYSTEM_EVENT, 1); - pr_notice("Re-enabled hotkeys\n"); - } else { - pr_err("Error reading hotkey status\n"); - return -EIO; - } - } seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); + return 0; } @@ -2361,22 +2339,28 @@ static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) { - u32 hci_result, value; - int retries = 3; - int scancode; - if (dev->info_supported) { - scancode = toshiba_acpi_query_hotkey(dev); - if (scancode < 0) + int scancode = toshiba_acpi_query_hotkey(dev); + + if (scancode < 0) { pr_err("Failed to query hotkey event\n"); - else if (scancode != 0) + } else if (scancode != 0) { toshiba_acpi_report_hotkey(dev, scancode); + dev->key_event_valid = 1; + dev->last_key_event = scancode; + } } else if (dev->system_event_supported) { + u32 result; + u32 value; + int retries = 3; + do { - hci_result = hci_read(dev, HCI_SYSTEM_EVENT, &value); - switch (hci_result) { + result = hci_read(dev, HCI_SYSTEM_EVENT, &value); + switch (result) { case TOS_SUCCESS: toshiba_acpi_report_hotkey(dev, (int)value); + dev->key_event_valid = 1; + dev->last_key_event = value; break; case TOS_NOT_SUPPORTED: /* @@ -2384,15 +2368,15 @@ static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) * issue on some machines where system events * sporadically become disabled. */ - hci_result = - hci_write(dev, HCI_SYSTEM_EVENT, 1); - pr_notice("Re-enabled hotkeys\n"); + result = hci_write(dev, HCI_SYSTEM_EVENT, 1); + if (result == TOS_SUCCESS) + pr_notice("Re-enabled hotkeys\n"); /* Fall through */ default: retries--; break; } - } while (retries && hci_result != TOS_FIFO_EMPTY); + } while (retries && result != TOS_FIFO_EMPTY); } } -- cgit v1.3-6-gb490 From fc5462f8525b47fa219452289ecb22c921c16823 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 18:09:11 -0600 Subject: toshiba_acpi: Add /dev/toshiba_acpi device There were previous attempts to "merge" the toshiba SMM module to the toshiba_acpi one, they were trying to imitate what the old toshiba module does, however, some models (TOS1900 devices) come with a "crippled" implementation and do not provide all the "features" a "genuine" Toshiba BIOS does. This patch adds a new device called toshiba_acpi, which aim is to enable userspace to access the SMM on Toshiba laptops via ACPI calls. Creating a new convenience _IOWR command to access the SCI functions by opening/closing the SCI internally to avoid buggy BIOS, while at the same time providing backwards compatibility. Older programs (and new) who wish to access the SMM on newer models can do it by pointing their path to /dev/toshiba_acpi (instead of /dev/toshiba) as the toshiba.h header was modified to reflect these changes as well as adds all the toshiba_acpi paths and command, however, it is strongly recommended to use the new IOCTL for any SCI command to avoid any buggy BIOS. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- Documentation/ioctl/ioctl-number.txt | 2 +- drivers/platform/x86/toshiba_acpi.c | 91 ++++++++++++++++++++++++++++++++++++ include/uapi/linux/toshiba.h | 32 +++++++++++-- 3 files changed, 121 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 611c52267d24..21d2f27c886b 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -263,7 +263,7 @@ Code Seq#(hex) Include File Comments 's' all linux/cdk.h 't' 00-7F linux/ppp-ioctl.h 't' 80-8F linux/isdn_ppp.h -'t' 90 linux/toshiba.h +'t' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM 'u' 00-1F linux/smb_fs.h gone 'u' 20-3F linux/uvcvideo.h USB video class host driver 'v' 00-1F linux/ext2_fs.h conflict! diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index c3a0c4d0c1dc..802577f43a23 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -50,6 +50,8 @@ #include #include #include +#include +#include #include MODULE_AUTHOR("John Belmonte"); @@ -170,6 +172,7 @@ struct toshiba_acpi_dev { struct led_classdev led_dev; struct led_classdev kbd_led; struct led_classdev eco_led; + struct miscdevice miscdev; int force_fan; int last_key_event; @@ -2239,6 +2242,81 @@ static struct attribute_group toshiba_attr_group = { .attrs = toshiba_attributes, }; +/* + * Misc device + */ +static int toshiba_acpi_smm_bridge(SMMRegisters *regs) +{ + u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx, + regs->edx, regs->esi, regs->edi }; + u32 out[TCI_WORDS]; + acpi_status status; + + status = tci_raw(toshiba_acpi, in, out); + if (ACPI_FAILURE(status)) { + pr_err("ACPI call to query SMM registers failed\n"); + return -EIO; + } + + /* Fillout the SMM struct with the TCI call results */ + regs->eax = out[0]; + regs->ebx = out[1]; + regs->ecx = out[2]; + regs->edx = out[3]; + regs->esi = out[4]; + regs->edi = out[5]; + + return 0; +} + +static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd, + unsigned long arg) +{ + SMMRegisters __user *argp = (SMMRegisters __user *)arg; + SMMRegisters regs; + int ret; + + if (!argp) + return -EINVAL; + + switch (cmd) { + case TOSH_SMM: + if (copy_from_user(®s, argp, sizeof(SMMRegisters))) + return -EFAULT; + ret = toshiba_acpi_smm_bridge(®s); + if (ret) + return ret; + if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) + return -EFAULT; + break; + case TOSHIBA_ACPI_SCI: + if (copy_from_user(®s, argp, sizeof(SMMRegisters))) + return -EFAULT; + /* Ensure we are being called with a SCI_{GET, SET} register */ + if (regs.eax != SCI_GET && regs.eax != SCI_SET) + return -EINVAL; + if (!sci_open(toshiba_acpi)) + return -EIO; + ret = toshiba_acpi_smm_bridge(®s); + sci_close(toshiba_acpi); + if (ret) + return ret; + if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) + return -EFAULT; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct file_operations toshiba_acpi_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = toshiba_acpi_ioctl, + .llseek = noop_llseek, +}; + /* * Hotkeys */ @@ -2540,6 +2618,8 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev) { struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); + misc_deregister(&dev->miscdev); + remove_toshiba_proc_entries(dev); if (dev->sysfs_created) @@ -2611,6 +2691,17 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) return -ENOMEM; dev->acpi_dev = acpi_dev; dev->method_hci = hci_method; + dev->miscdev.minor = MISC_DYNAMIC_MINOR; + dev->miscdev.name = "toshiba_acpi"; + dev->miscdev.fops = &toshiba_acpi_fops; + + ret = misc_register(&dev->miscdev); + if (ret) { + pr_err("Failed to register miscdevice\n"); + kfree(dev); + return ret; + } + acpi_dev->driver_data = dev; dev_set_drvdata(&acpi_dev->dev, dev); diff --git a/include/uapi/linux/toshiba.h b/include/uapi/linux/toshiba.h index e9bef5b2f91e..c58bf4b5bb26 100644 --- a/include/uapi/linux/toshiba.h +++ b/include/uapi/linux/toshiba.h @@ -1,6 +1,7 @@ /* toshiba.h -- Linux driver for accessing the SMM on Toshiba laptops * * Copyright (c) 1996-2000 Jonathan A. Buzzard (jonathan@buzzard.org.uk) + * Copyright (c) 2015 Azael Avalos * * Thanks to Juergen Heinzl for the pointers * on making sure the structure is aligned and packed. @@ -20,9 +21,18 @@ #ifndef _UAPI_LINUX_TOSHIBA_H #define _UAPI_LINUX_TOSHIBA_H -#define TOSH_PROC "/proc/toshiba" -#define TOSH_DEVICE "/dev/toshiba" -#define TOSH_SMM _IOWR('t', 0x90, int) /* broken: meant 24 bytes */ +/* + * Toshiba modules paths + */ + +#define TOSH_PROC "/proc/toshiba" +#define TOSH_DEVICE "/dev/toshiba" +#define TOSHIBA_ACPI_PROC "/proc/acpi/toshiba" +#define TOSHIBA_ACPI_DEVICE "/dev/toshiba_acpi" + +/* + * Toshiba SMM structure + */ typedef struct { unsigned int eax; @@ -33,5 +43,21 @@ typedef struct { unsigned int edi __attribute__ ((packed)); } SMMRegisters; +/* + * IOCTLs (0x90 - 0x91) + */ + +#define TOSH_SMM _IOWR('t', 0x90, SMMRegisters) +/* + * Convenience toshiba_acpi command. + * + * The System Configuration Interface (SCI) is opened/closed internally + * to avoid userspace of buggy BIOSes. + * + * The toshiba_acpi module checks whether the eax register is set with + * SCI_GET (0xf300) or SCI_SET (0xf400), returning -EINVAL if not. + */ +#define TOSHIBA_ACPI_SCI _IOWR('t', 0x91, SMMRegisters) + #endif /* _UAPI_LINUX_TOSHIBA_H */ -- cgit v1.3-6-gb490 From a88bc06e5aec4984f5bf01c6d410a0939134f737 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 18:09:12 -0600 Subject: toshiba_acpi: Avoid registering input device on WMI event laptops Commit f11f999e9890 ("toshiba_acpi: Refuse to load on machines with buggy INFO implementations") denied loading on laptops with a WMI Event GUID given that such laptops manage the hotkeys via that interface, however, such laptops have a working Toshiba Configuration Interface (TCI), and thus, such commit denied several supported features. This patch avoids registering the input device and ignores all hotkey events on laptops with such WMI Event GUID, making the supported features found in those laptops to work. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 802577f43a23..48b16b323c89 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -2466,6 +2466,11 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) u32 hci_result; int error; + if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { + pr_info("WMI event detected, hotkeys will not be monitored\n"); + return 0; + } + error = toshiba_acpi_enable_hotkeys(dev); if (error) return error; @@ -2813,6 +2818,14 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) switch (event) { case 0x80: /* Hotkeys and some system events */ + /* + * Machines with this WMI GUID aren't supported due to bugs in + * their AML. + * + * Return silently to avoid triggering a netlink event. + */ + if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) + return; toshiba_acpi_process_hotkeys(dev); break; case 0x81: /* Dock events */ @@ -2899,14 +2912,6 @@ static int __init toshiba_acpi_init(void) { int ret; - /* - * Machines with this WMI guid aren't supported due to bugs in - * their AML. This check relies on wmi initializing before - * toshiba_acpi to guarantee guids have been identified. - */ - if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) - return -ENODEV; - toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); if (!toshiba_proc_dir) { pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); -- cgit v1.3-6-gb490 From 695f6060903cefa08ffb78433136f51ac0f94488 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 18:09:13 -0600 Subject: toshiba_acpi: Transflective backlight updates This patch changes the tr function second parameter from bool to u32, to be on par with the rest of the TCI functions of the driver, and the code was updated accordingly. Also, the check for translective support was moved to the *add function, as the {__get, set}_lcd_brightness functions make use of it. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 48b16b323c89..649786de4a79 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1187,22 +1187,17 @@ static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, } /* Transflective Backlight */ -static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) +static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) { - u32 hci_result; - u32 status; + u32 hci_result = hci_read(dev, HCI_TR_BACKLIGHT, status); - hci_result = hci_read(dev, HCI_TR_BACKLIGHT, &status); - *enabled = !status; return hci_result == TOS_SUCCESS ? 0 : -EIO; } -static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) +static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status) { - u32 hci_result; - u32 value = !enable; + u32 hci_result = hci_write(dev, HCI_TR_BACKLIGHT, !status); - hci_result = hci_write(dev, HCI_TR_BACKLIGHT, value); return hci_result == TOS_SUCCESS ? 0 : -EIO; } @@ -1216,12 +1211,11 @@ static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) int brightness = 0; if (dev->tr_backlight_supported) { - bool enabled; - int ret = get_tr_backlight_status(dev, &enabled); + int ret = get_tr_backlight_status(dev, &value); if (ret) return ret; - if (enabled) + if (value) return 0; brightness++; } @@ -1271,8 +1265,7 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) u32 hci_result; if (dev->tr_backlight_supported) { - bool enable = !value; - int ret = set_tr_backlight_status(dev, enable); + int ret = set_tr_backlight_status(dev, !value); if (ret) return ret; @@ -2563,7 +2556,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) struct backlight_properties props; int brightness; int ret; - bool enabled; /* * Some machines don't support the backlight methods at all, and @@ -2580,10 +2572,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) return 0; } - /* Determine whether or not BIOS supports transflective backlight */ - ret = get_tr_backlight_status(dev, &enabled); - dev->tr_backlight_supported = !ret; - /* * Tell acpi-video-detect code to prefer vendor backlight on all * systems with transflective backlight and on dmi matched systems. @@ -2723,6 +2711,10 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) if (toshiba_acpi_setup_keyboard(dev)) pr_info("Unable to activate hotkeys\n"); + /* Determine whether or not BIOS supports transflective backlight */ + ret = get_tr_backlight_status(dev, &dummy); + dev->tr_backlight_supported = !ret; + ret = toshiba_acpi_setup_backlight(dev); if (ret) goto error; -- cgit v1.3-6-gb490 From d7e4f2e2ca392bce468718bcbba808108d81d501 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 19:37:47 -0600 Subject: toshiba_acpi: Remove unused wireless defines Commit 2b74103547b4 ("toshiba_acpi: Remove bluetooth rfkill code") removed bluetooth related code, however, the wireless defines were not removed and are unused. This patch simply removes those defines as there is no code using them. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 649786de4a79..90d8cb1c2e27 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -113,7 +113,6 @@ MODULE_LICENSE("GPL"); #define HCI_VIDEO_OUT 0x001c #define HCI_HOTKEY_EVENT 0x001e #define HCI_LCD_BRIGHTNESS 0x002a -#define HCI_WIRELESS 0x0056 #define HCI_ACCELEROMETER 0x006d #define HCI_KBD_ILLUMINATION 0x0095 #define HCI_ECO_MODE 0x0097 @@ -142,10 +141,6 @@ MODULE_LICENSE("GPL"); #define HCI_VIDEO_OUT_LCD 0x1 #define HCI_VIDEO_OUT_CRT 0x2 #define HCI_VIDEO_OUT_TV 0x4 -#define HCI_WIRELESS_KILL_SWITCH 0x01 -#define HCI_WIRELESS_BT_PRESENT 0x0f -#define HCI_WIRELESS_BT_ATTACH 0x40 -#define HCI_WIRELESS_BT_POWER 0x80 #define SCI_KBD_MODE_MASK 0x1f #define SCI_KBD_MODE_FNZ 0x1 #define SCI_KBD_MODE_AUTO 0x2 -- cgit v1.3-6-gb490 From d50c9005d32b4eda6e11f7ec4f1b00a93088e0ca Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 19:37:46 -0600 Subject: toshiba_acpi: Reorder toshiba_acpi_alt_keymap entries This patch simply reorders the entries found in the new keymap by ascending order, this is simply a cosmetic change, no functionality was modified. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 90d8cb1c2e27..6013a11caeea 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -246,16 +246,16 @@ static const struct key_entry toshiba_acpi_keymap[] = { }; static const struct key_entry toshiba_acpi_alt_keymap[] = { - { KE_KEY, 0x157, { KEY_MUTE } }, { KE_KEY, 0x102, { KEY_ZOOMOUT } }, { KE_KEY, 0x103, { KEY_ZOOMIN } }, { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, { KE_KEY, 0x139, { KEY_ZOOMRESET } }, - { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, - { KE_KEY, 0x158, { KEY_WLAN } }, + { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, + { KE_KEY, 0x157, { KEY_MUTE } }, + { KE_KEY, 0x158, { KEY_WLAN } }, { KE_END, 0 }, }; -- cgit v1.3-6-gb490 From 1e574dbfadafd9fd1f2a414efb731d7538277e71 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 19:37:49 -0600 Subject: toshiba_acpi: Change some variables to avoid warnings from ninja-check This patch changes some variables to avoid warnings from ninja-check. We are basically moving some variables inside the conditionals where such variables are being used, and we are checking the returned values of some others. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 6013a11caeea..3bfdfddc38ac 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1651,7 +1651,6 @@ static ssize_t kbd_backlight_mode_store(struct device *dev, { struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); int mode; - int time; int ret; @@ -1682,7 +1681,7 @@ static ssize_t kbd_backlight_mode_store(struct device *dev, /* Only make a change if the actual mode has changed */ if (toshiba->kbd_mode != mode) { /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ - time = toshiba->kbd_time << HCI_MISC_SHIFT; + int time = toshiba->kbd_time << HCI_MISC_SHIFT; /* OR the "base time" to the actual method format */ if (toshiba->kbd_type == 1) { @@ -2856,10 +2855,14 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) static int toshiba_acpi_suspend(struct device *device) { struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); - u32 result; - if (dev->hotkey_dev) + if (dev->hotkey_dev) { + u32 result; + result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); + if (result != TOS_SUCCESS) + pr_info("Unable to disable hotkeys\n"); + } return 0; } @@ -2867,10 +2870,10 @@ static int toshiba_acpi_suspend(struct device *device) static int toshiba_acpi_resume(struct device *device) { struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); - int error; if (dev->hotkey_dev) { - error = toshiba_acpi_enable_hotkeys(dev); + int error = toshiba_acpi_enable_hotkeys(dev); + if (error) pr_info("Unable to re-enable hotkeys\n"); } -- cgit v1.3-6-gb490 From 454d3a2500a4eb33be85dde3bfba9e5f6b5efadc Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 22 Jul 2015 17:59:11 +0200 Subject: cpufreq: Remove cpufreq_rwsem cpufreq_rwsem was introduced in commit 6eed9404ab3c4 ("cpufreq: Use rwsem for protecting critical sections) in order to replace try_module_get() on the cpu-freq driver. That try_module_get() worked well until the refcount was so heavily used that module removal became more or less impossible. Though when looking at the various (undocumented) protection mechanisms in that code, the randomly sprinkeled around cpufreq_rwsem locking sites are superfluous. The policy, which is acquired in cpufreq_cpu_get() and released in cpufreq_cpu_put() is sufficiently protected already. cpufreq_cpu_get(cpu) /* Protects against concurrent driver removal */ read_lock_irqsave(&cpufreq_driver_lock, flags); policy = per_cpu(cpufreq_cpu_data, cpu); kobject_get(&policy->kobj); read_unlock_irqrestore(&cpufreq_driver_lock, flags); The reference on the policy serializes versus module unload already: cpufreq_unregister_driver() subsys_interface_unregister() __cpufreq_remove_dev_finish() per_cpu(cpufreq_cpu_data) = NULL; cpufreq_policy_put_kobj() If there is a reference held on the policy, i.e. obtained prior to the unregister call, then cpufreq_policy_put_kobj() will wait until that reference is dropped. So once subsys_interface_unregister() returns there is no policy pointer in flight and no new reference can be obtained. So that rwsem protection is useless. The other usage of cpufreq_rwsem in show()/store() of the sysfs interface is redundant as well because sysfs already does the proper kobject_get()/put() pairs. That leaves CPU hotplug versus module removal. The current down_write() around the write_lock() in cpufreq_unregister_driver() is silly at best as it protects actually nothing. The trivial solution to this is to prevent hotplug across cpufreq_unregister_driver completely. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 41 +++-------------------------------------- 1 file changed, 3 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a3e8fb61cbcc..febda462681c 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -112,12 +112,6 @@ static inline bool has_target(void) return cpufreq_driver->target_index || cpufreq_driver->target; } -/* - * rwsem to guarantee that cpufreq driver module doesn't unload during critical - * sections - */ -static DECLARE_RWSEM(cpufreq_rwsem); - /* internal prototypes */ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); @@ -277,10 +271,6 @@ EXPORT_SYMBOL_GPL(cpufreq_generic_get); * If corresponding call cpufreq_cpu_put() isn't made, the policy wouldn't be * freed as that depends on the kobj count. * - * It also takes a read-lock of 'cpufreq_rwsem' and doesn't put it back if a - * valid policy is found. This is done to make sure the driver doesn't get - * unregistered while the policy is being used. - * * Return: A valid policy on success, otherwise NULL on failure. */ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) @@ -291,9 +281,6 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) if (WARN_ON(cpu >= nr_cpu_ids)) return NULL; - if (!down_read_trylock(&cpufreq_rwsem)) - return NULL; - /* get the cpufreq driver */ read_lock_irqsave(&cpufreq_driver_lock, flags); @@ -306,9 +293,6 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) read_unlock_irqrestore(&cpufreq_driver_lock, flags); - if (!policy) - up_read(&cpufreq_rwsem); - return policy; } EXPORT_SYMBOL_GPL(cpufreq_cpu_get); @@ -320,13 +304,10 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_get); * * This decrements the kobject reference count incremented earlier by calling * cpufreq_cpu_get(). - * - * It also drops the read-lock of 'cpufreq_rwsem' taken at cpufreq_cpu_get(). */ void cpufreq_cpu_put(struct cpufreq_policy *policy) { kobject_put(&policy->kobj); - up_read(&cpufreq_rwsem); } EXPORT_SYMBOL_GPL(cpufreq_cpu_put); @@ -851,9 +832,6 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) struct freq_attr *fattr = to_attr(attr); ssize_t ret; - if (!down_read_trylock(&cpufreq_rwsem)) - return -EINVAL; - down_read(&policy->rwsem); if (fattr->show) @@ -862,7 +840,6 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) ret = -EIO; up_read(&policy->rwsem); - up_read(&cpufreq_rwsem); return ret; } @@ -879,9 +856,6 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, if (!cpu_online(policy->cpu)) goto unlock; - if (!down_read_trylock(&cpufreq_rwsem)) - goto unlock; - down_write(&policy->rwsem); /* Updating inactive policies is invalid, so avoid doing that. */ @@ -897,8 +871,6 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, unlock_policy_rwsem: up_write(&policy->rwsem); - - up_read(&cpufreq_rwsem); unlock: put_online_cpus(); @@ -1261,15 +1233,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) if (cpu_is_offline(cpu)) return add_cpu_dev_symlink(per_cpu(cpufreq_cpu_data, cpu), cpu); - if (!down_read_trylock(&cpufreq_rwsem)) - return 0; - /* Check if this CPU already has a policy to manage it */ policy = per_cpu(cpufreq_cpu_data, cpu); if (policy && !policy_is_inactive(policy)) { WARN_ON(!cpumask_test_cpu(cpu, policy->related_cpus)); ret = cpufreq_add_policy_cpu(policy, cpu, dev); - up_read(&cpufreq_rwsem); return ret; } @@ -1395,8 +1363,6 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) kobject_uevent(&policy->kobj, KOBJ_ADD); - up_read(&cpufreq_rwsem); - /* Callback for handling stuff after policy is ready */ if (cpufreq_driver->ready) cpufreq_driver->ready(policy); @@ -1416,8 +1382,6 @@ out_exit_policy: out_free_policy: cpufreq_policy_free(policy, recover_policy); out_release_rwsem: - up_read(&cpufreq_rwsem); - return ret; } @@ -2604,19 +2568,20 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) pr_debug("unregistering driver %s\n", driver->name); + /* Protect against concurrent cpu hotplug */ + get_online_cpus(); subsys_interface_unregister(&cpufreq_interface); if (cpufreq_boost_supported()) cpufreq_sysfs_remove_file(&boost.attr); unregister_hotcpu_notifier(&cpufreq_cpu_notifier); - down_write(&cpufreq_rwsem); write_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_driver = NULL; write_unlock_irqrestore(&cpufreq_driver_lock, flags); - up_write(&cpufreq_rwsem); + put_online_cpus(); return 0; } -- cgit v1.3-6-gb490 From a155a5db9389c4088c0901e665002332f2503660 Mon Sep 17 00:00:00 2001 From: Sriharsha Basavapatna Date: Wed, 22 Jul 2015 11:15:12 +0530 Subject: be2net: support ndo_get_phys_port_id() Add be_get_phys_port_id() function to report physical port id. The port id should be unique across different be2net devices in the system. We use the chip serial number along with the physical port number for this. Signed-off-by: Sriharsha Basavapatna Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 3 +++ drivers/net/ethernet/emulex/benet/be_cmds.c | 7 ++++++- drivers/net/ethernet/emulex/benet/be_cmds.h | 8 +++++--- drivers/net/ethernet/emulex/benet/be_main.c | 22 ++++++++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index cb5777bb7429..8cd384d0e38a 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -105,6 +105,8 @@ #define MAX_VFS 30 /* Max VFs supported by BE3 FW */ #define FW_VER_LEN 32 +#define CNTL_SERIAL_NUM_WORDS 8 /* Controller serial number words */ +#define CNTL_SERIAL_NUM_WORD_SZ (sizeof(u16)) /* Byte-sz of serial num word */ #define RSS_INDIR_TABLE_LEN 128 #define RSS_HASH_KEY_LEN 40 @@ -590,6 +592,7 @@ struct be_adapter { struct rss_info rss_info; /* Filters for packets that need to be sent to BMC */ u32 bmc_filt_mask; + u16 serial_num[CNTL_SERIAL_NUM_WORDS]; }; #define be_physfn(adapter) (!adapter->virtfn) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index ecad46f79653..3be1fbdcdd02 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2852,10 +2852,11 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) struct be_mcc_wrb *wrb; struct be_cmd_req_cntl_attribs *req; struct be_cmd_resp_cntl_attribs *resp; - int status; + int status, i; int payload_len = max(sizeof(*req), sizeof(*resp)); struct mgmt_controller_attrib *attribs; struct be_dma_mem attribs_cmd; + u32 *serial_num; if (mutex_lock_interruptible(&adapter->mbox_lock)) return -1; @@ -2886,6 +2887,10 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) if (!status) { attribs = attribs_cmd.va + sizeof(struct be_cmd_resp_hdr); adapter->hba_port_num = attribs->hba_attribs.phy_port; + serial_num = attribs->hba_attribs.controller_serial_number; + for (i = 0; i < CNTL_SERIAL_NUM_WORDS; i++) + adapter->serial_num[i] = le32_to_cpu(serial_num[i]) & + (BIT_MASK(16) - 1); } err: diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index a4479f7488d3..36d835bd5f3c 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1637,10 +1637,12 @@ struct be_cmd_req_set_qos { struct mgmt_hba_attribs { u32 rsvd0[24]; u8 controller_model_number[32]; - u32 rsvd1[79]; - u8 rsvd2[3]; + u32 rsvd1[16]; + u32 controller_serial_number[8]; + u32 rsvd2[55]; + u8 rsvd3[3]; u8 phy_port; - u32 rsvd3[13]; + u32 rsvd4[13]; } __packed; struct mgmt_controller_attrib { diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index c996dd76f546..5e92db8947d9 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -5219,6 +5219,27 @@ static netdev_features_t be_features_check(struct sk_buff *skb, } #endif +static int be_get_phys_port_id(struct net_device *dev, + struct netdev_phys_item_id *ppid) +{ + int i, id_len = CNTL_SERIAL_NUM_WORDS * CNTL_SERIAL_NUM_WORD_SZ + 1; + struct be_adapter *adapter = netdev_priv(dev); + u8 *id; + + if (MAX_PHYS_ITEM_ID_LEN < id_len) + return -ENOSPC; + + ppid->id[0] = adapter->hba_port_num + 1; + id = &ppid->id[1]; + for (i = CNTL_SERIAL_NUM_WORDS - 1; i >= 0; + i--, id += CNTL_SERIAL_NUM_WORD_SZ) + memcpy(id, &adapter->serial_num[i], CNTL_SERIAL_NUM_WORD_SZ); + + ppid->id_len = id_len; + + return 0; +} + static const struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, @@ -5249,6 +5270,7 @@ static const struct net_device_ops be_netdev_ops = { .ndo_del_vxlan_port = be_del_vxlan_port, .ndo_features_check = be_features_check, #endif + .ndo_get_phys_port_id = be_get_phys_port_id, }; static void be_netdev_init(struct net_device *netdev) -- cgit v1.3-6-gb490 From cbf919bd32d9424be8b77dac06fd90cd0a297562 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Thu, 9 Jul 2015 22:48:25 +0200 Subject: phy: add lpc18xx usb otg phy driver Add PHY driver for the internal USB OTG PHY found on NXP LPC18xx and LPC43xx devices. This driver takes care of enabling the PHY in CREG (syscon) and setting the required clock frequency. Signed-off-by: Joachim Eastwood Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 11 +++ drivers/phy/Makefile | 1 + drivers/phy/phy-lpc18xx-usb-otg.c | 143 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 drivers/phy/phy-lpc18xx-usb-otg.c (limited to 'drivers') diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index c0e6ede3e27d..e2f2a4d394e1 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -54,6 +54,17 @@ config PHY_EXYNOS_MIPI_VIDEO Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P and EXYNOS SoCs. +config PHY_LPC18XX_USB_OTG + tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver" + depends on OF && (ARCH_LPC18XX || COMPILE_TEST) + depends on MFD_SYSCON + select GENERIC_PHY + help + Enable this to support NXP LPC18xx/43xx internal USB OTG PHY. + + This driver is need for USB0 support on LPC18xx/43xx and takes + care of enabling and clock setup. + config PHY_PXA_28NM_HSIC tristate "Marvell USB HSIC 28nm PHY Driver" select GENERIC_PHY diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f344e1b2e825..a5b18c18fc12 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o +obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o diff --git a/drivers/phy/phy-lpc18xx-usb-otg.c b/drivers/phy/phy-lpc18xx-usb-otg.c new file mode 100644 index 000000000000..3aa8e4de1b03 --- /dev/null +++ b/drivers/phy/phy-lpc18xx-usb-otg.c @@ -0,0 +1,143 @@ +/* + * PHY driver for NXP LPC18xx/43xx internal USB OTG PHY + * + * Copyright (C) 2015 Joachim Eastwood + * + * 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 + +/* USB OTG PHY register offset and bit in CREG */ +#define LPC18XX_CREG_CREG0 0x004 +#define LPC18XX_CREG_CREG0_USB0PHY BIT(5) + +struct lpc18xx_usb_otg_phy { + struct phy *phy; + struct clk *clk; + struct regmap *reg; +}; + +static int lpc18xx_usb_otg_phy_init(struct phy *phy) +{ + struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy); + int ret; + + ret = clk_prepare(lpc->clk); + if (ret) + return ret; + + /* The PHY must be clocked at 480 MHz */ + return clk_set_rate(lpc->clk, 480000000); +} + +static int lpc18xx_usb_otg_phy_exit(struct phy *phy) +{ + struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy); + + clk_unprepare(lpc->clk); + + return 0; +} + +static int lpc18xx_usb_otg_phy_power_on(struct phy *phy) +{ + struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy); + int ret; + + ret = clk_enable(lpc->clk); + if (ret) + return ret; + + /* The bit in CREG is cleared to enable the PHY */ + return regmap_update_bits(lpc->reg, LPC18XX_CREG_CREG0, + LPC18XX_CREG_CREG0_USB0PHY, 0); +} + +static int lpc18xx_usb_otg_phy_power_off(struct phy *phy) +{ + struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy); + int ret; + + ret = regmap_update_bits(lpc->reg, LPC18XX_CREG_CREG0, + LPC18XX_CREG_CREG0_USB0PHY, + LPC18XX_CREG_CREG0_USB0PHY); + if (ret) + return ret; + + clk_disable(lpc->clk); + + return 0; +} + +static const struct phy_ops lpc18xx_usb_otg_phy_ops = { + .init = lpc18xx_usb_otg_phy_init, + .exit = lpc18xx_usb_otg_phy_exit, + .power_on = lpc18xx_usb_otg_phy_power_on, + .power_off = lpc18xx_usb_otg_phy_power_off, + .owner = THIS_MODULE, +}; + +static int lpc18xx_usb_otg_phy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct lpc18xx_usb_otg_phy *lpc; + + lpc = devm_kzalloc(&pdev->dev, sizeof(*lpc), GFP_KERNEL); + if (!lpc) + return -ENOMEM; + + lpc->reg = syscon_node_to_regmap(pdev->dev.of_node->parent); + if (IS_ERR(lpc->reg)) { + dev_err(&pdev->dev, "failed to get syscon\n"); + return PTR_ERR(lpc->reg); + } + + lpc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(lpc->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + return PTR_ERR(lpc->clk); + } + + lpc->phy = devm_phy_create(&pdev->dev, NULL, &lpc18xx_usb_otg_phy_ops); + if (IS_ERR(lpc->phy)) { + dev_err(&pdev->dev, "failed to create PHY\n"); + return PTR_ERR(lpc->phy); + } + + phy_set_drvdata(lpc->phy, lpc); + + phy_provider = devm_of_phy_provider_register(&pdev->dev, + of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id lpc18xx_usb_otg_phy_match[] = { + { .compatible = "nxp,lpc1850-usb-otg-phy" }, + { } +}; +MODULE_DEVICE_TABLE(of, lpc18xx_usb_otg_phy_match); + +static struct platform_driver lpc18xx_usb_otg_phy_driver = { + .probe = lpc18xx_usb_otg_phy_probe, + .driver = { + .name = "lpc18xx-usb-otg-phy", + .of_match_table = lpc18xx_usb_otg_phy_match, + }, +}; +module_platform_driver(lpc18xx_usb_otg_phy_driver); + +MODULE_AUTHOR("Joachim Eastwood "); +MODULE_DESCRIPTION("NXP LPC18xx/43xx USB OTG PHY driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From d2332303efc00d35af7f3d8b025663965862b0e3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:45 +0200 Subject: phy-sun4i-usb: Add id and vbus detection support for the otg phy (phy0) The usb0 phy is connected to an OTG controller, and as such needs some special handling: 1) It allows explicit control over the pullups, enable these on phy_init and disable them on phy_exit. 2) It has bits to signal id and vbus detect to the musb-core, add support for for monitoring id and vbus detect gpio-s for use in dual role mode, and set these bits to the correct values for operating in host only mode when no gpios are specified in the devicetree. While updating the devicetree binding documentation also add documentation for the sofar undocumented usage of regulators for vbus for all 3 phys. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/sun4i-usb-phy.txt | 18 +- drivers/phy/phy-sun4i-usb.c | 250 ++++++++++++++++++++- 2 files changed, 256 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 16528b9eb561..557fa9940164 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -23,6 +23,13 @@ Required properties: * "usb1_reset" * "usb2_reset" for sun4i, sun6i or sun7i +Optional properties: +- usb0_id_det-gpios : gpio phandle for reading the otg id pin value +- usb0_vbus_det-gpios : gpio phandle for detecting the presence of usb0 vbus +- usb0_vbus-supply : regulator phandle for controller usb0 vbus +- usb1_vbus-supply : regulator phandle for controller usb1 vbus +- usb2_vbus-supply : regulator phandle for controller usb2 vbus + Example: usbphy: phy@0x01c13400 { #phy-cells = <1>; @@ -32,6 +39,13 @@ Example: reg-names = "phy_ctrl", "pmu1", "pmu2"; clocks = <&usb_clk 8>; clock-names = "usb_phy"; - resets = <&usb_clk 1>, <&usb_clk 2>; - reset-names = "usb1_reset", "usb2_reset"; + resets = <&usb_clk 0>, <&usb_clk 1>, <&usb_clk 2>; + reset-names = "usb0_reset", "usb1_reset", "usb2_reset"; + pinctrl-names = "default"; + pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>; + usb0_id_det-gpios = <&pio 7 19 GPIO_ACTIVE_HIGH>; /* PH19 */ + usb0_vbus_det-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */ + usb0_vbus-supply = <®_usb0_vbus>; + usb1_vbus-supply = <®_usb1_vbus>; + usb2_vbus-supply = <®_usb2_vbus>; }; diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index e17c539e4f6f..37f52f73fdba 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -1,7 +1,7 @@ /* * Allwinner sun4i USB phy driver * - * Copyright (C) 2014 Hans de Goede + * Copyright (C) 2014-2015 Hans de Goede * * Based on code from * Allwinner Technology Co., Ltd. @@ -24,16 +24,19 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include #include +#include #define REG_ISCR 0x00 #define REG_PHYCTL 0x04 @@ -47,6 +50,17 @@ #define SUNXI_AHB_INCRX_ALIGN_EN BIT(8) #define SUNXI_ULPI_BYPASS_EN BIT(0) +/* ISCR, Interface Status and Control bits */ +#define ISCR_ID_PULLUP_EN (1 << 17) +#define ISCR_DPDM_PULLUP_EN (1 << 16) +/* sunxi has the phy id/vbus pins not connected, so we use the force bits */ +#define ISCR_FORCE_ID_MASK (3 << 14) +#define ISCR_FORCE_ID_LOW (2 << 14) +#define ISCR_FORCE_ID_HIGH (3 << 14) +#define ISCR_FORCE_VBUS_MASK (3 << 12) +#define ISCR_FORCE_VBUS_LOW (2 << 12) +#define ISCR_FORCE_VBUS_HIGH (3 << 12) + /* Common Control Bits for Both PHYs */ #define PHY_PLL_BW 0x03 #define PHY_RES45_CAL_EN 0x0c @@ -63,6 +77,13 @@ #define MAX_PHYS 3 +/* + * Note do not raise the debounce time, we must report Vusb high within 100ms + * otherwise we get Vbus errors + */ +#define DEBOUNCE_TIME msecs_to_jiffies(50) +#define POLL_TIME msecs_to_jiffies(250) + struct sun4i_usb_phy_data { void __iomem *base; struct mutex mutex; @@ -74,13 +95,56 @@ struct sun4i_usb_phy_data { struct regulator *vbus; struct reset_control *reset; struct clk *clk; + bool regulator_on; int index; } phys[MAX_PHYS]; + /* phy0 / otg related variables */ + bool phy0_init; + bool phy0_poll; + struct gpio_desc *id_det_gpio; + struct gpio_desc *vbus_det_gpio; + int id_det_irq; + int vbus_det_irq; + int id_det; + int vbus_det; + struct delayed_work detect; }; #define to_sun4i_usb_phy_data(phy) \ container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index]) +static void sun4i_usb_phy0_update_iscr(struct phy *_phy, u32 clr, u32 set) +{ + struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + u32 iscr; + + iscr = readl(data->base + REG_ISCR); + iscr &= ~clr; + iscr |= set; + writel(iscr, data->base + REG_ISCR); +} + +static void sun4i_usb_phy0_set_id_detect(struct phy *phy, u32 val) +{ + if (val) + val = ISCR_FORCE_ID_HIGH; + else + val = ISCR_FORCE_ID_LOW; + + sun4i_usb_phy0_update_iscr(phy, ISCR_FORCE_ID_MASK, val); +} + +static void sun4i_usb_phy0_set_vbus_detect(struct phy *phy, u32 val) +{ + if (val) + val = ISCR_FORCE_VBUS_HIGH; + else + val = ISCR_FORCE_VBUS_LOW; + + sun4i_usb_phy0_update_iscr(phy, ISCR_FORCE_VBUS_MASK, val); +} + static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, int len) { @@ -171,12 +235,39 @@ static int sun4i_usb_phy_init(struct phy *_phy) sun4i_usb_phy_passby(phy, 1); + if (phy->index == 0) { + data->phy0_init = true; + + /* Enable pull-ups */ + sun4i_usb_phy0_update_iscr(_phy, 0, ISCR_DPDM_PULLUP_EN); + sun4i_usb_phy0_update_iscr(_phy, 0, ISCR_ID_PULLUP_EN); + + if (data->id_det_gpio) { + /* OTG mode, force ISCR and cable state updates */ + data->id_det = -1; + data->vbus_det = -1; + queue_delayed_work(system_wq, &data->detect, 0); + } else { + /* Host only mode */ + sun4i_usb_phy0_set_id_detect(_phy, 0); + sun4i_usb_phy0_set_vbus_detect(_phy, 1); + } + } + return 0; } static int sun4i_usb_phy_exit(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + + if (phy->index == 0) { + /* Disable pull-ups */ + sun4i_usb_phy0_update_iscr(_phy, ISCR_DPDM_PULLUP_EN, 0); + sun4i_usb_phy0_update_iscr(_phy, ISCR_ID_PULLUP_EN, 0); + data->phy0_init = false; + } sun4i_usb_phy_passby(phy, 0); reset_control_assert(phy->reset); @@ -188,20 +279,46 @@ static int sun4i_usb_phy_exit(struct phy *_phy) static int sun4i_usb_phy_power_on(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); - int ret = 0; + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + int ret; + + if (!phy->vbus || phy->regulator_on) + return 0; + + /* For phy0 only turn on Vbus if we don't have an ext. Vbus */ + if (phy->index == 0 && data->vbus_det) + return 0; - if (phy->vbus) - ret = regulator_enable(phy->vbus); + ret = regulator_enable(phy->vbus); + if (ret) + return ret; - return ret; + phy->regulator_on = true; + + /* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */ + if (phy->index == 0 && data->phy0_poll) + mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); + + return 0; } static int sun4i_usb_phy_power_off(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); + struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy); + + if (!phy->vbus || !phy->regulator_on) + return 0; - if (phy->vbus) - regulator_disable(phy->vbus); + regulator_disable(phy->vbus); + phy->regulator_on = false; + + /* + * phy0 vbus typically slowly discharges, sometimes this causes the + * Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan. + */ + if (phy->index == 0 && !data->phy0_poll) + mod_delayed_work(system_wq, &data->detect, POLL_TIME); return 0; } @@ -221,6 +338,49 @@ static struct phy_ops sun4i_usb_phy_ops = { .owner = THIS_MODULE, }; +static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) +{ + struct sun4i_usb_phy_data *data = + container_of(work, struct sun4i_usb_phy_data, detect.work); + struct phy *phy0 = data->phys[0].phy; + int id_det, vbus_det; + + id_det = gpiod_get_value_cansleep(data->id_det_gpio); + vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); + + mutex_lock(&phy0->mutex); + + if (!data->phy0_init) { + mutex_unlock(&phy0->mutex); + return; + } + + if (id_det != data->id_det) { + sun4i_usb_phy0_set_id_detect(phy0, id_det); + data->id_det = id_det; + } + + if (vbus_det != data->vbus_det) { + sun4i_usb_phy0_set_vbus_detect(phy0, vbus_det); + data->vbus_det = vbus_det; + } + + mutex_unlock(&phy0->mutex); + + if (data->phy0_poll) + queue_delayed_work(system_wq, &data->detect, POLL_TIME); +} + +static irqreturn_t sun4i_usb_phy0_id_vbus_det_irq(int irq, void *dev_id) +{ + struct sun4i_usb_phy_data *data = dev_id; + + /* vbus or id changed, let the pins settle and then scan them */ + mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); + + return IRQ_HANDLED; +} + static struct phy *sun4i_usb_phy_xlate(struct device *dev, struct of_phandle_args *args) { @@ -232,6 +392,21 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev, return data->phys[args->args[0]].phy; } +static int sun4i_usb_phy_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); + + if (data->id_det_irq >= 0) + devm_free_irq(dev, data->id_det_irq, data); + if (data->vbus_det_irq >= 0) + devm_free_irq(dev, data->vbus_det_irq, data); + + cancel_delayed_work_sync(&data->detect); + + return 0; +} + static int sun4i_usb_phy_probe(struct platform_device *pdev) { struct sun4i_usb_phy_data *data; @@ -240,13 +415,15 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) struct phy_provider *phy_provider; bool dedicated_clocks; struct resource *res; - int i; + int i, ret; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; mutex_init(&data->mutex); + INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan); + dev_set_drvdata(dev, data); if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy")) data->num_phys = 2; @@ -269,6 +446,26 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) if (IS_ERR(data->base)) return PTR_ERR(data->base); + data->id_det_gpio = devm_gpiod_get(dev, "usb0_id_det", GPIOD_IN); + if (IS_ERR(data->id_det_gpio)) { + if (PTR_ERR(data->id_det_gpio) == -EPROBE_DEFER) + return -EPROBE_DEFER; + data->id_det_gpio = NULL; + } + + data->vbus_det_gpio = devm_gpiod_get(dev, "usb0_vbus_det", GPIOD_IN); + if (IS_ERR(data->vbus_det_gpio)) { + if (PTR_ERR(data->vbus_det_gpio) == -EPROBE_DEFER) + return -EPROBE_DEFER; + data->vbus_det_gpio = NULL; + } + + /* We either want both gpio pins or neither (when in host mode) */ + if (!data->id_det_gpio != !data->vbus_det_gpio) { + dev_err(dev, "failed to get id or vbus detect pin\n"); + return -ENODEV; + } + for (i = 0; i < data->num_phys; i++) { struct sun4i_usb_phy *phy = data->phys + i; char name[16]; @@ -318,10 +515,42 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) phy_set_drvdata(phy->phy, &data->phys[i]); } - dev_set_drvdata(dev, data); + data->id_det_irq = gpiod_to_irq(data->id_det_gpio); + data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio); + if (data->id_det_irq < 0 || data->vbus_det_irq < 0) + data->phy0_poll = true; + + if (data->id_det_irq >= 0) { + ret = devm_request_irq(dev, data->id_det_irq, + sun4i_usb_phy0_id_vbus_det_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "usb0-id-det", data); + if (ret) { + dev_err(dev, "Err requesting id-det-irq: %d\n", ret); + return ret; + } + } + + if (data->vbus_det_irq >= 0) { + ret = devm_request_irq(dev, data->vbus_det_irq, + sun4i_usb_phy0_id_vbus_det_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "usb0-vbus-det", data); + if (ret) { + dev_err(dev, "Err requesting vbus-det-irq: %d\n", ret); + data->vbus_det_irq = -1; + sun4i_usb_phy_remove(pdev); /* Stop detect work */ + return ret; + } + } + phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate); + if (IS_ERR(phy_provider)) { + sun4i_usb_phy_remove(pdev); /* Stop detect work */ + return PTR_ERR(phy_provider); + } - return PTR_ERR_OR_ZERO(phy_provider); + return 0; } static const struct of_device_id sun4i_usb_phy_of_match[] = { @@ -335,6 +564,7 @@ MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); static struct platform_driver sun4i_usb_phy_driver = { .probe = sun4i_usb_phy_probe, + .remove = sun4i_usb_phy_remove, .driver = { .of_match_table = sun4i_usb_phy_of_match, .name = "sun4i-usb-phy", -- cgit v1.3-6-gb490 From 1a52abe6821da728b41187c6676b6ab7294e6e2c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:46 +0200 Subject: phy-sun4i-usb: Add extcon support for the otg phy (phy0) The sunxi musb glue needs to know if a host or normal usb cable is plugged in, add extcon support so that the musb glue can monitor the host status. Signed-off-by: Hans de Goede Acked-by: Chanwoo Choi Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/Kconfig | 1 + drivers/phy/phy-sun4i-usb.c | 32 +++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index e2f2a4d394e1..c0c1ad2e2c01 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -208,6 +208,7 @@ config PHY_SUN4I_USB tristate "Allwinner sunxi SoC USB PHY driver" depends on ARCH_SUNXI && HAS_IOMEM && OF depends on RESET_CONTROLLER + depends on EXTCON select GENERIC_PHY help Enable this to support the transceiver that is part of Allwinner diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 37f52f73fdba..a6ea2e6b1d5c 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -99,6 +100,7 @@ struct sun4i_usb_phy_data { int index; } phys[MAX_PHYS]; /* phy0 / otg related variables */ + struct extcon_dev *extcon; bool phy0_init; bool phy0_poll; struct gpio_desc *id_det_gpio; @@ -343,7 +345,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) struct sun4i_usb_phy_data *data = container_of(work, struct sun4i_usb_phy_data, detect.work); struct phy *phy0 = data->phys[0].phy; - int id_det, vbus_det; + int id_det, vbus_det, id_notify = 0, vbus_notify = 0; id_det = gpiod_get_value_cansleep(data->id_det_gpio); vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); @@ -358,15 +360,24 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) if (id_det != data->id_det) { sun4i_usb_phy0_set_id_detect(phy0, id_det); data->id_det = id_det; + id_notify = 1; } if (vbus_det != data->vbus_det) { sun4i_usb_phy0_set_vbus_detect(phy0, vbus_det); data->vbus_det = vbus_det; + vbus_notify = 1; } mutex_unlock(&phy0->mutex); + if (id_notify) + extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST, + !id_det); + + if (vbus_notify) + extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det); + if (data->phy0_poll) queue_delayed_work(system_wq, &data->detect, POLL_TIME); } @@ -407,6 +418,12 @@ static int sun4i_usb_phy_remove(struct platform_device *pdev) return 0; } +static const unsigned int sun4i_usb_phy0_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_NONE, +}; + static int sun4i_usb_phy_probe(struct platform_device *pdev) { struct sun4i_usb_phy_data *data; @@ -466,6 +483,19 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) return -ENODEV; } + if (data->id_det_gpio) { + data->extcon = devm_extcon_dev_allocate(dev, + sun4i_usb_phy0_cable); + if (IS_ERR(data->extcon)) + return PTR_ERR(data->extcon); + + ret = devm_extcon_dev_register(dev, data->extcon); + if (ret) { + dev_err(dev, "failed to register extcon: %d\n", ret); + return ret; + } + } + for (i = 0; i < data->num_phys; i++) { struct sun4i_usb_phy *phy = data->phys + i; char name[16]; -- cgit v1.3-6-gb490 From 2846469631393a1cf150f17a99b8ca2b5772b255 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:47 +0200 Subject: phy-sun4i-usb: Swap check for disconnect threshold Before this commit the code for determining the disconnect threshold was checking for "allwinner,sun4i-a10-usb-phy" or "allwinner,sun6i-a31-usb-phy" assuming that those where the exception and then newer SoCs would use a disconnect threshold of 2 like sun7i does. But it turns out that newer SoCs use a disconnect threshold of 3 and sun5i and sun7i are the exceptions, so check for those instead. Here are the settings from the various Allwinner SDK sources: sun4i-a10: USBC_Phy_Write(usbc_no, 0x2a, 3, 2); sun5i-a13: USBC_Phy_Write(usbc_no, 0x2a, 2, 2); sun6i-a31: USBC_Phy_Write(usbc_no, 0x2a, 3, 2); sun7i-a20: USBC_Phy_Write(usbc_no, 0x2a, 2, 2); sun8i-a23: USBC_Phy_Write(usbc_no, 0x2a, 3, 2); sun8i-h3: USBC_Phy_Write(usbc_no, 0x2a, 3, 2); sun9i-a80: USBC_Phy_Write(usbc_no, 0x2a, 3, 2); Note this commit makes no functional changes as currently we only support sun4i - sun7i. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index a6ea2e6b1d5c..50ecab9d73df 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -447,11 +447,11 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) else data->num_phys = 3; - if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy") || - of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy")) - data->disc_thresh = 3; - else + if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") || + of_device_is_compatible(np, "allwinner,sun7i-a20-usb-phy")) data->disc_thresh = 2; + else + data->disc_thresh = 3; if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy")) dedicated_clocks = true; -- cgit v1.3-6-gb490 From 123dfdbcfaf5eb8753cd6293ab50c41e9b8e9ebf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:48 +0200 Subject: phy-sun4i-usb: Add support for the usb-phys on the sun8i-a23 SoC The usb-phys on the sun8i-a23 SoC have the same setup wrt clocks as on the sun6i-a31 SoC, but there are only 2 instead of 3 like on the sun5i-a13 SoC. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt | 2 ++ drivers/phy/phy-sun4i-usb.c | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 557fa9940164..f0c640adee64 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -7,6 +7,7 @@ Required properties: * allwinner,sun5i-a13-usb-phy * allwinner,sun6i-a31-usb-phy * allwinner,sun7i-a20-usb-phy + * allwinner,sun8i-a23-usb-phy - reg : a list of offset + length pairs - reg-names : * "phy_ctrl" @@ -17,6 +18,7 @@ Required properties: - clock-names : * "usb_phy" for sun4i, sun5i or sun7i * "usb0_phy", "usb1_phy" and "usb2_phy" for sun6i + * "usb0_phy", "usb1_phy" for sun8i - resets : a list of phandle + reset specifier pairs - reset-names : * "usb0_reset" diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 50ecab9d73df..00424dde79c1 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -442,7 +442,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan); dev_set_drvdata(dev, data); - if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy")) + if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) data->num_phys = 2; else data->num_phys = 3; @@ -453,7 +454,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) else data->disc_thresh = 3; - if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy")) + if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) dedicated_clocks = true; else dedicated_clocks = false; @@ -588,6 +590,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { { .compatible = "allwinner,sun5i-a13-usb-phy" }, { .compatible = "allwinner,sun6i-a31-usb-phy" }, { .compatible = "allwinner,sun7i-a20-usb-phy" }, + { .compatible = "allwinner,sun8i-a23-usb-phy" }, { }, }; MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); -- cgit v1.3-6-gb490 From fc1f45ed3043da3aa901e88a9ef0995bbd320698 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:49 +0200 Subject: phy-sun4i-usb: Add support for the usb-phys on the sun8i-a33 SoC The usb-phys on the sun8i-a33 SoC are mostly the same as sun8i-a23 but for some reason (hw bug?) the phyctl register was moved to a different address and is not initialized to 0 on reset. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/sun4i-usb-phy.txt | 1 + drivers/phy/phy-sun4i-usb.c | 39 ++++++++++++++++------ 2 files changed, 29 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index f0c640adee64..5f48979b4edc 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -8,6 +8,7 @@ Required properties: * allwinner,sun6i-a31-usb-phy * allwinner,sun7i-a20-usb-phy * allwinner,sun8i-a23-usb-phy + * allwinner,sun8i-a33-usb-phy - reg : a list of offset + length pairs - reg-names : * "phy_ctrl" diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 00424dde79c1..ddc399536c5c 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -40,9 +40,10 @@ #include #define REG_ISCR 0x00 -#define REG_PHYCTL 0x04 +#define REG_PHYCTL_A10 0x04 #define REG_PHYBIST 0x08 #define REG_PHYTUNE 0x0c +#define REG_PHYCTL_A33 0x10 #define PHYCTL_DATA BIT(7) @@ -90,6 +91,7 @@ struct sun4i_usb_phy_data { struct mutex mutex; int num_phys; u32 disc_thresh; + bool has_a33_phyctl; struct sun4i_usb_phy { struct phy *phy; void __iomem *pmu; @@ -152,37 +154,46 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, { struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy); u32 temp, usbc_bit = BIT(phy->index * 2); + void *phyctl; int i; mutex_lock(&phy_data->mutex); + if (phy_data->has_a33_phyctl) { + phyctl = phy_data->base + REG_PHYCTL_A33; + /* A33 needs us to set phyctl to 0 explicitly */ + writel(0, phyctl); + } else { + phyctl = phy_data->base + REG_PHYCTL_A10; + } + for (i = 0; i < len; i++) { - temp = readl(phy_data->base + REG_PHYCTL); + temp = readl(phyctl); /* clear the address portion */ temp &= ~(0xff << 8); /* set the address */ temp |= ((addr + i) << 8); - writel(temp, phy_data->base + REG_PHYCTL); + writel(temp, phyctl); /* set the data bit and clear usbc bit*/ - temp = readb(phy_data->base + REG_PHYCTL); + temp = readb(phyctl); if (data & 0x1) temp |= PHYCTL_DATA; else temp &= ~PHYCTL_DATA; temp &= ~usbc_bit; - writeb(temp, phy_data->base + REG_PHYCTL); + writeb(temp, phyctl); /* pulse usbc_bit */ - temp = readb(phy_data->base + REG_PHYCTL); + temp = readb(phyctl); temp |= usbc_bit; - writeb(temp, phy_data->base + REG_PHYCTL); + writeb(temp, phyctl); - temp = readb(phy_data->base + REG_PHYCTL); + temp = readb(phyctl); temp &= ~usbc_bit; - writeb(temp, phy_data->base + REG_PHYCTL); + writeb(temp, phyctl); data >>= 1; } @@ -443,7 +454,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) dev_set_drvdata(dev, data); if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") || - of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy")) data->num_phys = 2; else data->num_phys = 3; @@ -455,11 +467,15 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->disc_thresh = 3; if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") || - of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy")) + of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") || + of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy")) dedicated_clocks = true; else dedicated_clocks = false; + if (of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy")) + data->has_a33_phyctl = true; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl"); data->base = devm_ioremap_resource(dev, res); if (IS_ERR(data->base)) @@ -591,6 +607,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { { .compatible = "allwinner,sun6i-a31-usb-phy" }, { .compatible = "allwinner,sun7i-a20-usb-phy" }, { .compatible = "allwinner,sun8i-a23-usb-phy" }, + { .compatible = "allwinner,sun8i-a33-usb-phy" }, { }, }; MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); -- cgit v1.3-6-gb490 From 1aedf3a7a47b8bbd38c147eeb0c83816c5590215 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:50 +0200 Subject: phy-sun4i-usb: Add support for boards with broken Vusb-detection On some boards we cannot detect the presence of an external Vusb, because e.g. the 5V of the otg connector is directly connected to the 5V of the board, and thus is always high. This commit adds support for using such boards by only looking at the id-detection pin. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index ddc399536c5c..4ba9856ac71a 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -309,7 +310,7 @@ static int sun4i_usb_phy_power_on(struct phy *_phy) phy->regulator_on = true; /* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */ - if (phy->index == 0 && data->phy0_poll) + if (phy->index == 0 && data->vbus_det_gpio && data->phy0_poll) mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); return 0; @@ -330,7 +331,7 @@ static int sun4i_usb_phy_power_off(struct phy *_phy) * phy0 vbus typically slowly discharges, sometimes this causes the * Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan. */ - if (phy->index == 0 && !data->phy0_poll) + if (phy->index == 0 && data->vbus_det_gpio && !data->phy0_poll) mod_delayed_work(system_wq, &data->detect, POLL_TIME); return 0; @@ -359,7 +360,10 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) int id_det, vbus_det, id_notify = 0, vbus_notify = 0; id_det = gpiod_get_value_cansleep(data->id_det_gpio); - vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); + if (data->vbus_det_gpio) + vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); + else + vbus_det = 1; /* Report vbus as high */ mutex_lock(&phy0->mutex); @@ -369,6 +373,16 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) } if (id_det != data->id_det) { + /* + * When a host cable (id == 0) gets plugged in on systems + * without vbus detection report vbus low for long enough for + * the musb-ip to end the current device session. + */ + if (!data->vbus_det_gpio && id_det == 0) { + sun4i_usb_phy0_set_vbus_detect(phy0, 0); + msleep(200); + sun4i_usb_phy0_set_vbus_detect(phy0, 1); + } sun4i_usb_phy0_set_id_detect(phy0, id_det); data->id_det = id_det; id_notify = 1; @@ -382,9 +396,22 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) mutex_unlock(&phy0->mutex); - if (id_notify) + if (id_notify) { extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST, !id_det); + /* + * When a host cable gets unplugged (id == 1) on systems + * without vbus detection report vbus low for long enough to + * the musb-ip to end the current host session. + */ + if (!data->vbus_det_gpio && id_det == 1) { + mutex_lock(&phy0->mutex); + sun4i_usb_phy0_set_vbus_detect(phy0, 0); + msleep(1000); + sun4i_usb_phy0_set_vbus_detect(phy0, 1); + mutex_unlock(&phy0->mutex); + } + } if (vbus_notify) extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det); @@ -495,9 +522,9 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->vbus_det_gpio = NULL; } - /* We either want both gpio pins or neither (when in host mode) */ - if (!data->id_det_gpio != !data->vbus_det_gpio) { - dev_err(dev, "failed to get id or vbus detect pin\n"); + /* vbus_det without id_det makes no sense, and is not supported */ + if (data->vbus_det_gpio && !data->id_det_gpio) { + dev_err(dev, "usb0_id_det missing or invalid\n"); return -ENODEV; } @@ -565,7 +592,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->id_det_irq = gpiod_to_irq(data->id_det_gpio); data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio); - if (data->id_det_irq < 0 || data->vbus_det_irq < 0) + if ((data->id_det_gpio && data->id_det_irq < 0) || + (data->vbus_det_gpio && data->vbus_det_irq < 0)) data->phy0_poll = true; if (data->id_det_irq >= 0) { -- cgit v1.3-6-gb490 From 8665c18bece7965c3690ac3824bef2f97bae3d71 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 Jun 2015 14:37:51 +0200 Subject: phy-sun4i-usb: Add support for monitoring vbus via a power-supply On some boards there is no vbus_det gpio pin, instead vbus-detection for otg can be done via the pmic. This commit adds support for monitoring vbus_det via the power_supply exported by the pmic, enabling support for otg on these boards. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- .../devicetree/bindings/phy/sun4i-usb-phy.txt | 1 + drivers/phy/Kconfig | 1 + drivers/phy/phy-sun4i-usb.c | 76 ++++++++++++++++++++-- 3 files changed, 71 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 5f48979b4edc..0cebf7454517 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -29,6 +29,7 @@ Required properties: Optional properties: - usb0_id_det-gpios : gpio phandle for reading the otg id pin value - usb0_vbus_det-gpios : gpio phandle for detecting the presence of usb0 vbus +- usb0_vbus_power-supply: power-supply phandle for usb0 vbus presence detect - usb0_vbus-supply : regulator phandle for controller usb0 vbus - usb1_vbus-supply : regulator phandle for controller usb1 vbus - usb2_vbus-supply : regulator phandle for controller usb2 vbus diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index c0c1ad2e2c01..0fe9bff7b37b 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -209,6 +209,7 @@ config PHY_SUN4I_USB depends on ARCH_SUNXI && HAS_IOMEM && OF depends on RESET_CONTROLLER depends on EXTCON + depends on POWER_SUPPLY select GENERIC_PHY help Enable this to support the transceiver that is part of Allwinner diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 4ba9856ac71a..5138843ec42d 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,9 @@ struct sun4i_usb_phy_data { bool phy0_poll; struct gpio_desc *id_det_gpio; struct gpio_desc *vbus_det_gpio; + struct power_supply *vbus_power_supply; + struct notifier_block vbus_power_nb; + bool vbus_power_nb_registered; int id_det_irq; int vbus_det_irq; int id_det; @@ -352,6 +356,30 @@ static struct phy_ops sun4i_usb_phy_ops = { .owner = THIS_MODULE, }; +static int sun4i_usb_phy0_get_vbus_det(struct sun4i_usb_phy_data *data) +{ + if (data->vbus_det_gpio) + return gpiod_get_value_cansleep(data->vbus_det_gpio); + + if (data->vbus_power_supply) { + union power_supply_propval val; + int r; + + r = power_supply_get_property(data->vbus_power_supply, + POWER_SUPPLY_PROP_PRESENT, &val); + if (r == 0) + return val.intval; + } + + /* Fallback: report vbus as high */ + return 1; +} + +static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data) +{ + return data->vbus_det_gpio || data->vbus_power_supply; +} + static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) { struct sun4i_usb_phy_data *data = @@ -360,10 +388,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) int id_det, vbus_det, id_notify = 0, vbus_notify = 0; id_det = gpiod_get_value_cansleep(data->id_det_gpio); - if (data->vbus_det_gpio) - vbus_det = gpiod_get_value_cansleep(data->vbus_det_gpio); - else - vbus_det = 1; /* Report vbus as high */ + vbus_det = sun4i_usb_phy0_get_vbus_det(data); mutex_lock(&phy0->mutex); @@ -378,7 +403,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) * without vbus detection report vbus low for long enough for * the musb-ip to end the current device session. */ - if (!data->vbus_det_gpio && id_det == 0) { + if (!sun4i_usb_phy0_have_vbus_det(data) && id_det == 0) { sun4i_usb_phy0_set_vbus_detect(phy0, 0); msleep(200); sun4i_usb_phy0_set_vbus_detect(phy0, 1); @@ -404,7 +429,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) * without vbus detection report vbus low for long enough to * the musb-ip to end the current host session. */ - if (!data->vbus_det_gpio && id_det == 1) { + if (!sun4i_usb_phy0_have_vbus_det(data) && id_det == 1) { mutex_lock(&phy0->mutex); sun4i_usb_phy0_set_vbus_detect(phy0, 0); msleep(1000); @@ -430,6 +455,20 @@ static irqreturn_t sun4i_usb_phy0_id_vbus_det_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static int sun4i_usb_phy0_vbus_notify(struct notifier_block *nb, + unsigned long val, void *v) +{ + struct sun4i_usb_phy_data *data = + container_of(nb, struct sun4i_usb_phy_data, vbus_power_nb); + struct power_supply *psy = v; + + /* Properties on the vbus_power_supply changed, scan vbus_det */ + if (val == PSY_EVENT_PROP_CHANGED && psy == data->vbus_power_supply) + mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME); + + return NOTIFY_OK; +} + static struct phy *sun4i_usb_phy_xlate(struct device *dev, struct of_phandle_args *args) { @@ -446,6 +485,8 @@ static int sun4i_usb_phy_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); + if (data->vbus_power_nb_registered) + power_supply_unreg_notifier(&data->vbus_power_nb); if (data->id_det_irq >= 0) devm_free_irq(dev, data->id_det_irq, data); if (data->vbus_det_irq >= 0) @@ -522,8 +563,18 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) data->vbus_det_gpio = NULL; } + if (of_find_property(np, "usb0_vbus_power-supply", NULL)) { + data->vbus_power_supply = devm_power_supply_get_by_phandle(dev, + "usb0_vbus_power-supply"); + if (IS_ERR(data->vbus_power_supply)) + return PTR_ERR(data->vbus_power_supply); + + if (!data->vbus_power_supply) + return -EPROBE_DEFER; + } + /* vbus_det without id_det makes no sense, and is not supported */ - if (data->vbus_det_gpio && !data->id_det_gpio) { + if (sun4i_usb_phy0_have_vbus_det(data) && !data->id_det_gpio) { dev_err(dev, "usb0_id_det missing or invalid\n"); return -ENODEV; } @@ -620,6 +671,17 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev) } } + if (data->vbus_power_supply) { + data->vbus_power_nb.notifier_call = sun4i_usb_phy0_vbus_notify; + data->vbus_power_nb.priority = 0; + ret = power_supply_reg_notifier(&data->vbus_power_nb); + if (ret) { + sun4i_usb_phy_remove(pdev); /* Stop detect work */ + return ret; + } + data->vbus_power_nb_registered = true; + } + phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate); if (IS_ERR(phy_provider)) { sun4i_usb_phy_remove(pdev); /* Stop detect work */ -- cgit v1.3-6-gb490 From 2c89e41f03fa9798405e07bae95760fc86a1068f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 24 Jun 2015 10:40:53 +0200 Subject: phy: berlin: .owner field is setup by core There was big cleanup in past to remove this unneeded setting. Signed-off-by: Michal Simek Acked-by: Antoine Tenart Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-berlin-usb.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c index c6fc95b53083..d7431f6ab975 100644 --- a/drivers/phy/phy-berlin-usb.c +++ b/drivers/phy/phy-berlin-usb.c @@ -207,7 +207,6 @@ static struct platform_driver phy_berlin_usb_driver = { .probe = phy_berlin_usb_probe, .driver = { .name = "phy-berlin-usb", - .owner = THIS_MODULE, .of_match_table = phy_berlin_sata_of_match, }, }; -- cgit v1.3-6-gb490 From 456dedc9e70d2d99b928d215baa881c03369c613 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 24 Jun 2015 10:40:54 +0200 Subject: phy: berlin: Do not use sata name in usb phy driver copy and paste error from berlin sata phy driver. Signed-off-by: Michal Simek Acked-by: Antoine Tenart Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-berlin-usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c index d7431f6ab975..762f0fbdc119 100644 --- a/drivers/phy/phy-berlin-usb.c +++ b/drivers/phy/phy-berlin-usb.c @@ -152,7 +152,7 @@ static struct phy_ops phy_berlin_usb_ops = { .owner = THIS_MODULE, }; -static const struct of_device_id phy_berlin_sata_of_match[] = { +static const struct of_device_id phy_berlin_usb_of_match[] = { { .compatible = "marvell,berlin2-usb-phy", .data = &phy_berlin_pll_dividers[0], @@ -163,12 +163,12 @@ static const struct of_device_id phy_berlin_sata_of_match[] = { }, { }, }; -MODULE_DEVICE_TABLE(of, phy_berlin_sata_of_match); +MODULE_DEVICE_TABLE(of, phy_berlin_usb_of_match); static int phy_berlin_usb_probe(struct platform_device *pdev) { const struct of_device_id *match = - of_match_device(phy_berlin_sata_of_match, &pdev->dev); + of_match_device(phy_berlin_usb_of_match, &pdev->dev); struct phy_berlin_usb_priv *priv; struct resource *res; struct phy *phy; @@ -207,7 +207,7 @@ static struct platform_driver phy_berlin_usb_driver = { .probe = phy_berlin_usb_probe, .driver = { .name = "phy-berlin-usb", - .of_match_table = phy_berlin_sata_of_match, + .of_match_table = phy_berlin_usb_of_match, }, }; module_platform_driver(phy_berlin_usb_driver); -- cgit v1.3-6-gb490 From 2508aaed39c94f61c11ee66787ed4702c8afbc67 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 24 Jun 2015 10:40:55 +0200 Subject: phy: berlin: Trivial coding style cleanup Remove unneeded space after tab. Signed-off-by: Michal Simek Acked-by: Antoine Tenart Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-berlin-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c index 762f0fbdc119..0fe0d81c29ee 100644 --- a/drivers/phy/phy-berlin-usb.c +++ b/drivers/phy/phy-berlin-usb.c @@ -208,7 +208,7 @@ static struct platform_driver phy_berlin_usb_driver = { .driver = { .name = "phy-berlin-usb", .of_match_table = phy_berlin_usb_of_match, - }, + }, }; module_platform_driver(phy_berlin_usb_driver); -- cgit v1.3-6-gb490 From 511fdecc9bc98c7b498e72b0dfe8f34481334e4c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:38:10 +0900 Subject: phy: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-armada375-usb2.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/phy/phy-armada375-usb2.c b/drivers/phy/phy-armada375-usb2.c index 8ccc3952c13d..39c7d21f12da 100644 --- a/drivers/phy/phy-armada375-usb2.c +++ b/drivers/phy/phy-armada375-usb2.c @@ -149,7 +149,6 @@ static struct platform_driver armada375_usb_phy_driver = { .driver = { .of_match_table = of_usb_cluster_table, .name = "armada-375-usb-cluster", - .owner = THIS_MODULE, } }; module_platform_driver(armada375_usb_phy_driver); -- cgit v1.3-6-gb490 From 219bf1599e1f6c0cbdc2fe775a97c00bf1ae392d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:26:27 +0900 Subject: phy: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-miphy28lp.c | 1 - drivers/phy/phy-qcom-ufs-qmp-14nm.c | 1 - drivers/phy/phy-qcom-ufs-qmp-20nm.c | 1 - drivers/phy/phy-rockchip-usb.c | 1 - 4 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index 5e257ef7ac05..677c290f4b14 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -1268,7 +1268,6 @@ static struct platform_driver miphy28lp_driver = { .probe = miphy28lp_probe, .driver = { .name = "miphy28lp-phy", - .owner = THIS_MODULE, .of_match_table = miphy28lp_of_match, } }; diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/phy-qcom-ufs-qmp-14nm.c index f5fc50a9fce7..e1eea1b379fc 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c @@ -191,7 +191,6 @@ static struct platform_driver ufs_qcom_phy_qmp_14nm_driver = { .driver = { .of_match_table = ufs_qcom_phy_qmp_14nm_of_match, .name = "ufs_qcom_phy_qmp_14nm", - .owner = THIS_MODULE, }, }; diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c index 8332f96b2c4a..fde8c876823b 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -247,7 +247,6 @@ static struct platform_driver ufs_qcom_phy_qmp_20nm_driver = { .driver = { .of_match_table = ufs_qcom_phy_qmp_20nm_of_match, .name = "ufs_qcom_phy_qmp_20nm", - .owner = THIS_MODULE, }, }; diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index 7d4c33643768..bf78721b58f4 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c @@ -146,7 +146,6 @@ static struct platform_driver rockchip_usb_driver = { .probe = rockchip_usb_phy_probe, .driver = { .name = "rockchip-usb-phy", - .owner = THIS_MODULE, .of_match_table = rockchip_usb_phy_dt_ids, }, }; -- cgit v1.3-6-gb490 From 92ff7a698badec3938edd3ba6b3e3ae035555365 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 25 Jul 2015 21:10:27 +0200 Subject: bcma: fix build error when build as module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently of_default_bus_match_table is not exported so we can only use this feature when bcma is build into the kernel. This patch removes support for child buses when bcma is build as a module as a temporary fix for a build problem introduces in this commit: commit cae761b5a6bdc597ba476a040fdcd5b4bc559b85 Author: Rafał Miłecki Date: Sun Jun 28 17:17:13 2015 +0200 bcma: populate bus DT subnodes as platform_device-s Reported-by: Stephen Rothwell Fixes: cae761b5a6bd ("bcma: populate bus DT subnodes as platform_device-s") Signed-off-by: Hauke Mehrtens Signed-off-by: Kalle Valo --- drivers/bcma/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 59128478a90f..8d973c4fc84e 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -410,7 +410,11 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_pci_early_init(&bus->drv_pci[0]); } - if (bus->host_pdev) { + /* TODO: remove check for IS_BUILTIN(CONFIG_BCMA) check when + * of_default_bus_match_table is exported or in some other way + * accessible. This is just a temporary workaround. + */ + if (IS_BUILTIN(CONFIG_BCMA) && bus->host_pdev) { struct device *dev = &bus->host_pdev->dev; of_platform_populate(dev->of_node, of_default_bus_match_table, -- cgit v1.3-6-gb490 From 7dd0e0af64afe4aa08ccdd167f64bd007f09b515 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 27 May 2015 17:11:37 -0400 Subject: intel_idle: allow idle states to be freeze-mode specific intel_idle uses a NULL "enter" field in a cpuidle state to recognize the invalid entry terminating a variable-length array. Linux-4.0 added support for the system-wide "freeze" state in cpuidle drivers via the new "enter_freeze" field. The natural way to expose a deep idle state for freeze, but not for run-time idle is to supply "enter_freeze" without "enter"; so we update the driver to accept such states. Signed-off-by: Len Brown --- drivers/idle/intel_idle.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 2a36a95d95cf..008e943d224d 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -965,7 +965,8 @@ static int __init intel_idle_cpuidle_driver_init(void) for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { int num_substates, mwait_hint, mwait_cstate; - if (cpuidle_state_table[cstate].enter == NULL) + if ((cpuidle_state_table[cstate].enter == NULL) && + (cpuidle_state_table[cstate].enter_freeze == NULL)) break; if (cstate + 1 > max_cstate) { -- cgit v1.3-6-gb490 From 6b6948dda798637aea237df0d0c8bcba8fa653bc Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Jul 2015 17:08:42 +0200 Subject: vxlan: Use proper endian type for vni in vxlan[6]_xmit_skb Silences the following sparse warnings: drivers/net/vxlan.c:1818:21: warning: incorrect type in assignment (different base types) drivers/net/vxlan.c:1818:21: expected restricted __be32 [usertype] vx_vni drivers/net/vxlan.c:1818:21: got unsigned int [unsigned] [usertype] vni drivers/net/vxlan.c:2014:58: warning: incorrect type in argument 11 (different base types) drivers/net/vxlan.c:2014:58: expected unsigned int [unsigned] [usertype] vni drivers/net/vxlan.c:2014:58: got restricted __be32 [usertype] Fixes: 614732eaa12d ("openvswitch: Use regular VXLAN net_device device") Reported-by: kbuild test robot Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index e9feefb41f0b..81f0f24b2cfb 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1686,7 +1686,7 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, - __be16 src_port, __be16 dst_port, __u32 vni, + __be16 src_port, __be16 dst_port, __be32 vni, struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; @@ -1771,7 +1771,7 @@ err: static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, - __be16 src_port, __be16 dst_port, __u32 vni, + __be16 src_port, __be16 dst_port, __be32 vni, struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; -- cgit v1.3-6-gb490 From 402b764533e9d973952573df7ff96c41189e1a14 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 22 Jul 2015 22:54:50 +0530 Subject: cxgb4: Allow firmware flash, only if cxgb4 is the master driver Adapter can go for a toss, if cxgb4 is loaded as slave and we try to upgrade the firmware. So add a check for the same before flashing firmware using ethtool. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c index 687acf71fa15..5eedb98ff581 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c @@ -925,6 +925,20 @@ static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) const struct firmware *fw; struct adapter *adap = netdev2adap(netdev); unsigned int mbox = PCIE_FW_MASTER_M + 1; + u32 pcie_fw; + unsigned int master; + u8 master_vld = 0; + + pcie_fw = t4_read_reg(adap, PCIE_FW_A); + master = PCIE_FW_MASTER_G(pcie_fw); + if (pcie_fw & PCIE_FW_MASTER_VLD_F) + master_vld = 1; + /* if csiostor is the master return */ + if (master_vld && (master != adap->pf)) { + dev_warn(adap->pdev_dev, + "cxgb4 driver needs to be loaded as MASTER to support FW flash\n"); + return -EOPNOTSUPP; + } ef->data[sizeof(ef->data) - 1] = '\0'; ret = request_firmware(&fw, ef->data, adap->pdev_dev); -- cgit v1.3-6-gb490 From b3e6b82a0099dfef038e40c630a554ed1e402504 Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Wed, 22 Jul 2015 11:42:32 -0700 Subject: hv_netvsc: Wait for sub-channels to be processed during probe The current code returns from probe without waiting for the proper handling of subchannels that may be requested. If the netvsc driver were to be rapidly loaded/unloaded, we can trigger a panic as the unload will be tearing down state that may not have been fully setup yet. We fix this issue by making sure that we return from the probe call only after ensuring that the sub-channel offers in flight are properly handled. Reviewed-and-tested-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 2 ++ drivers/net/hyperv/rndis_filter.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 26cd14ccf4d5..925b75d4d910 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -671,6 +671,8 @@ struct netvsc_device { u32 send_table[VRSS_SEND_TAB_SIZE]; u32 max_chn; u32 num_chn; + spinlock_t sc_lock; /* Protects num_sc_offered variable */ + u32 num_sc_offered; atomic_t queue_sends[NR_CPUS]; /* Holds rndis device info */ diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 2e40417a8087..9b8263db49cc 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -984,9 +984,16 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) struct netvsc_device *nvscdev; u16 chn_index = new_sc->offermsg.offer.sub_channel_index; int ret; + unsigned long flags; nvscdev = hv_get_drvdata(new_sc->primary_channel->device_obj); + spin_lock_irqsave(&nvscdev->sc_lock, flags); + nvscdev->num_sc_offered--; + spin_unlock_irqrestore(&nvscdev->sc_lock, flags); + if (nvscdev->num_sc_offered == 0) + complete(&nvscdev->channel_init_wait); + if (chn_index >= nvscdev->num_chn) return; @@ -1015,8 +1022,10 @@ int rndis_filter_device_add(struct hv_device *dev, u32 rsscap_size = sizeof(struct ndis_recv_scale_cap); u32 mtu, size; u32 num_rss_qs; + u32 sc_delta; const struct cpumask *node_cpu_mask; u32 num_possible_rss_qs; + unsigned long flags; rndis_device = get_rndis_device(); if (!rndis_device) @@ -1039,6 +1048,8 @@ int rndis_filter_device_add(struct hv_device *dev, net_device->max_chn = 1; net_device->num_chn = 1; + spin_lock_init(&net_device->sc_lock); + net_device->extension = rndis_device; rndis_device->net_dev = net_device; @@ -1116,6 +1127,9 @@ int rndis_filter_device_add(struct hv_device *dev, num_possible_rss_qs = cpumask_weight(node_cpu_mask); net_device->num_chn = min(num_possible_rss_qs, num_rss_qs); + num_rss_qs = net_device->num_chn - 1; + net_device->num_sc_offered = num_rss_qs; + if (net_device->num_chn == 1) goto out; @@ -1157,11 +1171,25 @@ int rndis_filter_device_add(struct hv_device *dev, ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn); + /* + * Wait for the host to send us the sub-channel offers. + */ + spin_lock_irqsave(&net_device->sc_lock, flags); + sc_delta = num_rss_qs - (net_device->num_chn - 1); + net_device->num_sc_offered -= sc_delta; + spin_unlock_irqrestore(&net_device->sc_lock, flags); + + while (net_device->num_sc_offered != 0) { + t = wait_for_completion_timeout(&net_device->channel_init_wait, 10*HZ); + if (t == 0) + WARN(1, "Netvsc: Waiting for sub-channel processing"); + } out: if (ret) { net_device->max_chn = 1; net_device->num_chn = 1; } + return 0; /* return 0 because primary channel can be used alone */ err_dev_remv: -- cgit v1.3-6-gb490 From 7d5d3075b5910cff7b33a68d3b065566fece4ba1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 22 Jul 2015 17:28:23 -0700 Subject: net: bcmgenet: Remove checks on clock handles Instead of multiplying the number of checks for IS_ERR(priv->clk), simply NULLify the 'struct clk' pointer which is something the Linux common clock framework perfectly deals with and does early return for each and every single clk_* API functions. Having every single function check for !IS_ERR(priv->clk) is both redundant and error prone, as it turns out, we were doing it for the main GENET clock: priv->clk, but not for the Wake-on-LAN or EEE clock, so let's just be consistent here. Signed-off-by: Florian Fainelli Acked-by: Petri Gynther Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 5bf7ce0ae221..c6f2d396edf0 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2625,8 +2625,7 @@ static int bcmgenet_open(struct net_device *dev) netif_dbg(priv, ifup, dev, "bcmgenet_open\n"); /* Turn on the clock */ - if (!IS_ERR(priv->clk)) - clk_prepare_enable(priv->clk); + clk_prepare_enable(priv->clk); /* If this is an internal GPHY, power it back on now, before UniMAC is * brought out of reset as absolutely no UniMAC activity is allowed @@ -2703,8 +2702,7 @@ err_irq0: err_fini_dma: bcmgenet_fini_dma(priv); err_clk_disable: - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk); return ret; } @@ -2761,8 +2759,7 @@ static int bcmgenet_close(struct net_device *dev) if (priv->internal_phy) ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE); - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk); return ret; } @@ -3215,11 +3212,12 @@ static int bcmgenet_probe(struct platform_device *pdev) priv->version = pd->genet_version; priv->clk = devm_clk_get(&priv->pdev->dev, "enet"); - if (IS_ERR(priv->clk)) + if (IS_ERR(priv->clk)) { dev_warn(&priv->pdev->dev, "failed to get enet clock\n"); + priv->clk = NULL; + } - if (!IS_ERR(priv->clk)) - clk_prepare_enable(priv->clk); + clk_prepare_enable(priv->clk); bcmgenet_set_hw_params(priv); @@ -3230,8 +3228,10 @@ static int bcmgenet_probe(struct platform_device *pdev) INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task); priv->clk_wol = devm_clk_get(&priv->pdev->dev, "enet-wol"); - if (IS_ERR(priv->clk_wol)) + if (IS_ERR(priv->clk_wol)) { dev_warn(&priv->pdev->dev, "failed to get enet-wol clock\n"); + priv->clk_wol = NULL; + } priv->clk_eee = devm_clk_get(&priv->pdev->dev, "enet-eee"); if (IS_ERR(priv->clk_eee)) { @@ -3257,8 +3257,7 @@ static int bcmgenet_probe(struct platform_device *pdev) netif_carrier_off(dev); /* Turn off the main clock, WOL clock is handled separately */ - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk); err = register_netdev(dev); if (err) @@ -3267,8 +3266,7 @@ static int bcmgenet_probe(struct platform_device *pdev) return err; err_clk_disable: - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk); err: free_netdev(dev); return err; -- cgit v1.3-6-gb490 From 6ac9de5f656352b24ab2cb3e925f078c8c809a19 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 22 Jul 2015 17:29:53 -0700 Subject: net: bcmgenet: Register link_update callback for all MoCA PHYs Commit 8d88c6ebb34c ("net: bcmgenet: enable MoCA link state change detection") added a fixed PHY link_update callback for MoCA PHYs when registered using platform_data exclusively, this change is also applicable to systems using Device Tree as their primary configuration interface. In order for this to work, move the link_update assignment into bcmgenet_moca_phy_setup() where we know for sure that we are running on a MoCA GENET instance, and do not override phydev->link since this is: - properly taken care of by the PHY library by getting the link UP/DOWN interrupts - this now runs everytime we call bcmgenet_open(), so we need to preserve whatever we detected before we went administratively DOWN and then UP - we need to make sure that MoCA PHYs start with a link DOWN during probe in order to force a link transition to occur To avoid a forward declaration, move bcmgenet_fixed_phy_link_update() above its caller. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmmii.c | 37 +++++++++++++++++----------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 0802cd9d2424..b3679ad1c1c7 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -163,6 +163,15 @@ void bcmgenet_mii_setup(struct net_device *dev) phy_print_status(phydev); } +static int bcmgenet_fixed_phy_link_update(struct net_device *dev, + struct fixed_phy_status *status) +{ + if (dev && dev->phydev && status) + status->link = dev->phydev->link; + + return 0; +} + void bcmgenet_phy_power_set(struct net_device *dev, bool enable) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -215,6 +224,10 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL); reg |= LED_ACT_SOURCE_MAC; bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL); + + if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) + fixed_phy_set_link_update(priv->phydev, + bcmgenet_fixed_phy_link_update); } int bcmgenet_mii_config(struct net_device *dev) @@ -460,6 +473,7 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) struct device_node *dn = priv->pdev->dev.of_node; struct device *kdev = &priv->pdev->dev; const char *phy_mode_str = NULL; + struct phy_device *phydev = NULL; char *compat; int phy_mode; int ret; @@ -515,14 +529,12 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) priv->internal_phy = true; } - return 0; -} - -static int bcmgenet_fixed_phy_link_update(struct net_device *dev, - struct fixed_phy_status *status) -{ - if (dev && dev->phydev && status) - status->link = dev->phydev->link; + /* Make sure we initialize MoCA PHYs with a link down */ + if (phy_mode == PHY_INTERFACE_MODE_MOCA) { + phydev = of_phy_find_device(dn); + if (phydev) + phydev->link = 0; + } return 0; } @@ -579,12 +591,9 @@ static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv) return -ENODEV; } - if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) { - ret = fixed_phy_set_link_update( - phydev, bcmgenet_fixed_phy_link_update); - if (!ret) - phydev->link = 0; - } + /* Make sure we initialize MoCA PHYs with a link down */ + phydev->link = 0; + } priv->phydev = phydev; -- cgit v1.3-6-gb490 From 9ece39ab9a91aa37090c8fbfe64c240f27ad9f1a Mon Sep 17 00:00:00 2001 From: Harini Katakam Date: Thu, 23 Jul 2015 15:44:25 +0530 Subject: net: macb: Change capability mask for jumbo support JUMBO and NO_GIGABIT_HALF have the same capability masks. Change one of them. Signed-off-by: Harini Katakam Acked-by: Nicolas Ferre Acked-by: Alexandre Belloni Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index d74655993d4b..8fb80b2dcf82 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -399,7 +399,7 @@ #define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000 #define MACB_CAPS_SG_DISABLED 0x40000000 #define MACB_CAPS_MACB_IS_GEM 0x80000000 -#define MACB_CAPS_JUMBO 0x00000008 +#define MACB_CAPS_JUMBO 0x00000010 /* Bit manipulation macros */ #define MACB_BIT(name) \ -- cgit v1.3-6-gb490 From ea6f82fe37319675e271dd6b55fb37731eef0e46 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 23 Jul 2015 22:41:14 +0530 Subject: cxgb4vf: Read correct FL congestion threshold for T5 and T6 VF driver was reading incorrect freelist congestion notification threshold for FLM queues when packing is enabled for T5 and T6 adapter. Fixing it now. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 5 +++++ drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 375a825573b0..ed8a8f350113 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -338,6 +338,11 @@ #define EGRTHRESHOLDPACKING_G(x) \ (((x) >> EGRTHRESHOLDPACKING_S) & EGRTHRESHOLDPACKING_M) +#define T6_EGRTHRESHOLDPACKING_S 16 +#define T6_EGRTHRESHOLDPACKING_M 0xffU +#define T6_EGRTHRESHOLDPACKING_G(x) \ + (((x) >> T6_EGRTHRESHOLDPACKING_S) & T6_EGRTHRESHOLDPACKING_M) + #define SGE_TIMESTAMP_LO_A 0x1098 #define SGE_TIMESTAMP_HI_A 0x109c diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index 1d5e77a566e1..fa3786a9d30e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -2668,8 +2668,22 @@ int t4vf_sge_init(struct adapter *adapter) * give it more Free List entries. (Note that the SGE's Egress * Congestion Threshold is in units of 2 Free List pointers.) */ - s->fl_starve_thres - = EGRTHRESHOLD_G(sge_params->sge_congestion_control)*2 + 1; + switch (CHELSIO_CHIP_VERSION(adapter->params.chip)) { + case CHELSIO_T4: + s->fl_starve_thres = + EGRTHRESHOLD_G(sge_params->sge_congestion_control); + break; + case CHELSIO_T5: + s->fl_starve_thres = + EGRTHRESHOLDPACKING_G(sge_params->sge_congestion_control); + break; + case CHELSIO_T6: + default: + s->fl_starve_thres = + T6_EGRTHRESHOLDPACKING_G(sge_params->sge_congestion_control); + break; + } + s->fl_starve_thres = s->fl_starve_thres * 2 + 1; /* * Set up tasklet timers. -- cgit v1.3-6-gb490 From aec89ef72ba6c94420f599dcb684ed66937cdacf Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 15 Jul 2015 15:38:28 +0100 Subject: irqchip/gic: Enable SKIP_SET_WAKE and MASK_ON_SUSPEND The GIC controller doesn't provides any facility to configure the wakeup sources. For the same reason, GIC chip implementation can't provide irq_set_wake functionality, but that results in the irqchip core preventing the systems from entering sleep states like "suspend to RAM". The GICv1/v2 controllers support wakeup events. They signal these wakeup events even when CPU interface is disabled which means the wakeup outputs are always enabled with the required logic in always-on domain. An implementation can powerdown the GIC completely, but then the wake-up must be relayed to some control logic within the power controller that acts as wake-up interrupt controller. Setting the IRQCHIP_SKIP_SET_WAKE flags will ensure that the interrupts from GIC can work as wakeup interrupts and resume from suspend-to-{idle, ram}. The wakeup interrupt sources need to use enable_irq_wake() and the irqchip core will then set the IRQD_WAKEUP_STATE flag. Also it's always safer to mask all the non wakeup interrupts are masked at the chip level when suspending. The irqchip infrastructure can handle masking of those interrupts at the chip level. The chip implementation just have to indicate that with IRQCHIP_MASK_ON_SUSPEND. This patch enables IRQCHIP_SKIP_SET_WAKE and IRQCHIP_MASK_ON_SUSPEND so that the irqchip core allows and handles the power managemant wake up modes. Signed-off-by: Sudeep Holla Cc: Marc Zyngier Cc: Simon Horman Cc: Jason Cooper Cc: Michal Simek Cc: Linus Walleij Cc: Magnus Damm Cc: Gregory CLEMENT Cc: Geert Uytterhoeven Cc: Lorenzo Pieralisi Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1436971109-20189-1-git-send-email-sudeep.holla@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic.c | 4 +++- drivers/irqchip/irq-hip04.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index cadd8628fb40..39ff8df8cf64 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -324,7 +324,9 @@ static struct irq_chip gic_chip = { #endif .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, - .flags = IRQCHIP_SET_TYPE_MASKED, + .flags = IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_MASK_ON_SUSPEND, }; void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index 55c2c1074e15..a0128c7c98dd 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -202,7 +202,9 @@ static struct irq_chip hip04_irq_chip = { #ifdef CONFIG_SMP .irq_set_affinity = hip04_irq_set_affinity, #endif - .flags = IRQCHIP_SET_TYPE_MASKED, + .flags = IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_MASK_ON_SUSPEND, }; static u16 hip04_get_cpumask(struct hip04_irq_data *intc) -- cgit v1.3-6-gb490 From 0d3f2c92e004c67404fabea19728c1962b777bd6 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 15 Jul 2015 15:38:29 +0100 Subject: irqchip/gic: Remove redundant gic_set_irqchip_flags Now that the GIC chip implementation enables IRQCHIP_SKIP_SET_WAKE and IRQCHIP_MASK_ON_SUSPEND by default, the platforms requiring them need not override the irqchip flags as before. This patch removes all the users of gic_set_irqchip_flags and the function itself. Signed-off-by: Sudeep Holla Acked-by: Linus Walleij Cc: Marc Zyngier Cc: Simon Horman Cc: Jason Cooper Cc: Michal Simek Cc: Magnus Damm Cc: Gregory CLEMENT Cc: Geert Uytterhoeven Cc: Lorenzo Pieralisi Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1436971109-20189-2-git-send-email-sudeep.holla@arm.com Signed-off-by: Thomas Gleixner --- arch/arm/mach-shmobile/intc-sh73a0.c | 1 - arch/arm/mach-shmobile/setup-r8a7779.c | 1 - arch/arm/mach-ux500/cpu.c | 1 - arch/arm/mach-zynq/common.c | 1 - drivers/irqchip/irq-gic.c | 5 ----- include/linux/irqchip/arm-gic.h | 1 - 6 files changed, 10 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index fd63ae6532fc..151a71a41fe3 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -313,7 +313,6 @@ void __init sh73a0_init_irq(void) void __iomem *gic_cpu_base = IOMEM(0xf0000100); void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE); - gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE); gic_init(0, 29, gic_dist_base, gic_cpu_base); register_intc_controller(&intcs_desc); diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index c03e562be12b..aea5cff9495d 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -719,7 +719,6 @@ void __init r8a7779_init_irq_dt(void) void __iomem *gic_dist_base = ioremap_nocache(0xf0001000, 0x1000); void __iomem *gic_cpu_base = ioremap_nocache(0xf0000100, 0x1000); #endif - gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE); #ifdef CONFIG_ARCH_SHMOBILE_LEGACY gic_init(0, 29, gic_dist_base, gic_cpu_base); diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index e31d3d61c998..6cb10c77afd8 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -56,7 +56,6 @@ void __init ux500_init_irq(void) struct device_node *np; struct resource r; - gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND); irqchip_init(); np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu"); of_address_to_resource(np, 0, &r); diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 616d5840fc2e..2ad1accfba35 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -186,7 +186,6 @@ static void __init zynq_map_io(void) static void __init zynq_irq_init(void) { - gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND); irqchip_init(); } diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 39ff8df8cf64..80fde37076c4 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -881,11 +881,6 @@ static const struct irq_domain_ops gic_irq_domain_ops = { .xlate = gic_irq_domain_xlate, }; -void gic_set_irqchip_flags(unsigned long flags) -{ - gic_chip.flags |= flags; -} - 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) diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 9de976b4f9a7..61a2007eb49a 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -95,7 +95,6 @@ struct device_node; -void gic_set_irqchip_flags(unsigned long flags); void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, u32 offset, struct device_node *); void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); -- cgit v1.3-6-gb490 From c376023b7096e76ac4d5526105cf9be8743bead9 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 24 Jul 2015 15:24:45 -0400 Subject: irqchip: Appropriate __init annotation for const data Init data marked const should be annotated with __initconst for correctness and not __initdata. And for those already __initconst, they should be qualified as const at the compiler level too. This also fixes LTO builds that otherwise fail with section mismatch errors. Signed-off-by: Nicolas Pitre Cc: Jason Cooper Link: http://lkml.kernel.org/r/alpine.LFD.2.20.1507241511551.1806@knanqh.ubzr Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-atmel-aic.c | 2 +- drivers/irqchip/irq-atmel-aic5.c | 2 +- drivers/irqchip/irq-bcm2835.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c index dbbf30aee278..8a0c7f288198 100644 --- a/drivers/irqchip/irq-atmel-aic.c +++ b/drivers/irqchip/irq-atmel-aic.c @@ -225,7 +225,7 @@ static void __init at91sam9g45_aic_irq_fixup(struct device_node *root) aic_common_rtt_irq_fixup(root); } -static const struct of_device_id __initdata aic_irq_fixups[] = { +static const struct of_device_id aic_irq_fixups[] __initconst = { { .compatible = "atmel,at91rm9200", .data = at91rm9200_aic_irq_fixup }, { .compatible = "atmel,at91sam9g45", .data = at91sam9g45_aic_irq_fixup }, { .compatible = "atmel,at91sam9n12", .data = at91rm9200_aic_irq_fixup }, diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index ff2e832af10d..9da9942ac83c 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -290,7 +290,7 @@ static void __init sama5d3_aic_irq_fixup(struct device_node *root) aic_common_rtc_irq_fixup(root); } -static const struct of_device_id __initdata aic5_irq_fixups[] = { +static const struct of_device_id aic5_irq_fixups[] __initconst = { { .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup }, { .compatible = "atmel,sama5d4", .data = sama5d3_aic_irq_fixup }, { /* sentinel */ }, diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index a36ba96e1448..ca35171e8afc 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -75,10 +75,10 @@ #define NR_BANKS 3 #define IRQS_PER_BANK 32 -static int reg_pending[] __initconst = { 0x00, 0x04, 0x08 }; -static int reg_enable[] __initconst = { 0x18, 0x10, 0x14 }; -static int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 }; -static int bank_irqs[] __initconst = { 8, 32, 32 }; +static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 }; +static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 }; +static const int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 }; +static const int bank_irqs[] __initconst = { 8, 32, 32 }; static const int shortcuts[] = { 7, 9, 10, 18, 19, /* Bank 1 */ -- cgit v1.3-6-gb490 From fd537766715e9b6bf7ff07abb22f4817201433db Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 22 Jul 2015 16:21:40 -0700 Subject: irqchip/bcm7120-l2: Perform suspend/resume even without installed child IRQs Make use of the new irq_chip_generic suspend/resume callbacks. This is required because if there are no installed child IRQs for this chip, the irq_chip::irq_{suspend,resume} functions will not be called. However, we still need to save/restore the forwarding mask, to enable the top-level GIC interrupt; otherwise, we lose UART output after S3 resume. In addition to refactoring the callbacks, we have to self-initialize the mask cache, since the genirq core also doesn't initialize this until the first child IRQ is installed. The original problem report is described in extra detail here: http://lkml.kernel.org/g/20150619224123.GL4917@ld-irv-0074 Signed-off-by: Brian Norris Tested-by: Florian Fainelli Cc: Gregory Fong Cc: bcm-kernel-feedback-list@broadcom.com Cc: linux-mips@linux-mips.org Cc: Kevin Cernekee Cc: Jason Cooper Link: http://lkml.kernel.org/r/1437607300-40858-2-git-send-email-computersforpeace@gmail.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-bcm7120-l2.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 88c9719e5d33..c885a5c4632a 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -80,11 +80,10 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } -static void bcm7120_l2_intc_suspend(struct irq_data *d) +static void bcm7120_l2_intc_suspend(struct irq_chip_generic *gc) { - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct irq_chip_type *ct = irq_data_get_chip_type(d); struct bcm7120_l2_intc_data *b = gc->private; + struct irq_chip_type *ct = gc->chip_types; irq_gc_lock(gc); if (b->can_wake) @@ -93,10 +92,9 @@ static void bcm7120_l2_intc_suspend(struct irq_data *d) irq_gc_unlock(gc); } -static void bcm7120_l2_intc_resume(struct irq_data *d) +static void bcm7120_l2_intc_resume(struct irq_chip_generic *gc) { - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct irq_chip_type *ct = irq_data_get_chip_type(d); + struct irq_chip_type *ct = gc->chip_types; /* Restore the saved mask */ irq_gc_lock(gc); @@ -279,8 +277,15 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_unmask = irq_gc_mask_set_bit; ct->chip.irq_ack = irq_gc_noop; - ct->chip.irq_suspend = bcm7120_l2_intc_suspend; - ct->chip.irq_resume = bcm7120_l2_intc_resume; + gc->suspend = bcm7120_l2_intc_suspend; + gc->resume = bcm7120_l2_intc_resume; + + /* + * Initialize mask-cache, in case we need it for + * saving/restoring fwd mask even w/o any child interrupts + * installed + */ + gc->mask_cache = irq_reg_readl(gc, ct->regs.mask); if (data->can_wake) { /* This IRQ chip can wake the system, set all -- cgit v1.3-6-gb490 From 0aef3997e12a10d4dfb6e01133e2fe478b9aa5eb Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 23 Jul 2015 15:52:21 -0700 Subject: irqchip/bcm7120-l2: Fix interrupt status for multiple parent IRQs Our irq-bcm7120-l2 interrupt controller driver utilizes the same handler function for the different parent interrupts it services: UPG_MAIN, UPG_BSC for instance. The problem is that function reads the IRQSTAT register which can combine interrupt causes for different parent interrupts, such that we can end-up in the following situation: - CPU takes an interrupt - bcm7120_l2_intc_irq_handle() reads IRQSTAT - generic_handle_irq() is invoked - there are still pending interrupts flagged in IRQSTAT from a different parent - handle_bad_irq() is invoked for these since they come from a different irq_desc/irq In order to fix this, make sure that we always mask IRQSTAT with the appropriate bits that correspond go the parent interrupt source this is coming from. To simplify things, associate an unique structure per parent interrupt handler to avoid multiplying the number of lookups. Fixes: a5042de2688d ("irqchip: bcm7120-l2: Add Broadcom BCM7120-style Level 2 interrupt controller") Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: cernekee@gmail.com Cc: jason@lakedaemon.net Cc: bcm-kernel-feedback-list@broadcom.com Cc: gregory.0xf0@gmail.com Cc: computersforpeace@gmail.com Link: http://lkml.kernel.org/r/1437691941-3100-1-git-send-email-f.fainelli@gmail.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-bcm7120-l2.c | 52 ++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index c885a5c4632a..d3f976913a6f 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -37,6 +37,11 @@ #define MAX_MAPPINGS (MAX_WORDS * 2) #define IRQS_PER_WORD 32 +struct bcm7120_l1_intc_data { + struct bcm7120_l2_intc_data *b; + u32 irq_map_mask[MAX_WORDS]; +}; + struct bcm7120_l2_intc_data { unsigned int n_words; void __iomem *map_base[MAX_MAPPINGS]; @@ -46,14 +51,15 @@ struct bcm7120_l2_intc_data { struct irq_domain *domain; bool can_wake; u32 irq_fwd_mask[MAX_WORDS]; - u32 irq_map_mask[MAX_WORDS]; + struct bcm7120_l1_intc_data *l1_data; int num_parent_irqs; const __be32 *map_mask_prop; }; static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) { - struct bcm7120_l2_intc_data *b = irq_desc_get_handler_data(desc); + struct bcm7120_l1_intc_data *data = irq_desc_get_handler_data(desc); + struct bcm7120_l2_intc_data *b = data->b; struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int idx; @@ -68,7 +74,8 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) irq_gc_lock(gc); pending = irq_reg_readl(gc, b->stat_offset[idx]) & - gc->mask_cache; + gc->mask_cache & + data->irq_map_mask[idx]; irq_gc_unlock(gc); for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) { @@ -104,8 +111,9 @@ static void bcm7120_l2_intc_resume(struct irq_chip_generic *gc) static int bcm7120_l2_intc_init_one(struct device_node *dn, struct bcm7120_l2_intc_data *data, - int irq) + int irq, u32 *valid_mask) { + struct bcm7120_l1_intc_data *l1_data = &data->l1_data[irq]; int parent_irq; unsigned int idx; @@ -117,20 +125,28 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, /* For multiple parent IRQs with multiple words, this looks like: * + * + * We need to associate a given parent interrupt with its corresponding + * map_mask in order to mask the status register with it because we + * have the same handler being called for multiple parent interrupts. + * + * This is typically something needed on BCM7xxx (STB chips). */ for (idx = 0; idx < data->n_words; idx++) { if (data->map_mask_prop) { - data->irq_map_mask[idx] |= + l1_data->irq_map_mask[idx] |= be32_to_cpup(data->map_mask_prop + irq * data->n_words + idx); } else { - data->irq_map_mask[idx] = 0xffffffff; + l1_data->irq_map_mask[idx] = 0xffffffff; } + valid_mask[idx] |= l1_data->irq_map_mask[idx]; } - irq_set_chained_handler_and_data(parent_irq, - bcm7120_l2_intc_irq_handle, data); + l1_data->b = data; + irq_set_chained_handler_and_data(parent_irq, + bcm7120_l2_intc_irq_handle, l1_data); return 0; } @@ -211,6 +227,7 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, struct irq_chip_type *ct; int ret = 0; unsigned int idx, irq, flags; + u32 valid_mask[MAX_WORDS] = { }; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) @@ -223,9 +240,16 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, goto out_unmap; } + data->l1_data = kcalloc(data->num_parent_irqs, sizeof(*data->l1_data), + GFP_KERNEL); + if (!data->l1_data) { + ret = -ENOMEM; + goto out_free_l1_data; + } + ret = iomap_regs_fn(dn, data); if (ret < 0) - goto out_unmap; + goto out_free_l1_data; for (idx = 0; idx < data->n_words; idx++) { __raw_writel(data->irq_fwd_mask[idx], @@ -234,16 +258,16 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, } for (irq = 0; irq < data->num_parent_irqs; irq++) { - ret = bcm7120_l2_intc_init_one(dn, data, irq); + ret = bcm7120_l2_intc_init_one(dn, data, irq, valid_mask); if (ret) - goto out_unmap; + goto out_free_l1_data; } data->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * data->n_words, &irq_generic_chip_ops, NULL); if (!data->domain) { ret = -ENOMEM; - goto out_unmap; + goto out_free_l1_data; } /* MIPS chips strapped for BE will automagically configure the @@ -267,7 +291,7 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, irq = idx * IRQS_PER_WORD; gc = irq_get_domain_generic_chip(data->domain, irq); - gc->unused = 0xffffffff & ~data->irq_map_mask[idx]; + gc->unused = 0xffffffff & ~valid_mask[idx]; gc->private = data; ct = gc->chip_types; @@ -304,6 +328,8 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, out_free_domain: irq_domain_remove(data->domain); +out_free_l1_data: + kfree(data->l1_data); out_unmap: for (idx = 0; idx < MAX_MAPPINGS; idx++) { if (data->map_base[idx]) -- cgit v1.3-6-gb490 From c0f54edbe26fbe8194d7e72c24c49f7b1c9c547f Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:19 -0400 Subject: net: netcp: Fixes the use of spin_lock_bh in timer function This patch fixes a bug in which the timer routine synchronized against the ethtool-triggered statistics updates with spin_lock_bh(). A timer function is itself a bottom-half, so this should be spin_lock(). Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 9b7e0a34c98b..cabf97728b2d 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -2189,14 +2189,15 @@ static void netcp_ethss_timer(unsigned long arg) netcp_ethss_update_link_state(gbe_dev, slave, NULL); } - spin_lock_bh(&gbe_dev->hw_stats_lock); + /* A timer runs as a BH, no need to block them */ + spin_lock(&gbe_dev->hw_stats_lock); if (gbe_dev->ss_version == GBE_SS_VERSION_14) gbe_update_stats_ver14(gbe_dev, NULL); else gbe_update_stats(gbe_dev, NULL); - spin_unlock_bh(&gbe_dev->hw_stats_lock); + spin_unlock(&gbe_dev->hw_stats_lock); gbe_dev->timer.expires = jiffies + GBE_TIMER_INTERVAL; add_timer(&gbe_dev->timer); -- cgit v1.3-6-gb490 From a94bcd09c554e8df3a32ef3f25ecfd74e73b9651 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:20 -0400 Subject: net: netcp: Fixes hw statistics module base setting error This patch fixes error in the setting of the hw statistics module base for K2HK platform. In K2HK although there are 4 hw statistics modules, but only 2 are visible at a time. Thus when setting up the pointers to the base of the corresponding hw statistics modules, modules 0 and 2 should point to one base, while modules 1 and 3 should point to the other. Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index cabf97728b2d..b954856f1198 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -2675,10 +2675,14 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + GBE13_SGMII_MODULE_OFFSET; gbe_dev->host_port_regs = gbe_dev->switch_regs + GBE13_HOST_PORT_OFFSET; + /* K2HK has only 2 hw stats modules visible at a time, so + * module 0 & 2 points to one base and + * module 1 & 3 points to the other base + */ for (i = 0; i < gbe_dev->max_num_slaves; i++) { gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs + GBE13_HW_STATS_OFFSET + - (GBE_HW_STATS_REG_MAP_SZ * i); + (GBE_HW_STATS_REG_MAP_SZ * (i & 0x1)); } gbe_dev->ale_reg = gbe_dev->switch_regs + GBE13_ALE_OFFSET; -- cgit v1.3-6-gb490 From 208c6b9a49df8b69ab698d9f53d40d25f143dbde Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:21 -0400 Subject: net: netcp: Fixes error in oversized memory allocation for statistics storage The CPSW driver keeps internally some, but not all, of the statistics available in the hw statistics modules. Furthermore, some of the locations in the hw statistics modules are reserved and contain no useful information. Prior to this patch, the driver allocates memory of the size of the the whole hw statistics modules, instead of the size of statistics-entries-interested-in (i.e. et_stats), for internal storage. This patch fixes that. Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 46 ++++++++++++++++------------------- 1 file changed, 21 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index b954856f1198..3976516b9a5f 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -295,8 +295,6 @@ struct xgbe_hw_stats { u32 rx_dma_overruns; }; -#define XGBE10_NUM_STAT_ENTRIES (sizeof(struct xgbe_hw_stats)/sizeof(u32)) - struct gbenu_ss_regs { u32 id_ver; u32 synce_count; /* NU */ @@ -480,7 +478,6 @@ struct gbenu_hw_stats { u32 tx_pri7_drop_bcnt; }; -#define GBENU_NUM_HW_STAT_ENTRIES (sizeof(struct gbenu_hw_stats) / sizeof(u32)) #define GBENU_HW_STATS_REG_MAP_SZ 0x200 struct gbe_ss_regs { @@ -615,7 +612,6 @@ struct gbe_hw_stats { u32 rx_dma_overruns; }; -#define GBE13_NUM_HW_STAT_ENTRIES (sizeof(struct gbe_hw_stats)/sizeof(u32)) #define GBE_MAX_HW_STAT_MODS 9 #define GBE_HW_STATS_REG_MAP_SZ 0x100 @@ -2555,10 +2551,12 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, } gbe_dev->xgbe_serdes_regs = regs; + gbe_dev->et_stats = xgbe10_et_stats; + gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats); + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, - XGBE10_NUM_STAT_ENTRIES * - (gbe_dev->max_num_ports) * sizeof(u64), - GFP_KERNEL); + gbe_dev->num_et_stats * sizeof(u64), + GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); return -ENOMEM; @@ -2577,8 +2575,6 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->host_port = XGBE10_HOST_PORT_NUM; gbe_dev->ale_entries = XGBE10_NUM_ALE_ENTRIES; - gbe_dev->et_stats = xgbe10_et_stats; - gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats); gbe_dev->stats_en_mask = (1 << (gbe_dev->max_num_ports)) - 1; /* Subsystem registers */ @@ -2663,10 +2659,12 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, } gbe_dev->switch_regs = regs; + gbe_dev->et_stats = gbe13_et_stats; + gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats); + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, - GBE13_NUM_HW_STAT_ENTRIES * - gbe_dev->max_num_slaves * sizeof(u64), - GFP_KERNEL); + gbe_dev->num_et_stats * sizeof(u64), + GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); return -ENOMEM; @@ -2689,8 +2687,6 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->host_port = GBE13_HOST_PORT_NUM; gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; - gbe_dev->et_stats = gbe13_et_stats; - gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats); gbe_dev->stats_en_mask = GBE13_REG_VAL_STAT_ENABLE_ALL; /* Subsystem registers */ @@ -2717,10 +2713,18 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, void __iomem *regs; int i, ret; + gbe_dev->et_stats = gbenu_et_stats; + + if (IS_SS_ID_NU(gbe_dev)) + gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + + (gbe_dev->max_num_slaves * GBENU_ET_STATS_PORT_SIZE); + else + gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + + GBENU_ET_STATS_PORT_SIZE; + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, - GBENU_NUM_HW_STAT_ENTRIES * - (gbe_dev->max_num_ports) * sizeof(u64), - GFP_KERNEL); + gbe_dev->num_et_stats * sizeof(u64), + GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); return -ENOMEM; @@ -2753,16 +2757,8 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->host_port = GBENU_HOST_PORT_NUM; gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; - gbe_dev->et_stats = gbenu_et_stats; gbe_dev->stats_en_mask = (1 << (gbe_dev->max_num_ports)) - 1; - if (IS_SS_ID_NU(gbe_dev)) - gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + - (gbe_dev->max_num_slaves * GBENU_ET_STATS_PORT_SIZE); - else - gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + - GBENU_ET_STATS_PORT_SIZE; - /* Subsystem registers */ GBENU_SET_REG_OFS(gbe_dev, ss_regs, id_ver); -- cgit v1.3-6-gb490 From fbf64c1915b964c05edd4434250fbbb31ded38c6 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:22 -0400 Subject: net: netcp: Consolidates statistics collection code Different Keystone2 platforms have different number and layouts of hw statistics modules. This patch consolidates the statistics processing of different Keystone2 platforms for easy maintenance. Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 99 +++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 3976516b9a5f..b06f210c8ada 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -1550,70 +1550,79 @@ static int keystone_get_sset_count(struct net_device *ndev, int stringset) } } -static void gbe_update_stats(struct gbe_priv *gbe_dev, uint64_t *data) +static inline void gbe_update_hw_stats_entry(struct gbe_priv *gbe_dev, + int et_stats_entry) { void __iomem *base = NULL; u32 __iomem *p; u32 tmp = 0; + + /* The hw_stats_regs pointers are already + * properly set to point to the right base: + */ + base = gbe_dev->hw_stats_regs[gbe_dev->et_stats[et_stats_entry].type]; + p = base + gbe_dev->et_stats[et_stats_entry].offset; + tmp = readl(p); + gbe_dev->hw_stats[et_stats_entry] += tmp; + + /* write-to-decrement: + * new register value = old register value - write value + */ + writel(tmp, p); +} + +static void gbe_update_stats(struct gbe_priv *gbe_dev, uint64_t *data) +{ int i; for (i = 0; i < gbe_dev->num_et_stats; i++) { - base = gbe_dev->hw_stats_regs[gbe_dev->et_stats[i].type]; - p = base + gbe_dev->et_stats[i].offset; - tmp = readl(p); - gbe_dev->hw_stats[i] = gbe_dev->hw_stats[i] + tmp; + gbe_update_hw_stats_entry(gbe_dev, i); + if (data) data[i] = gbe_dev->hw_stats[i]; - /* write-to-decrement: - * new register value = old register value - write value - */ - writel(tmp, p); } } -static void gbe_update_stats_ver14(struct gbe_priv *gbe_dev, uint64_t *data) +static inline void gbe_stats_mod_visible_ver14(struct gbe_priv *gbe_dev, + int stats_mod) { - void __iomem *gbe_statsa = gbe_dev->hw_stats_regs[0]; - void __iomem *gbe_statsb = gbe_dev->hw_stats_regs[1]; - u64 *hw_stats = &gbe_dev->hw_stats[0]; - void __iomem *base = NULL; - u32 __iomem *p; - u32 tmp = 0, val, pair_size = (gbe_dev->num_et_stats / 2); - int i, j, pair; + u32 val; - for (pair = 0; pair < 2; pair++) { - val = readl(GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); + val = readl(GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); - if (pair == 0) - val &= ~GBE_STATS_CD_SEL; - else - val |= GBE_STATS_CD_SEL; + switch (stats_mod) { + case GBE_STATSA_MODULE: + case GBE_STATSB_MODULE: + val &= ~GBE_STATS_CD_SEL; + break; + case GBE_STATSC_MODULE: + case GBE_STATSD_MODULE: + val |= GBE_STATS_CD_SEL; + break; + default: + return; + } + + /* make the stat module visible */ + writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); +} - /* make the stat modules visible */ - writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); +static void gbe_update_stats_ver14(struct gbe_priv *gbe_dev, uint64_t *data) +{ + u32 half_num_et_stats = (gbe_dev->num_et_stats / 2); + int et_entry, j, pair; - for (i = 0; i < pair_size; i++) { - j = pair * pair_size + i; - switch (gbe_dev->et_stats[j].type) { - case GBE_STATSA_MODULE: - case GBE_STATSC_MODULE: - base = gbe_statsa; - break; - case GBE_STATSB_MODULE: - case GBE_STATSD_MODULE: - base = gbe_statsb; - break; - } + for (pair = 0; pair < 2; pair++) { + gbe_stats_mod_visible_ver14(gbe_dev, (pair ? + GBE_STATSC_MODULE : + GBE_STATSA_MODULE)); + + for (j = 0; j < half_num_et_stats; j++) { + et_entry = pair * half_num_et_stats + j; + gbe_update_hw_stats_entry(gbe_dev, et_entry); - p = base + gbe_dev->et_stats[j].offset; - tmp = readl(p); - hw_stats[j] += tmp; if (data) - data[j] = hw_stats[j]; - /* write-to-decrement: - * new register value = old register value - write value - */ - writel(tmp, p); + data[et_entry] = gbe_dev->hw_stats[et_entry]; } } } -- cgit v1.3-6-gb490 From 489e8a2f09d772afc98a85ca477bb6bc52400c26 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:23 -0400 Subject: net: netcp: Fixes to CPSW statistics collection In certain applications it's beneficial to allow the CPSW h/w stats counters to continue to increment even while the kernel polls them. This patch implements this behavior for both 1G and 10G ethernet subsystem modules. Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 86 ++++++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index b06f210c8ada..aa330669aa08 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -642,6 +642,7 @@ struct gbe_priv { bool enable_ale; u8 max_num_slaves; u8 max_num_ports; /* max_num_slaves + 1 */ + u8 num_stats_mods; struct netcp_tx_pipe tx_pipe; int host_port; @@ -671,6 +672,7 @@ struct gbe_priv { struct net_device *dummy_ndev; u64 *hw_stats; + u32 *hw_stats_prev; const struct netcp_ethtool_stat *et_stats; int num_et_stats; /* Lock for updating the hwstats */ @@ -1550,25 +1552,37 @@ static int keystone_get_sset_count(struct net_device *ndev, int stringset) } } +static void gbe_reset_mod_stats(struct gbe_priv *gbe_dev, int stats_mod) +{ + void __iomem *base = gbe_dev->hw_stats_regs[stats_mod]; + u32 __iomem *p_stats_entry; + int i; + + for (i = 0; i < gbe_dev->num_et_stats; i++) { + if (gbe_dev->et_stats[i].type == stats_mod) { + p_stats_entry = base + gbe_dev->et_stats[i].offset; + gbe_dev->hw_stats[i] = 0; + gbe_dev->hw_stats_prev[i] = readl(p_stats_entry); + } + } +} + static inline void gbe_update_hw_stats_entry(struct gbe_priv *gbe_dev, int et_stats_entry) { void __iomem *base = NULL; - u32 __iomem *p; - u32 tmp = 0; + u32 __iomem *p_stats_entry; + u32 curr, delta; /* The hw_stats_regs pointers are already * properly set to point to the right base: */ base = gbe_dev->hw_stats_regs[gbe_dev->et_stats[et_stats_entry].type]; - p = base + gbe_dev->et_stats[et_stats_entry].offset; - tmp = readl(p); - gbe_dev->hw_stats[et_stats_entry] += tmp; - - /* write-to-decrement: - * new register value = old register value - write value - */ - writel(tmp, p); + p_stats_entry = base + gbe_dev->et_stats[et_stats_entry].offset; + curr = readl(p_stats_entry); + delta = curr - gbe_dev->hw_stats_prev[et_stats_entry]; + gbe_dev->hw_stats_prev[et_stats_entry] = curr; + gbe_dev->hw_stats[et_stats_entry] += delta; } static void gbe_update_stats(struct gbe_priv *gbe_dev, uint64_t *data) @@ -1607,6 +1621,12 @@ static inline void gbe_stats_mod_visible_ver14(struct gbe_priv *gbe_dev, writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); } +static void gbe_reset_mod_stats_ver14(struct gbe_priv *gbe_dev, int stats_mod) +{ + gbe_stats_mod_visible_ver14(gbe_dev, stats_mod); + gbe_reset_mod_stats(gbe_dev, stats_mod); +} + static void gbe_update_stats_ver14(struct gbe_priv *gbe_dev, uint64_t *data) { u32 half_num_et_stats = (gbe_dev->num_et_stats / 2); @@ -2560,6 +2580,7 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, } gbe_dev->xgbe_serdes_regs = regs; + gbe_dev->num_stats_mods = gbe_dev->max_num_ports; gbe_dev->et_stats = xgbe10_et_stats; gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats); @@ -2571,6 +2592,16 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, return -ENOMEM; } + gbe_dev->hw_stats_prev = + devm_kzalloc(gbe_dev->dev, + gbe_dev->num_et_stats * sizeof(u32), + GFP_KERNEL); + if (!gbe_dev->hw_stats_prev) { + dev_err(gbe_dev->dev, + "hw_stats_prev memory allocation failed\n"); + return -ENOMEM; + } + gbe_dev->ss_version = XGBE_SS_VERSION_10; gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + XGBE10_SGMII_MODULE_OFFSET; @@ -2668,6 +2699,7 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, } gbe_dev->switch_regs = regs; + gbe_dev->num_stats_mods = gbe_dev->max_num_slaves; gbe_dev->et_stats = gbe13_et_stats; gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats); @@ -2679,6 +2711,16 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, return -ENOMEM; } + gbe_dev->hw_stats_prev = + devm_kzalloc(gbe_dev->dev, + gbe_dev->num_et_stats * sizeof(u32), + GFP_KERNEL); + if (!gbe_dev->hw_stats_prev) { + dev_err(gbe_dev->dev, + "hw_stats_prev memory allocation failed\n"); + return -ENOMEM; + } + gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + GBE13_SGMII_MODULE_OFFSET; gbe_dev->host_port_regs = gbe_dev->switch_regs + GBE13_HOST_PORT_OFFSET; @@ -2722,6 +2764,7 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, void __iomem *regs; int i, ret; + gbe_dev->num_stats_mods = gbe_dev->max_num_ports; gbe_dev->et_stats = gbenu_et_stats; if (IS_SS_ID_NU(gbe_dev)) @@ -2739,6 +2782,16 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, return -ENOMEM; } + gbe_dev->hw_stats_prev = + devm_kzalloc(gbe_dev->dev, + gbe_dev->num_et_stats * sizeof(u32), + GFP_KERNEL); + if (!gbe_dev->hw_stats_prev) { + dev_err(gbe_dev->dev, + "hw_stats_prev memory allocation failed\n"); + return -ENOMEM; + } + ret = of_address_to_resource(node, GBENU_SM_REG_INDEX, &res); if (ret) { dev_err(gbe_dev->dev, @@ -2797,7 +2850,7 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, struct cpsw_ale_params ale_params; struct gbe_priv *gbe_dev; u32 slave_num; - int ret = 0; + int i, ret = 0; if (!node) { dev_err(dev, "device tree info unavailable\n"); @@ -2945,6 +2998,15 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, /* initialize host port */ gbe_init_host_port(gbe_dev); + spin_lock_bh(&gbe_dev->hw_stats_lock); + for (i = 0; i < gbe_dev->num_stats_mods; i++) { + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + gbe_reset_mod_stats_ver14(gbe_dev, i); + else + gbe_reset_mod_stats(gbe_dev, i); + } + spin_unlock_bh(&gbe_dev->hw_stats_lock); + init_timer(&gbe_dev->timer); gbe_dev->timer.data = (unsigned long)gbe_dev; gbe_dev->timer.function = netcp_ethss_timer; @@ -2956,6 +3018,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, quit: if (gbe_dev->hw_stats) devm_kfree(dev, gbe_dev->hw_stats); + if (gbe_dev->hw_stats_prev) + devm_kfree(dev, gbe_dev->hw_stats_prev); cpsw_ale_destroy(gbe_dev->ale); if (gbe_dev->ss_regs) devm_iounmap(dev, gbe_dev->ss_regs); -- cgit v1.3-6-gb490 From 5be4001eccb954da7f8ae68248167d3dbb6e7177 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:24 -0400 Subject: net: netcp: Adds missing statistics for K2L and K2E This patch adds the missing statistics for the host and slave ports of the CPSW on K2L and K2E platforms. Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 177 +++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index aa330669aa08..01a955cf5603 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -872,7 +872,7 @@ static const struct netcp_ethtool_stat gbe13_et_stats[] = { }; /* This is the size of entries in GBENU_STATS_HOST */ -#define GBENU_ET_STATS_HOST_SIZE 33 +#define GBENU_ET_STATS_HOST_SIZE 52 #define GBENU_STATS_HOST(field) \ { \ @@ -881,8 +881,8 @@ static const struct netcp_ethtool_stat gbe13_et_stats[] = { offsetof(struct gbenu_hw_stats, field) \ } -/* This is the size of entries in GBENU_STATS_HOST */ -#define GBENU_ET_STATS_PORT_SIZE 46 +/* This is the size of entries in GBENU_STATS_PORT */ +#define GBENU_ET_STATS_PORT_SIZE 65 #define GBENU_STATS_P1(field) \ { \ @@ -974,7 +974,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_HOST(ale_unknown_mcast_bytes), GBENU_STATS_HOST(ale_unknown_bcast), GBENU_STATS_HOST(ale_unknown_bcast_bytes), + GBENU_STATS_HOST(ale_pol_match), + GBENU_STATS_HOST(ale_pol_match_red), + GBENU_STATS_HOST(ale_pol_match_yellow), GBENU_STATS_HOST(tx_mem_protect_err), + GBENU_STATS_HOST(tx_pri0_drop), + GBENU_STATS_HOST(tx_pri1_drop), + GBENU_STATS_HOST(tx_pri2_drop), + GBENU_STATS_HOST(tx_pri3_drop), + GBENU_STATS_HOST(tx_pri4_drop), + GBENU_STATS_HOST(tx_pri5_drop), + GBENU_STATS_HOST(tx_pri6_drop), + GBENU_STATS_HOST(tx_pri7_drop), + GBENU_STATS_HOST(tx_pri0_drop_bcnt), + GBENU_STATS_HOST(tx_pri1_drop_bcnt), + GBENU_STATS_HOST(tx_pri2_drop_bcnt), + GBENU_STATS_HOST(tx_pri3_drop_bcnt), + GBENU_STATS_HOST(tx_pri4_drop_bcnt), + GBENU_STATS_HOST(tx_pri5_drop_bcnt), + GBENU_STATS_HOST(tx_pri6_drop_bcnt), + GBENU_STATS_HOST(tx_pri7_drop_bcnt), /* GBENU Module 1 */ GBENU_STATS_P1(rx_good_frames), GBENU_STATS_P1(rx_broadcast_frames), @@ -1021,7 +1040,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P1(ale_unknown_mcast_bytes), GBENU_STATS_P1(ale_unknown_bcast), GBENU_STATS_P1(ale_unknown_bcast_bytes), + GBENU_STATS_P1(ale_pol_match), + GBENU_STATS_P1(ale_pol_match_red), + GBENU_STATS_P1(ale_pol_match_yellow), GBENU_STATS_P1(tx_mem_protect_err), + GBENU_STATS_P1(tx_pri0_drop), + GBENU_STATS_P1(tx_pri1_drop), + GBENU_STATS_P1(tx_pri2_drop), + GBENU_STATS_P1(tx_pri3_drop), + GBENU_STATS_P1(tx_pri4_drop), + GBENU_STATS_P1(tx_pri5_drop), + GBENU_STATS_P1(tx_pri6_drop), + GBENU_STATS_P1(tx_pri7_drop), + GBENU_STATS_P1(tx_pri0_drop_bcnt), + GBENU_STATS_P1(tx_pri1_drop_bcnt), + GBENU_STATS_P1(tx_pri2_drop_bcnt), + GBENU_STATS_P1(tx_pri3_drop_bcnt), + GBENU_STATS_P1(tx_pri4_drop_bcnt), + GBENU_STATS_P1(tx_pri5_drop_bcnt), + GBENU_STATS_P1(tx_pri6_drop_bcnt), + GBENU_STATS_P1(tx_pri7_drop_bcnt), /* GBENU Module 2 */ GBENU_STATS_P2(rx_good_frames), GBENU_STATS_P2(rx_broadcast_frames), @@ -1068,7 +1106,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P2(ale_unknown_mcast_bytes), GBENU_STATS_P2(ale_unknown_bcast), GBENU_STATS_P2(ale_unknown_bcast_bytes), + GBENU_STATS_P2(ale_pol_match), + GBENU_STATS_P2(ale_pol_match_red), + GBENU_STATS_P2(ale_pol_match_yellow), GBENU_STATS_P2(tx_mem_protect_err), + GBENU_STATS_P2(tx_pri0_drop), + GBENU_STATS_P2(tx_pri1_drop), + GBENU_STATS_P2(tx_pri2_drop), + GBENU_STATS_P2(tx_pri3_drop), + GBENU_STATS_P2(tx_pri4_drop), + GBENU_STATS_P2(tx_pri5_drop), + GBENU_STATS_P2(tx_pri6_drop), + GBENU_STATS_P2(tx_pri7_drop), + GBENU_STATS_P2(tx_pri0_drop_bcnt), + GBENU_STATS_P2(tx_pri1_drop_bcnt), + GBENU_STATS_P2(tx_pri2_drop_bcnt), + GBENU_STATS_P2(tx_pri3_drop_bcnt), + GBENU_STATS_P2(tx_pri4_drop_bcnt), + GBENU_STATS_P2(tx_pri5_drop_bcnt), + GBENU_STATS_P2(tx_pri6_drop_bcnt), + GBENU_STATS_P2(tx_pri7_drop_bcnt), /* GBENU Module 3 */ GBENU_STATS_P3(rx_good_frames), GBENU_STATS_P3(rx_broadcast_frames), @@ -1115,7 +1172,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P3(ale_unknown_mcast_bytes), GBENU_STATS_P3(ale_unknown_bcast), GBENU_STATS_P3(ale_unknown_bcast_bytes), + GBENU_STATS_P3(ale_pol_match), + GBENU_STATS_P3(ale_pol_match_red), + GBENU_STATS_P3(ale_pol_match_yellow), GBENU_STATS_P3(tx_mem_protect_err), + GBENU_STATS_P3(tx_pri0_drop), + GBENU_STATS_P3(tx_pri1_drop), + GBENU_STATS_P3(tx_pri2_drop), + GBENU_STATS_P3(tx_pri3_drop), + GBENU_STATS_P3(tx_pri4_drop), + GBENU_STATS_P3(tx_pri5_drop), + GBENU_STATS_P3(tx_pri6_drop), + GBENU_STATS_P3(tx_pri7_drop), + GBENU_STATS_P3(tx_pri0_drop_bcnt), + GBENU_STATS_P3(tx_pri1_drop_bcnt), + GBENU_STATS_P3(tx_pri2_drop_bcnt), + GBENU_STATS_P3(tx_pri3_drop_bcnt), + GBENU_STATS_P3(tx_pri4_drop_bcnt), + GBENU_STATS_P3(tx_pri5_drop_bcnt), + GBENU_STATS_P3(tx_pri6_drop_bcnt), + GBENU_STATS_P3(tx_pri7_drop_bcnt), /* GBENU Module 4 */ GBENU_STATS_P4(rx_good_frames), GBENU_STATS_P4(rx_broadcast_frames), @@ -1162,7 +1238,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P4(ale_unknown_mcast_bytes), GBENU_STATS_P4(ale_unknown_bcast), GBENU_STATS_P4(ale_unknown_bcast_bytes), + GBENU_STATS_P4(ale_pol_match), + GBENU_STATS_P4(ale_pol_match_red), + GBENU_STATS_P4(ale_pol_match_yellow), GBENU_STATS_P4(tx_mem_protect_err), + GBENU_STATS_P4(tx_pri0_drop), + GBENU_STATS_P4(tx_pri1_drop), + GBENU_STATS_P4(tx_pri2_drop), + GBENU_STATS_P4(tx_pri3_drop), + GBENU_STATS_P4(tx_pri4_drop), + GBENU_STATS_P4(tx_pri5_drop), + GBENU_STATS_P4(tx_pri6_drop), + GBENU_STATS_P4(tx_pri7_drop), + GBENU_STATS_P4(tx_pri0_drop_bcnt), + GBENU_STATS_P4(tx_pri1_drop_bcnt), + GBENU_STATS_P4(tx_pri2_drop_bcnt), + GBENU_STATS_P4(tx_pri3_drop_bcnt), + GBENU_STATS_P4(tx_pri4_drop_bcnt), + GBENU_STATS_P4(tx_pri5_drop_bcnt), + GBENU_STATS_P4(tx_pri6_drop_bcnt), + GBENU_STATS_P4(tx_pri7_drop_bcnt), /* GBENU Module 5 */ GBENU_STATS_P5(rx_good_frames), GBENU_STATS_P5(rx_broadcast_frames), @@ -1209,7 +1304,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P5(ale_unknown_mcast_bytes), GBENU_STATS_P5(ale_unknown_bcast), GBENU_STATS_P5(ale_unknown_bcast_bytes), + GBENU_STATS_P5(ale_pol_match), + GBENU_STATS_P5(ale_pol_match_red), + GBENU_STATS_P5(ale_pol_match_yellow), GBENU_STATS_P5(tx_mem_protect_err), + GBENU_STATS_P5(tx_pri0_drop), + GBENU_STATS_P5(tx_pri1_drop), + GBENU_STATS_P5(tx_pri2_drop), + GBENU_STATS_P5(tx_pri3_drop), + GBENU_STATS_P5(tx_pri4_drop), + GBENU_STATS_P5(tx_pri5_drop), + GBENU_STATS_P5(tx_pri6_drop), + GBENU_STATS_P5(tx_pri7_drop), + GBENU_STATS_P5(tx_pri0_drop_bcnt), + GBENU_STATS_P5(tx_pri1_drop_bcnt), + GBENU_STATS_P5(tx_pri2_drop_bcnt), + GBENU_STATS_P5(tx_pri3_drop_bcnt), + GBENU_STATS_P5(tx_pri4_drop_bcnt), + GBENU_STATS_P5(tx_pri5_drop_bcnt), + GBENU_STATS_P5(tx_pri6_drop_bcnt), + GBENU_STATS_P5(tx_pri7_drop_bcnt), /* GBENU Module 6 */ GBENU_STATS_P6(rx_good_frames), GBENU_STATS_P6(rx_broadcast_frames), @@ -1256,7 +1370,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P6(ale_unknown_mcast_bytes), GBENU_STATS_P6(ale_unknown_bcast), GBENU_STATS_P6(ale_unknown_bcast_bytes), + GBENU_STATS_P6(ale_pol_match), + GBENU_STATS_P6(ale_pol_match_red), + GBENU_STATS_P6(ale_pol_match_yellow), GBENU_STATS_P6(tx_mem_protect_err), + GBENU_STATS_P6(tx_pri0_drop), + GBENU_STATS_P6(tx_pri1_drop), + GBENU_STATS_P6(tx_pri2_drop), + GBENU_STATS_P6(tx_pri3_drop), + GBENU_STATS_P6(tx_pri4_drop), + GBENU_STATS_P6(tx_pri5_drop), + GBENU_STATS_P6(tx_pri6_drop), + GBENU_STATS_P6(tx_pri7_drop), + GBENU_STATS_P6(tx_pri0_drop_bcnt), + GBENU_STATS_P6(tx_pri1_drop_bcnt), + GBENU_STATS_P6(tx_pri2_drop_bcnt), + GBENU_STATS_P6(tx_pri3_drop_bcnt), + GBENU_STATS_P6(tx_pri4_drop_bcnt), + GBENU_STATS_P6(tx_pri5_drop_bcnt), + GBENU_STATS_P6(tx_pri6_drop_bcnt), + GBENU_STATS_P6(tx_pri7_drop_bcnt), /* GBENU Module 7 */ GBENU_STATS_P7(rx_good_frames), GBENU_STATS_P7(rx_broadcast_frames), @@ -1303,7 +1436,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P7(ale_unknown_mcast_bytes), GBENU_STATS_P7(ale_unknown_bcast), GBENU_STATS_P7(ale_unknown_bcast_bytes), + GBENU_STATS_P7(ale_pol_match), + GBENU_STATS_P7(ale_pol_match_red), + GBENU_STATS_P7(ale_pol_match_yellow), GBENU_STATS_P7(tx_mem_protect_err), + GBENU_STATS_P7(tx_pri0_drop), + GBENU_STATS_P7(tx_pri1_drop), + GBENU_STATS_P7(tx_pri2_drop), + GBENU_STATS_P7(tx_pri3_drop), + GBENU_STATS_P7(tx_pri4_drop), + GBENU_STATS_P7(tx_pri5_drop), + GBENU_STATS_P7(tx_pri6_drop), + GBENU_STATS_P7(tx_pri7_drop), + GBENU_STATS_P7(tx_pri0_drop_bcnt), + GBENU_STATS_P7(tx_pri1_drop_bcnt), + GBENU_STATS_P7(tx_pri2_drop_bcnt), + GBENU_STATS_P7(tx_pri3_drop_bcnt), + GBENU_STATS_P7(tx_pri4_drop_bcnt), + GBENU_STATS_P7(tx_pri5_drop_bcnt), + GBENU_STATS_P7(tx_pri6_drop_bcnt), + GBENU_STATS_P7(tx_pri7_drop_bcnt), /* GBENU Module 8 */ GBENU_STATS_P8(rx_good_frames), GBENU_STATS_P8(rx_broadcast_frames), @@ -1350,7 +1502,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P8(ale_unknown_mcast_bytes), GBENU_STATS_P8(ale_unknown_bcast), GBENU_STATS_P8(ale_unknown_bcast_bytes), + GBENU_STATS_P8(ale_pol_match), + GBENU_STATS_P8(ale_pol_match_red), + GBENU_STATS_P8(ale_pol_match_yellow), GBENU_STATS_P8(tx_mem_protect_err), + GBENU_STATS_P8(tx_pri0_drop), + GBENU_STATS_P8(tx_pri1_drop), + GBENU_STATS_P8(tx_pri2_drop), + GBENU_STATS_P8(tx_pri3_drop), + GBENU_STATS_P8(tx_pri4_drop), + GBENU_STATS_P8(tx_pri5_drop), + GBENU_STATS_P8(tx_pri6_drop), + GBENU_STATS_P8(tx_pri7_drop), + GBENU_STATS_P8(tx_pri0_drop_bcnt), + GBENU_STATS_P8(tx_pri1_drop_bcnt), + GBENU_STATS_P8(tx_pri2_drop_bcnt), + GBENU_STATS_P8(tx_pri3_drop_bcnt), + GBENU_STATS_P8(tx_pri4_drop_bcnt), + GBENU_STATS_P8(tx_pri5_drop_bcnt), + GBENU_STATS_P8(tx_pri6_drop_bcnt), + GBENU_STATS_P8(tx_pri7_drop_bcnt), }; #define XGBE_STATS0_INFO(field) \ -- cgit v1.3-6-gb490 From 2be6967cdbc95a9960b620defedbf5e02e2af619 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 23 Jul 2015 23:35:56 +0300 Subject: net/mlx5e: Support ETH_RSS_HASH_XOR The ConnectX-4 HW implements inverted XOR8. To make it act as XOR we re-order the HW RSS indirection table. Set XOR to be the default RSS hash function and add ethtool API to control it. Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 + .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 39 ++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 46 +++++++++++++++++----- include/linux/mlx5/mlx5_ifc.h | 6 +-- 4 files changed, 79 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 3d23bd657e3c..61d8433392aa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -195,6 +195,7 @@ struct mlx5e_params { u16 rx_hash_log_tbl_sz; bool lro_en; u32 lro_wqe_sz; + u8 rss_hfunc; }; enum { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 388938482ff9..cb2853570504 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -662,6 +662,43 @@ out: return err; } +static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, + u8 *hfunc) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + if (hfunc) + *hfunc = priv->params.rss_hfunc; + + return 0; +} + +static int mlx5e_set_rxfh(struct net_device *netdev, const u32 *indir, + const u8 *key, const u8 hfunc) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + int err = 0; + + if (hfunc == ETH_RSS_HASH_NO_CHANGE) + return 0; + + if ((hfunc != ETH_RSS_HASH_XOR) && + (hfunc != ETH_RSS_HASH_TOP)) + return -EINVAL; + + mutex_lock(&priv->state_lock); + + priv->params.rss_hfunc = hfunc; + if (test_bit(MLX5E_STATE_OPENED, &priv->state)) { + mlx5e_close_locked(priv->netdev); + err = mlx5e_open_locked(priv->netdev); + } + + mutex_unlock(&priv->state_lock); + + return err; +} + const struct ethtool_ops mlx5e_ethtool_ops = { .get_drvinfo = mlx5e_get_drvinfo, .get_link = ethtool_op_get_link, @@ -676,4 +713,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = { .set_coalesce = mlx5e_set_coalesce, .get_settings = mlx5e_get_settings, .set_settings = mlx5e_set_settings, + .get_rxfh = mlx5e_get_rxfh, + .set_rxfh = mlx5e_set_rxfh, }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 40206da1f9d7..07d36275021e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1158,6 +1158,24 @@ static void mlx5e_close_tises(struct mlx5e_priv *priv) mlx5e_close_tis(priv, tc); } +static int mlx5e_rx_hash_fn(int hfunc) +{ + return (hfunc == ETH_RSS_HASH_TOP) ? + MLX5_RX_HASH_FN_TOEPLITZ : + MLX5_RX_HASH_FN_INVERTED_XOR8; +} + +static int mlx5e_bits_invert(unsigned long a, int size) +{ + int inv = 0; + int i; + + for (i = 0; i < size; i++) + inv |= (test_bit(size - i - 1, &a) ? 1 : 0) << i; + + return inv; +} + static int mlx5e_open_rqt(struct mlx5e_priv *priv) { struct mlx5_core_dev *mdev = priv->mdev; @@ -1166,11 +1184,10 @@ static int mlx5e_open_rqt(struct mlx5e_priv *priv) void *rqtc; int inlen; int err; - int sz; + int log_tbl_sz = priv->params.rx_hash_log_tbl_sz; + int sz = 1 << log_tbl_sz; int i; - sz = 1 << priv->params.rx_hash_log_tbl_sz; - inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz; in = mlx5_vzalloc(inlen); if (!in) @@ -1182,8 +1199,12 @@ static int mlx5e_open_rqt(struct mlx5e_priv *priv) MLX5_SET(rqtc, rqtc, rqt_max_size, sz); for (i = 0; i < sz; i++) { - int ix = i % priv->params.num_channels; + int ix = i; + + if (priv->params.rss_hfunc == ETH_RSS_HASH_XOR) + ix = mlx5e_bits_invert(i, log_tbl_sz); + ix = ix % priv->params.num_channels; MLX5_SET(rqtc, rqtc, rq_num[i], priv->channel[ix]->rq.rqn); } @@ -1254,12 +1275,16 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_SET(tirc, tirc, indirect_table, priv->rqtn); MLX5_SET(tirc, tirc, rx_hash_fn, - MLX5_TIRC_RX_HASH_FN_HASH_TOEPLITZ); - MLX5_SET(tirc, tirc, rx_hash_symmetric, 1); - netdev_rss_key_fill(MLX5_ADDR_OF(tirc, tirc, - rx_hash_toeplitz_key), - MLX5_FLD_SZ_BYTES(tirc, - rx_hash_toeplitz_key)); + mlx5e_rx_hash_fn(priv->params.rss_hfunc)); + if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) { + void *rss_key = MLX5_ADDR_OF(tirc, tirc, + rx_hash_toeplitz_key); + size_t len = MLX5_FLD_SZ_BYTES(tirc, + rx_hash_toeplitz_key); + + MLX5_SET(tirc, tirc, rx_hash_symmetric, 1); + netdev_rss_key_fill(rss_key, len); + } break; } @@ -1700,6 +1725,7 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev, MLX5E_PARAMS_DEFAULT_RX_HASH_LOG_TBL_SZ; priv->params.num_tc = 1; priv->params.default_vlan_prio = 0; + priv->params.rss_hfunc = ETH_RSS_HASH_XOR; priv->params.lro_en = false && !!MLX5_CAP_ETH(priv->mdev, lro_cap); priv->params.lro_wqe_sz = diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 6d2f6fee041c..c60a62bba652 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1936,9 +1936,9 @@ enum { }; enum { - MLX5_TIRC_RX_HASH_FN_HASH_NONE = 0x0, - MLX5_TIRC_RX_HASH_FN_HASH_INVERTED_XOR8 = 0x1, - MLX5_TIRC_RX_HASH_FN_HASH_TOEPLITZ = 0x2, + MLX5_RX_HASH_FN_NONE = 0x0, + MLX5_RX_HASH_FN_INVERTED_XOR8 = 0x1, + MLX5_RX_HASH_FN_TOEPLITZ = 0x2, }; enum { -- cgit v1.3-6-gb490 From 311c7c71c9bb8786c96fee353fe9886c08b017fe Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 23 Jul 2015 23:35:57 +0300 Subject: net/mlx5e: Allocate DMA coherent memory on reader NUMA node By affinity hints and XPS, each mlx5e channel is assigned a CPU core. Channel DMA coherent memory that is written by the NIC and read by SW (e.g CQ buffer) is allocated on the NUMA node of the CPU core assigned for the channel. Channel DMA coherent memory that is written by SW and read by the NIC (e.g SQ/RQ buffer) is allocated on the NUMA node of the NIC. Doorbell record (written by SW and read by the NIC) is an exception since it is accessed by SW more frequently. Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/alloc.c | 48 +++++++++++++++++++---- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 11 ++++-- drivers/net/ethernet/mellanox/mlx5/core/main.c | 6 ++- drivers/net/ethernet/mellanox/mlx5/core/wq.c | 12 +++--- drivers/net/ethernet/mellanox/mlx5/core/wq.h | 3 +- include/linux/mlx5/driver.h | 8 ++++ 6 files changed, 70 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c index 0715b497511f..6cb38304669f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c @@ -45,15 +45,34 @@ * register it in a memory region at HCA virtual address 0. */ -int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf) +static void *mlx5_dma_zalloc_coherent_node(struct mlx5_core_dev *dev, + size_t size, dma_addr_t *dma_handle, + int node) +{ + struct mlx5_priv *priv = &dev->priv; + int original_node; + void *cpu_handle; + + mutex_lock(&priv->alloc_mutex); + original_node = dev_to_node(&dev->pdev->dev); + set_dev_node(&dev->pdev->dev, node); + cpu_handle = dma_zalloc_coherent(&dev->pdev->dev, size, + dma_handle, GFP_KERNEL); + set_dev_node(&dev->pdev->dev, original_node); + mutex_unlock(&priv->alloc_mutex); + return cpu_handle; +} + +int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size, + struct mlx5_buf *buf, int node) { dma_addr_t t; buf->size = size; buf->npages = 1; buf->page_shift = (u8)get_order(size) + PAGE_SHIFT; - buf->direct.buf = dma_zalloc_coherent(&dev->pdev->dev, - size, &t, GFP_KERNEL); + buf->direct.buf = mlx5_dma_zalloc_coherent_node(dev, size, + &t, node); if (!buf->direct.buf) return -ENOMEM; @@ -66,6 +85,11 @@ int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf) return 0; } + +int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf) +{ + return mlx5_buf_alloc_node(dev, size, buf, dev->priv.numa_node); +} EXPORT_SYMBOL_GPL(mlx5_buf_alloc); void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf) @@ -75,7 +99,8 @@ void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf) } EXPORT_SYMBOL_GPL(mlx5_buf_free); -static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct device *dma_device) +static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct mlx5_core_dev *dev, + int node) { struct mlx5_db_pgdir *pgdir; @@ -84,8 +109,9 @@ static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct device *dma_device) return NULL; bitmap_fill(pgdir->bitmap, MLX5_DB_PER_PAGE); - pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE, - &pgdir->db_dma, GFP_KERNEL); + + pgdir->db_page = mlx5_dma_zalloc_coherent_node(dev, PAGE_SIZE, + &pgdir->db_dma, node); if (!pgdir->db_page) { kfree(pgdir); return NULL; @@ -118,7 +144,7 @@ static int mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir *pgdir, return 0; } -int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db) +int mlx5_db_alloc_node(struct mlx5_core_dev *dev, struct mlx5_db *db, int node) { struct mlx5_db_pgdir *pgdir; int ret = 0; @@ -129,7 +155,7 @@ int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db) if (!mlx5_alloc_db_from_pgdir(pgdir, db)) goto out; - pgdir = mlx5_alloc_db_pgdir(&(dev->pdev->dev)); + pgdir = mlx5_alloc_db_pgdir(dev, node); if (!pgdir) { ret = -ENOMEM; goto out; @@ -145,6 +171,12 @@ out: return ret; } +EXPORT_SYMBOL_GPL(mlx5_db_alloc_node); + +int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db) +{ + return mlx5_db_alloc_node(dev, db, dev->priv.numa_node); +} EXPORT_SYMBOL_GPL(mlx5_db_alloc); void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 07d36275021e..57cc8960b73b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -272,6 +272,8 @@ static int mlx5e_create_rq(struct mlx5e_channel *c, int err; int i; + param->wq.db_numa_node = cpu_to_node(c->cpu); + err = mlx5_wq_ll_create(mdev, ¶m->wq, rqc_wq, &rq->wq, &rq->wq_ctrl); if (err) @@ -502,6 +504,8 @@ static int mlx5e_create_sq(struct mlx5e_channel *c, if (err) return err; + param->wq.db_numa_node = cpu_to_node(c->cpu); + err = mlx5_wq_cyc_create(mdev, ¶m->wq, sqc_wq, &sq->wq, &sq->wq_ctrl); if (err) @@ -702,7 +706,8 @@ static int mlx5e_create_cq(struct mlx5e_channel *c, int err; u32 i; - param->wq.numa = cpu_to_node(c->cpu); + param->wq.buf_numa_node = cpu_to_node(c->cpu); + param->wq.db_numa_node = cpu_to_node(c->cpu); param->eq_ix = c->ix; err = mlx5_cqwq_create(mdev, ¶m->wq, param->cqc, &cq->wq, @@ -1000,7 +1005,7 @@ static void mlx5e_build_rq_param(struct mlx5e_priv *priv, MLX5_SET(wq, wq, log_wq_sz, priv->params.log_rq_size); MLX5_SET(wq, wq, pd, priv->pdn); - param->wq.numa = dev_to_node(&priv->mdev->pdev->dev); + param->wq.buf_numa_node = dev_to_node(&priv->mdev->pdev->dev); param->wq.linear = 1; } @@ -1014,7 +1019,7 @@ static void mlx5e_build_sq_param(struct mlx5e_priv *priv, MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB)); MLX5_SET(wq, wq, pd, priv->pdn); - param->wq.numa = dev_to_node(&priv->mdev->pdev->dev); + param->wq.buf_numa_node = dev_to_node(&priv->mdev->pdev->dev); } static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index afad529838de..c34eafbf1c04 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -455,7 +455,7 @@ static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i) struct mlx5_priv *priv = &mdev->priv; struct msix_entry *msix = priv->msix_arr; int irq = msix[i + MLX5_EQ_VEC_COMP_BASE].vector; - int numa_node = dev_to_node(&mdev->pdev->dev); + int numa_node = priv->numa_node; int err; if (!zalloc_cpumask_var(&priv->irq_info[i].mask, GFP_KERNEL)) { @@ -668,6 +668,10 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) INIT_LIST_HEAD(&priv->pgdir_list); spin_lock_init(&priv->mkey_lock); + mutex_init(&priv->alloc_mutex); + + priv->numa_node = dev_to_node(&dev->pdev->dev); + priv->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), mlx5_debugfs_root); if (!priv->dbg_root) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.c b/drivers/net/ethernet/mellanox/mlx5/core/wq.c index 8388411582cf..ce21ee5b2357 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.c @@ -73,13 +73,14 @@ int mlx5_wq_cyc_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, wq->log_stride = MLX5_GET(wq, wqc, log_wq_stride); wq->sz_m1 = (1 << MLX5_GET(wq, wqc, log_wq_sz)) - 1; - err = mlx5_db_alloc(mdev, &wq_ctrl->db); + err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node); if (err) { mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err); return err; } - err = mlx5_buf_alloc(mdev, mlx5_wq_cyc_get_byte_size(wq), &wq_ctrl->buf); + err = mlx5_buf_alloc_node(mdev, mlx5_wq_cyc_get_byte_size(wq), + &wq_ctrl->buf, param->buf_numa_node); if (err) { mlx5_core_warn(mdev, "mlx5_buf_alloc() failed, %d\n", err); goto err_db_free; @@ -108,13 +109,14 @@ int mlx5_cqwq_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, wq->log_sz = MLX5_GET(cqc, cqc, log_cq_size); wq->sz_m1 = (1 << wq->log_sz) - 1; - err = mlx5_db_alloc(mdev, &wq_ctrl->db); + err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node); if (err) { mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err); return err; } - err = mlx5_buf_alloc(mdev, mlx5_cqwq_get_byte_size(wq), &wq_ctrl->buf); + err = mlx5_buf_alloc_node(mdev, mlx5_cqwq_get_byte_size(wq), + &wq_ctrl->buf, param->buf_numa_node); if (err) { mlx5_core_warn(mdev, "mlx5_buf_alloc() failed, %d\n", err); goto err_db_free; @@ -144,7 +146,7 @@ int mlx5_wq_ll_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, wq->log_stride = MLX5_GET(wq, wqc, log_wq_stride); wq->sz_m1 = (1 << MLX5_GET(wq, wqc, log_wq_sz)) - 1; - err = mlx5_db_alloc(mdev, &wq_ctrl->db); + err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node); if (err) { mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err); return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h index e0ddd69fb429..6c2a8f95093c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h @@ -37,7 +37,8 @@ struct mlx5_wq_param { int linear; - int numa; + int buf_numa_node; + int db_numa_node; }; struct mlx5_wq_ctrl { diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 5722d88c2429..1c0d5d062d7c 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -463,6 +463,10 @@ struct mlx5_priv { /* end: mr staff */ /* start: alloc staff */ + /* protect buffer alocation according to numa node */ + struct mutex alloc_mutex; + int numa_node; + struct mutex pgdir_mutex; struct list_head pgdir_list; /* end: alloc staff */ @@ -672,6 +676,8 @@ void mlx5_health_cleanup(void); void __init mlx5_health_init(void); void mlx5_start_health_poll(struct mlx5_core_dev *dev); void mlx5_stop_health_poll(struct mlx5_core_dev *dev); +int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size, + struct mlx5_buf *buf, int node); int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf); void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf); struct mlx5_cmd_mailbox *mlx5_alloc_cmd_mailbox_chain(struct mlx5_core_dev *dev, @@ -773,6 +779,8 @@ void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev); int mlx5_cq_debugfs_init(struct mlx5_core_dev *dev); void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev); int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db); +int mlx5_db_alloc_node(struct mlx5_core_dev *dev, struct mlx5_db *db, + int node); void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db); const char *mlx5_command_str(int command); -- cgit v1.3-6-gb490 From 58d522912ac7d25b63f468fa4a4e8bb059c5144e Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Thu, 23 Jul 2015 23:35:58 +0300 Subject: net/mlx5e: Support TX packet copy into WQE AKA inline WQE. A TX latency optimization to save data gather DMA reads. Controlled by ETHTOOL_TX_COPYBREAK. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 + .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 53 ++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 13 ++++++ drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 10 +++- 4 files changed, 77 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 61d8433392aa..d9dc506188c8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -196,6 +196,7 @@ struct mlx5e_params { bool lro_en; u32 lro_wqe_sz; u8 rss_hfunc; + u16 tx_max_inline; }; enum { @@ -520,3 +521,4 @@ static inline void mlx5e_cq_arm(struct mlx5e_cq *cq) } extern const struct ethtool_ops mlx5e_ethtool_ops; +u16 mlx5e_get_max_inline_cap(struct mlx5_core_dev *mdev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index cb2853570504..14fd82c0d18e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -699,6 +699,57 @@ static int mlx5e_set_rxfh(struct net_device *netdev, const u32 *indir, return err; } +static int mlx5e_get_tunable(struct net_device *dev, + const struct ethtool_tunable *tuna, + void *data) +{ + const struct mlx5e_priv *priv = netdev_priv(dev); + int err = 0; + + switch (tuna->id) { + case ETHTOOL_TX_COPYBREAK: + *(u32 *)data = priv->params.tx_max_inline; + break; + default: + err = -EINVAL; + break; + } + + return err; +} + +static int mlx5e_set_tunable(struct net_device *dev, + const struct ethtool_tunable *tuna, + const void *data) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5e_params new_params; + u32 val; + int err = 0; + + switch (tuna->id) { + case ETHTOOL_TX_COPYBREAK: + val = *(u32 *)data; + if (val > mlx5e_get_max_inline_cap(mdev)) { + err = -EINVAL; + break; + } + + mutex_lock(&priv->state_lock); + new_params = priv->params; + new_params.tx_max_inline = val; + err = mlx5e_update_priv_params(priv, &new_params); + mutex_unlock(&priv->state_lock); + break; + default: + err = -EINVAL; + break; + } + + return err; +} + const struct ethtool_ops mlx5e_ethtool_ops = { .get_drvinfo = mlx5e_get_drvinfo, .get_link = ethtool_op_get_link, @@ -715,4 +766,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = { .set_settings = mlx5e_set_settings, .get_rxfh = mlx5e_get_rxfh, .set_rxfh = mlx5e_set_rxfh, + .get_tunable = mlx5e_get_tunable, + .set_tunable = mlx5e_set_tunable, }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 57cc8960b73b..c55fad431cbf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -41,6 +41,7 @@ struct mlx5e_rq_param { struct mlx5e_sq_param { u32 sqc[MLX5_ST_SZ_DW(sqc)]; struct mlx5_wq_param wq; + u16 max_inline; }; struct mlx5e_cq_param { @@ -514,6 +515,7 @@ static int mlx5e_create_sq(struct mlx5e_channel *c, sq->wq.db = &sq->wq.db[MLX5_SND_DBR]; sq->uar_map = sq->uar.map; sq->bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2; + sq->max_inline = param->max_inline; err = mlx5e_alloc_sq_db(sq, cpu_to_node(c->cpu)); if (err) @@ -1020,6 +1022,7 @@ static void mlx5e_build_sq_param(struct mlx5e_priv *priv, MLX5_SET(wq, wq, pd, priv->pdn); param->wq.buf_numa_node = dev_to_node(&priv->mdev->pdev->dev); + param->max_inline = priv->params.tx_max_inline; } static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv, @@ -1703,6 +1706,15 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev) return 0; } +u16 mlx5e_get_max_inline_cap(struct mlx5_core_dev *mdev) +{ + int bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2; + + return bf_buf_size - + sizeof(struct mlx5e_tx_wqe) + + 2 /*sizeof(mlx5e_tx_wqe.inline_hdr_start)*/; +} + static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev, struct net_device *netdev, int num_comp_vectors) @@ -1721,6 +1733,7 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev, MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC; priv->params.tx_cq_moderation_pkts = MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS; + priv->params.tx_max_inline = mlx5e_get_max_inline_cap(mdev); priv->params.min_rx_wqes = MLX5E_PARAMS_DEFAULT_MIN_RX_WQES; priv->params.rx_hash_log_tbl_sz = diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 03f28f438e55..351ac6982e22 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -112,7 +112,15 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, struct sk_buff *skb) { -#define MLX5E_MIN_INLINE 16 /* eth header with vlan (w/o next ethertype) */ + /* Some NIC TX decisions, e.g loopback, are based on the packet + * headers and occur before the data gather. + * Therefore these headers must be copied into the WQE + */ +#define MLX5E_MIN_INLINE (ETH_HLEN + 2/*vlan tag*/) + + if (skb_headlen(skb) <= sq->max_inline) + return skb_headlen(skb); + return MLX5E_MIN_INLINE; } -- cgit v1.3-6-gb490 From 88a85f99e51fb2373259ab83c8bb130a9bbf3804 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Thu, 23 Jul 2015 23:35:59 +0300 Subject: net/mlx5e: TX latency optimization to save DMA reads A regular TX WQE execution involves two or more DMA reads - one to fetch the WQE, and another one per WQE gather entry. These DMA reads obviously increase the TX latency. There are two mlx5 mechanisms to bypass these DMA reads: 1) Inline WQE 2) Blue Flame (BF) An inline WQE contains a whole packet, thus saves the DMA read/s of the regular WQE gather entry/s. Inline WQE support was already added in the previous commit. A BF WQE is written directly to the device I/O mapped memory, thus enables saving the DMA read that fetches the WQE. The BF WQE I/O write must be in cache line granularity, thus uses the CPU write combining mechanism. A BF WQE I/O write acts also as a TX doorbell for notifying the device of new TX WQEs. A BF WQE is written to the same I/O mapped address as the regular TX doorbell, thus this address is being mapped twice - once by ioremap() and once by io_mapping_map_wc(). While both mechanisms reduce the TX latency, they both consume more CPU cycles than a regular WQE: - A BF WQE must still be written to host memory, in addition to being written directly to the device I/O mapped memory. - An inline WQE involves copying the SKB data into it. To handle this tradeoff, we introduce here a heuristic algorithm that strives to avoid using these two mechanisms in case the TX queue is being back-pressured by the device, and limit their usage rate otherwise. An inline WQE will always be "Blue Flamed" (written directly to the device I/O mapped memory) while a BF WQE may not be inlined (may contain gather entries). Preliminary testing using netperf UDP_RR shows that the latency goes down from 17.5us to 16.9us, while the message rate (tested with pktgen) stays the same. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 24 +++++++++++++++------ drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 12 ++++++----- drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 26 ++++++++++++++++++----- drivers/net/ethernet/mellanox/mlx5/core/main.c | 26 +++++++++++++++++++++-- drivers/net/ethernet/mellanox/mlx5/core/uar.c | 6 ++++++ include/linux/mlx5/driver.h | 4 +++- 6 files changed, 79 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index d9dc506188c8..b66edd2c5a61 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -60,6 +60,7 @@ #define MLX5E_TX_CQ_POLL_BUDGET 128 #define MLX5E_UPDATE_STATS_INTERVAL 200 /* msecs */ +#define MLX5E_SQ_BF_BUDGET 16 static const char vport_strings[][ETH_GSTRING_LEN] = { /* vport statistics */ @@ -268,7 +269,9 @@ struct mlx5e_sq { /* dirtied @xmit */ u16 pc ____cacheline_aligned_in_smp; u32 dma_fifo_pc; - u32 bf_offset; + u16 bf_offset; + u16 prev_cc; + u8 bf_budget; struct mlx5e_sq_stats stats; struct mlx5e_cq cq; @@ -281,9 +284,10 @@ struct mlx5e_sq { struct mlx5_wq_cyc wq; u32 dma_fifo_mask; void __iomem *uar_map; + void __iomem *uar_bf_map; struct netdev_queue *txq; u32 sqn; - u32 bf_buf_size; + u16 bf_buf_size; u16 max_inline; u16 edge; struct device *pdev; @@ -493,8 +497,10 @@ int mlx5e_update_priv_params(struct mlx5e_priv *priv, struct mlx5e_params *new_params); static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq, - struct mlx5e_tx_wqe *wqe) + struct mlx5e_tx_wqe *wqe, int bf_sz) { + u16 ofst = MLX5_BF_OFFSET + sq->bf_offset; + /* ensure wqe is visible to device before updating doorbell record */ dma_wmb(); @@ -505,9 +511,15 @@ static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq, */ wmb(); - mlx5_write64((__be32 *)&wqe->ctrl, - sq->uar_map + MLX5_BF_OFFSET + sq->bf_offset, - NULL); + if (bf_sz) { + __iowrite64_copy(sq->uar_bf_map + ofst, &wqe->ctrl, bf_sz); + + /* flush the write-combining mapped buffer */ + wmb(); + + } else { + mlx5_write64((__be32 *)&wqe->ctrl, sq->uar_map + ofst, NULL); + } sq->bf_offset ^= sq->bf_buf_size; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index c55fad431cbf..4a87e9dcf52c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -514,6 +514,7 @@ static int mlx5e_create_sq(struct mlx5e_channel *c, sq->wq.db = &sq->wq.db[MLX5_SND_DBR]; sq->uar_map = sq->uar.map; + sq->uar_bf_map = sq->uar.bf_map; sq->bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2; sq->max_inline = param->max_inline; @@ -524,11 +525,12 @@ static int mlx5e_create_sq(struct mlx5e_channel *c, txq_ix = c->ix + tc * priv->params.num_channels; sq->txq = netdev_get_tx_queue(priv->netdev, txq_ix); - sq->pdev = c->pdev; - sq->mkey_be = c->mkey_be; - sq->channel = c; - sq->tc = tc; - sq->edge = (sq->wq.sz_m1 + 1) - MLX5_SEND_WQE_MAX_WQEBBS; + sq->pdev = c->pdev; + sq->mkey_be = c->mkey_be; + sq->channel = c; + sq->tc = tc; + sq->edge = (sq->wq.sz_m1 + 1) - MLX5_SEND_WQE_MAX_WQEBBS; + sq->bf_budget = MLX5E_SQ_BF_BUDGET; priv->txq_to_sq_map[txq_ix] = sq; return 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 351ac6982e22..64380bc0cd6a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -57,7 +57,7 @@ void mlx5e_send_nop(struct mlx5e_sq *sq, bool notify_hw) if (notify_hw) { cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE; - mlx5e_tx_notify_hw(sq, wqe); + mlx5e_tx_notify_hw(sq, wqe, 0); } } @@ -110,7 +110,7 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, } static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, - struct sk_buff *skb) + struct sk_buff *skb, bool bf) { /* Some NIC TX decisions, e.g loopback, are based on the packet * headers and occur before the data gather. @@ -118,7 +118,7 @@ static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, */ #define MLX5E_MIN_INLINE (ETH_HLEN + 2/*vlan tag*/) - if (skb_headlen(skb) <= sq->max_inline) + if (bf && (skb_headlen(skb) <= sq->max_inline)) return skb_headlen(skb); return MLX5E_MIN_INLINE; @@ -137,6 +137,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) u8 opcode = MLX5_OPCODE_SEND; dma_addr_t dma_addr = 0; + bool bf = false; u16 headlen; u16 ds_cnt; u16 ihs; @@ -149,6 +150,11 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) else sq->stats.csum_offload_none++; + if (sq->cc != sq->prev_cc) { + sq->prev_cc = sq->cc; + sq->bf_budget = (sq->cc == sq->pc) ? MLX5E_SQ_BF_BUDGET : 0; + } + if (skb_is_gso(skb)) { u32 payload_len; @@ -161,7 +167,10 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) sq->stats.tso_packets++; sq->stats.tso_bytes += payload_len; } else { - ihs = mlx5e_get_inline_hdr_size(sq, skb); + bf = sq->bf_budget && + !skb->xmit_more && + !skb_shinfo(skb)->nr_frags; + ihs = mlx5e_get_inline_hdr_size(sq, skb, bf); MLX5E_TX_SKB_CB(skb)->num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN); } @@ -233,14 +242,21 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) } if (!skb->xmit_more || netif_xmit_stopped(sq->txq)) { + int bf_sz = 0; + + if (bf && sq->uar_bf_map) + bf_sz = MLX5E_TX_SKB_CB(skb)->num_wqebbs << 3; + cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE; - mlx5e_tx_notify_hw(sq, wqe); + mlx5e_tx_notify_hw(sq, wqe, bf_sz); } /* fill sq edge with nops to avoid wqe wrap around */ while ((sq->pc & wq->sz_m1) > sq->edge) mlx5e_send_nop(sq, false); + sq->bf_budget = bf ? sq->bf_budget - 1 : 0; + sq->stats.packets++; return NETDEV_TX_OK; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index c34eafbf1c04..603a8b0908ee 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -654,6 +654,22 @@ static int mlx5_core_set_issi(struct mlx5_core_dev *dev) } #endif +static int map_bf_area(struct mlx5_core_dev *dev) +{ + resource_size_t bf_start = pci_resource_start(dev->pdev, 0); + resource_size_t bf_len = pci_resource_len(dev->pdev, 0); + + dev->priv.bf_mapping = io_mapping_create_wc(bf_start, bf_len); + + return dev->priv.bf_mapping ? 0 : -ENOMEM; +} + +static void unmap_bf_area(struct mlx5_core_dev *dev) +{ + if (dev->priv.bf_mapping) + io_mapping_free(dev->priv.bf_mapping); +} + static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) { struct mlx5_priv *priv = &dev->priv; @@ -808,10 +824,13 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) goto err_stop_eqs; } + if (map_bf_area(dev)) + dev_err(&pdev->dev, "Failed to map blue flame area\n"); + err = mlx5_irq_set_affinity_hints(dev); if (err) { dev_err(&pdev->dev, "Failed to alloc affinity hint cpumask\n"); - goto err_free_comp_eqs; + goto err_unmap_bf_area; } MLX5_INIT_DOORBELL_LOCK(&priv->cq_uar_lock); @@ -823,7 +842,9 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) return 0; -err_free_comp_eqs: +err_unmap_bf_area: + unmap_bf_area(dev); + free_comp_eqs(dev); err_stop_eqs: @@ -881,6 +902,7 @@ static void mlx5_dev_cleanup(struct mlx5_core_dev *dev) mlx5_cleanup_qp_table(dev); mlx5_cleanup_cq_table(dev); mlx5_irq_clear_affinity_hints(dev); + unmap_bf_area(dev); free_comp_eqs(dev); mlx5_stop_eqs(dev); mlx5_free_uuars(dev, &priv->uuari); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c index 9ef85873ceea..eb05c845ece9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/uar.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/uar.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include "mlx5_core.h" @@ -246,6 +247,10 @@ int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar) goto err_free_uar; } + if (mdev->priv.bf_mapping) + uar->bf_map = io_mapping_map_wc(mdev->priv.bf_mapping, + uar->index << PAGE_SHIFT); + return 0; err_free_uar: @@ -257,6 +262,7 @@ EXPORT_SYMBOL(mlx5_alloc_map_uar); void mlx5_unmap_free_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar) { + io_mapping_unmap(uar->bf_map); iounmap(uar->map); mlx5_cmd_free_uar(mdev, uar->index); } diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 1c0d5d062d7c..5fe0cae1a515 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -380,7 +380,7 @@ struct mlx5_uar { u32 index; struct list_head bf_list; unsigned free_bf_bmap; - void __iomem *wc_map; + void __iomem *bf_map; void __iomem *map; }; @@ -435,6 +435,8 @@ struct mlx5_priv { struct mlx5_uuar_info uuari; MLX5_DECLARE_DOORBELL_LOCK(cq_uar_lock); + struct io_mapping *bf_mapping; + /* pages stuff */ struct workqueue_struct *pg_wq; struct rb_root page_root; -- cgit v1.3-6-gb490 From 5a6f8aef16c53ffeb9c1497f0b583269695c067d Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Thu, 23 Jul 2015 23:36:00 +0300 Subject: net/mlx5e: Cosmetics: use BIT() instead of "1 <<", and others No logical change in this commit. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 16 +- .../ethernet/mellanox/mlx5/core/en_flow_table.c | 166 +++++++++++---------- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 20 +-- 3 files changed, 104 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index b66edd2c5a61..39294f2fbaac 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -330,14 +330,14 @@ struct mlx5e_channel { }; enum mlx5e_traffic_types { - MLX5E_TT_IPV4_TCP = 0, - MLX5E_TT_IPV6_TCP = 1, - MLX5E_TT_IPV4_UDP = 2, - MLX5E_TT_IPV6_UDP = 3, - MLX5E_TT_IPV4 = 4, - MLX5E_TT_IPV6 = 5, - MLX5E_TT_ANY = 6, - MLX5E_NUM_TT = 7, + MLX5E_TT_IPV4_TCP, + MLX5E_TT_IPV6_TCP, + MLX5E_TT_IPV4_UDP, + MLX5E_TT_IPV6_UDP, + MLX5E_TT_IPV4, + MLX5E_TT_IPV6, + MLX5E_TT_ANY, + MLX5E_NUM_TT, }; enum { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c index 120db80c47aa..cca34f6fa515 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c @@ -105,25 +105,25 @@ static void mlx5e_del_eth_addr_from_flow_table(struct mlx5e_priv *priv, { void *ft = priv->ft.main; - if (ai->tt_vec & (1 << MLX5E_TT_IPV6_TCP)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV6_TCP)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_TCP]); - if (ai->tt_vec & (1 << MLX5E_TT_IPV4_TCP)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV4_TCP)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_TCP]); - if (ai->tt_vec & (1 << MLX5E_TT_IPV6_UDP)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV6_UDP)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_UDP]); - if (ai->tt_vec & (1 << MLX5E_TT_IPV4_UDP)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV4_UDP)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_UDP]); - if (ai->tt_vec & (1 << MLX5E_TT_IPV6)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV6)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6]); - if (ai->tt_vec & (1 << MLX5E_TT_IPV4)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV4)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4]); - if (ai->tt_vec & (1 << MLX5E_TT_ANY)) + if (ai->tt_vec & BIT(MLX5E_TT_ANY)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_ANY]); } @@ -156,33 +156,33 @@ static u32 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type) switch (eth_addr_type) { case MLX5E_UC: ret = - (1 << MLX5E_TT_IPV4_TCP) | - (1 << MLX5E_TT_IPV6_TCP) | - (1 << MLX5E_TT_IPV4_UDP) | - (1 << MLX5E_TT_IPV6_UDP) | - (1 << MLX5E_TT_IPV4) | - (1 << MLX5E_TT_IPV6) | - (1 << MLX5E_TT_ANY) | + BIT(MLX5E_TT_IPV4_TCP) | + BIT(MLX5E_TT_IPV6_TCP) | + BIT(MLX5E_TT_IPV4_UDP) | + BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV4) | + BIT(MLX5E_TT_IPV6) | + BIT(MLX5E_TT_ANY) | 0; break; case MLX5E_MC_IPV4: ret = - (1 << MLX5E_TT_IPV4_UDP) | - (1 << MLX5E_TT_IPV4) | + BIT(MLX5E_TT_IPV4_UDP) | + BIT(MLX5E_TT_IPV4) | 0; break; case MLX5E_MC_IPV6: ret = - (1 << MLX5E_TT_IPV6_UDP) | - (1 << MLX5E_TT_IPV6) | + BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV6) | 0; break; case MLX5E_MC_OTHER: ret = - (1 << MLX5E_TT_ANY) | + BIT(MLX5E_TT_ANY) | 0; break; } @@ -191,23 +191,23 @@ static u32 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type) case MLX5E_ALLMULTI: ret = - (1 << MLX5E_TT_IPV4_UDP) | - (1 << MLX5E_TT_IPV6_UDP) | - (1 << MLX5E_TT_IPV4) | - (1 << MLX5E_TT_IPV6) | - (1 << MLX5E_TT_ANY) | + BIT(MLX5E_TT_IPV4_UDP) | + BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV4) | + BIT(MLX5E_TT_IPV6) | + BIT(MLX5E_TT_ANY) | 0; break; default: /* MLX5E_PROMISC */ ret = - (1 << MLX5E_TT_IPV4_TCP) | - (1 << MLX5E_TT_IPV6_TCP) | - (1 << MLX5E_TT_IPV4_UDP) | - (1 << MLX5E_TT_IPV6_UDP) | - (1 << MLX5E_TT_IPV4) | - (1 << MLX5E_TT_IPV6) | - (1 << MLX5E_TT_ANY) | + BIT(MLX5E_TT_IPV4_TCP) | + BIT(MLX5E_TT_IPV6_TCP) | + BIT(MLX5E_TT_IPV4_UDP) | + BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV4) | + BIT(MLX5E_TT_IPV6) | + BIT(MLX5E_TT_ANY) | 0; break; } @@ -226,6 +226,7 @@ static int __mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, u8 *match_criteria_dmac; void *ft = priv->ft.main; u32 *tirn = priv->tirn; + u32 *ft_ix; u32 tt_vec; int err; @@ -261,51 +262,51 @@ static int __mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, tt_vec = mlx5e_get_tt_vec(ai, type); - if (tt_vec & (1 << MLX5E_TT_ANY)) { + ft_ix = &ai->ft_ix[MLX5E_TT_ANY]; + if (tt_vec & BIT(MLX5E_TT_ANY)) { MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_ANY]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_ANY]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_ANY); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_ANY); } match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.ethertype); - if (tt_vec & (1 << MLX5E_TT_IPV4)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV4]; + if (tt_vec & BIT(MLX5E_TT_IPV4)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IP); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV4]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV4]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV4); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV4); } - if (tt_vec & (1 << MLX5E_TT_IPV6)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV6]; + if (tt_vec & BIT(MLX5E_TT_IPV6)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IPV6); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV6]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV6]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV6); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV6); } MLX5_SET_TO_ONES(fte_match_param, match_criteria, @@ -313,70 +314,75 @@ static int __mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, IPPROTO_UDP); - if (tt_vec & (1 << MLX5E_TT_IPV4_UDP)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV4_UDP]; + if (tt_vec & BIT(MLX5E_TT_IPV4_UDP)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IP); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV4_UDP]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV4_UDP]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV4_UDP); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV4_UDP); } - if (tt_vec & (1 << MLX5E_TT_IPV6_UDP)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV6_UDP]; + if (tt_vec & BIT(MLX5E_TT_IPV6_UDP)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IPV6); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV6_UDP]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV6_UDP]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV6_UDP); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV6_UDP); } MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, IPPROTO_TCP); - if (tt_vec & (1 << MLX5E_TT_IPV4_TCP)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV4_TCP]; + if (tt_vec & BIT(MLX5E_TT_IPV4_TCP)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IP); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV4_TCP]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV4_TCP]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV4_TCP); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV4_TCP); } - if (tt_vec & (1 << MLX5E_TT_IPV6_TCP)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV6_TCP]; + if (tt_vec & BIT(MLX5E_TT_IPV6_TCP)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IPV6); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV6_TCP]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV6_TCP]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV6_TCP); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV6_TCP); } return 0; + +err_del_ai: + mlx5e_del_eth_addr_from_flow_table(priv, ai); + + return err; } static int mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 4a87e9dcf52c..8194c32c7476 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1252,13 +1252,13 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) #define ROUGH_MAX_L2_L3_HDR_SZ 256 -#define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\ - MLX5_HASH_FIELD_SEL_DST_IP) +#define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\ + MLX5_HASH_FIELD_SEL_DST_IP) -#define MLX5_HASH_ALL (MLX5_HASH_FIELD_SEL_SRC_IP |\ - MLX5_HASH_FIELD_SEL_DST_IP |\ - MLX5_HASH_FIELD_SEL_L4_SPORT |\ - MLX5_HASH_FIELD_SEL_L4_DPORT) +#define MLX5_HASH_IP_L4PORTS (MLX5_HASH_FIELD_SEL_SRC_IP |\ + MLX5_HASH_FIELD_SEL_DST_IP |\ + MLX5_HASH_FIELD_SEL_L4_SPORT |\ + MLX5_HASH_FIELD_SEL_L4_DPORT) if (priv->params.lro_en) { MLX5_SET(tirc, tirc, lro_enable_mask, @@ -1305,7 +1305,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, MLX5_L4_PROT_TYPE_TCP); MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_ALL); + MLX5_HASH_IP_L4PORTS); break; case MLX5E_TT_IPV6_TCP: @@ -1314,7 +1314,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, MLX5_L4_PROT_TYPE_TCP); MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_ALL); + MLX5_HASH_IP_L4PORTS); break; case MLX5E_TT_IPV4_UDP: @@ -1323,7 +1323,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, MLX5_L4_PROT_TYPE_UDP); MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_ALL); + MLX5_HASH_IP_L4PORTS); break; case MLX5E_TT_IPV6_UDP: @@ -1332,7 +1332,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, MLX5_L4_PROT_TYPE_UDP); MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_ALL); + MLX5_HASH_IP_L4PORTS); break; case MLX5E_TT_IPV4: -- cgit v1.3-6-gb490 From a741749f214afd05402aeed0ecdca90eeaffc303 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Thu, 23 Jul 2015 23:36:01 +0300 Subject: net/mlx5e: Input IPSEC.SPI into the RX RSS hash function In addition to the source/destination IP which are already hashed. Only for unicast traffic for now. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 4 + .../ethernet/mellanox/mlx5/core/en_flow_table.c | 92 +++++++++++++++++++++- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 32 ++++++++ 3 files changed, 127 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 39294f2fbaac..b710e9bade38 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -334,6 +334,10 @@ enum mlx5e_traffic_types { MLX5E_TT_IPV6_TCP, MLX5E_TT_IPV4_UDP, MLX5E_TT_IPV6_UDP, + MLX5E_TT_IPV4_IPSEC_AH, + MLX5E_TT_IPV6_IPSEC_AH, + MLX5E_TT_IPV4_IPSEC_ESP, + MLX5E_TT_IPV6_IPSEC_ESP, MLX5E_TT_IPV4, MLX5E_TT_IPV6, MLX5E_TT_ANY, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c index cca34f6fa515..70ec31b9e1e9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c @@ -105,6 +105,22 @@ static void mlx5e_del_eth_addr_from_flow_table(struct mlx5e_priv *priv, { void *ft = priv->ft.main; + if (ai->tt_vec & BIT(MLX5E_TT_IPV6_IPSEC_ESP)) + mlx5_del_flow_table_entry(ft, + ai->ft_ix[MLX5E_TT_IPV6_IPSEC_ESP]); + + if (ai->tt_vec & BIT(MLX5E_TT_IPV4_IPSEC_ESP)) + mlx5_del_flow_table_entry(ft, + ai->ft_ix[MLX5E_TT_IPV4_IPSEC_ESP]); + + if (ai->tt_vec & BIT(MLX5E_TT_IPV6_IPSEC_AH)) + mlx5_del_flow_table_entry(ft, + ai->ft_ix[MLX5E_TT_IPV6_IPSEC_AH]); + + if (ai->tt_vec & BIT(MLX5E_TT_IPV4_IPSEC_AH)) + mlx5_del_flow_table_entry(ft, + ai->ft_ix[MLX5E_TT_IPV4_IPSEC_AH]); + if (ai->tt_vec & BIT(MLX5E_TT_IPV6_TCP)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_TCP]); @@ -160,6 +176,10 @@ static u32 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type) BIT(MLX5E_TT_IPV6_TCP) | BIT(MLX5E_TT_IPV4_UDP) | BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV4_IPSEC_AH) | + BIT(MLX5E_TT_IPV6_IPSEC_AH) | + BIT(MLX5E_TT_IPV4_IPSEC_ESP) | + BIT(MLX5E_TT_IPV6_IPSEC_ESP) | BIT(MLX5E_TT_IPV4) | BIT(MLX5E_TT_IPV6) | BIT(MLX5E_TT_ANY) | @@ -205,6 +225,10 @@ static u32 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type) BIT(MLX5E_TT_IPV6_TCP) | BIT(MLX5E_TT_IPV4_UDP) | BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV4_IPSEC_AH) | + BIT(MLX5E_TT_IPV6_IPSEC_AH) | + BIT(MLX5E_TT_IPV4_IPSEC_ESP) | + BIT(MLX5E_TT_IPV6_IPSEC_ESP) | BIT(MLX5E_TT_IPV4) | BIT(MLX5E_TT_IPV6) | BIT(MLX5E_TT_ANY) | @@ -377,6 +401,72 @@ static int __mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, ai->tt_vec |= BIT(MLX5E_TT_IPV6_TCP); } + MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, + IPPROTO_AH); + + ft_ix = &ai->ft_ix[MLX5E_TT_IPV4_IPSEC_AH]; + if (tt_vec & BIT(MLX5E_TT_IPV4_IPSEC_AH)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IP); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV4_IPSEC_AH]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV4_IPSEC_AH); + } + + ft_ix = &ai->ft_ix[MLX5E_TT_IPV6_IPSEC_AH]; + if (tt_vec & BIT(MLX5E_TT_IPV6_IPSEC_AH)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IPV6); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV6_IPSEC_AH]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV6_IPSEC_AH); + } + + MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, + IPPROTO_ESP); + + ft_ix = &ai->ft_ix[MLX5E_TT_IPV4_IPSEC_ESP]; + if (tt_vec & BIT(MLX5E_TT_IPV4_IPSEC_ESP)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IP); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV4_IPSEC_ESP]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV4_IPSEC_ESP); + } + + ft_ix = &ai->ft_ix[MLX5E_TT_IPV6_IPSEC_ESP]; + if (tt_vec & BIT(MLX5E_TT_IPV6_IPSEC_ESP)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IPV6); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV6_IPSEC_ESP]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV6_IPSEC_ESP); + } + return 0; err_del_ai: @@ -731,7 +821,7 @@ static int mlx5e_create_main_flow_table(struct mlx5e_priv *priv) if (!g) return -ENOMEM; - g[0].log_sz = 2; + g[0].log_sz = 3; g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, outer_headers.ethertype); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 8194c32c7476..355a10abe667 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1260,6 +1260,10 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_HASH_FIELD_SEL_L4_SPORT |\ MLX5_HASH_FIELD_SEL_L4_DPORT) +#define MLX5_HASH_IP_IPSEC_SPI (MLX5_HASH_FIELD_SEL_SRC_IP |\ + MLX5_HASH_FIELD_SEL_DST_IP |\ + MLX5_HASH_FIELD_SEL_IPSEC_SPI) + if (priv->params.lro_en) { MLX5_SET(tirc, tirc, lro_enable_mask, MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO | @@ -1335,6 +1339,34 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_HASH_IP_L4PORTS); break; + case MLX5E_TT_IPV4_IPSEC_AH: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + + case MLX5E_TT_IPV6_IPSEC_AH: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + + case MLX5E_TT_IPV4_IPSEC_ESP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + + case MLX5E_TT_IPV6_IPSEC_ESP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + case MLX5E_TT_IPV4: MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, MLX5_L3_PROT_TYPE_IPV4); -- cgit v1.3-6-gb490 From ba27b7ef4a72e0d4718a13bc93b769eec4567d2a Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Thu, 23 Jul 2015 10:38:47 +0000 Subject: Bluetooth: btmrvl: Coding style Fix for btmrvl header Fix for "Unnecessary space before function pointer arguments" reported by checkpatch. Signed-off-by: Prasanna Karthik Signed-off-by: Johan Hedberg --- drivers/bluetooth/btmrvl_drv.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 086f0ec89580..27a9aac25583 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -95,10 +95,10 @@ struct btmrvl_private { struct btmrvl_device btmrvl_dev; struct btmrvl_adapter *adapter; struct btmrvl_thread main_thread; - int (*hw_host_to_card) (struct btmrvl_private *priv, + int (*hw_host_to_card)(struct btmrvl_private *priv, u8 *payload, u16 nb); - int (*hw_wakeup_firmware) (struct btmrvl_private *priv); - int (*hw_process_int_status) (struct btmrvl_private *priv); + int (*hw_wakeup_firmware)(struct btmrvl_private *priv); + int (*hw_process_int_status)(struct btmrvl_private *priv); void (*firmware_dump)(struct btmrvl_private *priv); spinlock_t driver_lock; /* spinlock used by driver */ #ifdef CONFIG_DEBUG_FS -- cgit v1.3-6-gb490 From acf50c5fc6f3d1851d23c48737210b5f61f58e1f Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Thu, 23 Jul 2015 11:08:52 +0000 Subject: Bluetooth: hci_ldisc: Cleaned up coding style warnings Fix for Cleanpatch warning: Space prohibited between function name and open parenthesis '(' Signed-off-by: Prasanna Karthik Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ldisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 051f8213697d..20c2ac193ff9 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -770,7 +770,7 @@ static int __init hci_uart_init(void) /* Register the tty discipline */ - memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc)); + memset(&hci_uart_ldisc, 0, sizeof(hci_uart_ldisc)); hci_uart_ldisc.magic = TTY_LDISC_MAGIC; hci_uart_ldisc.name = "n_hci"; hci_uart_ldisc.open = hci_uart_tty_open; -- cgit v1.3-6-gb490 From fa4cf04e65cb7f75c147e2cc80f0f472b0d93534 Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Thu, 23 Jul 2015 11:22:56 +0000 Subject: Bluetooth: hci_h5: Cleaned up coding style warnings Cleanedup "Unnecessary space before function pointer arguments" warning reported by Checkpatch Signed-off-by: Prasanna Karthik Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_h5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 3455cecc9ecf..b35b238a0380 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -75,7 +75,7 @@ struct h5 { size_t rx_pending; /* Expecting more bytes */ u8 rx_ack; /* Last ack number received */ - int (*rx_func) (struct hci_uart *hu, u8 c); + int (*rx_func)(struct hci_uart *hu, u8 c); struct timer_list timer; /* Retransmission timer */ -- cgit v1.3-6-gb490 From 9267135cca60674321139626f49077a4937d730e Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 24 Jul 2015 14:16:10 +0800 Subject: net: phy: dp83867: fix simple_return.cocci warnings drivers/net/phy/dp83867.c:126:1-4: WARNING: end returns can be simpified drivers/net/phy/dp83867.c:74:5-8: WARNING: end returns can be simpified if tested value is negative or 0 Simplify a trivial if-return sequence. Possibly combine with a preceding function call. Generated by: scripts/coccinelle/misc/simple_return.cocci CC: Dan Murphy Signed-off-by: Fengguang Wu Signed-off-by: David S. Miller --- drivers/net/phy/dp83867.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 8a3bf5469892..32f10662f4ac 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -123,12 +123,8 @@ static int dp83867_of_init(struct phy_device *phydev) if (ret) return ret; - ret = of_property_read_u32(of_node, "ti,fifo-depth", + return of_property_read_u32(of_node, "ti,fifo-depth", &dp83867->fifo_depth); - if (ret) - return ret; - - return 0; } #else static int dp83867_of_init(struct phy_device *phydev) -- cgit v1.3-6-gb490 From 94724d102c829d9f2105b1cb6e831c99174cd49d Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Fri, 24 Jul 2015 19:26:02 +0800 Subject: net: phy: fix auto negotiation checking for teranetics When using fiber port, the phy cannot report it's auto negotiation state, driver should always report auto negotiation is done when using fiber port. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/phy/teranetics.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c index 7dcb5aada1c4..91e1bec6079f 100644 --- a/drivers/net/phy/teranetics.c +++ b/drivers/net/phy/teranetics.c @@ -51,8 +51,15 @@ static int teranetics_aneg_done(struct phy_device *phydev) { int reg; - reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); - return (reg < 0) ? reg : (reg & BMSR_ANEGCOMPLETE); + /* auto negotiation state can only be checked when using copper + * port, if using fiber port, just lie it's done. + */ + if (!phy_read_mmd(phydev, MDIO_MMD_VEND1, 93)) { + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + return (reg < 0) ? reg : (reg & BMSR_ANEGCOMPLETE); + } + + return 1; } static int teranetics_config_aneg(struct phy_device *phydev) -- cgit v1.3-6-gb490 From 205845a34763432040496908c8f52f1f97e5ee62 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 24 Jul 2015 15:50:31 +0200 Subject: bonding: convert num_grat_arp to the new bonding option API num_grat_arp wasn't converted to the new bonding option API, so do this now and remove the specific sysfs store option in order to use the standard one. num_grat_arp is the same as num_unsol_na so add it as an alias with the same option settings. An important difference is the option name which is matched in bond_sysfs_store_option(). Signed-off-by: Nikolay Aleksandrov Acked-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_options.c | 7 +++++++ drivers/net/bonding/bond_sysfs.c | 20 +++----------------- include/net/bond_options.h | 1 + 3 files changed, 11 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index e9c624d54dd4..6dda57e2e724 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -420,6 +420,13 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .flags = BOND_OPTFLAG_IFDOWN, .values = bond_ad_user_port_key_tbl, .set = bond_option_ad_user_port_key_set, + }, + [BOND_OPT_NUM_PEER_NOTIF_ALIAS] = { + .id = BOND_OPT_NUM_PEER_NOTIF_ALIAS, + .name = "num_grat_arp", + .desc = "Number of peer notifications to send on failover event", + .values = bond_num_peer_notif_tbl, + .set = bond_option_num_peer_notif_set } }; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 31835a4dab57..f4ae72086215 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -380,7 +380,7 @@ static ssize_t bonding_show_ad_select(struct device *d, static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_sysfs_store_option); -/* Show and set the number of peer notifications to send after a failover event. */ +/* Show the number of peer notifications to send after a failover event. */ static ssize_t bonding_show_num_peer_notif(struct device *d, struct device_attribute *attr, char *buf) @@ -388,24 +388,10 @@ static ssize_t bonding_show_num_peer_notif(struct device *d, struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.num_peer_notif); } - -static ssize_t bonding_store_num_peer_notif(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct bonding *bond = to_bond(d); - int ret; - - ret = bond_opt_tryset_rtnl(bond, BOND_OPT_NUM_PEER_NOTIF, (char *)buf); - if (!ret) - ret = count; - - return ret; -} static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, - bonding_show_num_peer_notif, bonding_store_num_peer_notif); + bonding_show_num_peer_notif, bonding_sysfs_store_option); static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, - bonding_show_num_peer_notif, bonding_store_num_peer_notif); + bonding_show_num_peer_notif, bonding_sysfs_store_option); /* Show the MII monitor interval. */ static ssize_t bonding_show_miimon(struct device *d, diff --git a/include/net/bond_options.h b/include/net/bond_options.h index c28aca25320e..1797235cd590 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -66,6 +66,7 @@ enum { BOND_OPT_AD_ACTOR_SYS_PRIO, BOND_OPT_AD_ACTOR_SYSTEM, BOND_OPT_AD_USER_PORT_KEY, + BOND_OPT_NUM_PEER_NOTIF_ALIAS, BOND_OPT_LAST }; -- cgit v1.3-6-gb490 From fc596660dd4e83f7f84e3cd7b25dc5e8e83000ef Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jul 2015 13:28:57 +0200 Subject: drm/atomic: add connectors_changed to separate it from mode_changed, v2 This can be a separate case from mode_changed, when connectors stay the same but only the mode is different. Drivers may choose to implement specific optimizations to prevent a full modeset for this case. Changes since v1: - Update kerneldocs slightly. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 39 +++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_display.c | 2 +- include/drm/drm_atomic.h | 3 ++- include/drm/drm_crtc.h | 8 +++++--- 4 files changed, 38 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 99656815641d..10bcdd554501 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -124,7 +124,7 @@ steal_encoder(struct drm_atomic_state *state, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - crtc_state->mode_changed = true; + crtc_state->connectors_changed = true; list_for_each_entry(connector, &config->connector_list, head) { if (connector->state->best_encoder != encoder) @@ -174,14 +174,14 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) idx = drm_crtc_index(connector->state->crtc); crtc_state = state->crtc_states[idx]; - crtc_state->mode_changed = true; + crtc_state->connectors_changed = true; } if (connector_state->crtc) { idx = drm_crtc_index(connector_state->crtc); crtc_state = state->crtc_states[idx]; - crtc_state->mode_changed = true; + crtc_state->connectors_changed = true; } } @@ -233,7 +233,7 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) idx = drm_crtc_index(connector_state->crtc); crtc_state = state->crtc_states[idx]; - crtc_state->mode_changed = true; + crtc_state->connectors_changed = true; DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n", connector->base.id, @@ -256,7 +256,8 @@ mode_fixup(struct drm_atomic_state *state) bool ret; for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!crtc_state->mode_changed) + if (!crtc_state->mode_changed && + !crtc_state->connectors_changed) continue; drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode); @@ -312,7 +313,8 @@ mode_fixup(struct drm_atomic_state *state) for_each_crtc_in_state(state, crtc, crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; - if (!crtc_state->mode_changed) + if (!crtc_state->mode_changed && + !crtc_state->connectors_changed) continue; funcs = crtc->helper_private; @@ -338,9 +340,14 @@ mode_fixup(struct drm_atomic_state *state) * * Check the state object to see if the requested state is physically possible. * This does all the crtc and connector related computations for an atomic - * update. It computes and updates crtc_state->mode_changed, adds any additional - * connectors needed for full modesets and calls down into ->mode_fixup - * functions of the driver backend. + * update and adds any additional connectors needed for full modesets and calls + * down into ->mode_fixup functions of the driver backend. + * + * crtc_state->mode_changed is set when the input mode is changed. + * crtc_state->connectors_changed is set when a connector is added or + * removed from the crtc. + * crtc_state->active_changed is set when crtc_state->active changes, + * which is used for dpms. * * IMPORTANT: * @@ -373,7 +380,17 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, if (crtc->state->enable != crtc_state->enable) { DRM_DEBUG_ATOMIC("[CRTC:%d] enable changed\n", crtc->base.id); + + /* + * For clarity this assignment is done here, but + * enable == 0 is only true when there are no + * connectors and a NULL mode. + * + * The other way around is true as well. enable != 0 + * iff connectors are attached and a mode is set. + */ crtc_state->mode_changed = true; + crtc_state->connectors_changed = true; } } @@ -448,6 +465,9 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset); * This does all the plane update related checks using by calling into the * ->atomic_check hooks provided by the driver. * + * It also sets crtc_state->planes_changed to indicate that a crtc has + * updated planes. + * * RETURNS * Zero for success or -errno */ @@ -2074,6 +2094,7 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, state->mode_changed = false; state->active_changed = false; state->planes_changed = false; + state->connectors_changed = false; state->event = NULL; } EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index af0bcfee4771..07cee59edece 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -413,7 +413,7 @@ static const intel_limit_t intel_limits_bxt = { static bool needs_modeset(struct drm_crtc_state *state) { - return state->mode_changed || state->active_changed; + return drm_atomic_crtc_needs_modeset(state); } /** diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 8a3a913320eb..e67aeac2aee0 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -166,7 +166,8 @@ int __must_check drm_atomic_async_commit(struct drm_atomic_state *state); static inline bool drm_atomic_crtc_needs_modeset(struct drm_crtc_state *state) { - return state->mode_changed || state->active_changed; + return state->mode_changed || state->active_changed || + state->connectors_changed; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 3071319ea194..90a0ff70384a 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -255,12 +255,13 @@ struct drm_atomic_state; * @crtc: backpointer to the CRTC * @enable: whether the CRTC should be enabled, gates all other state * @active: whether the CRTC is actively displaying (used for DPMS) - * @mode_changed: for use by helpers and drivers when computing state updates - * @active_changed: for use by helpers and drivers when computing state updates + * @planes_changed: planes on this crtc are updated + * @mode_changed: crtc_state->mode or crtc_state->enable has been changed + * @active_changed: crtc_state->active has been toggled. + * @connectors_changed: connectors to this crtc have been updated * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes * @last_vblank_count: for helpers and drivers to capture the vblank of the * update to ensure framebuffer cleanup isn't done too early - * @planes_changed: for use by helpers and drivers when computing state updates * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings * @mode: current mode timings * @event: optional pointer to a DRM event to signal upon completion of the @@ -283,6 +284,7 @@ struct drm_crtc_state { bool planes_changed : 1; bool mode_changed : 1; bool active_changed : 1; + bool connectors_changed : 1; /* attached planes bitmask: * WARNING: transitional helpers do not maintain plane_mask so -- cgit v1.3-6-gb490 From 71790a2792c8772e29bf5aa726215d9256ef93dc Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 24 Jul 2015 10:08:40 -0700 Subject: hv_netvsc: Add structs and handlers for VF messages This patch adds data structures and handlers for messages related to SRIOV Virtual Function. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 29 +++++++++++++++++++++++++++ drivers/net/hyperv/netvsc.c | 43 +++++++++++++++++++++++++++++++---------- 2 files changed, 62 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 925b75d4d910..5ce7020ca530 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -541,6 +541,29 @@ union nvsp_2_message_uber { struct nvsp_2_free_rxbuf free_rxbuf; } __packed; +struct nvsp_4_send_vf_association { + /* 1: allocated, serial number is valid. 0: not allocated */ + u32 allocated; + + /* Serial number of the VF to team with */ + u32 serial; +} __packed; + +enum nvsp_vm_datapath { + NVSP_DATAPATH_SYNTHETIC = 0, + NVSP_DATAPATH_VF, + NVSP_DATAPATH_MAX +}; + +struct nvsp_4_sw_datapath { + u32 active_datapath; /* active data path in VM */ +} __packed; + +union nvsp_4_message_uber { + struct nvsp_4_send_vf_association vf_assoc; + struct nvsp_4_sw_datapath active_dp; +} __packed; + enum nvsp_subchannel_operation { NVSP_SUBCHANNEL_NONE = 0, NVSP_SUBCHANNEL_ALLOCATE, @@ -578,6 +601,7 @@ union nvsp_all_messages { union nvsp_message_init_uber init_msg; union nvsp_1_message_uber v1_msg; union nvsp_2_message_uber v2_msg; + union nvsp_4_message_uber v4_msg; union nvsp_5_message_uber v5_msg; } __packed; @@ -691,6 +715,11 @@ struct netvsc_device { /* The net device context */ struct net_device_context *nd_ctx; + + /* 1: allocated, serial number is valid. 0: not allocated */ + u32 vf_alloc; + /* Serial number of the VF to team with */ + u32 vf_serial; }; /* NdisInitialize message */ diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 23126a74f357..51e4c0fd0a74 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -453,13 +453,16 @@ static int negotiate_nvsp_ver(struct hv_device *device, if (nvsp_ver == NVSP_PROTOCOL_VERSION_1) return 0; - /* NVSPv2 only: Send NDIS config */ + /* NVSPv2 or later: Send NDIS config */ memset(init_packet, 0, sizeof(struct nvsp_message)); init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG; init_packet->msg.v2_msg.send_ndis_config.mtu = net_device->ndev->mtu + ETH_HLEN; init_packet->msg.v2_msg.send_ndis_config.capability.ieee8021q = 1; + if (nvsp_ver >= NVSP_PROTOCOL_VERSION_5) + init_packet->msg.v2_msg.send_ndis_config.capability.sriov = 1; + ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), (unsigned long)init_packet, @@ -1064,11 +1067,10 @@ static void netvsc_receive(struct netvsc_device *net_device, static void netvsc_send_table(struct hv_device *hdev, - struct vmpacket_descriptor *vmpkt) + struct nvsp_message *nvmsg) { struct netvsc_device *nvscdev; struct net_device *ndev; - struct nvsp_message *nvmsg; int i; u32 count, *tab; @@ -1077,12 +1079,6 @@ static void netvsc_send_table(struct hv_device *hdev, return; ndev = nvscdev->ndev; - nvmsg = (struct nvsp_message *)((unsigned long)vmpkt + - (vmpkt->offset8 << 3)); - - if (nvmsg->hdr.msg_type != NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE) - return; - count = nvmsg->msg.v5_msg.send_table.count; if (count != VRSS_SEND_TAB_SIZE) { netdev_err(ndev, "Received wrong send-table size:%u\n", count); @@ -1096,6 +1092,28 @@ static void netvsc_send_table(struct hv_device *hdev, nvscdev->send_table[i] = tab[i]; } +static void netvsc_send_vf(struct netvsc_device *nvdev, + struct nvsp_message *nvmsg) +{ + nvdev->vf_alloc = nvmsg->msg.v4_msg.vf_assoc.allocated; + nvdev->vf_serial = nvmsg->msg.v4_msg.vf_assoc.serial; +} + +static inline void netvsc_receive_inband(struct hv_device *hdev, + struct netvsc_device *nvdev, + struct nvsp_message *nvmsg) +{ + switch (nvmsg->hdr.msg_type) { + case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE: + netvsc_send_table(hdev, nvmsg); + break; + + case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION: + netvsc_send_vf(nvdev, nvmsg); + break; + } +} + void netvsc_channel_cb(void *context) { int ret; @@ -1108,6 +1126,7 @@ void netvsc_channel_cb(void *context) unsigned char *buffer; int bufferlen = NETVSC_PACKET_SIZE; struct net_device *ndev; + struct nvsp_message *nvmsg; if (channel->primary_channel != NULL) device = channel->primary_channel->device_obj; @@ -1126,6 +1145,8 @@ void netvsc_channel_cb(void *context) if (ret == 0) { if (bytes_recvd > 0) { desc = (struct vmpacket_descriptor *)buffer; + nvmsg = (struct nvsp_message *)((unsigned long) + desc + (desc->offset8 << 3)); switch (desc->type) { case VM_PKT_COMP: netvsc_send_completion(net_device, @@ -1138,7 +1159,9 @@ void netvsc_channel_cb(void *context) break; case VM_PKT_DATA_INBAND: - netvsc_send_table(device, desc); + netvsc_receive_inband(device, + net_device, + nvmsg); break; default: -- cgit v1.3-6-gb490 From c22995c5488d7048554d85ee5ee8a269932b0aea Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 25 Jul 2015 09:42:28 -0700 Subject: dsa: mv88e6352/mv88e6xxx: Move temperature sensor code to mv88e6xxx.c Move the temperature sensing code for mv88e6352 and mv88e6320 families into mv88e6xxx.c to simplify adding support for additional chips. With this change, mv88e6xxx_6320_family() no longer needs to be a global function and is made static. Cc: Andrew Lunn Signed-off-by: Guenter Roeck Acked-by: Andrew Lunn Tested-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6352.c | 72 +----------------- drivers/net/dsa/mv88e6xxx.c | 176 ++++++++++++++++++++++++++++++++------------ drivers/net/dsa/mv88e6xxx.h | 7 +- 3 files changed, 136 insertions(+), 119 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index cfece5ae9d5f..af210efecc55 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -92,70 +92,6 @@ static int mv88e6352_setup_global(struct dsa_switch *ds) return 0; } -#ifdef CONFIG_NET_DSA_HWMON - -static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp) -{ - int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; - int ret; - - *temp = 0; - - ret = mv88e6xxx_phy_page_read(ds, phy, 6, 27); - if (ret < 0) - return ret; - - *temp = (ret & 0xff) - 25; - - return 0; -} - -static int mv88e6352_get_temp_limit(struct dsa_switch *ds, int *temp) -{ - int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; - int ret; - - *temp = 0; - - ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); - if (ret < 0) - return ret; - - *temp = (((ret >> 8) & 0x1f) * 5) - 25; - - return 0; -} - -static int mv88e6352_set_temp_limit(struct dsa_switch *ds, int temp) -{ - int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; - int ret; - - ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); - if (ret < 0) - return ret; - temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); - return mv88e6xxx_phy_page_write(ds, phy, 6, 26, - (ret & 0xe0ff) | (temp << 8)); -} - -static int mv88e6352_get_temp_alarm(struct dsa_switch *ds, bool *alarm) -{ - int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; - int ret; - - *alarm = false; - - ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); - if (ret < 0) - return ret; - - *alarm = !!(ret & 0x40); - - return 0; -} -#endif /* CONFIG_NET_DSA_HWMON */ - static int mv88e6352_setup(struct dsa_switch *ds) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); @@ -393,10 +329,10 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .set_eee = mv88e6xxx_set_eee, .get_eee = mv88e6xxx_get_eee, #ifdef CONFIG_NET_DSA_HWMON - .get_temp = mv88e6352_get_temp, - .get_temp_limit = mv88e6352_get_temp_limit, - .set_temp_limit = mv88e6352_set_temp_limit, - .get_temp_alarm = mv88e6352_get_temp_alarm, + .get_temp = mv88e6xxx_get_temp, + .get_temp_limit = mv88e6xxx_get_temp_limit, + .set_temp_limit = mv88e6xxx_set_temp_limit, + .get_temp_alarm = mv88e6xxx_get_temp_alarm, #endif .get_eeprom = mv88e6352_get_eeprom, .set_eeprom = mv88e6352_set_eeprom, diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 5158375b7abd..61ce4cf120a6 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -517,7 +517,7 @@ static bool mv88e6xxx_6185_family(struct dsa_switch *ds) return false; } -bool mv88e6xxx_6320_family(struct dsa_switch *ds) +static bool mv88e6xxx_6320_family(struct dsa_switch *ds) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); @@ -808,54 +808,6 @@ void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, } } -#ifdef CONFIG_NET_DSA_HWMON - -int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int ret; - int val; - - *temp = 0; - - mutex_lock(&ps->smi_mutex); - - ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); - if (ret < 0) - goto error; - - /* Enable temperature sensor */ - ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); - if (ret < 0) - goto error; - - ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5)); - if (ret < 0) - goto error; - - /* Wait for temperature to stabilize */ - usleep_range(10000, 12000); - - val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); - if (val < 0) { - ret = val; - goto error; - } - - /* Disable temperature sensor */ - ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5)); - if (ret < 0) - goto error; - - *temp = ((val & 0x1f) - 5) * 5; - -error: - _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); - mutex_unlock(&ps->smi_mutex); - return ret; -} -#endif /* CONFIG_NET_DSA_HWMON */ - /* Must be called with SMI lock held */ static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) @@ -2180,6 +2132,132 @@ mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum, return ret; } +#ifdef CONFIG_NET_DSA_HWMON + +static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int ret; + int val; + + *temp = 0; + + mutex_lock(&ps->smi_mutex); + + ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); + if (ret < 0) + goto error; + + /* Enable temperature sensor */ + ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); + if (ret < 0) + goto error; + + ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5)); + if (ret < 0) + goto error; + + /* Wait for temperature to stabilize */ + usleep_range(10000, 12000); + + val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); + if (val < 0) { + ret = val; + goto error; + } + + /* Disable temperature sensor */ + ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5)); + if (ret < 0) + goto error; + + *temp = ((val & 0x1f) - 5) * 5; + +error: + _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); + mutex_unlock(&ps->smi_mutex); + return ret; +} + +static int mv88e63xx_get_temp(struct dsa_switch *ds, int *temp) +{ + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; + int ret; + + *temp = 0; + + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 27); + if (ret < 0) + return ret; + + *temp = (ret & 0xff) - 25; + + return 0; +} + +int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) +{ + if (mv88e6xxx_6320_family(ds) || mv88e6xxx_6352_family(ds)) + return mv88e63xx_get_temp(ds, temp); + + return mv88e61xx_get_temp(ds, temp); +} + +int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp) +{ + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; + int ret; + + if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds)) + return -EOPNOTSUPP; + + *temp = 0; + + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); + if (ret < 0) + return ret; + + *temp = (((ret >> 8) & 0x1f) * 5) - 25; + + return 0; +} + +int mv88e6xxx_set_temp_limit(struct dsa_switch *ds, int temp) +{ + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; + int ret; + + if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds)) + return -EOPNOTSUPP; + + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); + if (ret < 0) + return ret; + temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); + return mv88e6xxx_phy_page_write(ds, phy, 6, 26, + (ret & 0xe0ff) | (temp << 8)); +} + +int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm) +{ + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; + int ret; + + if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds)) + return -EOPNOTSUPP; + + *alarm = false; + + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); + if (ret < 0) + return ret; + + *alarm = !!(ret & 0x40); + + return 0; +} +#endif /* CONFIG_NET_DSA_HWMON */ + static int __init mv88e6xxx_init(void) { #if IS_ENABLED(CONFIG_NET_DSA_MV88E6131) diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 64786cb89a93..78e37226a37d 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -394,7 +394,10 @@ int mv88e6xxx_get_sset_count_basic(struct dsa_switch *ds); int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port); void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, struct ethtool_regs *regs, void *_p); -int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp); +int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp); +int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp); +int mv88e6xxx_set_temp_limit(struct dsa_switch *ds, int temp); +int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm); int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds); int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds); int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum); @@ -415,7 +418,7 @@ int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg); int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, int reg, int val); -bool mv88e6xxx_6320_family(struct dsa_switch *ds); + extern struct dsa_switch_driver mv88e6131_switch_driver; extern struct dsa_switch_driver mv88e6123_61_65_switch_driver; extern struct dsa_switch_driver mv88e6352_switch_driver; -- cgit v1.3-6-gb490 From 2f45d1902acfc7e6680cfeeb38922dcc7e16deb6 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 25 Jul 2015 23:42:01 +0300 Subject: ravb: minimize TX data copying Renesas Ethernet AVB controller requires that all data are aligned on 4-byte boundary. While it's easily achievable for the RX data with the help of skb_reserve() (we even align on 128-byte boundary as recommended by the manual), we can't do the same with the TX data, and it always comes unaligned from the networking core. Originally we solved it an easy way, copying all packet to a preallocated aligned buffer; however, it's enough to copy only up to 3 first bytes from each packet, doing the transfer using 2 TX descriptors instead of just 1. Here's an implementation of the new TX algorithm that significantly reduces the driver's memory requirements. Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb.h | 5 +- drivers/net/ethernet/renesas/ravb_main.c | 104 ++++++++++++++++++------------- 2 files changed, 64 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index 8aa50ac4e2d6..a157aaaaff6a 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -658,6 +658,8 @@ struct ravb_desc { __le32 dptr; /* Descriptor pointer */ }; +#define DPTR_ALIGN 4 /* Required descriptor pointer alignment */ + enum DIE_DT { /* Frame data */ DT_FMID = 0x40, @@ -739,6 +741,7 @@ enum RAVB_QUEUE { #define RX_QUEUE_OFFSET 4 #define NUM_RX_QUEUE 2 #define NUM_TX_QUEUE 2 +#define NUM_TX_DESC 2 /* TX descriptors per packet */ struct ravb_tstamp_skb { struct list_head list; @@ -777,9 +780,9 @@ struct ravb_private { dma_addr_t tx_desc_dma[NUM_TX_QUEUE]; struct ravb_ex_rx_desc *rx_ring[NUM_RX_QUEUE]; struct ravb_tx_desc *tx_ring[NUM_TX_QUEUE]; + void *tx_align[NUM_TX_QUEUE]; struct sk_buff **rx_skb[NUM_RX_QUEUE]; struct sk_buff **tx_skb[NUM_TX_QUEUE]; - void **tx_buffers[NUM_TX_QUEUE]; u32 rx_over_errors; u32 rx_fifo_errors; struct net_device_stats stats[NUM_RX_QUEUE]; diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 779bb58a068e..3d972d819420 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -195,12 +195,8 @@ static void ravb_ring_free(struct net_device *ndev, int q) priv->tx_skb[q] = NULL; /* Free aligned TX buffers */ - if (priv->tx_buffers[q]) { - for (i = 0; i < priv->num_tx_ring[q]; i++) - kfree(priv->tx_buffers[q][i]); - } - kfree(priv->tx_buffers[q]); - priv->tx_buffers[q] = NULL; + kfree(priv->tx_align[q]); + priv->tx_align[q] = NULL; if (priv->rx_ring[q]) { ring_size = sizeof(struct ravb_ex_rx_desc) * @@ -212,7 +208,7 @@ static void ravb_ring_free(struct net_device *ndev, int q) if (priv->tx_ring[q]) { ring_size = sizeof(struct ravb_tx_desc) * - (priv->num_tx_ring[q] + 1); + (priv->num_tx_ring[q] * NUM_TX_DESC + 1); dma_free_coherent(NULL, ring_size, priv->tx_ring[q], priv->tx_desc_dma[q]); priv->tx_ring[q] = NULL; @@ -227,7 +223,8 @@ static void ravb_ring_format(struct net_device *ndev, int q) struct ravb_tx_desc *tx_desc; struct ravb_desc *desc; int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q]; - int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q]; + int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q] * + NUM_TX_DESC; dma_addr_t dma_addr; int i; @@ -260,11 +257,12 @@ static void ravb_ring_format(struct net_device *ndev, int q) memset(priv->tx_ring[q], 0, tx_ring_size); /* Build TX ring buffer */ - for (i = 0; i < priv->num_tx_ring[q]; i++) { - tx_desc = &priv->tx_ring[q][i]; + for (i = 0, tx_desc = priv->tx_ring[q]; i < priv->num_tx_ring[q]; + i++, tx_desc++) { + tx_desc->die_dt = DT_EEMPTY; + tx_desc++; tx_desc->die_dt = DT_EEMPTY; } - tx_desc = &priv->tx_ring[q][i]; tx_desc->dptr = cpu_to_le32((u32)priv->tx_desc_dma[q]); tx_desc->die_dt = DT_LINKFIX; /* type */ @@ -285,7 +283,6 @@ static int ravb_ring_init(struct net_device *ndev, int q) struct ravb_private *priv = netdev_priv(ndev); struct sk_buff *skb; int ring_size; - void *buffer; int i; /* Allocate RX and TX skb rings */ @@ -305,19 +302,11 @@ static int ravb_ring_init(struct net_device *ndev, int q) } /* Allocate rings for the aligned buffers */ - priv->tx_buffers[q] = kcalloc(priv->num_tx_ring[q], - sizeof(*priv->tx_buffers[q]), GFP_KERNEL); - if (!priv->tx_buffers[q]) + priv->tx_align[q] = kmalloc(DPTR_ALIGN * priv->num_tx_ring[q] + + DPTR_ALIGN - 1, GFP_KERNEL); + if (!priv->tx_align[q]) goto error; - for (i = 0; i < priv->num_tx_ring[q]; i++) { - buffer = kmalloc(PKT_BUF_SZ + RAVB_ALIGN - 1, GFP_KERNEL); - if (!buffer) - goto error; - /* Aligned TX buffer */ - priv->tx_buffers[q][i] = buffer; - } - /* Allocate all RX descriptors. */ ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1); priv->rx_ring[q] = dma_alloc_coherent(NULL, ring_size, @@ -329,7 +318,8 @@ static int ravb_ring_init(struct net_device *ndev, int q) priv->dirty_rx[q] = 0; /* Allocate all TX descriptors. */ - ring_size = sizeof(struct ravb_tx_desc) * (priv->num_tx_ring[q] + 1); + ring_size = sizeof(struct ravb_tx_desc) * + (priv->num_tx_ring[q] * NUM_TX_DESC + 1); priv->tx_ring[q] = dma_alloc_coherent(NULL, ring_size, &priv->tx_desc_dma[q], GFP_KERNEL); @@ -443,7 +433,8 @@ static int ravb_tx_free(struct net_device *ndev, int q) u32 size; for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) { - entry = priv->dirty_tx[q] % priv->num_tx_ring[q]; + entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] * + NUM_TX_DESC); desc = &priv->tx_ring[q][entry]; if (desc->die_dt != DT_FEMPTY) break; @@ -451,14 +442,18 @@ static int ravb_tx_free(struct net_device *ndev, int q) dma_rmb(); size = le16_to_cpu(desc->ds_tagl) & TX_DS; /* Free the original skb. */ - if (priv->tx_skb[q][entry]) { + if (priv->tx_skb[q][entry / NUM_TX_DESC]) { dma_unmap_single(&ndev->dev, le32_to_cpu(desc->dptr), size, DMA_TO_DEVICE); - dev_kfree_skb_any(priv->tx_skb[q][entry]); - priv->tx_skb[q][entry] = NULL; + /* Last packet descriptor? */ + if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) { + entry /= NUM_TX_DESC; + dev_kfree_skb_any(priv->tx_skb[q][entry]); + priv->tx_skb[q][entry] = NULL; + stats->tx_packets++; + } free_num++; } - stats->tx_packets++; stats->tx_bytes += size; desc->die_dt = DT_EEMPTY; } @@ -1284,37 +1279,53 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) u32 dma_addr; void *buffer; u32 entry; + u32 len; spin_lock_irqsave(&priv->lock, flags); - if (priv->cur_tx[q] - priv->dirty_tx[q] >= priv->num_tx_ring[q]) { + if (priv->cur_tx[q] - priv->dirty_tx[q] > (priv->num_tx_ring[q] - 1) * + NUM_TX_DESC) { netif_err(priv, tx_queued, ndev, "still transmitting with the full ring!\n"); netif_stop_subqueue(ndev, q); spin_unlock_irqrestore(&priv->lock, flags); return NETDEV_TX_BUSY; } - entry = priv->cur_tx[q] % priv->num_tx_ring[q]; - priv->tx_skb[q][entry] = skb; + entry = priv->cur_tx[q] % (priv->num_tx_ring[q] * NUM_TX_DESC); + priv->tx_skb[q][entry / NUM_TX_DESC] = skb; if (skb_put_padto(skb, ETH_ZLEN)) goto drop; - buffer = PTR_ALIGN(priv->tx_buffers[q][entry], RAVB_ALIGN); - memcpy(buffer, skb->data, skb->len); - desc = &priv->tx_ring[q][entry]; - desc->ds_tagl = cpu_to_le16(skb->len); - dma_addr = dma_map_single(&ndev->dev, buffer, skb->len, DMA_TO_DEVICE); + buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) + + entry / NUM_TX_DESC * DPTR_ALIGN; + len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data; + memcpy(buffer, skb->data, len); + dma_addr = dma_map_single(&ndev->dev, buffer, len, DMA_TO_DEVICE); if (dma_mapping_error(&ndev->dev, dma_addr)) goto drop; + + desc = &priv->tx_ring[q][entry]; + desc->ds_tagl = cpu_to_le16(len); + desc->dptr = cpu_to_le32(dma_addr); + + buffer = skb->data + len; + len = skb->len - len; + dma_addr = dma_map_single(&ndev->dev, buffer, len, DMA_TO_DEVICE); + if (dma_mapping_error(&ndev->dev, dma_addr)) + goto unmap; + + desc++; + desc->ds_tagl = cpu_to_le16(len); desc->dptr = cpu_to_le32(dma_addr); /* TX timestamp required */ if (q == RAVB_NC) { ts_skb = kmalloc(sizeof(*ts_skb), GFP_ATOMIC); if (!ts_skb) { - dma_unmap_single(&ndev->dev, dma_addr, skb->len, + desc--; + dma_unmap_single(&ndev->dev, dma_addr, len, DMA_TO_DEVICE); - goto drop; + goto unmap; } ts_skb->skb = skb; ts_skb->tag = priv->ts_skb_tag++; @@ -1330,13 +1341,15 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* Descriptor type must be set after all the above writes */ dma_wmb(); - desc->die_dt = DT_FSINGLE; + desc->die_dt = DT_FEND; + desc--; + desc->die_dt = DT_FSTART; ravb_write(ndev, ravb_read(ndev, TCCR) | (TCCR_TSRQ0 << q), TCCR); - priv->cur_tx[q]++; - if (priv->cur_tx[q] - priv->dirty_tx[q] >= priv->num_tx_ring[q] && - !ravb_tx_free(ndev, q)) + priv->cur_tx[q] += NUM_TX_DESC; + if (priv->cur_tx[q] - priv->dirty_tx[q] > + (priv->num_tx_ring[q] - 1) * NUM_TX_DESC && !ravb_tx_free(ndev, q)) netif_stop_subqueue(ndev, q); exit: @@ -1344,9 +1357,12 @@ exit: spin_unlock_irqrestore(&priv->lock, flags); return NETDEV_TX_OK; +unmap: + dma_unmap_single(&ndev->dev, le32_to_cpu(desc->dptr), + le16_to_cpu(desc->ds_tagl), DMA_TO_DEVICE); drop: dev_kfree_skb_any(skb); - priv->tx_skb[q][entry] = NULL; + priv->tx_skb[q][entry / NUM_TX_DESC] = NULL; goto exit; } -- cgit v1.3-6-gb490 From 042794b1f4234de36ce2d6edae071054c6985a03 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Jul 2015 13:55:10 +0200 Subject: drm/i915: Clean up Makefile Sorting became confused and a few new files ended up in strange places. Also move i915_irq.c to core since with the recent-ish extraction of i915_gpu_error.c and intel_hotplug.c it's more and more really just basic irq handling code. When adding new files please don't put them somewhere randomly. Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index e52e01251644..bf91482e14a3 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -6,12 +6,13 @@ # core driver code i915-y := i915_drv.o \ + i915_irq.o \ i915_params.o \ i915_suspend.o \ i915_sysfs.o \ + intel_csr.o \ intel_pm.o \ - intel_runtime_pm.o \ - intel_csr.o + intel_runtime_pm.o i915-$(CONFIG_COMPAT) += i915_ioc32.o i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o @@ -20,21 +21,19 @@ i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o i915-y += i915_cmd_parser.o \ i915_gem_batch_pool.o \ i915_gem_context.o \ - i915_gem_render_state.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_render_state.o \ i915_gem_shrinker.o \ i915_gem_stolen.o \ i915_gem_tiling.o \ i915_gem_userptr.o \ i915_gpu_error.o \ - i915_irq.o \ i915_trace_points.o \ - intel_hotplug.o \ intel_lrc.o \ intel_mocs.o \ intel_ringbuffer.o \ @@ -48,11 +47,14 @@ i915-y += intel_renderstate_gen6.o \ # modesetting core code i915-y += intel_audio.o \ + intel_atomic.o \ + intel_atomic_plane.o \ intel_bios.o \ intel_display.o \ intel_fbc.o \ intel_fifo_underrun.o \ intel_frontbuffer.o \ + intel_hotplug.o \ intel_modes.o \ intel_overlay.o \ intel_psr.o \ @@ -68,15 +70,13 @@ i915-y += dvo_ch7017.o \ dvo_ns2501.o \ dvo_sil164.o \ dvo_tfp410.o \ - intel_atomic.o \ - intel_atomic_plane.o \ intel_crt.o \ intel_ddi.o \ - intel_dp.o \ intel_dp_mst.o \ + intel_dp.o \ intel_dsi.o \ - intel_dsi_pll.o \ intel_dsi_panel_vbt.o \ + intel_dsi_pll.o \ intel_dvo.o \ intel_hdmi.o \ intel_i2c.o \ -- cgit v1.3-6-gb490 From 41a36b739ae378043ecc3984bec3dba00353fa34 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Jul 2015 13:55:11 +0200 Subject: drm/i915: Extract i915_gem_fence.c No code changes, just moving all the fence related code into a separate file (and avoiding a bunch of forward declarations while at it). Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.h | 16 +- drivers/gpu/drm/i915/i915_gem.c | 401 -------------------------------- drivers/gpu/drm/i915/i915_gem_fence.c | 422 ++++++++++++++++++++++++++++++++++ 4 files changed, 432 insertions(+), 408 deletions(-) create mode 100644 drivers/gpu/drm/i915/i915_gem_fence.c (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index bf91482e14a3..41fb8a9c5bef 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -25,6 +25,7 @@ i915-y += i915_cmd_parser.o \ i915_gem_dmabuf.o \ i915_gem_evict.o \ i915_gem_execbuffer.o \ + i915_gem_fence.o \ i915_gem_gtt.o \ i915_gem.o \ i915_gem_render_state.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b94ada96b348..d575029af541 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2868,11 +2868,6 @@ static inline bool i915_gem_request_completed(struct drm_i915_gem_request *req, int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno); int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno); -int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj); -int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); - -bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj); -void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj); struct drm_i915_gem_request * i915_gem_find_active_request(struct intel_engine_cs *ring); @@ -2970,8 +2965,6 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, struct dma_buf *i915_gem_prime_export(struct drm_device *dev, struct drm_gem_object *gem_obj, int flags); -void i915_gem_restore_fences(struct drm_device *dev); - unsigned long i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o, const struct i915_ggtt_view *view); @@ -3066,6 +3059,15 @@ i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj) i915_gem_object_ggtt_unpin_view(obj, &i915_ggtt_view_normal); } +/* i915_gem_fence.c */ +int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj); +int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); + +bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj); +void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj); + +void i915_gem_restore_fences(struct drm_device *dev); + /* i915_gem_context.c */ int __must_check i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 322bbefafbc3..5d685789b1f9 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -46,11 +46,6 @@ static void i915_gem_object_retire__write(struct drm_i915_gem_object *obj); static void i915_gem_object_retire__read(struct drm_i915_gem_object *obj, int ring); -static void i915_gem_write_fence(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj); -static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, - struct drm_i915_fence_reg *fence, - bool enable); static bool cpu_cache_is_coherent(struct drm_device *dev, enum i915_cache_level level) @@ -66,18 +61,6 @@ static bool cpu_write_needs_clflush(struct drm_i915_gem_object *obj) return obj->pin_display; } -static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj) -{ - if (obj->tiling_mode) - i915_gem_release_mmap(obj); - - /* As we do not have an associated fence register, we will force - * a tiling change if we ever need to acquire one. - */ - obj->fence_dirty = false; - obj->fence_reg = I915_FENCE_REG_NONE; -} - /* some bookkeeping */ static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv, size_t size) @@ -2793,27 +2776,6 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, } } -void i915_gem_restore_fences(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - - for (i = 0; i < dev_priv->num_fence_regs; i++) { - struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; - - /* - * Commit delayed tiling changes if we have an object still - * attached to the fence, otherwise just clear the fence. - */ - if (reg->obj) { - i915_gem_object_update_fence(reg->obj, reg, - reg->obj->tiling_mode); - } else { - i915_gem_write_fence(dev, i, NULL); - } - } -} - void i915_gem_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3340,343 +3302,6 @@ int i915_gpu_idle(struct drm_device *dev) return 0; } -static void i965_write_fence_reg(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int fence_reg; - int fence_pitch_shift; - - if (INTEL_INFO(dev)->gen >= 6) { - fence_reg = FENCE_REG_SANDYBRIDGE_0; - fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT; - } else { - fence_reg = FENCE_REG_965_0; - fence_pitch_shift = I965_FENCE_PITCH_SHIFT; - } - - fence_reg += reg * 8; - - /* To w/a incoherency with non-atomic 64-bit register updates, - * we split the 64-bit update into two 32-bit writes. In order - * for a partial fence not to be evaluated between writes, we - * precede the update with write to turn off the fence register, - * and only enable the fence as the last step. - * - * For extra levels of paranoia, we make sure each step lands - * before applying the next step. - */ - I915_WRITE(fence_reg, 0); - POSTING_READ(fence_reg); - - if (obj) { - u32 size = i915_gem_obj_ggtt_size(obj); - uint64_t val; - - /* Adjust fence size to match tiled area */ - if (obj->tiling_mode != I915_TILING_NONE) { - uint32_t row_size = obj->stride * - (obj->tiling_mode == I915_TILING_Y ? 32 : 8); - size = (size / row_size) * row_size; - } - - val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) & - 0xfffff000) << 32; - val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000; - val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift; - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I965_FENCE_TILING_Y_SHIFT; - val |= I965_FENCE_REG_VALID; - - I915_WRITE(fence_reg + 4, val >> 32); - POSTING_READ(fence_reg + 4); - - I915_WRITE(fence_reg + 0, val); - POSTING_READ(fence_reg); - } else { - I915_WRITE(fence_reg + 4, 0); - POSTING_READ(fence_reg + 4); - } -} - -static void i915_write_fence_reg(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 val; - - if (obj) { - u32 size = i915_gem_obj_ggtt_size(obj); - int pitch_val; - int tile_width; - - WARN((i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) || - (size & -size) != size || - (i915_gem_obj_ggtt_offset(obj) & (size - 1)), - "object 0x%08lx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n", - i915_gem_obj_ggtt_offset(obj), obj->map_and_fenceable, size); - - if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) - tile_width = 128; - else - tile_width = 512; - - /* Note: pitch better be a power of two tile widths */ - pitch_val = obj->stride / tile_width; - pitch_val = ffs(pitch_val) - 1; - - val = i915_gem_obj_ggtt_offset(obj); - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I830_FENCE_TILING_Y_SHIFT; - val |= I915_FENCE_SIZE_BITS(size); - val |= pitch_val << I830_FENCE_PITCH_SHIFT; - val |= I830_FENCE_REG_VALID; - } else - val = 0; - - if (reg < 8) - reg = FENCE_REG_830_0 + reg * 4; - else - reg = FENCE_REG_945_8 + (reg - 8) * 4; - - I915_WRITE(reg, val); - POSTING_READ(reg); -} - -static void i830_write_fence_reg(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t val; - - if (obj) { - u32 size = i915_gem_obj_ggtt_size(obj); - uint32_t pitch_val; - - WARN((i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) || - (size & -size) != size || - (i915_gem_obj_ggtt_offset(obj) & (size - 1)), - "object 0x%08lx not 512K or pot-size 0x%08x aligned\n", - i915_gem_obj_ggtt_offset(obj), size); - - pitch_val = obj->stride / 128; - pitch_val = ffs(pitch_val) - 1; - - val = i915_gem_obj_ggtt_offset(obj); - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I830_FENCE_TILING_Y_SHIFT; - val |= I830_FENCE_SIZE_BITS(size); - val |= pitch_val << I830_FENCE_PITCH_SHIFT; - val |= I830_FENCE_REG_VALID; - } else - val = 0; - - I915_WRITE(FENCE_REG_830_0 + reg * 4, val); - POSTING_READ(FENCE_REG_830_0 + reg * 4); -} - -inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj) -{ - return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT; -} - -static void i915_gem_write_fence(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* Ensure that all CPU reads are completed before installing a fence - * and all writes before removing the fence. - */ - if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj)) - mb(); - - WARN(obj && (!obj->stride || !obj->tiling_mode), - "bogus fence setup with stride: 0x%x, tiling mode: %i\n", - obj->stride, obj->tiling_mode); - - if (IS_GEN2(dev)) - i830_write_fence_reg(dev, reg, obj); - else if (IS_GEN3(dev)) - i915_write_fence_reg(dev, reg, obj); - else if (INTEL_INFO(dev)->gen >= 4) - i965_write_fence_reg(dev, reg, obj); - - /* And similarly be paranoid that no direct access to this region - * is reordered to before the fence is installed. - */ - if (i915_gem_object_needs_mb(obj)) - mb(); -} - -static inline int fence_number(struct drm_i915_private *dev_priv, - struct drm_i915_fence_reg *fence) -{ - return fence - dev_priv->fence_regs; -} - -static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, - struct drm_i915_fence_reg *fence, - bool enable) -{ - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - int reg = fence_number(dev_priv, fence); - - i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); - - if (enable) { - obj->fence_reg = reg; - fence->obj = obj; - list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); - } else { - obj->fence_reg = I915_FENCE_REG_NONE; - fence->obj = NULL; - list_del_init(&fence->lru_list); - } - obj->fence_dirty = false; -} - -static int -i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) -{ - if (obj->last_fenced_req) { - int ret = i915_wait_request(obj->last_fenced_req); - if (ret) - return ret; - - i915_gem_request_assign(&obj->last_fenced_req, NULL); - } - - return 0; -} - -int -i915_gem_object_put_fence(struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - struct drm_i915_fence_reg *fence; - int ret; - - ret = i915_gem_object_wait_fence(obj); - if (ret) - return ret; - - if (obj->fence_reg == I915_FENCE_REG_NONE) - return 0; - - fence = &dev_priv->fence_regs[obj->fence_reg]; - - if (WARN_ON(fence->pin_count)) - return -EBUSY; - - i915_gem_object_fence_lost(obj); - i915_gem_object_update_fence(obj, fence, false); - - return 0; -} - -static struct drm_i915_fence_reg * -i915_find_fence_reg(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_fence_reg *reg, *avail; - int i; - - /* First try to find a free reg */ - avail = NULL; - for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { - reg = &dev_priv->fence_regs[i]; - if (!reg->obj) - return reg; - - if (!reg->pin_count) - avail = reg; - } - - if (avail == NULL) - goto deadlock; - - /* None available, try to steal one or wait for a user to finish */ - list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { - if (reg->pin_count) - continue; - - return reg; - } - -deadlock: - /* Wait for completion of pending flips which consume fences */ - if (intel_has_pending_fb_unpin(dev)) - return ERR_PTR(-EAGAIN); - - return ERR_PTR(-EDEADLK); -} - -/** - * i915_gem_object_get_fence - set up fencing for an object - * @obj: object to map through a fence reg - * - * When mapping objects through the GTT, userspace wants to be able to write - * to them without having to worry about swizzling if the object is tiled. - * This function walks the fence regs looking for a free one for @obj, - * stealing one if it can't find any. - * - * It then sets up the reg based on the object's properties: address, pitch - * and tiling format. - * - * For an untiled surface, this removes any existing fence. - */ -int -i915_gem_object_get_fence(struct drm_i915_gem_object *obj) -{ - struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - bool enable = obj->tiling_mode != I915_TILING_NONE; - struct drm_i915_fence_reg *reg; - int ret; - - /* Have we updated the tiling parameters upon the object and so - * will need to serialise the write to the associated fence register? - */ - if (obj->fence_dirty) { - ret = i915_gem_object_wait_fence(obj); - if (ret) - return ret; - } - - /* Just update our place in the LRU if our fence is getting reused. */ - if (obj->fence_reg != I915_FENCE_REG_NONE) { - reg = &dev_priv->fence_regs[obj->fence_reg]; - if (!obj->fence_dirty) { - list_move_tail(®->lru_list, - &dev_priv->mm.fence_list); - return 0; - } - } else if (enable) { - if (WARN_ON(!obj->map_and_fenceable)) - return -EINVAL; - - reg = i915_find_fence_reg(dev); - if (IS_ERR(reg)) - return PTR_ERR(reg); - - if (reg->obj) { - struct drm_i915_gem_object *old = reg->obj; - - ret = i915_gem_object_wait_fence(old); - if (ret) - return ret; - - i915_gem_object_fence_lost(old); - } - } else - return 0; - - i915_gem_object_update_fence(obj, reg, enable); - - return 0; -} - static bool i915_gem_valid_gtt_space(struct i915_vma *vma, unsigned long cache_level) { @@ -4476,32 +4101,6 @@ i915_gem_object_ggtt_unpin_view(struct drm_i915_gem_object *obj, --vma->pin_count; } -bool -i915_gem_object_pin_fence(struct drm_i915_gem_object *obj) -{ - if (obj->fence_reg != I915_FENCE_REG_NONE) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - struct i915_vma *ggtt_vma = i915_gem_obj_to_ggtt(obj); - - WARN_ON(!ggtt_vma || - dev_priv->fence_regs[obj->fence_reg].pin_count > - ggtt_vma->pin_count); - dev_priv->fence_regs[obj->fence_reg].pin_count++; - return true; - } else - return false; -} - -void -i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) -{ - if (obj->fence_reg != I915_FENCE_REG_NONE) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count <= 0); - dev_priv->fence_regs[obj->fence_reg].pin_count--; - } -} - int i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_file *file) diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c new file mode 100644 index 000000000000..d3284ee04794 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -0,0 +1,422 @@ +/* + * Copyright © 2008-2015 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. + */ + +#include +#include +#include "i915_drv.h" + +static void i965_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int fence_reg; + int fence_pitch_shift; + + if (INTEL_INFO(dev)->gen >= 6) { + fence_reg = FENCE_REG_SANDYBRIDGE_0; + fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT; + } else { + fence_reg = FENCE_REG_965_0; + fence_pitch_shift = I965_FENCE_PITCH_SHIFT; + } + + fence_reg += reg * 8; + + /* To w/a incoherency with non-atomic 64-bit register updates, + * we split the 64-bit update into two 32-bit writes. In order + * for a partial fence not to be evaluated between writes, we + * precede the update with write to turn off the fence register, + * and only enable the fence as the last step. + * + * For extra levels of paranoia, we make sure each step lands + * before applying the next step. + */ + I915_WRITE(fence_reg, 0); + POSTING_READ(fence_reg); + + if (obj) { + u32 size = i915_gem_obj_ggtt_size(obj); + uint64_t val; + + /* Adjust fence size to match tiled area */ + if (obj->tiling_mode != I915_TILING_NONE) { + uint32_t row_size = obj->stride * + (obj->tiling_mode == I915_TILING_Y ? 32 : 8); + size = (size / row_size) * row_size; + } + + val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) & + 0xfffff000) << 32; + val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000; + val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift; + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I965_FENCE_TILING_Y_SHIFT; + val |= I965_FENCE_REG_VALID; + + I915_WRITE(fence_reg + 4, val >> 32); + POSTING_READ(fence_reg + 4); + + I915_WRITE(fence_reg + 0, val); + POSTING_READ(fence_reg); + } else { + I915_WRITE(fence_reg + 4, 0); + POSTING_READ(fence_reg + 4); + } +} + +static void i915_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + if (obj) { + u32 size = i915_gem_obj_ggtt_size(obj); + int pitch_val; + int tile_width; + + WARN((i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) || + (size & -size) != size || + (i915_gem_obj_ggtt_offset(obj) & (size - 1)), + "object 0x%08lx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n", + i915_gem_obj_ggtt_offset(obj), obj->map_and_fenceable, size); + + if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) + tile_width = 128; + else + tile_width = 512; + + /* Note: pitch better be a power of two tile widths */ + pitch_val = obj->stride / tile_width; + pitch_val = ffs(pitch_val) - 1; + + val = i915_gem_obj_ggtt_offset(obj); + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I830_FENCE_TILING_Y_SHIFT; + val |= I915_FENCE_SIZE_BITS(size); + val |= pitch_val << I830_FENCE_PITCH_SHIFT; + val |= I830_FENCE_REG_VALID; + } else + val = 0; + + if (reg < 8) + reg = FENCE_REG_830_0 + reg * 4; + else + reg = FENCE_REG_945_8 + (reg - 8) * 4; + + I915_WRITE(reg, val); + POSTING_READ(reg); +} + +static void i830_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t val; + + if (obj) { + u32 size = i915_gem_obj_ggtt_size(obj); + uint32_t pitch_val; + + WARN((i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) || + (size & -size) != size || + (i915_gem_obj_ggtt_offset(obj) & (size - 1)), + "object 0x%08lx not 512K or pot-size 0x%08x aligned\n", + i915_gem_obj_ggtt_offset(obj), size); + + pitch_val = obj->stride / 128; + pitch_val = ffs(pitch_val) - 1; + + val = i915_gem_obj_ggtt_offset(obj); + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I830_FENCE_TILING_Y_SHIFT; + val |= I830_FENCE_SIZE_BITS(size); + val |= pitch_val << I830_FENCE_PITCH_SHIFT; + val |= I830_FENCE_REG_VALID; + } else + val = 0; + + I915_WRITE(FENCE_REG_830_0 + reg * 4, val); + POSTING_READ(FENCE_REG_830_0 + reg * 4); +} + +inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj) +{ + return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT; +} + +static void i915_gem_write_fence(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Ensure that all CPU reads are completed before installing a fence + * and all writes before removing the fence. + */ + if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj)) + mb(); + + WARN(obj && (!obj->stride || !obj->tiling_mode), + "bogus fence setup with stride: 0x%x, tiling mode: %i\n", + obj->stride, obj->tiling_mode); + + if (IS_GEN2(dev)) + i830_write_fence_reg(dev, reg, obj); + else if (IS_GEN3(dev)) + i915_write_fence_reg(dev, reg, obj); + else if (INTEL_INFO(dev)->gen >= 4) + i965_write_fence_reg(dev, reg, obj); + + /* And similarly be paranoid that no direct access to this region + * is reordered to before the fence is installed. + */ + if (i915_gem_object_needs_mb(obj)) + mb(); +} + +static inline int fence_number(struct drm_i915_private *dev_priv, + struct drm_i915_fence_reg *fence) +{ + return fence - dev_priv->fence_regs; +} + +static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, + struct drm_i915_fence_reg *fence, + bool enable) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + int reg = fence_number(dev_priv, fence); + + i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); + + if (enable) { + obj->fence_reg = reg; + fence->obj = obj; + list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); + } else { + obj->fence_reg = I915_FENCE_REG_NONE; + fence->obj = NULL; + list_del_init(&fence->lru_list); + } + obj->fence_dirty = false; +} + +static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj) +{ + if (obj->tiling_mode) + i915_gem_release_mmap(obj); + + /* As we do not have an associated fence register, we will force + * a tiling change if we ever need to acquire one. + */ + obj->fence_dirty = false; + obj->fence_reg = I915_FENCE_REG_NONE; +} + +static int +i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) +{ + if (obj->last_fenced_req) { + int ret = i915_wait_request(obj->last_fenced_req); + if (ret) + return ret; + + i915_gem_request_assign(&obj->last_fenced_req, NULL); + } + + return 0; +} + +int +i915_gem_object_put_fence(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + struct drm_i915_fence_reg *fence; + int ret; + + ret = i915_gem_object_wait_fence(obj); + if (ret) + return ret; + + if (obj->fence_reg == I915_FENCE_REG_NONE) + return 0; + + fence = &dev_priv->fence_regs[obj->fence_reg]; + + if (WARN_ON(fence->pin_count)) + return -EBUSY; + + i915_gem_object_fence_lost(obj); + i915_gem_object_update_fence(obj, fence, false); + + return 0; +} + +static struct drm_i915_fence_reg * +i915_find_fence_reg(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_fence_reg *reg, *avail; + int i; + + /* First try to find a free reg */ + avail = NULL; + for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { + reg = &dev_priv->fence_regs[i]; + if (!reg->obj) + return reg; + + if (!reg->pin_count) + avail = reg; + } + + if (avail == NULL) + goto deadlock; + + /* None available, try to steal one or wait for a user to finish */ + list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { + if (reg->pin_count) + continue; + + return reg; + } + +deadlock: + /* Wait for completion of pending flips which consume fences */ + if (intel_has_pending_fb_unpin(dev)) + return ERR_PTR(-EAGAIN); + + return ERR_PTR(-EDEADLK); +} + +/** + * i915_gem_object_get_fence - set up fencing for an object + * @obj: object to map through a fence reg + * + * When mapping objects through the GTT, userspace wants to be able to write + * to them without having to worry about swizzling if the object is tiled. + * This function walks the fence regs looking for a free one for @obj, + * stealing one if it can't find any. + * + * It then sets up the reg based on the object's properties: address, pitch + * and tiling format. + * + * For an untiled surface, this removes any existing fence. + */ +int +i915_gem_object_get_fence(struct drm_i915_gem_object *obj) +{ + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + bool enable = obj->tiling_mode != I915_TILING_NONE; + struct drm_i915_fence_reg *reg; + int ret; + + /* Have we updated the tiling parameters upon the object and so + * will need to serialise the write to the associated fence register? + */ + if (obj->fence_dirty) { + ret = i915_gem_object_wait_fence(obj); + if (ret) + return ret; + } + + /* Just update our place in the LRU if our fence is getting reused. */ + if (obj->fence_reg != I915_FENCE_REG_NONE) { + reg = &dev_priv->fence_regs[obj->fence_reg]; + if (!obj->fence_dirty) { + list_move_tail(®->lru_list, + &dev_priv->mm.fence_list); + return 0; + } + } else if (enable) { + if (WARN_ON(!obj->map_and_fenceable)) + return -EINVAL; + + reg = i915_find_fence_reg(dev); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + if (reg->obj) { + struct drm_i915_gem_object *old = reg->obj; + + ret = i915_gem_object_wait_fence(old); + if (ret) + return ret; + + i915_gem_object_fence_lost(old); + } + } else + return 0; + + i915_gem_object_update_fence(obj, reg, enable); + + return 0; +} + +bool +i915_gem_object_pin_fence(struct drm_i915_gem_object *obj) +{ + if (obj->fence_reg != I915_FENCE_REG_NONE) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + struct i915_vma *ggtt_vma = i915_gem_obj_to_ggtt(obj); + + WARN_ON(!ggtt_vma || + dev_priv->fence_regs[obj->fence_reg].pin_count > + ggtt_vma->pin_count); + dev_priv->fence_regs[obj->fence_reg].pin_count++; + return true; + } else + return false; +} + +void +i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) +{ + if (obj->fence_reg != I915_FENCE_REG_NONE) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count <= 0); + dev_priv->fence_regs[obj->fence_reg].pin_count--; + } +} + +void i915_gem_restore_fences(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < dev_priv->num_fence_regs; i++) { + struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; + + /* + * Commit delayed tiling changes if we have an object still + * attached to the fence, otherwise just clear the fence. + */ + if (reg->obj) { + i915_gem_object_update_fence(reg->obj, reg, + reg->obj->tiling_mode); + } else { + i915_gem_write_fence(dev, i, NULL); + } + } +} -- cgit v1.3-6-gb490 From a794f62a300194dbc53165f10cc5ad236a6a43c2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Jul 2015 17:40:12 +0200 Subject: drm/i915: kerneldoc for fences v2: Clarify that this is about fence _registers_. Also clarify that the fence code revokes cpu ptes and not gtt ptes. Both suggested by Chris. Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 5 +++ drivers/gpu/drm/i915/i915_gem_fence.c | 75 +++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) (limited to 'drivers') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 1ca1171b16e5..ee2ed7ed27d1 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4197,6 +4197,11 @@ int num_ioctls; Global GTT views !Pdrivers/gpu/drm/i915/i915_gem_gtt.c Global GTT views !Idrivers/gpu/drm/i915/i915_gem_gtt.c + + + Global GTT Fence Handling +!Pdrivers/gpu/drm/i915/i915_gem_fence.c fence register handling +!Idrivers/gpu/drm/i915/i915_gem_fence.c Buffer Object Eviction diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c index d3284ee04794..0434c42d8c11 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -25,6 +25,36 @@ #include #include "i915_drv.h" +/** + * DOC: fence register handling + * + * Important to avoid confusions: "fences" in the i915 driver are not execution + * fences used to track command completion but hardware detiler objects which + * wrap a given range of the global GTT. Each platform has only a fairly limited + * set of these objects. + * + * Fences are used to detile GTT memory mappings. They're also connected to the + * hardware frontbuffer render tracking and hence interract with frontbuffer + * conmpression. Furthermore on older platforms fences are required for tiled + * objects used by the display engine. They can also be used by the render + * engine - they're required for blitter commands and are optional for render + * commands. But on gen4+ both display (with the exception of fbc) and rendering + * have their own tiling state bits and don't need fences. + * + * Also note that fences only support X and Y tiling and hence can't be used for + * the fancier new tiling formats like W, Ys and Yf. + * + * Finally note that because fences are such a restricted resource they're + * dynamically associated with objects. Furthermore fence state is committed to + * the hardware lazily to avoid unecessary stalls on gen2/3. Therefore code must + * explictly call i915_gem_object_get_fence() to synchronize fencing status + * for cpu access. Also note that some code wants an unfenced view, for those + * cases the fence can be removed forcefully with i915_gem_object_put_fence(). + * + * Internally these functions will synchronize with userspace access by removing + * CPU ptes into GTT mmaps (not the GTT ptes themselves) as needed. + */ + static void i965_write_fence_reg(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { @@ -247,6 +277,17 @@ i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) return 0; } +/** + * i915_gem_object_put_fence - force-remove fence for an object + * @obj: object to map through a fence reg + * + * This function force-removes any fence from the given object, which is useful + * if the kernel wants to do untiled GTT access. + * + * Returns: + * + * 0 on success, negative error code on failure. + */ int i915_gem_object_put_fence(struct drm_i915_gem_object *obj) { @@ -322,6 +363,10 @@ deadlock: * and tiling format. * * For an untiled surface, this removes any existing fence. + * + * Returns: + * + * 0 on success, negative error code on failure. */ int i915_gem_object_get_fence(struct drm_i915_gem_object *obj) @@ -374,6 +419,21 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) return 0; } +/** + * i915_gem_object_pin_fence - pin fencing state + * @obj: object to pin fencing for + * + * This pins the fencing state (whether tiled or untiled) to make sure the + * object is ready to be used as a scanout target. Fencing status must be + * synchronize first by calling i915_gem_object_get_fence(): + * + * The resulting fence pin reference must be released again with + * i915_gem_object_unpin_fence(). + * + * Returns: + * + * True if the object has a fence, false otherwise. + */ bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj) { @@ -390,6 +450,14 @@ i915_gem_object_pin_fence(struct drm_i915_gem_object *obj) return false; } +/** + * i915_gem_object_unpin_fence - unpin fencing state + * @obj: object to unpin fencing for + * + * This releases the fence pin reference acquired through + * i915_gem_object_pin_fence. It will handle both objects with and without an + * attached fence correctly, callers do not need to distinguish this. + */ void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) { @@ -400,6 +468,13 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) } } +/** + * i915_gem_restore_fences - restore fence state + * @dev: DRM device + * + * Restore the hw fence state to match the software tracking again, to be called + * after a gpu reset and on resume. + */ void i915_gem_restore_fences(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; -- cgit v1.3-6-gb490 From 7f96ecaf1ea26fd7041acc56379a5c4393ee51ad Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Jul 2015 17:40:14 +0200 Subject: drm/i915: Move low-level swizzling code to i915_gem_fence.c It fits more with the low-level fence code, and this move leaves only the userspace tiling ioctl handling in i915_gem_tiling.c. Suggested-by: Chris Wilson Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 8 +- drivers/gpu/drm/i915/i915_gem_fence.c | 268 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_gem_tiling.c | 219 --------------------------- 3 files changed, 272 insertions(+), 223 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d575029af541..40fea41affc9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3068,6 +3068,10 @@ void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj); void i915_gem_restore_fences(struct drm_device *dev); +void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); +void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj); +void i915_gem_object_save_bit_17_swizzle(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); @@ -3160,10 +3164,6 @@ static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_objec obj->tiling_mode != I915_TILING_NONE; } -void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); -void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj); -void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj); - /* i915_gem_debug.c */ #if WATCH_LISTS int i915_verify_lists(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c index 0434c42d8c11..c643260a90c5 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -495,3 +495,271 @@ void i915_gem_restore_fences(struct drm_device *dev) } } } + +/** + * + * Support for managing tiling state of buffer objects. + * + * The idea behind tiling is to increase cache hit rates by rearranging + * pixel data so that a group of pixel accesses are in the same cacheline. + * Performance improvement from doing this on the back/depth buffer are on + * the order of 30%. + * + * Intel architectures make this somewhat more complicated, though, by + * adjustments made to addressing of data when the memory is in interleaved + * mode (matched pairs of DIMMS) to improve memory bandwidth. + * For interleaved memory, the CPU sends every sequential 64 bytes + * to an alternate memory channel so it can get the bandwidth from both. + * + * The GPU also rearranges its accesses for increased bandwidth to interleaved + * memory, and it matches what the CPU does for non-tiled. However, when tiled + * it does it a little differently, since one walks addresses not just in the + * X direction but also Y. So, along with alternating channels when bit + * 6 of the address flips, it also alternates when other bits flip -- Bits 9 + * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines) + * are common to both the 915 and 965-class hardware. + * + * The CPU also sometimes XORs in higher bits as well, to improve + * bandwidth doing strided access like we do so frequently in graphics. This + * is called "Channel XOR Randomization" in the MCH documentation. The result + * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address + * decode. + * + * All of this bit 6 XORing has an effect on our memory management, + * as we need to make sure that the 3d driver can correctly address object + * contents. + * + * If we don't have interleaved memory, all tiling is safe and no swizzling is + * required. + * + * When bit 17 is XORed in, we simply refuse to tile at all. Bit + * 17 is not just a page offset, so as we page an objet out and back in, + * individual pages in it will have different bit 17 addresses, resulting in + * each 64 bytes being swapped with its neighbor! + * + * Otherwise, if interleaved, we have to tell the 3d driver what the address + * swizzling it needs to do is, since it's writing with the CPU to the pages + * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the + * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling + * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order + * to match what the GPU expects. + */ + +/** + * Detects bit 6 swizzling of address lookup between IGD access and CPU + * access through main memory. + */ +void +i915_gem_detect_bit_6_swizzle(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; + uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; + + if (INTEL_INFO(dev)->gen >= 8 || IS_VALLEYVIEW(dev)) { + /* + * On BDW+, swizzling is not used. We leave the CPU memory + * controller in charge of optimizing memory accesses without + * the extra address manipulation GPU side. + * + * VLV and CHV don't have GPU swizzling. + */ + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } else if (INTEL_INFO(dev)->gen >= 6) { + if (dev_priv->preserve_bios_swizzle) { + if (I915_READ(DISP_ARB_CTL) & + DISP_TILE_SURFACE_SWIZZLING) { + swizzle_x = I915_BIT_6_SWIZZLE_9_10; + swizzle_y = I915_BIT_6_SWIZZLE_9; + } else { + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } + } else { + uint32_t dimm_c0, dimm_c1; + dimm_c0 = I915_READ(MAD_DIMM_C0); + dimm_c1 = I915_READ(MAD_DIMM_C1); + dimm_c0 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK; + dimm_c1 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK; + /* Enable swizzling when the channels are populated + * with identically sized dimms. We don't need to check + * the 3rd channel because no cpu with gpu attached + * ships in that configuration. Also, swizzling only + * makes sense for 2 channels anyway. */ + if (dimm_c0 == dimm_c1) { + swizzle_x = I915_BIT_6_SWIZZLE_9_10; + swizzle_y = I915_BIT_6_SWIZZLE_9; + } else { + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } + } + } else if (IS_GEN5(dev)) { + /* On Ironlake whatever DRAM config, GPU always do + * same swizzling setup. + */ + swizzle_x = I915_BIT_6_SWIZZLE_9_10; + swizzle_y = I915_BIT_6_SWIZZLE_9; + } else if (IS_GEN2(dev)) { + /* As far as we know, the 865 doesn't have these bit 6 + * swizzling issues. + */ + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } else if (IS_MOBILE(dev) || (IS_GEN3(dev) && !IS_G33(dev))) { + uint32_t dcc; + + /* On 9xx chipsets, channel interleave by the CPU is + * determined by DCC. For single-channel, neither the CPU + * nor the GPU do swizzling. For dual channel interleaved, + * the GPU's interleave is bit 9 and 10 for X tiled, and bit + * 9 for Y tiled. The CPU's interleave is independent, and + * can be based on either bit 11 (haven't seen this yet) or + * bit 17 (common). + */ + dcc = I915_READ(DCC); + switch (dcc & DCC_ADDRESSING_MODE_MASK) { + case DCC_ADDRESSING_MODE_SINGLE_CHANNEL: + case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC: + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + break; + case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED: + if (dcc & DCC_CHANNEL_XOR_DISABLE) { + /* This is the base swizzling by the GPU for + * tiled buffers. + */ + swizzle_x = I915_BIT_6_SWIZZLE_9_10; + swizzle_y = I915_BIT_6_SWIZZLE_9; + } else if ((dcc & DCC_CHANNEL_XOR_BIT_17) == 0) { + /* Bit 11 swizzling by the CPU in addition. */ + swizzle_x = I915_BIT_6_SWIZZLE_9_10_11; + swizzle_y = I915_BIT_6_SWIZZLE_9_11; + } else { + /* Bit 17 swizzling by the CPU in addition. */ + swizzle_x = I915_BIT_6_SWIZZLE_9_10_17; + swizzle_y = I915_BIT_6_SWIZZLE_9_17; + } + break; + } + + /* check for L-shaped memory aka modified enhanced addressing */ + if (IS_GEN4(dev)) { + uint32_t ddc2 = I915_READ(DCC2); + + if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE)) + dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; + } + + if (dcc == 0xffffffff) { + DRM_ERROR("Couldn't read from MCHBAR. " + "Disabling tiling.\n"); + swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; + swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; + } + } else { + /* The 965, G33, and newer, have a very flexible memory + * configuration. It will enable dual-channel mode + * (interleaving) on as much memory as it can, and the GPU + * will additionally sometimes enable different bit 6 + * swizzling for tiled objects from the CPU. + * + * Here's what I found on the G965: + * slot fill memory size swizzling + * 0A 0B 1A 1B 1-ch 2-ch + * 512 0 0 0 512 0 O + * 512 0 512 0 16 1008 X + * 512 0 0 512 16 1008 X + * 0 512 0 512 16 1008 X + * 1024 1024 1024 0 2048 1024 O + * + * We could probably detect this based on either the DRB + * matching, which was the case for the swizzling required in + * the table above, or from the 1-ch value being less than + * the minimum size of a rank. + */ + if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) { + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } else { + swizzle_x = I915_BIT_6_SWIZZLE_9_10; + swizzle_y = I915_BIT_6_SWIZZLE_9; + } + } + + dev_priv->mm.bit_6_swizzle_x = swizzle_x; + dev_priv->mm.bit_6_swizzle_y = swizzle_y; +} + +/** + * Swap every 64 bytes of this page around, to account for it having a new + * bit 17 of its physical address and therefore being interpreted differently + * by the GPU. + */ +static void +i915_gem_swizzle_page(struct page *page) +{ + char temp[64]; + char *vaddr; + int i; + + vaddr = kmap(page); + + for (i = 0; i < PAGE_SIZE; i += 128) { + memcpy(temp, &vaddr[i], 64); + memcpy(&vaddr[i], &vaddr[i + 64], 64); + memcpy(&vaddr[i + 64], temp, 64); + } + + kunmap(page); +} + +void +i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) +{ + struct sg_page_iter sg_iter; + int i; + + if (obj->bit_17 == NULL) + return; + + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + struct page *page = sg_page_iter_page(&sg_iter); + char new_bit_17 = page_to_phys(page) >> 17; + if ((new_bit_17 & 0x1) != + (test_bit(i, obj->bit_17) != 0)) { + i915_gem_swizzle_page(page); + set_page_dirty(page); + } + i++; + } +} + +void +i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) +{ + struct sg_page_iter sg_iter; + int page_count = obj->base.size >> PAGE_SHIFT; + int i; + + if (obj->bit_17 == NULL) { + obj->bit_17 = kcalloc(BITS_TO_LONGS(page_count), + sizeof(long), GFP_KERNEL); + if (obj->bit_17 == NULL) { + DRM_ERROR("Failed to allocate memory for bit 17 " + "record\n"); + return; + } + } + + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17)) + __set_bit(i, obj->bit_17); + else + __clear_bit(i, obj->bit_17); + i++; + } +} diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 633bd1fcab69..fa7a8d7a24e0 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -80,153 +80,6 @@ * to match what the GPU expects. */ -/** - * Detects bit 6 swizzling of address lookup between IGD access and CPU - * access through main memory. - */ -void -i915_gem_detect_bit_6_swizzle(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; - uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; - - if (INTEL_INFO(dev)->gen >= 8 || IS_VALLEYVIEW(dev)) { - /* - * On BDW+, swizzling is not used. We leave the CPU memory - * controller in charge of optimizing memory accesses without - * the extra address manipulation GPU side. - * - * VLV and CHV don't have GPU swizzling. - */ - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } else if (INTEL_INFO(dev)->gen >= 6) { - if (dev_priv->preserve_bios_swizzle) { - if (I915_READ(DISP_ARB_CTL) & - DISP_TILE_SURFACE_SWIZZLING) { - swizzle_x = I915_BIT_6_SWIZZLE_9_10; - swizzle_y = I915_BIT_6_SWIZZLE_9; - } else { - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } - } else { - uint32_t dimm_c0, dimm_c1; - dimm_c0 = I915_READ(MAD_DIMM_C0); - dimm_c1 = I915_READ(MAD_DIMM_C1); - dimm_c0 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK; - dimm_c1 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK; - /* Enable swizzling when the channels are populated - * with identically sized dimms. We don't need to check - * the 3rd channel because no cpu with gpu attached - * ships in that configuration. Also, swizzling only - * makes sense for 2 channels anyway. */ - if (dimm_c0 == dimm_c1) { - swizzle_x = I915_BIT_6_SWIZZLE_9_10; - swizzle_y = I915_BIT_6_SWIZZLE_9; - } else { - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } - } - } else if (IS_GEN5(dev)) { - /* On Ironlake whatever DRAM config, GPU always do - * same swizzling setup. - */ - swizzle_x = I915_BIT_6_SWIZZLE_9_10; - swizzle_y = I915_BIT_6_SWIZZLE_9; - } else if (IS_GEN2(dev)) { - /* As far as we know, the 865 doesn't have these bit 6 - * swizzling issues. - */ - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } else if (IS_MOBILE(dev) || (IS_GEN3(dev) && !IS_G33(dev))) { - uint32_t dcc; - - /* On 9xx chipsets, channel interleave by the CPU is - * determined by DCC. For single-channel, neither the CPU - * nor the GPU do swizzling. For dual channel interleaved, - * the GPU's interleave is bit 9 and 10 for X tiled, and bit - * 9 for Y tiled. The CPU's interleave is independent, and - * can be based on either bit 11 (haven't seen this yet) or - * bit 17 (common). - */ - dcc = I915_READ(DCC); - switch (dcc & DCC_ADDRESSING_MODE_MASK) { - case DCC_ADDRESSING_MODE_SINGLE_CHANNEL: - case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC: - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - break; - case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED: - if (dcc & DCC_CHANNEL_XOR_DISABLE) { - /* This is the base swizzling by the GPU for - * tiled buffers. - */ - swizzle_x = I915_BIT_6_SWIZZLE_9_10; - swizzle_y = I915_BIT_6_SWIZZLE_9; - } else if ((dcc & DCC_CHANNEL_XOR_BIT_17) == 0) { - /* Bit 11 swizzling by the CPU in addition. */ - swizzle_x = I915_BIT_6_SWIZZLE_9_10_11; - swizzle_y = I915_BIT_6_SWIZZLE_9_11; - } else { - /* Bit 17 swizzling by the CPU in addition. */ - swizzle_x = I915_BIT_6_SWIZZLE_9_10_17; - swizzle_y = I915_BIT_6_SWIZZLE_9_17; - } - break; - } - - /* check for L-shaped memory aka modified enhanced addressing */ - if (IS_GEN4(dev)) { - uint32_t ddc2 = I915_READ(DCC2); - - if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE)) - dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; - } - - if (dcc == 0xffffffff) { - DRM_ERROR("Couldn't read from MCHBAR. " - "Disabling tiling.\n"); - swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; - swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; - } - } else { - /* The 965, G33, and newer, have a very flexible memory - * configuration. It will enable dual-channel mode - * (interleaving) on as much memory as it can, and the GPU - * will additionally sometimes enable different bit 6 - * swizzling for tiled objects from the CPU. - * - * Here's what I found on the G965: - * slot fill memory size swizzling - * 0A 0B 1A 1B 1-ch 2-ch - * 512 0 0 0 512 0 O - * 512 0 512 0 16 1008 X - * 512 0 0 512 16 1008 X - * 0 512 0 512 16 1008 X - * 1024 1024 1024 0 2048 1024 O - * - * We could probably detect this based on either the DRB - * matching, which was the case for the swizzling required in - * the table above, or from the 1-ch value being less than - * the minimum size of a rank. - */ - if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) { - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } else { - swizzle_x = I915_BIT_6_SWIZZLE_9_10; - swizzle_y = I915_BIT_6_SWIZZLE_9; - } - } - - dev_priv->mm.bit_6_swizzle_x = swizzle_x; - dev_priv->mm.bit_6_swizzle_y = swizzle_y; -} - /* Check pitch constriants for all chips & tiling formats */ static bool i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) @@ -475,75 +328,3 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, return 0; } - -/** - * Swap every 64 bytes of this page around, to account for it having a new - * bit 17 of its physical address and therefore being interpreted differently - * by the GPU. - */ -static void -i915_gem_swizzle_page(struct page *page) -{ - char temp[64]; - char *vaddr; - int i; - - vaddr = kmap(page); - - for (i = 0; i < PAGE_SIZE; i += 128) { - memcpy(temp, &vaddr[i], 64); - memcpy(&vaddr[i], &vaddr[i + 64], 64); - memcpy(&vaddr[i + 64], temp, 64); - } - - kunmap(page); -} - -void -i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) -{ - struct sg_page_iter sg_iter; - int i; - - if (obj->bit_17 == NULL) - return; - - i = 0; - for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { - struct page *page = sg_page_iter_page(&sg_iter); - char new_bit_17 = page_to_phys(page) >> 17; - if ((new_bit_17 & 0x1) != - (test_bit(i, obj->bit_17) != 0)) { - i915_gem_swizzle_page(page); - set_page_dirty(page); - } - i++; - } -} - -void -i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) -{ - struct sg_page_iter sg_iter; - int page_count = obj->base.size >> PAGE_SHIFT; - int i; - - if (obj->bit_17 == NULL) { - obj->bit_17 = kcalloc(BITS_TO_LONGS(page_count), - sizeof(long), GFP_KERNEL); - if (obj->bit_17 == NULL) { - DRM_ERROR("Failed to allocate memory for bit 17 " - "record\n"); - return; - } - } - - i = 0; - for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { - if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17)) - __set_bit(i, obj->bit_17); - else - __clear_bit(i, obj->bit_17); - i++; - } -} -- cgit v1.3-6-gb490 From 3271dca483a48759cdbdb5f16a13125ab91f6c05 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Jul 2015 17:40:15 +0200 Subject: drm/i915: kerneldoc for tiling IOCTL and swizzle functions Chris rightfully suggested that documenting fences without documenting the BO tiling tracking doesn't make much sense, so fix that. The important bit to stress here (since it lead to some confusion) is the GEM doesn't really care about tiling. Except for a few select cases where the kernel needs to manage something that userspace can't take care of: Namely the limited number of fences and fixing up swizzling, although we still fail at the later. v2: Move the low-level tiling/swizzling functions and kerneldoc to i915_gem_fence.c and leave only the userspace interface here. Suggested by Chris. Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 16 ++++++- drivers/gpu/drm/i915/i915_gem_fence.c | 28 ++++++++++-- drivers/gpu/drm/i915/i915_gem_tiling.c | 84 +++++++++++++++++----------------- 3 files changed, 80 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 20c39b7e21ee..43042739ae63 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4198,9 +4198,21 @@ int num_ioctls; !Idrivers/gpu/drm/i915/i915_gem_gtt.c - Global GTT Fence Handling -!Pdrivers/gpu/drm/i915/i915_gem_fence.c fence register handling + GTT Fences and Swizzling !Idrivers/gpu/drm/i915/i915_gem_fence.c + + Global GTT Fence Handling +!Pdrivers/gpu/drm/i915/i915_gem_fence.c fence register handling + + + Hardware Tiling and Swizzling Details +!Pdrivers/gpu/drm/i915/i915_gem_fence.c tiling swizzling details + + + + Object Tiling IOCTLs +!Idrivers/gpu/drm/i915/i915_gem_tiling.c +!Pdrivers/gpu/drm/i915/i915_gem_tiling.c buffer object tiling Buffer Object Eviction diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c index c643260a90c5..af1f8c461060 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -497,8 +497,7 @@ void i915_gem_restore_fences(struct drm_device *dev) } /** - * - * Support for managing tiling state of buffer objects. + * DOC: tiling swizzling details * * The idea behind tiling is to increase cache hit rates by rearranging * pixel data so that a group of pixel accesses are in the same cacheline. @@ -546,6 +545,9 @@ void i915_gem_restore_fences(struct drm_device *dev) */ /** + * i915_gem_detect_bit_6_swizzle - detect bit 6 swizzling pattern + * @dev: DRM device + * * Detects bit 6 swizzling of address lookup between IGD access and CPU * access through main memory. */ @@ -692,7 +694,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) dev_priv->mm.bit_6_swizzle_y = swizzle_y; } -/** +/* * Swap every 64 bytes of this page around, to account for it having a new * bit 17 of its physical address and therefore being interpreted differently * by the GPU. @@ -715,6 +717,18 @@ i915_gem_swizzle_page(struct page *page) kunmap(page); } +/** + * i915_gem_object_do_bit_17_swizzle - fixup bit 17 swizzling + * @obj: i915 GEM buffer object + * + * This function fixes up the swizzling in case any page frame number for this + * object has changed in bit 17 since that state has been saved with + * i915_gem_object_save_bit_17_swizzle(). + * + * This is called when pinning backing storage again, since the kernel is free + * to move unpinned backing storage around (either by directly moving pages or + * by swapping them out and back in again). + */ void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) { @@ -737,6 +751,14 @@ i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) } } +/** + * i915_gem_object_save_bit_17_swizzle - save bit 17 swizzling + * @obj: i915 GEM buffer object + * + * This function saves the bit 17 of each page frame number so that swizzling + * can be fixed up later on with i915_gem_object_do_bit_17_swizzle(). This must + * be called before the backing storage can be unpinned. + */ void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) { diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index fa7a8d7a24e0..ac3eb566c9d2 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -31,53 +31,31 @@ #include #include "i915_drv.h" -/** @file i915_gem_tiling.c - * - * Support for managing tiling state of buffer objects. - * - * The idea behind tiling is to increase cache hit rates by rearranging - * pixel data so that a group of pixel accesses are in the same cacheline. - * Performance improvement from doing this on the back/depth buffer are on - * the order of 30%. - * - * Intel architectures make this somewhat more complicated, though, by - * adjustments made to addressing of data when the memory is in interleaved - * mode (matched pairs of DIMMS) to improve memory bandwidth. - * For interleaved memory, the CPU sends every sequential 64 bytes - * to an alternate memory channel so it can get the bandwidth from both. - * - * The GPU also rearranges its accesses for increased bandwidth to interleaved - * memory, and it matches what the CPU does for non-tiled. However, when tiled - * it does it a little differently, since one walks addresses not just in the - * X direction but also Y. So, along with alternating channels when bit - * 6 of the address flips, it also alternates when other bits flip -- Bits 9 - * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines) - * are common to both the 915 and 965-class hardware. - * - * The CPU also sometimes XORs in higher bits as well, to improve - * bandwidth doing strided access like we do so frequently in graphics. This - * is called "Channel XOR Randomization" in the MCH documentation. The result - * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address - * decode. +/** + * DOC: buffer object tiling * - * All of this bit 6 XORing has an effect on our memory management, - * as we need to make sure that the 3d driver can correctly address object - * contents. + * i915_gem_set_tiling() and i915_gem_get_tiling() is the userspace interface to + * declare fence register requirements. * - * If we don't have interleaved memory, all tiling is safe and no swizzling is - * required. + * In principle GEM doesn't care at all about the internal data layout of an + * object, and hence it also doesn't care about tiling or swizzling. There's two + * exceptions: * - * When bit 17 is XORed in, we simply refuse to tile at all. Bit - * 17 is not just a page offset, so as we page an objet out and back in, - * individual pages in it will have different bit 17 addresses, resulting in - * each 64 bytes being swapped with its neighbor! + * - For X and Y tiling the hardware provides detilers for CPU access, so called + * fences. Since there's only a limited amount of them the kernel must manage + * these, and therefore userspace must tell the kernel the object tiling if it + * wants to use fences for detiling. + * - On gen3 and gen4 platforms have a swizzling pattern for tiled objects which + * depends upon the physical page frame number. When swapping such objects the + * page frame number might change and the kernel must be able to fix this up + * and hence now the tiling. Note that on a subset of platforms with + * asymmetric memory channel population the swizzling pattern changes in an + * unknown way, and for those the kernel simply forbids swapping completely. * - * Otherwise, if interleaved, we have to tell the 3d driver what the address - * swizzling it needs to do is, since it's writing with the CPU to the pages - * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the - * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling - * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order - * to match what the GPU expects. + * Since neither of this applies for new tiling layouts on modern platforms like + * W, Ys and Yf tiling GEM only allows object tiling to be set to X or Y tiled. + * Anything else can be handled in userspace entirely without the kernel's + * invovlement. */ /* Check pitch constriants for all chips & tiling formats */ @@ -166,8 +144,18 @@ i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode) } /** + * i915_gem_set_tiling - IOCTL handler to set tiling mode + * @dev: DRM device + * @data: data pointer for the ioctl + * @file: DRM file for the ioctl call + * * Sets the tiling mode of an object, returning the required swizzling of * bit 6 of addresses in the object. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. */ int i915_gem_set_tiling(struct drm_device *dev, void *data, @@ -285,7 +273,17 @@ err: } /** + * i915_gem_get_tiling - IOCTL handler to get tiling mode + * @dev: DRM device + * @data: data pointer for the ioctl + * @file: DRM file for the ioctl call + * * Returns the current tiling mode and required bit 6 swizzling for the object. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. */ int i915_gem_get_tiling(struct drm_device *dev, void *data, -- cgit v1.3-6-gb490 From 38b0e5071eca4db618e796a2f1dbad3b20c01358 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Tue, 5 May 2015 13:55:10 +0300 Subject: pinctrl: driver for Conexant Digicolor CX92755 pin mapping This adds pinctrl and gpio driver to the CX92755 SoC "General Purpose Pin Mapping" hardware block. The CX92755 is one SoC from the Conexant Digicolor series. Pin mapping hardware supports configuring pins as either GPIO, or up to 3 other "client select" functions. This driver adds support for pin muxing using the generic device tree binding, and a basic gpiolib driver for the GPIO functionality. This driver does not currently support GPIO interrupts, and pad configuration. v2: * Address review comments for Linus Walleij: - Add a pointer to pinctrl_desc in struct dc_pinmap - Drop the now redundant pinctrl_pin_desc field - Adapt dc_get_group_{name,pins} to these changes, and add a comment explaining the 1-to-1 pin-groups relation * Staticise dc_pmxops * Protect the GP_CLIENTSEL clct parameter with parenthesis Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 6 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-digicolor.c | 378 ++++++++++++++++++++++++++++++++++++ 3 files changed, 385 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-digicolor.c (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index e6362c61b560..84dd2ed47a92 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -82,6 +82,12 @@ config PINCTRL_AMD Requires ACPI/FDT device enumeration code to set up a platform device. +config PINCTRL_DIGICOLOR + bool + depends on OF && (ARCH_DIGICOLOR || COMPILE_TEST) + select PINMUX + select GENERIC_PINCONF + config PINCTRL_LANTIQ bool depends on LANTIQ diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 76ba976cb9ca..cad077c43fb7 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o +obj-$(CONFIG_PINCTRL_DIGICOLOR) += pinctrl-digicolor.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o diff --git a/drivers/pinctrl/pinctrl-digicolor.c b/drivers/pinctrl/pinctrl-digicolor.c new file mode 100644 index 000000000000..461fffc4c62a --- /dev/null +++ b/drivers/pinctrl/pinctrl-digicolor.c @@ -0,0 +1,378 @@ +/* + * Driver for Conexant Digicolor General Purpose Pin Mapping + * + * Author: Baruch Siach + * + * Copyright (C) 2015 Paradox Innovation Ltd. + * + * 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. + * + * TODO: + * - GPIO interrupt support + * - Pin pad configuration (pull up/down, strength) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pinctrl-utils.h" + +#define DRIVER_NAME "pinctrl-digicolor" + +#define GP_CLIENTSEL(clct) ((clct)*8 + 0x20) +#define GP_DRIVE0(clct) (GP_CLIENTSEL(clct) + 2) +#define GP_OUTPUT0(clct) (GP_CLIENTSEL(clct) + 3) +#define GP_INPUT(clct) (GP_CLIENTSEL(clct) + 6) + +#define PIN_COLLECTIONS ('R' - 'A' + 1) +#define PINS_PER_COLLECTION 8 +#define PINS_COUNT (PIN_COLLECTIONS * PINS_PER_COLLECTION) + +struct dc_pinmap { + void __iomem *regs; + struct device *dev; + struct pinctrl_dev *pctl; + + struct pinctrl_desc *desc; + const char *pin_names[PINS_COUNT]; + + struct gpio_chip chip; + spinlock_t lock; +}; + +static int dc_get_groups_count(struct pinctrl_dev *pctldev) +{ + return PINS_COUNT; +} + +static const char *dc_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev); + + /* Exactly one group per pin */ + return pmap->desc->pins[selector].name; +} + +static int dc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev); + + *pins = &pmap->desc->pins[selector].number; + *num_pins = 1; + + return 0; +} + +static struct pinctrl_ops dc_pinctrl_ops = { + .get_groups_count = dc_get_groups_count, + .get_group_name = dc_get_group_name, + .get_group_pins = dc_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static const char *const dc_functions[] = { + "gpio", + "client_a", + "client_b", + "client_c", +}; + +static int dc_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(dc_functions); +} + +static const char *dc_get_fname(struct pinctrl_dev *pctldev, unsigned selector) +{ + return dc_functions[selector]; +} + +static int dc_get_groups(struct pinctrl_dev *pctldev, unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev); + + *groups = pmap->pin_names; + *num_groups = PINS_COUNT; + + return 0; +} + +static void dc_client_sel(int pin_num, int *reg, int *bit) +{ + *bit = (pin_num % PINS_PER_COLLECTION) * 2; + *reg = GP_CLIENTSEL(pin_num/PINS_PER_COLLECTION); + + if (*bit >= PINS_PER_COLLECTION) { + *bit -= PINS_PER_COLLECTION; + *reg += 1; + } +} + +static int dc_set_mux(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev); + int bit_off, reg_off; + u8 reg; + + dc_client_sel(group, ®_off, &bit_off); + + reg = readb_relaxed(pmap->regs + reg_off); + reg &= ~(3 << bit_off); + reg |= (selector << bit_off); + writeb_relaxed(reg, pmap->regs + reg_off); + + return 0; +} + +static int dc_pmx_request_gpio(struct pinctrl_dev *pcdev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pcdev); + int bit_off, reg_off; + u8 reg; + + dc_client_sel(offset, ®_off, &bit_off); + + reg = readb_relaxed(pmap->regs + reg_off); + if ((reg & (3 << bit_off)) != 0) + return -EBUSY; + + return 0; +} + +static struct pinmux_ops dc_pmxops = { + .get_functions_count = dc_get_functions_count, + .get_function_name = dc_get_fname, + .get_function_groups = dc_get_groups, + .set_mux = dc_set_mux, + .gpio_request_enable = dc_pmx_request_gpio, +}; + +static int dc_gpio_request(struct gpio_chip *chip, unsigned gpio) +{ + return pinctrl_request_gpio(chip->base + gpio); +} + +static void dc_gpio_free(struct gpio_chip *chip, unsigned gpio) +{ + pinctrl_free_gpio(chip->base + gpio); +} + +static int dc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip); + int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION); + int bit_off = gpio % PINS_PER_COLLECTION; + u8 drive; + unsigned long flags; + + spin_lock_irqsave(&pmap->lock, flags); + drive = readb_relaxed(pmap->regs + reg_off); + drive &= ~BIT(bit_off); + writeb_relaxed(drive, pmap->regs + reg_off); + spin_unlock_irqrestore(&pmap->lock, flags); + + return 0; +} + +static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value); + +static int dc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, + int value) +{ + struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip); + int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION); + int bit_off = gpio % PINS_PER_COLLECTION; + u8 drive; + unsigned long flags; + + dc_gpio_set(chip, gpio, value); + + spin_lock_irqsave(&pmap->lock, flags); + drive = readb_relaxed(pmap->regs + reg_off); + drive |= BIT(bit_off); + writeb_relaxed(drive, pmap->regs + reg_off); + spin_unlock_irqrestore(&pmap->lock, flags); + + return 0; +} + +static int dc_gpio_get(struct gpio_chip *chip, unsigned gpio) +{ + struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip); + int reg_off = GP_INPUT(gpio/PINS_PER_COLLECTION); + int bit_off = gpio % PINS_PER_COLLECTION; + u8 input; + + input = readb_relaxed(pmap->regs + reg_off); + + return !!(input & BIT(bit_off)); +} + +static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) +{ + struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip); + int reg_off = GP_OUTPUT0(gpio/PINS_PER_COLLECTION); + int bit_off = gpio % PINS_PER_COLLECTION; + u8 output; + unsigned long flags; + + spin_lock_irqsave(&pmap->lock, flags); + output = readb_relaxed(pmap->regs + reg_off); + if (value) + output |= BIT(bit_off); + else + output &= ~BIT(bit_off); + writeb_relaxed(output, pmap->regs + reg_off); + spin_unlock_irqrestore(&pmap->lock, flags); +} + +static int dc_gpiochip_add(struct dc_pinmap *pmap, struct device_node *np) +{ + struct gpio_chip *chip = &pmap->chip; + int ret; + + chip->label = DRIVER_NAME; + chip->dev = pmap->dev; + chip->request = dc_gpio_request; + chip->free = dc_gpio_free; + chip->direction_input = dc_gpio_direction_input; + chip->direction_output = dc_gpio_direction_output; + chip->get = dc_gpio_get; + chip->set = dc_gpio_set; + chip->base = -1; + chip->ngpio = PINS_COUNT; + chip->of_node = np; + chip->of_gpio_n_cells = 2; + + spin_lock_init(&pmap->lock); + + ret = gpiochip_add(chip); + if (ret < 0) + return ret; + + ret = gpiochip_add_pin_range(chip, dev_name(pmap->dev), 0, 0, + PINS_COUNT); + if (ret < 0) { + gpiochip_remove(chip); + return ret; + } + + return 0; +} + +static int dc_pinctrl_probe(struct platform_device *pdev) +{ + struct dc_pinmap *pmap; + struct resource *r; + struct pinctrl_pin_desc *pins; + struct pinctrl_desc *pctl_desc; + char *pin_names; + int name_len = strlen("GP_xx") + 1; + int i, j, ret; + + pmap = devm_kzalloc(&pdev->dev, sizeof(*pmap), GFP_KERNEL); + if (!pmap) + return -ENOMEM; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pmap->regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(pmap->regs)) + return PTR_ERR(pmap->regs); + + pins = devm_kzalloc(&pdev->dev, sizeof(*pins)*PINS_COUNT, GFP_KERNEL); + if (!pins) + return -ENOMEM; + pin_names = devm_kzalloc(&pdev->dev, name_len * PINS_COUNT, + GFP_KERNEL); + if (!pin_names) + return -ENOMEM; + + for (i = 0; i < PIN_COLLECTIONS; i++) { + for (j = 0; j < PINS_PER_COLLECTION; j++) { + int pin_id = i*PINS_PER_COLLECTION + j; + char *name = &pin_names[pin_id * name_len]; + + snprintf(name, name_len, "GP_%c%c", 'A'+i, '0'+j); + + pins[pin_id].number = pin_id; + pins[pin_id].name = name; + pmap->pin_names[pin_id] = name; + } + } + + pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL); + if (!pctl_desc) + return -ENOMEM; + + pctl_desc->name = DRIVER_NAME, + pctl_desc->owner = THIS_MODULE, + pctl_desc->pctlops = &dc_pinctrl_ops, + pctl_desc->pmxops = &dc_pmxops, + pctl_desc->npins = PINS_COUNT; + pctl_desc->pins = pins; + pmap->desc = pctl_desc; + + pmap->dev = &pdev->dev; + + pmap->pctl = pinctrl_register(pctl_desc, &pdev->dev, pmap); + if (!pmap->pctl) { + dev_err(&pdev->dev, "pinctrl driver registration failed\n"); + return -EINVAL; + } + + ret = dc_gpiochip_add(pmap, pdev->dev.of_node); + if (ret < 0) { + pinctrl_unregister(pmap->pctl); + return ret; + } + + return 0; +} + +static int dc_pinctrl_remove(struct platform_device *pdev) +{ + struct dc_pinmap *pmap = platform_get_drvdata(pdev); + + pinctrl_unregister(pmap->pctl); + gpiochip_remove(&pmap->chip); + + return 0; +} + +static const struct of_device_id dc_pinctrl_ids[] = { + { .compatible = "cnxt,cx92755-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dc_pinctrl_ids); + +static struct platform_driver dc_pinctrl_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = dc_pinctrl_ids, + }, + .probe = dc_pinctrl_probe, + .remove = dc_pinctrl_remove, +}; +module_platform_driver(dc_pinctrl_driver); -- cgit v1.3-6-gb490 From 5a063d87e97df28ca0b00807bc4d6fa11c5a5107 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Jul 2015 09:56:05 +0200 Subject: pwm: sysfs: Properly convert from enum to string The current code will check for polarity in a boolean way. While it is correct that polarity is either normal or inversed, make it more obvious that it's an enumeration by using a switch statement and explicit matches on the enumeration values. Signed-off-by: Thierry Reding --- drivers/pwm/sysfs.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index ac0abecfbaa0..fbfc9e903230 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -133,9 +133,19 @@ static ssize_t pwm_polarity_show(struct device *child, char *buf) { const struct pwm_device *pwm = child_to_pwm_device(child); + const char *polarity = "unknown"; - return sprintf(buf, "%s\n", - pwm_get_polarity(pwm) ? "inversed" : "normal"); + switch (pwm_get_polarity(pwm)) { + case PWM_POLARITY_NORMAL: + polarity = "normal"; + break; + + case PWM_POLARITY_INVERSED: + polarity = "inversed"; + break; + } + + return sprintf(buf, "%s\n", polarity); } static ssize_t pwm_polarity_store(struct device *child, -- cgit v1.3-6-gb490 From 412820dd536fe2d01a35f0d68982ea225ec255b3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Jul 2015 09:58:09 +0200 Subject: pwm: sysfs: Remove unnecessary padding Padding initializers so that assignment operators align is bound to lead to inconsistencies or churn. Single spaces around the assignment is just fine. Signed-off-by: Thierry Reding --- drivers/pwm/sysfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index fbfc9e903230..c472772f00a7 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -312,9 +312,9 @@ static struct attribute *pwm_chip_attrs[] = { ATTRIBUTE_GROUPS(pwm_chip); static struct class pwm_class = { - .name = "pwm", - .owner = THIS_MODULE, - .dev_groups = pwm_chip_groups, + .name = "pwm", + .owner = THIS_MODULE, + .dev_groups = pwm_chip_groups, }; static int pwmchip_sysfs_match(struct device *parent, const void *data) -- cgit v1.3-6-gb490 From 4183afefd995e3472c10348998edd9f791eb523f Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 16 Jul 2015 21:08:21 +0200 Subject: gpio: mpc8xxx: constify of_device_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This variable is not modified in the driver and all functions it it passed to don't change it either. So it can and should be marked const. Signed-off-by: Uwe Kleine-König Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index da8e89205f37..0e2dbbb1645b 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -334,7 +334,7 @@ static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = { .xlate = irq_domain_xlate_twocell, }; -static struct of_device_id mpc8xxx_gpio_ids[] = { +static const struct of_device_id mpc8xxx_gpio_ids[] = { { .compatible = "fsl,mpc8349-gpio", }, { .compatible = "fsl,mpc8572-gpio", }, { .compatible = "fsl,mpc8610-gpio", }, -- cgit v1.3-6-gb490 From 82e39b0d8566fa67077c6941f776d17833c80fea Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 16 Jul 2015 21:08:22 +0200 Subject: gpio: mpc8xxx: handle differences between incarnations at a single place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gpio controllers that are handled by the mpc8xxx driver differ slightly. Up to now some differences were handled by use of of_device_is_compatible, others by use of struct of_device_id's data. To make this consistent and easily extendable handle the differences at a single place. Signed-off-by: Uwe Kleine-König Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 49 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 0e2dbbb1645b..836494420a56 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -312,17 +312,13 @@ static struct irq_chip mpc8xxx_irq_chip = { .irq_unmask = mpc8xxx_irq_unmask, .irq_mask = mpc8xxx_irq_mask, .irq_ack = mpc8xxx_irq_ack, + /* this might get overwritten in mpc8xxx_probe() */ .irq_set_type = mpc8xxx_irq_set_type, }; static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq, irq_hw_number_t hwirq) { - struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; - - if (mpc8xxx_gc->of_dev_id_data) - mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data; - irq_set_chip_data(irq, h->host_data); irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq); @@ -334,11 +330,32 @@ static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = { .xlate = irq_domain_xlate_twocell, }; +struct mpc8xxx_gpio_devtype { + int (*gpio_dir_out)(struct gpio_chip *, unsigned int, int); + int (*gpio_get)(struct gpio_chip *, unsigned int); + int (*irq_set_type)(struct irq_data *, unsigned int); +}; + +static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = { + .gpio_dir_out = mpc5121_gpio_dir_out, + .irq_set_type = mpc512x_irq_set_type, +}; + +static const struct mpc8xxx_gpio_devtype mpc8572_gpio_devtype = { + .gpio_get = mpc8572_gpio_get, +}; + +static const struct mpc8xxx_gpio_devtype mpc8xxx_gpio_devtype_default = { + .gpio_dir_out = mpc8xxx_gpio_dir_out, + .gpio_get = mpc8xxx_gpio_get, + .irq_set_type = mpc8xxx_irq_set_type, +}; + static const struct of_device_id mpc8xxx_gpio_ids[] = { { .compatible = "fsl,mpc8349-gpio", }, - { .compatible = "fsl,mpc8572-gpio", }, + { .compatible = "fsl,mpc8572-gpio", .data = &mpc8572_gpio_devtype, }, { .compatible = "fsl,mpc8610-gpio", }, - { .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, }, + { .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, }, { .compatible = "fsl,pq3-gpio", }, { .compatible = "fsl,qoriq-gpio", }, {} @@ -351,6 +368,8 @@ static int mpc8xxx_probe(struct platform_device *pdev) struct of_mm_gpio_chip *mm_gc; struct gpio_chip *gc; const struct of_device_id *id; + const struct mpc8xxx_gpio_devtype *devtype = + of_device_get_match_data(&pdev->dev); int ret; mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL); @@ -367,10 +386,18 @@ static int mpc8xxx_probe(struct platform_device *pdev) mm_gc->save_regs = mpc8xxx_gpio_save_regs; gc->ngpio = MPC8XXX_GPIO_PINS; gc->direction_input = mpc8xxx_gpio_dir_in; - gc->direction_output = of_device_is_compatible(np, "fsl,mpc5121-gpio") ? - mpc5121_gpio_dir_out : mpc8xxx_gpio_dir_out; - gc->get = of_device_is_compatible(np, "fsl,mpc8572-gpio") ? - mpc8572_gpio_get : mpc8xxx_gpio_get; + + if (!devtype) + devtype = &mpc8xxx_gpio_devtype_default; + + /* + * It's assumed that only a single type of gpio controller is available + * on the current machine, so overwriting global data is fine. + */ + mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type; + + gc->direction_output = devtype->gpio_dir_out ?: mpc8xxx_gpio_dir_out; + gc->get = devtype->gpio_get ?: mpc8xxx_gpio_get; gc->set = mpc8xxx_gpio_set; gc->set_multiple = mpc8xxx_gpio_set_multiple; gc->to_irq = mpc8xxx_gpio_to_irq; -- cgit v1.3-6-gb490 From 0ba69e089827c24f5a4b21124185914f9de4f466 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 16 Jul 2015 21:08:23 +0200 Subject: gpio: mpc8xxx: add support for MPC5125 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gpio controller on MPC5125 is identical to the MPC5121 register wise, the only difference is that the lines 0..3 are input only instead of 28..31 on MPC5121. Signed-off-by: Uwe Kleine-König Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 836494420a56..4c5137793431 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -174,6 +174,15 @@ static int mpc5121_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val return mpc8xxx_gpio_dir_out(gc, gpio, val); } +static int mpc5125_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + /* GPIO 0..3 are input only on MPC5125 */ + if (gpio <= 3) + return -EINVAL; + + return mpc8xxx_gpio_dir_out(gc, gpio, val); +} + static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); @@ -341,6 +350,11 @@ static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = { .irq_set_type = mpc512x_irq_set_type, }; +static const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = { + .gpio_dir_out = mpc5125_gpio_dir_out, + .irq_set_type = mpc512x_irq_set_type, +}; + static const struct mpc8xxx_gpio_devtype mpc8572_gpio_devtype = { .gpio_get = mpc8572_gpio_get, }; @@ -356,6 +370,7 @@ static const struct of_device_id mpc8xxx_gpio_ids[] = { { .compatible = "fsl,mpc8572-gpio", .data = &mpc8572_gpio_devtype, }, { .compatible = "fsl,mpc8610-gpio", }, { .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, }, + { .compatible = "fsl,mpc5125-gpio", .data = &mpc5125_gpio_devtype, }, { .compatible = "fsl,pq3-gpio", }, { .compatible = "fsl,qoriq-gpio", }, {} -- cgit v1.3-6-gb490 From a0d6de9bdf8d66be458fcda5898a799778169c60 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 20 Jul 2015 14:41:11 +0200 Subject: pinctrl: sunxi: Use common functions to change irq_chip and handler The current code uses some custom variable affectations, while we have common functions to do exactly that. Move to the common functions. Signed-off-by: Maxime Ripard Reviewed-by: Hans de Goede Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 3e905480ec56..c804f3832332 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -588,7 +588,6 @@ static void sunxi_pinctrl_irq_release_resources(struct irq_data *d) static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) { struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); - struct irq_desc *desc = container_of(d, struct irq_desc, irq_data); u32 reg = sunxi_irq_cfg_reg(d->hwirq); u8 index = sunxi_irq_cfg_offset(d->hwirq); unsigned long flags; @@ -615,16 +614,17 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - if (type & IRQ_TYPE_LEVEL_MASK) { - d->chip = &sunxi_pinctrl_level_irq_chip; - desc->handle_irq = handle_fasteoi_irq; - } else { - d->chip = &sunxi_pinctrl_edge_irq_chip; - desc->handle_irq = handle_edge_irq; - } - spin_lock_irqsave(&pctl->lock, flags); + if (type & IRQ_TYPE_LEVEL_MASK) + __irq_set_chip_handler_name_locked(d->irq, + &sunxi_pinctrl_level_irq_chip, + handle_fasteoi_irq, NULL); + else + __irq_set_chip_handler_name_locked(d->irq, + &sunxi_pinctrl_edge_irq_chip, + handle_edge_irq, NULL); + regval = readl(pctl->membase + reg); regval &= ~(IRQ_CFG_IRQ_MASK << index); writel(regval | (mode << index), pctl->membase + reg); -- cgit v1.3-6-gb490 From fb5b778808a1e5d6874c17b2e670c76fab9a1300 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 20 Jul 2015 14:41:12 +0200 Subject: pinctrl: sunxi: Add irq_chip name In order to ease the debugging, add a name to the irq_chips. Signed-off-by: Maxime Ripard Reviewed-by: Hans de Goede Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index c804f3832332..7f7e7bb4f22c 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -685,6 +685,7 @@ static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d) } static struct irq_chip sunxi_pinctrl_edge_irq_chip = { + .name = "sunxi_pio_edge", .irq_ack = sunxi_pinctrl_irq_ack, .irq_mask = sunxi_pinctrl_irq_mask, .irq_unmask = sunxi_pinctrl_irq_unmask, @@ -695,6 +696,7 @@ static struct irq_chip sunxi_pinctrl_edge_irq_chip = { }; static struct irq_chip sunxi_pinctrl_level_irq_chip = { + .name = "sunxi_pio_level", .irq_eoi = sunxi_pinctrl_irq_ack, .irq_mask = sunxi_pinctrl_irq_mask, .irq_unmask = sunxi_pinctrl_irq_unmask, -- cgit v1.3-6-gb490 From 805de8f43c20ba8b479bb598b543fa86b20067f6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 24 Apr 2015 01:12:32 +0200 Subject: atomic: Replace atomic_{set,clear}_mask() usage Replace the deprecated atomic_{set,clear}_mask() usage with the now ubiquous atomic_{or,andnot}() functions. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/blackfin/mach-common/smp.c | 2 +- arch/m32r/kernel/smp.c | 4 +-- arch/mn10300/mm/tlb-smp.c | 2 +- arch/s390/kernel/time.c | 4 +-- arch/s390/kvm/interrupt.c | 30 ++++++++++---------- arch/s390/kvm/kvm-s390.c | 32 ++++++++++----------- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_irq.c | 4 +-- drivers/s390/scsi/zfcp_aux.c | 2 +- drivers/s390/scsi/zfcp_erp.c | 62 ++++++++++++++++++++--------------------- drivers/s390/scsi/zfcp_fc.c | 8 +++--- drivers/s390/scsi/zfcp_fsf.c | 26 ++++++++--------- drivers/s390/scsi/zfcp_qdio.c | 14 +++++----- 14 files changed, 97 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index 1c7259597395..0030e21cfceb 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -195,7 +195,7 @@ void send_ipi(const struct cpumask *cpumask, enum ipi_message_type msg) local_irq_save(flags); for_each_cpu(cpu, cpumask) { bfin_ipi_data = &per_cpu(bfin_ipi, cpu); - atomic_set_mask((1 << msg), &bfin_ipi_data->bits); + atomic_or((1 << msg), &bfin_ipi_data->bits); atomic_inc(&bfin_ipi_data->count); } local_irq_restore(flags); diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c index c18ddc74ef9a..62d6961e7f2b 100644 --- a/arch/m32r/kernel/smp.c +++ b/arch/m32r/kernel/smp.c @@ -156,7 +156,7 @@ void smp_flush_cache_all(void) cpumask_clear_cpu(smp_processor_id(), &cpumask); spin_lock(&flushcache_lock); mask=cpumask_bits(&cpumask); - atomic_set_mask(*mask, (atomic_t *)&flushcache_cpumask); + atomic_or(*mask, (atomic_t *)&flushcache_cpumask); send_IPI_mask(&cpumask, INVALIDATE_CACHE_IPI, 0); _flush_cache_copyback_all(); while (flushcache_cpumask) @@ -407,7 +407,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, flush_vma = vma; flush_va = va; mask=cpumask_bits(&cpumask); - atomic_set_mask(*mask, (atomic_t *)&flush_cpumask); + atomic_or(*mask, (atomic_t *)&flush_cpumask); /* * We have to send the IPI only to diff --git a/arch/mn10300/mm/tlb-smp.c b/arch/mn10300/mm/tlb-smp.c index e5d0ef722bfa..9a39ea9031d4 100644 --- a/arch/mn10300/mm/tlb-smp.c +++ b/arch/mn10300/mm/tlb-smp.c @@ -119,7 +119,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, flush_mm = mm; flush_va = va; #if NR_CPUS <= BITS_PER_LONG - atomic_set_mask(cpumask.bits[0], &flush_cpumask.bits[0]); + atomic_or(cpumask.bits[0], (atomic_t *)&flush_cpumask.bits[0]); #else #error Not supported. #endif diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 9e733d965e08..f5a0bd778ace 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -381,7 +381,7 @@ static void disable_sync_clock(void *dummy) * increase the "sequence" counter to avoid the race of an * etr event and the complete recovery against get_sync_clock. */ - atomic_clear_mask(0x80000000, sw_ptr); + atomic_andnot(0x80000000, sw_ptr); atomic_inc(sw_ptr); } @@ -392,7 +392,7 @@ static void disable_sync_clock(void *dummy) static void enable_sync_clock(void) { atomic_t *sw_ptr = this_cpu_ptr(&clock_sync_word); - atomic_set_mask(0x80000000, sw_ptr); + atomic_or(0x80000000, sw_ptr); } /* diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index c98d89708e99..57309e9cdd80 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -170,20 +170,20 @@ static unsigned long deliverable_irqs(struct kvm_vcpu *vcpu) static void __set_cpu_idle(struct kvm_vcpu *vcpu) { - atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); set_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); } static void __unset_cpu_idle(struct kvm_vcpu *vcpu) { - atomic_clear_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); clear_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); } static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) { - atomic_clear_mask(CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, - &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, + &vcpu->arch.sie_block->cpuflags); vcpu->arch.sie_block->lctl = 0x0000; vcpu->arch.sie_block->ictl &= ~(ICTL_LPSW | ICTL_STCTL | ICTL_PINT); @@ -196,7 +196,7 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag) { - atomic_set_mask(flag, &vcpu->arch.sie_block->cpuflags); + atomic_or(flag, &vcpu->arch.sie_block->cpuflags); } static void set_intercept_indicators_io(struct kvm_vcpu *vcpu) @@ -919,7 +919,7 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu) spin_unlock(&li->lock); /* clear pending external calls set by sigp interpretation facility */ - atomic_clear_mask(CPUSTAT_ECALL_PEND, li->cpuflags); + atomic_andnot(CPUSTAT_ECALL_PEND, li->cpuflags); vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl = 0; } @@ -1020,7 +1020,7 @@ static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) li->irq.ext = irq->u.ext; set_bit(IRQ_PEND_PFAULT_INIT, &li->pending_irqs); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); return 0; } @@ -1035,7 +1035,7 @@ static int __inject_extcall_sigpif(struct kvm_vcpu *vcpu, uint16_t src_id) /* another external call is pending */ return -EBUSY; } - atomic_set_mask(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags); return 0; } @@ -1061,7 +1061,7 @@ static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs)) return -EBUSY; *extcall = irq->u.extcall; - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); return 0; } @@ -1133,7 +1133,7 @@ static int __inject_sigp_emergency(struct kvm_vcpu *vcpu, set_bit(irq->u.emerg.code, li->sigp_emerg_pending); set_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); return 0; } @@ -1177,7 +1177,7 @@ static int __inject_ckc(struct kvm_vcpu *vcpu) 0, 0, 2); set_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); return 0; } @@ -1190,7 +1190,7 @@ static int __inject_cpu_timer(struct kvm_vcpu *vcpu) 0, 0, 2); set_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); return 0; } @@ -1369,13 +1369,13 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type) spin_lock(&li->lock); switch (type) { case KVM_S390_MCHK: - atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags); + atomic_or(CPUSTAT_STOP_INT, li->cpuflags); break; case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: - atomic_set_mask(CPUSTAT_IO_INT, li->cpuflags); + atomic_or(CPUSTAT_IO_INT, li->cpuflags); break; default: - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); break; } spin_unlock(&li->lock); diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 2078f92d15ac..b73302fb0507 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -1215,12 +1215,12 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) } restore_access_regs(vcpu->run->s.regs.acrs); gmap_enable(vcpu->arch.gmap); - atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); } void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) { - atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); gmap_disable(vcpu->arch.gmap); if (test_kvm_facility(vcpu->kvm, 129)) { save_fp_ctl(&vcpu->run->s.regs.fpc); @@ -1320,9 +1320,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) CPUSTAT_STOPPED); if (test_kvm_facility(vcpu->kvm, 78)) - atomic_set_mask(CPUSTAT_GED2, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_GED2, &vcpu->arch.sie_block->cpuflags); else if (test_kvm_facility(vcpu->kvm, 8)) - atomic_set_mask(CPUSTAT_GED, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_GED, &vcpu->arch.sie_block->cpuflags); kvm_s390_vcpu_setup_model(vcpu); @@ -1422,24 +1422,24 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) void kvm_s390_vcpu_block(struct kvm_vcpu *vcpu) { - atomic_set_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20); + atomic_or(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20); exit_sie(vcpu); } void kvm_s390_vcpu_unblock(struct kvm_vcpu *vcpu) { - atomic_clear_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20); + atomic_andnot(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20); } static void kvm_s390_vcpu_request(struct kvm_vcpu *vcpu) { - atomic_set_mask(PROG_REQUEST, &vcpu->arch.sie_block->prog20); + atomic_or(PROG_REQUEST, &vcpu->arch.sie_block->prog20); exit_sie(vcpu); } static void kvm_s390_vcpu_request_handled(struct kvm_vcpu *vcpu) { - atomic_clear_mask(PROG_REQUEST, &vcpu->arch.sie_block->prog20); + atomic_or(PROG_REQUEST, &vcpu->arch.sie_block->prog20); } /* @@ -1448,7 +1448,7 @@ static void kvm_s390_vcpu_request_handled(struct kvm_vcpu *vcpu) * return immediately. */ void exit_sie(struct kvm_vcpu *vcpu) { - atomic_set_mask(CPUSTAT_STOP_INT, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_STOP_INT, &vcpu->arch.sie_block->cpuflags); while (vcpu->arch.sie_block->prog0c & PROG_IN_SIE) cpu_relax(); } @@ -1672,19 +1672,19 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, if (dbg->control & KVM_GUESTDBG_ENABLE) { vcpu->guest_debug = dbg->control; /* enforce guest PER */ - atomic_set_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); if (dbg->control & KVM_GUESTDBG_USE_HW_BP) rc = kvm_s390_import_bp_data(vcpu, dbg); } else { - atomic_clear_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); vcpu->arch.guestdbg.last_bp = 0; } if (rc) { vcpu->guest_debug = 0; kvm_s390_clear_bp_data(vcpu); - atomic_clear_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); } return rc; @@ -1771,7 +1771,7 @@ retry: if (kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu)) { if (!ibs_enabled(vcpu)) { trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 1); - atomic_set_mask(CPUSTAT_IBS, + atomic_or(CPUSTAT_IBS, &vcpu->arch.sie_block->cpuflags); } goto retry; @@ -1780,7 +1780,7 @@ retry: if (kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu)) { if (ibs_enabled(vcpu)) { trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 0); - atomic_clear_mask(CPUSTAT_IBS, + atomic_andnot(CPUSTAT_IBS, &vcpu->arch.sie_block->cpuflags); } goto retry; @@ -2280,7 +2280,7 @@ void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu) __disable_ibs_on_all_vcpus(vcpu->kvm); } - atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); /* * Another VCPU might have used IBS while we were offline. * Let's play safe and flush the VCPU at startup. @@ -2306,7 +2306,7 @@ void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu) /* SIGP STOP and SIGP STOP AND STORE STATUS has been fully processed */ kvm_s390_clear_stop_irq(vcpu); - atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); __disable_ibs_on_vcpu(vcpu); for (i = 0; i < online_vcpus; i++) { diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 884b4f9b81c4..8917c98ff121 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -748,7 +748,7 @@ static int i915_drm_resume(struct drm_device *dev) mutex_lock(&dev->struct_mutex); if (i915_gem_init_hw(dev)) { DRM_ERROR("failed to re-initialize GPU, declaring wedged!\n"); - atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter); + atomic_or(I915_WEDGED, &dev_priv->gpu_error.reset_counter); } mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 52b446b27b4d..7a918d1c12ba 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5091,7 +5091,7 @@ int i915_gem_init(struct drm_device *dev) * for all other failure, such as an allocation failure, bail. */ DRM_ERROR("Failed to initialize GPU, declaring it wedged\n"); - atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter); + atomic_or(I915_WEDGED, &dev_priv->gpu_error.reset_counter); ret = 0; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 984e2fe6688c..449a95c6c2a1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2446,7 +2446,7 @@ static void i915_reset_and_wakeup(struct drm_device *dev) kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, reset_done_event); } else { - atomic_set_mask(I915_WEDGED, &error->reset_counter); + atomic_or(I915_WEDGED, &error->reset_counter); } /* @@ -2574,7 +2574,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged, i915_report_and_clear_eir(dev); if (wedged) { - atomic_set_mask(I915_RESET_IN_PROGRESS_FLAG, + atomic_or(I915_RESET_IN_PROGRESS_FLAG, &dev_priv->gpu_error.reset_counter); /* diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 01a73395a017..c00ac4650dce 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -529,7 +529,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, list_add_tail(&port->list, &adapter->port_list); write_unlock_irq(&adapter->port_list_lock); - atomic_set_mask(status | ZFCP_STATUS_COMMON_RUNNING, &port->status); + atomic_or(status | ZFCP_STATUS_COMMON_RUNNING, &port->status); return port; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index acde3f5d6e9e..3fb410977014 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -190,7 +190,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, if (!(act_status & ZFCP_STATUS_ERP_NO_REF)) if (scsi_device_get(sdev)) return NULL; - atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &zfcp_sdev->status); erp_action = &zfcp_sdev->erp_action; memset(erp_action, 0, sizeof(struct zfcp_erp_action)); @@ -206,7 +206,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, if (!get_device(&port->dev)) return NULL; zfcp_erp_action_dismiss_port(port); - atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); + atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); erp_action = &port->erp_action; memset(erp_action, 0, sizeof(struct zfcp_erp_action)); erp_action->port = port; @@ -217,7 +217,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, case ZFCP_ERP_ACTION_REOPEN_ADAPTER: kref_get(&adapter->ref); zfcp_erp_action_dismiss_adapter(adapter); - atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); + atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); erp_action = &adapter->erp_action; memset(erp_action, 0, sizeof(struct zfcp_erp_action)); if (!(atomic_read(&adapter->status) & @@ -254,7 +254,7 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev); if (!act) goto out; - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); + atomic_or(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); ++adapter->erp_total_count; list_add_tail(&act->list, &adapter->erp_ready_head); wake_up(&adapter->erp_ready_wq); @@ -486,14 +486,14 @@ static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) { if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) zfcp_dbf_rec_run("eraubl1", &adapter->erp_action); - atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); + atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); } static void zfcp_erp_port_unblock(struct zfcp_port *port) { if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) zfcp_dbf_rec_run("erpubl1", &port->erp_action); - atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); + atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); } static void zfcp_erp_lun_unblock(struct scsi_device *sdev) @@ -502,7 +502,7 @@ static void zfcp_erp_lun_unblock(struct scsi_device *sdev) if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status)) zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action); - atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status); + atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status); } static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) @@ -642,7 +642,7 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) read_lock_irqsave(&adapter->erp_lock, flags); if (list_empty(&adapter->erp_ready_head) && list_empty(&adapter->erp_running_head)) { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, + atomic_andnot(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); wake_up(&adapter->erp_done_wqh); } @@ -665,16 +665,16 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) int sleep = 1; struct zfcp_adapter *adapter = erp_action->adapter; - atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); + atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); for (retries = 7; retries; retries--) { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status); write_lock_irq(&adapter->erp_lock); zfcp_erp_action_to_running(erp_action); write_unlock_irq(&adapter->erp_lock); if (zfcp_fsf_exchange_config_data(erp_action)) { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status); return ZFCP_ERP_FAILED; } @@ -692,7 +692,7 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) sleep *= 2; } - atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status); if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK)) @@ -764,7 +764,7 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) /* all ports and LUNs are closed */ zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN); - atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | + atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); } @@ -773,7 +773,7 @@ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act) struct zfcp_adapter *adapter = act->adapter; if (zfcp_qdio_open(adapter->qdio)) { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | + atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); return ZFCP_ERP_FAILED; @@ -784,7 +784,7 @@ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act) return ZFCP_ERP_FAILED; } - atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status); + atomic_or(ZFCP_STATUS_COMMON_OPEN, &adapter->status); return ZFCP_ERP_SUCCEEDED; } @@ -948,7 +948,7 @@ static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, + atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_DENIED, &zfcp_sdev->status); } @@ -1187,18 +1187,18 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) switch (erp_action->action) { case ZFCP_ERP_ACTION_REOPEN_LUN: zfcp_sdev = sdev_to_zfcp(erp_action->sdev); - atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE, &zfcp_sdev->status); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: case ZFCP_ERP_ACTION_REOPEN_PORT: - atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE, &erp_action->port->status); break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE, &erp_action->adapter->status); break; } @@ -1422,19 +1422,19 @@ void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask) unsigned long flags; u32 common_mask = mask & ZFCP_COMMON_FLAGS; - atomic_set_mask(mask, &adapter->status); + atomic_or(mask, &adapter->status); if (!common_mask) return; read_lock_irqsave(&adapter->port_list_lock, flags); list_for_each_entry(port, &adapter->port_list, list) - atomic_set_mask(common_mask, &port->status); + atomic_or(common_mask, &port->status); read_unlock_irqrestore(&adapter->port_list_lock, flags); spin_lock_irqsave(adapter->scsi_host->host_lock, flags); __shost_for_each_device(sdev, adapter->scsi_host) - atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status); + atomic_or(common_mask, &sdev_to_zfcp(sdev)->status); spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags); } @@ -1453,7 +1453,7 @@ void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask) u32 common_mask = mask & ZFCP_COMMON_FLAGS; u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; - atomic_clear_mask(mask, &adapter->status); + atomic_andnot(mask, &adapter->status); if (!common_mask) return; @@ -1463,7 +1463,7 @@ void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask) read_lock_irqsave(&adapter->port_list_lock, flags); list_for_each_entry(port, &adapter->port_list, list) { - atomic_clear_mask(common_mask, &port->status); + atomic_andnot(common_mask, &port->status); if (clear_counter) atomic_set(&port->erp_counter, 0); } @@ -1471,7 +1471,7 @@ void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask) spin_lock_irqsave(adapter->scsi_host->host_lock, flags); __shost_for_each_device(sdev, adapter->scsi_host) { - atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status); + atomic_andnot(common_mask, &sdev_to_zfcp(sdev)->status); if (clear_counter) atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); } @@ -1491,7 +1491,7 @@ void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask) u32 common_mask = mask & ZFCP_COMMON_FLAGS; unsigned long flags; - atomic_set_mask(mask, &port->status); + atomic_or(mask, &port->status); if (!common_mask) return; @@ -1499,7 +1499,7 @@ void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask) spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); __shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) - atomic_set_mask(common_mask, + atomic_or(common_mask, &sdev_to_zfcp(sdev)->status); spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags); } @@ -1518,7 +1518,7 @@ void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask) u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; unsigned long flags; - atomic_clear_mask(mask, &port->status); + atomic_andnot(mask, &port->status); if (!common_mask) return; @@ -1529,7 +1529,7 @@ void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask) spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); __shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) { - atomic_clear_mask(common_mask, + atomic_andnot(common_mask, &sdev_to_zfcp(sdev)->status); if (clear_counter) atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); @@ -1546,7 +1546,7 @@ void zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - atomic_set_mask(mask, &zfcp_sdev->status); + atomic_or(mask, &zfcp_sdev->status); } /** @@ -1558,7 +1558,7 @@ void zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - atomic_clear_mask(mask, &zfcp_sdev->status); + atomic_andnot(mask, &zfcp_sdev->status); if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) atomic_set(&zfcp_sdev->erp_counter, 0); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 25d49f32ca63..237688af179b 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -508,7 +508,7 @@ static void zfcp_fc_adisc_handler(void *data) /* port is good, unblock rport without going through erp */ zfcp_scsi_schedule_rport_register(port); out: - atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + atomic_andnot(ZFCP_STATUS_PORT_LINK_TEST, &port->status); put_device(&port->dev); kmem_cache_free(zfcp_fc_req_cache, fc_req); } @@ -564,14 +564,14 @@ void zfcp_fc_link_test_work(struct work_struct *work) if (atomic_read(&port->status) & ZFCP_STATUS_PORT_LINK_TEST) goto out; - atomic_set_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + atomic_or(ZFCP_STATUS_PORT_LINK_TEST, &port->status); retval = zfcp_fc_adisc(port); if (retval == 0) return; /* send of ADISC was not possible */ - atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + atomic_andnot(ZFCP_STATUS_PORT_LINK_TEST, &port->status); zfcp_erp_port_forced_reopen(port, 0, "fcltwk1"); out: @@ -640,7 +640,7 @@ static void zfcp_fc_validate_port(struct zfcp_port *port, struct list_head *lh) if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)) return; - atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); + atomic_andnot(ZFCP_STATUS_COMMON_NOESC, &port->status); if ((port->supported_classes != 0) || !list_empty(&port->unit_list)) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 21ec5e2f584c..27b976aa1818 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -114,7 +114,7 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) return; - atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); + atomic_or(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); zfcp_scsi_schedule_rports_block(adapter); @@ -345,7 +345,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3"); break; case FSF_PROT_HOST_CONNECTION_INITIALIZING: - atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + atomic_or(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status); break; case FSF_PROT_DUPLICATE_REQUEST_ID: @@ -554,7 +554,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1"); return; } - atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, + atomic_or(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); break; case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: @@ -567,7 +567,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) /* avoids adapter shutdown to be able to recognize * events such as LINK UP */ - atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, + atomic_or(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); zfcp_fsf_link_down_info_eval(req, &qtcb->header.fsf_status_qual.link_down_info); @@ -1394,9 +1394,9 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) break; case FSF_GOOD: port->handle = header->port_handle; - atomic_set_mask(ZFCP_STATUS_COMMON_OPEN | + atomic_or(ZFCP_STATUS_COMMON_OPEN | ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); - atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED, + atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_BOXED, &port->status); /* check whether D_ID has changed during open */ /* @@ -1677,10 +1677,10 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) case FSF_PORT_BOXED: /* can't use generic zfcp_erp_modify_port_status because * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ - atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); + atomic_andnot(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + atomic_andnot(ZFCP_STATUS_COMMON_OPEN, &sdev_to_zfcp(sdev)->status); zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ACCESS_BOXED); zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, @@ -1700,10 +1700,10 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) /* can't use generic zfcp_erp_modify_port_status because * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ - atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); + atomic_andnot(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + atomic_andnot(ZFCP_STATUS_COMMON_OPEN, &sdev_to_zfcp(sdev)->status); break; } @@ -1766,7 +1766,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) zfcp_sdev = sdev_to_zfcp(sdev); - atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | + atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_DENIED | ZFCP_STATUS_COMMON_ACCESS_BOXED, &zfcp_sdev->status); @@ -1822,7 +1822,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) case FSF_GOOD: zfcp_sdev->lun_handle = header->lun_handle; - atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); + atomic_or(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); break; } } @@ -1913,7 +1913,7 @@ static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) } break; case FSF_GOOD: - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); + atomic_andnot(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); break; } } diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 495e1cb3afa6..dbf2b54703f7 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -349,7 +349,7 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio) /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ spin_lock_irq(&qdio->req_q_lock); - atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); + atomic_andnot(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); spin_unlock_irq(&qdio->req_q_lock); wake_up(&qdio->req_q_wq); @@ -384,7 +384,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) return -EIO; - atomic_clear_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, + atomic_andnot(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, &qdio->adapter->status); zfcp_qdio_setup_init_data(&init_data, qdio); @@ -396,14 +396,14 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) goto failed_qdio; if (ssqd.qdioac2 & CHSC_AC2_DATA_DIV_ENABLED) - atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED, + atomic_or(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED, &qdio->adapter->status); if (ssqd.qdioac2 & CHSC_AC2_MULTI_BUFFER_ENABLED) { - atomic_set_mask(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); + atomic_or(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER; } else { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); + atomic_andnot(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER - 1; } @@ -427,7 +427,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) /* set index of first available SBALS / number of available SBALS */ qdio->req_q_idx = 0; atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q); - atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); + atomic_or(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); if (adapter->scsi_host) { adapter->scsi_host->sg_tablesize = qdio->max_sbale_per_req; @@ -499,6 +499,6 @@ void zfcp_qdio_siosl(struct zfcp_adapter *adapter) rc = ccw_device_siosl(adapter->ccw_device); if (!rc) - atomic_set_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, + atomic_or(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, &adapter->status); } -- cgit v1.3-6-gb490 From d1aceb80c685b0735268fba296523f5d7264ff22 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 21 Jul 2015 14:45:40 +0900 Subject: gpio: remove unneeded initializer in gpiochip_add_to_list() This variable is used as an iterator and initialized in the list_for_each() loop. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 6d60ec2c9a79..b7e24780683a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -190,7 +190,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction); */ static int gpiochip_add_to_list(struct gpio_chip *chip) { - struct list_head *pos = &gpio_chips; + struct list_head *pos; struct gpio_chip *_chip; int err = 0; -- cgit v1.3-6-gb490 From ba53219809f4b3a08f21600a0f3b675620d518bc Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 24 Jul 2015 12:02:22 -0400 Subject: HID: core: do not reject devices when they declare too many usages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some device present proprietary collections with a usage min of 0x00 and a usage max of 0xffff. hid-core currently reject them while most of the time this is harmless. Let's ignore the exceeding usages, and hope for the best. Reported-by: Simon Wörner Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 157c62775053..b403fe2c5cbe 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -427,6 +427,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) { __u32 data; unsigned n; + __u32 count; data = item_udata(item); @@ -490,6 +491,24 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) if (item->size <= 2) data = (parser->global.usage_page << 16) + data; + count = data - parser->local.usage_minimum; + if (count + parser->local.usage_index >= HID_MAX_USAGES) { + /* + * We do not warn if the name is not set, we are + * actually pre-scanning the device. + */ + if (dev_name(&parser->device->dev)) + hid_warn(parser->device, + "ignoring exceeding usage max\n"); + data = HID_MAX_USAGES - parser->local.usage_index + + parser->local.usage_minimum - 1; + if (data <= 0) { + hid_err(parser->device, + "no more usage index available\n"); + return -1; + } + } + for (n = parser->local.usage_minimum; n <= data; n++) if (hid_add_usage(parser, n)) { dbg_hid("hid_add_usage failed\n"); -- cgit v1.3-6-gb490 From 2b38ca6d1aaf9149f1286c93b131f3e62c3ac63b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 21 Jul 2015 15:25:26 +0900 Subject: pinctrl: use dev_err() to show message in pinctrl_register_one_pin() Use dev_err() rather than pr_err() to display the error message. (Besides, dev_err() is already used 7 lines below in this function.) Also, drop the redundant information "on %s" because dev_err() shows which device the message is related to. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 8b8f3a04c353..69723e07036b 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -231,8 +231,7 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev, pindesc = pin_desc_get(pctldev, number); if (pindesc != NULL) { - pr_err("pin %d already registered on %s\n", number, - pctldev->desc->name); + dev_err(pctldev->dev, "pin %d already registered\n", number); return -EINVAL; } -- cgit v1.3-6-gb490 From e324957096dbf5bbf1491231c9912c3f5d0bc216 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 21 Jul 2015 15:25:27 +0900 Subject: pinctrl: use dev_err() to show message in pinmux_func_name_to_selector() Use dev_err() rather than pr_err() to display the error message. pinctrl_dev_get_name(pctldev) is no longer necessary because dev_err() shows which device the message is related to. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/pinmux.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index e7ae890dcf1a..67e08cb315c4 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -322,8 +322,7 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev, selector++; } - pr_err("%s does not support function %s\n", - pinctrl_dev_get_name(pctldev), function); + dev_err(pctldev->dev, "function '%s' not supported\n", function); return -EINVAL; } -- cgit v1.3-6-gb490 From 4dbada2be460dc5568fa27784ef626232c28061f Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 21 Jul 2015 18:26:51 +0200 Subject: gpio: omap: use raw locks for locking This patch converts gpio_bank.lock from a spin_lock into a raw_spin_lock. The call path is to access this lock is always under a raw_spin_lock, for instance - __setup_irq() holds &desc->lock with irq off + __irq_set_trigger() + omap_gpio_irq_type() - handle_level_irq() (runs with irqs off therefore raw locks) + mask_ack_irq() + omap_gpio_mask_irq() This fixes the obvious backtrace on -RT. However the locking vs context is not and this is not limited to -RT: - omap_gpio_irq_type() is called with IRQ off and has an conditional call to pm_runtime_get_sync() which may sleep. Either it may happen or it may not happen but pm_runtime_get_sync() should not be called with irqs off. - omap_gpio_debounce() is holding the lock with IRQs off. + omap2_set_gpio_debounce() + clk_prepare_enable() + clk_prepare() this one might sleep. The number of users of gpiod_set_debounce() / gpio_set_debounce() looks low but still this is not good. Acked-by: Javier Martinez Canillas Acked-by: Santosh Shilimkar Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 80 ++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 04ea23ba37cc..a2ff0eec5b36 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -57,7 +57,7 @@ struct gpio_bank { u32 saved_datain; u32 level_mask; u32 toggle_mask; - spinlock_t lock; + raw_spinlock_t lock; struct gpio_chip chip; struct clk *dbck; u32 mod_usage; @@ -498,17 +498,17 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); retval = omap_set_gpio_triggering(bank, offset, type); if (retval) goto error; omap_gpio_init_irq(bank, offset); if (!omap_gpio_is_input(bank, offset)) { - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); retval = -EINVAL; goto error; } - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) irq_set_handler_locked(d, handle_level_irq); @@ -634,14 +634,14 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset, return -EINVAL; } - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); if (enable) bank->context.wake_en |= gpio_bit; else bank->context.wake_en &= ~gpio_bit; writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -667,10 +667,10 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); omap_enable_gpio_module(bank, offset); bank->mod_usage |= BIT(offset); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -680,14 +680,14 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); bank->mod_usage &= ~(BIT(offset)); if (!LINE_USED(bank->irq_usage, offset)) { omap_set_gpio_direction(bank, offset, 1); omap_clear_gpio_debounce(bank, offset); } omap_disable_gpio_module(bank, offset); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); /* * If this is the last gpio to be freed in the bank, @@ -789,7 +789,7 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); if (!LINE_USED(bank->mod_usage, offset)) omap_set_gpio_direction(bank, offset, 1); @@ -798,12 +798,12 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) omap_enable_gpio_module(bank, offset); bank->irq_usage |= BIT(offset); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); omap_gpio_unmask_irq(d); return 0; err: - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); if (!BANK_USED(bank)) pm_runtime_put(bank->dev); return -EINVAL; @@ -815,7 +815,7 @@ static void omap_gpio_irq_shutdown(struct irq_data *d) unsigned long flags; unsigned offset = d->hwirq; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); bank->irq_usage &= ~(BIT(offset)); omap_set_gpio_irqenable(bank, offset, 0); omap_clear_gpio_irqstatus(bank, offset); @@ -823,7 +823,7 @@ static void omap_gpio_irq_shutdown(struct irq_data *d) if (!LINE_USED(bank->mod_usage, offset)) omap_clear_gpio_debounce(bank, offset); omap_disable_gpio_module(bank, offset); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); /* * If this is the last IRQ to be freed in the bank, @@ -847,10 +847,10 @@ static void omap_gpio_mask_irq(struct irq_data *d) unsigned offset = d->hwirq; unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); omap_set_gpio_irqenable(bank, offset, 0); omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); } static void omap_gpio_unmask_irq(struct irq_data *d) @@ -860,7 +860,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d) u32 trigger = irqd_get_trigger_type(d); unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); if (trigger) omap_set_gpio_triggering(bank, offset, trigger); @@ -872,7 +872,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d) } omap_set_gpio_irqenable(bank, offset, 1); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); } /*---------------------------------------------------------------------*/ @@ -885,9 +885,9 @@ static int omap_mpuio_suspend_noirq(struct device *dev) OMAP_MPUIO_GPIO_MASKIT / bank->stride; unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); writel_relaxed(0xffff & ~bank->context.wake_en, mask_reg); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -900,9 +900,9 @@ static int omap_mpuio_resume_noirq(struct device *dev) OMAP_MPUIO_GPIO_MASKIT / bank->stride; unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); writel_relaxed(bank->context.wake_en, mask_reg); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -948,9 +948,9 @@ static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset) bank = container_of(chip, struct gpio_bank, chip); reg = bank->base + bank->regs->direction; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); dir = !!(readl_relaxed(reg) & BIT(offset)); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return dir; } @@ -960,9 +960,9 @@ static int omap_gpio_input(struct gpio_chip *chip, unsigned offset) unsigned long flags; bank = container_of(chip, struct gpio_bank, chip); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); omap_set_gpio_direction(bank, offset, 1); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -984,10 +984,10 @@ static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value) unsigned long flags; bank = container_of(chip, struct gpio_bank, chip); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); bank->set_dataout(bank, offset, value); omap_set_gpio_direction(bank, offset, 0); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -999,9 +999,9 @@ static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset, bank = container_of(chip, struct gpio_bank, chip); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); omap2_set_gpio_debounce(bank, offset, debounce); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -1012,9 +1012,9 @@ static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value) unsigned long flags; bank = container_of(chip, struct gpio_bank, chip); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); bank->set_dataout(bank, offset, value); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); } /*---------------------------------------------------------------------*/ @@ -1210,7 +1210,7 @@ static int omap_gpio_probe(struct platform_device *pdev) else bank->set_dataout = omap_set_gpio_dataout_mask; - spin_lock_init(&bank->lock); + raw_spin_lock_init(&bank->lock); /* Static mapping, never released */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1268,7 +1268,7 @@ static int omap_gpio_runtime_suspend(struct device *dev) unsigned long flags; u32 wake_low, wake_hi; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); /* * Only edges can generate a wakeup event to the PRCM. @@ -1321,7 +1321,7 @@ update_gpio_context_count: bank->get_context_loss_count(bank->dev); omap_gpio_dbck_disable(bank); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -1336,7 +1336,7 @@ static int omap_gpio_runtime_resume(struct device *dev) unsigned long flags; int c; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); /* * On the first resume during the probe, the context has not @@ -1372,14 +1372,14 @@ static int omap_gpio_runtime_resume(struct device *dev) if (c != bank->context_loss_count) { omap_gpio_restore_context(bank); } else { - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } } } if (!bank->workaround_enabled) { - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -1434,7 +1434,7 @@ static int omap_gpio_runtime_resume(struct device *dev) } bank->workaround_enabled = false; - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } -- cgit v1.3-6-gb490 From 8cd14702be9bcb2ec45e1ec30af04aea9b965708 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Tue, 21 Jul 2015 11:08:50 +0200 Subject: gpio: rcar: Add r8a7795 (R-Car H3) support R-Car Gen3's GPIO blocks are identical to Gen2's in every respect. Signed-off-by: Ulrich Hecht Acked-by: Simon Horman Acked-by: Kuninori Morimoto Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt | 1 + drivers/gpio/gpio-rcar.c | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index 38fb86f28ba2..f60e2f477e93 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -9,6 +9,7 @@ Required Properties: - "renesas,gpio-r8a7791": for R8A7791 (R-Car M2-W) compatible GPIO controller. - "renesas,gpio-r8a7793": for R8A7793 (R-Car M2-N) compatible GPIO controller. - "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller. + - "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller. - "renesas,gpio-rcar": for generic R-Car GPIO controller. - reg: Base address and length of each memory resource used by the GPIO diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 4fc13ce9c60a..2a8122444614 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -341,6 +341,10 @@ static const struct of_device_id gpio_rcar_of_table[] = { }, { .compatible = "renesas,gpio-r8a7794", .data = &gpio_rcar_info_gen2, + }, { + .compatible = "renesas,gpio-r8a7795", + /* Gen3 GPIO is identical to Gen2. */ + .data = &gpio_rcar_info_gen2, }, { .compatible = "renesas,gpio-rcar", .data = &gpio_rcar_info_gen1, -- cgit v1.3-6-gb490 From d8323c6b03533ac870fb665277e6dad7ebf7e4d3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 27 Jul 2015 14:41:57 +0200 Subject: pinctrl: sunxi: Add custom irq_domain_ops The current interrupt parsing code was working by accident, because the default was actually parsing the first node of interrupts. While that was mostly working (and the flags were actually ignored), this binding has never been documented, and doesn't work with SoCs that have multiple interrupt banks anyway. Add a proper interrupt xlate function, that uses the same description than the GPIOs ( ), that will make things less confusing. The EINT number will still be used as the hwirq number, but won't be exposed through the DT. Signed-off-by: Maxime Ripard Reviewed-by: Hans de Goede Signed-off-by: Linus Walleij --- .../bindings/pinctrl/allwinner,sunxi-pinctrl.txt | 37 +++++++++++++++++++++- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 35 ++++++++++++++++++-- 2 files changed, 69 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt index 9462ab7ddd1f..3c821cda1ad0 100644 --- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt @@ -48,7 +48,7 @@ Optional subnode-properties: Examples: -pinctrl@01c20800 { +pio: pinctrl@01c20800 { compatible = "allwinner,sun5i-a13-pinctrl"; reg = <0x01c20800 0x400>; #address-cells = <1>; @@ -68,3 +68,38 @@ pinctrl@01c20800 { allwinner,pull = <0>; }; }; + + +GPIO and interrupt controller +----------------------------- + +This hardware also acts as a GPIO controller and an interrupt +controller. + +Consumers that would want to refer to one or the other (or both) +should provide through the usual *-gpios and interrupts properties a +cell with 3 arguments, first the number of the bank, then the pin +inside that bank, and finally the flags for the GPIO/interrupts. + +Example: + +xio: gpio@38 { + compatible = "nxp,pcf8574a"; + reg = <0x38>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-parent = <&pio>; + interrupts = <6 0 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; +}; + +reg_usb1_vbus: usb1-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb1-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&pio 7 6 GPIO_ACTIVE_HIGH>; +}; diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 7f7e7bb4f22c..fb4669c0ce0e 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -711,6 +711,37 @@ static struct irq_chip sunxi_pinctrl_level_irq_chip = { IRQCHIP_EOI_IF_HANDLED, }; +static int sunxi_pinctrl_irq_of_xlate(struct irq_domain *d, + struct device_node *node, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + struct sunxi_desc_function *desc; + int pin, base; + + if (intsize < 3) + return -EINVAL; + + base = PINS_PER_BANK * intspec[0]; + pin = base + intspec[1]; + + desc = sunxi_pinctrl_desc_find_function_by_pin(d->host_data, + pin, "irq"); + if (!desc) + return -EINVAL; + + *out_hwirq = desc->irqbank * PINS_PER_BANK + desc->irqnum; + *out_type = intspec[2]; + + return 0; +} + +static struct irq_domain_ops sunxi_pinctrl_irq_domain_ops = { + .xlate = sunxi_pinctrl_irq_of_xlate, +}; + static void sunxi_pinctrl_irq_handler(unsigned __irq, struct irq_desc *desc) { unsigned int irq = irq_desc_get_irq(desc); @@ -986,8 +1017,8 @@ int sunxi_pinctrl_init(struct platform_device *pdev, pctl->domain = irq_domain_add_linear(node, pctl->desc->irq_banks * IRQ_PER_BANK, - &irq_domain_simple_ops, - NULL); + &sunxi_pinctrl_irq_domain_ops, + pctl); if (!pctl->domain) { dev_err(&pdev->dev, "Couldn't register IRQ domain\n"); ret = -ENOMEM; -- cgit v1.3-6-gb490 From 1296fba1a397b173d45534885a0934a7c005d7e3 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 22 Jul 2015 15:05:17 +0200 Subject: gpio: etraxfs: fix set register flag BGPIO_F_UNREADABLE_REG_SET is incorrect, since the set register _is_ readable. What's really required is BGPIO_F_READ_OUTPUT_REG_SET: reading the set register reads the set output value. Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij --- drivers/gpio/gpio-etraxfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c index 0e643140efde..625a9ed411da 100644 --- a/drivers/gpio/gpio-etraxfs.c +++ b/drivers/gpio/gpio-etraxfs.c @@ -140,7 +140,7 @@ static int etraxfs_gpio_probe(struct platform_device *pdev) NULL, /* clr */ regs + port->oe, /* dirout */ NULL, /* dirin */ - BGPIOF_UNREADABLE_REG_SET); + BGPIOF_READ_OUTPUT_REG_SET); if (ret) return ret; -- cgit v1.3-6-gb490 From 91492a44b998cf762150de8f1b40bda1902e8ea7 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 22 Jul 2015 15:05:18 +0200 Subject: gpio: generic: support input-only chips Allow chips to indicates that they are input-only and thus cannot set the output value. This will be used by the gpio-etraxfs driver. Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 23 ++++++++++++++++++++--- include/linux/basic_mmio_gpio.h | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 802e6d2c64e9..a3f07537fe62 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -153,6 +153,10 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio)); } +static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val) +{ +} + static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct bgpio_chip *bgc = to_bgpio_chip(gc); @@ -279,6 +283,12 @@ static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) return 0; } +static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio, + int val) +{ + return -EINVAL; +} + static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { @@ -460,6 +470,9 @@ static int bgpio_setup_io(struct bgpio_chip *bgc, bgc->reg_set = set; bgc->gc.set = bgpio_set_set; bgc->gc.set_multiple = bgpio_set_multiple_set; + } else if (flags & BGPIOF_NO_OUTPUT) { + bgc->gc.set = bgpio_set_none; + bgc->gc.set_multiple = NULL; } else { bgc->gc.set = bgpio_set; bgc->gc.set_multiple = bgpio_set_multiple; @@ -476,7 +489,8 @@ static int bgpio_setup_io(struct bgpio_chip *bgc, static int bgpio_setup_direction(struct bgpio_chip *bgc, void __iomem *dirout, - void __iomem *dirin) + void __iomem *dirin, + unsigned long flags) { if (dirout && dirin) { return -EINVAL; @@ -491,7 +505,10 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc, bgc->gc.direction_input = bgpio_dir_in_inv; bgc->gc.get_direction = bgpio_get_dir_inv; } else { - bgc->gc.direction_output = bgpio_simple_dir_out; + if (flags & BGPIOF_NO_OUTPUT) + bgc->gc.direction_output = bgpio_dir_out_err; + else + bgc->gc.direction_output = bgpio_simple_dir_out; bgc->gc.direction_input = bgpio_simple_dir_in; } @@ -543,7 +560,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, if (ret) return ret; - ret = bgpio_setup_direction(bgc, dirout, dirin); + ret = bgpio_setup_direction(bgc, dirout, dirin, flags); if (ret) return ret; diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h index 14eea946e640..ed3768f4ecc7 100644 --- a/include/linux/basic_mmio_gpio.h +++ b/include/linux/basic_mmio_gpio.h @@ -75,5 +75,6 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, #define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */ #define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3) #define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */ +#define BGPIOF_NO_OUTPUT BIT(5) /* only input */ #endif /* __BASIC_MMIO_GPIO_H */ -- cgit v1.3-6-gb490 From d705073cdafa75286970dd30f722d0df584bae54 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 22 Jul 2015 15:05:19 +0200 Subject: gpio: etraxfs: add support for ARTPEC-3 Add support for the GIO block in the ARTPEC-3 SoC. The basic functionality is essentialy the same as the version in the ETRAX FS, except for a different set of ports, including a read-only port. Cc: devicetree@vger.kernel.org Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-etraxfs.txt | 3 +- drivers/gpio/gpio-etraxfs.c | 66 ++++++++++++++++++++-- 2 files changed, 62 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt b/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt index abf4db736c6e..170194af3027 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt @@ -2,8 +2,9 @@ Axis ETRAX FS General I/O controller bindings Required properties: -- compatible: +- compatible: one of: - "axis,etraxfs-gio" + - "axis,artpec3-gio" - reg: Physical base address and length of the controller's registers. - #gpio-cells: Should be 3 - The first cell is the gpio offset number. diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c index 625a9ed411da..27e5d8855205 100644 --- a/drivers/gpio/gpio-etraxfs.c +++ b/drivers/gpio/gpio-etraxfs.c @@ -26,6 +26,17 @@ #define ETRAX_FS_r_pe_din 84 #define ETRAX_FS_rw_pe_oe 88 +#define ARTPEC3_r_pa_din 0 +#define ARTPEC3_rw_pa_dout 4 +#define ARTPEC3_rw_pa_oe 8 +#define ARTPEC3_r_pb_din 44 +#define ARTPEC3_rw_pb_dout 48 +#define ARTPEC3_rw_pb_oe 52 +#define ARTPEC3_r_pc_din 88 +#define ARTPEC3_rw_pc_dout 92 +#define ARTPEC3_rw_pc_oe 96 +#define ARTPEC3_r_pd_din 116 + struct etraxfs_gpio_port { const char *label; unsigned int oe; @@ -82,6 +93,40 @@ static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = { .ports = etraxfs_gpio_etraxfs_ports, }; +static const struct etraxfs_gpio_port etraxfs_gpio_artpec3_ports[] = { + { + .label = "A", + .ngpio = 32, + .oe = ARTPEC3_rw_pa_oe, + .dout = ARTPEC3_rw_pa_dout, + .din = ARTPEC3_r_pa_din, + }, + { + .label = "B", + .ngpio = 32, + .oe = ARTPEC3_rw_pb_oe, + .dout = ARTPEC3_rw_pb_dout, + .din = ARTPEC3_r_pb_din, + }, + { + .label = "C", + .ngpio = 16, + .oe = ARTPEC3_rw_pc_oe, + .dout = ARTPEC3_rw_pc_dout, + .din = ARTPEC3_r_pc_din, + }, + { + .label = "D", + .ngpio = 32, + .din = ARTPEC3_r_pd_din, + }, +}; + +static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = { + .num_ports = ARRAY_SIZE(etraxfs_gpio_artpec3_ports), + .ports = etraxfs_gpio_artpec3_ports, +}; + static int etraxfs_gpio_of_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags) @@ -101,6 +146,10 @@ static const struct of_device_id etraxfs_gpio_of_table[] = { .compatible = "axis,etraxfs-gio", .data = &etraxfs_gpio_etraxfs, }, + { + .compatible = "axis,artpec3-gio", + .data = &etraxfs_gpio_artpec3, + }, {}, }; @@ -133,14 +182,19 @@ static int etraxfs_gpio_probe(struct platform_device *pdev) for (i = 0; i < info->num_ports; i++) { struct bgpio_chip *bgc = &chips[i]; const struct etraxfs_gpio_port *port = &info->ports[i]; + unsigned long flags = BGPIOF_READ_OUTPUT_REG_SET; + void __iomem *dat = regs + port->din; + void __iomem *set = regs + port->dout; + void __iomem *dirout = regs + port->oe; + + if (dirout == set) { + dirout = set = NULL; + flags = BGPIOF_NO_OUTPUT; + } ret = bgpio_init(bgc, dev, 4, - regs + port->din, /* dat */ - regs + port->dout, /* set */ - NULL, /* clr */ - regs + port->oe, /* dirout */ - NULL, /* dirin */ - BGPIOF_READ_OUTPUT_REG_SET); + dat, set, NULL, dirout, NULL, + flags); if (ret) return ret; -- cgit v1.3-6-gb490 From ee04139d916a61454850f3e3c687f50f891fc8bd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 23 Jul 2015 09:09:49 +0200 Subject: pinctrl/ARM: move GPIO and pinctrl deps to device tree This gets the GPIO ranges out of the driver and into the device tree where they belong. Standard DT bindings already exist for this. Since no systems with this are deployed we can just augment all device trees and the drivers at the same time and simplify the world. This also defines the array of GPIO chips related to the pin controller. Cc: arm@kernel.org Acked-by: Olof Johansson Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-dbx5x0.dtsi | 23 ++++++++++++---------- arch/arm/boot/dts/ste-nomadik-stn8815.dtsi | 8 +++++++- drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c | 21 -------------------- drivers/pinctrl/nomadik/pinctrl-nomadik-db8540.c | 24 ----------------------- drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c | 16 --------------- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 17 ---------------- drivers/pinctrl/nomadik/pinctrl-nomadik.h | 4 ---- 7 files changed, 20 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index 853684ad7773..b8fadb1d8616 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -286,7 +286,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <0>; - + gpio-ranges = <&pinctrl 0 0 32>; clocks = <&prcc_pclk 1 9>; }; @@ -301,7 +301,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <1>; - + gpio-ranges = <&pinctrl 0 32 5>; clocks = <&prcc_pclk 1 9>; }; @@ -316,7 +316,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <2>; - + gpio-ranges = <&pinctrl 0 64 32>; clocks = <&prcc_pclk 3 8>; }; @@ -331,7 +331,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <3>; - + gpio-ranges = <&pinctrl 0 96 2>; clocks = <&prcc_pclk 3 8>; }; @@ -346,7 +346,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <4>; - + gpio-ranges = <&pinctrl 0 128 32>; clocks = <&prcc_pclk 3 8>; }; @@ -361,7 +361,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <5>; - + gpio-ranges = <&pinctrl 0 160 12>; clocks = <&prcc_pclk 3 8>; }; @@ -376,7 +376,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <6>; - + gpio-ranges = <&pinctrl 0 192 32>; clocks = <&prcc_pclk 2 11>; }; @@ -391,7 +391,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <7>; - + gpio-ranges = <&pinctrl 0 224 7>; clocks = <&prcc_pclk 2 11>; }; @@ -406,12 +406,15 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <8>; - + gpio-ranges = <&pinctrl 0 256 12>; clocks = <&prcc_pclk 5 1>; }; - pinctrl { + pinctrl: pinctrl { compatible = "stericsson,db8500-pinctrl"; + nomadik-gpio-chips = <&gpio0>, <&gpio1>, <&gpio2>, <&gpio3>, + <&gpio4>, <&gpio5>, <&gpio6>, <&gpio7>, + <&gpio8>; prcm = <&prcmu>; }; diff --git a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi index 9a5f2ba139b7..6846e3eb027d 100644 --- a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi +++ b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi @@ -52,6 +52,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <0>; + gpio-ranges = <&pinctrl 0 0 32>; clocks = <&pclk>; }; @@ -65,6 +66,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <1>; + gpio-ranges = <&pinctrl 0 32 32>; clocks = <&pclk>; }; @@ -78,12 +80,14 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <2>; + gpio-ranges = <&pinctrl 0 64 32>; clocks = <&pclk>; }; gpio3: gpio@101e7000 { compatible = "st,nomadik-gpio"; reg = <0x101e7000 0x80>; + ngpio = <28>; interrupt-parent = <&vica>; interrupts = <9>; interrupt-controller; @@ -91,11 +95,13 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <3>; + gpio-ranges = <&pinctrl 0 96 28>; clocks = <&pclk>; }; - pinctrl { + pinctrl: pinctrl { compatible = "stericsson,stn8815-pinctrl"; + nomadik-gpio-chips = <&gpio0>, <&gpio1>, <&gpio2>, <&gpio3>; /* Pin configurations */ uart0 { uart0_default_mux: uart0_mux { diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c index c74840729648..8392083514fb 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c @@ -355,25 +355,6 @@ static const struct pinctrl_pin_desc nmk_db8500_pins[] = { PINCTRL_PIN(DB8500_PIN_AC27, "GPIO267_AC27"), }; -#define DB8500_GPIO_RANGE(a, b, c) { .name = "DB8500", .id = a, .base = b, \ - .pin_base = b, .npins = c } - -/* - * This matches the 32-pin gpio chips registered by the GPIO portion. This - * cannot be const since we assign the struct gpio_chip * pointer at runtime. - */ -static struct pinctrl_gpio_range nmk_db8500_ranges[] = { - DB8500_GPIO_RANGE(0, 0, 32), - DB8500_GPIO_RANGE(1, 32, 5), - DB8500_GPIO_RANGE(2, 64, 32), - DB8500_GPIO_RANGE(3, 96, 2), - DB8500_GPIO_RANGE(4, 128, 32), - DB8500_GPIO_RANGE(5, 160, 12), - DB8500_GPIO_RANGE(6, 192, 32), - DB8500_GPIO_RANGE(7, 224, 7), - DB8500_GPIO_RANGE(8, 256, 12), -}; - /* * Read the pin group names like this: * u0_a_1 = first groups of pins for uart0 on alt function a @@ -1238,8 +1219,6 @@ static const u16 db8500_prcm_gpiocr_regs[] = { }; static const struct nmk_pinctrl_soc_data nmk_db8500_soc = { - .gpio_ranges = nmk_db8500_ranges, - .gpio_num_ranges = ARRAY_SIZE(nmk_db8500_ranges), .pins = nmk_db8500_pins, .npins = ARRAY_SIZE(nmk_db8500_pins), .functions = nmk_db8500_functions, diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-db8540.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8540.c index d7ba5443bae0..2860eafd1b42 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik-db8540.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8540.c @@ -341,28 +341,6 @@ static const struct pinctrl_pin_desc nmk_db8540_pins[] = { PINCTRL_PIN(DB8540_PIN_D17, "GPIO267_D17"), }; -#define DB8540_GPIO_RANGE(a, b, c) { .name = "db8540", .id = a, .base = b, \ - .pin_base = b, .npins = c } - -/* - * This matches the 32-pin gpio chips registered by the GPIO portion. This - * cannot be const since we assign the struct gpio_chip * pointer at runtime. - */ -static struct pinctrl_gpio_range nmk_db8540_ranges[] = { - DB8540_GPIO_RANGE(0, 0, 18), - DB8540_GPIO_RANGE(0, 22, 7), - DB8540_GPIO_RANGE(1, 33, 6), - DB8540_GPIO_RANGE(2, 64, 4), - DB8540_GPIO_RANGE(2, 70, 18), - DB8540_GPIO_RANGE(3, 116, 12), - DB8540_GPIO_RANGE(4, 128, 32), - DB8540_GPIO_RANGE(5, 160, 9), - DB8540_GPIO_RANGE(6, 192, 23), - DB8540_GPIO_RANGE(6, 219, 5), - DB8540_GPIO_RANGE(7, 224, 9), - DB8540_GPIO_RANGE(8, 256, 12), -}; - /* * Read the pin group names like this: * u0_a_1 = first groups of pins for uart0 on alt function a @@ -1247,8 +1225,6 @@ static const u16 db8540_prcm_gpiocr_regs[] = { }; static const struct nmk_pinctrl_soc_data nmk_db8540_soc = { - .gpio_ranges = nmk_db8540_ranges, - .gpio_num_ranges = ARRAY_SIZE(nmk_db8540_ranges), .pins = nmk_db8540_pins, .npins = ARRAY_SIZE(nmk_db8540_pins), .functions = nmk_db8540_functions, diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c index 2cd71470f270..a2de3b7a57a0 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c @@ -264,20 +264,6 @@ static const struct pinctrl_pin_desc nmk_stn8815_pins[] = { PINCTRL_PIN(STN8815_PIN_J22, "GPIO123_J22"), }; -#define STN8815_GPIO_RANGE(a, b, c) { .name = "STN8815", .id = a, .base = b, \ - .pin_base = b, .npins = c } - -/* - * This matches the 32-pin gpio chips registered by the GPIO portion. This - * cannot be const since we assign the struct gpio_chip * pointer at runtime. - */ -static struct pinctrl_gpio_range nmk_stn8815_ranges[] = { - STN8815_GPIO_RANGE(0, 0, 32), - STN8815_GPIO_RANGE(1, 32, 32), - STN8815_GPIO_RANGE(2, 64, 32), - STN8815_GPIO_RANGE(3, 96, 28), -}; - /* * Read the pin group names like this: * u0_a_1 = first groups of pins for uart0 on alt function a @@ -342,8 +328,6 @@ static const struct nmk_function nmk_stn8815_functions[] = { }; static const struct nmk_pinctrl_soc_data nmk_stn8815_soc = { - .gpio_ranges = nmk_stn8815_ranges, - .gpio_num_ranges = ARRAY_SIZE(nmk_stn8815_ranges), .pins = nmk_stn8815_pins, .npins = ARRAY_SIZE(nmk_stn8815_pins), .functions = nmk_stn8815_functions, diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 143d1c06078c..8c87b2ec29c1 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -2058,19 +2058,6 @@ static int nmk_pinctrl_probe(struct platform_device *pdev) } } - /* - * We need all the GPIO drivers to probe FIRST, or we will not be able - * to obtain references to the struct gpio_chip * for them, and we - * need this to proceed. - */ - for (i = 0; i < npct->soc->gpio_num_ranges; i++) { - if (!nmk_gpio_chips[npct->soc->gpio_ranges[i].id]) { - dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i); - return -EPROBE_DEFER; - } - npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[npct->soc->gpio_ranges[i].id]->chip; - } - nmk_pinctrl_desc.pins = npct->soc->pins; nmk_pinctrl_desc.npins = npct->soc->npins; npct->dev = &pdev->dev; @@ -2081,10 +2068,6 @@ static int nmk_pinctrl_probe(struct platform_device *pdev) return PTR_ERR(npct->pctl); } - /* We will handle a range of GPIO pins */ - for (i = 0; i < npct->soc->gpio_num_ranges; i++) - pinctrl_add_gpio_range(npct->pctl, &npct->soc->gpio_ranges[i]); - platform_set_drvdata(pdev, npct); dev_info(&pdev->dev, "initialized Nomadik pin control driver\n"); diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.h b/drivers/pinctrl/nomadik/pinctrl-nomadik.h index d8215f1e70c7..30bba2a75a58 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.h +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.h @@ -121,8 +121,6 @@ struct nmk_pingroup { /** * struct nmk_pinctrl_soc_data - Nomadik pin controller per-SoC configuration - * @gpio_ranges: An array of GPIO ranges for this SoC - * @gpio_num_ranges: The number of GPIO ranges for this SoC * @pins: An array describing all pins the pin controller affects. * All pins which are also GPIOs must be listed first within the * array, and be numbered identically to the GPIO controller's @@ -137,8 +135,6 @@ struct nmk_pingroup { * @prcm_gpiocr_registers: The array of PRCM GPIOCR registers on this SoC */ struct nmk_pinctrl_soc_data { - struct pinctrl_gpio_range *gpio_ranges; - unsigned gpio_num_ranges; const struct pinctrl_pin_desc *pins; unsigned npins; const struct nmk_function *functions; -- cgit v1.3-6-gb490 From 802bb9b67de75ea75638b8b1ca4b21a76a03bebf Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 22 Jul 2015 19:21:13 +0200 Subject: pinctrl: nomadik: depromote GPIO to subsystem_init() We no longer have to do GPIO initialization before the pinctrl initialization, instead we can initialize the pinctrl portions of the driver first and then the GPIO. Thus we can move GPIO initialization to a subsystem_initcall(), but not yet to a device_initcall(). Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 8c87b2ec29c1..181fa546b298 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -2102,15 +2102,15 @@ static struct platform_driver nmk_pinctrl_driver = { static int __init nmk_gpio_init(void) { - int ret; + return platform_driver_register(&nmk_gpio_driver); +} +subsys_initcall(nmk_gpio_init); - ret = platform_driver_register(&nmk_gpio_driver); - if (ret) - return ret; +static int __init nmk_pinctrl_init(void) +{ return platform_driver_register(&nmk_pinctrl_driver); } - -core_initcall(nmk_gpio_init); +core_initcall(nmk_pinctrl_init); MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini"); MODULE_DESCRIPTION("Nomadik GPIO Driver"); -- cgit v1.3-6-gb490 From 3309aa494186b0c5364d812ae000955262590655 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Mon, 27 Jul 2015 14:59:06 +0800 Subject: power/reset: zx: Remove unnecessary include file Including ARM related header file cause build failure in i386 build because COMILE_TEST also involve building zx driver. Remove the unnecessary include file. Signed-off-by: Jun Nie Signed-off-by: Sebastian Reichel --- drivers/power/reset/zx-reboot.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c index cf4b973dcedf..a5b009673d0e 100644 --- a/drivers/power/reset/zx-reboot.c +++ b/drivers/power/reset/zx-reboot.c @@ -18,8 +18,6 @@ #include #include -#include - static void __iomem *base; static void __iomem *pcu_base; -- cgit v1.3-6-gb490 From 71a5a508436332ac40f688ef06e61628f25f3e5b Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Sat, 25 Jul 2015 09:23:16 +0530 Subject: power_supply: bq24735: Convert to using managed resources Use managed resource functions like devm_kasprintf and devm_power_supply_register in bq24735_charger_probe. To be compatible with the change, replace various gotos by direct returns and drop unneeded labels. Also, remove bq24735_charger_remove as it is now redundant. Signed-off-by: Vaishali Thakkar Signed-off-by: Sebastian Reichel --- drivers/power/bq24735-charger.c | 51 +++++++++++------------------------------ 1 file changed, 13 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq24735-charger.c b/drivers/power/bq24735-charger.c index b0174379713c..eb2b3689de97 100644 --- a/drivers/power/bq24735-charger.c +++ b/drivers/power/bq24735-charger.c @@ -267,8 +267,9 @@ static int bq24735_charger_probe(struct i2c_client *client, name = (char *)charger->pdata->name; if (!name) { - name = kasprintf(GFP_KERNEL, "bq24735@%s", - dev_name(&client->dev)); + name = devm_kasprintf(&client->dev, GFP_KERNEL, + "bq24735@%s", + dev_name(&client->dev)); if (!name) { dev_err(&client->dev, "Failed to alloc device name\n"); return -ENOMEM; @@ -296,23 +297,21 @@ static int bq24735_charger_probe(struct i2c_client *client, if (ret < 0) { dev_err(&client->dev, "Failed to read manufacturer id : %d\n", ret); - goto err_free_name; + return ret; } else if (ret != 0x0040) { dev_err(&client->dev, "manufacturer id mismatch. 0x0040 != 0x%04x\n", ret); - ret = -ENODEV; - goto err_free_name; + return -ENODEV; } ret = bq24735_read_word(client, BQ24735_DEVICE_ID); if (ret < 0) { dev_err(&client->dev, "Failed to read device id : %d\n", ret); - goto err_free_name; + return ret; } else if (ret != 0x000B) { dev_err(&client->dev, "device id mismatch. 0x000b != 0x%04x\n", ret); - ret = -ENODEV; - goto err_free_name; + return -ENODEV; } if (gpio_is_valid(charger->pdata->status_gpio)) { @@ -331,7 +330,7 @@ static int bq24735_charger_probe(struct i2c_client *client, ret = bq24735_config_charger(charger); if (ret < 0) { dev_err(&client->dev, "failed in configuring charger"); - goto err_free_name; + return ret; } /* check for AC adapter presence */ @@ -339,17 +338,17 @@ static int bq24735_charger_probe(struct i2c_client *client, ret = bq24735_enable_charging(charger); if (ret < 0) { dev_err(&client->dev, "Failed to enable charging\n"); - goto err_free_name; + return ret; } } - charger->charger = power_supply_register(&client->dev, supply_desc, - &psy_cfg); + charger->charger = devm_power_supply_register(&client->dev, supply_desc, + &psy_cfg); if (IS_ERR(charger->charger)) { ret = PTR_ERR(charger->charger); dev_err(&client->dev, "Failed to register power supply: %d\n", ret); - goto err_free_name; + return ret; } if (client->irq) { @@ -364,33 +363,10 @@ static int bq24735_charger_probe(struct i2c_client *client, dev_err(&client->dev, "Unable to register IRQ %d err %d\n", client->irq, ret); - goto err_unregister_supply; + return ret; } } - return 0; -err_unregister_supply: - power_supply_unregister(charger->charger); -err_free_name: - if (name != charger->pdata->name) - kfree(name); - - return ret; -} - -static int bq24735_charger_remove(struct i2c_client *client) -{ - struct bq24735 *charger = i2c_get_clientdata(client); - - if (charger->client->irq) - devm_free_irq(&charger->client->dev, charger->client->irq, - &charger->charger); - - power_supply_unregister(charger->charger); - - if (charger->charger_desc.name != charger->pdata->name) - kfree(charger->charger_desc.name); - return 0; } @@ -412,7 +388,6 @@ static struct i2c_driver bq24735_charger_driver = { .of_match_table = bq24735_match_ids, }, .probe = bq24735_charger_probe, - .remove = bq24735_charger_remove, .id_table = bq24735_charger_id, }; -- cgit v1.3-6-gb490 From 613d2b272177c61c7cdb83be75a6e4c378d50ff9 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jul 2015 13:28:58 +0200 Subject: drm/atomic: pass old crtc state to atomic_begin/flush. In intel it's useful to keep track of some state changes with old crtc state vs new state, for example to disable initial planes or when a modeset's prevented during fastboot. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira [danvet: squash in fixup for exynos provided by Maarten.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 6 ++++-- drivers/gpu/drm/drm_atomic_helper.c | 8 ++++---- drivers/gpu/drm/drm_plane_helper.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 6 ++++-- drivers/gpu/drm/i915/intel_display.c | 10 ++++++---- drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c | 6 ++++-- drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 6 ++++-- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 6 ++++-- drivers/gpu/drm/sti/sti_drm_crtc.c | 6 ++++-- drivers/gpu/drm/tegra/dc.c | 6 ++++-- include/drm/drm_crtc_helper.h | 6 ++++-- 11 files changed, 44 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index f69b92535505..8b8fe3762ca9 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -239,7 +239,8 @@ static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c, return atmel_hlcdc_plane_prepare_disc_area(s); } -static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c) +static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c, + struct drm_crtc_state *old_s) { struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); @@ -253,7 +254,8 @@ static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c) } } -static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc) +static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_s) { /* TODO: write common plane control register if available */ } diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 10bcdd554501..5ec13c7cc832 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1164,7 +1164,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, if (!funcs || !funcs->atomic_begin) continue; - funcs->atomic_begin(crtc); + funcs->atomic_begin(crtc, old_crtc_state); } for_each_plane_in_state(old_state, plane, old_plane_state, i) { @@ -1194,7 +1194,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, if (!funcs || !funcs->atomic_flush) continue; - funcs->atomic_flush(crtc); + funcs->atomic_flush(crtc, old_crtc_state); } } EXPORT_SYMBOL(drm_atomic_helper_commit_planes); @@ -1230,7 +1230,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) crtc_funcs = crtc->helper_private; if (crtc_funcs && crtc_funcs->atomic_begin) - crtc_funcs->atomic_begin(crtc); + crtc_funcs->atomic_begin(crtc, old_crtc_state); drm_for_each_plane_mask(plane, crtc->dev, plane_mask) { struct drm_plane_state *old_plane_state = @@ -1253,7 +1253,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) } if (crtc_funcs && crtc_funcs->atomic_flush) - crtc_funcs->atomic_flush(crtc); + crtc_funcs->atomic_flush(crtc, old_crtc_state); } EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc); diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 46c704573306..5e5a07af02c8 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -437,7 +437,7 @@ int drm_plane_helper_commit(struct drm_plane *plane, for (i = 0; i < 2; i++) { if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin) - crtc_funcs[i]->atomic_begin(crtc[i]); + crtc_funcs[i]->atomic_begin(crtc[i], crtc[i]->state); } /* @@ -452,7 +452,7 @@ int drm_plane_helper_commit(struct drm_plane *plane, for (i = 0; i < 2; i++) { if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush) - crtc_funcs[i]->atomic_flush(crtc[i]); + crtc_funcs[i]->atomic_flush(crtc[i], crtc[i]->state); } /* diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 644b4b76e071..1610757230a5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -80,7 +80,8 @@ exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) exynos_crtc->ops->commit(exynos_crtc); } -static void exynos_crtc_atomic_begin(struct drm_crtc *crtc) +static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); @@ -90,7 +91,8 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc) } } -static void exynos_crtc_atomic_flush(struct drm_crtc *crtc) +static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 07cee59edece..40c73da2abcf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -102,8 +102,8 @@ static void vlv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); static void chv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); -static void intel_begin_crtc_commit(struct drm_crtc *crtc); -static void intel_finish_crtc_commit(struct drm_crtc *crtc); +static void intel_begin_crtc_commit(struct drm_crtc *, struct drm_crtc_state *); +static void intel_finish_crtc_commit(struct drm_crtc *, struct drm_crtc_state *); static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state); static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state, @@ -13628,7 +13628,8 @@ intel_disable_primary_plane(struct drm_plane *plane, dev_priv->display.update_primary_plane(crtc, NULL, 0, 0); } -static void intel_begin_crtc_commit(struct drm_crtc *crtc) +static void intel_begin_crtc_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -13644,7 +13645,8 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) skl_detach_scalers(intel_crtc); } -static void intel_finish_crtc_commit(struct drm_crtc *crtc) +static void intel_finish_crtc_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index c4bb9d9c7667..4dc158ed2e95 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -334,13 +334,15 @@ static int mdp4_crtc_atomic_check(struct drm_crtc *crtc, return 0; } -static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc) +static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); DBG("%s: begin", mdp4_crtc->name); } -static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc) +static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); struct drm_device *dev = crtc->dev; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index dea3d2e559b1..4c1df4e6e5bc 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -388,13 +388,15 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, return 0; } -static void mdp5_crtc_atomic_begin(struct drm_crtc *crtc) +static void mdp5_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); DBG("%s: begin", mdp5_crtc->name); } -static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc) +static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); struct drm_device *dev = crtc->dev; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 65d6ba6621ac..48cb19949ca3 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -496,7 +496,8 @@ static bool rcar_du_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc) +static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct drm_pending_vblank_event *event = crtc->state->event; struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); @@ -512,7 +513,8 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc) } } -static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc) +static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c index 6b641c5a2ec7..26e63bf14efe 100644 --- a/drivers/gpu/drm/sti/sti_drm_crtc.c +++ b/drivers/gpu/drm/sti/sti_drm_crtc.c @@ -164,7 +164,8 @@ sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode); } -static void sti_drm_atomic_begin(struct drm_crtc *crtc) +static void sti_drm_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct sti_mixer *mixer = to_sti_mixer(crtc); @@ -178,7 +179,8 @@ static void sti_drm_atomic_begin(struct drm_crtc *crtc) } } -static void sti_drm_atomic_flush(struct drm_crtc *crtc) +static void sti_drm_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { } diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index a287e4fec865..bf8ef3133e5b 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1277,7 +1277,8 @@ static int tegra_crtc_atomic_check(struct drm_crtc *crtc, return 0; } -static void tegra_crtc_atomic_begin(struct drm_crtc *crtc) +static void tegra_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct tegra_dc *dc = to_tegra_dc(crtc); @@ -1291,7 +1292,8 @@ static void tegra_crtc_atomic_begin(struct drm_crtc *crtc) } } -static void tegra_crtc_atomic_flush(struct drm_crtc *crtc) +static void tegra_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct tegra_dc_state *state = to_dc_state(crtc->state); struct tegra_dc *dc = to_tegra_dc(crtc); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index c8fc187061de..01cafcbe7deb 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -108,8 +108,10 @@ struct drm_crtc_helper_funcs { /* atomic helpers */ int (*atomic_check)(struct drm_crtc *crtc, struct drm_crtc_state *state); - void (*atomic_begin)(struct drm_crtc *crtc); - void (*atomic_flush)(struct drm_crtc *crtc); + void (*atomic_begin)(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state); + void (*atomic_flush)(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state); }; /** -- cgit v1.3-6-gb490 From 9a69a9ac20f7f3435dd18019f902351c61a9ad1d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jul 2015 11:34:55 +0200 Subject: drm: Make the connector dpms callback return a value, v2. This is required to properly handle failing dpms calls. When making a wait in i915 interruptible, I've noticed that the dpms sequence could fail with -ERESTARTSYS because it was waiting interruptibly for flips. So from now on allow drivers to fail in their connector dpms callback. Encoder and crtc dpms callbacks are unaffected. Changes since v1: - Update kerneldoc for the drm helper functions. Signed-off-by: Maarten Lankhorst [danvet: Resolve conflicts due to different merge order.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 28 ++++++++++++++++------------ drivers/gpu/drm/drm_crtc.c | 4 ++-- drivers/gpu/drm/drm_crtc_helper.c | 9 ++++++--- drivers/gpu/drm/i915/intel_crt.c | 8 +++++--- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_dvo.c | 8 +++++--- drivers/gpu/drm/i915/intel_sdvo.c | 8 +++++--- drivers/gpu/drm/nouveau/nouveau_connector.c | 4 ++-- drivers/gpu/drm/radeon/radeon_dp_mst.c | 3 ++- drivers/gpu/drm/tegra/dsi.c | 3 ++- drivers/gpu/drm/tegra/hdmi.c | 5 +++-- drivers/gpu/drm/tegra/rgb.c | 5 +++-- drivers/gpu/drm/tegra/sor.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 2 +- include/drm/drm_atomic_helper.h | 4 ++-- include/drm/drm_crtc.h | 2 +- include/drm/drm_crtc_helper.h | 2 +- 19 files changed, 65 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 5ec13c7cc832..57847ae8ce8c 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1974,9 +1974,12 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip); * implementing the legacy DPMS connector interface. It computes the new desired * ->active state for the corresponding CRTC (if the connector is enabled) and * updates it. + * + * Returns: + * Returns 0 on success, negative errno numbers on failure. */ -void drm_atomic_helper_connector_dpms(struct drm_connector *connector, - int mode) +int drm_atomic_helper_connector_dpms(struct drm_connector *connector, + int mode) { struct drm_mode_config *config = &connector->dev->mode_config; struct drm_atomic_state *state; @@ -1985,6 +1988,7 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector, struct drm_connector *tmp_connector; int ret; bool active = false; + int old_mode = connector->dpms; if (mode != DRM_MODE_DPMS_ON) mode = DRM_MODE_DPMS_OFF; @@ -1993,18 +1997,19 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector, crtc = connector->state->crtc; if (!crtc) - return; + return 0; - /* FIXME: ->dpms has no return value so can't forward the -ENOMEM. */ state = drm_atomic_state_alloc(connector->dev); if (!state) - return; + return -ENOMEM; state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); retry: crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return; + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto fail; + } WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); @@ -2023,17 +2028,16 @@ retry: if (ret != 0) goto fail; - /* Driver takes ownership of state on successful async commit. */ - return; + /* Driver takes ownership of state on successful commit. */ + return 0; fail: if (ret == -EDEADLK) goto backoff; + connector->dpms = old_mode; drm_atomic_state_free(state); - WARN(1, "Driver bug: Changing ->active failed with ret=%i\n", ret); - - return; + return ret; backoff: drm_atomic_state_clear(state); drm_atomic_legacy_backoff(state); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 1f0da41ae2a1..dfac394d0602 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4753,9 +4753,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, /* Do DPMS ourselves */ if (property == connector->dev->mode_config.dpms_property) { - if (connector->funcs->dpms) - (*connector->funcs->dpms)(connector, (int)value); ret = 0; + if (connector->funcs->dpms) + ret = (*connector->funcs->dpms)(connector, (int)value); } else if (connector->funcs->set_property) ret = connector->funcs->set_property(connector, property, value); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index d3d038f05bf7..ef534758a02c 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -762,15 +762,18 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc) * implementing the DPMS connector attribute. It computes the new desired DPMS * state for all encoders and crtcs in the output mesh and calls the ->dpms() * callback provided by the driver appropriately. + * + * Returns: + * Always returns 0. */ -void drm_helper_connector_dpms(struct drm_connector *connector, int mode) +int drm_helper_connector_dpms(struct drm_connector *connector, int mode) { struct drm_encoder *encoder = connector->encoder; struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF; if (mode == connector->dpms) - return; + return 0; old_dpms = connector->dpms; connector->dpms = mode; @@ -802,7 +805,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode) } } - return; + return 0; } EXPORT_SYMBOL(drm_helper_connector_dpms); diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 521af2c069cb..5d78c1feec81 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -237,7 +237,7 @@ static void intel_enable_crt(struct intel_encoder *encoder) } /* Special dpms function to support cloning between dvo/sdvo/crt. */ -static void intel_crt_dpms(struct drm_connector *connector, int mode) +static int intel_crt_dpms(struct drm_connector *connector, int mode) { struct drm_device *dev = connector->dev; struct intel_encoder *encoder = intel_attached_encoder(connector); @@ -249,7 +249,7 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) mode = DRM_MODE_DPMS_OFF; if (mode == connector->dpms) - return; + return 0; old_dpms = connector->dpms; connector->dpms = mode; @@ -258,7 +258,7 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) crtc = encoder->base.crtc; if (!crtc) { encoder->connectors_active = false; - return; + return 0; } /* We need the pipe to run for anything but OFF. */ @@ -281,6 +281,8 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) } intel_modeset_check_state(connector->dev); + + return 0; } static enum drm_mode_status diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 40c73da2abcf..13a6608be689 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6429,14 +6429,14 @@ struct intel_connector *intel_connector_alloc(void) /* Even simpler default implementation, if there's really no special case to * consider. */ -void intel_connector_dpms(struct drm_connector *connector, int mode) +int intel_connector_dpms(struct drm_connector *connector, int mode) { /* All the simple cases only support two dpms states. */ if (mode != DRM_MODE_DPMS_ON) mode = DRM_MODE_DPMS_OFF; if (mode == connector->dpms) - return; + return 0; connector->dpms = mode; @@ -6445,6 +6445,8 @@ void intel_connector_dpms(struct drm_connector *connector, int mode) intel_encoder_dpms(to_intel_encoder(connector->encoder), mode); intel_modeset_check_state(connector->dev); + + return 0; } /* Simple connector->get_hw_state implementation for encoders that support only diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 47cef0e6c79c..320c9e6bd848 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -997,7 +997,7 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); int intel_connector_init(struct intel_connector *); struct intel_connector *intel_connector_alloc(void); -void intel_connector_dpms(struct drm_connector *, int mode); +int intel_connector_dpms(struct drm_connector *, int mode); bool intel_connector_get_hw_state(struct intel_connector *connector); void intel_modeset_check_state(struct drm_device *dev); bool ibx_digital_port_connected(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index ece5bd754f85..fd5e522abebb 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -197,7 +197,7 @@ static void intel_enable_dvo(struct intel_encoder *encoder) } /* Special dpms function to support cloning between dvo/sdvo/crt. */ -static void intel_dvo_dpms(struct drm_connector *connector, int mode) +static int intel_dvo_dpms(struct drm_connector *connector, int mode) { struct intel_dvo *intel_dvo = intel_attached_dvo(connector); struct drm_crtc *crtc; @@ -208,7 +208,7 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode) mode = DRM_MODE_DPMS_OFF; if (mode == connector->dpms) - return; + return 0; connector->dpms = mode; @@ -216,7 +216,7 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode) crtc = intel_dvo->base.base.crtc; if (!crtc) { intel_dvo->base.connectors_active = false; - return; + return 0; } /* We call connector dpms manually below in case pipe dpms doesn't @@ -238,6 +238,8 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode) } intel_modeset_check_state(connector->dev); + + return 0; } static enum drm_mode_status diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index aa2fd751609c..2c435a79d4da 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1509,7 +1509,7 @@ static void intel_enable_sdvo(struct intel_encoder *encoder) } /* Special dpms function to support cloning between dvo/sdvo/crt. */ -static void intel_sdvo_dpms(struct drm_connector *connector, int mode) +static int intel_sdvo_dpms(struct drm_connector *connector, int mode) { struct drm_crtc *crtc; struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); @@ -1519,7 +1519,7 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) mode = DRM_MODE_DPMS_OFF; if (mode == connector->dpms) - return; + return 0; connector->dpms = mode; @@ -1527,7 +1527,7 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) crtc = intel_sdvo->base.base.crtc; if (!crtc) { intel_sdvo->base.connectors_active = false; - return; + return 0; } /* We set active outputs manually below in case pipe dpms doesn't change @@ -1551,6 +1551,8 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) } intel_modeset_check_state(connector->dev); + + return 0; } static enum drm_mode_status diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 3162040bc314..1f26eba245d1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -919,7 +919,7 @@ nouveau_connector_funcs_lvds = { .force = nouveau_connector_force }; -static void +static int nouveau_connector_dp_dpms(struct drm_connector *connector, int mode) { struct nouveau_encoder *nv_encoder = NULL; @@ -938,7 +938,7 @@ nouveau_connector_dp_dpms(struct drm_connector *connector, int mode) } } - drm_helper_connector_dpms(connector, mode); + return drm_helper_connector_dpms(connector, mode); } static const struct drm_connector_funcs diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index e4fc8f3bf58b..5e09c061847f 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -246,9 +246,10 @@ radeon_dp_mst_connector_destroy(struct drm_connector *connector) kfree(radeon_connector); } -static void radeon_connector_dpms(struct drm_connector *connector, int mode) +static int radeon_connector_dpms(struct drm_connector *connector, int mode) { DRM_DEBUG_KMS("\n"); + return 0; } static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = { diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index ed970f622903..dc97c0b3681d 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -726,8 +726,9 @@ static void tegra_dsi_soft_reset(struct tegra_dsi *dsi) tegra_dsi_soft_reset(dsi->slave); } -static void tegra_dsi_connector_dpms(struct drm_connector *connector, int mode) +static int tegra_dsi_connector_dpms(struct drm_connector *connector, int mode) { + return 0; } static void tegra_dsi_connector_reset(struct drm_connector *connector) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 06ab1783bba1..fe4008a7ddba 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -772,9 +772,10 @@ static bool tegra_output_is_hdmi(struct tegra_output *output) return drm_detect_hdmi_monitor(edid); } -static void tegra_hdmi_connector_dpms(struct drm_connector *connector, - int mode) +static int tegra_hdmi_connector_dpms(struct drm_connector *connector, + int mode) { + return 0; } static const struct drm_connector_funcs tegra_hdmi_connector_funcs = { diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 7cd833f5b5b5..9a99d213e1b1 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -88,9 +88,10 @@ static void tegra_dc_write_regs(struct tegra_dc *dc, tegra_dc_writel(dc, table[i].value, table[i].offset); } -static void tegra_rgb_connector_dpms(struct drm_connector *connector, - int mode) +static int tegra_rgb_connector_dpms(struct drm_connector *connector, + int mode) { + return 0; } static const struct drm_connector_funcs tegra_rgb_connector_funcs = { diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 7591d8901f9a..ee8ad0d4a0f2 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -866,8 +866,9 @@ static void tegra_sor_debugfs_exit(struct tegra_sor *sor) sor->debugfs_files = NULL; } -static void tegra_sor_connector_dpms(struct drm_connector *connector, int mode) +static int tegra_sor_connector_dpms(struct drm_connector *connector, int mode) { + return 0; } static enum drm_connector_status diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 07cda8cbbddb..2adc11bc0920 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1808,8 +1808,9 @@ void vmw_du_crtc_gamma_set(struct drm_crtc *crtc, } } -void vmw_du_connector_dpms(struct drm_connector *connector, int mode) +int vmw_du_connector_dpms(struct drm_connector *connector, int mode) { + return 0; } void vmw_du_connector_save(struct drm_connector *connector) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 8d038c36bd57..f1a324cfb4c3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -133,7 +133,7 @@ void vmw_du_crtc_gamma_set(struct drm_crtc *crtc, int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height); int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); -void vmw_du_connector_dpms(struct drm_connector *connector, int mode); +int vmw_du_connector_dpms(struct drm_connector *connector, int mode); void vmw_du_connector_save(struct drm_connector *connector); void vmw_du_connector_restore(struct drm_connector *connector); enum drm_connector_status diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index cc1fee8a12d0..11266d147a29 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -87,8 +87,8 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags); -void drm_atomic_helper_connector_dpms(struct drm_connector *connector, - int mode); +int drm_atomic_helper_connector_dpms(struct drm_connector *connector, + int mode); /* default implementations for state handling */ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 90a0ff70384a..574656965126 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -527,7 +527,7 @@ struct drm_connector_state { * etc. */ struct drm_connector_funcs { - void (*dpms)(struct drm_connector *connector, int mode); + int (*dpms)(struct drm_connector *connector, int mode); void (*save)(struct drm_connector *connector); void (*restore)(struct drm_connector *connector); void (*reset)(struct drm_connector *connector); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 01cafcbe7deb..800e0d1cf32c 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -189,7 +189,7 @@ extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder); -extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode); +extern int drm_helper_connector_dpms(struct drm_connector *connector, int mode); extern void drm_helper_move_panel_connectors_to_head(struct drm_device *); -- cgit v1.3-6-gb490 From 8c10342cb48f3140d9abeadcfd2fa6625d447282 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 27 Jul 2015 13:24:29 +0200 Subject: drm/atomic: Update legacy DPMS state during modesets, v3. This is required for DPMS to work correctly, during a modeset the DPMS property should be turned off, unless the state is crtc is made active in which case it should be set to DPMS on. Changes since v1: - Set DPMS to off when a connector is removed from a crtc too. - Update the legacy dpms property too. - Add an exception for the legacy dpms paths, it updates its own state. Changes since v2: - Do not preserve dpms property. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 26 ++++++++++++++++++++------ drivers/gpu/drm/i915/intel_display.c | 9 +-------- 2 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 57847ae8ce8c..0b475fae067d 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -660,15 +660,29 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev, struct drm_crtc_state *old_crtc_state; int i; - /* clear out existing links */ + /* clear out existing links and update dpms */ for_each_connector_in_state(old_state, connector, old_conn_state, i) { - if (!connector->encoder) - continue; + if (connector->encoder) { + WARN_ON(!connector->encoder->crtc); + + connector->encoder->crtc = NULL; + connector->encoder = NULL; + } - WARN_ON(!connector->encoder->crtc); + crtc = connector->state->crtc; + if ((!crtc && old_conn_state->crtc) || + (crtc && drm_atomic_crtc_needs_modeset(crtc->state))) { + struct drm_property *dpms_prop = + dev->mode_config.dpms_property; + int mode = DRM_MODE_DPMS_OFF; - connector->encoder->crtc = NULL; - connector->encoder = NULL; + if (crtc && crtc->state->active) + mode = DRM_MODE_DPMS_ON; + + connector->dpms = mode; + drm_object_property_set_value(&connector->base, + dpms_prop, mode); + } } /* set new links */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 13a6608be689..43b0f17ad1fa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12349,16 +12349,9 @@ intel_modeset_update_state(struct drm_atomic_state *state) continue; if (crtc->state->active) { - struct drm_property *dpms_property = - dev->mode_config.dpms_property; - - connector->dpms = DRM_MODE_DPMS_ON; - drm_object_property_set_value(&connector->base, dpms_property, DRM_MODE_DPMS_ON); - intel_encoder = to_intel_encoder(connector->encoder); intel_encoder->connectors_active = true; - } else - connector->dpms = DRM_MODE_DPMS_OFF; + } } } -- cgit v1.3-6-gb490 From 753f15833c4d782ee41e333f66bfe424a39680e6 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:26:47 +0300 Subject: power: ds2780_battery: clean up eeprom read/write functions The change removes redundant sysfs binary file boundary checks while reading or writing "param_eeprom" or "user_eeprom", the checks are not needed, since this task is done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Sebastian Reichel --- drivers/power/ds2780_battery.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c index a7a0427343f3..d3743d0ad55b 100644 --- a/drivers/power/ds2780_battery.c +++ b/drivers/power/ds2780_battery.c @@ -637,10 +637,6 @@ static ssize_t ds2780_read_param_eeprom_bin(struct file *filp, struct power_supply *psy = to_power_supply(dev); struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); - count = min_t(loff_t, count, - DS2780_EEPROM_BLOCK1_END - - DS2780_EEPROM_BLOCK1_START + 1 - off); - return ds2780_read_block(dev_info, buf, DS2780_EEPROM_BLOCK1_START + off, count); } @@ -655,10 +651,6 @@ static ssize_t ds2780_write_param_eeprom_bin(struct file *filp, struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); int ret; - count = min_t(loff_t, count, - DS2780_EEPROM_BLOCK1_END - - DS2780_EEPROM_BLOCK1_START + 1 - off); - ret = ds2780_write(dev_info, buf, DS2780_EEPROM_BLOCK1_START + off, count); if (ret < 0) @@ -676,7 +668,7 @@ static struct bin_attribute ds2780_param_eeprom_bin_attr = { .name = "param_eeprom", .mode = S_IRUGO | S_IWUSR, }, - .size = DS2780_EEPROM_BLOCK1_END - DS2780_EEPROM_BLOCK1_START + 1, + .size = DS2780_PARAM_EEPROM_SIZE, .read = ds2780_read_param_eeprom_bin, .write = ds2780_write_param_eeprom_bin, }; @@ -690,10 +682,6 @@ static ssize_t ds2780_read_user_eeprom_bin(struct file *filp, struct power_supply *psy = to_power_supply(dev); struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); - count = min_t(loff_t, count, - DS2780_EEPROM_BLOCK0_END - - DS2780_EEPROM_BLOCK0_START + 1 - off); - return ds2780_read_block(dev_info, buf, DS2780_EEPROM_BLOCK0_START + off, count); } @@ -708,10 +696,6 @@ static ssize_t ds2780_write_user_eeprom_bin(struct file *filp, struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); int ret; - count = min_t(loff_t, count, - DS2780_EEPROM_BLOCK0_END - - DS2780_EEPROM_BLOCK0_START + 1 - off); - ret = ds2780_write(dev_info, buf, DS2780_EEPROM_BLOCK0_START + off, count); if (ret < 0) @@ -729,7 +713,7 @@ static struct bin_attribute ds2780_user_eeprom_bin_attr = { .name = "user_eeprom", .mode = S_IRUGO | S_IWUSR, }, - .size = DS2780_EEPROM_BLOCK0_END - DS2780_EEPROM_BLOCK0_START + 1, + .size = DS2780_USER_EEPROM_SIZE, .read = ds2780_read_user_eeprom_bin, .write = ds2780_write_user_eeprom_bin, }; -- cgit v1.3-6-gb490 From 9f28b86552aef94733387814a57755cb0019cfb9 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:26:48 +0300 Subject: power: ds2781_battery: clean up eeprom read/write functions The change removes redundant calculation of left space on eeprom while reading or writing "param_eeprom" or "user_eeprom", the checks are not needed, since this task is done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Sebastian Reichel --- drivers/power/ds2781_battery.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/power/ds2781_battery.c b/drivers/power/ds2781_battery.c index 56d583dae908..c3680024f399 100644 --- a/drivers/power/ds2781_battery.c +++ b/drivers/power/ds2781_battery.c @@ -639,8 +639,6 @@ static ssize_t ds2781_read_param_eeprom_bin(struct file *filp, struct power_supply *psy = to_power_supply(dev); struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); - count = min_t(loff_t, count, DS2781_PARAM_EEPROM_SIZE - off); - return ds2781_read_block(dev_info, buf, DS2781_EEPROM_BLOCK1_START + off, count); } @@ -655,8 +653,6 @@ static ssize_t ds2781_write_param_eeprom_bin(struct file *filp, struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); int ret; - count = min_t(loff_t, count, DS2781_PARAM_EEPROM_SIZE - off); - ret = ds2781_write(dev_info, buf, DS2781_EEPROM_BLOCK1_START + off, count); if (ret < 0) @@ -688,8 +684,6 @@ static ssize_t ds2781_read_user_eeprom_bin(struct file *filp, struct power_supply *psy = to_power_supply(dev); struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); - count = min_t(loff_t, count, DS2781_USER_EEPROM_SIZE - off); - return ds2781_read_block(dev_info, buf, DS2781_EEPROM_BLOCK0_START + off, count); @@ -705,8 +699,6 @@ static ssize_t ds2781_write_user_eeprom_bin(struct file *filp, struct ds2781_device_info *dev_info = to_ds2781_device_info(psy); int ret; - count = min_t(loff_t, count, DS2781_USER_EEPROM_SIZE - off); - ret = ds2781_write(dev_info, buf, DS2781_EEPROM_BLOCK0_START + off, count); if (ret < 0) -- cgit v1.3-6-gb490 From 3e1d9c6f241961e2e21b8df9de5ee12e3dc6f177 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:26:49 +0300 Subject: power: olpc_battery: clean up eeprom read function The change removes redundant sysfs binary file boundary check while reading eeprom content from userspace, the check is done on caller side in fs/sysfs/file.c, if binary attribute size is not zero. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Sebastian Reichel --- drivers/power/olpc_battery.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index a944338a39de..9e29b1321648 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -521,11 +521,6 @@ static ssize_t olpc_bat_eeprom_read(struct file *filp, struct kobject *kobj, int ret; int i; - if (off >= EEPROM_SIZE) - return 0; - if (off + count > EEPROM_SIZE) - count = EEPROM_SIZE - off; - for (i = 0; i < count; i++) { ec_byte = EEPROM_START + off + i; ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &buf[i], 1); @@ -545,7 +540,7 @@ static struct bin_attribute olpc_bat_eeprom = { .name = "eeprom", .mode = S_IRUGO, }, - .size = 0, + .size = EEPROM_SIZE, .read = olpc_bat_eeprom_read, }; -- cgit v1.3-6-gb490 From 344e62b36d3fa680ffbd35ee26b52f7bf4c1c4ec Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 13 Jul 2015 17:32:27 +0530 Subject: char: misc: remove redundant ifdef The check for CONFIG_PROC_FS is not required as the check is being done in proc_fs.h and incase CONFIG_PROC_FS is not defined then proc_create() is defined as NULL. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/char/misc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/misc.c b/drivers/char/misc.c index fdb0f9b3fe45..3b95795cb640 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -282,9 +282,7 @@ static int __init misc_init(void) { int err; -#ifdef CONFIG_PROC_FS proc_create("misc", 0, NULL, &misc_proc_fops); -#endif misc_class = class_create(THIS_MODULE, "misc"); err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) -- cgit v1.3-6-gb490 From 1037b2787b6df12f31b7051f7cdbb289f7972ee7 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 13 Jul 2015 17:32:28 +0530 Subject: char: misc: fix error path Lets call remove_proc_entry() in the error path only if we have successfully created "misc" in procfs. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/char/misc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 3b95795cb640..c83ef9652bc9 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -281,8 +281,9 @@ static char *misc_devnode(struct device *dev, umode_t *mode) static int __init misc_init(void) { int err; + struct proc_dir_entry *ret; - proc_create("misc", 0, NULL, &misc_proc_fops); + ret = proc_create("misc", 0, NULL, &misc_proc_fops); misc_class = class_create(THIS_MODULE, "misc"); err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) @@ -298,7 +299,8 @@ fail_printk: printk("unable to get major %d for misc devices\n", MISC_MAJOR); class_destroy(misc_class); fail_remove: - remove_proc_entry("misc", NULL); + if (ret) + remove_proc_entry("misc", NULL); return err; } subsys_initcall(misc_init); -- cgit v1.3-6-gb490 From 14e51e599db0b5bd7d2fc11f144b68c38aa9d0c9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:23:17 +0900 Subject: misc: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ad525x_dpot-i2c.c | 1 - drivers/misc/apds990x.c | 1 - drivers/misc/bh1770glc.c | 1 - drivers/misc/bmp085-i2c.c | 1 - drivers/misc/eeprom/at24.c | 1 - drivers/misc/isl29003.c | 1 - drivers/misc/lis3lv02d/lis3lv02d_i2c.c | 1 - drivers/misc/ti-st/st_kim.c | 1 - drivers/misc/tsl2550.c | 1 - 9 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index 705b881e186d..d11187d36ddd 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c @@ -106,7 +106,6 @@ MODULE_DEVICE_TABLE(i2c, ad_dpot_id); static struct i2c_driver ad_dpot_i2c_driver = { .driver = { .name = "ad_dpot", - .owner = THIS_MODULE, }, .probe = ad_dpot_i2c_probe, .remove = ad_dpot_i2c_remove, diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index 3739ffa9cdf1..a3e789b85cc8 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -1275,7 +1275,6 @@ static const struct dev_pm_ops apds990x_pm_ops = { static struct i2c_driver apds990x_driver = { .driver = { .name = "apds990x", - .owner = THIS_MODULE, .pm = &apds990x_pm_ops, }, .probe = apds990x_probe, diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index b756381b8250..753d7ecdadaa 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c @@ -1396,7 +1396,6 @@ static const struct dev_pm_ops bh1770_pm_ops = { static struct i2c_driver bh1770_driver = { .driver = { .name = "bh1770glc", - .owner = THIS_MODULE, .pm = &bh1770_pm_ops, }, .probe = bh1770_probe, diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c index a7c16295b816..f35c218aaa1a 100644 --- a/drivers/misc/bmp085-i2c.c +++ b/drivers/misc/bmp085-i2c.c @@ -66,7 +66,6 @@ MODULE_DEVICE_TABLE(i2c, bmp085_id); static struct i2c_driver bmp085_i2c_driver = { .driver = { - .owner = THIS_MODULE, .name = BMP085_NAME, }, .id_table = bmp085_id, diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 2d3db81be099..8c157229ac82 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -689,7 +689,6 @@ static int at24_remove(struct i2c_client *client) static struct i2c_driver at24_driver = { .driver = { .name = "at24", - .owner = THIS_MODULE, }, .probe = at24_probe, .remove = at24_remove, diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c index 12c30b486b27..976df0013633 100644 --- a/drivers/misc/isl29003.c +++ b/drivers/misc/isl29003.c @@ -465,7 +465,6 @@ MODULE_DEVICE_TABLE(i2c, isl29003_id); static struct i2c_driver isl29003_driver = { .driver = { .name = ISL29003_DRV_NAME, - .owner = THIS_MODULE, .pm = ISL29003_PM_OPS, }, .probe = isl29003_probe, diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c index e3e7f1dc27ba..0c3bb7e3ee80 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c @@ -274,7 +274,6 @@ static const struct dev_pm_ops lis3_pm_ops = { static struct i2c_driver lis3lv02d_i2c_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &lis3_pm_ops, .of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids), }, diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 5027b8ffae43..c84093e639e0 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -939,7 +939,6 @@ static struct platform_driver kim_platform_driver = { .resume = kim_resume, .driver = { .name = "kim", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(kim_of_match), }, }; diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c index b00335652e52..87a13374fdc0 100644 --- a/drivers/misc/tsl2550.c +++ b/drivers/misc/tsl2550.c @@ -446,7 +446,6 @@ MODULE_DEVICE_TABLE(i2c, tsl2550_id); static struct i2c_driver tsl2550_driver = { .driver = { .name = TSL2550_DRV_NAME, - .owner = THIS_MODULE, .pm = TSL2550_PM_OPS, }, .probe = tsl2550_probe, -- cgit v1.3-6-gb490 From 458e2c82c5fbfbc431598636c05bdb21feb7056f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 27 Jul 2015 15:15:59 -0300 Subject: Revert "tty: serial: imx.c: Reset UART before activating interrupts" This reverts commit e95044ba4fee93f5ea8a1a24b2d921e148503833. Commit e95044ba4fee93 ("tty: serial: imx.c: Reset UART before activating interrupts") terribly messes up with the console on mx6 boards, so let's revert it. Reported-by: kernelci.org bot Cc: David Jander Signed-off-by: Fabio Estevam Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index e705149ba477..cf594ce7c54c 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1098,23 +1098,10 @@ static void imx_disable_dma(struct imx_port *sport) /* half the RX buffer size */ #define CTSTL 16 -static inline void imx_reset(struct imx_port *sport) -{ - int i = 100; - unsigned long temp; - - temp = readl(sport->port.membase + UCR2); - temp &= ~UCR2_SRST; - writel(temp, sport->port.membase + UCR2); - - while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) - udelay(1); -} - static int imx_startup(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - int retval; + int retval, i; unsigned long flags, temp; retval = clk_prepare_enable(sport->clk_per); @@ -1141,7 +1128,14 @@ static int imx_startup(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); /* Reset fifo's and state machines */ - imx_reset(sport); + i = 100; + + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_SRST; + writel(temp, sport->port.membase + UCR2); + + while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) + udelay(1); /* * Finally, clear and enable interrupts @@ -1980,14 +1974,6 @@ static int serial_imx_probe(struct platform_device *pdev) clk_disable_unprepare(sport->clk_ipg); - /* - * Perform a complete reset of the UART device. Needed if we don't - * come straight out of reset. - */ - writel(0, sport->port.membase + UCR2); - writel(0, sport->port.membase + UCR1); - imx_reset(sport); - /* * Allocate the IRQ(s) i.MX1 has three interrupts whereas later * chips only have one interrupt. -- cgit v1.3-6-gb490 From 77fc29c4bbbbd01ee22c50ce8260fd0f2e08c124 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Mon, 27 Jul 2015 14:46:31 +0300 Subject: net/mlx4_core: Preparations for 802.1ad VLAN support mlx4_core preparation to support hardware accelerated 802.1ad VLAN device. To allow 802.1ad accelerated device, "packet has vlan" (phv) Firmware capability should be available. Firmware without the phv capability won't behave properly and can't support 802.1ad device acceleration. The driver checks the Firmware capability and sets the phv bit accordingly in SET_PORT command. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 82 +++++++++++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/fw.h | 1 + drivers/net/ethernet/mellanox/mlx4/main.c | 15 ++++++ drivers/net/ethernet/mellanox/mlx4/mlx4.h | 3 ++ include/linux/mlx4/device.h | 5 ++ 5 files changed, 106 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index e30bf57ad7a1..5a1c3d249530 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -154,6 +154,7 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) [26] = "Port ETS Scheduler support", [27] = "Port beacon support", [28] = "RX-ALL support", + [29] = "802.1ad offload support", }; int i; @@ -307,6 +308,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, #define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80 #define QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS (1 << 31) +#define QUERY_FUNC_CAP_PHV_BIT 0x40 if (vhcr->op_modifier == 1) { struct mlx4_active_ports actv_ports = @@ -351,6 +353,12 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, MLX4_PUT(outbox->buf, dev->caps.phys_port_id[vhcr->in_modifier], QUERY_FUNC_CAP_PHYS_PORT_ID); + if (dev->caps.phv_bit[port]) { + field = QUERY_FUNC_CAP_PHV_BIT; + MLX4_PUT(outbox->buf, field, + QUERY_FUNC_CAP_FLAGS0_OFFSET); + } + } else if (vhcr->op_modifier == 0) { struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave); @@ -600,6 +608,9 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port, MLX4_GET(func_cap->phys_port_id, outbox, QUERY_FUNC_CAP_PHYS_PORT_ID); + MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET); + func_cap->flags |= (field & QUERY_FUNC_CAP_PHV_BIT); + /* All other resources are allocated by the master, but we still report * 'num' and 'reserved' capabilities as follows: * - num remains the maximum resource index @@ -700,6 +711,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) #define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET 0x92 #define QUERY_DEV_CAP_BMME_FLAGS_OFFSET 0x94 #define QUERY_DEV_CAP_CONFIG_DEV_OFFSET 0x94 +#define QUERY_DEV_CAP_PHV_EN_OFFSET 0x96 #define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98 #define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0 #define QUERY_DEV_CAP_ETH_BACKPL_OFFSET 0x9c @@ -898,6 +910,12 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CONFIG_DEV; if (field & (1 << 2)) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_IGNORE_FCS; + MLX4_GET(field, outbox, QUERY_DEV_CAP_PHV_EN_OFFSET); + if (field & 0x80) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PHV_EN; + if (field & 0x40) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN; + MLX4_GET(dev_cap->reserved_lkey, outbox, QUERY_DEV_CAP_RSVD_LKEY_OFFSET); MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETH_BACKPL_OFFSET); @@ -1992,6 +2010,10 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev, MLX4_GET(param->uar_page_sz, outbox, INIT_HCA_UAR_PAGE_SZ_OFFSET); MLX4_GET(param->log_uar_sz, outbox, INIT_HCA_LOG_UAR_SZ_OFFSET); + /* phv_check enable */ + MLX4_GET(byte_field, outbox, INIT_HCA_CACHELINE_SZ_OFFSET); + if (byte_field & 0x2) + param->phv_check_en = 1; out: mlx4_free_cmd_mailbox(dev, mailbox); @@ -2758,3 +2780,63 @@ int mlx4_ACCESS_REG_wrapper(struct mlx4_dev *dev, int slave, 0, MLX4_CMD_ACCESS_REG, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); } + +static int mlx4_SET_PORT_phv_bit(struct mlx4_dev *dev, u8 port, u8 phv_bit) +{ +#define SET_PORT_GEN_PHV_VALID 0x10 +#define SET_PORT_GEN_PHV_EN 0x80 + + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_port_general_context *context; + u32 in_mod; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + context = mailbox->buf; + + context->v_ignore_fcs |= SET_PORT_GEN_PHV_VALID; + if (phv_bit) + context->phv_en |= SET_PORT_GEN_PHV_EN; + + in_mod = MLX4_SET_PORT_GENERAL << 8 | port; + err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, + MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int get_phv_bit(struct mlx4_dev *dev, u8 port, int *phv) +{ + int err; + struct mlx4_func_cap func_cap; + + memset(&func_cap, 0, sizeof(func_cap)); + err = mlx4_QUERY_FUNC_CAP(dev, 1, &func_cap); + if (!err) + *phv = func_cap.flags & QUERY_FUNC_CAP_PHV_BIT; + return err; +} +EXPORT_SYMBOL(get_phv_bit); + +int set_phv_bit(struct mlx4_dev *dev, u8 port, int new_val) +{ + int ret; + + if (mlx4_is_slave(dev)) + return -EPERM; + + if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN && + !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) { + ret = mlx4_SET_PORT_phv_bit(dev, port, new_val); + if (!ret) + dev->caps.phv_bit[port] = new_val; + return ret; + } + + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(set_phv_bit); diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h index 07cb7c2461ad..08de5555c2f4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw.h @@ -204,6 +204,7 @@ struct mlx4_init_hca_param { u16 cqe_size; /* For use only when CQE stride feature enabled */ u16 eqe_size; /* For use only when EQE stride feature enabled */ u8 rss_ip_frags; + u8 phv_check_en; /* for QUERY_HCA */ }; struct mlx4_init_ib_param { diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index d76f4257e305..6f35b6c06193 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -405,6 +405,21 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.max_gso_sz = dev_cap->max_gso_sz; dev->caps.max_rss_tbl_sz = dev_cap->max_rss_tbl_sz; + if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN) { + struct mlx4_init_hca_param hca_param; + + memset(&hca_param, 0, sizeof(hca_param)); + err = mlx4_QUERY_HCA(dev, &hca_param); + /* Turn off PHV_EN flag in case phv_check_en is set. + * phv_check_en is a HW check that parse the packet and verify + * phv bit was reported correctly in the wqe. To allow QinQ + * PHV_EN flag should be set and phv_check_en must be cleared + * otherwise QinQ packets will be drop by the HW. + */ + if (err || hca_param.phv_check_en) + dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_PHV_EN; + } + /* Sense port always allowed on supported devices for ConnectX-1 and -2 */ if (mlx4_priv(dev)->pci_dev_data & MLX4_PCI_DEV_FORCE_SENSE_PORT) dev->caps.flags |= MLX4_DEV_CAP_FLAG_SENSE_SUPPORT; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index a092c5c34d43..232b2b55f23b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -787,6 +787,9 @@ struct mlx4_set_port_general_context { u8 pprx; u8 pfcrx; u16 reserved4; + u32 reserved5; + u8 phv_en; + u8 reserved6[3]; }; struct mlx4_set_port_rqp_calc_context { diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index fd13c1ce3b4a..bcbf8c72a77b 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -211,6 +211,8 @@ enum { MLX4_DEV_CAP_FLAG2_ETS_CFG = 1LL << 26, MLX4_DEV_CAP_FLAG2_PORT_BEACON = 1LL << 27, MLX4_DEV_CAP_FLAG2_IGNORE_FCS = 1LL << 28, + MLX4_DEV_CAP_FLAG2_PHV_EN = 1LL << 29, + MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN = 1LL << 30, }; enum { @@ -581,6 +583,7 @@ struct mlx4_caps { u64 phys_port_id[MLX4_MAX_PORTS + 1]; int tunnel_offload_mode; u8 rx_checksum_flags_port[MLX4_MAX_PORTS + 1]; + u8 phv_bit[MLX4_MAX_PORTS + 1]; u8 alloc_res_qp_mask; u32 dmfs_high_rate_qpn_base; u32 dmfs_high_rate_qpn_range; @@ -1332,6 +1335,8 @@ int mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time); int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value); int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable); +int set_phv_bit(struct mlx4_dev *dev, u8 port, int new_val); +int get_phv_bit(struct mlx4_dev *dev, u8 port, int *phv); int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx); int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx); int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index); -- cgit v1.3-6-gb490 From 7c509a48ff999463f698ed5082875a938094bfb3 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Mon, 27 Jul 2015 14:46:32 +0300 Subject: net/mlx4_en: Prepare ethtool private flags to support more flags Currently we support only one ethtool private flag. Prepare mlx4_en_set_priv_flags function to support more than one private flag. Will be used in the next patch to support hardware accelerated 802.1ad vlan. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 35 ++++++++++++------------- 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 99ba1c50e585..70f65534e786 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1801,30 +1801,29 @@ static int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags) bool bf_enabled_old = !!(priv->pflags & MLX4_EN_PRIV_FLAGS_BLUEFLAME); int i; - if (bf_enabled_new == bf_enabled_old) - return 0; /* Nothing to do */ + if (bf_enabled_new != bf_enabled_old) { + if (bf_enabled_new) { + bool bf_supported = true; - if (bf_enabled_new) { - bool bf_supported = true; + for (i = 0; i < priv->tx_ring_num; i++) + bf_supported &= priv->tx_ring[i]->bf_alloced; - for (i = 0; i < priv->tx_ring_num; i++) - bf_supported &= priv->tx_ring[i]->bf_alloced; + if (!bf_supported) { + en_err(priv, "BlueFlame is not supported\n"); + return -EINVAL; + } - if (!bf_supported) { - en_err(priv, "BlueFlame is not supported\n"); - return -EINVAL; + priv->pflags |= MLX4_EN_PRIV_FLAGS_BLUEFLAME; + } else { + priv->pflags &= ~MLX4_EN_PRIV_FLAGS_BLUEFLAME; } - priv->pflags |= MLX4_EN_PRIV_FLAGS_BLUEFLAME; - } else { - priv->pflags &= ~MLX4_EN_PRIV_FLAGS_BLUEFLAME; - } - - for (i = 0; i < priv->tx_ring_num; i++) - priv->tx_ring[i]->bf_enabled = bf_enabled_new; + for (i = 0; i < priv->tx_ring_num; i++) + priv->tx_ring[i]->bf_enabled = bf_enabled_new; - en_info(priv, "BlueFlame %s\n", - bf_enabled_new ? "Enabled" : "Disabled"); + en_info(priv, "BlueFlame %s\n", + bf_enabled_new ? "Enabled" : "Disabled"); + } return 0; } -- cgit v1.3-6-gb490 From e802f8e4c54e6adf4215ef9fa3d6eea8fcb10bf9 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Mon, 27 Jul 2015 14:46:33 +0300 Subject: net/mlx4: Prepare VLAN macros for 802.1ad Hardware accelerated support To add Hardware accelerated support in 802.1ad vlan, replace Current VLAN macros to CVLAN. Replace: MLX4_WQE_CTRL_INS_VLAN MLX4_CQE_VLAN_PRESENT_MASK With: MLX4_WQE_CTRL_INS_CVLAN MLX4_CQE_CVLAN_PRESENT_MASK Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/cq.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 6 +++--- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 2 +- include/linux/mlx4/cq.h | 2 +- include/linux/mlx4/qp.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 36eb3d012b6d..180a8f7ec82d 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -871,7 +871,7 @@ repoll: if (is_eth) { wc->sl = be16_to_cpu(cqe->sl_vid) >> 13; if (be32_to_cpu(cqe->vlan_my_qpn) & - MLX4_CQE_VLAN_PRESENT_MASK) { + MLX4_CQE_CVLAN_PRESENT_MASK) { wc->vlan_id = be16_to_cpu(cqe->sl_vid) & MLX4_CQE_VID_MASK; } else { diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 12c65e1ad6a9..10f6c2f1d5a0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -726,7 +726,7 @@ static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va, hw_checksum = csum_unfold((__force __sum16)cqe->checksum); - if (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK) && + if (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_CVLAN_PRESENT_MASK) && !(dev_features & NETIF_F_HW_VLAN_CTAG_RX)) { hw_checksum = get_fixed_vlan_csum(hw_checksum, hdr); hdr += sizeof(struct vlan_hdr); @@ -907,7 +907,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud gro_skb->csum_level = 1; if ((cqe->vlan_my_qpn & - cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) && + cpu_to_be32(MLX4_CQE_CVLAN_PRESENT_MASK)) && (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) { u16 vid = be16_to_cpu(cqe->sl_vid); @@ -970,7 +970,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud PKT_HASH_TYPE_L3); if ((be32_to_cpu(cqe->vlan_my_qpn) & - MLX4_CQE_VLAN_PRESENT_MASK) && + MLX4_CQE_CVLAN_PRESENT_MASK) && (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(cqe->sl_vid)); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index c10d98f6ad96..7c858f67ef28 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -958,7 +958,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ring->bf.offset ^= ring->bf.buf_size; } else { tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag); - tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN * + tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_CVLAN * !!skb_vlan_tag_present(skb); tx_desc->ctrl.fence_size = real_size; diff --git a/include/linux/mlx4/cq.h b/include/linux/mlx4/cq.h index e7ecc12a1163..899a97b20d27 100644 --- a/include/linux/mlx4/cq.h +++ b/include/linux/mlx4/cq.h @@ -88,7 +88,7 @@ struct mlx4_ts_cqe { enum { MLX4_CQE_L2_TUNNEL_IPOK = 1 << 31, - MLX4_CQE_VLAN_PRESENT_MASK = 1 << 29, + MLX4_CQE_CVLAN_PRESENT_MASK = 1 << 29, MLX4_CQE_L2_TUNNEL = 1 << 27, MLX4_CQE_L2_TUNNEL_CSUM = 1 << 26, MLX4_CQE_L2_TUNNEL_IPV4 = 1 << 25, diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h index 6fed539e5456..6c619006c21f 100644 --- a/include/linux/mlx4/qp.h +++ b/include/linux/mlx4/qp.h @@ -272,7 +272,7 @@ enum { MLX4_WQE_CTRL_SOLICITED = 1 << 1, MLX4_WQE_CTRL_IP_CSUM = 1 << 4, MLX4_WQE_CTRL_TCP_UDP_CSUM = 1 << 5, - MLX4_WQE_CTRL_INS_VLAN = 1 << 6, + MLX4_WQE_CTRL_INS_CVLAN = 1 << 6, MLX4_WQE_CTRL_STRONG_ORDER = 1 << 7, MLX4_WQE_CTRL_FORCE_LOOPBACK = 1 << 0, }; -- cgit v1.3-6-gb490 From e38af4faf01d0b35df6995fb395e5fa4a4898289 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Mon, 27 Jul 2015 14:46:34 +0300 Subject: net/mlx4_en: Add support for hardware accelerated 802.1ad vlan To enable device support in accelerated 802.1ad vlan, the port capability "packet has vlan enable" (phv_en) should be set. Firmware won't work properly, in case phv_en is not set. The user can enable "phv_en" port capability with the new ethtool private flag phv-bit. The phv-bit private flag default value is OFF, users who are interested in 802.1ad hardware acceleration should turn ON the phv-bit private flag: $ ethtool --set-priv-flags eth1 phv-bit on Once the private flag is set, the device is ready for 802.1ad vlan acceleration. The user should also change the interface device features and turn on "tx-vlan-stag-hw-insert" which is off by default: $ ethtool -K eth1 tx-vlan-stag-hw-insert on "phv-bit" private flag setting is available only for Physical Functions(PF), the Virtual Function (VF) will be able to use the feature by setting "tx-vlan-stag-hw-insert" ethtool device feature only if the feature was enabled by the Hypervisor. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 16 +++++++++ drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 46 +++++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/en_rx.c | 16 ++++++++- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 13 ++++--- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 + include/linux/mlx4/cq.h | 1 + include/linux/mlx4/qp.h | 1 + 7 files changed, 89 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 70f65534e786..f79d8124321e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -102,6 +102,7 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) static const char mlx4_en_priv_flags[][ETH_GSTRING_LEN] = { "blueflame", + "phv-bit" }; static const char main_strings[][ETH_GSTRING_LEN] = { @@ -1797,9 +1798,13 @@ static int mlx4_en_get_ts_info(struct net_device *dev, static int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags) { struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; bool bf_enabled_new = !!(flags & MLX4_EN_PRIV_FLAGS_BLUEFLAME); bool bf_enabled_old = !!(priv->pflags & MLX4_EN_PRIV_FLAGS_BLUEFLAME); + bool phv_enabled_new = !!(flags & MLX4_EN_PRIV_FLAGS_PHV); + bool phv_enabled_old = !!(priv->pflags & MLX4_EN_PRIV_FLAGS_PHV); int i; + int ret = 0; if (bf_enabled_new != bf_enabled_old) { if (bf_enabled_new) { @@ -1825,6 +1830,17 @@ static int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags) bf_enabled_new ? "Enabled" : "Disabled"); } + if (phv_enabled_new != phv_enabled_old) { + ret = set_phv_bit(mdev->dev, priv->port, (int)phv_enabled_new); + if (ret) + return ret; + else if (phv_enabled_new) + priv->pflags |= MLX4_EN_PRIV_FLAGS_PHV; + else + priv->pflags &= ~MLX4_EN_PRIV_FLAGS_PHV; + en_info(priv, "PHV bit %s\n", + phv_enabled_new ? "Enabled" : "Disabled"); + } return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index e0de2fd1ce12..4726122ea76b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2184,6 +2184,25 @@ static int mlx4_en_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } } +static netdev_features_t mlx4_en_fix_features(struct net_device *netdev, + netdev_features_t features) +{ + struct mlx4_en_priv *en_priv = netdev_priv(netdev); + struct mlx4_en_dev *mdev = en_priv->mdev; + + /* Since there is no support for separate RX C-TAG/S-TAG vlan accel + * enable/disable make sure S-TAG flag is always in same state as + * C-TAG. + */ + if (features & NETIF_F_HW_VLAN_CTAG_RX && + !(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) + features |= NETIF_F_HW_VLAN_STAG_RX; + else + features &= ~NETIF_F_HW_VLAN_STAG_RX; + + return features; +} + static int mlx4_en_set_features(struct net_device *netdev, netdev_features_t features) { @@ -2218,6 +2237,10 @@ static int mlx4_en_set_features(struct net_device *netdev, en_info(priv, "Turn %s TX vlan strip offload\n", (features & NETIF_F_HW_VLAN_CTAG_TX) ? "ON" : "OFF"); + if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_STAG_TX)) + en_info(priv, "Turn %s TX S-VLAN strip offload\n", + (features & NETIF_F_HW_VLAN_STAG_TX) ? "ON" : "OFF"); + if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_LOOPBACK)) { en_info(priv, "Turn %s loopback\n", (features & NETIF_F_LOOPBACK) ? "ON" : "OFF"); @@ -2460,6 +2483,7 @@ static const struct net_device_ops mlx4_netdev_ops = { .ndo_poll_controller = mlx4_en_netpoll, #endif .ndo_set_features = mlx4_en_set_features, + .ndo_fix_features = mlx4_en_fix_features, .ndo_setup_tc = mlx4_en_setup_tc, #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = mlx4_en_filter_rfs, @@ -2500,6 +2524,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = { .ndo_poll_controller = mlx4_en_netpoll, #endif .ndo_set_features = mlx4_en_set_features, + .ndo_fix_features = mlx4_en_fix_features, .ndo_setup_tc = mlx4_en_setup_tc, #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = mlx4_en_filter_rfs, @@ -2931,6 +2956,27 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, dev->hw_features |= NETIF_F_LOOPBACK | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; + if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) { + dev->features |= NETIF_F_HW_VLAN_STAG_RX | + NETIF_F_HW_VLAN_STAG_FILTER; + dev->hw_features |= NETIF_F_HW_VLAN_STAG_RX; + } + + if (mlx4_is_slave(mdev->dev)) { + int phv; + + err = get_phv_bit(mdev->dev, port, &phv); + if (!err && phv) { + dev->hw_features |= NETIF_F_HW_VLAN_STAG_TX; + priv->pflags |= MLX4_EN_PRIV_FLAGS_PHV; + } + } else { + if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN && + !(mdev->dev->caps.flags2 & + MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) + dev->hw_features |= NETIF_F_HW_VLAN_STAG_TX; + } + if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) dev->hw_features |= NETIF_F_RXFCS; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 10f6c2f1d5a0..a67fbb90d69e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -912,6 +912,12 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud u16 vid = be16_to_cpu(cqe->sl_vid); __vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid); + } else if ((be32_to_cpu(cqe->vlan_my_qpn) & + MLX4_CQE_SVLAN_PRESENT_MASK) && + (dev->features & NETIF_F_HW_VLAN_STAG_RX)) { + __vlan_hwaccel_put_tag(gro_skb, + htons(ETH_P_8021AD), + be16_to_cpu(cqe->sl_vid)); } if (dev->features & NETIF_F_RXHASH) @@ -973,6 +979,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud MLX4_CQE_CVLAN_PRESENT_MASK) && (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(cqe->sl_vid)); + else if ((be32_to_cpu(cqe->vlan_my_qpn) & + MLX4_CQE_SVLAN_PRESENT_MASK) && + (dev->features & NETIF_F_HW_VLAN_STAG_RX)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021AD), + be16_to_cpu(cqe->sl_vid)); if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) { timestamp = mlx4_en_get_cqe_ts(cqe); @@ -1070,7 +1081,10 @@ static const int frag_sizes[] = { void mlx4_en_calc_rx_buf(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); - int eff_mtu = dev->mtu + ETH_HLEN + VLAN_HLEN; + /* VLAN_HLEN is added twice,to support skb vlan tagged with multiple + * headers. (For example: ETH_P_8021Q and ETH_P_8021AD). + */ + int eff_mtu = dev->mtu + ETH_HLEN + (2 * VLAN_HLEN); int buf_size = 0; int i = 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 7c858f67ef28..494e7762fdb1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -718,6 +718,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) u32 index, bf_index; __be32 op_own; u16 vlan_tag = 0; + u16 vlan_proto = 0; int i_frag; int lso_header_size; void *fragptr = NULL; @@ -750,9 +751,10 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_drop; } - if (skb_vlan_tag_present(skb)) + if (skb_vlan_tag_present(skb)) { vlan_tag = skb_vlan_tag_get(skb); - + vlan_proto = be16_to_cpu(skb->vlan_proto); + } netdev_txq_bql_enqueue_prefetchw(ring->tx_queue); @@ -958,8 +960,11 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ring->bf.offset ^= ring->bf.buf_size; } else { tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag); - tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_CVLAN * - !!skb_vlan_tag_present(skb); + if (vlan_proto == ETH_P_8021AD) + tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_SVLAN; + else if (vlan_proto == ETH_P_8021Q) + tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_CVLAN; + tx_desc->ctrl.fence_size = real_size; /* Ensure new descriptor hits memory diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 666d1669eb52..defcf8c395bf 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -95,6 +95,7 @@ */ #define MLX4_EN_PRIV_FLAGS_BLUEFLAME 1 +#define MLX4_EN_PRIV_FLAGS_PHV 2 #define MLX4_EN_WATCHDOG_TIMEOUT (15 * HZ) diff --git a/include/linux/mlx4/cq.h b/include/linux/mlx4/cq.h index 899a97b20d27..09cebe528488 100644 --- a/include/linux/mlx4/cq.h +++ b/include/linux/mlx4/cq.h @@ -89,6 +89,7 @@ struct mlx4_ts_cqe { enum { MLX4_CQE_L2_TUNNEL_IPOK = 1 << 31, MLX4_CQE_CVLAN_PRESENT_MASK = 1 << 29, + MLX4_CQE_SVLAN_PRESENT_MASK = 1 << 30, MLX4_CQE_L2_TUNNEL = 1 << 27, MLX4_CQE_L2_TUNNEL_CSUM = 1 << 26, MLX4_CQE_L2_TUNNEL_IPV4 = 1 << 25, diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h index 6c619006c21f..de45a51b3f04 100644 --- a/include/linux/mlx4/qp.h +++ b/include/linux/mlx4/qp.h @@ -273,6 +273,7 @@ enum { MLX4_WQE_CTRL_IP_CSUM = 1 << 4, MLX4_WQE_CTRL_TCP_UDP_CSUM = 1 << 5, MLX4_WQE_CTRL_INS_CVLAN = 1 << 6, + MLX4_WQE_CTRL_INS_SVLAN = 1 << 7, MLX4_WQE_CTRL_STRONG_ORDER = 1 << 7, MLX4_WQE_CTRL_FORCE_LOOPBACK = 1 << 0, }; -- cgit v1.3-6-gb490 From 0817b62cc037a56c5e4238c7eb7522299ea27aef Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jul 2015 20:48:08 +0200 Subject: clk: change clk_ops' ->determine_rate() prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clock rates are stored in an unsigned long field, but ->determine_rate() (which returns a rounded rate from a requested one) returns a long value (errors are reported using negative error codes), which can lead to long overflow if the clock rate exceed 2Ghz. Change ->determine_rate() prototype to return 0 or an error code, and pass a pointer to a clk_rate_request structure containing the expected target rate and the rate constraints imposed by clk users. The clk_rate_request structure might be extended in the future to contain other kind of constraints like the rounding policy, the maximum clock inaccuracy or other things that are not yet supported by the CCF (power consumption constraints ?). Signed-off-by: Boris Brezillon CC: Jonathan Corbet CC: Tony Lindgren CC: Ralf Baechle CC: "Emilio López" CC: Maxime Ripard Acked-by: Tero Kristo CC: Peter De Schrijver CC: Prashant Gaikwad CC: Stephen Warren CC: Thierry Reding CC: Alexandre Courbot CC: linux-doc@vger.kernel.org CC: linux-kernel@vger.kernel.org CC: linux-arm-kernel@lists.infradead.org CC: linux-omap@vger.kernel.org CC: linux-mips@linux-mips.org CC: linux-tegra@vger.kernel.org [sboyd@codeaurora.org: Fix parent dereference problem in __clk_determine_rate()] Signed-off-by: Stephen Boyd Tested-by: Romain Perier Signed-off-by: Heiko Stuebner [sboyd@codeaurora.org: Folded in fix from Heiko for fixed-rate clocks without parents or a rate determining op] Signed-off-by: Stephen Boyd --- Documentation/clk.txt | 8 +- arch/arm/mach-omap2/dpll3xxx.c | 29 +++--- arch/arm/mach-omap2/dpll44xx.c | 30 +++--- arch/mips/alchemy/common/clock.c | 61 +++++-------- drivers/clk/at91/clk-programmable.c | 25 ++--- drivers/clk/at91/clk-usb.c | 28 +++--- drivers/clk/bcm/clk-kona.c | 34 ++++--- drivers/clk/clk-composite.c | 48 +++++----- drivers/clk/clk.c | 176 ++++++++++++++++++++---------------- drivers/clk/hisilicon/clk-hi3620.c | 39 ++++---- drivers/clk/mmp/clk-mix.c | 20 ++-- drivers/clk/qcom/clk-pll.c | 18 ++-- drivers/clk/qcom/clk-rcg.c | 44 ++++----- drivers/clk/qcom/clk-rcg2.c | 78 ++++++++-------- drivers/clk/sunxi/clk-factors.c | 21 ++--- drivers/clk/sunxi/clk-sun6i-ar100.c | 21 ++--- drivers/clk/sunxi/clk-sunxi.c | 20 ++-- drivers/clk/tegra/clk-emc.c | 28 +++--- include/linux/clk-provider.h | 49 ++++++---- include/linux/clk/ti.h | 16 +--- 20 files changed, 392 insertions(+), 401 deletions(-) (limited to 'drivers') diff --git a/Documentation/clk.txt b/Documentation/clk.txt index f463bdc37f88..5c4bc4d01d0c 100644 --- a/Documentation/clk.txt +++ b/Documentation/clk.txt @@ -71,12 +71,8 @@ the operations defined in clk.h: long (*round_rate)(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate); - long (*determine_rate)(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk); + int (*determine_rate)(struct clk_hw *hw, + struct clk_rate_request *req); int (*set_parent)(struct clk_hw *hw, u8 index); u8 (*get_parent)(struct clk_hw *hw); int (*set_rate)(struct clk_hw *hw, diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c index 44e57ec225d4..8c57ace30421 100644 --- a/arch/arm/mach-omap2/dpll3xxx.c +++ b/arch/arm/mach-omap2/dpll3xxx.c @@ -462,43 +462,38 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw) /** * omap3_noncore_dpll_determine_rate - determine rate for a DPLL * @hw: pointer to the clock to determine rate for - * @rate: target rate for the DPLL - * @best_parent_rate: pointer for returning best parent rate - * @best_parent_clk: pointer for returning best parent clock + * @req: target rate request * * Determines which DPLL mode to use for reaching a desired target rate. * Checks whether the DPLL shall be in bypass or locked mode, and if * locked, calculates the M,N values for the DPLL via round-rate. - * Returns a positive clock rate with success, negative error value - * in failure. + * Returns a 0 on success, negative error value in failure. */ -long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +int omap3_noncore_dpll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct dpll_data *dd; - if (!hw || !rate) + if (!req->rate) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; - if (__clk_get_rate(dd->clk_bypass) == rate && + if (__clk_get_rate(dd->clk_bypass) == req->rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - *best_parent_clk = __clk_get_hw(dd->clk_bypass); + req->best_parent_hw = __clk_get_hw(dd->clk_bypass); } else { - rate = omap2_dpll_round_rate(hw, rate, best_parent_rate); - *best_parent_clk = __clk_get_hw(dd->clk_ref); + req->rate = omap2_dpll_round_rate(hw, req->rate, + &req->best_parent_rate); + req->best_parent_hw = __clk_get_hw(dd->clk_ref); } - *best_parent_rate = rate; + req->best_parent_rate = req->rate; - return rate; + return 0; } /** diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c index f231be05b9a6..446a4e0d5a6a 100644 --- a/arch/arm/mach-omap2/dpll44xx.c +++ b/arch/arm/mach-omap2/dpll44xx.c @@ -191,42 +191,36 @@ out: /** * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL * @hw: pointer to the clock to determine rate for - * @rate: target rate for the DPLL - * @best_parent_rate: pointer for returning best parent rate - * @best_parent_clk: pointer for returning best parent clock + * @req: target rate request * * Determines which DPLL mode to use for reaching a desired rate. * Checks whether the DPLL shall be in bypass or locked mode, and if * locked, calculates the M,N values for the DPLL via round-rate. - * Returns a positive clock rate with success, negative error value - * in failure. + * Returns 0 on success and a negative error value otherwise. */ -long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_hw_omap *clk = to_clk_hw_omap(hw); struct dpll_data *dd; - if (!hw || !rate) + if (!req->rate) return -EINVAL; dd = clk->dpll_data; if (!dd) return -EINVAL; - if (__clk_get_rate(dd->clk_bypass) == rate && + if (__clk_get_rate(dd->clk_bypass) == req->rate && (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) { - *best_parent_clk = __clk_get_hw(dd->clk_bypass); + req->best_parent_hw = __clk_get_hw(dd->clk_bypass); } else { - rate = omap4_dpll_regm4xen_round_rate(hw, rate, - best_parent_rate); - *best_parent_clk = __clk_get_hw(dd->clk_ref); + req->rate = omap4_dpll_regm4xen_round_rate(hw, req->rate, + &req->best_parent_rate); + req->best_parent_hw = __clk_get_hw(dd->clk_ref); } - *best_parent_rate = rate; + req->best_parent_rate = req->rate; - return rate; + return 0; } diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c index 6e46abe0dac6..0b4cf3e9f005 100644 --- a/arch/mips/alchemy/common/clock.c +++ b/arch/mips/alchemy/common/clock.c @@ -389,10 +389,9 @@ static long alchemy_calc_div(unsigned long rate, unsigned long prate, return div1; } -static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk, - int scale, int maxdiv) +static int alchemy_clk_fgcs_detr(struct clk_hw *hw, + struct clk_rate_request *req, + int scale, int maxdiv) { struct clk *pc, *bpc, *free; long tdv, tpr, pr, nr, br, bpr, diff, lastdiff; @@ -422,14 +421,14 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, } pr = clk_get_rate(pc); - if (pr < rate) + if (pr < req->rate) continue; /* what can hardware actually provide */ - tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL); + tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv, NULL); nr = pr / tdv; - diff = rate - nr; - if (nr > rate) + diff = req->rate - nr; + if (nr > req->rate) continue; if (diff < lastdiff) { @@ -448,15 +447,16 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, */ if (lastdiff && free) { for (j = (maxdiv == 4) ? 1 : scale; j <= maxdiv; j += scale) { - tpr = rate * j; + tpr = req->rate * j; if (tpr < 0) break; pr = clk_round_rate(free, tpr); - tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL); + tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv, + NULL); nr = pr / tdv; - diff = rate - nr; - if (nr > rate) + diff = req->rate - nr; + if (nr > req->rate) continue; if (diff < lastdiff) { lastdiff = diff; @@ -469,9 +469,10 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, } } - *best_parent_rate = bpr; - *best_parent_clk = __clk_get_hw(bpc); - return br; + req->best_parent_rate = bpr; + req->best_parent_hw = __clk_get_hw(bpc); + req->rate = br; + return 0; } static int alchemy_clk_fgv1_en(struct clk_hw *hw) @@ -562,14 +563,10 @@ static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw, return parent_rate / v; } -static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int alchemy_clk_fgv1_detr(struct clk_hw *hw, + struct clk_rate_request *req) { - return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, - best_parent_clk, 2, 512); + return alchemy_clk_fgcs_detr(hw, req, 2, 512); } /* Au1000, Au1100, Au15x0, Au12x0 */ @@ -696,11 +693,8 @@ static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw, return t; } -static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int alchemy_clk_fgv2_detr(struct clk_hw *hw, + struct clk_rate_request *req) { struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); int scale, maxdiv; @@ -713,8 +707,7 @@ static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate, maxdiv = 512; } - return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, - best_parent_clk, scale, maxdiv); + return alchemy_clk_fgcs_detr(hw, req, scale, maxdiv); } /* Au1300 larger input mux, no separate disable bit, flexible divider */ @@ -917,17 +910,13 @@ static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate, return 0; } -static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int alchemy_clk_csrc_detr(struct clk_hw *hw, + struct clk_rate_request *req) { struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); int scale = c->dt[2] == 3 ? 1 : 2; /* au1300 check */ - return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, - best_parent_clk, scale, 4); + return alchemy_clk_fgcs_detr(hw, req, scale, 4); } static struct clk_ops alchemy_clkops_csrc = { diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 8c86c0f7847a..43dacad5c96d 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -54,12 +54,8 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw, return parent_rate >> pres; } -static long clk_programmable_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw) +static int clk_programmable_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *parent = NULL; long best_rate = -EINVAL; @@ -76,24 +72,29 @@ static long clk_programmable_determine_rate(struct clk_hw *hw, parent_rate = __clk_get_rate(parent); for (shift = 0; shift < PROG_PRES_MASK; shift++) { tmp_rate = parent_rate >> shift; - if (tmp_rate <= rate) + if (tmp_rate <= req->rate) break; } - if (tmp_rate > rate) + if (tmp_rate > req->rate) continue; - if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) { + if (best_rate < 0 || + (req->rate - tmp_rate) < (req->rate - best_rate)) { best_rate = tmp_rate; - *best_parent_rate = parent_rate; - *best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; + req->best_parent_hw = __clk_get_hw(parent); } if (!best_rate) break; } - return best_rate; + if (best_rate < 0) + return best_rate; + + req->rate = best_rate; + return 0; } static int clk_programmable_set_parent(struct clk_hw *hw, u8 index) diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index b0cbd2b1ff59..24747df97742 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -56,12 +56,8 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1)); } -static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw) +static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *parent = NULL; long best_rate = -EINVAL; @@ -80,23 +76,23 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, for (div = 1; div < SAM9X5_USB_MAX_DIV + 2; div++) { unsigned long tmp_parent_rate; - tmp_parent_rate = rate * div; + tmp_parent_rate = req->rate * div; tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate); tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div); - if (tmp_rate < rate) - tmp_diff = rate - tmp_rate; + if (tmp_rate < req->rate) + tmp_diff = req->rate - tmp_rate; else - tmp_diff = tmp_rate - rate; + tmp_diff = tmp_rate - req->rate; if (best_diff < 0 || best_diff > tmp_diff) { best_rate = tmp_rate; best_diff = tmp_diff; - *best_parent_rate = tmp_parent_rate; - *best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = tmp_parent_rate; + req->best_parent_hw = __clk_get_hw(parent); } - if (!best_diff || tmp_rate < rate) + if (!best_diff || tmp_rate < req->rate) break; } @@ -104,7 +100,11 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, break; } - return best_rate; + if (best_rate < 0) + return best_rate; + + req->rate = best_rate; + return 0; } static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index 79a98506c433..d9c039c1902c 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c @@ -1017,10 +1017,8 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate, rate ? rate : 1, *parent_rate, NULL); } -static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, struct clk_hw **best_parent) +static int kona_peri_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct kona_clk *bcm_clk = to_kona_clk(hw); struct clk *clk = hw->clk; @@ -1029,6 +1027,7 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, unsigned long best_delta; unsigned long best_rate; u32 parent_count; + long rate; u32 which; /* @@ -1037,14 +1036,21 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, */ WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT); parent_count = (u32)bcm_clk->init_data.num_parents; - if (parent_count < 2) - return kona_peri_clk_round_rate(hw, rate, best_parent_rate); + if (parent_count < 2) { + rate = kona_peri_clk_round_rate(hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + return 0; + } /* Unless we can do better, stick with current parent */ current_parent = clk_get_parent(clk); parent_rate = __clk_get_rate(current_parent); - best_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); - best_delta = abs(best_rate - rate); + best_rate = kona_peri_clk_round_rate(hw, req->rate, &parent_rate); + best_delta = abs(best_rate - req->rate); /* Check whether any other parent clock can produce a better result */ for (which = 0; which < parent_count; which++) { @@ -1058,17 +1064,19 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate, /* We don't support CLK_SET_RATE_PARENT */ parent_rate = __clk_get_rate(parent); - other_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate); - delta = abs(other_rate - rate); + other_rate = kona_peri_clk_round_rate(hw, req->rate, + &parent_rate); + delta = abs(other_rate - req->rate); if (delta < best_delta) { best_delta = delta; best_rate = other_rate; - *best_parent = __clk_get_hw(parent); - *best_parent_rate = parent_rate; + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; } } - return best_rate; + req->rate = best_rate; + return 0; } static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index) diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 616f5aef3c26..9e69f346ecc6 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -55,11 +55,8 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, return rate_ops->recalc_rate(rate_hw, parent_rate); } -static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +static int clk_composite_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_composite *composite = to_clk_composite(hw); const struct clk_ops *rate_ops = composite->rate_ops; @@ -71,25 +68,28 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, long tmp_rate, best_rate = 0; unsigned long rate_diff; unsigned long best_rate_diff = ULONG_MAX; + long rate; int i; if (rate_hw && rate_ops && rate_ops->determine_rate) { __clk_hw_set_clk(rate_hw, hw); - return rate_ops->determine_rate(rate_hw, rate, min_rate, - max_rate, - best_parent_rate, - best_parent_p); + return rate_ops->determine_rate(rate_hw, req); } else if (rate_hw && rate_ops && rate_ops->round_rate && mux_hw && mux_ops && mux_ops->set_parent) { - *best_parent_p = NULL; + req->best_parent_hw = NULL; if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) { parent = clk_get_parent(mux_hw->clk); - *best_parent_p = __clk_get_hw(parent); - *best_parent_rate = __clk_get_rate(parent); + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = __clk_get_rate(parent); - return rate_ops->round_rate(rate_hw, rate, - best_parent_rate); + rate = rate_ops->round_rate(rate_hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + return 0; } for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) { @@ -99,33 +99,33 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate, parent_rate = __clk_get_rate(parent); - tmp_rate = rate_ops->round_rate(rate_hw, rate, + tmp_rate = rate_ops->round_rate(rate_hw, req->rate, &parent_rate); if (tmp_rate < 0) continue; - rate_diff = abs(rate - tmp_rate); + rate_diff = abs(req->rate - tmp_rate); - if (!rate_diff || !*best_parent_p + if (!rate_diff || !req->best_parent_hw || best_rate_diff > rate_diff) { - *best_parent_p = __clk_get_hw(parent); - *best_parent_rate = parent_rate; + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; best_rate_diff = rate_diff; best_rate = tmp_rate; } if (!rate_diff) - return rate; + return 0; } - return best_rate; + req->rate = best_rate; + return 0; } else if (mux_hw && mux_ops && mux_ops->determine_rate) { __clk_hw_set_clk(mux_hw, hw); - return mux_ops->determine_rate(mux_hw, rate, min_rate, - max_rate, best_parent_rate, - best_parent_p); + return mux_ops->determine_rate(mux_hw, req); } else { pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n"); + req->rate = 0; return 0; } } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ddb4b541016f..4e9ff928ef88 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -436,28 +436,31 @@ static bool mux_is_better_rate(unsigned long rate, unsigned long now, return now <= rate && now > best; } -static long -clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p, +static int +clk_mux_determine_rate_flags(struct clk_hw *hw, struct clk_rate_request *req, unsigned long flags) { struct clk_core *core = hw->core, *parent, *best_parent = NULL; - int i, num_parents; - unsigned long parent_rate, best = 0; + int i, num_parents, ret; + unsigned long best = 0; + struct clk_rate_request parent_req = *req; /* if NO_REPARENT flag set, pass through to current parent */ if (core->flags & CLK_SET_RATE_NO_REPARENT) { parent = core->parent; - if (core->flags & CLK_SET_RATE_PARENT) - best = __clk_determine_rate(parent ? parent->hw : NULL, - rate, min_rate, max_rate); - else if (parent) + if (core->flags & CLK_SET_RATE_PARENT) { + ret = __clk_determine_rate(parent ? parent->hw : NULL, + &parent_req); + if (ret) + return ret; + + best = parent_req.rate; + } else if (parent) { best = clk_core_get_rate_nolock(parent); - else + } else { best = clk_core_get_rate_nolock(core); + } + goto out; } @@ -467,24 +470,30 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate, parent = clk_core_get_parent_by_index(core, i); if (!parent) continue; - if (core->flags & CLK_SET_RATE_PARENT) - parent_rate = __clk_determine_rate(parent->hw, rate, - min_rate, - max_rate); - else - parent_rate = clk_core_get_rate_nolock(parent); - if (mux_is_better_rate(rate, parent_rate, best, flags)) { + + if (core->flags & CLK_SET_RATE_PARENT) { + parent_req = *req; + ret = __clk_determine_rate(parent->hw, &parent_req); + if (ret) + continue; + } else { + parent_req.rate = clk_core_get_rate_nolock(parent); + } + + if (mux_is_better_rate(req->rate, parent_req.rate, + best, flags)) { best_parent = parent; - best = parent_rate; + best = parent_req.rate; } } out: if (best_parent) - *best_parent_p = best_parent->hw; - *best_parent_rate = best; + req->best_parent_hw = best_parent->hw; + req->best_parent_rate = best; + req->rate = best; - return best; + return 0; } struct clk *__clk_lookup(const char *name) @@ -515,28 +524,17 @@ static void clk_core_get_boundaries(struct clk_core *core, * directly as a determine_rate callback (e.g. for a mux), or from a more * complex clock that may combine a mux with other operations. */ -long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +int __clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate, - best_parent_rate, - best_parent_p, 0); + return clk_mux_determine_rate_flags(hw, req, 0); } EXPORT_SYMBOL_GPL(__clk_mux_determine_rate); -long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +int __clk_mux_determine_rate_closest(struct clk_hw *hw, + struct clk_rate_request *req) { - return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate, - best_parent_rate, - best_parent_p, - CLK_MUX_ROUND_CLOSEST); + return clk_mux_determine_rate_flags(hw, req, CLK_MUX_ROUND_CLOSEST); } EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest); @@ -759,14 +757,11 @@ int clk_enable(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_enable); -static unsigned long clk_core_round_rate_nolock(struct clk_core *core, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate) +static int clk_core_round_rate_nolock(struct clk_core *core, + struct clk_rate_request *req) { - unsigned long parent_rate = 0; struct clk_core *parent; - struct clk_hw *parent_hw; + long rate; lockdep_assert_held(&prepare_lock); @@ -774,21 +769,30 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core, return 0; parent = core->parent; - if (parent) - parent_rate = parent->rate; + if (parent) { + req->best_parent_hw = parent->hw; + req->best_parent_rate = parent->rate; + } else { + req->best_parent_hw = NULL; + req->best_parent_rate = 0; + } if (core->ops->determine_rate) { - parent_hw = parent ? parent->hw : NULL; - return core->ops->determine_rate(core->hw, rate, - min_rate, max_rate, - &parent_rate, &parent_hw); - } else if (core->ops->round_rate) - return core->ops->round_rate(core->hw, rate, &parent_rate); - else if (core->flags & CLK_SET_RATE_PARENT) - return clk_core_round_rate_nolock(core->parent, rate, min_rate, - max_rate); - else - return core->rate; + return core->ops->determine_rate(core->hw, req); + } else if (core->ops->round_rate) { + rate = core->ops->round_rate(core->hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + } else if (core->flags & CLK_SET_RATE_PARENT) { + return clk_core_round_rate_nolock(parent, req); + } else { + req->rate = core->rate; + } + + return 0; } /** @@ -800,15 +804,14 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core, * * Useful for clk_ops such as .set_rate and .determine_rate. */ -unsigned long __clk_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate) +int __clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - if (!hw) + if (!hw) { + req->rate = 0; return 0; + } - return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate); + return clk_core_round_rate_nolock(hw->core, req); } EXPORT_SYMBOL_GPL(__clk_determine_rate); @@ -821,15 +824,20 @@ EXPORT_SYMBOL_GPL(__clk_determine_rate); */ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) { - unsigned long min_rate; - unsigned long max_rate; + struct clk_rate_request req; + int ret; if (!clk) return 0; - clk_core_get_boundaries(clk->core, &min_rate, &max_rate); + clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate); + req.rate = rate; + + ret = clk_core_round_rate_nolock(clk->core, &req); + if (ret) + return 0; - return clk_core_round_rate_nolock(clk->core, rate, min_rate, max_rate); + return req.rate; } EXPORT_SYMBOL_GPL(__clk_round_rate); @@ -1249,7 +1257,6 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, { struct clk_core *top = core; struct clk_core *old_parent, *parent; - struct clk_hw *parent_hw; unsigned long best_parent_rate = 0; unsigned long new_rate; unsigned long min_rate; @@ -1270,20 +1277,29 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core, /* find the closest rate and parent clk/rate */ if (core->ops->determine_rate) { - parent_hw = parent ? parent->hw : NULL; - ret = core->ops->determine_rate(core->hw, rate, - min_rate, - max_rate, - &best_parent_rate, - &parent_hw); + struct clk_rate_request req; + + req.rate = rate; + req.min_rate = min_rate; + req.max_rate = max_rate; + if (parent) { + req.best_parent_hw = parent->hw; + req.best_parent_rate = parent->rate; + } else { + req.best_parent_hw = NULL; + req.best_parent_rate = 0; + } + + ret = core->ops->determine_rate(core->hw, &req); if (ret < 0) return NULL; - new_rate = ret; - parent = parent_hw ? parent_hw->core : NULL; + best_parent_rate = req.best_parent_rate; + new_rate = req.rate; + parent = req.best_parent_hw ? req.best_parent_hw->core : NULL; } else if (core->ops->round_rate) { ret = core->ops->round_rate(core->hw, rate, - &best_parent_rate); + &best_parent_rate); if (ret < 0) return NULL; diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c index 715d34a5ef9b..a0674ba6659e 100644 --- a/drivers/clk/hisilicon/clk-hi3620.c +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -294,34 +294,29 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw, } } -static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +static int mmc_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_mmc *mclk = to_mmc(hw); - unsigned long best = 0; - if ((rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) { - rate = 13000000; - best = 26000000; - } else if (rate <= 26000000) { - rate = 25000000; - best = 180000000; - } else if (rate <= 52000000) { - rate = 50000000; - best = 360000000; - } else if (rate <= 100000000) { - rate = 100000000; - best = 720000000; + if ((req->rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) { + req->rate = 13000000; + req->best_parent_rate = 26000000; + } else if (req->rate <= 26000000) { + req->rate = 25000000; + req->best_parent_rate = 180000000; + } else if (req->rate <= 52000000) { + req->rate = 50000000; + req->best_parent_rate = 360000000; + } else if (req->rate <= 100000000) { + req->rate = 100000000; + req->best_parent_rate = 720000000; } else { /* max is 180M */ - rate = 180000000; - best = 1440000000; + req->rate = 180000000; + req->best_parent_rate = 1440000000; } - *best_parent_rate = best; - return rate; + return 0; } static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len) diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c index de6a873175d2..7a37432761f9 100644 --- a/drivers/clk/mmp/clk-mix.c +++ b/drivers/clk/mmp/clk-mix.c @@ -201,11 +201,8 @@ error: return ret; } -static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int mmp_clk_mix_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct mmp_clk_mix *mix = to_clk_mix(hw); struct mmp_clk_mix_clk_table *item; @@ -221,7 +218,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, parent = NULL; mix_rate_best = 0; parent_rate_best = 0; - gap_best = rate; + gap_best = req->rate; parent_best = NULL; if (mix->table) { @@ -233,7 +230,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, item->parent_index); parent_rate = __clk_get_rate(parent); mix_rate = parent_rate / item->divisor; - gap = abs(mix_rate - rate); + gap = abs(mix_rate - req->rate); if (parent_best == NULL || gap < gap_best) { parent_best = parent; parent_rate_best = parent_rate; @@ -251,7 +248,7 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, for (j = 0; j < div_val_max; j++) { div = _get_div(mix, j); mix_rate = parent_rate / div; - gap = abs(mix_rate - rate); + gap = abs(mix_rate - req->rate); if (parent_best == NULL || gap < gap_best) { parent_best = parent; parent_rate_best = parent_rate; @@ -265,10 +262,11 @@ static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate, } found: - *best_parent_rate = parent_rate_best; - *best_parent_clk = __clk_get_hw(parent_best); + req->best_parent_rate = parent_rate_best; + req->best_parent_hw = __clk_get_hw(parent_best); + req->rate = mix_rate_best; - return mix_rate_best; + return 0; } static int mmp_clk_mix_set_rate_and_parent(struct clk_hw *hw, diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c index 245d5063a385..6017a76b47c8 100644 --- a/drivers/clk/qcom/clk-pll.c +++ b/drivers/clk/qcom/clk-pll.c @@ -135,19 +135,23 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate) return NULL; } -static long -clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int +clk_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { + struct clk *parent = __clk_get_parent(hw->clk); struct clk_pll *pll = to_clk_pll(hw); const struct pll_freq_tbl *f; - f = find_freq(pll->freq_tbl, rate); + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = __clk_get_rate(parent); + + f = find_freq(pll->freq_tbl, req->rate); if (!f) - return clk_pll_recalc_rate(hw, *p_rate); + req->rate = clk_pll_recalc_rate(hw, req->best_parent_rate); + else + req->rate = f->freq; - return f->freq; + return 0; } static int diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index 7b3d62674203..2bc42bb21b3d 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c @@ -404,13 +404,11 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return calc_rate(parent_rate, m, n, mode, pre_div); } -static long _freq_tbl_determine_rate(struct clk_hw *hw, - const struct freq_tbl *f, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p_hw, +static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, + struct clk_rate_request *req, const struct parent_map *parent_map) { - unsigned long clk_flags; + unsigned long clk_flags, rate = req->rate; struct clk *p; int index; @@ -435,25 +433,24 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, } else { rate = __clk_get_rate(p); } - *p_hw = __clk_get_hw(p); - *p_rate = rate; + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = rate; + req->rate = f->freq; - return f->freq; + return 0; } -static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_rcg_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg *rcg = to_clk_rcg(hw); - return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate, - max_rate, p_rate, p, rcg->s.parent_map); + return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, + rcg->s.parent_map); } -static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_dyn_rcg_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw); u32 reg; @@ -464,13 +461,11 @@ static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate, bank = reg_to_bank(rcg, reg); s = &rcg->s[bank]; - return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate, - max_rate, p_rate, p, s->parent_map); + return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, s->parent_map); } -static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p_hw) +static int clk_rcg_bypass_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg *rcg = to_clk_rcg(hw); const struct freq_tbl *f = rcg->freq_tbl; @@ -478,10 +473,11 @@ static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate, int index = qcom_find_src_index(hw, rcg->s.parent_map, f->src); p = clk_get_parent_by_index(hw->clk, index); - *p_hw = __clk_get_hw(p); - *p_rate = __clk_round_rate(p, rate); + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = __clk_round_rate(p, req->rate); + req->rate = req->best_parent_rate; - return *p_rate; + return 0; } static int __clk_rcg_set_rate(struct clk_rcg *rcg, const struct freq_tbl *f) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index b95d17fbb8d7..aa6c3bdac040 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -176,11 +176,10 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return calc_rate(parent_rate, m, n, mode, hid_div); } -static long _freq_tbl_determine_rate(struct clk_hw *hw, - const struct freq_tbl *f, unsigned long rate, - unsigned long *p_rate, struct clk_hw **p_hw) +static int _freq_tbl_determine_rate(struct clk_hw *hw, + const struct freq_tbl *f, struct clk_rate_request *req) { - unsigned long clk_flags; + unsigned long clk_flags, rate = req->rate; struct clk *p; struct clk_rcg2 *rcg = to_clk_rcg2(hw); int index; @@ -210,19 +209,19 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw, } else { rate = __clk_get_rate(p); } - *p_hw = __clk_get_hw(p); - *p_rate = rate; + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = rate; + req->rate = f->freq; - return f->freq; + return 0; } -static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_rcg2_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); - return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); + return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req); } static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) @@ -374,35 +373,34 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw, return clk_edp_pixel_set_rate(hw, rate, parent_rate); } -static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_edp_pixel_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f = rcg->freq_tbl; const struct frac_entry *frac; int delta = 100000; - s64 src_rate = *p_rate; s64 request; u32 mask = BIT(rcg->hid_width) - 1; u32 hid_div; int index = qcom_find_src_index(hw, rcg->parent_map, f->src); + struct clk *p = clk_get_parent_by_index(hw->clk, index); /* Force the correct parent */ - *p = __clk_get_hw(clk_get_parent_by_index(hw->clk, index)); + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = __clk_get_rate(p); - if (src_rate == 810000000) + if (req->best_parent_rate == 810000000) frac = frac_table_810m; else frac = frac_table_675m; for (; frac->num; frac++) { - request = rate; + request = req->rate; request *= frac->den; request = div_s64(request, frac->num); - if ((src_rate < (request - delta)) || - (src_rate > (request + delta))) + if ((req->best_parent_rate < (request - delta)) || + (req->best_parent_rate > (request + delta))) continue; regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, @@ -410,8 +408,10 @@ static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, hid_div >>= CFG_SRC_DIV_SHIFT; hid_div &= mask; - return calc_rate(src_rate, frac->num, frac->den, !!frac->den, - hid_div); + req->rate = calc_rate(req->best_parent_rate, + frac->num, frac->den, + !!frac->den, hid_div); + return 0; } return -EINVAL; @@ -428,9 +428,8 @@ const struct clk_ops clk_edp_pixel_ops = { }; EXPORT_SYMBOL_GPL(clk_edp_pixel_ops); -static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p_hw) +static int clk_byte_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f = rcg->freq_tbl; @@ -439,17 +438,19 @@ static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, u32 mask = BIT(rcg->hid_width) - 1; struct clk *p; - if (rate == 0) + if (req->rate == 0) return -EINVAL; p = clk_get_parent_by_index(hw->clk, index); - *p_hw = __clk_get_hw(p); - *p_rate = parent_rate = __clk_round_rate(p, rate); + req->best_parent_hw = __clk_get_hw(p); + req->best_parent_rate = parent_rate = __clk_round_rate(p, req->rate); - div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; + div = DIV_ROUND_UP((2 * parent_rate), req->rate) - 1; div = min_t(u32, div, mask); - return calc_rate(parent_rate, 0, 0, 0, div); + req->rate = calc_rate(parent_rate, 0, 0, 0, div); + + return 0; } static int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate, @@ -494,10 +495,8 @@ static const struct frac_entry frac_table_pixel[] = { { } }; -static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *p_rate, struct clk_hw **p) +static int clk_pixel_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); unsigned long request, src_rate; @@ -507,18 +506,19 @@ static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, int index = qcom_find_src_index(hw, rcg->parent_map, f->src); struct clk *parent = clk_get_parent_by_index(hw->clk, index); - *p = __clk_get_hw(parent); + req->best_parent_hw = __clk_get_hw(parent); for (; frac->num; frac++) { - request = (rate * frac->den) / frac->num; + request = (req->rate * frac->den) / frac->num; src_rate = __clk_round_rate(parent, request); if ((src_rate < (request - delta)) || (src_rate > (request + delta))) continue; - *p_rate = src_rate; - return (src_rate * frac->num) / frac->den; + req->best_parent_rate = src_rate; + req->rate = (src_rate * frac->num) / frac->den; + return 0; } return -EINVAL; diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 8c20190a3e9f..7a485870991d 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -79,11 +79,8 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate, return rate; } -static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p) +static int clk_factors_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *clk = hw->clk, *parent, *best_parent = NULL; int i, num_parents; @@ -96,13 +93,14 @@ static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, if (!parent) continue; if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT) - parent_rate = __clk_round_rate(parent, rate); + parent_rate = __clk_round_rate(parent, req->rate); else parent_rate = __clk_get_rate(parent); - child_rate = clk_factors_round_rate(hw, rate, &parent_rate); + child_rate = clk_factors_round_rate(hw, req->rate, + &parent_rate); - if (child_rate <= rate && child_rate > best_child_rate) { + if (child_rate <= req->rate && child_rate > best_child_rate) { best_parent = parent; best = parent_rate; best_child_rate = child_rate; @@ -110,10 +108,11 @@ static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate, } if (best_parent) - *best_parent_p = __clk_get_hw(best_parent); - *best_parent_rate = best; + req->best_parent_hw = __clk_get_hw(best_parent); + req->best_parent_rate = best; + req->rate = best_child_rate; - return best_child_rate; + return 0; } static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate, diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c index 63cf149195ae..d70c1ea345db 100644 --- a/drivers/clk/sunxi/clk-sun6i-ar100.c +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c @@ -44,17 +44,14 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw, return (parent_rate >> shift) / (div + 1); } -static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int ar100_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { int nparents = __clk_get_num_parents(hw->clk); long best_rate = -EINVAL; int i; - *best_parent_clk = NULL; + req->best_parent_hw = NULL; for (i = 0; i < nparents; i++) { unsigned long parent_rate; @@ -65,7 +62,7 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, parent = clk_get_parent_by_index(hw->clk, i); parent_rate = __clk_get_rate(parent); - div = DIV_ROUND_UP(parent_rate, rate); + div = DIV_ROUND_UP(parent_rate, req->rate); /* * The AR100 clk contains 2 divisors: @@ -101,14 +98,16 @@ static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate, continue; tmp_rate = (parent_rate >> shift) / div; - if (!*best_parent_clk || tmp_rate > best_rate) { - *best_parent_clk = __clk_get_hw(parent); - *best_parent_rate = parent_rate; + if (!req->best_parent_hw || tmp_rate > best_rate) { + req->best_parent_hw = __clk_get_hw(parent); + req->best_parent_rate = parent_rate; best_rate = tmp_rate; } } - return best_rate; + req->rate = best_rate; + + return 0; } static int ar100_set_parent(struct clk_hw *hw, u8 index) diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 9a82f17d2d73..d0f72a151bf1 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -118,11 +118,8 @@ static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp, return (parent_rate / calcm) >> calcp; } -static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk) +static int sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct clk *clk = hw->clk, *parent, *best_parent = NULL; int i, num_parents; @@ -135,14 +132,14 @@ static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate, if (!parent) continue; if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT) - parent_rate = __clk_round_rate(parent, rate); + parent_rate = __clk_round_rate(parent, req->rate); else parent_rate = __clk_get_rate(parent); - child_rate = sun6i_ahb1_clk_round(rate, NULL, NULL, i, + child_rate = sun6i_ahb1_clk_round(req->rate, NULL, NULL, i, parent_rate); - if (child_rate <= rate && child_rate > best_child_rate) { + if (child_rate <= req->rate && child_rate > best_child_rate) { best_parent = parent; best = parent_rate; best_child_rate = child_rate; @@ -150,10 +147,11 @@ static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate, } if (best_parent) - *best_parent_clk = __clk_get_hw(best_parent); - *best_parent_rate = best; + req->best_parent_hw = __clk_get_hw(best_parent); + req->best_parent_rate = best; + req->rate = best_child_rate; - return best_child_rate; + return 0; } static int sun6i_ahb1_clk_set_rate(struct clk_hw *hw, unsigned long rate, diff --git a/drivers/clk/tegra/clk-emc.c b/drivers/clk/tegra/clk-emc.c index 7649685c86bc..08ae518c9950 100644 --- a/drivers/clk/tegra/clk-emc.c +++ b/drivers/clk/tegra/clk-emc.c @@ -116,11 +116,7 @@ static unsigned long emc_recalc_rate(struct clk_hw *hw, * safer since things have EMC rate floors. Also don't touch parent_rate * since we don't want the CCF to play with our parent clocks. */ -static long emc_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw) +static int emc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { struct tegra_clk_emc *tegra; u8 ram_code = tegra_read_ram_code(); @@ -135,22 +131,28 @@ static long emc_determine_rate(struct clk_hw *hw, unsigned long rate, timing = tegra->timings + i; - if (timing->rate > max_rate) { + if (timing->rate > req->max_rate) { i = min(i, 1); - return tegra->timings[i - 1].rate; + req->rate = tegra->timings[i - 1].rate; + return 0; } - if (timing->rate < min_rate) + if (timing->rate < req->min_rate) continue; - if (timing->rate >= rate) - return timing->rate; + if (timing->rate >= req->rate) { + req->rate = timing->rate; + return 0; + } } - if (timing) - return timing->rate; + if (timing) { + req->rate = timing->rate; + return 0; + } - return __clk_get_rate(hw->clk); + req->rate = __clk_get_rate(hw->clk); + return 0; } static u8 emc_get_parent(struct clk_hw *hw) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 78842f46f152..14998f05acf2 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -37,6 +37,28 @@ struct clk_hw; struct clk_core; struct dentry; +/** + * struct clk_rate_request - Structure encoding the clk constraints that + * a clock user might require. + * + * @rate: Requested clock rate. This field will be adjusted by + * clock drivers according to hardware capabilities. + * @min_rate: Minimum rate imposed by clk users. + * @max_rate: Maximum rate a imposed by clk users. + * @best_parent_rate: The best parent rate a parent can provide to fulfill the + * requested constraints. + * @best_parent_hw: The most appropriate parent clock that fulfills the + * requested constraints. + * + */ +struct clk_rate_request { + unsigned long rate; + unsigned long min_rate; + unsigned long max_rate; + unsigned long best_parent_rate; + struct clk_hw *best_parent_hw; +}; + /** * struct clk_ops - Callback operations for hardware clocks; these are to * be provided by the clock implementation, and will be called by drivers @@ -176,12 +198,8 @@ struct clk_ops { unsigned long parent_rate); long (*round_rate)(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate); - long (*determine_rate)(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_hw); + int (*determine_rate)(struct clk_hw *hw, + struct clk_rate_request *req); int (*set_parent)(struct clk_hw *hw, u8 index); u8 (*get_parent)(struct clk_hw *hw); int (*set_rate)(struct clk_hw *hw, unsigned long rate, @@ -578,20 +596,11 @@ unsigned long __clk_get_flags(struct clk *clk); bool __clk_is_prepared(struct clk *clk); bool __clk_is_enabled(struct clk *clk); struct clk *__clk_lookup(const char *name); -long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p); -unsigned long __clk_determine_rate(struct clk_hw *core, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate); -long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_p); +int __clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req); +int __clk_determine_rate(struct clk_hw *core, struct clk_rate_request *req); +int __clk_mux_determine_rate_closest(struct clk_hw *hw, + struct clk_rate_request *req); void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent); static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src) diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 79b76e13d904..448b4f87b9eb 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -269,23 +269,15 @@ int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate, u8 index); -long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk); +int omap3_noncore_dpll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req); unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, unsigned long parent_rate); long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw, unsigned long target_rate, unsigned long *parent_rate); -long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long min_rate, - unsigned long max_rate, - unsigned long *best_parent_rate, - struct clk_hw **best_parent_clk); +int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req); u8 omap2_init_dpll_parent(struct clk_hw *hw); unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate); long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, -- cgit v1.3-6-gb490 From 57d866e606ddf2a0cd51f7140cfd8df1fdaa48f6 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 9 Jul 2015 22:39:38 +0200 Subject: clk: fix some determine_rate implementations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some determine_rate implementations are not returning an error when they failed to adapt the rate according to the rate request. Fix them so that they return an error instead of silently returning 0. Signed-off-by: Boris Brezillon CC: Jonathan Corbet CC: Tony Lindgren CC: Ralf Baechle CC: "Emilio López" CC: Maxime Ripard Cc: Tero Kristo CC: Peter De Schrijver CC: Prashant Gaikwad CC: Stephen Warren CC: Thierry Reding CC: Alexandre Courbot CC: linux-doc@vger.kernel.org CC: linux-kernel@vger.kernel.org CC: linux-arm-kernel@lists.infradead.org CC: linux-omap@vger.kernel.org CC: linux-mips@linux-mips.org CC: linux-tegra@vger.kernel.org Signed-off-by: Stephen Boyd --- arch/mips/alchemy/common/clock.c | 4 ++++ drivers/clk/clk-composite.c | 3 +-- drivers/clk/clk.c | 3 +++ drivers/clk/hisilicon/clk-hi3620.c | 2 +- drivers/clk/mmp/clk-mix.c | 5 ++++- drivers/clk/sunxi/clk-factors.c | 6 ++++-- drivers/clk/sunxi/clk-sun6i-ar100.c | 3 +++ drivers/clk/sunxi/clk-sunxi.c | 6 ++++-- 8 files changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c index 0b4cf3e9f005..7cc3eed83a1e 100644 --- a/arch/mips/alchemy/common/clock.c +++ b/arch/mips/alchemy/common/clock.c @@ -469,9 +469,13 @@ static int alchemy_clk_fgcs_detr(struct clk_hw *hw, } } + if (br < 0) + return br; + req->best_parent_rate = bpr; req->best_parent_hw = __clk_get_hw(bpc); req->rate = br; + return 0; } diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 9e69f346ecc6..35ac062d7df6 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -125,8 +125,7 @@ static int clk_composite_determine_rate(struct clk_hw *hw, return mux_ops->determine_rate(mux_hw, req); } else { pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n"); - req->rate = 0; - return 0; + return -EINVAL; } } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 4e9ff928ef88..c907289ff03c 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -487,6 +487,9 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, struct clk_rate_request *req, } } + if (!best_parent) + return -EINVAL; + out: if (best_parent) req->best_parent_hw = best_parent->hw; diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c index a0674ba6659e..c84ec867a91c 100644 --- a/drivers/clk/hisilicon/clk-hi3620.c +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -316,7 +316,7 @@ static int mmc_clk_determine_rate(struct clk_hw *hw, req->rate = 180000000; req->best_parent_rate = 1440000000; } - return 0; + return -EINVAL; } static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len) diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c index 7a37432761f9..665cb6794639 100644 --- a/drivers/clk/mmp/clk-mix.c +++ b/drivers/clk/mmp/clk-mix.c @@ -218,7 +218,7 @@ static int mmp_clk_mix_determine_rate(struct clk_hw *hw, parent = NULL; mix_rate_best = 0; parent_rate_best = 0; - gap_best = req->rate; + gap_best = ULONG_MAX; parent_best = NULL; if (mix->table) { @@ -262,6 +262,9 @@ static int mmp_clk_mix_determine_rate(struct clk_hw *hw, } found: + if (!parent_best) + return -EINVAL; + req->best_parent_rate = parent_rate_best; req->best_parent_hw = __clk_get_hw(parent_best); req->rate = mix_rate_best; diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 7a485870991d..94e2570a2409 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -107,8 +107,10 @@ static int clk_factors_determine_rate(struct clk_hw *hw, } } - if (best_parent) - req->best_parent_hw = __clk_get_hw(best_parent); + if (!best_parent) + return -EINVAL; + + req->best_parent_hw = __clk_get_hw(best_parent); req->best_parent_rate = best; req->rate = best_child_rate; diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c index d70c1ea345db..21b076ee59d1 100644 --- a/drivers/clk/sunxi/clk-sun6i-ar100.c +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c @@ -105,6 +105,9 @@ static int ar100_determine_rate(struct clk_hw *hw, } } + if (best_rate < 0) + return best_rate; + req->rate = best_rate; return 0; diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index d0f72a151bf1..0e15165280dc 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -146,8 +146,10 @@ static int sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, } } - if (best_parent) - req->best_parent_hw = __clk_get_hw(best_parent); + if (!best_parent) + return -EINVAL; + + req->best_parent_hw = __clk_get_hw(best_parent); req->best_parent_rate = best; req->rate = best_child_rate; -- cgit v1.3-6-gb490 From 5e32940621eb62064d98f42c9889db71b0368bde Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 11 Jul 2015 10:02:46 -0400 Subject: libnvdimm, btt: sparse fix Fix: drivers/nvdimm/btt.c:635:29: warning: restricted __le64 degrades to integer Signed-off-by: Dan Williams --- drivers/nvdimm/btt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 411c7b2bb37a..552f1c4f4dc6 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -632,8 +632,9 @@ static void parse_arena_meta(struct arena_info *arena, struct btt_sb *super, arena->logoff = arena_off + le64_to_cpu(super->logoff); arena->info2off = arena_off + le64_to_cpu(super->info2off); - arena->size = (super->nextoff > 0) ? (le64_to_cpu(super->nextoff)) : - (arena->info2off - arena->infooff + BTT_PG_SIZE); + arena->size = (le64_to_cpu(super->nextoff) > 0) + ? (le64_to_cpu(super->nextoff)) + : (arena->info2off - arena->infooff + BTT_PG_SIZE); arena->flags = le32_to_cpu(super->flags); } -- cgit v1.3-6-gb490 From 39c686b862cdb2049b90e095b6c6c727b2a7ab60 Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 9 Jul 2015 13:25:36 -0600 Subject: libnvdimm: Add DSM support for Address Range Scrub commands Add support for the three ARS DSM commands: - Query ARS Capabilities - Queries the firmware to check if a given range supports scrub, and if so, which type (persistent vs. volatile) - Start ARS - Starts a scrub for a given range/type - Query ARS Status - Checks status of a previously started scrub, and provides the error logs if any. The commands are described by the example DSM spec at: http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf Also add these commands to the nfit_test test framework, and return canned data. Signed-off-by: Vishal Verma Signed-off-by: Dan Williams --- drivers/acpi/nfit.c | 1 + drivers/acpi/nfit.h | 1 + include/uapi/linux/ndctl.h | 10 ++ tools/testing/nvdimm/test/nfit.c | 199 +++++++++++++++++++++++++++------------ 4 files changed, 152 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 628a42c41ab1..ef8a664db254 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -868,6 +868,7 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc) struct acpi_device *adev; int i; + nd_desc->dsm_mask = acpi_desc->bus_dsm_force_en; adev = to_acpi_dev(acpi_desc); if (!adev) return; diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index 79b6d83875c1..f2c2bb751882 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h @@ -107,6 +107,7 @@ struct acpi_nfit_desc { struct nvdimm_bus *nvdimm_bus; struct device *dev; unsigned long dimm_dsm_force_en; + unsigned long bus_dsm_force_en; int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa, void *iobuf, u64 len, int rw); }; diff --git a/include/uapi/linux/ndctl.h b/include/uapi/linux/ndctl.h index e94bc20016b2..5b4a4be06e2b 100644 --- a/include/uapi/linux/ndctl.h +++ b/include/uapi/linux/ndctl.h @@ -111,6 +111,11 @@ enum { ND_CMD_VENDOR = 9, }; +enum { + ND_ARS_VOLATILE = 1, + ND_ARS_PERSISTENT = 2, +}; + static inline const char *nvdimm_bus_cmd_name(unsigned cmd) { static const char * const names[] = { @@ -194,4 +199,9 @@ enum nd_driver_flags { enum { ND_MIN_NAMESPACE_SIZE = 0x00400000, }; + +enum ars_masks { + ARS_STATUS_MASK = 0x0000FFFF, + ARS_EXT_STATUS_SHIFT = 16, +}; #endif /* __NDCTL_H__ */ diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index d0bdae40ccc9..28dba918524e 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -147,75 +147,153 @@ static struct nfit_test *to_nfit_test(struct device *dev) return container_of(pdev, struct nfit_test, pdev); } +static int nfit_test_cmd_get_config_size(struct nd_cmd_get_config_size *nd_cmd, + unsigned int buf_len) +{ + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + + nd_cmd->status = 0; + nd_cmd->config_size = LABEL_SIZE; + nd_cmd->max_xfer = SZ_4K; + + return 0; +} + +static int nfit_test_cmd_get_config_data(struct nd_cmd_get_config_data_hdr + *nd_cmd, unsigned int buf_len, void *label) +{ + unsigned int len, offset = nd_cmd->in_offset; + int rc; + + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + if (offset >= LABEL_SIZE) + return -EINVAL; + if (nd_cmd->in_length + sizeof(*nd_cmd) > buf_len) + return -EINVAL; + + nd_cmd->status = 0; + len = min(nd_cmd->in_length, LABEL_SIZE - offset); + memcpy(nd_cmd->out_buf, label + offset, len); + rc = buf_len - sizeof(*nd_cmd) - len; + + return rc; +} + +static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd, + unsigned int buf_len, void *label) +{ + unsigned int len, offset = nd_cmd->in_offset; + u32 *status; + int rc; + + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + if (offset >= LABEL_SIZE) + return -EINVAL; + if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len) + return -EINVAL; + + status = (void *)nd_cmd + nd_cmd->in_length + sizeof(*nd_cmd); + *status = 0; + len = min(nd_cmd->in_length, LABEL_SIZE - offset); + memcpy(label + offset, nd_cmd->in_buf, len); + rc = buf_len - sizeof(*nd_cmd) - (len + 4); + + return rc; +} + +static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd, + unsigned int buf_len) +{ + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + + nd_cmd->max_ars_out = 256; + nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16; + + return 0; +} + +static int nfit_test_cmd_ars_start(struct nd_cmd_ars_start *nd_cmd, + unsigned int buf_len) +{ + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + + nd_cmd->status = 0; + + return 0; +} + +static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd, + unsigned int buf_len) +{ + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + + nd_cmd->out_length = 256; + nd_cmd->num_records = 0; + nd_cmd->status = 0; + + return 0; +} + static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd, void *buf, unsigned int buf_len) { struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); - struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); - int i, rc; + int i, rc = 0; + + if (nvdimm) { + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); - if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask)) - return -ENOTTY; + if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask)) + return -ENOTTY; - /* lookup label space for the given dimm */ - for (i = 0; i < ARRAY_SIZE(handle); i++) - if (__to_nfit_memdev(nfit_mem)->device_handle == handle[i]) + /* lookup label space for the given dimm */ + for (i = 0; i < ARRAY_SIZE(handle); i++) + if (__to_nfit_memdev(nfit_mem)->device_handle == + handle[i]) + break; + if (i >= ARRAY_SIZE(handle)) + return -ENXIO; + + switch (cmd) { + case ND_CMD_GET_CONFIG_SIZE: + rc = nfit_test_cmd_get_config_size(buf, buf_len); break; - if (i >= ARRAY_SIZE(handle)) - return -ENXIO; + case ND_CMD_GET_CONFIG_DATA: + rc = nfit_test_cmd_get_config_data(buf, buf_len, + t->label[i]); + break; + case ND_CMD_SET_CONFIG_DATA: + rc = nfit_test_cmd_set_config_data(buf, buf_len, + t->label[i]); + break; + default: + return -ENOTTY; + } + } else { + if (!nd_desc || !test_bit(cmd, &nd_desc->dsm_mask)) + return -ENOTTY; - switch (cmd) { - case ND_CMD_GET_CONFIG_SIZE: { - struct nd_cmd_get_config_size *nd_cmd = buf; - - if (buf_len < sizeof(*nd_cmd)) - return -EINVAL; - nd_cmd->status = 0; - nd_cmd->config_size = LABEL_SIZE; - nd_cmd->max_xfer = SZ_4K; - rc = 0; - break; - } - case ND_CMD_GET_CONFIG_DATA: { - struct nd_cmd_get_config_data_hdr *nd_cmd = buf; - unsigned int len, offset = nd_cmd->in_offset; - - if (buf_len < sizeof(*nd_cmd)) - return -EINVAL; - if (offset >= LABEL_SIZE) - return -EINVAL; - if (nd_cmd->in_length + sizeof(*nd_cmd) > buf_len) - return -EINVAL; - - nd_cmd->status = 0; - len = min(nd_cmd->in_length, LABEL_SIZE - offset); - memcpy(nd_cmd->out_buf, t->label[i] + offset, len); - rc = buf_len - sizeof(*nd_cmd) - len; - break; - } - case ND_CMD_SET_CONFIG_DATA: { - struct nd_cmd_set_config_hdr *nd_cmd = buf; - unsigned int len, offset = nd_cmd->in_offset; - u32 *status; - - if (buf_len < sizeof(*nd_cmd)) - return -EINVAL; - if (offset >= LABEL_SIZE) - return -EINVAL; - if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len) - return -EINVAL; - - status = buf + nd_cmd->in_length + sizeof(*nd_cmd); - *status = 0; - len = min(nd_cmd->in_length, LABEL_SIZE - offset); - memcpy(t->label[i] + offset, nd_cmd->in_buf, len); - rc = buf_len - sizeof(*nd_cmd) - (len + 4); - break; - } - default: - return -ENOTTY; + switch (cmd) { + case ND_CMD_ARS_CAP: + rc = nfit_test_cmd_ars_cap(buf, buf_len); + break; + case ND_CMD_ARS_START: + rc = nfit_test_cmd_ars_start(buf, buf_len); + break; + case ND_CMD_ARS_STATUS: + rc = nfit_test_cmd_ars_status(buf, buf_len); + break; + default: + return -ENOTTY; + } } return rc; @@ -876,6 +954,9 @@ static void nfit_test0_setup(struct nfit_test *t) set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); + set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); + set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); + set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en); nd_desc = &acpi_desc->nd_desc; nd_desc->ndctl = nfit_test_ctl; } -- cgit v1.3-6-gb490 From 6b47496a6fc81816e7edaf8224dfb88e402a05f5 Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 23 Jul 2015 11:58:48 -0600 Subject: libnvdimm, pmem: Change pmem physical sector size to PAGE_SIZE Based on a patch: c8fa317 brd: Request from fdisk 4k alignment by Boaz Harrosh, allow fdisk to create properly aligned partitions for DAX. This will also cause mkfs.ext4 to emit a warning if using a file system block size of less than PAGE_SIZE. Cc: Dan Williams Cc: Ross Zwisler Cc: Matthew Wilcox Cc: Christoph Hellwig Cc: Elliott, Robert Signed-off-by: Vishal Verma Acked-by: Boaz Harrosh Acked-by: Ross Zwisler Signed-off-by: Dan Williams --- drivers/nvdimm/pmem.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index ade9eb917a4d..bcf48f133443 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -162,6 +162,7 @@ static int pmem_attach_disk(struct nd_namespace_common *ndns, return -ENOMEM; blk_queue_make_request(pmem->pmem_queue, pmem_make_request); + blk_queue_physical_block_size(pmem->pmem_queue, PAGE_SIZE); blk_queue_max_hw_sectors(pmem->pmem_queue, UINT_MAX); blk_queue_bounce_limit(pmem->pmem_queue, BLK_BOUNCE_ANY); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, pmem->pmem_queue); -- cgit v1.3-6-gb490 From 60e95f43fc8573e81f54b0c1e0bc542c2260d956 Mon Sep 17 00:00:00 2001 From: Linda Knippers Date: Wed, 22 Jul 2015 16:17:22 -0400 Subject: nfit: Don't check _STA on NVDIMM devices The _STA only applies to the root device, not the individual NVDIMMS, so don't check here. NVDIMM device state flags are checked elsewhere. Signed-off-by: Linda Knippers Signed-off-by: Dan Williams --- drivers/acpi/nfit.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index ef8a664db254..7c2638f914a9 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -764,9 +764,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, struct acpi_device *adev, *adev_dimm; struct device *dev = acpi_desc->dev; const u8 *uuid = to_nfit_uuid(NFIT_DEV_DIMM); - unsigned long long sta; - int i, rc = -ENODEV; - acpi_status status; + int i; nfit_mem->dsm_mask = acpi_desc->dimm_dsm_force_en; adev = to_acpi_dev(acpi_desc); @@ -781,25 +779,11 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, return force_enable_dimms ? 0 : -ENODEV; } - status = acpi_evaluate_integer(adev_dimm->handle, "_STA", NULL, &sta); - if (status == AE_NOT_FOUND) { - dev_dbg(dev, "%s missing _STA, assuming enabled...\n", - dev_name(&adev_dimm->dev)); - rc = 0; - } else if (ACPI_FAILURE(status)) - dev_err(dev, "%s failed to retrieve_STA, disabling...\n", - dev_name(&adev_dimm->dev)); - else if ((sta & ACPI_STA_DEVICE_ENABLED) == 0) - dev_info(dev, "%s disabled by firmware\n", - dev_name(&adev_dimm->dev)); - else - rc = 0; - for (i = ND_CMD_SMART; i <= ND_CMD_VENDOR; i++) if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i)) set_bit(i, &nfit_mem->dsm_mask); - return force_enable_dimms ? 0 : rc; + return 0; } static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) -- cgit v1.3-6-gb490 From a636df9673e1e4627722777fe6075943372e76be Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 27 Jul 2015 17:26:38 -0700 Subject: Input: tsc2005 - improve readability of register defines Improve defines for first control byte by removing 0x00 prefix (the defines are for 8 bit values and not for 16 bit values) and expose register structure by exposing the shift. Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index aaf947525cd9..2a27a1f77bcb 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -61,16 +61,24 @@ #define TSC2005_CMD_12BIT 0x04 /* control byte 0 */ -#define TSC2005_REG_READ 0x0001 -#define TSC2005_REG_PND0 0x0002 -#define TSC2005_REG_X 0x0000 -#define TSC2005_REG_Y 0x0008 -#define TSC2005_REG_Z1 0x0010 -#define TSC2005_REG_Z2 0x0018 -#define TSC2005_REG_TEMP_HIGH 0x0050 -#define TSC2005_REG_CFR0 0x0060 -#define TSC2005_REG_CFR1 0x0068 -#define TSC2005_REG_CFR2 0x0070 +#define TSC2005_REG_READ 0x01 /* R/W access */ +#define TSC2005_REG_PND0 0x02 /* Power Not Down Control */ +#define TSC2005_REG_X (0x0 << 3) +#define TSC2005_REG_Y (0x1 << 3) +#define TSC2005_REG_Z1 (0x2 << 3) +#define TSC2005_REG_Z2 (0x3 << 3) +#define TSC2005_REG_AUX (0x4 << 3) +#define TSC2005_REG_TEMP1 (0x5 << 3) +#define TSC2005_REG_TEMP2 (0x6 << 3) +#define TSC2005_REG_STATUS (0x7 << 3) +#define TSC2005_REG_AUX_HIGH (0x8 << 3) +#define TSC2005_REG_AUX_LOW (0x9 << 3) +#define TSC2005_REG_TEMP_HIGH (0xA << 3) +#define TSC2005_REG_TEMP_LOW (0xB << 3) +#define TSC2005_REG_CFR0 (0xC << 3) +#define TSC2005_REG_CFR1 (0xD << 3) +#define TSC2005_REG_CFR2 (0xE << 3) +#define TSC2005_REG_CONV_FUNC (0xF << 3) /* configuration register 0 */ #define TSC2005_CFR0_PRECHARGE_276US 0x0040 -- cgit v1.3-6-gb490 From f00d1f8f1d9720dcf9ec7911916b685e6f92729f Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 27 Jul 2015 17:27:09 -0700 Subject: Input: tsc2005 - fix Kconfig indentation Replace spaces with tab, so that the tsc2005 Kconfig entry matches the other entries in drivers/input/touchscreen/Kconfig. Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 5b272ba091ab..cb8405d40506 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -915,10 +915,10 @@ config TOUCHSCREEN_TSC_SERIO module will be called tsc40. config TOUCHSCREEN_TSC2005 - tristate "TSC2005 based touchscreens" - depends on SPI_MASTER - help - Say Y here if you have a TSC2005 based touchscreen. + tristate "TSC2005 based touchscreens" + depends on SPI_MASTER + help + Say Y here if you have a TSC2005 based touchscreen. If unsure, say N. -- cgit v1.3-6-gb490 From 273cf48aa95a86ee368a10b9a2a6b0c62544ffe5 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 27 Jul 2015 17:27:25 -0700 Subject: Input: tsc2005 - convert to regmap Convert driver so that it uses regmap instead of directly using spi_transfer for all register accesses. Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 1 + drivers/input/touchscreen/tsc2005.c | 171 +++++++++++++----------------------- 2 files changed, 60 insertions(+), 112 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index cb8405d40506..860d426c480e 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -917,6 +917,7 @@ config TOUCHSCREEN_TSC_SERIO config TOUCHSCREEN_TSC2005 tristate "TSC2005 based touchscreens" depends on SPI_MASTER + select REGMAP_SPI help Say Y here if you have a TSC2005 based touchscreen. diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 2a27a1f77bcb..b116ee9069ca 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -34,6 +34,7 @@ #include #include #include +#include /* * The touchscreen interface operates as follows: @@ -120,20 +121,37 @@ #define TSC2005_SPI_MAX_SPEED_HZ 10000000 #define TSC2005_PENUP_TIME_MS 40 -struct tsc2005_spi_rd { - struct spi_transfer spi_xfer; - u32 spi_tx; - u32 spi_rx; +static const struct regmap_range tsc2005_writable_ranges[] = { + regmap_reg_range(TSC2005_REG_AUX_HIGH, TSC2005_REG_CFR2), }; +static const struct regmap_access_table tsc2005_writable_table = { + .yes_ranges = tsc2005_writable_ranges, + .n_yes_ranges = ARRAY_SIZE(tsc2005_writable_ranges), +}; + +static struct regmap_config tsc2005_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .reg_stride = 0x08, + .max_register = 0x78, + .read_flag_mask = TSC2005_REG_READ, + .write_flag_mask = TSC2005_REG_PND0, + .wr_table = &tsc2005_writable_table, + .use_single_rw = true, +}; + +struct tsc2005_data { + u16 x; + u16 y; + u16 z1; + u16 z2; +} __packed; +#define TSC2005_DATA_REGS 4 + struct tsc2005 { struct spi_device *spi; - - struct spi_message spi_read_msg; - struct tsc2005_spi_rd spi_x; - struct tsc2005_spi_rd spi_y; - struct tsc2005_spi_rd spi_z1; - struct tsc2005_spi_rd spi_z2; + struct regmap *regmap; struct input_dev *idev; char phys[32]; @@ -190,62 +208,6 @@ static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd) return 0; } -static int tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) -{ - u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value; - struct spi_transfer xfer = { - .tx_buf = &tx, - .len = 4, - .bits_per_word = 24, - }; - struct spi_message msg; - int error; - - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - - error = spi_sync(ts->spi, &msg); - if (error) { - dev_err(&ts->spi->dev, - "%s: failed, register: %x, value: %x, error: %d\n", - __func__, reg, value, error); - return error; - } - - return 0; -} - -static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) -{ - memset(rd, 0, sizeof(*rd)); - - rd->spi_tx = (reg | TSC2005_REG_READ) << 16; - rd->spi_xfer.tx_buf = &rd->spi_tx; - rd->spi_xfer.rx_buf = &rd->spi_rx; - rd->spi_xfer.len = 4; - rd->spi_xfer.bits_per_word = 24; - rd->spi_xfer.cs_change = !last; -} - -static int tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) -{ - struct tsc2005_spi_rd spi_rd; - struct spi_message msg; - int error; - - tsc2005_setup_read(&spi_rd, reg, true); - - spi_message_init(&msg); - spi_message_add_tail(&spi_rd.spi_xfer, &msg); - - error = spi_sync(ts->spi, &msg); - if (error) - return error; - - *value = spi_rd.spi_rx; - return 0; -} - static void tsc2005_update_pen_state(struct tsc2005 *ts, int x, int y, int pressure) { @@ -274,26 +236,23 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) struct tsc2005 *ts = _ts; unsigned long flags; unsigned int pressure; - u32 x, y; - u32 z1, z2; + struct tsc2005_data tsdata; int error; /* read the coordinates */ - error = spi_sync(ts->spi, &ts->spi_read_msg); + error = regmap_bulk_read(ts->regmap, TSC2005_REG_X, &tsdata, + TSC2005_DATA_REGS); if (unlikely(error)) goto out; - x = ts->spi_x.spi_rx; - y = ts->spi_y.spi_rx; - z1 = ts->spi_z1.spi_rx; - z2 = ts->spi_z2.spi_rx; - /* validate position */ - if (unlikely(x > MAX_12BIT || y > MAX_12BIT)) + if (unlikely(tsdata.x > MAX_12BIT || tsdata.y > MAX_12BIT)) goto out; /* Skip reading if the pressure components are out of range */ - if (unlikely(z1 == 0 || z2 > MAX_12BIT || z1 >= z2)) + if (unlikely(tsdata.z1 == 0 || tsdata.z2 > MAX_12BIT)) + goto out; + if (unlikely(tsdata.z1 >= tsdata.z2)) goto out; /* @@ -301,8 +260,8 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) * the value before pen-up - that implies SPI fed us stale data */ if (!ts->pen_down && - ts->in_x == x && ts->in_y == y && - ts->in_z1 == z1 && ts->in_z2 == z2) { + ts->in_x == tsdata.x && ts->in_y == tsdata.y && + ts->in_z1 == tsdata.z1 && ts->in_z2 == tsdata.z2) { goto out; } @@ -310,20 +269,20 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) * At this point we are happy we have a valid and useful reading. * Remember it for later comparisons. We may now begin downsampling. */ - ts->in_x = x; - ts->in_y = y; - ts->in_z1 = z1; - ts->in_z2 = z2; + ts->in_x = tsdata.x; + ts->in_y = tsdata.y; + ts->in_z1 = tsdata.z1; + ts->in_z2 = tsdata.z2; /* Compute touch pressure resistance using equation #1 */ - pressure = x * (z2 - z1) / z1; + pressure = tsdata.x * (tsdata.z2 - tsdata.z1) / tsdata.z1; pressure = pressure * ts->x_plate_ohm / 4096; if (unlikely(pressure > MAX_12BIT)) goto out; spin_lock_irqsave(&ts->lock, flags); - tsc2005_update_pen_state(ts, x, y, pressure); + tsc2005_update_pen_state(ts, tsdata.x, tsdata.y, pressure); mod_timer(&ts->penup_timer, jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); @@ -346,9 +305,9 @@ static void tsc2005_penup_timer(unsigned long data) static void tsc2005_start_scan(struct tsc2005 *ts) { - tsc2005_write(ts, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE); - tsc2005_write(ts, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE); - tsc2005_write(ts, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE); + regmap_write(ts->regmap, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE); + regmap_write(ts->regmap, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE); + regmap_write(ts->regmap, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE); tsc2005_cmd(ts, TSC2005_CMD_NORMAL); } @@ -398,9 +357,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev, { struct spi_device *spi = to_spi_device(dev); struct tsc2005 *ts = spi_get_drvdata(spi); - u16 temp_high; - u16 temp_high_orig; - u16 temp_high_test; + unsigned int temp_high; + unsigned int temp_high_orig; + unsigned int temp_high_test; bool success = true; int error; @@ -411,7 +370,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, */ __tsc2005_disable(ts); - error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); + error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high_orig); if (error) { dev_warn(dev, "selftest failed: read error %d\n", error); success = false; @@ -420,14 +379,14 @@ static ssize_t tsc2005_selftest_show(struct device *dev, temp_high_test = (temp_high_orig - 1) & MAX_12BIT; - error = tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test); + error = regmap_write(ts->regmap, TSC2005_REG_TEMP_HIGH, temp_high_test); if (error) { dev_warn(dev, "selftest failed: write error %d\n", error); success = false; goto out; } - error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high); if (error) { dev_warn(dev, "selftest failed: read error %d after write\n", error); @@ -450,7 +409,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, goto out; /* test that the reset really happened */ - error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high); if (error) { dev_warn(dev, "selftest failed: read error %d after reset\n", error); @@ -503,7 +462,7 @@ static void tsc2005_esd_work(struct work_struct *work) { struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work); int error; - u16 r; + unsigned int r; if (!mutex_trylock(&ts->mutex)) { /* @@ -519,7 +478,7 @@ static void tsc2005_esd_work(struct work_struct *work) goto out; /* We should be able to read register without disabling interrupts. */ - error = tsc2005_read(ts, TSC2005_REG_CFR0, &r); + error = regmap_read(ts->regmap, TSC2005_REG_CFR0, &r); if (!error && !((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { goto out; @@ -583,20 +542,6 @@ static void tsc2005_close(struct input_dev *input) mutex_unlock(&ts->mutex); } -static void tsc2005_setup_spi_xfer(struct tsc2005 *ts) -{ - tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, false); - tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, false); - tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, false); - tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, true); - - spi_message_init(&ts->spi_read_msg); - spi_message_add_tail(&ts->spi_x.spi_xfer, &ts->spi_read_msg); - spi_message_add_tail(&ts->spi_y.spi_xfer, &ts->spi_read_msg); - spi_message_add_tail(&ts->spi_z1.spi_xfer, &ts->spi_read_msg); - spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg); -} - static int tsc2005_probe(struct spi_device *spi) { const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev); @@ -661,6 +606,10 @@ static int tsc2005_probe(struct spi_device *spi) ts->spi = spi; ts->idev = input_dev; + ts->regmap = devm_regmap_init_spi(spi, &tsc2005_regmap_config); + if (IS_ERR(ts->regmap)) + return PTR_ERR(ts->regmap); + ts->x_plate_ohm = x_plate_ohm; ts->esd_timeout = esd_timeout; @@ -700,8 +649,6 @@ static int tsc2005_probe(struct spi_device *spi) INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work); - tsc2005_setup_spi_xfer(ts); - snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", dev_name(&spi->dev)); -- cgit v1.3-6-gb490 From 80b46aa69e543939e39eca5ae96fe508a1da2230 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 27 Jul 2015 17:28:37 -0700 Subject: Input: tsc2005 - simplify drvdata acquisition Using dev_*_drvdata() instead of spi_*_drvdata() reduces lines of code and prepares the driver for possible tsc2004 support, which is i2c based. Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index b116ee9069ca..4d3f3ee37d6d 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -355,8 +355,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(dev); unsigned int temp_high; unsigned int temp_high_orig; unsigned int temp_high_test; @@ -441,8 +440,7 @@ static umode_t tsc2005_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { struct device *dev = container_of(kobj, struct device, kobj); - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(dev); umode_t mode = attr->mode; if (attr == &dev_attr_selftest.attr) { @@ -690,7 +688,7 @@ static int tsc2005_probe(struct spi_device *spi) return error; } - spi_set_drvdata(spi, ts); + dev_set_drvdata(&spi->dev, ts); error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group); if (error) { dev_err(&spi->dev, @@ -718,7 +716,7 @@ disable_regulator: static int tsc2005_remove(struct spi_device *spi) { - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(&spi->dev); sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); @@ -730,8 +728,7 @@ static int tsc2005_remove(struct spi_device *spi) static int __maybe_unused tsc2005_suspend(struct device *dev) { - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(dev); mutex_lock(&ts->mutex); @@ -747,8 +744,7 @@ static int __maybe_unused tsc2005_suspend(struct device *dev) static int __maybe_unused tsc2005_resume(struct device *dev) { - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(dev); mutex_lock(&ts->mutex); -- cgit v1.3-6-gb490 From d257f2980feb431ac7f0ffa1978fb694f56c7782 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 27 Jul 2015 17:28:58 -0700 Subject: Input: tsc2005 - convert to gpiod The GPIOD API can be used from boardcode, so that the DT check can be removed. To avoid breaking existing boardcode, _optional() variant has been chosen. For completely removing the DT check, the regulator has also been made optional, so that it could be supplied from boardcode. As a side-effect the patch fixes the after-probe reset GPIO state, so that the device is not kept in reset state. Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 47 ++++++++++++++----------------------- 1 file changed, 18 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 4d3f3ee37d6d..0f65d02eeb26 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -30,11 +30,11 @@ #include #include #include -#include #include #include #include #include +#include /* * The touchscreen interface operates as follows: @@ -180,7 +180,7 @@ struct tsc2005 { struct regulator *vio; - int reset_gpio; + struct gpio_desc *reset_gpio; void (*set_reset)(bool enable); }; @@ -318,8 +318,8 @@ static void tsc2005_stop_scan(struct tsc2005 *ts) static void tsc2005_set_reset(struct tsc2005 *ts, bool enable) { - if (ts->reset_gpio >= 0) - gpio_set_value(ts->reset_gpio, enable); + if (ts->reset_gpio) + gpiod_set_value_cansleep(ts->reset_gpio, enable); else if (ts->set_reset) ts->set_reset(enable); } @@ -611,34 +611,23 @@ static int tsc2005_probe(struct spi_device *spi) ts->x_plate_ohm = x_plate_ohm; ts->esd_timeout = esd_timeout; - if (np) { - ts->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); - if (ts->reset_gpio == -EPROBE_DEFER) - return ts->reset_gpio; - if (ts->reset_gpio < 0) { - dev_err(&spi->dev, "error acquiring reset gpio: %d\n", - ts->reset_gpio); - return ts->reset_gpio; - } + ts->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + dev_err(&spi->dev, "error acquiring reset gpio: %d\n", error); + return error; + } - error = devm_gpio_request_one(&spi->dev, ts->reset_gpio, 0, - "reset-gpios"); - if (error) { - dev_err(&spi->dev, "error requesting reset gpio: %d\n", - error); - return error; - } + ts->vio = devm_regulator_get_optional(&spi->dev, "vio"); + if (IS_ERR(ts->vio)) { + error = PTR_ERR(ts->vio); + dev_err(&spi->dev, "vio regulator missing (%d)", error); + return error; + } - ts->vio = devm_regulator_get(&spi->dev, "vio"); - if (IS_ERR(ts->vio)) { - error = PTR_ERR(ts->vio); - dev_err(&spi->dev, "vio regulator missing (%d)", error); - return error; - } - } else { - ts->reset_gpio = -1; + if (!ts->reset_gpio && pdata) ts->set_reset = pdata->set_reset; - } mutex_init(&ts->mutex); -- cgit v1.3-6-gb490 From 5995752eadfd64edece5810b6fb0639806726594 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Fri, 24 Jul 2015 13:18:25 -0700 Subject: crypto: qat - remove redundant struct elem The element pci_dev_id in the struct adf_hw_device_data is redundant since the PCI device id can be retrieved from the struct pci_dev. Signed-off-by: Bruce Allan Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_accel_devices.h | 1 - drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c | 1 - drivers/crypto/qat/qat_dh895xcc/adf_drv.c | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index 45db8d53a9d3..99cbce6b3cbc 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -153,7 +153,6 @@ struct adf_hw_device_data { void (*enable_ints)(struct adf_accel_dev *accel_dev); const char *fw_name; const char *fw_mmp_name; - uint32_t pci_dev_id; uint32_t fuses; uint32_t accel_capabilities_mask; uint16_t accel_mask; diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c index eb2f408d4302..155ace9d4a43 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -208,7 +208,6 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) hw_data->instance_id = dh895xcc_class.instances++; hw_data->num_banks = ADF_DH895XCC_ETR_MAX_BANKS; hw_data->num_accel = ADF_DH895XCC_MAX_ACCELERATORS; - hw_data->pci_dev_id = ADF_DH895XCC_PCI_DEVICE_ID; hw_data->num_logical_accel = 1; hw_data->num_engines = ADF_DH895XCC_MAX_ACCELENGINES; hw_data->tx_rx_gap = ADF_DH895XCC_RX_RINGS_OFFSET; diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c index d241037f8728..4abeca1b1c33 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c @@ -100,7 +100,7 @@ static void adf_cleanup_accel(struct adf_accel_dev *accel_dev) } if (accel_dev->hw_device) { - switch (accel_dev->hw_device->pci_dev_id) { + switch (accel_pci_dev->pci_dev->device) { case ADF_DH895XCC_PCI_DEVICE_ID: adf_clean_hw_data_dh895xcc(accel_dev->hw_device); break; -- cgit v1.3-6-gb490 From ea77fcdaf1aa6c3e69ba87cfef2e89b07f929598 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Fri, 24 Jul 2015 13:18:25 -0700 Subject: crypto: qat - fix bug in ADF_RING_SIZE_BYTES_MIN macro The subject macro mistakenly compares the passed-in ring size in bytes with ADF_RING_SIZE_4K which is 0x6 (an internal representation of 4KB) rather than comparing with the intended value of 4096. Signed-off-by: Bruce Allan Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_transport_access_macros.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_transport_access_macros.h b/drivers/crypto/qat/qat_common/adf_transport_access_macros.h index 160c9a36c919..6ad7e4e1edca 100644 --- a/drivers/crypto/qat/qat_common/adf_transport_access_macros.h +++ b/drivers/crypto/qat/qat_common/adf_transport_access_macros.h @@ -97,8 +97,9 @@ #define ADF_RING_SIZE_IN_BYTES_TO_SIZE(SIZE) ((1 << (SIZE - 1)) >> 7) /* Minimum ring bufer size for memory allocation */ -#define ADF_RING_SIZE_BYTES_MIN(SIZE) ((SIZE < ADF_RING_SIZE_4K) ? \ - ADF_RING_SIZE_4K : SIZE) +#define ADF_RING_SIZE_BYTES_MIN(SIZE) \ + ((SIZE < ADF_SIZE_TO_RING_SIZE_IN_BYTES(ADF_RING_SIZE_4K)) ? \ + ADF_SIZE_TO_RING_SIZE_IN_BYTES(ADF_RING_SIZE_4K) : SIZE) #define ADF_RING_SIZE_MODULO(SIZE) (SIZE + 0x6) #define ADF_SIZE_TO_POW(SIZE) ((((SIZE & 0x4) >> 1) | ((SIZE & 0x4) >> 2) | \ SIZE) & ~0x4) -- cgit v1.3-6-gb490 From 13dd7bee20634a4991a75a551ce0707eb6aefd29 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Fri, 24 Jul 2015 13:18:25 -0700 Subject: crypto: qat - remove unused define Signed-off-by: Bruce Allan Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/qat_hal.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/qat_hal.c b/drivers/crypto/qat/qat_common/qat_hal.c index 1d6d28916590..8e711d1c3084 100644 --- a/drivers/crypto/qat/qat_common/qat_hal.c +++ b/drivers/crypto/qat/qat_common/qat_hal.c @@ -671,7 +671,6 @@ static int qat_hal_clear_gpr(struct icp_qat_fw_loader_handle *handle) #define ICP_DH895XCC_CAP_OFFSET (ICP_DH895XCC_AE_OFFSET + 0x10000) #define LOCAL_TO_XFER_REG_OFFSET 0x800 #define ICP_DH895XCC_EP_OFFSET 0x3a000 -#define ICP_DH895XCC_PMISC_BAR 1 int qat_hal_init(struct adf_accel_dev *accel_dev) { unsigned char ae; -- cgit v1.3-6-gb490 From ec0d6fa3e8849fd52755bca6cec550985d66546d Mon Sep 17 00:00:00 2001 From: Ahsan Atta Date: Fri, 24 Jul 2015 13:18:26 -0700 Subject: crypto: qat - Fix typo othewise->otherwise Signed-off-by: Ahsan Atta Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_aer.c | 2 +- drivers/crypto/qat/qat_common/adf_cfg.c | 6 +++--- drivers/crypto/qat/qat_common/adf_dev_mgr.c | 2 +- drivers/crypto/qat/qat_common/adf_init.c | 10 +++++----- drivers/crypto/qat/qat_common/adf_transport.c | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_aer.c b/drivers/crypto/qat/qat_common/adf_aer.c index 2dbc733b8ab2..8f34a5fce72a 100644 --- a/drivers/crypto/qat/qat_common/adf_aer.c +++ b/drivers/crypto/qat/qat_common/adf_aer.c @@ -206,7 +206,7 @@ static struct pci_error_handlers adf_err_handler = { * QAT acceleration device accel_dev. * To be used by QAT device specific drivers. * - * Return: 0 on success, error code othewise. + * Return: 0 on success, error code otherwise. */ int adf_enable_aer(struct adf_accel_dev *accel_dev, struct pci_driver *adf) { diff --git a/drivers/crypto/qat/qat_common/adf_cfg.c b/drivers/crypto/qat/qat_common/adf_cfg.c index ab65bc274561..76eccb8d96a8 100644 --- a/drivers/crypto/qat/qat_common/adf_cfg.c +++ b/drivers/crypto/qat/qat_common/adf_cfg.c @@ -123,7 +123,7 @@ static const struct file_operations qat_dev_cfg_fops = { * The table stores device specific config values. * To be used by QAT device specific drivers. * - * Return: 0 on success, error code othewise. + * Return: 0 on success, error code otherwise. */ int adf_cfg_dev_add(struct adf_accel_dev *accel_dev) { @@ -276,7 +276,7 @@ static int adf_cfg_key_val_get(struct adf_accel_dev *accel_dev, * in the given acceleration device * To be used by QAT device specific drivers. * - * Return: 0 on success, error code othewise. + * Return: 0 on success, error code otherwise. */ int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev, const char *section_name, @@ -327,7 +327,7 @@ EXPORT_SYMBOL_GPL(adf_cfg_add_key_value_param); * will be stored. * To be used by QAT device specific drivers. * - * Return: 0 on success, error code othewise. + * Return: 0 on success, error code otherwise. */ int adf_cfg_section_add(struct adf_accel_dev *accel_dev, const char *name) { diff --git a/drivers/crypto/qat/qat_common/adf_dev_mgr.c b/drivers/crypto/qat/qat_common/adf_dev_mgr.c index 3f0ff9e7d840..4bd38e362884 100644 --- a/drivers/crypto/qat/qat_common/adf_dev_mgr.c +++ b/drivers/crypto/qat/qat_common/adf_dev_mgr.c @@ -60,7 +60,7 @@ static uint32_t num_devices; * Function adds acceleration device to the acceleration framework. * To be used by QAT device specific drivers. * - * Return: 0 on success, error code othewise. + * Return: 0 on success, error code otherwise. */ int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev) { diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c index 7f9dffad7931..9a90b287ad68 100644 --- a/drivers/crypto/qat/qat_common/adf_init.c +++ b/drivers/crypto/qat/qat_common/adf_init.c @@ -69,7 +69,7 @@ static void adf_service_add(struct service_hndl *service) * Function adds the acceleration service to the acceleration framework. * To be used by QAT device specific drivers. * - * Return: 0 on success, error code othewise. + * Return: 0 on success, error code otherwise. */ int adf_service_register(struct service_hndl *service) { @@ -94,7 +94,7 @@ static void adf_service_remove(struct service_hndl *service) * Function remove the acceleration service from the acceleration framework. * To be used by QAT device specific drivers. * - * Return: 0 on success, error code othewise. + * Return: 0 on success, error code otherwise. */ int adf_service_unregister(struct service_hndl *service) { @@ -114,7 +114,7 @@ EXPORT_SYMBOL_GPL(adf_service_unregister); * Initialize the ring data structures and the admin comms and arbitration * services. * - * Return: 0 on success, error code othewise. + * Return: 0 on success, error code otherwise. */ int adf_dev_init(struct adf_accel_dev *accel_dev) { @@ -214,7 +214,7 @@ EXPORT_SYMBOL_GPL(adf_dev_init); * is ready to be used. * To be used by QAT device specific drivers. * - * Return: 0 on success, error code othewise. + * Return: 0 on success, error code otherwise. */ int adf_dev_start(struct adf_accel_dev *accel_dev) { @@ -276,7 +276,7 @@ EXPORT_SYMBOL_GPL(adf_dev_start); * is shuting down. * To be used by QAT device specific drivers. * - * Return: 0 on success, error code othewise. + * Return: 0 on success, error code otherwise. */ int adf_dev_stop(struct adf_accel_dev *accel_dev) { diff --git a/drivers/crypto/qat/qat_common/adf_transport.c b/drivers/crypto/qat/qat_common/adf_transport.c index db2926bff8a5..df0331d26838 100644 --- a/drivers/crypto/qat/qat_common/adf_transport.c +++ b/drivers/crypto/qat/qat_common/adf_transport.c @@ -463,7 +463,7 @@ err: * acceleration device accel_dev. * To be used by QAT device specific drivers. * - * Return: 0 on success, error code othewise. + * Return: 0 on success, error code otherwise. */ int adf_init_etr_data(struct adf_accel_dev *accel_dev) { -- cgit v1.3-6-gb490 From caa8c508494c5de3ea70b44804abfd003f6b0107 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Mon, 27 Jul 2015 12:58:32 -0700 Subject: crypto: qat - remove unnecessary list iteration There's no need to iterate through the list for instances in the accel_table since the number of devices is already known in this file. Signed-off-by: Bruce Allan Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_dev_mgr.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_dev_mgr.c b/drivers/crypto/qat/qat_common/adf_dev_mgr.c index 4bd38e362884..b574a82368a4 100644 --- a/drivers/crypto/qat/qat_common/adf_dev_mgr.c +++ b/drivers/crypto/qat/qat_common/adf_dev_mgr.c @@ -182,12 +182,7 @@ int adf_devmgr_verify_id(uint32_t id) void adf_devmgr_get_num_dev(uint32_t *num) { - struct list_head *itr; - - *num = 0; - list_for_each(itr, &accel_table) { - (*num)++; - } + *num = num_devices; } int adf_dev_in_use(struct adf_accel_dev *accel_dev) -- cgit v1.3-6-gb490 From 23393d49fb75ca97b179668aa86b7038c2dc0831 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Jul 2015 15:55:16 -0500 Subject: gpio: kill off set_irq_flags usage set_irq_flags is ARM specific with custom flags which have genirq equivalents. Convert drivers to use the genirq interfaces directly, so we can kill off set_irq_flags. The translation of flags is as follows: IRQF_VALID -> !IRQ_NOREQUEST IRQF_PROBE -> !IRQ_NOPROBE IRQF_NOAUTOEN -> IRQ_NOAUTOEN For IRQs managed by an irqdomain, the irqdomain core code handles clearing and setting IRQ_NOREQUEST already, so there is no need to do this in .map() functions and we can simply remove the set_irq_flags calls. Some users also modify IRQ_NOPROBE and this has been maintained although it is not clear that is really needed as most platforms don't use probing. There appears to be a great deal of blind copy and paste of this code. Signed-off-by: Rob Herring Cc: Michael Hennerich Acked-by: Linus Walleij Cc: Alexandre Courbot Cc: Ray Jui Cc: Stephen Warren Cc: Thierry Reding Cc: linux-gpio@vger.kernel.org Cc: bcm-kernel-feedback-list@broadcom.com Cc: linux-tegra@vger.kernel.org Signed-off-by: Linus Walleij --- drivers/gpio/gpio-adp5588.c | 10 +--------- drivers/gpio/gpio-bcm-kona.c | 15 --------------- drivers/gpio/gpio-davinci.c | 1 - drivers/gpio/gpio-em.c | 1 - drivers/gpio/gpio-ep93xx.c | 2 +- drivers/gpio/gpio-grgpio.c | 8 -------- drivers/gpio/gpio-mcp23s08.c | 4 ---- drivers/gpio/gpio-msm-v2.c | 1 - drivers/gpio/gpio-pxa.c | 8 ++++---- drivers/gpio/gpio-sa1100.c | 2 +- drivers/gpio/gpio-sta2x11.c | 2 +- drivers/gpio/gpio-tegra.c | 1 - drivers/gpio/gpio-timberdale.c | 4 +--- drivers/gpio/gpiolib.c | 8 +------- 14 files changed, 10 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index d3fe6a6776da..984186ee58a0 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -305,15 +305,7 @@ static int adp5588_irq_setup(struct adp5588_gpio *dev) irq_set_chip_and_handler(irq, &adp5588_irq_chip, handle_level_irq); irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - /* - * ARM needs us to explicitly flag the IRQ as VALID, - * once we do so, it will also set the noprobe. - */ - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif + irq_modify_status(irq, IRQ_NOREQUEST, IRQ_NOPROBE); } ret = request_threaded_irq(client->irq, diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 109083f65248..31b90ac15204 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -525,11 +525,7 @@ static int bcm_kona_gpio_irq_map(struct irq_domain *d, unsigned int irq, return ret; irq_set_lockdep_class(irq, &gpio_lock_class); irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, handle_simple_irq); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif return 0; } @@ -644,17 +640,6 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev) dev_err(dev, "Couldn't add GPIO chip -- %d\n", ret); goto err_irq_domain; } - for (i = 0; i < chip->ngpio; i++) { - int irq = bcm_kona_gpio_to_irq(chip, i); - irq_set_lockdep_class(irq, &gpio_lock_class); - irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, - handle_simple_irq); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - } for (i = 0; i < kona_gpio->num_bank; i++) { bank = &kona_gpio->banks[i]; irq_set_chained_handler_and_data(bank->irq, diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 7be269402baf..94b0ab709721 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -423,7 +423,6 @@ davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq, irq_set_irq_type(irq, IRQ_TYPE_NONE); irq_set_chip_data(irq, (__force void *)g); irq_set_handler_data(irq, (void *)__gpio_mask(hw)); - set_irq_flags(irq, IRQF_VALID); return 0; } diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index a77f16c8d142..6bca1e125e12 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -261,7 +261,6 @@ static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int irq, irq_set_chip_data(irq, h->host_data); irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); /* kill me now */ return 0; } diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index dc0c40935940..9d90366ea259 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -236,7 +236,7 @@ static void ep93xx_gpio_init_irq(void) gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip, handle_level_irq); - set_irq_flags(gpio_irq, IRQF_VALID); + irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST); } irq_set_chained_handler(IRQ_EP93XX_GPIO_AB, diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 0a8f7617e72e..77053d61466e 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -281,12 +281,7 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq, irq_set_chip_data(irq, priv); irq_set_chip_and_handler(irq, &grgpio_irq_chip, handle_simple_irq); - irq_clear_status_flags(irq, IRQ_NOREQUEST); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif return ret; } @@ -301,9 +296,6 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) int ngpio = priv->bgc.gc.ngpio; int i; -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif irq_set_chip_and_handler(irq, NULL, NULL); irq_set_chip_data(irq, NULL); diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 2fc7ff852d16..73db7ecd7ffd 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -507,11 +507,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) irq_set_chip_data(irq, mcp); irq_set_chip(irq, &mcp23s08_irq_chip); irq_set_nested_thread(irq, true); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif } return 0; } diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index 1f0fb19209bf..d2012cfb5571 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -355,7 +355,6 @@ static int msm_gpio_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_set_lockdep_class(irq, &msm_gpio_lock_class); irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); return 0; } diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index cdbbcf0faf9d..55a11de3d5b7 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -524,7 +524,7 @@ static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq, { irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_noprobe(irq); return 0; } @@ -643,20 +643,20 @@ static int pxa_gpio_probe(struct platform_device *pdev) irq = gpio_to_irq(0); irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } if (irq1 > 0) { irq = gpio_to_irq(1); irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } for (irq = gpio_to_irq(gpio_offset); irq <= gpio_to_irq(pxa_last_gpio); irq++) { irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } } diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index e847a4cf9326..67bd2f5d89e8 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -155,7 +155,7 @@ static int sa1100_gpio_irqdomain_map(struct irq_domain *d, { irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_noprobe(irq); return 0; } diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 18579ac65b2b..55e47828ddfc 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -346,7 +346,7 @@ static void gsta_alloc_irq_chip(struct gsta_gpio *chip) i = chip->irq_base + j; irq_set_chip_and_handler(i, &ct->chip, ct->handler); irq_set_chip_data(i, gc); - irq_modify_status(i, IRQ_NOREQUEST | IRQ_NOPROBE, 0); + irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); } gc->irq_cnt = i - gc->irq_base; } diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 530b27f9d66f..9b14aafb576d 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -507,7 +507,6 @@ static int tegra_gpio_probe(struct platform_device *pdev) irq_set_chip_data(irq, bank); irq_set_chip_and_handler(irq, &tegra_gpio_irq_chip, handle_simple_irq); - set_irq_flags(irq, IRQF_VALID); } for (i = 0; i < tegra_gpio_bank_count; i++) { diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index ac53ff0a8086..5a492054589f 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -295,9 +295,7 @@ static int timbgpio_probe(struct platform_device *pdev) irq_set_chip_and_handler(tgpio->irq_base + i, &timbgpio_irqchip, handle_simple_irq); irq_set_chip_data(tgpio->irq_base + i, tgpio); -#ifdef CONFIG_ARM - set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE); -#endif + irq_clear_status_flags(tgpio->irq_base + i, IRQ_NOREQUEST | IRQ_NOPROBE); } irq_set_chained_handler_and_data(irq, timbgpio_irq, tgpio); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b7e24780683a..9312bbcb19b9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -486,11 +486,8 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, /* Chips that can sleep need nested thread handlers */ if (chip->can_sleep && !chip->irq_not_threaded) irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif + /* * No set-up of the hardware will happen if IRQ_TYPE_NONE * is passed as default type. @@ -505,9 +502,6 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) { struct gpio_chip *chip = d->host_data; -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif if (chip->can_sleep) irq_set_nested_thread(irq, 0); irq_set_chip_and_handler(irq, NULL, NULL); -- cgit v1.3-6-gb490 From 13b2c4a0c3b1cd37ee6bcfbb5b6e2b94e9a75364 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 27 Jul 2015 18:03:56 +0300 Subject: PM / QoS: Make it possible to expose device latency tolerance to userspace Typically when a device is created the bus core it belongs to (for example PCI) does not know if the device supports things like latency tolerance. This is left to the driver that binds to the device in question. However, at that time the device has already been created and there is no way to set its dev->power.set_latency_tolerance anymore. So follow what has been done for other PM QoS attributes as well and allow drivers to expose and hide latency tolerance from userspace, if the device supports it. Acked-by: Rafael J. Wysocki Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/base/power/power.h | 2 ++ drivers/base/power/qos.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/base/power/sysfs.c | 11 +++++++++++ include/linux/pm_qos.h | 5 +++++ 4 files changed, 55 insertions(+) (limited to 'drivers') diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index f1a5d95e7b20..998fa6b23084 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -73,6 +73,8 @@ extern int pm_qos_sysfs_add_resume_latency(struct device *dev); extern void pm_qos_sysfs_remove_resume_latency(struct device *dev); extern int pm_qos_sysfs_add_flags(struct device *dev); extern void pm_qos_sysfs_remove_flags(struct device *dev); +extern int pm_qos_sysfs_add_latency_tolerance(struct device *dev); +extern void pm_qos_sysfs_remove_latency_tolerance(struct device *dev); #else /* CONFIG_PM */ diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index e56d538d039e..7f3646e459cb 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -883,3 +883,40 @@ int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val) mutex_unlock(&dev_pm_qos_mtx); return ret; } + +/** + * dev_pm_qos_expose_latency_tolerance - Expose latency tolerance to userspace + * @dev: Device whose latency tolerance to expose + */ +int dev_pm_qos_expose_latency_tolerance(struct device *dev) +{ + int ret; + + if (!dev->power.set_latency_tolerance) + return -EINVAL; + + mutex_lock(&dev_pm_qos_sysfs_mtx); + ret = pm_qos_sysfs_add_latency_tolerance(dev); + mutex_unlock(&dev_pm_qos_sysfs_mtx); + + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_tolerance); + +/** + * dev_pm_qos_hide_latency_tolerance - Hide latency tolerance from userspace + * @dev: Device whose latency tolerance to hide + */ +void dev_pm_qos_hide_latency_tolerance(struct device *dev) +{ + mutex_lock(&dev_pm_qos_sysfs_mtx); + pm_qos_sysfs_remove_latency_tolerance(dev); + mutex_unlock(&dev_pm_qos_sysfs_mtx); + + /* Remove the request from user space now */ + pm_runtime_get_sync(dev); + dev_pm_qos_update_user_latency_tolerance(dev, + PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT); + pm_runtime_put(dev); +} +EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_tolerance); diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index d2be3f9c211c..a7b46798c81d 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -738,6 +738,17 @@ void pm_qos_sysfs_remove_flags(struct device *dev) sysfs_unmerge_group(&dev->kobj, &pm_qos_flags_attr_group); } +int pm_qos_sysfs_add_latency_tolerance(struct device *dev) +{ + return sysfs_merge_group(&dev->kobj, + &pm_qos_latency_tolerance_attr_group); +} + +void pm_qos_sysfs_remove_latency_tolerance(struct device *dev) +{ + sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_tolerance_attr_group); +} + void rpm_sysfs_remove(struct device *dev) { sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group); diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 7b3ae0cffc05..0f65d36c2a75 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -161,6 +161,8 @@ void dev_pm_qos_hide_flags(struct device *dev); int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set); s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev); int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val); +int dev_pm_qos_expose_latency_tolerance(struct device *dev); +void dev_pm_qos_hide_latency_tolerance(struct device *dev); static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { @@ -229,6 +231,9 @@ static inline s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev) { return PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT; } static inline int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val) { return 0; } +static inline int dev_pm_qos_expose_latency_tolerance(struct device *dev) + { return 0; } +static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {} static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; } static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; } -- cgit v1.3-6-gb490 From 712e960f0ee9337f3473ba3de2bcfc7e87b7c5a4 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 27 Jul 2015 18:03:57 +0300 Subject: ACPI / PM: Attach ACPI power domain only once Some devices, like MFD subdevices, share a single ACPI companion device so that they are able to access their resources and children. However, currently all these subdevices are attached to the ACPI power domain and this might cause that the power methods for the companion device get called more than once. In order to solve this we attach the ACPI power domain only to the first physical device that is bound to the ACPI companion device. In case of MFD devices, this is the parent MFD device itself. Acked-by: Rafael J. Wysocki Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/acpi/device_pm.c | 8 ++++++++ drivers/acpi/internal.h | 2 ++ drivers/acpi/scan.c | 46 ++++++++++++++++++++++++++++++---------------- 3 files changed, 40 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 717afcdb5f4a..08dc3ec7e892 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1123,6 +1123,14 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) if (dev->pm_domain) return -EEXIST; + /* + * Only attach the power domain to the first device if the + * companion is shared by multiple. This is to prevent doing power + * management twice. + */ + if (!acpi_device_is_first_physical_node(adev, dev)) + return -EBUSY; + acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func); dev->pm_domain = &acpi_general_pm_domain; if (power_on) { diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 4683a96932b9..f6aefe984941 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -97,6 +97,8 @@ void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); bool acpi_device_is_present(struct acpi_device *adev); bool acpi_device_is_battery(struct acpi_device *adev); +bool acpi_device_is_first_physical_node(struct acpi_device *adev, + const struct device *dev); /* -------------------------------------------------------------------------- Power Resource diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ec256352f423..89ff6d2eef8a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -226,6 +226,35 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias, return len; } +/** + * acpi_device_is_first_physical_node - Is given dev first physical node + * @adev: ACPI companion device + * @dev: Physical device to check + * + * Function checks if given @dev is the first physical devices attached to + * the ACPI companion device. This distinction is needed in some cases + * where the same companion device is shared between many physical devices. + * + * Note that the caller have to provide valid @adev pointer. + */ +bool acpi_device_is_first_physical_node(struct acpi_device *adev, + const struct device *dev) +{ + bool ret = false; + + mutex_lock(&adev->physical_node_lock); + if (!list_empty(&adev->physical_node_list)) { + const struct acpi_device_physical_node *node; + + node = list_first_entry(&adev->physical_node_list, + struct acpi_device_physical_node, node); + ret = node->dev == dev; + } + mutex_unlock(&adev->physical_node_lock); + + return ret; +} + /* * acpi_companion_match() - Can we match via ACPI companion device * @dev: Device in question @@ -250,7 +279,6 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias, static struct acpi_device *acpi_companion_match(const struct device *dev) { struct acpi_device *adev; - struct mutex *physical_node_lock; adev = ACPI_COMPANION(dev); if (!adev) @@ -259,21 +287,7 @@ static struct acpi_device *acpi_companion_match(const struct device *dev) if (list_empty(&adev->pnp.ids)) return NULL; - physical_node_lock = &adev->physical_node_lock; - mutex_lock(physical_node_lock); - if (list_empty(&adev->physical_node_list)) { - adev = NULL; - } else { - const struct acpi_device_physical_node *node; - - node = list_first_entry(&adev->physical_node_list, - struct acpi_device_physical_node, node); - if (node->dev != dev) - adev = NULL; - } - mutex_unlock(physical_node_lock); - - return adev; + return acpi_device_is_first_physical_node(adev, dev) ? adev : NULL; } static int __acpi_device_uevent_modalias(struct acpi_device *adev, -- cgit v1.3-6-gb490 From ddef08dd00f5548f943422c86e4ffe67dd040b6c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 27 Jul 2015 18:03:58 +0300 Subject: Driver core: wakeup the parent device before trying probe If the parent is still suspended when driver probe is attempted, the result may be failure. For example, if the parent is a PCI MFD device that has been suspended when we try to probe our device, any register reads will return 0xffffffff. To fix the problem, making sure the parent is always awake before attempting driver probe. Signed-off-by: Heikki Krogerus Signed-off-by: Rafael J. Wysocki Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/base/dd.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a638bbb1a27a..2d6df1dd3852 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -399,6 +399,8 @@ EXPORT_SYMBOL_GPL(wait_for_device_probe); * * This function must be called with @dev lock held. When called for a * USB interface, @dev->parent lock must be held as well. + * + * If the device has a parent, runtime-resume the parent before driver probing. */ int driver_probe_device(struct device_driver *drv, struct device *dev) { @@ -410,10 +412,16 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); + if (dev->parent) + pm_runtime_get_sync(dev->parent); + pm_runtime_barrier(dev); ret = really_probe(dev, drv); pm_request_idle(dev); + if (dev->parent) + pm_runtime_put(dev->parent); + return ret; } @@ -507,11 +515,17 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie) device_lock(dev); + if (dev->parent) + pm_runtime_get_sync(dev->parent); + bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); dev_dbg(dev, "async probe completed\n"); pm_request_idle(dev); + if (dev->parent) + pm_runtime_put(dev->parent); + device_unlock(dev); put_device(dev); @@ -541,6 +555,9 @@ static int __device_attach(struct device *dev, bool allow_async) .want_async = false, }; + if (dev->parent) + pm_runtime_get_sync(dev->parent); + ret = bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); if (!ret && allow_async && data.have_async) { @@ -557,6 +574,9 @@ static int __device_attach(struct device *dev, bool allow_async) } else { pm_request_idle(dev); } + + if (dev->parent) + pm_runtime_put(dev->parent); } out_unlock: device_unlock(dev); -- cgit v1.3-6-gb490 From 3d060aeb72113cda0acf906bfe26914fc689506a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Jul 2015 18:04:00 +0300 Subject: driver core: implement device_for_each_child_reverse() The new function device_for_each_child_reverse() is helpful to traverse the registered devices in a reversed order, e.g. in the case when an operation on each device should be done first on the last added device, then on one before last and so on. Signed-off-by: Andy Shevchenko Acked-by: Greg Kroah-Hartman Signed-off-by: Lee Jones --- drivers/base/core.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/linux/device.h | 2 ++ 2 files changed, 45 insertions(+) (limited to 'drivers') diff --git a/drivers/base/core.c b/drivers/base/core.c index dafae6d2f7ac..7d6279554afc 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1252,6 +1252,19 @@ void device_unregister(struct device *dev) } EXPORT_SYMBOL_GPL(device_unregister); +static struct device *prev_device(struct klist_iter *i) +{ + struct klist_node *n = klist_prev(i); + struct device *dev = NULL; + struct device_private *p; + + if (n) { + p = to_device_private_parent(n); + dev = p->device; + } + return dev; +} + static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); @@ -1340,6 +1353,36 @@ int device_for_each_child(struct device *parent, void *data, } EXPORT_SYMBOL_GPL(device_for_each_child); +/** + * device_for_each_child_reverse - device child iterator in reversed order. + * @parent: parent struct device. + * @fn: function to be called for each device. + * @data: data for the callback. + * + * Iterate over @parent's child devices, and call @fn for each, + * passing it @data. + * + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. + */ +int device_for_each_child_reverse(struct device *parent, void *data, + int (*fn)(struct device *dev, void *data)) +{ + struct klist_iter i; + struct device *child; + int error = 0; + + if (!parent->p) + return 0; + + klist_iter_init(&parent->p->klist_children, &i); + while ((child = prev_device(&i)) && !error) + error = fn(child, data); + klist_iter_exit(&i); + return error; +} +EXPORT_SYMBOL_GPL(device_for_each_child_reverse); + /** * device_find_child - device iterator for locating a particular device. * @parent: parent struct device diff --git a/include/linux/device.h b/include/linux/device.h index 5a31bf3a4024..af6fbc35d8a6 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -958,6 +958,8 @@ extern int __must_check device_add(struct device *dev); extern void device_del(struct device *dev); extern int device_for_each_child(struct device *dev, void *data, int (*fn)(struct device *dev, void *data)); +extern int device_for_each_child_reverse(struct device *dev, void *data, + int (*fn)(struct device *dev, void *data)); extern struct device *device_find_child(struct device *dev, void *data, int (*match)(struct device *dev, void *data)); extern int device_rename(struct device *dev, const char *new_name); -- cgit v1.3-6-gb490 From b9a8a271c38fcb1664fd6034fb9326cc9a0dec94 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Jul 2015 18:04:01 +0300 Subject: mfd: make mfd_remove_devices() iterate in reverse order The newly introduced device_for_each_child_reverse() would be used when MFD core removes the device. After this patch applied the devices will be removed in a reversed order. This behaviour is useful when devices have implicit dependency on order, i.e. consider MFD device with serial bus controller, such as SPI, and DMA IP that is attached to serial bus controller: before remove the DMA driver we have to be ensured that no DMA transfers is ongoing and the requested channel are unused. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/mfd-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 14fd5cbcf0f2..c17635d3e504 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -302,7 +302,7 @@ void mfd_remove_devices(struct device *parent) { atomic_t *cnts = NULL; - device_for_each_child(parent, &cnts, mfd_remove_devices_fn); + device_for_each_child_reverse(parent, &cnts, mfd_remove_devices_fn); kfree(cnts); } EXPORT_SYMBOL(mfd_remove_devices); -- cgit v1.3-6-gb490 From 667dfed98615ae1fc4cc05b0763078435598c0f5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Jul 2015 18:04:02 +0300 Subject: dmaengine: add a driver for Intel integrated DMA 64-bit Intel integrated DMA (iDMA) 64-bit is a specific IP that is used as a part of LPSS devices such as HSUART or SPI. The iDMA IP is attached for private usage on each host controller independently. While it has similarities with Synopsys DesignWare DMA, the following distinctions doesn't allow to use the existing driver: - 64-bit mode with corresponding changes in Hardware Linked List data structure - many slight differences in the channel registers Moreover this driver is based on the DMA virtual channels framework that helps to make the driver cleaner and easy to understand. Signed-off-by: Andy Shevchenko Acked-by: Vinod Koul Signed-off-by: Lee Jones --- drivers/dma/Kconfig | 8 + drivers/dma/Makefile | 1 + drivers/dma/idma64.c | 710 +++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/dma/idma64.h | 233 +++++++++++++++++ 4 files changed, 952 insertions(+) create mode 100644 drivers/dma/idma64.c create mode 100644 drivers/dma/idma64.h (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 88d474b78076..bdbbe5bcfb83 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -85,6 +85,14 @@ config INTEL_IOP_ADMA help Enable support for the Intel(R) IOP Series RAID engines. +config IDMA64 + tristate "Intel integrated DMA 64-bit support" + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Enable DMA support for Intel Low Power Subsystem such as found on + Intel Skylake PCH. + source "drivers/dma/dw/Kconfig" config AT_HDMAC diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 6a4d6f2827da..56ff8c705c00 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_HSU_DMA) += hsu/ obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ obj-$(CONFIG_MV_XOR) += mv_xor.o +obj-$(CONFIG_IDMA64) += idma64.o obj-$(CONFIG_DW_DMAC_CORE) += dw/ obj-$(CONFIG_AT_HDMAC) += at_hdmac.o obj-$(CONFIG_AT_XDMAC) += at_xdmac.o diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c new file mode 100644 index 000000000000..18c14e1f1414 --- /dev/null +++ b/drivers/dma/idma64.c @@ -0,0 +1,710 @@ +/* + * Core driver for the Intel integrated DMA 64-bit + * + * Copyright (C) 2015 Intel Corporation + * Author: Andy Shevchenko + * + * 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 "idma64.h" + +/* Platform driver name */ +#define DRV_NAME "idma64" + +/* For now we support only two channels */ +#define IDMA64_NR_CHAN 2 + +/* ---------------------------------------------------------------------- */ + +static struct device *chan2dev(struct dma_chan *chan) +{ + return &chan->dev->device; +} + +/* ---------------------------------------------------------------------- */ + +static void idma64_off(struct idma64 *idma64) +{ + unsigned short count = 100; + + dma_writel(idma64, CFG, 0); + + channel_clear_bit(idma64, MASK(XFER), idma64->all_chan_mask); + channel_clear_bit(idma64, MASK(BLOCK), idma64->all_chan_mask); + channel_clear_bit(idma64, MASK(SRC_TRAN), idma64->all_chan_mask); + channel_clear_bit(idma64, MASK(DST_TRAN), idma64->all_chan_mask); + channel_clear_bit(idma64, MASK(ERROR), idma64->all_chan_mask); + + do { + cpu_relax(); + } while (dma_readl(idma64, CFG) & IDMA64_CFG_DMA_EN && --count); +} + +static void idma64_on(struct idma64 *idma64) +{ + dma_writel(idma64, CFG, IDMA64_CFG_DMA_EN); +} + +/* ---------------------------------------------------------------------- */ + +static void idma64_chan_init(struct idma64 *idma64, struct idma64_chan *idma64c) +{ + u32 cfghi = IDMA64C_CFGH_SRC_PER(1) | IDMA64C_CFGH_DST_PER(0); + u32 cfglo = 0; + + /* Enforce FIFO drain when channel is suspended */ + cfglo |= IDMA64C_CFGL_CH_DRAIN; + + /* Set default burst alignment */ + cfglo |= IDMA64C_CFGL_DST_BURST_ALIGN | IDMA64C_CFGL_SRC_BURST_ALIGN; + + channel_writel(idma64c, CFG_LO, cfglo); + channel_writel(idma64c, CFG_HI, cfghi); + + /* Enable interrupts */ + channel_set_bit(idma64, MASK(XFER), idma64c->mask); + channel_set_bit(idma64, MASK(ERROR), idma64c->mask); + + /* + * Enforce the controller to be turned on. + * + * The iDMA is turned off in ->probe() and looses context during system + * suspend / resume cycle. That's why we have to enable it each time we + * use it. + */ + idma64_on(idma64); +} + +static void idma64_chan_stop(struct idma64 *idma64, struct idma64_chan *idma64c) +{ + channel_clear_bit(idma64, CH_EN, idma64c->mask); +} + +static void idma64_chan_start(struct idma64 *idma64, struct idma64_chan *idma64c) +{ + struct idma64_desc *desc = idma64c->desc; + struct idma64_hw_desc *hw = &desc->hw[0]; + + channel_writeq(idma64c, SAR, 0); + channel_writeq(idma64c, DAR, 0); + + channel_writel(idma64c, CTL_HI, IDMA64C_CTLH_BLOCK_TS(~0UL)); + channel_writel(idma64c, CTL_LO, IDMA64C_CTLL_LLP_S_EN | IDMA64C_CTLL_LLP_D_EN); + + channel_writeq(idma64c, LLP, hw->llp); + + channel_set_bit(idma64, CH_EN, idma64c->mask); +} + +static void idma64_stop_transfer(struct idma64_chan *idma64c) +{ + struct idma64 *idma64 = to_idma64(idma64c->vchan.chan.device); + + idma64_chan_stop(idma64, idma64c); +} + +static void idma64_start_transfer(struct idma64_chan *idma64c) +{ + struct idma64 *idma64 = to_idma64(idma64c->vchan.chan.device); + struct virt_dma_desc *vdesc; + + /* Get the next descriptor */ + vdesc = vchan_next_desc(&idma64c->vchan); + if (!vdesc) { + idma64c->desc = NULL; + return; + } + + list_del(&vdesc->node); + idma64c->desc = to_idma64_desc(vdesc); + + /* Configure the channel */ + idma64_chan_init(idma64, idma64c); + + /* Start the channel with a new descriptor */ + idma64_chan_start(idma64, idma64c); +} + +/* ---------------------------------------------------------------------- */ + +static void idma64_chan_irq(struct idma64 *idma64, unsigned short c, + u32 status_err, u32 status_xfer) +{ + struct idma64_chan *idma64c = &idma64->chan[c]; + struct idma64_desc *desc; + unsigned long flags; + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + desc = idma64c->desc; + if (desc) { + if (status_err & (1 << c)) { + dma_writel(idma64, CLEAR(ERROR), idma64c->mask); + desc->status = DMA_ERROR; + } else if (status_xfer & (1 << c)) { + dma_writel(idma64, CLEAR(XFER), idma64c->mask); + desc->status = DMA_COMPLETE; + vchan_cookie_complete(&desc->vdesc); + idma64_start_transfer(idma64c); + } + + /* idma64_start_transfer() updates idma64c->desc */ + if (idma64c->desc == NULL || desc->status == DMA_ERROR) + idma64_stop_transfer(idma64c); + } + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); +} + +static irqreturn_t idma64_irq(int irq, void *dev) +{ + struct idma64 *idma64 = dev; + u32 status = dma_readl(idma64, STATUS_INT); + u32 status_xfer; + u32 status_err; + unsigned short i; + + dev_vdbg(idma64->dma.dev, "%s: status=%#x\n", __func__, status); + + /* Check if we have any interrupt from the DMA controller */ + if (!status) + return IRQ_NONE; + + /* Disable interrupts */ + channel_clear_bit(idma64, MASK(XFER), idma64->all_chan_mask); + channel_clear_bit(idma64, MASK(ERROR), idma64->all_chan_mask); + + status_xfer = dma_readl(idma64, RAW(XFER)); + status_err = dma_readl(idma64, RAW(ERROR)); + + for (i = 0; i < idma64->dma.chancnt; i++) + idma64_chan_irq(idma64, i, status_err, status_xfer); + + /* Re-enable interrupts */ + channel_set_bit(idma64, MASK(XFER), idma64->all_chan_mask); + channel_set_bit(idma64, MASK(ERROR), idma64->all_chan_mask); + + return IRQ_HANDLED; +} + +/* ---------------------------------------------------------------------- */ + +static struct idma64_desc *idma64_alloc_desc(unsigned int ndesc) +{ + struct idma64_desc *desc; + + desc = kzalloc(sizeof(*desc), GFP_NOWAIT); + if (!desc) + return NULL; + + desc->hw = kcalloc(ndesc, sizeof(*desc->hw), GFP_NOWAIT); + if (!desc->hw) { + kfree(desc); + return NULL; + } + + return desc; +} + +static void idma64_desc_free(struct idma64_chan *idma64c, + struct idma64_desc *desc) +{ + struct idma64_hw_desc *hw; + + if (desc->ndesc) { + unsigned int i = desc->ndesc; + + do { + hw = &desc->hw[--i]; + dma_pool_free(idma64c->pool, hw->lli, hw->llp); + } while (i); + } + + kfree(desc->hw); + kfree(desc); +} + +static void idma64_vdesc_free(struct virt_dma_desc *vdesc) +{ + struct idma64_chan *idma64c = to_idma64_chan(vdesc->tx.chan); + + idma64_desc_free(idma64c, to_idma64_desc(vdesc)); +} + +static u64 idma64_hw_desc_fill(struct idma64_hw_desc *hw, + struct dma_slave_config *config, + enum dma_transfer_direction direction, u64 llp) +{ + struct idma64_lli *lli = hw->lli; + u64 sar, dar; + u32 ctlhi = IDMA64C_CTLH_BLOCK_TS(hw->len); + u32 ctllo = IDMA64C_CTLL_LLP_S_EN | IDMA64C_CTLL_LLP_D_EN; + u32 src_width, dst_width; + + if (direction == DMA_MEM_TO_DEV) { + sar = hw->phys; + dar = config->dst_addr; + ctllo |= IDMA64C_CTLL_DST_FIX | IDMA64C_CTLL_SRC_INC | + IDMA64C_CTLL_FC_M2P; + src_width = min_t(u32, 2, __fls(sar | hw->len)); + dst_width = __fls(config->dst_addr_width); + } else { /* DMA_DEV_TO_MEM */ + sar = config->src_addr; + dar = hw->phys; + ctllo |= IDMA64C_CTLL_DST_INC | IDMA64C_CTLL_SRC_FIX | + IDMA64C_CTLL_FC_P2M; + src_width = __fls(config->src_addr_width); + dst_width = min_t(u32, 2, __fls(dar | hw->len)); + } + + lli->sar = sar; + lli->dar = dar; + + lli->ctlhi = ctlhi; + lli->ctllo = ctllo | + IDMA64C_CTLL_SRC_MSIZE(config->src_maxburst) | + IDMA64C_CTLL_DST_MSIZE(config->dst_maxburst) | + IDMA64C_CTLL_DST_WIDTH(dst_width) | + IDMA64C_CTLL_SRC_WIDTH(src_width); + + lli->llp = llp; + return hw->llp; +} + +static void idma64_desc_fill(struct idma64_chan *idma64c, + struct idma64_desc *desc) +{ + struct dma_slave_config *config = &idma64c->config; + struct idma64_hw_desc *hw = &desc->hw[desc->ndesc - 1]; + struct idma64_lli *lli = hw->lli; + u64 llp = 0; + unsigned int i = desc->ndesc; + + /* Fill the hardware descriptors and link them to a list */ + do { + hw = &desc->hw[--i]; + llp = idma64_hw_desc_fill(hw, config, desc->direction, llp); + desc->length += hw->len; + } while (i); + + /* Trigger interrupt after last block */ + lli->ctllo |= IDMA64C_CTLL_INT_EN; +} + +static struct dma_async_tx_descriptor *idma64_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + struct idma64_desc *desc; + struct scatterlist *sg; + unsigned int i; + + desc = idma64_alloc_desc(sg_len); + if (!desc) + return NULL; + + for_each_sg(sgl, sg, sg_len, i) { + struct idma64_hw_desc *hw = &desc->hw[i]; + + /* Allocate DMA capable memory for hardware descriptor */ + hw->lli = dma_pool_alloc(idma64c->pool, GFP_NOWAIT, &hw->llp); + if (!hw->lli) { + desc->ndesc = i; + idma64_desc_free(idma64c, desc); + return NULL; + } + + hw->phys = sg_dma_address(sg); + hw->len = sg_dma_len(sg); + } + + desc->ndesc = sg_len; + desc->direction = direction; + desc->status = DMA_IN_PROGRESS; + + idma64_desc_fill(idma64c, desc); + return vchan_tx_prep(&idma64c->vchan, &desc->vdesc, flags); +} + +static void idma64_issue_pending(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + if (vchan_issue_pending(&idma64c->vchan) && !idma64c->desc) + idma64_start_transfer(idma64c); + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); +} + +static size_t idma64_active_desc_size(struct idma64_chan *idma64c) +{ + struct idma64_desc *desc = idma64c->desc; + struct idma64_hw_desc *hw; + size_t bytes = desc->length; + u64 llp; + u32 ctlhi; + unsigned int i = 0; + + llp = channel_readq(idma64c, LLP); + do { + hw = &desc->hw[i]; + } while ((hw->llp != llp) && (++i < desc->ndesc)); + + if (!i) + return bytes; + + do { + bytes -= desc->hw[--i].len; + } while (i); + + ctlhi = channel_readl(idma64c, CTL_HI); + return bytes - IDMA64C_CTLH_BLOCK_TS(ctlhi); +} + +static enum dma_status idma64_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *state) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + struct virt_dma_desc *vdesc; + enum dma_status status; + size_t bytes; + unsigned long flags; + + status = dma_cookie_status(chan, cookie, state); + if (status == DMA_COMPLETE) + return status; + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + vdesc = vchan_find_desc(&idma64c->vchan, cookie); + if (idma64c->desc && cookie == idma64c->desc->vdesc.tx.cookie) { + bytes = idma64_active_desc_size(idma64c); + dma_set_residue(state, bytes); + status = idma64c->desc->status; + } else if (vdesc) { + bytes = to_idma64_desc(vdesc)->length; + dma_set_residue(state, bytes); + } + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); + + return status; +} + +static void convert_burst(u32 *maxburst) +{ + if (*maxburst) + *maxburst = __fls(*maxburst); + else + *maxburst = 0; +} + +static int idma64_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + + /* Check if chan will be configured for slave transfers */ + if (!is_slave_direction(config->direction)) + return -EINVAL; + + memcpy(&idma64c->config, config, sizeof(idma64c->config)); + + convert_burst(&idma64c->config.src_maxburst); + convert_burst(&idma64c->config.dst_maxburst); + + return 0; +} + +static void idma64_chan_deactivate(struct idma64_chan *idma64c) +{ + unsigned short count = 100; + u32 cfglo; + + cfglo = channel_readl(idma64c, CFG_LO); + channel_writel(idma64c, CFG_LO, cfglo | IDMA64C_CFGL_CH_SUSP); + do { + udelay(1); + cfglo = channel_readl(idma64c, CFG_LO); + } while (!(cfglo & IDMA64C_CFGL_FIFO_EMPTY) && --count); +} + +static void idma64_chan_activate(struct idma64_chan *idma64c) +{ + u32 cfglo; + + cfglo = channel_readl(idma64c, CFG_LO); + channel_writel(idma64c, CFG_LO, cfglo & ~IDMA64C_CFGL_CH_SUSP); +} + +static int idma64_pause(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + if (idma64c->desc && idma64c->desc->status == DMA_IN_PROGRESS) { + idma64_chan_deactivate(idma64c); + idma64c->desc->status = DMA_PAUSED; + } + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); + + return 0; +} + +static int idma64_resume(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + if (idma64c->desc && idma64c->desc->status == DMA_PAUSED) { + idma64c->desc->status = DMA_IN_PROGRESS; + idma64_chan_activate(idma64c); + } + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); + + return 0; +} + +static int idma64_terminate_all(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + idma64_chan_deactivate(idma64c); + idma64_stop_transfer(idma64c); + if (idma64c->desc) { + idma64_vdesc_free(&idma64c->desc->vdesc); + idma64c->desc = NULL; + } + vchan_get_all_descriptors(&idma64c->vchan, &head); + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); + + vchan_dma_desc_free_list(&idma64c->vchan, &head); + return 0; +} + +static int idma64_alloc_chan_resources(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + + /* Create a pool of consistent memory blocks for hardware descriptors */ + idma64c->pool = dma_pool_create(dev_name(chan2dev(chan)), + chan->device->dev, + sizeof(struct idma64_lli), 8, 0); + if (!idma64c->pool) { + dev_err(chan2dev(chan), "No memory for descriptors\n"); + return -ENOMEM; + } + + return 0; +} + +static void idma64_free_chan_resources(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + + vchan_free_chan_resources(to_virt_chan(chan)); + dma_pool_destroy(idma64c->pool); + idma64c->pool = NULL; +} + +/* ---------------------------------------------------------------------- */ + +#define IDMA64_BUSWIDTHS \ + BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) + +static int idma64_probe(struct idma64_chip *chip) +{ + struct idma64 *idma64; + unsigned short nr_chan = IDMA64_NR_CHAN; + unsigned short i; + int ret; + + idma64 = devm_kzalloc(chip->dev, sizeof(*idma64), GFP_KERNEL); + if (!idma64) + return -ENOMEM; + + idma64->regs = chip->regs; + chip->idma64 = idma64; + + idma64->chan = devm_kcalloc(chip->dev, nr_chan, sizeof(*idma64->chan), + GFP_KERNEL); + if (!idma64->chan) + return -ENOMEM; + + idma64->all_chan_mask = (1 << nr_chan) - 1; + + /* Turn off iDMA controller */ + idma64_off(idma64); + + ret = devm_request_irq(chip->dev, chip->irq, idma64_irq, IRQF_SHARED, + dev_name(chip->dev), idma64); + if (ret) + return ret; + + INIT_LIST_HEAD(&idma64->dma.channels); + for (i = 0; i < nr_chan; i++) { + struct idma64_chan *idma64c = &idma64->chan[i]; + + idma64c->vchan.desc_free = idma64_vdesc_free; + vchan_init(&idma64c->vchan, &idma64->dma); + + idma64c->regs = idma64->regs + i * IDMA64_CH_LENGTH; + idma64c->mask = BIT(i); + } + + dma_cap_set(DMA_SLAVE, idma64->dma.cap_mask); + dma_cap_set(DMA_PRIVATE, idma64->dma.cap_mask); + + idma64->dma.device_alloc_chan_resources = idma64_alloc_chan_resources; + idma64->dma.device_free_chan_resources = idma64_free_chan_resources; + + idma64->dma.device_prep_slave_sg = idma64_prep_slave_sg; + + idma64->dma.device_issue_pending = idma64_issue_pending; + idma64->dma.device_tx_status = idma64_tx_status; + + idma64->dma.device_config = idma64_slave_config; + idma64->dma.device_pause = idma64_pause; + idma64->dma.device_resume = idma64_resume; + idma64->dma.device_terminate_all = idma64_terminate_all; + + idma64->dma.src_addr_widths = IDMA64_BUSWIDTHS; + idma64->dma.dst_addr_widths = IDMA64_BUSWIDTHS; + idma64->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + idma64->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + + idma64->dma.dev = chip->dev; + + ret = dma_async_device_register(&idma64->dma); + if (ret) + return ret; + + dev_info(chip->dev, "Found Intel integrated DMA 64-bit\n"); + return 0; +} + +static int idma64_remove(struct idma64_chip *chip) +{ + struct idma64 *idma64 = chip->idma64; + unsigned short i; + + dma_async_device_unregister(&idma64->dma); + + /* + * Explicitly call devm_request_irq() to avoid the side effects with + * the scheduled tasklets. + */ + devm_free_irq(chip->dev, chip->irq, idma64); + + for (i = 0; i < idma64->dma.chancnt; i++) { + struct idma64_chan *idma64c = &idma64->chan[i]; + + tasklet_kill(&idma64c->vchan.task); + } + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int idma64_platform_probe(struct platform_device *pdev) +{ + struct idma64_chip *chip; + struct device *dev = &pdev->dev; + struct resource *mem; + int ret; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->irq = platform_get_irq(pdev, 0); + if (chip->irq < 0) + return chip->irq; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + chip->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(chip->regs)) + return PTR_ERR(chip->regs); + + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) + return ret; + + chip->dev = dev; + + ret = idma64_probe(chip); + if (ret) + return ret; + + platform_set_drvdata(pdev, chip); + return 0; +} + +static int idma64_platform_remove(struct platform_device *pdev) +{ + struct idma64_chip *chip = platform_get_drvdata(pdev); + + return idma64_remove(chip); +} + +#ifdef CONFIG_PM_SLEEP + +static int idma64_pm_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct idma64_chip *chip = platform_get_drvdata(pdev); + + idma64_off(chip->idma64); + return 0; +} + +static int idma64_pm_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct idma64_chip *chip = platform_get_drvdata(pdev); + + idma64_on(chip->idma64); + return 0; +} + +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops idma64_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(idma64_pm_suspend, idma64_pm_resume) +}; + +static struct platform_driver idma64_platform_driver = { + .probe = idma64_platform_probe, + .remove = idma64_platform_remove, + .driver = { + .name = DRV_NAME, + .pm = &idma64_dev_pm_ops, + }, +}; + +module_platform_driver(idma64_platform_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("iDMA64 core driver"); +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/dma/idma64.h b/drivers/dma/idma64.h new file mode 100644 index 000000000000..a4d99685a7c4 --- /dev/null +++ b/drivers/dma/idma64.h @@ -0,0 +1,233 @@ +/* + * Driver for the Intel integrated DMA 64-bit + * + * Copyright (C) 2015 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 + * published by the Free Software Foundation. + */ + +#ifndef __DMA_IDMA64_H__ +#define __DMA_IDMA64_H__ + +#include +#include +#include +#include + +#include "virt-dma.h" + +/* Channel registers */ + +#define IDMA64_CH_SAR 0x00 /* Source Address Register */ +#define IDMA64_CH_DAR 0x08 /* Destination Address Register */ +#define IDMA64_CH_LLP 0x10 /* Linked List Pointer */ +#define IDMA64_CH_CTL_LO 0x18 /* Control Register Low */ +#define IDMA64_CH_CTL_HI 0x1c /* Control Register High */ +#define IDMA64_CH_SSTAT 0x20 +#define IDMA64_CH_DSTAT 0x28 +#define IDMA64_CH_SSTATAR 0x30 +#define IDMA64_CH_DSTATAR 0x38 +#define IDMA64_CH_CFG_LO 0x40 /* Configuration Register Low */ +#define IDMA64_CH_CFG_HI 0x44 /* Configuration Register High */ +#define IDMA64_CH_SGR 0x48 +#define IDMA64_CH_DSR 0x50 + +#define IDMA64_CH_LENGTH 0x58 + +/* Bitfields in CTL_LO */ +#define IDMA64C_CTLL_INT_EN (1 << 0) /* irqs enabled? */ +#define IDMA64C_CTLL_DST_WIDTH(x) ((x) << 1) /* bytes per element */ +#define IDMA64C_CTLL_SRC_WIDTH(x) ((x) << 4) +#define IDMA64C_CTLL_DST_INC (0 << 8) /* DAR update/not */ +#define IDMA64C_CTLL_DST_FIX (1 << 8) +#define IDMA64C_CTLL_SRC_INC (0 << 10) /* SAR update/not */ +#define IDMA64C_CTLL_SRC_FIX (1 << 10) +#define IDMA64C_CTLL_DST_MSIZE(x) ((x) << 11) /* burst, #elements */ +#define IDMA64C_CTLL_SRC_MSIZE(x) ((x) << 14) +#define IDMA64C_CTLL_FC_M2P (1 << 20) /* mem-to-periph */ +#define IDMA64C_CTLL_FC_P2M (2 << 20) /* periph-to-mem */ +#define IDMA64C_CTLL_LLP_D_EN (1 << 27) /* dest block chain */ +#define IDMA64C_CTLL_LLP_S_EN (1 << 28) /* src block chain */ + +/* Bitfields in CTL_HI */ +#define IDMA64C_CTLH_BLOCK_TS(x) ((x) & ((1 << 17) - 1)) +#define IDMA64C_CTLH_DONE (1 << 17) + +/* Bitfields in CFG_LO */ +#define IDMA64C_CFGL_DST_BURST_ALIGN (1 << 0) /* dst burst align */ +#define IDMA64C_CFGL_SRC_BURST_ALIGN (1 << 1) /* src burst align */ +#define IDMA64C_CFGL_CH_SUSP (1 << 8) +#define IDMA64C_CFGL_FIFO_EMPTY (1 << 9) +#define IDMA64C_CFGL_CH_DRAIN (1 << 10) /* drain FIFO */ +#define IDMA64C_CFGL_DST_OPT_BL (1 << 20) /* optimize dst burst length */ +#define IDMA64C_CFGL_SRC_OPT_BL (1 << 21) /* optimize src burst length */ + +/* Bitfields in CFG_HI */ +#define IDMA64C_CFGH_SRC_PER(x) ((x) << 0) /* src peripheral */ +#define IDMA64C_CFGH_DST_PER(x) ((x) << 4) /* dst peripheral */ +#define IDMA64C_CFGH_RD_ISSUE_THD(x) ((x) << 8) +#define IDMA64C_CFGH_RW_ISSUE_THD(x) ((x) << 18) + +/* Interrupt registers */ + +#define IDMA64_INT_XFER 0x00 +#define IDMA64_INT_BLOCK 0x08 +#define IDMA64_INT_SRC_TRAN 0x10 +#define IDMA64_INT_DST_TRAN 0x18 +#define IDMA64_INT_ERROR 0x20 + +#define IDMA64_RAW(x) (0x2c0 + IDMA64_INT_##x) /* r */ +#define IDMA64_STATUS(x) (0x2e8 + IDMA64_INT_##x) /* r (raw & mask) */ +#define IDMA64_MASK(x) (0x310 + IDMA64_INT_##x) /* rw (set = irq enabled) */ +#define IDMA64_CLEAR(x) (0x338 + IDMA64_INT_##x) /* w (ack, affects "raw") */ + +/* Common registers */ + +#define IDMA64_STATUS_INT 0x360 /* r */ +#define IDMA64_CFG 0x398 +#define IDMA64_CH_EN 0x3a0 + +/* Bitfields in CFG */ +#define IDMA64_CFG_DMA_EN (1 << 0) + +/* Hardware descriptor for Linked LIst transfers */ +struct idma64_lli { + u64 sar; + u64 dar; + u64 llp; + u32 ctllo; + u32 ctlhi; + u32 sstat; + u32 dstat; +}; + +struct idma64_hw_desc { + struct idma64_lli *lli; + dma_addr_t llp; + dma_addr_t phys; + unsigned int len; +}; + +struct idma64_desc { + struct virt_dma_desc vdesc; + enum dma_transfer_direction direction; + struct idma64_hw_desc *hw; + unsigned int ndesc; + size_t length; + enum dma_status status; +}; + +static inline struct idma64_desc *to_idma64_desc(struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct idma64_desc, vdesc); +} + +struct idma64_chan { + struct virt_dma_chan vchan; + + void __iomem *regs; + + /* hardware configuration */ + enum dma_transfer_direction direction; + unsigned int mask; + struct dma_slave_config config; + + void *pool; + struct idma64_desc *desc; +}; + +static inline struct idma64_chan *to_idma64_chan(struct dma_chan *chan) +{ + return container_of(chan, struct idma64_chan, vchan.chan); +} + +#define channel_set_bit(idma64, reg, mask) \ + dma_writel(idma64, reg, ((mask) << 8) | (mask)) +#define channel_clear_bit(idma64, reg, mask) \ + dma_writel(idma64, reg, ((mask) << 8) | 0) + +static inline u32 idma64c_readl(struct idma64_chan *idma64c, int offset) +{ + return readl(idma64c->regs + offset); +} + +static inline void idma64c_writel(struct idma64_chan *idma64c, int offset, + u32 value) +{ + writel(value, idma64c->regs + offset); +} + +#define channel_readl(idma64c, reg) \ + idma64c_readl(idma64c, IDMA64_CH_##reg) +#define channel_writel(idma64c, reg, value) \ + idma64c_writel(idma64c, IDMA64_CH_##reg, (value)) + +static inline u64 idma64c_readq(struct idma64_chan *idma64c, int offset) +{ + u64 l, h; + + l = idma64c_readl(idma64c, offset); + h = idma64c_readl(idma64c, offset + 4); + + return l | (h << 32); +} + +static inline void idma64c_writeq(struct idma64_chan *idma64c, int offset, + u64 value) +{ + idma64c_writel(idma64c, offset, value); + idma64c_writel(idma64c, offset + 4, value >> 32); +} + +#define channel_readq(idma64c, reg) \ + idma64c_readq(idma64c, IDMA64_CH_##reg) +#define channel_writeq(idma64c, reg, value) \ + idma64c_writeq(idma64c, IDMA64_CH_##reg, (value)) + +struct idma64 { + struct dma_device dma; + + void __iomem *regs; + + /* channels */ + unsigned short all_chan_mask; + struct idma64_chan *chan; +}; + +static inline struct idma64 *to_idma64(struct dma_device *ddev) +{ + return container_of(ddev, struct idma64, dma); +} + +static inline u32 idma64_readl(struct idma64 *idma64, int offset) +{ + return readl(idma64->regs + offset); +} + +static inline void idma64_writel(struct idma64 *idma64, int offset, u32 value) +{ + writel(value, idma64->regs + offset); +} + +#define dma_readl(idma64, reg) \ + idma64_readl(idma64, IDMA64_##reg) +#define dma_writel(idma64, reg, value) \ + idma64_writel(idma64, IDMA64_##reg, (value)) + +/** + * struct idma64_chip - representation of DesignWare DMA controller hardware + * @dev: struct device of the DMA controller + * @irq: irq line + * @regs: memory mapped I/O space + * @idma64: struct idma64 that is filed by idma64_probe() + */ +struct idma64_chip { + struct device *dev; + int irq; + void __iomem *regs; + struct idma64 *idma64; +}; + +#endif /* __DMA_IDMA64_H__ */ -- cgit v1.3-6-gb490 From 4b45efe8526359a11ca60a299bef3aebf413fd77 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Jul 2015 18:04:03 +0300 Subject: mfd: Add support for Intel Sunrisepoint LPSS devices The new coming Intel platforms such as Skylake will contain Sunrisepoint PCH. The main difference to the previous platforms is that the LPSS devices are compound devices where usually main (SPI, HSUART, or I2C) and DMA IPs are present. This patch brings the driver for such devices found on Sunrisepoint PCH. Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 23 ++ drivers/mfd/Makefile | 3 + drivers/mfd/intel-lpss-acpi.c | 84 +++++++ drivers/mfd/intel-lpss-pci.c | 113 +++++++++ drivers/mfd/intel-lpss.c | 524 ++++++++++++++++++++++++++++++++++++++++++ drivers/mfd/intel-lpss.h | 62 +++++ 6 files changed, 809 insertions(+) create mode 100644 drivers/mfd/intel-lpss-acpi.c create mode 100644 drivers/mfd/intel-lpss-pci.c create mode 100644 drivers/mfd/intel-lpss.c create mode 100644 drivers/mfd/intel-lpss.h (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 653815950aa2..268b6dd79acc 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -328,6 +328,29 @@ config INTEL_SOC_PMIC thermal, charger and related power management functions on these systems. +config MFD_INTEL_LPSS + tristate + select COMMON_CLK + select MFD_CORE + +config MFD_INTEL_LPSS_ACPI + tristate "Intel Low Power Subsystem support in ACPI mode" + select MFD_INTEL_LPSS + depends on X86 && ACPI + help + This driver supports Intel Low Power Subsystem (LPSS) devices such as + I2C, SPI and HS-UART starting from Intel Sunrisepoint (Intel Skylake + PCH) in ACPI mode. + +config MFD_INTEL_LPSS_PCI + tristate "Intel Low Power Subsystem support in PCI mode" + select MFD_INTEL_LPSS + depends on X86 && PCI + help + This driver supports Intel Low Power Subsystem (LPSS) devices such as + I2C, SPI and HS-UART starting from Intel Sunrisepoint (Intel Skylake + PCH) in PCI mode. + config MFD_INTEL_MSIC bool "Intel MSIC" depends on INTEL_SCU_IPC diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index ea40e076cb61..9d730a2d1878 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -161,6 +161,9 @@ obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_MFD_TPS65090) += tps65090.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o +obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o +obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o +obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o obj-$(CONFIG_MFD_PALMAS) += palmas.o obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c new file mode 100644 index 000000000000..0d92d73bfa0e --- /dev/null +++ b/drivers/mfd/intel-lpss-acpi.c @@ -0,0 +1,84 @@ +/* + * Intel LPSS ACPI support. + * + * Copyright (C) 2015, Intel Corporation + * + * Authors: Andy Shevchenko + * Mika Westerberg + * + * 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 "intel-lpss.h" + +static const struct intel_lpss_platform_info spt_info = { + .clk_rate = 120000000, +}; + +static const struct acpi_device_id intel_lpss_acpi_ids[] = { + /* SPT */ + { "INT3446", (kernel_ulong_t)&spt_info }, + { "INT3447", (kernel_ulong_t)&spt_info }, + { } +}; +MODULE_DEVICE_TABLE(acpi, intel_lpss_acpi_ids); + +static int intel_lpss_acpi_probe(struct platform_device *pdev) +{ + struct intel_lpss_platform_info *info; + const struct acpi_device_id *id; + + id = acpi_match_device(intel_lpss_acpi_ids, &pdev->dev); + if (!id) + return -ENODEV; + + info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + info->irq = platform_get_irq(pdev, 0); + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + return intel_lpss_probe(&pdev->dev, info); +} + +static int intel_lpss_acpi_remove(struct platform_device *pdev) +{ + intel_lpss_remove(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static INTEL_LPSS_PM_OPS(intel_lpss_acpi_pm_ops); + +static struct platform_driver intel_lpss_acpi_driver = { + .probe = intel_lpss_acpi_probe, + .remove = intel_lpss_acpi_remove, + .driver = { + .name = "intel-lpss", + .acpi_match_table = intel_lpss_acpi_ids, + .pm = &intel_lpss_acpi_pm_ops, + }, +}; + +module_platform_driver(intel_lpss_acpi_driver); + +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_DESCRIPTION("Intel LPSS ACPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c new file mode 100644 index 000000000000..9236dffeb4d6 --- /dev/null +++ b/drivers/mfd/intel-lpss-pci.c @@ -0,0 +1,113 @@ +/* + * Intel LPSS PCI support. + * + * Copyright (C) 2015, Intel Corporation + * + * Authors: Andy Shevchenko + * Mika Westerberg + * + * 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 "intel-lpss.h" + +static int intel_lpss_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct intel_lpss_platform_info *info; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->mem = &pdev->resource[0]; + info->irq = pdev->irq; + + /* Probably it is enough to set this for iDMA capable devices only */ + pci_set_master(pdev); + + ret = intel_lpss_probe(&pdev->dev, info); + if (ret) + return ret; + + pm_runtime_put(&pdev->dev); + pm_runtime_allow(&pdev->dev); + + return 0; +} + +static void intel_lpss_pci_remove(struct pci_dev *pdev) +{ + pm_runtime_forbid(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + + intel_lpss_remove(&pdev->dev); +} + +static INTEL_LPSS_PM_OPS(intel_lpss_pci_pm_ops); + +static const struct intel_lpss_platform_info spt_info = { + .clk_rate = 120000000, +}; + +static const struct intel_lpss_platform_info spt_uart_info = { + .clk_rate = 120000000, + .clk_con_id = "baudclk", +}; + +static const struct pci_device_id intel_lpss_pci_ids[] = { + /* SPT-LP */ + { PCI_VDEVICE(INTEL, 0x9d27), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d63), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d66), (kernel_ulong_t)&spt_uart_info }, + /* SPT-H */ + { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info }, + { } +}; +MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids); + +static struct pci_driver intel_lpss_pci_driver = { + .name = "intel-lpss", + .id_table = intel_lpss_pci_ids, + .probe = intel_lpss_pci_probe, + .remove = intel_lpss_pci_remove, + .driver = { + .pm = &intel_lpss_pci_pm_ops, + }, +}; + +module_pci_driver(intel_lpss_pci_driver); + +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_DESCRIPTION("Intel LPSS PCI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c new file mode 100644 index 000000000000..fdf4d5c1add2 --- /dev/null +++ b/drivers/mfd/intel-lpss.c @@ -0,0 +1,524 @@ +/* + * Intel Sunrisepoint LPSS core support. + * + * Copyright (C) 2015, Intel Corporation + * + * Authors: Andy Shevchenko + * Mika Westerberg + * Heikki Krogerus + * Jarkko Nikula + * + * 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 "intel-lpss.h" + +#define LPSS_DEV_OFFSET 0x000 +#define LPSS_DEV_SIZE 0x200 +#define LPSS_PRIV_OFFSET 0x200 +#define LPSS_PRIV_SIZE 0x100 +#define LPSS_IDMA64_OFFSET 0x800 +#define LPSS_IDMA64_SIZE 0x800 + +/* Offsets from lpss->priv */ +#define LPSS_PRIV_RESETS 0x04 +#define LPSS_PRIV_RESETS_FUNC BIT(2) +#define LPSS_PRIV_RESETS_IDMA 0x3 + +#define LPSS_PRIV_ACTIVELTR 0x10 +#define LPSS_PRIV_IDLELTR 0x14 + +#define LPSS_PRIV_LTR_REQ BIT(15) +#define LPSS_PRIV_LTR_SCALE_MASK 0xc00 +#define LPSS_PRIV_LTR_SCALE_1US 0x800 +#define LPSS_PRIV_LTR_SCALE_32US 0xc00 +#define LPSS_PRIV_LTR_VALUE_MASK 0x3ff + +#define LPSS_PRIV_SSP_REG 0x20 +#define LPSS_PRIV_SSP_REG_DIS_DMA_FIN BIT(0) + +#define LPSS_PRIV_REMAP_ADDR_LO 0x40 +#define LPSS_PRIV_REMAP_ADDR_HI 0x44 + +#define LPSS_PRIV_CAPS 0xfc +#define LPSS_PRIV_CAPS_NO_IDMA BIT(8) +#define LPSS_PRIV_CAPS_TYPE_SHIFT 4 +#define LPSS_PRIV_CAPS_TYPE_MASK (0xf << LPSS_PRIV_CAPS_TYPE_SHIFT) + +/* This matches the type field in CAPS register */ +enum intel_lpss_dev_type { + LPSS_DEV_I2C = 0, + LPSS_DEV_UART, + LPSS_DEV_SPI, +}; + +struct intel_lpss { + const struct intel_lpss_platform_info *info; + enum intel_lpss_dev_type type; + struct clk *clk; + struct clk_lookup *clock; + const struct mfd_cell *cell; + struct device *dev; + void __iomem *priv; + int devid; + u32 caps; + u32 active_ltr; + u32 idle_ltr; + struct dentry *debugfs; +}; + +static const struct resource intel_lpss_dev_resources[] = { + DEFINE_RES_MEM_NAMED(LPSS_DEV_OFFSET, LPSS_DEV_SIZE, "lpss_dev"), + DEFINE_RES_MEM_NAMED(LPSS_PRIV_OFFSET, LPSS_PRIV_SIZE, "lpss_priv"), + DEFINE_RES_IRQ(0), +}; + +static const struct resource intel_lpss_idma64_resources[] = { + DEFINE_RES_MEM(LPSS_IDMA64_OFFSET, LPSS_IDMA64_SIZE), + DEFINE_RES_IRQ(0), +}; + +#define LPSS_IDMA64_DRIVER_NAME "idma64" + +/* + * Cells needs to be ordered so that the iDMA is created first. This is + * because we need to be sure the DMA is available when the host controller + * driver is probed. + */ +static const struct mfd_cell intel_lpss_idma64_cell = { + .name = LPSS_IDMA64_DRIVER_NAME, + .num_resources = ARRAY_SIZE(intel_lpss_idma64_resources), + .resources = intel_lpss_idma64_resources, +}; + +static const struct mfd_cell intel_lpss_i2c_cell = { + .name = "i2c_designware", + .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), + .resources = intel_lpss_dev_resources, +}; + +static const struct mfd_cell intel_lpss_uart_cell = { + .name = "dw-apb-uart", + .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), + .resources = intel_lpss_dev_resources, +}; + +static const struct mfd_cell intel_lpss_spi_cell = { + .name = "pxa2xx-spi", + .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), + .resources = intel_lpss_dev_resources, +}; + +static DEFINE_IDA(intel_lpss_devid_ida); +static struct dentry *intel_lpss_debugfs; + +static int intel_lpss_request_dma_module(const char *name) +{ + static bool intel_lpss_dma_requested; + + if (intel_lpss_dma_requested) + return 0; + + intel_lpss_dma_requested = true; + return request_module("%s", name); +} + +static void intel_lpss_cache_ltr(struct intel_lpss *lpss) +{ + lpss->active_ltr = readl(lpss->priv + LPSS_PRIV_ACTIVELTR); + lpss->idle_ltr = readl(lpss->priv + LPSS_PRIV_IDLELTR); +} + +static int intel_lpss_debugfs_add(struct intel_lpss *lpss) +{ + struct dentry *dir; + + dir = debugfs_create_dir(dev_name(lpss->dev), intel_lpss_debugfs); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + /* Cache the values into lpss structure */ + intel_lpss_cache_ltr(lpss); + + debugfs_create_x32("capabilities", S_IRUGO, dir, &lpss->caps); + debugfs_create_x32("active_ltr", S_IRUGO, dir, &lpss->active_ltr); + debugfs_create_x32("idle_ltr", S_IRUGO, dir, &lpss->idle_ltr); + + lpss->debugfs = dir; + return 0; +} + +static void intel_lpss_debugfs_remove(struct intel_lpss *lpss) +{ + debugfs_remove_recursive(lpss->debugfs); +} + +static void intel_lpss_ltr_set(struct device *dev, s32 val) +{ + struct intel_lpss *lpss = dev_get_drvdata(dev); + u32 ltr; + + /* + * Program latency tolerance (LTR) accordingly what has been asked + * by the PM QoS layer or disable it in case we were passed + * negative value or PM_QOS_LATENCY_ANY. + */ + ltr = readl(lpss->priv + LPSS_PRIV_ACTIVELTR); + + if (val == PM_QOS_LATENCY_ANY || val < 0) { + ltr &= ~LPSS_PRIV_LTR_REQ; + } else { + ltr |= LPSS_PRIV_LTR_REQ; + ltr &= ~LPSS_PRIV_LTR_SCALE_MASK; + ltr &= ~LPSS_PRIV_LTR_VALUE_MASK; + + if (val > LPSS_PRIV_LTR_VALUE_MASK) + ltr |= LPSS_PRIV_LTR_SCALE_32US | val >> 5; + else + ltr |= LPSS_PRIV_LTR_SCALE_1US | val; + } + + if (ltr == lpss->active_ltr) + return; + + writel(ltr, lpss->priv + LPSS_PRIV_ACTIVELTR); + writel(ltr, lpss->priv + LPSS_PRIV_IDLELTR); + + /* Cache the values into lpss structure */ + intel_lpss_cache_ltr(lpss); +} + +static void intel_lpss_ltr_expose(struct intel_lpss *lpss) +{ + lpss->dev->power.set_latency_tolerance = intel_lpss_ltr_set; + dev_pm_qos_expose_latency_tolerance(lpss->dev); +} + +static void intel_lpss_ltr_hide(struct intel_lpss *lpss) +{ + dev_pm_qos_hide_latency_tolerance(lpss->dev); + lpss->dev->power.set_latency_tolerance = NULL; +} + +static int intel_lpss_assign_devs(struct intel_lpss *lpss) +{ + unsigned int type; + + type = lpss->caps & LPSS_PRIV_CAPS_TYPE_MASK; + type >>= LPSS_PRIV_CAPS_TYPE_SHIFT; + + switch (type) { + case LPSS_DEV_I2C: + lpss->cell = &intel_lpss_i2c_cell; + break; + case LPSS_DEV_UART: + lpss->cell = &intel_lpss_uart_cell; + break; + case LPSS_DEV_SPI: + lpss->cell = &intel_lpss_spi_cell; + break; + default: + return -ENODEV; + } + + lpss->type = type; + + return 0; +} + +static bool intel_lpss_has_idma(const struct intel_lpss *lpss) +{ + return (lpss->caps & LPSS_PRIV_CAPS_NO_IDMA) == 0; +} + +static void intel_lpss_set_remap_addr(const struct intel_lpss *lpss) +{ + resource_size_t addr = lpss->info->mem->start; + + writel(addr, lpss->priv + LPSS_PRIV_REMAP_ADDR_LO); +#if BITS_PER_LONG > 32 + writel(addr >> 32, lpss->priv + LPSS_PRIV_REMAP_ADDR_HI); +#else + writel(0, lpss->priv + LPSS_PRIV_REMAP_ADDR_HI); +#endif +} + +static void intel_lpss_deassert_reset(const struct intel_lpss *lpss) +{ + u32 value = LPSS_PRIV_RESETS_FUNC | LPSS_PRIV_RESETS_IDMA; + + /* Bring out the device from reset */ + writel(value, lpss->priv + LPSS_PRIV_RESETS); +} + +static void intel_lpss_init_dev(const struct intel_lpss *lpss) +{ + u32 value = LPSS_PRIV_SSP_REG_DIS_DMA_FIN; + + intel_lpss_deassert_reset(lpss); + + if (!intel_lpss_has_idma(lpss)) + return; + + intel_lpss_set_remap_addr(lpss); + + /* Make sure that SPI multiblock DMA transfers are re-enabled */ + if (lpss->type == LPSS_DEV_SPI) + writel(value, lpss->priv + LPSS_PRIV_SSP_REG); +} + +static void intel_lpss_unregister_clock_tree(struct clk *clk) +{ + struct clk *parent; + + while (clk) { + parent = clk_get_parent(clk); + clk_unregister(clk); + clk = parent; + } +} + +static int intel_lpss_register_clock_divider(struct intel_lpss *lpss, + const char *devname, + struct clk **clk) +{ + char name[32]; + struct clk *tmp = *clk; + + snprintf(name, sizeof(name), "%s-enable", devname); + tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), 0, + lpss->priv, 0, 0, NULL); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + + snprintf(name, sizeof(name), "%s-div", devname); + tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp), + 0, lpss->priv, 1, 15, 16, 15, 0, + NULL); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + *clk = tmp; + + snprintf(name, sizeof(name), "%s-update", devname); + tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), + CLK_SET_RATE_PARENT, lpss->priv, 31, 0, NULL); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + *clk = tmp; + + return 0; +} + +static int intel_lpss_register_clock(struct intel_lpss *lpss) +{ + const struct mfd_cell *cell = lpss->cell; + struct clk *clk; + char devname[24]; + int ret; + + if (!lpss->info->clk_rate) + return 0; + + /* Root clock */ + clk = clk_register_fixed_rate(NULL, dev_name(lpss->dev), NULL, + CLK_IS_ROOT, lpss->info->clk_rate); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + snprintf(devname, sizeof(devname), "%s.%d", cell->name, lpss->devid); + + /* + * Support for clock divider only if it has some preset value. + * Otherwise we assume that the divider is not used. + */ + if (lpss->type != LPSS_DEV_I2C) { + ret = intel_lpss_register_clock_divider(lpss, devname, &clk); + if (ret) + goto err_clk_register; + } + + ret = -ENOMEM; + + /* Clock for the host controller */ + lpss->clock = clkdev_create(clk, lpss->info->clk_con_id, "%s", devname); + if (!lpss->clock) + goto err_clk_register; + + lpss->clk = clk; + + return 0; + +err_clk_register: + intel_lpss_unregister_clock_tree(clk); + + return ret; +} + +static void intel_lpss_unregister_clock(struct intel_lpss *lpss) +{ + if (IS_ERR_OR_NULL(lpss->clk)) + return; + + clkdev_drop(lpss->clock); + intel_lpss_unregister_clock_tree(lpss->clk); +} + +int intel_lpss_probe(struct device *dev, + const struct intel_lpss_platform_info *info) +{ + struct intel_lpss *lpss; + int ret; + + if (!info || !info->mem || info->irq <= 0) + return -EINVAL; + + lpss = devm_kzalloc(dev, sizeof(*lpss), GFP_KERNEL); + if (!lpss) + return -ENOMEM; + + lpss->priv = devm_ioremap(dev, info->mem->start + LPSS_PRIV_OFFSET, + LPSS_PRIV_SIZE); + if (!lpss->priv) + return -ENOMEM; + + lpss->info = info; + lpss->dev = dev; + lpss->caps = readl(lpss->priv + LPSS_PRIV_CAPS); + + dev_set_drvdata(dev, lpss); + + ret = intel_lpss_assign_devs(lpss); + if (ret) + return ret; + + intel_lpss_init_dev(lpss); + + lpss->devid = ida_simple_get(&intel_lpss_devid_ida, 0, 0, GFP_KERNEL); + if (lpss->devid < 0) + return lpss->devid; + + ret = intel_lpss_register_clock(lpss); + if (ret) + goto err_clk_register; + + intel_lpss_ltr_expose(lpss); + + ret = intel_lpss_debugfs_add(lpss); + if (ret) + dev_warn(dev, "Failed to create debugfs entries\n"); + + if (intel_lpss_has_idma(lpss)) { + /* + * Ensure the DMA driver is loaded before the host + * controller device appears, so that the host controller + * driver can request its DMA channels as early as + * possible. + * + * If the DMA module is not there that's OK as well. + */ + intel_lpss_request_dma_module(LPSS_IDMA64_DRIVER_NAME); + + ret = mfd_add_devices(dev, lpss->devid, &intel_lpss_idma64_cell, + 1, info->mem, info->irq, NULL); + if (ret) + dev_warn(dev, "Failed to add %s, fallback to PIO\n", + LPSS_IDMA64_DRIVER_NAME); + } + + ret = mfd_add_devices(dev, lpss->devid, lpss->cell, + 1, info->mem, info->irq, NULL); + if (ret) + goto err_remove_ltr; + + return 0; + +err_remove_ltr: + intel_lpss_debugfs_remove(lpss); + intel_lpss_ltr_hide(lpss); + +err_clk_register: + ida_simple_remove(&intel_lpss_devid_ida, lpss->devid); + + return ret; +} +EXPORT_SYMBOL_GPL(intel_lpss_probe); + +void intel_lpss_remove(struct device *dev) +{ + struct intel_lpss *lpss = dev_get_drvdata(dev); + + mfd_remove_devices(dev); + intel_lpss_debugfs_remove(lpss); + intel_lpss_ltr_hide(lpss); + intel_lpss_unregister_clock(lpss); + ida_simple_remove(&intel_lpss_devid_ida, lpss->devid); +} +EXPORT_SYMBOL_GPL(intel_lpss_remove); + +static int resume_lpss_device(struct device *dev, void *data) +{ + pm_runtime_resume(dev); + return 0; +} + +int intel_lpss_prepare(struct device *dev) +{ + /* + * Resume both child devices before entering system sleep. This + * ensures that they are in proper state before they get suspended. + */ + device_for_each_child_reverse(dev, NULL, resume_lpss_device); + return 0; +} +EXPORT_SYMBOL_GPL(intel_lpss_prepare); + +int intel_lpss_suspend(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL_GPL(intel_lpss_suspend); + +int intel_lpss_resume(struct device *dev) +{ + struct intel_lpss *lpss = dev_get_drvdata(dev); + + intel_lpss_init_dev(lpss); + + return 0; +} +EXPORT_SYMBOL_GPL(intel_lpss_resume); + +static int __init intel_lpss_init(void) +{ + intel_lpss_debugfs = debugfs_create_dir("intel_lpss", NULL); + return 0; +} +module_init(intel_lpss_init); + +static void __exit intel_lpss_exit(void) +{ + debugfs_remove(intel_lpss_debugfs); +} +module_exit(intel_lpss_exit); + +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_AUTHOR("Heikki Krogerus "); +MODULE_AUTHOR("Jarkko Nikula "); +MODULE_DESCRIPTION("Intel LPSS core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h new file mode 100644 index 000000000000..f28cb28a62f8 --- /dev/null +++ b/drivers/mfd/intel-lpss.h @@ -0,0 +1,62 @@ +/* + * Intel LPSS core support. + * + * Copyright (C) 2015, Intel Corporation + * + * Authors: Andy Shevchenko + * Mika Westerberg + * + * 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 __MFD_INTEL_LPSS_H +#define __MFD_INTEL_LPSS_H + +struct device; +struct resource; + +struct intel_lpss_platform_info { + struct resource *mem; + int irq; + unsigned long clk_rate; + const char *clk_con_id; +}; + +int intel_lpss_probe(struct device *dev, + const struct intel_lpss_platform_info *info); +void intel_lpss_remove(struct device *dev); + +#ifdef CONFIG_PM +int intel_lpss_prepare(struct device *dev); +int intel_lpss_suspend(struct device *dev); +int intel_lpss_resume(struct device *dev); + +#ifdef CONFIG_PM_SLEEP +#define INTEL_LPSS_SLEEP_PM_OPS \ + .prepare = intel_lpss_prepare, \ + .suspend = intel_lpss_suspend, \ + .resume = intel_lpss_resume, \ + .freeze = intel_lpss_suspend, \ + .thaw = intel_lpss_resume, \ + .poweroff = intel_lpss_suspend, \ + .restore = intel_lpss_resume, +#endif + +#define INTEL_LPSS_RUNTIME_PM_OPS \ + .runtime_suspend = intel_lpss_suspend, \ + .runtime_resume = intel_lpss_resume, + +#else /* !CONFIG_PM */ +#define INTEL_LPSS_SLEEP_PM_OPS +#define INTEL_LPSS_RUNTIME_PM_OPS +#endif /* CONFIG_PM */ + +#define INTEL_LPSS_PM_OPS(name) \ +const struct dev_pm_ops name = { \ + INTEL_LPSS_SLEEP_PM_OPS \ + INTEL_LPSS_RUNTIME_PM_OPS \ +} + +#endif /* __MFD_INTEL_LPSS_H */ -- cgit v1.3-6-gb490 From 9458120ea112c06f56ea1b75a1511815d36aecc2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Jul 2015 15:55:22 -0500 Subject: pinctrl: kill off set_irq_flags usage set_irq_flags is ARM specific with custom flags which have genirq equivalents. Convert drivers to use the genirq interfaces directly, so we can kill off set_irq_flags. The translation of flags is as follows: IRQF_VALID -> !IRQ_NOREQUEST IRQF_PROBE -> !IRQ_NOPROBE IRQF_NOAUTOEN -> IRQ_NOAUTOEN For IRQs managed by an irqdomain, the irqdomain core code handles clearing and setting IRQ_NOREQUEST already, so there is no need to do this in .map() functions and we can simply remove the set_irq_flags calls. Some users also modify IRQ_NOPROBE and this has been maintained although it is not clear that is really needed. There appears to be a great deal of blind copy and paste of this code. Signed-off-by: Rob Herring Cc: Stephen Warren Cc: Lee Jones Cc: Matthias Brugger Cc: Tomasz Figa Cc: Thomas Abraham Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: linux-gpio@vger.kernel.org Cc: linux-rpi-kernel@lists.infradead.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-mediatek@lists.infradead.org Cc: linux-samsung-soc@vger.kernel.org Signed-off-by: Linus Walleij --- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1 - drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 2 -- drivers/pinctrl/pinctrl-single.c | 5 ----- drivers/pinctrl/samsung/pinctrl-exynos.c | 1 - drivers/pinctrl/samsung/pinctrl-exynos5440.c | 1 - drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 2 -- drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 2 -- 7 files changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index 104d8a63bbce..f4d0168d814e 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -987,7 +987,6 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) irq_set_chip_and_handler(irq, &bcm2835_gpio_irq_chip, handle_level_irq); irq_set_chip_data(irq, pc); - set_irq_flags(irq, IRQF_VALID); } for (i = 0; i < BCM2835_NUM_BANKS; i++) { diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index 4be0124e9936..0350a807da1a 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -1348,11 +1348,9 @@ int mtk_pctrl_init(struct platform_device *pdev, irq_set_chip_and_handler(virq, &mtk_pinctrl_irq_chip, handle_level_irq); irq_set_chip_data(virq, pctl); - set_irq_flags(virq, IRQF_VALID); }; irq_set_chained_handler_and_data(irq, mtk_eint_irq_handler, pctl); - set_irq_flags(irq, IRQF_VALID); return 0; chip_error: diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index b8aaf9559ddd..e99cabe33696 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1716,12 +1716,7 @@ static int pcs_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_set_chip_data(irq, pcs_soc); irq_set_chip_and_handler(irq, &pcs->chip, handle_level_irq); - -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif return 0; } diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 07773c70c12c..5f45caaef46d 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -256,7 +256,6 @@ static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, b); irq_set_chip_and_handler(virq, &b->irq_chip->chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); return 0; } diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c index 5574b8ae5949..9ce0b8619d4c 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c @@ -894,7 +894,6 @@ static int exynos5440_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, d); irq_set_chip_and_handler(virq, &exynos5440_gpio_irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); return 0; } diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index 5d7b6112fc7e..019844d479bb 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -437,7 +437,6 @@ static int s3c24xx_gpf_irq_map(struct irq_domain *h, unsigned int virq, handle_edge_irq); } irq_set_chip_data(virq, bank); - set_irq_flags(virq, IRQF_VALID); return 0; } @@ -457,7 +456,6 @@ static int s3c24xx_gpg_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_and_handler(virq, &s3c24xx_eint_chip, handle_edge_irq); irq_set_chip_data(virq, bank); - set_irq_flags(virq, IRQF_VALID); return 0; } diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index 8700f0c9eee1..f5ea40a69711 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -395,7 +395,6 @@ static int s3c64xx_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_and_handler(virq, &s3c64xx_gpio_irq_chip, handle_level_irq); irq_set_chip_data(virq, bank); - set_irq_flags(virq, IRQF_VALID); return 0; } @@ -671,7 +670,6 @@ static int s3c64xx_eint0_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_and_handler(virq, &s3c64xx_eint0_irq_chip, handle_level_irq); irq_set_chip_data(virq, ddata); - set_irq_flags(virq, IRQF_VALID); return 0; } -- cgit v1.3-6-gb490 From 3b9a02e844948fc14cb32a06bc00e0e61bde3577 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 27 Jul 2015 11:47:38 +0200 Subject: drm/i915: Fake AGP is dead Remove the leftovers, yay! AGP for i915 kms died long ago with commit 3bb6ce66866310f50d461b9eff949c1ce95560ce Author: Daniel Vetter Date: Wed Nov 13 22:14:16 2013 +0100 drm/i915: Kill legeacy AGP for gen3 kms and with ums now gone to there's really no users any more. Note that device_is_agp is only called when DRIVER_USE_AGP is set and since we've unconditionally cleared that since a while there are really no users left for i915_driver_device_is_agp. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 10 ---------- drivers/gpu/drm/i915/i915_drv.c | 4 ---- drivers/gpu/drm/i915/i915_drv.h | 1 - 3 files changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index b1f9e5561cf2..ab37d1121be8 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1274,13 +1274,3 @@ const struct drm_ioctl_desc i915_ioctls[] = { }; int i915_max_ioctl = ARRAY_SIZE(i915_ioctls); - -/* - * This is really ugly: Because old userspace abused the linux agp interface to - * manage the gtt, we need to claim that all intel devices are agp. For - * otherwise the drm core refuses to initialize the agp support code. - */ -int i915_driver_device_is_agp(struct drm_device *dev) -{ - return 1; -} diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0d6775a3e88c..151263b433e6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -935,8 +935,6 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (PCI_FUNC(pdev->devfn)) return -ENODEV; - driver.driver_features &= ~(DRIVER_USE_AGP); - return drm_get_pci_dev(pdev, ent, &driver); } @@ -1649,7 +1647,6 @@ static struct drm_driver driver = { * deal with them for Intel hardware. */ .driver_features = - DRIVER_USE_AGP | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER, .load = i915_driver_load, @@ -1664,7 +1661,6 @@ static struct drm_driver driver = { .suspend = i915_suspend_legacy, .resume = i915_resume_legacy, - .device_is_agp = i915_driver_device_is_agp, #if defined(CONFIG_DEBUG_FS) .debugfs_init = i915_debugfs_init, .debugfs_cleanup = i915_debugfs_cleanup, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 40fea41affc9..abd1a8659d83 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2628,7 +2628,6 @@ extern void i915_driver_preclose(struct drm_device *dev, struct drm_file *file); extern void i915_driver_postclose(struct drm_device *dev, struct drm_file *file); -extern int i915_driver_device_is_agp(struct drm_device * dev); #ifdef CONFIG_COMPAT extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); -- cgit v1.3-6-gb490 From 28355f81969962cf01aef5b13d7de5b4ab0c5f13 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Tue, 14 Jul 2015 10:29:54 +0200 Subject: gpio: defer probe if pinctrl cannot be found When an OF node has a pin range for its GPIOs, return -EPROBE_DEFER if the pin controller isn't available. Otherwise, the GPIO range wouldn't be set at all unless the pin controller probed always before the GPIO chip. With this change, the probe of the GPIO chip will be deferred and will be retried at a later point, hopefully once the pin controller has been registered and probed already. Signed-off-by: Tomeu Vizoso Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 27 ++++++++++++++++++--------- drivers/gpio/gpiolib.c | 5 ++++- include/linux/of_gpio.h | 4 ++-- 3 files changed, 24 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 1e36ec5e2e0c..fa6e3c8823d6 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -335,7 +335,7 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc) EXPORT_SYMBOL(of_mm_gpiochip_remove); #ifdef CONFIG_PINCTRL -static void of_gpiochip_add_pin_range(struct gpio_chip *chip) +static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { struct device_node *np = chip->of_node; struct of_phandle_args pinspec; @@ -346,7 +346,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) struct property *group_names; if (!np) - return; + return 0; group_names = of_find_property(np, group_names_propname, NULL); @@ -358,7 +358,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) pctldev = of_pinctrl_get(pinspec.np); if (!pctldev) - break; + return -EPROBE_DEFER; if (pinspec.args[2]) { if (group_names) { @@ -378,7 +378,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) pinspec.args[1], pinspec.args[2]); if (ret) - break; + return ret; } else { /* npins == 0: special range */ if (pinspec.args[1]) { @@ -408,32 +408,41 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) ret = gpiochip_add_pingroup_range(chip, pctldev, pinspec.args[0], name); if (ret) - break; + return ret; } } + + return 0; } #else -static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} +static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; } #endif -void of_gpiochip_add(struct gpio_chip *chip) +int of_gpiochip_add(struct gpio_chip *chip) { + int status; + if ((!chip->of_node) && (chip->dev)) chip->of_node = chip->dev->of_node; if (!chip->of_node) - return; + return 0; if (!chip->of_xlate) { chip->of_gpio_n_cells = 2; chip->of_xlate = of_gpio_simple_xlate; } - of_gpiochip_add_pin_range(chip); + status = of_gpiochip_add_pin_range(chip); + if (status) + return status; + of_node_get(chip->of_node); of_gpiochip_scan_hogs(chip); + + return 0; } void of_gpiochip_remove(struct gpio_chip *chip) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9312bbcb19b9..1b5b8da71154 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -290,7 +290,10 @@ int gpiochip_add(struct gpio_chip *chip) if (!chip->owner && chip->dev && chip->dev->driver) chip->owner = chip->dev->driver->owner; - of_gpiochip_add(chip); + status = of_gpiochip_add(chip); + if (status) + goto err_remove_chip; + acpi_gpiochip_add(chip); status = gpiochip_sysfs_register(chip); diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 69dbe312b11b..f3191828f037 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -54,7 +54,7 @@ extern int of_mm_gpiochip_add(struct device_node *np, struct of_mm_gpio_chip *mm_gc); extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc); -extern void of_gpiochip_add(struct gpio_chip *gc); +extern int of_gpiochip_add(struct gpio_chip *gc); extern void of_gpiochip_remove(struct gpio_chip *gc); extern int of_gpio_simple_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, @@ -76,7 +76,7 @@ static inline int of_gpio_simple_xlate(struct gpio_chip *gc, return -ENOSYS; } -static inline void of_gpiochip_add(struct gpio_chip *gc) { } +static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; } static inline void of_gpiochip_remove(struct gpio_chip *gc) { } #endif /* CONFIG_OF_GPIO */ -- cgit v1.3-6-gb490 From 1051fade4b1fac0de19478b33383b25bd1d24d10 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 25 Jul 2015 11:23:12 +0200 Subject: pinctrl: nomadik: split stn8815 UART0 pin groups Split the UART pin groups so we can activate RX/TX, CTS/RTS and the modem pins (DCD, DSR, RI, DTR) as three different groups with function u0. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c index a2de3b7a57a0..587b222f12f3 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c @@ -271,9 +271,11 @@ static const struct pinctrl_pin_desc nmk_stn8815_pins[] = { */ /* Altfunction A */ -static const unsigned u0_a_1_pins[] = { STN8815_PIN_B4, STN8815_PIN_D5, - STN8815_PIN_C5, STN8815_PIN_A4, STN8815_PIN_B5, STN8815_PIN_D6, - STN8815_PIN_C6, STN8815_PIN_B6 }; +static const unsigned u0txrx_a_1_pins[] = { STN8815_PIN_B4, STN8815_PIN_D5 }; +static const unsigned u0ctsrts_a_1_pins[] = { STN8815_PIN_C5, STN8815_PIN_B6 }; +/* Modem pins: DCD, DSR, RI, DTR */ +static const unsigned u0modem_a_1_pins[] = { STN8815_PIN_A4, STN8815_PIN_B5, + STN8815_PIN_D6, STN8815_PIN_C6 }; static const unsigned mmcsd_a_1_pins[] = { STN8815_PIN_B10, STN8815_PIN_A10, STN8815_PIN_C11, STN8815_PIN_B11, STN8815_PIN_A11, STN8815_PIN_C12, STN8815_PIN_B12, STN8815_PIN_A12, STN8815_PIN_C13, STN8815_PIN_C15 }; @@ -290,7 +292,9 @@ static const unsigned i2cusb_b_1_pins[] = { STN8815_PIN_C21, STN8815_PIN_C20 }; .npins = ARRAY_SIZE(a##_pins), .altsetting = b } static const struct nmk_pingroup nmk_stn8815_groups[] = { - STN8815_PIN_GROUP(u0_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(u0txrx_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(u0ctsrts_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(u0modem_a_1, NMK_GPIO_ALT_A), STN8815_PIN_GROUP(mmcsd_a_1, NMK_GPIO_ALT_A), STN8815_PIN_GROUP(mmcsd_b_1, NMK_GPIO_ALT_B), STN8815_PIN_GROUP(u1_a_1, NMK_GPIO_ALT_A), @@ -304,7 +308,7 @@ static const struct nmk_pingroup nmk_stn8815_groups[] = { #define STN8815_FUNC_GROUPS(a, b...) \ static const char * const a##_groups[] = { b }; -STN8815_FUNC_GROUPS(u0, "u0_a_1"); +STN8815_FUNC_GROUPS(u0, "u0txrx_a_1", "u0ctsrts_a_1", "u0modem_a_1"); STN8815_FUNC_GROUPS(mmcsd, "mmcsd_a_1", "mmcsd_b_1"); STN8815_FUNC_GROUPS(u1, "u1_a_1", "u1_b_1"); STN8815_FUNC_GROUPS(i2c1, "i2c1_a_1"); -- cgit v1.3-6-gb490 From e8d36d5dbb6a6ec4f5222f8775d664ec29d5527d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Jul 2015 15:55:13 -0500 Subject: ARM: kill off set_irq_flags usage set_irq_flags is ARM specific with custom flags which have genirq equivalents. Convert drivers to use the genirq interfaces directly, so we can kill off set_irq_flags. The translation of flags is as follows: IRQF_VALID -> !IRQ_NOREQUEST IRQF_PROBE -> !IRQ_NOPROBE IRQF_NOAUTOEN -> IRQ_NOAUTOEN For IRQs managed by an irqdomain, the irqdomain core code handles clearing and setting IRQ_NOREQUEST already, so there is no need to do this in .map() functions and we can simply remove the set_irq_flags calls. Some users also modify IRQ_NOPROBE and this has been maintained although it is not clear that is really needed. There appears to be a great deal of blind copy and paste of this code. Signed-off-by: Rob Herring Cc: Russell King Cc: Sekhar Nori Cc: Kevin Hilman Cc: Jason Cooper Cc: Andrew Lunn Cc: Sebastian Hesselbarth Cc: Gregory Clement Acked-by: Hans Ulli Kroll Acked-by: Shawn Guo Cc: Sascha Hauer Cc: Imre Kaloz Acked-by: Krzysztof Halasa Cc: Greg Ungerer Cc: Roland Stigge Cc: Tony Lindgren Cc: Daniel Mack Cc: Haojian Zhuang Cc: Robert Jarzmik Cc: Simtec Linux Team Cc: Kukjin Kim Cc: Krzysztof Kozlowski Acked-by: Wan ZongShun Cc: linux-arm-kernel@lists.infradead.org Cc: linux-omap@vger.kernel.org Cc: linux-samsung-soc@vger.kernel.org Tested-by: Kevin Hilman Signed-off-by: Olof Johansson --- arch/arm/common/it8152.c | 2 +- arch/arm/common/locomo.c | 2 +- arch/arm/common/sa1111.c | 4 ++-- arch/arm/mach-davinci/cp_intc.c | 2 +- arch/arm/mach-dove/irq.c | 2 +- arch/arm/mach-ebsa110/core.c | 2 +- arch/arm/mach-footbridge/common.c | 2 +- arch/arm/mach-footbridge/isa-irq.c | 8 ++++---- arch/arm/mach-gemini/gpio.c | 2 +- arch/arm/mach-gemini/irq.c | 2 +- arch/arm/mach-imx/3ds_debugboard.c | 2 +- arch/arm/mach-imx/mach-mx31ads.c | 2 +- arch/arm/mach-iop13xx/irq.c | 2 +- arch/arm/mach-iop32x/irq.c | 2 +- arch/arm/mach-iop33x/irq.c | 2 +- arch/arm/mach-ixp4xx/common.c | 2 +- arch/arm/mach-ks8695/irq.c | 2 +- arch/arm/mach-lpc32xx/irq.c | 2 +- arch/arm/mach-netx/generic.c | 2 +- arch/arm/mach-omap1/fpga.c | 2 +- arch/arm/mach-omap1/irq.c | 2 +- arch/arm/mach-pxa/balloon3.c | 2 +- arch/arm/mach-pxa/irq.c | 1 - arch/arm/mach-pxa/lpd270.c | 2 +- arch/arm/mach-pxa/pcm990-baseboard.c | 2 +- arch/arm/mach-pxa/pxa3xx.c | 2 +- arch/arm/mach-pxa/viper.c | 2 +- arch/arm/mach-pxa/zeus.c | 2 +- arch/arm/mach-rpc/ecard.c | 2 +- arch/arm/mach-rpc/irq.c | 16 ++++++++-------- arch/arm/mach-s3c24xx/bast-irq.c | 2 +- arch/arm/mach-s3c64xx/common.c | 2 +- arch/arm/mach-sa1100/neponset.c | 4 ++-- arch/arm/mach-w90x900/irq.c | 2 +- drivers/irqchip/irq-sa11x0.c | 1 - 35 files changed, 45 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c index 5114b68e99d5..96dabcb6c621 100644 --- a/arch/arm/common/it8152.c +++ b/arch/arm/common/it8152.c @@ -91,7 +91,7 @@ void it8152_init_irq(void) for (irq = IT8152_IRQ(0); irq <= IT8152_LAST_IRQ; irq++) { irq_set_chip_and_handler(irq, &it8152_irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } } diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index b55c3625d7ee..339fc414daad 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -205,7 +205,7 @@ static void locomo_setup_irq(struct locomo *lchip) for ( ; irq <= lchip->irq_base + 3; irq++) { irq_set_chip_and_handler(irq, &locomo_chip, handle_level_irq); irq_set_chip_data(irq, lchip); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } } diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 93ee70dbbdd3..680374de06a9 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -486,7 +486,7 @@ static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base) irq_set_chip_and_handler(irq, &sa1111_low_chip, handle_edge_irq); irq_set_chip_data(irq, sachip); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } for (i = AUDXMTDMADONEA; i <= IRQ_S1_BVD1_STSCHG; i++) { @@ -494,7 +494,7 @@ static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base) irq_set_chip_and_handler(irq, &sa1111_high_chip, handle_edge_irq); irq_set_chip_data(irq, sachip); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } /* diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c index 006dae8dfe44..bf12ce64407a 100644 --- a/arch/arm/mach-davinci/cp_intc.c +++ b/arch/arm/mach-davinci/cp_intc.c @@ -112,7 +112,7 @@ static int cp_intc_host_map(struct irq_domain *h, unsigned int virq, pr_debug("cp_intc_host_map(%d, 0x%lx)\n", virq, hw); irq_set_chip(virq, &cp_intc_irq_chip); - set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(virq); irq_set_handler(virq, handle_edge_irq); return 0; } diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c index df0223f76fa9..ea7892e72242 100644 --- a/arch/arm/mach-dove/irq.c +++ b/arch/arm/mach-dove/irq.c @@ -172,7 +172,7 @@ void __init dove_init_irq(void) for (i = IRQ_DOVE_PMU_START; i < NR_IRQS; i++) { irq_set_chip_and_handler(i, &pmu_irq_chip, handle_level_irq); irq_set_status_flags(i, IRQ_LEVEL); - set_irq_flags(i, IRQF_VALID); + irq_clear_status_flags(i, IRQ_NOREQUEST); } irq_set_chained_handler(IRQ_DOVE_PMU, pmu_irq_handler); } diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c index 8254e716b095..688e5fed49a7 100644 --- a/arch/arm/mach-ebsa110/core.c +++ b/arch/arm/mach-ebsa110/core.c @@ -65,7 +65,7 @@ static void __init ebsa110_init_irq(void) for (irq = 0; irq < NR_IRQS; irq++) { irq_set_chip_and_handler(irq, &ebsa110_irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } } diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c index 9e8220e38398..0f0c9e040fcc 100644 --- a/arch/arm/mach-footbridge/common.c +++ b/arch/arm/mach-footbridge/common.c @@ -106,7 +106,7 @@ static void __init __fb_init_irq(void) for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) { irq_set_chip_and_handler(irq, &fb_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } } diff --git a/arch/arm/mach-footbridge/isa-irq.c b/arch/arm/mach-footbridge/isa-irq.c index c3a0abbc9049..fcd79bc3a3e1 100644 --- a/arch/arm/mach-footbridge/isa-irq.c +++ b/arch/arm/mach-footbridge/isa-irq.c @@ -153,13 +153,13 @@ void __init isa_init_irq(unsigned int host_irq) for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) { irq_set_chip_and_handler(irq, &isa_lo_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) { irq_set_chip_and_handler(irq, &isa_hi_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } request_resource(&ioport_resource, &pic1_resource); @@ -175,8 +175,8 @@ void __init isa_init_irq(unsigned int host_irq) * resistor on this line. */ if (machine_is_netwinder()) - set_irq_flags(_ISA_IRQ(11), IRQF_VALID | - IRQF_PROBE | IRQF_NOAUTOEN); + irq_modify_status(_ISA_IRQ(11), + IRQ_NOREQUEST | IRQ_NOPROBE, IRQ_NOAUTOEN); } } diff --git a/arch/arm/mach-gemini/gpio.c b/arch/arm/mach-gemini/gpio.c index 3292f2e6ed6f..220333ed741d 100644 --- a/arch/arm/mach-gemini/gpio.c +++ b/arch/arm/mach-gemini/gpio.c @@ -220,7 +220,7 @@ void __init gemini_gpio_init(void) j < GPIO_IRQ_BASE + (i + 1) * 32; j++) { irq_set_chip_and_handler(j, &gpio_irq_chip, handle_edge_irq); - set_irq_flags(j, IRQF_VALID); + irq_clear_status_flags(j, IRQ_NOREQUEST); } irq_set_chained_handler_and_data(IRQ_GPIO(i), gpio_irq_handler, diff --git a/arch/arm/mach-gemini/irq.c b/arch/arm/mach-gemini/irq.c index 44f50dcb616d..d929b3ff18fd 100644 --- a/arch/arm/mach-gemini/irq.c +++ b/arch/arm/mach-gemini/irq.c @@ -92,7 +92,7 @@ void __init gemini_init_irq(void) } else { irq_set_handler(i, handle_level_irq); } - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); } /* Disable all interrupts */ diff --git a/arch/arm/mach-imx/3ds_debugboard.c b/arch/arm/mach-imx/3ds_debugboard.c index 134377352966..45903be6e7b3 100644 --- a/arch/arm/mach-imx/3ds_debugboard.c +++ b/arch/arm/mach-imx/3ds_debugboard.c @@ -195,7 +195,7 @@ int __init mxc_expio_init(u32 base, u32 intr_gpio) for (i = irq_base; i < irq_base + MXC_MAX_EXP_IO_LINES; i++) { irq_set_chip_and_handler(i, &expio_irq_chip, handle_level_irq); - set_irq_flags(i, IRQF_VALID); + irq_clear_status_flags(i, IRQ_NOREQUEST); } irq_set_irq_type(p_irq, IRQF_TRIGGER_LOW); irq_set_chained_handler(p_irq, mxc_expio_irq_handler); diff --git a/arch/arm/mach-imx/mach-mx31ads.c b/arch/arm/mach-imx/mach-mx31ads.c index d08c37c696f6..2c0853560bd2 100644 --- a/arch/arm/mach-imx/mach-mx31ads.c +++ b/arch/arm/mach-imx/mach-mx31ads.c @@ -238,7 +238,7 @@ static void __init mx31ads_init_expio(void) for (i = irq_base; i < irq_base + MXC_MAX_EXP_IO_LINES; i++) { irq_set_chip_and_handler(i, &expio_irq_chip, handle_level_irq); - set_irq_flags(i, IRQF_VALID); + irq_clear_status_flags(i, IRQ_NOREQUEST); } irq = gpio_to_irq(IOMUX_TO_GPIO(MX31_PIN_GPIO1_4)); irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); diff --git a/arch/arm/mach-iop13xx/irq.c b/arch/arm/mach-iop13xx/irq.c index bc739701c301..623d85a4af2d 100644 --- a/arch/arm/mach-iop13xx/irq.c +++ b/arch/arm/mach-iop13xx/irq.c @@ -233,7 +233,7 @@ void __init iop13xx_init_irq(void) irq_set_chip(i, &iop13xx_irqchip4); irq_set_handler(i, handle_level_irq); - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); } iop13xx_msi_init(); diff --git a/arch/arm/mach-iop32x/irq.c b/arch/arm/mach-iop32x/irq.c index d7ee2789d890..2d1f69a68cbc 100644 --- a/arch/arm/mach-iop32x/irq.c +++ b/arch/arm/mach-iop32x/irq.c @@ -69,6 +69,6 @@ void __init iop32x_init_irq(void) for (i = 0; i < NR_IRQS; i++) { irq_set_chip_and_handler(i, &ext_chip, handle_level_irq); - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); } } diff --git a/arch/arm/mach-iop33x/irq.c b/arch/arm/mach-iop33x/irq.c index f7f5d3e451c7..c99ec8d0d285 100644 --- a/arch/arm/mach-iop33x/irq.c +++ b/arch/arm/mach-iop33x/irq.c @@ -113,6 +113,6 @@ void __init iop33x_init_irq(void) irq_set_chip_and_handler(i, (i < 32) ? &iop33x_irqchip1 : &iop33x_irqchip2, handle_level_irq); - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); } } diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 70773b948e7e..1cb6f2f02880 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -296,7 +296,7 @@ void __init ixp4xx_init_irq(void) for(i = 0; i < NR_IRQS; i++) { irq_set_chip_and_handler(i, &ixp4xx_irq_chip, handle_level_irq); - set_irq_flags(i, IRQF_VALID); + irq_clear_status_flags(i, IRQ_NOREQUEST); } } diff --git a/arch/arm/mach-ks8695/irq.c b/arch/arm/mach-ks8695/irq.c index 76802aac0f45..31439f2ee21e 100644 --- a/arch/arm/mach-ks8695/irq.c +++ b/arch/arm/mach-ks8695/irq.c @@ -172,6 +172,6 @@ void __init ks8695_init_irq(void) handle_edge_irq); } - set_irq_flags(irq, IRQF_VALID); + irq_clear_status_flags(irq, IRQ_NOREQUEST); } } diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c index d4f7dc87042b..4ffe333ad331 100644 --- a/arch/arm/mach-lpc32xx/irq.c +++ b/arch/arm/mach-lpc32xx/irq.c @@ -434,7 +434,7 @@ void __init lpc32xx_init_irq(void) for (i = 0; i < NR_IRQS; i++) { irq_set_chip_and_handler(i, &lpc32xx_irq_chip, handle_level_irq); - set_irq_flags(i, IRQF_VALID); + irq_clear_status_flags(i, IRQ_NOREQUEST); } /* Set default mappings */ diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c index db25b0cef3a7..6373e2bff203 100644 --- a/arch/arm/mach-netx/generic.c +++ b/arch/arm/mach-netx/generic.c @@ -174,7 +174,7 @@ void __init netx_init_irq(void) for (irq = NETX_IRQ_HIF_CHAINED(0); irq <= NETX_IRQ_HIF_LAST; irq++) { irq_set_chip_and_handler(irq, &netx_hif_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); + irq_clear_status_flags(irq, IRQ_NOREQUEST); } writel(NETX_DPMAS_INT_EN_GLB_EN, NETX_DPMAS_INT_EN); diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c index 3c0e42219200..dfec671b1639 100644 --- a/arch/arm/mach-omap1/fpga.c +++ b/arch/arm/mach-omap1/fpga.c @@ -169,7 +169,7 @@ void omap1510_fpga_init_irq(void) } irq_set_handler(i, handle_edge_irq); - set_irq_flags(i, IRQF_VALID); + irq_clear_status_flags(i, IRQ_NOREQUEST); } /* diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c index f4d346fda9da..b11edc8a46f0 100644 --- a/arch/arm/mach-omap1/irq.c +++ b/arch/arm/mach-omap1/irq.c @@ -262,7 +262,7 @@ void __init omap1_init_irq(void) irq_trigger = irq_banks[i].trigger_map >> IRQ_BIT(j); omap_irq_set_cfg(j, 0, 0, irq_trigger); - set_irq_flags(j, IRQF_VALID); + irq_clear_status_flags(j, IRQ_NOREQUEST); } omap_alloc_gc(irq_banks[i].va, irq_base + i * 32, 32); } diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c index d897292712eb..09b9a36049c7 100644 --- a/arch/arm/mach-pxa/balloon3.c +++ b/arch/arm/mach-pxa/balloon3.c @@ -528,7 +528,7 @@ static void __init balloon3_init_irq(void) for (irq = BALLOON3_IRQ(0); irq <= BALLOON3_IRQ(7); irq++) { irq_set_chip_and_handler(irq, &balloon3_irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } irq_set_chained_handler(BALLOON3_AUX_NIRQ, balloon3_irq_handler); diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 98608c5575cb..9c10248fadcc 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -133,7 +133,6 @@ static int pxa_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_and_handler(virq, &pxa_internal_irq_chip, handle_level_irq); irq_set_chip_data(virq, base); - set_irq_flags(virq, IRQF_VALID); return 0; } diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c index eaee2c20b189..2670fb0c6a21 100644 --- a/arch/arm/mach-pxa/lpd270.c +++ b/arch/arm/mach-pxa/lpd270.c @@ -151,7 +151,7 @@ static void __init lpd270_init_irq(void) for (irq = LPD270_IRQ(2); irq <= LPD270_IRQ(4); irq++) { irq_set_chip_and_handler(irq, &lpd270_irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } irq_set_chained_handler(PXA_GPIO_TO_IRQ(0), lpd270_irq_handler); irq_set_irq_type(PXA_GPIO_TO_IRQ(0), IRQ_TYPE_EDGE_FALLING); diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c index 2897da2a5df6..86e01bfc65b5 100644 --- a/arch/arm/mach-pxa/pcm990-baseboard.c +++ b/arch/arm/mach-pxa/pcm990-baseboard.c @@ -311,7 +311,7 @@ static void __init pcm990_init_irq(void) for (irq = PCM027_IRQ(0); irq <= PCM027_IRQ(3); irq++) { irq_set_chip_and_handler(irq, &pcm990_irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } /* disable all Interrupts */ diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index bd4cbef15ccf..e1362c0eeafc 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -325,7 +325,7 @@ static void __init pxa_init_ext_wakeup_irq(int (*fn)(struct irq_data *, for (irq = IRQ_WAKEUP0; irq <= IRQ_WAKEUP1; irq++) { irq_set_chip_and_handler(irq, &pxa_ext_wakeup_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID); + irq_clear_status_flags(irq, IRQ_NOREQUEST); } pxa_ext_wakeup_chip.irq_set_wake = fn; diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c index de3b08073fe7..dae3de8ce58c 100644 --- a/arch/arm/mach-pxa/viper.c +++ b/arch/arm/mach-pxa/viper.c @@ -313,7 +313,7 @@ static void __init viper_init_irq(void) isa_irq = viper_bit_to_irq(level); irq_set_chip_and_handler(isa_irq, &viper_irq_chip, handle_edge_irq); - set_irq_flags(isa_irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(isa_irq, IRQ_NOREQUEST | IRQ_NOPROBE); } irq_set_chained_handler(gpio_to_irq(VIPER_CPLD_GPIO), diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index ac2ae5c71ab4..48dd5bd64d77 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -151,7 +151,7 @@ static void __init zeus_init_irq(void) isa_irq = zeus_bit_to_irq(level); irq_set_chip_and_handler(isa_irq, &zeus_irq_chip, handle_edge_irq); - set_irq_flags(isa_irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(isa_irq, IRQ_NOREQUEST | IRQ_NOPROBE); } irq_set_irq_type(gpio_to_irq(ZEUS_ISA_GPIO), IRQ_TYPE_EDGE_RISING); diff --git a/arch/arm/mach-rpc/ecard.c b/arch/arm/mach-rpc/ecard.c index fcb1d59f7aec..f726d4c4e6dd 100644 --- a/arch/arm/mach-rpc/ecard.c +++ b/arch/arm/mach-rpc/ecard.c @@ -946,7 +946,7 @@ static int __init ecard_probe(int slot, unsigned irq, card_type_t type) irq_set_chip_and_handler(ec->irq, &ecard_chip, handle_level_irq); irq_set_chip_data(ec->irq, ec); - set_irq_flags(ec->irq, IRQF_VALID); + irq_clear_status_flags(ec->irq, IRQ_NOREQUEST); } #ifdef CONFIG_ARCH_RPC diff --git a/arch/arm/mach-rpc/irq.c b/arch/arm/mach-rpc/irq.c index 3e4fa849c64d..66502e6207fe 100644 --- a/arch/arm/mach-rpc/irq.c +++ b/arch/arm/mach-rpc/irq.c @@ -117,7 +117,7 @@ extern unsigned char rpc_default_fiq_start, rpc_default_fiq_end; void __init rpc_init_irq(void) { - unsigned int irq, flags; + unsigned int irq, clr, set = 0; iomd_writeb(0, IOMD_IRQMASKA); iomd_writeb(0, IOMD_IRQMASKB); @@ -128,37 +128,37 @@ void __init rpc_init_irq(void) &rpc_default_fiq_end - &rpc_default_fiq_start); for (irq = 0; irq < NR_IRQS; irq++) { - flags = IRQF_VALID; + clr = IRQ_NOREQUEST; if (irq <= 6 || (irq >= 9 && irq <= 15)) - flags |= IRQF_PROBE; + clr |= IRQ_NOPROBE; if (irq == 21 || (irq >= 16 && irq <= 19) || irq == IRQ_KEYBOARDTX) - flags |= IRQF_NOAUTOEN; + set |= IRQ_NOAUTOEN; switch (irq) { case 0 ... 7: irq_set_chip_and_handler(irq, &iomd_a_chip, handle_level_irq); - set_irq_flags(irq, flags); + irq_modify_status(irq, clr, set); break; case 8 ... 15: irq_set_chip_and_handler(irq, &iomd_b_chip, handle_level_irq); - set_irq_flags(irq, flags); + irq_modify_status(irq, clr, set); break; case 16 ... 21: irq_set_chip_and_handler(irq, &iomd_dma_chip, handle_level_irq); - set_irq_flags(irq, flags); + irq_modify_status(irq, clr, set); break; case 64 ... 71: irq_set_chip(irq, &iomd_fiq_chip); - set_irq_flags(irq, IRQF_VALID); + irq_modify_status(irq, clr, set); break; } } diff --git a/arch/arm/mach-s3c24xx/bast-irq.c b/arch/arm/mach-s3c24xx/bast-irq.c index cb1b791954de..ced1ab86ac83 100644 --- a/arch/arm/mach-s3c24xx/bast-irq.c +++ b/arch/arm/mach-s3c24xx/bast-irq.c @@ -147,7 +147,7 @@ static __init int bast_irq_init(void) irq_set_chip_and_handler(irqno, &bast_pc104_chip, handle_level_irq); - set_irq_flags(irqno, IRQF_VALID); + irq_clear_status_flags(irqno, IRQ_NOREQUEST); } } diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c index 16547f2641a3..06ba9438c262 100644 --- a/arch/arm/mach-s3c64xx/common.c +++ b/arch/arm/mach-s3c64xx/common.c @@ -420,7 +420,7 @@ static int __init s3c64xx_init_irq_eint(void) for (irq = IRQ_EINT(0); irq <= IRQ_EINT(27); irq++) { irq_set_chip_and_handler(irq, &s3c_irq_eint, handle_level_irq); irq_set_chip_data(irq, (void *)eint_irq_to_bit(irq)); - set_irq_flags(irq, IRQF_VALID); + irq_clear_status_flags(irq, IRQ_NOREQUEST); } irq_set_chained_handler(IRQ_EINT0_3, s3c_irq_demux_eint0_3); diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index 99d9a3b1bf34..6d237b4f7a8e 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -320,10 +320,10 @@ static int neponset_probe(struct platform_device *dev) irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip, handle_simple_irq); - set_irq_flags(d->irq_base + NEP_IRQ_SMC91X, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(d->irq_base + NEP_IRQ_SMC91X, IRQ_NOREQUEST | IRQ_NOPROBE); irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip, handle_simple_irq); - set_irq_flags(d->irq_base + NEP_IRQ_USAR, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(d->irq_base + NEP_IRQ_USAR, IRQ_NOREQUEST | IRQ_NOPROBE); irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip); irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); diff --git a/arch/arm/mach-w90x900/irq.c b/arch/arm/mach-w90x900/irq.c index d66d43ae8df5..491b317daffa 100644 --- a/arch/arm/mach-w90x900/irq.c +++ b/arch/arm/mach-w90x900/irq.c @@ -211,6 +211,6 @@ void __init nuc900_init_irq(void) for (irqno = IRQ_WDT; irqno <= IRQ_ADC; irqno++) { irq_set_chip_and_handler(irqno, &nuc900_irq_chip, handle_level_irq); - set_irq_flags(irqno, IRQF_VALID); + irq_clear_status_flags(irqno, IRQ_NOREQUEST); } } diff --git a/drivers/irqchip/irq-sa11x0.c b/drivers/irqchip/irq-sa11x0.c index 46df2875dc1c..61bb28d7b19b 100644 --- a/drivers/irqchip/irq-sa11x0.c +++ b/drivers/irqchip/irq-sa11x0.c @@ -70,7 +70,6 @@ static int sa1100_normal_irqdomain_map(struct irq_domain *d, { irq_set_chip_and_handler(irq, &sa1100_normal_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); return 0; } -- cgit v1.3-6-gb490 From 48356aa79ccb3df36f654d8f622256052bb2bb65 Mon Sep 17 00:00:00 2001 From: Wei Chen Date: Mon, 27 Jul 2015 11:57:25 +0000 Subject: pinctrl: sirf: add power management support for atlas7 We had not implemented the pm interface of atlas7 pinctrl and gpio drivers. So when system resumes from sleep, all pin configuration and gpio status will be lost. Now, we implement these interfaces to support pm. At the same time, this patch also drops a lot of if-else by look-up table for getting and setting pull. Signed-off-by: Wei Chen Signed-off-by: Barry Song Signed-off-by: Linus Walleij --- drivers/pinctrl/sirf/pinctrl-atlas7.c | 392 ++++++++++++++++++++++++++++------ 1 file changed, 325 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c index 0cd945c3af67..d16e62996e05 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas7.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c @@ -148,6 +148,19 @@ enum altas7_pad_type { #define DIV_DISABLE 0x1 #define DIV_ENABLE 0x0 +/* Number of Function input disable registers */ +#define NUM_OF_IN_DISABLE_REG 0x2 + +/* Offset of Function input disable registers */ +#define IN_DISABLE_0_REG_SET 0x0A00 +#define IN_DISABLE_0_REG_CLR 0x0A04 +#define IN_DISABLE_1_REG_SET 0x0A08 +#define IN_DISABLE_1_REG_CLR 0x0A0C +#define IN_DISABLE_VAL_0_REG_SET 0x0A80 +#define IN_DISABLE_VAL_0_REG_CLR 0x0A84 +#define IN_DISABLE_VAL_1_REG_SET 0x0A88 +#define IN_DISABLE_VAL_1_REG_CLR 0x0A8C + struct dt_params { const char *property; int value; @@ -196,6 +209,16 @@ struct atlas7_pad_config { .ad_ctrl_bit = adb, \ } +/** + * struct atlas7_pad_status - Atlas7 Pad status + */ +struct atlas7_pad_status { + u8 func; + u8 pull; + u8 dstr; + u8 reserved; +}; + /** * struct atlas7_pad_mux - Atlas7 mux * @bank: The bank of this pad's registers on. @@ -285,6 +308,9 @@ struct atlas7_pinctrl_data { /* Platform info of atlas7 pinctrl */ #define ATLAS7_PINCTRL_REG_BANKS 2 #define ATLAS7_PINCTRL_BANK_0_PINS 18 +#define ATLAS7_PINCTRL_BANK_1_PINS 141 +#define ATLAS7_PINCTRL_TOTAL_PINS \ + (ATLAS7_PINCTRL_BANK_0_PINS + ATLAS7_PINCTRL_BANK_1_PINS) /** * Atlas7 GPIO Chip @@ -316,6 +342,7 @@ struct atlas7_gpio_bank { unsigned int gpio_offset; unsigned int ngpio; const unsigned int *gpio_pins; + u32 sleep_data[NGPIO_OF_BANK]; }; struct atlas7_gpio_chip { @@ -343,6 +370,9 @@ struct atlas7_pmx { struct pinctrl_desc pctl_desc; struct atlas7_pinctrl_data *pctl_data; void __iomem *regs[ATLAS7_PINCTRL_REG_BANKS]; + u32 status_ds[NUM_OF_IN_DISABLE_REG]; + u32 status_dsv[NUM_OF_IN_DISABLE_REG]; + struct atlas7_pad_status sleep_data[ATLAS7_PINCTRL_TOTAL_PINS]; }; /* @@ -3480,6 +3510,93 @@ struct atlas7_pinctrl_data atlas7_ioc_data = { .confs_cnt = ARRAY_SIZE(atlas7_ioc_pad_confs), }; +struct map_data { + u8 idx; + u8 data; +}; + +struct atlas7_pull_info { + u8 pad_type; + u8 mask; + const struct map_data *v2s; + const struct map_data *s2v; +}; + +/* Pull Register value map to status */ +static const struct map_data p4we_pull_v2s[] = { + { P4WE_PULL_UP, PULL_UP }, + { P4WE_HIGH_HYSTERESIS, HIGH_HYSTERESIS }, + { P4WE_HIGH_Z, HIGH_Z }, + { P4WE_PULL_DOWN, PULL_DOWN }, +}; + +static const struct map_data p16st_pull_v2s[] = { + { P16ST_PULL_UP, PULL_UP }, + { PD, PULL_UNKNOWN }, + { P16ST_HIGH_Z, HIGH_Z }, + { P16ST_PULL_DOWN, PULL_DOWN }, +}; + +static const struct map_data pm31_pull_v2s[] = { + { PM31_PULL_DISABLED, PULL_DOWN }, + { PM31_PULL_ENABLED, PULL_UP }, +}; + +static const struct map_data pangd_pull_v2s[] = { + { PANGD_PULL_UP, PULL_UP }, + { PD, PULL_UNKNOWN }, + { PANGD_HIGH_Z, HIGH_Z }, + { PANGD_PULL_DOWN, PULL_DOWN }, +}; + +/* Pull status map to register value */ +static const struct map_data p4we_pull_s2v[] = { + { PULL_UP, P4WE_PULL_UP }, + { HIGH_HYSTERESIS, P4WE_HIGH_HYSTERESIS }, + { HIGH_Z, P4WE_HIGH_Z }, + { PULL_DOWN, P4WE_PULL_DOWN }, + { PULL_DISABLE, -1 }, + { PULL_ENABLE, -1 }, +}; + +static const struct map_data p16st_pull_s2v[] = { + { PULL_UP, P16ST_PULL_UP }, + { HIGH_HYSTERESIS, -1 }, + { HIGH_Z, P16ST_HIGH_Z }, + { PULL_DOWN, P16ST_PULL_DOWN }, + { PULL_DISABLE, -1 }, + { PULL_ENABLE, -1 }, +}; + +static const struct map_data pm31_pull_s2v[] = { + { PULL_UP, PM31_PULL_ENABLED }, + { HIGH_HYSTERESIS, -1 }, + { HIGH_Z, -1 }, + { PULL_DOWN, PM31_PULL_DISABLED }, + { PULL_DISABLE, -1 }, + { PULL_ENABLE, -1 }, +}; + +static const struct map_data pangd_pull_s2v[] = { + { PULL_UP, PANGD_PULL_UP }, + { HIGH_HYSTERESIS, -1 }, + { HIGH_Z, PANGD_HIGH_Z }, + { PULL_DOWN, PANGD_PULL_DOWN }, + { PULL_DISABLE, -1 }, + { PULL_ENABLE, -1 }, +}; + +static const struct atlas7_pull_info atlas7_pull_map[] = { + { PAD_T_4WE_PD, P4WE_PULL_MASK, p4we_pull_v2s, p4we_pull_s2v }, + { PAD_T_4WE_PU, P4WE_PULL_MASK, p4we_pull_v2s, p4we_pull_s2v }, + { PAD_T_16ST, P16ST_PULL_MASK, p16st_pull_v2s, p16st_pull_s2v }, + { PAD_T_M31_0204_PD, PM31_PULL_MASK, pm31_pull_v2s, pm31_pull_s2v }, + { PAD_T_M31_0204_PU, PM31_PULL_MASK, pm31_pull_v2s, pm31_pull_s2v }, + { PAD_T_M31_0610_PD, PM31_PULL_MASK, pm31_pull_v2s, pm31_pull_s2v }, + { PAD_T_M31_0610_PU, PM31_PULL_MASK, pm31_pull_v2s, pm31_pull_s2v }, + { PAD_T_AD, PANGD_PULL_MASK, pangd_pull_v2s, pangd_pull_s2v }, +}; + static inline u32 atlas7_pin_to_bank(u32 pin) { return (pin >= ATLAS7_PINCTRL_BANK_0_PINS) ? 1 : 0; @@ -3730,83 +3847,44 @@ static u32 convert_current_to_drive_strength(u32 type, u32 ma) return DS_NULL; } +static u32 altas7_pinctrl_get_pull_sel(struct atlas7_pmx *pmx, u32 pin) +{ + struct atlas7_pad_config *conf = &pmx->pctl_data->confs[pin]; + const struct atlas7_pull_info *pull_info; + int bank; + unsigned long regv; + + bank = atlas7_pin_to_bank(pin); + pull_info = &atlas7_pull_map[conf->type]; + + regv = readl(pmx->regs[bank] + conf->pupd_reg); + regv = (regv >> conf->pupd_bit) & pull_info->mask; + + return pull_info->v2s[regv].data; +} + static int altas7_pinctrl_set_pull_sel(struct pinctrl_dev *pctldev, u32 pin, u32 sel) { struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); struct atlas7_pad_config *conf = &pmx->pctl_data->confs[pin]; - u32 type = conf->type; - u32 shift = conf->pupd_bit; - u32 bank = atlas7_pin_to_bank(pin); + const struct atlas7_pull_info *pull_info; + u32 bank; + unsigned long regv; void __iomem *pull_sel_reg, *pull_clr_reg; + bank = atlas7_pin_to_bank(pin); + pull_info = &atlas7_pull_map[conf->type]; + pull_sel_reg = pmx->regs[bank] + conf->pupd_reg; pull_clr_reg = CLR_REG(pull_sel_reg); - if (type == PAD_T_4WE_PD || type == PAD_T_4WE_PU) { - writel(P4WE_PULL_MASK << shift, pull_clr_reg); - - if (sel == PULL_UP) - writel(P4WE_PULL_UP << shift, pull_sel_reg); - else if (sel == HIGH_HYSTERESIS) - writel(P4WE_HIGH_HYSTERESIS << shift, pull_sel_reg); - else if (sel == HIGH_Z) - writel(P4WE_HIGH_Z << shift, pull_sel_reg); - else if (sel == PULL_DOWN) - writel(P4WE_PULL_DOWN << shift, pull_sel_reg); - else { - pr_err("Unknown Pull select type for 4WEPAD#%d\n", - pin); - return -ENOTSUPP; - } - } else if (type == PAD_T_16ST) { - writel(P16ST_PULL_MASK << shift, pull_clr_reg); - - if (sel == PULL_UP) - writel(P16ST_PULL_UP << shift, pull_sel_reg); - else if (sel == HIGH_Z) - writel(P16ST_HIGH_Z << shift, pull_sel_reg); - else if (sel == PULL_DOWN) - writel(P16ST_PULL_DOWN << shift, pull_sel_reg); - else { - pr_err("Unknown Pull select type for 16STPAD#%d\n", - pin); - return -ENOTSUPP; - } - } else if (type == PAD_T_M31_0204_PD || - type == PAD_T_M31_0204_PU || - type == PAD_T_M31_0610_PD || - type == PAD_T_M31_0610_PU) { - writel(PM31_PULL_MASK << shift, pull_clr_reg); - - if (sel == PULL_UP) - writel(PM31_PULL_ENABLED << shift, pull_sel_reg); - else if (sel == PULL_DOWN) - writel(PM31_PULL_DISABLED << shift, pull_sel_reg); - else { - pr_err("Unknown Pull select type for M31PAD#%d\n", - pin); - return -ENOTSUPP; - } - } else if (type == PAD_T_AD) { - writel(PANGD_PULL_MASK << shift, pull_clr_reg); - - if (sel == PULL_UP) - writel(PANGD_PULL_UP << shift, pull_sel_reg); - else if (sel == HIGH_Z) - writel(PANGD_HIGH_Z << shift, pull_sel_reg); - else if (sel == PULL_DOWN) - writel(PANGD_PULL_DOWN << shift, pull_sel_reg); - else { - pr_err("Unknown Pull select type for A/D PAD#%d\n", - pin); - return -ENOTSUPP; - } - } else { - pr_err("Unknown Pad type[%d] for pull select PAD#%d\n", - type, pin); - return -ENOTSUPP; - } + /* Retrieve correspond register value from table by sel */ + regv = pull_info->s2v[sel].data & pull_info->mask; + + /* Clear & Set new value to pull register */ + writel(pull_info->mask << conf->pupd_bit, pull_clr_reg); + writel(regv << conf->pupd_bit, pull_sel_reg); pr_debug("PIN_CFG ### SET PIN#%d PULL SELECTOR:%d == OK ####\n", pin, sel); @@ -4101,14 +4179,144 @@ unmap_io: return ret; } +#ifdef CONFIG_PM_SLEEP +static int atlas7_pinmux_suspend_noirq(struct device *dev) +{ + struct atlas7_pmx *pmx = dev_get_drvdata(dev); + struct atlas7_pad_status *status; + struct atlas7_pad_config *conf; + int idx; + u32 bank; + unsigned long regv; + + for (idx = 0; idx < pmx->pctl_desc.npins; idx++) { + /* Get this Pad's descriptor from PINCTRL */ + conf = &pmx->pctl_data->confs[idx]; + bank = atlas7_pin_to_bank(idx); + status = &pmx->sleep_data[idx]; + + /* Save Function selector */ + regv = readl(pmx->regs[bank] + conf->mux_reg); + status->func = (regv >> conf->mux_bit) & FUNC_CLEAR_MASK; + + /* Check if Pad is in Analogue selector */ + if (conf->ad_ctrl_reg == -1) + goto save_ds_sel; + + regv = readl(pmx->regs[bank] + conf->ad_ctrl_reg); + if (!(regv & (conf->ad_ctrl_bit << ANA_CLEAR_MASK))) + status->func = FUNC_ANALOGUE; + +save_ds_sel: + if (conf->drvstr_reg == -1) + goto save_pull_sel; + + /* Save Drive Strength selector */ + regv = readl(pmx->regs[bank] + conf->drvstr_reg); + if (PAD_T_4WE_PD == conf->type || PAD_T_4WE_PU == conf->type) + status->dstr = (regv >> conf->drvstr_bit) & + DS_2BIT_MASK; + else if (PAD_T_16ST == conf->type) + status->dstr = (regv >> conf->drvstr_bit) & + DS_4BIT_MASK; + else if (PAD_T_M31_0204_PD == conf->type || + PAD_T_M31_0204_PU == conf->type || + PAD_T_M31_0610_PD == conf->type || + PAD_T_M31_0610_PU == conf->type) + status->dstr = (regv >> conf->drvstr_bit) & + DS_1BIT_MASK; + +save_pull_sel: + /* Save Pull selector */ + regv = readl(pmx->regs[bank] + conf->pupd_reg); + status->pull = altas7_pinctrl_get_pull_sel(pmx, idx); + pr_debug("idx %d %p %x: %x %x %x\n", idx, + pmx->regs[bank], conf->mux_reg, + status->func, status->pull, status->dstr); + } + + /* + * Save disable input selector, this selector is not for Pin, + * but for Mux function. + */ + for (idx = 0; idx < NUM_OF_IN_DISABLE_REG; idx++) { + pmx->status_ds[idx] = readl(pmx->regs[BANK_DS] + + IN_DISABLE_0_REG_SET + 0x8 * idx); + pmx->status_dsv[idx] = readl(pmx->regs[BANK_DS] + + IN_DISABLE_VAL_0_REG_SET + 0x8 * idx); + } + + return 0; +} + +static int atlas7_pinmux_resume_noirq(struct device *dev) +{ + struct atlas7_pmx *pmx = dev_get_drvdata(dev); + struct atlas7_pad_status *status; + struct atlas7_pad_config *conf; + int idx; + u32 bank; + + for (idx = 0; idx < pmx->pctl_desc.npins; idx++) { + /* Get this Pad's descriptor from PINCTRL */ + conf = &pmx->pctl_data->confs[idx]; + bank = atlas7_pin_to_bank(idx); + status = &pmx->sleep_data[idx]; + + /* Restore Function selector */ + __atlas7_pmx_pin_enable(pmx, idx, (u32)status->func & 0xff); + + if (FUNC_ANALOGUE == status->func) + goto restore_pull_sel; + + /* Restore Drive Strength selector */ + __altas7_pinctrl_set_drive_strength_sel(pmx->pctl, idx, + (u32)status->dstr & 0xff); + +restore_pull_sel: + /* Restore Pull selector */ + altas7_pinctrl_set_pull_sel(pmx->pctl, idx, + (u32)status->pull & 0xff); + } + + /* + * Restore disable input selector, this selector is not for Pin, + * but for Mux function + */ + for (idx = 0; idx < NUM_OF_IN_DISABLE_REG; idx++) { + writel(~0, pmx->regs[BANK_DS] + + IN_DISABLE_0_REG_CLR + 0x8 * idx); + writel(pmx->status_ds[idx], pmx->regs[BANK_DS] + + IN_DISABLE_0_REG_SET + 0x8 * idx); + writel(~0, pmx->regs[BANK_DS] + + IN_DISABLE_VAL_0_REG_CLR + 0x8 * idx); + writel(pmx->status_dsv[idx], pmx->regs[BANK_DS] + + IN_DISABLE_VAL_0_REG_SET + 0x8 * idx); + } + + return 0; +} + +static const struct dev_pm_ops atlas7_pinmux_pm_ops = { + .suspend_noirq = atlas7_pinmux_suspend_noirq, + .resume_noirq = atlas7_pinmux_resume_noirq, + .freeze_noirq = atlas7_pinmux_suspend_noirq, + .restore_noirq = atlas7_pinmux_resume_noirq, +}; +#endif + static const struct of_device_id atlas7_pinmux_ids[] = { { .compatible = "sirf,atlas7-ioc",}, + {}, }; static struct platform_driver atlas7_pinmux_driver = { .driver = { .name = "atlas7-ioc", .of_match_table = atlas7_pinmux_ids, +#ifdef CONFIG_PM_SLEEP + .pm = &atlas7_pinmux_pm_ops, +#endif }, .probe = atlas7_pinmux_probe, }; @@ -4497,6 +4705,7 @@ static void atlas7_gpio_set_value(struct gpio_chip *chip, static const struct of_device_id atlas7_gpio_ids[] = { { .compatible = "sirf,atlas7-gpio", }, + {}, }; static int atlas7_gpio_probe(struct platform_device *pdev) @@ -4613,16 +4822,65 @@ static int atlas7_gpio_probe(struct platform_device *pdev) BUG_ON(!bank->pctldev); } + platform_set_drvdata(pdev, a7gc); dev_info(&pdev->dev, "add to system.\n"); return 0; failed: return ret; } +#ifdef CONFIG_PM_SLEEP +static int atlas7_gpio_suspend_noirq(struct device *dev) +{ + struct atlas7_gpio_chip *a7gc = dev_get_drvdata(dev); + struct atlas7_gpio_bank *bank; + void __iomem *ctrl_reg; + u32 idx, pin; + + for (idx = 0; idx < a7gc->nbank; idx++) { + bank = &a7gc->banks[idx]; + for (pin = 0; pin < bank->ngpio; pin++) { + ctrl_reg = ATLAS7_GPIO_CTRL(bank, pin); + bank->sleep_data[pin] = readl(ctrl_reg); + } + } + + return 0; +} + +static int atlas7_gpio_resume_noirq(struct device *dev) +{ + struct atlas7_gpio_chip *a7gc = dev_get_drvdata(dev); + struct atlas7_gpio_bank *bank; + void __iomem *ctrl_reg; + u32 idx, pin; + + for (idx = 0; idx < a7gc->nbank; idx++) { + bank = &a7gc->banks[idx]; + for (pin = 0; pin < bank->ngpio; pin++) { + ctrl_reg = ATLAS7_GPIO_CTRL(bank, pin); + writel(bank->sleep_data[pin], ctrl_reg); + } + } + + return 0; +} + +static const struct dev_pm_ops atlas7_gpio_pm_ops = { + .suspend_noirq = atlas7_gpio_suspend_noirq, + .resume_noirq = atlas7_gpio_resume_noirq, + .freeze_noirq = atlas7_gpio_suspend_noirq, + .restore_noirq = atlas7_gpio_resume_noirq, +}; +#endif + static struct platform_driver atlas7_gpio_driver = { .driver = { .name = "atlas7-gpio", .of_match_table = atlas7_gpio_ids, +#ifdef CONFIG_PM_SLEEP + .pm = &atlas7_gpio_pm_ops, +#endif }, .probe = atlas7_gpio_probe, }; -- cgit v1.3-6-gb490 From 505936131ea71ec998344355f7e5e8af8d6b15dc Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 21 Jul 2015 15:54:30 +0200 Subject: gpio: mpc8xxx: Convert mpc8xxx_gpio_chip.lock to raw_spinlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mpc8xxx_gpio_chip.lock needs to be a real spinlock in preempt-rt. Especially the interrupt related functions can not be converted to a sleeping lock. Signed-off-by: Alexander Stein Acked-by: Uwe Kleine-König Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 48 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 4c5137793431..8ef7a12de983 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -32,7 +32,7 @@ struct mpc8xxx_gpio_chip { struct of_mm_gpio_chip mm_gc; - spinlock_t lock; + raw_spinlock_t lock; /* * shadowed data register to be able to clear/set output pins in @@ -95,7 +95,7 @@ static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); if (val) mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio); @@ -104,7 +104,7 @@ static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc, @@ -115,7 +115,7 @@ static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc, unsigned long flags; int i; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); for (i = 0; i < gc->ngpio; i++) { if (*mask == 0) @@ -130,7 +130,7 @@ static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc, out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) @@ -139,11 +139,11 @@ static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); return 0; } @@ -156,11 +156,11 @@ static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val mpc8xxx_gpio_set(gc, gpio, val); - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); return 0; } @@ -215,11 +215,11 @@ static void mpc8xxx_irq_unmask(struct irq_data *d) struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static void mpc8xxx_irq_mask(struct irq_data *d) @@ -228,11 +228,11 @@ static void mpc8xxx_irq_mask(struct irq_data *d) struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static void mpc8xxx_irq_ack(struct irq_data *d) @@ -251,17 +251,17 @@ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) switch (flow_type) { case IRQ_TYPE_EDGE_FALLING: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); setbits32(mm->regs + GPIO_ICR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; case IRQ_TYPE_EDGE_BOTH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(mm->regs + GPIO_ICR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; default: @@ -291,22 +291,22 @@ static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type) switch (flow_type) { case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_LEVEL_LOW: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrsetbits_be32(reg, 3 << shift, 2 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_LEVEL_HIGH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrsetbits_be32(reg, 3 << shift, 1 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; case IRQ_TYPE_EDGE_BOTH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(reg, 3 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; default: @@ -393,7 +393,7 @@ static int mpc8xxx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mpc8xxx_gc); - spin_lock_init(&mpc8xxx_gc->lock); + raw_spin_lock_init(&mpc8xxx_gc->lock); mm_gc = &mpc8xxx_gc->mm_gc; gc = &mm_gc->gc; -- cgit v1.3-6-gb490 From 6c24695988774d56ea8d6a47ffdaf0fd32072488 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 27 Jul 2015 10:26:26 +0100 Subject: drm/i915: Keep the mm.bound_list in rough LRU order When we shrink our working sets, we want to avoid stealing pages from objects that likely to be reused in the near future. We first look at inactive objects before processing active objects - but what about a recently active object that is about to be used again. That object's position in the bound_list is ordered by the time of binding, not the time of last use, so the most recently used inactive object could well be at the head of the shrink list. To compensate, give the object a bump to MRU when it becomes inactive (thus transitioning to the end of the first pass in shrink lists). Conversely, bumping on inactive makes bumping on active useless, since when we do have to reap from the active working set, everything is going to become inactive very quickly and the order pretty much random - just hope for the best at that point, as once we start stalling on active objects, we can hope that the rebinding neatly orders vital objects. Suggested-by: Daniel Vetter Signed-off-by: Chris Wilson Cc: Daniel Vetter [danvet: Resolve merge conflict.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5d685789b1f9..84f91bcc12f7 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2385,6 +2385,13 @@ i915_gem_object_retire__read(struct drm_i915_gem_object *obj, int ring) if (obj->active) return; + /* Bump our place on the bound list to keep it roughly in LRU order + * so that we don't steal from recently used but inactive objects + * (unless we are forced to ofc!) + */ + list_move_tail(&obj->global_list, + &to_i915(obj->base.dev)->mm.bound_list); + list_for_each_entry(vma, &obj->vma_list, vma_link) { if (!list_empty(&vma->mm_list)) list_move_tail(&vma->mm_list, &vma->vm->inactive_list); -- cgit v1.3-6-gb490 From ed425dcf6afa2b206f6da7d7ec6a62501172b5c0 Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Fri, 24 Jul 2015 17:36:49 +0200 Subject: spi: s3c64xx: print fifo size on probe. Printing the FIFO depth does not add much noise in the log and can be useful for debugging transfer issues. Signed-off-by: Michal Suchanek Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 2a8c513c4d07..cd1cfac0447f 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1191,8 +1191,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n", sdd->port_id, master->num_chipselect); - dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tDMA=[Rx-%d, Tx-%d]\n", - mem_res, + dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\tDMA=[Rx-%d, Tx-%d]\n", + mem_res, (FIFO_LVL_MASK(sdd) >> 1) + 1, sdd->rx_dma.dmach, sdd->tx_dma.dmach); return 0; -- cgit v1.3-6-gb490 From 15c0b4d222f83672407419f9c9e167e996d8ad2b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 27 Jul 2015 23:11:09 +0200 Subject: cpufreq: Rework two functions related to CPU offline Since __cpufreq_remove_dev_prepare() and __cpufreq_remove_dev_finish() are about CPU offline rather than about CPU removal, rename them to cpufreq_offline_prepare() and cpufreq_offline_finish(), respectively. Also change their argument from a struct device pointer to a CPU number, because they use the CPU number only internally anyway and make them void as their return values are ignored. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 46251e8d30f2..29e3ec979266 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1398,10 +1398,8 @@ out_release_rwsem: return ret; } -static int __cpufreq_remove_dev_prepare(struct device *dev) +static void cpufreq_offline_prepare(unsigned int cpu) { - unsigned int cpu = dev->id; - int ret = 0; struct cpufreq_policy *policy; pr_debug("%s: unregistering CPU %u\n", __func__, cpu); @@ -1409,11 +1407,11 @@ static int __cpufreq_remove_dev_prepare(struct device *dev) policy = cpufreq_cpu_get_raw(cpu); if (!policy) { pr_debug("%s: No cpu_data found\n", __func__); - return -EINVAL; + return; } if (has_target()) { - ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + int ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); if (ret) pr_err("%s: Failed to stop governor\n", __func__); } @@ -1434,7 +1432,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev) /* Start governor again for active policy */ if (!policy_is_inactive(policy)) { if (has_target()) { - ret = __cpufreq_governor(policy, CPUFREQ_GOV_START); + int ret = __cpufreq_governor(policy, CPUFREQ_GOV_START); if (!ret) ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS); @@ -1444,28 +1442,24 @@ static int __cpufreq_remove_dev_prepare(struct device *dev) } else if (cpufreq_driver->stop_cpu) { cpufreq_driver->stop_cpu(policy); } - - return ret; } -static int __cpufreq_remove_dev_finish(struct device *dev) +static void cpufreq_offline_finish(unsigned int cpu) { - unsigned int cpu = dev->id; - int ret; struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); if (!policy) { pr_debug("%s: No cpu_data found\n", __func__); - return -EINVAL; + return; } /* Only proceed for inactive policies */ if (!policy_is_inactive(policy)) - return 0; + return; /* If cpu is last user of policy, free policy */ if (has_target()) { - ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); + int ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); if (ret) pr_err("%s: Failed to exit governor\n", __func__); } @@ -1477,8 +1471,6 @@ static int __cpufreq_remove_dev_finish(struct device *dev) */ if (cpufreq_driver->exit) cpufreq_driver->exit(policy); - - return 0; } /** @@ -1495,8 +1487,8 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) return 0; if (cpu_online(cpu)) { - __cpufreq_remove_dev_prepare(dev); - __cpufreq_remove_dev_finish(dev); + cpufreq_offline_prepare(cpu); + cpufreq_offline_finish(cpu); } cpumask_clear_cpu(cpu, policy->real_cpus); @@ -2379,11 +2371,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, break; case CPU_DOWN_PREPARE: - __cpufreq_remove_dev_prepare(dev); + cpufreq_offline_prepare(cpu); break; case CPU_POST_DEAD: - __cpufreq_remove_dev_finish(dev); + cpufreq_offline_finish(cpu); break; case CPU_DOWN_FAILED: -- cgit v1.3-6-gb490 From 11ce707e6c2aea05e1f54680fb89a8a44ded5db4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 27 Jul 2015 23:11:21 +0200 Subject: cpufreq: Drop cpufreq_policy_restore() Notice that when cpufreq_policy_restore() is called, its per-CPU cpufreq_cpu_data variable has been already dereferenced and if that variable is not NULL, the policy local pointer in cpufreq_add_dev() contains its value. Therefore it is not necessary to dereference it again and the policy pointer can be used directly. Moreover, if that pointer is not NULL, the policy is inactive (or the previous check would have made us return from cpufreq_add_dev()) so the restoration code from cpufreq_policy_restore() can be moved to that point in cpufreq_add_dev(). Do that and drop cpufreq_policy_restore(). Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 44 +++++++++++--------------------------------- 1 file changed, 11 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 29e3ec979266..3199b8dafd60 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1092,28 +1092,6 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu) -{ - struct cpufreq_policy *policy; - unsigned long flags; - - read_lock_irqsave(&cpufreq_driver_lock, flags); - policy = per_cpu(cpufreq_cpu_data, cpu); - read_unlock_irqrestore(&cpufreq_driver_lock, flags); - - if (likely(policy)) { - /* Policy should be inactive here */ - WARN_ON(!policy_is_inactive(policy)); - - down_write(&policy->rwsem); - policy->cpu = cpu; - policy->governor = NULL; - up_write(&policy->rwsem); - } - - return policy; -} - static struct cpufreq_policy *cpufreq_policy_alloc(struct device *dev) { struct cpufreq_policy *policy; @@ -1226,7 +1204,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) int ret = -ENOMEM; struct cpufreq_policy *policy; unsigned long flags; - bool recover_policy = !sif; + bool recover_policy; pr_debug("adding CPU %u\n", cpu); @@ -1244,18 +1222,18 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) /* Check if this CPU already has a policy to manage it */ policy = per_cpu(cpufreq_cpu_data, cpu); - if (policy && !policy_is_inactive(policy)) { + if (policy) { WARN_ON(!cpumask_test_cpu(cpu, policy->related_cpus)); - ret = cpufreq_add_policy_cpu(policy, cpu, dev); - return ret; - } + if (!policy_is_inactive(policy)) + return cpufreq_add_policy_cpu(policy, cpu, dev); - /* - * Restore the saved policy when doing light-weight init and fall back - * to the full init if that fails. - */ - policy = recover_policy ? cpufreq_policy_restore(cpu) : NULL; - if (!policy) { + /* This is the only online CPU for the policy. Start over. */ + recover_policy = true; + down_write(&policy->rwsem); + policy->cpu = cpu; + policy->governor = NULL; + up_write(&policy->rwsem); + } else { recover_policy = false; policy = cpufreq_policy_alloc(dev); if (!policy) -- cgit v1.3-6-gb490 From d4d854d6c7706e6a5cda297e350e3626d55e9bc9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 27 Jul 2015 23:11:30 +0200 Subject: cpufreq: Drop unnecessary label from cpufreq_add_dev() The leftover out_release_rwsem label in cpufreq_add_dev() is not necessary any more and confusing, so drop it. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3199b8dafd60..5c80502339a1 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1201,7 +1201,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy, bool notify) static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) { unsigned int j, cpu = dev->id; - int ret = -ENOMEM; + int ret; struct cpufreq_policy *policy; unsigned long flags; bool recover_policy; @@ -1237,7 +1237,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) recover_policy = false; policy = cpufreq_policy_alloc(dev); if (!policy) - goto out_release_rwsem; + return -ENOMEM; } cpumask_copy(policy->cpus, cpumask_of(cpu)); @@ -1372,7 +1372,6 @@ out_exit_policy: cpufreq_driver->exit(policy); out_free_policy: cpufreq_policy_free(policy, recover_policy); -out_release_rwsem: return ret; } -- cgit v1.3-6-gb490 From d9612a495b0bc93f5db0e0033fe4ee7abb7167c7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 27 Jul 2015 23:11:37 +0200 Subject: cpufreq: Drop unused dev argument from two functions The dev argument of cpufreq_add_policy_cpu() and cpufreq_add_dev_interface() is not used by any of them, so drop it. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 5c80502339a1..9d8f8cd64e58 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -999,8 +999,7 @@ static void cpufreq_remove_dev_symlink(struct cpufreq_policy *policy) } } -static int cpufreq_add_dev_interface(struct cpufreq_policy *policy, - struct device *dev) +static int cpufreq_add_dev_interface(struct cpufreq_policy *policy) { struct freq_attr **drv_attr; int ret = 0; @@ -1057,8 +1056,7 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy) return cpufreq_set_policy(policy, &new_policy); } -static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, - unsigned int cpu, struct device *dev) +static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu) { int ret = 0; @@ -1225,7 +1223,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) if (policy) { WARN_ON(!cpumask_test_cpu(cpu, policy->related_cpus)); if (!policy_is_inactive(policy)) - return cpufreq_add_policy_cpu(policy, cpu, dev); + return cpufreq_add_policy_cpu(policy, cpu); /* This is the only online CPU for the policy. Start over. */ recover_policy = true; @@ -1328,7 +1326,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) CPUFREQ_START, policy); if (!recover_policy) { - ret = cpufreq_add_dev_interface(policy, dev); + ret = cpufreq_add_dev_interface(policy); if (ret) goto out_exit_policy; blocking_notifier_call_chain(&cpufreq_policy_notifier_list, -- cgit v1.3-6-gb490 From 4d1f3a5bcb489cc6f7cbc128e0c292fed7868d32 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 27 Jul 2015 23:11:44 +0200 Subject: cpufreq: Do not update related_cpus on every policy activation The related_cpus mask includes CPUs whose cpufreq_cpu_data per-CPU pointers have been set the the given policy. Since those pointers are only set at the policy creation time and unset when the policy is deleted, the related_cpus should not be updated between those two operations. For this reason, avoid updating it whenever the first of the "related" CPUs goes online. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 9d8f8cd64e58..0ea4bb723760 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1251,12 +1251,12 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) down_write(&policy->rwsem); - /* related cpus should atleast have policy->cpus */ - cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); - - /* Remember which CPUs have been present at the policy creation time. */ - if (!recover_policy) + if (!recover_policy) { + /* related_cpus should at least include policy->cpus. */ + cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); + /* Remember CPUs present at the policy creation time. */ cpumask_and(policy->real_cpus, policy->cpus, cpu_present_mask); + } /* * affected cpus must always be the one, which are online. We aren't -- cgit v1.3-6-gb490 From a34e63b14486e98cf78c99bf8ef141de7508dbc2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 27 Jul 2015 23:11:50 +0200 Subject: cpufreq: Pass CPU number to cpufreq_policy_alloc() Change cpufreq_policy_alloc() to take a CPU number instead of a CPU device pointer as its argument, as it is the only function called by cpufreq_add_dev() taking a device pointer argument at this point. That will allow us to split the CPU online part from cpufreq_add_dev() more cleanly going forward. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0ea4bb723760..0618522d4863 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1090,11 +1090,15 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp return 0; } -static struct cpufreq_policy *cpufreq_policy_alloc(struct device *dev) +static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) { + struct device *dev = get_cpu_device(cpu); struct cpufreq_policy *policy; int ret; + if (WARN_ON(!dev)) + return NULL; + policy = kzalloc(sizeof(*policy), GFP_KERNEL); if (!policy) return NULL; @@ -1122,10 +1126,10 @@ static struct cpufreq_policy *cpufreq_policy_alloc(struct device *dev) init_completion(&policy->kobj_unregister); INIT_WORK(&policy->update, handle_update); - policy->cpu = dev->id; + policy->cpu = cpu; /* Set this once on allocation */ - policy->kobj_cpu = dev->id; + policy->kobj_cpu = cpu; return policy; @@ -1233,7 +1237,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) up_write(&policy->rwsem); } else { recover_policy = false; - policy = cpufreq_policy_alloc(dev); + policy = cpufreq_policy_alloc(cpu); if (!policy) return -ENOMEM; } -- cgit v1.3-6-gb490 From 053819e0bf8407746cc5febf7a4947bee50377b4 Mon Sep 17 00:00:00 2001 From: Shilpasri G Bhat Date: Thu, 16 Jul 2015 13:34:18 +0530 Subject: cpufreq: powernv: Handle throttling due to Pmax capping at chip level The On-Chip-Controller(OCC) can throttle cpu frequency by reducing the max allowed frequency for that chip if the chip exceeds its power or temperature limits. As Pmax capping is a chip level condition report this throttling behavior at chip level and also do not set the global 'throttled' on Pmax capping instead set the per-chip throttled variable. Report unthrottling if Pmax is restored after throttling. This patch adds a structure to store chip id and throttled state of the chip. Signed-off-by: Shilpasri G Bhat Reviewed-by: Preeti U Murthy Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/powernv-cpufreq.c | 59 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index ebef0d8279c7..d0c18c9ce1ff 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,13 @@ static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; static bool rebooting, throttled; +static struct chip { + unsigned int id; + bool throttled; +} *chips; + +static int nr_chips; + /* * Note: The set of pstates consists of contiguous integers, the * smallest of which is indicated by powernv_pstate_info.min, the @@ -301,22 +309,33 @@ static inline unsigned int get_nominal_index(void) static void powernv_cpufreq_throttle_check(unsigned int cpu) { unsigned long pmsr; - int pmsr_pmax, pmsr_lp; + int pmsr_pmax, pmsr_lp, i; pmsr = get_pmspr(SPRN_PMSR); + for (i = 0; i < nr_chips; i++) + if (chips[i].id == cpu_to_chip_id(cpu)) + break; + /* Check for Pmax Capping */ pmsr_pmax = (s8)PMSR_MAX(pmsr); if (pmsr_pmax != powernv_pstate_info.max) { - throttled = true; - pr_info("CPU %d Pmax is reduced to %d\n", cpu, pmsr_pmax); - pr_info("Max allowed Pstate is capped\n"); + if (chips[i].throttled) + goto next; + chips[i].throttled = true; + pr_info("CPU %d on Chip %u has Pmax reduced to %d\n", cpu, + chips[i].id, pmsr_pmax); + } else if (chips[i].throttled) { + chips[i].throttled = false; + pr_info("CPU %d on Chip %u has Pmax restored to %d\n", cpu, + chips[i].id, pmsr_pmax); } /* * Check for Psafe by reading LocalPstate * or check if Psafe_mode_active is set in PMSR. */ +next: pmsr_lp = (s8)PMSR_LP(pmsr); if ((pmsr_lp < powernv_pstate_info.min) || (pmsr & PMSR_PSAFE_ENABLE)) { @@ -414,6 +433,33 @@ static struct cpufreq_driver powernv_cpufreq_driver = { .attr = powernv_cpu_freq_attr, }; +static int init_chip_info(void) +{ + unsigned int chip[256]; + unsigned int cpu, i; + unsigned int prev_chip_id = UINT_MAX; + + for_each_possible_cpu(cpu) { + unsigned int id = cpu_to_chip_id(cpu); + + if (prev_chip_id != id) { + prev_chip_id = id; + chip[nr_chips++] = id; + } + } + + chips = kmalloc_array(nr_chips, sizeof(struct chip), GFP_KERNEL); + if (!chips) + return -ENOMEM; + + for (i = 0; i < nr_chips; i++) { + chips[i].id = chip[i]; + chips[i].throttled = false; + } + + return 0; +} + static int __init powernv_cpufreq_init(void) { int rc = 0; @@ -429,6 +475,11 @@ static int __init powernv_cpufreq_init(void) return rc; } + /* Populate chip info */ + rc = init_chip_info(); + if (rc) + return rc; + register_reboot_notifier(&powernv_cpufreq_reboot_nb); return cpufreq_register_driver(&powernv_cpufreq_driver); } -- cgit v1.3-6-gb490 From cb166fa937a2fbc14badcafca86202354c34a213 Mon Sep 17 00:00:00 2001 From: Shilpasri G Bhat Date: Thu, 16 Jul 2015 13:34:20 +0530 Subject: cpufreq: powernv: Register for OCC related opal_message notification OCC is an On-Chip-Controller which takes care of power and thermal safety of the chip. During runtime due to power failure or overtemperature the OCC may throttle the frequencies of the CPUs to remain within the power budget. We want the cpufreq driver to be aware of such situations to be able to report the reason to the user. We register to opal_message_notifier to receive OCC messages from opal. powernv_cpufreq_throttle_check() reports any frequency throttling and this patch will report the reason or event that caused throttling. We can be throttled if OCC is reset or OCC limits Pmax due to power or thermal reasons. We are also notified of unthrottling after an OCC reset or if OCC restores Pmax on the chip. Signed-off-by: Shilpasri G Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/powernv-cpufreq.c | 74 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index d0c18c9ce1ff..a634199052b6 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -33,6 +33,7 @@ #include #include #include /* Required for cpu_sibling_mask() in UP configs */ +#include #define POWERNV_MAX_PSTATES 256 #define PMSR_PSAFE_ENABLE (1UL << 30) @@ -41,7 +42,7 @@ #define PMSR_LP(x) ((x >> 48) & 0xFF) static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; -static bool rebooting, throttled; +static bool rebooting, throttled, occ_reset; static struct chip { unsigned int id; @@ -414,6 +415,74 @@ static struct notifier_block powernv_cpufreq_reboot_nb = { .notifier_call = powernv_cpufreq_reboot_notifier, }; +static char throttle_reason[][30] = { + "No throttling", + "Power Cap", + "Processor Over Temperature", + "Power Supply Failure", + "Over Current", + "OCC Reset" + }; + +static int powernv_cpufreq_occ_msg(struct notifier_block *nb, + unsigned long msg_type, void *_msg) +{ + struct opal_msg *msg = _msg; + struct opal_occ_msg omsg; + + if (msg_type != OPAL_MSG_OCC) + return 0; + + omsg.type = be64_to_cpu(msg->params[0]); + + switch (omsg.type) { + case OCC_RESET: + occ_reset = true; + /* + * powernv_cpufreq_throttle_check() is called in + * target() callback which can detect the throttle state + * for governors like ondemand. + * But static governors will not call target() often thus + * report throttling here. + */ + if (!throttled) { + throttled = true; + pr_crit("CPU Frequency is throttled\n"); + } + pr_info("OCC: Reset\n"); + break; + case OCC_LOAD: + pr_info("OCC: Loaded\n"); + break; + case OCC_THROTTLE: + omsg.chip = be64_to_cpu(msg->params[1]); + omsg.throttle_status = be64_to_cpu(msg->params[2]); + + if (occ_reset) { + occ_reset = false; + throttled = false; + pr_info("OCC: Active\n"); + return 0; + } + + if (omsg.throttle_status && + omsg.throttle_status <= OCC_MAX_THROTTLE_STATUS) + pr_info("OCC: Chip %u Pmax reduced due to %s\n", + (unsigned int)omsg.chip, + throttle_reason[omsg.throttle_status]); + else if (!omsg.throttle_status) + pr_info("OCC: Chip %u %s\n", (unsigned int)omsg.chip, + throttle_reason[omsg.throttle_status]); + } + return 0; +} + +static struct notifier_block powernv_cpufreq_opal_nb = { + .notifier_call = powernv_cpufreq_occ_msg, + .next = NULL, + .priority = 0, +}; + static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy) { struct powernv_smp_call_data freq_data; @@ -481,6 +550,7 @@ static int __init powernv_cpufreq_init(void) return rc; register_reboot_notifier(&powernv_cpufreq_reboot_nb); + opal_message_notifier_register(OPAL_MSG_OCC, &powernv_cpufreq_opal_nb); return cpufreq_register_driver(&powernv_cpufreq_driver); } module_init(powernv_cpufreq_init); @@ -488,6 +558,8 @@ module_init(powernv_cpufreq_init); static void __exit powernv_cpufreq_exit(void) { unregister_reboot_notifier(&powernv_cpufreq_reboot_nb); + opal_message_notifier_unregister(OPAL_MSG_OCC, + &powernv_cpufreq_opal_nb); cpufreq_unregister_driver(&powernv_cpufreq_driver); } module_exit(powernv_cpufreq_exit); -- cgit v1.3-6-gb490 From 735366fc407755626058218fc8d0430735a669ac Mon Sep 17 00:00:00 2001 From: Shilpasri G Bhat Date: Thu, 16 Jul 2015 13:34:21 +0530 Subject: cpufreq: powernv: Call throttle_check() on receiving OCC_THROTTLE Re-evaluate the chip's throttled state on recieving OCC_THROTTLE notification by executing *throttle_check() on any one of the cpu on the chip. This is a sanity check to verify if we were indeed throttled/unthrottled after receiving OCC_THROTTLE notification. We cannot call *throttle_check() directly from the notification handler because we could be handling chip1's notification in chip2. So initiate an smp_call to execute *throttle_check(). We are irq-disabled in the notification handler, so use a worker thread to smp_call throttle_check() on any of the cpu in the chipmask. Signed-off-by: Shilpasri G Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/powernv-cpufreq.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index a634199052b6..22f33ff2d77a 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -47,6 +47,8 @@ static bool rebooting, throttled, occ_reset; static struct chip { unsigned int id; bool throttled; + cpumask_t mask; + struct work_struct throttle; } *chips; static int nr_chips; @@ -307,8 +309,9 @@ static inline unsigned int get_nominal_index(void) return powernv_pstate_info.max - powernv_pstate_info.nominal; } -static void powernv_cpufreq_throttle_check(unsigned int cpu) +static void powernv_cpufreq_throttle_check(void *data) { + unsigned int cpu = smp_processor_id(); unsigned long pmsr; int pmsr_pmax, pmsr_lp, i; @@ -370,7 +373,7 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy, return 0; if (!throttled) - powernv_cpufreq_throttle_check(smp_processor_id()); + powernv_cpufreq_throttle_check(NULL); freq_data.pstate_id = powernv_freqs[new_index].driver_data; @@ -415,6 +418,14 @@ static struct notifier_block powernv_cpufreq_reboot_nb = { .notifier_call = powernv_cpufreq_reboot_notifier, }; +void powernv_cpufreq_work_fn(struct work_struct *work) +{ + struct chip *chip = container_of(work, struct chip, throttle); + + smp_call_function_any(&chip->mask, + powernv_cpufreq_throttle_check, NULL, 0); +} + static char throttle_reason[][30] = { "No throttling", "Power Cap", @@ -429,6 +440,7 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb, { struct opal_msg *msg = _msg; struct opal_occ_msg omsg; + int i; if (msg_type != OPAL_MSG_OCC) return 0; @@ -462,6 +474,10 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb, occ_reset = false; throttled = false; pr_info("OCC: Active\n"); + + for (i = 0; i < nr_chips; i++) + schedule_work(&chips[i].throttle); + return 0; } @@ -473,6 +489,12 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb, else if (!omsg.throttle_status) pr_info("OCC: Chip %u %s\n", (unsigned int)omsg.chip, throttle_reason[omsg.throttle_status]); + else + return 0; + + for (i = 0; i < nr_chips; i++) + if (chips[i].id == omsg.chip) + schedule_work(&chips[i].throttle); } return 0; } @@ -524,6 +546,8 @@ static int init_chip_info(void) for (i = 0; i < nr_chips; i++) { chips[i].id = chip[i]; chips[i].throttled = false; + cpumask_copy(&chips[i].mask, cpumask_of_node(chip[i])); + INIT_WORK(&chips[i].throttle, powernv_cpufreq_work_fn); } return 0; -- cgit v1.3-6-gb490 From 3dd3ebe5bb3837aeac28a23f8f22b97cb84abab6 Mon Sep 17 00:00:00 2001 From: Shilpasri G Bhat Date: Thu, 16 Jul 2015 13:34:22 +0530 Subject: cpufreq: powernv: Report Psafe only if PMSR.psafe_mode_active bit is set On a reset cycle of OCC, although the system retires from safe frequency state the local pstate is not restored to Pmin or last requested pstate. Now if the cpufreq governor initiates a pstate change, the local pstate will be in Psafe and we will be reporting a false positive when we are not throttled. So in powernv_cpufreq_throttle_check() remove the condition which checks if local pstate is less than Pmin while checking for Psafe frequency. If the cpus are forced to Psafe then PMSR.psafe_mode_active bit will be set. So, when OCCs become active this bit will be cleared. Let us just rely on this bit for reporting throttling. Signed-off-by: Shilpasri G Bhat Reviewed-by: Preeti U Murthy Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/powernv-cpufreq.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 22f33ff2d77a..90b42938837e 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -39,7 +39,6 @@ #define PMSR_PSAFE_ENABLE (1UL << 30) #define PMSR_SPR_EM_DISABLE (1UL << 31) #define PMSR_MAX(x) ((x >> 32) & 0xFF) -#define PMSR_LP(x) ((x >> 48) & 0xFF) static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; static bool rebooting, throttled, occ_reset; @@ -313,7 +312,7 @@ static void powernv_cpufreq_throttle_check(void *data) { unsigned int cpu = smp_processor_id(); unsigned long pmsr; - int pmsr_pmax, pmsr_lp, i; + int pmsr_pmax, i; pmsr = get_pmspr(SPRN_PMSR); @@ -335,14 +334,9 @@ static void powernv_cpufreq_throttle_check(void *data) chips[i].id, pmsr_pmax); } - /* - * Check for Psafe by reading LocalPstate - * or check if Psafe_mode_active is set in PMSR. - */ + /* Check if Psafe_mode_active is set in PMSR. */ next: - pmsr_lp = (s8)PMSR_LP(pmsr); - if ((pmsr_lp < powernv_pstate_info.min) || - (pmsr & PMSR_PSAFE_ENABLE)) { + if (pmsr & PMSR_PSAFE_ENABLE) { throttled = true; pr_info("Pstate set to safe frequency\n"); } -- cgit v1.3-6-gb490 From 227942809b52f23cda414858b635c0285f11de00 Mon Sep 17 00:00:00 2001 From: Shilpasri G Bhat Date: Thu, 16 Jul 2015 13:34:23 +0530 Subject: cpufreq: powernv: Restore cpu frequency to policy->cur on unthrottling If frequency is throttled due to OCC reset then cpus will be in Psafe frequency, so restore the frequency on all cpus to policy->cur when OCCs are active again. And if frequency is throttled due to Pmax capping then restore the frequency of all the cpus in the chip on unthrottling. Signed-off-by: Shilpasri G Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/powernv-cpufreq.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 90b42938837e..546e056e416d 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -48,6 +48,7 @@ static struct chip { bool throttled; cpumask_t mask; struct work_struct throttle; + bool restore; } *chips; static int nr_chips; @@ -415,9 +416,29 @@ static struct notifier_block powernv_cpufreq_reboot_nb = { void powernv_cpufreq_work_fn(struct work_struct *work) { struct chip *chip = container_of(work, struct chip, throttle); + unsigned int cpu; + cpumask_var_t mask; smp_call_function_any(&chip->mask, powernv_cpufreq_throttle_check, NULL, 0); + + if (!chip->restore) + return; + + chip->restore = false; + cpumask_copy(mask, &chip->mask); + for_each_cpu_and(cpu, mask, cpu_online_mask) { + int index, tcpu; + struct cpufreq_policy policy; + + cpufreq_get_policy(&policy, cpu); + cpufreq_frequency_table_target(&policy, policy.freq_table, + policy.cur, + CPUFREQ_RELATION_C, &index); + powernv_cpufreq_target_index(&policy, index); + for_each_cpu(tcpu, policy.cpus) + cpumask_clear_cpu(tcpu, mask); + } } static char throttle_reason[][30] = { @@ -469,8 +490,10 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb, throttled = false; pr_info("OCC: Active\n"); - for (i = 0; i < nr_chips; i++) + for (i = 0; i < nr_chips; i++) { + chips[i].restore = true; schedule_work(&chips[i].throttle); + } return 0; } @@ -487,8 +510,11 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb, return 0; for (i = 0; i < nr_chips; i++) - if (chips[i].id == omsg.chip) + if (chips[i].id == omsg.chip) { + if (!omsg.throttle_status) + chips[i].restore = true; schedule_work(&chips[i].throttle); + } } return 0; } @@ -542,6 +568,7 @@ static int init_chip_info(void) chips[i].throttled = false; cpumask_copy(&chips[i].mask, cpumask_of_node(chip[i])); INIT_WORK(&chips[i].throttle, powernv_cpufreq_work_fn); + chips[i].restore = false; } return 0; -- cgit v1.3-6-gb490 From 9298f0267c7ed620f8d8261ded8518ebf8e89f9e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 13 Jul 2015 16:54:04 -0700 Subject: clk: h8300: Drop allocation printk and cleanup sizeof style We don't need to print an error on allocation failures, drop it. While we're here, change the sizeof() to be sizeof(*) to make code more future proof. Cc: Yoshinori Sato Signed-off-by: Stephen Boyd --- drivers/clk/h8300/clk-h8s2678.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c index 4701b093e497..c121eb55e2e1 100644 --- a/drivers/clk/h8300/clk-h8s2678.c +++ b/drivers/clk/h8300/clk-h8s2678.c @@ -98,11 +98,9 @@ static void __init h8s2678_pll_clk_setup(struct device_node *node) } - pll_clock = kzalloc(sizeof(struct pll_clock), GFP_KERNEL); - if (!pll_clock) { - pr_err("%s: failed to alloc memory", clk_name); + pll_clock = kzalloc(sizeof(*pll_clock), GFP_KERNEL); + if (!pll_clock) return; - } pll_clock->sckcr = of_iomap(node, 0); if (pll_clock->sckcr == NULL) { -- cgit v1.3-6-gb490 From 006cb8b66e18ce7aff934883f6c50e3b85052681 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 13 Jul 2015 17:06:53 -0700 Subject: clk: h8300: Use standard Linux I/O accessors There doesn't seem to be any reason why we can't use the standard readb()/writeb() accessors here because ctrl_inb() and ctrl_outb() match the generic implementation of readb() and writeb() that the h8300 architecture uses. This allows us to test compile this driver on other architectures besides h8300. Cc: Yoshinori Sato Signed-off-by: Stephen Boyd --- drivers/clk/h8300/clk-h8s2678.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c index c121eb55e2e1..11808cb4f141 100644 --- a/drivers/clk/h8300/clk-h8s2678.c +++ b/drivers/clk/h8300/clk-h8s2678.c @@ -28,7 +28,7 @@ static unsigned long pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct pll_clock *pll_clock = to_pll_clock(hw); - int mul = 1 << (ctrl_inb((unsigned long)pll_clock->pllcr) & 3); + int mul = 1 << (readb(pll_clock->pllcr) & 3); return parent_rate * mul; } @@ -65,13 +65,13 @@ static int pll_set_rate(struct clk_hw *hw, unsigned long rate, pll = ((rate / parent_rate) / 2) & 0x03; spin_lock_irqsave(&clklock, flags); - val = ctrl_inb((unsigned long)pll_clock->sckcr); + val = readb(pll_clock->sckcr); val |= 0x08; - ctrl_outb(val, (unsigned long)pll_clock->sckcr); - val = ctrl_inb((unsigned long)pll_clock->pllcr); + writeb(val, pll_clock->sckcr); + val = readb(pll_clock->pllcr); val &= ~0x03; val |= pll; - ctrl_outb(val, (unsigned long)pll_clock->pllcr); + writeb(val, pll_clock->pllcr); spin_unlock_irqrestore(&clklock, flags); return 0; } -- cgit v1.3-6-gb490 From c5e857a46af24a772f445edcc01a861ee2d6a713 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 14 Jul 2015 12:45:19 -0700 Subject: clk: gpio: Unlock mutex on error path We don't unlock the mutex if we fail to allocate the parent names array. Unlock it and return an error in this case as well. Reported-by: kbuild test robot Acked-by: Julia Lawall Cc: Sergej Sawazki Signed-off-by: Stephen Boyd --- drivers/clk/clk-gpio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index c0d202c24a97..41277a1526c7 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -251,8 +251,10 @@ static struct clk *of_clk_gpio_delayed_register_get( num_parents = of_clk_get_parent_count(data->node); parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL); - if (!parent_names) - return ERR_PTR(-ENOMEM); + if (!parent_names) { + clk = ERR_PTR(-ENOMEM); + goto out; + } for (i = 0; i < num_parents; i++) parent_names[i] = of_clk_get_parent_name(data->node, i); -- cgit v1.3-6-gb490 From d7a304e9d018c99dda80f4c16ec0fe817b5be4a1 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 14 Jul 2015 16:57:29 -0700 Subject: clk: qcom: Set CLK_SET_RATE_PARENT on ce1 clocks The other ce clocks have the flag set, but ce1 doesn't, so clk_set_rate() doesn't propagate up the tree to the ce1_src_clk. Set the flag as this is supported. Reported-by: Bjorn Andersson Tested-by: Bjorn Andersson Fixes: 02824653200b ("clk: qcom: Add APQ8084 Global Clock Controller support") Fixes: d33faa9ead8d ("clk: qcom: Add support for MSM8974's global clock controller (GCC)") Signed-off-by: Stephen Boyd --- drivers/clk/qcom/gcc-apq8084.c | 1 + drivers/clk/qcom/gcc-msm8974.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c index 05b7a25b80e8..3563019b8e3c 100644 --- a/drivers/clk/qcom/gcc-apq8084.c +++ b/drivers/clk/qcom/gcc-apq8084.c @@ -2105,6 +2105,7 @@ static struct clk_branch gcc_ce1_clk = { "ce1_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c index 2c289702119f..2bcf87538f9d 100644 --- a/drivers/clk/qcom/gcc-msm8974.c +++ b/drivers/clk/qcom/gcc-msm8974.c @@ -1783,6 +1783,7 @@ static struct clk_branch gcc_ce1_clk = { "ce1_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, -- cgit v1.3-6-gb490 From e306479ac252928b84cc563c6e790f9b7e7ae427 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 20 Jun 2015 15:27:03 +0800 Subject: clk: h8300: Fix signness bug of_clk_get_parent_count() may return negative error code, so num_parents needs to be int rather than unsigned int. Signed-off-by: Axel Lin Signed-off-by: Stephen Boyd --- drivers/clk/h8300/clk-div.c | 2 +- drivers/clk/h8300/clk-h8s2678.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/h8300/clk-div.c b/drivers/clk/h8300/clk-div.c index 56f9eba91b83..e13d5c33a887 100644 --- a/drivers/clk/h8300/clk-div.c +++ b/drivers/clk/h8300/clk-div.c @@ -15,7 +15,7 @@ static DEFINE_SPINLOCK(clklock); static void __init h8300_div_clk_setup(struct device_node *node) { - unsigned int num_parents; + int num_parents; struct clk *clk; const char *clk_name = node->name; const char *parent_name; diff --git a/drivers/clk/h8300/clk-h8s2678.c b/drivers/clk/h8300/clk-h8s2678.c index 11808cb4f141..46e16f22b38f 100644 --- a/drivers/clk/h8300/clk-h8s2678.c +++ b/drivers/clk/h8300/clk-h8s2678.c @@ -84,7 +84,7 @@ static const struct clk_ops pll_ops = { static void __init h8s2678_pll_clk_setup(struct device_node *node) { - unsigned int num_parents; + int num_parents; struct clk *clk; const char *clk_name = node->name; const char *parent_name; -- cgit v1.3-6-gb490 From f645f72d876586c4950dcd5bf516744db0aeb30b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Jul 2015 11:55:42 -0700 Subject: clk: ti: Check kzalloc() for failures smatch reports a failure to check kzalloc() here: drivers/clk/ti/clk.c:232 omap2_clk_provider_init() error: potential null dereference 'io'. (kzalloc returns null) Check for an allocation failure and return -ENOMEM. Acked-by: Tero Kristo Signed-off-by: Stephen Boyd --- drivers/clk/ti/clk.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 3343bde47fe4..521e330e3046 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -227,6 +227,8 @@ int __init omap2_clk_provider_init(struct device_node *parent, int index, clocks_node_ptr[index] = clocks; io = kzalloc(sizeof(*io), GFP_KERNEL); + if (!io) + return -ENOMEM; io->regmap = syscon; io->mem = mem; -- cgit v1.3-6-gb490 From 3fe6d697420c706b640730dbbae17f48b3aad506 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Jul 2015 12:03:52 -0700 Subject: clk: ti: Mark ti_clk_features static This variable isn't exported outside of this file so mark it static. Silences the following sparse warning: drivers/clk/ti/clk.c:36:24: warning: symbol 'ti_clk_features' was not declared. Should it be static? Acked-by: Tero Kristo Signed-off-by: Stephen Boyd --- drivers/clk/ti/clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 521e330e3046..0d8861cf21a8 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -32,7 +32,7 @@ struct ti_clk_ll_ops *ti_clk_ll_ops; static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; -struct ti_clk_features ti_clk_features; +static struct ti_clk_features ti_clk_features; struct clk_iomap { struct regmap *regmap; -- cgit v1.3-6-gb490 From 76642eb4cb040b436319e5aa747a5ef026207eef Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Jul 2015 12:04:53 -0700 Subject: clk: ti: clk-3xxx: Remove unused structures Sparse complains about these structures missing static, but they also don't look to be used. Remove them. drivers/clk/ti/clk-3xxx.c:74:30: warning: symbol 'clkhwops_omap3430es2_ssi_wait' was not declared. Should it be static? drivers/clk/ti/clk-3xxx.c:157:30: warning: symbol 'clkhwops_omap3430es2_hsotgusb_wait' was not declared. Should it be static? Acked-by: Tero Kristo Signed-off-by: Stephen Boyd --- drivers/clk/ti/clk-3xxx.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c index 6e33332b6b34..70eb85ac88f3 100644 --- a/drivers/clk/ti/clk-3xxx.c +++ b/drivers/clk/ti/clk-3xxx.c @@ -70,11 +70,6 @@ static void omap3430es2_clk_ssi_find_idlest(struct clk_hw_omap *clk, *idlest_val = OMAP34XX_CM_IDLEST_VAL; } -const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait = { - .find_idlest = omap3430es2_clk_ssi_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait = { .allow_idle = omap2_clkt_iclk_allow_idle, .deny_idle = omap2_clkt_iclk_deny_idle, @@ -153,11 +148,6 @@ const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait = { .find_companion = omap2_clk_dflt_find_companion, }; -const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait = { - .find_idlest = omap3430es2_clk_hsotgusb_find_idlest, - .find_companion = omap2_clk_dflt_find_companion, -}; - /** * am35xx_clk_find_idlest - return clock ACK info for AM35XX IPSS * @clk: struct clk * being enabled -- cgit v1.3-6-gb490 From 14cc4e9578841a4c0025ce064133b2da53c9d1c9 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 15 Jul 2015 12:58:22 -0700 Subject: clk: ti: Force pointer to be __iomem Add __force here so that sparse doesn't complain about us playing tricks with __iomem. Acked-by: Tero Kristo Signed-off-by: Stephen Boyd --- drivers/clk/ti/clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 0d8861cf21a8..78a47ccff19a 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -193,7 +193,7 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) reg->offset = val; - return (void __iomem *)tmp; + return (__force void __iomem *)tmp; } /** -- cgit v1.3-6-gb490 From 5a1cfafaeab5237523d43cd033e1fb42bf5c1933 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Jun 2015 15:09:27 +0200 Subject: clk: shmobile: Remove unneeded #include The CCF implementations for the various shmobile SoCs don't use clkdev functionality, hence drop the inclusion of . Add the missing #include , which was included implicitly through before. Signed-off-by: Geert Uytterhoeven Signed-off-by: Stephen Boyd --- drivers/clk/shmobile/clk-div6.c | 2 +- drivers/clk/shmobile/clk-r8a73a4.c | 2 +- drivers/clk/shmobile/clk-r8a7740.c | 2 +- drivers/clk/shmobile/clk-r8a7778.c | 2 +- drivers/clk/shmobile/clk-r8a7779.c | 2 +- drivers/clk/shmobile/clk-rcar-gen2.c | 2 +- drivers/clk/shmobile/clk-sh73a0.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c index 036a692c7219..6810bfb6ef5e 100644 --- a/drivers/clk/shmobile/clk-div6.c +++ b/drivers/clk/shmobile/clk-div6.c @@ -11,12 +11,12 @@ */ #include -#include #include #include #include #include #include +#include #define CPG_DIV6_CKSTP BIT(8) #define CPG_DIV6_DIV(d) ((d) & 0x3f) diff --git a/drivers/clk/shmobile/clk-r8a73a4.c b/drivers/clk/shmobile/clk-r8a73a4.c index 29b9a0b0012a..9326204bed9d 100644 --- a/drivers/clk/shmobile/clk-r8a73a4.c +++ b/drivers/clk/shmobile/clk-r8a73a4.c @@ -9,10 +9,10 @@ */ #include -#include #include #include #include +#include #include #include #include diff --git a/drivers/clk/shmobile/clk-r8a7740.c b/drivers/clk/shmobile/clk-r8a7740.c index 1e2eaae21e01..1e6b1da58065 100644 --- a/drivers/clk/shmobile/clk-r8a7740.c +++ b/drivers/clk/shmobile/clk-r8a7740.c @@ -9,10 +9,10 @@ */ #include -#include #include #include #include +#include #include #include #include diff --git a/drivers/clk/shmobile/clk-r8a7778.c b/drivers/clk/shmobile/clk-r8a7778.c index cb33b57274bf..e97e28fcfc13 100644 --- a/drivers/clk/shmobile/clk-r8a7778.c +++ b/drivers/clk/shmobile/clk-r8a7778.c @@ -9,9 +9,9 @@ */ #include -#include #include #include +#include struct r8a7778_cpg { struct clk_onecell_data data; diff --git a/drivers/clk/shmobile/clk-r8a7779.c b/drivers/clk/shmobile/clk-r8a7779.c index 652ecacb6daf..af297963489f 100644 --- a/drivers/clk/shmobile/clk-r8a7779.c +++ b/drivers/clk/shmobile/clk-r8a7779.c @@ -11,12 +11,12 @@ */ #include -#include #include #include #include #include #include +#include #include #include diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c index acfb6d7dbd6b..9233ebf8cc49 100644 --- a/drivers/clk/shmobile/clk-rcar-gen2.c +++ b/drivers/clk/shmobile/clk-rcar-gen2.c @@ -11,13 +11,13 @@ */ #include -#include #include #include #include #include #include #include +#include #include struct rcar_gen2_cpg { diff --git a/drivers/clk/shmobile/clk-sh73a0.c b/drivers/clk/shmobile/clk-sh73a0.c index cd529cfe412f..8966f8bbfd72 100644 --- a/drivers/clk/shmobile/clk-sh73a0.c +++ b/drivers/clk/shmobile/clk-sh73a0.c @@ -9,12 +9,12 @@ */ #include -#include #include #include #include #include #include +#include #include struct sh73a0_cpg { -- cgit v1.3-6-gb490 From 264e3b75de4eee6e4ee4616bf2b2a3d522cad72a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 16 Jul 2015 21:59:43 +0800 Subject: clk: s2mps11: Simplify s2mps11_clk_probe unwind paths The devm_clk_unregister() in .probe error case is not necessary as it will be automatically called when probe fails. Signed-off-by: Axel Lin Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- drivers/clk/clk-s2mps11.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index 9b13a303d3f8..ba7fb1b8c182 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -246,7 +246,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev) s2mps11_name(s2mps11_clk), NULL); if (!s2mps11_clk->lookup) { ret = -ENOMEM; - goto err_lup; + goto err_reg; } } @@ -265,16 +265,10 @@ static int s2mps11_clk_probe(struct platform_device *pdev) platform_set_drvdata(pdev, s2mps11_clks); return ret; -err_lup: - devm_clk_unregister(&pdev->dev, s2mps11_clk->clk); + err_reg: - while (s2mps11_clk > s2mps11_clks) { - if (s2mps11_clk->lookup) { - clkdev_drop(s2mps11_clk->lookup); - devm_clk_unregister(&pdev->dev, s2mps11_clk->clk); - } - s2mps11_clk--; - } + while (--i >= 0) + clkdev_drop(s2mps11_clks[i].lookup); return ret; } -- cgit v1.3-6-gb490 From 5c757456c16ce056a40a120e63235bc00c94ee7f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 16 Jul 2015 22:15:53 +0800 Subject: clk: twl6040: Convert to use devm_clk_register Use devm_clk_register() to simplify the code by removing twl6040_clk_remove(). Signed-off-by: Axel Lin Acked-by: Peter Ujfalusi Signed-off-by: Stephen Boyd --- drivers/clk/clk-twl6040.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index 4a755135bcd3..8515232ffc75 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -91,7 +91,7 @@ static int twl6040_clk_probe(struct platform_device *pdev) clkdata->twl6040 = twl6040; clkdata->mcpdm_fclk.init = &wm831x_clkout_init; - clkdata->clk = clk_register(&pdev->dev, &clkdata->mcpdm_fclk); + clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->mcpdm_fclk); if (IS_ERR(clkdata->clk)) return PTR_ERR(clkdata->clk); @@ -100,21 +100,11 @@ static int twl6040_clk_probe(struct platform_device *pdev) return 0; } -static int twl6040_clk_remove(struct platform_device *pdev) -{ - struct twl6040_clk *clkdata = platform_get_drvdata(pdev); - - clk_unregister(clkdata->clk); - - return 0; -} - static struct platform_driver twl6040_clk_driver = { .driver = { .name = "twl6040-clk", }, .probe = twl6040_clk_probe, - .remove = twl6040_clk_remove, }; module_platform_driver(twl6040_clk_driver); -- cgit v1.3-6-gb490 From 9783c0d98501aa146ff467916ab4b8830a655d7c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 16 Jul 2015 12:50:27 -0700 Subject: clk: Allow providers to configure min/max rates clk providers are using the consumer APIs to set min/max rates on the clock they're providing. To encourage clk providers to move away from the consumer APIs, add a provider API to set the min/max rate of a clock. The assumption is that this is done before the clock can be requested via clk_get() and that the clock rate is already within the boundaries of the min/max that's configured. Tested-by: Sudeep Holla Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 16 ++++++++++++++-- include/linux/clk-provider.h | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index bd6dfbe04cf0..1ac237fe2fdb 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -58,6 +58,8 @@ struct clk_core { unsigned long flags; unsigned int enable_count; unsigned int prepare_count; + unsigned long min_rate; + unsigned long max_rate; unsigned long accuracy; int phase; struct hlist_head children; @@ -512,8 +514,8 @@ static void clk_core_get_boundaries(struct clk_core *core, { struct clk *clk_user; - *min_rate = 0; - *max_rate = ULONG_MAX; + *min_rate = core->min_rate; + *max_rate = core->max_rate; hlist_for_each_entry(clk_user, &core->clks, clks_node) *min_rate = max(*min_rate, clk_user->min_rate); @@ -522,6 +524,14 @@ static void clk_core_get_boundaries(struct clk_core *core, *max_rate = min(*max_rate, clk_user->max_rate); } +void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate, + unsigned long max_rate) +{ + hw->core->min_rate = min_rate; + hw->core->max_rate = max_rate; +} +EXPORT_SYMBOL_GPL(clk_hw_set_rate_range); + /* * Helper for finding best parent to provide a given frequency. This can be used * directly as a determine_rate callback (e.g. for a mux), or from a more @@ -2498,6 +2508,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) core->hw = hw; core->flags = hw->init->flags; core->num_parents = hw->init->num_parents; + core->min_rate = 0; + core->max_rate = ULONG_MAX; hw->core = core; /* allocate local copy in case parent_names is __initdata */ diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 2116e2b8a5f2..d62e7eab1dbe 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -619,6 +619,8 @@ int __clk_determine_rate(struct clk_hw *core, struct clk_rate_request *req); int __clk_mux_determine_rate_closest(struct clk_hw *hw, struct clk_rate_request *req); void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent); +void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate, + unsigned long max_rate); static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src) { -- cgit v1.3-6-gb490 From b3be457e5854e3095cd0be850058c765aaf467ab Mon Sep 17 00:00:00 2001 From: James Liao Date: Fri, 10 Jul 2015 16:39:32 +0800 Subject: clk: mediatek: Fix PLL registers setting flow Write postdiv and pcw settings at the same time for PLLs if postdiv and pcw settings are on the same register. This is need by PLLs such as MT8173 MMPLL and ARM*PLL. Signed-off-by: James Liao Acked-by: Sascha Hauer Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-pll.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 44409e98c52f..68af5183cda0 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -90,20 +90,23 @@ static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin, static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw, int postdiv) { - u32 con1, pd, val; + u32 con1, val; int pll_en; - /* set postdiv */ - pd = readl(pll->pd_addr); - pd &= ~(POSTDIV_MASK << pll->data->pd_shift); - pd |= (ffs(postdiv) - 1) << pll->data->pd_shift; - writel(pd, pll->pd_addr); - pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN; - /* set pcw */ - val = readl(pll->pcw_addr); + /* set postdiv */ + val = readl(pll->pd_addr); + val &= ~(POSTDIV_MASK << pll->data->pd_shift); + val |= (ffs(postdiv) - 1) << pll->data->pd_shift; + + /* postdiv and pcw need to set at the same time if on same register */ + if (pll->pd_addr != pll->pcw_addr) { + writel(val, pll->pd_addr); + val = readl(pll->pcw_addr); + } + /* set pcw */ val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1, pll->data->pcw_shift); val |= pcw << pll->data->pcw_shift; -- cgit v1.3-6-gb490 From 196de71a9d9e9090406a87362d22b67ae633fa7a Mon Sep 17 00:00:00 2001 From: James Liao Date: Fri, 10 Jul 2015 16:39:33 +0800 Subject: clk: mediatek: Fix calculation of PLL rate settings Avoid u32 overflow when calculate post divider setting, and increase the max post divider setting from 3 (/8) to 4 (/16). Signed-off-by: James Liao Acked-by: Sascha Hauer Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-pll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 68af5183cda0..0e3f4ef0e871 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -144,9 +144,9 @@ static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv, if (freq > pll->data->fmax) freq = pll->data->fmax; - for (val = 0; val < 4; val++) { + for (val = 0; val < 5; val++) { *postdiv = 1 << val; - if (freq * *postdiv >= fmin) + if ((u64)freq * *postdiv >= fmin) break; } -- cgit v1.3-6-gb490 From 75ce0cdb6243d42daca6130e5feb71f536bb136e Mon Sep 17 00:00:00 2001 From: James Liao Date: Fri, 10 Jul 2015 16:39:34 +0800 Subject: clk: mediatek: Add MT8173 MMPLL change rate support MT8173 MMPLL frequency settings are different from common PLLs. It needs different post divider settings for some ranges of frequency. This patch add support for MT8173 MMPLL frequency setting by adding div-rate table to lookup suitable post divider setting under a specified frequency. Signed-off-by: James Liao Acked-by: Sascha Hauer Signed-off-by: Stephen Boyd --- drivers/clk/mediatek/clk-mt8173.c | 24 +++++++++++++++++++++--- drivers/clk/mediatek/clk-mtk.h | 6 ++++++ drivers/clk/mediatek/clk-pll.c | 18 +++++++++++++++--- 3 files changed, 42 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mediatek/clk-mt8173.c b/drivers/clk/mediatek/clk-mt8173.c index 8b6523d15fb8..cd3fad3ca993 100644 --- a/drivers/clk/mediatek/clk-mt8173.c +++ b/drivers/clk/mediatek/clk-mt8173.c @@ -795,8 +795,9 @@ CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init); #define CON0_MT8173_RST_BAR BIT(24) -#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, _pd_reg, _pd_shift, \ - _tuner_reg, _pcw_reg, _pcw_shift) { \ +#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift, _div_table) { \ .id = _id, \ .name = _name, \ .reg = _reg, \ @@ -811,14 +812,31 @@ CLK_OF_DECLARE(mtk_pericfg, "mediatek,mt8173-pericfg", mtk_pericfg_init); .tuner_reg = _tuner_reg, \ .pcw_reg = _pcw_reg, \ .pcw_shift = _pcw_shift, \ + .div_table = _div_table, \ } +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift) \ + PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ + NULL) + +static const struct mtk_pll_div_table mmpll_div_table[] = { + { .div = 0, .freq = MT8173_PLL_FMAX }, + { .div = 1, .freq = 1000000000 }, + { .div = 2, .freq = 702000000 }, + { .div = 3, .freq = 253500000 }, + { .div = 4, .freq = 126750000 }, + { } /* sentinel */ +}; + static const struct mtk_pll_data plls[] = { PLL(CLK_APMIXED_ARMCA15PLL, "armca15pll", 0x200, 0x20c, 0x00000001, 0, 21, 0x204, 24, 0x0, 0x204, 0), PLL(CLK_APMIXED_ARMCA7PLL, "armca7pll", 0x210, 0x21c, 0x00000001, 0, 21, 0x214, 24, 0x0, 0x214, 0), PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x220, 0x22c, 0xf0000101, HAVE_RST_BAR, 21, 0x220, 4, 0x0, 0x224, 0), PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x230, 0x23c, 0xfe000001, HAVE_RST_BAR, 7, 0x230, 4, 0x0, 0x234, 14), - PLL(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0), + PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x240, 0x24c, 0x00000001, 0, 21, 0x244, 24, 0x0, 0x244, 0, mmpll_div_table), PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x250, 0x25c, 0x00000001, 0, 21, 0x250, 4, 0x0, 0x254, 0), PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x260, 0x26c, 0x00000001, 0, 21, 0x260, 4, 0x0, 0x264, 0), PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x270, 0x27c, 0x00000001, 0, 21, 0x270, 4, 0x0, 0x274, 0), diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index 9dda9d8ad10b..efea28d6e1e6 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -134,6 +134,11 @@ struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num); #define HAVE_RST_BAR BIT(0) +struct mtk_pll_div_table { + u32 div; + unsigned long freq; +}; + struct mtk_pll_data { int id; const char *name; @@ -150,6 +155,7 @@ struct mtk_pll_data { int pcwbits; uint32_t pcw_reg; int pcw_shift; + const struct mtk_pll_div_table *div_table; }; void __init mtk_clk_register_plls(struct device_node *node, diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 0e3f4ef0e871..622e7b6c62b4 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -138,16 +138,28 @@ static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv, u32 freq, u32 fin) { unsigned long fmin = 1000 * MHZ; + const struct mtk_pll_div_table *div_table = pll->data->div_table; u64 _pcw; u32 val; if (freq > pll->data->fmax) freq = pll->data->fmax; - for (val = 0; val < 5; val++) { + if (div_table) { + if (freq > div_table[0].freq) + freq = div_table[0].freq; + + for (val = 0; div_table[val + 1].freq != 0; val++) { + if (freq > div_table[val + 1].freq) + break; + } *postdiv = 1 << val; - if ((u64)freq * *postdiv >= fmin) - break; + } else { + for (val = 0; val < 5; val++) { + *postdiv = 1 << val; + if ((u64)freq * *postdiv >= fmin) + break; + } } /* _pcw = freq * postdiv / fin * 2^pcwfbits */ -- cgit v1.3-6-gb490 From f0557fbe1303aade362bd578753a1c898a80851c Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 6 Jul 2015 22:59:01 -0500 Subject: clk: at91: make use of of_clk_parent_fill helper function Use of_clk_parent_fill to fill in the parent clock names' array. Signed-off-by: Dinh Nguyen Cc: Boris Brezillon Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-main.c | 7 +------ drivers/clk/at91/clk-master.c | 7 +------ drivers/clk/at91/clk-programmable.c | 7 +------ drivers/clk/at91/clk-slow.c | 14 ++------------ drivers/clk/at91/clk-smd.c | 7 +------ drivers/clk/at91/clk-usb.c | 7 +------ 6 files changed, 7 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c index 27dfa965cfed..fd7247deabdc 100644 --- a/drivers/clk/at91/clk-main.c +++ b/drivers/clk/at91/clk-main.c @@ -614,17 +614,12 @@ void __init of_at91sam9x5_clk_main_setup(struct device_node *np, int num_parents; unsigned int irq; const char *name = np->name; - int i; num_parents = of_clk_get_parent_count(np); if (num_parents <= 0 || num_parents > 2) return; - for (i = 0; i < num_parents; ++i) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index 5b3ded5205a2..620ea323356b 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -222,7 +222,6 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, { struct clk *clk; int num_parents; - int i; unsigned int irq; const char *parent_names[MASTER_SOURCE_MAX]; const char *name = np->name; @@ -232,11 +231,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX) return; - for (i = 0; i < num_parents; ++i) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c index 43dacad5c96d..ce9c3b9d00f2 100644 --- a/drivers/clk/at91/clk-programmable.c +++ b/drivers/clk/at91/clk-programmable.c @@ -231,7 +231,6 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, { int num; u32 id; - int i; struct clk *clk; int num_parents; const char *parent_names[PROG_SOURCE_MAX]; @@ -242,11 +241,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX) return; - for (i = 0; i < num_parents; ++i) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); num = of_get_child_count(np); if (!num || num > (PROG_ID_MAX + 1)) diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c index 98a84a865fe1..84c19d7d29e8 100644 --- a/drivers/clk/at91/clk-slow.c +++ b/drivers/clk/at91/clk-slow.c @@ -371,17 +371,12 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, const char *parent_names[2]; int num_parents; const char *name = np->name; - int i; num_parents = of_clk_get_parent_count(np); if (num_parents <= 0 || num_parents > 2) return; - for (i = 0; i < num_parents; ++i) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); @@ -449,17 +444,12 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np, const char *parent_names[2]; int num_parents; const char *name = np->name; - int i; num_parents = of_clk_get_parent_count(np); if (num_parents != 2) return; - for (i = 0; i < num_parents; ++i) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c index 3817ea865ca2..a7f8501cfa05 100644 --- a/drivers/clk/at91/clk-smd.c +++ b/drivers/clk/at91/clk-smd.c @@ -145,7 +145,6 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, struct at91_pmc *pmc) { struct clk *clk; - int i; int num_parents; const char *parent_names[SMD_SOURCE_MAX]; const char *name = np->name; @@ -154,11 +153,7 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX) return; - for (i = 0; i < num_parents; i++) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 24747df97742..1fdf0e33545d 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -373,7 +373,6 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, struct at91_pmc *pmc) { struct clk *clk; - int i; int num_parents; const char *parent_names[USB_SOURCE_MAX]; const char *name = np->name; @@ -382,11 +381,7 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, if (num_parents <= 0 || num_parents > USB_SOURCE_MAX) return; - for (i = 0; i < num_parents; i++) { - parent_names[i] = of_clk_get_parent_name(np, i); - if (!parent_names[i]) - return; - } + of_clk_parent_fill(np, parent_names, num_parents); of_property_read_string(np, "clock-output-names", &name); -- cgit v1.3-6-gb490 From 5f23eff7af6bc1d8cc8e17fc12e8d989042236ed Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 6 Jul 2015 22:59:03 -0500 Subject: clk: keystone: make use of of_clk_parent_fill helper function Use of_clk_parent_fill to fill in the parent clock names' array. Signed-off-by: Dinh Nguyen Acked-by: Santosh Shilimkar Signed-off-by: Stephen Boyd --- drivers/clk/keystone/pll.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c index 4a375ead70e9..d6ef063dae7e 100644 --- a/drivers/clk/keystone/pll.c +++ b/drivers/clk/keystone/pll.c @@ -309,8 +309,7 @@ static void __init of_pll_mux_clk_init(struct device_node *node) return; } - parents[0] = of_clk_get_parent_name(node, 0); - parents[1] = of_clk_get_parent_name(node, 1); + of_clk_parent_fill(node, parents, 2); if (!parents[0] || !parents[1]) { pr_err("%s: missing parent clocks\n", __func__); return; -- cgit v1.3-6-gb490 From 0b4e7f0842fe5c8bd19654999f6c41c4119e7c90 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 6 Jul 2015 22:59:04 -0500 Subject: clk: st: make use of of_clk_parent_fill helper function Use of_clk_parent_fill to fill in the parent clock names' array. Signed-off-by: Dinh Nguyen Tested-by Gabriel Fernandez Cc: Peter Griffin Signed-off-by: Stephen Boyd --- drivers/clk/st/clk-flexgen.c | 6 ++---- drivers/clk/st/clkgen-mux.c | 7 ++----- 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c index 8dd8cce27361..308dc2f265b1 100644 --- a/drivers/clk/st/clk-flexgen.c +++ b/drivers/clk/st/clk-flexgen.c @@ -243,7 +243,7 @@ static const char ** __init flexgen_get_parents(struct device_node *np, int *num_parents) { const char **parents; - int nparents, i; + int nparents; nparents = of_clk_get_parent_count(np); if (WARN_ON(nparents <= 0)) @@ -253,10 +253,8 @@ static const char ** __init flexgen_get_parents(struct device_node *np, if (!parents) return NULL; - for (i = 0; i < nparents; i++) - parents[i] = of_clk_get_parent_name(np, i); + *num_parents = of_clk_parent_fill(np, parents, nparents); - *num_parents = nparents; return parents; } diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c index ab9298395264..de6c64f7839b 100644 --- a/drivers/clk/st/clkgen-mux.c +++ b/drivers/clk/st/clkgen-mux.c @@ -24,7 +24,7 @@ static const char ** __init clkgen_mux_get_parents(struct device_node *np, int *num_parents) { const char **parents; - int nparents, i; + int nparents; nparents = of_clk_get_parent_count(np); if (WARN_ON(nparents <= 0)) @@ -34,10 +34,7 @@ static const char ** __init clkgen_mux_get_parents(struct device_node *np, if (!parents) return ERR_PTR(-ENOMEM); - for (i = 0; i < nparents; i++) - parents[i] = of_clk_get_parent_name(np, i); - - *num_parents = nparents; + *num_parents = of_clk_parent_fill(np, parents, nparents); return parents; } -- cgit v1.3-6-gb490 From 8a53fb2bceea00081c4a6af7b477bea8ec00b74b Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 6 Jul 2015 22:59:05 -0500 Subject: clk: sunxi: make use of of_clk_parent_fill helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use of_clk_parent_fill to fill in the parent clock names' array. Signed-off-by: Dinh Nguyen Acked-by: Maxime Ripard Cc: "Emilio López" Signed-off-by: Stephen Boyd --- drivers/clk/sunxi/clk-a20-gmac.c | 4 +--- drivers/clk/sunxi/clk-factors.c | 4 +--- drivers/clk/sunxi/clk-sun6i-ar100.c | 4 +--- drivers/clk/sunxi/clk-sunxi.c | 14 ++++---------- 4 files changed, 7 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/sunxi/clk-a20-gmac.c b/drivers/clk/sunxi/clk-a20-gmac.c index 0dcf4f205fb8..1611b036421c 100644 --- a/drivers/clk/sunxi/clk-a20-gmac.c +++ b/drivers/clk/sunxi/clk-a20-gmac.c @@ -80,9 +80,7 @@ static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) goto free_mux; /* gmac clock requires exactly 2 parents */ - parents[0] = of_clk_get_parent_name(node, 0); - parents[1] = of_clk_get_parent_name(node, 1); - if (!parents[0] || !parents[1]) + if (of_clk_parent_fill(node, parents, 2) != 2) goto free_gate; reg = of_iomap(node, 0); diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 94e2570a2409..a650eae4cc49 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -175,9 +175,7 @@ struct clk *sunxi_factors_register(struct device_node *node, int i = 0; /* if we have a mux, we will have >1 parents */ - while (i < FACTORS_MAX_PARENTS && - (parents[i] = of_clk_get_parent_name(node, i)) != NULL) - i++; + i = of_clk_parent_fill(node, parents, FACTORS_MAX_PARENTS); /* * some factor clocks, such as pll5 and pll6, may have multiple diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c index 21b076ee59d1..3a2ea010f148 100644 --- a/drivers/clk/sunxi/clk-sun6i-ar100.c +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c @@ -182,7 +182,6 @@ static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev) struct resource *r; struct clk *clk; int nparents; - int i; ar100 = devm_kzalloc(&pdev->dev, sizeof(*ar100), GFP_KERNEL); if (!ar100) @@ -197,8 +196,7 @@ static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev) if (nparents > SUN6I_AR100_MAX_PARENTS) nparents = SUN6I_AR100_MAX_PARENTS; - for (i = 0; i < nparents; i++) - parents[i] = of_clk_get_parent_name(np, i); + of_clk_parent_fill(np, parents, nparents); of_property_read_string(np, "clock-output-names", &clk_name); diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 0e15165280dc..2011f2178bd8 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c @@ -195,17 +195,14 @@ static void __init sun6i_ahb1_clk_setup(struct device_node *node) const char *clk_name = node->name; const char *parents[SUN6I_AHB1_MAX_PARENTS]; void __iomem *reg; - int i = 0; + int i; reg = of_io_request_and_map(node, 0, of_node_full_name(node)); if (IS_ERR(reg)) return; /* we have a mux, we will have >1 parents */ - while (i < SUN6I_AHB1_MAX_PARENTS && - (parents[i] = of_clk_get_parent_name(node, i)) != NULL) - i++; - + i = of_clk_parent_fill(node, parents, SUN6I_AHB1_MAX_PARENTS); of_property_read_string(node, "clock-output-names", &clk_name); ahb1 = kzalloc(sizeof(struct sun6i_ahb1_clk), GFP_KERNEL); @@ -786,14 +783,11 @@ static void __init sunxi_mux_clk_setup(struct device_node *node, const char *clk_name = node->name; const char *parents[SUNXI_MAX_PARENTS]; void __iomem *reg; - int i = 0; + int i; reg = of_iomap(node, 0); - while (i < SUNXI_MAX_PARENTS && - (parents[i] = of_clk_get_parent_name(node, i)) != NULL) - i++; - + i = of_clk_parent_fill(node, parents, SUNXI_MAX_PARENTS); of_property_read_string(node, "clock-output-names", &clk_name); clk = clk_register_mux(NULL, clk_name, parents, i, -- cgit v1.3-6-gb490 From 9da9e761273702b3afd6e3538c23ece95693e586 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 6 Jul 2015 22:59:06 -0500 Subject: clk: ti: make use of of_clk_parent_fill helper function Use of_clk_parent_fill to fill in the parent clock names' array. Signed-off-by: Dinh Nguyen Cc: Tero Kristo Signed-off-by: Stephen Boyd --- drivers/clk/ti/apll.c | 4 +--- drivers/clk/ti/composite.c | 4 +--- drivers/clk/ti/dpll.c | 4 +--- drivers/clk/ti/fapll.c | 3 +-- drivers/clk/ti/mux.c | 4 +--- 5 files changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index 594b759f02ee..de5a02dfd326 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -172,7 +172,6 @@ static void __init of_dra7_apll_setup(struct device_node *node) struct clk_hw_omap *clk_hw = NULL; struct clk_init_data *init = NULL; const char **parent_names = NULL; - int i; ad = kzalloc(sizeof(*ad), GFP_KERNEL); clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); @@ -197,8 +196,7 @@ static void __init of_dra7_apll_setup(struct device_node *node) if (!parent_names) goto cleanup; - for (i = 0; i < init->num_parents; i++) - parent_names[i] = of_clk_get_parent_name(node, i); + of_clk_parent_fill(node, parent_names, init->num_parents); init->parent_names = parent_names; diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c index 96f83cedb4b3..dbef218fe5ec 100644 --- a/drivers/clk/ti/composite.c +++ b/drivers/clk/ti/composite.c @@ -276,7 +276,6 @@ int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int num_parents; const char **parent_names; struct component_clk *clk; - int i; num_parents = of_clk_get_parent_count(node); @@ -289,8 +288,7 @@ int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw, if (!parent_names) return -ENOMEM; - for (i = 0; i < num_parents; i++) - parent_names[i] = of_clk_get_parent_name(node, i); + of_clk_parent_fill(node, parent_names, num_parents); clk = kzalloc(sizeof(*clk), GFP_KERNEL); if (!clk) { diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 2aacf7a3bcae..49acdf23ad40 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -341,7 +341,6 @@ static void __init of_ti_dpll_setup(struct device_node *node, struct clk_init_data *init = NULL; const char **parent_names = NULL; struct dpll_data *dd = NULL; - int i; u8 dpll_mode = 0; dd = kzalloc(sizeof(*dd), GFP_KERNEL); @@ -370,8 +369,7 @@ static void __init of_ti_dpll_setup(struct device_node *node, if (!parent_names) goto cleanup; - for (i = 0; i < init->num_parents; i++) - parent_names[i] = of_clk_get_parent_name(node, i); + of_clk_parent_fill(node, parent_names, init->num_parents); init->parent_names = parent_names; diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c index 730aa62454a2..b1c741b11502 100644 --- a/drivers/clk/ti/fapll.c +++ b/drivers/clk/ti/fapll.c @@ -558,8 +558,7 @@ static void __init ti_fapll_setup(struct device_node *node) goto free; } - parent_name[0] = of_clk_get_parent_name(node, 0); - parent_name[1] = of_clk_get_parent_name(node, 1); + of_clk_parent_fill(node, parent_name, 2); init->parent_names = parent_name; fd->clk_ref = of_clk_get(node, 0); diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index 5cdeed538b08..99fe27e8376b 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -190,7 +190,6 @@ static void of_mux_clk_setup(struct device_node *node) void __iomem *reg; int num_parents; const char **parent_names; - int i; u8 clk_mux_flags = 0; u32 mask = 0; u32 shift = 0; @@ -205,8 +204,7 @@ static void of_mux_clk_setup(struct device_node *node) if (!parent_names) goto cleanup; - for (i = 0; i < num_parents; i++) - parent_names[i] = of_clk_get_parent_name(node, i); + of_clk_parent_fill(node, parent_names, num_parents); reg = ti_clk_get_reg_addr(node, 0); -- cgit v1.3-6-gb490 From 2bbfe00147a7c075f5c43e657ec218afea662819 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 21 Jul 2015 13:41:23 -0700 Subject: clk: rockchip: Fix PLL bandwidth In the TRM we see that BWADJ is "a 12-bit bus that selects the values 1-4096 for the bandwidth divider (NB)": NB = BWADJ[11:0] + 1 The recommended setting of NB: NB = NF / 2. So: NB = NF / 2 BWADJ[11:0] + 1 = NF / 2 BWADJ[11:0] = NF / 2 - 1 Right now, we have: { \ .rate = _rate##U, \ .nr = _nr, \ .nf = _nf, \ .no = _no, \ .bwadj = (_nf >> 1), \ } That means we set bwadj to NF / 2, not NF / 2 - 1 All of this is a bit confusing because we specify "NR" (the 1-based value), "NF" (the 1-based value), "NO" (the 1-based value), but "BWADJ" (the 0-based value) instead of "NB" (the 1-based value). Let's change to working with "NB" and fix the off by one error. This may affect PLL jitter in a small way (hopefully for the better). Signed-off-by: Douglas Anderson Reviewed-by: Heiko Stuebner Signed-off-by: Stephen Boyd --- drivers/clk/rockchip/clk-pll.c | 18 +++++++++--------- drivers/clk/rockchip/clk-rk3188.c | 2 +- drivers/clk/rockchip/clk-rk3288.c | 2 +- drivers/clk/rockchip/clk.h | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 1f88dd158b93..96903ae8b192 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -120,8 +120,8 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) #define RK3066_PLLCON0_NR_SHIFT 8 #define RK3066_PLLCON1_NF_MASK 0x1fff #define RK3066_PLLCON1_NF_SHIFT 0 -#define RK3066_PLLCON2_BWADJ_MASK 0xfff -#define RK3066_PLLCON2_BWADJ_SHIFT 0 +#define RK3066_PLLCON2_NB_MASK 0xfff +#define RK3066_PLLCON2_NB_SHIFT 0 #define RK3066_PLLCON3_RESET (1 << 5) #define RK3066_PLLCON3_PWRDOWN (1 << 1) #define RK3066_PLLCON3_BYPASS (1 << 0) @@ -207,8 +207,8 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(HIWORD_UPDATE(rate->nf - 1, RK3066_PLLCON1_NF_MASK, RK3066_PLLCON1_NF_SHIFT), pll->reg_base + RK3066_PLLCON(1)); - writel_relaxed(HIWORD_UPDATE(rate->bwadj, RK3066_PLLCON2_BWADJ_MASK, - RK3066_PLLCON2_BWADJ_SHIFT), + writel_relaxed(HIWORD_UPDATE(rate->nb - 1, RK3066_PLLCON2_NB_MASK, + RK3066_PLLCON2_NB_SHIFT), pll->reg_base + RK3066_PLLCON(2)); /* leave reset and wait the reset_delay */ @@ -261,7 +261,7 @@ static void rockchip_rk3066_pll_init(struct clk_hw *hw) { struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw); const struct rockchip_pll_rate_table *rate; - unsigned int nf, nr, no, bwadj; + unsigned int nf, nr, no, nb; unsigned long drate; u32 pllcon; @@ -283,13 +283,13 @@ static void rockchip_rk3066_pll_init(struct clk_hw *hw) nf = ((pllcon >> RK3066_PLLCON1_NF_SHIFT) & RK3066_PLLCON1_NF_MASK) + 1; pllcon = readl_relaxed(pll->reg_base + RK3066_PLLCON(2)); - bwadj = (pllcon >> RK3066_PLLCON2_BWADJ_SHIFT) & RK3066_PLLCON2_BWADJ_MASK; + nb = ((pllcon >> RK3066_PLLCON2_NB_SHIFT) & RK3066_PLLCON2_NB_MASK) + 1; - pr_debug("%s: pll %s@%lu: nr (%d:%d); no (%d:%d); nf(%d:%d), bwadj(%d:%d)\n", + pr_debug("%s: pll %s@%lu: nr (%d:%d); no (%d:%d); nf(%d:%d), nb(%d:%d)\n", __func__, __clk_get_name(hw->clk), drate, rate->nr, nr, - rate->no, no, rate->nf, nf, rate->bwadj, bwadj); + rate->no, no, rate->nf, nf, rate->nb, nb); if (rate->nr != nr || rate->no != no || rate->nf != nf - || rate->bwadj != bwadj) { + || rate->nb != nb) { struct clk *parent = __clk_get_parent(hw->clk); unsigned long prate; diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index edbafbcabeb6..0abf22d14401 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -817,7 +817,7 @@ static void __init rk3188_clk_init(struct device_node *np) rate = pll->rate_table; while (rate->rate > 0) { - rate->bwadj = 0; + rate->nb = 1; rate++; } } diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index a8bad7d3a487..0df5bae9ddbf 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -84,7 +84,7 @@ static struct rockchip_pll_rate_table rk3288_pll_rates[] = { RK3066_PLL_RATE( 742500000, 8, 495, 2), RK3066_PLL_RATE( 696000000, 1, 58, 2), RK3066_PLL_RATE( 600000000, 1, 50, 2), - RK3066_PLL_RATE_BWADJ(594000000, 1, 198, 8, 1), + RK3066_PLL_RATE_NB(594000000, 1, 198, 8, 1), RK3066_PLL_RATE( 552000000, 1, 46, 2), RK3066_PLL_RATE( 504000000, 1, 84, 4), RK3066_PLL_RATE( 500000000, 3, 125, 2), diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index 93ea335f2653..dc8ecb2673b7 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h @@ -83,16 +83,16 @@ enum rockchip_pll_type { .nr = _nr, \ .nf = _nf, \ .no = _no, \ - .bwadj = ((_nf) >> 1), \ + .nb = ((_nf) < 2) ? 1 : (_nf) >> 1, \ } -#define RK3066_PLL_RATE_BWADJ(_rate, _nr, _nf, _no, _bw) \ +#define RK3066_PLL_RATE_NB(_rate, _nr, _nf, _no, _nb) \ { \ .rate = _rate##U, \ .nr = _nr, \ .nf = _nf, \ .no = _no, \ - .bwadj = _bw, \ + .nb = _nb, \ } struct rockchip_pll_rate_table { @@ -100,7 +100,7 @@ struct rockchip_pll_rate_table { unsigned int nr; unsigned int nf; unsigned int no; - unsigned int bwadj; + unsigned int nb; }; /** -- cgit v1.3-6-gb490 From 4b5fb7dc9096d949a22651370bb6bf11f21edb30 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 12 Jul 2015 22:49:53 +0200 Subject: clk: pxa: fix core frequency reporting unit Legacy drivers which are not yet ported, such as cpufreq-pxa[23]xx, rely on pxaXXx_get_clk_frequency_khz() to find the CPU core frequency. This reporting was broken because the expected unit is kHz and not Hz. Fix the reporting for pxa25x, pxa27x and pxa3xx. Fixes: fe7710fae477 ("clk: add pxa25x clock drivers") Fixes: d40670dc6169 ("clk: add pxa27x clock drivers") Fixes: 9bbb8a338fb2 ("clk: pxa: add pxa3xx clock driver") Signed-off-by: Robert Jarzmik Signed-off-by: Stephen Boyd --- drivers/clk/pxa/clk-pxa25x.c | 2 +- drivers/clk/pxa/clk-pxa27x.c | 2 +- drivers/clk/pxa/clk-pxa3xx.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/pxa/clk-pxa25x.c b/drivers/clk/pxa/clk-pxa25x.c index 6cd88d963a7f..542e45ef5087 100644 --- a/drivers/clk/pxa/clk-pxa25x.c +++ b/drivers/clk/pxa/clk-pxa25x.c @@ -79,7 +79,7 @@ unsigned int pxa25x_get_clk_frequency_khz(int info) clks[3] / 1000000, (clks[3] % 1000000) / 10000); } - return (unsigned int)clks[0]; + return (unsigned int)clks[0] / KHz; } static unsigned long clk_pxa25x_memory_get_rate(struct clk_hw *hw, diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c index 9a31b77eed23..5b82d30baf9f 100644 --- a/drivers/clk/pxa/clk-pxa27x.c +++ b/drivers/clk/pxa/clk-pxa27x.c @@ -80,7 +80,7 @@ unsigned int pxa27x_get_clk_frequency_khz(int info) pr_info("System bus clock: %ld.%02ldMHz\n", clks[4] / 1000000, (clks[4] % 1000000) / 10000); } - return (unsigned int)clks[0]; + return (unsigned int)clks[0] / KHz; } bool pxa27x_is_ppll_disabled(void) diff --git a/drivers/clk/pxa/clk-pxa3xx.c b/drivers/clk/pxa/clk-pxa3xx.c index 4b93a1efb36d..c677b9ab5367 100644 --- a/drivers/clk/pxa/clk-pxa3xx.c +++ b/drivers/clk/pxa/clk-pxa3xx.c @@ -78,7 +78,7 @@ unsigned int pxa3xx_get_clk_frequency_khz(int info) pr_info("System bus clock: %ld.%02ldMHz\n", clks[4] / 1000000, (clks[4] % 1000000) / 10000); } - return (unsigned int)clks[0]; + return (unsigned int)clks[0] / KHz; } static unsigned long clk_pxa3xx_ac97_get_rate(struct clk_hw *hw, -- cgit v1.3-6-gb490 From 25d4d341d31b349836e1b12d10be34b9b575c12b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 13 Jul 2015 17:07:43 +0300 Subject: clk: socfpga: switch to GENMASK() Convert the code to use GENMASK() helper instead of div_mask() macro. Signed-off-by: Andy Shevchenko Acked-by: Dinh Nguyen Signed-off-by: Stephen Boyd --- drivers/clk/socfpga/clk-gate-a10.c | 2 +- drivers/clk/socfpga/clk-gate.c | 2 +- drivers/clk/socfpga/clk-periph-a10.c | 2 +- drivers/clk/socfpga/clk-periph.c | 2 +- drivers/clk/socfpga/clk.h | 1 - 5 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/socfpga/clk-gate-a10.c b/drivers/clk/socfpga/clk-gate-a10.c index 538ca504dea1..1cebf253e8fd 100644 --- a/drivers/clk/socfpga/clk-gate-a10.c +++ b/drivers/clk/socfpga/clk-gate-a10.c @@ -39,7 +39,7 @@ static unsigned long socfpga_gate_clk_recalc_rate(struct clk_hw *hwclk, div = socfpgaclk->fixed_div; else if (socfpgaclk->div_reg) { val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift; - val &= div_mask(socfpgaclk->width); + val &= GENMASK(socfpgaclk->width - 1, 0); div = (1 << val); } diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c index 37e0bb60ac68..aa7a6e6a15b6 100644 --- a/drivers/clk/socfpga/clk-gate.c +++ b/drivers/clk/socfpga/clk-gate.c @@ -105,7 +105,7 @@ static unsigned long socfpga_clk_recalc_rate(struct clk_hw *hwclk, div = socfpgaclk->fixed_div; else if (socfpgaclk->div_reg) { val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift; - val &= div_mask(socfpgaclk->width); + val &= GENMASK(socfpgaclk->width - 1, 0); /* Check for GPIO_DB_CLK by its offset */ if ((int) socfpgaclk->div_reg & SOCFPGA_GPIO_DB_CLK_OFFSET) div = val + 1; diff --git a/drivers/clk/socfpga/clk-periph-a10.c b/drivers/clk/socfpga/clk-periph-a10.c index 64f93acbbd25..1f397cb72e89 100644 --- a/drivers/clk/socfpga/clk-periph-a10.c +++ b/drivers/clk/socfpga/clk-periph-a10.c @@ -38,7 +38,7 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk, div = socfpgaclk->fixed_div; } else if (socfpgaclk->div_reg) { div = readl(socfpgaclk->div_reg) >> socfpgaclk->shift; - div &= div_mask(socfpgaclk->width); + div &= GENMASK(socfpgaclk->width - 1, 0); div += 1; } else { div = ((readl(socfpgaclk->hw.reg) & 0x7ff) + 1); diff --git a/drivers/clk/socfpga/clk-periph.c b/drivers/clk/socfpga/clk-periph.c index ab9c8164a98f..0c6686331493 100644 --- a/drivers/clk/socfpga/clk-periph.c +++ b/drivers/clk/socfpga/clk-periph.c @@ -35,7 +35,7 @@ static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk, } else { if (socfpgaclk->div_reg) { val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift; - val &= div_mask(socfpgaclk->width); + val &= GENMASK(socfpgaclk->width - 1, 0); parent_rate /= (val + 1); } div = ((readl(socfpgaclk->hw.reg) & 0x1ff) + 1); diff --git a/drivers/clk/socfpga/clk.h b/drivers/clk/socfpga/clk.h index f4219202844a..aa2741dbe81a 100644 --- a/drivers/clk/socfpga/clk.h +++ b/drivers/clk/socfpga/clk.h @@ -26,7 +26,6 @@ #define CLKMGR_PERPLL_SRC 0xAC #define SOCFPGA_MAX_PARENTS 5 -#define div_mask(width) ((1 << (width)) - 1) #define streq(a, b) (strcmp((a), (b)) == 0) #define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \ -- cgit v1.3-6-gb490 From afe76c8fd030dd6b75fa69f7af7b7eb1e212f248 Mon Sep 17 00:00:00 2001 From: Jim Quinlan Date: Fri, 15 May 2015 15:45:47 -0400 Subject: clk: allow a clk divider with max divisor when zero This commit allows certain Broadcom STB clock dividers to be used with clk-divider.c. It allows for a clock whose field value is the equal to the divisor, execpt when the field value is zero, in which case the divisor is 2^width. For example, consider a divisor clock with a two bit field: value divisor 0 4 1 1 2 2 3 3 Signed-off-by: Jim Quinlan Signed-off-by: Michael Turquette --- drivers/clk/clk-divider.c | 16 +++++++++++----- include/linux/clk-provider.h | 4 ++++ 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 706b5783c360..2cab88b9c1a8 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -78,12 +78,14 @@ static unsigned int _get_table_div(const struct clk_div_table *table, } static unsigned int _get_div(const struct clk_div_table *table, - unsigned int val, unsigned long flags) + unsigned int val, unsigned long flags, u8 width) { if (flags & CLK_DIVIDER_ONE_BASED) return val; if (flags & CLK_DIVIDER_POWER_OF_TWO) return 1 << val; + if (flags & CLK_DIVIDER_MAX_AT_ZERO) + return val ? val : div_mask(width) + 1; if (table) return _get_table_div(table, val); return val + 1; @@ -101,12 +103,14 @@ static unsigned int _get_table_val(const struct clk_div_table *table, } static unsigned int _get_val(const struct clk_div_table *table, - unsigned int div, unsigned long flags) + unsigned int div, unsigned long flags, u8 width) { if (flags & CLK_DIVIDER_ONE_BASED) return div; if (flags & CLK_DIVIDER_POWER_OF_TWO) return __ffs(div); + if (flags & CLK_DIVIDER_MAX_AT_ZERO) + return (div == div_mask(width) + 1) ? 0 : div; if (table) return _get_table_val(table, div); return div - 1; @@ -117,9 +121,10 @@ unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, const struct clk_div_table *table, unsigned long flags) { + struct clk_divider *divider = to_clk_divider(hw); unsigned int div; - div = _get_div(table, val, flags); + div = _get_div(table, val, flags, divider->width); if (!div) { WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO), "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", @@ -351,7 +356,8 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, if (divider->flags & CLK_DIVIDER_READ_ONLY) { bestdiv = readl(divider->reg) >> divider->shift; bestdiv &= div_mask(divider->width); - bestdiv = _get_div(divider->table, bestdiv, divider->flags); + bestdiv = _get_div(divider->table, bestdiv, divider->flags, + divider->width); return DIV_ROUND_UP(*prate, bestdiv); } @@ -370,7 +376,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate, if (!_is_valid_div(table, div, flags)) return -EINVAL; - value = _get_val(table, div, flags); + value = _get_val(table, div, flags, width); return min_t(unsigned int, value, div_mask(width)); } diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 402478ed9933..699a25075170 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -361,6 +361,9 @@ struct clk_div_table { * to the closest integer instead of the up one. * CLK_DIVIDER_READ_ONLY - The divider settings are preconfigured and should * not be changed by the clock framework. + * CLK_DIVIDER_MAX_AT_ZERO - For dividers which are like CLK_DIVIDER_ONE_BASED + * except when the value read from the register is zero, the divisor is + * 2^width of the field. */ struct clk_divider { struct clk_hw hw; @@ -378,6 +381,7 @@ struct clk_divider { #define CLK_DIVIDER_HIWORD_MASK BIT(3) #define CLK_DIVIDER_ROUND_CLOSEST BIT(4) #define CLK_DIVIDER_READ_ONLY BIT(5) +#define CLK_DIVIDER_MAX_AT_ZERO BIT(6) extern const struct clk_ops clk_divider_ops; -- cgit v1.3-6-gb490 From 37bff2c159a3629b592e54162239cb8c337c965d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 24 Jul 2015 09:31:29 -0700 Subject: clk: gpio: Mark parent_names array const Let's encourage const arrays of parent names like other basic clock types. Cc: Sergej Sawazki Signed-off-by: Stephen Boyd --- drivers/clk/clk-gpio.c | 13 +++++++------ include/linux/clk-provider.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 41277a1526c7..10819e248414 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -95,7 +95,7 @@ const struct clk_ops clk_gpio_mux_ops = { EXPORT_SYMBOL_GPL(clk_gpio_mux_ops); static struct clk *clk_register_gpio(struct device *dev, const char *name, - const char **parent_names, u8 num_parents, unsigned gpio, + const char * const *parent_names, u8 num_parents, unsigned gpio, bool active_low, unsigned long flags, const struct clk_ops *clk_gpio_ops) { @@ -188,7 +188,7 @@ EXPORT_SYMBOL_GPL(clk_register_gpio_gate); * @flags: clock flags */ struct clk *clk_register_gpio_mux(struct device *dev, const char *name, - const char **parent_names, u8 num_parents, unsigned gpio, + const char * const *parent_names, u8 num_parents, unsigned gpio, bool active_low, unsigned long flags) { if (num_parents != 2) { @@ -213,7 +213,7 @@ struct clk_gpio_delayed_register_data { struct mutex lock; struct clk *clk; struct clk *(*clk_register_get)(const char *name, - const char **parent_names, u8 num_parents, + const char * const *parent_names, u8 num_parents, unsigned gpio, bool active_low); }; @@ -273,7 +273,7 @@ out: } static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name, - const char **parent_names, u8 num_parents, + const char * const *parent_names, u8 num_parents, unsigned gpio, bool active_low) { return clk_register_gpio_gate(NULL, name, parent_names[0], @@ -281,7 +281,7 @@ static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name, } static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name, - const char **parent_names, u8 num_parents, unsigned gpio, + const char * const *parent_names, u8 num_parents, unsigned gpio, bool active_low) { return clk_register_gpio_mux(NULL, name, parent_names, num_parents, @@ -291,7 +291,8 @@ static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name, static void __init of_gpio_clk_setup(struct device_node *node, const char *gpio_name, struct clk *(*clk_register_get)(const char *name, - const char **parent_names, u8 num_parents, + const char * const *parent_names, + u8 num_parents, unsigned gpio, bool active_low)) { struct clk_gpio_delayed_register_data *data; diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 699a25075170..06a56e55cfaf 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -583,7 +583,7 @@ void of_gpio_clk_gate_setup(struct device_node *node); extern const struct clk_ops clk_gpio_mux_ops; struct clk *clk_register_gpio_mux(struct device *dev, const char *name, - const char **parent_names, u8 num_parents, unsigned gpio, + const char * const *parent_names, u8 num_parents, unsigned gpio, bool active_low, unsigned long flags); void of_gpio_mux_clk_setup(struct device_node *node); -- cgit v1.3-6-gb490 From 169f05e80522e2848c9089a17976ebf31e735d5c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 24 Jul 2015 11:55:42 -0700 Subject: clk: qcom: Give clk-qcom.ko module a GPLv2 license The missing license causes the clk-qcom.ko module to taint the kernel. Add the appropriate license to avoid taint. Signed-off-by: Stephen Boyd --- drivers/clk/qcom/common.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index f7101e330b1d..34e60c552cea 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -144,3 +145,5 @@ void qcom_cc_remove(struct platform_device *pdev) reset_controller_unregister(platform_get_drvdata(pdev)); } EXPORT_SYMBOL_GPL(qcom_cc_remove); + +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From 661e2180cf050a2f859d466f30d74e990b9345be Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 24 Jul 2015 12:21:12 -0700 Subject: clk: basic-type: Silence warnings about lock imbalances The basic clock types use conditional locking for the register accessor spinlocks. Add __acquire() and __release() markings in the right locations so that sparse isn't tripped up on the conditional locking. drivers/clk/clk-mux.c:68:12: warning: context imbalance in 'clk_mux_set_parent' - different lock contexts for basic block drivers/clk/clk-divider.c:379:12: warning: context imbalance in 'clk_divider_set_rate' - different lock contexts for basic block drivers/clk/clk-gate.c:71:9: warning: context imbalance in 'clk_gate_endisable' - different lock contexts for basic block drivers/clk/clk-fractional-divider.c:36:9: warning: context imbalance in 'clk_fd_recalc_rate' - different lock contexts for basic block drivers/clk/clk-fractional-divider.c:68:12: warning: context imbalance in 'clk_fd_set_rate' - different lock contexts for basic block Cc: Andy Shevchenko Signed-off-by: Stephen Boyd --- drivers/clk/clk-divider.c | 4 ++++ drivers/clk/clk-fractional-divider.c | 8 ++++++++ drivers/clk/clk-gate.c | 4 ++++ drivers/clk/clk-mux.c | 4 ++++ 4 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 2cab88b9c1a8..a417162537b8 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -395,6 +395,8 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, if (divider->lock) spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { val = div_mask(divider->width) << (divider->shift + 16); @@ -407,6 +409,8 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, if (divider->lock) spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); return 0; } diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index 140eb5844dc4..e85f856b8592 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -27,11 +27,15 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, if (fd->lock) spin_lock_irqsave(fd->lock, flags); + else + __acquire(fd->lock); val = clk_readl(fd->reg); if (fd->lock) spin_unlock_irqrestore(fd->lock, flags); + else + __release(fd->lock); m = (val & fd->mmask) >> fd->mshift; n = (val & fd->nmask) >> fd->nshift; @@ -80,6 +84,8 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, if (fd->lock) spin_lock_irqsave(fd->lock, flags); + else + __acquire(fd->lock); val = clk_readl(fd->reg); val &= ~(fd->mmask | fd->nmask); @@ -88,6 +94,8 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate, if (fd->lock) spin_unlock_irqrestore(fd->lock, flags); + else + __release(fd->lock); return 0; } diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index 551dd0672794..de0b322f5f58 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -52,6 +52,8 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable) if (gate->lock) spin_lock_irqsave(gate->lock, flags); + else + __acquire(gate->lock); if (gate->flags & CLK_GATE_HIWORD_MASK) { reg = BIT(gate->bit_idx + 16); @@ -70,6 +72,8 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable) if (gate->lock) spin_unlock_irqrestore(gate->lock, flags); + else + __release(gate->lock); } static int clk_gate_enable(struct clk_hw *hw) diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index c705cf573569..33c09a3bfa51 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -84,6 +84,8 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) if (mux->lock) spin_lock_irqsave(mux->lock, flags); + else + __acquire(mux->lock); if (mux->flags & CLK_MUX_HIWORD_MASK) { val = mux->mask << (mux->shift + 16); @@ -96,6 +98,8 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) if (mux->lock) spin_unlock_irqrestore(mux->lock, flags); + else + __release(mux->lock); return 0; } -- cgit v1.3-6-gb490 From a57aa18539f8b232065f574f438edb646c6b9d9b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 24 Jul 2015 12:24:48 -0700 Subject: clk: Silence warnings about lock imbalances The recursive spinlock implementation trips up sparse and it complains that these functions have lock imbalances. That isn't really true though, so add some __acquires() and __releases() information so that sparse is quiet. drivers/clk/clk.c:116:22: warning: context imbalance in 'clk_enable_lock' - wrong count at exit drivers/clk/clk.c:141:9: warning: context imbalance in 'clk_enable_unlock' - unexpected unlock Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 819ffa6db83d..898052ee0efa 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -114,12 +114,14 @@ static void clk_prepare_unlock(void) } static unsigned long clk_enable_lock(void) + __acquires(enable_lock) { unsigned long flags; if (!spin_trylock_irqsave(&enable_lock, flags)) { if (enable_owner == current) { enable_refcnt++; + __acquire(enable_lock); return flags; } spin_lock_irqsave(&enable_lock, flags); @@ -132,12 +134,15 @@ static unsigned long clk_enable_lock(void) } static void clk_enable_unlock(unsigned long flags) + __releases(enable_lock) { WARN_ON_ONCE(enable_owner != current); WARN_ON_ONCE(enable_refcnt == 0); - if (--enable_refcnt) + if (--enable_refcnt) { + __release(enable_lock); return; + } enable_owner = NULL; spin_unlock_irqrestore(&enable_lock, flags); } -- cgit v1.3-6-gb490 From 7764d0cdc3dbf15010f66e0e2e5786f0f03d402a Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Wed, 22 Jul 2015 15:04:53 +0530 Subject: clk: s2mps11: Use kcalloc instead of kzalloc for array allocation This patch cleans up the driver for, - Use devm_kcalloc() variant instead of devm_kzalloc() for array allocation. - clk_prepare()/unprepare(), remove "ret" variable as it is not required - use __exit for cleanup function As I am referring this driver as a reference for my 88pm800 clk driver, applying same changes here as well. Signed-off-by: Vaibhav Hiremath Tested-by: Anand Moon Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stephen Boyd --- drivers/clk/clk-s2mps11.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index ba7fb1b8c182..d266299dfdb1 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -58,21 +58,17 @@ static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw) static int s2mps11_clk_prepare(struct clk_hw *hw) { struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw); - int ret; - ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, + return regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg, s2mps11->mask, s2mps11->mask); - - return ret; } 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, + regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg, s2mps11->mask, ~s2mps11->mask); } @@ -186,15 +182,15 @@ static int s2mps11_clk_probe(struct platform_device *pdev) struct clk_init_data *clks_init; int i, ret = 0; - s2mps11_clks = devm_kzalloc(&pdev->dev, sizeof(*s2mps11_clk) * - S2MPS11_CLKS_NUM, GFP_KERNEL); + s2mps11_clks = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM, + sizeof(*s2mps11_clk), GFP_KERNEL); if (!s2mps11_clks) return -ENOMEM; s2mps11_clk = s2mps11_clks; - clk_table = devm_kzalloc(&pdev->dev, sizeof(struct clk *) * - S2MPS11_CLKS_NUM, GFP_KERNEL); + clk_table = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM, + sizeof(struct clk *), GFP_KERNEL); if (!clk_table) return -ENOMEM; @@ -316,7 +312,7 @@ static int __init s2mps11_clk_init(void) } subsys_initcall(s2mps11_clk_init); -static void __init s2mps11_clk_cleanup(void) +static void __exit s2mps11_clk_cleanup(void) { platform_driver_unregister(&s2mps11_clk_driver); } -- cgit v1.3-6-gb490 From 4599dd2c926915b5e8c27e0ca21a6172f9d6881c Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Thu, 23 Jul 2015 15:02:51 +0800 Subject: clk: zx: Add audio div clock method for zx296702 Add SPDIF/I2S divider clock method for zx296702 Signed-off-by: Jun Nie Signed-off-by: Stephen Boyd --- drivers/clk/zte/Makefile | 2 +- drivers/clk/zte/clk-pll.c | 172 -------------------------- drivers/clk/zte/clk.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/zte/clk.h | 9 ++ 4 files changed, 319 insertions(+), 173 deletions(-) delete mode 100644 drivers/clk/zte/clk-pll.c create mode 100644 drivers/clk/zte/clk.c (limited to 'drivers') diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile index 95b707c18108..74005aa322a2 100644 --- a/drivers/clk/zte/Makefile +++ b/drivers/clk/zte/Makefile @@ -1,2 +1,2 @@ -obj-y := clk-pll.o +obj-y := clk.o obj-$(CONFIG_SOC_ZX296702) += clk-zx296702.o diff --git a/drivers/clk/zte/clk-pll.c b/drivers/clk/zte/clk-pll.c deleted file mode 100644 index c3b221ae6cd7..000000000000 --- a/drivers/clk/zte/clk-pll.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2014 Linaro Ltd. - * Copyright (C) 2014 ZTE 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 - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include "clk.h" - -#define to_clk_zx_pll(_hw) container_of(_hw, struct clk_zx_pll, hw) - -#define CFG0_CFG1_OFFSET 4 -#define LOCK_FLAG BIT(30) -#define POWER_DOWN BIT(31) - -static int rate_to_idx(struct clk_zx_pll *zx_pll, unsigned long rate) -{ - const struct zx_pll_config *config = zx_pll->lookup_table; - int i; - - for (i = 0; i < zx_pll->count; i++) { - if (config[i].rate > rate) - return i > 0 ? i - 1 : 0; - - if (config[i].rate == rate) - return i; - } - - return i - 1; -} - -static int hw_to_idx(struct clk_zx_pll *zx_pll) -{ - const struct zx_pll_config *config = zx_pll->lookup_table; - u32 hw_cfg0, hw_cfg1; - int i; - - hw_cfg0 = readl_relaxed(zx_pll->reg_base); - hw_cfg1 = readl_relaxed(zx_pll->reg_base + CFG0_CFG1_OFFSET); - - /* For matching the value in lookup table */ - hw_cfg0 &= ~LOCK_FLAG; - hw_cfg0 |= POWER_DOWN; - - for (i = 0; i < zx_pll->count; i++) { - if (hw_cfg0 == config[i].cfg0 && hw_cfg1 == config[i].cfg1) - return i; - } - - return -EINVAL; -} - -static unsigned long zx_pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); - int idx; - - idx = hw_to_idx(zx_pll); - if (unlikely(idx == -EINVAL)) - return 0; - - return zx_pll->lookup_table[idx].rate; -} - -static long zx_pll_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); - int idx; - - idx = rate_to_idx(zx_pll, rate); - - return zx_pll->lookup_table[idx].rate; -} - -static int zx_pll_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - /* Assume current cpu is not running on current PLL */ - struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); - const struct zx_pll_config *config; - int idx; - - idx = rate_to_idx(zx_pll, rate); - config = &zx_pll->lookup_table[idx]; - - writel_relaxed(config->cfg0, zx_pll->reg_base); - writel_relaxed(config->cfg1, zx_pll->reg_base + CFG0_CFG1_OFFSET); - - return 0; -} - -static int zx_pll_enable(struct clk_hw *hw) -{ - struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); - u32 reg; - - reg = readl_relaxed(zx_pll->reg_base); - writel_relaxed(reg & ~POWER_DOWN, zx_pll->reg_base); - - return readl_relaxed_poll_timeout(zx_pll->reg_base, reg, - reg & LOCK_FLAG, 0, 100); -} - -static void zx_pll_disable(struct clk_hw *hw) -{ - struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); - u32 reg; - - reg = readl_relaxed(zx_pll->reg_base); - writel_relaxed(reg | POWER_DOWN, zx_pll->reg_base); -} - -static int zx_pll_is_enabled(struct clk_hw *hw) -{ - struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); - u32 reg; - - reg = readl_relaxed(zx_pll->reg_base); - - return !(reg & POWER_DOWN); -} - -static const struct clk_ops zx_pll_ops = { - .recalc_rate = zx_pll_recalc_rate, - .round_rate = zx_pll_round_rate, - .set_rate = zx_pll_set_rate, - .enable = zx_pll_enable, - .disable = zx_pll_disable, - .is_enabled = zx_pll_is_enabled, -}; - -struct clk *clk_register_zx_pll(const char *name, const char *parent_name, - unsigned long flags, void __iomem *reg_base, - const struct zx_pll_config *lookup_table, int count, spinlock_t *lock) -{ - struct clk_zx_pll *zx_pll; - struct clk *clk; - struct clk_init_data init; - - zx_pll = kzalloc(sizeof(*zx_pll), GFP_KERNEL); - if (!zx_pll) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &zx_pll_ops; - init.flags = flags; - init.parent_names = parent_name ? &parent_name : NULL; - init.num_parents = parent_name ? 1 : 0; - - zx_pll->reg_base = reg_base; - zx_pll->lookup_table = lookup_table; - zx_pll->count = count; - zx_pll->lock = lock; - zx_pll->hw.init = &init; - - clk = clk_register(NULL, &zx_pll->hw); - if (IS_ERR(clk)) - kfree(zx_pll); - - return clk; -} diff --git a/drivers/clk/zte/clk.c b/drivers/clk/zte/clk.c new file mode 100644 index 000000000000..7c73c538c43d --- /dev/null +++ b/drivers/clk/zte/clk.c @@ -0,0 +1,309 @@ +/* + * Copyright 2014 Linaro Ltd. + * Copyright (C) 2014 ZTE 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 + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define to_clk_zx_pll(_hw) container_of(_hw, struct clk_zx_pll, hw) +#define to_clk_zx_audio(_hw) container_of(_hw, struct clk_zx_audio, hw) + +#define CFG0_CFG1_OFFSET 4 +#define LOCK_FLAG BIT(30) +#define POWER_DOWN BIT(31) + +static int rate_to_idx(struct clk_zx_pll *zx_pll, unsigned long rate) +{ + const struct zx_pll_config *config = zx_pll->lookup_table; + int i; + + for (i = 0; i < zx_pll->count; i++) { + if (config[i].rate > rate) + return i > 0 ? i - 1 : 0; + + if (config[i].rate == rate) + return i; + } + + return i - 1; +} + +static int hw_to_idx(struct clk_zx_pll *zx_pll) +{ + const struct zx_pll_config *config = zx_pll->lookup_table; + u32 hw_cfg0, hw_cfg1; + int i; + + hw_cfg0 = readl_relaxed(zx_pll->reg_base); + hw_cfg1 = readl_relaxed(zx_pll->reg_base + CFG0_CFG1_OFFSET); + + /* For matching the value in lookup table */ + hw_cfg0 &= ~LOCK_FLAG; + hw_cfg0 |= POWER_DOWN; + + for (i = 0; i < zx_pll->count; i++) { + if (hw_cfg0 == config[i].cfg0 && hw_cfg1 == config[i].cfg1) + return i; + } + + return -EINVAL; +} + +static unsigned long zx_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); + int idx; + + idx = hw_to_idx(zx_pll); + if (unlikely(idx == -EINVAL)) + return 0; + + return zx_pll->lookup_table[idx].rate; +} + +static long zx_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); + int idx; + + idx = rate_to_idx(zx_pll, rate); + + return zx_pll->lookup_table[idx].rate; +} + +static int zx_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + /* Assume current cpu is not running on current PLL */ + struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); + const struct zx_pll_config *config; + int idx; + + idx = rate_to_idx(zx_pll, rate); + config = &zx_pll->lookup_table[idx]; + + writel_relaxed(config->cfg0, zx_pll->reg_base); + writel_relaxed(config->cfg1, zx_pll->reg_base + CFG0_CFG1_OFFSET); + + return 0; +} + +static int zx_pll_enable(struct clk_hw *hw) +{ + struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); + u32 reg; + + reg = readl_relaxed(zx_pll->reg_base); + writel_relaxed(reg & ~POWER_DOWN, zx_pll->reg_base); + + return readl_relaxed_poll_timeout(zx_pll->reg_base, reg, + reg & LOCK_FLAG, 0, 100); +} + +static void zx_pll_disable(struct clk_hw *hw) +{ + struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); + u32 reg; + + reg = readl_relaxed(zx_pll->reg_base); + writel_relaxed(reg | POWER_DOWN, zx_pll->reg_base); +} + +static int zx_pll_is_enabled(struct clk_hw *hw) +{ + struct clk_zx_pll *zx_pll = to_clk_zx_pll(hw); + u32 reg; + + reg = readl_relaxed(zx_pll->reg_base); + + return !(reg & POWER_DOWN); +} + +static const struct clk_ops zx_pll_ops = { + .recalc_rate = zx_pll_recalc_rate, + .round_rate = zx_pll_round_rate, + .set_rate = zx_pll_set_rate, + .enable = zx_pll_enable, + .disable = zx_pll_disable, + .is_enabled = zx_pll_is_enabled, +}; + +struct clk *clk_register_zx_pll(const char *name, const char *parent_name, + unsigned long flags, void __iomem *reg_base, + const struct zx_pll_config *lookup_table, + int count, spinlock_t *lock) +{ + struct clk_zx_pll *zx_pll; + struct clk *clk; + struct clk_init_data init; + + zx_pll = kzalloc(sizeof(*zx_pll), GFP_KERNEL); + if (!zx_pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &zx_pll_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + zx_pll->reg_base = reg_base; + zx_pll->lookup_table = lookup_table; + zx_pll->count = count; + zx_pll->lock = lock; + zx_pll->hw.init = &init; + + clk = clk_register(NULL, &zx_pll->hw); + if (IS_ERR(clk)) + kfree(zx_pll); + + return clk; +} + +#define BPAR 1000000 +static u32 calc_reg(u32 parent_rate, u32 rate) +{ + u32 sel, integ, fra_div, tmp; + u64 tmp64 = (u64)parent_rate * BPAR; + + do_div(tmp64, rate); + integ = (u32)tmp64 / BPAR; + integ = integ >> 1; + + tmp = (u32)tmp64 % BPAR; + sel = tmp / BPAR; + + tmp = tmp % BPAR; + fra_div = tmp * 0xff / BPAR; + tmp = (sel << 24) | (integ << 16) | (0xff << 8) | fra_div; + + /* Set I2S integer divider as 1. This bit is reserved for SPDIF + * and do no harm. + */ + tmp |= BIT(28); + return tmp; +} + +static u32 calc_rate(u32 reg, u32 parent_rate) +{ + u32 sel, integ, fra_div, tmp; + u64 tmp64 = (u64)parent_rate * BPAR; + + tmp = reg; + sel = (tmp >> 24) & BIT(0); + integ = (tmp >> 16) & 0xff; + fra_div = tmp & 0xff; + + tmp = fra_div * BPAR; + tmp = tmp / 0xff; + tmp += sel * BPAR; + tmp += 2 * integ * BPAR; + do_div(tmp64, tmp); + + return (u32)tmp64; +} + +static unsigned long zx_audio_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_zx_audio *zx_audio = to_clk_zx_audio(hw); + u32 reg; + + reg = readl_relaxed(zx_audio->reg_base); + return calc_rate(reg, parent_rate); +} + +static long zx_audio_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + u32 reg; + + if (rate * 2 > *prate) + return -EINVAL; + + reg = calc_reg(*prate, rate); + return calc_rate(reg, *prate); +} + +static int zx_audio_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_zx_audio *zx_audio = to_clk_zx_audio(hw); + u32 reg; + + reg = calc_reg(parent_rate, rate); + writel_relaxed(reg, zx_audio->reg_base); + + return 0; +} + +#define ZX_AUDIO_EN BIT(25) +static int zx_audio_enable(struct clk_hw *hw) +{ + struct clk_zx_audio *zx_audio = to_clk_zx_audio(hw); + u32 reg; + + reg = readl_relaxed(zx_audio->reg_base); + writel_relaxed(reg & ~ZX_AUDIO_EN, zx_audio->reg_base); + return 0; +} + +static void zx_audio_disable(struct clk_hw *hw) +{ + struct clk_zx_audio *zx_audio = to_clk_zx_audio(hw); + u32 reg; + + reg = readl_relaxed(zx_audio->reg_base); + writel_relaxed(reg | ZX_AUDIO_EN, zx_audio->reg_base); +} + +static const struct clk_ops zx_audio_ops = { + .recalc_rate = zx_audio_recalc_rate, + .round_rate = zx_audio_round_rate, + .set_rate = zx_audio_set_rate, + .enable = zx_audio_enable, + .disable = zx_audio_disable, +}; + +struct clk *clk_register_zx_audio(const char *name, + const char * const parent_name, + unsigned long flags, + void __iomem *reg_base) +{ + struct clk_zx_audio *zx_audio; + struct clk *clk; + struct clk_init_data init; + + zx_audio = kzalloc(sizeof(*zx_audio), GFP_KERNEL); + if (!zx_audio) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &zx_audio_ops; + init.flags = flags; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + + zx_audio->reg_base = reg_base; + zx_audio->hw.init = &init; + + clk = clk_register(NULL, &zx_audio->hw); + if (IS_ERR(clk)) + kfree(zx_audio); + + return clk; +} diff --git a/drivers/clk/zte/clk.h b/drivers/clk/zte/clk.h index 0914a82d0535..65ae08b818d3 100644 --- a/drivers/clk/zte/clk.h +++ b/drivers/clk/zte/clk.h @@ -29,4 +29,13 @@ struct clk_zx_pll { struct clk *clk_register_zx_pll(const char *name, const char *parent_name, unsigned long flags, void __iomem *reg_base, const struct zx_pll_config *lookup_table, int count, spinlock_t *lock); + +struct clk_zx_audio { + struct clk_hw hw; + void __iomem *reg_base; +}; + +struct clk *clk_register_zx_audio(const char *name, + const char * const parent_name, + unsigned long flags, void __iomem *reg_base); #endif -- cgit v1.3-6-gb490 From 105644e59a2b1c43fe2eeba6595d142c390552c2 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Thu, 23 Jul 2015 15:02:52 +0800 Subject: clk: zx: Add audio and GPIO clock for zx296702 Add SPDIF/I2S and GPIO clock for zx296702 Signed-off-by: Jun Nie Signed-off-by: Stephen Boyd --- drivers/clk/zte/clk-zx296702.c | 92 +++++++++++++++++++++++++++++- include/dt-bindings/clock/zx296702-clock.h | 17 +++++- 2 files changed, 105 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/zte/clk-zx296702.c b/drivers/clk/zte/clk-zx296702.c index 929d033594af..9dcac73480ba 100644 --- a/drivers/clk/zte/clk-zx296702.c +++ b/drivers/clk/zte/clk-zx296702.c @@ -36,10 +36,21 @@ static struct clk_onecell_data lsp1clk_data; #define CLK_MUX1 (topcrm_base + 0x8c) #define CLK_SDMMC1 (lsp0crpm_base + 0x0c) +#define CLK_GPIO (lsp0crpm_base + 0x2c) +#define CLK_SPDIF0 (lsp0crpm_base + 0x10) +#define SPDIF0_DIV (lsp0crpm_base + 0x14) +#define CLK_I2S0 (lsp0crpm_base + 0x18) +#define I2S0_DIV (lsp0crpm_base + 0x1c) +#define CLK_I2S1 (lsp0crpm_base + 0x20) +#define I2S1_DIV (lsp0crpm_base + 0x24) +#define CLK_I2S2 (lsp0crpm_base + 0x34) +#define I2S2_DIV (lsp0crpm_base + 0x38) #define CLK_UART0 (lsp1crpm_base + 0x20) #define CLK_UART1 (lsp1crpm_base + 0x24) #define CLK_SDMMC0 (lsp1crpm_base + 0x2c) +#define CLK_SPDIF1 (lsp1crpm_base + 0x30) +#define SPDIF1_DIV (lsp1crpm_base + 0x34) static const struct zx_pll_config pll_a9_config[] = { { .rate = 700000000, .cfg0 = 0x800405d1, .cfg1 = 0x04555555 }, @@ -170,6 +181,21 @@ static const char * uart_wclk_sel[] = { "lsp1_26M_wclk", }; +static const char * spdif0_wclk_sel[] = { + "lsp0_104M_wclk", + "lsp0_26M_wclk", +}; + +static const char * spdif1_wclk_sel[] = { + "lsp1_104M_wclk", + "lsp1_26M_wclk", +}; + +static const char * i2s_wclk_sel[] = { + "lsp0_104M_wclk", + "lsp0_26M_wclk", +}; + static inline struct clk *zx_divtbl(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width, const struct clk_div_table *table) @@ -196,7 +222,7 @@ static inline struct clk *zx_gate(const char *name, const char *parent, void __iomem *reg, u8 shift) { return clk_register_gate(NULL, name, parent, CLK_IGNORE_UNUSED, - reg, shift, 0, ®_lock); + reg, shift, CLK_SET_RATE_PARENT, ®_lock); } static void __init zx296702_top_clocks_init(struct device_node *np) @@ -585,7 +611,57 @@ static void __init zx296702_lsp0_clocks_init(struct device_node *np) clk[ZX296702_SDMMC1_WCLK] = zx_gate("sdmmc1_wclk", "sdmmc1_wclk_div", CLK_SDMMC1, 1); clk[ZX296702_SDMMC1_PCLK] = - zx_gate("sdmmc1_pclk", "lsp1_apb_pclk", CLK_SDMMC1, 0); + zx_gate("sdmmc1_pclk", "lsp0_apb_pclk", CLK_SDMMC1, 0); + + clk[ZX296702_GPIO_CLK] = + zx_gate("gpio_clk", "lsp0_apb_pclk", CLK_GPIO, 0); + + /* SPDIF */ + clk[ZX296702_SPDIF0_WCLK_MUX] = + zx_mux("spdif0_wclk_mux", spdif0_wclk_sel, + ARRAY_SIZE(spdif0_wclk_sel), CLK_SPDIF0, 4, 1); + clk[ZX296702_SPDIF0_WCLK] = + zx_gate("spdif0_wclk", "spdif0_wclk_mux", CLK_SPDIF0, 1); + clk[ZX296702_SPDIF0_PCLK] = + zx_gate("spdif0_pclk", "lsp0_apb_pclk", CLK_SPDIF0, 0); + + clk[ZX296702_SPDIF0_DIV] = + clk_register_zx_audio("spdif0_div", "spdif0_wclk", 0, + SPDIF0_DIV); + + /* I2S */ + clk[ZX296702_I2S0_WCLK_MUX] = + zx_mux("i2s0_wclk_mux", i2s_wclk_sel, + ARRAY_SIZE(i2s_wclk_sel), CLK_I2S0, 4, 1); + clk[ZX296702_I2S0_WCLK] = + zx_gate("i2s0_wclk", "i2s0_wclk_mux", CLK_I2S0, 1); + clk[ZX296702_I2S0_PCLK] = + zx_gate("i2s0_pclk", "lsp0_apb_pclk", CLK_I2S0, 0); + + clk[ZX296702_I2S0_DIV] = + clk_register_zx_audio("i2s0_div", "i2s0_wclk", 0, I2S0_DIV); + + clk[ZX296702_I2S1_WCLK_MUX] = + zx_mux("i2s1_wclk_mux", i2s_wclk_sel, + ARRAY_SIZE(i2s_wclk_sel), CLK_I2S1, 4, 1); + clk[ZX296702_I2S1_WCLK] = + zx_gate("i2s1_wclk", "i2s1_wclk_mux", CLK_I2S1, 1); + clk[ZX296702_I2S1_PCLK] = + zx_gate("i2s1_pclk", "lsp0_apb_pclk", CLK_I2S1, 0); + + clk[ZX296702_I2S1_DIV] = + clk_register_zx_audio("i2s1_div", "i2s1_wclk", 0, I2S1_DIV); + + clk[ZX296702_I2S2_WCLK_MUX] = + zx_mux("i2s2_wclk_mux", i2s_wclk_sel, + ARRAY_SIZE(i2s_wclk_sel), CLK_I2S2, 4, 1); + clk[ZX296702_I2S2_WCLK] = + zx_gate("i2s2_wclk", "i2s2_wclk_mux", CLK_I2S2, 1); + clk[ZX296702_I2S2_PCLK] = + zx_gate("i2s2_pclk", "lsp0_apb_pclk", CLK_I2S2, 0); + + clk[ZX296702_I2S2_DIV] = + clk_register_zx_audio("i2s2_div", "i2s2_wclk", 0, I2S2_DIV); for (i = 0; i < ARRAY_SIZE(lsp0clk); i++) { if (IS_ERR(clk[i])) { @@ -641,6 +717,18 @@ static void __init zx296702_lsp1_clocks_init(struct device_node *np) clk[ZX296702_SDMMC0_PCLK] = zx_gate("sdmmc0_pclk", "lsp1_apb_pclk", CLK_SDMMC0, 0); + clk[ZX296702_SPDIF1_WCLK_MUX] = + zx_mux("spdif1_wclk_mux", spdif1_wclk_sel, + ARRAY_SIZE(spdif1_wclk_sel), CLK_SPDIF1, 4, 1); + clk[ZX296702_SPDIF1_WCLK] = + zx_gate("spdif1_wclk", "spdif1_wclk_mux", CLK_SPDIF1, 1); + clk[ZX296702_SPDIF1_PCLK] = + zx_gate("spdif1_pclk", "lsp1_apb_pclk", CLK_SPDIF1, 0); + + clk[ZX296702_SPDIF1_DIV] = + clk_register_zx_audio("spdif1_div", "spdif1_wclk", 0, + SPDIF1_DIV); + for (i = 0; i < ARRAY_SIZE(lsp1clk); i++) { if (IS_ERR(clk[i])) { pr_err("zx296702 clk %d: register failed with %ld\n", diff --git a/include/dt-bindings/clock/zx296702-clock.h b/include/dt-bindings/clock/zx296702-clock.h index e683dbb7e7c5..26ee564b0e68 100644 --- a/include/dt-bindings/clock/zx296702-clock.h +++ b/include/dt-bindings/clock/zx296702-clock.h @@ -153,7 +153,16 @@ #define ZX296702_I2S0_WCLK 9 #define ZX296702_I2S0_PCLK 10 #define ZX296702_I2S0_DIV 11 -#define ZX296702_LSP0CLK_END 12 +#define ZX296702_I2S1_WCLK_MUX 12 +#define ZX296702_I2S1_WCLK 13 +#define ZX296702_I2S1_PCLK 14 +#define ZX296702_I2S1_DIV 15 +#define ZX296702_I2S2_WCLK_MUX 16 +#define ZX296702_I2S2_WCLK 17 +#define ZX296702_I2S2_PCLK 18 +#define ZX296702_I2S2_DIV 19 +#define ZX296702_GPIO_CLK 20 +#define ZX296702_LSP0CLK_END 21 #define ZX296702_UART0_WCLK_MUX 0 #define ZX296702_UART0_WCLK 1 @@ -165,6 +174,10 @@ #define ZX296702_SDMMC0_WCLK_DIV 7 #define ZX296702_SDMMC0_WCLK 8 #define ZX296702_SDMMC0_PCLK 9 -#define ZX296702_LSP1CLK_END 10 +#define ZX296702_SPDIF1_WCLK_MUX 10 +#define ZX296702_SPDIF1_WCLK 11 +#define ZX296702_SPDIF1_PCLK 12 +#define ZX296702_SPDIF1_DIV 13 +#define ZX296702_LSP1CLK_END 14 #endif /* __DT_BINDINGS_CLOCK_ZX296702_H */ -- cgit v1.3-6-gb490 From d99215ae06be51558b723a3648515e672898ca4b Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Thu, 23 Jul 2015 15:02:53 +0800 Subject: clk: zx: Constify parent names in clock init data The array of parent names can be made as array of const pointers to const strings. Signed-off-by: Jun Nie Signed-off-by: Stephen Boyd --- drivers/clk/zte/clk-zx296702.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/zte/clk-zx296702.c b/drivers/clk/zte/clk-zx296702.c index 9dcac73480ba..ebd20d852e73 100644 --- a/drivers/clk/zte/clk-zx296702.c +++ b/drivers/clk/zte/clk-zx296702.c @@ -83,115 +83,115 @@ static const struct clk_div_table sec_wclk_divider[] = { { /* sentinel */ } }; -static const char * matrix_aclk_sel[] = { +static const char * const matrix_aclk_sel[] = { "pll_mm0_198M", "osc", "clk_148M5", "pll_lsp_104M", }; -static const char * a9_wclk_sel[] = { +static const char * const a9_wclk_sel[] = { "pll_a9", "osc", "clk_500", "clk_250", }; -static const char * a9_as1_aclk_sel[] = { +static const char * const a9_as1_aclk_sel[] = { "clk_250", "osc", "pll_mm0_396M", "pll_mac_333M", }; -static const char * a9_trace_clkin_sel[] = { +static const char * const a9_trace_clkin_sel[] = { "clk_74M25", "pll_mm1_108M", "clk_125", "clk_148M5", }; -static const char * decppu_aclk_sel[] = { +static const char * const decppu_aclk_sel[] = { "clk_250", "pll_mm0_198M", "pll_lsp_104M", "pll_audio_294M912", }; -static const char * vou_main_wclk_sel[] = { +static const char * const vou_main_wclk_sel[] = { "clk_148M5", "clk_74M25", "clk_27", "pll_mm1_54M", }; -static const char * vou_scaler_wclk_sel[] = { +static const char * const vou_scaler_wclk_sel[] = { "clk_250", "pll_mac_333M", "pll_audio_294M912", "pll_mm0_198M", }; -static const char * r2d_wclk_sel[] = { +static const char * const r2d_wclk_sel[] = { "pll_audio_294M912", "pll_mac_333M", "pll_a9_350M", "pll_mm0_396M", }; -static const char * ddr_wclk_sel[] = { +static const char * const ddr_wclk_sel[] = { "pll_mac_333M", "pll_ddr_266M", "pll_audio_294M912", "pll_mm0_198M", }; -static const char * nand_wclk_sel[] = { +static const char * const nand_wclk_sel[] = { "pll_lsp_104M", "osc", }; -static const char * lsp_26_wclk_sel[] = { +static const char * const lsp_26_wclk_sel[] = { "pll_lsp_26M", "osc", }; -static const char * vl0_sel[] = { +static const char * const vl0_sel[] = { "vou_main_channel_div", "vou_aux_channel_div", }; -static const char * hdmi_sel[] = { +static const char * const hdmi_sel[] = { "vou_main_channel_wclk", "vou_aux_channel_wclk", }; -static const char * sdmmc0_wclk_sel[] = { +static const char * const sdmmc0_wclk_sel[] = { "lsp1_104M_wclk", "lsp1_26M_wclk", }; -static const char * sdmmc1_wclk_sel[] = { +static const char * const sdmmc1_wclk_sel[] = { "lsp0_104M_wclk", "lsp0_26M_wclk", }; -static const char * uart_wclk_sel[] = { +static const char * const uart_wclk_sel[] = { "lsp1_104M_wclk", "lsp1_26M_wclk", }; -static const char * spdif0_wclk_sel[] = { +static const char * const spdif0_wclk_sel[] = { "lsp0_104M_wclk", "lsp0_26M_wclk", }; -static const char * spdif1_wclk_sel[] = { +static const char * const spdif1_wclk_sel[] = { "lsp1_104M_wclk", "lsp1_26M_wclk", }; -static const char * i2s_wclk_sel[] = { +static const char * const i2s_wclk_sel[] = { "lsp0_104M_wclk", "lsp0_26M_wclk", }; @@ -211,7 +211,7 @@ static inline struct clk *zx_div(const char *name, const char *parent, reg, shift, width, 0, ®_lock); } -static inline struct clk *zx_mux(const char *name, const char **parents, +static inline struct clk *zx_mux(const char *name, const char * const *parents, int num_parents, void __iomem *reg, u8 shift, u8 width) { return clk_register_mux(NULL, name, parents, num_parents, -- cgit v1.3-6-gb490 From 00f3ec37d29efed8983a2add67b692ca509ec99b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Jul 2015 15:55:14 -0500 Subject: clk: kill off set_irq_flags usage set_irq_flags is ARM specific with custom flags which have genirq equivalents. Convert drivers to use the genirq interfaces directly, so we can kill off set_irq_flags. The translation of flags is as follows: IRQF_VALID -> !IRQ_NOREQUEST IRQF_PROBE -> !IRQ_NOPROBE IRQF_NOAUTOEN -> IRQ_NOAUTOEN For IRQs managed by an irqdomain, the irqdomain core code handles clearing and setting IRQ_NOREQUEST already, so there is no need to do this in .map() functions and we can simply remove the set_irq_flags calls. Some users also modify IRQ_NOPROBE and this has been maintained although it is not clear that is really needed. There appears to be a great deal of blind copy and paste of this code. Signed-off-by: Rob Herring Acked-by: Boris Brezillon Cc: Mike Turquette Acked-by: Stephen Boyd Cc: linux-clk@vger.kernel.org Signed-off-by: Stephen Boyd --- drivers/clk/at91/pmc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 39be2be82b0a..d1844f1f3729 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -125,7 +125,6 @@ static int pmc_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_and_handler(virq, &pmc_irq, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); irq_set_chip_data(virq, pmc); return 0; -- cgit v1.3-6-gb490 From 4b638df4c9d556a6d947d6dbac364bee37b68b8e Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 26 Jun 2015 14:50:10 -0700 Subject: soc: qcom: Add Shared Memory Manager driver The Shared Memory Manager driver implements an interface for allocating and accessing items in the memory area shared among all of the processors in a Qualcomm platform. Signed-off-by: Bjorn Andersson Acked-by: Andy Gross Signed-off-by: Andy Gross --- drivers/soc/qcom/Kconfig | 8 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/smem.c | 775 ++++++++++++++++++++++++++++++++++++++++++ include/linux/soc/qcom/smem.h | 11 + 4 files changed, 795 insertions(+) create mode 100644 drivers/soc/qcom/smem.c create mode 100644 include/linux/soc/qcom/smem.h (limited to 'drivers') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 5eea374c8fa6..8544e1594c2c 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -17,3 +17,11 @@ config QCOM_PM QCOM Platform specific power driver to manage cores and L2 low power modes. It interface with various system drivers to put the cores in low power modes. + +config QCOM_SMEM + tristate "Qualcomm Shared Memory Manager (SMEM)" + depends on ARCH_QCOM + help + Say y here to enable support for the Qualcomm Shared Memory Manager. + The driver provides an interface to items in a heap shared among all + processors in a Qualcomm platform. diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 931d385386c5..3a033c43c0ef 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_PM) += spm.o +obj-$(CONFIG_QCOM_SMEM) += smem.o diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c new file mode 100644 index 000000000000..7c2c324c4b10 --- /dev/null +++ b/drivers/soc/qcom/smem.c @@ -0,0 +1,775 @@ +/* + * Copyright (c) 2015, Sony Mobile Communications AB. + * Copyright (c) 2012-2013, 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 + * only 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 +#include +#include + +/* + * The Qualcomm shared memory system is a allocate only heap structure that + * consists of one of more memory areas that can be accessed by the processors + * in the SoC. + * + * All systems contains a global heap, accessible by all processors in the SoC, + * with a table of contents data structure (@smem_header) at the beginning of + * the main shared memory block. + * + * The global header contains meta data for allocations as well as a fixed list + * of 512 entries (@smem_global_entry) that can be initialized to reference + * parts of the shared memory space. + * + * + * In addition to this global heap a set of "private" heaps can be set up at + * boot time with access restrictions so that only certain processor pairs can + * access the data. + * + * These partitions are referenced from an optional partition table + * (@smem_ptable), that is found 4kB from the end of the main smem region. The + * partition table entries (@smem_ptable_entry) lists the involved processors + * (or hosts) and their location in the main shared memory region. + * + * Each partition starts with a header (@smem_partition_header) that identifies + * the partition and holds properties for the two internal memory regions. The + * two regions are cached and non-cached memory respectively. Each region + * contain a link list of allocation headers (@smem_private_entry) followed by + * their data. + * + * Items in the non-cached region are allocated from the start of the partition + * while items in the cached region are allocated from the end. The free area + * is hence the region between the cached and non-cached offsets. + * + * + * To synchronize allocations in the shared memory heaps a remote spinlock must + * be held - currently lock number 3 of the sfpb or tcsr is used for this on all + * platforms. + * + */ + +/* + * Item 3 of the global heap contains an array of versions for the various + * software components in the SoC. We verify that the boot loader version is + * what the expected version (SMEM_EXPECTED_VERSION) as a sanity check. + */ +#define SMEM_ITEM_VERSION 3 +#define SMEM_MASTER_SBL_VERSION_INDEX 7 +#define SMEM_EXPECTED_VERSION 11 + +/* + * The first 8 items are only to be allocated by the boot loader while + * initializing the heap. + */ +#define SMEM_ITEM_LAST_FIXED 8 + +/* Highest accepted item number, for both global and private heaps */ +#define SMEM_ITEM_COUNT 512 + +/* Processor/host identifier for the application processor */ +#define SMEM_HOST_APPS 0 + +/* Max number of processors/hosts in a system */ +#define SMEM_HOST_COUNT 9 + +/** + * struct smem_proc_comm - proc_comm communication struct (legacy) + * @command: current command to be executed + * @status: status of the currently requested command + * @params: parameters to the command + */ +struct smem_proc_comm { + u32 command; + u32 status; + u32 params[2]; +}; + +/** + * struct smem_global_entry - entry to reference smem items on the heap + * @allocated: boolean to indicate if this entry is used + * @offset: offset to the allocated space + * @size: size of the allocated space, 8 byte aligned + * @aux_base: base address for the memory region used by this unit, or 0 for + * the default region. bits 0,1 are reserved + */ +struct smem_global_entry { + u32 allocated; + u32 offset; + u32 size; + u32 aux_base; /* bits 1:0 reserved */ +}; +#define AUX_BASE_MASK 0xfffffffc + +/** + * struct smem_header - header found in beginning of primary smem region + * @proc_comm: proc_comm communication interface (legacy) + * @version: array of versions for the various subsystems + * @initialized: boolean to indicate that smem is initialized + * @free_offset: index of the first unallocated byte in smem + * @available: number of bytes available for allocation + * @reserved: reserved field, must be 0 + * toc: array of references to items + */ +struct smem_header { + struct smem_proc_comm proc_comm[4]; + u32 version[32]; + u32 initialized; + u32 free_offset; + u32 available; + u32 reserved; + struct smem_global_entry toc[SMEM_ITEM_COUNT]; +}; + +/** + * struct smem_ptable_entry - one entry in the @smem_ptable list + * @offset: offset, within the main shared memory region, of the partition + * @size: size of the partition + * @flags: flags for the partition (currently unused) + * @host0: first processor/host with access to this partition + * @host1: second processor/host with access to this partition + * @reserved: reserved entries for later use + */ +struct smem_ptable_entry { + u32 offset; + u32 size; + u32 flags; + u16 host0; + u16 host1; + u32 reserved[8]; +}; + +/** + * struct smem_ptable - partition table for the private partitions + * @magic: magic number, must be SMEM_PTABLE_MAGIC + * @version: version of the partition table + * @num_entries: number of partitions in the table + * @reserved: for now reserved entries + * @entry: list of @smem_ptable_entry for the @num_entries partitions + */ +struct smem_ptable { + u32 magic; + u32 version; + u32 num_entries; + u32 reserved[5]; + struct smem_ptable_entry entry[]; +}; +#define SMEM_PTABLE_MAGIC 0x434f5424 /* "$TOC" */ + +/** + * struct smem_partition_header - header of the partitions + * @magic: magic number, must be SMEM_PART_MAGIC + * @host0: first processor/host with access to this partition + * @host1: second processor/host with access to this partition + * @size: size of the partition + * @offset_free_uncached: offset to the first free byte of uncached memory in + * this partition + * @offset_free_cached: offset to the first free byte of cached memory in this + * partition + * @reserved: for now reserved entries + */ +struct smem_partition_header { + u32 magic; + u16 host0; + u16 host1; + u32 size; + u32 offset_free_uncached; + u32 offset_free_cached; + u32 reserved[3]; +}; +#define SMEM_PART_MAGIC 0x54525024 /* "$PRT" */ + +/** + * struct smem_private_entry - header of each item in the private partition + * @canary: magic number, must be SMEM_PRIVATE_CANARY + * @item: identifying number of the smem item + * @size: size of the data, including padding bytes + * @padding_data: number of bytes of padding of data + * @padding_hdr: number of bytes of padding between the header and the data + * @reserved: for now reserved entry + */ +struct smem_private_entry { + u16 canary; + u16 item; + u32 size; /* includes padding bytes */ + u16 padding_data; + u16 padding_hdr; + u32 reserved; +}; +#define SMEM_PRIVATE_CANARY 0xa5a5 + +/** + * struct smem_region - representation of a chunk of memory used for smem + * @aux_base: identifier of aux_mem base + * @virt_base: virtual base address of memory with this aux_mem identifier + * @size: size of the memory region + */ +struct smem_region { + u32 aux_base; + void __iomem *virt_base; + size_t size; +}; + +/** + * struct qcom_smem - device data for the smem device + * @dev: device pointer + * @hwlock: reference to a hwspinlock + * @partitions: list of pointers to partitions affecting the current + * processor/host + * @num_regions: number of @regions + * @regions: list of the memory regions defining the shared memory + */ +struct qcom_smem { + struct device *dev; + + struct hwspinlock *hwlock; + + struct smem_partition_header *partitions[SMEM_HOST_COUNT]; + + unsigned num_regions; + struct smem_region regions[0]; +}; + +/* Pointer to the one and only smem handle */ +static struct qcom_smem *__smem; + +/* Timeout (ms) for the trylock of remote spinlocks */ +#define HWSPINLOCK_TIMEOUT 1000 + +static int qcom_smem_alloc_private(struct qcom_smem *smem, + unsigned host, + unsigned item, + size_t size) +{ + struct smem_partition_header *phdr; + struct smem_private_entry *hdr; + size_t alloc_size; + void *p; + + /* We're not going to find it if there's no matching partition */ + if (host >= SMEM_HOST_COUNT || !smem->partitions[host]) + return -ENOENT; + + phdr = smem->partitions[host]; + + p = (void *)phdr + sizeof(*phdr); + while (p < (void *)phdr + phdr->offset_free_uncached) { + hdr = p; + + if (hdr->canary != SMEM_PRIVATE_CANARY) { + dev_err(smem->dev, + "Found invalid canary in host %d partition\n", + host); + return -EINVAL; + } + + if (hdr->item == item) + return -EEXIST; + + p += sizeof(*hdr) + hdr->padding_hdr + hdr->size; + } + + /* Check that we don't grow into the cached region */ + alloc_size = sizeof(*hdr) + ALIGN(size, 8); + if (p + alloc_size >= (void *)phdr + phdr->offset_free_cached) { + dev_err(smem->dev, "Out of memory\n"); + return -ENOSPC; + } + + hdr = p; + hdr->canary = SMEM_PRIVATE_CANARY; + hdr->item = item; + hdr->size = ALIGN(size, 8); + hdr->padding_data = hdr->size - size; + hdr->padding_hdr = 0; + + /* + * Ensure the header is written before we advance the free offset, so + * that remote processors that does not take the remote spinlock still + * gets a consistent view of the linked list. + */ + wmb(); + phdr->offset_free_uncached += alloc_size; + + return 0; +} + +static int qcom_smem_alloc_global(struct qcom_smem *smem, + unsigned item, + size_t size) +{ + struct smem_header *header; + struct smem_global_entry *entry; + + if (WARN_ON(item >= SMEM_ITEM_COUNT)) + return -EINVAL; + + header = smem->regions[0].virt_base; + entry = &header->toc[item]; + if (entry->allocated) + return -EEXIST; + + size = ALIGN(size, 8); + if (WARN_ON(size > header->available)) + return -ENOMEM; + + entry->offset = header->free_offset; + entry->size = size; + + /* + * Ensure the header is consistent before we mark the item allocated, + * so that remote processors will get a consistent view of the item + * even though they do not take the spinlock on read. + */ + wmb(); + entry->allocated = 1; + + header->free_offset += size; + header->available -= size; + + return 0; +} + +/** + * qcom_smem_alloc() - allocate space for a smem item + * @host: remote processor id, or -1 + * @item: smem item handle + * @size: number of bytes to be allocated + * + * Allocate space for a given smem item of size @size, given that the item is + * not yet allocated. + */ +int qcom_smem_alloc(unsigned host, unsigned item, size_t size) +{ + unsigned long flags; + int ret; + + if (!__smem) + return -EPROBE_DEFER; + + if (item < SMEM_ITEM_LAST_FIXED) { + dev_err(__smem->dev, + "Rejecting allocation of static entry %d\n", item); + return -EINVAL; + } + + ret = hwspin_lock_timeout_irqsave(__smem->hwlock, + HWSPINLOCK_TIMEOUT, + &flags); + if (ret) + return ret; + + ret = qcom_smem_alloc_private(__smem, host, item, size); + if (ret == -ENOENT) + ret = qcom_smem_alloc_global(__smem, item, size); + + hwspin_unlock_irqrestore(__smem->hwlock, &flags); + + return ret; +} +EXPORT_SYMBOL(qcom_smem_alloc); + +static int qcom_smem_get_global(struct qcom_smem *smem, + unsigned item, + void **ptr, + size_t *size) +{ + struct smem_header *header; + struct smem_region *area; + struct smem_global_entry *entry; + u32 aux_base; + unsigned i; + + if (WARN_ON(item >= SMEM_ITEM_COUNT)) + return -EINVAL; + + header = smem->regions[0].virt_base; + entry = &header->toc[item]; + if (!entry->allocated) + return -ENXIO; + + if (ptr != NULL) { + aux_base = entry->aux_base & AUX_BASE_MASK; + + for (i = 0; i < smem->num_regions; i++) { + area = &smem->regions[i]; + + if (area->aux_base == aux_base || !aux_base) { + *ptr = area->virt_base + entry->offset; + break; + } + } + } + if (size != NULL) + *size = entry->size; + + return 0; +} + +static int qcom_smem_get_private(struct qcom_smem *smem, + unsigned host, + unsigned item, + void **ptr, + size_t *size) +{ + struct smem_partition_header *phdr; + struct smem_private_entry *hdr; + void *p; + + /* We're not going to find it if there's no matching partition */ + if (host >= SMEM_HOST_COUNT || !smem->partitions[host]) + return -ENOENT; + + phdr = smem->partitions[host]; + + p = (void *)phdr + sizeof(*phdr); + while (p < (void *)phdr + phdr->offset_free_uncached) { + hdr = p; + + if (hdr->canary != SMEM_PRIVATE_CANARY) { + dev_err(smem->dev, + "Found invalid canary in host %d partition\n", + host); + return -EINVAL; + } + + if (hdr->item == item) { + if (ptr != NULL) + *ptr = p + sizeof(*hdr) + hdr->padding_hdr; + + if (size != NULL) + *size = hdr->size - hdr->padding_data; + + return 0; + } + + p += sizeof(*hdr) + hdr->padding_hdr + hdr->size; + } + + return -ENOENT; +} + +/** + * qcom_smem_get() - resolve ptr of size of a smem item + * @host: the remote processor, or -1 + * @item: smem item handle + * @ptr: pointer to be filled out with address of the item + * @size: pointer to be filled out with size of the item + * + * Looks up pointer and size of a smem item. + */ +int qcom_smem_get(unsigned host, unsigned item, void **ptr, size_t *size) +{ + unsigned long flags; + int ret; + + if (!__smem) + return -EPROBE_DEFER; + + ret = hwspin_lock_timeout_irqsave(__smem->hwlock, + HWSPINLOCK_TIMEOUT, + &flags); + if (ret) + return ret; + + ret = qcom_smem_get_private(__smem, host, item, ptr, size); + if (ret == -ENOENT) + ret = qcom_smem_get_global(__smem, item, ptr, size); + + hwspin_unlock_irqrestore(__smem->hwlock, &flags); + return ret; + +} +EXPORT_SYMBOL(qcom_smem_get); + +/** + * qcom_smem_get_free_space() - retrieve amount of free space in a partition + * @host: the remote processor identifying a partition, or -1 + * + * To be used by smem clients as a quick way to determine if any new + * allocations has been made. + */ +int qcom_smem_get_free_space(unsigned host) +{ + struct smem_partition_header *phdr; + struct smem_header *header; + unsigned ret; + + if (!__smem) + return -EPROBE_DEFER; + + if (host < SMEM_HOST_COUNT && __smem->partitions[host]) { + phdr = __smem->partitions[host]; + ret = phdr->offset_free_cached - phdr->offset_free_uncached; + } else { + header = __smem->regions[0].virt_base; + ret = header->available; + } + + return ret; +} +EXPORT_SYMBOL(qcom_smem_get_free_space); + +static int qcom_smem_get_sbl_version(struct qcom_smem *smem) +{ + unsigned *versions; + size_t size; + int ret; + + ret = qcom_smem_get_global(smem, SMEM_ITEM_VERSION, + (void **)&versions, &size); + if (ret < 0) { + dev_err(smem->dev, "Unable to read the version item\n"); + return -ENOENT; + } + + if (size < sizeof(unsigned) * SMEM_MASTER_SBL_VERSION_INDEX) { + dev_err(smem->dev, "Version item is too small\n"); + return -EINVAL; + } + + return versions[SMEM_MASTER_SBL_VERSION_INDEX]; +} + +static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, + unsigned local_host) +{ + struct smem_partition_header *header; + struct smem_ptable_entry *entry; + struct smem_ptable *ptable; + unsigned remote_host; + int i; + + ptable = smem->regions[0].virt_base + smem->regions[0].size - SZ_4K; + if (ptable->magic != SMEM_PTABLE_MAGIC) + return 0; + + if (ptable->version != 1) { + dev_err(smem->dev, + "Unsupported partition header version %d\n", + ptable->version); + return -EINVAL; + } + + for (i = 0; i < ptable->num_entries; i++) { + entry = &ptable->entry[i]; + + if (entry->host0 != local_host && entry->host1 != local_host) + continue; + + if (!entry->offset) + continue; + + if (!entry->size) + continue; + + if (entry->host0 == local_host) + remote_host = entry->host1; + else + remote_host = entry->host0; + + if (remote_host >= SMEM_HOST_COUNT) { + dev_err(smem->dev, + "Invalid remote host %d\n", + remote_host); + return -EINVAL; + } + + if (smem->partitions[remote_host]) { + dev_err(smem->dev, + "Already found a partition for host %d\n", + remote_host); + return -EINVAL; + } + + header = smem->regions[0].virt_base + entry->offset; + + if (header->magic != SMEM_PART_MAGIC) { + dev_err(smem->dev, + "Partition %d has invalid magic\n", i); + return -EINVAL; + } + + if (header->host0 != local_host && header->host1 != local_host) { + dev_err(smem->dev, + "Partition %d hosts are invalid\n", i); + return -EINVAL; + } + + if (header->host0 != remote_host && header->host1 != remote_host) { + dev_err(smem->dev, + "Partition %d hosts are invalid\n", i); + return -EINVAL; + } + + if (header->size != entry->size) { + dev_err(smem->dev, + "Partition %d has invalid size\n", i); + return -EINVAL; + } + + if (header->offset_free_uncached > header->size) { + dev_err(smem->dev, + "Partition %d has invalid free pointer\n", i); + return -EINVAL; + } + + smem->partitions[remote_host] = header; + } + + return 0; +} + +static int qcom_smem_count_mem_regions(struct platform_device *pdev) +{ + struct resource *res; + int num_regions = 0; + int i; + + for (i = 0; i < pdev->num_resources; i++) { + res = &pdev->resource[i]; + + if (resource_type(res) == IORESOURCE_MEM) + num_regions++; + } + + return num_regions; +} + +static int qcom_smem_probe(struct platform_device *pdev) +{ + struct smem_header *header; + struct device_node *np; + struct qcom_smem *smem; + struct resource *res; + struct resource r; + size_t array_size; + int num_regions = 0; + int hwlock_id; + u32 version; + int ret; + int i; + + num_regions = qcom_smem_count_mem_regions(pdev) + 1; + + array_size = num_regions * sizeof(struct smem_region); + smem = devm_kzalloc(&pdev->dev, sizeof(*smem) + array_size, GFP_KERNEL); + if (!smem) + return -ENOMEM; + + smem->dev = &pdev->dev; + smem->num_regions = num_regions; + + np = of_parse_phandle(pdev->dev.of_node, "memory-region", 0); + if (!np) { + dev_err(&pdev->dev, "No memory-region specified\n"); + return -EINVAL; + } + + ret = of_address_to_resource(np, 0, &r); + of_node_put(np); + if (ret) + return ret; + + smem->regions[0].aux_base = (u32)r.start; + smem->regions[0].size = resource_size(&r); + smem->regions[0].virt_base = devm_ioremap_nocache(&pdev->dev, + r.start, + resource_size(&r)); + if (!smem->regions[0].virt_base) + return -ENOMEM; + + for (i = 1; i < num_regions; i++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i - 1); + + smem->regions[i].aux_base = (u32)res->start; + smem->regions[i].size = resource_size(res); + smem->regions[i].virt_base = devm_ioremap_nocache(&pdev->dev, + res->start, + resource_size(res)); + if (!smem->regions[i].virt_base) + return -ENOMEM; + } + + header = smem->regions[0].virt_base; + if (header->initialized != 1 || header->reserved) { + dev_err(&pdev->dev, "SMEM is not initialized by SBL\n"); + return -EINVAL; + } + + version = qcom_smem_get_sbl_version(smem); + if (version >> 16 != SMEM_EXPECTED_VERSION) { + dev_err(&pdev->dev, "Unsupported SMEM version 0x%x\n", version); + return -EINVAL; + } + + ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); + if (ret < 0) + return ret; + + hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0); + if (hwlock_id < 0) { + dev_err(&pdev->dev, "failed to retrieve hwlock\n"); + return hwlock_id; + } + + smem->hwlock = hwspin_lock_request_specific(hwlock_id); + if (!smem->hwlock) + return -ENXIO; + + __smem = smem; + + return 0; +} + +static int qcom_smem_remove(struct platform_device *pdev) +{ + __smem = NULL; + hwspin_lock_free(__smem->hwlock); + + return 0; +} + +static const struct of_device_id qcom_smem_of_match[] = { + { .compatible = "qcom,smem" }, + {} +}; +MODULE_DEVICE_TABLE(of, qcom_smem_of_match); + +static struct platform_driver qcom_smem_driver = { + .probe = qcom_smem_probe, + .remove = qcom_smem_remove, + .driver = { + .name = "qcom-smem", + .of_match_table = qcom_smem_of_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init qcom_smem_init(void) +{ + return platform_driver_register(&qcom_smem_driver); +} +arch_initcall(qcom_smem_init); + +static void __exit qcom_smem_exit(void) +{ + platform_driver_unregister(&qcom_smem_driver); +} +module_exit(qcom_smem_exit) + +MODULE_AUTHOR("Bjorn Andersson "); +MODULE_DESCRIPTION("Qualcomm Shared Memory Manager"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/soc/qcom/smem.h b/include/linux/soc/qcom/smem.h new file mode 100644 index 000000000000..bc9630d3aced --- /dev/null +++ b/include/linux/soc/qcom/smem.h @@ -0,0 +1,11 @@ +#ifndef __QCOM_SMEM_H__ +#define __QCOM_SMEM_H__ + +#define QCOM_SMEM_HOST_ANY -1 + +int qcom_smem_alloc(unsigned host, unsigned item, size_t size); +int qcom_smem_get(unsigned host, unsigned item, void **ptr, size_t *size); + +int qcom_smem_get_free_space(unsigned host); + +#endif -- cgit v1.3-6-gb490 From 23b38ceb814ca8a2bd92613687f82b70041b9238 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Fri, 10 Jul 2015 14:18:00 -0600 Subject: drivers: qcom: Select QCOM_SCM unconditionally for QCOM_PM Enable QCOM_SCM for QCOM power management driver Signed-off-by: Lina Iyer Acked-by: Stephen Boyd Acked-by: Andy Gross Signed-off-by: Andy Gross --- drivers/soc/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 8544e1594c2c..0d4faaf32662 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -13,6 +13,7 @@ config QCOM_GSBI config QCOM_PM bool "Qualcomm Power Management" depends on ARCH_QCOM && !ARM64 + select QCOM_SCM help QCOM Platform specific power driver to manage cores and L2 low power modes. It interface with various system drivers to put the cores in -- cgit v1.3-6-gb490 From e323d56eb06b266b77c2b430cb5f1977ba549e03 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 12 Jun 2015 10:53:25 +0900 Subject: clk: exynos4: Fix wrong clock for Exynos4x12 ADC The TSADC gate clock was used in Exynos4x12 DTSI for exynos-adc driver. However TSADC is present only on Exynos4210 so on Trats2 board (with Exynos4412 SoC) the exynos-adc driver could not be probed: ERROR: could not get clock /adc@126C0000:adc(0) exynos-adc 126c0000.adc: failed getting clock, err = -2 exynos-adc: probe of 126c0000.adc failed with error -2 Instead on Exynos4x12 SoCs the main clock used by Analog to Digital Converter is located in different register and it is named in datasheet as PCLK_ADC. Regardless of the name the purpose of this PCLK_ADC clock is the same as purpose of TSADC from Exynos4210. The patch adds gate clock for Exynos4x12 using the proper register so backward compatibility is preserved. This fixes the probe of exynos-adc driver on Exynos4x12 boards and allows accessing sensors connected to it on Trats2 board (ntc,ncp15wb473 AP and battery thermistors). Signed-off-by: Krzysztof Kozlowski Cc: Fixes: c63c57433003 ("ARM: dts: Add ADC's dt data to read raw data for exynos4x12") Reviewed-by: Javier Martinez Canillas Acked-by: Tomasz Figa Signed-off-by: Stephen Boyd --- drivers/clk/samsung/clk-exynos4.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 65e20eb6356e..251f48dcd12d 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -86,6 +86,7 @@ #define DIV_PERIL4 0xc560 #define DIV_PERIL5 0xc564 #define E4X12_DIV_CAM1 0xc568 +#define E4X12_GATE_BUS_FSYS1 0xc744 #define GATE_SCLK_CAM 0xc820 #define GATE_IP_CAM 0xc920 #define GATE_IP_TV 0xc924 @@ -1097,6 +1098,7 @@ static struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = { 0), GATE(CLK_PPMUIMAGE, "ppmuimage", "aclk200", E4X12_GATE_IP_IMAGE, 9, 0, 0), + GATE(CLK_TSADC, "tsadc", "aclk133", E4X12_GATE_BUS_FSYS1, 16, 0, 0), GATE(CLK_MIPI_HSI, "mipi_hsi", "aclk133", GATE_IP_FSYS, 10, 0, 0), GATE(CLK_CHIPID, "chipid", "aclk100", E4X12_GATE_IP_PERIR, 0, 0, 0), GATE(CLK_SYSREG, "sysreg", "aclk100", E4X12_GATE_IP_PERIR, 1, -- cgit v1.3-6-gb490 From 3e07e5baa2af166a6f38a51e14ff036c341a57c7 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Mon, 27 Jul 2015 19:22:23 -0600 Subject: toshiba_acpi: Add set_fan_status function This patch adds a new function named "set_fan_status" to complement its get* counterpart, as well as to avoid code duplication between "fan_proc_write" and "fan_store". Also, both functions (get*, set*) are now checking for TOS_FAILURE, TOS_NOT_SUPPORTED and TOS_SUCCESS (to be on par with the rest of the HCI/SCI functions), printing an error message, returning -ENODEV and zero respectively. The proc and sysfs functions were updated to reflect these changes as well, returning -EIO for proc, and propagating the error value on the sysfs functions. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 66 ++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 3bfdfddc38ac..f7228987bd50 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1422,27 +1422,47 @@ static const struct file_operations video_proc_fops = { .write = video_proc_write, }; +/* Fan status */ static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) { - u32 hci_result; + u32 result = hci_read(dev, HCI_FAN, status); - hci_result = hci_read(dev, HCI_FAN, status); - return hci_result == TOS_SUCCESS ? 0 : -EIO; + if (result == TOS_FAILURE) + pr_err("ACPI call to get Fan status failed\n"); + else if (result == TOS_NOT_SUPPORTED) + return -ENODEV; + else if (result == TOS_SUCCESS) + return 0; + + return -EIO; +} + +static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status) +{ + u32 result = hci_write(dev, HCI_FAN, status); + + if (result == TOS_FAILURE) + pr_err("ACPI call to set Fan status failed\n"); + else if (result == TOS_NOT_SUPPORTED) + return -ENODEV; + else if (result == TOS_SUCCESS) + return 0; + + return -EIO; } static int fan_proc_show(struct seq_file *m, void *v) { struct toshiba_acpi_dev *dev = m->private; - int ret; u32 value; - ret = get_fan_status(dev, &value); - if (!ret) { - seq_printf(m, "running: %d\n", (value > 0)); - seq_printf(m, "force_on: %d\n", dev->force_fan); - } + if (get_fan_status(dev, &value)) + return -EIO; - return ret; + seq_printf(m, "running: %d\n", (value > 0)); + seq_printf(m, "force_on: %d\n", dev->force_fan); + + return 0; } static int fan_proc_open(struct inode *inode, struct file *file) @@ -1457,23 +1477,20 @@ static ssize_t fan_proc_write(struct file *file, const char __user *buf, char cmd[42]; size_t len; int value; - u32 hci_result; len = min(count, sizeof(cmd) - 1); if (copy_from_user(cmd, buf, len)) return -EFAULT; cmd[len] = '\0'; - if (sscanf(cmd, " force_on : %i", &value) == 1 && - value >= 0 && value <= 1) { - hci_result = hci_write(dev, HCI_FAN, value); - if (hci_result == TOS_SUCCESS) - dev->force_fan = value; - else - return -EIO; - } else { + if (sscanf(cmd, " force_on : %i", &value) != 1 && + value != 0 && value != 1) return -EINVAL; - } + + if (set_fan_status(dev, value)) + return -EIO; + + dev->force_fan = value; return count; } @@ -1610,7 +1627,6 @@ static ssize_t fan_store(struct device *dev, const char *buf, size_t count) { struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); - u32 result; int state; int ret; @@ -1621,11 +1637,9 @@ static ssize_t fan_store(struct device *dev, if (state != 0 && state != 1) return -EINVAL; - result = hci_write(toshiba, HCI_FAN, state); - if (result == TOS_FAILURE) - return -EIO; - else if (result == TOS_NOT_SUPPORTED) - return -ENODEV; + ret = set_fan_status(toshiba, state); + if (ret) + return ret; return count; } -- cgit v1.3-6-gb490 From 077742dac2c7098ebf932ef02637c2a3b1397046 Mon Sep 17 00:00:00 2001 From: Lars Persson Date: Tue, 28 Jul 2015 12:01:48 +0200 Subject: dwc_eth_qos: Add support for Synopsys DWC Ethernet QoS This patch adds a platform driver for the new generation of the gigabit ethernet IP from Synopsys. It is developed for version 4.10a of the IP core. Signed-off-by: Lars Persson Signed-off-by: David S. Miller --- drivers/net/ethernet/synopsys/Kconfig | 27 + drivers/net/ethernet/synopsys/Makefile | 5 + drivers/net/ethernet/synopsys/dwc_eth_qos.c | 3019 +++++++++++++++++++++++++++ 3 files changed, 3051 insertions(+) create mode 100644 drivers/net/ethernet/synopsys/Kconfig create mode 100644 drivers/net/ethernet/synopsys/Makefile create mode 100644 drivers/net/ethernet/synopsys/dwc_eth_qos.c (limited to 'drivers') diff --git a/drivers/net/ethernet/synopsys/Kconfig b/drivers/net/ethernet/synopsys/Kconfig new file mode 100644 index 000000000000..a8f315106742 --- /dev/null +++ b/drivers/net/ethernet/synopsys/Kconfig @@ -0,0 +1,27 @@ +# +# Synopsys network device configuration +# + +config NET_VENDOR_SYNOPSYS + bool "Synopsys devices" + default y + ---help--- + If you have a network (Ethernet) device belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Synopsys devices. If you say Y, you will be asked + for your specific device in the following questions. + +if NET_VENDOR_SYNOPSYS + +config SYNOPSYS_DWC_ETH_QOS + tristate "Sypnopsys DWC Ethernet QOS v4.10a support" + select PHYLIB + select CRC32 + select MII + depends on OF + ---help--- + This driver supports the DWC Ethernet QoS from Synopsys + +endif # NET_VENDOR_SYNOPSYS diff --git a/drivers/net/ethernet/synopsys/Makefile b/drivers/net/ethernet/synopsys/Makefile new file mode 100644 index 000000000000..7a375723fc18 --- /dev/null +++ b/drivers/net/ethernet/synopsys/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Synopsys network device drivers. +# + +obj-$(CONFIG_SYNOPSYS_DWC_ETH_QOS) += dwc_eth_qos.o diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c new file mode 100644 index 000000000000..85b3326775b8 --- /dev/null +++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c @@ -0,0 +1,3019 @@ +/* Synopsys DWC Ethernet Quality-of-Service v4.10a linux driver + * + * This is a driver for the Synopsys DWC Ethernet QoS IP version 4.10a (GMAC). + * This version introduced a lot of changes which breaks backwards + * compatibility the non-QoS IP from Synopsys (used in the ST Micro drivers). + * Some fields differ between version 4.00a and 4.10a, mainly the interrupt + * bit fields. The driver could be made compatible with 4.00, if all relevant + * HW erratas are handled. + * + * The GMAC is highly configurable at synthesis time. This driver has been + * developed for a subset of the total available feature set. Currently + * it supports: + * - TSO + * - Checksum offload for RX and TX. + * - Energy efficient ethernet. + * - GMII phy interface. + * - The statistics module. + * - Single RX and TX queue. + * + * Copyright (C) 2015 Axis Communications AB. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "dwceqos" +#define DRIVER_DESCRIPTION "Synopsys DWC Ethernet QoS driver" +#define DRIVER_VERSION "0.9" + +#define DWCEQOS_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | \ + NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP) + +#define DWCEQOS_TX_TIMEOUT 5 /* Seconds */ + +#define DWCEQOS_LPI_TIMER_MIN 8 +#define DWCEQOS_LPI_TIMER_MAX ((1 << 20) - 1) + +#define DWCEQOS_RX_BUF_SIZE 2048 + +#define DWCEQOS_RX_DCNT 256 +#define DWCEQOS_TX_DCNT 256 + +#define DWCEQOS_HASH_TABLE_SIZE 64 + +/* The size field in the DMA descriptor is 14 bits */ +#define BYTES_PER_DMA_DESC 16376 + +/* Hardware registers */ +#define START_MAC_REG_OFFSET 0x0000 +#define MAX_MAC_REG_OFFSET 0x0bd0 +#define START_MTL_REG_OFFSET 0x0c00 +#define MAX_MTL_REG_OFFSET 0x0d7c +#define START_DMA_REG_OFFSET 0x1000 +#define MAX_DMA_REG_OFFSET 0x117C + +#define REG_SPACE_SIZE 0x1800 + +/* DMA */ +#define REG_DWCEQOS_DMA_MODE 0x1000 +#define REG_DWCEQOS_DMA_SYSBUS_MODE 0x1004 +#define REG_DWCEQOS_DMA_IS 0x1008 +#define REG_DWCEQOS_DMA_DEBUG_ST0 0x100c + +/* DMA channel registers */ +#define REG_DWCEQOS_DMA_CH0_CTRL 0x1100 +#define REG_DWCEQOS_DMA_CH0_TX_CTRL 0x1104 +#define REG_DWCEQOS_DMA_CH0_RX_CTRL 0x1108 +#define REG_DWCEQOS_DMA_CH0_TXDESC_LIST 0x1114 +#define REG_DWCEQOS_DMA_CH0_RXDESC_LIST 0x111c +#define REG_DWCEQOS_DMA_CH0_TXDESC_TAIL 0x1120 +#define REG_DWCEQOS_DMA_CH0_RXDESC_TAIL 0x1128 +#define REG_DWCEQOS_DMA_CH0_TXDESC_LEN 0x112c +#define REG_DWCEQOS_DMA_CH0_RXDESC_LEN 0x1130 +#define REG_DWCEQOS_DMA_CH0_IE 0x1134 +#define REG_DWCEQOS_DMA_CH0_CUR_TXDESC 0x1144 +#define REG_DWCEQOS_DMA_CH0_CUR_RXDESC 0x114c +#define REG_DWCEQOS_DMA_CH0_CUR_TXBUF 0x1154 +#define REG_DWCEQOS_DMA_CH0_CUR_RXBUG 0x115c +#define REG_DWCEQOS_DMA_CH0_STA 0x1160 + +#define DWCEQOS_DMA_MODE_TXPR BIT(11) +#define DWCEQOS_DMA_MODE_DA BIT(1) + +#define DWCEQOS_DMA_SYSBUS_MODE_EN_LPI BIT(31) +#define DWCEQOS_DMA_SYSBUS_MODE_FB BIT(0) +#define DWCEQOS_DMA_SYSBUS_MODE_AAL BIT(12) + +#define DWCEQOS_DMA_SYSBUS_MODE_RD_OSR_LIMIT(x) \ + (((x) << 16) & 0x000F0000) +#define DWCEQOS_DMA_SYSBUS_MODE_RD_OSR_LIMIT_DEFAULT 3 +#define DWCEQOS_DMA_SYSBUS_MODE_RD_OSR_LIMIT_MASK GENMASK(19, 16) + +#define DWCEQOS_DMA_SYSBUS_MODE_WR_OSR_LIMIT(x) \ + (((x) << 24) & 0x0F000000) +#define DWCEQOS_DMA_SYSBUS_MODE_WR_OSR_LIMIT_DEFAULT 3 +#define DWCEQOS_DMA_SYSBUS_MODE_WR_OSR_LIMIT_MASK GENMASK(27, 24) + +#define DWCEQOS_DMA_SYSBUS_MODE_BURST_MASK GENMASK(7, 1) +#define DWCEQOS_DMA_SYSBUS_MODE_BURST(x) \ + (((x) << 1) & DWCEQOS_DMA_SYSBUS_MODE_BURST_MASK) +#define DWCEQOS_DMA_SYSBUS_MODE_BURST_DEFAULT GENMASK(3, 1) + +#define DWCEQOS_DMA_CH_CTRL_PBLX8 BIT(16) +#define DWCEQOS_DMA_CH_CTRL_DSL(x) ((x) << 18) + +#define DWCEQOS_DMA_CH_CTRL_PBL(x) ((x) << 16) +#define DWCEQOS_DMA_CH_CTRL_START BIT(0) +#define DWCEQOS_DMA_CH_RX_CTRL_BUFSIZE(x) ((x) << 1) +#define DWCEQOS_DMA_CH_TX_OSP BIT(4) +#define DWCEQOS_DMA_CH_TX_TSE BIT(12) + +#define DWCEQOS_DMA_CH0_IE_NIE BIT(15) +#define DWCEQOS_DMA_CH0_IE_AIE BIT(14) +#define DWCEQOS_DMA_CH0_IE_RIE BIT(6) +#define DWCEQOS_DMA_CH0_IE_TIE BIT(0) +#define DWCEQOS_DMA_CH0_IE_FBEE BIT(12) +#define DWCEQOS_DMA_CH0_IE_RBUE BIT(7) + +#define DWCEQOS_DMA_IS_DC0IS BIT(0) +#define DWCEQOS_DMA_IS_MTLIS BIT(16) +#define DWCEQOS_DMA_IS_MACIS BIT(17) + +#define DWCEQOS_DMA_CH0_IS_TI BIT(0) +#define DWCEQOS_DMA_CH0_IS_RI BIT(6) +#define DWCEQOS_DMA_CH0_IS_RBU BIT(7) +#define DWCEQOS_DMA_CH0_IS_FBE BIT(12) +#define DWCEQOS_DMA_CH0_IS_CDE BIT(13) +#define DWCEQOS_DMA_CH0_IS_AIS BIT(14) + +#define DWCEQOS_DMA_CH0_IS_TEB GENMASK(18, 16) +#define DWCEQOS_DMA_CH0_IS_TX_ERR_READ BIT(16) +#define DWCEQOS_DMA_CH0_IS_TX_ERR_DESCR BIT(17) + +#define DWCEQOS_DMA_CH0_IS_REB GENMASK(21, 19) +#define DWCEQOS_DMA_CH0_IS_RX_ERR_READ BIT(19) +#define DWCEQOS_DMA_CH0_IS_RX_ERR_DESCR BIT(20) + +/* DMA descriptor bits for RX normal descriptor (read format) */ +#define DWCEQOS_DMA_RDES3_OWN BIT(31) +#define DWCEQOS_DMA_RDES3_INTE BIT(30) +#define DWCEQOS_DMA_RDES3_BUF2V BIT(25) +#define DWCEQOS_DMA_RDES3_BUF1V BIT(24) + +/* DMA descriptor bits for RX normal descriptor (write back format) */ +#define DWCEQOS_DMA_RDES1_IPCE BIT(7) +#define DWCEQOS_DMA_RDES3_ES BIT(15) +#define DWCEQOS_DMA_RDES3_E_JT BIT(14) +#define DWCEQOS_DMA_RDES3_PL(x) ((x) & 0x7fff) +#define DWCEQOS_DMA_RDES1_PT 0x00000007 +#define DWCEQOS_DMA_RDES1_PT_UDP BIT(0) +#define DWCEQOS_DMA_RDES1_PT_TCP BIT(1) +#define DWCEQOS_DMA_RDES1_PT_ICMP 0x00000003 + +/* DMA descriptor bits for TX normal descriptor (read format) */ +#define DWCEQOS_DMA_TDES2_IOC BIT(31) +#define DWCEQOS_DMA_TDES3_OWN BIT(31) +#define DWCEQOS_DMA_TDES3_CTXT BIT(30) +#define DWCEQOS_DMA_TDES3_FD BIT(29) +#define DWCEQOS_DMA_TDES3_LD BIT(28) +#define DWCEQOS_DMA_TDES3_CIPH BIT(16) +#define DWCEQOS_DMA_TDES3_CIPP BIT(17) +#define DWCEQOS_DMA_TDES3_CA 0x00030000 +#define DWCEQOS_DMA_TDES3_TSE BIT(18) +#define DWCEQOS_DMA_DES3_THL(x) ((x) << 19) +#define DWCEQOS_DMA_DES2_B2L(x) ((x) << 16) + +#define DWCEQOS_DMA_TDES3_TCMSSV BIT(26) + +/* DMA channel states */ +#define DMA_TX_CH_STOPPED 0 +#define DMA_TX_CH_SUSPENDED 6 + +#define DMA_GET_TX_STATE_CH0(status0) ((status0 & 0xF000) >> 12) + +/* MTL */ +#define REG_DWCEQOS_MTL_OPER 0x0c00 +#define REG_DWCEQOS_MTL_DEBUG_ST 0x0c0c +#define REG_DWCEQOS_MTL_TXQ0_DEBUG_ST 0x0d08 +#define REG_DWCEQOS_MTL_RXQ0_DEBUG_ST 0x0d38 + +#define REG_DWCEQOS_MTL_IS 0x0c20 +#define REG_DWCEQOS_MTL_TXQ0_OPER 0x0d00 +#define REG_DWCEQOS_MTL_RXQ0_OPER 0x0d30 +#define REG_DWCEQOS_MTL_RXQ0_MIS_CNT 0x0d34 +#define REG_DWCEQOS_MTL_RXQ0_CTRL 0x0d3c + +#define REG_DWCEQOS_MTL_Q0_ISCTRL 0x0d2c + +#define DWCEQOS_MTL_SCHALG_STRICT 0x00000060 + +#define DWCEQOS_MTL_TXQ_TXQEN BIT(3) +#define DWCEQOS_MTL_TXQ_TSF BIT(1) +#define DWCEQOS_MTL_TXQ_FTQ BIT(0) +#define DWCEQOS_MTL_TXQ_TTC512 0x00000070 + +#define DWCEQOS_MTL_TXQ_SIZE(x) ((((x) - 256) & 0xff00) << 8) + +#define DWCEQOS_MTL_RXQ_SIZE(x) ((((x) - 256) & 0xff00) << 12) +#define DWCEQOS_MTL_RXQ_EHFC BIT(7) +#define DWCEQOS_MTL_RXQ_DIS_TCP_EF BIT(6) +#define DWCEQOS_MTL_RXQ_FEP BIT(4) +#define DWCEQOS_MTL_RXQ_FUP BIT(3) +#define DWCEQOS_MTL_RXQ_RSF BIT(5) +#define DWCEQOS_MTL_RXQ_RTC32 BIT(0) + +/* MAC */ +#define REG_DWCEQOS_MAC_CFG 0x0000 +#define REG_DWCEQOS_MAC_EXT_CFG 0x0004 +#define REG_DWCEQOS_MAC_PKT_FILT 0x0008 +#define REG_DWCEQOS_MAC_WD_TO 0x000c +#define REG_DWCEQOS_HASTABLE_LO 0x0010 +#define REG_DWCEQOS_HASTABLE_HI 0x0014 +#define REG_DWCEQOS_MAC_IS 0x00b0 +#define REG_DWCEQOS_MAC_IE 0x00b4 +#define REG_DWCEQOS_MAC_STAT 0x00b8 +#define REG_DWCEQOS_MAC_MDIO_ADDR 0x0200 +#define REG_DWCEQOS_MAC_MDIO_DATA 0x0204 +#define REG_DWCEQOS_MAC_MAC_ADDR0_HI 0x0300 +#define REG_DWCEQOS_MAC_MAC_ADDR0_LO 0x0304 +#define REG_DWCEQOS_MAC_RXQ0_CTRL0 0x00a0 +#define REG_DWCEQOS_MAC_HW_FEATURE0 0x011c +#define REG_DWCEQOS_MAC_HW_FEATURE1 0x0120 +#define REG_DWCEQOS_MAC_HW_FEATURE2 0x0124 +#define REG_DWCEQOS_MAC_HASHTABLE_LO 0x0010 +#define REG_DWCEQOS_MAC_HASHTABLE_HI 0x0014 +#define REG_DWCEQOS_MAC_LPI_CTRL_STATUS 0x00d0 +#define REG_DWCEQOS_MAC_LPI_TIMERS_CTRL 0x00d4 +#define REG_DWCEQOS_MAC_LPI_ENTRY_TIMER 0x00d8 +#define REG_DWCEQOS_MAC_1US_TIC_COUNTER 0x00dc +#define REG_DWCEQOS_MAC_RX_FLOW_CTRL 0x0090 +#define REG_DWCEQOS_MAC_Q0_TX_FLOW 0x0070 + +#define DWCEQOS_MAC_CFG_ACS BIT(20) +#define DWCEQOS_MAC_CFG_JD BIT(17) +#define DWCEQOS_MAC_CFG_JE BIT(16) +#define DWCEQOS_MAC_CFG_PS BIT(15) +#define DWCEQOS_MAC_CFG_FES BIT(14) +#define DWCEQOS_MAC_CFG_DM BIT(13) +#define DWCEQOS_MAC_CFG_DO BIT(10) +#define DWCEQOS_MAC_CFG_TE BIT(1) +#define DWCEQOS_MAC_CFG_IPC BIT(27) +#define DWCEQOS_MAC_CFG_RE BIT(0) + +#define DWCEQOS_ADDR_HIGH(reg) (0x00000300 + (reg * 8)) +#define DWCEQOS_ADDR_LOW(reg) (0x00000304 + (reg * 8)) + +#define DWCEQOS_MAC_IS_LPI_INT BIT(5) +#define DWCEQOS_MAC_IS_MMC_INT BIT(8) + +#define DWCEQOS_MAC_RXQ_EN BIT(1) +#define DWCEQOS_MAC_MAC_ADDR_HI_EN BIT(31) +#define DWCEQOS_MAC_PKT_FILT_RA BIT(31) +#define DWCEQOS_MAC_PKT_FILT_HPF BIT(10) +#define DWCEQOS_MAC_PKT_FILT_SAF BIT(9) +#define DWCEQOS_MAC_PKT_FILT_SAIF BIT(8) +#define DWCEQOS_MAC_PKT_FILT_DBF BIT(5) +#define DWCEQOS_MAC_PKT_FILT_PM BIT(4) +#define DWCEQOS_MAC_PKT_FILT_DAIF BIT(3) +#define DWCEQOS_MAC_PKT_FILT_HMC BIT(2) +#define DWCEQOS_MAC_PKT_FILT_HUC BIT(1) +#define DWCEQOS_MAC_PKT_FILT_PR BIT(0) + +#define DWCEQOS_MAC_MDIO_ADDR_CR(x) (((x & 15)) << 8) +#define DWCEQOS_MAC_MDIO_ADDR_CR_20 2 +#define DWCEQOS_MAC_MDIO_ADDR_CR_35 3 +#define DWCEQOS_MAC_MDIO_ADDR_CR_60 0 +#define DWCEQOS_MAC_MDIO_ADDR_CR_100 1 +#define DWCEQOS_MAC_MDIO_ADDR_CR_150 4 +#define DWCEQOS_MAC_MDIO_ADDR_CR_250 5 +#define DWCEQOS_MAC_MDIO_ADDR_GOC_READ 0x0000000c +#define DWCEQOS_MAC_MDIO_ADDR_GOC_WRITE BIT(2) +#define DWCEQOS_MAC_MDIO_ADDR_GB BIT(0) + +#define DWCEQOS_MAC_LPI_CTRL_STATUS_TLPIEN BIT(0) +#define DWCEQOS_MAC_LPI_CTRL_STATUS_TLPIEX BIT(1) +#define DWCEQOS_MAC_LPI_CTRL_STATUS_RLPIEN BIT(2) +#define DWCEQOS_MAC_LPI_CTRL_STATUS_RLPIEX BIT(3) +#define DWCEQOS_MAC_LPI_CTRL_STATUS_TLPIST BIT(8) +#define DWCEQOS_MAC_LPI_CTRL_STATUS_RLPIST BIT(9) +#define DWCEQOS_MAC_LPI_CTRL_STATUS_LPIEN BIT(16) +#define DWCEQOS_MAC_LPI_CTRL_STATUS_PLS BIT(17) +#define DWCEQOS_MAC_LPI_CTRL_STATUS_PLSEN BIT(18) +#define DWCEQOS_MAC_LPI_CTRL_STATUS_LIPTXA BIT(19) +#define DWCEQOS_MAC_LPI_CTRL_STATUS_LPITE BIT(20) +#define DWCEQOS_MAC_LPI_CTRL_STATUS_LPITCSE BIT(21) + +#define DWCEQOS_MAC_1US_TIC_COUNTER_VAL(x) ((x) & GENMASK(11, 0)) + +#define DWCEQOS_LPI_CTRL_ENABLE_EEE (DWCEQOS_MAC_LPI_CTRL_STATUS_LPITE | \ + DWCEQOS_MAC_LPI_CTRL_STATUS_LIPTXA | \ + DWCEQOS_MAC_LPI_CTRL_STATUS_LPIEN) + +#define DWCEQOS_MAC_RX_FLOW_CTRL_RFE BIT(0) + +#define DWCEQOS_MAC_Q0_TX_FLOW_TFE BIT(1) +#define DWCEQOS_MAC_Q0_TX_FLOW_PT(time) ((time) << 16) +#define DWCEQOS_MAC_Q0_TX_FLOW_PLT_4_SLOTS (0 << 4) + +/* Features */ +#define DWCEQOS_MAC_HW_FEATURE0_RXCOESEL BIT(16) +#define DWCEQOS_MAC_HW_FEATURE0_TXCOESEL BIT(14) +#define DWCEQOS_MAC_HW_FEATURE0_HDSEL BIT(2) +#define DWCEQOS_MAC_HW_FEATURE0_EEESEL BIT(13) +#define DWCEQOS_MAC_HW_FEATURE0_GMIISEL BIT(1) +#define DWCEQOS_MAC_HW_FEATURE0_MIISEL BIT(0) + +#define DWCEQOS_MAC_HW_FEATURE1_TSOEN BIT(18) +#define DWCEQOS_MAC_HW_FEATURE1_TXFIFOSIZE(x) ((128 << ((x) & 0x7c0)) >> 6) +#define DWCEQOS_MAC_HW_FEATURE1_RXFIFOSIZE(x) (128 << ((x) & 0x1f)) + +#define DWCEQOS_MAX_PERFECT_ADDRESSES(feature1) \ + (1 + (((feature1) & 0x1fc0000) >> 18)) + +#define DWCEQOS_MDIO_PHYADDR(x) (((x) & 0x1f) << 21) +#define DWCEQOS_MDIO_PHYREG(x) (((x) & 0x1f) << 16) + +#define DWCEQOS_DMA_MODE_SWR BIT(0) + +#define DWCEQOS_DWCEQOS_RX_BUF_SIZE 2048 + +/* Mac Management Counters */ +#define REG_DWCEQOS_MMC_CTRL 0x0700 +#define REG_DWCEQOS_MMC_RXIRQ 0x0704 +#define REG_DWCEQOS_MMC_TXIRQ 0x0708 +#define REG_DWCEQOS_MMC_RXIRQMASK 0x070c +#define REG_DWCEQOS_MMC_TXIRQMASK 0x0710 + +#define DWCEQOS_MMC_CTRL_CNTRST BIT(0) +#define DWCEQOS_MMC_CTRL_RSTONRD BIT(2) + +#define DWC_MMC_TXLPITRANSCNTR 0x07F0 +#define DWC_MMC_TXLPIUSCNTR 0x07EC +#define DWC_MMC_TXOVERSIZE_G 0x0778 +#define DWC_MMC_TXVLANPACKETS_G 0x0774 +#define DWC_MMC_TXPAUSEPACKETS 0x0770 +#define DWC_MMC_TXEXCESSDEF 0x076C +#define DWC_MMC_TXPACKETCOUNT_G 0x0768 +#define DWC_MMC_TXOCTETCOUNT_G 0x0764 +#define DWC_MMC_TXCARRIERERROR 0x0760 +#define DWC_MMC_TXEXCESSCOL 0x075C +#define DWC_MMC_TXLATECOL 0x0758 +#define DWC_MMC_TXDEFERRED 0x0754 +#define DWC_MMC_TXMULTICOL_G 0x0750 +#define DWC_MMC_TXSINGLECOL_G 0x074C +#define DWC_MMC_TXUNDERFLOWERROR 0x0748 +#define DWC_MMC_TXBROADCASTPACKETS_GB 0x0744 +#define DWC_MMC_TXMULTICASTPACKETS_GB 0x0740 +#define DWC_MMC_TXUNICASTPACKETS_GB 0x073C +#define DWC_MMC_TX1024TOMAXOCTETS_GB 0x0738 +#define DWC_MMC_TX512TO1023OCTETS_GB 0x0734 +#define DWC_MMC_TX256TO511OCTETS_GB 0x0730 +#define DWC_MMC_TX128TO255OCTETS_GB 0x072C +#define DWC_MMC_TX65TO127OCTETS_GB 0x0728 +#define DWC_MMC_TX64OCTETS_GB 0x0724 +#define DWC_MMC_TXMULTICASTPACKETS_G 0x0720 +#define DWC_MMC_TXBROADCASTPACKETS_G 0x071C +#define DWC_MMC_TXPACKETCOUNT_GB 0x0718 +#define DWC_MMC_TXOCTETCOUNT_GB 0x0714 + +#define DWC_MMC_RXLPITRANSCNTR 0x07F8 +#define DWC_MMC_RXLPIUSCNTR 0x07F4 +#define DWC_MMC_RXCTRLPACKETS_G 0x07E4 +#define DWC_MMC_RXRCVERROR 0x07E0 +#define DWC_MMC_RXWATCHDOG 0x07DC +#define DWC_MMC_RXVLANPACKETS_GB 0x07D8 +#define DWC_MMC_RXFIFOOVERFLOW 0x07D4 +#define DWC_MMC_RXPAUSEPACKETS 0x07D0 +#define DWC_MMC_RXOUTOFRANGETYPE 0x07CC +#define DWC_MMC_RXLENGTHERROR 0x07C8 +#define DWC_MMC_RXUNICASTPACKETS_G 0x07C4 +#define DWC_MMC_RX1024TOMAXOCTETS_GB 0x07C0 +#define DWC_MMC_RX512TO1023OCTETS_GB 0x07BC +#define DWC_MMC_RX256TO511OCTETS_GB 0x07B8 +#define DWC_MMC_RX128TO255OCTETS_GB 0x07B4 +#define DWC_MMC_RX65TO127OCTETS_GB 0x07B0 +#define DWC_MMC_RX64OCTETS_GB 0x07AC +#define DWC_MMC_RXOVERSIZE_G 0x07A8 +#define DWC_MMC_RXUNDERSIZE_G 0x07A4 +#define DWC_MMC_RXJABBERERROR 0x07A0 +#define DWC_MMC_RXRUNTERROR 0x079C +#define DWC_MMC_RXALIGNMENTERROR 0x0798 +#define DWC_MMC_RXCRCERROR 0x0794 +#define DWC_MMC_RXMULTICASTPACKETS_G 0x0790 +#define DWC_MMC_RXBROADCASTPACKETS_G 0x078C +#define DWC_MMC_RXOCTETCOUNT_G 0x0788 +#define DWC_MMC_RXOCTETCOUNT_GB 0x0784 +#define DWC_MMC_RXPACKETCOUNT_GB 0x0780 + +static int debug = 3; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "DWC_eth_qos debug level (0=none,...,16=all)"); + +/* DMA ring descriptor. These are used as support descriptors for the HW DMA */ +struct ring_desc { + struct sk_buff *skb; + dma_addr_t mapping; + size_t len; +}; + +/* DMA hardware descriptor */ +struct dwceqos_dma_desc { + u32 des0; + u32 des1; + u32 des2; + u32 des3; +} ____cacheline_aligned; + +struct dwceqos_mmc_counters { + __u64 txlpitranscntr; + __u64 txpiuscntr; + __u64 txoversize_g; + __u64 txvlanpackets_g; + __u64 txpausepackets; + __u64 txexcessdef; + __u64 txpacketcount_g; + __u64 txoctetcount_g; + __u64 txcarriererror; + __u64 txexcesscol; + __u64 txlatecol; + __u64 txdeferred; + __u64 txmulticol_g; + __u64 txsinglecol_g; + __u64 txunderflowerror; + __u64 txbroadcastpackets_gb; + __u64 txmulticastpackets_gb; + __u64 txunicastpackets_gb; + __u64 tx1024tomaxoctets_gb; + __u64 tx512to1023octets_gb; + __u64 tx256to511octets_gb; + __u64 tx128to255octets_gb; + __u64 tx65to127octets_gb; + __u64 tx64octets_gb; + __u64 txmulticastpackets_g; + __u64 txbroadcastpackets_g; + __u64 txpacketcount_gb; + __u64 txoctetcount_gb; + + __u64 rxlpitranscntr; + __u64 rxlpiuscntr; + __u64 rxctrlpackets_g; + __u64 rxrcverror; + __u64 rxwatchdog; + __u64 rxvlanpackets_gb; + __u64 rxfifooverflow; + __u64 rxpausepackets; + __u64 rxoutofrangetype; + __u64 rxlengtherror; + __u64 rxunicastpackets_g; + __u64 rx1024tomaxoctets_gb; + __u64 rx512to1023octets_gb; + __u64 rx256to511octets_gb; + __u64 rx128to255octets_gb; + __u64 rx65to127octets_gb; + __u64 rx64octets_gb; + __u64 rxoversize_g; + __u64 rxundersize_g; + __u64 rxjabbererror; + __u64 rxrunterror; + __u64 rxalignmenterror; + __u64 rxcrcerror; + __u64 rxmulticastpackets_g; + __u64 rxbroadcastpackets_g; + __u64 rxoctetcount_g; + __u64 rxoctetcount_gb; + __u64 rxpacketcount_gb; +}; + +/* Ethtool statistics */ + +struct dwceqos_stat { + const char stat_name[ETH_GSTRING_LEN]; + int offset; +}; + +#define STAT_ITEM(name, var) \ + {\ + name,\ + offsetof(struct dwceqos_mmc_counters, var),\ + } + +static const struct dwceqos_stat dwceqos_ethtool_stats[] = { + STAT_ITEM("tx_bytes", txoctetcount_gb), + STAT_ITEM("tx_packets", txpacketcount_gb), + STAT_ITEM("tx_unicst_packets", txunicastpackets_gb), + STAT_ITEM("tx_broadcast_packets", txbroadcastpackets_gb), + STAT_ITEM("tx_multicast_packets", txmulticastpackets_gb), + STAT_ITEM("tx_pause_packets", txpausepackets), + STAT_ITEM("tx_up_to_64_byte_packets", tx64octets_gb), + STAT_ITEM("tx_65_to_127_byte_packets", tx65to127octets_gb), + STAT_ITEM("tx_128_to_255_byte_packets", tx128to255octets_gb), + STAT_ITEM("tx_256_to_511_byte_packets", tx256to511octets_gb), + STAT_ITEM("tx_512_to_1023_byte_packets", tx512to1023octets_gb), + STAT_ITEM("tx_1024_to_maxsize_packets", tx1024tomaxoctets_gb), + STAT_ITEM("tx_underflow_errors", txunderflowerror), + STAT_ITEM("tx_lpi_count", txlpitranscntr), + + STAT_ITEM("rx_bytes", rxoctetcount_gb), + STAT_ITEM("rx_packets", rxpacketcount_gb), + STAT_ITEM("rx_unicast_packets", rxunicastpackets_g), + STAT_ITEM("rx_broadcast_packets", rxbroadcastpackets_g), + STAT_ITEM("rx_multicast_packets", rxmulticastpackets_g), + STAT_ITEM("rx_vlan_packets", rxvlanpackets_gb), + STAT_ITEM("rx_pause_packets", rxpausepackets), + STAT_ITEM("rx_up_to_64_byte_packets", rx64octets_gb), + STAT_ITEM("rx_65_to_127_byte_packets", rx65to127octets_gb), + STAT_ITEM("rx_128_to_255_byte_packets", rx128to255octets_gb), + STAT_ITEM("rx_256_to_511_byte_packets", rx256to511octets_gb), + STAT_ITEM("rx_512_to_1023_byte_packets", rx512to1023octets_gb), + STAT_ITEM("rx_1024_to_maxsize_packets", rx1024tomaxoctets_gb), + STAT_ITEM("rx_fifo_overflow_errors", rxfifooverflow), + STAT_ITEM("rx_oversize_packets", rxoversize_g), + STAT_ITEM("rx_undersize_packets", rxundersize_g), + STAT_ITEM("rx_jabbers", rxjabbererror), + STAT_ITEM("rx_align_errors", rxalignmenterror), + STAT_ITEM("rx_crc_errors", rxcrcerror), + STAT_ITEM("rx_lpi_count", rxlpitranscntr), +}; + +/* Configuration of AXI bus parameters. + * These values depend on the parameters set on the MAC core as well + * as the AXI interconnect. + */ +struct dwceqos_bus_cfg { + /* Enable AXI low-power interface. */ + bool en_lpi; + /* Limit on number of outstanding AXI write requests. */ + u32 write_requests; + /* Limit on number of outstanding AXI read requests. */ + u32 read_requests; + /* Bitmap of allowed AXI burst lengths, 4-256 beats. */ + u32 burst_map; + /* DMA Programmable burst length*/ + u32 tx_pbl; + u32 rx_pbl; +}; + +struct dwceqos_flowcontrol { + int autoneg; + int rx; + int rx_current; + int tx; + int tx_current; +}; + +struct net_local { + void __iomem *baseaddr; + struct clk *phy_ref_clk; + struct clk *apb_pclk; + + struct device_node *phy_node; + struct net_device *ndev; + struct platform_device *pdev; + + u32 msg_enable; + + struct tasklet_struct tx_bdreclaim_tasklet; + struct workqueue_struct *txtimeout_handler_wq; + struct work_struct txtimeout_reinit; + + phy_interface_t phy_interface; + struct phy_device *phy_dev; + struct mii_bus *mii_bus; + + unsigned int link; + unsigned int speed; + unsigned int duplex; + + struct napi_struct napi; + + /* DMA Descriptor Areas */ + struct ring_desc *rx_skb; + struct ring_desc *tx_skb; + + struct dwceqos_dma_desc *tx_descs; + struct dwceqos_dma_desc *rx_descs; + + /* DMA Mapped Descriptor areas*/ + dma_addr_t tx_descs_addr; + dma_addr_t rx_descs_addr; + dma_addr_t tx_descs_tail_addr; + dma_addr_t rx_descs_tail_addr; + + size_t tx_free; + size_t tx_next; + size_t rx_cur; + size_t tx_cur; + + /* Spinlocks for accessing DMA Descriptors */ + spinlock_t tx_lock; + + /* Spinlock for register read-modify-writes. */ + spinlock_t hw_lock; + + u32 feature0; + u32 feature1; + u32 feature2; + + struct dwceqos_bus_cfg bus_cfg; + bool en_tx_lpi_clockgating; + + int eee_enabled; + int eee_active; + int csr_val; + u32 gso_size; + + struct dwceqos_mmc_counters mmc_counters; + /* Protect the mmc_counter updates. */ + spinlock_t stats_lock; + u32 mmc_rx_counters_mask; + u32 mmc_tx_counters_mask; + + struct dwceqos_flowcontrol flowcontrol; +}; + +static void dwceqos_read_mmc_counters(struct net_local *lp, u32 rx_mask, + u32 tx_mask); + +static void dwceqos_set_umac_addr(struct net_local *lp, unsigned char *addr, + unsigned int reg_n); +static int dwceqos_stop(struct net_device *ndev); +static int dwceqos_open(struct net_device *ndev); +static void dwceqos_tx_poll_demand(struct net_local *lp); + +static void dwceqos_set_rx_flowcontrol(struct net_local *lp, bool enable); +static void dwceqos_set_tx_flowcontrol(struct net_local *lp, bool enable); + +static void dwceqos_reset_state(struct net_local *lp); + +#define dwceqos_read(lp, reg) \ + readl_relaxed(((void __iomem *)((lp)->baseaddr)) + (reg)) +#define dwceqos_write(lp, reg, val) \ + writel_relaxed((val), ((void __iomem *)((lp)->baseaddr)) + (reg)) + +static void dwceqos_reset_state(struct net_local *lp) +{ + lp->link = 0; + lp->speed = 0; + lp->duplex = DUPLEX_UNKNOWN; + lp->flowcontrol.rx_current = 0; + lp->flowcontrol.tx_current = 0; + lp->eee_active = 0; + lp->eee_enabled = 0; +} + +static void print_descriptor(struct net_local *lp, int index, int tx) +{ + struct dwceqos_dma_desc *dd; + + if (tx) + dd = (struct dwceqos_dma_desc *)&lp->tx_descs[index]; + else + dd = (struct dwceqos_dma_desc *)&lp->rx_descs[index]; + + pr_info("%s DMA Descriptor #%d@%p Contents:\n", tx ? "TX" : "RX", + index, dd); + pr_info("0x%08x 0x%08x 0x%08x 0x%08x\n", dd->des0, dd->des1, dd->des2, + dd->des3); +} + +static void print_status(struct net_local *lp) +{ + size_t desci, i; + + pr_info("tx_free %zu, tx_cur %zu, tx_next %zu\n", lp->tx_free, + lp->tx_cur, lp->tx_next); + + print_descriptor(lp, lp->rx_cur, 0); + + for (desci = (lp->tx_cur - 10) % DWCEQOS_TX_DCNT, i = 0; + i < DWCEQOS_TX_DCNT; + ++i) { + print_descriptor(lp, desci, 1); + desci = (desci + 1) % DWCEQOS_TX_DCNT; + } + + pr_info("DMA_Debug_Status0: 0x%08x\n", + dwceqos_read(lp, REG_DWCEQOS_DMA_DEBUG_ST0)); + pr_info("DMA_CH0_Status: 0x%08x\n", + dwceqos_read(lp, REG_DWCEQOS_DMA_IS)); + pr_info("DMA_CH0_Current_App_TxDesc: 0x%08x\n", + dwceqos_read(lp, 0x1144)); + pr_info("DMA_CH0_Current_App_TxBuff: 0x%08x\n", + dwceqos_read(lp, 0x1154)); + pr_info("MTL_Debug_Status: 0x%08x\n", + dwceqos_read(lp, REG_DWCEQOS_MTL_DEBUG_ST)); + pr_info("MTL_TXQ0_Debug_Status: 0x%08x\n", + dwceqos_read(lp, REG_DWCEQOS_MTL_TXQ0_DEBUG_ST)); + pr_info("MTL_RXQ0_Debug_Status: 0x%08x\n", + dwceqos_read(lp, REG_DWCEQOS_MTL_RXQ0_DEBUG_ST)); + pr_info("Current TX DMA: 0x%08x, RX DMA: 0x%08x\n", + dwceqos_read(lp, REG_DWCEQOS_DMA_CH0_CUR_TXDESC), + dwceqos_read(lp, REG_DWCEQOS_DMA_CH0_CUR_RXDESC)); +} + +static void dwceqos_mdio_set_csr(struct net_local *lp) +{ + int rate = clk_get_rate(lp->apb_pclk); + + if (rate <= 20000000) + lp->csr_val = DWCEQOS_MAC_MDIO_ADDR_CR_20; + else if (rate <= 35000000) + lp->csr_val = DWCEQOS_MAC_MDIO_ADDR_CR_35; + else if (rate <= 60000000) + lp->csr_val = DWCEQOS_MAC_MDIO_ADDR_CR_60; + else if (rate <= 100000000) + lp->csr_val = DWCEQOS_MAC_MDIO_ADDR_CR_100; + else if (rate <= 150000000) + lp->csr_val = DWCEQOS_MAC_MDIO_ADDR_CR_150; + else if (rate <= 250000000) + lp->csr_val = DWCEQOS_MAC_MDIO_ADDR_CR_250; +} + +/* Simple MDIO functions implementing mii_bus */ +static int dwceqos_mdio_read(struct mii_bus *bus, int mii_id, int phyreg) +{ + struct net_local *lp = bus->priv; + u32 regval; + int i; + int data; + + regval = DWCEQOS_MDIO_PHYADDR(mii_id) | + DWCEQOS_MDIO_PHYREG(phyreg) | + DWCEQOS_MAC_MDIO_ADDR_CR(lp->csr_val) | + DWCEQOS_MAC_MDIO_ADDR_GB | + DWCEQOS_MAC_MDIO_ADDR_GOC_READ; + dwceqos_write(lp, REG_DWCEQOS_MAC_MDIO_ADDR, regval); + + for (i = 0; i < 5; ++i) { + usleep_range(64, 128); + if (!(dwceqos_read(lp, REG_DWCEQOS_MAC_MDIO_ADDR) & + DWCEQOS_MAC_MDIO_ADDR_GB)) + break; + } + + data = dwceqos_read(lp, REG_DWCEQOS_MAC_MDIO_DATA); + if (i == 5) { + netdev_warn(lp->ndev, "MDIO read timed out\n"); + data = 0xffff; + } + + return data & 0xffff; +} + +static int dwceqos_mdio_write(struct mii_bus *bus, int mii_id, int phyreg, + u16 value) +{ + struct net_local *lp = bus->priv; + u32 regval; + int i; + + dwceqos_write(lp, REG_DWCEQOS_MAC_MDIO_DATA, value); + + regval = DWCEQOS_MDIO_PHYADDR(mii_id) | + DWCEQOS_MDIO_PHYREG(phyreg) | + DWCEQOS_MAC_MDIO_ADDR_CR(lp->csr_val) | + DWCEQOS_MAC_MDIO_ADDR_GB | + DWCEQOS_MAC_MDIO_ADDR_GOC_WRITE; + dwceqos_write(lp, REG_DWCEQOS_MAC_MDIO_ADDR, regval); + + for (i = 0; i < 5; ++i) { + usleep_range(64, 128); + if (!(dwceqos_read(lp, REG_DWCEQOS_MAC_MDIO_ADDR) & + DWCEQOS_MAC_MDIO_ADDR_GB)) + break; + } + if (i == 5) + netdev_warn(lp->ndev, "MDIO write timed out\n"); + return 0; +} + +static int dwceqos_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) +{ + struct net_local *lp = netdev_priv(ndev); + struct phy_device *phydev = lp->phy_dev; + + if (!netif_running(ndev)) + return -EINVAL; + + if (!phydev) + return -ENODEV; + + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return phy_mii_ioctl(phydev, rq, cmd); + default: + dev_info(&lp->pdev->dev, "ioctl %X not implemented.\n", cmd); + return -EOPNOTSUPP; + } +} + +static void dwceqos_link_down(struct net_local *lp) +{ + u32 regval; + unsigned long flags; + + /* Indicate link down to the LPI state machine */ + spin_lock_irqsave(&lp->hw_lock, flags); + regval = dwceqos_read(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS); + regval &= ~DWCEQOS_MAC_LPI_CTRL_STATUS_PLS; + dwceqos_write(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS, regval); + spin_unlock_irqrestore(&lp->hw_lock, flags); +} + +static void dwceqos_link_up(struct net_local *lp) +{ + u32 regval; + unsigned long flags; + + /* Indicate link up to the LPI state machine */ + spin_lock_irqsave(&lp->hw_lock, flags); + regval = dwceqos_read(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS); + regval |= DWCEQOS_MAC_LPI_CTRL_STATUS_PLS; + dwceqos_write(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS, regval); + spin_unlock_irqrestore(&lp->hw_lock, flags); + + lp->eee_active = !phy_init_eee(lp->phy_dev, 0); + + /* Check for changed EEE capability */ + if (!lp->eee_active && lp->eee_enabled) { + lp->eee_enabled = 0; + + spin_lock_irqsave(&lp->hw_lock, flags); + regval = dwceqos_read(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS); + regval &= ~DWCEQOS_LPI_CTRL_ENABLE_EEE; + dwceqos_write(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS, regval); + spin_unlock_irqrestore(&lp->hw_lock, flags); + } +} + +static void dwceqos_set_speed(struct net_local *lp) +{ + struct phy_device *phydev = lp->phy_dev; + u32 regval; + + regval = dwceqos_read(lp, REG_DWCEQOS_MAC_CFG); + regval &= ~(DWCEQOS_MAC_CFG_PS | DWCEQOS_MAC_CFG_FES | + DWCEQOS_MAC_CFG_DM); + + if (phydev->duplex) + regval |= DWCEQOS_MAC_CFG_DM; + if (phydev->speed == SPEED_10) { + regval |= DWCEQOS_MAC_CFG_PS; + } else if (phydev->speed == SPEED_100) { + regval |= DWCEQOS_MAC_CFG_PS | + DWCEQOS_MAC_CFG_FES; + } else if (phydev->speed != SPEED_1000) { + netdev_err(lp->ndev, + "unknown PHY speed %d\n", + phydev->speed); + return; + } + + dwceqos_write(lp, REG_DWCEQOS_MAC_CFG, regval); +} + +static void dwceqos_adjust_link(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + struct phy_device *phydev = lp->phy_dev; + int status_change = 0; + + if (phydev->link) { + if ((lp->speed != phydev->speed) || + (lp->duplex != phydev->duplex)) { + dwceqos_set_speed(lp); + + lp->speed = phydev->speed; + lp->duplex = phydev->duplex; + status_change = 1; + } + + if (lp->flowcontrol.autoneg) { + lp->flowcontrol.rx = phydev->pause || + phydev->asym_pause; + lp->flowcontrol.tx = phydev->pause || + phydev->asym_pause; + } + + if (lp->flowcontrol.rx != lp->flowcontrol.rx_current) { + if (netif_msg_link(lp)) + netdev_dbg(ndev, "set rx flow to %d\n", + lp->flowcontrol.rx); + dwceqos_set_rx_flowcontrol(lp, lp->flowcontrol.rx); + lp->flowcontrol.rx_current = lp->flowcontrol.rx; + } + if (lp->flowcontrol.tx != lp->flowcontrol.tx_current) { + if (netif_msg_link(lp)) + netdev_dbg(ndev, "set tx flow to %d\n", + lp->flowcontrol.tx); + dwceqos_set_tx_flowcontrol(lp, lp->flowcontrol.tx); + lp->flowcontrol.tx_current = lp->flowcontrol.tx; + } + } + + if (phydev->link != lp->link) { + lp->link = phydev->link; + status_change = 1; + } + + if (status_change) { + if (phydev->link) { + lp->ndev->trans_start = jiffies; + dwceqos_link_up(lp); + } else { + dwceqos_link_down(lp); + } + phy_print_status(phydev); + } +} + +static int dwceqos_mii_probe(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + struct phy_device *phydev = NULL; + + if (lp->phy_node) { + phydev = of_phy_connect(lp->ndev, + lp->phy_node, + &dwceqos_adjust_link, + 0, + lp->phy_interface); + + if (!phydev) { + netdev_err(ndev, "no PHY found\n"); + return -1; + } + } else { + netdev_err(ndev, "no PHY configured\n"); + return -ENODEV; + } + + if (netif_msg_probe(lp)) + netdev_dbg(lp->ndev, + "phydev %p, phydev->phy_id 0xa%x, phydev->addr 0x%x\n", + phydev, phydev->phy_id, phydev->addr); + + phydev->supported &= PHY_GBIT_FEATURES; + + lp->link = 0; + lp->speed = 0; + lp->duplex = DUPLEX_UNKNOWN; + lp->phy_dev = phydev; + + if (netif_msg_probe(lp)) { + netdev_dbg(lp->ndev, "phy_addr 0x%x, phy_id 0x%08x\n", + lp->phy_dev->addr, lp->phy_dev->phy_id); + + netdev_dbg(lp->ndev, "attach [%s] phy driver\n", + lp->phy_dev->drv->name); + } + + return 0; +} + +static void dwceqos_alloc_rxring_desc(struct net_local *lp, int index) +{ + struct sk_buff *new_skb; + dma_addr_t new_skb_baddr = 0; + + new_skb = netdev_alloc_skb(lp->ndev, DWCEQOS_RX_BUF_SIZE); + if (!new_skb) { + netdev_err(lp->ndev, "alloc_skb error for desc %d\n", index); + goto err_out; + } + + new_skb_baddr = dma_map_single(lp->ndev->dev.parent, + new_skb->data, DWCEQOS_RX_BUF_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(lp->ndev->dev.parent, new_skb_baddr)) { + netdev_err(lp->ndev, "DMA map error\n"); + dev_kfree_skb(new_skb); + new_skb = NULL; + goto err_out; + } + + lp->rx_descs[index].des0 = new_skb_baddr; + lp->rx_descs[index].des1 = 0; + lp->rx_descs[index].des2 = 0; + lp->rx_descs[index].des3 = DWCEQOS_DMA_RDES3_INTE | + DWCEQOS_DMA_RDES3_BUF1V | + DWCEQOS_DMA_RDES3_OWN; + + lp->rx_skb[index].mapping = new_skb_baddr; + lp->rx_skb[index].len = DWCEQOS_RX_BUF_SIZE; + +err_out: + lp->rx_skb[index].skb = new_skb; +} + +static void dwceqos_clean_rings(struct net_local *lp) +{ + int i; + + if (lp->rx_skb) { + for (i = 0; i < DWCEQOS_RX_DCNT; i++) { + if (lp->rx_skb[i].skb) { + dma_unmap_single(lp->ndev->dev.parent, + lp->rx_skb[i].mapping, + lp->rx_skb[i].len, + DMA_FROM_DEVICE); + + dev_kfree_skb(lp->rx_skb[i].skb); + lp->rx_skb[i].skb = NULL; + lp->rx_skb[i].mapping = 0; + } + } + } + + if (lp->tx_skb) { + for (i = 0; i < DWCEQOS_TX_DCNT; i++) { + if (lp->tx_skb[i].skb) { + dev_kfree_skb(lp->tx_skb[i].skb); + lp->tx_skb[i].skb = NULL; + } + if (lp->tx_skb[i].mapping) { + dma_unmap_single(lp->ndev->dev.parent, + lp->tx_skb[i].mapping, + lp->tx_skb[i].len, + DMA_TO_DEVICE); + lp->tx_skb[i].mapping = 0; + } + } + } +} + +static void dwceqos_descriptor_free(struct net_local *lp) +{ + int size; + + dwceqos_clean_rings(lp); + + kfree(lp->tx_skb); + lp->tx_skb = NULL; + kfree(lp->rx_skb); + lp->rx_skb = NULL; + + size = DWCEQOS_RX_DCNT * sizeof(struct dwceqos_dma_desc); + if (lp->rx_descs) { + dma_free_coherent(lp->ndev->dev.parent, size, + (void *)(lp->rx_descs), lp->rx_descs_addr); + lp->rx_descs = NULL; + } + + size = DWCEQOS_TX_DCNT * sizeof(struct dwceqos_dma_desc); + if (lp->tx_descs) { + dma_free_coherent(lp->ndev->dev.parent, size, + (void *)(lp->tx_descs), lp->tx_descs_addr); + lp->tx_descs = NULL; + } +} + +static int dwceqos_descriptor_init(struct net_local *lp) +{ + int size; + u32 i; + + lp->gso_size = 0; + + lp->tx_skb = NULL; + lp->rx_skb = NULL; + lp->rx_descs = NULL; + lp->tx_descs = NULL; + + /* Reset the DMA indexes */ + lp->rx_cur = 0; + lp->tx_cur = 0; + lp->tx_next = 0; + lp->tx_free = DWCEQOS_TX_DCNT; + + /* Allocate Ring descriptors */ + size = DWCEQOS_RX_DCNT * sizeof(struct ring_desc); + lp->rx_skb = kzalloc(size, GFP_KERNEL); + if (!lp->rx_skb) + goto err_out; + + size = DWCEQOS_TX_DCNT * sizeof(struct ring_desc); + lp->tx_skb = kzalloc(size, GFP_KERNEL); + if (!lp->tx_skb) + goto err_out; + + /* Allocate DMA descriptors */ + size = DWCEQOS_RX_DCNT * sizeof(struct dwceqos_dma_desc); + lp->rx_descs = dma_alloc_coherent(lp->ndev->dev.parent, size, + &lp->rx_descs_addr, 0); + if (!lp->rx_descs) + goto err_out; + lp->rx_descs_tail_addr = lp->rx_descs_addr + + sizeof(struct dwceqos_dma_desc) * DWCEQOS_RX_DCNT; + + size = DWCEQOS_TX_DCNT * sizeof(struct dwceqos_dma_desc); + lp->tx_descs = dma_alloc_coherent(lp->ndev->dev.parent, size, + &lp->tx_descs_addr, 0); + if (!lp->tx_descs) + goto err_out; + lp->tx_descs_tail_addr = lp->tx_descs_addr + + sizeof(struct dwceqos_dma_desc) * DWCEQOS_TX_DCNT; + + /* Initialize RX Ring Descriptors and buffers */ + for (i = 0; i < DWCEQOS_RX_DCNT; ++i) { + dwceqos_alloc_rxring_desc(lp, i); + if (!(lp->rx_skb[lp->rx_cur].skb)) + goto err_out; + } + + /* Initialize TX Descriptors */ + for (i = 0; i < DWCEQOS_TX_DCNT; ++i) { + lp->tx_descs[i].des0 = 0; + lp->tx_descs[i].des1 = 0; + lp->tx_descs[i].des2 = 0; + lp->tx_descs[i].des3 = 0; + } + + /* Make descriptor writes visible to the DMA. */ + wmb(); + + return 0; + +err_out: + dwceqos_descriptor_free(lp); + return -ENOMEM; +} + +static int dwceqos_packet_avail(struct net_local *lp) +{ + return !(lp->rx_descs[lp->rx_cur].des3 & DWCEQOS_DMA_RDES3_OWN); +} + +static void dwceqos_get_hwfeatures(struct net_local *lp) +{ + lp->feature0 = dwceqos_read(lp, REG_DWCEQOS_MAC_HW_FEATURE0); + lp->feature1 = dwceqos_read(lp, REG_DWCEQOS_MAC_HW_FEATURE1); + lp->feature2 = dwceqos_read(lp, REG_DWCEQOS_MAC_HW_FEATURE2); +} + +static void dwceqos_dma_enable_txirq(struct net_local *lp) +{ + u32 regval; + unsigned long flags; + + spin_lock_irqsave(&lp->hw_lock, flags); + regval = dwceqos_read(lp, REG_DWCEQOS_DMA_CH0_IE); + regval |= DWCEQOS_DMA_CH0_IE_TIE; + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_IE, regval); + spin_unlock_irqrestore(&lp->hw_lock, flags); +} + +static void dwceqos_dma_disable_txirq(struct net_local *lp) +{ + u32 regval; + unsigned long flags; + + spin_lock_irqsave(&lp->hw_lock, flags); + regval = dwceqos_read(lp, REG_DWCEQOS_DMA_CH0_IE); + regval &= ~DWCEQOS_DMA_CH0_IE_TIE; + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_IE, regval); + spin_unlock_irqrestore(&lp->hw_lock, flags); +} + +static void dwceqos_dma_enable_rxirq(struct net_local *lp) +{ + u32 regval; + unsigned long flags; + + spin_lock_irqsave(&lp->hw_lock, flags); + regval = dwceqos_read(lp, REG_DWCEQOS_DMA_CH0_IE); + regval |= DWCEQOS_DMA_CH0_IE_RIE; + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_IE, regval); + spin_unlock_irqrestore(&lp->hw_lock, flags); +} + +static void dwceqos_dma_disable_rxirq(struct net_local *lp) +{ + u32 regval; + unsigned long flags; + + spin_lock_irqsave(&lp->hw_lock, flags); + regval = dwceqos_read(lp, REG_DWCEQOS_DMA_CH0_IE); + regval &= ~DWCEQOS_DMA_CH0_IE_RIE; + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_IE, regval); + spin_unlock_irqrestore(&lp->hw_lock, flags); +} + +static void dwceqos_enable_mmc_interrupt(struct net_local *lp) +{ + dwceqos_write(lp, REG_DWCEQOS_MMC_RXIRQMASK, 0); + dwceqos_write(lp, REG_DWCEQOS_MMC_TXIRQMASK, 0); +} + +static int dwceqos_mii_init(struct net_local *lp) +{ + int ret = -ENXIO, i; + struct resource res; + struct device_node *mdionode; + + mdionode = of_get_child_by_name(lp->pdev->dev.of_node, "mdio"); + + if (!mdionode) + return 0; + + lp->mii_bus = mdiobus_alloc(); + if (!lp->mii_bus) { + ret = -ENOMEM; + goto err_out; + } + + lp->mii_bus->name = "DWCEQOS MII bus"; + lp->mii_bus->read = &dwceqos_mdio_read; + lp->mii_bus->write = &dwceqos_mdio_write; + lp->mii_bus->priv = lp; + lp->mii_bus->parent = &lp->ndev->dev; + + lp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!lp->mii_bus->irq) { + ret = -ENOMEM; + goto err_out_free_mdiobus; + } + + for (i = 0; i < PHY_MAX_ADDR; i++) + lp->mii_bus->irq[i] = PHY_POLL; + of_address_to_resource(lp->pdev->dev.of_node, 0, &res); + snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%.8llx", + (unsigned long long)res.start); + if (of_mdiobus_register(lp->mii_bus, mdionode)) + goto err_out_free_mdio_irq; + + return 0; + +err_out_free_mdio_irq: + kfree(lp->mii_bus->irq); +err_out_free_mdiobus: + mdiobus_free(lp->mii_bus); +err_out: + of_node_put(mdionode); + return ret; +} + +/* DMA reset. When issued also resets all MTL and MAC registers as well */ +static void dwceqos_reset_hw(struct net_local *lp) +{ + /* Wait (at most) 0.5 seconds for DMA reset*/ + int i = 5000; + u32 reg; + + /* Force gigabit to guarantee a TX clock for GMII. */ + reg = dwceqos_read(lp, REG_DWCEQOS_MAC_CFG); + reg &= ~(DWCEQOS_MAC_CFG_PS | DWCEQOS_MAC_CFG_FES); + reg |= DWCEQOS_MAC_CFG_DM; + dwceqos_write(lp, REG_DWCEQOS_MAC_CFG, reg); + + dwceqos_write(lp, REG_DWCEQOS_DMA_MODE, DWCEQOS_DMA_MODE_SWR); + + do { + udelay(100); + i--; + reg = dwceqos_read(lp, REG_DWCEQOS_DMA_MODE); + } while ((reg & DWCEQOS_DMA_MODE_SWR) && i); + /* We might experience a timeout if the chip clock mux is broken */ + if (!i) + netdev_err(lp->ndev, "DMA reset timed out!\n"); +} + +static void dwceqos_fatal_bus_error(struct net_local *lp, u32 dma_status) +{ + if (dma_status & DWCEQOS_DMA_CH0_IS_TEB) { + netdev_err(lp->ndev, "txdma bus error %s %s (status=%08x)\n", + dma_status & DWCEQOS_DMA_CH0_IS_TX_ERR_READ ? + "read" : "write", + dma_status & DWCEQOS_DMA_CH0_IS_TX_ERR_DESCR ? + "descr" : "data", + dma_status); + + print_status(lp); + } + if (dma_status & DWCEQOS_DMA_CH0_IS_REB) { + netdev_err(lp->ndev, "rxdma bus error %s %s (status=%08x)\n", + dma_status & DWCEQOS_DMA_CH0_IS_RX_ERR_READ ? + "read" : "write", + dma_status & DWCEQOS_DMA_CH0_IS_RX_ERR_DESCR ? + "descr" : "data", + dma_status); + + print_status(lp); + } +} + +static void dwceqos_mmc_interrupt(struct net_local *lp) +{ + unsigned long flags; + + spin_lock_irqsave(&lp->stats_lock, flags); + + /* A latched mmc interrupt can not be masked, we must read + * all the counters with an interrupt pending. + */ + dwceqos_read_mmc_counters(lp, + dwceqos_read(lp, REG_DWCEQOS_MMC_RXIRQ), + dwceqos_read(lp, REG_DWCEQOS_MMC_TXIRQ)); + + spin_unlock_irqrestore(&lp->stats_lock, flags); +} + +static void dwceqos_mac_interrupt(struct net_local *lp) +{ + u32 cause; + + cause = dwceqos_read(lp, REG_DWCEQOS_MAC_IS); + + if (cause & DWCEQOS_MAC_IS_MMC_INT) + dwceqos_mmc_interrupt(lp); +} + +static irqreturn_t dwceqos_interrupt(int irq, void *dev_id) +{ + struct net_device *ndev = dev_id; + struct net_local *lp = netdev_priv(ndev); + + u32 cause; + u32 dma_status; + irqreturn_t ret = IRQ_NONE; + + cause = dwceqos_read(lp, REG_DWCEQOS_DMA_IS); + /* DMA Channel 0 Interrupt */ + if (cause & DWCEQOS_DMA_IS_DC0IS) { + dma_status = dwceqos_read(lp, REG_DWCEQOS_DMA_CH0_STA); + + /* Transmit Interrupt */ + if (dma_status & DWCEQOS_DMA_CH0_IS_TI) { + tasklet_schedule(&lp->tx_bdreclaim_tasklet); + dwceqos_dma_disable_txirq(lp); + } + + /* Receive Interrupt */ + if (dma_status & DWCEQOS_DMA_CH0_IS_RI) { + /* Disable RX IRQs */ + dwceqos_dma_disable_rxirq(lp); + napi_schedule(&lp->napi); + } + + /* Fatal Bus Error interrupt */ + if (unlikely(dma_status & DWCEQOS_DMA_CH0_IS_FBE)) { + dwceqos_fatal_bus_error(lp, dma_status); + + /* errata 9000831707 */ + dma_status |= DWCEQOS_DMA_CH0_IS_TEB | + DWCEQOS_DMA_CH0_IS_REB; + } + + /* Ack all DMA Channel 0 IRQs */ + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_STA, dma_status); + ret = IRQ_HANDLED; + } + + if (cause & DWCEQOS_DMA_IS_MTLIS) { + u32 val = dwceqos_read(lp, REG_DWCEQOS_MTL_Q0_ISCTRL); + + dwceqos_write(lp, REG_DWCEQOS_MTL_Q0_ISCTRL, val); + ret = IRQ_HANDLED; + } + + if (cause & DWCEQOS_DMA_IS_MACIS) { + dwceqos_mac_interrupt(lp); + ret = IRQ_HANDLED; + } + return ret; +} + +static void dwceqos_set_rx_flowcontrol(struct net_local *lp, bool enable) +{ + u32 regval; + unsigned long flags; + + spin_lock_irqsave(&lp->hw_lock, flags); + + regval = dwceqos_read(lp, REG_DWCEQOS_MAC_RX_FLOW_CTRL); + if (enable) + regval |= DWCEQOS_MAC_RX_FLOW_CTRL_RFE; + else + regval &= ~DWCEQOS_MAC_RX_FLOW_CTRL_RFE; + dwceqos_write(lp, REG_DWCEQOS_MAC_RX_FLOW_CTRL, regval); + + spin_unlock_irqrestore(&lp->hw_lock, flags); +} + +static void dwceqos_set_tx_flowcontrol(struct net_local *lp, bool enable) +{ + u32 regval; + unsigned long flags; + + spin_lock_irqsave(&lp->hw_lock, flags); + + /* MTL flow control */ + regval = dwceqos_read(lp, REG_DWCEQOS_MTL_RXQ0_OPER); + if (enable) + regval |= DWCEQOS_MTL_RXQ_EHFC; + else + regval &= ~DWCEQOS_MTL_RXQ_EHFC; + + dwceqos_write(lp, REG_DWCEQOS_MTL_RXQ0_OPER, regval); + + /* MAC flow control */ + regval = dwceqos_read(lp, REG_DWCEQOS_MAC_Q0_TX_FLOW); + if (enable) + regval |= DWCEQOS_MAC_Q0_TX_FLOW_TFE; + else + regval &= ~DWCEQOS_MAC_Q0_TX_FLOW_TFE; + dwceqos_write(lp, REG_DWCEQOS_MAC_Q0_TX_FLOW, regval); + + spin_unlock_irqrestore(&lp->hw_lock, flags); +} + +static void dwceqos_configure_flow_control(struct net_local *lp) +{ + u32 regval; + unsigned long flags; + int RQS, RFD, RFA; + + spin_lock_irqsave(&lp->hw_lock, flags); + + regval = dwceqos_read(lp, REG_DWCEQOS_MTL_RXQ0_OPER); + + /* The queue size is in units of 256 bytes. We want 512 bytes units for + * the threshold fields. + */ + RQS = ((regval >> 20) & 0x3FF) + 1; + RQS /= 2; + + /* The thresholds are relative to a full queue, with a bias + * of 1 KiByte below full. + */ + RFD = RQS / 2 - 2; + RFA = RQS / 8 - 2; + + regval = (regval & 0xFFF000FF) | (RFD << 14) | (RFA << 8); + + if (RFD >= 0 && RFA >= 0) { + dwceqos_write(lp, REG_DWCEQOS_MTL_RXQ0_OPER, regval); + } else { + netdev_warn(lp->ndev, + "FIFO too small for flow control."); + } + + regval = DWCEQOS_MAC_Q0_TX_FLOW_PT(256) | + DWCEQOS_MAC_Q0_TX_FLOW_PLT_4_SLOTS; + + dwceqos_write(lp, REG_DWCEQOS_MAC_Q0_TX_FLOW, regval); + + spin_unlock_irqrestore(&lp->hw_lock, flags); +} + +static void dwceqos_configure_clock(struct net_local *lp) +{ + unsigned long rate_mhz = clk_get_rate(lp->apb_pclk) / 1000000; + + BUG_ON(!rate_mhz); + + dwceqos_write(lp, + REG_DWCEQOS_MAC_1US_TIC_COUNTER, + DWCEQOS_MAC_1US_TIC_COUNTER_VAL(rate_mhz - 1)); +} + +static void dwceqos_configure_bus(struct net_local *lp) +{ + u32 sysbus_reg; + + /* N.B. We do not support the Fixed Burst mode because it + * opens a race window by making HW access to DMA descriptors + * non-atomic. + */ + + sysbus_reg = DWCEQOS_DMA_SYSBUS_MODE_AAL; + + if (lp->bus_cfg.en_lpi) + sysbus_reg |= DWCEQOS_DMA_SYSBUS_MODE_EN_LPI; + + if (lp->bus_cfg.burst_map) + sysbus_reg |= DWCEQOS_DMA_SYSBUS_MODE_BURST( + lp->bus_cfg.burst_map); + else + sysbus_reg |= DWCEQOS_DMA_SYSBUS_MODE_BURST( + DWCEQOS_DMA_SYSBUS_MODE_BURST_DEFAULT); + + if (lp->bus_cfg.read_requests) + sysbus_reg |= DWCEQOS_DMA_SYSBUS_MODE_RD_OSR_LIMIT( + lp->bus_cfg.read_requests - 1); + else + sysbus_reg |= DWCEQOS_DMA_SYSBUS_MODE_RD_OSR_LIMIT( + DWCEQOS_DMA_SYSBUS_MODE_RD_OSR_LIMIT_DEFAULT); + + if (lp->bus_cfg.write_requests) + sysbus_reg |= DWCEQOS_DMA_SYSBUS_MODE_WR_OSR_LIMIT( + lp->bus_cfg.write_requests - 1); + else + sysbus_reg |= DWCEQOS_DMA_SYSBUS_MODE_WR_OSR_LIMIT( + DWCEQOS_DMA_SYSBUS_MODE_WR_OSR_LIMIT_DEFAULT); + + if (netif_msg_hw(lp)) + netdev_dbg(lp->ndev, "SysbusMode %#X\n", sysbus_reg); + + dwceqos_write(lp, REG_DWCEQOS_DMA_SYSBUS_MODE, sysbus_reg); +} + +static void dwceqos_init_hw(struct net_local *lp) +{ + u32 regval; + u32 buswidth; + u32 dma_skip; + + /* Software reset */ + dwceqos_reset_hw(lp); + + dwceqos_configure_bus(lp); + + /* Probe data bus width, 32/64/128 bits. */ + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_TXDESC_TAIL, 0xF); + regval = dwceqos_read(lp, REG_DWCEQOS_DMA_CH0_TXDESC_TAIL); + buswidth = (regval ^ 0xF) + 1; + + /* Cache-align dma descriptors. */ + dma_skip = (sizeof(struct dwceqos_dma_desc) - 16) / buswidth; + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_CTRL, + DWCEQOS_DMA_CH_CTRL_DSL(dma_skip) | + DWCEQOS_DMA_CH_CTRL_PBLX8); + + /* Initialize DMA Channel 0 */ + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_TXDESC_LEN, DWCEQOS_TX_DCNT - 1); + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_RXDESC_LEN, DWCEQOS_RX_DCNT - 1); + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_TXDESC_LIST, + (u32)lp->tx_descs_addr); + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_RXDESC_LIST, + (u32)lp->rx_descs_addr); + + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_TXDESC_TAIL, + lp->tx_descs_tail_addr); + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_RXDESC_TAIL, + lp->rx_descs_tail_addr); + + if (lp->bus_cfg.tx_pbl) + regval = DWCEQOS_DMA_CH_CTRL_PBL(lp->bus_cfg.tx_pbl); + else + regval = DWCEQOS_DMA_CH_CTRL_PBL(2); + + /* Enable TSO if the HW support it */ + if (lp->feature1 & DWCEQOS_MAC_HW_FEATURE1_TSOEN) + regval |= DWCEQOS_DMA_CH_TX_TSE; + + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_TX_CTRL, regval); + + if (lp->bus_cfg.rx_pbl) + regval = DWCEQOS_DMA_CH_CTRL_PBL(lp->bus_cfg.rx_pbl); + else + regval = DWCEQOS_DMA_CH_CTRL_PBL(2); + + regval |= DWCEQOS_DMA_CH_RX_CTRL_BUFSIZE(DWCEQOS_DWCEQOS_RX_BUF_SIZE); + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_RX_CTRL, regval); + + regval |= DWCEQOS_DMA_CH_CTRL_START; + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_RX_CTRL, regval); + + /* Initialize MTL Queues */ + regval = DWCEQOS_MTL_SCHALG_STRICT; + dwceqos_write(lp, REG_DWCEQOS_MTL_OPER, regval); + + regval = DWCEQOS_MTL_TXQ_SIZE( + DWCEQOS_MAC_HW_FEATURE1_TXFIFOSIZE(lp->feature1)) | + DWCEQOS_MTL_TXQ_TXQEN | DWCEQOS_MTL_TXQ_TSF | + DWCEQOS_MTL_TXQ_TTC512; + dwceqos_write(lp, REG_DWCEQOS_MTL_TXQ0_OPER, regval); + + regval = DWCEQOS_MTL_RXQ_SIZE( + DWCEQOS_MAC_HW_FEATURE1_RXFIFOSIZE(lp->feature1)) | + DWCEQOS_MTL_RXQ_FUP | DWCEQOS_MTL_RXQ_FEP | DWCEQOS_MTL_RXQ_RSF; + dwceqos_write(lp, REG_DWCEQOS_MTL_RXQ0_OPER, regval); + + dwceqos_configure_flow_control(lp); + + /* Initialize MAC */ + dwceqos_set_umac_addr(lp, lp->ndev->dev_addr, 0); + + lp->eee_enabled = 0; + + dwceqos_configure_clock(lp); + + /* MMC counters */ + + /* probe implemented counters */ + dwceqos_write(lp, REG_DWCEQOS_MMC_RXIRQMASK, ~0u); + dwceqos_write(lp, REG_DWCEQOS_MMC_TXIRQMASK, ~0u); + lp->mmc_rx_counters_mask = dwceqos_read(lp, REG_DWCEQOS_MMC_RXIRQMASK); + lp->mmc_tx_counters_mask = dwceqos_read(lp, REG_DWCEQOS_MMC_TXIRQMASK); + + dwceqos_write(lp, REG_DWCEQOS_MMC_CTRL, DWCEQOS_MMC_CTRL_CNTRST | + DWCEQOS_MMC_CTRL_RSTONRD); + dwceqos_enable_mmc_interrupt(lp); + + /* Enable Interrupts */ + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_IE, + DWCEQOS_DMA_CH0_IE_NIE | + DWCEQOS_DMA_CH0_IE_RIE | DWCEQOS_DMA_CH0_IE_TIE | + DWCEQOS_DMA_CH0_IE_AIE | + DWCEQOS_DMA_CH0_IE_FBEE); + + dwceqos_write(lp, REG_DWCEQOS_MAC_IE, 0); + + dwceqos_write(lp, REG_DWCEQOS_MAC_CFG, DWCEQOS_MAC_CFG_IPC | + DWCEQOS_MAC_CFG_DM | DWCEQOS_MAC_CFG_TE | DWCEQOS_MAC_CFG_RE); + + /* Start TX DMA */ + regval = dwceqos_read(lp, REG_DWCEQOS_DMA_CH0_TX_CTRL); + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_TX_CTRL, + regval | DWCEQOS_DMA_CH_CTRL_START); + + /* Enable MAC TX/RX */ + regval = dwceqos_read(lp, REG_DWCEQOS_MAC_CFG); + dwceqos_write(lp, REG_DWCEQOS_MAC_CFG, + regval | DWCEQOS_MAC_CFG_TE | DWCEQOS_MAC_CFG_RE); +} + +static void dwceqos_tx_reclaim(unsigned long data) +{ + struct net_device *ndev = (struct net_device *)data; + struct net_local *lp = netdev_priv(ndev); + unsigned int tx_bytes = 0; + unsigned int tx_packets = 0; + + spin_lock(&lp->tx_lock); + + while (lp->tx_free < DWCEQOS_TX_DCNT) { + struct dwceqos_dma_desc *dd = &lp->tx_descs[lp->tx_cur]; + struct ring_desc *rd = &lp->tx_skb[lp->tx_cur]; + + /* Descriptor still being held by DMA ? */ + if (dd->des3 & DWCEQOS_DMA_TDES3_OWN) + break; + + if (rd->mapping) + dma_unmap_single(ndev->dev.parent, rd->mapping, rd->len, + DMA_TO_DEVICE); + + if (unlikely(rd->skb)) { + ++tx_packets; + tx_bytes += rd->skb->len; + dev_consume_skb_any(rd->skb); + } + + rd->skb = NULL; + rd->mapping = 0; + lp->tx_free++; + lp->tx_cur = (lp->tx_cur + 1) % DWCEQOS_TX_DCNT; + + if ((dd->des3 & DWCEQOS_DMA_TDES3_LD) && + (dd->des3 & DWCEQOS_DMA_RDES3_ES)) { + if (netif_msg_tx_err(lp)) + netdev_err(ndev, "TX Error, TDES3 = 0x%x\n", + dd->des3); + if (netif_msg_hw(lp)) + print_status(lp); + } + } + spin_unlock(&lp->tx_lock); + + netdev_completed_queue(ndev, tx_packets, tx_bytes); + + dwceqos_dma_enable_txirq(lp); + netif_wake_queue(ndev); +} + +static int dwceqos_rx(struct net_local *lp, int budget) +{ + struct sk_buff *skb; + u32 tot_size = 0; + unsigned int n_packets = 0; + unsigned int n_descs = 0; + u32 len; + + struct dwceqos_dma_desc *dd; + struct sk_buff *new_skb; + dma_addr_t new_skb_baddr = 0; + + while (n_descs < budget) { + if (!dwceqos_packet_avail(lp)) + break; + + new_skb = netdev_alloc_skb(lp->ndev, DWCEQOS_RX_BUF_SIZE); + if (!new_skb) { + netdev_err(lp->ndev, "no memory for new sk_buff\n"); + break; + } + + /* Get dma handle of skb->data */ + new_skb_baddr = (u32)dma_map_single(lp->ndev->dev.parent, + new_skb->data, + DWCEQOS_RX_BUF_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(lp->ndev->dev.parent, new_skb_baddr)) { + netdev_err(lp->ndev, "DMA map error\n"); + dev_kfree_skb(new_skb); + break; + } + + /* Read descriptor data after reading owner bit. */ + dma_rmb(); + + dd = &lp->rx_descs[lp->rx_cur]; + len = DWCEQOS_DMA_RDES3_PL(dd->des3); + skb = lp->rx_skb[lp->rx_cur].skb; + + /* Unmap old buffer */ + dma_unmap_single(lp->ndev->dev.parent, + lp->rx_skb[lp->rx_cur].mapping, + lp->rx_skb[lp->rx_cur].len, DMA_FROM_DEVICE); + + /* Discard packet on reception error or bad checksum */ + if ((dd->des3 & DWCEQOS_DMA_RDES3_ES) || + (dd->des1 & DWCEQOS_DMA_RDES1_IPCE)) { + dev_kfree_skb(skb); + skb = NULL; + } else { + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, lp->ndev); + switch (dd->des1 & DWCEQOS_DMA_RDES1_PT) { + case DWCEQOS_DMA_RDES1_PT_UDP: + case DWCEQOS_DMA_RDES1_PT_TCP: + case DWCEQOS_DMA_RDES1_PT_ICMP: + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + default: + skb->ip_summed = CHECKSUM_NONE; + break; + } + } + + if (unlikely(!skb)) { + if (netif_msg_rx_err(lp)) + netdev_dbg(lp->ndev, "rx error: des3=%X\n", + lp->rx_descs[lp->rx_cur].des3); + } else { + tot_size += skb->len; + n_packets++; + + netif_receive_skb(skb); + } + + lp->rx_descs[lp->rx_cur].des0 = new_skb_baddr; + lp->rx_descs[lp->rx_cur].des1 = 0; + lp->rx_descs[lp->rx_cur].des2 = 0; + /* The DMA must observe des0/1/2 written before des3. */ + wmb(); + lp->rx_descs[lp->rx_cur].des3 = DWCEQOS_DMA_RDES3_INTE | + DWCEQOS_DMA_RDES3_OWN | + DWCEQOS_DMA_RDES3_BUF1V; + + lp->rx_skb[lp->rx_cur].mapping = new_skb_baddr; + lp->rx_skb[lp->rx_cur].len = DWCEQOS_RX_BUF_SIZE; + lp->rx_skb[lp->rx_cur].skb = new_skb; + + n_descs++; + lp->rx_cur = (lp->rx_cur + 1) % DWCEQOS_RX_DCNT; + } + + /* Make sure any ownership update is written to the descriptors before + * DMA wakeup. + */ + wmb(); + + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_STA, DWCEQOS_DMA_CH0_IS_RI); + /* Wake up RX by writing tail pointer */ + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_RXDESC_TAIL, + lp->rx_descs_tail_addr); + + return n_descs; +} + +static int dwceqos_rx_poll(struct napi_struct *napi, int budget) +{ + struct net_local *lp = container_of(napi, struct net_local, napi); + int work_done = 0; + + work_done = dwceqos_rx(lp, budget - work_done); + + if (!dwceqos_packet_avail(lp) && work_done < budget) { + napi_complete(napi); + dwceqos_dma_enable_rxirq(lp); + } else { + work_done = budget; + } + + return work_done; +} + +/* Reinitialize function if a TX timed out */ +static void dwceqos_reinit_for_txtimeout(struct work_struct *data) +{ + struct net_local *lp = container_of(data, struct net_local, + txtimeout_reinit); + + netdev_err(lp->ndev, "transmit timeout %d s, resetting...\n", + DWCEQOS_TX_TIMEOUT); + + if (netif_msg_hw(lp)) + print_status(lp); + + rtnl_lock(); + dwceqos_stop(lp->ndev); + dwceqos_open(lp->ndev); + rtnl_unlock(); +} + +/* DT Probing function called by main probe */ +static inline int dwceqos_probe_config_dt(struct platform_device *pdev) +{ + struct net_device *ndev; + struct net_local *lp; + const void *mac_address; + struct dwceqos_bus_cfg *bus_cfg; + struct device_node *np = pdev->dev.of_node; + + ndev = platform_get_drvdata(pdev); + lp = netdev_priv(ndev); + bus_cfg = &lp->bus_cfg; + + /* Set the MAC address. */ + mac_address = of_get_mac_address(pdev->dev.of_node); + if (mac_address) + ether_addr_copy(ndev->dev_addr, mac_address); + + /* These are all optional parameters */ + lp->en_tx_lpi_clockgating = of_property_read_bool(np, + "snps,en-tx-lpi-clockgating"); + bus_cfg->en_lpi = of_property_read_bool(np, "snps,en-lpi"); + of_property_read_u32(np, "snps,write-requests", + &bus_cfg->write_requests); + of_property_read_u32(np, "snps,read-requests", &bus_cfg->read_requests); + of_property_read_u32(np, "snps,burst-map", &bus_cfg->burst_map); + of_property_read_u32(np, "snps,txpbl", &bus_cfg->tx_pbl); + of_property_read_u32(np, "snps,rxpbl", &bus_cfg->rx_pbl); + + netdev_dbg(ndev, "BusCfg: lpi:%u wr:%u rr:%u bm:%X rxpbl:%u txpbl:%d\n", + bus_cfg->en_lpi, + bus_cfg->write_requests, + bus_cfg->read_requests, + bus_cfg->burst_map, + bus_cfg->rx_pbl, + bus_cfg->tx_pbl); + + return 0; +} + +static int dwceqos_open(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + int res; + + dwceqos_reset_state(lp); + res = dwceqos_descriptor_init(lp); + if (res) { + netdev_err(ndev, "Unable to allocate DMA memory, rc %d\n", res); + return res; + } + netdev_reset_queue(ndev); + + napi_enable(&lp->napi); + phy_start(lp->phy_dev); + dwceqos_init_hw(lp); + + netif_start_queue(ndev); + tasklet_enable(&lp->tx_bdreclaim_tasklet); + + return 0; +} + +static bool dweqos_is_tx_dma_suspended(struct net_local *lp) +{ + u32 reg; + + reg = dwceqos_read(lp, REG_DWCEQOS_DMA_DEBUG_ST0); + reg = DMA_GET_TX_STATE_CH0(reg); + + return reg == DMA_TX_CH_SUSPENDED; +} + +static void dwceqos_drain_dma(struct net_local *lp) +{ + /* Wait for all pending TX buffers to be sent. Upper limit based + * on max frame size on a 10 Mbit link. + */ + size_t limit = (DWCEQOS_TX_DCNT * 1250) / 100; + + while (!dweqos_is_tx_dma_suspended(lp) && limit--) + usleep_range(100, 200); +} + +static int dwceqos_stop(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + + phy_stop(lp->phy_dev); + + tasklet_disable(&lp->tx_bdreclaim_tasklet); + netif_stop_queue(ndev); + napi_disable(&lp->napi); + + dwceqos_drain_dma(lp); + + netif_tx_lock(lp->ndev); + dwceqos_reset_hw(lp); + dwceqos_descriptor_free(lp); + netif_tx_unlock(lp->ndev); + + return 0; +} + +static void dwceqos_dmadesc_set_ctx(struct net_local *lp, + unsigned short gso_size) +{ + struct dwceqos_dma_desc *dd = &lp->tx_descs[lp->tx_next]; + + dd->des0 = 0; + dd->des1 = 0; + dd->des2 = gso_size; + dd->des3 = DWCEQOS_DMA_TDES3_CTXT | DWCEQOS_DMA_TDES3_TCMSSV; + + lp->tx_next = (lp->tx_next + 1) % DWCEQOS_TX_DCNT; +} + +static void dwceqos_tx_poll_demand(struct net_local *lp) +{ + dwceqos_write(lp, REG_DWCEQOS_DMA_CH0_TXDESC_TAIL, + lp->tx_descs_tail_addr); +} + +struct dwceqos_tx { + size_t nr_descriptors; + size_t initial_descriptor; + size_t last_descriptor; + size_t prev_gso_size; + size_t network_header_len; +}; + +static void dwceqos_tx_prepare(struct sk_buff *skb, struct net_local *lp, + struct dwceqos_tx *tx) +{ + size_t n = 1; + size_t i; + + if (skb_is_gso(skb) && skb_shinfo(skb)->gso_size != lp->gso_size) + ++n; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + n += (skb_frag_size(frag) + BYTES_PER_DMA_DESC - 1) / + BYTES_PER_DMA_DESC; + } + + tx->nr_descriptors = n; + tx->initial_descriptor = lp->tx_next; + tx->last_descriptor = lp->tx_next; + tx->prev_gso_size = lp->gso_size; + + tx->network_header_len = skb_transport_offset(skb); + if (skb_is_gso(skb)) + tx->network_header_len += tcp_hdrlen(skb); +} + +static int dwceqos_tx_linear(struct sk_buff *skb, struct net_local *lp, + struct dwceqos_tx *tx) +{ + struct ring_desc *rd; + struct dwceqos_dma_desc *dd; + size_t payload_len; + dma_addr_t dma_handle; + + if (skb_is_gso(skb) && skb_shinfo(skb)->gso_size != lp->gso_size) { + dwceqos_dmadesc_set_ctx(lp, skb_shinfo(skb)->gso_size); + lp->gso_size = skb_shinfo(skb)->gso_size; + } + + dma_handle = dma_map_single(lp->ndev->dev.parent, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + + if (dma_mapping_error(lp->ndev->dev.parent, dma_handle)) { + netdev_err(lp->ndev, "TX DMA Mapping error\n"); + return -ENOMEM; + } + + rd = &lp->tx_skb[lp->tx_next]; + dd = &lp->tx_descs[lp->tx_next]; + + rd->skb = NULL; + rd->len = skb_headlen(skb); + rd->mapping = dma_handle; + + /* Set up DMA Descriptor */ + dd->des0 = dma_handle; + + if (skb_is_gso(skb)) { + payload_len = skb_headlen(skb) - tx->network_header_len; + + if (payload_len) + dd->des1 = dma_handle + tx->network_header_len; + dd->des2 = tx->network_header_len | + DWCEQOS_DMA_DES2_B2L(payload_len); + dd->des3 = DWCEQOS_DMA_TDES3_TSE | + DWCEQOS_DMA_DES3_THL((tcp_hdrlen(skb) / 4)) | + (skb->len - tx->network_header_len); + } else { + dd->des1 = 0; + dd->des2 = skb_headlen(skb); + dd->des3 = skb->len; + + switch (skb->ip_summed) { + case CHECKSUM_PARTIAL: + dd->des3 |= DWCEQOS_DMA_TDES3_CA; + case CHECKSUM_NONE: + case CHECKSUM_UNNECESSARY: + case CHECKSUM_COMPLETE: + default: + break; + } + } + + dd->des3 |= DWCEQOS_DMA_TDES3_FD; + if (lp->tx_next != tx->initial_descriptor) + dd->des3 |= DWCEQOS_DMA_TDES3_OWN; + + tx->last_descriptor = lp->tx_next; + lp->tx_next = (lp->tx_next + 1) % DWCEQOS_TX_DCNT; + + return 0; +} + +static int dwceqos_tx_frags(struct sk_buff *skb, struct net_local *lp, + struct dwceqos_tx *tx) +{ + struct ring_desc *rd = NULL; + struct dwceqos_dma_desc *dd; + dma_addr_t dma_handle; + size_t i; + + /* Setup more ring and DMA descriptor if the packet is fragmented */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; ++i) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + size_t frag_size; + size_t consumed_size; + + /* Map DMA Area */ + dma_handle = skb_frag_dma_map(lp->ndev->dev.parent, frag, 0, + skb_frag_size(frag), + DMA_TO_DEVICE); + if (dma_mapping_error(lp->ndev->dev.parent, dma_handle)) { + netdev_err(lp->ndev, "DMA Mapping error\n"); + return -ENOMEM; + } + + /* order-3 fragments span more than one descriptor. */ + frag_size = skb_frag_size(frag); + consumed_size = 0; + while (consumed_size < frag_size) { + size_t dma_size = min_t(size_t, 16376, + frag_size - consumed_size); + + rd = &lp->tx_skb[lp->tx_next]; + memset(rd, 0, sizeof(*rd)); + + dd = &lp->tx_descs[lp->tx_next]; + + /* Set DMA Descriptor fields */ + dd->des0 = dma_handle; + dd->des1 = 0; + dd->des2 = dma_size; + + if (skb_is_gso(skb)) + dd->des3 = (skb->len - tx->network_header_len); + else + dd->des3 = skb->len; + + dd->des3 |= DWCEQOS_DMA_TDES3_OWN; + + tx->last_descriptor = lp->tx_next; + lp->tx_next = (lp->tx_next + 1) % DWCEQOS_TX_DCNT; + consumed_size += dma_size; + } + + rd->len = skb_frag_size(frag); + rd->mapping = dma_handle; + } + + return 0; +} + +static void dwceqos_tx_finalize(struct sk_buff *skb, struct net_local *lp, + struct dwceqos_tx *tx) +{ + lp->tx_descs[tx->last_descriptor].des3 |= DWCEQOS_DMA_TDES3_LD; + lp->tx_descs[tx->last_descriptor].des2 |= DWCEQOS_DMA_TDES2_IOC; + + lp->tx_skb[tx->last_descriptor].skb = skb; + + /* Make all descriptor updates visible to the DMA before setting the + * owner bit. + */ + wmb(); + + lp->tx_descs[tx->initial_descriptor].des3 |= DWCEQOS_DMA_TDES3_OWN; + + /* Make the owner bit visible before TX wakeup. */ + wmb(); + + dwceqos_tx_poll_demand(lp); +} + +static void dwceqos_tx_rollback(struct net_local *lp, struct dwceqos_tx *tx) +{ + size_t i = tx->initial_descriptor; + + while (i != lp->tx_next) { + if (lp->tx_skb[i].mapping) + dma_unmap_single(lp->ndev->dev.parent, + lp->tx_skb[i].mapping, + lp->tx_skb[i].len, + DMA_TO_DEVICE); + + lp->tx_skb[i].mapping = 0; + lp->tx_skb[i].skb = NULL; + + memset(&lp->tx_descs[i], 0, sizeof(lp->tx_descs[i])); + + i = (i + 1) % DWCEQOS_TX_DCNT; + } + + lp->tx_next = tx->initial_descriptor; + lp->gso_size = tx->prev_gso_size; +} + +static int dwceqos_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + struct dwceqos_tx trans; + int err; + + dwceqos_tx_prepare(skb, lp, &trans); + if (lp->tx_free < trans.nr_descriptors) { + netif_stop_queue(ndev); + return NETDEV_TX_BUSY; + } + + err = dwceqos_tx_linear(skb, lp, &trans); + if (err) + goto tx_error; + + err = dwceqos_tx_frags(skb, lp, &trans); + if (err) + goto tx_error; + + WARN_ON(lp->tx_next != + ((trans.initial_descriptor + trans.nr_descriptors) % + DWCEQOS_TX_DCNT)); + + dwceqos_tx_finalize(skb, lp, &trans); + + netdev_sent_queue(ndev, skb->len); + + spin_lock_bh(&lp->tx_lock); + lp->tx_free -= trans.nr_descriptors; + spin_unlock_bh(&lp->tx_lock); + + ndev->trans_start = jiffies; + return 0; + +tx_error: + dwceqos_tx_rollback(lp, &trans); + dev_kfree_skb(skb); + return 0; +} + +/* Set MAC address and then update HW accordingly */ +static int dwceqos_set_mac_address(struct net_device *ndev, void *addr) +{ + struct net_local *lp = netdev_priv(ndev); + struct sockaddr *hwaddr = (struct sockaddr *)addr; + + if (netif_running(ndev)) + return -EBUSY; + + if (!is_valid_ether_addr(hwaddr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(ndev->dev_addr, hwaddr->sa_data, ndev->addr_len); + + dwceqos_set_umac_addr(lp, lp->ndev->dev_addr, 0); + return 0; +} + +static void dwceqos_tx_timeout(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + + queue_work(lp->txtimeout_handler_wq, &lp->txtimeout_reinit); +} + +static void dwceqos_set_umac_addr(struct net_local *lp, unsigned char *addr, + unsigned int reg_n) +{ + unsigned long data; + + data = (addr[5] << 8) | addr[4]; + dwceqos_write(lp, DWCEQOS_ADDR_HIGH(reg_n), + data | DWCEQOS_MAC_MAC_ADDR_HI_EN); + data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + dwceqos_write(lp, DWCEQOS_ADDR_LOW(reg_n), data); +} + +static void dwceqos_disable_umac_addr(struct net_local *lp, unsigned int reg_n) +{ + /* Do not disable MAC address 0 */ + if (reg_n != 0) + dwceqos_write(lp, DWCEQOS_ADDR_HIGH(reg_n), 0); +} + +static void dwceqos_set_rx_mode(struct net_device *ndev) +{ + struct net_local *lp = netdev_priv(ndev); + u32 regval = 0; + u32 mc_filter[2]; + int reg = 1; + struct netdev_hw_addr *ha; + unsigned int max_mac_addr; + + max_mac_addr = DWCEQOS_MAX_PERFECT_ADDRESSES(lp->feature1); + + if (ndev->flags & IFF_PROMISC) { + regval = DWCEQOS_MAC_PKT_FILT_PR; + } else if (((netdev_mc_count(ndev) > DWCEQOS_HASH_TABLE_SIZE) || + (ndev->flags & IFF_ALLMULTI))) { + regval = DWCEQOS_MAC_PKT_FILT_PM; + dwceqos_write(lp, REG_DWCEQOS_HASTABLE_LO, 0xffffffff); + dwceqos_write(lp, REG_DWCEQOS_HASTABLE_HI, 0xffffffff); + } else if (!netdev_mc_empty(ndev)) { + regval = DWCEQOS_MAC_PKT_FILT_HMC; + memset(mc_filter, 0, sizeof(mc_filter)); + netdev_for_each_mc_addr(ha, ndev) { + /* The upper 6 bits of the calculated CRC are used to + * index the contens of the hash table + */ + int bit_nr = bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26; + /* The most significant bit determines the register + * to use (H/L) while the other 5 bits determine + * the bit within the register. + */ + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + } + dwceqos_write(lp, REG_DWCEQOS_HASTABLE_LO, mc_filter[0]); + dwceqos_write(lp, REG_DWCEQOS_HASTABLE_HI, mc_filter[1]); + } + if (netdev_uc_count(ndev) > max_mac_addr) { + regval |= DWCEQOS_MAC_PKT_FILT_PR; + } else { + netdev_for_each_uc_addr(ha, ndev) { + dwceqos_set_umac_addr(lp, ha->addr, reg); + reg++; + } + for (; reg < DWCEQOS_MAX_PERFECT_ADDRESSES(lp->feature1); reg++) + dwceqos_disable_umac_addr(lp, reg); + } + dwceqos_write(lp, REG_DWCEQOS_MAC_PKT_FILT, regval); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void dwceqos_poll_controller(struct net_device *ndev) +{ + disable_irq(ndev->irq); + dwceqos_interrupt(ndev->irq, ndev); + enable_irq(ndev->irq); +} +#endif + +static void dwceqos_read_mmc_counters(struct net_local *lp, u32 rx_mask, + u32 tx_mask) +{ + if (tx_mask & BIT(27)) + lp->mmc_counters.txlpitranscntr += + dwceqos_read(lp, DWC_MMC_TXLPITRANSCNTR); + if (tx_mask & BIT(26)) + lp->mmc_counters.txpiuscntr += + dwceqos_read(lp, DWC_MMC_TXLPIUSCNTR); + if (tx_mask & BIT(25)) + lp->mmc_counters.txoversize_g += + dwceqos_read(lp, DWC_MMC_TXOVERSIZE_G); + if (tx_mask & BIT(24)) + lp->mmc_counters.txvlanpackets_g += + dwceqos_read(lp, DWC_MMC_TXVLANPACKETS_G); + if (tx_mask & BIT(23)) + lp->mmc_counters.txpausepackets += + dwceqos_read(lp, DWC_MMC_TXPAUSEPACKETS); + if (tx_mask & BIT(22)) + lp->mmc_counters.txexcessdef += + dwceqos_read(lp, DWC_MMC_TXEXCESSDEF); + if (tx_mask & BIT(21)) + lp->mmc_counters.txpacketcount_g += + dwceqos_read(lp, DWC_MMC_TXPACKETCOUNT_G); + if (tx_mask & BIT(20)) + lp->mmc_counters.txoctetcount_g += + dwceqos_read(lp, DWC_MMC_TXOCTETCOUNT_G); + if (tx_mask & BIT(19)) + lp->mmc_counters.txcarriererror += + dwceqos_read(lp, DWC_MMC_TXCARRIERERROR); + if (tx_mask & BIT(18)) + lp->mmc_counters.txexcesscol += + dwceqos_read(lp, DWC_MMC_TXEXCESSCOL); + if (tx_mask & BIT(17)) + lp->mmc_counters.txlatecol += + dwceqos_read(lp, DWC_MMC_TXLATECOL); + if (tx_mask & BIT(16)) + lp->mmc_counters.txdeferred += + dwceqos_read(lp, DWC_MMC_TXDEFERRED); + if (tx_mask & BIT(15)) + lp->mmc_counters.txmulticol_g += + dwceqos_read(lp, DWC_MMC_TXMULTICOL_G); + if (tx_mask & BIT(14)) + lp->mmc_counters.txsinglecol_g += + dwceqos_read(lp, DWC_MMC_TXSINGLECOL_G); + if (tx_mask & BIT(13)) + lp->mmc_counters.txunderflowerror += + dwceqos_read(lp, DWC_MMC_TXUNDERFLOWERROR); + if (tx_mask & BIT(12)) + lp->mmc_counters.txbroadcastpackets_gb += + dwceqos_read(lp, DWC_MMC_TXBROADCASTPACKETS_GB); + if (tx_mask & BIT(11)) + lp->mmc_counters.txmulticastpackets_gb += + dwceqos_read(lp, DWC_MMC_TXMULTICASTPACKETS_GB); + if (tx_mask & BIT(10)) + lp->mmc_counters.txunicastpackets_gb += + dwceqos_read(lp, DWC_MMC_TXUNICASTPACKETS_GB); + if (tx_mask & BIT(9)) + lp->mmc_counters.tx1024tomaxoctets_gb += + dwceqos_read(lp, DWC_MMC_TX1024TOMAXOCTETS_GB); + if (tx_mask & BIT(8)) + lp->mmc_counters.tx512to1023octets_gb += + dwceqos_read(lp, DWC_MMC_TX512TO1023OCTETS_GB); + if (tx_mask & BIT(7)) + lp->mmc_counters.tx256to511octets_gb += + dwceqos_read(lp, DWC_MMC_TX256TO511OCTETS_GB); + if (tx_mask & BIT(6)) + lp->mmc_counters.tx128to255octets_gb += + dwceqos_read(lp, DWC_MMC_TX128TO255OCTETS_GB); + if (tx_mask & BIT(5)) + lp->mmc_counters.tx65to127octets_gb += + dwceqos_read(lp, DWC_MMC_TX65TO127OCTETS_GB); + if (tx_mask & BIT(4)) + lp->mmc_counters.tx64octets_gb += + dwceqos_read(lp, DWC_MMC_TX64OCTETS_GB); + if (tx_mask & BIT(3)) + lp->mmc_counters.txmulticastpackets_g += + dwceqos_read(lp, DWC_MMC_TXMULTICASTPACKETS_G); + if (tx_mask & BIT(2)) + lp->mmc_counters.txbroadcastpackets_g += + dwceqos_read(lp, DWC_MMC_TXBROADCASTPACKETS_G); + if (tx_mask & BIT(1)) + lp->mmc_counters.txpacketcount_gb += + dwceqos_read(lp, DWC_MMC_TXPACKETCOUNT_GB); + if (tx_mask & BIT(0)) + lp->mmc_counters.txoctetcount_gb += + dwceqos_read(lp, DWC_MMC_TXOCTETCOUNT_GB); + + if (rx_mask & BIT(27)) + lp->mmc_counters.rxlpitranscntr += + dwceqos_read(lp, DWC_MMC_RXLPITRANSCNTR); + if (rx_mask & BIT(26)) + lp->mmc_counters.rxlpiuscntr += + dwceqos_read(lp, DWC_MMC_RXLPIUSCNTR); + if (rx_mask & BIT(25)) + lp->mmc_counters.rxctrlpackets_g += + dwceqos_read(lp, DWC_MMC_RXCTRLPACKETS_G); + if (rx_mask & BIT(24)) + lp->mmc_counters.rxrcverror += + dwceqos_read(lp, DWC_MMC_RXRCVERROR); + if (rx_mask & BIT(23)) + lp->mmc_counters.rxwatchdog += + dwceqos_read(lp, DWC_MMC_RXWATCHDOG); + if (rx_mask & BIT(22)) + lp->mmc_counters.rxvlanpackets_gb += + dwceqos_read(lp, DWC_MMC_RXVLANPACKETS_GB); + if (rx_mask & BIT(21)) + lp->mmc_counters.rxfifooverflow += + dwceqos_read(lp, DWC_MMC_RXFIFOOVERFLOW); + if (rx_mask & BIT(20)) + lp->mmc_counters.rxpausepackets += + dwceqos_read(lp, DWC_MMC_RXPAUSEPACKETS); + if (rx_mask & BIT(19)) + lp->mmc_counters.rxoutofrangetype += + dwceqos_read(lp, DWC_MMC_RXOUTOFRANGETYPE); + if (rx_mask & BIT(18)) + lp->mmc_counters.rxlengtherror += + dwceqos_read(lp, DWC_MMC_RXLENGTHERROR); + if (rx_mask & BIT(17)) + lp->mmc_counters.rxunicastpackets_g += + dwceqos_read(lp, DWC_MMC_RXUNICASTPACKETS_G); + if (rx_mask & BIT(16)) + lp->mmc_counters.rx1024tomaxoctets_gb += + dwceqos_read(lp, DWC_MMC_RX1024TOMAXOCTETS_GB); + if (rx_mask & BIT(15)) + lp->mmc_counters.rx512to1023octets_gb += + dwceqos_read(lp, DWC_MMC_RX512TO1023OCTETS_GB); + if (rx_mask & BIT(14)) + lp->mmc_counters.rx256to511octets_gb += + dwceqos_read(lp, DWC_MMC_RX256TO511OCTETS_GB); + if (rx_mask & BIT(13)) + lp->mmc_counters.rx128to255octets_gb += + dwceqos_read(lp, DWC_MMC_RX128TO255OCTETS_GB); + if (rx_mask & BIT(12)) + lp->mmc_counters.rx65to127octets_gb += + dwceqos_read(lp, DWC_MMC_RX65TO127OCTETS_GB); + if (rx_mask & BIT(11)) + lp->mmc_counters.rx64octets_gb += + dwceqos_read(lp, DWC_MMC_RX64OCTETS_GB); + if (rx_mask & BIT(10)) + lp->mmc_counters.rxoversize_g += + dwceqos_read(lp, DWC_MMC_RXOVERSIZE_G); + if (rx_mask & BIT(9)) + lp->mmc_counters.rxundersize_g += + dwceqos_read(lp, DWC_MMC_RXUNDERSIZE_G); + if (rx_mask & BIT(8)) + lp->mmc_counters.rxjabbererror += + dwceqos_read(lp, DWC_MMC_RXJABBERERROR); + if (rx_mask & BIT(7)) + lp->mmc_counters.rxrunterror += + dwceqos_read(lp, DWC_MMC_RXRUNTERROR); + if (rx_mask & BIT(6)) + lp->mmc_counters.rxalignmenterror += + dwceqos_read(lp, DWC_MMC_RXALIGNMENTERROR); + if (rx_mask & BIT(5)) + lp->mmc_counters.rxcrcerror += + dwceqos_read(lp, DWC_MMC_RXCRCERROR); + if (rx_mask & BIT(4)) + lp->mmc_counters.rxmulticastpackets_g += + dwceqos_read(lp, DWC_MMC_RXMULTICASTPACKETS_G); + if (rx_mask & BIT(3)) + lp->mmc_counters.rxbroadcastpackets_g += + dwceqos_read(lp, DWC_MMC_RXBROADCASTPACKETS_G); + if (rx_mask & BIT(2)) + lp->mmc_counters.rxoctetcount_g += + dwceqos_read(lp, DWC_MMC_RXOCTETCOUNT_G); + if (rx_mask & BIT(1)) + lp->mmc_counters.rxoctetcount_gb += + dwceqos_read(lp, DWC_MMC_RXOCTETCOUNT_GB); + if (rx_mask & BIT(0)) + lp->mmc_counters.rxpacketcount_gb += + dwceqos_read(lp, DWC_MMC_RXPACKETCOUNT_GB); +} + +static struct rtnl_link_stats64* +dwceqos_get_stats64(struct net_device *ndev, struct rtnl_link_stats64 *s) +{ + unsigned long flags; + struct net_local *lp = netdev_priv(ndev); + struct dwceqos_mmc_counters *hwstats = &lp->mmc_counters; + + spin_lock_irqsave(&lp->stats_lock, flags); + dwceqos_read_mmc_counters(lp, lp->mmc_rx_counters_mask, + lp->mmc_tx_counters_mask); + spin_unlock_irqrestore(&lp->stats_lock, flags); + + s->rx_packets = hwstats->rxpacketcount_gb; + s->rx_bytes = hwstats->rxoctetcount_gb; + s->rx_errors = hwstats->rxpacketcount_gb - + hwstats->rxbroadcastpackets_g - + hwstats->rxmulticastpackets_g - + hwstats->rxunicastpackets_g; + s->multicast = hwstats->rxmulticastpackets_g; + s->rx_length_errors = hwstats->rxlengtherror; + s->rx_crc_errors = hwstats->rxcrcerror; + s->rx_fifo_errors = hwstats->rxfifooverflow; + + s->tx_packets = hwstats->txpacketcount_gb; + s->tx_bytes = hwstats->txoctetcount_gb; + + if (lp->mmc_tx_counters_mask & BIT(21)) + s->tx_errors = hwstats->txpacketcount_gb - + hwstats->txpacketcount_g; + else + s->tx_errors = hwstats->txunderflowerror + + hwstats->txcarriererror; + + return s; +} + +static int +dwceqos_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) +{ + struct net_local *lp = netdev_priv(ndev); + struct phy_device *phydev = lp->phy_dev; + + if (!phydev) + return -ENODEV; + + return phy_ethtool_gset(phydev, ecmd); +} + +static int +dwceqos_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) +{ + struct net_local *lp = netdev_priv(ndev); + struct phy_device *phydev = lp->phy_dev; + + if (!phydev) + return -ENODEV; + + return phy_ethtool_sset(phydev, ecmd); +} + +static void +dwceqos_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *ed) +{ + const struct net_local *lp = netdev_priv(ndev); + + strcpy(ed->driver, lp->pdev->dev.driver->name); + strcpy(ed->version, DRIVER_VERSION); +} + +static void dwceqos_get_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pp) +{ + const struct net_local *lp = netdev_priv(ndev); + + pp->autoneg = lp->flowcontrol.autoneg; + pp->tx_pause = lp->flowcontrol.tx; + pp->rx_pause = lp->flowcontrol.rx; +} + +static int dwceqos_set_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pp) +{ + struct net_local *lp = netdev_priv(ndev); + int ret = 0; + + lp->flowcontrol.autoneg = pp->autoneg; + if (pp->autoneg) { + lp->phy_dev->advertising |= ADVERTISED_Pause; + lp->phy_dev->advertising |= ADVERTISED_Asym_Pause; + } else { + lp->phy_dev->advertising &= ~ADVERTISED_Pause; + lp->phy_dev->advertising &= ~ADVERTISED_Asym_Pause; + lp->flowcontrol.rx = pp->rx_pause; + lp->flowcontrol.tx = pp->tx_pause; + } + + if (netif_running(ndev)) + ret = phy_start_aneg(lp->phy_dev); + + return ret; +} + +static void dwceqos_get_strings(struct net_device *ndev, u32 stringset, + u8 *data) +{ + size_t i; + + if (stringset != ETH_SS_STATS) + return; + + for (i = 0; i < ARRAY_SIZE(dwceqos_ethtool_stats); ++i) { + memcpy(data, dwceqos_ethtool_stats[i].stat_name, + ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } +} + +static void dwceqos_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *stats, u64 *data) +{ + struct net_local *lp = netdev_priv(ndev); + unsigned long flags; + size_t i; + u8 *mmcstat = (u8 *)&lp->mmc_counters; + + spin_lock_irqsave(&lp->stats_lock, flags); + dwceqos_read_mmc_counters(lp, lp->mmc_rx_counters_mask, + lp->mmc_tx_counters_mask); + spin_unlock_irqrestore(&lp->stats_lock, flags); + + for (i = 0; i < ARRAY_SIZE(dwceqos_ethtool_stats); ++i) { + memcpy(data, + mmcstat + dwceqos_ethtool_stats[i].offset, + sizeof(u64)); + data++; + } +} + +static int dwceqos_get_sset_count(struct net_device *ndev, int sset) +{ + if (sset == ETH_SS_STATS) + return ARRAY_SIZE(dwceqos_ethtool_stats); + + return -EOPNOTSUPP; +} + +static void dwceqos_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *space) +{ + const struct net_local *lp = netdev_priv(dev); + u32 *reg_space = (u32 *)space; + int reg_offset; + int reg_ix = 0; + + /* MAC registers */ + for (reg_offset = START_MAC_REG_OFFSET; + reg_offset <= MAX_DMA_REG_OFFSET; reg_offset += 4) { + reg_space[reg_ix] = dwceqos_read(lp, reg_offset); + reg_ix++; + } + /* MTL registers */ + for (reg_offset = START_MTL_REG_OFFSET; + reg_offset <= MAX_MTL_REG_OFFSET; reg_offset += 4) { + reg_space[reg_ix] = dwceqos_read(lp, reg_offset); + reg_ix++; + } + + /* DMA registers */ + for (reg_offset = START_DMA_REG_OFFSET; + reg_offset <= MAX_DMA_REG_OFFSET; reg_offset += 4) { + reg_space[reg_ix] = dwceqos_read(lp, reg_offset); + reg_ix++; + } + + BUG_ON(4 * reg_ix > REG_SPACE_SIZE); +} + +static int dwceqos_get_regs_len(struct net_device *dev) +{ + return REG_SPACE_SIZE; +} + +static inline const char *dwceqos_get_rx_lpi_state(u32 lpi_ctrl) +{ + return (lpi_ctrl & DWCEQOS_MAC_LPI_CTRL_STATUS_RLPIST) ? "on" : "off"; +} + +static inline const char *dwceqos_get_tx_lpi_state(u32 lpi_ctrl) +{ + return (lpi_ctrl & DWCEQOS_MAC_LPI_CTRL_STATUS_TLPIST) ? "on" : "off"; +} + +static int dwceqos_get_eee(struct net_device *ndev, struct ethtool_eee *edata) +{ + struct net_local *lp = netdev_priv(ndev); + u32 lpi_status; + u32 lpi_enabled; + + if (!(lp->feature0 & DWCEQOS_MAC_HW_FEATURE0_EEESEL)) + return -EOPNOTSUPP; + + edata->eee_active = lp->eee_active; + edata->eee_enabled = lp->eee_enabled; + edata->tx_lpi_timer = dwceqos_read(lp, REG_DWCEQOS_MAC_LPI_ENTRY_TIMER); + lpi_status = dwceqos_read(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS); + lpi_enabled = !!(lpi_status & DWCEQOS_MAC_LPI_CTRL_STATUS_LIPTXA); + edata->tx_lpi_enabled = lpi_enabled; + + if (netif_msg_hw(lp)) { + u32 regval; + + regval = dwceqos_read(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS); + + netdev_info(lp->ndev, "MAC LPI State: RX:%s TX:%s\n", + dwceqos_get_rx_lpi_state(regval), + dwceqos_get_tx_lpi_state(regval)); + } + + return phy_ethtool_get_eee(lp->phy_dev, edata); +} + +static int dwceqos_set_eee(struct net_device *ndev, struct ethtool_eee *edata) +{ + struct net_local *lp = netdev_priv(ndev); + u32 regval; + unsigned long flags; + + if (!(lp->feature0 & DWCEQOS_MAC_HW_FEATURE0_EEESEL)) + return -EOPNOTSUPP; + + if (edata->eee_enabled && !lp->eee_active) + return -EOPNOTSUPP; + + if (edata->tx_lpi_enabled) { + if (edata->tx_lpi_timer < DWCEQOS_LPI_TIMER_MIN || + edata->tx_lpi_timer > DWCEQOS_LPI_TIMER_MAX) + return -EINVAL; + } + + lp->eee_enabled = edata->eee_enabled; + + if (edata->eee_enabled && edata->tx_lpi_enabled) { + dwceqos_write(lp, REG_DWCEQOS_MAC_LPI_ENTRY_TIMER, + edata->tx_lpi_timer); + + spin_lock_irqsave(&lp->hw_lock, flags); + regval = dwceqos_read(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS); + regval |= DWCEQOS_LPI_CTRL_ENABLE_EEE; + if (lp->en_tx_lpi_clockgating) + regval |= DWCEQOS_MAC_LPI_CTRL_STATUS_LPITCSE; + dwceqos_write(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS, regval); + spin_unlock_irqrestore(&lp->hw_lock, flags); + } else { + spin_lock_irqsave(&lp->hw_lock, flags); + regval = dwceqos_read(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS); + regval &= ~DWCEQOS_LPI_CTRL_ENABLE_EEE; + dwceqos_write(lp, REG_DWCEQOS_MAC_LPI_CTRL_STATUS, regval); + spin_unlock_irqrestore(&lp->hw_lock, flags); + } + + return phy_ethtool_set_eee(lp->phy_dev, edata); +} + +static u32 dwceqos_get_msglevel(struct net_device *ndev) +{ + const struct net_local *lp = netdev_priv(ndev); + + return lp->msg_enable; +} + +static void dwceqos_set_msglevel(struct net_device *ndev, u32 msglevel) +{ + struct net_local *lp = netdev_priv(ndev); + + lp->msg_enable = msglevel; +} + +static struct ethtool_ops dwceqos_ethtool_ops = { + .get_settings = dwceqos_get_settings, + .set_settings = dwceqos_set_settings, + .get_drvinfo = dwceqos_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_pauseparam = dwceqos_get_pauseparam, + .set_pauseparam = dwceqos_set_pauseparam, + .get_strings = dwceqos_get_strings, + .get_ethtool_stats = dwceqos_get_ethtool_stats, + .get_sset_count = dwceqos_get_sset_count, + .get_regs = dwceqos_get_regs, + .get_regs_len = dwceqos_get_regs_len, + .get_eee = dwceqos_get_eee, + .set_eee = dwceqos_set_eee, + .get_msglevel = dwceqos_get_msglevel, + .set_msglevel = dwceqos_set_msglevel, +}; + +static struct net_device_ops netdev_ops = { + .ndo_open = dwceqos_open, + .ndo_stop = dwceqos_stop, + .ndo_start_xmit = dwceqos_start_xmit, + .ndo_set_rx_mode = dwceqos_set_rx_mode, + .ndo_set_mac_address = dwceqos_set_mac_address, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = dwceqos_poll_controller, +#endif + .ndo_do_ioctl = dwceqos_ioctl, + .ndo_tx_timeout = dwceqos_tx_timeout, + .ndo_get_stats64 = dwceqos_get_stats64, +}; + +static const struct of_device_id dwceq_of_match[] = { + { .compatible = "snps,dwc-qos-ethernet-4.10", }, + {} +}; +MODULE_DEVICE_TABLE(of, dwceq_of_match); + +static int dwceqos_probe(struct platform_device *pdev) +{ + struct resource *r_mem = NULL; + struct net_device *ndev; + struct net_local *lp; + int ret = -ENXIO; + + r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r_mem) { + dev_err(&pdev->dev, "no IO resource defined.\n"); + return -ENXIO; + } + + ndev = alloc_etherdev(sizeof(*lp)); + if (!ndev) { + dev_err(&pdev->dev, "etherdev allocation failed.\n"); + return -ENOMEM; + } + + SET_NETDEV_DEV(ndev, &pdev->dev); + + lp = netdev_priv(ndev); + lp->ndev = ndev; + lp->pdev = pdev; + lp->msg_enable = netif_msg_init(debug, DWCEQOS_MSG_DEFAULT); + + spin_lock_init(&lp->tx_lock); + spin_lock_init(&lp->hw_lock); + spin_lock_init(&lp->stats_lock); + + lp->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk"); + if (IS_ERR(lp->apb_pclk)) { + dev_err(&pdev->dev, "apb_pclk clock not found.\n"); + ret = PTR_ERR(lp->apb_pclk); + goto err_out_free_netdev; + } + + ret = clk_prepare_enable(lp->apb_pclk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable APER clock.\n"); + goto err_out_free_netdev; + } + + lp->baseaddr = devm_ioremap_resource(&pdev->dev, r_mem); + if (IS_ERR(lp->baseaddr)) { + dev_err(&pdev->dev, "failed to map baseaddress.\n"); + ret = PTR_ERR(lp->baseaddr); + goto err_out_clk_dis_aper; + } + + ndev->irq = platform_get_irq(pdev, 0); + ndev->watchdog_timeo = DWCEQOS_TX_TIMEOUT * HZ; + ndev->netdev_ops = &netdev_ops; + ndev->ethtool_ops = &dwceqos_ethtool_ops; + ndev->base_addr = r_mem->start; + + dwceqos_get_hwfeatures(lp); + dwceqos_mdio_set_csr(lp); + + ndev->hw_features = NETIF_F_SG; + + if (lp->feature1 & DWCEQOS_MAC_HW_FEATURE1_TSOEN) + ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; + + if (lp->feature0 & DWCEQOS_MAC_HW_FEATURE0_TXCOESEL) + ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + + if (lp->feature0 & DWCEQOS_MAC_HW_FEATURE0_RXCOESEL) + ndev->hw_features |= NETIF_F_RXCSUM; + + ndev->features = ndev->hw_features; + + netif_napi_add(ndev, &lp->napi, dwceqos_rx_poll, NAPI_POLL_WEIGHT); + + ret = register_netdev(ndev); + if (ret) { + dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); + goto err_out_clk_dis_aper; + } + + lp->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk"); + if (IS_ERR(lp->phy_ref_clk)) { + dev_err(&pdev->dev, "phy_ref_clk clock not found.\n"); + ret = PTR_ERR(lp->phy_ref_clk); + goto err_out_unregister_netdev; + } + + ret = clk_prepare_enable(lp->phy_ref_clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable device clock.\n"); + goto err_out_unregister_netdev; + } + + lp->phy_node = of_parse_phandle(lp->pdev->dev.of_node, + "phy-handle", 0); + if (!lp->phy_node && of_phy_is_fixed_link(lp->pdev->dev.of_node)) { + ret = of_phy_register_fixed_link(lp->pdev->dev.of_node); + if (ret < 0) { + dev_err(&pdev->dev, "invalid fixed-link"); + goto err_out_unregister_netdev; + } + + lp->phy_node = of_node_get(lp->pdev->dev.of_node); + } + + ret = of_get_phy_mode(lp->pdev->dev.of_node); + if (ret < 0) { + dev_err(&lp->pdev->dev, "error in getting phy i/f\n"); + goto err_out_unregister_clk_notifier; + } + + lp->phy_interface = ret; + + ret = dwceqos_mii_init(lp); + if (ret) { + dev_err(&lp->pdev->dev, "error in dwceqos_mii_init\n"); + goto err_out_unregister_clk_notifier; + } + + ret = dwceqos_mii_probe(ndev); + if (ret != 0) { + netdev_err(ndev, "mii_probe fail.\n"); + ret = -ENXIO; + goto err_out_unregister_clk_notifier; + } + + dwceqos_set_umac_addr(lp, lp->ndev->dev_addr, 0); + + tasklet_init(&lp->tx_bdreclaim_tasklet, dwceqos_tx_reclaim, + (unsigned long)ndev); + tasklet_disable(&lp->tx_bdreclaim_tasklet); + + lp->txtimeout_handler_wq = create_singlethread_workqueue(DRIVER_NAME); + INIT_WORK(&lp->txtimeout_reinit, dwceqos_reinit_for_txtimeout); + + platform_set_drvdata(pdev, ndev); + ret = dwceqos_probe_config_dt(pdev); + if (ret) { + dev_err(&lp->pdev->dev, "Unable to retrieve DT, error %d\n", + ret); + goto err_out_unregister_clk_notifier; + } + dev_info(&lp->pdev->dev, "pdev->id %d, baseaddr 0x%08lx, irq %d\n", + pdev->id, ndev->base_addr, ndev->irq); + + ret = devm_request_irq(&pdev->dev, ndev->irq, &dwceqos_interrupt, 0, + ndev->name, ndev); + if (ret) { + dev_err(&lp->pdev->dev, "Unable to request IRQ %d, error %d\n", + ndev->irq, ret); + goto err_out_unregister_clk_notifier; + } + + if (netif_msg_probe(lp)) + netdev_dbg(ndev, "net_local@%p\n", lp); + + return 0; + +err_out_unregister_clk_notifier: + clk_disable_unprepare(lp->phy_ref_clk); +err_out_unregister_netdev: + unregister_netdev(ndev); +err_out_clk_dis_aper: + clk_disable_unprepare(lp->apb_pclk); +err_out_free_netdev: + if (lp->phy_node) + of_node_put(lp->phy_node); + free_netdev(ndev); + platform_set_drvdata(pdev, NULL); + return ret; +} + +static int dwceqos_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct net_local *lp; + + if (ndev) { + lp = netdev_priv(ndev); + + if (lp->phy_dev) + phy_disconnect(lp->phy_dev); + mdiobus_unregister(lp->mii_bus); + kfree(lp->mii_bus->irq); + mdiobus_free(lp->mii_bus); + + unregister_netdev(ndev); + + clk_disable_unprepare(lp->phy_ref_clk); + clk_disable_unprepare(lp->apb_pclk); + + free_netdev(ndev); + } + + return 0; +} + +static struct platform_driver dwceqos_driver = { + .probe = dwceqos_probe, + .remove = dwceqos_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = dwceq_of_match, + }, +}; + +module_platform_driver(dwceqos_driver); + +MODULE_DESCRIPTION("DWC Ethernet QoS v4.10a driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Andreas Irestaal "); +MODULE_AUTHOR("Lars Persson "); -- cgit v1.3-6-gb490 From 2a050731525b9eb2f5048c6d0904a2e2df1a908b Mon Sep 17 00:00:00 2001 From: Lars Persson Date: Tue, 28 Jul 2015 12:01:49 +0200 Subject: dwc_eth_qos: Add the synopsys folder to the build system. Signed-off-by: Lars Persson Signed-off-by: David S. Miller --- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index f3bb1784066b..05aa7597dab9 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -167,6 +167,7 @@ source "drivers/net/ethernet/sgi/Kconfig" source "drivers/net/ethernet/smsc/Kconfig" source "drivers/net/ethernet/stmicro/Kconfig" source "drivers/net/ethernet/sun/Kconfig" +source "drivers/net/ethernet/synopsys/Kconfig" source "drivers/net/ethernet/tehuti/Kconfig" source "drivers/net/ethernet/ti/Kconfig" source "drivers/net/ethernet/tile/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index c51014b0464f..f42177b11723 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_NET_VENDOR_SGI) += sgi/ obj-$(CONFIG_NET_VENDOR_SMSC) += smsc/ obj-$(CONFIG_NET_VENDOR_STMICRO) += stmicro/ obj-$(CONFIG_NET_VENDOR_SUN) += sun/ +obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/ obj-$(CONFIG_NET_VENDOR_TEHUTI) += tehuti/ obj-$(CONFIG_NET_VENDOR_TI) += ti/ obj-$(CONFIG_TILE_NET) += tile/ -- cgit v1.3-6-gb490 From a04c0aef74bbd807cd43ffa12404c3d6a6021865 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 29 Jul 2015 00:08:48 +0200 Subject: stmmac: fix ptr_ret.cocci warning drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c:304:1-3: WARNING: PTR_ERR_OR_ZERO can be used Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR Generated by: scripts/coccinelle/api/ptr_ret.cocci Signed-off-by: Fengguang Wu [je: rebase and insert newline before return] Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index eca0eb845241..1dcb5ebefe5c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -298,10 +298,8 @@ int stmmac_get_platform_resources(struct platform_device *pdev, res = platform_get_resource(pdev, IORESOURCE_MEM, 0); stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(stmmac_res->addr)) - return PTR_ERR(stmmac_res->addr); - return 0; + return PTR_ERR_OR_ZERO(stmmac_res->addr); } EXPORT_SYMBOL_GPL(stmmac_get_platform_resources); -- cgit v1.3-6-gb490 From 213088f6fadfbccc675bc8ebf6901327d802c3a2 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:08:49 +0200 Subject: stmmac: dwmac-ipq806x: move ipq806x_gmac_fix_mac_speed function Move ipq806x_gmac_fix_mac_speed in preparation for turning the setup glue callback in a proper probe function. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index 7e3129e7f143..5f1b3f9d8dba 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -248,6 +248,13 @@ static void *ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac) return NULL; } +static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed) +{ + struct ipq806x_gmac *gmac = priv; + + ipq806x_gmac_set_speed(gmac, speed); +} + static void *ipq806x_gmac_setup(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -330,13 +337,6 @@ static void *ipq806x_gmac_setup(struct platform_device *pdev) return gmac; } -static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed) -{ - struct ipq806x_gmac *gmac = priv; - - ipq806x_gmac_set_speed(gmac, speed); -} - static const struct stmmac_of_data ipq806x_gmac_data = { .has_gmac = 1, .setup = ipq806x_gmac_setup, -- cgit v1.3-6-gb490 From 5ed1c04a38979f025dd2cf5f37ef5c39a9fc2f85 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:08:50 +0200 Subject: stmmac: dwmac-ipq806x: turn setup callback into a probe function By using a few functions from stmmac_platform a proper probe function can be created from the setup glue callback. This makes it look more like a standard driver and the OF match data can also be dropped. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/dwmac-ipq806x.c | 38 +++++++++++++--------- 1 file changed, 23 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index 5f1b3f9d8dba..333489f0fd24 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -255,23 +255,33 @@ static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed) ipq806x_gmac_set_speed(gmac, speed); } -static void *ipq806x_gmac_setup(struct platform_device *pdev) +static int ipq806x_gmac_probe(struct platform_device *pdev) { + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; struct device *dev = &pdev->dev; struct ipq806x_gmac *gmac; int val; void *err; + val = stmmac_get_platform_resources(pdev, &stmmac_res); + if (val) + return val; + + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); + gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); if (!gmac) - return ERR_PTR(-ENOMEM); + return -ENOMEM; gmac->pdev = pdev; err = ipq806x_gmac_of_parse(gmac); - if (err) { + if (IS_ERR(err)) { dev_err(dev, "device tree parsing error\n"); - return err; + return PTR_ERR(err); } regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL, @@ -292,7 +302,7 @@ static void *ipq806x_gmac_setup(struct platform_device *pdev) default: dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", phy_modes(gmac->phy_mode)); - return NULL; + return -EINVAL; } regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val); @@ -311,7 +321,7 @@ static void *ipq806x_gmac_setup(struct platform_device *pdev) default: dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", phy_modes(gmac->phy_mode)); - return NULL; + return -EINVAL; } regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val); @@ -334,23 +344,21 @@ static void *ipq806x_gmac_setup(struct platform_device *pdev) 0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET); } - return gmac; -} + plat_dat->has_gmac = true; + plat_dat->bsp_priv = gmac; + plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed; -static const struct stmmac_of_data ipq806x_gmac_data = { - .has_gmac = 1, - .setup = ipq806x_gmac_setup, - .fix_mac_speed = ipq806x_gmac_fix_mac_speed, -}; + return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); +} static const struct of_device_id ipq806x_gmac_dwmac_match[] = { - { .compatible = "qcom,ipq806x-gmac", .data = &ipq806x_gmac_data }, + { .compatible = "qcom,ipq806x-gmac" }, { } }; MODULE_DEVICE_TABLE(of, ipq806x_gmac_dwmac_match); static struct platform_driver ipq806x_gmac_dwmac_driver = { - .probe = stmmac_pltfr_probe, + .probe = ipq806x_gmac_probe, .remove = stmmac_pltfr_remove, .driver = { .name = "ipq806x-gmac-dwmac", -- cgit v1.3-6-gb490 From 82732789e8e7fb19091f773f2b3536968398ae4b Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:08:51 +0200 Subject: stmmac: dwmac-socfpga: move socfpga_dwmac_probe function Move socfpga_dwmac_probe in preparation for turning it into a proper probe function. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 50 +++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 8141c5b844ae..0df409e2edcd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -175,31 +175,6 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac) return 0; } -static void *socfpga_dwmac_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - int ret; - struct socfpga_dwmac *dwmac; - - dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); - if (!dwmac) - return ERR_PTR(-ENOMEM); - - ret = socfpga_dwmac_parse_data(dwmac, dev); - if (ret) { - dev_err(dev, "Unable to parse OF data\n"); - return ERR_PTR(ret); - } - - ret = socfpga_dwmac_setup(dwmac); - if (ret) { - dev_err(dev, "couldn't setup SoC glue (%d)\n", ret); - return ERR_PTR(ret); - } - - return dwmac; -} - static void socfpga_dwmac_exit(struct platform_device *pdev, void *priv) { struct socfpga_dwmac *dwmac = priv; @@ -257,6 +232,31 @@ static int socfpga_dwmac_init(struct platform_device *pdev, void *priv) return ret; } +static void *socfpga_dwmac_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int ret; + struct socfpga_dwmac *dwmac; + + dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); + if (!dwmac) + return ERR_PTR(-ENOMEM); + + ret = socfpga_dwmac_parse_data(dwmac, dev); + if (ret) { + dev_err(dev, "Unable to parse OF data\n"); + return ERR_PTR(ret); + } + + ret = socfpga_dwmac_setup(dwmac); + if (ret) { + dev_err(dev, "couldn't setup SoC glue (%d)\n", ret); + return ERR_PTR(ret); + } + + return dwmac; +} + static const struct stmmac_of_data socfpga_gmac_data = { .setup = socfpga_dwmac_probe, .init = socfpga_dwmac_init, -- cgit v1.3-6-gb490 From 8880b6c849916a3d688e2f2404a063cc14cc4a88 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:08:52 +0200 Subject: stmmac: dwmac-socfpga: turn setup callback into a probe function By using a few functions from stmmac_platform a proper probe function can be created from the setup glue callback. This makes it look more like a standard driver and the OF match data can also be dropped. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 40 ++++++++++++++-------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 0df409e2edcd..401383b252a8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -232,46 +232,58 @@ static int socfpga_dwmac_init(struct platform_device *pdev, void *priv) return ret; } -static void *socfpga_dwmac_probe(struct platform_device *pdev) +static int socfpga_dwmac_probe(struct platform_device *pdev) { + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; struct device *dev = &pdev->dev; int ret; struct socfpga_dwmac *dwmac; + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); + dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); if (!dwmac) - return ERR_PTR(-ENOMEM); + return -ENOMEM; ret = socfpga_dwmac_parse_data(dwmac, dev); if (ret) { dev_err(dev, "Unable to parse OF data\n"); - return ERR_PTR(ret); + return ret; } ret = socfpga_dwmac_setup(dwmac); if (ret) { dev_err(dev, "couldn't setup SoC glue (%d)\n", ret); - return ERR_PTR(ret); + return ret; } - return dwmac; -} + plat_dat->bsp_priv = dwmac; + plat_dat->init = socfpga_dwmac_init; + plat_dat->exit = socfpga_dwmac_exit; + plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; -static const struct stmmac_of_data socfpga_gmac_data = { - .setup = socfpga_dwmac_probe, - .init = socfpga_dwmac_init, - .exit = socfpga_dwmac_exit, - .fix_mac_speed = socfpga_dwmac_fix_mac_speed, -}; + ret = socfpga_dwmac_init(pdev, plat_dat->bsp_priv); + if (ret) + return ret; + + return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); +} static const struct of_device_id socfpga_dwmac_match[] = { - { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data }, + { .compatible = "altr,socfpga-stmmac" }, { } }; MODULE_DEVICE_TABLE(of, socfpga_dwmac_match); static struct platform_driver socfpga_dwmac_driver = { - .probe = stmmac_pltfr_probe, + .probe = socfpga_dwmac_probe, .remove = stmmac_pltfr_remove, .driver = { .name = "socfpga-dwmac", -- cgit v1.3-6-gb490 From 22caae03172114147c86982e39fa6f42fea51165 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:08:53 +0200 Subject: stmmac: dwmac-sunxi: move sun7i_gmac_setup function Move sun7i_gmac_setup in preparation for turning it into a proper probe function. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c | 58 +++++++++++------------ 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index 15048ca39759..c9d6e2d5bfc9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -33,35 +33,6 @@ struct sunxi_priv_data { struct regulator *regulator; }; -static void *sun7i_gmac_setup(struct platform_device *pdev) -{ - struct sunxi_priv_data *gmac; - struct device *dev = &pdev->dev; - - gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); - if (!gmac) - return ERR_PTR(-ENOMEM); - - gmac->interface = of_get_phy_mode(dev->of_node); - - gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); - if (IS_ERR(gmac->tx_clk)) { - dev_err(dev, "could not get tx clock\n"); - return gmac->tx_clk; - } - - /* Optional regulator for PHY */ - gmac->regulator = devm_regulator_get_optional(dev, "phy"); - if (IS_ERR(gmac->regulator)) { - if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) - return ERR_PTR(-EPROBE_DEFER); - dev_info(dev, "no regulator found\n"); - gmac->regulator = NULL; - } - - return gmac; -} - #define SUN7I_GMAC_GMII_RGMII_RATE 125000000 #define SUN7I_GMAC_MII_RATE 25000000 @@ -132,6 +103,35 @@ static void sun7i_fix_speed(void *priv, unsigned int speed) } } +static void *sun7i_gmac_setup(struct platform_device *pdev) +{ + struct sunxi_priv_data *gmac; + struct device *dev = &pdev->dev; + + gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); + if (!gmac) + return ERR_PTR(-ENOMEM); + + gmac->interface = of_get_phy_mode(dev->of_node); + + gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); + if (IS_ERR(gmac->tx_clk)) { + dev_err(dev, "could not get tx clock\n"); + return gmac->tx_clk; + } + + /* Optional regulator for PHY */ + gmac->regulator = devm_regulator_get_optional(dev, "phy"); + if (IS_ERR(gmac->regulator)) { + if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) + return ERR_PTR(-EPROBE_DEFER); + dev_info(dev, "no regulator found\n"); + gmac->regulator = NULL; + } + + return gmac; +} + /* of_data specifying hardware features and callbacks. * hardware features were copied from Allwinner drivers. */ static const struct stmmac_of_data sun7i_gmac_data = { -- cgit v1.3-6-gb490 From 9a9e9a1edee8c5d81f7b6a73ab3c312c0dddf476 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:08:54 +0200 Subject: stmmac: dwmac-sunxi: turn setup callback into a probe function By using a few functions from stmmac_platform a proper probe function can be created from the setup glue callback. This makes it look more like a standard driver and the OF match data can also be dropped. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c | 49 ++++++++++++++--------- 1 file changed, 31 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index c9d6e2d5bfc9..52b8ed9bd87c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -103,54 +103,67 @@ static void sun7i_fix_speed(void *priv, unsigned int speed) } } -static void *sun7i_gmac_setup(struct platform_device *pdev) +static int sun7i_gmac_probe(struct platform_device *pdev) { + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; struct sunxi_priv_data *gmac; struct device *dev = &pdev->dev; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); if (!gmac) - return ERR_PTR(-ENOMEM); + return -ENOMEM; gmac->interface = of_get_phy_mode(dev->of_node); gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); if (IS_ERR(gmac->tx_clk)) { dev_err(dev, "could not get tx clock\n"); - return gmac->tx_clk; + return PTR_ERR(gmac->tx_clk); } /* Optional regulator for PHY */ gmac->regulator = devm_regulator_get_optional(dev, "phy"); if (IS_ERR(gmac->regulator)) { if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) - return ERR_PTR(-EPROBE_DEFER); + return -EPROBE_DEFER; dev_info(dev, "no regulator found\n"); gmac->regulator = NULL; } - return gmac; -} + /* platform data specifying hardware features and callbacks. + * hardware features were copied from Allwinner drivers. */ + plat_dat->tx_coe = 1; + plat_dat->has_gmac = true; + plat_dat->bsp_priv = gmac; + plat_dat->init = sun7i_gmac_init; + plat_dat->exit = sun7i_gmac_exit; + plat_dat->fix_mac_speed = sun7i_fix_speed; -/* of_data specifying hardware features and callbacks. - * hardware features were copied from Allwinner drivers. */ -static const struct stmmac_of_data sun7i_gmac_data = { - .has_gmac = 1, - .tx_coe = 1, - .fix_mac_speed = sun7i_fix_speed, - .setup = sun7i_gmac_setup, - .init = sun7i_gmac_init, - .exit = sun7i_gmac_exit, -}; + ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv); + if (ret) + return ret; + + return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); +} static const struct of_device_id sun7i_dwmac_match[] = { - { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data}, + { .compatible = "allwinner,sun7i-a20-gmac" }, { } }; MODULE_DEVICE_TABLE(of, sun7i_dwmac_match); static struct platform_driver sun7i_dwmac_driver = { - .probe = stmmac_pltfr_probe, + .probe = sun7i_gmac_probe, .remove = stmmac_pltfr_remove, .driver = { .name = "sun7i-dwmac", -- cgit v1.3-6-gb490 From 8387ee21f972debce15d92e98a37455ae7e035e4 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:08:55 +0200 Subject: stmmac: dwmac-sti: turn setup callback into a probe function By using a few functions from stmmac_platform a proper probe function can be created from the setup glue callback. This makes it look more like a standard driver and prepares the driver for further clean ups. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c | 31 ++++++++++++++++++------- 1 file changed, 22 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index a2e8111c5d14..b17238aac791 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -334,36 +334,49 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, return 0; } -static void *sti_dwmac_setup(struct platform_device *pdev) +static int sti_dwmac_probe(struct platform_device *pdev) { + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; struct sti_dwmac *dwmac; int ret; + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); if (!dwmac) - return ERR_PTR(-ENOMEM); + return -ENOMEM; ret = sti_dwmac_parse_data(dwmac, pdev); if (ret) { dev_err(&pdev->dev, "Unable to parse OF data\n"); - return ERR_PTR(ret); + return ret; } - return dwmac; + plat_dat->bsp_priv = dwmac; + plat_dat->exit = sti_dwmac_exit; + + ret = plat_dat->init(pdev, plat_dat->bsp_priv); + if (ret) + return ret; + + return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); } static const struct stmmac_of_data stih4xx_dwmac_data = { .fix_mac_speed = stih4xx_fix_retime_src, - .setup = sti_dwmac_setup, .init = stix4xx_init, - .exit = sti_dwmac_exit, }; static const struct stmmac_of_data stid127_dwmac_data = { .fix_mac_speed = stid127_fix_retime_src, - .setup = sti_dwmac_setup, .init = stid127_init, - .exit = sti_dwmac_exit, }; static const struct of_device_id sti_dwmac_match[] = { @@ -376,7 +389,7 @@ static const struct of_device_id sti_dwmac_match[] = { MODULE_DEVICE_TABLE(of, sti_dwmac_match); static struct platform_driver sti_dwmac_driver = { - .probe = stmmac_pltfr_probe, + .probe = sti_dwmac_probe, .remove = stmmac_pltfr_remove, .driver = { .name = "sti-dwmac", -- cgit v1.3-6-gb490 From 27ffefd2d10902352c01394169e577f3b91113f2 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:08:56 +0200 Subject: stmmac: dwmac-rk: create a new probe function Create a new probe functions that call the necessary setup functions. This is done in preparation for a code refactor in this driver and dropping the common probe function in stmmac_platform.c. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 40 ++++++++++++++++++++------ 1 file changed, 31 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 00a1e1e09d4f..21193a73acfc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -576,20 +576,42 @@ static void rk_fix_speed(void *priv, unsigned int speed) dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface); } +static int rk_gmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); + + plat_dat->has_gmac = true; + plat_dat->init = rk_gmac_init; + plat_dat->exit = rk_gmac_exit; + plat_dat->fix_mac_speed = rk_fix_speed; + + plat_dat->bsp_priv = plat_dat->setup(pdev); + if (IS_ERR(plat_dat->bsp_priv)) + return PTR_ERR(plat_dat->bsp_priv); + + ret = rk_gmac_init(pdev, plat_dat->bsp_priv); + if (ret) + return ret; + + return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); +} + static const struct stmmac_of_data rk3288_gmac_data = { - .has_gmac = 1, - .fix_mac_speed = rk_fix_speed, .setup = rk3288_gmac_setup, - .init = rk_gmac_init, - .exit = rk_gmac_exit, }; static const struct stmmac_of_data rk3368_gmac_data = { - .has_gmac = 1, - .fix_mac_speed = rk_fix_speed, .setup = rk3368_gmac_setup, - .init = rk_gmac_init, - .exit = rk_gmac_exit, }; static const struct of_device_id rk_gmac_dwmac_match[] = { @@ -600,7 +622,7 @@ static const struct of_device_id rk_gmac_dwmac_match[] = { MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match); static struct platform_driver rk_gmac_dwmac_driver = { - .probe = stmmac_pltfr_probe, + .probe = rk_gmac_probe, .remove = stmmac_pltfr_remove, .driver = { .name = "rk_gmac-dwmac", -- cgit v1.3-6-gb490 From 85d89e6115cd5613b36f31a5038feb9cb4e13dfc Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:08:57 +0200 Subject: stmmac: move stmmac_pltfr_probe into dwmac-generic As all dwmac-* drivers now have their own probe function move the common one into dwmac-generic driver and drop the EXPORT. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/dwmac-generic.c | 49 ++++++++++++++++++- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 55 ---------------------- .../net/ethernet/stmicro/stmmac/stmmac_platform.h | 1 - 3 files changed, 48 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c index e817a1a44379..f4fe9f1a33b4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c @@ -16,6 +16,53 @@ #include "stmmac.h" #include "stmmac_platform.h" +static int dwmac_generic_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + if (pdev->dev.of_node) { + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) { + dev_err(&pdev->dev, "dt configuration failed\n"); + return PTR_ERR(plat_dat); + } + } else { + plat_dat = dev_get_platdata(&pdev->dev); + if (!plat_dat) { + dev_err(&pdev->dev, "no platform data provided\n"); + return -EINVAL; + } + + /* Set default value for multicast hash bins */ + plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; + + /* Set default value for unicast filter entries */ + plat_dat->unicast_filter_entries = 1; + } + + /* Custom setup (if needed) */ + if (plat_dat->setup) { + plat_dat->bsp_priv = plat_dat->setup(pdev); + if (IS_ERR(plat_dat->bsp_priv)) + return PTR_ERR(plat_dat->bsp_priv); + } + + /* Custom initialisation (if needed) */ + if (plat_dat->init) { + ret = plat_dat->init(pdev, plat_dat->bsp_priv); + if (ret) + return ret; + } + + return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); +} + static const struct of_device_id dwmac_generic_match[] = { { .compatible = "st,spear600-gmac"}, { .compatible = "snps,dwmac-3.610"}, @@ -27,7 +74,7 @@ static const struct of_device_id dwmac_generic_match[] = { MODULE_DEVICE_TABLE(of, dwmac_generic_match); static struct platform_driver dwmac_generic_driver = { - .probe = stmmac_pltfr_probe, + .probe = dwmac_generic_probe, .remove = stmmac_pltfr_remove, .driver = { .name = STMMAC_RESOURCE_NAME, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 1dcb5ebefe5c..9c49d95e529a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -303,61 +303,6 @@ int stmmac_get_platform_resources(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(stmmac_get_platform_resources); -/** - * stmmac_pltfr_probe - platform driver probe. - * @pdev: platform device pointer - * Description: platform_device probe function. It is to allocate - * the necessary platform resources, invoke custom helper (if required) and - * invoke the main probe function. - */ -int stmmac_pltfr_probe(struct platform_device *pdev) -{ - struct plat_stmmacenet_data *plat_dat; - struct stmmac_resources stmmac_res; - int ret; - - ret = stmmac_get_platform_resources(pdev, &stmmac_res); - if (ret) - return ret; - - if (pdev->dev.of_node) { - plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); - if (IS_ERR(plat_dat)) { - dev_err(&pdev->dev, "dt configuration failed\n"); - return PTR_ERR(plat_dat); - } - } else { - plat_dat = dev_get_platdata(&pdev->dev); - if (!plat_dat) { - dev_err(&pdev->dev, "no platform data provided\n"); - return -EINVAL; - } - - /* Set default value for multicast hash bins */ - plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; - - /* Set default value for unicast filter entries */ - plat_dat->unicast_filter_entries = 1; - } - - /* Custom setup (if needed) */ - if (plat_dat->setup) { - plat_dat->bsp_priv = plat_dat->setup(pdev); - if (IS_ERR(plat_dat->bsp_priv)) - return PTR_ERR(plat_dat->bsp_priv); - } - - /* Custom initialisation (if needed)*/ - if (plat_dat->init) { - ret = plat_dat->init(pdev, plat_dat->bsp_priv); - if (unlikely(ret)) - return ret; - } - - return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); -} -EXPORT_SYMBOL_GPL(stmmac_pltfr_probe); - /** * stmmac_pltfr_remove * @pdev: platform device pointer diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index 84ceb5342686..ffeb8d9e2b2e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -27,7 +27,6 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac); int stmmac_get_platform_resources(struct platform_device *pdev, struct stmmac_resources *stmmac_res); -int stmmac_pltfr_probe(struct platform_device *pdev); int stmmac_pltfr_remove(struct platform_device *pdev); extern const struct dev_pm_ops stmmac_pltfr_pm_ops; -- cgit v1.3-6-gb490 From 149adedd7696cbcf1d72d143ca181334000d0ee7 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:08:58 +0200 Subject: stmmac: let dwmac-* drivers handle their own match data Since only a few of the dwmac-* drivers actually need to use the OF match move handling into the dwmac-* drivers that need it. This will also allow dwmac-* drivers to use their own custom match data structure. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 8 ++++++++ drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c | 10 ++++++++++ drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 18 ------------------ 3 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 21193a73acfc..65c1e1afe6a8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -580,8 +580,15 @@ static int rk_gmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; struct stmmac_resources stmmac_res; + const struct stmmac_of_data *data; int ret; + data = of_device_get_match_data(&pdev->dev); + if (!data) { + dev_err(&pdev->dev, "no of match data provided\n"); + return -EINVAL; + } + ret = stmmac_get_platform_resources(pdev, &stmmac_res); if (ret) return ret; @@ -591,6 +598,7 @@ static int rk_gmac_probe(struct platform_device *pdev) return PTR_ERR(plat_dat); plat_dat->has_gmac = true; + plat_dat->setup = data->setup; plat_dat->init = rk_gmac_init; plat_dat->exit = rk_gmac_exit; plat_dat->fix_mac_speed = rk_fix_speed; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index b17238aac791..8a977fde1a46 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "stmmac_platform.h" @@ -337,10 +338,17 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, static int sti_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; + const struct stmmac_of_data *data; struct stmmac_resources stmmac_res; struct sti_dwmac *dwmac; int ret; + data = of_device_get_match_data(&pdev->dev); + if (!data) { + dev_err(&pdev->dev, "No OF match data provided\n"); + return -EINVAL; + } + ret = stmmac_get_platform_resources(pdev, &stmmac_res); if (ret) return ret; @@ -360,7 +368,9 @@ static int sti_dwmac_probe(struct platform_device *pdev) } plat_dat->bsp_priv = dwmac; + plat_dat->init = data->init; plat_dat->exit = sti_dwmac_exit; + plat_dat->fix_mac_speed = data->fix_mac_speed; ret = plat_dat->init(pdev, plat_dat->bsp_priv); if (ret) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 9c49d95e529a..55e569b330b2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -109,30 +109,12 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { struct device_node *np = pdev->dev.of_node; struct plat_stmmacenet_data *plat; - const struct stmmac_of_data *data; struct stmmac_dma_cfg *dma_cfg; plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); if (!plat) return ERR_PTR(-ENOMEM); - data = of_device_get_match_data(&pdev->dev); - if (data) { - plat->has_gmac = data->has_gmac; - plat->enh_desc = data->enh_desc; - plat->tx_coe = data->tx_coe; - plat->rx_coe = data->rx_coe; - plat->bugged_jumbo = data->bugged_jumbo; - plat->pmt = data->pmt; - plat->riwt_off = data->riwt_off; - plat->fix_mac_speed = data->fix_mac_speed; - plat->bus_setup = data->bus_setup; - plat->setup = data->setup; - plat->free = data->free; - plat->init = data->init; - plat->exit = data->exit; - } - *mac = of_get_mac_address(np); plat->interface = of_get_phy_mode(np); -- cgit v1.3-6-gb490 From 07ca3749cec2b8c7967d73cfa030a144610d3d4e Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:08:59 +0200 Subject: stmmac: dwmac-sti: use custom of match structure Create a new private structure for OF match data in the dwmac-sti driver. This enables us to eventually drop the common OF match data structure which contains a lot of unused fields. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index 8a977fde1a46..83c501edb688 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -131,6 +131,11 @@ struct sti_dwmac { u32 speed; }; +struct sti_dwmac_of_data { + void (*fix_mac_speed)(void *priv, unsigned int speed); + int (*init)(struct platform_device *pdev, void *priv); +}; + static u32 phy_intf_sels[] = { [PHY_INTERFACE_MODE_MII] = ETH_PHY_SEL_MII, [PHY_INTERFACE_MODE_GMII] = ETH_PHY_SEL_GMII, @@ -338,7 +343,7 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, static int sti_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; - const struct stmmac_of_data *data; + const struct sti_dwmac_of_data *data; struct stmmac_resources stmmac_res; struct sti_dwmac *dwmac; int ret; @@ -379,12 +384,12 @@ static int sti_dwmac_probe(struct platform_device *pdev) return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); } -static const struct stmmac_of_data stih4xx_dwmac_data = { +static const struct sti_dwmac_of_data stih4xx_dwmac_data = { .fix_mac_speed = stih4xx_fix_retime_src, .init = stix4xx_init, }; -static const struct stmmac_of_data stid127_dwmac_data = { +static const struct sti_dwmac_of_data stid127_dwmac_data = { .fix_mac_speed = stid127_fix_retime_src, .init = stid127_init, }; -- cgit v1.3-6-gb490 From 92c2588fc60c06525c2ef8d6de5b2314c202c3be Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:09:00 +0200 Subject: stmmac: dwmac-rk: make rk_gmac_ops structs static const Mark the rk_gmac_ops structures as static const as they should be. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 65c1e1afe6a8..5d8042ea8370 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -46,7 +46,7 @@ struct rk_priv_data { struct platform_device *pdev; int phy_iface; struct regulator *regulator; - struct rk_gmac_ops *ops; + const struct rk_gmac_ops *ops; bool clk_enabled; bool clock_input; @@ -177,7 +177,7 @@ static void rk3288_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) } } -struct rk_gmac_ops rk3288_ops = { +static const struct rk_gmac_ops rk3288_ops = { .set_to_rgmii = rk3288_set_to_rgmii, .set_to_rmii = rk3288_set_to_rmii, .set_rgmii_speed = rk3288_set_rgmii_speed, @@ -289,7 +289,7 @@ static void rk3368_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) } } -struct rk_gmac_ops rk3368_ops = { +static const struct rk_gmac_ops rk3368_ops = { .set_to_rgmii = rk3368_set_to_rgmii, .set_to_rmii = rk3368_set_to_rmii, .set_rgmii_speed = rk3368_set_rgmii_speed, @@ -448,7 +448,7 @@ static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable) } static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev, - struct rk_gmac_ops *ops) + const struct rk_gmac_ops *ops) { struct rk_priv_data *bsp_priv; struct device *dev = &pdev->dev; -- cgit v1.3-6-gb490 From f529f18255ed5fbb888498cfaa8cad63eab629e4 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:09:01 +0200 Subject: stmmac: dwmac-rk: use rk_gmac_ops as of match data Remove the setup glue callback and use rk_gmac_ops as OF match data so it can used directly when calling rk_gmac_setup. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 27 ++++---------------------- 1 file changed, 4 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 5d8042ea8370..11baa4b19779 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -529,16 +529,6 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev, return bsp_priv; } -static void *rk3288_gmac_setup(struct platform_device *pdev) -{ - return rk_gmac_setup(pdev, &rk3288_ops); -} - -static void *rk3368_gmac_setup(struct platform_device *pdev) -{ - return rk_gmac_setup(pdev, &rk3368_ops); -} - static int rk_gmac_init(struct platform_device *pdev, void *priv) { struct rk_priv_data *bsp_priv = priv; @@ -580,7 +570,7 @@ static int rk_gmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; struct stmmac_resources stmmac_res; - const struct stmmac_of_data *data; + const struct rk_gmac_ops *data; int ret; data = of_device_get_match_data(&pdev->dev); @@ -598,12 +588,11 @@ static int rk_gmac_probe(struct platform_device *pdev) return PTR_ERR(plat_dat); plat_dat->has_gmac = true; - plat_dat->setup = data->setup; plat_dat->init = rk_gmac_init; plat_dat->exit = rk_gmac_exit; plat_dat->fix_mac_speed = rk_fix_speed; - plat_dat->bsp_priv = plat_dat->setup(pdev); + plat_dat->bsp_priv = rk_gmac_setup(pdev, data); if (IS_ERR(plat_dat->bsp_priv)) return PTR_ERR(plat_dat->bsp_priv); @@ -614,17 +603,9 @@ static int rk_gmac_probe(struct platform_device *pdev) return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); } -static const struct stmmac_of_data rk3288_gmac_data = { - .setup = rk3288_gmac_setup, -}; - -static const struct stmmac_of_data rk3368_gmac_data = { - .setup = rk3368_gmac_setup, -}; - static const struct of_device_id rk_gmac_dwmac_match[] = { - { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_gmac_data}, - { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_gmac_data}, + { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops }, + { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops }, { } }; MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match); -- cgit v1.3-6-gb490 From 75fee59550a9899fd9438ebc0a64c972829a8dd2 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:09:03 +0200 Subject: stmmac: remove setup/free glue callbacks As all dwmac-* drivers have been converted to have a proper probe function the setup callback can now be removed. Also remove the free callback that wasn't used by any driver. New dwmac-* drivers should implement standard probe and remove functions to preform any needed setup and teardown. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- Documentation/networking/stmmac.txt | 8 ++------ drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c | 7 ------- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 --- include/linux/stmmac.h | 2 -- 4 files changed, 2 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt index de5c42342ec3..2903b1cf4d70 100644 --- a/Documentation/networking/stmmac.txt +++ b/Documentation/networking/stmmac.txt @@ -135,8 +135,6 @@ struct plat_stmmacenet_data { int maxmtu; void (*fix_mac_speed)(void *priv, unsigned int speed); void (*bus_setup)(void __iomem *ioaddr); - void *(*setup)(struct platform_device *pdev); - void (*free)(struct platform_device *pdev, void *priv); int (*init)(struct platform_device *pdev, void *priv); void (*exit)(struct platform_device *pdev, void *priv); void *bsp_priv; @@ -177,12 +175,10 @@ Where: o bus_setup: perform HW setup of the bus. For example, on some ST platforms this field is used to configure the AMBA bridge to generate more efficient STBus traffic. - o setup/init/exit: callbacks used for calling a custom initialization; + o init/exit: callbacks used for calling a custom initialization; this is sometime necessary on some platforms (e.g. ST boxes) where the HW needs to have set some PIO lines or system cfg - registers. setup should return a pointer to private data, - which will be stored in bsp_priv, and then passed to init and - exit callbacks. init/exit callbacks should not use or modify + registers. init/exit callbacks should not use or modify platform data. o bsp_priv: another private pointer. diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c index f4fe9f1a33b4..b1e5f24708c9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c @@ -46,13 +46,6 @@ static int dwmac_generic_probe(struct platform_device *pdev) plat_dat->unicast_filter_entries = 1; } - /* Custom setup (if needed) */ - if (plat_dat->setup) { - plat_dat->bsp_priv = plat_dat->setup(pdev); - if (IS_ERR(plat_dat->bsp_priv)) - return PTR_ERR(plat_dat->bsp_priv); - } - /* Custom initialisation (if needed) */ if (plat_dat->init) { ret = plat_dat->init(pdev, plat_dat->bsp_priv); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 55e569b330b2..1cb660405f35 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -300,9 +300,6 @@ int stmmac_pltfr_remove(struct platform_device *pdev) if (priv->plat->exit) priv->plat->exit(pdev, priv->plat->bsp_priv); - if (priv->plat->free) - priv->plat->free(pdev, priv->plat->bsp_priv); - return ret; } EXPORT_SYMBOL_GPL(stmmac_pltfr_remove); diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index b43cd56b78e9..eead8ab93c0a 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -119,8 +119,6 @@ struct plat_stmmacenet_data { int rx_fifo_size; void (*fix_mac_speed)(void *priv, unsigned int speed); void (*bus_setup)(void __iomem *ioaddr); - void *(*setup)(struct platform_device *pdev); - void (*free)(struct platform_device *pdev, void *priv); int (*init)(struct platform_device *pdev, void *priv); void (*exit)(struct platform_device *pdev, void *priv); void *bsp_priv; -- cgit v1.3-6-gb490 From 16b1adbb16c8a52b206092d875030b346b9ce50b Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 29 Jul 2015 00:09:04 +0200 Subject: stmmac: dwmac-sti: refactor the init glue callbacks Remove the two platform specific init callbacks and make them use a common one by creating a function member in the internal data structure. This allow us to remove the layer of indirection and simplify the code a bit. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c | 43 +++++++------------------ 1 file changed, 12 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index 83c501edb688..7f6f4a4fcc70 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -129,11 +129,11 @@ struct sti_dwmac { struct device *dev; struct regmap *regmap; u32 speed; + void (*fix_retime_src)(void *priv, unsigned int speed); }; struct sti_dwmac_of_data { - void (*fix_mac_speed)(void *priv, unsigned int speed); - int (*init)(struct platform_device *pdev, void *priv); + void (*fix_retime_src)(void *priv, unsigned int speed); }; static u32 phy_intf_sels[] = { @@ -228,8 +228,9 @@ static void stid127_fix_retime_src(void *priv, u32 spd) regmap_update_bits(dwmac->regmap, reg, STID127_RETIME_SRC_MASK, val); } -static void sti_dwmac_ctrl_init(struct sti_dwmac *dwmac) +static int sti_dwmac_init(struct platform_device *pdev, void *priv) { + struct sti_dwmac *dwmac = priv; struct regmap *regmap = dwmac->regmap; int iface = dwmac->interface; struct device *dev = dwmac->dev; @@ -247,28 +248,8 @@ static void sti_dwmac_ctrl_init(struct sti_dwmac *dwmac) val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII; regmap_update_bits(regmap, reg, ENMII_MASK, val); -} - -static int stix4xx_init(struct platform_device *pdev, void *priv) -{ - struct sti_dwmac *dwmac = priv; - u32 spd = dwmac->speed; - - sti_dwmac_ctrl_init(dwmac); - stih4xx_fix_retime_src(priv, spd); - - return 0; -} - -static int stid127_init(struct platform_device *pdev, void *priv) -{ - struct sti_dwmac *dwmac = priv; - u32 spd = dwmac->speed; - - sti_dwmac_ctrl_init(dwmac); - - stid127_fix_retime_src(priv, spd); + dwmac->fix_retime_src(priv, dwmac->speed); return 0; } @@ -372,12 +353,14 @@ static int sti_dwmac_probe(struct platform_device *pdev) return ret; } + dwmac->fix_retime_src = data->fix_retime_src; + plat_dat->bsp_priv = dwmac; - plat_dat->init = data->init; + plat_dat->init = sti_dwmac_init; plat_dat->exit = sti_dwmac_exit; - plat_dat->fix_mac_speed = data->fix_mac_speed; + plat_dat->fix_mac_speed = data->fix_retime_src; - ret = plat_dat->init(pdev, plat_dat->bsp_priv); + ret = sti_dwmac_init(pdev, plat_dat->bsp_priv); if (ret) return ret; @@ -385,13 +368,11 @@ static int sti_dwmac_probe(struct platform_device *pdev) } static const struct sti_dwmac_of_data stih4xx_dwmac_data = { - .fix_mac_speed = stih4xx_fix_retime_src, - .init = stix4xx_init, + .fix_retime_src = stih4xx_fix_retime_src, }; static const struct sti_dwmac_of_data stid127_dwmac_data = { - .fix_mac_speed = stid127_fix_retime_src, - .init = stid127_init, + .fix_retime_src = stid127_fix_retime_src, }; static const struct of_device_id sti_dwmac_match[] = { -- cgit v1.3-6-gb490 From d0abe2f3a9a541ded2e30ef7275f057fb7f0335a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:51:22 +0000 Subject: sh/irq: Use irq accessor functions instead of open coded access This is a preparatory patch for refactoring the internals if irq_data. Signed-off-by: Jiang Liu Cc: Simon Horman Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150713151626.616384365@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- drivers/sh/intc/virq.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c index f5f1b821241a..0f735301d3ec 100644 --- a/drivers/sh/intc/virq.c +++ b/drivers/sh/intc/virq.c @@ -83,12 +83,11 @@ EXPORT_SYMBOL_GPL(intc_irq_lookup); static int add_virq_to_pirq(unsigned int irq, unsigned int virq) { - struct intc_virq_list **last, *entry; - struct irq_data *data = irq_get_irq_data(irq); + struct intc_virq_list *entry; + struct intc_virq_list **last = NULL; /* scan for duplicates */ - last = (struct intc_virq_list **)&data->handler_data; - for_each_virq(entry, data->handler_data) { + for_each_virq(entry, irq_get_handler_data(irq)) { if (entry->irq == virq) return 0; last = &entry->next; @@ -102,7 +101,10 @@ static int add_virq_to_pirq(unsigned int irq, unsigned int virq) entry->irq = virq; - *last = entry; + if (last) + *last = entry; + else + irq_set_handler_data(irq, entry); return 0; } -- cgit v1.3-6-gb490 From 8b8149df9ce99e02cb2b4655bf20d0ce459b9076 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:51:23 +0000 Subject: sh/irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Cc: Simon Horman Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150713151626.713278346@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/sh/kernel/irq.c | 7 ++++--- drivers/sh/intc/chip.c | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 8dc677cc136b..6c0378c0b8b5 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -228,15 +228,16 @@ void migrate_irqs(void) struct irq_data *data = irq_get_irq_data(irq); if (irq_data_get_node(data) == cpu) { - unsigned int newcpu = cpumask_any_and(data->affinity, + struct cpumask *mask = irq_data_get_affinity_mask(data); + unsigned int newcpu = cpumask_any_and(mask, cpu_online_mask); if (newcpu >= nr_cpu_ids) { pr_info_ratelimited("IRQ%u no longer affine to CPU%u\n", irq, cpu); - cpumask_setall(data->affinity); + cpumask_setall(mask); } - irq_set_affinity(irq, data->affinity); + irq_set_affinity(irq, mask); } } } diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c index 46427b48e2f1..358df7510186 100644 --- a/drivers/sh/intc/chip.c +++ b/drivers/sh/intc/chip.c @@ -22,7 +22,7 @@ void _intc_enable(struct irq_data *data, unsigned long handle) for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { #ifdef CONFIG_SMP - if (!cpumask_test_cpu(cpu, data->affinity)) + if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data))) continue; #endif addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); @@ -50,7 +50,7 @@ static void intc_disable(struct irq_data *data) for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { #ifdef CONFIG_SMP - if (!cpumask_test_cpu(cpu, data->affinity)) + if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data))) continue; #endif addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); @@ -72,7 +72,7 @@ static int intc_set_affinity(struct irq_data *data, if (!cpumask_intersects(cpumask, cpu_online_mask)) return -1; - cpumask_copy(data->affinity, cpumask); + cpumask_copy(irq_data_get_affinity_mask(data), cpumask); return IRQ_SET_MASK_OK_NOCOPY; } -- cgit v1.3-6-gb490 From 8228a048961a93e871779c658eaa801f747e6c1d Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:51:25 +0000 Subject: sh/intc: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. Also replace generic_handle_irq with generic_handle_irq_desc() to avoid looking up irq_desc again. Signed-off-by: Jiang Liu Cc: Simon Horman Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150713151626.792845830@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/sh/boards/mach-se/7343/irq.c | 2 +- arch/sh/boards/mach-se/7722/irq.c | 2 +- arch/sh/boards/mach-x3proto/gpio.c | 2 +- drivers/sh/intc/core.c | 2 +- drivers/sh/intc/virq.c | 14 ++++++++------ 5 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/arch/sh/boards/mach-se/7343/irq.c b/arch/sh/boards/mach-se/7343/irq.c index 1087dba9b015..6f97a8f0d0d6 100644 --- a/arch/sh/boards/mach-se/7343/irq.c +++ b/arch/sh/boards/mach-se/7343/irq.c @@ -31,7 +31,7 @@ struct irq_domain *se7343_irq_domain; static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc) { - struct irq_data *data = irq_get_irq_data(irq); + struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(data); unsigned long mask; int bit; diff --git a/arch/sh/boards/mach-se/7722/irq.c b/arch/sh/boards/mach-se/7722/irq.c index 00e699232621..60aebd14ccf8 100644 --- a/arch/sh/boards/mach-se/7722/irq.c +++ b/arch/sh/boards/mach-se/7722/irq.c @@ -30,7 +30,7 @@ struct irq_domain *se7722_irq_domain; static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc) { - struct irq_data *data = irq_get_irq_data(irq); + struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(data); unsigned long mask; int bit; diff --git a/arch/sh/boards/mach-x3proto/gpio.c b/arch/sh/boards/mach-x3proto/gpio.c index f035a7ac6456..24555c364d5b 100644 --- a/arch/sh/boards/mach-x3proto/gpio.c +++ b/arch/sh/boards/mach-x3proto/gpio.c @@ -62,7 +62,7 @@ static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct irq_data *data = irq_get_irq_data(irq); + struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(data); unsigned long mask; int pin; diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 156b790072b4..043419dcee92 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -67,7 +67,7 @@ void intc_set_prio_level(unsigned int irq, unsigned int level) static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc) { - generic_handle_irq((unsigned int)irq_get_handler_data(irq)); + generic_handle_irq((unsigned int)irq_desc_get_handler_data(desc)); } static void __init intc_register_irq(struct intc_desc *desc, diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c index 0f735301d3ec..503d95a48d13 100644 --- a/drivers/sh/intc/virq.c +++ b/drivers/sh/intc/virq.c @@ -111,7 +111,7 @@ static int add_virq_to_pirq(unsigned int irq, unsigned int virq) static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) { - struct irq_data *data = irq_get_irq_data(irq); + struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(data); struct intc_virq_list *entry, *vlist = irq_data_get_irq_handler_data(data); struct intc_desc_int *d = get_intc_desc(irq); @@ -120,12 +120,14 @@ static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) for_each_virq(entry, vlist) { unsigned long addr, handle; + struct irq_desc *vdesc = irq_to_desc(entry->irq); - handle = (unsigned long)irq_get_handler_data(entry->irq); - addr = INTC_REG(d, _INTC_ADDR_E(handle), 0); - - if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0)) - generic_handle_irq(entry->irq); + if (vdesc) { + handle = (unsigned long)irq_desc_get_handler_data(vdesc); + addr = INTC_REG(d, _INTC_ADDR_E(handle), 0); + if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0)) + generic_handle_irq_desc(entry->irq, vdesc); + } } chip->irq_unmask(data); -- cgit v1.3-6-gb490 From c497615c0cb62ba0b06db9580911dcf6d612bdb9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:51:26 +0000 Subject: sh/intc: Prepare irq flow handlers for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Simon Horman Cc: Magnus Damm Cc: Julia Lawall Link: http://lkml.kernel.org/r/20150713151626.872605327@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/sh/boards/mach-se/7724/irq.c | 3 ++- drivers/sh/intc/virq.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/arch/sh/boards/mach-se/7724/irq.c b/arch/sh/boards/mach-se/7724/irq.c index 5d1d3ec9a6cd..9f2033898652 100644 --- a/arch/sh/boards/mach-se/7724/irq.c +++ b/arch/sh/boards/mach-se/7724/irq.c @@ -92,8 +92,9 @@ static struct irq_chip se7724_irq_chip __read_mostly = { .irq_unmask = enable_se7724_irq, }; -static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc) +static void se7724_irq_demux(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct fpga_irq set = get_fpga_irq(irq); unsigned short intv = __raw_readw(set.sraddr); unsigned int ext_irq = set.base; diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c index 503d95a48d13..bafc51c6f0ba 100644 --- a/drivers/sh/intc/virq.c +++ b/drivers/sh/intc/virq.c @@ -109,8 +109,9 @@ static int add_virq_to_pirq(unsigned int irq, unsigned int virq) return 0; } -static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) +static void intc_virq_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(data); struct intc_virq_list *entry, *vlist = irq_data_get_irq_handler_data(data); -- cgit v1.3-6-gb490 From fb68ba6d0b06cf287e9081d60f705501c52124f6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:52:24 +0000 Subject: spmi/pmic_arb: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Greg Kroah-Hartman Cc: Jiang Liu Cc: Julia Lawall Link: http://lkml.kernel.org/r/20150713151750.831790045@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- drivers/spmi/spmi-pmic-arb.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index d7119db49cfe..db2aac173509 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -928,8 +928,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) goto err_put_ctrl; } - irq_set_handler_data(pa->irq, pa); - irq_set_chained_handler(pa->irq, pmic_arb_chained_irq); + irq_set_chained_handler_and_data(pa->irq, pmic_arb_chained_irq, pa); err = spmi_controller_add(ctrl); if (err) @@ -938,8 +937,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) return 0; err_domain_remove: - irq_set_chained_handler(pa->irq, NULL); - irq_set_handler_data(pa->irq, NULL); + irq_set_chained_handler_and_data(pa->irq, NULL, NULL); irq_domain_remove(pa->domain); err_put_ctrl: spmi_controller_put(ctrl); @@ -951,8 +949,7 @@ static int spmi_pmic_arb_remove(struct platform_device *pdev) struct spmi_controller *ctrl = platform_get_drvdata(pdev); struct spmi_pmic_arb_dev *pa = spmi_controller_get_drvdata(ctrl); spmi_controller_remove(ctrl); - irq_set_chained_handler(pa->irq, NULL); - irq_set_handler_data(pa->irq, NULL); + irq_set_chained_handler_and_data(pa->irq, NULL, NULL); irq_domain_remove(pa->domain); spmi_controller_put(ctrl); return 0; -- cgit v1.3-6-gb490 From 7fe88f3c00e7bfa44421681640fab3a9fadfef3b Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:52:25 +0000 Subject: spmi/pmic: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. Signed-off-by: Jiang Liu Cc: Greg Kroah-Hartman Link: http://lkml.kernel.org/r/20150713151750.915477120@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- drivers/spmi/spmi-pmic-arb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index db2aac173509..483948459765 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -453,8 +453,8 @@ static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid) static void pmic_arb_chained_irq(unsigned int irq, struct irq_desc *desc) { - struct spmi_pmic_arb_dev *pa = irq_get_handler_data(irq); - struct irq_chip *chip = irq_get_chip(irq); + struct spmi_pmic_arb_dev *pa = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); void __iomem *intr = pa->intr; int first = pa->min_apid >> 5; int last = pa->max_apid >> 5; -- cgit v1.3-6-gb490 From a0d61f5f61290ee70cd024c7573e2ac5562f7a78 Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 29 Jun 2015 13:30:37 -0400 Subject: ath6kl: spell "distribution" correctly in a comment. This fixes two misspellings of "distribution" in a comment. Signed-off-by: Nik Nyby Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/htc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index 14cab1403dd6..112d8a9b8d43 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -427,7 +427,7 @@ struct htc_endpoint_credit_dist { }; /* - * credit distibution code that is passed into the distrbution function, + * credit distribution code that is passed into the distribution function, * there are mandatory and optional codes that must be handled */ enum htc_credit_dist_reason { -- cgit v1.3-6-gb490 From 3413e97dbbae8561e01ac28ccb0d4bbe7ce933f4 Mon Sep 17 00:00:00 2001 From: Kevin Darbyshire-Bryant Date: Tue, 21 Jul 2015 15:50:15 +0100 Subject: ath10k: suppress 'failed to process fft' warning messages When using DFS channels on Ath10k, kernel log has repeated warning message 'failed to process fft: -22' typically under medium/heavy traffic. This patch switches the warnings to driver debug (WMI events) mode only thus reducing log file noise. DFS and spectral scan share underlying HW mechanisms and enabling one (DFS) enables the other (spectral scan) as far as event reporting from firmware to driver is concerned. Spectral scan events take no part in processing of DFS radar pulses which are delivered as distinct events, so the fft (spectral event) warning is harmless and DFS interference detection/protection still occurs. Symptoms seen & fix tested in both debug & non-debug modes on TP-Link Archer C7 v2 platform. Signed-off-by: Kevin Darbyshire-Bryant Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 0791a4336e80..1435614b0a55 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3498,7 +3498,7 @@ void ath10k_wmi_event_spectral_scan(struct ath10k *ar, fftr, fftr_len, tsf); if (res < 0) { - ath10k_warn(ar, "failed to process fft report: %d\n", + ath10k_dbg(ar, ATH10K_DBG_WMI, "failed to process fft report: %d\n", res); return; } -- cgit v1.3-6-gb490 From afe0d67e1f67250ddf69fc6ef9b76f4407e6815a Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 23 Jul 2015 16:35:45 -0700 Subject: drm/i915: Try to stop sink crc calculation on error. Right now if we face any kind of error sink crc calculation stays enabled. So, let's give a shot and try to stop it anyway if it got enabled. Signed-off-by: Rodrigo Vivi Reviewed-by: Rafael Antognolli Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f1b9f939b435..70a4a37b7f7f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3994,7 +3994,7 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0) { ret = -EIO; - goto out; + goto stop; } test_crc_count = buf & DP_TEST_COUNT_MASK; @@ -4003,7 +4003,7 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0) { ret = -EIO; - goto out; + goto stop; } intel_wait_for_vblank(dev, intel_crtc->pipe); } while (--attempts && (buf & DP_TEST_COUNT_MASK) == test_crc_count); @@ -4011,14 +4011,15 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) if (attempts == 0) { DRM_DEBUG_KMS("Panel is unable to calculate CRC after 6 vblanks\n"); ret = -ETIMEDOUT; - goto out; + goto stop; } if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) { ret = -EIO; - goto out; + goto stop; } +stop: if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) { ret = -EIO; goto out; -- cgit v1.3-6-gb490 From dcc13bcb488874568c5e2c32b43b68e069ada75c Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 23 Jul 2015 16:35:46 -0700 Subject: drm/i915: Don't return error on sink crc stop. If we got to the point where we are trying to stop sink CRC the main output of this function was already gotten properly, so don't return the error and let userspace use the crc data. Let's replace the errnos returns with some log messages. Signed-off-by: Rodrigo Vivi Reviewed-by: Rafael Antognolli Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 70a4a37b7f7f..44f8a32e4d1e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4021,12 +4021,12 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) stop: if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) { - ret = -EIO; + DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n"); goto out; } if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, buf & ~DP_TEST_SINK_START) < 0) { - ret = -EIO; + DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n"); goto out; } out: -- cgit v1.3-6-gb490 From 005fb161310f72070ad5f4352d6b81ffaca8a11e Mon Sep 17 00:00:00 2001 From: Qi Zhou Date: Wed, 22 Jul 2015 16:38:24 -0400 Subject: ath10k: Improve performance by reducing tx_lock contention During tx completion, tx_lock is held for longer than required, preventing efficient refill of htt->pending_tx. Refactor the code so that only MSDU related operations are protected by the lock. Improves downstream performance on a dual-core ARM Freescale LS1024A (f.k.a. Mindspeed Comcerto 2000) AP with a 3x3 client from 495 to 580 Mbps. Other CPU bound multicore systems may also benefit. Signed-off-by: Denton Gentry Signed-off-by: Avery Pennarun [mfaltesek@google.com: removed conflicting code for tracking msdu_ids.] Signed-off-by: Marty Faltesek Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 12 ++---------- drivers/net/wireless/ath/ath10k/htt_tx.c | 8 ++------ drivers/net/wireless/ath/ath10k/txrx.c | 17 ++++++++--------- 3 files changed, 12 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 61a26264728a..5e54c393767e 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1631,8 +1631,6 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar, __le16 msdu_id; int i; - lockdep_assert_held(&htt->tx_lock); - switch (status) { case HTT_DATA_TX_STATUS_NO_ACK: tx_done.no_ack = true; @@ -1998,15 +1996,11 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; } - spin_lock_bh(&htt->tx_lock); ath10k_txrx_tx_unref(htt, &tx_done); - spin_unlock_bh(&htt->tx_lock); break; } case HTT_T2H_MSG_TYPE_TX_COMPL_IND: - spin_lock_bh(&htt->tx_lock); - __skb_queue_tail(&htt->tx_compl_q, skb); - spin_unlock_bh(&htt->tx_lock); + skb_queue_tail(&htt->tx_compl_q, skb); tasklet_schedule(&htt->txrx_compl_task); return; case HTT_T2H_MSG_TYPE_SEC_IND: { @@ -2095,12 +2089,10 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) struct htt_resp *resp; struct sk_buff *skb; - spin_lock_bh(&htt->tx_lock); - while ((skb = __skb_dequeue(&htt->tx_compl_q))) { + while ((skb = skb_dequeue(&htt->tx_compl_q))) { ath10k_htt_rx_frm_tx_compl(htt->ar, skb); dev_kfree_skb_any(skb); } - spin_unlock_bh(&htt->tx_lock); spin_lock_bh(&htt->rx_ring.lock); while ((skb = __skb_dequeue(&htt->rx_compl_q))) { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index a97dd9d4295b..2c0627b7141b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -134,9 +134,7 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) tx_done.discard = 1; tx_done.msdu_id = msdu_id; - spin_lock_bh(&htt->tx_lock); ath10k_txrx_tx_unref(htt, &tx_done); - spin_unlock_bh(&htt->tx_lock); return 0; } @@ -429,12 +427,11 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) spin_lock_bh(&htt->tx_lock); res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); + spin_unlock_bh(&htt->tx_lock); if (res < 0) { - spin_unlock_bh(&htt->tx_lock); goto err_tx_dec; } msdu_id = res; - spin_unlock_bh(&htt->tx_lock); txdesc = ath10k_htc_alloc_skb(ar, len); if (!txdesc) { @@ -506,12 +503,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) spin_lock_bh(&htt->tx_lock); res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); + spin_unlock_bh(&htt->tx_lock); if (res < 0) { - spin_unlock_bh(&htt->tx_lock); goto err_tx_dec; } msdu_id = res; - spin_unlock_bh(&htt->tx_lock); prefetch_len = min(htt->prefetch_len, msdu->len); prefetch_len = roundup(prefetch_len, 4); diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 6cf289158840..e4a9c4c8d0cb 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -53,8 +53,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct ath10k_skb_cb *skb_cb; struct sk_buff *msdu; - lockdep_assert_held(&htt->tx_lock); - ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d success %d\n", tx_done->msdu_id, !!tx_done->discard, @@ -66,12 +64,19 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, return; } + spin_lock_bh(&htt->tx_lock); msdu = idr_find(&htt->pending_tx, tx_done->msdu_id); if (!msdu) { ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n", tx_done->msdu_id); + spin_unlock_bh(&htt->tx_lock); return; } + ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); + __ath10k_htt_tx_dec_pending(htt); + if (htt->num_pending_tx == 0) + wake_up(&htt->empty_tx_wq); + spin_unlock_bh(&htt->tx_lock); skb_cb = ATH10K_SKB_CB(msdu); @@ -90,7 +95,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, if (tx_done->discard) { ieee80211_free_txskb(htt->ar->hw, msdu); - goto exit; + return; } if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) @@ -104,12 +109,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ieee80211_tx_status(htt->ar->hw, msdu); /* we do not own the msdu anymore */ - -exit: - ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); - __ath10k_htt_tx_dec_pending(htt); - if (htt->num_pending_tx == 0) - wake_up(&htt->empty_tx_wq); } struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, -- cgit v1.3-6-gb490 From ccec9038c7217e537f5ae5e3ac5af8293a21bbfd Mon Sep 17 00:00:00 2001 From: David Liu Date: Fri, 24 Jul 2015 20:25:32 +0300 Subject: ath10k: enable raw encap mode and software crypto engine This patch enables raw Rx/Tx encap mode to support software based crypto engine. This patch introduces a new module param 'cryptmode'. cryptmode: 0: Use hardware crypto engine globally with native Wi-Fi mode TX/RX encapsulation to the firmware. This is the default mode. 1: Use sofware crypto engine globally with raw mode TX/RX encapsulation to the firmware. Known limitation: A-MSDU must be disabled for RAW Tx encap mode to perform well when heavy traffic is applied. Testing: (by Michal Kazior ) a) Performance Testing cryptmode=1 ap=qca988x sta=killer1525 killer1525 -> qca988x 194.496 mbps [tcp1 ip4] killer1525 -> qca988x 238.309 mbps [tcp5 ip4] killer1525 -> qca988x 266.958 mbps [udp1 ip4] killer1525 -> qca988x 477.468 mbps [udp5 ip4] qca988x -> killer1525 301.378 mbps [tcp1 ip4] qca988x -> killer1525 297.949 mbps [tcp5 ip4] qca988x -> killer1525 331.351 mbps [udp1 ip4] qca988x -> killer1525 371.528 mbps [udp5 ip4] ap=killer1525 sta=qca988x qca988x -> killer1525 331.447 mbps [tcp1 ip4] qca988x -> killer1525 328.783 mbps [tcp5 ip4] qca988x -> killer1525 375.309 mbps [udp1 ip4] qca988x -> killer1525 403.379 mbps [udp5 ip4] killer1525 -> qca988x 203.689 mbps [tcp1 ip4] killer1525 -> qca988x 222.339 mbps [tcp5 ip4] killer1525 -> qca988x 264.199 mbps [udp1 ip4] killer1525 -> qca988x 479.371 mbps [udp5 ip4] Note: - only open network tested for RAW vs nwifi performance comparison - killer1525 (qca6174 hw2.2) is 2x2 device (hence max 866mbps) - used iperf - OTA, devices a few cm apart from each other, no shielding - tcpX/udpX, X - means number of threads used Overview: - relative Tx performance drop is seen but is within reasonable and expected threshold (A-MSDU must be disabled with RAW Tx) b) Connectivity Testing cryptmode=1 ap=iwl6205 sta1=qca988x crypto=open topology-1ap1sta OK ap=iwl6205 sta1=qca988x crypto=wep1 topology-1ap1sta OK ap=iwl6205 sta1=qca988x crypto=wpa topology-1ap1sta OK ap=iwl6205 sta1=qca988x crypto=wpa-ccmp topology-1ap1sta OK ap=qca988x sta1=iwl6205 crypto=open topology-1ap1sta OK ap=qca988x sta1=iwl6205 crypto=wep1 topology-1ap1sta OK ap=qca988x sta1=iwl6205 crypto=wpa topology-1ap1sta OK ap=qca988x sta1=iwl6205 crypto=wpa-ccmp topology-1ap1sta OK ap=iwl6205 sta1=qca988x crypto=open topology-1ap1sta2br OK ap=iwl6205 sta1=qca988x crypto=wep1 topology-1ap1sta2br OK ap=iwl6205 sta1=qca988x crypto=wpa topology-1ap1sta2br OK ap=iwl6205 sta1=qca988x crypto=wpa-ccmp topology-1ap1sta2br OK ap=qca988x sta1=iwl6205 crypto=open topology-1ap1sta2br OK ap=qca988x sta1=iwl6205 crypto=wep1 topology-1ap1sta2br OK ap=qca988x sta1=iwl6205 crypto=wpa topology-1ap1sta2br OK ap=qca988x sta1=iwl6205 crypto=wpa-ccmp topology-1ap1sta2br OK ap=iwl6205 sta1=qca988x crypto=open topology-1ap1sta2br1vlan OK ap=iwl6205 sta1=qca988x crypto=wep1 topology-1ap1sta2br1vlan OK ap=iwl6205 sta1=qca988x crypto=wpa topology-1ap1sta2br1vlan OK ap=iwl6205 sta1=qca988x crypto=wpa-ccmp topology-1ap1sta2br1vlan OK ap=qca988x sta1=iwl6205 crypto=open topology-1ap1sta2br1vlan OK ap=qca988x sta1=iwl6205 crypto=wep1 topology-1ap1sta2br1vlan OK ap=qca988x sta1=iwl6205 crypto=wpa topology-1ap1sta2br1vlan OK ap=qca988x sta1=iwl6205 crypto=wpa-ccmp topology-1ap1sta2br1vlan OK Note: - each test takes all possible endpoint pairs and pings - each pair-ping flushes arp table - ip6 is used c) Testbed Topology: 1ap1sta: [ap] ---- [sta] endpoints: ap, sta 1ap1sta2br: [veth0] [ap] ---- [sta] [veth2] | | | | [veth1] | \ [veth3] \ / \ / [br0] [br1] endpoints: veth0, veth2, br0, br1 note: STA works in 4addr mode, AP has wds_sta=1 1ap1sta2br1vlan: [veth0] [ap] ---- [sta] [veth2] | | | | [veth1] | \ [veth3] \ / \ / [br0] [br1] | | [vlan0_id2] [vlan1_id2] endpoints: vlan0_id2, vlan1_id2 note: STA works in 4addr mode, AP has wds_sta=1 Credits: Thanks to Michal Kazior who helped find the amsdu issue, contributed a workaround (already squashed into this patch), and contributed the throughput and connectivity tests results. Signed-off-by: David Liu Signed-off-by: Michal Kazior Tested-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 43 +++++++++++++++++++ drivers/net/wireless/ath/ath10k/core.h | 31 +++++++++++--- drivers/net/wireless/ath/ath10k/debug.c | 19 ++++----- drivers/net/wireless/ath/ath10k/htt.c | 23 +++++++++- drivers/net/wireless/ath/ath10k/htt.h | 8 ++++ drivers/net/wireless/ath/ath10k/htt_rx.c | 7 ++-- drivers/net/wireless/ath/ath10k/htt_tx.c | 12 +++++- drivers/net/wireless/ath/ath10k/hw.h | 11 ++--- drivers/net/wireless/ath/ath10k/mac.c | 70 ++++++++++++++++++++++++------- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 8 ++-- 11 files changed, 183 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f79fa6c67ebc..29d2541d87dd 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -31,16 +31,19 @@ #include "wmi-ops.h" unsigned int ath10k_debug_mask; +static unsigned int ath10k_cryptmode_param; static bool uart_print; static bool skip_otp; module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); +module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644); module_param(uart_print, bool, 0644); module_param(skip_otp, bool, 0644); MODULE_PARM_DESC(debug_mask, "Debugging mask"); MODULE_PARM_DESC(uart_print, "Uart target debugging"); MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software"); static const struct ath10k_hw_params ath10k_hw_params_list[] = { { @@ -1073,6 +1076,46 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) return -EINVAL; } + ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + switch (ath10k_cryptmode_param) { + case ATH10K_CRYPT_MODE_HW: + clear_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags); + clear_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags); + break; + case ATH10K_CRYPT_MODE_SW: + if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT, + ar->fw_features)) { + ath10k_err(ar, "cryptmode > 0 requires raw mode support from firmware"); + return -EINVAL; + } + + set_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags); + set_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags); + break; + default: + ath10k_info(ar, "invalid cryptmode: %d\n", + ath10k_cryptmode_param); + return -EINVAL; + } + + ar->htt.max_num_amsdu = ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT; + ar->htt.max_num_ampdu = ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT; + + if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { + ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_RAW; + + /* Workaround: + * + * Firmware A-MSDU aggregation breaks with RAW Tx encap mode + * and causes enormous performance issues (malformed frames, + * etc). + * + * Disabling A-MSDU makes RAW mode stable with heavy traffic + * albeit a bit slower compared to regular operation. + */ + ar->htt.max_num_amsdu = 1; + } + /* Backwards compatibility for firmwares without * ATH10K_FW_IE_WMI_OP_VERSION. */ diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 78e07051b897..35f40388b622 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -92,6 +92,7 @@ struct ath10k_skb_cb { u8 tid; u16 freq; bool is_offchan; + bool nohwcrypt; struct ath10k_htt_txbuf *txbuf; u32 txbuf_paddr; } __packed htt; @@ -152,6 +153,7 @@ struct ath10k_wmi { const struct wmi_ops *ops; u32 num_mem_chunks; + u32 rx_decap_mode; struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS]; }; @@ -341,6 +343,7 @@ struct ath10k_vif { } u; bool use_cts_prot; + bool nohwcrypt; int num_legacy_stations; int txpower; struct wmi_wmm_params_all_arg wmm_params; @@ -382,9 +385,6 @@ struct ath10k_debug { u32 reg_addr; u32 nf_cal_period; - u8 htt_max_amsdu; - u8 htt_max_ampdu; - struct ath10k_fw_crash_data *fw_crash_data; }; @@ -453,16 +453,21 @@ enum ath10k_fw_features { ATH10K_FW_FEATURE_WOWLAN_SUPPORT = 6, /* Don't trust error code from otp.bin */ - ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, + ATH10K_FW_FEATURE_IGNORE_OTP_RESULT = 7, /* Some firmware revisions pad 4th hw address to 4 byte boundary making * it 8 bytes long in Native Wifi Rx decap. */ - ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING, + ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING = 8, /* Firmware supports bypassing PLL setting on init. */ ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9, + /* Raw mode support. If supported, FW supports receiving and trasmitting + * frames in raw mode. + */ + ATH10K_FW_FEATURE_RAW_MODE_SUPPORT = 10, + /* keep last */ ATH10K_FW_FEATURE_COUNT, }; @@ -476,6 +481,15 @@ enum ath10k_dev_flags { * waiters should immediately cancel instead of waiting for a time out. */ ATH10K_FLAG_CRASH_FLUSH, + + /* Use Raw mode instead of native WiFi Tx/Rx encap mode. + * Raw mode supports both hardware and software crypto. Native WiFi only + * supports hardware crypto. + */ + ATH10K_FLAG_RAW_MODE, + + /* Disable HW crypto engine */ + ATH10K_FLAG_HW_CRYPTO_DISABLED, }; enum ath10k_cal_mode { @@ -484,6 +498,13 @@ enum ath10k_cal_mode { ATH10K_CAL_MODE_DT, }; +enum ath10k_crypt_mode { + /* Only use hardware crypto engine */ + ATH10K_CRYPT_MODE_HW, + /* Only use software crypto engine */ + ATH10K_CRYPT_MODE_SW, +}; + static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) { switch (mode) { diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index edf6047997a7..1a33bf04b7b7 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -128,7 +128,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); - ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d features %s\n", + ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d features %s\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -144,6 +144,8 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->htt.op_version, ath10k_cal_mode_str(ar->cal_mode), ar->max_num_stations, + test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags), + !test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags), fw_features); ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", config_enabled(CONFIG_ATH10K_DEBUG), @@ -1363,12 +1365,8 @@ static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file, mutex_lock(&ar->conf_mutex); - if (ar->debug.htt_max_amsdu) - amsdu = ar->debug.htt_max_amsdu; - - if (ar->debug.htt_max_ampdu) - ampdu = ar->debug.htt_max_ampdu; - + amsdu = ar->htt.max_num_amsdu; + ampdu = ar->htt.max_num_ampdu; mutex_unlock(&ar->conf_mutex); len = scnprintf(buf, sizeof(buf), "%u %u\n", amsdu, ampdu); @@ -1402,8 +1400,8 @@ static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file, goto out; res = count; - ar->debug.htt_max_amsdu = amsdu; - ar->debug.htt_max_ampdu = ampdu; + ar->htt.max_num_amsdu = amsdu; + ar->htt.max_num_ampdu = ampdu; out: mutex_unlock(&ar->conf_mutex); @@ -1905,9 +1903,6 @@ void ath10k_debug_stop(struct ath10k *ar) if (ar->debug.htt_stats_mask != 0) cancel_delayed_work(&ar->debug.htt_stats_dwork); - ar->debug.htt_max_amsdu = 0; - ar->debug.htt_max_ampdu = 0; - ath10k_wmi_pdev_pktlog_disable(ar); } diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 4474c3e839db..3e6ba63dfdff 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -246,12 +246,31 @@ int ath10k_htt_setup(struct ath10k_htt *htt) } status = ath10k_htt_verify_version(htt); - if (status) + if (status) { + ath10k_warn(ar, "failed to verify htt version: %d\n", + status); return status; + } status = ath10k_htt_send_frag_desc_bank_cfg(htt); if (status) return status; - return ath10k_htt_send_rx_ring_cfg_ll(htt); + status = ath10k_htt_send_rx_ring_cfg_ll(htt); + if (status) { + ath10k_warn(ar, "failed to setup rx ring: %d\n", + status); + return status; + } + + status = ath10k_htt_h2t_aggr_cfg_msg(htt, + htt->max_num_ampdu, + htt->max_num_amsdu); + if (status) { + ath10k_warn(ar, "failed to setup amsdu/ampdu limit: %d\n", + status); + return status; + } + + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 7583a126e879..573187512895 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -1396,6 +1396,8 @@ struct ath10k_htt { u8 target_version_minor; struct completion target_version_received; enum ath10k_fw_htt_op_version op_version; + u8 max_num_amsdu; + u8 max_num_ampdu; const enum htt_t2h_msg_type *t2h_msg_types; u32 t2h_msg_types_max; @@ -1558,6 +1560,12 @@ struct htt_rx_desc { #define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */ #define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1) +/* These values are default in most firmware revisions and apparently are a + * sweet spot performance wise. + */ +#define ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT 3 +#define ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT 64 + int ath10k_htt_connect(struct ath10k_htt *htt); int ath10k_htt_init(struct ath10k *ar); int ath10k_htt_setup(struct ath10k_htt *htt); diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 5e54c393767e..1b7a04366256 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1017,9 +1017,8 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar, skb_trim(msdu, msdu->len - FCS_LEN); /* In most cases this will be true for sniffed frames. It makes sense - * to deliver them as-is without stripping the crypto param. This would - * also make sense for software based decryption (which is not - * implemented in ath10k). + * to deliver them as-is without stripping the crypto param. This is + * necessary for software based decryption. * * If there's no error then the frame is decrypted. At least that is * the case for frames that come in via fragmented rx indication. @@ -2066,6 +2065,8 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; case HTT_T2H_MSG_TYPE_CHAN_CHANGE: break; + case HTT_T2H_MSG_TYPE_AGGR_CONF: + break; case HTT_T2H_MSG_TYPE_EN_STATS: case HTT_T2H_MSG_TYPE_TX_FETCH_IND: case HTT_T2H_MSG_TYPE_TX_FETCH_CONF: diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 2c0627b7141b..81fd81f4df01 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -523,8 +523,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) if ((ieee80211_is_action(hdr->frame_control) || ieee80211_is_deauth(hdr->frame_control) || ieee80211_is_disassoc(hdr->frame_control)) && - ieee80211_has_protected(hdr->frame_control)) + ieee80211_has_protected(hdr->frame_control)) { skb_put(msdu, IEEE80211_CCMP_MIC_LEN); + } else if (!skb_cb->htt.nohwcrypt && + skb_cb->txmode == ATH10K_HW_TXRX_RAW) { + skb_put(msdu, IEEE80211_CCMP_MIC_LEN); + } skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, DMA_TO_DEVICE); @@ -595,12 +599,16 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) prefetch_len); skb_cb->htt.txbuf->htc_hdr.flags = 0; + if (skb_cb->htt.nohwcrypt) + flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; + if (!skb_cb->is_protected) flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); - if (msdu->ip_summed == CHECKSUM_PARTIAL) { + if (msdu->ip_summed == CHECKSUM_PARTIAL && + !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; if (ar->hw_params.continuous_frag_desc) diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 917228517546..7bfb9e276d17 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -217,14 +217,16 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, #define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0) /* Known pecularities: - * - current FW doesn't support raw rx mode (last tested v599) - * - current FW dumps upon raw tx mode (last tested v599) * - raw appears in nwifi decap, raw and nwifi appear in ethernet decap * - raw have FCS, nwifi doesn't * - ethernet frames have 802.11 header decapped and parts (base hdr, cipher * param, llc/snap) are aligned to 4byte boundaries each */ enum ath10k_hw_txrx_mode { ATH10K_HW_TXRX_RAW = 0, + + /* Native Wifi decap mode is used to align IP frames to 4-byte + * boundaries and avoid a very expensive re-alignment in mac80211. + */ ATH10K_HW_TXRX_NATIVE_WIFI = 1, ATH10K_HW_TXRX_ETHERNET = 2, @@ -286,10 +288,6 @@ enum ath10k_hw_rate_cck { #define TARGET_RX_TIMEOUT_LO_PRI 100 #define TARGET_RX_TIMEOUT_HI_PRI 40 -/* Native Wifi decap mode is used to align IP frames to 4-byte boundaries and - * avoid a very expensive re-alignment in mac80211. */ -#define TARGET_RX_DECAP_MODE ATH10K_HW_TXRX_NATIVE_WIFI - #define TARGET_SCAN_MAX_PENDING_REQS 4 #define TARGET_BMISS_OFFLOAD_MAX_VDEV 3 #define TARGET_ROAM_OFFLOAD_MAX_VDEV 3 @@ -324,7 +322,6 @@ enum ath10k_hw_rate_cck { #define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2)) #define TARGET_10X_RX_TIMEOUT_LO_PRI 100 #define TARGET_10X_RX_TIMEOUT_HI_PRI 40 -#define TARGET_10X_RX_DECAP_MODE ATH10K_HW_TXRX_NATIVE_WIFI #define TARGET_10X_SCAN_MAX_PENDING_REQS 4 #define TARGET_10X_BMISS_OFFLOAD_MAX_VDEV 2 #define TARGET_10X_ROAM_OFFLOAD_MAX_VDEV 2 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 49a54a1f07a8..acd222f3b899 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -197,6 +197,10 @@ static int ath10k_send_key(struct ath10k_vif *arvif, return -EOPNOTSUPP; } + if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + } + if (cmd == DISABLE_KEY) { arg.key_cipher = WMI_CIPHER_NONE; arg.key_data = NULL; @@ -218,6 +222,9 @@ static int ath10k_install_key(struct ath10k_vif *arvif, reinit_completion(&ar->install_key_done); + if (arvif->nohwcrypt) + return 1; + ret = ath10k_send_key(arvif, key, cmd, macaddr, flags); if (ret) return ret; @@ -256,7 +263,7 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, addr, flags); - if (ret) + if (ret < 0) return ret; flags = 0; @@ -264,7 +271,7 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif, ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY, addr, flags); - if (ret) + if (ret < 0) return ret; spin_lock_bh(&ar->data_lock); @@ -322,10 +329,10 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif, /* key flags are not required to delete the key */ ret = ath10k_install_key(arvif, peer->keys[i], DISABLE_KEY, addr, flags); - if (ret && first_errno == 0) + if (ret < 0 && first_errno == 0) first_errno = ret; - if (ret) + if (ret < 0) ath10k_warn(ar, "failed to remove peer wep key %d: %d\n", i, ret); @@ -398,7 +405,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif, break; /* key flags are not required to delete the key */ ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, flags); - if (ret && first_errno == 0) + if (ret < 0 && first_errno == 0) first_errno = ret; if (ret) @@ -3149,13 +3156,30 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif, * Some wmi-tlv firmwares for qca6174 have broken Tx key selection for * NativeWifi txmode - it selects AP key instead of peer key. It seems * to work with Ethernet txmode so use it. + * + * FIXME: Check if raw mode works with TDLS. */ if (ieee80211_is_data_present(fc) && sta && sta->tdls) return ATH10K_HW_TXRX_ETHERNET; + if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) + return ATH10K_HW_TXRX_RAW; + return ATH10K_HW_TXRX_NATIVE_WIFI; } +static bool ath10k_tx_h_use_hwcrypto(struct ieee80211_vif *vif, + struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + const u32 mask = IEEE80211_TX_INTFL_DONT_ENCRYPT | + IEEE80211_TX_CTL_INJECTED; + if ((info->flags & mask) == mask) + return false; + if (vif) + return !ath10k_vif_to_arvif(vif)->nohwcrypt; + return true; +} + /* HTT Tx uses Native Wifi tx mode which expects 802.11 frames without QoS * Control in the header. */ @@ -3600,6 +3624,7 @@ static void ath10k_tx(struct ieee80211_hw *hw, ATH10K_SKB_CB(skb)->htt.is_offchan = false; ATH10K_SKB_CB(skb)->htt.freq = 0; ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr); + ATH10K_SKB_CB(skb)->htt.nohwcrypt = !ath10k_tx_h_use_hwcrypto(vif, skb); ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif); ATH10K_SKB_CB(skb)->txmode = ath10k_tx_h_get_txmode(ar, vif, sta, skb); ATH10K_SKB_CB(skb)->is_protected = ieee80211_has_protected(fc); @@ -3615,12 +3640,11 @@ static void ath10k_tx(struct ieee80211_hw *hw, ath10k_tx_h_8023(skb); break; case ATH10K_HW_TXRX_RAW: - /* FIXME: Packet injection isn't implemented. It should be - * doable with firmware 10.2 on qca988x. - */ - WARN_ON_ONCE(1); - ieee80211_free_txskb(hw, skb); - return; + if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { + WARN_ON_ONCE(1); + ieee80211_free_txskb(hw, skb); + return; + } } if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { @@ -4139,6 +4163,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err; } } + if (test_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags)) + arvif->nohwcrypt = true; + + if (arvif->nohwcrypt && + !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { + ath10k_warn(ar, "cryptmode module param needed for sw crypto\n"); + goto err; + } ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n", arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, @@ -4728,6 +4760,9 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) return 1; + if (arvif->nohwcrypt) + return 1; + if (key->keyidx > WMI_MAX_KEY_INDEX) return -ENOSPC; @@ -4797,6 +4832,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags); if (ret) { + WARN_ON(ret > 0); ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n", arvif->vdev_id, peer_addr, ret); goto exit; @@ -4812,13 +4848,16 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = ath10k_install_key(arvif, key, cmd, peer_addr, flags2); if (ret) { + WARN_ON(ret > 0); ath10k_warn(ar, "failed to install (ucast) key for vdev %i peer %pM: %d\n", arvif->vdev_id, peer_addr, ret); ret2 = ath10k_install_key(arvif, key, DISABLE_KEY, peer_addr, flags); - if (ret2) + if (ret2) { + WARN_ON(ret2 > 0); ath10k_warn(ar, "failed to disable (mcast) key for vdev %i peer %pM: %d\n", arvif->vdev_id, peer_addr, ret2); + } goto exit; } } @@ -6892,7 +6931,6 @@ int ath10k_mac_register(struct ath10k *ar) ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL); ieee80211_hw_set(ar->hw, AP_LINK_PS); ieee80211_hw_set(ar->hw, SPECTRUM_MGMT); - ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(ar->hw, CONNECTION_MONITOR); ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK); @@ -6900,6 +6938,9 @@ int ath10k_mac_register(struct ath10k *ar) ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA); ieee80211_hw_set(ar->hw, QUEUE_CONTROL); + if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) + ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); + ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; @@ -7003,7 +7044,8 @@ int ath10k_mac_register(struct ath10k *ar) goto err_free; } - ar->hw->netdev_features = NETIF_F_HW_CSUM; + if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) + ar->hw->netdev_features = NETIF_F_HW_CSUM; if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { /* Init ath dfs pattern detector */ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 4189d4a90ce0..34fbc8fddb72 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1373,7 +1373,7 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cfg->rx_timeout_pri[1] = __cpu_to_le32(0x64); cfg->rx_timeout_pri[2] = __cpu_to_le32(0x64); cfg->rx_timeout_pri[3] = __cpu_to_le32(0x28); - cfg->rx_decap_mode = __cpu_to_le32(1); + cfg->rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode); cfg->scan_max_pending_reqs = __cpu_to_le32(4); cfg->bmiss_offload_max_vdev = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); cfg->roam_offload_max_vdev = __cpu_to_le32(TARGET_TLV_NUM_VDEVS); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 1435614b0a55..3d46813b9beb 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4688,8 +4688,7 @@ static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar) config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_be = __cpu_to_le32(TARGET_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_RX_TIMEOUT_HI_PRI); - config.rx_decap_mode = __cpu_to_le32(TARGET_RX_DECAP_MODE); - + config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode); config.scan_max_pending_reqs = __cpu_to_le32(TARGET_SCAN_MAX_PENDING_REQS); @@ -4757,8 +4756,7 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar) config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI); - config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE); - + config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode); config.scan_max_pending_reqs = __cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS); @@ -4823,7 +4821,7 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI); config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI); - config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE); + config.rx_decap_mode = __cpu_to_le32(ar->wmi.rx_decap_mode); config.scan_max_pending_reqs = __cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS); -- cgit v1.3-6-gb490 From 9f58582c7ad64f025e7fc582461c5bfafb46818f Mon Sep 17 00:00:00 2001 From: Hanno Böck Date: Wed, 29 Jul 2015 10:29:58 +0200 Subject: drm/i915: Properly sort MI coomand table In the future, we may want to speed up command/register searching using a bisection and so we require them to be in ascending order respectively by command value or register address. However, this was not true for one pair in the MI table; make it so. Signed-off-by: Hanno Boeck Reviewed-by: Chris Wilson [danvet: Hand-assemble patch from raw patch from Hanno and commit message from Chris.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 430571b977db..dc5d9b22cebc 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -151,8 +151,8 @@ static const struct drm_i915_cmd_descriptor render_cmds[] = { CMD( MI_ARB_ON_OFF, SMI, F, 1, R ), CMD( MI_PREDICATE, SMI, F, 1, S ), CMD( MI_TOPOLOGY_FILTER, SMI, F, 1, S ), - CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), CMD( MI_SET_APPID, SMI, F, 1, S ), + CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ), CMD( MI_SET_CONTEXT, SMI, !F, 0xFF, R ), CMD( MI_URB_CLEAR, SMI, !F, 0xFF, S ), CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3F, B, -- cgit v1.3-6-gb490 From 8453580cb8834dedffda86bcb64f13befc90eb03 Mon Sep 17 00:00:00 2001 From: Hanno Böck Date: Wed, 29 Jul 2015 10:31:04 +0200 Subject: drm/i915: Fix command parser table validator As we may like to use a bisection search on the tables in future, we need them to be ordered. For convenience we expect the compiled tables to be order and check on initialisation. However, the validator used the wrong iterators failed to spot the misordered MI tables and instead walked off into the unknown (as spotted by kasan). Signed-off-by: Hanno Boeck Reviewed-by: Chris Wilson [danvet: Again hand-assemble patch ...] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index dc5d9b22cebc..237ff6884a22 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -564,7 +564,7 @@ static bool validate_cmds_sorted(struct intel_engine_cs *ring, for (j = 0; j < table->count; j++) { const struct drm_i915_cmd_descriptor *desc = - &table->table[i]; + &table->table[j]; u32 curr = desc->cmd.value & desc->cmd.mask; if (curr < previous) { -- cgit v1.3-6-gb490 From c873d9aba7c9782b4dc74488ab964ed6cf54678f Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Thu, 23 Jul 2015 19:10:03 -0600 Subject: HID: hid-lg: Add USBID for Logitech G29 Wheel Since this wheel is now available, and the USBID is listed on their website, this patch adds it to allow the hid-lg4ff force feedback driver to find it. I do not have this wheel to test with, but this should at least get it working in emulation mode. Note: There is probably more work required for adjust HID descriptor and handle switching between emulation and native modes. Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-lg.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b04b0820d816..653bfd4b9490 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -599,6 +599,7 @@ #define USB_DEVICE_ID_LOGITECH_DUAL_ACTION 0xc216 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219 +#define USB_DEVICE_ID_LOGITECH_G29_WHEEL 0xc24f #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286 #define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287 diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 429340d809b5..5332fb7d072a 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -776,6 +776,8 @@ static const struct hid_device_id lg_devices[] = { .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2), .driver_data = LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL), + .driver_data = LG_FF4 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D), .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO), -- cgit v1.3-6-gb490 From 9a1d78a3780e0e37eeff11b377fc5fbb01446a36 Mon Sep 17 00:00:00 2001 From: Николай Кудрявцев Date: Tue, 21 Jul 2015 13:31:52 +0300 Subject: HID: chicony: Add support for Acer Aspire Switch 12 Acer Aspire Switch 12 keyboard Chicony's controller reports too big usage index on the 1st interface. The patch fixes the report. The work based on solution from drivers/hid/hid-holtek-mouse.c Bug report: https://bugzilla.kernel.org/show_bug.cgi?id=101721 Signed-off-by: Nicholas Kudriavtsev Signed-off-by: Jiri Kosina --- drivers/hid/hid-chicony.c | 26 ++++++++++++++++++++++++++ drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + 3 files changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c index b613d5a79684..bc3cec199fee 100644 --- a/drivers/hid/hid-chicony.c +++ b/drivers/hid/hid-chicony.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "hid-ids.h" @@ -57,10 +58,34 @@ static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi, return 1; } +static __u8 *ch_switch12_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + + if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { + /* Change usage maximum and logical maximum from 0x7fff to + * 0x2fff, so they don't exceed HID_MAX_USAGES */ + switch (hdev->product) { + case USB_DEVICE_ID_CHICONY_ACER_SWITCH12: + if (*rsize >= 128 && rdesc[64] == 0xff && rdesc[65] == 0x7f + && rdesc[69] == 0xff && rdesc[70] == 0x7f) { + hid_info(hdev, "Fixing up report descriptor\n"); + rdesc[65] = rdesc[70] = 0x2f; + } + break; + } + + } + return rdesc; +} + + static const struct hid_device_id ch_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) }, { } }; MODULE_DEVICE_TABLE(hid, ch_devices); @@ -68,6 +93,7 @@ MODULE_DEVICE_TABLE(hid, ch_devices); static struct hid_driver ch_driver = { .name = "chicony", .id_table = ch_devices, + .report_fixup = ch_switch12_report_fixup, .input_mapping = ch_input_mapping, }; module_hid_driver(ch_driver); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 157c62775053..a77d30388b4d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1804,6 +1804,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) }, { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b04b0820d816..7c712dff2ca1 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -230,6 +230,7 @@ #define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053 #define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123 #define USB_DEVICE_ID_CHICONY_AK1D 0x1125 +#define USB_DEVICE_ID_CHICONY_ACER_SWITCH12 0x1421 #define USB_VENDOR_ID_CHUNGHWAT 0x2247 #define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001 -- cgit v1.3-6-gb490 From 03f6199a359e460714b6bd08c10b566760f150a6 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Fri, 10 Jul 2015 15:37:25 -0400 Subject: nohz: Prevent tilegx network driver interrupts Normally the tilegx networking shim sends irqs to all the cores to distribute the load of processing incoming-packet interrupts, so that you can get to multiple Gb's of traffic inbound. However, in nohz_full mode we don't want to interrupt the nohz_full cores by default, so we limit the set of cores we use to only the online housekeeping cores. To make client code easier to read, we introduce a new nohz_full accessor, housekeeping_cpumask(), which returns a pointer to the housekeeping_mask if nohz_full is enabled, and otherwise returns the cpu_possible_mask. Signed-off-by: Chris Metcalf Cc: Christoph Lameter Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Preeti U Murthy Cc: Rik van Riel Cc: Thomas Gleixner Cc: Viresh Kumar Signed-off-by: Frederic Weisbecker --- drivers/net/ethernet/tile/tilegx.c | 4 +++- include/linux/tick.h | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index a3f7610002aa..0a15acc075b3 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -2273,7 +2274,8 @@ static int __init tile_net_init_module(void) tile_net_dev_init(name, mac); if (!network_cpus_init()) - network_cpus_map = *cpu_online_mask; + cpumask_and(&network_cpus_map, housekeeping_cpumask(), + cpu_online_mask); return 0; } diff --git a/include/linux/tick.h b/include/linux/tick.h index edbfc9a5293e..1ca93f2de6f5 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -163,6 +163,15 @@ static inline void tick_nohz_full_kick_all(void) { } static inline void __tick_nohz_task_switch(struct task_struct *tsk) { } #endif +static inline const struct cpumask *housekeeping_cpumask(void) +{ +#ifdef CONFIG_NO_HZ_FULL + if (tick_nohz_full_enabled()) + return housekeeping_mask; +#endif + return cpu_possible_mask; +} + static inline bool is_housekeeping_cpu(int cpu) { #ifdef CONFIG_NO_HZ_FULL -- cgit v1.3-6-gb490 From 011710e2ab659c7ad6e5e554806414bd7a9508be Mon Sep 17 00:00:00 2001 From: Sifan Naeem Date: Mon, 27 Jul 2015 13:11:15 +0100 Subject: spi: img-spfi: check for timeout error before proceeding Calling spfi_wait_all_done is not required if the transfer has timed out before all data is transferred. spfi_wait_all_done polls for Alldone interrupt which is triggered to mark the transfer as complete and to indicate it is now safe to issue a new transfer. Fixes: 8c2c8c0 ("spi: img-spfi: Control CS lines with GPIO") Signed-off-by: Sifan Naeem Reviewed-by: Andrew Bresticker Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-img-spfi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index 788e2b176a4f..83b97418fc8d 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -266,15 +266,15 @@ static int img_spfi_start_pio(struct spi_master *master, cpu_relax(); } - ret = spfi_wait_all_done(spfi); - if (ret < 0) - return ret; - if (rx_bytes > 0 || tx_bytes > 0) { dev_err(spfi->dev, "PIO transfer timed out\n"); return -ETIMEDOUT; } + ret = spfi_wait_all_done(spfi); + if (ret < 0) + return ret; + return 0; } -- cgit v1.3-6-gb490 From b10c7f3cc948107fb992d3a14eeaa0fdfb5c95da Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Tue, 28 Jul 2015 11:34:11 +0300 Subject: regulator: max8973: Set VSEL regmap ops if DVS GPIO is not set Use regmap helpers for get_voltage_sel and set_voltage_sel ops if the DVS GPIO is not set. The DVS GPIO allows on the fly selection of the VSEL register from two choices. However, if it is not set, the VSEL register will stay fixed and we can use the regmap ops. This allows use of the *hardware_vsel* regulator APIs. Signed-off-by: Mikko Perttunen Signed-off-by: Mark Brown --- drivers/regulator/max8973-regulator.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index f67365962b67..8857cc02d9a8 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -637,6 +637,15 @@ static int max8973_probe(struct i2c_client *client, max->lru_index[i] = i; max->lru_index[0] = max->curr_vout_reg; max->lru_index[max->curr_vout_reg] = 0; + } else { + /* + * If there is no DVS GPIO, the VOUT register + * address is fixed. + */ + max->ops.set_voltage_sel = regulator_set_voltage_sel_regmap; + max->ops.get_voltage_sel = regulator_get_voltage_sel_regmap; + max->desc.vsel_reg = max->curr_vout_reg; + max->desc.vsel_mask = MAX8973_VOUT_MASK; } if (pdata_from_dt) -- cgit v1.3-6-gb490 From 26a67ec47a4c58fe79c6421c3dc3d697d322d2d6 Mon Sep 17 00:00:00 2001 From: Lars Persson Date: Wed, 29 Jul 2015 09:32:02 +0200 Subject: spi: Fix regression in spi-bitbang-txrx.h This patch fixes a regression introduced by commit 232a5adc5199 ("spi: bitbang: only toggle bitchanges"). The attempt to optimize writes of consecutive bit patterns broke most of the combinations of word size and SPI modes due to selecting the wrong bit as the MSB value. Fixes: 232a5adc5199 (spi: bitbang: only toggle bitchanges) Signed-off-by: Lars Persson Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-bitbang-txrx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-bitbang-txrx.h b/drivers/spi/spi-bitbang-txrx.h index 06b34e5bcfa3..47bb9b898dfd 100644 --- a/drivers/spi/spi-bitbang-txrx.h +++ b/drivers/spi/spi-bitbang-txrx.h @@ -49,7 +49,7 @@ bitbang_txrx_be_cpha0(struct spi_device *spi, { /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */ - bool oldbit = !(word & 1); + u32 oldbit = (!(word & (1<<(bits-1)))) << 31; /* clock starts at inactive polarity */ for (word <<= (32 - bits); likely(bits); bits--) { @@ -81,7 +81,7 @@ bitbang_txrx_be_cpha1(struct spi_device *spi, { /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */ - bool oldbit = !(word & (1 << 31)); + u32 oldbit = (!(word & (1<<(bits-1)))) << 31; /* clock starts at inactive polarity */ for (word <<= (32 - bits); likely(bits); bits--) { -- cgit v1.3-6-gb490 From 4246a0b63bd8f56a1469b12eafeb875b1041a451 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 20 Jul 2015 15:29:37 +0200 Subject: block: add a bi_error field to struct bio Currently we have two different ways to signal an I/O error on a BIO: (1) by clearing the BIO_UPTODATE flag (2) by returning a Linux errno value to the bi_end_io callback The first one has the drawback of only communicating a single possible error (-EIO), and the second one has the drawback of not beeing persistent when bios are queued up, and are not passed along from child to parent bio in the ever more popular chaining scenario. Having both mechanisms available has the additional drawback of utterly confusing driver authors and introducing bugs where various I/O submitters only deal with one of them, and the others have to add boilerplate code to deal with both kinds of error returns. So add a new bi_error field to store an errno value directly in struct bio and remove the existing mechanisms to clean all this up. Signed-off-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Reviewed-by: NeilBrown Signed-off-by: Jens Axboe --- Documentation/block/biodoc.txt | 2 +- arch/m68k/emu/nfblock.c | 2 +- arch/powerpc/sysdev/axonram.c | 2 +- arch/xtensa/platforms/iss/simdisk.c | 12 ++----- block/bio-integrity.c | 11 +++---- block/bio.c | 43 +++++++++++-------------- block/blk-core.c | 15 ++++----- block/blk-lib.c | 30 ++++++++---------- block/blk-map.c | 2 +- block/blk-mq.c | 6 ++-- block/bounce.c | 27 ++++++++-------- drivers/block/aoe/aoecmd.c | 10 +++--- drivers/block/aoe/aoedev.c | 2 +- drivers/block/brd.c | 13 +++++--- drivers/block/drbd/drbd_actlog.c | 4 +-- drivers/block/drbd/drbd_bitmap.c | 19 +++--------- drivers/block/drbd/drbd_int.h | 11 ++++--- drivers/block/drbd/drbd_req.c | 10 +++--- drivers/block/drbd/drbd_worker.c | 44 +++++++------------------- drivers/block/floppy.c | 7 +++-- drivers/block/null_blk.c | 2 +- drivers/block/pktcdvd.c | 32 +++++++++---------- drivers/block/ps3vram.c | 3 +- drivers/block/rsxx/dev.c | 9 ++++-- drivers/block/umem.c | 4 +-- drivers/block/xen-blkback/blkback.c | 4 +-- drivers/block/xen-blkfront.c | 9 ++---- drivers/block/zram/zram_drv.c | 5 ++- drivers/md/bcache/btree.c | 10 +++--- drivers/md/bcache/closure.h | 2 +- drivers/md/bcache/io.c | 8 ++--- drivers/md/bcache/journal.c | 8 ++--- drivers/md/bcache/movinggc.c | 8 ++--- drivers/md/bcache/request.c | 27 ++++++++-------- drivers/md/bcache/super.c | 14 ++++----- drivers/md/bcache/writeback.c | 10 +++--- drivers/md/dm-bio-prison.c | 6 ++-- drivers/md/dm-bufio.c | 26 ++++++++++------ drivers/md/dm-cache-target.c | 24 +++++++------- drivers/md/dm-crypt.c | 14 ++++----- drivers/md/dm-flakey.c | 2 +- drivers/md/dm-io.c | 6 ++-- drivers/md/dm-log-writes.c | 11 +++---- drivers/md/dm-raid1.c | 24 +++++++------- drivers/md/dm-snap.c | 6 ++-- drivers/md/dm-stripe.c | 2 +- drivers/md/dm-thin.c | 41 +++++++++++++----------- drivers/md/dm-verity.c | 9 +++--- drivers/md/dm-zero.c | 2 +- drivers/md/dm.c | 15 +++++---- drivers/md/faulty.c | 4 +-- drivers/md/linear.c | 2 +- drivers/md/md.c | 18 +++++------ drivers/md/multipath.c | 12 +++---- drivers/md/raid0.c | 2 +- drivers/md/raid1.c | 53 ++++++++++++++++--------------- drivers/md/raid10.c | 55 +++++++++++++++----------------- drivers/md/raid5.c | 52 +++++++++++++++---------------- drivers/nvdimm/blk.c | 5 +-- drivers/nvdimm/btt.c | 5 +-- drivers/nvdimm/pmem.c | 2 +- drivers/s390/block/dcssblk.c | 2 +- drivers/s390/block/xpram.c | 3 +- drivers/target/target_core_iblock.c | 21 +++++-------- drivers/target/target_core_pscsi.c | 6 ++-- fs/btrfs/check-integrity.c | 10 +++--- fs/btrfs/compression.c | 24 ++++++++------ fs/btrfs/disk-io.c | 35 +++++++++++---------- fs/btrfs/extent_io.c | 30 +++++++----------- fs/btrfs/inode.c | 50 ++++++++++++++++-------------- fs/btrfs/raid56.c | 62 +++++++++++++++++-------------------- fs/btrfs/scrub.c | 22 ++++++------- fs/btrfs/volumes.c | 23 +++++++------- fs/buffer.c | 4 +-- fs/direct-io.c | 13 ++++---- fs/ext4/page-io.c | 15 ++++----- fs/ext4/readpage.c | 6 ++-- fs/f2fs/data.c | 10 +++--- fs/gfs2/lops.c | 10 +++--- fs/gfs2/ops_fstype.c | 6 ++-- fs/jfs/jfs_logmgr.c | 8 ++--- fs/jfs/jfs_metapage.c | 8 ++--- fs/logfs/dev_bdev.c | 12 +++---- fs/mpage.c | 4 +-- fs/nfs/blocklayout/blocklayout.c | 14 ++++----- fs/nilfs2/segbuf.c | 5 ++- fs/ocfs2/cluster/heartbeat.c | 9 +++--- fs/xfs/xfs_aops.c | 5 ++- fs/xfs/xfs_buf.c | 7 ++--- include/linux/bio.h | 13 +++++--- include/linux/blk_types.h | 4 +-- include/linux/swap.h | 4 +-- kernel/power/swap.c | 12 +++---- kernel/trace/blktrace.c | 10 ++---- mm/page_io.c | 12 +++---- 95 files changed, 622 insertions(+), 682 deletions(-) (limited to 'drivers') diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index fd12c0d835fd..5be8a7f4cc7f 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -1109,7 +1109,7 @@ it will loop and handle as many sectors (on a bio-segment granularity) as specified. Now bh->b_end_io is replaced by bio->bi_end_io, but most of the time the -right thing to use is bio_endio(bio, uptodate) instead. +right thing to use is bio_endio(bio) instead. If the driver is dropping the io_request_lock from its request_fn strategy, then it just needs to replace that with q->queue_lock instead. diff --git a/arch/m68k/emu/nfblock.c b/arch/m68k/emu/nfblock.c index 2d75ae246167..f2a00c591bf7 100644 --- a/arch/m68k/emu/nfblock.c +++ b/arch/m68k/emu/nfblock.c @@ -76,7 +76,7 @@ static void nfhd_make_request(struct request_queue *queue, struct bio *bio) bvec_to_phys(&bvec)); sec += len; } - bio_endio(bio, 0); + bio_endio(bio); } static int nfhd_getgeo(struct block_device *bdev, struct hd_geometry *geo) diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index ee90db17b097..f86250c48b53 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -132,7 +132,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) phys_mem += vec.bv_len; transfered += vec.bv_len; } - bio_endio(bio, 0); + bio_endio(bio); } /** diff --git a/arch/xtensa/platforms/iss/simdisk.c b/arch/xtensa/platforms/iss/simdisk.c index 48eebacdf5fe..fa84ca990caa 100644 --- a/arch/xtensa/platforms/iss/simdisk.c +++ b/arch/xtensa/platforms/iss/simdisk.c @@ -101,8 +101,9 @@ static void simdisk_transfer(struct simdisk *dev, unsigned long sector, spin_unlock(&dev->lock); } -static int simdisk_xfer_bio(struct simdisk *dev, struct bio *bio) +static void simdisk_make_request(struct request_queue *q, struct bio *bio) { + struct simdisk *dev = q->queuedata; struct bio_vec bvec; struct bvec_iter iter; sector_t sector = bio->bi_iter.bi_sector; @@ -116,17 +117,10 @@ static int simdisk_xfer_bio(struct simdisk *dev, struct bio *bio) sector += len; __bio_kunmap_atomic(buffer); } - return 0; -} -static void simdisk_make_request(struct request_queue *q, struct bio *bio) -{ - struct simdisk *dev = q->queuedata; - int status = simdisk_xfer_bio(dev, bio); - bio_endio(bio, status); + bio_endio(bio); } - static int simdisk_open(struct block_device *bdev, fmode_t mode) { struct simdisk *dev = bdev->bd_disk->private_data; diff --git a/block/bio-integrity.c b/block/bio-integrity.c index 719b7152aed1..4aecca79374a 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -355,13 +355,12 @@ static void bio_integrity_verify_fn(struct work_struct *work) container_of(work, struct bio_integrity_payload, bip_work); struct bio *bio = bip->bip_bio; struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - int error; - error = bio_integrity_process(bio, bi->verify_fn); + bio->bi_error = bio_integrity_process(bio, bi->verify_fn); /* Restore original bio completion handler */ bio->bi_end_io = bip->bip_end_io; - bio_endio(bio, error); + bio_endio(bio); } /** @@ -376,7 +375,7 @@ static void bio_integrity_verify_fn(struct work_struct *work) * in process context. This function postpones completion * accordingly. */ -void bio_integrity_endio(struct bio *bio, int error) +void bio_integrity_endio(struct bio *bio) { struct bio_integrity_payload *bip = bio_integrity(bio); @@ -386,9 +385,9 @@ void bio_integrity_endio(struct bio *bio, int error) * integrity metadata. Restore original bio end_io handler * and run it. */ - if (error) { + if (bio->bi_error) { bio->bi_end_io = bip->bip_end_io; - bio_endio(bio, error); + bio_endio(bio); return; } diff --git a/block/bio.c b/block/bio.c index 2a00d349cd68..a23f489f398f 100644 --- a/block/bio.c +++ b/block/bio.c @@ -269,7 +269,6 @@ static void bio_free(struct bio *bio) void bio_init(struct bio *bio) { memset(bio, 0, sizeof(*bio)); - bio->bi_flags = 1 << BIO_UPTODATE; atomic_set(&bio->__bi_remaining, 1); atomic_set(&bio->__bi_cnt, 1); } @@ -292,14 +291,17 @@ void bio_reset(struct bio *bio) __bio_free(bio); memset(bio, 0, BIO_RESET_BYTES); - bio->bi_flags = flags | (1 << BIO_UPTODATE); + bio->bi_flags = flags; atomic_set(&bio->__bi_remaining, 1); } EXPORT_SYMBOL(bio_reset); -static void bio_chain_endio(struct bio *bio, int error) +static void bio_chain_endio(struct bio *bio) { - bio_endio(bio->bi_private, error); + struct bio *parent = bio->bi_private; + + parent->bi_error = bio->bi_error; + bio_endio(parent); bio_put(bio); } @@ -896,11 +898,11 @@ struct submit_bio_ret { int error; }; -static void submit_bio_wait_endio(struct bio *bio, int error) +static void submit_bio_wait_endio(struct bio *bio) { struct submit_bio_ret *ret = bio->bi_private; - ret->error = error; + ret->error = bio->bi_error; complete(&ret->event); } @@ -1445,7 +1447,7 @@ void bio_unmap_user(struct bio *bio) } EXPORT_SYMBOL(bio_unmap_user); -static void bio_map_kern_endio(struct bio *bio, int err) +static void bio_map_kern_endio(struct bio *bio) { bio_put(bio); } @@ -1501,13 +1503,13 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len, } EXPORT_SYMBOL(bio_map_kern); -static void bio_copy_kern_endio(struct bio *bio, int err) +static void bio_copy_kern_endio(struct bio *bio) { bio_free_pages(bio); bio_put(bio); } -static void bio_copy_kern_endio_read(struct bio *bio, int err) +static void bio_copy_kern_endio_read(struct bio *bio) { char *p = bio->bi_private; struct bio_vec *bvec; @@ -1518,7 +1520,7 @@ static void bio_copy_kern_endio_read(struct bio *bio, int err) p += bvec->bv_len; } - bio_copy_kern_endio(bio, err); + bio_copy_kern_endio(bio); } /** @@ -1778,25 +1780,15 @@ static inline bool bio_remaining_done(struct bio *bio) /** * bio_endio - end I/O on a bio * @bio: bio - * @error: error, if any * * Description: - * bio_endio() will end I/O on the whole bio. bio_endio() is the - * preferred way to end I/O on a bio, it takes care of clearing - * BIO_UPTODATE on error. @error is 0 on success, and and one of the - * established -Exxxx (-EIO, for instance) error values in case - * something went wrong. No one should call bi_end_io() directly on a - * bio unless they own it and thus know that it has an end_io - * function. + * bio_endio() will end I/O on the whole bio. bio_endio() is the preferred + * way to end I/O on a bio. No one should call bi_end_io() directly on a + * bio unless they own it and thus know that it has an end_io function. **/ -void bio_endio(struct bio *bio, int error) +void bio_endio(struct bio *bio) { while (bio) { - if (error) - clear_bit(BIO_UPTODATE, &bio->bi_flags); - else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) - error = -EIO; - if (unlikely(!bio_remaining_done(bio))) break; @@ -1810,11 +1802,12 @@ void bio_endio(struct bio *bio, int error) */ if (bio->bi_end_io == bio_chain_endio) { struct bio *parent = bio->bi_private; + parent->bi_error = bio->bi_error; bio_put(bio); bio = parent; } else { if (bio->bi_end_io) - bio->bi_end_io(bio, error); + bio->bi_end_io(bio); bio = NULL; } } diff --git a/block/blk-core.c b/block/blk-core.c index 627ed0c593fb..7ef15b947b91 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -143,9 +143,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio, unsigned int nbytes, int error) { if (error) - clear_bit(BIO_UPTODATE, &bio->bi_flags); - else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) - error = -EIO; + bio->bi_error = error; if (unlikely(rq->cmd_flags & REQ_QUIET)) set_bit(BIO_QUIET, &bio->bi_flags); @@ -154,7 +152,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio, /* don't actually finish bio if it's part of flush sequence */ if (bio->bi_iter.bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ)) - bio_endio(bio, error); + bio_endio(bio); } void blk_dump_rq_flags(struct request *rq, char *msg) @@ -1620,7 +1618,8 @@ static void blk_queue_bio(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - bio_endio(bio, -EIO); + bio->bi_error = -EIO; + bio_endio(bio); return; } @@ -1673,7 +1672,8 @@ get_rq: */ req = get_request(q, rw_flags, bio, GFP_NOIO); if (IS_ERR(req)) { - bio_endio(bio, PTR_ERR(req)); /* @q is dead */ + bio->bi_error = PTR_ERR(req); + bio_endio(bio); goto out_unlock; } @@ -1896,7 +1896,8 @@ generic_make_request_checks(struct bio *bio) return true; end_io: - bio_endio(bio, err); + bio->bi_error = err; + bio_endio(bio); return false; } diff --git a/block/blk-lib.c b/block/blk-lib.c index 7688ee3f5d72..6dee17443f14 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -11,16 +11,16 @@ struct bio_batch { atomic_t done; - unsigned long flags; + int error; struct completion *wait; }; -static void bio_batch_end_io(struct bio *bio, int err) +static void bio_batch_end_io(struct bio *bio) { struct bio_batch *bb = bio->bi_private; - if (err && (err != -EOPNOTSUPP)) - clear_bit(BIO_UPTODATE, &bb->flags); + if (bio->bi_error && bio->bi_error != -EOPNOTSUPP) + bb->error = bio->bi_error; if (atomic_dec_and_test(&bb->done)) complete(bb->wait); bio_put(bio); @@ -78,7 +78,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, } atomic_set(&bb.done, 1); - bb.flags = 1 << BIO_UPTODATE; + bb.error = 0; bb.wait = &wait; blk_start_plug(&plug); @@ -134,9 +134,8 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, if (!atomic_dec_and_test(&bb.done)) wait_for_completion_io(&wait); - if (!test_bit(BIO_UPTODATE, &bb.flags)) - ret = -EIO; - + if (bb.error) + return bb.error; return ret; } EXPORT_SYMBOL(blkdev_issue_discard); @@ -172,7 +171,7 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, return -EOPNOTSUPP; atomic_set(&bb.done, 1); - bb.flags = 1 << BIO_UPTODATE; + bb.error = 0; bb.wait = &wait; while (nr_sects) { @@ -208,9 +207,8 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, if (!atomic_dec_and_test(&bb.done)) wait_for_completion_io(&wait); - if (!test_bit(BIO_UPTODATE, &bb.flags)) - ret = -ENOTSUPP; - + if (bb.error) + return bb.error; return ret; } EXPORT_SYMBOL(blkdev_issue_write_same); @@ -236,7 +234,7 @@ static int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, DECLARE_COMPLETION_ONSTACK(wait); atomic_set(&bb.done, 1); - bb.flags = 1 << BIO_UPTODATE; + bb.error = 0; bb.wait = &wait; ret = 0; @@ -270,10 +268,8 @@ static int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, if (!atomic_dec_and_test(&bb.done)) wait_for_completion_io(&wait); - if (!test_bit(BIO_UPTODATE, &bb.flags)) - /* One of bios in the batch was completed with error.*/ - ret = -EIO; - + if (bb.error) + return bb.error; return ret; } diff --git a/block/blk-map.c b/block/blk-map.c index da310a105429..5fe1c30bfba7 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -103,7 +103,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, * normal IO completion path */ bio_get(bio); - bio_endio(bio, 0); + bio_endio(bio); __blk_rq_unmap_user(bio); return -EINVAL; } diff --git a/block/blk-mq.c b/block/blk-mq.c index 7d842db59699..94559025c5e6 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1199,7 +1199,7 @@ static struct request *blk_mq_map_request(struct request_queue *q, struct blk_mq_alloc_data alloc_data; if (unlikely(blk_mq_queue_enter(q, GFP_KERNEL))) { - bio_endio(bio, -EIO); + bio_io_error(bio); return NULL; } @@ -1283,7 +1283,7 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - bio_endio(bio, -EIO); + bio_io_error(bio); return; } @@ -1368,7 +1368,7 @@ static void blk_sq_make_request(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - bio_endio(bio, -EIO); + bio_io_error(bio); return; } diff --git a/block/bounce.c b/block/bounce.c index b17311227c12..f4db245b9f3a 100644 --- a/block/bounce.c +++ b/block/bounce.c @@ -123,7 +123,7 @@ static void copy_to_high_bio_irq(struct bio *to, struct bio *from) } } -static void bounce_end_io(struct bio *bio, mempool_t *pool, int err) +static void bounce_end_io(struct bio *bio, mempool_t *pool) { struct bio *bio_orig = bio->bi_private; struct bio_vec *bvec, *org_vec; @@ -141,39 +141,40 @@ static void bounce_end_io(struct bio *bio, mempool_t *pool, int err) mempool_free(bvec->bv_page, pool); } - bio_endio(bio_orig, err); + bio_orig->bi_error = bio->bi_error; + bio_endio(bio_orig); bio_put(bio); } -static void bounce_end_io_write(struct bio *bio, int err) +static void bounce_end_io_write(struct bio *bio) { - bounce_end_io(bio, page_pool, err); + bounce_end_io(bio, page_pool); } -static void bounce_end_io_write_isa(struct bio *bio, int err) +static void bounce_end_io_write_isa(struct bio *bio) { - bounce_end_io(bio, isa_page_pool, err); + bounce_end_io(bio, isa_page_pool); } -static void __bounce_end_io_read(struct bio *bio, mempool_t *pool, int err) +static void __bounce_end_io_read(struct bio *bio, mempool_t *pool) { struct bio *bio_orig = bio->bi_private; - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) + if (!bio->bi_error) copy_to_high_bio_irq(bio_orig, bio); - bounce_end_io(bio, pool, err); + bounce_end_io(bio, pool); } -static void bounce_end_io_read(struct bio *bio, int err) +static void bounce_end_io_read(struct bio *bio) { - __bounce_end_io_read(bio, page_pool, err); + __bounce_end_io_read(bio, page_pool); } -static void bounce_end_io_read_isa(struct bio *bio, int err) +static void bounce_end_io_read_isa(struct bio *bio) { - __bounce_end_io_read(bio, isa_page_pool, err); + __bounce_end_io_read(bio, isa_page_pool); } #ifdef CONFIG_NEED_BOUNCE_POOL diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 422b7d84f686..ad80c85e0857 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -1110,7 +1110,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) d->ip.rq = NULL; do { bio = rq->bio; - bok = !fastfail && test_bit(BIO_UPTODATE, &bio->bi_flags); + bok = !fastfail && !bio->bi_error; } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_iter.bi_size)); /* cf. http://lkml.org/lkml/2006/10/31/28 */ @@ -1172,7 +1172,7 @@ ktiocomplete(struct frame *f) ahout->cmdstat, ahin->cmdstat, d->aoemajor, d->aoeminor); noskb: if (buf) - clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + buf->bio->bi_error = -EIO; goto out; } @@ -1185,7 +1185,7 @@ noskb: if (buf) "aoe: runt data size in read from", (long) d->aoemajor, d->aoeminor, skb->len, n); - clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + buf->bio->bi_error = -EIO; break; } if (n > f->iter.bi_size) { @@ -1193,7 +1193,7 @@ noskb: if (buf) "aoe: too-large data size in read from", (long) d->aoemajor, d->aoeminor, n, f->iter.bi_size); - clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + buf->bio->bi_error = -EIO; break; } bvcpy(skb, f->buf->bio, f->iter, n); @@ -1695,7 +1695,7 @@ aoe_failbuf(struct aoedev *d, struct buf *buf) if (buf == NULL) return; buf->iter.bi_size = 0; - clear_bit(BIO_UPTODATE, &buf->bio->bi_flags); + buf->bio->bi_error = -EIO; if (buf->nframesout == 0) aoe_end_buf(d, buf); } diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index e774c50b6842..ffd1947500c6 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -170,7 +170,7 @@ aoe_failip(struct aoedev *d) if (rq == NULL) return; while ((bio = d->ip.nxbio)) { - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; d->ip.nxbio = bio->bi_next; n = (unsigned long) rq->special; rq->special = (void *) --n; diff --git a/drivers/block/brd.c b/drivers/block/brd.c index e573e470bd8a..f9ab74505e69 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -331,14 +331,12 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) struct bio_vec bvec; sector_t sector; struct bvec_iter iter; - int err = -EIO; sector = bio->bi_iter.bi_sector; if (bio_end_sector(bio) > get_capacity(bdev->bd_disk)) - goto out; + goto io_error; if (unlikely(bio->bi_rw & REQ_DISCARD)) { - err = 0; discard_from_brd(brd, sector, bio->bi_iter.bi_size); goto out; } @@ -349,15 +347,20 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) bio_for_each_segment(bvec, bio, iter) { unsigned int len = bvec.bv_len; + int err; + err = brd_do_bvec(brd, bvec.bv_page, len, bvec.bv_offset, rw, sector); if (err) - break; + goto io_error; sector += len >> SECTOR_SHIFT; } out: - bio_endio(bio, err); + bio_endio(bio); + return; +io_error: + bio_io_error(bio); } static int brd_rw_page(struct block_device *bdev, sector_t sector, diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 1318e3217cb0..b3868e7a1ffd 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -175,11 +175,11 @@ static int _drbd_md_sync_page_io(struct drbd_device *device, atomic_inc(&device->md_io.in_use); /* drbd_md_put_buffer() is in the completion handler */ device->md_io.submit_jif = jiffies; if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) - bio_endio(bio, -EIO); + bio_io_error(bio); else submit_bio(rw, bio); wait_until_done_or_force_detached(device, bdev, &device->md_io.done); - if (bio_flagged(bio, BIO_UPTODATE)) + if (!bio->bi_error) err = device->md_io.error; out: diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 434c77dcc99e..e5e0f19ceda0 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -941,36 +941,27 @@ static void drbd_bm_aio_ctx_destroy(struct kref *kref) } /* bv_page may be a copy, or may be the original */ -static void drbd_bm_endio(struct bio *bio, int error) +static void drbd_bm_endio(struct bio *bio) { struct drbd_bm_aio_ctx *ctx = bio->bi_private; struct drbd_device *device = ctx->device; struct drbd_bitmap *b = device->bitmap; unsigned int idx = bm_page_to_idx(bio->bi_io_vec[0].bv_page); - int uptodate = bio_flagged(bio, BIO_UPTODATE); - - - /* strange behavior of some lower level drivers... - * fail the request by clearing the uptodate flag, - * but do not return any error?! - * do we want to WARN() on this? */ - if (!error && !uptodate) - error = -EIO; if ((ctx->flags & BM_AIO_COPY_PAGES) == 0 && !bm_test_page_unchanged(b->bm_pages[idx])) drbd_warn(device, "bitmap page idx %u changed during IO!\n", idx); - if (error) { + if (bio->bi_error) { /* ctx error will hold the completed-last non-zero error code, * in case error codes differ. */ - ctx->error = error; + ctx->error = bio->bi_error; bm_set_page_io_err(b->bm_pages[idx]); /* Not identical to on disk version of it. * Is BM_PAGE_IO_ERROR enough? */ if (__ratelimit(&drbd_ratelimit_state)) drbd_err(device, "IO ERROR %d on bitmap page idx %u\n", - error, idx); + bio->bi_error, idx); } else { bm_clear_page_io_err(b->bm_pages[idx]); dynamic_drbd_dbg(device, "bitmap page idx %u completed\n", idx); @@ -1031,7 +1022,7 @@ static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_ho if (drbd_insert_fault(device, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) { bio->bi_rw |= rw; - bio_endio(bio, -EIO); + bio_io_error(bio); } else { submit_bio(rw, bio); /* this should not count as user activity and cause the diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index efd19c2da9c2..a08c4a9179f1 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1481,9 +1481,9 @@ extern int drbd_khelper(struct drbd_device *device, char *cmd); /* drbd_worker.c */ /* bi_end_io handlers */ -extern void drbd_md_endio(struct bio *bio, int error); -extern void drbd_peer_request_endio(struct bio *bio, int error); -extern void drbd_request_endio(struct bio *bio, int error); +extern void drbd_md_endio(struct bio *bio); +extern void drbd_peer_request_endio(struct bio *bio); +extern void drbd_request_endio(struct bio *bio); extern int drbd_worker(struct drbd_thread *thi); enum drbd_ret_code drbd_resync_after_valid(struct drbd_device *device, int o_minor); void drbd_resync_after_changed(struct drbd_device *device); @@ -1604,12 +1604,13 @@ static inline void drbd_generic_make_request(struct drbd_device *device, __release(local); if (!bio->bi_bdev) { drbd_err(device, "drbd_generic_make_request: bio->bi_bdev == NULL\n"); - bio_endio(bio, -ENODEV); + bio->bi_error = -ENODEV; + bio_endio(bio); return; } if (drbd_insert_fault(device, fault_type)) - bio_endio(bio, -EIO); + bio_io_error(bio); else generic_make_request(bio); } diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 3907202fb9d9..9cb41166366e 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -201,7 +201,8 @@ void start_new_tl_epoch(struct drbd_connection *connection) void complete_master_bio(struct drbd_device *device, struct bio_and_error *m) { - bio_endio(m->bio, m->error); + m->bio->bi_error = m->error; + bio_endio(m->bio); dec_ap_bio(device); } @@ -1153,12 +1154,12 @@ drbd_submit_req_private_bio(struct drbd_request *req) rw == WRITE ? DRBD_FAULT_DT_WR : rw == READ ? DRBD_FAULT_DT_RD : DRBD_FAULT_DT_RA)) - bio_endio(bio, -EIO); + bio_io_error(bio); else generic_make_request(bio); put_ldev(device); } else - bio_endio(bio, -EIO); + bio_io_error(bio); } static void drbd_queue_write(struct drbd_device *device, struct drbd_request *req) @@ -1191,7 +1192,8 @@ drbd_request_prepare(struct drbd_device *device, struct bio *bio, unsigned long /* only pass the error to the upper layers. * if user cannot handle io errors, that's not our business. */ drbd_err(device, "could not kmalloc() req\n"); - bio_endio(bio, -ENOMEM); + bio->bi_error = -ENOMEM; + bio_endio(bio); return ERR_PTR(-ENOMEM); } req->start_jif = start_jif; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index d0fae55d871d..5578c1477ba6 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -65,12 +65,12 @@ rwlock_t global_state_lock; /* used for synchronous meta data and bitmap IO * submitted by drbd_md_sync_page_io() */ -void drbd_md_endio(struct bio *bio, int error) +void drbd_md_endio(struct bio *bio) { struct drbd_device *device; device = bio->bi_private; - device->md_io.error = error; + device->md_io.error = bio->bi_error; /* We grabbed an extra reference in _drbd_md_sync_page_io() to be able * to timeout on the lower level device, and eventually detach from it. @@ -170,31 +170,20 @@ void drbd_endio_write_sec_final(struct drbd_peer_request *peer_req) __releases(l /* writes on behalf of the partner, or resync writes, * "submitted" by the receiver. */ -void drbd_peer_request_endio(struct bio *bio, int error) +void drbd_peer_request_endio(struct bio *bio) { struct drbd_peer_request *peer_req = bio->bi_private; struct drbd_device *device = peer_req->peer_device->device; - int uptodate = bio_flagged(bio, BIO_UPTODATE); int is_write = bio_data_dir(bio) == WRITE; int is_discard = !!(bio->bi_rw & REQ_DISCARD); - if (error && __ratelimit(&drbd_ratelimit_state)) + if (bio->bi_error && __ratelimit(&drbd_ratelimit_state)) drbd_warn(device, "%s: error=%d s=%llus\n", is_write ? (is_discard ? "discard" : "write") - : "read", error, + : "read", bio->bi_error, (unsigned long long)peer_req->i.sector); - if (!error && !uptodate) { - if (__ratelimit(&drbd_ratelimit_state)) - drbd_warn(device, "%s: setting error to -EIO s=%llus\n", - is_write ? "write" : "read", - (unsigned long long)peer_req->i.sector); - /* strange behavior of some lower level drivers... - * fail the request by clearing the uptodate flag, - * but do not return any error?! */ - error = -EIO; - } - if (error) + if (bio->bi_error) set_bit(__EE_WAS_ERROR, &peer_req->flags); bio_put(bio); /* no need for the bio anymore */ @@ -208,24 +197,13 @@ void drbd_peer_request_endio(struct bio *bio, int error) /* read, readA or write requests on R_PRIMARY coming from drbd_make_request */ -void drbd_request_endio(struct bio *bio, int error) +void drbd_request_endio(struct bio *bio) { unsigned long flags; struct drbd_request *req = bio->bi_private; struct drbd_device *device = req->device; struct bio_and_error m; enum drbd_req_event what; - int uptodate = bio_flagged(bio, BIO_UPTODATE); - - if (!error && !uptodate) { - drbd_warn(device, "p %s: setting error to -EIO\n", - bio_data_dir(bio) == WRITE ? "write" : "read"); - /* strange behavior of some lower level drivers... - * fail the request by clearing the uptodate flag, - * but do not return any error?! */ - error = -EIO; - } - /* If this request was aborted locally before, * but now was completed "successfully", @@ -259,14 +237,14 @@ void drbd_request_endio(struct bio *bio, int error) if (__ratelimit(&drbd_ratelimit_state)) drbd_emerg(device, "delayed completion of aborted local request; disk-timeout may be too aggressive\n"); - if (!error) + if (!bio->bi_error) panic("possible random memory corruption caused by delayed completion of aborted local request\n"); } /* to avoid recursion in __req_mod */ - if (unlikely(error)) { + if (unlikely(bio->bi_error)) { if (bio->bi_rw & REQ_DISCARD) - what = (error == -EOPNOTSUPP) + what = (bio->bi_error == -EOPNOTSUPP) ? DISCARD_COMPLETED_NOTSUPP : DISCARD_COMPLETED_WITH_ERROR; else @@ -279,7 +257,7 @@ void drbd_request_endio(struct bio *bio, int error) what = COMPLETED_OK; bio_put(req->private_bio); - req->private_bio = ERR_PTR(error); + req->private_bio = ERR_PTR(bio->bi_error); /* not req_mod(), we need irqsave here! */ spin_lock_irqsave(&device->resource->req_lock, flags); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index a08cda955285..331363e7de0f 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3771,13 +3771,14 @@ struct rb0_cbdata { struct completion complete; }; -static void floppy_rb0_cb(struct bio *bio, int err) +static void floppy_rb0_cb(struct bio *bio) { struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private; int drive = cbdata->drive; - if (err) { - pr_info("floppy: error %d while reading block 0\n", err); + if (bio->bi_error) { + pr_info("floppy: error %d while reading block 0\n", + bio->bi_error); set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags); } complete(&cbdata->complete); diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 69de41a87b74..016a59afcf24 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -222,7 +222,7 @@ static void end_cmd(struct nullb_cmd *cmd) blk_end_request_all(cmd->rq, 0); break; case NULL_Q_BIO: - bio_endio(cmd->bio, 0); + bio_endio(cmd->bio); break; } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 4c20c228184c..a7a259e031da 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -977,7 +977,7 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct bio_vec *bvec) } } -static void pkt_end_io_read(struct bio *bio, int err) +static void pkt_end_io_read(struct bio *bio) { struct packet_data *pkt = bio->bi_private; struct pktcdvd_device *pd = pkt->pd; @@ -985,9 +985,9 @@ static void pkt_end_io_read(struct bio *bio, int err) pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d\n", bio, (unsigned long long)pkt->sector, - (unsigned long long)bio->bi_iter.bi_sector, err); + (unsigned long long)bio->bi_iter.bi_sector, bio->bi_error); - if (err) + if (bio->bi_error) atomic_inc(&pkt->io_errors); if (atomic_dec_and_test(&pkt->io_wait)) { atomic_inc(&pkt->run_sm); @@ -996,13 +996,13 @@ static void pkt_end_io_read(struct bio *bio, int err) pkt_bio_finished(pd); } -static void pkt_end_io_packet_write(struct bio *bio, int err) +static void pkt_end_io_packet_write(struct bio *bio) { struct packet_data *pkt = bio->bi_private; struct pktcdvd_device *pd = pkt->pd; BUG_ON(!pd); - pkt_dbg(2, pd, "id=%d, err=%d\n", pkt->id, err); + pkt_dbg(2, pd, "id=%d, err=%d\n", pkt->id, bio->bi_error); pd->stats.pkt_ended++; @@ -1340,22 +1340,22 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) pkt_queue_bio(pd, pkt->w_bio); } -static void pkt_finish_packet(struct packet_data *pkt, int uptodate) +static void pkt_finish_packet(struct packet_data *pkt, int error) { struct bio *bio; - if (!uptodate) + if (error) pkt->cache_valid = 0; /* Finish all bios corresponding to this packet */ - while ((bio = bio_list_pop(&pkt->orig_bios))) - bio_endio(bio, uptodate ? 0 : -EIO); + while ((bio = bio_list_pop(&pkt->orig_bios))) { + bio->bi_error = error; + bio_endio(bio); + } } static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data *pkt) { - int uptodate; - pkt_dbg(2, pd, "pkt %d\n", pkt->id); for (;;) { @@ -1384,7 +1384,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data if (atomic_read(&pkt->io_wait) > 0) return; - if (test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags)) { + if (!pkt->w_bio->bi_error) { pkt_set_state(pkt, PACKET_FINISHED_STATE); } else { pkt_set_state(pkt, PACKET_RECOVERY_STATE); @@ -1401,8 +1401,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data break; case PACKET_FINISHED_STATE: - uptodate = test_bit(BIO_UPTODATE, &pkt->w_bio->bi_flags); - pkt_finish_packet(pkt, uptodate); + pkt_finish_packet(pkt, pkt->w_bio->bi_error); return; default: @@ -2332,13 +2331,14 @@ static void pkt_close(struct gendisk *disk, fmode_t mode) } -static void pkt_end_io_read_cloned(struct bio *bio, int err) +static void pkt_end_io_read_cloned(struct bio *bio) { struct packet_stacked_data *psd = bio->bi_private; struct pktcdvd_device *pd = psd->pd; + psd->bio->bi_error = bio->bi_error; bio_put(bio); - bio_endio(psd->bio, err); + bio_endio(psd->bio); mempool_free(psd, psd_pool); pkt_bio_finished(pd); } diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index b1612eb16172..49b4706b162c 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -593,7 +593,8 @@ out: next = bio_list_peek(&priv->list); spin_unlock_irq(&priv->lock); - bio_endio(bio, error); + bio->bi_error = error; + bio_endio(bio); return next; } diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c index ac8c62cb4875..63b9d2ffa8ee 100644 --- a/drivers/block/rsxx/dev.c +++ b/drivers/block/rsxx/dev.c @@ -137,7 +137,10 @@ static void bio_dma_done_cb(struct rsxx_cardinfo *card, if (!card->eeh_state && card->gendisk) disk_stats_complete(card, meta->bio, meta->start_time); - bio_endio(meta->bio, atomic_read(&meta->error) ? -EIO : 0); + if (atomic_read(&meta->error)) + bio_io_error(meta->bio); + else + bio_endio(meta->bio); kmem_cache_free(bio_meta_pool, meta); } } @@ -199,7 +202,9 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) queue_err: kmem_cache_free(bio_meta_pool, bio_meta); req_err: - bio_endio(bio, st); + if (st) + bio->bi_error = st; + bio_endio(bio); } /*----------------- Device Setup -------------------*/ diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 4cf81b5bf0f7..3b3afd2ec5d6 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -456,7 +456,7 @@ static void process_page(unsigned long data) PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); if (control & DMASCR_HARD_ERROR) { /* error */ - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; dev_printk(KERN_WARNING, &card->dev->dev, "I/O error on sector %d/%d\n", le32_to_cpu(desc->local_addr)>>9, @@ -505,7 +505,7 @@ static void process_page(unsigned long data) return_bio = bio->bi_next; bio->bi_next = NULL; - bio_endio(bio, 0); + bio_endio(bio); } } diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index ced96777b677..662648e08596 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -1078,9 +1078,9 @@ static void __end_block_io_op(struct pending_req *pending_req, int error) /* * bio callback. */ -static void end_block_io_op(struct bio *bio, int error) +static void end_block_io_op(struct bio *bio) { - __end_block_io_op(bio->bi_private, error); + __end_block_io_op(bio->bi_private, bio->bi_error); bio_put(bio); } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 6d89ed35d80c..d542db7a6c73 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -82,7 +82,6 @@ struct blk_shadow { struct split_bio { struct bio *bio; atomic_t pending; - int err; }; static DEFINE_MUTEX(blkfront_mutex); @@ -1478,16 +1477,14 @@ static int blkfront_probe(struct xenbus_device *dev, return 0; } -static void split_bio_end(struct bio *bio, int error) +static void split_bio_end(struct bio *bio) { struct split_bio *split_bio = bio->bi_private; - if (error) - split_bio->err = error; - if (atomic_dec_and_test(&split_bio->pending)) { split_bio->bio->bi_phys_segments = 0; - bio_endio(split_bio->bio, split_bio->err); + split_bio->bio->bi_error = bio->bi_error; + bio_endio(split_bio->bio); kfree(split_bio); } bio_put(bio); diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index f439ad2800da..68c3d4800464 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -850,7 +850,7 @@ static void __zram_make_request(struct zram *zram, struct bio *bio) if (unlikely(bio->bi_rw & REQ_DISCARD)) { zram_bio_discard(zram, index, offset, bio); - bio_endio(bio, 0); + bio_endio(bio); return; } @@ -883,8 +883,7 @@ static void __zram_make_request(struct zram *zram, struct bio *bio) update_position(&index, &offset, &bvec); } - set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_endio(bio, 0); + bio_endio(bio); return; out: diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 00cde40db572..83392f856dfd 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -278,7 +278,7 @@ err: goto out; } -static void btree_node_read_endio(struct bio *bio, int error) +static void btree_node_read_endio(struct bio *bio) { struct closure *cl = bio->bi_private; closure_put(cl); @@ -305,7 +305,7 @@ static void bch_btree_node_read(struct btree *b) bch_submit_bbio(bio, b->c, &b->key, 0); closure_sync(&cl); - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) + if (bio->bi_error) set_btree_node_io_error(b); bch_bbio_free(bio, b->c); @@ -371,15 +371,15 @@ static void btree_node_write_done(struct closure *cl) __btree_node_write_done(cl); } -static void btree_node_write_endio(struct bio *bio, int error) +static void btree_node_write_endio(struct bio *bio) { struct closure *cl = bio->bi_private; struct btree *b = container_of(cl, struct btree, io); - if (error) + if (bio->bi_error) set_btree_node_io_error(b); - bch_bbio_count_io_errors(b->c, bio, error, "writing btree"); + bch_bbio_count_io_errors(b->c, bio, bio->bi_error, "writing btree"); closure_put(cl); } diff --git a/drivers/md/bcache/closure.h b/drivers/md/bcache/closure.h index 79a6d63e8ed3..782cc2c8a185 100644 --- a/drivers/md/bcache/closure.h +++ b/drivers/md/bcache/closure.h @@ -38,7 +38,7 @@ * they are running owned by the thread that is running them. Otherwise, suppose * you submit some bios and wish to have a function run when they all complete: * - * foo_endio(struct bio *bio, int error) + * foo_endio(struct bio *bio) * { * closure_put(cl); * } diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index bf6a9ca18403..9440df94bc83 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -55,19 +55,19 @@ static void bch_bio_submit_split_done(struct closure *cl) s->bio->bi_end_io = s->bi_end_io; s->bio->bi_private = s->bi_private; - bio_endio(s->bio, 0); + bio_endio(s->bio); closure_debug_destroy(&s->cl); mempool_free(s, s->p->bio_split_hook); } -static void bch_bio_submit_split_endio(struct bio *bio, int error) +static void bch_bio_submit_split_endio(struct bio *bio) { struct closure *cl = bio->bi_private; struct bio_split_hook *s = container_of(cl, struct bio_split_hook, cl); - if (error) - clear_bit(BIO_UPTODATE, &s->bio->bi_flags); + if (bio->bi_error) + s->bio->bi_error = bio->bi_error; bio_put(bio); closure_put(cl); diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index 418607a6ba33..d6a4e16030a6 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -24,7 +24,7 @@ * bit. */ -static void journal_read_endio(struct bio *bio, int error) +static void journal_read_endio(struct bio *bio) { struct closure *cl = bio->bi_private; closure_put(cl); @@ -401,7 +401,7 @@ retry: #define last_seq(j) ((j)->seq - fifo_used(&(j)->pin) + 1) -static void journal_discard_endio(struct bio *bio, int error) +static void journal_discard_endio(struct bio *bio) { struct journal_device *ja = container_of(bio, struct journal_device, discard_bio); @@ -547,11 +547,11 @@ void bch_journal_next(struct journal *j) pr_debug("journal_pin full (%zu)", fifo_used(&j->pin)); } -static void journal_write_endio(struct bio *bio, int error) +static void journal_write_endio(struct bio *bio) { struct journal_write *w = bio->bi_private; - cache_set_err_on(error, w->c, "journal io error"); + cache_set_err_on(bio->bi_error, w->c, "journal io error"); closure_put(&w->c->journal.io); } diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c index cd7490311e51..b929fc944e9c 100644 --- a/drivers/md/bcache/movinggc.c +++ b/drivers/md/bcache/movinggc.c @@ -60,20 +60,20 @@ static void write_moving_finish(struct closure *cl) closure_return_with_destructor(cl, moving_io_destructor); } -static void read_moving_endio(struct bio *bio, int error) +static void read_moving_endio(struct bio *bio) { struct bbio *b = container_of(bio, struct bbio, bio); struct moving_io *io = container_of(bio->bi_private, struct moving_io, cl); - if (error) - io->op.error = error; + if (bio->bi_error) + io->op.error = bio->bi_error; else if (!KEY_DIRTY(&b->key) && ptr_stale(io->op.c, &b->key, 0)) { io->op.error = -EINTR; } - bch_bbio_endio(io->op.c, bio, error, "reading data to move"); + bch_bbio_endio(io->op.c, bio, bio->bi_error, "reading data to move"); } static void moving_init(struct moving_io *io) diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index f292790997d7..a09b9462ff49 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -173,22 +173,22 @@ static void bch_data_insert_error(struct closure *cl) bch_data_insert_keys(cl); } -static void bch_data_insert_endio(struct bio *bio, int error) +static void bch_data_insert_endio(struct bio *bio) { struct closure *cl = bio->bi_private; struct data_insert_op *op = container_of(cl, struct data_insert_op, cl); - if (error) { + if (bio->bi_error) { /* TODO: We could try to recover from this. */ if (op->writeback) - op->error = error; + op->error = bio->bi_error; else if (!op->replace) set_closure_fn(cl, bch_data_insert_error, op->wq); else set_closure_fn(cl, NULL, NULL); } - bch_bbio_endio(op->c, bio, error, "writing data to cache"); + bch_bbio_endio(op->c, bio, bio->bi_error, "writing data to cache"); } static void bch_data_insert_start(struct closure *cl) @@ -477,7 +477,7 @@ struct search { struct data_insert_op iop; }; -static void bch_cache_read_endio(struct bio *bio, int error) +static void bch_cache_read_endio(struct bio *bio) { struct bbio *b = container_of(bio, struct bbio, bio); struct closure *cl = bio->bi_private; @@ -490,15 +490,15 @@ static void bch_cache_read_endio(struct bio *bio, int error) * from the backing device. */ - if (error) - s->iop.error = error; + if (bio->bi_error) + s->iop.error = bio->bi_error; else if (!KEY_DIRTY(&b->key) && ptr_stale(s->iop.c, &b->key, 0)) { atomic_long_inc(&s->iop.c->cache_read_races); s->iop.error = -EINTR; } - bch_bbio_endio(s->iop.c, bio, error, "reading from cache"); + bch_bbio_endio(s->iop.c, bio, bio->bi_error, "reading from cache"); } /* @@ -591,13 +591,13 @@ static void cache_lookup(struct closure *cl) /* Common code for the make_request functions */ -static void request_endio(struct bio *bio, int error) +static void request_endio(struct bio *bio) { struct closure *cl = bio->bi_private; - if (error) { + if (bio->bi_error) { struct search *s = container_of(cl, struct search, cl); - s->iop.error = error; + s->iop.error = bio->bi_error; /* Only cache read errors are recoverable */ s->recoverable = false; } @@ -613,7 +613,8 @@ static void bio_complete(struct search *s) &s->d->disk->part0, s->start_time); trace_bcache_request_end(s->d, s->orig_bio); - bio_endio(s->orig_bio, s->iop.error); + s->orig_bio->bi_error = s->iop.error; + bio_endio(s->orig_bio); s->orig_bio = NULL; } } @@ -992,7 +993,7 @@ static void cached_dev_make_request(struct request_queue *q, struct bio *bio) } else { if ((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(dc->bdev))) - bio_endio(bio, 0); + bio_endio(bio); else bch_generic_make_request(bio, &d->bio_split_hook); } diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index fc8e545ced18..be01fd3c87f1 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -221,7 +221,7 @@ err: return err; } -static void write_bdev_super_endio(struct bio *bio, int error) +static void write_bdev_super_endio(struct bio *bio) { struct cached_dev *dc = bio->bi_private; /* XXX: error checking */ @@ -290,11 +290,11 @@ void bch_write_bdev_super(struct cached_dev *dc, struct closure *parent) closure_return_with_destructor(cl, bch_write_bdev_super_unlock); } -static void write_super_endio(struct bio *bio, int error) +static void write_super_endio(struct bio *bio) { struct cache *ca = bio->bi_private; - bch_count_io_errors(ca, error, "writing superblock"); + bch_count_io_errors(ca, bio->bi_error, "writing superblock"); closure_put(&ca->set->sb_write); } @@ -339,12 +339,12 @@ void bcache_write_super(struct cache_set *c) /* UUID io */ -static void uuid_endio(struct bio *bio, int error) +static void uuid_endio(struct bio *bio) { struct closure *cl = bio->bi_private; struct cache_set *c = container_of(cl, struct cache_set, uuid_write); - cache_set_err_on(error, c, "accessing uuids"); + cache_set_err_on(bio->bi_error, c, "accessing uuids"); bch_bbio_free(bio, c); closure_put(cl); } @@ -512,11 +512,11 @@ static struct uuid_entry *uuid_find_empty(struct cache_set *c) * disk. */ -static void prio_endio(struct bio *bio, int error) +static void prio_endio(struct bio *bio) { struct cache *ca = bio->bi_private; - cache_set_err_on(error, ca->set, "accessing priorities"); + cache_set_err_on(bio->bi_error, ca->set, "accessing priorities"); bch_bbio_free(bio, ca->set); closure_put(&ca->prio); } diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index f1986bcd1bf0..b4fc874c30fd 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -166,12 +166,12 @@ static void write_dirty_finish(struct closure *cl) closure_return_with_destructor(cl, dirty_io_destructor); } -static void dirty_endio(struct bio *bio, int error) +static void dirty_endio(struct bio *bio) { struct keybuf_key *w = bio->bi_private; struct dirty_io *io = w->private; - if (error) + if (bio->bi_error) SET_KEY_DIRTY(&w->key, false); closure_put(&io->cl); @@ -193,15 +193,15 @@ static void write_dirty(struct closure *cl) continue_at(cl, write_dirty_finish, system_wq); } -static void read_dirty_endio(struct bio *bio, int error) +static void read_dirty_endio(struct bio *bio) { struct keybuf_key *w = bio->bi_private; struct dirty_io *io = w->private; bch_count_io_errors(PTR_CACHE(io->dc->disk.c, &w->key, 0), - error, "reading dirty data from cache"); + bio->bi_error, "reading dirty data from cache"); - dirty_endio(bio, error); + dirty_endio(bio); } static void read_dirty_submit(struct closure *cl) diff --git a/drivers/md/dm-bio-prison.c b/drivers/md/dm-bio-prison.c index cd6d1d21e057..03af174485d3 100644 --- a/drivers/md/dm-bio-prison.c +++ b/drivers/md/dm-bio-prison.c @@ -236,8 +236,10 @@ void dm_cell_error(struct dm_bio_prison *prison, bio_list_init(&bios); dm_cell_release(prison, cell, &bios); - while ((bio = bio_list_pop(&bios))) - bio_endio(bio, error); + while ((bio = bio_list_pop(&bios))) { + bio->bi_error = error; + bio_endio(bio); + } } EXPORT_SYMBOL_GPL(dm_cell_error); diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 86dbbc737402..83cc52eaf56d 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -545,7 +545,8 @@ static void dmio_complete(unsigned long error, void *context) { struct dm_buffer *b = context; - b->bio.bi_end_io(&b->bio, error ? -EIO : 0); + b->bio.bi_error = error ? -EIO : 0; + b->bio.bi_end_io(&b->bio); } static void use_dmio(struct dm_buffer *b, int rw, sector_t block, @@ -575,13 +576,16 @@ static void use_dmio(struct dm_buffer *b, int rw, sector_t block, b->bio.bi_end_io = end_io; r = dm_io(&io_req, 1, ®ion, NULL); - if (r) - end_io(&b->bio, r); + if (r) { + b->bio.bi_error = r; + end_io(&b->bio); + } } -static void inline_endio(struct bio *bio, int error) +static void inline_endio(struct bio *bio) { bio_end_io_t *end_fn = bio->bi_private; + int error = bio->bi_error; /* * Reset the bio to free any attached resources @@ -589,7 +593,8 @@ static void inline_endio(struct bio *bio, int error) */ bio_reset(bio); - end_fn(bio, error); + bio->bi_error = error; + end_fn(bio); } static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block, @@ -661,13 +666,14 @@ static void submit_io(struct dm_buffer *b, int rw, sector_t block, * Set the error, clear B_WRITING bit and wake anyone who was waiting on * it. */ -static void write_endio(struct bio *bio, int error) +static void write_endio(struct bio *bio) { struct dm_buffer *b = container_of(bio, struct dm_buffer, bio); - b->write_error = error; - if (unlikely(error)) { + b->write_error = bio->bi_error; + if (unlikely(bio->bi_error)) { struct dm_bufio_client *c = b->c; + int error = bio->bi_error; (void)cmpxchg(&c->async_write_error, 0, error); } @@ -1026,11 +1032,11 @@ found_buffer: * The endio routine for reading: set the error, clear the bit and wake up * anyone waiting on the buffer. */ -static void read_endio(struct bio *bio, int error) +static void read_endio(struct bio *bio) { struct dm_buffer *b = container_of(bio, struct dm_buffer, bio); - b->read_error = error; + b->read_error = bio->bi_error; BUG_ON(!test_bit(B_READING, &b->state)); diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 1b4e1756b169..04d0dadc48b1 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -919,14 +919,14 @@ static void defer_writethrough_bio(struct cache *cache, struct bio *bio) wake_worker(cache); } -static void writethrough_endio(struct bio *bio, int err) +static void writethrough_endio(struct bio *bio) { struct per_bio_data *pb = get_per_bio_data(bio, PB_DATA_SIZE_WT); dm_unhook_bio(&pb->hook_info, bio); - if (err) { - bio_endio(bio, err); + if (bio->bi_error) { + bio_endio(bio); return; } @@ -1231,7 +1231,7 @@ static void migration_success_post_commit(struct dm_cache_migration *mg) * The block was promoted via an overwrite, so it's dirty. */ set_dirty(cache, mg->new_oblock, mg->cblock); - bio_endio(mg->new_ocell->holder, 0); + bio_endio(mg->new_ocell->holder); cell_defer(cache, mg->new_ocell, false); } free_io_migration(mg); @@ -1284,7 +1284,7 @@ static void issue_copy(struct dm_cache_migration *mg) } } -static void overwrite_endio(struct bio *bio, int err) +static void overwrite_endio(struct bio *bio) { struct dm_cache_migration *mg = bio->bi_private; struct cache *cache = mg->cache; @@ -1294,7 +1294,7 @@ static void overwrite_endio(struct bio *bio, int err) dm_unhook_bio(&pb->hook_info, bio); - if (err) + if (bio->bi_error) mg->err = true; mg->requeue_holder = false; @@ -1358,7 +1358,7 @@ static void issue_discard(struct dm_cache_migration *mg) b = to_dblock(from_dblock(b) + 1); } - bio_endio(bio, 0); + bio_endio(bio); cell_defer(mg->cache, mg->new_ocell, false); free_migration(mg); } @@ -1631,7 +1631,7 @@ static void process_discard_bio(struct cache *cache, struct prealloc *structs, calc_discard_block_range(cache, bio, &b, &e); if (b == e) { - bio_endio(bio, 0); + bio_endio(bio); return; } @@ -2213,8 +2213,10 @@ static void requeue_deferred_bios(struct cache *cache) bio_list_merge(&bios, &cache->deferred_bios); bio_list_init(&cache->deferred_bios); - while ((bio = bio_list_pop(&bios))) - bio_endio(bio, DM_ENDIO_REQUEUE); + while ((bio = bio_list_pop(&bios))) { + bio->bi_error = DM_ENDIO_REQUEUE; + bio_endio(bio); + } } static int more_work(struct cache *cache) @@ -3119,7 +3121,7 @@ static int cache_map(struct dm_target *ti, struct bio *bio) * This is a duplicate writethrough io that is no * longer needed because the block has been demoted. */ - bio_endio(bio, 0); + bio_endio(bio); // FIXME: remap everything as a miss cell_defer(cache, cell, false); r = DM_MAPIO_SUBMITTED; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 0f48fed44a17..744b80c608e5 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1076,7 +1076,8 @@ static void crypt_dec_pending(struct dm_crypt_io *io) if (io->ctx.req) crypt_free_req(cc, io->ctx.req, base_bio); - bio_endio(base_bio, error); + base_bio->bi_error = error; + bio_endio(base_bio); } /* @@ -1096,15 +1097,12 @@ static void crypt_dec_pending(struct dm_crypt_io *io) * The work is done per CPU global for all dm-crypt instances. * They should not depend on each other and do not block. */ -static void crypt_endio(struct bio *clone, int error) +static void crypt_endio(struct bio *clone) { struct dm_crypt_io *io = clone->bi_private; struct crypt_config *cc = io->cc; unsigned rw = bio_data_dir(clone); - if (unlikely(!bio_flagged(clone, BIO_UPTODATE) && !error)) - error = -EIO; - /* * free the processed pages */ @@ -1113,13 +1111,13 @@ static void crypt_endio(struct bio *clone, int error) bio_put(clone); - if (rw == READ && !error) { + if (rw == READ && !clone->bi_error) { kcryptd_queue_crypt(io); return; } - if (unlikely(error)) - io->error = error; + if (unlikely(clone->bi_error)) + io->error = clone->bi_error; crypt_dec_pending(io); } diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index b257e46876d3..04481247aab8 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -296,7 +296,7 @@ static int flakey_map(struct dm_target *ti, struct bio *bio) * Drop writes? */ if (test_bit(DROP_WRITES, &fc->flags)) { - bio_endio(bio, 0); + bio_endio(bio); return DM_MAPIO_SUBMITTED; } diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 74adcd2c967e..efc6659f9d6a 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -134,12 +134,12 @@ static void dec_count(struct io *io, unsigned int region, int error) complete_io(io); } -static void endio(struct bio *bio, int error) +static void endio(struct bio *bio) { struct io *io; unsigned region; - if (error && bio_data_dir(bio) == READ) + if (bio->bi_error && bio_data_dir(bio) == READ) zero_fill_bio(bio); /* @@ -149,7 +149,7 @@ static void endio(struct bio *bio, int error) bio_put(bio); - dec_count(io, region, error); + dec_count(io, region, bio->bi_error); } /*----------------------------------------------------------------- diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c index ad1b049ae2ab..e9d17488d5e3 100644 --- a/drivers/md/dm-log-writes.c +++ b/drivers/md/dm-log-writes.c @@ -146,16 +146,16 @@ static void put_io_block(struct log_writes_c *lc) } } -static void log_end_io(struct bio *bio, int err) +static void log_end_io(struct bio *bio) { struct log_writes_c *lc = bio->bi_private; struct bio_vec *bvec; int i; - if (err) { + if (bio->bi_error) { unsigned long flags; - DMERR("Error writing log block, error=%d", err); + DMERR("Error writing log block, error=%d", bio->bi_error); spin_lock_irqsave(&lc->blocks_lock, flags); lc->logging_enabled = false; spin_unlock_irqrestore(&lc->blocks_lock, flags); @@ -205,7 +205,6 @@ static int write_metadata(struct log_writes_c *lc, void *entry, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; - set_bit(BIO_UPTODATE, &bio->bi_flags); page = alloc_page(GFP_KERNEL); if (!page) { @@ -270,7 +269,6 @@ static int log_one_block(struct log_writes_c *lc, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; - set_bit(BIO_UPTODATE, &bio->bi_flags); for (i = 0; i < block->vec_cnt; i++) { /* @@ -292,7 +290,6 @@ static int log_one_block(struct log_writes_c *lc, bio->bi_bdev = lc->logdev->bdev; bio->bi_end_io = log_end_io; bio->bi_private = lc; - set_bit(BIO_UPTODATE, &bio->bi_flags); ret = bio_add_page(bio, block->vecs[i].bv_page, block->vecs[i].bv_len, 0); @@ -606,7 +603,7 @@ static int log_writes_map(struct dm_target *ti, struct bio *bio) WARN_ON(flush_bio || fua_bio); if (lc->device_supports_discard) goto map_bio; - bio_endio(bio, 0); + bio_endio(bio); return DM_MAPIO_SUBMITTED; } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index d83696bf403b..e1eabfb2f52d 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -490,9 +490,11 @@ static void hold_bio(struct mirror_set *ms, struct bio *bio) * If device is suspended, complete the bio. */ if (dm_noflush_suspending(ms->ti)) - bio_endio(bio, DM_ENDIO_REQUEUE); + bio->bi_error = DM_ENDIO_REQUEUE; else - bio_endio(bio, -EIO); + bio->bi_error = -EIO; + + bio_endio(bio); return; } @@ -515,7 +517,7 @@ static void read_callback(unsigned long error, void *context) bio_set_m(bio, NULL); if (likely(!error)) { - bio_endio(bio, 0); + bio_endio(bio); return; } @@ -531,7 +533,7 @@ static void read_callback(unsigned long error, void *context) DMERR_LIMIT("Read failure on mirror device %s. Failing I/O.", m->dev->name); - bio_endio(bio, -EIO); + bio_io_error(bio); } /* Asynchronous read. */ @@ -580,7 +582,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads) if (likely(m)) read_async_bio(m, bio); else - bio_endio(bio, -EIO); + bio_io_error(bio); } } @@ -598,7 +600,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads) static void write_callback(unsigned long error, void *context) { - unsigned i, ret = 0; + unsigned i; struct bio *bio = (struct bio *) context; struct mirror_set *ms; int should_wake = 0; @@ -614,7 +616,7 @@ static void write_callback(unsigned long error, void *context) * regions with the same code. */ if (likely(!error)) { - bio_endio(bio, ret); + bio_endio(bio); return; } @@ -623,7 +625,8 @@ static void write_callback(unsigned long error, void *context) * degrade the array. */ if (bio->bi_rw & REQ_DISCARD) { - bio_endio(bio, -EOPNOTSUPP); + bio->bi_error = -EOPNOTSUPP; + bio_endio(bio); return; } @@ -828,13 +831,12 @@ static void do_failures(struct mirror_set *ms, struct bio_list *failures) * be wrong if the failed leg returned after reboot and * got replicated back to the good legs.) */ - if (unlikely(!get_valid_mirror(ms) || (keep_log(ms) && ms->log_failure))) - bio_endio(bio, -EIO); + bio_io_error(bio); else if (errors_handled(ms) && !keep_log(ms)) hold_bio(ms, bio); else - bio_endio(bio, 0); + bio_endio(bio); } } diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 7c82d3ccce87..dd8ca0bb0980 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -1490,7 +1490,7 @@ out: error_bios(snapshot_bios); } else { if (full_bio) - bio_endio(full_bio, 0); + bio_endio(full_bio); flush_bios(snapshot_bios); } @@ -1580,11 +1580,11 @@ static void start_copy(struct dm_snap_pending_exception *pe) dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe); } -static void full_bio_end_io(struct bio *bio, int error) +static void full_bio_end_io(struct bio *bio) { void *callback_data = bio->bi_private; - dm_kcopyd_do_callback(callback_data, 0, error ? 1 : 0); + dm_kcopyd_do_callback(callback_data, 0, bio->bi_error ? 1 : 0); } static void start_full_bio(struct dm_snap_pending_exception *pe, diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index a672a1502c14..4f94c7da82f6 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -273,7 +273,7 @@ static int stripe_map_range(struct stripe_c *sc, struct bio *bio, return DM_MAPIO_REMAPPED; } else { /* The range doesn't map to the target stripe */ - bio_endio(bio, 0); + bio_endio(bio); return DM_MAPIO_SUBMITTED; } } diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index c33f61a4cc28..2ade2c46dca9 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -614,8 +614,10 @@ static void error_bio_list(struct bio_list *bios, int error) { struct bio *bio; - while ((bio = bio_list_pop(bios))) - bio_endio(bio, error); + while ((bio = bio_list_pop(bios))) { + bio->bi_error = error; + bio_endio(bio); + } } static void error_thin_bio_list(struct thin_c *tc, struct bio_list *master, int error) @@ -864,14 +866,14 @@ static void copy_complete(int read_err, unsigned long write_err, void *context) complete_mapping_preparation(m); } -static void overwrite_endio(struct bio *bio, int err) +static void overwrite_endio(struct bio *bio) { struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook)); struct dm_thin_new_mapping *m = h->overwrite_mapping; bio->bi_end_io = m->saved_bi_end_io; - m->err = err; + m->err = bio->bi_error; complete_mapping_preparation(m); } @@ -996,7 +998,7 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m) */ if (bio) { inc_remap_and_issue_cell(tc, m->cell, m->data_block); - bio_endio(bio, 0); + bio_endio(bio); } else { inc_all_io_entry(tc->pool, m->cell->holder); remap_and_issue(tc, m->cell->holder, m->data_block); @@ -1026,7 +1028,7 @@ static void process_prepared_discard_fail(struct dm_thin_new_mapping *m) static void process_prepared_discard_success(struct dm_thin_new_mapping *m) { - bio_endio(m->bio, 0); + bio_endio(m->bio); free_discard_mapping(m); } @@ -1040,7 +1042,7 @@ static void process_prepared_discard_no_passdown(struct dm_thin_new_mapping *m) metadata_operation_failed(tc->pool, "dm_thin_remove_range", r); bio_io_error(m->bio); } else - bio_endio(m->bio, 0); + bio_endio(m->bio); cell_defer_no_holder(tc, m->cell); mempool_free(m, tc->pool->mapping_pool); @@ -1111,7 +1113,8 @@ static void process_prepared_discard_passdown(struct dm_thin_new_mapping *m) * Even if r is set, there could be sub discards in flight that we * need to wait for. */ - bio_endio(m->bio, r); + m->bio->bi_error = r; + bio_endio(m->bio); cell_defer_no_holder(tc, m->cell); mempool_free(m, pool->mapping_pool); } @@ -1487,9 +1490,10 @@ static void handle_unserviceable_bio(struct pool *pool, struct bio *bio) { int error = should_error_unserviceable_bio(pool); - if (error) - bio_endio(bio, error); - else + if (error) { + bio->bi_error = error; + bio_endio(bio); + } else retry_on_resume(bio); } @@ -1625,7 +1629,7 @@ static void process_discard_cell_passdown(struct thin_c *tc, struct dm_bio_priso * will prevent completion until the sub range discards have * completed. */ - bio_endio(bio, 0); + bio_endio(bio); } static void process_discard_bio(struct thin_c *tc, struct bio *bio) @@ -1639,7 +1643,7 @@ static void process_discard_bio(struct thin_c *tc, struct bio *bio) /* * The discard covers less than a block. */ - bio_endio(bio, 0); + bio_endio(bio); return; } @@ -1784,7 +1788,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block if (bio_data_dir(bio) == READ) { zero_fill_bio(bio); cell_defer_no_holder(tc, cell); - bio_endio(bio, 0); + bio_endio(bio); return; } @@ -1849,7 +1853,7 @@ static void process_cell(struct thin_c *tc, struct dm_bio_prison_cell *cell) } else { zero_fill_bio(bio); - bio_endio(bio, 0); + bio_endio(bio); } } else provision_block(tc, bio, block, cell); @@ -1920,7 +1924,7 @@ static void __process_bio_read_only(struct thin_c *tc, struct bio *bio, } zero_fill_bio(bio); - bio_endio(bio, 0); + bio_endio(bio); break; default: @@ -1945,7 +1949,7 @@ static void process_cell_read_only(struct thin_c *tc, struct dm_bio_prison_cell static void process_bio_success(struct thin_c *tc, struct bio *bio) { - bio_endio(bio, 0); + bio_endio(bio); } static void process_bio_fail(struct thin_c *tc, struct bio *bio) @@ -2581,7 +2585,8 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio) thin_hook_bio(tc, bio); if (tc->requeue_mode) { - bio_endio(bio, DM_ENDIO_REQUEUE); + bio->bi_error = DM_ENDIO_REQUEUE; + bio_endio(bio); return DM_MAPIO_SUBMITTED; } diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index bb9c6a00e4b0..4b34df8fdb58 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -458,8 +458,9 @@ static void verity_finish_io(struct dm_verity_io *io, int error) bio->bi_end_io = io->orig_bi_end_io; bio->bi_private = io->orig_bi_private; + bio->bi_error = error; - bio_endio(bio, error); + bio_endio(bio); } static void verity_work(struct work_struct *w) @@ -469,12 +470,12 @@ static void verity_work(struct work_struct *w) verity_finish_io(io, verity_verify_io(io)); } -static void verity_end_io(struct bio *bio, int error) +static void verity_end_io(struct bio *bio) { struct dm_verity_io *io = bio->bi_private; - if (error) { - verity_finish_io(io, error); + if (bio->bi_error) { + verity_finish_io(io, bio->bi_error); return; } diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c index b9a64bbce304..766bc93006e6 100644 --- a/drivers/md/dm-zero.c +++ b/drivers/md/dm-zero.c @@ -47,7 +47,7 @@ static int zero_map(struct dm_target *ti, struct bio *bio) break; } - bio_endio(bio, 0); + bio_endio(bio); /* accepted bio, don't make new request */ return DM_MAPIO_SUBMITTED; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f331d888e7f5..7f367fcace03 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -944,7 +944,8 @@ static void dec_pending(struct dm_io *io, int error) } else { /* done with normal IO or empty flush */ trace_block_bio_complete(md->queue, bio, io_error); - bio_endio(bio, io_error); + bio->bi_error = io_error; + bio_endio(bio); } } } @@ -957,17 +958,15 @@ static void disable_write_same(struct mapped_device *md) limits->max_write_same_sectors = 0; } -static void clone_endio(struct bio *bio, int error) +static void clone_endio(struct bio *bio) { + int error = bio->bi_error; int r = error; struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone); struct dm_io *io = tio->io; struct mapped_device *md = tio->io->md; dm_endio_fn endio = tio->ti->type->end_io; - if (!bio_flagged(bio, BIO_UPTODATE) && !error) - error = -EIO; - if (endio) { r = endio(tio->ti, bio, error); if (r < 0 || r == DM_ENDIO_REQUEUE) @@ -996,7 +995,7 @@ static void clone_endio(struct bio *bio, int error) /* * Partial completion handling for request-based dm */ -static void end_clone_bio(struct bio *clone, int error) +static void end_clone_bio(struct bio *clone) { struct dm_rq_clone_bio_info *info = container_of(clone, struct dm_rq_clone_bio_info, clone); @@ -1013,13 +1012,13 @@ static void end_clone_bio(struct bio *clone, int error) * the remainder. */ return; - else if (error) { + else if (bio->bi_error) { /* * Don't notice the error to the upper layer yet. * The error handling decision is made by the target driver, * when the request is completed. */ - tio->error = error; + tio->error = bio->bi_error; return; } diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index 1277eb26b58a..4a8e15058e8b 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -70,7 +70,7 @@ #include -static void faulty_fail(struct bio *bio, int error) +static void faulty_fail(struct bio *bio) { struct bio *b = bio->bi_private; @@ -181,7 +181,7 @@ static void make_request(struct mddev *mddev, struct bio *bio) /* special case - don't decrement, don't generic_make_request, * just fail immediately */ - bio_endio(bio, -EIO); + bio_io_error(bio); return; } diff --git a/drivers/md/linear.c b/drivers/md/linear.c index fa7d577f3d12..aefd66142eef 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -297,7 +297,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) if (unlikely((split->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(split->bi_bdev)))) { /* Just ignore it */ - bio_endio(split, 0); + bio_endio(split); } else generic_make_request(split); } while (split != bio); diff --git a/drivers/md/md.c b/drivers/md/md.c index d429c30cd514..ac4381a6625c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -263,7 +263,9 @@ static void md_make_request(struct request_queue *q, struct bio *bio) return; } if (mddev->ro == 1 && unlikely(rw == WRITE)) { - bio_endio(bio, bio_sectors(bio) == 0 ? 0 : -EROFS); + if (bio_sectors(bio) != 0) + bio->bi_error = -EROFS; + bio_endio(bio); return; } smp_rmb(); /* Ensure implications of 'active' are visible */ @@ -377,7 +379,7 @@ static int md_mergeable_bvec(struct request_queue *q, * Generic flush handling for md */ -static void md_end_flush(struct bio *bio, int err) +static void md_end_flush(struct bio *bio) { struct md_rdev *rdev = bio->bi_private; struct mddev *mddev = rdev->mddev; @@ -433,7 +435,7 @@ static void md_submit_flush_data(struct work_struct *ws) if (bio->bi_iter.bi_size == 0) /* an empty barrier - all done */ - bio_endio(bio, 0); + bio_endio(bio); else { bio->bi_rw &= ~REQ_FLUSH; mddev->pers->make_request(mddev, bio); @@ -728,15 +730,13 @@ void md_rdev_clear(struct md_rdev *rdev) } EXPORT_SYMBOL_GPL(md_rdev_clear); -static void super_written(struct bio *bio, int error) +static void super_written(struct bio *bio) { struct md_rdev *rdev = bio->bi_private; struct mddev *mddev = rdev->mddev; - if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) { - printk("md: super_written gets error=%d, uptodate=%d\n", - error, test_bit(BIO_UPTODATE, &bio->bi_flags)); - WARN_ON(test_bit(BIO_UPTODATE, &bio->bi_flags)); + if (bio->bi_error) { + printk("md: super_written gets error=%d\n", bio->bi_error); md_error(mddev, rdev); } @@ -791,7 +791,7 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size, bio_add_page(bio, page, size, 0); submit_bio_wait(rw, bio); - ret = test_bit(BIO_UPTODATE, &bio->bi_flags); + ret = !bio->bi_error; bio_put(bio); return ret; } diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index ac3ede2bd00e..082a489af9d3 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -77,18 +77,18 @@ static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err) struct bio *bio = mp_bh->master_bio; struct mpconf *conf = mp_bh->mddev->private; - bio_endio(bio, err); + bio->bi_error = err; + bio_endio(bio); mempool_free(mp_bh, conf->pool); } -static void multipath_end_request(struct bio *bio, int error) +static void multipath_end_request(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct multipath_bh *mp_bh = bio->bi_private; struct mpconf *conf = mp_bh->mddev->private; struct md_rdev *rdev = conf->multipaths[mp_bh->path].rdev; - if (uptodate) + if (!bio->bi_error) multipath_end_bh_io(mp_bh, 0); else if (!(bio->bi_rw & REQ_RAHEAD)) { /* @@ -101,7 +101,7 @@ static void multipath_end_request(struct bio *bio, int error) (unsigned long long)bio->bi_iter.bi_sector); multipath_reschedule_retry(mp_bh); } else - multipath_end_bh_io(mp_bh, error); + multipath_end_bh_io(mp_bh, bio->bi_error); rdev_dec_pending(rdev, conf->mddev); } @@ -123,7 +123,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio) mp_bh->path = multipath_map(conf); if (mp_bh->path < 0) { - bio_endio(bio, -EIO); + bio_io_error(bio); mempool_free(mp_bh, conf->pool); return; } diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index efb654eb5399..e6e0ae56f66b 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -543,7 +543,7 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) if (unlikely((split->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(split->bi_bdev)))) { /* Just ignore it */ - bio_endio(split, 0); + bio_endio(split); } else generic_make_request(split); } while (split != bio); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index f80f1af61ce7..9aa7d1fb2bc1 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -255,9 +255,10 @@ static void call_bio_endio(struct r1bio *r1_bio) done = 1; if (!test_bit(R1BIO_Uptodate, &r1_bio->state)) - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; + if (done) { - bio_endio(bio, 0); + bio_endio(bio); /* * Wake up any possible resync thread that waits for the device * to go idle. @@ -312,9 +313,9 @@ static int find_bio_disk(struct r1bio *r1_bio, struct bio *bio) return mirror; } -static void raid1_end_read_request(struct bio *bio, int error) +static void raid1_end_read_request(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + int uptodate = !bio->bi_error; struct r1bio *r1_bio = bio->bi_private; int mirror; struct r1conf *conf = r1_bio->mddev->private; @@ -397,9 +398,8 @@ static void r1_bio_write_done(struct r1bio *r1_bio) } } -static void raid1_end_write_request(struct bio *bio, int error) +static void raid1_end_write_request(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct r1bio *r1_bio = bio->bi_private; int mirror, behind = test_bit(R1BIO_BehindIO, &r1_bio->state); struct r1conf *conf = r1_bio->mddev->private; @@ -410,7 +410,7 @@ static void raid1_end_write_request(struct bio *bio, int error) /* * 'one mirror IO has finished' event handler: */ - if (!uptodate) { + if (bio->bi_error) { set_bit(WriteErrorSeen, &conf->mirrors[mirror].rdev->flags); if (!test_and_set_bit(WantReplacement, @@ -793,7 +793,7 @@ static void flush_pending_writes(struct r1conf *conf) if (unlikely((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) /* Just ignore it */ - bio_endio(bio, 0); + bio_endio(bio); else generic_make_request(bio); bio = next; @@ -1068,7 +1068,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule) if (unlikely((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) /* Just ignore it */ - bio_endio(bio, 0); + bio_endio(bio); else generic_make_request(bio); bio = next; @@ -1734,7 +1734,7 @@ abort: return err; } -static void end_sync_read(struct bio *bio, int error) +static void end_sync_read(struct bio *bio) { struct r1bio *r1_bio = bio->bi_private; @@ -1745,16 +1745,16 @@ static void end_sync_read(struct bio *bio, int error) * or re-read if the read failed. * We don't do much here, just schedule handling by raid1d */ - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) + if (!bio->bi_error) set_bit(R1BIO_Uptodate, &r1_bio->state); if (atomic_dec_and_test(&r1_bio->remaining)) reschedule_retry(r1_bio); } -static void end_sync_write(struct bio *bio, int error) +static void end_sync_write(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + int uptodate = !bio->bi_error; struct r1bio *r1_bio = bio->bi_private; struct mddev *mddev = r1_bio->mddev; struct r1conf *conf = mddev->private; @@ -1941,7 +1941,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio) idx ++; } set_bit(R1BIO_Uptodate, &r1_bio->state); - set_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = 0; return 1; } @@ -1965,15 +1965,14 @@ static void process_checks(struct r1bio *r1_bio) for (i = 0; i < conf->raid_disks * 2; i++) { int j; int size; - int uptodate; + int error; struct bio *b = r1_bio->bios[i]; if (b->bi_end_io != end_sync_read) continue; - /* fixup the bio for reuse, but preserve BIO_UPTODATE */ - uptodate = test_bit(BIO_UPTODATE, &b->bi_flags); + /* fixup the bio for reuse, but preserve errno */ + error = b->bi_error; bio_reset(b); - if (!uptodate) - clear_bit(BIO_UPTODATE, &b->bi_flags); + b->bi_error = error; b->bi_vcnt = vcnt; b->bi_iter.bi_size = r1_bio->sectors << 9; b->bi_iter.bi_sector = r1_bio->sector + @@ -1996,7 +1995,7 @@ static void process_checks(struct r1bio *r1_bio) } for (primary = 0; primary < conf->raid_disks * 2; primary++) if (r1_bio->bios[primary]->bi_end_io == end_sync_read && - test_bit(BIO_UPTODATE, &r1_bio->bios[primary]->bi_flags)) { + !r1_bio->bios[primary]->bi_error) { r1_bio->bios[primary]->bi_end_io = NULL; rdev_dec_pending(conf->mirrors[primary].rdev, mddev); break; @@ -2006,14 +2005,14 @@ static void process_checks(struct r1bio *r1_bio) int j; struct bio *pbio = r1_bio->bios[primary]; struct bio *sbio = r1_bio->bios[i]; - int uptodate = test_bit(BIO_UPTODATE, &sbio->bi_flags); + int error = sbio->bi_error; if (sbio->bi_end_io != end_sync_read) continue; - /* Now we can 'fixup' the BIO_UPTODATE flag */ - set_bit(BIO_UPTODATE, &sbio->bi_flags); + /* Now we can 'fixup' the error value */ + sbio->bi_error = 0; - if (uptodate) { + if (!error) { for (j = vcnt; j-- ; ) { struct page *p, *s; p = pbio->bi_io_vec[j].bv_page; @@ -2028,7 +2027,7 @@ static void process_checks(struct r1bio *r1_bio) if (j >= 0) atomic64_add(r1_bio->sectors, &mddev->resync_mismatches); if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery) - && uptodate)) { + && !error)) { /* No need to write to this device. */ sbio->bi_end_io = NULL; rdev_dec_pending(conf->mirrors[i].rdev, mddev); @@ -2269,11 +2268,11 @@ static void handle_sync_write_finished(struct r1conf *conf, struct r1bio *r1_bio struct bio *bio = r1_bio->bios[m]; if (bio->bi_end_io == NULL) continue; - if (test_bit(BIO_UPTODATE, &bio->bi_flags) && + if (!bio->bi_error && test_bit(R1BIO_MadeGood, &r1_bio->state)) { rdev_clear_badblocks(rdev, r1_bio->sector, s, 0); } - if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && + if (bio->bi_error && test_bit(R1BIO_WriteError, &r1_bio->state)) { if (!rdev_set_badblocks(rdev, r1_bio->sector, s, 0)) md_error(conf->mddev, rdev); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 940f2f365461..929e9a26d81b 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -101,7 +101,7 @@ static int _enough(struct r10conf *conf, int previous, int ignore); static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *skipped); static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio); -static void end_reshape_write(struct bio *bio, int error); +static void end_reshape_write(struct bio *bio); static void end_reshape(struct r10conf *conf); static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data) @@ -307,9 +307,9 @@ static void raid_end_bio_io(struct r10bio *r10_bio) } else done = 1; if (!test_bit(R10BIO_Uptodate, &r10_bio->state)) - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; if (done) { - bio_endio(bio, 0); + bio_endio(bio); /* * Wake up any possible resync thread that waits for the device * to go idle. @@ -358,9 +358,9 @@ static int find_bio_disk(struct r10conf *conf, struct r10bio *r10_bio, return r10_bio->devs[slot].devnum; } -static void raid10_end_read_request(struct bio *bio, int error) +static void raid10_end_read_request(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + int uptodate = !bio->bi_error; struct r10bio *r10_bio = bio->bi_private; int slot, dev; struct md_rdev *rdev; @@ -438,9 +438,8 @@ static void one_write_done(struct r10bio *r10_bio) } } -static void raid10_end_write_request(struct bio *bio, int error) +static void raid10_end_write_request(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct r10bio *r10_bio = bio->bi_private; int dev; int dec_rdev = 1; @@ -460,7 +459,7 @@ static void raid10_end_write_request(struct bio *bio, int error) /* * this branch is our 'one mirror IO has finished' event handler: */ - if (!uptodate) { + if (bio->bi_error) { if (repl) /* Never record new bad blocks to replacement, * just fail it. @@ -957,7 +956,7 @@ static void flush_pending_writes(struct r10conf *conf) if (unlikely((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) /* Just ignore it */ - bio_endio(bio, 0); + bio_endio(bio); else generic_make_request(bio); bio = next; @@ -1133,7 +1132,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule) if (unlikely((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) /* Just ignore it */ - bio_endio(bio, 0); + bio_endio(bio); else generic_make_request(bio); bio = next; @@ -1916,7 +1915,7 @@ abort: return err; } -static void end_sync_read(struct bio *bio, int error) +static void end_sync_read(struct bio *bio) { struct r10bio *r10_bio = bio->bi_private; struct r10conf *conf = r10_bio->mddev->private; @@ -1928,7 +1927,7 @@ static void end_sync_read(struct bio *bio, int error) } else d = find_bio_disk(conf, r10_bio, bio, NULL, NULL); - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) + if (!bio->bi_error) set_bit(R10BIO_Uptodate, &r10_bio->state); else /* The write handler will notice the lack of @@ -1977,9 +1976,8 @@ static void end_sync_request(struct r10bio *r10_bio) } } -static void end_sync_write(struct bio *bio, int error) +static void end_sync_write(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct r10bio *r10_bio = bio->bi_private; struct mddev *mddev = r10_bio->mddev; struct r10conf *conf = mddev->private; @@ -1996,7 +1994,7 @@ static void end_sync_write(struct bio *bio, int error) else rdev = conf->mirrors[d].rdev; - if (!uptodate) { + if (bio->bi_error) { if (repl) md_error(mddev, rdev); else { @@ -2044,7 +2042,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) /* find the first device with a block */ for (i=0; icopies; i++) - if (test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags)) + if (!r10_bio->devs[i].bio->bi_error) break; if (i == conf->copies) @@ -2064,7 +2062,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) continue; if (i == first) continue; - if (test_bit(BIO_UPTODATE, &r10_bio->devs[i].bio->bi_flags)) { + if (!r10_bio->devs[i].bio->bi_error) { /* We know that the bi_io_vec layout is the same for * both 'first' and 'i', so we just compare them. * All vec entries are PAGE_SIZE; @@ -2706,8 +2704,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) rdev = conf->mirrors[dev].rdev; if (r10_bio->devs[m].bio == NULL) continue; - if (test_bit(BIO_UPTODATE, - &r10_bio->devs[m].bio->bi_flags)) { + if (!r10_bio->devs[m].bio->bi_error) { rdev_clear_badblocks( rdev, r10_bio->devs[m].addr, @@ -2722,8 +2719,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) rdev = conf->mirrors[dev].replacement; if (r10_bio->devs[m].repl_bio == NULL) continue; - if (test_bit(BIO_UPTODATE, - &r10_bio->devs[m].repl_bio->bi_flags)) { + + if (!r10_bio->devs[m].repl_bio->bi_error) { rdev_clear_badblocks( rdev, r10_bio->devs[m].addr, @@ -2748,8 +2745,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) r10_bio->devs[m].addr, r10_bio->sectors, 0); rdev_dec_pending(rdev, conf->mddev); - } else if (bio != NULL && - !test_bit(BIO_UPTODATE, &bio->bi_flags)) { + } else if (bio != NULL && bio->bi_error) { if (!narrow_write_error(r10_bio, m)) { md_error(conf->mddev, rdev); set_bit(R10BIO_Degraded, @@ -3263,7 +3259,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio = r10_bio->devs[i].bio; bio_reset(bio); - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; if (conf->mirrors[d].rdev == NULL || test_bit(Faulty, &conf->mirrors[d].rdev->flags)) continue; @@ -3300,7 +3296,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, /* Need to set up for writing to the replacement */ bio = r10_bio->devs[i].repl_bio; bio_reset(bio); - clear_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = -EIO; sector = r10_bio->devs[i].addr; atomic_inc(&conf->mirrors[d].rdev->nr_pending); @@ -3377,7 +3373,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, if (bio->bi_end_io == end_sync_read) { md_sync_acct(bio->bi_bdev, nr_sectors); - set_bit(BIO_UPTODATE, &bio->bi_flags); + bio->bi_error = 0; generic_make_request(bio); } } @@ -4380,7 +4376,7 @@ read_more: read_bio->bi_end_io = end_sync_read; read_bio->bi_rw = READ; read_bio->bi_flags &= (~0UL << BIO_RESET_BITS); - __set_bit(BIO_UPTODATE, &read_bio->bi_flags); + read_bio->bi_error = 0; read_bio->bi_vcnt = 0; read_bio->bi_iter.bi_size = 0; r10_bio->master_bio = read_bio; @@ -4601,9 +4597,8 @@ static int handle_reshape_read_error(struct mddev *mddev, return 0; } -static void end_reshape_write(struct bio *bio, int error) +static void end_reshape_write(struct bio *bio) { - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct r10bio *r10_bio = bio->bi_private; struct mddev *mddev = r10_bio->mddev; struct r10conf *conf = mddev->private; @@ -4620,7 +4615,7 @@ static void end_reshape_write(struct bio *bio, int error) rdev = conf->mirrors[d].rdev; } - if (!uptodate) { + if (bio->bi_error) { /* FIXME should record badblock */ md_error(mddev, rdev); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 59e44e99eef3..84d6eec1033e 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -233,7 +233,7 @@ static void return_io(struct bio *return_bi) bi->bi_iter.bi_size = 0; trace_block_bio_complete(bdev_get_queue(bi->bi_bdev), bi, 0); - bio_endio(bi, 0); + bio_endio(bi); bi = return_bi; } } @@ -887,9 +887,9 @@ static int use_new_offset(struct r5conf *conf, struct stripe_head *sh) } static void -raid5_end_read_request(struct bio *bi, int error); +raid5_end_read_request(struct bio *bi); static void -raid5_end_write_request(struct bio *bi, int error); +raid5_end_write_request(struct bio *bi); static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) { @@ -2277,12 +2277,11 @@ static void shrink_stripes(struct r5conf *conf) conf->slab_cache = NULL; } -static void raid5_end_read_request(struct bio * bi, int error) +static void raid5_end_read_request(struct bio * bi) { struct stripe_head *sh = bi->bi_private; struct r5conf *conf = sh->raid_conf; int disks = sh->disks, i; - int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); char b[BDEVNAME_SIZE]; struct md_rdev *rdev = NULL; sector_t s; @@ -2291,9 +2290,9 @@ static void raid5_end_read_request(struct bio * bi, int error) if (bi == &sh->dev[i].req) break; - pr_debug("end_read_request %llu/%d, count: %d, uptodate %d.\n", + pr_debug("end_read_request %llu/%d, count: %d, error %d.\n", (unsigned long long)sh->sector, i, atomic_read(&sh->count), - uptodate); + bi->bi_error); if (i == disks) { BUG(); return; @@ -2312,7 +2311,7 @@ static void raid5_end_read_request(struct bio * bi, int error) s = sh->sector + rdev->new_data_offset; else s = sh->sector + rdev->data_offset; - if (uptodate) { + if (!bi->bi_error) { set_bit(R5_UPTODATE, &sh->dev[i].flags); if (test_bit(R5_ReadError, &sh->dev[i].flags)) { /* Note that this cannot happen on a @@ -2400,13 +2399,12 @@ static void raid5_end_read_request(struct bio * bi, int error) release_stripe(sh); } -static void raid5_end_write_request(struct bio *bi, int error) +static void raid5_end_write_request(struct bio *bi) { struct stripe_head *sh = bi->bi_private; struct r5conf *conf = sh->raid_conf; int disks = sh->disks, i; struct md_rdev *uninitialized_var(rdev); - int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); sector_t first_bad; int bad_sectors; int replacement = 0; @@ -2429,23 +2427,23 @@ static void raid5_end_write_request(struct bio *bi, int error) break; } } - pr_debug("end_write_request %llu/%d, count %d, uptodate: %d.\n", + pr_debug("end_write_request %llu/%d, count %d, error: %d.\n", (unsigned long long)sh->sector, i, atomic_read(&sh->count), - uptodate); + bi->bi_error); if (i == disks) { BUG(); return; } if (replacement) { - if (!uptodate) + if (bi->bi_error) md_error(conf->mddev, rdev); else if (is_badblock(rdev, sh->sector, STRIPE_SECTORS, &first_bad, &bad_sectors)) set_bit(R5_MadeGoodRepl, &sh->dev[i].flags); } else { - if (!uptodate) { + if (bi->bi_error) { set_bit(STRIPE_DEGRADED, &sh->state); set_bit(WriteErrorSeen, &rdev->flags); set_bit(R5_WriteError, &sh->dev[i].flags); @@ -2466,7 +2464,7 @@ static void raid5_end_write_request(struct bio *bi, int error) } rdev_dec_pending(rdev, conf->mddev); - if (sh->batch_head && !uptodate && !replacement) + if (sh->batch_head && bi->bi_error && !replacement) set_bit(STRIPE_BATCH_ERR, &sh->batch_head->state); if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags)) @@ -3107,7 +3105,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, while (bi && bi->bi_iter.bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); - clear_bit(BIO_UPTODATE, &bi->bi_flags); + + bi->bi_error = -EIO; if (!raid5_dec_bi_active_stripes(bi)) { md_write_end(conf->mddev); bi->bi_next = *return_bi; @@ -3131,7 +3130,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, while (bi && bi->bi_iter.bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector); - clear_bit(BIO_UPTODATE, &bi->bi_flags); + + bi->bi_error = -EIO; if (!raid5_dec_bi_active_stripes(bi)) { md_write_end(conf->mddev); bi->bi_next = *return_bi; @@ -3156,7 +3156,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, sh->dev[i].sector + STRIPE_SECTORS) { struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); - clear_bit(BIO_UPTODATE, &bi->bi_flags); + + bi->bi_error = -EIO; if (!raid5_dec_bi_active_stripes(bi)) { bi->bi_next = *return_bi; *return_bi = bi; @@ -4749,12 +4750,11 @@ static struct bio *remove_bio_from_retry(struct r5conf *conf) * first). * If the read failed.. */ -static void raid5_align_endio(struct bio *bi, int error) +static void raid5_align_endio(struct bio *bi) { struct bio* raid_bi = bi->bi_private; struct mddev *mddev; struct r5conf *conf; - int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); struct md_rdev *rdev; bio_put(bi); @@ -4766,10 +4766,10 @@ static void raid5_align_endio(struct bio *bi, int error) rdev_dec_pending(rdev, conf->mddev); - if (!error && uptodate) { + if (!bi->bi_error) { trace_block_bio_complete(bdev_get_queue(raid_bi->bi_bdev), raid_bi, 0); - bio_endio(raid_bi, 0); + bio_endio(raid_bi); if (atomic_dec_and_test(&conf->active_aligned_reads)) wake_up(&conf->wait_for_quiescent); return; @@ -5133,7 +5133,7 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi) remaining = raid5_dec_bi_active_stripes(bi); if (remaining == 0) { md_write_end(mddev); - bio_endio(bi, 0); + bio_endio(bi); } } @@ -5297,7 +5297,7 @@ static void make_request(struct mddev *mddev, struct bio * bi) release_stripe_plug(mddev, sh); } else { /* cannot get stripe for read-ahead, just give-up */ - clear_bit(BIO_UPTODATE, &bi->bi_flags); + bi->bi_error = -EIO; break; } } @@ -5311,7 +5311,7 @@ static void make_request(struct mddev *mddev, struct bio * bi) trace_block_bio_complete(bdev_get_queue(bi->bi_bdev), bi, 0); - bio_endio(bi, 0); + bio_endio(bi); } } @@ -5707,7 +5707,7 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio) if (remaining == 0) { trace_block_bio_complete(bdev_get_queue(raid_bio->bi_bdev), raid_bio, 0); - bio_endio(raid_bio, 0); + bio_endio(raid_bio); } if (atomic_dec_and_test(&conf->active_aligned_reads)) wake_up(&conf->wait_for_quiescent); diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c index 4f97b248c236..0df77cb07df6 100644 --- a/drivers/nvdimm/blk.c +++ b/drivers/nvdimm/blk.c @@ -180,7 +180,7 @@ static void nd_blk_make_request(struct request_queue *q, struct bio *bio) * another kernel subsystem, and we just pass it through. */ if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - err = -EIO; + bio->bi_error = -EIO; goto out; } @@ -199,6 +199,7 @@ static void nd_blk_make_request(struct request_queue *q, struct bio *bio) "io error in %s sector %lld, len %d,\n", (rw == READ) ? "READ" : "WRITE", (unsigned long long) iter.bi_sector, len); + bio->bi_error = err; break; } } @@ -206,7 +207,7 @@ static void nd_blk_make_request(struct request_queue *q, struct bio *bio) nd_iostat_end(bio, start); out: - bio_endio(bio, err); + bio_endio(bio); } static int nd_blk_rw_bytes(struct nd_namespace_common *ndns, diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 411c7b2bb37a..341202ed32b4 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -1189,7 +1189,7 @@ static void btt_make_request(struct request_queue *q, struct bio *bio) * another kernel subsystem, and we just pass it through. */ if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - err = -EIO; + bio->bi_error = -EIO; goto out; } @@ -1211,6 +1211,7 @@ static void btt_make_request(struct request_queue *q, struct bio *bio) "io error in %s sector %lld, len %d,\n", (rw == READ) ? "READ" : "WRITE", (unsigned long long) iter.bi_sector, len); + bio->bi_error = err; break; } } @@ -1218,7 +1219,7 @@ static void btt_make_request(struct request_queue *q, struct bio *bio) nd_iostat_end(bio, start); out: - bio_endio(bio, err); + bio_endio(bio); } static int btt_rw_page(struct block_device *bdev, sector_t sector, diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index ade9eb917a4d..4c079d5cb539 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -77,7 +77,7 @@ static void pmem_make_request(struct request_queue *q, struct bio *bio) if (bio_data_dir(bio)) wmb_pmem(); - bio_endio(bio, 0); + bio_endio(bio); } static int pmem_rw_page(struct block_device *bdev, sector_t sector, diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index da212813f2d5..8bcb822b0bac 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -871,7 +871,7 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) } bytes_done += bvec.bv_len; } - bio_endio(bio, 0); + bio_endio(bio); return; fail: bio_io_error(bio); diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 7d4e9397ac31..93856b9b6214 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -220,8 +220,7 @@ static void xpram_make_request(struct request_queue *q, struct bio *bio) index++; } } - set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_endio(bio, 0); + bio_endio(bio); return; fail: bio_io_error(bio); diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 6d88d24e6cce..5a9982f5d5d6 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -306,20 +306,13 @@ static void iblock_complete_cmd(struct se_cmd *cmd) kfree(ibr); } -static void iblock_bio_done(struct bio *bio, int err) +static void iblock_bio_done(struct bio *bio) { struct se_cmd *cmd = bio->bi_private; struct iblock_req *ibr = cmd->priv; - /* - * Set -EIO if !BIO_UPTODATE and the passed is still err=0 - */ - if (!test_bit(BIO_UPTODATE, &bio->bi_flags) && !err) - err = -EIO; - - if (err != 0) { - pr_err("test_bit(BIO_UPTODATE) failed for bio: %p," - " err: %d\n", bio, err); + if (bio->bi_error) { + pr_err("bio error: %p, err: %d\n", bio, bio->bi_error); /* * Bump the ib_bio_err_cnt and release bio. */ @@ -370,15 +363,15 @@ static void iblock_submit_bios(struct bio_list *list, int rw) blk_finish_plug(&plug); } -static void iblock_end_io_flush(struct bio *bio, int err) +static void iblock_end_io_flush(struct bio *bio) { struct se_cmd *cmd = bio->bi_private; - if (err) - pr_err("IBLOCK: cache flush failed: %d\n", err); + if (bio->bi_error) + pr_err("IBLOCK: cache flush failed: %d\n", bio->bi_error); if (cmd) { - if (err) + if (bio->bi_error) target_complete_cmd(cmd, SAM_STAT_CHECK_CONDITION); else target_complete_cmd(cmd, SAM_STAT_GOOD); diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 08e9084ee615..de18790eb21c 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -852,7 +852,7 @@ static ssize_t pscsi_show_configfs_dev_params(struct se_device *dev, char *b) return bl; } -static void pscsi_bi_endio(struct bio *bio, int error) +static void pscsi_bi_endio(struct bio *bio) { bio_put(bio); } @@ -973,7 +973,7 @@ fail: while (*hbio) { bio = *hbio; *hbio = (*hbio)->bi_next; - bio_endio(bio, 0); /* XXX: should be error */ + bio_endio(bio); } return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } @@ -1061,7 +1061,7 @@ fail_free_bio: while (hbio) { struct bio *bio = hbio; hbio = hbio->bi_next; - bio_endio(bio, 0); /* XXX: should be error */ + bio_endio(bio); } ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; fail: diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index ce7dec88f4b8..541fbfaed276 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -343,7 +343,7 @@ static int btrfsic_process_written_superblock( struct btrfsic_state *state, struct btrfsic_block *const block, struct btrfs_super_block *const super_hdr); -static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status); +static void btrfsic_bio_end_io(struct bio *bp); static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate); static int btrfsic_is_block_ref_by_superblock(const struct btrfsic_state *state, const struct btrfsic_block *block, @@ -2207,7 +2207,7 @@ continue_loop: goto again; } -static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status) +static void btrfsic_bio_end_io(struct bio *bp) { struct btrfsic_block *block = (struct btrfsic_block *)bp->bi_private; int iodone_w_error; @@ -2215,7 +2215,7 @@ static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status) /* mutex is not held! This is not save if IO is not yet completed * on umount */ iodone_w_error = 0; - if (bio_error_status) + if (bp->bi_error) iodone_w_error = 1; BUG_ON(NULL == block); @@ -2230,7 +2230,7 @@ static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status) BTRFSIC_PRINT_MASK_END_IO_BIO_BH)) printk(KERN_INFO "bio_end_io(err=%d) for %c @%llu (%s/%llu/%d)\n", - bio_error_status, + bp->bi_error, btrfsic_get_block_type(dev_state->state, block), block->logical_bytenr, dev_state->name, block->dev_bytenr, block->mirror_num); @@ -2252,7 +2252,7 @@ static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status) block = next_block; } while (NULL != block); - bp->bi_end_io(bp, bio_error_status); + bp->bi_end_io(bp); } static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate) diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index ce62324c78e7..302266ec2cdb 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -152,7 +152,7 @@ fail: * The compressed pages are freed here, and it must be run * in process context */ -static void end_compressed_bio_read(struct bio *bio, int err) +static void end_compressed_bio_read(struct bio *bio) { struct compressed_bio *cb = bio->bi_private; struct inode *inode; @@ -160,7 +160,7 @@ static void end_compressed_bio_read(struct bio *bio, int err) unsigned long index; int ret; - if (err) + if (bio->bi_error) cb->errors = 1; /* if there are more bios still pending for this compressed @@ -210,7 +210,7 @@ csum_failed: bio_for_each_segment_all(bvec, cb->orig_bio, i) SetPageChecked(bvec->bv_page); - bio_endio(cb->orig_bio, 0); + bio_endio(cb->orig_bio); } /* finally free the cb struct */ @@ -266,7 +266,7 @@ static noinline void end_compressed_writeback(struct inode *inode, * This also calls the writeback end hooks for the file pages so that * metadata and checksums can be updated in the file. */ -static void end_compressed_bio_write(struct bio *bio, int err) +static void end_compressed_bio_write(struct bio *bio) { struct extent_io_tree *tree; struct compressed_bio *cb = bio->bi_private; @@ -274,7 +274,7 @@ static void end_compressed_bio_write(struct bio *bio, int err) struct page *page; unsigned long index; - if (err) + if (bio->bi_error) cb->errors = 1; /* if there are more bios still pending for this compressed @@ -293,7 +293,7 @@ static void end_compressed_bio_write(struct bio *bio, int err) cb->start, cb->start + cb->len - 1, NULL, - err ? 0 : 1); + bio->bi_error ? 0 : 1); cb->compressed_pages[0]->mapping = NULL; end_compressed_writeback(inode, cb); @@ -697,8 +697,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); - if (ret) - bio_endio(comp_bio, ret); + if (ret) { + bio->bi_error = ret; + bio_endio(comp_bio); + } bio_put(comp_bio); @@ -724,8 +726,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, } ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); - if (ret) - bio_endio(comp_bio, ret); + if (ret) { + bio->bi_error = ret; + bio_endio(comp_bio); + } bio_put(comp_bio); return 0; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index a9aadb2ad525..a8c0de888a9d 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -703,7 +703,7 @@ static int btree_io_failed_hook(struct page *page, int failed_mirror) return -EIO; /* we fixed nothing */ } -static void end_workqueue_bio(struct bio *bio, int err) +static void end_workqueue_bio(struct bio *bio) { struct btrfs_end_io_wq *end_io_wq = bio->bi_private; struct btrfs_fs_info *fs_info; @@ -711,7 +711,7 @@ static void end_workqueue_bio(struct bio *bio, int err) btrfs_work_func_t func; fs_info = end_io_wq->info; - end_io_wq->error = err; + end_io_wq->error = bio->bi_error; if (bio->bi_rw & REQ_WRITE) { if (end_io_wq->metadata == BTRFS_WQ_ENDIO_METADATA) { @@ -808,7 +808,8 @@ static void run_one_async_done(struct btrfs_work *work) /* If an error occured we just want to clean up the bio and move on */ if (async->error) { - bio_endio(async->bio, async->error); + async->bio->bi_error = async->error; + bio_endio(async->bio); return; } @@ -908,8 +909,10 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio, * submission context. Just jump into btrfs_map_bio */ ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1); - if (ret) - bio_endio(bio, ret); + if (ret) { + bio->bi_error = ret; + bio_endio(bio); + } return ret; } @@ -960,10 +963,13 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, __btree_submit_bio_done); } - if (ret) { + if (ret) + goto out_w_error; + return 0; + out_w_error: - bio_endio(bio, ret); - } + bio->bi_error = ret; + bio_endio(bio); return ret; } @@ -1735,16 +1741,15 @@ static void end_workqueue_fn(struct btrfs_work *work) { struct bio *bio; struct btrfs_end_io_wq *end_io_wq; - int error; end_io_wq = container_of(work, struct btrfs_end_io_wq, work); bio = end_io_wq->bio; - error = end_io_wq->error; + bio->bi_error = end_io_wq->error; bio->bi_private = end_io_wq->private; bio->bi_end_io = end_io_wq->end_io; kmem_cache_free(btrfs_end_io_wq_cache, end_io_wq); - bio_endio(bio, error); + bio_endio(bio); } static int cleaner_kthread(void *arg) @@ -3323,10 +3328,8 @@ static int write_dev_supers(struct btrfs_device *device, * endio for the write_dev_flush, this will wake anyone waiting * for the barrier when it is done */ -static void btrfs_end_empty_barrier(struct bio *bio, int err) +static void btrfs_end_empty_barrier(struct bio *bio) { - if (err) - clear_bit(BIO_UPTODATE, &bio->bi_flags); if (bio->bi_private) complete(bio->bi_private); bio_put(bio); @@ -3354,8 +3357,8 @@ static int write_dev_flush(struct btrfs_device *device, int wait) wait_for_completion(&device->flush_wait); - if (!bio_flagged(bio, BIO_UPTODATE)) { - ret = -EIO; + if (bio->bi_error) { + ret = bio->bi_error; btrfs_dev_stat_inc_and_print(device, BTRFS_DEV_STAT_FLUSH_ERRS); } diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 02d05817cbdf..c22f175ed024 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2486,7 +2486,7 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end) * Scheduling is not allowed, so the extent state tree is expected * to have one and only one object corresponding to this IO. */ -static void end_bio_extent_writepage(struct bio *bio, int err) +static void end_bio_extent_writepage(struct bio *bio) { struct bio_vec *bvec; u64 start; @@ -2516,7 +2516,7 @@ static void end_bio_extent_writepage(struct bio *bio, int err) start = page_offset(page); end = start + bvec->bv_offset + bvec->bv_len - 1; - if (end_extent_writepage(page, err, start, end)) + if (end_extent_writepage(page, bio->bi_error, start, end)) continue; end_page_writeback(page); @@ -2548,10 +2548,10 @@ endio_readpage_release_extent(struct extent_io_tree *tree, u64 start, u64 len, * Scheduling is not allowed, so the extent state tree is expected * to have one and only one object corresponding to this IO. */ -static void end_bio_extent_readpage(struct bio *bio, int err) +static void end_bio_extent_readpage(struct bio *bio) { struct bio_vec *bvec; - int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); + int uptodate = !bio->bi_error; struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); struct extent_io_tree *tree; u64 offset = 0; @@ -2564,16 +2564,13 @@ static void end_bio_extent_readpage(struct bio *bio, int err) int ret; int i; - if (err) - uptodate = 0; - bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; struct inode *inode = page->mapping->host; pr_debug("end_bio_extent_readpage: bi_sector=%llu, err=%d, " - "mirror=%u\n", (u64)bio->bi_iter.bi_sector, err, - io_bio->mirror_num); + "mirror=%u\n", (u64)bio->bi_iter.bi_sector, + bio->bi_error, io_bio->mirror_num); tree = &BTRFS_I(inode)->io_tree; /* We always issue full-page reads, but if some block @@ -2614,8 +2611,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) if (tree->ops && tree->ops->readpage_io_failed_hook) { ret = tree->ops->readpage_io_failed_hook(page, mirror); - if (!ret && !err && - test_bit(BIO_UPTODATE, &bio->bi_flags)) + if (!ret && !bio->bi_error) uptodate = 1; } else { /* @@ -2631,10 +2627,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) ret = bio_readpage_error(bio, offset, page, start, end, mirror); if (ret == 0) { - uptodate = - test_bit(BIO_UPTODATE, &bio->bi_flags); - if (err) - uptodate = 0; + uptodate = !bio->bi_error; offset += len; continue; } @@ -2684,7 +2677,7 @@ readpage_ok: endio_readpage_release_extent(tree, extent_start, extent_len, uptodate); if (io_bio->end_io) - io_bio->end_io(io_bio, err); + io_bio->end_io(io_bio, bio->bi_error); bio_put(bio); } @@ -3696,7 +3689,7 @@ static void set_btree_ioerr(struct page *page) } } -static void end_bio_extent_buffer_writepage(struct bio *bio, int err) +static void end_bio_extent_buffer_writepage(struct bio *bio) { struct bio_vec *bvec; struct extent_buffer *eb; @@ -3709,7 +3702,8 @@ static void end_bio_extent_buffer_writepage(struct bio *bio, int err) BUG_ON(!eb); done = atomic_dec_and_test(&eb->io_pages); - if (err || test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) { + if (bio->bi_error || + test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) { ClearPageUptodate(page); set_btree_ioerr(page); } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b33c0cf02668..6b8becfe2057 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1845,8 +1845,10 @@ static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio, int ret; ret = btrfs_map_bio(root, rw, bio, mirror_num, 1); - if (ret) - bio_endio(bio, ret); + if (ret) { + bio->bi_error = ret; + bio_endio(bio); + } return ret; } @@ -1906,8 +1908,10 @@ mapit: ret = btrfs_map_bio(root, rw, bio, mirror_num, 0); out: - if (ret < 0) - bio_endio(bio, ret); + if (ret < 0) { + bio->bi_error = ret; + bio_endio(bio); + } return ret; } @@ -7689,13 +7693,13 @@ struct btrfs_retry_complete { int uptodate; }; -static void btrfs_retry_endio_nocsum(struct bio *bio, int err) +static void btrfs_retry_endio_nocsum(struct bio *bio) { struct btrfs_retry_complete *done = bio->bi_private; struct bio_vec *bvec; int i; - if (err) + if (bio->bi_error) goto end; done->uptodate = 1; @@ -7744,7 +7748,7 @@ try_again: return 0; } -static void btrfs_retry_endio(struct bio *bio, int err) +static void btrfs_retry_endio(struct bio *bio) { struct btrfs_retry_complete *done = bio->bi_private; struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); @@ -7753,7 +7757,7 @@ static void btrfs_retry_endio(struct bio *bio, int err) int ret; int i; - if (err) + if (bio->bi_error) goto end; uptodate = 1; @@ -7836,12 +7840,13 @@ static int btrfs_subio_endio_read(struct inode *inode, } } -static void btrfs_endio_direct_read(struct bio *bio, int err) +static void btrfs_endio_direct_read(struct bio *bio) { struct btrfs_dio_private *dip = bio->bi_private; struct inode *inode = dip->inode; struct bio *dio_bio; struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); + int err = bio->bi_error; if (dip->flags & BTRFS_DIO_ORIG_BIO_SUBMITTED) err = btrfs_subio_endio_read(inode, io_bio, err); @@ -7852,17 +7857,14 @@ static void btrfs_endio_direct_read(struct bio *bio, int err) kfree(dip); - /* If we had a csum failure make sure to clear the uptodate flag */ - if (err) - clear_bit(BIO_UPTODATE, &dio_bio->bi_flags); - dio_end_io(dio_bio, err); + dio_end_io(dio_bio, bio->bi_error); if (io_bio->end_io) io_bio->end_io(io_bio, err); bio_put(bio); } -static void btrfs_endio_direct_write(struct bio *bio, int err) +static void btrfs_endio_direct_write(struct bio *bio) { struct btrfs_dio_private *dip = bio->bi_private; struct inode *inode = dip->inode; @@ -7876,7 +7878,8 @@ static void btrfs_endio_direct_write(struct bio *bio, int err) again: ret = btrfs_dec_test_first_ordered_pending(inode, &ordered, &ordered_offset, - ordered_bytes, !err); + ordered_bytes, + !bio->bi_error); if (!ret) goto out_test; @@ -7899,10 +7902,7 @@ out_test: kfree(dip); - /* If we had an error make sure to clear the uptodate flag */ - if (err) - clear_bit(BIO_UPTODATE, &dio_bio->bi_flags); - dio_end_io(dio_bio, err); + dio_end_io(dio_bio, bio->bi_error); bio_put(bio); } @@ -7917,9 +7917,10 @@ static int __btrfs_submit_bio_start_direct_io(struct inode *inode, int rw, return 0; } -static void btrfs_end_dio_bio(struct bio *bio, int err) +static void btrfs_end_dio_bio(struct bio *bio) { struct btrfs_dio_private *dip = bio->bi_private; + int err = bio->bi_error; if (err) btrfs_warn(BTRFS_I(dip->inode)->root->fs_info, @@ -7948,8 +7949,8 @@ static void btrfs_end_dio_bio(struct bio *bio, int err) if (dip->errors) { bio_io_error(dip->orig_bio); } else { - set_bit(BIO_UPTODATE, &dip->dio_bio->bi_flags); - bio_endio(dip->orig_bio, 0); + dip->dio_bio->bi_error = 0; + bio_endio(dip->orig_bio); } out: bio_put(bio); @@ -8220,7 +8221,8 @@ free_ordered: * callbacks - they require an allocated dip and a clone of dio_bio. */ if (io_bio && dip) { - bio_endio(io_bio, ret); + io_bio->bi_error = -EIO; + bio_endio(io_bio); /* * The end io callbacks free our dip, do the final put on io_bio * and all the cleanup and final put for dio_bio (through @@ -8247,7 +8249,7 @@ free_ordered: unlock_extent(&BTRFS_I(inode)->io_tree, file_offset, file_offset + dio_bio->bi_iter.bi_size - 1); } - clear_bit(BIO_UPTODATE, &dio_bio->bi_flags); + dio_bio->bi_error = -EIO; /* * Releases and cleans up our dio_bio, no need to bio_put() * nor bio_endio()/bio_io_error() against dio_bio. diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index fa72068bd256..0a02e24900aa 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -851,7 +851,7 @@ static void free_raid_bio(struct btrfs_raid_bio *rbio) * this frees the rbio and runs through all the bios in the * bio_list and calls end_io on them */ -static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err, int uptodate) +static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err) { struct bio *cur = bio_list_get(&rbio->bio_list); struct bio *next; @@ -864,9 +864,8 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err, int uptodate) while (cur) { next = cur->bi_next; cur->bi_next = NULL; - if (uptodate) - set_bit(BIO_UPTODATE, &cur->bi_flags); - bio_endio(cur, err); + cur->bi_error = err; + bio_endio(cur); cur = next; } } @@ -875,9 +874,10 @@ static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err, int uptodate) * end io function used by finish_rmw. When we finally * get here, we've written a full stripe */ -static void raid_write_end_io(struct bio *bio, int err) +static void raid_write_end_io(struct bio *bio) { struct btrfs_raid_bio *rbio = bio->bi_private; + int err = bio->bi_error; if (err) fail_bio_stripe(rbio, bio); @@ -893,7 +893,7 @@ static void raid_write_end_io(struct bio *bio, int err) if (atomic_read(&rbio->error) > rbio->bbio->max_errors) err = -EIO; - rbio_orig_end_io(rbio, err, 0); + rbio_orig_end_io(rbio, err); return; } @@ -1071,7 +1071,7 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio, * devices or if they are not contiguous */ if (last_end == disk_start && stripe->dev->bdev && - test_bit(BIO_UPTODATE, &last->bi_flags) && + !last->bi_error && last->bi_bdev == stripe->dev->bdev) { ret = bio_add_page(last, page, PAGE_CACHE_SIZE, 0); if (ret == PAGE_CACHE_SIZE) @@ -1087,7 +1087,6 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio, bio->bi_iter.bi_size = 0; bio->bi_bdev = stripe->dev->bdev; bio->bi_iter.bi_sector = disk_start >> 9; - set_bit(BIO_UPTODATE, &bio->bi_flags); bio_add_page(bio, page, PAGE_CACHE_SIZE, 0); bio_list_add(bio_list, bio); @@ -1312,13 +1311,12 @@ write_data: bio->bi_private = rbio; bio->bi_end_io = raid_write_end_io; - BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags)); submit_bio(WRITE, bio); } return; cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); } /* @@ -1441,11 +1439,11 @@ static void set_bio_pages_uptodate(struct bio *bio) * This will usually kick off finish_rmw once all the bios are read in, but it * may trigger parity reconstruction if we had any errors along the way */ -static void raid_rmw_end_io(struct bio *bio, int err) +static void raid_rmw_end_io(struct bio *bio) { struct btrfs_raid_bio *rbio = bio->bi_private; - if (err) + if (bio->bi_error) fail_bio_stripe(rbio, bio); else set_bio_pages_uptodate(bio); @@ -1455,7 +1453,6 @@ static void raid_rmw_end_io(struct bio *bio, int err) if (!atomic_dec_and_test(&rbio->stripes_pending)) return; - err = 0; if (atomic_read(&rbio->error) > rbio->bbio->max_errors) goto cleanup; @@ -1469,7 +1466,7 @@ static void raid_rmw_end_io(struct bio *bio, int err) cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); } static void async_rmw_stripe(struct btrfs_raid_bio *rbio) @@ -1572,14 +1569,13 @@ static int raid56_rmw_stripe(struct btrfs_raid_bio *rbio) btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); - BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags)); submit_bio(READ, bio); } /* the actual write will happen once the reads are done */ return 0; cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); return -EIO; finish: @@ -1964,7 +1960,7 @@ cleanup_io: else clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags); - rbio_orig_end_io(rbio, err, err == 0); + rbio_orig_end_io(rbio, err); } else if (err == 0) { rbio->faila = -1; rbio->failb = -1; @@ -1976,7 +1972,7 @@ cleanup_io: else BUG(); } else { - rbio_orig_end_io(rbio, err, 0); + rbio_orig_end_io(rbio, err); } } @@ -1984,7 +1980,7 @@ cleanup_io: * This is called only for stripes we've read from disk to * reconstruct the parity. */ -static void raid_recover_end_io(struct bio *bio, int err) +static void raid_recover_end_io(struct bio *bio) { struct btrfs_raid_bio *rbio = bio->bi_private; @@ -1992,7 +1988,7 @@ static void raid_recover_end_io(struct bio *bio, int err) * we only read stripe pages off the disk, set them * up to date if there were no errors */ - if (err) + if (bio->bi_error) fail_bio_stripe(rbio, bio); else set_bio_pages_uptodate(bio); @@ -2002,7 +1998,7 @@ static void raid_recover_end_io(struct bio *bio, int err) return; if (atomic_read(&rbio->error) > rbio->bbio->max_errors) - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); else __raid_recover_end_io(rbio); } @@ -2094,7 +2090,6 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio) btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); - BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags)); submit_bio(READ, bio); } out: @@ -2102,7 +2097,7 @@ out: cleanup: if (rbio->operation == BTRFS_RBIO_READ_REBUILD) - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); return -EIO; } @@ -2277,11 +2272,12 @@ static int alloc_rbio_essential_pages(struct btrfs_raid_bio *rbio) * end io function used by finish_rmw. When we finally * get here, we've written a full stripe */ -static void raid_write_parity_end_io(struct bio *bio, int err) +static void raid_write_parity_end_io(struct bio *bio) { struct btrfs_raid_bio *rbio = bio->bi_private; + int err = bio->bi_error; - if (err) + if (bio->bi_error) fail_bio_stripe(rbio, bio); bio_put(bio); @@ -2294,7 +2290,7 @@ static void raid_write_parity_end_io(struct bio *bio, int err) if (atomic_read(&rbio->error)) err = -EIO; - rbio_orig_end_io(rbio, err, 0); + rbio_orig_end_io(rbio, err); } static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, @@ -2437,7 +2433,7 @@ submit_write: nr_data = bio_list_size(&bio_list); if (!nr_data) { /* Every parity is right */ - rbio_orig_end_io(rbio, 0, 0); + rbio_orig_end_io(rbio, 0); return; } @@ -2450,13 +2446,12 @@ submit_write: bio->bi_private = rbio; bio->bi_end_io = raid_write_parity_end_io; - BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags)); submit_bio(WRITE, bio); } return; cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); } static inline int is_data_stripe(struct btrfs_raid_bio *rbio, int stripe) @@ -2524,7 +2519,7 @@ static void validate_rbio_for_parity_scrub(struct btrfs_raid_bio *rbio) return; cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); } /* @@ -2535,11 +2530,11 @@ cleanup: * This will usually kick off finish_rmw once all the bios are read in, but it * may trigger parity reconstruction if we had any errors along the way */ -static void raid56_parity_scrub_end_io(struct bio *bio, int err) +static void raid56_parity_scrub_end_io(struct bio *bio) { struct btrfs_raid_bio *rbio = bio->bi_private; - if (err) + if (bio->bi_error) fail_bio_stripe(rbio, bio); else set_bio_pages_uptodate(bio); @@ -2632,14 +2627,13 @@ static void raid56_parity_scrub_stripe(struct btrfs_raid_bio *rbio) btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56); - BUG_ON(!test_bit(BIO_UPTODATE, &bio->bi_flags)); submit_bio(READ, bio); } /* the actual write will happen once the reads are done */ return; cleanup: - rbio_orig_end_io(rbio, -EIO, 0); + rbio_orig_end_io(rbio, -EIO); return; finish: diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 94db0fa5225a..ebb8260186fe 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -278,7 +278,7 @@ static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, u64 physical, struct btrfs_device *dev, u64 flags, 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(struct bio *bio); 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, @@ -295,7 +295,7 @@ static void scrub_free_wr_ctx(struct scrub_wr_ctx *wr_ctx); 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(struct bio *bio); 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); @@ -1429,11 +1429,11 @@ struct scrub_bio_ret { int error; }; -static void scrub_bio_wait_endio(struct bio *bio, int error) +static void scrub_bio_wait_endio(struct bio *bio) { struct scrub_bio_ret *ret = bio->bi_private; - ret->error = error; + ret->error = bio->bi_error; complete(&ret->event); } @@ -1790,12 +1790,12 @@ static void scrub_wr_submit(struct scrub_ctx *sctx) btrfsic_submit_bio(WRITE, sbio->bio); } -static void scrub_wr_bio_end_io(struct bio *bio, int err) +static void scrub_wr_bio_end_io(struct bio *bio) { struct scrub_bio *sbio = bio->bi_private; struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info; - sbio->err = err; + sbio->err = bio->bi_error; sbio->bio = bio; btrfs_init_work(&sbio->work, btrfs_scrubwrc_helper, @@ -2098,7 +2098,7 @@ static void scrub_submit(struct scrub_ctx *sctx) */ printk_ratelimited(KERN_WARNING "BTRFS: scrub_submit(bio bdev == NULL) is unexpected!\n"); - bio_endio(sbio->bio, -EIO); + bio_io_error(sbio->bio); } else { btrfsic_submit_bio(READ, sbio->bio); } @@ -2260,12 +2260,12 @@ leave_nomem: return 0; } -static void scrub_bio_end_io(struct bio *bio, int err) +static void scrub_bio_end_io(struct bio *bio) { struct scrub_bio *sbio = bio->bi_private; struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info; - sbio->err = err; + sbio->err = bio->bi_error; sbio->bio = bio; btrfs_queue_work(fs_info->scrub_workers, &sbio->work); @@ -2672,11 +2672,11 @@ static void scrub_parity_bio_endio_worker(struct btrfs_work *work) scrub_pending_bio_dec(sctx); } -static void scrub_parity_bio_endio(struct bio *bio, int error) +static void scrub_parity_bio_endio(struct bio *bio) { struct scrub_parity *sparity = (struct scrub_parity *)bio->bi_private; - if (error) + if (bio->bi_error) bitmap_or(sparity->ebitmap, sparity->ebitmap, sparity->dbitmap, sparity->nsectors); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index fbe7c104531c..8f2ca18c71f4 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5741,23 +5741,23 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, return 0; } -static inline void btrfs_end_bbio(struct btrfs_bio *bbio, struct bio *bio, int err) +static inline void btrfs_end_bbio(struct btrfs_bio *bbio, struct bio *bio) { bio->bi_private = bbio->private; bio->bi_end_io = bbio->end_io; - bio_endio(bio, err); + bio_endio(bio); btrfs_put_bbio(bbio); } -static void btrfs_end_bio(struct bio *bio, int err) +static void btrfs_end_bio(struct bio *bio) { struct btrfs_bio *bbio = bio->bi_private; int is_orig_bio = 0; - if (err) { + if (bio->bi_error) { atomic_inc(&bbio->error); - if (err == -EIO || err == -EREMOTEIO) { + if (bio->bi_error == -EIO || bio->bi_error == -EREMOTEIO) { unsigned int stripe_index = btrfs_io_bio(bio)->stripe_index; struct btrfs_device *dev; @@ -5795,17 +5795,16 @@ static void btrfs_end_bio(struct bio *bio, int err) * beyond the tolerance of the btrfs bio */ if (atomic_read(&bbio->error) > bbio->max_errors) { - err = -EIO; + bio->bi_error = -EIO; } else { /* * this bio is actually up to date, we didn't * go over the max number of errors */ - set_bit(BIO_UPTODATE, &bio->bi_flags); - err = 0; + bio->bi_error = 0; } - btrfs_end_bbio(bbio, bio, err); + btrfs_end_bbio(bbio, bio); } else if (!is_orig_bio) { bio_put(bio); } @@ -5826,7 +5825,7 @@ static noinline void btrfs_schedule_bio(struct btrfs_root *root, struct btrfs_pending_bios *pending_bios; if (device->missing || !device->bdev) { - bio_endio(bio, -EIO); + bio_io_error(bio); return; } @@ -5973,8 +5972,8 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) btrfs_io_bio(bio)->mirror_num = bbio->mirror_num; bio->bi_iter.bi_sector = logical >> 9; - - btrfs_end_bbio(bbio, bio, -EIO); + bio->bi_error = -EIO; + btrfs_end_bbio(bbio, bio); } } diff --git a/fs/buffer.c b/fs/buffer.c index 1cf7a53a0277..7a49bb84ecb5 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2957,14 +2957,14 @@ sector_t generic_block_bmap(struct address_space *mapping, sector_t block, } EXPORT_SYMBOL(generic_block_bmap); -static void end_bio_bh_io_sync(struct bio *bio, int err) +static void end_bio_bh_io_sync(struct bio *bio) { struct buffer_head *bh = bio->bi_private; if (unlikely (test_bit(BIO_QUIET,&bio->bi_flags))) set_bit(BH_Quiet, &bh->b_state); - bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags)); + bh->b_end_io(bh, !bio->bi_error); bio_put(bio); } diff --git a/fs/direct-io.c b/fs/direct-io.c index 745d2342651a..e1639c8c14d5 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -285,7 +285,7 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio); /* * Asynchronous IO callback. */ -static void dio_bio_end_aio(struct bio *bio, int error) +static void dio_bio_end_aio(struct bio *bio) { struct dio *dio = bio->bi_private; unsigned long remaining; @@ -318,7 +318,7 @@ static void dio_bio_end_aio(struct bio *bio, int error) * During I/O bi_private points at the dio. After I/O, bi_private is used to * implement a singly-linked list of completed BIOs, at dio->bio_list. */ -static void dio_bio_end_io(struct bio *bio, int error) +static void dio_bio_end_io(struct bio *bio) { struct dio *dio = bio->bi_private; unsigned long flags; @@ -345,9 +345,9 @@ void dio_end_io(struct bio *bio, int error) struct dio *dio = bio->bi_private; if (dio->is_async) - dio_bio_end_aio(bio, error); + dio_bio_end_aio(bio); else - dio_bio_end_io(bio, error); + dio_bio_end_io(bio); } EXPORT_SYMBOL_GPL(dio_end_io); @@ -457,11 +457,10 @@ static struct bio *dio_await_one(struct dio *dio) */ static int dio_bio_complete(struct dio *dio, struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec; unsigned i; - if (!uptodate) + if (bio->bi_error) dio->io_error = -EIO; if (dio->is_async && dio->rw == READ) { @@ -476,7 +475,7 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio) } bio_put(bio); } - return uptodate ? 0 : -EIO; + return bio->bi_error; } /* diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 5602450f03f6..aa95566f14be 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -61,7 +61,6 @@ static void buffer_io_error(struct buffer_head *bh) static void ext4_finish_bio(struct bio *bio) { int i; - int error = !test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec; bio_for_each_segment_all(bvec, bio, i) { @@ -88,7 +87,7 @@ static void ext4_finish_bio(struct bio *bio) } #endif - if (error) { + if (bio->bi_error) { SetPageError(page); set_bit(AS_EIO, &page->mapping->flags); } @@ -107,7 +106,7 @@ static void ext4_finish_bio(struct bio *bio) continue; } clear_buffer_async_write(bh); - if (error) + if (bio->bi_error) buffer_io_error(bh); } while ((bh = bh->b_this_page) != head); bit_spin_unlock(BH_Uptodate_Lock, &head->b_state); @@ -310,27 +309,25 @@ ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end) } /* BIO completion function for page writeback */ -static void ext4_end_bio(struct bio *bio, int error) +static void ext4_end_bio(struct bio *bio) { ext4_io_end_t *io_end = bio->bi_private; sector_t bi_sector = bio->bi_iter.bi_sector; BUG_ON(!io_end); bio->bi_end_io = NULL; - if (test_bit(BIO_UPTODATE, &bio->bi_flags)) - error = 0; - if (error) { + if (bio->bi_error) { struct inode *inode = io_end->inode; ext4_warning(inode->i_sb, "I/O error %d writing to inode %lu " "(offset %llu size %ld starting block %llu)", - error, inode->i_ino, + bio->bi_error, inode->i_ino, (unsigned long long) io_end->offset, (long) io_end->size, (unsigned long long) bi_sector >> (inode->i_blkbits - 9)); - mapping_set_error(inode->i_mapping, error); + mapping_set_error(inode->i_mapping, bio->bi_error); } if (io_end->flag & EXT4_IO_END_UNWRITTEN) { diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index ec3ef93a52db..5de5b871c178 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -98,7 +98,7 @@ static inline bool ext4_bio_encrypted(struct bio *bio) * status of that page is hard. See end_buffer_async_read() for the details. * There is no point in duplicating all that complexity. */ -static void mpage_end_io(struct bio *bio, int err) +static void mpage_end_io(struct bio *bio) { struct bio_vec *bv; int i; @@ -106,7 +106,7 @@ static void mpage_end_io(struct bio *bio, int err) if (ext4_bio_encrypted(bio)) { struct ext4_crypto_ctx *ctx = bio->bi_private; - if (err) { + if (bio->bi_error) { ext4_release_crypto_ctx(ctx); } else { INIT_WORK(&ctx->r.work, completion_pages); @@ -118,7 +118,7 @@ static void mpage_end_io(struct bio *bio, int err) bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - if (!err) { + if (!bio->bi_error) { SetPageUptodate(page); } else { ClearPageUptodate(page); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 9bedfa8dd3a5..8f0baa7ffb50 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -29,13 +29,13 @@ static struct kmem_cache *extent_tree_slab; static struct kmem_cache *extent_node_slab; -static void f2fs_read_end_io(struct bio *bio, int err) +static void f2fs_read_end_io(struct bio *bio) { struct bio_vec *bvec; int i; if (f2fs_bio_encrypted(bio)) { - if (err) { + if (bio->bi_error) { f2fs_release_crypto_ctx(bio->bi_private); } else { f2fs_end_io_crypto_work(bio->bi_private, bio); @@ -46,7 +46,7 @@ static void f2fs_read_end_io(struct bio *bio, int err) bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; - if (!err) { + if (!bio->bi_error) { SetPageUptodate(page); } else { ClearPageUptodate(page); @@ -57,7 +57,7 @@ static void f2fs_read_end_io(struct bio *bio, int err) bio_put(bio); } -static void f2fs_write_end_io(struct bio *bio, int err) +static void f2fs_write_end_io(struct bio *bio) { struct f2fs_sb_info *sbi = bio->bi_private; struct bio_vec *bvec; @@ -68,7 +68,7 @@ static void f2fs_write_end_io(struct bio *bio, int err) f2fs_restore_and_release_control_page(&page); - if (unlikely(err)) { + if (unlikely(bio->bi_error)) { set_page_dirty(page); set_bit(AS_EIO, &page->mapping->flags); f2fs_stop_checkpoint(sbi); diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 2c1ae861dc94..c0a1b967deba 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -202,22 +202,22 @@ static void gfs2_end_log_write_bh(struct gfs2_sbd *sdp, struct bio_vec *bvec, * */ -static void gfs2_end_log_write(struct bio *bio, int error) +static void gfs2_end_log_write(struct bio *bio) { struct gfs2_sbd *sdp = bio->bi_private; struct bio_vec *bvec; struct page *page; int i; - if (error) { - sdp->sd_log_error = error; - fs_err(sdp, "Error %d writing to log\n", error); + if (bio->bi_error) { + sdp->sd_log_error = bio->bi_error; + fs_err(sdp, "Error %d writing to log\n", bio->bi_error); } bio_for_each_segment_all(bvec, bio, i) { page = bvec->bv_page; if (page_has_buffers(page)) - gfs2_end_log_write_bh(sdp, bvec, error); + gfs2_end_log_write_bh(sdp, bvec, bio->bi_error); else mempool_free(page, gfs2_page_pool); } diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 1e3a93f2f71d..02586e7eb964 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -171,14 +171,14 @@ static int gfs2_check_sb(struct gfs2_sbd *sdp, int silent) return -EINVAL; } -static void end_bio_io_page(struct bio *bio, int error) +static void end_bio_io_page(struct bio *bio) { struct page *page = bio->bi_private; - if (!error) + if (!bio->bi_error) SetPageUptodate(page); else - pr_warn("error %d reading superblock\n", error); + pr_warn("error %d reading superblock\n", bio->bi_error); unlock_page(page); } diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index bc462dcd7a40..d301acfdb80d 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -2011,7 +2011,7 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp) /*check if journaling to disk has been disabled*/ if (log->no_integrity) { bio->bi_iter.bi_size = 0; - lbmIODone(bio, 0); + lbmIODone(bio); } else { submit_bio(READ_SYNC, bio); } @@ -2158,7 +2158,7 @@ static void lbmStartIO(struct lbuf * bp) /* check if journaling to disk has been disabled */ if (log->no_integrity) { bio->bi_iter.bi_size = 0; - lbmIODone(bio, 0); + lbmIODone(bio); } else { submit_bio(WRITE_SYNC, bio); INCREMENT(lmStat.submitted); @@ -2196,7 +2196,7 @@ static int lbmIOWait(struct lbuf * bp, int flag) * * executed at INTIODONE level */ -static void lbmIODone(struct bio *bio, int error) +static void lbmIODone(struct bio *bio) { struct lbuf *bp = bio->bi_private; struct lbuf *nextbp, *tail; @@ -2212,7 +2212,7 @@ static void lbmIODone(struct bio *bio, int error) bp->l_flag |= lbmDONE; - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { + if (bio->bi_error) { bp->l_flag |= lbmERROR; jfs_err("lbmIODone: I/O error in JFS log"); diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 16a0922beb59..a3eb316b1ac3 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -276,11 +276,11 @@ static void last_read_complete(struct page *page) unlock_page(page); } -static void metapage_read_end_io(struct bio *bio, int err) +static void metapage_read_end_io(struct bio *bio) { struct page *page = bio->bi_private; - if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { + if (bio->bi_error) { printk(KERN_ERR "metapage_read_end_io: I/O error\n"); SetPageError(page); } @@ -331,13 +331,13 @@ static void last_write_complete(struct page *page) end_page_writeback(page); } -static void metapage_write_end_io(struct bio *bio, int err) +static void metapage_write_end_io(struct bio *bio) { struct page *page = bio->bi_private; BUG_ON(!PagePrivate(page)); - if (! test_bit(BIO_UPTODATE, &bio->bi_flags)) { + if (bio->bi_error) { printk(KERN_ERR "metapage_write_end_io: I/O error\n"); SetPageError(page); } diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index 76279e11982d..cea0cc9878b7 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -53,16 +53,14 @@ static int bdev_readpage(void *_sb, struct page *page) static DECLARE_WAIT_QUEUE_HEAD(wq); -static void writeseg_end_io(struct bio *bio, int err) +static void writeseg_end_io(struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct bio_vec *bvec; int i; struct super_block *sb = bio->bi_private; struct logfs_super *super = logfs_super(sb); - BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */ - BUG_ON(err); + BUG_ON(bio->bi_error); /* FIXME: Retry io or write elsewhere */ bio_for_each_segment_all(bvec, bio, i) { end_page_writeback(bvec->bv_page); @@ -153,14 +151,12 @@ static void bdev_writeseg(struct super_block *sb, u64 ofs, size_t len) } -static void erase_end_io(struct bio *bio, int err) +static void erase_end_io(struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct super_block *sb = bio->bi_private; struct logfs_super *super = logfs_super(sb); - BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */ - BUG_ON(err); + BUG_ON(bio->bi_error); /* FIXME: Retry io or write elsewhere */ BUG_ON(bio->bi_vcnt == 0); bio_put(bio); if (atomic_dec_and_test(&super->s_pending_writes)) diff --git a/fs/mpage.c b/fs/mpage.c index ca0244b69de8..abac9361b3f1 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -42,14 +42,14 @@ * status of that page is hard. See end_buffer_async_read() for the details. * There is no point in duplicating all that complexity. */ -static void mpage_end_io(struct bio *bio, int err) +static void mpage_end_io(struct bio *bio) { struct bio_vec *bv; int i; bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; - page_endio(page, bio_data_dir(bio), err); + page_endio(page, bio_data_dir(bio), bio->bi_error); } bio_put(bio); diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index d2554fe140a3..9cd4eb3a1e22 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -116,7 +116,7 @@ bl_submit_bio(int rw, struct bio *bio) static struct bio * bl_alloc_init_bio(int npg, struct block_device *bdev, sector_t disk_sector, - void (*end_io)(struct bio *, int err), struct parallel_io *par) + bio_end_io_t end_io, struct parallel_io *par) { struct bio *bio; @@ -139,8 +139,7 @@ bl_alloc_init_bio(int npg, struct block_device *bdev, sector_t disk_sector, static struct bio * do_add_page_to_bio(struct bio *bio, int npg, int rw, sector_t isect, struct page *page, struct pnfs_block_dev_map *map, - struct pnfs_block_extent *be, - void (*end_io)(struct bio *, int err), + struct pnfs_block_extent *be, bio_end_io_t end_io, struct parallel_io *par, unsigned int offset, int *len) { struct pnfs_block_dev *dev = @@ -183,11 +182,11 @@ retry: return bio; } -static void bl_end_io_read(struct bio *bio, int err) +static void bl_end_io_read(struct bio *bio) { struct parallel_io *par = bio->bi_private; - if (err) { + if (bio->bi_error) { struct nfs_pgio_header *header = par->data; if (!header->pnfs_error) @@ -316,13 +315,12 @@ out: return PNFS_ATTEMPTED; } -static void bl_end_io_write(struct bio *bio, int err) +static void bl_end_io_write(struct bio *bio) { struct parallel_io *par = bio->bi_private; - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct nfs_pgio_header *header = par->data; - if (!uptodate) { + if (bio->bi_error) { if (!header->pnfs_error) header->pnfs_error = -EIO; pnfs_set_lo_fail(header->lseg); diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 42468e5ab3e7..550b10efb14e 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -338,12 +338,11 @@ void nilfs_add_checksums_on_logs(struct list_head *logs, u32 seed) /* * BIO operations */ -static void nilfs_end_bio_write(struct bio *bio, int err) +static void nilfs_end_bio_write(struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct nilfs_segment_buffer *segbuf = bio->bi_private; - if (!uptodate) + if (bio->bi_error) atomic_inc(&segbuf->sb_err); bio_put(bio); diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 16eff45727ee..140de3c93d2e 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -372,14 +372,13 @@ static void o2hb_wait_on_io(struct o2hb_region *reg, wait_for_completion(&wc->wc_io_complete); } -static void o2hb_bio_end_io(struct bio *bio, - int error) +static void o2hb_bio_end_io(struct bio *bio) { struct o2hb_bio_wait_ctxt *wc = bio->bi_private; - if (error) { - mlog(ML_ERROR, "IO Error %d\n", error); - wc->wc_error = error; + if (bio->bi_error) { + mlog(ML_ERROR, "IO Error %d\n", bio->bi_error); + wc->wc_error = bio->bi_error; } o2hb_bio_wait_dec(wc, 1); diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 3859f5e27a4d..3714844a81d8 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -351,12 +351,11 @@ xfs_imap_valid( */ STATIC void xfs_end_bio( - struct bio *bio, - int error) + struct bio *bio) { xfs_ioend_t *ioend = bio->bi_private; - ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error; + ioend->io_error = bio->bi_error; /* Toss bio and pass work off to an xfsdatad thread */ bio->bi_private = NULL; diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index a4b7d92e946c..01bd6781974e 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1096,8 +1096,7 @@ xfs_bwrite( STATIC void xfs_buf_bio_end_io( - struct bio *bio, - int error) + struct bio *bio) { xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private; @@ -1105,10 +1104,10 @@ xfs_buf_bio_end_io( * don't overwrite existing errors - otherwise we can lose errors on * buffers that require multiple bios to complete. */ - if (error) { + if (bio->bi_error) { spin_lock(&bp->b_lock); if (!bp->b_io_error) - bp->b_io_error = error; + bp->b_io_error = bio->bi_error; spin_unlock(&bp->b_lock); } diff --git a/include/linux/bio.h b/include/linux/bio.h index 5e963a6d7c14..6b918177002d 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -195,8 +195,6 @@ static inline bool bvec_gap_to_prev(struct bio_vec *bprv, unsigned int offset) return offset || ((bprv->bv_offset + bprv->bv_len) & (PAGE_SIZE - 1)); } -#define bio_io_error(bio) bio_endio((bio), -EIO) - /* * drivers should _never_ use the all version - the bio may have been split * before it got to the driver and the driver won't own all of it @@ -426,7 +424,14 @@ static inline struct bio *bio_clone_kmalloc(struct bio *bio, gfp_t gfp_mask) } -extern void bio_endio(struct bio *, int); +extern void bio_endio(struct bio *); + +static inline void bio_io_error(struct bio *bio) +{ + bio->bi_error = -EIO; + bio_endio(bio); +} + struct request_queue; extern int bio_phys_segments(struct request_queue *, struct bio *); @@ -717,7 +722,7 @@ extern void bio_integrity_free(struct bio *); extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int); extern bool bio_integrity_enabled(struct bio *bio); extern int bio_integrity_prep(struct bio *); -extern void bio_integrity_endio(struct bio *, int); +extern void bio_integrity_endio(struct bio *); extern void bio_integrity_advance(struct bio *, unsigned int); extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int); extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t); diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 7303b3405520..6164fb8a817b 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -14,7 +14,7 @@ struct page; struct block_device; struct io_context; struct cgroup_subsys_state; -typedef void (bio_end_io_t) (struct bio *, int); +typedef void (bio_end_io_t) (struct bio *); typedef void (bio_destructor_t) (struct bio *); /* @@ -53,6 +53,7 @@ struct bio { struct bvec_iter bi_iter; + int bi_error; /* Number of segments in this BIO after * physical address coalescing is performed. */ @@ -111,7 +112,6 @@ struct bio { /* * bio flags */ -#define BIO_UPTODATE 0 /* ok after I/O completion */ #define BIO_SEG_VALID 1 /* bi_phys_segments valid */ #define BIO_CLONED 2 /* doesn't own data */ #define BIO_BOUNCED 3 /* bio is a bounce bio */ diff --git a/include/linux/swap.h b/include/linux/swap.h index 38874729dc5f..31496d201fdc 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -373,9 +373,9 @@ static inline void mem_cgroup_uncharge_swap(swp_entry_t entry) /* linux/mm/page_io.c */ extern int swap_readpage(struct page *); extern int swap_writepage(struct page *page, struct writeback_control *wbc); -extern void end_swap_bio_write(struct bio *bio, int err); +extern void end_swap_bio_write(struct bio *bio); extern int __swap_writepage(struct page *page, struct writeback_control *wbc, - void (*end_write_func)(struct bio *, int)); + bio_end_io_t end_write_func); extern int swap_set_page_dirty(struct page *page); int add_swap_extent(struct swap_info_struct *sis, unsigned long start_page, diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 2f30ca91e4fa..b2066fb5b10f 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -227,27 +227,23 @@ static void hib_init_batch(struct hib_bio_batch *hb) hb->error = 0; } -static void hib_end_io(struct bio *bio, int error) +static void hib_end_io(struct bio *bio) { struct hib_bio_batch *hb = bio->bi_private; - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; - if (!uptodate || error) { + if (bio->bi_error) { printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)\n", imajor(bio->bi_bdev->bd_inode), iminor(bio->bi_bdev->bd_inode), (unsigned long long)bio->bi_iter.bi_sector); - - if (!error) - error = -EIO; } if (bio_data_dir(bio) == WRITE) put_page(page); - if (error && !hb->error) - hb->error = error; + if (bio->bi_error && !hb->error) + hb->error = bio->bi_error; if (atomic_dec_and_test(&hb->count)) wake_up(&hb->wait); diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index b3e6b39b6cf9..90e72a0c3047 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -778,9 +778,6 @@ static void blk_add_trace_bio(struct request_queue *q, struct bio *bio, if (likely(!bt)) return; - if (!error && !bio_flagged(bio, BIO_UPTODATE)) - error = EIO; - __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, bio->bi_rw, what, error, 0, NULL); } @@ -887,8 +884,7 @@ static void blk_add_trace_split(void *ignore, __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, bio->bi_rw, BLK_TA_SPLIT, - !bio_flagged(bio, BIO_UPTODATE), - sizeof(rpdu), &rpdu); + bio->bi_error, sizeof(rpdu), &rpdu); } } @@ -920,8 +916,8 @@ static void blk_add_trace_bio_remap(void *ignore, r.sector_from = cpu_to_be64(from); __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, - bio->bi_rw, BLK_TA_REMAP, - !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r); + bio->bi_rw, BLK_TA_REMAP, bio->bi_error, + sizeof(r), &r); } /** diff --git a/mm/page_io.c b/mm/page_io.c index 520baa4b04d7..338ce68942a0 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -43,12 +43,11 @@ static struct bio *get_swap_bio(gfp_t gfp_flags, return bio; } -void end_swap_bio_write(struct bio *bio, int err) +void end_swap_bio_write(struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; - if (!uptodate) { + if (bio->bi_error) { SetPageError(page); /* * We failed to write the page out to swap-space. @@ -69,12 +68,11 @@ void end_swap_bio_write(struct bio *bio, int err) bio_put(bio); } -static void end_swap_bio_read(struct bio *bio, int err) +static void end_swap_bio_read(struct bio *bio) { - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct page *page = bio->bi_io_vec[0].bv_page; - if (!uptodate) { + if (bio->bi_error) { SetPageError(page); ClearPageUptodate(page); printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)\n", @@ -254,7 +252,7 @@ static sector_t swap_page_sector(struct page *page) } int __swap_writepage(struct page *page, struct writeback_control *wbc, - void (*end_write_func)(struct bio *, int)) + bio_end_io_t end_write_func) { struct bio *bio; int ret, rw = WRITE; -- cgit v1.3-6-gb490 From b7c44ed9d2fc6b461378c65eaf144ccc80a47772 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 24 Jul 2015 12:37:59 -0600 Subject: block: manipulate bio->bi_flags through helpers Some places use helpers now, others don't. We only have the 'is set' helper, add helpers for setting and clearing flags too. It was a bit of a mess of atomic vs non-atomic access. With BIO_UPTODATE gone, we don't have any risk of concurrent access to the flags. So relax the restriction and don't make any of them atomic. The flags that do have serialization issues (reffed and chained), we already handle those separately. Signed-off-by: Jens Axboe --- block/bio.c | 14 +++++++------- block/blk-core.c | 2 +- block/blk-map.c | 2 +- block/blk-merge.c | 2 +- block/bounce.c | 2 +- drivers/md/raid1.c | 4 ++-- drivers/md/raid10.c | 6 +++--- drivers/md/raid5.c | 2 +- fs/buffer.c | 2 +- include/linux/bio.h | 15 +++++++++++++++ include/linux/blk_types.h | 2 -- 11 files changed, 33 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/block/bio.c b/block/bio.c index a23f489f398f..911ae8f82752 100644 --- a/block/bio.c +++ b/block/bio.c @@ -311,7 +311,7 @@ static void bio_chain_endio(struct bio *bio) */ static inline void bio_inc_remaining(struct bio *bio) { - bio->bi_flags |= (1 << BIO_CHAIN); + bio_set_flag(bio, BIO_CHAIN); smp_mb__before_atomic(); atomic_inc(&bio->__bi_remaining); } @@ -495,7 +495,7 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs) if (unlikely(!bvl)) goto err_free; - bio->bi_flags |= 1 << BIO_OWNS_VEC; + bio_set_flag(bio, BIO_OWNS_VEC); } else if (nr_iovecs) { bvl = bio->bi_inline_vecs; } @@ -580,7 +580,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) * so we don't set nor calculate new physical/hw segment counts here */ bio->bi_bdev = bio_src->bi_bdev; - bio->bi_flags |= 1 << BIO_CLONED; + bio_set_flag(bio, BIO_CLONED); bio->bi_rw = bio_src->bi_rw; bio->bi_iter = bio_src->bi_iter; bio->bi_io_vec = bio_src->bi_io_vec; @@ -829,7 +829,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page /* If we may be able to merge these biovecs, force a recount */ if (bio->bi_vcnt > 1 && (BIOVEC_PHYS_MERGEABLE(bvec-1, bvec))) - bio->bi_flags &= ~(1 << BIO_SEG_VALID); + bio_clear_flag(bio, BIO_SEG_VALID); done: return len; @@ -1390,7 +1390,7 @@ struct bio *bio_map_user_iov(struct request_queue *q, if (iter->type & WRITE) bio->bi_rw |= REQ_WRITE; - bio->bi_flags |= (1 << BIO_USER_MAPPED); + bio_set_flag(bio, BIO_USER_MAPPED); /* * subtle -- if __bio_map_user() ended up bouncing a bio, @@ -1770,7 +1770,7 @@ static inline bool bio_remaining_done(struct bio *bio) BUG_ON(atomic_read(&bio->__bi_remaining) <= 0); if (atomic_dec_and_test(&bio->__bi_remaining)) { - clear_bit(BIO_CHAIN, &bio->bi_flags); + bio_clear_flag(bio, BIO_CHAIN); return true; } @@ -1866,7 +1866,7 @@ void bio_trim(struct bio *bio, int offset, int size) if (offset == 0 && size == bio->bi_iter.bi_size) return; - clear_bit(BIO_SEG_VALID, &bio->bi_flags); + bio_clear_flag(bio, BIO_SEG_VALID); bio_advance(bio, offset << 9); diff --git a/block/blk-core.c b/block/blk-core.c index 7ef15b947b91..d1796b54e97a 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -146,7 +146,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio, bio->bi_error = error; if (unlikely(rq->cmd_flags & REQ_QUIET)) - set_bit(BIO_QUIET, &bio->bi_flags); + bio_set_flag(bio, BIO_QUIET); bio_advance(bio, nbytes); diff --git a/block/blk-map.c b/block/blk-map.c index 5fe1c30bfba7..233841644c9d 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -94,7 +94,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, return PTR_ERR(bio); if (map_data && map_data->null_mapped) - bio->bi_flags |= (1 << BIO_NULL_MAPPED); + bio_set_flag(bio, BIO_NULL_MAPPED); if (bio->bi_iter.bi_size != iter->count) { /* diff --git a/block/blk-merge.c b/block/blk-merge.c index 30a0d9f89017..a455b9860143 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -116,7 +116,7 @@ void blk_recount_segments(struct request_queue *q, struct bio *bio) bio->bi_next = nxt; } - bio->bi_flags |= (1 << BIO_SEG_VALID); + bio_set_flag(bio, BIO_SEG_VALID); } EXPORT_SYMBOL(blk_recount_segments); diff --git a/block/bounce.c b/block/bounce.c index f4db245b9f3a..2c310ea007ee 100644 --- a/block/bounce.c +++ b/block/bounce.c @@ -186,7 +186,7 @@ static int must_snapshot_stable_pages(struct request_queue *q, struct bio *bio) if (!bdi_cap_stable_pages_required(&q->backing_dev_info)) return 0; - return test_bit(BIO_SNAP_STABLE, &bio->bi_flags); + return bio_flagged(bio, BIO_SNAP_STABLE); } #else static int must_snapshot_stable_pages(struct request_queue *q, struct bio *bio) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 9aa7d1fb2bc1..60d0a8626e63 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1157,7 +1157,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) * non-zero, then it is the number of not-completed requests. */ bio->bi_phys_segments = 0; - clear_bit(BIO_SEG_VALID, &bio->bi_flags); + bio_clear_flag(bio, BIO_SEG_VALID); if (rw == READ) { /* @@ -2711,7 +2711,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp /* remove last page from this bio */ bio->bi_vcnt--; bio->bi_iter.bi_size -= len; - __clear_bit(BIO_SEG_VALID, &bio->bi_flags); + bio_clear_flag(bio, BIO_SEG_VALID); } goto bio_full; } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 929e9a26d81b..316ff6f611e9 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1216,7 +1216,7 @@ static void __make_request(struct mddev *mddev, struct bio *bio) * non-zero, then it is the number of not-completed requests. */ bio->bi_phys_segments = 0; - clear_bit(BIO_SEG_VALID, &bio->bi_flags); + bio_clear_flag(bio, BIO_SEG_VALID); if (rw == READ) { /* @@ -3353,7 +3353,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, /* remove last page from this bio */ bio2->bi_vcnt--; bio2->bi_iter.bi_size -= len; - __clear_bit(BIO_SEG_VALID, &bio2->bi_flags); + bio_clear_flag(bio2, BIO_SEG_VALID); } goto bio_full; } @@ -4433,7 +4433,7 @@ read_more: /* Remove last page from this bio */ bio2->bi_vcnt--; bio2->bi_iter.bi_size -= len; - __clear_bit(BIO_SEG_VALID, &bio2->bi_flags); + bio_clear_flag(bio2, BIO_SEG_VALID); } goto bio_full; } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 84d6eec1033e..e3d48775c9df 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -4850,7 +4850,7 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio) rcu_read_unlock(); raid_bio->bi_next = (void*)rdev; align_bi->bi_bdev = rdev->bdev; - __clear_bit(BIO_SEG_VALID, &align_bi->bi_flags); + bio_clear_flag(align_bi, BIO_SEG_VALID); if (!bio_fits_rdev(align_bi) || is_badblock(rdev, align_bi->bi_iter.bi_sector, diff --git a/fs/buffer.c b/fs/buffer.c index 7a49bb84ecb5..7887bb466368 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2961,7 +2961,7 @@ static void end_bio_bh_io_sync(struct bio *bio) { struct buffer_head *bh = bio->bi_private; - if (unlikely (test_bit(BIO_QUIET,&bio->bi_flags))) + if (unlikely(bio_flagged(bio, BIO_QUIET))) set_bit(BH_Quiet, &bh->b_state); bh->b_end_io(bh, !bio->bi_error); diff --git a/include/linux/bio.h b/include/linux/bio.h index 6b918177002d..986e6e19feb5 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -304,6 +304,21 @@ static inline void bio_cnt_set(struct bio *bio, unsigned int count) atomic_set(&bio->__bi_cnt, count); } +static inline bool bio_flagged(struct bio *bio, unsigned int bit) +{ + return (bio->bi_flags & (1UL << bit)) != 0; +} + +static inline void bio_set_flag(struct bio *bio, unsigned int bit) +{ + bio->bi_flags |= (1UL << bit); +} + +static inline void bio_clear_flag(struct bio *bio, unsigned int bit) +{ + bio->bi_flags &= ~(1UL << bit); +} + enum bip_flags { BIP_BLOCK_INTEGRITY = 1 << 0, /* block layer owns integrity data */ BIP_MAPPED_INTEGRITY = 1 << 1, /* ref tag has been remapped */ diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 6164fb8a817b..a765a50e780f 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -129,8 +129,6 @@ struct bio { #define BIO_RESET_BITS 13 #define BIO_OWNS_VEC 13 /* bio_free() should free bvec */ -#define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag))) - /* * top 4 bits of bio flags indicate the pool this bio came from */ -- cgit v1.3-6-gb490 From 5ea75095fe6d683900ccc674fcac375e7df68005 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Mon, 8 Jun 2015 08:20:05 +0200 Subject: usb: gadget: nokia: Add mass storage driver to g_nokia MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds removable mass storage support to g_nokia gadget (for N900). It means that at runtime block device can be exported or unexported. So it does not export anything by default and thus allows to use MyDocs partition as before... [ balbi@ti.com: make it build ] Signed-off-by: Pali Rohár Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/Kconfig | 1 + drivers/usb/gadget/legacy/nokia.c | 102 +++++++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index d5a7102de696..ddef41f6df3e 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -346,6 +346,7 @@ config USB_G_NOKIA select USB_F_OBEX select USB_F_PHONET select USB_F_ECM + select USB_F_MASS_STORAGE help The Nokia composite gadget provides support for acm, obex and phonet in only one composite gadget driver. diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index 4bb498a38a1c..e3791b919996 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -24,6 +24,7 @@ #include "u_phonet.h" #include "u_ecm.h" #include "gadget_chips.h" +#include "f_mass_storage.h" /* Defines */ @@ -34,6 +35,29 @@ USB_GADGET_COMPOSITE_OPTIONS(); USB_ETHERNET_MODULE_PARAMETERS(); +static struct fsg_module_parameters fsg_mod_data = { + .stall = 0, + .luns = 2, + .removable_count = 2, + .removable = { 1, 1, }, +}; + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_DEBUG */ + +FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); + #define NOKIA_VENDOR_ID 0x0421 /* Nokia */ #define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */ @@ -94,6 +118,8 @@ static struct usb_function *f_obex1_cfg2; static struct usb_function *f_obex2_cfg2; static struct usb_function *f_phonet_cfg1; static struct usb_function *f_phonet_cfg2; +static struct usb_function *f_msg_cfg1; +static struct usb_function *f_msg_cfg2; static struct usb_configuration nokia_config_500ma_driver = { @@ -117,6 +143,7 @@ static struct usb_function_instance *fi_ecm; static struct usb_function_instance *fi_obex1; static struct usb_function_instance *fi_obex2; static struct usb_function_instance *fi_phonet; +static struct usb_function_instance *fi_msg; static int nokia_bind_config(struct usb_configuration *c) { @@ -125,6 +152,8 @@ static int nokia_bind_config(struct usb_configuration *c) struct usb_function *f_obex1 = NULL; struct usb_function *f_ecm; struct usb_function *f_obex2 = NULL; + struct usb_function *f_msg; + struct fsg_opts *fsg_opts; int status = 0; int obex1_stat = -1; int obex2_stat = -1; @@ -160,6 +189,12 @@ static int nokia_bind_config(struct usb_configuration *c) goto err_get_ecm; } + f_msg = usb_get_function(fi_msg); + if (IS_ERR(f_msg)) { + status = PTR_ERR(f_msg); + goto err_get_msg; + } + if (!IS_ERR_OR_NULL(f_phonet)) { phonet_stat = usb_add_function(c, f_phonet); if (phonet_stat) @@ -187,21 +222,36 @@ static int nokia_bind_config(struct usb_configuration *c) pr_debug("could not bind ecm config %d\n", status); goto err_ecm; } + + fsg_opts = fsg_opts_from_func_inst(fi_msg); + + status = fsg_common_run_thread(fsg_opts->common); + if (status) + goto err_msg; + + status = usb_add_function(c, f_msg); + if (status) + goto err_msg; + if (c == &nokia_config_500ma_driver) { f_acm_cfg1 = f_acm; f_ecm_cfg1 = f_ecm; f_phonet_cfg1 = f_phonet; f_obex1_cfg1 = f_obex1; f_obex2_cfg1 = f_obex2; + f_msg_cfg1 = f_msg; } else { f_acm_cfg2 = f_acm; f_ecm_cfg2 = f_ecm; f_phonet_cfg2 = f_phonet; f_obex1_cfg2 = f_obex1; f_obex2_cfg2 = f_obex2; + f_msg_cfg2 = f_msg; } return status; +err_msg: + usb_remove_function(c, f_ecm); err_ecm: usb_remove_function(c, f_acm); err_conf: @@ -211,6 +261,8 @@ err_conf: usb_remove_function(c, f_obex1); if (!phonet_stat) usb_remove_function(c, f_phonet); + usb_put_function(f_msg); +err_get_msg: usb_put_function(f_ecm); err_get_ecm: usb_put_function(f_acm); @@ -227,6 +279,8 @@ err_get_acm: static int nokia_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; + struct fsg_opts *fsg_opts; + struct fsg_config fsg_config; int status; status = usb_string_ids_tab(cdev, strings_dev); @@ -267,11 +321,46 @@ static int nokia_bind(struct usb_composite_dev *cdev) goto err_acm_inst; } + fi_msg = usb_get_function_instance("mass_storage"); + if (IS_ERR(fi_msg)) { + status = PTR_ERR(fi_msg); + goto err_ecm_inst; + } + + /* set up mass storage function */ + fsg_config_from_params(&fsg_config, &fsg_mod_data, fsg_num_buffers); + fsg_config.vendor_name = "Nokia"; + fsg_config.product_name = "N900"; + + fsg_opts = fsg_opts_from_func_inst(fi_msg); + fsg_opts->no_configfs = true; + + status = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers); + if (status) + goto err_msg_inst; + + status = fsg_common_set_nluns(fsg_opts->common, fsg_config.nluns); + if (status) + goto err_msg_buf; + + status = fsg_common_set_cdev(fsg_opts->common, cdev, fsg_config.can_stall); + if (status) + goto err_msg_set_nluns; + + fsg_common_set_sysfs(fsg_opts->common, true); + + status = fsg_common_create_luns(fsg_opts->common, &fsg_config); + if (status) + goto err_msg_set_nluns; + + fsg_common_set_inquiry_string(fsg_opts->common, fsg_config.vendor_name, + fsg_config.product_name); + /* finally register the configuration */ status = usb_add_config(cdev, &nokia_config_500ma_driver, nokia_bind_config); if (status < 0) - goto err_ecm_inst; + goto err_msg_set_cdev; status = usb_add_config(cdev, &nokia_config_100ma_driver, nokia_bind_config); @@ -292,6 +381,14 @@ err_put_cfg1: if (!IS_ERR_OR_NULL(f_phonet_cfg1)) usb_put_function(f_phonet_cfg1); usb_put_function(f_ecm_cfg1); +err_msg_set_cdev: + fsg_common_remove_luns(fsg_opts->common); +err_msg_set_nluns: + fsg_common_free_luns(fsg_opts->common); +err_msg_buf: + fsg_common_free_buffers(fsg_opts->common); +err_msg_inst: + usb_put_function_instance(fi_msg); err_ecm_inst: usb_put_function_instance(fi_ecm); err_acm_inst: @@ -325,7 +422,10 @@ static int nokia_unbind(struct usb_composite_dev *cdev) usb_put_function(f_acm_cfg2); usb_put_function(f_ecm_cfg1); usb_put_function(f_ecm_cfg2); + usb_put_function(f_msg_cfg1); + usb_put_function(f_msg_cfg2); + usb_put_function_instance(fi_msg); usb_put_function_instance(fi_ecm); if (!IS_ERR(fi_obex2)) usb_put_function_instance(fi_obex2); -- cgit v1.3-6-gb490 From 5a350d53f4c4784cf6bb4d94e7b8d76ca4f96e9f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 29 Jun 2015 20:17:22 -0500 Subject: usb: dwc2: gadget: use | instead of + for bitmasks It's just a lot clearer to use | operator instead of + operator. Caught by coccicheck: " drivers/usb/dwc2/gadget.c:2883:26-27: WARNING: sum of probable bitmasks, consider | " Cc: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 4d47b7c09238..731b13dfc512 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2880,7 +2880,7 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) epctl = readl(hs->regs + epreg); if (value) { - epctl |= DXEPCTL_STALL + DXEPCTL_SNAK; + epctl |= DXEPCTL_STALL | DXEPCTL_SNAK; if (epctl & DXEPCTL_EPENA) epctl |= DXEPCTL_EPDIS; } else { -- cgit v1.3-6-gb490 From e4f7566754675b2fd89ed32eee867d5f19bac934 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:46:07 -0500 Subject: usb: dwc3: omap: drop dev_dbg() usage Some of the messages were plain unnecessary and some were actually errors. Fix it all up. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 43 ++++--------------------------------------- 1 file changed, 4 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 6b486a36863c..e8a09a88eddd 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -225,12 +225,10 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, switch (status) { case OMAP_DWC3_ID_GROUND: - dev_dbg(omap->dev, "ID GND\n"); - if (omap->vbus_reg) { ret = regulator_enable(omap->vbus_reg); if (ret) { - dev_dbg(omap->dev, "regulator enable failed\n"); + dev_err(omap->dev, "regulator enable failed\n"); return; } } @@ -245,8 +243,6 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, break; case OMAP_DWC3_VBUS_VALID: - dev_dbg(omap->dev, "VBUS Connect\n"); - val = dwc3_omap_read_utmi_ctrl(omap); val &= ~USBOTGSS_UTMI_OTG_CTRL_SESSEND; val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG @@ -261,8 +257,6 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, regulator_disable(omap->vbus_reg); case OMAP_DWC3_VBUS_OFF: - dev_dbg(omap->dev, "VBUS Disconnect\n"); - val = dwc3_omap_read_utmi_ctrl(omap); val &= ~(USBOTGSS_UTMI_OTG_CTRL_SESSVALID | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID @@ -273,7 +267,7 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap, break; default: - dev_dbg(omap->dev, "invalid state\n"); + dev_WARN(omap->dev, "invalid state\n"); } } @@ -284,37 +278,8 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) reg = dwc3_omap_read_irqmisc_status(omap); - if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) { - dev_dbg(omap->dev, "DMA Disable was Cleared\n"); + if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) omap->dma_status = false; - } - - if (reg & USBOTGSS_IRQMISC_OEVT) - dev_dbg(omap->dev, "OTG Event\n"); - - if (reg & USBOTGSS_IRQMISC_DRVVBUS_RISE) - dev_dbg(omap->dev, "DRVVBUS Rise\n"); - - if (reg & USBOTGSS_IRQMISC_CHRGVBUS_RISE) - dev_dbg(omap->dev, "CHRGVBUS Rise\n"); - - if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_RISE) - dev_dbg(omap->dev, "DISCHRGVBUS Rise\n"); - - if (reg & USBOTGSS_IRQMISC_IDPULLUP_RISE) - dev_dbg(omap->dev, "IDPULLUP Rise\n"); - - if (reg & USBOTGSS_IRQMISC_DRVVBUS_FALL) - dev_dbg(omap->dev, "DRVVBUS Fall\n"); - - if (reg & USBOTGSS_IRQMISC_CHRGVBUS_FALL) - dev_dbg(omap->dev, "CHRGVBUS Fall\n"); - - if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_FALL) - dev_dbg(omap->dev, "DISCHRGVBUS Fall\n"); - - if (reg & USBOTGSS_IRQMISC_IDPULLUP_FALL) - dev_dbg(omap->dev, "IDPULLUP Fall\n"); dwc3_omap_write_irqmisc_status(omap, reg); @@ -434,7 +399,7 @@ static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap) reg &= ~USBOTGSS_UTMI_OTG_CTRL_SW_MODE; break; default: - dev_dbg(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode); + dev_WARN(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode); } dwc3_omap_write_utmi_ctrl(omap, reg); -- cgit v1.3-6-gb490 From 9ff0fdca3b628d3f8719237cbc8f148379527108 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:46:53 -0500 Subject: usb: dwc3: keystone: convert dev_dbg() to dev_err() that's an error condition, not a debugging message. Let's promote it appropriately. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-keystone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index fe3b9335a74e..2be268d2423d 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -115,7 +115,7 @@ static int kdwc3_probe(struct platform_device *pdev) error = clk_prepare_enable(kdwc->clk); if (error < 0) { - dev_dbg(kdwc->dev, "unable to enable usb clock, err %d\n", + dev_err(kdwc->dev, "unable to enable usb clock, error %d\n", error); return error; } -- cgit v1.3-6-gb490 From 42f69a02e7ab42f1ec75b91faf05b86e75de794a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:47:45 -0500 Subject: usb: dwc3: exynos: switch dev_dbg() to dev_info() that message is informing that the clock is missing. However, that's a valid condition for some setups; driver even ignores the error and continues just fine. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-exynos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 7bd0a95b2815..dd5cb5577dca 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -145,7 +145,7 @@ static int dwc3_exynos_probe(struct platform_device *pdev) exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk"); if (IS_ERR(exynos->susp_clk)) { - dev_dbg(dev, "no suspend clk specified\n"); + dev_info(dev, "no suspend clk specified\n"); exynos->susp_clk = NULL; } clk_prepare_enable(exynos->susp_clk); -- cgit v1.3-6-gb490 From 2babd0d148a365728649addaaa09bfb690ce6b83 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:48:58 -0500 Subject: usb: dwc3: qcom: switch dev_dbg() to dev_info() those two messages are informing that the clock doesn't exist; that, however, is a valid situation and driver continues just fine by ignoring the error. Reviewed-by: Andy Gross Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-qcom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 8c2e8eec80c2..088026048f49 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -48,13 +48,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev) qdwc->iface_clk = devm_clk_get(qdwc->dev, "iface"); if (IS_ERR(qdwc->iface_clk)) { - dev_dbg(qdwc->dev, "failed to get optional iface clock\n"); + dev_info(qdwc->dev, "failed to get optional iface clock\n"); qdwc->iface_clk = NULL; } qdwc->sleep_clk = devm_clk_get(qdwc->dev, "sleep"); if (IS_ERR(qdwc->sleep_clk)) { - dev_dbg(qdwc->dev, "failed to get optional sleep clock\n"); + dev_info(qdwc->dev, "failed to get optional sleep clock\n"); qdwc->sleep_clk = NULL; } -- cgit v1.3-6-gb490 From e746b06cc76afea568c7d53f83a834dc8d720da1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:50:46 -0500 Subject: usb: dwc3: st: remove two unnecessary messages the mode of operation is exposed through debugfs at all times. Because of that, we're removing the unnecessary messages. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-st.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c index 4a1a543deeda..de4d52f62517 100644 --- a/drivers/usb/dwc3/dwc3-st.c +++ b/drivers/usb/dwc3/dwc3-st.c @@ -135,8 +135,6 @@ static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data) | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2); val |= USB3_DEVICE_NOT_HOST; - - dev_dbg(dwc3_data->dev, "Configuring as Device\n"); break; case USB_DR_MODE_HOST: @@ -154,8 +152,6 @@ static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data) */ val |= USB3_DELAY_VBUSVALID; - - dev_dbg(dwc3_data->dev, "Configuring as Host\n"); break; default: -- cgit v1.3-6-gb490 From 9fcfa463e17adc48865b1a4124d48d48e0b59556 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 30 Jun 2015 12:51:49 -0500 Subject: usb: dwc3: drop CONFIG_USB_DWC3_DEBUG now that we have no users of dev_dbg() in dwc3, we can safely remove CONFIG_USB_DWC3_DEBUG. If dev_dbg() is ever strictly necessary - and I don't see why it would, considering we want to rely on tracepoints for debug - we will depend on DYNAMIC_PRINTK to enable such messages. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/Kconfig | 7 ------- drivers/usb/dwc3/Makefile | 2 -- 2 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index dede32e809b6..5a42c4590402 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -104,11 +104,4 @@ config USB_DWC3_QCOM Recent Qualcomm SoCs ship with one DesignWare Core USB3 IP inside, say 'Y' or 'M' if you have one such device. -comment "Debugging features" - -config USB_DWC3_DEBUG - bool "Enable Debugging Messages" - help - Say Y here to enable debugging messages on DWC3 Driver. - endif diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index c7076e37c4ed..acc951d46c27 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -1,8 +1,6 @@ # define_trace.h needs to know how to find our header CFLAGS_trace.o := -I$(src) -ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG - obj-$(CONFIG_USB_DWC3) += dwc3.o dwc3-y := core.o debug.o trace.o -- cgit v1.3-6-gb490 From e425be9304ce4da9cd231b55630ca941752635e9 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Fri, 19 Jun 2015 12:05:05 +0200 Subject: usb: gadget: loopback: Remove out-of-date comment As loopback function has been reworked for ConfigFS composite gadget this comment is no longer valid. Signed-off-by: Krzysztof Opasiak Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_loopback.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c index 39f49f1ad22f..6e2fe63b9267 100644 --- a/drivers/usb/gadget/function/f_loopback.c +++ b/drivers/usb/gadget/function/f_loopback.c @@ -28,11 +28,6 @@ * This takes messages of various sizes written OUT to a device, and loops * them back so they can be read IN from it. It has been used by certain * test applications. It supports limited testing of data queueing logic. - * - * - * This is currently packaged as a configuration driver, which can't be - * combined with other functions to make composite devices. However, it - * can be combined with other independent configurations. */ struct f_loopback { struct usb_function function; -- cgit v1.3-6-gb490 From d3c1ac4a69667300996ea76fe25c33434372a2a8 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Fri, 19 Jun 2015 12:16:45 +0200 Subject: usb: gadget: SourceSink: Remove out-of-date comment As SourceSink function has been reworked for ConfigFS composite gadget this comment is no longer valid. Signed-off-by: Krzysztof Opasiak Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_sourcesink.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index 3a5ae9900b1e..e6af1719d851 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -42,11 +42,6 @@ * queues are relatively independent, will receive a range of packet sizes, * and can often be made to run out completely. Those issues are important * when stress testing peripheral controller drivers. - * - * - * This is currently packaged as a configuration driver, which can't be - * combined with other functions to make composite devices. However, it - * can be combined with other independent configurations. */ struct f_sourcesink { struct usb_function function; -- cgit v1.3-6-gb490 From b8464bcf0a20970471e8f897fe4706fcc2702263 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Sat, 6 Jun 2015 07:02:53 +0530 Subject: usb: gadget: Convert use of __constant_cpu_to_le16 to cpu_to_le16 In big endian cases, macro cpu_to_le16 unfolds to __swab16 which provides special case for constants. In little endian cases, __constant_cpu_to_le16 and cpu_to_le16 expand directly to the same expression. So, replace __constant_cpu_to_le16 with cpu_to_le16 with the goal of getting rid of the definition of __constant_cpu_to_le16 completely. The semantic patch that performs this transformation is as follows: @@expression x;@@ - __constant_cpu_to_le16(x) + cpu_to_le16(x) Signed-off-by: Vaishali Thakkar Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/audio.c | 6 +++--- drivers/usb/gadget/legacy/dbgp.c | 10 +++++----- drivers/usb/gadget/legacy/gmidi.c | 6 +++--- drivers/usb/gadget/legacy/nokia.c | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index f289caf18a45..b8095bfe57b6 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -124,7 +124,7 @@ static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x200), + .bcdUSB = cpu_to_le16(0x200), #ifdef CONFIG_GADGET_UAC1 .bDeviceClass = USB_CLASS_PER_INTERFACE, @@ -141,8 +141,8 @@ static struct usb_device_descriptor device_desc = { * we support. (As does bNumConfigurations.) These values can * also be overridden by module parameters. */ - .idVendor = __constant_cpu_to_le16(AUDIO_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16(AUDIO_PRODUCT_NUM), + .idVendor = cpu_to_le16(AUDIO_VENDOR_NUM), + .idProduct = cpu_to_le16(AUDIO_PRODUCT_NUM), /* .bcdDevice = f(hardware) */ /* .iManufacturer = DYNAMIC */ /* .iProduct = DYNAMIC */ diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c index 204b10b1a7e7..5231a32aef55 100644 --- a/drivers/usb/gadget/legacy/dbgp.c +++ b/drivers/usb/gadget/legacy/dbgp.c @@ -35,10 +35,10 @@ static struct dbgp { static struct usb_device_descriptor device_desc = { .bLength = sizeof device_desc, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x0200), + .bcdUSB = cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_VENDOR_SPEC, - .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID), - .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID), + .idVendor = cpu_to_le16(DRIVER_VENDOR_ID), + .idProduct = cpu_to_le16(DRIVER_PRODUCT_ID), .bNumConfigurations = 1, }; @@ -251,7 +251,7 @@ static int dbgp_configure_endpoints(struct usb_gadget *gadget) dbgp.i_ep->driver_data = gadget; i_desc.wMaxPacketSize = - __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE); + cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE); dbgp.o_ep = usb_ep_autoconfig(gadget, &o_desc); if (!dbgp.o_ep) { @@ -262,7 +262,7 @@ static int dbgp_configure_endpoints(struct usb_gadget *gadget) dbgp.o_ep->driver_data = gadget; o_desc.wMaxPacketSize = - __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE); + cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE); dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress; dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress; diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c index da19c486b61e..650568de0de3 100644 --- a/drivers/usb/gadget/legacy/gmidi.c +++ b/drivers/usb/gadget/legacy/gmidi.c @@ -88,10 +88,10 @@ MODULE_PARM_DESC(out_ports, "Number of MIDI output ports"); static struct usb_device_descriptor device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x0200), + .bcdUSB = cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_PER_INTERFACE, - .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM), + .idVendor = cpu_to_le16(DRIVER_VENDOR_NUM), + .idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM), /* .iManufacturer = DYNAMIC */ /* .iProduct = DYNAMIC */ .bNumConfigurations = 1, diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index e3791b919996..8902f454b7bc 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -90,10 +90,10 @@ static struct usb_gadget_strings *dev_strings[] = { static struct usb_device_descriptor device_desc = { .bLength = USB_DT_DEVICE_SIZE, .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x0200), + .bcdUSB = cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_COMM, - .idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID), - .idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID), + .idVendor = cpu_to_le16(NOKIA_VENDOR_ID), + .idProduct = cpu_to_le16(NOKIA_PRODUCT_ID), .bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM), /* .iManufacturer = DYNAMIC */ /* .iProduct = DYNAMIC */ -- cgit v1.3-6-gb490 From ad4676ab58ae38e5597a2d6bc0d12e9b5e0b0d18 Mon Sep 17 00:00:00 2001 From: Diego Viola Date: Sun, 31 May 2015 15:52:41 -0300 Subject: usb: gadget: composite.c: i18n is not an acronym I18N should be spelled as i18n because it's not an acronym Signed-off-by: Diego Viola Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 58b4657fc721..9ff3203b50e2 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -896,7 +896,7 @@ void usb_remove_config(struct usb_composite_dev *cdev, /* We support strings in multiple languages ... string descriptor zero * says which languages are supported. The typical case will be that - * only one language (probably English) is used, with I18N handled on + * only one language (probably English) is used, with i18n handled on * the host side. */ @@ -949,7 +949,7 @@ static int get_string(struct usb_composite_dev *cdev, struct usb_function *f; int len; - /* Yes, not only is USB's I18N support probably more than most + /* Yes, not only is USB's i18n support probably more than most * folk will ever care about ... also, it's all supported here. * (Except for UTF8 support for Unicode's "Astral Planes".) */ -- cgit v1.3-6-gb490 From b5c03bffa67727697252e913f64703e3404867ae Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Wed, 10 Jun 2015 16:04:25 +0530 Subject: usb: udc: Convert use of __constant_cpu_to_leXX to cpu_to_leXX In big endian cases, the macro cpu_to_le{16,32} unfolds to __swab{16,32} which provides special case for constants. In little endian cases, __constant_cpu_to_le{16,32} and cpu_to_le{16,32} expand directly to the same expression. So, replace __constant_cpu_to_le{16,32} with cpu_to_le{16,32} with the goal of getting rid of the definition of __constant_cpu_to_le{16,32} completely. The semantic patch that performs this transformation is as follows: @@expression x;@@ ( - __constant_cpu_to_le16(x) + cpu_to_le16(x) | - __constant_cpu_to_le32(x) + cpu_to_le32(x) ) Signed-off-by: Vaishali Thakkar Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2272.c | 4 ++-- drivers/usb/gadget/udc/pch_udc.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 195baf3e1fcd..c2ed5daebb75 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -1826,9 +1826,9 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat) if (!e || u.r.wLength > 2) goto do_stall; if (net2272_ep_read(e, EP_RSPSET) & (1 << ENDPOINT_HALT)) - status = __constant_cpu_to_le16(1); + status = cpu_to_le16(1); else - status = __constant_cpu_to_le16(0); + status = cpu_to_le16(0); /* don't bother with a request object! */ net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 613547f07828..dcf5defdb9e5 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -1793,7 +1793,7 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep, } /* prevent from using desc. - set HOST BUSY */ dma_desc->status |= PCH_UDC_BS_HST_BSY; - dma_desc->dataptr = __constant_cpu_to_le32(DMA_ADDR_INVALID); + dma_desc->dataptr = cpu_to_le32(DMA_ADDR_INVALID); req->td_data = dma_desc; req->td_data_last = dma_desc; req->chain_len = 1; -- cgit v1.3-6-gb490 From 5960387a2fb8314687351f6d8485cf62d7722b4e Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 1 Jul 2015 13:11:30 +0900 Subject: usb: dwc3: omap: Replace deprecated API of extcon This patch removes the deprecated notifier API of extcon framwork and then use the new extcon API with the unique id to indicate the each external connector (USB, USB-HOST). Alter deprecated API as following: - extcon_register_interest() -> extcon_register_notifier() - extcon_get_cable_state(*edev, char *) -> extcon_get_cable_state_(*edev, id) Cc: Felipe Balbi Cc: Greg Kroah-Hartman Signed-off-by: Chanwoo Choi Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index e8a09a88eddd..a5a1b7c45743 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -128,8 +128,7 @@ struct dwc3_omap { u32 dma_status:1; - struct extcon_specific_cable_nb extcon_vbus_dev; - struct extcon_specific_cable_nb extcon_id_dev; + struct extcon_dev *edev; struct notifier_block vbus_nb; struct notifier_block id_nb; @@ -419,23 +418,23 @@ static int dwc3_omap_extcon_register(struct dwc3_omap *omap) } omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier; - ret = extcon_register_interest(&omap->extcon_vbus_dev, - edev->name, "USB", - &omap->vbus_nb); + ret = extcon_register_notifier(edev, EXTCON_USB, + &omap->vbus_nb); if (ret < 0) dev_vdbg(omap->dev, "failed to register notifier for USB\n"); omap->id_nb.notifier_call = dwc3_omap_id_notifier; - ret = extcon_register_interest(&omap->extcon_id_dev, - edev->name, "USB-HOST", - &omap->id_nb); + ret = extcon_register_notifier(edev, EXTCON_USB_HOST, + &omap->id_nb); if (ret < 0) dev_vdbg(omap->dev, "failed to register notifier for USB-HOST\n"); - if (extcon_get_cable_state(edev, "USB") == true) + if (extcon_get_cable_state_(edev, EXTCON_USB) == true) dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); - if (extcon_get_cable_state(edev, "USB-HOST") == true) + if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) == true) dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); + + omap->edev = edev; } return 0; @@ -530,11 +529,8 @@ static int dwc3_omap_probe(struct platform_device *pdev) return 0; err3: - if (omap->extcon_vbus_dev.edev) - extcon_unregister_interest(&omap->extcon_vbus_dev); - if (omap->extcon_id_dev.edev) - extcon_unregister_interest(&omap->extcon_id_dev); - + extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb); + extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb); err2: dwc3_omap_disable_irqs(omap); @@ -551,10 +547,8 @@ static int dwc3_omap_remove(struct platform_device *pdev) { struct dwc3_omap *omap = platform_get_drvdata(pdev); - if (omap->extcon_vbus_dev.edev) - extcon_unregister_interest(&omap->extcon_vbus_dev); - if (omap->extcon_id_dev.edev) - extcon_unregister_interest(&omap->extcon_id_dev); + extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb); + extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb); dwc3_omap_disable_irqs(omap); of_platform_depopulate(omap->dev); pm_runtime_put_sync(&pdev->dev); -- cgit v1.3-6-gb490 From a2fd2423240fe1abd7a154a1cc0fd1624c339bff Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 1 Jul 2015 13:11:31 +0900 Subject: usb: phy: omap-otg: Replace deprecated API of extcon This patch removes the deprecated notifier API of extcon framwork and then use the new extcon API with the unique id to indicate the each external connector (USB, USB-HOST). Alter deprecated API as following: - extcon_register_interest() -> extcon_register_notifier() - extcon_get_cable_state(*edev, char *) -> extcon_get_cable_state_(*edev, id) [ balbi@ti.com : fix build break ] Cc: Greg Kroah-Hartman Signed-off-by: Chanwoo Choi Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-omap-otg.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-omap-otg.c b/drivers/usb/phy/phy-omap-otg.c index 56ee7603034b..1270906ccb95 100644 --- a/drivers/usb/phy/phy-omap-otg.c +++ b/drivers/usb/phy/phy-omap-otg.c @@ -30,8 +30,7 @@ struct otg_device { void __iomem *base; bool id; bool vbus; - struct extcon_specific_cable_nb vbus_dev; - struct extcon_specific_cable_nb id_dev; + struct extcon_dev *extcon; struct notifier_block vbus_nb; struct notifier_block id_nb; }; @@ -106,6 +105,7 @@ static int omap_otg_probe(struct platform_device *pdev) extcon = extcon_get_extcon_dev(config->extcon); if (!extcon) return -EPROBE_DEFER; + otg_dev->extcon = extcon; otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL); if (!otg_dev) @@ -118,20 +118,19 @@ static int omap_otg_probe(struct platform_device *pdev) otg_dev->id_nb.notifier_call = omap_otg_id_notifier; otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier; - ret = extcon_register_interest(&otg_dev->id_dev, config->extcon, - "USB-HOST", &otg_dev->id_nb); + ret = extcon_register_notifier(extcon, EXTCON_USB_HOST, &otg_dev->id_nb); if (ret) return ret; - ret = extcon_register_interest(&otg_dev->vbus_dev, config->extcon, - "USB", &otg_dev->vbus_nb); + ret = extcon_register_notifier(extcon, EXTCON_USB, &otg_dev->vbus_nb); if (ret) { - extcon_unregister_interest(&otg_dev->id_dev); + extcon_unregister_notifier(extcon, EXTCON_USB_HOST, + &otg_dev->id_nb); return ret; } - otg_dev->id = extcon_get_cable_state(extcon, "USB-HOST"); - otg_dev->vbus = extcon_get_cable_state(extcon, "USB"); + otg_dev->id = extcon_get_cable_state_(extcon, EXTCON_USB_HOST); + otg_dev->vbus = extcon_get_cable_state_(extcon, EXTCON_USB); omap_otg_set_mode(otg_dev); rev = readl(otg_dev->base); @@ -147,9 +146,10 @@ static int omap_otg_probe(struct platform_device *pdev) static int omap_otg_remove(struct platform_device *pdev) { struct otg_device *otg_dev = platform_get_drvdata(pdev); + struct extcon_dev *edev = otg_dev->extcon; - extcon_unregister_interest(&otg_dev->id_dev); - extcon_unregister_interest(&otg_dev->vbus_dev); + extcon_unregister_notifier(edev, EXTCON_USB_HOST,&otg_dev->id_nb); + extcon_unregister_notifier(edev, EXTCON_USB, &otg_dev->vbus_nb); return 0; } -- cgit v1.3-6-gb490 From 860d2686fda7e4dceaa4e676e62adcdbfc7f7a2c Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 1 Jul 2015 13:11:32 +0900 Subject: usb: phy: tahvo: Use devm_extcon_dev_[allocate|register]() and replace deprecated API This patch uses the devm_extcon_dev_[allocate|register]() to manage the resource automatically and replace deprecated API as following: - extcon_[set|get]_cable_state(*edev, char *) -> extcon_[set|get]_cable_state_(*edev, id) Cc: Felipe Balbi Cc: Greg Kroah-Hartman Signed-off-by: Chanwoo Choi Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-tahvo.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index b40d6a87d694..ab5d364f6e8c 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -57,7 +57,7 @@ struct tahvo_usb { struct clk *ick; int irq; int tahvo_mode; - struct extcon_dev extcon; + struct extcon_dev *extcon; }; static const unsigned int tahvo_cable[] = { @@ -121,7 +121,7 @@ static void check_vbus_state(struct tahvo_usb *tu) prev_state = tu->vbus_state; tu->vbus_state = reg & TAHVO_STAT_VBUS; if (prev_state != tu->vbus_state) { - extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state); + extcon_set_cable_state_(tu->extcon, EXTCON_USB, tu->vbus_state); sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state"); } } @@ -130,7 +130,7 @@ static void tahvo_usb_become_host(struct tahvo_usb *tu) { struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); - extcon_set_cable_state(&tu->extcon, "USB-HOST", true); + extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, true); /* Power up the transceiver in USB host mode */ retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND | @@ -149,7 +149,7 @@ static void tahvo_usb_become_peripheral(struct tahvo_usb *tu) { struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); - extcon_set_cable_state(&tu->extcon, "USB-HOST", false); + extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, false); /* Power up transceiver and set it in USB peripheral mode */ retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | @@ -365,11 +365,13 @@ static int tahvo_usb_probe(struct platform_device *pdev) */ tu->vbus_state = retu_read(rdev, TAHVO_REG_IDSR) & TAHVO_STAT_VBUS; - tu->extcon.name = DRIVER_NAME; - tu->extcon.supported_cable = tahvo_cable; - tu->extcon.dev.parent = &pdev->dev; + tu->extcon = devm_extcon_dev_allocate(&pdev->dev, tahvo_cable); + if (IS_ERR(tu->extcon)) { + dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); + return -ENOMEM; + } - ret = extcon_dev_register(&tu->extcon); + ret = devm_extcon_dev_register(&pdev->dev, tu->extcon); if (ret) { dev_err(&pdev->dev, "could not register extcon device: %d\n", ret); @@ -377,9 +379,9 @@ static int tahvo_usb_probe(struct platform_device *pdev) } /* Set the initial cable state. */ - extcon_set_cable_state(&tu->extcon, "USB-HOST", + extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, tu->tahvo_mode == TAHVO_MODE_HOST); - extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state); + extcon_set_cable_state_(tu->extcon, EXTCON_USB, tu->vbus_state); /* Create OTG interface */ tahvo_usb_power_off(tu); @@ -396,7 +398,7 @@ static int tahvo_usb_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "cannot register USB transceiver: %d\n", ret); - goto err_extcon_unreg; + goto err_disable_clk; } dev_set_drvdata(&pdev->dev, tu); @@ -424,8 +426,6 @@ err_free_irq: free_irq(tu->irq, tu); err_remove_phy: usb_remove_phy(&tu->phy); -err_extcon_unreg: - extcon_dev_unregister(&tu->extcon); err_disable_clk: if (!IS_ERR(tu->ick)) clk_disable(tu->ick); @@ -440,7 +440,6 @@ static int tahvo_usb_remove(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &tahvo_attr_group); free_irq(tu->irq, tu); usb_remove_phy(&tu->phy); - extcon_dev_unregister(&tu->extcon); if (!IS_ERR(tu->ick)) clk_disable(tu->ick); -- cgit v1.3-6-gb490 From 50297b79b8fd426f678431a8e9dcee59afd33ec8 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 1 Jul 2015 13:11:33 +0900 Subject: usb: renesas_usbhs: Replace deprecated API of extcon This patch removes the deprecated API of extcon and then use the new extcon API with the unique id to indicate the each external connector (USB-HOST). - extcon_get_cable_state(*edev, char *) -> extcon_get_cable_state_(*edev, id) Cc: Greg Kroah-Hartman Cc: Felipe Balbi Cc: Yoshihiro Shimoda Cc: Sergei Shtylyov Cc: Yoshihiro Shimoda Cc: Peter Chen Cc: Varka Bhadram Cc: Takeshi Kihara Signed-off-by: Chanwoo Choi Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index e8bf40808b39..7b98e1d9194c 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -388,7 +388,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv) if (enable && !mod) { if (priv->edev) { - cable = extcon_get_cable_state(priv->edev, "USB-HOST"); + cable = extcon_get_cable_state_(priv->edev, EXTCON_USB_HOST); if ((cable > 0 && id != USBHS_HOST) || (!cable && id != USBHS_GADGET)) { dev_info(&pdev->dev, -- cgit v1.3-6-gb490 From 83b7b67c780500a1d5d87c44ee8963166154adfa Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Wed, 1 Jul 2015 13:11:34 +0900 Subject: usb: phy: msm-usb: Replace deprecated API of extcon This patch removes the deprecated notifier API of extcon framwork and then use the new extcon API with the unique id to indicate the each external connector (USB, USB-HOST). Alter deprecated API as following: - extcon_register_interest() -> extcon_register_notifier() - extcon_get_cable_state(*edev, char *) -> extcon_get_cable_state_(*edev, id) Cc: Felipe Balbi Cc: Greg Kroah-Hartman Signed-off-by: Chanwoo Choi Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-msm-usb.c | 20 ++++++++++---------- include/linux/usb/msm_hsusb.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 00c49bb1bd29..61d86d8bf5b7 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -1561,15 +1561,16 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) } if (!IS_ERR(ext_vbus)) { + motg->vbus.extcon = ext_vbus; motg->vbus.nb.notifier_call = msm_otg_vbus_notifier; - ret = extcon_register_interest(&motg->vbus.conn, ext_vbus->name, - "USB", &motg->vbus.nb); + ret = extcon_register_notifier(ext_vbus, EXTCON_USB, + &motg->vbus.nb); if (ret < 0) { dev_err(&pdev->dev, "register VBUS notifier failed\n"); return ret; } - ret = extcon_get_cable_state(ext_vbus, "USB"); + ret = extcon_get_cable_state_(ext_vbus, EXTCON_USB); if (ret) set_bit(B_SESS_VLD, &motg->inputs); else @@ -1577,15 +1578,16 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) } if (!IS_ERR(ext_id)) { + motg->id.extcon = ext_id; motg->id.nb.notifier_call = msm_otg_id_notifier; - ret = extcon_register_interest(&motg->id.conn, ext_id->name, - "USB-HOST", &motg->id.nb); + ret = extcon_register_notifier(ext_id, EXTCON_USB_HOST, + &motg->id.nb); if (ret < 0) { dev_err(&pdev->dev, "register ID notifier failed\n"); return ret; } - ret = extcon_get_cable_state(ext_id, "USB-HOST"); + ret = extcon_get_cable_state_(ext_id, EXTCON_USB_HOST); if (ret) clear_bit(ID, &motg->inputs); else @@ -1805,10 +1807,8 @@ static int msm_otg_remove(struct platform_device *pdev) if (phy->otg->host || phy->otg->gadget) return -EBUSY; - if (motg->id.conn.edev) - extcon_unregister_interest(&motg->id.conn); - if (motg->vbus.conn.edev) - extcon_unregister_interest(&motg->vbus.conn); + extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb); + extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb); msm_otg_debugfs_cleanup(); cancel_delayed_work_sync(&motg->chg_work); diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index e55a1504266e..5df2c8f59aa0 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -128,7 +128,7 @@ struct msm_otg_platform_data { */ struct msm_usb_cable { struct notifier_block nb; - struct extcon_specific_cable_nb conn; + struct extcon_dev *extcon; }; /** -- cgit v1.3-6-gb490 From 2df033ca39b56605725384bac1579cdd30e052a6 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 6 Jul 2015 11:09:48 +0200 Subject: usb: dwc3: pci: make better use of gpiod API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Use this additional parameter and the _optional variant to simplify the driver and improve error handling. Also expand the comment to explain why it's not sensible to switch to devm_gpiod_get and why the gpiod_put is also necessary. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Tested-by: Heikki Krogerus Signed-off-by: Uwe Kleine-König Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-pci.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 27e4fc896e9d..f62617999f3c 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -83,17 +83,23 @@ static int dwc3_pci_quirks(struct pci_dev *pdev) acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev), acpi_dwc3_byt_gpios); - /* These GPIOs will turn on the USB2 PHY */ - gpio = gpiod_get(&pdev->dev, "cs"); - if (!IS_ERR(gpio)) { - gpiod_direction_output(gpio, 0); - gpiod_set_value_cansleep(gpio, 1); - gpiod_put(gpio); - } + /* + * These GPIOs will turn on the USB2 PHY. Note that we have to + * put the gpio descriptors again here because the phy driver + * might want to grab them, too. + */ + gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + + gpiod_set_value_cansleep(gpio, 1); + gpiod_put(gpio); + + gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); - gpio = gpiod_get(&pdev->dev, "reset"); - if (!IS_ERR(gpio)) { - gpiod_direction_output(gpio, 0); + if (gpio) { gpiod_set_value_cansleep(gpio, 1); gpiod_put(gpio); usleep_range(10000, 11000); -- cgit v1.3-6-gb490 From 88167fc0b22aac0fe7b9c4fadf9c251a9f864f32 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 6 Jul 2015 11:09:49 +0200 Subject: usb: pass flags parameter to gpiod_get functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Currently this parameter is made optional with the help of a cpp trick. To allow dropping this hack convert callers to explictly pass a value for flags. Acked-by: Felipe Balbi Acked-by: Robert Jarzmik Signed-off-by: Uwe Kleine-König Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pxa27x_udc.c | 2 +- drivers/usb/phy/phy-generic.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index b51226abade6..042f06b52677 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -2422,7 +2422,7 @@ static int pxa_udc_probe(struct platform_device *pdev) } udc->udc_command = mach->udc_command; } else { - udc->gpiod = devm_gpiod_get(&pdev->dev, NULL); + udc->gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_ASIS); } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index deee68eafb72..ec6ecd03269c 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -218,11 +218,13 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, clk_rate = 0; needs_vcc = of_property_read_bool(node, "vcc-supply"); - nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset"); + nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset", + GPIOD_ASIS); err = PTR_ERR_OR_ZERO(nop->gpiod_reset); if (!err) { nop->gpiod_vbus = devm_gpiod_get_optional(dev, - "vbus-detect"); + "vbus-detect", + GPIOD_ASIS); err = PTR_ERR_OR_ZERO(nop->gpiod_vbus); } } else if (pdata) { -- cgit v1.3-6-gb490 From d9972f470bcb40947dd91af90f17f9cb01db1f41 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 7 Jul 2015 13:45:23 -0500 Subject: usb: dwc3: core: remove unnecessary dev_warn() When a SoC supports both PHY interfaces but doesn't define HSPHY in DT/pdata, we will get an unnecessary dev_warn() which can mislead users into thinking that they're missing something. Instead, let's just silently rely on a correct default. If the HW default is wrong, then HSPHY is required and USB won't work, this will be motivation enough for engineers to patch their way into a working setup. Reported-by: Murali Karicheri Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ff5773c66b84..064123e44566 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -455,8 +455,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc) reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); } else { - dev_warn(dwc->dev, "HSPHY Interface not defined\n"); - /* Relying on default value. */ if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI)) break; -- cgit v1.3-6-gb490 From 7eaeac5c0e44921eb583d5b59b9c54741ecaa899 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 20 Jul 2015 14:46:15 -0500 Subject: usb: dwc3: gadget: add a trace when disabling EPs We have a "Enabling %s" trace when enabling an endpoint but that message felt lonely without a matching "Disabling %s". Add it. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 333a7c0078fc..1f8f730c7cc5 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -586,6 +586,8 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) struct dwc3 *dwc = dep->dwc; u32 reg; + dwc3_trace(trace_dwc3_gadget, "Disabling %s", dep->name); + dwc3_remove_requests(dwc, dep); /* make sure HW endpoint isn't stalled */ -- cgit v1.3-6-gb490 From aa7399744dd02537523b7bf9e3070600b6f79751 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 20 Jul 2015 14:48:13 -0500 Subject: usb: dwc3: gadget: defer endpoint name change We should only change endpoint names when we actually manage to enable/disable it. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1f8f730c7cc5..d97fcfa8fe87 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -547,6 +547,23 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, trb_link->ctrl |= DWC3_TRB_CTRL_HWO; } + switch (usb_endpoint_type(desc)) { + case USB_ENDPOINT_XFER_CONTROL: + strlcat(dep->name, "-control", sizeof(dep->name)); + break; + case USB_ENDPOINT_XFER_ISOC: + strlcat(dep->name, "-isoc", sizeof(dep->name)); + break; + case USB_ENDPOINT_XFER_BULK: + strlcat(dep->name, "-bulk", sizeof(dep->name)); + break; + case USB_ENDPOINT_XFER_INT: + strlcat(dep->name, "-int", sizeof(dep->name)); + break; + default: + dev_err(dwc->dev, "invalid endpoint transfer type\n"); + } + return 0; } @@ -604,6 +621,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dep->type = 0; dep->flags = 0; + snprintf(dep->name, sizeof(dep->name), "ep%d%s", + dep->number >> 1, + (dep->number & 1) ? "in" : "out"); + return 0; } @@ -649,23 +670,6 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, return 0; } - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_CONTROL: - strlcat(dep->name, "-control", sizeof(dep->name)); - break; - case USB_ENDPOINT_XFER_ISOC: - strlcat(dep->name, "-isoc", sizeof(dep->name)); - break; - case USB_ENDPOINT_XFER_BULK: - strlcat(dep->name, "-bulk", sizeof(dep->name)); - break; - case USB_ENDPOINT_XFER_INT: - strlcat(dep->name, "-int", sizeof(dep->name)); - break; - default: - dev_err(dwc->dev, "invalid endpoint transfer type\n"); - } - spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false); spin_unlock_irqrestore(&dwc->lock, flags); @@ -694,10 +698,6 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep) return 0; } - snprintf(dep->name, sizeof(dep->name), "ep%d%s", - dep->number >> 1, - (dep->number & 1) ? "in" : "out"); - spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_disable(dep); spin_unlock_irqrestore(&dwc->lock, flags); -- cgit v1.3-6-gb490 From 903588a99c26ed6f103eaa0cfa4ccbe9cd779398 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Mon, 20 Jul 2015 20:15:17 +0200 Subject: usb: gadget: mass_storage: Free buffers if create lun fails Creation of LUN 0 may fail (for example due to ENOMEM). As fsg_common_set_num_buffers() does some memory allocation we should free it before it becomes unavailable. Signed-off-by: Krzysztof Opasiak Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index f936268d26c6..f72102adc7ef 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -3524,6 +3524,9 @@ static struct usb_function_instance *fsg_alloc_inst(void) config.removable = true; rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0", (const char **)&opts->func_inst.group.cg_item.ci_name); + if (rc) + goto release_buffers; + opts->lun0.lun = opts->common->luns[0]; opts->lun0.lun_id = 0; config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type); @@ -3534,6 +3537,8 @@ static struct usb_function_instance *fsg_alloc_inst(void) return &opts->func_inst; +release_buffers: + fsg_common_free_buffers(opts->common); release_luns: kfree(opts->common->luns); release_opts: -- cgit v1.3-6-gb490 From bab7a1f199fa617c7a0600c74ebbb514aed6dbe8 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Mon, 20 Jul 2015 20:15:18 +0200 Subject: usb: gadget: mass_storage: Place EXPORT_SYMBOL_GPL() after func definition EXPORT_SYMBOL_GPL() is usually placed after function definition not before. Signed-off-by: Krzysztof Opasiak Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index f72102adc7ef..c3b62c7cb584 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2761,12 +2761,12 @@ static void _fsg_common_remove_luns(struct fsg_common *common, int n) common->luns[i] = NULL; } } -EXPORT_SYMBOL_GPL(fsg_common_remove_luns); void fsg_common_remove_luns(struct fsg_common *common) { _fsg_common_remove_luns(common, common->nluns); } +EXPORT_SYMBOL_GPL(fsg_common_remove_luns); void fsg_common_free_luns(struct fsg_common *common) { -- cgit v1.3-6-gb490 From 75ddead2a77db61e818bc0cbe330a856a912f4d9 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Mon, 20 Jul 2015 20:15:19 +0200 Subject: usb: gadget: storage-common: Set FSG_MAX_LUNS to 16 Mass storage spec allows up to 16 LUNs, so let's not add some more restrictive limits. Signed-off-by: Krzysztof Opasiak Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 2 +- drivers/usb/gadget/function/storage_common.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index c3b62c7cb584..9e88e2b18d95 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -54,7 +54,7 @@ * following fields: * * nluns Number of LUNs function have (anywhere from 1 - * to FSG_MAX_LUNS which is 8). + * to FSG_MAX_LUNS). * luns An array of LUN configuration values. This * should be filled for each LUN that * function will include (ie. for "nluns" diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h index 70c891469f57..c3544e61da66 100644 --- a/drivers/usb/gadget/function/storage_common.h +++ b/drivers/usb/gadget/function/storage_common.h @@ -123,7 +123,7 @@ static inline bool fsg_lun_is_open(struct fsg_lun *curlun) #define FSG_BUFLEN ((u32)16384) /* Maximal number of LUNs supported in mass storage function */ -#define FSG_MAX_LUNS 8 +#define FSG_MAX_LUNS 16 enum fsg_buffer_state { BUF_STATE_EMPTY = 0, -- cgit v1.3-6-gb490 From 351169933ea22592fb42b97c76c4c130fe287cca Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Wed, 8 Jul 2015 17:57:40 +0300 Subject: usb: phy: qcom: New APQ8016/MSM8916 USB transceiver driver Driver handles PHY initialization, clock management, power management and workarounds required after resetting the hardware. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/qcom,usb-8x16-phy.txt | 76 ++++ drivers/usb/phy/Kconfig | 14 + drivers/usb/phy/Makefile | 1 + drivers/usb/phy/phy-qcom-8x16-usb.c | 436 +++++++++++++++++++++ 4 files changed, 527 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt create mode 100644 drivers/usb/phy/phy-qcom-8x16-usb.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt b/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt new file mode 100644 index 000000000000..2cb2168cef41 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt @@ -0,0 +1,76 @@ +Qualcomm's APQ8016/MSM8916 USB transceiver controller + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,usb-8x16-phy". + +- reg: + Usage: required + Value type: + Definition: USB PHY base address and length of the register map + +- clocks: + Usage: required + Value type: + Definition: See clock-bindings.txt section "consumers". List of + two clock specifiers for interface and core controller + clocks. + +- clock-names: + Usage: required + Value type: + Definition: Must contain "iface" and "core" strings. + +- vddcx-supply: + Usage: required + Value type: + Definition: phandle to the regulator VDCCX supply node. + +- v1p8-supply: + Usage: required + Value type: + Definition: phandle to the regulator 1.8V supply node. + +- v3p3-supply: + Usage: required + Value type: + Definition: phandle to the regulator 3.3V supply node. + +- resets: + Usage: required + Value type: + Definition: See reset.txt section "consumers". PHY reset specifier. + +- reset-names: + Usage: required + Value type: + Definition: Must contain "phy" string. + +- switch-gpio: + Usage: optional + Value type: + Definition: Some boards are using Dual SPDT USB Switch, witch is + controlled by GPIO to de/multiplex D+/D- USB lines + between connectors. + +Example: + usb_phy: phy@78d9000 { + compatible = "qcom,usb-8x16-phy"; + reg = <0x78d9000 0x400>; + + vddcx-supply = <&pm8916_s1_corner>; + v1p8-supply = <&pm8916_l7>; + v3p3-supply = <&pm8916_l13>; + + clocks = <&gcc GCC_USB_HS_AHB_CLK>, + <&gcc GCC_USB_HS_SYSTEM_CLK>; + clock-names = "iface", "core"; + + resets = <&gcc GCC_USB2A_PHY_BCR>; + reset-names = "phy"; + + // D+/D- lines: 1 - Routed to HUB, 0 - Device connector + switch-gpio = <&pm8916_gpios 4 GPIO_ACTIVE_HIGH>; + }; + diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 869c0cfcad98..7d3beee2a587 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -152,6 +152,20 @@ config USB_MSM_OTG This driver is not supported on boards like trout which has an external PHY. +config USB_QCOM_8X16_PHY + tristate "Qualcomm APQ8016/MSM8916 on-chip USB PHY controller support" + depends on ARCH_QCOM || COMPILE_TEST + depends on RESET_CONTROLLER + select USB_PHY + select USB_ULPI_VIEWPORT + help + Enable this to support the USB transceiver on Qualcomm 8x16 chipsets. + It handles PHY initialization, clock management, power management, + and workarounds required after resetting the hardware. + + To compile this driver as a module, choose M here: the + module will be called phy-qcom-8x16-usb. + config USB_MV_OTG tristate "Marvell USB OTG support" depends on USB_EHCI_MV && USB_MV_UDC && PM diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index e36ab1d46d8b..19c0dccbb116 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_USB_EHCI_TEGRA) += phy-tegra-usb.o obj-$(CONFIG_USB_GPIO_VBUS) += phy-gpio-vbus-usb.o obj-$(CONFIG_USB_ISP1301) += phy-isp1301.o obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o +obj-$(CONFIG_USB_QCOM_8X16_PHY) += phy-qcom-8x16-usb.o obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c new file mode 100644 index 000000000000..5d357a94599e --- /dev/null +++ b/drivers/usb/phy/phy-qcom-8x16-usb.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2015, Linaro Limited + * + * 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 + * only 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HSPHY_AHBBURST 0x0090 +#define HSPHY_AHBMODE 0x0098 +#define HSPHY_GENCONFIG 0x009c +#define HSPHY_GENCONFIG_2 0x00a0 + +#define HSPHY_USBCMD 0x0140 +#define HSPHY_ULPI_VIEWPORT 0x0170 +#define HSPHY_CTRL 0x0240 + +#define HSPHY_TXFIFO_IDLE_FORCE_DIS BIT(4) +#define HSPHY_SESS_VLD_CTRL_EN BIT(7) +#define HSPHY_POR_ASSERT BIT(0) +#define HSPHY_RETEN BIT(1) + +#define HSPHY_SESS_VLD_CTRL BIT(25) + +#define ULPI_PWR_CLK_MNG_REG 0x88 +#define ULPI_PWR_OTG_COMP_DISABLE BIT(0) + +#define ULPI_MISC_A 0x96 +#define ULPI_MISC_A_VBUSVLDEXTSEL BIT(1) +#define ULPI_MISC_A_VBUSVLDEXT BIT(0) + +#define HSPHY_3P3_MIN 3050000 /* uV */ +#define HSPHY_3P3_MAX 3300000 /* uV */ + +#define HSPHY_1P8_MIN 1800000 /* uV */ +#define HSPHY_1P8_MAX 1800000 /* uV */ + +#define HSPHY_VDD_MIN 5 +#define HSPHY_VDD_MAX 7 + +struct phy_8x16 { + struct usb_phy phy; + void __iomem *regs; + struct clk *core_clk; + struct clk *iface_clk; + struct regulator *v3p3; + struct regulator *v1p8; + struct regulator *vdd; + + struct reset_control *phy_reset; + + struct extcon_specific_cable_nb vbus_cable; + struct notifier_block vbus_notify; + + struct gpio_desc *switch_gpio; + struct notifier_block reboot_notify; +}; + +static int phy_8x16_regulators_enable(struct phy_8x16 *qphy) +{ + int ret; + + ret = regulator_set_voltage(qphy->vdd, HSPHY_VDD_MIN, HSPHY_VDD_MAX); + if (ret) + return ret; + + ret = regulator_enable(qphy->vdd); + if (ret) + return ret; + + ret = regulator_set_voltage(qphy->v3p3, HSPHY_3P3_MIN, HSPHY_3P3_MAX); + if (ret) + goto off_vdd; + + ret = regulator_enable(qphy->v3p3); + if (ret) + goto off_vdd; + + ret = regulator_set_voltage(qphy->v1p8, HSPHY_1P8_MIN, HSPHY_1P8_MAX); + if (ret) + goto off_3p3; + + ret = regulator_enable(qphy->v1p8); + if (ret) + goto off_3p3; + + return 0; + +off_3p3: + regulator_disable(qphy->v3p3); +off_vdd: + regulator_disable(qphy->vdd); + + return ret; +} + +static void phy_8x16_regulators_disable(struct phy_8x16 *qphy) +{ + regulator_disable(qphy->v1p8); + regulator_disable(qphy->v3p3); + regulator_disable(qphy->vdd); +} + +static int phy_8x16_notify_connect(struct usb_phy *phy, + enum usb_device_speed speed) +{ + struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy); + u32 val; + + val = ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT; + usb_phy_io_write(&qphy->phy, val, ULPI_SET(ULPI_MISC_A)); + + val = readl(qphy->regs + HSPHY_USBCMD); + val |= HSPHY_SESS_VLD_CTRL; + writel(val, qphy->regs + HSPHY_USBCMD); + + return 0; +} + +static int phy_8x16_notify_disconnect(struct usb_phy *phy, + enum usb_device_speed speed) +{ + struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy); + u32 val; + + val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL; + usb_phy_io_write(&qphy->phy, val, ULPI_CLR(ULPI_MISC_A)); + + val = readl(qphy->regs + HSPHY_USBCMD); + val &= ~HSPHY_SESS_VLD_CTRL; + writel(val, qphy->regs + HSPHY_USBCMD); + + return 0; +} + +static int phy_8x16_vbus_on(struct phy_8x16 *qphy) +{ + phy_8x16_notify_connect(&qphy->phy, USB_SPEED_UNKNOWN); + + /* Switch D+/D- lines to Device connector */ + gpiod_set_value_cansleep(qphy->switch_gpio, 0); + + return 0; +} + +static int phy_8x16_vbus_off(struct phy_8x16 *qphy) +{ + phy_8x16_notify_disconnect(&qphy->phy, USB_SPEED_UNKNOWN); + + /* Switch D+/D- lines to USB HUB */ + gpiod_set_value_cansleep(qphy->switch_gpio, 1); + + return 0; +} + +static int phy_8x16_vbus_notify(struct notifier_block *nb, unsigned long event, + void *ptr) +{ + struct phy_8x16 *qphy = container_of(nb, struct phy_8x16, vbus_notify); + + if (event) + phy_8x16_vbus_on(qphy); + else + phy_8x16_vbus_off(qphy); + + return NOTIFY_DONE; +} + +static int phy_8x16_init(struct usb_phy *phy) +{ + struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy); + u32 val, init[] = {0x44, 0x6B, 0x24, 0x13}; + u32 addr = ULPI_EXT_VENDOR_SPECIFIC; + int idx, state; + + for (idx = 0; idx < ARRAY_SIZE(init); idx++) + usb_phy_io_write(phy, init[idx], addr + idx); + + reset_control_reset(qphy->phy_reset); + + /* Assert USB HSPHY_POR */ + val = readl(qphy->regs + HSPHY_CTRL); + val |= HSPHY_POR_ASSERT; + writel(val, qphy->regs + HSPHY_CTRL); + + /* + * wait for minimum 10 microseconds as suggested in HPG. + * Use a slightly larger value since the exact value didn't + * work 100% of the time. + */ + usleep_range(12, 15); + + /* Deassert USB HSPHY_POR */ + val = readl(qphy->regs + HSPHY_CTRL); + val &= ~HSPHY_POR_ASSERT; + writel(val, qphy->regs + HSPHY_CTRL); + + usleep_range(10, 15); + + writel(0x00, qphy->regs + HSPHY_AHBBURST); + writel(0x08, qphy->regs + HSPHY_AHBMODE); + + /* workaround for rx buffer collision issue */ + val = readl(qphy->regs + HSPHY_GENCONFIG); + val &= ~HSPHY_TXFIFO_IDLE_FORCE_DIS; + writel(val, qphy->regs + HSPHY_GENCONFIG); + + val = readl(qphy->regs + HSPHY_GENCONFIG_2); + val |= HSPHY_SESS_VLD_CTRL_EN; + writel(val, qphy->regs + HSPHY_GENCONFIG_2); + + val = ULPI_PWR_OTG_COMP_DISABLE; + usb_phy_io_write(phy, val, ULPI_SET(ULPI_PWR_CLK_MNG_REG)); + + state = extcon_get_cable_state(qphy->vbus_cable.edev, "USB"); + if (state) + phy_8x16_vbus_on(qphy); + else + phy_8x16_vbus_off(qphy); + + val = usb_phy_io_read(&qphy->phy, ULPI_FUNC_CTRL); + val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + val |= ULPI_FUNC_CTRL_OPMODE_NORMAL; + usb_phy_io_write(&qphy->phy, val, ULPI_FUNC_CTRL); + + return 0; +} + +static void phy_8x16_shutdown(struct usb_phy *phy) +{ + u32 val; + + /* Put the controller in non-driving mode */ + val = usb_phy_io_read(phy, ULPI_FUNC_CTRL); + val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; + val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; + usb_phy_io_write(phy, val, ULPI_FUNC_CTRL); +} + +static int phy_8x16_read_devicetree(struct phy_8x16 *qphy) +{ + struct regulator_bulk_data regs[3]; + struct device *dev = qphy->phy.dev; + int ret; + + qphy->core_clk = devm_clk_get(dev, "core"); + if (IS_ERR(qphy->core_clk)) + return PTR_ERR(qphy->core_clk); + + qphy->iface_clk = devm_clk_get(dev, "iface"); + if (IS_ERR(qphy->iface_clk)) + return PTR_ERR(qphy->iface_clk); + + regs[0].supply = "v3p3"; + regs[1].supply = "v1p8"; + regs[2].supply = "vddcx"; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(regs), regs); + if (ret) + return ret; + + qphy->v3p3 = regs[0].consumer; + qphy->v1p8 = regs[1].consumer; + qphy->vdd = regs[2].consumer; + + qphy->phy_reset = devm_reset_control_get(dev, "phy"); + if (IS_ERR(qphy->phy_reset)) + return PTR_ERR(qphy->phy_reset); + + qphy->switch_gpio = devm_gpiod_get_optional(dev, "switch", + GPIOD_OUT_LOW); + if (IS_ERR(qphy->switch_gpio)) + return PTR_ERR(qphy->switch_gpio); + + return 0; +} + +static int phy_8x16_reboot_notify(struct notifier_block *this, + unsigned long code, void *unused) +{ + struct phy_8x16 *qphy; + + qphy = container_of(this, struct phy_8x16, reboot_notify); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot_notify + */ + gpiod_set_value_cansleep(qphy->switch_gpio, 0); + return NOTIFY_DONE; +} + +static int phy_8x16_probe(struct platform_device *pdev) +{ + struct extcon_dev *edev; + struct phy_8x16 *qphy; + struct resource *res; + struct usb_phy *phy; + int ret; + + qphy = devm_kzalloc(&pdev->dev, sizeof(*qphy), GFP_KERNEL); + if (!qphy) + return -ENOMEM; + + platform_set_drvdata(pdev, qphy); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + qphy->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!qphy->regs) + return -ENOMEM; + + phy = &qphy->phy; + phy->dev = &pdev->dev; + phy->label = dev_name(&pdev->dev); + phy->init = phy_8x16_init; + phy->shutdown = phy_8x16_shutdown; + phy->notify_connect = phy_8x16_notify_connect; + phy->notify_disconnect = phy_8x16_notify_disconnect; + phy->io_priv = qphy->regs + HSPHY_ULPI_VIEWPORT; + phy->io_ops = &ulpi_viewport_access_ops; + phy->type = USB_PHY_TYPE_USB2; + + ret = phy_8x16_read_devicetree(qphy); + if (ret < 0) + return ret; + + edev = extcon_get_edev_by_phandle(phy->dev, 0); + if (IS_ERR(edev)) + return PTR_ERR(edev); + + ret = clk_set_rate(qphy->core_clk, INT_MAX); + if (ret < 0) + dev_dbg(phy->dev, "Can't boost core clock\n"); + + ret = clk_prepare_enable(qphy->core_clk); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(qphy->iface_clk); + if (ret < 0) + goto off_core; + + ret = phy_8x16_regulators_enable(qphy); + if (0 && ret) + goto off_clks; + + qphy->vbus_notify.notifier_call = phy_8x16_vbus_notify; + ret = extcon_register_interest(&qphy->vbus_cable, edev->name, + "USB", &qphy->vbus_notify); + if (ret < 0) + goto off_power; + + ret = usb_add_phy_dev(&qphy->phy); + if (ret) + goto off_extcon; + + qphy->reboot_notify.notifier_call = phy_8x16_reboot_notify; + register_reboot_notifier(&qphy->reboot_notify); + + return 0; + +off_extcon: + extcon_unregister_interest(&qphy->vbus_cable); +off_power: + phy_8x16_regulators_disable(qphy); +off_clks: + clk_disable_unprepare(qphy->iface_clk); +off_core: + clk_disable_unprepare(qphy->core_clk); + return ret; +} + +static int phy_8x16_remove(struct platform_device *pdev) +{ + struct phy_8x16 *qphy = platform_get_drvdata(pdev); + + unregister_reboot_notifier(&qphy->reboot_notify); + extcon_unregister_interest(&qphy->vbus_cable); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot_notify + */ + gpiod_set_value_cansleep(qphy->switch_gpio, 0); + + usb_remove_phy(&qphy->phy); + + clk_disable_unprepare(qphy->iface_clk); + clk_disable_unprepare(qphy->core_clk); + phy_8x16_regulators_disable(qphy); + return 0; +} + +static const struct of_device_id phy_8x16_dt_match[] = { + { .compatible = "qcom,usb-8x16-phy" }, + { } +}; +MODULE_DEVICE_TABLE(of, phy_8x16_dt_match); + +static struct platform_driver phy_8x16_driver = { + .probe = phy_8x16_probe, + .remove = phy_8x16_remove, + .driver = { + .name = "phy-qcom-8x16-usb", + .of_match_table = phy_8x16_dt_match, + }, +}; +module_platform_driver(phy_8x16_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm APQ8016/MSM8916 chipsets USB transceiver driver"); -- cgit v1.3-6-gb490 From 5601250bb1b4e736cf487d332f2d8d8833a84209 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 4 May 2015 14:55:12 +0200 Subject: usb: composite: fix usb_function_activate/deactivate functions Using usb_gadget_disconnect to make gadget temporarily invisible to host doesn't provide desired result, because gadget is connected immediately after binding regardless to previous usb_gadget_disconnect() calls. For this reason we use usb_gadget_deactivate() instead of usb_gadget_disconnect() to make it working as expected. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 9ff3203b50e2..86d4e8fdf8d3 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -279,7 +279,7 @@ int usb_function_deactivate(struct usb_function *function) spin_lock_irqsave(&cdev->lock, flags); if (cdev->deactivations == 0) - status = usb_gadget_disconnect(cdev->gadget); + status = usb_gadget_deactivate(cdev->gadget); if (status == 0) cdev->deactivations++; @@ -311,7 +311,7 @@ int usb_function_activate(struct usb_function *function) else { cdev->deactivations--; if (cdev->deactivations == 0) - status = usb_gadget_connect(cdev->gadget); + status = usb_gadget_activate(cdev->gadget); } spin_unlock_irqrestore(&cdev->lock, flags); -- cgit v1.3-6-gb490 From d5bb9b81dbfa35d117ecb58022ee6e7e41e4772d Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 4 May 2015 14:55:13 +0200 Subject: usb: composite: add bind_deactivated flag to usb_function This patch introduces 'bind_deactivated' flag in struct usb_function. Functions which don't want to be activated automatically after bind should set this flag, and when they start to be ready to work they should call usb_function_activate(). When USB function sets 'bind_deactivated' flag, initial deactivation counter is incremented automatically, so there is no need to call usb_function_deactivate() in function bind. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 6 ++++++ include/linux/usb/composite.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 86d4e8fdf8d3..36c6f47642f8 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -209,6 +209,12 @@ int usb_add_function(struct usb_configuration *config, function->config = config; list_add_tail(&function->list, &config->functions); + if (function->bind_deactivated) { + value = usb_function_deactivate(function); + if (value) + goto done; + } + /* REVISIT *require* function->bind? */ if (function->bind) { value = function->bind(config, function); diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 2511469a9904..1074b8921a5d 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -228,6 +228,8 @@ struct usb_function { struct list_head list; DECLARE_BITMAP(endpoints, 32); const struct usb_function_instance *fi; + + unsigned int bind_deactivated:1; }; int usb_add_function(struct usb_configuration *, struct usb_function *); -- cgit v1.3-6-gb490 From f277bf27cf5cd56bcd1c4b95ae140f61680a6e83 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 4 May 2015 14:55:14 +0200 Subject: usb: gadget: f_uvc: use bind_deactivated flag Use bind_deactivated flag instead of calling usb_function_deactivate() in function bind(). Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uvc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index cf0df8fbba89..743be34605dc 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -733,12 +733,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) uvc->control_req->complete = uvc_function_ep0_complete; uvc->control_req->context = uvc; - /* Avoid letting this gadget enumerate until the userspace server is - * active. - */ - if ((ret = usb_function_deactivate(f)) < 0) - goto error; - if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) { printk(KERN_INFO "v4l2_device_register failed\n"); goto error; @@ -949,6 +943,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) uvc->func.disable = uvc_function_disable; uvc->func.setup = uvc_function_setup; uvc->func.free_func = uvc_free; + uvc->func.bind_deactivated = true; return &uvc->func; } -- cgit v1.3-6-gb490 From 4cfbd95232dd6194c04d432d1a8ac45cec269d8b Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 4 May 2015 14:55:15 +0200 Subject: usb: gadget: f_obex: use bind_deactivated flag Use bind_deactivated flag instead of calling usb_function_deactivate() in function bind(). Field 'can_activate' in struct f_obex is no longer needed as setting 'bind_deactivated' flag makes us sure, that the function will be binded only if deactivation can be performed successfully. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_obex.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c index a1b79c53499c..5519f858904b 100644 --- a/drivers/usb/gadget/function/f_obex.c +++ b/drivers/usb/gadget/function/f_obex.c @@ -37,7 +37,6 @@ struct f_obex { u8 data_id; u8 cur_alt; u8 port_num; - u8 can_activate; }; static inline struct f_obex *func_to_obex(struct usb_function *f) @@ -268,9 +267,6 @@ static void obex_connect(struct gserial *g) struct usb_composite_dev *cdev = g->func.config->cdev; int status; - if (!obex->can_activate) - return; - status = usb_function_activate(&g->func); if (status) dev_dbg(&cdev->gadget->dev, @@ -284,9 +280,6 @@ static void obex_disconnect(struct gserial *g) struct usb_composite_dev *cdev = g->func.config->cdev; int status; - if (!obex->can_activate) - return; - status = usb_function_deactivate(&g->func); if (status) dev_dbg(&cdev->gadget->dev, @@ -378,17 +371,6 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f) if (status) goto fail; - /* Avoid letting this gadget enumerate until the userspace - * OBEX server is active. - */ - status = usb_function_deactivate(f); - if (status < 0) - WARNING(cdev, "obex ttyGS%d: can't prevent enumeration, %d\n", - obex->port_num, status); - else - obex->can_activate = true; - - dev_dbg(&cdev->gadget->dev, "obex ttyGS%d: %s speed IN/%s OUT/%s\n", obex->port_num, gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", @@ -529,6 +511,7 @@ static struct usb_function *obex_alloc(struct usb_function_instance *fi) obex->port.func.get_alt = obex_get_alt; obex->port.func.disable = obex_disable; obex->port.func.free_func = obex_free; + obex->port.func.bind_deactivated = true; return &obex->port.func; } -- cgit v1.3-6-gb490 From 744543c599c420bcddca08cd2e2713b82a008328 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 8 Jul 2015 16:41:38 +0200 Subject: usb: musb: sunxi: Add support for the Allwinner sunxi musb controller This is based on initial code to get the Allwinner sunxi musb controller supported by Chen-Yu Tsai and Roman Byshko. This adds support for the Allwinner sunxi musb controller in both host only and otg mode. Peripheral only mode is not supported, as no boards use that. This has been tested on a cubietruck (A20 SoC) and an UTOO P66 tablet (A13 SoC) with a variety of devices in host mode and with the g_serial gadget driver in peripheral mode, plugging otg / host cables in/out a lot of times in all possible imaginable plug orders. Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi --- .../bindings/usb/allwinner,sun4i-a10-musb.txt | 27 + drivers/usb/musb/Kconfig | 13 +- drivers/usb/musb/Makefile | 1 + drivers/usb/musb/sunxi.c | 703 +++++++++++++++++++++ 4 files changed, 743 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt create mode 100644 drivers/usb/musb/sunxi.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt new file mode 100644 index 000000000000..9254a6c81808 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt @@ -0,0 +1,27 @@ +Allwinner sun4i A10 musb DRC/OTG controller +------------------------------------------- + +Required properties: + - compatible : "allwinner,sun4i-a10-musb" + - reg : mmio address range of the musb controller + - clocks : clock specifier for the musb controller ahb gate clock + - interrupts : interrupt to which the musb controller is connected + - interrupt-names : must be "mc" + - phys : phy specifier for the otg phy + - phy-names : must be "usb" + - dr_mode : Dual-Role mode must be "host" or "otg" + - extcon : extcon specifier for the otg phy + +Example: + + usb_otg: usb@01c13000 { + compatible = "allwinner,sun4i-a10-musb"; + reg = <0x01c13000 0x0400>; + clocks = <&ahb_gates 0>; + interrupts = <38>; + interrupt-names = "mc"; + phys = <&usbphy 0>; + phy-names = "usb"; + extcon = <&usbphy 0>; + status = "disabled"; + }; diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 39db8b603627..37081ed8f295 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -5,7 +5,7 @@ # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller config USB_MUSB_HDRC - tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' + tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...)' depends on (USB || USB_GADGET) help Say Y here if your system has a dual role high speed USB @@ -20,6 +20,8 @@ config USB_MUSB_HDRC Analog Devices parts using this IP include Blackfin BF54x, BF525 and BF527. + Allwinner SoCs using this IP include A10, A13, A20, ... + If you do not know what this is, please say N. To compile this driver as a module, choose M here; the @@ -60,6 +62,15 @@ endchoice comment "Platform Glue Layer" +config USB_MUSB_SUNXI + tristate "Allwinner (sunxi)" + depends on ARCH_SUNXI + depends on NOP_USB_XCEIV + depends on PHY_SUN4I_USB + depends on EXTCON + depends on GENERIC_PHY + select SUNXI_SRAM + config USB_MUSB_DAVINCI tristate "DaVinci" depends on ARCH_DAVINCI_DMx diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index ba495018b416..f95befe18cc1 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o obj-$(CONFIG_USB_MUSB_UX500) += ux500.o obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o +obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c new file mode 100644 index 000000000000..00d7248a4840 --- /dev/null +++ b/drivers/usb/musb/sunxi.c @@ -0,0 +1,703 @@ +/* + * Allwinner sun4i MUSB Glue Layer + * + * Copyright (C) 2015 Hans de Goede + * + * Based on code from + * Allwinner Technology Co., Ltd. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "musb_core.h" + +/* + * Register offsets, note sunxi musb has a different layout then most + * musb implementations, we translate the layout in musb_readb & friends. + */ +#define SUNXI_MUSB_POWER 0x0040 +#define SUNXI_MUSB_DEVCTL 0x0041 +#define SUNXI_MUSB_INDEX 0x0042 +#define SUNXI_MUSB_VEND0 0x0043 +#define SUNXI_MUSB_INTRTX 0x0044 +#define SUNXI_MUSB_INTRRX 0x0046 +#define SUNXI_MUSB_INTRTXE 0x0048 +#define SUNXI_MUSB_INTRRXE 0x004a +#define SUNXI_MUSB_INTRUSB 0x004c +#define SUNXI_MUSB_INTRUSBE 0x0050 +#define SUNXI_MUSB_FRAME 0x0054 +#define SUNXI_MUSB_TXFIFOSZ 0x0090 +#define SUNXI_MUSB_TXFIFOADD 0x0092 +#define SUNXI_MUSB_RXFIFOSZ 0x0094 +#define SUNXI_MUSB_RXFIFOADD 0x0096 +#define SUNXI_MUSB_FADDR 0x0098 +#define SUNXI_MUSB_TXFUNCADDR 0x0098 +#define SUNXI_MUSB_TXHUBADDR 0x009a +#define SUNXI_MUSB_TXHUBPORT 0x009b +#define SUNXI_MUSB_RXFUNCADDR 0x009c +#define SUNXI_MUSB_RXHUBADDR 0x009e +#define SUNXI_MUSB_RXHUBPORT 0x009f +#define SUNXI_MUSB_CONFIGDATA 0x00c0 + +/* VEND0 bits */ +#define SUNXI_MUSB_VEND0_PIO_MODE 0 + +/* flags */ +#define SUNXI_MUSB_FL_ENABLED 0 +#define SUNXI_MUSB_FL_HOSTMODE 1 +#define SUNXI_MUSB_FL_HOSTMODE_PEND 2 +#define SUNXI_MUSB_FL_VBUS_ON 3 +#define SUNXI_MUSB_FL_PHY_ON 4 + +/* Our read/write methods need access and do not get passed in a musb ref :| */ +static struct musb *sunxi_musb; + +struct sunxi_glue { + struct device *dev; + struct platform_device *musb; + struct clk *clk; + struct phy *phy; + struct platform_device *usb_phy; + struct usb_phy *xceiv; + unsigned long flags; + struct work_struct work; + struct extcon_dev *extcon; + struct notifier_block host_nb; +}; + +/* phy_power_on / off may sleep, so we use a workqueue */ +static void sunxi_musb_work(struct work_struct *work) +{ + struct sunxi_glue *glue = container_of(work, struct sunxi_glue, work); + bool vbus_on, phy_on; + + if (!test_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags)) + return; + + if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) { + struct musb *musb = platform_get_drvdata(glue->musb); + unsigned long flags; + u8 devctl; + + spin_lock_irqsave(&musb->lock, flags); + + devctl = readb(musb->mregs + SUNXI_MUSB_DEVCTL); + if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) { + set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + musb->xceiv->otg->default_a = 1; + musb->xceiv->otg->state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); + devctl |= MUSB_DEVCTL_SESSION; + } else { + clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + musb->xceiv->otg->default_a = 0; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; + MUSB_DEV_MODE(musb); + devctl &= ~MUSB_DEVCTL_SESSION; + } + writeb(devctl, musb->mregs + SUNXI_MUSB_DEVCTL); + + spin_unlock_irqrestore(&musb->lock, flags); + } + + vbus_on = test_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + phy_on = test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + + if (phy_on != vbus_on) { + if (vbus_on) { + phy_power_on(glue->phy); + set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + } else { + phy_power_off(glue->phy); + clear_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + } + } +} + +static void sunxi_musb_set_vbus(struct musb *musb, int is_on) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + if (is_on) + set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + else + clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + + schedule_work(&glue->work); +} + +static void sunxi_musb_pre_root_reset_end(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + sun4i_usb_phy_set_squelch_detect(glue->phy, false); +} + +static void sunxi_musb_post_root_reset_end(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + sun4i_usb_phy_set_squelch_detect(glue->phy, true); +} + +static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci) +{ + struct musb *musb = __hci; + unsigned long flags; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = readb(musb->mregs + SUNXI_MUSB_INTRUSB); + if (musb->int_usb) + writeb(musb->int_usb, musb->mregs + SUNXI_MUSB_INTRUSB); + + /* + * sunxi musb often signals babble on low / full speed device + * disconnect, without ever raising MUSB_INTR_DISCONNECT, since + * normally babble never happens treat it as disconnect. + */ + if ((musb->int_usb & MUSB_INTR_BABBLE) && is_host_active(musb)) { + musb->int_usb &= ~MUSB_INTR_BABBLE; + musb->int_usb |= MUSB_INTR_DISCONNECT; + } + + if ((musb->int_usb & MUSB_INTR_RESET) && !is_host_active(musb)) { + /* ep0 FADDR must be 0 when (re)entering peripheral mode */ + musb_ep_select(musb->mregs, 0); + musb_writeb(musb->mregs, MUSB_FADDR, 0); + } + + musb->int_tx = readw(musb->mregs + SUNXI_MUSB_INTRTX); + if (musb->int_tx) + writew(musb->int_tx, musb->mregs + SUNXI_MUSB_INTRTX); + + musb->int_rx = readw(musb->mregs + SUNXI_MUSB_INTRRX); + if (musb->int_rx) + writew(musb->int_rx, musb->mregs + SUNXI_MUSB_INTRRX); + + musb_interrupt(musb); + + spin_unlock_irqrestore(&musb->lock, flags); + + return IRQ_HANDLED; +} + +static int sunxi_musb_host_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct sunxi_glue *glue = container_of(nb, struct sunxi_glue, host_nb); + + if (event) + set_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags); + else + clear_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags); + + set_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags); + schedule_work(&glue->work); + + return NOTIFY_DONE; +} + +static int sunxi_musb_init(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + int ret; + + sunxi_musb = musb; + musb->phy = glue->phy; + musb->xceiv = glue->xceiv; + + ret = sunxi_sram_claim(musb->controller->parent); + if (ret) + return ret; + + ret = clk_prepare_enable(glue->clk); + if (ret) + goto error_sram_release; + + writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0); + + /* Register notifier before calling phy_init() */ + if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) { + ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); + if (ret) + goto error_clk_disable; + } + + ret = phy_init(glue->phy); + if (ret) + goto error_unregister_notifier; + + if (musb->port_mode == MUSB_PORT_MODE_HOST) { + ret = phy_power_on(glue->phy); + if (ret) + goto error_phy_exit; + set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags); + /* Stop musb work from turning vbus off again */ + set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags); + } + + musb->isr = sunxi_musb_interrupt; + + /* Stop the musb-core from doing runtime pm (not supported on sunxi) */ + pm_runtime_get(musb->controller); + + return 0; + +error_phy_exit: + phy_exit(glue->phy); +error_unregister_notifier: + if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) + extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); +error_clk_disable: + clk_disable_unprepare(glue->clk); +error_sram_release: + sunxi_sram_release(musb->controller->parent); + return ret; +} + +static int sunxi_musb_exit(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + pm_runtime_put(musb->controller); + + cancel_work_sync(&glue->work); + if (test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags)) + phy_power_off(glue->phy); + + phy_exit(glue->phy); + + if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) + extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, + &glue->host_nb); + + clk_disable_unprepare(glue->clk); + sunxi_sram_release(musb->controller->parent); + + return 0; +} + +static void sunxi_musb_enable(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + /* musb_core does not call us in a balanced manner */ + if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags)) + return; + + schedule_work(&glue->work); +} + +static void sunxi_musb_disable(struct musb *musb) +{ + struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent); + + clear_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags); +} + +/* + * sunxi musb register layout + * 0x00 - 0x17 fifo regs, 1 long per fifo + * 0x40 - 0x57 generic control regs (power - frame) + * 0x80 - 0x8f ep control regs (addressed through hw_ep->regs, indexed) + * 0x90 - 0x97 fifo control regs (indexed) + * 0x98 - 0x9f multipoint / busctl regs (indexed) + * 0xc0 configdata reg + */ + +static u32 sunxi_musb_fifo_offset(u8 epnum) +{ + return (epnum * 4); +} + +static u32 sunxi_musb_ep_offset(u8 epnum, u16 offset) +{ + WARN_ONCE(offset != 0, + "sunxi_musb_ep_offset called with non 0 offset\n"); + + return 0x80; /* indexed, so ignore epnum */ +} + +static u32 sunxi_musb_busctl_offset(u8 epnum, u16 offset) +{ + return SUNXI_MUSB_TXFUNCADDR + offset; +} + +static u8 sunxi_musb_readb(const void __iomem *addr, unsigned offset) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_FADDR: + return readb(addr + SUNXI_MUSB_FADDR); + case MUSB_POWER: + return readb(addr + SUNXI_MUSB_POWER); + case MUSB_INTRUSB: + return readb(addr + SUNXI_MUSB_INTRUSB); + case MUSB_INTRUSBE: + return readb(addr + SUNXI_MUSB_INTRUSBE); + case MUSB_INDEX: + return readb(addr + SUNXI_MUSB_INDEX); + case MUSB_TESTMODE: + return 0; /* No testmode on sunxi */ + case MUSB_DEVCTL: + return readb(addr + SUNXI_MUSB_DEVCTL); + case MUSB_TXFIFOSZ: + return readb(addr + SUNXI_MUSB_TXFIFOSZ); + case MUSB_RXFIFOSZ: + return readb(addr + SUNXI_MUSB_RXFIFOSZ); + case MUSB_CONFIGDATA + 0x10: /* See musb_read_configdata() */ + return readb(addr + SUNXI_MUSB_CONFIGDATA); + /* Offset for these is fixed by sunxi_musb_busctl_offset() */ + case SUNXI_MUSB_TXFUNCADDR: + case SUNXI_MUSB_TXHUBADDR: + case SUNXI_MUSB_TXHUBPORT: + case SUNXI_MUSB_RXFUNCADDR: + case SUNXI_MUSB_RXHUBADDR: + case SUNXI_MUSB_RXHUBPORT: + /* multipoint / busctl reg access */ + return readb(addr + offset); + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown readb offset %u\n", offset); + return 0; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + /* sunxi has a 2 byte hole before the txtype register */ + if (offset >= MUSB_TXTYPE) + offset += 2; + return readb(addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown readb at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); + return 0; +} + +static void sunxi_musb_writeb(void __iomem *addr, unsigned offset, u8 data) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_FADDR: + return writeb(data, addr + SUNXI_MUSB_FADDR); + case MUSB_POWER: + return writeb(data, addr + SUNXI_MUSB_POWER); + case MUSB_INTRUSB: + return writeb(data, addr + SUNXI_MUSB_INTRUSB); + case MUSB_INTRUSBE: + return writeb(data, addr + SUNXI_MUSB_INTRUSBE); + case MUSB_INDEX: + return writeb(data, addr + SUNXI_MUSB_INDEX); + case MUSB_TESTMODE: + if (data) + dev_warn(sunxi_musb->controller->parent, + "sunxi-musb does not have testmode\n"); + return; + case MUSB_DEVCTL: + return writeb(data, addr + SUNXI_MUSB_DEVCTL); + case MUSB_TXFIFOSZ: + return writeb(data, addr + SUNXI_MUSB_TXFIFOSZ); + case MUSB_RXFIFOSZ: + return writeb(data, addr + SUNXI_MUSB_RXFIFOSZ); + /* Offset for these is fixed by sunxi_musb_busctl_offset() */ + case SUNXI_MUSB_TXFUNCADDR: + case SUNXI_MUSB_TXHUBADDR: + case SUNXI_MUSB_TXHUBPORT: + case SUNXI_MUSB_RXFUNCADDR: + case SUNXI_MUSB_RXHUBADDR: + case SUNXI_MUSB_RXHUBPORT: + /* multipoint / busctl reg access */ + return writeb(data, addr + offset); + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown writeb offset %u\n", offset); + return; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + if (offset >= MUSB_TXTYPE) + offset += 2; + return writeb(data, addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown writeb at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); +} + +static u16 sunxi_musb_readw(const void __iomem *addr, unsigned offset) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_INTRTX: + return readw(addr + SUNXI_MUSB_INTRTX); + case MUSB_INTRRX: + return readw(addr + SUNXI_MUSB_INTRRX); + case MUSB_INTRTXE: + return readw(addr + SUNXI_MUSB_INTRTXE); + case MUSB_INTRRXE: + return readw(addr + SUNXI_MUSB_INTRRXE); + case MUSB_FRAME: + return readw(addr + SUNXI_MUSB_FRAME); + case MUSB_TXFIFOADD: + return readw(addr + SUNXI_MUSB_TXFIFOADD); + case MUSB_RXFIFOADD: + return readw(addr + SUNXI_MUSB_RXFIFOADD); + case MUSB_HWVERS: + return 0; /* sunxi musb version is not known */ + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown readw offset %u\n", offset); + return 0; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + return readw(addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown readw at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); + return 0; +} + +static void sunxi_musb_writew(void __iomem *addr, unsigned offset, u16 data) +{ + if (addr == sunxi_musb->mregs) { + /* generic control or fifo control reg access */ + switch (offset) { + case MUSB_INTRTX: + return writew(data, addr + SUNXI_MUSB_INTRTX); + case MUSB_INTRRX: + return writew(data, addr + SUNXI_MUSB_INTRRX); + case MUSB_INTRTXE: + return writew(data, addr + SUNXI_MUSB_INTRTXE); + case MUSB_INTRRXE: + return writew(data, addr + SUNXI_MUSB_INTRRXE); + case MUSB_FRAME: + return writew(data, addr + SUNXI_MUSB_FRAME); + case MUSB_TXFIFOADD: + return writew(data, addr + SUNXI_MUSB_TXFIFOADD); + case MUSB_RXFIFOADD: + return writew(data, addr + SUNXI_MUSB_RXFIFOADD); + default: + dev_err(sunxi_musb->controller->parent, + "Error unknown writew offset %u\n", offset); + return; + } + } else if (addr == (sunxi_musb->mregs + 0x80)) { + /* ep control reg access */ + return writew(data, addr + offset); + } + + dev_err(sunxi_musb->controller->parent, + "Error unknown writew at 0x%x bytes offset\n", + (int)(addr - sunxi_musb->mregs)); +} + +static const struct musb_platform_ops sunxi_musb_ops = { + .quirks = MUSB_INDEXED_EP, + .init = sunxi_musb_init, + .exit = sunxi_musb_exit, + .enable = sunxi_musb_enable, + .disable = sunxi_musb_disable, + .fifo_offset = sunxi_musb_fifo_offset, + .ep_offset = sunxi_musb_ep_offset, + .busctl_offset = sunxi_musb_busctl_offset, + .readb = sunxi_musb_readb, + .writeb = sunxi_musb_writeb, + .readw = sunxi_musb_readw, + .writew = sunxi_musb_writew, + .set_vbus = sunxi_musb_set_vbus, + .pre_root_reset_end = sunxi_musb_pre_root_reset_end, + .post_root_reset_end = sunxi_musb_post_root_reset_end, +}; + +/* Allwinner OTG supports up to 5 endpoints */ +#define SUNXI_MUSB_MAX_EP_NUM 6 +#define SUNXI_MUSB_RAM_BITS 11 + +static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = { + MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512), +}; + +static struct musb_hdrc_config sunxi_musb_hdrc_config = { + .fifo_cfg = sunxi_musb_mode_cfg, + .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg), + .multipoint = true, + .dyn_fifo = true, + .soft_con = true, + .num_eps = SUNXI_MUSB_MAX_EP_NUM, + .ram_bits = SUNXI_MUSB_RAM_BITS, + .dma = 0, +}; + +static int sunxi_musb_probe(struct platform_device *pdev) +{ + struct musb_hdrc_platform_data pdata; + struct platform_device_info pinfo; + struct sunxi_glue *glue; + struct device_node *np = pdev->dev.of_node; + int ret; + + if (!np) { + dev_err(&pdev->dev, "Error no device tree node found\n"); + return -EINVAL; + } + + glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); + if (!glue) + return -ENOMEM; + + memset(&pdata, 0, sizeof(pdata)); + switch (of_usb_get_dr_mode(np)) { +#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST + case USB_DR_MODE_HOST: + pdata.mode = MUSB_PORT_MODE_HOST; + break; +#endif +#ifdef CONFIG_USB_MUSB_DUAL_ROLE + case USB_DR_MODE_OTG: + glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0); + if (IS_ERR(glue->extcon)) { + if (PTR_ERR(glue->extcon) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "Invalid or missing extcon\n"); + return PTR_ERR(glue->extcon); + } + pdata.mode = MUSB_PORT_MODE_DUAL_ROLE; + break; +#endif + default: + dev_err(&pdev->dev, "Invalid or missing 'dr_mode' property\n"); + return -EINVAL; + } + pdata.platform_ops = &sunxi_musb_ops; + pdata.config = &sunxi_musb_hdrc_config; + + glue->dev = &pdev->dev; + INIT_WORK(&glue->work, sunxi_musb_work); + glue->host_nb.notifier_call = sunxi_musb_host_notifier; + + glue->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(glue->clk)) { + dev_err(&pdev->dev, "Error getting clock: %ld\n", + PTR_ERR(glue->clk)); + return PTR_ERR(glue->clk); + } + + glue->phy = devm_phy_get(&pdev->dev, "usb"); + if (IS_ERR(glue->phy)) { + if (PTR_ERR(glue->phy) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "Error getting phy %ld\n", + PTR_ERR(glue->phy)); + return PTR_ERR(glue->phy); + } + + glue->usb_phy = usb_phy_generic_register(); + if (IS_ERR(glue->usb_phy)) { + dev_err(&pdev->dev, "Error registering usb-phy %ld\n", + PTR_ERR(glue->usb_phy)); + return PTR_ERR(glue->usb_phy); + } + + glue->xceiv = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); + if (IS_ERR(glue->xceiv)) { + ret = PTR_ERR(glue->xceiv); + dev_err(&pdev->dev, "Error getting usb-phy %d\n", ret); + goto err_unregister_usb_phy; + } + + platform_set_drvdata(pdev, glue); + + memset(&pinfo, 0, sizeof(pinfo)); + pinfo.name = "musb-hdrc"; + pinfo.id = PLATFORM_DEVID_AUTO; + pinfo.parent = &pdev->dev; + pinfo.res = pdev->resource; + pinfo.num_res = pdev->num_resources; + pinfo.data = &pdata; + pinfo.size_data = sizeof(pdata); + + glue->musb = platform_device_register_full(&pinfo); + if (IS_ERR(glue->musb)) { + ret = PTR_ERR(glue->musb); + dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret); + goto err_unregister_usb_phy; + } + + return 0; + +err_unregister_usb_phy: + usb_phy_generic_unregister(glue->usb_phy); + return ret; +} + +static int sunxi_musb_remove(struct platform_device *pdev) +{ + struct sunxi_glue *glue = platform_get_drvdata(pdev); + struct platform_device *usb_phy = glue->usb_phy; + + platform_device_unregister(glue->musb); /* Frees glue ! */ + usb_phy_generic_unregister(usb_phy); + + return 0; +} + +static const struct of_device_id sunxi_musb_match[] = { + { .compatible = "allwinner,sun4i-a10-musb", }, + {} +}; + +static struct platform_driver sunxi_musb_driver = { + .probe = sunxi_musb_probe, + .remove = sunxi_musb_remove, + .driver = { + .name = "musb-sunxi", + .of_match_table = sunxi_musb_match, + }, +}; +module_platform_driver(sunxi_musb_driver); + +MODULE_DESCRIPTION("Allwinner sunxi MUSB Glue Layer"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From 132e23775779cc895c37f7883c33a60a1a8a7cdd Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 8 Jul 2015 16:41:39 +0200 Subject: usb: musb: sunxi: Add support for musb controller in A31 SoC The A31 SoC uses the same musb controller as found in earlier SoCs, but it is hooked up slightly different. Its SRAM is private and no longer controlled through the SRAM controller, and its reset is controlled via a separate reset controller. This commit adds support for this setup. Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi --- .../bindings/usb/allwinner,sun4i-a10-musb.txt | 3 +- drivers/usb/musb/sunxi.c | 50 +++++++++++++++++++--- 2 files changed, 46 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt index 9254a6c81808..fde180bfb162 100644 --- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt @@ -2,9 +2,10 @@ Allwinner sun4i A10 musb DRC/OTG controller ------------------------------------------- Required properties: - - compatible : "allwinner,sun4i-a10-musb" + - compatible : "allwinner,sun4i-a10-musb" or "allwinner,sun6i-a31-musb" - reg : mmio address range of the musb controller - clocks : clock specifier for the musb controller ahb gate clock + - reset : reset specifier for the ahb reset (A31 and newer only) - interrupts : interrupt to which the musb controller is connected - interrupt-names : must be "mc" - phys : phy specifier for the otg phy diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index 00d7248a4840..df2f75eb9895 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,8 @@ #define SUNXI_MUSB_FL_HOSTMODE_PEND 2 #define SUNXI_MUSB_FL_VBUS_ON 3 #define SUNXI_MUSB_FL_PHY_ON 4 +#define SUNXI_MUSB_FL_HAS_SRAM 5 +#define SUNXI_MUSB_FL_HAS_RESET 6 /* Our read/write methods need access and do not get passed in a musb ref :| */ static struct musb *sunxi_musb; @@ -78,6 +81,7 @@ struct sunxi_glue { struct device *dev; struct platform_device *musb; struct clk *clk; + struct reset_control *rst; struct phy *phy; struct platform_device *usb_phy; struct usb_phy *xceiv; @@ -229,14 +233,22 @@ static int sunxi_musb_init(struct musb *musb) musb->phy = glue->phy; musb->xceiv = glue->xceiv; - ret = sunxi_sram_claim(musb->controller->parent); - if (ret) - return ret; + if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) { + ret = sunxi_sram_claim(musb->controller->parent); + if (ret) + return ret; + } ret = clk_prepare_enable(glue->clk); if (ret) goto error_sram_release; + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) { + ret = reset_control_deassert(glue->rst); + if (ret) + goto error_clk_disable; + } + writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0); /* Register notifier before calling phy_init() */ @@ -244,7 +256,7 @@ static int sunxi_musb_init(struct musb *musb) ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST, &glue->host_nb); if (ret) - goto error_clk_disable; + goto error_reset_assert; } ret = phy_init(glue->phy); @@ -273,10 +285,14 @@ error_unregister_notifier: if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, &glue->host_nb); +error_reset_assert: + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) + reset_control_assert(glue->rst); error_clk_disable: clk_disable_unprepare(glue->clk); error_sram_release: - sunxi_sram_release(musb->controller->parent); + if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) + sunxi_sram_release(musb->controller->parent); return ret; } @@ -296,8 +312,12 @@ static int sunxi_musb_exit(struct musb *musb) extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, &glue->host_nb); + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) + reset_control_assert(glue->rst); + clk_disable_unprepare(glue->clk); - sunxi_sram_release(musb->controller->parent); + if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) + sunxi_sram_release(musb->controller->parent); return 0; } @@ -617,6 +637,12 @@ static int sunxi_musb_probe(struct platform_device *pdev) INIT_WORK(&glue->work, sunxi_musb_work); glue->host_nb.notifier_call = sunxi_musb_host_notifier; + if (of_device_is_compatible(np, "allwinner,sun4i-a10-musb")) + set_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags); + + if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb")) + set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); + glue->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(glue->clk)) { dev_err(&pdev->dev, "Error getting clock: %ld\n", @@ -624,6 +650,17 @@ static int sunxi_musb_probe(struct platform_device *pdev) return PTR_ERR(glue->clk); } + if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) { + glue->rst = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(glue->rst)) { + if (PTR_ERR(glue->rst) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "Error getting reset %ld\n", + PTR_ERR(glue->rst)); + return PTR_ERR(glue->rst); + } + } + glue->phy = devm_phy_get(&pdev->dev, "usb"); if (IS_ERR(glue->phy)) { if (PTR_ERR(glue->phy) == -EPROBE_DEFER) @@ -685,6 +722,7 @@ static int sunxi_musb_remove(struct platform_device *pdev) static const struct of_device_id sunxi_musb_match[] = { { .compatible = "allwinner,sun4i-a10-musb", }, + { .compatible = "allwinner,sun6i-a31-musb", }, {} }; -- cgit v1.3-6-gb490 From d91de093d94eca6e280e50c24b172ed598bb5724 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 8 Jul 2015 16:41:40 +0200 Subject: usb: musb: sunxi: Add support for musb controller in A33 SoC The A33 SoC uses the same musb controller as found on the A31 and later, but allwinner has removed the configdata register, this commit adds special handling for this. Signed-off-by: Hans de Goede Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt | 3 ++- drivers/usb/musb/sunxi.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt index fde180bfb162..862cd7c79805 100644 --- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt @@ -2,7 +2,8 @@ Allwinner sun4i A10 musb DRC/OTG controller ------------------------------------------- Required properties: - - compatible : "allwinner,sun4i-a10-musb" or "allwinner,sun6i-a31-musb" + - compatible : "allwinner,sun4i-a10-musb", "allwinner,sun6i-a31-musb" + or "allwinner,sun8i-a33-musb" - reg : mmio address range of the musb controller - clocks : clock specifier for the musb controller ahb gate clock - reset : reset specifier for the ahb reset (A31 and newer only) diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index df2f75eb9895..f9f6304ad854 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -73,6 +73,7 @@ #define SUNXI_MUSB_FL_PHY_ON 4 #define SUNXI_MUSB_FL_HAS_SRAM 5 #define SUNXI_MUSB_FL_HAS_RESET 6 +#define SUNXI_MUSB_FL_NO_CONFIGDATA 7 /* Our read/write methods need access and do not get passed in a musb ref :| */ static struct musb *sunxi_musb; @@ -370,6 +371,8 @@ static u32 sunxi_musb_busctl_offset(u8 epnum, u16 offset) static u8 sunxi_musb_readb(const void __iomem *addr, unsigned offset) { + struct sunxi_glue *glue; + if (addr == sunxi_musb->mregs) { /* generic control or fifo control reg access */ switch (offset) { @@ -392,6 +395,12 @@ static u8 sunxi_musb_readb(const void __iomem *addr, unsigned offset) case MUSB_RXFIFOSZ: return readb(addr + SUNXI_MUSB_RXFIFOSZ); case MUSB_CONFIGDATA + 0x10: /* See musb_read_configdata() */ + glue = dev_get_drvdata(sunxi_musb->controller->parent); + /* A33 saves a reg, and we get to hardcode this */ + if (test_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, + &glue->flags)) + return 0xde; + return readb(addr + SUNXI_MUSB_CONFIGDATA); /* Offset for these is fixed by sunxi_musb_busctl_offset() */ case SUNXI_MUSB_TXFUNCADDR: @@ -643,6 +652,11 @@ static int sunxi_musb_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb")) set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); + if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb")) { + set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); + set_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, &glue->flags); + } + glue->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(glue->clk)) { dev_err(&pdev->dev, "Error getting clock: %ld\n", @@ -723,6 +737,7 @@ static int sunxi_musb_remove(struct platform_device *pdev) static const struct of_device_id sunxi_musb_match[] = { { .compatible = "allwinner,sun4i-a10-musb", }, { .compatible = "allwinner,sun6i-a31-musb", }, + { .compatible = "allwinner,sun8i-a33-musb", }, {} }; -- cgit v1.3-6-gb490 From 53e6242db8d60da0587d36951cc9434d1a1c21dd Mon Sep 17 00:00:00 2001 From: Macpaul Lin Date: Thu, 9 Jul 2015 15:18:42 +0800 Subject: usb: gadget: composite: add USB_DT_OTG request handling Copy usb_otg_descriptor from config's descriptor if host requests USB_DT_OTG. Signed-off-by: Macpaul Lin Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 36c6f47642f8..b474499839d3 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "u_os_desc.h" @@ -1540,6 +1541,32 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min(w_length, (u16) value); } break; + case USB_DT_OTG: + if (gadget_is_otg(gadget)) { + struct usb_configuration *config; + int otg_desc_len = 0; + + if (cdev->config) + config = cdev->config; + else + config = list_first_entry( + &cdev->configs, + struct usb_configuration, list); + if (!config) + goto done; + + if (gadget->otg_caps && + (gadget->otg_caps->otg_rev >= 0x0200)) + otg_desc_len += sizeof( + struct usb_otg20_descriptor); + else + otg_desc_len += sizeof( + struct usb_otg_descriptor); + + value = min_t(int, w_length, otg_desc_len); + memcpy(req->buf, config->descriptors[0], value); + } + break; } break; -- cgit v1.3-6-gb490 From 929412d94f2b75fe2a662afa2977bfb6a233c1c3 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:44 +0800 Subject: usb: common: add API to update usb otg capabilities by device tree Check property of usb hardware to update otg version and disable SRP, HNP and ADP if its disable flag is present. Reviewed-by: Roger Quadros Signed-off-by: Li Jun Signed-off-by: Felipe Balbi --- drivers/usb/common/common.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/usb/of.h | 7 ++++++ 2 files changed, 63 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index b530fd403ffb..9e39286a4e5a 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -154,6 +154,62 @@ bool of_usb_host_tpl_support(struct device_node *np) return false; } EXPORT_SYMBOL_GPL(of_usb_host_tpl_support); + +/** + * of_usb_update_otg_caps - to update usb otg capabilities according to + * the passed properties in DT. + * @np: Pointer to the given device_node + * @otg_caps: Pointer to the target usb_otg_caps to be set + * + * The function updates the otg capabilities + */ +int of_usb_update_otg_caps(struct device_node *np, + struct usb_otg_caps *otg_caps) +{ + u32 otg_rev; + + if (!otg_caps) + return -EINVAL; + + if (!of_property_read_u32(np, "otg-rev", &otg_rev)) { + switch (otg_rev) { + case 0x0100: + case 0x0120: + case 0x0130: + case 0x0200: + /* Choose the lesser one if it's already been set */ + if (otg_caps->otg_rev) + otg_caps->otg_rev = min_t(u16, otg_rev, + otg_caps->otg_rev); + else + otg_caps->otg_rev = otg_rev; + break; + default: + pr_err("%s: unsupported otg-rev: 0x%x\n", + np->full_name, otg_rev); + return -EINVAL; + } + } else { + /* + * otg-rev is mandatory for otg properties, if not passed + * we set it to be 0 and assume it's a legacy otg device. + * Non-dt platform can set it afterwards. + */ + otg_caps->otg_rev = 0; + } + + if (of_find_property(np, "hnp-disable", NULL)) + otg_caps->hnp_support = false; + if (of_find_property(np, "srp-disable", NULL)) + otg_caps->srp_support = false; + if (of_find_property(np, "adp-disable", NULL) || + (otg_caps->otg_rev < 0x0200)) + otg_caps->adp_support = false; + + return 0; +} +EXPORT_SYMBOL_GPL(of_usb_update_otg_caps); + #endif MODULE_LICENSE("GPL"); diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index cfe0528cdbb1..8c5a818ec244 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -15,6 +15,8 @@ enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np); enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np); bool of_usb_host_tpl_support(struct device_node *np); +int of_usb_update_otg_caps(struct device_node *np, + struct usb_otg_caps *otg_caps); #else static inline enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np) { @@ -30,6 +32,11 @@ static inline bool of_usb_host_tpl_support(struct device_node *np) { return false; } +static inline int of_usb_update_otg_caps(struct device_node *np, + struct usb_otg_caps *otg_caps) +{ + return 0; +} #endif #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT) -- cgit v1.3-6-gb490 From 79742351c89b76ebcf82b73103aed50f98ac2ee4 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:45 +0800 Subject: usb: chipidea: set usb otg capabilities Init and update otg capabilities by DT, set gadget's otg capabilities accordingly. Acked-by: Peter Chen Reviewed-by: Roger Quadros Signed-off-by: Li Jun Signed-off-by: Felipe Balbi --- drivers/usb/chipidea/core.c | 15 +++++++++++++++ drivers/usb/chipidea/udc.c | 7 ++++++- include/linux/usb/chipidea.h | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 74fea4fa41b1..1e6d5f0c18f2 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -560,6 +560,8 @@ static irqreturn_t ci_irq(int irq, void *data) static int ci_get_platdata(struct device *dev, struct ci_hdrc_platform_data *platdata) { + int ret; + if (!platdata->phy_mode) platdata->phy_mode = of_usb_get_phy_mode(dev->of_node); @@ -588,6 +590,19 @@ static int ci_get_platdata(struct device *dev, of_usb_host_tpl_support(dev->of_node); } + if (platdata->dr_mode == USB_DR_MODE_OTG) { + /* We can support HNP and SRP of OTG 2.0 */ + platdata->ci_otg_caps.otg_rev = 0x0200; + platdata->ci_otg_caps.hnp_support = true; + platdata->ci_otg_caps.srp_support = true; + + /* Update otg capabilities by DT properties */ + ret = of_usb_update_otg_caps(dev->of_node, + &platdata->ci_otg_caps); + if (ret) + return ret; + } + if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL) platdata->flags |= CI_HDRC_FORCE_FULLSPEED; diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 764f668d45a9..b7cca3e597bf 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1827,6 +1827,7 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci) static int udc_start(struct ci_hdrc *ci) { struct device *dev = ci->dev; + struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps; int retval = 0; spin_lock_init(&ci->lock); @@ -1834,8 +1835,12 @@ static int udc_start(struct ci_hdrc *ci) ci->gadget.ops = &usb_gadget_ops; ci->gadget.speed = USB_SPEED_UNKNOWN; ci->gadget.max_speed = USB_SPEED_HIGH; - ci->gadget.is_otg = ci->is_otg ? 1 : 0; ci->gadget.name = ci->platdata->name; + ci->gadget.otg_caps = otg_caps; + + if (otg_caps->hnp_support || otg_caps->srp_support || + otg_caps->adp_support) + ci->gadget.is_otg = 1; INIT_LIST_HEAD(&ci->gadget.ep_list); diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index ab94f78c4dd1..e10cefc721ad 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -34,6 +34,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 void (*notify_event) (struct ci_hdrc *ci, unsigned event); struct regulator *reg_vbus; + struct usb_otg_caps ci_otg_caps; bool tpl_support; }; -- cgit v1.3-6-gb490 From b0930d4cafb487a663ac6780a0369d1a0f461bc2 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:46 +0800 Subject: usb: chipidea: update ci_otg_is_fsm_mode conditions After introduce usb otg properties, update ci_otg_is_fsm_mode conditions to be depending on both usb hardware properties and usb driver config, also resolve a compile issue in debug.c after the API change. Acked-by: Peter Chen Signed-off-by: Li Jun Signed-off-by: Felipe Balbi --- drivers/usb/chipidea/ci.h | 5 ++++- drivers/usb/chipidea/debug.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 6d6200e37b71..f243f0b431c3 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -406,8 +406,11 @@ static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg, static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci) { #ifdef CONFIG_USB_OTG_FSM + struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps; + return ci->is_otg && ci->roles[CI_ROLE_HOST] && - ci->roles[CI_ROLE_GADGET]; + ci->roles[CI_ROLE_GADGET] && (otg_caps->srp_support || + otg_caps->hnp_support || otg_caps->adp_support); #else return false; #endif diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index 5b7061a33103..3869c6d75515 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "ci.h" #include "udc.h" -- cgit v1.3-6-gb490 From d1606dfb98e59221332704c05f5908d9116456ab Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:47 +0800 Subject: usb: gadget: add usb otg descriptor allocate and init interface Allocate usb otg descriptor and initialize it according to gadget's otg capabilities, if usb_otg_caps is not set, keep settings as current gadget drivers. With this 2 new interfaces, gadget can use usb_otg_descriptor for OTG 1.x, and usb_otg20_descriptor for OTG 2.0 or above, and otg features can be decided by the combination of usb hardware property and driver config. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/config.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/usb/gadget.h | 4 ++++ 2 files changed, 60 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 34e12fc52c23..0fafa7a1b6f6 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -20,6 +20,7 @@ #include #include #include +#include /** * usb_descriptor_fillbuf - fill buffer with descriptors @@ -195,3 +196,58 @@ void usb_free_all_descriptors(struct usb_function *f) usb_free_descriptors(f->ss_descriptors); } EXPORT_SYMBOL_GPL(usb_free_all_descriptors); + +struct usb_descriptor_header *usb_otg_descriptor_alloc( + struct usb_gadget *gadget) +{ + struct usb_descriptor_header *otg_desc; + unsigned length = 0; + + if (gadget->otg_caps && (gadget->otg_caps->otg_rev >= 0x0200)) + length = sizeof(struct usb_otg20_descriptor); + else + length = sizeof(struct usb_otg_descriptor); + + otg_desc = kzalloc(length, GFP_KERNEL); + return otg_desc; +} +EXPORT_SYMBOL_GPL(usb_otg_descriptor_alloc); + +int usb_otg_descriptor_init(struct usb_gadget *gadget, + struct usb_descriptor_header *otg_desc) +{ + struct usb_otg_descriptor *otg1x_desc; + struct usb_otg20_descriptor *otg20_desc; + struct usb_otg_caps *otg_caps = gadget->otg_caps; + u8 otg_attributes = 0; + + if (!otg_desc) + return -EINVAL; + + if (otg_caps && otg_caps->otg_rev) { + if (otg_caps->hnp_support) + otg_attributes |= USB_OTG_HNP; + if (otg_caps->srp_support) + otg_attributes |= USB_OTG_SRP; + if (otg_caps->adp_support && (otg_caps->otg_rev >= 0x0200)) + otg_attributes |= USB_OTG_ADP; + } else { + otg_attributes = USB_OTG_SRP | USB_OTG_HNP; + } + + if (otg_caps && (otg_caps->otg_rev >= 0x0200)) { + otg20_desc = (struct usb_otg20_descriptor *)otg_desc; + otg20_desc->bLength = sizeof(struct usb_otg20_descriptor); + otg20_desc->bDescriptorType = USB_DT_OTG; + otg20_desc->bmAttributes = otg_attributes; + otg20_desc->bcdOTG = cpu_to_le16(otg_caps->otg_rev); + } else { + otg1x_desc = (struct usb_otg_descriptor *)otg_desc; + otg1x_desc->bLength = sizeof(struct usb_otg_descriptor); + otg1x_desc->bDescriptorType = USB_DT_OTG; + otg1x_desc->bmAttributes = otg_attributes; + } + + return 0; +} +EXPORT_SYMBOL_GPL(usb_otg_descriptor_init); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index fffceafb6b8c..cea0511a1bc9 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -1092,6 +1092,10 @@ int usb_assign_descriptors(struct usb_function *f, struct usb_descriptor_header **ss); void usb_free_all_descriptors(struct usb_function *f); +struct usb_descriptor_header *usb_otg_descriptor_alloc( + struct usb_gadget *gadget); +int usb_otg_descriptor_init(struct usb_gadget *gadget, + struct usb_descriptor_header *otg_desc); /*-------------------------------------------------------------------------*/ /* utility to simplify map/unmap of usb_requests to/from DMA */ -- cgit v1.3-6-gb490 From 41ce84c86d0a04ef70a9608bd744afb122b6d103 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:48 +0800 Subject: usb: gadget: configfs: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations, free it while composite unbind. If otg capability is not defined, keep its otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/configfs.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 289e20119fea..294eb74fb078 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -41,6 +41,8 @@ int check_user_usb_string(const char *name, #define MAX_NAME_LEN 40 #define MAX_USB_STRING_LANGS 2 +static const struct usb_descriptor_header *otg_desc[2]; + struct gadget_info { struct config_group group; struct config_group functions_group; @@ -55,9 +57,6 @@ struct gadget_info { struct list_head available_func; const char *udc_name; -#ifdef CONFIG_USB_OTG - struct usb_otg_descriptor otg; -#endif struct usb_composite_driver composite; struct usb_composite_dev cdev; bool use_os_desc; @@ -1376,6 +1375,19 @@ static int configfs_composite_bind(struct usb_gadget *gadget, memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN); } + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) { + ret = -ENOMEM; + goto err_comp_cleanup; + } + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* Go through all configs, attach all functions */ list_for_each_entry(c, &gi->cdev.configs, list) { struct config_usb_cfg *cfg; @@ -1383,6 +1395,9 @@ static int configfs_composite_bind(struct usb_gadget *gadget, struct usb_function *tmp; struct gadget_config_name *cn; + if (gadget_is_otg(gadget)) + c->descriptors = otg_desc; + cfg = container_of(c, struct config_usb_cfg, c); if (!list_empty(&cfg->string_list)) { i = 0; @@ -1437,6 +1452,8 @@ static void configfs_composite_unbind(struct usb_gadget *gadget) cdev = get_gadget_data(gadget); gi = container_of(cdev, struct gadget_info, cdev); + kfree(otg_desc[0]); + otg_desc[0] = NULL; purge_configs_funcs(gi); composite_dev_cleanup(cdev); usb_ep_autoconfig_reset(cdev->gadget); @@ -1510,12 +1527,6 @@ static struct config_group *gadgets_make( if (!gi->composite.gadget_driver.function) goto err; -#ifdef CONFIG_USB_OTG - gi->otg.bLength = sizeof(struct usb_otg_descriptor); - gi->otg.bDescriptorType = USB_DT_OTG; - gi->otg.bmAttributes = USB_OTG_SRP | USB_OTG_HNP; -#endif - config_group_init_type_name(&gi->group, name, &gadget_root_type); return &gi->group; -- cgit v1.3-6-gb490 From 9b95236eebdbdf2ff68517cc32390683f4114a37 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:49 +0800 Subject: usb: gadget: ether: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations, free it while ether unbind. If otg capability is not defined, keep its otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/ether.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/ether.c b/drivers/usb/gadget/legacy/ether.c index a3323dca218f..31e9160223e9 100644 --- a/drivers/usb/gadget/legacy/ether.c +++ b/drivers/usb/gadget/legacy/ether.c @@ -171,20 +171,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; static struct usb_string strings_dev[] = { [USB_GADGET_MANUFACTURER_IDX].s = "", @@ -416,17 +403,28 @@ static int eth_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto fail1; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* register our configuration(s); RNDIS first, if it's used */ if (has_rndis()) { status = usb_add_config(cdev, &rndis_config_driver, rndis_do_config); if (status < 0) - goto fail1; + goto fail2; } status = usb_add_config(cdev, ð_config_driver, eth_do_config); if (status < 0) - goto fail1; + goto fail2; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", @@ -434,6 +432,9 @@ static int eth_bind(struct usb_composite_dev *cdev) return 0; +fail2: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail1: if (has_rndis()) usb_put_function_instance(fi_rndis); @@ -463,6 +464,9 @@ static int eth_unbind(struct usb_composite_dev *cdev) usb_put_function(f_geth); usb_put_function_instance(fi_geth); } + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From 578aa8a2b12cb4cc3cfdb6ccd56af9f5f0dd6118 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:50 +0800 Subject: usb: gadget: acm_ms: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/acm_ms.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index 1194b09ae746..4d8adb48b8a7 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -58,21 +58,7 @@ static struct usb_device_descriptor device_desc = { /*.bNumConfigurations = DYNAMIC*/ }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* - * REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; /* string IDs are assigned dynamically */ static struct usb_string strings_dev[] = { @@ -225,10 +211,21 @@ static int acm_ms_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto fail_string_ids; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* register our configuration */ status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config); if (status < 0) - goto fail_string_ids; + goto fail_otg_desc; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", @@ -236,6 +233,9 @@ static int acm_ms_bind(struct usb_composite_dev *cdev) return 0; /* error recovery */ +fail_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail_string_ids: fsg_common_remove_luns(opts->common); fail_set_cdev: @@ -255,6 +255,9 @@ static int acm_ms_unbind(struct usb_composite_dev *cdev) usb_put_function_instance(fi_msg); usb_put_function(f_acm); usb_put_function_instance(f_acm_inst); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From 56023ce0fd7025154494d139b2c9891d75fee622 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:51 +0800 Subject: usb: gadget: audio: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/audio.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index b8095bfe57b6..9b2c1c68746b 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -150,20 +150,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; /*-------------------------------------------------------------------------*/ @@ -259,14 +246,28 @@ static int audio_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) + goto fail; + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + status = usb_add_config(cdev, &audio_config_driver, audio_do_config); if (status < 0) - goto fail; + goto fail_otg_desc; usb_composite_overwrite_options(cdev, &coverwrite); INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION); return 0; +fail_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail: #ifndef CONFIG_GADGET_UAC1 usb_put_function_instance(fi_uac2); @@ -289,6 +290,9 @@ static int audio_unbind(struct usb_composite_dev *cdev) if (!IS_ERR_OR_NULL(fi_uac2)) usb_put_function_instance(fi_uac2); #endif + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From ab6796ae98330389754b82d37bed89029d1dab51 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:52 +0800 Subject: usb: gadget: cdc2: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/cdc2.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/cdc2.c b/drivers/usb/gadget/legacy/cdc2.c index afd3e37921a7..ecd8c8d62f2e 100644 --- a/drivers/usb/gadget/legacy/cdc2.c +++ b/drivers/usb/gadget/legacy/cdc2.c @@ -60,21 +60,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; - +static const struct usb_descriptor_header *otg_desc[2]; /* string IDs are assigned dynamically */ static struct usb_string strings_dev[] = { @@ -193,10 +179,21 @@ static int cdc_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto fail1; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* register our configuration */ status = usb_add_config(cdev, &cdc_config_driver, cdc_do_config); if (status < 0) - goto fail1; + goto fail2; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", @@ -204,6 +201,9 @@ static int cdc_bind(struct usb_composite_dev *cdev) return 0; +fail2: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail1: usb_put_function_instance(fi_serial); fail: @@ -219,6 +219,9 @@ static int cdc_unbind(struct usb_composite_dev *cdev) usb_put_function(f_ecm); if (!IS_ERR_OR_NULL(fi_ecm)) usb_put_function_instance(fi_ecm); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From 75c9310a050b77a6788addf8060b533ab2d9de00 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:53 +0800 Subject: usb: gadget: g_ffs: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/g_ffs.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c index e821931c965c..320a81b2baa6 100644 --- a/drivers/usb/gadget/legacy/g_ffs.c +++ b/drivers/usb/gadget/legacy/g_ffs.c @@ -88,21 +88,7 @@ MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol"); module_param_array_named(functions, func_names, charp, &func_num, 0); MODULE_PARM_DESC(functions, "USB Functions list"); -static const struct usb_descriptor_header *gfs_otg_desc[] = { - (const struct usb_descriptor_header *) - &(const struct usb_otg_descriptor) { - .bLength = sizeof(struct usb_otg_descriptor), - .bDescriptorType = USB_DT_OTG, - - /* - * REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, - }, - - NULL -}; +static const struct usb_descriptor_header *gfs_otg_desc[2]; /* String IDs are assigned dynamically */ static struct usb_string gfs_strings[] = { @@ -412,6 +398,17 @@ static int gfs_bind(struct usb_composite_dev *cdev) goto error_rndis; gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(cdev->gadget) && !gfs_otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) + goto error_rndis; + usb_otg_descriptor_init(cdev->gadget, usb_desc); + gfs_otg_desc[0] = usb_desc; + gfs_otg_desc[1] = NULL; + } + for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) { struct gfs_configuration *c = gfs_configurations + i; int sid = USB_GADGET_FIRST_AVAIL_IDX + i; @@ -432,6 +429,8 @@ static int gfs_bind(struct usb_composite_dev *cdev) /* TODO */ error_unbind: + kfree(gfs_otg_desc[0]); + gfs_otg_desc[0] = NULL; error_rndis: #ifdef CONFIG_USB_FUNCTIONFS_RNDIS usb_put_function_instance(fi_rndis); @@ -473,6 +472,9 @@ static int gfs_unbind(struct usb_composite_dev *cdev) for (i = 0; i < N_CONF * func_num; ++i) usb_put_function(*(f_ffs[0] + i)); + kfree(gfs_otg_desc[0]); + gfs_otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From d9e1867917ccf43ebe6f0e43e19958cbdeb0d8f2 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:54 +0800 Subject: usb: gadget: hid: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/hid.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c index 2baa572686c6..e4874d3183dc 100644 --- a/drivers/usb/gadget/legacy/hid.c +++ b/drivers/usb/gadget/legacy/hid.c @@ -68,21 +68,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; - +static const struct usb_descriptor_header *otg_desc[2]; /* string IDs are assigned dynamically */ static struct usb_string strings_dev[] = { @@ -186,16 +172,30 @@ static int hid_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto put; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* register our configuration */ status = usb_add_config(cdev, &config_driver, do_config); if (status < 0) - goto put; + goto free_otg_desc; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); return 0; +free_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; put: list_for_each_entry(m, &hidg_func_list, node) { if (m == n) @@ -213,6 +213,10 @@ static int hid_unbind(struct usb_composite_dev *cdev) usb_put_function(n->f); usb_put_function_instance(n->fi); } + + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From d867889797615761975e693881a12283ebc92b0f Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:55 +0800 Subject: usb: gadget: mass_storage: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/mass_storage.c | 35 +++++++++++++++++--------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c index e7bfb081f111..ab1a42ce75d2 100644 --- a/drivers/usb/gadget/legacy/mass_storage.c +++ b/drivers/usb/gadget/legacy/mass_storage.c @@ -64,21 +64,7 @@ static struct usb_device_descriptor msg_device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* - * REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; static struct usb_string strings_dev[] = { [USB_GADGET_MANUFACTURER_IDX].s = "", @@ -214,9 +200,20 @@ static int msg_bind(struct usb_composite_dev *cdev) goto fail_string_ids; msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) + goto fail_string_ids; + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + status = usb_add_config(cdev, &msg_config_driver, msg_do_config); if (status < 0) - goto fail_string_ids; + goto fail_otg_desc; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&cdev->gadget->dev, @@ -224,6 +221,9 @@ static int msg_bind(struct usb_composite_dev *cdev) set_bit(0, &msg_registered); return 0; +fail_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail_string_ids: fsg_common_remove_luns(opts->common); fail_set_cdev: @@ -243,6 +243,9 @@ static int msg_unbind(struct usb_composite_dev *cdev) if (!IS_ERR(fi_msg)) usb_put_function_instance(fi_msg); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From 21ddc2a860ca69eb92ab0c48c05187f89aa6a39a Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:56 +0800 Subject: usb: gadget: multi: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/multi.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c index b21b51f0c9fa..c38ead1d67a4 100644 --- a/drivers/usb/gadget/legacy/multi.c +++ b/drivers/usb/gadget/legacy/multi.c @@ -78,21 +78,7 @@ static struct usb_device_descriptor device_desc = { .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM), }; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &(struct usb_otg_descriptor){ - .bLength = sizeof(struct usb_otg_descriptor), - .bDescriptorType = USB_DT_OTG, - - /* - * REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, - }, - NULL, -}; - +static const struct usb_descriptor_header *otg_desc[2]; enum { MULTI_STRING_RNDIS_CONFIG_IDX = USB_GADGET_FIRST_AVAIL_IDX, @@ -429,14 +415,25 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) goto fail_string_ids; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto fail_string_ids; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + /* register configurations */ status = rndis_config_register(cdev); if (unlikely(status < 0)) - goto fail_string_ids; + goto fail_otg_desc; status = cdc_config_register(cdev); if (unlikely(status < 0)) - goto fail_string_ids; + goto fail_otg_desc; usb_composite_overwrite_options(cdev, &coverwrite); /* we're done */ @@ -445,6 +442,9 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) /* error recovery */ +fail_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail_string_ids: fsg_common_remove_luns(fsg_opts->common); fail_set_cdev: @@ -490,6 +490,9 @@ static int multi_unbind(struct usb_composite_dev *cdev) usb_put_function(f_ecm); usb_put_function_instance(fi_ecm); #endif + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From 1156e91dd7cc3a579544286d07fd46f0162e3ec6 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:57 +0800 Subject: usb: gadget: ncm: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/ncm.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/ncm.c b/drivers/usb/gadget/legacy/ncm.c index 6ce7421412e9..2bae4381332d 100644 --- a/drivers/usb/gadget/legacy/ncm.c +++ b/drivers/usb/gadget/legacy/ncm.c @@ -69,20 +69,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; /* string IDs are assigned dynamically */ static struct usb_string strings_dev[] = { @@ -171,16 +158,30 @@ static int gncm_bind(struct usb_composite_dev *cdev) device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id; + if (gadget_is_otg(gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); + if (!usb_desc) + goto fail; + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } + status = usb_add_config(cdev, &ncm_config_driver, ncm_do_config); if (status < 0) - goto fail; + goto fail1; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s\n", DRIVER_DESC); return 0; +fail1: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail: usb_put_function_instance(f_ncm_inst); return status; @@ -192,6 +193,9 @@ static int gncm_unbind(struct usb_composite_dev *cdev) usb_put_function(f_ncm); if (!IS_ERR_OR_NULL(f_ncm_inst)) usb_put_function_instance(f_ncm_inst); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From 93d39afdb8f99a11d1cbd04f4670226494bf03da Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:58 +0800 Subject: usb: gadget: printer: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Reviewed-by: Roger Quadros Signed-off-by: Li Jun Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/printer.c | 49 +++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index 1ce7df1060a5..0c1fc0622d09 100644 --- a/drivers/usb/gadget/legacy/printer.c +++ b/drivers/usb/gadget/legacy/printer.c @@ -82,16 +82,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1 }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - .bmAttributes = USB_OTG_SRP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; /*-------------------------------------------------------------------------*/ @@ -136,7 +127,6 @@ static int printer_do_config(struct usb_configuration *c) usb_gadget_set_selfpowered(gadget); if (gadget_is_otg(gadget)) { - otg_descriptor.bmAttributes |= USB_OTG_HNP; printer_cfg_driver.descriptors = otg_desc; printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } @@ -174,21 +164,39 @@ static int printer_bind(struct usb_composite_dev *cdev) opts->q_len = QLEN; ret = usb_string_ids_tab(cdev, strings); - if (ret < 0) { - usb_put_function_instance(fi_printer); - return ret; - } + if (ret < 0) + goto fail_put_func_inst; + device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id; device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id; device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id; - ret = usb_add_config(cdev, &printer_cfg_driver, printer_do_config); - if (ret) { - usb_put_function_instance(fi_printer); - return ret; + if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) { + ret = -ENOMEM; + goto fail_put_func_inst; + } + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; } + + ret = usb_add_config(cdev, &printer_cfg_driver, printer_do_config); + if (ret) + goto fail_free_otg_desc; + usb_composite_overwrite_options(cdev, &coverwrite); return ret; + +fail_free_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; +fail_put_func_inst: + usb_put_function_instance(fi_printer); + return ret; } static int printer_unbind(struct usb_composite_dev *cdev) @@ -196,6 +204,9 @@ static int printer_unbind(struct usb_composite_dev *cdev) usb_put_function(f_printer); usb_put_function_instance(fi_printer); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From 3dcc7053087fb58c799cd964a00a5396bec3bc9e Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:18:59 +0800 Subject: usb: gadget: serial: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Reviewed-by: Roger Quadros Signed-off-by: Li Jun Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/serial.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/serial.c b/drivers/usb/gadget/legacy/serial.c index 8b7528f9b78e..9836d164469a 100644 --- a/drivers/usb/gadget/legacy/serial.c +++ b/drivers/usb/gadget/legacy/serial.c @@ -79,20 +79,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1, }; -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; +static const struct usb_descriptor_header *otg_desc[2]; /*-------------------------------------------------------------------------*/ @@ -191,6 +178,18 @@ static int gs_bind(struct usb_composite_dev *cdev) serial_config_driver.iConfiguration = status; if (gadget_is_otg(cdev->gadget)) { + if (!otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) { + status = -ENOMEM; + goto fail; + } + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } serial_config_driver.descriptors = otg_desc; serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } @@ -208,13 +207,15 @@ static int gs_bind(struct usb_composite_dev *cdev) "gser"); } if (status < 0) - goto fail; + goto fail1; usb_composite_overwrite_options(cdev, &coverwrite); INFO(cdev, "%s\n", GS_VERSION_NAME); return 0; - +fail1: + kfree(otg_desc[0]); + otg_desc[0] = NULL; fail: return status; } @@ -227,6 +228,10 @@ static int gs_unbind(struct usb_composite_dev *cdev) usb_put_function(f_serial[i]); usb_put_function_instance(fi_serial[i]); } + + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From 9e832bf7c011965b378bd963955e315bd0c23aa4 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Thu, 9 Jul 2015 15:19:00 +0800 Subject: usb: gadget: zero: allocate and init otg descriptor by otg capabilities Allocate and initialize usb otg descriptor according to gadget otg capabilities, add it for each usb configurations. If otg capability is not defined, keep its original otg descriptor unchanged. Reviewed-by: Roger Quadros Signed-off-by: Li Jun Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/zero.c | 41 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c index c986e8addb90..37a410056fed 100644 --- a/drivers/usb/gadget/legacy/zero.c +++ b/drivers/usb/gadget/legacy/zero.c @@ -121,24 +121,7 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 2, }; -#ifdef CONFIG_USB_OTG -static struct usb_otg_descriptor otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - /* REVISIT SRP-only hardware is possible, although - * it would not be called "OTG" ... - */ - .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, -}; - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; -#else -#define otg_desc NULL -#endif +static const struct usb_descriptor_header *otg_desc[2]; /* string IDs are assigned dynamically */ /* default serial number takes at least two packets */ @@ -341,6 +324,18 @@ static int zero_bind(struct usb_composite_dev *cdev) /* support OTG systems */ if (gadget_is_otg(cdev->gadget)) { + if (!otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) { + status = -ENOMEM; + goto err_conf_flb; + } + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; + } sourcesink_driver.descriptors = otg_desc; sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; loopback_driver.descriptors = otg_desc; @@ -359,12 +354,12 @@ static int zero_bind(struct usb_composite_dev *cdev) } status = usb_add_function(&sourcesink_driver, func_ss); if (status) - goto err_conf_flb; + goto err_free_otg_desc; usb_ep_autoconfig_reset(cdev->gadget); status = usb_add_function(&loopback_driver, func_lb); if (status) - goto err_conf_flb; + goto err_free_otg_desc; usb_ep_autoconfig_reset(cdev->gadget); usb_composite_overwrite_options(cdev, &coverwrite); @@ -373,6 +368,9 @@ static int zero_bind(struct usb_composite_dev *cdev) return 0; +err_free_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] = NULL; err_conf_flb: usb_put_function(func_lb); func_lb = NULL; @@ -397,6 +395,9 @@ static int zero_unbind(struct usb_composite_dev *cdev) if (!IS_ERR_OR_NULL(func_lb)) usb_put_function(func_lb); usb_put_function_instance(func_inst_lb); + kfree(otg_desc[0]); + otg_desc[0] = NULL; + return 0; } -- cgit v1.3-6-gb490 From b5a2875605cac14a7d7744ec8254547a26c02612 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 13 Jul 2015 16:30:18 +0100 Subject: usb: renesas_usbhs: Allow an OTG PHY driver to provide VBUS These changes allow a PHY driver to trigger a VBUS interrupt and to provide the value of VBUS. Reviewed-by: Laurent Pinchart Signed-off-by: Phil Edworthy Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 62 ++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index dc2aa3261202..494dfe06bb27 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "common.h" /* @@ -50,6 +51,8 @@ struct usbhsg_gpriv { int uep_size; struct usb_gadget_driver *driver; + struct usb_phy *transceiver; + bool vbus_active; u32 status; #define USBHSG_STATUS_STARTED (1 << 0) @@ -872,6 +875,27 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) return 0; } +/* + * VBUS provided by the PHY + */ +static int usbhsm_phy_get_vbus(struct platform_device *pdev) +{ + struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + + return gpriv->vbus_active; +} + +static void usbhs_mod_phy_mode(struct usbhs_priv *priv) +{ + struct usbhs_mod_info *info = &priv->mod_info; + + info->irq_vbus = NULL; + priv->pfunc.get_vbus = usbhsm_phy_get_vbus; + + usbhs_irq_callback_update(priv, NULL); +} + /* * * linux usb function @@ -882,12 +906,28 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget, { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + struct device *dev = usbhs_priv_to_dev(priv); + int ret; if (!driver || !driver->setup || driver->max_speed < USB_SPEED_FULL) return -EINVAL; + /* connect to bus through transceiver */ + if (!IS_ERR_OR_NULL(gpriv->transceiver)) { + ret = otg_set_peripheral(gpriv->transceiver->otg, + &gpriv->gadget); + if (ret) { + dev_err(dev, "%s: can't bind to transceiver\n", + gpriv->gadget.name); + return ret; + } + + /* get vbus using phy versions */ + usbhs_mod_phy_mode(priv); + } + /* first hook up the driver ... */ gpriv->driver = driver; @@ -900,6 +940,10 @@ static int usbhsg_gadget_stop(struct usb_gadget *gadget) struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD); + + if (!IS_ERR_OR_NULL(gpriv->transceiver)) + otg_set_peripheral(gpriv->transceiver->otg, NULL); + gpriv->driver = NULL; return 0; @@ -947,12 +991,26 @@ static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self) return 0; } +static int usbhsg_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); + struct platform_device *pdev = usbhs_priv_to_pdev(priv); + + gpriv->vbus_active = !!is_active; + + renesas_usbhs_call_notify_hotplug(pdev); + + return 0; +} + static const struct usb_gadget_ops usbhsg_gadget_ops = { .get_frame = usbhsg_get_frame, .set_selfpowered = usbhsg_set_selfpowered, .udc_start = usbhsg_gadget_start, .udc_stop = usbhsg_gadget_stop, .pullup = usbhsg_pullup, + .vbus_session = usbhsg_vbus_session, }; static int usbhsg_start(struct usbhs_priv *priv) @@ -994,6 +1052,10 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) goto usbhs_mod_gadget_probe_err_gpriv; } + gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED); + dev_info(dev, "%stransceiver found\n", + gpriv->transceiver ? "" : "no "); + /* * CAUTION * -- cgit v1.3-6-gb490 From acace73df2c1913a526c1b41e4741a4a6704c863 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Tue, 28 Jul 2015 14:03:12 +0000 Subject: spi: bcm2835: set up spi-mode before asserting cs-gpio When using reverse polarity for clock (spi-cpol) on a device the clock line gets altered after chip-select has been asserted resulting in an additional clock beat, which confuses hardware. This did not show when using native-CS, as the same register is used to control cs as well as polarity, so the changes came into effect at the same time. Unfortunately this is not true with gpio-cs. To avoid this situation this patch moves the setup of polarity (spi-cpol and spi-cpha) outside of the chip-select into prepare_message, which is run prior to asserting chip-select. Also fixes resetting 3-wire mode after use of rx-mode, so that a 3-Wire sequence TX, RX, TX works as well (right now it runs TX, RX, RX instead) Reported-by: Noralf Tronnes Signed-off-by: Martin Sperl Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-bcm2835.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 59705ab23577..c9357bb393d3 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -553,13 +553,11 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, spi_used_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536); bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); - /* handle all the modes */ + /* handle all the 3-wire mode */ if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf)) cs |= BCM2835_SPI_CS_REN; - if (spi->mode & SPI_CPOL) - cs |= BCM2835_SPI_CS_CPOL; - if (spi->mode & SPI_CPHA) - cs |= BCM2835_SPI_CS_CPHA; + else + cs &= ~BCM2835_SPI_CS_REN; /* for gpio_cs set dummy CS so that no HW-CS get changed * we can not run this in bcm2835_spi_set_cs, as it does @@ -592,6 +590,25 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs); } +static int bcm2835_spi_prepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct spi_device *spi = msg->spi; + struct bcm2835_spi *bs = spi_master_get_devdata(master); + u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + + cs &= ~(BCM2835_SPI_CS_CPOL | BCM2835_SPI_CS_CPHA); + + if (spi->mode & SPI_CPOL) + cs |= BCM2835_SPI_CS_CPOL; + if (spi->mode & SPI_CPHA) + cs |= BCM2835_SPI_CS_CPHA; + + bcm2835_wr(bs, BCM2835_SPI_CS, cs); + + return 0; +} + static void bcm2835_spi_handle_err(struct spi_master *master, struct spi_message *msg) { @@ -739,6 +756,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) master->set_cs = bcm2835_spi_set_cs; master->transfer_one = bcm2835_spi_transfer_one; master->handle_err = bcm2835_spi_handle_err; + master->prepare_message = bcm2835_spi_prepare_message; master->dev.of_node = pdev->dev.of_node; bs = spi_master_get_devdata(master); -- cgit v1.3-6-gb490 From 0122a5183088e3117bb9c8fbe248914efb502f3f Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Wed, 29 Jul 2015 07:34:10 +0000 Subject: spi: bcm2835: fix overflow in calculation of transfer time This resulted in the use of polling mode when other approaches (dma or interrupts) would have been more appropriate. Happened for transfers longer than 477 bytes. Reported-by: Noralf Tronnes Signed-off-by: Martin Sperl Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index c9357bb393d3..e7874a6171ec 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -480,7 +480,7 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master, struct spi_device *spi, struct spi_transfer *tfr, u32 cs, - unsigned long xfer_time_us) + unsigned long long xfer_time_us) { struct bcm2835_spi *bs = spi_master_get_devdata(master); unsigned long timeout; @@ -531,7 +531,8 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, { struct bcm2835_spi *bs = spi_master_get_devdata(master); unsigned long spi_hz, clk_hz, cdiv; - unsigned long spi_used_hz, xfer_time_us; + unsigned long spi_used_hz; + unsigned long long xfer_time_us; u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); /* set clock */ @@ -573,9 +574,10 @@ static int bcm2835_spi_transfer_one(struct spi_master *master, bs->rx_len = tfr->len; /* calculate the estimated time in us the transfer runs */ - xfer_time_us = tfr->len + xfer_time_us = (unsigned long long)tfr->len * 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */ - * 1000000 / spi_used_hz; + * 1000000; + do_div(xfer_time_us, spi_used_hz); /* for short requests run polling*/ if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US) -- cgit v1.3-6-gb490 From 3294bee87091be5f179474f6c39d1d87769635e2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 29 Jul 2015 13:17:06 +0300 Subject: clk: versatile: off by one in clk_sp810_timerclken_of_get() The ">" should be ">=" or we end up reading beyond the end of the array. Fixes: 6e973d2c4385 ('clk: vexpress: Add separate SP810 driver') Signed-off-by: Dan Carpenter Acked-by: Pawel Moll Signed-off-by: Stephen Boyd --- drivers/clk/versatile/clk-sp810.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c index 64b0129a0216..7fbe4d4bf35e 100644 --- a/drivers/clk/versatile/clk-sp810.c +++ b/drivers/clk/versatile/clk-sp810.c @@ -129,8 +129,8 @@ static struct clk *clk_sp810_timerclken_of_get(struct of_phandle_args *clkspec, { struct clk_sp810 *sp810 = data; - if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] > - ARRAY_SIZE(sp810->timerclken))) + if (WARN_ON(clkspec->args_count != 1 || + clkspec->args[0] >= ARRAY_SIZE(sp810->timerclken))) return NULL; return sp810->timerclken[clkspec->args[0]].clk; -- cgit v1.3-6-gb490 From f2ab3298fb4932358d27fc4c7ea1a1891ad7e042 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 27 Jul 2015 20:20:30 -0700 Subject: soc: qcom: Add Shared Memory Driver This adds the Qualcomm Shared Memory Driver (SMD) providing communication channels to remote processors, ontop of SMEM. Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/Kconfig | 8 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/smd.c | 1319 ++++++++++++++++++++++++++++++++++++++++++ include/linux/soc/qcom/smd.h | 46 ++ 4 files changed, 1374 insertions(+) create mode 100644 drivers/soc/qcom/smd.c create mode 100644 include/linux/soc/qcom/smd.h (limited to 'drivers') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 0d4faaf32662..188295e2c9ba 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -19,6 +19,14 @@ config QCOM_PM modes. It interface with various system drivers to put the cores in low power modes. +config QCOM_SMD + tristate "Qualcomm Shared Memory Driver (SMD)" + depends on QCOM_SMEM + help + Say y here to enable support for the Qualcomm Shared Memory Driver + providing communication channels to remote processors in Qualcomm + platforms. + config QCOM_SMEM tristate "Qualcomm Shared Memory Manager (SMEM)" depends on ARCH_QCOM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 3a033c43c0ef..f961a8796ed2 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_PM) += spm.o +obj-$(CONFIG_QCOM_SMD) += smd.o obj-$(CONFIG_QCOM_SMEM) += smem.o diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c new file mode 100644 index 000000000000..327adcf117c1 --- /dev/null +++ b/drivers/soc/qcom/smd.c @@ -0,0 +1,1319 @@ +/* + * Copyright (c) 2015, Sony Mobile Communications AB. + * Copyright (c) 2012-2013, 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 + * only 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 +#include +#include +#include +#include +#include +#include +#include + +/* + * The Qualcomm Shared Memory communication solution provides point-to-point + * channels for clients to send and receive streaming or packet based data. + * + * Each channel consists of a control item (channel info) and a ring buffer + * pair. The channel info carry information related to channel state, flow + * control and the offsets within the ring buffer. + * + * All allocated channels are listed in an allocation table, identifying the + * pair of items by name, type and remote processor. + * + * Upon creating a new channel the remote processor allocates channel info and + * ring buffer items from the smem heap and populate the allocation table. An + * interrupt is sent to the other end of the channel and a scan for new + * channels should be done. A channel never goes away, it will only change + * state. + * + * The remote processor signals it intent for bring up the communication + * channel by setting the state of its end of the channel to "opening" and + * sends out an interrupt. We detect this change and register a smd device to + * consume the channel. Upon finding a consumer we finish the handshake and the + * channel is up. + * + * Upon closing a channel, the remote processor will update the state of its + * end of the channel and signal us, we will then unregister any attached + * device and close our end of the channel. + * + * Devices attached to a channel can use the qcom_smd_send function to push + * data to the channel, this is done by copying the data into the tx ring + * buffer, updating the pointers in the channel info and signaling the remote + * processor. + * + * The remote processor does the equivalent when it transfer data and upon + * receiving the interrupt we check the channel info for new data and delivers + * this to the attached device. If the device is not ready to receive the data + * we leave it in the ring buffer for now. + */ + +struct smd_channel_info; +struct smd_channel_info_word; + +#define SMD_ALLOC_TBL_COUNT 2 +#define SMD_ALLOC_TBL_SIZE 64 + +/* + * This lists the various smem heap items relevant for the allocation table and + * smd channel entries. + */ +static const struct { + unsigned alloc_tbl_id; + unsigned info_base_id; + unsigned fifo_base_id; +} smem_items[SMD_ALLOC_TBL_COUNT] = { + { + .alloc_tbl_id = 13, + .info_base_id = 14, + .fifo_base_id = 338 + }, + { + .alloc_tbl_id = 14, + .info_base_id = 266, + .fifo_base_id = 202, + }, +}; + +/** + * struct qcom_smd_edge - representing a remote processor + * @smd: handle to qcom_smd + * @of_node: of_node handle for information related to this edge + * @edge_id: identifier of this edge + * @irq: interrupt for signals on this edge + * @ipc_regmap: regmap handle holding the outgoing ipc register + * @ipc_offset: offset within @ipc_regmap of the register for ipc + * @ipc_bit: bit in the register at @ipc_offset of @ipc_regmap + * @channels: list of all channels detected on this edge + * @channels_lock: guard for modifications of @channels + * @allocated: array of bitmaps representing already allocated channels + * @need_rescan: flag that the @work needs to scan smem for new channels + * @smem_available: last available amount of smem triggering a channel scan + * @work: work item for edge house keeping + */ +struct qcom_smd_edge { + struct qcom_smd *smd; + struct device_node *of_node; + unsigned edge_id; + + int irq; + + struct regmap *ipc_regmap; + int ipc_offset; + int ipc_bit; + + struct list_head channels; + spinlock_t channels_lock; + + DECLARE_BITMAP(allocated[SMD_ALLOC_TBL_COUNT], SMD_ALLOC_TBL_SIZE); + + bool need_rescan; + unsigned smem_available; + + struct work_struct work; +}; + +/* + * SMD channel states. + */ +enum smd_channel_state { + SMD_CHANNEL_CLOSED, + SMD_CHANNEL_OPENING, + SMD_CHANNEL_OPENED, + SMD_CHANNEL_FLUSHING, + SMD_CHANNEL_CLOSING, + SMD_CHANNEL_RESET, + SMD_CHANNEL_RESET_OPENING +}; + +/** + * struct qcom_smd_channel - smd channel struct + * @edge: qcom_smd_edge this channel is living on + * @qsdev: reference to a associated smd client device + * @name: name of the channel + * @state: local state of the channel + * @remote_state: remote state of the channel + * @tx_info: byte aligned outgoing channel info + * @rx_info: byte aligned incoming channel info + * @tx_info_word: word aligned outgoing channel info + * @rx_info_word: word aligned incoming channel info + * @tx_lock: lock to make writes to the channel mutually exclusive + * @fblockread_event: wakeup event tied to tx fBLOCKREADINTR + * @tx_fifo: pointer to the outgoing ring buffer + * @rx_fifo: pointer to the incoming ring buffer + * @fifo_size: size of each ring buffer + * @bounce_buffer: bounce buffer for reading wrapped packets + * @cb: callback function registered for this channel + * @recv_lock: guard for rx info modifications and cb pointer + * @pkt_size: size of the currently handled packet + * @list: lite entry for @channels in qcom_smd_edge + */ +struct qcom_smd_channel { + struct qcom_smd_edge *edge; + + struct qcom_smd_device *qsdev; + + char *name; + enum smd_channel_state state; + enum smd_channel_state remote_state; + + struct smd_channel_info *tx_info; + struct smd_channel_info *rx_info; + + struct smd_channel_info_word *tx_info_word; + struct smd_channel_info_word *rx_info_word; + + struct mutex tx_lock; + wait_queue_head_t fblockread_event; + + void *tx_fifo; + void *rx_fifo; + int fifo_size; + + void *bounce_buffer; + int (*cb)(struct qcom_smd_device *, const void *, size_t); + + spinlock_t recv_lock; + + int pkt_size; + + struct list_head list; +}; + +/** + * struct qcom_smd - smd struct + * @dev: device struct + * @num_edges: number of entries in @edges + * @edges: array of edges to be handled + */ +struct qcom_smd { + struct device *dev; + + unsigned num_edges; + struct qcom_smd_edge edges[0]; +}; + +/* + * Format of the smd_info smem items, for byte aligned channels. + */ +struct smd_channel_info { + u32 state; + u8 fDSR; + u8 fCTS; + u8 fCD; + u8 fRI; + u8 fHEAD; + u8 fTAIL; + u8 fSTATE; + u8 fBLOCKREADINTR; + u32 tail; + u32 head; +}; + +/* + * Format of the smd_info smem items, for word aligned channels. + */ +struct smd_channel_info_word { + u32 state; + u32 fDSR; + u32 fCTS; + u32 fCD; + u32 fRI; + u32 fHEAD; + u32 fTAIL; + u32 fSTATE; + u32 fBLOCKREADINTR; + u32 tail; + u32 head; +}; + +#define GET_RX_CHANNEL_INFO(channel, param) \ + (channel->rx_info_word ? \ + channel->rx_info_word->param : \ + channel->rx_info->param) + +#define SET_RX_CHANNEL_INFO(channel, param, value) \ + (channel->rx_info_word ? \ + (channel->rx_info_word->param = value) : \ + (channel->rx_info->param = value)) + +#define GET_TX_CHANNEL_INFO(channel, param) \ + (channel->tx_info_word ? \ + channel->tx_info_word->param : \ + channel->tx_info->param) + +#define SET_TX_CHANNEL_INFO(channel, param, value) \ + (channel->tx_info_word ? \ + (channel->tx_info_word->param = value) : \ + (channel->tx_info->param = value)) + +/** + * struct qcom_smd_alloc_entry - channel allocation entry + * @name: channel name + * @cid: channel index + * @flags: channel flags and edge id + * @ref_count: reference count of the channel + */ +struct qcom_smd_alloc_entry { + u8 name[20]; + u32 cid; + u32 flags; + u32 ref_count; +} __packed; + +#define SMD_CHANNEL_FLAGS_EDGE_MASK 0xff +#define SMD_CHANNEL_FLAGS_STREAM BIT(8) +#define SMD_CHANNEL_FLAGS_PACKET BIT(9) + +/* + * Each smd packet contains a 20 byte header, with the first 4 being the length + * of the packet. + */ +#define SMD_PACKET_HEADER_LEN 20 + +/* + * Signal the remote processor associated with 'channel'. + */ +static void qcom_smd_signal_channel(struct qcom_smd_channel *channel) +{ + struct qcom_smd_edge *edge = channel->edge; + + regmap_write(edge->ipc_regmap, edge->ipc_offset, BIT(edge->ipc_bit)); +} + +/* + * Initialize the tx channel info + */ +static void qcom_smd_channel_reset(struct qcom_smd_channel *channel) +{ + SET_TX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED); + SET_TX_CHANNEL_INFO(channel, fDSR, 0); + SET_TX_CHANNEL_INFO(channel, fCTS, 0); + SET_TX_CHANNEL_INFO(channel, fCD, 0); + SET_TX_CHANNEL_INFO(channel, fRI, 0); + SET_TX_CHANNEL_INFO(channel, fHEAD, 0); + SET_TX_CHANNEL_INFO(channel, fTAIL, 0); + SET_TX_CHANNEL_INFO(channel, fSTATE, 1); + SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 0); + SET_TX_CHANNEL_INFO(channel, head, 0); + SET_TX_CHANNEL_INFO(channel, tail, 0); + + qcom_smd_signal_channel(channel); + + channel->state = SMD_CHANNEL_CLOSED; + channel->pkt_size = 0; +} + +/* + * Calculate the amount of data available in the rx fifo + */ +static size_t qcom_smd_channel_get_rx_avail(struct qcom_smd_channel *channel) +{ + unsigned head; + unsigned tail; + + head = GET_RX_CHANNEL_INFO(channel, head); + tail = GET_RX_CHANNEL_INFO(channel, tail); + + return (head - tail) & (channel->fifo_size - 1); +} + +/* + * Set tx channel state and inform the remote processor + */ +static void qcom_smd_channel_set_state(struct qcom_smd_channel *channel, + int state) +{ + struct qcom_smd_edge *edge = channel->edge; + bool is_open = state == SMD_CHANNEL_OPENED; + + if (channel->state == state) + return; + + dev_dbg(edge->smd->dev, "set_state(%s, %d)\n", channel->name, state); + + SET_TX_CHANNEL_INFO(channel, fDSR, is_open); + SET_TX_CHANNEL_INFO(channel, fCTS, is_open); + SET_TX_CHANNEL_INFO(channel, fCD, is_open); + + SET_TX_CHANNEL_INFO(channel, state, state); + SET_TX_CHANNEL_INFO(channel, fSTATE, 1); + + channel->state = state; + qcom_smd_signal_channel(channel); +} + +/* + * Copy count bytes of data using 32bit accesses, if that's required. + */ +static void smd_copy_to_fifo(void __iomem *_dst, + const void *_src, + size_t count, + bool word_aligned) +{ + u32 *dst = (u32 *)_dst; + u32 *src = (u32 *)_src; + + if (word_aligned) { + count /= sizeof(u32); + while (count--) + writel_relaxed(*src++, dst++); + } else { + memcpy_toio(_dst, _src, count); + } +} + +/* + * Copy count bytes of data using 32bit accesses, if that is required. + */ +static void smd_copy_from_fifo(void *_dst, + const void __iomem *_src, + size_t count, + bool word_aligned) +{ + u32 *dst = (u32 *)_dst; + u32 *src = (u32 *)_src; + + if (word_aligned) { + count /= sizeof(u32); + while (count--) + *dst++ = readl_relaxed(src++); + } else { + memcpy_fromio(_dst, _src, count); + } +} + +/* + * Read count bytes of data from the rx fifo into buf, but don't advance the + * tail. + */ +static size_t qcom_smd_channel_peek(struct qcom_smd_channel *channel, + void *buf, size_t count) +{ + bool word_aligned; + unsigned tail; + size_t len; + + word_aligned = channel->rx_info_word != NULL; + tail = GET_RX_CHANNEL_INFO(channel, tail); + + len = min_t(size_t, count, channel->fifo_size - tail); + if (len) { + smd_copy_from_fifo(buf, + channel->rx_fifo + tail, + len, + word_aligned); + } + + if (len != count) { + smd_copy_from_fifo(buf + len, + channel->rx_fifo, + count - len, + word_aligned); + } + + return count; +} + +/* + * Advance the rx tail by count bytes. + */ +static void qcom_smd_channel_advance(struct qcom_smd_channel *channel, + size_t count) +{ + unsigned tail; + + tail = GET_RX_CHANNEL_INFO(channel, tail); + tail += count; + tail &= (channel->fifo_size - 1); + SET_RX_CHANNEL_INFO(channel, tail, tail); +} + +/* + * Read out a single packet from the rx fifo and deliver it to the device + */ +static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel) +{ + struct qcom_smd_device *qsdev = channel->qsdev; + unsigned tail; + size_t len; + void *ptr; + int ret; + + if (!channel->cb) + return 0; + + tail = GET_RX_CHANNEL_INFO(channel, tail); + + /* Use bounce buffer if the data wraps */ + if (tail + channel->pkt_size >= channel->fifo_size) { + ptr = channel->bounce_buffer; + len = qcom_smd_channel_peek(channel, ptr, channel->pkt_size); + } else { + ptr = channel->rx_fifo + tail; + len = channel->pkt_size; + } + + ret = channel->cb(qsdev, ptr, len); + if (ret < 0) + return ret; + + /* Only forward the tail if the client consumed the data */ + qcom_smd_channel_advance(channel, len); + + channel->pkt_size = 0; + + return 0; +} + +/* + * Per channel interrupt handling + */ +static bool qcom_smd_channel_intr(struct qcom_smd_channel *channel) +{ + bool need_state_scan = false; + int remote_state; + u32 pktlen; + int avail; + int ret; + + /* Handle state changes */ + remote_state = GET_RX_CHANNEL_INFO(channel, state); + if (remote_state != channel->remote_state) { + channel->remote_state = remote_state; + need_state_scan = true; + } + /* Indicate that we have seen any state change */ + SET_RX_CHANNEL_INFO(channel, fSTATE, 0); + + /* Signal waiting qcom_smd_send() about the interrupt */ + if (!GET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR)) + wake_up_interruptible(&channel->fblockread_event); + + /* Don't consume any data until we've opened the channel */ + if (channel->state != SMD_CHANNEL_OPENED) + goto out; + + /* Indicate that we've seen the new data */ + SET_RX_CHANNEL_INFO(channel, fHEAD, 0); + + /* Consume data */ + for (;;) { + avail = qcom_smd_channel_get_rx_avail(channel); + + if (!channel->pkt_size && avail >= SMD_PACKET_HEADER_LEN) { + qcom_smd_channel_peek(channel, &pktlen, sizeof(pktlen)); + qcom_smd_channel_advance(channel, SMD_PACKET_HEADER_LEN); + channel->pkt_size = pktlen; + } else if (channel->pkt_size && avail >= channel->pkt_size) { + ret = qcom_smd_channel_recv_single(channel); + if (ret) + break; + } else { + break; + } + } + + /* Indicate that we have seen and updated tail */ + SET_RX_CHANNEL_INFO(channel, fTAIL, 1); + + /* Signal the remote that we've consumed the data (if requested) */ + if (!GET_RX_CHANNEL_INFO(channel, fBLOCKREADINTR)) { + /* Ensure ordering of channel info updates */ + wmb(); + + qcom_smd_signal_channel(channel); + } + +out: + return need_state_scan; +} + +/* + * The edge interrupts are triggered by the remote processor on state changes, + * channel info updates or when new channels are created. + */ +static irqreturn_t qcom_smd_edge_intr(int irq, void *data) +{ + struct qcom_smd_edge *edge = data; + struct qcom_smd_channel *channel; + unsigned available; + bool kick_worker = false; + + /* + * Handle state changes or data on each of the channels on this edge + */ + spin_lock(&edge->channels_lock); + list_for_each_entry(channel, &edge->channels, list) { + spin_lock(&channel->recv_lock); + kick_worker |= qcom_smd_channel_intr(channel); + spin_unlock(&channel->recv_lock); + } + spin_unlock(&edge->channels_lock); + + /* + * Creating a new channel requires allocating an smem entry, so we only + * have to scan if the amount of available space in smem have changed + * since last scan. + */ + available = qcom_smem_get_free_space(edge->edge_id); + if (available != edge->smem_available) { + edge->smem_available = available; + edge->need_rescan = true; + kick_worker = true; + } + + if (kick_worker) + schedule_work(&edge->work); + + return IRQ_HANDLED; +} + +/* + * Delivers any outstanding packets in the rx fifo, can be used after probe of + * the clients to deliver any packets that wasn't delivered before the client + * was setup. + */ +static void qcom_smd_channel_resume(struct qcom_smd_channel *channel) +{ + unsigned long flags; + + spin_lock_irqsave(&channel->recv_lock, flags); + qcom_smd_channel_intr(channel); + spin_unlock_irqrestore(&channel->recv_lock, flags); +} + +/* + * Calculate how much space is available in the tx fifo. + */ +static size_t qcom_smd_get_tx_avail(struct qcom_smd_channel *channel) +{ + unsigned head; + unsigned tail; + unsigned mask = channel->fifo_size - 1; + + head = GET_TX_CHANNEL_INFO(channel, head); + tail = GET_TX_CHANNEL_INFO(channel, tail); + + return mask - ((head - tail) & mask); +} + +/* + * Write count bytes of data into channel, possibly wrapping in the ring buffer + */ +static int qcom_smd_write_fifo(struct qcom_smd_channel *channel, + const void *data, + size_t count) +{ + bool word_aligned; + unsigned head; + size_t len; + + word_aligned = channel->tx_info_word != NULL; + head = GET_TX_CHANNEL_INFO(channel, head); + + len = min_t(size_t, count, channel->fifo_size - head); + if (len) { + smd_copy_to_fifo(channel->tx_fifo + head, + data, + len, + word_aligned); + } + + if (len != count) { + smd_copy_to_fifo(channel->tx_fifo, + data + len, + count - len, + word_aligned); + } + + head += count; + head &= (channel->fifo_size - 1); + SET_TX_CHANNEL_INFO(channel, head, head); + + return count; +} + +/** + * qcom_smd_send - write data to smd channel + * @channel: channel handle + * @data: buffer of data to write + * @len: number of bytes to write + * + * This is a blocking write of len bytes into the channel's tx ring buffer and + * signal the remote end. It will sleep until there is enough space available + * in the tx buffer, utilizing the fBLOCKREADINTR signaling mechanism to avoid + * polling. + */ +int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len) +{ + u32 hdr[5] = {len,}; + int tlen = sizeof(hdr) + len; + int ret; + + /* Word aligned channels only accept word size aligned data */ + if (channel->rx_info_word != NULL && len % 4) + return -EINVAL; + + ret = mutex_lock_interruptible(&channel->tx_lock); + if (ret) + return ret; + + while (qcom_smd_get_tx_avail(channel) < tlen) { + if (channel->state != SMD_CHANNEL_OPENED) { + ret = -EPIPE; + goto out; + } + + SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 1); + + ret = wait_event_interruptible(channel->fblockread_event, + qcom_smd_get_tx_avail(channel) >= tlen || + channel->state != SMD_CHANNEL_OPENED); + if (ret) + goto out; + + SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 0); + } + + SET_TX_CHANNEL_INFO(channel, fTAIL, 0); + + qcom_smd_write_fifo(channel, hdr, sizeof(hdr)); + qcom_smd_write_fifo(channel, data, len); + + SET_TX_CHANNEL_INFO(channel, fHEAD, 1); + + /* Ensure ordering of channel info updates */ + wmb(); + + qcom_smd_signal_channel(channel); + +out: + mutex_unlock(&channel->tx_lock); + + return ret; +} +EXPORT_SYMBOL(qcom_smd_send); + +static struct qcom_smd_device *to_smd_device(struct device *dev) +{ + return container_of(dev, struct qcom_smd_device, dev); +} + +static struct qcom_smd_driver *to_smd_driver(struct device *dev) +{ + struct qcom_smd_device *qsdev = to_smd_device(dev); + + return container_of(qsdev->dev.driver, struct qcom_smd_driver, driver); +} + +static int qcom_smd_dev_match(struct device *dev, struct device_driver *drv) +{ + return of_driver_match_device(dev, drv); +} + +/* + * Probe the smd client. + * + * The remote side have indicated that it want the channel to be opened, so + * complete the state handshake and probe our client driver. + */ +static int qcom_smd_dev_probe(struct device *dev) +{ + struct qcom_smd_device *qsdev = to_smd_device(dev); + struct qcom_smd_driver *qsdrv = to_smd_driver(dev); + struct qcom_smd_channel *channel = qsdev->channel; + size_t bb_size; + int ret; + + /* + * Packets are maximum 4k, but reduce if the fifo is smaller + */ + bb_size = min(channel->fifo_size, SZ_4K); + channel->bounce_buffer = kmalloc(bb_size, GFP_KERNEL); + if (!channel->bounce_buffer) + return -ENOMEM; + + channel->cb = qsdrv->callback; + + qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENING); + + qcom_smd_channel_set_state(channel, SMD_CHANNEL_OPENED); + + ret = qsdrv->probe(qsdev); + if (ret) + goto err; + + qcom_smd_channel_resume(channel); + + return 0; + +err: + dev_err(&qsdev->dev, "probe failed\n"); + + channel->cb = NULL; + kfree(channel->bounce_buffer); + channel->bounce_buffer = NULL; + + qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED); + return ret; +} + +/* + * Remove the smd client. + * + * The channel is going away, for some reason, so remove the smd client and + * reset the channel state. + */ +static int qcom_smd_dev_remove(struct device *dev) +{ + struct qcom_smd_device *qsdev = to_smd_device(dev); + struct qcom_smd_driver *qsdrv = to_smd_driver(dev); + struct qcom_smd_channel *channel = qsdev->channel; + unsigned long flags; + + qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSING); + + /* + * Make sure we don't race with the code receiving data. + */ + spin_lock_irqsave(&channel->recv_lock, flags); + channel->cb = NULL; + spin_unlock_irqrestore(&channel->recv_lock, flags); + + /* Wake up any sleepers in qcom_smd_send() */ + wake_up_interruptible(&channel->fblockread_event); + + /* + * We expect that the client might block in remove() waiting for any + * outstanding calls to qcom_smd_send() to wake up and finish. + */ + if (qsdrv->remove) + qsdrv->remove(qsdev); + + /* + * The client is now gone, cleanup and reset the channel state. + */ + channel->qsdev = NULL; + kfree(channel->bounce_buffer); + channel->bounce_buffer = NULL; + + qcom_smd_channel_set_state(channel, SMD_CHANNEL_CLOSED); + + qcom_smd_channel_reset(channel); + + return 0; +} + +static struct bus_type qcom_smd_bus = { + .name = "qcom_smd", + .match = qcom_smd_dev_match, + .probe = qcom_smd_dev_probe, + .remove = qcom_smd_dev_remove, +}; + +/* + * Release function for the qcom_smd_device object. + */ +static void qcom_smd_release_device(struct device *dev) +{ + struct qcom_smd_device *qsdev = to_smd_device(dev); + + kfree(qsdev); +} + +/* + * Finds the device_node for the smd child interested in this channel. + */ +static struct device_node *qcom_smd_match_channel(struct device_node *edge_node, + const char *channel) +{ + struct device_node *child; + const char *name; + const char *key; + int ret; + + for_each_available_child_of_node(edge_node, child) { + key = "qcom,smd-channels"; + ret = of_property_read_string(child, key, &name); + if (ret) { + of_node_put(child); + continue; + } + + if (strcmp(name, channel) == 0) + return child; + } + + return NULL; +} + +/* + * Create a smd client device for channel that is being opened. + */ +static int qcom_smd_create_device(struct qcom_smd_channel *channel) +{ + struct qcom_smd_device *qsdev; + struct qcom_smd_edge *edge = channel->edge; + struct device_node *node; + struct qcom_smd *smd = edge->smd; + int ret; + + if (channel->qsdev) + return -EEXIST; + + node = qcom_smd_match_channel(edge->of_node, channel->name); + if (!node) { + dev_dbg(smd->dev, "no match for '%s'\n", channel->name); + return -ENXIO; + } + + dev_dbg(smd->dev, "registering '%s'\n", channel->name); + + qsdev = kzalloc(sizeof(*qsdev), GFP_KERNEL); + if (!qsdev) + return -ENOMEM; + + dev_set_name(&qsdev->dev, "%s.%s", edge->of_node->name, node->name); + qsdev->dev.parent = smd->dev; + qsdev->dev.bus = &qcom_smd_bus; + qsdev->dev.release = qcom_smd_release_device; + qsdev->dev.of_node = node; + + qsdev->channel = channel; + + channel->qsdev = qsdev; + + ret = device_register(&qsdev->dev); + if (ret) { + dev_err(smd->dev, "device_register failed: %d\n", ret); + put_device(&qsdev->dev); + } + + return ret; +} + +/* + * Destroy a smd client device for a channel that's going away. + */ +static void qcom_smd_destroy_device(struct qcom_smd_channel *channel) +{ + struct device *dev; + + BUG_ON(!channel->qsdev); + + dev = &channel->qsdev->dev; + + device_unregister(dev); + of_node_put(dev->of_node); + put_device(dev); +} + +/** + * qcom_smd_driver_register - register a smd driver + * @qsdrv: qcom_smd_driver struct + */ +int qcom_smd_driver_register(struct qcom_smd_driver *qsdrv) +{ + qsdrv->driver.bus = &qcom_smd_bus; + return driver_register(&qsdrv->driver); +} +EXPORT_SYMBOL(qcom_smd_driver_register); + +/** + * qcom_smd_driver_unregister - unregister a smd driver + * @qsdrv: qcom_smd_driver struct + */ +void qcom_smd_driver_unregister(struct qcom_smd_driver *qsdrv) +{ + driver_unregister(&qsdrv->driver); +} +EXPORT_SYMBOL(qcom_smd_driver_unregister); + +/* + * Allocate the qcom_smd_channel object for a newly found smd channel, + * retrieving and validating the smem items involved. + */ +static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *edge, + unsigned smem_info_item, + unsigned smem_fifo_item, + char *name) +{ + struct qcom_smd_channel *channel; + struct qcom_smd *smd = edge->smd; + size_t fifo_size; + size_t info_size; + void *fifo_base; + void *info; + int ret; + + channel = devm_kzalloc(smd->dev, sizeof(*channel), GFP_KERNEL); + if (!channel) + return ERR_PTR(-ENOMEM); + + channel->edge = edge; + channel->name = devm_kstrdup(smd->dev, name, GFP_KERNEL); + if (!channel->name) + return ERR_PTR(-ENOMEM); + + mutex_init(&channel->tx_lock); + spin_lock_init(&channel->recv_lock); + init_waitqueue_head(&channel->fblockread_event); + + ret = qcom_smem_get(edge->edge_id, smem_info_item, (void **)&info, &info_size); + if (ret) + goto free_name_and_channel; + + /* + * Use the size of the item to figure out which channel info struct to + * use. + */ + if (info_size == 2 * sizeof(struct smd_channel_info_word)) { + channel->tx_info_word = info; + channel->rx_info_word = info + sizeof(struct smd_channel_info_word); + } else if (info_size == 2 * sizeof(struct smd_channel_info)) { + channel->tx_info = info; + channel->rx_info = info + sizeof(struct smd_channel_info); + } else { + dev_err(smd->dev, + "channel info of size %zu not supported\n", info_size); + ret = -EINVAL; + goto free_name_and_channel; + } + + ret = qcom_smem_get(edge->edge_id, smem_fifo_item, &fifo_base, &fifo_size); + if (ret) + goto free_name_and_channel; + + /* The channel consist of a rx and tx fifo of equal size */ + fifo_size /= 2; + + dev_dbg(smd->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n", + name, info_size, fifo_size); + + channel->tx_fifo = fifo_base; + channel->rx_fifo = fifo_base + fifo_size; + channel->fifo_size = fifo_size; + + qcom_smd_channel_reset(channel); + + return channel; + +free_name_and_channel: + devm_kfree(smd->dev, channel->name); + devm_kfree(smd->dev, channel); + + return ERR_PTR(ret); +} + +/* + * Scans the allocation table for any newly allocated channels, calls + * qcom_smd_create_channel() to create representations of these and add + * them to the edge's list of channels. + */ +static void qcom_discover_channels(struct qcom_smd_edge *edge) +{ + struct qcom_smd_alloc_entry *alloc_tbl; + struct qcom_smd_alloc_entry *entry; + struct qcom_smd_channel *channel; + struct qcom_smd *smd = edge->smd; + unsigned long flags; + unsigned fifo_id; + unsigned info_id; + int ret; + int tbl; + int i; + + for (tbl = 0; tbl < SMD_ALLOC_TBL_COUNT; tbl++) { + ret = qcom_smem_get(edge->edge_id, + smem_items[tbl].alloc_tbl_id, + (void **)&alloc_tbl, + NULL); + if (ret < 0) + continue; + + for (i = 0; i < SMD_ALLOC_TBL_SIZE; i++) { + entry = &alloc_tbl[i]; + if (test_bit(i, edge->allocated[tbl])) + continue; + + if (entry->ref_count == 0) + continue; + + if (!entry->name[0]) + continue; + + if (!(entry->flags & SMD_CHANNEL_FLAGS_PACKET)) + continue; + + if ((entry->flags & SMD_CHANNEL_FLAGS_EDGE_MASK) != edge->edge_id) + continue; + + info_id = smem_items[tbl].info_base_id + entry->cid; + fifo_id = smem_items[tbl].fifo_base_id + entry->cid; + + channel = qcom_smd_create_channel(edge, info_id, fifo_id, entry->name); + if (IS_ERR(channel)) + continue; + + spin_lock_irqsave(&edge->channels_lock, flags); + list_add(&channel->list, &edge->channels); + spin_unlock_irqrestore(&edge->channels_lock, flags); + + dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name); + set_bit(i, edge->allocated[tbl]); + } + } + + schedule_work(&edge->work); +} + +/* + * This per edge worker scans smem for any new channels and register these. It + * then scans all registered channels for state changes that should be handled + * by creating or destroying smd client devices for the registered channels. + * + * LOCKING: edge->channels_lock is not needed to be held during the traversal + * of the channels list as it's done synchronously with the only writer. + */ +static void qcom_channel_state_worker(struct work_struct *work) +{ + struct qcom_smd_channel *channel; + struct qcom_smd_edge *edge = container_of(work, + struct qcom_smd_edge, + work); + unsigned remote_state; + + /* + * Rescan smem if we have reason to belive that there are new channels. + */ + if (edge->need_rescan) { + edge->need_rescan = false; + qcom_discover_channels(edge); + } + + /* + * Register a device for any closed channel where the remote processor + * is showing interest in opening the channel. + */ + list_for_each_entry(channel, &edge->channels, list) { + if (channel->state != SMD_CHANNEL_CLOSED) + continue; + + remote_state = GET_RX_CHANNEL_INFO(channel, state); + if (remote_state != SMD_CHANNEL_OPENING && + remote_state != SMD_CHANNEL_OPENED) + continue; + + qcom_smd_create_device(channel); + } + + /* + * Unregister the device for any channel that is opened where the + * remote processor is closing the channel. + */ + list_for_each_entry(channel, &edge->channels, list) { + if (channel->state != SMD_CHANNEL_OPENING && + channel->state != SMD_CHANNEL_OPENED) + continue; + + remote_state = GET_RX_CHANNEL_INFO(channel, state); + if (remote_state == SMD_CHANNEL_OPENING || + remote_state == SMD_CHANNEL_OPENED) + continue; + + qcom_smd_destroy_device(channel); + } +} + +/* + * Parses an of_node describing an edge. + */ +static int qcom_smd_parse_edge(struct device *dev, + struct device_node *node, + struct qcom_smd_edge *edge) +{ + struct device_node *syscon_np; + const char *key; + int irq; + int ret; + + INIT_LIST_HEAD(&edge->channels); + spin_lock_init(&edge->channels_lock); + + INIT_WORK(&edge->work, qcom_channel_state_worker); + + edge->of_node = of_node_get(node); + + irq = irq_of_parse_and_map(node, 0); + if (irq < 0) { + dev_err(dev, "required smd interrupt missing\n"); + return -EINVAL; + } + + ret = devm_request_irq(dev, irq, + qcom_smd_edge_intr, IRQF_TRIGGER_RISING, + node->name, edge); + if (ret) { + dev_err(dev, "failed to request smd irq\n"); + return ret; + } + + edge->irq = irq; + + key = "qcom,smd-edge"; + ret = of_property_read_u32(node, key, &edge->edge_id); + if (ret) { + dev_err(dev, "edge missing %s property\n", key); + return -EINVAL; + } + + syscon_np = of_parse_phandle(node, "qcom,ipc", 0); + if (!syscon_np) { + dev_err(dev, "no qcom,ipc node\n"); + return -ENODEV; + } + + edge->ipc_regmap = syscon_node_to_regmap(syscon_np); + if (IS_ERR(edge->ipc_regmap)) + return PTR_ERR(edge->ipc_regmap); + + key = "qcom,ipc"; + ret = of_property_read_u32_index(node, key, 1, &edge->ipc_offset); + if (ret < 0) { + dev_err(dev, "no offset in %s\n", key); + return -EINVAL; + } + + ret = of_property_read_u32_index(node, key, 2, &edge->ipc_bit); + if (ret < 0) { + dev_err(dev, "no bit in %s\n", key); + return -EINVAL; + } + + return 0; +} + +static int qcom_smd_probe(struct platform_device *pdev) +{ + struct qcom_smd_edge *edge; + struct device_node *node; + struct qcom_smd *smd; + size_t array_size; + int num_edges; + int ret; + int i = 0; + + /* Wait for smem */ + ret = qcom_smem_get(QCOM_SMEM_HOST_ANY, smem_items[0].alloc_tbl_id, NULL, NULL); + if (ret == -EPROBE_DEFER) + return ret; + + num_edges = of_get_available_child_count(pdev->dev.of_node); + array_size = sizeof(*smd) + num_edges * sizeof(struct qcom_smd_edge); + smd = devm_kzalloc(&pdev->dev, array_size, GFP_KERNEL); + if (!smd) + return -ENOMEM; + smd->dev = &pdev->dev; + + smd->num_edges = num_edges; + for_each_available_child_of_node(pdev->dev.of_node, node) { + edge = &smd->edges[i++]; + edge->smd = smd; + + ret = qcom_smd_parse_edge(&pdev->dev, node, edge); + if (ret) + continue; + + edge->need_rescan = true; + schedule_work(&edge->work); + } + + platform_set_drvdata(pdev, smd); + + return 0; +} + +/* + * Shut down all smd clients by making sure that each edge stops processing + * events and scanning for new channels, then call destroy on the devices. + */ +static int qcom_smd_remove(struct platform_device *pdev) +{ + struct qcom_smd_channel *channel; + struct qcom_smd_edge *edge; + struct qcom_smd *smd = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < smd->num_edges; i++) { + edge = &smd->edges[i]; + + disable_irq(edge->irq); + cancel_work_sync(&edge->work); + + list_for_each_entry(channel, &edge->channels, list) { + if (!channel->qsdev) + continue; + + qcom_smd_destroy_device(channel); + } + } + + return 0; +} + +static const struct of_device_id qcom_smd_of_match[] = { + { .compatible = "qcom,smd" }, + {} +}; +MODULE_DEVICE_TABLE(of, qcom_smd_of_match); + +static struct platform_driver qcom_smd_driver = { + .probe = qcom_smd_probe, + .remove = qcom_smd_remove, + .driver = { + .name = "qcom-smd", + .of_match_table = qcom_smd_of_match, + }, +}; + +static int __init qcom_smd_init(void) +{ + int ret; + + ret = bus_register(&qcom_smd_bus); + if (ret) { + pr_err("failed to register smd bus: %d\n", ret); + return ret; + } + + return platform_driver_register(&qcom_smd_driver); +} +postcore_initcall(qcom_smd_init); + +static void __exit qcom_smd_exit(void) +{ + platform_driver_unregister(&qcom_smd_driver); + bus_unregister(&qcom_smd_bus); +} +module_exit(qcom_smd_exit); + +MODULE_AUTHOR("Bjorn Andersson "); +MODULE_DESCRIPTION("Qualcomm Shared Memory Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h new file mode 100644 index 000000000000..d7e50aa6a4ac --- /dev/null +++ b/include/linux/soc/qcom/smd.h @@ -0,0 +1,46 @@ +#ifndef __QCOM_SMD_H__ +#define __QCOM_SMD_H__ + +#include +#include + +struct qcom_smd; +struct qcom_smd_channel; +struct qcom_smd_lookup; + +/** + * struct qcom_smd_device - smd device struct + * @dev: the device struct + * @channel: handle to the smd channel for this device + */ +struct qcom_smd_device { + struct device dev; + struct qcom_smd_channel *channel; +}; + +/** + * struct qcom_smd_driver - smd driver struct + * @driver: underlying device driver + * @probe: invoked when the smd channel is found + * @remove: invoked when the smd channel is closed + * @callback: invoked when an inbound message is received on the channel, + * should return 0 on success or -EBUSY if the data cannot be + * consumed at this time + */ +struct qcom_smd_driver { + struct device_driver driver; + int (*probe)(struct qcom_smd_device *dev); + void (*remove)(struct qcom_smd_device *dev); + int (*callback)(struct qcom_smd_device *, const void *, size_t); +}; + +int qcom_smd_driver_register(struct qcom_smd_driver *drv); +void qcom_smd_driver_unregister(struct qcom_smd_driver *drv); + +#define module_qcom_smd_driver(__smd_driver) \ + module_driver(__smd_driver, qcom_smd_driver_register, \ + qcom_smd_driver_unregister) + +int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len); + +#endif -- cgit v1.3-6-gb490 From 936f14cf4e67168fcd37f10cebf5a475f490fb6e Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 27 Jul 2015 20:20:32 -0700 Subject: soc: qcom: Driver for the Qualcomm RPM over SMD Driver for the Resource Power Manager (RPM) found in Qualcomm 8974 based devices. The driver exposes resources that child drivers can operate on; to implementing regulator, clock and bus frequency drivers. Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/Kconfig | 14 +++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/smd-rpm.c | 244 +++++++++++++++++++++++++++++++++++++++ include/linux/soc/qcom/smd-rpm.h | 35 ++++++ 4 files changed, 294 insertions(+) create mode 100644 drivers/soc/qcom/smd-rpm.c create mode 100644 include/linux/soc/qcom/smd-rpm.h (limited to 'drivers') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 188295e2c9ba..ba47b70f4d85 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -27,6 +27,20 @@ config QCOM_SMD providing communication channels to remote processors in Qualcomm platforms. +config QCOM_SMD_RPM + tristate "Qualcomm Resource Power Manager (RPM) over SMD" + depends on QCOM_SMD && OF + help + If you say yes to this option, support will be included for the + Resource Power Manager system found in the Qualcomm 8974 based + devices. + + This is required to access many regulators, clocks and bus + frequencies controlled by the RPM on these devices. + + Say M here if you want to include support for the Qualcomm RPM as a + module. This will build a module called "qcom-smd-rpm". + config QCOM_SMEM tristate "Qualcomm Shared Memory Manager (SMEM)" depends on ARCH_QCOM diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index f961a8796ed2..10a93d168e0e 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_PM) += spm.o obj-$(CONFIG_QCOM_SMD) += smd.o +obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o obj-$(CONFIG_QCOM_SMEM) += smem.o diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c new file mode 100644 index 000000000000..1392ccf14a20 --- /dev/null +++ b/drivers/soc/qcom/smd-rpm.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2015, Sony Mobile Communications AB. + * Copyright (c) 2012-2013, 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 + * only 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 +#include + +#define RPM_REQUEST_TIMEOUT (5 * HZ) + +/** + * struct qcom_smd_rpm - state of the rpm device driver + * @rpm_channel: reference to the smd channel + * @ack: completion for acks + * @lock: mutual exclusion around the send/complete pair + * @ack_status: result of the rpm request + */ +struct qcom_smd_rpm { + struct qcom_smd_channel *rpm_channel; + + struct completion ack; + struct mutex lock; + int ack_status; +}; + +/** + * struct qcom_rpm_header - header for all rpm requests and responses + * @service_type: identifier of the service + * @length: length of the payload + */ +struct qcom_rpm_header { + u32 service_type; + u32 length; +}; + +/** + * struct qcom_rpm_request - request message to the rpm + * @msg_id: identifier of the outgoing message + * @flags: active/sleep state flags + * @type: resource type + * @id: resource id + * @data_len: length of the payload following this header + */ +struct qcom_rpm_request { + u32 msg_id; + u32 flags; + u32 type; + u32 id; + u32 data_len; +}; + +/** + * struct qcom_rpm_message - response message from the rpm + * @msg_type: indicator of the type of message + * @length: the size of this message, including the message header + * @msg_id: message id + * @message: textual message from the rpm + * + * Multiple of these messages can be stacked in an rpm message. + */ +struct qcom_rpm_message { + u32 msg_type; + u32 length; + union { + u32 msg_id; + u8 message[0]; + }; +}; + +#define RPM_SERVICE_TYPE_REQUEST 0x00716572 /* "req\0" */ + +#define RPM_MSG_TYPE_ERR 0x00727265 /* "err\0" */ +#define RPM_MSG_TYPE_MSG_ID 0x2367736d /* "msg#" */ + +/** + * qcom_rpm_smd_write - write @buf to @type:@id + * @rpm: rpm handle + * @type: resource type + * @id: resource identifier + * @buf: the data to be written + * @count: number of bytes in @buf + */ +int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm, + int state, + u32 type, u32 id, + void *buf, + size_t count) +{ + static unsigned msg_id = 1; + int left; + int ret; + + struct { + struct qcom_rpm_header hdr; + struct qcom_rpm_request req; + u8 payload[count]; + } pkt; + + /* SMD packets to the RPM may not exceed 256 bytes */ + if (WARN_ON(sizeof(pkt) >= 256)) + return -EINVAL; + + mutex_lock(&rpm->lock); + + pkt.hdr.service_type = RPM_SERVICE_TYPE_REQUEST; + pkt.hdr.length = sizeof(struct qcom_rpm_request) + count; + + pkt.req.msg_id = msg_id++; + pkt.req.flags = BIT(state); + pkt.req.type = type; + pkt.req.id = id; + pkt.req.data_len = count; + memcpy(pkt.payload, buf, count); + + ret = qcom_smd_send(rpm->rpm_channel, &pkt, sizeof(pkt)); + if (ret) + goto out; + + left = wait_for_completion_timeout(&rpm->ack, RPM_REQUEST_TIMEOUT); + if (!left) + ret = -ETIMEDOUT; + else + ret = rpm->ack_status; + +out: + mutex_unlock(&rpm->lock); + return ret; +} +EXPORT_SYMBOL(qcom_rpm_smd_write); + +static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev, + const void *data, + size_t count) +{ + const struct qcom_rpm_header *hdr = data; + const struct qcom_rpm_message *msg; + struct qcom_smd_rpm *rpm = dev_get_drvdata(&qsdev->dev); + const u8 *buf = data + sizeof(struct qcom_rpm_header); + const u8 *end = buf + hdr->length; + char msgbuf[32]; + int status = 0; + u32 len; + + if (hdr->service_type != RPM_SERVICE_TYPE_REQUEST || + hdr->length < sizeof(struct qcom_rpm_message)) { + dev_err(&qsdev->dev, "invalid request\n"); + return 0; + } + + while (buf < end) { + msg = (struct qcom_rpm_message *)buf; + switch (msg->msg_type) { + case RPM_MSG_TYPE_MSG_ID: + break; + case RPM_MSG_TYPE_ERR: + len = min_t(u32, ALIGN(msg->length, 4), sizeof(msgbuf)); + memcpy_fromio(msgbuf, msg->message, len); + msgbuf[len - 1] = 0; + + if (!strcmp(msgbuf, "resource does not exist")) + status = -ENXIO; + else + status = -EINVAL; + break; + } + + buf = PTR_ALIGN(buf + 2 * sizeof(u32) + msg->length, 4); + } + + rpm->ack_status = status; + complete(&rpm->ack); + return 0; +} + +static int qcom_smd_rpm_probe(struct qcom_smd_device *sdev) +{ + struct qcom_smd_rpm *rpm; + + rpm = devm_kzalloc(&sdev->dev, sizeof(*rpm), GFP_KERNEL); + if (!rpm) + return -ENOMEM; + + mutex_init(&rpm->lock); + init_completion(&rpm->ack); + + rpm->rpm_channel = sdev->channel; + + dev_set_drvdata(&sdev->dev, rpm); + + return of_platform_populate(sdev->dev.of_node, NULL, NULL, &sdev->dev); +} + +static void qcom_smd_rpm_remove(struct qcom_smd_device *sdev) +{ + of_platform_depopulate(&sdev->dev); +} + +static const struct of_device_id qcom_smd_rpm_of_match[] = { + { .compatible = "qcom,rpm-msm8974" }, + {} +}; +MODULE_DEVICE_TABLE(of, qcom_smd_rpm_of_match); + +static struct qcom_smd_driver qcom_smd_rpm_driver = { + .probe = qcom_smd_rpm_probe, + .remove = qcom_smd_rpm_remove, + .callback = qcom_smd_rpm_callback, + .driver = { + .name = "qcom_smd_rpm", + .owner = THIS_MODULE, + .of_match_table = qcom_smd_rpm_of_match, + }, +}; + +static int __init qcom_smd_rpm_init(void) +{ + return qcom_smd_driver_register(&qcom_smd_rpm_driver); +} +arch_initcall(qcom_smd_rpm_init); + +static void __exit qcom_smd_rpm_exit(void) +{ + qcom_smd_driver_unregister(&qcom_smd_rpm_driver); +} +module_exit(qcom_smd_rpm_exit); + +MODULE_AUTHOR("Bjorn Andersson "); +MODULE_DESCRIPTION("Qualcomm SMD backed RPM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/soc/qcom/smd-rpm.h b/include/linux/soc/qcom/smd-rpm.h new file mode 100644 index 000000000000..2a53dcaeeeed --- /dev/null +++ b/include/linux/soc/qcom/smd-rpm.h @@ -0,0 +1,35 @@ +#ifndef __QCOM_SMD_RPM_H__ +#define __QCOM_SMD_RPM_H__ + +struct qcom_smd_rpm; + +#define QCOM_SMD_RPM_ACTIVE_STATE 0 +#define QCOM_SMD_RPM_SLEEP_STATE 1 + +/* + * Constants used for addressing resources in the RPM. + */ +#define QCOM_SMD_RPM_BOOST 0x61747362 +#define QCOM_SMD_RPM_BUS_CLK 0x316b6c63 +#define QCOM_SMD_RPM_BUS_MASTER 0x73616d62 +#define QCOM_SMD_RPM_BUS_SLAVE 0x766c7362 +#define QCOM_SMD_RPM_CLK_BUF_A 0x616B6C63 +#define QCOM_SMD_RPM_LDOA 0x616f646c +#define QCOM_SMD_RPM_LDOB 0x626F646C +#define QCOM_SMD_RPM_MEM_CLK 0x326b6c63 +#define QCOM_SMD_RPM_MISC_CLK 0x306b6c63 +#define QCOM_SMD_RPM_NCPA 0x6170636E +#define QCOM_SMD_RPM_NCPB 0x6270636E +#define QCOM_SMD_RPM_OCMEM_PWR 0x706d636f +#define QCOM_SMD_RPM_QPIC_CLK 0x63697071 +#define QCOM_SMD_RPM_SMPA 0x61706d73 +#define QCOM_SMD_RPM_SMPB 0x62706d73 +#define QCOM_SMD_RPM_SPDM 0x63707362 +#define QCOM_SMD_RPM_VSA 0x00617376 + +int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm, + int state, + u32 resource_type, u32 resource_id, + void *buf, size_t count); + +#endif -- cgit v1.3-6-gb490 From 35e455f47ac2e7fbc0c25871a4e91c563ff78ce1 Mon Sep 17 00:00:00 2001 From: Amir Vadai Date: Tue, 28 Jul 2015 13:19:19 +0300 Subject: net/mlx4_en: Hardware accelerated 802.1ad works only on the first port Fix mistakenly used, hard coded, port number in get_phv_bit() Fixes: 77fc29c ("net/mlx4_core: Preparations for 802.1ad VLAN support") Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 5a1c3d249530..e8ec1dec5789 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -2815,7 +2815,7 @@ int get_phv_bit(struct mlx4_dev *dev, u8 port, int *phv) struct mlx4_func_cap func_cap; memset(&func_cap, 0, sizeof(func_cap)); - err = mlx4_QUERY_FUNC_CAP(dev, 1, &func_cap); + err = mlx4_QUERY_FUNC_CAP(dev, port, &func_cap); if (!err) *phv = func_cap.flags & QUERY_FUNC_CAP_PHV_BIT; return err; -- cgit v1.3-6-gb490 From db9d6d790968fd6df9faa7fa1f51967e05afd492 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 27 Jul 2015 15:42:18 -0700 Subject: PCI: iproc: enable arm64 support for iProc PCIe PCI: iproc: Add arm64 support Add arm64 support to the iProc PCIe driver. Note that on arm32, bus->sysdata points to the arm32-specific pci_sys_data struct, and pci_sys_data.private_data contains the iproc_pcie pointer. For arm64, there's nothing corresponding to pci_sys_data, so we keep the iproc_pcie pointer directly in bus->sysdata. In addition, arm64 does IRQ mapping in pcibios_add_device(), so it doesn't need pci_fixup_irqs() as arm32 does. Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas Reviewed-by: Scott Branden Acked-by: Bjorn Helgaas Signed-off-by: Olof Johansson --- drivers/pci/host/pcie-iproc.c | 27 ++++++++++++++++++++------- drivers/pci/host/pcie-iproc.h | 4 +++- 2 files changed, 23 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index d77481ea553e..ba087b57961d 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -58,9 +58,17 @@ #define SYS_RC_INTX_EN 0x330 #define SYS_RC_INTX_MASK 0xf -static inline struct iproc_pcie *sys_to_pcie(struct pci_sys_data *sys) +static inline struct iproc_pcie *iproc_data(struct pci_bus *bus) { - return sys->private_data; + struct iproc_pcie *pcie; +#ifdef CONFIG_ARM + struct pci_sys_data *sys = bus->sysdata; + + pcie = sys->private_data; +#else + pcie = bus->sysdata; +#endif + return pcie; } /** @@ -71,8 +79,7 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct pci_bus *bus, unsigned int devfn, int where) { - struct pci_sys_data *sys = bus->sysdata; - struct iproc_pcie *pcie = sys_to_pcie(sys); + struct iproc_pcie *pcie = iproc_data(bus); unsigned slot = PCI_SLOT(devfn); unsigned fn = PCI_FUNC(devfn); unsigned busno = bus->number; @@ -186,6 +193,7 @@ static void iproc_pcie_enable(struct iproc_pcie *pcie) int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) { int ret; + void *sysdata; struct pci_bus *bus; if (!pcie || !pcie->dev || !pcie->base) @@ -208,10 +216,13 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) iproc_pcie_reset(pcie); +#ifdef CONFIG_ARM pcie->sysdata.private_data = pcie; - - bus = pci_create_root_bus(pcie->dev, 0, &iproc_pcie_ops, - &pcie->sysdata, res); + sysdata = &pcie->sysdata; +#else + sysdata = pcie; +#endif + bus = pci_create_root_bus(pcie->dev, 0, &iproc_pcie_ops, sysdata, res); if (!bus) { dev_err(pcie->dev, "unable to create PCI root bus\n"); ret = -ENOMEM; @@ -229,7 +240,9 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) pci_scan_child_bus(bus); pci_assign_unassigned_bus_resources(bus); +#ifdef CONFIG_ARM pci_fixup_irqs(pci_common_swizzle, pcie->map_irq); +#endif pci_bus_add_devices(bus); return 0; diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index ba0a108309cc..c9e4c10a462e 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h @@ -21,7 +21,7 @@ * @dev: pointer to device data structure * @base: PCIe host controller I/O register base * @resources: linked list of all PCI resources - * @sysdata: Per PCI controller data + * @sysdata: Per PCI controller data (ARM-specific) * @root_bus: pointer to root bus * @phy: optional PHY device that controls the Serdes * @irqs: interrupt IDs @@ -29,7 +29,9 @@ struct iproc_pcie { struct device *dev; void __iomem *base; +#ifdef CONFIG_ARM struct pci_sys_data sysdata; +#endif struct pci_bus *root_bus; struct phy *phy; int irqs[IPROC_PCIE_MAX_NUM_IRQS]; -- cgit v1.3-6-gb490 From b00c4415fb231f276221c634a47ce7328df9aae5 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 27 Jul 2015 15:42:19 -0700 Subject: PCI: iproc: Fix ARM64 dependency in Kconfig Allow Broadcom iProc PCIe core driver to be compiled for ARM64 Signed-off-by: Ray Jui Reviewed-by: Vikram Prakash Reviewed-by: Scott Branden Acked-by: Bjorn Helgaas Signed-off-by: Olof Johansson --- drivers/pci/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index c132bddc03f3..d2c614453819 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -117,7 +117,7 @@ config PCI_VERSATILE config PCIE_IPROC tristate "Broadcom iProc PCIe controller" - depends on OF && ARM + depends on OF && (ARM || ARM64) default n help This enables the iProc PCIe core controller support for Broadcom's -- cgit v1.3-6-gb490 From 70d334ca71b0e35ef21493d86799cec83f452d94 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Wed, 29 Jul 2015 10:12:53 -0700 Subject: PCI: iproc: Fix BCMA dependency in Kconfig The current iProc BCMA front-end driver can only work on ARM32 based platforms; therefore its config option in Kconfig should be changed to reflect that. This fixes arm64 allmodconfig build failure when compiling the the iProc BCMA driver that contains struct pci_sys_data that is arm32 specific Signed-off-by: Ray Jui Signed-off-by: Olof Johansson --- drivers/pci/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index d2c614453819..48b5b3058d9d 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -136,7 +136,7 @@ config PCIE_IPROC_PLATFORM config PCIE_IPROC_BCMA bool "Broadcom iProc PCIe BCMA bus driver" - depends on ARCH_BCM_IPROC || (ARM && COMPILE_TEST) + depends on ARM && (ARCH_BCM_IPROC || COMPILE_TEST) select PCIE_IPROC select BCMA select PCI_DOMAINS -- cgit v1.3-6-gb490 From 1f26d1c1053ac179b0ee1edea7809cef07fe728e Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Thu, 16 Jul 2015 16:55:32 -0700 Subject: ARM: qcom: Add coincell charger driver This driver is used to configure the coincell charger found in Qualcomm PMICs. The driver allows configuring the current-limiting resistor for the charger, as well as the voltage to apply to the coincell (or capacitor) when charging. Signed-off-by: Tim Bird Reviewed-by: Andy Gross Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 10 +++ drivers/misc/Makefile | 1 + drivers/misc/qcom-coincell.c | 152 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 drivers/misc/qcom-coincell.c (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 42c38525904b..ccccc2943f2f 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -271,6 +271,16 @@ config HP_ILO To compile this driver as a module, choose M here: the module will be called hpilo. +config QCOM_COINCELL + tristate "Qualcomm coincell charger support" + depends on MFD_SPMI_PMIC || COMPILE_TEST + help + This driver supports the coincell block found inside of + Qualcomm PMICs. The coincell charger provides a means to + charge a coincell battery or backup capacitor which is used + to maintain PMIC register and RTC state in the absence of + external power. + config SGI_GRU tristate "SGI GRU driver" depends on X86_UV && SMP diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d056fb7186fe..537d7f3b78da 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_PHANTOM) += phantom.o +obj-$(CONFIG_QCOM_COINCELL) += qcom-coincell.o obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o diff --git a/drivers/misc/qcom-coincell.c b/drivers/misc/qcom-coincell.c new file mode 100644 index 000000000000..7b4a2da487a5 --- /dev/null +++ b/drivers/misc/qcom-coincell.c @@ -0,0 +1,152 @@ +/* Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2015, Sony Mobile Communications 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 and + * only 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 +#include + +struct qcom_coincell { + struct device *dev; + struct regmap *regmap; + u32 base_addr; +}; + +#define QCOM_COINCELL_REG_RSET 0x44 +#define QCOM_COINCELL_REG_VSET 0x45 +#define QCOM_COINCELL_REG_ENABLE 0x46 + +#define QCOM_COINCELL_ENABLE BIT(7) + +static const int qcom_rset_map[] = { 2100, 1700, 1200, 800 }; +static const int qcom_vset_map[] = { 2500, 3200, 3100, 3000 }; +/* NOTE: for pm8921 and others, voltage of 2500 is 16 (10000b), not 0 */ + +/* if enable==0, rset and vset are ignored */ +static int qcom_coincell_chgr_config(struct qcom_coincell *chgr, int rset, + int vset, bool enable) +{ + int i, j, rc; + + /* if disabling, just do that and skip other operations */ + if (!enable) + return regmap_write(chgr->regmap, + chgr->base_addr + QCOM_COINCELL_REG_ENABLE, 0); + + /* find index for current-limiting resistor */ + for (i = 0; i < ARRAY_SIZE(qcom_rset_map); i++) + if (rset == qcom_rset_map[i]) + break; + + if (i >= ARRAY_SIZE(qcom_rset_map)) { + dev_err(chgr->dev, "invalid rset-ohms value %d\n", rset); + return -EINVAL; + } + + /* find index for charge voltage */ + for (j = 0; j < ARRAY_SIZE(qcom_vset_map); j++) + if (vset == qcom_vset_map[j]) + break; + + if (j >= ARRAY_SIZE(qcom_vset_map)) { + dev_err(chgr->dev, "invalid vset-millivolts value %d\n", vset); + return -EINVAL; + } + + rc = regmap_write(chgr->regmap, + chgr->base_addr + QCOM_COINCELL_REG_RSET, i); + if (rc) { + /* + * This is mainly to flag a bad base_addr (reg) from dts. + * Other failures writing to the registers should be + * extremely rare, or indicative of problems that + * should be reported elsewhere (eg. spmi failure). + */ + dev_err(chgr->dev, "could not write to RSET register\n"); + return rc; + } + + rc = regmap_write(chgr->regmap, + chgr->base_addr + QCOM_COINCELL_REG_VSET, j); + if (rc) + return rc; + + /* set 'enable' register */ + return regmap_write(chgr->regmap, + chgr->base_addr + QCOM_COINCELL_REG_ENABLE, + QCOM_COINCELL_ENABLE); +} + +static int qcom_coincell_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct qcom_coincell chgr; + u32 rset, vset; + bool enable; + int rc; + + chgr.dev = &pdev->dev; + + chgr.regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chgr.regmap) { + dev_err(chgr.dev, "Unable to get regmap\n"); + return -EINVAL; + } + + rc = of_property_read_u32(node, "reg", &chgr.base_addr); + if (rc) + return rc; + + enable = !of_property_read_bool(node, "qcom,charger-disable"); + + if (enable) { + rc = of_property_read_u32(node, "qcom,rset-ohms", &rset); + if (rc) { + dev_err(chgr.dev, + "can't find 'qcom,rset-ohms' in DT block"); + return rc; + } + + rc = of_property_read_u32(node, "qcom,vset-millivolts", &vset); + if (rc) { + dev_err(chgr.dev, + "can't find 'qcom,vset-millivolts' in DT block"); + return rc; + } + } + + return qcom_coincell_chgr_config(&chgr, rset, vset, enable); +} + +static const struct of_device_id qcom_coincell_match_table[] = { + { .compatible = "qcom,pm8941-coincell", }, + {} +}; + +MODULE_DEVICE_TABLE(of, qcom_coincell_match_table); + +static struct platform_driver qcom_coincell_driver = { + .driver = { + .name = "qcom-spmi-coincell", + .of_match_table = qcom_coincell_match_table, + }, + .probe = qcom_coincell_probe, +}; + +module_platform_driver(qcom_coincell_driver); + +MODULE_DESCRIPTION("Qualcomm PMIC coincell charger driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From add04a9854106a724b9fbf8bc9925781e5b0059e Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Mon, 27 Jul 2015 10:31:09 +0900 Subject: staging: most: core.c: remove semicolon at the end of define statement Remove semicolon at the end of define statement to fix checkpatch warning. WARNING: macros should not use a trailing semicolon Signed-off-by: Chaehyun Lim Acked-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/mostcore/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/most/mostcore/core.c b/drivers/staging/most/mostcore/core.c index f4f903404f1b..98a4c900d1c2 100644 --- a/drivers/staging/most/mostcore/core.c +++ b/drivers/staging/most/mostcore/core.c @@ -328,7 +328,7 @@ static ssize_t show_channel_starving(struct most_c_obj *c, #define create_show_channel_attribute(val) \ - static MOST_CHNL_ATTR(val, S_IRUGO, show_##val, NULL); + static MOST_CHNL_ATTR(val, S_IRUGO, show_##val, NULL) create_show_channel_attribute(available_directions); create_show_channel_attribute(available_datatypes); -- cgit v1.3-6-gb490 From 7ac5c9f0a0228fff35c0ea85008ff642b07e6db3 Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Tue, 28 Jul 2015 17:16:09 +0200 Subject: Staging: most: fix snprintf() is printing too much This patch prevents snprintf from exceeding a given buffer size. Reported-by: Dan Carpenter Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/mostcore/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/most/mostcore/core.c b/drivers/staging/most/mostcore/core.c index 98a4c900d1c2..49d03af599d5 100644 --- a/drivers/staging/most/mostcore/core.c +++ b/drivers/staging/most/mostcore/core.c @@ -983,7 +983,7 @@ static ssize_t store_add_link(struct most_aim_obj *aim_obj, return ret; if (mdev_devnod == 0 || *mdev_devnod == 0) { - snprintf(devnod_buf, PAGE_SIZE, "%s-%s", mdev, mdev_ch); + snprintf(devnod_buf, sizeof(devnod_buf), "%s-%s", mdev, mdev_ch); mdev_devnod = devnod_buf; } -- cgit v1.3-6-gb490 From 2e4c30458e31e5f6487d1393254f2ab347cfb02c Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Tue, 28 Jul 2015 17:16:10 +0200 Subject: Staging: most: fix dereferencing freed memory This patch fixes the dereferencing of freed memory. Reported-by: Dan Carpenter Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/aim-cdev/cdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/most/aim-cdev/cdev.c b/drivers/staging/most/aim-cdev/cdev.c index d5fb4a0e0818..cfc32dff6512 100644 --- a/drivers/staging/most/aim-cdev/cdev.c +++ b/drivers/staging/most/aim-cdev/cdev.c @@ -124,9 +124,9 @@ static int aim_close(struct inode *inode, struct file *filp) cdev_del(&channel->cdev); kfifo_free(&channel->fifo); list_del(&channel->list); - kfree(channel); ida_simple_remove(&minor_id, MINOR(channel->devno)); wake_up_interruptible(&channel->wq); + kfree(channel); return 0; } mutex_unlock(&channel->io_mutex); -- cgit v1.3-6-gb490 From a11442fe87d63994816cf2edde4450410df397af Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Tue, 28 Jul 2015 17:16:11 +0200 Subject: Staging: most: fix passing a potential null pointer This patch fixes passing of a potential null pointer. Reported-by: Dan Carpenter Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/aim-cdev/cdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/most/aim-cdev/cdev.c b/drivers/staging/most/aim-cdev/cdev.c index cfc32dff6512..252a17cf153c 100644 --- a/drivers/staging/most/aim-cdev/cdev.c +++ b/drivers/staging/most/aim-cdev/cdev.c @@ -204,7 +204,8 @@ static ssize_t aim_write(struct file *filp, const char __user *buf, } return actual_len - retval; error: - most_put_mbo(mbo); + if (mbo) + most_put_mbo(mbo); return err; } -- cgit v1.3-6-gb490 From d10e0a6332fdea740fa74f541e354788903878a1 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 28 Jul 2015 10:45:07 -0700 Subject: staging: most: fix aim-network build errors Fix build errors when CONFIG_NET is not enabled by making the driver depend on NET. Also correct the loadable module name. ERROR: "__netdev_alloc_skb" [drivers/staging/most/aim-network/aim_network.ko] undefined! ERROR: "netif_rx" [drivers/staging/most/aim-network/aim_network.ko] undefined! ERROR: "netif_tx_wake_queue" [drivers/staging/most/aim-network/aim_network.ko] undefined! ERROR: "free_netdev" [drivers/staging/most/aim-network/aim_network.ko] undefined! ERROR: "register_netdev" [drivers/staging/most/aim-network/aim_network.ko] undefined! ERROR: "kfree_skb" [drivers/staging/most/aim-network/aim_network.ko] undefined! ERROR: "alloc_netdev_mqs" [drivers/staging/most/aim-network/aim_network.ko] undefined! ERROR: "eth_type_trans" [drivers/staging/most/aim-network/aim_network.ko] undefined! ERROR: "ether_setup" [drivers/staging/most/aim-network/aim_network.ko] undefined! ERROR: "unregister_netdev" [drivers/staging/most/aim-network/aim_network.ko] undefined! ERROR: "skb_put" [drivers/staging/most/aim-network/aim_network.ko] undefined! ERROR: "eth_mac_addr" [drivers/staging/most/aim-network/aim_network.ko] undefined! Signed-off-by: Randy Dunlap Cc: Andrey Shvetsov Cc: Michael Fabry Acked-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/aim-network/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/most/aim-network/Kconfig b/drivers/staging/most/aim-network/Kconfig index 507232a7f7ee..4c66b24cf73c 100644 --- a/drivers/staging/most/aim-network/Kconfig +++ b/drivers/staging/most/aim-network/Kconfig @@ -4,9 +4,10 @@ config AIM_NETWORK tristate "Networking AIM" + depends on NET ---help--- Say Y here if you want to commumicate via a networking device. To compile this driver as a module, choose M here: the - module will be called aim_networking. + module will be called aim_network. -- cgit v1.3-6-gb490 From 1625d2166cbcace6fff3b4413be78522f4137f57 Mon Sep 17 00:00:00 2001 From: Tony Cho Date: Tue, 28 Jul 2015 17:47:20 +0900 Subject: staging: wilc1000: remove unnecessary files This patch removes the following files which are not used anymore. - fifo_buffer.c - fifo_buffer.h - coreconfigsimulator.h - wilc_wfi_netdevice.c Signed-off-by: Robin Hwang Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/Makefile | 4 +- drivers/staging/wilc1000/coreconfigsimulator.h | 17 - drivers/staging/wilc1000/fifo_buffer.c | 132 ---- drivers/staging/wilc1000/fifo_buffer.h | 26 - drivers/staging/wilc1000/host_interface.h | 1 - drivers/staging/wilc1000/wilc_wfi_netdevice.c | 909 ------------------------- 6 files changed, 2 insertions(+), 1087 deletions(-) delete mode 100644 drivers/staging/wilc1000/coreconfigsimulator.h delete mode 100644 drivers/staging/wilc1000/fifo_buffer.c delete mode 100644 drivers/staging/wilc1000/fifo_buffer.h delete mode 100644 drivers/staging/wilc1000/wilc_wfi_netdevice.c (limited to 'drivers') diff --git a/drivers/staging/wilc1000/Makefile b/drivers/staging/wilc1000/Makefile index a78c4d529a58..5ca8fa253306 100644 --- a/drivers/staging/wilc1000/Makefile +++ b/drivers/staging/wilc1000/Makefile @@ -25,10 +25,10 @@ ccflags-$(CONFIG_WILC1000_PREALLOCATE_AT_LOADING_DRIVER) += -DMEMORY_STATIC \ ccflags-$(CONFIG_WILC1000_DYNAMICALLY_ALLOCATE_MEMROY) += -DWILC_NORMAL_ALLOC -wilc1000-objs := wilc_wfi_netdevice.o wilc_wfi_cfgoperations.o linux_wlan.o linux_mon.o \ +wilc1000-objs := wilc_wfi_cfgoperations.o linux_wlan.o linux_mon.o \ wilc_memory.o wilc_msgqueue.o wilc_sleep.o wilc_strutils.o \ wilc_timer.o coreconfigurator.o host_interface.o \ - fifo_buffer.o wilc_sdio.o wilc_spi.o wilc_wlan_cfg.o wilc_debugfs.o + wilc_sdio.o wilc_spi.o wilc_wlan_cfg.o wilc_debugfs.o wilc1000-$(CONFIG_WILC1000_SDIO) += linux_wlan_sdio.o wilc1000-$(CONFIG_WILC1000_SPI) += linux_wlan_spi.o diff --git a/drivers/staging/wilc1000/coreconfigsimulator.h b/drivers/staging/wilc1000/coreconfigsimulator.h deleted file mode 100644 index 5e01f8e4a41d..000000000000 --- a/drivers/staging/wilc1000/coreconfigsimulator.h +++ /dev/null @@ -1,17 +0,0 @@ - -/*! - * @file coreconfigsimulator.h - * @brief - * @author - * @sa coreconfigsimulator.c - * @date 1 Mar 2012 - * @version 1.0 - */ - -#ifndef CORECONFIGSIMULATOR_H -#define CORECONFIGSIMULATOR_H - -extern s32 CoreConfigSimulatorInit(void); -extern s32 CoreConfigSimulatorDeInit(void); - -#endif diff --git a/drivers/staging/wilc1000/fifo_buffer.c b/drivers/staging/wilc1000/fifo_buffer.c deleted file mode 100644 index 86eb82e36be0..000000000000 --- a/drivers/staging/wilc1000/fifo_buffer.c +++ /dev/null @@ -1,132 +0,0 @@ - - -#include "fifo_buffer.h" - - - -u32 FIFO_InitBuffer(tHANDLE *hBuffer, u32 u32BufferLength) -{ - u32 u32Error = 0; - tstrFifoHandler *pstrFifoHandler = WILC_MALLOC (sizeof (tstrFifoHandler)); - if (pstrFifoHandler) { - WILC_memset (pstrFifoHandler, 0, sizeof (tstrFifoHandler)); - pstrFifoHandler->pu8Buffer = WILC_MALLOC (u32BufferLength); - if (pstrFifoHandler->pu8Buffer) { - pstrFifoHandler->u32BufferLength = u32BufferLength; - WILC_memset (pstrFifoHandler->pu8Buffer, 0, u32BufferLength); - /* create semaphore */ - sema_init(&pstrFifoHandler->SemBuffer, 1); - *hBuffer = pstrFifoHandler; - } else { - *hBuffer = NULL; - u32Error = 1; - } - } else { - u32Error = 1; - } - return u32Error; -} -u32 FIFO_DeInit(tHANDLE hFifo) -{ - u32 u32Error = 0; - tstrFifoHandler *pstrFifoHandler = (tstrFifoHandler *) hFifo; - if (pstrFifoHandler) { - if (pstrFifoHandler->pu8Buffer) - WILC_FREE (pstrFifoHandler->pu8Buffer); - else - u32Error = 1; - - WILC_FREE (pstrFifoHandler); - } else { - u32Error = 1; - } - return u32Error; -} - -u32 FIFO_ReadBytes(tHANDLE hFifo, u8 *pu8Buffer, u32 u32BytesToRead, u32 *pu32BytesRead) -{ - u32 u32Error = 0; - tstrFifoHandler *pstrFifoHandler = (tstrFifoHandler *) hFifo; - if (pstrFifoHandler && pu32BytesRead) { - if (pstrFifoHandler->u32TotalBytes) { - down(&pstrFifoHandler->SemBuffer); - - if (u32BytesToRead > pstrFifoHandler->u32TotalBytes) - *pu32BytesRead = pstrFifoHandler->u32TotalBytes; - else - *pu32BytesRead = u32BytesToRead; - - if ((pstrFifoHandler->u32ReadOffset + u32BytesToRead) <= pstrFifoHandler->u32BufferLength) { - WILC_memcpy(pu8Buffer, pstrFifoHandler->pu8Buffer + pstrFifoHandler->u32ReadOffset, - *pu32BytesRead); - /* update read offset and total bytes */ - pstrFifoHandler->u32ReadOffset += u32BytesToRead; - pstrFifoHandler->u32TotalBytes -= u32BytesToRead; - - } else { - u32 u32FirstPart = - pstrFifoHandler->u32BufferLength - pstrFifoHandler->u32ReadOffset; - WILC_memcpy(pu8Buffer, pstrFifoHandler->pu8Buffer + pstrFifoHandler->u32ReadOffset, - u32FirstPart); - WILC_memcpy(pu8Buffer + u32FirstPart, pstrFifoHandler->pu8Buffer, - u32BytesToRead - u32FirstPart); - /* update read offset and total bytes */ - pstrFifoHandler->u32ReadOffset = u32BytesToRead - u32FirstPart; - pstrFifoHandler->u32TotalBytes -= u32BytesToRead; - } - up(&pstrFifoHandler->SemBuffer); - } else { - u32Error = 1; - } - } else { - u32Error = 1; - } - return u32Error; -} - -u32 FIFO_WriteBytes(tHANDLE hFifo, u8 *pu8Buffer, u32 u32BytesToWrite, bool bForceOverWrite) -{ - u32 u32Error = 0; - tstrFifoHandler *pstrFifoHandler = (tstrFifoHandler *) hFifo; - if (pstrFifoHandler) { - if (u32BytesToWrite < pstrFifoHandler->u32BufferLength) { - if ((pstrFifoHandler->u32TotalBytes + u32BytesToWrite) <= pstrFifoHandler->u32BufferLength || - bForceOverWrite) { - down(&pstrFifoHandler->SemBuffer); - if ((pstrFifoHandler->u32WriteOffset + u32BytesToWrite) <= pstrFifoHandler->u32BufferLength) { - WILC_memcpy(pstrFifoHandler->pu8Buffer + pstrFifoHandler->u32WriteOffset, pu8Buffer, - u32BytesToWrite); - /* update read offset and total bytes */ - pstrFifoHandler->u32WriteOffset += u32BytesToWrite; - pstrFifoHandler->u32TotalBytes += u32BytesToWrite; - - } else { - u32 u32FirstPart = - pstrFifoHandler->u32BufferLength - pstrFifoHandler->u32WriteOffset; - WILC_memcpy(pstrFifoHandler->pu8Buffer + pstrFifoHandler->u32WriteOffset, pu8Buffer, - u32FirstPart); - WILC_memcpy(pstrFifoHandler->pu8Buffer, pu8Buffer + u32FirstPart, - u32BytesToWrite - u32FirstPart); - /* update read offset and total bytes */ - pstrFifoHandler->u32WriteOffset = u32BytesToWrite - u32FirstPart; - pstrFifoHandler->u32TotalBytes += u32BytesToWrite; - } - /* if data overwriten */ - if (pstrFifoHandler->u32TotalBytes > pstrFifoHandler->u32BufferLength) { - /* adjust read offset to the oldest data available */ - pstrFifoHandler->u32ReadOffset = pstrFifoHandler->u32WriteOffset; - /* data availabe is the buffer length */ - pstrFifoHandler->u32TotalBytes = pstrFifoHandler->u32BufferLength; - } - up(&pstrFifoHandler->SemBuffer); - } else { - u32Error = 1; - } - } else { - u32Error = 1; - } - } else { - u32Error = 1; - } - return u32Error; -} diff --git a/drivers/staging/wilc1000/fifo_buffer.h b/drivers/staging/wilc1000/fifo_buffer.h deleted file mode 100644 index 7b76998e4238..000000000000 --- a/drivers/staging/wilc1000/fifo_buffer.h +++ /dev/null @@ -1,26 +0,0 @@ - -#include -#include -#include "wilc_memory.h" -#include "wilc_strutils.h" - - -#define tHANDLE void * - -typedef struct { - u8 *pu8Buffer; - u32 u32BufferLength; - u32 u32WriteOffset; - u32 u32ReadOffset; - u32 u32TotalBytes; - struct semaphore SemBuffer; -} tstrFifoHandler; - - -extern u32 FIFO_InitBuffer(tHANDLE *hBuffer, - u32 u32BufferLength); -extern u32 FIFO_DeInit(tHANDLE hFifo); -extern u32 FIFO_ReadBytes(tHANDLE hFifo, u8 *pu8Buffer, - u32 u32BytesToRead, u32 *pu32BytesRead); -extern u32 FIFO_WriteBytes(tHANDLE hFifo, u8 *pu8Buffer, - u32 u32BytesToWrite, bool bForceOverWrite); diff --git a/drivers/staging/wilc1000/host_interface.h b/drivers/staging/wilc1000/host_interface.h index 38db740745cd..cdfb43a2b144 100644 --- a/drivers/staging/wilc1000/host_interface.h +++ b/drivers/staging/wilc1000/host_interface.h @@ -11,7 +11,6 @@ #define HOST_INT_H #include "coreconfigurator.h" -#include "coreconfigsimulator.h" /*****************************************************************************/ /* Macros */ /*****************************************************************************/ diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.c b/drivers/staging/wilc1000/wilc_wfi_netdevice.c deleted file mode 100644 index af9b85822ced..000000000000 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.c +++ /dev/null @@ -1,909 +0,0 @@ -/*! - * @file wilc_wfi_netdevice.c - * @brief File Operations OS wrapper functionality - * @author mdaftedar - * @sa wilc_wfi_netdevice.h - * @date 01 MAR 2012 - * @version 1.0 - */ - -#ifdef SIMULATION - -#include "wilc_wfi_cfgoperations.h" -#include "host_interface.h" - -MODULE_AUTHOR("Mai Daftedar"); -MODULE_LICENSE("Dual BSD/GPL"); - -struct net_device *WILC_WFI_devs[2]; - -/* - * Transmitter lockup simulation, normally disabled. - */ -static int lockup; -module_param(lockup, int, 0); - -static int timeout = WILC_WFI_TIMEOUT; -module_param(timeout, int, 0); - -/* - * Do we run in NAPI mode? - */ -static int use_napi; -module_param(use_napi, int, 0); - -/* - * A structure representing an in-flight packet. - */ -struct WILC_WFI_packet { - struct WILC_WFI_packet *next; - struct net_device *dev; - int datalen; - u8 data[ETH_DATA_LEN]; -}; - -int pool_size = 8; -module_param(pool_size, int, 0); - -static void WILC_WFI_TxTimeout(struct net_device *dev); -static void (*WILC_WFI_Interrupt)(int, void *, struct pt_regs *); - -/** - * @brief WILC_WFI_SetupPool - * @details Set up a device's packet pool. - * @param[in] struct net_device *dev : Network Device Pointer - * @return NONE - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -void WILC_WFI_SetupPool(struct net_device *dev) -{ - struct WILC_WFI_priv *priv = netdev_priv(dev); - int i; - struct WILC_WFI_packet *pkt; - - priv->ppool = NULL; - for (i = 0; i < pool_size; i++) { - pkt = kmalloc(sizeof(struct WILC_WFI_packet), GFP_KERNEL); - if (pkt == NULL) { - PRINT_D(RX_DBG, "Ran out of memory allocating packet pool\n"); - return; - } - pkt->dev = dev; - pkt->next = priv->ppool; - priv->ppool = pkt; - } -} - -/** - * @brief WILC_WFI_TearDownPool - * @details Internal cleanup function that's called after the network device - * driver is unregistered - * @param[in] struct net_device *dev : Network Device Driver - * @return NONE - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -void WILC_WFI_TearDownPool(struct net_device *dev) -{ - struct WILC_WFI_priv *priv = netdev_priv(dev); - struct WILC_WFI_packet *pkt; - - while ((pkt = priv->ppool)) { - priv->ppool = pkt->next; - kfree(pkt); - /* FIXME - in-flight packets ? */ - } -} - -/** - * @brief WILC_WFI_GetTxBuffer - * @details Buffer/pool management - * @param[in] net_device *dev : Network Device Driver Structure - * @return struct WILC_WFI_packet - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -struct WILC_WFI_packet *WILC_WFI_GetTxBuffer(struct net_device *dev) -{ - struct WILC_WFI_priv *priv = netdev_priv(dev); - unsigned long flags; - struct WILC_WFI_packet *pkt; - - spin_lock_irqsave(&priv->lock, flags); - pkt = priv->ppool; - priv->ppool = pkt->next; - if (priv->ppool == NULL) { - PRINT_INFO(RX_DBG, "Pool empty\n"); - netif_stop_queue(dev); - } - spin_unlock_irqrestore(&priv->lock, flags); - return pkt; -} -/** - * @brief WILC_WFI_ReleaseBuffer - * @details Buffer/pool management - * @param[in] WILC_WFI_packet *pkt : Structure holding in-flight packet - * @return NONE - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -void WILC_WFI_ReleaseBuffer(struct WILC_WFI_packet *pkt) -{ - unsigned long flags; - struct WILC_WFI_priv *priv = netdev_priv(pkt->dev); - - spin_lock_irqsave(&priv->lock, flags); - pkt->next = priv->ppool; - priv->ppool = pkt; - spin_unlock_irqrestore(&priv->lock, flags); - if (netif_queue_stopped(pkt->dev) && pkt->next == NULL) - netif_wake_queue(pkt->dev); -} - -/** - * @brief WILC_WFI_EnqueueBuf - * @details Enqueuing packets in an RX buffer queue - * @param[in] WILC_WFI_packet *pkt : Structure holding in-flight packet - * @param[in] net_device *dev : Network Device Driver Structure - * @return NONE - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -void WILC_WFI_EnqueueBuf(struct net_device *dev, struct WILC_WFI_packet *pkt) -{ - unsigned long flags; - struct WILC_WFI_priv *priv = netdev_priv(dev); - - spin_lock_irqsave(&priv->lock, flags); - pkt->next = priv->rx_queue; /* FIXME - misorders packets */ - priv->rx_queue = pkt; - spin_unlock_irqrestore(&priv->lock, flags); -} - -/** - * @brief WILC_WFI_DequeueBuf - * @details Dequeuing packets from the RX buffer queue - * @param[in] net_device *dev : Network Device Driver Structure - * @return WILC_WFI_packet *pkt : Structure holding in-flight pac - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -struct WILC_WFI_packet *WILC_WFI_DequeueBuf(struct net_device *dev) -{ - struct WILC_WFI_priv *priv = netdev_priv(dev); - struct WILC_WFI_packet *pkt; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - pkt = priv->rx_queue; - if (pkt != NULL) - priv->rx_queue = pkt->next; - spin_unlock_irqrestore(&priv->lock, flags); - return pkt; -} -/** - * @brief WILC_WFI_RxInts - * @details Enable and disable receive interrupts. - * @param[in] net_device *dev : Network Device Driver Structure - * @param[in] enable : Enable/Disable flag - * @return NONE - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -static void WILC_WFI_RxInts(struct net_device *dev, int enable) -{ - struct WILC_WFI_priv *priv = netdev_priv(dev); - - priv->rx_int_enabled = enable; -} - -/** - * @brief WILC_WFI_Open - * @details Open Network Device Driver, called when the network - * interface is opened. It starts the interface's transmit queue. - * @param[in] net_device *dev : Network Device Driver Structure - * @param[in] enable : Enable/Disable flag - * @return int : Returns 0 upon success. - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -int WILC_WFI_Open(struct net_device *dev) -{ - /* request_region(), request_irq(), .... (like fops->open) */ - /* - * Assign the hardware address of the board: use "\0SNULx", where - * x is 0 or 1. The first byte is '\0' to avoid being a multicast - * address (the first byte of multicast addrs is odd). - */ - memcpy(dev->dev_addr, "\0WLAN0", ETH_ALEN); - if (dev == WILC_WFI_devs[1]) - dev->dev_addr[ETH_ALEN - 1]++; /* \0SNUL1 */ - - WILC_WFI_InitHostInt(dev); - netif_start_queue(dev); - return 0; -} -/** - * @brief WILC_WFI_Release - * @details Release Network Device Driver, called when the network - * interface is stopped or brought down. This function marks - * the network driver as not being able to transmit - * @param[in] net_device *dev : Network Device Driver Structure - * @return int : Return 0 on Success. - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -int WILC_WFI_Release(struct net_device *dev) -{ - /* release ports, irq and such -- like fops->close */ - netif_stop_queue(dev); /* can't transmit any more */ - - return 0; -} -/** - * @brief WILC_WFI_Config - * @details Configuration changes (passed on by ifconfig) - * @param[in] net_device *dev : Network Device Driver Structure - * @param[in] struct ifmap *map : Contains the ioctl implementation for the - * network driver. - * @return int : Return 0 on Success. - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -int WILC_WFI_Config(struct net_device *dev, struct ifmap *map) -{ - if (dev->flags & IFF_UP) /* can't act on a running interface */ - return -EBUSY; - - /* Don't allow changing the I/O address */ - if (map->base_addr != dev->base_addr) { - PRINT_D(RX_DBG, KERN_WARNING "WILC_WFI: Can't change I/O address\n"); - return -EOPNOTSUPP; - } - - /* Allow changing the IRQ */ - if (map->irq != dev->irq) { - dev->irq = map->irq; - /* request_irq() is delayed to open-time */ - } - - /* ignore other fields */ - return 0; -} -/** - * @brief WILC_WFI_Rx - * @details Receive a packet: retrieve, encapsulate and pass over to upper - * levels - * @param[in] net_device *dev : Network Device Driver Structure - * @param[in] WILC_WFI_packet : - * @return NONE - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -void WILC_WFI_Rx(struct net_device *dev, struct WILC_WFI_packet *pkt) -{ - int i; - struct sk_buff *skb; - struct WILC_WFI_priv *priv = netdev_priv(dev); - s8 rssi; - /* - * The packet has been retrieved from the transmission - * medium. Build an skb around it, so upper layers can handle it - */ - - - skb = dev_alloc_skb(pkt->datalen + 2); - if (!skb) { - if (printk_ratelimit()) - PRINT_D(RX_DBG, "WILC_WFI rx: low on mem - packet dropped\n"); - priv->stats.rx_dropped++; - goto out; - } - skb_reserve(skb, 2); /* align IP on 16B boundary */ - memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); - - if (priv->monitor_flag) { - PRINT_INFO(RX_DBG, "In monitor device name %s\n", dev->name); - priv = wiphy_priv(priv->dev->ieee80211_ptr->wiphy); - PRINT_D(RX_DBG, "VALUE PASSED IN OF HRWD %p\n", priv->hWILCWFIDrv); - if (INFO) { - for (i = 14; i < skb->len; i++) - PRINT_INFO(RX_DBG, "RXdata[%d] %02x\n", i, skb->data[i]); - } - WILC_WFI_monitor_rx(dev, skb); - return; - } -out: - return; -} - -/** - * @brief WILC_WFI_Poll - * @details The poll implementation - * @param[in] struct napi_struct *napi : - * @param[in] int budget : - * @return int : Return 0 on Success. - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -static int WILC_WFI_Poll(struct napi_struct *napi, int budget) -{ - int npackets = 0; - struct sk_buff *skb; - struct WILC_WFI_priv *priv = container_of(napi, struct WILC_WFI_priv, napi); - struct net_device *dev = priv->dev; - struct WILC_WFI_packet *pkt; - - while (npackets < budget && priv->rx_queue) { - pkt = WILC_WFI_DequeueBuf(dev); - skb = dev_alloc_skb(pkt->datalen + 2); - if (!skb) { - if (printk_ratelimit()) - PRINT_D(RX_DBG, "WILC_WFI: packet dropped\n"); - priv->stats.rx_dropped++; - WILC_WFI_ReleaseBuffer(pkt); - continue; - } - skb_reserve(skb, 2); /* align IP on 16B boundary */ - memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen); - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ - netif_receive_skb(skb); - /* Maintain stats */ - npackets++; - WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, pkt->datalen, WILC_WFI_RX_PKT); - WILC_WFI_ReleaseBuffer(pkt); - } - /* If we processed all packets, we're done; tell the kernel and re-enable ints */ - if (npackets < budget) { - napi_complete(napi); - WILC_WFI_RxInts(dev, 1); - } - return npackets; -} - -/** - * @brief WILC_WFI_Poll - * @details The typical interrupt entry point - * @param[in] struct napi_struct *napi : - * @param[in] int budget : - * @return int : Return 0 on Success. - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -static void WILC_WFI_RegularInterrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - int statusword; - struct WILC_WFI_priv *priv; - struct WILC_WFI_packet *pkt = NULL; - /* - * As usual, check the "device" pointer to be sure it is - * really interrupting. - * Then assign "struct device *dev" - */ - struct net_device *dev = (struct net_device *)dev_id; - /* ... and check with hw if it's really ours */ - - /* paranoid */ - if (!dev) - return; - - /* Lock the device */ - priv = netdev_priv(dev); - spin_lock(&priv->lock); - - /* retrieve statusword: real netdevices use I/O instructions */ - statusword = priv->status; - priv->status = 0; - if (statusword & WILC_WFI_RX_INTR) { - /* send it to WILC_WFI_rx for handling */ - pkt = priv->rx_queue; - if (pkt) { - priv->rx_queue = pkt->next; - WILC_WFI_Rx(dev, pkt); - } - } - if (statusword & WILC_WFI_TX_INTR) { - /* a transmission is over: free the skb */ - WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, priv->tx_packetlen, WILC_WFI_TX_PKT); - dev_kfree_skb(priv->skb); - } - - /* Unlock the device and we are done */ - spin_unlock(&priv->lock); - if (pkt) - WILC_WFI_ReleaseBuffer(pkt); /* Do this outside the lock! */ - return; -} -/** - * @brief WILC_WFI_NapiInterrupt - * @details A NAPI interrupt handler - * @param[in] irq: - * @param[in] dev_id: - * @param[in] pt_regs: - * @return NONE - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -static void WILC_WFI_NapiInterrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - int statusword; - struct WILC_WFI_priv *priv; - - /* - * As usual, check the "device" pointer for shared handlers. - * Then assign "struct device *dev" - */ - struct net_device *dev = (struct net_device *)dev_id; - /* ... and check with hw if it's really ours */ - - /* paranoid */ - if (!dev) - return; - - /* Lock the device */ - priv = netdev_priv(dev); - spin_lock(&priv->lock); - - /* retrieve statusword: real netdevices use I/O instructions */ - statusword = priv->status; - priv->status = 0; - if (statusword & WILC_WFI_RX_INTR) { - WILC_WFI_RxInts(dev, 0); /* Disable further interrupts */ - napi_schedule(&priv->napi); - } - if (statusword & WILC_WFI_TX_INTR) { - /* a transmission is over: free the skb */ - - WILC_WFI_update_stats(priv->dev->ieee80211_ptr->wiphy, priv->tx_packetlen, WILC_WFI_TX_PKT); - dev_kfree_skb(priv->skb); - } - - /* Unlock the device and we are done */ - spin_unlock(&priv->lock); - return; -} - -/** - * @brief MI_WFI_HwTx - * @details Transmit a packet (low level interface) - * @param[in] buf: - * @param[in] len: - * @param[in] net_device *dev: - * @return NONE - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -void WILC_WFI_HwTx(char *buf, int len, struct net_device *dev) -{ - /* - * This function deals with hw details. This interface loops - * back the packet to the other WILC_WFI interface (if any). - * In other words, this function implements the WILC_WFI behaviour, - * while all other procedures are rather device-independent - */ - struct iphdr *ih; - struct net_device *dest; - struct WILC_WFI_priv *priv; - u32 *saddr, *daddr; - struct WILC_WFI_packet *tx_buffer; - - /* I am paranoid. Ain't I? */ - if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { - PRINT_D(RX_DBG, "WILC_WFI: Hmm... packet too short (%i octets)\n", - len); - return; - } - - if (0) { /* enable this conditional to look at the data */ - int i; - - PRINT_D(RX_DBG, "len is %i", len); - for (i = 14; i < len; i++) - PRINT_D(RX_DBG, "TXdata[%d] %02x\n", i, buf[i] & 0xff); - /* PRINT_D(RX_DBG, "\n"); */ - } - /* - * Ethhdr is 14 bytes, but the kernel arranges for iphdr - * to be aligned (i.e., ethhdr is unaligned) - */ - ih = (struct iphdr *)(buf + sizeof(struct ethhdr)); - saddr = &ih->saddr; - daddr = &ih->daddr; - - ((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */ - ((u8 *)daddr)[2] ^= 1; - - ih->check = 0; /* and rebuild the checksum (ip needs it) */ - ih->check = ip_fast_csum((unsigned char *)ih, ih->ihl); - - - if (dev == WILC_WFI_devs[0]) - PRINT_D(RX_DBG, "%08x:%05i --> %08x:%05i\n", - ntohl(ih->saddr), ntohs(((struct tcphdr *)(ih + 1))->source), - ntohl(ih->daddr), ntohs(((struct tcphdr *)(ih + 1))->dest)); - else - PRINT_D(RX_DBG, "%08x:%05i <-- %08x:%05i\n", - ntohl(ih->daddr), ntohs(((struct tcphdr *)(ih + 1))->dest), - ntohl(ih->saddr), ntohs(((struct tcphdr *)(ih + 1))->source)); - - /* - * Ok, now the packet is ready for transmission: first simulate a - * receive interrupt on the twin device, then a - * transmission-done on the transmitting device - */ - dest = WILC_WFI_devs[dev == WILC_WFI_devs[0] ? 1 : 0]; - priv = netdev_priv(dest); - - tx_buffer = WILC_WFI_GetTxBuffer(dev); - tx_buffer->datalen = len; - memcpy(tx_buffer->data, buf, len); - WILC_WFI_EnqueueBuf(dest, tx_buffer); - if (priv->rx_int_enabled) { - priv->status |= WILC_WFI_RX_INTR; - WILC_WFI_Interrupt(0, dest, NULL); - } - - priv = netdev_priv(dev); - priv->tx_packetlen = len; - priv->tx_packetdata = buf; - priv->status |= WILC_WFI_TX_INTR; - if (lockup && ((priv->stats.tx_packets + 1) % lockup) == 0) { - /* Simulate a dropped transmit interrupt */ - netif_stop_queue(dev); - PRINT_D(RX_DBG, "Simulate lockup at %ld, txp %ld\n", jiffies, - (unsigned long) priv->stats.tx_packets); - } else - WILC_WFI_Interrupt(0, dev, NULL); -} - -/** - * @brief WILC_WFI_Tx - * @details Transmit a packet (called by the kernel) - * @param[in] sk_buff *skb: - * @param[in] net_device *dev: - * @return NONE - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -int WILC_WFI_Tx(struct sk_buff *skb, struct net_device *dev) -{ - int len; - char *data, shortpkt[ETH_ZLEN]; - struct WILC_WFI_priv *priv = netdev_priv(dev); - - data = skb->data; - len = skb->len; - - if (len < ETH_ZLEN) { - memset(shortpkt, 0, ETH_ZLEN); - memcpy(shortpkt, skb->data, skb->len); - len = ETH_ZLEN; - data = shortpkt; - } - dev->trans_start = jiffies; /* save the timestamp */ - - /* Remember the skb, so we can free it at interrupt time */ - priv->skb = skb; - - /* actual deliver of data is device-specific, and not shown here */ - WILC_WFI_HwTx(data, len, dev); - - return 0; /* Our simple device can not fail */ -} - -/** - * @brief WILC_WFI_TxTimeout - * @details Deal with a transmit timeout. - * @param[in] net_device *dev: - * @return NONE - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -void WILC_WFI_TxTimeout(struct net_device *dev) -{ - struct WILC_WFI_priv *priv = netdev_priv(dev); - - PRINT_D(RX_DBG, "Transmit timeout at %ld, latency %ld\n", jiffies, - jiffies - dev->trans_start); - /* Simulate a transmission interrupt to get things moving */ - priv->status = WILC_WFI_TX_INTR; - WILC_WFI_Interrupt(0, dev, NULL); - priv->stats.tx_errors++; - netif_wake_queue(dev); - return; -} - -/** - * @brief WILC_WFI_Ioctl - * @details Ioctl commands - * @param[in] net_device *dev: - * @param[in] ifreq *rq - * @param[in] cmd: - * @return int : Return 0 on Success - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -int WILC_WFI_Ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - PRINT_D(RX_DBG, "ioctl\n"); - return 0; -} - -/** - * @brief WILC_WFI_Stat - * @details Return statistics to the caller - * @param[in] net_device *dev: - * @return WILC_WFI_Stats : Return net_device_stats stucture with the - * network device driver private data contents. - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -struct net_device_stats *WILC_WFI_Stats(struct net_device *dev) -{ - struct WILC_WFI_priv *priv = netdev_priv(dev); - - return &priv->stats; -} - -/** - * @brief WILC_WFI_RebuildHeader - * @details This function is called to fill up an eth header, since arp is not - * available on the interface - * @param[in] sk_buff *skb: - * @return int : Return 0 on Success - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -int WILC_WFI_RebuildHeader(struct sk_buff *skb) -{ - struct ethhdr *eth = (struct ethhdr *) skb->data; - struct net_device *dev = skb->dev; - - memcpy(eth->h_source, dev->dev_addr, dev->addr_len); - memcpy(eth->h_dest, dev->dev_addr, dev->addr_len); - eth->h_dest[ETH_ALEN - 1] ^= 0x01; /* dest is us xor 1 */ - return 0; -} -/** - * @brief WILC_WFI_RebuildHeader - * @details This function is called to fill up an eth header, since arp is not - * available on the interface - * @param[in] sk_buff *skb: - * @param[in] struct net_device *dev: - * @param[in] unsigned short type: - * @param[in] const void *saddr, - * @param[in] const void *daddr: - * @param[in] unsigned int len - * @return int : Return 0 on Success - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -int WILC_WFI_Header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *daddr, const void *saddr, - unsigned int len) -{ - struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); - - eth->h_proto = htons(type); - memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len); - memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr, dev->addr_len); - eth->h_dest[ETH_ALEN - 1] ^= 0x01; /* dest is us xor 1 */ - return dev->hard_header_len; -} - -/** - * @brief WILC_WFI_ChangeMtu - * @details The "change_mtu" method is usually not needed. - * If you need it, it must be like this. - * @param[in] net_device *dev : Network Device Driver Structure - * @param[in] new_mtu : - * @return int : Returns 0 on Success. - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -int WILC_WFI_ChangeMtu(struct net_device *dev, int new_mtu) -{ - unsigned long flags; - struct WILC_WFI_priv *priv = netdev_priv(dev); - spinlock_t *lock = &priv->lock; - - /* check ranges */ - if ((new_mtu < 68) || (new_mtu > 1500)) - return -EINVAL; - /* - * Do anything you need, and the accept the value - */ - spin_lock_irqsave(lock, flags); - dev->mtu = new_mtu; - spin_unlock_irqrestore(lock, flags); - return 0; /* success */ -} - -static const struct header_ops WILC_WFI_header_ops = { - .create = WILC_WFI_Header, - .rebuild = WILC_WFI_RebuildHeader, - .cache = NULL, /* disable caching */ -}; - - -static const struct net_device_ops WILC_WFI_netdev_ops = { - .ndo_open = WILC_WFI_Open, - .ndo_stop = WILC_WFI_Release, - .ndo_set_config = WILC_WFI_Config, - .ndo_start_xmit = WILC_WFI_Tx, - .ndo_do_ioctl = WILC_WFI_Ioctl, - .ndo_get_stats = WILC_WFI_Stats, - .ndo_change_mtu = WILC_WFI_ChangeMtu, - .ndo_tx_timeout = WILC_WFI_TxTimeout, -}; - -/** - * @brief WILC_WFI_Init - * @details The init function (sometimes called probe). - * It is invoked by register_netdev() - * @param[in] net_device *dev: - * @return NONE - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -void WILC_WFI_Init(struct net_device *dev) -{ - struct WILC_WFI_priv *priv; - - /* - * Then, assign other fields in dev, using ether_setup() and some - * hand assignments - */ - ether_setup(dev); /* assign some of the fields */ - /* 1- Allocate space */ - - dev->netdev_ops = &WILC_WFI_netdev_ops; - dev->header_ops = &WILC_WFI_header_ops; - dev->watchdog_timeo = timeout; - /* keep the default flags, just add NOARP */ - dev->flags |= IFF_NOARP; - dev->features |= NETIF_F_NO_CSUM; - /* - * Then, initialize the priv field. This encloses the statistics - * and a few private fields. - */ - priv = netdev_priv(dev); - memset(priv, 0, sizeof(struct WILC_WFI_priv)); - priv->dev = dev; - netif_napi_add(dev, &priv->napi, WILC_WFI_Poll, 2); - /* The last parameter above is the NAPI "weight". */ - spin_lock_init(&priv->lock); - WILC_WFI_RxInts(dev, 1); /* enable receive interrupts */ - WILC_WFI_SetupPool(dev); -} - -/** - * @brief WILC_WFI_Stat - * @details Return statistics to the caller - * @param[in] net_device *dev: - * @return WILC_WFI_Stats : Return net_device_stats stucture with the - * network device driver private data contents. - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ - -void WILC_WFI_Cleanup(void) -{ - int i; - struct WILC_WFI_priv *priv[2]; - - for (i = 0; i < 2; i++) { - priv[i] = netdev_priv(WILC_WFI_devs[i]); - - if (WILC_WFI_devs[i]) { - PRINT_D(RX_DBG, "Unregistering\n"); - unregister_netdev(WILC_WFI_devs[i]); - WILC_WFI_TearDownPool(WILC_WFI_devs[i]); - free_netdev(WILC_WFI_devs[i]); - PRINT_D(RX_DBG, "[NETDEV]Stopping interface\n"); - WILC_WFI_DeInitHostInt(WILC_WFI_devs[i]); - WILC_WFI_WiphyFree(WILC_WFI_devs[i]); - } - - } - /* unregister_netdev(hwsim_mon); */ - WILC_WFI_deinit_mon_interface(); - return; -} - - -void StartConfigSim(void); - -/** - * @brief WILC_WFI_Stat - * @details Return statistics to the caller - * @param[in] net_device *dev: - * @return WILC_WFI_Stats : Return net_device_stats stucture with the - * network device driver private data contents. - * @author mdaftedar - * @date 01 MAR 2012 - * @version 1.0 - */ -int WILC_WFI_InitModule(void) -{ - - int result, i, ret = -ENOMEM; - struct WILC_WFI_priv *priv[2], *netpriv; - struct wireless_dev *wdev; - - WILC_WFI_Interrupt = use_napi ? WILC_WFI_NapiInterrupt : WILC_WFI_RegularInterrupt; - - for (i = 0; i < 2; i++) { - /* Allocate the net devices */ - WILC_WFI_devs[i] = alloc_netdev(sizeof(struct WILC_WFI_priv), "wlan%d", - WILC_WFI_Init); - if (WILC_WFI_devs[i] == NULL) - goto out; - - wdev = WILC_WFI_WiphyRegister(WILC_WFI_devs[i]); - WILC_WFI_devs[i]->ieee80211_ptr = wdev; - netpriv = netdev_priv(WILC_WFI_devs[i]); - netpriv->dev->ieee80211_ptr = wdev; - netpriv->dev->ml_priv = netpriv; - wdev->netdev = netpriv->dev; - - /*Registering the net device*/ - result = register_netdev(WILC_WFI_devs[i]); - if (result) - PRINT_D(RX_DBG, "WILC_WFI: error %i registering device \"%s\"\n", - result, WILC_WFI_devs[i]->name); - else - ret = 0; - } - - /*init atmel driver */ - priv[0] = netdev_priv(WILC_WFI_devs[0]); - priv[1] = netdev_priv(WILC_WFI_devs[1]); - - priv[0]->bCfgScanning = false; - priv[0]->u32RcvdChCount = 0; - - WILC_memset(priv[0]->au8AssociatedBss, 0xFF, ETH_ALEN); - - if (ret) - PRINT_ER("Error Init Driver\n"); - -out: - if (ret) - WILC_WFI_Cleanup(); - return ret; - - -} - -module_init(WILC_WFI_InitModule); -module_exit(WILC_WFI_Cleanup); - -#endif -- cgit v1.3-6-gb490 From 5f8966d91e2e87ac9455aa5b2c10fccefa6d59a4 Mon Sep 17 00:00:00 2001 From: Tony Cho Date: Tue, 28 Jul 2015 17:47:21 +0900 Subject: staging: wilc1000: describe the config symbol fully This patch removes the warnings reported by checkpatch.pl on the short description for the config symbol in the Kconfig by adding more comments to describe the config symbol in more detail. Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/Kconfig | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/Kconfig b/drivers/staging/wilc1000/Kconfig index 062d9c5ca4bd..51bbf468fe45 100644 --- a/drivers/staging/wilc1000/Kconfig +++ b/drivers/staging/wilc1000/Kconfig @@ -37,17 +37,26 @@ choice bool "SDIO support" depends on MMC ---help--- - This module adds support for the SDIO interface - of adapters using WILC chipset. Select this if - your platform is using the SDIO bus. + This module adds support for the SDIO interface of adapters using + WILC1000 chipset. The Atmel WILC1000 SDIO is a full speed interface. + It meets SDIO card specification version 2.0. The interface supports + the 1-bit/4-bit SD transfer mode at the clock range of 0-50 MHz. + The host can use this interface to read and write from any register + within the chip as well as configure the WILC1000 for data DMA. + To use this interface, pin9 (SDIO_SPI_CFG) must be grounded. Select + this if your platform is using the SDIO bus. config WILC1000_SPI depends on SPI bool "SPI support" ---help--- - This module adds support for the SPI interface - of adapters using WILC chipset. Select this if - your platform is using the SPI bus. + This module adds support for the SPI interface of adapters using + WILC1000 chipset. The Atmel WILC1000 has a Serial Peripheral + Interface (SPI) that operates as a SPI slave. This SPI interface can + be used for control and for serial I/O of 802.11 data. The SPI is a + full-duplex slave synchronous serial interface that is available + immediately following reset when pin 9 (SDIO_SPI_CFG) is tied to + VDDIO. Select this if your platform is using the SPI bus. endchoice config WILC1000_HW_OOB_INTR @@ -55,5 +64,8 @@ config WILC1000_HW_OOB_INTR depends on WILC1000 && WILC1000_SDIO default n ---help--- - If your platform don't recognize SDIO IRQ, connect chipset external IRQ pin - and check this option. Or, Use this to get all interrupts including SDIO interrupts. + This option enables out-of-band interrupt support for the WILC1000 + chipset. This OOB interrupt is intended to provide a faster interrupt + mechanism for SDIO host controllers that don't support SDIO interrupt. + Select this option If the SDIO host controller in your platform + doesn't support SDIO time devision interrupt. -- cgit v1.3-6-gb490 From 9690df3f9de3689e7d2e916189761fff4754cd72 Mon Sep 17 00:00:00 2001 From: Tony Cho Date: Tue, 28 Jul 2015 17:47:22 +0900 Subject: staging: wilc1000: remove dead codes related to SIMULATION This patch removes preprocessor conditionals (#ifdef or #ifndef) related to SIMULATION definition from the codes becasue that SIMULATION feature is not used anymore. Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/coreconfigurator.c | 86 ----------------------- drivers/staging/wilc1000/host_interface.c | 23 ------ drivers/staging/wilc1000/linux_mon.c | 15 +--- drivers/staging/wilc1000/linux_wlan.c | 2 - drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 13 ---- 5 files changed, 3 insertions(+), 136 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c index b0696141e10f..8bacd8cfd945 100644 --- a/drivers/staging/wilc1000/coreconfigurator.c +++ b/drivers/staging/wilc1000/coreconfigurator.c @@ -1877,89 +1877,6 @@ s32 ConfigWaitResponse(char *pcRespBuffer, s32 s32MaxRespBuffLen, s32 *ps32Bytes return s32Error; } -/** - * @brief sends certain Configuration Packet based on the input WIDs pstrWIDs - * and retrieves the packet response pu8RxResp - * @details - * @param[in] pstrWIDs WIDs to be sent in the configuration packet - * @param[in] u32WIDsCount number of WIDs to be sent in the configuration packet - * @param[out] pu8RxResp The received Packet Response - * @param[out] ps32RxRespLen Length of the received Packet Response - * @return Error code indicating success/failure - * @note - * @author mabubakr - * @date 1 Mar 2012 - * @version 1.0 - */ -#ifdef SIMULATION -s32 SendConfigPkt(u8 u8Mode, tstrWID *pstrWIDs, - u32 u32WIDsCount, bool bRespRequired, u32 drvHandler) -{ - s32 s32Error = WILC_SUCCESS; - s32 err = WILC_SUCCESS; - s32 s32ConfigPacketLen = 0; - s32 s32RcvdRespLen = 0; - - down(&SemHandleSendPkt); - - /*set the packet mode*/ - g_oper_mode = u8Mode; - - WILC_memset((void *)gps8ConfigPacket, 0, MAX_PACKET_BUFF_SIZE); - - if (CreateConfigPacket(gps8ConfigPacket, &s32ConfigPacketLen, pstrWIDs, u32WIDsCount) != WILC_SUCCESS) { - s32Error = WILC_FAIL; - goto End_ConfigPkt; - } - /*bug 3878*/ - gstrConfigPktInfo.pcRespBuffer = gps8ConfigPacket; - gstrConfigPktInfo.s32MaxRespBuffLen = MAX_PACKET_BUFF_SIZE; - PRINT_INFO(CORECONFIG_DBG, "GLOBAL =bRespRequired =%d\n", bRespRequired); - gstrConfigPktInfo.bRespRequired = bRespRequired; - - s32Error = SendRawPacket(gps8ConfigPacket, s32ConfigPacketLen); - if (s32Error != WILC_SUCCESS) { - goto End_ConfigPkt; - } - - WILC_memset((void *)gps8ConfigPacket, 0, MAX_PACKET_BUFF_SIZE); - - ConfigWaitResponse(gps8ConfigPacket, MAX_PACKET_BUFF_SIZE, &s32RcvdRespLen, bRespRequired); - - - if (bRespRequired) { - /* If the operating Mode is GET, then we expect a response frame from */ - /* the driver. Hence start listening to the port for response */ - if (g_oper_mode == GET_CFG) { - #if 1 - err = ParseResponse(gps8ConfigPacket, pstrWIDs); - if (err != 0) { - s32Error = WILC_FAIL; - goto End_ConfigPkt; - } else { - s32Error = WILC_SUCCESS; - } - #endif - } else { - err = ParseWriteResponse(gps8ConfigPacket); - if (err != WRITE_RESP_SUCCESS) { - s32Error = WILC_FAIL; - goto End_ConfigPkt; - } else { - s32Error = WILC_SUCCESS; - } - } - - - } - - -End_ConfigPkt: - up(&SemHandleSendPkt); - - return s32Error; -} -#endif s32 ConfigProvideResponse(char *pcRespBuffer, s32 s32RespLen) { s32 s32Error = WILC_SUCCESS; @@ -2052,8 +1969,6 @@ s32 CoreConfiguratorDeInit(void) return s32Error; } - -#ifndef SIMULATION /*Using the global handle of the driver*/ extern wilc_wlan_oup_t *gpstrWlanOps; /** @@ -2127,4 +2042,3 @@ s32 SendConfigPkt(u8 u8Mode, tstrWID *pstrWIDs, return ret; } -#endif diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index c089e739465a..02aaf39bf28d 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -570,9 +570,7 @@ static u8 gs8GetIP[2][4]; static u32 gu32InactiveTime; static u8 gu8DelBcn; #endif -#ifndef SIMULATION static u32 gu32WidConnRstHack; -#endif /*BugID_5137*/ u8 *gu8FlushedJoinReq; @@ -1626,14 +1624,12 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon strWIDList[u32WidsCount].ps8WidVal = (s8 *)&u8bssDscListIndex; u32WidsCount++; - #ifndef SIMULATION /* A temporary workaround to avoid handling the misleading MAC_DISCONNECTED raised from the * firmware at chip reset when processing the WIDs of the Connect Request. * (This workaround should be removed in the future when the Chip reset of the Connect WIDs is disabled) */ /* ////////////////////// */ gu32WidConnRstHack = 0; /* ////////////////////// */ - #endif s32Error = SendConfigPkt(SET_CFG, strWIDList, u32WidsCount, false, (u32)pstrWFIDrv); if (s32Error) { @@ -1936,14 +1932,12 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon #endif /* #ifdef WILC_PARSE_SCAN_IN_HOST*/ u32WidsCount++; - #ifndef SIMULATION /* A temporary workaround to avoid handling the misleading MAC_DISCONNECTED raised from the * firmware at chip reset when processing the WIDs of the Connect Request. * (This workaround should be removed in the future when the Chip reset of the Connect WIDs is disabled) */ /* ////////////////////// */ gu32WidConnRstHack = 0; /* ////////////////////// */ - #endif /*BugID_5137*/ if (WILC_memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) { @@ -6586,12 +6580,6 @@ s32 host_int_init(WILC_WFIDrvHandle *phWFIDrv) sema_init(&(pstrWFIDrv->gtOsCfgValuesSem), 1); down(&(pstrWFIDrv->gtOsCfgValuesSem)); - - -#ifdef SIMULATION - TransportInit(); -#endif - pstrWFIDrv->enuHostIFstate = HOST_IF_IDLE; /* gWFiDrvHandle->bPendingConnRequest = false; */ @@ -6627,11 +6615,6 @@ s32 host_int_init(WILC_WFIDrvHandle *phWFIDrv) goto _fail_mem_; } -#ifdef SIMULATION - /*Initialize Simulaor*/ - CoreConfigSimulatorInit(); -#endif - u32Intialized = 1; clients_count++; /* increase number of created entities */ @@ -6731,13 +6714,7 @@ s32 host_int_deinit(WILC_WFIDrvHandle hWFIDrv) pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult = NULL; } /*deinit configurator and simulator*/ -#ifdef SIMULATION - CoreConfigSimulatorDeInit(); -#endif CoreConfiguratorDeInit(); -#ifdef SIMULATION - TransportDeInit(); -#endif pstrWFIDrv->enuHostIFstate = HOST_IF_IDLE; diff --git a/drivers/staging/wilc1000/linux_mon.c b/drivers/staging/wilc1000/linux_mon.c index d812a3b194f3..aa20421021fa 100644 --- a/drivers/staging/wilc1000/linux_mon.c +++ b/drivers/staging/wilc1000/linux_mon.c @@ -6,20 +6,15 @@ * @date 01 MAR 2012 * @version 1.0 */ - -#ifndef SIMULATION #include "wilc_wfi_cfgoperations.h" #include "linux_wlan_common.h" #include "wilc_wlan_if.h" #include "wilc_wlan.h" -#endif + #ifdef WILC_FULLY_HOSTING_AP #include "wilc_host_ap.h" #endif #ifdef WILC_AP_EXTERNAL_MLME -#ifdef SIMULATION -#include "wilc_wfi_cfgoperations.h" -#endif struct wilc_wfi_radiotap_hdr { struct ieee80211_radiotap_header hdr; @@ -39,9 +34,7 @@ extern linux_wlan_t *g_linux_wlan; static struct net_device *wilc_wfi_mon; /* global monitor netdev */ -#ifdef SIMULATION -extern int WILC_WFI_Tx(struct sk_buff *skb, struct net_device *dev); -#elif USE_WIRELESS +#if USE_WIRELESS extern int mac_xmit(struct sk_buff *skb, struct net_device *dev); #endif @@ -374,9 +367,7 @@ static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb, PRINT_INFO(HOSTAPD_DBG, "SKB netdevice name = %s\n", skb->dev->name); PRINT_INFO(HOSTAPD_DBG, "MONITOR real dev name = %s\n", mon_priv->real_ndev->name); - #ifdef SIMULATION - ret = WILC_WFI_Tx(skb, mon_priv->real_ndev); - #elif USE_WIRELESS + #if USE_WIRELESS /* Identify if Ethernet or MAC header (data or mgmt) */ memcpy(srcAdd, &skb->data[10], 6); memcpy(bssid, &skb->data[16], 6); diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 5a794df0da4d..10ea53a60a06 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -1,4 +1,3 @@ -#ifndef SIMULATION #include "wilc_wfi_cfgoperations.h" #include "linux_wlan_common.h" #include "wilc_wlan_if.h" @@ -2778,4 +2777,3 @@ static void __exit exit_wilc_driver(void) module_exit(exit_wilc_driver); MODULE_LICENSE("GPL"); -#endif diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 1d0b7f87b100..c2ef46f4740b 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -2875,7 +2875,6 @@ static int WILC_WFI_change_virt_intf(struct wiphy *wiphy, struct net_device *dev /*Remove the enteries of the previously connected clients*/ memset(priv->assoc_stainfo.au8Sta_AssociatedBss, 0, MAX_NUM_STA * ETH_ALEN); - #ifndef SIMULATION #ifdef WILC_P2P interface_type = nic->iftype; nic->iftype = STATION_MODE; @@ -2953,7 +2952,6 @@ static int WILC_WFI_change_virt_intf(struct wiphy *wiphy, struct net_device *dev host_int_set_power_mgmt(priv->hWILCWFIDrv, 1, 0); } #endif - #endif break; case NL80211_IFTYPE_P2P_CLIENT: @@ -2968,7 +2966,6 @@ static int WILC_WFI_change_virt_intf(struct wiphy *wiphy, struct net_device *dev priv->wdev->iftype = type; nic->monitor_flag = 0; - #ifndef SIMULATION #ifdef WILC_P2P PRINT_D(HOSTAPD_DBG, "Downloading P2P_CONCURRENCY_FIRMWARE\n"); @@ -3042,7 +3039,6 @@ static int WILC_WFI_change_virt_intf(struct wiphy *wiphy, struct net_device *dev } } #endif - #endif break; case NL80211_IFTYPE_AP: @@ -3053,7 +3049,6 @@ static int WILC_WFI_change_virt_intf(struct wiphy *wiphy, struct net_device *dev nic->iftype = AP_MODE; PRINT_D(CORECONFIG_DBG, "priv->hWILCWFIDrv[%p]\n", priv->hWILCWFIDrv); - #ifndef SIMULATION PRINT_D(HOSTAPD_DBG, "Downloading AP firmware\n"); linux_wlan_get_firmware(nic); #ifdef WILC_P2P @@ -3075,7 +3070,6 @@ static int WILC_WFI_change_virt_intf(struct wiphy *wiphy, struct net_device *dev } } #endif - #endif break; case NL80211_IFTYPE_P2P_GO: @@ -3099,7 +3093,6 @@ static int WILC_WFI_change_virt_intf(struct wiphy *wiphy, struct net_device *dev PRINT_D(CORECONFIG_DBG, "priv->hWILCWFIDrv[%p]\n", priv->hWILCWFIDrv); - #ifndef SIMULATION #ifdef WILC_P2P PRINT_D(HOSTAPD_DBG, "Downloading P2P_CONCURRENCY_FIRMWARE\n"); @@ -3174,7 +3167,6 @@ static int WILC_WFI_change_virt_intf(struct wiphy *wiphy, struct net_device *dev } } #endif - #endif break; default: @@ -3570,13 +3562,8 @@ struct wireless_dev *WILC_WFI_add_virt_intf(struct wiphy *wiphy, const char *nam new_ifc = WILC_WFI_init_mon_interface(name, nic->wilc_netdev); if (new_ifc != NULL) { PRINT_D(HOSTAPD_DBG, "Setting monitor flag in private structure\n"); - #ifdef SIMULATION - priv = netdev_priv(priv->wdev->netdev); - priv->monitor_flag = 1; - #else nic = netdev_priv(priv->wdev->netdev); nic->monitor_flag = 1; - #endif } else PRINT_ER("Error in initializing monitor interface\n "); } -- cgit v1.3-6-gb490 From 0dff54785f92f832663d2af77cdd5b198fd90bb6 Mon Sep 17 00:00:00 2001 From: Tony Cho Date: Tue, 28 Jul 2015 17:47:23 +0900 Subject: staging: wilc1000: remove warnings on the multiple line uses This patch removes the warnings reported by checkpatch.pl for using multiple blank lines. Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_sdio.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c index 897e47e317ff..632b2b081fc6 100644 --- a/drivers/staging/wilc1000/wilc_sdio.c +++ b/drivers/staging/wilc1000/wilc_sdio.c @@ -10,7 +10,6 @@ #include "wilc_wlan_if.h" #include "wilc_wlan.h" - #ifdef WILC1000_SINGLE_TRANSFER #define WILC_SDIO_BLOCK_SIZE 256 #else @@ -90,7 +89,6 @@ static int sdio_set_func0_csa_address_byte0(uint32_t adr) { sdio_cmd52_t cmd; - /** * Review: BIG ENDIAN **/ @@ -222,8 +220,6 @@ uint32_t sdio_xfer_cnt(void) cnt |= (cmd.data << 16); return cnt; - - } /******************************************** @@ -412,7 +408,6 @@ static int sdio_write(uint32_t addr, uint8_t *buf, uint32_t size) } - if (rest > 0) { cmd.block_mode = 1; cmd.increment = 1; @@ -458,7 +453,6 @@ static int sdio_write(uint32_t addr, uint8_t *buf, uint32_t size) #endif /* platform */ } - if (nleft > 0) { cmd.block_mode = 0; cmd.increment = 1; @@ -622,7 +616,6 @@ static int sdio_read(uint32_t addr, uint8_t *buf, uint32_t size) cmd.buffer = buf; cmd.block_size = block_size; - if (addr > 0) { if (!sdio_set_func0_csa_address(addr)) goto _fail_; @@ -639,7 +632,6 @@ static int sdio_read(uint32_t addr, uint8_t *buf, uint32_t size) } - if (rest > 0) { cmd.block_mode = 1; cmd.increment = 1; @@ -898,7 +890,6 @@ static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func) } g_sdio.dPrint(N_ERR, "[wilc sdio]: has_thrpt_enh3 = %d...\n", g_sdio.has_thrpt_enh3); - return 1; _fail_: @@ -1097,7 +1088,6 @@ static int sdio_clear_int_ext(uint32_t val) } #endif /* WILC_SDIO_IRQ_GPIO */ - { uint32_t vmm_ctl; @@ -1138,7 +1128,6 @@ static int sdio_sync_ext(int nint /* how mant interrupts to enable. */) { uint32_t reg; - if (nint > MAX_NUM_INT) { g_sdio.dPrint(N_ERR, "[wilc sdio]: Too many interupts (%d)...\n", nint); return 0; @@ -1148,7 +1137,6 @@ static int sdio_sync_ext(int nint /* how mant interrupts to enable. */) return 0; } - g_sdio.nint = nint; /** @@ -1170,7 +1158,6 @@ static int sdio_sync_ext(int nint /* how mant interrupts to enable. */) uint32_t reg; int ret, i; - /** * interrupt pin mux select **/ @@ -1225,7 +1212,6 @@ static int sdio_sync_ext(int nint /* how mant interrupts to enable. */) return 1; } - /******************************************** * * Global sdio HIF function table -- cgit v1.3-6-gb490 From 9c844693eaf31eb8587a3bba37bbc8601ac4e5ca Mon Sep 17 00:00:00 2001 From: Tony Cho Date: Tue, 28 Jul 2015 17:47:24 +0900 Subject: staging: wilc1000: remove the warnings on missing blank line This patch removes the warnings reported by checkpatch.pl on missing a blank line after declaration. Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_sdio.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c index 632b2b081fc6..6e865d417efb 100644 --- a/drivers/staging/wilc1000/wilc_sdio.c +++ b/drivers/staging/wilc1000/wilc_sdio.c @@ -168,6 +168,7 @@ static int sdio_clear_int(void) #ifndef WILC_SDIO_IRQ_GPIO /* uint32_t sts; */ sdio_cmd52_t cmd; + cmd.read_write = 0; cmd.function = 1; cmd.raw = 0; @@ -179,6 +180,7 @@ static int sdio_clear_int(void) return cmd.data; #else uint32_t reg; + if (!sdio_read_reg(WILC_HOST_RX_CTRL_0, ®)) { g_sdio.dPrint(N_ERR, "[wilc spi]: Failed read reg (%08x)...\n", WILC_HOST_RX_CTRL_0); return 0; @@ -195,6 +197,7 @@ uint32_t sdio_xfer_cnt(void) { uint32_t cnt = 0; sdio_cmd52_t cmd; + cmd.read_write = 0; cmd.function = 1; cmd.raw = 0; @@ -259,6 +262,7 @@ static int sdio_write_reg(uint32_t addr, uint32_t data) if ((addr >= 0xf0) && (addr <= 0xff)) { sdio_cmd52_t cmd; + cmd.read_write = 1; cmd.function = 0; cmd.raw = 0; @@ -482,6 +486,7 @@ static int sdio_read_reg(uint32_t addr, uint32_t *data) { if ((addr >= 0xf0) && (addr <= 0xff)) { sdio_cmd52_t cmd; + cmd.read_write = 0; cmd.function = 0; cmd.raw = 0; @@ -776,6 +781,7 @@ static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func) sdio_cmd52_t cmd; int loop; uint32_t chipid; + memset(&g_sdio, 0, sizeof(wilc_sdio_t)); g_sdio.dPrint = func; @@ -977,6 +983,7 @@ static int sdio_read_int(uint32_t *int_status) } { int i; + for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { if ((tmp >> (IRG_FLAGS_OFFSET + i)) & 0x1) { g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt (1) : tmp=%x, data=%x\n", tmp, cmd.data); @@ -1015,6 +1022,7 @@ static int sdio_clear_int_ext(uint32_t val) #ifdef WILC_SDIO_IRQ_GPIO { uint32_t flags; + flags = val & ((1 << MAX_NUN_INT_THRPT_ENH2) - 1); reg = flags; } @@ -1032,6 +1040,7 @@ static int sdio_clear_int_ext(uint32_t val) reg |= (1 << 7); if (reg) { sdio_cmd52_t cmd; + cmd.read_write = 1; cmd.function = 0; cmd.raw = 0; @@ -1051,6 +1060,7 @@ static int sdio_clear_int_ext(uint32_t val) /* see below. has_thrpt_enh2 uses register 0xf8 to clear interrupts. */ /* Cannot clear multiple interrupts. Must clear each interrupt individually */ uint32_t flags; + flags = val & ((1 << MAX_NUM_INT) - 1); if (flags) { int i; @@ -1059,6 +1069,7 @@ static int sdio_clear_int_ext(uint32_t val) for (i = 0; i < g_sdio.nint; i++) { if (flags & 1) { sdio_cmd52_t cmd; + cmd.read_write = 1; cmd.function = 0; cmd.raw = 0; -- cgit v1.3-6-gb490 From 4aa85772e3fa98646ce3b2a18b12c6474b853104 Mon Sep 17 00:00:00 2001 From: Tony Cho Date: Tue, 28 Jul 2015 17:47:25 +0900 Subject: staging: wilc1000: remove the warnings on unnecessary braces This patch removes the warnings reported by checkpatch.pl on {} not necessary for the single statement blocks. Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_sdio.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c index 6e865d417efb..967df95a4e02 100644 --- a/drivers/staging/wilc1000/wilc_sdio.c +++ b/drivers/staging/wilc1000/wilc_sdio.c @@ -106,6 +106,7 @@ static int sdio_set_func0_csa_address_byte0(uint32_t adr) _fail_: return 0; } + static int sdio_set_func0_block_size(uint32_t block_size) { sdio_cmd52_t cmd; @@ -963,24 +964,18 @@ static int sdio_read_int(uint32_t *int_status) cmd.data = 0; g_sdio.sdio_cmd52(&cmd); - if (cmd.data & (1 << 0)) { + if (cmd.data & (1 << 0)) tmp |= INT_0; - } - if (cmd.data & (1 << 2)) { + if (cmd.data & (1 << 2)) tmp |= INT_1; - } - if (cmd.data & (1 << 3)) { + if (cmd.data & (1 << 3)) tmp |= INT_2; - } - if (cmd.data & (1 << 4)) { + if (cmd.data & (1 << 4)) tmp |= INT_3; - } - if (cmd.data & (1 << 5)) { + if (cmd.data & (1 << 5)) tmp |= INT_4; - } - if (cmd.data & (1 << 6)) { + if (cmd.data & (1 << 6)) tmp |= INT_5; - } { int i; @@ -1087,9 +1082,8 @@ static int sdio_clear_int_ext(uint32_t val) break; flags >>= 1; } - if (!ret) { + if (!ret) goto _fail_; - } for (i = g_sdio.nint; i < MAX_NUM_INT; i++) { if (flags & 1) g_sdio.dPrint(N_ERR, "[wilc sdio]: Unexpected interrupt cleared %d...\n", i); @@ -1193,9 +1187,8 @@ static int sdio_sync_ext(int nint /* how mant interrupts to enable. */) return 0; } - for (i = 0; (i < 5) && (nint > 0); i++, nint--) { + for (i = 0; (i < 5) && (nint > 0); i++, nint--) reg |= (1 << (27 + i)); - } ret = sdio_write_reg(WILC_INTR_ENABLE, reg); if (!ret) { g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed write reg (%08x)...\n", WILC_INTR_ENABLE); @@ -1208,9 +1201,8 @@ static int sdio_sync_ext(int nint /* how mant interrupts to enable. */) return 0; } - for (i = 0; (i < 3) && (nint > 0); i++, nint--) { + for (i = 0; (i < 3) && (nint > 0); i++, nint--) reg |= (1 << i); - } ret = sdio_read_reg(WILC_INTR2_ENABLE, ®); if (!ret) { -- cgit v1.3-6-gb490 From 229d7402bd8ffc58cacc22115011693257c21215 Mon Sep 17 00:00:00 2001 From: Tony Cho Date: Tue, 28 Jul 2015 17:47:26 +0900 Subject: staging: wilc1000: remove preprocessor conditionals unused This patch removes unused preprocessor conditionals for the PLAT_AML8726_M3_BACKUP and PLAT_AML8726_M3 which are not used and so dead codes. They are also platform-dependent codes. Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_sdio.c | 174 +---------------------------------- 1 file changed, 1 insertion(+), 173 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c index 967df95a4e02..ea545c9bf935 100644 --- a/drivers/staging/wilc1000/wilc_sdio.c +++ b/drivers/staging/wilc1000/wilc_sdio.c @@ -13,12 +13,7 @@ #ifdef WILC1000_SINGLE_TRANSFER #define WILC_SDIO_BLOCK_SIZE 256 #else - #if defined(PLAT_AML8726_M3) /* johnny */ - #define WILC_SDIO_BLOCK_SIZE 512 - #define MAX_SEG_SIZE (1 << 12) /* 4096 */ - #else - #define WILC_SDIO_BLOCK_SIZE 512 - #endif +#define WILC_SDIO_BLOCK_SIZE 512 #endif typedef struct { @@ -356,88 +351,6 @@ static int sdio_write(uint32_t addr, uint8_t *buf, uint32_t size) nleft = size % block_size; if (nblk > 0) { - -#if defined(PLAT_AML8726_M3_BACKUP) /* johnny */ - int i; - - for (i = 0; i < nblk; i++) { - cmd.block_mode = 0; /* 1; */ - cmd.increment = 1; - cmd.count = block_size; /* nblk; */ - cmd.buffer = buf; - cmd.block_size = block_size; - if (addr > 0) { - if (!sdio_set_func0_csa_address(addr)) - goto _fail_; - } - if (!g_sdio.sdio_cmd53(&cmd)) { - g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block send...\n", addr); - goto _fail_; - } - - if (addr > 0) - addr += block_size; /* addr += nblk*block_size; */ - - buf += block_size; /* buf += nblk*block_size; */ - } - -#elif defined(PLAT_AML8726_M3) /* johnny */ - - int i; - int rest; - int seg_cnt; - - seg_cnt = (nblk * block_size) / MAX_SEG_SIZE; - rest = (nblk * block_size) & (MAX_SEG_SIZE - 1); - - for (i = 0; i < seg_cnt; i++) { - cmd.block_mode = 1; - cmd.increment = 1; - cmd.count = MAX_SEG_SIZE / block_size; - cmd.buffer = buf; - cmd.block_size = block_size; - - if (addr > 0) { - if (!sdio_set_func0_csa_address(addr)) - goto _fail_; - } - if (!g_sdio.sdio_cmd53(&cmd)) { - g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block send...\n", addr); - goto _fail_; - } - - if (addr > 0) - addr += MAX_SEG_SIZE; - - buf += MAX_SEG_SIZE; - - } - - if (rest > 0) { - cmd.block_mode = 1; - cmd.increment = 1; - cmd.count = rest / block_size; - cmd.buffer = buf; - cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */ - - if (addr > 0) { - if (!sdio_set_func0_csa_address(addr)) - goto _fail_; - } - if (!g_sdio.sdio_cmd53(&cmd)) { - g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], bytes send...\n", addr); - goto _fail_; - } - - if (addr > 0) - addr += rest; - - buf += rest; - - } - -#else - cmd.block_mode = 1; cmd.increment = 1; cmd.count = nblk; @@ -454,8 +367,6 @@ static int sdio_write(uint32_t addr, uint8_t *buf, uint32_t size) if (addr > 0) addr += nblk * block_size; buf += nblk * block_size; - -#endif /* platform */ } if (nleft > 0) { @@ -582,87 +493,6 @@ static int sdio_read(uint32_t addr, uint8_t *buf, uint32_t size) nleft = size % block_size; if (nblk > 0) { - -#if defined(PLAT_AML8726_M3_BACKUP) /* johnny */ - - int i; - - for (i = 0; i < nblk; i++) { - cmd.block_mode = 0; /* 1; */ - cmd.increment = 1; - cmd.count = block_size; /* nblk; */ - cmd.buffer = buf; - cmd.block_size = block_size; - if (addr > 0) { - if (!sdio_set_func0_csa_address(addr)) - goto _fail_; - } - if (!g_sdio.sdio_cmd53(&cmd)) { - g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block read...\n", addr); - goto _fail_; - } - if (addr > 0) - addr += block_size; /* addr += nblk*block_size; */ - buf += block_size; /* buf += nblk*block_size; */ - } - -#elif defined(PLAT_AML8726_M3) /* johnny */ - - int i; - int rest; - int seg_cnt; - - seg_cnt = (nblk * block_size) / MAX_SEG_SIZE; - rest = (nblk * block_size) & (MAX_SEG_SIZE - 1); - - for (i = 0; i < seg_cnt; i++) { - cmd.block_mode = 1; - cmd.increment = 1; - cmd.count = MAX_SEG_SIZE / block_size; - cmd.buffer = buf; - cmd.block_size = block_size; - - if (addr > 0) { - if (!sdio_set_func0_csa_address(addr)) - goto _fail_; - } - if (!g_sdio.sdio_cmd53(&cmd)) { - g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block read...\n", addr); - goto _fail_; - } - - if (addr > 0) - addr += MAX_SEG_SIZE; - - buf += MAX_SEG_SIZE; - - } - - if (rest > 0) { - cmd.block_mode = 1; - cmd.increment = 1; - cmd.count = rest / block_size; - cmd.buffer = buf; - cmd.block_size = block_size; /* johnny : prevent it from setting unexpected value */ - - if (addr > 0) { - if (!sdio_set_func0_csa_address(addr)) - goto _fail_; - } - if (!g_sdio.sdio_cmd53(&cmd)) { - g_sdio.dPrint(N_ERR, "[wilc sdio]: Failed cmd53 [%x], block read...\n", addr); - goto _fail_; - } - - if (addr > 0) - addr += rest; - - buf += rest; - - } - -#else - cmd.block_mode = 1; cmd.increment = 1; cmd.count = nblk; @@ -679,8 +509,6 @@ static int sdio_read(uint32_t addr, uint8_t *buf, uint32_t size) if (addr > 0) addr += nblk * block_size; buf += nblk * block_size; - -#endif /* platform */ } /* if (nblk > 0) */ if (nleft > 0) { -- cgit v1.3-6-gb490 From 51a5fcaf718788b11e767640dc65c40f409de1a8 Mon Sep 17 00:00:00 2001 From: Tony Cho Date: Tue, 28 Jul 2015 17:47:27 +0900 Subject: staging: wilc1000: remove a dead preprocessor conditionals This patch removes the preprocessor conditionals which are related to the WILC1000_SINGLE_TRANSFER definition becasue this is not used. Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_sdio.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c index ea545c9bf935..8f674adbdfee 100644 --- a/drivers/staging/wilc1000/wilc_sdio.c +++ b/drivers/staging/wilc1000/wilc_sdio.c @@ -10,11 +10,7 @@ #include "wilc_wlan_if.h" #include "wilc_wlan.h" -#ifdef WILC1000_SINGLE_TRANSFER -#define WILC_SDIO_BLOCK_SIZE 256 -#else #define WILC_SDIO_BLOCK_SIZE 512 -#endif typedef struct { void *os_context; @@ -321,16 +317,6 @@ static int sdio_write(uint32_t addr, uint8_t *buf, uint32_t size) cmd.function = 0; cmd.address = 0x10f; } else { -#ifdef WILC1000_SINGLE_TRANSFER - /** - * has to be block aligned... - **/ - nleft = size % block_size; - if (nleft > 0) { - size += block_size; - size &= ~(block_size - 1); - } -#else /** * has to be word aligned... **/ @@ -338,7 +324,6 @@ static int sdio_write(uint32_t addr, uint8_t *buf, uint32_t size) size += 4; size &= ~0x3; } -#endif /** * func 1 access @@ -463,16 +448,6 @@ static int sdio_read(uint32_t addr, uint8_t *buf, uint32_t size) cmd.function = 0; cmd.address = 0x10f; } else { -#ifdef WILC1000_SINGLE_TRANSFER - /** - * has to be block aligned... - **/ - nleft = size % block_size; - if (nleft > 0) { - size += block_size; - size &= ~(block_size - 1); - } -#else /** * has to be word aligned... **/ @@ -480,7 +455,6 @@ static int sdio_read(uint32_t addr, uint8_t *buf, uint32_t size) size += 4; size &= ~0x3; } -#endif /** * func 1 access -- cgit v1.3-6-gb490 From 232ced3d8fde6221231d5d541326cdb5e7afc50a Mon Sep 17 00:00:00 2001 From: "Jude.Lee" Date: Tue, 28 Jul 2015 17:47:30 +0900 Subject: staging: wilc1000: remove multiple blank lines This patch removes the warnings reported by checkpatch.pl for using multiple blank lines. Signed-off-by: Jude.Lee Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/coreconfigurator.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/coreconfigurator.h b/drivers/staging/wilc1000/coreconfigurator.h index 9059c8df7ce5..3b4b01b26dd0 100644 --- a/drivers/staging/wilc1000/coreconfigurator.h +++ b/drivers/staging/wilc1000/coreconfigurator.h @@ -8,7 +8,6 @@ * @version 1.0 */ - #ifndef CORECONFIGURATOR_H #define CORECONFIGURATOR_H @@ -42,7 +41,6 @@ extern u16 g_num_total_switches; #define AID_LEN 2 #define IE_HDR_LEN 2 - /* Operating Mode: SET */ #define SET_CFG 0 /* Operating Mode: GET */ @@ -59,15 +57,12 @@ extern u16 g_num_total_switches; #define MAC_CONNECTED 1 #define MAC_DISCONNECTED 0 - - /*****************************************************************************/ /* Function Macros */ /*****************************************************************************/ #define MAKE_WORD16(lsb, msb) ((((u16)(msb) << 8) & 0xFF00) | (lsb)) #define MAKE_WORD32(lsw, msw) ((((u32)(msw) << 16) & 0xFFFF0000) | (lsw)) - /*****************************************************************************/ /* Type Definitions */ /*****************************************************************************/ @@ -140,7 +135,6 @@ typedef struct { u16 u16RespIEsLen; } tstrConnectRespInfo; - typedef struct { u8 au8bssid[6]; u8 *pu8ReqIEs; @@ -150,8 +144,6 @@ typedef struct { u16 u16ConnectStatus; } tstrConnectInfo; - - typedef struct { u16 u16reason; u8 *ie; -- cgit v1.3-6-gb490 From 1e553d542bf9bb4bfb39ba6f130e2b62a356db57 Mon Sep 17 00:00:00 2001 From: "Jude.Lee" Date: Tue, 28 Jul 2015 17:47:31 +0900 Subject: staging: wilc1000: alignment should match open parenthesis This patch fixes the checks reported by checkpatch.pl alignment should match open parenthesis Signed-off-by: Jude.Lee Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/coreconfigurator.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/coreconfigurator.h b/drivers/staging/wilc1000/coreconfigurator.h index 3b4b01b26dd0..56ff2ba139ed 100644 --- a/drivers/staging/wilc1000/coreconfigurator.h +++ b/drivers/staging/wilc1000/coreconfigurator.h @@ -167,17 +167,18 @@ extern s32 CoreConfiguratorInit(void); extern s32 CoreConfiguratorDeInit(void); extern s32 SendConfigPkt(u8 u8Mode, tstrWID *pstrWIDs, - u32 u32WIDsCount, bool bRespRequired, u32 drvHandler); + u32 u32WIDsCount, bool bRespRequired, u32 drvHandler); extern s32 ParseNetworkInfo(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo); extern s32 DeallocateNetworkInfo(tstrNetworkInfo *pstrNetworkInfo); extern s32 ParseAssocRespInfo(u8 *pu8Buffer, u32 u32BufferLen, - tstrConnectRespInfo **ppstrConnectRespInfo); + tstrConnectRespInfo **ppstrConnectRespInfo); extern s32 DeallocateAssocRespInfo(tstrConnectRespInfo *pstrConnectRespInfo); #ifndef CONNECT_DIRECT extern s32 ParseSurveyResults(u8 ppu8RcvdSiteSurveyResults[][MAX_SURVEY_RESULT_FRAG_SIZE], - wid_site_survey_reslts_s **ppstrSurveyResults, u32 *pu32SurveyResultsCount); + wid_site_survey_reslts_s **ppstrSurveyResults, + u32 *pu32SurveyResultsCount); extern s32 DeallocateSurveyResults(wid_site_survey_reslts_s *pstrSurveyResults); #endif -- cgit v1.3-6-gb490 From a0261e0b136b3535a5940179bdb95a8cc89eebd5 Mon Sep 17 00:00:00 2001 From: Tony Cho Date: Tue, 28 Jul 2015 17:47:33 +0900 Subject: staging: wilc1000: remove warnings on unnecessary braces This patch removes the warnings reported by checkpatch.pl on the braces {} not necessary for any arm of this statement. Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_sdio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c index 8f674adbdfee..fd87add7c4cb 100644 --- a/drivers/staging/wilc1000/wilc_sdio.c +++ b/drivers/staging/wilc1000/wilc_sdio.c @@ -692,11 +692,10 @@ static int sdio_init(wilc_wlan_inp_t *inp, wilc_debug_func func) goto _fail_; } g_sdio.dPrint(N_ERR, "[wilc sdio]: chipid (%08x)\n", chipid); - if ((chipid & 0xfff) > 0x2a0) { + if ((chipid & 0xfff) > 0x2a0) g_sdio.has_thrpt_enh3 = 1; - } else { + else g_sdio.has_thrpt_enh3 = 0; - } g_sdio.dPrint(N_ERR, "[wilc sdio]: has_thrpt_enh3 = %d...\n", g_sdio.has_thrpt_enh3); return 1; -- cgit v1.3-6-gb490 From 202f66a8169a2ab8c92656914867d56ff6510a44 Mon Sep 17 00:00:00 2001 From: Tony Cho Date: Tue, 28 Jul 2015 17:47:35 +0900 Subject: staging: wilc1000: remove unnecessary inner braces This patch removes unnecessary inner braces. Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_sdio.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c index fd87add7c4cb..5a18148a593e 100644 --- a/drivers/staging/wilc1000/wilc_sdio.c +++ b/drivers/staging/wilc1000/wilc_sdio.c @@ -724,23 +724,21 @@ static int sdio_read_size(uint32_t *size) /** * Read DMA count in words **/ - { - cmd.read_write = 0; - cmd.function = 0; - cmd.raw = 0; - cmd.address = 0xf2; - cmd.data = 0; - g_sdio.sdio_cmd52(&cmd); - tmp = cmd.data; + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = 0xf2; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + tmp = cmd.data; - /* cmd.read_write = 0; */ - /* cmd.function = 0; */ - /* cmd.raw = 0; */ - cmd.address = 0xf3; - cmd.data = 0; - g_sdio.sdio_cmd52(&cmd); - tmp |= (cmd.data << 8); - } + /* cmd.read_write = 0; */ + /* cmd.function = 0; */ + /* cmd.raw = 0; */ + cmd.address = 0xf3; + cmd.data = 0; + g_sdio.sdio_cmd52(&cmd); + tmp |= (cmd.data << 8); *size = tmp; return 1; -- cgit v1.3-6-gb490 From fc4b95d69c603668331d1edb92e3fb0dbcb1d959 Mon Sep 17 00:00:00 2001 From: "Kim, Leo" Date: Tue, 28 Jul 2015 17:47:37 +0900 Subject: staging: wilc1000: remove braces {} for single statement blocks This patch removes the warnings reported by checkpatch.pl on braces {} not necessary for the single statement blocks. Signed-off-by: Kim, Leo Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/linux_wlan.c | 78 ++++++++++++----------------------- 1 file changed, 26 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 10ea53a60a06..a4589b799db9 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -207,9 +207,8 @@ void printk_later(const char *format, ...) va_start (args, format); ps8current += vsprintf (ps8current, format, args); va_end (args); - if ((ps8current - DebugBuffer) > DEGUG_BUFFER_LENGTH) { + if ((ps8current - DebugBuffer) > DEGUG_BUFFER_LENGTH) ps8current = DebugBuffer; - } } @@ -779,9 +778,8 @@ struct net_device *GetIfHandler(uint8_t *pMacHeader) } } PRINT_INFO(INIT_DBG, "Invalide handle\n"); - for (i = 0; i < 25; i++) { + for (i = 0; i < 25; i++) PRINT_D(INIT_DBG, "%02x ", pMacHeader[i]); - } Bssid = pMacHeader + 18; Bssid1 = pMacHeader + 12; for (i = 0; i < g_linux_wlan->u8NoIfcs; i++) { @@ -821,9 +819,8 @@ int linux_wlan_get_num_conn_ifcs(void) uint8_t ret_val = 0; for (i = 0; i < g_linux_wlan->u8NoIfcs; i++) { - if (memcmp(g_linux_wlan->strInterfaceInfo[i].aBSSID, null_bssid, 6)) { + if (memcmp(g_linux_wlan->strInterfaceInfo[i].aBSSID, null_bssid, 6)) ret_val++; - } } return ret_val; } @@ -912,15 +909,13 @@ static int linux_wlan_txq_task(void *vp) msleep(TX_BACKOFF_WEIGHT_UNIT_MS << backoff_weight); } while (/*timeout*/ 0); backoff_weight += TX_BACKOFF_WEIGHT_INCR_STEP; - if (backoff_weight > TX_BACKOFF_WEIGHT_MAX) { + if (backoff_weight > TX_BACKOFF_WEIGHT_MAX) backoff_weight = TX_BACKOFF_WEIGHT_MAX; - } } else { if (backoff_weight > TX_BACKOFF_WEIGHT_MIN) { backoff_weight -= TX_BACKOFF_WEIGHT_DECR_STEP; - if (backoff_weight < TX_BACKOFF_WEIGHT_MIN) { + if (backoff_weight < TX_BACKOFF_WEIGHT_MIN) backoff_weight = TX_BACKOFF_WEIGHT_MIN; - } } } /*TODO: drop packets after a certain time/number of retry count. */ @@ -1051,9 +1046,8 @@ static int linux_wlan_firmware_download(linux_wlan_t *p_nic) **/ PRINT_D(INIT_DBG, "Downloading Firmware ...\n"); ret = g_linux_wlan->oup.wlan_firmware_download(g_linux_wlan->wilc_firmware->data, g_linux_wlan->wilc_firmware->size); - if (ret < 0) { + if (ret < 0) goto _FAIL_; - } /* Freeing FW buffer */ PRINT_D(INIT_DBG, "Freeing FW buffer ...\n"); @@ -1384,13 +1378,11 @@ void wilc1000_wlan_deinit(linux_wlan_t *nic) /* not sure if the following unlocks are needed or not*/ - if (&g_linux_wlan->rxq_event != NULL) { + if (&g_linux_wlan->rxq_event != NULL) linux_wlan_unlock(&g_linux_wlan->rxq_event); - } - if (&g_linux_wlan->txq_event != NULL) { + if (&g_linux_wlan->txq_event != NULL) linux_wlan_unlock(&g_linux_wlan->txq_event); - } #if (RX_BH_TYPE == RX_BH_WORK_QUEUE) @@ -1744,14 +1736,12 @@ static int linux_wlan_read_mac_addr(void *vp) } } - if (index == array_size) { + if (index == array_size) PRINT_ER("random MAC\n"); - } exit: - if (fp && !IS_ERR(fp)) { + if (fp && !IS_ERR(fp)) filp_close(fp, NULL); - } set_fs(old_fs); @@ -1783,9 +1773,8 @@ uint8_t wilc1000_prepare_11b_core(wilc_wlan_inp_t *nwi, wilc_wlan_oup_t *nwo, li sdio_register_driver(&wilc_bus); - while (!probe) { + while (!probe) msleep(100); - } probe = 0; g_linux_wlan->wilc_sdio_func = local_sdio_func; linux_to_wlan(nwi, nic); @@ -1817,9 +1806,8 @@ int repeat_power_cycle(perInterface_wlan_t *nic) sdio_register_driver(&wilc_bus); /* msleep(1000); */ - while (!probe) { + while (!probe) msleep(100); - } probe = 0; g_linux_wlan->wilc_sdio_func = local_sdio_func; linux_to_wlan(&nwi, g_linux_wlan); @@ -1844,9 +1832,8 @@ int repeat_power_cycle(perInterface_wlan_t *nic) } /* Start firmware*/ ret = linux_wlan_start_firmware(nic); - if (ret < 0) { + if (ret < 0) PRINT_ER("Failed to start firmware\n"); - } __fail__: return ret; } @@ -1868,9 +1855,8 @@ int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic) #ifdef STATIC_MACADDRESS wilc_mac_thread = kthread_run(linux_wlan_read_mac_addr, NULL, "wilc_mac_thread"); - if (wilc_mac_thread < 0) { + if (wilc_mac_thread < 0) PRINT_ER("couldn't create Mac addr thread\n"); - } #endif linux_to_wlan(&nwi, g_linux_wlan); @@ -2234,18 +2220,16 @@ int mac_xmit(struct sk_buff *skb, struct net_device *ndev) tx_data->skb = skb; eth_h = (struct ethhdr *)(skb->data); - if (eth_h->h_proto == 0x8e88) { + if (eth_h->h_proto == 0x8e88) PRINT_D(INIT_DBG, "EAPOL transmitted\n"); - } /*get source and dest ip addresses*/ ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr)); pu8UdpBuffer = (char *)ih + sizeof(struct iphdr); - if ((pu8UdpBuffer[1] == 68 && pu8UdpBuffer[3] == 67) || (pu8UdpBuffer[1] == 67 && pu8UdpBuffer[3] == 68)) { + if ((pu8UdpBuffer[1] == 68 && pu8UdpBuffer[3] == 67) || (pu8UdpBuffer[1] == 67 && pu8UdpBuffer[3] == 68)) PRINT_D(GENERIC_DBG, "DHCP Message transmitted, type:%x %x %x\n", pu8UdpBuffer[248], pu8UdpBuffer[249], pu8UdpBuffer[250]); - } PRINT_D(TX_DBG, "Sending packet - Size = %d - Address = %p - SKB = %p\n", tx_data->size, tx_data->buff, tx_data->skb); /* Send packet to MAC HW - for now the tx_complete function will be just status @@ -2419,9 +2403,8 @@ int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd) done: - if (buff != NULL) { + if (buff != NULL) kfree(buff); - } return s32Error; } @@ -2462,14 +2445,12 @@ void frmw_to_linux(uint8_t *buff, uint32_t size, uint32_t pkt_offset) skb_reserve(skb, (unsigned int)skb->data & 0x3); - if (g_linux_wlan == NULL || wilc_netdev == NULL) { + if (g_linux_wlan == NULL || wilc_netdev == NULL) PRINT_ER("wilc_netdev in g_linux_wlan is NULL"); - } skb->dev = wilc_netdev; - if (skb->dev == NULL) { + if (skb->dev == NULL) PRINT_ER("skb->dev is NULL\n"); - } /* * for(i=0;i<40;i++) @@ -2499,9 +2480,8 @@ void frmw_to_linux(uint8_t *buff, uint32_t size, uint32_t pkt_offset) ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr)); pu8UdpBuffer = (char *)ih + sizeof(struct iphdr); - if (buff_to_send[35] == 67 && buff_to_send[37] == 68) { + if (buff_to_send[35] == 67 && buff_to_send[37] == 68) PRINT_D(RX_DBG, "DHCP Message received\n"); - } if (buff_to_send[12] == 0x88 && buff_to_send[13] == 0x8e) PRINT_D(GENERIC_DBG, "eapol received\n"); #endif @@ -2513,9 +2493,8 @@ void frmw_to_linux(uint8_t *buff, uint32_t size, uint32_t pkt_offset) PRINT_D(RX_DBG, "netif_rx ret value is: %d\n", stats); } #ifndef TCP_ENHANCEMENTS - else { + else PRINT_ER("Discard sending packet with len = %d\n", size); - } #endif } @@ -2538,9 +2517,8 @@ void WILC_WFI_mgmt_rx(uint8_t *buff, uint32_t size) #ifdef WILC_P2P nic = netdev_priv(g_linux_wlan->strInterfaceInfo[1].wilc_netdev); /* p2p0 */ if ((buff[0] == nic->g_struct_frame_reg[0].frame_type && nic->g_struct_frame_reg[0].reg) || - (buff[0] == nic->g_struct_frame_reg[1].frame_type && nic->g_struct_frame_reg[1].reg)) { + (buff[0] == nic->g_struct_frame_reg[1].frame_type && nic->g_struct_frame_reg[1].reg)) WILC_WFI_p2p_rx(g_linux_wlan->strInterfaceInfo[1].wilc_netdev, buff, size); - } #endif } @@ -2671,17 +2649,15 @@ static int __init init_wilc_driver(void) int ret; ret = sdio_register_driver(&wilc_bus); - if (ret < 0) { + if (ret < 0) PRINT_D(INIT_DBG, "init_wilc_driver: Failed register sdio driver\n"); - } return ret; } #else PRINT_D(INIT_DBG, "Initializing netdev\n"); - if (wilc_netdev_init()) { + if (wilc_netdev_init()) PRINT_ER("Couldn't initialize netdev\n"); - } return 0; #endif } @@ -2699,9 +2675,8 @@ static void __exit exit_wilc_driver(void) unregister_inetaddr_notifier(&g_dev_notifier); #endif - for (i = 0; i < NUM_CONCURRENT_IFC; i++) { + for (i = 0; i < NUM_CONCURRENT_IFC; i++) nic[i] = netdev_priv(g_linux_wlan->strInterfaceInfo[i].wilc_netdev); - } } @@ -2724,9 +2699,8 @@ static void __exit exit_wilc_driver(void) for (i = 0; i < NUM_CONCURRENT_IFC; i++) { /* close all opened interfaces */ if (g_linux_wlan->strInterfaceInfo[i].wilc_netdev != NULL) { - if (nic[i]->mac_opened) { + if (nic[i]->mac_opened) mac_close(g_linux_wlan->strInterfaceInfo[i].wilc_netdev); - } } } for (i = 0; i < NUM_CONCURRENT_IFC; i++) { -- cgit v1.3-6-gb490 From 4423f3b0d96a40ff7f1c2552b1e23c3c3eadcbe8 Mon Sep 17 00:00:00 2001 From: "Kim, Leo" Date: Tue, 28 Jul 2015 17:47:38 +0900 Subject: staging: wilc1000: remove warnings on the multiple blank lines uses This patch removes the warnings reported by checkpatch.pl for using multiple blank lines. Signed-off-by: Kim, Leo Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/linux_wlan.c | 69 ----------------------------------- 1 file changed, 69 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index a4589b799db9..d012af5f1fb5 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -102,7 +102,6 @@ static int linux_wlan_device_detection(int on_off) return 0; } - #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP static int dev_state_ev_handler(struct notifier_block *this, unsigned long event, void *ptr); @@ -115,7 +114,6 @@ static struct notifier_block g_dev_notifier = { if (g_linux_wlan->oup.wlan_cleanup != NULL) \ g_linux_wlan->oup.wlan_cleanup(); } - #ifndef STA_FIRMWARE #define STA_FIRMWARE "wifi_firmware.bin" #endif @@ -128,15 +126,12 @@ static struct notifier_block g_dev_notifier = { #define P2P_CONCURRENCY_FIRMWARE "wifi_firmware_p2p_concurrency.bin" #endif - - typedef struct android_wifi_priv_cmd { char *buf; int used_len; int total_len; } android_wifi_priv_cmd; - #define IRQ_WAIT 1 #define IRQ_NO_WAIT 0 /* @@ -157,7 +152,6 @@ void linux_wlan_unlock(void *vp); extern void WILC_WFI_monitor_rx(uint8_t *buff, uint32_t size); extern void WILC_WFI_p2p_rx(struct net_device *dev, uint8_t *buff, uint32_t size); - static void *internal_alloc(uint32_t size, uint32_t flag); static void linux_wlan_tx_complete(void *priv, int status); void frmw_to_linux(uint8_t *buff, uint32_t size, uint32_t pkt_offset); @@ -169,8 +163,6 @@ static struct net_device_stats *mac_stats(struct net_device *dev); static int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd); static void wilc_set_multicast_list(struct net_device *dev); - - /* * for now - in frmw_to_linux there should be private data to be passed to it * and this data should be pointer to net device @@ -199,8 +191,6 @@ volatile int WatchDogdebuggerCounter; char DebugBuffer[DEGUG_BUFFER_LENGTH + 20] = {0}; static char *ps8current = DebugBuffer; - - void printk_later(const char *format, ...) { va_list args; @@ -212,7 +202,6 @@ void printk_later(const char *format, ...) } - void dump_logs() { if (DebugBuffer[0]) { @@ -244,11 +233,8 @@ static int DebuggingThreadTask(void *vp) WatchDogdebuggerCounter = 0; } } - - #endif - #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP static int dev_state_ev_handler(struct notifier_block *this, unsigned long event, void *ptr) { @@ -296,7 +282,6 @@ static int dev_state_ev_handler(struct notifier_block *this, unsigned long event PRINT_INFO(GENERIC_DBG, "\n ============== IP Address Obtained ===============\n\n"); - /*If we are in station mode or client mode*/ if (nic->iftype == STATION_MODE || nic->iftype == CLIENT_MODE) { pstrWFIDrv->IFC_UP = 1; @@ -305,8 +290,6 @@ static int dev_state_ev_handler(struct notifier_block *this, unsigned long event PRINT_D(GENERIC_DBG, "IP obtained , enable scan\n"); } - - if (bEnablePS) host_int_set_power_mgmt((WILC_WFIDrvHandle)pstrWFIDrv, 1, 0); @@ -332,7 +315,6 @@ static int dev_state_ev_handler(struct notifier_block *this, unsigned long event resolve_disconnect_aberration(pstrWFIDrv); - PRINT_D(GENERIC_DBG, "[%s] Down IP\n", dev_iface->ifa_label); pIP_Add_buff = null_ip; @@ -385,8 +367,6 @@ void linux_wlan_disable_irq(int wait) #if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO) static irqreturn_t isr_uh_routine(int irq, void *user_data) { - - int_rcvdU++; #if (RX_BH_TYPE != RX_BH_THREADED_IRQ) linux_wlan_disable_irq(IRQ_NO_WAIT); @@ -438,9 +418,6 @@ static void isr_bh_routine(struct work_struct *work) #else return; #endif - - - } int_rcvdB++; @@ -451,7 +428,6 @@ static void isr_bh_routine(struct work_struct *work) PRINT_ER("wlan_handle_rx_isr() hasn't been initialized\n"); } - #if (RX_BH_TYPE == RX_BH_THREADED_IRQ) return IRQ_HANDLED; #endif @@ -485,7 +461,6 @@ static int isr_bh_routine(void *vp) } #endif - #if (defined WILC_SPI) || (defined WILC_SDIO_IRQ_GPIO) static int init_irq(linux_wlan_t *p_nic) { @@ -516,7 +491,6 @@ static int init_irq(linux_wlan_t *p_nic) PRINT_ER("could not obtain gpio for WILC_INTR\n"); } - #if (RX_BH_TYPE == RX_BH_THREADED_IRQ) if ((ret != -1) && (request_threaded_irq(nic->dev_irq_num, isr_uh_routine, isr_bh_routine, IRQF_TRIGGER_LOW | IRQF_ONESHOT, /*Without IRQF_ONESHOT the uh will remain kicked in and dont gave a chance to bh*/ @@ -552,7 +526,6 @@ static void deinit_irq(linux_wlan_t *nic) #endif } - /* * OS functions */ @@ -599,7 +572,6 @@ void linux_wlan_free(void *vp) } } - static void *internal_alloc(uint32_t size, uint32_t flag) { char *pntr = NULL; @@ -608,7 +580,6 @@ static void *internal_alloc(uint32_t size, uint32_t flag) return (void *)pntr; } - static void linux_wlan_init_lock(char *lockName, void *plock, int count) { sema_init((struct semaphore *)plock, count); @@ -654,7 +625,6 @@ void linux_wlan_unlock(void *vp) } } - static void linux_wlan_init_mutex(char *lockName, void *plock, int count) { mutex_init((struct mutex *)plock); @@ -700,7 +670,6 @@ static void linux_wlan_unlock_mutex(void *vp) } } - /*Added by Amr - BugID_4720*/ static void linux_wlan_init_spin_lock(char *lockName, void *plock, int count) { @@ -938,7 +907,6 @@ int linux_wlan_get_firmware(perInterface_wlan_t *p_nic) const struct firmware *wilc_firmware; char *firmware; - if (nic->iftype == AP_MODE) firmware = AP_FIRMWARE; else if (nic->iftype == STATION_MODE) @@ -950,8 +918,6 @@ int linux_wlan_get_firmware(perInterface_wlan_t *p_nic) firmware = P2P_CONCURRENCY_FIRMWARE; } - - if (nic == NULL) { PRINT_ER("NIC is NULL\n"); goto _fail_; @@ -962,7 +928,6 @@ int linux_wlan_get_firmware(perInterface_wlan_t *p_nic) goto _fail_; } - /* the firmare should be located in /lib/firmware in * root file system with the name specified above */ @@ -1061,7 +1026,6 @@ _FAIL_: return ret; } - /* startup configuration - could be changed later using iconfig*/ static int linux_wlan_init_test_config(struct net_device *dev, linux_wlan_t *p_nic) { @@ -1087,7 +1051,6 @@ static int linux_wlan_init_test_config(struct net_device *dev, linux_wlan_t *p_n PRINT_D(INIT_DBG, "MAC address is : %02x-%02x-%02x-%02x-%02x-%02x\n", mac_add[0], mac_add[1], mac_add[2], mac_add[3], mac_add[4], mac_add[5]); wilc_get_chipid(0); - if (g_linux_wlan->oup.wlan_cfg_set == NULL) { PRINT_D(INIT_DBG, "Null p[ointer\n"); goto _fail_; @@ -1107,7 +1070,6 @@ static int linux_wlan_init_test_config(struct net_device *dev, linux_wlan_t *p_n if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_BSS_TYPE, c_val, 1, 0, 0)) goto _fail_; - /* c_val[0] = RATE_AUTO; / * bug 4275: Enable autorate and limit it to 24Mbps * / */ c_val[0] = RATE_AUTO; if (!g_linux_wlan->oup.wlan_cfg_set(0, WID_CURRENT_TX_RATE, c_val, 1, 0, 0)) @@ -1342,7 +1304,6 @@ _fail_: return -1; } - /**************************/ void wilc1000_wlan_deinit(linux_wlan_t *nic) { @@ -1376,7 +1337,6 @@ void wilc1000_wlan_deinit(linux_wlan_t *nic) #endif #endif - /* not sure if the following unlocks are needed or not*/ if (&g_linux_wlan->rxq_event != NULL) linux_wlan_unlock(&g_linux_wlan->rxq_event); @@ -1384,7 +1344,6 @@ void wilc1000_wlan_deinit(linux_wlan_t *nic) if (&g_linux_wlan->txq_event != NULL) linux_wlan_unlock(&g_linux_wlan->txq_event); - #if (RX_BH_TYPE == RX_BH_WORK_QUEUE) /*Removing the work struct from the linux kernel workqueue*/ if (&g_linux_wlan->rx_work_queue != NULL) @@ -1401,7 +1360,6 @@ void wilc1000_wlan_deinit(linux_wlan_t *nic) PRINT_D(INIT_DBG, "Deinitializing IRQ\n"); deinit_irq(g_linux_wlan); - if (&g_linux_wlan->oup != NULL) { if (g_linux_wlan->oup.wlan_stop != NULL) g_linux_wlan->oup.wlan_stop(); @@ -1662,17 +1620,14 @@ static void wlan_deinitialize_threads(linux_wlan_t *nic) if (&g_linux_wlan->rxq_event != NULL) linux_wlan_unlock(&g_linux_wlan->rxq_event); - if (g_linux_wlan->rxq_thread != NULL) { kthread_stop(g_linux_wlan->rxq_thread); g_linux_wlan->rxq_thread = NULL; } - if (&g_linux_wlan->txq_event != NULL) linux_wlan_unlock(&g_linux_wlan->txq_event); - if (g_linux_wlan->txq_thread != NULL) { kthread_stop(g_linux_wlan->txq_thread); g_linux_wlan->txq_thread = NULL; @@ -1872,7 +1827,6 @@ int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic) /*Save the oup structre into global pointer*/ gpstrWlanOps = &g_linux_wlan->oup; - ret = wlan_initialize_threads(nic); if (ret < 0) { PRINT_ER("Initializing Threads FAILED\n"); @@ -1910,7 +1864,6 @@ int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic) goto _fail_irq_enable_; } - /*Download firmware*/ ret = linux_wlan_firmware_download(g_linux_wlan); if (ret < 0) { @@ -1950,7 +1903,6 @@ int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic) g_linux_wlan->wilc1000_initialized = 1; return 0; /*success*/ - _fail_fw_start_: if (&g_linux_wlan->oup != NULL) { if (g_linux_wlan->oup.wlan_stop != NULL) @@ -1979,7 +1931,6 @@ _fail_locks_: return ret; } - /* * - this function will be called automatically by OS when module inserted. */ @@ -2011,7 +1962,6 @@ int mac_init_fn(struct net_device *ndev) } #endif - void WILC_WFI_frame_register(struct wiphy *wiphy, struct net_device *dev, u16 frame_type, bool reg); @@ -2075,7 +2025,6 @@ int mac_open(struct net_device *ndev) goto _err_; } - WILC_WFI_frame_register(nic->wilc_netdev->ieee80211_ptr->wiphy, nic->wilc_netdev, nic->g_struct_frame_reg[0].frame_type, nic->g_struct_frame_reg[0].reg); WILC_WFI_frame_register(nic->wilc_netdev->ieee80211_ptr->wiphy, nic->wilc_netdev, @@ -2114,7 +2063,6 @@ struct net_device_stats *mac_stats(struct net_device *dev) { perInterface_wlan_t *nic = netdev_priv(dev); - return &nic->netstats; } @@ -2129,7 +2077,6 @@ static void wilc_set_multicast_list(struct net_device *dev) priv = wiphy_priv(dev->ieee80211_ptr->wiphy); pstrWFIDrv = (tstrWILC_WFIDrv *)priv->hWILCWFIDrv; - if (!dev) return; @@ -2250,7 +2197,6 @@ int mac_xmit(struct sk_buff *skb, struct net_device *ndev) QueueCount = WILC_Xmit_data((void *)tx_data, HOST_TO_WLAN); #endif /* WILC_FULLY_HOSTING_AP */ - if (QueueCount > FLOW_CONTROL_UPPER_THRESHOLD) { netif_stop_queue(g_linux_wlan->strInterfaceInfo[0].wilc_netdev); netif_stop_queue(g_linux_wlan->strInterfaceInfo[1].wilc_netdev); @@ -2259,7 +2205,6 @@ int mac_xmit(struct sk_buff *skb, struct net_device *ndev) return 0; } - int mac_close(struct net_device *ndev) { struct WILC_WFI_priv *priv; @@ -2282,8 +2227,6 @@ int mac_close(struct net_device *ndev) pstrWFIDrv = (tstrWILC_WFIDrv *)priv->hWILCWFIDrv; - - PRINT_D(GENERIC_DBG, "Mac close\n"); if (g_linux_wlan == NULL) { @@ -2329,7 +2272,6 @@ int mac_close(struct net_device *ndev) return 0; } - int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd) { @@ -2340,8 +2282,6 @@ int mac_ioctl(struct net_device *ndev, struct ifreq *req, int cmd) struct WILC_WFI_priv *priv; s32 s32Error = WILC_SUCCESS; - - /* struct iwreq *wrq = (struct iwreq *) req; // tony moved to case SIOCSIWPRIV */ #ifdef USE_WIRELESS nic = netdev_priv(ndev); @@ -2435,7 +2375,6 @@ void frmw_to_linux(uint8_t *buff, uint32_t size, uint32_t pkt_offset) frame_len = size; buff_to_send = buff; - /* Need to send the packet up to the host, allocate a skb buffer */ skb = dev_alloc_skb(frame_len); if (skb == NULL) { @@ -2600,7 +2539,6 @@ int wilc_netdev_init(void) } #endif - if (register_netdev(ndev)) { PRINT_ER("Device couldn't be registered - %s\n", ndev->name); return -1; /* ERROR */ @@ -2624,12 +2562,9 @@ int wilc_netdev_init(void) return 0; } - /*The 1st function called after module inserted*/ static int __init init_wilc_driver(void) { - - #if defined (WILC_DEBUGFS) if (wilc_debugfs_init() < 0) { PRINT_D(GENERIC_DBG, "fail to create debugfs for wilc driver\n"); @@ -2679,13 +2614,11 @@ static void __exit exit_wilc_driver(void) nic[i] = netdev_priv(g_linux_wlan->strInterfaceInfo[i].wilc_netdev); } - if ((g_linux_wlan != NULL) && g_linux_wlan->wilc_firmware != NULL) { release_firmware(g_linux_wlan->wilc_firmware); g_linux_wlan->wilc_firmware = NULL; } - if ((g_linux_wlan != NULL) && (((g_linux_wlan->strInterfaceInfo[0].wilc_netdev) != NULL) || ((g_linux_wlan->strInterfaceInfo[1].wilc_netdev) != NULL))) { PRINT_D(INIT_DBG, "Waiting for mac_close ....\n"); @@ -2695,7 +2628,6 @@ static void __exit exit_wilc_driver(void) else PRINT_D(INIT_DBG, "mac_closed\n"); - for (i = 0; i < NUM_CONCURRENT_IFC; i++) { /* close all opened interfaces */ if (g_linux_wlan->strInterfaceInfo[i].wilc_netdev != NULL) { @@ -2715,7 +2647,6 @@ static void __exit exit_wilc_driver(void) } } - #ifdef USE_WIRELESS #ifdef WILC_AP_EXTERNAL_MLME /* Bug 4600 : WILC_WFI_deinit_mon_interface was already called at mac_close */ -- cgit v1.3-6-gb490 From 3369463284cff3adafb49914a4dffe608421848a Mon Sep 17 00:00:00 2001 From: "Kim, Leo" Date: Tue, 28 Jul 2015 17:47:39 +0900 Subject: staging: wilc1000: remove unnecessary spcae This patch removes the warnings reported by checkpatch.pl on space prohibited between function name and open parenthesis '(' Signed-off-by: Kim, Leo Signed-off-by: Tony Cho Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/linux_wlan.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index d012af5f1fb5..3e55a8ac2966 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -194,9 +194,9 @@ static char *ps8current = DebugBuffer; void printk_later(const char *format, ...) { va_list args; - va_start (args, format); - ps8current += vsprintf (ps8current, format, args); - va_end (args); + va_start(args, format); + ps8current += vsprintf(ps8current, format, args); + va_end(args); if ((ps8current - DebugBuffer) > DEGUG_BUFFER_LENGTH) ps8current = DebugBuffer; @@ -477,9 +477,9 @@ static int init_irq(linux_wlan_t *p_nic) * * ex) nic->dev_irq_num = gpio_to_irq(GPIO_NUM); */ -#elif defined (NM73131_0_BOARD) +#elif defined(NM73131_0_BOARD) nic->dev_irq_num = IRQ_WILC1000; -#elif defined (PANDA_BOARD) +#elif defined(PANDA_BOARD) gpio_export(GPIO_NUM, 1); nic->dev_irq_num = OMAP_GPIO_IRQ(GPIO_NUM); irq_set_irq_type(nic->dev_irq_num, IRQ_TYPE_LEVEL_LOW); @@ -1483,7 +1483,7 @@ void linux_to_wlan(wilc_wlan_inp_t *nwi, linux_wlan_t *nic) nwi->os_context.txq_wait_event = (void *)&g_linux_wlan->txq_event; -#if defined (MEMORY_STATIC) +#if defined(MEMORY_STATIC) nwi->os_context.rx_buffer_size = LINUX_RX_SIZE; #endif nwi->os_context.rxq_critical_section = (void *)&g_linux_wlan->rxq_cs; @@ -1935,7 +1935,7 @@ _fail_locks_: * - this function will be called automatically by OS when module inserted. */ -#if !defined (NM73131_0_BOARD) +#if !defined(NM73131_0_BOARD) int mac_init_fn(struct net_device *ndev) { @@ -1966,7 +1966,7 @@ void WILC_WFI_frame_register(struct wiphy *wiphy, struct net_device *dev, u16 frame_type, bool reg); /* This fn is called, when this device is setup using ifconfig */ -#if !defined (NM73131_0_BOARD) +#if !defined(NM73131_0_BOARD) int mac_open(struct net_device *ndev) { perInterface_wlan_t *nic; @@ -2565,7 +2565,7 @@ int wilc_netdev_init(void) /*The 1st function called after module inserted*/ static int __init init_wilc_driver(void) { -#if defined (WILC_DEBUGFS) +#if defined(WILC_DEBUGFS) if (wilc_debugfs_init() < 0) { PRINT_D(GENERIC_DBG, "fail to create debugfs for wilc driver\n"); return -1; @@ -2671,7 +2671,7 @@ static void __exit exit_wilc_driver(void) } printk("Module_exit Done.\n"); -#if defined (WILC_DEBUGFS) +#if defined(WILC_DEBUGFS) wilc_debugfs_remove(); #endif -- cgit v1.3-6-gb490 From 29edbe5e29d0ba3f619723f964724adab168f6f8 Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Wed, 29 Jul 2015 12:18:58 +0530 Subject: Staging : wilc1000: Remove braces for single statement blocks This patch fixes the following checkpatch.pl warning: WARNING: braces {} are not necessary for single statement blocks Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/coreconfigurator.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c index 8bacd8cfd945..342a3368d4a2 100644 --- a/drivers/staging/wilc1000/coreconfigurator.c +++ b/drivers/staging/wilc1000/coreconfigurator.c @@ -855,9 +855,8 @@ s32 ParseNetworkInfo(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo) /* Get DTIM Period */ pu8TimElm = get_tim_elm(pu8msa, (u16RxLen + FCS_LEN), u8index); - if (pu8TimElm != 0) { + if (pu8TimElm != 0) pstrNetworkInfo->u8DtimPeriod = pu8TimElm[3]; - } pu8IEs = &pu8msa[MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + CAP_INFO_LEN]; u16IEsLen = u16RxLen - (MAC_HDR_LEN + TIME_STAMP_LEN + BEACON_INTERVAL_LEN + CAP_INFO_LEN); -- cgit v1.3-6-gb490 From 0380839dc90c53e24ddfa0f17ad909c2ddc345c2 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:09 +0100 Subject: PCI/MSI: Register irq domain with specific token When creating a PCI/MSI domain, tag it with DOMAIN_BUS_PCI_MSI so that it can be looked-up using irq_find_matching_host(). Acked-by: Bjorn Helgaas Reviewed-by: Hanjun Guo Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-3-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/pci/msi.c | 9 ++++++++- include/linux/irqdomain.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index cd4c78c193de..3aae7c9ad31c 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1273,12 +1273,19 @@ struct irq_domain *pci_msi_create_irq_domain(struct device_node *node, struct msi_domain_info *info, struct irq_domain *parent) { + struct irq_domain *domain; + if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) pci_msi_domain_update_dom_ops(info); if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) pci_msi_domain_update_chip_ops(info); - return msi_create_irq_domain(node, info, parent); + domain = msi_create_irq_domain(node, info, parent); + if (!domain) + return NULL; + + domain->bus_token = DOMAIN_BUS_PCI_MSI; + return domain; } /** diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 91a83adf5e45..25e9e6696a65 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -54,6 +54,7 @@ struct irq_data; */ enum irq_domain_bus_token { DOMAIN_BUS_ANY = 0, + DOMAIN_BUS_PCI_MSI, }; /** -- cgit v1.3-6-gb490 From 44aa0c657e3e45795a92addeb0dce7d28d9b0bd2 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:11 +0100 Subject: PCI/MSI: Add hooks to populate the msi_domain field In order to be able to populate the device msi_domain field, add the necessary hooks to propagate the host bridge msi_domain across secondary busses to devices. So far, nobody populates the initial msi_domain. Acked-by: Bjorn Helgaas Reviewed-by: Hanjun Guo Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-5-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/pci/probe.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cefd636681b6..c03ecbffc50b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -661,6 +661,32 @@ static void pci_set_bus_speed(struct pci_bus *bus) } } +static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus) +{ + /* + * Any firmware interface that can resolve the msi_domain + * should be called from here. + */ + + return NULL; +} + +static void pci_set_bus_msi_domain(struct pci_bus *bus) +{ + struct irq_domain *d; + + /* + * Either bus is the root, and we must obtain it from the + * firmware, or we inherit it from the bridge device. + */ + if (pci_is_root_bus(bus)) + d = pci_host_bridge_msi_domain(bus); + else + d = dev_get_msi_domain(&bus->self->dev); + + dev_set_msi_domain(&bus->dev, d); +} + static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) { @@ -714,6 +740,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, bridge->subordinate = child; add_dev: + pci_set_bus_msi_domain(child); ret = device_register(&child->dev); WARN_ON(ret < 0); @@ -1544,6 +1571,17 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_enable_acs(dev); } +static void pci_set_msi_domain(struct pci_dev *dev) +{ + /* + * If no domain has been set through the pcibios_add_device + * callback, inherit the default from the bus device. + */ + if (!dev_get_msi_domain(&dev->dev)) + dev_set_msi_domain(&dev->dev, + dev_get_msi_domain(&dev->bus->dev)); +} + void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) { int ret; @@ -1585,6 +1623,9 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) ret = pcibios_add_device(dev); WARN_ON(ret < 0); + /* Setup MSI irq domain */ + pci_set_msi_domain(dev); + /* Notifier could use PCI capabilities */ dev->match_driver = false; ret = device_add(&dev->dev); @@ -1975,6 +2016,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, b->bridge = get_device(&bridge->dev); device_enable_async_suspend(b->bridge); pci_set_bus_of_node(b); + pci_set_bus_msi_domain(b); if (!parent) set_dev_node(b->bridge, pcibus_to_node(b)); -- cgit v1.3-6-gb490 From b165e2b60b39888a7ff8efbc1de40137471dda41 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:12 +0100 Subject: PCI/MSI: Add support for OF-provided msi_domain In order to populate the PCI host bridge msi_domain, use the "msi-parent" attribute to lookup a corresponding irq domain. If found, this is our MSI domain. This gets plugged into the core PCI code. Acked-by: Bjorn Helgaas Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-6-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/pci/of.c | 25 +++++++++++++++++++++++++ drivers/pci/probe.c | 5 ++++- include/linux/pci.h | 4 ++++ 3 files changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/of.c b/drivers/pci/of.c index f0929934bb7a..85844d8c3efd 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -9,6 +9,7 @@ * 2 of the License, or (at your option) any later version. */ +#include #include #include #include @@ -59,3 +60,27 @@ struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus) return of_node_get(bus->bridge->parent->of_node); return NULL; } + +struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus) +{ +#ifdef CONFIG_IRQ_DOMAIN + struct device_node *np; + struct irq_domain *d; + + if (!bus->dev.of_node) + return NULL; + + /* Start looking for a phandle to an MSI controller. */ + np = of_parse_phandle(bus->dev.of_node, "msi-parent", 0); + if (!np) + return NULL; + + d = irq_find_matching_host(np, DOMAIN_BUS_PCI_MSI); + if (d) + return d; + + return irq_find_host(np); +#else + return NULL; +#endif +} diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c03ecbffc50b..a7afeacce7f1 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -663,12 +663,15 @@ static void pci_set_bus_speed(struct pci_bus *bus) static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus) { + struct irq_domain *d; + /* * Any firmware interface that can resolve the msi_domain * should be called from here. */ + d = pci_host_bridge_of_msi_domain(bus); - return NULL; + return d; } static void pci_set_bus_msi_domain(struct pci_bus *bus) diff --git a/include/linux/pci.h b/include/linux/pci.h index fbf245f5eba7..772616d3b184 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1841,10 +1841,12 @@ int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off, /* PCI <-> OF binding helpers */ #ifdef CONFIG_OF struct device_node; +struct irq_domain; void pci_set_of_node(struct pci_dev *dev); void pci_release_of_node(struct pci_dev *dev); void pci_set_bus_of_node(struct pci_bus *bus); void pci_release_bus_of_node(struct pci_bus *bus); +struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus); /* Arch may override this (weak) */ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus); @@ -1867,6 +1869,8 @@ static inline void pci_set_bus_of_node(struct pci_bus *bus) { } static inline void pci_release_bus_of_node(struct pci_bus *bus) { } static inline struct device_node * pci_device_to_OF_node(const struct pci_dev *pdev) { return NULL; } +static inline struct irq_domain * +pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; } #endif /* CONFIG_OF */ #ifdef CONFIG_EEH -- cgit v1.3-6-gb490 From 471c931cb248ab7af0cd62503d811239b47f217b Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:13 +0100 Subject: PCI/MSI: Allow msi_domain lookup using the host bridge node A number of platforms do not need to use the msi-parent property, as the host bridge itself provides the MSI controller. Allow this configuration by performing an irq domain lookup based on the host bridge node if it doesn't have a valid msi-parent property. Acked-by: Bjorn Helgaas Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-7-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/pci/of.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 85844d8c3efd..2e99a500cb83 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -72,8 +72,13 @@ struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus) /* Start looking for a phandle to an MSI controller. */ np = of_parse_phandle(bus->dev.of_node, "msi-parent", 0); + + /* + * If we don't have an msi-parent property, look for a domain + * directly attached to the host bridge. + */ if (!np) - return NULL; + np = bus->dev.of_node; d = irq_find_matching_host(np, DOMAIN_BUS_PCI_MSI); if (d) -- cgit v1.3-6-gb490 From d8a1cb7575502d2be502a65ecb344ff05c8d9f44 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:14 +0100 Subject: PCI/MSI: Let pci_msi_get_domain use struct device::msi_domain Now that we can easily find which MSI domain a PCI device is using, use dev_get_msi_domain as a way to retrieve the information. The original code is still used as a fallback. Acked-by: Bjorn Helgaas Reviewed-by: Hanjun Guo Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-8-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/pci/msi.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 3aae7c9ad31c..460334409794 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -39,14 +39,16 @@ struct irq_domain * __weak arch_get_pci_msi_domain(struct pci_dev *dev) static struct irq_domain *pci_msi_get_domain(struct pci_dev *dev) { - struct irq_domain *domain = NULL; + struct irq_domain *domain; - if (dev->bus->msi) - domain = dev->bus->msi->domain; - if (!domain) - domain = arch_get_pci_msi_domain(dev); + domain = dev_get_msi_domain(&dev->dev); + if (domain) + return domain; - return domain; + if (dev->bus->msi && (domain = dev->bus->msi->domain)) + return domain; + + return arch_get_pci_msi_domain(dev); } static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) -- cgit v1.3-6-gb490 From c706c239af5bc297b5fbf1adc715632e1c222f7a Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:15 +0100 Subject: of/platform: Assign MSI domain to platform device As for PCI, we're able to populate the msi_domain field at probe time, provided that the device tree has an "msi-parent" property. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-9-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/of/irq.c | 21 +++++++++++++++++++++ drivers/of/platform.c | 1 + include/linux/irqdomain.h | 1 + include/linux/of_irq.h | 1 + 4 files changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 3cf7a01f557f..2956d725649f 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -18,6 +18,7 @@ * driver. */ +#include #include #include #include @@ -576,3 +577,23 @@ err: kfree(desc); } } + +/** + * of_msi_configure - Set the msi_domain field of a device + * @dev: device structure to associate with an MSI irq domain + * @np: device node for that device + */ +void of_msi_configure(struct device *dev, struct device_node *np) +{ + struct device_node *msi_np; + struct irq_domain *d; + + msi_np = of_parse_phandle(np, "msi-parent", 0); + if (!msi_np) + return; + + d = irq_find_matching_host(msi_np, DOMAIN_BUS_PLATFORM_MSI); + if (!d) + d = irq_find_host(msi_np); + dev_set_msi_domain(dev, d); +} diff --git a/drivers/of/platform.c b/drivers/of/platform.c index ddf8e42c9367..8a002d6151f2 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -184,6 +184,7 @@ static struct platform_device *of_platform_device_create_pdata( dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; of_dma_configure(&dev->dev, dev->dev.of_node); + of_msi_configure(&dev->dev, dev->dev.of_node); if (of_device_add(dev) != 0) { of_dma_deconfigure(&dev->dev); diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 25e9e6696a65..b4a74f73a0c3 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -55,6 +55,7 @@ struct irq_data; enum irq_domain_bus_token { DOMAIN_BUS_ANY = 0, DOMAIN_BUS_PCI_MSI, + DOMAIN_BUS_PLATFORM_MSI, }; /** diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index d884929a7747..4bcbd586a672 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -74,6 +74,7 @@ static inline int of_irq_to_resource_table(struct device_node *dev, */ extern unsigned int irq_of_parse_and_map(struct device_node *node, int index); extern struct device_node *of_irq_find_parent(struct device_node *child); +extern void of_msi_configure(struct device *dev, struct device_node *np); #else /* !CONFIG_OF */ static inline unsigned int irq_of_parse_and_map(struct device_node *dev, -- cgit v1.3-6-gb490 From c09fcc4b2b48d58d769a8cff5041533535ece449 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:16 +0100 Subject: drivers/base: Add MSI domain support for non-PCI devices With the msi_list and the msi_domain properties now being at the generic device level, it is starting to be relatively easy to offer a generic way of providing non-PCI MSIs. The two major hurdles with this idea are: - Lack of global ID that identifies a device: this is worked around by having a global ID allocator for each device that gets enrolled in the platform MSI subsystem - Lack of standard way to write the message in the generating device. This is solved by mandating driver code to provide a write_msg callback, so that everyone can have their own square wheel Apart from that, the API is fairly straightforward: - platform_msi_create_irq_domain creates an MSI domain that gets tagged with DOMAIN_BUS_PLATFORM_MSI - platform_msi_domain_alloc_irqs allocate MSIs for a given device, populating the msi_list - platform_msi_domain_free_irqs does what is written on the tin [ tglx: Created a seperate struct platform_msi_desc and added kerneldoc entries ] Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-10-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/base/Makefile | 1 + drivers/base/platform-msi.c | 282 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/msi.h | 22 ++++ 3 files changed, 305 insertions(+) create mode 100644 drivers/base/platform-msi.c (limited to 'drivers') diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 527d291706e8..6b2a84e7f2be 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_REGMAP) += regmap/ obj-$(CONFIG_SOC_BUS) += soc.o obj-$(CONFIG_PINCTRL) += pinctrl.o obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o +obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c new file mode 100644 index 000000000000..1857a5dd0816 --- /dev/null +++ b/drivers/base/platform-msi.c @@ -0,0 +1,282 @@ +/* + * MSI framework for platform devices + * + * Copyright (C) 2015 ARM Limited, All Rights Reserved. + * Author: Marc Zyngier + * + * 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, see . + */ + +#include +#include +#include +#include +#include +#include + +#define DEV_ID_SHIFT 24 + +/* + * Internal data structure containing a (made up, but unique) devid + * and the callback to write the MSI message. + */ +struct platform_msi_priv_data { + irq_write_msi_msg_t write_msg; + int devid; +}; + +/* The devid allocator */ +static DEFINE_IDA(platform_msi_devid_ida); + +#ifdef GENERIC_MSI_DOMAIN_OPS +/* + * Convert an msi_desc to a globaly unique identifier (per-device + * devid + msi_desc position in the msi_list). + */ +static irq_hw_number_t platform_msi_calc_hwirq(struct msi_desc *desc) +{ + u32 devid; + + devid = desc->platform.msi_priv_data->devid; + + return (devid << (32 - DEV_ID_SHIFT)) | desc->platform.msi_index; +} + +static void platform_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) +{ + arg->desc = desc; + arg->hwirq = platform_msi_calc_hwirq(desc); +} + +static int platform_msi_init(struct irq_domain *domain, + struct msi_domain_info *info, + unsigned int virq, irq_hw_number_t hwirq, + msi_alloc_info_t *arg) +{ + struct irq_data *data; + + irq_domain_set_hwirq_and_chip(domain, virq, hwirq, + info->chip, info->chip_data); + + /* + * Save the MSI descriptor in handler_data so that the + * irq_write_msi_msg callback can retrieve it (and the + * associated device). + */ + data = irq_domain_get_irq_data(domain, virq); + data->handler_data = arg->desc; + + return 0; +} +#else +#define platform_msi_set_desc NULL +#define platform_msi_init NULL +#endif + +static void platform_msi_update_dom_ops(struct msi_domain_info *info) +{ + struct msi_domain_ops *ops = info->ops; + + BUG_ON(!ops); + + if (ops->msi_init == NULL) + ops->msi_init = platform_msi_init; + if (ops->set_desc == NULL) + ops->set_desc = platform_msi_set_desc; +} + +static void platform_msi_write_msg(struct irq_data *data, struct msi_msg *msg) +{ + struct msi_desc *desc = irq_data_get_irq_handler_data(data); + struct platform_msi_priv_data *priv_data; + + priv_data = desc->platform.msi_priv_data; + + priv_data->write_msg(desc, msg); +} + +static void platform_msi_update_chip_ops(struct msi_domain_info *info) +{ + struct irq_chip *chip = info->chip; + + BUG_ON(!chip); + if (!chip->irq_mask) + chip->irq_mask = irq_chip_mask_parent; + if (!chip->irq_unmask) + chip->irq_unmask = irq_chip_unmask_parent; + if (!chip->irq_eoi) + chip->irq_eoi = irq_chip_eoi_parent; + if (!chip->irq_set_affinity) + chip->irq_set_affinity = msi_domain_set_affinity; + if (!chip->irq_write_msi_msg) + chip->irq_write_msi_msg = platform_msi_write_msg; +} + +static void platform_msi_free_descs(struct device *dev) +{ + struct msi_desc *desc, *tmp; + + list_for_each_entry_safe(desc, tmp, dev_to_msi_list(dev), list) { + list_del(&desc->list); + free_msi_entry(desc); + } +} + +static int platform_msi_alloc_descs(struct device *dev, int nvec, + struct platform_msi_priv_data *data) + +{ + int i; + + for (i = 0; i < nvec; i++) { + struct msi_desc *desc; + + desc = alloc_msi_entry(dev); + if (!desc) + break; + + desc->platform.msi_priv_data = data; + desc->platform.msi_index = i; + desc->nvec_used = 1; + + list_add_tail(&desc->list, dev_to_msi_list(dev)); + } + + if (i != nvec) { + /* Clean up the mess */ + platform_msi_free_descs(dev); + + return -ENOMEM; + } + + return 0; +} + +/** + * platform_msi_create_irq_domain - Create a platform MSI interrupt domain + * @np: Optional device-tree node of the interrupt controller + * @info: MSI domain info + * @parent: Parent irq domain + * + * Updates the domain and chip ops and creates a platform MSI + * interrupt domain. + * + * Returns: + * A domain pointer or NULL in case of failure. + */ +struct irq_domain *platform_msi_create_irq_domain(struct device_node *np, + struct msi_domain_info *info, + struct irq_domain *parent) +{ + struct irq_domain *domain; + + if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) + platform_msi_update_dom_ops(info); + if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) + platform_msi_update_chip_ops(info); + + domain = msi_create_irq_domain(np, info, parent); + if (domain) + domain->bus_token = DOMAIN_BUS_PLATFORM_MSI; + + return domain; +} + +/** + * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev + * @dev: The device for which to allocate interrupts + * @nvec: The number of interrupts to allocate + * @write_msi_msg: Callback to write an interrupt message for @dev + * + * Returns: + * Zero for success, or an error code in case of failure + */ +int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, + irq_write_msi_msg_t write_msi_msg) +{ + struct platform_msi_priv_data *priv_data; + int err; + + /* + * Limit the number of interrupts to 256 per device. Should we + * need to bump this up, DEV_ID_SHIFT should be adjusted + * accordingly (which would impact the max number of MSI + * capable devices). + */ + if (!dev->msi_domain || !write_msi_msg || !nvec || + nvec > (1 << (32 - DEV_ID_SHIFT))) + return -EINVAL; + + if (dev->msi_domain->bus_token != DOMAIN_BUS_PLATFORM_MSI) { + dev_err(dev, "Incompatible msi_domain, giving up\n"); + return -EINVAL; + } + + /* Already had a helping of MSI? Greed... */ + if (!list_empty(dev_to_msi_list(dev))) + return -EBUSY; + + priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL); + if (!priv_data) + return -ENOMEM; + + priv_data->devid = ida_simple_get(&platform_msi_devid_ida, + 0, 1 << DEV_ID_SHIFT, GFP_KERNEL); + if (priv_data->devid < 0) { + err = priv_data->devid; + goto out_free_data; + } + + priv_data->write_msg = write_msi_msg; + + err = platform_msi_alloc_descs(dev, nvec, priv_data); + if (err) + goto out_free_id; + + err = msi_domain_alloc_irqs(dev->msi_domain, dev, nvec); + if (err) + goto out_free_desc; + + return 0; + +out_free_desc: + platform_msi_free_descs(dev); +out_free_id: + ida_simple_remove(&platform_msi_devid_ida, priv_data->devid); +out_free_data: + kfree(priv_data); + + return err; +} + +/** + * platform_msi_domain_free_irqs - Free MSI interrupts for @dev + * @dev: The device for which to free interrupts + */ +void platform_msi_domain_free_irqs(struct device *dev) +{ + struct msi_desc *desc; + + desc = first_msi_entry(dev); + if (desc) { + struct platform_msi_priv_data *data; + + data = desc->platform.msi_priv_data; + + ida_simple_remove(&platform_msi_devid_ida, data->devid); + kfree(data); + } + + msi_domain_free_irqs(dev->msi_domain, dev); + platform_msi_free_descs(dev); +} diff --git a/include/linux/msi.h b/include/linux/msi.h index f83c87e447bc..809b749f9300 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -15,9 +15,23 @@ extern int pci_msi_ignore_mask; struct irq_data; struct msi_desc; struct pci_dev; +struct platform_msi_priv_data; void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg); void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg); +typedef void (*irq_write_msi_msg_t)(struct msi_desc *desc, + struct msi_msg *msg); + +/** + * platform_msi_desc - Platform device specific msi descriptor data + * @msi_priv_data: Pointer to platform private data + * @msi_index: The index of the MSI descriptor for multi MSI + */ +struct platform_msi_desc { + struct platform_msi_priv_data *msi_priv_data; + u16 msi_index; +}; + /** * struct msi_desc - Descriptor structure for MSI based interrupts * @list: List head for management @@ -36,6 +50,7 @@ void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg); * @default_irq:[PCI MSI/X] The default pre-assigned non-MSI irq * @mask_pos: [PCI MSI] Mask register position * @mask_base: [PCI MSI-X] Mask register base address + * @platform: [platform] Platform device specific msi descriptor data */ struct msi_desc { /* Shared device/bus type independent data */ @@ -71,6 +86,7 @@ struct msi_desc { * anonymous for now as it would require an immediate * tree wide cleanup. */ + struct platform_msi_desc platform; }; }; @@ -257,6 +273,12 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev); struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain); +struct irq_domain *platform_msi_create_irq_domain(struct device_node *np, + struct msi_domain_info *info, + struct irq_domain *parent); +int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, + irq_write_msi_msg_t write_msi_msg); +void platform_msi_domain_free_irqs(struct device *dev); #endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */ #ifdef CONFIG_PCI_MSI_IRQ_DOMAIN -- cgit v1.3-6-gb490 From f130420e51df30891b55efcef24f5358b2fc2b97 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:18 +0100 Subject: irqchip/gicv3-its: Split PCI/MSI code from the core ITS driver It is becoming obvious that having the PCI/MSI code in the same file as the the core ITS code is giving people implementing non-PCI MSI support the wrong kind of idea. In order to make things a bit clearer, let's move the PCI/MSI code out to its own file. Hopefully it will make it clear that whoever thinks of hooking into the core ITS better have a very strong point. We use a temporary entry point that will get removed in a subsequent patch, once the proper infrastructure is added. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-12-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/Makefile | 2 +- drivers/irqchip/irq-gic-v3-its-pci-msi.c | 105 +++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic-v3-its.c | 94 ++++----------------------- include/linux/irqchip/arm-gic-v3.h | 6 ++ 4 files changed, 123 insertions(+), 84 deletions(-) create mode 100644 drivers/irqchip/irq-gic-v3-its-pci-msi.c (limited to 'drivers') diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index b8d4e9691890..0d5f2a98a6ef 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o -obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o +obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o obj-$(CONFIG_ARM_NVIC) += irq-nvic.o obj-$(CONFIG_ARM_VIC) += irq-vic.o obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c new file mode 100644 index 000000000000..76147219da7f --- /dev/null +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved. + * Author: Marc Zyngier + * + * 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, see . + */ + +#include +#include +#include +#include + +#include + +static void its_mask_msi_irq(struct irq_data *d) +{ + pci_msi_mask_irq(d); + irq_chip_mask_parent(d); +} + +static void its_unmask_msi_irq(struct irq_data *d) +{ + pci_msi_unmask_irq(d); + irq_chip_unmask_parent(d); +} + +static struct irq_chip its_msi_irq_chip = { + .name = "ITS-MSI", + .irq_unmask = its_unmask_msi_irq, + .irq_mask = its_mask_msi_irq, + .irq_eoi = irq_chip_eoi_parent, + .irq_write_msi_msg = pci_msi_domain_write_msg, +}; + +struct its_pci_alias { + struct pci_dev *pdev; + u32 dev_id; + u32 count; +}; + +static int its_pci_msi_vec_count(struct pci_dev *pdev) +{ + int msi, msix; + + msi = max(pci_msi_vec_count(pdev), 0); + msix = max(pci_msix_vec_count(pdev), 0); + + return max(msi, msix); +} + +static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data) +{ + struct its_pci_alias *dev_alias = data; + + dev_alias->dev_id = alias; + if (pdev != dev_alias->pdev) + dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev); + + return 0; +} + +static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, + int nvec, msi_alloc_info_t *info) +{ + struct pci_dev *pdev; + struct its_pci_alias dev_alias; + + if (!dev_is_pci(dev)) + return -EINVAL; + + pdev = to_pci_dev(dev); + dev_alias.pdev = pdev; + dev_alias.count = nvec; + + pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias); + + return its_msi_prepare(domain, dev_alias.dev_id, dev_alias.count, info); +} + +static struct msi_domain_ops its_pci_msi_ops = { + .msi_prepare = its_pci_msi_prepare, +}; + +static struct msi_domain_info its_pci_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), + .ops = &its_pci_msi_ops, + .chip = &its_msi_irq_chip, +}; + +struct irq_domain *its_pci_msi_alloc_domain(struct device_node *np, + struct irq_domain *parent) +{ + return pci_msi_create_irq_domain(np, &its_pci_msi_domain_info, parent); +} diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 1df956afb937..7f995d876029 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -642,26 +642,6 @@ static struct irq_chip its_irq_chip = { .irq_compose_msi_msg = its_irq_compose_msi_msg, }; -static void its_mask_msi_irq(struct irq_data *d) -{ - pci_msi_mask_irq(d); - irq_chip_mask_parent(d); -} - -static void its_unmask_msi_irq(struct irq_data *d) -{ - pci_msi_unmask_irq(d); - irq_chip_unmask_parent(d); -} - -static struct irq_chip its_msi_irq_chip = { - .name = "ITS-MSI", - .irq_unmask = its_unmask_msi_irq, - .irq_mask = its_mask_msi_irq, - .irq_eoi = irq_chip_eoi_parent, - .irq_write_msi_msg = pci_msi_domain_write_msg, -}; - /* * How we allocate LPIs: * @@ -1208,85 +1188,34 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq) return 0; } -struct its_pci_alias { - struct pci_dev *pdev; - u32 dev_id; - u32 count; -}; - -static int its_pci_msi_vec_count(struct pci_dev *pdev) -{ - int msi, msix; - - msi = max(pci_msi_vec_count(pdev), 0); - msix = max(pci_msix_vec_count(pdev), 0); - - return max(msi, msix); -} - -static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data) +int its_msi_prepare(struct irq_domain *domain, u32 dev_id, + int nvec, msi_alloc_info_t *info) { - struct its_pci_alias *dev_alias = data; - - dev_alias->dev_id = alias; - if (pdev != dev_alias->pdev) - dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev); - - return 0; -} - -static int its_msi_prepare(struct irq_domain *domain, struct device *dev, - int nvec, msi_alloc_info_t *info) -{ - struct pci_dev *pdev; struct its_node *its; struct its_device *its_dev; - struct its_pci_alias dev_alias; - - if (!dev_is_pci(dev)) - return -EINVAL; - - pdev = to_pci_dev(dev); - dev_alias.pdev = pdev; - dev_alias.count = nvec; - pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias); its = domain->parent->host_data; - - its_dev = its_find_device(its, dev_alias.dev_id); + its_dev = its_find_device(its, dev_id); if (its_dev) { /* * We already have seen this ID, probably through * another alias (PCI bridge of some sort). No need to * create the device. */ - dev_dbg(dev, "Reusing ITT for devID %x\n", dev_alias.dev_id); + pr_debug("Reusing ITT for devID %x\n", dev_id); goto out; } - its_dev = its_create_device(its, dev_alias.dev_id, dev_alias.count); + its_dev = its_create_device(its, dev_id, nvec); if (!its_dev) return -ENOMEM; - dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n", - dev_alias.count, ilog2(dev_alias.count)); + pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec)); out: info->scratchpad[0].ptr = its_dev; - info->scratchpad[1].ptr = dev; return 0; } -static struct msi_domain_ops its_pci_msi_ops = { - .msi_prepare = its_msi_prepare, -}; - -static struct msi_domain_info its_pci_msi_domain_info = { - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), - .ops = &its_pci_msi_ops, - .chip = &its_msi_irq_chip, -}; - static int its_irq_gic_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) @@ -1322,9 +1251,9 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq, &its_irq_chip, its_dev); - dev_dbg(info->scratchpad[1].ptr, "ID:%d pID:%d vID:%d\n", - (int)(hwirq - its_dev->event_map.lpi_base), - (int)hwirq, virq + i); + pr_debug("ID:%d pID:%d vID:%d\n", + (int)(hwirq - its_dev->event_map.lpi_base), + (int) hwirq, virq + i); } return 0; @@ -1523,9 +1452,8 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) its->domain->parent = parent; - its->msi_chip.domain = pci_msi_create_irq_domain(node, - &its_pci_msi_domain_info, - its->domain); + its->msi_chip.domain = its_pci_msi_alloc_domain(node, + its->domain); if (!its->msi_chip.domain) { err = -ENOMEM; goto out_free_domains; diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index ffbc034c8810..d6149baaf643 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -360,6 +360,7 @@ #ifndef __ASSEMBLY__ #include +#include /* * We need a value to serve as a irq-type for LPIs. Choose one that will @@ -388,6 +389,11 @@ struct irq_domain; int its_cpu_init(void); int its_init(struct device_node *node, struct rdists *rdists, struct irq_domain *domain); +int its_msi_prepare(struct irq_domain *domain, u32 dev_id, + int nvec, msi_alloc_info_t *info); + +struct irq_domain *its_pci_msi_alloc_domain(struct device_node *node, + struct irq_domain *parent); #endif -- cgit v1.3-6-gb490 From e55dcd4d8b8b82e4ecef2937c6d1dde7ba82916b Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:19 +0100 Subject: irqchip/gicv3-its: Register irq domain with NEXUS token Now that we can distinguish between multiple domains carrying the same device_node, tag the raw ITS domain with DOMAIN_BUS_NEXUS. This will allow MSI providers built on top of the raw ITS domain to identify it. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-13-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic-v3-its.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 7f995d876029..58dc70e72c45 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1444,13 +1444,14 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) { - its->domain = irq_domain_add_tree(NULL, &its_domain_ops, its); + its->domain = irq_domain_add_tree(node, &its_domain_ops, its); if (!its->domain) { err = -ENOMEM; goto out_free_tables; } its->domain->parent = parent; + its->domain->bus_token = DOMAIN_BUS_NEXUS; its->msi_chip.domain = its_pci_msi_alloc_domain(node, its->domain); -- cgit v1.3-6-gb490 From 841514ab41ced765158d71d818b1d564ebe9436d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:20 +0100 Subject: irqchip/gicv3-its: Get rid of struct msi_controller The GICv3 ITS only uses the msi_controller structure as a way to match the host bridge with its MSI HW, and thus the msi_domain. But now that we can directly associate an msi_domain with a device, there is no use keeping this msi_controller around. Just remove all traces of msi_controller from the driver. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-14-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic-v3-its.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 58dc70e72c45..dc4fbbfa0212 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -53,13 +53,12 @@ struct its_collection { /* * The ITS structure - contains most of the infrastructure, with the - * msi_controller, the command queue, the collections, and the list of - * devices writing to it. + * top-level MSI domain, the command queue, the collections, and the + * list of devices writing to it. */ struct its_node { raw_spinlock_t lock; struct list_head entry; - struct msi_controller msi_chip; struct irq_domain *domain; void __iomem *base; unsigned long phys_base; @@ -810,7 +809,7 @@ static void its_free_tables(struct its_node *its) } } -static int its_alloc_tables(struct its_node *its) +static int its_alloc_tables(const char *node_name, struct its_node *its) { int err; int i; @@ -853,7 +852,7 @@ static int its_alloc_tables(struct its_node *its) if (order >= MAX_ORDER) { order = MAX_ORDER - 1; pr_warn("%s: Device Table too large, reduce its page order to %u\n", - its->msi_chip.of_node->full_name, order); + node_name, order); } } @@ -923,7 +922,7 @@ retry_baser: if (val != tmp) { pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n", - its->msi_chip.of_node->full_name, i, + node_name, i, (unsigned long) val, (unsigned long) tmp); err = -ENXIO; goto out_free; @@ -1354,6 +1353,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) struct resource res; struct its_node *its; void __iomem *its_base; + struct irq_domain *inner_domain = NULL; u32 val; u64 baser, tmp; int err; @@ -1397,7 +1397,6 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) INIT_LIST_HEAD(&its->its_device_list); its->base = its_base; its->phys_base = res.start; - its->msi_chip.of_node = node; its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1; its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL); @@ -1407,7 +1406,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) } its->cmd_write = its->cmd_base; - err = its_alloc_tables(its); + err = its_alloc_tables(node->full_name, its); if (err) goto out_free_cmd; @@ -1443,26 +1442,21 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) writeq_relaxed(0, its->base + GITS_CWRITER); writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); - if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) { - its->domain = irq_domain_add_tree(node, &its_domain_ops, its); - if (!its->domain) { + if (of_property_read_bool(node, "msi-controller")) { + inner_domain = irq_domain_add_tree(node, &its_domain_ops, its); + if (!inner_domain) { err = -ENOMEM; goto out_free_tables; } - its->domain->parent = parent; - its->domain->bus_token = DOMAIN_BUS_NEXUS; + inner_domain->parent = parent; + inner_domain->bus_token = DOMAIN_BUS_NEXUS; - its->msi_chip.domain = its_pci_msi_alloc_domain(node, - its->domain); - if (!its->msi_chip.domain) { + its->domain = its_pci_msi_alloc_domain(node, inner_domain); + if (!its->domain) { err = -ENOMEM; goto out_free_domains; } - - err = of_pci_msi_chip_add(&its->msi_chip); - if (err) - goto out_free_domains; } spin_lock(&its_lock); @@ -1472,10 +1466,10 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) return 0; out_free_domains: - if (its->msi_chip.domain) - irq_domain_remove(its->msi_chip.domain); if (its->domain) irq_domain_remove(its->domain); + if (inner_domain) + irq_domain_remove(inner_domain); out_free_tables: its_free_tables(its); out_free_cmd: -- cgit v1.3-6-gb490 From 54456db9a23753b87ce4d49adabe7da853bf13a2 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:21 +0100 Subject: irqchip/gicv3-its: Make the PCI/MSI code standalone We can now lookup the base ITS domain, making it possible to initialize the PCI/MSI code independently from the main ITS subsystem. This allows us to remove all the previously add hooks. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-15-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic-v3-its-pci-msi.c | 47 +++++++++++++++++++++++++++---- drivers/irqchip/irq-gic-v3-its.c | 48 +++++++++++++++++++++----------- include/linux/irqchip/arm-gic-v3.h | 5 ---- 3 files changed, 73 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c index 76147219da7f..cf351c637464 100644 --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -20,8 +20,6 @@ #include #include -#include - static void its_mask_msi_irq(struct irq_data *d) { pci_msi_mask_irq(d); @@ -74,17 +72,24 @@ static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, { struct pci_dev *pdev; struct its_pci_alias dev_alias; + struct msi_domain_info *msi_info; if (!dev_is_pci(dev)) return -EINVAL; + msi_info = msi_get_domain_info(domain->parent); + pdev = to_pci_dev(dev); dev_alias.pdev = pdev; dev_alias.count = nvec; pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias); - return its_msi_prepare(domain, dev_alias.dev_id, dev_alias.count, info); + /* ITS specific DeviceID, as the core ITS ignores dev. */ + info->scratchpad[0].ul = dev_alias.dev_id; + + return msi_info->ops->msi_prepare(domain->parent, + dev, dev_alias.count, info); } static struct msi_domain_ops its_pci_msi_ops = { @@ -98,8 +103,38 @@ static struct msi_domain_info its_pci_msi_domain_info = { .chip = &its_msi_irq_chip, }; -struct irq_domain *its_pci_msi_alloc_domain(struct device_node *np, - struct irq_domain *parent) +static struct of_device_id its_device_id[] = { + { .compatible = "arm,gic-v3-its", }, + {}, +}; + +static int __init its_pci_msi_init(void) { - return pci_msi_create_irq_domain(np, &its_pci_msi_domain_info, parent); + struct device_node *np; + struct irq_domain *parent; + + for (np = of_find_matching_node(NULL, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { + if (!of_property_read_bool(np, "msi-controller")) + continue; + + parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS); + if (!parent || !msi_get_domain_info(parent)) { + pr_err("%s: unable to locate ITS domain\n", + np->full_name); + continue; + } + + if (!pci_msi_create_irq_domain(np, &its_pci_msi_domain_info, + parent)) { + pr_err("%s: unable to create PCI domain\n", + np->full_name); + continue; + } + + pr_info("PCI/MSI: %s domain created\n", np->full_name); + } + + return 0; } +early_initcall(its_pci_msi_init); diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index dc4fbbfa0212..26b55c53755f 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -59,7 +59,6 @@ struct its_collection { struct its_node { raw_spinlock_t lock; struct list_head entry; - struct irq_domain *domain; void __iomem *base; unsigned long phys_base; struct its_cmd_block *cmd_base; @@ -1187,13 +1186,25 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq) return 0; } -int its_msi_prepare(struct irq_domain *domain, u32 dev_id, - int nvec, msi_alloc_info_t *info) +static int its_msi_prepare(struct irq_domain *domain, struct device *dev, + int nvec, msi_alloc_info_t *info) { struct its_node *its; struct its_device *its_dev; + struct msi_domain_info *msi_info; + u32 dev_id; + + /* + * We ignore "dev" entierely, and rely on the dev_id that has + * been passed via the scratchpad. This limits this domain's + * usefulness to upper layers that definitely know that they + * are built on top of the ITS. + */ + dev_id = info->scratchpad[0].ul; + + msi_info = msi_get_domain_info(domain); + its = msi_info->data; - its = domain->parent->host_data; its_dev = its_find_device(its, dev_id); if (its_dev) { /* @@ -1215,6 +1226,10 @@ out: return 0; } +static struct msi_domain_ops its_msi_domain_ops = { + .msi_prepare = its_msi_prepare, +}; + static int its_irq_gic_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) @@ -1353,7 +1368,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) struct resource res; struct its_node *its; void __iomem *its_base; - struct irq_domain *inner_domain = NULL; + struct irq_domain *inner_domain; u32 val; u64 baser, tmp; int err; @@ -1443,20 +1458,26 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); if (of_property_read_bool(node, "msi-controller")) { + struct msi_domain_info *info; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + err = -ENOMEM; + goto out_free_tables; + } + inner_domain = irq_domain_add_tree(node, &its_domain_ops, its); if (!inner_domain) { err = -ENOMEM; + kfree(info); goto out_free_tables; } inner_domain->parent = parent; inner_domain->bus_token = DOMAIN_BUS_NEXUS; - - its->domain = its_pci_msi_alloc_domain(node, inner_domain); - if (!its->domain) { - err = -ENOMEM; - goto out_free_domains; - } + info->ops = &its_msi_domain_ops; + info->data = its; + inner_domain->host_data = info; } spin_lock(&its_lock); @@ -1465,11 +1486,6 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) return 0; -out_free_domains: - if (its->domain) - irq_domain_remove(its->domain); - if (inner_domain) - irq_domain_remove(inner_domain); out_free_tables: its_free_tables(its); out_free_cmd: diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index d6149baaf643..bf982e021fbd 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -389,11 +389,6 @@ struct irq_domain; int its_cpu_init(void); int its_init(struct device_node *node, struct rdists *rdists, struct irq_domain *domain); -int its_msi_prepare(struct irq_domain *domain, u32 dev_id, - int nvec, msi_alloc_info_t *info); - -struct irq_domain *its_pci_msi_alloc_domain(struct device_node *node, - struct irq_domain *parent); #endif -- cgit v1.3-6-gb490 From 1e6db000482fa65a419d1776f9ae1ff919afe605 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:22 +0100 Subject: irqchip/gicv3-its: Add platform MSI support In order to support non-PCI MSI with the GICv3 ITS, add the minimal required entry points for the MSI domain (an msi_prepare implementation). The rest is only boilerplate code to find the raw ITS domain. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-16-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/Makefile | 2 +- drivers/irqchip/irq-gic-v3-its-platform-msi.c | 93 +++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 drivers/irqchip/irq-gic-v3-its-platform-msi.c (limited to 'drivers') diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 0d5f2a98a6ef..11d08c9a0724 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o -obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o +obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o obj-$(CONFIG_ARM_NVIC) += irq-nvic.o obj-$(CONFIG_ARM_VIC) += irq-vic.o obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c new file mode 100644 index 000000000000..a86550562779 --- /dev/null +++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved. + * Author: Marc Zyngier + * + * 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, see . + */ + +#include +#include +#include +#include + +static struct irq_chip its_pmsi_irq_chip = { + .name = "ITS-pMSI", +}; + +static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev, + int nvec, msi_alloc_info_t *info) +{ + struct msi_domain_info *msi_info; + u32 dev_id; + int ret; + + msi_info = msi_get_domain_info(domain->parent); + + /* Suck the DeviceID out of the msi-parent property */ + ret = of_property_read_u32_index(dev->of_node, "msi-parent", + 1, &dev_id); + if (ret) + return ret; + + /* ITS specific DeviceID, as the core ITS ignores dev. */ + info->scratchpad[0].ul = dev_id; + + return msi_info->ops->msi_prepare(domain->parent, + dev, nvec, info); +} + +static struct msi_domain_ops its_pmsi_ops = { + .msi_prepare = its_pmsi_prepare, +}; + +static struct msi_domain_info its_pmsi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), + .ops = &its_pmsi_ops, + .chip = &its_pmsi_irq_chip, +}; + +static struct of_device_id its_device_id[] = { + { .compatible = "arm,gic-v3-its", }, + {}, +}; + +static int __init its_pmsi_init(void) +{ + struct device_node *np; + struct irq_domain *parent; + + for (np = of_find_matching_node(NULL, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { + if (!of_property_read_bool(np, "msi-controller")) + continue; + + parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS); + if (!parent || !msi_get_domain_info(parent)) { + pr_err("%s: unable to locate ITS domain\n", + np->full_name); + continue; + } + + if (!platform_msi_create_irq_domain(np, &its_pmsi_domain_info, + parent)) { + pr_err("%s: unable to create platform domain\n", + np->full_name); + continue; + } + + pr_info("Platform MSI: %s domain created\n", np->full_name); + } + + return 0; +} +early_initcall(its_pmsi_init); -- cgit v1.3-6-gb490 From 5cedceb37c253c6181dbdd4bfe1b9d792e51fd37 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:23 +0100 Subject: irqchip/GICv2m: Get rid of struct msi_controller GICv2m only uses the msi_controller structure as a way to match the host bridge with its MSI HW, and thus the msi_domain. But now that we can directly associate an msi_domain with a device, there is no use keeping this msi_controller around. Just remove all traces of msi_controller from the driver. Also tag the inner (non-PCI) domain with DOMAIN_BUS_NEXUS. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-17-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic-v2m.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index fdf706555d72..ec9c37674a0b 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -45,7 +45,6 @@ struct v2m_data { spinlock_t msi_cnt_lock; - struct msi_controller mchip; struct resource res; /* GICv2m resource */ void __iomem *base; /* GICv2m virt address */ u32 spi_start; /* The SPI number that MSIs start */ @@ -218,6 +217,7 @@ static int __init gicv2m_init_one(struct device_node *node, { int ret; struct v2m_data *v2m; + struct irq_domain *inner_domain; v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL); if (!v2m) { @@ -261,19 +261,18 @@ static int __init gicv2m_init_one(struct device_node *node, goto err_iounmap; } - v2m->domain = irq_domain_add_tree(NULL, &gicv2m_domain_ops, v2m); - if (!v2m->domain) { + inner_domain = irq_domain_add_tree(node, &gicv2m_domain_ops, v2m); + if (!inner_domain) { pr_err("Failed to create GICv2m domain\n"); ret = -ENOMEM; goto err_free_bm; } - v2m->domain->parent = parent; - v2m->mchip.of_node = node; - v2m->mchip.domain = pci_msi_create_irq_domain(node, - &gicv2m_msi_domain_info, - v2m->domain); - if (!v2m->mchip.domain) { + inner_domain->bus_token = DOMAIN_BUS_NEXUS; + inner_domain->parent = parent; + v2m->domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info, + inner_domain); + if (!v2m->domain) { pr_err("Failed to create MSI domain\n"); ret = -ENOMEM; goto err_free_domains; @@ -281,12 +280,6 @@ static int __init gicv2m_init_one(struct device_node *node, spin_lock_init(&v2m->msi_cnt_lock); - ret = of_pci_msi_chip_add(&v2m->mchip); - if (ret) { - pr_err("Failed to add msi_chip.\n"); - goto err_free_domains; - } - pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name, (unsigned long)v2m->res.start, (unsigned long)v2m->res.end, v2m->spi_start, (v2m->spi_start + v2m->nr_spis)); @@ -294,10 +287,10 @@ static int __init gicv2m_init_one(struct device_node *node, return 0; err_free_domains: - if (v2m->mchip.domain) - irq_domain_remove(v2m->mchip.domain); if (v2m->domain) irq_domain_remove(v2m->domain); + if (inner_domain) + irq_domain_remove(inner_domain); err_free_bm: kfree(v2m->bm); err_iounmap: -- cgit v1.3-6-gb490 From ef50645aa32c6b55fe1445b5d06c73bfdf65019f Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:24 +0100 Subject: irqchip/GICv2m: Add platform MSI support In order to support non-PCI MSI with GICv2m, add the minimal required entry points for the MSI domain, which is actually almost nothing (we just use the defaults provided by the core code). Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-18-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic-v2m.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index ec9c37674a0b..db04fc1f56b2 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -50,7 +50,6 @@ struct v2m_data { u32 spi_start; /* The SPI number that MSIs start */ u32 nr_spis; /* The number of SPIs for MSIs */ unsigned long *bm; /* MSI vector bitmap */ - struct irq_domain *domain; }; static void gicv2m_mask_msi_irq(struct irq_data *d) @@ -212,12 +211,25 @@ static bool is_msi_spi_valid(u32 base, u32 num) return true; } +static struct irq_chip gicv2m_pmsi_irq_chip = { + .name = "pMSI", +}; + +static struct msi_domain_ops gicv2m_pmsi_ops = { +}; + +static struct msi_domain_info gicv2m_pmsi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), + .ops = &gicv2m_pmsi_ops, + .chip = &gicv2m_pmsi_irq_chip, +}; + static int __init gicv2m_init_one(struct device_node *node, struct irq_domain *parent) { int ret; struct v2m_data *v2m; - struct irq_domain *inner_domain; + struct irq_domain *inner_domain, *pci_domain, *plat_domain; v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL); if (!v2m) { @@ -270,10 +282,13 @@ static int __init gicv2m_init_one(struct device_node *node, inner_domain->bus_token = DOMAIN_BUS_NEXUS; inner_domain->parent = parent; - v2m->domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info, - inner_domain); - if (!v2m->domain) { - pr_err("Failed to create MSI domain\n"); + pci_domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info, + inner_domain); + plat_domain = platform_msi_create_irq_domain(node, + &gicv2m_pmsi_domain_info, + inner_domain); + if (!pci_domain || !plat_domain) { + pr_err("Failed to create MSI domains\n"); ret = -ENOMEM; goto err_free_domains; } @@ -287,8 +302,10 @@ static int __init gicv2m_init_one(struct device_node *node, return 0; err_free_domains: - if (v2m->domain) - irq_domain_remove(v2m->domain); + if (plat_domain) + irq_domain_remove(plat_domain); + if (pci_domain) + irq_domain_remove(pci_domain); if (inner_domain) irq_domain_remove(inner_domain); err_free_bm: -- cgit v1.3-6-gb490 From 8d63bc7beaeecdc2dfafed69c3555471fbe4aee7 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:25 +0100 Subject: PCI/MSI: pci-xgene-msi: Get rid of struct msi_controller The X-Gene MSI driver only uses the msi_controller structure as a way to match the host bridge with its MSI HW, and thus the msi_domain. But now that we can directly associate an msi_domain with a device, there is no use keeping this msi_controller around. Just remove all traces of msi_controller from the driver. Tested-by: Duc Dang Acked-by: Bjorn Helgaas Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Hanjun Guo Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-19-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/pci/host/pci-xgene-msi.c | 41 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-xgene-msi.c b/drivers/pci/host/pci-xgene-msi.c index 2d31d4d6fd08..ec5a14b3189b 100644 --- a/drivers/pci/host/pci-xgene-msi.c +++ b/drivers/pci/host/pci-xgene-msi.c @@ -40,8 +40,8 @@ struct xgene_msi_group { struct xgene_msi { struct device_node *node; - struct msi_controller mchip; - struct irq_domain *domain; + struct irq_domain *inner_domain; + struct irq_domain *msi_domain; u64 msi_addr; void __iomem *msi_regs; unsigned long *bitmap; @@ -252,17 +252,17 @@ static const struct irq_domain_ops msi_domain_ops = { static int xgene_allocate_domains(struct xgene_msi *msi) { - msi->domain = irq_domain_add_linear(NULL, NR_MSI_VEC, - &msi_domain_ops, msi); - if (!msi->domain) + msi->inner_domain = irq_domain_add_linear(NULL, NR_MSI_VEC, + &msi_domain_ops, msi); + if (!msi->inner_domain) return -ENOMEM; - msi->mchip.domain = pci_msi_create_irq_domain(msi->mchip.of_node, - &xgene_msi_domain_info, - msi->domain); + msi->msi_domain = pci_msi_create_irq_domain(msi->node, + &xgene_msi_domain_info, + msi->inner_domain); - if (!msi->mchip.domain) { - irq_domain_remove(msi->domain); + if (!msi->msi_domain) { + irq_domain_remove(msi->inner_domain); return -ENOMEM; } @@ -271,10 +271,10 @@ static int xgene_allocate_domains(struct xgene_msi *msi) static void xgene_free_domains(struct xgene_msi *msi) { - if (msi->mchip.domain) - irq_domain_remove(msi->mchip.domain); - if (msi->domain) - irq_domain_remove(msi->domain); + if (msi->msi_domain) + irq_domain_remove(msi->msi_domain); + if (msi->inner_domain) + irq_domain_remove(msi->inner_domain); } static int xgene_msi_init_allocator(struct xgene_msi *xgene_msi) @@ -340,7 +340,7 @@ static void xgene_msi_isr(unsigned int irq, struct irq_desc *desc) * CPU0 */ hw_irq = hwirq_to_canonical_hwirq(hw_irq); - virq = irq_find_mapping(xgene_msi->domain, hw_irq); + virq = irq_find_mapping(xgene_msi->inner_domain, hw_irq); WARN_ON(!virq); if (virq != 0) generic_handle_irq(virq); @@ -497,7 +497,7 @@ static int xgene_msi_probe(struct platform_device *pdev) goto error; } xgene_msi->msi_addr = res->start; - + xgene_msi->node = pdev->dev.of_node; xgene_msi->num_cpus = num_possible_cpus(); rc = xgene_msi_init_allocator(xgene_msi); @@ -561,19 +561,10 @@ static int xgene_msi_probe(struct platform_device *pdev) cpu_notifier_register_done(); - xgene_msi->mchip.of_node = pdev->dev.of_node; - rc = of_pci_msi_chip_add(&xgene_msi->mchip); - if (rc) { - dev_err(&pdev->dev, "failed to add MSI controller chip\n"); - goto error_notifier; - } - dev_info(&pdev->dev, "APM X-Gene PCIe MSI driver loaded\n"); return 0; -error_notifier: - unregister_hotcpu_notifier(&xgene_msi_cpu_notifier); error: xgene_msi_remove(pdev); return rc; -- cgit v1.3-6-gb490 From f075915ac0b11847fcfc8c4d55526a317e71c4d1 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:26 +0100 Subject: PCI/MSI: Drop domain field from msi_controller The only three users of that field are not using the msi_controller structure anymore, so drop it altogether. Acked-by: Bjorn Helgaas Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-20-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/pci/msi.c | 3 --- include/linux/msi.h | 3 --- 2 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 460334409794..f70aa0f5cbaf 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -45,9 +45,6 @@ static struct irq_domain *pci_msi_get_domain(struct pci_dev *dev) if (domain) return domain; - if (dev->bus->msi && (domain = dev->bus->msi->domain)) - return domain; - return arch_get_pci_msi_domain(dev); } diff --git a/include/linux/msi.h b/include/linux/msi.h index 809b749f9300..ad939d0ba816 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -160,9 +160,6 @@ struct msi_controller { struct device *dev; struct device_node *of_node; struct list_head list; -#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN - struct irq_domain *domain; -#endif int (*setup_irq)(struct msi_controller *chip, struct pci_dev *dev, struct msi_desc *desc); -- cgit v1.3-6-gb490 From 71382bc0431ea5901640a3794fea4eeb71cbcb2e Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Tue, 28 Jul 2015 16:01:11 -0400 Subject: net: netcp: Fixes efuse mac addr swap on k2e and k2l On some of the K2E and K2L platforms, the two DWORDs in efuse occupied by the pre-programmed mac address for slave port 1 are swapped. To workaround this issue, this patch adds a new define NETCP_EFUSE_ADDR_SWAP (2) which signifies the occurrence of such swapping so that the driver can take proper action. The flag can be enabled in the corresponding netcp interface dts binding as efuse-mac = <2> under the corresponding netcp interface node. Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/keystone-netcp.txt | 6 +++++- drivers/net/ethernet/ti/netcp_core.c | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/net/keystone-netcp.txt b/Documentation/devicetree/bindings/net/keystone-netcp.txt index d0e6fa38f335..b30ab6b5cbfa 100644 --- a/Documentation/devicetree/bindings/net/keystone-netcp.txt +++ b/Documentation/devicetree/bindings/net/keystone-netcp.txt @@ -130,7 +130,11 @@ Required properties: Optional properties: - efuse-mac: If this is 1, then the MAC address for the interface is - obtained from the device efuse mac address register + obtained from the device efuse mac address register. + If this is 2, the two DWORDs occupied by the MAC address + are swapped. The netcp driver will swap the two DWORDs + back to the proper order when this property is set to 2 + when it obtains the mac address from efuse. - local-mac-address: the driver is designed to use the of_get_mac_address api only if efuse-mac is 0. When efuse-mac is 0, the MAC address is obtained from local-mac-address. If this diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c index 3ca87f26582a..6f2e151fbc73 100644 --- a/drivers/net/ethernet/ti/netcp_core.c +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -51,6 +51,8 @@ NETIF_MSG_PKTDATA | NETIF_MSG_TX_QUEUED | \ NETIF_MSG_RX_STATUS) +#define NETCP_EFUSE_ADDR_SWAP 2 + #define knav_queue_get_id(q) knav_queue_device_control(q, \ KNAV_QUEUE_GET_ID, (unsigned long)NULL) @@ -172,13 +174,22 @@ static void set_words(u32 *words, int num_words, u32 *desc) } /* Read the e-fuse value as 32 bit values to be endian independent */ -static int emac_arch_get_mac_addr(char *x, void __iomem *efuse_mac) +static int emac_arch_get_mac_addr(char *x, void __iomem *efuse_mac, u32 swap) { unsigned int addr0, addr1; addr1 = readl(efuse_mac + 4); addr0 = readl(efuse_mac); + switch (swap) { + case NETCP_EFUSE_ADDR_SWAP: + addr0 = addr1; + addr1 = readl(efuse_mac); + break; + default: + break; + } + x[0] = (addr1 & 0x0000ff00) >> 8; x[1] = addr1 & 0x000000ff; x[2] = (addr0 & 0xff000000) >> 24; @@ -1902,7 +1913,7 @@ static int netcp_create_interface(struct netcp_device *netcp_device, goto quit; } - emac_arch_get_mac_addr(efuse_mac_addr, efuse); + emac_arch_get_mac_addr(efuse_mac_addr, efuse, efuse_mac); if (is_valid_ether_addr(efuse_mac_addr)) ether_addr_copy(ndev->dev_addr, efuse_mac_addr); else -- cgit v1.3-6-gb490 From a6d678645210f187a23c4715579a34152ce10af6 Mon Sep 17 00:00:00 2001 From: Radha Mohan Chintakuntla Date: Tue, 28 Jul 2015 15:12:11 -0700 Subject: net: mdio-octeon: Modify driver to work on both ThunderX and Octeon This patch modifies the mdio-octeon driver to work on both ThunderX and Octeon SoCs from Cavium Inc. Signed-off-by: Sunil Goutham Signed-off-by: Radha Mohan Chintakuntla Signed-off-by: David Daney Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 10 ++-- drivers/net/phy/mdio-octeon.c | 122 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 111 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index d6aff873803c..8ef819144220 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -150,13 +150,13 @@ config MDIO_GPIO will be called mdio-gpio. config MDIO_OCTEON - tristate "Support for MDIO buses on Octeon SOCs" - depends on CAVIUM_OCTEON_SOC - default y + tristate "Support for MDIO buses on Octeon and ThunderX SOCs" + depends on 64BIT help - This module provides a driver for the Octeon MDIO busses. - It is required by the Octeon Ethernet device drivers. + This module provides a driver for the Octeon and ThunderX MDIO + busses. It is required by the Octeon and ThunderX ethernet device + drivers. If in doubt, say Y. diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c index c838ad6155f7..1509937e93c0 100644 --- a/drivers/net/phy/mdio-octeon.c +++ b/drivers/net/phy/mdio-octeon.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -14,11 +15,12 @@ #include #include +#ifdef CONFIG_CAVIUM_OCTEON_SOC #include -#include +#endif -#define DRV_VERSION "1.0" -#define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver" +#define DRV_VERSION "1.1" +#define DRV_DESCRIPTION "Cavium Networks Octeon/ThunderX SMI/MDIO driver" #define SMI_CMD 0x0 #define SMI_WR_DAT 0x8 @@ -26,6 +28,79 @@ #define SMI_CLK 0x18 #define SMI_EN 0x20 +#ifdef __BIG_ENDIAN_BITFIELD +#define OCT_MDIO_BITFIELD_FIELD(field, more) \ + field; \ + more + +#else +#define OCT_MDIO_BITFIELD_FIELD(field, more) \ + more \ + field; + +#endif + +union cvmx_smix_clk { + u64 u64; + struct cvmx_smix_clk_s { + OCT_MDIO_BITFIELD_FIELD(u64 reserved_25_63:39, + OCT_MDIO_BITFIELD_FIELD(u64 mode:1, + OCT_MDIO_BITFIELD_FIELD(u64 reserved_21_23:3, + OCT_MDIO_BITFIELD_FIELD(u64 sample_hi:5, + OCT_MDIO_BITFIELD_FIELD(u64 sample_mode:1, + OCT_MDIO_BITFIELD_FIELD(u64 reserved_14_14:1, + OCT_MDIO_BITFIELD_FIELD(u64 clk_idle:1, + OCT_MDIO_BITFIELD_FIELD(u64 preamble:1, + OCT_MDIO_BITFIELD_FIELD(u64 sample:4, + OCT_MDIO_BITFIELD_FIELD(u64 phase:8, + ;)))))))))) + } s; +}; + +union cvmx_smix_cmd { + u64 u64; + struct cvmx_smix_cmd_s { + OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46, + OCT_MDIO_BITFIELD_FIELD(u64 phy_op:2, + OCT_MDIO_BITFIELD_FIELD(u64 reserved_13_15:3, + OCT_MDIO_BITFIELD_FIELD(u64 phy_adr:5, + OCT_MDIO_BITFIELD_FIELD(u64 reserved_5_7:3, + OCT_MDIO_BITFIELD_FIELD(u64 reg_adr:5, + ;)))))) + } s; +}; + +union cvmx_smix_en { + u64 u64; + struct cvmx_smix_en_s { + OCT_MDIO_BITFIELD_FIELD(u64 reserved_1_63:63, + OCT_MDIO_BITFIELD_FIELD(u64 en:1, + ;)) + } s; +}; + +union cvmx_smix_rd_dat { + u64 u64; + struct cvmx_smix_rd_dat_s { + OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46, + OCT_MDIO_BITFIELD_FIELD(u64 pending:1, + OCT_MDIO_BITFIELD_FIELD(u64 val:1, + OCT_MDIO_BITFIELD_FIELD(u64 dat:16, + ;)))) + } s; +}; + +union cvmx_smix_wr_dat { + u64 u64; + struct cvmx_smix_wr_dat_s { + OCT_MDIO_BITFIELD_FIELD(u64 reserved_18_63:46, + OCT_MDIO_BITFIELD_FIELD(u64 pending:1, + OCT_MDIO_BITFIELD_FIELD(u64 val:1, + OCT_MDIO_BITFIELD_FIELD(u64 dat:16, + ;)))) + } s; +}; + enum octeon_mdiobus_mode { UNINIT = 0, C22, @@ -41,6 +116,21 @@ struct octeon_mdiobus { int phy_irq[PHY_MAX_ADDR]; }; +#ifdef CONFIG_CAVIUM_OCTEON_SOC +static void oct_mdio_writeq(u64 val, u64 addr) +{ + cvmx_write_csr(addr, val); +} + +static u64 oct_mdio_readq(u64 addr) +{ + return cvmx_read_csr(addr); +} +#else +#define oct_mdio_writeq(val, addr) writeq_relaxed(val, (void *)addr) +#define oct_mdio_readq(addr) readq_relaxed((void *)addr) +#endif + static void octeon_mdiobus_set_mode(struct octeon_mdiobus *p, enum octeon_mdiobus_mode m) { @@ -49,10 +139,10 @@ static void octeon_mdiobus_set_mode(struct octeon_mdiobus *p, if (m == p->mode) return; - smi_clk.u64 = cvmx_read_csr(p->register_base + SMI_CLK); + smi_clk.u64 = oct_mdio_readq(p->register_base + SMI_CLK); smi_clk.s.mode = (m == C45) ? 1 : 0; smi_clk.s.preamble = 1; - cvmx_write_csr(p->register_base + SMI_CLK, smi_clk.u64); + oct_mdio_writeq(smi_clk.u64, p->register_base + SMI_CLK); p->mode = m; } @@ -67,7 +157,7 @@ static int octeon_mdiobus_c45_addr(struct octeon_mdiobus *p, smi_wr.u64 = 0; smi_wr.s.dat = regnum & 0xffff; - cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64); + oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); regnum = (regnum >> 16) & 0x1f; @@ -75,14 +165,14 @@ static int octeon_mdiobus_c45_addr(struct octeon_mdiobus *p, smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */ smi_cmd.s.phy_adr = phy_id; smi_cmd.s.reg_adr = regnum; - cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); + oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); do { /* Wait 1000 clocks so we don't saturate the RSL bus * doing reads. */ __delay(1000); - smi_wr.u64 = cvmx_read_csr(p->register_base + SMI_WR_DAT); + smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT); } while (smi_wr.s.pending && --timeout); if (timeout <= 0) @@ -114,14 +204,14 @@ static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum) smi_cmd.s.phy_op = op; smi_cmd.s.phy_adr = phy_id; smi_cmd.s.reg_adr = regnum; - cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); + oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); do { /* Wait 1000 clocks so we don't saturate the RSL bus * doing reads. */ __delay(1000); - smi_rd.u64 = cvmx_read_csr(p->register_base + SMI_RD_DAT); + smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT); } while (smi_rd.s.pending && --timeout); if (smi_rd.s.val) @@ -153,20 +243,20 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id, smi_wr.u64 = 0; smi_wr.s.dat = val; - cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64); + oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); smi_cmd.u64 = 0; smi_cmd.s.phy_op = op; smi_cmd.s.phy_adr = phy_id; smi_cmd.s.reg_adr = regnum; - cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); + oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); do { /* Wait 1000 clocks so we don't saturate the RSL bus * doing reads. */ __delay(1000); - smi_wr.u64 = cvmx_read_csr(p->register_base + SMI_WR_DAT); + smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT); } while (smi_wr.s.pending && --timeout); if (timeout <= 0) @@ -210,7 +300,7 @@ static int octeon_mdiobus_probe(struct platform_device *pdev) smi_en.u64 = 0; smi_en.s.en = 1; - cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64); + oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); bus->mii_bus->priv = bus; bus->mii_bus->irq = bus->phy_irq; @@ -234,7 +324,7 @@ fail_register: mdiobus_free(bus->mii_bus); fail: smi_en.u64 = 0; - cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64); + oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); return err; } @@ -248,7 +338,7 @@ static int octeon_mdiobus_remove(struct platform_device *pdev) mdiobus_unregister(bus->mii_bus); mdiobus_free(bus->mii_bus); smi_en.u64 = 0; - cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64); + oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); return 0; } -- cgit v1.3-6-gb490 From de9e397e40f56b9f34af4bf6a5bd7a75ea02456c Mon Sep 17 00:00:00 2001 From: Radha Mohan Chintakuntla Date: Tue, 28 Jul 2015 15:12:12 -0700 Subject: net: mdio-octeon: Fix octeon_mdiobus_probe function for return values This patch fixes a possible crash in the octeon_mdiobus_probe function if the return values are not handled properly. Signed-off-by: Radha Mohan Chintakuntla Signed-off-by: Tomasz Nowicki Signed-off-by: David S. Miller --- drivers/net/phy/mdio-octeon.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c index 1509937e93c0..fcf4e4df7cc8 100644 --- a/drivers/net/phy/mdio-octeon.c +++ b/drivers/net/phy/mdio-octeon.c @@ -277,24 +277,28 @@ static int octeon_mdiobus_probe(struct platform_device *pdev) return -ENOMEM; res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res_mem == NULL) { dev_err(&pdev->dev, "found no memory resource\n"); - err = -ENXIO; - goto fail; + return -ENXIO; } + bus->mdio_phys = res_mem->start; bus->regsize = resource_size(res_mem); + if (!devm_request_mem_region(&pdev->dev, bus->mdio_phys, bus->regsize, res_mem->name)) { dev_err(&pdev->dev, "request_mem_region failed\n"); - goto fail; + return -ENXIO; } + bus->register_base = (u64)devm_ioremap(&pdev->dev, bus->mdio_phys, bus->regsize); + if (!bus->register_base) { + dev_err(&pdev->dev, "dev_ioremap failed\n"); + return -ENOMEM; + } bus->mii_bus = mdiobus_alloc(); - if (!bus->mii_bus) goto fail; -- cgit v1.3-6-gb490 From 274b0b3984a93d6a2cbc2966a146fa3ed7288b1e Mon Sep 17 00:00:00 2001 From: Radha Mohan Chintakuntla Date: Tue, 28 Jul 2015 15:12:13 -0700 Subject: net: thunderx: Select CONFIG_MDIO_OCTEON for ThunderX NIC The CONFIG_MDIO_OCTEON is required so that the ThunderX NIC driver can talk to the PHY drivers. Signed-off-by: Radha Mohan Chintakuntla Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/Kconfig b/drivers/net/ethernet/cavium/Kconfig index c4d6bbe9458d..358442087878 100644 --- a/drivers/net/ethernet/cavium/Kconfig +++ b/drivers/net/ethernet/cavium/Kconfig @@ -37,6 +37,8 @@ config THUNDER_NIC_BGX tristate "Thunder MAC interface driver (BGX)" depends on 64BIT default ARCH_THUNDER + select PHYLIB + select MDIO_OCTEON ---help--- This driver supports programming and controlling of MAC interface from NIC physical function driver. -- cgit v1.3-6-gb490 From b4b67f269d28c70174e11b7af7fbdb81124d220c Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Wed, 29 Jul 2015 16:13:06 +0300 Subject: gianfar: Fix warnings when built on 64-bit As part of defconfig consolidation using fragments, we'd like to be able to have the same drivers enabled on 32-bit and 64-bit. Gianfar happens to only exist on 32-bit systems, and when building the resulting 64-bit kernel warnings were produced. A couple of the warnings are trivial, but the rfbptr code has deeper issues. It uses the virtual address as the DMA address, which again, happens to work in the environments where this driver is currently used, but is not the right thing to do. Fixes: 45b679c9a3cc ("gianfar: Implement PAUSE frame generation support") Signed-off-by: Scott Wood Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 15 +++++++++------ drivers/net/ethernet/freescale/gianfar.h | 9 +++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 648ca85c5859..afa3ea7ccf76 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2611,7 +2611,8 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) { struct skb_shared_hwtstamps shhwtstamps; - u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7); + u64 *ns = (u64 *)(((uintptr_t)skb->data + 0x10) & + ~0x7UL); memset(&shhwtstamps, 0, sizeof(shhwtstamps)); shhwtstamps.hwtstamp = ns_to_ktime(*ns); @@ -3043,8 +3044,9 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) /* Update Last Free RxBD pointer for LFC */ if (unlikely(priv->tx_actual_en)) { - bdp = gfar_rxbd_lastfree(rx_queue); - gfar_write(rx_queue->rfbptr, (u32)bdp); + u32 bdp_dma = gfar_rxbd_dma_lastfree(rx_queue); + + gfar_write(rx_queue->rfbptr, bdp_dma); } return howmany; @@ -3563,7 +3565,6 @@ static noinline void gfar_update_link_state(struct gfar_private *priv) struct phy_device *phydev = priv->phydev; struct gfar_priv_rx_q *rx_queue = NULL; int i; - struct rxbd8 *bdp; if (unlikely(test_bit(GFAR_RESETTING, &priv->state))) return; @@ -3620,9 +3621,11 @@ static noinline void gfar_update_link_state(struct gfar_private *priv) /* Turn last free buffer recording on */ if ((tempval1 & MACCFG1_TX_FLOW) && !tx_flow_oldval) { for (i = 0; i < priv->num_rx_queues; i++) { + u32 bdp_dma; + rx_queue = priv->rx_queue[i]; - bdp = gfar_rxbd_lastfree(rx_queue); - gfar_write(rx_queue->rfbptr, (u32)bdp); + bdp_dma = gfar_rxbd_dma_lastfree(rx_queue); + gfar_write(rx_queue->rfbptr, bdp_dma); } priv->tx_actual_en = 1; diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 44021243c187..8a5f4de9df1c 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -1310,13 +1310,18 @@ static inline int gfar_rxbd_unused(struct gfar_priv_rx_q *rxq) return rxq->rx_ring_size + rxq->next_to_clean - rxq->next_to_use - 1; } -static inline struct rxbd8 *gfar_rxbd_lastfree(struct gfar_priv_rx_q *rxq) +static inline u32 gfar_rxbd_dma_lastfree(struct gfar_priv_rx_q *rxq) { + struct rxbd8 *bdp; + u32 bdp_dma; int i; i = rxq->next_to_use ? rxq->next_to_use - 1 : rxq->rx_ring_size - 1; + bdp = &rxq->rx_bd_base[i]; + bdp_dma = lower_32_bits(rxq->rx_bd_dma_base); + bdp_dma += (uintptr_t)bdp - (uintptr_t)rxq->rx_bd_base; - return &rxq->rx_bd_base[i]; + return bdp_dma; } irqreturn_t gfar_receive(int irq, void *dev_id); -- cgit v1.3-6-gb490 From c928ed55171b3aa5e14a9474ffe60f31590b89ff Mon Sep 17 00:00:00 2001 From: Haggai Abramonvsky Date: Wed, 29 Jul 2015 15:05:39 +0300 Subject: net/mlx5_core: Check the return value of mlx5_command_exec() mlx5_cmd_exec() might fail - need to check return value. Signed-off-by: Haggai Abramovsky Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index fc88ecaecb4b..566a70488db1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -73,7 +73,12 @@ static inline int mlx5_cmd_exec_check_status(struct mlx5_core_dev *dev, u32 *in, int in_size, u32 *out, int out_size) { - mlx5_cmd_exec(dev, in, in_size, out, out_size); + int err; + + err = mlx5_cmd_exec(dev, in, in_size, out, out_size); + if (err) + return err; + return mlx5_cmd_status_to_err((struct mlx5_outbox_hdr *)out); } -- cgit v1.3-6-gb490 From 68cdf5d6e91068c98d6091b193dc7a5ab7dcf5eb Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Wed, 29 Jul 2015 15:05:40 +0300 Subject: net/mlx5e: Use hard-coded 4K page size for RQ/SQ/CQ The page size of the device's RQ/SQ/CQ objects is defined in 4K units regardless of the system pages size. Thus using the Linux's PAGE_SHIFT macro yields wrong device configuration in systems where PAGE_SHIFT!=12. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 355a10abe667..05b35bd511e7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -349,7 +349,7 @@ static int mlx5e_enable_rq(struct mlx5e_rq *rq, struct mlx5e_rq_param *param) MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST); MLX5_SET(rqc, rqc, flush_in_error_en, 1); MLX5_SET(wq, wq, log_wq_pg_sz, rq->wq_ctrl.buf.page_shift - - PAGE_SHIFT); + MLX5_ADAPTER_PAGE_SHIFT); MLX5_SET64(wq, wq, dbr_addr, rq->wq_ctrl.db.dma); mlx5_fill_page_array(&rq->wq_ctrl.buf, @@ -587,7 +587,7 @@ static int mlx5e_enable_sq(struct mlx5e_sq *sq, struct mlx5e_sq_param *param) MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC); MLX5_SET(wq, wq, uar_page, sq->uar.index); MLX5_SET(wq, wq, log_wq_pg_sz, sq->wq_ctrl.buf.page_shift - - PAGE_SHIFT); + MLX5_ADAPTER_PAGE_SHIFT); MLX5_SET64(wq, wq, dbr_addr, sq->wq_ctrl.db.dma); mlx5_fill_page_array(&sq->wq_ctrl.buf, @@ -782,7 +782,7 @@ static int mlx5e_enable_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param) MLX5_SET(cqc, cqc, c_eqn, eqn); MLX5_SET(cqc, cqc, uar_page, mcq->uar->index); MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift - - PAGE_SHIFT); + MLX5_ADAPTER_PAGE_SHIFT); MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma); err = mlx5_core_create_cq(mdev, mcq, in, inlen); -- cgit v1.3-6-gb490 From a4418a6c36cd9eb080cde0473d15f5cee4c3f35d Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Wed, 29 Jul 2015 15:05:41 +0300 Subject: net/mlx5e: Remove redundant field mlx5e_priv->num_tc This field already exists under the mlx5e_params struct Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 - .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 6 +++--- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 25 ++++++++++------------ 3 files changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index b710e9bade38..7b5a679ab185 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -389,7 +389,6 @@ struct mlx5e_flow_table { struct mlx5e_priv { /* priv data path fields - start */ - int num_tc; int default_vlan_prio; struct mlx5e_sq **txq_to_sq_map; /* priv data path fields - end */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 14fd82c0d18e..f4a7534c553c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -173,7 +173,7 @@ static int mlx5e_get_sset_count(struct net_device *dev, int sset) case ETH_SS_STATS: return NUM_VPORT_COUNTERS + priv->params.num_channels * NUM_RQ_STATS + - priv->params.num_channels * priv->num_tc * + priv->params.num_channels * priv->params.num_tc * NUM_SQ_STATS; /* fallthrough */ default: @@ -207,7 +207,7 @@ static void mlx5e_get_strings(struct net_device *dev, "rx%d_%s", i, rq_stats_strings[j]); for (i = 0; i < priv->params.num_channels; i++) - for (tc = 0; tc < priv->num_tc; tc++) + for (tc = 0; tc < priv->params.num_tc; tc++) for (j = 0; j < NUM_SQ_STATS; j++) sprintf(data + (idx++) * ETH_GSTRING_LEN, @@ -242,7 +242,7 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev, ((u64 *)&priv->channel[i]->rq.stats)[j]; for (i = 0; i < priv->params.num_channels; i++) - for (tc = 0; tc < priv->num_tc; tc++) + for (tc = 0; tc < priv->params.num_tc; tc++) for (j = 0; j < NUM_SQ_STATS; j++) data[idx++] = !test_bit(MLX5E_STATE_OPENED, &priv->state) ? 0 : diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 05b35bd511e7..48dbed9e4cb0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -117,7 +117,7 @@ void mlx5e_update_stats(struct mlx5e_priv *priv) s->rx_csum_none += rq_stats->csum_none; s->rx_wqe_err += rq_stats->wqe_err; - for (j = 0; j < priv->num_tc; j++) { + for (j = 0; j < priv->params.num_tc; j++) { sq_stats = &priv->channel[i]->sq[j].stats; s->tso_packets += sq_stats->tso_packets; @@ -938,7 +938,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, c->pdev = &priv->mdev->pdev->dev; c->netdev = priv->netdev; c->mkey_be = cpu_to_be32(priv->mr.key); - c->num_tc = priv->num_tc; + c->num_tc = priv->params.num_tc; mlx5e_build_tc_to_txq_map(c, priv->params.num_channels); @@ -1069,27 +1069,28 @@ static void mlx5e_build_channel_param(struct mlx5e_priv *priv, static int mlx5e_open_channels(struct mlx5e_priv *priv) { struct mlx5e_channel_param cparam; + int nch = priv->params.num_channels; int err = -ENOMEM; int i; int j; - priv->channel = kcalloc(priv->params.num_channels, - sizeof(struct mlx5e_channel *), GFP_KERNEL); + priv->channel = kcalloc(nch, sizeof(struct mlx5e_channel *), + GFP_KERNEL); - priv->txq_to_sq_map = kcalloc(priv->params.num_channels * priv->num_tc, + priv->txq_to_sq_map = kcalloc(nch * priv->params.num_tc, sizeof(struct mlx5e_sq *), GFP_KERNEL); if (!priv->channel || !priv->txq_to_sq_map) goto err_free_txq_to_sq_map; mlx5e_build_channel_param(priv, &cparam); - for (i = 0; i < priv->params.num_channels; i++) { + for (i = 0; i < nch; i++) { err = mlx5e_open_channel(priv, i, &cparam, &priv->channel[i]); if (err) goto err_close_channels; } - for (j = 0; j < priv->params.num_channels; j++) { + for (j = 0; j < nch; j++) { err = mlx5e_wait_for_min_rx_wqes(&priv->channel[j]->rq); if (err) goto err_close_channels; @@ -1140,11 +1141,10 @@ static void mlx5e_close_tis(struct mlx5e_priv *priv, int tc) static int mlx5e_open_tises(struct mlx5e_priv *priv) { - int num_tc = priv->num_tc; int err; int tc; - for (tc = 0; tc < num_tc; tc++) { + for (tc = 0; tc < priv->params.num_tc; tc++) { err = mlx5e_open_tis(priv, tc); if (err) goto err_close_tises; @@ -1161,10 +1161,9 @@ err_close_tises: static void mlx5e_close_tises(struct mlx5e_priv *priv) { - int num_tc = priv->num_tc; int tc; - for (tc = 0; tc < num_tc; tc++) + for (tc = 0; tc < priv->params.num_tc; tc++) mlx5e_close_tis(priv, tc); } @@ -1786,7 +1785,6 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev, priv->mdev = mdev; priv->netdev = netdev; priv->params.num_channels = num_comp_vectors; - priv->num_tc = priv->params.num_tc; priv->default_vlan_prio = priv->params.default_vlan_prio; spin_lock_init(&priv->async_events_spinlock); @@ -1811,9 +1809,8 @@ static void mlx5e_build_netdev(struct net_device *netdev) SET_NETDEV_DEV(netdev, &mdev->pdev->dev); - if (priv->num_tc > 1) { + if (priv->params.num_tc > 1) mlx5e_netdev_ops.ndo_select_queue = mlx5e_select_queue; - } netdev->netdev_ops = &mlx5e_netdev_ops; netdev->watchdog_timeo = 15 * HZ; -- cgit v1.3-6-gb490 From 28abbfddf4477c4e9a04f276858ffa3fad90b7ac Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Wed, 29 Jul 2015 15:05:42 +0300 Subject: net/mlx5e: Remove redundant assignment of sq->user_index It is not needed by the mlx5 Eth driver since it has a CQ per RQ/SQ. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 48dbed9e4cb0..ef1480b6c4b3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -577,7 +577,6 @@ static int mlx5e_enable_sq(struct mlx5e_sq *sq, struct mlx5e_sq_param *param) memcpy(sqc, param->sqc, sizeof(param->sqc)); - MLX5_SET(sqc, sqc, user_index, sq->tc); MLX5_SET(sqc, sqc, tis_num_0, priv->tisn[sq->tc]); MLX5_SET(sqc, sqc, cqn, c->sq[sq->tc].cq.mcq.cqn); MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST); -- cgit v1.3-6-gb490 From 97de9f310a588161f0d27158c4ea6d8b477a4625 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Wed, 29 Jul 2015 15:05:43 +0300 Subject: net/mlx5e: Avoid redundant de-reference Use the already defined rq pointer directly. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index ef1480b6c4b3..550491034356 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -345,7 +345,7 @@ static int mlx5e_enable_rq(struct mlx5e_rq *rq, struct mlx5e_rq_param *param) memcpy(rqc, param->rqc, sizeof(param->rqc)); - MLX5_SET(rqc, rqc, cqn, c->rq.cq.mcq.cqn); + MLX5_SET(rqc, rqc, cqn, rq->cq.mcq.cqn); MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST); MLX5_SET(rqc, rqc, flush_in_error_en, 1); MLX5_SET(wq, wq, log_wq_pg_sz, rq->wq_ctrl.buf.page_shift - -- cgit v1.3-6-gb490 From 1f2a30037bf18ae6d1bab2c47caeceb4eb0f6464 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Wed, 29 Jul 2015 15:05:44 +0300 Subject: net/mlx5e: Do not use netdev_err() before the netdev is registered Since it is un-named at this time. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 550491034356..6581f5896d92 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1893,36 +1893,31 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev) err = mlx5_alloc_map_uar(mdev, &priv->cq_uar); if (err) { - netdev_err(netdev, "%s: mlx5_alloc_map_uar failed, %d\n", - __func__, err); + mlx5_core_err(mdev, "alloc_map uar failed, %d\n", err); goto err_free_netdev; } err = mlx5_core_alloc_pd(mdev, &priv->pdn); if (err) { - netdev_err(netdev, "%s: mlx5_core_alloc_pd failed, %d\n", - __func__, err); + mlx5_core_err(mdev, "alloc pd failed, %d\n", err); goto err_unmap_free_uar; } err = mlx5_alloc_transport_domain(mdev, &priv->tdn); if (err) { - netdev_err(netdev, "%s: mlx5_alloc_transport_domain failed, %d\n", - __func__, err); + mlx5_core_err(mdev, "alloc td failed, %d\n", err); goto err_dealloc_pd; } err = mlx5e_create_mkey(priv, priv->pdn, &priv->mr); if (err) { - netdev_err(netdev, "%s: mlx5e_create_mkey failed, %d\n", - __func__, err); + mlx5_core_err(mdev, "create mkey failed, %d\n", err); goto err_dealloc_transport_domain; } err = register_netdev(netdev); if (err) { - netdev_err(netdev, "%s: register_netdev failed, %d\n", - __func__, err); + mlx5_core_err(mdev, "register_netdev failed, %d\n", err); goto err_destroy_mkey; } -- cgit v1.3-6-gb490 From 1fc22739a83a245ddad9d9f7c2001c8b3b44c500 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Wed, 29 Jul 2015 15:05:45 +0300 Subject: net/mlx5e: Introduce create/destroy RSS indir table access functions Introduce access functions to create/destroy RSS indrection table and use it in the Ethernet driver. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 19 ++------------ drivers/net/ethernet/mellanox/mlx5/core/transobj.c | 29 ++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/transobj.h | 4 +++ 3 files changed, 35 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 6581f5896d92..8ddb2a026ed9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1188,7 +1188,6 @@ static int mlx5e_open_rqt(struct mlx5e_priv *priv) { struct mlx5_core_dev *mdev = priv->mdev; u32 *in; - u32 out[MLX5_ST_SZ_DW(create_rqt_out)]; void *rqtc; int inlen; int err; @@ -1216,12 +1215,7 @@ static int mlx5e_open_rqt(struct mlx5e_priv *priv) MLX5_SET(rqtc, rqtc, rq_num[i], priv->channel[ix]->rq.rqn); } - MLX5_SET(create_rqt_in, in, opcode, MLX5_CMD_OP_CREATE_RQT); - - memset(out, 0, sizeof(out)); - err = mlx5_cmd_exec_check_status(mdev, in, inlen, out, sizeof(out)); - if (!err) - priv->rqtn = MLX5_GET(create_rqt_out, out, rqtn); + err = mlx5_core_create_rqt(mdev, in, inlen, &priv->rqtn); kvfree(in); @@ -1230,16 +1224,7 @@ static int mlx5e_open_rqt(struct mlx5e_priv *priv) static void mlx5e_close_rqt(struct mlx5e_priv *priv) { - u32 in[MLX5_ST_SZ_DW(destroy_rqt_in)]; - u32 out[MLX5_ST_SZ_DW(destroy_rqt_out)]; - - memset(in, 0, sizeof(in)); - - MLX5_SET(destroy_rqt_in, in, opcode, MLX5_CMD_OP_DESTROY_RQT); - MLX5_SET(destroy_rqt_in, in, rqtn, priv->rqtn); - - mlx5_cmd_exec_check_status(priv->mdev, in, sizeof(in), out, - sizeof(out)); + mlx5_core_destroy_rqt(priv->mdev, priv->rqtn); } static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c index 8d98b03026d5..c4f3f74908ec 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c @@ -358,3 +358,32 @@ int mlx5_core_arm_xsrq(struct mlx5_core_dev *dev, u32 xsrqn, u16 lwm) return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out)); } + +int mlx5_core_create_rqt(struct mlx5_core_dev *dev, u32 *in, int inlen, + u32 *rqtn) +{ + u32 out[MLX5_ST_SZ_DW(create_rqt_out)]; + int err; + + MLX5_SET(create_rqt_in, in, opcode, MLX5_CMD_OP_CREATE_RQT); + + memset(out, 0, sizeof(out)); + err = mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); + if (!err) + *rqtn = MLX5_GET(create_rqt_out, out, rqtn); + + return err; +} + +void mlx5_core_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn) +{ + u32 in[MLX5_ST_SZ_DW(destroy_rqt_in)]; + u32 out[MLX5_ST_SZ_DW(destroy_rqt_out)]; + + memset(in, 0, sizeof(in)); + + MLX5_SET(destroy_rqt_in, in, opcode, MLX5_CMD_OP_DESTROY_RQT); + MLX5_SET(destroy_rqt_in, in, rqtn, rqtn); + + mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, sizeof(out)); +} diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h index f9ef244710d5..10bd75e7d9b1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h @@ -61,4 +61,8 @@ int mlx5_core_destroy_xsrq(struct mlx5_core_dev *dev, u32 rmpn); int mlx5_core_query_xsrq(struct mlx5_core_dev *dev, u32 rmpn, u32 *out); int mlx5_core_arm_xsrq(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm); +int mlx5_core_create_rqt(struct mlx5_core_dev *dev, u32 *in, int inlen, + u32 *rqtn); +void mlx5_core_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn); + #endif /* __TRANSOBJ_H__ */ -- cgit v1.3-6-gb490 From 98e81b0ad6f25e2c4e2ff1680f50f9c66bec9e08 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Wed, 29 Jul 2015 15:05:46 +0300 Subject: net/mlx5e: Remove the mlx5e_update_priv_params() function It was used to update netdev priv parameters that require stopping and re-opening the device in a generic way - it got the new parameters and did: ndo_stop(), copy new parameters into current parameters, ndo_open(). We chose to remove it for two reasons: 1) It requires additional instance of struct mlx5e_params on the stack and looking forward we expect this struct to grow. 2) Sometimes we want to do additional operations (besides just updating the priv parameters) while the netdev is stopped. For example, updating netdev->mtu @mlx5e_change_mtu() should be done while the netdev is stopped (done in this commit). Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 - .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 57 +++++++++++++++------- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 51 ++++++++----------- 3 files changed, 60 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 7b5a679ab185..45f6dc75c0df 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -496,8 +496,6 @@ void mlx5e_del_all_vlan_rules(struct mlx5e_priv *priv); int mlx5e_open_locked(struct net_device *netdev); int mlx5e_close_locked(struct net_device *netdev); -int mlx5e_update_priv_params(struct mlx5e_priv *priv, - struct mlx5e_params *new_params); static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq, struct mlx5e_tx_wqe *wqe, int bf_sz) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index f4a7534c553c..b95aa3384c36 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -264,7 +264,7 @@ static int mlx5e_set_ringparam(struct net_device *dev, struct ethtool_ringparam *param) { struct mlx5e_priv *priv = netdev_priv(dev); - struct mlx5e_params new_params; + bool was_opened; u16 min_rx_wqes; u8 log_rq_size; u8 log_sq_size; @@ -316,11 +316,18 @@ static int mlx5e_set_ringparam(struct net_device *dev, return 0; mutex_lock(&priv->state_lock); - new_params = priv->params; - new_params.log_rq_size = log_rq_size; - new_params.log_sq_size = log_sq_size; - new_params.min_rx_wqes = min_rx_wqes; - err = mlx5e_update_priv_params(priv, &new_params); + + was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); + if (was_opened) + mlx5e_close_locked(dev); + + priv->params.log_rq_size = log_rq_size; + priv->params.log_sq_size = log_sq_size; + priv->params.min_rx_wqes = min_rx_wqes; + + if (was_opened) + err = mlx5e_open_locked(dev); + mutex_unlock(&priv->state_lock); return err; @@ -342,7 +349,7 @@ static int mlx5e_set_channels(struct net_device *dev, struct mlx5e_priv *priv = netdev_priv(dev); int ncv = priv->mdev->priv.eq_table.num_comp_vectors; unsigned int count = ch->combined_count; - struct mlx5e_params new_params; + bool was_opened; int err = 0; if (!count) { @@ -365,9 +372,16 @@ static int mlx5e_set_channels(struct net_device *dev, return 0; mutex_lock(&priv->state_lock); - new_params = priv->params; - new_params.num_channels = count; - err = mlx5e_update_priv_params(priv, &new_params); + + was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); + if (was_opened) + mlx5e_close_locked(dev); + + priv->params.num_channels = count; + + if (was_opened) + err = mlx5e_open_locked(dev); + mutex_unlock(&priv->state_lock); return err; @@ -673,10 +687,10 @@ static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, return 0; } -static int mlx5e_set_rxfh(struct net_device *netdev, const u32 *indir, +static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc) { - struct mlx5e_priv *priv = netdev_priv(netdev); + struct mlx5e_priv *priv = netdev_priv(dev); int err = 0; if (hfunc == ETH_RSS_HASH_NO_CHANGE) @@ -690,8 +704,8 @@ static int mlx5e_set_rxfh(struct net_device *netdev, const u32 *indir, priv->params.rss_hfunc = hfunc; if (test_bit(MLX5E_STATE_OPENED, &priv->state)) { - mlx5e_close_locked(priv->netdev); - err = mlx5e_open_locked(priv->netdev); + mlx5e_close_locked(dev); + err = mlx5e_open_locked(dev); } mutex_unlock(&priv->state_lock); @@ -724,7 +738,7 @@ static int mlx5e_set_tunable(struct net_device *dev, { struct mlx5e_priv *priv = netdev_priv(dev); struct mlx5_core_dev *mdev = priv->mdev; - struct mlx5e_params new_params; + bool was_opened; u32 val; int err = 0; @@ -737,9 +751,16 @@ static int mlx5e_set_tunable(struct net_device *dev, } mutex_lock(&priv->state_lock); - new_params = priv->params; - new_params.tx_max_inline = val; - err = mlx5e_update_priv_params(priv, &new_params); + + was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); + if (was_opened) + mlx5e_close_locked(dev); + + priv->params.tx_max_inline = val; + + if (was_opened) + err = mlx5e_open_locked(dev); + mutex_unlock(&priv->state_lock); break; default: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 8ddb2a026ed9..bb815893d3a8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1570,26 +1570,6 @@ static int mlx5e_close(struct net_device *netdev) return err; } -int mlx5e_update_priv_params(struct mlx5e_priv *priv, - struct mlx5e_params *new_params) -{ - int err = 0; - int was_opened; - - WARN_ON(!mutex_is_locked(&priv->state_lock)); - - was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); - if (was_opened) - mlx5e_close_locked(priv->netdev); - - priv->params = *new_params; - - if (was_opened) - err = mlx5e_open_locked(priv->netdev); - - return err; -} - static struct rtnl_link_stats64 * mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) { @@ -1639,20 +1619,22 @@ static int mlx5e_set_features(struct net_device *netdev, netdev_features_t features) { struct mlx5e_priv *priv = netdev_priv(netdev); + int err = 0; netdev_features_t changes = features ^ netdev->features; - struct mlx5e_params new_params; - bool update_params = false; mutex_lock(&priv->state_lock); - new_params = priv->params; if (changes & NETIF_F_LRO) { - new_params.lro_en = !!(features & NETIF_F_LRO); - update_params = true; - } + bool was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); + + if (was_opened) + mlx5e_close_locked(priv->netdev); - if (update_params) - mlx5e_update_priv_params(priv, &new_params); + priv->params.lro_en = !!(features & NETIF_F_LRO); + + if (was_opened) + err = mlx5e_open_locked(priv->netdev); + } if (changes & NETIF_F_HW_VLAN_CTAG_FILTER) { if (features & NETIF_F_HW_VLAN_CTAG_FILTER) @@ -1670,8 +1652,9 @@ static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu) { struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5_core_dev *mdev = priv->mdev; + bool was_opened; int max_mtu; - int err; + int err = 0; mlx5_query_port_max_mtu(mdev, &max_mtu, 1); @@ -1683,8 +1666,16 @@ static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu) } mutex_lock(&priv->state_lock); + + was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); + if (was_opened) + mlx5e_close_locked(netdev); + netdev->mtu = new_mtu; - err = mlx5e_update_priv_params(priv, &priv->params); + + if (was_opened) + err = mlx5e_open_locked(netdev); + mutex_unlock(&priv->state_lock); return err; -- cgit v1.3-6-gb490 From 05cc5a39ddb74dd81a716a45e67b938d8ebed463 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 29 Jul 2015 15:52:46 +0300 Subject: bnx2x: add vlan filtering offload Current driver always uses vlan-promisc mode, i.e., it receives both tagged and untagged traffic and lets the network stack drop packets tagged with unrequested vlan tags. This patch implements vlan-filtering offload in the driver - Unless explicitly configured to promisc mode, only untagged packets or packets tagged with requested vlans would reach the Rx flow. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 46 ++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 5 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 13 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 250 ++++++++++++++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 258 +++++++++++++++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h | 18 ++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 345 ++++++++++------------ drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h | 43 ++- drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c | 202 ++++++++++--- drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h | 15 +- 10 files changed, 905 insertions(+), 290 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index a1f9785f0209..5762c485ea06 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1228,6 +1228,10 @@ struct bnx2x_slowpath { struct eth_classify_rules_ramrod_data e2; } mac_rdata; + union { + struct eth_classify_rules_ramrod_data e2; + } vlan_rdata; + union { struct tstorm_eth_mac_filter_config e1x; struct eth_filter_rules_ramrod_data e2; @@ -1410,6 +1414,9 @@ struct bnx2x_sp_objs { /* Queue State object */ struct bnx2x_queue_sp_obj q_obj; + + /* VLANs object */ + struct bnx2x_vlan_mac_obj vlan_obj; }; struct bnx2x_fp_stats { @@ -1427,6 +1434,12 @@ enum { SUB_MF_MODE_BD, }; +struct bnx2x_vlan_entry { + struct list_head link; + u16 vid; + bool hw; +}; + struct bnx2x { /* Fields used in the tx and intr/napi performance paths * are grouped together in the beginning of the structure @@ -1865,8 +1878,6 @@ struct bnx2x { int dcb_version; /* CAM credit pools */ - - /* used only in sriov */ struct bnx2x_credit_pool_obj vlans_pool; struct bnx2x_credit_pool_obj macs_pool; @@ -1929,6 +1940,11 @@ struct bnx2x { u16 rx_filter; struct bnx2x_link_report_data vf_link_vars; + struct list_head vlan_reg; + u16 vlan_cnt; + u16 vlan_credit; + u16 vxlan_dst_port; + bool accept_any_vlan; }; /* Tx queues may be less or equal to Rx queues */ @@ -1956,23 +1972,14 @@ extern int num_queues; #define RSS_IPV6_TCP_CAP_MASK \ TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY -/* func init flags */ -#define FUNC_FLG_RSS 0x0001 -#define FUNC_FLG_STATS 0x0002 -/* removed FUNC_FLG_UNMATCHED 0x0004 */ -#define FUNC_FLG_TPA 0x0008 -#define FUNC_FLG_SPQ 0x0010 -#define FUNC_FLG_LEADING 0x0020 /* PF only */ -#define FUNC_FLG_LEADING_STATS 0x0040 struct bnx2x_func_init_params { /* dma */ - dma_addr_t fw_stat_map; /* valid iff FUNC_FLG_STATS */ - dma_addr_t spq_map; /* valid iff FUNC_FLG_SPQ */ + bool spq_active; + dma_addr_t spq_map; + u16 spq_prod; - u16 func_flgs; u16 func_id; /* abs fid */ u16 pf_id; - u16 spq_prod; /* valid iff FUNC_FLG_SPQ */ }; #define for_each_cnic_queue(bp, var) \ @@ -2082,6 +2089,11 @@ struct bnx2x_func_init_params { int bnx2x_set_mac_one(struct bnx2x *bp, u8 *mac, struct bnx2x_vlan_mac_obj *obj, bool set, int mac_type, unsigned long *ramrod_flags); + +int bnx2x_set_vlan_one(struct bnx2x *bp, u16 vlan, + struct bnx2x_vlan_mac_obj *obj, bool set, + unsigned long *ramrod_flags); + /** * bnx2x_del_all_macs - delete all MACs configured for the specific MAC object * @@ -2486,6 +2498,7 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, #define VF_ACQUIRE_THRESH 3 #define VF_ACQUIRE_MAC_FILTERS 1 #define VF_ACQUIRE_MC_FILTERS 10 +#define VF_ACQUIRE_VLAN_FILTERS 2 /* VLAN0 + 'real' VLAN */ #define GOOD_ME_REG(me_reg) (((me_reg) & ME_REG_VF_VALID) && \ (!((me_reg) & ME_REG_VF_ERR))) @@ -2596,4 +2609,9 @@ void bnx2x_set_rx_ts(struct bnx2x *bp, struct sk_buff *skb); #define BNX2X_MAX_PHC_DRIFT 31000000 #define BNX2X_PTP_TX_TIMEOUT +/* Re-configure all previously configured vlan filters. + * Meant for implicit re-load flows. + */ +int bnx2x_vlan_reconfigure_vid(struct bnx2x *bp); + #endif /* bnx2x.h */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 6088c86c4872..1637de6caf46 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2848,6 +2848,11 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* Start fast path */ + /* Re-configure vlan filters */ + rc = bnx2x_vlan_reconfigure_vid(bp); + if (rc) + LOAD_ERROR_EXIT(bp, load_error3); + /* Initialize Rx filter. */ bnx2x_set_rx_mode_inner(bp); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 821346ce50eb..fa7c53201265 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -1066,6 +1066,15 @@ static inline void bnx2x_init_vlan_mac_fp_objs(struct bnx2x_fastpath *fp, BNX2X_FILTER_MAC_PENDING, &bp->sp_state, obj_type, &bp->macs_pool); + + if (!CHIP_IS_E1x(bp)) + bnx2x_init_vlan_obj(bp, &bnx2x_sp_obj(bp, fp).vlan_obj, + fp->cl_id, fp->cid, BP_FUNC(bp), + bnx2x_sp(bp, vlan_rdata), + bnx2x_sp_mapping(bp, vlan_rdata), + BNX2X_FILTER_VLAN_PENDING, + &bp->sp_state, obj_type, + &bp->vlans_pool); } /** @@ -1125,7 +1134,7 @@ static inline void bnx2x_init_bp_objs(struct bnx2x *bp) bnx2x_init_mac_credit_pool(bp, &bp->macs_pool, BP_FUNC(bp), bnx2x_get_path_func_num(bp)); - bnx2x_init_vlan_credit_pool(bp, &bp->vlans_pool, BP_ABS_FUNC(bp)>>1, + bnx2x_init_vlan_credit_pool(bp, &bp->vlans_pool, BP_FUNC(bp), bnx2x_get_path_func_num(bp)); /* RSS configuration object */ @@ -1135,6 +1144,8 @@ static inline void bnx2x_init_bp_objs(struct bnx2x *bp) bnx2x_sp_mapping(bp, rss_rdata), BNX2X_FILTER_RSS_CONF_PENDING, &bp->sp_state, BNX2X_OBJ_TYPE_RX); + + bp->vlan_credit = PF_VLAN_CREDIT_E2(bp, bnx2x_get_path_func_num(bp)); } static inline u8 bnx2x_fp_qzone_id(struct bnx2x_fastpath *fp) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 78e55fe616e3..96ad9ec65faf 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -3067,7 +3067,7 @@ void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p) storm_memset_func_en(bp, p->func_id, 1); /* spq */ - if (p->func_flgs & FUNC_FLG_SPQ) { + if (p->spq_active) { storm_memset_spq_addr(bp, p->spq_map, p->func_id); REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PROD_OFFSET(p->func_id), p->spq_prod); @@ -3283,7 +3283,6 @@ static void bnx2x_pf_init(struct bnx2x *bp) { struct bnx2x_func_init_params func_init = {0}; struct event_ring_data eq_data = { {0} }; - u16 flags; if (!CHIP_IS_E1x(bp)) { /* reset IGU PF statistics: MSIX + ATTN */ @@ -3300,15 +3299,7 @@ static void bnx2x_pf_init(struct bnx2x *bp) BP_FUNC(bp) : BP_VN(bp))*4, 0); } - /* function setup flags */ - flags = (FUNC_FLG_STATS | FUNC_FLG_LEADING | FUNC_FLG_SPQ); - - /* This flag is relevant for E1x only. - * E2 doesn't have a TPA configuration in a function level. - */ - flags |= (bp->dev->features & NETIF_F_LRO) ? FUNC_FLG_TPA : 0; - - func_init.func_flgs = flags; + func_init.spq_active = true; func_init.pf_id = BP_FUNC(bp); func_init.func_id = BP_FUNC(bp); func_init.spq_map = bp->spq_mapping; @@ -5303,6 +5294,10 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp, else vlan_mac_obj = &bp->sp_objs[cid].mac_obj; + break; + case BNX2X_FILTER_VLAN_PENDING: + DP(BNX2X_MSG_SP, "Got SETUP_VLAN completions\n"); + vlan_mac_obj = &bp->sp_objs[cid].vlan_obj; break; case BNX2X_FILTER_MCAST_PENDING: DP(BNX2X_MSG_SP, "Got SETUP_MCAST completions\n"); @@ -5617,7 +5612,7 @@ static void bnx2x_eq_int(struct bnx2x *bp) BNX2X_STATE_DIAG): case (EVENT_RING_OPCODE_CLASSIFICATION_RULES | BNX2X_STATE_CLOSING_WAIT4_HALT): - DP(BNX2X_MSG_SP, "got (un)set mac ramrod\n"); + DP(BNX2X_MSG_SP, "got (un)set vlan/mac ramrod\n"); bnx2x_handle_classification_eqe(bp, elem); break; @@ -6205,6 +6200,11 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode, __set_bit(BNX2X_ACCEPT_MULTICAST, tx_accept_flags); __set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags); + if (bp->accept_any_vlan) { + __set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags); + __set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags); + } + break; case BNX2X_RX_MODE_ALLMULTI: __set_bit(BNX2X_ACCEPT_UNICAST, rx_accept_flags); @@ -6216,6 +6216,11 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode, __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, tx_accept_flags); __set_bit(BNX2X_ACCEPT_BROADCAST, tx_accept_flags); + if (bp->accept_any_vlan) { + __set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags); + __set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags); + } + break; case BNX2X_RX_MODE_PROMISC: /* According to definition of SI mode, iface in promisc mode @@ -6236,18 +6241,15 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode, else __set_bit(BNX2X_ACCEPT_UNICAST, tx_accept_flags); + __set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags); + __set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags); + break; default: BNX2X_ERR("Unknown rx_mode: %d\n", rx_mode); return -EINVAL; } - /* Set ACCEPT_ANY_VLAN as we do not enable filtering by VLAN */ - if (rx_mode != BNX2X_RX_MODE_NONE) { - __set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags); - __set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags); - } - return 0; } @@ -8441,6 +8443,42 @@ int bnx2x_set_mac_one(struct bnx2x *bp, u8 *mac, return rc; } +int bnx2x_set_vlan_one(struct bnx2x *bp, u16 vlan, + struct bnx2x_vlan_mac_obj *obj, bool set, + unsigned long *ramrod_flags) +{ + int rc; + struct bnx2x_vlan_mac_ramrod_params ramrod_param; + + memset(&ramrod_param, 0, sizeof(ramrod_param)); + + /* Fill general parameters */ + ramrod_param.vlan_mac_obj = obj; + ramrod_param.ramrod_flags = *ramrod_flags; + + /* Fill a user request section if needed */ + if (!test_bit(RAMROD_CONT, ramrod_flags)) { + ramrod_param.user_req.u.vlan.vlan = vlan; + /* Set the command: ADD or DEL */ + if (set) + ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_ADD; + else + ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_DEL; + } + + rc = bnx2x_config_vlan_mac(bp, &ramrod_param); + + if (rc == -EEXIST) { + /* Do not treat adding same vlan as error. */ + DP(BNX2X_MSG_SP, "Failed to schedule ADD operations: %d\n", rc); + rc = 0; + } else if (rc < 0) { + BNX2X_ERR("%s VLAN failed\n", (set ? "Set" : "Del")); + } + + return rc; +} + int bnx2x_del_all_macs(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *mac_obj, int mac_type, bool wait_for_comp) @@ -12140,6 +12178,7 @@ static int bnx2x_init_bp(struct bnx2x *bp) mutex_init(&bp->drv_info_mutex); sema_init(&bp->stats_lock, 1); bp->drv_info_mng_owner = false; + INIT_LIST_HEAD(&bp->vlan_reg); INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task); INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task); @@ -12658,6 +12697,169 @@ static netdev_features_t bnx2x_features_check(struct sk_buff *skb, return vxlan_features_check(skb, features); } +static int __bnx2x_vlan_configure_vid(struct bnx2x *bp, u16 vid, bool add) +{ + int rc; + + if (IS_PF(bp)) { + unsigned long ramrod_flags = 0; + + __set_bit(RAMROD_COMP_WAIT, &ramrod_flags); + rc = bnx2x_set_vlan_one(bp, vid, &bp->sp_objs->vlan_obj, + add, &ramrod_flags); + } else { + rc = bnx2x_vfpf_update_vlan(bp, vid, bp->fp->index, add); + } + + return rc; +} + +int bnx2x_vlan_reconfigure_vid(struct bnx2x *bp) +{ + struct bnx2x_vlan_entry *vlan; + int rc = 0; + + if (!bp->vlan_cnt) { + DP(NETIF_MSG_IFUP, "No need to re-configure vlan filters\n"); + return 0; + } + + list_for_each_entry(vlan, &bp->vlan_reg, link) { + /* Prepare for cleanup in case of errors */ + if (rc) { + vlan->hw = false; + continue; + } + + if (!vlan->hw) + continue; + + DP(NETIF_MSG_IFUP, "Re-configuring vlan 0x%04x\n", vlan->vid); + + rc = __bnx2x_vlan_configure_vid(bp, vlan->vid, true); + if (rc) { + BNX2X_ERR("Unable to configure VLAN %d\n", vlan->vid); + vlan->hw = false; + rc = -EINVAL; + continue; + } + } + + return rc; +} + +static int bnx2x_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid) +{ + struct bnx2x *bp = netdev_priv(dev); + struct bnx2x_vlan_entry *vlan; + bool hw = false; + int rc = 0; + + if (!netif_running(bp->dev)) { + DP(NETIF_MSG_IFUP, + "Ignoring VLAN configuration the interface is down\n"); + return -EFAULT; + } + + DP(NETIF_MSG_IFUP, "Adding VLAN %d\n", vid); + + vlan = kmalloc(sizeof(*vlan), GFP_KERNEL); + if (!vlan) + return -ENOMEM; + + bp->vlan_cnt++; + if (bp->vlan_cnt > bp->vlan_credit && !bp->accept_any_vlan) { + DP(NETIF_MSG_IFUP, "Accept all VLAN raised\n"); + bp->accept_any_vlan = true; + if (IS_PF(bp)) + bnx2x_set_rx_mode_inner(bp); + else + bnx2x_vfpf_storm_rx_mode(bp); + } else if (bp->vlan_cnt <= bp->vlan_credit) { + rc = __bnx2x_vlan_configure_vid(bp, vid, true); + hw = true; + } + + vlan->vid = vid; + vlan->hw = hw; + + if (!rc) { + list_add(&vlan->link, &bp->vlan_reg); + } else { + bp->vlan_cnt--; + kfree(vlan); + } + + DP(NETIF_MSG_IFUP, "Adding VLAN result %d\n", rc); + + return rc; +} + +static int bnx2x_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid) +{ + struct bnx2x *bp = netdev_priv(dev); + struct bnx2x_vlan_entry *vlan; + int rc = 0; + + if (!netif_running(bp->dev)) { + DP(NETIF_MSG_IFUP, + "Ignoring VLAN configuration the interface is down\n"); + return -EFAULT; + } + + DP(NETIF_MSG_IFUP, "Removing VLAN %d\n", vid); + + if (!bp->vlan_cnt) { + BNX2X_ERR("Unable to kill VLAN %d\n", vid); + return -EINVAL; + } + + list_for_each_entry(vlan, &bp->vlan_reg, link) + if (vlan->vid == vid) + break; + + if (vlan->vid != vid) { + BNX2X_ERR("Unable to kill VLAN %d - not found\n", vid); + return -EINVAL; + } + + if (vlan->hw) + rc = __bnx2x_vlan_configure_vid(bp, vid, false); + + list_del(&vlan->link); + kfree(vlan); + + bp->vlan_cnt--; + + if (bp->vlan_cnt <= bp->vlan_credit && bp->accept_any_vlan) { + /* Configure all non-configured entries */ + list_for_each_entry(vlan, &bp->vlan_reg, link) { + if (vlan->hw) + continue; + + rc = __bnx2x_vlan_configure_vid(bp, vlan->vid, true); + if (rc) { + BNX2X_ERR("Unable to config VLAN %d\n", + vlan->vid); + continue; + } + DP(NETIF_MSG_IFUP, "HW configured for VLAN %d\n", + vlan->vid); + vlan->hw = true; + } + DP(NETIF_MSG_IFUP, "Accept all VLAN Removed\n"); + bp->accept_any_vlan = false; + if (IS_PF(bp)) + bnx2x_set_rx_mode_inner(bp); + else + bnx2x_vfpf_storm_rx_mode(bp); + } + + DP(NETIF_MSG_IFUP, "Removing VLAN result %d\n", rc); + + return rc; +} + static const struct net_device_ops bnx2x_netdev_ops = { .ndo_open = bnx2x_open, .ndo_stop = bnx2x_close, @@ -12671,6 +12873,8 @@ static const struct net_device_ops bnx2x_netdev_ops = { .ndo_fix_features = bnx2x_fix_features, .ndo_set_features = bnx2x_set_features, .ndo_tx_timeout = bnx2x_tx_timeout, + .ndo_vlan_rx_add_vid = bnx2x_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = bnx2x_vlan_rx_kill_vid, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = poll_bnx2x, #endif @@ -12881,6 +13085,16 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev, dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_HIGHDMA; + /* VF with OLD Hypervisor or old PF do not support filtering */ + if (IS_PF(bp)) { + if (CHIP_IS_E1x(bp)) + bp->accept_any_vlan = true; + else + dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; + } else if (bp->acquire_resp.pfdev_info.pf_cap & PFVF_CAP_VLAN_FILTER) { + dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; + } + dev->features |= dev->hw_features | NETIF_F_HW_VLAN_CTAG_RX; dev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 265fe0a90adc..c9bd7f16018e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -357,6 +357,23 @@ static bool bnx2x_get_credit_vlan(struct bnx2x_vlan_mac_obj *o) return vp->get(vp, 1); } + +static bool bnx2x_get_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o) +{ + struct bnx2x_credit_pool_obj *mp = o->macs_pool; + struct bnx2x_credit_pool_obj *vp = o->vlans_pool; + + if (!mp->get(mp, 1)) + return false; + + if (!vp->get(vp, 1)) { + mp->put(mp, 1); + return false; + } + + return true; +} + static bool bnx2x_put_cam_offset_mac(struct bnx2x_vlan_mac_obj *o, int offset) { struct bnx2x_credit_pool_obj *mp = o->macs_pool; @@ -385,6 +402,22 @@ static bool bnx2x_put_credit_vlan(struct bnx2x_vlan_mac_obj *o) return vp->put(vp, 1); } +static bool bnx2x_put_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o) +{ + struct bnx2x_credit_pool_obj *mp = o->macs_pool; + struct bnx2x_credit_pool_obj *vp = o->vlans_pool; + + if (!mp->put(mp, 1)) + return false; + + if (!vp->put(vp, 1)) { + mp->get(mp, 1); + return false; + } + + return true; +} + /** * __bnx2x_vlan_mac_h_write_trylock - try getting the vlan mac writer lock * @@ -638,6 +671,26 @@ static int bnx2x_check_vlan_add(struct bnx2x *bp, return 0; } +static int bnx2x_check_vlan_mac_add(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + union bnx2x_classification_ramrod_data *data) +{ + struct bnx2x_vlan_mac_registry_elem *pos; + + DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for ADD command\n", + data->vlan_mac.mac, data->vlan_mac.vlan); + + list_for_each_entry(pos, &o->head, link) + if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) && + (!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac, + ETH_ALEN)) && + (data->vlan_mac.is_inner_mac == + pos->u.vlan_mac.is_inner_mac)) + return -EEXIST; + + return 0; +} + /* check_del() callbacks */ static struct bnx2x_vlan_mac_registry_elem * bnx2x_check_mac_del(struct bnx2x *bp, @@ -672,6 +725,27 @@ static struct bnx2x_vlan_mac_registry_elem * return NULL; } +static struct bnx2x_vlan_mac_registry_elem * + bnx2x_check_vlan_mac_del(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + union bnx2x_classification_ramrod_data *data) +{ + struct bnx2x_vlan_mac_registry_elem *pos; + + DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for DEL command\n", + data->vlan_mac.mac, data->vlan_mac.vlan); + + list_for_each_entry(pos, &o->head, link) + if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) && + (!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac, + ETH_ALEN)) && + (data->vlan_mac.is_inner_mac == + pos->u.vlan_mac.is_inner_mac)) + return pos; + + return NULL; +} + /* check_move() callback */ static bool bnx2x_check_move(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *src_o, @@ -1038,6 +1112,96 @@ static void bnx2x_set_one_vlan_e2(struct bnx2x *bp, rule_cnt); } +static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + struct bnx2x_exeq_elem *elem, + int rule_idx, int cam_offset) +{ + struct bnx2x_raw_obj *raw = &o->raw; + struct eth_classify_rules_ramrod_data *data = + (struct eth_classify_rules_ramrod_data *)(raw->rdata); + int rule_cnt = rule_idx + 1; + union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx]; + enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd; + bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false; + u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan; + u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac; + u16 inner_mac; + + /* Reset the ramrod data buffer for the first rule */ + if (rule_idx == 0) + memset(data, 0, sizeof(*data)); + + /* Set a rule header */ + bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_PAIR, + &rule_entry->pair.header); + + /* Set VLAN and MAC themselves */ + rule_entry->pair.vlan = cpu_to_le16(vlan); + bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb, + &rule_entry->pair.mac_mid, + &rule_entry->pair.mac_lsb, mac); + inner_mac = elem->cmd_data.vlan_mac.u.vlan_mac.is_inner_mac; + rule_entry->pair.inner_mac = cpu_to_le16(inner_mac); + /* MOVE: Add a rule that will add this MAC/VLAN to the target Queue */ + if (cmd == BNX2X_VLAN_MAC_MOVE) { + struct bnx2x_vlan_mac_obj *target_obj; + + rule_entry++; + rule_cnt++; + + /* Setup ramrod data */ + target_obj = elem->cmd_data.vlan_mac.target_obj; + bnx2x_vlan_mac_set_cmd_hdr_e2(bp, target_obj, + true, CLASSIFY_RULE_OPCODE_PAIR, + &rule_entry->pair.header); + + /* Set a VLAN itself */ + rule_entry->pair.vlan = cpu_to_le16(vlan); + bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb, + &rule_entry->pair.mac_mid, + &rule_entry->pair.mac_lsb, mac); + rule_entry->pair.inner_mac = cpu_to_le16(inner_mac); + } + + /* Set the ramrod data header */ + bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header, + rule_cnt); +} + +/** + * bnx2x_set_one_vlan_mac_e1h - + * + * @bp: device handle + * @o: bnx2x_vlan_mac_obj + * @elem: bnx2x_exeq_elem + * @rule_idx: rule_idx + * @cam_offset: cam_offset + */ +static void bnx2x_set_one_vlan_mac_e1h(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + struct bnx2x_exeq_elem *elem, + int rule_idx, int cam_offset) +{ + struct bnx2x_raw_obj *raw = &o->raw; + struct mac_configuration_cmd *config = + (struct mac_configuration_cmd *)(raw->rdata); + /* 57710 and 57711 do not support MOVE command, + * so it's either ADD or DEL + */ + bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ? + true : false; + + /* Reset the ramrod data buffer */ + memset(config, 0, sizeof(*config)); + + bnx2x_vlan_mac_set_rdata_e1x(bp, o, BNX2X_FILTER_VLAN_MAC_PENDING, + cam_offset, add, + elem->cmd_data.vlan_mac.u.vlan_mac.mac, + elem->cmd_data.vlan_mac.u.vlan_mac.vlan, + ETH_VLAN_FILTER_CLASSIFY, config); +} + /** * bnx2x_vlan_mac_restore - reconfigure next MAC/VLAN/VLAN-MAC element * @@ -1137,6 +1301,25 @@ static struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan( return NULL; } +static struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan_mac( + struct bnx2x_exe_queue_obj *o, + struct bnx2x_exeq_elem *elem) +{ + struct bnx2x_exeq_elem *pos; + struct bnx2x_vlan_mac_ramrod_data *data = + &elem->cmd_data.vlan_mac.u.vlan_mac; + + /* Check pending for execution commands */ + list_for_each_entry(pos, &o->exe_queue, link) + if (!memcmp(&pos->cmd_data.vlan_mac.u.vlan_mac, data, + sizeof(*data)) && + (pos->cmd_data.vlan_mac.cmd == + elem->cmd_data.vlan_mac.cmd)) + return pos; + + return NULL; +} + /** * bnx2x_validate_vlan_mac_add - check if an ADD command can be executed * @@ -2044,6 +2227,68 @@ void bnx2x_init_vlan_obj(struct bnx2x *bp, } } +void bnx2x_init_vlan_mac_obj(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *vlan_mac_obj, + u8 cl_id, u32 cid, u8 func_id, void *rdata, + dma_addr_t rdata_mapping, int state, + unsigned long *pstate, bnx2x_obj_type type, + struct bnx2x_credit_pool_obj *macs_pool, + struct bnx2x_credit_pool_obj *vlans_pool) +{ + union bnx2x_qable_obj *qable_obj = + (union bnx2x_qable_obj *)vlan_mac_obj; + + bnx2x_init_vlan_mac_common(vlan_mac_obj, cl_id, cid, func_id, rdata, + rdata_mapping, state, pstate, type, + macs_pool, vlans_pool); + + /* CAM pool handling */ + vlan_mac_obj->get_credit = bnx2x_get_credit_vlan_mac; + vlan_mac_obj->put_credit = bnx2x_put_credit_vlan_mac; + /* CAM offset is relevant for 57710 and 57711 chips only which have a + * single CAM for both MACs and VLAN-MAC pairs. So the offset + * will be taken from MACs' pool object only. + */ + vlan_mac_obj->get_cam_offset = bnx2x_get_cam_offset_mac; + vlan_mac_obj->put_cam_offset = bnx2x_put_cam_offset_mac; + + if (CHIP_IS_E1(bp)) { + BNX2X_ERR("Do not support chips others than E2\n"); + BUG(); + } else if (CHIP_IS_E1H(bp)) { + vlan_mac_obj->set_one_rule = bnx2x_set_one_vlan_mac_e1h; + vlan_mac_obj->check_del = bnx2x_check_vlan_mac_del; + vlan_mac_obj->check_add = bnx2x_check_vlan_mac_add; + vlan_mac_obj->check_move = bnx2x_check_move_always_err; + vlan_mac_obj->ramrod_cmd = RAMROD_CMD_ID_ETH_SET_MAC; + + /* Exe Queue */ + bnx2x_exe_queue_init(bp, + &vlan_mac_obj->exe_queue, 1, qable_obj, + bnx2x_validate_vlan_mac, + bnx2x_remove_vlan_mac, + bnx2x_optimize_vlan_mac, + bnx2x_execute_vlan_mac, + bnx2x_exeq_get_vlan_mac); + } else { + vlan_mac_obj->set_one_rule = bnx2x_set_one_vlan_mac_e2; + vlan_mac_obj->check_del = bnx2x_check_vlan_mac_del; + vlan_mac_obj->check_add = bnx2x_check_vlan_mac_add; + vlan_mac_obj->check_move = bnx2x_check_move; + vlan_mac_obj->ramrod_cmd = + RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES; + + /* Exe Queue */ + bnx2x_exe_queue_init(bp, + &vlan_mac_obj->exe_queue, + CLASSIFY_RULES_COUNT, + qable_obj, bnx2x_validate_vlan_mac, + bnx2x_remove_vlan_mac, + bnx2x_optimize_vlan_mac, + bnx2x_execute_vlan_mac, + bnx2x_exeq_get_vlan_mac); + } +} /* RX_MODE verbs: DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */ static inline void __storm_memset_mac_filters(struct bnx2x *bp, struct tstorm_eth_mac_filter_config *mac_filters, @@ -3856,8 +4101,8 @@ static bool bnx2x_credit_pool_get_entry_always_true( * If credit is negative pool operations will always succeed (unlimited pool). * */ -static inline void bnx2x_init_credit_pool(struct bnx2x_credit_pool_obj *p, - int base, int credit) +void bnx2x_init_credit_pool(struct bnx2x_credit_pool_obj *p, + int base, int credit) { /* Zero the object first */ memset(p, 0, sizeof(*p)); @@ -3936,9 +4181,9 @@ void bnx2x_init_mac_credit_pool(struct bnx2x *bp, /* CAM credit is equaly divided between all active functions * on the PATH. */ - if ((func_num > 0)) { + if (func_num > 0) { if (!CHIP_REV_IS_SLOW(bp)) - cam_sz = (MAX_MAC_CREDIT_E2 / func_num); + cam_sz = PF_MAC_CREDIT_E2(bp, func_num); else cam_sz = BNX2X_CAM_SIZE_EMUL; @@ -3968,8 +4213,9 @@ void bnx2x_init_vlan_credit_pool(struct bnx2x *bp, * on the PATH. */ if (func_num > 0) { - int credit = MAX_VLAN_CREDIT_E2 / func_num; - bnx2x_init_credit_pool(p, func_id * credit, credit); + int credit = PF_VLAN_CREDIT_E2(bp, func_num); + + bnx2x_init_credit_pool(p, -1/*unused for E2*/, credit); } else /* this should never happen! Block VLAN operations. */ bnx2x_init_credit_pool(p, 0, 0); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h index 324e9f986314..4048fc594cce 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h @@ -1413,6 +1413,14 @@ void bnx2x_init_vlan_obj(struct bnx2x *bp, unsigned long *pstate, bnx2x_obj_type type, struct bnx2x_credit_pool_obj *vlans_pool); +void bnx2x_init_vlan_mac_obj(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *vlan_mac_obj, + u8 cl_id, u32 cid, u8 func_id, void *rdata, + dma_addr_t rdata_mapping, int state, + unsigned long *pstate, bnx2x_obj_type type, + struct bnx2x_credit_pool_obj *macs_pool, + struct bnx2x_credit_pool_obj *vlans_pool); + int bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o); void bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp, @@ -1483,6 +1491,8 @@ void bnx2x_init_mac_credit_pool(struct bnx2x *bp, void bnx2x_init_vlan_credit_pool(struct bnx2x *bp, struct bnx2x_credit_pool_obj *p, u8 func_id, u8 func_num); +void bnx2x_init_credit_pool(struct bnx2x_credit_pool_obj *p, + int base, int credit); /****************** RSS CONFIGURATION ****************/ void bnx2x_init_rss_config_obj(struct bnx2x *bp, @@ -1510,4 +1520,12 @@ int bnx2x_config_rss(struct bnx2x *bp, void bnx2x_get_rss_ind_table(struct bnx2x_rss_config_obj *rss_obj, u8 *ind_table); +#define PF_MAC_CREDIT_E2(bp, func_num) \ + ((MAX_MAC_CREDIT_E2 - GET_NUM_VFS_PER_PATH(bp) * VF_MAC_CREDIT_CNT) / \ + func_num + GET_NUM_VFS_PER_PF(bp) * VF_MAC_CREDIT_CNT) + +#define PF_VLAN_CREDIT_E2(bp, func_num) \ + ((MAX_MAC_CREDIT_E2 - GET_NUM_VFS_PER_PATH(bp) * VF_VLAN_CREDIT_CNT) / \ + func_num + GET_NUM_VFS_PER_PF(bp) * VF_VLAN_CREDIT_CNT) + #endif /* BNX2X_SP_VERBS */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 5b243bcec3fa..ec82831f5071 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -197,14 +197,6 @@ void bnx2x_vfop_qctor_prep(struct bnx2x *bp, setup_p->gen_params.stat_id = vfq_stat_id(vf, q); setup_p->gen_params.fp_hsi = vf->fp_hsi; - /* Setup-op pause params: - * Nothing to do, the pause thresholds are set by default to 0 which - * effectively turns off the feature for this queue. We don't want - * one queue (VF) to interfering with another queue (another VF) - */ - if (vf->cfg_flags & VF_CFG_FW_FC) - BNX2X_ERR("No support for pause to VFs (abs_vfid: %d)\n", - vf->abs_vfid); /* Setup-op flags: * collect statistics, zero statistics, local-switching, security, * OV for Flex10, RSS and MCAST for leading @@ -360,22 +352,24 @@ static inline void bnx2x_vf_vlan_credit(struct bnx2x *bp, } static int bnx2x_vf_vlan_mac_clear(struct bnx2x *bp, struct bnx2x_virtf *vf, - int qid, bool drv_only, bool mac) + int qid, bool drv_only, int type) { struct bnx2x_vlan_mac_ramrod_params ramrod; int rc; DP(BNX2X_MSG_IOV, "vf[%d] - deleting all %s\n", vf->abs_vfid, - mac ? "MACs" : "VLANs"); + (type == BNX2X_VF_FILTER_VLAN_MAC) ? "VLAN-MACs" : + (type == BNX2X_VF_FILTER_MAC) ? "MACs" : "VLANs"); /* Prepare ramrod params */ memset(&ramrod, 0, sizeof(struct bnx2x_vlan_mac_ramrod_params)); - if (mac) { + if (type == BNX2X_VF_FILTER_VLAN_MAC) { + set_bit(BNX2X_ETH_MAC, &ramrod.user_req.vlan_mac_flags); + ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_mac_obj); + } else if (type == BNX2X_VF_FILTER_MAC) { set_bit(BNX2X_ETH_MAC, &ramrod.user_req.vlan_mac_flags); ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj); } else { - set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, - &ramrod.user_req.vlan_mac_flags); ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj); } ramrod.user_req.cmd = BNX2X_VLAN_MAC_DEL; @@ -393,14 +387,11 @@ static int bnx2x_vf_vlan_mac_clear(struct bnx2x *bp, struct bnx2x_virtf *vf, &ramrod.ramrod_flags); if (rc) { BNX2X_ERR("Failed to delete all %s\n", - mac ? "MACs" : "VLANs"); + (type == BNX2X_VF_FILTER_VLAN_MAC) ? "VLAN-MACs" : + (type == BNX2X_VF_FILTER_MAC) ? "MACs" : "VLANs"); return rc; } - /* Clear the vlan counters */ - if (!mac) - atomic_set(&bnx2x_vfq(vf, qid, vlan_count), 0); - return 0; } @@ -414,13 +405,17 @@ static int bnx2x_vf_mac_vlan_config(struct bnx2x *bp, DP(BNX2X_MSG_IOV, "vf[%d] - %s a %s filter\n", vf->abs_vfid, filter->add ? "Adding" : "Deleting", - filter->type == BNX2X_VF_FILTER_MAC ? "MAC" : "VLAN"); + (filter->type == BNX2X_VF_FILTER_VLAN_MAC) ? "VLAN-MAC" : + (filter->type == BNX2X_VF_FILTER_MAC) ? "MAC" : "VLAN"); /* Prepare ramrod params */ memset(&ramrod, 0, sizeof(struct bnx2x_vlan_mac_ramrod_params)); - if (filter->type == BNX2X_VF_FILTER_VLAN) { - set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, - &ramrod.user_req.vlan_mac_flags); + if (filter->type == BNX2X_VF_FILTER_VLAN_MAC) { + ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_mac_obj); + ramrod.user_req.u.vlan.vlan = filter->vid; + memcpy(&ramrod.user_req.u.mac.mac, filter->mac, ETH_ALEN); + set_bit(BNX2X_ETH_MAC, &ramrod.user_req.vlan_mac_flags); + } else if (filter->type == BNX2X_VF_FILTER_VLAN) { ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj); ramrod.user_req.u.vlan.vlan = filter->vid; } else { @@ -431,16 +426,6 @@ static int bnx2x_vf_mac_vlan_config(struct bnx2x *bp, ramrod.user_req.cmd = filter->add ? BNX2X_VLAN_MAC_ADD : BNX2X_VLAN_MAC_DEL; - /* Verify there are available vlan credits */ - if (filter->add && filter->type == BNX2X_VF_FILTER_VLAN && - (atomic_read(&bnx2x_vfq(vf, qid, vlan_count)) >= - vf_vlan_rules_cnt(vf))) { - BNX2X_ERR("No credits for vlan [%d >= %d]\n", - atomic_read(&bnx2x_vfq(vf, qid, vlan_count)), - vf_vlan_rules_cnt(vf)); - return -ENOMEM; - } - set_bit(RAMROD_EXEC, &ramrod.ramrod_flags); if (drv_only) set_bit(RAMROD_DRV_CLR_ONLY, &ramrod.ramrod_flags); @@ -452,16 +437,13 @@ static int bnx2x_vf_mac_vlan_config(struct bnx2x *bp, if (rc && rc != -EEXIST) { BNX2X_ERR("Failed to %s %s\n", filter->add ? "add" : "delete", - filter->type == BNX2X_VF_FILTER_MAC ? "MAC" : - "VLAN"); + (filter->type == BNX2X_VF_FILTER_VLAN_MAC) ? + "VLAN-MAC" : + (filter->type == BNX2X_VF_FILTER_MAC) ? + "MAC" : "VLAN"); return rc; } - /* Update the vlan counters */ - if (filter->type == BNX2X_VF_FILTER_VLAN) - bnx2x_vf_vlan_credit(bp, ramrod.vlan_mac_obj, - &bnx2x_vfq(vf, qid, vlan_count)); - return 0; } @@ -513,21 +495,7 @@ int bnx2x_vf_queue_setup(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid, if (rc) goto op_err; - /* Configure vlan0 for leading queue */ - if (!qid) { - struct bnx2x_vf_mac_vlan_filter filter; - - memset(&filter, 0, sizeof(struct bnx2x_vf_mac_vlan_filter)); - filter.type = BNX2X_VF_FILTER_VLAN; - filter.add = true; - filter.vid = 0; - rc = bnx2x_vf_mac_vlan_config(bp, vf, qid, &filter, false); - if (rc) - goto op_err; - } - /* Schedule the configuration of any pending vlan filters */ - vf->cfg_flags |= VF_CFG_VLAN; bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_HYPERVISOR_VLAN, BNX2X_MSG_IOV); return 0; @@ -546,10 +514,16 @@ static int bnx2x_vf_queue_flr(struct bnx2x *bp, struct bnx2x_virtf *vf, /* If needed, clean the filtering data base */ if ((qid == LEADING_IDX) && bnx2x_validate_vf_sp_objs(bp, vf, false)) { - rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true, false); + rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true, + BNX2X_VF_FILTER_VLAN_MAC); + if (rc) + goto op_err; + rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true, + BNX2X_VF_FILTER_VLAN); if (rc) goto op_err; - rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true, true); + rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true, + BNX2X_VF_FILTER_MAC); if (rc) goto op_err; } @@ -682,11 +656,18 @@ int bnx2x_vf_queue_teardown(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid) /* Remove filtering if feasible */ if (bnx2x_validate_vf_sp_objs(bp, vf, true)) { rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, - false, false); + false, + BNX2X_VF_FILTER_VLAN_MAC); + if (rc) + goto op_err; + rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, + false, + BNX2X_VF_FILTER_VLAN); if (rc) goto op_err; rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, - false, true); + false, + BNX2X_VF_FILTER_MAC); if (rc) goto op_err; rc = bnx2x_vf_mcast(bp, vf, NULL, 0, false); @@ -767,8 +748,6 @@ static void bnx2x_vf_igu_reset(struct bnx2x *bp, struct bnx2x_virtf *vf) val = REG_RD(bp, IGU_REG_VF_CONFIGURATION); val |= (IGU_VF_CONF_FUNC_EN | IGU_VF_CONF_MSI_MSIX_EN); - if (vf->cfg_flags & VF_CFG_INT_SIMD) - val |= IGU_VF_CONF_SINGLE_ISR_EN; val &= ~IGU_VF_CONF_PARENT_MASK; val |= (BP_ABS_FUNC(bp) >> 1) << IGU_VF_CONF_PARENT_SHIFT; REG_WR(bp, IGU_REG_VF_CONFIGURATION, val); @@ -847,29 +826,6 @@ int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid) return 0; } -static void bnx2x_iov_re_set_vlan_filters(struct bnx2x *bp, - struct bnx2x_virtf *vf, - int new) -{ - int num = vf_vlan_rules_cnt(vf); - int diff = new - num; - bool rc = true; - - DP(BNX2X_MSG_IOV, "vf[%d] - %d vlan filter credits [previously %d]\n", - vf->abs_vfid, new, num); - - if (diff > 0) - rc = bp->vlans_pool.get(&bp->vlans_pool, diff); - else if (diff < 0) - rc = bp->vlans_pool.put(&bp->vlans_pool, -diff); - - if (rc) - vf_vlan_rules_cnt(vf) = new; - else - DP(BNX2X_MSG_IOV, "vf[%d] - Failed to configure vlan filter credits change\n", - vf->abs_vfid); -} - /* must be called after the number of PF queues and the number of VFs are * both known */ @@ -877,21 +833,13 @@ static void bnx2x_iov_static_resc(struct bnx2x *bp, struct bnx2x_virtf *vf) { struct vf_pf_resc_request *resc = &vf->alloc_resc; - u16 vlan_count = 0; /* will be set only during VF-ACQUIRE */ resc->num_rxqs = 0; resc->num_txqs = 0; - /* no credit calculations for macs (just yet) */ - resc->num_mac_filters = 1; - - /* divvy up vlan rules */ - bnx2x_iov_re_set_vlan_filters(bp, vf, 0); - vlan_count = bp->vlans_pool.check(&bp->vlans_pool); - vlan_count = 1 << ilog2(vlan_count); - bnx2x_iov_re_set_vlan_filters(bp, vf, - vlan_count / BNX2X_NR_VIRTFN(bp)); + resc->num_mac_filters = VF_MAC_CREDIT_CNT; + resc->num_vlan_filters = VF_VLAN_CREDIT_CNT; /* no real limitation */ resc->num_mc_filters = 0; @@ -1625,6 +1573,11 @@ int bnx2x_iov_nic_init(struct bnx2x *bp) vf->filter_state = 0; vf->sp_cl_id = bnx2x_fp(bp, 0, cl_id); + bnx2x_init_credit_pool(&vf->vf_vlans_pool, 0, + vf_vlan_rules_cnt(vf)); + bnx2x_init_credit_pool(&vf->vf_macs_pool, 0, + vf_mac_rules_cnt(vf)); + /* init mcast object - This object will be re-initialized * during VF-ACQUIRE with the proper cl_id and cid. * It needs to be initialized here so that it can be safely @@ -2037,12 +1990,11 @@ int bnx2x_vf_chk_avail_resc(struct bnx2x *bp, struct bnx2x_virtf *vf, u8 rxq_cnt = vf_rxq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf); u8 txq_cnt = vf_txq_count(vf) ? : bnx2x_vf_max_queue_cnt(bp, vf); - /* Save a vlan filter for the Hypervisor */ return ((req_resc->num_rxqs <= rxq_cnt) && (req_resc->num_txqs <= txq_cnt) && (req_resc->num_sbs <= vf_sb_count(vf)) && (req_resc->num_mac_filters <= vf_mac_rules_cnt(vf)) && - (req_resc->num_vlan_filters <= vf_vlan_rules_visible_cnt(vf))); + (req_resc->num_vlan_filters <= vf_vlan_rules_cnt(vf))); } /* CORE VF API */ @@ -2096,16 +2048,12 @@ int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf, vf_sb_count(vf) = resc->num_sbs; vf_rxq_count(vf) = resc->num_rxqs ? : bnx2x_vf_max_queue_cnt(bp, vf); vf_txq_count(vf) = resc->num_txqs ? : bnx2x_vf_max_queue_cnt(bp, vf); - if (resc->num_mac_filters) - vf_mac_rules_cnt(vf) = resc->num_mac_filters; - /* Add an additional vlan filter credit for the hypervisor */ - bnx2x_iov_re_set_vlan_filters(bp, vf, resc->num_vlan_filters + 1); DP(BNX2X_MSG_IOV, "Fulfilling vf request: sb count %d, tx_count %d, rx_count %d, mac_rules_count %d, vlan_rules_count %d\n", vf_sb_count(vf), vf_rxq_count(vf), vf_txq_count(vf), vf_mac_rules_cnt(vf), - vf_vlan_rules_visible_cnt(vf)); + vf_vlan_rules_cnt(vf)); /* Initialize the queues */ if (!vf->vfqs) { @@ -2138,7 +2086,6 @@ int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf, int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf, dma_addr_t *sb_map) { struct bnx2x_func_init_params func_init = {0}; - u16 flags = 0; int i; /* the sb resources are initialized at this point, do the @@ -2165,23 +2112,9 @@ int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf, dma_addr_t *sb_map) /* reset IGU VF statistics: MSIX */ REG_WR(bp, IGU_REG_STATISTIC_NUM_MESSAGE_SENT + vf->abs_vfid * 4 , 0); - /* vf init */ - if (vf->cfg_flags & VF_CFG_STATS) - flags |= (FUNC_FLG_STATS | FUNC_FLG_SPQ); - - if (vf->cfg_flags & VF_CFG_TPA) - flags |= FUNC_FLG_TPA; - - if (is_vf_multi(vf)) - flags |= FUNC_FLG_RSS; - /* function setup */ - func_init.func_flgs = flags; func_init.pf_id = BP_FUNC(bp); func_init.func_id = FW_VF_HANDLE(vf->abs_vfid); - func_init.fw_stat_map = vf->fw_stat_map; - func_init.spq_map = vf->spq_map; - func_init.spq_prod = 0; bnx2x_func_init(bp, &func_init); /* Enable the vf */ @@ -2594,8 +2527,8 @@ void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp) DP(BNX2X_MSG_IOV, "configuring vlan for VFs from sp-task\n"); for_each_vf(bp, vfidx) { - bulletin = BP_VF_BULLETIN(bp, vfidx); - if (BP_VF(bp, vfidx)->cfg_flags & VF_CFG_VLAN) + bulletin = BP_VF_BULLETIN(bp, vfidx); + if (bulletin->valid_bitmap & VLAN_VALID) bnx2x_set_vf_vlan(bp->dev, vfidx, bulletin->vlan, 0); } } @@ -2813,20 +2746,58 @@ out: return rc; } -int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) +static void bnx2x_set_vf_vlan_acceptance(struct bnx2x *bp, + struct bnx2x_virtf *vf, bool accept) +{ + struct bnx2x_rx_mode_ramrod_params rx_ramrod; + unsigned long accept_flags; + + /* need to remove/add the VF's accept_any_vlan bit */ + accept_flags = bnx2x_leading_vfq(vf, accept_flags); + if (accept) + set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags); + else + clear_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags); + + bnx2x_vf_prep_rx_mode(bp, LEADING_IDX, &rx_ramrod, vf, + accept_flags); + bnx2x_leading_vfq(vf, accept_flags) = accept_flags; + bnx2x_config_rx_mode(bp, &rx_ramrod); +} + +static int bnx2x_set_vf_vlan_filter(struct bnx2x *bp, struct bnx2x_virtf *vf, + u16 vlan, bool add) { - struct bnx2x_queue_state_params q_params = {NULL}; struct bnx2x_vlan_mac_ramrod_params ramrod_param; - struct bnx2x_queue_update_params *update_params; + unsigned long ramrod_flags = 0; + int rc = 0; + + /* configure the new vlan to device */ + memset(&ramrod_param, 0, sizeof(ramrod_param)); + __set_bit(RAMROD_COMP_WAIT, &ramrod_flags); + ramrod_param.vlan_mac_obj = &bnx2x_leading_vfq(vf, vlan_obj); + ramrod_param.ramrod_flags = ramrod_flags; + ramrod_param.user_req.u.vlan.vlan = vlan; + ramrod_param.user_req.cmd = add ? BNX2X_VLAN_MAC_ADD + : BNX2X_VLAN_MAC_DEL; + rc = bnx2x_config_vlan_mac(bp, &ramrod_param); + if (rc) { + BNX2X_ERR("failed to configure vlan\n"); + return -EINVAL; + } + + return 0; +} + +int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) +{ struct pf_vf_bulletin_content *bulletin = NULL; - struct bnx2x_rx_mode_ramrod_params rx_ramrod; struct bnx2x *bp = netdev_priv(dev); struct bnx2x_vlan_mac_obj *vlan_obj; unsigned long vlan_mac_flags = 0; unsigned long ramrod_flags = 0; struct bnx2x_virtf *vf = NULL; - unsigned long accept_flags; - int rc; + int i, rc; if (vlan > 4095) { BNX2X_ERR("illegal vlan value %d\n", vlan); @@ -2855,6 +2826,10 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) bulletin->valid_bitmap &= ~(1 << VLAN_VALID); bulletin->vlan = vlan; + /* Post update on VF's bulletin board */ + rc = bnx2x_post_vf_bulletin(bp, vfidx); + if (rc) + BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx); mutex_unlock(&bp->vfdb->bulletin_mutex); /* is vf initialized and queue set up? */ @@ -2881,84 +2856,76 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) goto out; } - /* need to remove/add the VF's accept_any_vlan bit */ - accept_flags = bnx2x_leading_vfq(vf, accept_flags); - if (vlan) - clear_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags); - else - set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags); - - bnx2x_vf_prep_rx_mode(bp, LEADING_IDX, &rx_ramrod, vf, - accept_flags); - bnx2x_leading_vfq(vf, accept_flags) = accept_flags; - bnx2x_config_rx_mode(bp, &rx_ramrod); + /* clear accept_any_vlan when HV forces vlan, otherwise + * according to VF capabilities + */ + if (vlan || !(vf->cfg_flags & VF_CFG_VLAN_FILTER)) + bnx2x_set_vf_vlan_acceptance(bp, vf, !vlan); - /* configure the new vlan to device */ - memset(&ramrod_param, 0, sizeof(ramrod_param)); - __set_bit(RAMROD_COMP_WAIT, &ramrod_flags); - ramrod_param.vlan_mac_obj = vlan_obj; - ramrod_param.ramrod_flags = ramrod_flags; - set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, - &ramrod_param.user_req.vlan_mac_flags); - ramrod_param.user_req.u.vlan.vlan = vlan; - ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_ADD; - rc = bnx2x_config_vlan_mac(bp, &ramrod_param); - if (rc) { - BNX2X_ERR("failed to configure vlan\n"); - rc = -EINVAL; + rc = bnx2x_set_vf_vlan_filter(bp, vf, vlan, true); + if (rc) goto out; - } - /* send queue update ramrod to configure default vlan and silent - * vlan removal + /* send queue update ramrods to configure default vlan and + * silent vlan removal */ - __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags); - q_params.cmd = BNX2X_Q_CMD_UPDATE; - q_params.q_obj = &bnx2x_leading_vfq(vf, sp_obj); - update_params = &q_params.params.update; - __set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG, - &update_params->update_flags); - __set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG, - &update_params->update_flags); - if (vlan == 0) { - /* if vlan is 0 then we want to leave the VF traffic - * untagged, and leave the incoming traffic untouched - * (i.e. do not remove any vlan tags). - */ - __clear_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN, - &update_params->update_flags); - __clear_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, - &update_params->update_flags); - } else { - /* configure default vlan to vf queue and set silent - * vlan removal (the vf remains unaware of this vlan). - */ - __set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN, + for_each_vfq(vf, i) { + struct bnx2x_queue_state_params q_params = {NULL}; + struct bnx2x_queue_update_params *update_params; + + q_params.q_obj = &bnx2x_vfq(vf, i, sp_obj); + + /* validate the Q is UP */ + if (bnx2x_get_q_logical_state(bp, q_params.q_obj) != + BNX2X_Q_LOGICAL_STATE_ACTIVE) + continue; + + __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags); + q_params.cmd = BNX2X_Q_CMD_UPDATE; + update_params = &q_params.params.update; + __set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG, &update_params->update_flags); - __set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, + __set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG, &update_params->update_flags); - update_params->def_vlan = vlan; - update_params->silent_removal_value = - vlan & VLAN_VID_MASK; - update_params->silent_removal_mask = VLAN_VID_MASK; - } + if (vlan == 0) { + /* if vlan is 0 then we want to leave the VF traffic + * untagged, and leave the incoming traffic untouched + * (i.e. do not remove any vlan tags). + */ + __clear_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN, + &update_params->update_flags); + __clear_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, + &update_params->update_flags); + } else { + /* configure default vlan to vf queue and set silent + * vlan removal (the vf remains unaware of this vlan). + */ + __set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN, + &update_params->update_flags); + __set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, + &update_params->update_flags); + update_params->def_vlan = vlan; + update_params->silent_removal_value = + vlan & VLAN_VID_MASK; + update_params->silent_removal_mask = VLAN_VID_MASK; + } - /* Update the Queue state */ - rc = bnx2x_queue_state_change(bp, &q_params); - if (rc) { - BNX2X_ERR("Failed to configure default VLAN\n"); - goto out; + /* Update the Queue state */ + rc = bnx2x_queue_state_change(bp, &q_params); + if (rc) { + BNX2X_ERR("Failed to configure default VLAN queue %d\n", + i); + goto out; + } } - - - /* clear the flag indicating that this VF needs its vlan - * (will only be set if the HV configured the Vlan before vf was - * up and we were called because the VF came up later - */ out: - vf->cfg_flags &= ~VF_CFG_VLAN; bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN); + if (rc) + DP(BNX2X_MSG_IOV, + "updated VF[%d] vlan configuration (vlan = %d)\n", + vfidx, vlan); + return rc; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h index 2011205ec8d4..01f364358e5b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h @@ -77,7 +77,10 @@ struct bnx2x_vf_queue { /* VLANs object */ struct bnx2x_vlan_mac_obj vlan_obj; - atomic_t vlan_count; /* 0 means vlan-0 is set ~ untagged */ + + /* VLAN-MACs object */ + struct bnx2x_vlan_mac_obj vlan_mac_obj; + unsigned long accept_flags; /* last accept flags configured */ /* Queue Slow-path State object */ @@ -105,8 +108,10 @@ struct bnx2x_virtf; struct bnx2x_vf_mac_vlan_filter { int type; -#define BNX2X_VF_FILTER_MAC 1 -#define BNX2X_VF_FILTER_VLAN 2 +#define BNX2X_VF_FILTER_MAC BIT(0) +#define BNX2X_VF_FILTER_VLAN BIT(1) +#define BNX2X_VF_FILTER_VLAN_MAC \ + (BNX2X_VF_FILTER_MAC | BNX2X_VF_FILTER_VLAN) /*shortcut*/ bool add; u8 *mac; @@ -121,14 +126,9 @@ struct bnx2x_vf_mac_vlan_filters { /* vf context */ struct bnx2x_virtf { u16 cfg_flags; -#define VF_CFG_STATS 0x0001 -#define VF_CFG_FW_FC 0x0002 -#define VF_CFG_TPA 0x0004 -#define VF_CFG_INT_SIMD 0x0008 -#define VF_CACHE_LINE 0x0010 -#define VF_CFG_VLAN 0x0020 -#define VF_CFG_STATS_COALESCE 0x0040 -#define VF_CFG_EXT_BULLETIN 0x0080 +#define VF_CFG_STATS_COALESCE 0x1 +#define VF_CFG_EXT_BULLETIN 0x2 +#define VF_CFG_VLAN_FILTER 0x4 u8 link_cfg; /* IFLA_VF_LINK_STATE_AUTO * IFLA_VF_LINK_STATE_ENABLE * IFLA_VF_LINK_STATE_DISABLE @@ -142,9 +142,8 @@ struct bnx2x_virtf { bool flr_clnup_stage; /* true during flr cleanup */ /* dma */ - dma_addr_t fw_stat_map; /* valid iff VF_CFG_STATS */ + dma_addr_t fw_stat_map; u16 stats_stride; - dma_addr_t spq_map; dma_addr_t bulletin_map; /* Allocated resources counters. Before the VF is acquired, the @@ -165,8 +164,6 @@ struct bnx2x_virtf { #define vf_mac_rules_cnt(vf) ((vf)->alloc_resc.num_mac_filters) #define vf_vlan_rules_cnt(vf) ((vf)->alloc_resc.num_vlan_filters) #define vf_mc_rules_cnt(vf) ((vf)->alloc_resc.num_mc_filters) - /* Hide a single vlan filter credit for the hypervisor */ -#define vf_vlan_rules_visible_cnt(vf) (vf_vlan_rules_cnt(vf) - 1) u8 sb_count; /* actual number of SBs */ u8 igu_base_id; /* base igu status block id */ @@ -209,6 +206,9 @@ struct bnx2x_virtf { enum channel_tlvs op_current; u8 fp_hsi; + + struct bnx2x_credit_pool_obj vf_vlans_pool; + struct bnx2x_credit_pool_obj vf_macs_pool; }; #define BNX2X_NR_VIRTFN(bp) ((bp)->vfdb->sriov.nr_virtfn) @@ -232,6 +232,12 @@ struct bnx2x_virtf { #define FW_VF_HANDLE(abs_vfid) \ (abs_vfid + FW_PF_MAX_HANDLE) +#define GET_NUM_VFS_PER_PATH(bp) 64 /* use max possible value */ +#define GET_NUM_VFS_PER_PF(bp) ((bp)->vfdb ? (bp)->vfdb->sriov.total \ + : 0) +#define VF_MAC_CREDIT_CNT 1 +#define VF_VLAN_CREDIT_CNT 2 /* VLAN0 + 'real' VLAN */ + /* locking and unlocking the channel mutex */ void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf, enum channel_tlvs tlv); @@ -275,6 +281,10 @@ struct bnx2x_vf_sp { struct eth_classify_rules_ramrod_data e2; } vlan_rdata; + union { + struct eth_classify_rules_ramrod_data e2; + } vlan_mac_rdata; + union { struct eth_filter_rules_ramrod_data e2; } rx_mode_rdata; @@ -538,6 +548,7 @@ int bnx2x_iov_link_update_vf(struct bnx2x *bp, int idx); int bnx2x_set_vf_link_state(struct net_device *dev, int vf, int link_state); +int bnx2x_vfpf_update_vlan(struct bnx2x *bp, u16 vid, u8 vf_qid, bool add); #else /* CONFIG_BNX2X_SRIOV */ static inline void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid, @@ -606,5 +617,7 @@ struct pf_vf_bulletin_content; static inline void bnx2x_vf_bulletin_finalize(struct pf_vf_bulletin_content *bulletin, bool support_long) {} +static inline int bnx2x_vfpf_update_vlan(struct bnx2x *bp, u16 vid, u8 vf_qid, bool add) {return 0; } + #endif /* CONFIG_BNX2X_SRIOV */ #endif /* bnx2x_sriov.h */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index 31b79bd13292..1374e5394a79 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -247,6 +247,7 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count) req->resc_request.num_sbs = bp->igu_sb_cnt; req->resc_request.num_mac_filters = VF_ACQUIRE_MAC_FILTERS; req->resc_request.num_mc_filters = VF_ACQUIRE_MC_FILTERS; + req->resc_request.num_vlan_filters = VF_ACQUIRE_VLAN_FILTERS; /* pf 2 vf bulletin board address */ req->bulletin_addr = bp->pf2vf_bulletin_mapping; @@ -257,6 +258,8 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count) /* Bulletin support for bulletin board with length > legacy length */ req->vfdev_info.caps |= VF_CAP_SUPPORT_EXT_BULLETIN; + /* vlan filtering is supported */ + req->vfdev_info.caps |= VF_CAP_SUPPORT_VLAN_FILTER; /* add list termination tlv */ bnx2x_add_tlv(bp, req, @@ -375,6 +378,8 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count) NO_WOL_FLAG | NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG | NO_FCOE_FLAG; bp->igu_sb_cnt = bp->acquire_resp.resc.num_sbs; bp->igu_base_sb = bp->acquire_resp.resc.hw_sbs[0].hw_sb_id; + bp->vlan_credit = bp->acquire_resp.resc.num_vlan_filters; + strlcpy(bp->fw_ver, bp->acquire_resp.pfdev_info.fw_ver, sizeof(bp->fw_ver)); @@ -548,7 +553,7 @@ static void bnx2x_leading_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf, BNX2X_FILTER_MAC_PENDING, &vf->filter_state, BNX2X_OBJ_TYPE_RX_TX, - &bp->macs_pool); + &vf->vf_macs_pool); /* vlan */ bnx2x_init_vlan_obj(bp, &q->vlan_obj, cl_id, q->cid, func_id, @@ -557,8 +562,17 @@ static void bnx2x_leading_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf, BNX2X_FILTER_VLAN_PENDING, &vf->filter_state, BNX2X_OBJ_TYPE_RX_TX, - &bp->vlans_pool); - + &vf->vf_vlans_pool); + /* vlan-mac */ + bnx2x_init_vlan_mac_obj(bp, &q->vlan_mac_obj, + cl_id, q->cid, func_id, + bnx2x_vf_sp(bp, vf, vlan_mac_rdata), + bnx2x_vf_sp_map(bp, vf, vlan_mac_rdata), + BNX2X_FILTER_VLAN_MAC_PENDING, + &vf->filter_state, + BNX2X_OBJ_TYPE_RX_TX, + &vf->vf_macs_pool, + &vf->vf_vlans_pool); /* mcast */ bnx2x_init_mcast_obj(bp, &vf->mcast_obj, cl_id, q->cid, func_id, func_id, @@ -725,7 +739,7 @@ int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr, u8 vf_qid, bool set) req->filters[0].flags = VFPF_Q_FILTER_DEST_MAC_VALID; if (set) - req->filters[0].flags |= VFPF_Q_FILTER_SET_MAC; + req->filters[0].flags |= VFPF_Q_FILTER_SET; /* sample bulletin board for new mac */ bnx2x_sample_bulletin(bp); @@ -913,6 +927,67 @@ out: return 0; } +/* request pf to add a vlan for the vf */ +int bnx2x_vfpf_update_vlan(struct bnx2x *bp, u16 vid, u8 vf_qid, bool add) +{ + struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters; + struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; + int rc = 0; + + if (!(bp->acquire_resp.pfdev_info.pf_cap & PFVF_CAP_VLAN_FILTER)) { + DP(BNX2X_MSG_IOV, "HV does not support vlan filtering\n"); + return 0; + } + + /* clear mailbox and prep first tlv */ + bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS, + sizeof(*req)); + + req->flags = VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED; + req->vf_qid = vf_qid; + req->n_mac_vlan_filters = 1; + + req->filters[0].flags = VFPF_Q_FILTER_VLAN_TAG_VALID; + + if (add) + req->filters[0].flags |= VFPF_Q_FILTER_SET; + + /* sample bulletin board for hypervisor vlan */ + bnx2x_sample_bulletin(bp); + + if (bp->shadow_bulletin.content.valid_bitmap & 1 << VLAN_VALID) { + BNX2X_ERR("Hypervisor will dicline the request, avoiding\n"); + rc = -EINVAL; + goto out; + } + + req->filters[0].vlan_tag = vid; + + /* add list termination tlv */ + bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END, + sizeof(struct channel_list_end_tlv)); + + /* output tlvs list */ + bnx2x_dp_tlv_list(bp, req); + + /* send message to pf */ + rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping); + if (rc) { + BNX2X_ERR("failed to send message to pf. rc was %d\n", rc); + goto out; + } + + if (resp->hdr.status != PFVF_STATUS_SUCCESS) { + BNX2X_ERR("vfpf %s VLAN %d failed\n", add ? "add" : "del", + vid); + rc = -EINVAL; + } +out: + bnx2x_vfpf_finalize(bp, &req->first_tlv); + + return rc; +} + int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) { int mode = bp->rx_mode; @@ -936,8 +1011,13 @@ int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) req->rx_mask = VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST; req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST; req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST; + if (mode == BNX2X_RX_MODE_PROMISC) + req->rx_mask |= VFPF_RX_MASK_ACCEPT_ANY_VLAN; } + if (bp->accept_any_vlan) + req->rx_mask |= VFPF_RX_MASK_ACCEPT_ANY_VLAN; + req->flags |= VFPF_SET_Q_FILTERS_RX_MASK_CHANGED; req->vf_qid = 0; @@ -1190,7 +1270,8 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf, resp->pfdev_info.indices_per_sb = HC_SB_MAX_INDICES_E2; resp->pfdev_info.pf_cap = (PFVF_CAP_RSS | PFVF_CAP_TPA | - PFVF_CAP_TPA_UPDATE); + PFVF_CAP_TPA_UPDATE | + PFVF_CAP_VLAN_FILTER); bnx2x_fill_fw_str(bp, resp->pfdev_info.fw_ver, sizeof(resp->pfdev_info.fw_ver)); @@ -1205,7 +1286,7 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf, bnx2x_vf_max_queue_cnt(bp, vf); resc->num_sbs = vf_sb_count(vf); resc->num_mac_filters = vf_mac_rules_cnt(vf); - resc->num_vlan_filters = vf_vlan_rules_visible_cnt(vf); + resc->num_vlan_filters = vf_vlan_rules_cnt(vf); resc->num_mc_filters = 0; if (status == PFVF_STATUS_SUCCESS) { @@ -1372,6 +1453,14 @@ static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf, vf->cfg_flags &= ~VF_CFG_EXT_BULLETIN; } + if (acquire->vfdev_info.caps & VF_CAP_SUPPORT_VLAN_FILTER) { + DP(BNX2X_MSG_IOV, "VF[%d] supports vlan filtering\n", + vf->abs_vfid); + vf->cfg_flags |= VF_CFG_VLAN_FILTER; + } else { + vf->cfg_flags &= ~VF_CFG_VLAN_FILTER; + } + out: /* response */ bnx2x_vf_mbx_acquire_resp(bp, vf, mbx, rc); @@ -1384,7 +1473,6 @@ static void bnx2x_vf_mbx_init_vf(struct bnx2x *bp, struct bnx2x_virtf *vf, int rc; /* record ghost addresses from vf message */ - vf->spq_map = init->spq_addr; vf->fw_stat_map = init->stats_addr; vf->stats_stride = init->stats_stride; rc = bnx2x_vf_init(bp, vf, (dma_addr_t *)init->sb_addr); @@ -1580,17 +1668,18 @@ static int bnx2x_vf_mbx_macvlan_list(struct bnx2x *bp, if ((msg_filter->flags & type_flag) != type_flag) continue; - if (type_flag == VFPF_Q_FILTER_DEST_MAC_VALID) { + memset(&fl->filters[j], 0, sizeof(fl->filters[j])); + if (type_flag & VFPF_Q_FILTER_DEST_MAC_VALID) { fl->filters[j].mac = msg_filter->mac; - fl->filters[j].type = BNX2X_VF_FILTER_MAC; - } else { + fl->filters[j].type |= BNX2X_VF_FILTER_MAC; + } + if (type_flag & VFPF_Q_FILTER_VLAN_TAG_VALID) { fl->filters[j].vid = msg_filter->vlan_tag; - fl->filters[j].type = BNX2X_VF_FILTER_VLAN; + fl->filters[j].type |= BNX2X_VF_FILTER_VLAN; } - fl->filters[j].add = - (msg_filter->flags & VFPF_Q_FILTER_SET_MAC) ? - true : false; + fl->filters[j].add = !!(msg_filter->flags & VFPF_Q_FILTER_SET); fl->count++; + j++; } if (!fl->count) kfree(fl); @@ -1600,6 +1689,18 @@ static int bnx2x_vf_mbx_macvlan_list(struct bnx2x *bp, return 0; } +static int bnx2x_vf_filters_contain(struct vfpf_set_q_filters_tlv *filters, + u32 flags) +{ + int i, cnt = 0; + + for (i = 0; i < filters->n_mac_vlan_filters; i++) + if ((filters->filters[i].flags & flags) == flags) + cnt++; + + return cnt; +} + static void bnx2x_vf_mbx_dp_q_filter(struct bnx2x *bp, int msglvl, int idx, struct vfpf_q_mac_vlan_filter *filter) { @@ -1631,6 +1732,7 @@ static void bnx2x_vf_mbx_dp_q_filters(struct bnx2x *bp, int msglvl, #define VFPF_MAC_FILTER VFPF_Q_FILTER_DEST_MAC_VALID #define VFPF_VLAN_FILTER VFPF_Q_FILTER_VLAN_TAG_VALID +#define VFPF_VLAN_MAC_FILTER (VFPF_VLAN_FILTER | VFPF_MAC_FILTER) static int bnx2x_vf_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf) { @@ -1641,17 +1743,17 @@ static int bnx2x_vf_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf) /* check for any mac/vlan changes */ if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) { - /* build mac list */ struct bnx2x_vf_mac_vlan_filters *fl = NULL; + /* build vlan-mac list */ rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl, - VFPF_MAC_FILTER); + VFPF_VLAN_MAC_FILTER); if (rc) goto op_err; if (fl) { - /* set mac list */ + /* set vlan-mac list */ rc = bnx2x_vf_mac_vlan_config_list(bp, vf, fl, msg->vf_qid, false); @@ -1659,22 +1761,23 @@ static int bnx2x_vf_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf) goto op_err; } - /* build vlan list */ + /* build mac list */ fl = NULL; rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl, - VFPF_VLAN_FILTER); + VFPF_MAC_FILTER); if (rc) goto op_err; if (fl) { - /* set vlan list */ + /* set mac list */ rc = bnx2x_vf_mac_vlan_config_list(bp, vf, fl, msg->vf_qid, false); if (rc) goto op_err; } + } if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) { @@ -1689,11 +1792,15 @@ static int bnx2x_vf_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf) __set_bit(BNX2X_ACCEPT_BROADCAST, &accept); } - /* A packet arriving the vf's mac should be accepted - * with any vlan, unless a vlan has already been - * configured. + /* any_vlan is not configured if HV is forcing VLAN + * any_vlan is configured if + * 1. VF does not support vlan filtering + * OR + * 2. VF supports vlan filtering and explicitly requested it */ - if (!(bulletin->valid_bitmap & (1 << VLAN_VALID))) + if (!(bulletin->valid_bitmap & (1 << VLAN_VALID)) && + (!(vf->cfg_flags & VF_CFG_VLAN_FILTER) || + msg->rx_mask & VFPF_RX_MASK_ACCEPT_ANY_VLAN)) __set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept); /* set rx-mode */ @@ -1729,17 +1836,31 @@ static int bnx2x_filters_validate_mac(struct bnx2x *bp, * since queue was not set up. */ if (bulletin->valid_bitmap & 1 << MAC_ADDR_VALID) { - /* once a mac was set by ndo can only accept a single mac... */ - if (filters->n_mac_vlan_filters > 1) { - BNX2X_ERR("VF[%d] requested the addition of multiple macs after set_vf_mac ndo was called\n", - vf->abs_vfid); - rc = -EPERM; - goto response; + struct vfpf_q_mac_vlan_filter *filter = NULL; + int i; + + for (i = 0; i < filters->n_mac_vlan_filters; i++) { + if (!(filters->filters[i].flags & + VFPF_Q_FILTER_DEST_MAC_VALID)) + continue; + + /* once a mac was set by ndo can only accept + * a single mac... + */ + if (filter) { + BNX2X_ERR("VF[%d] requested the addition of multiple macs after set_vf_mac ndo was called [%d filters]\n", + vf->abs_vfid, + filters->n_mac_vlan_filters); + rc = -EPERM; + goto response; + } + + filter = &filters->filters[i]; } /* ...and only the mac set by the ndo */ - if (filters->n_mac_vlan_filters == 1 && - !ether_addr_equal(filters->filters->mac, bulletin->mac)) { + if (filter && + !ether_addr_equal(filter->mac, bulletin->mac)) { BNX2X_ERR("VF[%d] requested the addition of a mac address not matching the one configured by set_vf_mac ndo\n", vf->abs_vfid); @@ -1761,17 +1882,14 @@ static int bnx2x_filters_validate_vlan(struct bnx2x *bp, /* if vlan was set by hypervisor we don't allow guest to config vlan */ if (bulletin->valid_bitmap & 1 << VLAN_VALID) { - int i; - /* search for vlan filters */ - for (i = 0; i < filters->n_mac_vlan_filters; i++) { - if (filters->filters[i].flags & - VFPF_Q_FILTER_VLAN_TAG_VALID) { - BNX2X_ERR("VF[%d] attempted to configure vlan but one was already set by Hypervisor. Aborting request\n", - vf->abs_vfid); - rc = -EPERM; - goto response; - } + + if (bnx2x_vf_filters_contain(filters, + VFPF_Q_FILTER_VLAN_TAG_VALID)) { + BNX2X_ERR("VF[%d] attempted to configure vlan but one was already set by Hypervisor. Aborting request\n", + vf->abs_vfid); + rc = -EPERM; + goto response; } } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h index f0110f4bd0a3..64f2b52c5829 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h @@ -70,6 +70,8 @@ struct hw_sb_info { #define VFPF_RX_MASK_ACCEPT_ALL_UNICAST 0x00000004 #define VFPF_RX_MASK_ACCEPT_ALL_MULTICAST 0x00000008 #define VFPF_RX_MASK_ACCEPT_BROADCAST 0x00000010 +#define VFPF_RX_MASK_ACCEPT_ANY_VLAN 0x00000020 + #define BULLETIN_CONTENT_SIZE (sizeof(struct pf_vf_bulletin_content)) #define BULLETIN_CONTENT_LEGACY_SIZE (32) #define BULLETIN_ATTEMPTS 5 /* crc failures before throwing towel */ @@ -133,6 +135,7 @@ struct vfpf_acquire_tlv { u8 fp_hsi_ver; u8 caps; #define VF_CAP_SUPPORT_EXT_BULLETIN (1 << 0) +#define VF_CAP_SUPPORT_VLAN_FILTER (1 << 1) } vfdev_info; struct vf_pf_resc_request resc_request; @@ -174,10 +177,12 @@ struct pfvf_acquire_resp_tlv { struct pf_vf_pfdev_info { u32 chip_num; u32 pf_cap; -#define PFVF_CAP_RSS 0x00000001 -#define PFVF_CAP_DHC 0x00000002 -#define PFVF_CAP_TPA 0x00000004 -#define PFVF_CAP_TPA_UPDATE 0x00000008 +#define PFVF_CAP_RSS 0x00000001 +#define PFVF_CAP_DHC 0x00000002 +#define PFVF_CAP_TPA 0x00000004 +#define PFVF_CAP_TPA_UPDATE 0x00000008 +#define PFVF_CAP_VLAN_FILTER 0x00000010 + char fw_ver[32]; u16 db_size; u8 indices_per_sb; @@ -294,7 +299,7 @@ struct vfpf_q_mac_vlan_filter { u32 flags; #define VFPF_Q_FILTER_DEST_MAC_VALID 0x01 #define VFPF_Q_FILTER_VLAN_TAG_VALID 0x02 -#define VFPF_Q_FILTER_SET_MAC 0x100 /* set/clear */ +#define VFPF_Q_FILTER_SET 0x100 /* set/clear */ u8 mac[ETH_ALEN]; u16 vlan_tag; }; -- cgit v1.3-6-gb490 From e8a64b20eb27cd9c9403f51e4e6c415f9e096e39 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 29 Jul 2015 10:33:06 +0300 Subject: drm/amdgpu: fix bug when amdkfd destroys hqd The wrong define was used to check if the hqd is still active v2: Don't use SHIFT as the MASK is already shifted Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index 2daad335b809..dd2037bc0b4a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -450,7 +450,7 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, while (true) { temp = RREG32(mmCP_HQD_ACTIVE); - if (temp & CP_HQD_ACTIVE__ACTIVE__SHIFT) + if (temp & CP_HQD_ACTIVE__ACTIVE_MASK) break; if (timeout == 0) { pr_err("kfd: cp queue preemption time out (%dms)\n", -- cgit v1.3-6-gb490 From a63c580a5271b61f12cf91e768120e33792e2907 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 29 Jul 2015 10:40:26 +0300 Subject: drm/amdkfd: fix bug when initializing sdma vm A logical AND operation was used during mask and shift, instead of a bitwise AND operation. This patch fixes this bug by changing the operation to bitwise AND. Signed-off-by: Oded Gabbay Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c index 23ce774ff09d..c6f435aa803f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c @@ -143,7 +143,7 @@ static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, get_sh_mem_bases_32(qpd_to_pdd(qpd)); else value |= ((get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd))) << - SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) && + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) & SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE_MASK; q->properties.sdma_vm_addr = value; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c index 44c38e8e54d3..7e9cae9d349b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c @@ -155,7 +155,7 @@ static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, get_sh_mem_bases_32(qpd_to_pdd(qpd)); else value |= ((get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd))) << - SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) && + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) & SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE_MASK; q->properties.sdma_vm_addr = value; -- cgit v1.3-6-gb490 From 8670f2a5acec2f79839785efdfb3626dfada7ed4 Mon Sep 17 00:00:00 2001 From: Sriharsha Basavapatna Date: Wed, 29 Jul 2015 19:35:32 +0530 Subject: be2net: Support vxlan offload stats in the driver This patch adds vxlan offload specific counters to ethtool stats. We provide tx/rx queue counters to show the number of vxlan offload pkts sent/received. Signed-off-by: Sriharsha Basavapatna Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 2 ++ drivers/net/ethernet/emulex/benet/be_ethtool.c | 2 ++ drivers/net/ethernet/emulex/benet/be_main.c | 7 ++++++- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 8cd384d0e38a..0a27805cbbbd 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -230,6 +230,7 @@ struct be_mcc_obj { struct be_tx_stats { u64 tx_bytes; u64 tx_pkts; + u64 tx_vxlan_offload_pkts; u64 tx_reqs; u64 tx_compl; ulong tx_jiffies; @@ -277,6 +278,7 @@ struct be_rx_page_info { struct be_rx_stats { u64 rx_bytes; u64 rx_pkts; + u64 rx_vxlan_offload_pkts; u32 rx_drops_no_skbs; /* skb allocation errors */ u32 rx_drops_no_frags; /* HW has no fetched frags */ u32 rx_post_fail; /* page post alloc failures */ diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index d20ff054c1f7..2c9ed1710ba6 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -138,6 +138,7 @@ static const struct be_ethtool_stat et_stats[] = { static const struct be_ethtool_stat et_rx_stats[] = { {DRVSTAT_RX_INFO(rx_bytes)},/* If moving this member see above note */ {DRVSTAT_RX_INFO(rx_pkts)}, /* If moving this member see above note */ + {DRVSTAT_RX_INFO(rx_vxlan_offload_pkts)}, {DRVSTAT_RX_INFO(rx_compl)}, {DRVSTAT_RX_INFO(rx_compl_err)}, {DRVSTAT_RX_INFO(rx_mcast_pkts)}, @@ -190,6 +191,7 @@ static const struct be_ethtool_stat et_tx_stats[] = { {DRVSTAT_TX_INFO(tx_internal_parity_err)}, {DRVSTAT_TX_INFO(tx_bytes)}, {DRVSTAT_TX_INFO(tx_pkts)}, + {DRVSTAT_TX_INFO(tx_vxlan_offload_pkts)}, /* Number of skbs queued for trasmission by the driver */ {DRVSTAT_TX_INFO(tx_reqs)}, /* Number of times the TX queue was stopped due to lack diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 5e92db8947d9..d86bc5d52246 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -677,11 +677,14 @@ void be_link_status_update(struct be_adapter *adapter, u8 link_status) static void be_tx_stats_update(struct be_tx_obj *txo, struct sk_buff *skb) { struct be_tx_stats *stats = tx_stats(txo); + u64 tx_pkts = skb_shinfo(skb)->gso_segs ? : 1; u64_stats_update_begin(&stats->sync); stats->tx_reqs++; stats->tx_bytes += skb->len; - stats->tx_pkts += (skb_shinfo(skb)->gso_segs ? : 1); + stats->tx_pkts += tx_pkts; + if (skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL) + stats->tx_vxlan_offload_pkts += tx_pkts; u64_stats_update_end(&stats->sync); } @@ -1957,6 +1960,8 @@ static void be_rx_stats_update(struct be_rx_obj *rxo, stats->rx_compl++; stats->rx_bytes += rxcp->pkt_size; stats->rx_pkts++; + if (rxcp->tunneled) + stats->rx_vxlan_offload_pkts++; if (rxcp->pkt_type == BE_MULTICAST_PACKET) stats->rx_mcast_pkts++; if (rxcp->err) -- cgit v1.3-6-gb490 From 93c1edb27f9e7ef7f276b91763c93242bbda71cb Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 29 Jul 2015 23:33:46 +0200 Subject: mlxsw: Introduce Mellanox switch driver core Add core components of Mellanox switch driver infrastructure. Core infrastructure is designed so that it can be used by multiple bus drivers (PCI now, I2C and SGMII are planned to be implemented in the future). Multiple switch kind drivers can be registered as well. This core serves as a glue between buses and drivers. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Elad Raz Reviewed-by: Scott Feldman Signed-off-by: David S. Miller --- MAINTAINERS | 9 + drivers/net/ethernet/mellanox/Kconfig | 1 + drivers/net/ethernet/mellanox/Makefile | 1 + drivers/net/ethernet/mellanox/mlxsw/Kconfig | 11 + drivers/net/ethernet/mellanox/mlxsw/Makefile | 2 + drivers/net/ethernet/mellanox/mlxsw/cmd.h | 1090 ++++++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlxsw/core.c | 550 +++++++++++++ drivers/net/ethernet/mellanox/mlxsw/core.h | 179 +++++ drivers/net/ethernet/mellanox/mlxsw/item.h | 405 ++++++++++ drivers/net/ethernet/mellanox/mlxsw/port.h | 52 ++ drivers/net/ethernet/mellanox/mlxsw/trap.h | 66 ++ 11 files changed, 2366 insertions(+) create mode 100644 drivers/net/ethernet/mellanox/mlxsw/Kconfig create mode 100644 drivers/net/ethernet/mellanox/mlxsw/Makefile create mode 100644 drivers/net/ethernet/mellanox/mlxsw/cmd.h create mode 100644 drivers/net/ethernet/mellanox/mlxsw/core.c create mode 100644 drivers/net/ethernet/mellanox/mlxsw/core.h create mode 100644 drivers/net/ethernet/mellanox/mlxsw/item.h create mode 100644 drivers/net/ethernet/mellanox/mlxsw/port.h create mode 100644 drivers/net/ethernet/mellanox/mlxsw/trap.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 0c787660a106..6712fd5f4200 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6645,6 +6645,15 @@ W: http://www.mellanox.com Q: http://patchwork.ozlabs.org/project/netdev/list/ F: drivers/net/ethernet/mellanox/mlx4/en_* +MELLANOX ETHERNET SWITCH DRIVERS +M: Jiri Pirko +M: Ido Schimmel +L: netdev@vger.kernel.org +S: Supported +W: http://www.mellanox.com +Q: http://patchwork.ozlabs.org/project/netdev/list/ +F: drivers/net/ethernet/mellanox/mlxsw/ + MEMORY MANAGEMENT L: linux-mm@kvack.org W: http://www.linux-mm.org diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig index 52a6665b7abf..d54701047401 100644 --- a/drivers/net/ethernet/mellanox/Kconfig +++ b/drivers/net/ethernet/mellanox/Kconfig @@ -18,5 +18,6 @@ if NET_VENDOR_MELLANOX source "drivers/net/ethernet/mellanox/mlx4/Kconfig" source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig" +source "drivers/net/ethernet/mellanox/mlxsw/Kconfig" endif # NET_VENDOR_MELLANOX diff --git a/drivers/net/ethernet/mellanox/Makefile b/drivers/net/ethernet/mellanox/Makefile index 38fe32ef5e5f..2e2a5ec509ac 100644 --- a/drivers/net/ethernet/mellanox/Makefile +++ b/drivers/net/ethernet/mellanox/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/ obj-$(CONFIG_MLX5_CORE) += mlx5/core/ +obj-$(CONFIG_MLXSW_CORE) += mlxsw/ diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig new file mode 100644 index 000000000000..46268f260e1b --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig @@ -0,0 +1,11 @@ +# +# Mellanox switch drivers configuration +# + +config MLXSW_CORE + tristate "Mellanox Technologies Switch ASICs support" + ---help--- + This driver supports Mellanox Technologies Switch ASICs family. + + To compile this driver as a module, choose M here: the + module will be called mlxsw_core. diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile new file mode 100644 index 000000000000..271de28cc8ae --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_MLXSW_CORE) += mlxsw_core.o +mlxsw_core-objs := core.o diff --git a/drivers/net/ethernet/mellanox/mlxsw/cmd.h b/drivers/net/ethernet/mellanox/mlxsw/cmd.h new file mode 100644 index 000000000000..770db17eb03f --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/cmd.h @@ -0,0 +1,1090 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/cmd.h + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Jiri Pirko + * Copyright (c) 2015 Ido Schimmel + * + * 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 _MLXSW_CMD_H +#define _MLXSW_CMD_H + +#include "item.h" + +#define MLXSW_CMD_MBOX_SIZE 4096 + +static inline char *mlxsw_cmd_mbox_alloc(void) +{ + return kzalloc(MLXSW_CMD_MBOX_SIZE, GFP_KERNEL); +} + +static inline void mlxsw_cmd_mbox_free(char *mbox) +{ + kfree(mbox); +} + +static inline void mlxsw_cmd_mbox_zero(char *mbox) +{ + memset(mbox, 0, MLXSW_CMD_MBOX_SIZE); +} + +struct mlxsw_core; + +int mlxsw_cmd_exec(struct mlxsw_core *mlxsw_core, u16 opcode, u8 opcode_mod, + u32 in_mod, bool out_mbox_direct, + char *in_mbox, size_t in_mbox_size, + char *out_mbox, size_t out_mbox_size); + +static inline int mlxsw_cmd_exec_in(struct mlxsw_core *mlxsw_core, u16 opcode, + u8 opcode_mod, u32 in_mod, char *in_mbox, + size_t in_mbox_size) +{ + return mlxsw_cmd_exec(mlxsw_core, opcode, opcode_mod, in_mod, false, + in_mbox, in_mbox_size, NULL, 0); +} + +static inline int mlxsw_cmd_exec_out(struct mlxsw_core *mlxsw_core, u16 opcode, + u8 opcode_mod, u32 in_mod, + bool out_mbox_direct, + char *out_mbox, size_t out_mbox_size) +{ + return mlxsw_cmd_exec(mlxsw_core, opcode, opcode_mod, in_mod, + out_mbox_direct, NULL, 0, + out_mbox, out_mbox_size); +} + +static inline int mlxsw_cmd_exec_none(struct mlxsw_core *mlxsw_core, u16 opcode, + u8 opcode_mod, u32 in_mod) +{ + return mlxsw_cmd_exec(mlxsw_core, opcode, opcode_mod, in_mod, false, + NULL, 0, NULL, 0); +} + +enum mlxsw_cmd_opcode { + MLXSW_CMD_OPCODE_QUERY_FW = 0x004, + MLXSW_CMD_OPCODE_QUERY_BOARDINFO = 0x006, + MLXSW_CMD_OPCODE_QUERY_AQ_CAP = 0x003, + MLXSW_CMD_OPCODE_MAP_FA = 0xFFF, + MLXSW_CMD_OPCODE_UNMAP_FA = 0xFFE, + MLXSW_CMD_OPCODE_CONFIG_PROFILE = 0x100, + MLXSW_CMD_OPCODE_ACCESS_REG = 0x040, + MLXSW_CMD_OPCODE_SW2HW_DQ = 0x201, + MLXSW_CMD_OPCODE_HW2SW_DQ = 0x202, + MLXSW_CMD_OPCODE_2ERR_DQ = 0x01E, + MLXSW_CMD_OPCODE_QUERY_DQ = 0x022, + MLXSW_CMD_OPCODE_SW2HW_CQ = 0x016, + MLXSW_CMD_OPCODE_HW2SW_CQ = 0x017, + MLXSW_CMD_OPCODE_QUERY_CQ = 0x018, + MLXSW_CMD_OPCODE_SW2HW_EQ = 0x013, + MLXSW_CMD_OPCODE_HW2SW_EQ = 0x014, + MLXSW_CMD_OPCODE_QUERY_EQ = 0x015, +}; + +static inline const char *mlxsw_cmd_opcode_str(u16 opcode) +{ + switch (opcode) { + case MLXSW_CMD_OPCODE_QUERY_FW: + return "QUERY_FW"; + case MLXSW_CMD_OPCODE_QUERY_BOARDINFO: + return "QUERY_BOARDINFO"; + case MLXSW_CMD_OPCODE_QUERY_AQ_CAP: + return "QUERY_AQ_CAP"; + case MLXSW_CMD_OPCODE_MAP_FA: + return "MAP_FA"; + case MLXSW_CMD_OPCODE_UNMAP_FA: + return "UNMAP_FA"; + case MLXSW_CMD_OPCODE_CONFIG_PROFILE: + return "CONFIG_PROFILE"; + case MLXSW_CMD_OPCODE_ACCESS_REG: + return "ACCESS_REG"; + case MLXSW_CMD_OPCODE_SW2HW_DQ: + return "SW2HW_DQ"; + case MLXSW_CMD_OPCODE_HW2SW_DQ: + return "HW2SW_DQ"; + case MLXSW_CMD_OPCODE_2ERR_DQ: + return "2ERR_DQ"; + case MLXSW_CMD_OPCODE_QUERY_DQ: + return "QUERY_DQ"; + case MLXSW_CMD_OPCODE_SW2HW_CQ: + return "SW2HW_CQ"; + case MLXSW_CMD_OPCODE_HW2SW_CQ: + return "HW2SW_CQ"; + case MLXSW_CMD_OPCODE_QUERY_CQ: + return "QUERY_CQ"; + case MLXSW_CMD_OPCODE_SW2HW_EQ: + return "SW2HW_EQ"; + case MLXSW_CMD_OPCODE_HW2SW_EQ: + return "HW2SW_EQ"; + case MLXSW_CMD_OPCODE_QUERY_EQ: + return "QUERY_EQ"; + default: + return "*UNKNOWN*"; + } +} + +enum mlxsw_cmd_status { + /* Command execution succeeded. */ + MLXSW_CMD_STATUS_OK = 0x00, + /* Internal error (e.g. bus error) occurred while processing command. */ + MLXSW_CMD_STATUS_INTERNAL_ERR = 0x01, + /* Operation/command not supported or opcode modifier not supported. */ + MLXSW_CMD_STATUS_BAD_OP = 0x02, + /* Parameter not supported, parameter out of range. */ + MLXSW_CMD_STATUS_BAD_PARAM = 0x03, + /* System was not enabled or bad system state. */ + MLXSW_CMD_STATUS_BAD_SYS_STATE = 0x04, + /* Attempt to access reserved or unallocated resource, or resource in + * inappropriate ownership. + */ + MLXSW_CMD_STATUS_BAD_RESOURCE = 0x05, + /* Requested resource is currently executing a command. */ + MLXSW_CMD_STATUS_RESOURCE_BUSY = 0x06, + /* Required capability exceeds device limits. */ + MLXSW_CMD_STATUS_EXCEED_LIM = 0x08, + /* Resource is not in the appropriate state or ownership. */ + MLXSW_CMD_STATUS_BAD_RES_STATE = 0x09, + /* Index out of range (might be beyond table size or attempt to + * access a reserved resource). + */ + MLXSW_CMD_STATUS_BAD_INDEX = 0x0A, + /* NVMEM checksum/CRC failed. */ + MLXSW_CMD_STATUS_BAD_NVMEM = 0x0B, + /* Bad management packet (silently discarded). */ + MLXSW_CMD_STATUS_BAD_PKT = 0x30, +}; + +static inline const char *mlxsw_cmd_status_str(u8 status) +{ + switch (status) { + case MLXSW_CMD_STATUS_OK: + return "OK"; + case MLXSW_CMD_STATUS_INTERNAL_ERR: + return "INTERNAL_ERR"; + case MLXSW_CMD_STATUS_BAD_OP: + return "BAD_OP"; + case MLXSW_CMD_STATUS_BAD_PARAM: + return "BAD_PARAM"; + case MLXSW_CMD_STATUS_BAD_SYS_STATE: + return "BAD_SYS_STATE"; + case MLXSW_CMD_STATUS_BAD_RESOURCE: + return "BAD_RESOURCE"; + case MLXSW_CMD_STATUS_RESOURCE_BUSY: + return "RESOURCE_BUSY"; + case MLXSW_CMD_STATUS_EXCEED_LIM: + return "EXCEED_LIM"; + case MLXSW_CMD_STATUS_BAD_RES_STATE: + return "BAD_RES_STATE"; + case MLXSW_CMD_STATUS_BAD_INDEX: + return "BAD_INDEX"; + case MLXSW_CMD_STATUS_BAD_NVMEM: + return "BAD_NVMEM"; + case MLXSW_CMD_STATUS_BAD_PKT: + return "BAD_PKT"; + default: + return "*UNKNOWN*"; + } +} + +/* QUERY_FW - Query Firmware + * ------------------------- + * OpMod == 0, INMmod == 0 + * ----------------------- + * The QUERY_FW command retrieves information related to firmware, command + * interface version and the amount of resources that should be allocated to + * the firmware. + */ + +static inline int mlxsw_cmd_query_fw(struct mlxsw_core *mlxsw_core, + char *out_mbox) +{ + return mlxsw_cmd_exec_out(mlxsw_core, MLXSW_CMD_OPCODE_QUERY_FW, + 0, 0, false, out_mbox, MLXSW_CMD_MBOX_SIZE); +} + +/* cmd_mbox_query_fw_fw_pages + * Amount of physical memory to be allocatedfor firmware usage in 4KB pages. + */ +MLXSW_ITEM32(cmd_mbox, query_fw, fw_pages, 0x00, 16, 16); + +/* cmd_mbox_query_fw_fw_rev_major + * Firmware Revision - Major + */ +MLXSW_ITEM32(cmd_mbox, query_fw, fw_rev_major, 0x00, 0, 16); + +/* cmd_mbox_query_fw_fw_rev_subminor + * Firmware Sub-minor version (Patch level) + */ +MLXSW_ITEM32(cmd_mbox, query_fw, fw_rev_subminor, 0x04, 16, 16); + +/* cmd_mbox_query_fw_fw_rev_minor + * Firmware Revision - Minor + */ +MLXSW_ITEM32(cmd_mbox, query_fw, fw_rev_minor, 0x04, 0, 16); + +/* cmd_mbox_query_fw_core_clk + * Internal Clock Frequency (in MHz) + */ +MLXSW_ITEM32(cmd_mbox, query_fw, core_clk, 0x08, 16, 16); + +/* cmd_mbox_query_fw_cmd_interface_rev + * Command Interface Interpreter Revision ID. This number is bumped up + * every time a non-backward-compatible change is done for the command + * interface. The current cmd_interface_rev is 1. + */ +MLXSW_ITEM32(cmd_mbox, query_fw, cmd_interface_rev, 0x08, 0, 16); + +/* cmd_mbox_query_fw_dt + * If set, Debug Trace is supported + */ +MLXSW_ITEM32(cmd_mbox, query_fw, dt, 0x0C, 31, 1); + +/* cmd_mbox_query_fw_api_version + * Indicates the version of the API, to enable software querying + * for compatibility. The current api_version is 1. + */ +MLXSW_ITEM32(cmd_mbox, query_fw, api_version, 0x0C, 0, 16); + +/* cmd_mbox_query_fw_fw_hour + * Firmware timestamp - hour + */ +MLXSW_ITEM32(cmd_mbox, query_fw, fw_hour, 0x10, 24, 8); + +/* cmd_mbox_query_fw_fw_minutes + * Firmware timestamp - minutes + */ +MLXSW_ITEM32(cmd_mbox, query_fw, fw_minutes, 0x10, 16, 8); + +/* cmd_mbox_query_fw_fw_seconds + * Firmware timestamp - seconds + */ +MLXSW_ITEM32(cmd_mbox, query_fw, fw_seconds, 0x10, 8, 8); + +/* cmd_mbox_query_fw_fw_year + * Firmware timestamp - year + */ +MLXSW_ITEM32(cmd_mbox, query_fw, fw_year, 0x14, 16, 16); + +/* cmd_mbox_query_fw_fw_month + * Firmware timestamp - month + */ +MLXSW_ITEM32(cmd_mbox, query_fw, fw_month, 0x14, 8, 8); + +/* cmd_mbox_query_fw_fw_day + * Firmware timestamp - day + */ +MLXSW_ITEM32(cmd_mbox, query_fw, fw_day, 0x14, 0, 8); + +/* cmd_mbox_query_fw_clr_int_base_offset + * Clear Interrupt register's offset from clr_int_bar register + * in PCI address space. + */ +MLXSW_ITEM64(cmd_mbox, query_fw, clr_int_base_offset, 0x20, 0, 64); + +/* cmd_mbox_query_fw_clr_int_bar + * PCI base address register (BAR) where clr_int register is located. + * 00 - BAR 0-1 (64 bit BAR) + */ +MLXSW_ITEM32(cmd_mbox, query_fw, clr_int_bar, 0x28, 30, 2); + +/* cmd_mbox_query_fw_error_buf_offset + * Read Only buffer for internal error reports of offset + * from error_buf_bar register in PCI address space). + */ +MLXSW_ITEM64(cmd_mbox, query_fw, error_buf_offset, 0x30, 0, 64); + +/* cmd_mbox_query_fw_error_buf_size + * Internal error buffer size in DWORDs + */ +MLXSW_ITEM32(cmd_mbox, query_fw, error_buf_size, 0x38, 0, 32); + +/* cmd_mbox_query_fw_error_int_bar + * PCI base address register (BAR) where error buffer + * register is located. + * 00 - BAR 0-1 (64 bit BAR) + */ +MLXSW_ITEM32(cmd_mbox, query_fw, error_int_bar, 0x3C, 30, 2); + +/* cmd_mbox_query_fw_doorbell_page_offset + * Offset of the doorbell page + */ +MLXSW_ITEM64(cmd_mbox, query_fw, doorbell_page_offset, 0x40, 0, 64); + +/* cmd_mbox_query_fw_doorbell_page_bar + * PCI base address register (BAR) of the doorbell page + * 00 - BAR 0-1 (64 bit BAR) + */ +MLXSW_ITEM32(cmd_mbox, query_fw, doorbell_page_bar, 0x48, 30, 2); + +/* QUERY_BOARDINFO - Query Board Information + * ----------------------------------------- + * OpMod == 0 (N/A), INMmod == 0 (N/A) + * ----------------------------------- + * The QUERY_BOARDINFO command retrieves adapter specific parameters. + */ + +static inline int mlxsw_cmd_boardinfo(struct mlxsw_core *mlxsw_core, + char *out_mbox) +{ + return mlxsw_cmd_exec_out(mlxsw_core, MLXSW_CMD_OPCODE_QUERY_BOARDINFO, + 0, 0, false, out_mbox, MLXSW_CMD_MBOX_SIZE); +} + +/* cmd_mbox_boardinfo_intapin + * When PCIe interrupt messages are being used, this value is used for clearing + * an interrupt. When using MSI-X, this register is not used. + */ +MLXSW_ITEM32(cmd_mbox, boardinfo, intapin, 0x10, 24, 8); + +/* cmd_mbox_boardinfo_vsd_vendor_id + * PCISIG Vendor ID (www.pcisig.com/membership/vid_search) of the vendor + * specifying/formatting the VSD. The vsd_vendor_id identifies the management + * domain of the VSD/PSID data. Different vendors may choose different VSD/PSID + * format and encoding as long as they use their assigned vsd_vendor_id. + */ +MLXSW_ITEM32(cmd_mbox, boardinfo, vsd_vendor_id, 0x1C, 0, 16); + +/* cmd_mbox_boardinfo_vsd + * Vendor Specific Data. The VSD string that is burnt to the Flash + * with the firmware. + */ +#define MLXSW_CMD_BOARDINFO_VSD_LEN 208 +MLXSW_ITEM_BUF(cmd_mbox, boardinfo, vsd, 0x20, MLXSW_CMD_BOARDINFO_VSD_LEN); + +/* cmd_mbox_boardinfo_psid + * The PSID field is a 16-ascii (byte) character string which acts as + * the board ID. The PSID format is used in conjunction with + * Mellanox vsd_vendor_id (15B3h). + */ +#define MLXSW_CMD_BOARDINFO_PSID_LEN 16 +MLXSW_ITEM_BUF(cmd_mbox, boardinfo, psid, 0xF0, MLXSW_CMD_BOARDINFO_PSID_LEN); + +/* QUERY_AQ_CAP - Query Asynchronous Queues Capabilities + * ----------------------------------------------------- + * OpMod == 0 (N/A), INMmod == 0 (N/A) + * ----------------------------------- + * The QUERY_AQ_CAP command returns the device asynchronous queues + * capabilities supported. + */ + +static inline int mlxsw_cmd_query_aq_cap(struct mlxsw_core *mlxsw_core, + char *out_mbox) +{ + return mlxsw_cmd_exec_out(mlxsw_core, MLXSW_CMD_OPCODE_QUERY_AQ_CAP, + 0, 0, false, out_mbox, MLXSW_CMD_MBOX_SIZE); +} + +/* cmd_mbox_query_aq_cap_log_max_sdq_sz + * Log (base 2) of max WQEs allowed on SDQ. + */ +MLXSW_ITEM32(cmd_mbox, query_aq_cap, log_max_sdq_sz, 0x00, 24, 8); + +/* cmd_mbox_query_aq_cap_max_num_sdqs + * Maximum number of SDQs. + */ +MLXSW_ITEM32(cmd_mbox, query_aq_cap, max_num_sdqs, 0x00, 0, 8); + +/* cmd_mbox_query_aq_cap_log_max_rdq_sz + * Log (base 2) of max WQEs allowed on RDQ. + */ +MLXSW_ITEM32(cmd_mbox, query_aq_cap, log_max_rdq_sz, 0x04, 24, 8); + +/* cmd_mbox_query_aq_cap_max_num_rdqs + * Maximum number of RDQs. + */ +MLXSW_ITEM32(cmd_mbox, query_aq_cap, max_num_rdqs, 0x04, 0, 8); + +/* cmd_mbox_query_aq_cap_log_max_cq_sz + * Log (base 2) of max CQEs allowed on CQ. + */ +MLXSW_ITEM32(cmd_mbox, query_aq_cap, log_max_cq_sz, 0x08, 24, 8); + +/* cmd_mbox_query_aq_cap_max_num_cqs + * Maximum number of CQs. + */ +MLXSW_ITEM32(cmd_mbox, query_aq_cap, max_num_cqs, 0x08, 0, 8); + +/* cmd_mbox_query_aq_cap_log_max_eq_sz + * Log (base 2) of max EQEs allowed on EQ. + */ +MLXSW_ITEM32(cmd_mbox, query_aq_cap, log_max_eq_sz, 0x0C, 24, 8); + +/* cmd_mbox_query_aq_cap_max_num_eqs + * Maximum number of EQs. + */ +MLXSW_ITEM32(cmd_mbox, query_aq_cap, max_num_eqs, 0x0C, 0, 8); + +/* cmd_mbox_query_aq_cap_max_sg_sq + * The maximum S/G list elements in an DSQ. DSQ must not contain + * more S/G entries than indicated here. + */ +MLXSW_ITEM32(cmd_mbox, query_aq_cap, max_sg_sq, 0x10, 8, 8); + +/* cmd_mbox_query_aq_cap_ + * The maximum S/G list elements in an DRQ. DRQ must not contain + * more S/G entries than indicated here. + */ +MLXSW_ITEM32(cmd_mbox, query_aq_cap, max_sg_rq, 0x10, 0, 8); + +/* MAP_FA - Map Firmware Area + * -------------------------- + * OpMod == 0 (N/A), INMmod == Number of VPM entries + * ------------------------------------------------- + * The MAP_FA command passes physical pages to the switch. These pages + * are used to store the device firmware. MAP_FA can be executed multiple + * times until all the firmware area is mapped (the size that should be + * mapped is retrieved through the QUERY_FW command). All required pages + * must be mapped to finish the initialization phase. Physical memory + * passed in this command must be pinned. + */ + +static inline int mlxsw_cmd_map_fa(struct mlxsw_core *mlxsw_core, + char *in_mbox, u32 vpm_entries_count) +{ + return mlxsw_cmd_exec_in(mlxsw_core, MLXSW_CMD_OPCODE_MAP_FA, + 0, vpm_entries_count, + in_mbox, MLXSW_CMD_MBOX_SIZE); +} + +/* cmd_mbox_map_fa_pa + * Physical Address. + */ +MLXSW_ITEM64_INDEXED(cmd_mbox, map_fa, pa, 0x00, 12, 52, 0x08, 0x00, true); + +/* cmd_mbox_map_fa_log2size + * Log (base 2) of the size in 4KB pages of the physical and contiguous memory + * that starts at PA_L/H. + */ +MLXSW_ITEM32_INDEXED(cmd_mbox, map_fa, log2size, 0x00, 0, 5, 0x08, 0x04, false); + +/* UNMAP_FA - Unmap Firmware Area + * ------------------------------ + * OpMod == 0 (N/A), INMmod == 0 (N/A) + * ----------------------------------- + * The UNMAP_FA command unload the firmware and unmaps all the + * firmware area. After this command is completed the device will not access + * the pages that were mapped to the firmware area. After executing UNMAP_FA + * command, software reset must be done prior to execution of MAP_FW command. + */ + +static inline int mlxsw_cmd_unmap_fa(struct mlxsw_core *mlxsw_core) +{ + return mlxsw_cmd_exec_none(mlxsw_core, MLXSW_CMD_OPCODE_UNMAP_FA, 0, 0); +} + +/* CONFIG_PROFILE (Set) - Configure Switch Profile + * ------------------------------ + * OpMod == 1 (Set), INMmod == 0 (N/A) + * ----------------------------------- + * The CONFIG_PROFILE command sets the switch profile. The command can be + * executed on the device only once at startup in order to allocate and + * configure all switch resources and prepare it for operational mode. + * It is not possible to change the device profile after the chip is + * in operational mode. + * Failure of the CONFIG_PROFILE command leaves the hardware in an indeterminate + * state therefore it is required to perform software reset to the device + * following an unsuccessful completion of the command. It is required + * to perform software reset to the device to change an existing profile. + */ + +static inline int mlxsw_cmd_config_profile_set(struct mlxsw_core *mlxsw_core, + char *in_mbox) +{ + return mlxsw_cmd_exec_in(mlxsw_core, MLXSW_CMD_OPCODE_CONFIG_PROFILE, + 1, 0, in_mbox, MLXSW_CMD_MBOX_SIZE); +} + +/* cmd_mbox_config_profile_set_max_vepa_channels + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_max_vepa_channels, 0x0C, 0, 1); + +/* cmd_mbox_config_profile_set_max_lag + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_max_lag, 0x0C, 1, 1); + +/* cmd_mbox_config_profile_set_max_port_per_lag + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_max_port_per_lag, 0x0C, 2, 1); + +/* cmd_mbox_config_profile_set_max_mid + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_max_mid, 0x0C, 3, 1); + +/* cmd_mbox_config_profile_set_max_pgt + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_max_pgt, 0x0C, 4, 1); + +/* cmd_mbox_config_profile_set_max_system_port + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_max_system_port, 0x0C, 5, 1); + +/* cmd_mbox_config_profile_set_max_vlan_groups + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_max_vlan_groups, 0x0C, 6, 1); + +/* cmd_mbox_config_profile_set_max_regions + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_max_regions, 0x0C, 7, 1); + +/* cmd_mbox_config_profile_set_fid_based + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_flood_mode, 0x0C, 8, 1); + +/* cmd_mbox_config_profile_set_max_flood_tables + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_flood_tables, 0x0C, 9, 1); + +/* cmd_mbox_config_profile_set_max_ib_mc + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_max_ib_mc, 0x0C, 12, 1); + +/* cmd_mbox_config_profile_set_max_pkey + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_max_pkey, 0x0C, 13, 1); + +/* cmd_mbox_config_profile_set_adaptive_routing_group_cap + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, + set_adaptive_routing_group_cap, 0x0C, 14, 1); + +/* cmd_mbox_config_profile_set_ar_sec + * Capability bit. Setting a bit to 1 configures the profile + * according to the mailbox contents. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, set_ar_sec, 0x0C, 15, 1); + +/* cmd_mbox_config_profile_max_vepa_channels + * Maximum number of VEPA channels per port (0 through 16) + * 0 - multi-channel VEPA is disabled + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_vepa_channels, 0x10, 0, 8); + +/* cmd_mbox_config_profile_max_lag + * Maximum number of LAG IDs requested. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_lag, 0x14, 0, 16); + +/* cmd_mbox_config_profile_max_port_per_lag + * Maximum number of ports per LAG requested. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_port_per_lag, 0x18, 0, 16); + +/* cmd_mbox_config_profile_max_mid + * Maximum Multicast IDs. + * Multicast IDs are allocated from 0 to max_mid-1 + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_mid, 0x1C, 0, 16); + +/* cmd_mbox_config_profile_max_pgt + * Maximum records in the Port Group Table per Switch Partition. + * Port Group Table indexes are from 0 to max_pgt-1 + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_pgt, 0x20, 0, 16); + +/* cmd_mbox_config_profile_max_system_port + * The maximum number of system ports that can be allocated. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_system_port, 0x24, 0, 16); + +/* cmd_mbox_config_profile_max_vlan_groups + * Maximum number VLAN Groups for VLAN binding. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_vlan_groups, 0x28, 0, 12); + +/* cmd_mbox_config_profile_max_regions + * Maximum number of TCAM Regions. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_regions, 0x2C, 0, 16); + +/* cmd_mbox_config_profile_max_flood_tables + * Maximum number of Flooding Tables. Flooding Tables are associated to + * the different packet types for the different switch partitions. + * Note that the table size depends on the fid_based mode. + * In SwitchX silicon, tables are split equally between the switch + * partitions. e.g. for 2 swids and 8 tables, the first 4 are associated + * with swid-1 and the last 4 are associated with swid-2. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_flood_tables, 0x30, 16, 4); + +/* cmd_mbox_config_profile_max_vid_flood_tables + * Maximum number of per-vid flooding tables. Flooding tables are associated + * to the different packet types for the different switch partitions. + * Table size is 4K entries covering all VID space. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_vid_flood_tables, 0x30, 8, 4); + +/* cmd_mbox_config_profile_fid_based + * FID Based Flood Mode + * 00 Do not use FID to offset the index into the Port Group Table/Multicast ID + * 01 Use FID to offset the index to the Port Group Table (pgi) + * 10 Use FID to offset the index to the Port Group Table (pgi) and + * the Multicast ID + */ +MLXSW_ITEM32(cmd_mbox, config_profile, flood_mode, 0x30, 0, 2); + +/* cmd_mbox_config_profile_max_ib_mc + * Maximum number of multicast FDB records for InfiniBand + * FDB (in 512 chunks) per InfiniBand switch partition. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_ib_mc, 0x40, 0, 15); + +/* cmd_mbox_config_profile_max_pkey + * Maximum per port PKEY table size (for PKEY enforcement) + */ +MLXSW_ITEM32(cmd_mbox, config_profile, max_pkey, 0x44, 0, 15); + +/* cmd_mbox_config_profile_ar_sec + * Primary/secondary capability + * Describes the number of adaptive routing sub-groups + * 0 - disable primary/secondary (single group) + * 1 - enable primary/secondary (2 sub-groups) + * 2 - 3 sub-groups: Not supported in SwitchX, SwitchX-2 + * 3 - 4 sub-groups: Not supported in SwitchX, SwitchX-2 + */ +MLXSW_ITEM32(cmd_mbox, config_profile, ar_sec, 0x4C, 24, 2); + +/* cmd_mbox_config_profile_adaptive_routing_group_cap + * Adaptive Routing Group Capability. Indicates the number of AR groups + * supported. Note that when Primary/secondary is enabled, each + * primary/secondary couple consumes 2 adaptive routing entries. + */ +MLXSW_ITEM32(cmd_mbox, config_profile, adaptive_routing_group_cap, 0x4C, 0, 16); + +/* cmd_mbox_config_profile_arn + * Adaptive Routing Notification Enable + * Not supported in SwitchX, SwitchX-2 + */ +MLXSW_ITEM32(cmd_mbox, config_profile, arn, 0x50, 31, 1); + +/* cmd_mbox_config_profile_swid_config_mask + * Modify Switch Partition Configuration mask. When set, the configu- + * ration value for the Switch Partition are taken from the mailbox. + * When clear, the current configuration values are used. + * Bit 0 - set type + * Bit 1 - properties + * Other - reserved + */ +MLXSW_ITEM32_INDEXED(cmd_mbox, config_profile, swid_config_mask, + 0x60, 24, 8, 0x08, 0x00, false); + +/* cmd_mbox_config_profile_swid_config_type + * Switch Partition type. + * 0000 - disabled (Switch Partition does not exist) + * 0001 - InfiniBand + * 0010 - Ethernet + * 1000 - router port (SwitchX-2 only) + * Other - reserved + */ +MLXSW_ITEM32_INDEXED(cmd_mbox, config_profile, swid_config_type, + 0x60, 20, 4, 0x08, 0x00, false); + +/* cmd_mbox_config_profile_swid_config_properties + * Switch Partition properties. + */ +MLXSW_ITEM32_INDEXED(cmd_mbox, config_profile, swid_config_properties, + 0x60, 0, 8, 0x08, 0x00, false); + +/* ACCESS_REG - Access EMAD Supported Register + * ---------------------------------- + * OpMod == 0 (N/A), INMmod == 0 (N/A) + * ------------------------------------- + * The ACCESS_REG command supports accessing device registers. This access + * is mainly used for bootstrapping. + */ + +static inline int mlxsw_cmd_access_reg(struct mlxsw_core *mlxsw_core, + char *in_mbox, char *out_mbox) +{ + return mlxsw_cmd_exec(mlxsw_core, MLXSW_CMD_OPCODE_ACCESS_REG, + 0, 0, false, in_mbox, MLXSW_CMD_MBOX_SIZE, + out_mbox, MLXSW_CMD_MBOX_SIZE); +} + +/* SW2HW_DQ - Software to Hardware DQ + * ---------------------------------- + * OpMod == 0 (send DQ) / OpMod == 1 (receive DQ) + * INMmod == DQ number + * ---------------------------------------------- + * The SW2HW_DQ command transitions a descriptor queue from software to + * hardware ownership. The command enables posting WQEs and ringing DoorBells + * on the descriptor queue. + */ + +static inline int __mlxsw_cmd_sw2hw_dq(struct mlxsw_core *mlxsw_core, + char *in_mbox, u32 dq_number, + u8 opcode_mod) +{ + return mlxsw_cmd_exec_in(mlxsw_core, MLXSW_CMD_OPCODE_SW2HW_DQ, + opcode_mod, dq_number, + in_mbox, MLXSW_CMD_MBOX_SIZE); +} + +enum { + MLXSW_CMD_OPCODE_MOD_SDQ = 0, + MLXSW_CMD_OPCODE_MOD_RDQ = 1, +}; + +static inline int mlxsw_cmd_sw2hw_sdq(struct mlxsw_core *mlxsw_core, + char *in_mbox, u32 dq_number) +{ + return __mlxsw_cmd_sw2hw_dq(mlxsw_core, in_mbox, dq_number, + MLXSW_CMD_OPCODE_MOD_SDQ); +} + +static inline int mlxsw_cmd_sw2hw_rdq(struct mlxsw_core *mlxsw_core, + char *in_mbox, u32 dq_number) +{ + return __mlxsw_cmd_sw2hw_dq(mlxsw_core, in_mbox, dq_number, + MLXSW_CMD_OPCODE_MOD_RDQ); +} + +/* cmd_mbox_sw2hw_dq_cq + * Number of the CQ that this Descriptor Queue reports completions to. + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_dq, cq, 0x00, 24, 8); + +/* cmd_mbox_sw2hw_dq_sdq_tclass + * SDQ: CPU Egress TClass + * RDQ: Reserved + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_dq, sdq_tclass, 0x00, 16, 6); + +/* cmd_mbox_sw2hw_dq_log2_dq_sz + * Log (base 2) of the Descriptor Queue size in 4KB pages. + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_dq, log2_dq_sz, 0x00, 0, 6); + +/* cmd_mbox_sw2hw_dq_pa + * Physical Address. + */ +MLXSW_ITEM64_INDEXED(cmd_mbox, sw2hw_dq, pa, 0x10, 12, 52, 0x08, 0x00, true); + +/* HW2SW_DQ - Hardware to Software DQ + * ---------------------------------- + * OpMod == 0 (send DQ) / OpMod == 1 (receive DQ) + * INMmod == DQ number + * ---------------------------------------------- + * The HW2SW_DQ command transitions a descriptor queue from hardware to + * software ownership. Incoming packets on the DQ are silently discarded, + * SW should not post descriptors on nonoperational DQs. + */ + +static inline int __mlxsw_cmd_hw2sw_dq(struct mlxsw_core *mlxsw_core, + u32 dq_number, u8 opcode_mod) +{ + return mlxsw_cmd_exec_none(mlxsw_core, MLXSW_CMD_OPCODE_HW2SW_DQ, + opcode_mod, dq_number); +} + +static inline int mlxsw_cmd_hw2sw_sdq(struct mlxsw_core *mlxsw_core, + u32 dq_number) +{ + return __mlxsw_cmd_hw2sw_dq(mlxsw_core, dq_number, + MLXSW_CMD_OPCODE_MOD_SDQ); +} + +static inline int mlxsw_cmd_hw2sw_rdq(struct mlxsw_core *mlxsw_core, + u32 dq_number) +{ + return __mlxsw_cmd_hw2sw_dq(mlxsw_core, dq_number, + MLXSW_CMD_OPCODE_MOD_RDQ); +} + +/* 2ERR_DQ - To Error DQ + * --------------------- + * OpMod == 0 (send DQ) / OpMod == 1 (receive DQ) + * INMmod == DQ number + * ---------------------------------------------- + * The 2ERR_DQ command transitions the DQ into the error state from the state + * in which it has been. While the command is executed, some in-process + * descriptors may complete. Once the DQ transitions into the error state, + * if there are posted descriptors on the RDQ/SDQ, the hardware writes + * a completion with error (flushed) for all descriptors posted in the RDQ/SDQ. + * When the command is completed successfully, the DQ is already in + * the error state. + */ + +static inline int __mlxsw_cmd_2err_dq(struct mlxsw_core *mlxsw_core, + u32 dq_number, u8 opcode_mod) +{ + return mlxsw_cmd_exec_none(mlxsw_core, MLXSW_CMD_OPCODE_2ERR_DQ, + opcode_mod, dq_number); +} + +static inline int mlxsw_cmd_2err_sdq(struct mlxsw_core *mlxsw_core, + u32 dq_number) +{ + return __mlxsw_cmd_2err_dq(mlxsw_core, dq_number, + MLXSW_CMD_OPCODE_MOD_SDQ); +} + +static inline int mlxsw_cmd_2err_rdq(struct mlxsw_core *mlxsw_core, + u32 dq_number) +{ + return __mlxsw_cmd_2err_dq(mlxsw_core, dq_number, + MLXSW_CMD_OPCODE_MOD_RDQ); +} + +/* QUERY_DQ - Query DQ + * --------------------- + * OpMod == 0 (send DQ) / OpMod == 1 (receive DQ) + * INMmod == DQ number + * ---------------------------------------------- + * The QUERY_DQ command retrieves a snapshot of DQ parameters from the hardware. + * + * Note: Output mailbox has the same format as SW2HW_DQ. + */ + +static inline int __mlxsw_cmd_query_dq(struct mlxsw_core *mlxsw_core, + char *out_mbox, u32 dq_number, + u8 opcode_mod) +{ + return mlxsw_cmd_exec_out(mlxsw_core, MLXSW_CMD_OPCODE_2ERR_DQ, + opcode_mod, dq_number, false, + out_mbox, MLXSW_CMD_MBOX_SIZE); +} + +static inline int mlxsw_cmd_query_sdq(struct mlxsw_core *mlxsw_core, + char *out_mbox, u32 dq_number) +{ + return __mlxsw_cmd_query_dq(mlxsw_core, out_mbox, dq_number, + MLXSW_CMD_OPCODE_MOD_SDQ); +} + +static inline int mlxsw_cmd_query_rdq(struct mlxsw_core *mlxsw_core, + char *out_mbox, u32 dq_number) +{ + return __mlxsw_cmd_query_dq(mlxsw_core, out_mbox, dq_number, + MLXSW_CMD_OPCODE_MOD_RDQ); +} + +/* SW2HW_CQ - Software to Hardware CQ + * ---------------------------------- + * OpMod == 0 (N/A), INMmod == CQ number + * ------------------------------------- + * The SW2HW_CQ command transfers ownership of a CQ context entry from software + * to hardware. The command takes the CQ context entry from the input mailbox + * and stores it in the CQC in the ownership of the hardware. The command fails + * if the requested CQC entry is already in the ownership of the hardware. + */ + +static inline int mlxsw_cmd_sw2hw_cq(struct mlxsw_core *mlxsw_core, + char *in_mbox, u32 cq_number) +{ + return mlxsw_cmd_exec_in(mlxsw_core, MLXSW_CMD_OPCODE_SW2HW_CQ, + 0, cq_number, in_mbox, MLXSW_CMD_MBOX_SIZE); +} + +/* cmd_mbox_sw2hw_cq_cv + * CQE Version. + * 0 - CQE Version 0, 1 - CQE Version 1 + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_cq, cv, 0x00, 28, 4); + +/* cmd_mbox_sw2hw_cq_c_eqn + * Event Queue this CQ reports completion events to. + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_cq, c_eqn, 0x00, 24, 1); + +/* cmd_mbox_sw2hw_cq_oi + * When set, overrun ignore is enabled. When set, updates of + * CQ consumer counter (poll for completion) or Request completion + * notifications (Arm CQ) DoorBells should not be rung on that CQ. + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_cq, oi, 0x00, 12, 1); + +/* cmd_mbox_sw2hw_cq_st + * Event delivery state machine + * 0x0 - FIRED + * 0x1 - ARMED (Request for Notification) + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_cq, st, 0x00, 8, 1); + +/* cmd_mbox_sw2hw_cq_log_cq_size + * Log (base 2) of the CQ size (in entries). + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_cq, log_cq_size, 0x00, 0, 4); + +/* cmd_mbox_sw2hw_cq_producer_counter + * Producer Counter. The counter is incremented for each CQE that is + * written by the HW to the CQ. + * Maintained by HW (valid for the QUERY_CQ command only) + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_cq, producer_counter, 0x04, 0, 16); + +/* cmd_mbox_sw2hw_cq_pa + * Physical Address. + */ +MLXSW_ITEM64_INDEXED(cmd_mbox, sw2hw_cq, pa, 0x10, 11, 53, 0x08, 0x00, true); + +/* HW2SW_CQ - Hardware to Software CQ + * ---------------------------------- + * OpMod == 0 (N/A), INMmod == CQ number + * ------------------------------------- + * The HW2SW_CQ command transfers ownership of a CQ context entry from hardware + * to software. The CQC entry is invalidated as a result of this command. + */ + +static inline int mlxsw_cmd_hw2sw_cq(struct mlxsw_core *mlxsw_core, + u32 cq_number) +{ + return mlxsw_cmd_exec_none(mlxsw_core, MLXSW_CMD_OPCODE_HW2SW_CQ, + 0, cq_number); +} + +/* QUERY_CQ - Query CQ + * ---------------------------------- + * OpMod == 0 (N/A), INMmod == CQ number + * ------------------------------------- + * The QUERY_CQ command retrieves a snapshot of the current CQ context entry. + * The command stores the snapshot in the output mailbox in the software format. + * Note that the CQ context state and values are not affected by the QUERY_CQ + * command. The QUERY_CQ command is for debug purposes only. + * + * Note: Output mailbox has the same format as SW2HW_CQ. + */ + +static inline int mlxsw_cmd_query_cq(struct mlxsw_core *mlxsw_core, + char *out_mbox, u32 cq_number) +{ + return mlxsw_cmd_exec_out(mlxsw_core, MLXSW_CMD_OPCODE_QUERY_CQ, + 0, cq_number, false, + out_mbox, MLXSW_CMD_MBOX_SIZE); +} + +/* SW2HW_EQ - Software to Hardware EQ + * ---------------------------------- + * OpMod == 0 (N/A), INMmod == EQ number + * ------------------------------------- + * The SW2HW_EQ command transfers ownership of an EQ context entry from software + * to hardware. The command takes the EQ context entry from the input mailbox + * and stores it in the EQC in the ownership of the hardware. The command fails + * if the requested EQC entry is already in the ownership of the hardware. + */ + +static inline int mlxsw_cmd_sw2hw_eq(struct mlxsw_core *mlxsw_core, + char *in_mbox, u32 eq_number) +{ + return mlxsw_cmd_exec_in(mlxsw_core, MLXSW_CMD_OPCODE_SW2HW_EQ, + 0, eq_number, in_mbox, MLXSW_CMD_MBOX_SIZE); +} + +/* cmd_mbox_sw2hw_eq_int_msix + * When set, MSI-X cycles will be generated by this EQ. + * When cleared, an interrupt will be generated by this EQ. + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_eq, int_msix, 0x00, 24, 1); + +/* cmd_mbox_sw2hw_eq_int_oi + * When set, overrun ignore is enabled. + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_eq, oi, 0x00, 12, 1); + +/* cmd_mbox_sw2hw_eq_int_st + * Event delivery state machine + * 0x0 - FIRED + * 0x1 - ARMED (Request for Notification) + * 0x11 - Always ARMED + * other - reserved + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_eq, st, 0x00, 8, 2); + +/* cmd_mbox_sw2hw_eq_int_log_eq_size + * Log (base 2) of the EQ size (in entries). + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_eq, log_eq_size, 0x00, 0, 4); + +/* cmd_mbox_sw2hw_eq_int_producer_counter + * Producer Counter. The counter is incremented for each EQE that is written + * by the HW to the EQ. + * Maintained by HW (valid for the QUERY_EQ command only) + */ +MLXSW_ITEM32(cmd_mbox, sw2hw_eq, producer_counter, 0x04, 0, 16); + +/* cmd_mbox_sw2hw_eq_int_pa + * Physical Address. + */ +MLXSW_ITEM64_INDEXED(cmd_mbox, sw2hw_eq, pa, 0x10, 11, 53, 0x08, 0x00, true); + +/* HW2SW_EQ - Hardware to Software EQ + * ---------------------------------- + * OpMod == 0 (N/A), INMmod == EQ number + * ------------------------------------- + */ + +static inline int mlxsw_cmd_hw2sw_eq(struct mlxsw_core *mlxsw_core, + u32 eq_number) +{ + return mlxsw_cmd_exec_none(mlxsw_core, MLXSW_CMD_OPCODE_HW2SW_EQ, + 0, eq_number); +} + +/* QUERY_EQ - Query EQ + * ---------------------------------- + * OpMod == 0 (N/A), INMmod == EQ number + * ------------------------------------- + * + * Note: Output mailbox has the same format as SW2HW_EQ. + */ + +static inline int mlxsw_cmd_query_eq(struct mlxsw_core *mlxsw_core, + char *out_mbox, u32 eq_number) +{ + return mlxsw_cmd_exec_out(mlxsw_core, MLXSW_CMD_OPCODE_QUERY_EQ, + 0, eq_number, false, + out_mbox, MLXSW_CMD_MBOX_SIZE); +} + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c new file mode 100644 index 000000000000..a4bb94bf7a44 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -0,0 +1,550 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/core.c + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Jiri Pirko + * Copyright (c) 2015 Ido Schimmel + * Copyright (c) 2015 Elad Raz + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "item.h" +#include "cmd.h" +#include "port.h" +#include "trap.h" + +static LIST_HEAD(mlxsw_core_driver_list); +static DEFINE_SPINLOCK(mlxsw_core_driver_list_lock); + +static const char mlxsw_core_driver_name[] = "mlxsw_core"; + +static struct dentry *mlxsw_core_dbg_root; + +struct mlxsw_core_pcpu_stats { + u64 trap_rx_packets[MLXSW_TRAP_ID_MAX]; + u64 trap_rx_bytes[MLXSW_TRAP_ID_MAX]; + u64 port_rx_packets[MLXSW_PORT_MAX_PORTS]; + u64 port_rx_bytes[MLXSW_PORT_MAX_PORTS]; + struct u64_stats_sync syncp; + u32 trap_rx_dropped[MLXSW_TRAP_ID_MAX]; + u32 port_rx_dropped[MLXSW_PORT_MAX_PORTS]; + u32 trap_rx_invalid; + u32 port_rx_invalid; +}; + +struct mlxsw_core { + struct mlxsw_driver *driver; + const struct mlxsw_bus *bus; + void *bus_priv; + const struct mlxsw_bus_info *bus_info; + struct list_head rx_listener_list; + struct mlxsw_core_pcpu_stats __percpu *pcpu_stats; + struct dentry *dbg_dir; + struct { + struct debugfs_blob_wrapper vsd_blob; + struct debugfs_blob_wrapper psid_blob; + } dbg; + unsigned long driver_priv[0]; + /* driver_priv has to be always the last item */ +}; + +struct mlxsw_rx_listener_item { + struct list_head list; + struct mlxsw_rx_listener rxl; + void *priv; +}; + +/***************** + * Core functions + *****************/ + +static int mlxsw_core_rx_stats_dbg_read(struct seq_file *file, void *data) +{ + struct mlxsw_core *mlxsw_core = file->private; + struct mlxsw_core_pcpu_stats *p; + u64 rx_packets, rx_bytes; + u64 tmp_rx_packets, tmp_rx_bytes; + u32 rx_dropped, rx_invalid; + unsigned int start; + int i; + int j; + static const char hdr[] = + " NUM RX_PACKETS RX_BYTES RX_DROPPED\n"; + + seq_printf(file, hdr); + for (i = 0; i < MLXSW_TRAP_ID_MAX; i++) { + rx_packets = 0; + rx_bytes = 0; + rx_dropped = 0; + for_each_possible_cpu(j) { + p = per_cpu_ptr(mlxsw_core->pcpu_stats, j); + do { + start = u64_stats_fetch_begin(&p->syncp); + tmp_rx_packets = p->trap_rx_packets[i]; + tmp_rx_bytes = p->trap_rx_bytes[i]; + } while (u64_stats_fetch_retry(&p->syncp, start)); + + rx_packets += tmp_rx_packets; + rx_bytes += tmp_rx_bytes; + rx_dropped += p->trap_rx_dropped[i]; + } + seq_printf(file, "trap %3d %12llu %12llu %10u\n", + i, rx_packets, rx_bytes, rx_dropped); + } + rx_invalid = 0; + for_each_possible_cpu(j) { + p = per_cpu_ptr(mlxsw_core->pcpu_stats, j); + rx_invalid += p->trap_rx_invalid; + } + seq_printf(file, "trap INV %10u\n", + rx_invalid); + + for (i = 0; i < MLXSW_PORT_MAX_PORTS; i++) { + rx_packets = 0; + rx_bytes = 0; + rx_dropped = 0; + for_each_possible_cpu(j) { + p = per_cpu_ptr(mlxsw_core->pcpu_stats, j); + do { + start = u64_stats_fetch_begin(&p->syncp); + tmp_rx_packets = p->port_rx_packets[i]; + tmp_rx_bytes = p->port_rx_bytes[i]; + } while (u64_stats_fetch_retry(&p->syncp, start)); + + rx_packets += tmp_rx_packets; + rx_bytes += tmp_rx_bytes; + rx_dropped += p->port_rx_dropped[i]; + } + seq_printf(file, "port %3d %12llu %12llu %10u\n", + i, rx_packets, rx_bytes, rx_dropped); + } + rx_invalid = 0; + for_each_possible_cpu(j) { + p = per_cpu_ptr(mlxsw_core->pcpu_stats, j); + rx_invalid += p->port_rx_invalid; + } + seq_printf(file, "port INV %10u\n", + rx_invalid); + return 0; +} + +static int mlxsw_core_rx_stats_dbg_open(struct inode *inode, struct file *f) +{ + struct mlxsw_core *mlxsw_core = inode->i_private; + + return single_open(f, mlxsw_core_rx_stats_dbg_read, mlxsw_core); +} + +static const struct file_operations mlxsw_core_rx_stats_dbg_ops = { + .owner = THIS_MODULE, + .open = mlxsw_core_rx_stats_dbg_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek +}; + +static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core, + const char *buf, size_t size) +{ + __be32 *m = (__be32 *) buf; + int i; + int count = size / sizeof(__be32); + + for (i = count - 1; i >= 0; i--) + if (m[i]) + break; + i++; + count = i ? i : 1; + for (i = 0; i < count; i += 4) + dev_dbg(mlxsw_core->bus_info->dev, "%04x - %08x %08x %08x %08x\n", + i * 4, be32_to_cpu(m[i]), be32_to_cpu(m[i + 1]), + be32_to_cpu(m[i + 2]), be32_to_cpu(m[i + 3])); +} + +int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver) +{ + spin_lock(&mlxsw_core_driver_list_lock); + list_add_tail(&mlxsw_driver->list, &mlxsw_core_driver_list); + spin_unlock(&mlxsw_core_driver_list_lock); + return 0; +} +EXPORT_SYMBOL(mlxsw_core_driver_register); + +void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver) +{ + spin_lock(&mlxsw_core_driver_list_lock); + list_del(&mlxsw_driver->list); + spin_unlock(&mlxsw_core_driver_list_lock); +} +EXPORT_SYMBOL(mlxsw_core_driver_unregister); + +static struct mlxsw_driver *__driver_find(const char *kind) +{ + struct mlxsw_driver *mlxsw_driver; + + list_for_each_entry(mlxsw_driver, &mlxsw_core_driver_list, list) { + if (strcmp(mlxsw_driver->kind, kind) == 0) + return mlxsw_driver; + } + return NULL; +} + +static struct mlxsw_driver *mlxsw_core_driver_get(const char *kind) +{ + struct mlxsw_driver *mlxsw_driver; + + spin_lock(&mlxsw_core_driver_list_lock); + mlxsw_driver = __driver_find(kind); + if (!mlxsw_driver) { + spin_unlock(&mlxsw_core_driver_list_lock); + request_module(MLXSW_MODULE_ALIAS_PREFIX "%s", kind); + spin_lock(&mlxsw_core_driver_list_lock); + mlxsw_driver = __driver_find(kind); + } + if (mlxsw_driver) { + if (!try_module_get(mlxsw_driver->owner)) + mlxsw_driver = NULL; + } + + spin_unlock(&mlxsw_core_driver_list_lock); + return mlxsw_driver; +} + +static void mlxsw_core_driver_put(const char *kind) +{ + struct mlxsw_driver *mlxsw_driver; + + spin_lock(&mlxsw_core_driver_list_lock); + mlxsw_driver = __driver_find(kind); + spin_unlock(&mlxsw_core_driver_list_lock); + if (!mlxsw_driver) + return; + module_put(mlxsw_driver->owner); +} + +static int mlxsw_core_debugfs_init(struct mlxsw_core *mlxsw_core) +{ + const struct mlxsw_bus_info *bus_info = mlxsw_core->bus_info; + + mlxsw_core->dbg_dir = debugfs_create_dir(bus_info->device_name, + mlxsw_core_dbg_root); + if (!mlxsw_core->dbg_dir) + return -ENOMEM; + debugfs_create_file("rx_stats", S_IRUGO, mlxsw_core->dbg_dir, + mlxsw_core, &mlxsw_core_rx_stats_dbg_ops); + mlxsw_core->dbg.vsd_blob.data = (void *) &bus_info->vsd; + mlxsw_core->dbg.vsd_blob.size = sizeof(bus_info->vsd); + debugfs_create_blob("vsd", S_IRUGO, mlxsw_core->dbg_dir, + &mlxsw_core->dbg.vsd_blob); + mlxsw_core->dbg.psid_blob.data = (void *) &bus_info->psid; + mlxsw_core->dbg.psid_blob.size = sizeof(bus_info->psid); + debugfs_create_blob("psid", S_IRUGO, mlxsw_core->dbg_dir, + &mlxsw_core->dbg.psid_blob); + return 0; +} + +static void mlxsw_core_debugfs_fini(struct mlxsw_core *mlxsw_core) +{ + debugfs_remove_recursive(mlxsw_core->dbg_dir); +} + +int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + const struct mlxsw_bus *mlxsw_bus, + void *bus_priv) +{ + const char *device_kind = mlxsw_bus_info->device_kind; + struct mlxsw_core *mlxsw_core; + struct mlxsw_driver *mlxsw_driver; + size_t alloc_size; + int err; + + mlxsw_driver = mlxsw_core_driver_get(device_kind); + if (!mlxsw_driver) + return -EINVAL; + alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size; + mlxsw_core = kzalloc(alloc_size, GFP_KERNEL); + if (!mlxsw_core) { + err = -ENOMEM; + goto err_core_alloc; + } + + INIT_LIST_HEAD(&mlxsw_core->rx_listener_list); + mlxsw_core->driver = mlxsw_driver; + mlxsw_core->bus = mlxsw_bus; + mlxsw_core->bus_priv = bus_priv; + mlxsw_core->bus_info = mlxsw_bus_info; + + mlxsw_core->pcpu_stats = + netdev_alloc_pcpu_stats(struct mlxsw_core_pcpu_stats); + if (!mlxsw_core->pcpu_stats) { + err = -ENOMEM; + goto err_alloc_stats; + } + err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile); + if (err) + goto err_bus_init; + + err = mlxsw_driver->init(mlxsw_core->driver_priv, mlxsw_core, + mlxsw_bus_info); + if (err) + goto err_driver_init; + + err = mlxsw_core_debugfs_init(mlxsw_core); + if (err) + goto err_debugfs_init; + + return 0; + +err_debugfs_init: + mlxsw_core->driver->fini(mlxsw_core->driver_priv); +err_driver_init: + mlxsw_bus->fini(bus_priv); +err_bus_init: + free_percpu(mlxsw_core->pcpu_stats); +err_alloc_stats: + kfree(mlxsw_core); +err_core_alloc: + mlxsw_core_driver_put(device_kind); + return err; +} +EXPORT_SYMBOL(mlxsw_core_bus_device_register); + +void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core) +{ + const char *device_kind = mlxsw_core->bus_info->device_kind; + + mlxsw_core_debugfs_fini(mlxsw_core); + mlxsw_core->driver->fini(mlxsw_core->driver_priv); + mlxsw_core->bus->fini(mlxsw_core->bus_priv); + free_percpu(mlxsw_core->pcpu_stats); + kfree(mlxsw_core); + mlxsw_core_driver_put(device_kind); +} +EXPORT_SYMBOL(mlxsw_core_bus_device_unregister); + +static struct mlxsw_core *__mlxsw_core_get(void *driver_priv) +{ + return container_of(driver_priv, struct mlxsw_core, driver_priv); +} + +int mlxsw_core_skb_transmit(void *driver_priv, struct sk_buff *skb, + const struct mlxsw_tx_info *tx_info) +{ + struct mlxsw_core *mlxsw_core = __mlxsw_core_get(driver_priv); + + return mlxsw_core->bus->skb_transmit(mlxsw_core->bus_priv, skb, + tx_info); +} +EXPORT_SYMBOL(mlxsw_core_skb_transmit); + +static bool __is_rx_listener_equal(const struct mlxsw_rx_listener *rxl_a, + const struct mlxsw_rx_listener *rxl_b) +{ + return (rxl_a->func == rxl_b->func && + rxl_a->local_port == rxl_b->local_port && + rxl_a->trap_id == rxl_b->trap_id); +} + +static struct mlxsw_rx_listener_item * +__find_rx_listener_item(struct mlxsw_core *mlxsw_core, + const struct mlxsw_rx_listener *rxl, + void *priv) +{ + struct mlxsw_rx_listener_item *rxl_item; + + list_for_each_entry(rxl_item, &mlxsw_core->rx_listener_list, list) { + if (__is_rx_listener_equal(&rxl_item->rxl, rxl) && + rxl_item->priv == priv) + return rxl_item; + } + return NULL; +} + +int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core, + const struct mlxsw_rx_listener *rxl, + void *priv) +{ + struct mlxsw_rx_listener_item *rxl_item; + + rxl_item = __find_rx_listener_item(mlxsw_core, rxl, priv); + if (rxl_item) + return -EEXIST; + rxl_item = kmalloc(sizeof(*rxl_item), GFP_KERNEL); + if (!rxl_item) + return -ENOMEM; + rxl_item->rxl = *rxl; + rxl_item->priv = priv; + + list_add_rcu(&rxl_item->list, &mlxsw_core->rx_listener_list); + return 0; +} +EXPORT_SYMBOL(mlxsw_core_rx_listener_register); + +void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core, + const struct mlxsw_rx_listener *rxl, + void *priv) +{ + struct mlxsw_rx_listener_item *rxl_item; + + rxl_item = __find_rx_listener_item(mlxsw_core, rxl, priv); + if (!rxl_item) + return; + list_del_rcu(&rxl_item->list); + synchronize_rcu(); + kfree(rxl_item); +} +EXPORT_SYMBOL(mlxsw_core_rx_listener_unregister); + +void mlxsw_core_skb_receive(struct mlxsw_core *mlxsw_core, struct sk_buff *skb, + struct mlxsw_rx_info *rx_info) +{ + struct mlxsw_rx_listener_item *rxl_item; + const struct mlxsw_rx_listener *rxl; + struct mlxsw_core_pcpu_stats *pcpu_stats; + u8 local_port = rx_info->sys_port; + bool found = false; + + dev_dbg_ratelimited(mlxsw_core->bus_info->dev, "%s: sys_port = %d, trap_id = 0x%x\n", + __func__, rx_info->sys_port, rx_info->trap_id); + + if ((rx_info->trap_id >= MLXSW_TRAP_ID_MAX) || + (local_port >= MLXSW_PORT_MAX_PORTS)) + goto drop; + + rcu_read_lock(); + list_for_each_entry_rcu(rxl_item, &mlxsw_core->rx_listener_list, list) { + rxl = &rxl_item->rxl; + if ((rxl->local_port == MLXSW_PORT_DONT_CARE || + rxl->local_port == local_port) && + rxl->trap_id == rx_info->trap_id) { + found = true; + break; + } + } + rcu_read_unlock(); + if (!found) + goto drop; + + pcpu_stats = this_cpu_ptr(mlxsw_core->pcpu_stats); + u64_stats_update_begin(&pcpu_stats->syncp); + pcpu_stats->port_rx_packets[local_port]++; + pcpu_stats->port_rx_bytes[local_port] += skb->len; + pcpu_stats->trap_rx_packets[rx_info->trap_id]++; + pcpu_stats->trap_rx_bytes[rx_info->trap_id] += skb->len; + u64_stats_update_end(&pcpu_stats->syncp); + + rxl->func(skb, local_port, rxl_item->priv); + return; + +drop: + if (rx_info->trap_id >= MLXSW_TRAP_ID_MAX) + this_cpu_inc(mlxsw_core->pcpu_stats->trap_rx_invalid); + else + this_cpu_inc(mlxsw_core->pcpu_stats->trap_rx_dropped[rx_info->trap_id]); + if (local_port >= MLXSW_PORT_MAX_PORTS) + this_cpu_inc(mlxsw_core->pcpu_stats->port_rx_invalid); + else + this_cpu_inc(mlxsw_core->pcpu_stats->port_rx_dropped[local_port]); + dev_kfree_skb(skb); +} +EXPORT_SYMBOL(mlxsw_core_skb_receive); + +int mlxsw_cmd_exec(struct mlxsw_core *mlxsw_core, u16 opcode, u8 opcode_mod, + u32 in_mod, bool out_mbox_direct, + char *in_mbox, size_t in_mbox_size, + char *out_mbox, size_t out_mbox_size) +{ + u8 status; + int err; + + BUG_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32)); + if (!mlxsw_core->bus->cmd_exec) + return -EOPNOTSUPP; + + dev_dbg(mlxsw_core->bus_info->dev, "Cmd exec (opcode=%x(%s),opcode_mod=%x,in_mod=%x)\n", + opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod, in_mod); + if (in_mbox) { + dev_dbg(mlxsw_core->bus_info->dev, "Input mailbox:\n"); + mlxsw_core_buf_dump_dbg(mlxsw_core, in_mbox, in_mbox_size); + } + + err = mlxsw_core->bus->cmd_exec(mlxsw_core->bus_priv, opcode, + opcode_mod, in_mod, out_mbox_direct, + in_mbox, in_mbox_size, + out_mbox, out_mbox_size, &status); + + if (err == -EIO && status != MLXSW_CMD_STATUS_OK) { + dev_err(mlxsw_core->bus_info->dev, "Cmd exec failed (opcode=%x(%s),opcode_mod=%x,in_mod=%x,status=%x(%s))\n", + opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod, + in_mod, status, mlxsw_cmd_status_str(status)); + } else if (err == -ETIMEDOUT) { + dev_err(mlxsw_core->bus_info->dev, "Cmd exec timed-out (opcode=%x(%s),opcode_mod=%x,in_mod=%x)\n", + opcode, mlxsw_cmd_opcode_str(opcode), opcode_mod, + in_mod); + } + + if (!err && out_mbox) { + dev_dbg(mlxsw_core->bus_info->dev, "Output mailbox:\n"); + mlxsw_core_buf_dump_dbg(mlxsw_core, out_mbox, out_mbox_size); + } + return err; +} +EXPORT_SYMBOL(mlxsw_cmd_exec); + +static int __init mlxsw_core_module_init(void) +{ + mlxsw_core_dbg_root = debugfs_create_dir(mlxsw_core_driver_name, NULL); + if (!mlxsw_core_dbg_root) + return -ENOMEM; + return 0; +} + +static void __exit mlxsw_core_module_exit(void) +{ + debugfs_remove_recursive(mlxsw_core_dbg_root); +} + +module_init(mlxsw_core_module_init); +module_exit(mlxsw_core_module_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Jiri Pirko "); +MODULE_DESCRIPTION("Mellanox switch device core driver"); diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h new file mode 100644 index 000000000000..f4ab36a0235e --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -0,0 +1,179 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/core.h + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Jiri Pirko + * Copyright (c) 2015 Ido Schimmel + * Copyright (c) 2015 Elad Raz + * + * 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 _MLXSW_CORE_H +#define _MLXSW_CORE_H + +#include +#include +#include +#include +#include +#include + +#include "cmd.h" + +#define MLXSW_MODULE_ALIAS_PREFIX "mlxsw-driver-" +#define MODULE_MLXSW_DRIVER_ALIAS(kind) \ + MODULE_ALIAS(MLXSW_MODULE_ALIAS_PREFIX kind) + +struct mlxsw_core; +struct mlxsw_driver; +struct mlxsw_bus; +struct mlxsw_bus_info; + +int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver); +void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver); + +int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + const struct mlxsw_bus *mlxsw_bus, + void *bus_priv); +void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core); + +struct mlxsw_tx_info { + u8 local_port; + bool is_emad; +}; + +int mlxsw_core_skb_transmit(void *driver_priv, struct sk_buff *skb, + const struct mlxsw_tx_info *tx_info); + +struct mlxsw_rx_listener { + void (*func)(struct sk_buff *skb, u8 local_port, void *priv); + u8 local_port; + u16 trap_id; +}; + +int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core, + const struct mlxsw_rx_listener *rxl, + void *priv); +void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core, + const struct mlxsw_rx_listener *rxl, + void *priv); + +struct mlxsw_rx_info { + u16 sys_port; + int trap_id; +}; + +void mlxsw_core_skb_receive(struct mlxsw_core *mlxsw_core, struct sk_buff *skb, + struct mlxsw_rx_info *rx_info); + +#define MLXSW_CONFIG_PROFILE_SWID_COUNT 8 + +struct mlxsw_swid_config { + u8 used_type:1, + used_properties:1; + u8 type; + u8 properties; +}; + +struct mlxsw_config_profile { + u16 used_max_vepa_channels:1, + used_max_lag:1, + used_max_port_per_lag:1, + used_max_mid:1, + used_max_pgt:1, + used_max_system_port:1, + used_max_vlan_groups:1, + used_max_regions:1, + used_flood_tables:1, + used_flood_mode:1, + used_max_ib_mc:1, + used_max_pkey:1, + used_ar_sec:1, + used_adaptive_routing_group_cap:1; + u8 max_vepa_channels; + u16 max_lag; + u16 max_port_per_lag; + u16 max_mid; + u16 max_pgt; + u16 max_system_port; + u16 max_vlan_groups; + u16 max_regions; + u8 max_flood_tables; + u8 max_vid_flood_tables; + u8 flood_mode; + u16 max_ib_mc; + u16 max_pkey; + u8 ar_sec; + u16 adaptive_routing_group_cap; + u8 arn; + struct mlxsw_swid_config swid_config[MLXSW_CONFIG_PROFILE_SWID_COUNT]; +}; + +struct mlxsw_driver { + struct list_head list; + const char *kind; + struct module *owner; + size_t priv_size; + int (*init)(void *driver_priv, struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info); + void (*fini)(void *driver_priv); + void (*txhdr_construct)(struct sk_buff *skb, + const struct mlxsw_tx_info *tx_info); + u8 txhdr_len; + const struct mlxsw_config_profile *profile; +}; + +struct mlxsw_bus { + const char *kind; + int (*init)(void *bus_priv, struct mlxsw_core *mlxsw_core, + const struct mlxsw_config_profile *profile); + void (*fini)(void *bus_priv); + int (*skb_transmit)(void *bus_priv, struct sk_buff *skb, + const struct mlxsw_tx_info *tx_info); + int (*cmd_exec)(void *bus_priv, u16 opcode, u8 opcode_mod, + u32 in_mod, bool out_mbox_direct, + char *in_mbox, size_t in_mbox_size, + char *out_mbox, size_t out_mbox_size, + u8 *p_status); +}; + +struct mlxsw_bus_info { + const char *device_kind; + const char *device_name; + struct device *dev; + struct { + u16 major; + u16 minor; + u16 subminor; + } fw_rev; + u8 vsd[MLXSW_CMD_BOARDINFO_VSD_LEN]; + u8 psid[MLXSW_CMD_BOARDINFO_PSID_LEN]; +}; + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/item.h b/drivers/net/ethernet/mellanox/mlxsw/item.h new file mode 100644 index 000000000000..4d0ac882bec3 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/item.h @@ -0,0 +1,405 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/item.h + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Jiri Pirko + * Copyright (c) 2015 Ido Schimmel + * + * 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 _MLXSW_ITEM_H +#define _MLXSW_ITEM_H + +#include +#include +#include + +struct mlxsw_item { + unsigned short offset; /* bytes in container */ + unsigned short step; /* step in bytes for indexed items */ + unsigned short in_step_offset; /* offset within one step */ + unsigned char shift; /* shift in bits */ + unsigned char element_size; /* size of element in bit array */ + bool no_real_shift; + union { + unsigned char bits; + unsigned short bytes; + } size; + const char *name; +}; + +static inline unsigned int +__mlxsw_item_offset(struct mlxsw_item *item, unsigned short index, + size_t typesize) +{ + BUG_ON(index && !item->step); + if (item->offset % typesize != 0 || + item->step % typesize != 0 || + item->in_step_offset % typesize != 0) { + pr_err("mlxsw: item bug (name=%s,offset=%x,step=%x,in_step_offset=%x,typesize=%lx)\n", + item->name, item->offset, item->step, + item->in_step_offset, typesize); + BUG(); + } + + return ((item->offset + item->step * index + item->in_step_offset) / + typesize); +} + +static inline u16 __mlxsw_item_get16(char *buf, struct mlxsw_item *item, + unsigned short index) +{ + unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u16)); + __be16 *b = (__be16 *) buf; + u16 tmp; + + tmp = be16_to_cpu(b[offset]); + tmp >>= item->shift; + tmp &= GENMASK(item->size.bits - 1, 0); + if (item->no_real_shift) + tmp <<= item->shift; + return tmp; +} + +static inline void __mlxsw_item_set16(char *buf, struct mlxsw_item *item, + unsigned short index, u16 val) +{ + unsigned int offset = __mlxsw_item_offset(item, index, + sizeof(u16)); + __be16 *b = (__be16 *) buf; + u16 mask = GENMASK(item->size.bits - 1, 0) << item->shift; + u16 tmp; + + if (!item->no_real_shift) + val <<= item->shift; + val &= mask; + tmp = be16_to_cpu(b[offset]); + tmp &= ~mask; + tmp |= val; + b[offset] = cpu_to_be16(tmp); +} + +static inline u32 __mlxsw_item_get32(char *buf, struct mlxsw_item *item, + unsigned short index) +{ + unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u32)); + __be32 *b = (__be32 *) buf; + u32 tmp; + + tmp = be32_to_cpu(b[offset]); + tmp >>= item->shift; + tmp &= GENMASK(item->size.bits - 1, 0); + if (item->no_real_shift) + tmp <<= item->shift; + return tmp; +} + +static inline void __mlxsw_item_set32(char *buf, struct mlxsw_item *item, + unsigned short index, u32 val) +{ + unsigned int offset = __mlxsw_item_offset(item, index, + sizeof(u32)); + __be32 *b = (__be32 *) buf; + u32 mask = GENMASK(item->size.bits - 1, 0) << item->shift; + u32 tmp; + + if (!item->no_real_shift) + val <<= item->shift; + val &= mask; + tmp = be32_to_cpu(b[offset]); + tmp &= ~mask; + tmp |= val; + b[offset] = cpu_to_be32(tmp); +} + +static inline u64 __mlxsw_item_get64(char *buf, struct mlxsw_item *item, + unsigned short index) +{ + unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64)); + __be64 *b = (__be64 *) buf; + u64 tmp; + + tmp = be64_to_cpu(b[offset]); + tmp >>= item->shift; + tmp &= GENMASK_ULL(item->size.bits - 1, 0); + if (item->no_real_shift) + tmp <<= item->shift; + return tmp; +} + +static inline void __mlxsw_item_set64(char *buf, struct mlxsw_item *item, + unsigned short index, u64 val) +{ + unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64)); + __be64 *b = (__be64 *) buf; + u64 mask = GENMASK_ULL(item->size.bits - 1, 0) << item->shift; + u64 tmp; + + if (!item->no_real_shift) + val <<= item->shift; + val &= mask; + tmp = be64_to_cpu(b[offset]); + tmp &= ~mask; + tmp |= val; + b[offset] = cpu_to_be64(tmp); +} + +static inline void __mlxsw_item_memcpy_from(char *buf, char *dst, + struct mlxsw_item *item) +{ + memcpy(dst, &buf[item->offset], item->size.bytes); +} + +static inline void __mlxsw_item_memcpy_to(char *buf, char *src, + struct mlxsw_item *item) +{ + memcpy(&buf[item->offset], src, item->size.bytes); +} + +static inline u16 +__mlxsw_item_bit_array_offset(struct mlxsw_item *item, u16 index, u8 *shift) +{ + u16 max_index, be_index; + u16 offset; /* byte offset inside the array */ + + BUG_ON(index && !item->element_size); + if (item->offset % sizeof(u32) != 0 || + BITS_PER_BYTE % item->element_size != 0) { + pr_err("mlxsw: item bug (name=%s,offset=%x,element_size=%x)\n", + item->name, item->offset, item->element_size); + BUG(); + } + + max_index = (item->size.bytes << 3) / item->element_size - 1; + be_index = max_index - index; + offset = be_index * item->element_size >> 3; + *shift = index % (BITS_PER_BYTE / item->element_size) << 1; + + return item->offset + offset; +} + +static inline u8 __mlxsw_item_bit_array_get(char *buf, struct mlxsw_item *item, + u16 index) +{ + u8 shift, tmp; + u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift); + + tmp = buf[offset]; + tmp >>= shift; + tmp &= GENMASK(item->element_size - 1, 0); + return tmp; +} + +static inline void __mlxsw_item_bit_array_set(char *buf, struct mlxsw_item *item, + u16 index, u8 val) +{ + u8 shift, tmp; + u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift); + u8 mask = GENMASK(item->element_size - 1, 0) << shift; + + val <<= shift; + val &= mask; + tmp = buf[offset]; + tmp &= ~mask; + tmp |= val; + buf[offset] = tmp; +} + +#define __ITEM_NAME(_type, _cname, _iname) \ + mlxsw_##_type##_##_cname##_##_iname##_item + +/* _type: cmd_mbox, reg, etc. + * _cname: containter name (e.g. command name, register name) + * _iname: item name within the container + */ + +#define MLXSW_ITEM16(_type, _cname, _iname, _offset, _shift, _sizebits) \ +static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ + .offset = _offset, \ + .shift = _shift, \ + .size = {.bits = _sizebits,}, \ + .name = #_type "_" #_cname "_" #_iname, \ +}; \ +static inline u16 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf) \ +{ \ + return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ +} \ +static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 val)\ +{ \ + __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \ +} + +#define MLXSW_ITEM16_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \ + _step, _instepoffset, _norealshift) \ +static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ + .offset = _offset, \ + .step = _step, \ + .in_step_offset = _instepoffset, \ + .shift = _shift, \ + .no_real_shift = _norealshift, \ + .size = {.bits = _sizebits,}, \ + .name = #_type "_" #_cname "_" #_iname, \ +}; \ +static inline u16 \ +mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index) \ +{ \ + return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), \ + index); \ +} \ +static inline void \ +mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \ + u16 val) \ +{ \ + __mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), \ + index, val); \ +} + +#define MLXSW_ITEM32(_type, _cname, _iname, _offset, _shift, _sizebits) \ +static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ + .offset = _offset, \ + .shift = _shift, \ + .size = {.bits = _sizebits,}, \ + .name = #_type "_" #_cname "_" #_iname, \ +}; \ +static inline u32 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf) \ +{ \ + return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ +} \ +static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u32 val)\ +{ \ + __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \ +} + +#define MLXSW_ITEM32_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits, \ + _step, _instepoffset, _norealshift) \ +static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ + .offset = _offset, \ + .step = _step, \ + .in_step_offset = _instepoffset, \ + .shift = _shift, \ + .no_real_shift = _norealshift, \ + .size = {.bits = _sizebits,}, \ + .name = #_type "_" #_cname "_" #_iname, \ +}; \ +static inline u32 \ +mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index) \ +{ \ + return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), \ + index); \ +} \ +static inline void \ +mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \ + u32 val) \ +{ \ + __mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), \ + index, val); \ +} + +#define MLXSW_ITEM64(_type, _cname, _iname, _offset, _shift, _sizebits) \ +static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ + .offset = _offset, \ + .shift = _shift, \ + .size = {.bits = _sizebits,}, \ + .name = #_type "_" #_cname "_" #_iname, \ +}; \ +static inline u64 mlxsw_##_type##_##_cname##_##_iname##_get(char *buf) \ +{ \ + return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), 0); \ +} \ +static inline void mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u64 val)\ +{ \ + __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val); \ +} + +#define MLXSW_ITEM64_INDEXED(_type, _cname, _iname, _offset, _shift, \ + _sizebits, _step, _instepoffset, _norealshift) \ +static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ + .offset = _offset, \ + .step = _step, \ + .in_step_offset = _instepoffset, \ + .shift = _shift, \ + .no_real_shift = _norealshift, \ + .size = {.bits = _sizebits,}, \ + .name = #_type "_" #_cname "_" #_iname, \ +}; \ +static inline u64 \ +mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, unsigned short index) \ +{ \ + return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), \ + index); \ +} \ +static inline void \ +mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index, \ + u64 val) \ +{ \ + __mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), \ + index, val); \ +} + +#define MLXSW_ITEM_BUF(_type, _cname, _iname, _offset, _sizebytes) \ +static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ + .offset = _offset, \ + .size = {.bytes = _sizebytes,}, \ + .name = #_type "_" #_cname "_" #_iname, \ +}; \ +static inline void \ +mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(char *buf, char *dst) \ +{ \ + __mlxsw_item_memcpy_from(buf, dst, &__ITEM_NAME(_type, _cname, _iname));\ +} \ +static inline void \ +mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, char *src) \ +{ \ + __mlxsw_item_memcpy_to(buf, src, &__ITEM_NAME(_type, _cname, _iname)); \ +} + +#define MLXSW_ITEM_BIT_ARRAY(_type, _cname, _iname, _offset, _sizebytes, \ + _element_size) \ +static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = { \ + .offset = _offset, \ + .element_size = _element_size, \ + .size = {.bytes = _sizebytes,}, \ + .name = #_type "_" #_cname "_" #_iname, \ +}; \ +static inline u8 \ +mlxsw_##_type##_##_cname##_##_iname##_get(char *buf, u16 index) \ +{ \ + return __mlxsw_item_bit_array_get(buf, \ + &__ITEM_NAME(_type, _cname, _iname), \ + index); \ +} \ +static inline void \ +mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 index, u8 val) \ +{ \ + return __mlxsw_item_bit_array_set(buf, \ + &__ITEM_NAME(_type, _cname, _iname), \ + index, val); \ +} \ + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/port.h b/drivers/net/ethernet/mellanox/mlxsw/port.h new file mode 100644 index 000000000000..1b43c7d58ac5 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/port.h @@ -0,0 +1,52 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/port.h + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Elad Raz + * Copyright (c) 2015 Jiri Pirko + * Copyright (c) 2015 Ido Schimmel + * + * 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 _MLXSW_PORT_H +#define _MLXSW_PORT_H + +#include + +#define MLXSW_PORT_MAX_MTU 10000 + +#define MLXSW_PORT_DEFAULT_VID 1 + +#define MLXSW_PORT_MAX_PHY_PORTS 0x40 +#define MLXSW_PORT_MAX_PORTS MLXSW_PORT_MAX_PHY_PORTS + +#define MLXSW_PORT_CPU_PORT 0x0 + +#define MLXSW_PORT_DONT_CARE (MLXSW_PORT_MAX_PORTS) + +#endif /* _MLXSW_PORT_H */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h new file mode 100644 index 000000000000..53a9550be75e --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -0,0 +1,66 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/trap.h + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Elad Raz + * Copyright (c) 2015 Jiri Pirko + * Copyright (c) 2015 Ido Schimmel + * + * 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 _MLXSW_TRAP_H +#define _MLXSW_TRAP_H + +enum { + /* Ethernet EMAD and FDB miss */ + MLXSW_TRAP_ID_FDB_MC = 0x01, + MLXSW_TRAP_ID_ETHEMAD = 0x05, + /* L2 traps for specific packet types */ + MLXSW_TRAP_ID_STP = 0x10, + MLXSW_TRAP_ID_LACP = 0x11, + MLXSW_TRAP_ID_EAPOL = 0x12, + MLXSW_TRAP_ID_LLDP = 0x13, + MLXSW_TRAP_ID_MMRP = 0x14, + MLXSW_TRAP_ID_MVRP = 0x15, + MLXSW_TRAP_ID_RPVST = 0x16, + MLXSW_TRAP_ID_DHCP = 0x19, + MLXSW_TRAP_ID_IGMP_QUERY = 0x30, + MLXSW_TRAP_ID_IGMP_V1_REPORT = 0x31, + MLXSW_TRAP_ID_IGMP_V2_REPORT = 0x32, + MLXSW_TRAP_ID_IGMP_V2_LEAVE = 0x33, + MLXSW_TRAP_ID_IGMP_V3_REPORT = 0x34, + + MLXSW_TRAP_ID_MAX = 0x1FF +}; + +enum mlxsw_event_trap_id { + /* Port Up/Down event generated by hardware */ + MLXSW_TRAP_ID_PUDE = 0x8, +}; + +#endif /* _MLXSW_TRAP_H */ -- cgit v1.3-6-gb490 From eda6500a987a027b78a275c11db6454404a626aa Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 29 Jul 2015 23:33:47 +0200 Subject: mlxsw: Add PCI bus implementation Add PCI bus implementation for Mellanox Technologies Switch ASICs. This includes firmware initialization, async queues manipulation and command interface implementation. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Elad Raz Reviewed-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/Kconfig | 10 + drivers/net/ethernet/mellanox/mlxsw/Makefile | 2 + drivers/net/ethernet/mellanox/mlxsw/pci.c | 1791 ++++++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlxsw/pci.h | 220 ++++ 4 files changed, 2023 insertions(+) create mode 100644 drivers/net/ethernet/mellanox/mlxsw/pci.c create mode 100644 drivers/net/ethernet/mellanox/mlxsw/pci.h (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig index 46268f260e1b..1385f2caea11 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig @@ -9,3 +9,13 @@ config MLXSW_CORE To compile this driver as a module, choose M here: the module will be called mlxsw_core. + +config MLXSW_PCI + tristate "PCI bus implementation for Mellanox Technologies Switch ASICs" + depends on PCI && MLXSW_CORE + default m + ---help--- + This is PCI bus implementation for Mellanox Technologies Switch ASICs. + + To compile this driver as a module, choose M here: the + module will be called mlxsw_pci. diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile index 271de28cc8ae..94841c3329b6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Makefile +++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile @@ -1,2 +1,4 @@ obj-$(CONFIG_MLXSW_CORE) += mlxsw_core.o mlxsw_core-objs := core.o +obj-$(CONFIG_MLXSW_PCI) += mlxsw_pci.o +mlxsw_pci-objs := pci.o diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c new file mode 100644 index 000000000000..64f725fde602 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -0,0 +1,1791 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/pci.c + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Jiri Pirko + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pci.h" +#include "core.h" +#include "cmd.h" +#include "port.h" + +static const char mlxsw_pci_driver_name[] = "mlxsw_pci"; + +static const struct pci_device_id mlxsw_pci_id_table[] = { + {0, } +}; + +static struct dentry *mlxsw_pci_dbg_root; + +static const char *mlxsw_pci_device_kind_get(const struct pci_device_id *id) +{ + switch (id->device) { + default: + BUG(); + } +} + +#define mlxsw_pci_write32(mlxsw_pci, reg, val) \ + iowrite32be(val, (mlxsw_pci)->hw_addr + (MLXSW_PCI_ ## reg)) +#define mlxsw_pci_read32(mlxsw_pci, reg) \ + ioread32be((mlxsw_pci)->hw_addr + (MLXSW_PCI_ ## reg)) + +enum mlxsw_pci_queue_type { + MLXSW_PCI_QUEUE_TYPE_SDQ, + MLXSW_PCI_QUEUE_TYPE_RDQ, + MLXSW_PCI_QUEUE_TYPE_CQ, + MLXSW_PCI_QUEUE_TYPE_EQ, +}; + +static const char *mlxsw_pci_queue_type_str(enum mlxsw_pci_queue_type q_type) +{ + switch (q_type) { + case MLXSW_PCI_QUEUE_TYPE_SDQ: + return "sdq"; + case MLXSW_PCI_QUEUE_TYPE_RDQ: + return "rdq"; + case MLXSW_PCI_QUEUE_TYPE_CQ: + return "cq"; + case MLXSW_PCI_QUEUE_TYPE_EQ: + return "eq"; + } + BUG(); +} + +#define MLXSW_PCI_QUEUE_TYPE_COUNT 4 + +static const u16 mlxsw_pci_doorbell_type_offset[] = { + MLXSW_PCI_DOORBELL_SDQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_SDQ */ + MLXSW_PCI_DOORBELL_RDQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_RDQ */ + MLXSW_PCI_DOORBELL_CQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_CQ */ + MLXSW_PCI_DOORBELL_EQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_EQ */ +}; + +static const u16 mlxsw_pci_doorbell_arm_type_offset[] = { + 0, /* unused */ + 0, /* unused */ + MLXSW_PCI_DOORBELL_ARM_CQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_CQ */ + MLXSW_PCI_DOORBELL_ARM_EQ_OFFSET, /* for type MLXSW_PCI_QUEUE_TYPE_EQ */ +}; + +struct mlxsw_pci_mem_item { + char *buf; + dma_addr_t mapaddr; + size_t size; +}; + +struct mlxsw_pci_queue_elem_info { + char *elem; /* pointer to actual dma mapped element mem chunk */ + union { + struct { + struct sk_buff *skb; + } sdq; + struct { + struct sk_buff *skb; + } rdq; + } u; +}; + +struct mlxsw_pci_queue { + spinlock_t lock; /* for queue accesses */ + struct mlxsw_pci_mem_item mem_item; + struct mlxsw_pci_queue_elem_info *elem_info; + u16 producer_counter; + u16 consumer_counter; + u16 count; /* number of elements in queue */ + u8 num; /* queue number */ + u8 elem_size; /* size of one element */ + enum mlxsw_pci_queue_type type; + struct tasklet_struct tasklet; /* queue processing tasklet */ + struct mlxsw_pci *pci; + union { + struct { + u32 comp_sdq_count; + u32 comp_rdq_count; + } cq; + struct { + u32 ev_cmd_count; + u32 ev_comp_count; + u32 ev_other_count; + } eq; + } u; +}; + +struct mlxsw_pci_queue_type_group { + struct mlxsw_pci_queue *q; + u8 count; /* number of queues in group */ +}; + +struct mlxsw_pci { + struct pci_dev *pdev; + u8 __iomem *hw_addr; + struct mlxsw_pci_queue_type_group queues[MLXSW_PCI_QUEUE_TYPE_COUNT]; + u32 doorbell_offset; + struct msix_entry msix_entry; + struct mlxsw_core *core; + struct { + u16 num_pages; + struct mlxsw_pci_mem_item *items; + } fw_area; + struct { + struct mutex lock; /* Lock access to command registers */ + bool nopoll; + wait_queue_head_t wait; + bool wait_done; + struct { + u8 status; + u64 out_param; + } comp; + } cmd; + struct mlxsw_bus_info bus_info; + struct dentry *dbg_dir; +}; + +static void mlxsw_pci_queue_tasklet_schedule(struct mlxsw_pci_queue *q) +{ + tasklet_schedule(&q->tasklet); +} + +static char *__mlxsw_pci_queue_elem_get(struct mlxsw_pci_queue *q, + size_t elem_size, int elem_index) +{ + return q->mem_item.buf + (elem_size * elem_index); +} + +static struct mlxsw_pci_queue_elem_info * +mlxsw_pci_queue_elem_info_get(struct mlxsw_pci_queue *q, int elem_index) +{ + return &q->elem_info[elem_index]; +} + +static struct mlxsw_pci_queue_elem_info * +mlxsw_pci_queue_elem_info_producer_get(struct mlxsw_pci_queue *q) +{ + int index = q->producer_counter & (q->count - 1); + + if ((q->producer_counter - q->consumer_counter) == q->count) + return NULL; + return mlxsw_pci_queue_elem_info_get(q, index); +} + +static struct mlxsw_pci_queue_elem_info * +mlxsw_pci_queue_elem_info_consumer_get(struct mlxsw_pci_queue *q) +{ + int index = q->consumer_counter & (q->count - 1); + + return mlxsw_pci_queue_elem_info_get(q, index); +} + +static char *mlxsw_pci_queue_elem_get(struct mlxsw_pci_queue *q, int elem_index) +{ + return mlxsw_pci_queue_elem_info_get(q, elem_index)->elem; +} + +static bool mlxsw_pci_elem_hw_owned(struct mlxsw_pci_queue *q, bool owner_bit) +{ + return owner_bit != !!(q->consumer_counter & q->count); +} + +static char *mlxsw_pci_queue_sw_elem_get(struct mlxsw_pci_queue *q, + u32 (*get_elem_owner_func)(char *)) +{ + struct mlxsw_pci_queue_elem_info *elem_info; + char *elem; + bool owner_bit; + + elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); + elem = elem_info->elem; + owner_bit = get_elem_owner_func(elem); + if (mlxsw_pci_elem_hw_owned(q, owner_bit)) + return NULL; + q->consumer_counter++; + rmb(); /* make sure we read owned bit before the rest of elem */ + return elem; +} + +static struct mlxsw_pci_queue_type_group * +mlxsw_pci_queue_type_group_get(struct mlxsw_pci *mlxsw_pci, + enum mlxsw_pci_queue_type q_type) +{ + return &mlxsw_pci->queues[q_type]; +} + +static u8 __mlxsw_pci_queue_count(struct mlxsw_pci *mlxsw_pci, + enum mlxsw_pci_queue_type q_type) +{ + struct mlxsw_pci_queue_type_group *queue_group; + + queue_group = mlxsw_pci_queue_type_group_get(mlxsw_pci, q_type); + return queue_group->count; +} + +static u8 mlxsw_pci_sdq_count(struct mlxsw_pci *mlxsw_pci) +{ + return __mlxsw_pci_queue_count(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_SDQ); +} + +static u8 mlxsw_pci_rdq_count(struct mlxsw_pci *mlxsw_pci) +{ + return __mlxsw_pci_queue_count(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_RDQ); +} + +static u8 mlxsw_pci_cq_count(struct mlxsw_pci *mlxsw_pci) +{ + return __mlxsw_pci_queue_count(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_CQ); +} + +static u8 mlxsw_pci_eq_count(struct mlxsw_pci *mlxsw_pci) +{ + return __mlxsw_pci_queue_count(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_EQ); +} + +static struct mlxsw_pci_queue * +__mlxsw_pci_queue_get(struct mlxsw_pci *mlxsw_pci, + enum mlxsw_pci_queue_type q_type, u8 q_num) +{ + return &mlxsw_pci->queues[q_type].q[q_num]; +} + +static struct mlxsw_pci_queue *mlxsw_pci_sdq_get(struct mlxsw_pci *mlxsw_pci, + u8 q_num) +{ + return __mlxsw_pci_queue_get(mlxsw_pci, + MLXSW_PCI_QUEUE_TYPE_SDQ, q_num); +} + +static struct mlxsw_pci_queue *mlxsw_pci_rdq_get(struct mlxsw_pci *mlxsw_pci, + u8 q_num) +{ + return __mlxsw_pci_queue_get(mlxsw_pci, + MLXSW_PCI_QUEUE_TYPE_RDQ, q_num); +} + +static struct mlxsw_pci_queue *mlxsw_pci_cq_get(struct mlxsw_pci *mlxsw_pci, + u8 q_num) +{ + return __mlxsw_pci_queue_get(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_CQ, q_num); +} + +static struct mlxsw_pci_queue *mlxsw_pci_eq_get(struct mlxsw_pci *mlxsw_pci, + u8 q_num) +{ + return __mlxsw_pci_queue_get(mlxsw_pci, MLXSW_PCI_QUEUE_TYPE_EQ, q_num); +} + +static void __mlxsw_pci_queue_doorbell_set(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q, + u16 val) +{ + mlxsw_pci_write32(mlxsw_pci, + DOORBELL(mlxsw_pci->doorbell_offset, + mlxsw_pci_doorbell_type_offset[q->type], + q->num), val); +} + +static void __mlxsw_pci_queue_doorbell_arm_set(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q, + u16 val) +{ + mlxsw_pci_write32(mlxsw_pci, + DOORBELL(mlxsw_pci->doorbell_offset, + mlxsw_pci_doorbell_arm_type_offset[q->type], + q->num), val); +} + +static void mlxsw_pci_queue_doorbell_producer_ring(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q) +{ + wmb(); /* ensure all writes are done before we ring a bell */ + __mlxsw_pci_queue_doorbell_set(mlxsw_pci, q, q->producer_counter); +} + +static void mlxsw_pci_queue_doorbell_consumer_ring(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q) +{ + wmb(); /* ensure all writes are done before we ring a bell */ + __mlxsw_pci_queue_doorbell_set(mlxsw_pci, q, + q->consumer_counter + q->count); +} + +static void +mlxsw_pci_queue_doorbell_arm_consumer_ring(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q) +{ + wmb(); /* ensure all writes are done before we ring a bell */ + __mlxsw_pci_queue_doorbell_arm_set(mlxsw_pci, q, q->consumer_counter); +} + +static dma_addr_t __mlxsw_pci_queue_page_get(struct mlxsw_pci_queue *q, + int page_index) +{ + return q->mem_item.mapaddr + MLXSW_PCI_PAGE_SIZE * page_index; +} + +static int mlxsw_pci_sdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, + struct mlxsw_pci_queue *q) +{ + int i; + int err; + + q->producer_counter = 0; + q->consumer_counter = 0; + + /* Set CQ of same number of this SDQ. */ + mlxsw_cmd_mbox_sw2hw_dq_cq_set(mbox, q->num); + mlxsw_cmd_mbox_sw2hw_dq_sdq_tclass_set(mbox, 7); + mlxsw_cmd_mbox_sw2hw_dq_log2_dq_sz_set(mbox, 3); /* 8 pages */ + for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { + dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); + + mlxsw_cmd_mbox_sw2hw_dq_pa_set(mbox, i, mapaddr); + } + + err = mlxsw_cmd_sw2hw_sdq(mlxsw_pci->core, mbox, q->num); + if (err) + return err; + mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); + return 0; +} + +static void mlxsw_pci_sdq_fini(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q) +{ + mlxsw_cmd_hw2sw_sdq(mlxsw_pci->core, q->num); +} + +static int mlxsw_pci_sdq_dbg_read(struct seq_file *file, void *data) +{ + struct mlxsw_pci *mlxsw_pci = dev_get_drvdata(file->private); + struct mlxsw_pci_queue *q; + int i; + static const char hdr[] = + "NUM PROD_COUNT CONS_COUNT COUNT\n"; + + seq_printf(file, hdr); + for (i = 0; i < mlxsw_pci_sdq_count(mlxsw_pci); i++) { + q = mlxsw_pci_sdq_get(mlxsw_pci, i); + spin_lock_bh(&q->lock); + seq_printf(file, "%3d %10d %10d %5d\n", + i, q->producer_counter, q->consumer_counter, + q->count); + spin_unlock_bh(&q->lock); + } + return 0; +} + +static int mlxsw_pci_wqe_frag_map(struct mlxsw_pci *mlxsw_pci, char *wqe, + int index, char *frag_data, size_t frag_len, + int direction) +{ + struct pci_dev *pdev = mlxsw_pci->pdev; + dma_addr_t mapaddr; + + mapaddr = pci_map_single(pdev, frag_data, frag_len, direction); + if (unlikely(pci_dma_mapping_error(pdev, mapaddr))) { + if (net_ratelimit()) + dev_err(&pdev->dev, "failed to dma map tx frag\n"); + return -EIO; + } + mlxsw_pci_wqe_address_set(wqe, index, mapaddr); + mlxsw_pci_wqe_byte_count_set(wqe, index, frag_len); + return 0; +} + +static void mlxsw_pci_wqe_frag_unmap(struct mlxsw_pci *mlxsw_pci, char *wqe, + int index, int direction) +{ + struct pci_dev *pdev = mlxsw_pci->pdev; + size_t frag_len = mlxsw_pci_wqe_byte_count_get(wqe, index); + dma_addr_t mapaddr = mlxsw_pci_wqe_address_get(wqe, index); + + if (!frag_len) + return; + pci_unmap_single(pdev, mapaddr, frag_len, direction); +} + +static int mlxsw_pci_rdq_skb_alloc(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue_elem_info *elem_info) +{ + size_t buf_len = MLXSW_PORT_MAX_MTU; + char *wqe = elem_info->elem; + struct sk_buff *skb; + int err; + + elem_info->u.rdq.skb = NULL; + skb = netdev_alloc_skb_ip_align(NULL, buf_len); + if (!skb) + return -ENOMEM; + + /* Assume that wqe was previously zeroed. */ + + err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, 0, skb->data, + buf_len, DMA_FROM_DEVICE); + if (err) + goto err_frag_map; + + elem_info->u.rdq.skb = skb; + return 0; + +err_frag_map: + dev_kfree_skb_any(skb); + return err; +} + +static void mlxsw_pci_rdq_skb_free(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue_elem_info *elem_info) +{ + struct sk_buff *skb; + char *wqe; + + skb = elem_info->u.rdq.skb; + wqe = elem_info->elem; + + mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, 0, DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); +} + +static int mlxsw_pci_rdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, + struct mlxsw_pci_queue *q) +{ + struct mlxsw_pci_queue_elem_info *elem_info; + int i; + int err; + + q->producer_counter = 0; + q->consumer_counter = 0; + + /* Set CQ of same number of this RDQ with base + * above MLXSW_PCI_SDQS_MAX as the lower ones are assigned to SDQs. + */ + mlxsw_cmd_mbox_sw2hw_dq_cq_set(mbox, q->num + MLXSW_PCI_SDQS_COUNT); + mlxsw_cmd_mbox_sw2hw_dq_log2_dq_sz_set(mbox, 3); /* 8 pages */ + for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { + dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); + + mlxsw_cmd_mbox_sw2hw_dq_pa_set(mbox, i, mapaddr); + } + + err = mlxsw_cmd_sw2hw_rdq(mlxsw_pci->core, mbox, q->num); + if (err) + return err; + + mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); + + for (i = 0; i < q->count; i++) { + elem_info = mlxsw_pci_queue_elem_info_producer_get(q); + BUG_ON(!elem_info); + err = mlxsw_pci_rdq_skb_alloc(mlxsw_pci, elem_info); + if (err) + goto rollback; + /* Everything is set up, ring doorbell to pass elem to HW */ + q->producer_counter++; + mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); + } + + return 0; + +rollback: + for (i--; i >= 0; i--) { + elem_info = mlxsw_pci_queue_elem_info_get(q, i); + mlxsw_pci_rdq_skb_free(mlxsw_pci, elem_info); + } + mlxsw_cmd_hw2sw_rdq(mlxsw_pci->core, q->num); + + return err; +} + +static void mlxsw_pci_rdq_fini(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q) +{ + struct mlxsw_pci_queue_elem_info *elem_info; + int i; + + mlxsw_cmd_hw2sw_rdq(mlxsw_pci->core, q->num); + for (i = 0; i < q->count; i++) { + elem_info = mlxsw_pci_queue_elem_info_get(q, i); + mlxsw_pci_rdq_skb_free(mlxsw_pci, elem_info); + } +} + +static int mlxsw_pci_rdq_dbg_read(struct seq_file *file, void *data) +{ + struct mlxsw_pci *mlxsw_pci = dev_get_drvdata(file->private); + struct mlxsw_pci_queue *q; + int i; + static const char hdr[] = + "NUM PROD_COUNT CONS_COUNT COUNT\n"; + + seq_printf(file, hdr); + for (i = 0; i < mlxsw_pci_rdq_count(mlxsw_pci); i++) { + q = mlxsw_pci_rdq_get(mlxsw_pci, i); + spin_lock_bh(&q->lock); + seq_printf(file, "%3d %10d %10d %5d\n", + i, q->producer_counter, q->consumer_counter, + q->count); + spin_unlock_bh(&q->lock); + } + return 0; +} + +static int mlxsw_pci_cq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, + struct mlxsw_pci_queue *q) +{ + int i; + int err; + + q->consumer_counter = 0; + + for (i = 0; i < q->count; i++) { + char *elem = mlxsw_pci_queue_elem_get(q, i); + + mlxsw_pci_cqe_owner_set(elem, 1); + } + + mlxsw_cmd_mbox_sw2hw_cq_cv_set(mbox, 0); /* CQE ver 0 */ + mlxsw_cmd_mbox_sw2hw_cq_c_eqn_set(mbox, MLXSW_PCI_EQ_COMP_NUM); + mlxsw_cmd_mbox_sw2hw_cq_oi_set(mbox, 0); + mlxsw_cmd_mbox_sw2hw_cq_st_set(mbox, 0); + mlxsw_cmd_mbox_sw2hw_cq_log_cq_size_set(mbox, ilog2(q->count)); + for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { + dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); + + mlxsw_cmd_mbox_sw2hw_cq_pa_set(mbox, i, mapaddr); + } + err = mlxsw_cmd_sw2hw_cq(mlxsw_pci->core, mbox, q->num); + if (err) + return err; + mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); + mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); + return 0; +} + +static void mlxsw_pci_cq_fini(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q) +{ + mlxsw_cmd_hw2sw_cq(mlxsw_pci->core, q->num); +} + +static int mlxsw_pci_cq_dbg_read(struct seq_file *file, void *data) +{ + struct mlxsw_pci *mlxsw_pci = dev_get_drvdata(file->private); + + struct mlxsw_pci_queue *q; + int i; + static const char hdr[] = + "NUM CONS_INDEX SDQ_COUNT RDQ_COUNT COUNT\n"; + + seq_printf(file, hdr); + for (i = 0; i < mlxsw_pci_cq_count(mlxsw_pci); i++) { + q = mlxsw_pci_cq_get(mlxsw_pci, i); + spin_lock_bh(&q->lock); + seq_printf(file, "%3d %10d %10d %10d %5d\n", + i, q->consumer_counter, q->u.cq.comp_sdq_count, + q->u.cq.comp_rdq_count, q->count); + spin_unlock_bh(&q->lock); + } + return 0; +} + +static void mlxsw_pci_cqe_sdq_handle(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q, + u16 consumer_counter_limit, + char *cqe) +{ + struct pci_dev *pdev = mlxsw_pci->pdev; + struct mlxsw_pci_queue_elem_info *elem_info; + char *wqe; + struct sk_buff *skb; + int i; + + spin_lock(&q->lock); + elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); + skb = elem_info->u.sdq.skb; + wqe = elem_info->elem; + for (i = 0; i < MLXSW_PCI_WQE_SG_ENTRIES; i++) + mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, i, DMA_TO_DEVICE); + dev_kfree_skb_any(skb); + elem_info->u.sdq.skb = NULL; + + if (q->consumer_counter++ != consumer_counter_limit) + dev_dbg_ratelimited(&pdev->dev, "Consumer counter does not match limit in SDQ\n"); + spin_unlock(&q->lock); +} + +static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q, + u16 consumer_counter_limit, + char *cqe) +{ + struct pci_dev *pdev = mlxsw_pci->pdev; + struct mlxsw_pci_queue_elem_info *elem_info; + char *wqe; + struct sk_buff *skb; + struct mlxsw_rx_info rx_info; + int err; + + elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); + skb = elem_info->u.sdq.skb; + if (!skb) + return; + wqe = elem_info->elem; + mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, 0, DMA_FROM_DEVICE); + + if (q->consumer_counter++ != consumer_counter_limit) + dev_dbg_ratelimited(&pdev->dev, "Consumer counter does not match limit in RDQ\n"); + + /* We do not support lag now */ + if (mlxsw_pci_cqe_lag_get(cqe)) + goto drop; + + rx_info.sys_port = mlxsw_pci_cqe_system_port_get(cqe); + rx_info.trap_id = mlxsw_pci_cqe_trap_id_get(cqe); + + skb_put(skb, mlxsw_pci_cqe_byte_count_get(cqe)); + mlxsw_core_skb_receive(mlxsw_pci->core, skb, &rx_info); + +put_new_skb: + memset(wqe, 0, q->elem_size); + err = mlxsw_pci_rdq_skb_alloc(mlxsw_pci, elem_info); + if (err && net_ratelimit()) + dev_dbg(&pdev->dev, "Failed to alloc skb for RDQ\n"); + /* Everything is set up, ring doorbell to pass elem to HW */ + q->producer_counter++; + mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); + return; + +drop: + dev_kfree_skb_any(skb); + goto put_new_skb; +} + +static char *mlxsw_pci_cq_sw_cqe_get(struct mlxsw_pci_queue *q) +{ + return mlxsw_pci_queue_sw_elem_get(q, mlxsw_pci_cqe_owner_get); +} + +static void mlxsw_pci_cq_tasklet(unsigned long data) +{ + struct mlxsw_pci_queue *q = (struct mlxsw_pci_queue *) data; + struct mlxsw_pci *mlxsw_pci = q->pci; + char *cqe; + int items = 0; + int credits = q->count >> 1; + + while ((cqe = mlxsw_pci_cq_sw_cqe_get(q))) { + u16 wqe_counter = mlxsw_pci_cqe_wqe_counter_get(cqe); + u8 sendq = mlxsw_pci_cqe_sr_get(cqe); + u8 dqn = mlxsw_pci_cqe_dqn_get(cqe); + + if (sendq) { + struct mlxsw_pci_queue *sdq; + + sdq = mlxsw_pci_sdq_get(mlxsw_pci, dqn); + mlxsw_pci_cqe_sdq_handle(mlxsw_pci, sdq, + wqe_counter, cqe); + q->u.cq.comp_sdq_count++; + } else { + struct mlxsw_pci_queue *rdq; + + rdq = mlxsw_pci_rdq_get(mlxsw_pci, dqn); + mlxsw_pci_cqe_rdq_handle(mlxsw_pci, rdq, + wqe_counter, cqe); + q->u.cq.comp_rdq_count++; + } + if (++items == credits) + break; + } + if (items) { + mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); + mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); + } +} + +static int mlxsw_pci_eq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, + struct mlxsw_pci_queue *q) +{ + int i; + int err; + + q->consumer_counter = 0; + + for (i = 0; i < q->count; i++) { + char *elem = mlxsw_pci_queue_elem_get(q, i); + + mlxsw_pci_eqe_owner_set(elem, 1); + } + + mlxsw_cmd_mbox_sw2hw_eq_int_msix_set(mbox, 1); /* MSI-X used */ + mlxsw_cmd_mbox_sw2hw_eq_oi_set(mbox, 0); + mlxsw_cmd_mbox_sw2hw_eq_st_set(mbox, 1); /* armed */ + mlxsw_cmd_mbox_sw2hw_eq_log_eq_size_set(mbox, ilog2(q->count)); + for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { + dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); + + mlxsw_cmd_mbox_sw2hw_eq_pa_set(mbox, i, mapaddr); + } + err = mlxsw_cmd_sw2hw_eq(mlxsw_pci->core, mbox, q->num); + if (err) + return err; + mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); + mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); + return 0; +} + +static void mlxsw_pci_eq_fini(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q) +{ + mlxsw_cmd_hw2sw_eq(mlxsw_pci->core, q->num); +} + +static int mlxsw_pci_eq_dbg_read(struct seq_file *file, void *data) +{ + struct mlxsw_pci *mlxsw_pci = dev_get_drvdata(file->private); + struct mlxsw_pci_queue *q; + int i; + static const char hdr[] = + "NUM CONS_COUNT EV_CMD EV_COMP EV_OTHER COUNT\n"; + + seq_printf(file, hdr); + for (i = 0; i < mlxsw_pci_eq_count(mlxsw_pci); i++) { + q = mlxsw_pci_eq_get(mlxsw_pci, i); + spin_lock_bh(&q->lock); + seq_printf(file, "%3d %10d %10d %10d %10d %5d\n", + i, q->consumer_counter, q->u.eq.ev_cmd_count, + q->u.eq.ev_comp_count, q->u.eq.ev_other_count, + q->count); + spin_unlock_bh(&q->lock); + } + return 0; +} + +static void mlxsw_pci_eq_cmd_event(struct mlxsw_pci *mlxsw_pci, char *eqe) +{ + mlxsw_pci->cmd.comp.status = mlxsw_pci_eqe_cmd_status_get(eqe); + mlxsw_pci->cmd.comp.out_param = + ((u64) mlxsw_pci_eqe_cmd_out_param_h_get(eqe)) << 32 | + mlxsw_pci_eqe_cmd_out_param_l_get(eqe); + mlxsw_pci->cmd.wait_done = true; + wake_up(&mlxsw_pci->cmd.wait); +} + +static char *mlxsw_pci_eq_sw_eqe_get(struct mlxsw_pci_queue *q) +{ + return mlxsw_pci_queue_sw_elem_get(q, mlxsw_pci_eqe_owner_get); +} + +static void mlxsw_pci_eq_tasklet(unsigned long data) +{ + struct mlxsw_pci_queue *q = (struct mlxsw_pci_queue *) data; + struct mlxsw_pci *mlxsw_pci = q->pci; + unsigned long active_cqns[BITS_TO_LONGS(MLXSW_PCI_CQS_COUNT)]; + char *eqe; + u8 cqn; + bool cq_handle = false; + int items = 0; + int credits = q->count >> 1; + + memset(&active_cqns, 0, sizeof(active_cqns)); + + while ((eqe = mlxsw_pci_eq_sw_eqe_get(q))) { + u8 event_type = mlxsw_pci_eqe_event_type_get(eqe); + + switch (event_type) { + case MLXSW_PCI_EQE_EVENT_TYPE_CMD: + mlxsw_pci_eq_cmd_event(mlxsw_pci, eqe); + q->u.eq.ev_cmd_count++; + break; + case MLXSW_PCI_EQE_EVENT_TYPE_COMP: + cqn = mlxsw_pci_eqe_cqn_get(eqe); + set_bit(cqn, active_cqns); + cq_handle = true; + q->u.eq.ev_comp_count++; + break; + default: + q->u.eq.ev_other_count++; + } + if (++items == credits) + break; + } + if (items) { + mlxsw_pci_queue_doorbell_consumer_ring(mlxsw_pci, q); + mlxsw_pci_queue_doorbell_arm_consumer_ring(mlxsw_pci, q); + } + + if (!cq_handle) + return; + for_each_set_bit(cqn, active_cqns, MLXSW_PCI_CQS_COUNT) { + q = mlxsw_pci_cq_get(mlxsw_pci, cqn); + mlxsw_pci_queue_tasklet_schedule(q); + } +} + +struct mlxsw_pci_queue_ops { + const char *name; + enum mlxsw_pci_queue_type type; + int (*init)(struct mlxsw_pci *mlxsw_pci, char *mbox, + struct mlxsw_pci_queue *q); + void (*fini)(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_queue *q); + void (*tasklet)(unsigned long data); + int (*dbg_read)(struct seq_file *s, void *data); + u16 elem_count; + u8 elem_size; +}; + +static const struct mlxsw_pci_queue_ops mlxsw_pci_sdq_ops = { + .type = MLXSW_PCI_QUEUE_TYPE_SDQ, + .init = mlxsw_pci_sdq_init, + .fini = mlxsw_pci_sdq_fini, + .dbg_read = mlxsw_pci_sdq_dbg_read, + .elem_count = MLXSW_PCI_WQE_COUNT, + .elem_size = MLXSW_PCI_WQE_SIZE, +}; + +static const struct mlxsw_pci_queue_ops mlxsw_pci_rdq_ops = { + .type = MLXSW_PCI_QUEUE_TYPE_RDQ, + .init = mlxsw_pci_rdq_init, + .fini = mlxsw_pci_rdq_fini, + .dbg_read = mlxsw_pci_rdq_dbg_read, + .elem_count = MLXSW_PCI_WQE_COUNT, + .elem_size = MLXSW_PCI_WQE_SIZE +}; + +static const struct mlxsw_pci_queue_ops mlxsw_pci_cq_ops = { + .type = MLXSW_PCI_QUEUE_TYPE_CQ, + .init = mlxsw_pci_cq_init, + .fini = mlxsw_pci_cq_fini, + .tasklet = mlxsw_pci_cq_tasklet, + .dbg_read = mlxsw_pci_cq_dbg_read, + .elem_count = MLXSW_PCI_CQE_COUNT, + .elem_size = MLXSW_PCI_CQE_SIZE +}; + +static const struct mlxsw_pci_queue_ops mlxsw_pci_eq_ops = { + .type = MLXSW_PCI_QUEUE_TYPE_EQ, + .init = mlxsw_pci_eq_init, + .fini = mlxsw_pci_eq_fini, + .tasklet = mlxsw_pci_eq_tasklet, + .dbg_read = mlxsw_pci_eq_dbg_read, + .elem_count = MLXSW_PCI_EQE_COUNT, + .elem_size = MLXSW_PCI_EQE_SIZE +}; + +static int mlxsw_pci_queue_init(struct mlxsw_pci *mlxsw_pci, char *mbox, + const struct mlxsw_pci_queue_ops *q_ops, + struct mlxsw_pci_queue *q, u8 q_num) +{ + struct mlxsw_pci_mem_item *mem_item = &q->mem_item; + int i; + int err; + + spin_lock_init(&q->lock); + q->num = q_num; + q->count = q_ops->elem_count; + q->elem_size = q_ops->elem_size; + q->type = q_ops->type; + q->pci = mlxsw_pci; + + if (q_ops->tasklet) + tasklet_init(&q->tasklet, q_ops->tasklet, (unsigned long) q); + + mem_item->size = MLXSW_PCI_AQ_SIZE; + mem_item->buf = pci_alloc_consistent(mlxsw_pci->pdev, + mem_item->size, + &mem_item->mapaddr); + if (!mem_item->buf) + return -ENOMEM; + memset(mem_item->buf, 0, mem_item->size); + + q->elem_info = kcalloc(q->count, sizeof(*q->elem_info), GFP_KERNEL); + if (!q->elem_info) { + err = -ENOMEM; + goto err_elem_info_alloc; + } + + /* Initialize dma mapped elements info elem_info for + * future easy access. + */ + for (i = 0; i < q->count; i++) { + struct mlxsw_pci_queue_elem_info *elem_info; + + elem_info = mlxsw_pci_queue_elem_info_get(q, i); + elem_info->elem = + __mlxsw_pci_queue_elem_get(q, q_ops->elem_size, i); + } + + mlxsw_cmd_mbox_zero(mbox); + err = q_ops->init(mlxsw_pci, mbox, q); + if (err) + goto err_q_ops_init; + return 0; + +err_q_ops_init: + kfree(q->elem_info); +err_elem_info_alloc: + pci_free_consistent(mlxsw_pci->pdev, mem_item->size, + mem_item->buf, mem_item->mapaddr); + return err; +} + +static void mlxsw_pci_queue_fini(struct mlxsw_pci *mlxsw_pci, + const struct mlxsw_pci_queue_ops *q_ops, + struct mlxsw_pci_queue *q) +{ + struct mlxsw_pci_mem_item *mem_item = &q->mem_item; + + q_ops->fini(mlxsw_pci, q); + kfree(q->elem_info); + pci_free_consistent(mlxsw_pci->pdev, mem_item->size, + mem_item->buf, mem_item->mapaddr); +} + +static int mlxsw_pci_queue_group_init(struct mlxsw_pci *mlxsw_pci, char *mbox, + const struct mlxsw_pci_queue_ops *q_ops, + u8 num_qs) +{ + struct pci_dev *pdev = mlxsw_pci->pdev; + struct mlxsw_pci_queue_type_group *queue_group; + char tmp[16]; + int i; + int err; + + queue_group = mlxsw_pci_queue_type_group_get(mlxsw_pci, q_ops->type); + queue_group->q = kcalloc(num_qs, sizeof(*queue_group->q), GFP_KERNEL); + if (!queue_group->q) + return -ENOMEM; + + for (i = 0; i < num_qs; i++) { + err = mlxsw_pci_queue_init(mlxsw_pci, mbox, q_ops, + &queue_group->q[i], i); + if (err) + goto err_queue_init; + } + queue_group->count = num_qs; + + sprintf(tmp, "%s_stats", mlxsw_pci_queue_type_str(q_ops->type)); + debugfs_create_devm_seqfile(&pdev->dev, tmp, mlxsw_pci->dbg_dir, + q_ops->dbg_read); + + return 0; + +err_queue_init: + for (i--; i >= 0; i--) + mlxsw_pci_queue_fini(mlxsw_pci, q_ops, &queue_group->q[i]); + kfree(queue_group->q); + return err; +} + +static void mlxsw_pci_queue_group_fini(struct mlxsw_pci *mlxsw_pci, + const struct mlxsw_pci_queue_ops *q_ops) +{ + struct mlxsw_pci_queue_type_group *queue_group; + int i; + + queue_group = mlxsw_pci_queue_type_group_get(mlxsw_pci, q_ops->type); + for (i = 0; i < queue_group->count; i++) + mlxsw_pci_queue_fini(mlxsw_pci, q_ops, &queue_group->q[i]); + kfree(queue_group->q); +} + +static int mlxsw_pci_aqs_init(struct mlxsw_pci *mlxsw_pci, char *mbox) +{ + struct pci_dev *pdev = mlxsw_pci->pdev; + u8 num_sdqs; + u8 sdq_log2sz; + u8 num_rdqs; + u8 rdq_log2sz; + u8 num_cqs; + u8 cq_log2sz; + u8 num_eqs; + u8 eq_log2sz; + int err; + + mlxsw_cmd_mbox_zero(mbox); + err = mlxsw_cmd_query_aq_cap(mlxsw_pci->core, mbox); + if (err) + return err; + + num_sdqs = mlxsw_cmd_mbox_query_aq_cap_max_num_sdqs_get(mbox); + sdq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_sdq_sz_get(mbox); + num_rdqs = mlxsw_cmd_mbox_query_aq_cap_max_num_rdqs_get(mbox); + rdq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_rdq_sz_get(mbox); + num_cqs = mlxsw_cmd_mbox_query_aq_cap_max_num_cqs_get(mbox); + cq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_cq_sz_get(mbox); + num_eqs = mlxsw_cmd_mbox_query_aq_cap_max_num_eqs_get(mbox); + eq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_eq_sz_get(mbox); + + if ((num_sdqs != MLXSW_PCI_SDQS_COUNT) || + (num_rdqs != MLXSW_PCI_RDQS_COUNT) || + (num_cqs != MLXSW_PCI_CQS_COUNT) || + (num_eqs != MLXSW_PCI_EQS_COUNT)) { + dev_err(&pdev->dev, "Unsupported number of queues\n"); + return -EINVAL; + } + + if ((1 << sdq_log2sz != MLXSW_PCI_WQE_COUNT) || + (1 << rdq_log2sz != MLXSW_PCI_WQE_COUNT) || + (1 << cq_log2sz != MLXSW_PCI_CQE_COUNT) || + (1 << eq_log2sz != MLXSW_PCI_EQE_COUNT)) { + dev_err(&pdev->dev, "Unsupported number of async queue descriptors\n"); + return -EINVAL; + } + + err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_eq_ops, + num_eqs); + if (err) { + dev_err(&pdev->dev, "Failed to initialize event queues\n"); + return err; + } + + err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_cq_ops, + num_cqs); + if (err) { + dev_err(&pdev->dev, "Failed to initialize completion queues\n"); + goto err_cqs_init; + } + + err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_sdq_ops, + num_sdqs); + if (err) { + dev_err(&pdev->dev, "Failed to initialize send descriptor queues\n"); + goto err_sdqs_init; + } + + err = mlxsw_pci_queue_group_init(mlxsw_pci, mbox, &mlxsw_pci_rdq_ops, + num_rdqs); + if (err) { + dev_err(&pdev->dev, "Failed to initialize receive descriptor queues\n"); + goto err_rdqs_init; + } + + /* We have to poll in command interface until queues are initialized */ + mlxsw_pci->cmd.nopoll = true; + return 0; + +err_rdqs_init: + mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_sdq_ops); +err_sdqs_init: + mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_cq_ops); +err_cqs_init: + mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_eq_ops); + return err; +} + +static void mlxsw_pci_aqs_fini(struct mlxsw_pci *mlxsw_pci) +{ + mlxsw_pci->cmd.nopoll = false; + mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_rdq_ops); + mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_sdq_ops); + mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_cq_ops); + mlxsw_pci_queue_group_fini(mlxsw_pci, &mlxsw_pci_eq_ops); +} + +static void +mlxsw_pci_config_profile_swid_config(struct mlxsw_pci *mlxsw_pci, + char *mbox, int index, + const struct mlxsw_swid_config *swid) +{ + u8 mask = 0; + + if (swid->used_type) { + mlxsw_cmd_mbox_config_profile_swid_config_type_set( + mbox, index, swid->type); + mask |= 1; + } + if (swid->used_properties) { + mlxsw_cmd_mbox_config_profile_swid_config_properties_set( + mbox, index, swid->properties); + mask |= 2; + } + mlxsw_cmd_mbox_config_profile_swid_config_mask_set(mbox, index, mask); +} + +static int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox, + const struct mlxsw_config_profile *profile) +{ + int i; + + mlxsw_cmd_mbox_zero(mbox); + + if (profile->used_max_vepa_channels) { + mlxsw_cmd_mbox_config_profile_set_max_vepa_channels_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_max_vepa_channels_set( + mbox, profile->max_vepa_channels); + } + if (profile->used_max_lag) { + mlxsw_cmd_mbox_config_profile_set_max_lag_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_max_lag_set( + mbox, profile->max_lag); + } + if (profile->used_max_port_per_lag) { + mlxsw_cmd_mbox_config_profile_set_max_port_per_lag_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_max_port_per_lag_set( + mbox, profile->max_port_per_lag); + } + if (profile->used_max_mid) { + mlxsw_cmd_mbox_config_profile_set_max_mid_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_max_mid_set( + mbox, profile->max_mid); + } + if (profile->used_max_pgt) { + mlxsw_cmd_mbox_config_profile_set_max_pgt_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_max_pgt_set( + mbox, profile->max_pgt); + } + if (profile->used_max_system_port) { + mlxsw_cmd_mbox_config_profile_set_max_system_port_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_max_system_port_set( + mbox, profile->max_system_port); + } + if (profile->used_max_vlan_groups) { + mlxsw_cmd_mbox_config_profile_set_max_vlan_groups_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_max_vlan_groups_set( + mbox, profile->max_vlan_groups); + } + if (profile->used_max_regions) { + mlxsw_cmd_mbox_config_profile_set_max_regions_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_max_regions_set( + mbox, profile->max_regions); + } + if (profile->used_flood_tables) { + mlxsw_cmd_mbox_config_profile_set_flood_tables_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_max_flood_tables_set( + mbox, profile->max_flood_tables); + mlxsw_cmd_mbox_config_profile_max_vid_flood_tables_set( + mbox, profile->max_vid_flood_tables); + } + if (profile->used_flood_mode) { + mlxsw_cmd_mbox_config_profile_set_flood_mode_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_flood_mode_set( + mbox, profile->flood_mode); + } + if (profile->used_max_ib_mc) { + mlxsw_cmd_mbox_config_profile_set_max_ib_mc_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_max_ib_mc_set( + mbox, profile->max_ib_mc); + } + if (profile->used_max_pkey) { + mlxsw_cmd_mbox_config_profile_set_max_pkey_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_max_pkey_set( + mbox, profile->max_pkey); + } + if (profile->used_ar_sec) { + mlxsw_cmd_mbox_config_profile_set_ar_sec_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_ar_sec_set( + mbox, profile->ar_sec); + } + if (profile->used_adaptive_routing_group_cap) { + mlxsw_cmd_mbox_config_profile_set_adaptive_routing_group_cap_set( + mbox, 1); + mlxsw_cmd_mbox_config_profile_adaptive_routing_group_cap_set( + mbox, profile->adaptive_routing_group_cap); + } + + for (i = 0; i < MLXSW_CONFIG_PROFILE_SWID_COUNT; i++) + mlxsw_pci_config_profile_swid_config(mlxsw_pci, mbox, i, + &profile->swid_config[i]); + + return mlxsw_cmd_config_profile_set(mlxsw_pci->core, mbox); +} + +static int mlxsw_pci_boardinfo(struct mlxsw_pci *mlxsw_pci, char *mbox) +{ + struct mlxsw_bus_info *bus_info = &mlxsw_pci->bus_info; + int err; + + mlxsw_cmd_mbox_zero(mbox); + err = mlxsw_cmd_boardinfo(mlxsw_pci->core, mbox); + if (err) + return err; + mlxsw_cmd_mbox_boardinfo_vsd_memcpy_from(mbox, bus_info->vsd); + mlxsw_cmd_mbox_boardinfo_psid_memcpy_from(mbox, bus_info->psid); + return 0; +} + +static int mlxsw_pci_fw_area_init(struct mlxsw_pci *mlxsw_pci, char *mbox, + u16 num_pages) +{ + struct mlxsw_pci_mem_item *mem_item; + int i; + int err; + + mlxsw_pci->fw_area.items = kcalloc(num_pages, sizeof(*mem_item), + GFP_KERNEL); + if (!mlxsw_pci->fw_area.items) + return -ENOMEM; + mlxsw_pci->fw_area.num_pages = num_pages; + + mlxsw_cmd_mbox_zero(mbox); + for (i = 0; i < num_pages; i++) { + mem_item = &mlxsw_pci->fw_area.items[i]; + + mem_item->size = MLXSW_PCI_PAGE_SIZE; + mem_item->buf = pci_alloc_consistent(mlxsw_pci->pdev, + mem_item->size, + &mem_item->mapaddr); + if (!mem_item->buf) { + err = -ENOMEM; + goto err_alloc; + } + mlxsw_cmd_mbox_map_fa_pa_set(mbox, i, mem_item->mapaddr); + mlxsw_cmd_mbox_map_fa_log2size_set(mbox, i, 0); /* 1 page */ + } + + err = mlxsw_cmd_map_fa(mlxsw_pci->core, mbox, num_pages); + if (err) + goto err_cmd_map_fa; + + return 0; + +err_cmd_map_fa: +err_alloc: + for (i--; i >= 0; i--) { + mem_item = &mlxsw_pci->fw_area.items[i]; + + pci_free_consistent(mlxsw_pci->pdev, mem_item->size, + mem_item->buf, mem_item->mapaddr); + } + kfree(mlxsw_pci->fw_area.items); + return err; +} + +static void mlxsw_pci_fw_area_fini(struct mlxsw_pci *mlxsw_pci) +{ + struct mlxsw_pci_mem_item *mem_item; + int i; + + mlxsw_cmd_unmap_fa(mlxsw_pci->core); + + for (i = 0; i < mlxsw_pci->fw_area.num_pages; i++) { + mem_item = &mlxsw_pci->fw_area.items[i]; + + pci_free_consistent(mlxsw_pci->pdev, mem_item->size, + mem_item->buf, mem_item->mapaddr); + } + kfree(mlxsw_pci->fw_area.items); +} + +static irqreturn_t mlxsw_pci_eq_irq_handler(int irq, void *dev_id) +{ + struct mlxsw_pci *mlxsw_pci = dev_id; + struct mlxsw_pci_queue *q; + int i; + + for (i = 0; i < MLXSW_PCI_EQS_COUNT; i++) { + q = mlxsw_pci_eq_get(mlxsw_pci, i); + mlxsw_pci_queue_tasklet_schedule(q); + } + return IRQ_HANDLED; +} + +static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, + const struct mlxsw_config_profile *profile) +{ + struct mlxsw_pci *mlxsw_pci = bus_priv; + struct pci_dev *pdev = mlxsw_pci->pdev; + char *mbox; + u16 num_pages; + int err; + + mutex_init(&mlxsw_pci->cmd.lock); + init_waitqueue_head(&mlxsw_pci->cmd.wait); + + mlxsw_pci->core = mlxsw_core; + + mbox = mlxsw_cmd_mbox_alloc(); + if (!mbox) + return -ENOMEM; + err = mlxsw_cmd_query_fw(mlxsw_core, mbox); + if (err) + goto err_query_fw; + + mlxsw_pci->bus_info.fw_rev.major = + mlxsw_cmd_mbox_query_fw_fw_rev_major_get(mbox); + mlxsw_pci->bus_info.fw_rev.minor = + mlxsw_cmd_mbox_query_fw_fw_rev_minor_get(mbox); + mlxsw_pci->bus_info.fw_rev.subminor = + mlxsw_cmd_mbox_query_fw_fw_rev_subminor_get(mbox); + + if (mlxsw_cmd_mbox_query_fw_cmd_interface_rev_get(mbox) != 1) { + dev_err(&pdev->dev, "Unsupported cmd interface revision ID queried from hw\n"); + err = -EINVAL; + goto err_iface_rev; + } + if (mlxsw_cmd_mbox_query_fw_doorbell_page_bar_get(mbox) != 0) { + dev_err(&pdev->dev, "Unsupported doorbell page bar queried from hw\n"); + err = -EINVAL; + goto err_doorbell_page_bar; + } + + mlxsw_pci->doorbell_offset = + mlxsw_cmd_mbox_query_fw_doorbell_page_offset_get(mbox); + + num_pages = mlxsw_cmd_mbox_query_fw_fw_pages_get(mbox); + err = mlxsw_pci_fw_area_init(mlxsw_pci, mbox, num_pages); + if (err) + goto err_fw_area_init; + + err = mlxsw_pci_boardinfo(mlxsw_pci, mbox); + if (err) + goto err_boardinfo; + + err = mlxsw_pci_config_profile(mlxsw_pci, mbox, profile); + if (err) + goto err_config_profile; + + err = mlxsw_pci_aqs_init(mlxsw_pci, mbox); + if (err) + goto err_aqs_init; + + err = request_irq(mlxsw_pci->msix_entry.vector, + mlxsw_pci_eq_irq_handler, 0, + mlxsw_pci_driver_name, mlxsw_pci); + if (err) { + dev_err(&pdev->dev, "IRQ request failed\n"); + goto err_request_eq_irq; + } + + goto mbox_put; + +err_request_eq_irq: + mlxsw_pci_aqs_fini(mlxsw_pci); +err_aqs_init: +err_config_profile: +err_boardinfo: + mlxsw_pci_fw_area_fini(mlxsw_pci); +err_fw_area_init: +err_doorbell_page_bar: +err_iface_rev: +err_query_fw: +mbox_put: + mlxsw_cmd_mbox_free(mbox); + return err; +} + +static void mlxsw_pci_fini(void *bus_priv) +{ + struct mlxsw_pci *mlxsw_pci = bus_priv; + + free_irq(mlxsw_pci->msix_entry.vector, mlxsw_pci); + mlxsw_pci_aqs_fini(mlxsw_pci); + mlxsw_pci_fw_area_fini(mlxsw_pci); +} + +static struct mlxsw_pci_queue * +mlxsw_pci_sdq_pick(struct mlxsw_pci *mlxsw_pci, + const struct mlxsw_tx_info *tx_info) +{ + u8 sdqn = tx_info->local_port % mlxsw_pci_sdq_count(mlxsw_pci); + + return mlxsw_pci_sdq_get(mlxsw_pci, sdqn); +} + +static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb, + const struct mlxsw_tx_info *tx_info) +{ + struct mlxsw_pci *mlxsw_pci = bus_priv; + struct mlxsw_pci_queue *q; + struct mlxsw_pci_queue_elem_info *elem_info; + char *wqe; + int i; + int err; + + if (skb_shinfo(skb)->nr_frags > MLXSW_PCI_WQE_SG_ENTRIES - 1) { + err = skb_linearize(skb); + if (err) + return err; + } + + q = mlxsw_pci_sdq_pick(mlxsw_pci, tx_info); + spin_lock_bh(&q->lock); + elem_info = mlxsw_pci_queue_elem_info_producer_get(q); + if (!elem_info) { + /* queue is full */ + err = -EAGAIN; + goto unlock; + } + elem_info->u.sdq.skb = skb; + + wqe = elem_info->elem; + mlxsw_pci_wqe_c_set(wqe, 1); /* always report completion */ + mlxsw_pci_wqe_lp_set(wqe, !!tx_info->is_emad); + mlxsw_pci_wqe_type_set(wqe, MLXSW_PCI_WQE_TYPE_ETHERNET); + + err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, 0, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + if (err) + goto unlock; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + err = mlxsw_pci_wqe_frag_map(mlxsw_pci, wqe, i + 1, + skb_frag_address(frag), + skb_frag_size(frag), + DMA_TO_DEVICE); + if (err) + goto unmap_frags; + } + + /* Set unused sq entries byte count to zero. */ + for (i++; i < MLXSW_PCI_WQE_SG_ENTRIES; i++) + mlxsw_pci_wqe_byte_count_set(wqe, i, 0); + + /* Everything is set up, ring producer doorbell to get HW going */ + q->producer_counter++; + mlxsw_pci_queue_doorbell_producer_ring(mlxsw_pci, q); + + goto unlock; + +unmap_frags: + for (; i >= 0; i--) + mlxsw_pci_wqe_frag_unmap(mlxsw_pci, wqe, i, DMA_TO_DEVICE); +unlock: + spin_unlock_bh(&q->lock); + return err; +} + +static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, + u32 in_mod, bool out_mbox_direct, + char *in_mbox, size_t in_mbox_size, + char *out_mbox, size_t out_mbox_size, + u8 *p_status) +{ + struct mlxsw_pci *mlxsw_pci = bus_priv; + dma_addr_t in_mapaddr = 0; + dma_addr_t out_mapaddr = 0; + bool evreq = mlxsw_pci->cmd.nopoll; + unsigned long timeout = msecs_to_jiffies(MLXSW_PCI_CIR_TIMEOUT_MSECS); + bool *p_wait_done = &mlxsw_pci->cmd.wait_done; + int err; + + *p_status = MLXSW_CMD_STATUS_OK; + + err = mutex_lock_interruptible(&mlxsw_pci->cmd.lock); + if (err) + return err; + + if (in_mbox) { + in_mapaddr = pci_map_single(mlxsw_pci->pdev, in_mbox, + in_mbox_size, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(mlxsw_pci->pdev, + in_mapaddr))) { + err = -EIO; + goto err_in_mbox_map; + } + } + mlxsw_pci_write32(mlxsw_pci, CIR_IN_PARAM_HI, in_mapaddr >> 32); + mlxsw_pci_write32(mlxsw_pci, CIR_IN_PARAM_LO, in_mapaddr); + + if (out_mbox) { + out_mapaddr = pci_map_single(mlxsw_pci->pdev, out_mbox, + out_mbox_size, PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(mlxsw_pci->pdev, + out_mapaddr))) { + err = -EIO; + goto err_out_mbox_map; + } + } + mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_HI, out_mapaddr >> 32); + mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_LO, out_mapaddr); + + mlxsw_pci_write32(mlxsw_pci, CIR_IN_MODIFIER, in_mod); + mlxsw_pci_write32(mlxsw_pci, CIR_TOKEN, 0); + + *p_wait_done = false; + + wmb(); /* all needs to be written before we write control register */ + mlxsw_pci_write32(mlxsw_pci, CIR_CTRL, + MLXSW_PCI_CIR_CTRL_GO_BIT | + (evreq ? MLXSW_PCI_CIR_CTRL_EVREQ_BIT : 0) | + (opcode_mod << MLXSW_PCI_CIR_CTRL_OPCODE_MOD_SHIFT) | + opcode); + + if (!evreq) { + unsigned long end; + + end = jiffies + timeout; + do { + u32 ctrl = mlxsw_pci_read32(mlxsw_pci, CIR_CTRL); + + if (!(ctrl & MLXSW_PCI_CIR_CTRL_GO_BIT)) { + *p_wait_done = true; + *p_status = ctrl >> MLXSW_PCI_CIR_CTRL_STATUS_SHIFT; + break; + } + cond_resched(); + } while (time_before(jiffies, end)); + } else { + wait_event_timeout(mlxsw_pci->cmd.wait, *p_wait_done, timeout); + *p_status = mlxsw_pci->cmd.comp.status; + } + + err = 0; + if (*p_wait_done) { + if (*p_status) + err = -EIO; + } else { + err = -ETIMEDOUT; + } + + if (!err && out_mbox && out_mbox_direct) { + /* Some commands does not use output param as address to mailbox + * but they store output directly into registers. In that case, + * copy registers into mbox buffer. + */ + __be32 tmp; + + if (!evreq) { + tmp = cpu_to_be32(mlxsw_pci_read32(mlxsw_pci, + CIR_OUT_PARAM_HI)); + memcpy(out_mbox, &tmp, sizeof(tmp)); + tmp = cpu_to_be32(mlxsw_pci_read32(mlxsw_pci, + CIR_OUT_PARAM_LO)); + memcpy(out_mbox + sizeof(tmp), &tmp, sizeof(tmp)); + } + } + + if (out_mapaddr) + pci_unmap_single(mlxsw_pci->pdev, out_mapaddr, out_mbox_size, + PCI_DMA_FROMDEVICE); + + /* fall through */ + +err_out_mbox_map: + if (in_mapaddr) + pci_unmap_single(mlxsw_pci->pdev, in_mapaddr, in_mbox_size, + PCI_DMA_TODEVICE); +err_in_mbox_map: + mutex_unlock(&mlxsw_pci->cmd.lock); + + return err; +} + +static const struct mlxsw_bus mlxsw_pci_bus = { + .kind = "pci", + .init = mlxsw_pci_init, + .fini = mlxsw_pci_fini, + .skb_transmit = mlxsw_pci_skb_transmit, + .cmd_exec = mlxsw_pci_cmd_exec, +}; + +static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci) +{ + mlxsw_pci_write32(mlxsw_pci, SW_RESET, MLXSW_PCI_SW_RESET_RST_BIT); + /* Current firware does not let us know when the reset is done. + * So we just wait here for constant time and hope for the best. + */ + msleep(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS); + return 0; +} + +static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct mlxsw_pci *mlxsw_pci; + int err; + + mlxsw_pci = kzalloc(sizeof(*mlxsw_pci), GFP_KERNEL); + if (!mlxsw_pci) + return -ENOMEM; + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "pci_enable_device failed\n"); + goto err_pci_enable_device; + } + + err = pci_request_regions(pdev, mlxsw_pci_driver_name); + if (err) { + dev_err(&pdev->dev, "pci_request_regions failed\n"); + goto err_pci_request_regions; + } + + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (!err) { + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (err) { + dev_err(&pdev->dev, "pci_set_consistent_dma_mask failed\n"); + goto err_pci_set_dma_mask; + } + } else { + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, "pci_set_dma_mask failed\n"); + goto err_pci_set_dma_mask; + } + } + + if (pci_resource_len(pdev, 0) < MLXSW_PCI_BAR0_SIZE) { + dev_err(&pdev->dev, "invalid PCI region size\n"); + err = -EINVAL; + goto err_pci_resource_len_check; + } + + mlxsw_pci->hw_addr = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!mlxsw_pci->hw_addr) { + dev_err(&pdev->dev, "ioremap failed\n"); + err = -EIO; + goto err_ioremap; + } + pci_set_master(pdev); + + mlxsw_pci->pdev = pdev; + pci_set_drvdata(pdev, mlxsw_pci); + + err = mlxsw_pci_sw_reset(mlxsw_pci); + if (err) { + dev_err(&pdev->dev, "Software reset failed\n"); + goto err_sw_reset; + } + + err = pci_enable_msix_exact(pdev, &mlxsw_pci->msix_entry, 1); + if (err) { + dev_err(&pdev->dev, "MSI-X init failed\n"); + goto err_msix_init; + } + + mlxsw_pci->bus_info.device_kind = mlxsw_pci_device_kind_get(id); + mlxsw_pci->bus_info.device_name = pci_name(mlxsw_pci->pdev); + mlxsw_pci->bus_info.dev = &pdev->dev; + + mlxsw_pci->dbg_dir = debugfs_create_dir(mlxsw_pci->bus_info.device_name, + mlxsw_pci_dbg_root); + if (!mlxsw_pci->dbg_dir) { + dev_err(&pdev->dev, "Failed to create debugfs dir\n"); + goto err_dbg_create_dir; + } + + err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, + &mlxsw_pci_bus, mlxsw_pci); + if (err) { + dev_err(&pdev->dev, "cannot register bus device\n"); + goto err_bus_device_register; + } + + return 0; + +err_bus_device_register: + debugfs_remove_recursive(mlxsw_pci->dbg_dir); +err_dbg_create_dir: + pci_disable_msix(mlxsw_pci->pdev); +err_msix_init: +err_sw_reset: + iounmap(mlxsw_pci->hw_addr); +err_ioremap: +err_pci_resource_len_check: +err_pci_set_dma_mask: + pci_release_regions(pdev); +err_pci_request_regions: + pci_disable_device(pdev); +err_pci_enable_device: + kfree(mlxsw_pci); + return err; +} + +static void mlxsw_pci_remove(struct pci_dev *pdev) +{ + struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev); + + mlxsw_core_bus_device_unregister(mlxsw_pci->core); + debugfs_remove_recursive(mlxsw_pci->dbg_dir); + pci_disable_msix(mlxsw_pci->pdev); + iounmap(mlxsw_pci->hw_addr); + pci_release_regions(mlxsw_pci->pdev); + pci_disable_device(mlxsw_pci->pdev); + kfree(mlxsw_pci); +} + +static struct pci_driver mlxsw_pci_driver = { + .name = mlxsw_pci_driver_name, + .id_table = mlxsw_pci_id_table, + .probe = mlxsw_pci_probe, + .remove = mlxsw_pci_remove, +}; + +static int __init mlxsw_pci_module_init(void) +{ + int err; + + mlxsw_pci_dbg_root = debugfs_create_dir(mlxsw_pci_driver_name, NULL); + if (!mlxsw_pci_dbg_root) + return -ENOMEM; + err = pci_register_driver(&mlxsw_pci_driver); + if (err) + goto err_register_driver; + return 0; + +err_register_driver: + debugfs_remove_recursive(mlxsw_pci_dbg_root); + return err; +} + +static void __exit mlxsw_pci_module_exit(void) +{ + pci_unregister_driver(&mlxsw_pci_driver); + debugfs_remove_recursive(mlxsw_pci_dbg_root); +} + +module_init(mlxsw_pci_module_init); +module_exit(mlxsw_pci_module_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Jiri Pirko "); +MODULE_DESCRIPTION("Mellanox switch PCI interface driver"); +MODULE_DEVICE_TABLE(pci, mlxsw_pci_id_table); diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.h b/drivers/net/ethernet/mellanox/mlxsw/pci.h new file mode 100644 index 000000000000..6176a930130b --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.h @@ -0,0 +1,220 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/pci.h + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Jiri Pirko + * + * 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 _MLXSW_PCI_H +#define _MLXSW_PCI_H + +#include + +#include "item.h" + +#define MLXSW_PCI_BAR0_SIZE (1024 * 1024) /* 1MB */ +#define MLXSW_PCI_PAGE_SIZE 4096 + +#define MLXSW_PCI_CIR_BASE 0x71000 +#define MLXSW_PCI_CIR_IN_PARAM_HI MLXSW_PCI_CIR_BASE +#define MLXSW_PCI_CIR_IN_PARAM_LO (MLXSW_PCI_CIR_BASE + 0x04) +#define MLXSW_PCI_CIR_IN_MODIFIER (MLXSW_PCI_CIR_BASE + 0x08) +#define MLXSW_PCI_CIR_OUT_PARAM_HI (MLXSW_PCI_CIR_BASE + 0x0C) +#define MLXSW_PCI_CIR_OUT_PARAM_LO (MLXSW_PCI_CIR_BASE + 0x10) +#define MLXSW_PCI_CIR_TOKEN (MLXSW_PCI_CIR_BASE + 0x14) +#define MLXSW_PCI_CIR_CTRL (MLXSW_PCI_CIR_BASE + 0x18) +#define MLXSW_PCI_CIR_CTRL_GO_BIT BIT(23) +#define MLXSW_PCI_CIR_CTRL_EVREQ_BIT BIT(22) +#define MLXSW_PCI_CIR_CTRL_OPCODE_MOD_SHIFT 12 +#define MLXSW_PCI_CIR_CTRL_STATUS_SHIFT 24 +#define MLXSW_PCI_CIR_TIMEOUT_MSECS 1000 + +#define MLXSW_PCI_SW_RESET 0xF0010 +#define MLXSW_PCI_SW_RESET_RST_BIT BIT(0) +#define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS 5000 + +#define MLXSW_PCI_DOORBELL_SDQ_OFFSET 0x000 +#define MLXSW_PCI_DOORBELL_RDQ_OFFSET 0x200 +#define MLXSW_PCI_DOORBELL_CQ_OFFSET 0x400 +#define MLXSW_PCI_DOORBELL_EQ_OFFSET 0x600 +#define MLXSW_PCI_DOORBELL_ARM_CQ_OFFSET 0x800 +#define MLXSW_PCI_DOORBELL_ARM_EQ_OFFSET 0xA00 + +#define MLXSW_PCI_DOORBELL(offset, type_offset, num) \ + ((offset) + (type_offset) + (num) * 4) + +#define MLXSW_PCI_RDQS_COUNT 24 +#define MLXSW_PCI_SDQS_COUNT 24 +#define MLXSW_PCI_CQS_COUNT (MLXSW_PCI_RDQS_COUNT + MLXSW_PCI_SDQS_COUNT) +#define MLXSW_PCI_EQS_COUNT 2 +#define MLXSW_PCI_EQ_ASYNC_NUM 0 +#define MLXSW_PCI_EQ_COMP_NUM 1 + +#define MLXSW_PCI_AQ_PAGES 8 +#define MLXSW_PCI_AQ_SIZE (MLXSW_PCI_PAGE_SIZE * MLXSW_PCI_AQ_PAGES) +#define MLXSW_PCI_WQE_SIZE 32 /* 32 bytes per element */ +#define MLXSW_PCI_CQE_SIZE 16 /* 16 bytes per element */ +#define MLXSW_PCI_EQE_SIZE 16 /* 16 bytes per element */ +#define MLXSW_PCI_WQE_COUNT (MLXSW_PCI_AQ_SIZE / MLXSW_PCI_WQE_SIZE) +#define MLXSW_PCI_CQE_COUNT (MLXSW_PCI_AQ_SIZE / MLXSW_PCI_CQE_SIZE) +#define MLXSW_PCI_EQE_COUNT (MLXSW_PCI_AQ_SIZE / MLXSW_PCI_EQE_SIZE) +#define MLXSW_PCI_EQE_UPDATE_COUNT 0x80 + +#define MLXSW_PCI_WQE_SG_ENTRIES 3 +#define MLXSW_PCI_WQE_TYPE_ETHERNET 0xA + +/* pci_wqe_c + * If set it indicates that a completion should be reported upon + * execution of this descriptor. + */ +MLXSW_ITEM32(pci, wqe, c, 0x00, 31, 1); + +/* pci_wqe_lp + * Local Processing, set if packet should be processed by the local + * switch hardware: + * For Ethernet EMAD (Direct Route and non Direct Route) - + * must be set if packet destination is local device + * For InfiniBand CTL - must be set if packet destination is local device + * Otherwise it must be clear + * Local Process packets must not exceed the size of 2K (including payload + * and headers). + */ +MLXSW_ITEM32(pci, wqe, lp, 0x00, 30, 1); + +/* pci_wqe_type + * Packet type. + */ +MLXSW_ITEM32(pci, wqe, type, 0x00, 23, 4); + +/* pci_wqe_byte_count + * Size of i-th scatter/gather entry, 0 if entry is unused. + */ +MLXSW_ITEM16_INDEXED(pci, wqe, byte_count, 0x02, 0, 14, 0x02, 0x00, false); + +/* pci_wqe_address + * Physical address of i-th scatter/gather entry. + * Gather Entries must be 2Byte aligned. + */ +MLXSW_ITEM64_INDEXED(pci, wqe, address, 0x08, 0, 64, 0x8, 0x0, false); + +/* pci_cqe_lag + * Packet arrives from a port which is a LAG + */ +MLXSW_ITEM32(pci, cqe, lag, 0x00, 23, 1); + +/* pci_cqe_system_port + * When lag=0: System port on which the packet was received + * When lag=1: + * bits [15:4] LAG ID on which the packet was received + * bits [3:0] sub_port on which the packet was received + */ +MLXSW_ITEM32(pci, cqe, system_port, 0x00, 0, 16); + +/* pci_cqe_wqe_counter + * WQE count of the WQEs completed on the associated dqn + */ +MLXSW_ITEM32(pci, cqe, wqe_counter, 0x04, 16, 16); + +/* pci_cqe_byte_count + * Byte count of received packets including additional two + * Reserved Bytes that are append to the end of the frame. + * Reserved for Send CQE. + */ +MLXSW_ITEM32(pci, cqe, byte_count, 0x04, 0, 14); + +/* pci_cqe_trap_id + * Trap ID that captured the packet. + */ +MLXSW_ITEM32(pci, cqe, trap_id, 0x08, 0, 8); + +/* pci_cqe_e + * CQE with Error. + */ +MLXSW_ITEM32(pci, cqe, e, 0x0C, 7, 1); + +/* pci_cqe_sr + * 1 - Send Queue + * 0 - Receive Queue + */ +MLXSW_ITEM32(pci, cqe, sr, 0x0C, 6, 1); + +/* pci_cqe_dqn + * Descriptor Queue (DQ) Number. + */ +MLXSW_ITEM32(pci, cqe, dqn, 0x0C, 1, 5); + +/* pci_cqe_owner + * Ownership bit. + */ +MLXSW_ITEM32(pci, cqe, owner, 0x0C, 0, 1); + +/* pci_eqe_event_type + * Event type. + */ +MLXSW_ITEM32(pci, eqe, event_type, 0x0C, 24, 8); +#define MLXSW_PCI_EQE_EVENT_TYPE_COMP 0x00 +#define MLXSW_PCI_EQE_EVENT_TYPE_CMD 0x0A + +/* pci_eqe_event_sub_type + * Event type. + */ +MLXSW_ITEM32(pci, eqe, event_sub_type, 0x0C, 16, 8); + +/* pci_eqe_cqn + * Completion Queue that triggeret this EQE. + */ +MLXSW_ITEM32(pci, eqe, cqn, 0x0C, 8, 7); + +/* pci_eqe_owner + * Ownership bit. + */ +MLXSW_ITEM32(pci, eqe, owner, 0x0C, 0, 1); + +/* pci_eqe_cmd_token + * Command completion event - token + */ +MLXSW_ITEM32(pci, eqe, cmd_token, 0x08, 16, 16); + +/* pci_eqe_cmd_status + * Command completion event - status + */ +MLXSW_ITEM32(pci, eqe, cmd_status, 0x08, 0, 8); + +/* pci_eqe_cmd_out_param_h + * Command completion event - output parameter - higher part + */ +MLXSW_ITEM32(pci, eqe, cmd_out_param_h, 0x0C, 0, 32); + +/* pci_eqe_cmd_out_param_l + * Command completion event - output parameter - lower part + */ +MLXSW_ITEM32(pci, eqe, cmd_out_param_l, 0x10, 0, 32); + +#endif -- cgit v1.3-6-gb490 From 4ec14b7634b298186f18f65d959354dc3c60e02c Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 29 Jul 2015 23:33:48 +0200 Subject: mlxsw: Add interface to access registers and process events Ethernet Management Datagrams (EMADs) are Ethernet packets sent between the host and the device in order to configure the available device registers. Another use case is notifications sent from the device to the host, letting it know about certain events, such as port up / down. Add the ability to construct EMADs with provisions to construct and parse the registers' payloads. Implement EMAD transaction layer which is responsible for the reliable transmission of EMADs. Also, add an infrastructure used by the switch driver to register for particular events generated by the device. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: Elad Raz Reviewed-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 736 ++++++++++++++++ drivers/net/ethernet/mellanox/mlxsw/core.h | 21 + drivers/net/ethernet/mellanox/mlxsw/emad.h | 127 +++ drivers/net/ethernet/mellanox/mlxsw/port.h | 19 + drivers/net/ethernet/mellanox/mlxsw/reg.h | 1289 ++++++++++++++++++++++++++++ 5 files changed, 2192 insertions(+) create mode 100644 drivers/net/ethernet/mellanox/mlxsw/emad.h create mode 100644 drivers/net/ethernet/mellanox/mlxsw/reg.h (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index a4bb94bf7a44..ad66ae44a0d7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -44,12 +44,27 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "core.h" #include "item.h" #include "cmd.h" #include "port.h" #include "trap.h" +#include "emad.h" +#include "reg.h" static LIST_HEAD(mlxsw_core_driver_list); static DEFINE_SPINLOCK(mlxsw_core_driver_list_lock); @@ -76,6 +91,15 @@ struct mlxsw_core { void *bus_priv; const struct mlxsw_bus_info *bus_info; struct list_head rx_listener_list; + struct list_head event_listener_list; + struct { + struct sk_buff *resp_skb; + u64 tid; + wait_queue_head_t wait; + bool trans_active; + struct mutex lock; /* One EMAD transaction at a time. */ + bool use_emad; + } emad; struct mlxsw_core_pcpu_stats __percpu *pcpu_stats; struct dentry *dbg_dir; struct { @@ -92,6 +116,473 @@ struct mlxsw_rx_listener_item { void *priv; }; +struct mlxsw_event_listener_item { + struct list_head list; + struct mlxsw_event_listener el; + void *priv; +}; + +/****************** + * EMAD processing + ******************/ + +/* emad_eth_hdr_dmac + * Destination MAC in EMAD's Ethernet header. + * Must be set to 01:02:c9:00:00:01 + */ +MLXSW_ITEM_BUF(emad, eth_hdr, dmac, 0x00, 6); + +/* emad_eth_hdr_smac + * Source MAC in EMAD's Ethernet header. + * Must be set to 00:02:c9:01:02:03 + */ +MLXSW_ITEM_BUF(emad, eth_hdr, smac, 0x06, 6); + +/* emad_eth_hdr_ethertype + * Ethertype in EMAD's Ethernet header. + * Must be set to 0x8932 + */ +MLXSW_ITEM32(emad, eth_hdr, ethertype, 0x0C, 16, 16); + +/* emad_eth_hdr_mlx_proto + * Mellanox protocol. + * Must be set to 0x0. + */ +MLXSW_ITEM32(emad, eth_hdr, mlx_proto, 0x0C, 8, 8); + +/* emad_eth_hdr_ver + * Mellanox protocol version. + * Must be set to 0x0. + */ +MLXSW_ITEM32(emad, eth_hdr, ver, 0x0C, 4, 4); + +/* emad_op_tlv_type + * Type of the TLV. + * Must be set to 0x1 (operation TLV). + */ +MLXSW_ITEM32(emad, op_tlv, type, 0x00, 27, 5); + +/* emad_op_tlv_len + * Length of the operation TLV in u32. + * Must be set to 0x4. + */ +MLXSW_ITEM32(emad, op_tlv, len, 0x00, 16, 11); + +/* emad_op_tlv_dr + * Direct route bit. Setting to 1 indicates the EMAD is a direct route + * EMAD. DR TLV must follow. + * + * Note: Currently not supported and must not be set. + */ +MLXSW_ITEM32(emad, op_tlv, dr, 0x00, 15, 1); + +/* emad_op_tlv_status + * Returned status in case of EMAD response. Must be set to 0 in case + * of EMAD request. + * 0x0 - success + * 0x1 - device is busy. Requester should retry + * 0x2 - Mellanox protocol version not supported + * 0x3 - unknown TLV + * 0x4 - register not supported + * 0x5 - operation class not supported + * 0x6 - EMAD method not supported + * 0x7 - bad parameter (e.g. port out of range) + * 0x8 - resource not available + * 0x9 - message receipt acknowledgment. Requester should retry + * 0x70 - internal error + */ +MLXSW_ITEM32(emad, op_tlv, status, 0x00, 8, 7); + +/* emad_op_tlv_register_id + * Register ID of register within register TLV. + */ +MLXSW_ITEM32(emad, op_tlv, register_id, 0x04, 16, 16); + +/* emad_op_tlv_r + * Response bit. Setting to 1 indicates Response, otherwise request. + */ +MLXSW_ITEM32(emad, op_tlv, r, 0x04, 15, 1); + +/* emad_op_tlv_method + * EMAD method type. + * 0x1 - query + * 0x2 - write + * 0x3 - send (currently not supported) + * 0x4 - event + */ +MLXSW_ITEM32(emad, op_tlv, method, 0x04, 8, 7); + +/* emad_op_tlv_class + * EMAD operation class. Must be set to 0x1 (REG_ACCESS). + */ +MLXSW_ITEM32(emad, op_tlv, class, 0x04, 0, 8); + +/* emad_op_tlv_tid + * EMAD transaction ID. Used for pairing request and response EMADs. + */ +MLXSW_ITEM64(emad, op_tlv, tid, 0x08, 0, 64); + +/* emad_reg_tlv_type + * Type of the TLV. + * Must be set to 0x3 (register TLV). + */ +MLXSW_ITEM32(emad, reg_tlv, type, 0x00, 27, 5); + +/* emad_reg_tlv_len + * Length of the operation TLV in u32. + */ +MLXSW_ITEM32(emad, reg_tlv, len, 0x00, 16, 11); + +/* emad_end_tlv_type + * Type of the TLV. + * Must be set to 0x0 (end TLV). + */ +MLXSW_ITEM32(emad, end_tlv, type, 0x00, 27, 5); + +/* emad_end_tlv_len + * Length of the end TLV in u32. + * Must be set to 1. + */ +MLXSW_ITEM32(emad, end_tlv, len, 0x00, 16, 11); + +enum mlxsw_core_reg_access_type { + MLXSW_CORE_REG_ACCESS_TYPE_QUERY, + MLXSW_CORE_REG_ACCESS_TYPE_WRITE, +}; + +static inline const char * +mlxsw_core_reg_access_type_str(enum mlxsw_core_reg_access_type type) +{ + switch (type) { + case MLXSW_CORE_REG_ACCESS_TYPE_QUERY: + return "query"; + case MLXSW_CORE_REG_ACCESS_TYPE_WRITE: + return "write"; + } + BUG(); +} + +static void mlxsw_emad_pack_end_tlv(char *end_tlv) +{ + mlxsw_emad_end_tlv_type_set(end_tlv, MLXSW_EMAD_TLV_TYPE_END); + mlxsw_emad_end_tlv_len_set(end_tlv, MLXSW_EMAD_END_TLV_LEN); +} + +static void mlxsw_emad_pack_reg_tlv(char *reg_tlv, + const struct mlxsw_reg_info *reg, + char *payload) +{ + mlxsw_emad_reg_tlv_type_set(reg_tlv, MLXSW_EMAD_TLV_TYPE_REG); + mlxsw_emad_reg_tlv_len_set(reg_tlv, reg->len / sizeof(u32) + 1); + memcpy(reg_tlv + sizeof(u32), payload, reg->len); +} + +static void mlxsw_emad_pack_op_tlv(char *op_tlv, + const struct mlxsw_reg_info *reg, + enum mlxsw_core_reg_access_type type, + struct mlxsw_core *mlxsw_core) +{ + mlxsw_emad_op_tlv_type_set(op_tlv, MLXSW_EMAD_TLV_TYPE_OP); + mlxsw_emad_op_tlv_len_set(op_tlv, MLXSW_EMAD_OP_TLV_LEN); + mlxsw_emad_op_tlv_dr_set(op_tlv, 0); + mlxsw_emad_op_tlv_status_set(op_tlv, 0); + mlxsw_emad_op_tlv_register_id_set(op_tlv, reg->id); + mlxsw_emad_op_tlv_r_set(op_tlv, MLXSW_EMAD_OP_TLV_REQUEST); + if (MLXSW_CORE_REG_ACCESS_TYPE_QUERY == type) + mlxsw_emad_op_tlv_method_set(op_tlv, + MLXSW_EMAD_OP_TLV_METHOD_QUERY); + else + mlxsw_emad_op_tlv_method_set(op_tlv, + MLXSW_EMAD_OP_TLV_METHOD_WRITE); + mlxsw_emad_op_tlv_class_set(op_tlv, + MLXSW_EMAD_OP_TLV_CLASS_REG_ACCESS); + mlxsw_emad_op_tlv_tid_set(op_tlv, mlxsw_core->emad.tid); +} + +static int mlxsw_emad_construct_eth_hdr(struct sk_buff *skb) +{ + char *eth_hdr = skb_push(skb, MLXSW_EMAD_ETH_HDR_LEN); + + mlxsw_emad_eth_hdr_dmac_memcpy_to(eth_hdr, MLXSW_EMAD_EH_DMAC); + mlxsw_emad_eth_hdr_smac_memcpy_to(eth_hdr, MLXSW_EMAD_EH_SMAC); + mlxsw_emad_eth_hdr_ethertype_set(eth_hdr, MLXSW_EMAD_EH_ETHERTYPE); + mlxsw_emad_eth_hdr_mlx_proto_set(eth_hdr, MLXSW_EMAD_EH_MLX_PROTO); + mlxsw_emad_eth_hdr_ver_set(eth_hdr, MLXSW_EMAD_EH_PROTO_VERSION); + + skb_reset_mac_header(skb); + + return 0; +} + +static void mlxsw_emad_construct(struct sk_buff *skb, + const struct mlxsw_reg_info *reg, + char *payload, + enum mlxsw_core_reg_access_type type, + struct mlxsw_core *mlxsw_core) +{ + char *buf; + + buf = skb_push(skb, MLXSW_EMAD_END_TLV_LEN * sizeof(u32)); + mlxsw_emad_pack_end_tlv(buf); + + buf = skb_push(skb, reg->len + sizeof(u32)); + mlxsw_emad_pack_reg_tlv(buf, reg, payload); + + buf = skb_push(skb, MLXSW_EMAD_OP_TLV_LEN * sizeof(u32)); + mlxsw_emad_pack_op_tlv(buf, reg, type, mlxsw_core); + + mlxsw_emad_construct_eth_hdr(skb); +} + +static char *mlxsw_emad_op_tlv(const struct sk_buff *skb) +{ + return ((char *) (skb->data + MLXSW_EMAD_ETH_HDR_LEN)); +} + +static char *mlxsw_emad_reg_tlv(const struct sk_buff *skb) +{ + return ((char *) (skb->data + MLXSW_EMAD_ETH_HDR_LEN + + MLXSW_EMAD_OP_TLV_LEN * sizeof(u32))); +} + +static char *mlxsw_emad_reg_payload(const char *op_tlv) +{ + return ((char *) (op_tlv + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32))); +} + +static u64 mlxsw_emad_get_tid(const struct sk_buff *skb) +{ + char *op_tlv; + + op_tlv = mlxsw_emad_op_tlv(skb); + return mlxsw_emad_op_tlv_tid_get(op_tlv); +} + +static bool mlxsw_emad_is_resp(const struct sk_buff *skb) +{ + char *op_tlv; + + op_tlv = mlxsw_emad_op_tlv(skb); + return (MLXSW_EMAD_OP_TLV_RESPONSE == mlxsw_emad_op_tlv_r_get(op_tlv)); +} + +#define MLXSW_EMAD_TIMEOUT_MS 200 + +static int __mlxsw_emad_transmit(struct mlxsw_core *mlxsw_core, + struct sk_buff *skb, + const struct mlxsw_tx_info *tx_info) +{ + int err; + int ret; + + err = mlxsw_core_skb_transmit(mlxsw_core->driver_priv, skb, tx_info); + if (err) { + dev_warn(mlxsw_core->bus_info->dev, "Failed to transmit EMAD (tid=%llx)\n", + mlxsw_core->emad.tid); + dev_kfree_skb(skb); + return err; + } + + mlxsw_core->emad.trans_active = true; + ret = wait_event_timeout(mlxsw_core->emad.wait, + !(mlxsw_core->emad.trans_active), + msecs_to_jiffies(MLXSW_EMAD_TIMEOUT_MS)); + if (!ret) { + dev_warn(mlxsw_core->bus_info->dev, "EMAD timed-out (tid=%llx)\n", + mlxsw_core->emad.tid); + mlxsw_core->emad.trans_active = false; + return -EIO; + } + + return 0; +} + +static int mlxsw_emad_process_status(struct mlxsw_core *mlxsw_core, + char *op_tlv) +{ + enum mlxsw_emad_op_tlv_status status; + u64 tid; + + status = mlxsw_emad_op_tlv_status_get(op_tlv); + tid = mlxsw_emad_op_tlv_tid_get(op_tlv); + + switch (status) { + case MLXSW_EMAD_OP_TLV_STATUS_SUCCESS: + return 0; + case MLXSW_EMAD_OP_TLV_STATUS_BUSY: + case MLXSW_EMAD_OP_TLV_STATUS_MESSAGE_RECEIPT_ACK: + dev_warn(mlxsw_core->bus_info->dev, "Reg access status again (tid=%llx,status=%x(%s))\n", + tid, status, mlxsw_emad_op_tlv_status_str(status)); + return -EAGAIN; + case MLXSW_EMAD_OP_TLV_STATUS_VERSION_NOT_SUPPORTED: + case MLXSW_EMAD_OP_TLV_STATUS_UNKNOWN_TLV: + case MLXSW_EMAD_OP_TLV_STATUS_REGISTER_NOT_SUPPORTED: + case MLXSW_EMAD_OP_TLV_STATUS_CLASS_NOT_SUPPORTED: + case MLXSW_EMAD_OP_TLV_STATUS_METHOD_NOT_SUPPORTED: + case MLXSW_EMAD_OP_TLV_STATUS_BAD_PARAMETER: + case MLXSW_EMAD_OP_TLV_STATUS_RESOURCE_NOT_AVAILABLE: + case MLXSW_EMAD_OP_TLV_STATUS_INTERNAL_ERROR: + default: + dev_err(mlxsw_core->bus_info->dev, "Reg access status failed (tid=%llx,status=%x(%s))\n", + tid, status, mlxsw_emad_op_tlv_status_str(status)); + return -EIO; + } +} + +static int mlxsw_emad_process_status_skb(struct mlxsw_core *mlxsw_core, + struct sk_buff *skb) +{ + return mlxsw_emad_process_status(mlxsw_core, mlxsw_emad_op_tlv(skb)); +} + +static int mlxsw_emad_transmit(struct mlxsw_core *mlxsw_core, + struct sk_buff *skb, + const struct mlxsw_tx_info *tx_info) +{ + struct sk_buff *trans_skb; + int n_retry; + int err; + + n_retry = 0; +retry: + /* We copy the EMAD to a new skb, since we might need + * to retransmit it in case of failure. + */ + trans_skb = skb_copy(skb, GFP_KERNEL); + if (!trans_skb) { + err = -ENOMEM; + goto out; + } + + err = __mlxsw_emad_transmit(mlxsw_core, trans_skb, tx_info); + if (!err) { + struct sk_buff *resp_skb = mlxsw_core->emad.resp_skb; + + err = mlxsw_emad_process_status_skb(mlxsw_core, resp_skb); + if (err) + dev_kfree_skb(resp_skb); + if (!err || err != -EAGAIN) + goto out; + } + if (n_retry++ < MLXSW_EMAD_MAX_RETRY) + goto retry; + +out: + dev_kfree_skb(skb); + mlxsw_core->emad.tid++; + return err; +} + +static void mlxsw_emad_rx_listener_func(struct sk_buff *skb, u8 local_port, + void *priv) +{ + struct mlxsw_core *mlxsw_core = priv; + + if (mlxsw_emad_is_resp(skb) && + mlxsw_core->emad.trans_active && + mlxsw_emad_get_tid(skb) == mlxsw_core->emad.tid) { + mlxsw_core->emad.resp_skb = skb; + mlxsw_core->emad.trans_active = false; + wake_up(&mlxsw_core->emad.wait); + } else { + dev_kfree_skb(skb); + } +} + +static const struct mlxsw_rx_listener mlxsw_emad_rx_listener = { + .func = mlxsw_emad_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_ETHEMAD, +}; + +static int mlxsw_emad_traps_set(struct mlxsw_core *mlxsw_core) +{ + char htgt_pl[MLXSW_REG_HTGT_LEN]; + char hpkt_pl[MLXSW_REG_HPKT_LEN]; + int err; + + mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_EMAD); + err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); + if (err) + return err; + + mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_TRAP_TO_CPU, + MLXSW_REG_HTGT_TRAP_GROUP_EMAD, + MLXSW_TRAP_ID_ETHEMAD); + return mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); +} + +static int mlxsw_emad_init(struct mlxsw_core *mlxsw_core) +{ + int err; + + /* Set the upper 32 bits of the transaction ID field to a random + * number. This allows us to discard EMADs addressed to other + * devices. + */ + get_random_bytes(&mlxsw_core->emad.tid, 4); + mlxsw_core->emad.tid = mlxsw_core->emad.tid << 32; + + init_waitqueue_head(&mlxsw_core->emad.wait); + mlxsw_core->emad.trans_active = false; + mutex_init(&mlxsw_core->emad.lock); + + err = mlxsw_core_rx_listener_register(mlxsw_core, + &mlxsw_emad_rx_listener, + mlxsw_core); + if (err) + return err; + + err = mlxsw_emad_traps_set(mlxsw_core); + if (err) + goto err_emad_trap_set; + + mlxsw_core->emad.use_emad = true; + + return 0; + +err_emad_trap_set: + mlxsw_core_rx_listener_unregister(mlxsw_core, + &mlxsw_emad_rx_listener, + mlxsw_core); + return err; +} + +static void mlxsw_emad_fini(struct mlxsw_core *mlxsw_core) +{ + char hpkt_pl[MLXSW_REG_HPKT_LEN]; + + mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_DISCARD, + MLXSW_REG_HTGT_TRAP_GROUP_EMAD, + MLXSW_TRAP_ID_ETHEMAD); + mlxsw_reg_write(mlxsw_core, MLXSW_REG(hpkt), hpkt_pl); + + mlxsw_core_rx_listener_unregister(mlxsw_core, + &mlxsw_emad_rx_listener, + mlxsw_core); +} + +static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core, + u16 reg_len) +{ + struct sk_buff *skb; + u16 emad_len; + + emad_len = (reg_len + sizeof(u32) + MLXSW_EMAD_ETH_HDR_LEN + + (MLXSW_EMAD_OP_TLV_LEN + MLXSW_EMAD_END_TLV_LEN) * + sizeof(u32) + mlxsw_core->driver->txhdr_len); + if (emad_len > MLXSW_EMAD_MAX_FRAME_LEN) + return NULL; + + skb = netdev_alloc_skb(NULL, emad_len); + if (!skb) + return NULL; + memset(skb->data, 0, emad_len); + skb_reserve(skb, emad_len); + + return skb; +} + /***************** * Core functions *****************/ @@ -307,6 +798,7 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, } INIT_LIST_HEAD(&mlxsw_core->rx_listener_list); + INIT_LIST_HEAD(&mlxsw_core->event_listener_list); mlxsw_core->driver = mlxsw_driver; mlxsw_core->bus = mlxsw_bus; mlxsw_core->bus_priv = bus_priv; @@ -318,10 +810,15 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, err = -ENOMEM; goto err_alloc_stats; } + err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile); if (err) goto err_bus_init; + err = mlxsw_emad_init(mlxsw_core); + if (err) + goto err_emad_init; + err = mlxsw_driver->init(mlxsw_core->driver_priv, mlxsw_core, mlxsw_bus_info); if (err) @@ -336,6 +833,8 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, err_debugfs_init: mlxsw_core->driver->fini(mlxsw_core->driver_priv); err_driver_init: + mlxsw_emad_fini(mlxsw_core); +err_emad_init: mlxsw_bus->fini(bus_priv); err_bus_init: free_percpu(mlxsw_core->pcpu_stats); @@ -353,6 +852,7 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core) mlxsw_core_debugfs_fini(mlxsw_core); mlxsw_core->driver->fini(mlxsw_core->driver_priv); + mlxsw_emad_fini(mlxsw_core); mlxsw_core->bus->fini(mlxsw_core->bus_priv); free_percpu(mlxsw_core->pcpu_stats); kfree(mlxsw_core); @@ -433,6 +933,242 @@ void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core, } EXPORT_SYMBOL(mlxsw_core_rx_listener_unregister); +static void mlxsw_core_event_listener_func(struct sk_buff *skb, u8 local_port, + void *priv) +{ + struct mlxsw_event_listener_item *event_listener_item = priv; + struct mlxsw_reg_info reg; + char *payload; + char *op_tlv = mlxsw_emad_op_tlv(skb); + char *reg_tlv = mlxsw_emad_reg_tlv(skb); + + reg.id = mlxsw_emad_op_tlv_register_id_get(op_tlv); + reg.len = (mlxsw_emad_reg_tlv_len_get(reg_tlv) - 1) * sizeof(u32); + payload = mlxsw_emad_reg_payload(op_tlv); + event_listener_item->el.func(®, payload, event_listener_item->priv); + dev_kfree_skb(skb); +} + +static bool __is_event_listener_equal(const struct mlxsw_event_listener *el_a, + const struct mlxsw_event_listener *el_b) +{ + return (el_a->func == el_b->func && + el_a->trap_id == el_b->trap_id); +} + +static struct mlxsw_event_listener_item * +__find_event_listener_item(struct mlxsw_core *mlxsw_core, + const struct mlxsw_event_listener *el, + void *priv) +{ + struct mlxsw_event_listener_item *el_item; + + list_for_each_entry(el_item, &mlxsw_core->event_listener_list, list) { + if (__is_event_listener_equal(&el_item->el, el) && + el_item->priv == priv) + return el_item; + } + return NULL; +} + +int mlxsw_core_event_listener_register(struct mlxsw_core *mlxsw_core, + const struct mlxsw_event_listener *el, + void *priv) +{ + int err; + struct mlxsw_event_listener_item *el_item; + const struct mlxsw_rx_listener rxl = { + .func = mlxsw_core_event_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = el->trap_id, + }; + + el_item = __find_event_listener_item(mlxsw_core, el, priv); + if (el_item) + return -EEXIST; + el_item = kmalloc(sizeof(*el_item), GFP_KERNEL); + if (!el_item) + return -ENOMEM; + el_item->el = *el; + el_item->priv = priv; + + err = mlxsw_core_rx_listener_register(mlxsw_core, &rxl, el_item); + if (err) + goto err_rx_listener_register; + + /* No reason to save item if we did not manage to register an RX + * listener for it. + */ + list_add_rcu(&el_item->list, &mlxsw_core->event_listener_list); + + return 0; + +err_rx_listener_register: + kfree(el_item); + return err; +} +EXPORT_SYMBOL(mlxsw_core_event_listener_register); + +void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core, + const struct mlxsw_event_listener *el, + void *priv) +{ + struct mlxsw_event_listener_item *el_item; + const struct mlxsw_rx_listener rxl = { + .func = mlxsw_core_event_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = el->trap_id, + }; + + el_item = __find_event_listener_item(mlxsw_core, el, priv); + if (!el_item) + return; + mlxsw_core_rx_listener_unregister(mlxsw_core, &rxl, el_item); + list_del(&el_item->list); + kfree(el_item); +} +EXPORT_SYMBOL(mlxsw_core_event_listener_unregister); + +static int mlxsw_core_reg_access_emad(struct mlxsw_core *mlxsw_core, + const struct mlxsw_reg_info *reg, + char *payload, + enum mlxsw_core_reg_access_type type) +{ + int err; + char *op_tlv; + struct sk_buff *skb; + struct mlxsw_tx_info tx_info = { + .local_port = MLXSW_PORT_CPU_PORT, + .is_emad = true, + }; + + skb = mlxsw_emad_alloc(mlxsw_core, reg->len); + if (!skb) + return -ENOMEM; + + mlxsw_emad_construct(skb, reg, payload, type, mlxsw_core); + mlxsw_core->driver->txhdr_construct(skb, &tx_info); + + dev_dbg(mlxsw_core->bus_info->dev, "EMAD send (tid=%llx)\n", + mlxsw_core->emad.tid); + mlxsw_core_buf_dump_dbg(mlxsw_core, skb->data, skb->len); + + err = mlxsw_emad_transmit(mlxsw_core, skb, &tx_info); + if (!err) { + op_tlv = mlxsw_emad_op_tlv(mlxsw_core->emad.resp_skb); + memcpy(payload, mlxsw_emad_reg_payload(op_tlv), + reg->len); + + dev_dbg(mlxsw_core->bus_info->dev, "EMAD recv (tid=%llx)\n", + mlxsw_core->emad.tid - 1); + mlxsw_core_buf_dump_dbg(mlxsw_core, + mlxsw_core->emad.resp_skb->data, + skb->len); + + dev_kfree_skb(mlxsw_core->emad.resp_skb); + } + + return err; +} + +static int mlxsw_core_reg_access_cmd(struct mlxsw_core *mlxsw_core, + const struct mlxsw_reg_info *reg, + char *payload, + enum mlxsw_core_reg_access_type type) +{ + int err, n_retry; + char *in_mbox, *out_mbox, *tmp; + + in_mbox = mlxsw_cmd_mbox_alloc(); + if (!in_mbox) + return -ENOMEM; + + out_mbox = mlxsw_cmd_mbox_alloc(); + if (!out_mbox) { + err = -ENOMEM; + goto free_in_mbox; + } + + mlxsw_emad_pack_op_tlv(in_mbox, reg, type, mlxsw_core); + tmp = in_mbox + MLXSW_EMAD_OP_TLV_LEN * sizeof(u32); + mlxsw_emad_pack_reg_tlv(tmp, reg, payload); + + n_retry = 0; +retry: + err = mlxsw_cmd_access_reg(mlxsw_core, in_mbox, out_mbox); + if (!err) { + err = mlxsw_emad_process_status(mlxsw_core, out_mbox); + if (err == -EAGAIN && n_retry++ < MLXSW_EMAD_MAX_RETRY) + goto retry; + } + + if (!err) + memcpy(payload, mlxsw_emad_reg_payload(out_mbox), + reg->len); + + mlxsw_core->emad.tid++; + mlxsw_cmd_mbox_free(out_mbox); +free_in_mbox: + mlxsw_cmd_mbox_free(in_mbox); + return err; +} + +static int mlxsw_core_reg_access(struct mlxsw_core *mlxsw_core, + const struct mlxsw_reg_info *reg, + char *payload, + enum mlxsw_core_reg_access_type type) +{ + u64 cur_tid; + int err; + + if (mutex_lock_interruptible(&mlxsw_core->emad.lock)) { + dev_err(mlxsw_core->bus_info->dev, "Reg access interrupted (reg_id=%x(%s),type=%s)\n", + reg->id, mlxsw_reg_id_str(reg->id), + mlxsw_core_reg_access_type_str(type)); + return -EINTR; + } + + cur_tid = mlxsw_core->emad.tid; + dev_dbg(mlxsw_core->bus_info->dev, "Reg access (tid=%llx,reg_id=%x(%s),type=%s)\n", + cur_tid, reg->id, mlxsw_reg_id_str(reg->id), + mlxsw_core_reg_access_type_str(type)); + + /* During initialization EMAD interface is not available to us, + * so we default to command interface. We switch to EMAD interface + * after setting the appropriate traps. + */ + if (!mlxsw_core->emad.use_emad) + err = mlxsw_core_reg_access_cmd(mlxsw_core, reg, + payload, type); + else + err = mlxsw_core_reg_access_emad(mlxsw_core, reg, + payload, type); + + if (err) + dev_err(mlxsw_core->bus_info->dev, "Reg access failed (tid=%llx,reg_id=%x(%s),type=%s)\n", + cur_tid, reg->id, mlxsw_reg_id_str(reg->id), + mlxsw_core_reg_access_type_str(type)); + + mutex_unlock(&mlxsw_core->emad.lock); + return err; +} + +int mlxsw_reg_query(struct mlxsw_core *mlxsw_core, + const struct mlxsw_reg_info *reg, char *payload) +{ + return mlxsw_core_reg_access(mlxsw_core, reg, payload, + MLXSW_CORE_REG_ACCESS_TYPE_QUERY); +} +EXPORT_SYMBOL(mlxsw_reg_query); + +int mlxsw_reg_write(struct mlxsw_core *mlxsw_core, + const struct mlxsw_reg_info *reg, char *payload) +{ + return mlxsw_core_reg_access(mlxsw_core, reg, payload, + MLXSW_CORE_REG_ACCESS_TYPE_WRITE); +} +EXPORT_SYMBOL(mlxsw_reg_write); + void mlxsw_core_skb_receive(struct mlxsw_core *mlxsw_core, struct sk_buff *skb, struct mlxsw_rx_info *rx_info) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index f4ab36a0235e..53ef20ab06cb 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -44,6 +44,9 @@ #include #include +#include "trap.h" +#include "reg.h" + #include "cmd.h" #define MLXSW_MODULE_ALIAS_PREFIX "mlxsw-driver-" @@ -77,6 +80,12 @@ struct mlxsw_rx_listener { u16 trap_id; }; +struct mlxsw_event_listener { + void (*func)(const struct mlxsw_reg_info *reg, + char *payload, void *priv); + enum mlxsw_event_trap_id trap_id; +}; + int mlxsw_core_rx_listener_register(struct mlxsw_core *mlxsw_core, const struct mlxsw_rx_listener *rxl, void *priv); @@ -84,6 +93,18 @@ void mlxsw_core_rx_listener_unregister(struct mlxsw_core *mlxsw_core, const struct mlxsw_rx_listener *rxl, void *priv); +int mlxsw_core_event_listener_register(struct mlxsw_core *mlxsw_core, + const struct mlxsw_event_listener *el, + void *priv); +void mlxsw_core_event_listener_unregister(struct mlxsw_core *mlxsw_core, + const struct mlxsw_event_listener *el, + void *priv); + +int mlxsw_reg_query(struct mlxsw_core *mlxsw_core, + const struct mlxsw_reg_info *reg, char *payload); +int mlxsw_reg_write(struct mlxsw_core *mlxsw_core, + const struct mlxsw_reg_info *reg, char *payload); + struct mlxsw_rx_info { u16 sys_port; int trap_id; diff --git a/drivers/net/ethernet/mellanox/mlxsw/emad.h b/drivers/net/ethernet/mellanox/mlxsw/emad.h new file mode 100644 index 000000000000..97b6bb5d9185 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/emad.h @@ -0,0 +1,127 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/emad.h + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Ido Schimmel + * Copyright (c) 2015 Jiri Pirko + * + * 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 _MLXSW_EMAD_H +#define _MLXSW_EMAD_H + +#define MLXSW_EMAD_MAX_FRAME_LEN 1518 /* Length in u8 */ +#define MLXSW_EMAD_MAX_RETRY 5 + +/* EMAD Ethernet header */ +#define MLXSW_EMAD_ETH_HDR_LEN 0x10 /* Length in u8 */ +#define MLXSW_EMAD_EH_DMAC "\x01\x02\xc9\x00\x00\x01" +#define MLXSW_EMAD_EH_SMAC "\x00\x02\xc9\x01\x02\x03" +#define MLXSW_EMAD_EH_ETHERTYPE 0x8932 +#define MLXSW_EMAD_EH_MLX_PROTO 0 +#define MLXSW_EMAD_EH_PROTO_VERSION 0 + +/* EMAD TLV Types */ +enum { + MLXSW_EMAD_TLV_TYPE_END, + MLXSW_EMAD_TLV_TYPE_OP, + MLXSW_EMAD_TLV_TYPE_DR, + MLXSW_EMAD_TLV_TYPE_REG, + MLXSW_EMAD_TLV_TYPE_USERDATA, + MLXSW_EMAD_TLV_TYPE_OOBETH, +}; + +/* OP TLV */ +#define MLXSW_EMAD_OP_TLV_LEN 4 /* Length in u32 */ + +enum { + MLXSW_EMAD_OP_TLV_CLASS_REG_ACCESS = 1, + MLXSW_EMAD_OP_TLV_CLASS_IPC = 2, +}; + +enum mlxsw_emad_op_tlv_status { + MLXSW_EMAD_OP_TLV_STATUS_SUCCESS, + MLXSW_EMAD_OP_TLV_STATUS_BUSY, + MLXSW_EMAD_OP_TLV_STATUS_VERSION_NOT_SUPPORTED, + MLXSW_EMAD_OP_TLV_STATUS_UNKNOWN_TLV, + MLXSW_EMAD_OP_TLV_STATUS_REGISTER_NOT_SUPPORTED, + MLXSW_EMAD_OP_TLV_STATUS_CLASS_NOT_SUPPORTED, + MLXSW_EMAD_OP_TLV_STATUS_METHOD_NOT_SUPPORTED, + MLXSW_EMAD_OP_TLV_STATUS_BAD_PARAMETER, + MLXSW_EMAD_OP_TLV_STATUS_RESOURCE_NOT_AVAILABLE, + MLXSW_EMAD_OP_TLV_STATUS_MESSAGE_RECEIPT_ACK, + MLXSW_EMAD_OP_TLV_STATUS_INTERNAL_ERROR = 0x70, +}; + +static inline char *mlxsw_emad_op_tlv_status_str(u8 status) +{ + switch (status) { + case MLXSW_EMAD_OP_TLV_STATUS_SUCCESS: + return "operation performed"; + case MLXSW_EMAD_OP_TLV_STATUS_BUSY: + return "device is busy"; + case MLXSW_EMAD_OP_TLV_STATUS_VERSION_NOT_SUPPORTED: + return "version not supported"; + case MLXSW_EMAD_OP_TLV_STATUS_UNKNOWN_TLV: + return "unknown TLV"; + case MLXSW_EMAD_OP_TLV_STATUS_REGISTER_NOT_SUPPORTED: + return "register not supported"; + case MLXSW_EMAD_OP_TLV_STATUS_CLASS_NOT_SUPPORTED: + return "class not supported"; + case MLXSW_EMAD_OP_TLV_STATUS_METHOD_NOT_SUPPORTED: + return "method not supported"; + case MLXSW_EMAD_OP_TLV_STATUS_BAD_PARAMETER: + return "bad parameter"; + case MLXSW_EMAD_OP_TLV_STATUS_RESOURCE_NOT_AVAILABLE: + return "resource not available"; + case MLXSW_EMAD_OP_TLV_STATUS_MESSAGE_RECEIPT_ACK: + return "acknowledged. retransmit"; + case MLXSW_EMAD_OP_TLV_STATUS_INTERNAL_ERROR: + return "internal error"; + default: + return "*UNKNOWN*"; + } +} + +enum { + MLXSW_EMAD_OP_TLV_REQUEST, + MLXSW_EMAD_OP_TLV_RESPONSE +}; + +enum { + MLXSW_EMAD_OP_TLV_METHOD_QUERY = 1, + MLXSW_EMAD_OP_TLV_METHOD_WRITE = 2, + MLXSW_EMAD_OP_TLV_METHOD_SEND = 3, + MLXSW_EMAD_OP_TLV_METHOD_EVENT = 5, +}; + +/* END TLV */ +#define MLXSW_EMAD_END_TLV_LEN 1 /* Length in u32 */ + +#endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/port.h b/drivers/net/ethernet/mellanox/mlxsw/port.h index 1b43c7d58ac5..4606966af980 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/port.h +++ b/drivers/net/ethernet/mellanox/mlxsw/port.h @@ -42,6 +42,12 @@ #define MLXSW_PORT_DEFAULT_VID 1 +#define MLXSW_PORT_SWID_DISABLED_PORT 255 +#define MLXSW_PORT_SWID_ALL_SWIDS 254 +#define MLXSW_PORT_SWID_TYPE_ETH 2 + +#define MLXSW_PORT_MID 0xd000 + #define MLXSW_PORT_MAX_PHY_PORTS 0x40 #define MLXSW_PORT_MAX_PORTS MLXSW_PORT_MAX_PHY_PORTS @@ -49,4 +55,17 @@ #define MLXSW_PORT_DONT_CARE (MLXSW_PORT_MAX_PORTS) +enum mlxsw_port_admin_status { + MLXSW_PORT_ADMIN_STATUS_UP = 1, + MLXSW_PORT_ADMIN_STATUS_DOWN = 2, + MLXSW_PORT_ADMIN_STATUS_UP_ONCE = 3, + MLXSW_PORT_ADMIN_STATUS_DISABLED = 4, +}; + +enum mlxsw_reg_pude_oper_status { + MLXSW_PORT_OPER_STATUS_UP = 1, + MLXSW_PORT_OPER_STATUS_DOWN = 2, + MLXSW_PORT_OPER_STATUS_FAILURE = 4, /* Can be set to up again. */ +}; + #endif /* _MLXSW_PORT_H */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h new file mode 100644 index 000000000000..b5a72f8e78b1 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -0,0 +1,1289 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/reg.h + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Ido Schimmel + * Copyright (c) 2015 Elad Raz + * Copyright (c) 2015 Jiri Pirko + * + * 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 _MLXSW_REG_H +#define _MLXSW_REG_H + +#include +#include +#include + +#include "item.h" +#include "port.h" + +struct mlxsw_reg_info { + u16 id; + u16 len; /* In u8 */ +}; + +#define MLXSW_REG(type) (&mlxsw_reg_##type) +#define MLXSW_REG_LEN(type) MLXSW_REG(type)->len +#define MLXSW_REG_ZERO(type, payload) memset(payload, 0, MLXSW_REG(type)->len) + +/* SGCR - Switch General Configuration Register + * -------------------------------------------- + * This register is used for configuration of the switch capabilities. + */ +#define MLXSW_REG_SGCR_ID 0x2000 +#define MLXSW_REG_SGCR_LEN 0x10 + +static const struct mlxsw_reg_info mlxsw_reg_sgcr = { + .id = MLXSW_REG_SGCR_ID, + .len = MLXSW_REG_SGCR_LEN, +}; + +/* reg_sgcr_llb + * Link Local Broadcast (Default=0) + * When set, all Link Local packets (224.0.0.X) will be treated as broadcast + * packets and ignore the IGMP snooping entries. + * Access: RW + */ +MLXSW_ITEM32(reg, sgcr, llb, 0x04, 0, 1); + +static inline void mlxsw_reg_sgcr_pack(char *payload, bool llb) +{ + MLXSW_REG_ZERO(sgcr, payload); + mlxsw_reg_sgcr_llb_set(payload, !!llb); +} + +/* SPAD - Switch Physical Address Register + * --------------------------------------- + * The SPAD register configures the switch physical MAC address. + */ +#define MLXSW_REG_SPAD_ID 0x2002 +#define MLXSW_REG_SPAD_LEN 0x10 + +static const struct mlxsw_reg_info mlxsw_reg_spad = { + .id = MLXSW_REG_SPAD_ID, + .len = MLXSW_REG_SPAD_LEN, +}; + +/* reg_spad_base_mac + * Base MAC address for the switch partitions. + * Per switch partition MAC address is equal to: + * base_mac + swid + * Access: RW + */ +MLXSW_ITEM_BUF(reg, spad, base_mac, 0x02, 6); + +/* SMID - Switch Multicast ID + * -------------------------- + * In multi-chip configuration, each device should maintain mapping between + * Multicast ID (MID) into a list of local ports. This mapping is used in all + * the devices other than the ingress device, and is implemented as part of the + * FDB. The MID record maps from a MID, which is a unique identi- fier of the + * multicast group within the stacking domain, into a list of local ports into + * which the packet is replicated. + */ +#define MLXSW_REG_SMID_ID 0x2007 +#define MLXSW_REG_SMID_LEN 0x420 + +static const struct mlxsw_reg_info mlxsw_reg_smid = { + .id = MLXSW_REG_SMID_ID, + .len = MLXSW_REG_SMID_LEN, +}; + +/* reg_smid_swid + * Switch partition ID. + * Access: Index + */ +MLXSW_ITEM32(reg, smid, swid, 0x00, 24, 8); + +/* reg_smid_mid + * Multicast identifier - global identifier that represents the multicast group + * across all devices + * Access: Index + */ +MLXSW_ITEM32(reg, smid, mid, 0x00, 0, 16); + +/* reg_smid_port + * Local port memebership (1 bit per port). + * Access: RW + */ +MLXSW_ITEM_BIT_ARRAY(reg, smid, port, 0x20, 0x20, 1); + +/* reg_smid_port_mask + * Local port mask (1 bit per port). + * Access: W + */ +MLXSW_ITEM_BIT_ARRAY(reg, smid, port_mask, 0x220, 0x20, 1); + +static inline void mlxsw_reg_smid_pack(char *payload, u16 mid) +{ + MLXSW_REG_ZERO(smid, payload); + mlxsw_reg_smid_swid_set(payload, 0); + mlxsw_reg_smid_mid_set(payload, mid); + mlxsw_reg_smid_port_set(payload, MLXSW_PORT_CPU_PORT, 1); + mlxsw_reg_smid_port_mask_set(payload, MLXSW_PORT_CPU_PORT, 1); +} + +/* SPMS - Switch Port MSTP/RSTP State Register + * ------------------------------------------- + * Configures the spanning tree state of a physical port. + */ +#define MLXSW_REG_SPMS_ID 0x200d +#define MLXSW_REG_SPMS_LEN 0x404 + +static const struct mlxsw_reg_info mlxsw_reg_spms = { + .id = MLXSW_REG_SPMS_ID, + .len = MLXSW_REG_SPMS_LEN, +}; + +/* reg_spms_local_port + * Local port number. + * Access: Index + */ +MLXSW_ITEM32(reg, spms, local_port, 0x00, 16, 8); + +enum mlxsw_reg_spms_state { + MLXSW_REG_SPMS_STATE_NO_CHANGE, + MLXSW_REG_SPMS_STATE_DISCARDING, + MLXSW_REG_SPMS_STATE_LEARNING, + MLXSW_REG_SPMS_STATE_FORWARDING, +}; + +/* reg_spms_state + * Spanning tree state of each VLAN ID (VID) of the local port. + * 0 - Do not change spanning tree state (used only when writing). + * 1 - Discarding. No learning or forwarding to/from this port (default). + * 2 - Learning. Port is learning, but not forwarding. + * 3 - Forwarding. Port is learning and forwarding. + * Access: RW + */ +MLXSW_ITEM_BIT_ARRAY(reg, spms, state, 0x04, 0x400, 2); + +static inline void mlxsw_reg_spms_pack(char *payload, u8 local_port, u16 vid, + enum mlxsw_reg_spms_state state) +{ + MLXSW_REG_ZERO(spms, payload); + mlxsw_reg_spms_local_port_set(payload, local_port); + mlxsw_reg_spms_state_set(payload, vid, state); +} + +/* SFGC - Switch Flooding Group Configuration + * ------------------------------------------ + * The following register controls the association of flooding tables and MIDs + * to packet types used for flooding. + */ +#define MLXSW_REG_SFGC_ID 0x2011 +#define MLXSW_REG_SFGC_LEN 0x10 + +static const struct mlxsw_reg_info mlxsw_reg_sfgc = { + .id = MLXSW_REG_SFGC_ID, + .len = MLXSW_REG_SFGC_LEN, +}; + +enum mlxsw_reg_sfgc_type { + MLXSW_REG_SFGC_TYPE_BROADCAST = 0, + MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST = 1, + MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4 = 2, + MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6 = 3, + MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP = 5, + MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL = 6, + MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST = 7, +}; + +/* reg_sfgc_type + * The traffic type to reach the flooding table. + * Access: Index + */ +MLXSW_ITEM32(reg, sfgc, type, 0x00, 0, 4); + +enum mlxsw_reg_sfgc_bridge_type { + MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID = 0, + MLXSW_REG_SFGC_BRIDGE_TYPE_VFID = 1, +}; + +/* reg_sfgc_bridge_type + * Access: Index + * + * Note: SwitchX-2 only supports 802.1Q mode. + */ +MLXSW_ITEM32(reg, sfgc, bridge_type, 0x04, 24, 3); + +enum mlxsw_flood_table_type { + MLXSW_REG_SFGC_TABLE_TYPE_VID = 1, + MLXSW_REG_SFGC_TABLE_TYPE_SINGLE = 2, + MLXSW_REG_SFGC_TABLE_TYPE_ANY = 0, + MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST = 3, + MLXSW_REG_SFGC_TABLE_TYPE_FID = 4, +}; + +/* reg_sfgc_table_type + * See mlxsw_flood_table_type + * Access: RW + * + * Note: FID offset and FID types are not supported in SwitchX-2. + */ +MLXSW_ITEM32(reg, sfgc, table_type, 0x04, 16, 3); + +/* reg_sfgc_flood_table + * Flooding table index to associate with the specific type on the specific + * switch partition. + * Access: RW + */ +MLXSW_ITEM32(reg, sfgc, flood_table, 0x04, 0, 6); + +/* reg_sfgc_mid + * The multicast ID for the swid. Not supported for Spectrum + * Access: RW + */ +MLXSW_ITEM32(reg, sfgc, mid, 0x08, 0, 16); + +/* reg_sfgc_counter_set_type + * Counter Set Type for flow counters. + * Access: RW + */ +MLXSW_ITEM32(reg, sfgc, counter_set_type, 0x0C, 24, 8); + +/* reg_sfgc_counter_index + * Counter Index for flow counters. + * Access: RW + */ +MLXSW_ITEM32(reg, sfgc, counter_index, 0x0C, 0, 24); + +static inline void +mlxsw_reg_sfgc_pack(char *payload, enum mlxsw_reg_sfgc_type type, + enum mlxsw_reg_sfgc_bridge_type bridge_type, + enum mlxsw_flood_table_type table_type, + unsigned int flood_table) +{ + MLXSW_REG_ZERO(sfgc, payload); + mlxsw_reg_sfgc_type_set(payload, type); + mlxsw_reg_sfgc_bridge_type_set(payload, bridge_type); + mlxsw_reg_sfgc_table_type_set(payload, table_type); + mlxsw_reg_sfgc_flood_table_set(payload, flood_table); + mlxsw_reg_sfgc_mid_set(payload, MLXSW_PORT_MID); +} + +/* SFTR - Switch Flooding Table Register + * ------------------------------------- + * The switch flooding table is used for flooding packet replication. The table + * defines a bit mask of ports for packet replication. + */ +#define MLXSW_REG_SFTR_ID 0x2012 +#define MLXSW_REG_SFTR_LEN 0x420 + +static const struct mlxsw_reg_info mlxsw_reg_sftr = { + .id = MLXSW_REG_SFTR_ID, + .len = MLXSW_REG_SFTR_LEN, +}; + +/* reg_sftr_swid + * Switch partition ID with which to associate the port. + * Access: Index + */ +MLXSW_ITEM32(reg, sftr, swid, 0x00, 24, 8); + +/* reg_sftr_flood_table + * Flooding table index to associate with the specific type on the specific + * switch partition. + * Access: Index + */ +MLXSW_ITEM32(reg, sftr, flood_table, 0x00, 16, 6); + +/* reg_sftr_index + * Index. Used as an index into the Flooding Table in case the table is + * configured to use VID / FID or FID Offset. + * Access: Index + */ +MLXSW_ITEM32(reg, sftr, index, 0x00, 0, 16); + +/* reg_sftr_table_type + * See mlxsw_flood_table_type + * Access: RW + */ +MLXSW_ITEM32(reg, sftr, table_type, 0x04, 16, 3); + +/* reg_sftr_range + * Range of entries to update + * Access: Index + */ +MLXSW_ITEM32(reg, sftr, range, 0x04, 0, 16); + +/* reg_sftr_port + * Local port membership (1 bit per port). + * Access: RW + */ +MLXSW_ITEM_BIT_ARRAY(reg, sftr, port, 0x20, 0x20, 1); + +/* reg_sftr_cpu_port_mask + * CPU port mask (1 bit per port). + * Access: W + */ +MLXSW_ITEM_BIT_ARRAY(reg, sftr, port_mask, 0x220, 0x20, 1); + +static inline void mlxsw_reg_sftr_pack(char *payload, + unsigned int flood_table, + unsigned int index, + enum mlxsw_flood_table_type table_type, + unsigned int range) +{ + MLXSW_REG_ZERO(sftr, payload); + mlxsw_reg_sftr_swid_set(payload, 0); + mlxsw_reg_sftr_flood_table_set(payload, flood_table); + mlxsw_reg_sftr_index_set(payload, index); + mlxsw_reg_sftr_table_type_set(payload, table_type); + mlxsw_reg_sftr_range_set(payload, range); + mlxsw_reg_sftr_port_set(payload, MLXSW_PORT_CPU_PORT, 1); + mlxsw_reg_sftr_port_mask_set(payload, MLXSW_PORT_CPU_PORT, 1); +} + +/* SPMLR - Switch Port MAC Learning Register + * ----------------------------------------- + * Controls the Switch MAC learning policy per port. + */ +#define MLXSW_REG_SPMLR_ID 0x2018 +#define MLXSW_REG_SPMLR_LEN 0x8 + +static const struct mlxsw_reg_info mlxsw_reg_spmlr = { + .id = MLXSW_REG_SPMLR_ID, + .len = MLXSW_REG_SPMLR_LEN, +}; + +/* reg_spmlr_local_port + * Local port number. + * Access: Index + */ +MLXSW_ITEM32(reg, spmlr, local_port, 0x00, 16, 8); + +/* reg_spmlr_sub_port + * Virtual port within the physical port. + * Should be set to 0 when virtual ports are not enabled on the port. + * Access: Index + */ +MLXSW_ITEM32(reg, spmlr, sub_port, 0x00, 8, 8); + +enum mlxsw_reg_spmlr_learn_mode { + MLXSW_REG_SPMLR_LEARN_MODE_DISABLE = 0, + MLXSW_REG_SPMLR_LEARN_MODE_ENABLE = 2, + MLXSW_REG_SPMLR_LEARN_MODE_SEC = 3, +}; + +/* reg_spmlr_learn_mode + * Learning mode on the port. + * 0 - Learning disabled. + * 2 - Learning enabled. + * 3 - Security mode. + * + * In security mode the switch does not learn MACs on the port, but uses the + * SMAC to see if it exists on another ingress port. If so, the packet is + * classified as a bad packet and is discarded unless the software registers + * to receive port security error packets usign HPKT. + */ +MLXSW_ITEM32(reg, spmlr, learn_mode, 0x04, 30, 2); + +static inline void mlxsw_reg_spmlr_pack(char *payload, u8 local_port, + enum mlxsw_reg_spmlr_learn_mode mode) +{ + MLXSW_REG_ZERO(spmlr, payload); + mlxsw_reg_spmlr_local_port_set(payload, local_port); + mlxsw_reg_spmlr_sub_port_set(payload, 0); + mlxsw_reg_spmlr_learn_mode_set(payload, mode); +} + +/* PMLP - Ports Module to Local Port Register + * ------------------------------------------ + * Configures the assignment of modules to local ports. + */ +#define MLXSW_REG_PMLP_ID 0x5002 +#define MLXSW_REG_PMLP_LEN 0x40 + +static const struct mlxsw_reg_info mlxsw_reg_pmlp = { + .id = MLXSW_REG_PMLP_ID, + .len = MLXSW_REG_PMLP_LEN, +}; + +/* reg_pmlp_rxtx + * 0 - Tx value is used for both Tx and Rx. + * 1 - Rx value is taken from a separte field. + * Access: RW + */ +MLXSW_ITEM32(reg, pmlp, rxtx, 0x00, 31, 1); + +/* reg_pmlp_local_port + * Local port number. + * Access: Index + */ +MLXSW_ITEM32(reg, pmlp, local_port, 0x00, 16, 8); + +/* reg_pmlp_width + * 0 - Unmap local port. + * 1 - Lane 0 is used. + * 2 - Lanes 0 and 1 are used. + * 4 - Lanes 0, 1, 2 and 3 are used. + * Access: RW + */ +MLXSW_ITEM32(reg, pmlp, width, 0x00, 0, 8); + +/* reg_pmlp_module + * Module number. + * Access: RW + */ +MLXSW_ITEM32_INDEXED(reg, pmlp, module, 0x04, 0, 8, 0x04, 0, false); + +/* reg_pmlp_tx_lane + * Tx Lane. When rxtx field is cleared, this field is used for Rx as well. + * Access: RW + */ +MLXSW_ITEM32_INDEXED(reg, pmlp, tx_lane, 0x04, 16, 2, 0x04, 16, false); + +/* reg_pmlp_rx_lane + * Rx Lane. When rxtx field is cleared, this field is ignored and Rx lane is + * equal to Tx lane. + * Access: RW + */ +MLXSW_ITEM32_INDEXED(reg, pmlp, rx_lane, 0x04, 24, 2, 0x04, 24, false); + +static inline void mlxsw_reg_pmlp_pack(char *payload, u8 local_port) +{ + MLXSW_REG_ZERO(pmlp, payload); + mlxsw_reg_pmlp_local_port_set(payload, local_port); +} + +/* PMTU - Port MTU Register + * ------------------------ + * Configures and reports the port MTU. + */ +#define MLXSW_REG_PMTU_ID 0x5003 +#define MLXSW_REG_PMTU_LEN 0x10 + +static const struct mlxsw_reg_info mlxsw_reg_pmtu = { + .id = MLXSW_REG_PMTU_ID, + .len = MLXSW_REG_PMTU_LEN, +}; + +/* reg_pmtu_local_port + * Local port number. + * Access: Index + */ +MLXSW_ITEM32(reg, pmtu, local_port, 0x00, 16, 8); + +/* reg_pmtu_max_mtu + * Maximum MTU. + * When port type (e.g. Ethernet) is configured, the relevant MTU is + * reported, otherwise the minimum between the max_mtu of the different + * types is reported. + * Access: RO + */ +MLXSW_ITEM32(reg, pmtu, max_mtu, 0x04, 16, 16); + +/* reg_pmtu_admin_mtu + * MTU value to set port to. Must be smaller or equal to max_mtu. + * Note: If port type is Infiniband, then port must be disabled, when its + * MTU is set. + * Access: RW + */ +MLXSW_ITEM32(reg, pmtu, admin_mtu, 0x08, 16, 16); + +/* reg_pmtu_oper_mtu + * The actual MTU configured on the port. Packets exceeding this size + * will be dropped. + * Note: In Ethernet and FC oper_mtu == admin_mtu, however, in Infiniband + * oper_mtu might be smaller than admin_mtu. + * Access: RO + */ +MLXSW_ITEM32(reg, pmtu, oper_mtu, 0x0C, 16, 16); + +static inline void mlxsw_reg_pmtu_pack(char *payload, u8 local_port, + u16 new_mtu) +{ + MLXSW_REG_ZERO(pmtu, payload); + mlxsw_reg_pmtu_local_port_set(payload, local_port); + mlxsw_reg_pmtu_max_mtu_set(payload, 0); + mlxsw_reg_pmtu_admin_mtu_set(payload, new_mtu); + mlxsw_reg_pmtu_oper_mtu_set(payload, 0); +} + +/* PTYS - Port Type and Speed Register + * ----------------------------------- + * Configures and reports the port speed type. + * + * Note: When set while the link is up, the changes will not take effect + * until the port transitions from down to up state. + */ +#define MLXSW_REG_PTYS_ID 0x5004 +#define MLXSW_REG_PTYS_LEN 0x40 + +static const struct mlxsw_reg_info mlxsw_reg_ptys = { + .id = MLXSW_REG_PTYS_ID, + .len = MLXSW_REG_PTYS_LEN, +}; + +/* reg_ptys_local_port + * Local port number. + * Access: Index + */ +MLXSW_ITEM32(reg, ptys, local_port, 0x00, 16, 8); + +#define MLXSW_REG_PTYS_PROTO_MASK_ETH BIT(2) + +/* reg_ptys_proto_mask + * Protocol mask. Indicates which protocol is used. + * 0 - Infiniband. + * 1 - Fibre Channel. + * 2 - Ethernet. + * Access: Index + */ +MLXSW_ITEM32(reg, ptys, proto_mask, 0x00, 0, 3); + +#define MLXSW_REG_PTYS_ETH_SPEED_SGMII BIT(0) +#define MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX BIT(1) +#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 BIT(2) +#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 BIT(3) +#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR BIT(4) +#define MLXSW_REG_PTYS_ETH_SPEED_20GBASE_KR2 BIT(5) +#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 BIT(6) +#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 BIT(7) +#define MLXSW_REG_PTYS_ETH_SPEED_56GBASE_R4 BIT(8) +#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR BIT(12) +#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR BIT(13) +#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR BIT(14) +#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 BIT(15) +#define MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4 BIT(16) +#define MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR4 BIT(19) +#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4 BIT(20) +#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 BIT(21) +#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 BIT(22) +#define MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4 BIT(23) +#define MLXSW_REG_PTYS_ETH_SPEED_100BASE_TX BIT(24) +#define MLXSW_REG_PTYS_ETH_SPEED_100BASE_T BIT(25) +#define MLXSW_REG_PTYS_ETH_SPEED_10GBASE_T BIT(26) +#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR BIT(27) +#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR BIT(28) +#define MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR BIT(29) +#define MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2 BIT(30) +#define MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2 BIT(31) + +/* reg_ptys_eth_proto_cap + * Ethernet port supported speeds and protocols. + * Access: RO + */ +MLXSW_ITEM32(reg, ptys, eth_proto_cap, 0x0C, 0, 32); + +/* reg_ptys_eth_proto_admin + * Speed and protocol to set port to. + * Access: RW + */ +MLXSW_ITEM32(reg, ptys, eth_proto_admin, 0x18, 0, 32); + +/* reg_ptys_eth_proto_oper + * The current speed and protocol configured for the port. + * Access: RO + */ +MLXSW_ITEM32(reg, ptys, eth_proto_oper, 0x24, 0, 32); + +static inline void mlxsw_reg_ptys_pack(char *payload, u8 local_port, + u32 proto_admin) +{ + MLXSW_REG_ZERO(ptys, payload); + mlxsw_reg_ptys_local_port_set(payload, local_port); + mlxsw_reg_ptys_proto_mask_set(payload, MLXSW_REG_PTYS_PROTO_MASK_ETH); + mlxsw_reg_ptys_eth_proto_admin_set(payload, proto_admin); +} + +static inline void mlxsw_reg_ptys_unpack(char *payload, u32 *p_eth_proto_cap, + u32 *p_eth_proto_adm, + u32 *p_eth_proto_oper) +{ + if (p_eth_proto_cap) + *p_eth_proto_cap = mlxsw_reg_ptys_eth_proto_cap_get(payload); + if (p_eth_proto_adm) + *p_eth_proto_adm = mlxsw_reg_ptys_eth_proto_admin_get(payload); + if (p_eth_proto_oper) + *p_eth_proto_oper = mlxsw_reg_ptys_eth_proto_oper_get(payload); +} + +/* PPAD - Port Physical Address Register + * ------------------------------------- + * The PPAD register configures the per port physical MAC address. + */ +#define MLXSW_REG_PPAD_ID 0x5005 +#define MLXSW_REG_PPAD_LEN 0x10 + +static const struct mlxsw_reg_info mlxsw_reg_ppad = { + .id = MLXSW_REG_PPAD_ID, + .len = MLXSW_REG_PPAD_LEN, +}; + +/* reg_ppad_single_base_mac + * 0: base_mac, local port should be 0 and mac[7:0] is + * reserved. HW will set incremental + * 1: single_mac - mac of the local_port + * Access: RW + */ +MLXSW_ITEM32(reg, ppad, single_base_mac, 0x00, 28, 1); + +/* reg_ppad_local_port + * port number, if single_base_mac = 0 then local_port is reserved + * Access: RW + */ +MLXSW_ITEM32(reg, ppad, local_port, 0x00, 16, 8); + +/* reg_ppad_mac + * If single_base_mac = 0 - base MAC address, mac[7:0] is reserved. + * If single_base_mac = 1 - the per port MAC address + * Access: RW + */ +MLXSW_ITEM_BUF(reg, ppad, mac, 0x02, 6); + +static inline void mlxsw_reg_ppad_pack(char *payload, bool single_base_mac, + u8 local_port) +{ + MLXSW_REG_ZERO(ppad, payload); + mlxsw_reg_ppad_single_base_mac_set(payload, !!single_base_mac); + mlxsw_reg_ppad_local_port_set(payload, local_port); +} + +/* PAOS - Ports Administrative and Operational Status Register + * ----------------------------------------------------------- + * Configures and retrieves per port administrative and operational status. + */ +#define MLXSW_REG_PAOS_ID 0x5006 +#define MLXSW_REG_PAOS_LEN 0x10 + +static const struct mlxsw_reg_info mlxsw_reg_paos = { + .id = MLXSW_REG_PAOS_ID, + .len = MLXSW_REG_PAOS_LEN, +}; + +/* reg_paos_swid + * Switch partition ID with which to associate the port. + * Note: while external ports uses unique local port numbers (and thus swid is + * redundant), router ports use the same local port number where swid is the + * only indication for the relevant port. + * Access: Index + */ +MLXSW_ITEM32(reg, paos, swid, 0x00, 24, 8); + +/* reg_paos_local_port + * Local port number. + * Access: Index + */ +MLXSW_ITEM32(reg, paos, local_port, 0x00, 16, 8); + +/* reg_paos_admin_status + * Port administrative state (the desired state of the port): + * 1 - Up. + * 2 - Down. + * 3 - Up once. This means that in case of link failure, the port won't go + * into polling mode, but will wait to be re-enabled by software. + * 4 - Disabled by system. Can only be set by hardware. + * Access: RW + */ +MLXSW_ITEM32(reg, paos, admin_status, 0x00, 8, 4); + +/* reg_paos_oper_status + * Port operational state (the current state): + * 1 - Up. + * 2 - Down. + * 3 - Down by port failure. This means that the device will not let the + * port up again until explicitly specified by software. + * Access: RO + */ +MLXSW_ITEM32(reg, paos, oper_status, 0x00, 0, 4); + +/* reg_paos_ase + * Admin state update enabled. + * Access: WO + */ +MLXSW_ITEM32(reg, paos, ase, 0x04, 31, 1); + +/* reg_paos_ee + * Event update enable. If this bit is set, event generation will be + * updated based on the e field. + * Access: WO + */ +MLXSW_ITEM32(reg, paos, ee, 0x04, 30, 1); + +/* reg_paos_e + * Event generation on operational state change: + * 0 - Do not generate event. + * 1 - Generate Event. + * 2 - Generate Single Event. + * Access: RW + */ +MLXSW_ITEM32(reg, paos, e, 0x04, 0, 2); + +static inline void mlxsw_reg_paos_pack(char *payload, u8 local_port, + enum mlxsw_port_admin_status status) +{ + MLXSW_REG_ZERO(paos, payload); + mlxsw_reg_paos_swid_set(payload, 0); + mlxsw_reg_paos_local_port_set(payload, local_port); + mlxsw_reg_paos_admin_status_set(payload, status); + mlxsw_reg_paos_oper_status_set(payload, 0); + mlxsw_reg_paos_ase_set(payload, 1); + mlxsw_reg_paos_ee_set(payload, 1); + mlxsw_reg_paos_e_set(payload, 1); +} + +/* PPCNT - Ports Performance Counters Register + * ------------------------------------------- + * The PPCNT register retrieves per port performance counters. + */ +#define MLXSW_REG_PPCNT_ID 0x5008 +#define MLXSW_REG_PPCNT_LEN 0x100 + +static const struct mlxsw_reg_info mlxsw_reg_ppcnt = { + .id = MLXSW_REG_PPCNT_ID, + .len = MLXSW_REG_PPCNT_LEN, +}; + +/* reg_ppcnt_swid + * For HCA: must be always 0. + * Switch partition ID to associate port with. + * Switch partitions are numbered from 0 to 7 inclusively. + * Switch partition 254 indicates stacking ports. + * Switch partition 255 indicates all switch partitions. + * Only valid on Set() operation with local_port=255. + * Access: Index + */ +MLXSW_ITEM32(reg, ppcnt, swid, 0x00, 24, 8); + +/* reg_ppcnt_local_port + * Local port number. + * 255 indicates all ports on the device, and is only allowed + * for Set() operation. + * Access: Index + */ +MLXSW_ITEM32(reg, ppcnt, local_port, 0x00, 16, 8); + +/* reg_ppcnt_pnat + * Port number access type: + * 0 - Local port number + * 1 - IB port number + * Access: Index + */ +MLXSW_ITEM32(reg, ppcnt, pnat, 0x00, 14, 2); + +/* reg_ppcnt_grp + * Performance counter group. + * Group 63 indicates all groups. Only valid on Set() operation with + * clr bit set. + * 0x0: IEEE 802.3 Counters + * 0x1: RFC 2863 Counters + * 0x2: RFC 2819 Counters + * 0x3: RFC 3635 Counters + * 0x5: Ethernet Extended Counters + * 0x8: Link Level Retransmission Counters + * 0x10: Per Priority Counters + * 0x11: Per Traffic Class Counters + * 0x12: Physical Layer Counters + * Access: Index + */ +MLXSW_ITEM32(reg, ppcnt, grp, 0x00, 0, 6); + +/* reg_ppcnt_clr + * Clear counters. Setting the clr bit will reset the counter value + * for all counters in the counter group. This bit can be set + * for both Set() and Get() operation. + * Access: OP + */ +MLXSW_ITEM32(reg, ppcnt, clr, 0x04, 31, 1); + +/* reg_ppcnt_prio_tc + * Priority for counter set that support per priority, valid values: 0-7. + * Traffic class for counter set that support per traffic class, + * valid values: 0- cap_max_tclass-1 . + * For HCA: cap_max_tclass is always 8. + * Otherwise must be 0. + * Access: Index + */ +MLXSW_ITEM32(reg, ppcnt, prio_tc, 0x04, 0, 5); + +/* reg_ppcnt_a_frames_transmitted_ok + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_frames_transmitted_ok, + 0x08 + 0x00, 0, 64); + +/* reg_ppcnt_a_frames_received_ok + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_frames_received_ok, + 0x08 + 0x08, 0, 64); + +/* reg_ppcnt_a_frame_check_sequence_errors + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_frame_check_sequence_errors, + 0x08 + 0x10, 0, 64); + +/* reg_ppcnt_a_alignment_errors + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_alignment_errors, + 0x08 + 0x18, 0, 64); + +/* reg_ppcnt_a_octets_transmitted_ok + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_octets_transmitted_ok, + 0x08 + 0x20, 0, 64); + +/* reg_ppcnt_a_octets_received_ok + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_octets_received_ok, + 0x08 + 0x28, 0, 64); + +/* reg_ppcnt_a_multicast_frames_xmitted_ok + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_multicast_frames_xmitted_ok, + 0x08 + 0x30, 0, 64); + +/* reg_ppcnt_a_broadcast_frames_xmitted_ok + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_broadcast_frames_xmitted_ok, + 0x08 + 0x38, 0, 64); + +/* reg_ppcnt_a_multicast_frames_received_ok + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_multicast_frames_received_ok, + 0x08 + 0x40, 0, 64); + +/* reg_ppcnt_a_broadcast_frames_received_ok + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_broadcast_frames_received_ok, + 0x08 + 0x48, 0, 64); + +/* reg_ppcnt_a_in_range_length_errors + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_in_range_length_errors, + 0x08 + 0x50, 0, 64); + +/* reg_ppcnt_a_out_of_range_length_field + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_out_of_range_length_field, + 0x08 + 0x58, 0, 64); + +/* reg_ppcnt_a_frame_too_long_errors + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_frame_too_long_errors, + 0x08 + 0x60, 0, 64); + +/* reg_ppcnt_a_symbol_error_during_carrier + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_symbol_error_during_carrier, + 0x08 + 0x68, 0, 64); + +/* reg_ppcnt_a_mac_control_frames_transmitted + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_mac_control_frames_transmitted, + 0x08 + 0x70, 0, 64); + +/* reg_ppcnt_a_mac_control_frames_received + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_mac_control_frames_received, + 0x08 + 0x78, 0, 64); + +/* reg_ppcnt_a_unsupported_opcodes_received + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_unsupported_opcodes_received, + 0x08 + 0x80, 0, 64); + +/* reg_ppcnt_a_pause_mac_ctrl_frames_received + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_pause_mac_ctrl_frames_received, + 0x08 + 0x88, 0, 64); + +/* reg_ppcnt_a_pause_mac_ctrl_frames_transmitted + * Access: RO + */ +MLXSW_ITEM64(reg, ppcnt, a_pause_mac_ctrl_frames_transmitted, + 0x08 + 0x90, 0, 64); + +static inline void mlxsw_reg_ppcnt_pack(char *payload, u8 local_port) +{ + MLXSW_REG_ZERO(ppcnt, payload); + mlxsw_reg_ppcnt_swid_set(payload, 0); + mlxsw_reg_ppcnt_local_port_set(payload, local_port); + mlxsw_reg_ppcnt_pnat_set(payload, 0); + mlxsw_reg_ppcnt_grp_set(payload, 0); + mlxsw_reg_ppcnt_clr_set(payload, 0); + mlxsw_reg_ppcnt_prio_tc_set(payload, 0); +} + +/* PSPA - Port Switch Partition Allocation + * --------------------------------------- + * Controls the association of a port with a switch partition and enables + * configuring ports as stacking ports. + */ +#define MLXSW_REG_PSPA_ID 0x500d +#define MLXSW_REG_PSPA_LEN 0x8 + +static const struct mlxsw_reg_info mlxsw_reg_pspa = { + .id = MLXSW_REG_PSPA_ID, + .len = MLXSW_REG_PSPA_LEN, +}; + +/* reg_pspa_swid + * Switch partition ID. + * Access: RW + */ +MLXSW_ITEM32(reg, pspa, swid, 0x00, 24, 8); + +/* reg_pspa_local_port + * Local port number. + * Access: Index + */ +MLXSW_ITEM32(reg, pspa, local_port, 0x00, 16, 8); + +/* reg_pspa_sub_port + * Virtual port within the local port. Set to 0 when virtual ports are + * disabled on the local port. + * Access: Index + */ +MLXSW_ITEM32(reg, pspa, sub_port, 0x00, 8, 8); + +static inline void mlxsw_reg_pspa_pack(char *payload, u8 swid, u8 local_port) +{ + MLXSW_REG_ZERO(pspa, payload); + mlxsw_reg_pspa_swid_set(payload, swid); + mlxsw_reg_pspa_local_port_set(payload, local_port); + mlxsw_reg_pspa_sub_port_set(payload, 0); +} + +/* HTGT - Host Trap Group Table + * ---------------------------- + * Configures the properties for forwarding to CPU. + */ +#define MLXSW_REG_HTGT_ID 0x7002 +#define MLXSW_REG_HTGT_LEN 0x100 + +static const struct mlxsw_reg_info mlxsw_reg_htgt = { + .id = MLXSW_REG_HTGT_ID, + .len = MLXSW_REG_HTGT_LEN, +}; + +/* reg_htgt_swid + * Switch partition ID. + * Access: Index + */ +MLXSW_ITEM32(reg, htgt, swid, 0x00, 24, 8); + +#define MLXSW_REG_HTGT_PATH_TYPE_LOCAL 0x0 /* For locally attached CPU */ + +/* reg_htgt_type + * CPU path type. + * Access: RW + */ +MLXSW_ITEM32(reg, htgt, type, 0x00, 8, 4); + +#define MLXSW_REG_HTGT_TRAP_GROUP_EMAD 0x0 +#define MLXSW_REG_HTGT_TRAP_GROUP_RX 0x1 + +/* reg_htgt_trap_group + * Trap group number. User defined number specifying which trap groups + * should be forwarded to the CPU. The mapping between trap IDs and trap + * groups is configured using HPKT register. + * Access: Index + */ +MLXSW_ITEM32(reg, htgt, trap_group, 0x00, 0, 8); + +enum { + MLXSW_REG_HTGT_POLICER_DISABLE, + MLXSW_REG_HTGT_POLICER_ENABLE, +}; + +/* reg_htgt_pide + * Enable policer ID specified using 'pid' field. + * Access: RW + */ +MLXSW_ITEM32(reg, htgt, pide, 0x04, 15, 1); + +/* reg_htgt_pid + * Policer ID for the trap group. + * Access: RW + */ +MLXSW_ITEM32(reg, htgt, pid, 0x04, 0, 8); + +#define MLXSW_REG_HTGT_TRAP_TO_CPU 0x0 + +/* reg_htgt_mirror_action + * Mirror action to use. + * 0 - Trap to CPU. + * 1 - Trap to CPU and mirror to a mirroring agent. + * 2 - Mirror to a mirroring agent and do not trap to CPU. + * Access: RW + * + * Note: Mirroring to a mirroring agent is only supported in Spectrum. + */ +MLXSW_ITEM32(reg, htgt, mirror_action, 0x08, 8, 2); + +/* reg_htgt_mirroring_agent + * Mirroring agent. + * Access: RW + */ +MLXSW_ITEM32(reg, htgt, mirroring_agent, 0x08, 0, 3); + +/* reg_htgt_priority + * Trap group priority. + * In case a packet matches multiple classification rules, the packet will + * only be trapped once, based on the trap ID associated with the group (via + * register HPKT) with the highest priority. + * Supported values are 0-7, with 7 represnting the highest priority. + * Access: RW + * + * Note: In SwitchX-2 this field is ignored and the priority value is replaced + * by the 'trap_group' field. + */ +MLXSW_ITEM32(reg, htgt, priority, 0x0C, 0, 4); + +/* reg_htgt_local_path_cpu_tclass + * CPU ingress traffic class for the trap group. + * Access: RW + */ +MLXSW_ITEM32(reg, htgt, local_path_cpu_tclass, 0x10, 16, 6); + +#define MLXSW_REG_HTGT_LOCAL_PATH_RDQ_EMAD 0x15 +#define MLXSW_REG_HTGT_LOCAL_PATH_RDQ_RX 0x14 + +/* reg_htgt_local_path_rdq + * Receive descriptor queue (RDQ) to use for the trap group. + * Access: RW + */ +MLXSW_ITEM32(reg, htgt, local_path_rdq, 0x10, 0, 6); + +static inline void mlxsw_reg_htgt_pack(char *payload, u8 trap_group) +{ + u8 swid, rdq; + + MLXSW_REG_ZERO(htgt, payload); + if (MLXSW_REG_HTGT_TRAP_GROUP_EMAD == trap_group) { + swid = MLXSW_PORT_SWID_ALL_SWIDS; + rdq = MLXSW_REG_HTGT_LOCAL_PATH_RDQ_EMAD; + } else { + swid = 0; + rdq = MLXSW_REG_HTGT_LOCAL_PATH_RDQ_RX; + } + mlxsw_reg_htgt_swid_set(payload, swid); + mlxsw_reg_htgt_type_set(payload, MLXSW_REG_HTGT_PATH_TYPE_LOCAL); + mlxsw_reg_htgt_trap_group_set(payload, trap_group); + mlxsw_reg_htgt_pide_set(payload, MLXSW_REG_HTGT_POLICER_DISABLE); + mlxsw_reg_htgt_pid_set(payload, 0); + mlxsw_reg_htgt_mirror_action_set(payload, MLXSW_REG_HTGT_TRAP_TO_CPU); + mlxsw_reg_htgt_mirroring_agent_set(payload, 0); + mlxsw_reg_htgt_priority_set(payload, 0); + mlxsw_reg_htgt_local_path_cpu_tclass_set(payload, 7); + mlxsw_reg_htgt_local_path_rdq_set(payload, rdq); +} + +/* HPKT - Host Packet Trap + * ----------------------- + * Configures trap IDs inside trap groups. + */ +#define MLXSW_REG_HPKT_ID 0x7003 +#define MLXSW_REG_HPKT_LEN 0x10 + +static const struct mlxsw_reg_info mlxsw_reg_hpkt = { + .id = MLXSW_REG_HPKT_ID, + .len = MLXSW_REG_HPKT_LEN, +}; + +enum { + MLXSW_REG_HPKT_ACK_NOT_REQUIRED, + MLXSW_REG_HPKT_ACK_REQUIRED, +}; + +/* reg_hpkt_ack + * Require acknowledgements from the host for events. + * If set, then the device will wait for the event it sent to be acknowledged + * by the host. This option is only relevant for event trap IDs. + * Access: RW + * + * Note: Currently not supported by firmware. + */ +MLXSW_ITEM32(reg, hpkt, ack, 0x00, 24, 1); + +enum mlxsw_reg_hpkt_action { + MLXSW_REG_HPKT_ACTION_FORWARD, + MLXSW_REG_HPKT_ACTION_TRAP_TO_CPU, + MLXSW_REG_HPKT_ACTION_MIRROR_TO_CPU, + MLXSW_REG_HPKT_ACTION_DISCARD, + MLXSW_REG_HPKT_ACTION_SOFT_DISCARD, + MLXSW_REG_HPKT_ACTION_TRAP_AND_SOFT_DISCARD, +}; + +/* reg_hpkt_action + * Action to perform on packet when trapped. + * 0 - No action. Forward to CPU based on switching rules. + * 1 - Trap to CPU (CPU receives sole copy). + * 2 - Mirror to CPU (CPU receives a replica of the packet). + * 3 - Discard. + * 4 - Soft discard (allow other traps to act on the packet). + * 5 - Trap and soft discard (allow other traps to overwrite this trap). + * Access: RW + * + * Note: Must be set to 0 (forward) for event trap IDs, as they are already + * addressed to the CPU. + */ +MLXSW_ITEM32(reg, hpkt, action, 0x00, 20, 3); + +/* reg_hpkt_trap_group + * Trap group to associate the trap with. + * Access: RW + */ +MLXSW_ITEM32(reg, hpkt, trap_group, 0x00, 12, 6); + +/* reg_hpkt_trap_id + * Trap ID. + * Access: Index + * + * Note: A trap ID can only be associated with a single trap group. The device + * will associate the trap ID with the last trap group configured. + */ +MLXSW_ITEM32(reg, hpkt, trap_id, 0x00, 0, 9); + +enum { + MLXSW_REG_HPKT_CTRL_PACKET_DEFAULT, + MLXSW_REG_HPKT_CTRL_PACKET_NO_BUFFER, + MLXSW_REG_HPKT_CTRL_PACKET_USE_BUFFER, +}; + +/* reg_hpkt_ctrl + * Configure dedicated buffer resources for control packets. + * 0 - Keep factory defaults. + * 1 - Do not use control buffer for this trap ID. + * 2 - Use control buffer for this trap ID. + * Access: RW + */ +MLXSW_ITEM32(reg, hpkt, ctrl, 0x04, 16, 2); + +static inline void mlxsw_reg_hpkt_pack(char *payload, u8 action, + u8 trap_group, u16 trap_id) +{ + MLXSW_REG_ZERO(hpkt, payload); + mlxsw_reg_hpkt_ack_set(payload, MLXSW_REG_HPKT_ACK_NOT_REQUIRED); + mlxsw_reg_hpkt_action_set(payload, action); + mlxsw_reg_hpkt_trap_group_set(payload, trap_group); + mlxsw_reg_hpkt_trap_id_set(payload, trap_id); + mlxsw_reg_hpkt_ctrl_set(payload, MLXSW_REG_HPKT_CTRL_PACKET_DEFAULT); +} + +static inline const char *mlxsw_reg_id_str(u16 reg_id) +{ + switch (reg_id) { + case MLXSW_REG_SGCR_ID: + return "SGCR"; + case MLXSW_REG_SPAD_ID: + return "SPAD"; + case MLXSW_REG_SMID_ID: + return "SMID"; + case MLXSW_REG_SPMS_ID: + return "SPMS"; + case MLXSW_REG_SFGC_ID: + return "SFGC"; + case MLXSW_REG_SFTR_ID: + return "SFTR"; + case MLXSW_REG_SPMLR_ID: + return "SPMLR"; + case MLXSW_REG_PMLP_ID: + return "PMLP"; + case MLXSW_REG_PMTU_ID: + return "PMTU"; + case MLXSW_REG_PTYS_ID: + return "PTYS"; + case MLXSW_REG_PPAD_ID: + return "PPAD"; + case MLXSW_REG_PAOS_ID: + return "PAOS"; + case MLXSW_REG_PPCNT_ID: + return "PPCNT"; + case MLXSW_REG_PSPA_ID: + return "PSPA"; + case MLXSW_REG_HTGT_ID: + return "HTGT"; + case MLXSW_REG_HPKT_ID: + return "HPKT"; + default: + return "*UNKNOWN*"; + } +} + +/* PUDE - Port Up / Down Event + * --------------------------- + * Reports the operational state change of a port. + */ +#define MLXSW_REG_PUDE_LEN 0x10 + +/* reg_pude_swid + * Switch partition ID with which to associate the port. + * Access: Index + */ +MLXSW_ITEM32(reg, pude, swid, 0x00, 24, 8); + +/* reg_pude_local_port + * Local port number. + * Access: Index + */ +MLXSW_ITEM32(reg, pude, local_port, 0x00, 16, 8); + +/* reg_pude_admin_status + * Port administrative state (the desired state). + * 1 - Up. + * 2 - Down. + * 3 - Up once. This means that in case of link failure, the port won't go + * into polling mode, but will wait to be re-enabled by software. + * 4 - Disabled by system. Can only be set by hardware. + * Access: RO + */ +MLXSW_ITEM32(reg, pude, admin_status, 0x00, 8, 4); + +/* reg_pude_oper_status + * Port operatioanl state. + * 1 - Up. + * 2 - Down. + * 3 - Down by port failure. This means that the device will not let the + * port up again until explicitly specified by software. + * Access: RO + */ +MLXSW_ITEM32(reg, pude, oper_status, 0x00, 0, 4); + +#endif -- cgit v1.3-6-gb490 From 31557f0f9755696530d08465cf9940404f2d48e2 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 29 Jul 2015 23:33:49 +0200 Subject: mlxsw: Introduce Mellanox SwitchX-2 ASIC support Benefit from the previously introduced Mellanox Switch infrastructure and add driver for SwitchX-2 ASIC. Note that this driver is very simple now. It implements bare minimum for getting device to work on slow-path. Fast-path offload functionality is going to be added soon. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Elad Raz Reviewed-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/Kconfig | 11 + drivers/net/ethernet/mellanox/mlxsw/Makefile | 2 + drivers/net/ethernet/mellanox/mlxsw/core.h | 2 + drivers/net/ethernet/mellanox/mlxsw/pci.c | 3 + drivers/net/ethernet/mellanox/mlxsw/pci.h | 1 + drivers/net/ethernet/mellanox/mlxsw/port.h | 4 + drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 1552 ++++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlxsw/txheader.h | 80 ++ 8 files changed, 1655 insertions(+) create mode 100644 drivers/net/ethernet/mellanox/mlxsw/switchx2.c create mode 100644 drivers/net/ethernet/mellanox/mlxsw/txheader.h (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig index 1385f2caea11..8d1080da49b5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig @@ -19,3 +19,14 @@ config MLXSW_PCI To compile this driver as a module, choose M here: the module will be called mlxsw_pci. + +config MLXSW_SWITCHX2 + tristate "Mellanox Technologies SwitchX-2 support" + depends on MLXSW_CORE && NET_SWITCHDEV + default m + ---help--- + This driver supports Mellanox Technologies SwitchX-2 Ethernet + Switch ASICs. + + To compile this driver as a module, choose M here: the + module will be called mlxsw_switchx2. diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile index 94841c3329b6..0a05f65ee814 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Makefile +++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile @@ -2,3 +2,5 @@ obj-$(CONFIG_MLXSW_CORE) += mlxsw_core.o mlxsw_core-objs := core.o obj-$(CONFIG_MLXSW_PCI) += mlxsw_pci.o mlxsw_pci-objs := pci.o +obj-$(CONFIG_MLXSW_SWITCHX2) += mlxsw_switchx2.o +mlxsw_switchx2-objs := switchx2.o diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index 53ef20ab06cb..2280b319c362 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -53,6 +53,8 @@ #define MODULE_MLXSW_DRIVER_ALIAS(kind) \ MODULE_ALIAS(MLXSW_MODULE_ALIAS_PREFIX kind) +#define MLXSW_DEVICE_KIND_SWITCHX2 "switchx2" + struct mlxsw_core; struct mlxsw_driver; struct mlxsw_bus; diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 64f725fde602..298ead5b42ca 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -55,6 +55,7 @@ static const char mlxsw_pci_driver_name[] = "mlxsw_pci"; static const struct pci_device_id mlxsw_pci_id_table[] = { + {PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_SWITCHX2), 0}, {0, } }; @@ -63,6 +64,8 @@ static struct dentry *mlxsw_pci_dbg_root; static const char *mlxsw_pci_device_kind_get(const struct pci_device_id *id) { switch (id->device) { + case PCI_DEVICE_ID_MELLANOX_SWITCHX2: + return MLXSW_DEVICE_KIND_SWITCHX2; default: BUG(); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.h b/drivers/net/ethernet/mellanox/mlxsw/pci.h index 6176a930130b..887af8459149 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.h @@ -39,6 +39,7 @@ #include "item.h" +#define PCI_DEVICE_ID_MELLANOX_SWITCHX2 0xc738 #define MLXSW_PCI_BAR0_SIZE (1024 * 1024) /* 1MB */ #define MLXSW_PCI_PAGE_SIZE 4096 diff --git a/drivers/net/ethernet/mellanox/mlxsw/port.h b/drivers/net/ethernet/mellanox/mlxsw/port.h index 4606966af980..726f5435b32f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/port.h +++ b/drivers/net/ethernet/mellanox/mlxsw/port.h @@ -51,6 +51,10 @@ #define MLXSW_PORT_MAX_PHY_PORTS 0x40 #define MLXSW_PORT_MAX_PORTS MLXSW_PORT_MAX_PHY_PORTS +#define MLXSW_PORT_DEVID_BITS_OFFSET 10 +#define MLXSW_PORT_PHY_BITS_OFFSET 4 +#define MLXSW_PORT_PHY_BITS_MASK (MLXSW_PORT_MAX_PHY_PORTS - 1) + #define MLXSW_PORT_CPU_PORT 0x0 #define MLXSW_PORT_DONT_CARE (MLXSW_PORT_MAX_PORTS) diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c new file mode 100644 index 000000000000..29b46eef9769 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c @@ -0,0 +1,1552 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/switchx2.c + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Jiri Pirko + * Copyright (c) 2015 Ido Schimmel + * Copyright (c) 2015 Elad Raz + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "reg.h" +#include "port.h" +#include "trap.h" +#include "txheader.h" + +static const char mlxsw_sx_driver_name[] = "mlxsw_switchx2"; +static const char mlxsw_sx_driver_version[] = "1.0"; + +struct mlxsw_sx_port; + +#define MLXSW_SW_HW_ID_LEN 6 + +struct mlxsw_sx { + struct mlxsw_sx_port **ports; + struct mlxsw_core *core; + const struct mlxsw_bus_info *bus_info; + u8 hw_id[MLXSW_SW_HW_ID_LEN]; +}; + +struct mlxsw_sx_port_pcpu_stats { + u64 rx_packets; + u64 rx_bytes; + u64 tx_packets; + u64 tx_bytes; + struct u64_stats_sync syncp; + u32 tx_dropped; +}; + +struct mlxsw_sx_port { + struct net_device *dev; + struct mlxsw_sx_port_pcpu_stats __percpu *pcpu_stats; + struct mlxsw_sx *mlxsw_sx; + u8 local_port; +}; + +/* tx_hdr_version + * Tx header version. + * Must be set to 0. + */ +MLXSW_ITEM32(tx, hdr, version, 0x00, 28, 4); + +/* tx_hdr_ctl + * Packet control type. + * 0 - Ethernet control (e.g. EMADs, LACP) + * 1 - Ethernet data + */ +MLXSW_ITEM32(tx, hdr, ctl, 0x00, 26, 2); + +/* tx_hdr_proto + * Packet protocol type. Must be set to 1 (Ethernet). + */ +MLXSW_ITEM32(tx, hdr, proto, 0x00, 21, 3); + +/* tx_hdr_etclass + * Egress TClass to be used on the egress device on the egress port. + * The MSB is specified in the 'ctclass3' field. + * Range is 0-15, where 15 is the highest priority. + */ +MLXSW_ITEM32(tx, hdr, etclass, 0x00, 18, 3); + +/* tx_hdr_swid + * Switch partition ID. + */ +MLXSW_ITEM32(tx, hdr, swid, 0x00, 12, 3); + +/* tx_hdr_port_mid + * Destination local port for unicast packets. + * Destination multicast ID for multicast packets. + * + * Control packets are directed to a specific egress port, while data + * packets are transmitted through the CPU port (0) into the switch partition, + * where forwarding rules are applied. + */ +MLXSW_ITEM32(tx, hdr, port_mid, 0x04, 16, 16); + +/* tx_hdr_ctclass3 + * See field 'etclass'. + */ +MLXSW_ITEM32(tx, hdr, ctclass3, 0x04, 14, 1); + +/* tx_hdr_rdq + * RDQ for control packets sent to remote CPU. + * Must be set to 0x1F for EMADs, otherwise 0. + */ +MLXSW_ITEM32(tx, hdr, rdq, 0x04, 9, 5); + +/* tx_hdr_cpu_sig + * Signature control for packets going to CPU. Must be set to 0. + */ +MLXSW_ITEM32(tx, hdr, cpu_sig, 0x04, 0, 9); + +/* tx_hdr_sig + * Stacking protocl signature. Must be set to 0xE0E0. + */ +MLXSW_ITEM32(tx, hdr, sig, 0x0C, 16, 16); + +/* tx_hdr_stclass + * Stacking TClass. + */ +MLXSW_ITEM32(tx, hdr, stclass, 0x0C, 13, 3); + +/* tx_hdr_emad + * EMAD bit. Must be set for EMADs. + */ +MLXSW_ITEM32(tx, hdr, emad, 0x0C, 5, 1); + +/* tx_hdr_type + * 0 - Data packets + * 6 - Control packets + */ +MLXSW_ITEM32(tx, hdr, type, 0x0C, 0, 4); + +static void mlxsw_sx_txhdr_construct(struct sk_buff *skb, + const struct mlxsw_tx_info *tx_info) +{ + char *txhdr = skb_push(skb, MLXSW_TXHDR_LEN); + bool is_emad = tx_info->is_emad; + + memset(txhdr, 0, MLXSW_TXHDR_LEN); + + /* We currently set default values for the egress tclass (QoS). */ + mlxsw_tx_hdr_version_set(txhdr, MLXSW_TXHDR_VERSION_0); + mlxsw_tx_hdr_ctl_set(txhdr, MLXSW_TXHDR_ETH_CTL); + mlxsw_tx_hdr_proto_set(txhdr, MLXSW_TXHDR_PROTO_ETH); + mlxsw_tx_hdr_etclass_set(txhdr, is_emad ? MLXSW_TXHDR_ETCLASS_6 : + MLXSW_TXHDR_ETCLASS_5); + mlxsw_tx_hdr_swid_set(txhdr, 0); + mlxsw_tx_hdr_port_mid_set(txhdr, tx_info->local_port); + mlxsw_tx_hdr_ctclass3_set(txhdr, MLXSW_TXHDR_CTCLASS3); + mlxsw_tx_hdr_rdq_set(txhdr, is_emad ? MLXSW_TXHDR_RDQ_EMAD : + MLXSW_TXHDR_RDQ_OTHER); + mlxsw_tx_hdr_cpu_sig_set(txhdr, MLXSW_TXHDR_CPU_SIG); + mlxsw_tx_hdr_sig_set(txhdr, MLXSW_TXHDR_SIG); + mlxsw_tx_hdr_stclass_set(txhdr, MLXSW_TXHDR_STCLASS_NONE); + mlxsw_tx_hdr_emad_set(txhdr, is_emad ? MLXSW_TXHDR_EMAD : + MLXSW_TXHDR_NOT_EMAD); + mlxsw_tx_hdr_type_set(txhdr, MLXSW_TXHDR_TYPE_CONTROL); +} + +static int mlxsw_sx_port_admin_status_set(struct mlxsw_sx_port *mlxsw_sx_port, + bool is_up) +{ + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char paos_pl[MLXSW_REG_PAOS_LEN]; + + mlxsw_reg_paos_pack(paos_pl, mlxsw_sx_port->local_port, + is_up ? MLXSW_PORT_ADMIN_STATUS_UP : + MLXSW_PORT_ADMIN_STATUS_DOWN); + return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(paos), paos_pl); +} + +static int mlxsw_sx_port_oper_status_get(struct mlxsw_sx_port *mlxsw_sx_port, + bool *p_is_up) +{ + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char paos_pl[MLXSW_REG_PAOS_LEN]; + u8 oper_status; + int err; + + mlxsw_reg_paos_pack(paos_pl, mlxsw_sx_port->local_port, 0); + err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(paos), paos_pl); + if (err) + return err; + oper_status = mlxsw_reg_paos_oper_status_get(paos_pl); + *p_is_up = oper_status == MLXSW_PORT_ADMIN_STATUS_UP ? true : false; + return 0; +} + +static int mlxsw_sx_port_mtu_set(struct mlxsw_sx_port *mlxsw_sx_port, u16 mtu) +{ + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char pmtu_pl[MLXSW_REG_PMTU_LEN]; + int max_mtu; + int err; + + mtu += MLXSW_TXHDR_LEN + ETH_HLEN; + mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sx_port->local_port, 0); + err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(pmtu), pmtu_pl); + if (err) + return err; + max_mtu = mlxsw_reg_pmtu_max_mtu_get(pmtu_pl); + + if (mtu > max_mtu) + return -EINVAL; + + mlxsw_reg_pmtu_pack(pmtu_pl, mlxsw_sx_port->local_port, mtu); + return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(pmtu), pmtu_pl); +} + +static int mlxsw_sx_port_swid_set(struct mlxsw_sx_port *mlxsw_sx_port, u8 swid) +{ + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char pspa_pl[MLXSW_REG_PSPA_LEN]; + + mlxsw_reg_pspa_pack(pspa_pl, swid, mlxsw_sx_port->local_port); + return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(pspa), pspa_pl); +} + +static int mlxsw_sx_port_module_check(struct mlxsw_sx_port *mlxsw_sx_port, + bool *p_usable) +{ + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char pmlp_pl[MLXSW_REG_PMLP_LEN]; + int err; + + mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sx_port->local_port); + err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(pmlp), pmlp_pl); + if (err) + return err; + *p_usable = mlxsw_reg_pmlp_width_get(pmlp_pl) ? true : false; + return 0; +} + +static int mlxsw_sx_port_open(struct net_device *dev) +{ + struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev); + int err; + + err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, true); + if (err) + return err; + netif_start_queue(dev); + return 0; +} + +static int mlxsw_sx_port_stop(struct net_device *dev) +{ + struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev); + + netif_stop_queue(dev); + return mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false); +} + +static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev); + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + struct mlxsw_sx_port_pcpu_stats *pcpu_stats; + const struct mlxsw_tx_info tx_info = { + .local_port = mlxsw_sx_port->local_port, + .is_emad = false, + }; + struct sk_buff *skb_old = NULL; + int err; + + if (unlikely(skb_headroom(skb) < MLXSW_TXHDR_LEN)) { + struct sk_buff *skb_new; + + skb_old = skb; + skb_new = skb_realloc_headroom(skb, MLXSW_TXHDR_LEN); + if (!skb_new) { + this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped); + dev_kfree_skb_any(skb_old); + return NETDEV_TX_OK; + } + skb = skb_new; + } + mlxsw_sx_txhdr_construct(skb, &tx_info); + err = mlxsw_core_skb_transmit(mlxsw_sx, skb, &tx_info); + if (err == -EAGAIN) { + if (skb_old) + dev_kfree_skb_any(skb); + return NETDEV_TX_BUSY; + } + + if (skb_old) + dev_kfree_skb_any(skb_old); + + if (!err) { + pcpu_stats = this_cpu_ptr(mlxsw_sx_port->pcpu_stats); + u64_stats_update_begin(&pcpu_stats->syncp); + pcpu_stats->tx_packets++; + pcpu_stats->tx_bytes += skb->len; + u64_stats_update_end(&pcpu_stats->syncp); + } else { + this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped); + dev_kfree_skb_any(skb); + } + return NETDEV_TX_OK; +} + +static int mlxsw_sx_port_change_mtu(struct net_device *dev, int mtu) +{ + struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev); + int err; + + err = mlxsw_sx_port_mtu_set(mlxsw_sx_port, mtu); + if (err) + return err; + dev->mtu = mtu; + return 0; +} + +static struct rtnl_link_stats64 * +mlxsw_sx_port_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) +{ + struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev); + struct mlxsw_sx_port_pcpu_stats *p; + u64 rx_packets, rx_bytes, tx_packets, tx_bytes; + u32 tx_dropped = 0; + unsigned int start; + int i; + + for_each_possible_cpu(i) { + p = per_cpu_ptr(mlxsw_sx_port->pcpu_stats, i); + do { + start = u64_stats_fetch_begin_irq(&p->syncp); + rx_packets = p->rx_packets; + rx_bytes = p->rx_bytes; + tx_packets = p->tx_packets; + tx_bytes = p->tx_bytes; + } while (u64_stats_fetch_retry_irq(&p->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; + stats->tx_packets += tx_packets; + stats->tx_bytes += tx_bytes; + /* tx_dropped is u32, updated without syncp protection. */ + tx_dropped += p->tx_dropped; + } + stats->tx_dropped = tx_dropped; + return stats; +} + +static const struct net_device_ops mlxsw_sx_port_netdev_ops = { + .ndo_open = mlxsw_sx_port_open, + .ndo_stop = mlxsw_sx_port_stop, + .ndo_start_xmit = mlxsw_sx_port_xmit, + .ndo_change_mtu = mlxsw_sx_port_change_mtu, + .ndo_get_stats64 = mlxsw_sx_port_get_stats64, +}; + +static void mlxsw_sx_port_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *drvinfo) +{ + struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev); + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + + strlcpy(drvinfo->driver, mlxsw_sx_driver_name, sizeof(drvinfo->driver)); + strlcpy(drvinfo->version, mlxsw_sx_driver_version, + sizeof(drvinfo->version)); + snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), + "%d.%d.%d", + mlxsw_sx->bus_info->fw_rev.major, + mlxsw_sx->bus_info->fw_rev.minor, + mlxsw_sx->bus_info->fw_rev.subminor); + strlcpy(drvinfo->bus_info, mlxsw_sx->bus_info->device_name, + sizeof(drvinfo->bus_info)); +} + +struct mlxsw_sx_port_hw_stats { + char str[ETH_GSTRING_LEN]; + u64 (*getter)(char *payload); +}; + +static const struct mlxsw_sx_port_hw_stats mlxsw_sx_port_hw_stats[] = { + { + .str = "a_frames_transmitted_ok", + .getter = mlxsw_reg_ppcnt_a_frames_transmitted_ok_get, + }, + { + .str = "a_frames_received_ok", + .getter = mlxsw_reg_ppcnt_a_frames_received_ok_get, + }, + { + .str = "a_frame_check_sequence_errors", + .getter = mlxsw_reg_ppcnt_a_frame_check_sequence_errors_get, + }, + { + .str = "a_alignment_errors", + .getter = mlxsw_reg_ppcnt_a_alignment_errors_get, + }, + { + .str = "a_octets_transmitted_ok", + .getter = mlxsw_reg_ppcnt_a_octets_transmitted_ok_get, + }, + { + .str = "a_octets_received_ok", + .getter = mlxsw_reg_ppcnt_a_octets_received_ok_get, + }, + { + .str = "a_multicast_frames_xmitted_ok", + .getter = mlxsw_reg_ppcnt_a_multicast_frames_xmitted_ok_get, + }, + { + .str = "a_broadcast_frames_xmitted_ok", + .getter = mlxsw_reg_ppcnt_a_broadcast_frames_xmitted_ok_get, + }, + { + .str = "a_multicast_frames_received_ok", + .getter = mlxsw_reg_ppcnt_a_multicast_frames_received_ok_get, + }, + { + .str = "a_broadcast_frames_received_ok", + .getter = mlxsw_reg_ppcnt_a_broadcast_frames_received_ok_get, + }, + { + .str = "a_in_range_length_errors", + .getter = mlxsw_reg_ppcnt_a_in_range_length_errors_get, + }, + { + .str = "a_out_of_range_length_field", + .getter = mlxsw_reg_ppcnt_a_out_of_range_length_field_get, + }, + { + .str = "a_frame_too_long_errors", + .getter = mlxsw_reg_ppcnt_a_frame_too_long_errors_get, + }, + { + .str = "a_symbol_error_during_carrier", + .getter = mlxsw_reg_ppcnt_a_symbol_error_during_carrier_get, + }, + { + .str = "a_mac_control_frames_transmitted", + .getter = mlxsw_reg_ppcnt_a_mac_control_frames_transmitted_get, + }, + { + .str = "a_mac_control_frames_received", + .getter = mlxsw_reg_ppcnt_a_mac_control_frames_received_get, + }, + { + .str = "a_unsupported_opcodes_received", + .getter = mlxsw_reg_ppcnt_a_unsupported_opcodes_received_get, + }, + { + .str = "a_pause_mac_ctrl_frames_received", + .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_received_get, + }, + { + .str = "a_pause_mac_ctrl_frames_xmitted", + .getter = mlxsw_reg_ppcnt_a_pause_mac_ctrl_frames_transmitted_get, + }, +}; + +#define MLXSW_SX_PORT_HW_STATS_LEN ARRAY_SIZE(mlxsw_sx_port_hw_stats) + +static void mlxsw_sx_port_get_strings(struct net_device *dev, + u32 stringset, u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < MLXSW_SX_PORT_HW_STATS_LEN; i++) { + memcpy(p, mlxsw_sx_port_hw_stats[i].str, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static void mlxsw_sx_port_get_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev); + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char ppcnt_pl[MLXSW_REG_PPCNT_LEN]; + int i; + int err; + + mlxsw_reg_ppcnt_pack(ppcnt_pl, mlxsw_sx_port->local_port); + err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ppcnt), ppcnt_pl); + for (i = 0; i < MLXSW_SX_PORT_HW_STATS_LEN; i++) + data[i] = !err ? mlxsw_sx_port_hw_stats[i].getter(ppcnt_pl) : 0; +} + +static int mlxsw_sx_port_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return MLXSW_SX_PORT_HW_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +struct mlxsw_sx_port_link_mode { + u32 mask; + u32 supported; + u32 advertised; + u32 speed; +}; + +static const struct mlxsw_sx_port_link_mode mlxsw_sx_port_link_mode[] = { + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_100BASE_T, + .supported = SUPPORTED_100baseT_Full, + .advertised = ADVERTISED_100baseT_Full, + .speed = 100, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_100BASE_TX, + .speed = 100, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_SGMII | + MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX, + .supported = SUPPORTED_1000baseKX_Full, + .advertised = ADVERTISED_1000baseKX_Full, + .speed = 1000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_T, + .supported = SUPPORTED_10000baseT_Full, + .advertised = ADVERTISED_10000baseT_Full, + .speed = 10000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CX4 | + MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4, + .supported = SUPPORTED_10000baseKX4_Full, + .advertised = ADVERTISED_10000baseKX4_Full, + .speed = 10000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR | + MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR | + MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR | + MLXSW_REG_PTYS_ETH_SPEED_10GBASE_ER_LR, + .supported = SUPPORTED_10000baseKR_Full, + .advertised = ADVERTISED_10000baseKR_Full, + .speed = 10000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_20GBASE_KR2, + .supported = SUPPORTED_20000baseKR2_Full, + .advertised = ADVERTISED_20000baseKR2_Full, + .speed = 20000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4, + .supported = SUPPORTED_40000baseCR4_Full, + .advertised = ADVERTISED_40000baseCR4_Full, + .speed = 40000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4, + .supported = SUPPORTED_40000baseKR4_Full, + .advertised = ADVERTISED_40000baseKR4_Full, + .speed = 40000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4, + .supported = SUPPORTED_40000baseSR4_Full, + .advertised = ADVERTISED_40000baseSR4_Full, + .speed = 40000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_40GBASE_LR4_ER4, + .supported = SUPPORTED_40000baseLR4_Full, + .advertised = ADVERTISED_40000baseLR4_Full, + .speed = 40000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_25GBASE_CR | + MLXSW_REG_PTYS_ETH_SPEED_25GBASE_KR | + MLXSW_REG_PTYS_ETH_SPEED_25GBASE_SR, + .speed = 25000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR4 | + MLXSW_REG_PTYS_ETH_SPEED_50GBASE_CR2 | + MLXSW_REG_PTYS_ETH_SPEED_50GBASE_KR2, + .speed = 50000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_56GBASE_R4, + .supported = SUPPORTED_56000baseKR4_Full, + .advertised = ADVERTISED_56000baseKR4_Full, + .speed = 56000, + }, + { + .mask = MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4 | + MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 | + MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 | + MLXSW_REG_PTYS_ETH_SPEED_100GBASE_LR4_ER4, + .speed = 100000, + }, +}; + +#define MLXSW_SX_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sx_port_link_mode) + +static u32 mlxsw_sx_from_ptys_supported_port(u32 ptys_eth_proto) +{ + if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR | + MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR | + MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 | + MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 | + MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 | + MLXSW_REG_PTYS_ETH_SPEED_SGMII)) + return SUPPORTED_FIBRE; + + if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR | + MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 | + MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 | + MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4 | + MLXSW_REG_PTYS_ETH_SPEED_1000BASE_KX)) + return SUPPORTED_Backplane; + return 0; +} + +static u32 mlxsw_sx_from_ptys_supported_link(u32 ptys_eth_proto) +{ + u32 modes = 0; + int i; + + for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) { + if (ptys_eth_proto & mlxsw_sx_port_link_mode[i].mask) + modes |= mlxsw_sx_port_link_mode[i].supported; + } + return modes; +} + +static u32 mlxsw_sx_from_ptys_advert_link(u32 ptys_eth_proto) +{ + u32 modes = 0; + int i; + + for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) { + if (ptys_eth_proto & mlxsw_sx_port_link_mode[i].mask) + modes |= mlxsw_sx_port_link_mode[i].advertised; + } + return modes; +} + +static void mlxsw_sx_from_ptys_speed_duplex(bool carrier_ok, u32 ptys_eth_proto, + struct ethtool_cmd *cmd) +{ + u32 speed = SPEED_UNKNOWN; + u8 duplex = DUPLEX_UNKNOWN; + int i; + + if (!carrier_ok) + goto out; + + for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) { + if (ptys_eth_proto & mlxsw_sx_port_link_mode[i].mask) { + speed = mlxsw_sx_port_link_mode[i].speed; + duplex = DUPLEX_FULL; + break; + } + } +out: + ethtool_cmd_speed_set(cmd, speed); + cmd->duplex = duplex; +} + +static u8 mlxsw_sx_port_connector_port(u32 ptys_eth_proto) +{ + if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_SR | + MLXSW_REG_PTYS_ETH_SPEED_40GBASE_SR4 | + MLXSW_REG_PTYS_ETH_SPEED_100GBASE_SR4 | + MLXSW_REG_PTYS_ETH_SPEED_SGMII)) + return PORT_FIBRE; + + if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_CR | + MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4 | + MLXSW_REG_PTYS_ETH_SPEED_100GBASE_CR4)) + return PORT_DA; + + if (ptys_eth_proto & (MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KR | + MLXSW_REG_PTYS_ETH_SPEED_10GBASE_KX4 | + MLXSW_REG_PTYS_ETH_SPEED_40GBASE_KR4 | + MLXSW_REG_PTYS_ETH_SPEED_100GBASE_KR4)) + return PORT_NONE; + + return PORT_OTHER; +} + +static int mlxsw_sx_port_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev); + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char ptys_pl[MLXSW_REG_PTYS_LEN]; + u32 eth_proto_cap; + u32 eth_proto_admin; + u32 eth_proto_oper; + int err; + + mlxsw_reg_ptys_pack(ptys_pl, mlxsw_sx_port->local_port, 0); + err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl); + if (err) { + netdev_err(dev, "Failed to get proto"); + return err; + } + mlxsw_reg_ptys_unpack(ptys_pl, ð_proto_cap, + ð_proto_admin, ð_proto_oper); + + cmd->supported = mlxsw_sx_from_ptys_supported_port(eth_proto_cap) | + mlxsw_sx_from_ptys_supported_link(eth_proto_cap) | + SUPPORTED_Pause | SUPPORTED_Asym_Pause; + cmd->advertising = mlxsw_sx_from_ptys_advert_link(eth_proto_admin); + mlxsw_sx_from_ptys_speed_duplex(netif_carrier_ok(dev), + eth_proto_oper, cmd); + + eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap; + cmd->port = mlxsw_sx_port_connector_port(eth_proto_oper); + cmd->lp_advertising = mlxsw_sx_from_ptys_advert_link(eth_proto_oper); + + cmd->transceiver = XCVR_INTERNAL; + return 0; +} + +static u32 mlxsw_sx_to_ptys_advert_link(u32 advertising) +{ + u32 ptys_proto = 0; + int i; + + for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) { + if (advertising & mlxsw_sx_port_link_mode[i].advertised) + ptys_proto |= mlxsw_sx_port_link_mode[i].mask; + } + return ptys_proto; +} + +static u32 mlxsw_sx_to_ptys_speed(u32 speed) +{ + u32 ptys_proto = 0; + int i; + + for (i = 0; i < MLXSW_SX_PORT_LINK_MODE_LEN; i++) { + if (speed == mlxsw_sx_port_link_mode[i].speed) + ptys_proto |= mlxsw_sx_port_link_mode[i].mask; + } + return ptys_proto; +} + +static int mlxsw_sx_port_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev); + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char ptys_pl[MLXSW_REG_PTYS_LEN]; + u32 speed; + u32 eth_proto_new; + u32 eth_proto_cap; + u32 eth_proto_admin; + bool is_up; + int err; + + speed = ethtool_cmd_speed(cmd); + + eth_proto_new = cmd->autoneg == AUTONEG_ENABLE ? + mlxsw_sx_to_ptys_advert_link(cmd->advertising) : + mlxsw_sx_to_ptys_speed(speed); + + mlxsw_reg_ptys_pack(ptys_pl, mlxsw_sx_port->local_port, 0); + err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl); + if (err) { + netdev_err(dev, "Failed to get proto"); + return err; + } + mlxsw_reg_ptys_unpack(ptys_pl, ð_proto_cap, ð_proto_admin, NULL); + + eth_proto_new = eth_proto_new & eth_proto_cap; + if (!eth_proto_new) { + netdev_err(dev, "Not supported proto admin requested"); + return -EINVAL; + } + if (eth_proto_new == eth_proto_admin) + return 0; + + mlxsw_reg_ptys_pack(ptys_pl, mlxsw_sx_port->local_port, eth_proto_new); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl); + if (err) { + netdev_err(dev, "Failed to set proto admin"); + return err; + } + + err = mlxsw_sx_port_oper_status_get(mlxsw_sx_port, &is_up); + if (err) { + netdev_err(dev, "Failed to get oper status"); + return err; + } + if (!is_up) + return 0; + + err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false); + if (err) { + netdev_err(dev, "Failed to set admin status"); + return err; + } + + err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, true); + if (err) { + netdev_err(dev, "Failed to set admin status"); + return err; + } + + return 0; +} + +static const struct ethtool_ops mlxsw_sx_port_ethtool_ops = { + .get_drvinfo = mlxsw_sx_port_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_strings = mlxsw_sx_port_get_strings, + .get_ethtool_stats = mlxsw_sx_port_get_stats, + .get_sset_count = mlxsw_sx_port_get_sset_count, + .get_settings = mlxsw_sx_port_get_settings, + .set_settings = mlxsw_sx_port_set_settings, +}; + +static int mlxsw_sx_port_attr_get(struct net_device *dev, + struct switchdev_attr *attr) +{ + struct mlxsw_sx_port *mlxsw_sx_port = netdev_priv(dev); + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + + switch (attr->id) { + case SWITCHDEV_ATTR_PORT_PARENT_ID: + attr->u.ppid.id_len = sizeof(mlxsw_sx->hw_id); + memcpy(&attr->u.ppid.id, &mlxsw_sx->hw_id, attr->u.ppid.id_len); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static const struct switchdev_ops mlxsw_sx_port_switchdev_ops = { + .switchdev_port_attr_get = mlxsw_sx_port_attr_get, +}; + +static int mlxsw_sx_hw_id_get(struct mlxsw_sx *mlxsw_sx) +{ + char spad_pl[MLXSW_REG_SPAD_LEN]; + int err; + + err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(spad), spad_pl); + if (err) + return err; + mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_sx->hw_id); + return 0; +} + +static int mlxsw_sx_port_dev_addr_get(struct mlxsw_sx_port *mlxsw_sx_port) +{ + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + struct net_device *dev = mlxsw_sx_port->dev; + char ppad_pl[MLXSW_REG_PPAD_LEN]; + int err; + + mlxsw_reg_ppad_pack(ppad_pl, false, 0); + err = mlxsw_reg_query(mlxsw_sx->core, MLXSW_REG(ppad), ppad_pl); + if (err) + return err; + mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, dev->dev_addr); + /* The last byte value in base mac address is guaranteed + * to be such it does not overflow when adding local_port + * value. + */ + dev->dev_addr[ETH_ALEN - 1] += mlxsw_sx_port->local_port; + return 0; +} + +static int mlxsw_sx_port_stp_state_set(struct mlxsw_sx_port *mlxsw_sx_port, + u16 vid, enum mlxsw_reg_spms_state state) +{ + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char *spms_pl; + int err; + + spms_pl = kmalloc(MLXSW_REG_SPMS_LEN, GFP_KERNEL); + if (!spms_pl) + return -ENOMEM; + mlxsw_reg_spms_pack(spms_pl, mlxsw_sx_port->local_port, vid, state); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(spms), spms_pl); + kfree(spms_pl); + return err; +} + +static int mlxsw_sx_port_speed_set(struct mlxsw_sx_port *mlxsw_sx_port, + u32 speed) +{ + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char ptys_pl[MLXSW_REG_PTYS_LEN]; + + mlxsw_reg_ptys_pack(ptys_pl, mlxsw_sx_port->local_port, speed); + return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(ptys), ptys_pl); +} + +static int +mlxsw_sx_port_mac_learning_mode_set(struct mlxsw_sx_port *mlxsw_sx_port, + enum mlxsw_reg_spmlr_learn_mode mode) +{ + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char spmlr_pl[MLXSW_REG_SPMLR_LEN]; + + mlxsw_reg_spmlr_pack(spmlr_pl, mlxsw_sx_port->local_port, mode); + return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(spmlr), spmlr_pl); +} + +static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port) +{ + struct mlxsw_sx_port *mlxsw_sx_port; + struct net_device *dev; + bool usable; + int err; + + dev = alloc_etherdev(sizeof(struct mlxsw_sx_port)); + if (!dev) + return -ENOMEM; + mlxsw_sx_port = netdev_priv(dev); + mlxsw_sx_port->dev = dev; + mlxsw_sx_port->mlxsw_sx = mlxsw_sx; + mlxsw_sx_port->local_port = local_port; + + mlxsw_sx_port->pcpu_stats = + netdev_alloc_pcpu_stats(struct mlxsw_sx_port_pcpu_stats); + if (!mlxsw_sx_port->pcpu_stats) { + err = -ENOMEM; + goto err_alloc_stats; + } + + dev->netdev_ops = &mlxsw_sx_port_netdev_ops; + dev->ethtool_ops = &mlxsw_sx_port_ethtool_ops; + dev->switchdev_ops = &mlxsw_sx_port_switchdev_ops; + + err = mlxsw_sx_port_dev_addr_get(mlxsw_sx_port); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Port %d: Unable to get port mac address\n", + mlxsw_sx_port->local_port); + goto err_dev_addr_get; + } + + netif_carrier_off(dev); + + dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_LLTX | NETIF_F_SG | + NETIF_F_VLAN_CHALLENGED; + + /* Each packet needs to have a Tx header (metadata) on top all other + * headers. + */ + dev->hard_header_len += MLXSW_TXHDR_LEN; + + err = mlxsw_sx_port_module_check(mlxsw_sx_port, &usable); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to check module\n", + mlxsw_sx_port->local_port); + goto err_port_module_check; + } + + if (!usable) { + dev_dbg(mlxsw_sx->bus_info->dev, "Port %d: Not usable, skipping initialization\n", + mlxsw_sx_port->local_port); + goto port_not_usable; + } + + err = mlxsw_sx_port_swid_set(mlxsw_sx_port, 0); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set SWID\n", + mlxsw_sx_port->local_port); + goto err_port_swid_set; + } + + err = mlxsw_sx_port_speed_set(mlxsw_sx_port, + MLXSW_REG_PTYS_ETH_SPEED_40GBASE_CR4); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set speed\n", + mlxsw_sx_port->local_port); + goto err_port_speed_set; + } + + err = mlxsw_sx_port_mtu_set(mlxsw_sx_port, ETH_DATA_LEN); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set MTU\n", + mlxsw_sx_port->local_port); + goto err_port_mtu_set; + } + + err = mlxsw_sx_port_admin_status_set(mlxsw_sx_port, false); + if (err) + goto err_port_admin_status_set; + + err = mlxsw_sx_port_stp_state_set(mlxsw_sx_port, + MLXSW_PORT_DEFAULT_VID, + MLXSW_REG_SPMS_STATE_FORWARDING); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set STP state\n", + mlxsw_sx_port->local_port); + goto err_port_stp_state_set; + } + + err = mlxsw_sx_port_mac_learning_mode_set(mlxsw_sx_port, + MLXSW_REG_SPMLR_LEARN_MODE_DISABLE); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set MAC learning mode\n", + mlxsw_sx_port->local_port); + goto err_port_mac_learning_mode_set; + } + + err = register_netdev(dev); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to register netdev\n", + mlxsw_sx_port->local_port); + goto err_register_netdev; + } + + mlxsw_sx->ports[local_port] = mlxsw_sx_port; + return 0; + +err_register_netdev: +err_port_admin_status_set: +err_port_mac_learning_mode_set: +err_port_stp_state_set: +err_port_mtu_set: +err_port_speed_set: +err_port_swid_set: +port_not_usable: +err_port_module_check: +err_dev_addr_get: + free_percpu(mlxsw_sx_port->pcpu_stats); +err_alloc_stats: + free_netdev(dev); + return err; +} + +static void mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port) +{ + struct mlxsw_sx_port *mlxsw_sx_port = mlxsw_sx->ports[local_port]; + + if (!mlxsw_sx_port) + return; + unregister_netdev(mlxsw_sx_port->dev); /* This calls ndo_stop */ + mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT); + free_percpu(mlxsw_sx_port->pcpu_stats); +} + +static void mlxsw_sx_ports_remove(struct mlxsw_sx *mlxsw_sx) +{ + int i; + + for (i = 1; i < MLXSW_PORT_MAX_PORTS; i++) + mlxsw_sx_port_remove(mlxsw_sx, i); + kfree(mlxsw_sx->ports); +} + +static int mlxsw_sx_ports_create(struct mlxsw_sx *mlxsw_sx) +{ + size_t alloc_size; + int i; + int err; + + alloc_size = sizeof(struct mlxsw_sx_port *) * MLXSW_PORT_MAX_PORTS; + mlxsw_sx->ports = kzalloc(alloc_size, GFP_KERNEL); + if (!mlxsw_sx->ports) + return -ENOMEM; + + for (i = 1; i < MLXSW_PORT_MAX_PORTS; i++) { + err = mlxsw_sx_port_create(mlxsw_sx, i); + if (err) + goto err_port_create; + } + return 0; + +err_port_create: + for (i--; i >= 1; i--) + mlxsw_sx_port_remove(mlxsw_sx, i); + kfree(mlxsw_sx->ports); + return err; +} + +static void mlxsw_sx_pude_event_func(const struct mlxsw_reg_info *reg, + char *pude_pl, void *priv) +{ + struct mlxsw_sx *mlxsw_sx = priv; + struct mlxsw_sx_port *mlxsw_sx_port; + enum mlxsw_reg_pude_oper_status status; + u8 local_port; + + local_port = mlxsw_reg_pude_local_port_get(pude_pl); + mlxsw_sx_port = mlxsw_sx->ports[local_port]; + if (!mlxsw_sx_port) { + dev_warn(mlxsw_sx->bus_info->dev, "Port %d: Link event received for non-existent port\n", + local_port); + return; + } + + status = mlxsw_reg_pude_oper_status_get(pude_pl); + if (MLXSW_PORT_OPER_STATUS_UP == status) { + netdev_info(mlxsw_sx_port->dev, "link up\n"); + netif_carrier_on(mlxsw_sx_port->dev); + } else { + netdev_info(mlxsw_sx_port->dev, "link down\n"); + netif_carrier_off(mlxsw_sx_port->dev); + } +} + +static struct mlxsw_event_listener mlxsw_sx_pude_event = { + .func = mlxsw_sx_pude_event_func, + .trap_id = MLXSW_TRAP_ID_PUDE, +}; + +static int mlxsw_sx_event_register(struct mlxsw_sx *mlxsw_sx, + enum mlxsw_event_trap_id trap_id) +{ + struct mlxsw_event_listener *el; + char hpkt_pl[MLXSW_REG_HPKT_LEN]; + int err; + + switch (trap_id) { + case MLXSW_TRAP_ID_PUDE: + el = &mlxsw_sx_pude_event; + break; + } + err = mlxsw_core_event_listener_register(mlxsw_sx->core, el, mlxsw_sx); + if (err) + return err; + + mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_FORWARD, + MLXSW_REG_HTGT_TRAP_GROUP_EMAD, trap_id); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(hpkt), hpkt_pl); + if (err) + goto err_event_trap_set; + + return 0; + +err_event_trap_set: + mlxsw_core_event_listener_unregister(mlxsw_sx->core, el, mlxsw_sx); + return err; +} + +static void mlxsw_sx_event_unregister(struct mlxsw_sx *mlxsw_sx, + enum mlxsw_event_trap_id trap_id) +{ + struct mlxsw_event_listener *el; + + switch (trap_id) { + case MLXSW_TRAP_ID_PUDE: + el = &mlxsw_sx_pude_event; + break; + } + mlxsw_core_event_listener_unregister(mlxsw_sx->core, el, mlxsw_sx); +} + +static void mlxsw_sx_rx_listener_func(struct sk_buff *skb, u8 local_port, + void *priv) +{ + struct mlxsw_sx *mlxsw_sx = priv; + struct mlxsw_sx_port *mlxsw_sx_port = mlxsw_sx->ports[local_port]; + struct mlxsw_sx_port_pcpu_stats *pcpu_stats; + + if (unlikely(!mlxsw_sx_port)) { + if (net_ratelimit()) + dev_warn(mlxsw_sx->bus_info->dev, "Port %d: skb received for non-existent port\n", + local_port); + return; + } + + skb->dev = mlxsw_sx_port->dev; + + pcpu_stats = this_cpu_ptr(mlxsw_sx_port->pcpu_stats); + u64_stats_update_begin(&pcpu_stats->syncp); + pcpu_stats->rx_packets++; + pcpu_stats->rx_bytes += skb->len; + u64_stats_update_end(&pcpu_stats->syncp); + + skb->protocol = eth_type_trans(skb, skb->dev); + netif_receive_skb(skb); +} + +static const struct mlxsw_rx_listener mlxsw_sx_rx_listener[] = { + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_FDB_MC, + }, + /* Traps for specific L2 packet types, not trapped as FDB MC */ + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_STP, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_LACP, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_EAPOL, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_LLDP, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_MMRP, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_MVRP, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_RPVST, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_DHCP, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_IGMP_QUERY, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_IGMP_V1_REPORT, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_IGMP_V2_REPORT, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_IGMP_V2_LEAVE, + }, + { + .func = mlxsw_sx_rx_listener_func, + .local_port = MLXSW_PORT_DONT_CARE, + .trap_id = MLXSW_TRAP_ID_IGMP_V3_REPORT, + }, +}; + +static int mlxsw_sx_traps_init(struct mlxsw_sx *mlxsw_sx) +{ + char htgt_pl[MLXSW_REG_HTGT_LEN]; + char hpkt_pl[MLXSW_REG_HPKT_LEN]; + int i; + int err; + + mlxsw_reg_htgt_pack(htgt_pl, MLXSW_REG_HTGT_TRAP_GROUP_RX); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(htgt), htgt_pl); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(mlxsw_sx_rx_listener); i++) { + err = mlxsw_core_rx_listener_register(mlxsw_sx->core, + &mlxsw_sx_rx_listener[i], + mlxsw_sx); + if (err) + goto err_rx_listener_register; + + mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_TRAP_TO_CPU, + MLXSW_REG_HTGT_TRAP_GROUP_RX, + mlxsw_sx_rx_listener[i].trap_id); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(hpkt), hpkt_pl); + if (err) + goto err_rx_trap_set; + } + return 0; + +err_rx_trap_set: + mlxsw_core_rx_listener_unregister(mlxsw_sx->core, + &mlxsw_sx_rx_listener[i], + mlxsw_sx); +err_rx_listener_register: + for (i--; i >= 0; i--) { + mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_FORWARD, + MLXSW_REG_HTGT_TRAP_GROUP_RX, + mlxsw_sx_rx_listener[i].trap_id); + mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(hpkt), hpkt_pl); + + mlxsw_core_rx_listener_unregister(mlxsw_sx->core, + &mlxsw_sx_rx_listener[i], + mlxsw_sx); + } + return err; +} + +static void mlxsw_sx_traps_fini(struct mlxsw_sx *mlxsw_sx) +{ + char hpkt_pl[MLXSW_REG_HPKT_LEN]; + int i; + + for (i = 0; i < ARRAY_SIZE(mlxsw_sx_rx_listener); i++) { + mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_FORWARD, + MLXSW_REG_HTGT_TRAP_GROUP_RX, + mlxsw_sx_rx_listener[i].trap_id); + mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(hpkt), hpkt_pl); + + mlxsw_core_rx_listener_unregister(mlxsw_sx->core, + &mlxsw_sx_rx_listener[i], + mlxsw_sx); + } +} + +static int mlxsw_sx_flood_init(struct mlxsw_sx *mlxsw_sx) +{ + char sfgc_pl[MLXSW_REG_SFGC_LEN]; + char sgcr_pl[MLXSW_REG_SGCR_LEN]; + char *smid_pl; + char *sftr_pl; + int err; + + /* Due to FW bug, we must configure SMID. */ + smid_pl = kmalloc(MLXSW_REG_SMID_LEN, GFP_KERNEL); + if (!smid_pl) + return -ENOMEM; + mlxsw_reg_smid_pack(smid_pl, MLXSW_PORT_MID); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(smid), smid_pl); + kfree(smid_pl); + if (err) + return err; + + /* Configure a flooding table, which includes only CPU port. */ + sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); + if (!sftr_pl) + return -ENOMEM; + mlxsw_reg_sftr_pack(sftr_pl, 0, 0, MLXSW_REG_SFGC_TABLE_TYPE_SINGLE, 0); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sftr), sftr_pl); + kfree(sftr_pl); + if (err) + return err; + + /* Flood different packet types using the flooding table. */ + mlxsw_reg_sfgc_pack(sfgc_pl, + MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST, + MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + MLXSW_REG_SFGC_TABLE_TYPE_SINGLE, + 0); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl); + if (err) + return err; + + mlxsw_reg_sfgc_pack(sfgc_pl, + MLXSW_REG_SFGC_TYPE_BROADCAST, + MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + MLXSW_REG_SFGC_TABLE_TYPE_SINGLE, + 0); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl); + if (err) + return err; + + mlxsw_reg_sfgc_pack(sfgc_pl, + MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP, + MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + MLXSW_REG_SFGC_TABLE_TYPE_SINGLE, + 0); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl); + if (err) + return err; + + mlxsw_reg_sfgc_pack(sfgc_pl, + MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6, + MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + MLXSW_REG_SFGC_TABLE_TYPE_SINGLE, + 0); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl); + if (err) + return err; + + mlxsw_reg_sfgc_pack(sfgc_pl, + MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4, + MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + MLXSW_REG_SFGC_TABLE_TYPE_SINGLE, + 0); + err = mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sfgc), sfgc_pl); + if (err) + return err; + + mlxsw_reg_sgcr_pack(sgcr_pl, true); + return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sgcr), sgcr_pl); +} + +static int mlxsw_sx_init(void *priv, struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info) +{ + struct mlxsw_sx *mlxsw_sx = priv; + int err; + + mlxsw_sx->core = mlxsw_core; + mlxsw_sx->bus_info = mlxsw_bus_info; + + err = mlxsw_sx_hw_id_get(mlxsw_sx); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Failed to get switch HW ID\n"); + return err; + } + + err = mlxsw_sx_ports_create(mlxsw_sx); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Failed to create ports\n"); + return err; + } + + err = mlxsw_sx_event_register(mlxsw_sx, MLXSW_TRAP_ID_PUDE); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Failed to register for PUDE events\n"); + goto err_event_register; + } + + err = mlxsw_sx_traps_init(mlxsw_sx); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Failed to set traps for RX\n"); + goto err_rx_listener_register; + } + + err = mlxsw_sx_flood_init(mlxsw_sx); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Failed to initialize flood tables\n"); + goto err_flood_init; + } + + return 0; + +err_flood_init: + mlxsw_sx_traps_fini(mlxsw_sx); +err_rx_listener_register: + mlxsw_sx_event_unregister(mlxsw_sx, MLXSW_TRAP_ID_PUDE); +err_event_register: + mlxsw_sx_ports_remove(mlxsw_sx); + return err; +} + +static void mlxsw_sx_fini(void *priv) +{ + struct mlxsw_sx *mlxsw_sx = priv; + + mlxsw_sx_traps_fini(mlxsw_sx); + mlxsw_sx_event_unregister(mlxsw_sx, MLXSW_TRAP_ID_PUDE); + mlxsw_sx_ports_remove(mlxsw_sx); +} + +static struct mlxsw_config_profile mlxsw_sx_config_profile = { + .used_max_vepa_channels = 1, + .max_vepa_channels = 0, + .used_max_lag = 1, + .max_lag = 64, + .used_max_port_per_lag = 1, + .max_port_per_lag = 16, + .used_max_mid = 1, + .max_mid = 7000, + .used_max_pgt = 1, + .max_pgt = 0, + .used_max_system_port = 1, + .max_system_port = 48000, + .used_max_vlan_groups = 1, + .max_vlan_groups = 127, + .used_max_regions = 1, + .max_regions = 400, + .used_flood_tables = 1, + .max_flood_tables = 2, + .max_vid_flood_tables = 1, + .used_flood_mode = 1, + .flood_mode = 3, + .used_max_ib_mc = 1, + .max_ib_mc = 0, + .used_max_pkey = 1, + .max_pkey = 0, + .swid_config = { + { + .used_type = 1, + .type = MLXSW_PORT_SWID_TYPE_ETH, + } + }, +}; + +static struct mlxsw_driver mlxsw_sx_driver = { + .kind = MLXSW_DEVICE_KIND_SWITCHX2, + .owner = THIS_MODULE, + .priv_size = sizeof(struct mlxsw_sx), + .init = mlxsw_sx_init, + .fini = mlxsw_sx_fini, + .txhdr_construct = mlxsw_sx_txhdr_construct, + .txhdr_len = MLXSW_TXHDR_LEN, + .profile = &mlxsw_sx_config_profile, +}; + +static int __init mlxsw_sx_module_init(void) +{ + return mlxsw_core_driver_register(&mlxsw_sx_driver); +} + +static void __exit mlxsw_sx_module_exit(void) +{ + mlxsw_core_driver_unregister(&mlxsw_sx_driver); +} + +module_init(mlxsw_sx_module_init); +module_exit(mlxsw_sx_module_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Jiri Pirko "); +MODULE_DESCRIPTION("Mellanox SwitchX-2 driver"); +MODULE_MLXSW_DRIVER_ALIAS(MLXSW_DEVICE_KIND_SWITCHX2); diff --git a/drivers/net/ethernet/mellanox/mlxsw/txheader.h b/drivers/net/ethernet/mellanox/mlxsw/txheader.h new file mode 100644 index 000000000000..06fc46c78a0b --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/txheader.h @@ -0,0 +1,80 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/txheader.h + * Copyright (c) 2015 Mellanox Technologies. All rights reserved. + * Copyright (c) 2015 Ido Schimmel + * Copyright (c) 2015 Jiri Pirko + * + * 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 _MLXSW_TXHEADER_H +#define _MLXSW_TXHEADER_H + +#define MLXSW_TXHDR_LEN 0x10 +#define MLXSW_TXHDR_VERSION_0 0 + +enum { + MLXSW_TXHDR_ETH_CTL, + MLXSW_TXHDR_ETH_DATA, +}; + +#define MLXSW_TXHDR_PROTO_ETH 1 + +enum { + MLXSW_TXHDR_ETCLASS_0, + MLXSW_TXHDR_ETCLASS_1, + MLXSW_TXHDR_ETCLASS_2, + MLXSW_TXHDR_ETCLASS_3, + MLXSW_TXHDR_ETCLASS_4, + MLXSW_TXHDR_ETCLASS_5, + MLXSW_TXHDR_ETCLASS_6, + MLXSW_TXHDR_ETCLASS_7, +}; + +enum { + MLXSW_TXHDR_RDQ_OTHER, + MLXSW_TXHDR_RDQ_EMAD = 0x1f, +}; + +#define MLXSW_TXHDR_CTCLASS3 0 +#define MLXSW_TXHDR_CPU_SIG 0 +#define MLXSW_TXHDR_SIG 0xE0E0 +#define MLXSW_TXHDR_STCLASS_NONE 0 + +enum { + MLXSW_TXHDR_NOT_EMAD, + MLXSW_TXHDR_EMAD, +}; + +enum { + MLXSW_TXHDR_TYPE_DATA, + MLXSW_TXHDR_TYPE_CONTROL = 6, +}; + +#endif -- cgit v1.3-6-gb490 From 4a546ec364633fcbe5709811230d7e0580c9dc1d Mon Sep 17 00:00:00 2001 From: Frederic Danis Date: Mon, 27 Jul 2015 18:02:25 +0200 Subject: Bluetooth: btbcm: Add BCM4330B1 UART device Add "waiting for configuration" address. Add lmp_subver and firmware name for BCM4330B1 controller. Signed-off-by: Frederic Danis Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btbcm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 9ceb8ac68fdc..02ed816a18f9 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -34,6 +34,7 @@ #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}}) +#define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}}) int btbcm_check_bdaddr(struct hci_dev *hdev) { @@ -66,9 +67,13 @@ int btbcm_check_bdaddr(struct hci_dev *hdev) * * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller * with waiting for configuration state. + * + * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller + * with waiting for configuration state. */ if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) || - !bacmp(&bda->bdaddr, BDADDR_BCM4324B3)) { + !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) || + !bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) { BT_INFO("%s: BCM: Using default device address (%pMR)", hdev->name, &bda->bdaddr); set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); @@ -241,6 +246,7 @@ static const struct { u16 subver; const char *name; } bcm_uart_subver_table[] = { + { 0x4103, "BCM4330B1" }, /* 002.001.003 */ { 0x410e, "BCM43341B0" }, /* 002.001.014 */ { 0x4406, "BCM4324B3" }, /* 002.004.006 */ { 0x610c, "BCM4354" }, /* 003.001.012 */ -- cgit v1.3-6-gb490 From d63b282645f56641900e15fb14572bdf6c9bed27 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 17 Jul 2015 11:12:25 -0600 Subject: Bluetooth: btusb: match generic class code in interface descriptor btusb currently has a generic match on USB device descriptors: { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, However, http://www.usb.org/developers/defined_class states: Base Class E0h (Wireless Controller) This base class is defined for devices that are Wireless controllers. Values not shown in the table below are reserved. These class codes are to be used in Interface Descriptors, with the exception of the Bluetooth class code which can also be used in a Device Descriptor. Add a match on the interface descriptors accordingly. This fixes compatibility with the RTL8723AU device shown below. This device conforms to the USB Interface Association Descriptor specification, which requires the device to have class ef/02/01. The extra IAD descriptor then specifies that interfaces 0 and 1 belong to the same function/driver, which is true. Provided that the Bluetooth device class spec accepts use of the IAD, I imagine that technically, all btusb devices should be configured like this. T: Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 3 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0bda ProdID=0724 Rev= 2.00 S: Manufacturer=Realtek S: Product=802.11n WLAN Adapter S: SerialNumber=00e04c000001 C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=500mA A: FirstIf#= 0 IfCount= 2 Cls=e0(wlcon) Sub=01 Prot=01 I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 4 Cls=ff(vend.) Sub=ff Prot=ff Driver=rtl8723au E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=03(Int.) MxPS= 64 Ivl=500us Signed-off-by: Daniel Drake Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 93339a4f25f1..cc92b0f84a51 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -68,6 +68,9 @@ static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth AMP device */ { USB_DEVICE_INFO(0xe0, 0x01, 0x04), .driver_info = BTUSB_AMP }, + /* Generic Bluetooth USB interface */ + { USB_INTERFACE_INFO(0xe0, 0x01, 0x01) }, + /* Apple-specific (Broadcom) devices */ { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01), .driver_info = BTUSB_BCM_APPLE }, -- cgit v1.3-6-gb490 From 8b44f0dd2f90acd6c8842537223b39f890f2e713 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 30 Jul 2015 12:13:29 +0200 Subject: at86rf230: remove hrtimer on 1 usec delay According Documentation/timers/timers-howto.txt the usually case for setting up a hrtimer takes > ~10us. So we should use udelay in this case so we are sure that the state change was done, before doing the state change assert. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index f7bd9f3ddaac..d0d5bf6cbb68 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -545,7 +545,9 @@ at86rf230_async_state_delay(void *context) } /* Default delay is 1us in the most cases */ - tim = ktime_set(0, NSEC_PER_USEC); + udelay(1); + at86rf230_async_state_timer(&ctx->timer); + return; change: hrtimer_start(&ctx->timer, tim, HRTIMER_MODE_REL); -- cgit v1.3-6-gb490 From 7371c0a5c205455d69f8e8dc1d16791f08a38155 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 29 Jul 2015 19:42:09 -0400 Subject: crypto: nx - don't err if compressed output > input Return success instead of error if compression succeeds but the output is larger than the input. It's unlikely that the caller will use the compressed data since it's larger than the original uncompressed data, but there was no error and returning an error code is incorrect. Further, for testing small input buffers, the output is likely to be larger than the input and success needs to be returned to verify the test. Signed-off-by: Dan Streetman Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-pseries.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-pseries.c b/drivers/crypto/nx/nx-842-pseries.c index b6a26907e11f..f4cbde03c6ad 100644 --- a/drivers/crypto/nx/nx-842-pseries.c +++ b/drivers/crypto/nx/nx-842-pseries.c @@ -226,9 +226,12 @@ static int nx842_validate_result(struct device *dev, switch (csb->completion_code) { case 0: /* Completed without error */ break; - case 64: /* Target bytes > Source bytes during compression */ + case 64: /* Compression ok, but output larger than input */ + dev_dbg(dev, "%s: output size larger than input size\n", + __func__); + break; case 13: /* Output buffer too small */ - dev_dbg(dev, "%s: Compression output larger than input\n", + dev_dbg(dev, "%s: Out of space in output buffer\n", __func__); return -ENOSPC; case 66: /* Input data contains an illegal template field */ -- cgit v1.3-6-gb490 From 844190dbeb5f37af5218f8587aeae25682fcb3a1 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 29 Jul 2015 19:43:29 -0400 Subject: crypto: nx - use be32_to_cpu for __be32 field in debug msg One of the debug messages in the NX 842 PowerNV driver is missing the required be32_to_cpu() wrapper when accessing the __be32 field csb->count. Add the wrapper so the message will show the correct count. Signed-off-by: Dan Streetman Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-842-powernv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c index 684ce51d2d68..3750e13d8721 100644 --- a/drivers/crypto/nx/nx-842-powernv.c +++ b/drivers/crypto/nx/nx-842-powernv.c @@ -346,7 +346,8 @@ static int wait_for_csb(struct nx842_workmem *wmem, } /* successful completion */ - pr_debug_ratelimited("Processed %u bytes in %lu us\n", csb->count, + pr_debug_ratelimited("Processed %u bytes in %lu us\n", + be32_to_cpu(csb->count), (unsigned long)ktime_us_delta(now, start)); return 0; -- cgit v1.3-6-gb490 From c8ecfc1c33979054fb631d2066745d03ce322b6f Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 29 Jul 2015 11:40:38 +0300 Subject: ath10k: fix memory alloc failure in qca99x0 during wmi svc rdy event Host memory required for firmware is allocated while handling wmi service ready event. Right now, wmi service ready is handled in tasklet context and it calls dma_alloc_coherent() with atomic flag (GFP_ATOMIC) to allocate memory in host needed for firmware. The problem is, dma_alloc_coherent() with GFP_ATOMIC fails in the platform (at least in AP platform) where it has less atomic pool memory (< 2mb). QCA99X0 requires around 2 MB of host memory for one card, having additional QCA99X0 card in the same platform will require similarly amount of memory. So, it's not guaranteed that all the platform will have enough atomic memory pool. Fix this issue, by handling wmi service ready event in workqueue context and calling dma_alloc_coherent() with GFP_KERNEL. mac80211 work queue will not be ready at the time of handling wmi service ready. So, it can't be used to handle wmi service ready. Also, register work gets scheduled during insmod in existing ath10k_wq and waits for wmi service ready to completed. Both workqueue can't be used for this purpose. New auxiliary workqueue is added to handle wmi service ready. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 11 +++++++++- drivers/net/wireless/ath/ath10k/core.h | 5 +++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 34 +++++++++++++++++++++++++------ 4 files changed, 44 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 29d2541d87dd..25510679fd2e 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1649,6 +1649,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, if (!ar->workqueue) goto err_free_mac; + ar->workqueue_aux = create_singlethread_workqueue("ath10k_aux_wq"); + if (!ar->workqueue_aux) + goto err_free_wq; + mutex_init(&ar->conf_mutex); spin_lock_init(&ar->data_lock); @@ -1669,10 +1673,12 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ret = ath10k_debug_create(ar); if (ret) - goto err_free_wq; + goto err_free_aux_wq; return ar; +err_free_aux_wq: + destroy_workqueue(ar->workqueue_aux); err_free_wq: destroy_workqueue(ar->workqueue); @@ -1688,6 +1694,9 @@ void ath10k_core_destroy(struct ath10k *ar) flush_workqueue(ar->workqueue); destroy_workqueue(ar->workqueue); + flush_workqueue(ar->workqueue_aux); + destroy_workqueue(ar->workqueue_aux); + ath10k_debug_destroy(ar); ath10k_mac_destroy(ar); } diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 35f40388b622..6a387bac27b0 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -694,6 +694,8 @@ struct ath10k { struct completion vdev_setup_done; struct workqueue_struct *workqueue; + /* Auxiliary workqueue */ + struct workqueue_struct *workqueue_aux; /* prevents concurrent FW reconfiguration */ struct mutex conf_mutex; @@ -716,6 +718,9 @@ struct ath10k { int num_active_peers; int num_tids; + struct work_struct svc_rdy_work; + struct sk_buff *svc_rdy_skb; + struct work_struct offchan_tx_work; struct sk_buff_head offchan_tx_queue; struct completion offchan_tx_completed; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 34fbc8fddb72..567b79720b69 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -519,7 +519,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) break; case WMI_TLV_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); - break; + return; case WMI_TLV_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 3d46813b9beb..e6d6b420ecea 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3789,7 +3789,7 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, ar->wmi.mem_chunks[idx].vaddr = dma_alloc_coherent(ar->dev, pool_size, &paddr, - GFP_ATOMIC); + GFP_KERNEL); if (!ar->wmi.mem_chunks[idx].vaddr) { ath10k_warn(ar, "failed to allocate memory chunk\n"); return -ENOMEM; @@ -3878,12 +3878,19 @@ ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } -void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) +static void ath10k_wmi_event_service_ready_work(struct work_struct *work) { + struct ath10k *ar = container_of(work, struct ath10k, svc_rdy_work); + struct sk_buff *skb = ar->svc_rdy_skb; struct wmi_svc_rdy_ev_arg arg = {}; u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; int ret; + if (!skb) { + ath10k_warn(ar, "invalid service ready event skb\n"); + return; + } + ret = ath10k_wmi_pull_svc_rdy(ar, skb, &arg); if (ret) { ath10k_warn(ar, "failed to parse service ready: %d\n", ret); @@ -4003,9 +4010,17 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) __le32_to_cpu(arg.eeprom_rd), __le32_to_cpu(arg.num_mem_reqs)); + dev_kfree_skb(skb); + ar->svc_rdy_skb = NULL; complete(&ar->wmi.service_ready); } +void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) +{ + ar->svc_rdy_skb = skb; + queue_work(ar->workqueue_aux, &ar->svc_rdy_work); +} + static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb, struct wmi_rdy_ev_arg *arg) { @@ -4177,7 +4192,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb) break; case WMI_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); - break; + return; case WMI_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; @@ -4298,7 +4313,7 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb) break; case WMI_10X_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); - break; + return; case WMI_10X_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; @@ -4409,7 +4424,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb) break; case WMI_10_2_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); - break; + return; case WMI_10_2_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; @@ -4461,7 +4476,7 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) break; case WMI_10_4_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); - break; + return; case WMI_10_4_SCAN_EVENTID: ath10k_wmi_event_scan(ar, skb); break; @@ -6512,6 +6527,8 @@ int ath10k_wmi_attach(struct ath10k *ar) init_completion(&ar->wmi.service_ready); init_completion(&ar->wmi.unified_ready); + INIT_WORK(&ar->svc_rdy_work, ath10k_wmi_event_service_ready_work); + return 0; } @@ -6519,6 +6536,11 @@ void ath10k_wmi_detach(struct ath10k *ar) { int i; + cancel_work_sync(&ar->svc_rdy_work); + + if (ar->svc_rdy_skb) + dev_kfree_skb(ar->svc_rdy_skb); + /* free the host memory chunks requested by firmware */ for (i = 0; i < ar->wmi.num_mem_chunks; i++) { dma_free_coherent(ar->dev, -- cgit v1.3-6-gb490 From 1201844e6ddc4e13dfc1a7ffbba0cfd180944679 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Wed, 29 Jul 2015 11:40:38 +0300 Subject: ath10k: increase max client to 512 in qca99x0 When max client was set to 512 in qca99x0, there was host memory alloc failure during wmi service ready event handling. This issue got resolved now, increasing max client limit from 256 to 512. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 7bfb9e276d17..d9de4a738470 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -360,10 +360,7 @@ enum ath10k_hw_rate_cck { (TARGET_10_4_NUM_VDEVS)) #define TARGET_10_4_ACTIVE_PEERS 0 -/* TODO: increase qcache max client limit to 512 after - * testing with 512 client. - */ -#define TARGET_10_4_NUM_QCACHE_PEERS_MAX 256 +#define TARGET_10_4_NUM_QCACHE_PEERS_MAX 512 #define TARGET_10_4_QCACHE_ACTIVE_PEERS 50 #define TARGET_10_4_NUM_OFFLOAD_PEERS 0 #define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0 -- cgit v1.3-6-gb490 From 8a055a8adc875768223be2dfc33de5dc70212756 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 29 Jul 2015 11:40:39 +0300 Subject: ath10k: add QCA99X0 to supported device list Add vendor/device id of QCA99X0 V2.0 to pci id table and QCA99X0_HW_2_0_CHIP_ID_REV to ath10k_pci_supp_chips[] for QCA99X0 to get detected by the driver. kvalo: now QCA99X0 family of chipsets is supported by ath10k. Tested client, AP and monitor mode with QCA9990. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index a69bfa41c68b..f00b251ec9ce 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -64,6 +64,7 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */ + { PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */ {0} }; @@ -78,6 +79,7 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, + { QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV }, }; static void ath10k_pci_buffer_cleanup(struct ath10k *ar); -- cgit v1.3-6-gb490 From ae7d3821a769a4ac64d4c244b5cd8b134768d452 Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Wed, 29 Jul 2015 11:58:50 +0300 Subject: ath10k: initialize msdu ext. descriptor before use Initial QCA99X0 support has a known issue with TCP Tx throughput. All other path such as UDP Tx/Rx and TCP Rx meet their expectation (> 900Mbps), but TCP Tx marked as low as 5Mbps when single pair is used on iperf. The root cause is turned out because TSO flag is not initialized properly so that firmware configures TSO in wrong way. TSO flags in msdu extension descriptor is required to be reset to indicate firmware there is no TSO is enabled, otherwise it could act as TSO is enabled which causes huge throughput drop. In fact, it's enough by resetting TSO flags only to prevent the unexpected behavior, but initializing whole msdu ext. descriptor will help to clear uncertainty of firmware could bring on as it constantly updated. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_tx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 81fd81f4df01..704bb5e07193 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -543,6 +543,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) /* pass through */ case ATH10K_HW_TXRX_ETHERNET: if (ar->hw_params.continuous_frag_desc) { + memset(&htt->frag_desc.vaddr[msdu_id], 0, + sizeof(struct htt_msdu_ext_desc)); frags = (struct htt_data_tx_desc_frag *) &htt->frag_desc.vaddr[msdu_id].frags; ext_desc = &htt->frag_desc.vaddr[msdu_id]; @@ -550,8 +552,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) __cpu_to_le32(skb_cb->paddr); frags[0].tword_addr.paddr_hi = 0; frags[0].tword_addr.len_16 = __cpu_to_le16(msdu->len); - frags[1].tword_addr.paddr_lo = 0; - frags[1].tword_addr.paddr_hi = 0; frags_paddr = htt->frag_desc.paddr + (sizeof(struct htt_msdu_ext_desc) * msdu_id); -- cgit v1.3-6-gb490 From 49bda21266fdf195142e8b5dea057f09e96ada9f Mon Sep 17 00:00:00 2001 From: Michał Pecio Date: Sun, 26 Jul 2015 11:14:34 +0200 Subject: USB: pl2303: fix baud-rate divisor calculations This commit fixes the following issues: 1. The 9th bit of buf was believed to be the LSB of divisor's exponent, but the hardware interprets it as MSB (9th bit) of the mantissa. The exponent is actually one bit shorter and applies to base 4, not 2 as previously believed. 2. Loop iterations doubled the exponent instead of incrementing. 3. The exponent wasn't checked for overflow. 4. The function returned requested rate instead of actual rate. Due to issue #2, the old code deviated from the wrong formula described in #1 and actually yielded correct rates when divisor was lower than 4096 by using exponents of 0, 2 or 4 base-2, interpreted as 0, 1, 2 base-4 with the 9th mantissa bit clear. However, at 93.75 kbaud or less the rate turned out too slow due to #2 or too fast due to #2 and #3. I tested this patch by sending and validating 0x00,0x01,..,0xff to an FTDI dongle at 234, 987, 2401, 9601, 31415, 115199, 250k, 500k, 750k, 1M, 1.5M, 3M+1 baud. All rates passed. I also used pv to check speed at some rates unsupported by FTDI: 45 (the lowest possible), 2M, 4M, 5M and 6M-1. Looked sane. Signed-off-by: Michal Pecio Fixes: 399aa9a75ad3 ("USB: pl2303: use divisors for unsupported baud rates") Cc: stable # v3.18 [johan: update summary ] Signed-off-by: Johan Hovold --- drivers/usb/serial/pl2303.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index f5257af33ecf..ae682e4eeaef 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -362,21 +362,38 @@ static speed_t pl2303_encode_baud_rate_direct(unsigned char buf[4], static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4], speed_t baud) { - unsigned int tmp; + unsigned int baseline, mantissa, exponent; /* * Apparently the formula is: - * baudrate = 12M * 32 / (2^buf[1]) / buf[0] + * baudrate = 12M * 32 / (mantissa * 4^exponent) + * where + * mantissa = buf[8:0] + * exponent = buf[11:9] */ - tmp = 12000000 * 32 / baud; + baseline = 12000000 * 32; + mantissa = baseline / baud; + if (mantissa == 0) + mantissa = 1; /* Avoid dividing by zero if baud > 32*12M. */ + exponent = 0; + while (mantissa >= 512) { + if (exponent < 7) { + mantissa >>= 2; /* divide by 4 */ + exponent++; + } else { + /* Exponent is maxed. Trim mantissa and leave. */ + mantissa = 511; + break; + } + } + buf[3] = 0x80; buf[2] = 0; - buf[1] = (tmp >= 256); - while (tmp >= 256) { - tmp >>= 2; - buf[1] <<= 1; - } - buf[0] = tmp; + buf[1] = exponent << 1 | mantissa >> 8; + buf[0] = mantissa & 0xff; + + /* Calculate and return the exact baud rate. */ + baud = (baseline / mantissa) >> (exponent << 1); return baud; } -- cgit v1.3-6-gb490 From b2fb5b1a0f50d3ebc12342c8d8dead245e9c9d4e Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:27 +0530 Subject: usb: dwc3: ep0: Fix mem corruption on OUT transfers of more than 512 bytes DWC3 uses bounce buffer to handle non max packet aligned OUT transfers and the size of bounce buffer is 512 bytes. However if the host initiates OUT transfers of size more than 512 bytes (and non max packet aligned), the driver throws a WARN dump but still programs the TRB to receive more than 512 bytes. This will cause bounce buffer to overflow and corrupt the adjacent memory locations which can be fatal. Fix it by programming the TRB to receive a maximum of DWC3_EP0_BOUNCE_SIZE (512) bytes. Cc: # 3.4+ Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 69e769c35cf5..06ecd1e6871c 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -820,6 +820,11 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, unsigned maxp = ep0->endpoint.maxpacket; transfer_size += (maxp - (transfer_size % maxp)); + + /* Maximum of DWC3_EP0_BOUNCE_SIZE can only be received */ + if (transfer_size > DWC3_EP0_BOUNCE_SIZE) + transfer_size = DWC3_EP0_BOUNCE_SIZE; + transferred = min_t(u32, ur->length, transfer_size - length); memcpy(ur->buf, dwc->ep0_bounce, transferred); @@ -941,11 +946,14 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, return; } - WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE); - maxpacket = dep->endpoint.maxpacket; transfer_size = roundup(req->request.length, maxpacket); + if (transfer_size > DWC3_EP0_BOUNCE_SIZE) { + dev_WARN(dwc->dev, "bounce buf can't handle req len\n"); + transfer_size = DWC3_EP0_BOUNCE_SIZE; + } + dwc->ep0_bounced = true; /* -- cgit v1.3-6-gb490 From 2e5464da4e7dc55e1751d2beb3e6e78f35020756 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:28 +0530 Subject: usb: dwc3: ep0: use _roundup_ to calculate the transfer size No functional change. Used _roundup_ macro to calculate the transfer size aligned to maxpacket in dwc3_ep0_complete_data. It also makes it similar to how transfer size is calculated in __dwc3_ep0_do_control_data. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 06ecd1e6871c..672d55a6d598 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -816,10 +816,8 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, length = trb->size & DWC3_TRB_SIZE_MASK; if (dwc->ep0_bounced) { - unsigned transfer_size = ur->length; unsigned maxp = ep0->endpoint.maxpacket; - - transfer_size += (maxp - (transfer_size % maxp)); + unsigned transfer_size = roundup(ur->length, maxp); /* Maximum of DWC3_EP0_BOUNCE_SIZE can only be received */ if (transfer_size > DWC3_EP0_BOUNCE_SIZE) -- cgit v1.3-6-gb490 From 8a3442205630d52b1b1777efe07c80832aa5ee73 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:29 +0530 Subject: usb: dwc3: ep0: preparation for handling non maxpacket aligned transfers > 512 No functional change. This is in preparation for handling non maxpacket aligned transfers greater than bounce buffer size. This is basically to avoid code duplication when using chained TRB transfers to handle non maxpacket aligned transfers greater than bounce buffer size. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 672d55a6d598..396c2af00fed 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -783,7 +783,11 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, struct usb_request *ur; struct dwc3_trb *trb; struct dwc3_ep *ep0; - u32 transferred; + unsigned transfer_size = 0; + unsigned maxp; + unsigned remaining_ur_length; + void *buf; + u32 transferred = 0; u32 status; u32 length; u8 epnum; @@ -812,20 +816,24 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, } ur = &r->request; + buf = ur->buf; + remaining_ur_length = ur->length; length = trb->size & DWC3_TRB_SIZE_MASK; + maxp = ep0->endpoint.maxpacket; + if (dwc->ep0_bounced) { - unsigned maxp = ep0->endpoint.maxpacket; - unsigned transfer_size = roundup(ur->length, maxp); + transfer_size = roundup((ur->length - transfer_size), + maxp); /* Maximum of DWC3_EP0_BOUNCE_SIZE can only be received */ if (transfer_size > DWC3_EP0_BOUNCE_SIZE) transfer_size = DWC3_EP0_BOUNCE_SIZE; - transferred = min_t(u32, ur->length, - transfer_size - length); - memcpy(ur->buf, dwc->ep0_bounce, transferred); + transferred = min_t(u32, remaining_ur_length, + transfer_size - length); + memcpy(buf, dwc->ep0_bounce, transferred); } else { transferred = ur->length - length; } @@ -934,7 +942,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, DWC3_TRBCTL_CONTROL_DATA); } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && (dep->number == 0)) { - u32 transfer_size; + u32 transfer_size = 0; u32 maxpacket; ret = usb_gadget_map_request(&dwc->gadget, &req->request, @@ -945,7 +953,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, } maxpacket = dep->endpoint.maxpacket; - transfer_size = roundup(req->request.length, maxpacket); + transfer_size = roundup((req->request.length - transfer_size), + maxpacket); if (transfer_size > DWC3_EP0_BOUNCE_SIZE) { dev_WARN(dwc->dev, "bounce buf can't handle req len\n"); -- cgit v1.3-6-gb490 From 368ca113ca0a41bbf60be6886bbbd238523c6fba Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:30 +0530 Subject: usb: dwc3; ep0: Modify _dwc3_ep0_start_trans_ API to take 'chain' parameter No functional change. Added a new parameter in _dwc3_ep0_start_trans_ to indicate whether the TRB is a chained TRB or last TRB. This is in preparation for adding chained TRB support for ep0. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 396c2af00fed..3f709a3ef31a 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -56,7 +56,7 @@ static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) } static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, - u32 len, u32 type) + u32 len, u32 type, bool chain) { struct dwc3_gadget_ep_cmd_params params; struct dwc3_trb *trb; @@ -302,7 +302,7 @@ void dwc3_ep0_out_start(struct dwc3 *dwc) int ret; ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8, - DWC3_TRBCTL_CONTROL_SETUP); + DWC3_TRBCTL_CONTROL_SETUP, false); WARN_ON(ret < 0); } @@ -855,7 +855,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, ret = dwc3_ep0_start_trans(dwc, epnum, dwc->ctrl_req_addr, 0, - DWC3_TRBCTL_CONTROL_DATA); + DWC3_TRBCTL_CONTROL_DATA, false); WARN_ON(ret < 0); } } @@ -939,7 +939,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, if (req->request.length == 0) { ret = dwc3_ep0_start_trans(dwc, dep->number, dwc->ctrl_req_addr, 0, - DWC3_TRBCTL_CONTROL_DATA); + DWC3_TRBCTL_CONTROL_DATA, false); } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && (dep->number == 0)) { u32 transfer_size = 0; @@ -970,7 +970,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, */ ret = dwc3_ep0_start_trans(dwc, dep->number, dwc->ep0_bounce_addr, transfer_size, - DWC3_TRBCTL_CONTROL_DATA); + DWC3_TRBCTL_CONTROL_DATA, false); } else { ret = usb_gadget_map_request(&dwc->gadget, &req->request, dep->number); @@ -980,7 +980,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, } ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma, - req->request.length, DWC3_TRBCTL_CONTROL_DATA); + req->request.length, DWC3_TRBCTL_CONTROL_DATA, + false); } WARN_ON(ret < 0); @@ -995,7 +996,7 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) : DWC3_TRBCTL_CONTROL_STATUS2; return dwc3_ep0_start_trans(dwc, dep->number, - dwc->ctrl_req_addr, 0, type); + dwc->ctrl_req_addr, 0, type, false); } static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) -- cgit v1.3-6-gb490 From 2abd9d5fa60f90cd99801687904f528156d31e18 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:31 +0530 Subject: usb: dwc3: ep0: Add chained TRB support Add chained TRB support to ep0. Now TRB's can be chained just by invoking _dwc3_ep0_start_trans_ with 'chain' parameter set to true. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 16 +++++++++++++--- drivers/usb/dwc3/gadget.c | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3f709a3ef31a..ebf2621fae5d 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -70,7 +70,10 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, return 0; } - trb = dwc->ep0_trb; + trb = &dwc->ep0_trb[dep->free_slot]; + + if (chain) + dep->free_slot++; trb->bpl = lower_32_bits(buf_dma); trb->bph = upper_32_bits(buf_dma); @@ -78,10 +81,17 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, trb->ctrl = type; trb->ctrl |= (DWC3_TRB_CTRL_HWO - | DWC3_TRB_CTRL_LST - | DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI); + if (chain) + trb->ctrl |= DWC3_TRB_CTRL_CHN; + else + trb->ctrl |= (DWC3_TRB_CTRL_IOC + | DWC3_TRB_CTRL_LST); + + if (chain) + return 0; + memset(¶ms, 0, sizeof(params)); params.param0 = upper_32_bits(dwc->ep0_trb_addr); params.param1 = lower_32_bits(dwc->ep0_trb_addr); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d97fcfa8fe87..2feed9e03583 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2687,7 +2687,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err0; } - dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb), + dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2, &dwc->ep0_trb_addr, GFP_KERNEL); if (!dwc->ep0_trb) { dev_err(dwc->dev, "failed to allocate ep0 trb\n"); -- cgit v1.3-6-gb490 From c0bd5456a470223e331a9e9e93b4a7425ecfaabb Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Jul 2015 12:25:32 +0530 Subject: usb: dwc3: ep0: handle non maxpacket aligned transfers > 512 Use chained TRB mechanism to handle non maxpacket aligned transfers greater than bounce buffer size. With this the first TRB will be programmed to receive 'ALIGN(ur->length - maxp, maxp)' data and the second TRB will be programmed to receive the remaining data using bounce buffer. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index ebf2621fae5d..5320e939e090 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -834,13 +834,26 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, maxp = ep0->endpoint.maxpacket; if (dwc->ep0_bounced) { + /* + * Handle the first TRB before handling the bounce buffer if + * the request length is greater than the bounce buffer size + */ + if (ur->length > DWC3_EP0_BOUNCE_SIZE) { + transfer_size = ALIGN(ur->length - maxp, maxp); + transferred = transfer_size - length; + buf = (u8 *)buf + transferred; + ur->actual += transferred; + remaining_ur_length -= transferred; + + trb++; + length = trb->size & DWC3_TRB_SIZE_MASK; + + ep0->free_slot = 0; + } + transfer_size = roundup((ur->length - transfer_size), maxp); - /* Maximum of DWC3_EP0_BOUNCE_SIZE can only be received */ - if (transfer_size > DWC3_EP0_BOUNCE_SIZE) - transfer_size = DWC3_EP0_BOUNCE_SIZE; - transferred = min_t(u32, remaining_ur_length, transfer_size - length); memcpy(buf, dwc->ep0_bounce, transferred); @@ -963,21 +976,22 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, } maxpacket = dep->endpoint.maxpacket; - transfer_size = roundup((req->request.length - transfer_size), - maxpacket); - if (transfer_size > DWC3_EP0_BOUNCE_SIZE) { - dev_WARN(dwc->dev, "bounce buf can't handle req len\n"); - transfer_size = DWC3_EP0_BOUNCE_SIZE; + if (req->request.length > DWC3_EP0_BOUNCE_SIZE) { + transfer_size = ALIGN(req->request.length - maxpacket, + maxpacket); + ret = dwc3_ep0_start_trans(dwc, dep->number, + req->request.dma, + transfer_size, + DWC3_TRBCTL_CONTROL_DATA, + true); } + transfer_size = roundup((req->request.length - transfer_size), + maxpacket); + dwc->ep0_bounced = true; - /* - * REVISIT in case request length is bigger than - * DWC3_EP0_BOUNCE_SIZE we will need two chained - * TRBs to handle the transfer. - */ ret = dwc3_ep0_start_trans(dwc, dep->number, dwc->ep0_bounce_addr, transfer_size, DWC3_TRBCTL_CONTROL_DATA, false); -- cgit v1.3-6-gb490 From ffd9a0fcbbed300b55f84e8397e96c2edd06cbdf Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:19:58 +0200 Subject: usb: gadget: add 'quirk_altset_not_supp' to usb_gadget Due to some UDC controllers may not support altsettings, usb gadget layer needs to provide a generic way to inform gadget functions about non-standard hardware limitations. This patch adds 'quirk_altset_not_supp' field to struct usb_gadget and helper function gadget_is_altset_supported(). It also sets 'quirk_altset_not_supp' to 1 in pxa25x_udc and pxa27x_udc drivers, which have such limitation. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pxa25x_udc.c | 1 + drivers/usb/gadget/udc/pxa27x_udc.c | 1 + include/linux/usb/gadget.h | 11 +++++++++++ 3 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index f6cbe667ce39..27f944231477 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1176,6 +1176,7 @@ static void udc_reinit(struct pxa25x_udc *dev) INIT_LIST_HEAD (&dev->gadget.ep_list); INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); dev->ep0state = EP0_IDLE; + dev->gadget.quirk_altset_not_supp = 1; /* basic endpoint records init */ for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 042f06b52677..670ac0b12f00 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -1710,6 +1710,7 @@ static void udc_init_data(struct pxa_udc *dev) INIT_LIST_HEAD(&dev->gadget.ep_list); INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0]; + dev->gadget.quirk_altset_not_supp = 1; ep0_idle(dev); /* PXA endpoints init */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index cea0511a1bc9..31be84b7e645 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -572,6 +572,7 @@ struct usb_gadget { unsigned a_hnp_support:1; unsigned a_alt_hnp_support:1; unsigned quirk_ep_out_aligned_size:1; + unsigned quirk_altset_not_supp:1; unsigned is_selfpowered:1; unsigned deactivated:1; unsigned connected:1; @@ -609,6 +610,16 @@ usb_ep_align_maybe(struct usb_gadget *g, struct usb_ep *ep, size_t len) round_up(len, (size_t)ep->desc->wMaxPacketSize); } +/** + * gadget_is_altset_supported - return true iff the hardware supports + * altsettings + * @g: controller to check for quirk + */ +static inline int gadget_is_altset_supported(struct usb_gadget *g) +{ + return !g->quirk_altset_not_supp; +} + /** * gadget_is_dualspeed - return true iff the hardware handles high speed * @g: controller that might support both high and full speeds -- cgit v1.3-6-gb490 From 02ded1b0d8e73dad7d2626c960ef20fb7dc30753 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:19:59 +0200 Subject: usb: gadget: add 'quirk_stall_not_supp' to usb_gadget Due to some UDC controllers may not support stalling, usb gadget layer needs to provide a generic way to inform gadget functions about non-standard hardware limitations. This patch adds 'quirk_stall_not_supp' field to struct usb_gadget and helper function gadget_is_stall_supported(). It also sets 'quirk_stall_not_supp' to 1 in at91_udc driver, which has such limitation. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/at91_udc.c | 1 + include/linux/usb/gadget.h | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index fc4226462f8f..32f50a7944dd 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -825,6 +825,7 @@ static void udc_reinit(struct at91_udc *udc) INIT_LIST_HEAD(&udc->gadget.ep_list); INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); + udc->gadget.quirk_stall_not_supp = 1; for (i = 0; i < NUM_ENDPOINTS; i++) { struct at91_ep *ep = &udc->ep[i]; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 31be84b7e645..f195a76548f6 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -573,6 +573,7 @@ struct usb_gadget { unsigned a_alt_hnp_support:1; unsigned quirk_ep_out_aligned_size:1; unsigned quirk_altset_not_supp:1; + unsigned quirk_stall_not_supp:1; unsigned is_selfpowered:1; unsigned deactivated:1; unsigned connected:1; @@ -620,6 +621,15 @@ static inline int gadget_is_altset_supported(struct usb_gadget *g) return !g->quirk_altset_not_supp; } +/** + * gadget_is_stall_supported - return true iff the hardware supports stalling + * @g: controller to check for quirk + */ +static inline int gadget_is_stall_supported(struct usb_gadget *g) +{ + return !g->quirk_stall_not_supp; +} + /** * gadget_is_dualspeed - return true iff the hardware handles high speed * @g: controller that might support both high and full speeds -- cgit v1.3-6-gb490 From ca1023c81dd10f76a5d0a8be2fdbe724fe7a126a Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:20:00 +0200 Subject: usb: gadget: add 'quirk_zlp_not_supp' to usb_gadget Due to some UDC controllers may not support zlp, usb gadget layer needs to provide a generic way to inform gadget functions about non-standard hardware limitations. This patch adds 'quirk_zlp_not_supp' field to struct usb_gadget and helper function gadget_is_zlp_supported(). It also sets 'quirk_zlp_not_supp' to 1 in musb UDC driver, which has such limitation. [ balbi@ti.com : make it build ] Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 1 + include/linux/usb/gadget.h | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 625d482f1a97..9e18178f1d45 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -2075,6 +2075,7 @@ __acquires(musb->lock) musb->g.b_hnp_enable = 0; musb->g.a_alt_hnp_support = 0; musb->g.a_hnp_support = 0; + musb->g.quirk_zlp_not_supp = 1; /* Normal reset, as B-Device; * or else after HNP, as A-Device diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index f195a76548f6..353a72096dda 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -574,6 +574,7 @@ struct usb_gadget { unsigned quirk_ep_out_aligned_size:1; unsigned quirk_altset_not_supp:1; unsigned quirk_stall_not_supp:1; + unsigned quirk_zlp_not_supp:1; unsigned is_selfpowered:1; unsigned deactivated:1; unsigned connected:1; @@ -630,6 +631,15 @@ static inline int gadget_is_stall_supported(struct usb_gadget *g) return !g->quirk_stall_not_supp; } +/** + * gadget_is_zlp_supported - return true iff the hardware supports zlp + * @g: controller to check for quirk + */ +static inline int gadget_is_zlp_supported(struct usb_gadget *g) +{ + return !g->quirk_zlp_not_supp; +} + /** * gadget_is_dualspeed - return true iff the hardware handles high speed * @g: controller that might support both high and full speeds -- cgit v1.3-6-gb490 From a4cc42157f3f8c3dd5562b91c7430376912c6fb8 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:20:01 +0200 Subject: usb: gadget: f_mass_storage: check quirk instead of UDC name Use generic mechanism to check if UDC controller supports stalling. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 9e88e2b18d95..a2291946ca7e 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2836,7 +2836,8 @@ int fsg_common_set_cdev(struct fsg_common *common, * halt bulk endpoints correctly. If one of them is present, * disable stalls. */ - common->can_stall = can_stall && !(gadget_is_at91(common->gadget)); + common->can_stall = can_stall && + gadget_is_stall_supported(common->gadget); return 0; } -- cgit v1.3-6-gb490 From 7a896d40525349e7d52307fb957882696e09466c Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:20:02 +0200 Subject: usb: gadget: f_ecm/f_ncm: check quirk instead of UDC name Use generic mechanism to check if UDC controller supports zlp. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_ecm.c | 4 ++-- drivers/usb/gadget/function/f_ncm.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index 798760fa7e70..7b7424f10ddd 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -585,8 +585,8 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* Enable zlps by default for ECM conformance; * override for musb_hdrc (avoids txdma ovhead). */ - ecm->port.is_zlp_ok = !(gadget_is_musbhdrc(cdev->gadget) - ); + ecm->port.is_zlp_ok = + gadget_is_zlp_supported(cdev->gadget); ecm->port.cdc_filter = DEFAULT_FILTER; DBG(cdev, "activate ecm\n"); net = gether_connect(&ecm->port); diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index bdcda9f5148e..3f05c6bd57f0 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -853,9 +853,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) /* Enable zlps by default for NCM conformance; * override for musb_hdrc (avoids txdma ovhead) */ - ncm->port.is_zlp_ok = !( - gadget_is_musbhdrc(cdev->gadget) - ); + ncm->port.is_zlp_ok = + gadget_is_zlp_supported(cdev->gadget); ncm->port.cdc_filter = DEFAULT_FILTER; DBG(cdev, "activate ncm\n"); net = gether_connect(&ncm->port); -- cgit v1.3-6-gb490 From 736d093b5985c1f6583460c8eea1be3c9ee5635e Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 28 Jul 2015 07:20:03 +0200 Subject: usb: gadget: apply generic altsetting support check mechanism Replace calls of gadget_supports_altsettings() function (which check altset support by comparing UDC controller name with hardcoded names) with gadget_is_altset_supported() which checks generic quirk bitfield. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_obex.c | 2 +- drivers/usb/gadget/function/u_ether.h | 2 +- drivers/usb/gadget/legacy/nokia.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c index 5519f858904b..2682d59f5675 100644 --- a/drivers/usb/gadget/function/f_obex.c +++ b/drivers/usb/gadget/function/f_obex.c @@ -297,7 +297,7 @@ static inline bool can_support_obex(struct usb_configuration *c) * * Altsettings are mandatory, however... */ - if (!gadget_supports_altsettings(c->cdev->gadget)) + if (!gadget_is_altset_supported(c->cdev->gadget)) return false; /* everything else is *probably* fine ... */ diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 334b38947916..1384f000bd80 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -259,7 +259,7 @@ void gether_disconnect(struct gether *); /* Some controllers can't support CDC Ethernet (ECM) ... */ static inline bool can_support_ecm(struct usb_gadget *gadget) { - if (!gadget_supports_altsettings(gadget)) + if (!gadget_is_altset_supported(gadget)) return false; /* Everything else is *presumably* fine ... but this is a bit diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index 8902f454b7bc..264c97e15478 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -292,7 +292,7 @@ static int nokia_bind(struct usb_composite_dev *cdev) nokia_config_500ma_driver.iConfiguration = status; nokia_config_100ma_driver.iConfiguration = status; - if (!gadget_supports_altsettings(gadget)) { + if (!gadget_is_altset_supported(gadget)) { status = -ENODEV; goto err_usb; } -- cgit v1.3-6-gb490 From 6f98f545b0b4effdf67e83e214a4eb13cd41fba2 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Tue, 28 Jul 2015 11:10:22 +0300 Subject: usb: phy: msm: Add D+/D- lines route control apq8016-sbc board is using Dual SPDT USB Switch (TC7USB40MU), witch is controlled by GPIO to de/multiplex D+/D- USB lines to USB2513B Hub and uB connector. Add support for this. Signed-off-by: Ivan T. Ivanov Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/msm-hsusb.txt | 4 ++ drivers/usb/phy/phy-msm-usb.c | 47 ++++++++++++++++++++++ include/linux/usb/msm_hsusb.h | 7 ++++ 3 files changed, 58 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt index bd8d9e753029..8654a3ec23e4 100644 --- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt @@ -52,6 +52,10 @@ Required properties: Optional properties: - dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" +- switch-gpio: A phandle + gpio-specifier pair. Some boards are using Dual + SPDT USB Switch, witch is cotrolled by GPIO to de/multiplex + D+/D- USB lines between connectors. + - qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device Mode Eye Diagram test. Start address at which these values will be written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 61d86d8bf5b7..c58c3c0dbe35 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #include #include @@ -1471,6 +1473,14 @@ static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event, else clear_bit(B_SESS_VLD, &motg->inputs); + if (test_bit(B_SESS_VLD, &motg->inputs)) { + /* Switch D+/D- lines to Device connector */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + } else { + /* Switch D+/D- lines to Hub */ + gpiod_set_value_cansleep(motg->switch_gpio, 1); + } + schedule_work(&motg->sm_work); return NOTIFY_DONE; @@ -1546,6 +1556,11 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup"); + motg->switch_gpio = devm_gpiod_get_optional(&pdev->dev, "switch", + GPIOD_OUT_LOW); + if (IS_ERR(motg->switch_gpio)) + return PTR_ERR(motg->switch_gpio); + ext_id = ERR_PTR(-ENODEV); ext_vbus = ERR_PTR(-ENODEV); if (of_property_read_bool(node, "extcon")) { @@ -1617,6 +1632,19 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) return 0; } +static int msm_otg_reboot_notify(struct notifier_block *this, + unsigned long code, void *unused) +{ + struct msm_otg *motg = container_of(this, struct msm_otg, reboot); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot + */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + return NOTIFY_DONE; +} + static int msm_otg_probe(struct platform_device *pdev) { struct regulator_bulk_data regs[3]; @@ -1781,6 +1809,17 @@ static int msm_otg_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Can not create mode change file\n"); } + if (test_bit(B_SESS_VLD, &motg->inputs)) { + /* Switch D+/D- lines to Device connector */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + } else { + /* Switch D+/D- lines to Hub */ + gpiod_set_value_cansleep(motg->switch_gpio, 1); + } + + motg->reboot.notifier_call = msm_otg_reboot_notify; + register_reboot_notifier(&motg->reboot); + pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -1807,6 +1846,14 @@ static int msm_otg_remove(struct platform_device *pdev) if (phy->otg->host || phy->otg->gadget) return -EBUSY; + unregister_reboot_notifier(&motg->reboot); + + /* + * Ensure that D+/D- lines are routed to uB connector, so + * we could load bootloader/kernel at next reboot + */ + gpiod_set_value_cansleep(motg->switch_gpio, 0); + extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb); extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb); diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h index 5df2c8f59aa0..8c8f6854c993 100644 --- a/include/linux/usb/msm_hsusb.h +++ b/include/linux/usb/msm_hsusb.h @@ -155,6 +155,10 @@ struct msm_usb_cable { * starting controller using usbcmd run/stop bit. * @vbus: VBUS signal state trakining, using extcon framework * @id: ID signal state trakining, using extcon framework + * @switch_gpio: Descriptor for GPIO used to control external Dual + * SPDT USB Switch. + * @reboot: Used to inform the driver to route USB D+/D- line to Device + * connector */ struct msm_otg { struct usb_phy phy; @@ -188,6 +192,9 @@ struct msm_otg { struct msm_usb_cable vbus; struct msm_usb_cable id; + + struct gpio_desc *switch_gpio; + struct notifier_block reboot; }; #endif -- cgit v1.3-6-gb490 From 1c99cabfc95d3b08fbf06d558ebfa76b5303710c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 30 Jul 2015 00:29:23 +0300 Subject: usb: gadget: fotg210-udc: remove duplicate conditions We handle the "if (!req->req.length)" condition at the start of the function and return. We can delete this dead code. Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fotg210-udc.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index 1137e3384218..a99ed6d80e9a 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -384,25 +384,15 @@ static void fotg210_ep0_queue(struct fotg210_ep *ep, return; } if (ep->dir_in) { /* if IN */ - if (req->req.length) { - fotg210_start_dma(ep, req); - } else { - pr_err("%s : req->req.length = 0x%x\n", - __func__, req->req.length); - } + fotg210_start_dma(ep, req); if ((req->req.length == req->req.actual) || (req->req.actual < ep->ep.maxpacket)) fotg210_done(ep, req, 0); } else { /* OUT */ - if (!req->req.length) { - fotg210_done(ep, req, 0); - } else { - u32 value = ioread32(ep->fotg210->reg + - FOTG210_DMISGR0); + u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR0); - value &= ~DMISGR0_MCX_OUT_INT; - iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR0); - } + value &= ~DMISGR0_MCX_OUT_INT; + iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR0); } } -- cgit v1.3-6-gb490 From 5feb5d2003499b1094d898c010a7604d7afddc4c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 30 Jul 2015 00:30:58 +0300 Subject: usb: gadget: m66592-udc: forever loop in set_feature() There is an "&&" vs "||" typo here so this loops 3000 times or if we get unlucky it could loop forever. Fixes: ceaa0a6eeadf ('usb: gadget: m66592-udc: add support for TEST_MODE') Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/m66592-udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index 309706fe4bf0..9704053dfe05 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1052,7 +1052,7 @@ static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) tmp = m66592_read(m66592, M66592_INTSTS0) & M66592_CTSQ; udelay(1); - } while (tmp != M66592_CS_IDST || timeout-- > 0); + } while (tmp != M66592_CS_IDST && timeout-- > 0); if (tmp == M66592_CS_IDST) m66592_bset(m66592, -- cgit v1.3-6-gb490 From 8078f314b8c8012cf36e5decc75378b803bfba4d Mon Sep 17 00:00:00 2001 From: Sanjay Singh Rawat Date: Wed, 22 Jul 2015 16:29:46 +0530 Subject: usb: gadget: f_mass_storage: stop thread in bind failure case After the worker thread is launched, bind function is doing further configuration. In case of failure stop the thread. Acked-by: Michal Nazarewicz Signed-off-by: Sanjay Singh Rawat Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index a2291946ca7e..f94a8e2e9b60 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -3081,7 +3081,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) /* New interface */ i = usb_interface_id(c, f); if (i < 0) - return i; + goto fail; fsg_intf_desc.bInterfaceNumber = i; fsg->interface_number = i; @@ -3124,7 +3124,14 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) autoconf_fail: ERROR(fsg, "unable to autoconfigure all endpoints\n"); - return -ENOTSUPP; + i = -ENOTSUPP; +fail: + /* terminate the thread */ + if (fsg->common->state != FSG_STATE_TERMINATED) { + raise_exception(fsg->common, FSG_STATE_EXIT); + wait_for_completion(&fsg->common->thread_notifier); + } + return i; } /****************************** ALLOCATE FUNCTION *************************/ -- cgit v1.3-6-gb490 From 913e4a90b6f9687ac0f543e7b632753e4f51c441 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Thu, 30 Jul 2015 13:13:03 +0800 Subject: usb: gadget: f_uac2: finalize wMaxPacketSize according to bandwidth According to USB Audio Device 2.0 Spec, Ch4.10.1.1: wMaxPacketSize is defined as follows: Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. This is determined by the audio bandwidth constraints of the endpoint. In current code, the wMaxPacketSize is defined as the maximum packet size for ISO endpoint, and it will let the host reserve much more space than it really needs, so that we can't let more endpoints work together at one frame. We find this issue when we try to let 4 f_uac2 gadgets work together [1] at FS connection. [1]http://www.spinics.net/lists/linux-usb/msg123478.html Acked-by: Daniel Mack Cc: andrzej.p@samsung.com Cc: Daniel Mack Cc: tiwai@suse.de Cc: #v3.18+ Cc: Alan Stern Signed-off-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uac2.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 6d3eb8b00a48..b5680246d6aa 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -975,6 +975,29 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep) "%s:%d Error!\n", __func__, __LINE__); } +static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, + struct usb_endpoint_descriptor *ep_desc, + unsigned int factor, bool is_playback) +{ + int chmask, srate, ssize; + u16 max_packet_size; + + if (is_playback) { + chmask = uac2_opts->p_chmask; + srate = uac2_opts->p_srate; + ssize = uac2_opts->p_ssize; + } else { + chmask = uac2_opts->c_chmask; + srate = uac2_opts->c_srate; + ssize = uac2_opts->c_ssize; + } + + max_packet_size = num_channels(chmask) * ssize * + DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); + ep_desc->wMaxPacketSize = cpu_to_le16(min(max_packet_size, + le16_to_cpu(ep_desc->wMaxPacketSize))); +} + static int afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) { @@ -1070,10 +1093,14 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) uac2->p_prm.uac2 = uac2; uac2->c_prm.uac2 = uac2; + /* Calculate wMaxPacketSize according to audio bandwidth */ + set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true); + set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false); + set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true); + set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false); + hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; - hs_epout_desc.wMaxPacketSize = fs_epout_desc.wMaxPacketSize; hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; - hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize; ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL); if (ret) -- cgit v1.3-6-gb490 From ce7fa78ce16e476a610e165dd0e8c1e85a75d60f Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 30 Jul 2015 14:30:29 +0300 Subject: bnx2x: Fix compilation when CONFIG_BNX2X_SRIOV is not set Commit 05cc5a39ddb7 ("bnx2x: add vlan filtering offload") has broken compilation when CONFIG_BNX2X_SRIOV is not set. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 2 ++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h | 5 +++++ 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 96ad9ec65faf..31c63aa22521 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -13091,8 +13091,10 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev, bp->accept_any_vlan = true; else dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; +#ifdef CONFIG_BNX2X_SRIOV } else if (bp->acquire_resp.pfdev_info.pf_cap & PFVF_CAP_VLAN_FILTER) { dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; +#endif } dev->features |= dev->hw_features | NETIF_F_HW_VLAN_CTAG_RX; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h index 01f364358e5b..670a581ffabc 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h @@ -551,6 +551,11 @@ int bnx2x_set_vf_link_state(struct net_device *dev, int vf, int link_state); int bnx2x_vfpf_update_vlan(struct bnx2x *bp, u16 vid, u8 vf_qid, bool add); #else /* CONFIG_BNX2X_SRIOV */ +#define GET_NUM_VFS_PER_PATH(bp) 0 +#define GET_NUM_VFS_PER_PF(bp) 0 +#define VF_MAC_CREDIT_CNT 0 +#define VF_VLAN_CREDIT_CNT 0 + static inline void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid, struct bnx2x_queue_sp_obj **q_obj) {} static inline void bnx2x_vf_handle_flr_event(struct bnx2x *bp) {} -- cgit v1.3-6-gb490 From 2e9e910e8a4626d1217b6887c74a456d2835be2a Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 10:38:52 -0700 Subject: Input: export I2C module alias information in missing drivers The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Dmitry Torokhov --- drivers/input/misc/gp2ap002a00f.c | 1 + drivers/input/touchscreen/goodix.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c index ba301af91b95..3bfdfcc20485 100644 --- a/drivers/input/misc/gp2ap002a00f.c +++ b/drivers/input/misc/gp2ap002a00f.c @@ -267,6 +267,7 @@ static const struct i2c_device_id gp2a_i2c_id[] = { { GP2A_I2C_NAME, 0 }, { } }; +MODULE_DEVICE_TABLE(i2c, gp2a_i2c_id); static struct i2c_driver gp2a_i2c_driver = { .driver = { diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index ccd9dca61195..d3f44a8577f5 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -384,6 +384,7 @@ static const struct i2c_device_id goodix_ts_id[] = { { "GDIX1001:00", 0 }, { } }; +MODULE_DEVICE_TABLE(i2c, goodix_ts_id); #ifdef CONFIG_ACPI static const struct acpi_device_id goodix_acpi_match[] = { -- cgit v1.3-6-gb490 From 02d9bd05dcf77bed954ed21b2d4c330879fa3103 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 10:39:28 -0700 Subject: Input: touchscreen - export OF module alias information The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/egalax_ts.c | 1 + drivers/input/touchscreen/mms114.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 7bce2d90ec74..1afc08b08155 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -264,6 +264,7 @@ static const struct of_device_id egalax_ts_dt_ids[] = { { .compatible = "eeti,egalax_ts" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, egalax_ts_dt_ids); static struct i2c_driver egalax_ts_driver = { .driver = { diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 6b69f461733c..7cce87650fc8 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -572,6 +572,7 @@ static const struct of_device_id mms114_dt_match[] = { { .compatible = "melfas,mms114" }, { } }; +MODULE_DEVICE_TABLE(of, mms114_dt_match); #endif static struct i2c_driver mms114_driver = { -- cgit v1.3-6-gb490 From 36e9615bd70dc8cd5d7d4831943f788f5231350f Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Thu, 30 Jul 2015 11:19:18 -0700 Subject: Input: cyapa - add regulator vcc support We need to power up the chip before we can initialize it. On systems that delegate task of powering up regulators to firmware we assume that we'll be simply given a dummy regulator. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 29 +++++++++++++++++++++++++++++ drivers/input/mouse/cyapa.h | 1 + 2 files changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 6195ccb3cfde..1479ca996647 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1241,6 +1242,13 @@ static void cyapa_remove_sysfs_group(void *data) sysfs_remove_group(&cyapa->client->dev.kobj, &cyapa_sysfs_group); } +static void cyapa_disable_regulator(void *data) +{ + struct cyapa *cyapa = data; + + regulator_disable(cyapa->vcc); +} + static int cyapa_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) { @@ -1274,6 +1282,27 @@ static int cyapa_probe(struct i2c_client *client, sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr, client->addr); + cyapa->vcc = devm_regulator_get(dev, "vcc"); + if (IS_ERR(cyapa->vcc)) { + error = PTR_ERR(cyapa->vcc); + dev_err(dev, "failed to get vcc regulator: %d\n", error); + return error; + } + + error = regulator_enable(cyapa->vcc); + if (error) { + dev_err(dev, "failed to enable regulator: %d\n", error); + return error; + } + + error = devm_add_action(dev, cyapa_disable_regulator, cyapa); + if (error) { + cyapa_disable_regulator(cyapa); + dev_err(dev, "failed to add disable regulator action: %d\n", + error); + return error; + } + error = cyapa_initialize(cyapa); if (error) { dev_err(dev, "failed to detect and initialize tp device.\n"); diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h index af1253640590..b812bba8cdd7 100644 --- a/drivers/input/mouse/cyapa.h +++ b/drivers/input/mouse/cyapa.h @@ -321,6 +321,7 @@ struct cyapa { u8 status[BL_STATUS_SIZE]; bool operational; /* true: ready for data reporting; false: not. */ + struct regulator *vcc; struct i2c_client *client; struct input_dev *input; char phys[32]; /* Device physical location */ -- cgit v1.3-6-gb490 From ddbb299db0e040aca8e26361ab778224eeacf9d3 Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Thu, 30 Jul 2015 11:24:16 -0700 Subject: Input: cyapa - introduce device tree binding Add device tree support for Cypress trackpad devices. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/cypress,cyapa.txt | 44 ++++++++++++++++++++++ .../devicetree/bindings/vendor-prefixes.txt | 1 + drivers/input/mouse/cyapa.c | 10 +++++ 3 files changed, 55 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/cypress,cyapa.txt (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/cypress,cyapa.txt b/Documentation/devicetree/bindings/input/cypress,cyapa.txt new file mode 100644 index 000000000000..635a3b036630 --- /dev/null +++ b/Documentation/devicetree/bindings/input/cypress,cyapa.txt @@ -0,0 +1,44 @@ +Cypress I2C Touchpad + +Required properties: +- compatible: must be "cypress,cyapa". +- reg: I2C address of the chip. +- interrupt-parent: a phandle for the interrupt controller (see interrupt + binding[0]). +- interrupts: interrupt to which the chip is connected (see interrupt + binding[0]). + +Optional properties: +- wakeup-source: touchpad can be used as a wakeup source. +- pinctrl-names: should be "default" (see pinctrl binding [1]). +- pinctrl-0: a phandle pointing to the pin settings for the device (see + pinctrl binding [1]). +- vcc-supply: a phandle for the regulator supplying 3.3V power. + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Example: + &i2c0 { + /* ... */ + + /* Cypress Gen3 touchpad */ + touchpad@67 { + compatible = "cypress,cyapa"; + reg = <0x24>; + interrupt-parent = <&gpio>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; /* GPIO 2 */ + wakeup-source; + }; + + /* Cypress Gen5 and later touchpad */ + touchpad@24 { + compatible = "cypress,cyapa"; + reg = <0x24>; + interrupt-parent = <&gpio>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; /* GPIO 2 */ + wakeup-source; + }; + + /* ... */ + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d444757c4d9e..57c0f5f8839c 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -54,6 +54,7 @@ cortina Cortina Systems, Inc. cosmic Cosmic Circuits crystalfontz Crystalfontz America, Inc. cubietech Cubietech, Ltd. +cypress Cypress Semiconductor Corporation dallas Maxim Integrated Products (formerly Dallas Semiconductor) davicom DAVICOM Semiconductor, Inc. delta Delta Electronics, Inc. diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 1479ca996647..eb76b61418f3 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "cyapa.h" @@ -1487,11 +1488,20 @@ static const struct acpi_device_id cyapa_acpi_id[] = { MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id); #endif +#ifdef CONFIG_OF +static const struct of_device_id cyapa_of_match[] = { + { .compatible = "cypress,cyapa" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, cyapa_of_match); +#endif + static struct i2c_driver cyapa_driver = { .driver = { .name = "cyapa", .pm = &cyapa_pm_ops, .acpi_match_table = ACPI_PTR(cyapa_acpi_id), + .of_match_table = of_match_ptr(cyapa_of_match), }, .probe = cyapa_probe, -- cgit v1.3-6-gb490 From 0642ffd6a864629c12a4cd7528782ed5b68ac69c Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Thu, 30 Jul 2015 11:26:39 -0700 Subject: Input: cyapa - do not try to enable proximity reporting on older devices Avoid the driver generate warning message when the cyapa driver working with the old Gen5 trackpad device which does not support the proximity function. Those old Gen5 trackpad device all have the platform version less than 2. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa_gen5.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index 6d7abbed67e4..118ba977181e 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -2519,10 +2519,13 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) __func__); /* By default, the trackpad proximity function is enabled. */ - error = cyapa_pip_set_proximity(cyapa, true); - if (error) - dev_warn(dev, "%s: failed to enable proximity.\n", - __func__); + if (cyapa->platform_ver >= 2) { + error = cyapa_pip_set_proximity(cyapa, true); + if (error) + dev_warn(dev, + "%s: failed to enable proximity.\n", + __func__); + } /* Get trackpad product information. */ error = cyapa_gen5_get_query_data(cyapa); -- cgit v1.3-6-gb490 From 890e4847587fcff5eb0438e90992ad7d2a261f33 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 10 Jun 2015 16:54:58 +0800 Subject: PCI: Add pcibios_alloc_irq() and pcibios_free_irq() Add pcibios_alloc_irq() and pcibios_free_irq(), which are called when binding/unbinding PCI device drivers. PCI arch code may implement these to manage IRQ resources for hotplugged devices. [bhelgaas: changelog] Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas Acked-by: Thomas Gleixner --- drivers/pci/pci-driver.c | 26 ++++++++++++++++++++------ include/linux/pci.h | 2 ++ 2 files changed, 22 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 3cb2210de553..52a880ca1768 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -388,18 +388,31 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) return error; } +int __weak pcibios_alloc_irq(struct pci_dev *dev) +{ + return 0; +} + +void __weak pcibios_free_irq(struct pci_dev *dev) +{ +} + static int pci_device_probe(struct device *dev) { - int error = 0; - struct pci_driver *drv; - struct pci_dev *pci_dev; + int error; + struct pci_dev *pci_dev = to_pci_dev(dev); + struct pci_driver *drv = to_pci_driver(dev->driver); + + error = pcibios_alloc_irq(pci_dev); + if (error < 0) + return error; - drv = to_pci_driver(dev->driver); - pci_dev = to_pci_dev(dev); pci_dev_get(pci_dev); error = __pci_device_probe(drv, pci_dev); - if (error) + if (error) { + pcibios_free_irq(pci_dev); pci_dev_put(pci_dev); + } return error; } @@ -415,6 +428,7 @@ static int pci_device_remove(struct device *dev) drv->remove(pci_dev); pm_runtime_put_noidle(dev); } + pcibios_free_irq(pci_dev); pci_dev->driver = NULL; } diff --git a/include/linux/pci.h b/include/linux/pci.h index 8a0321a8fb59..b4832c92f23e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1645,6 +1645,8 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, int pcibios_add_device(struct pci_dev *dev); void pcibios_release_device(struct pci_dev *dev); void pcibios_penalize_isa_irq(int irq, int active); +int pcibios_alloc_irq(struct pci_dev *dev); +void pcibios_free_irq(struct pci_dev *dev); #ifdef CONFIG_HIBERNATE_CALLBACKS extern struct dev_pm_ops pcibios_pm_ops; -- cgit v1.3-6-gb490 From 991de2e59090e55c65a7f59a049142e3c480f7bd Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 10 Jun 2015 16:54:59 +0800 Subject: PCI, x86: Implement pcibios_alloc_irq() and pcibios_free_irq() To support IOAPIC hotplug, we need to allocate PCI IRQ resources on demand and free them when not used anymore. Implement pcibios_alloc_irq() and pcibios_free_irq() to dynamically allocate and free PCI IRQs. Remove mp_should_keep_irq(), which is no longer used. [bhelgaas: changelog] Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas Acked-by: Thomas Gleixner --- arch/x86/include/asm/pci_x86.h | 2 -- arch/x86/pci/common.c | 20 +++++++++----------- arch/x86/pci/intel_mid_pci.c | 7 +++++-- arch/x86/pci/irq.c | 15 +-------------- drivers/acpi/pci_irq.c | 9 +-------- 5 files changed, 16 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h index 164e3f8d3c3d..fa1195dae425 100644 --- a/arch/x86/include/asm/pci_x86.h +++ b/arch/x86/include/asm/pci_x86.h @@ -93,8 +93,6 @@ extern raw_spinlock_t pci_config_lock; extern int (*pcibios_enable_irq)(struct pci_dev *dev); extern void (*pcibios_disable_irq)(struct pci_dev *dev); -extern bool mp_should_keep_irq(struct device *dev); - struct pci_raw_ops { int (*read)(unsigned int domain, unsigned int bus, unsigned int devfn, int reg, int len, u32 *val); diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 8fd6f44aee83..dc78a4a9a466 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -673,24 +673,22 @@ int pcibios_add_device(struct pci_dev *dev) return 0; } -int pcibios_enable_device(struct pci_dev *dev, int mask) +int pcibios_alloc_irq(struct pci_dev *dev) { - int err; - - if ((err = pci_enable_resources(dev, mask)) < 0) - return err; - - if (!pci_dev_msi_enabled(dev)) - return pcibios_enable_irq(dev); - return 0; + return pcibios_enable_irq(dev); } -void pcibios_disable_device (struct pci_dev *dev) +void pcibios_free_irq(struct pci_dev *dev) { - if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq) + if (pcibios_disable_irq) pcibios_disable_irq(dev); } +int pcibios_enable_device(struct pci_dev *dev, int mask) +{ + return pci_enable_resources(dev, mask); +} + int pci_ext_cfg_avail(void) { if (raw_pci_ext_ops) diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index 27062303c881..fb7a1f96d80c 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c @@ -234,10 +234,13 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) static void intel_mid_pci_irq_disable(struct pci_dev *dev) { - if (!mp_should_keep_irq(&dev->dev) && dev->irq_managed && - dev->irq > 0) { + if (dev->irq_managed && dev->irq > 0) { mp_unmap_irq(dev->irq); dev->irq_managed = 0; + /* + * Don't reset dev->irq here, otherwise + * intel_mid_pci_irq_enable() will fail on next call. + */ } } diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 9bd115484745..72108f0b66b1 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -1257,22 +1257,9 @@ static int pirq_enable_irq(struct pci_dev *dev) return 0; } -bool mp_should_keep_irq(struct device *dev) -{ - if (dev->power.is_prepared) - return true; -#ifdef CONFIG_PM - if (dev->power.runtime_status == RPM_SUSPENDING) - return true; -#endif - - return false; -} - static void pirq_disable_irq(struct pci_dev *dev) { - if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) && - dev->irq_managed && dev->irq) { + if (io_apic_assign_pci_irqs && dev->irq_managed && dev->irq) { mp_unmap_irq(dev->irq); dev->irq = 0; dev->irq_managed = 0; diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 304eccb0ae5c..d1aad6900b4c 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -484,14 +484,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) if (!pin || !dev->irq_managed || dev->irq <= 0) return; - /* Keep IOAPIC pin configuration when suspending */ - if (dev->dev.power.is_prepared) - return; -#ifdef CONFIG_PM - if (dev->dev.power.runtime_status == RPM_SUSPENDING) - return; -#endif - entry = acpi_pci_irq_lookup(dev, pin); if (!entry) return; @@ -512,5 +504,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) if (gsi >= 0) { acpi_unregister_gsi(gsi); dev->irq_managed = 0; + dev->irq = 0; } } -- cgit v1.3-6-gb490 From 811a4e6fce09bc9239c664c6a1a53645a678c303 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 10 Jun 2015 16:55:00 +0800 Subject: PCI: Add helpers to manage pci_dev->irq and pci_dev->irq_managed Add pci_has_managed_irq(), pci_set_managed_irq(), and pci_reset_managed_irq() to simplify code. No functional change. [bhelgaas: changelog] Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas Acked-by: Thomas Gleixner --- arch/x86/pci/intel_mid_pci.c | 4 ++-- arch/x86/pci/irq.c | 10 ++++------ drivers/acpi/pci_irq.c | 10 ++++------ include/linux/pci.h | 17 +++++++++++++++++ 4 files changed, 27 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/arch/x86/pci/intel_mid_pci.c b/arch/x86/pci/intel_mid_pci.c index fb7a1f96d80c..22aaefb4f1ca 100644 --- a/arch/x86/pci/intel_mid_pci.c +++ b/arch/x86/pci/intel_mid_pci.c @@ -211,7 +211,7 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) struct irq_alloc_info info; int polarity; - if (dev->irq_managed && dev->irq > 0) + if (pci_has_managed_irq(dev)) return 0; if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) @@ -234,7 +234,7 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) static void intel_mid_pci_irq_disable(struct pci_dev *dev) { - if (dev->irq_managed && dev->irq > 0) { + if (pci_has_managed_irq(dev)) { mp_unmap_irq(dev->irq); dev->irq_managed = 0; /* diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 72108f0b66b1..32e70343e6fd 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -1202,7 +1202,7 @@ static int pirq_enable_irq(struct pci_dev *dev) struct pci_dev *temp_dev; int irq; - if (dev->irq_managed && dev->irq > 0) + if (pci_has_managed_irq(dev)) return 0; irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, @@ -1230,8 +1230,7 @@ static int pirq_enable_irq(struct pci_dev *dev) } dev = temp_dev; if (irq >= 0) { - dev->irq_managed = 1; - dev->irq = irq; + pci_set_managed_irq(dev, irq); dev_info(&dev->dev, "PCI->APIC IRQ transform: " "INT %c -> IRQ %d\n", 'A' + pin - 1, irq); return 0; @@ -1259,9 +1258,8 @@ static int pirq_enable_irq(struct pci_dev *dev) static void pirq_disable_irq(struct pci_dev *dev) { - if (io_apic_assign_pci_irqs && dev->irq_managed && dev->irq) { + if (io_apic_assign_pci_irqs && pci_has_managed_irq(dev)) { mp_unmap_irq(dev->irq); - dev->irq = 0; - dev->irq_managed = 0; + pci_reset_managed_irq(dev); } } diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index d1aad6900b4c..afa16c557c17 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -412,7 +412,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) return 0; } - if (dev->irq_managed && dev->irq > 0) + if (pci_has_managed_irq(dev)) return 0; entry = acpi_pci_irq_lookup(dev, pin); @@ -457,8 +457,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) kfree(entry); return rc; } - dev->irq = rc; - dev->irq_managed = 1; + pci_set_managed_irq(dev, rc); if (link) snprintf(link_desc, sizeof(link_desc), " -> Link[%s]", link); @@ -481,7 +480,7 @@ void acpi_pci_irq_disable(struct pci_dev *dev) u8 pin; pin = dev->pin; - if (!pin || !dev->irq_managed || dev->irq <= 0) + if (!pin || !pci_has_managed_irq(dev)) return; entry = acpi_pci_irq_lookup(dev, pin); @@ -503,7 +502,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin)); if (gsi >= 0) { acpi_unregister_gsi(gsi); - dev->irq_managed = 0; - dev->irq = 0; + pci_reset_managed_irq(dev); } } diff --git a/include/linux/pci.h b/include/linux/pci.h index b4832c92f23e..b7ab0c424ed6 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -963,6 +963,23 @@ static inline int pci_is_managed(struct pci_dev *pdev) return pdev->is_managed; } +static inline void pci_set_managed_irq(struct pci_dev *pdev, unsigned int irq) +{ + pdev->irq = irq; + pdev->irq_managed = 1; +} + +static inline void pci_reset_managed_irq(struct pci_dev *pdev) +{ + pdev->irq = 0; + pdev->irq_managed = 0; +} + +static inline bool pci_has_managed_irq(struct pci_dev *pdev) +{ + return pdev->irq_managed && pdev->irq > 0; +} + void pci_disable_device(struct pci_dev *dev); extern unsigned int pcibios_max_latency; -- cgit v1.3-6-gb490 From 5f2269916b0e509f2926346b58209abfa8316143 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 30 Jul 2015 14:00:08 -0500 Subject: PCI/MSI: Free legacy IRQ when enabling MSI/MSI-X Once MSI/MSI-X is enabled by the device driver, a PCI device won't use legacy IRQs again until MSI/MSI-X is disabled. Call pcibios_free_irq() when enabling MSI/MSI-X and pcibios_alloc_irq() when disabling MSI/MSI-X. This allows arch code to manage resources associated with the legacy IRQ. [bhelgaas: changelog] Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas Acked-by: Thomas Gleixner --- drivers/pci/msi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f66be868ad21..bb74238c0cb6 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -665,6 +665,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) pci_msi_set_enable(dev, 1); dev->msi_enabled = 1; + pcibios_free_irq(dev); dev->irq = entry->irq; return 0; } @@ -792,9 +793,9 @@ static int msix_capability_init(struct pci_dev *dev, /* Set MSI-X enabled bits and unmask the function */ pci_intx_for_msi(dev, 0); dev->msix_enabled = 1; - pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0); + pcibios_free_irq(dev); return 0; out_avail: @@ -909,6 +910,7 @@ void pci_msi_shutdown(struct pci_dev *dev) /* Restore dev->irq to its default pin-assertion irq */ dev->irq = desc->msi_attrib.default_irq; + pcibios_alloc_irq(dev); } void pci_disable_msi(struct pci_dev *dev) @@ -1009,6 +1011,7 @@ void pci_msix_shutdown(struct pci_dev *dev) pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0); pci_intx_for_msi(dev, 1); dev->msix_enabled = 0; + pcibios_alloc_irq(dev); } void pci_disable_msix(struct pci_dev *dev) -- cgit v1.3-6-gb490 From 0ae80ba91f57726f31b5b5890cb7c5173e624ca4 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 12 Jun 2015 16:12:48 +0200 Subject: scsi: retry MODE SENSE on unit attention The 'sd' driver is calling scsi_mode_sense() to figure out internal details. But scsi_mode_sense() never checks for any pending unit attentions, so we're getting annoying error messages like: MODE SENSE: unimplemented page/subpage: 0x00/0x00 and a possible wrong decision for device cache handling. Reviewed-by: Ewan Milne Signed-off-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 448ebdaa3d69..dffa91c67f5b 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2423,7 +2423,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, unsigned char cmd[12]; int use_10_for_ms; int header_length; - int result; + int result, retry_count = retries; struct scsi_sense_hdr my_sshdr; memset(data, 0, sizeof(*data)); @@ -2502,6 +2502,11 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, data->block_descriptor_length = buffer[3]; } data->header_length = header_length; + } else if ((status_byte(result) == CHECK_CONDITION) && + scsi_sense_valid(sshdr) && + sshdr->sense_key == UNIT_ATTENTION && retry_count) { + retry_count--; + goto retry; } return result; -- cgit v1.3-6-gb490 From bb8647e86e769bd45d2d5e010b3af516210d5760 Mon Sep 17 00:00:00 2001 From: Wen Xiong Date: Thu, 11 Jun 2015 20:45:18 -0500 Subject: ipr: Byte swapping for device_id attribute in sysfs On LE system, users see the wrong device_id attribute. This patch does necessary byte swapping for device_id attribute and works on both of LE and BE systems. Signed-off-by: Wen Xiong Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ipr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index a9aa38903efe..15da7544177c 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4455,7 +4455,7 @@ static ssize_t ipr_show_device_id(struct device *dev, struct device_attribute *a spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); res = (struct ipr_resource_entry *)sdev->hostdata; if (res && ioa_cfg->sis64) - len = snprintf(buf, PAGE_SIZE, "0x%llx\n", res->dev_id); + len = snprintf(buf, PAGE_SIZE, "0x%llx\n", be64_to_cpu(res->dev_id)); else if (res) len = snprintf(buf, PAGE_SIZE, "0x%llx\n", res->lun_wwn); -- cgit v1.3-6-gb490 From 359d96e73cea0ef2429db20e1a2322c75bc13830 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 11 Jun 2015 20:45:20 -0500 Subject: ipr: Endian / sparse fixes Some misc fixes for endianness checking with sparse so sparse with endian checking now runs clean. Fixes a minor bug in the process which was uncovered by sparse which would result in unnecessary error recovery for check conditions. Signed-off-by: Brian King Reviewed-by: Wen Xiong Signed-off-by: James Bottomley --- drivers/scsi/ipr.c | 13 +++++++------ drivers/scsi/ipr.h | 13 ++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 15da7544177c..341191952155 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -1165,7 +1165,8 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res, if (ioa_cfg->sis64) { proto = cfgtew->u.cfgte64->proto; - res->res_flags = cfgtew->u.cfgte64->res_flags; + res->flags = be16_to_cpu(cfgtew->u.cfgte64->flags); + res->res_flags = be16_to_cpu(cfgtew->u.cfgte64->res_flags); res->qmodel = IPR_QUEUEING_MODEL64(res); res->type = cfgtew->u.cfgte64->res_type; @@ -1313,8 +1314,8 @@ static void ipr_update_res_entry(struct ipr_resource_entry *res, int new_path = 0; if (res->ioa_cfg->sis64) { - res->flags = cfgtew->u.cfgte64->flags; - res->res_flags = cfgtew->u.cfgte64->res_flags; + res->flags = be16_to_cpu(cfgtew->u.cfgte64->flags); + res->res_flags = be16_to_cpu(cfgtew->u.cfgte64->res_flags); res->type = cfgtew->u.cfgte64->res_type; memcpy(&res->std_inq_data, &cfgtew->u.cfgte64->std_inq_data, @@ -1900,7 +1901,7 @@ static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg, * Return value: * none **/ -static void ipr_log_hex_data(struct ipr_ioa_cfg *ioa_cfg, u32 *data, int len) +static void ipr_log_hex_data(struct ipr_ioa_cfg *ioa_cfg, __be32 *data, int len) { int i; @@ -2270,7 +2271,7 @@ static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg, ((unsigned long)fabric + be16_to_cpu(fabric->length)); } - ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len); + ipr_log_hex_data(ioa_cfg, (__be32 *)fabric, add_len); } /** @@ -2364,7 +2365,7 @@ static void ipr_log_sis64_fabric_error(struct ipr_ioa_cfg *ioa_cfg, ((unsigned long)fabric + be16_to_cpu(fabric->length)); } - ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len); + ipr_log_hex_data(ioa_cfg, (__be32 *)fabric, add_len); } /** diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 6b97ee45c7b4..0cca05f0fc3d 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1005,13 +1005,13 @@ struct ipr_hostrcb_type_24_error { struct ipr_hostrcb_type_07_error { u8 failure_reason[64]; struct ipr_vpd vpd; - u32 data[222]; + __be32 data[222]; }__attribute__((packed, aligned (4))); struct ipr_hostrcb_type_17_error { u8 failure_reason[64]; struct ipr_ext_vpd vpd; - u32 data[476]; + __be32 data[476]; }__attribute__((packed, aligned (4))); struct ipr_hostrcb_config_element { @@ -1289,18 +1289,17 @@ struct ipr_resource_entry { (((res)->bus << 24) | ((res)->target << 8) | (res)->lun) u8 ata_class; - - u8 flags; - __be16 res_flags; - u8 type; + u16 flags; + u16 res_flags; + u8 qmodel; struct ipr_std_inq_data std_inq_data; __be32 res_handle; __be64 dev_id; - __be64 lun_wwn; + u64 lun_wwn; struct scsi_lun dev_lun; u8 res_path[8]; -- cgit v1.3-6-gb490 From aaf1b059387863ac9675eb42d01d03415c7529a5 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 11 Jun 2015 20:45:22 -0500 Subject: ipr: Driver version 2.6.2 Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ipr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 0cca05f0fc3d..e4fb17a58649 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -39,8 +39,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.6.1" -#define IPR_DRIVER_DATE "(March 12, 2015)" +#define IPR_DRIVER_VERSION "2.6.2" +#define IPR_DRIVER_DATE "(June 11, 2015)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding -- cgit v1.3-6-gb490 From 9c8108a4d3a837c51a29f28229a06d97654eaeb6 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 16 Jun 2015 16:07:13 -0700 Subject: iSCSI: let session recovery_tmo sysfs writes persist across recovery The iSCSI session recovery_tmo setting is writeable in sysfs, but it's also set every time a connection is established when parameters are set from iscsid over netlink. That results in the timeout being reset to the default value after every recovery. The DM multipath tools want to use the sysfs interface to lower the default timeout when there are multiple paths to fail over. It has caused confusion that we have a writeable sysfs value that seem to keep resetting itself. This patch adds an in-kernel flag that gets set once a sysfs write occurs, and then ignores netlink parameter setting once it's been modified via the sysfs interface. My thinking here is that the sysfs interface is much simpler for external tools to influence the session timeout, but if we're going to allow it to be modified directly we should ensure that setting is maintained. Signed-off-by: Chris Leech Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_iscsi.c | 11 ++++++++--- include/scsi/scsi_transport_iscsi.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 55647aae065c..4c25539abc84 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -2042,6 +2042,7 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport, session->transport = transport; session->creator = -1; session->recovery_tmo = 120; + session->recovery_tmo_sysfs_override = false; session->state = ISCSI_SESSION_FREE; INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); INIT_LIST_HEAD(&session->sess_list); @@ -2786,7 +2787,8 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) switch (ev->u.set_param.param) { case ISCSI_PARAM_SESS_RECOVERY_TMO: sscanf(data, "%d", &value); - session->recovery_tmo = value; + if (!session->recovery_tmo_sysfs_override) + session->recovery_tmo = value; break; default: err = transport->set_param(conn, ev->u.set_param.param, @@ -4049,13 +4051,15 @@ store_priv_session_##field(struct device *dev, \ if ((session->state == ISCSI_SESSION_FREE) || \ (session->state == ISCSI_SESSION_FAILED)) \ return -EBUSY; \ - if (strncmp(buf, "off", 3) == 0) \ + if (strncmp(buf, "off", 3) == 0) { \ session->field = -1; \ - else { \ + session->field##_sysfs_override = true; \ + } else { \ val = simple_strtoul(buf, &cp, 0); \ if (*cp != '\0' && *cp != '\n') \ return -EINVAL; \ session->field = val; \ + session->field##_sysfs_override = true; \ } \ return count; \ } @@ -4066,6 +4070,7 @@ store_priv_session_##field(struct device *dev, \ static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUSR, \ show_priv_session_##field, \ store_priv_session_##field) + iscsi_priv_session_rw_attr(recovery_tmo, "%d"); static struct attribute *iscsi_session_attrs[] = { diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 2555ee5343fd..6183d20a01fb 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -241,6 +241,7 @@ struct iscsi_cls_session { /* recovery fields */ int recovery_tmo; + bool recovery_tmo_sysfs_override; struct delayed_work recovery_work; unsigned int target_id; -- cgit v1.3-6-gb490 From 2dc127bb299d1c7436a08e79193bd0251068356e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 4 Jun 2015 17:47:56 +0300 Subject: hpsa: fix an sprintf() overflow in the reset handler The string "cmd %d RESET FAILED, new lockup detected" is not quite large enough so the sprintf() will overflow. I have increased the size of the buffer and also changed the sprintf calls to snprintf. Fixes: 73153fe533bc ('hpsa: use block layer tag for command allocation') Signed-off-by: Dan Carpenter Acked-by: Don Brace Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1dafeb43333b..cab4e98b2b0e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5104,7 +5104,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) int rc; struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; - char msg[40]; + char msg[48]; /* find the controller to which the command to be aborted was sent */ h = sdev_to_hba(scsicmd->device); @@ -5122,16 +5122,18 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) /* if controller locked up, we can guarantee command won't complete */ if (lockup_detected(h)) { - sprintf(msg, "cmd %d RESET FAILED, lockup detected", - hpsa_get_cmd_index(scsicmd)); + snprintf(msg, sizeof(msg), + "cmd %d RESET FAILED, lockup detected", + hpsa_get_cmd_index(scsicmd)); hpsa_show_dev_msg(KERN_WARNING, h, dev, msg); return FAILED; } /* this reset request might be the result of a lockup; check */ if (detect_controller_lockup(h)) { - sprintf(msg, "cmd %d RESET FAILED, new lockup detected", - hpsa_get_cmd_index(scsicmd)); + snprintf(msg, sizeof(msg), + "cmd %d RESET FAILED, new lockup detected", + hpsa_get_cmd_index(scsicmd)); hpsa_show_dev_msg(KERN_WARNING, h, dev, msg); return FAILED; } @@ -5145,7 +5147,8 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) /* send a reset to the SCSI LUN which the command was sent to */ rc = hpsa_do_reset(h, dev, dev->scsi3addr, HPSA_RESET_TYPE_LUN, DEFAULT_REPLY_QUEUE); - sprintf(msg, "reset %s", rc == 0 ? "completed successfully" : "failed"); + snprintf(msg, sizeof(msg), "reset %s", + rc == 0 ? "completed successfully" : "failed"); hpsa_show_dev_msg(KERN_WARNING, h, dev, msg); return rc == 0 ? SUCCESS : FAILED; } -- cgit v1.3-6-gb490 From 67546762978f523749eac157903e0b01c18e083a Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Fri, 17 Jul 2015 17:16:31 +0800 Subject: PCI: Protect pci_bus->slots with pci_slot_mutex, not pci_bus_sem Rajat Jain reported a deadlock when PCIe hot-add and AER recovery happen at the same time: thread 1: pciehp_enable_slot pciehp_configure_device pci_bus_add_devices pci_bus_add_device device_attach device_lock(dev) # acquire device lock ... pciehp_probe init_slot pci_hp_register pci_create_slot down_write(pci_bus_sem) # deadlock here thread 2: aer_isr_one_error aer_process_err_device do_recovery broadcast_error_message(..., report_error_detected) pci_walk_bus(..., cb=report_error_detected, ...) down_read(&pci_bus_sem) # acquire pci_bus_sem report_error_detected(dev) # cb() device_lock(dev) # deadlock here Previously, the bus->devices and bus->slots list were protected by pci_bus_sem. In pci_create_slot(), we held it for writing so we could add to the bus->slots list. Add a new local pci_slot_mutex to protect bus->slots. Hold pci_bus_sem for reading while searching the bus->devices list. [bhelgaas: changelog] Link: http://lkml.kernel.org/r/CAA93t1qpPqbih+UB0McA_d_+2rVaNkXsinAUxYzK9+JXSS+L-g@mail.gmail.com Reported-by: Rajat Jain Tested-by: Guenter Roeck Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- drivers/pci/slot.c | 18 +++++++++++------- include/linux/pci.h | 3 ++- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 396c200b9ddb..4bd3fce93fa4 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -14,6 +14,7 @@ struct kset *pci_slots_kset; EXPORT_SYMBOL_GPL(pci_slots_kset); +static DEFINE_MUTEX(pci_slot_mutex); static ssize_t pci_slot_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) @@ -106,9 +107,11 @@ static void pci_slot_release(struct kobject *kobj) dev_dbg(&slot->bus->dev, "dev %02x, released physical slot %s\n", slot->number, pci_slot_name(slot)); + down_read(&pci_bus_sem); list_for_each_entry(dev, &slot->bus->devices, bus_list) if (PCI_SLOT(dev->devfn) == slot->number) dev->slot = NULL; + up_read(&pci_bus_sem); list_del(&slot->list); @@ -194,9 +197,8 @@ static int rename_slot(struct pci_slot *slot, const char *name) static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) { struct pci_slot *slot; - /* - * We already hold pci_bus_sem so don't worry - */ + + /* We already hold pci_slot_mutex */ list_for_each_entry(slot, &parent->slots, list) if (slot->number == slot_nr) { kobject_get(&slot->kobj); @@ -253,7 +255,7 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, int err = 0; char *slot_name = NULL; - down_write(&pci_bus_sem); + mutex_lock(&pci_slot_mutex); if (slot_nr == -1) goto placeholder; @@ -301,16 +303,18 @@ placeholder: INIT_LIST_HEAD(&slot->list); list_add(&slot->list, &parent->slots); + down_read(&pci_bus_sem); list_for_each_entry(dev, &parent->devices, bus_list) if (PCI_SLOT(dev->devfn) == slot_nr) dev->slot = slot; + up_read(&pci_bus_sem); dev_dbg(&parent->dev, "dev %02x, created physical slot %s\n", slot_nr, pci_slot_name(slot)); out: kfree(slot_name); - up_write(&pci_bus_sem); + mutex_unlock(&pci_slot_mutex); return slot; err: kfree(slot); @@ -332,9 +336,9 @@ void pci_destroy_slot(struct pci_slot *slot) dev_dbg(&slot->bus->dev, "dev %02x, dec refcount to %d\n", slot->number, atomic_read(&slot->kobj.kref.refcount) - 1); - down_write(&pci_bus_sem); + mutex_lock(&pci_slot_mutex); kobject_put(&slot->kobj); - up_write(&pci_bus_sem); + mutex_unlock(&pci_slot_mutex); } EXPORT_SYMBOL_GPL(pci_destroy_slot); diff --git a/include/linux/pci.h b/include/linux/pci.h index 8a0321a8fb59..aaee493174e2 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -446,7 +446,8 @@ struct pci_bus { struct list_head children; /* list of child buses */ struct list_head devices; /* list of devices on this bus */ struct pci_dev *self; /* bridge device as seen by parent */ - struct list_head slots; /* list of slots on this bus */ + struct list_head slots; /* list of slots on this bus; + protected by pci_slot_mutex */ struct resource *resource[PCI_BRIDGE_RESOURCE_NUM]; struct list_head resources; /* address space routed to this bus */ struct resource busn_res; /* bus numbers routed to this bus */ -- cgit v1.3-6-gb490 From 2f51a9b8adbb6ad06689ec28342e89f40acb97fc Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 30 Jul 2015 00:44:20 +0300 Subject: net: phy: spi_ks8995: clean up ks8995_registers_read/write The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: David S. Miller --- drivers/net/phy/spi_ks8995.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c index 46530159256b..f091d691cf6f 100644 --- a/drivers/net/phy/spi_ks8995.c +++ b/drivers/net/phy/spi_ks8995.c @@ -209,8 +209,6 @@ static int ks8995_reset(struct ks8995_switch *ks) return ks8995_start(ks); } -/* ------------------------------------------------------------------------ */ - static ssize_t ks8995_registers_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { @@ -220,19 +218,9 @@ static ssize_t ks8995_registers_read(struct file *filp, struct kobject *kobj, dev = container_of(kobj, struct device, kobj); ks8995 = dev_get_drvdata(dev); - if (unlikely(off > ks8995->regs_attr.size)) - return 0; - - if ((off + count) > ks8995->regs_attr.size) - count = ks8995->regs_attr.size - off; - - if (unlikely(!count)) - return count; - return ks8995_read(ks8995, buf, off, count); } - static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { @@ -242,19 +230,9 @@ static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj, dev = container_of(kobj, struct device, kobj); ks8995 = dev_get_drvdata(dev); - if (unlikely(off >= ks8995->regs_attr.size)) - return -EFBIG; - - if ((off + count) > ks8995->regs_attr.size) - count = ks8995->regs_attr.size - off; - - if (unlikely(!count)) - return count; - return ks8995_write(ks8995, buf, off, count); } - static const struct bin_attribute ks8995_registers_attr = { .attr = { .name = "registers", -- cgit v1.3-6-gb490 From 017ffe64e8b8c8db0f50433a71da41c6a4e12710 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Fri, 17 Jul 2015 17:16:32 +0800 Subject: PCI: Hold pci_slot_mutex while searching bus->slots list Previously, pci_setup_device() and similar functions searched the pci_bus->slots list without any locking. It was possible for another thread to update the list while we searched it. Add pci_dev_assign_slot() to search the list while holding pci_slot_mutex. [bhelgaas: changelog, fold in CONFIG_SYSFS fix] Tested-by: Guenter Roeck Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- arch/powerpc/kernel/pci_of_scan.c | 6 +----- arch/sparc/kernel/pci.c | 6 +----- drivers/pci/probe.c | 6 +----- drivers/pci/slot.c | 11 +++++++++++ include/linux/pci.h | 5 +++++ 5 files changed, 19 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 42e02a2d570b..5e2debfc6ce5 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -126,7 +126,6 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, { struct pci_dev *dev; const char *type; - struct pci_slot *slot; dev = pci_alloc_dev(bus); if (!dev) @@ -145,10 +144,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, dev->needs_freset = 0; /* pcie fundamental reset required */ set_pcie_port_type(dev); - list_for_each_entry(slot, &dev->bus->slots, list) - if (PCI_SLOT(dev->devfn) == slot->number) - dev->slot = slot; - + pci_dev_assign_slot(dev); dev->vendor = get_int_prop(node, "vendor-id", 0xffff); dev->device = get_int_prop(node, "device-id", 0xffff); dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0); diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index c928bc64b4ba..3a0e1a986bfe 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -249,7 +249,6 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, struct pci_bus *bus, int devfn) { struct dev_archdata *sd; - struct pci_slot *slot; struct platform_device *op; struct pci_dev *dev; const char *type; @@ -290,10 +289,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, dev->multifunction = 0; /* maybe a lie? */ set_pcie_port_type(dev); - list_for_each_entry(slot, &dev->bus->slots, list) - if (PCI_SLOT(dev->devfn) == slot->number) - dev->slot = slot; - + pci_dev_assign_slot(dev); dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); dev->device = of_getintprop_default(node, "device-id", 0xffff); dev->subsystem_vendor = diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cefd636681b6..2a9ce16cb374 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1133,7 +1133,6 @@ int pci_setup_device(struct pci_dev *dev) { u32 class; u8 hdr_type; - struct pci_slot *slot; int pos = 0; struct pci_bus_region region; struct resource *res; @@ -1149,10 +1148,7 @@ int pci_setup_device(struct pci_dev *dev) dev->error_state = pci_channel_io_normal; set_pcie_port_type(dev); - list_for_each_entry(slot, &dev->bus->slots, list) - if (PCI_SLOT(dev->devfn) == slot->number) - dev->slot = slot; - + pci_dev_assign_slot(dev); /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) set this higher, assuming the system even supports it. */ dev->dma_mask = 0xffffffff; diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 4bd3fce93fa4..429d34c348b9 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -194,6 +194,17 @@ static int rename_slot(struct pci_slot *slot, const char *name) return result; } +void pci_dev_assign_slot(struct pci_dev *dev) +{ + struct pci_slot *slot; + + mutex_lock(&pci_slot_mutex); + list_for_each_entry(slot, &dev->bus->slots, list) + if (PCI_SLOT(dev->devfn) == slot->number) + dev->slot = slot; + mutex_unlock(&pci_slot_mutex); +} + static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) { struct pci_slot *slot; diff --git a/include/linux/pci.h b/include/linux/pci.h index aaee493174e2..b3ba7fef2916 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -798,6 +798,11 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, const char *name, struct hotplug_slot *hotplug); void pci_destroy_slot(struct pci_slot *slot); +#ifdef CONFIG_SYSFS +void pci_dev_assign_slot(struct pci_dev *dev); +#else +static inline void pci_dev_assign_slot(struct pci_dev *dev) { } +#endif int pci_scan_slot(struct pci_bus *bus, int devfn); struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn); void pci_device_add(struct pci_dev *dev, struct pci_bus *bus); -- cgit v1.3-6-gb490 From c21e0bbfc48509a776ec4a39bd9a0fb45a9c315b Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Tue, 9 Jun 2015 17:15:52 -0500 Subject: cxlflash: Base support for IBM CXL Flash Adapter SCSI device driver to support filesystem access on the IBM CXL Flash adapter. Supported-by: Stephen Bates Reviewed-by: Michael Neuling Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 1 + drivers/scsi/Makefile | 1 + drivers/scsi/cxlflash/Kconfig | 11 + drivers/scsi/cxlflash/Makefile | 2 + drivers/scsi/cxlflash/common.h | 180 +++ drivers/scsi/cxlflash/main.c | 2294 +++++++++++++++++++++++++++++++++++++++ drivers/scsi/cxlflash/main.h | 104 ++ drivers/scsi/cxlflash/sislite.h | 465 ++++++++ 8 files changed, 3058 insertions(+) create mode 100644 drivers/scsi/cxlflash/Kconfig create mode 100644 drivers/scsi/cxlflash/Makefile create mode 100644 drivers/scsi/cxlflash/common.h create mode 100644 drivers/scsi/cxlflash/main.c create mode 100644 drivers/scsi/cxlflash/main.h create mode 100755 drivers/scsi/cxlflash/sislite.h (limited to 'drivers') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 456e1567841c..95f7a76cfafc 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -345,6 +345,7 @@ source "drivers/scsi/cxgbi/Kconfig" source "drivers/scsi/bnx2i/Kconfig" source "drivers/scsi/bnx2fc/Kconfig" source "drivers/scsi/be2iscsi/Kconfig" +source "drivers/scsi/cxlflash/Kconfig" config SGIWD93_SCSI tristate "SGI WD93C93 SCSI Driver" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 91209e3d27e3..471d08791766 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -102,6 +102,7 @@ obj-$(CONFIG_SCSI_7000FASST) += wd7000.o obj-$(CONFIG_SCSI_EATA) += eata.o obj-$(CONFIG_SCSI_DC395x) += dc395x.o obj-$(CONFIG_SCSI_AM53C974) += esp_scsi.o am53c974.o +obj-$(CONFIG_CXLFLASH) += cxlflash/ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ obj-$(CONFIG_MEGARAID_SAS) += megaraid/ diff --git a/drivers/scsi/cxlflash/Kconfig b/drivers/scsi/cxlflash/Kconfig new file mode 100644 index 000000000000..c7075084cfdb --- /dev/null +++ b/drivers/scsi/cxlflash/Kconfig @@ -0,0 +1,11 @@ +# +# IBM CXL-attached Flash Accelerator SCSI Driver +# + +config CXLFLASH + tristate "Support for IBM CAPI Flash" + depends on PCI && SCSI && CXL + default m + help + Allows CAPI Accelerated IO to Flash + If unsure, say N. diff --git a/drivers/scsi/cxlflash/Makefile b/drivers/scsi/cxlflash/Makefile new file mode 100644 index 000000000000..dc95e203e3af --- /dev/null +++ b/drivers/scsi/cxlflash/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_CXLFLASH) += cxlflash.o +cxlflash-y += main.o diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h new file mode 100644 index 000000000000..5f43608dc8a1 --- /dev/null +++ b/drivers/scsi/cxlflash/common.h @@ -0,0 +1,180 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _CXLFLASH_COMMON_H +#define _CXLFLASH_COMMON_H + +#include +#include +#include +#include + + +#define MAX_CONTEXT CXLFLASH_MAX_CONTEXT /* num contexts per afu */ + +#define CXLFLASH_BLOCK_SIZE 4096 /* 4K blocks */ +#define CXLFLASH_MAX_XFER_SIZE 16777216 /* 16MB transfer */ +#define CXLFLASH_MAX_SECTORS (CXLFLASH_MAX_XFER_SIZE/512) /* SCSI wants + max_sectors + in units of + 512 byte + sectors + */ + +#define NUM_RRQ_ENTRY 16 /* for master issued cmds */ +#define MAX_RHT_PER_CONTEXT (PAGE_SIZE / sizeof(struct sisl_rht_entry)) + +/* AFU command retry limit */ +#define MC_RETRY_CNT 5 /* sufficient for SCSI check and + certain AFU errors */ + +/* Command management definitions */ +#define CXLFLASH_NUM_CMDS (2 * CXLFLASH_MAX_CMDS) /* Must be a pow2 for + alignment and more + efficient array + index derivation + */ + +#define CXLFLASH_MAX_CMDS 16 +#define CXLFLASH_MAX_CMDS_PER_LUN CXLFLASH_MAX_CMDS + + +static inline void check_sizes(void) +{ + BUILD_BUG_ON_NOT_POWER_OF_2(CXLFLASH_NUM_CMDS); +} + +/* AFU defines a fixed size of 4K for command buffers (borrow 4K page define) */ +#define CMD_BUFSIZE SIZE_4K + +/* flags in IOA status area for host use */ +#define B_DONE 0x01 +#define B_ERROR 0x02 /* set with B_DONE */ +#define B_TIMEOUT 0x04 /* set with B_DONE & B_ERROR */ + +enum cxlflash_lr_state { + LINK_RESET_INVALID, + LINK_RESET_REQUIRED, + LINK_RESET_COMPLETE +}; + +enum cxlflash_init_state { + INIT_STATE_NONE, + INIT_STATE_PCI, + INIT_STATE_AFU, + INIT_STATE_SCSI +}; + +/* + * Each context has its own set of resource handles that is visible + * only from that context. + */ + +struct cxlflash_cfg { + struct afu *afu; + struct cxl_context *mcctx; + + struct pci_dev *dev; + struct pci_device_id *dev_id; + struct Scsi_Host *host; + + ulong cxlflash_regs_pci; + + wait_queue_head_t eeh_waitq; + + struct work_struct work_q; + enum cxlflash_init_state init_state; + enum cxlflash_lr_state lr_state; + int lr_port; + + struct cxl_afu *cxl_afu; + + struct pci_pool *cxlflash_cmd_pool; + struct pci_dev *parent_dev; + + wait_queue_head_t tmf_waitq; + bool tmf_active; + u8 err_recovery_active:1; +}; + +struct afu_cmd { + struct sisl_ioarcb rcb; /* IOARCB (cache line aligned) */ + struct sisl_ioasa sa; /* IOASA must follow IOARCB */ + spinlock_t slock; + struct completion cevent; + char *buf; /* per command buffer */ + struct afu *parent; + int slot; + atomic_t free; + + u8 cmd_tmf:1; + + /* As per the SISLITE spec the IOARCB EA has to be 16-byte aligned. + * However for performance reasons the IOARCB/IOASA should be + * cache line aligned. + */ +} __aligned(cache_line_size()); + +struct afu { + /* Stuff requiring alignment go first. */ + + u64 rrq_entry[NUM_RRQ_ENTRY]; /* 128B RRQ */ + /* + * Command & data for AFU commands. + */ + struct afu_cmd cmd[CXLFLASH_NUM_CMDS]; + + /* Beware of alignment till here. Preferably introduce new + * fields after this point + */ + + /* AFU HW */ + struct cxl_ioctl_start_work work; + struct cxlflash_afu_map *afu_map; /* entire MMIO map */ + struct sisl_host_map *host_map; /* MC host map */ + struct sisl_ctrl_map *ctrl_map; /* MC control map */ + + ctx_hndl_t ctx_hndl; /* master's context handle */ + u64 *hrrq_start; + u64 *hrrq_end; + u64 *hrrq_curr; + bool toggle; + bool read_room; + atomic64_t room; + u64 hb; + u32 cmd_couts; /* Number of command checkouts */ + u32 internal_lun; /* User-desired LUN mode for this AFU */ + + char version[8]; + u64 interface_version; + + struct cxlflash_cfg *parent; /* Pointer back to parent cxlflash_cfg */ + +}; + +static inline u64 lun_to_lunid(u64 lun) +{ + u64 lun_id; + + int_to_scsilun(lun, (struct scsi_lun *)&lun_id); + return swab64(lun_id); +} + +int cxlflash_send_cmd(struct afu *, struct afu_cmd *); +void cxlflash_wait_resp(struct afu *, struct afu_cmd *); +int cxlflash_afu_reset(struct cxlflash_cfg *); +struct afu_cmd *cxlflash_cmd_checkout(struct afu *); +void cxlflash_cmd_checkin(struct afu_cmd *); +int cxlflash_afu_sync(struct afu *, ctx_hndl_t, res_hndl_t, u8); +#endif /* ifndef _CXLFLASH_COMMON_H */ diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c new file mode 100644 index 000000000000..0720d2f13c2a --- /dev/null +++ b/drivers/scsi/cxlflash/main.c @@ -0,0 +1,2294 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include "main.h" +#include "sislite.h" +#include "common.h" + +MODULE_DESCRIPTION(CXLFLASH_ADAPTER_NAME); +MODULE_AUTHOR("Manoj N. Kumar "); +MODULE_AUTHOR("Matthew R. Ochs "); +MODULE_LICENSE("GPL"); + + +/** + * cxlflash_cmd_checkout() - checks out an AFU command + * @afu: AFU to checkout from. + * + * Commands are checked out in a round-robin fashion. Note that since + * the command pool is larger than the hardware queue, the majority of + * times we will only loop once or twice before getting a command. The + * buffer and CDB within the command are initialized (zeroed) prior to + * returning. + * + * Return: The checked out command or NULL when command pool is empty. + */ +struct afu_cmd *cxlflash_cmd_checkout(struct afu *afu) +{ + int k, dec = CXLFLASH_NUM_CMDS; + struct afu_cmd *cmd; + + while (dec--) { + k = (afu->cmd_couts++ & (CXLFLASH_NUM_CMDS - 1)); + + cmd = &afu->cmd[k]; + + if (!atomic_dec_if_positive(&cmd->free)) { + pr_debug("%s: returning found index=%d\n", + __func__, cmd->slot); + memset(cmd->buf, 0, CMD_BUFSIZE); + memset(cmd->rcb.cdb, 0, sizeof(cmd->rcb.cdb)); + return cmd; + } + } + + return NULL; +} + +/** + * cxlflash_cmd_checkin() - checks in an AFU command + * @cmd: AFU command to checkin. + * + * Safe to pass commands that have already been checked in. Several + * internal tracking fields are reset as part of the checkin. Note + * that these are intentionally reset prior to toggling the free bit + * to avoid clobbering values in the event that the command is checked + * out right away. + */ +void cxlflash_cmd_checkin(struct afu_cmd *cmd) +{ + cmd->rcb.scp = NULL; + cmd->rcb.timeout = 0; + cmd->sa.ioasc = 0; + cmd->cmd_tmf = false; + cmd->sa.host_use[0] = 0; /* clears both completion and retry bytes */ + + if (unlikely(atomic_inc_return(&cmd->free) != 1)) { + pr_err("%s: Freeing cmd (%d) that is not in use!\n", + __func__, cmd->slot); + return; + } + + pr_debug("%s: released cmd %p index=%d\n", __func__, cmd, cmd->slot); +} + +/** + * process_cmd_err() - command error handler + * @cmd: AFU command that experienced the error. + * @scp: SCSI command associated with the AFU command in error. + * + * Translates error bits from AFU command to SCSI command results. + */ +static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) +{ + struct sisl_ioarcb *ioarcb; + struct sisl_ioasa *ioasa; + + if (unlikely(!cmd)) + return; + + ioarcb = &(cmd->rcb); + ioasa = &(cmd->sa); + + if (ioasa->rc.flags & SISL_RC_FLAGS_UNDERRUN) { + pr_debug("%s: cmd underrun cmd = %p scp = %p\n", + __func__, cmd, scp); + scp->result = (DID_ERROR << 16); + } + + if (ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN) { + pr_debug("%s: cmd underrun cmd = %p scp = %p\n", + __func__, cmd, scp); + scp->result = (DID_ERROR << 16); + } + + pr_debug("%s: cmd failed afu_rc=%d scsi_rc=%d fc_rc=%d " + "afu_extra=0x%X, scsi_entra=0x%X, fc_extra=0x%X\n", + __func__, ioasa->rc.afu_rc, ioasa->rc.scsi_rc, + ioasa->rc.fc_rc, ioasa->afu_extra, ioasa->scsi_extra, + ioasa->fc_extra); + + if (ioasa->rc.scsi_rc) { + /* We have a SCSI status */ + if (ioasa->rc.flags & SISL_RC_FLAGS_SENSE_VALID) { + memcpy(scp->sense_buffer, ioasa->sense_data, + SISL_SENSE_DATA_LEN); + scp->result = ioasa->rc.scsi_rc; + } else + scp->result = ioasa->rc.scsi_rc | (DID_ERROR << 16); + } + + /* + * We encountered an error. Set scp->result based on nature + * of error. + */ + if (ioasa->rc.fc_rc) { + /* We have an FC status */ + switch (ioasa->rc.fc_rc) { + case SISL_FC_RC_LINKDOWN: + scp->result = (DID_REQUEUE << 16); + break; + case SISL_FC_RC_RESID: + /* This indicates an FCP resid underrun */ + if (!(ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN)) { + /* If the SISL_RC_FLAGS_OVERRUN flag was set, + * then we will handle this error else where. + * If not then we must handle it here. + * This is probably an AFU bug. We will + * attempt a retry to see if that resolves it. + */ + scp->result = (DID_ERROR << 16); + } + break; + case SISL_FC_RC_RESIDERR: + /* Resid mismatch between adapter and device */ + case SISL_FC_RC_TGTABORT: + case SISL_FC_RC_ABORTOK: + case SISL_FC_RC_ABORTFAIL: + case SISL_FC_RC_NOLOGI: + case SISL_FC_RC_ABORTPEND: + case SISL_FC_RC_WRABORTPEND: + case SISL_FC_RC_NOEXP: + case SISL_FC_RC_INUSE: + scp->result = (DID_ERROR << 16); + break; + } + } + + if (ioasa->rc.afu_rc) { + /* We have an AFU error */ + switch (ioasa->rc.afu_rc) { + case SISL_AFU_RC_NO_CHANNELS: + scp->result = (DID_MEDIUM_ERROR << 16); + break; + case SISL_AFU_RC_DATA_DMA_ERR: + switch (ioasa->afu_extra) { + case SISL_AFU_DMA_ERR_PAGE_IN: + /* Retry */ + scp->result = (DID_IMM_RETRY << 16); + break; + case SISL_AFU_DMA_ERR_INVALID_EA: + default: + scp->result = (DID_ERROR << 16); + } + break; + case SISL_AFU_RC_OUT_OF_DATA_BUFS: + /* Retry */ + scp->result = (DID_ALLOC_FAILURE << 16); + break; + default: + scp->result = (DID_ERROR << 16); + } + } +} + +/** + * cmd_complete() - command completion handler + * @cmd: AFU command that has completed. + * + * Prepares and submits command that has either completed or timed out to + * the SCSI stack. Checks AFU command back into command pool for non-internal + * (rcb.scp populated) commands. + */ +static void cmd_complete(struct afu_cmd *cmd) +{ + struct scsi_cmnd *scp; + u32 resid; + ulong lock_flags; + struct afu *afu = cmd->parent; + struct cxlflash_cfg *cfg = afu->parent; + bool cmd_is_tmf; + + spin_lock_irqsave(&cmd->slock, lock_flags); + cmd->sa.host_use_b[0] |= B_DONE; + spin_unlock_irqrestore(&cmd->slock, lock_flags); + + if (cmd->rcb.scp) { + scp = cmd->rcb.scp; + if (unlikely(cmd->sa.rc.afu_rc || + cmd->sa.rc.scsi_rc || + cmd->sa.rc.fc_rc)) + process_cmd_err(cmd, scp); + else + scp->result = (DID_OK << 16); + + resid = cmd->sa.resid; + cmd_is_tmf = cmd->cmd_tmf; + cxlflash_cmd_checkin(cmd); /* Don't use cmd after here */ + + pr_debug("%s: calling scsi_set_resid, scp=%p " + "result=%X resid=%d\n", __func__, + scp, scp->result, resid); + + scsi_set_resid(scp, resid); + scsi_dma_unmap(scp); + scp->scsi_done(scp); + + if (cmd_is_tmf) { + spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + cfg->tmf_active = false; + wake_up_all_locked(&cfg->tmf_waitq); + spin_unlock_irqrestore(&cfg->tmf_waitq.lock, + lock_flags); + } + } else + complete(&cmd->cevent); +} + +/** + * send_tmf() - sends a Task Management Function (TMF) + * @afu: AFU to checkout from. + * @scp: SCSI command from stack. + * @tmfcmd: TMF command to send. + * + * Return: + * 0 on success + * SCSI_MLQUEUE_HOST_BUSY when host is busy + */ +static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) +{ + struct afu_cmd *cmd; + + u32 port_sel = scp->device->channel + 1; + short lflag = 0; + struct Scsi_Host *host = scp->device->host; + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + ulong lock_flags; + int rc = 0; + + cmd = cxlflash_cmd_checkout(afu); + if (unlikely(!cmd)) { + pr_err("%s: could not get a free command\n", __func__); + rc = SCSI_MLQUEUE_HOST_BUSY; + goto out; + } + + /* If a Task Management Function is active, do not send one more. + */ + spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + if (cfg->tmf_active) + wait_event_interruptible_locked_irq(cfg->tmf_waitq, + !cfg->tmf_active); + cfg->tmf_active = true; + cmd->cmd_tmf = true; + spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + + cmd->rcb.ctx_id = afu->ctx_hndl; + cmd->rcb.port_sel = port_sel; + cmd->rcb.lun_id = lun_to_lunid(scp->device->lun); + + lflag = SISL_REQ_FLAGS_TMF_CMD; + + cmd->rcb.req_flags = (SISL_REQ_FLAGS_PORT_LUN_ID | + SISL_REQ_FLAGS_SUP_UNDERRUN | lflag); + + /* Stash the scp in the reserved field, for reuse during interrupt */ + cmd->rcb.scp = scp; + + /* Copy the CDB from the cmd passed in */ + memcpy(cmd->rcb.cdb, &tmfcmd, sizeof(tmfcmd)); + + /* Send the command */ + rc = cxlflash_send_cmd(afu, cmd); + if (unlikely(rc)) { + cxlflash_cmd_checkin(cmd); + spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + cfg->tmf_active = false; + spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + goto out; + } + + spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + wait_event_interruptible_locked_irq(cfg->tmf_waitq, !cfg->tmf_active); + spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); +out: + return rc; +} + +/** + * cxlflash_driver_info() - information handler for this host driver + * @host: SCSI host associated with device. + * + * Return: A string describing the device. + */ +static const char *cxlflash_driver_info(struct Scsi_Host *host) +{ + return CXLFLASH_ADAPTER_NAME; +} + +/** + * cxlflash_queuecommand() - sends a mid-layer request + * @host: SCSI host associated with device. + * @scp: SCSI command to send. + * + * Return: + * 0 on success + * SCSI_MLQUEUE_HOST_BUSY when host is busy + */ +static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct afu *afu = cfg->afu; + struct pci_dev *pdev = cfg->dev; + struct afu_cmd *cmd; + u32 port_sel = scp->device->channel + 1; + int nseg, i, ncount; + struct scatterlist *sg; + ulong lock_flags; + short lflag = 0; + int rc = 0; + + pr_debug("%s: (scp=%p) %d/%d/%d/%llu cdb=(%08X-%08X-%08X-%08X)\n", + __func__, scp, host->host_no, scp->device->channel, + scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + + /* If a Task Management Function is active, wait for it to complete + * before continuing with regular commands. + */ + spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + if (cfg->tmf_active) { + spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + rc = SCSI_MLQUEUE_HOST_BUSY; + goto out; + } + spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + + cmd = cxlflash_cmd_checkout(afu); + if (unlikely(!cmd)) { + pr_err("%s: could not get a free command\n", __func__); + rc = SCSI_MLQUEUE_HOST_BUSY; + goto out; + } + + cmd->rcb.ctx_id = afu->ctx_hndl; + cmd->rcb.port_sel = port_sel; + cmd->rcb.lun_id = lun_to_lunid(scp->device->lun); + + if (scp->sc_data_direction == DMA_TO_DEVICE) + lflag = SISL_REQ_FLAGS_HOST_WRITE; + else + lflag = SISL_REQ_FLAGS_HOST_READ; + + cmd->rcb.req_flags = (SISL_REQ_FLAGS_PORT_LUN_ID | + SISL_REQ_FLAGS_SUP_UNDERRUN | lflag); + + /* Stash the scp in the reserved field, for reuse during interrupt */ + cmd->rcb.scp = scp; + + nseg = scsi_dma_map(scp); + if (unlikely(nseg < 0)) { + dev_err(&pdev->dev, "%s: Fail DMA map! nseg=%d\n", + __func__, nseg); + rc = SCSI_MLQUEUE_HOST_BUSY; + goto out; + } + + ncount = scsi_sg_count(scp); + scsi_for_each_sg(scp, sg, ncount, i) { + cmd->rcb.data_len = sg_dma_len(sg); + cmd->rcb.data_ea = sg_dma_address(sg); + } + + /* Copy the CDB from the scsi_cmnd passed in */ + memcpy(cmd->rcb.cdb, scp->cmnd, sizeof(cmd->rcb.cdb)); + + /* Send the command */ + rc = cxlflash_send_cmd(afu, cmd); + if (unlikely(rc)) { + cxlflash_cmd_checkin(cmd); + scsi_dma_unmap(scp); + } + +out: + return rc; +} + +/** + * cxlflash_eh_device_reset_handler() - reset a single LUN + * @scp: SCSI command to send. + * + * Return: + * SUCCESS as defined in scsi/scsi.h + * FAILED as defined in scsi/scsi.h + */ +static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) +{ + int rc = SUCCESS; + struct Scsi_Host *host = scp->device->host; + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct afu *afu = cfg->afu; + int rcr = 0; + + pr_debug("%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, + host->host_no, scp->device->channel, + scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + + rcr = send_tmf(afu, scp, TMF_LUN_RESET); + if (unlikely(rcr)) + rc = FAILED; + + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_eh_host_reset_handler() - reset the host adapter + * @scp: SCSI command from stack identifying host. + * + * Return: + * SUCCESS as defined in scsi/scsi.h + * FAILED as defined in scsi/scsi.h + */ +static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) +{ + int rc = SUCCESS; + int rcr = 0; + struct Scsi_Host *host = scp->device->host; + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + + pr_debug("%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, + host->host_no, scp->device->channel, + scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + + rcr = cxlflash_afu_reset(cfg); + if (rcr == 0) + rc = SUCCESS; + else + rc = FAILED; + + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_change_queue_depth() - change the queue depth for the device + * @sdev: SCSI device destined for queue depth change. + * @qdepth: Requested queue depth value to set. + * + * The requested queue depth is capped to the maximum supported value. + * + * Return: The actual queue depth set. + */ +static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth) +{ + + if (qdepth > CXLFLASH_MAX_CMDS_PER_LUN) + qdepth = CXLFLASH_MAX_CMDS_PER_LUN; + + scsi_change_queue_depth(sdev, qdepth); + return sdev->queue_depth; +} + +/** + * cxlflash_show_port_status() - queries and presents the current port status + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_port_status(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + char *disp_status; + int rc; + u32 port; + u64 status; + u64 *fc_regs; + + rc = kstrtouint((attr->attr.name + 4), 10, &port); + if (rc || (port > NUM_FC_PORTS)) + return 0; + + fc_regs = &afu->afu_map->global.fc_regs[port][0]; + status = + (readq_be(&fc_regs[FC_MTIP_STATUS / 8]) & FC_MTIP_STATUS_MASK); + + if (status == FC_MTIP_STATUS_ONLINE) + disp_status = "online"; + else if (status == FC_MTIP_STATUS_OFFLINE) + disp_status = "offline"; + else + disp_status = "unknown"; + + return snprintf(buf, PAGE_SIZE, "%s\n", disp_status); +} + +/** + * cxlflash_show_lun_mode() - presents the current LUN mode of the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the lun mode. + * @buf: Buffer of length PAGE_SIZE to report back the LUN mode in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_lun_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + return snprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun); +} + +/** + * cxlflash_store_lun_mode() - sets the LUN mode of the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the lun mode. + * @buf: Buffer of length PAGE_SIZE containing the LUN mode in ASCII. + * @count: Length of data resizing in @buf. + * + * The CXL Flash AFU supports a dummy LUN mode where the external + * links and storage are not required. Space on the FPGA is used + * to create 1 or 2 small LUNs which are presented to the system + * as if they were a normal storage device. This feature is useful + * during development and also provides manufacturing with a way + * to test the AFU without an actual device. + * + * 0 = external LUN[s] (default) + * 1 = internal LUN (1 x 64K, 512B blocks, id 0) + * 2 = internal LUN (1 x 64K, 4K blocks, id 0) + * 3 = internal LUN (2 x 32K, 512B blocks, ids 0,1) + * 4 = internal LUN (2 x 32K, 4K blocks, ids 0,1) + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_store_lun_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + int rc; + u32 lun_mode; + + rc = kstrtouint(buf, 10, &lun_mode); + if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) { + afu->internal_lun = lun_mode; + cxlflash_afu_reset(cfg); + scsi_scan_host(cfg->host); + } + + return count; +} + +/** + * cxlflash_show_dev_mode() - presents the current mode of the device + * @dev: Generic device associated with the device. + * @attr: Device attribute representing the device mode. + * @buf: Buffer of length PAGE_SIZE to report back the dev mode in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_dev_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + return snprintf(buf, PAGE_SIZE, "%s\n", + sdev->hostdata ? "superpipe" : "legacy"); +} + +/** + * cxlflash_wait_for_pci_err_recovery() - wait for error recovery during probe + * @cxlflash: Internal structure associated with the host. + */ +static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) +{ + struct pci_dev *pdev = cfg->dev; + + if (pci_channel_offline(pdev)) + wait_event_timeout(cfg->eeh_waitq, + !pci_channel_offline(pdev), + CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT); +} + +/* + * Host attributes + */ +static DEVICE_ATTR(port0, S_IRUGO, cxlflash_show_port_status, NULL); +static DEVICE_ATTR(port1, S_IRUGO, cxlflash_show_port_status, NULL); +static DEVICE_ATTR(lun_mode, S_IRUGO | S_IWUSR, cxlflash_show_lun_mode, + cxlflash_store_lun_mode); + +static struct device_attribute *cxlflash_host_attrs[] = { + &dev_attr_port0, + &dev_attr_port1, + &dev_attr_lun_mode, + NULL +}; + +/* + * Device attributes + */ +static DEVICE_ATTR(mode, S_IRUGO, cxlflash_show_dev_mode, NULL); + +static struct device_attribute *cxlflash_dev_attrs[] = { + &dev_attr_mode, + NULL +}; + +/* + * Host template + */ +static struct scsi_host_template driver_template = { + .module = THIS_MODULE, + .name = CXLFLASH_ADAPTER_NAME, + .info = cxlflash_driver_info, + .proc_name = CXLFLASH_NAME, + .queuecommand = cxlflash_queuecommand, + .eh_device_reset_handler = cxlflash_eh_device_reset_handler, + .eh_host_reset_handler = cxlflash_eh_host_reset_handler, + .change_queue_depth = cxlflash_change_queue_depth, + .cmd_per_lun = 16, + .can_queue = CXLFLASH_MAX_CMDS, + .this_id = -1, + .sg_tablesize = SG_NONE, /* No scatter gather support. */ + .max_sectors = CXLFLASH_MAX_SECTORS, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = cxlflash_host_attrs, + .sdev_attrs = cxlflash_dev_attrs, +}; + +/* + * Device dependent values + */ +static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS }; + +/* + * PCI device binding table + */ +static struct pci_device_id cxlflash_pci_table[] = { + {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals}, + {} +}; + +MODULE_DEVICE_TABLE(pci, cxlflash_pci_table); + +/** + * free_mem() - free memory associated with the AFU + * @cxlflash: Internal structure associated with the host. + */ +static void free_mem(struct cxlflash_cfg *cfg) +{ + int i; + char *buf = NULL; + struct afu *afu = cfg->afu; + + if (cfg->afu) { + for (i = 0; i < CXLFLASH_NUM_CMDS; i++) { + buf = afu->cmd[i].buf; + if (!((u64)buf & (PAGE_SIZE - 1))) + free_page((ulong)buf); + } + + free_pages((ulong)afu, get_order(sizeof(struct afu))); + cfg->afu = NULL; + } +} + +/** + * stop_afu() - stops the AFU command timers and unmaps the MMIO space + * @cxlflash: Internal structure associated with the host. + * + * Safe to call with AFU in a partially allocated/initialized state. + */ +static void stop_afu(struct cxlflash_cfg *cfg) +{ + int i; + struct afu *afu = cfg->afu; + + if (likely(afu)) { + for (i = 0; i < CXLFLASH_NUM_CMDS; i++) + complete(&afu->cmd[i].cevent); + + if (likely(afu->afu_map)) { + cxl_psa_unmap((void *)afu->afu_map); + afu->afu_map = NULL; + } + } +} + +/** + * term_mc() - terminates the master context + * @cxlflash: Internal structure associated with the host. + * @level: Depth of allocation, where to begin waterfall tear down. + * + * Safe to call with AFU/MC in partially allocated/initialized state. + */ +static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level) +{ + int rc = 0; + struct afu *afu = cfg->afu; + + if (!afu || !cfg->mcctx) { + pr_err("%s: returning from term_mc with NULL afu or MC\n", + __func__); + return; + } + + switch (level) { + case UNDO_START: + rc = cxl_stop_context(cfg->mcctx); + BUG_ON(rc); + case UNMAP_THREE: + cxl_unmap_afu_irq(cfg->mcctx, 3, afu); + case UNMAP_TWO: + cxl_unmap_afu_irq(cfg->mcctx, 2, afu); + case UNMAP_ONE: + cxl_unmap_afu_irq(cfg->mcctx, 1, afu); + case FREE_IRQ: + cxl_free_afu_irqs(cfg->mcctx); + case RELEASE_CONTEXT: + cfg->mcctx = NULL; + } +} + +/** + * term_afu() - terminates the AFU + * @cxlflash: Internal structure associated with the host. + * + * Safe to call with AFU/MC in partially allocated/initialized state. + */ +static void term_afu(struct cxlflash_cfg *cfg) +{ + term_mc(cfg, UNDO_START); + + if (cfg->afu) + stop_afu(cfg); + + pr_debug("%s: returning\n", __func__); +} + +/** + * cxlflash_remove() - PCI entry point to tear down host + * @pdev: PCI device associated with the host. + * + * Safe to use as a cleanup in partially allocated/initialized state. + */ +static void cxlflash_remove(struct pci_dev *pdev) +{ + struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); + ulong lock_flags; + + /* If a Task Management Function is active, wait for it to complete + * before continuing with remove. + */ + spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + if (cfg->tmf_active) + wait_event_interruptible_locked_irq(cfg->tmf_waitq, + !cfg->tmf_active); + spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + + switch (cfg->init_state) { + case INIT_STATE_SCSI: + scsi_remove_host(cfg->host); + scsi_host_put(cfg->host); + /* Fall through */ + case INIT_STATE_AFU: + term_afu(cfg); + case INIT_STATE_PCI: + pci_release_regions(cfg->dev); + pci_disable_device(pdev); + case INIT_STATE_NONE: + flush_work(&cfg->work_q); + free_mem(cfg); + break; + } + + pr_debug("%s: returning\n", __func__); +} + +/** + * alloc_mem() - allocates the AFU and its command pool + * @cxlflash: Internal structure associated with the host. + * + * A partially allocated state remains on failure. + * + * Return: + * 0 on success + * -ENOMEM on failure to allocate memory + */ +static int alloc_mem(struct cxlflash_cfg *cfg) +{ + int rc = 0; + int i; + char *buf = NULL; + + /* This allocation is about 12K, i.e. only 1 64k page + * and upto 4 4k pages + */ + cfg->afu = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + get_order(sizeof(struct afu))); + if (unlikely(!cfg->afu)) { + pr_err("%s: cannot get %d free pages\n", + __func__, get_order(sizeof(struct afu))); + rc = -ENOMEM; + goto out; + } + cfg->afu->parent = cfg; + cfg->afu->afu_map = NULL; + + for (i = 0; i < CXLFLASH_NUM_CMDS; buf += CMD_BUFSIZE, i++) { + if (!((u64)buf & (PAGE_SIZE - 1))) { + buf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + if (unlikely(!buf)) { + pr_err("%s: Allocate command buffers fail!\n", + __func__); + rc = -ENOMEM; + free_mem(cfg); + goto out; + } + } + + cfg->afu->cmd[i].buf = buf; + atomic_set(&cfg->afu->cmd[i].free, 1); + cfg->afu->cmd[i].slot = i; + } + +out: + return rc; +} + +/** + * init_pci() - initializes the host as a PCI device + * @cxlflash: Internal structure associated with the host. + * + * Return: + * 0 on success + * -EIO on unable to communicate with device + * A return code from the PCI sub-routines + */ +static int init_pci(struct cxlflash_cfg *cfg) +{ + struct pci_dev *pdev = cfg->dev; + int rc = 0; + + cfg->cxlflash_regs_pci = pci_resource_start(pdev, 0); + rc = pci_request_regions(pdev, CXLFLASH_NAME); + if (rc < 0) { + dev_err(&pdev->dev, + "%s: Couldn't register memory range of registers\n", + __func__); + goto out; + } + + rc = pci_enable_device(pdev); + if (rc || pci_channel_offline(pdev)) { + if (pci_channel_offline(pdev)) { + cxlflash_wait_for_pci_err_recovery(cfg); + rc = pci_enable_device(pdev); + } + + if (rc) { + dev_err(&pdev->dev, "%s: Cannot enable adapter\n", + __func__); + cxlflash_wait_for_pci_err_recovery(cfg); + goto out_release_regions; + } + } + + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc < 0) { + dev_dbg(&pdev->dev, "%s: Failed to set 64 bit PCI DMA mask\n", + __func__); + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + } + + if (rc < 0) { + dev_err(&pdev->dev, "%s: Failed to set PCI DMA mask\n", + __func__); + goto out_disable; + } + + pci_set_master(pdev); + + if (pci_channel_offline(pdev)) { + cxlflash_wait_for_pci_err_recovery(cfg); + if (pci_channel_offline(pdev)) { + rc = -EIO; + goto out_msi_disable; + } + } + + rc = pci_save_state(pdev); + + if (rc != PCIBIOS_SUCCESSFUL) { + dev_err(&pdev->dev, "%s: Failed to save PCI config space\n", + __func__); + rc = -EIO; + goto cleanup_nolog; + } + +out: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; + +cleanup_nolog: +out_msi_disable: + cxlflash_wait_for_pci_err_recovery(cfg); +out_disable: + pci_disable_device(pdev); +out_release_regions: + pci_release_regions(pdev); + goto out; + +} + +/** + * init_scsi() - adds the host to the SCSI stack and kicks off host scan + * @cxlflash: Internal structure associated with the host. + * + * Return: + * 0 on success + * A return code from adding the host + */ +static int init_scsi(struct cxlflash_cfg *cfg) +{ + struct pci_dev *pdev = cfg->dev; + int rc = 0; + + rc = scsi_add_host(cfg->host, &pdev->dev); + if (rc) { + dev_err(&pdev->dev, "%s: scsi_add_host failed (rc=%d)\n", + __func__, rc); + goto out; + } + + scsi_scan_host(cfg->host); + +out: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * set_port_online() - transitions the specified host FC port to online state + * @fc_regs: Top of MMIO region defined for specified port. + * + * The provided MMIO region must be mapped prior to call. Online state means + * that the FC link layer has synced, completed the handshaking process, and + * is ready for login to start. + */ +static void set_port_online(u64 *fc_regs) +{ + u64 cmdcfg; + + cmdcfg = readq_be(&fc_regs[FC_MTIP_CMDCONFIG / 8]); + cmdcfg &= (~FC_MTIP_CMDCONFIG_OFFLINE); /* clear OFF_LINE */ + cmdcfg |= (FC_MTIP_CMDCONFIG_ONLINE); /* set ON_LINE */ + writeq_be(cmdcfg, &fc_regs[FC_MTIP_CMDCONFIG / 8]); +} + +/** + * set_port_offline() - transitions the specified host FC port to offline state + * @fc_regs: Top of MMIO region defined for specified port. + * + * The provided MMIO region must be mapped prior to call. + */ +static void set_port_offline(u64 *fc_regs) +{ + u64 cmdcfg; + + cmdcfg = readq_be(&fc_regs[FC_MTIP_CMDCONFIG / 8]); + cmdcfg &= (~FC_MTIP_CMDCONFIG_ONLINE); /* clear ON_LINE */ + cmdcfg |= (FC_MTIP_CMDCONFIG_OFFLINE); /* set OFF_LINE */ + writeq_be(cmdcfg, &fc_regs[FC_MTIP_CMDCONFIG / 8]); +} + +/** + * wait_port_online() - waits for the specified host FC port come online + * @fc_regs: Top of MMIO region defined for specified port. + * @delay_us: Number of microseconds to delay between reading port status. + * @nretry: Number of cycles to retry reading port status. + * + * The provided MMIO region must be mapped prior to call. This will timeout + * when the cable is not plugged in. + * + * Return: + * TRUE (1) when the specified port is online + * FALSE (0) when the specified port fails to come online after timeout + * -EINVAL when @delay_us is less than 1000 + */ +static int wait_port_online(u64 *fc_regs, u32 delay_us, u32 nretry) +{ + u64 status; + + if (delay_us < 1000) { + pr_err("%s: invalid delay specified %d\n", __func__, delay_us); + return -EINVAL; + } + + do { + msleep(delay_us / 1000); + status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); + } while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_ONLINE && + nretry--); + + return ((status & FC_MTIP_STATUS_MASK) == FC_MTIP_STATUS_ONLINE); +} + +/** + * wait_port_offline() - waits for the specified host FC port go offline + * @fc_regs: Top of MMIO region defined for specified port. + * @delay_us: Number of microseconds to delay between reading port status. + * @nretry: Number of cycles to retry reading port status. + * + * The provided MMIO region must be mapped prior to call. + * + * Return: + * TRUE (1) when the specified port is offline + * FALSE (0) when the specified port fails to go offline after timeout + * -EINVAL when @delay_us is less than 1000 + */ +static int wait_port_offline(u64 *fc_regs, u32 delay_us, u32 nretry) +{ + u64 status; + + if (delay_us < 1000) { + pr_err("%s: invalid delay specified %d\n", __func__, delay_us); + return -EINVAL; + } + + do { + msleep(delay_us / 1000); + status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); + } while ((status & FC_MTIP_STATUS_MASK) != FC_MTIP_STATUS_OFFLINE && + nretry--); + + return ((status & FC_MTIP_STATUS_MASK) == FC_MTIP_STATUS_OFFLINE); +} + +/** + * afu_set_wwpn() - configures the WWPN for the specified host FC port + * @afu: AFU associated with the host that owns the specified FC port. + * @port: Port number being configured. + * @fc_regs: Top of MMIO region defined for specified port. + * @wwpn: The world-wide-port-number previously discovered for port. + * + * The provided MMIO region must be mapped prior to call. As part of the + * sequence to configure the WWPN, the port is toggled offline and then back + * online. This toggling action can cause this routine to delay up to a few + * seconds. When configured to use the internal LUN feature of the AFU, a + * failure to come online is overridden. + * + * Return: + * 0 when the WWPN is successfully written and the port comes back online + * -1 when the port fails to go offline or come back up online + */ +static int afu_set_wwpn(struct afu *afu, int port, u64 *fc_regs, u64 wwpn) +{ + int ret = 0; + + set_port_offline(fc_regs); + + if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, + FC_PORT_STATUS_RETRY_CNT)) { + pr_debug("%s: wait on port %d to go offline timed out\n", + __func__, port); + ret = -1; /* but continue on to leave the port back online */ + } + + if (ret == 0) + writeq_be(wwpn, &fc_regs[FC_PNAME / 8]); + + set_port_online(fc_regs); + + if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, + FC_PORT_STATUS_RETRY_CNT)) { + pr_debug("%s: wait on port %d to go online timed out\n", + __func__, port); + ret = -1; + + /* + * Override for internal lun!!! + */ + if (afu->internal_lun) { + pr_debug("%s: Overriding port %d online timeout!!!\n", + __func__, port); + ret = 0; + } + } + + pr_debug("%s: returning rc=%d\n", __func__, ret); + + return ret; +} + +/** + * afu_link_reset() - resets the specified host FC port + * @afu: AFU associated with the host that owns the specified FC port. + * @port: Port number being configured. + * @fc_regs: Top of MMIO region defined for specified port. + * + * The provided MMIO region must be mapped prior to call. The sequence to + * reset the port involves toggling it offline and then back online. This + * action can cause this routine to delay up to a few seconds. An effort + * is made to maintain link with the device by switching to host to use + * the alternate port exclusively while the reset takes place. + * failure to come online is overridden. + */ +static void afu_link_reset(struct afu *afu, int port, u64 *fc_regs) +{ + u64 port_sel; + + /* first switch the AFU to the other links, if any */ + port_sel = readq_be(&afu->afu_map->global.regs.afu_port_sel); + port_sel &= ~(1 << port); + writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel); + cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC); + + set_port_offline(fc_regs); + if (!wait_port_offline(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, + FC_PORT_STATUS_RETRY_CNT)) + pr_err("%s: wait on port %d to go offline timed out\n", + __func__, port); + + set_port_online(fc_regs); + if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, + FC_PORT_STATUS_RETRY_CNT)) + pr_err("%s: wait on port %d to go online timed out\n", + __func__, port); + + /* switch back to include this port */ + port_sel |= (1 << port); + writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel); + cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC); + + pr_debug("%s: returning port_sel=%lld\n", __func__, port_sel); +} + +/* + * Asynchronous interrupt information table + */ +static const struct asyc_intr_info ainfo[] = { + {SISL_ASTATUS_FC0_OTHER, "other error", 0, CLR_FC_ERROR | LINK_RESET}, + {SISL_ASTATUS_FC0_LOGO, "target initiated LOGO", 0, 0}, + {SISL_ASTATUS_FC0_CRC_T, "CRC threshold exceeded", 0, LINK_RESET}, + {SISL_ASTATUS_FC0_LOGI_R, "login timed out, retrying", 0, 0}, + {SISL_ASTATUS_FC0_LOGI_F, "login failed", 0, CLR_FC_ERROR}, + {SISL_ASTATUS_FC0_LOGI_S, "login succeeded", 0, 0}, + {SISL_ASTATUS_FC0_LINK_DN, "link down", 0, 0}, + {SISL_ASTATUS_FC0_LINK_UP, "link up", 0, 0}, + {SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET}, + {SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0}, + {SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET}, + {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, 0}, + {SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR}, + {SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, 0}, + {SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0}, + {SISL_ASTATUS_FC1_LINK_UP, "link up", 1, 0}, + {0x0, "", 0, 0} /* terminator */ +}; + +/** + * find_ainfo() - locates and returns asynchronous interrupt information + * @status: Status code set by AFU on error. + * + * Return: The located information or NULL when the status code is invalid. + */ +static const struct asyc_intr_info *find_ainfo(u64 status) +{ + const struct asyc_intr_info *info; + + for (info = &ainfo[0]; info->status; info++) + if (info->status == status) + return info; + + return NULL; +} + +/** + * afu_err_intr_init() - clears and initializes the AFU for error interrupts + * @afu: AFU associated with the host. + */ +static void afu_err_intr_init(struct afu *afu) +{ + int i; + u64 reg; + + /* global async interrupts: AFU clears afu_ctrl on context exit + * if async interrupts were sent to that context. This prevents + * the AFU form sending further async interrupts when + * there is + * nobody to receive them. + */ + + /* mask all */ + writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_mask); + /* set LISN# to send and point to master context */ + reg = ((u64) (((afu->ctx_hndl << 8) | SISL_MSI_ASYNC_ERROR)) << 40); + + if (afu->internal_lun) + reg |= 1; /* Bit 63 indicates local lun */ + writeq_be(reg, &afu->afu_map->global.regs.afu_ctrl); + /* clear all */ + writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_clear); + /* unmask bits that are of interest */ + /* note: afu can send an interrupt after this step */ + writeq_be(SISL_ASTATUS_MASK, &afu->afu_map->global.regs.aintr_mask); + /* clear again in case a bit came on after previous clear but before */ + /* unmask */ + writeq_be(-1ULL, &afu->afu_map->global.regs.aintr_clear); + + /* Clear/Set internal lun bits */ + reg = readq_be(&afu->afu_map->global.fc_regs[0][FC_CONFIG2 / 8]); + reg &= SISL_FC_INTERNAL_MASK; + if (afu->internal_lun) + reg |= ((u64)(afu->internal_lun - 1) << SISL_FC_INTERNAL_SHIFT); + writeq_be(reg, &afu->afu_map->global.fc_regs[0][FC_CONFIG2 / 8]); + + /* now clear FC errors */ + for (i = 0; i < NUM_FC_PORTS; i++) { + writeq_be(0xFFFFFFFFU, + &afu->afu_map->global.fc_regs[i][FC_ERROR / 8]); + writeq_be(0, &afu->afu_map->global.fc_regs[i][FC_ERRCAP / 8]); + } + + /* sync interrupts for master's IOARRIN write */ + /* note that unlike asyncs, there can be no pending sync interrupts */ + /* at this time (this is a fresh context and master has not written */ + /* IOARRIN yet), so there is nothing to clear. */ + + /* set LISN#, it is always sent to the context that wrote IOARRIN */ + writeq_be(SISL_MSI_SYNC_ERROR, &afu->host_map->ctx_ctrl); + writeq_be(SISL_ISTATUS_MASK, &afu->host_map->intr_mask); +} + +/** + * cxlflash_sync_err_irq() - interrupt handler for synchronous errors + * @irq: Interrupt number. + * @data: Private data provided at interrupt registration, the AFU. + * + * Return: Always return IRQ_HANDLED. + */ +static irqreturn_t cxlflash_sync_err_irq(int irq, void *data) +{ + struct afu *afu = (struct afu *)data; + u64 reg; + u64 reg_unmasked; + + reg = readq_be(&afu->host_map->intr_status); + reg_unmasked = (reg & SISL_ISTATUS_UNMASK); + + if (reg_unmasked == 0UL) { + pr_err("%s: %llX: spurious interrupt, intr_status %016llX\n", + __func__, (u64)afu, reg); + goto cxlflash_sync_err_irq_exit; + } + + pr_err("%s: %llX: unexpected interrupt, intr_status %016llX\n", + __func__, (u64)afu, reg); + + writeq_be(reg_unmasked, &afu->host_map->intr_clear); + +cxlflash_sync_err_irq_exit: + pr_debug("%s: returning rc=%d\n", __func__, IRQ_HANDLED); + return IRQ_HANDLED; +} + +/** + * cxlflash_rrq_irq() - interrupt handler for read-response queue (normal path) + * @irq: Interrupt number. + * @data: Private data provided at interrupt registration, the AFU. + * + * Return: Always return IRQ_HANDLED. + */ +static irqreturn_t cxlflash_rrq_irq(int irq, void *data) +{ + struct afu *afu = (struct afu *)data; + struct afu_cmd *cmd; + bool toggle = afu->toggle; + u64 entry, + *hrrq_start = afu->hrrq_start, + *hrrq_end = afu->hrrq_end, + *hrrq_curr = afu->hrrq_curr; + + /* Process however many RRQ entries that are ready */ + while (true) { + entry = *hrrq_curr; + + if ((entry & SISL_RESP_HANDLE_T_BIT) != toggle) + break; + + cmd = (struct afu_cmd *)(entry & ~SISL_RESP_HANDLE_T_BIT); + cmd_complete(cmd); + + /* Advance to next entry or wrap and flip the toggle bit */ + if (hrrq_curr < hrrq_end) + hrrq_curr++; + else { + hrrq_curr = hrrq_start; + toggle ^= SISL_RESP_HANDLE_T_BIT; + } + } + + afu->hrrq_curr = hrrq_curr; + afu->toggle = toggle; + + return IRQ_HANDLED; +} + +/** + * cxlflash_async_err_irq() - interrupt handler for asynchronous errors + * @irq: Interrupt number. + * @data: Private data provided at interrupt registration, the AFU. + * + * Return: Always return IRQ_HANDLED. + */ +static irqreturn_t cxlflash_async_err_irq(int irq, void *data) +{ + struct afu *afu = (struct afu *)data; + struct cxlflash_cfg *cfg; + u64 reg_unmasked; + const struct asyc_intr_info *info; + struct sisl_global_map *global = &afu->afu_map->global; + u64 reg; + u8 port; + int i; + + cfg = afu->parent; + + reg = readq_be(&global->regs.aintr_status); + reg_unmasked = (reg & SISL_ASTATUS_UNMASK); + + if (reg_unmasked == 0) { + pr_err("%s: spurious interrupt, aintr_status 0x%016llX\n", + __func__, reg); + goto out; + } + + /* it is OK to clear AFU status before FC_ERROR */ + writeq_be(reg_unmasked, &global->regs.aintr_clear); + + /* check each bit that is on */ + for (i = 0; reg_unmasked; i++, reg_unmasked = (reg_unmasked >> 1)) { + info = find_ainfo(1ULL << i); + if ((reg_unmasked & 0x1) || !info) + continue; + + port = info->port; + + pr_err("%s: FC Port %d -> %s, fc_status 0x%08llX\n", + __func__, port, info->desc, + readq_be(&global->fc_regs[port][FC_STATUS / 8])); + + /* + * do link reset first, some OTHER errors will set FC_ERROR + * again if cleared before or w/o a reset + */ + if (info->action & LINK_RESET) { + pr_err("%s: FC Port %d: resetting link\n", + __func__, port); + cfg->lr_state = LINK_RESET_REQUIRED; + cfg->lr_port = port; + schedule_work(&cfg->work_q); + } + + if (info->action & CLR_FC_ERROR) { + reg = readq_be(&global->fc_regs[port][FC_ERROR / 8]); + + /* + * since all errors are unmasked, FC_ERROR and FC_ERRCAP + * should be the same and tracing one is sufficient. + */ + + pr_err("%s: fc %d: clearing fc_error 0x%08llX\n", + __func__, port, reg); + + writeq_be(reg, &global->fc_regs[port][FC_ERROR / 8]); + writeq_be(0, &global->fc_regs[port][FC_ERRCAP / 8]); + } + } + +out: + pr_debug("%s: returning rc=%d, afu=%p\n", __func__, IRQ_HANDLED, afu); + return IRQ_HANDLED; +} + +/** + * start_context() - starts the master context + * @cxlflash: Internal structure associated with the host. + * + * Return: A success or failure value from CXL services. + */ +static int start_context(struct cxlflash_cfg *cfg) +{ + int rc = 0; + + rc = cxl_start_context(cfg->mcctx, + cfg->afu->work.work_element_descriptor, + NULL); + + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * read_vpd() - obtains the WWPNs from VPD + * @cxlflash: Internal structure associated with the host. + * @wwpn: Array of size NUM_FC_PORTS to pass back WWPNs + * + * Return: + * 0 on success + * -ENODEV when VPD or WWPN keywords not found + */ +static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) +{ + struct pci_dev *dev = cfg->parent_dev; + int rc = 0; + int ro_start, ro_size, i, j, k; + ssize_t vpd_size; + char vpd_data[CXLFLASH_VPD_LEN]; + char tmp_buf[WWPN_BUF_LEN] = { 0 }; + char *wwpn_vpd_tags[NUM_FC_PORTS] = { "V5", "V6" }; + + /* Get the VPD data from the device */ + vpd_size = pci_read_vpd(dev, 0, sizeof(vpd_data), vpd_data); + if (unlikely(vpd_size <= 0)) { + pr_err("%s: Unable to read VPD (size = %ld)\n", + __func__, vpd_size); + rc = -ENODEV; + goto out; + } + + /* Get the read only section offset */ + ro_start = pci_vpd_find_tag(vpd_data, 0, vpd_size, + PCI_VPD_LRDT_RO_DATA); + if (unlikely(ro_start < 0)) { + pr_err("%s: VPD Read-only data not found\n", __func__); + rc = -ENODEV; + goto out; + } + + /* Get the read only section size, cap when extends beyond read VPD */ + ro_size = pci_vpd_lrdt_size(&vpd_data[ro_start]); + j = ro_size; + i = ro_start + PCI_VPD_LRDT_TAG_SIZE; + if (unlikely((i + j) > vpd_size)) { + pr_debug("%s: Might need to read more VPD (%d > %ld)\n", + __func__, (i + j), vpd_size); + ro_size = vpd_size - i; + } + + /* + * Find the offset of the WWPN tag within the read only + * VPD data and validate the found field (partials are + * no good to us). Convert the ASCII data to an integer + * value. Note that we must copy to a temporary buffer + * because the conversion service requires that the ASCII + * string be terminated. + */ + for (k = 0; k < NUM_FC_PORTS; k++) { + j = ro_size; + i = ro_start + PCI_VPD_LRDT_TAG_SIZE; + + i = pci_vpd_find_info_keyword(vpd_data, i, j, wwpn_vpd_tags[k]); + if (unlikely(i < 0)) { + pr_err("%s: Port %d WWPN not found in VPD\n", + __func__, k); + rc = -ENODEV; + goto out; + } + + j = pci_vpd_info_field_size(&vpd_data[i]); + i += PCI_VPD_INFO_FLD_HDR_SIZE; + if (unlikely((i + j > vpd_size) || (j != WWPN_LEN))) { + pr_err("%s: Port %d WWPN incomplete or VPD corrupt\n", + __func__, k); + rc = -ENODEV; + goto out; + } + + memcpy(tmp_buf, &vpd_data[i], WWPN_LEN); + rc = kstrtoul(tmp_buf, WWPN_LEN, (ulong *)&wwpn[k]); + if (unlikely(rc)) { + pr_err("%s: Fail to convert port %d WWPN to integer\n", + __func__, k); + rc = -ENODEV; + goto out; + } + } + +out: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_context_reset() - timeout handler for AFU commands + * @cmd: AFU command that timed out. + * + * Sends a reset to the AFU. + */ +void cxlflash_context_reset(struct afu_cmd *cmd) +{ + int nretry = 0; + u64 rrin = 0x1; + u64 room = 0; + struct afu *afu = cmd->parent; + ulong lock_flags; + + pr_debug("%s: cmd=%p\n", __func__, cmd); + + spin_lock_irqsave(&cmd->slock, lock_flags); + + /* Already completed? */ + if (cmd->sa.host_use_b[0] & B_DONE) { + spin_unlock_irqrestore(&cmd->slock, lock_flags); + return; + } + + cmd->sa.host_use_b[0] |= (B_DONE | B_ERROR | B_TIMEOUT); + spin_unlock_irqrestore(&cmd->slock, lock_flags); + + /* + * We really want to send this reset at all costs, so spread + * out wait time on successive retries for available room. + */ + do { + room = readq_be(&afu->host_map->cmd_room); + atomic64_set(&afu->room, room); + if (room) + goto write_rrin; + udelay(nretry); + } while (nretry++ < MC_ROOM_RETRY_CNT); + + pr_err("%s: no cmd_room to send reset\n", __func__); + return; + +write_rrin: + nretry = 0; + writeq_be(rrin, &afu->host_map->ioarrin); + do { + rrin = readq_be(&afu->host_map->ioarrin); + if (rrin != 0x1) + break; + /* Double delay each time */ + udelay(2 ^ nretry); + } while (nretry++ < MC_ROOM_RETRY_CNT); +} + +/** + * init_pcr() - initialize the provisioning and control registers + * @cxlflash: Internal structure associated with the host. + * + * Also sets up fast access to the mapped registers and initializes AFU + * command fields that never change. + */ +void init_pcr(struct cxlflash_cfg *cfg) +{ + struct afu *afu = cfg->afu; + struct sisl_ctrl_map *ctrl_map; + int i; + + for (i = 0; i < MAX_CONTEXT; i++) { + ctrl_map = &afu->afu_map->ctrls[i].ctrl; + /* disrupt any clients that could be running */ + /* e. g. clients that survived a master restart */ + writeq_be(0, &ctrl_map->rht_start); + writeq_be(0, &ctrl_map->rht_cnt_id); + writeq_be(0, &ctrl_map->ctx_cap); + } + + /* copy frequently used fields into afu */ + afu->ctx_hndl = (u16) cxl_process_element(cfg->mcctx); + /* ctx_hndl is 16 bits in CAIA */ + afu->host_map = &afu->afu_map->hosts[afu->ctx_hndl].host; + afu->ctrl_map = &afu->afu_map->ctrls[afu->ctx_hndl].ctrl; + + /* Program the Endian Control for the master context */ + writeq_be(SISL_ENDIAN_CTRL, &afu->host_map->endian_ctrl); + + /* initialize cmd fields that never change */ + for (i = 0; i < CXLFLASH_NUM_CMDS; i++) { + afu->cmd[i].rcb.ctx_id = afu->ctx_hndl; + afu->cmd[i].rcb.msi = SISL_MSI_RRQ_UPDATED; + afu->cmd[i].rcb.rrq = 0x0; + } +} + +/** + * init_global() - initialize AFU global registers + * @cxlflash: Internal structure associated with the host. + */ +int init_global(struct cxlflash_cfg *cfg) +{ + struct afu *afu = cfg->afu; + u64 wwpn[NUM_FC_PORTS]; /* wwpn of AFU ports */ + int i = 0, num_ports = 0; + int rc = 0; + u64 reg; + + rc = read_vpd(cfg, &wwpn[0]); + if (rc) { + pr_err("%s: could not read vpd rc=%d\n", __func__, rc); + goto out; + } + + pr_debug("%s: wwpn0=0x%llX wwpn1=0x%llX\n", __func__, wwpn[0], wwpn[1]); + + /* set up RRQ in AFU for master issued cmds */ + writeq_be((u64) afu->hrrq_start, &afu->host_map->rrq_start); + writeq_be((u64) afu->hrrq_end, &afu->host_map->rrq_end); + + /* AFU configuration */ + reg = readq_be(&afu->afu_map->global.regs.afu_config); + reg |= SISL_AFUCONF_AR_ALL|SISL_AFUCONF_ENDIAN; + /* enable all auto retry options and control endianness */ + /* leave others at default: */ + /* CTX_CAP write protected, mbox_r does not clear on read and */ + /* checker on if dual afu */ + writeq_be(reg, &afu->afu_map->global.regs.afu_config); + + /* global port select: select either port */ + if (afu->internal_lun) { + /* only use port 0 */ + writeq_be(PORT0, &afu->afu_map->global.regs.afu_port_sel); + num_ports = NUM_FC_PORTS - 1; + } else { + writeq_be(BOTH_PORTS, &afu->afu_map->global.regs.afu_port_sel); + num_ports = NUM_FC_PORTS; + } + + for (i = 0; i < num_ports; i++) { + /* unmask all errors (but they are still masked at AFU) */ + writeq_be(0, &afu->afu_map->global.fc_regs[i][FC_ERRMSK / 8]); + /* clear CRC error cnt & set a threshold */ + (void)readq_be(&afu->afu_map->global. + fc_regs[i][FC_CNT_CRCERR / 8]); + writeq_be(MC_CRC_THRESH, &afu->afu_map->global.fc_regs[i] + [FC_CRC_THRESH / 8]); + + /* set WWPNs. If already programmed, wwpn[i] is 0 */ + if (wwpn[i] != 0 && + afu_set_wwpn(afu, i, + &afu->afu_map->global.fc_regs[i][0], + wwpn[i])) { + pr_err("%s: failed to set WWPN on port %d\n", + __func__, i); + rc = -EIO; + goto out; + } + /* Programming WWPN back to back causes additional + * offline/online transitions and a PLOGI + */ + msleep(100); + + } + + /* set up master's own CTX_CAP to allow real mode, host translation */ + /* tbls, afu cmds and read/write GSCSI cmds. */ + /* First, unlock ctx_cap write by reading mbox */ + (void)readq_be(&afu->ctrl_map->mbox_r); /* unlock ctx_cap */ + writeq_be((SISL_CTX_CAP_REAL_MODE | SISL_CTX_CAP_HOST_XLATE | + SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD | + SISL_CTX_CAP_AFU_CMD | SISL_CTX_CAP_GSCSI_CMD), + &afu->ctrl_map->ctx_cap); + /* init heartbeat */ + afu->hb = readq_be(&afu->afu_map->global.regs.afu_hb); + +out: + return rc; +} + +/** + * start_afu() - initializes and starts the AFU + * @cxlflash: Internal structure associated with the host. + */ +static int start_afu(struct cxlflash_cfg *cfg) +{ + struct afu *afu = cfg->afu; + struct afu_cmd *cmd; + + int i = 0; + int rc = 0; + + for (i = 0; i < CXLFLASH_NUM_CMDS; i++) { + cmd = &afu->cmd[i]; + + init_completion(&cmd->cevent); + spin_lock_init(&cmd->slock); + cmd->parent = afu; + } + + init_pcr(cfg); + + /* initialize RRQ pointers */ + afu->hrrq_start = &afu->rrq_entry[0]; + afu->hrrq_end = &afu->rrq_entry[NUM_RRQ_ENTRY - 1]; + afu->hrrq_curr = afu->hrrq_start; + afu->toggle = 1; + + rc = init_global(cfg); + + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * init_mc() - create and register as the master context + * @cxlflash: Internal structure associated with the host. + * + * Return: + * 0 on success + * -ENOMEM when unable to obtain a context from CXL services + * A failure value from CXL services. + */ +static int init_mc(struct cxlflash_cfg *cfg) +{ + struct cxl_context *ctx; + struct device *dev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + int rc = 0; + enum undo_level level; + + ctx = cxl_get_context(cfg->dev); + if (unlikely(!ctx)) + return -ENOMEM; + cfg->mcctx = ctx; + + /* Set it up as a master with the CXL */ + cxl_set_master(ctx); + + /* During initialization reset the AFU to start from a clean slate */ + rc = cxl_afu_reset(cfg->mcctx); + if (unlikely(rc)) { + dev_err(dev, "%s: initial AFU reset failed rc=%d\n", + __func__, rc); + level = RELEASE_CONTEXT; + goto out; + } + + rc = cxl_allocate_afu_irqs(ctx, 3); + if (unlikely(rc)) { + dev_err(dev, "%s: call to allocate_afu_irqs failed rc=%d!\n", + __func__, rc); + level = RELEASE_CONTEXT; + goto out; + } + + rc = cxl_map_afu_irq(ctx, 1, cxlflash_sync_err_irq, afu, + "SISL_MSI_SYNC_ERROR"); + if (unlikely(rc <= 0)) { + dev_err(dev, "%s: IRQ 1 (SISL_MSI_SYNC_ERROR) map failed!\n", + __func__); + level = FREE_IRQ; + goto out; + } + + rc = cxl_map_afu_irq(ctx, 2, cxlflash_rrq_irq, afu, + "SISL_MSI_RRQ_UPDATED"); + if (unlikely(rc <= 0)) { + dev_err(dev, "%s: IRQ 2 (SISL_MSI_RRQ_UPDATED) map failed!\n", + __func__); + level = UNMAP_ONE; + goto out; + } + + rc = cxl_map_afu_irq(ctx, 3, cxlflash_async_err_irq, afu, + "SISL_MSI_ASYNC_ERROR"); + if (unlikely(rc <= 0)) { + dev_err(dev, "%s: IRQ 3 (SISL_MSI_ASYNC_ERROR) map failed!\n", + __func__); + level = UNMAP_TWO; + goto out; + } + + rc = 0; + + /* This performs the equivalent of the CXL_IOCTL_START_WORK. + * The CXL_IOCTL_GET_PROCESS_ELEMENT is implicit in the process + * element (pe) that is embedded in the context (ctx) + */ + rc = start_context(cfg); + if (unlikely(rc)) { + dev_err(dev, "%s: start context failed rc=%d\n", __func__, rc); + level = UNMAP_THREE; + goto out; + } +ret: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +out: + term_mc(cfg, level); + goto ret; +} + +/** + * init_afu() - setup as master context and start AFU + * @cxlflash: Internal structure associated with the host. + * + * This routine is a higher level of control for configuring the + * AFU on probe and reset paths. + * + * Return: + * 0 on success + * -ENOMEM when unable to map the AFU MMIO space + * A failure value from internal services. + */ +static int init_afu(struct cxlflash_cfg *cfg) +{ + u64 reg; + int rc = 0; + struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; + + rc = init_mc(cfg); + if (rc) { + dev_err(dev, "%s: call to init_mc failed, rc=%d!\n", + __func__, rc); + goto err1; + } + + /* Map the entire MMIO space of the AFU. + */ + afu->afu_map = cxl_psa_map(cfg->mcctx); + if (!afu->afu_map) { + rc = -ENOMEM; + term_mc(cfg, UNDO_START); + dev_err(dev, "%s: call to cxl_psa_map failed!\n", __func__); + goto err1; + } + + /* don't byte reverse on reading afu_version, else the string form */ + /* will be backwards */ + reg = afu->afu_map->global.regs.afu_version; + memcpy(afu->version, ®, 8); + afu->interface_version = + readq_be(&afu->afu_map->global.regs.interface_version); + pr_debug("%s: afu version %s, interface version 0x%llX\n", + __func__, afu->version, afu->interface_version); + + rc = start_afu(cfg); + if (rc) { + dev_err(dev, "%s: call to start_afu failed, rc=%d!\n", + __func__, rc); + term_mc(cfg, UNDO_START); + cxl_psa_unmap((void *)afu->afu_map); + afu->afu_map = NULL; + goto err1; + } + + afu_err_intr_init(cfg->afu); + atomic64_set(&afu->room, readq_be(&afu->host_map->cmd_room)); + +err1: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_send_cmd() - sends an AFU command + * @afu: AFU associated with the host. + * @cmd: AFU command to send. + * + * Return: + * 0 on success + * -1 on failure + */ +int cxlflash_send_cmd(struct afu *afu, struct afu_cmd *cmd) +{ + struct cxlflash_cfg *cfg = afu->parent; + int nretry = 0; + int rc = 0; + u64 room; + long newval; + + /* + * This routine is used by critical users such an AFU sync and to + * send a task management function (TMF). Thus we want to retry a + * bit before returning an error. To avoid the performance penalty + * of MMIO, we spread the update of 'room' over multiple commands. + */ +retry: + newval = atomic64_dec_if_positive(&afu->room); + if (!newval) { + do { + room = readq_be(&afu->host_map->cmd_room); + atomic64_set(&afu->room, room); + if (room) + goto write_ioarrin; + udelay(nretry); + } while (nretry++ < MC_ROOM_RETRY_CNT); + + pr_err("%s: no cmd_room to send 0x%X\n", + __func__, cmd->rcb.cdb[0]); + + goto no_room; + } else if (unlikely(newval < 0)) { + /* This should be rare. i.e. Only if two threads race and + * decrement before the MMIO read is done. In this case + * just benefit from the other thread having updated + * afu->room. + */ + if (nretry++ < MC_ROOM_RETRY_CNT) { + udelay(nretry); + goto retry; + } + + goto no_room; + } + +write_ioarrin: + writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin); +out: + pr_debug("%s: cmd=%p len=%d ea=%p rc=%d\n", __func__, cmd, + cmd->rcb.data_len, (void *)cmd->rcb.data_ea, rc); + return rc; + +no_room: + afu->read_room = true; + schedule_work(&cfg->work_q); + rc = SCSI_MLQUEUE_HOST_BUSY; + goto out; +} + +/** + * cxlflash_wait_resp() - polls for a response or timeout to a sent AFU command + * @afu: AFU associated with the host. + * @cmd: AFU command that was sent. + */ +void cxlflash_wait_resp(struct afu *afu, struct afu_cmd *cmd) +{ + ulong timeout = jiffies + (cmd->rcb.timeout * 2 * HZ); + + timeout = wait_for_completion_timeout(&cmd->cevent, timeout); + if (!timeout) + cxlflash_context_reset(cmd); + + if (unlikely(cmd->sa.ioasc != 0)) + pr_err("%s: CMD 0x%X failed, IOASC: flags 0x%X, afu_rc 0x%X, " + "scsi_rc 0x%X, fc_rc 0x%X\n", __func__, cmd->rcb.cdb[0], + cmd->sa.rc.flags, cmd->sa.rc.afu_rc, cmd->sa.rc.scsi_rc, + cmd->sa.rc.fc_rc); +} + +/** + * cxlflash_afu_sync() - builds and sends an AFU sync command + * @afu: AFU associated with the host. + * @ctx_hndl_u: Identifies context requesting sync. + * @res_hndl_u: Identifies resource requesting sync. + * @mode: Type of sync to issue (lightweight, heavyweight, global). + * + * The AFU can only take 1 sync command at a time. This routine enforces this + * limitation by using a mutex to provide exlusive access to the AFU during + * the sync. This design point requires calling threads to not be on interrupt + * context due to the possibility of sleeping during concurrent sync operations. + * + * Return: + * 0 on success + * -1 on failure + */ +int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, + res_hndl_t res_hndl_u, u8 mode) +{ + struct afu_cmd *cmd = NULL; + int rc = 0; + int retry_cnt = 0; + static DEFINE_MUTEX(sync_active); + + mutex_lock(&sync_active); +retry: + cmd = cxlflash_cmd_checkout(afu); + if (unlikely(!cmd)) { + retry_cnt++; + udelay(1000 * retry_cnt); + if (retry_cnt < MC_RETRY_CNT) + goto retry; + pr_err("%s: could not get a free command\n", __func__); + rc = -1; + goto out; + } + + pr_debug("%s: afu=%p cmd=%p %d\n", __func__, afu, cmd, ctx_hndl_u); + + memset(cmd->rcb.cdb, 0, sizeof(cmd->rcb.cdb)); + + cmd->rcb.req_flags = SISL_REQ_FLAGS_AFU_CMD; + cmd->rcb.port_sel = 0x0; /* NA */ + cmd->rcb.lun_id = 0x0; /* NA */ + cmd->rcb.data_len = 0x0; + cmd->rcb.data_ea = 0x0; + cmd->rcb.timeout = MC_AFU_SYNC_TIMEOUT; + + cmd->rcb.cdb[0] = 0xC0; /* AFU Sync */ + cmd->rcb.cdb[1] = mode; + + /* The cdb is aligned, no unaligned accessors required */ + *((u16 *)&cmd->rcb.cdb[2]) = swab16(ctx_hndl_u); + *((u32 *)&cmd->rcb.cdb[4]) = swab32(res_hndl_u); + + rc = cxlflash_send_cmd(afu, cmd); + if (unlikely(rc)) + goto out; + + cxlflash_wait_resp(afu, cmd); + + /* set on timeout */ + if (unlikely((cmd->sa.ioasc != 0) || + (cmd->sa.host_use_b[0] & B_ERROR))) + rc = -1; +out: + mutex_unlock(&sync_active); + if (cmd) + cxlflash_cmd_checkin(cmd); + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_afu_reset() - resets the AFU + * @cxlflash: Internal structure associated with the host. + * + * Return: + * 0 on success + * A failure value from internal services. + */ +int cxlflash_afu_reset(struct cxlflash_cfg *cfg) +{ + int rc = 0; + /* Stop the context before the reset. Since the context is + * no longer available restart it after the reset is complete + */ + + term_afu(cfg); + + rc = init_afu(cfg); + + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_worker_thread() - work thread handler for the AFU + * @work: Work structure contained within cxlflash associated with host. + * + * Handles the following events: + * - Link reset which cannot be performed on interrupt context due to + * blocking up to a few seconds + * - Read AFU command room + */ +static void cxlflash_worker_thread(struct work_struct *work) +{ + struct cxlflash_cfg *cfg = + container_of(work, struct cxlflash_cfg, work_q); + struct afu *afu = cfg->afu; + int port; + ulong lock_flags; + + spin_lock_irqsave(cfg->host->host_lock, lock_flags); + + if (cfg->lr_state == LINK_RESET_REQUIRED) { + port = cfg->lr_port; + if (port < 0) + pr_err("%s: invalid port index %d\n", __func__, port); + else { + spin_unlock_irqrestore(cfg->host->host_lock, + lock_flags); + + /* The reset can block... */ + afu_link_reset(afu, port, + &afu->afu_map-> + global.fc_regs[port][0]); + spin_lock_irqsave(cfg->host->host_lock, lock_flags); + } + + cfg->lr_state = LINK_RESET_COMPLETE; + } + + if (afu->read_room) { + atomic64_set(&afu->room, readq_be(&afu->host_map->cmd_room)); + afu->read_room = false; + } + + spin_unlock_irqrestore(cfg->host->host_lock, lock_flags); +} + +/** + * cxlflash_probe() - PCI entry point to add host + * @pdev: PCI device associated with the host. + * @dev_id: PCI device id associated with device. + * + * Return: 0 on success / non-zero on failure + */ +static int cxlflash_probe(struct pci_dev *pdev, + const struct pci_device_id *dev_id) +{ + struct Scsi_Host *host; + struct cxlflash_cfg *cfg = NULL; + struct device *phys_dev; + struct dev_dependent_vals *ddv; + int rc = 0; + + dev_dbg(&pdev->dev, "%s: Found CXLFLASH with IRQ: %d\n", + __func__, pdev->irq); + + ddv = (struct dev_dependent_vals *)dev_id->driver_data; + driver_template.max_sectors = ddv->max_sectors; + + host = scsi_host_alloc(&driver_template, sizeof(struct cxlflash_cfg)); + if (!host) { + dev_err(&pdev->dev, "%s: call to scsi_host_alloc failed!\n", + __func__); + rc = -ENOMEM; + goto out; + } + + host->max_id = CXLFLASH_MAX_NUM_TARGETS_PER_BUS; + host->max_lun = CXLFLASH_MAX_NUM_LUNS_PER_TARGET; + host->max_channel = NUM_FC_PORTS - 1; + host->unique_id = host->host_no; + host->max_cmd_len = CXLFLASH_MAX_CDB_LEN; + + cfg = (struct cxlflash_cfg *)host->hostdata; + cfg->host = host; + rc = alloc_mem(cfg); + if (rc) { + dev_err(&pdev->dev, "%s: call to scsi_host_alloc failed!\n", + __func__); + rc = -ENOMEM; + goto out; + } + + cfg->init_state = INIT_STATE_NONE; + cfg->dev = pdev; + cfg->dev_id = (struct pci_device_id *)dev_id; + cfg->mcctx = NULL; + cfg->err_recovery_active = 0; + + init_waitqueue_head(&cfg->tmf_waitq); + init_waitqueue_head(&cfg->eeh_waitq); + + INIT_WORK(&cfg->work_q, cxlflash_worker_thread); + cfg->lr_state = LINK_RESET_INVALID; + cfg->lr_port = -1; + + pci_set_drvdata(pdev, cfg); + + /* Use the special service provided to look up the physical + * PCI device, since we are called on the probe of the virtual + * PCI host bus (vphb) + */ + phys_dev = cxl_get_phys_dev(pdev); + if (!dev_is_pci(phys_dev)) { + pr_err("%s: not a pci dev\n", __func__); + rc = -ENODEV; + goto out_remove; + } + cfg->parent_dev = to_pci_dev(phys_dev); + + cfg->cxl_afu = cxl_pci_to_afu(pdev); + + rc = init_pci(cfg); + if (rc) { + dev_err(&pdev->dev, "%s: call to init_pci " + "failed rc=%d!\n", __func__, rc); + goto out_remove; + } + cfg->init_state = INIT_STATE_PCI; + + rc = init_afu(cfg); + if (rc) { + dev_err(&pdev->dev, "%s: call to init_afu " + "failed rc=%d!\n", __func__, rc); + goto out_remove; + } + cfg->init_state = INIT_STATE_AFU; + + + rc = init_scsi(cfg); + if (rc) { + dev_err(&pdev->dev, "%s: call to init_scsi " + "failed rc=%d!\n", __func__, rc); + goto out_remove; + } + cfg->init_state = INIT_STATE_SCSI; + +out: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; + +out_remove: + cxlflash_remove(pdev); + goto out; +} + +/* + * PCI device structure + */ +static struct pci_driver cxlflash_driver = { + .name = CXLFLASH_NAME, + .id_table = cxlflash_pci_table, + .probe = cxlflash_probe, + .remove = cxlflash_remove, +}; + +/** + * init_cxlflash() - module entry point + * + * Return: 0 on success / non-zero on failure + */ +static int __init init_cxlflash(void) +{ + pr_info("%s: IBM Power CXL Flash Adapter: %s\n", + __func__, CXLFLASH_DRIVER_DATE); + + return pci_register_driver(&cxlflash_driver); +} + +/** + * exit_cxlflash() - module exit point + */ +static void __exit exit_cxlflash(void) +{ + pci_unregister_driver(&cxlflash_driver); +} + +module_init(init_cxlflash); +module_exit(exit_cxlflash); diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h new file mode 100644 index 000000000000..7f890ccf3289 --- /dev/null +++ b/drivers/scsi/cxlflash/main.h @@ -0,0 +1,104 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _CXLFLASH_MAIN_H +#define _CXLFLASH_MAIN_H + +#include +#include +#include +#include + +#define CXLFLASH_NAME "cxlflash" +#define CXLFLASH_ADAPTER_NAME "IBM POWER CXL Flash Adapter" +#define CXLFLASH_DRIVER_DATE "(June 2, 2015)" + +#define PCI_DEVICE_ID_IBM_CORSA 0x04F0 +#define CXLFLASH_SUBS_DEV_ID 0x04F0 + +/* Since there is only one target, make it 0 */ +#define CXLFLASH_TARGET 0 +#define CXLFLASH_MAX_CDB_LEN 16 + +/* Really only one target per bus since the Texan is directly attached */ +#define CXLFLASH_MAX_NUM_TARGETS_PER_BUS 1 +#define CXLFLASH_MAX_NUM_LUNS_PER_TARGET 65536 + +#define CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT (120 * HZ) + +#define NUM_FC_PORTS CXLFLASH_NUM_FC_PORTS /* ports per AFU */ + +/* FC defines */ +#define FC_MTIP_CMDCONFIG 0x010 +#define FC_MTIP_STATUS 0x018 + +#define FC_PNAME 0x300 +#define FC_CONFIG 0x320 +#define FC_CONFIG2 0x328 +#define FC_STATUS 0x330 +#define FC_ERROR 0x380 +#define FC_ERRCAP 0x388 +#define FC_ERRMSK 0x390 +#define FC_CNT_CRCERR 0x538 +#define FC_CRC_THRESH 0x580 + +#define FC_MTIP_CMDCONFIG_ONLINE 0x20ULL +#define FC_MTIP_CMDCONFIG_OFFLINE 0x40ULL + +#define FC_MTIP_STATUS_MASK 0x30ULL +#define FC_MTIP_STATUS_ONLINE 0x20ULL +#define FC_MTIP_STATUS_OFFLINE 0x10ULL + +/* TIMEOUT and RETRY definitions */ + +/* AFU command timeout values */ +#define MC_AFU_SYNC_TIMEOUT 5 /* 5 secs */ + +/* AFU command room retry limit */ +#define MC_ROOM_RETRY_CNT 10 + +/* FC CRC clear periodic timer */ +#define MC_CRC_THRESH 100 /* threshold in 5 mins */ + +#define FC_PORT_STATUS_RETRY_CNT 100 /* 100 100ms retries = 10 seconds */ +#define FC_PORT_STATUS_RETRY_INTERVAL_US 100000 /* microseconds */ + +/* VPD defines */ +#define CXLFLASH_VPD_LEN 256 +#define WWPN_LEN 16 +#define WWPN_BUF_LEN (WWPN_LEN + 1) + +enum undo_level { + RELEASE_CONTEXT = 0, + FREE_IRQ, + UNMAP_ONE, + UNMAP_TWO, + UNMAP_THREE, + UNDO_START +}; + +struct dev_dependent_vals { + u64 max_sectors; +}; + +struct asyc_intr_info { + u64 status; + char *desc; + u8 port; + u8 action; +#define CLR_FC_ERROR 0x01 +#define LINK_RESET 0x02 +}; + +#endif /* _CXLFLASH_MAIN_H */ diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h new file mode 100755 index 000000000000..bf5d39978630 --- /dev/null +++ b/drivers/scsi/cxlflash/sislite.h @@ -0,0 +1,465 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM 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; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _SISLITE_H +#define _SISLITE_H + +#include + +typedef u16 ctx_hndl_t; +typedef u32 res_hndl_t; + +#define SIZE_4K 4096 +#define SIZE_64K 65536 + +/* + * IOARCB: 64 bytes, min 16 byte alignment required, host native endianness + * except for SCSI CDB which remains big endian per SCSI standards. + */ +struct sisl_ioarcb { + u16 ctx_id; /* ctx_hndl_t */ + u16 req_flags; +#define SISL_REQ_FLAGS_RES_HNDL 0x8000U /* bit 0 (MSB) */ +#define SISL_REQ_FLAGS_PORT_LUN_ID 0x0000U + +#define SISL_REQ_FLAGS_SUP_UNDERRUN 0x4000U /* bit 1 */ + +#define SISL_REQ_FLAGS_TIMEOUT_SECS 0x0000U /* bits 8,9 */ +#define SISL_REQ_FLAGS_TIMEOUT_MSECS 0x0040U +#define SISL_REQ_FLAGS_TIMEOUT_USECS 0x0080U +#define SISL_REQ_FLAGS_TIMEOUT_CYCLES 0x00C0U + +#define SISL_REQ_FLAGS_TMF_CMD 0x0004u /* bit 13 */ + +#define SISL_REQ_FLAGS_AFU_CMD 0x0002U /* bit 14 */ + +#define SISL_REQ_FLAGS_HOST_WRITE 0x0001U /* bit 15 (LSB) */ +#define SISL_REQ_FLAGS_HOST_READ 0x0000U + + union { + u32 res_hndl; /* res_hndl_t */ + u32 port_sel; /* this is a selection mask: + * 0x1 -> port#0 can be selected, + * 0x2 -> port#1 can be selected. + * Can be bitwise ORed. + */ + }; + u64 lun_id; + u32 data_len; /* 4K for read/write */ + u32 ioadl_len; + union { + u64 data_ea; /* min 16 byte aligned */ + u64 ioadl_ea; + }; + u8 msi; /* LISN to send on RRQ write */ +#define SISL_MSI_CXL_PFAULT 0 /* reserved for CXL page faults */ +#define SISL_MSI_SYNC_ERROR 1 /* recommended for AFU sync error */ +#define SISL_MSI_RRQ_UPDATED 2 /* recommended for IO completion */ +#define SISL_MSI_ASYNC_ERROR 3 /* master only - for AFU async error */ + + u8 rrq; /* 0 for a single RRQ */ + u16 timeout; /* in units specified by req_flags */ + u32 rsvd1; + u8 cdb[16]; /* must be in big endian */ + struct scsi_cmnd *scp; +} __packed; + +struct sisl_rc { + u8 flags; +#define SISL_RC_FLAGS_SENSE_VALID 0x80U +#define SISL_RC_FLAGS_FCP_RSP_CODE_VALID 0x40U +#define SISL_RC_FLAGS_OVERRUN 0x20U +#define SISL_RC_FLAGS_UNDERRUN 0x10U + + u8 afu_rc; +#define SISL_AFU_RC_RHT_INVALID 0x01U /* user error */ +#define SISL_AFU_RC_RHT_UNALIGNED 0x02U /* should never happen */ +#define SISL_AFU_RC_RHT_OUT_OF_BOUNDS 0x03u /* user error */ +#define SISL_AFU_RC_RHT_DMA_ERR 0x04u /* see afu_extra + may retry if afu_retry is off + possible on master exit + */ +#define SISL_AFU_RC_RHT_RW_PERM 0x05u /* no RW perms, user error */ +#define SISL_AFU_RC_LXT_UNALIGNED 0x12U /* should never happen */ +#define SISL_AFU_RC_LXT_OUT_OF_BOUNDS 0x13u /* user error */ +#define SISL_AFU_RC_LXT_DMA_ERR 0x14u /* see afu_extra + may retry if afu_retry is off + possible on master exit + */ +#define SISL_AFU_RC_LXT_RW_PERM 0x15u /* no RW perms, user error */ + +#define SISL_AFU_RC_NOT_XLATE_HOST 0x1au /* possible if master exited */ + + /* NO_CHANNELS means the FC ports selected by dest_port in + * IOARCB or in the LXT entry are down when the AFU tried to select + * a FC port. If the port went down on an active IO, it will set + * fc_rc to =0x54(NOLOGI) or 0x57(LINKDOWN) instead. + */ +#define SISL_AFU_RC_NO_CHANNELS 0x20U /* see afu_extra, may retry */ +#define SISL_AFU_RC_CAP_VIOLATION 0x21U /* either user error or + afu reset/master restart + */ +#define SISL_AFU_RC_OUT_OF_DATA_BUFS 0x30U /* always retry */ +#define SISL_AFU_RC_DATA_DMA_ERR 0x31U /* see afu_extra + may retry if afu_retry is off + */ + + u8 scsi_rc; /* SCSI status byte, retry as appropriate */ +#define SISL_SCSI_RC_CHECK 0x02U +#define SISL_SCSI_RC_BUSY 0x08u + + u8 fc_rc; /* retry */ + /* + * We should only see fc_rc=0x57 (LINKDOWN) or 0x54(NOLOGI) for + * commands that are in flight when a link goes down or is logged out. + * If the link is down or logged out before AFU selects the port, either + * it will choose the other port or we will get afu_rc=0x20 (no_channel) + * if there is no valid port to use. + * + * ABORTPEND/ABORTOK/ABORTFAIL/TGTABORT can be retried, typically these + * would happen if a frame is dropped and something times out. + * NOLOGI or LINKDOWN can be retried if the other port is up. + * RESIDERR can be retried as well. + * + * ABORTFAIL might indicate that lots of frames are getting CRC errors. + * So it maybe retried once and reset the link if it happens again. + * The link can also be reset on the CRC error threshold interrupt. + */ +#define SISL_FC_RC_ABORTPEND 0x52 /* exchange timeout or abort request */ +#define SISL_FC_RC_WRABORTPEND 0x53 /* due to write XFER_RDY invalid */ +#define SISL_FC_RC_NOLOGI 0x54 /* port not logged in, in-flight cmds */ +#define SISL_FC_RC_NOEXP 0x55 /* FC protocol error or HW bug */ +#define SISL_FC_RC_INUSE 0x56 /* tag already in use, HW bug */ +#define SISL_FC_RC_LINKDOWN 0x57 /* link down, in-flight cmds */ +#define SISL_FC_RC_ABORTOK 0x58 /* pending abort completed w/success */ +#define SISL_FC_RC_ABORTFAIL 0x59 /* pending abort completed w/fail */ +#define SISL_FC_RC_RESID 0x5A /* ioasa underrun/overrun flags set */ +#define SISL_FC_RC_RESIDERR 0x5B /* actual data len does not match SCSI + reported len, possbly due to dropped + frames */ +#define SISL_FC_RC_TGTABORT 0x5C /* command aborted by target */ +}; + +#define SISL_SENSE_DATA_LEN 20 /* Sense data length */ + +/* + * IOASA: 64 bytes & must follow IOARCB, min 16 byte alignment required, + * host native endianness + */ +struct sisl_ioasa { + union { + struct sisl_rc rc; + u32 ioasc; +#define SISL_IOASC_GOOD_COMPLETION 0x00000000U + }; + u32 resid; + u8 port; + u8 afu_extra; + /* when afu_rc=0x04, 0x14, 0x31 (_xxx_DMA_ERR): + * afu_exta contains PSL response code. Useful codes are: + */ +#define SISL_AFU_DMA_ERR_PAGE_IN 0x0A /* AFU_retry_on_pagein Action + * Enabled N/A + * Disabled retry + */ +#define SISL_AFU_DMA_ERR_INVALID_EA 0x0B /* this is a hard error + * afu_rc Implies + * 0x04, 0x14 master exit. + * 0x31 user error. + */ + /* when afu rc=0x20 (no channels): + * afu_extra bits [4:5]: available portmask, [6:7]: requested portmask. + */ +#define SISL_AFU_NO_CLANNELS_AMASK(afu_extra) (((afu_extra) & 0x0C) >> 2) +#define SISL_AFU_NO_CLANNELS_RMASK(afu_extra) ((afu_extra) & 0x03) + + u8 scsi_extra; + u8 fc_extra; + u8 sense_data[SISL_SENSE_DATA_LEN]; + + /* These fields are defined by the SISlite architecture for the + * host to use as they see fit for their implementation. + */ + union { + u64 host_use[4]; + u8 host_use_b[32]; + }; +} __packed; + +#define SISL_RESP_HANDLE_T_BIT 0x1ULL /* Toggle bit */ + +/* MMIO space is required to support only 64-bit access */ + +/* + * This AFU has two mechanisms to deal with endian-ness. + * One is a global configuration (in the afu_config) register + * below that specifies the endian-ness of the host. + * The other is a per context (i.e. application) specification + * controlled by the endian_ctrl field here. Since the master + * context is one such application the master context's + * endian-ness is set to be the same as the host. + * + * As per the SISlite spec, the MMIO registers are always + * big endian. + */ +#define SISL_ENDIAN_CTRL_BE 0x8000000000000080ULL +#define SISL_ENDIAN_CTRL_LE 0x0000000000000000ULL + +#ifdef __BIG_ENDIAN +#define SISL_ENDIAN_CTRL SISL_ENDIAN_CTRL_BE +#else +#define SISL_ENDIAN_CTRL SISL_ENDIAN_CTRL_LE +#endif + +/* per context host transport MMIO */ +struct sisl_host_map { + __be64 endian_ctrl; /* Per context Endian Control. The AFU will + * operate on whatever the context is of the + * host application. + */ + + __be64 intr_status; /* this sends LISN# programmed in ctx_ctrl. + * Only recovery in a PERM_ERR is a context + * exit since there is no way to tell which + * command caused the error. + */ +#define SISL_ISTATUS_PERM_ERR_CMDROOM 0x0010ULL /* b59, user error */ +#define SISL_ISTATUS_PERM_ERR_RCB_READ 0x0008ULL /* b60, user error */ +#define SISL_ISTATUS_PERM_ERR_SA_WRITE 0x0004ULL /* b61, user error */ +#define SISL_ISTATUS_PERM_ERR_RRQ_WRITE 0x0002ULL /* b62, user error */ + /* Page in wait accessing RCB/IOASA/RRQ is reported in b63. + * Same error in data/LXT/RHT access is reported via IOASA. + */ +#define SISL_ISTATUS_TEMP_ERR_PAGEIN 0x0001ULL /* b63, can be generated + * only when AFU auto + * retry is disabled. + * If user can determine + * the command that + * caused the error, it + * can be retried. + */ +#define SISL_ISTATUS_UNMASK (0x001FULL) /* 1 means unmasked */ +#define SISL_ISTATUS_MASK ~(SISL_ISTATUS_UNMASK) /* 1 means masked */ + + __be64 intr_clear; + __be64 intr_mask; + __be64 ioarrin; /* only write what cmd_room permits */ + __be64 rrq_start; /* start & end are both inclusive */ + __be64 rrq_end; /* write sequence: start followed by end */ + __be64 cmd_room; + __be64 ctx_ctrl; /* least signiifcant byte or b56:63 is LISN# */ + __be64 mbox_w; /* restricted use */ +}; + +/* per context provisioning & control MMIO */ +struct sisl_ctrl_map { + __be64 rht_start; + __be64 rht_cnt_id; + /* both cnt & ctx_id args must be ULL */ +#define SISL_RHT_CNT_ID(cnt, ctx_id) (((cnt) << 48) | ((ctx_id) << 32)) + + __be64 ctx_cap; /* afu_rc below is when the capability is violated */ +#define SISL_CTX_CAP_PROXY_ISSUE 0x8000000000000000ULL /* afu_rc 0x21 */ +#define SISL_CTX_CAP_REAL_MODE 0x4000000000000000ULL /* afu_rc 0x21 */ +#define SISL_CTX_CAP_HOST_XLATE 0x2000000000000000ULL /* afu_rc 0x1a */ +#define SISL_CTX_CAP_PROXY_TARGET 0x1000000000000000ULL /* afu_rc 0x21 */ +#define SISL_CTX_CAP_AFU_CMD 0x0000000000000008ULL /* afu_rc 0x21 */ +#define SISL_CTX_CAP_GSCSI_CMD 0x0000000000000004ULL /* afu_rc 0x21 */ +#define SISL_CTX_CAP_WRITE_CMD 0x0000000000000002ULL /* afu_rc 0x21 */ +#define SISL_CTX_CAP_READ_CMD 0x0000000000000001ULL /* afu_rc 0x21 */ + __be64 mbox_r; +}; + +/* single copy global regs */ +struct sisl_global_regs { + __be64 aintr_status; + /* In cxlflash, each FC port/link gets a byte of status */ +#define SISL_ASTATUS_FC0_OTHER 0x8000ULL /* b48, other err, + FC_ERRCAP[31:20] */ +#define SISL_ASTATUS_FC0_LOGO 0x4000ULL /* b49, target sent FLOGI/PLOGI/LOGO + while logged in */ +#define SISL_ASTATUS_FC0_CRC_T 0x2000ULL /* b50, CRC threshold exceeded */ +#define SISL_ASTATUS_FC0_LOGI_R 0x1000ULL /* b51, login state mechine timed out + and retrying */ +#define SISL_ASTATUS_FC0_LOGI_F 0x0800ULL /* b52, login failed, + FC_ERROR[19:0] */ +#define SISL_ASTATUS_FC0_LOGI_S 0x0400ULL /* b53, login succeeded */ +#define SISL_ASTATUS_FC0_LINK_DN 0x0200ULL /* b54, link online to offline */ +#define SISL_ASTATUS_FC0_LINK_UP 0x0100ULL /* b55, link offline to online */ + +#define SISL_ASTATUS_FC1_OTHER 0x0080ULL /* b56 */ +#define SISL_ASTATUS_FC1_LOGO 0x0040ULL /* b57 */ +#define SISL_ASTATUS_FC1_CRC_T 0x0020ULL /* b58 */ +#define SISL_ASTATUS_FC1_LOGI_R 0x0010ULL /* b59 */ +#define SISL_ASTATUS_FC1_LOGI_F 0x0008ULL /* b60 */ +#define SISL_ASTATUS_FC1_LOGI_S 0x0004ULL /* b61 */ +#define SISL_ASTATUS_FC1_LINK_DN 0x0002ULL /* b62 */ +#define SISL_ASTATUS_FC1_LINK_UP 0x0001ULL /* b63 */ + +#define SISL_FC_INTERNAL_UNMASK 0x0000000300000000ULL /* 1 means unmasked */ +#define SISL_FC_INTERNAL_MASK ~(SISL_FC_INTERNAL_UNMASK) +#define SISL_FC_INTERNAL_SHIFT 32 + +#define SISL_ASTATUS_UNMASK 0xFFFFULL /* 1 means unmasked */ +#define SISL_ASTATUS_MASK ~(SISL_ASTATUS_UNMASK) /* 1 means masked */ + + __be64 aintr_clear; + __be64 aintr_mask; + __be64 afu_ctrl; + __be64 afu_hb; + __be64 afu_scratch_pad; + __be64 afu_port_sel; +#define SISL_AFUCONF_AR_IOARCB 0x4000ULL +#define SISL_AFUCONF_AR_LXT 0x2000ULL +#define SISL_AFUCONF_AR_RHT 0x1000ULL +#define SISL_AFUCONF_AR_DATA 0x0800ULL +#define SISL_AFUCONF_AR_RSRC 0x0400ULL +#define SISL_AFUCONF_AR_IOASA 0x0200ULL +#define SISL_AFUCONF_AR_RRQ 0x0100ULL +/* Aggregate all Auto Retry Bits */ +#define SISL_AFUCONF_AR_ALL (SISL_AFUCONF_AR_IOARCB|SISL_AFUCONF_AR_LXT| \ + SISL_AFUCONF_AR_RHT|SISL_AFUCONF_AR_DATA| \ + SISL_AFUCONF_AR_RSRC|SISL_AFUCONF_AR_IOASA| \ + SISL_AFUCONF_AR_RRQ) +#ifdef __BIG_ENDIAN +#define SISL_AFUCONF_ENDIAN 0x0000ULL +#else +#define SISL_AFUCONF_ENDIAN 0x0020ULL +#endif +#define SISL_AFUCONF_MBOX_CLR_READ 0x0010ULL + __be64 afu_config; + __be64 rsvd[0xf8]; + __be64 afu_version; + __be64 interface_version; +}; + +#define CXLFLASH_NUM_FC_PORTS 2 +#define CXLFLASH_MAX_CONTEXT 512 /* how many contexts per afu */ +#define CXLFLASH_NUM_VLUNS 512 + +struct sisl_global_map { + union { + struct sisl_global_regs regs; + char page0[SIZE_4K]; /* page 0 */ + }; + + char page1[SIZE_4K]; /* page 1 */ + + /* pages 2 & 3 */ + __be64 fc_regs[CXLFLASH_NUM_FC_PORTS][CXLFLASH_NUM_VLUNS]; + + /* pages 4 & 5 (lun tbl) */ + __be64 fc_port[CXLFLASH_NUM_FC_PORTS][CXLFLASH_NUM_VLUNS]; + +}; + +/* + * CXL Flash Memory Map + * + * +-------------------------------+ + * | 512 * 64 KB User MMIO | + * | (per context) | + * | User Accessible | + * +-------------------------------+ + * | 512 * 128 B per context | + * | Provisioning and Control | + * | Trusted Process accessible | + * +-------------------------------+ + * | 64 KB Global | + * | Trusted Process accessible | + * +-------------------------------+ +*/ +struct cxlflash_afu_map { + union { + struct sisl_host_map host; + char harea[SIZE_64K]; /* 64KB each */ + } hosts[CXLFLASH_MAX_CONTEXT]; + + union { + struct sisl_ctrl_map ctrl; + char carea[cache_line_size()]; /* 128B each */ + } ctrls[CXLFLASH_MAX_CONTEXT]; + + union { + struct sisl_global_map global; + char garea[SIZE_64K]; /* 64KB single block */ + }; +}; + +/* LBA translation control blocks */ + +struct sisl_lxt_entry { + u64 rlba_base; /* bits 0:47 is base + * b48:55 is lun index + * b58:59 is write & read perms + * (if no perm, afu_rc=0x15) + * b60:63 is port_sel mask + */ + +}; + +/* Per the SISlite spec, RHT entries are to be 16-byte aligned */ +struct sisl_rht_entry { + struct sisl_lxt_entry *lxt_start; + u32 lxt_cnt; + u16 rsvd; + u8 fp; /* format & perm nibbles. + * (if no perm, afu_rc=0x05) + */ + u8 nmask; +} __packed __aligned(16); + +struct sisl_rht_entry_f1 { + u64 lun_id; + union { + struct { + u8 valid; + u8 rsvd[5]; + u8 fp; + u8 port_sel; + }; + + u64 dw; + }; +} __packed __aligned(16); + +/* make the fp byte */ +#define SISL_RHT_FP(fmt, perm) (((fmt) << 4) | (perm)) + +/* make the fp byte for a clone from a source fp and clone flags + * flags must be only 2 LSB bits. + */ +#define SISL_RHT_FP_CLONE(src_fp, cln_flags) ((src_fp) & (0xFC | (cln_flags))) + +#define RHT_PERM_READ 0x01U +#define RHT_PERM_WRITE 0x02U +#define RHT_PERM_RW (RHT_PERM_READ | RHT_PERM_WRITE) + +/* extract the perm bits from a fp */ +#define SISL_RHT_PERM(fp) ((fp) & RHT_PERM_RW) + +#define PORT0 0x01U +#define PORT1 0x02U +#define BOTH_PORTS (PORT0 | PORT1) + +/* AFU Sync Mode byte */ +#define AFU_LW_SYNC 0x0U +#define AFU_HW_SYNC 0x1U +#define AFU_GSYNC 0x2U + +/* Special Task Management Function CDB */ +#define TMF_LUN_RESET 0x1U +#define TMF_CLEAR_ACA 0x2U + +#endif /* _SISLITE_H */ -- cgit v1.3-6-gb490 From b6a54b8d895648d915c7e8308f3d3e6bf2505d69 Mon Sep 17 00:00:00 2001 From: Chris Zankel Date: Mon, 20 Jul 2015 16:29:50 -0700 Subject: target: remove initiatorname field in se_acl_lun From: Chris Zankel The initiatorname field in se_acl_lun is only a copy of the same field in se_node_acl, so remove it and use the version in se_node_acl where needed (it's actually only used for pr_debug) Signed-off-by: Chris Zankel Signed-off-by: Spencer Baugh Reviewed-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 8 +++----- drivers/target/target_core_fabric_configfs.c | 2 +- include/target/target_core_base.h | 1 - 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index db7034292053..55f2cb2a9947 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -620,8 +620,6 @@ struct se_lun_acl *core_dev_init_initiator_node_lun_acl( lacl->mapped_lun = mapped_lun; lacl->se_lun_nacl = nacl; - snprintf(lacl->initiatorname, TRANSPORT_IQN_LEN, "%s", - nacl->initiatorname); return lacl; } @@ -656,7 +654,7 @@ int core_dev_add_initiator_node_lun_acl( " InitiatorNode: %s\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, lacl->mapped_lun, (lun_access & TRANSPORT_LUNFLAGS_READ_WRITE) ? "RW" : "RO", - lacl->initiatorname); + nacl->initiatorname); /* * Check to see if there are any existing persistent reservation APTPL * pre-registrations that need to be enabled for this LUN ACL.. @@ -688,7 +686,7 @@ int core_dev_del_initiator_node_lun_acl( " InitiatorNode: %s Mapped LUN: %llu\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun, - lacl->initiatorname, lacl->mapped_lun); + nacl->initiatorname, lacl->mapped_lun); return 0; } @@ -701,7 +699,7 @@ void core_dev_free_initiator_node_lun_acl( " Mapped LUN: %llu\n", tpg->se_tpg_tfo->get_fabric_name(), tpg->se_tpg_tfo->tpg_get_tag(tpg), tpg->se_tpg_tfo->get_fabric_name(), - lacl->initiatorname, lacl->mapped_lun); + lacl->se_lun_nacl->initiatorname, lacl->mapped_lun); kfree(lacl); } diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 48a36989c1a6..be42429468e2 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -203,7 +203,7 @@ static ssize_t target_fabric_mappedlun_store_write_protect( pr_debug("%s_ConfigFS: Changed Initiator ACL: %s" " Mapped LUN: %llu Write Protect bit to %s\n", se_tpg->se_tpg_tfo->get_fabric_name(), - lacl->initiatorname, lacl->mapped_lun, (op) ? "ON" : "OFF"); + se_nacl->initiatorname, lacl->mapped_lun, (op) ? "ON" : "OFF"); return count; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index d57a0cbf265b..95e65bd31e05 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -593,7 +593,6 @@ struct se_ml_stat_grps { }; struct se_lun_acl { - char initiatorname[TRANSPORT_IQN_LEN]; u64 mapped_lun; struct se_node_acl *se_lun_nacl; struct se_lun *se_lun; -- cgit v1.3-6-gb490 From aa75679c797c0250a853e600e45368f1f9545c27 Mon Sep 17 00:00:00 2001 From: Alexei Potashnik Date: Mon, 20 Jul 2015 17:12:12 -0700 Subject: target/iscsi: Use proper SGL accessors for digest computation Current implementation assumes that all the buffers of an IO are linked with a single SG list, which is OK because target-core is only allocating a contigious scatterlist region. However, this assumption is wrong for se_cmd descriptors that want to use chaining across multiple SGL regions. Fix this up by using proper SGL accessors for digest payload computation. Signed-off-by: Alexei Potashnik Cc: Roland Dreier Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 4e68b62193ed..a4cf58cb835d 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1209,7 +1209,6 @@ static u32 iscsit_do_crypto_hash_sg( u8 *pad_bytes) { u32 data_crc; - u32 i; struct scatterlist *sg; unsigned int page_off; @@ -1218,15 +1217,15 @@ static u32 iscsit_do_crypto_hash_sg( sg = cmd->first_data_sg; page_off = cmd->first_data_sg_off; - i = 0; while (data_length) { - u32 cur_len = min_t(u32, data_length, (sg[i].length - page_off)); + u32 cur_len = min_t(u32, data_length, (sg->length - page_off)); - crypto_hash_update(hash, &sg[i], cur_len); + crypto_hash_update(hash, sg, cur_len); data_length -= cur_len; page_off = 0; - i++; + /* iscsit_map_iovec has already checked for invalid sg pointers */ + sg = sg_next(sg); } if (padding) { -- cgit v1.3-6-gb490 From c72c5250224d475614a00c1d7e54a67f77cd3410 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 22 Jul 2015 15:08:18 -0700 Subject: target: allow underflow/overflow for PR OUT etc. commands It's not necessarily a fatal error if a command with a data-out phase has a data length that differs from the transport data length (e.g. PERSISTENT RESERVE OUT might have a parameter list length in the CDB that's smaller than the FC_DL field), so allow these commands. The Windows compliance test sends them. Signed-off-by: Roland Dreier Signed-off-by: Spencer Baugh Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 98155db28365..729ec7345e99 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1088,9 +1088,9 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size) " 0x%02x\n", cmd->se_tfo->get_fabric_name(), cmd->data_length, size, cmd->t_task_cdb[0]); - if (cmd->data_direction == DMA_TO_DEVICE) { - pr_err("Rejecting underflow/overflow" - " WRITE data\n"); + if (cmd->data_direction == DMA_TO_DEVICE && + cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) { + pr_err("Rejecting underflow/overflow WRITE data\n"); return TCM_INVALID_CDB_FIELD; } /* -- cgit v1.3-6-gb490 From 568e1f6524b06ff113cebf5711832ca95d37259f Mon Sep 17 00:00:00 2001 From: Joern Engel Date: Wed, 22 Jul 2015 15:01:36 -0700 Subject: target: improve unsupported opcode message Make the warning about unsupported SCSI opcode more useful: - Add in the initiator name so we know who's sending it. - Print the warning even for opcodes that spc_parse_cdb() knows about but that we don't handle. Signed-off-by: Joern Engel Signed-off-by: Spencer Baugh Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_spc.c | 3 --- drivers/target/target_core_transport.c | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index b949d335a6ba..a07d455e0dd5 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1390,9 +1390,6 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) } break; default: - pr_warn("TARGET_CORE[%s]: Unsupported SCSI Opcode" - " 0x%02x, sending CHECK_CONDITION.\n", - cmd->se_tfo->get_fabric_name(), cdb[0]); return TCM_UNSUPPORTED_SCSI_OPCODE; } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 729ec7345e99..bd68727a6806 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1247,6 +1247,11 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb) } ret = dev->transport->parse_cdb(cmd); + if (ret == TCM_UNSUPPORTED_SCSI_OPCODE) + pr_warn_ratelimited("%s/%s: Unsupported SCSI Opcode 0x%02x, sending CHECK_CONDITION.\n", + cmd->se_tfo->get_fabric_name(), + cmd->se_sess->se_node_acl->initiatorname, + cmd->t_task_cdb[0]); if (ret) return ret; -- cgit v1.3-6-gb490 From 45182ed576898b846a98ac3bff2ddcb9d35a0181 Mon Sep 17 00:00:00 2001 From: Brian Bunker Date: Thu, 23 Jul 2015 15:27:46 -0700 Subject: target: add support for START_STOP_UNIT SCSI opcode AIX servers using VIOS servers that virtualize FC cards will have a problem booting without support for START_STOP_UNIT. Cite sbc3r36 exactly, clean up if conditions (rob + hch) Signed-off-by: Brian Bunker Signed-off-by: Spencer Baugh Reviewed-by: Christoph Hellwig Cc: "Robert Elliott (Server Storage)" Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index ac7215039e5a..4fc8343786f2 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -154,6 +154,38 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd) return 0; } +static sense_reason_t +sbc_emulate_startstop(struct se_cmd *cmd) +{ + unsigned char *cdb = cmd->t_task_cdb; + + /* + * See sbc3r36 section 5.25 + * Immediate bit should be set since there is nothing to complete + * POWER CONDITION MODIFIER 0h + */ + if (!(cdb[1] & 1) || cdb[2] || cdb[3]) + return TCM_INVALID_CDB_FIELD; + + /* + * See sbc3r36 section 5.25 + * POWER CONDITION 0h START_VALID - process START and LOEJ + */ + if (cdb[4] >> 4 & 0xf) + return TCM_INVALID_CDB_FIELD; + + /* + * See sbc3r36 section 5.25 + * LOEJ 0h - nothing to load or unload + * START 1h - we are ready + */ + if (!(cdb[4] & 1) || (cdb[4] & 2) || (cdb[4] & 4)) + return TCM_INVALID_CDB_FIELD; + + target_complete_cmd(cmd, SAM_STAT_GOOD); + return 0; +} + sector_t sbc_get_write_same_sectors(struct se_cmd *cmd) { u32 num_blocks; @@ -1069,6 +1101,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) size = 0; cmd->execute_cmd = sbc_emulate_noop; break; + case START_STOP: + size = 0; + cmd->execute_cmd = sbc_emulate_startstop; + break; default: ret = spc_parse_cdb(cmd, &size); if (ret) -- cgit v1.3-6-gb490 From 9c31820b6ab93ec298ad98abeee49759b5f5958c Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 21 Jul 2015 17:45:32 -0700 Subject: target: Remove cmd->se_ordered_id (unused except debug log lines) For every command, we set se_ordered_id by doing atomic_inc_return on dev->dev_ordered_id for the corresponding device. However, the only places this value gets used are in pr_debug() calls, which doesn't seem worth an extra atomic op per IO. Signed-off-by: Roland Dreier Reviewed-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 1 - drivers/target/target_core_transport.c | 39 ++++++++++++---------------------- include/target/target_core_base.h | 2 -- 3 files changed, 13 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 55f2cb2a9947..dcc424ac35d4 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -769,7 +769,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) spin_lock_init(&dev->se_tmr_lock); spin_lock_init(&dev->qf_cmd_lock); sema_init(&dev->caw_sem, 1); - atomic_set(&dev->dev_ordered_id, 0); INIT_LIST_HEAD(&dev->t10_wwn.t10_vpd_list); spin_lock_init(&dev->t10_wwn.t10_vpd_lock); INIT_LIST_HEAD(&dev->t10_pr.registration_list); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index bd68727a6806..3f0b50082de4 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1178,14 +1178,7 @@ transport_check_alloc_task_attr(struct se_cmd *cmd) " emulation is not supported\n"); return TCM_INVALID_CDB_FIELD; } - /* - * Used to determine when ORDERED commands should go from - * Dormant to Active status. - */ - cmd->se_ordered_id = atomic_inc_return(&dev->dev_ordered_id); - pr_debug("Allocated se_ordered_id: %u for Task Attr: 0x%02x on %s\n", - cmd->se_ordered_id, cmd->sam_task_attr, - dev->transport->name); + return 0; } @@ -1773,16 +1766,14 @@ static bool target_handle_task_attr(struct se_cmd *cmd) */ switch (cmd->sam_task_attr) { case TCM_HEAD_TAG: - pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x, " - "se_ordered_id: %u\n", - cmd->t_task_cdb[0], cmd->se_ordered_id); + pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x\n", + cmd->t_task_cdb[0]); return false; case TCM_ORDERED_TAG: atomic_inc_mb(&dev->dev_ordered_sync); - pr_debug("Added ORDERED for CDB: 0x%02x to ordered list, " - " se_ordered_id: %u\n", - cmd->t_task_cdb[0], cmd->se_ordered_id); + pr_debug("Added ORDERED for CDB: 0x%02x to ordered list\n", + cmd->t_task_cdb[0]); /* * Execute an ORDERED command if no other older commands @@ -1806,10 +1797,8 @@ static bool target_handle_task_attr(struct se_cmd *cmd) list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list); spin_unlock(&dev->delayed_cmd_lock); - pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to" - " delayed CMD list, se_ordered_id: %u\n", - cmd->t_task_cdb[0], cmd->sam_task_attr, - cmd->se_ordered_id); + pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to delayed CMD listn", + cmd->t_task_cdb[0], cmd->sam_task_attr); return true; } @@ -1894,20 +1883,18 @@ static void transport_complete_task_attr(struct se_cmd *cmd) if (cmd->sam_task_attr == TCM_SIMPLE_TAG) { atomic_dec_mb(&dev->simple_cmds); dev->dev_cur_ordered_id++; - pr_debug("Incremented dev->dev_cur_ordered_id: %u for" - " SIMPLE: %u\n", dev->dev_cur_ordered_id, - cmd->se_ordered_id); + pr_debug("Incremented dev->dev_cur_ordered_id: %u for SIMPLE\n", + dev->dev_cur_ordered_id); } else if (cmd->sam_task_attr == TCM_HEAD_TAG) { dev->dev_cur_ordered_id++; - pr_debug("Incremented dev_cur_ordered_id: %u for" - " HEAD_OF_QUEUE: %u\n", dev->dev_cur_ordered_id, - cmd->se_ordered_id); + pr_debug("Incremented dev_cur_ordered_id: %u for HEAD_OF_QUEUE\n", + dev->dev_cur_ordered_id); } else if (cmd->sam_task_attr == TCM_ORDERED_TAG) { atomic_dec_mb(&dev->dev_ordered_sync); dev->dev_cur_ordered_id++; - pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED:" - " %u\n", dev->dev_cur_ordered_id, cmd->se_ordered_id); + pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED\n", + dev->dev_cur_ordered_id); } target_restart_delayed_cmds(dev); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 95e65bd31e05..3afd8dba54e8 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -454,7 +454,6 @@ struct se_cmd { unsigned unknown_data_length:1; /* See se_cmd_flags_table */ u32 se_cmd_flags; - u32 se_ordered_id; /* Total size in bytes associated with command */ u32 data_length; u32 residual_count; @@ -744,7 +743,6 @@ struct se_device { atomic_long_t write_bytes; /* Active commands on this virtual SE device */ atomic_t simple_cmds; - atomic_t dev_ordered_id; atomic_t dev_ordered_sync; atomic_t dev_qf_count; u32 export_count; -- cgit v1.3-6-gb490 From 4aad0cc5c3f715efc294ac60fd0bf0e90829e18b Mon Sep 17 00:00:00 2001 From: Horia Geant? Date: Thu, 30 Jul 2015 22:11:18 +0300 Subject: crypto: caam - fix rfc4106 encap shared descriptor The encap shared descriptor was changed to use the new IV convention. In the process some commands were shifted, making the output length zero, caam effectively writing garbage in dst. While here, update the decap descriptor to execute the "write" commands before the "read"s (as it previously was). This makes sure the input fifo is drained before becoming full. Fixes: 46218750d523 ("crypto: caam - Use new IV convention") Signed-off-by: Horia Geant? Signed-off-by: Tudor Ambarus Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 3c50a5082127..e49373409582 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -87,8 +87,8 @@ #define DESC_GCM_DEC_LEN (DESC_GCM_BASE + 12 * CAAM_CMD_SZ) #define DESC_RFC4106_BASE (3 * CAAM_CMD_SZ) -#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 12 * CAAM_CMD_SZ) -#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 12 * CAAM_CMD_SZ) +#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) +#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) #define DESC_RFC4543_BASE (3 * CAAM_CMD_SZ) #define DESC_RFC4543_ENC_LEN (DESC_RFC4543_BASE + 11 * CAAM_CMD_SZ) @@ -989,19 +989,22 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) /* Will read cryptlen bytes */ append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - /* Read payload data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); + /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG); /* Skip assoc data */ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); /* cryptlen = seqoutlen - assoclen */ - append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + append_math_sub(desc, VARSEQOUTLEN, VARSEQINLEN, REG0, CAAM_CMD_SZ); /* Write encrypted data */ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); + /* Read payload data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); + /* Write ICV */ append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT); @@ -1060,9 +1063,8 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) /* Will read cryptlen bytes */ append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG3, CAAM_CMD_SZ); - /* Read encrypted data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); + /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG); /* Skip assoc data */ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); @@ -1073,6 +1075,10 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) /* Store payload data */ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); + /* Read encrypted data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); + /* Read ICV */ append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); -- cgit v1.3-6-gb490 From ab81a5e0660a058c2cc728fc114fa3082be78952 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Thu, 23 Jul 2015 22:33:21 +0200 Subject: target: check DPO/FUA usage for COMPARE AND WRITE COMPARE AND WRITE requests should fail if DPO or FUA is set, but the device is not advertising support. Signed-off-by: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_sbc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 4fc8343786f2..0b4b2a67d9f9 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -992,6 +992,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) " than 1\n", sectors); return TCM_INVALID_CDB_FIELD; } + if (sbc_check_dpofua(dev, cmd, cdb)) + return TCM_INVALID_CDB_FIELD; + /* * Double size because we have two buffers, note that * zero is not an error.. -- cgit v1.3-6-gb490 From 360d9bb5ee2db4d409448667de606c05b3914d53 Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Fri, 31 Jul 2015 10:17:35 +0300 Subject: Revert "ath9k: export HW random number generator" This reverts commit 6301566e0b2dafa7d6779598621bca867962a0a2. Oleksij Rempel noticed that the randomness doesn't look to be good enough and Stephan Mueller commented: "I would say that the discussed RNG does not seem fit for hooking it up with the hwrandom framework." http://lkml.kernel.org/g/3945775.m5HblJPgiO@tauon.atsec.com So let's the revert the patch until we are sure that we can trust this random generator. Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/Kconfig | 7 --- drivers/net/wireless/ath/ath9k/Makefile | 1 - drivers/net/wireless/ath/ath9k/ath9k.h | 23 ---------- drivers/net/wireless/ath/ath9k/main.c | 4 -- drivers/net/wireless/ath/ath9k/rng.c | 75 --------------------------------- 5 files changed, 110 deletions(-) delete mode 100644 drivers/net/wireless/ath/ath9k/rng.c (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index bde62ec98bc7..fee0cadb0f5e 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -176,10 +176,3 @@ config ATH9K_HTC_DEBUGFS depends on ATH9K_HTC && DEBUG_FS ---help--- Say Y, if you need access to ath9k_htc's statistics. - -config ATH9K_HWRNG - bool "Random number generator support" - depends on ATH9K && (HW_RANDOM = y || HW_RANDOM = ATH9K) - default y - ---help--- - Provides a hardware random number generator to the kernel. diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 76f9dc37500b..ecda613c2d54 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -15,7 +15,6 @@ ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o ath9k-$(CONFIG_ATH9K_TX99) += tx99.o ath9k-$(CONFIG_ATH9K_WOW) += wow.o -ath9k-$(CONFIG_ATH9K_HWRNG) += rng.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 45596e5ae4db..a7a81b3969ce 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -23,7 +23,6 @@ #include #include #include -#include #include "common.h" #include "debug.h" @@ -1042,12 +1041,6 @@ struct ath_softc { u32 wow_intr_before_sleep; bool force_wow; #endif - -#ifdef CONFIG_ATH9K_HWRNG - struct hwrng rng; - bool rng_initialized; - u32 rng_last; -#endif }; /********/ @@ -1070,22 +1063,6 @@ static inline int ath9k_tx99_send(struct ath_softc *sc, } #endif /* CONFIG_ATH9K_TX99 */ -/***************************/ -/* Random Number Generator */ -/***************************/ -#ifdef CONFIG_ATH9K_HWRNG -void ath9k_rng_register(struct ath_softc *sc); -void ath9k_rng_unregister(struct ath_softc *sc); -#else -static inline void ath9k_rng_register(struct ath_softc *sc) -{ -} - -static inline void ath9k_rng_unregister(struct ath_softc *sc) -{ -} -#endif - static inline void ath_read_cachesize(struct ath_common *common, int *csz) { common->bus_ops->read_cachesize(common, csz); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5916ab2f4a3d..cfd45cb8ccfc 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -739,8 +739,6 @@ static int ath9k_start(struct ieee80211_hw *hw) ath9k_ps_restore(sc); - ath9k_rng_register(sc); - return 0; } @@ -830,8 +828,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_deinit_channel_context(sc); - ath9k_rng_unregister(sc); - mutex_lock(&sc->mutex); ath_cancel_work(sc); diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c deleted file mode 100644 index d8fa7a535ab8..000000000000 --- a/drivers/net/wireless/ath/ath9k/rng.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2015 Qualcomm Atheros, 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 "ath9k.h" -#include "hw.h" -#include "ar9003_phy.h" - -static int ath9k_rng_data_read(struct hwrng *rng, u32 *data) -{ - u32 v1, v2; - struct ath_softc *sc = (struct ath_softc *)rng->priv; - struct ath_hw *ah = sc->sc_ah; - - ath9k_ps_wakeup(sc); - - REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 5); - REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5); - REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0); - - v1 = REG_READ(ah, AR_PHY_TST_ADC); - v2 = REG_READ(ah, AR_PHY_TST_ADC); - - ath9k_ps_restore(sc); - - /* wait for data ready */ - if (v1 && v2 && sc->rng_last != v1 && v1 != v2) { - *data = (v1 & 0xffff) | (v2 << 16); - sc->rng_last = v2; - - return sizeof(u32); - } - - sc->rng_last = v2; - - return 0; -} - -void ath9k_rng_register(struct ath_softc *sc) -{ - struct ath_hw *ah = sc->sc_ah; - - if (WARN_ON(sc->rng_initialized)) - return; - - if (!AR_SREV_9300_20_OR_LATER(ah)) - return; - - sc->rng.name = "ath9k"; - sc->rng.data_read = ath9k_rng_data_read; - sc->rng.priv = (unsigned long)sc; - - if (!hwrng_register(&sc->rng)) - sc->rng_initialized = true; -} - -void ath9k_rng_unregister(struct ath_softc *sc) -{ - if (sc->rng_initialized) { - hwrng_unregister(&sc->rng); - sc->rng_initialized = false; - } -} -- cgit v1.3-6-gb490 From 824deff87f5b1a2f32b9c3164191b0f5b22276b8 Mon Sep 17 00:00:00 2001 From: Rostislav Pehlivanov Date: Tue, 28 Jul 2015 08:38:47 +0100 Subject: HID: sony: Fix DS4 controller reporting rate issues This commit removes the cap on the DualShock 4 controller reporting rate when connected using Bluetooth. The previous value of '0xB0' capped the rate to only 20.83 Hz which many userspace utilities mistook as a sign of a bad signal. Since a 'B' and an '8' can look similar it's possible that someone mistook the one for another. The new value of '0x80' enables the full 1000 Hz peak reporting rate that the controller is capable of. Frank adds: "Back when the original code was written the purpose of that value was unknown and 0xB0 seemed to work so that's what ended up being used. Now that we know what it actually does and that 0x80 is a better choice I support this patch." [jkosina@suse.com: update changelog] Signed-off-by: Rostislav Pehlivanov Acked-by: Frank Praznik Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index ed0496abf573..661f94f8ab8b 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1854,7 +1854,7 @@ static void dualshock4_state_worker(struct work_struct *work) } else { memset(buf, 0, DS4_REPORT_0x11_SIZE); buf[0] = 0x11; - buf[1] = 0xB0; + buf[1] = 0x80; buf[3] = 0x0F; offset = 6; } -- cgit v1.3-6-gb490 From 5d8a0d0b44c207690adda723b8d60158c18fec8a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 31 Jul 2015 09:52:56 +0200 Subject: drm/i915: Update DRIVER_DATE to 20150731 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index abd1a8659d83..86e69f1ad3ee 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -56,7 +56,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20150717" +#define DRIVER_DATE "20150731" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ -- cgit v1.3-6-gb490 From 07e4d3d9e281136fdd781e8c3b9146b97f2d28d6 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 27 Jul 2015 16:36:42 +0900 Subject: clk: zynq: remove redundant $(CONFIG_ARCH_ZYNQ) in Makefile Kbuild descends into drivers/clk/zynq/ only when CONFIG_ARCH_ZYNQ is enabled. (see drivers/clk/Makefile) $(CONFIG_ARCH_ZYNQ) in drivers/clk/zynq/Makefile always evaluates to 'y'. Signed-off-by: Masahiro Yamada Signed-off-by: Michal Simek --- drivers/clk/zynq/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/zynq/Makefile b/drivers/clk/zynq/Makefile index 156d923f4fa9..0afc2e7cc5c1 100644 --- a/drivers/clk/zynq/Makefile +++ b/drivers/clk/zynq/Makefile @@ -1,3 +1,3 @@ # Zynq clock specific Makefile -obj-$(CONFIG_ARCH_ZYNQ) += clkc.o pll.o +obj-y += clkc.o pll.o -- cgit v1.3-6-gb490 From 93c03a2c36d2bc70d42acdeef12d0ac156ffecda Mon Sep 17 00:00:00 2001 From: Keerthy Date: Thu, 18 Jun 2015 13:31:12 +0530 Subject: ARM: dts: AM437X: add dpll_clksel_mac_clk node The patch adds the missing dpll_clksel_mac_clk clock node. Signed-off-by: Keerthy Signed-off-by: Tero Kristo --- arch/arm/boot/dts/am43xx-clocks.dtsi | 9 +++++++++ drivers/clk/ti/clk-43xx.c | 1 + 2 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/arch/arm/boot/dts/am43xx-clocks.dtsi b/arch/arm/boot/dts/am43xx-clocks.dtsi index d0c0dfa4ec48..cc88728d751d 100644 --- a/arch/arm/boot/dts/am43xx-clocks.dtsi +++ b/arch/arm/boot/dts/am43xx-clocks.dtsi @@ -486,6 +486,15 @@ reg = <0x4238>; }; + dpll_clksel_mac_clk: dpll_clksel_mac_clk { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_m5_ck>; + reg = <0x4234>; + ti,bit-shift = <2>; + ti,dividers = <2>, <5>; + }; + clk_32k_mosc_ck: clk_32k_mosc_ck { #clock-cells = <0>; compatible = "fixed-clock"; diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c index 3795fce8a830..7549b87c41ef 100644 --- a/drivers/clk/ti/clk-43xx.c +++ b/drivers/clk/ti/clk-43xx.c @@ -71,6 +71,7 @@ static struct ti_dt_clk am43xx_clks[] = { DT_CLK(NULL, "clk_24mhz", "clk_24mhz"), DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"), DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"), + DT_CLK(NULL, "dpll_clksel_mac_clk", "dpll_clksel_mac_clk"), DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"), DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"), DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"), -- cgit v1.3-6-gb490 From c3ece7e70dd8fab4fd3e4b9a74ad2df4cfa22e11 Mon Sep 17 00:00:00 2001 From: "Peter E. Berger" Date: Fri, 31 Jul 2015 01:55:05 -0500 Subject: USB: io_ti: Increase insufficient timeout for firmware downloads The io_ti driver fails to download firmware to Edgeport devices such as the EP/416 and EP/421 (devices with on-board E2PROM). One of the problems is that the default 1 second timeout in ti_vsend_sync() is insufficient for download operations. This patch increases the download timeout to 10 seconds. Signed-off-by: Peter E. Berger Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index ddbb8fe1046d..69378a7ee342 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -210,6 +210,10 @@ static int edge_create_sysfs_attrs(struct usb_serial_port *port); static int edge_remove_sysfs_attrs(struct usb_serial_port *port); +/* Timeouts in msecs: firmware downloads take longer */ +#define TI_VSEND_TIMEOUT_DEFAULT 1000 +#define TI_VSEND_TIMEOUT_FW_DOWNLOAD 10000 + static int ti_vread_sync(struct usb_device *dev, __u8 request, __u16 value, __u16 index, u8 *data, int size) { @@ -228,14 +232,14 @@ static int ti_vread_sync(struct usb_device *dev, __u8 request, return 0; } -static int ti_vsend_sync(struct usb_device *dev, __u8 request, - __u16 value, __u16 index, u8 *data, int size) +static int ti_vsend_sync(struct usb_device *dev, u8 request, u16 value, + u16 index, u8 *data, int size, int timeout) { int status; status = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT), - value, index, data, size, 1000); + value, index, data, size, timeout); if (status < 0) return status; if (status != size) { @@ -250,7 +254,8 @@ static int send_cmd(struct usb_device *dev, __u8 command, __u8 moduleid, __u16 value, u8 *data, int size) { - return ti_vsend_sync(dev, command, value, moduleid, data, size); + return ti_vsend_sync(dev, command, value, moduleid, data, size, + TI_VSEND_TIMEOUT_DEFAULT); } /* clear tx/rx buffers and fifo in TI UMP */ @@ -378,9 +383,9 @@ static int write_boot_mem(struct edgeport_serial *serial, } for (i = 0; i < length; ++i) { - status = ti_vsend_sync(serial->serial->dev, - UMPC_MEMORY_WRITE, buffer[i], - (__u16)(i + start_address), NULL, 0); + status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, + buffer[i], (u16)(i + start_address), NULL, + 0, TI_VSEND_TIMEOUT_DEFAULT); if (status) return status; } @@ -421,10 +426,9 @@ static int write_i2c_mem(struct edgeport_serial *serial, * regardless of host byte order. */ be_start_address = swab16((u16)start_address); - status = ti_vsend_sync(serial->serial->dev, - UMPC_MEMORY_WRITE, (__u16)address_type, - be_start_address, - buffer, write_length); + status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, + (u16)address_type, be_start_address, + buffer, write_length, TI_VSEND_TIMEOUT_DEFAULT); if (status) { dev_dbg(dev, "%s - ERROR %d\n", __func__, status); return status; @@ -454,9 +458,8 @@ static int write_i2c_mem(struct edgeport_serial *serial, */ be_start_address = swab16((u16)start_address); status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, - (__u16)address_type, - be_start_address, - buffer, write_length); + (u16)address_type, be_start_address, buffer, + write_length, TI_VSEND_TIMEOUT_DEFAULT); if (status) { dev_err(dev, "%s - ERROR %d\n", __func__, status); return status; @@ -1129,7 +1132,8 @@ static int download_fw(struct edgeport_serial *serial) /* Reset UMP -- Back to BOOT MODE */ status = ti_vsend_sync(serial->serial->dev, UMPC_HARDWARE_RESET, - 0, 0, NULL, 0); + 0, 0, NULL, 0, + TI_VSEND_TIMEOUT_DEFAULT); dev_dbg(dev, "%s - HARDWARE RESET return %d\n", __func__, status); @@ -1229,7 +1233,9 @@ static int download_fw(struct edgeport_serial *serial) /* Tell firmware to copy download image into I2C */ status = ti_vsend_sync(serial->serial->dev, - UMPC_COPY_DNLD_TO_I2C, 0, 0, NULL, 0); + UMPC_COPY_DNLD_TO_I2C, + 0, 0, NULL, 0, + TI_VSEND_TIMEOUT_FW_DOWNLOAD); dev_dbg(dev, "%s - Update complete 0x%x\n", __func__, status); if (status) { -- cgit v1.3-6-gb490 From c0e34831c8d9d8bf24f7bc9e12663e3daf1646ef Mon Sep 17 00:00:00 2001 From: "Peter E. Berger" Date: Fri, 31 Jul 2015 01:55:06 -0500 Subject: USB: io_ti: Fix firmware version handling The io_ti driver fails to download firmware to Edgeport devices such as the EP/416, even when the on-disk firmware image (/lib/firmware/edgeport/down3.bin) is more current than the version on the EP/416. The current download code is broken in a few ways. Notably it mis-uses global variables OperationalMajorVersion and OperationalMinorVersion (reading their values before they've been properly initialized and subsequently initializing them multiple times without synchronization). This patch drops the global variables and replaces the redundant calls to request_firmware()/release_firmware() in download_fw() with a single call pair in edge_startup(); the firmware image pointer is then passed to download_fw() and build_i2c_fw_hdr(). Signed-off-by: Peter E. Berger Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 114 ++++++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 69378a7ee342..b562665e9fb1 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -71,6 +71,25 @@ struct product_info { __u8 hardware_type; /* Type of hardware */ } __attribute__((packed)); +/* + * Edgeport firmware header + * + * "build_number" has been set to 0 in all three of the images I have + * seen, and Digi Tech Support suggests that it is safe to ignore it. + * + * "length" is the number of bytes of actual data following the header. + * + * "checksum" is the low order byte resulting from adding the values of + * all the data bytes. + */ +struct edgeport_fw_hdr { + u8 major_version; + u8 minor_version; + __le16 build_number; + __le16 length; + u8 checksum; +} __packed; + struct edgeport_port { __u16 uart_base; __u16 dma_address; @@ -101,6 +120,7 @@ struct edgeport_serial { struct mutex es_lock; int num_ports_open; struct usb_serial *serial; + int fw_version; }; @@ -187,10 +207,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static unsigned char OperationalMajorVersion; -static unsigned char OperationalMinorVersion; -static unsigned short OperationalBuildNumber; - static int closing_wait = EDGE_CLOSING_WAIT; static bool ignore_cpu_rev; static int default_uart_mode; /* RS232 */ @@ -751,18 +767,17 @@ exit: } /* Build firmware header used for firmware update */ -static int build_i2c_fw_hdr(__u8 *header, struct device *dev) +static int build_i2c_fw_hdr(u8 *header, struct device *dev, + const struct firmware *fw) { __u8 *buffer; int buffer_size; int i; - int err; __u8 cs = 0; struct ti_i2c_desc *i2c_header; struct ti_i2c_image_header *img_header; struct ti_i2c_firmware_rec *firmware_rec; - const struct firmware *fw; - const char *fw_name = "edgeport/down3.bin"; + struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; /* In order to update the I2C firmware we must change the type 2 record * to type 0xF2. This will force the UMP to come up in Boot Mode. @@ -785,24 +800,11 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) // Set entire image of 0xffs memset(buffer, 0xff, buffer_size); - err = request_firmware(&fw, fw_name, dev); - if (err) { - dev_err(dev, "Failed to load image \"%s\" err %d\n", - fw_name, err); - kfree(buffer); - return err; - } - - /* Save Download Version Number */ - OperationalMajorVersion = fw->data[0]; - OperationalMinorVersion = fw->data[1]; - OperationalBuildNumber = fw->data[2] | (fw->data[3] << 8); - /* Copy version number into firmware record */ firmware_rec = (struct ti_i2c_firmware_rec *)buffer; - firmware_rec->Ver_Major = OperationalMajorVersion; - firmware_rec->Ver_Minor = OperationalMinorVersion; + firmware_rec->Ver_Major = fw_hdr->major_version; + firmware_rec->Ver_Minor = fw_hdr->minor_version; /* Pointer to fw_down memory image */ img_header = (struct ti_i2c_image_header *)&fw->data[4]; @@ -811,8 +813,6 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) &fw->data[4 + sizeof(struct ti_i2c_image_header)], le16_to_cpu(img_header->Length)); - release_firmware(fw); - for (i=0; i < buffer_size; i++) { cs = (__u8)(cs + buffer[i]); } @@ -826,8 +826,8 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev) i2c_header->Type = I2C_DESC_TYPE_FIRMWARE_BLANK; i2c_header->Size = cpu_to_le16(buffer_size); i2c_header->CheckSum = cs; - firmware_rec->Ver_Major = OperationalMajorVersion; - firmware_rec->Ver_Minor = OperationalMinorVersion; + firmware_rec->Ver_Major = fw_hdr->major_version; + firmware_rec->Ver_Minor = fw_hdr->minor_version; return 0; } @@ -934,7 +934,8 @@ static int ti_cpu_rev(struct edge_ti_manuf_descriptor *desc) * This routine downloads the main operating code into the TI5052, using the * boot code already burned into E2PROM or ROM. */ -static int download_fw(struct edgeport_serial *serial) +static int download_fw(struct edgeport_serial *serial, + const struct firmware *fw) { struct device *dev = &serial->serial->dev->dev; int status = 0; @@ -943,6 +944,17 @@ static int download_fw(struct edgeport_serial *serial) struct usb_interface_descriptor *interface; int download_cur_ver; int download_new_ver; + struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; + + if (fw->size < sizeof(struct edgeport_fw_hdr)) { + dev_err(&serial->serial->interface->dev, + "Incomplete firmware header.\n"); + return -EINVAL; + } + + /* If on-board version is newer, "fw_version" will be updated below. */ + serial->fw_version = (fw_hdr->major_version << 8) + + fw_hdr->minor_version; /* This routine is entered by both the BOOT mode and the Download mode * We can determine which code is running by the reading the config @@ -1050,14 +1062,13 @@ static int download_fw(struct edgeport_serial *serial) version in I2c */ download_cur_ver = (firmware_version->Ver_Major << 8) + (firmware_version->Ver_Minor); - download_new_ver = (OperationalMajorVersion << 8) + - (OperationalMinorVersion); + download_new_ver = (fw_hdr->major_version << 8) + + (fw_hdr->minor_version); dev_dbg(dev, "%s - >> FW Versions Device %d.%d Driver %d.%d\n", __func__, firmware_version->Ver_Major, firmware_version->Ver_Minor, - OperationalMajorVersion, - OperationalMinorVersion); + fw_hdr->major_version, fw_hdr->minor_version); /* Check if we have an old version in the I2C and update if necessary */ @@ -1066,8 +1077,8 @@ static int download_fw(struct edgeport_serial *serial) __func__, firmware_version->Ver_Major, firmware_version->Ver_Minor, - OperationalMajorVersion, - OperationalMinorVersion); + fw_hdr->major_version, + fw_hdr->minor_version); record = kmalloc(1, GFP_KERNEL); if (!record) { @@ -1143,6 +1154,9 @@ static int download_fw(struct edgeport_serial *serial) kfree(rom_desc); kfree(ti_manuf_desc); return -ENODEV; + } else { + /* Same or newer fw version is already loaded */ + serial->fw_version = download_cur_ver; } kfree(firmware_version); } @@ -1181,7 +1195,7 @@ static int download_fw(struct edgeport_serial *serial) * UMP Ram to I2C and the firmware will update the * record type from 0xf2 to 0x02. */ - status = build_i2c_fw_hdr(header, dev); + status = build_i2c_fw_hdr(header, dev, fw); if (status) { kfree(vheader); kfree(header); @@ -1284,9 +1298,6 @@ static int download_fw(struct edgeport_serial *serial) __u8 cs = 0; __u8 *buffer; int buffer_size; - int err; - const struct firmware *fw; - const char *fw_name = "edgeport/down3.bin"; /* Validate Hardware version number * Read Manufacturing Descriptor from TI Based Edgeport @@ -1334,16 +1345,7 @@ static int download_fw(struct edgeport_serial *serial) /* Initialize the buffer to 0xff (pad the buffer) */ memset(buffer, 0xff, buffer_size); - - err = request_firmware(&fw, fw_name, dev); - if (err) { - dev_err(dev, "Failed to load image \"%s\" err %d\n", - fw_name, err); - kfree(buffer); - return err; - } memcpy(buffer, &fw->data[4], fw->size - 4); - release_firmware(fw); for (i = sizeof(struct ti_i2c_image_header); i < buffer_size; i++) { @@ -1358,7 +1360,9 @@ static int download_fw(struct edgeport_serial *serial) header->CheckSum = cs; /* Download the operational code */ - dev_dbg(dev, "%s - Downloading operational code image (TI UMP)\n", __func__); + dev_dbg(dev, "%s - Downloading operational code image version %d.%d (TI UMP)\n", + __func__, + fw_hdr->major_version, fw_hdr->minor_version); status = download_code(serial, buffer, buffer_size); kfree(buffer); @@ -2383,6 +2387,9 @@ static int edge_startup(struct usb_serial *serial) { struct edgeport_serial *edge_serial; int status; + const struct firmware *fw; + const char *fw_name = "edgeport/down3.bin"; + struct device *dev = &serial->interface->dev; /* create our private serial structure */ edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); @@ -2393,7 +2400,16 @@ static int edge_startup(struct usb_serial *serial) edge_serial->serial = serial; usb_set_serial_data(serial, edge_serial); - status = download_fw(edge_serial); + status = request_firmware(&fw, fw_name, dev); + if (status) { + dev_err(dev, "Failed to load image \"%s\" err %d\n", + fw_name, status); + kfree(edge_serial); + return status; + } + + status = download_fw(edge_serial, fw); + release_firmware(fw); if (status) { kfree(edge_serial); return status; -- cgit v1.3-6-gb490 From dcb8e99dbc8a8a7825e39a43e79558d46b20d1e5 Mon Sep 17 00:00:00 2001 From: "Peter E. Berger" Date: Fri, 31 Jul 2015 01:55:07 -0500 Subject: USB: io_ti: Add firmware image sanity checks Do what we can to verify that the driver's firmware image is valid (before attempting to download it to the Edgeport) by adding a new function, check_fw_sanity(), and a call to it in in download_fw(). Note: It looks like some Edgeports (models like the EP/416 with on-board E2PROM) may be able to function even if the on-disk firmware image is bad or missing, iff their local E2PROM versions are valid. But most Edgeport models (I've tried EP/1 and EP/8) do not appear to have this capability and they always rely on the on-disk firmware image. I tested an implementation that calls the new check_fw_sanity() function at the top of download_fw() and, rather than simply returning an error if the firmware image is bad or missing, it saves the result and defers the decision until later when it may find that it is running on a E2PROM-equipped device with a valid image. But I think this is messier than it is worth (adding still more messiness to the already very messy download_fw()) for such a marginal possible benefit. So, at least for now, I have chosen the much simpler approach of returning an error whenever edge_startup() fails to load an on-disk firmware image, or check_fw_sanity() indicates that it is unusable. Signed-off-by: Peter E. Berger [johan: drop redundant checksum mask ] Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index b562665e9fb1..422423671ee4 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -928,6 +928,41 @@ static int ti_cpu_rev(struct edge_ti_manuf_descriptor *desc) return TI_GET_CPU_REVISION(desc->CpuRev_BoardRev); } +static int check_fw_sanity(struct edgeport_serial *serial, + const struct firmware *fw) +{ + u16 length_total; + u8 checksum = 0; + int pos; + struct device *dev = &serial->serial->interface->dev; + struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; + + if (fw->size < sizeof(struct edgeport_fw_hdr)) { + dev_err(dev, "incomplete fw header\n"); + return -EINVAL; + } + + length_total = le16_to_cpu(fw_hdr->length) + + sizeof(struct edgeport_fw_hdr); + + if (fw->size != length_total) { + dev_err(dev, "bad fw size (expected: %u, got: %zu)\n", + length_total, fw->size); + return -EINVAL; + } + + for (pos = sizeof(struct edgeport_fw_hdr); pos < fw->size; ++pos) + checksum += fw->data[pos]; + + if (checksum != fw_hdr->checksum) { + dev_err(dev, "bad fw checksum (expected: 0x%x, got: 0x%x)\n", + fw_hdr->checksum, checksum); + return -EINVAL; + } + + return 0; +} + /** * DownloadTIFirmware - Download run-time operating firmware to the TI5052 * @@ -946,11 +981,8 @@ static int download_fw(struct edgeport_serial *serial, int download_new_ver; struct edgeport_fw_hdr *fw_hdr = (struct edgeport_fw_hdr *)fw->data; - if (fw->size < sizeof(struct edgeport_fw_hdr)) { - dev_err(&serial->serial->interface->dev, - "Incomplete firmware header.\n"); + if (check_fw_sanity(serial, fw)) return -EINVAL; - } /* If on-board version is newer, "fw_version" will be updated below. */ serial->fw_version = (fw_hdr->major_version << 8) + -- cgit v1.3-6-gb490 From 26c78daade0fbeef7f20bae3c5508a7c571078cd Mon Sep 17 00:00:00 2001 From: "Peter E. Berger" Date: Fri, 31 Jul 2015 01:55:08 -0500 Subject: USB: io_ti: Add heartbeat to keep idle EP/416 ports from disconnecting When using Edgeport/416 models with newer firmware (sometime after firmware version 4.80.0), idle ports are automatically bounced (disconnected and then reconnected) approximately every 60 seconds. This breaks programs (e.g: minicom) where idle periods are common, normal and expected. I confirmed with the manufacturer (Digi International) that Edgeport/416 models now ship from the factory with firmware that expects periodic "heartbeat" queries from the driver to keep idle ports alive. This patch implements heartbeat support using the mechanism Digi suggested (periodically requesting an I2C descriptor address) that appears effective on Edgeports running the newer firmware (that require it) and benign on Edgeport devices running older firmware. Since we know that Edgeport firmware version 4.80 (the version distributed in /lib/firmware/down3.bin and used for Edgeports that are either running still older versions or have no onboard non-volatile firmware image) does not require heartbeat support, this patch schedules heartbeats only on Edgeport/416 devices, and only if they are running firmware versions newer than 4.80. Signed-off-by: Peter E. Berger [johan: minor style changes ] Signed-off-by: Johan Hovold --- drivers/usb/serial/io_ti.c | 95 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 422423671ee4..0ac1b10be1f7 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -120,7 +120,9 @@ struct edgeport_serial { struct mutex es_lock; int num_ports_open; struct usb_serial *serial; + struct delayed_work heartbeat_work; int fw_version; + bool use_heartbeat; }; @@ -225,6 +227,22 @@ static void edge_send(struct usb_serial_port *port, struct tty_struct *tty); static int edge_create_sysfs_attrs(struct usb_serial_port *port); static int edge_remove_sysfs_attrs(struct usb_serial_port *port); +/* + * Some release of Edgeport firmware "down3.bin" after version 4.80 + * introduced code to automatically disconnect idle devices on some + * Edgeport models after periods of inactivity, typically ~60 seconds. + * This occurs without regard to whether ports on the device are open + * or not. Digi International Tech Support suggested: + * + * 1. Adding driver "heartbeat" code to reset the firmware timer by + * requesting a descriptor record every 15 seconds, which should be + * effective with newer firmware versions that require it, and benign + * with older versions that do not. In practice 40 seconds seems often + * enough. + * 2. The heartbeat code is currently required only on Edgeport/416 models. + */ +#define FW_HEARTBEAT_VERSION_CUTOFF ((4 << 8) + 80) +#define FW_HEARTBEAT_SECS 40 /* Timeouts in msecs: firmware downloads take longer */ #define TI_VSEND_TIMEOUT_DEFAULT 1000 @@ -2415,6 +2433,36 @@ static void edge_break(struct tty_struct *tty, int break_state) __func__, status); } +static void edge_heartbeat_schedule(struct edgeport_serial *edge_serial) +{ + if (!edge_serial->use_heartbeat) + return; + + schedule_delayed_work(&edge_serial->heartbeat_work, + FW_HEARTBEAT_SECS * HZ); +} + +static void edge_heartbeat_work(struct work_struct *work) +{ + struct edgeport_serial *serial; + struct ti_i2c_desc *rom_desc; + + serial = container_of(work, struct edgeport_serial, + heartbeat_work.work); + + rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); + + /* Descriptor address request is enough to reset the firmware timer */ + if (!rom_desc || !get_descriptor_addr(serial, I2C_DESC_TYPE_ION, + rom_desc)) { + dev_err(&serial->serial->interface->dev, + "%s - Incomplete heartbeat\n", __func__); + } + kfree(rom_desc); + + edge_heartbeat_schedule(serial); +} + static int edge_startup(struct usb_serial *serial) { struct edgeport_serial *edge_serial; @@ -2422,6 +2470,7 @@ static int edge_startup(struct usb_serial *serial) const struct firmware *fw; const char *fw_name = "edgeport/down3.bin"; struct device *dev = &serial->interface->dev; + u16 product_id; /* create our private serial structure */ edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); @@ -2447,6 +2496,20 @@ static int edge_startup(struct usb_serial *serial) return status; } + product_id = le16_to_cpu( + edge_serial->serial->dev->descriptor.idProduct); + + /* Currently only the EP/416 models require heartbeat support */ + if (edge_serial->fw_version > FW_HEARTBEAT_VERSION_CUTOFF) { + if (product_id == ION_DEVICE_ID_TI_EDGEPORT_416 || + product_id == ION_DEVICE_ID_TI_EDGEPORT_416B) { + edge_serial->use_heartbeat = true; + } + } + + INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work); + edge_heartbeat_schedule(edge_serial); + return 0; } @@ -2456,7 +2519,10 @@ static void edge_disconnect(struct usb_serial *serial) static void edge_release(struct usb_serial *serial) { - kfree(usb_get_serial_data(serial)); + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + + cancel_delayed_work_sync(&edge_serial->heartbeat_work); + kfree(edge_serial); } static int edge_port_probe(struct usb_serial_port *port) @@ -2560,6 +2626,25 @@ static int edge_remove_sysfs_attrs(struct usb_serial_port *port) return 0; } +#ifdef CONFIG_PM +static int edge_suspend(struct usb_serial *serial, pm_message_t message) +{ + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + + cancel_delayed_work_sync(&edge_serial->heartbeat_work); + + return 0; +} + +static int edge_resume(struct usb_serial *serial) +{ + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + + edge_heartbeat_schedule(edge_serial); + + return 0; +} +#endif static struct usb_serial_driver edgeport_1port_device = { .driver = { @@ -2592,6 +2677,10 @@ static struct usb_serial_driver edgeport_1port_device = { .read_int_callback = edge_interrupt_callback, .read_bulk_callback = edge_bulk_in_callback, .write_bulk_callback = edge_bulk_out_callback, +#ifdef CONFIG_PM + .suspend = edge_suspend, + .resume = edge_resume, +#endif }; static struct usb_serial_driver edgeport_2port_device = { @@ -2625,6 +2714,10 @@ static struct usb_serial_driver edgeport_2port_device = { .read_int_callback = edge_interrupt_callback, .read_bulk_callback = edge_bulk_in_callback, .write_bulk_callback = edge_bulk_out_callback, +#ifdef CONFIG_PM + .suspend = edge_suspend, + .resume = edge_resume, +#endif }; static struct usb_serial_driver * const serial_drivers[] = { -- cgit v1.3-6-gb490 From ccd6385dfbb7b2f2e6670b5cfc55bb7ec0aa3839 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 15 Jul 2015 11:55:18 +0100 Subject: iommu/arm-smmu: Fix enabling of PRIQ interrupt When an ARM SMMUv3 instance supports PRI, the driver registers an interrupt handler, but fails to enable the generation of such interrupt at the SMMU level. This patches simply moves the enable flags to a variable that gets updated by the PRI handling code before being written to the SMMU register. Signed-off-by: Marc Zyngier Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index da902baaa794..5d2cbdab5afa 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -118,6 +118,7 @@ #define ARM_SMMU_IRQ_CTRL 0x50 #define IRQ_CTRL_EVTQ_IRQEN (1 << 2) +#define IRQ_CTRL_PRIQ_IRQEN (1 << 1) #define IRQ_CTRL_GERROR_IRQEN (1 << 0) #define ARM_SMMU_IRQ_CTRLACK 0x54 @@ -2198,6 +2199,7 @@ static int arm_smmu_write_reg_sync(struct arm_smmu_device *smmu, u32 val, static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu) { int ret, irq; + u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN; /* Disable IRQs first */ ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_IRQ_CTRL, @@ -2252,13 +2254,13 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu) if (IS_ERR_VALUE(ret)) dev_warn(smmu->dev, "failed to enable priq irq\n"); + else + irqen_flags |= IRQ_CTRL_PRIQ_IRQEN; } } /* Enable interrupt generation on the SMMU */ - ret = arm_smmu_write_reg_sync(smmu, - IRQ_CTRL_EVTQ_IRQEN | - IRQ_CTRL_GERROR_IRQEN, + ret = arm_smmu_write_reg_sync(smmu, irqen_flags, ARM_SMMU_IRQ_CTRL, ARM_SMMU_IRQ_CTRLACK); if (ret) dev_warn(smmu->dev, "failed to enable irqs\n"); -- cgit v1.3-6-gb490 From ec11d63c677bbba15e65a35f5ba06c1d6eba4dbe Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 15 Jul 2015 11:55:19 +0100 Subject: iommu/arm-smmu: Fix MSI memory attributes to match specification The MSI memory attributes in the SMMUv3 driver are from an older revision of the spec, which doesn't match the current implementations. Out with the old, in with the new. Signed-off-by: Marc Zyngier Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 5d2cbdab5afa..c2c1ad8915d9 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -174,14 +174,14 @@ #define ARM_SMMU_PRIQ_IRQ_CFG2 0xdc /* Common MSI config fields */ -#define MSI_CFG0_SH_SHIFT 60 -#define MSI_CFG0_SH_NSH (0UL << MSI_CFG0_SH_SHIFT) -#define MSI_CFG0_SH_OSH (2UL << MSI_CFG0_SH_SHIFT) -#define MSI_CFG0_SH_ISH (3UL << MSI_CFG0_SH_SHIFT) -#define MSI_CFG0_MEMATTR_SHIFT 56 -#define MSI_CFG0_MEMATTR_DEVICE_nGnRE (0x1 << MSI_CFG0_MEMATTR_SHIFT) #define MSI_CFG0_ADDR_SHIFT 2 #define MSI_CFG0_ADDR_MASK 0x3fffffffffffUL +#define MSI_CFG2_SH_SHIFT 4 +#define MSI_CFG2_SH_NSH (0UL << MSI_CFG2_SH_SHIFT) +#define MSI_CFG2_SH_OSH (2UL << MSI_CFG2_SH_SHIFT) +#define MSI_CFG2_SH_ISH (3UL << MSI_CFG2_SH_SHIFT) +#define MSI_CFG2_MEMATTR_SHIFT 0 +#define MSI_CFG2_MEMATTR_DEVICE_nGnRE (0x1 << MSI_CFG2_MEMATTR_SHIFT) #define Q_IDX(q, p) ((p) & ((1 << (q)->max_n_shift) - 1)) #define Q_WRP(q, p) ((p) & (1 << (q)->max_n_shift)) -- cgit v1.3-6-gb490 From 28c8b4045b18b013e05656b493ce9a57cbf1f09a Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 16 Jul 2015 17:50:12 +0100 Subject: iommu/arm-smmu: Limit 2-level strtab allocation for small SID sizes If the StreamIDs in a system can all be resolved by a single level-2 stream table (i.e. SIDSIZE < SPLIT), then we currently get our maths wrong and allocate the largest strtab we support, thanks to unsigned overflow in our calculation. This patch fixes the issue by checking the SIDSIZE explicitly when calculating the size of our first-level stream table. Reported-by: Matt Evans Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index c2c1ad8915d9..4f093373f4c3 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -2054,9 +2054,17 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu) int ret; struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; - /* Calculate the L1 size, capped to the SIDSIZE */ - size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3); - size = min(size, smmu->sid_bits - STRTAB_SPLIT); + /* + * If we can resolve everything with a single L2 table, then we + * just need a single L1 descriptor. Otherwise, calculate the L1 + * size, capped to the SIDSIZE. + */ + if (smmu->sid_bits < STRTAB_SPLIT) { + size = 0; + } else { + size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3); + size = min(size, smmu->sid_bits - STRTAB_SPLIT); + } cfg->num_l1_ents = 1 << size; size += STRTAB_SPLIT; -- cgit v1.3-6-gb490 From bae2c2d421cdea9dd8d62425eef99e389584cdb3 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 29 Jul 2015 19:46:05 +0100 Subject: iommu/arm-smmu: Sort out coherency Currently, we detect whether the SMMU has coherent page table walk capability from the IDR0.CTTW field, and base our cache maintenance decisions on that. In preparation for fixing the bogus DMA API usage, however, we need to ensure that the DMA API agrees about this, which necessitates deferring to the dma-coherent property in the device tree for the final say. As an added bonus, since systems exist where an external CTTW signal has been tied off incorrectly at integration, allowing DT to override it offers a neat workaround for coherency issues with such SMMUs. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- Documentation/devicetree/bindings/iommu/arm,smmu.txt | 6 ++++++ drivers/iommu/arm-smmu.c | 20 +++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 06760503a819..718074501fcb 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -43,6 +43,12 @@ conditions. ** System MMU optional properties: +- dma-coherent : Present if page table walks made by the SMMU are + cache coherent with the CPU. + + NOTE: this only applies to the SMMU itself, not + masters connected upstream of the SMMU. + - calxeda,smmu-secure-config-access : Enable proper handling of buggy implementations that always use secure access to SMMU configuration registers. In this case non-secure diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 4cd0c29cb585..0583ed2f33c0 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1532,6 +1533,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) unsigned long size; void __iomem *gr0_base = ARM_SMMU_GR0(smmu); u32 id; + bool cttw_dt, cttw_reg; dev_notice(smmu->dev, "probing hardware configuration...\n"); dev_notice(smmu->dev, "SMMUv%d with:\n", smmu->version); @@ -1571,10 +1573,22 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) dev_notice(smmu->dev, "\taddress translation ops\n"); } - if (id & ID0_CTTW) { + /* + * In order for DMA API calls to work properly, we must defer to what + * the DT says about coherency, regardless of what the hardware claims. + * Fortunately, this also opens up a workaround for systems where the + * ID register value has ended up configured incorrectly. + */ + cttw_dt = of_dma_is_coherent(smmu->dev->of_node); + cttw_reg = !!(id & ID0_CTTW); + if (cttw_dt) smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK; - dev_notice(smmu->dev, "\tcoherent table walk\n"); - } + if (cttw_dt || cttw_reg) + dev_notice(smmu->dev, "\t%scoherent table walk\n", + cttw_dt ? "" : "non-"); + if (cttw_dt != cttw_reg) + dev_notice(smmu->dev, + "\t(IDR0.CTTW overridden by dma-coherent property)\n"); if (id & ID0_SMS) { u32 smr, sid, mask; -- cgit v1.3-6-gb490 From ba3e127ec105e790eeec4034d9769e018e4a1b54 Mon Sep 17 00:00:00 2001 From: Brian Gerst Date: Wed, 29 Jul 2015 01:41:21 -0400 Subject: x86/vm86: Clean up vm86.h includes vm86.h was being implicitly included in alot of places via processor.h, which in turn got it from math_emu.h. Break that chain and explicitly include vm86.h in all files that need it. Also remove unused vm86 field from math_emu_info. Signed-off-by: Brian Gerst Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1438148483-11932-7-git-send-email-brgerst@gmail.com [ Fixed build failure. ] Signed-off-by: Ingo Molnar --- arch/x86/include/asm/math_emu.h | 6 +----- arch/x86/include/asm/syscalls.h | 1 + arch/x86/kernel/process_32.c | 1 + arch/x86/kernel/signal.c | 1 + arch/x86/kernel/traps.c | 1 + arch/x86/kernel/vm86_32.c | 1 + arch/x86/math-emu/get_address.c | 1 + arch/x86/mm/fault.c | 1 + drivers/scsi/dpt_i2o.c | 3 +++ 9 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/arch/x86/include/asm/math_emu.h b/arch/x86/include/asm/math_emu.h index 031f6266f425..0d9b14f60d2c 100644 --- a/arch/x86/include/asm/math_emu.h +++ b/arch/x86/include/asm/math_emu.h @@ -2,7 +2,6 @@ #define _ASM_X86_MATH_EMU_H #include -#include /* This structure matches the layout of the data saved to the stack following a device-not-present interrupt, part of it saved @@ -10,9 +9,6 @@ */ struct math_emu_info { long ___orig_eip; - union { - struct pt_regs *regs; - struct kernel_vm86_regs *vm86; - }; + struct pt_regs *regs; }; #endif /* _ASM_X86_MATH_EMU_H */ diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h index 592a6a672e07..91dfcafe27a6 100644 --- a/arch/x86/include/asm/syscalls.h +++ b/arch/x86/include/asm/syscalls.h @@ -37,6 +37,7 @@ asmlinkage long sys_get_thread_area(struct user_desc __user *); asmlinkage unsigned long sys_sigreturn(void); /* kernel/vm86_32.c */ +struct vm86_struct; asmlinkage long sys_vm86old(struct vm86_struct __user *); asmlinkage long sys_vm86(unsigned long, unsigned long); diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index f73c962fe636..c13df2c735f8 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -53,6 +53,7 @@ #include #include #include +#include asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread"); diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index bfd736e80c89..07eb84407036 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef CONFIG_X86_64 #include diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 8e65d8a9b8db..86a82eafb96f 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -62,6 +62,7 @@ #include #include #include +#include #ifdef CONFIG_X86_64 #include diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index ffe98eceda77..0de1f66ad001 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -51,6 +51,7 @@ #include #include #include +#include /* * Known problems: diff --git a/arch/x86/math-emu/get_address.c b/arch/x86/math-emu/get_address.c index 6ef5e99380f9..a2eefb121a5f 100644 --- a/arch/x86/math-emu/get_address.c +++ b/arch/x86/math-emu/get_address.c @@ -21,6 +21,7 @@ #include #include +#include #include "fpu_system.h" #include "exception.h" diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 34a368d2d533..eef44d9a3f77 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -20,6 +20,7 @@ #include /* kmemcheck_*(), ... */ #include /* VSYSCALL_ADDR */ #include /* emulate_vsyscall */ +#include /* struct vm86 */ #define CREATE_TRACE_POINTS #include diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index f35ed53adaac..d4cda5e9600e 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -1924,6 +1924,9 @@ static void adpt_alpha_info(sysInfo_S* si) #endif #if defined __i386__ + +#include + static void adpt_i386_info(sysInfo_S* si) { // This is all the info we need for now -- cgit v1.3-6-gb490 From 55d811211b139ed097ddaf40d173c258f133c130 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 13 Jul 2015 11:03:50 +0200 Subject: usb: gadget: ffs: call functionfs_unbind() if _ffs_func_bind() fails Function ffs_do_functionfs_bind() calls functionfs_bind() which allocates usb request and increments refcounts. These things needs to be cleaned up by if further steps of initialization fail by calling functionfs_unbind(). Signed-off-by: Robert Baldyga Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 6e7be91e6097..adc6d52efa46 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2897,11 +2897,17 @@ static int ffs_func_bind(struct usb_configuration *c, struct usb_function *f) { struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c); + struct ffs_function *func = ffs_func_from_usb(f); + int ret; if (IS_ERR(ffs_opts)) return PTR_ERR(ffs_opts); - return _ffs_func_bind(c, f); + ret = _ffs_func_bind(c, f); + if (ret && !--ffs_opts->refcnt) + functionfs_unbind(func->ffs); + + return ret; } -- cgit v1.3-6-gb490 From 4ef7a4a1f097b2c17f4f2873a1595aa0aca9f6b4 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 13 Jul 2015 11:03:51 +0200 Subject: usb: gadget: midi: avoid redundant f_midi_set_alt() call Function midi registers two interfaces with single set_alt() function which means that f_midi_set_alt() is called twice when configuration is set. That means that endpoint initialization and ep request allocation is done two times. To avoid this problem we do such things only once, for interface number 1 (MIDI Streaming interface). Signed-off-by: Robert Baldyga Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_midi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index ad50a67c1465..a287a4829273 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -329,6 +329,10 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) unsigned i; int err; + /* For Control Device interface we do nothing */ + if (intf == 0) + return 0; + err = f_midi_start_ep(midi, f, midi->in_ep); if (err) return err; -- cgit v1.3-6-gb490 From 6fd82b69796cc8f313f160ac55bfd24cedc60fed Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 13 Jul 2015 11:03:52 +0200 Subject: usb: isp1760: udc: add missing usb_ep_set_maxpacket_limit() Since maxpacket_limit was introduced all UDC drivers should use usb_ep_set_maxpacket_limit() function instead of setting maxpacket value manually. ep.maxpacket_limit contains actual maximum maxpacket value supported by hardware which is needed by epautoconf. Signed-off-by: Robert Baldyga Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/isp1760/isp1760-udc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c index 18ebf5b1f256..3699962987b2 100644 --- a/drivers/usb/isp1760/isp1760-udc.c +++ b/drivers/usb/isp1760/isp1760-udc.c @@ -1382,11 +1382,11 @@ static void isp1760_udc_init_eps(struct isp1760_udc *udc) * This fits in the 8kB FIFO without double-buffering. */ if (ep_num == 0) { - ep->ep.maxpacket = 64; + usb_ep_set_maxpacket_limit(&ep->ep, 64); ep->maxpacket = 64; udc->gadget.ep0 = &ep->ep; } else { - ep->ep.maxpacket = 512; + usb_ep_set_maxpacket_limit(&ep->ep, 512); ep->maxpacket = 0; list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); } -- cgit v1.3-6-gb490 From cb009d6e0b800e3834cd5e306df90d84e08f9cf7 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 13 Jul 2015 11:03:53 +0200 Subject: staging: emxx_udc: add missing usb_ep_set_maxpacket_limit() Since maxpacket_limit was introduced all UDC drivers should use usb_ep_set_maxpacket_limit() function instead of setting maxpacket value manually. ep.maxpacket_limit contains actual maximum maxpacket value supported by hardware which is needed by epautoconf. Signed-off-by: Robert Baldyga Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/staging/emxx_udc/emxx_udc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c index 4178d96f94cf..3b7aa36b0486 100644 --- a/drivers/staging/emxx_udc/emxx_udc.c +++ b/drivers/staging/emxx_udc/emxx_udc.c @@ -3203,7 +3203,8 @@ static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc) ep->ep.name = gp_ep_name[i]; ep->ep.ops = &nbu2ss_ep_ops; - ep->ep.maxpacket = (i == 0 ? EP0_PACKETSIZE : EP_PACKETSIZE); + usb_ep_set_maxpacket_limit(&ep->ep, + i == 0 ? EP0_PACKETSIZE : EP_PACKETSIZE); list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); INIT_LIST_HEAD(&ep->queue); -- cgit v1.3-6-gb490 From 7674cba55ad66b2565f8abe8d081a6ea4269bfb6 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 13 Jul 2015 11:03:54 +0200 Subject: usb: gadget: atmel_usba_udc: add missing ret value check Add missing return value check. In case of error print debug message and return error code. Signed-off-by: Robert Baldyga Acked-by: Nicolas Ferre Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/atmel_usba_udc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 4095cce05e6a..37d414ec2d69 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1989,6 +1989,10 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc"); ret = of_property_read_string(pp, "name", &name); + if (ret) { + dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret); + goto err; + } ep->ep.name = name; ep->ep_regs = udc->regs + USBA_EPT_BASE(i); -- cgit v1.3-6-gb490 From 5542f58c95aef67bc9016855f7c0bd6117b43100 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Fri, 31 Jul 2015 13:37:45 +0200 Subject: usb: gadget: mass_storage: Fix freeing luns sysfs implementation Use device_is_registered() instad of sysfs flag to determine if we should free sysfs representation of particular LUN. sysfs flag in fsg common determines if luns attributes should be exposed using sysfs. This flag is used when creating and freeing luns. Unfortunately there is no guarantee that this flag will not be changed between creation and removal of particular LUN. Especially because of lun.0 which is created during allocating instance of function. This may lead to resource leak or NULL pointer dereference: [ 62.539925] Unable to handle kernel NULL pointer dereference at virtual address 00000044 [ 62.548014] pgd = ec994000 [ 62.550679] [00000044] *pgd=6d7be831, *pte=00000000, *ppte=00000000 [ 62.556933] Internal error: Oops: 17 [#1] PREEMPT SMP ARM [ 62.562310] Modules linked in: g_mass_storage(+) [ 62.566916] CPU: 2 PID: 613 Comm: insmod Not tainted 4.2.0-rc4-00077-ge29ee91-dirty #125 [ 62.574984] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 62.581061] task: eca56e80 ti: eca76000 task.ti: eca76000 [ 62.586450] PC is at kernfs_find_ns+0x8/0xe8 [ 62.590698] LR is at kernfs_find_and_get_ns+0x30/0x48 [ 62.595732] pc : [] lr : [] psr: 40010053 [ 62.595732] sp : eca77c40 ip : eca77c38 fp : 000008c1 [ 62.607187] r10: 00000001 r9 : c0082f38 r8 : ed41ce40 [ 62.612395] r7 : c05c1484 r6 : 00000000 r5 : 00000000 r4 : c0814488 [ 62.618904] r3 : 00000000 r2 : 00000000 r1 : c05c1484 r0 : 00000000 [ 62.625417] Flags: nZcv IRQs on FIQs off Mode SVC_32 ISA ARM Segment user [ 62.632620] Control: 10c5387d Table: 6c99404a DAC: 00000015 [ 62.638348] Process insmod (pid: 613, stack limit = 0xeca76210) [ 62.644251] Stack: (0xeca77c40 to 0xeca78000) [ 62.648594] 7c40: c0814488 00000000 00000000 c05c1484 ed41ce40 c0127b88 00000000 c0824888 [ 62.656753] 7c60: ed41d038 ed41d030 ed41d000 c012af4c 00000000 c0824858 ed41d038 c02e3314 [ 62.664912] 7c80: ed41d030 00000000 ed41ce04 c02d9e8c c070eda8 eca77cb4 000008c1 c058317c [ 62.673071] 7ca0: 000008c1 ed41d030 ed41ce00 ed41ce04 ed41d000 c02da044 ed41cf48 c0375870 [ 62.681230] 7cc0: ed9d3c04 ed9d3c00 ed52df80 bf000940 fffffff0 c03758f4 c03758c0 00000000 [ 62.689389] 7ce0: bf000564 c03614e0 ed9d3c04 bf000194 c0082f38 00000001 00000000 c0000100 [ 62.697548] 7d00: c0814488 c0814488 c086b1dc c05893a8 00000000 ed7e8320 00000000 c0128b88 [ 62.705707] 7d20: ed8a6b40 00000000 00000000 ed410500 ed8a6b40 c0594818 ed7e8320 00000000 [ 62.713867] 7d40: 00000000 c0129f20 00000000 c082c444 ed8a6b40 c012a684 00001000 00000000 [ 62.722026] 7d60: c0594818 c082c444 00000000 00000000 ed52df80 ed52df80 00000000 00000000 [ 62.730185] 7d80: 00000000 00000000 00000001 00000002 ed8e9b70 ed52df80 bf0006d0 00000000 [ 62.738345] 7da0: ed8e9b70 ed410500 ed618340 c036129c ed8c1c00 bf0006d0 c080b158 ed8c1c00 [ 62.746504] 7dc0: bf0006d0 c080b158 ed8c1c08 ed410500 c0082f38 ed618340 000008c1 c03640ac [ 62.754663] 7de0: 00000000 bf0006d0 c082c8dc c080b158 c080b158 c03642d4 00000000 bf003000 [ 62.762822] 7e00: 00000000 c0009784 00000000 00000001 00000000 c05849b0 00000002 ee7ab780 [ 62.770981] 7e20: 00000002 ed4105c0 0000c53e 000000d0 c0808600 eca77e5c 00000004 00000000 [ 62.779140] 7e40: bf000000 c0095680 c08075a0 ee001f00 ed4105c0 c00cadc0 ed52df80 bf000780 [ 62.787300] 7e60: ed4105c0 bf000780 00000001 bf0007c8 c0082f38 ed618340 000008c1 c0083e24 [ 62.795459] 7e80: 00000001 bf000780 00000001 eca77f58 00000001 bf000780 00000001 c00857f4 [ 62.803618] 7ea0: bf00078c 00007fff 00000000 c00835b4 eca77f58 00000000 c0082fac eca77f58 [ 62.811777] 7ec0: f05038c0 0003b008 bf000904 00000000 00000000 bf00078c 6e72656b 00006c65 [ 62.819936] 7ee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 62.828095] 7f00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 62.836255] 7f20: 00000000 00000000 00000000 00000000 00000000 00000000 00000003 0003b008 [ 62.844414] 7f40: 0000017b c000f5c8 eca76000 00000000 0003b008 c0085df8 f04ef000 0001b8a9 [ 62.852573] 7f60: f0503258 f05030c2 f0509fe8 00000968 00000dc8 00000000 00000000 00000000 [ 62.860732] 7f80: 00000029 0000002a 00000011 00000000 0000000a 00000000 33f6eb00 0003b008 [ 62.868892] 7fa0: bef01cac c000f400 33f6eb00 0003b008 00000003 0003b008 00000000 00000003 [ 62.877051] 7fc0: 33f6eb00 0003b008 bef01cac 0000017b 00000000 0003b008 0000000b 0003b008 [ 62.885210] 7fe0: bef01ae0 bef01ad0 0001dc23 b6e8c162 800b0070 00000003 c0c0c0c0 c0c0c0c0 [ 62.893380] [] (kernfs_find_ns) from [] (pm_qos_latency_tolerance_attr_group+0x0/0x10) [ 62.903005] Code: e28dd00c e8bd80f0 e92d41f0 e2923000 (e1d0e4b4) [ 62.909115] ---[ end trace 02fb4373ef095c7b ]--- Acked-by: Michal Nazarewicz Signed-off-by: Krzysztof Opasiak Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 12 ++++++------ drivers/usb/gadget/function/f_mass_storage.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index f94a8e2e9b60..9870913e34bf 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2742,9 +2742,9 @@ error_release: } EXPORT_SYMBOL_GPL(fsg_common_set_num_buffers); -void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs) +void fsg_common_remove_lun(struct fsg_lun *lun) { - if (sysfs) + if (device_is_registered(&lun->dev)) device_unregister(&lun->dev); fsg_lun_close(lun); kfree(lun); @@ -2757,7 +2757,7 @@ static void _fsg_common_remove_luns(struct fsg_common *common, int n) for (i = 0; i < n; ++i) if (common->luns[i]) { - fsg_common_remove_lun(common->luns[i], common->sysfs); + fsg_common_remove_lun(common->luns[i]); common->luns[i] = NULL; } } @@ -2950,7 +2950,7 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, return 0; error_lun: - if (common->sysfs) + if (device_is_registered(&lun->dev)) device_unregister(&lun->dev); fsg_lun_close(lun); common->luns[id] = NULL; @@ -3038,7 +3038,7 @@ static void fsg_common_release(struct kref *ref) if (!lun) continue; fsg_lun_close(lun); - if (common->sysfs) + if (device_is_registered(&lun->dev)) device_unregister(&lun->dev); kfree(lun); } @@ -3363,7 +3363,7 @@ static void fsg_lun_drop(struct config_group *group, struct config_item *item) unregister_gadget_item(gadget); } - fsg_common_remove_lun(lun_opts->lun, fsg_opts->common->sysfs); + fsg_common_remove_lun(lun_opts->lun); fsg_opts->common->luns[lun_opts->lun_id] = NULL; lun_opts->lun_id = 0; mutex_unlock(&fsg_opts->lock); diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h index b4866fcef30b..37bc94cbb7f3 100644 --- a/drivers/usb/gadget/function/f_mass_storage.h +++ b/drivers/usb/gadget/function/f_mass_storage.h @@ -137,7 +137,7 @@ void fsg_common_free_buffers(struct fsg_common *common); int fsg_common_set_cdev(struct fsg_common *common, struct usb_composite_dev *cdev, bool can_stall); -void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs); +void fsg_common_remove_lun(struct fsg_lun *lun); void fsg_common_remove_luns(struct fsg_common *common); -- cgit v1.3-6-gb490 From fa8ad7889d83bcf0a6cdbf6d3622f3ec019cde14 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 6 Jul 2015 12:23:53 +0100 Subject: arm: perf: factor arm_pmu core out to drivers To enable sharing of the arm_pmu code with arm64, this patch factors it out to drivers/perf/. A new drivers/perf directory is added for performance monitor drivers to live under. MAINTAINERS is updated accordingly. Files added previously without a corresponsing MAINTAINERS update (perf_regs.c, perf_callchain.c, and perf_event.h) are also added. Cc: Arnaldo Carvalho de Melo Cc: Greg Kroah-Hartman Cc: Ingo Molnar Cc: Linus Walleij Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Russell King Cc: Will Deacon Signed-off-by: Mark Rutland [will: augmented Kconfig help slightly] Signed-off-by: Will Deacon --- MAINTAINERS | 6 +- arch/arm/Kconfig | 8 +- arch/arm/include/asm/pmu.h | 154 ------ arch/arm/kernel/Makefile | 3 +- arch/arm/kernel/perf_event.c | 921 ------------------------------------ arch/arm/kernel/perf_event_v6.c | 2 +- arch/arm/kernel/perf_event_v7.c | 2 +- arch/arm/kernel/perf_event_xscale.c | 2 +- arch/arm/mach-ux500/cpu-db8500.c | 2 +- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/perf/Kconfig | 15 + drivers/perf/Makefile | 1 + drivers/perf/arm_pmu.c | 921 ++++++++++++++++++++++++++++++++++++ include/linux/perf/arm_pmu.h | 154 ++++++ 15 files changed, 1105 insertions(+), 1089 deletions(-) delete mode 100644 arch/arm/include/asm/pmu.h delete mode 100644 arch/arm/kernel/perf_event.c create mode 100644 drivers/perf/Kconfig create mode 100644 drivers/perf/Makefile create mode 100644 drivers/perf/arm_pmu.c create mode 100644 include/linux/perf/arm_pmu.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index fd6078443083..485c92ced47d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -799,11 +799,13 @@ F: arch/arm/include/asm/floppy.h ARM PMU PROFILING AND DEBUGGING M: Will Deacon S: Maintained -F: arch/arm/kernel/perf_event* +F: arch/arm/kernel/perf_* F: arch/arm/oprofile/common.c -F: arch/arm/include/asm/pmu.h F: arch/arm/kernel/hw_breakpoint.c F: arch/arm/include/asm/hw_breakpoint.h +F: arch/arm/include/asm/perf_event.h +F: drivers/perf/arm_pmu.c +F: include/linux/perf/arm_pmu.h ARM PORT M: Russell King diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1c5021002fe4..4f7bc3d4b186 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1701,12 +1701,8 @@ config HIGHPTE user-space 2nd level page tables to reside in high memory. config HW_PERF_EVENTS - bool "Enable hardware performance counter support for perf events" - depends on PERF_EVENTS - default y - help - Enable hardware performance counter support for perf events. If - disabled, perf events will use software events only. + def_bool y + depends on ARM_PMU config SYS_SUPPORTS_HUGETLBFS def_bool y diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h deleted file mode 100644 index 3fc87dfd77e6..000000000000 --- a/arch/arm/include/asm/pmu.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * linux/arch/arm/include/asm/pmu.h - * - * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles - * - * 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_PMU_H__ -#define __ARM_PMU_H__ - -#include -#include - -#include - -/* - * struct arm_pmu_platdata - ARM PMU platform data - * - * @handle_irq: an optional handler which will be called from the - * interrupt and passed the address of the low level handler, - * and can be used to implement any platform specific handling - * before or after calling it. - */ -struct arm_pmu_platdata { - irqreturn_t (*handle_irq)(int irq, void *dev, - irq_handler_t pmu_handler); -}; - -#ifdef CONFIG_HW_PERF_EVENTS - -/* - * The ARMv7 CPU PMU supports up to 32 event counters. - */ -#define ARMPMU_MAX_HWEVENTS 32 - -#define HW_OP_UNSUPPORTED 0xFFFF -#define C(_x) PERF_COUNT_HW_CACHE_##_x -#define CACHE_OP_UNSUPPORTED 0xFFFF - -#define PERF_MAP_ALL_UNSUPPORTED \ - [0 ... PERF_COUNT_HW_MAX - 1] = HW_OP_UNSUPPORTED - -#define PERF_CACHE_MAP_ALL_UNSUPPORTED \ -[0 ... C(MAX) - 1] = { \ - [0 ... C(OP_MAX) - 1] = { \ - [0 ... C(RESULT_MAX) - 1] = CACHE_OP_UNSUPPORTED, \ - }, \ -} - -/* The events for a given PMU register set. */ -struct pmu_hw_events { - /* - * The events that are active on the PMU for the given index. - */ - struct perf_event *events[ARMPMU_MAX_HWEVENTS]; - - /* - * A 1 bit for an index indicates that the counter is being used for - * an event. A 0 means that the counter can be used. - */ - DECLARE_BITMAP(used_mask, ARMPMU_MAX_HWEVENTS); - - /* - * Hardware lock to serialize accesses to PMU registers. Needed for the - * read/modify/write sequences. - */ - raw_spinlock_t pmu_lock; - - /* - * When using percpu IRQs, we need a percpu dev_id. Place it here as we - * already have to allocate this struct per cpu. - */ - struct arm_pmu *percpu_pmu; -}; - -struct arm_pmu { - struct pmu pmu; - cpumask_t active_irqs; - cpumask_t supported_cpus; - int *irq_affinity; - char *name; - irqreturn_t (*handle_irq)(int irq_num, void *dev); - void (*enable)(struct perf_event *event); - void (*disable)(struct perf_event *event); - int (*get_event_idx)(struct pmu_hw_events *hw_events, - struct perf_event *event); - void (*clear_event_idx)(struct pmu_hw_events *hw_events, - struct perf_event *event); - int (*set_event_filter)(struct hw_perf_event *evt, - struct perf_event_attr *attr); - u32 (*read_counter)(struct perf_event *event); - void (*write_counter)(struct perf_event *event, u32 val); - void (*start)(struct arm_pmu *); - void (*stop)(struct arm_pmu *); - void (*reset)(void *); - int (*request_irq)(struct arm_pmu *, irq_handler_t handler); - void (*free_irq)(struct arm_pmu *); - int (*map_event)(struct perf_event *event); - int num_events; - atomic_t active_events; - struct mutex reserve_mutex; - u64 max_period; - struct platform_device *plat_device; - struct pmu_hw_events __percpu *hw_events; - struct notifier_block hotplug_nb; -}; - -#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) - -int armpmu_register(struct arm_pmu *armpmu, int type); - -u64 armpmu_event_update(struct perf_event *event); - -int armpmu_event_set_period(struct perf_event *event); - -int armpmu_map_event(struct perf_event *event, - const unsigned (*event_map)[PERF_COUNT_HW_MAX], - const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX], - u32 raw_event_mask); - -struct pmu_probe_info { - unsigned int cpuid; - unsigned int mask; - int (*init)(struct arm_pmu *); -}; - -#define PMU_PROBE(_cpuid, _mask, _fn) \ -{ \ - .cpuid = (_cpuid), \ - .mask = (_mask), \ - .init = (_fn), \ -} - -#define ARM_PMU_PROBE(_cpuid, _fn) \ - PMU_PROBE(_cpuid, ARM_CPU_PART_MASK, _fn) - -#define ARM_PMU_XSCALE_MASK ((0xff << 24) | ARM_CPU_XSCALE_ARCH_MASK) - -#define XSCALE_PMU_PROBE(_version, _fn) \ - PMU_PROBE(ARM_CPU_IMP_INTEL << 24 | _version, ARM_PMU_XSCALE_MASK, _fn) - -int arm_pmu_device_probe(struct platform_device *pdev, - const struct of_device_id *of_table, - const struct pmu_probe_info *probe_table); - -#endif /* CONFIG_HW_PERF_EVENTS */ - -#endif /* __ARM_PMU_H__ */ diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index e69f7a19735d..fcb25c1c5c21 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -71,8 +71,7 @@ obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o obj-$(CONFIG_CPU_PJ4B) += pj4-cp0.o obj-$(CONFIG_IWMMXT) += iwmmxt.o obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o -obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o \ - perf_event_xscale.o perf_event_v6.o \ +obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_xscale.o perf_event_v6.o \ perf_event_v7.o CFLAGS_pj4-cp0.o := -marm AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c deleted file mode 100644 index 1cb40651d783..000000000000 --- a/arch/arm/kernel/perf_event.c +++ /dev/null @@ -1,921 +0,0 @@ -#undef DEBUG - -/* - * ARM performance counter support. - * - * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles - * Copyright (C) 2010 ARM Ltd., Will Deacon - * - * This code is based on the sparc64 perf event code, which is in turn based - * on the x86 code. - */ -#define pr_fmt(fmt) "hw perfevents: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -static int -armpmu_map_cache_event(const unsigned (*cache_map) - [PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX], - u64 config) -{ - unsigned int cache_type, cache_op, cache_result, ret; - - 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; - - ret = (int)(*cache_map)[cache_type][cache_op][cache_result]; - - if (ret == CACHE_OP_UNSUPPORTED) - return -ENOENT; - - return ret; -} - -static int -armpmu_map_hw_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config) -{ - int mapping; - - if (config >= PERF_COUNT_HW_MAX) - return -EINVAL; - - mapping = (*event_map)[config]; - return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping; -} - -static int -armpmu_map_raw_event(u32 raw_event_mask, u64 config) -{ - return (int)(config & raw_event_mask); -} - -int -armpmu_map_event(struct perf_event *event, - const unsigned (*event_map)[PERF_COUNT_HW_MAX], - const unsigned (*cache_map) - [PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX], - u32 raw_event_mask) -{ - u64 config = event->attr.config; - int type = event->attr.type; - - if (type == event->pmu->type) - return armpmu_map_raw_event(raw_event_mask, config); - - switch (type) { - case PERF_TYPE_HARDWARE: - return armpmu_map_hw_event(event_map, config); - case PERF_TYPE_HW_CACHE: - return armpmu_map_cache_event(cache_map, config); - case PERF_TYPE_RAW: - return armpmu_map_raw_event(raw_event_mask, config); - } - - return -ENOENT; -} - -int armpmu_event_set_period(struct perf_event *event) -{ - struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - s64 left = local64_read(&hwc->period_left); - s64 period = hwc->sample_period; - int ret = 0; - - 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; - } - - /* - * Limit the maximum period to prevent the counter value - * from overtaking the one we are about to program. In - * effect we are reducing max_period to account for - * interrupt latency (and we are being very conservative). - */ - if (left > (armpmu->max_period >> 1)) - left = armpmu->max_period >> 1; - - local64_set(&hwc->prev_count, (u64)-left); - - armpmu->write_counter(event, (u64)(-left) & 0xffffffff); - - perf_event_update_userpage(event); - - return ret; -} - -u64 armpmu_event_update(struct perf_event *event) -{ - struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - u64 delta, prev_raw_count, new_raw_count; - -again: - prev_raw_count = local64_read(&hwc->prev_count); - new_raw_count = armpmu->read_counter(event); - - if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, - new_raw_count) != prev_raw_count) - goto again; - - delta = (new_raw_count - prev_raw_count) & armpmu->max_period; - - local64_add(delta, &event->count); - local64_sub(delta, &hwc->period_left); - - return new_raw_count; -} - -static void -armpmu_read(struct perf_event *event) -{ - armpmu_event_update(event); -} - -static void -armpmu_stop(struct perf_event *event, int flags) -{ - struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - - /* - * ARM pmu always has to update the counter, so ignore - * PERF_EF_UPDATE, see comments in armpmu_start(). - */ - if (!(hwc->state & PERF_HES_STOPPED)) { - armpmu->disable(event); - armpmu_event_update(event); - hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; - } -} - -static void armpmu_start(struct perf_event *event, int flags) -{ - struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - - /* - * ARM pmu always has to reprogram the period, so ignore - * PERF_EF_RELOAD, see the comment below. - */ - if (flags & PERF_EF_RELOAD) - WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); - - hwc->state = 0; - /* - * Set the period again. Some counters can't be stopped, so when we - * were stopped we simply disabled the IRQ source and the counter - * may have been left counting. If we don't do this step then we may - * get an interrupt too soon or *way* too late if the overflow has - * happened since disabling. - */ - armpmu_event_set_period(event); - armpmu->enable(event); -} - -static void -armpmu_del(struct perf_event *event, int flags) -{ - struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); - struct hw_perf_event *hwc = &event->hw; - int idx = hwc->idx; - - armpmu_stop(event, PERF_EF_UPDATE); - hw_events->events[idx] = NULL; - clear_bit(idx, hw_events->used_mask); - if (armpmu->clear_event_idx) - armpmu->clear_event_idx(hw_events, event); - - perf_event_update_userpage(event); -} - -static int -armpmu_add(struct perf_event *event, int flags) -{ - struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); - struct hw_perf_event *hwc = &event->hw; - int idx; - int err = 0; - - /* An event following a process won't be stopped earlier */ - if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus)) - return -ENOENT; - - perf_pmu_disable(event->pmu); - - /* If we don't have a space for the counter then finish early. */ - idx = armpmu->get_event_idx(hw_events, event); - if (idx < 0) { - err = idx; - goto out; - } - - /* - * If there is an event in the counter we are going to use then make - * sure it is disabled. - */ - event->hw.idx = idx; - armpmu->disable(event); - hw_events->events[idx] = event; - - hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; - if (flags & PERF_EF_START) - armpmu_start(event, PERF_EF_RELOAD); - - /* Propagate our changes to the userspace mapping. */ - perf_event_update_userpage(event); - -out: - perf_pmu_enable(event->pmu); - return err; -} - -static int -validate_event(struct pmu *pmu, struct pmu_hw_events *hw_events, - struct perf_event *event) -{ - struct arm_pmu *armpmu; - - if (is_software_event(event)) - return 1; - - /* - * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The - * core perf code won't check that the pmu->ctx == leader->ctx - * until after pmu->event_init(event). - */ - if (event->pmu != pmu) - return 0; - - if (event->state < PERF_EVENT_STATE_OFF) - return 1; - - if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec) - return 1; - - armpmu = to_arm_pmu(event->pmu); - return armpmu->get_event_idx(hw_events, event) >= 0; -} - -static int -validate_group(struct perf_event *event) -{ - struct perf_event *sibling, *leader = event->group_leader; - struct pmu_hw_events fake_pmu; - - /* - * Initialise the fake PMU. We only need to populate the - * used_mask for the purposes of validation. - */ - memset(&fake_pmu.used_mask, 0, sizeof(fake_pmu.used_mask)); - - if (!validate_event(event->pmu, &fake_pmu, leader)) - return -EINVAL; - - list_for_each_entry(sibling, &leader->sibling_list, group_entry) { - if (!validate_event(event->pmu, &fake_pmu, sibling)) - return -EINVAL; - } - - if (!validate_event(event->pmu, &fake_pmu, event)) - return -EINVAL; - - return 0; -} - -static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) -{ - struct arm_pmu *armpmu; - struct platform_device *plat_device; - struct arm_pmu_platdata *plat; - int ret; - u64 start_clock, finish_clock; - - /* - * we request the IRQ with a (possibly percpu) struct arm_pmu**, but - * the handlers expect a struct arm_pmu*. The percpu_irq framework will - * do any necessary shifting, we just need to perform the first - * dereference. - */ - armpmu = *(void **)dev; - plat_device = armpmu->plat_device; - plat = dev_get_platdata(&plat_device->dev); - - start_clock = sched_clock(); - if (plat && plat->handle_irq) - ret = plat->handle_irq(irq, armpmu, armpmu->handle_irq); - else - ret = armpmu->handle_irq(irq, armpmu); - finish_clock = sched_clock(); - - perf_sample_event_took(finish_clock - start_clock); - return ret; -} - -static void -armpmu_release_hardware(struct arm_pmu *armpmu) -{ - armpmu->free_irq(armpmu); -} - -static int -armpmu_reserve_hardware(struct arm_pmu *armpmu) -{ - int err = armpmu->request_irq(armpmu, armpmu_dispatch_irq); - if (err) { - armpmu_release_hardware(armpmu); - return err; - } - - return 0; -} - -static void -hw_perf_event_destroy(struct perf_event *event) -{ - struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - atomic_t *active_events = &armpmu->active_events; - struct mutex *pmu_reserve_mutex = &armpmu->reserve_mutex; - - if (atomic_dec_and_mutex_lock(active_events, pmu_reserve_mutex)) { - armpmu_release_hardware(armpmu); - mutex_unlock(pmu_reserve_mutex); - } -} - -static int -event_requires_mode_exclusion(struct perf_event_attr *attr) -{ - return attr->exclude_idle || attr->exclude_user || - attr->exclude_kernel || attr->exclude_hv; -} - -static int -__hw_perf_event_init(struct perf_event *event) -{ - struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - int mapping; - - mapping = armpmu->map_event(event); - - if (mapping < 0) { - pr_debug("event %x:%llx not supported\n", event->attr.type, - event->attr.config); - return mapping; - } - - /* - * We don't assign an index until we actually place the event onto - * hardware. Use -1 to signify that we haven't decided where to put it - * yet. For SMP systems, each core has it's own PMU so we can't do any - * clever allocation or constraints checking at this point. - */ - hwc->idx = -1; - hwc->config_base = 0; - hwc->config = 0; - hwc->event_base = 0; - - /* - * Check whether we need to exclude the counter from certain modes. - */ - if ((!armpmu->set_event_filter || - armpmu->set_event_filter(hwc, &event->attr)) && - event_requires_mode_exclusion(&event->attr)) { - pr_debug("ARM performance counters do not support " - "mode exclusion\n"); - return -EOPNOTSUPP; - } - - /* - * Store the event encoding into the config_base field. - */ - hwc->config_base |= (unsigned long)mapping; - - if (!is_sampling_event(event)) { - /* - * For non-sampling runs, limit the sample_period to half - * of the counter width. That way, the new counter value - * is far less likely to overtake the previous one unless - * you have some serious IRQ latency issues. - */ - hwc->sample_period = armpmu->max_period >> 1; - hwc->last_period = hwc->sample_period; - local64_set(&hwc->period_left, hwc->sample_period); - } - - if (event->group_leader != event) { - if (validate_group(event) != 0) - return -EINVAL; - } - - return 0; -} - -static int armpmu_event_init(struct perf_event *event) -{ - struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - int err = 0; - atomic_t *active_events = &armpmu->active_events; - - /* - * Reject CPU-affine events for CPUs that are of a different class to - * that which this PMU handles. Process-following events (where - * event->cpu == -1) can be migrated between CPUs, and thus we have to - * reject them later (in armpmu_add) if they're scheduled on a - * different class of CPU. - */ - if (event->cpu != -1 && - !cpumask_test_cpu(event->cpu, &armpmu->supported_cpus)) - return -ENOENT; - - /* does not support taken branch sampling */ - if (has_branch_stack(event)) - return -EOPNOTSUPP; - - if (armpmu->map_event(event) == -ENOENT) - return -ENOENT; - - event->destroy = hw_perf_event_destroy; - - if (!atomic_inc_not_zero(active_events)) { - mutex_lock(&armpmu->reserve_mutex); - if (atomic_read(active_events) == 0) - err = armpmu_reserve_hardware(armpmu); - - if (!err) - atomic_inc(active_events); - mutex_unlock(&armpmu->reserve_mutex); - } - - if (err) - return err; - - err = __hw_perf_event_init(event); - if (err) - hw_perf_event_destroy(event); - - return err; -} - -static void armpmu_enable(struct pmu *pmu) -{ - struct arm_pmu *armpmu = to_arm_pmu(pmu); - struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); - int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events); - - /* For task-bound events we may be called on other CPUs */ - if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus)) - return; - - if (enabled) - armpmu->start(armpmu); -} - -static void armpmu_disable(struct pmu *pmu) -{ - struct arm_pmu *armpmu = to_arm_pmu(pmu); - - /* For task-bound events we may be called on other CPUs */ - if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus)) - return; - - armpmu->stop(armpmu); -} - -/* - * In heterogeneous systems, events are specific to a particular - * microarchitecture, and aren't suitable for another. Thus, only match CPUs of - * the same microarchitecture. - */ -static int armpmu_filter_match(struct perf_event *event) -{ - struct arm_pmu *armpmu = to_arm_pmu(event->pmu); - unsigned int cpu = smp_processor_id(); - return cpumask_test_cpu(cpu, &armpmu->supported_cpus); -} - -static void armpmu_init(struct arm_pmu *armpmu) -{ - atomic_set(&armpmu->active_events, 0); - mutex_init(&armpmu->reserve_mutex); - - armpmu->pmu = (struct pmu) { - .pmu_enable = armpmu_enable, - .pmu_disable = armpmu_disable, - .event_init = armpmu_event_init, - .add = armpmu_add, - .del = armpmu_del, - .start = armpmu_start, - .stop = armpmu_stop, - .read = armpmu_read, - .filter_match = armpmu_filter_match, - }; -} - -int armpmu_register(struct arm_pmu *armpmu, int type) -{ - armpmu_init(armpmu); - pr_info("enabled with %s PMU driver, %d counters available\n", - armpmu->name, armpmu->num_events); - return perf_pmu_register(&armpmu->pmu, armpmu->name, type); -} - -/* Set at runtime when we know what CPU type we are. */ -static struct arm_pmu *__oprofile_cpu_pmu; - -/* - * Despite the names, these two functions are CPU-specific and are used - * by the OProfile/perf code. - */ -const char *perf_pmu_name(void) -{ - if (!__oprofile_cpu_pmu) - return NULL; - - return __oprofile_cpu_pmu->name; -} -EXPORT_SYMBOL_GPL(perf_pmu_name); - -int perf_num_counters(void) -{ - int max_events = 0; - - if (__oprofile_cpu_pmu != NULL) - max_events = __oprofile_cpu_pmu->num_events; - - return max_events; -} -EXPORT_SYMBOL_GPL(perf_num_counters); - -static void cpu_pmu_enable_percpu_irq(void *data) -{ - int irq = *(int *)data; - - enable_percpu_irq(irq, IRQ_TYPE_NONE); -} - -static void cpu_pmu_disable_percpu_irq(void *data) -{ - int irq = *(int *)data; - - disable_percpu_irq(irq); -} - -static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu) -{ - int i, irq, irqs; - struct platform_device *pmu_device = cpu_pmu->plat_device; - struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events; - - irqs = min(pmu_device->num_resources, num_possible_cpus()); - - irq = platform_get_irq(pmu_device, 0); - if (irq >= 0 && irq_is_percpu(irq)) { - on_each_cpu(cpu_pmu_disable_percpu_irq, &irq, 1); - free_percpu_irq(irq, &hw_events->percpu_pmu); - } else { - for (i = 0; i < irqs; ++i) { - int cpu = i; - - if (cpu_pmu->irq_affinity) - cpu = cpu_pmu->irq_affinity[i]; - - if (!cpumask_test_and_clear_cpu(cpu, &cpu_pmu->active_irqs)) - continue; - irq = platform_get_irq(pmu_device, i); - if (irq >= 0) - free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); - } - } -} - -static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) -{ - int i, err, irq, irqs; - struct platform_device *pmu_device = cpu_pmu->plat_device; - struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events; - - if (!pmu_device) - return -ENODEV; - - irqs = min(pmu_device->num_resources, num_possible_cpus()); - if (irqs < 1) { - pr_warn_once("perf/ARM: No irqs for PMU defined, sampling events not supported\n"); - return 0; - } - - irq = platform_get_irq(pmu_device, 0); - if (irq >= 0 && irq_is_percpu(irq)) { - err = request_percpu_irq(irq, handler, "arm-pmu", - &hw_events->percpu_pmu); - if (err) { - pr_err("unable to request IRQ%d for ARM PMU counters\n", - irq); - return err; - } - on_each_cpu(cpu_pmu_enable_percpu_irq, &irq, 1); - } else { - for (i = 0; i < irqs; ++i) { - int cpu = i; - - err = 0; - irq = platform_get_irq(pmu_device, i); - if (irq < 0) - continue; - - if (cpu_pmu->irq_affinity) - cpu = cpu_pmu->irq_affinity[i]; - - /* - * If we have a single PMU interrupt that we can't shift, - * assume that we're running on a uniprocessor machine and - * continue. Otherwise, continue without this interrupt. - */ - if (irq_set_affinity(irq, cpumask_of(cpu)) && irqs > 1) { - pr_warn("unable to set irq affinity (irq=%d, cpu=%u)\n", - irq, cpu); - continue; - } - - err = request_irq(irq, handler, - IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu", - per_cpu_ptr(&hw_events->percpu_pmu, cpu)); - if (err) { - pr_err("unable to request IRQ%d for ARM PMU counters\n", - irq); - return err; - } - - cpumask_set_cpu(cpu, &cpu_pmu->active_irqs); - } - } - - return 0; -} - -/* - * PMU hardware loses all context when a CPU goes offline. - * When a CPU is hotplugged back in, since some hardware registers are - * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading - * junk values out of them. - */ -static int cpu_pmu_notify(struct notifier_block *b, unsigned long action, - void *hcpu) -{ - int cpu = (unsigned long)hcpu; - struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb); - - if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) - return NOTIFY_DONE; - - if (!cpumask_test_cpu(cpu, &pmu->supported_cpus)) - return NOTIFY_DONE; - - if (pmu->reset) - pmu->reset(pmu); - else - return NOTIFY_DONE; - - return NOTIFY_OK; -} - -static int cpu_pmu_init(struct arm_pmu *cpu_pmu) -{ - int err; - int cpu; - struct pmu_hw_events __percpu *cpu_hw_events; - - cpu_hw_events = alloc_percpu(struct pmu_hw_events); - if (!cpu_hw_events) - return -ENOMEM; - - cpu_pmu->hotplug_nb.notifier_call = cpu_pmu_notify; - err = register_cpu_notifier(&cpu_pmu->hotplug_nb); - if (err) - goto out_hw_events; - - for_each_possible_cpu(cpu) { - struct pmu_hw_events *events = per_cpu_ptr(cpu_hw_events, cpu); - raw_spin_lock_init(&events->pmu_lock); - events->percpu_pmu = cpu_pmu; - } - - cpu_pmu->hw_events = cpu_hw_events; - cpu_pmu->request_irq = cpu_pmu_request_irq; - cpu_pmu->free_irq = cpu_pmu_free_irq; - - /* Ensure the PMU has sane values out of reset. */ - if (cpu_pmu->reset) - on_each_cpu_mask(&cpu_pmu->supported_cpus, cpu_pmu->reset, - cpu_pmu, 1); - - /* If no interrupts available, set the corresponding capability flag */ - if (!platform_get_irq(cpu_pmu->plat_device, 0)) - cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; - - return 0; - -out_hw_events: - free_percpu(cpu_hw_events); - return err; -} - -static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu) -{ - unregister_cpu_notifier(&cpu_pmu->hotplug_nb); - free_percpu(cpu_pmu->hw_events); -} - -/* - * CPU PMU identification and probing. - */ -static int probe_current_pmu(struct arm_pmu *pmu, - const struct pmu_probe_info *info) -{ - int cpu = get_cpu(); - unsigned int cpuid = read_cpuid_id(); - int ret = -ENODEV; - - pr_info("probing PMU on CPU %d\n", cpu); - - for (; info->init != NULL; info++) { - if ((cpuid & info->mask) != info->cpuid) - continue; - ret = info->init(pmu); - break; - } - - put_cpu(); - return ret; -} - -static int of_pmu_irq_cfg(struct arm_pmu *pmu) -{ - int *irqs, i = 0; - bool using_spi = false; - struct platform_device *pdev = pmu->plat_device; - - irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); - if (!irqs) - return -ENOMEM; - - do { - struct device_node *dn; - int cpu, irq; - - /* See if we have an affinity entry */ - dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity", i); - if (!dn) - break; - - /* Check the IRQ type and prohibit a mix of PPIs and SPIs */ - irq = platform_get_irq(pdev, i); - if (irq >= 0) { - bool spi = !irq_is_percpu(irq); - - if (i > 0 && spi != using_spi) { - pr_err("PPI/SPI IRQ type mismatch for %s!\n", - dn->name); - kfree(irqs); - return -EINVAL; - } - - using_spi = spi; - } - - /* Now look up the logical CPU number */ - for_each_possible_cpu(cpu) - if (dn == of_cpu_device_node_get(cpu)) - break; - - if (cpu >= nr_cpu_ids) { - pr_warn("Failed to find logical CPU for %s\n", - dn->name); - of_node_put(dn); - cpumask_setall(&pmu->supported_cpus); - break; - } - of_node_put(dn); - - /* For SPIs, we need to track the affinity per IRQ */ - if (using_spi) { - if (i >= pdev->num_resources) { - of_node_put(dn); - break; - } - - irqs[i] = cpu; - } - - /* Keep track of the CPUs containing this PMU type */ - cpumask_set_cpu(cpu, &pmu->supported_cpus); - of_node_put(dn); - i++; - } while (1); - - /* If we didn't manage to parse anything, claim to support all CPUs */ - if (cpumask_weight(&pmu->supported_cpus) == 0) - cpumask_setall(&pmu->supported_cpus); - - /* If we matched up the IRQ affinities, use them to route the SPIs */ - if (using_spi && i == pdev->num_resources) - pmu->irq_affinity = irqs; - else - kfree(irqs); - - return 0; -} - -int arm_pmu_device_probe(struct platform_device *pdev, - const struct of_device_id *of_table, - const struct pmu_probe_info *probe_table) -{ - const struct of_device_id *of_id; - const int (*init_fn)(struct arm_pmu *); - struct device_node *node = pdev->dev.of_node; - struct arm_pmu *pmu; - int ret = -ENODEV; - - pmu = kzalloc(sizeof(struct arm_pmu), GFP_KERNEL); - if (!pmu) { - pr_info("failed to allocate PMU device!\n"); - return -ENOMEM; - } - - if (!__oprofile_cpu_pmu) - __oprofile_cpu_pmu = pmu; - - pmu->plat_device = pdev; - - if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) { - init_fn = of_id->data; - - ret = of_pmu_irq_cfg(pmu); - if (!ret) - ret = init_fn(pmu); - } else { - ret = probe_current_pmu(pmu, probe_table); - cpumask_setall(&pmu->supported_cpus); - } - - if (ret) { - pr_info("failed to probe PMU!\n"); - goto out_free; - } - - ret = cpu_pmu_init(pmu); - if (ret) - goto out_free; - - ret = armpmu_register(pmu, -1); - if (ret) - goto out_destroy; - - return 0; - -out_destroy: - cpu_pmu_destroy(pmu); -out_free: - pr_info("failed to register PMU devices!\n"); - kfree(pmu); - return ret; -} diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index 09f83e414a72..09413e7b49aa 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c @@ -34,9 +34,9 @@ #include #include -#include #include +#include #include enum armv6_perf_types { diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index f9b37f876e20..126dc679b230 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -21,11 +21,11 @@ #include #include #include -#include #include #include "../vfp/vfpinstr.h" #include +#include #include /* diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c index 304d056d5b25..aa0499e2eef7 100644 --- a/arch/arm/kernel/perf_event_xscale.c +++ b/arch/arm/kernel/perf_event_xscale.c @@ -16,9 +16,9 @@ #include #include -#include #include +#include #include enum xscale_perf_types { diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index 16913800bbf9..5578dc1ab52b 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -20,10 +20,10 @@ #include #include #include +#include #include #include -#include #include #include "setup.h" diff --git a/drivers/Kconfig b/drivers/Kconfig index 6e973b8e3a3b..3497485f5eab 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -176,6 +176,8 @@ source "drivers/powercap/Kconfig" source "drivers/mcb/Kconfig" +source "drivers/perf/Kconfig" + source "drivers/ras/Kconfig" source "drivers/thunderbolt/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index b64b49f6e01b..f245f2291b8a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -161,6 +161,7 @@ obj-$(CONFIG_NTB) += ntb/ obj-$(CONFIG_FMC) += fmc/ obj-$(CONFIG_POWERCAP) += powercap/ obj-$(CONFIG_MCB) += mcb/ +obj-$(CONFIG_PERF_EVENTS) += perf/ obj-$(CONFIG_RAS) += ras/ obj-$(CONFIG_THUNDERBOLT) += thunderbolt/ obj-$(CONFIG_CORESIGHT) += hwtracing/coresight/ diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig new file mode 100644 index 000000000000..d9de36ee165d --- /dev/null +++ b/drivers/perf/Kconfig @@ -0,0 +1,15 @@ +# +# Performance Monitor Drivers +# + +menu "Performance monitor support" + +config ARM_PMU + depends on PERF_EVENTS && ARM + bool "ARM PMU framework" + default y + help + Say y if you want to use CPU performance monitors on ARM-based + systems. + +endmenu diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile new file mode 100644 index 000000000000..acd2397ded94 --- /dev/null +++ b/drivers/perf/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ARM_PMU) += arm_pmu.o diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c new file mode 100644 index 000000000000..2365a32a595e --- /dev/null +++ b/drivers/perf/arm_pmu.c @@ -0,0 +1,921 @@ +#undef DEBUG + +/* + * ARM performance counter support. + * + * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles + * Copyright (C) 2010 ARM Ltd., Will Deacon + * + * This code is based on the sparc64 perf event code, which is in turn based + * on the x86 code. + */ +#define pr_fmt(fmt) "hw perfevents: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int +armpmu_map_cache_event(const unsigned (*cache_map) + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX], + u64 config) +{ + unsigned int cache_type, cache_op, cache_result, ret; + + 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; + + ret = (int)(*cache_map)[cache_type][cache_op][cache_result]; + + if (ret == CACHE_OP_UNSUPPORTED) + return -ENOENT; + + return ret; +} + +static int +armpmu_map_hw_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config) +{ + int mapping; + + if (config >= PERF_COUNT_HW_MAX) + return -EINVAL; + + mapping = (*event_map)[config]; + return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping; +} + +static int +armpmu_map_raw_event(u32 raw_event_mask, u64 config) +{ + return (int)(config & raw_event_mask); +} + +int +armpmu_map_event(struct perf_event *event, + const unsigned (*event_map)[PERF_COUNT_HW_MAX], + const unsigned (*cache_map) + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX], + u32 raw_event_mask) +{ + u64 config = event->attr.config; + int type = event->attr.type; + + if (type == event->pmu->type) + return armpmu_map_raw_event(raw_event_mask, config); + + switch (type) { + case PERF_TYPE_HARDWARE: + return armpmu_map_hw_event(event_map, config); + case PERF_TYPE_HW_CACHE: + return armpmu_map_cache_event(cache_map, config); + case PERF_TYPE_RAW: + return armpmu_map_raw_event(raw_event_mask, config); + } + + return -ENOENT; +} + +int armpmu_event_set_period(struct perf_event *event) +{ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + s64 left = local64_read(&hwc->period_left); + s64 period = hwc->sample_period; + int ret = 0; + + 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; + } + + /* + * Limit the maximum period to prevent the counter value + * from overtaking the one we are about to program. In + * effect we are reducing max_period to account for + * interrupt latency (and we are being very conservative). + */ + if (left > (armpmu->max_period >> 1)) + left = armpmu->max_period >> 1; + + local64_set(&hwc->prev_count, (u64)-left); + + armpmu->write_counter(event, (u64)(-left) & 0xffffffff); + + perf_event_update_userpage(event); + + return ret; +} + +u64 armpmu_event_update(struct perf_event *event) +{ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + u64 delta, prev_raw_count, new_raw_count; + +again: + prev_raw_count = local64_read(&hwc->prev_count); + new_raw_count = armpmu->read_counter(event); + + if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count) != prev_raw_count) + goto again; + + delta = (new_raw_count - prev_raw_count) & armpmu->max_period; + + local64_add(delta, &event->count); + local64_sub(delta, &hwc->period_left); + + return new_raw_count; +} + +static void +armpmu_read(struct perf_event *event) +{ + armpmu_event_update(event); +} + +static void +armpmu_stop(struct perf_event *event, int flags) +{ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + + /* + * ARM pmu always has to update the counter, so ignore + * PERF_EF_UPDATE, see comments in armpmu_start(). + */ + if (!(hwc->state & PERF_HES_STOPPED)) { + armpmu->disable(event); + armpmu_event_update(event); + hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; + } +} + +static void armpmu_start(struct perf_event *event, int flags) +{ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + + /* + * ARM pmu always has to reprogram the period, so ignore + * PERF_EF_RELOAD, see the comment below. + */ + if (flags & PERF_EF_RELOAD) + WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); + + hwc->state = 0; + /* + * Set the period again. Some counters can't be stopped, so when we + * were stopped we simply disabled the IRQ source and the counter + * may have been left counting. If we don't do this step then we may + * get an interrupt too soon or *way* too late if the overflow has + * happened since disabling. + */ + armpmu_event_set_period(event); + armpmu->enable(event); +} + +static void +armpmu_del(struct perf_event *event, int flags) +{ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + + armpmu_stop(event, PERF_EF_UPDATE); + hw_events->events[idx] = NULL; + clear_bit(idx, hw_events->used_mask); + if (armpmu->clear_event_idx) + armpmu->clear_event_idx(hw_events, event); + + perf_event_update_userpage(event); +} + +static int +armpmu_add(struct perf_event *event, int flags) +{ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); + struct hw_perf_event *hwc = &event->hw; + int idx; + int err = 0; + + /* An event following a process won't be stopped earlier */ + if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus)) + return -ENOENT; + + perf_pmu_disable(event->pmu); + + /* If we don't have a space for the counter then finish early. */ + idx = armpmu->get_event_idx(hw_events, event); + if (idx < 0) { + err = idx; + goto out; + } + + /* + * If there is an event in the counter we are going to use then make + * sure it is disabled. + */ + event->hw.idx = idx; + armpmu->disable(event); + hw_events->events[idx] = event; + + hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; + if (flags & PERF_EF_START) + armpmu_start(event, PERF_EF_RELOAD); + + /* Propagate our changes to the userspace mapping. */ + perf_event_update_userpage(event); + +out: + perf_pmu_enable(event->pmu); + return err; +} + +static int +validate_event(struct pmu *pmu, struct pmu_hw_events *hw_events, + struct perf_event *event) +{ + struct arm_pmu *armpmu; + + if (is_software_event(event)) + return 1; + + /* + * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The + * core perf code won't check that the pmu->ctx == leader->ctx + * until after pmu->event_init(event). + */ + if (event->pmu != pmu) + return 0; + + if (event->state < PERF_EVENT_STATE_OFF) + return 1; + + if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec) + return 1; + + armpmu = to_arm_pmu(event->pmu); + return armpmu->get_event_idx(hw_events, event) >= 0; +} + +static int +validate_group(struct perf_event *event) +{ + struct perf_event *sibling, *leader = event->group_leader; + struct pmu_hw_events fake_pmu; + + /* + * Initialise the fake PMU. We only need to populate the + * used_mask for the purposes of validation. + */ + memset(&fake_pmu.used_mask, 0, sizeof(fake_pmu.used_mask)); + + if (!validate_event(event->pmu, &fake_pmu, leader)) + return -EINVAL; + + list_for_each_entry(sibling, &leader->sibling_list, group_entry) { + if (!validate_event(event->pmu, &fake_pmu, sibling)) + return -EINVAL; + } + + if (!validate_event(event->pmu, &fake_pmu, event)) + return -EINVAL; + + return 0; +} + +static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) +{ + struct arm_pmu *armpmu; + struct platform_device *plat_device; + struct arm_pmu_platdata *plat; + int ret; + u64 start_clock, finish_clock; + + /* + * we request the IRQ with a (possibly percpu) struct arm_pmu**, but + * the handlers expect a struct arm_pmu*. The percpu_irq framework will + * do any necessary shifting, we just need to perform the first + * dereference. + */ + armpmu = *(void **)dev; + plat_device = armpmu->plat_device; + plat = dev_get_platdata(&plat_device->dev); + + start_clock = sched_clock(); + if (plat && plat->handle_irq) + ret = plat->handle_irq(irq, armpmu, armpmu->handle_irq); + else + ret = armpmu->handle_irq(irq, armpmu); + finish_clock = sched_clock(); + + perf_sample_event_took(finish_clock - start_clock); + return ret; +} + +static void +armpmu_release_hardware(struct arm_pmu *armpmu) +{ + armpmu->free_irq(armpmu); +} + +static int +armpmu_reserve_hardware(struct arm_pmu *armpmu) +{ + int err = armpmu->request_irq(armpmu, armpmu_dispatch_irq); + if (err) { + armpmu_release_hardware(armpmu); + return err; + } + + return 0; +} + +static void +hw_perf_event_destroy(struct perf_event *event) +{ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + atomic_t *active_events = &armpmu->active_events; + struct mutex *pmu_reserve_mutex = &armpmu->reserve_mutex; + + if (atomic_dec_and_mutex_lock(active_events, pmu_reserve_mutex)) { + armpmu_release_hardware(armpmu); + mutex_unlock(pmu_reserve_mutex); + } +} + +static int +event_requires_mode_exclusion(struct perf_event_attr *attr) +{ + return attr->exclude_idle || attr->exclude_user || + attr->exclude_kernel || attr->exclude_hv; +} + +static int +__hw_perf_event_init(struct perf_event *event) +{ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + int mapping; + + mapping = armpmu->map_event(event); + + if (mapping < 0) { + pr_debug("event %x:%llx not supported\n", event->attr.type, + event->attr.config); + return mapping; + } + + /* + * We don't assign an index until we actually place the event onto + * hardware. Use -1 to signify that we haven't decided where to put it + * yet. For SMP systems, each core has it's own PMU so we can't do any + * clever allocation or constraints checking at this point. + */ + hwc->idx = -1; + hwc->config_base = 0; + hwc->config = 0; + hwc->event_base = 0; + + /* + * Check whether we need to exclude the counter from certain modes. + */ + if ((!armpmu->set_event_filter || + armpmu->set_event_filter(hwc, &event->attr)) && + event_requires_mode_exclusion(&event->attr)) { + pr_debug("ARM performance counters do not support " + "mode exclusion\n"); + return -EOPNOTSUPP; + } + + /* + * Store the event encoding into the config_base field. + */ + hwc->config_base |= (unsigned long)mapping; + + if (!is_sampling_event(event)) { + /* + * For non-sampling runs, limit the sample_period to half + * of the counter width. That way, the new counter value + * is far less likely to overtake the previous one unless + * you have some serious IRQ latency issues. + */ + hwc->sample_period = armpmu->max_period >> 1; + hwc->last_period = hwc->sample_period; + local64_set(&hwc->period_left, hwc->sample_period); + } + + if (event->group_leader != event) { + if (validate_group(event) != 0) + return -EINVAL; + } + + return 0; +} + +static int armpmu_event_init(struct perf_event *event) +{ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + int err = 0; + atomic_t *active_events = &armpmu->active_events; + + /* + * Reject CPU-affine events for CPUs that are of a different class to + * that which this PMU handles. Process-following events (where + * event->cpu == -1) can be migrated between CPUs, and thus we have to + * reject them later (in armpmu_add) if they're scheduled on a + * different class of CPU. + */ + if (event->cpu != -1 && + !cpumask_test_cpu(event->cpu, &armpmu->supported_cpus)) + return -ENOENT; + + /* does not support taken branch sampling */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + + if (armpmu->map_event(event) == -ENOENT) + return -ENOENT; + + event->destroy = hw_perf_event_destroy; + + if (!atomic_inc_not_zero(active_events)) { + mutex_lock(&armpmu->reserve_mutex); + if (atomic_read(active_events) == 0) + err = armpmu_reserve_hardware(armpmu); + + if (!err) + atomic_inc(active_events); + mutex_unlock(&armpmu->reserve_mutex); + } + + if (err) + return err; + + err = __hw_perf_event_init(event); + if (err) + hw_perf_event_destroy(event); + + return err; +} + +static void armpmu_enable(struct pmu *pmu) +{ + struct arm_pmu *armpmu = to_arm_pmu(pmu); + struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); + int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events); + + /* For task-bound events we may be called on other CPUs */ + if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus)) + return; + + if (enabled) + armpmu->start(armpmu); +} + +static void armpmu_disable(struct pmu *pmu) +{ + struct arm_pmu *armpmu = to_arm_pmu(pmu); + + /* For task-bound events we may be called on other CPUs */ + if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus)) + return; + + armpmu->stop(armpmu); +} + +/* + * In heterogeneous systems, events are specific to a particular + * microarchitecture, and aren't suitable for another. Thus, only match CPUs of + * the same microarchitecture. + */ +static int armpmu_filter_match(struct perf_event *event) +{ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + unsigned int cpu = smp_processor_id(); + return cpumask_test_cpu(cpu, &armpmu->supported_cpus); +} + +static void armpmu_init(struct arm_pmu *armpmu) +{ + atomic_set(&armpmu->active_events, 0); + mutex_init(&armpmu->reserve_mutex); + + armpmu->pmu = (struct pmu) { + .pmu_enable = armpmu_enable, + .pmu_disable = armpmu_disable, + .event_init = armpmu_event_init, + .add = armpmu_add, + .del = armpmu_del, + .start = armpmu_start, + .stop = armpmu_stop, + .read = armpmu_read, + .filter_match = armpmu_filter_match, + }; +} + +int armpmu_register(struct arm_pmu *armpmu, int type) +{ + armpmu_init(armpmu); + pr_info("enabled with %s PMU driver, %d counters available\n", + armpmu->name, armpmu->num_events); + return perf_pmu_register(&armpmu->pmu, armpmu->name, type); +} + +/* Set at runtime when we know what CPU type we are. */ +static struct arm_pmu *__oprofile_cpu_pmu; + +/* + * Despite the names, these two functions are CPU-specific and are used + * by the OProfile/perf code. + */ +const char *perf_pmu_name(void) +{ + if (!__oprofile_cpu_pmu) + return NULL; + + return __oprofile_cpu_pmu->name; +} +EXPORT_SYMBOL_GPL(perf_pmu_name); + +int perf_num_counters(void) +{ + int max_events = 0; + + if (__oprofile_cpu_pmu != NULL) + max_events = __oprofile_cpu_pmu->num_events; + + return max_events; +} +EXPORT_SYMBOL_GPL(perf_num_counters); + +static void cpu_pmu_enable_percpu_irq(void *data) +{ + int irq = *(int *)data; + + enable_percpu_irq(irq, IRQ_TYPE_NONE); +} + +static void cpu_pmu_disable_percpu_irq(void *data) +{ + int irq = *(int *)data; + + disable_percpu_irq(irq); +} + +static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu) +{ + int i, irq, irqs; + struct platform_device *pmu_device = cpu_pmu->plat_device; + struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events; + + irqs = min(pmu_device->num_resources, num_possible_cpus()); + + irq = platform_get_irq(pmu_device, 0); + if (irq >= 0 && irq_is_percpu(irq)) { + on_each_cpu(cpu_pmu_disable_percpu_irq, &irq, 1); + free_percpu_irq(irq, &hw_events->percpu_pmu); + } else { + for (i = 0; i < irqs; ++i) { + int cpu = i; + + if (cpu_pmu->irq_affinity) + cpu = cpu_pmu->irq_affinity[i]; + + if (!cpumask_test_and_clear_cpu(cpu, &cpu_pmu->active_irqs)) + continue; + irq = platform_get_irq(pmu_device, i); + if (irq >= 0) + free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); + } + } +} + +static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) +{ + int i, err, irq, irqs; + struct platform_device *pmu_device = cpu_pmu->plat_device; + struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events; + + if (!pmu_device) + return -ENODEV; + + irqs = min(pmu_device->num_resources, num_possible_cpus()); + if (irqs < 1) { + pr_warn_once("perf/ARM: No irqs for PMU defined, sampling events not supported\n"); + return 0; + } + + irq = platform_get_irq(pmu_device, 0); + if (irq >= 0 && irq_is_percpu(irq)) { + err = request_percpu_irq(irq, handler, "arm-pmu", + &hw_events->percpu_pmu); + if (err) { + pr_err("unable to request IRQ%d for ARM PMU counters\n", + irq); + return err; + } + on_each_cpu(cpu_pmu_enable_percpu_irq, &irq, 1); + } else { + for (i = 0; i < irqs; ++i) { + int cpu = i; + + err = 0; + irq = platform_get_irq(pmu_device, i); + if (irq < 0) + continue; + + if (cpu_pmu->irq_affinity) + cpu = cpu_pmu->irq_affinity[i]; + + /* + * If we have a single PMU interrupt that we can't shift, + * assume that we're running on a uniprocessor machine and + * continue. Otherwise, continue without this interrupt. + */ + if (irq_set_affinity(irq, cpumask_of(cpu)) && irqs > 1) { + pr_warn("unable to set irq affinity (irq=%d, cpu=%u)\n", + irq, cpu); + continue; + } + + err = request_irq(irq, handler, + IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu", + per_cpu_ptr(&hw_events->percpu_pmu, cpu)); + if (err) { + pr_err("unable to request IRQ%d for ARM PMU counters\n", + irq); + return err; + } + + cpumask_set_cpu(cpu, &cpu_pmu->active_irqs); + } + } + + return 0; +} + +/* + * PMU hardware loses all context when a CPU goes offline. + * When a CPU is hotplugged back in, since some hardware registers are + * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading + * junk values out of them. + */ +static int cpu_pmu_notify(struct notifier_block *b, unsigned long action, + void *hcpu) +{ + int cpu = (unsigned long)hcpu; + struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb); + + if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) + return NOTIFY_DONE; + + if (!cpumask_test_cpu(cpu, &pmu->supported_cpus)) + return NOTIFY_DONE; + + if (pmu->reset) + pmu->reset(pmu); + else + return NOTIFY_DONE; + + return NOTIFY_OK; +} + +static int cpu_pmu_init(struct arm_pmu *cpu_pmu) +{ + int err; + int cpu; + struct pmu_hw_events __percpu *cpu_hw_events; + + cpu_hw_events = alloc_percpu(struct pmu_hw_events); + if (!cpu_hw_events) + return -ENOMEM; + + cpu_pmu->hotplug_nb.notifier_call = cpu_pmu_notify; + err = register_cpu_notifier(&cpu_pmu->hotplug_nb); + if (err) + goto out_hw_events; + + for_each_possible_cpu(cpu) { + struct pmu_hw_events *events = per_cpu_ptr(cpu_hw_events, cpu); + raw_spin_lock_init(&events->pmu_lock); + events->percpu_pmu = cpu_pmu; + } + + cpu_pmu->hw_events = cpu_hw_events; + cpu_pmu->request_irq = cpu_pmu_request_irq; + cpu_pmu->free_irq = cpu_pmu_free_irq; + + /* Ensure the PMU has sane values out of reset. */ + if (cpu_pmu->reset) + on_each_cpu_mask(&cpu_pmu->supported_cpus, cpu_pmu->reset, + cpu_pmu, 1); + + /* If no interrupts available, set the corresponding capability flag */ + if (!platform_get_irq(cpu_pmu->plat_device, 0)) + cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; + + return 0; + +out_hw_events: + free_percpu(cpu_hw_events); + return err; +} + +static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu) +{ + unregister_cpu_notifier(&cpu_pmu->hotplug_nb); + free_percpu(cpu_pmu->hw_events); +} + +/* + * CPU PMU identification and probing. + */ +static int probe_current_pmu(struct arm_pmu *pmu, + const struct pmu_probe_info *info) +{ + int cpu = get_cpu(); + unsigned int cpuid = read_cpuid_id(); + int ret = -ENODEV; + + pr_info("probing PMU on CPU %d\n", cpu); + + for (; info->init != NULL; info++) { + if ((cpuid & info->mask) != info->cpuid) + continue; + ret = info->init(pmu); + break; + } + + put_cpu(); + return ret; +} + +static int of_pmu_irq_cfg(struct arm_pmu *pmu) +{ + int *irqs, i = 0; + bool using_spi = false; + struct platform_device *pdev = pmu->plat_device; + + irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); + if (!irqs) + return -ENOMEM; + + do { + struct device_node *dn; + int cpu, irq; + + /* See if we have an affinity entry */ + dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity", i); + if (!dn) + break; + + /* Check the IRQ type and prohibit a mix of PPIs and SPIs */ + irq = platform_get_irq(pdev, i); + if (irq >= 0) { + bool spi = !irq_is_percpu(irq); + + if (i > 0 && spi != using_spi) { + pr_err("PPI/SPI IRQ type mismatch for %s!\n", + dn->name); + kfree(irqs); + return -EINVAL; + } + + using_spi = spi; + } + + /* Now look up the logical CPU number */ + for_each_possible_cpu(cpu) + if (dn == of_cpu_device_node_get(cpu)) + break; + + if (cpu >= nr_cpu_ids) { + pr_warn("Failed to find logical CPU for %s\n", + dn->name); + of_node_put(dn); + cpumask_setall(&pmu->supported_cpus); + break; + } + of_node_put(dn); + + /* For SPIs, we need to track the affinity per IRQ */ + if (using_spi) { + if (i >= pdev->num_resources) { + of_node_put(dn); + break; + } + + irqs[i] = cpu; + } + + /* Keep track of the CPUs containing this PMU type */ + cpumask_set_cpu(cpu, &pmu->supported_cpus); + of_node_put(dn); + i++; + } while (1); + + /* If we didn't manage to parse anything, claim to support all CPUs */ + if (cpumask_weight(&pmu->supported_cpus) == 0) + cpumask_setall(&pmu->supported_cpus); + + /* If we matched up the IRQ affinities, use them to route the SPIs */ + if (using_spi && i == pdev->num_resources) + pmu->irq_affinity = irqs; + else + kfree(irqs); + + return 0; +} + +int arm_pmu_device_probe(struct platform_device *pdev, + const struct of_device_id *of_table, + const struct pmu_probe_info *probe_table) +{ + const struct of_device_id *of_id; + const int (*init_fn)(struct arm_pmu *); + struct device_node *node = pdev->dev.of_node; + struct arm_pmu *pmu; + int ret = -ENODEV; + + pmu = kzalloc(sizeof(struct arm_pmu), GFP_KERNEL); + if (!pmu) { + pr_info("failed to allocate PMU device!\n"); + return -ENOMEM; + } + + if (!__oprofile_cpu_pmu) + __oprofile_cpu_pmu = pmu; + + pmu->plat_device = pdev; + + if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) { + init_fn = of_id->data; + + ret = of_pmu_irq_cfg(pmu); + if (!ret) + ret = init_fn(pmu); + } else { + ret = probe_current_pmu(pmu, probe_table); + cpumask_setall(&pmu->supported_cpus); + } + + if (ret) { + pr_info("failed to probe PMU!\n"); + goto out_free; + } + + ret = cpu_pmu_init(pmu); + if (ret) + goto out_free; + + ret = armpmu_register(pmu, -1); + if (ret) + goto out_destroy; + + return 0; + +out_destroy: + cpu_pmu_destroy(pmu); +out_free: + pr_info("failed to register PMU devices!\n"); + kfree(pmu); + return ret; +} diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h new file mode 100644 index 000000000000..bfa673bb822d --- /dev/null +++ b/include/linux/perf/arm_pmu.h @@ -0,0 +1,154 @@ +/* + * linux/arch/arm/include/asm/pmu.h + * + * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles + * + * 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_PMU_H__ +#define __ARM_PMU_H__ + +#include +#include + +#include + +/* + * struct arm_pmu_platdata - ARM PMU platform data + * + * @handle_irq: an optional handler which will be called from the + * interrupt and passed the address of the low level handler, + * and can be used to implement any platform specific handling + * before or after calling it. + */ +struct arm_pmu_platdata { + irqreturn_t (*handle_irq)(int irq, void *dev, + irq_handler_t pmu_handler); +}; + +#ifdef CONFIG_ARM_PMU + +/* + * The ARMv7 CPU PMU supports up to 32 event counters. + */ +#define ARMPMU_MAX_HWEVENTS 32 + +#define HW_OP_UNSUPPORTED 0xFFFF +#define C(_x) PERF_COUNT_HW_CACHE_##_x +#define CACHE_OP_UNSUPPORTED 0xFFFF + +#define PERF_MAP_ALL_UNSUPPORTED \ + [0 ... PERF_COUNT_HW_MAX - 1] = HW_OP_UNSUPPORTED + +#define PERF_CACHE_MAP_ALL_UNSUPPORTED \ +[0 ... C(MAX) - 1] = { \ + [0 ... C(OP_MAX) - 1] = { \ + [0 ... C(RESULT_MAX) - 1] = CACHE_OP_UNSUPPORTED, \ + }, \ +} + +/* The events for a given PMU register set. */ +struct pmu_hw_events { + /* + * The events that are active on the PMU for the given index. + */ + struct perf_event *events[ARMPMU_MAX_HWEVENTS]; + + /* + * A 1 bit for an index indicates that the counter is being used for + * an event. A 0 means that the counter can be used. + */ + DECLARE_BITMAP(used_mask, ARMPMU_MAX_HWEVENTS); + + /* + * Hardware lock to serialize accesses to PMU registers. Needed for the + * read/modify/write sequences. + */ + raw_spinlock_t pmu_lock; + + /* + * When using percpu IRQs, we need a percpu dev_id. Place it here as we + * already have to allocate this struct per cpu. + */ + struct arm_pmu *percpu_pmu; +}; + +struct arm_pmu { + struct pmu pmu; + cpumask_t active_irqs; + cpumask_t supported_cpus; + int *irq_affinity; + char *name; + irqreturn_t (*handle_irq)(int irq_num, void *dev); + void (*enable)(struct perf_event *event); + void (*disable)(struct perf_event *event); + int (*get_event_idx)(struct pmu_hw_events *hw_events, + struct perf_event *event); + void (*clear_event_idx)(struct pmu_hw_events *hw_events, + struct perf_event *event); + int (*set_event_filter)(struct hw_perf_event *evt, + struct perf_event_attr *attr); + u32 (*read_counter)(struct perf_event *event); + void (*write_counter)(struct perf_event *event, u32 val); + void (*start)(struct arm_pmu *); + void (*stop)(struct arm_pmu *); + void (*reset)(void *); + int (*request_irq)(struct arm_pmu *, irq_handler_t handler); + void (*free_irq)(struct arm_pmu *); + int (*map_event)(struct perf_event *event); + int num_events; + atomic_t active_events; + struct mutex reserve_mutex; + u64 max_period; + struct platform_device *plat_device; + struct pmu_hw_events __percpu *hw_events; + struct notifier_block hotplug_nb; +}; + +#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) + +int armpmu_register(struct arm_pmu *armpmu, int type); + +u64 armpmu_event_update(struct perf_event *event); + +int armpmu_event_set_period(struct perf_event *event); + +int armpmu_map_event(struct perf_event *event, + const unsigned (*event_map)[PERF_COUNT_HW_MAX], + const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX], + u32 raw_event_mask); + +struct pmu_probe_info { + unsigned int cpuid; + unsigned int mask; + int (*init)(struct arm_pmu *); +}; + +#define PMU_PROBE(_cpuid, _mask, _fn) \ +{ \ + .cpuid = (_cpuid), \ + .mask = (_mask), \ + .init = (_fn), \ +} + +#define ARM_PMU_PROBE(_cpuid, _fn) \ + PMU_PROBE(_cpuid, ARM_CPU_PART_MASK, _fn) + +#define ARM_PMU_XSCALE_MASK ((0xff << 24) | ARM_CPU_XSCALE_ARCH_MASK) + +#define XSCALE_PMU_PROBE(_version, _fn) \ + PMU_PROBE(ARM_CPU_IMP_INTEL << 24 | _version, ARM_PMU_XSCALE_MASK, _fn) + +int arm_pmu_device_probe(struct platform_device *pdev, + const struct of_device_id *of_table, + const struct pmu_probe_info *probe_table); + +#endif /* CONFIG_ARM_PMU */ + +#endif /* __ARM_PMU_H__ */ -- cgit v1.3-6-gb490 From dd02ea5a33059e4a753ae8bb877b698c54ee2907 Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Fri, 31 Jul 2015 13:46:07 +0200 Subject: usb: gadget: mass_storage: Use static array for luns This patch replace dynamicly allocated luns array with static one. This simplifies the code of mass storage function and modules. Signed-off-by: Krzysztof Opasiak Acked-by: Michal Nazarewicz --- drivers/usb/gadget/function/f_mass_storage.c | 127 ++++++++++----------------- drivers/usb/gadget/function/f_mass_storage.h | 4 - drivers/usb/gadget/legacy/acm_ms.c | 6 -- drivers/usb/gadget/legacy/mass_storage.c | 6 -- drivers/usb/gadget/legacy/multi.c | 6 -- drivers/usb/gadget/legacy/nokia.c | 14 +-- 6 files changed, 50 insertions(+), 113 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 9870913e34bf..04c3bb6e9dcd 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -279,9 +279,8 @@ struct fsg_common { int cmnd_size; u8 cmnd[MAX_COMMAND_SIZE]; - unsigned int nluns; unsigned int lun; - struct fsg_lun **luns; + struct fsg_lun *luns[FSG_MAX_LUNS]; struct fsg_lun *curlun; unsigned int bulk_out_maxpacket; @@ -490,6 +489,16 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) spin_unlock(&common->lock); } +static int _fsg_common_get_max_lun(struct fsg_common *common) +{ + int i = ARRAY_SIZE(common->luns) - 1; + + while (i >= 0 && !common->luns[i]) + --i; + + return i; +} + static int fsg_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { @@ -533,7 +542,7 @@ static int fsg_setup(struct usb_function *f, w_length != 1) return -EDOM; VDBG(fsg, "get max LUN\n"); - *(u8 *)req->buf = fsg->common->nluns - 1; + *(u8 *)req->buf = _fsg_common_get_max_lun(fsg->common); /* Respond with data/status */ req->length = min((u16)1, w_length); @@ -2131,8 +2140,9 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) } /* Is the CBW meaningful? */ - if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN || - cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { + if (cbw->Lun >= ARRAY_SIZE(common->luns) || + cbw->Flags & ~US_BULK_FLAG_IN || cbw->Length <= 0 || + cbw->Length > MAX_COMMAND_SIZE) { DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " "cmdlen %u\n", cbw->Lun, cbw->Flags, cbw->Length); @@ -2159,7 +2169,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) if (common->data_size == 0) common->data_dir = DATA_DIR_NONE; common->lun = cbw->Lun; - if (common->lun < common->nluns) + if (common->lun < ARRAY_SIZE(common->luns)) common->curlun = common->luns[common->lun]; else common->curlun = NULL; @@ -2307,7 +2317,7 @@ reset: } common->running = 1; - for (i = 0; i < common->nluns; ++i) + for (i = 0; i < ARRAY_SIZE(common->luns); ++i) if (common->luns[i]) common->luns[i]->unit_attention_data = SS_RESET_OCCURRED; @@ -2409,7 +2419,7 @@ static void handle_exception(struct fsg_common *common) if (old_state == FSG_STATE_ABORT_BULK_OUT) common->state = FSG_STATE_STATUS_PHASE; else { - for (i = 0; i < common->nluns; ++i) { + for (i = 0; i < ARRAY_SIZE(common->luns); ++i) { curlun = common->luns[i]; if (!curlun) continue; @@ -2453,7 +2463,7 @@ static void handle_exception(struct fsg_common *common) * a waste of time. Ditto for the INTERFACE_CHANGE and * CONFIG_CHANGE cases. */ - /* for (i = 0; i < common->nluns; ++i) */ + /* for (i = 0; i < common->ARRAY_SIZE(common->luns); ++i) */ /* if (common->luns[i]) */ /* common->luns[i]->unit_attention_data = */ /* SS_RESET_OCCURRED; */ @@ -2552,12 +2562,11 @@ static int fsg_main_thread(void *common_) if (!common->ops || !common->ops->thread_exits || common->ops->thread_exits(common) < 0) { - struct fsg_lun **curlun_it = common->luns; - unsigned i = common->nluns; + int i; down_write(&common->filesem); - for (; i--; ++curlun_it) { - struct fsg_lun *curlun = *curlun_it; + for (i = 0; i < ARRAY_SIZE(common->luns); --i) { + struct fsg_lun *curlun = common->luns[i]; if (!curlun || !fsg_lun_is_open(curlun)) continue; @@ -2676,6 +2685,7 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common) init_completion(&common->thread_notifier); init_waitqueue_head(&common->fsg_wait); common->state = FSG_STATE_TERMINATED; + memset(common->luns, 0, sizeof(common->luns)); return common; } @@ -2764,42 +2774,10 @@ static void _fsg_common_remove_luns(struct fsg_common *common, int n) void fsg_common_remove_luns(struct fsg_common *common) { - _fsg_common_remove_luns(common, common->nluns); + _fsg_common_remove_luns(common, ARRAY_SIZE(common->luns)); } EXPORT_SYMBOL_GPL(fsg_common_remove_luns); -void fsg_common_free_luns(struct fsg_common *common) -{ - fsg_common_remove_luns(common); - kfree(common->luns); - common->luns = NULL; -} -EXPORT_SYMBOL_GPL(fsg_common_free_luns); - -int fsg_common_set_nluns(struct fsg_common *common, int nluns) -{ - struct fsg_lun **curlun; - - /* Find out how many LUNs there should be */ - if (nluns < 1 || nluns > FSG_MAX_LUNS) { - pr_err("invalid number of LUNs: %u\n", nluns); - return -EINVAL; - } - - curlun = kcalloc(FSG_MAX_LUNS, sizeof(*curlun), GFP_KERNEL); - if (unlikely(!curlun)) - return -ENOMEM; - - if (common->luns) - fsg_common_free_luns(common); - - common->luns = curlun; - common->nluns = nluns; - - return 0; -} -EXPORT_SYMBOL_GPL(fsg_common_set_nluns); - void fsg_common_set_ops(struct fsg_common *common, const struct fsg_operations *ops) { @@ -2881,7 +2859,7 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, char *pathbuf, *p; int rc = -ENOMEM; - if (!common->nluns || !common->luns) + if (id >= ARRAY_SIZE(common->luns)) return -ENODEV; if (common->luns[id]) @@ -2965,14 +2943,16 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg) char buf[8]; /* enough for 100000000 different numbers, decimal */ int i, rc; - for (i = 0; i < common->nluns; ++i) { + fsg_common_remove_luns(common); + + for (i = 0; i < cfg->nluns; ++i) { snprintf(buf, sizeof(buf), "lun%d", i); rc = fsg_common_create_lun(common, &cfg->luns[i], i, buf, NULL); if (rc) goto fail; } - pr_info("Number of LUNs=%d\n", common->nluns); + pr_info("Number of LUNs=%d\n", cfg->nluns); return 0; @@ -3021,6 +3001,7 @@ EXPORT_SYMBOL_GPL(fsg_common_run_thread); static void fsg_common_release(struct kref *ref) { struct fsg_common *common = container_of(ref, struct fsg_common, ref); + int i; /* If the thread isn't already dead, tell it to exit now */ if (common->state != FSG_STATE_TERMINATED) { @@ -3028,22 +3009,14 @@ static void fsg_common_release(struct kref *ref) wait_for_completion(&common->thread_notifier); } - if (likely(common->luns)) { - struct fsg_lun **lun_it = common->luns; - unsigned i = common->nluns; - - /* In error recovery common->nluns may be zero. */ - for (; i; --i, ++lun_it) { - struct fsg_lun *lun = *lun_it; - if (!lun) - continue; - fsg_lun_close(lun); + for (i = 0; i < ARRAY_SIZE(common->luns); ++i) { + struct fsg_lun *lun = common->luns[i]; + if (!lun) + continue; + fsg_lun_close(lun); if (device_is_registered(&lun->dev)) - device_unregister(&lun->dev); - kfree(lun); - } - - kfree(common->luns); + device_unregister(&lun->dev); + kfree(lun); } _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); @@ -3057,6 +3030,7 @@ static void fsg_common_release(struct kref *ref) static int fsg_bind(struct usb_configuration *c, struct usb_function *f) { struct fsg_dev *fsg = fsg_from_func(f); + struct fsg_common *common = fsg->common; struct usb_gadget *gadget = c->cdev->gadget; int i; struct usb_ep *ep; @@ -3064,6 +3038,13 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) int ret; struct fsg_opts *opts; + /* Don't allow to bind if we don't have at least one LUN */ + ret = _fsg_common_get_max_lun(common); + if (ret < 0) { + pr_err("There should be at least one LUN.\n"); + return -EINVAL; + } + opts = fsg_opts_from_func_inst(f->fi); if (!opts->no_configfs) { ret = fsg_common_set_cdev(fsg->common, c->cdev, @@ -3517,14 +3498,11 @@ static struct usb_function_instance *fsg_alloc_inst(void) rc = PTR_ERR(opts->common); goto release_opts; } - rc = fsg_common_set_nluns(opts->common, FSG_MAX_LUNS); - if (rc) - goto release_opts; rc = fsg_common_set_num_buffers(opts->common, CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS); if (rc) - goto release_luns; + goto release_opts; pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); @@ -3547,8 +3525,6 @@ static struct usb_function_instance *fsg_alloc_inst(void) release_buffers: fsg_common_free_buffers(opts->common); -release_luns: - kfree(opts->common->luns); release_opts: kfree(opts); return ERR_PTR(rc); @@ -3574,23 +3550,12 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi) struct fsg_opts *opts = fsg_opts_from_func_inst(fi); struct fsg_common *common = opts->common; struct fsg_dev *fsg; - unsigned nluns, i; fsg = kzalloc(sizeof(*fsg), GFP_KERNEL); if (unlikely(!fsg)) return ERR_PTR(-ENOMEM); mutex_lock(&opts->lock); - if (!opts->refcnt) { - for (nluns = i = 0; i < FSG_MAX_LUNS; ++i) - if (common->luns[i]) - nluns = i + 1; - if (!nluns) - pr_warn("No LUNS defined, continuing anyway\n"); - else - common->nluns = nluns; - pr_info("Number of LUNs=%u\n", common->nluns); - } opts->refcnt++; mutex_unlock(&opts->lock); diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h index 37bc94cbb7f3..445df6775609 100644 --- a/drivers/usb/gadget/function/f_mass_storage.h +++ b/drivers/usb/gadget/function/f_mass_storage.h @@ -141,10 +141,6 @@ void fsg_common_remove_lun(struct fsg_lun *lun); void fsg_common_remove_luns(struct fsg_common *common); -void fsg_common_free_luns(struct fsg_common *common); - -int fsg_common_set_nluns(struct fsg_common *common, int nluns); - void fsg_common_set_ops(struct fsg_common *common, const struct fsg_operations *ops); diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index 4d8adb48b8a7..4b158e2d1e57 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -186,10 +186,6 @@ static int acm_ms_bind(struct usb_composite_dev *cdev) if (status) goto fail; - status = fsg_common_set_nluns(opts->common, config.nluns); - if (status) - goto fail_set_nluns; - status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); if (status) goto fail_set_cdev; @@ -239,8 +235,6 @@ fail_otg_desc: fail_string_ids: fsg_common_remove_luns(opts->common); fail_set_cdev: - fsg_common_free_luns(opts->common); -fail_set_nluns: fsg_common_free_buffers(opts->common); fail: usb_put_function_instance(fi_msg); diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c index ab1a42ce75d2..bda3c519110f 100644 --- a/drivers/usb/gadget/legacy/mass_storage.c +++ b/drivers/usb/gadget/legacy/mass_storage.c @@ -177,10 +177,6 @@ static int msg_bind(struct usb_composite_dev *cdev) if (status) goto fail; - status = fsg_common_set_nluns(opts->common, config.nluns); - if (status) - goto fail_set_nluns; - fsg_common_set_ops(opts->common, &ops); status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); @@ -227,8 +223,6 @@ fail_otg_desc: fail_string_ids: fsg_common_remove_luns(opts->common); fail_set_cdev: - fsg_common_free_luns(opts->common); -fail_set_nluns: fsg_common_free_buffers(opts->common); fail: usb_put_function_instance(fi_msg); diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c index c38ead1d67a4..4fe794ddcd49 100644 --- a/drivers/usb/gadget/legacy/multi.c +++ b/drivers/usb/gadget/legacy/multi.c @@ -393,10 +393,6 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) if (status) goto fail2; - status = fsg_common_set_nluns(fsg_opts->common, config.nluns); - if (status) - goto fail_set_nluns; - status = fsg_common_set_cdev(fsg_opts->common, cdev, config.can_stall); if (status) goto fail_set_cdev; @@ -448,8 +444,6 @@ fail_otg_desc: fail_string_ids: fsg_common_remove_luns(fsg_opts->common); fail_set_cdev: - fsg_common_free_luns(fsg_opts->common); -fail_set_nluns: fsg_common_free_buffers(fsg_opts->common); fail2: usb_put_function_instance(fi_msg); diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index 264c97e15478..c20f3b58f126 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -339,19 +339,15 @@ static int nokia_bind(struct usb_composite_dev *cdev) if (status) goto err_msg_inst; - status = fsg_common_set_nluns(fsg_opts->common, fsg_config.nluns); - if (status) - goto err_msg_buf; - status = fsg_common_set_cdev(fsg_opts->common, cdev, fsg_config.can_stall); if (status) - goto err_msg_set_nluns; + goto err_msg_buf; fsg_common_set_sysfs(fsg_opts->common, true); status = fsg_common_create_luns(fsg_opts->common, &fsg_config); if (status) - goto err_msg_set_nluns; + goto err_msg_buf; fsg_common_set_inquiry_string(fsg_opts->common, fsg_config.vendor_name, fsg_config.product_name); @@ -360,7 +356,7 @@ static int nokia_bind(struct usb_composite_dev *cdev) status = usb_add_config(cdev, &nokia_config_500ma_driver, nokia_bind_config); if (status < 0) - goto err_msg_set_cdev; + goto err_msg_luns; status = usb_add_config(cdev, &nokia_config_100ma_driver, nokia_bind_config); @@ -381,10 +377,8 @@ err_put_cfg1: if (!IS_ERR_OR_NULL(f_phonet_cfg1)) usb_put_function(f_phonet_cfg1); usb_put_function(f_ecm_cfg1); -err_msg_set_cdev: +err_msg_luns: fsg_common_remove_luns(fsg_opts->common); -err_msg_set_nluns: - fsg_common_free_luns(fsg_opts->common); err_msg_buf: fsg_common_free_buffers(fsg_opts->common); err_msg_inst: -- cgit v1.3-6-gb490 From 98c7863c36bdf20c07e38d8bea5261902b52f98d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:27 +0200 Subject: spi: xcomm: Export I2C module alias information The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Mark Brown --- drivers/spi/spi-xcomm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index d0561a8d9f16..3c28e24b10f5 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -237,6 +237,7 @@ static const struct i2c_device_id spi_xcomm_ids[] = { { "spi-xcomm" }, { }, }; +MODULE_DEVICE_TABLE(i2c, spi_xcomm_ids); static struct i2c_driver spi_xcomm_driver = { .driver = { -- cgit v1.3-6-gb490 From e80c47bd738badeaa70b1114d4cd75f892672bd3 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:40 +0200 Subject: regulator: fan53555: Export I2C module alias information The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Mark Brown --- drivers/regulator/fan53555.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index 42865681c00b..4940e8287df6 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -439,6 +439,7 @@ static const struct i2c_device_id fan53555_id[] = { }, { }, }; +MODULE_DEVICE_TABLE(i2c, fan53555_id); static struct i2c_driver fan53555_regulator_driver = { .driver = { -- cgit v1.3-6-gb490 From 34cadd9c1bcbd5ad5a1f379b013526a8046d4aed Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 30 Jul 2015 16:30:07 +0300 Subject: spi: pxa2xx: Add support for Intel Sunrisepoint Major difference in LPSS SPI between Intel Sunrisepoint PCH and earlier platforms is an integrated DMA (iDMA) engine. iDMA is an IP that is private for each LPSS host controller (UART/SPI/I2C). Other differences are private register space offset, a few private registers that are in different location and FIFO thresholds. Intel Sunrisepoint LPSS SPI and iDMA devices are probed and registered in MFD layer as platform devices. Here these compound devices are detected by matching against known PCI IDs. This allows us to share pxa2xx_spi_acpi_get_pdata() for setting up the platform data instead of duplicating it in MFD part. This patch adds configuration for Intel Sunrisepoint LPSS SPI, above detection and DMA filter function that picks the DMA channel only from an associated iDMA block. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 59 ++++++++++++++++++++++++++++++++++++++++++---- include/linux/pxa2xx_ssp.h | 1 + 2 files changed, 56 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 7293d6d875c5..2c9fa409d2bf 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,15 @@ static const struct lpss_config lpss_platforms[] = { .tx_threshold_lo = 160, .tx_threshold_hi = 224, }, + { /* LPSS_SPT_SSP */ + .offset = 0x200, + .reg_general = -1, + .reg_ssp = 0x20, + .reg_cs_ctrl = 0x24, + .rx_threshold = 1, + .tx_threshold_lo = 32, + .tx_threshold_hi = 56, + }, }; static inline const struct lpss_config @@ -110,6 +120,7 @@ static bool is_lpss_ssp(const struct driver_data *drv_data) switch (drv_data->ssp_type) { case LPSS_LPT_SSP: case LPSS_BYT_SSP: + case LPSS_SPT_SSP: return true; default: return false; @@ -1107,6 +1118,7 @@ static int setup(struct spi_device *spi) break; case LPSS_LPT_SSP: case LPSS_BYT_SSP: + case LPSS_SPT_SSP: config = lpss_get_config(drv_data); tx_thres = config->tx_threshold_lo; tx_hi_thres = config->tx_threshold_hi; @@ -1276,6 +1288,30 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); +/* + * PCI IDs of compound devices that integrate both host controller and private + * integrated DMA engine. Please note these are not used in module + * autoloading and probing in this module but matching the LPSS SSP type. + */ +static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { + /* SPT-LP */ + { PCI_VDEVICE(INTEL, 0x9d29), LPSS_SPT_SSP }, + { PCI_VDEVICE(INTEL, 0x9d2a), LPSS_SPT_SSP }, + /* SPT-H */ + { PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP }, + { PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP }, +}; + +static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param) +{ + struct device *dev = param; + + if (dev != chan->device->dev->parent) + return false; + + return true; +} + static struct pxa2xx_spi_master * pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) { @@ -1283,16 +1319,25 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) struct acpi_device *adev; struct ssp_device *ssp; struct resource *res; - const struct acpi_device_id *id; + const struct acpi_device_id *adev_id = NULL; + const struct pci_device_id *pcidev_id = NULL; int devid, type; if (!ACPI_HANDLE(&pdev->dev) || acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev)) return NULL; - id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); - if (id) - type = (int)id->driver_data; + if (dev_is_pci(pdev->dev.parent)) + pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match, + to_pci_dev(pdev->dev.parent)); + else + adev_id = acpi_match_device(pdev->dev.driver->acpi_match_table, + &pdev->dev); + + if (adev_id) + type = (int)adev_id->driver_data; + else if (pcidev_id) + type = (int)pcidev_id->driver_data; else return NULL; @@ -1311,6 +1356,12 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev) if (IS_ERR(ssp->mmio_base)) return NULL; + if (pcidev_id) { + pdata->tx_param = pdev->dev.parent; + pdata->rx_param = pdev->dev.parent; + pdata->dma_filter = pxa2xx_spi_idma_filter; + } + ssp->clk = devm_clk_get(&pdev->dev, NULL); ssp->irq = platform_get_irq(pdev, 0); ssp->type = type; diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h index 0485bab061fd..92273776bce6 100644 --- a/include/linux/pxa2xx_ssp.h +++ b/include/linux/pxa2xx_ssp.h @@ -197,6 +197,7 @@ enum pxa_ssp_type { QUARK_X1000_SSP, LPSS_LPT_SSP, /* Keep LPSS types sorted with lpss_platforms[] */ LPSS_BYT_SSP, + LPSS_SPT_SSP, }; struct ssp_device { -- cgit v1.3-6-gb490 From 0b7367017087cfe6f4514eb9e9c108ac8d6a101b Mon Sep 17 00:00:00 2001 From: Joel Porquet Date: Tue, 7 Jul 2015 17:18:23 -0400 Subject: irqchip: Remove header drivers/irqchip/irqchip.h All drivers using the macro IRQCHIP_DECLARE have been converted to using global header include/linux/irqchip.h. Local header drivers/irqchip/irqchip.h is now useless and can be removed. Signed-off-by: Joel Porquet Cc: vgupta@synopsys.com Cc: monstr@monstr.eu Cc: ralf@linux-mips.org Cc: jason@lakedaemon.net Link: http://lkml.kernel.org/r/2818400.nekF4hg2Ig@joel-zenbook Signed-off-by: Thomas Gleixner --- drivers/irqchip/irqchip.h | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 drivers/irqchip/irqchip.h (limited to 'drivers') diff --git a/drivers/irqchip/irqchip.h b/drivers/irqchip/irqchip.h deleted file mode 100644 index 0f67ae32464f..000000000000 --- a/drivers/irqchip/irqchip.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (C) 2012 Thomas Petazzoni - * - * 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. - */ - -#include -- cgit v1.3-6-gb490 From 0b275352872b2641ed5c94d0f0f8c7e907bf3e3f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 29 Jul 2015 03:03:44 +0200 Subject: cpufreq: Separate CPU device registration from CPU online To separate the CPU online interface from the CPU device registration, split cpufreq_online() out of cpufreq_add_dev() and make cpufreq_cpu_callback() call the former, while cpufreq_add_dev() itself will only be used as the CPU device addition subsystem interface callback. Signed-off-by: Rafael J. Wysocki Suggested-by: Russell King Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 90 +++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0618522d4863..0d46b557c016 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1191,36 +1191,15 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy, bool notify) kfree(policy); } -/** - * cpufreq_add_dev - add a CPU device - * - * Adds the cpufreq interface for a CPU device. - * - * The Oracle says: try running cpufreq registration/unregistration concurrently - * with with cpu hotplugging and all hell will break loose. Tried to clean this - * mess up, but more thorough testing is needed. - Mathieu - */ -static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) +static int cpufreq_online(unsigned int cpu) { - unsigned int j, cpu = dev->id; - int ret; struct cpufreq_policy *policy; - unsigned long flags; bool recover_policy; + unsigned long flags; + unsigned int j; + int ret; - pr_debug("adding CPU %u\n", cpu); - - if (cpu_is_offline(cpu)) { - /* - * Only possible if we are here from the subsys_interface add - * callback. A hotplug notifier will follow and we will handle - * it as CPU online then. For now, just create the sysfs link, - * unless there is no policy or the link is already present. - */ - policy = per_cpu(cpufreq_cpu_data, cpu); - return policy && !cpumask_test_and_set_cpu(cpu, policy->real_cpus) - ? add_cpu_dev_symlink(policy, cpu) : 0; - } + pr_debug("%s: bringing CPU%u online\n", __func__, cpu); /* Check if this CPU already has a policy to manage it */ policy = per_cpu(cpufreq_cpu_data, cpu); @@ -1377,6 +1356,35 @@ out_free_policy: return ret; } +/** + * cpufreq_add_dev - the cpufreq interface for a CPU device. + * @dev: CPU device. + * @sif: Subsystem interface structure pointer (not used) + */ +static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) +{ + unsigned cpu = dev->id; + int ret; + + dev_dbg(dev, "%s: adding CPU%u\n", __func__, cpu); + + if (cpu_online(cpu)) { + ret = cpufreq_online(cpu); + } else { + /* + * A hotplug notifier will follow and we will handle it as CPU + * online then. For now, just create the sysfs link, unless + * there is no policy or the link is already present. + */ + struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); + + ret = policy && !cpumask_test_and_set_cpu(cpu, policy->real_cpus) + ? add_cpu_dev_symlink(policy, cpu) : 0; + } + + return ret; +} + static void cpufreq_offline_prepare(unsigned int cpu) { struct cpufreq_policy *policy; @@ -2340,27 +2348,23 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; - struct device *dev; - dev = get_cpu_device(cpu); - if (dev) { - switch (action & ~CPU_TASKS_FROZEN) { - case CPU_ONLINE: - cpufreq_add_dev(dev, NULL); - break; + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_ONLINE: + cpufreq_online(cpu); + break; - case CPU_DOWN_PREPARE: - cpufreq_offline_prepare(cpu); - break; + case CPU_DOWN_PREPARE: + cpufreq_offline_prepare(cpu); + break; - case CPU_POST_DEAD: - cpufreq_offline_finish(cpu); - break; + case CPU_POST_DEAD: + cpufreq_offline_finish(cpu); + break; - case CPU_DOWN_FAILED: - cpufreq_add_dev(dev, NULL); - break; - } + case CPU_DOWN_FAILED: + cpufreq_online(cpu); + break; } return NOTIFY_OK; } -- cgit v1.3-6-gb490 From 194d99c7e3ce54a8c7d8adf79fb1d8ad49a9bf9f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 29 Jul 2015 03:08:57 +0200 Subject: cpufreq: Replace recover_policy with new_policy in cpufreq_online() The recover_policy is unsed in cpufreq_online() to indicate whether a new policy object is created or an existing one is reinitialized. The "recover" part of the name is slightly confusing (it should be "reinitialization" rather than "recovery") and the logical not (!) operator is applied to it in almost all of the checks it is used in, so replace that variable with a new one called "new_policy" that will be true in the case of a new policy creation. While at it, drop one of the labels that is jumped to from only one spot. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0d46b557c016..24e4ba568e77 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1194,7 +1194,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy, bool notify) static int cpufreq_online(unsigned int cpu) { struct cpufreq_policy *policy; - bool recover_policy; + bool new_policy; unsigned long flags; unsigned int j; int ret; @@ -1209,13 +1209,13 @@ static int cpufreq_online(unsigned int cpu) return cpufreq_add_policy_cpu(policy, cpu); /* This is the only online CPU for the policy. Start over. */ - recover_policy = true; + new_policy = false; down_write(&policy->rwsem); policy->cpu = cpu; policy->governor = NULL; up_write(&policy->rwsem); } else { - recover_policy = false; + new_policy = true; policy = cpufreq_policy_alloc(cpu); if (!policy) return -ENOMEM; @@ -1234,7 +1234,7 @@ static int cpufreq_online(unsigned int cpu) down_write(&policy->rwsem); - if (!recover_policy) { + if (new_policy) { /* related_cpus should at least include policy->cpus. */ cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus); /* Remember CPUs present at the policy creation time. */ @@ -1247,7 +1247,7 @@ static int cpufreq_online(unsigned int cpu) */ cpumask_and(policy->cpus, policy->cpus, cpu_online_mask); - if (!recover_policy) { + if (new_policy) { policy->user_policy.min = policy->min; policy->user_policy.max = policy->max; @@ -1308,7 +1308,7 @@ static int cpufreq_online(unsigned int cpu) blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_START, policy); - if (!recover_policy) { + if (new_policy) { ret = cpufreq_add_dev_interface(policy); if (ret) goto out_exit_policy; @@ -1324,10 +1324,12 @@ static int cpufreq_online(unsigned int cpu) if (ret) { pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n", __func__, cpu, ret); - goto out_remove_policy_notify; + /* cpufreq_policy_free() will notify based on this */ + new_policy = false; + goto out_exit_policy; } - if (!recover_policy) { + if (new_policy) { policy->user_policy.policy = policy->policy; policy->user_policy.governor = policy->governor; } @@ -1343,16 +1345,13 @@ static int cpufreq_online(unsigned int cpu) return 0; -out_remove_policy_notify: - /* cpufreq_policy_free() will notify based on this */ - recover_policy = true; out_exit_policy: up_write(&policy->rwsem); if (cpufreq_driver->exit) cpufreq_driver->exit(policy); out_free_policy: - cpufreq_policy_free(policy, recover_policy); + cpufreq_policy_free(policy, !new_policy); return ret; } -- cgit v1.3-6-gb490 From fdd320da84c63092fe6e155cb7b8d80f7f765fa9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 30 Jul 2015 01:45:07 +0200 Subject: cpufreq: Lock CPU online/offline in cpufreq_register_driver() To protect against races with concurrent CPU online/offline, call get_online_cpus() before registering a cpufreq driver. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 24e4ba568e77..0f4e96ff99e8 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2471,10 +2471,14 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) pr_debug("trying to register driver %s\n", driver_data->name); + /* Protect against concurrent CPU online/offline. */ + get_online_cpus(); + write_lock_irqsave(&cpufreq_driver_lock, flags); if (cpufreq_driver) { write_unlock_irqrestore(&cpufreq_driver_lock, flags); - return -EEXIST; + ret = -EEXIST; + goto out; } cpufreq_driver = driver_data; write_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -2513,7 +2517,10 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) register_hotcpu_notifier(&cpufreq_cpu_notifier); pr_debug("driver %s up and running\n", driver_data->name); - return 0; +out: + put_online_cpus(); + return ret; + err_if_unreg: subsys_interface_unregister(&cpufreq_interface); err_boost_unreg: @@ -2523,7 +2530,7 @@ err_null_driver: write_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_driver = NULL; write_unlock_irqrestore(&cpufreq_driver_lock, flags); - return ret; + goto out; } EXPORT_SYMBOL_GPL(cpufreq_register_driver); -- cgit v1.3-6-gb490 From 0509cfde038d8afb0c1df1d52c90ae847b425d97 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 8 Jul 2015 14:46:08 +0200 Subject: MIPS/irqchip: Move i8259 irqchip driver to drivers/irqchip Signed-off-by: Ralf Baechle Signed-off-by: Thomas Gleixner --- arch/mips/Kconfig | 4 - arch/mips/kernel/Makefile | 1 - arch/mips/kernel/i8259.c | 383 -------------------------------------------- drivers/irqchip/Kconfig | 4 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-i8259.c | 383 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 388 insertions(+), 388 deletions(-) delete mode 100644 arch/mips/kernel/i8259.c create mode 100644 drivers/irqchip/irq-i8259.c (limited to 'drivers') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index cee5f93e5712..d61297252006 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1071,10 +1071,6 @@ config HOTPLUG_CPU config SYS_SUPPORTS_HOTPLUG_CPU bool -config I8259 - bool - select IRQ_DOMAIN - config MIPS_BONITO64 bool diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 3f5cf8aff6f3..3156c8d253c1 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -61,7 +61,6 @@ obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o obj-$(CONFIG_MIPS_VPE_APSP_API_CMP) += rtlx-cmp.o obj-$(CONFIG_MIPS_VPE_APSP_API_MT) += rtlx-mt.o -obj-$(CONFIG_I8259) += i8259.o obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o obj-$(CONFIG_MIPS_MSC) += irq-msc01.o obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c deleted file mode 100644 index a8acee7eab92..000000000000 --- a/arch/mips/kernel/i8259.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Code to handle x86 style IRQs plus some generic interrupt stuff. - * - * Copyright (C) 1992 Linus Torvalds - * Copyright (C) 1994 - 2000 Ralf Baechle - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* - * This is the 'legacy' 8259A Programmable Interrupt Controller, - * present in the majority of PC/AT boxes. - * plus some generic x86 specific things if generic specifics makes - * any sense at all. - * this file should become arch/i386/kernel/irq.c when the old irq.c - * moves to arch independent land - */ - -static int i8259A_auto_eoi = -1; -DEFINE_RAW_SPINLOCK(i8259A_lock); -static void disable_8259A_irq(struct irq_data *d); -static void enable_8259A_irq(struct irq_data *d); -static void mask_and_ack_8259A(struct irq_data *d); -static void init_8259A(int auto_eoi); - -static struct irq_chip i8259A_chip = { - .name = "XT-PIC", - .irq_mask = disable_8259A_irq, - .irq_disable = disable_8259A_irq, - .irq_unmask = enable_8259A_irq, - .irq_mask_ack = mask_and_ack_8259A, -}; - -/* - * 8259A PIC functions to handle ISA devices: - */ - -/* - * This contains the irq mask for both 8259A irq controllers, - */ -static unsigned int cached_irq_mask = 0xffff; - -#define cached_master_mask (cached_irq_mask) -#define cached_slave_mask (cached_irq_mask >> 8) - -static void disable_8259A_irq(struct irq_data *d) -{ - unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; - unsigned long flags; - - mask = 1 << irq; - raw_spin_lock_irqsave(&i8259A_lock, flags); - cached_irq_mask |= mask; - if (irq & 8) - outb(cached_slave_mask, PIC_SLAVE_IMR); - else - outb(cached_master_mask, PIC_MASTER_IMR); - raw_spin_unlock_irqrestore(&i8259A_lock, flags); -} - -static void enable_8259A_irq(struct irq_data *d) -{ - unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; - unsigned long flags; - - mask = ~(1 << irq); - raw_spin_lock_irqsave(&i8259A_lock, flags); - cached_irq_mask &= mask; - if (irq & 8) - outb(cached_slave_mask, PIC_SLAVE_IMR); - else - outb(cached_master_mask, PIC_MASTER_IMR); - raw_spin_unlock_irqrestore(&i8259A_lock, flags); -} - -int i8259A_irq_pending(unsigned int irq) -{ - unsigned int mask; - unsigned long flags; - int ret; - - irq -= I8259A_IRQ_BASE; - mask = 1 << irq; - raw_spin_lock_irqsave(&i8259A_lock, flags); - if (irq < 8) - ret = inb(PIC_MASTER_CMD) & mask; - else - ret = inb(PIC_SLAVE_CMD) & (mask >> 8); - raw_spin_unlock_irqrestore(&i8259A_lock, flags); - - return ret; -} - -void make_8259A_irq(unsigned int irq) -{ - disable_irq_nosync(irq); - irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq); - enable_irq(irq); -} - -/* - * This function assumes to be called rarely. Switching between - * 8259A registers is slow. - * This has to be protected by the irq controller spinlock - * before being called. - */ -static inline int i8259A_irq_real(unsigned int irq) -{ - int value; - int irqmask = 1 << irq; - - if (irq < 8) { - outb(0x0B, PIC_MASTER_CMD); /* ISR register */ - value = inb(PIC_MASTER_CMD) & irqmask; - outb(0x0A, PIC_MASTER_CMD); /* back to the IRR register */ - return value; - } - outb(0x0B, PIC_SLAVE_CMD); /* ISR register */ - value = inb(PIC_SLAVE_CMD) & (irqmask >> 8); - outb(0x0A, PIC_SLAVE_CMD); /* back to the IRR register */ - return value; -} - -/* - * Careful! The 8259A is a fragile beast, it pretty - * much _has_ to be done exactly like this (mask it - * first, _then_ send the EOI, and the order of EOI - * to the two 8259s is important! - */ -static void mask_and_ack_8259A(struct irq_data *d) -{ - unsigned int irqmask, irq = d->irq - I8259A_IRQ_BASE; - unsigned long flags; - - irqmask = 1 << irq; - raw_spin_lock_irqsave(&i8259A_lock, flags); - /* - * Lightweight spurious IRQ detection. We do not want - * to overdo spurious IRQ handling - it's usually a sign - * of hardware problems, so we only do the checks we can - * do without slowing down good hardware unnecessarily. - * - * Note that IRQ7 and IRQ15 (the two spurious IRQs - * usually resulting from the 8259A-1|2 PICs) occur - * even if the IRQ is masked in the 8259A. Thus we - * can check spurious 8259A IRQs without doing the - * quite slow i8259A_irq_real() call for every IRQ. - * This does not cover 100% of spurious interrupts, - * but should be enough to warn the user that there - * is something bad going on ... - */ - if (cached_irq_mask & irqmask) - goto spurious_8259A_irq; - cached_irq_mask |= irqmask; - -handle_real_irq: - if (irq & 8) { - inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */ - outb(cached_slave_mask, PIC_SLAVE_IMR); - outb(0x60+(irq&7), PIC_SLAVE_CMD);/* 'Specific EOI' to slave */ - outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */ - } else { - inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */ - outb(cached_master_mask, PIC_MASTER_IMR); - outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */ - } - raw_spin_unlock_irqrestore(&i8259A_lock, flags); - return; - -spurious_8259A_irq: - /* - * this is the slow path - should happen rarely. - */ - if (i8259A_irq_real(irq)) - /* - * oops, the IRQ _is_ in service according to the - * 8259A - not spurious, go handle it. - */ - goto handle_real_irq; - - { - static int spurious_irq_mask; - /* - * At this point we can be sure the IRQ is spurious, - * lets ACK and report it. [once per IRQ] - */ - if (!(spurious_irq_mask & irqmask)) { - printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); - spurious_irq_mask |= irqmask; - } - atomic_inc(&irq_err_count); - /* - * Theoretically we do not have to handle this IRQ, - * but in Linux this does not cause problems and is - * simpler for us. - */ - goto handle_real_irq; - } -} - -static void i8259A_resume(void) -{ - if (i8259A_auto_eoi >= 0) - init_8259A(i8259A_auto_eoi); -} - -static void i8259A_shutdown(void) -{ - /* Put the i8259A into a quiescent state that - * the kernel initialization code can get it - * out of. - */ - if (i8259A_auto_eoi >= 0) { - outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ - outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ - } -} - -static struct syscore_ops i8259_syscore_ops = { - .resume = i8259A_resume, - .shutdown = i8259A_shutdown, -}; - -static int __init i8259A_init_sysfs(void) -{ - register_syscore_ops(&i8259_syscore_ops); - return 0; -} - -device_initcall(i8259A_init_sysfs); - -static void init_8259A(int auto_eoi) -{ - unsigned long flags; - - i8259A_auto_eoi = auto_eoi; - - raw_spin_lock_irqsave(&i8259A_lock, flags); - - outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ - outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ - - /* - * outb_p - this has to work on a wide range of PC hardware. - */ - outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */ - outb_p(I8259A_IRQ_BASE + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0 mapped to I8259A_IRQ_BASE + 0x00 */ - outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */ - if (auto_eoi) /* master does Auto EOI */ - outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR); - else /* master expects normal EOI */ - outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR); - - outb_p(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */ - outb_p(I8259A_IRQ_BASE + 8, PIC_SLAVE_IMR); /* ICW2: 8259A-2 IR0 mapped to I8259A_IRQ_BASE + 0x08 */ - outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); /* 8259A-2 is a slave on master's IR2 */ - outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ - if (auto_eoi) - /* - * In AEOI mode we just have to mask the interrupt - * when acking. - */ - i8259A_chip.irq_mask_ack = disable_8259A_irq; - else - i8259A_chip.irq_mask_ack = mask_and_ack_8259A; - - udelay(100); /* wait for 8259A to initialize */ - - outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */ - outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */ - - raw_spin_unlock_irqrestore(&i8259A_lock, flags); -} - -/* - * IRQ2 is cascade interrupt to second interrupt controller - */ -static struct irqaction irq2 = { - .handler = no_action, - .name = "cascade", - .flags = IRQF_NO_THREAD, -}; - -static struct resource pic1_io_resource = { - .name = "pic1", - .start = PIC_MASTER_CMD, - .end = PIC_MASTER_IMR, - .flags = IORESOURCE_BUSY -}; - -static struct resource pic2_io_resource = { - .name = "pic2", - .start = PIC_SLAVE_CMD, - .end = PIC_SLAVE_IMR, - .flags = IORESOURCE_BUSY -}; - -static int i8259A_irq_domain_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) -{ - irq_set_chip_and_handler(virq, &i8259A_chip, handle_level_irq); - irq_set_probe(virq); - return 0; -} - -static struct irq_domain_ops i8259A_ops = { - .map = i8259A_irq_domain_map, - .xlate = irq_domain_xlate_onecell, -}; - -/* - * On systems with i8259-style interrupt controllers we assume for - * driver compatibility reasons interrupts 0 - 15 to be the i8259 - * interrupts even if the hardware uses a different interrupt numbering. - */ -struct irq_domain * __init __init_i8259_irqs(struct device_node *node) -{ - struct irq_domain *domain; - - insert_resource(&ioport_resource, &pic1_io_resource); - insert_resource(&ioport_resource, &pic2_io_resource); - - init_8259A(0); - - domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0, - &i8259A_ops, NULL); - if (!domain) - panic("Failed to add i8259 IRQ domain"); - - setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); - return domain; -} - -void __init init_i8259_irqs(void) -{ - __init_i8259_irqs(NULL); -} - -static void i8259_irq_dispatch(unsigned int irq, struct irq_desc *desc) -{ - struct irq_domain *domain = irq_get_handler_data(irq); - int hwirq = i8259_irq(); - - if (hwirq < 0) - return; - - irq = irq_linear_revmap(domain, hwirq); - generic_handle_irq(irq); -} - -int __init i8259_of_init(struct device_node *node, struct device_node *parent) -{ - struct irq_domain *domain; - unsigned int parent_irq; - - parent_irq = irq_of_parse_and_map(node, 0); - if (!parent_irq) { - pr_err("Failed to map i8259 parent IRQ\n"); - return -ENODEV; - } - - domain = __init_i8259_irqs(node); - irq_set_handler_data(parent_irq, domain); - irq_set_chained_handler(parent_irq, i8259_irq_dispatch); - return 0; -} -IRQCHIP_DECLARE(i8259, "intel,i8259", i8259_of_init); diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 120d81543e53..5b853715f40b 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -61,6 +61,10 @@ config ATMEL_AIC5_IRQ select MULTI_IRQ_HANDLER select SPARSE_IRQ +config I8259 + bool + select IRQ_DOMAIN + config BCM7038_L1_IRQ bool select GENERIC_IRQ_CHIP diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 11d08c9a0724..d4c5e56b7912 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_ARM_NVIC) += irq-nvic.o obj-$(CONFIG_ARM_VIC) += irq-vic.o obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o obj-$(CONFIG_ATMEL_AIC5_IRQ) += irq-atmel-aic-common.o irq-atmel-aic5.o +obj-$(CONFIG_I8259) += irq-i8259.o obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o obj-$(CONFIG_IRQ_MIPS_CPU) += irq-mips-cpu.o obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c new file mode 100644 index 000000000000..a29638a1e6e5 --- /dev/null +++ b/drivers/irqchip/irq-i8259.c @@ -0,0 +1,383 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Code to handle x86 style IRQs plus some generic interrupt stuff. + * + * Copyright (C) 1992 Linus Torvalds + * Copyright (C) 1994 - 2000 Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * This is the 'legacy' 8259A Programmable Interrupt Controller, + * present in the majority of PC/AT boxes. + * plus some generic x86 specific things if generic specifics makes + * any sense at all. + * this file should become arch/i386/kernel/irq.c when the old irq.c + * moves to arch independent land + */ + +static int i8259A_auto_eoi = -1; +DEFINE_RAW_SPINLOCK(i8259A_lock); +static void disable_8259A_irq(struct irq_data *d); +static void enable_8259A_irq(struct irq_data *d); +static void mask_and_ack_8259A(struct irq_data *d); +static void init_8259A(int auto_eoi); + +static struct irq_chip i8259A_chip = { + .name = "XT-PIC", + .irq_mask = disable_8259A_irq, + .irq_disable = disable_8259A_irq, + .irq_unmask = enable_8259A_irq, + .irq_mask_ack = mask_and_ack_8259A, +}; + +/* + * 8259A PIC functions to handle ISA devices: + */ + +/* + * This contains the irq mask for both 8259A irq controllers, + */ +static unsigned int cached_irq_mask = 0xffff; + +#define cached_master_mask (cached_irq_mask) +#define cached_slave_mask (cached_irq_mask >> 8) + +static void disable_8259A_irq(struct irq_data *d) +{ + unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; + unsigned long flags; + + mask = 1 << irq; + raw_spin_lock_irqsave(&i8259A_lock, flags); + cached_irq_mask |= mask; + if (irq & 8) + outb(cached_slave_mask, PIC_SLAVE_IMR); + else + outb(cached_master_mask, PIC_MASTER_IMR); + raw_spin_unlock_irqrestore(&i8259A_lock, flags); +} + +static void enable_8259A_irq(struct irq_data *d) +{ + unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; + unsigned long flags; + + mask = ~(1 << irq); + raw_spin_lock_irqsave(&i8259A_lock, flags); + cached_irq_mask &= mask; + if (irq & 8) + outb(cached_slave_mask, PIC_SLAVE_IMR); + else + outb(cached_master_mask, PIC_MASTER_IMR); + raw_spin_unlock_irqrestore(&i8259A_lock, flags); +} + +int i8259A_irq_pending(unsigned int irq) +{ + unsigned int mask; + unsigned long flags; + int ret; + + irq -= I8259A_IRQ_BASE; + mask = 1 << irq; + raw_spin_lock_irqsave(&i8259A_lock, flags); + if (irq < 8) + ret = inb(PIC_MASTER_CMD) & mask; + else + ret = inb(PIC_SLAVE_CMD) & (mask >> 8); + raw_spin_unlock_irqrestore(&i8259A_lock, flags); + + return ret; +} + +void make_8259A_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq); + enable_irq(irq); +} + +/* + * This function assumes to be called rarely. Switching between + * 8259A registers is slow. + * This has to be protected by the irq controller spinlock + * before being called. + */ +static inline int i8259A_irq_real(unsigned int irq) +{ + int value; + int irqmask = 1 << irq; + + if (irq < 8) { + outb(0x0B, PIC_MASTER_CMD); /* ISR register */ + value = inb(PIC_MASTER_CMD) & irqmask; + outb(0x0A, PIC_MASTER_CMD); /* back to the IRR register */ + return value; + } + outb(0x0B, PIC_SLAVE_CMD); /* ISR register */ + value = inb(PIC_SLAVE_CMD) & (irqmask >> 8); + outb(0x0A, PIC_SLAVE_CMD); /* back to the IRR register */ + return value; +} + +/* + * Careful! The 8259A is a fragile beast, it pretty + * much _has_ to be done exactly like this (mask it + * first, _then_ send the EOI, and the order of EOI + * to the two 8259s is important! + */ +static void mask_and_ack_8259A(struct irq_data *d) +{ + unsigned int irqmask, irq = d->irq - I8259A_IRQ_BASE; + unsigned long flags; + + irqmask = 1 << irq; + raw_spin_lock_irqsave(&i8259A_lock, flags); + /* + * Lightweight spurious IRQ detection. We do not want + * to overdo spurious IRQ handling - it's usually a sign + * of hardware problems, so we only do the checks we can + * do without slowing down good hardware unnecessarily. + * + * Note that IRQ7 and IRQ15 (the two spurious IRQs + * usually resulting from the 8259A-1|2 PICs) occur + * even if the IRQ is masked in the 8259A. Thus we + * can check spurious 8259A IRQs without doing the + * quite slow i8259A_irq_real() call for every IRQ. + * This does not cover 100% of spurious interrupts, + * but should be enough to warn the user that there + * is something bad going on ... + */ + if (cached_irq_mask & irqmask) + goto spurious_8259A_irq; + cached_irq_mask |= irqmask; + +handle_real_irq: + if (irq & 8) { + inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */ + outb(cached_slave_mask, PIC_SLAVE_IMR); + outb(0x60+(irq&7), PIC_SLAVE_CMD);/* 'Specific EOI' to slave */ + outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */ + } else { + inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */ + outb(cached_master_mask, PIC_MASTER_IMR); + outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */ + } + raw_spin_unlock_irqrestore(&i8259A_lock, flags); + return; + +spurious_8259A_irq: + /* + * this is the slow path - should happen rarely. + */ + if (i8259A_irq_real(irq)) + /* + * oops, the IRQ _is_ in service according to the + * 8259A - not spurious, go handle it. + */ + goto handle_real_irq; + + { + static int spurious_irq_mask; + /* + * At this point we can be sure the IRQ is spurious, + * lets ACK and report it. [once per IRQ] + */ + if (!(spurious_irq_mask & irqmask)) { + printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); + spurious_irq_mask |= irqmask; + } + atomic_inc(&irq_err_count); + /* + * Theoretically we do not have to handle this IRQ, + * but in Linux this does not cause problems and is + * simpler for us. + */ + goto handle_real_irq; + } +} + +static void i8259A_resume(void) +{ + if (i8259A_auto_eoi >= 0) + init_8259A(i8259A_auto_eoi); +} + +static void i8259A_shutdown(void) +{ + /* Put the i8259A into a quiescent state that + * the kernel initialization code can get it + * out of. + */ + if (i8259A_auto_eoi >= 0) { + outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ + outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ + } +} + +static struct syscore_ops i8259_syscore_ops = { + .resume = i8259A_resume, + .shutdown = i8259A_shutdown, +}; + +static int __init i8259A_init_sysfs(void) +{ + register_syscore_ops(&i8259_syscore_ops); + return 0; +} + +device_initcall(i8259A_init_sysfs); + +static void init_8259A(int auto_eoi) +{ + unsigned long flags; + + i8259A_auto_eoi = auto_eoi; + + raw_spin_lock_irqsave(&i8259A_lock, flags); + + outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ + outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ + + /* + * outb_p - this has to work on a wide range of PC hardware. + */ + outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */ + outb_p(I8259A_IRQ_BASE + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0 mapped to I8259A_IRQ_BASE + 0x00 */ + outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */ + if (auto_eoi) /* master does Auto EOI */ + outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR); + else /* master expects normal EOI */ + outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR); + + outb_p(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */ + outb_p(I8259A_IRQ_BASE + 8, PIC_SLAVE_IMR); /* ICW2: 8259A-2 IR0 mapped to I8259A_IRQ_BASE + 0x08 */ + outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); /* 8259A-2 is a slave on master's IR2 */ + outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ + if (auto_eoi) + /* + * In AEOI mode we just have to mask the interrupt + * when acking. + */ + i8259A_chip.irq_mask_ack = disable_8259A_irq; + else + i8259A_chip.irq_mask_ack = mask_and_ack_8259A; + + udelay(100); /* wait for 8259A to initialize */ + + outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */ + outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */ + + raw_spin_unlock_irqrestore(&i8259A_lock, flags); +} + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { + .handler = no_action, + .name = "cascade", + .flags = IRQF_NO_THREAD, +}; + +static struct resource pic1_io_resource = { + .name = "pic1", + .start = PIC_MASTER_CMD, + .end = PIC_MASTER_IMR, + .flags = IORESOURCE_BUSY +}; + +static struct resource pic2_io_resource = { + .name = "pic2", + .start = PIC_SLAVE_CMD, + .end = PIC_SLAVE_IMR, + .flags = IORESOURCE_BUSY +}; + +static int i8259A_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &i8259A_chip, handle_level_irq); + irq_set_probe(virq); + return 0; +} + +static struct irq_domain_ops i8259A_ops = { + .map = i8259A_irq_domain_map, + .xlate = irq_domain_xlate_onecell, +}; + +/* + * On systems with i8259-style interrupt controllers we assume for + * driver compatibility reasons interrupts 0 - 15 to be the i8259 + * interrupts even if the hardware uses a different interrupt numbering. + */ +struct irq_domain * __init __init_i8259_irqs(struct device_node *node) +{ + struct irq_domain *domain; + + insert_resource(&ioport_resource, &pic1_io_resource); + insert_resource(&ioport_resource, &pic2_io_resource); + + init_8259A(0); + + domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0, + &i8259A_ops, NULL); + if (!domain) + panic("Failed to add i8259 IRQ domain"); + + setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); + return domain; +} + +void __init init_i8259_irqs(void) +{ + __init_i8259_irqs(NULL); +} + +static void i8259_irq_dispatch(unsigned int irq, struct irq_desc *desc) +{ + struct irq_domain *domain = irq_get_handler_data(irq); + int hwirq = i8259_irq(); + + if (hwirq < 0) + return; + + irq = irq_linear_revmap(domain, hwirq); + generic_handle_irq(irq); +} + +int __init i8259_of_init(struct device_node *node, struct device_node *parent) +{ + struct irq_domain *domain; + unsigned int parent_irq; + + parent_irq = irq_of_parse_and_map(node, 0); + if (!parent_irq) { + pr_err("Failed to map i8259 parent IRQ\n"); + return -ENODEV; + } + + domain = __init_i8259_irqs(node); + irq_set_handler_data(parent_irq, domain); + irq_set_chained_handler(parent_irq, i8259_irq_dispatch); + return 0; +} +IRQCHIP_DECLARE(i8259, "intel,i8259", i8259_of_init); -- cgit v1.3-6-gb490 From 4ba375016f0234f8d8e7572494eac09d0b1a7252 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 31 Jul 2015 21:59:10 +0200 Subject: irqchip/i8259: Prepare i8259_irq_dispatch for irq argument removal Make irq a local variable and retrieve domain from the irq descriptor which avoid a redundant lookup. Signed-off-by: Thomas Gleixner Cc: Ralf Baechle --- drivers/irqchip/irq-i8259.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c index a29638a1e6e5..4836102ba312 100644 --- a/drivers/irqchip/irq-i8259.c +++ b/drivers/irqchip/irq-i8259.c @@ -352,10 +352,11 @@ void __init init_i8259_irqs(void) __init_i8259_irqs(NULL); } -static void i8259_irq_dispatch(unsigned int irq, struct irq_desc *desc) +static void i8259_irq_dispatch(unsigned int __irq, struct irq_desc *desc) { - struct irq_domain *domain = irq_get_handler_data(irq); + struct irq_domain *domain = irq_desc_get_handler_data(desc); int hwirq = i8259_irq(); + unsigned int irq; if (hwirq < 0) return; -- cgit v1.3-6-gb490 From d2109a12198edf22eb85e475c223eea14b9c3fbe Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:32 +0800 Subject: parisc/irq: Use access helper irq_data_get_affinity_mask() Use access helper irq_data_get_affinity_mask() to hide implementation details of struct irq_desc. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: James E.J. Bottomley Cc: Helge Deller Link: http://lkml.kernel.org/r/1433145945-789-24-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/parisc/kernel/irq.c | 12 ++++++------ drivers/parisc/iosapic.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index f3191db6e2e9..413ec3c3f9cc 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -131,7 +131,7 @@ static int cpu_set_affinity_irq(struct irq_data *d, const struct cpumask *dest, if (cpu_dest < 0) return -1; - cpumask_copy(d->affinity, dest); + cpumask_copy(irq_data_get_affinity_mask(d), dest); return 0; } @@ -339,7 +339,7 @@ unsigned long txn_affinity_addr(unsigned int irq, int cpu) { #ifdef CONFIG_SMP struct irq_data *d = irq_get_irq_data(irq); - cpumask_copy(d->affinity, cpumask_of(cpu)); + cpumask_copy(irq_data_get_affinity_mask(d), cpumask_of(cpu)); #endif return per_cpu(cpu_data, cpu).txn_addr; @@ -508,7 +508,7 @@ void do_cpu_irq_mask(struct pt_regs *regs) unsigned long eirr_val; int irq, cpu = smp_processor_id(); #ifdef CONFIG_SMP - struct irq_desc *desc; + struct irq_data *irq_data; cpumask_t dest; #endif @@ -522,9 +522,9 @@ void do_cpu_irq_mask(struct pt_regs *regs) irq = eirr_to_irq(eirr_val); #ifdef CONFIG_SMP - desc = irq_to_desc(irq); - cpumask_copy(&dest, desc->irq_data.affinity); - if (irqd_is_per_cpu(&desc->irq_data) && + irq_data = irq_get_irq_data(irq); + cpumask_copy(&dest, irq_data_get_affinity_mask(irq_data)); + if (irqd_is_per_cpu(irq_data) && !cpumask_test_cpu(smp_processor_id(), &dest)) { int cpu = cpumask_first(&dest); diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 9ee04b4b68bf..144c77dfe4b1 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -691,7 +691,7 @@ static int iosapic_set_affinity_irq(struct irq_data *d, if (dest_cpu < 0) return -1; - cpumask_copy(d->affinity, cpumask_of(dest_cpu)); + cpumask_copy(irq_data_get_affinity_mask(d), cpumask_of(dest_cpu)); vi->txn_addr = txn_affinity_addr(d->irq, dest_cpu); spin_lock_irqsave(&iosapic_lock, flags); -- cgit v1.3-6-gb490 From fba9573b33f8bddd772195c202f6b8ec0751cedd Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Thu, 30 Jul 2015 18:10:40 +0800 Subject: cpufreq: Correct a freq check in cpufreq_set_policy() This check was originally added by commit 9c9a43ed2734 ("[CPUFREQ] return error when failing to set minfreq").It attempt to return an error on obviously incorrect limits when we echo xxx >.../scaling_max,min_freq Actually we just need check if new_policy->min > new_policy->max. Because at least one of max/min is copied from cpufreq_get_policy(). For example, when we echo xxx > .../scaling_min_freq, new_policy is copied from policy in cpufreq_get_policy. new_policy->max is same with policy->max. new_policy->min is set to a new value. Let me explain it in deduction method, first statement in if (): new_policy->min > policy->max policy->max == new_policy->max ==> new_policy->min > new_policy->max second statement in if(): new_policy->max < policy->min policy->max < policy->min ==>new_policy->min > new_policy->max (induction method) So we have proved that we only need check if new_policy->min > new_policy->max. After apply this patch, we can also modify ->min and ->max at same time if new freq range is very much different from current freq range. For example, if current freq range is 480000-960000, then we want to set this range to 1120000-2240000, we would fail in the past because new_policy->min > policy->max. As long as the cpufreq range is valid, we has no reason to reject the user. So correct the check to avoid such case. Signed-off-by: Pan Xinhui Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0f4e96ff99e8..76a26609d96b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2190,7 +2190,11 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo)); - if (new_policy->min > policy->max || new_policy->max < policy->min) + /* + * This check works well when we store new min/max freq attributes, + * because new_policy is a copy of policy with one field updated. + */ + if (new_policy->min > new_policy->max) return -EINVAL; /* verify the cpu speed can be set within this limit */ -- cgit v1.3-6-gb490 From 144c8e172b5c388ddf41fa64e154f53384ec3448 Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Wed, 29 Jul 2015 23:53:10 +0800 Subject: intel_pstate: Fix possible overflow complained by Coverity Coverity scanning performed on intel_pstate.c shows possible overflow when doing left shifting: val = pstate << 8; since pstate is of type integer, while val is of u64, left shifting pstate might lead to potential loss of upper bits. Say, if pstate equals 0x4000 0000, after pstate << 8 we will get zero assigned to val. Although pstate will not likely be that big, this patch cast the left operand to u64 before performing the left shift, to avoid complaining from Coverity. Reported-by: Coquard, Christophe Signed-off-by: Chen Yu Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 7b2721fb861f..b9354b6f7149 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -521,7 +521,7 @@ static void byt_set_pstate(struct cpudata *cpudata, int pstate) int32_t vid_fp; u32 vid; - val = pstate << 8; + val = (u64)pstate << 8; if (limits.no_turbo && !limits.turbo_disabled) val |= (u64)1 << 32; @@ -610,7 +610,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate) { u64 val; - val = pstate << 8; + val = (u64)pstate << 8; if (limits.no_turbo && !limits.turbo_disabled) val |= (u64)1 << 32; -- cgit v1.3-6-gb490 From ba2bbfbf63075850bb523e2adb815d45e3509995 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 18 Jun 2015 15:17:53 +0200 Subject: PM / Domains: Remove intermediate states from the power off sequence Genpd's ->runtime_suspend() (assigned to pm_genpd_runtime_suspend()) doesn't immediately walk the hierarchy of ->runtime_suspend() callbacks. Instead, pm_genpd_runtime_suspend() calls pm_genpd_poweroff() which postpones that until *all* the devices in the genpd are runtime suspended. When pm_genpd_poweroff() discovers that the last device in the genpd is about to be runtime suspended, it calls __pm_genpd_save_device() for *all* the devices in the genpd sequentially. Furthermore, __pm_genpd_save_device() invokes the ->start() callback, walks the hierarchy of the ->runtime_suspend() callbacks and invokes the ->stop() callback. This causes a "thundering herd" problem. Let's address this issue by having pm_genpd_runtime_suspend() immediately walk the hierarchy of the ->runtime_suspend() callbacks, instead of postponing that to the power off sequence via pm_genpd_poweroff(). If the selected ->runtime_suspend() callback doesn't return an error code, call pm_genpd_poweroff() to see if it's feasible to also power off the PM domain. Adopting this change enables us to simplify parts of the code in genpd, for example the locking mechanism. Additionally, it gives some positive side effects, as described below. i) One device's ->runtime_resume() latency is no longer affected by other devices' latencies in a genpd. The complexity genpd has to support the option to abort the power off sequence suffers from latency issues. More precisely, a device that is requested to be runtime resumed, may end up waiting for __pm_genpd_save_device() to complete its operations for *another* device. That's because pm_genpd_poweroff() can't confirm an abort request while it waits for __pm_genpd_save_device() to return. As this patch removes the intermediate states in pm_genpd_poweroff() while powering off the PM domain, we no longer need the ability to abort that sequence. ii) Make pm_runtime[_status]_suspended() reliable when used with genpd. Until the last device in a genpd becomes idle, pm_genpd_runtime_suspend() will return 0 without actually walking the hierarchy of the ->runtime_suspend() callbacks. However, by returning 0 the runtime PM core considers the device as runtime_suspended, so pm_runtime[_status]_suspended() will return true, even though the device isn't (yet) runtime suspended. After this patch, since pm_genpd_runtime_suspend() immediately walks the hierarchy of the ->runtime_suspend() callbacks, pm_runtime[_status]_suspended() will accurately reflect the status of the device. iii) Enable fine-grained PM through runtime PM callbacks in drivers/subsystems. There are currently cases were drivers/subsystems implements runtime PM callbacks to deploy fine-grained PM (e.g. gate clocks, move pinctrl to power-save state, etc.). While using the genpd, pm_genpd_runtime_suspend() postpones invoking these callbacks until *all* the devices in the genpd are runtime suspended. In essence, one runtime resumed device prevents fine-grained PM for other devices within the same genpd. After this patch, since pm_genpd_runtime_suspend() immediately walks the hierarchy of the ->runtime_suspend() callbacks, fine-grained PM is enabled throughout all the levels of runtime PM callbacks. iiii) Enable fine-grained PM for IRQ safe devices Per the definition for an IRQ safe device, its runtime PM callbacks must be able to execute in atomic context. In the path while genpd walks the hierarchy of the ->runtime_suspend() callbacks for the device, it uses a mutex. Therefore, genpd prevents that path to be executed for IRQ safe devices. As this patch changes pm_genpd_runtime_suspend() to immediately walk the hierarchy of the ->runtime_suspend() callbacks and without needing to use a mutex, fine-grained PM is enabled throughout all the levels of runtime PM callbacks for IRQ safe devices. Unfortunately this patch also comes with a drawback, as described in the summary below. Driver's/subsystem's runtime PM callbacks may be invoked even when the genpd hasn't actually powered off the PM domain, potentially introducing unnecessary latency. However, in most cases, saving/restoring register contexts for devices are typically fast operations or can be optimized in device specific ways (e.g. shadow copies of register contents in memory, device-specific checks to see if context has been lost before restoring context, etc.). Still, in some cases the driver/subsystem may suffer from latency if runtime PM is used in a very fine-grained manner (e.g. for each IO request or xfer). To prevent that extra overhead, the driver/subsystem may deploy the runtime PM autosuspend feature. Signed-off-by: Ulf Hansson Reviewed-by: Kevin Hilman Tested-by: Geert Uytterhoeven Tested-by: Lina Iyer Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 363 ++++++++------------------------------------ include/linux/pm_domain.h | 7 - 2 files changed, 62 insertions(+), 308 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 0ee43c1056e0..a1abe16dfe16 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -114,8 +114,12 @@ static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev) stop_latency_ns, "stop"); } -static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev) +static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev, + bool timed) { + if (!timed) + return GENPD_DEV_CALLBACK(genpd, int, start, dev); + return GENPD_DEV_TIMED_CALLBACK(genpd, int, start, dev, start_latency_ns, "start"); } @@ -136,41 +140,6 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd) smp_mb__after_atomic(); } -static void genpd_acquire_lock(struct generic_pm_domain *genpd) -{ - DEFINE_WAIT(wait); - - mutex_lock(&genpd->lock); - /* - * Wait for the domain to transition into either the active, - * or the power off state. - */ - for (;;) { - prepare_to_wait(&genpd->status_wait_queue, &wait, - TASK_UNINTERRUPTIBLE); - if (genpd->status == GPD_STATE_ACTIVE - || genpd->status == GPD_STATE_POWER_OFF) - break; - mutex_unlock(&genpd->lock); - - schedule(); - - mutex_lock(&genpd->lock); - } - finish_wait(&genpd->status_wait_queue, &wait); -} - -static void genpd_release_lock(struct generic_pm_domain *genpd) -{ - mutex_unlock(&genpd->lock); -} - -static void genpd_set_active(struct generic_pm_domain *genpd) -{ - if (genpd->resume_count == 0) - genpd->status = GPD_STATE_ACTIVE; -} - static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd) { s64 usecs64; @@ -251,35 +220,14 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed) * resume a device belonging to it. */ static int __pm_genpd_poweron(struct generic_pm_domain *genpd) - __releases(&genpd->lock) __acquires(&genpd->lock) { struct gpd_link *link; - DEFINE_WAIT(wait); int ret = 0; - /* If the domain's master is being waited for, we have to wait too. */ - for (;;) { - prepare_to_wait(&genpd->status_wait_queue, &wait, - TASK_UNINTERRUPTIBLE); - if (genpd->status != GPD_STATE_WAIT_MASTER) - break; - mutex_unlock(&genpd->lock); - - schedule(); - - mutex_lock(&genpd->lock); - } - finish_wait(&genpd->status_wait_queue, &wait); - if (genpd->status == GPD_STATE_ACTIVE || (genpd->prepared_count > 0 && genpd->suspend_power_off)) return 0; - if (genpd->status != GPD_STATE_POWER_OFF) { - genpd_set_active(genpd); - return 0; - } - if (genpd->cpuidle_data) { cpuidle_pause_and_lock(); genpd->cpuidle_data->idle_state->disabled = true; @@ -294,20 +242,8 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd) */ list_for_each_entry(link, &genpd->slave_links, slave_node) { genpd_sd_counter_inc(link->master); - genpd->status = GPD_STATE_WAIT_MASTER; - - mutex_unlock(&genpd->lock); ret = pm_genpd_poweron(link->master); - - mutex_lock(&genpd->lock); - - /* - * The "wait for parent" status is guaranteed not to change - * while the master is powering on. - */ - genpd->status = GPD_STATE_POWER_OFF; - wake_up_all(&genpd->status_wait_queue); if (ret) { genpd_sd_counter_dec(link->master); goto err; @@ -319,8 +255,7 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd) goto err; out: - genpd_set_active(genpd); - + genpd->status = GPD_STATE_ACTIVE; return 0; err: @@ -356,20 +291,18 @@ int pm_genpd_name_poweron(const char *domain_name) return genpd ? pm_genpd_poweron(genpd) : -EINVAL; } -static int genpd_start_dev_no_timing(struct generic_pm_domain *genpd, - struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, start, dev); -} - static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev) { return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev, save_state_latency_ns, "state save"); } -static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev) +static int genpd_restore_dev(struct generic_pm_domain *genpd, + struct device *dev, bool timed) { + if (!timed) + return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev); + return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev, restore_state_latency_ns, "state restore"); @@ -415,89 +348,6 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, return NOTIFY_DONE; } -/** - * __pm_genpd_save_device - Save the pre-suspend state of a device. - * @pdd: Domain data of the device to save the state of. - * @genpd: PM domain the device belongs to. - */ -static int __pm_genpd_save_device(struct pm_domain_data *pdd, - struct generic_pm_domain *genpd) - __releases(&genpd->lock) __acquires(&genpd->lock) -{ - struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); - struct device *dev = pdd->dev; - int ret = 0; - - if (gpd_data->need_restore > 0) - return 0; - - /* - * If the value of the need_restore flag is still unknown at this point, - * we trust that pm_genpd_poweroff() has verified that the device is - * already runtime PM suspended. - */ - if (gpd_data->need_restore < 0) { - gpd_data->need_restore = 1; - return 0; - } - - mutex_unlock(&genpd->lock); - - genpd_start_dev(genpd, dev); - ret = genpd_save_dev(genpd, dev); - genpd_stop_dev(genpd, dev); - - mutex_lock(&genpd->lock); - - if (!ret) - gpd_data->need_restore = 1; - - return ret; -} - -/** - * __pm_genpd_restore_device - Restore the pre-suspend state of a device. - * @pdd: Domain data of the device to restore the state of. - * @genpd: PM domain the device belongs to. - */ -static void __pm_genpd_restore_device(struct pm_domain_data *pdd, - struct generic_pm_domain *genpd) - __releases(&genpd->lock) __acquires(&genpd->lock) -{ - struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd); - struct device *dev = pdd->dev; - int need_restore = gpd_data->need_restore; - - gpd_data->need_restore = 0; - mutex_unlock(&genpd->lock); - - genpd_start_dev(genpd, dev); - - /* - * Call genpd_restore_dev() for recently added devices too (need_restore - * is negative then). - */ - if (need_restore) - genpd_restore_dev(genpd, dev); - - mutex_lock(&genpd->lock); -} - -/** - * genpd_abort_poweroff - Check if a PM domain power off should be aborted. - * @genpd: PM domain to check. - * - * Return true if a PM domain's status changed to GPD_STATE_ACTIVE during - * a "power off" operation, which means that a "power on" has occured in the - * meantime, or if its resume_count field is different from zero, which means - * that one of its devices has been resumed in the meantime. - */ -static bool genpd_abort_poweroff(struct generic_pm_domain *genpd) -{ - return genpd->status == GPD_STATE_WAIT_MASTER - || genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0; -} - /** * genpd_queue_power_off_work - Queue up the execution of pm_genpd_poweroff(). * @genpd: PM domait to power off. @@ -515,34 +365,26 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) * @genpd: PM domain to power down. * * If all of the @genpd's devices have been suspended and all of its subdomains - * have been powered down, run the runtime suspend callbacks provided by all of - * the @genpd's devices' drivers and remove power from @genpd. + * have been powered down, remove power from @genpd. */ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) - __releases(&genpd->lock) __acquires(&genpd->lock) { struct pm_domain_data *pdd; struct gpd_link *link; - unsigned int not_suspended; - int ret = 0; + unsigned int not_suspended = 0; - start: /* * Do not try to power off the domain in the following situations: * (1) The domain is already in the "power off" state. - * (2) The domain is waiting for its master to power up. - * (3) One of the domain's devices is being resumed right now. - * (4) System suspend is in progress. + * (2) System suspend is in progress. */ if (genpd->status == GPD_STATE_POWER_OFF - || genpd->status == GPD_STATE_WAIT_MASTER - || genpd->resume_count > 0 || genpd->prepared_count > 0) + || genpd->prepared_count > 0) return 0; if (atomic_read(&genpd->sd_count) > 0) return -EBUSY; - not_suspended = 0; list_for_each_entry(pdd, &genpd->dev_list, list_node) { enum pm_qos_flags_status stat; @@ -560,41 +402,11 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) if (not_suspended > genpd->in_progress) return -EBUSY; - if (genpd->poweroff_task) { - /* - * Another instance of pm_genpd_poweroff() is executing - * callbacks, so tell it to start over and return. - */ - genpd->status = GPD_STATE_REPEAT; - return 0; - } - if (genpd->gov && genpd->gov->power_down_ok) { if (!genpd->gov->power_down_ok(&genpd->domain)) return -EAGAIN; } - genpd->status = GPD_STATE_BUSY; - genpd->poweroff_task = current; - - list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) { - ret = atomic_read(&genpd->sd_count) == 0 ? - __pm_genpd_save_device(pdd, genpd) : -EBUSY; - - if (genpd_abort_poweroff(genpd)) - goto out; - - if (ret) { - genpd_set_active(genpd); - goto out; - } - - if (genpd->status == GPD_STATE_REPEAT) { - genpd->poweroff_task = NULL; - goto start; - } - } - if (genpd->cpuidle_data) { /* * If cpuidle_data is set, cpuidle should turn the domain off @@ -607,14 +419,14 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) cpuidle_pause_and_lock(); genpd->cpuidle_data->idle_state->disabled = false; cpuidle_resume_and_unlock(); - goto out; + return 0; } if (genpd->power_off) { - if (atomic_read(&genpd->sd_count) > 0) { - ret = -EBUSY; - goto out; - } + int ret; + + if (atomic_read(&genpd->sd_count) > 0) + return -EBUSY; /* * If sd_count > 0 at this point, one of the subdomains hasn't @@ -625,10 +437,8 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) * happen very often). */ ret = genpd_power_off(genpd, true); - if (ret == -EBUSY) { - genpd_set_active(genpd); - goto out; - } + if (ret) + return ret; } genpd->status = GPD_STATE_POWER_OFF; @@ -638,10 +448,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) genpd_queue_power_off_work(link->master); } - out: - genpd->poweroff_task = NULL; - wake_up_all(&genpd->status_wait_queue); - return ret; + return 0; } /** @@ -654,9 +461,9 @@ static void genpd_power_off_work_fn(struct work_struct *work) genpd = container_of(work, struct generic_pm_domain, power_off_work); - genpd_acquire_lock(genpd); + mutex_lock(&genpd->lock); pm_genpd_poweroff(genpd); - genpd_release_lock(genpd); + mutex_unlock(&genpd->lock); } /** @@ -670,7 +477,6 @@ static void genpd_power_off_work_fn(struct work_struct *work) static int pm_genpd_runtime_suspend(struct device *dev) { struct generic_pm_domain *genpd; - struct generic_pm_domain_data *gpd_data; bool (*stop_ok)(struct device *__dev); int ret; @@ -684,10 +490,16 @@ static int pm_genpd_runtime_suspend(struct device *dev) if (stop_ok && !stop_ok(dev)) return -EBUSY; - ret = genpd_stop_dev(genpd, dev); + ret = genpd_save_dev(genpd, dev); if (ret) return ret; + ret = genpd_stop_dev(genpd, dev); + if (ret) { + genpd_restore_dev(genpd, dev, true); + return ret; + } + /* * If power.irq_safe is set, this routine will be run with interrupts * off, so it can't use mutexes. @@ -696,16 +508,6 @@ static int pm_genpd_runtime_suspend(struct device *dev) return 0; mutex_lock(&genpd->lock); - - /* - * If we have an unknown state of the need_restore flag, it means none - * of the runtime PM callbacks has been invoked yet. Let's update the - * flag to reflect that the current state is active. - */ - gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); - if (gpd_data->need_restore < 0) - gpd_data->need_restore = 0; - genpd->in_progress++; pm_genpd_poweroff(genpd); genpd->in_progress--; @@ -725,8 +527,8 @@ static int pm_genpd_runtime_suspend(struct device *dev) static int pm_genpd_runtime_resume(struct device *dev) { struct generic_pm_domain *genpd; - DEFINE_WAIT(wait); int ret; + bool timed = true; dev_dbg(dev, "%s()\n", __func__); @@ -735,39 +537,21 @@ static int pm_genpd_runtime_resume(struct device *dev) return -EINVAL; /* If power.irq_safe, the PM domain is never powered off. */ - if (dev->power.irq_safe) - return genpd_start_dev_no_timing(genpd, dev); + if (dev->power.irq_safe) { + timed = false; + goto out; + } mutex_lock(&genpd->lock); ret = __pm_genpd_poweron(genpd); - if (ret) { - mutex_unlock(&genpd->lock); - return ret; - } - genpd->status = GPD_STATE_BUSY; - genpd->resume_count++; - for (;;) { - prepare_to_wait(&genpd->status_wait_queue, &wait, - TASK_UNINTERRUPTIBLE); - /* - * If current is the powering off task, we have been called - * reentrantly from one of the device callbacks, so we should - * not wait. - */ - if (!genpd->poweroff_task || genpd->poweroff_task == current) - break; - mutex_unlock(&genpd->lock); + mutex_unlock(&genpd->lock); - schedule(); + if (ret) + return ret; - mutex_lock(&genpd->lock); - } - finish_wait(&genpd->status_wait_queue, &wait); - __pm_genpd_restore_device(dev->power.subsys_data->domain_data, genpd); - genpd->resume_count--; - genpd_set_active(genpd); - wake_up_all(&genpd->status_wait_queue); - mutex_unlock(&genpd->lock); + out: + genpd_start_dev(genpd, dev, timed); + genpd_restore_dev(genpd, dev, timed); return 0; } @@ -883,7 +667,7 @@ static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd, { struct gpd_link *link; - if (genpd->status != GPD_STATE_POWER_OFF) + if (genpd->status == GPD_STATE_ACTIVE) return; list_for_each_entry(link, &genpd->slave_links, slave_node) { @@ -960,14 +744,14 @@ static int pm_genpd_prepare(struct device *dev) if (resume_needed(dev, genpd)) pm_runtime_resume(dev); - genpd_acquire_lock(genpd); + mutex_lock(&genpd->lock); if (genpd->prepared_count++ == 0) { genpd->suspended_count = 0; genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF; } - genpd_release_lock(genpd); + mutex_unlock(&genpd->lock); if (genpd->suspend_power_off) { pm_runtime_put_noidle(dev); @@ -1102,7 +886,7 @@ static int pm_genpd_resume_noirq(struct device *dev) pm_genpd_sync_poweron(genpd, true); genpd->suspended_count--; - return genpd_start_dev(genpd, dev); + return genpd_start_dev(genpd, dev, true); } /** @@ -1230,7 +1014,7 @@ static int pm_genpd_thaw_noirq(struct device *dev) if (IS_ERR(genpd)) return -EINVAL; - return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev); + return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev, true); } /** @@ -1324,7 +1108,7 @@ static int pm_genpd_restore_noirq(struct device *dev) pm_genpd_sync_poweron(genpd, true); - return genpd_start_dev(genpd, dev); + return genpd_start_dev(genpd, dev, true); } /** @@ -1440,7 +1224,6 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, gpd_data->td = *td; gpd_data->base.dev = dev; - gpd_data->need_restore = -1; gpd_data->td.constraint_changed = true; gpd_data->td.effective_constraint_ns = -1; gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; @@ -1502,7 +1285,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, if (IS_ERR(gpd_data)) return PTR_ERR(gpd_data); - genpd_acquire_lock(genpd); + mutex_lock(&genpd->lock); if (genpd->prepared_count > 0) { ret = -EAGAIN; @@ -1519,7 +1302,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); out: - genpd_release_lock(genpd); + mutex_unlock(&genpd->lock); if (ret) genpd_free_dev_data(dev, gpd_data); @@ -1563,7 +1346,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, gpd_data = to_gpd_data(pdd); dev_pm_qos_remove_notifier(dev, &gpd_data->nb); - genpd_acquire_lock(genpd); + mutex_lock(&genpd->lock); if (genpd->prepared_count > 0) { ret = -EAGAIN; @@ -1578,14 +1361,14 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd, list_del_init(&pdd->list_node); - genpd_release_lock(genpd); + mutex_unlock(&genpd->lock); genpd_free_dev_data(dev, gpd_data); return 0; out: - genpd_release_lock(genpd); + mutex_unlock(&genpd->lock); dev_pm_qos_add_notifier(dev, &gpd_data->nb); return ret; @@ -1606,17 +1389,9 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, || genpd == subdomain) return -EINVAL; - start: - genpd_acquire_lock(genpd); + mutex_lock(&genpd->lock); mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING); - if (subdomain->status != GPD_STATE_POWER_OFF - && subdomain->status != GPD_STATE_ACTIVE) { - mutex_unlock(&subdomain->lock); - genpd_release_lock(genpd); - goto start; - } - if (genpd->status == GPD_STATE_POWER_OFF && subdomain->status != GPD_STATE_POWER_OFF) { ret = -EINVAL; @@ -1644,7 +1419,7 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, out: mutex_unlock(&subdomain->lock); - genpd_release_lock(genpd); + mutex_unlock(&genpd->lock); return ret; } @@ -1692,8 +1467,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain)) return -EINVAL; - start: - genpd_acquire_lock(genpd); + mutex_lock(&genpd->lock); list_for_each_entry(link, &genpd->master_links, master_node) { if (link->slave != subdomain) @@ -1701,13 +1475,6 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING); - if (subdomain->status != GPD_STATE_POWER_OFF - && subdomain->status != GPD_STATE_ACTIVE) { - mutex_unlock(&subdomain->lock); - genpd_release_lock(genpd); - goto start; - } - list_del(&link->master_node); list_del(&link->slave_node); kfree(link); @@ -1720,7 +1487,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, break; } - genpd_release_lock(genpd); + mutex_unlock(&genpd->lock); return ret; } @@ -1744,7 +1511,7 @@ int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state) if (IS_ERR_OR_NULL(genpd) || state < 0) return -EINVAL; - genpd_acquire_lock(genpd); + mutex_lock(&genpd->lock); if (genpd->cpuidle_data) { ret = -EEXIST; @@ -1775,7 +1542,7 @@ int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state) genpd_recalc_cpu_exit_latency(genpd); out: - genpd_release_lock(genpd); + mutex_unlock(&genpd->lock); return ret; err: @@ -1812,7 +1579,7 @@ int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd) if (IS_ERR_OR_NULL(genpd)) return -EINVAL; - genpd_acquire_lock(genpd); + mutex_lock(&genpd->lock); cpuidle_data = genpd->cpuidle_data; if (!cpuidle_data) { @@ -1830,7 +1597,7 @@ int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd) kfree(cpuidle_data); out: - genpd_release_lock(genpd); + mutex_unlock(&genpd->lock); return ret; } @@ -1912,9 +1679,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd, genpd->in_progress = 0; atomic_set(&genpd->sd_count, 0); genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE; - init_waitqueue_head(&genpd->status_wait_queue); - genpd->poweroff_task = NULL; - genpd->resume_count = 0; genpd->device_count = 0; genpd->max_off_time_ns = -1; genpd->max_off_time_changed = true; @@ -2293,9 +2057,6 @@ static int pm_genpd_summary_one(struct seq_file *s, { static const char * const status_lookup[] = { [GPD_STATE_ACTIVE] = "on", - [GPD_STATE_WAIT_MASTER] = "wait-master", - [GPD_STATE_BUSY] = "busy", - [GPD_STATE_REPEAT] = "off-in-progress", [GPD_STATE_POWER_OFF] = "off" }; struct pm_domain_data *pm_data; diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index 681ccb053f72..b2725e6e8e7b 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -22,9 +22,6 @@ enum gpd_status { GPD_STATE_ACTIVE = 0, /* PM domain is active */ - GPD_STATE_WAIT_MASTER, /* PM domain's master is being waited for */ - GPD_STATE_BUSY, /* Something is happening to the PM domain */ - GPD_STATE_REPEAT, /* Power off in progress, to be repeated */ GPD_STATE_POWER_OFF, /* PM domain is off */ }; @@ -59,9 +56,6 @@ struct generic_pm_domain { unsigned int in_progress; /* Number of devices being suspended now */ atomic_t sd_count; /* Number of subdomains with power "on" */ enum gpd_status status; /* Current state of the domain */ - wait_queue_head_t status_wait_queue; - struct task_struct *poweroff_task; /* Powering off task */ - unsigned int resume_count; /* Number of devices being resumed */ unsigned int device_count; /* Number of devices */ unsigned int suspended_count; /* System suspend device counter */ unsigned int prepared_count; /* Suspend counter of prepared devices */ @@ -113,7 +107,6 @@ struct generic_pm_domain_data { struct pm_domain_data base; struct gpd_timing_data td; struct notifier_block nb; - int need_restore; }; #ifdef CONFIG_PM_GENERIC_DOMAINS -- cgit v1.3-6-gb490 From 311fa6adf92c5110057daa439fdaff012864aa2b Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 31 Jul 2015 10:20:00 +0100 Subject: PM / Domains: Return -EPROBE_DEFER if we fail to init or turn-on domain When a device is probed, the function dev_pm_domain_attach() is called to see if there is a power-domain that is associated with the device and needs to be turned on. If dev_pm_domain_attach() does not return -EPROBE_DEFER then the device will be probed. For devices using genpd, dev_pm_domain_attach() will call genpd_dev_pm_attach(). If genpd_dev_pm_attach() does not find a power domain associated with the device then it returns an error code not equal to -EPROBE_DEFER to allow the device to be probed. However, if genpd_dev_pm_attach() does find a power-domain that is associated with the device, then it does not return -EPROBE_DEFER on failure and hence the device will still be probed. Furthermore, genpd_dev_pm_attach() does not check the error code returned by pm_genpd_poweron() to see if the power-domain was turned on successfully. Fix this by checking the return code from pm_genpd_poweron() and returning -EPROBE_DEFER from genpd_dev_pm_attach on failure, if there is a power-domain associated with the device. Signed-off-by: Jon Hunter Acked-by: Ulf Hansson Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index a1abe16dfe16..7666a1cbaf95 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1947,7 +1947,10 @@ static void genpd_dev_pm_sync(struct device *dev) * Both generic and legacy Samsung-specific DT bindings are supported to keep * backwards compatibility with existing DTBs. * - * Returns 0 on successfully attached PM domain or negative error code. + * Returns 0 on successfully attached PM domain or negative error code. Note + * that if a power-domain exists for the device, but it cannot be found or + * turned on, then return -EPROBE_DEFER to ensure that the device is not + * probed and to re-try again later. */ int genpd_dev_pm_attach(struct device *dev) { @@ -1984,7 +1987,7 @@ int genpd_dev_pm_attach(struct device *dev) dev_dbg(dev, "%s() failed to find PM domain: %ld\n", __func__, PTR_ERR(pd)); of_node_put(dev->of_node); - return PTR_ERR(pd); + return -EPROBE_DEFER; } dev_dbg(dev, "adding to PM domain %s\n", pd->name); @@ -2002,14 +2005,15 @@ int genpd_dev_pm_attach(struct device *dev) dev_err(dev, "failed to add to PM domain %s: %d", pd->name, ret); of_node_put(dev->of_node); - return ret; + goto out; } dev->pm_domain->detach = genpd_dev_pm_detach; dev->pm_domain->sync = genpd_dev_pm_sync; - pm_genpd_poweron(pd); + ret = pm_genpd_poweron(pd); - return 0; +out: + return ret ? -EPROBE_DEFER : 0; } EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ -- cgit v1.3-6-gb490 From f6ef5a2a50816b58e3126206de13d0b9fdf89df5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 28 Jul 2015 12:27:01 -0700 Subject: nvdimm: fix inline function return type warning Fix multiple build warnings when CONFIG_BTT is not enabled: In file included from ../drivers/nvdimm/bus.c:29:0: ../drivers/nvdimm/nd.h:169:15: warning: return type defaults to 'int' [-Wreturn-type] static inline nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata) ^ Signed-off-by: Randy Dunlap Cc: Dan Williams Cc: linux-nvdimm@lists.01.org Signed-off-by: Dan Williams --- drivers/nvdimm/nd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index c41f53e74277..835263e47bb8 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -166,7 +166,7 @@ int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata); bool is_nd_btt(struct device *dev); struct device *nd_btt_create(struct nd_region *nd_region); #else -static inline nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata) +static inline int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata) { return -ENODEV; } -- cgit v1.3-6-gb490 From 55d7de9de6c30adce8d675c7ce513e283829c2ff Mon Sep 17 00:00:00 2001 From: "Woojung.Huh@microchip.com" Date: Thu, 30 Jul 2015 19:45:21 +0000 Subject: Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver Repost patch of driver for LAN7800 family of USB 2.0 & USB 3.0 to Gigabit Ethernet. - remove module param which can be configurable by standard mechanism. - remove other module parms except msg_level per review comment. - update to handle byte swap for statistics structure correctly. Signed-off-by: Woojung Huh Signed-off-by: David S. Miller --- drivers/net/usb/Kconfig | 10 + drivers/net/usb/Makefile | 1 + drivers/net/usb/lan78xx.c | 3530 +++++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/lan78xx.h | 1069 ++++++++++++++ 4 files changed, 4610 insertions(+) create mode 100644 drivers/net/usb/lan78xx.c create mode 100644 drivers/net/usb/lan78xx.h (limited to 'drivers') diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 7ba8d0885f12..1610b79ae386 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -106,6 +106,16 @@ config USB_RTL8152 To compile this driver as a module, choose M here: the module will be called r8152. +config USB_LAN78XX + tristate "Microchip LAN78XX Based USB Ethernet Adapters" + select MII + help + This option adds support for Microchip LAN78XX based USB 2 + & USB 3 10/100/1000 Ethernet adapters. + + To compile this driver as a module, choose M here: the + module will be called lan78xx. + config USB_USBNET tristate "Multi-purpose USB Networking Framework" select MII diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index e2797f1e1b31..cf6a0e610a7f 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RTL8150) += rtl8150.o obj-$(CONFIG_USB_RTL8152) += r8152.o obj-$(CONFIG_USB_HSO) += hso.o +obj-$(CONFIG_USB_LAN78XX) += lan78xx.o obj-$(CONFIG_USB_NET_AX8817X) += asix.o asix-y := asix_devices.o asix_common.o ax88172a.o obj-$(CONFIG_USB_NET_AX88179_178A) += ax88179_178a.o diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c new file mode 100644 index 000000000000..ec8bd34ce47b --- /dev/null +++ b/drivers/net/usb/lan78xx.c @@ -0,0 +1,3530 @@ +/* + * Copyright (C) 2015 Microchip Technology + * + * 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, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lan78xx.h" + +#define DRIVER_AUTHOR "WOOJUNG HUH " +#define DRIVER_DESC "LAN78XX USB 3.0 Gigabit Ethernet Devices" +#define DRIVER_NAME "lan78xx" +#define DRIVER_VERSION "1.0.0" + +#define TX_TIMEOUT_JIFFIES (5 * HZ) +#define THROTTLE_JIFFIES (HZ / 8) +#define UNLINK_TIMEOUT_MS 3 + +#define RX_MAX_QUEUE_MEMORY (60 * 1518) + +#define SS_USB_PKT_SIZE (1024) +#define HS_USB_PKT_SIZE (512) +#define FS_USB_PKT_SIZE (64) + +#define MAX_RX_FIFO_SIZE (12 * 1024) +#define MAX_TX_FIFO_SIZE (12 * 1024) +#define DEFAULT_BURST_CAP_SIZE (MAX_TX_FIFO_SIZE) +#define DEFAULT_BULK_IN_DELAY (0x0800) +#define MAX_SINGLE_PACKET_SIZE (9000) +#define DEFAULT_TX_CSUM_ENABLE (true) +#define DEFAULT_RX_CSUM_ENABLE (true) +#define DEFAULT_TSO_CSUM_ENABLE (true) +#define DEFAULT_VLAN_FILTER_ENABLE (true) +#define INTERNAL_PHY_ID (2) /* 2: GMII */ +#define TX_OVERHEAD (8) +#define RXW_PADDING 2 + +#define LAN78XX_USB_VENDOR_ID (0x0424) +#define LAN7800_USB_PRODUCT_ID (0x7800) +#define LAN7850_USB_PRODUCT_ID (0x7850) +#define LAN78XX_EEPROM_MAGIC (0x78A5) +#define LAN78XX_OTP_MAGIC (0x78F3) + +#define MII_READ 1 +#define MII_WRITE 0 + +#define EEPROM_INDICATOR (0xA5) +#define EEPROM_MAC_OFFSET (0x01) +#define MAX_EEPROM_SIZE 512 +#define OTP_INDICATOR_1 (0xF3) +#define OTP_INDICATOR_2 (0xF7) + +#define WAKE_ALL (WAKE_PHY | WAKE_UCAST | \ + WAKE_MCAST | WAKE_BCAST | \ + WAKE_ARP | WAKE_MAGIC) + +/* USB related defines */ +#define BULK_IN_PIPE 1 +#define BULK_OUT_PIPE 2 + +/* default autosuspend delay (mSec)*/ +#define DEFAULT_AUTOSUSPEND_DELAY (10 * 1000) + +static const char lan78xx_gstrings[][ETH_GSTRING_LEN] = { + "RX FCS Errors", + "RX Alignment Errors", + "Rx Fragment Errors", + "RX Jabber Errors", + "RX Undersize Frame Errors", + "RX Oversize Frame Errors", + "RX Dropped Frames", + "RX Unicast Byte Count", + "RX Broadcast Byte Count", + "RX Multicast Byte Count", + "RX Unicast Frames", + "RX Broadcast Frames", + "RX Multicast Frames", + "RX Pause Frames", + "RX 64 Byte Frames", + "RX 65 - 127 Byte Frames", + "RX 128 - 255 Byte Frames", + "RX 256 - 511 Bytes Frames", + "RX 512 - 1023 Byte Frames", + "RX 1024 - 1518 Byte Frames", + "RX Greater 1518 Byte Frames", + "EEE RX LPI Transitions", + "EEE RX LPI Time", + "TX FCS Errors", + "TX Excess Deferral Errors", + "TX Carrier Errors", + "TX Bad Byte Count", + "TX Single Collisions", + "TX Multiple Collisions", + "TX Excessive Collision", + "TX Late Collisions", + "TX Unicast Byte Count", + "TX Broadcast Byte Count", + "TX Multicast Byte Count", + "TX Unicast Frames", + "TX Broadcast Frames", + "TX Multicast Frames", + "TX Pause Frames", + "TX 64 Byte Frames", + "TX 65 - 127 Byte Frames", + "TX 128 - 255 Byte Frames", + "TX 256 - 511 Bytes Frames", + "TX 512 - 1023 Byte Frames", + "TX 1024 - 1518 Byte Frames", + "TX Greater 1518 Byte Frames", + "EEE TX LPI Transitions", + "EEE TX LPI Time", +}; + +struct lan78xx_statstage { + u32 rx_fcs_errors; + u32 rx_alignment_errors; + u32 rx_fragment_errors; + u32 rx_jabber_errors; + u32 rx_undersize_frame_errors; + u32 rx_oversize_frame_errors; + u32 rx_dropped_frames; + u32 rx_unicast_byte_count; + u32 rx_broadcast_byte_count; + u32 rx_multicast_byte_count; + u32 rx_unicast_frames; + u32 rx_broadcast_frames; + u32 rx_multicast_frames; + u32 rx_pause_frames; + u32 rx_64_byte_frames; + u32 rx_65_127_byte_frames; + u32 rx_128_255_byte_frames; + u32 rx_256_511_bytes_frames; + u32 rx_512_1023_byte_frames; + u32 rx_1024_1518_byte_frames; + u32 rx_greater_1518_byte_frames; + u32 eee_rx_lpi_transitions; + u32 eee_rx_lpi_time; + u32 tx_fcs_errors; + u32 tx_excess_deferral_errors; + u32 tx_carrier_errors; + u32 tx_bad_byte_count; + u32 tx_single_collisions; + u32 tx_multiple_collisions; + u32 tx_excessive_collision; + u32 tx_late_collisions; + u32 tx_unicast_byte_count; + u32 tx_broadcast_byte_count; + u32 tx_multicast_byte_count; + u32 tx_unicast_frames; + u32 tx_broadcast_frames; + u32 tx_multicast_frames; + u32 tx_pause_frames; + u32 tx_64_byte_frames; + u32 tx_65_127_byte_frames; + u32 tx_128_255_byte_frames; + u32 tx_256_511_bytes_frames; + u32 tx_512_1023_byte_frames; + u32 tx_1024_1518_byte_frames; + u32 tx_greater_1518_byte_frames; + u32 eee_tx_lpi_transitions; + u32 eee_tx_lpi_time; +}; + +struct lan78xx_net; + +struct lan78xx_priv { + struct lan78xx_net *dev; + u32 rfe_ctl; + u32 mchash_table[DP_SEL_VHF_HASH_LEN]; /* multicat hash table */ + u32 pfilter_table[NUM_OF_MAF][2]; /* perfect filter table */ + u32 vlan_table[DP_SEL_VHF_VLAN_LEN]; + struct mutex dataport_mutex; /* for dataport access */ + spinlock_t rfe_ctl_lock; /* for rfe register access */ + struct work_struct set_multicast; + struct work_struct set_vlan; + u32 wol; +}; + +enum skb_state { + illegal = 0, + tx_start, + tx_done, + rx_start, + rx_done, + rx_cleanup, + unlink_start +}; + +struct skb_data { /* skb->cb is one of these */ + struct urb *urb; + struct lan78xx_net *dev; + enum skb_state state; + size_t length; +}; + +struct usb_context { + struct usb_ctrlrequest req; + struct lan78xx_net *dev; +}; + +#define EVENT_TX_HALT 0 +#define EVENT_RX_HALT 1 +#define EVENT_RX_MEMORY 2 +#define EVENT_STS_SPLIT 3 +#define EVENT_LINK_RESET 4 +#define EVENT_RX_PAUSED 5 +#define EVENT_DEV_WAKING 6 +#define EVENT_DEV_ASLEEP 7 +#define EVENT_DEV_OPEN 8 + +struct lan78xx_net { + struct net_device *net; + struct usb_device *udev; + struct usb_interface *intf; + void *driver_priv; + + int rx_qlen; + int tx_qlen; + struct sk_buff_head rxq; + struct sk_buff_head txq; + struct sk_buff_head done; + struct sk_buff_head rxq_pause; + struct sk_buff_head txq_pend; + + struct tasklet_struct bh; + struct delayed_work wq; + + struct usb_host_endpoint *ep_blkin; + struct usb_host_endpoint *ep_blkout; + struct usb_host_endpoint *ep_intr; + + int msg_enable; + + struct urb *urb_intr; + struct usb_anchor deferred; + + struct mutex phy_mutex; /* for phy access */ + unsigned pipe_in, pipe_out, pipe_intr; + + u32 hard_mtu; /* count any extra framing */ + size_t rx_urb_size; /* size for rx urbs */ + + unsigned long flags; + + wait_queue_head_t *wait; + unsigned char suspend_count; + + unsigned maxpacket; + struct timer_list delay; + + unsigned long data[5]; + struct mii_if_info mii; + + int link_on; + u8 mdix_ctrl; +}; + +/* use ethtool to change the level for any given device */ +static int msg_level = -1; +module_param(msg_level, int, 0); +MODULE_PARM_DESC(msg_level, "Override default message level"); + +static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data) +{ + u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL); + int ret; + + BUG_ON(!dev); + + if (!buf) + return -ENOMEM; + + ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), + USB_VENDOR_REQUEST_READ_REGISTER, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, buf, 4, USB_CTRL_GET_TIMEOUT); + if (likely(ret >= 0)) { + le32_to_cpus(buf); + *data = *buf; + } else { + netdev_warn(dev->net, + "Failed to read register index 0x%08x. ret = %d", + index, ret); + } + + kfree(buf); + + return ret; +} + +static int lan78xx_write_reg(struct lan78xx_net *dev, u32 index, u32 data) +{ + u32 *buf = kmalloc(sizeof(u32), GFP_KERNEL); + int ret; + + BUG_ON(!dev); + + if (!buf) + return -ENOMEM; + + *buf = data; + cpu_to_le32s(buf); + + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), + USB_VENDOR_REQUEST_WRITE_REGISTER, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, buf, 4, USB_CTRL_SET_TIMEOUT); + if (unlikely(ret < 0)) { + netdev_warn(dev->net, + "Failed to write register index 0x%08x. ret = %d", + index, ret); + } + + kfree(buf); + + return ret; +} + +static int lan78xx_read_stats(struct lan78xx_net *dev, + struct lan78xx_statstage *data) +{ + int ret = 0; + int i; + struct lan78xx_statstage *stats; + u32 *src; + u32 *dst; + + BUG_ON(!dev); + BUG_ON(!data); + BUG_ON(sizeof(struct lan78xx_statstage) != 0xBC); + + stats = kmalloc(sizeof(*stats), GFP_KERNEL); + if (!stats) + return -ENOMEM; + + ret = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + USB_VENDOR_REQUEST_GET_STATS, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, + 0, + (void *)stats, + sizeof(*stats), + USB_CTRL_SET_TIMEOUT); + if (likely(ret >= 0)) { + src = (u32 *)stats; + dst = (u32 *)data; + for (i = 0; i < sizeof(*stats)/sizeof(u32); i++) { + le32_to_cpus(&src[i]); + dst[i] = src[i]; + } + } else { + netdev_warn(dev->net, + "Failed to read stat ret = 0x%x", ret); + } + + kfree(stats); + + return ret; +} + +/* Loop until the read is completed with timeout called with phy_mutex held */ +static int lan78xx_phy_wait_not_busy(struct lan78xx_net *dev) +{ + unsigned long start_time = jiffies; + u32 val; + int ret; + + do { + ret = lan78xx_read_reg(dev, MII_ACC, &val); + if (unlikely(ret < 0)) + return -EIO; + + if (!(val & MII_ACC_MII_BUSY_)) + return 0; + } while (!time_after(jiffies, start_time + HZ)); + + return -EIO; +} + +static inline u32 mii_access(int id, int index, int read) +{ + u32 ret; + + ret = ((u32)id << MII_ACC_PHY_ADDR_SHIFT_) & MII_ACC_PHY_ADDR_MASK_; + ret |= ((u32)index << MII_ACC_MIIRINDA_SHIFT_) & MII_ACC_MIIRINDA_MASK_; + if (read) + ret |= MII_ACC_MII_READ_; + else + ret |= MII_ACC_MII_WRITE_; + ret |= MII_ACC_MII_BUSY_; + + return ret; +} + +static int lan78xx_mdio_read(struct net_device *netdev, int phy_id, int idx) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + u32 val, addr; + int ret; + + ret = usb_autopm_get_interface(dev->intf); + if (ret < 0) + return ret; + + mutex_lock(&dev->phy_mutex); + + /* confirm MII not busy */ + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + /* set the address, index & direction (read from PHY) */ + phy_id &= dev->mii.phy_id_mask; + idx &= dev->mii.reg_num_mask; + addr = mii_access(phy_id, idx, MII_READ); + ret = lan78xx_write_reg(dev, MII_ACC, addr); + + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + ret = lan78xx_read_reg(dev, MII_DATA, &val); + + ret = (int)(val & 0xFFFF); + +done: + mutex_unlock(&dev->phy_mutex); + usb_autopm_put_interface(dev->intf); + return ret; +} + +static void lan78xx_mdio_write(struct net_device *netdev, int phy_id, + int idx, int regval) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + u32 val, addr; + int ret; + + if (usb_autopm_get_interface(dev->intf) < 0) + return; + + mutex_lock(&dev->phy_mutex); + + /* confirm MII not busy */ + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + val = regval; + ret = lan78xx_write_reg(dev, MII_DATA, val); + + /* set the address, index & direction (write to PHY) */ + phy_id &= dev->mii.phy_id_mask; + idx &= dev->mii.reg_num_mask; + addr = mii_access(phy_id, idx, MII_WRITE); + ret = lan78xx_write_reg(dev, MII_ACC, addr); + + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + +done: + mutex_unlock(&dev->phy_mutex); + usb_autopm_put_interface(dev->intf); +} + +static void lan78xx_mmd_write(struct net_device *netdev, int phy_id, + int mmddev, int mmdidx, int regval) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + u32 val, addr; + int ret; + + if (usb_autopm_get_interface(dev->intf) < 0) + return; + + mutex_lock(&dev->phy_mutex); + + /* confirm MII not busy */ + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + mmddev &= 0x1F; + + /* set up device address for MMD */ + ret = lan78xx_write_reg(dev, MII_DATA, mmddev); + + phy_id &= dev->mii.phy_id_mask; + addr = mii_access(phy_id, PHY_MMD_CTL, MII_WRITE); + ret = lan78xx_write_reg(dev, MII_ACC, addr); + + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + /* select register of MMD */ + val = mmdidx; + ret = lan78xx_write_reg(dev, MII_DATA, val); + + phy_id &= dev->mii.phy_id_mask; + addr = mii_access(phy_id, PHY_MMD_REG_DATA, MII_WRITE); + ret = lan78xx_write_reg(dev, MII_ACC, addr); + + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + /* select register data for MMD */ + val = PHY_MMD_CTRL_OP_DNI_ | mmddev; + ret = lan78xx_write_reg(dev, MII_DATA, val); + + phy_id &= dev->mii.phy_id_mask; + addr = mii_access(phy_id, PHY_MMD_CTL, MII_WRITE); + ret = lan78xx_write_reg(dev, MII_ACC, addr); + + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + /* write to MMD */ + val = regval; + ret = lan78xx_write_reg(dev, MII_DATA, val); + + phy_id &= dev->mii.phy_id_mask; + addr = mii_access(phy_id, PHY_MMD_REG_DATA, MII_WRITE); + ret = lan78xx_write_reg(dev, MII_ACC, addr); + + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + +done: + mutex_unlock(&dev->phy_mutex); + usb_autopm_put_interface(dev->intf); +} + +static int lan78xx_mmd_read(struct net_device *netdev, int phy_id, + int mmddev, int mmdidx) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + u32 val, addr; + int ret; + + ret = usb_autopm_get_interface(dev->intf); + if (ret < 0) + return ret; + + mutex_lock(&dev->phy_mutex); + + /* confirm MII not busy */ + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + /* set up device address for MMD */ + ret = lan78xx_write_reg(dev, MII_DATA, mmddev); + + phy_id &= dev->mii.phy_id_mask; + addr = mii_access(phy_id, PHY_MMD_CTL, MII_WRITE); + ret = lan78xx_write_reg(dev, MII_ACC, addr); + + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + /* select register of MMD */ + val = mmdidx; + ret = lan78xx_write_reg(dev, MII_DATA, val); + + phy_id &= dev->mii.phy_id_mask; + addr = mii_access(phy_id, PHY_MMD_REG_DATA, MII_WRITE); + ret = lan78xx_write_reg(dev, MII_ACC, addr); + + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + /* select register data for MMD */ + val = PHY_MMD_CTRL_OP_DNI_ | mmddev; + ret = lan78xx_write_reg(dev, MII_DATA, val); + + phy_id &= dev->mii.phy_id_mask; + addr = mii_access(phy_id, PHY_MMD_CTL, MII_WRITE); + ret = lan78xx_write_reg(dev, MII_ACC, addr); + + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + /* set the address, index & direction (read from PHY) */ + phy_id &= dev->mii.phy_id_mask; + addr = mii_access(phy_id, PHY_MMD_REG_DATA, MII_READ); + ret = lan78xx_write_reg(dev, MII_ACC, addr); + + ret = lan78xx_phy_wait_not_busy(dev); + if (ret < 0) + goto done; + + /* read from MMD */ + ret = lan78xx_read_reg(dev, MII_DATA, &val); + + ret = (int)(val & 0xFFFF); + +done: + mutex_unlock(&dev->phy_mutex); + usb_autopm_put_interface(dev->intf); + return ret; +} + +static int lan78xx_wait_eeprom(struct lan78xx_net *dev) +{ + unsigned long start_time = jiffies; + u32 val; + int ret; + + do { + ret = lan78xx_read_reg(dev, E2P_CMD, &val); + if (unlikely(ret < 0)) + return -EIO; + + if (!(val & E2P_CMD_EPC_BUSY_) || + (val & E2P_CMD_EPC_TIMEOUT_)) + break; + usleep_range(40, 100); + } while (!time_after(jiffies, start_time + HZ)); + + if (val & (E2P_CMD_EPC_TIMEOUT_ | E2P_CMD_EPC_BUSY_)) { + netdev_warn(dev->net, "EEPROM read operation timeout"); + return -EIO; + } + + return 0; +} + +static int lan78xx_eeprom_confirm_not_busy(struct lan78xx_net *dev) +{ + unsigned long start_time = jiffies; + u32 val; + int ret; + + do { + ret = lan78xx_read_reg(dev, E2P_CMD, &val); + if (unlikely(ret < 0)) + return -EIO; + + if (!(val & E2P_CMD_EPC_BUSY_)) + return 0; + + usleep_range(40, 100); + } while (!time_after(jiffies, start_time + HZ)); + + netdev_warn(dev->net, "EEPROM is busy"); + return -EIO; +} + +static int lan78xx_read_raw_eeprom(struct lan78xx_net *dev, u32 offset, + u32 length, u8 *data) +{ + u32 val; + int i, ret; + + BUG_ON(!dev); + BUG_ON(!data); + + ret = lan78xx_eeprom_confirm_not_busy(dev); + if (ret) + return ret; + + for (i = 0; i < length; i++) { + val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_READ_; + val |= (offset & E2P_CMD_EPC_ADDR_MASK_); + ret = lan78xx_write_reg(dev, E2P_CMD, val); + if (unlikely(ret < 0)) + return -EIO; + + ret = lan78xx_wait_eeprom(dev); + if (ret < 0) + return ret; + + ret = lan78xx_read_reg(dev, E2P_DATA, &val); + if (unlikely(ret < 0)) + return -EIO; + + data[i] = val & 0xFF; + offset++; + } + + return 0; +} + +static int lan78xx_read_eeprom(struct lan78xx_net *dev, u32 offset, + u32 length, u8 *data) +{ + u8 sig; + int ret; + + ret = lan78xx_read_raw_eeprom(dev, 0, 1, &sig); + if ((ret == 0) && (sig == EEPROM_INDICATOR)) + ret = lan78xx_read_raw_eeprom(dev, offset, length, data); + else + ret = -EINVAL; + + return ret; +} + +static int lan78xx_write_raw_eeprom(struct lan78xx_net *dev, u32 offset, + u32 length, u8 *data) +{ + u32 val; + int i, ret; + + BUG_ON(!dev); + BUG_ON(!data); + + ret = lan78xx_eeprom_confirm_not_busy(dev); + if (ret) + return ret; + + /* Issue write/erase enable command */ + val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWEN_; + ret = lan78xx_write_reg(dev, E2P_CMD, val); + if (unlikely(ret < 0)) + return -EIO; + + ret = lan78xx_wait_eeprom(dev); + if (ret < 0) + return ret; + + for (i = 0; i < length; i++) { + /* Fill data register */ + val = data[i]; + ret = lan78xx_write_reg(dev, E2P_DATA, val); + if (ret < 0) + return ret; + + /* Send "write" command */ + val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_WRITE_; + val |= (offset & E2P_CMD_EPC_ADDR_MASK_); + ret = lan78xx_write_reg(dev, E2P_CMD, val); + if (ret < 0) + return ret; + + ret = lan78xx_wait_eeprom(dev); + if (ret < 0) + return ret; + + offset++; + } + + return 0; +} + +static int lan78xx_read_raw_otp(struct lan78xx_net *dev, u32 offset, + u32 length, u8 *data) +{ + int i; + int ret; + u32 buf; + unsigned long timeout; + + ret = lan78xx_read_reg(dev, OTP_PWR_DN, &buf); + + if (buf & OTP_PWR_DN_PWRDN_N_) { + /* clear it and wait to be cleared */ + ret = lan78xx_write_reg(dev, OTP_PWR_DN, 0); + + timeout = jiffies + HZ; + do { + usleep_range(1, 10); + ret = lan78xx_read_reg(dev, OTP_PWR_DN, &buf); + if (time_after(jiffies, timeout)) { + netdev_warn(dev->net, + "timeout on OTP_PWR_DN"); + return -EIO; + } + } while (buf & OTP_PWR_DN_PWRDN_N_); + } + + for (i = 0; i < length; i++) { + ret = lan78xx_write_reg(dev, OTP_ADDR1, + ((offset + i) >> 8) & OTP_ADDR1_15_11); + ret = lan78xx_write_reg(dev, OTP_ADDR2, + ((offset + i) & OTP_ADDR2_10_3)); + + ret = lan78xx_write_reg(dev, OTP_FUNC_CMD, OTP_FUNC_CMD_READ_); + ret = lan78xx_write_reg(dev, OTP_CMD_GO, OTP_CMD_GO_GO_); + + timeout = jiffies + HZ; + do { + udelay(1); + ret = lan78xx_read_reg(dev, OTP_STATUS, &buf); + if (time_after(jiffies, timeout)) { + netdev_warn(dev->net, + "timeout on OTP_STATUS"); + return -EIO; + } + } while (buf & OTP_STATUS_BUSY_); + + ret = lan78xx_read_reg(dev, OTP_RD_DATA, &buf); + + data[i] = (u8)(buf & 0xFF); + } + + return 0; +} + +static int lan78xx_read_otp(struct lan78xx_net *dev, u32 offset, + u32 length, u8 *data) +{ + u8 sig; + int ret; + + ret = lan78xx_read_raw_otp(dev, 0, 1, &sig); + + if (ret == 0) { + if (sig == OTP_INDICATOR_1) + offset = offset; + else if (sig == OTP_INDICATOR_2) + offset += 0x100; + else + ret = -EINVAL; + ret = lan78xx_read_raw_otp(dev, offset, length, data); + } + + return ret; +} + +static int lan78xx_dataport_wait_not_busy(struct lan78xx_net *dev) +{ + int i, ret; + + for (i = 0; i < 100; i++) { + u32 dp_sel; + + ret = lan78xx_read_reg(dev, DP_SEL, &dp_sel); + if (unlikely(ret < 0)) + return -EIO; + + if (dp_sel & DP_SEL_DPRDY_) + return 0; + + usleep_range(40, 100); + } + + netdev_warn(dev->net, "lan78xx_dataport_wait_not_busy timed out"); + + return -EIO; +} + +static int lan78xx_dataport_write(struct lan78xx_net *dev, u32 ram_select, + u32 addr, u32 length, u32 *buf) +{ + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + u32 dp_sel; + int i, ret; + + if (usb_autopm_get_interface(dev->intf) < 0) + return 0; + + mutex_lock(&pdata->dataport_mutex); + + ret = lan78xx_dataport_wait_not_busy(dev); + if (ret < 0) + goto done; + + ret = lan78xx_read_reg(dev, DP_SEL, &dp_sel); + + dp_sel &= ~DP_SEL_RSEL_MASK_; + dp_sel |= ram_select; + ret = lan78xx_write_reg(dev, DP_SEL, dp_sel); + + for (i = 0; i < length; i++) { + ret = lan78xx_write_reg(dev, DP_ADDR, addr + i); + + ret = lan78xx_write_reg(dev, DP_DATA, buf[i]); + + ret = lan78xx_write_reg(dev, DP_CMD, DP_CMD_WRITE_); + + ret = lan78xx_dataport_wait_not_busy(dev); + if (ret < 0) + goto done; + } + +done: + mutex_unlock(&pdata->dataport_mutex); + usb_autopm_put_interface(dev->intf); + + return ret; +} + +static void lan78xx_set_addr_filter(struct lan78xx_priv *pdata, + int index, u8 addr[ETH_ALEN]) +{ + u32 temp; + + if ((pdata) && (index > 0) && (index < NUM_OF_MAF)) { + temp = addr[3]; + temp = addr[2] | (temp << 8); + temp = addr[1] | (temp << 8); + temp = addr[0] | (temp << 8); + pdata->pfilter_table[index][1] = temp; + temp = addr[5]; + temp = addr[4] | (temp << 8); + temp |= MAF_HI_VALID_ | MAF_HI_TYPE_DST_; + pdata->pfilter_table[index][0] = temp; + } +} + +/* returns hash bit number for given MAC address */ +static inline u32 lan78xx_hash(char addr[ETH_ALEN]) +{ + return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff; +} + +static void lan78xx_deferred_multicast_write(struct work_struct *param) +{ + struct lan78xx_priv *pdata = + container_of(param, struct lan78xx_priv, set_multicast); + struct lan78xx_net *dev = pdata->dev; + int i; + int ret; + + netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x\n", + pdata->rfe_ctl); + + lan78xx_dataport_write(dev, DP_SEL_RSEL_VLAN_DA_, DP_SEL_VHF_VLAN_LEN, + DP_SEL_VHF_HASH_LEN, pdata->mchash_table); + + for (i = 1; i < NUM_OF_MAF; i++) { + ret = lan78xx_write_reg(dev, MAF_HI(i), 0); + ret = lan78xx_write_reg(dev, MAF_LO(i), + pdata->pfilter_table[i][1]); + ret = lan78xx_write_reg(dev, MAF_HI(i), + pdata->pfilter_table[i][0]); + } + + ret = lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); +} + +static void lan78xx_set_multicast(struct net_device *netdev) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + unsigned long flags; + int i; + + spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); + + pdata->rfe_ctl &= ~(RFE_CTL_UCAST_EN_ | RFE_CTL_MCAST_EN_ | + RFE_CTL_DA_PERFECT_ | RFE_CTL_MCAST_HASH_); + + for (i = 0; i < DP_SEL_VHF_HASH_LEN; i++) + pdata->mchash_table[i] = 0; + /* pfilter_table[0] has own HW address */ + for (i = 1; i < NUM_OF_MAF; i++) { + pdata->pfilter_table[i][0] = + pdata->pfilter_table[i][1] = 0; + } + + pdata->rfe_ctl |= RFE_CTL_BCAST_EN_; + + if (dev->net->flags & IFF_PROMISC) { + netif_dbg(dev, drv, dev->net, "promiscuous mode enabled"); + pdata->rfe_ctl |= RFE_CTL_MCAST_EN_ | RFE_CTL_UCAST_EN_; + } else { + if (dev->net->flags & IFF_ALLMULTI) { + netif_dbg(dev, drv, dev->net, + "receive all multicast enabled"); + pdata->rfe_ctl |= RFE_CTL_MCAST_EN_; + } + } + + if (netdev_mc_count(dev->net)) { + struct netdev_hw_addr *ha; + int i; + + netif_dbg(dev, drv, dev->net, "receive multicast hash filter"); + + pdata->rfe_ctl |= RFE_CTL_DA_PERFECT_; + + i = 1; + netdev_for_each_mc_addr(ha, netdev) { + /* set first 32 into Perfect Filter */ + if (i < 33) { + lan78xx_set_addr_filter(pdata, i, ha->addr); + } else { + u32 bitnum = lan78xx_hash(ha->addr); + + pdata->mchash_table[bitnum / 32] |= + (1 << (bitnum % 32)); + pdata->rfe_ctl |= RFE_CTL_MCAST_HASH_; + } + i++; + } + } + + spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); + + /* defer register writes to a sleepable context */ + schedule_work(&pdata->set_multicast); +} + +static int lan78xx_update_flowcontrol(struct lan78xx_net *dev, u8 duplex, + u16 lcladv, u16 rmtadv) +{ + u32 flow = 0, fct_flow = 0; + int ret; + + u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); + + if (cap & FLOW_CTRL_TX) + flow = (FLOW_CR_TX_FCEN_ | 0xFFFF); + + if (cap & FLOW_CTRL_RX) + flow |= FLOW_CR_RX_FCEN_; + + if (dev->udev->speed == USB_SPEED_SUPER) + fct_flow = 0x817; + else if (dev->udev->speed == USB_SPEED_HIGH) + fct_flow = 0x211; + + netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s", + (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), + (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); + + ret = lan78xx_write_reg(dev, FCT_FLOW, fct_flow); + + /* threshold value should be set before enabling flow */ + ret = lan78xx_write_reg(dev, FLOW, flow); + + return 0; +} + +static int lan78xx_link_reset(struct lan78xx_net *dev) +{ + struct mii_if_info *mii = &dev->mii; + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; + u16 ladv, radv; + int ret; + u32 buf; + + /* clear PHY interrupt status */ + /* VTSE PHY */ + ret = lan78xx_mdio_read(dev->net, mii->phy_id, PHY_VTSE_INT_STS); + if (unlikely(ret < 0)) + return -EIO; + + /* clear LAN78xx interrupt status */ + ret = lan78xx_write_reg(dev, INT_STS, INT_STS_PHY_INT_); + if (unlikely(ret < 0)) + return -EIO; + + if (!mii_link_ok(mii) && dev->link_on) { + dev->link_on = false; + netif_carrier_off(dev->net); + + /* reset MAC */ + ret = lan78xx_read_reg(dev, MAC_CR, &buf); + if (unlikely(ret < 0)) + return -EIO; + buf |= MAC_CR_RST_; + ret = lan78xx_write_reg(dev, MAC_CR, buf); + if (unlikely(ret < 0)) + return -EIO; + } else if (mii_link_ok(mii) && !dev->link_on) { + dev->link_on = true; + + mii_check_media(mii, 1, 1); + mii_ethtool_gset(&dev->mii, &ecmd); + + mii->mdio_read(mii->dev, mii->phy_id, PHY_VTSE_INT_STS); + + if (dev->udev->speed == USB_SPEED_SUPER) { + if (ethtool_cmd_speed(&ecmd) == 1000) { + /* disable U2 */ + ret = lan78xx_read_reg(dev, USB_CFG1, &buf); + buf &= ~USB_CFG1_DEV_U2_INIT_EN_; + ret = lan78xx_write_reg(dev, USB_CFG1, buf); + /* enable U1 */ + ret = lan78xx_read_reg(dev, USB_CFG1, &buf); + buf |= USB_CFG1_DEV_U1_INIT_EN_; + ret = lan78xx_write_reg(dev, USB_CFG1, buf); + } else { + /* enable U1 & U2 */ + ret = lan78xx_read_reg(dev, USB_CFG1, &buf); + buf |= USB_CFG1_DEV_U2_INIT_EN_; + buf |= USB_CFG1_DEV_U1_INIT_EN_; + ret = lan78xx_write_reg(dev, USB_CFG1, buf); + } + } + + ladv = lan78xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); + if (unlikely(ladv < 0)) + return -EIO; + + radv = lan78xx_mdio_read(dev->net, mii->phy_id, MII_LPA); + if (unlikely(radv < 0)) + return -EIO; + + netif_dbg(dev, link, dev->net, + "speed: %u duplex: %d anadv: 0x%04x anlpa: 0x%04x", + ethtool_cmd_speed(&ecmd), ecmd.duplex, ladv, radv); + + ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv); + netif_carrier_on(dev->net); + } + + return ret; +} + +/* some work can't be done in tasklets, so we use keventd + * + * NOTE: annoying asymmetry: if it's active, schedule_work() fails, + * but tasklet_schedule() doesn't. hope the failure is rare. + */ +void lan78xx_defer_kevent(struct lan78xx_net *dev, int work) +{ + set_bit(work, &dev->flags); + if (!schedule_delayed_work(&dev->wq, 0)) + netdev_err(dev->net, "kevent %d may have been dropped\n", work); +} + +static void lan78xx_status(struct lan78xx_net *dev, struct urb *urb) +{ + u32 intdata; + + if (urb->actual_length != 4) { + netdev_warn(dev->net, + "unexpected urb length %d", urb->actual_length); + return; + } + + memcpy(&intdata, urb->transfer_buffer, 4); + le32_to_cpus(&intdata); + + if (intdata & INT_ENP_PHY_INT) { + netif_dbg(dev, link, dev->net, "PHY INTR: 0x%08x\n", intdata); + lan78xx_defer_kevent(dev, EVENT_LINK_RESET); + } else + netdev_warn(dev->net, + "unexpected interrupt: 0x%08x\n", intdata); +} + +static int lan78xx_ethtool_get_eeprom_len(struct net_device *netdev) +{ + return MAX_EEPROM_SIZE; +} + +static int lan78xx_ethtool_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *ee, u8 *data) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + + ee->magic = LAN78XX_EEPROM_MAGIC; + + return lan78xx_read_raw_eeprom(dev, ee->offset, ee->len, data); +} + +static int lan78xx_ethtool_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *ee, u8 *data) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + + /* Allow entire eeprom update only */ + if ((ee->magic == LAN78XX_EEPROM_MAGIC) && + (ee->offset == 0) && + (ee->len == 512) && + (data[0] == EEPROM_INDICATOR)) + return lan78xx_write_raw_eeprom(dev, ee->offset, ee->len, data); + else if ((ee->magic == LAN78XX_OTP_MAGIC) && + (ee->offset == 0) && + (ee->len == 512) && + (data[0] == OTP_INDICATOR_1)) + return lan78xx_write_raw_eeprom(dev, ee->offset, ee->len, data); + + return -EINVAL; +} + +static void lan78xx_get_strings(struct net_device *netdev, u32 stringset, + u8 *data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, lan78xx_gstrings, sizeof(lan78xx_gstrings)); +} + +static int lan78xx_get_sset_count(struct net_device *netdev, int sset) +{ + if (sset == ETH_SS_STATS) + return ARRAY_SIZE(lan78xx_gstrings); + else + return -EOPNOTSUPP; +} + +static void lan78xx_get_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + struct lan78xx_statstage lan78xx_stat; + u32 *p; + int i; + + if (usb_autopm_get_interface(dev->intf) < 0) + return; + + if (lan78xx_read_stats(dev, &lan78xx_stat) > 0) { + p = (u32 *)&lan78xx_stat; + for (i = 0; i < (sizeof(lan78xx_stat) / (sizeof(u32))); i++) + data[i] = p[i]; + } + + usb_autopm_put_interface(dev->intf); +} + +static void lan78xx_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + int ret; + u32 buf; + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + + if (usb_autopm_get_interface(dev->intf) < 0) + return; + + ret = lan78xx_read_reg(dev, USB_CFG0, &buf); + if (unlikely(ret < 0)) { + wol->supported = 0; + wol->wolopts = 0; + } else { + if (buf & USB_CFG_RMT_WKP_) { + wol->supported = WAKE_ALL; + wol->wolopts = pdata->wol; + } else { + wol->supported = 0; + wol->wolopts = 0; + } + } + + usb_autopm_put_interface(dev->intf); +} + +static int lan78xx_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + int ret; + + ret = usb_autopm_get_interface(dev->intf); + if (ret < 0) + return ret; + + pdata->wol = 0; + if (wol->wolopts & WAKE_UCAST) + pdata->wol |= WAKE_UCAST; + if (wol->wolopts & WAKE_MCAST) + pdata->wol |= WAKE_MCAST; + if (wol->wolopts & WAKE_BCAST) + pdata->wol |= WAKE_BCAST; + if (wol->wolopts & WAKE_MAGIC) + pdata->wol |= WAKE_MAGIC; + if (wol->wolopts & WAKE_PHY) + pdata->wol |= WAKE_PHY; + if (wol->wolopts & WAKE_ARP) + pdata->wol |= WAKE_ARP; + + device_set_wakeup_enable(&dev->udev->dev, (bool)wol->wolopts); + + usb_autopm_put_interface(dev->intf); + + return ret; +} + +static int lan78xx_get_eee(struct net_device *net, struct ethtool_eee *edata) +{ + struct lan78xx_net *dev = netdev_priv(net); + int ret; + u32 buf; + u32 adv, lpadv; + + ret = usb_autopm_get_interface(dev->intf); + if (ret < 0) + return ret; + + ret = lan78xx_read_reg(dev, MAC_CR, &buf); + if (buf & MAC_CR_EEE_EN_) { + buf = lan78xx_mmd_read(dev->net, dev->mii.phy_id, + PHY_MMD_DEV_7, PHY_EEE_ADVERTISEMENT); + adv = mmd_eee_adv_to_ethtool_adv_t(buf); + buf = lan78xx_mmd_read(dev->net, dev->mii.phy_id, + PHY_MMD_DEV_7, PHY_EEE_LP_ADVERTISEMENT); + lpadv = mmd_eee_adv_to_ethtool_adv_t(buf); + + edata->eee_enabled = true; + edata->supported = true; + edata->eee_active = !!(adv & lpadv); + edata->advertised = adv; + edata->lp_advertised = lpadv; + edata->tx_lpi_enabled = true; + /* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */ + ret = lan78xx_read_reg(dev, EEE_TX_LPI_REQ_DLY, &buf); + edata->tx_lpi_timer = buf; + } else { + buf = lan78xx_mmd_read(dev->net, dev->mii.phy_id, + PHY_MMD_DEV_7, PHY_EEE_LP_ADVERTISEMENT); + lpadv = mmd_eee_adv_to_ethtool_adv_t(buf); + + edata->eee_enabled = false; + edata->eee_active = false; + edata->supported = false; + edata->advertised = 0; + edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(lpadv); + edata->tx_lpi_enabled = false; + edata->tx_lpi_timer = 0; + } + + usb_autopm_put_interface(dev->intf); + + return 0; +} + +static int lan78xx_set_eee(struct net_device *net, struct ethtool_eee *edata) +{ + struct lan78xx_net *dev = netdev_priv(net); + int ret; + u32 buf; + + ret = usb_autopm_get_interface(dev->intf); + if (ret < 0) + return ret; + + if (edata->eee_enabled) { + ret = lan78xx_read_reg(dev, MAC_CR, &buf); + buf |= MAC_CR_EEE_EN_; + ret = lan78xx_write_reg(dev, MAC_CR, buf); + + buf = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); + lan78xx_mmd_write(dev->net, dev->mii.phy_id, + PHY_MMD_DEV_7, PHY_EEE_ADVERTISEMENT, buf); + } else { + ret = lan78xx_read_reg(dev, MAC_CR, &buf); + buf &= ~MAC_CR_EEE_EN_; + ret = lan78xx_write_reg(dev, MAC_CR, buf); + } + + usb_autopm_put_interface(dev->intf); + + return 0; +} + +static u32 lan78xx_get_link(struct net_device *net) +{ + struct lan78xx_net *dev = netdev_priv(net); + + return mii_link_ok(&dev->mii); +} + +int lan78xx_nway_reset(struct net_device *net) +{ + struct lan78xx_net *dev = netdev_priv(net); + + if ((!dev->mii.mdio_read) || (!dev->mii.mdio_write)) + return -EOPNOTSUPP; + + return mii_nway_restart(&dev->mii); +} + +static void lan78xx_get_drvinfo(struct net_device *net, + struct ethtool_drvinfo *info) +{ + struct lan78xx_net *dev = netdev_priv(net); + + strncpy(info->driver, DRIVER_NAME, sizeof(info->driver)); + strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); + usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info)); +} + +static u32 lan78xx_get_msglevel(struct net_device *net) +{ + struct lan78xx_net *dev = netdev_priv(net); + + return dev->msg_enable; +} + +static void lan78xx_set_msglevel(struct net_device *net, u32 level) +{ + struct lan78xx_net *dev = netdev_priv(net); + + dev->msg_enable = level; +} + +static int lan78xx_get_settings(struct net_device *net, struct ethtool_cmd *cmd) +{ + struct lan78xx_net *dev = netdev_priv(net); + struct mii_if_info *mii = &dev->mii; + int ret; + int buf; + + if ((!dev->mii.mdio_read) || (!dev->mii.mdio_write)) + return -EOPNOTSUPP; + + ret = usb_autopm_get_interface(dev->intf); + if (ret < 0) + return ret; + + ret = mii_ethtool_gset(&dev->mii, cmd); + + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_1); + buf = mii->mdio_read(mii->dev, mii->phy_id, PHY_EXT_MODE_CTRL); + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_0); + + buf &= PHY_EXT_MODE_CTRL_MDIX_MASK_; + if (buf == PHY_EXT_MODE_CTRL_AUTO_MDIX_) { + cmd->eth_tp_mdix = ETH_TP_MDI_AUTO; + cmd->eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO; + } else if (buf == PHY_EXT_MODE_CTRL_MDI_) { + cmd->eth_tp_mdix = ETH_TP_MDI; + cmd->eth_tp_mdix_ctrl = ETH_TP_MDI; + } else if (buf == PHY_EXT_MODE_CTRL_MDI_X_) { + cmd->eth_tp_mdix = ETH_TP_MDI_X; + cmd->eth_tp_mdix_ctrl = ETH_TP_MDI_X; + } + + usb_autopm_put_interface(dev->intf); + + return ret; +} + +static int lan78xx_set_settings(struct net_device *net, struct ethtool_cmd *cmd) +{ + struct lan78xx_net *dev = netdev_priv(net); + struct mii_if_info *mii = &dev->mii; + int ret = 0; + int temp; + + if ((!dev->mii.mdio_read) || (!dev->mii.mdio_write)) + return -EOPNOTSUPP; + + ret = usb_autopm_get_interface(dev->intf); + if (ret < 0) + return ret; + + if (dev->mdix_ctrl != cmd->eth_tp_mdix_ctrl) { + if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI) { + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_GPIO_PAGE, + PHY_EXT_GPIO_PAGE_SPACE_1); + temp = mii->mdio_read(mii->dev, mii->phy_id, + PHY_EXT_MODE_CTRL); + temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_; + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_MODE_CTRL, + temp | PHY_EXT_MODE_CTRL_MDI_); + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_GPIO_PAGE, + PHY_EXT_GPIO_PAGE_SPACE_0); + } else if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI_X) { + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_GPIO_PAGE, + PHY_EXT_GPIO_PAGE_SPACE_1); + temp = mii->mdio_read(mii->dev, mii->phy_id, + PHY_EXT_MODE_CTRL); + temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_; + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_MODE_CTRL, + temp | PHY_EXT_MODE_CTRL_MDI_X_); + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_GPIO_PAGE, + PHY_EXT_GPIO_PAGE_SPACE_0); + } else if (cmd->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO) { + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_GPIO_PAGE, + PHY_EXT_GPIO_PAGE_SPACE_1); + temp = mii->mdio_read(mii->dev, mii->phy_id, + PHY_EXT_MODE_CTRL); + temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_; + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_MODE_CTRL, + temp | PHY_EXT_MODE_CTRL_AUTO_MDIX_); + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_GPIO_PAGE, + PHY_EXT_GPIO_PAGE_SPACE_0); + } + } + + /* change speed & duplex */ + ret = mii_ethtool_sset(&dev->mii, cmd); + + if (!cmd->autoneg) { + /* force link down */ + temp = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR); + mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, + temp | BMCR_LOOPBACK); + mdelay(1); + mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, temp); + } + + usb_autopm_put_interface(dev->intf); + + return ret; +} + +static const struct ethtool_ops lan78xx_ethtool_ops = { + .get_link = lan78xx_get_link, + .nway_reset = lan78xx_nway_reset, + .get_drvinfo = lan78xx_get_drvinfo, + .get_msglevel = lan78xx_get_msglevel, + .set_msglevel = lan78xx_set_msglevel, + .get_settings = lan78xx_get_settings, + .set_settings = lan78xx_set_settings, + .get_eeprom_len = lan78xx_ethtool_get_eeprom_len, + .get_eeprom = lan78xx_ethtool_get_eeprom, + .set_eeprom = lan78xx_ethtool_set_eeprom, + .get_ethtool_stats = lan78xx_get_stats, + .get_sset_count = lan78xx_get_sset_count, + .get_strings = lan78xx_get_strings, + .get_wol = lan78xx_get_wol, + .set_wol = lan78xx_set_wol, + .get_eee = lan78xx_get_eee, + .set_eee = lan78xx_set_eee, +}; + +static int lan78xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + + if (!netif_running(netdev)) + return -EINVAL; + + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +static void lan78xx_init_mac_address(struct lan78xx_net *dev) +{ + u32 addr_lo, addr_hi; + int ret; + u8 addr[6]; + + ret = lan78xx_read_reg(dev, RX_ADDRL, &addr_lo); + ret = lan78xx_read_reg(dev, RX_ADDRH, &addr_hi); + + addr[0] = addr_lo & 0xFF; + addr[1] = (addr_lo >> 8) & 0xFF; + addr[2] = (addr_lo >> 16) & 0xFF; + addr[3] = (addr_lo >> 24) & 0xFF; + addr[4] = addr_hi & 0xFF; + addr[5] = (addr_hi >> 8) & 0xFF; + + if (!is_valid_ether_addr(addr)) { + /* reading mac address from EEPROM or OTP */ + if ((lan78xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, + addr) == 0) || + (lan78xx_read_otp(dev, EEPROM_MAC_OFFSET, ETH_ALEN, + addr) == 0)) { + if (is_valid_ether_addr(addr)) { + /* eeprom values are valid so use them */ + netif_dbg(dev, ifup, dev->net, + "MAC address read from EEPROM"); + } else { + /* generate random MAC */ + random_ether_addr(addr); + netif_dbg(dev, ifup, dev->net, + "MAC address set to random addr"); + } + + addr_lo = addr[0] | (addr[1] << 8) | + (addr[2] << 16) | (addr[3] << 24); + addr_hi = addr[4] | (addr[5] << 8); + + ret = lan78xx_write_reg(dev, RX_ADDRL, addr_lo); + ret = lan78xx_write_reg(dev, RX_ADDRH, addr_hi); + } else { + /* generate random MAC */ + random_ether_addr(addr); + netif_dbg(dev, ifup, dev->net, + "MAC address set to random addr"); + } + } + + ret = lan78xx_write_reg(dev, MAF_LO(0), addr_lo); + ret = lan78xx_write_reg(dev, MAF_HI(0), addr_hi | MAF_HI_VALID_); + + ether_addr_copy(dev->net->dev_addr, addr); +} + +static void lan78xx_mii_init(struct lan78xx_net *dev) +{ + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = lan78xx_mdio_read; + dev->mii.mdio_write = lan78xx_mdio_write; + dev->mii.phy_id_mask = 0x1f; + dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = INTERNAL_PHY_ID; + dev->mii.supports_gmii = true; +} + +static int lan78xx_phy_init(struct lan78xx_net *dev) +{ + int temp; + struct mii_if_info *mii = &dev->mii; + + if ((!mii->mdio_write) || (!mii->mdio_read)) + return -EOPNOTSUPP; + + temp = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE); + temp |= ADVERTISE_ALL; + mii->mdio_write(mii->dev, mii->phy_id, MII_ADVERTISE, + temp | ADVERTISE_CSMA | + ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + + /* set to AUTOMDIX */ + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_1); + temp = mii->mdio_read(mii->dev, mii->phy_id, PHY_EXT_MODE_CTRL); + temp &= ~PHY_EXT_MODE_CTRL_MDIX_MASK_; + mii->mdio_write(mii->dev, mii->phy_id, PHY_EXT_MODE_CTRL, + temp | PHY_EXT_MODE_CTRL_AUTO_MDIX_); + mii->mdio_write(mii->dev, mii->phy_id, + PHY_EXT_GPIO_PAGE, PHY_EXT_GPIO_PAGE_SPACE_0); + dev->mdix_ctrl = ETH_TP_MDI_AUTO; + + /* MAC doesn't support 1000HD */ + temp = mii->mdio_read(mii->dev, mii->phy_id, MII_CTRL1000); + mii->mdio_write(mii->dev, mii->phy_id, MII_CTRL1000, + temp & ~ADVERTISE_1000HALF); + + /* clear interrupt */ + mii->mdio_read(mii->dev, mii->phy_id, PHY_VTSE_INT_STS); + mii->mdio_write(mii->dev, mii->phy_id, PHY_VTSE_INT_MASK, + PHY_VTSE_INT_MASK_MDINTPIN_EN_ | + PHY_VTSE_INT_MASK_LINK_CHANGE_); + + netif_dbg(dev, ifup, dev->net, "phy initialised successfully"); + + return 0; +} + +static int lan78xx_set_rx_max_frame_length(struct lan78xx_net *dev, int size) +{ + int ret = 0; + u32 buf; + bool rxenabled; + + ret = lan78xx_read_reg(dev, MAC_RX, &buf); + + rxenabled = ((buf & MAC_RX_RXEN_) != 0); + + if (rxenabled) { + buf &= ~MAC_RX_RXEN_; + ret = lan78xx_write_reg(dev, MAC_RX, buf); + } + + /* add 4 to size for FCS */ + buf &= ~MAC_RX_MAX_SIZE_MASK_; + buf |= (((size + 4) << MAC_RX_MAX_SIZE_SHIFT_) & MAC_RX_MAX_SIZE_MASK_); + + ret = lan78xx_write_reg(dev, MAC_RX, buf); + + if (rxenabled) { + buf |= MAC_RX_RXEN_; + ret = lan78xx_write_reg(dev, MAC_RX, buf); + } + + return 0; +} + +static int unlink_urbs(struct lan78xx_net *dev, struct sk_buff_head *q) +{ + struct sk_buff *skb; + unsigned long flags; + int count = 0; + + spin_lock_irqsave(&q->lock, flags); + while (!skb_queue_empty(q)) { + struct skb_data *entry; + struct urb *urb; + int ret; + + skb_queue_walk(q, skb) { + entry = (struct skb_data *)skb->cb; + if (entry->state != unlink_start) + goto found; + } + break; +found: + entry->state = unlink_start; + urb = entry->urb; + + /* Get reference count of the URB to avoid it to be + * freed during usb_unlink_urb, which may trigger + * use-after-free problem inside usb_unlink_urb since + * usb_unlink_urb is always racing with .complete + * handler(include defer_bh). + */ + usb_get_urb(urb); + spin_unlock_irqrestore(&q->lock, flags); + /* during some PM-driven resume scenarios, + * these (async) unlinks complete immediately + */ + ret = usb_unlink_urb(urb); + if (ret != -EINPROGRESS && ret != 0) + netdev_dbg(dev->net, "unlink urb err, %d\n", ret); + else + count++; + usb_put_urb(urb); + spin_lock_irqsave(&q->lock, flags); + } + spin_unlock_irqrestore(&q->lock, flags); + return count; +} + +static int lan78xx_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + int ll_mtu = new_mtu + netdev->hard_header_len; + int old_hard_mtu = dev->hard_mtu; + int old_rx_urb_size = dev->rx_urb_size; + int ret; + + if (new_mtu > MAX_SINGLE_PACKET_SIZE) + return -EINVAL; + + if (new_mtu <= 0) + return -EINVAL; + /* no second zero-length packet read wanted after mtu-sized packets */ + if ((ll_mtu % dev->maxpacket) == 0) + return -EDOM; + + ret = lan78xx_set_rx_max_frame_length(dev, new_mtu + ETH_HLEN); + + netdev->mtu = new_mtu; + + dev->hard_mtu = netdev->mtu + netdev->hard_header_len; + if (dev->rx_urb_size == old_hard_mtu) { + dev->rx_urb_size = dev->hard_mtu; + if (dev->rx_urb_size > old_rx_urb_size) { + if (netif_running(dev->net)) { + unlink_urbs(dev, &dev->rxq); + tasklet_schedule(&dev->bh); + } + } + } + + return 0; +} + +int lan78xx_set_mac_addr(struct net_device *netdev, void *p) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + struct sockaddr *addr = p; + u32 addr_lo, addr_hi; + int ret; + + if (netif_running(netdev)) + return -EBUSY; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + ether_addr_copy(netdev->dev_addr, addr->sa_data); + + addr_lo = netdev->dev_addr[0] | + netdev->dev_addr[1] << 8 | + netdev->dev_addr[2] << 16 | + netdev->dev_addr[3] << 24; + addr_hi = netdev->dev_addr[4] | + netdev->dev_addr[5] << 8; + + ret = lan78xx_write_reg(dev, RX_ADDRL, addr_lo); + ret = lan78xx_write_reg(dev, RX_ADDRH, addr_hi); + + return 0; +} + +/* Enable or disable Rx checksum offload engine */ +static int lan78xx_set_features(struct net_device *netdev, + netdev_features_t features) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + unsigned long flags; + int ret; + + spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); + + if (features & NETIF_F_RXCSUM) { + pdata->rfe_ctl |= RFE_CTL_TCPUDP_COE_ | RFE_CTL_IP_COE_; + pdata->rfe_ctl |= RFE_CTL_ICMP_COE_ | RFE_CTL_IGMP_COE_; + } else { + pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_COE_ | RFE_CTL_IP_COE_); + pdata->rfe_ctl &= ~(RFE_CTL_ICMP_COE_ | RFE_CTL_IGMP_COE_); + } + + if (features & NETIF_F_HW_VLAN_CTAG_RX) + pdata->rfe_ctl |= RFE_CTL_VLAN_FILTER_; + else + pdata->rfe_ctl &= ~RFE_CTL_VLAN_FILTER_; + + spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); + + ret = lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); + + return 0; +} + +static void lan78xx_deferred_vlan_write(struct work_struct *param) +{ + struct lan78xx_priv *pdata = + container_of(param, struct lan78xx_priv, set_vlan); + struct lan78xx_net *dev = pdata->dev; + + lan78xx_dataport_write(dev, DP_SEL_RSEL_VLAN_DA_, 0, + DP_SEL_VHF_VLAN_LEN, pdata->vlan_table); +} + +static int lan78xx_vlan_rx_add_vid(struct net_device *netdev, + __be16 proto, u16 vid) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + u16 vid_bit_index; + u16 vid_dword_index; + + vid_dword_index = (vid >> 5) & 0x7F; + vid_bit_index = vid & 0x1F; + + pdata->vlan_table[vid_dword_index] |= (1 << vid_bit_index); + + /* defer register writes to a sleepable context */ + schedule_work(&pdata->set_vlan); + + return 0; +} + +static int lan78xx_vlan_rx_kill_vid(struct net_device *netdev, + __be16 proto, u16 vid) +{ + struct lan78xx_net *dev = netdev_priv(netdev); + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + u16 vid_bit_index; + u16 vid_dword_index; + + vid_dword_index = (vid >> 5) & 0x7F; + vid_bit_index = vid & 0x1F; + + pdata->vlan_table[vid_dword_index] &= ~(1 << vid_bit_index); + + /* defer register writes to a sleepable context */ + schedule_work(&pdata->set_vlan); + + return 0; +} + +static void lan78xx_init_ltm(struct lan78xx_net *dev) +{ + int ret; + u32 buf; + u32 regs[6] = { 0 }; + + ret = lan78xx_read_reg(dev, USB_CFG1, &buf); + if (buf & USB_CFG1_LTM_ENABLE_) { + u8 temp[2]; + /* Get values from EEPROM first */ + if (lan78xx_read_eeprom(dev, 0x3F, 2, temp) == 0) { + if (temp[0] == 24) { + ret = lan78xx_read_raw_eeprom(dev, + temp[1] * 2, + 24, + (u8 *)regs); + if (ret < 0) + return; + } + } else if (lan78xx_read_otp(dev, 0x3F, 2, temp) == 0) { + if (temp[0] == 24) { + ret = lan78xx_read_raw_otp(dev, + temp[1] * 2, + 24, + (u8 *)regs); + if (ret < 0) + return; + } + } + } + + lan78xx_write_reg(dev, LTM_BELT_IDLE0, regs[0]); + lan78xx_write_reg(dev, LTM_BELT_IDLE1, regs[1]); + lan78xx_write_reg(dev, LTM_BELT_ACT0, regs[2]); + lan78xx_write_reg(dev, LTM_BELT_ACT1, regs[3]); + lan78xx_write_reg(dev, LTM_INACTIVE0, regs[4]); + lan78xx_write_reg(dev, LTM_INACTIVE1, regs[5]); +} + +static int lan78xx_reset(struct lan78xx_net *dev) +{ + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + u32 buf; + int ret = 0; + unsigned long timeout; + + ret = lan78xx_read_reg(dev, HW_CFG, &buf); + buf |= HW_CFG_LRST_; + ret = lan78xx_write_reg(dev, HW_CFG, buf); + + timeout = jiffies + HZ; + do { + mdelay(1); + ret = lan78xx_read_reg(dev, HW_CFG, &buf); + if (time_after(jiffies, timeout)) { + netdev_warn(dev->net, + "timeout on completion of LiteReset"); + return -EIO; + } + } while (buf & HW_CFG_LRST_); + + lan78xx_init_mac_address(dev); + + /* Respond to the IN token with a NAK */ + ret = lan78xx_read_reg(dev, USB_CFG0, &buf); + buf |= USB_CFG_BIR_; + ret = lan78xx_write_reg(dev, USB_CFG0, buf); + + /* Init LTM */ + lan78xx_init_ltm(dev); + + dev->net->hard_header_len += TX_OVERHEAD; + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; + + if (dev->udev->speed == USB_SPEED_SUPER) { + buf = DEFAULT_BURST_CAP_SIZE / SS_USB_PKT_SIZE; + dev->rx_urb_size = DEFAULT_BURST_CAP_SIZE; + dev->rx_qlen = 4; + dev->tx_qlen = 4; + } else if (dev->udev->speed == USB_SPEED_HIGH) { + buf = DEFAULT_BURST_CAP_SIZE / HS_USB_PKT_SIZE; + dev->rx_urb_size = DEFAULT_BURST_CAP_SIZE; + dev->rx_qlen = RX_MAX_QUEUE_MEMORY / dev->rx_urb_size; + dev->tx_qlen = RX_MAX_QUEUE_MEMORY / dev->hard_mtu; + } else { + buf = DEFAULT_BURST_CAP_SIZE / FS_USB_PKT_SIZE; + dev->rx_urb_size = DEFAULT_BURST_CAP_SIZE; + dev->rx_qlen = 4; + } + + ret = lan78xx_write_reg(dev, BURST_CAP, buf); + ret = lan78xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY); + + ret = lan78xx_read_reg(dev, HW_CFG, &buf); + buf |= HW_CFG_MEF_; + ret = lan78xx_write_reg(dev, HW_CFG, buf); + + ret = lan78xx_read_reg(dev, USB_CFG0, &buf); + buf |= USB_CFG_BCE_; + ret = lan78xx_write_reg(dev, USB_CFG0, buf); + + /* set FIFO sizes */ + buf = (MAX_RX_FIFO_SIZE - 512) / 512; + ret = lan78xx_write_reg(dev, FCT_RX_FIFO_END, buf); + + buf = (MAX_TX_FIFO_SIZE - 512) / 512; + ret = lan78xx_write_reg(dev, FCT_TX_FIFO_END, buf); + + ret = lan78xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL_); + ret = lan78xx_write_reg(dev, FLOW, 0); + ret = lan78xx_write_reg(dev, FCT_FLOW, 0); + + /* Don't need rfe_ctl_lock during initialisation */ + ret = lan78xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl); + pdata->rfe_ctl |= RFE_CTL_BCAST_EN_ | RFE_CTL_DA_PERFECT_; + ret = lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); + + /* Enable or disable checksum offload engines */ + lan78xx_set_features(dev->net, dev->net->features); + + lan78xx_set_multicast(dev->net); + + /* reset PHY */ + ret = lan78xx_read_reg(dev, PMT_CTL, &buf); + buf |= PMT_CTL_PHY_RST_; + ret = lan78xx_write_reg(dev, PMT_CTL, buf); + + timeout = jiffies + HZ; + do { + mdelay(1); + ret = lan78xx_read_reg(dev, PMT_CTL, &buf); + if (time_after(jiffies, timeout)) { + netdev_warn(dev->net, "timeout waiting for PHY Reset"); + return -EIO; + } + } while (buf & PMT_CTL_PHY_RST_); + + lan78xx_mii_init(dev); + + ret = lan78xx_phy_init(dev); + + ret = lan78xx_read_reg(dev, MAC_CR, &buf); + + buf |= MAC_CR_GMII_EN_; + buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_; + + ret = lan78xx_write_reg(dev, MAC_CR, buf); + + /* enable on PHY */ + if (buf & MAC_CR_EEE_EN_) + lan78xx_mmd_write(dev->net, dev->mii.phy_id, 0x07, 0x3C, 0x06); + + /* enable PHY interrupts */ + ret = lan78xx_read_reg(dev, INT_EP_CTL, &buf); + buf |= INT_ENP_PHY_INT; + ret = lan78xx_write_reg(dev, INT_EP_CTL, buf); + + ret = lan78xx_read_reg(dev, MAC_TX, &buf); + buf |= MAC_TX_TXEN_; + ret = lan78xx_write_reg(dev, MAC_TX, buf); + + ret = lan78xx_read_reg(dev, FCT_TX_CTL, &buf); + buf |= FCT_TX_CTL_EN_; + ret = lan78xx_write_reg(dev, FCT_TX_CTL, buf); + + ret = lan78xx_set_rx_max_frame_length(dev, dev->net->mtu + ETH_HLEN); + + ret = lan78xx_read_reg(dev, MAC_RX, &buf); + buf |= MAC_RX_RXEN_; + ret = lan78xx_write_reg(dev, MAC_RX, buf); + + ret = lan78xx_read_reg(dev, FCT_RX_CTL, &buf); + buf |= FCT_RX_CTL_EN_; + ret = lan78xx_write_reg(dev, FCT_RX_CTL, buf); + + if (!mii_nway_restart(&dev->mii)) + netif_dbg(dev, link, dev->net, "autoneg initiated"); + + return 0; +} + +static int lan78xx_open(struct net_device *net) +{ + struct lan78xx_net *dev = netdev_priv(net); + int ret; + + ret = usb_autopm_get_interface(dev->intf); + if (ret < 0) + goto out; + + ret = lan78xx_reset(dev); + if (ret < 0) + goto done; + + /* for Link Check */ + if (dev->urb_intr) { + ret = usb_submit_urb(dev->urb_intr, GFP_KERNEL); + if (ret < 0) { + netif_err(dev, ifup, dev->net, + "intr submit %d\n", ret); + goto done; + } + } + + set_bit(EVENT_DEV_OPEN, &dev->flags); + + netif_start_queue(net); + + dev->link_on = false; + + lan78xx_defer_kevent(dev, EVENT_LINK_RESET); +done: + usb_autopm_put_interface(dev->intf); + +out: + return ret; +} + +static void lan78xx_terminate_urbs(struct lan78xx_net *dev) +{ + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup); + DECLARE_WAITQUEUE(wait, current); + int temp; + + /* ensure there are no more active urbs */ + add_wait_queue(&unlink_wakeup, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + dev->wait = &unlink_wakeup; + temp = unlink_urbs(dev, &dev->txq) + unlink_urbs(dev, &dev->rxq); + + /* maybe wait for deletions to finish. */ + while (!skb_queue_empty(&dev->rxq) && + !skb_queue_empty(&dev->txq) && + !skb_queue_empty(&dev->done)) { + schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS)); + set_current_state(TASK_UNINTERRUPTIBLE); + netif_dbg(dev, ifdown, dev->net, + "waited for %d urb completions\n", temp); + } + set_current_state(TASK_RUNNING); + dev->wait = NULL; + remove_wait_queue(&unlink_wakeup, &wait); +} + +int lan78xx_stop(struct net_device *net) +{ + struct lan78xx_net *dev = netdev_priv(net); + + clear_bit(EVENT_DEV_OPEN, &dev->flags); + netif_stop_queue(net); + + netif_info(dev, ifdown, dev->net, + "stop stats: rx/tx %lu/%lu, errs %lu/%lu\n", + net->stats.rx_packets, net->stats.tx_packets, + net->stats.rx_errors, net->stats.tx_errors); + + lan78xx_terminate_urbs(dev); + + usb_kill_urb(dev->urb_intr); + + skb_queue_purge(&dev->rxq_pause); + + /* deferred work (task, timer, softirq) must also stop. + * can't flush_scheduled_work() until we drop rtnl (later), + * else workers could deadlock; so make workers a NOP. + */ + dev->flags = 0; + cancel_delayed_work_sync(&dev->wq); + tasklet_kill(&dev->bh); + + usb_autopm_put_interface(dev->intf); + + return 0; +} + +static int lan78xx_linearize(struct sk_buff *skb) +{ + return skb_linearize(skb); +} + +static struct sk_buff *lan78xx_tx_prep(struct lan78xx_net *dev, + struct sk_buff *skb, gfp_t flags) +{ + u32 tx_cmd_a, tx_cmd_b; + + if (skb_headroom(skb) < TX_OVERHEAD) { + struct sk_buff *skb2; + + skb2 = skb_copy_expand(skb, TX_OVERHEAD, 0, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + if (lan78xx_linearize(skb) < 0) + return NULL; + + tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN_MASK_) | TX_CMD_A_FCS_; + + if (skb->ip_summed == CHECKSUM_PARTIAL) + tx_cmd_a |= TX_CMD_A_IPE_ | TX_CMD_A_TPE_; + + tx_cmd_b = 0; + if (skb_is_gso(skb)) { + u16 mss = max(skb_shinfo(skb)->gso_size, TX_CMD_B_MSS_MIN_); + + tx_cmd_b = (mss << TX_CMD_B_MSS_SHIFT_) & TX_CMD_B_MSS_MASK_; + + tx_cmd_a |= TX_CMD_A_LSO_; + } + + if (skb_vlan_tag_present(skb)) { + tx_cmd_a |= TX_CMD_A_IVTG_; + tx_cmd_b |= skb_vlan_tag_get(skb) & TX_CMD_B_VTAG_MASK_; + } + + skb_push(skb, 4); + cpu_to_le32s(&tx_cmd_b); + memcpy(skb->data, &tx_cmd_b, 4); + + skb_push(skb, 4); + cpu_to_le32s(&tx_cmd_a); + memcpy(skb->data, &tx_cmd_a, 4); + + return skb; +} + +static enum skb_state defer_bh(struct lan78xx_net *dev, struct sk_buff *skb, + struct sk_buff_head *list, enum skb_state state) +{ + unsigned long flags; + enum skb_state old_state; + struct skb_data *entry = (struct skb_data *)skb->cb; + + spin_lock_irqsave(&list->lock, flags); + old_state = entry->state; + entry->state = state; + if (!list->prev) + BUG_ON(!list->prev); + if (!list->next) + BUG_ON(!list->next); + if (!skb->prev || !skb->next) + BUG_ON(true); + + __skb_unlink(skb, list); + spin_unlock(&list->lock); + spin_lock(&dev->done.lock); + if (!dev->done.prev) + BUG_ON(!dev->done.prev); + if (!dev->done.next) + BUG_ON(!dev->done.next); + + __skb_queue_tail(&dev->done, skb); + if (skb_queue_len(&dev->done) == 1) + tasklet_schedule(&dev->bh); + spin_unlock_irqrestore(&dev->done.lock, flags); + + return old_state; +} + +static void tx_complete(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *)urb->context; + struct skb_data *entry = (struct skb_data *)skb->cb; + struct lan78xx_net *dev = entry->dev; + + if (urb->status == 0) { + dev->net->stats.tx_packets++; + dev->net->stats.tx_bytes += entry->length; + } else { + dev->net->stats.tx_errors++; + + switch (urb->status) { + case -EPIPE: + lan78xx_defer_kevent(dev, EVENT_TX_HALT); + break; + + /* software-driven interface shutdown */ + case -ECONNRESET: + case -ESHUTDOWN: + break; + + case -EPROTO: + case -ETIME: + case -EILSEQ: + netif_stop_queue(dev->net); + break; + default: + netif_dbg(dev, tx_err, dev->net, + "tx err %d\n", entry->urb->status); + break; + } + } + + usb_autopm_put_interface_async(dev->intf); + + if (skb) + defer_bh(dev, skb, &dev->txq, tx_done); +} + +static void lan78xx_queue_skb(struct sk_buff_head *list, + struct sk_buff *newsk, enum skb_state state) +{ + struct skb_data *entry = (struct skb_data *)newsk->cb; + + __skb_queue_tail(list, newsk); + entry->state = state; +} + +netdev_tx_t lan78xx_start_xmit(struct sk_buff *skb, struct net_device *net) +{ + struct lan78xx_net *dev = netdev_priv(net); + + if (skb) + skb_tx_timestamp(skb); + + skb = lan78xx_tx_prep(dev, skb, GFP_ATOMIC); + if (skb) { + skb_queue_tail(&dev->txq_pend, skb); + + if (skb_queue_len(&dev->txq_pend) > 10) + netif_stop_queue(net); + } else { + netif_dbg(dev, tx_err, dev->net, + "lan78xx_tx_prep return NULL\n"); + dev->net->stats.tx_errors++; + dev->net->stats.tx_dropped++; + } + + tasklet_schedule(&dev->bh); + + return NETDEV_TX_OK; +} + +int lan78xx_get_endpoints(struct lan78xx_net *dev, struct usb_interface *intf) +{ + int tmp; + struct usb_host_interface *alt = NULL; + struct usb_host_endpoint *in = NULL, *out = NULL; + struct usb_host_endpoint *status = NULL; + + for (tmp = 0; tmp < intf->num_altsetting; tmp++) { + unsigned ep; + + in = NULL; + out = NULL; + status = NULL; + alt = intf->altsetting + tmp; + + for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { + struct usb_host_endpoint *e; + int intr = 0; + + e = alt->endpoint + ep; + switch (e->desc.bmAttributes) { + case USB_ENDPOINT_XFER_INT: + if (!usb_endpoint_dir_in(&e->desc)) + continue; + intr = 1; + /* FALLTHROUGH */ + case USB_ENDPOINT_XFER_BULK: + break; + default: + continue; + } + if (usb_endpoint_dir_in(&e->desc)) { + if (!intr && !in) + in = e; + else if (intr && !status) + status = e; + } else { + if (!out) + out = e; + } + } + if (in && out) + break; + } + if (!alt || !in || !out) + return -EINVAL; + + dev->pipe_in = usb_rcvbulkpipe(dev->udev, + in->desc.bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK); + dev->pipe_out = usb_sndbulkpipe(dev->udev, + out->desc.bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK); + dev->ep_intr = status; + + return 0; +} + +static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) +{ + struct lan78xx_priv *pdata = NULL; + int ret; + int i; + + ret = lan78xx_get_endpoints(dev, intf); + + dev->data[0] = (unsigned long)kzalloc(sizeof(*pdata), GFP_KERNEL); + + pdata = (struct lan78xx_priv *)(dev->data[0]); + if (!pdata) { + netdev_warn(dev->net, "Unable to allocate lan78xx_priv"); + return -ENOMEM; + } + + pdata->dev = dev; + + spin_lock_init(&pdata->rfe_ctl_lock); + mutex_init(&pdata->dataport_mutex); + + INIT_WORK(&pdata->set_multicast, lan78xx_deferred_multicast_write); + + for (i = 0; i < DP_SEL_VHF_VLAN_LEN; i++) + pdata->vlan_table[i] = 0; + + INIT_WORK(&pdata->set_vlan, lan78xx_deferred_vlan_write); + + dev->net->features = 0; + + if (DEFAULT_TX_CSUM_ENABLE) + dev->net->features |= NETIF_F_HW_CSUM; + + if (DEFAULT_RX_CSUM_ENABLE) + dev->net->features |= NETIF_F_RXCSUM; + + if (DEFAULT_TSO_CSUM_ENABLE) + dev->net->features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG; + + dev->net->hw_features = dev->net->features; + + /* Init all registers */ + ret = lan78xx_reset(dev); + + dev->net->flags |= IFF_MULTICAST; + + pdata->wol = WAKE_MAGIC; + + return 0; +} + +static void lan78xx_unbind(struct lan78xx_net *dev, struct usb_interface *intf) +{ + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + + if (pdata) { + netif_dbg(dev, ifdown, dev->net, "free pdata"); + kfree(pdata); + pdata = NULL; + dev->data[0] = 0; + } +} + +static void lan78xx_rx_csum_offload(struct lan78xx_net *dev, + struct sk_buff *skb, + u32 rx_cmd_a, u32 rx_cmd_b) +{ + if (!(dev->net->features & NETIF_F_RXCSUM) || + unlikely(rx_cmd_a & RX_CMD_A_ICSM_)) { + skb->ip_summed = CHECKSUM_NONE; + } else { + skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT_)); + skb->ip_summed = CHECKSUM_COMPLETE; + } +} + +void lan78xx_skb_return(struct lan78xx_net *dev, struct sk_buff *skb) +{ + int status; + + if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { + skb_queue_tail(&dev->rxq_pause, skb); + return; + } + + skb->protocol = eth_type_trans(skb, dev->net); + dev->net->stats.rx_packets++; + dev->net->stats.rx_bytes += skb->len; + + netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n", + skb->len + sizeof(struct ethhdr), skb->protocol); + memset(skb->cb, 0, sizeof(struct skb_data)); + + if (skb_defer_rx_timestamp(skb)) + return; + + status = netif_rx(skb); + if (status != NET_RX_SUCCESS) + netif_dbg(dev, rx_err, dev->net, + "netif_rx status %d\n", status); +} + +static int lan78xx_rx(struct lan78xx_net *dev, struct sk_buff *skb) +{ + if (skb->len < dev->net->hard_header_len) + return 0; + + while (skb->len > 0) { + u32 rx_cmd_a, rx_cmd_b, align_count, size; + u16 rx_cmd_c; + struct sk_buff *skb2; + unsigned char *packet; + + memcpy(&rx_cmd_a, skb->data, sizeof(rx_cmd_a)); + le32_to_cpus(&rx_cmd_a); + skb_pull(skb, sizeof(rx_cmd_a)); + + memcpy(&rx_cmd_b, skb->data, sizeof(rx_cmd_b)); + le32_to_cpus(&rx_cmd_b); + skb_pull(skb, sizeof(rx_cmd_b)); + + memcpy(&rx_cmd_c, skb->data, sizeof(rx_cmd_c)); + le16_to_cpus(&rx_cmd_c); + skb_pull(skb, sizeof(rx_cmd_c)); + + packet = skb->data; + + /* get the packet length */ + size = (rx_cmd_a & RX_CMD_A_LEN_MASK_); + align_count = (4 - ((size + RXW_PADDING) % 4)) % 4; + + if (unlikely(rx_cmd_a & RX_CMD_A_RED_)) { + netif_dbg(dev, rx_err, dev->net, + "Error rx_cmd_a=0x%08x", rx_cmd_a); + } else { + /* last frame in this batch */ + if (skb->len == size) { + lan78xx_rx_csum_offload(dev, skb, + rx_cmd_a, rx_cmd_b); + + skb_trim(skb, skb->len - 4); /* remove fcs */ + skb->truesize = size + sizeof(struct sk_buff); + + return 1; + } + + skb2 = skb_clone(skb, GFP_ATOMIC); + if (unlikely(!skb2)) { + netdev_warn(dev->net, "Error allocating skb"); + return 0; + } + + skb2->len = size; + skb2->data = packet; + skb_set_tail_pointer(skb2, size); + + lan78xx_rx_csum_offload(dev, skb2, rx_cmd_a, rx_cmd_b); + + skb_trim(skb2, skb2->len - 4); /* remove fcs */ + skb2->truesize = size + sizeof(struct sk_buff); + + lan78xx_skb_return(dev, skb2); + } + + skb_pull(skb, size); + + /* padding bytes before the next frame starts */ + if (skb->len) + skb_pull(skb, align_count); + } + + if (unlikely(skb->len < 0)) { + netdev_warn(dev->net, "invalid rx length<0 %d", skb->len); + return 0; + } + + return 1; +} + +static inline void rx_process(struct lan78xx_net *dev, struct sk_buff *skb) +{ + if (!lan78xx_rx(dev, skb)) { + dev->net->stats.rx_errors++; + goto done; + } + + if (skb->len) { + lan78xx_skb_return(dev, skb); + return; + } + + netif_dbg(dev, rx_err, dev->net, "drop\n"); + dev->net->stats.rx_errors++; +done: + skb_queue_tail(&dev->done, skb); +} + +static void rx_complete(struct urb *urb); + +static int rx_submit(struct lan78xx_net *dev, struct urb *urb, gfp_t flags) +{ + struct sk_buff *skb; + struct skb_data *entry; + unsigned long lockflags; + size_t size = dev->rx_urb_size; + int ret = 0; + + skb = netdev_alloc_skb_ip_align(dev->net, size); + if (!skb) { + usb_free_urb(urb); + return -ENOMEM; + } + + entry = (struct skb_data *)skb->cb; + entry->urb = urb; + entry->dev = dev; + entry->length = 0; + + usb_fill_bulk_urb(urb, dev->udev, dev->pipe_in, + skb->data, size, rx_complete, skb); + + spin_lock_irqsave(&dev->rxq.lock, lockflags); + + if (netif_device_present(dev->net) && + netif_running(dev->net) && + !test_bit(EVENT_RX_HALT, &dev->flags) && + !test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { + ret = usb_submit_urb(urb, GFP_ATOMIC); + switch (ret) { + case 0: + lan78xx_queue_skb(&dev->rxq, skb, rx_start); + break; + case -EPIPE: + lan78xx_defer_kevent(dev, EVENT_RX_HALT); + break; + case -ENODEV: + netif_dbg(dev, ifdown, dev->net, "device gone\n"); + netif_device_detach(dev->net); + break; + case -EHOSTUNREACH: + ret = -ENOLINK; + break; + default: + netif_dbg(dev, rx_err, dev->net, + "rx submit, %d\n", ret); + tasklet_schedule(&dev->bh); + } + } else { + netif_dbg(dev, ifdown, dev->net, "rx: stopped\n"); + ret = -ENOLINK; + } + spin_unlock_irqrestore(&dev->rxq.lock, lockflags); + if (ret) { + dev_kfree_skb_any(skb); + usb_free_urb(urb); + } + return ret; +} + +static void rx_complete(struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *)urb->context; + struct skb_data *entry = (struct skb_data *)skb->cb; + struct lan78xx_net *dev = entry->dev; + int urb_status = urb->status; + enum skb_state state; + + skb_put(skb, urb->actual_length); + state = rx_done; + entry->urb = NULL; + + switch (urb_status) { + case 0: + if (skb->len < dev->net->hard_header_len) { + state = rx_cleanup; + dev->net->stats.rx_errors++; + dev->net->stats.rx_length_errors++; + netif_dbg(dev, rx_err, dev->net, + "rx length %d\n", skb->len); + } + usb_mark_last_busy(dev->udev); + break; + case -EPIPE: + dev->net->stats.rx_errors++; + lan78xx_defer_kevent(dev, EVENT_RX_HALT); + /* FALLTHROUGH */ + case -ECONNRESET: /* async unlink */ + case -ESHUTDOWN: /* hardware gone */ + netif_dbg(dev, ifdown, dev->net, + "rx shutdown, code %d\n", urb_status); + state = rx_cleanup; + entry->urb = urb; + urb = NULL; + break; + case -EPROTO: + case -ETIME: + case -EILSEQ: + dev->net->stats.rx_errors++; + state = rx_cleanup; + entry->urb = urb; + urb = NULL; + break; + + /* data overrun ... flush fifo? */ + case -EOVERFLOW: + dev->net->stats.rx_over_errors++; + /* FALLTHROUGH */ + + default: + state = rx_cleanup; + dev->net->stats.rx_errors++; + netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status); + break; + } + + state = defer_bh(dev, skb, &dev->rxq, state); + + if (urb) { + if (netif_running(dev->net) && + !test_bit(EVENT_RX_HALT, &dev->flags) && + state != unlink_start) { + rx_submit(dev, urb, GFP_ATOMIC); + return; + } + usb_free_urb(urb); + } + netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n"); +} + +static void lan78xx_tx_bh(struct lan78xx_net *dev) +{ + int length; + struct urb *urb = NULL; + struct skb_data *entry; + unsigned long flags; + struct sk_buff_head *tqp = &dev->txq_pend; + struct sk_buff *skb, *skb2; + int ret; + int count, pos; + int skb_totallen, pkt_cnt; + + skb_totallen = 0; + pkt_cnt = 0; + for (skb = tqp->next; pkt_cnt < tqp->qlen; skb = skb->next) { + if (skb_is_gso(skb)) { + if (pkt_cnt) { + /* handle previous packets first */ + break; + } + length = skb->len; + skb2 = skb_dequeue(tqp); + goto gso_skb; + } + + if ((skb_totallen + skb->len) > MAX_SINGLE_PACKET_SIZE) + break; + skb_totallen = skb->len + roundup(skb_totallen, sizeof(u32)); + pkt_cnt++; + } + + /* copy to a single skb */ + skb = alloc_skb(skb_totallen, GFP_ATOMIC); + if (!skb) + goto drop; + + skb_put(skb, skb_totallen); + + for (count = pos = 0; count < pkt_cnt; count++) { + skb2 = skb_dequeue(tqp); + if (skb2) { + memcpy(skb->data + pos, skb2->data, skb2->len); + pos += roundup(skb2->len, sizeof(u32)); + dev_kfree_skb(skb2); + } else { + BUG_ON(true); + } + } + + length = skb_totallen; + +gso_skb: + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + netif_dbg(dev, tx_err, dev->net, "no urb\n"); + goto drop; + } + + entry = (struct skb_data *)skb->cb; + entry->urb = urb; + entry->dev = dev; + entry->length = length; + + spin_lock_irqsave(&dev->txq.lock, flags); + ret = usb_autopm_get_interface_async(dev->intf); + if (ret < 0) { + spin_unlock_irqrestore(&dev->txq.lock, flags); + goto drop; + } + + usb_fill_bulk_urb(urb, dev->udev, dev->pipe_out, + skb->data, skb->len, tx_complete, skb); + + if (length % dev->maxpacket == 0) { + /* send USB_ZERO_PACKET */ + urb->transfer_flags |= URB_ZERO_PACKET; + } + +#ifdef CONFIG_PM + /* if this triggers the device is still a sleep */ + if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { + /* transmission will be done in resume */ + usb_anchor_urb(urb, &dev->deferred); + /* no use to process more packets */ + netif_stop_queue(dev->net); + usb_put_urb(urb); + spin_unlock_irqrestore(&dev->txq.lock, flags); + netdev_dbg(dev->net, "Delaying transmission for resumption\n"); + return; + } +#endif + + ret = usb_submit_urb(urb, GFP_ATOMIC); + switch (ret) { + case 0: + dev->net->trans_start = jiffies; + lan78xx_queue_skb(&dev->txq, skb, tx_start); + if (skb_queue_len(&dev->txq) >= dev->tx_qlen) + netif_stop_queue(dev->net); + break; + case -EPIPE: + netif_stop_queue(dev->net); + lan78xx_defer_kevent(dev, EVENT_TX_HALT); + usb_autopm_put_interface_async(dev->intf); + break; + default: + usb_autopm_put_interface_async(dev->intf); + netif_dbg(dev, tx_err, dev->net, + "tx: submit urb err %d\n", ret); + break; + } + + spin_unlock_irqrestore(&dev->txq.lock, flags); + + if (ret) { + netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", ret); +drop: + dev->net->stats.tx_dropped++; + if (skb) + dev_kfree_skb_any(skb); + usb_free_urb(urb); + } else + netif_dbg(dev, tx_queued, dev->net, + "> tx, len %d, type 0x%x\n", length, skb->protocol); +} + +static void lan78xx_rx_bh(struct lan78xx_net *dev) +{ + struct urb *urb; + int i; + + if (skb_queue_len(&dev->rxq) < dev->rx_qlen) { + for (i = 0; i < 10; i++) { + if (skb_queue_len(&dev->rxq) >= dev->rx_qlen) + break; + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (urb) + if (rx_submit(dev, urb, GFP_ATOMIC) == -ENOLINK) + return; + } + + if (skb_queue_len(&dev->rxq) < dev->rx_qlen) + tasklet_schedule(&dev->bh); + } + if (skb_queue_len(&dev->txq) < dev->tx_qlen) + netif_wake_queue(dev->net); +} + +static void lan78xx_bh(unsigned long param) +{ + struct lan78xx_net *dev = (struct lan78xx_net *)param; + struct sk_buff *skb; + struct skb_data *entry; + + if (!dev->done.prev) + BUG_ON(!dev->done.prev); + if (!dev->done.next) + BUG_ON(!dev->done.next); + + while ((skb = skb_dequeue(&dev->done))) { + entry = (struct skb_data *)(skb->cb); + switch (entry->state) { + case rx_done: + entry->state = rx_cleanup; + rx_process(dev, skb); + continue; + case tx_done: + usb_free_urb(entry->urb); + dev_kfree_skb(skb); + continue; + case rx_cleanup: + usb_free_urb(entry->urb); + dev_kfree_skb(skb); + continue; + default: + netdev_dbg(dev->net, "skb state %d\n", entry->state); + return; + } + if (!dev->done.prev) + BUG_ON(!dev->done.prev); + if (!dev->done.next) + BUG_ON(!dev->done.next); + } + + if (netif_device_present(dev->net) && netif_running(dev->net)) { + if (!skb_queue_empty(&dev->txq_pend)) + lan78xx_tx_bh(dev); + + if (!timer_pending(&dev->delay) && + !test_bit(EVENT_RX_HALT, &dev->flags)) + lan78xx_rx_bh(dev); + } +} + +static void lan78xx_delayedwork(struct work_struct *work) +{ + int status; + struct lan78xx_net *dev; + + dev = container_of(work, struct lan78xx_net, wq.work); + + if (test_bit(EVENT_TX_HALT, &dev->flags)) { + unlink_urbs(dev, &dev->txq); + status = usb_autopm_get_interface(dev->intf); + if (status < 0) + goto fail_pipe; + status = usb_clear_halt(dev->udev, dev->pipe_out); + usb_autopm_put_interface(dev->intf); + if (status < 0 && + status != -EPIPE && + status != -ESHUTDOWN) { + if (netif_msg_tx_err(dev)) +fail_pipe: + netdev_err(dev->net, + "can't clear tx halt, status %d\n", + status); + } else { + clear_bit(EVENT_TX_HALT, &dev->flags); + if (status != -ESHUTDOWN) + netif_wake_queue(dev->net); + } + } + if (test_bit(EVENT_RX_HALT, &dev->flags)) { + unlink_urbs(dev, &dev->rxq); + status = usb_autopm_get_interface(dev->intf); + if (status < 0) + goto fail_halt; + status = usb_clear_halt(dev->udev, dev->pipe_in); + usb_autopm_put_interface(dev->intf); + if (status < 0 && + status != -EPIPE && + status != -ESHUTDOWN) { + if (netif_msg_rx_err(dev)) +fail_halt: + netdev_err(dev->net, + "can't clear rx halt, status %d\n", + status); + } else { + clear_bit(EVENT_RX_HALT, &dev->flags); + tasklet_schedule(&dev->bh); + } + } + + if (test_bit(EVENT_LINK_RESET, &dev->flags)) { + int ret = 0; + + clear_bit(EVENT_LINK_RESET, &dev->flags); + status = usb_autopm_get_interface(dev->intf); + if (status < 0) + goto skip_reset; + if (lan78xx_link_reset(dev) < 0) { + usb_autopm_put_interface(dev->intf); +skip_reset: + netdev_info(dev->net, "link reset failed (%d)\n", + ret); + } else { + usb_autopm_put_interface(dev->intf); + } + } +} + +static void intr_complete(struct urb *urb) +{ + struct lan78xx_net *dev = urb->context; + int status = urb->status; + + switch (status) { + /* success */ + case 0: + lan78xx_status(dev, urb); + break; + + /* software-driven interface shutdown */ + case -ENOENT: /* urb killed */ + case -ESHUTDOWN: /* hardware gone */ + netif_dbg(dev, ifdown, dev->net, + "intr shutdown, code %d\n", status); + return; + + /* NOTE: not throttling like RX/TX, since this endpoint + * already polls infrequently + */ + default: + netdev_dbg(dev->net, "intr status %d\n", status); + break; + } + + if (!netif_running(dev->net)) + return; + + memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status != 0) + netif_err(dev, timer, dev->net, + "intr resubmit --> %d\n", status); +} + +static void lan78xx_disconnect(struct usb_interface *intf) +{ + struct lan78xx_net *dev; + struct usb_device *udev; + struct net_device *net; + + dev = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + if (!dev) + return; + + udev = interface_to_usbdev(intf); + + net = dev->net; + unregister_netdev(net); + + cancel_delayed_work_sync(&dev->wq); + + usb_scuttle_anchored_urbs(&dev->deferred); + + lan78xx_unbind(dev, intf); + + usb_kill_urb(dev->urb_intr); + usb_free_urb(dev->urb_intr); + + free_netdev(net); + usb_put_dev(udev); +} + +void lan78xx_tx_timeout(struct net_device *net) +{ + struct lan78xx_net *dev = netdev_priv(net); + + unlink_urbs(dev, &dev->txq); + tasklet_schedule(&dev->bh); +} + +static const struct net_device_ops lan78xx_netdev_ops = { + .ndo_open = lan78xx_open, + .ndo_stop = lan78xx_stop, + .ndo_start_xmit = lan78xx_start_xmit, + .ndo_tx_timeout = lan78xx_tx_timeout, + .ndo_change_mtu = lan78xx_change_mtu, + .ndo_set_mac_address = lan78xx_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = lan78xx_ioctl, + .ndo_set_rx_mode = lan78xx_set_multicast, + .ndo_set_features = lan78xx_set_features, + .ndo_vlan_rx_add_vid = lan78xx_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = lan78xx_vlan_rx_kill_vid, +}; + +static int lan78xx_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct lan78xx_net *dev; + struct net_device *netdev; + struct usb_device *udev; + int ret; + unsigned maxp; + unsigned period; + u8 *buf = NULL; + + udev = interface_to_usbdev(intf); + udev = usb_get_dev(udev); + + ret = -ENOMEM; + netdev = alloc_etherdev(sizeof(struct lan78xx_net)); + if (!netdev) { + dev_err(&intf->dev, "Error: OOM\n"); + goto out1; + } + + /* netdev_printk() needs this */ + SET_NETDEV_DEV(netdev, &intf->dev); + + dev = netdev_priv(netdev); + dev->udev = udev; + dev->intf = intf; + dev->net = netdev; + dev->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV + | NETIF_MSG_PROBE | NETIF_MSG_LINK); + + skb_queue_head_init(&dev->rxq); + skb_queue_head_init(&dev->txq); + skb_queue_head_init(&dev->done); + skb_queue_head_init(&dev->rxq_pause); + skb_queue_head_init(&dev->txq_pend); + mutex_init(&dev->phy_mutex); + + tasklet_init(&dev->bh, lan78xx_bh, (unsigned long)dev); + INIT_DELAYED_WORK(&dev->wq, lan78xx_delayedwork); + init_usb_anchor(&dev->deferred); + + netdev->netdev_ops = &lan78xx_netdev_ops; + netdev->watchdog_timeo = TX_TIMEOUT_JIFFIES; + netdev->ethtool_ops = &lan78xx_ethtool_ops; + + ret = lan78xx_bind(dev, intf); + if (ret < 0) + goto out2; + strcpy(netdev->name, "eth%d"); + + if (netdev->mtu > (dev->hard_mtu - netdev->hard_header_len)) + netdev->mtu = dev->hard_mtu - netdev->hard_header_len; + + dev->ep_blkin = (intf->cur_altsetting)->endpoint + 0; + dev->ep_blkout = (intf->cur_altsetting)->endpoint + 1; + dev->ep_intr = (intf->cur_altsetting)->endpoint + 2; + + dev->pipe_in = usb_rcvbulkpipe(udev, BULK_IN_PIPE); + dev->pipe_out = usb_sndbulkpipe(udev, BULK_OUT_PIPE); + + dev->pipe_intr = usb_rcvintpipe(dev->udev, + dev->ep_intr->desc.bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK); + period = dev->ep_intr->desc.bInterval; + + maxp = usb_maxpacket(dev->udev, dev->pipe_intr, 0); + buf = kmalloc(maxp, GFP_KERNEL); + if (buf) { + dev->urb_intr = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->urb_intr) { + kfree(buf); + goto out3; + } else { + usb_fill_int_urb(dev->urb_intr, dev->udev, + dev->pipe_intr, buf, maxp, + intr_complete, dev, period); + } + } + + dev->maxpacket = usb_maxpacket(dev->udev, dev->pipe_out, 1); + + /* driver requires remote-wakeup capability during autosuspend. */ + intf->needs_remote_wakeup = 1; + + ret = register_netdev(netdev); + if (ret != 0) { + netif_err(dev, probe, netdev, "couldn't register the device\n"); + goto out2; + } + + usb_set_intfdata(intf, dev); + + ret = device_set_wakeup_enable(&udev->dev, true); + + /* Default delay of 2sec has more overhead than advantage. + * Set to 10sec as default. + */ + pm_runtime_set_autosuspend_delay(&udev->dev, + DEFAULT_AUTOSUSPEND_DELAY); + + return 0; + + usb_set_intfdata(intf, NULL); +out3: + lan78xx_unbind(dev, intf); +out2: + free_netdev(netdev); +out1: + usb_put_dev(udev); + + return ret; +} + +static u16 lan78xx_wakeframe_crc16(const u8 *buf, int len) +{ + const u16 crc16poly = 0x8005; + int i; + u16 bit, crc, msb; + u8 data; + + crc = 0xFFFF; + for (i = 0; i < len; i++) { + data = *buf++; + for (bit = 0; bit < 8; bit++) { + msb = crc >> 15; + crc <<= 1; + + if (msb ^ (u16)(data & 1)) { + crc ^= crc16poly; + crc |= (u16)0x0001U; + } + data >>= 1; + } + } + + return crc; +} + +static int lan78xx_set_suspend(struct lan78xx_net *dev, u32 wol) +{ + u32 buf; + int ret; + int mask_index; + u16 crc; + u32 temp_wucsr; + u32 temp_pmt_ctl; + const u8 ipv4_multicast[3] = { 0x01, 0x00, 0x5E }; + const u8 ipv6_multicast[3] = { 0x33, 0x33 }; + const u8 arp_type[2] = { 0x08, 0x06 }; + + ret = lan78xx_read_reg(dev, MAC_TX, &buf); + buf &= ~MAC_TX_TXEN_; + ret = lan78xx_write_reg(dev, MAC_TX, buf); + ret = lan78xx_read_reg(dev, MAC_RX, &buf); + buf &= ~MAC_RX_RXEN_; + ret = lan78xx_write_reg(dev, MAC_RX, buf); + + ret = lan78xx_write_reg(dev, WUCSR, 0); + ret = lan78xx_write_reg(dev, WUCSR2, 0); + ret = lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL); + + temp_wucsr = 0; + + temp_pmt_ctl = 0; + ret = lan78xx_read_reg(dev, PMT_CTL, &temp_pmt_ctl); + temp_pmt_ctl &= ~PMT_CTL_RES_CLR_WKP_EN_; + temp_pmt_ctl |= PMT_CTL_RES_CLR_WKP_STS_; + + for (mask_index = 0; mask_index < NUM_OF_WUF_CFG; mask_index++) + ret = lan78xx_write_reg(dev, WUF_CFG(mask_index), 0); + + mask_index = 0; + if (wol & WAKE_PHY) { + temp_pmt_ctl |= PMT_CTL_PHY_WAKE_EN_; + + temp_pmt_ctl |= PMT_CTL_WOL_EN_; + temp_pmt_ctl &= ~PMT_CTL_SUS_MODE_MASK_; + temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_; + } + if (wol & WAKE_MAGIC) { + temp_wucsr |= WUCSR_MPEN_; + + temp_pmt_ctl |= PMT_CTL_WOL_EN_; + temp_pmt_ctl &= ~PMT_CTL_SUS_MODE_MASK_; + temp_pmt_ctl |= PMT_CTL_SUS_MODE_3_; + } + if (wol & WAKE_BCAST) { + temp_wucsr |= WUCSR_BCST_EN_; + + temp_pmt_ctl |= PMT_CTL_WOL_EN_; + temp_pmt_ctl &= ~PMT_CTL_SUS_MODE_MASK_; + temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_; + } + if (wol & WAKE_MCAST) { + temp_wucsr |= WUCSR_WAKE_EN_; + + /* set WUF_CFG & WUF_MASK for IPv4 Multicast */ + crc = lan78xx_wakeframe_crc16(ipv4_multicast, 3); + ret = lan78xx_write_reg(dev, WUF_CFG(mask_index), + WUF_CFGX_EN_ | + WUF_CFGX_TYPE_MCAST_ | + (0 << WUF_CFGX_OFFSET_SHIFT_) | + (crc & WUF_CFGX_CRC16_MASK_)); + + ret = lan78xx_write_reg(dev, WUF_MASK0(mask_index), 7); + ret = lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0); + ret = lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0); + ret = lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0); + mask_index++; + + /* for IPv6 Multicast */ + crc = lan78xx_wakeframe_crc16(ipv6_multicast, 2); + ret = lan78xx_write_reg(dev, WUF_CFG(mask_index), + WUF_CFGX_EN_ | + WUF_CFGX_TYPE_MCAST_ | + (0 << WUF_CFGX_OFFSET_SHIFT_) | + (crc & WUF_CFGX_CRC16_MASK_)); + + ret = lan78xx_write_reg(dev, WUF_MASK0(mask_index), 3); + ret = lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0); + ret = lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0); + ret = lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0); + mask_index++; + + temp_pmt_ctl |= PMT_CTL_WOL_EN_; + temp_pmt_ctl &= ~PMT_CTL_SUS_MODE_MASK_; + temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_; + } + if (wol & WAKE_UCAST) { + temp_wucsr |= WUCSR_PFDA_EN_; + + temp_pmt_ctl |= PMT_CTL_WOL_EN_; + temp_pmt_ctl &= ~PMT_CTL_SUS_MODE_MASK_; + temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_; + } + if (wol & WAKE_ARP) { + temp_wucsr |= WUCSR_WAKE_EN_; + + /* set WUF_CFG & WUF_MASK + * for packettype (offset 12,13) = ARP (0x0806) + */ + crc = lan78xx_wakeframe_crc16(arp_type, 2); + ret = lan78xx_write_reg(dev, WUF_CFG(mask_index), + WUF_CFGX_EN_ | + WUF_CFGX_TYPE_ALL_ | + (0 << WUF_CFGX_OFFSET_SHIFT_) | + (crc & WUF_CFGX_CRC16_MASK_)); + + ret = lan78xx_write_reg(dev, WUF_MASK0(mask_index), 0x3000); + ret = lan78xx_write_reg(dev, WUF_MASK1(mask_index), 0); + ret = lan78xx_write_reg(dev, WUF_MASK2(mask_index), 0); + ret = lan78xx_write_reg(dev, WUF_MASK3(mask_index), 0); + mask_index++; + + temp_pmt_ctl |= PMT_CTL_WOL_EN_; + temp_pmt_ctl &= ~PMT_CTL_SUS_MODE_MASK_; + temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_; + } + + ret = lan78xx_write_reg(dev, WUCSR, temp_wucsr); + + /* when multiple WOL bits are set */ + if (hweight_long((unsigned long)wol) > 1) { + temp_pmt_ctl |= PMT_CTL_WOL_EN_; + temp_pmt_ctl &= ~PMT_CTL_SUS_MODE_MASK_; + temp_pmt_ctl |= PMT_CTL_SUS_MODE_0_; + } + ret = lan78xx_write_reg(dev, PMT_CTL, temp_pmt_ctl); + + /* clear WUPS */ + ret = lan78xx_read_reg(dev, PMT_CTL, &buf); + buf |= PMT_CTL_WUPS_MASK_; + ret = lan78xx_write_reg(dev, PMT_CTL, buf); + + ret = lan78xx_read_reg(dev, MAC_RX, &buf); + buf |= MAC_RX_RXEN_; + ret = lan78xx_write_reg(dev, MAC_RX, buf); + + return 0; +} + +int lan78xx_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct lan78xx_net *dev = usb_get_intfdata(intf); + struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); + u32 buf; + int ret; + int event; + + ret = 0; + event = message.event; + + if (!dev->suspend_count++) { + spin_lock_irq(&dev->txq.lock); + /* don't autosuspend while transmitting */ + if ((skb_queue_len(&dev->txq) || + skb_queue_len(&dev->txq_pend)) && + PMSG_IS_AUTO(message)) { + spin_unlock_irq(&dev->txq.lock); + ret = -EBUSY; + goto out; + } else { + set_bit(EVENT_DEV_ASLEEP, &dev->flags); + spin_unlock_irq(&dev->txq.lock); + } + + /* stop TX & RX */ + ret = lan78xx_read_reg(dev, MAC_TX, &buf); + buf &= ~MAC_TX_TXEN_; + ret = lan78xx_write_reg(dev, MAC_TX, buf); + ret = lan78xx_read_reg(dev, MAC_RX, &buf); + buf &= ~MAC_RX_RXEN_; + ret = lan78xx_write_reg(dev, MAC_RX, buf); + + /* empty out the rx and queues */ + netif_device_detach(dev->net); + lan78xx_terminate_urbs(dev); + usb_kill_urb(dev->urb_intr); + + /* reattach */ + netif_device_attach(dev->net); + } + + if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { + if (PMSG_IS_AUTO(message)) { + /* auto suspend (selective suspend) */ + ret = lan78xx_read_reg(dev, MAC_TX, &buf); + buf &= ~MAC_TX_TXEN_; + ret = lan78xx_write_reg(dev, MAC_TX, buf); + ret = lan78xx_read_reg(dev, MAC_RX, &buf); + buf &= ~MAC_RX_RXEN_; + ret = lan78xx_write_reg(dev, MAC_RX, buf); + + ret = lan78xx_write_reg(dev, WUCSR, 0); + ret = lan78xx_write_reg(dev, WUCSR2, 0); + ret = lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL); + + /* set goodframe wakeup */ + ret = lan78xx_read_reg(dev, WUCSR, &buf); + + buf |= WUCSR_RFE_WAKE_EN_; + buf |= WUCSR_STORE_WAKE_; + + ret = lan78xx_write_reg(dev, WUCSR, buf); + + ret = lan78xx_read_reg(dev, PMT_CTL, &buf); + + buf &= ~PMT_CTL_RES_CLR_WKP_EN_; + buf |= PMT_CTL_RES_CLR_WKP_STS_; + + buf |= PMT_CTL_PHY_WAKE_EN_; + buf |= PMT_CTL_WOL_EN_; + buf &= ~PMT_CTL_SUS_MODE_MASK_; + buf |= PMT_CTL_SUS_MODE_3_; + + ret = lan78xx_write_reg(dev, PMT_CTL, buf); + + ret = lan78xx_read_reg(dev, PMT_CTL, &buf); + + buf |= PMT_CTL_WUPS_MASK_; + + ret = lan78xx_write_reg(dev, PMT_CTL, buf); + + ret = lan78xx_read_reg(dev, MAC_RX, &buf); + buf |= MAC_RX_RXEN_; + ret = lan78xx_write_reg(dev, MAC_RX, buf); + } else { + lan78xx_set_suspend(dev, pdata->wol); + } + } + +out: + return ret; +} + +int lan78xx_resume(struct usb_interface *intf) +{ + struct lan78xx_net *dev = usb_get_intfdata(intf); + struct sk_buff *skb; + struct urb *res; + int ret; + u32 buf; + + if (!--dev->suspend_count) { + /* resume interrupt URBs */ + if (dev->urb_intr && test_bit(EVENT_DEV_OPEN, &dev->flags)) + usb_submit_urb(dev->urb_intr, GFP_NOIO); + + spin_lock_irq(&dev->txq.lock); + while ((res = usb_get_from_anchor(&dev->deferred))) { + skb = (struct sk_buff *)res->context; + ret = usb_submit_urb(res, GFP_ATOMIC); + if (ret < 0) { + dev_kfree_skb_any(skb); + usb_free_urb(res); + usb_autopm_put_interface_async(dev->intf); + } else { + dev->net->trans_start = jiffies; + lan78xx_queue_skb(&dev->txq, skb, tx_start); + } + } + + clear_bit(EVENT_DEV_ASLEEP, &dev->flags); + spin_unlock_irq(&dev->txq.lock); + + if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { + if (!(skb_queue_len(&dev->txq) >= dev->tx_qlen)) + netif_start_queue(dev->net); + tasklet_schedule(&dev->bh); + } + } + + ret = lan78xx_write_reg(dev, WUCSR2, 0); + ret = lan78xx_write_reg(dev, WUCSR, 0); + ret = lan78xx_write_reg(dev, WK_SRC, 0xFFF1FF1FUL); + + ret = lan78xx_write_reg(dev, WUCSR2, WUCSR2_NS_RCD_ | + WUCSR2_ARP_RCD_ | + WUCSR2_IPV6_TCPSYN_RCD_ | + WUCSR2_IPV4_TCPSYN_RCD_); + + ret = lan78xx_write_reg(dev, WUCSR, WUCSR_EEE_TX_WAKE_ | + WUCSR_EEE_RX_WAKE_ | + WUCSR_PFDA_FR_ | + WUCSR_RFE_WAKE_FR_ | + WUCSR_WUFR_ | + WUCSR_MPR_ | + WUCSR_BCST_FR_); + + ret = lan78xx_read_reg(dev, MAC_TX, &buf); + buf |= MAC_TX_TXEN_; + ret = lan78xx_write_reg(dev, MAC_TX, buf); + + return 0; +} + +int lan78xx_reset_resume(struct usb_interface *intf) +{ + struct lan78xx_net *dev = usb_get_intfdata(intf); + + lan78xx_reset(dev); + return lan78xx_resume(intf); +} + +static const struct usb_device_id products[] = { + { + /* LAN7800 USB Gigabit Ethernet Device */ + USB_DEVICE(LAN78XX_USB_VENDOR_ID, LAN7800_USB_PRODUCT_ID), + }, + { + /* LAN7850 USB Gigabit Ethernet Device */ + USB_DEVICE(LAN78XX_USB_VENDOR_ID, LAN7850_USB_PRODUCT_ID), + }, + {}, +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver lan78xx_driver = { + .name = DRIVER_NAME, + .id_table = products, + .probe = lan78xx_probe, + .disconnect = lan78xx_disconnect, + .suspend = lan78xx_suspend, + .resume = lan78xx_resume, + .reset_resume = lan78xx_reset_resume, + .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, +}; + +module_usb_driver(lan78xx_driver); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/lan78xx.h b/drivers/net/usb/lan78xx.h new file mode 100644 index 000000000000..ae7562ee72ad --- /dev/null +++ b/drivers/net/usb/lan78xx.h @@ -0,0 +1,1069 @@ +/* + * Copyright (C) 2015 Microchip Technology + * + * 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, see . + */ +#ifndef _LAN78XX_H +#define _LAN78XX_H + +/* USB Vendor Requests */ +#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0 +#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1 +#define USB_VENDOR_REQUEST_GET_STATS 0xA2 + +/* Interrupt Endpoint status word bitfields */ +#define INT_ENP_EEE_START_TX_LPI_INT BIT(26) +#define INT_ENP_EEE_STOP_TX_LPI_INT BIT(25) +#define INT_ENP_EEE_RX_LPI_INT BIT(24) +#define INT_ENP_RDFO_INT BIT(22) +#define INT_ENP_TXE_INT BIT(21) +#define INT_ENP_TX_DIS_INT BIT(19) +#define INT_ENP_RX_DIS_INT BIT(18) +#define INT_ENP_PHY_INT BIT(17) +#define INT_ENP_DP_INT BIT(16) +#define INT_ENP_MAC_ERR_INT BIT(15) +#define INT_ENP_TDFU_INT BIT(14) +#define INT_ENP_TDFO_INT BIT(13) +#define INT_ENP_UTX_FP_INT BIT(12) + +#define TX_PKT_ALIGNMENT 4 +#define RX_PKT_ALIGNMENT 4 + +/* Tx Command A */ +#define TX_CMD_A_IGE_ (0x20000000) +#define TX_CMD_A_ICE_ (0x10000000) +#define TX_CMD_A_LSO_ (0x08000000) +#define TX_CMD_A_IPE_ (0x04000000) +#define TX_CMD_A_TPE_ (0x02000000) +#define TX_CMD_A_IVTG_ (0x01000000) +#define TX_CMD_A_RVTG_ (0x00800000) +#define TX_CMD_A_FCS_ (0x00400000) +#define TX_CMD_A_LEN_MASK_ (0x000FFFFF) + +/* Tx Command B */ +#define TX_CMD_B_MSS_SHIFT_ (16) +#define TX_CMD_B_MSS_MASK_ (0x3FFF0000) +#define TX_CMD_B_MSS_MIN_ ((unsigned short)8) +#define TX_CMD_B_VTAG_MASK_ (0x0000FFFF) +#define TX_CMD_B_VTAG_PRI_MASK_ (0x0000E000) +#define TX_CMD_B_VTAG_CFI_MASK_ (0x00001000) +#define TX_CMD_B_VTAG_VID_MASK_ (0x00000FFF) + +/* Rx Command A */ +#define RX_CMD_A_ICE_ (0x80000000) +#define RX_CMD_A_TCE_ (0x40000000) +#define RX_CMD_A_CSE_MASK_ (0xC0000000) +#define RX_CMD_A_IPV_ (0x20000000) +#define RX_CMD_A_PID_MASK_ (0x18000000) +#define RX_CMD_A_PID_NONE_IP_ (0x00000000) +#define RX_CMD_A_PID_TCP_IP_ (0x08000000) +#define RX_CMD_A_PID_UDP_IP_ (0x10000000) +#define RX_CMD_A_PID_IP_ (0x18000000) +#define RX_CMD_A_PFF_ (0x04000000) +#define RX_CMD_A_BAM_ (0x02000000) +#define RX_CMD_A_MAM_ (0x01000000) +#define RX_CMD_A_FVTG_ (0x00800000) +#define RX_CMD_A_RED_ (0x00400000) +#define RX_CMD_A_RX_ERRS_MASK_ (0xC03F0000) +#define RX_CMD_A_RWT_ (0x00200000) +#define RX_CMD_A_RUNT_ (0x00100000) +#define RX_CMD_A_LONG_ (0x00080000) +#define RX_CMD_A_RXE_ (0x00040000) +#define RX_CMD_A_DRB_ (0x00020000) +#define RX_CMD_A_FCS_ (0x00010000) +#define RX_CMD_A_UAM_ (0x00008000) +#define RX_CMD_A_ICSM_ (0x00004000) +#define RX_CMD_A_LEN_MASK_ (0x00003FFF) + +/* Rx Command B */ +#define RX_CMD_B_CSUM_SHIFT_ (16) +#define RX_CMD_B_CSUM_MASK_ (0xFFFF0000) +#define RX_CMD_B_VTAG_MASK_ (0x0000FFFF) +#define RX_CMD_B_VTAG_PRI_MASK_ (0x0000E000) +#define RX_CMD_B_VTAG_CFI_MASK_ (0x00001000) +#define RX_CMD_B_VTAG_VID_MASK_ (0x00000FFF) + +/* Rx Command C */ +#define RX_CMD_C_WAKE_SHIFT_ (15) +#define RX_CMD_C_WAKE_ (0x8000) +#define RX_CMD_C_REF_FAIL_SHIFT_ (14) +#define RX_CMD_C_REF_FAIL_ (0x4000) + +/* SCSRs */ +#define NUMBER_OF_REGS (193) + +#define ID_REV (0x00) +#define ID_REV_CHIP_ID_MASK_ (0xFFFF0000) +#define ID_REV_CHIP_REV_MASK_ (0x0000FFFF) +#define ID_REV_CHIP_ID_7800_ (0x7800) + +#define FPGA_REV (0x04) +#define FPGA_REV_MINOR_MASK_ (0x0000FF00) +#define FPGA_REV_MAJOR_MASK_ (0x000000FF) + +#define INT_STS (0x0C) +#define INT_STS_CLEAR_ALL_ (0xFFFFFFFF) +#define INT_STS_EEE_TX_LPI_STRT_ (0x04000000) +#define INT_STS_EEE_TX_LPI_STOP_ (0x02000000) +#define INT_STS_EEE_RX_LPI_ (0x01000000) +#define INT_STS_RDFO_ (0x00400000) +#define INT_STS_TXE_ (0x00200000) +#define INT_STS_TX_DIS_ (0x00080000) +#define INT_STS_RX_DIS_ (0x00040000) +#define INT_STS_PHY_INT_ (0x00020000) +#define INT_STS_DP_INT_ (0x00010000) +#define INT_STS_MAC_ERR_ (0x00008000) +#define INT_STS_TDFU_ (0x00004000) +#define INT_STS_TDFO_ (0x00002000) +#define INT_STS_UFX_FP_ (0x00001000) +#define INT_STS_GPIO_MASK_ (0x00000FFF) +#define INT_STS_GPIO11_ (0x00000800) +#define INT_STS_GPIO10_ (0x00000400) +#define INT_STS_GPIO9_ (0x00000200) +#define INT_STS_GPIO8_ (0x00000100) +#define INT_STS_GPIO7_ (0x00000080) +#define INT_STS_GPIO6_ (0x00000040) +#define INT_STS_GPIO5_ (0x00000020) +#define INT_STS_GPIO4_ (0x00000010) +#define INT_STS_GPIO3_ (0x00000008) +#define INT_STS_GPIO2_ (0x00000004) +#define INT_STS_GPIO1_ (0x00000002) +#define INT_STS_GPIO0_ (0x00000001) + +#define HW_CFG (0x010) +#define HW_CFG_CLK125_EN_ (0x02000000) +#define HW_CFG_REFCLK25_EN_ (0x01000000) +#define HW_CFG_LED3_EN_ (0x00800000) +#define HW_CFG_LED2_EN_ (0x00400000) +#define HW_CFG_LED1_EN_ (0x00200000) +#define HW_CFG_LED0_EN_ (0x00100000) +#define HW_CFG_EEE_PHY_LUSU_ (0x00020000) +#define HW_CFG_EEE_TSU_ (0x00010000) +#define HW_CFG_NETDET_STS_ (0x00008000) +#define HW_CFG_NETDET_EN_ (0x00004000) +#define HW_CFG_EEM_ (0x00002000) +#define HW_CFG_RST_PROTECT_ (0x00001000) +#define HW_CFG_CONNECT_BUF_ (0x00000400) +#define HW_CFG_CONNECT_EN_ (0x00000200) +#define HW_CFG_CONNECT_POL_ (0x00000100) +#define HW_CFG_SUSPEND_N_SEL_MASK_ (0x000000C0) +#define HW_CFG_SUSPEND_N_SEL_2 (0x00000000) +#define HW_CFG_SUSPEND_N_SEL_12N (0x00000040) +#define HW_CFG_SUSPEND_N_SEL_012N (0x00000080) +#define HW_CFG_SUSPEND_N_SEL_0123N (0x000000C0) +#define HW_CFG_SUSPEND_N_POL_ (0x00000020) +#define HW_CFG_MEF_ (0x00000010) +#define HW_CFG_ETC_ (0x00000008) +#define HW_CFG_LRST_ (0x00000002) +#define HW_CFG_SRST_ (0x00000001) + +#define PMT_CTL (0x014) +#define PMT_CTL_EEE_WAKEUP_EN_ (0x00002000) +#define PMT_CTL_EEE_WUPS_ (0x00001000) +#define PMT_CTL_MAC_SRST_ (0x00000800) +#define PMT_CTL_PHY_PWRUP_ (0x00000400) +#define PMT_CTL_RES_CLR_WKP_MASK_ (0x00000300) +#define PMT_CTL_RES_CLR_WKP_STS_ (0x00000200) +#define PMT_CTL_RES_CLR_WKP_EN_ (0x00000100) +#define PMT_CTL_READY_ (0x00000080) +#define PMT_CTL_SUS_MODE_MASK_ (0x00000060) +#define PMT_CTL_SUS_MODE_0_ (0x00000000) +#define PMT_CTL_SUS_MODE_1_ (0x00000020) +#define PMT_CTL_SUS_MODE_2_ (0x00000040) +#define PMT_CTL_SUS_MODE_3_ (0x00000060) +#define PMT_CTL_PHY_RST_ (0x00000010) +#define PMT_CTL_WOL_EN_ (0x00000008) +#define PMT_CTL_PHY_WAKE_EN_ (0x00000004) +#define PMT_CTL_WUPS_MASK_ (0x00000003) +#define PMT_CTL_WUPS_MLT_ (0x00000003) +#define PMT_CTL_WUPS_MAC_ (0x00000002) +#define PMT_CTL_WUPS_PHY_ (0x00000001) + +#define GPIO_CFG0 (0x018) +#define GPIO_CFG0_GPIOEN_MASK_ (0x0000F000) +#define GPIO_CFG0_GPIOEN3_ (0x00008000) +#define GPIO_CFG0_GPIOEN2_ (0x00004000) +#define GPIO_CFG0_GPIOEN1_ (0x00002000) +#define GPIO_CFG0_GPIOEN0_ (0x00001000) +#define GPIO_CFG0_GPIOBUF_MASK_ (0x00000F00) +#define GPIO_CFG0_GPIOBUF3_ (0x00000800) +#define GPIO_CFG0_GPIOBUF2_ (0x00000400) +#define GPIO_CFG0_GPIOBUF1_ (0x00000200) +#define GPIO_CFG0_GPIOBUF0_ (0x00000100) +#define GPIO_CFG0_GPIODIR_MASK_ (0x000000F0) +#define GPIO_CFG0_GPIODIR3_ (0x00000080) +#define GPIO_CFG0_GPIODIR2_ (0x00000040) +#define GPIO_CFG0_GPIODIR1_ (0x00000020) +#define GPIO_CFG0_GPIODIR0_ (0x00000010) +#define GPIO_CFG0_GPIOD_MASK_ (0x0000000F) +#define GPIO_CFG0_GPIOD3_ (0x00000008) +#define GPIO_CFG0_GPIOD2_ (0x00000004) +#define GPIO_CFG0_GPIOD1_ (0x00000002) +#define GPIO_CFG0_GPIOD0_ (0x00000001) + +#define GPIO_CFG1 (0x01C) +#define GPIO_CFG1_GPIOEN_MASK_ (0xFF000000) +#define GPIO_CFG1_GPIOEN11_ (0x80000000) +#define GPIO_CFG1_GPIOEN10_ (0x40000000) +#define GPIO_CFG1_GPIOEN9_ (0x20000000) +#define GPIO_CFG1_GPIOEN8_ (0x10000000) +#define GPIO_CFG1_GPIOEN7_ (0x08000000) +#define GPIO_CFG1_GPIOEN6_ (0x04000000) +#define GPIO_CFG1_GPIOEN5_ (0x02000000) +#define GPIO_CFG1_GPIOEN4_ (0x01000000) +#define GPIO_CFG1_GPIOBUF_MASK_ (0x00FF0000) +#define GPIO_CFG1_GPIOBUF11_ (0x00800000) +#define GPIO_CFG1_GPIOBUF10_ (0x00400000) +#define GPIO_CFG1_GPIOBUF9_ (0x00200000) +#define GPIO_CFG1_GPIOBUF8_ (0x00100000) +#define GPIO_CFG1_GPIOBUF7_ (0x00080000) +#define GPIO_CFG1_GPIOBUF6_ (0x00040000) +#define GPIO_CFG1_GPIOBUF5_ (0x00020000) +#define GPIO_CFG1_GPIOBUF4_ (0x00010000) +#define GPIO_CFG1_GPIODIR_MASK_ (0x0000FF00) +#define GPIO_CFG1_GPIODIR11_ (0x00008000) +#define GPIO_CFG1_GPIODIR10_ (0x00004000) +#define GPIO_CFG1_GPIODIR9_ (0x00002000) +#define GPIO_CFG1_GPIODIR8_ (0x00001000) +#define GPIO_CFG1_GPIODIR7_ (0x00000800) +#define GPIO_CFG1_GPIODIR6_ (0x00000400) +#define GPIO_CFG1_GPIODIR5_ (0x00000200) +#define GPIO_CFG1_GPIODIR4_ (0x00000100) +#define GPIO_CFG1_GPIOD_MASK_ (0x000000FF) +#define GPIO_CFG1_GPIOD11_ (0x00000080) +#define GPIO_CFG1_GPIOD10_ (0x00000040) +#define GPIO_CFG1_GPIOD9_ (0x00000020) +#define GPIO_CFG1_GPIOD8_ (0x00000010) +#define GPIO_CFG1_GPIOD7_ (0x00000008) +#define GPIO_CFG1_GPIOD6_ (0x00000004) +#define GPIO_CFG1_GPIOD6_ (0x00000004) +#define GPIO_CFG1_GPIOD5_ (0x00000002) +#define GPIO_CFG1_GPIOD4_ (0x00000001) + +#define GPIO_WAKE (0x020) +#define GPIO_WAKE_GPIOPOL_MASK_ (0x0FFF0000) +#define GPIO_WAKE_GPIOPOL11_ (0x08000000) +#define GPIO_WAKE_GPIOPOL10_ (0x04000000) +#define GPIO_WAKE_GPIOPOL9_ (0x02000000) +#define GPIO_WAKE_GPIOPOL8_ (0x01000000) +#define GPIO_WAKE_GPIOPOL7_ (0x00800000) +#define GPIO_WAKE_GPIOPOL6_ (0x00400000) +#define GPIO_WAKE_GPIOPOL5_ (0x00200000) +#define GPIO_WAKE_GPIOPOL4_ (0x00100000) +#define GPIO_WAKE_GPIOPOL3_ (0x00080000) +#define GPIO_WAKE_GPIOPOL2_ (0x00040000) +#define GPIO_WAKE_GPIOPOL1_ (0x00020000) +#define GPIO_WAKE_GPIOPOL0_ (0x00010000) +#define GPIO_WAKE_GPIOWK_MASK_ (0x00000FFF) +#define GPIO_WAKE_GPIOWK11_ (0x00000800) +#define GPIO_WAKE_GPIOWK10_ (0x00000400) +#define GPIO_WAKE_GPIOWK9_ (0x00000200) +#define GPIO_WAKE_GPIOWK8_ (0x00000100) +#define GPIO_WAKE_GPIOWK7_ (0x00000080) +#define GPIO_WAKE_GPIOWK6_ (0x00000040) +#define GPIO_WAKE_GPIOWK5_ (0x00000020) +#define GPIO_WAKE_GPIOWK4_ (0x00000010) +#define GPIO_WAKE_GPIOWK3_ (0x00000008) +#define GPIO_WAKE_GPIOWK2_ (0x00000004) +#define GPIO_WAKE_GPIOWK1_ (0x00000002) +#define GPIO_WAKE_GPIOWK0_ (0x00000001) + +#define DP_SEL (0x024) +#define DP_SEL_DPRDY_ (0x80000000) +#define DP_SEL_RSEL_MASK_ (0x0000000F) +#define DP_SEL_RSEL_USB_PHY_CSRS_ (0x0000000F) +#define DP_SEL_RSEL_OTP_64BIT_ (0x00000009) +#define DP_SEL_RSEL_OTP_8BIT_ (0x00000008) +#define DP_SEL_RSEL_UTX_BUF_RAM_ (0x00000007) +#define DP_SEL_RSEL_DESC_RAM_ (0x00000005) +#define DP_SEL_RSEL_TXFIFO_ (0x00000004) +#define DP_SEL_RSEL_RXFIFO_ (0x00000003) +#define DP_SEL_RSEL_LSO_ (0x00000002) +#define DP_SEL_RSEL_VLAN_DA_ (0x00000001) +#define DP_SEL_RSEL_URXBUF_ (0x00000000) +#define DP_SEL_VHF_HASH_LEN (16) +#define DP_SEL_VHF_VLAN_LEN (128) + +#define DP_CMD (0x028) +#define DP_CMD_WRITE_ (0x00000001) +#define DP_CMD_READ_ (0x00000000) + +#define DP_ADDR (0x02C) +#define DP_ADDR_MASK_ (0x00003FFF) + +#define DP_DATA (0x030) + +#define E2P_CMD (0x040) +#define E2P_CMD_EPC_BUSY_ (0x80000000) +#define E2P_CMD_EPC_CMD_MASK_ (0x70000000) +#define E2P_CMD_EPC_CMD_RELOAD_ (0x70000000) +#define E2P_CMD_EPC_CMD_ERAL_ (0x60000000) +#define E2P_CMD_EPC_CMD_ERASE_ (0x50000000) +#define E2P_CMD_EPC_CMD_WRAL_ (0x40000000) +#define E2P_CMD_EPC_CMD_WRITE_ (0x30000000) +#define E2P_CMD_EPC_CMD_EWEN_ (0x20000000) +#define E2P_CMD_EPC_CMD_EWDS_ (0x10000000) +#define E2P_CMD_EPC_CMD_READ_ (0x00000000) +#define E2P_CMD_EPC_TIMEOUT_ (0x00000400) +#define E2P_CMD_EPC_DL_ (0x00000200) +#define E2P_CMD_EPC_ADDR_MASK_ (0x000001FF) + +#define E2P_DATA (0x044) +#define E2P_DATA_EEPROM_DATA_MASK_ (0x000000FF) + +#define BOS_ATTR (0x050) +#define BOS_ATTR_BLOCK_SIZE_MASK_ (0x000000FF) + +#define SS_ATTR (0x054) +#define SS_ATTR_POLL_INT_MASK_ (0x00FF0000) +#define SS_ATTR_DEV_DESC_SIZE_MASK_ (0x0000FF00) +#define SS_ATTR_CFG_BLK_SIZE_MASK_ (0x000000FF) + +#define HS_ATTR (0x058) +#define HS_ATTR_POLL_INT_MASK_ (0x00FF0000) +#define HS_ATTR_DEV_DESC_SIZE_MASK_ (0x0000FF00) +#define HS_ATTR_CFG_BLK_SIZE_MASK_ (0x000000FF) + +#define FS_ATTR (0x05C) +#define FS_ATTR_POLL_INT_MASK_ (0x00FF0000) +#define FS_ATTR_DEV_DESC_SIZE_MASK_ (0x0000FF00) +#define FS_ATTR_CFG_BLK_SIZE_MASK_ (0x000000FF) + +#define STR_ATTR0 (0x060) +#define STR_ATTR0_CFGSTR_DESC_SIZE_MASK_ (0xFF000000) +#define STR_ATTR0_SERSTR_DESC_SIZE_MASK_ (0x00FF0000) +#define STR_ATTR0_PRODSTR_DESC_SIZE_MASK_ (0x0000FF00) +#define STR_ATTR0_MANUF_DESC_SIZE_MASK_ (0x000000FF) + +#define STR_ATTR1 (0x064) +#define STR_ATTR1_INTSTR_DESC_SIZE_MASK_ (0x000000FF) + +#define STR_FLAG_ATTR (0x068) +#define STR_FLAG_ATTR_PME_FLAGS_MASK_ (0x000000FF) + +#define USB_CFG0 (0x080) +#define USB_CFG_LPM_RESPONSE_ (0x80000000) +#define USB_CFG_LPM_CAPABILITY_ (0x40000000) +#define USB_CFG_LPM_ENBL_SLPM_ (0x20000000) +#define USB_CFG_HIRD_THR_MASK_ (0x1F000000) +#define USB_CFG_HIRD_THR_960_ (0x1C000000) +#define USB_CFG_HIRD_THR_885_ (0x1B000000) +#define USB_CFG_HIRD_THR_810_ (0x1A000000) +#define USB_CFG_HIRD_THR_735_ (0x19000000) +#define USB_CFG_HIRD_THR_660_ (0x18000000) +#define USB_CFG_HIRD_THR_585_ (0x17000000) +#define USB_CFG_HIRD_THR_510_ (0x16000000) +#define USB_CFG_HIRD_THR_435_ (0x15000000) +#define USB_CFG_HIRD_THR_360_ (0x14000000) +#define USB_CFG_HIRD_THR_285_ (0x13000000) +#define USB_CFG_HIRD_THR_210_ (0x12000000) +#define USB_CFG_HIRD_THR_135_ (0x11000000) +#define USB_CFG_HIRD_THR_60_ (0x10000000) +#define USB_CFG_MAX_BURST_BI_MASK_ (0x00F00000) +#define USB_CFG_MAX_BURST_BO_MASK_ (0x000F0000) +#define USB_CFG_MAX_DEV_SPEED_MASK_ (0x0000E000) +#define USB_CFG_MAX_DEV_SPEED_SS_ (0x00008000) +#define USB_CFG_MAX_DEV_SPEED_HS_ (0x00000000) +#define USB_CFG_MAX_DEV_SPEED_FS_ (0x00002000) +#define USB_CFG_PHY_BOOST_MASK_ (0x00000180) +#define USB_CFG_PHY_BOOST_PLUS_12_ (0x00000180) +#define USB_CFG_PHY_BOOST_PLUS_8_ (0x00000100) +#define USB_CFG_PHY_BOOST_PLUS_4_ (0x00000080) +#define USB_CFG_PHY_BOOST_NORMAL_ (0x00000000) +#define USB_CFG_BIR_ (0x00000040) +#define USB_CFG_BCE_ (0x00000020) +#define USB_CFG_PORT_SWAP_ (0x00000010) +#define USB_CFG_LPM_EN_ (0x00000008) +#define USB_CFG_RMT_WKP_ (0x00000004) +#define USB_CFG_PWR_SEL_ (0x00000002) +#define USB_CFG_STALL_BO_DIS_ (0x00000001) + +#define USB_CFG1 (0x084) +#define USB_CFG1_U1_TIMEOUT_MASK_ (0xFF000000) +#define USB_CFG1_U2_TIMEOUT_MASK_ (0x00FF0000) +#define USB_CFG1_HS_TOUT_CAL_MASK_ (0x0000E000) +#define USB_CFG1_DEV_U2_INIT_EN_ (0x00001000) +#define USB_CFG1_DEV_U2_EN_ (0x00000800) +#define USB_CFG1_DEV_U1_INIT_EN_ (0x00000400) +#define USB_CFG1_DEV_U1_EN_ (0x00000200) +#define USB_CFG1_LTM_ENABLE_ (0x00000100) +#define USB_CFG1_FS_TOUT_CAL_MASK_ (0x00000070) +#define USB_CFG1_SCALE_DOWN_MASK_ (0x00000003) +#define USB_CFG1_SCALE_DOWN_MODE3_ (0x00000003) +#define USB_CFG1_SCALE_DOWN_MODE2_ (0x00000002) +#define USB_CFG1_SCALE_DOWN_MODE1_ (0x00000001) +#define USB_CFG1_SCALE_DOWN_MODE0_ (0x00000000) + +#define USB_CFG2 (0x088) +#define USB_CFG2_SS_DETACH_TIME_MASK_ (0xFFFF0000) +#define USB_CFG2_HS_DETACH_TIME_MASK_ (0x0000FFFF) + +#define BURST_CAP (0x090) +#define BURST_CAP_SIZE_MASK_ (0x000000FF) + +#define BULK_IN_DLY (0x094) +#define BULK_IN_DLY_MASK_ (0x0000FFFF) + +#define INT_EP_CTL (0x098) +#define INT_EP_INTEP_ON_ (0x80000000) +#define INT_STS_EEE_TX_LPI_STRT_EN_ (0x04000000) +#define INT_STS_EEE_TX_LPI_STOP_EN_ (0x02000000) +#define INT_STS_EEE_RX_LPI_EN_ (0x01000000) +#define INT_EP_RDFO_EN_ (0x00400000) +#define INT_EP_TXE_EN_ (0x00200000) +#define INT_EP_TX_DIS_EN_ (0x00080000) +#define INT_EP_RX_DIS_EN_ (0x00040000) +#define INT_EP_PHY_INT_EN_ (0x00020000) +#define INT_EP_DP_INT_EN_ (0x00010000) +#define INT_EP_MAC_ERR_EN_ (0x00008000) +#define INT_EP_TDFU_EN_ (0x00004000) +#define INT_EP_TDFO_EN_ (0x00002000) +#define INT_EP_UTX_FP_EN_ (0x00001000) +#define INT_EP_GPIO_EN_MASK_ (0x00000FFF) + +#define PIPE_CTL (0x09C) +#define PIPE_CTL_TXSWING_ (0x00000040) +#define PIPE_CTL_TXMARGIN_MASK_ (0x00000038) +#define PIPE_CTL_TXDEEMPHASIS_MASK_ (0x00000006) +#define PIPE_CTL_ELASTICITYBUFFERMODE_ (0x00000001) + +#define U1_LATENCY (0xA0) +#define U2_LATENCY (0xA4) + +#define USB_STATUS (0x0A8) +#define USB_STATUS_REMOTE_WK_ (0x00100000) +#define USB_STATUS_FUNC_REMOTE_WK_ (0x00080000) +#define USB_STATUS_LTM_ENABLE_ (0x00040000) +#define USB_STATUS_U2_ENABLE_ (0x00020000) +#define USB_STATUS_U1_ENABLE_ (0x00010000) +#define USB_STATUS_SET_SEL_ (0x00000020) +#define USB_STATUS_REMOTE_WK_STS_ (0x00000010) +#define USB_STATUS_FUNC_REMOTE_WK_STS_ (0x00000008) +#define USB_STATUS_LTM_ENABLE_STS_ (0x00000004) +#define USB_STATUS_U2_ENABLE_STS_ (0x00000002) +#define USB_STATUS_U1_ENABLE_STS_ (0x00000001) + +#define USB_CFG3 (0x0AC) +#define USB_CFG3_EN_U2_LTM_ (0x40000000) +#define USB_CFG3_BULK_OUT_NUMP_OVR_ (0x20000000) +#define USB_CFG3_DIS_FAST_U1_EXIT_ (0x10000000) +#define USB_CFG3_LPM_NYET_THR_ (0x0F000000) +#define USB_CFG3_RX_DET_2_POL_LFPS_ (0x00800000) +#define USB_CFG3_LFPS_FILT_ (0x00400000) +#define USB_CFG3_SKIP_RX_DET_ (0x00200000) +#define USB_CFG3_DELAY_P1P2P3_ (0x001C0000) +#define USB_CFG3_DELAY_PHY_PWR_CHG_ (0x00020000) +#define USB_CFG3_U1U2_EXIT_FR_ (0x00010000) +#define USB_CFG3_REQ_P1P2P3 (0x00008000) +#define USB_CFG3_HST_PRT_CMPL_ (0x00004000) +#define USB_CFG3_DIS_SCRAMB_ (0x00002000) +#define USB_CFG3_PWR_DN_SCALE_ (0x00001FFF) + +#define RFE_CTL (0x0B0) +#define RFE_CTL_IGMP_COE_ (0x00004000) +#define RFE_CTL_ICMP_COE_ (0x00002000) +#define RFE_CTL_TCPUDP_COE_ (0x00001000) +#define RFE_CTL_IP_COE_ (0x00000800) +#define RFE_CTL_BCAST_EN_ (0x00000400) +#define RFE_CTL_MCAST_EN_ (0x00000200) +#define RFE_CTL_UCAST_EN_ (0x00000100) +#define RFE_CTL_VLAN_STRIP_ (0x00000080) +#define RFE_CTL_DISCARD_UNTAGGED_ (0x00000040) +#define RFE_CTL_VLAN_FILTER_ (0x00000020) +#define RFE_CTL_SA_FILTER_ (0x00000010) +#define RFE_CTL_MCAST_HASH_ (0x00000008) +#define RFE_CTL_DA_HASH_ (0x00000004) +#define RFE_CTL_DA_PERFECT_ (0x00000002) +#define RFE_CTL_RST_ (0x00000001) + +#define VLAN_TYPE (0x0B4) +#define VLAN_TYPE_MASK_ (0x0000FFFF) + +#define FCT_RX_CTL (0x0C0) +#define FCT_RX_CTL_EN_ (0x80000000) +#define FCT_RX_CTL_RST_ (0x40000000) +#define FCT_RX_CTL_SBF_ (0x02000000) +#define FCT_RX_CTL_OVFL_ (0x01000000) +#define FCT_RX_CTL_DROP_ (0x00800000) +#define FCT_RX_CTL_NOT_EMPTY_ (0x00400000) +#define FCT_RX_CTL_EMPTY_ (0x00200000) +#define FCT_RX_CTL_DIS_ (0x00100000) +#define FCT_RX_CTL_USED_MASK_ (0x0000FFFF) + +#define FCT_TX_CTL (0x0C4) +#define FCT_TX_CTL_EN_ (0x80000000) +#define FCT_TX_CTL_RST_ (0x40000000) +#define FCT_TX_CTL_NOT_EMPTY_ (0x00400000) +#define FCT_TX_CTL_EMPTY_ (0x00200000) +#define FCT_TX_CTL_DIS_ (0x00100000) +#define FCT_TX_CTL_USED_MASK_ (0x0000FFFF) + +#define FCT_RX_FIFO_END (0x0C8) +#define FCT_RX_FIFO_END_MASK_ (0x0000007F) + +#define FCT_TX_FIFO_END (0x0CC) +#define FCT_TX_FIFO_END_MASK_ (0x0000003F) + +#define FCT_FLOW (0x0D0) +#define FCT_FLOW_OFF_MASK_ (0x00007F00) +#define FCT_FLOW_ON_MASK_ (0x0000007F) + +#define RX_DP_STOR (0x0D4) +#define RX_DP_STORE_TOT_RXUSED_MASK_ (0xFFFF0000) +#define RX_DP_STORE_UTX_RXUSED_MASK_ (0x0000FFFF) + +#define TX_DP_STOR (0x0D8) +#define TX_DP_STORE_TOT_TXUSED_MASK_ (0xFFFF0000) +#define TX_DP_STORE_URX_TXUSED_MASK_ (0x0000FFFF) + +#define LTM_BELT_IDLE0 (0x0E0) +#define LTM_BELT_IDLE0_IDLE1000_ (0x0FFF0000) +#define LTM_BELT_IDLE0_IDLE100_ (0x00000FFF) + +#define LTM_BELT_IDLE1 (0x0E4) +#define LTM_BELT_IDLE1_IDLE10_ (0x00000FFF) + +#define LTM_BELT_ACT0 (0x0E8) +#define LTM_BELT_ACT0_ACT1000_ (0x0FFF0000) +#define LTM_BELT_ACT0_ACT100_ (0x00000FFF) + +#define LTM_BELT_ACT1 (0x0EC) +#define LTM_BELT_ACT1_ACT10_ (0x00000FFF) + +#define LTM_INACTIVE0 (0x0F0) +#define LTM_INACTIVE0_TIMER1000_ (0xFFFF0000) +#define LTM_INACTIVE0_TIMER100_ (0x0000FFFF) + +#define LTM_INACTIVE1 (0x0F4) +#define LTM_INACTIVE1_TIMER10_ (0x0000FFFF) + +#define MAC_CR (0x100) +#define MAC_CR_GMII_EN_ (0x00080000) +#define MAC_CR_EEE_TX_CLK_STOP_EN_ (0x00040000) +#define MAC_CR_EEE_EN_ (0x00020000) +#define MAC_CR_EEE_TLAR_EN_ (0x00010000) +#define MAC_CR_ADP_ (0x00002000) +#define MAC_CR_AUTO_DUPLEX_ (0x00001000) +#define MAC_CR_AUTO_SPEED_ (0x00000800) +#define MAC_CR_LOOPBACK_ (0x00000400) +#define MAC_CR_BOLMT_MASK_ (0x000000C0) +#define MAC_CR_FULL_DUPLEX_ (0x00000008) +#define MAC_CR_SPEED_MASK_ (0x00000006) +#define MAC_CR_SPEED_1000_ (0x00000004) +#define MAC_CR_SPEED_100_ (0x00000002) +#define MAC_CR_SPEED_10_ (0x00000000) +#define MAC_CR_RST_ (0x00000001) + +#define MAC_RX (0x104) +#define MAC_RX_MAX_SIZE_SHIFT_ (16) +#define MAC_RX_MAX_SIZE_MASK_ (0x3FFF0000) +#define MAC_RX_FCS_STRIP_ (0x00000010) +#define MAC_RX_VLAN_FSE_ (0x00000004) +#define MAC_RX_RXD_ (0x00000002) +#define MAC_RX_RXEN_ (0x00000001) + +#define MAC_TX (0x108) +#define MAC_TX_BAD_FCS_ (0x00000004) +#define MAC_TX_TXD_ (0x00000002) +#define MAC_TX_TXEN_ (0x00000001) + +#define FLOW (0x10C) +#define FLOW_CR_FORCE_FC_ (0x80000000) +#define FLOW_CR_TX_FCEN_ (0x40000000) +#define FLOW_CR_RX_FCEN_ (0x20000000) +#define FLOW_CR_FPF_ (0x10000000) +#define FLOW_CR_FCPT_MASK_ (0x0000FFFF) + +#define RAND_SEED (0x110) +#define RAND_SEED_MASK_ (0x0000FFFF) + +#define ERR_STS (0x114) +#define ERR_STS_FERR_ (0x00000100) +#define ERR_STS_LERR_ (0x00000080) +#define ERR_STS_RFERR_ (0x00000040) +#define ERR_STS_ECERR_ (0x00000010) +#define ERR_STS_ALERR_ (0x00000008) +#define ERR_STS_URERR_ (0x00000004) + +#define RX_ADDRH (0x118) +#define RX_ADDRH_MASK_ (0x0000FFFF) + +#define RX_ADDRL (0x11C) +#define RX_ADDRL_MASK_ (0xFFFFFFFF) + +#define MII_ACC (0x120) +#define MII_ACC_PHY_ADDR_SHIFT_ (11) +#define MII_ACC_PHY_ADDR_MASK_ (0x0000F800) +#define MII_ACC_MIIRINDA_SHIFT_ (6) +#define MII_ACC_MIIRINDA_MASK_ (0x000007C0) +#define MII_ACC_MII_READ_ (0x00000000) +#define MII_ACC_MII_WRITE_ (0x00000002) +#define MII_ACC_MII_BUSY_ (0x00000001) + +#define MII_DATA (0x124) +#define MII_DATA_MASK_ (0x0000FFFF) + +#define MAC_RGMII_ID (0x128) +#define MAC_RGMII_ID_TXC_DELAY_EN_ (0x00000002) +#define MAC_RGMII_ID_RXC_DELAY_EN_ (0x00000001) + +#define EEE_TX_LPI_REQ_DLY (0x130) +#define EEE_TX_LPI_REQ_DLY_CNT_MASK_ (0xFFFFFFFF) + +#define EEE_TW_TX_SYS (0x134) +#define EEE_TW_TX_SYS_CNT1G_MASK_ (0xFFFF0000) +#define EEE_TW_TX_SYS_CNT100M_MASK_ (0x0000FFFF) + +#define EEE_TX_LPI_REM_DLY (0x138) +#define EEE_TX_LPI_REM_DLY_CNT_ (0x00FFFFFF) + +#define WUCSR (0x140) +#define WUCSR_TESTMODE_ (0x80000000) +#define WUCSR_RFE_WAKE_EN_ (0x00004000) +#define WUCSR_EEE_TX_WAKE_ (0x00002000) +#define WUCSR_EEE_TX_WAKE_EN_ (0x00001000) +#define WUCSR_EEE_RX_WAKE_ (0x00000800) +#define WUCSR_EEE_RX_WAKE_EN_ (0x00000400) +#define WUCSR_RFE_WAKE_FR_ (0x00000200) +#define WUCSR_STORE_WAKE_ (0x00000100) +#define WUCSR_PFDA_FR_ (0x00000080) +#define WUCSR_WUFR_ (0x00000040) +#define WUCSR_MPR_ (0x00000020) +#define WUCSR_BCST_FR_ (0x00000010) +#define WUCSR_PFDA_EN_ (0x00000008) +#define WUCSR_WAKE_EN_ (0x00000004) +#define WUCSR_MPEN_ (0x00000002) +#define WUCSR_BCST_EN_ (0x00000001) + +#define WK_SRC (0x144) +#define WK_SRC_GPIOX_INT_WK_SHIFT_ (20) +#define WK_SRC_GPIOX_INT_WK_MASK_ (0xFFF00000) +#define WK_SRC_IPV6_TCPSYN_RCD_WK_ (0x00010000) +#define WK_SRC_IPV4_TCPSYN_RCD_WK_ (0x00008000) +#define WK_SRC_EEE_TX_WK_ (0x00004000) +#define WK_SRC_EEE_RX_WK_ (0x00002000) +#define WK_SRC_GOOD_FR_WK_ (0x00001000) +#define WK_SRC_PFDA_FR_WK_ (0x00000800) +#define WK_SRC_MP_FR_WK_ (0x00000400) +#define WK_SRC_BCAST_FR_WK_ (0x00000200) +#define WK_SRC_WU_FR_WK_ (0x00000100) +#define WK_SRC_WUFF_MATCH_MASK_ (0x0000001F) + +#define WUF_CFG0 (0x150) +#define NUM_OF_WUF_CFG (32) +#define WUF_CFG_BEGIN (WUF_CFG0) +#define WUF_CFG(index) (WUF_CFG_BEGIN + (4 * (index))) +#define WUF_CFGX_EN_ (0x80000000) +#define WUF_CFGX_TYPE_MASK_ (0x03000000) +#define WUF_CFGX_TYPE_MCAST_ (0x02000000) +#define WUF_CFGX_TYPE_ALL_ (0x01000000) +#define WUF_CFGX_TYPE_UCAST_ (0x00000000) +#define WUF_CFGX_OFFSET_SHIFT_ (16) +#define WUF_CFGX_OFFSET_MASK_ (0x00FF0000) +#define WUF_CFGX_CRC16_MASK_ (0x0000FFFF) + +#define WUF_MASK0_0 (0x200) +#define WUF_MASK0_1 (0x204) +#define WUF_MASK0_2 (0x208) +#define WUF_MASK0_3 (0x20C) +#define NUM_OF_WUF_MASK (32) +#define WUF_MASK0_BEGIN (WUF_MASK0_0) +#define WUF_MASK1_BEGIN (WUF_MASK0_1) +#define WUF_MASK2_BEGIN (WUF_MASK0_2) +#define WUF_MASK3_BEGIN (WUF_MASK0_3) +#define WUF_MASK0(index) (WUF_MASK0_BEGIN + (0x10 * (index))) +#define WUF_MASK1(index) (WUF_MASK1_BEGIN + (0x10 * (index))) +#define WUF_MASK2(index) (WUF_MASK2_BEGIN + (0x10 * (index))) +#define WUF_MASK3(index) (WUF_MASK3_BEGIN + (0x10 * (index))) + +#define MAF_BASE (0x400) +#define MAF_HIX (0x00) +#define MAF_LOX (0x04) +#define NUM_OF_MAF (33) +#define MAF_HI_BEGIN (MAF_BASE + MAF_HIX) +#define MAF_LO_BEGIN (MAF_BASE + MAF_LOX) +#define MAF_HI(index) (MAF_BASE + (8 * (index)) + (MAF_HIX)) +#define MAF_LO(index) (MAF_BASE + (8 * (index)) + (MAF_LOX)) +#define MAF_HI_VALID_ (0x80000000) +#define MAF_HI_TYPE_MASK_ (0x40000000) +#define MAF_HI_TYPE_SRC_ (0x40000000) +#define MAF_HI_TYPE_DST_ (0x00000000) +#define MAF_HI_ADDR_MASK (0x0000FFFF) +#define MAF_LO_ADDR_MASK (0xFFFFFFFF) + +#define WUCSR2 (0x600) +#define WUCSR2_CSUM_DISABLE_ (0x80000000) +#define WUCSR2_NA_SA_SEL_ (0x00000100) +#define WUCSR2_NS_RCD_ (0x00000080) +#define WUCSR2_ARP_RCD_ (0x00000040) +#define WUCSR2_IPV6_TCPSYN_RCD_ (0x00000020) +#define WUCSR2_IPV4_TCPSYN_RCD_ (0x00000010) +#define WUCSR2_NS_OFFLOAD_EN_ (0x00000008) +#define WUCSR2_ARP_OFFLOAD_EN_ (0x00000004) +#define WUCSR2_IPV6_TCPSYN_WAKE_EN_ (0x00000002) +#define WUCSR2_IPV4_TCPSYN_WAKE_EN_ (0x00000001) + +#define NS1_IPV6_ADDR_DEST0 (0x610) +#define NS1_IPV6_ADDR_DEST1 (0x614) +#define NS1_IPV6_ADDR_DEST2 (0x618) +#define NS1_IPV6_ADDR_DEST3 (0x61C) + +#define NS1_IPV6_ADDR_SRC0 (0x620) +#define NS1_IPV6_ADDR_SRC1 (0x624) +#define NS1_IPV6_ADDR_SRC2 (0x628) +#define NS1_IPV6_ADDR_SRC3 (0x62C) + +#define NS1_ICMPV6_ADDR0_0 (0x630) +#define NS1_ICMPV6_ADDR0_1 (0x634) +#define NS1_ICMPV6_ADDR0_2 (0x638) +#define NS1_ICMPV6_ADDR0_3 (0x63C) + +#define NS1_ICMPV6_ADDR1_0 (0x640) +#define NS1_ICMPV6_ADDR1_1 (0x644) +#define NS1_ICMPV6_ADDR1_2 (0x648) +#define NS1_ICMPV6_ADDR1_3 (0x64C) + +#define NS2_IPV6_ADDR_DEST0 (0x650) +#define NS2_IPV6_ADDR_DEST1 (0x654) +#define NS2_IPV6_ADDR_DEST2 (0x658) +#define NS2_IPV6_ADDR_DEST3 (0x65C) + +#define NS2_IPV6_ADDR_SRC0 (0x660) +#define NS2_IPV6_ADDR_SRC1 (0x664) +#define NS2_IPV6_ADDR_SRC2 (0x668) +#define NS2_IPV6_ADDR_SRC3 (0x66C) + +#define NS2_ICMPV6_ADDR0_0 (0x670) +#define NS2_ICMPV6_ADDR0_1 (0x674) +#define NS2_ICMPV6_ADDR0_2 (0x678) +#define NS2_ICMPV6_ADDR0_3 (0x67C) + +#define NS2_ICMPV6_ADDR1_0 (0x680) +#define NS2_ICMPV6_ADDR1_1 (0x684) +#define NS2_ICMPV6_ADDR1_2 (0x688) +#define NS2_ICMPV6_ADDR1_3 (0x68C) + +#define SYN_IPV4_ADDR_SRC (0x690) +#define SYN_IPV4_ADDR_DEST (0x694) +#define SYN_IPV4_TCP_PORTS (0x698) +#define SYN_IPV4_TCP_PORTS_IPV4_DEST_PORT_SHIFT_ (16) +#define SYN_IPV4_TCP_PORTS_IPV4_DEST_PORT_MASK_ (0xFFFF0000) +#define SYN_IPV4_TCP_PORTS_IPV4_SRC_PORT_MASK_ (0x0000FFFF) + +#define SYN_IPV6_ADDR_SRC0 (0x69C) +#define SYN_IPV6_ADDR_SRC1 (0x6A0) +#define SYN_IPV6_ADDR_SRC2 (0x6A4) +#define SYN_IPV6_ADDR_SRC3 (0x6A8) + +#define SYN_IPV6_ADDR_DEST0 (0x6AC) +#define SYN_IPV6_ADDR_DEST1 (0x6B0) +#define SYN_IPV6_ADDR_DEST2 (0x6B4) +#define SYN_IPV6_ADDR_DEST3 (0x6B8) + +#define SYN_IPV6_TCP_PORTS (0x6BC) +#define SYN_IPV6_TCP_PORTS_IPV6_DEST_PORT_SHIFT_ (16) +#define SYN_IPV6_TCP_PORTS_IPV6_DEST_PORT_MASK_ (0xFFFF0000) +#define SYN_IPV6_TCP_PORTS_IPV6_SRC_PORT_MASK_ (0x0000FFFF) + +#define ARP_SPA (0x6C0) +#define ARP_TPA (0x6C4) + +#define PHY_DEV_ID (0x700) +#define PHY_DEV_ID_REV_SHIFT_ (28) +#define PHY_DEV_ID_REV_SHIFT_ (28) +#define PHY_DEV_ID_REV_MASK_ (0xF0000000) +#define PHY_DEV_ID_MODEL_SHIFT_ (22) +#define PHY_DEV_ID_MODEL_MASK_ (0x0FC00000) +#define PHY_DEV_ID_OUI_MASK_ (0x003FFFFF) + +#define OTP_BASE_ADDR (0x00001000) +#define OTP_ADDR_RANGE_ (0x1FF) + +#define OTP_PWR_DN (OTP_BASE_ADDR + 4 * 0x00) +#define OTP_PWR_DN_PWRDN_N_ (0x01) + +#define OTP_ADDR1 (OTP_BASE_ADDR + 4 * 0x01) +#define OTP_ADDR1_15_11 (0x1F) + +#define OTP_ADDR2 (OTP_BASE_ADDR + 4 * 0x02) +#define OTP_ADDR2_10_3 (0xFF) + +#define OTP_ADDR3 (OTP_BASE_ADDR + 4 * 0x03) +#define OTP_ADDR3_2_0 (0x03) + +#define OTP_PRGM_DATA (OTP_BASE_ADDR + 4 * 0x04) + +#define OTP_PRGM_MODE (OTP_BASE_ADDR + 4 * 0x05) +#define OTP_PRGM_MODE_BYTE_ (0x01) + +#define OTP_RD_DATA (OTP_BASE_ADDR + 4 * 0x06) + +#define OTP_FUNC_CMD (OTP_BASE_ADDR + 4 * 0x08) +#define OTP_FUNC_CMD_RESET_ (0x04) +#define OTP_FUNC_CMD_PROGRAM_ (0x02) +#define OTP_FUNC_CMD_READ_ (0x01) + +#define OTP_TST_CMD (OTP_BASE_ADDR + 4 * 0x09) +#define OTP_TST_CMD_TEST_DEC_SEL_ (0x10) +#define OTP_TST_CMD_PRGVRFY_ (0x08) +#define OTP_TST_CMD_WRTEST_ (0x04) +#define OTP_TST_CMD_TESTDEC_ (0x02) +#define OTP_TST_CMD_BLANKCHECK_ (0x01) + +#define OTP_CMD_GO (OTP_BASE_ADDR + 4 * 0x0A) +#define OTP_CMD_GO_GO_ (0x01) + +#define OTP_PASS_FAIL (OTP_BASE_ADDR + 4 * 0x0B) +#define OTP_PASS_FAIL_PASS_ (0x02) +#define OTP_PASS_FAIL_FAIL_ (0x01) + +#define OTP_STATUS (OTP_BASE_ADDR + 4 * 0x0C) +#define OTP_STATUS_OTP_LOCK_ (0x10) +#define OTP_STATUS_WEB_ (0x08) +#define OTP_STATUS_PGMEN (0x04) +#define OTP_STATUS_CPUMPEN_ (0x02) +#define OTP_STATUS_BUSY_ (0x01) + +#define OTP_MAX_PRG (OTP_BASE_ADDR + 4 * 0x0D) +#define OTP_MAX_PRG_MAX_PROG (0x1F) + +#define OTP_INTR_STATUS (OTP_BASE_ADDR + 4 * 0x10) +#define OTP_INTR_STATUS_READY_ (0x01) + +#define OTP_INTR_MASK (OTP_BASE_ADDR + 4 * 0x11) +#define OTP_INTR_MASK_READY_ (0x01) + +#define OTP_RSTB_PW1 (OTP_BASE_ADDR + 4 * 0x14) +#define OTP_RSTB_PW2 (OTP_BASE_ADDR + 4 * 0x15) +#define OTP_PGM_PW1 (OTP_BASE_ADDR + 4 * 0x18) +#define OTP_PGM_PW2 (OTP_BASE_ADDR + 4 * 0x19) +#define OTP_READ_PW1 (OTP_BASE_ADDR + 4 * 0x1C) +#define OTP_READ_PW2 (OTP_BASE_ADDR + 4 * 0x1D) +#define OTP_TCRST (OTP_BASE_ADDR + 4 * 0x20) +#define OTP_RSRD (OTP_BASE_ADDR + 4 * 0x21) +#define OTP_TREADEN_VAL (OTP_BASE_ADDR + 4 * 0x22) +#define OTP_TDLES_VAL (OTP_BASE_ADDR + 4 * 0x23) +#define OTP_TWWL_VAL (OTP_BASE_ADDR + 4 * 0x24) +#define OTP_TDLEH_VAL (OTP_BASE_ADDR + 4 * 0x25) +#define OTP_TWPED_VAL (OTP_BASE_ADDR + 4 * 0x26) +#define OTP_TPES_VAL (OTP_BASE_ADDR + 4 * 0x27) +#define OTP_TCPS_VAL (OTP_BASE_ADDR + 4 * 0x28) +#define OTP_TCPH_VAL (OTP_BASE_ADDR + 4 * 0x29) +#define OTP_TPGMVFY_VAL (OTP_BASE_ADDR + 4 * 0x2A) +#define OTP_TPEH_VAL (OTP_BASE_ADDR + 4 * 0x2B) +#define OTP_TPGRST_VAL (OTP_BASE_ADDR + 4 * 0x2C) +#define OTP_TCLES_VAL (OTP_BASE_ADDR + 4 * 0x2D) +#define OTP_TCLEH_VAL (OTP_BASE_ADDR + 4 * 0x2E) +#define OTP_TRDES_VAL (OTP_BASE_ADDR + 4 * 0x2F) +#define OTP_TBCACC_VAL (OTP_BASE_ADDR + 4 * 0x30) +#define OTP_TAAC_VAL (OTP_BASE_ADDR + 4 * 0x31) +#define OTP_TACCT_VAL (OTP_BASE_ADDR + 4 * 0x32) +#define OTP_TRDEP_VAL (OTP_BASE_ADDR + 4 * 0x38) +#define OTP_TPGSV_VAL (OTP_BASE_ADDR + 4 * 0x39) +#define OTP_TPVSR_VAL (OTP_BASE_ADDR + 4 * 0x3A) +#define OTP_TPVHR_VAL (OTP_BASE_ADDR + 4 * 0x3B) +#define OTP_TPVSA_VAL (OTP_BASE_ADDR + 4 * 0x3C) + +#define PHY_ID1 (0x02) +#define PHY_ID2 (0x03) + +#define PHY_DEV_ID_OUI_VTSE (0x04001C) +#define PHY_DEV_ID_MODEL_VTSE_8502 (0x23) + +#define PHY_AUTONEG_ADV (0x04) +#define NWAY_AR_NEXT_PAGE_ (0x8000) +#define NWAY_AR_REMOTE_FAULT_ (0x2000) +#define NWAY_AR_ASM_DIR_ (0x0800) +#define NWAY_AR_PAUSE_ (0x0400) +#define NWAY_AR_100T4_CAPS_ (0x0200) +#define NWAY_AR_100TX_FD_CAPS_ (0x0100) +#define NWAY_AR_SELECTOR_FIELD_ (0x001F) +#define NWAY_AR_100TX_HD_CAPS_ (0x0080) +#define NWAY_AR_10T_FD_CAPS_ (0x0040) +#define NWAY_AR_10T_HD_CAPS_ (0x0020) +#define NWAY_AR_ALL_CAPS_ (NWAY_AR_10T_HD_CAPS_ | \ + NWAY_AR_10T_FD_CAPS_ | \ + NWAY_AR_100TX_HD_CAPS_ | \ + NWAY_AR_100TX_FD_CAPS_) +#define NWAY_AR_PAUSE_MASK (NWAY_AR_PAUSE_ | NWAY_AR_ASM_DIR_) + +#define PHY_LP_ABILITY (0x05) +#define NWAY_LPAR_NEXT_PAGE_ (0x8000) +#define NWAY_LPAR_ACKNOWLEDGE_ (0x4000) +#define NWAY_LPAR_REMOTE_FAULT_ (0x2000) +#define NWAY_LPAR_ASM_DIR_ (0x0800) +#define NWAY_LPAR_PAUSE_ (0x0400) +#define NWAY_LPAR_100T4_CAPS_ (0x0200) +#define NWAY_LPAR_100TX_FD_CAPS_ (0x0100) +#define NWAY_LPAR_100TX_HD_CAPS_ (0x0080) +#define NWAY_LPAR_10T_FD_CAPS_ (0x0040) +#define NWAY_LPAR_10T_HD_CAPS_ (0x0020) +#define NWAY_LPAR_SELECTOR_FIELD_ (0x001F) + +#define PHY_AUTONEG_EXP (0x06) +#define NWAY_ER_PAR_DETECT_FAULT_ (0x0010) +#define NWAY_ER_LP_NEXT_PAGE_CAPS_ (0x0008) +#define NWAY_ER_NEXT_PAGE_CAPS_ (0x0004) +#define NWAY_ER_PAGE_RXD_ (0x0002) +#define NWAY_ER_LP_NWAY_CAPS_ (0x0001) + +#define PHY_NEXT_PAGE_TX (0x07) +#define NPTX_NEXT_PAGE_ (0x8000) +#define NPTX_MSG_PAGE_ (0x2000) +#define NPTX_ACKNOWLDGE2_ (0x1000) +#define NPTX_TOGGLE_ (0x0800) +#define NPTX_MSG_CODE_FIELD_ (0x0001) + +#define PHY_LP_NEXT_PAGE (0x08) +#define LP_RNPR_NEXT_PAGE_ (0x8000) +#define LP_RNPR_ACKNOWLDGE_ (0x4000) +#define LP_RNPR_MSG_PAGE_ (0x2000) +#define LP_RNPR_ACKNOWLDGE2_ (0x1000) +#define LP_RNPR_TOGGLE_ (0x0800) +#define LP_RNPR_MSG_CODE_FIELD_ (0x0001) + +#define PHY_1000T_CTRL (0x09) +#define CR_1000T_TEST_MODE_4_ (0x8000) +#define CR_1000T_TEST_MODE_3_ (0x6000) +#define CR_1000T_TEST_MODE_2_ (0x4000) +#define CR_1000T_TEST_MODE_1_ (0x2000) +#define CR_1000T_MS_ENABLE_ (0x1000) +#define CR_1000T_MS_VALUE_ (0x0800) +#define CR_1000T_REPEATER_DTE_ (0x0400) +#define CR_1000T_FD_CAPS_ (0x0200) +#define CR_1000T_HD_CAPS_ (0x0100) +#define CR_1000T_ASYM_PAUSE_ (0x0080) +#define CR_1000T_TEST_MODE_NORMAL_ (0x0000) + +#define PHY_1000T_STATUS (0x0A) +#define SR_1000T_MS_CONFIG_FAULT_ (0x8000) +#define SR_1000T_MS_CONFIG_RES_ (0x4000) +#define SR_1000T_LOCAL_RX_STATUS_ (0x2000) +#define SR_1000T_REMOTE_RX_STATUS_ (0x1000) +#define SR_1000T_LP_FD_CAPS_ (0x0800) +#define SR_1000T_LP_HD_CAPS_ (0x0400) +#define SR_1000T_ASYM_PAUSE_DIR_ (0x0100) +#define SR_1000T_IDLE_ERROR_CNT_ (0x00FF) +#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12 +#define SR_1000T_LOCAL_RX_STATUS_SHIFT 13 +#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5 +#define FFE_IDLE_ERR_COUNT_TIMEOUT_20 20 +#define FFE_IDLE_ERR_COUNT_TIMEOUT_100 100 + +#define PHY_EXT_STATUS (0x0F) +#define IEEE_ESR_1000X_FD_CAPS_ (0x8000) +#define IEEE_ESR_1000X_HD_CAPS_ (0x4000) +#define IEEE_ESR_1000T_FD_CAPS_ (0x2000) +#define IEEE_ESR_1000T_HD_CAPS_ (0x1000) +#define PHY_TX_POLARITY_MASK_ (0x0100) +#define PHY_TX_NORMAL_POLARITY_ (0x0000) +#define AUTO_POLARITY_DISABLE_ (0x0010) + +#define PHY_MMD_CTL (0x0D) +#define PHY_MMD_CTRL_OP_MASK_ (0xC000) +#define PHY_MMD_CTRL_OP_REG_ (0x0000) +#define PHY_MMD_CTRL_OP_DNI_ (0x4000) +#define PHY_MMD_CTRL_OP_DPIRW_ (0x8000) +#define PHY_MMD_CTRL_OP_DPIWO_ (0xC000) +#define PHY_MMD_CTRL_DEV_ADDR_MASK_ (0x001F) + +#define PHY_MMD_REG_DATA (0x0E) + +/* VTSE Vendor Specific registers */ +#define PHY_VTSE_BYPASS (0x12) +#define PHY_VTSE_BYPASS_DISABLE_PAIR_SWAP_ (0x0020) + +#define PHY_VTSE_INT_MASK (0x19) +#define PHY_VTSE_INT_MASK_MDINTPIN_EN_ (0x8000) +#define PHY_VTSE_INT_MASK_SPEED_CHANGE_ (0x4000) +#define PHY_VTSE_INT_MASK_LINK_CHANGE_ (0x2000) +#define PHY_VTSE_INT_MASK_FDX_CHANGE_ (0x1000) +#define PHY_VTSE_INT_MASK_AUTONEG_ERR_ (0x0800) +#define PHY_VTSE_INT_MASK_AUTONEG_DONE_ (0x0400) +#define PHY_VTSE_INT_MASK_POE_DETECT_ (0x0200) +#define PHY_VTSE_INT_MASK_SYMBOL_ERR_ (0x0100) +#define PHY_VTSE_INT_MASK_FAST_LINK_FAIL_ (0x0080) +#define PHY_VTSE_INT_MASK_WOL_EVENT_ (0x0040) +#define PHY_VTSE_INT_MASK_EXTENDED_INT_ (0x0020) +#define PHY_VTSE_INT_MASK_RESERVED_ (0x0010) +#define PHY_VTSE_INT_MASK_FALSE_CARRIER_ (0x0008) +#define PHY_VTSE_INT_MASK_LINK_SPEED_DS_ (0x0004) +#define PHY_VTSE_INT_MASK_MASTER_SLAVE_DONE_ (0x0002) +#define PHY_VTSE_INT_MASK_RX__ER_ (0x0001) + +#define PHY_VTSE_INT_STS (0x1A) +#define PHY_VTSE_INT_STS_INT_ACTIVE_ (0x8000) +#define PHY_VTSE_INT_STS_SPEED_CHANGE_ (0x4000) +#define PHY_VTSE_INT_STS_LINK_CHANGE_ (0x2000) +#define PHY_VTSE_INT_STS_FDX_CHANGE_ (0x1000) +#define PHY_VTSE_INT_STS_AUTONEG_ERR_ (0x0800) +#define PHY_VTSE_INT_STS_AUTONEG_DONE_ (0x0400) +#define PHY_VTSE_INT_STS_POE_DETECT_ (0x0200) +#define PHY_VTSE_INT_STS_SYMBOL_ERR_ (0x0100) +#define PHY_VTSE_INT_STS_FAST_LINK_FAIL_ (0x0080) +#define PHY_VTSE_INT_STS_WOL_EVENT_ (0x0040) +#define PHY_VTSE_INT_STS_EXTENDED_INT_ (0x0020) +#define PHY_VTSE_INT_STS_RESERVED_ (0x0010) +#define PHY_VTSE_INT_STS_FALSE_CARRIER_ (0x0008) +#define PHY_VTSE_INT_STS_LINK_SPEED_DS_ (0x0004) +#define PHY_VTSE_INT_STS_MASTER_SLAVE_DONE_ (0x0002) +#define PHY_VTSE_INT_STS_RX_ER_ (0x0001) + +/* VTSE PHY registers */ +#define PHY_EXT_GPIO_PAGE (0x1F) +#define PHY_EXT_GPIO_PAGE_SPACE_0 (0x0000) +#define PHY_EXT_GPIO_PAGE_SPACE_1 (0x0001) +#define PHY_EXT_GPIO_PAGE_SPACE_2 (0x0002) + +/* Extended Register Page 1 space */ +#define PHY_EXT_MODE_CTRL (0x13) +#define PHY_EXT_MODE_CTRL_MDIX_MASK_ (0x000C) +#define PHY_EXT_MODE_CTRL_AUTO_MDIX_ (0x0000) +#define PHY_EXT_MODE_CTRL_MDI_ (0x0008) +#define PHY_EXT_MODE_CTRL_MDI_X_ (0x000C) + +#define PHY_ANA_10BASE_T_HD 0x01 +#define PHY_ANA_10BASE_T_FD 0x02 +#define PHY_ANA_100BASE_TX_HD 0x04 +#define PHY_ANA_100BASE_TX_FD 0x08 +#define PHY_ANA_1000BASE_T_FD 0x10 +#define PHY_ANA_ALL_SUPPORTED_MEDIA (PHY_ANA_10BASE_T_HD | \ + PHY_ANA_10BASE_T_FD | \ + PHY_ANA_100BASE_TX_HD | \ + PHY_ANA_100BASE_TX_FD | \ + PHY_ANA_1000BASE_T_FD) +/* PHY MMD registers */ +#define PHY_MMD_DEV_3 3 + +#define PHY_EEE_PCS_STATUS (0x1) +#define PHY_EEE_PCS_STATUS_TX_LPI_RCVD_ ((WORD)0x0800) +#define PHY_EEE_PCS_STATUS_RX_LPI_RCVD_ ((WORD)0x0400) +#define PHY_EEE_PCS_STATUS_TX_LPI_IND_ ((WORD)0x0200) +#define PHY_EEE_PCS_STATUS_RX_LPI_IND_ ((WORD)0x0100) +#define PHY_EEE_PCS_STATUS_PCS_RCV_LNK_STS_ ((WORD)0x0004) + +#define PHY_EEE_CAPABILITIES (0x14) +#define PHY_EEE_CAPABILITIES_1000BT_EEE_ ((WORD)0x0004) +#define PHY_EEE_CAPABILITIES_100BT_EEE_ ((WORD)0x0002) + +#define PHY_MMD_DEV_7 7 + +#define PHY_EEE_ADVERTISEMENT (0x3C) +#define PHY_EEE_ADVERTISEMENT_1000BT_EEE_ ((WORD)0x0004) +#define PHY_EEE_ADVERTISEMENT_100BT_EEE_ ((WORD)0x0002) + +#define PHY_EEE_LP_ADVERTISEMENT (0x3D) +#define PHY_EEE_1000BT_EEE_CAPABLE_ ((WORD)0x0004) +#define PHY_EEE_100BT_EEE_CAPABLE_ ((WORD)0x0002) +#endif /* _LAN78XX_H */ -- cgit v1.3-6-gb490 From 343d60aada5a358ca186d6e9e353230379c426d8 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Thu, 30 Jul 2015 13:34:53 -0700 Subject: ipv6: change ipv6_stub_impl.ipv6_dst_lookup to take net argument This patch adds net argument to ipv6_stub_impl.ipv6_dst_lookup for use cases where sk is not available (like mpls). sk appears to be needed to get the namespace 'net' and is optional otherwise. This patch series changes ipv6_stub_impl.ipv6_dst_lookup to take net argument. sk remains optional. All callers of ipv6_stub_impl.ipv6_dst_lookup have been modified to pass net. I have modified them to use already available 'net' in the scope of the call. I can change them to sock_net(sk) to avoid any unintended change in behaviour if sock namespace is different. They dont seem to be from code inspection. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 2 +- include/net/addrconf.h | 4 ++-- include/net/ipv6.h | 3 ++- net/ipv6/addrconf_core.c | 11 ++++++++++- net/ipv6/icmp.c | 6 +++--- net/ipv6/ip6_output.c | 12 ++++++------ net/tipc/udp_media.c | 3 ++- 7 files changed, 26 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 81f0f24b2cfb..beed5d4025a3 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2034,7 +2034,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, fl6.flowi6_mark = skb->mark; fl6.flowi6_proto = IPPROTO_UDP; - if (ipv6_stub->ipv6_dst_lookup(sk, &ndst, &fl6)) { + if (ipv6_stub->ipv6_dst_lookup(vxlan->net, sk, &ndst, &fl6)) { netdev_dbg(dev, "no route to %pI6\n", &dst->sin6.sin6_addr); dev->stats.tx_carrier_errors++; diff --git a/include/net/addrconf.h b/include/net/addrconf.h index def59d3a34d5..0c3ac5acb85f 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -158,8 +158,8 @@ struct ipv6_stub { const struct in6_addr *addr); int (*ipv6_sock_mc_drop)(struct sock *sk, int ifindex, const struct in6_addr *addr); - int (*ipv6_dst_lookup)(struct sock *sk, struct dst_entry **dst, - struct flowi6 *fl6); + int (*ipv6_dst_lookup)(struct net *net, struct sock *sk, + struct dst_entry **dst, struct flowi6 *fl6); void (*udpv6_encap_enable)(void); void (*ndisc_send_na)(struct net_device *dev, struct neighbour *neigh, const struct in6_addr *daddr, diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 7c79798bcaab..eecdfc92f807 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -813,7 +813,8 @@ static inline struct sk_buff *ip6_finish_skb(struct sock *sk) &inet6_sk(sk)->cork); } -int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6); +int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst, + struct flowi6 *fl6); struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, const struct in6_addr *final_dst); struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c index ca09bf49ac68..bfa941fc1165 100644 --- a/net/ipv6/addrconf_core.c +++ b/net/ipv6/addrconf_core.c @@ -107,7 +107,16 @@ int inet6addr_notifier_call_chain(unsigned long val, void *v) } EXPORT_SYMBOL(inet6addr_notifier_call_chain); -const struct ipv6_stub *ipv6_stub __read_mostly; +static int eafnosupport_ipv6_dst_lookup(struct net *net, struct sock *u1, + struct dst_entry **u2, + struct flowi6 *u3) +{ + return -EAFNOSUPPORT; +} + +const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) { + .ipv6_dst_lookup = eafnosupport_ipv6_dst_lookup, +}; EXPORT_SYMBOL_GPL(ipv6_stub); /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 713d7434c911..6c2b2132c8d3 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -329,7 +329,7 @@ static struct dst_entry *icmpv6_route_lookup(struct net *net, struct flowi6 fl2; int err; - err = ip6_dst_lookup(sk, &dst, fl6); + err = ip6_dst_lookup(net, sk, &dst, fl6); if (err) return ERR_PTR(err); @@ -361,7 +361,7 @@ static struct dst_entry *icmpv6_route_lookup(struct net *net, if (err) goto relookup_failed; - err = ip6_dst_lookup(sk, &dst2, &fl2); + err = ip6_dst_lookup(net, sk, &dst2, &fl2); if (err) goto relookup_failed; @@ -591,7 +591,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) else if (!fl6.flowi6_oif) fl6.flowi6_oif = np->ucast_oif; - err = ip6_dst_lookup(sk, &dst, &fl6); + err = ip6_dst_lookup(net, sk, &dst, &fl6); if (err) goto out; dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c5fc85286ef6..92b7cf0dc1f9 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -881,10 +881,9 @@ out: return dst; } -static int ip6_dst_lookup_tail(struct sock *sk, +static int ip6_dst_lookup_tail(struct net *net, struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6) { - struct net *net = sock_net(sk); #ifdef CONFIG_IPV6_OPTIMISTIC_DAD struct neighbour *n; struct rt6_info *rt; @@ -994,10 +993,11 @@ out_err_release: * * It returns zero on success, or a standard errno code on error. */ -int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6) +int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst, + struct flowi6 *fl6) { *dst = NULL; - return ip6_dst_lookup_tail(sk, dst, fl6); + return ip6_dst_lookup_tail(net, sk, dst, fl6); } EXPORT_SYMBOL_GPL(ip6_dst_lookup); @@ -1018,7 +1018,7 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, struct dst_entry *dst = NULL; int err; - err = ip6_dst_lookup_tail(sk, &dst, fl6); + err = ip6_dst_lookup_tail(sock_net(sk), sk, &dst, fl6); if (err) return ERR_PTR(err); if (final_dst) @@ -1052,7 +1052,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, dst = ip6_sk_dst_check(sk, dst, fl6); - err = ip6_dst_lookup_tail(sk, &dst, fl6); + err = ip6_dst_lookup_tail(sock_net(sk), sk, &dst, fl6); if (err) return ERR_PTR(err); if (final_dst) diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 66deebc66aa1..c170d3138953 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -194,7 +194,8 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb, .saddr = src->ipv6, .flowi6_proto = IPPROTO_UDP }; - err = ipv6_stub->ipv6_dst_lookup(ub->ubsock->sk, &ndst, &fl6); + err = ipv6_stub->ipv6_dst_lookup(net, ub->ubsock->sk, &ndst, + &fl6); if (err) goto tx_error; ttl = ip6_dst_hoplimit(ndst); -- cgit v1.3-6-gb490 From f8a9b1bc1b238eed9987da747a0e52f5bb009980 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Thu, 30 Jul 2015 20:10:22 -0700 Subject: vxlan: expose COLLECT_METADATA flag to user space Two vxlan driver flags FLOWBASED and COLLECT_METADATA need to be set to make use of its new flow mode. The former already exposed. Expose the latter. Signed-off-by: Alexei Starovoitov Acked-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 5 +++++ include/uapi/linux/if_link.h | 1 + 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index beed5d4025a3..e90f7a484e1c 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2463,6 +2463,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 }, [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 }, [IFLA_VXLAN_FLOWBASED] = { .type = NLA_U8 }, + [IFLA_VXLAN_COLLECT_METADATA] = { .type = NLA_U8 }, [IFLA_VXLAN_PORT] = { .type = NLA_U16 }, [IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 }, [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 }, @@ -2817,6 +2818,10 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, nla_get_u8(data[IFLA_VXLAN_FLOWBASED])) conf.flags |= VXLAN_F_FLOW_BASED; + if (data[IFLA_VXLAN_COLLECT_METADATA] && + nla_get_u8(data[IFLA_VXLAN_COLLECT_METADATA])) + conf.flags |= VXLAN_F_COLLECT_METADATA; + if (data[IFLA_VXLAN_PORT_RANGE]) { const struct ifla_vxlan_port_range *p = nla_data(data[IFLA_VXLAN_PORT_RANGE]); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 9eeb5d9cf8f0..24e22cd4be79 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -383,6 +383,7 @@ enum { IFLA_VXLAN_GBP, IFLA_VXLAN_REMCSUM_NOPARTIAL, IFLA_VXLAN_FLOWBASED, + IFLA_VXLAN_COLLECT_METADATA, __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) -- cgit v1.3-6-gb490 From e90fba8d9f6067cd511f7b855518eebda6bf2532 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Fri, 31 Jul 2015 11:23:39 +0800 Subject: r8152: disable the capability of zero length The UEFI driver would enable zero length, and the Linux driver doesn't need it. Zero length let the hw complete the transfer with length 0, when there is no received packet. It would add the load of USB host controller and reduce the performance. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 57b72ecb5455..348652a190af 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -339,6 +339,7 @@ /* USB_USB_CTRL */ #define RX_AGG_DISABLE 0x0010 +#define RX_ZERO_EN 0x0080 /* USB_U2P3_CTRL */ #define U2P3_ENABLE 0x0001 @@ -2705,7 +2706,7 @@ static void r8153_first_init(struct r8152 *tp) /* rx aggregation */ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); - ocp_data &= ~RX_AGG_DISABLE; + ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); } @@ -3227,7 +3228,7 @@ static void r8152b_init(struct r8152 *tp) /* enable rx aggregation */ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); - ocp_data &= ~RX_AGG_DISABLE; + ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); } -- cgit v1.3-6-gb490 From bee8259dd31f419a883174556b11edc6f9a153d1 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Fri, 31 Jul 2015 16:58:42 +0800 Subject: net: phy: add driver for aquantia phy This patch added driver to support Aquantia PHYs AQ1202, AQ2104, AQR105, AQR405, which accessed through clause 45. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 5 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/aquantia.c | 152 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 drivers/net/phy/aquantia.c (limited to 'drivers') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 8ef819144220..c07030dbe748 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -14,6 +14,11 @@ if PHYLIB comment "MII PHY device drivers" +config AQUANTIA_PHY + tristate "Drivers for the Aquantia PHYs" + ---help--- + Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 + config AT803X_PHY tristate "Drivers for Atheros AT803X PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 16aac1c3e703..9bb103358c74 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -3,6 +3,7 @@ libphy-objs := phy.o phy_device.o mdio_bus.o obj-$(CONFIG_PHYLIB) += libphy.o +obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o obj-$(CONFIG_MARVELL_PHY) += marvell.o obj-$(CONFIG_DAVICOM_PHY) += davicom.o obj-$(CONFIG_CICADA_PHY) += cicada.o diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c new file mode 100644 index 000000000000..73d347d7cb04 --- /dev/null +++ b/drivers/net/phy/aquantia.c @@ -0,0 +1,152 @@ +/* + * Driver for Aquantia PHY + * + * Author: Shaohui Xie + * + * Copyright 2015 Freescale Semiconductor, 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PHY_ID_AQ1202 0x03a1b445 +#define PHY_ID_AQ2104 0x03a1b460 +#define PHY_ID_AQR105 0x03a1b4a2 +#define PHY_ID_AQR405 0x03a1b4b0 + +#define PHY_AQUANTIA_FEATURES (SUPPORTED_10000baseT_Full | \ + SUPPORTED_1000baseT_Full | \ + SUPPORTED_100baseT_Full | \ + PHY_DEFAULT_FEATURES) + +static int aquantia_config_aneg(struct phy_device *phydev) +{ + phydev->supported = PHY_AQUANTIA_FEATURES; + phydev->advertising = phydev->supported; + + return 0; +} + +static int aquantia_aneg_done(struct phy_device *phydev) +{ + int reg; + + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + return (reg < 0) ? reg : (reg & BMSR_ANEGCOMPLETE); +} + +static int aquantia_read_status(struct phy_device *phydev) +{ + int reg; + + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + if (reg & MDIO_STAT1_LSTATUS) + phydev->link = 1; + else + phydev->link = 0; + + reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800); + mdelay(10); + reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800); + + switch (reg) { + case 0x9: + phydev->speed = SPEED_2500; + break; + case 0x5: + phydev->speed = SPEED_1000; + break; + case 0x3: + phydev->speed = SPEED_100; + break; + case 0x7: + default: + phydev->speed = SPEED_10000; + break; + } + phydev->duplex = DUPLEX_FULL; + + return 0; +} + +static struct phy_driver aquantia_driver[] = { +{ + .phy_id = PHY_ID_AQ1202, + .phy_id_mask = 0xfffffff0, + .name = "Aquantia AQ1202", + .features = PHY_AQUANTIA_FEATURES, + .aneg_done = aquantia_aneg_done, + .config_aneg = aquantia_config_aneg, + .read_status = aquantia_read_status, + .driver = { .owner = THIS_MODULE,}, +}, +{ + .phy_id = PHY_ID_AQ2104, + .phy_id_mask = 0xfffffff0, + .name = "Aquantia AQ2104", + .features = PHY_AQUANTIA_FEATURES, + .aneg_done = aquantia_aneg_done, + .config_aneg = aquantia_config_aneg, + .read_status = aquantia_read_status, + .driver = { .owner = THIS_MODULE,}, +}, +{ + .phy_id = PHY_ID_AQR105, + .phy_id_mask = 0xfffffff0, + .name = "Aquantia AQR105", + .features = PHY_AQUANTIA_FEATURES, + .aneg_done = aquantia_aneg_done, + .config_aneg = aquantia_config_aneg, + .read_status = aquantia_read_status, + .driver = { .owner = THIS_MODULE,}, +}, +{ + .phy_id = PHY_ID_AQR405, + .phy_id_mask = 0xfffffff0, + .name = "Aquantia AQR405", + .features = PHY_AQUANTIA_FEATURES, + .aneg_done = aquantia_aneg_done, + .config_aneg = aquantia_config_aneg, + .read_status = aquantia_read_status, + .driver = { .owner = THIS_MODULE,}, +}, +}; + +static int __init aquantia_init(void) +{ + return phy_drivers_register(aquantia_driver, + ARRAY_SIZE(aquantia_driver)); +} + +static void __exit aquantia_exit(void) +{ + return phy_drivers_unregister(aquantia_driver, + ARRAY_SIZE(aquantia_driver)); +} + +module_init(aquantia_init); +module_exit(aquantia_exit); + +static struct mdio_device_id __maybe_unused aquantia_tbl[] = { + { PHY_ID_AQ1202, 0xfffffff0 }, + { PHY_ID_AQ2104, 0xfffffff0 }, + { PHY_ID_AQR105, 0xfffffff0 }, + { PHY_ID_AQR405, 0xfffffff0 }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, aquantia_tbl); + +MODULE_DESCRIPTION("Aquantia PHY driver"); +MODULE_AUTHOR("Shaohui Xie "); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From 273248202013aa9d6d1bb2c1c4e4034a2813453f Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Fri, 31 Jul 2015 11:14:54 +0100 Subject: sfc: allow ethtool selftest and MC reboot to complete on an unprivileged function The policy in the net driver is to attempt MCDI commands and then handle any EPERM error codes appropriately when returned by unprivileged functions. The ethtool selftest contains some tests which are useful on an unprivileged function, such as the event queue interrupt tests, but other tests cannot be performed as the function does not have the required permissions. If a test returns -EPERM, act as though the test was not run and continue. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 8 ++++++++ drivers/net/ethernet/sfc/selftest.c | 14 +++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 8505d82290cb..7e2e206dafa3 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -1041,6 +1041,12 @@ static int efx_ef10_reset(struct efx_nic *efx, enum reset_type reset_type) { int rc = efx_mcdi_reset(efx, reset_type); + /* Unprivileged functions return -EPERM, but need to return success + * here so that the datapath is brought back up. + */ + if (reset_type == RESET_TYPE_WORLD && rc == -EPERM) + rc = 0; + /* If it was a port reset, trigger reallocation of MC resources. * Note that on an MC reset nothing needs to be done now because we'll * detect the MC reset later and handle it then. @@ -4324,6 +4330,8 @@ efx_ef10_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) rc = efx_mcdi_reset(efx, RESET_TYPE_WORLD); out: + if (rc == -EPERM) + rc = 0; rc2 = efx_reset_up(efx, RESET_TYPE_WORLD, rc == 0); return rc ? rc : rc2; } diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index b605dfd5c7bc..9d78830da609 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -114,7 +114,10 @@ static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) if (efx->type->test_nvram) { rc = efx->type->test_nvram(efx); - tests->nvram = rc ? -1 : 1; + if (rc == -EPERM) + rc = 0; + else + tests->nvram = rc ? -1 : 1; } return rc; @@ -253,6 +256,12 @@ static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, mutex_lock(&efx->mac_lock); rc = efx->phy_op->run_tests(efx, tests->phy_ext, flags); mutex_unlock(&efx->mac_lock); + if (rc == -EPERM) + rc = 0; + else + netif_info(efx, drv, efx->net_dev, + "%s phy selftest\n", rc ? "Failed" : "Passed"); + return rc; } @@ -661,6 +670,9 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, wmb(); kfree(state); + if (rc == -EPERM) + rc = 0; + return rc; } -- cgit v1.3-6-gb490 From 774ad031dd6d2ef840375a662693952b73a3ae71 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Fri, 31 Jul 2015 11:15:22 +0100 Subject: sfc: MC allocations must be restored following an entity reset Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 7e2e206dafa3..06b8061f1b42 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -991,12 +991,24 @@ static int efx_ef10_init_nic(struct efx_nic *efx) static void efx_ef10_reset_mc_allocations(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; +#ifdef CONFIG_SFC_SRIOV + unsigned int i; +#endif /* All our allocations have been reset */ nic_data->must_realloc_vis = true; nic_data->must_restore_filters = true; nic_data->must_restore_piobufs = true; nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID; + + /* Driver-created vswitches and vports must be re-created */ + nic_data->must_probe_vswitching = true; + nic_data->vport_id = EVB_PORT_ID_ASSIGNED; +#ifdef CONFIG_SFC_SRIOV + if (nic_data->vf) + for (i = 0; i < efx->vf_count; i++) + nic_data->vf[i].vport_id = 0; +#endif } static enum reset_type efx_ef10_map_reset_reason(enum reset_type reason) @@ -1571,10 +1583,6 @@ static int efx_ef10_mcdi_poll_reboot(struct efx_nic *efx) /* All our allocations have been reset */ efx_ef10_reset_mc_allocations(efx); - /* Driver-created vswitches and vports must be re-created */ - nic_data->must_probe_vswitching = true; - nic_data->vport_id = EVB_PORT_ID_ASSIGNED; - /* The datapath firmware might have been changed */ nic_data->must_check_datapath_caps = true; -- cgit v1.3-6-gb490 From 0f7bffd9e512b77279bbce704fad3cb1d6887958 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 31 Jul 2015 16:49:43 +0200 Subject: bonding: add tlb_dynamic_lb netlink support tlb_dynamic_lb could be set only via sysfs, this patch allows it to be set via netlink. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_netlink.c | 17 +++++++++++++++-- include/uapi/linux/if_link.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 1bda29249d12..db760e84119f 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -111,6 +111,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { [IFLA_BOND_AD_USER_PORT_KEY] = { .type = NLA_U16 }, [IFLA_BOND_AD_ACTOR_SYSTEM] = { .type = NLA_BINARY, .len = ETH_ALEN }, + [IFLA_BOND_TLB_DYNAMIC_LB] = { .type = NLA_U8 }, }; static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = { @@ -405,7 +406,6 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } - if (data[IFLA_BOND_AD_USER_PORT_KEY]) { int port_key = nla_get_u16(data[IFLA_BOND_AD_USER_PORT_KEY]); @@ -415,7 +415,6 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } - if (data[IFLA_BOND_AD_ACTOR_SYSTEM]) { if (nla_len(data[IFLA_BOND_AD_ACTOR_SYSTEM]) != ETH_ALEN) return -EINVAL; @@ -426,6 +425,15 @@ static int bond_changelink(struct net_device *bond_dev, if (err) return err; } + if (data[IFLA_BOND_TLB_DYNAMIC_LB]) { + int dynamic_lb = nla_get_u8(data[IFLA_BOND_TLB_DYNAMIC_LB]); + + bond_opt_initval(&newval, dynamic_lb); + err = __bond_opt_set(bond, BOND_OPT_TLB_DYNAMIC_LB, &newval); + if (err) + return err; + } + return 0; } @@ -476,6 +484,7 @@ static size_t bond_get_size(const struct net_device *bond_dev) nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_ACTOR_SYS_PRIO */ nla_total_size(sizeof(u16)) + /* IFLA_BOND_AD_USER_PORT_KEY */ nla_total_size(ETH_ALEN) + /* IFLA_BOND_AD_ACTOR_SYSTEM */ + nla_total_size(sizeof(u8)) + /* IFLA_BOND_TLB_DYNAMIC_LB */ 0; } @@ -598,6 +607,10 @@ static int bond_fill_info(struct sk_buff *skb, bond->params.ad_select)) goto nla_put_failure; + if (nla_put_u8(skb, IFLA_BOND_TLB_DYNAMIC_LB, + bond->params.tlb_dynamic_lb)) + goto nla_put_failure; + if (BOND_MODE(bond) == BOND_MODE_8023AD) { struct ad_info info; diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 24e22cd4be79..ea047480a1f0 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -434,6 +434,7 @@ enum { IFLA_BOND_AD_ACTOR_SYS_PRIO, IFLA_BOND_AD_USER_PORT_KEY, IFLA_BOND_AD_ACTOR_SYSTEM, + IFLA_BOND_TLB_DYNAMIC_LB, __IFLA_BOND_MAX, }; -- cgit v1.3-6-gb490 From 4d2e88828f25eb587b78a430e18071a5bc8d18c2 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 31 Jul 2015 11:42:54 -0700 Subject: net: bcmgenet: Add netconsole support Implement a poll controller for netconsole which invokes both of our interrupt handlers for the different RX/TX queues. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index c6f2d396edf0..eb080ef8ee97 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2388,6 +2388,23 @@ static irqreturn_t bcmgenet_wol_isr(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void bcmgenet_poll_controller(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + /* Invoke the main RX/TX interrupt handler */ + disable_irq(priv->irq0); + bcmgenet_isr0(priv->irq0, priv); + enable_irq(priv->irq0); + + /* And the interrupt handler for RX/TX priority queues */ + disable_irq(priv->irq1); + bcmgenet_isr1(priv->irq1, priv); + enable_irq(priv->irq1); +} +#endif + static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) { u32 reg; @@ -2939,6 +2956,9 @@ static const struct net_device_ops bcmgenet_netdev_ops = { .ndo_set_mac_address = bcmgenet_set_mac_addr, .ndo_do_ioctl = bcmgenet_ioctl, .ndo_set_features = bcmgenet_set_features, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = bcmgenet_poll_controller, +#endif }; /* Array of GENET hardware parameters/characteristics */ -- cgit v1.3-6-gb490 From 6cec4f5e00a34a1c7407af302470246dd4f8be28 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 31 Jul 2015 11:42:55 -0700 Subject: net: systemport: Add netconsole support Implement a poll controller for netconsole which invokes the RX interrupt handler to poll for incoming packets, and cleans up all TX queues by invoking the TX interrupt handler. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bcmsysport.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 4566cdf0bc39..b9a5a97ed4dd 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -933,6 +933,21 @@ static irqreturn_t bcm_sysport_wol_isr(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void bcm_sysport_poll_controller(struct net_device *dev) +{ + struct bcm_sysport_priv *priv = netdev_priv(dev); + + disable_irq(priv->irq0); + bcm_sysport_rx_isr(priv->irq0, priv); + enable_irq(priv->irq0); + + disable_irq(priv->irq1); + bcm_sysport_tx_isr(priv->irq1, priv); + enable_irq(priv->irq1); +} +#endif + static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb, struct net_device *dev) { @@ -1723,6 +1738,9 @@ static const struct net_device_ops bcm_sysport_netdev_ops = { .ndo_set_features = bcm_sysport_set_features, .ndo_set_rx_mode = bcm_sysport_set_rx_mode, .ndo_set_mac_address = bcm_sysport_change_mac, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = bcm_sysport_poll_controller, +#endif }; #define REV_FMT "v%2x.%02x" -- cgit v1.3-6-gb490 From 648d6e6ce4457f9558e1c9d5a8ed73e2baace312 Mon Sep 17 00:00:00 2001 From: Pan Li Date: Mon, 27 Jul 2015 13:48:10 +0800 Subject: staging: lustre: Replace spaces at the start of a line. Replace the spaces at the start of a line with tab for indent. Signed-off-by: Pan Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/cl_page.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index 282ae734fba2..4def88106d3a 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -52,12 +52,12 @@ static void cl_page_delete0(const struct lu_env *env, struct cl_page *pg, int radix); # define PASSERT(env, page, expr) \ - do { \ + do { \ if (unlikely(!(expr))) { \ CL_PAGE_DEBUG(D_ERROR, (env), (page), #expr "\n"); \ LASSERT(0); \ } \ - } while (0) + } while (0) # define PINVRNT(env, page, exp) \ ((void)sizeof(env), (void)sizeof(page), (void)sizeof !!(exp)) -- cgit v1.3-6-gb490 From b16d335ddf0b89eae6b65d7c2e0c360846fc4846 Mon Sep 17 00:00:00 2001 From: Pan Li Date: Mon, 27 Jul 2015 13:49:11 +0800 Subject: staging: lustre: Adjust code indent for macro and tail blackslash Adjust code indent for macro with tab, as well as tail blackslash. Signed-off-by: Pan Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/cl_page.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index 4def88106d3a..7c8643786205 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -51,12 +51,12 @@ static void cl_page_delete0(const struct lu_env *env, struct cl_page *pg, int radix); -# define PASSERT(env, page, expr) \ - do { \ - if (unlikely(!(expr))) { \ - CL_PAGE_DEBUG(D_ERROR, (env), (page), #expr "\n"); \ - LASSERT(0); \ - } \ +# define PASSERT(env, page, expr) \ + do { \ + if (unlikely(!(expr))) { \ + CL_PAGE_DEBUG(D_ERROR, (env), (page), #expr "\n"); \ + LASSERT(0); \ + } \ } while (0) # define PINVRNT(env, page, exp) \ -- cgit v1.3-6-gb490 From 8de056a13fcd09a85a79f52f7fe72b3fa95ccd66 Mon Sep 17 00:00:00 2001 From: Pan Li Date: Mon, 27 Jul 2015 13:50:09 +0800 Subject: staging: lustre: Add a blank line after declarations. Add a blank line after local variable declarations. Signed-off-by: Pan Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/cl_page.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index 7c8643786205..ec21f2b64d7b 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -169,6 +169,7 @@ int cl_page_gang_lookup(const struct lu_env *env, struct cl_object *obj, while ((nr = radix_tree_gang_lookup(&hdr->coh_tree, (void **)pvec, idx, CLT_PVEC_SIZE)) > 0) { int end_of_region = 0; + idx = pvec[nr - 1]->cp_index + 1; for (i = 0, j = 0; i < nr; ++i) { page = pvec[i]; @@ -286,6 +287,7 @@ static struct cl_page *cl_page_alloc(const struct lu_env *env, GFP_NOFS); if (page != NULL) { int result = 0; + atomic_set(&page->cp_ref, 1); if (type == CPT_CACHEABLE) /* for radix tree */ atomic_inc(&page->cp_ref); -- cgit v1.3-6-gb490 From 437dffebadd5cf22403505528f35b0c1b3aa34e2 Mon Sep 17 00:00:00 2001 From: Pan Li Date: Mon, 27 Jul 2015 13:50:34 +0800 Subject: staging: lustre: Remove a trailing */ of a separate line. Remove a trailing */ of a separate comments block line. Signed-off-by: Pan Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/cl_page.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index ec21f2b64d7b..1f6ca7c7978f 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -354,8 +354,10 @@ static struct cl_page *cl_page_find0(const struct lu_env *env, idx, PFID(&hdr->coh_lu.loh_fid), vmpage, vmpage->private, type); /* fast path. */ if (type == CPT_CACHEABLE) { - /* vmpage lock is used to protect the child/parent - * relationship */ + /* + * vmpage lock is used to protect the child/parent + * relationship + */ KLASSERT(PageLocked(vmpage)); /* * cl_vmpage_page() can be called here without any locks as -- cgit v1.3-6-gb490 From 585d84b4838ac061f935b5d5c84550ec9f5dee82 Mon Sep 17 00:00:00 2001 From: Pan Li Date: Mon, 27 Jul 2015 13:52:48 +0800 Subject: staging: lustre: Remove unnecessary braces {} for single statement blocks Remove unnecessary braces {} for single line statement blocks. Signed-off-by: Pan Li Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/cl_page.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index 1f6ca7c7978f..0f3417159fc1 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -376,9 +376,8 @@ static struct cl_page *cl_page_find0(const struct lu_env *env, idx) == page)); } - if (page != NULL) { + if (page != NULL) return page; - } /* allocate and initialize cl_page */ page = cl_page_alloc(env, o, idx, vmpage, type); -- cgit v1.3-6-gb490 From f926cac2f70e5dc62e9a11d8e599206c0ad357ba Mon Sep 17 00:00:00 2001 From: Mario Bambagini Date: Tue, 28 Jul 2015 22:08:48 +0200 Subject: staging: lustre: fixed lines longer than 80 chars this set of patches fixes several code style problems: -patch 1: lines with more than 80 chars -patch 2: comments without */ on a separate line -patch 3: bad alignment of lines split on more than one line -patch 4: modified comparisons against NULL -patch 5: added spaces between concatenated strings This patch fixes 2 lines longer than 80 chars The first one is a function whose argument has been moved to next line. The second one is a comment split on two lines Signed-off-by: Mario Bambagini Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/llite/llite_capa.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/llite/llite_capa.c b/drivers/staging/lustre/lustre/llite/llite_capa.c index a6268718b76e..9c9e48285b6a 100644 --- a/drivers/staging/lustre/lustre/llite/llite_capa.c +++ b/drivers/staging/lustre/lustre/llite/llite_capa.c @@ -70,7 +70,8 @@ static unsigned long long ll_capa_renewal_retries; static int ll_update_capa(struct obd_capa *ocapa, struct lustre_capa *capa); -static inline void update_capa_timer(struct obd_capa *ocapa, unsigned long expiry) +static inline void update_capa_timer(struct obd_capa *ocapa, + unsigned long expiry) { if (time_before(expiry, ll_capa_timer.expires) || !timer_pending(&ll_capa_timer)) { @@ -165,7 +166,8 @@ static void ll_delete_capa(struct obd_capa *ocapa) /* three places where client capa is deleted: * 1. capa_thread_main(), main place to delete expired capa. * 2. ll_clear_inode_capas() in ll_clear_inode(). - * 3. ll_truncate_free_capa() delete truncate capa explicitly in ll_setattr_ost(). + * 3. ll_truncate_free_capa() delete truncate capa explicitly in + * ll_setattr_ost(). */ static int capa_thread_main(void *unused) { -- cgit v1.3-6-gb490 From e28e92b6d18199ad304f076fb24293d8c384cf1b Mon Sep 17 00:00:00 2001 From: Mario Bambagini Date: Tue, 28 Jul 2015 22:08:49 +0200 Subject: staging: lustre: fixed comments without */ on a new line This patch fixes 4 comments without */ on a new line Signed-off-by: Mario Bambagini Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/llite/llite_capa.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/llite/llite_capa.c b/drivers/staging/lustre/lustre/llite/llite_capa.c index 9c9e48285b6a..4432a64447bb 100644 --- a/drivers/staging/lustre/lustre/llite/llite_capa.c +++ b/drivers/staging/lustre/lustre/llite/llite_capa.c @@ -208,7 +208,8 @@ static int capa_thread_main(void *unused) * lock. */ /* ibits may be changed by ll_have_md_lock() so we have - * to set it each time */ + * to set it each time + */ ibits = MDS_INODELOCK_LOOKUP; if (capa_for_mds(&ocapa->c_capa) && !S_ISDIR(ocapa->u.cli.inode->i_mode) && @@ -227,7 +228,8 @@ static int capa_thread_main(void *unused) if (capa_for_oss(&ocapa->c_capa) && obd_capa_open_count(ocapa) == 0) { /* oss capa with open count == 0 won't renew, - * move to idle list */ + * move to idle list + */ sort_add_capa(ocapa, &ll_idle_capas); continue; } @@ -449,7 +451,8 @@ static inline void inode_add_oss_capa(struct inode *inode, struct list_head *next = NULL; /* capa is sorted in lli_oss_capas so lookup can always find the - * latest one */ + * latest one + */ list_for_each_entry(tmp, &lli->lli_oss_capas, u.cli.lli_list) { if (cfs_time_after(ocapa->c_expiry, tmp->c_expiry)) { next = &tmp->u.cli.lli_list; @@ -539,7 +542,8 @@ static int ll_update_capa(struct obd_capa *ocapa, struct lustre_capa *capa) ll_capa_renewal_failed++; /* failed capa won't be renewed any longer, but if -EIO, - * client might be doing recovery, retry in 2 min. */ + * client might be doing recovery, retry in 2 min. + */ if (rc == -EIO && !capa_is_expired(ocapa)) { delay_capa_renew(ocapa, 120); DEBUG_CAPA(D_ERROR, &ocapa->c_capa, -- cgit v1.3-6-gb490 From 6b0e2d6232e9a0b98d39647f3cc6ff5fd8f1cd92 Mon Sep 17 00:00:00 2001 From: Mario Bambagini Date: Tue, 28 Jul 2015 22:08:50 +0200 Subject: staging: lustre: fixed bad alignment This patch fixes 7 bad alignments. When a line is split on more than one line, the other lines must be aligned with paranthesis. Signed-off-by: Mario Bambagini Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/llite/llite_capa.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/llite/llite_capa.c b/drivers/staging/lustre/lustre/llite/llite_capa.c index 4432a64447bb..a3b3c46e08a3 100644 --- a/drivers/staging/lustre/lustre/llite/llite_capa.c +++ b/drivers/staging/lustre/lustre/llite/llite_capa.c @@ -103,13 +103,13 @@ static inline int have_expired_capa(void) spin_lock(&capa_lock); if (!list_empty(ll_capa_list)) { ocapa = list_entry(ll_capa_list->next, struct obd_capa, - c_list); + c_list); expired = capa_is_to_expire(ocapa); if (!expired) update_capa_timer(ocapa, capa_renewal_time(ocapa)); } else if (!list_empty(&ll_idle_capas)) { ocapa = list_entry(ll_idle_capas.next, struct obd_capa, - c_list); + c_list); expired = capa_is_expired(ocapa); if (!expired) update_capa_timer(ocapa, ocapa->c_expiry); @@ -259,7 +259,7 @@ static int capa_thread_main(void *unused) update_capa_timer(next, capa_renewal_time(next)); list_for_each_entry_safe(ocapa, tmp, &ll_idle_capas, - c_list) { + c_list) { if (!capa_is_expired(ocapa)) { if (!next) update_capa_timer(ocapa, @@ -303,11 +303,11 @@ int ll_capa_thread_start(void) task = kthread_run(capa_thread_main, NULL, "ll_capa"); if (IS_ERR(task)) { CERROR("cannot start expired capa thread: rc %ld\n", - PTR_ERR(task)); + PTR_ERR(task)); return PTR_ERR(task); } wait_event(ll_capa_thread.t_ctl_waitq, - thread_is_running(&ll_capa_thread)); + thread_is_running(&ll_capa_thread)); return 0; } @@ -317,7 +317,7 @@ void ll_capa_thread_stop(void) thread_set_flags(&ll_capa_thread, SVC_STOPPING); wake_up(&ll_capa_thread.t_ctl_waitq); wait_event(ll_capa_thread.t_ctl_waitq, - thread_is_stopped(&ll_capa_thread)); + thread_is_stopped(&ll_capa_thread)); } struct obd_capa *ll_osscapa_get(struct inode *inode, __u64 opc) @@ -644,7 +644,7 @@ void ll_clear_inode_capas(struct inode *inode) ll_delete_capa(ocapa); list_for_each_entry_safe(ocapa, tmp, &lli->lli_oss_capas, - u.cli.lli_list) + u.cli.lli_list) ll_delete_capa(ocapa); spin_unlock(&capa_lock); } -- cgit v1.3-6-gb490 From 911677393b13a3f2fc6db2e297b336fb2669f0f1 Mon Sep 17 00:00:00 2001 From: Mario Bambagini Date: Tue, 28 Jul 2015 22:08:51 +0200 Subject: staging: lustre: modified comparisons against NULL The explicit comparisons against NULL has been modified to be shorter. Signed-off-by: Mario Bambagini Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/llite/llite_capa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/llite/llite_capa.c b/drivers/staging/lustre/lustre/llite/llite_capa.c index a3b3c46e08a3..7768c6d8d1a8 100644 --- a/drivers/staging/lustre/lustre/llite/llite_capa.c +++ b/drivers/staging/lustre/lustre/llite/llite_capa.c @@ -236,7 +236,7 @@ static int capa_thread_main(void *unused) /* NB iput() is in ll_update_capa() */ inode = igrab(ocapa->u.cli.inode); - if (inode == NULL) { + if (!inode) { DEBUG_CAPA(D_ERROR, &ocapa->c_capa, "igrab failed for"); continue; @@ -380,7 +380,7 @@ struct obd_capa *ll_mdscapa_get(struct inode *inode) struct ll_inode_info *lli = ll_i2info(inode); struct obd_capa *ocapa; - LASSERT(inode != NULL); + LASSERT(inode); if ((ll_i2sbi(inode)->ll_flags & LL_SBI_MDS_CAPA) == 0) return NULL; -- cgit v1.3-6-gb490 From 01eb73d53070ca2c7a75c272291a79613604cd97 Mon Sep 17 00:00:00 2001 From: Mario Bambagini Date: Tue, 28 Jul 2015 22:08:52 +0200 Subject: staging: lustre: added a space between concatenated strings A space has been inserted between two concatenated strings as required from checkpatch.pl These two updates do not lead to any problem as DFID is defined as a string in ./drivers/staging/lustre/lustre/include/lustre/lustre_user.h The script checkpatch.pl does not return any other warning/error. Signed-off-by: Mario Bambagini Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/llite/llite_capa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/llite/llite_capa.c b/drivers/staging/lustre/lustre/llite/llite_capa.c index 7768c6d8d1a8..24590ae36090 100644 --- a/drivers/staging/lustre/lustre/llite/llite_capa.c +++ b/drivers/staging/lustre/lustre/llite/llite_capa.c @@ -364,7 +364,7 @@ struct obd_capa *ll_osscapa_get(struct inode *inode, __u64 opc) ocapa = NULL; if (atomic_read(&ll_capa_debug)) { - CERROR("no capability for "DFID" opc %#llx\n", + CERROR("no capability for " DFID " opc %#llx\n", PFID(&lli->lli_fid), opc); atomic_set(&ll_capa_debug, 0); } @@ -389,7 +389,7 @@ struct obd_capa *ll_mdscapa_get(struct inode *inode) ocapa = capa_get(lli->lli_mds_capa); spin_unlock(&capa_lock); if (!ocapa && atomic_read(&ll_capa_debug)) { - CERROR("no mds capability for "DFID"\n", PFID(&lli->lli_fid)); + CERROR("no mds capability for " DFID "\n", PFID(&lli->lli_fid)); atomic_set(&ll_capa_debug, 0); } -- cgit v1.3-6-gb490 From 0d749519f0441144f7da53e157d11f0680c15313 Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Mon, 27 Jul 2015 22:20:35 +0530 Subject: Staging: lustre: Drop unnecessary cast This patch does away with the cast on void * as it is unnecessary. Semantic patch used is as follows: @r@ expression x; void* e; type T; identifier f; @@ ( *((T *)e) | ((T *)x)[...] | ((T *)x)->f | - (T *) e ) Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c index aa3fffed1519..fbbc8a7e308d 100644 --- a/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c +++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-crypto.c @@ -114,7 +114,7 @@ int cfs_crypto_hash_digest(unsigned char alg_id, crypto_free_hash(hdesc.tfm); return -ENOSPC; } - sg_init_one(&sl, (void *)buf, buf_len); + sg_init_one(&sl, buf, buf_len); hdesc.flags = 0; err = crypto_hash_digest(&hdesc, &sl, sl.length, hash); @@ -165,7 +165,7 @@ int cfs_crypto_hash_update(struct cfs_crypto_hash_desc *hdesc, { struct scatterlist sl; - sg_init_one(&sl, (void *)buf, buf_len); + sg_init_one(&sl, buf, buf_len); return crypto_hash_update((struct hash_desc *)hdesc, &sl, sl.length); } -- cgit v1.3-6-gb490 From b921ecea84a3f137f7c585af079f86922aa15aa4 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Thu, 30 Jul 2015 18:27:52 -0400 Subject: staging/lustre: Remove unused ll_vfs_* compat defines Lustre defines quite a bit of those compatibility defines duplicating kernel vfs api, but they are not actually used in the client so remove them all and also ll_dirty_inode, ll_security_inode_unlink and cfs_path_put Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- .../lustre/lustre/include/linux/lustre_compat25.h | 25 ---------------------- 1 file changed, 25 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 513c81f43d6e..622bc933122f 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -74,22 +74,9 @@ #define FS_HAS_FIEMAP (0) #endif -#define ll_vfs_rmdir(dir, entry, mnt) vfs_rmdir(dir, entry) -#define ll_vfs_mkdir(inode, dir, mnt, mode) vfs_mkdir(inode, dir, mode) -#define ll_vfs_link(old, mnt, dir, new, mnt1) vfs_link(old, dir, new) -#define ll_vfs_unlink(inode, entry, mnt) vfs_unlink(inode, entry) -#define ll_vfs_mknod(dir, entry, mnt, mode, dev) \ - vfs_mknod(dir, entry, mode, dev) -#define ll_security_inode_unlink(dir, entry, mnt) \ - security_inode_unlink(dir, entry) -#define ll_vfs_rename(old, old_dir, mnt, new, new_dir, mnt1) \ - vfs_rename(old, old_dir, new, new_dir, NULL, 0) - #define cfs_bio_io_error(a, b) bio_io_error((a)) #define cfs_bio_endio(a, b, c) bio_endio((a), (c)) -#define cfs_path_put(nd) path_put(&(nd)->path) - #ifndef SLAB_DESTROY_BY_RCU #define SLAB_DESTROY_BY_RCU 0 @@ -127,14 +114,6 @@ static inline int ll_quota_off(struct super_block *sb, int off, int remount) } -# define ll_vfs_dq_init dquot_initialize -# define ll_vfs_dq_drop dquot_drop -# define ll_vfs_dq_transfer dquot_transfer -# define ll_vfs_dq_off(sb, remount) dquot_suspend(sb, -1) - - - - #define queue_max_phys_segments(rq) queue_max_segments(rq) #define queue_max_hw_segments(rq) queue_max_segments(rq) @@ -194,8 +173,4 @@ static inline int ll_quota_off(struct super_block *sb, int off, int remount) # define ll_umode_t umode_t -#include - -# define ll_dirty_inode(inode, flag) (inode)->i_sb->s_op->dirty_inode((inode), flag) - #endif /* _COMPAT25_H */ -- cgit v1.3-6-gb490 From 5109ea606f9d9d26d2d69a0457d17267b8bfd629 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Thu, 30 Jul 2015 18:27:53 -0400 Subject: staging/lustre: get rid of cfs_bio_* compat macroses This replaces cfs_bio_io_error with direct calls to bio_io_error and cfs_bio_end_io with bio_end_io Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 4 ---- drivers/staging/lustre/lustre/llite/lloop.c | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 622bc933122f..e7d57e8b0a4b 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -74,10 +74,6 @@ #define FS_HAS_FIEMAP (0) #endif -#define cfs_bio_io_error(a, b) bio_io_error((a)) -#define cfs_bio_endio(a, b, c) bio_endio((a), (c)) - - #ifndef SLAB_DESTROY_BY_RCU #define SLAB_DESTROY_BY_RCU 0 #endif diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c index cc00fd10fbcf..56938d2446bf 100644 --- a/drivers/staging/lustre/lustre/llite/lloop.c +++ b/drivers/staging/lustre/lustre/llite/lloop.c @@ -365,7 +365,7 @@ static void loop_make_request(struct request_queue *q, struct bio *old_bio) loop_add_bio(lo, old_bio); return; err: - cfs_bio_io_error(old_bio, old_bio->bi_iter.bi_size); + bio_io_error(old_bio); } @@ -376,7 +376,7 @@ static inline void loop_handle_bio(struct lloop_device *lo, struct bio *bio) while (bio) { struct bio *tmp = bio->bi_next; bio->bi_next = NULL; - cfs_bio_endio(bio, bio->bi_iter.bi_size, ret); + bio_endio(bio, ret); bio = tmp; } } -- cgit v1.3-6-gb490 From 5c8eae72ff46f0e70d03ae2e86e631d7a1ca4fe6 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Thu, 30 Jul 2015 18:27:54 -0400 Subject: staging/lustre: Drop FS_HAS_FIEMAP compat macro FS_HAS_FIEMAP was some sort of old RHEL5 construct that's not really important anymore Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 5 ----- drivers/staging/lustre/lustre/obdclass/obd_mount.c | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index e7d57e8b0a4b..1a6b2fb5da86 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -69,11 +69,6 @@ # define inode_dio_read(i) atomic_inc(&(i)->i_dio_count) /* inode_dio_done(i) use as-is for read unlock */ - -#ifndef FS_HAS_FIEMAP -#define FS_HAS_FIEMAP (0) -#endif - #ifndef SLAB_DESTROY_BY_RCU #define SLAB_DESTROY_BY_RCU 0 #endif diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c index 3e0b8a4b6486..40ab7b272d03 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c @@ -1281,7 +1281,7 @@ struct file_system_type lustre_fs_type = { .mount = lustre_mount, .kill_sb = lustre_kill_super, .fs_flags = FS_BINARY_MOUNTDATA | FS_REQUIRES_DEV | - FS_HAS_FIEMAP | FS_RENAME_DOES_D_MOVE, + FS_RENAME_DOES_D_MOVE, }; MODULE_ALIAS_FS("lustre"); -- cgit v1.3-6-gb490 From 629819c7dedbbd6f38c075bb8aba1fe554be4cdb Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Thu, 30 Jul 2015 18:27:55 -0400 Subject: staging/lustre: Drop SLAB_DESTROY_BY_RCU redefine, it's always defined SLAB_DESTROY_BY_RCU is always defined in kernel slab.h, so no point in checking for it. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 1a6b2fb5da86..38eda2391182 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -69,12 +69,6 @@ # define inode_dio_read(i) atomic_inc(&(i)->i_dio_count) /* inode_dio_done(i) use as-is for read unlock */ -#ifndef SLAB_DESTROY_BY_RCU -#define SLAB_DESTROY_BY_RCU 0 -#endif - - - static inline int ll_quota_on(struct super_block *sb, int off, int ver, char *name, int remount) { -- cgit v1.3-6-gb490 From 6e74468da6965ca473a46a83f88e89c88d9811cc Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Thu, 30 Jul 2015 18:27:56 -0400 Subject: staging/lustre: remove *hw_segments compat defines queue_max_phys_segments, queue_max_hw_segments and bio_hw_segments are not used anywhere in the client code, so remove them Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 38eda2391182..d0e8f3c813a1 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -100,10 +100,6 @@ static inline int ll_quota_off(struct super_block *sb, int off, int remount) -#define queue_max_phys_segments(rq) queue_max_segments(rq) -#define queue_max_hw_segments(rq) queue_max_segments(rq) - - #define ll_d_hlist_node hlist_node #define ll_d_hlist_empty(list) hlist_empty(list) #define ll_d_hlist_entry(ptr, type, name) hlist_entry(ptr.first, type, name) @@ -112,8 +108,6 @@ static inline int ll_quota_off(struct super_block *sb, int off, int remount) p = NULL; hlist_for_each_entry(dentry, i_dentry, alias) -#define bio_hw_segments(q, bio) 0 - #define ll_pagevec_init(pv, cold) do {} while (0) #define ll_pagevec_add(pv, pg) (0) -- cgit v1.3-6-gb490 From e3befdc7579eee51407ad162a5614ba30c97a405 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Thu, 30 Jul 2015 18:27:59 -0400 Subject: staging/lustre: replace ll_umode_t with umode_t umode_t is what we need anyway, so replace all users and drop the define. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 6 ------ drivers/staging/lustre/lustre/llite/namei.c | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index d0e8f3c813a1..1dcd78b9c5e5 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -146,10 +146,4 @@ static inline int ll_quota_off(struct super_block *sb, int off, int remount) # define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET) #endif - -#include -#include - -# define ll_umode_t umode_t - #endif /* _COMPAT25_H */ diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 72ce6e72845f..2ed1e0ac5553 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -1008,7 +1008,7 @@ static int ll_unlink(struct inode *dir, struct dentry *dentry) return rc; } -static int ll_mkdir(struct inode *dir, struct dentry *dentry, ll_umode_t mode) +static int ll_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int err; -- cgit v1.3-6-gb490 From b81f9b6db644c2ca0fbce1ac2eda8e74860e8c63 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Thu, 30 Jul 2015 18:28:02 -0400 Subject: staging/lustre: ATTR_TIMES_SET is always defined, so don't check it Remove ATTR_TIMES_SET check as it's always present, move the mask of times define close to where it's used. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 6 ------ drivers/staging/lustre/lustre/llite/llite_lib.c | 2 ++ 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 1dcd78b9c5e5..f16ba9c8b214 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -140,10 +140,4 @@ static inline int ll_quota_off(struct super_block *sb, int off, int remount) # define ext2_find_next_zero_bit find_next_zero_bit_le #endif -#ifdef ATTR_TIMES_SET -# define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) -#else -# define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET) -#endif - #endif /* _COMPAT25_H */ diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index ab4839cad939..39f0b2a07aec 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -1150,6 +1150,8 @@ void ll_clear_inode(struct inode *inode) lli->lli_has_smd = false; } +#define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) + static int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data, struct md_open_data **mod) { -- cgit v1.3-6-gb490 From e56e17ea935a66fe3a6cd2445649a0d9365a8449 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Thu, 30 Jul 2015 18:28:04 -0400 Subject: staging/lustre: use ATTR_OPEN directly, remove ATTR_RAW ATTR_RAW is unused. No point in redefining ATTR_OPEN as ATTR_FROM_OPEN Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- .../lustre/lustre/include/linux/lustre_patchless_compat.h | 12 ------------ drivers/staging/lustre/lustre/mdc/mdc_lib.c | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h b/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h index 14562788e4e0..ebe8d68ed813 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h @@ -60,18 +60,6 @@ truncate_complete_page(struct address_space *mapping, struct page *page) ll_delete_from_page_cache(page); } -#ifdef ATTR_OPEN -# define ATTR_FROM_OPEN ATTR_OPEN -#else -# ifndef ATTR_FROM_OPEN -# define ATTR_FROM_OPEN 0 -# endif -#endif /* ATTR_OPEN */ - -#ifndef ATTR_RAW -#define ATTR_RAW 0 -#endif - #ifndef ATTR_CTIME_SET /* * set ATTR_CTIME_SET to a high value to avoid any risk of collision with other diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c index d3234cb1ea22..1a850ea26849 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c @@ -286,7 +286,7 @@ static inline __u64 attr_pack(unsigned int ia_valid) sa_valid |= MDS_ATTR_KILL_SGID; if (ia_valid & ATTR_CTIME_SET) sa_valid |= MDS_ATTR_CTIME_SET; - if (ia_valid & ATTR_FROM_OPEN) + if (ia_valid & ATTR_OPEN) sa_valid |= MDS_ATTR_FROM_OPEN; if (ia_valid & ATTR_BLOCKS) sa_valid |= MDS_ATTR_BLOCKS; -- cgit v1.3-6-gb490 From 208bf77049a95cd023c8e884a28449a9182f1c1a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 31 Jul 2015 16:32:43 +0530 Subject: staging: lustre: drop redundant check There is no need to verify that its an error, as we are anyway going to match the error value to -ENOENT. Drop the redundant check. Reported-by: "Kirill A. Shutemov" Signed-off-by: Viresh Kumar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/lu_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c index 4d9b6333eeae..9469a250d8dc 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c @@ -674,7 +674,7 @@ static struct lu_object *lu_object_find_try(const struct lu_env *env, cfs_hash_bd_lock(hs, &bd, 1); shadow = htable_lookup(s, &bd, f, waiter, &version); - if (likely(IS_ERR(shadow) && PTR_ERR(shadow) == -ENOENT)) { + if (likely(PTR_ERR(shadow) == -ENOENT)) { struct lu_site_bkt_data *bkt; bkt = cfs_hash_bd_extra_get(hs, &bd); -- cgit v1.3-6-gb490 From 176d1b96436dee996f5bd7b36429e6068a848478 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Thu, 30 Jul 2015 18:49:55 -0400 Subject: staging/lustre/llite: Don't set page writeback on non-dirty page New writeback changes in 4.2-RC1 have exposed that we incorrectly set page_writeback on a page that is being written synchronously, which aside from this new crash (dereference of NULL inode->i_wb from set_page_writeback) likely threw off some related page statistics in the past. BUG: unable to handle kernel NULL pointer dereference at 0000000000000138 IP: [] __percpu_counter_add+0x1a/0x80 PGD 0 Oops: 0000 [#1] SMP DEBUG_PAGEALLOC Modules linked in: osc(C) lmv(C) fld(C) mgc(C) lustre(C) mdc(C) fid(C) lov(C) ksocklnd(C) ptlrpc(C) obdclass(C) lnet(C) libcfs(C) loop sha512_generic crc32 rpcsec_gss_krb5 microcode joydev i2c_piix4 acpi_cpufreq pcspkr nfsd syscopyarea sysfillrect sysimgblt drm_kms_helper ttm drm serio_raw virtio_blk [last unloaded: libcfs] CPU: 0 PID: 13328 Comm: cvs Tainted: G C 4.2.0-rc1-vm-nfs+ #30 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 task: ffff8800cc98a400 ti: ffff8801157e8000 task.ti: ffff8801157e8000 RIP: 0010:[] [] __percpu_counter_add+0x1a/0x80 RSP: 0018:ffff8801157eb698 EFLAGS: 00010086 RAX: 0000000000000003 RBX: ffffea0002b91cc0 RCX: 000000000000001a RDX: 0000000000000020 RSI: 0000000000000001 RDI: 00000000000000e8 RBP: ffff8801157eb6b8 R08: 0000000000000001 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 00000000000000e8 R13: 0000000000000001 R14: ffff8800673587a8 R15: ffff8800673589b0 FS: 00007f6718b89800(0000) GS:ffff88011f400000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000138 CR3: 000000009d51c000 CR4: 00000000000007f0 Stack: ffffffff811919e2 ffffea0002b91cc0 ffff880067358998 ffff880119419800 ffff8801157eb718 ffffffff81191a58 ffff8801157eb788 0000000000000282 ffff8800ce5ce920 0000000000000000 ffff8800a525af80 ffff880053f68f10 Call Trace: [] ? __test_set_page_writeback+0x72/0x240 [] __test_set_page_writeback+0xe8/0x240 [] vvp_page_prep_write+0x33/0xb0 [lustre] [] cl_page_invoke+0x57/0x90 [obdclass] [] cl_page_prep+0x2d/0x180 [obdclass] [] osc_io_submit+0x134/0x4a0 [osc] [] cl_io_submit_rw+0x53/0xb0 [obdclass] [] lov_io_submit+0x3a5/0x570 [lov] [] ? lockdep_init_map+0x5b/0x6d0 [] cl_io_submit_rw+0x53/0xb0 [obdclass] [] cl_io_submit_sync+0xed/0x1c0 [obdclass] [] vvp_page_sync_io.isra.15+0x4d/0x100 [lustre] [] ? cl_page_clip+0xff/0x130 [obdclass] [] vvp_io_commit_write+0x448/0x500 [lustre] [] cl_io_commit_write+0x9a/0x130 [obdclass] [] ll_commit_write+0xc2/0x230 [lustre] [] ll_write_end+0x2a/0x50 [lustre] [] generic_perform_write+0xfa/0x1b0 [] ? dentry_needs_remove_privs.part.16+0x1e/0x30 [] __generic_file_write_iter+0x190/0x1f0 [] generic_file_write_iter+0xea/0x1e0 [] vvp_io_write_start+0xa0/0x1e0 [lustre] [] cl_io_start+0x49/0x80 [obdclass] [] cl_io_loop+0x73/0xd0 [obdclass] [] ll_file_io_generic+0x45f/0x4b0 [lustre] [] ll_file_write_iter+0x6c/0xc0 [lustre] [] __vfs_write+0xaa/0xe0 [] vfs_write+0xa9/0x190 [] SyS_write+0x49/0xa0 [] entry_SYSCALL_64_fastpath+0x16/0x7a Code: 5b 41 5c 41 5d 41 5e 5d c3 0f 1f 84 00 00 00 00 00 55 48 89 e5 41 55 41 54 53 49 89 fc 49 89 f5 48 83 ec 08 65 ff 05 8e d1 bf 7e <48> 8b 47 50 48 63 ca 65 8b 18 48 63 db 48 01 f3 48 39 cb 7d 0a Signed-off-by: Jinshan Xiong Signed-off-by: Oleg Drokin Reviewed-on: http://review.whamcloud.com/15610 Intel-bug-id: https://jira.hpdd.intel.com/browse/LU-6854 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/llite/vvp_page.c | 27 +++++++++++++++--------- drivers/staging/lustre/lustre/obdclass/cl_page.c | 3 --- 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/llite/vvp_page.c b/drivers/staging/lustre/lustre/llite/vvp_page.c index 954ed08c6af2..a3cf5ad20c60 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_page.c +++ b/drivers/staging/lustre/lustre/llite/vvp_page.c @@ -227,11 +227,16 @@ static int vvp_page_prep_write(const struct lu_env *env, struct cl_io *unused) { struct page *vmpage = cl2vm_page(slice); + struct cl_page *pg = slice->cpl_page; LASSERT(PageLocked(vmpage)); LASSERT(!PageDirty(vmpage)); - set_page_writeback(vmpage); + /* ll_writepage path is not a sync write, so need to set page writeback + * flag */ + if (!pg->cp_sync_io) + set_page_writeback(vmpage); + vvp_write_pending(cl2ccc(slice->cpl_obj), cl2ccc_page(slice)); return 0; @@ -298,9 +303,6 @@ static void vvp_page_completion_write(const struct lu_env *env, struct cl_page *pg = slice->cpl_page; struct page *vmpage = cp->cpg_page; - LASSERT(ergo(pg->cp_sync_io != NULL, PageLocked(vmpage))); - LASSERT(PageWriteback(vmpage)); - CL_PAGE_HEADER(D_PAGE, env, pg, "completing WRITE with %d\n", ioret); /* @@ -316,14 +318,19 @@ static void vvp_page_completion_write(const struct lu_env *env, cp->cpg_write_queued = 0; vvp_write_complete(cl2ccc(slice->cpl_obj), cp); - /* - * Only mark the page error only when it's an async write because - * applications won't wait for IO to finish. - */ - if (pg->cp_sync_io == NULL) + if (pg->cp_sync_io != NULL) { + LASSERT(PageLocked(vmpage)); + LASSERT(!PageWriteback(vmpage)); + } else { + LASSERT(PageWriteback(vmpage)); + /* + * Only mark the page error only when it's an async write + * because applications won't wait for IO to finish. + */ vvp_vmpage_error(ccc_object_inode(pg->cp_obj), vmpage, ioret); - end_page_writeback(vmpage); + end_page_writeback(vmpage); + } } /** diff --git a/drivers/staging/lustre/lustre/obdclass/cl_page.c b/drivers/staging/lustre/lustre/obdclass/cl_page.c index 0f3417159fc1..d5fb81f84cd4 100644 --- a/drivers/staging/lustre/lustre/obdclass/cl_page.c +++ b/drivers/staging/lustre/lustre/obdclass/cl_page.c @@ -1192,9 +1192,6 @@ int cl_page_prep(const struct lu_env *env, struct cl_io *io, if (result == 0) cl_page_io_start(env, pg, crt); - KLASSERT(ergo(crt == CRT_WRITE && pg->cp_type == CPT_CACHEABLE, - equi(result == 0, - PageWriteback(cl_page_vmpage(env, pg))))); CL_PAGE_HEADER(D_TRACE, env, pg, "%d %d\n", crt, result); return result; } -- cgit v1.3-6-gb490 From be3d2e0fe154f9da9098d59477ef08230a533426 Mon Sep 17 00:00:00 2001 From: Dave Perez Date: Wed, 29 Jul 2015 21:50:30 -0400 Subject: Staging: rtl8188eu: fixed newlines after declarations This is a patch to the rtw_debug.c file that fixes styling errors relating to new lines after variable declarations. Signed-off-by: Dave Perez Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_debug.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_debug.c b/drivers/staging/rtl8188eu/core/rtw_debug.c index bc3fe10ff247..12beab046a4a 100644 --- a/drivers/staging/rtl8188eu/core/rtw_debug.c +++ b/drivers/staging/rtl8188eu/core/rtw_debug.c @@ -219,6 +219,7 @@ int proc_get_ht_option(char *page, char **start, struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); int len = 0; + len += snprintf(page + len, count - len, "ht_option=%d\n", pmlmepriv->htpriv.ht_option); *eof = 1; return len; @@ -588,6 +589,7 @@ int proc_set_rx_signal(struct file *file, const char __user *buffer, if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) { int num = sscanf(tmp, "%u %u", &is_signal_dbg, &signal_strength); + is_signal_dbg = is_signal_dbg == 0 ? 0 : 1; if (is_signal_dbg && num != 2) return count; -- cgit v1.3-6-gb490 From 35cf0b5596c6936588726bd9fbc9789cac371561 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Wed, 29 Jul 2015 10:15:15 +0200 Subject: staging: rtl8188eu: don't duplicate ieee80211 WLAN_EID_* constants linux/ieee80211.h already defines constants for information element IDs. Resolve discrepancies in naming and remove the duplicated definitions. Signed-off-by: Jakub Sitnicki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_ieee80211.c | 2 +- drivers/staging/rtl8188eu/include/ieee80211.h | 38 -------------------------- drivers/staging/rtl8188eu/os_dep/ioctl_linux.c | 2 +- 3 files changed, 2 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c index d43e8672d86e..c3c582881a09 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8188eu/core/rtw_ieee80211.c @@ -1044,7 +1044,7 @@ enum parse_res rtw_ieee802_11_parse_elems(u8 *start, uint len, elems->timeout_int = pos; elems->timeout_int_len = elen; break; - case WLAN_EID_HT_CAP: + case WLAN_EID_HT_CAPABILITY: elems->ht_capabilities = pos; elems->ht_capabilities_len = elen; break; diff --git a/drivers/staging/rtl8188eu/include/ieee80211.h b/drivers/staging/rtl8188eu/include/ieee80211.h index fabb95917e8b..cf3f64db34d2 100644 --- a/drivers/staging/rtl8188eu/include/ieee80211.h +++ b/drivers/staging/rtl8188eu/include/ieee80211.h @@ -486,44 +486,6 @@ struct ieee80211_snap_hdr { /* Non standard? Not in */ #define WLAN_REASON_EXPIRATION_CHK 65535 -/* Information Element IDs */ -#define WLAN_EID_SSID 0 -#define WLAN_EID_SUPP_RATES 1 -#define WLAN_EID_FH_PARAMS 2 -#define WLAN_EID_DS_PARAMS 3 -#define WLAN_EID_CF_PARAMS 4 -#define WLAN_EID_TIM 5 -#define WLAN_EID_IBSS_PARAMS 6 -#define WLAN_EID_CHALLENGE 16 -/* EIDs defined by IEEE 802.11h - START */ -#define WLAN_EID_PWR_CONSTRAINT 32 -#define WLAN_EID_PWR_CAPABILITY 33 -#define WLAN_EID_TPC_REQUEST 34 -#define WLAN_EID_TPC_REPORT 35 -#define WLAN_EID_SUPPORTED_CHANNELS 36 -#define WLAN_EID_CHANNEL_SWITCH 37 -#define WLAN_EID_MEASURE_REQUEST 38 -#define WLAN_EID_MEASURE_REPORT 39 -#define WLAN_EID_QUITE 40 -#define WLAN_EID_IBSS_DFS 41 -/* EIDs defined by IEEE 802.11h - END */ -#define WLAN_EID_ERP_INFO 42 -#define WLAN_EID_HT_CAP 45 -#define WLAN_EID_RSN 48 -#define WLAN_EID_EXT_SUPP_RATES 50 -#define WLAN_EID_MOBILITY_DOMAIN 54 -#define WLAN_EID_FAST_BSS_TRANSITION 55 -#define WLAN_EID_TIMEOUT_INTERVAL 56 -#define WLAN_EID_RIC_DATA 57 -#define WLAN_EID_HT_OPERATION 61 -#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 -#define WLAN_EID_20_40_BSS_COEXISTENCE 72 -#define WLAN_EID_20_40_BSS_INTOLERANT 73 -#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74 -#define WLAN_EID_MMIE 76 -#define WLAN_EID_VENDOR_SPECIFIC 221 -#define WLAN_EID_GENERIC (WLAN_EID_VENDOR_SPECIFIC) - #define IEEE80211_MGMT_HDR_LEN 24 #define IEEE80211_DATA_HDR3_LEN 24 #define IEEE80211_DATA_HDR4_LEN 30 diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index 2db86fbe29d2..554c04d56fd3 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -2666,7 +2666,7 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) psta = rtw_get_stainfo(pstapriv, param->sta_addr); if (psta) { - if ((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_GENERIC)) { + if ((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC)) { int wpa_ie_len; int copy_len; -- cgit v1.3-6-gb490 From 63d6c969b7424b014fc3cc43b549f63db166aa2a Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Wed, 29 Jul 2015 10:15:16 +0200 Subject: staging: rtl8188eu: wrap a long if condition and remove extra parenthesis Signed-off-by: Jakub Sitnicki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/ioctl_linux.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index 554c04d56fd3..844ed6f3263a 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -2666,7 +2666,8 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) psta = rtw_get_stainfo(pstapriv, param->sta_addr); if (psta) { - if ((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC)) { + if (psta->wpa_ie[0] == WLAN_EID_RSN || + psta->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) { int wpa_ie_len; int copy_len; -- cgit v1.3-6-gb490 From b5efb33e5c6ea76d1f413bfd8e5d0a9811b958d0 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Wed, 29 Jul 2015 10:15:17 +0200 Subject: staging: rtl8188eu: don't duplicate ieee80211 WLAN_AUTH_* constants linux/ieee80211.h already defines constants for authentication algorithms. Remove the duplicated definitions. Signed-off-by: Jakub Sitnicki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/include/ieee80211.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/include/ieee80211.h b/drivers/staging/rtl8188eu/include/ieee80211.h index cf3f64db34d2..6400f75707bd 100644 --- a/drivers/staging/rtl8188eu/include/ieee80211.h +++ b/drivers/staging/rtl8188eu/include/ieee80211.h @@ -477,12 +477,6 @@ struct ieee80211_snap_hdr { #define WLAN_GET_SEQ_FRAG(seq) ((seq) & RTW_IEEE80211_SCTL_FRAG) #define WLAN_GET_SEQ_SEQ(seq) ((seq) & RTW_IEEE80211_SCTL_SEQ) -/* Authentication algorithms */ -#define WLAN_AUTH_OPEN 0 -#define WLAN_AUTH_SHARED_KEY 1 - -#define WLAN_AUTH_CHALLENGE_LEN 128 - /* Non standard? Not in */ #define WLAN_REASON_EXPIRATION_CHK 65535 -- cgit v1.3-6-gb490 From 26589720620e8fe429681f599fdc145c8f57a8c6 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Wed, 29 Jul 2015 10:15:18 +0200 Subject: staging: rtl8188eu: don't duplicate ieee80211 WLAN_HT_CAP_SM_PS_* constants linux/ieee80211.h already defines constants for spatial multiplexing power save modes. Remove the duplicated definitions. Signed-off-by: Jakub Sitnicki Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/include/wifi.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/include/wifi.h b/drivers/staging/rtl8188eu/include/wifi.h index a08a2e045e59..dba8af1ec41e 100644 --- a/drivers/staging/rtl8188eu/include/wifi.h +++ b/drivers/staging/rtl8188eu/include/wifi.h @@ -649,13 +649,6 @@ enum ht_cap_ampdu_factor { #define IEEE80211_MAX_AMPDU_BUF 0x40 -/* Spatial Multiplexing Power Save Modes */ -#define WLAN_HT_CAP_SM_PS_STATIC 0 -#define WLAN_HT_CAP_SM_PS_DYNAMIC 1 -#define WLAN_HT_CAP_SM_PS_INVALID 2 -#define WLAN_HT_CAP_SM_PS_DISABLED 3 - - #define OP_MODE_PURE 0 #define OP_MODE_MAY_BE_LEGACY_STAS 1 #define OP_MODE_20MHZ_HT_STA_ASSOCED 2 -- cgit v1.3-6-gb490 From f523c7d7a66d97d0584182eb3ff4b2425219f9d8 Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Mon, 27 Jul 2015 19:07:57 +0530 Subject: Staging : rtl8188eu : os_dep : Compression of lines for immediate return This patch compresses two lines into a single line if immediate return is found. Also remove variable ret as it is no longer needed. Semantic patch used for this is as follows: @@ type T; identifier i,f; constant C; @@ - T i; ...when != i when strict ( return -C; | - i = + return f(...); - return i; ) Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/ioctl_linux.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index 844ed6f3263a..969574926e21 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -2485,16 +2485,13 @@ static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int static int rtw_hostapd_sta_flush(struct net_device *dev) { - int ret = 0; struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); DBG_88E("%s\n", __func__); flush_all_cam_entry(padapter); /* clear CAM */ - ret = rtw_sta_flush(padapter); - - return ret; + return rtw_sta_flush(padapter); } static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) @@ -2810,7 +2807,6 @@ static int rtw_set_hidden_ssid(struct net_device *dev, struct ieee_param *param, static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *param, int len) { - int ret = 0; struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); @@ -2821,13 +2817,11 @@ static int rtw_ioctl_acl_remove_sta(struct net_device *dev, struct ieee_param *p param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) return -EINVAL; - ret = rtw_acl_remove_sta(padapter, param->sta_addr); - return ret; + return rtw_acl_remove_sta(padapter, param->sta_addr); } static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *param, int len) { - int ret = 0; struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); @@ -2838,8 +2832,7 @@ static int rtw_ioctl_acl_add_sta(struct net_device *dev, struct ieee_param *para param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) return -EINVAL; - ret = rtw_acl_add_sta(padapter, param->sta_addr); - return ret; + return rtw_acl_add_sta(padapter, param->sta_addr); } static int rtw_ioctl_set_macaddr_acl(struct net_device *dev, struct ieee_param *param, int len) -- cgit v1.3-6-gb490 From cfa48d936a22928060c7f9d401e927af3d5f87cf Mon Sep 17 00:00:00 2001 From: Mayank Bareja Date: Tue, 28 Jul 2015 05:50:12 +0000 Subject: Staging: rtl8188eu/hal: Fixed code indentation warning detected with checkpatch.pl fixed code indentation warning as reported by checkpatch.pl. Replaced Spaces with Tabs. Signed-off-by: Mayank Bareja Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/hal/bb_cfg.c | 6 +++--- drivers/staging/rtl8188eu/hal/rf.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/hal/bb_cfg.c b/drivers/staging/rtl8188eu/hal/bb_cfg.c index 8eb2b39a0b67..9c7e626aa703 100644 --- a/drivers/staging/rtl8188eu/hal/bb_cfg.c +++ b/drivers/staging/rtl8188eu/hal/bb_cfg.c @@ -24,9 +24,9 @@ #define read_next_pair(array, v1, v2, i) \ do { \ - i += 2; \ - v1 = array[i]; \ - v2 = array[i+1]; \ + i += 2; \ + v1 = array[i]; \ + v2 = array[i+1]; \ } while (0) diff --git a/drivers/staging/rtl8188eu/hal/rf.c b/drivers/staging/rtl8188eu/hal/rf.c index 097092772a86..38845d17d593 100644 --- a/drivers/staging/rtl8188eu/hal/rf.c +++ b/drivers/staging/rtl8188eu/hal/rf.c @@ -102,7 +102,7 @@ void rtl88eu_phy_rf6052_set_cck_txpower(struct adapter *adapt, u8 *powerlevel) } } rtl88eu_dm_txpower_track_adjust(&hal_data->odmpriv, 1, &direction, - &pwrtrac_value); + &pwrtrac_value); if (direction == 1) { /* Increase TX power */ -- cgit v1.3-6-gb490 From 4cc38b0849d68c5a43b1b57f771fa8c6fb779081 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Fri, 24 Jul 2015 12:06:51 -0400 Subject: drivers, staging, unisys, cleanup channel_guid.h This file has a lot of dead comments and needs to be cleaned up. Signed-off-by: Prarit Bhargava Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/include/channel_guid.h | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/include/channel_guid.h b/drivers/staging/unisys/include/channel_guid.h index 706363fc3e9a..2cc4b0b465a1 100644 --- a/drivers/staging/unisys/include/channel_guid.h +++ b/drivers/staging/unisys/include/channel_guid.h @@ -17,35 +17,27 @@ * CHANNEL Guids */ -/* Used in IOChannel - * {414815ed-c58c-11da-95a9-00e08161165f} - */ +/* {414815ed-c58c-11da-95a9-00e08161165f} */ #define SPAR_VHBA_CHANNEL_PROTOCOL_UUID \ UUID_LE(0x414815ed, 0xc58c, 0x11da, \ 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) static const uuid_le spar_vhba_channel_protocol_uuid = SPAR_VHBA_CHANNEL_PROTOCOL_UUID; -/* Used in IOChannel - * {8cd5994d-c58e-11da-95a9-00e08161165f} - */ +/* {8cd5994d-c58e-11da-95a9-00e08161165f} */ #define SPAR_VNIC_CHANNEL_PROTOCOL_UUID \ UUID_LE(0x8cd5994d, 0xc58e, 0x11da, \ 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) static const uuid_le spar_vnic_channel_protocol_uuid = SPAR_VNIC_CHANNEL_PROTOCOL_UUID; -/* Used in IOChannel - * {72120008-4AAB-11DC-8530-444553544200} - */ +/* {72120008-4AAB-11DC-8530-444553544200} */ #define SPAR_SIOVM_UUID \ UUID_LE(0x72120008, 0x4AAB, 0x11DC, \ 0x85, 0x30, 0x44, 0x45, 0x53, 0x54, 0x42, 0x00) static const uuid_le spar_siovm_uuid = SPAR_SIOVM_UUID; -/* Used in visornoop/visornoop_main.c - * {5b52c5ac-e5f5-4d42-8dff-429eaecd221f} - */ +/* {5b52c5ac-e5f5-4d42-8dff-429eaecd221f} */ #define SPAR_CONTROLDIRECTOR_CHANNEL_PROTOCOL_UUID \ UUID_LE(0x5b52c5ac, 0xe5f5, 0x4d42, \ 0x8d, 0xff, 0x42, 0x9e, 0xae, 0xcd, 0x22, 0x1f) @@ -53,9 +45,7 @@ static const uuid_le spar_siovm_uuid = SPAR_SIOVM_UUID; static const uuid_le spar_controldirector_channel_protocol_uuid = SPAR_CONTROLDIRECTOR_CHANNEL_PROTOCOL_UUID; -/* Used in visorchipset/visorchipset_main.c - * {B4E79625-AEDE-4EAA-9E11-D3EDDCD4504C} - */ +/* {b4e79625-aede-4eAA-9e11-D3eddcd4504c} */ #define SPAR_DIAG_POOL_CHANNEL_PROTOCOL_UUID \ UUID_LE(0xb4e79625, 0xaede, 0x4eaa, \ 0x9e, 0x11, 0xd3, 0xed, 0xdc, 0xd4, 0x50, 0x4c) -- cgit v1.3-6-gb490 From f93b0cbfdf919c956ce8cdd1fff10068004ff3a5 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Fri, 24 Jul 2015 12:06:52 -0400 Subject: staging: unisys: add UUID strings to channel_guid.h Define additional strings for module loading code ease of use. Signed-off-by: Prarit Bhargava Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/include/channel_guid.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/unisys/include/channel_guid.h b/drivers/staging/unisys/include/channel_guid.h index 2cc4b0b465a1..17cb499cb53c 100644 --- a/drivers/staging/unisys/include/channel_guid.h +++ b/drivers/staging/unisys/include/channel_guid.h @@ -23,6 +23,8 @@ 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) static const uuid_le spar_vhba_channel_protocol_uuid = SPAR_VHBA_CHANNEL_PROTOCOL_UUID; +#define SPAR_VHBA_CHANNEL_PROTOCOL_UUID_STR \ + "414815ed-c58c-11da-95a9-00e08161165f" /* {8cd5994d-c58e-11da-95a9-00e08161165f} */ #define SPAR_VNIC_CHANNEL_PROTOCOL_UUID \ @@ -30,6 +32,8 @@ static const uuid_le spar_vhba_channel_protocol_uuid = 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f) static const uuid_le spar_vnic_channel_protocol_uuid = SPAR_VNIC_CHANNEL_PROTOCOL_UUID; +#define SPAR_VNIC_CHANNEL_PROTOCOL_UUID_STR \ + "8cd5994d-c58e-11da-95a9-00e08161165f" /* {72120008-4AAB-11DC-8530-444553544200} */ #define SPAR_SIOVM_UUID \ -- cgit v1.3-6-gb490 From 59fd2c8bd11ff1cc9e8fd84f69d8047e63fad0a3 Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Fri, 24 Jul 2015 12:06:53 -0400 Subject: drivers, staging, unisys Add modalias files to visorbus devices This patch adds modalias files that export the device UUID type to sysfs so that udev can autoload the appropriate device driver on demand. Note that is required a minor name change to the channel device sysfs files which are currently named visorbus_dev_groups, and are now named visorbus_channel_groups. Signed-off-by: Prarit Bhargava Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorbus/visorbus_main.c | 45 +++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorbus/visorbus_main.c b/drivers/staging/unisys/visorbus/visorbus_main.c index 403c13b7864b..cc4a0292c287 100644 --- a/drivers/staging/unisys/visorbus/visorbus_main.c +++ b/drivers/staging/unisys/visorbus/visorbus_main.c @@ -69,6 +69,38 @@ static const struct attribute_group *visorbus_bus_groups[] = { NULL, }; +/* + * DEVICE type attributes + * + * The modalias file will contain the guid of the device. + */ +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct visor_device *vdev; + uuid_le guid; + + vdev = to_visor_device(dev); + guid = visorchannel_get_uuid(vdev->visorchannel); + return snprintf(buf, PAGE_SIZE, "visorbus:%pUl\n", &guid); +} +static DEVICE_ATTR_RO(modalias); + +static struct attribute *visorbus_dev_attrs[] = { + &dev_attr_modalias.attr, + NULL, +}; + +/* sysfs example for bridge-only sysfs files using device_type's */ +static const struct attribute_group visorbus_dev_group = { + .attrs = visorbus_dev_attrs, +}; + +const struct attribute_group *visorbus_dev_groups[] = { + &visorbus_dev_group, + NULL, +}; + /** This describes the TYPE of bus. * (Don't confuse this with an INSTANCE of the bus.) */ @@ -76,6 +108,7 @@ struct bus_type visorbus_type = { .name = "visorbus", .match = visorbus_match, .uevent = visorbus_uevent, + .dev_groups = visorbus_dev_groups, .bus_groups = visorbus_bus_groups, }; @@ -128,7 +161,13 @@ static LIST_HEAD(list_all_device_instances); static int visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env) { - if (add_uevent_var(env, "VERSION=%s", VERSION)) + struct visor_device *dev; + uuid_le guid; + + dev = to_visor_device(xdev); + guid = visorchannel_get_uuid(dev->visorchannel); + + if (add_uevent_var(env, "MODALIAS=visorbus:%pUl", &guid)) return -ENOMEM; return 0; } @@ -477,7 +516,7 @@ static struct attribute_group channel_attr_grp = { .attrs = channel_attrs, }; -static const struct attribute_group *visorbus_dev_groups[] = { +static const struct attribute_group *visorbus_channel_groups[] = { &channel_attr_grp, NULL }; @@ -936,7 +975,7 @@ create_visor_device(struct visor_device *dev) sema_init(&dev->visordriver_callback_lock, 1); /* unlocked */ dev->device.bus = &visorbus_type; - dev->device.groups = visorbus_dev_groups; + dev->device.groups = visorbus_channel_groups; device_initialize(&dev->device); dev->device.release = visorbus_release_device; /* keep a reference just for us (now 2) */ -- cgit v1.3-6-gb490 From 30948df80c1d17a7dfe5f4efba7e8f4880fc7662 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 28 Jul 2015 12:29:06 -0400 Subject: staging: unisys: avoid format string parsing This makes sure the kthread name can't be parsed as a format string. Signed-off-by: Kees Cook Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 2a9b055dcc51..f4c0c9fd077b 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -316,7 +316,7 @@ static int visor_thread_start(struct visor_thread_info *thrinfo, void *thrcontext, char *name) { /* used to stop the thread */ - thrinfo->task = kthread_run(threadfn, thrcontext, name); + thrinfo->task = kthread_run(threadfn, thrcontext, "%s", name); if (IS_ERR(thrinfo->task)) { pr_debug("%s failed (%ld)\n", __func__, PTR_ERR(thrinfo->task)); -- cgit v1.3-6-gb490 From 6f562b21612d938cf43202ca3fe29636893aa5df Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Fri, 31 Jul 2015 13:21:33 -0400 Subject: staging: unisys: visornic - prevent lock recursion after IO recovery In the patch which changed the serverdown logic to by synchronous, we were mistakenly holding on to devdata->priv_lock in the call to visornic_serverdown_complete(), which ultimately ended up recursively attempting to grab the same lock via the path: --> dev_close --> visornic_close() --> visornic_disable_with_timeout() Evidence: BUG: spinlock recursion on CPU#0, kworker/u2:0/1567 lock: 0xffff88002d7e4c90, .magic: dead4ead, .owner: kworker/ .owner_cpu: 0 CPU: 0 PID: 1567 Comm: kworker/u2:0 Tainted: G WC 4.2.0-rc3-ARCH+ #60 Hardware name: Dell Inc. PowerEdge T110/ , BIOS 1.23 12/15/2009 Workqueue: visorchipset_controlvm controlvm_periodic_work [visorbus] ffff8800216a9380 ffff88002d167878 ffffffff81476874 000000000000061f ffff88002d7e4c90 ffff88002d167898 ffffffff8109e2bc ffff88002d7e4c90 ffffffff81763d7c ffff88002d1678b8 ffffffff8109e330 ffff88002d7e4c90 Call Trace: [] dump_stack+0x4f/0x73 [] spin_dump+0x7c/0xc0 [] spin_bug+0x30/0x40 [] do_raw_spin_lock+0x127/0x140 [] _raw_spin_lock_irqsave+0x4b/0x60 [] ? visornic_disable_with_timeout.clone.2+0x3c/ [visornic] [] ? _raw_spin_unlock_bh+0x39/0x40 [] visornic_disable_with_timeout.clone.2+0x3c/ [visornic] [] visornic_close+0xe/0x20 [visornic] [] __dev_close_many+0x92/0xe0 [] dev_close_many+0x7a/0x110 [] ? down+0x16/0x50 [] dev_close+0x3f/0x50 [] visornic_serverdown+0x91/0x1a0 [visornic] [] ? device_changestate_responder.clone. [visorbus] [] visornic_pause+0x15/0x20 [visornic] [] initiate_chipset_device_pause_resume+0x9f/0xe0 [visorbus] [] chipset_device_pause+0x13/0x20 [visorbus] [] device_epilog+0x12b/0x1a0 [visorbus] [] handle_command+0x72b/0x970 [visorbus] [] ? visorchannel_signalremove+0x6e/0x80 [visorbus] [] controlvm_periodic_work+0x271/0x420 [visorbus] [] process_one_work+0x1d2/0x540 [] ? process_one_work+0x139/0x540 [] ? __schedule+0x807/0xc30 [] worker_thread+0x57/0x4c0 [] ? process_scheduled_works+0x40/0x40 [] ? process_scheduled_works+0x40/0x40 [] kthread+0xe9/0x110 [] ? __init_kthread_worker+0x70/0x70 [] ret_from_fork+0x3f/0x70 [] ? __init_kthread_worker+0x70/0x70 BUG: spinlock lockup suspected on CPU#0, kworker/u2:0/1567 Fixes: f2b70efaf48f ("staging: unisys: Make serverdown synchronous") Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index f4c0c9fd077b..801e66abf58e 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -416,14 +416,15 @@ visornic_serverdown(struct visornic_devdata *devdata, } devdata->server_change_state = true; devdata->server_down_complete_func = complete_func; + spin_unlock_irqrestore(&devdata->priv_lock, flags); visornic_serverdown_complete(devdata); } else if (devdata->server_change_state) { dev_dbg(&devdata->dev->device, "%s changing state\n", __func__); spin_unlock_irqrestore(&devdata->priv_lock, flags); return -EINVAL; - } - spin_unlock_irqrestore(&devdata->priv_lock, flags); + } else + spin_unlock_irqrestore(&devdata->priv_lock, flags); return 0; } -- cgit v1.3-6-gb490 From 6483783d24afc22248f3051326681a4327e29e72 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Tue, 28 Jul 2015 12:29:08 -0400 Subject: staging: unisys: visornic - correctly reset flag prior to send_enbdis() Because devdata->enab_dis_acked is the flag used to determine whether an enable/disable operation to the IO partition has completed, it should always be cleared prior to initiating the operation. The call added to visornic_enable_with_timeout() added in this patch makes the usage there consistent with visornic_disable_with_timeout(). Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 801e66abf58e..02906ef6c4c6 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -680,6 +680,7 @@ visornic_enable_with_timeout(struct net_device *netdev, const int timeout) spin_lock_irqsave(&devdata->priv_lock, flags); devdata->enabled = 1; + devdata->enab_dis_acked = 0; /* now we're ready, let's send an ENB to uisnic but until we get * an ACK back from uisnic, we'll drop the packets -- cgit v1.3-6-gb490 From c847020e7ae07c6a3d68c9a617815b9d4f8a1e10 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Tue, 28 Jul 2015 12:29:09 -0400 Subject: staging: unisys: visornic_resume needs to mirror _serverdown_complete Previously we simplified the serverdown function to basically turn it into a dev_close(), but missed the analogous logic in visornic_resume() (which is essentially the "book-end" of visornic_serverdown_complete()). As a result, during IO partition recovery, the nic would go closed when the IO partition went away, but would never be opened again when the IO partition came back. This patch changes visornic_resume() to use dev_open(), so that it once again plays nicely with visornic_serverdown_complete(). Because dev_open() forces us into the visornic_open() path, other logic in visornic_resume() was no longer necessary, and lended to simplifying visornic_resume() even more. Fixes: 36645d72a377 ("staging: unisys: simplify visornic_serverdown_complete") Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 56 ++++++++++++------------- 1 file changed, 26 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 02906ef6c4c6..dd908b8f40ef 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -2071,39 +2071,35 @@ static int visornic_resume(struct visor_device *dev, netdev = devdata->netdev; - if (devdata->server_down && !devdata->server_change_state) { - devdata->server_change_state = true; - /* Must transition channel to ATTACHED state BEFORE - * we can start using the device again. - * TODO: State transitions - */ - if (!devdata->threadinfo.id) - visor_thread_start(&devdata->threadinfo, - process_incoming_rsps, - devdata, "vnic_incoming"); - else - pr_warn("vnic_incoming already running!\n"); - - init_rcv_bufs(netdev, devdata); - spin_lock_irqsave(&devdata->priv_lock, flags); - devdata->enabled = 1; - - /* Now we're ready, let's send an ENB to uisnic but until - * we get an ACK back from uisnic, we'll drop the packets - */ - devdata->enab_dis_acked = 0; + spin_lock_irqsave(&devdata->priv_lock, flags); + if (devdata->server_change_state) { spin_unlock_irqrestore(&devdata->priv_lock, flags); - - /* send enable and wait for ack - don't hold lock when - * sending enable because if the queue if sull, insert - * might sleep. - */ - send_enbdis(netdev, 1, devdata); - } else if (devdata->server_change_state) { - dev_err(&dev->device, "%s server_change_state\n", + dev_err(&dev->device, "%s server already changing state\n", __func__); - return -EIO; + return -EINVAL; } + if (!devdata->server_down) { + spin_unlock_irqrestore(&devdata->priv_lock, flags); + dev_err(&dev->device, "%s server not down\n", __func__); + complete_func(dev, 0); + return 0; + } + devdata->server_change_state = true; + spin_unlock_irqrestore(&devdata->priv_lock, flags); + /* Must transition channel to ATTACHED state BEFORE + * we can start using the device again. + * TODO: State transitions + */ + if (!devdata->threadinfo.id) + visor_thread_start(&devdata->threadinfo, + process_incoming_rsps, + devdata, "vnic_incoming"); + else + pr_warn("vnic_incoming already running!\n"); + + rtnl_lock(); + dev_open(netdev); + rtnl_unlock(); complete_func(dev, 0); return 0; -- cgit v1.3-6-gb490 From cb84fca03d99ec1bb8d370b575aa2984b60a8374 Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Tue, 28 Jul 2015 12:29:10 -0400 Subject: staging: unisys: visornic: enable skb->len error-check, remove DEBUG blocks * A skb->len error-check was enabled (removed from a "#ifdef DEBUG" block). * Several unneeded "#ifdef DEBUG" blocks were removed. * A dev_err() was converted to the more-appropriate netdev_err(). Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 26 +++---------------------- 1 file changed, 3 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index dd908b8f40ef..14563afb3c70 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -1169,9 +1169,6 @@ visornic_rx(struct uiscmdrsp *cmdrsp) int cc, currsize, off, status; struct ethhdr *eth; unsigned long flags; -#ifdef DEBUG - struct phys_info testfrags[MAX_PHYS_INFO]; -#endif /* post new rcv buf to the other end using the cmdrsp we have at hand * post it without holding lock - but we'll use the signal lock to @@ -1282,29 +1279,12 @@ visornic_rx(struct uiscmdrsp *cmdrsp) curr->data_len = 0; off += currsize; } -#ifdef DEBUG /* assert skb->len == off */ if (skb->len != off) { - dev_err(&devdata->netdev->dev, - "%s something wrong; skb->len:%d != off:%d\n", - netdev->name, skb->len, off); - } - /* test code */ - cc = util_copy_fragsinfo_from_skb("rcvchaintest", skb, - RCVPOST_BUF_SIZE, - MAX_PHYS_INFO, testfrags); - if (cc != cmdrsp->net.rcv.numrcvbufs) { - dev_err(&devdata->netdev->dev, - "**** %s Something wrong; rcvd chain length %d different from one we calculated %d\n", - netdev->name, cmdrsp->net.rcv.numrcvbufs, cc); - } - for (i = 0; i < cc; i++) { - dev_inf(&devdata->netdev->dev, - "test:RCVPOST_BUF_SIZE:%d[%d] pfn:%llu off:0x%x len:%d\n", - RCVPOST_BUF_SIZE, i, testfrags[i].pi_pfn, - testfrags[i].pi_off, testfrags[i].pi_len); + netdev_err(devdata->netdev, + "something wrong; skb->len:%d != off:%d\n", + skb->len, off); } -#endif } /* set up packet's protocl type using ethernet header - this -- cgit v1.3-6-gb490 From 36927c1828c526c571973758b2d3a4bad051bc3f Mon Sep 17 00:00:00 2001 From: Tim Sell Date: Tue, 28 Jul 2015 12:29:11 -0400 Subject: staging: unisys: visornic - consolidate+simplify xmit watermark checks The code that tests for high and low xmit watermarks was consolidatedand simplified. The output behavior should be identical, with the exception of an off-by-one error being corrected in the tests done when the counters overflowed. Signed-off-by: Tim Sell Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 114 ++++++++++++++++-------- 1 file changed, 75 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 14563afb3c70..7d4602973bbb 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -135,15 +135,16 @@ struct visornic_devdata { atomic_t num_rcvbuf_in_iovm; unsigned long alloc_failed_in_if_needed_cnt; unsigned long alloc_failed_in_repost_rtn_cnt; - int max_outstanding_net_xmits; /* absolute max number of outstanding - * xmits - should never hit this - */ - int upper_threshold_net_xmits; /* high water mark for calling - * netif_stop_queue() - */ - int lower_threshold_net_xmits; /* high water mark for calling - * netif_wake_queue() - */ + unsigned long max_outstanding_net_xmits; /* absolute max number of + * outstanding xmits - should + * never hit this + */ + unsigned long upper_threshold_net_xmits; /* high water mark for + * calling netif_stop_queue() + */ + unsigned long lower_threshold_net_xmits; /* high water mark for calling + * netif_wake_queue() + */ struct sk_buff_head xmitbufhead; /* xmitbufhead is the head of the * xmit buffer list that have been * sent to the IOPART end @@ -794,6 +795,53 @@ visornic_close(struct net_device *netdev) return 0; } +/** + * devdata_xmits_outstanding - compute outstanding xmits + * @devdata: visornic_devdata for device + * + * Return value is the number of outstanding xmits. + */ +static unsigned long devdata_xmits_outstanding(struct visornic_devdata *devdata) +{ + if (devdata->chstat.sent_xmit >= devdata->chstat.got_xmit_done) + return devdata->chstat.sent_xmit - + devdata->chstat.got_xmit_done; + else + return (ULONG_MAX - devdata->chstat.got_xmit_done + + devdata->chstat.sent_xmit + 1); +} + +/** + * vnic_hit_high_watermark + * @devdata: indicates visornic device we are checking + * @high_watermark: max num of unacked xmits we will tolerate, + * before we will start throttling + * + * Returns true iff the number of unacked xmits sent to + * the IO partition is >= high_watermark. + */ +static inline bool vnic_hit_high_watermark(struct visornic_devdata *devdata, + ulong high_watermark) +{ + return (devdata_xmits_outstanding(devdata) >= high_watermark); +} + +/** + * vnic_hit_low_watermark + * @devdata: indicates visornic device we are checking + * @low_watermark: we will wait until the num of unacked xmits + * drops to this value or lower before we start + * transmitting again + * + * Returns true iff the number of unacked xmits sent to + * the IO partition is <= low_watermark. + */ +static inline bool vnic_hit_low_watermark(struct visornic_devdata *devdata, + ulong low_watermark) +{ + return (devdata_xmits_outstanding(devdata) <= low_watermark); +} + /** * visornic_xmit - send a packet to the IO Partition * @skb: Packet to be sent @@ -869,13 +917,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) /* save the pointer to skb -- we'll need it for completion */ cmdrsp->net.buf = skb; - if (((devdata->chstat.sent_xmit >= devdata->chstat.got_xmit_done) && - (devdata->chstat.sent_xmit - devdata->chstat.got_xmit_done >= - devdata->max_outstanding_net_xmits)) || - ((devdata->chstat.sent_xmit < devdata->chstat.got_xmit_done) && - (ULONG_MAX - devdata->chstat.got_xmit_done + - devdata->chstat.sent_xmit >= - devdata->max_outstanding_net_xmits))) { + if (vnic_hit_high_watermark(devdata, + devdata->max_outstanding_net_xmits)) { /* too many NET_XMITs queued over to IOVM - need to wait */ devdata->chstat.reject_count++; @@ -957,13 +1000,8 @@ visornic_xmit(struct sk_buff *skb, struct net_device *netdev) /* check to see if we have hit the high watermark for * netif_stop_queue() */ - if (((devdata->chstat.sent_xmit >= devdata->chstat.got_xmit_done) && - (devdata->chstat.sent_xmit - devdata->chstat.got_xmit_done >= - devdata->upper_threshold_net_xmits)) || - ((devdata->chstat.sent_xmit < devdata->chstat.got_xmit_done) && - (ULONG_MAX - devdata->chstat.got_xmit_done + - devdata->chstat.sent_xmit >= - devdata->upper_threshold_net_xmits))) { + if (vnic_hit_high_watermark(devdata, + devdata->upper_threshold_net_xmits)) { /* too many NET_XMITs queued over to IOVM - need to wait */ netif_stop_queue(netdev); /* calling stop queue - call * netif_wake_queue() after lower @@ -1457,13 +1495,13 @@ static ssize_t info_debugfs_read(struct file *file, char __user *buf, " num_rcv_bufs = %d\n", devdata->num_rcv_bufs); str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " max_oustanding_next_xmits = %d\n", + " max_oustanding_next_xmits = %lu\n", devdata->max_outstanding_net_xmits); str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " upper_threshold_net_xmits = %d\n", + " upper_threshold_net_xmits = %lu\n", devdata->upper_threshold_net_xmits); str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " lower_threshold_net_xmits = %d\n", + " lower_threshold_net_xmits = %lu\n", devdata->lower_threshold_net_xmits); str_pos += scnprintf(vbuf + str_pos, len - str_pos, " queuefullmsg_logged = %d\n", @@ -1562,6 +1600,9 @@ static ssize_t info_debugfs_read(struct file *file, char __user *buf, " netif_queue = %s\n", netif_queue_stopped(devdata->netdev) ? "stopped" : "running"); + str_pos += scnprintf(vbuf + str_pos, len - str_pos, + " xmits_outstanding = %lu\n", + devdata_xmits_outstanding(devdata)); } rcu_read_unlock(); bytes_read = simple_read_from_buffer(buf, len, offset, vbuf, str_pos); @@ -1655,16 +1696,8 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata) * the lower watermark for * netif_wake_queue() */ - if (((devdata->chstat.sent_xmit >= - devdata->chstat.got_xmit_done) && - (devdata->chstat.sent_xmit - - devdata->chstat.got_xmit_done <= - devdata->lower_threshold_net_xmits)) || - ((devdata->chstat.sent_xmit < - devdata->chstat.got_xmit_done) && - (ULONG_MAX - devdata->chstat.got_xmit_done - + devdata->chstat.sent_xmit <= - devdata->lower_threshold_net_xmits))) { + if (vnic_hit_low_watermark(devdata, + devdata->lower_threshold_net_xmits)) { /* enough NET_XMITs completed * so can restart netif queue */ @@ -1834,12 +1867,15 @@ static int visornic_probe(struct visor_device *dev) /* set the net_xmit outstanding threshold */ /* always leave two slots open but you should have 3 at a minimum */ + /* note that max_outstanding_net_xmits must be > 0 */ devdata->max_outstanding_net_xmits = - max(3, ((devdata->num_rcv_bufs / 3) - 2)); + max_t(unsigned long, 3, ((devdata->num_rcv_bufs / 3) - 2)); devdata->upper_threshold_net_xmits = - max(2, devdata->max_outstanding_net_xmits - 1); + max_t(unsigned long, + 2, (devdata->max_outstanding_net_xmits - 1)); devdata->lower_threshold_net_xmits = - max(1, devdata->max_outstanding_net_xmits / 2); + max_t(unsigned long, + 1, (devdata->max_outstanding_net_xmits / 2)); skb_queue_head_init(&devdata->xmitbufhead); -- cgit v1.3-6-gb490 From f3c709b8fc1bbdeddd9b9c1f7785b9b35d2301d9 Mon Sep 17 00:00:00 2001 From: Navy Cheng Date: Mon, 27 Jul 2015 16:09:35 +0800 Subject: Staging: dgnc: dgnc_driver.h: remove unnecessary comments The public headers is well known by others and the redundant commits make the code mess. Remove the comments of the public headers to make the code tidy. Signed-off-by: Navy Cheng Signed-off-by: Greg Kroah-Hartman --- drivers/staging/dgnc/dgnc_driver.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/dgnc/dgnc_driver.h b/drivers/staging/dgnc/dgnc_driver.h index d04671fa4b75..06ece5151fe4 100644 --- a/drivers/staging/dgnc/dgnc_driver.h +++ b/drivers/staging/dgnc/dgnc_driver.h @@ -21,9 +21,9 @@ #ifndef __DGNC_DRIVER_H #define __DGNC_DRIVER_H -#include /* To pick up the varions Linux types */ -#include /* To pick up the various tty structs/defines */ -#include /* For irqreturn_t type */ +#include +#include +#include #include "digi.h" /* Digi specific ioctl header */ #include "dgnc_sysfs.h" /* Support for SYSFS */ -- cgit v1.3-6-gb490 From 4bc8ff7479c57f2e0332d8b8dc7ba44b31b6839c Mon Sep 17 00:00:00 2001 From: Kevin Darbyshire-Bryant Date: Sat, 25 Jul 2015 10:48:28 +0100 Subject: staging: octeon: add missing blank line after declarations Fixes checkpatch.pl WARNING: Missing a blank line after delarations Signed-off-by: Kevin Darbyshire-Bryant Signed-off-by: Greg Kroah-Hartman --- drivers/staging/octeon/ethernet.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index f9dba23a3759..0718b35f7335 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -157,6 +157,7 @@ static void cvm_oct_configure_common_hw(void) #ifdef __LITTLE_ENDIAN { union cvmx_ipd_ctl_status ipd_ctl_status; + ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS); ipd_ctl_status.s.pkt_lend = 1; ipd_ctl_status.s.wqe_lend = 1; -- cgit v1.3-6-gb490 From 5a3a3f64cabe1590d76d6e8bc1b24c11219ab61e Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Sat, 25 Jul 2015 01:59:08 +0200 Subject: staging/xgifb: fix dumpVGAReg compile error if DEBUG is set If DEBUG is set dumpVGAReg is called and tries to access XGISR which is defined as (xgifb_info->dev_info.P3c4) which is not known within this function. -> add as parameter to dumpVGAReg so xgifb_info becomes known Signed-off-by: Peter Huewe Signed-off-by: Greg Kroah-Hartman --- drivers/staging/xgifb/XGI_main_26.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c index 5bfe151ea328..5a6251a45112 100644 --- a/drivers/staging/xgifb/XGI_main_26.c +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -29,7 +29,7 @@ static unsigned int refresh_rate; /* -------------------- Macro definitions ---------------------------- */ #ifdef DEBUG -static void dumpVGAReg(void) +static void dumpVGAReg(struct xgifb_video_info *xgifb_info) { u8 i, reg; @@ -48,7 +48,7 @@ static void dumpVGAReg(void) } } #else -static inline void dumpVGAReg(void) +static inline void dumpVGAReg(struct xgifb_video_info *xgifb_info) { } #endif @@ -1073,7 +1073,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive, } XGIfb_bpp_to_var(xgifb_info, var); /*update ARGB info*/ - dumpVGAReg(); + dumpVGAReg(xgifb_info); return 0; } @@ -2019,7 +2019,7 @@ static int xgifb_probe(struct pci_dev *pdev, goto error_mtrr; } - dumpVGAReg(); + dumpVGAReg(xgifb_info); return 0; -- cgit v1.3-6-gb490 From 740d6c17c8fe25b917273195db8d49d33b87e6ae Mon Sep 17 00:00:00 2001 From: Ciprian Manea Date: Sun, 26 Jul 2015 22:26:18 +0100 Subject: staging: slicoss: Add blank line after variable declarations. This patch fixes the checkpatch.pl warning: WARNING: Missing a blank line after declarations + unsigned long flags; + pshmem = (struct slic_shmem *)(unsigned long) Signed-off-by: Ciprian Manea Signed-off-by: Greg Kroah-Hartman --- drivers/staging/slicoss/slicoss.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index a609f3e67256..858597087ba7 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -2329,6 +2329,7 @@ static int slic_if_init(struct adapter *adapter, unsigned long *flags) if (!adapter->isp_initialized) { unsigned long flags; + pshmem = (struct slic_shmem *)(unsigned long) adapter->phys_shmem; -- cgit v1.3-6-gb490 From 61c854f510505177e95b0f2bc88249c4ed68f501 Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Mon, 27 Jul 2015 15:36:26 +0530 Subject: Staging : android :Replace comma with a semicolon Replace comma between expression statements by a semicolon. The semantic patch used is as follows: @@ expression e1,e2; @@ e1 - , + ; e2; Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ashmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index c5c037ccf32c..7958d5c9663f 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -660,7 +660,7 @@ restart: if (page_range_subsumed_by_range(range, pgstart, pgend)) return 0; if (page_range_in_range(range, pgstart, pgend)) { - pgstart = min_t(size_t, range->pgstart, pgstart), + pgstart = min_t(size_t, range->pgstart, pgstart); pgend = max_t(size_t, range->pgend, pgend); purged |= range->purged; range_del(range); -- cgit v1.3-6-gb490 From bd1ccd33150261f0e58be6de615e4b14389ac208 Mon Sep 17 00:00:00 2001 From: Freeman Zhang Date: Mon, 27 Jul 2015 14:37:25 +0800 Subject: staging: rtl8192u: Fix checkpatch issue with comma in r819xU_firmware.c Add space after ',' to fix the error message provided by checkpatch.pl: ERROR: space required after that ',' Signed-off-by: Freeman Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/r819xU_firmware.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c index 742725e9bfc1..a7d30339390b 100644 --- a/drivers/staging/rtl8192u/r819xU_firmware.c +++ b/drivers/staging/rtl8192u/r819xU_firmware.c @@ -91,7 +91,7 @@ static bool fw_download_code(struct net_device *dev, u8 *code_virtual_address, if (!priv->ieee80211->check_nic_enough_desc(dev, index) || (!skb_queue_empty(&priv->ieee80211->skb_waitQ[index])) || (priv->ieee80211->queue_stop)) { - RT_TRACE(COMP_FIRMWARE,"=====================================================> tx full!\n"); + RT_TRACE(COMP_FIRMWARE, "=====================================================> tx full!\n"); skb_queue_tail(&priv->ieee80211->skb_waitQ[tcb_desc->queue_index], skb); } else { priv->ieee80211->softmac_hard_start_xmit(skb, dev); @@ -242,7 +242,7 @@ bool init_firmware(struct net_device *dev) * or read image file from array. Default load from IMG file */ if (rst_opt == OPT_SYSTEM_RESET) { - rc = request_firmware(&fw_entry, fw_name[init_step],&priv->udev->dev); + rc = request_firmware(&fw_entry, fw_name[init_step], &priv->udev->dev); if (rc < 0) { RT_TRACE(COMP_ERR, "request firmware fail!\n"); goto download_firmware_fail; @@ -254,12 +254,12 @@ bool init_firmware(struct net_device *dev) } if (init_step != FW_INIT_STEP1_MAIN) { - memcpy(pfirmware->firmware_buf,fw_entry->data,fw_entry->size); + memcpy(pfirmware->firmware_buf, fw_entry->data, fw_entry->size); mapped_file = pfirmware->firmware_buf; file_length = fw_entry->size; } else { memset(pfirmware->firmware_buf, 0, 128); - memcpy(&pfirmware->firmware_buf[128],fw_entry->data,fw_entry->size); + memcpy(&pfirmware->firmware_buf[128], fw_entry->data, fw_entry->size); mapped_file = pfirmware->firmware_buf; file_length = fw_entry->size + 128; } @@ -319,7 +319,7 @@ bool init_firmware(struct net_device *dev) rt_status = CPUcheck_firmware_ready(dev); if (!rt_status) { - RT_TRACE(COMP_ERR, "CPUcheck_firmware_ready fail(%d)!\n",rt_status); + RT_TRACE(COMP_ERR, "CPUcheck_firmware_ready fail(%d)!\n", rt_status); goto download_firmware_fail; } -- cgit v1.3-6-gb490 From 6ba4df24bb87246472be90b11fcecb720c2a15ba Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Mon, 27 Jul 2015 23:30:52 +0530 Subject: Staging:dgap :Compression of lines for immediate return This patch compresses two lines into a single line if immediate return statement is found. Remove variable rc as it is no longer needed. It is done using script Coccinelle. And coccinelle uses the following semantic patch for this compression function: @@ type T; identifier i,f; constant C; @@ - T i; ...when != i when strict ( return -C; | - i = + return f(...); - return i; ) Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/dgap/dgap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c index b344e035b0ef..9112dd2bf4d7 100644 --- a/drivers/staging/dgap/dgap.c +++ b/drivers/staging/dgap/dgap.c @@ -4953,9 +4953,8 @@ static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); spin_unlock_irqrestore(&bd->bd_lock, lock_flags); - rc = put_user(C_CLOCAL(tty) ? 1 : 0, + return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg); - return rc; case TIOCSSOFTCAR: spin_unlock_irqrestore(&ch->ch_lock, lock_flags2); -- cgit v1.3-6-gb490 From 936d61eeac71504b52977cc9f9339cb86866c531 Mon Sep 17 00:00:00 2001 From: Jignesh R Patel Date: Tue, 28 Jul 2015 16:19:36 +0530 Subject: staging: android: Fixed line over 80 char Fixes the following checkpatch warning: Warning: Line over 80 characters Signed-off-by: Jignesh R Patel Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ion/ion_cma_heap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index 86b91fd53852..0b2448c32495 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -73,7 +73,8 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, if (!info->table) goto free_mem; - if (dma_get_sgtable(dev, info->table, info->cpu_addr, info->handle, len)) + if (dma_get_sgtable(dev, info->table, info->cpu_addr, info->handle, + len)) goto free_table; /* keep this for memory release */ buffer->priv_virt = info; -- cgit v1.3-6-gb490 From 6852ac9acbb8f11fe736116f7cc819891021404f Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Thu, 30 Jul 2015 15:31:37 +0200 Subject: Staging: most: fix double unlock This patch fixes double unlocking of a spinlock the aim-v4l2 module. Reported-by: Dan Carpenter Signed-off-by: Christian Gromm Signed-off-by: Andrey Shvetsov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/aim-v4l2/video.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/most/aim-v4l2/video.c b/drivers/staging/most/aim-v4l2/video.c index a977b883ee36..d9687910e4a4 100644 --- a/drivers/staging/most/aim-v4l2/video.c +++ b/drivers/staging/most/aim-v4l2/video.c @@ -619,6 +619,7 @@ static void __exit aim_exit(void) aim_unregister_videodev(mdev); v4l2_device_disconnect(&mdev->v4l2_dev); v4l2_device_put(&mdev->v4l2_dev); + spin_lock(&list_lock); } spin_unlock(&list_lock); -- cgit v1.3-6-gb490 From 3f78f6116d581e1342f56a4dacdd576d79b054c4 Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Thu, 30 Jul 2015 15:31:39 +0200 Subject: Staging: most: replace min() by min_t() This patch fixes wrong casting. Reported-by: Dan Carpenter Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/mostcore/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/most/mostcore/core.c b/drivers/staging/most/mostcore/core.c index 49d03af599d5..f872dc0bc118 100644 --- a/drivers/staging/most/mostcore/core.c +++ b/drivers/staging/most/mostcore/core.c @@ -973,7 +973,7 @@ static ssize_t store_add_link(struct most_aim_obj *aim_obj, char *mdev_devnod; char devnod_buf[STRING_SIZE]; int ret; - unsigned int max_len = min((int)len + 1, STRING_SIZE); + size_t max_len = min_t(size_t, len + 1, STRING_SIZE); strlcpy(buffer, buf, max_len); strlcpy(aim_obj->add_link, buf, max_len); @@ -1036,7 +1036,7 @@ static ssize_t store_remove_link(struct most_aim_obj *aim_obj, char *mdev; char *mdev_ch; int ret; - unsigned int max_len = min((int)len + 1, STRING_SIZE); + size_t max_len = min_t(size_t, len + 1, STRING_SIZE); strlcpy(buffer, buf, max_len); strlcpy(aim_obj->remove_link, buf, max_len); -- cgit v1.3-6-gb490 From 412c8232edfac024ed22bd1424f37f68fcbb555c Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Thu, 30 Jul 2015 18:18:55 +0200 Subject: Staging: most: fix doing DMA on stack This patch fixes error "doing DMA on the stack" by using kzalloc for buffer allocation. Reported-by: Dan Carpenter Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/hdm-usb/hdm_usb.c | 36 ++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/most/hdm-usb/hdm_usb.c b/drivers/staging/most/hdm-usb/hdm_usb.c index a4a3e266b3ef..feb4c821d3a9 100644 --- a/drivers/staging/most/hdm-usb/hdm_usb.c +++ b/drivers/staging/most/hdm-usb/hdm_usb.c @@ -45,6 +45,7 @@ #define USB_VENDOR_ID_SMSC 0x0424 /* VID: SMSC */ #define USB_DEV_ID_BRDG 0xC001 /* PID: USB Bridge */ #define USB_DEV_ID_INIC 0xCF18 /* PID: USB INIC */ +#define HW_RESYNC 0x0000 /* DRCI Addresses */ #define DRCI_REG_NI_STATE 0x0100 #define DRCI_REG_PACKET_BW 0x0101 @@ -140,20 +141,29 @@ static void wq_netinfo(struct work_struct *wq_obj); * @dev: usb device * */ -static inline void trigger_resync_vr(struct usb_device *dev) +static void trigger_resync_vr(struct usb_device *dev) { - int data = 0; - - if (0 > usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - 0, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, - 0, - 0, - &data, - 0, - 5 * HZ)) - pr_info("Vendor request \"stall\" failed\n"); + int retval; + u8 request_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; + int *data = kzalloc(sizeof(*data), GFP_KERNEL); + + if (!data) + goto error; + *data = HW_RESYNC; + retval = usb_control_msg(dev, + usb_sndctrlpipe(dev, 0), + 0, + request_type, + 0, + 0, + data, + 0, + 5 * HZ); + kfree(data); + if (retval >= 0) + return; +error: + pr_info("Vendor request \"stall\" failed\n"); } /** -- cgit v1.3-6-gb490 From 59ed0480b95032418be6960375a13201c35364f7 Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Thu, 30 Jul 2015 18:19:41 +0200 Subject: Staging: most: replace pr_*() functions by dev_*() This patch replaces pr_*() functions with dev_*(). Reported-by: Greg Kroah-Hartman Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/hdm-usb/hdm_usb.c | 116 +++++++++++++++++---------------- 1 file changed, 59 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/most/hdm-usb/hdm_usb.c b/drivers/staging/most/hdm-usb/hdm_usb.c index feb4c821d3a9..514ce3529b7a 100644 --- a/drivers/staging/most/hdm-usb/hdm_usb.c +++ b/drivers/staging/most/hdm-usb/hdm_usb.c @@ -163,7 +163,7 @@ static void trigger_resync_vr(struct usb_device *dev) if (retval >= 0) return; error: - pr_info("Vendor request \"stall\" failed\n"); + dev_err(&dev->dev, "Vendor request \"stall\" failed\n"); } /** @@ -256,7 +256,7 @@ static unsigned int get_stream_frame_size(struct most_channel_config *cfg) unsigned int sub_size = cfg->subbuffer_size; if (!sub_size) { - pr_info("Misconfig: Subbuffer size zero.\n"); + pr_warn("Misconfig: Subbuffer size zero.\n"); return frame_size; } switch (cfg->data_type) { @@ -265,7 +265,7 @@ static unsigned int get_stream_frame_size(struct most_channel_config *cfg) break; case MOST_CH_SYNC: if (cfg->packets_per_xact == 0) { - pr_info("Misconfig: Packets per XACT zero\n"); + pr_warn("Misconfig: Packets per XACT zero\n"); frame_size = 0; } else if (cfg->packets_per_xact == 0xFF) frame_size = (USB_MTU / sub_size) * sub_size; @@ -294,16 +294,16 @@ int hdm_poison_channel(struct most_interface *iface, int channel) { struct most_dev *mdev; + mdev = to_mdev(iface); if (unlikely(!iface)) { - pr_info("Poison: Bad interface.\n"); + dev_warn(&mdev->usb_device->dev, "Poison: Bad interface.\n"); return -EIO; } if (unlikely((channel < 0) || (channel >= iface->num_channels))) { - pr_info("Channel ID out of range.\n"); + dev_warn(&mdev->usb_device->dev, "Channel ID out of range.\n"); return -ECHRNG; } - mdev = to_mdev(iface); mdev->is_channel_healthy[channel] = false; mutex_lock(&mdev->io_mutex); @@ -340,7 +340,8 @@ int hdm_add_padding(struct most_dev *mdev, int channel, struct mbo *mbo) num_frames = mbo->buffer_length / frame_size; if (num_frames < 1) { - pr_err("Missed minimal transfer unit.\n"); + dev_err(&mdev->usb_device->dev, + "Missed minimal transfer unit.\n"); return -EIO; } @@ -399,6 +400,7 @@ static void hdm_write_completion(struct urb *urb) struct mbo *mbo; struct buf_anchor *anchor; struct most_dev *mdev; + struct device *dev; unsigned int channel; unsigned long flags; @@ -406,6 +408,7 @@ static void hdm_write_completion(struct urb *urb) anchor = mbo->priv; mdev = to_mdev(mbo->ifp); channel = mbo->hdm_channel_id; + dev = &mdev->usb_device->dev; if ((urb->status == -ENOENT) || (urb->status == -ECONNRESET) || (mdev->is_channel_healthy[channel] == false)) { @@ -419,7 +422,7 @@ static void hdm_write_completion(struct urb *urb) mbo->processed_length = 0; switch (urb->status) { case -EPIPE: - pr_info("Broken OUT pipe detected\n"); + dev_warn(dev, "Broken OUT pipe detected\n"); most_stop_enqueue(&mdev->iface, channel); mbo->status = MBO_E_INVAL; usb_unlink_urb(urb); @@ -562,6 +565,7 @@ static void hdm_read_completion(struct urb *urb) struct mbo *mbo; struct buf_anchor *anchor; struct most_dev *mdev; + struct device *dev; unsigned long flags; unsigned int channel; struct most_channel_config *conf; @@ -570,6 +574,7 @@ static void hdm_read_completion(struct urb *urb) anchor = mbo->priv; mdev = to_mdev(mbo->ifp); channel = mbo->hdm_channel_id; + dev = &mdev->usb_device->dev; if ((urb->status == -ENOENT) || (urb->status == -ECONNRESET) || (mdev->is_channel_healthy[channel] == false)) { @@ -585,7 +590,7 @@ static void hdm_read_completion(struct urb *urb) mbo->processed_length = 0; switch (urb->status) { case -EPIPE: - pr_info("Broken IN pipe detected\n"); + dev_warn(dev, "Broken IN pipe detected\n"); mbo->status = MBO_E_INVAL; usb_unlink_urb(urb); INIT_WORK(&anchor->clear_work_obj, wq_clear_halt); @@ -596,7 +601,7 @@ static void hdm_read_completion(struct urb *urb) mbo->status = MBO_E_CLOSE; break; case -EOVERFLOW: - pr_info("Babble on IN pipe detected\n"); + dev_warn(dev, "Babble on IN pipe detected\n"); default: mbo->status = MBO_E_INVAL; break; @@ -644,30 +649,28 @@ int hdm_enqueue(struct most_interface *iface, int channel, struct mbo *mbo) struct most_dev *mdev; struct buf_anchor *anchor; struct most_channel_config *conf; + struct device *dev; int retval = 0; struct urb *urb; unsigned long flags; unsigned long length; void *virt_address; - if (unlikely(!iface || !mbo)) { - pr_info("Bad interface or MBO\n"); + if (unlikely(!iface || !mbo)) return -EIO; - } - if (unlikely(iface->num_channels <= channel) || (channel < 0)) { - pr_info("Channel ID out of range\n"); + if (unlikely(iface->num_channels <= channel) || (channel < 0)) return -ECHRNG; - } mdev = to_mdev(iface); conf = &mdev->conf[channel]; + dev = &mdev->usb_device->dev; if (!mdev->usb_device) return -ENODEV; urb = usb_alloc_urb(NO_ISOCHRONOUS_URB, GFP_ATOMIC); if (!urb) { - pr_info("Failed to allocate URB\n"); + dev_err(dev, "Failed to allocate URB\n"); return -ENOMEM; } @@ -719,7 +722,7 @@ int hdm_enqueue(struct most_interface *iface, int channel, struct mbo *mbo) retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { - pr_info("URB submit failed with error %d.\n", retval); + dev_err(dev, "URB submit failed with error %d.\n", retval); goto _error_1; } return 0; @@ -748,23 +751,25 @@ int hdm_configure_channel(struct most_interface *iface, int channel, unsigned int temp_size; unsigned int tail_space; struct most_dev *mdev; + struct device *dev; + + mdev = to_mdev(iface); + mdev->is_channel_healthy[channel] = true; + dev = &mdev->usb_device->dev; if (unlikely(!iface || !conf)) { - pr_info("Bad interface or config pointer.\n"); + dev_err(dev, "Bad interface or config pointer.\n"); return -EINVAL; } if (unlikely((channel < 0) || (channel >= iface->num_channels))) { - pr_info("Channel ID out of range.\n"); + dev_err(dev, "Channel ID out of range.\n"); return -EINVAL; } if ((!conf->num_buffers) || (!conf->buffer_size)) { - pr_info("Misconfig: buffer size or number of buffers zero.\n"); + dev_err(dev, "Misconfig: buffer size or #buffers zero.\n"); return -EINVAL; } - mdev = to_mdev(iface); - mdev->is_channel_healthy[channel] = true; - if (!(conf->data_type == MOST_CH_SYNC) && !((conf->data_type == MOST_CH_ISOC_AVP) && (conf->packets_per_xact != 0xFF))) { @@ -777,13 +782,13 @@ int hdm_configure_channel(struct most_interface *iface, int channel, if ((conf->data_type != MOST_CH_SYNC) && (conf->data_type != MOST_CH_ISOC_AVP)) { - pr_info("Unsupported data type\n"); + dev_warn(dev, "Unsupported data type\n"); return -EINVAL; } frame_size = get_stream_frame_size(conf); if ((frame_size == 0) || (frame_size > USB_MTU)) { - pr_info("Misconfig: frame size wrong\n"); + dev_warn(dev, "Misconfig: frame size wrong\n"); return -EINVAL; } @@ -792,11 +797,12 @@ int hdm_configure_channel(struct most_interface *iface, int channel, tmp_val = conf->buffer_size / frame_size; conf->buffer_size = tmp_val * frame_size; - pr_info("Channel %d - rouding buffer size to %d bytes," - " channel config says %d bytes", - channel, - conf->buffer_size, - temp_size); + dev_notice(dev, + "Channel %d - rouding buffer size to %d bytes, " + "channel config says %d bytes\n", + channel, + conf->buffer_size, + temp_size); } num_frames = conf->buffer_size / frame_size; @@ -820,6 +826,7 @@ exit: */ int hdm_update_netinfo(struct most_dev *mdev) { + struct device *dev = &mdev->usb_device->dev; int i; u16 link; u8 addr[6]; @@ -827,17 +834,17 @@ int hdm_update_netinfo(struct most_dev *mdev) if (!is_valid_ether_addr(mdev->hw_addr)) { if (0 > drci_rd_reg(mdev->usb_device, DRCI_REG_HW_ADDR_HI, addr)) { - pr_info("Vendor request \"hw_addr_hi\" failed\n"); + dev_err(dev, "Vendor request \"hw_addr_hi\" failed\n"); return -1; } if (0 > drci_rd_reg(mdev->usb_device, DRCI_REG_HW_ADDR_MI, addr + 2)) { - pr_info("Vendor request \"hw_addr_mid\" failed\n"); + dev_err(dev, "Vendor request \"hw_addr_mid\" failed\n"); return -1; } if (0 > drci_rd_reg(mdev->usb_device, DRCI_REG_HW_ADDR_LO, addr + 4)) { - pr_info("Vendor request \"hw_addr_low\" failed\n"); + dev_err(dev, "Vendor request \"hw_addr_low\" failed\n"); return -1; } mutex_lock(&mdev->io_mutex); @@ -847,7 +854,7 @@ int hdm_update_netinfo(struct most_dev *mdev) } if (0 > drci_rd_reg(mdev->usb_device, DRCI_REG_NI_STATE, &link)) { - pr_info("Vendor request \"link status\" failed\n"); + dev_err(dev, "Vendor request \"link status\" failed\n"); return -1; } le16_to_cpus(&link); @@ -947,7 +954,7 @@ static void wq_clear_halt(struct work_struct *wq_obj) channel = mbo->hdm_channel_id; if (usb_clear_halt(urb->dev, urb->pipe)) - pr_info("Failed to reset endpoint.\n"); + dev_warn(&mdev->usb_device->dev, "Failed to reset endpoint.\n"); usb_free_urb(urb); spin_lock_irqsave(&mdev->anchor_list_lock[channel], flags); @@ -1237,12 +1244,14 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) struct most_channel_capability *tmp_cap; struct most_dev *mdev; struct usb_device *usb_dev; + struct device *dev; struct usb_host_interface *usb_iface_desc; struct usb_endpoint_descriptor *ep_desc; int ret = 0; usb_iface_desc = interface->cur_altsetting; usb_dev = interface_to_usbdev(interface); + dev = &usb_dev->dev; mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); if (!mdev) goto exit_ENOMEM; @@ -1320,19 +1329,17 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) INIT_LIST_HEAD(&mdev->anchor_list[i]); spin_lock_init(&mdev->anchor_list_lock[i]); } - pr_info("claimed gadget: Vendor=%4.4x ProdID=%4.4x Bus=%02x Device=%02x If#=%d Alt=%d\n", - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - usb_dev->bus->busnum, - usb_dev->devnum, - usb_iface_desc->desc.bInterfaceNumber, - usb_iface_desc->desc.bAlternateSetting); - - pr_info("device path: /sys/bus/usb/devices/%d-%s:%d.%d\n", - usb_dev->bus->busnum, - usb_dev->devpath, - usb_dev->config->desc.bConfigurationValue, - usb_iface_desc->desc.bInterfaceNumber); + dev_notice(dev, "claimed gadget: Vendor=%4.4x ProdID=%4.4x Bus=%02x Device=%02x\n", + le16_to_cpu(usb_dev->descriptor.idVendor), + le16_to_cpu(usb_dev->descriptor.idProduct), + usb_dev->bus->busnum, + usb_dev->devnum); + + dev_notice(dev, "device path: /sys/bus/usb/devices/%d-%s:%d.%d\n", + usb_dev->bus->busnum, + usb_dev->devpath, + usb_dev->config->desc.bConfigurationValue, + usb_iface_desc->desc.bInterfaceNumber); mdev->parent = most_register_interface(&mdev->iface); if (IS_ERR(mdev->parent)) { @@ -1373,7 +1380,7 @@ exit_free: exit_ENOMEM: if (ret == 0 || ret == -ENOMEM) { ret = -ENOMEM; - pr_info("out of memory\n"); + dev_err(dev, "out of memory\n"); } return ret; } @@ -1392,11 +1399,6 @@ static void hdm_disconnect(struct usb_interface *interface) struct most_dev *mdev; mdev = usb_get_intfdata(interface); - if (unlikely(!mdev)) { - pr_info("failed to retrieve interface data\n"); - return; - } - mutex_lock(&mdev->io_mutex); usb_set_intfdata(interface, NULL); mdev->usb_device = NULL; @@ -1426,12 +1428,12 @@ static int __init hdm_usb_init(void) { pr_info("hdm_usb_init()\n"); if (usb_register(&hdm_usb)) { - pr_info("could not register hdm_usb driver\n"); + pr_err("could not register hdm_usb driver\n"); return -EIO; } schedule_usb_work = create_workqueue("hdmu_work"); if (schedule_usb_work == NULL) { - pr_info("could not create workqueue\n"); + pr_err("could not create workqueue\n"); usb_deregister(&hdm_usb); return -ENOMEM; } -- cgit v1.3-6-gb490 From b3c1a61744d02ca2c249dae04c8eb8f5b0822bc3 Mon Sep 17 00:00:00 2001 From: Michael Hornung Date: Fri, 31 Jul 2015 22:18:17 +0200 Subject: linux-next: drivers: staging: most: Fix return value * Fix sparse warning "Using plain integer as NULL pointer" Signed-off-by: Michael Hornung Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/aim-network/networking.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/most/aim-network/networking.c b/drivers/staging/most/aim-network/networking.c index 4639c49240f1..c8ab2399faad 100644 --- a/drivers/staging/most/aim-network/networking.c +++ b/drivers/staging/most/aim-network/networking.c @@ -311,7 +311,7 @@ static struct net_dev_context *get_net_dev_context( } } spin_unlock(&list_lock); - return 0; + return NULL; } static int aim_probe_channel(struct most_interface *iface, int channel_idx, -- cgit v1.3-6-gb490 From 7f44cb0ba88b40c09c5bdfc46186e09f42b1a9b0 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 31 Jul 2015 14:08:30 +0530 Subject: drivers: staging: Drop unlikely before IS_ERR(_OR_NULL) IS_ERR(_OR_NULL) already contain an 'unlikely' compiler flag and there is no need to do that again from its callers. Drop it. This also replaces an IS_ERR(x) + (x == NULL) check to IS_ERR_OR_NULL check. Signed-off-by: Viresh Kumar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ashmem.c | 2 +- drivers/staging/lustre/include/linux/libcfs/libcfs.h | 2 +- drivers/staging/lustre/lustre/obdclass/lu_object.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 7958d5c9663f..cefc208c313a 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -388,7 +388,7 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma) /* ... and allocate the backing shmem file */ vmfile = shmem_file_setup(name, asma->size, vma->vm_flags); - if (unlikely(IS_ERR(vmfile))) { + if (IS_ERR(vmfile)) { ret = PTR_ERR(vmfile); goto out; } diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h index 5dd9cdfae30c..d585041041c7 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h @@ -134,7 +134,7 @@ void cfs_get_random_bytes(void *buf, int size); /* container_of depends on "likely" which is defined in libcfs_private.h */ static inline void *__container_of(void *ptr, unsigned long shift) { - if (unlikely(IS_ERR(ptr) || ptr == NULL)) + if (IS_ERR_OR_NULL(ptr)) return ptr; return (char *)ptr - shift; } diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c index 9469a250d8dc..8e472327c880 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c @@ -602,7 +602,7 @@ static struct lu_object *lu_object_new(const struct lu_env *env, struct lu_site_bkt_data *bkt; o = lu_object_alloc(env, dev, f, conf); - if (unlikely(IS_ERR(o))) + if (IS_ERR(o)) return o; hs = dev->ld_site->ls_obj_hash; @@ -666,7 +666,7 @@ static struct lu_object *lu_object_find_try(const struct lu_env *env, * operations, including fld queries, inode loading, etc. */ o = lu_object_alloc(env, dev, f, conf); - if (unlikely(IS_ERR(o))) + if (IS_ERR(o)) return o; LASSERT(lu_fid_eq(lu_object_fid(o), f)); @@ -1558,7 +1558,7 @@ static int keys_fill(struct lu_context *ctx) LINVRNT(key->lct_index == i); value = key->lct_init(ctx, key); - if (unlikely(IS_ERR(value))) + if (IS_ERR(value)) return PTR_ERR(value); if (!(ctx->lc_tags & LCT_NOREF)) -- cgit v1.3-6-gb490 From 881bf281237c3eaf7759040653e779c6cc6c2e00 Mon Sep 17 00:00:00 2001 From: Alex Wilson Date: Fri, 31 Jul 2015 11:08:29 -0600 Subject: staging: panel: fix block comment usage Fixed two coding style warnings concerning multiline comments. Signed-off-by: Alex Wilson Signed-off-by: Greg Kroah-Hartman --- drivers/staging/panel/panel.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c index bda208da514e..3e9ee7ee6be2 100644 --- a/drivers/staging/panel/panel.c +++ b/drivers/staging/panel/panel.c @@ -781,14 +781,18 @@ static void long_sleep(int ms) schedule_timeout_interruptible(msecs_to_jiffies(ms)); } -/* send a serial byte to the LCD panel. The caller is responsible for locking - if needed. */ +/* + * send a serial byte to the LCD panel. The caller is responsible for locking + * if needed. + */ static void lcd_send_serial(int byte) { int bit; - /* the data bit is set on D0, and the clock on STROBE. - * LCD reads D0 on STROBE's rising edge. */ + /* + * the data bit is set on D0, and the clock on STROBE. + * LCD reads D0 on STROBE's rising edge. + */ for (bit = 0; bit < 8; bit++) { bits.cl = BIT_CLR; /* CLK low */ panel_set_bits(); -- cgit v1.3-6-gb490 From d1f0f3118e55ad80136d19dd4afdb32ccba26a42 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Jul 2015 18:48:21 +0300 Subject: Staging: rtl8192e: array overflow in rtl92e_set_swcam() "EntryNo" is comes from the user in the ioctl and it's a number between 0-255. The ieee->swcamtable[] array only has 32 elements so it can result in memory corruption. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index dc8c7a86bf93..c146b7e720a9 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -78,6 +78,10 @@ void rtl92e_set_swcam(struct net_device *dev, u8 EntryNo, u8 KeyIndex, RT_TRACE(COMP_DBG, "===========>%s():EntryNo is %d,KeyIndex is %d,KeyType is %d,is_mesh is %d\n", __func__, EntryNo, KeyIndex, KeyType, is_mesh); + + if (EntryNo >= TOTAL_CAM_ENTRY) + return; + if (!is_mesh) { ieee->swcamtable[EntryNo].bused = true; ieee->swcamtable[EntryNo].key_index = KeyIndex; -- cgit v1.3-6-gb490 From a9cf7250ba85427a372225067d57cf3ff4471047 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Jul 2015 18:49:25 +0300 Subject: staging: rtl8192e: don't just print an error and continue I was looking at how TOTAL_CAM_ENTRY is used and I saw this code. We print an error but continue writing "EntryNo" to a register as if it were valid. "EntryNo" is controlled by the user in rtl8192_ioctl() so it definitely can be invalid. I'm not positive what happens with the invalid data but it can't be good. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_cam.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c index c146b7e720a9..29dd93ac5e93 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c @@ -117,8 +117,10 @@ void rtl92e_set_key(struct net_device *dev, u8 EntryNo, u8 KeyIndex, } } priv->rtllib->is_set_key = true; - if (EntryNo >= TOTAL_CAM_ENTRY) + if (EntryNo >= TOTAL_CAM_ENTRY) { netdev_info(dev, "%s(): Invalid CAM entry\n", __func__); + return; + } RT_TRACE(COMP_SEC, "====>to rtl92e_set_key(), dev:%p, EntryNo:%d, KeyIndex:%d,KeyType:%d, MacAddr %pM\n", -- cgit v1.3-6-gb490 From c15a7009325b84adac2eb0f3919d9c3ff8d5ed11 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 30 Jul 2015 00:36:32 +0300 Subject: staging: comedi: das16: remove a duplicate condition We checked that "it->options[3]" was non-zero on the line before so there is no need to check again. Signed-off-by: Dan Carpenter Reviewed-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/das16.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index d7cf4b153f7c..056bca9c67d5 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -1032,8 +1032,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* check that clock setting is valid */ if (it->options[3]) { - if (it->options[3] != 0 && - it->options[3] != 1 && it->options[3] != 10) { + if (it->options[3] != 1 && it->options[3] != 10) { dev_err(dev->class_dev, "Invalid option. Master clock must be set to 1 or 10 (MHz)\n"); return -EINVAL; -- cgit v1.3-6-gb490 From 74214e526e605f155ba2609c516cf866ae965316 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 28 Jul 2015 23:31:37 +0200 Subject: staging: rtl8192e: Remove rtl8192_phy_updateInitGain Function is empty and called only once. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 1 - drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c | 4 ---- drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h | 1 - 3 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 1013101309e8..6d6060390182 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -872,7 +872,6 @@ start: } RT_TRACE(COMP_INIT, "RF Config Finished!\n"); } - rtl8192_phy_updateInitGain(dev); rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bCCKEn, 0x1); rtl92e_set_bb_reg(dev, rFPGA0_RFMOD, bOFDMEn, 0x1); diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c index 7acae7d49c91..3a15a0f5b479 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c @@ -712,10 +712,6 @@ bool rtl92e_config_phy(struct net_device *dev) return rtStatus; } -void rtl8192_phy_updateInitGain(struct net_device *dev) -{ -} - u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath) { diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h index da25cba6aeb6..350d3063df72 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h @@ -86,7 +86,6 @@ extern bool rtl92e_config_bb(struct net_device *dev); extern void rtl92e_get_tx_power(struct net_device *dev); extern void rtl92e_set_tx_power(struct net_device *dev, u8 channel); extern bool rtl92e_config_phy(struct net_device *dev); -extern void rtl8192_phy_updateInitGain(struct net_device *dev); extern u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath); -- cgit v1.3-6-gb490 From 45f57357f2a4ac71e4df7d3ca1a4ea234856d399 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 28 Jul 2015 23:31:38 +0200 Subject: staging: rtl8192e: Remove ActUpdateChannelAccessSetting Function is empty and called only once. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 6 ------ drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 3 --- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 4 ---- 3 files changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index 6d6060390182..f8ad81e8fb1f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2388,9 +2388,3 @@ bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev) return Reval; } - -void ActUpdateChannelAccessSetting(struct net_device *dev, - enum wireless_mode WirelessMode, - struct channel_access_setting *ChnlAccessSetting) -{ -} diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index f0e175def6a4..584b78cd90b7 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -737,9 +737,6 @@ void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode) priv->rtllib->mode = wireless_mode; - ActUpdateChannelAccessSetting(dev, wireless_mode, - &priv->ChannelAccessSetting); - if ((wireless_mode == WIRELESS_MODE_N_24G) || (wireless_mode == WIRELESS_MODE_N_5G)) { priv->rtllib->pHTInfo->bEnableHT = 1; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index 20df4e20edf2..bdb50323f61b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -619,8 +619,4 @@ bool rtl92e_set_rf_state(struct net_device *dev, enum rt_rf_power_state StateToSet, RT_RF_CHANGE_SOURCE ChangeSource, bool ProtectOrNot); -void ActUpdateChannelAccessSetting(struct net_device *dev, - enum wireless_mode WirelessMode, - struct channel_access_setting *ChnlAccessSetting); - #endif -- cgit v1.3-6-gb490 From f971e9f3ba70eac49ab9fbaa4f5bd5dfbaf9fe7b Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 28 Jul 2015 23:31:39 +0200 Subject: staging: rtl8192e: Remove rtl8192_data_hard_stop Function is empty; rtllib checks if handler is NULL. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 584b78cd90b7..14fc2785b5a4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -90,7 +90,6 @@ static struct pci_driver rtl8192_pci_driver = { static short rtl8192_is_tx_queue_empty(struct net_device *dev); static void rtl819x_watchdog_wqcallback(void *data); static void watch_dog_timer_callback(unsigned long data); -static void rtl8192_data_hard_stop(struct net_device *dev); static void rtl8192_data_hard_resume(struct net_device *dev); static void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int rate); @@ -866,7 +865,6 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->set_chan = rtl8192_set_chan; priv->rtllib->link_change = priv->ops->link_change; priv->rtllib->softmac_data_hard_start_xmit = rtl8192_hard_data_xmit; - priv->rtllib->data_hard_stop = rtl8192_data_hard_stop; priv->rtllib->data_hard_resume = rtl8192_data_hard_resume; priv->rtllib->check_nic_enough_desc = rtl8192_check_nic_enough_desc; priv->rtllib->handle_assoc_response = rtl8192_handle_assoc_response; @@ -1641,10 +1639,6 @@ static void rtl8192_free_tx_ring(struct net_device *dev, unsigned int prio) ring->desc = NULL; } -static void rtl8192_data_hard_stop(struct net_device *dev) -{ -} - static void rtl8192_data_hard_resume(struct net_device *dev) { } -- cgit v1.3-6-gb490 From f2d4d4e1e203a242e98ee4038db0af37d5ac107b Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 28 Jul 2015 23:31:40 +0200 Subject: staging: rtl8192e: Remove rtl8192_data_hard_resume Function is empty; rtllib checks if handler is NULL. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 14fc2785b5a4..4157f8a58409 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -90,7 +90,6 @@ static struct pci_driver rtl8192_pci_driver = { static short rtl8192_is_tx_queue_empty(struct net_device *dev); static void rtl819x_watchdog_wqcallback(void *data); static void watch_dog_timer_callback(unsigned long data); -static void rtl8192_data_hard_resume(struct net_device *dev); static void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int rate); static int rtl8192_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); @@ -865,7 +864,6 @@ static void rtl8192_init_priv_handler(struct net_device *dev) priv->rtllib->set_chan = rtl8192_set_chan; priv->rtllib->link_change = priv->ops->link_change; priv->rtllib->softmac_data_hard_start_xmit = rtl8192_hard_data_xmit; - priv->rtllib->data_hard_resume = rtl8192_data_hard_resume; priv->rtllib->check_nic_enough_desc = rtl8192_check_nic_enough_desc; priv->rtllib->handle_assoc_response = rtl8192_handle_assoc_response; priv->rtllib->handle_beacon = rtl8192_handle_beacon; @@ -1365,8 +1363,6 @@ RESET_START: rtllib_start_send_beacons(ieee); - if (ieee->data_hard_resume) - ieee->data_hard_resume(ieee->dev); netif_carrier_on(ieee->dev); } else if (ieee->iw_mode == IW_MODE_MESH) { rtl819x_silentreset_mesh_bk(dev, IsPortal); @@ -1639,10 +1635,6 @@ static void rtl8192_free_tx_ring(struct net_device *dev, unsigned int prio) ring->desc = NULL; } -static void rtl8192_data_hard_resume(struct net_device *dev) -{ -} - static void rtl8192_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, int rate) { -- cgit v1.3-6-gb490 From 2937a5d272031eb3e189d4383587bc9f62621c43 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 28 Jul 2015 23:31:41 +0200 Subject: staging: rtl8192e: MgntActSet_RF_State: remove ProtectOrNot parameter It is set at the very beginning of function to a constant value. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 8 ++-- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 60 +++++++++++--------------- drivers/staging/rtl8192e/rtl8192e/rtl_core.h | 3 +- drivers/staging/rtl8192e/rtl8192e/rtl_dm.c | 3 +- drivers/staging/rtl8192e/rtl8192e/rtl_pm.c | 4 +- drivers/staging/rtl8192e/rtl8192e/rtl_ps.c | 7 ++- 6 files changed, 36 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index f8ad81e8fb1f..b2f307f3a442 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -882,19 +882,17 @@ start: RT_TRACE((COMP_INIT | COMP_RF | COMP_POWER), "%s(): Turn off RF for RegRfOff ----------\n", __func__); - rtl92e_set_rf_state(dev, eRfOff, RF_CHANGE_BY_SW, true); + rtl92e_set_rf_state(dev, eRfOff, RF_CHANGE_BY_SW); } else if (priv->rtllib->RfOffReason > RF_CHANGE_BY_PS) { RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), "%s(): Turn off RF for RfOffReason(%d) ----------\n", __func__, priv->rtllib->RfOffReason); - rtl92e_set_rf_state(dev, eRfOff, priv->rtllib->RfOffReason, - true); + rtl92e_set_rf_state(dev, eRfOff, priv->rtllib->RfOffReason); } else if (priv->rtllib->RfOffReason >= RF_CHANGE_BY_IPS) { RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), "%s(): Turn off RF for RfOffReason(%d) ----------\n", __func__, priv->rtllib->RfOffReason); - rtl92e_set_rf_state(dev, eRfOff, priv->rtllib->RfOffReason, - true); + rtl92e_set_rf_state(dev, eRfOff, priv->rtllib->RfOffReason); } else { RT_TRACE((COMP_INIT|COMP_RF|COMP_POWER), "%s(): RF-ON\n", __func__); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 4157f8a58409..0033cfb21351 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -149,8 +149,7 @@ void rtl92e_writew(struct net_device *dev, int x, u16 y) *****************************************************************************/ bool rtl92e_set_rf_state(struct net_device *dev, enum rt_rf_power_state StateToSet, - RT_RF_CHANGE_SOURCE ChangeSource, - bool ProtectOrNot) + RT_RF_CHANGE_SOURCE ChangeSource) { struct r8192_priv *priv = rtllib_priv(dev); struct rtllib_device *ieee = priv->rtllib; @@ -163,37 +162,32 @@ bool rtl92e_set_rf_state(struct net_device *dev, RT_TRACE((COMP_PS | COMP_RF), "===>rtl92e_set_rf_state(): StateToSet(%d)\n", StateToSet); - ProtectOrNot = false; - + while (true) { + spin_lock_irqsave(&priv->rf_ps_lock, flag); + if (priv->RFChangeInProgress) { + spin_unlock_irqrestore(&priv->rf_ps_lock, flag); + RT_TRACE((COMP_PS | COMP_RF), + "rtl92e_set_rf_state(): RF Change in progress! Wait to set..StateToSet(%d).\n", + StateToSet); - if (!ProtectOrNot) { - while (true) { - spin_lock_irqsave(&priv->rf_ps_lock, flag); - if (priv->RFChangeInProgress) { - spin_unlock_irqrestore(&priv->rf_ps_lock, flag); + while (priv->RFChangeInProgress) { + RFWaitCounter++; RT_TRACE((COMP_PS | COMP_RF), - "rtl92e_set_rf_state(): RF Change in progress! Wait to set..StateToSet(%d).\n", - StateToSet); - - while (priv->RFChangeInProgress) { - RFWaitCounter++; - RT_TRACE((COMP_PS | COMP_RF), - "rtl92e_set_rf_state(): Wait 1 ms (%d times)...\n", - RFWaitCounter); - mdelay(1); - - if (RFWaitCounter > 100) { - netdev_warn(dev, - "%s(): Timeout waiting for RF change.\n", - __func__); - return false; - } + "rtl92e_set_rf_state(): Wait 1 ms (%d times)...\n", + RFWaitCounter); + mdelay(1); + + if (RFWaitCounter > 100) { + netdev_warn(dev, + "%s(): Timeout waiting for RF change.\n", + __func__); + return false; } - } else { - priv->RFChangeInProgress = true; - spin_unlock_irqrestore(&priv->rf_ps_lock, flag); - break; } + } else { + priv->RFChangeInProgress = true; + spin_unlock_irqrestore(&priv->rf_ps_lock, flag); + break; } } @@ -270,11 +264,9 @@ bool rtl92e_set_rf_state(struct net_device *dev, StateToSet, ChangeSource, priv->rtllib->RfOffReason); } - if (!ProtectOrNot) { - spin_lock_irqsave(&priv->rf_ps_lock, flag); - priv->RFChangeInProgress = false; - spin_unlock_irqrestore(&priv->rf_ps_lock, flag); - } + spin_lock_irqsave(&priv->rf_ps_lock, flag); + priv->RFChangeInProgress = false; + spin_unlock_irqrestore(&priv->rf_ps_lock, flag); RT_TRACE((COMP_PS | COMP_RF), "<===rtl92e_set_rf_state()\n"); return bActionAllowed; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h index bdb50323f61b..cd948bb13840 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h @@ -617,6 +617,5 @@ bool rtl92e_disable_nic(struct net_device *dev); bool rtl92e_set_rf_state(struct net_device *dev, enum rt_rf_power_state StateToSet, - RT_RF_CHANGE_SOURCE ChangeSource, - bool ProtectOrNot); + RT_RF_CHANGE_SOURCE ChangeSource); #endif diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 458097ee09e7..1a0c690bfa07 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -1888,8 +1888,7 @@ static void dm_CheckRfCtrlGPIO(void *data) if (bActuallySet) { mdelay(1000); priv->bHwRfOffAction = 1; - rtl92e_set_rf_state(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW, - true); + rtl92e_set_rf_state(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW); if (priv->bHwRadioOff) argv[1] = "RFOFF"; else diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c index c224adedaf62..b0268fdc100f 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c @@ -45,7 +45,7 @@ int rtl92e_suspend(struct pci_dev *pdev, pm_message_t state) netif_device_detach(dev); if (!priv->rtllib->bSupportRemoteWakeUp) { - rtl92e_set_rf_state(dev, eRfOff, RF_CHANGE_BY_INIT, true); + rtl92e_set_rf_state(dev, eRfOff, RF_CHANGE_BY_INIT); ulRegRead = rtl92e_readl(dev, CPU_GEN); ulRegRead |= CPU_GEN_SYSTEM_RESET; rtl92e_writel(dev, CPU_GEN, ulRegRead); @@ -108,7 +108,7 @@ int rtl92e_resume(struct pci_dev *pdev) dev->netdev_ops->ndo_open(dev); if (!priv->rtllib->bSupportRemoteWakeUp) - rtl92e_set_rf_state(dev, eRfOn, RF_CHANGE_BY_INIT, true); + rtl92e_set_rf_state(dev, eRfOn, RF_CHANGE_BY_INIT); out: RT_TRACE(COMP_POWER, "<================r8192E resume call.\n"); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c index 38addad24f18..f09560d60dc4 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_ps.c @@ -45,7 +45,7 @@ static void rtl8192_hw_sleep_down(struct net_device *dev) spin_unlock_irqrestore(&priv->rf_ps_lock, flags); RT_TRACE(COMP_DBG, "%s()============>come to sleep down\n", __func__); - rtl92e_set_rf_state(dev, eRfSleep, RF_CHANGE_BY_PS, false); + rtl92e_set_rf_state(dev, eRfSleep, RF_CHANGE_BY_PS); } void rtl92e_hw_sleep_wq(void *data) @@ -74,7 +74,7 @@ void rtl92e_hw_wakeup(struct net_device *dev) } spin_unlock_irqrestore(&priv->rf_ps_lock, flags); RT_TRACE(COMP_PS, "%s()============>come to wake up\n", __func__); - rtl92e_set_rf_state(dev, eRfOn, RF_CHANGE_BY_PS, false); + rtl92e_set_rf_state(dev, eRfOn, RF_CHANGE_BY_PS); } void rtl92e_hw_wakeup_wq(void *data) @@ -133,8 +133,7 @@ static void InactivePsWorkItemCallback(struct net_device *dev) RT_TRACE(COMP_PS, "InactivePsWorkItemCallback(): Set RF to %s.\n", pPSC->eInactivePowerState == eRfOff ? "OFF" : "ON"); - rtl92e_set_rf_state(dev, pPSC->eInactivePowerState, RF_CHANGE_BY_IPS, - false); + rtl92e_set_rf_state(dev, pPSC->eInactivePowerState, RF_CHANGE_BY_IPS); pPSC->bSwRfProcessing = false; RT_TRACE(COMP_PS, "InactivePsWorkItemCallback() <---------\n"); -- cgit v1.3-6-gb490 From 99d4f5d236eb6a1eaaddb7179a251f385f7e4c2b Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 28 Jul 2015 23:31:42 +0200 Subject: staging: rtl8192e: Simplify rtl92e_is_halfn_supported_by_ap Function should return struct member - no extra logic is needed. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c index b2f307f3a442..c28cabc23fc0 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c @@ -2375,14 +2375,8 @@ bool rtl92e_get_nmode_support_by_sec(struct net_device *dev) bool rtl92e_is_halfn_supported_by_ap(struct net_device *dev) { - bool Reval; struct r8192_priv *priv = rtllib_priv(dev); struct rtllib_device *ieee = priv->rtllib; - if (ieee->bHalfWirelessN24GMode == true) - Reval = true; - else - Reval = false; - - return Reval; + return ieee->bHalfWirelessN24GMode; } -- cgit v1.3-6-gb490 From 72f1f75257de812137ee5110822370fadc4927f6 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 28 Jul 2015 23:31:43 +0200 Subject: staging: rtl8192e: Simplify rtl92e_set_bandwidth Move phy version check outside of the loop. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 53 ++++++++-------------- 1 file changed, 18 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index e5f4c2df69fd..85f9341ac281 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -28,49 +28,32 @@ void rtl92e_set_bandwidth(struct net_device *dev, u8 eRFPath; struct r8192_priv *priv = rtllib_priv(dev); + if (priv->card_8192_version != VERSION_8190_BD && + priv->card_8192_version != VERSION_8190_BE) { + netdev_warn(dev, "%s(): Unknown HW version.\n", __func__); + return; + } + for (eRFPath = 0; eRFPath < priv->NumTotalRFPath; eRFPath++) { if (!rtl92e_is_legal_rf_path(dev, eRFPath)) continue; switch (Bandwidth) { case HT_CHANNEL_WIDTH_20: - if (priv->card_8192_version == VERSION_8190_BD || - priv->card_8192_version == VERSION_8190_BE) { - rtl92e_set_rf_reg(dev, - (enum rf90_radio_path)eRFPath, - 0x0b, bMask12Bits, 0x100); - rtl92e_set_rf_reg(dev, - (enum rf90_radio_path)eRFPath, - 0x2c, bMask12Bits, 0x3d7); - rtl92e_set_rf_reg(dev, - (enum rf90_radio_path)eRFPath, - 0x0e, bMask12Bits, 0x021); - - } else { - netdev_warn(dev, "%s(): Unknown HW version.\n", - __func__); - } - + rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, + 0x0b, bMask12Bits, 0x100); + rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, + 0x2c, bMask12Bits, 0x3d7); + rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, + 0x0e, bMask12Bits, 0x021); break; case HT_CHANNEL_WIDTH_20_40: - if (priv->card_8192_version == VERSION_8190_BD || - priv->card_8192_version == VERSION_8190_BE) { - rtl92e_set_rf_reg(dev, - (enum rf90_radio_path)eRFPath, - 0x0b, bMask12Bits, 0x300); - rtl92e_set_rf_reg(dev, - (enum rf90_radio_path)eRFPath, - 0x2c, bMask12Bits, 0x3ff); - rtl92e_set_rf_reg(dev, - (enum rf90_radio_path)eRFPath, - 0x0e, bMask12Bits, 0x0e1); - - } else { - netdev_warn(dev, "%s(): Unknown HW version.\n", - __func__); - } - - + rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, + 0x0b, bMask12Bits, 0x300); + rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, + 0x2c, bMask12Bits, 0x3ff); + rtl92e_set_rf_reg(dev, (enum rf90_radio_path)eRFPath, + 0x0e, bMask12Bits, 0x0e1); break; default: netdev_err(dev, "%s(): Unknown bandwidth: %#X\n", -- cgit v1.3-6-gb490 From 90959c3dfcb66cd8467ba0921469b62e42d7879c Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 28 Jul 2015 23:31:44 +0200 Subject: staging: rtl8192e: Remove phy_RF8256_Config_ParaFile Merge function into rtl92e_config_rf as having them separated gives no benefit. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index 85f9341ac281..194d64cf24ea 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -64,7 +64,7 @@ void rtl92e_set_bandwidth(struct net_device *dev, } } -static bool phy_RF8256_Config_ParaFile(struct net_device *dev) +bool rtl92e_config_rf(struct net_device *dev) { u32 u4RegValue = 0; u8 eRFPath; @@ -77,6 +77,8 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) u8 ConstRetryTimes = 5, RetryTimes = 5; u8 ret = 0; + priv->NumTotalRFPath = RTL819X_TOTAL_RF_PATH; + for (eRFPath = (enum rf90_radio_path)RF90_PATH_A; eRFPath < priv->NumTotalRFPath; eRFPath++) { if (!rtl92e_is_legal_rf_path(dev, eRFPath)) @@ -115,7 +117,7 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) if (!rtStatus) { netdev_err(dev, "%s(): Failed to check RF Path %d.\n", __func__, eRFPath); - goto phy_RF8256_Config_ParaFile_Fail; + goto fail; } RetryTimes = ConstRetryTimes; @@ -203,7 +205,7 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) netdev_err(dev, "%s(): Failed to initialize RF Path %d.\n", __func__, eRFPath); - goto phy_RF8256_Config_ParaFile_Fail; + goto fail; } } @@ -211,18 +213,10 @@ static bool phy_RF8256_Config_ParaFile(struct net_device *dev) RT_TRACE(COMP_PHY, "PHY Initialization Success\n"); return true; -phy_RF8256_Config_ParaFile_Fail: +fail: return false; } -bool rtl92e_config_rf(struct net_device *dev) -{ - struct r8192_priv *priv = rtllib_priv(dev); - - priv->NumTotalRFPath = RTL819X_TOTAL_RF_PATH; - return phy_RF8256_Config_ParaFile(dev); -} - void rtl92e_set_cck_tx_power(struct net_device *dev, u8 powerlevel) { u32 TxAGC = 0; -- cgit v1.3-6-gb490 From 976a06cc89e817e94b0d87cf55bb46134c494060 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 28 Jul 2015 23:31:45 +0200 Subject: staging: rtl8192e: Fix IW_IOCTL macro Macro caused checkpatch complaints - replace [] braces with () and use [] braces as array initializers. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_wx.c | 68 +++++++++++++++--------------- 1 file changed, 34 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index 183d1b2e64f1..7e3ca7ef997b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -1115,41 +1115,41 @@ static int r8192_wx_get_PromiscuousMode(struct net_device *dev, } -#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] +#define IW_IOCTL(x) ((x) - SIOCSIWCOMMIT) static iw_handler r8192_wx_handlers[] = { - IW_IOCTL(SIOCGIWNAME) = r8192_wx_get_name, - IW_IOCTL(SIOCSIWFREQ) = r8192_wx_set_freq, - IW_IOCTL(SIOCGIWFREQ) = r8192_wx_get_freq, - IW_IOCTL(SIOCSIWMODE) = r8192_wx_set_mode, - IW_IOCTL(SIOCGIWMODE) = r8192_wx_get_mode, - IW_IOCTL(SIOCSIWSENS) = r8192_wx_set_sens, - IW_IOCTL(SIOCGIWSENS) = r8192_wx_get_sens, - IW_IOCTL(SIOCGIWRANGE) = rtl8192_wx_get_range, - IW_IOCTL(SIOCSIWAP) = r8192_wx_set_wap, - IW_IOCTL(SIOCGIWAP) = r8192_wx_get_wap, - IW_IOCTL(SIOCSIWSCAN) = r8192_wx_set_scan, - IW_IOCTL(SIOCGIWSCAN) = r8192_wx_get_scan, - IW_IOCTL(SIOCSIWESSID) = r8192_wx_set_essid, - IW_IOCTL(SIOCGIWESSID) = r8192_wx_get_essid, - IW_IOCTL(SIOCSIWNICKN) = r8192_wx_set_nick, - IW_IOCTL(SIOCGIWNICKN) = r8192_wx_get_nick, - IW_IOCTL(SIOCSIWRATE) = r8192_wx_set_rate, - IW_IOCTL(SIOCGIWRATE) = r8192_wx_get_rate, - IW_IOCTL(SIOCSIWRTS) = r8192_wx_set_rts, - IW_IOCTL(SIOCGIWRTS) = r8192_wx_get_rts, - IW_IOCTL(SIOCSIWFRAG) = r8192_wx_set_frag, - IW_IOCTL(SIOCGIWFRAG) = r8192_wx_get_frag, - IW_IOCTL(SIOCSIWRETRY) = r8192_wx_set_retry, - IW_IOCTL(SIOCGIWRETRY) = r8192_wx_get_retry, - IW_IOCTL(SIOCSIWENCODE) = r8192_wx_set_enc, - IW_IOCTL(SIOCGIWENCODE) = r8192_wx_get_enc, - IW_IOCTL(SIOCSIWPOWER) = r8192_wx_set_power, - IW_IOCTL(SIOCGIWPOWER) = r8192_wx_get_power, - IW_IOCTL(SIOCSIWGENIE) = r8192_wx_set_gen_ie, - IW_IOCTL(SIOCGIWGENIE) = r8192_wx_get_gen_ie, - IW_IOCTL(SIOCSIWMLME) = r8192_wx_set_mlme, - IW_IOCTL(SIOCSIWAUTH) = r8192_wx_set_auth, - IW_IOCTL(SIOCSIWENCODEEXT) = r8192_wx_set_enc_ext, + [IW_IOCTL(SIOCGIWNAME)] = r8192_wx_get_name, + [IW_IOCTL(SIOCSIWFREQ)] = r8192_wx_set_freq, + [IW_IOCTL(SIOCGIWFREQ)] = r8192_wx_get_freq, + [IW_IOCTL(SIOCSIWMODE)] = r8192_wx_set_mode, + [IW_IOCTL(SIOCGIWMODE)] = r8192_wx_get_mode, + [IW_IOCTL(SIOCSIWSENS)] = r8192_wx_set_sens, + [IW_IOCTL(SIOCGIWSENS)] = r8192_wx_get_sens, + [IW_IOCTL(SIOCGIWRANGE)] = rtl8192_wx_get_range, + [IW_IOCTL(SIOCSIWAP)] = r8192_wx_set_wap, + [IW_IOCTL(SIOCGIWAP)] = r8192_wx_get_wap, + [IW_IOCTL(SIOCSIWSCAN)] = r8192_wx_set_scan, + [IW_IOCTL(SIOCGIWSCAN)] = r8192_wx_get_scan, + [IW_IOCTL(SIOCSIWESSID)] = r8192_wx_set_essid, + [IW_IOCTL(SIOCGIWESSID)] = r8192_wx_get_essid, + [IW_IOCTL(SIOCSIWNICKN)] = r8192_wx_set_nick, + [IW_IOCTL(SIOCGIWNICKN)] = r8192_wx_get_nick, + [IW_IOCTL(SIOCSIWRATE)] = r8192_wx_set_rate, + [IW_IOCTL(SIOCGIWRATE)] = r8192_wx_get_rate, + [IW_IOCTL(SIOCSIWRTS)] = r8192_wx_set_rts, + [IW_IOCTL(SIOCGIWRTS)] = r8192_wx_get_rts, + [IW_IOCTL(SIOCSIWFRAG)] = r8192_wx_set_frag, + [IW_IOCTL(SIOCGIWFRAG)] = r8192_wx_get_frag, + [IW_IOCTL(SIOCSIWRETRY)] = r8192_wx_set_retry, + [IW_IOCTL(SIOCGIWRETRY)] = r8192_wx_get_retry, + [IW_IOCTL(SIOCSIWENCODE)] = r8192_wx_set_enc, + [IW_IOCTL(SIOCGIWENCODE)] = r8192_wx_get_enc, + [IW_IOCTL(SIOCSIWPOWER)] = r8192_wx_set_power, + [IW_IOCTL(SIOCGIWPOWER)] = r8192_wx_get_power, + [IW_IOCTL(SIOCSIWGENIE)] = r8192_wx_set_gen_ie, + [IW_IOCTL(SIOCGIWGENIE)] = r8192_wx_get_gen_ie, + [IW_IOCTL(SIOCSIWMLME)] = r8192_wx_set_mlme, + [IW_IOCTL(SIOCSIWAUTH)] = r8192_wx_set_auth, + [IW_IOCTL(SIOCSIWENCODEEXT)] = r8192_wx_set_enc_ext, }; /* the following rule need to be following, -- cgit v1.3-6-gb490 From cb7cca3ae8f152151104252298d2e1e91db6df92 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 28 Jul 2015 23:31:46 +0200 Subject: staging: rtl8192e: Drop large switch in rtl92e_config_rf The same steps were made for each RF path independently. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c | 69 +++------------------- 1 file changed, 9 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c index 194d64cf24ea..c8f25ade2535 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8190P_rtl8256.c @@ -122,70 +122,19 @@ bool rtl92e_config_rf(struct net_device *dev) RetryTimes = ConstRetryTimes; RF3_Final_Value = 0; - switch (eRFPath) { - case RF90_PATH_A: - while (RF3_Final_Value != RegValueToBeCheck && - RetryTimes != 0) { - ret = rtl92e_config_rf_path(dev, - (enum rf90_radio_path)eRFPath); - RF3_Final_Value = rtl92e_get_rf_reg(dev, - (enum rf90_radio_path)eRFPath, - RegOffSetToBeCheck, - bMask12Bits); - RT_TRACE(COMP_RF, - "RF %d %d register final value: %x\n", - eRFPath, RegOffSetToBeCheck, - RF3_Final_Value); - RetryTimes--; - } - break; - case RF90_PATH_B: - while (RF3_Final_Value != RegValueToBeCheck && - RetryTimes != 0) { - ret = rtl92e_config_rf_path(dev, + while (RF3_Final_Value != RegValueToBeCheck && + RetryTimes != 0) { + ret = rtl92e_config_rf_path(dev, (enum rf90_radio_path)eRFPath); - RF3_Final_Value = rtl92e_get_rf_reg(dev, - (enum rf90_radio_path)eRFPath, - RegOffSetToBeCheck, - bMask12Bits); - RT_TRACE(COMP_RF, - "RF %d %d register final value: %x\n", - eRFPath, RegOffSetToBeCheck, - RF3_Final_Value); - RetryTimes--; - } - break; - case RF90_PATH_C: - while (RF3_Final_Value != RegValueToBeCheck && - RetryTimes != 0) { - ret = rtl92e_config_rf_path(dev, - (enum rf90_radio_path)eRFPath); - RF3_Final_Value = rtl92e_get_rf_reg(dev, + RF3_Final_Value = rtl92e_get_rf_reg(dev, (enum rf90_radio_path)eRFPath, RegOffSetToBeCheck, bMask12Bits); - RT_TRACE(COMP_RF, - "RF %d %d register final value: %x\n", - eRFPath, RegOffSetToBeCheck, - RF3_Final_Value); - RetryTimes--; - } - break; - case RF90_PATH_D: - while (RF3_Final_Value != RegValueToBeCheck && - RetryTimes != 0) { - ret = rtl92e_config_rf_path(dev, - (enum rf90_radio_path)eRFPath); - RF3_Final_Value = rtl92e_get_rf_reg(dev, - (enum rf90_radio_path)eRFPath, - RegOffSetToBeCheck, bMask12Bits); - RT_TRACE(COMP_RF, - "RF %d %d register final value: %x\n", - eRFPath, RegOffSetToBeCheck, - RF3_Final_Value); - RetryTimes--; - } - break; + RT_TRACE(COMP_RF, + "RF %d %d register final value: %x\n", + eRFPath, RegOffSetToBeCheck, + RF3_Final_Value); + RetryTimes--; } switch (eRFPath) { -- cgit v1.3-6-gb490 From 948fa942dc6bb4000bdf94901e99570b7636ed7c Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Tue, 28 Jul 2015 23:31:47 +0200 Subject: staging: rtl8192e: probe: iounmap mmio when probe fails In case of probe failure, io memory was not released properly. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/rtl_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 0033cfb21351..c868cb373a4b 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -2642,12 +2642,12 @@ static int rtl8192_pci_probe(struct pci_dev *pdev, pci_read_config_byte(pdev, 0x08, &revision_id); /* If the revisionid is 0x10, the device uses rtl8192se. */ if (pdev->device == 0x8192 && revision_id == 0x10) - goto err_rel_mem; + goto err_unmap; priv->ops = ops; if (rtl92e_check_adapter(pdev, dev) == false) - goto err_rel_mem; + goto err_unmap; dev->irq = pdev->irq; priv->irq = 0; @@ -2688,6 +2688,8 @@ static int rtl8192_pci_probe(struct pci_dev *pdev, err_free_irq: free_irq(dev->irq, dev); priv->irq = 0; +err_unmap: + iounmap((void __iomem *)ioaddr); err_rel_mem: release_mem_region(pmem_start, pmem_len); err_rel_rtllib: -- cgit v1.3-6-gb490 From 2cac1f700c2c6baf836f24c778a73a847a48f484 Mon Sep 17 00:00:00 2001 From: Radivoje Jovanovic Date: Fri, 31 Jul 2015 08:07:10 -0700 Subject: powercap / RAPL: Add support for Skylake H/S This patche enabled RAPL to support Intel Skylake H/S Signed-off-by: Radivoje Jovanovic Signed-off-by: Rafael J. Wysocki --- drivers/powercap/intel_rapl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index 482b22ddc7b2..bca9620b5d38 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -1101,6 +1101,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { RAPL_CPU(0x4A, rapl_defaults_tng),/* Tangier */ RAPL_CPU(0x56, rapl_defaults_core),/* Future Xeon */ RAPL_CPU(0x5A, rapl_defaults_ann),/* Annidale */ + RAPL_CPU(0x5E, rapl_defaults_core),/* Skylake-H/S */ RAPL_CPU(0x57, rapl_defaults_hsw_server),/* Knights Landing */ {} }; -- cgit v1.3-6-gb490 From 4e0bec9e833a6884dc2e242e45e0ebd99f46624e Mon Sep 17 00:00:00 2001 From: Radivoje Jovanovic Date: Fri, 31 Jul 2015 08:07:36 -0700 Subject: powercap / RAPL: Add support for Broadwell-H This patch enabled RAPL to support Broadwell-H Signed-off-by: Radivoje Jovanovic Signed-off-by: Rafael J. Wysocki --- drivers/powercap/intel_rapl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index bca9620b5d38..a5eddfbb0230 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -1096,6 +1096,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { RAPL_CPU(0x3f, rapl_defaults_hsw_server),/* Haswell servers */ RAPL_CPU(0x4f, rapl_defaults_hsw_server),/* Broadwell servers */ RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */ + RAPL_CPU(0x47, rapl_defaults_core),/* Broadwell-H */ RAPL_CPU(0x4E, rapl_defaults_core),/* Skylake */ RAPL_CPU(0x4C, rapl_defaults_cht),/* Braswell/Cherryview */ RAPL_CPU(0x4A, rapl_defaults_tng),/* Tangier */ -- cgit v1.3-6-gb490 From 9d8c94e48a5faafae1e52bec18b8d99211b2ccd4 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 31 Jul 2015 14:08:31 +0530 Subject: drivers: target: Drop unlikely before IS_ERR(_OR_NULL) IS_ERR(_OR_NULL) already contain an 'unlikely' compiler flag and there is no need to do that again from its callers. Drop it. Signed-off-by: Viresh Kumar Signed-off-by: Nicholas Bellinger --- drivers/target/tcm_fc/tfc_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 68031723e5be..aa3caca8bace 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -255,7 +255,7 @@ static void ft_recv_seq(struct fc_seq *sp, struct fc_frame *fp, void *arg) struct ft_cmd *cmd = arg; struct fc_frame_header *fh; - if (unlikely(IS_ERR(fp))) { + if (IS_ERR(fp)) { /* XXX need to find cmd if queued */ cmd->seq = NULL; cmd->aborted = true; -- cgit v1.3-6-gb490 From 36f024ed8fc96f50f01d171097237ebe51dadee7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 31 Jul 2015 22:12:29 +0200 Subject: PCI/MSI: pci-xgene-msi: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Duc Dang --- drivers/pci/host/pci-xgene-msi.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-xgene-msi.c b/drivers/pci/host/pci-xgene-msi.c index ec5a14b3189b..23456b90ca0b 100644 --- a/drivers/pci/host/pci-xgene-msi.c +++ b/drivers/pci/host/pci-xgene-msi.c @@ -368,10 +368,8 @@ static int xgene_msi_remove(struct platform_device *pdev) for (i = 0; i < NR_HW_IRQS; i++) { virq = msi->msi_groups[i].gic_irq; - if (virq != 0) { - irq_set_chained_handler(virq, NULL); - irq_set_handler_data(virq, NULL); - } + if (virq != 0) + irq_set_chained_handler_and_data(virq, NULL, NULL); } kfree(msi->msi_groups); @@ -421,8 +419,8 @@ static int xgene_msi_hwirq_alloc(unsigned int cpu) } if (err) { - irq_set_chained_handler(msi_group->gic_irq, NULL); - irq_set_handler_data(msi_group->gic_irq, NULL); + irq_set_chained_handler_and_data(msi_group->gic_irq, + NULL, NULL); return err; } } @@ -441,8 +439,8 @@ static void xgene_msi_hwirq_free(unsigned int cpu) if (!msi_group->gic_irq) continue; - irq_set_chained_handler(msi_group->gic_irq, NULL); - irq_set_handler_data(msi_group->gic_irq, NULL); + irq_set_chained_handler_and_data(msi_group->gic_irq, NULL, + NULL); } } -- cgit v1.3-6-gb490 From 58e446fcc69436988fdab4a81981f44193f064f7 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:28 +0200 Subject: iio: Export I2C module alias information in missing drivers The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 1 + drivers/iio/accel/stk8ba50.c | 1 + drivers/iio/light/stk3310.c | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index c2bd1444d6da..a553736b6e51 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -662,6 +662,7 @@ static const struct i2c_device_id stk8312_i2c_id[] = { {"STK8312", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id); static const struct acpi_device_id stk8312_acpi_id[] = { {"STK8312", 0}, diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 16cee637109b..80f77d8704b5 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -572,6 +572,7 @@ static const struct i2c_device_id stk8ba50_i2c_id[] = { {"stk8ba50", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id); static const struct acpi_device_id stk8ba50_acpi_id[] = { {"STK8BA50", 0}, diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index fee4297d7c8f..d26b931730ee 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -695,6 +695,7 @@ static const struct i2c_device_id stk3310_i2c_id[] = { {"STK3311", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id); static const struct acpi_device_id stk3310_acpi_id[] = { {"STK3310", 0}, -- cgit v1.3-6-gb490 From 119c4fce683a22a2fdbe343e00bc1a20cc1dd11c Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:42 +0200 Subject: iio: Export OF module alias information in missing drivers The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 1 + drivers/iio/light/cm32181.c | 1 + drivers/iio/light/cm3232.c | 1 + drivers/iio/light/cm36651.c | 1 + drivers/iio/light/gp2ap020a00f.c | 1 + 5 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index e8e2077c7244..3c4ad1563ca4 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -968,6 +968,7 @@ static const struct of_device_id mma8452_dt_ids[] = { { .compatible = "fsl,mma8452" }, { } }; +MODULE_DEVICE_TABLE(of, mma8452_dt_ids); static struct i2c_driver mma8452_driver = { .driver = { diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index 1c0de2f8885d..d6fd0dace74f 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -353,6 +353,7 @@ static const struct of_device_id cm32181_of_match[] = { { .compatible = "capella,cm32181" }, { } }; +MODULE_DEVICE_TABLE(of, cm32181_of_match); static struct i2c_driver cm32181_driver = { .driver = { diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 1b508c65877c..fe89b6823217 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -417,6 +417,7 @@ static const struct of_device_id cm3232_of_match[] = { {.compatible = "capella,cm3232"}, {} }; +MODULE_DEVICE_TABLE(of, cm3232_of_match); static struct i2c_driver cm3232_driver = { .driver = { diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 2a39e141e90c..c8d7b5ea7e78 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -731,6 +731,7 @@ static const struct of_device_id cm36651_of_match[] = { { .compatible = "capella,cm36651" }, { } }; +MODULE_DEVICE_TABLE(of, cm36651_of_match); static struct i2c_driver cm36651_driver = { .driver = { diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 0334a814b5eb..6d41086f7c64 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1634,6 +1634,7 @@ static const struct of_device_id gp2ap020a00f_of_match[] = { { .compatible = "sharp,gp2ap020a00f" }, { } }; +MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match); #endif static struct i2c_driver gp2ap020a00f_driver = { -- cgit v1.3-6-gb490 From 9e35d366a1e8bd710fbebcf9af90d3fafbc55e36 Mon Sep 17 00:00:00 2001 From: Teodora Baluta Date: Fri, 31 Jul 2015 17:27:24 +0300 Subject: iio: mmc35240: minor change to improve code readibility This patch changes two variables to arrays to improve code readibility. Signed-off-by: Teodora Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/mmc35240.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index 9bc542daa732..fa4ccd070e56 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -308,31 +308,31 @@ static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3]) static int mmc35240_raw_to_mgauss(struct mmc35240_data *data, int index, __le16 buf[], int *val) { - int raw_x, raw_y, raw_z; - int sens_x, sens_y, sens_z; + int raw[3]; + int sens[3]; int nfo; - raw_x = le16_to_cpu(buf[AXIS_X]); - raw_y = le16_to_cpu(buf[AXIS_Y]); - raw_z = le16_to_cpu(buf[AXIS_Z]); + raw[AXIS_X] = le16_to_cpu(buf[AXIS_X]); + raw[AXIS_Y] = le16_to_cpu(buf[AXIS_Y]); + raw[AXIS_Z] = le16_to_cpu(buf[AXIS_Z]); - sens_x = mmc35240_props_table[data->res].sens[AXIS_X]; - sens_y = mmc35240_props_table[data->res].sens[AXIS_Y]; - sens_z = mmc35240_props_table[data->res].sens[AXIS_Z]; + sens[AXIS_X] = mmc35240_props_table[data->res].sens[AXIS_X]; + sens[AXIS_Y] = mmc35240_props_table[data->res].sens[AXIS_Y]; + sens[AXIS_Z] = mmc35240_props_table[data->res].sens[AXIS_Z]; nfo = mmc35240_props_table[data->res].nfo; switch (index) { case AXIS_X: - *val = (raw_x - nfo) * 1000 / sens_x; + *val = (raw[AXIS_X] - nfo) * 1000 / sens[AXIS_X]; break; case AXIS_Y: - *val = (raw_y - nfo) * 1000 / sens_y - - (raw_z - nfo) * 1000 / sens_z; + *val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] - + (raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z]; break; case AXIS_Z: - *val = (raw_y - nfo) * 1000 / sens_y + - (raw_z - nfo) * 1000 / sens_z; + *val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] + + (raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z]; break; default: return -EINVAL; -- cgit v1.3-6-gb490 From f9ba1ab4d19a79b4bef4baf21f559f9dd8ba33f9 Mon Sep 17 00:00:00 2001 From: Crt Mori Date: Mon, 20 Jul 2015 21:38:27 +0200 Subject: iio: mlx90614: Define magic numbers Translates the magic constant numbers to named macros and add some additional comments about their meaning. The diff is made towards togreg branch as that branch seems to have the most recent updates of mlx90614 driver (many are yet to be merged). Signed-off-by: Crt Mori Acked-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mlx90614.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index 90f70b461567..5d033a5af615 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -65,6 +65,13 @@ #define MLX90614_AUTOSLEEP_DELAY 5000 /* default autosleep delay */ +/* Magic constants */ +#define MLX90614_CONST_OFFSET_DEC -13657 /* decimal part of the Kelvin offset */ +#define MLX90614_CONST_OFFSET_REM 500000 /* remainder of offset (273.15*50) */ +#define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */ +#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */ +#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */ + struct mlx90614_data { struct i2c_client *client; struct mutex lock; /* for EEPROM access only */ @@ -204,11 +211,11 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, *val = ret; return IIO_VAL_INT; case IIO_CHAN_INFO_OFFSET: - *val = 13657; - *val2 = 500000; + *val = MLX90614_CONST_OFFSET_DEC; + *val2 = MLX90614_CONST_OFFSET_REM; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SCALE: - *val = 20; + *val = MLX90614_CONST_SCALE; return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */ mlx90614_power_get(data, false); @@ -221,12 +228,12 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - if (ret == 65535) { + if (ret == MLX90614_CONST_RAW_EMISSIVITY_MAX) { *val = 1; *val2 = 0; } else { *val = 0; - *val2 = ret * 15259; /* 1/65535 ~ 0.000015259 */ + *val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION; } return IIO_VAL_INT_PLUS_NANO; default: @@ -245,7 +252,8 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */ if (val < 0 || val2 < 0 || val > 1 || (val == 1 && val2 != 0)) return -EINVAL; - val = val * 65535 + val2 / 15259; /* 1/65535 ~ 0.000015259 */ + val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX + + val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION; mlx90614_power_get(data, false); mutex_lock(&data->lock); -- cgit v1.3-6-gb490 From 3021678a94cdb942bea4e634a37e91fe341b27b0 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Fri, 17 Jul 2015 10:52:30 +0200 Subject: iio:magnetometer:bmc150_magn: expand mutex in trigger_handler Keep the mutex locked, until the content of data->buffer has been pushed out. Signed-off-by: Hartmut Knaack Acked-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 074a99da7367..324412d51cf8 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -664,7 +664,6 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) mutex_lock(&data->mutex); ret = bmc150_magn_read_xyz(data, data->buffer); - mutex_unlock(&data->mutex); if (ret < 0) goto err; @@ -672,6 +671,7 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) pf->timestamp); err: + mutex_unlock(&data->mutex); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; -- cgit v1.3-6-gb490 From 1506f3cd0b8169773188a080d367c2ed019373a3 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Fri, 17 Jul 2015 10:52:31 +0200 Subject: iio:magnetometer:bmc150_magn: use descriptive name for mask Define and use a descriptive name for the repetition registers data mask, instead of a 'magic' value. Signed-off-by: Hartmut Knaack Acked-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 324412d51cf8..9ae6479b8d84 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -85,6 +85,7 @@ #define BMC150_MAGN_REG_HIGH_THRESH 0x50 #define BMC150_MAGN_REG_REP_XY 0x51 #define BMC150_MAGN_REG_REP_Z 0x52 +#define BMC150_MAGN_REG_REP_DATAMASK GENMASK(7, 0) #define BMC150_MAGN_REG_TRIM_START 0x5D #define BMC150_MAGN_REG_TRIM_END 0x71 @@ -559,7 +560,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev, } ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_REP_XY, - 0xFF, + BMC150_MAGN_REG_REP_DATAMASK, BMC150_MAGN_REPXY_TO_REGVAL (val)); mutex_unlock(&data->mutex); @@ -575,7 +576,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev, } ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_REP_Z, - 0xFF, + BMC150_MAGN_REG_REP_DATAMASK, BMC150_MAGN_REPZ_TO_REGVAL (val)); mutex_unlock(&data->mutex); -- cgit v1.3-6-gb490 From 019cc46d0a5c559bca6c7e949cc277f529a51296 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Thu, 23 Jul 2015 20:15:01 +0300 Subject: iio: magn: bmc150_magn: add locking comment for runtime resume Runtime resume function is called with the data->mutex lock held. Add a comment to indicate this. Signed-off-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 9ae6479b8d84..57f21fe10dd7 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -1044,6 +1044,9 @@ static int bmc150_magn_runtime_suspend(struct device *dev) return 0; } +/* + * Should be called with data->mutex held. + */ static int bmc150_magn_runtime_resume(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); -- cgit v1.3-6-gb490 From 5ab744d0d6e7fc90572250239ac796cd79b0ed77 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Thu, 23 Jul 2015 20:15:02 +0300 Subject: iio: magn: bmc150_magn: do not set power state twice when setting trigger state When setting the trigger state, the device power state is set through buffer preenable and postdisable hooks. There is no need to also set it in the trigger set state call. Remove duplicate set power state from the trigger set state call. Signed-off-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/bmc150_magn.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 57f21fe10dd7..bf47c8838b49 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -784,29 +784,23 @@ static int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig, if (state == data->dready_trigger_on) goto err_unlock; - ret = bmc150_magn_set_power_state(data, state); - if (ret < 0) - goto err_unlock; - ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_INT_DRDY, BMC150_MAGN_MASK_DRDY_EN, state << BMC150_MAGN_SHIFT_DRDY_EN); if (ret < 0) - goto err_poweroff; + goto err_unlock; data->dready_trigger_on = state; if (state) { ret = bmc150_magn_reset_intr(data); if (ret < 0) - goto err_poweroff; + goto err_unlock; } mutex_unlock(&data->mutex); return 0; -err_poweroff: - bmc150_magn_set_power_state(data, false); err_unlock: mutex_unlock(&data->mutex); return ret; -- cgit v1.3-6-gb490 From 2498dcf6e09b3ecce2b32ed6434bd02fc4219d5b Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Fri, 24 Jul 2015 16:16:19 +0300 Subject: iio: core: Add function params for kernel docs This patch adds the missing fields in kernel docs to remove some warnings that appear when the IIO Documentation DocBook is generated. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index d8051cdcbdc2..b3fcc2c449d8 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -406,10 +406,16 @@ EXPORT_SYMBOL_GPL(iio_enum_write); /** * iio_format_value() - Formats a IIO value into its string representation - * @buf: The buffer to which the formated value gets written - * @type: One of the IIO_VAL_... constants. This decides how the val and val2 - * parameters are formatted. - * @vals: pointer to the values, exact meaning depends on the type parameter. + * @buf: The buffer to which the formatted value gets written + * @type: One of the IIO_VAL_... constants. This decides how the val + * and val2 parameters are formatted. + * @size: Number of IIO value entries contained in vals + * @vals: Pointer to the values, exact meaning depends on the + * type parameter. + * + * Return: 0 by default, a negative number on failure or the + * total number of characters written for a type that belongs + * to the IIO_VAL_... constant. */ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) { @@ -1096,6 +1102,11 @@ EXPORT_SYMBOL_GPL(devm_iio_device_free); /** * iio_chrdev_open() - chrdev file open for buffer access and ioctls + * @inode: Inode structure for identifying the device in the file system + * @filp: File structure for iio device used to keep and later access + * private data + * + * Return: 0 on success or -EBUSY if the device is already opened **/ static int iio_chrdev_open(struct inode *inode, struct file *filp) { @@ -1114,7 +1125,11 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp) /** * iio_chrdev_release() - chrdev file close buffer access and ioctls - **/ + * @inode: Inode structure pointer for the char device + * @filp: File structure pointer for the char device + * + * Return: 0 for successful release + */ static int iio_chrdev_release(struct inode *inode, struct file *filp) { struct iio_dev *indio_dev = container_of(inode->i_cdev, -- cgit v1.3-6-gb490 From 0123635a77f72e0787f6f8b3ac796a40f796fcc4 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Fri, 24 Jul 2015 16:18:09 +0300 Subject: iio: buffer: Fix kernel docs warnings Fix kernel docs for structures and functions in order to remove some warnings when the documentation gets generated. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index f72be48e650c..faed6efa49ec 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -91,9 +91,16 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, /** * iio_buffer_read_first_n_outer() - chrdev read for buffer access + * @filp: File structure pointer for the char device + * @buf: Destination buffer for iio buffer read + * @n: First n bytes to read + * @f_ps: Long offset provided by the user as a seek position * * This function relies on all buffer implementations having an * iio_buffer as their first element. + * + * Return: negative values corresponding to error codes or ret != 0 + * for ending the reading activity **/ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, size_t n, loff_t *f_ps) @@ -143,6 +150,12 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, /** * iio_buffer_poll() - poll the buffer to find out if it has data + * @filp: File structure pointer for device access + * @wait: Poll table structure pointer for which the driver adds + * a wait queue + * + * Return: (POLLIN | POLLRDNORM) if data is available for reading + * or 0 for other cases */ unsigned int iio_buffer_poll(struct file *filp, struct poll_table_struct *wait) @@ -1136,7 +1149,7 @@ int iio_scan_mask_query(struct iio_dev *indio_dev, EXPORT_SYMBOL_GPL(iio_scan_mask_query); /** - * struct iio_demux_table() - table describing demux memcpy ops + * struct iio_demux_table - table describing demux memcpy ops * @from: index to copy from * @to: index to copy to * @length: how many bytes to copy -- cgit v1.3-6-gb490 From a316c01d59e9d45ede1083a81ae82eb15ae7eab3 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Fri, 24 Jul 2015 16:21:50 +0300 Subject: iio: event: Add missing fields in kernel docs Fix kernel docs warnings by adding the missing fields, each with its associated description. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-event.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 894d8137c4cf..b2f63f919cc4 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -32,6 +32,7 @@ * @dev_attr_list: list of event interface sysfs attribute * @flags: file operations related flags including busy flag. * @group: event interface sysfs attribute group + * @read_lock: lock to protect kfifo read operations */ struct iio_event_interface { wait_queue_head_t wait; @@ -75,6 +76,11 @@ EXPORT_SYMBOL(iio_push_event); /** * iio_event_poll() - poll the event queue to find out if it has data + * @filep: File structure pointer to identify the device + * @wait: Poll table pointer to add the wait queue on + * + * Return: (POLLIN | POLLRDNORM) if data is available for reading + * or a negative error code on failure */ static unsigned int iio_event_poll(struct file *filep, struct poll_table_struct *wait) -- cgit v1.3-6-gb490 From 19d566420b8c5a26d4f9666ef665e088173d3df3 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:38:58 +0200 Subject: iio:adc:berlin2-adc: pass up real error code Pass up the real error code returned by platform_get_irq_byname(). Signed-off-by: Hartmut Knaack Acked-by: Antoine Tenart Signed-off-by: Jonathan Cameron --- drivers/iio/adc/berlin2-adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index aecc9ad995ad..30e2090df96d 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -301,11 +301,11 @@ static int berlin2_adc_probe(struct platform_device *pdev) irq = platform_get_irq_byname(pdev, "adc"); if (irq < 0) - return -ENODEV; + return irq; tsen_irq = platform_get_irq_byname(pdev, "tsen"); if (tsen_irq < 0) - return -ENODEV; + return tsen_irq; ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0, pdev->dev.driver->name, indio_dev); -- cgit v1.3-6-gb490 From 688febbd168c52ab54ad29c210aceecb72386398 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:39:00 +0200 Subject: iio:adc:berlin2-adc: constify iio_chan_spec Mark berlin2_adc_channels array as constant. Signed-off-by: Hartmut Knaack Acked-by: Antoine Tenart Signed-off-by: Jonathan Cameron --- drivers/iio/adc/berlin2-adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index 30e2090df96d..2084b0b66ea0 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -86,7 +86,7 @@ struct berlin2_adc_priv { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ } -static struct iio_chan_spec berlin2_adc_channels[] = { +static const struct iio_chan_spec berlin2_adc_channels[] = { BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */ BERLIN2_ADC_CHANNEL(1, IIO_VOLTAGE), /* external input */ BERLIN2_ADC_CHANNEL(2, IIO_VOLTAGE), /* external input */ -- cgit v1.3-6-gb490 From 609e9d88f277bfe83392595745cc3976d42125b2 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:39:01 +0200 Subject: iio:adc:berlin2-adc: use short operator format Use augmented assignment to subtract the offset for negative temperature values. Specify the amount of private data to be allocated through devm_iio_device_alloc() with sizeof(*priv), as it is shorter and common practice in IIO. Signed-off-by: Hartmut Knaack Acked-by: Antoine Tenart Signed-off-by: Jonathan Cameron --- drivers/iio/adc/berlin2-adc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index 2084b0b66ea0..e04b7734df1d 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -221,7 +221,7 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev, return temp; if (temp > 2047) - temp = -(4096 - temp); + temp -= 4096; /* Convert to milli Celsius */ *val = ((temp * 100000) / 264 - 270000); @@ -286,8 +286,7 @@ static int berlin2_adc_probe(struct platform_device *pdev) int irq, tsen_irq; int ret; - indio_dev = devm_iio_device_alloc(&pdev->dev, - sizeof(struct berlin2_adc_priv)); + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); if (!indio_dev) return -ENOMEM; -- cgit v1.3-6-gb490 From 546384c968383b512ba50f77c76ae7bdfa321f31 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:39:02 +0200 Subject: iio:adc:berlin2-adc: use channel-array size directly Drop the otherwise unused definition of the channel-array size and use it directly in _probe - makes it a bit more obvious. Signed-off-by: Hartmut Knaack Acked-by: Antoine Tenart Signed-off-by: Jonathan Cameron --- drivers/iio/adc/berlin2-adc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index e04b7734df1d..3aaf3a975c79 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -103,7 +103,6 @@ static const struct iio_chan_spec berlin2_adc_channels[] = { BERLIN2_ADC_CHANNEL(7, IIO_VOLTAGE), /* reserved */ IIO_CHAN_SOFT_TIMESTAMP(8), /* timestamp */ }; -#define BERLIN2_N_CHANNELS ARRAY_SIZE(berlin2_adc_channels) static int berlin2_adc_read(struct iio_dev *indio_dev, int channel) { @@ -324,8 +323,8 @@ static int berlin2_adc_probe(struct platform_device *pdev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &berlin2_adc_info; - indio_dev->num_channels = BERLIN2_N_CHANNELS; indio_dev->channels = berlin2_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(berlin2_adc_channels); /* Power up the ADC */ regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, -- cgit v1.3-6-gb490 From 946448e08e2f693ff21418d92a598b7aa296816d Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:49:21 +0200 Subject: iio:accel:stk8312: add triggered buffer dependency Add the still missing dependencies for triggered buffer support. Fixes: 95c12bba51c37 ("iio: accel: Add buffer mode for Sensortek STK8312") Signed-off-by: Hartmut Knaack Reviewed-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 00e7bcbdbe24..c99d8e242218 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -140,6 +140,8 @@ config MMA9553 config STK8312 tristate "Sensortek STK8312 3-Axis Accelerometer Driver" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to get support for the Sensortek STK8312 3-axis accelerometer. -- cgit v1.3-6-gb490 From b41e63cf83affa50a6141eba52be1fbd05f29b21 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Tue, 28 Jul 2015 00:49:22 +0200 Subject: iio:accel:stk8312: check for invalid value Revision 1.2 of the datasheet recommends on page 22 to only write non-zero values read from OTP register 0x70 into AFECTRL register. Signed-off-by: Hartmut Knaack Reviewed-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index a553736b6e51..8280a37e0068 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -150,6 +150,8 @@ static int stk8312_otp_init(struct stk8312_data *data) goto exit_err; ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPDATA); + if (ret == 0) + ret = -EINVAL; if (ret < 0) goto exit_err; -- cgit v1.3-6-gb490 From c46309c7f8e7923a1311fbdf6884a59a5f9954cf Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Sun, 2 Aug 2015 12:42:41 +0300 Subject: bnx2x: Correct logic for pvid configuration. Commit 05cc5a39ddb7 ("bnx2x: add vlan filtering offload") has introduced an incorrect logic for checking whether pvid should be configured for a vf, causing the hypervisor driver to send unneeded ramrods for all of the vfs each time a pvid has changed. Reported-by: Dan Carpenter Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index ec82831f5071..9d027348cd09 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -2528,7 +2528,7 @@ void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp) DP(BNX2X_MSG_IOV, "configuring vlan for VFs from sp-task\n"); for_each_vf(bp, vfidx) { bulletin = BP_VF_BULLETIN(bp, vfidx); - if (bulletin->valid_bitmap & VLAN_VALID) + if (bulletin->valid_bitmap & (1 << VLAN_VALID)) bnx2x_set_vf_vlan(bp->dev, vfidx, bulletin->vlan, 0); } } -- cgit v1.3-6-gb490 From a6415cddc4e6e1675a5648e7785aef716980c90c Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Sat, 1 Aug 2015 00:10:12 -0700 Subject: iscsi-target: Add tpg_enabled_sendtargets for disabled discovery This patch adds a new tpg_enabled_sendtargets configfs attribute to allow in-band sendtargets discovery information to include target-portal-groups (TPGs) in !TPG_STATE_ACTIVE state. This functionality is useful for clustered iSCSI targets, where TPGTs handled on remote cluster nodes should be advertised in the SendTargets response. By default, this new attribute retains the default behaviour of existing code which to ignore portal-groups in !TPG_STATE_ACTIVE state. Signed-off-by: David Disseldorp Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 10 +++++----- drivers/target/iscsi/iscsi_target_configfs.c | 6 ++++++ drivers/target/iscsi/iscsi_target_tpg.c | 19 +++++++++++++++++++ drivers/target/iscsi/iscsi_target_tpg.h | 1 + include/target/iscsi/iscsi_target_core.h | 3 +++ 5 files changed, 34 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index a4cf58cb835d..986518c3ea12 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -3398,6 +3398,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, int target_name_printed; unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */ unsigned char *text_in = cmd->text_in_ptr, *text_ptr = NULL; + bool active; buffer_len = min(conn->conn_ops->MaxRecvDataSegmentLength, SENDTARGETS_BUF_LIMIT); @@ -3451,13 +3452,12 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, } spin_lock(&tpg->tpg_state_lock); - if ((tpg->tpg_state == TPG_STATE_FREE) || - (tpg->tpg_state == TPG_STATE_INACTIVE)) { - spin_unlock(&tpg->tpg_state_lock); - continue; - } + active = (tpg->tpg_state == TPG_STATE_ACTIVE); spin_unlock(&tpg->tpg_state_lock); + if (!active && tpg->tpg_attrib.tpg_enabled_sendtargets) + continue; + spin_lock(&tpg->tpg_np_lock); list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index c1898c84b3d2..05f16640fb9b 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -1010,6 +1010,11 @@ TPG_ATTR(t10_pi, S_IRUGO | S_IWUSR); */ DEF_TPG_ATTRIB(fabric_prot_type); TPG_ATTR(fabric_prot_type, S_IRUGO | S_IWUSR); +/* + * Define iscsi_tpg_attrib_s_tpg_enabled_sendtargets + */ +DEF_TPG_ATTRIB(tpg_enabled_sendtargets); +TPG_ATTR(tpg_enabled_sendtargets, S_IRUGO | S_IWUSR); static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { &iscsi_tpg_attrib_authentication.attr, @@ -1024,6 +1029,7 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { &iscsi_tpg_attrib_default_erl.attr, &iscsi_tpg_attrib_t10_pi.attr, &iscsi_tpg_attrib_fabric_prot_type.attr, + &iscsi_tpg_attrib_tpg_enabled_sendtargets.attr, NULL, }; diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 968068ffcb1c..8262a853e888 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -226,6 +226,7 @@ static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg) a->default_erl = TA_DEFAULT_ERL; a->t10_pi = TA_DEFAULT_T10_PI; a->fabric_prot_type = TA_DEFAULT_FABRIC_PROT_TYPE; + a->tpg_enabled_sendtargets = TA_DEFAULT_TPG_ENABLED_SENDTARGETS; } int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg) @@ -892,3 +893,21 @@ int iscsit_ta_fabric_prot_type( return 0; } + +int iscsit_ta_tpg_enabled_sendtargets( + struct iscsi_portal_group *tpg, + u32 flag) +{ + struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; + + if ((flag != 0) && (flag != 1)) { + pr_err("Illegal value %d\n", flag); + return -EINVAL; + } + + a->tpg_enabled_sendtargets = flag; + pr_debug("iSCSI_TPG[%hu] - TPG enabled bit required for SendTargets:" + " %s\n", tpg->tpgt, (a->tpg_enabled_sendtargets) ? "ON" : "OFF"); + + return 0; +} diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index 95ff5bdecd71..a2790fd8f7da 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h @@ -40,5 +40,6 @@ extern int iscsit_ta_demo_mode_discovery(struct iscsi_portal_group *, u32); extern int iscsit_ta_default_erl(struct iscsi_portal_group *, u32); extern int iscsit_ta_t10_pi(struct iscsi_portal_group *, u32); extern int iscsit_ta_fabric_prot_type(struct iscsi_portal_group *, u32); +extern int iscsit_ta_tpg_enabled_sendtargets(struct iscsi_portal_group *, u32); #endif /* ISCSI_TARGET_TPG_H */ diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 34117b8b72e4..ab465858f462 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -62,6 +62,8 @@ /* T10 protection information disabled by default */ #define TA_DEFAULT_T10_PI 0 #define TA_DEFAULT_FABRIC_PROT_TYPE 0 +/* TPG status needs to be enabled to return sendtargets discovery endpoint info */ +#define TA_DEFAULT_TPG_ENABLED_SENDTARGETS 1 #define ISCSI_IOV_DATA_BUFFER 5 @@ -763,6 +765,7 @@ struct iscsi_tpg_attrib { u32 default_erl; u8 t10_pi; u32 fabric_prot_type; + u32 tpg_enabled_sendtargets; struct iscsi_portal_group *tpg; }; -- cgit v1.3-6-gb490 From 3d87b02281a2ec977108ad90ce502e721b447301 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Fri, 24 Jul 2015 13:17:24 +0900 Subject: PM / devfreq: exynos-ppmu: Add the support of PPMUv2 for Exynos5433 This patch adds the support for PPMU (Platform Performance Monitoring Unit) version 2.0 for Exynos5433 SoC. Exynos5433 SoC must need PPMUv2 which is quite different from PPMUv1.1. The exynos-ppmu.c driver supports both PPMUv1.1 and PPMUv2. Cc: MyungJoo Ham Cc: Kyungmin Park Signed-off-by: Chanwoo Choi --- drivers/devfreq/event/exynos-ppmu.c | 170 ++++++++++++++++++++++++++++++++++-- drivers/devfreq/event/exynos-ppmu.h | 70 +++++++++++++++ 2 files changed, 233 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c index 7d99d13bacd8..f9901f52a225 100644 --- a/drivers/devfreq/event/exynos-ppmu.c +++ b/drivers/devfreq/event/exynos-ppmu.c @@ -1,7 +1,7 @@ /* * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support * - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd. * Author : Chanwoo Choi * * This program is free software; you can redistribute it and/or modify @@ -82,6 +82,15 @@ struct __exynos_ppmu_events { PPMU_EVENT(mscl), PPMU_EVENT(fimd0x), PPMU_EVENT(fimd1x), + + /* Only for Exynos5433 SoCs */ + PPMU_EVENT(d0-cpu), + PPMU_EVENT(d0-general), + PPMU_EVENT(d0-rt), + PPMU_EVENT(d1-cpu), + PPMU_EVENT(d1-general), + PPMU_EVENT(d1-rt), + { /* sentinel */ }, }; @@ -96,6 +105,9 @@ static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev) return -EINVAL; } +/* + * The devfreq-event ops structure for PPMU v1.1 + */ static int exynos_ppmu_disable(struct devfreq_event_dev *edev) { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); @@ -200,10 +212,158 @@ static const struct devfreq_event_ops exynos_ppmu_ops = { .get_event = exynos_ppmu_get_event, }; +/* + * The devfreq-event ops structure for PPMU v2.0 + */ +static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev) +{ + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + u32 pmnc, clear; + + /* Disable all counters */ + clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK + | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK); + + __raw_writel(clear, info->ppmu.base + PPMU_V2_FLAG); + __raw_writel(clear, info->ppmu.base + PPMU_V2_INTENC); + __raw_writel(clear, info->ppmu.base + PPMU_V2_CNTENC); + __raw_writel(clear, info->ppmu.base + PPMU_V2_CNT_RESET); + + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG0); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG1); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG2); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_RESULT); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CNT_AUTO); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV0_TYPE); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV1_TYPE); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV2_TYPE); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV3_TYPE); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_V); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_A); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_V); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_A); + __raw_writel(0x0, info->ppmu.base + PPMU_V2_INTERRUPT_RESET); + + /* Disable PPMU */ + pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); + pmnc &= ~PPMU_PMNC_ENABLE_MASK; + __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); + + return 0; +} + +static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) +{ + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + int id = exynos_ppmu_find_ppmu_id(edev); + u32 pmnc, cntens; + + /* Enable all counters */ + cntens = __raw_readl(info->ppmu.base + PPMU_V2_CNTENS); + cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); + __raw_writel(cntens, info->ppmu.base + PPMU_V2_CNTENS); + + /* Set the event of Read/Write data count */ + switch (id) { + case PPMU_PMNCNT0: + case PPMU_PMNCNT1: + case PPMU_PMNCNT2: + __raw_writel(PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT, + info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); + break; + case PPMU_PMNCNT3: + __raw_writel(PPMU_V2_EVT3_RW_DATA_CNT, + info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); + break; + } + + /* Reset cycle counter/performance counter and enable PPMU */ + pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); + pmnc &= ~(PPMU_PMNC_ENABLE_MASK + | PPMU_PMNC_COUNTER_RESET_MASK + | PPMU_PMNC_CC_RESET_MASK + | PPMU_PMNC_CC_DIVIDER_MASK + | PPMU_V2_PMNC_START_MODE_MASK); + pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); + pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); + pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); + pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT); + __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); + + return 0; +} + +static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev, + struct devfreq_event_data *edata) +{ + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + int id = exynos_ppmu_find_ppmu_id(edev); + u32 pmnc, cntenc; + u32 pmcnt_high, pmcnt_low; + u64 load_count = 0; + + /* Disable PPMU */ + pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); + pmnc &= ~PPMU_PMNC_ENABLE_MASK; + __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); + + /* Read cycle count and performance count */ + edata->total_count = __raw_readl(info->ppmu.base + PPMU_V2_CCNT); + + switch (id) { + case PPMU_PMNCNT0: + case PPMU_PMNCNT1: + case PPMU_PMNCNT2: + load_count = __raw_readl(info->ppmu.base + PPMU_V2_PMNCT(id)); + break; + case PPMU_PMNCNT3: + pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH); + pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW); + load_count = (u64)((pmcnt_high & 0xff) << 32) + (u64)pmcnt_low; + break; + } + edata->load_count = load_count; + + /* Disable all counters */ + cntenc = __raw_readl(info->ppmu.base + PPMU_V2_CNTENC); + cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); + __raw_writel(cntenc, info->ppmu.base + PPMU_V2_CNTENC); + + dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name, + edata->load_count, edata->total_count); + return 0; +} + +static const struct devfreq_event_ops exynos_ppmu_v2_ops = { + .disable = exynos_ppmu_v2_disable, + .set_event = exynos_ppmu_v2_set_event, + .get_event = exynos_ppmu_v2_get_event, +}; + +static const struct of_device_id exynos_ppmu_id_match[] = { + { + .compatible = "samsung,exynos-ppmu", + .data = (void *)&exynos_ppmu_ops, + }, { + .compatible = "samsung,exynos-ppmu-v2", + .data = (void *)&exynos_ppmu_v2_ops, + }, + { /* sentinel */ }, +}; + +static struct devfreq_event_ops *exynos_bus_get_ops(struct device_node *np) +{ + const struct of_device_id *match; + + match = of_match_node(exynos_ppmu_id_match, np); + return (struct devfreq_event_ops *)match->data; +} + static int of_get_devfreq_events(struct device_node *np, struct exynos_ppmu *info) { struct devfreq_event_desc *desc; + struct devfreq_event_ops *event_ops; struct device *dev = info->dev; struct device_node *events_np, *node; int i, j, count; @@ -214,6 +374,7 @@ static int of_get_devfreq_events(struct device_node *np, "failed to get child node of devfreq-event devices\n"); return -EINVAL; } + event_ops = exynos_bus_get_ops(np); count = of_get_child_count(events_np); desc = devm_kzalloc(dev, sizeof(*desc) * count, GFP_KERNEL); @@ -238,7 +399,7 @@ static int of_get_devfreq_events(struct device_node *np, continue; } - desc[j].ops = &exynos_ppmu_ops; + desc[j].ops = event_ops; desc[j].driver_data = info; of_property_read_string(node, "event-name", &desc[j].name); @@ -354,11 +515,6 @@ static int exynos_ppmu_remove(struct platform_device *pdev) return 0; } -static struct of_device_id exynos_ppmu_id_match[] = { - { .compatible = "samsung,exynos-ppmu", }, - { /* sentinel */ }, -}; - static struct platform_driver exynos_ppmu_driver = { .probe = exynos_ppmu_probe, .remove = exynos_ppmu_remove, diff --git a/drivers/devfreq/event/exynos-ppmu.h b/drivers/devfreq/event/exynos-ppmu.h index 4e831d48c138..05774c449137 100644 --- a/drivers/devfreq/event/exynos-ppmu.h +++ b/drivers/devfreq/event/exynos-ppmu.h @@ -26,6 +26,9 @@ enum ppmu_counter { PPMU_PMNCNT_MAX, }; +/*** + * PPMUv1.1 Definitions + */ enum ppmu_event_type { PPMU_RO_BUSY_CYCLE_CNT = 0x0, PPMU_WO_BUSY_CYCLE_CNT = 0x1, @@ -90,4 +93,71 @@ enum ppmu_reg { #define PPMU_PMNCT(x) (PPMU_PMCNT0 + (0x10 * x)) #define PPMU_BEVTxSEL(x) (PPMU_BEVT0SEL + (0x100 * x)) +/*** + * PPMU_V2.0 definitions + */ +enum ppmu_v2_mode { + PPMU_V2_MODE_MANUAL = 0, + PPMU_V2_MODE_AUTO = 1, + PPMU_V2_MODE_CIG = 2, /* CIG (Conditional Interrupt Generation) */ +}; + +enum ppmu_v2_event_type { + PPMU_V2_RO_DATA_CNT = 0x4, + PPMU_V2_WO_DATA_CNT = 0x5, + + PPMU_V2_EVT3_RW_DATA_CNT = 0x22, /* Only for Event3 */ +}; + +enum ppmu_V2_reg { + /* PPC control register */ + PPMU_V2_PMNC = 0x04, + PPMU_V2_CNTENS = 0x08, + PPMU_V2_CNTENC = 0x0c, + PPMU_V2_INTENS = 0x10, + PPMU_V2_INTENC = 0x14, + PPMU_V2_FLAG = 0x18, + + /* Cycle Counter and Performance Event Counter Register */ + PPMU_V2_CCNT = 0x48, + PPMU_V2_PMCNT0 = 0x34, + PPMU_V2_PMCNT1 = 0x38, + PPMU_V2_PMCNT2 = 0x3c, + PPMU_V2_PMCNT3_LOW = 0x40, + PPMU_V2_PMCNT3_HIGH = 0x44, + + /* Bus Event Generator */ + PPMU_V2_CIG_CFG0 = 0x1c, + PPMU_V2_CIG_CFG1 = 0x20, + PPMU_V2_CIG_CFG2 = 0x24, + PPMU_V2_CIG_RESULT = 0x28, + PPMU_V2_CNT_RESET = 0x2c, + PPMU_V2_CNT_AUTO = 0x30, + PPMU_V2_CH_EV0_TYPE = 0x200, + PPMU_V2_CH_EV1_TYPE = 0x204, + PPMU_V2_CH_EV2_TYPE = 0x208, + PPMU_V2_CH_EV3_TYPE = 0x20c, + PPMU_V2_SM_ID_V = 0x220, + PPMU_V2_SM_ID_A = 0x224, + PPMU_V2_SM_OTHERS_V = 0x228, + PPMU_V2_SM_OTHERS_A = 0x22c, + PPMU_V2_INTERRUPT_RESET = 0x260, +}; + +/* PMNC register */ +#define PPMU_V2_PMNC_START_MODE_SHIFT 20 +#define PPMU_V2_PMNC_START_MODE_MASK (0x3 << PPMU_V2_PMNC_START_MODE_SHIFT) + +#define PPMU_PMNC_CC_RESET_SHIFT 2 +#define PPMU_PMNC_COUNTER_RESET_SHIFT 1 +#define PPMU_PMNC_ENABLE_SHIFT 0 +#define PPMU_PMNC_START_MODE_MASK BIT(16) +#define PPMU_PMNC_CC_DIVIDER_MASK BIT(3) +#define PPMU_PMNC_CC_RESET_MASK BIT(2) +#define PPMU_PMNC_COUNTER_RESET_MASK BIT(1) +#define PPMU_PMNC_ENABLE_MASK BIT(0) + +#define PPMU_V2_PMNCT(x) (PPMU_V2_PMCNT0 + (0x4 * x)) +#define PPMU_V2_CH_EVx_TYPE(x) (PPMU_V2_CH_EV0_TYPE + (0x4 * x)) + #endif /* __EXYNOS_PPMU_H__ */ -- cgit v1.3-6-gb490 From 24c7d6c7316c72301bf8ecfc1189fd476176fd75 Mon Sep 17 00:00:00 2001 From: Sebastian Herbszt Date: Mon, 3 Aug 2015 00:21:50 +0200 Subject: qla2xxx: Update tcm_qla2xxx module description to 24xx+ Pre 24xx HBAs are not supported by tcm_qla2xxx, so go ahead and reflect this for informational purposes. Also fix QLogic spelling. Signed-off-by: Sebastian Herbszt Signed-off-by: Nicholas Bellinger --- drivers/scsi/qla2xxx/Kconfig | 4 ++-- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig index 33f60c92e20e..a0f732b138e4 100644 --- a/drivers/scsi/qla2xxx/Kconfig +++ b/drivers/scsi/qla2xxx/Kconfig @@ -32,10 +32,10 @@ config SCSI_QLA_FC They are also included in the linux-firmware tree as well. config TCM_QLA2XXX - tristate "TCM_QLA2XXX fabric module for Qlogic 2xxx series target mode HBAs" + tristate "TCM_QLA2XXX fabric module for QLogic 24xx+ series target mode HBAs" depends on SCSI_QLA_FC && TARGET_CORE depends on LIBFC select BTREE default n ---help--- - Say Y here to enable the TCM_QLA2XXX fabric module for Qlogic 2xxx series target mode HBAs + Say Y here to enable the TCM_QLA2XXX fabric module for QLogic 24xx+ series target mode HBAs diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 474d0c0e6dba..c621623abeed 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1956,7 +1956,7 @@ static void __exit tcm_qla2xxx_exit(void) tcm_qla2xxx_deregister_configfs(); } -MODULE_DESCRIPTION("TCM QLA2XXX series NPIV enabled fabric driver"); +MODULE_DESCRIPTION("TCM QLA24XX+ series NPIV enabled fabric driver"); MODULE_LICENSE("GPL"); module_init(tcm_qla2xxx_init); module_exit(tcm_qla2xxx_exit); -- cgit v1.3-6-gb490 From 109e2381749c1cfd94a0d22b2b54142539024973 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 23 Jul 2015 14:53:32 -0700 Subject: target: Drop iSCSI use of mutex around max_cmd_sn increment In a performance profile, taking a mutex in iscsit_increment_maxcmdsn() shows up very high. However taking a mutex around "sess->max_cmd_sn += 1" seems pretty silly: we're not serializing against other contexts in any useful way. I did a quick audit and there don't appear to be any other places that use max_cmd_sn within the mutex more than once, so this lock can't be providing any useful serialization. (Get correct values for logging - fix whitespace damage) Signed-off-by: Roland Dreier Signed-off-by: Spencer Baugh Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 18 +++++++++--------- drivers/target/iscsi/iscsi_target_configfs.c | 6 ++++-- drivers/target/iscsi/iscsi_target_device.c | 7 ++----- drivers/target/iscsi/iscsi_target_login.c | 2 +- drivers/target/iscsi/iscsi_target_nego.c | 9 +++------ drivers/target/iscsi/iscsi_target_tmr.c | 2 +- drivers/target/iscsi/iscsi_target_util.c | 7 ++++--- include/target/iscsi/iscsi_target_core.h | 2 +- 8 files changed, 25 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 986518c3ea12..e55f49c7c847 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -2555,7 +2555,7 @@ static int iscsit_send_conn_drop_async_message( cmd->stat_sn = conn->stat_sn++; hdr->statsn = cpu_to_be32(cmd->stat_sn); hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); + hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); hdr->async_event = ISCSI_ASYNC_MSG_DROPPING_CONNECTION; hdr->param1 = cpu_to_be16(cmd->logout_cid); hdr->param2 = cpu_to_be16(conn->sess->sess_ops->DefaultTime2Wait); @@ -2627,7 +2627,7 @@ iscsit_build_datain_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn, hdr->statsn = cpu_to_be32(0xFFFFFFFF); hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); + hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); hdr->datasn = cpu_to_be32(datain->data_sn); hdr->offset = cpu_to_be32(datain->offset); @@ -2838,7 +2838,7 @@ iscsit_build_logout_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, iscsit_increment_maxcmdsn(cmd, conn->sess); hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); + hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); pr_debug("Built Logout Response ITT: 0x%08x StatSN:" " 0x%08x Response: 0x%02x CID: %hu on CID: %hu\n", @@ -2901,7 +2901,7 @@ iscsit_build_nopin_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, iscsit_increment_maxcmdsn(cmd, conn->sess); hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); + hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); pr_debug("Built NOPIN %s Response ITT: 0x%08x, TTT: 0x%08x," " StatSN: 0x%08x, Length %u\n", (nopout_response) ? @@ -3048,7 +3048,7 @@ static int iscsit_send_r2t( hdr->ttt = cpu_to_be32(r2t->targ_xfer_tag); hdr->statsn = cpu_to_be32(conn->stat_sn); hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); + hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); hdr->r2tsn = cpu_to_be32(r2t->r2t_sn); hdr->data_offset = cpu_to_be32(r2t->offset); hdr->data_length = cpu_to_be32(r2t->xfer_len); @@ -3201,7 +3201,7 @@ void iscsit_build_rsp_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn, iscsit_increment_maxcmdsn(cmd, conn->sess); hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); + hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); pr_debug("Built SCSI Response, ITT: 0x%08x, StatSN: 0x%08x," " Response: 0x%02x, SAM Status: 0x%02x, CID: %hu\n", @@ -3320,7 +3320,7 @@ iscsit_build_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, iscsit_increment_maxcmdsn(cmd, conn->sess); hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); + hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); pr_debug("Built Task Management Response ITT: 0x%08x," " StatSN: 0x%08x, Response: 0x%02x, CID: %hu\n", @@ -3575,7 +3575,7 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, */ cmd->maxcmdsn_inc = 0; hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); + hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); pr_debug("Built Text Response: ITT: 0x%08x, TTT: 0x%08x, StatSN: 0x%08x," " Length: %u, CID: %hu F: %d C: %d\n", cmd->init_task_tag, @@ -3653,7 +3653,7 @@ iscsit_build_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn, cmd->stat_sn = conn->stat_sn++; hdr->statsn = cpu_to_be32(cmd->stat_sn); hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); + hdr->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); } EXPORT_SYMBOL(iscsit_build_reject); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 05f16640fb9b..48f708bc101d 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -656,6 +656,7 @@ static ssize_t lio_target_nacl_show_info( struct iscsi_conn *conn; struct se_session *se_sess; ssize_t rb = 0; + u32 max_cmd_sn; spin_lock_bh(&se_nacl->nacl_sess_lock); se_sess = se_nacl->nacl_sess; @@ -703,11 +704,12 @@ static ssize_t lio_target_nacl_show_info( " Values]-----------------------\n"); rb += sprintf(page+rb, " CmdSN/WR : CmdSN/WC : ExpCmdSN" " : MaxCmdSN : ITT : TTT\n"); + max_cmd_sn = (u32) atomic_read(&sess->max_cmd_sn); rb += sprintf(page+rb, " 0x%08x 0x%08x 0x%08x 0x%08x" " 0x%08x 0x%08x\n", sess->cmdsn_window, - (sess->max_cmd_sn - sess->exp_cmd_sn) + 1, - sess->exp_cmd_sn, sess->max_cmd_sn, + (max_cmd_sn - sess->exp_cmd_sn) + 1, + sess->exp_cmd_sn, max_cmd_sn, sess->init_task_tag, sess->targ_xfer_tag); rb += sprintf(page+rb, "----------------------[iSCSI" " Connections]-------------------------\n"); diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c index 5fabcd3d623f..07d2ef67dba6 100644 --- a/drivers/target/iscsi/iscsi_target_device.c +++ b/drivers/target/iscsi/iscsi_target_device.c @@ -47,7 +47,7 @@ void iscsit_determine_maxcmdsn(struct iscsi_session *sess) * core_set_queue_depth_for_node(). */ sess->cmdsn_window = se_nacl->queue_depth; - sess->max_cmd_sn = (sess->max_cmd_sn + se_nacl->queue_depth) - 1; + atomic_set(&sess->max_cmd_sn, (u32) atomic_read(&sess->max_cmd_sn) + se_nacl->queue_depth - 1); } void iscsit_increment_maxcmdsn(struct iscsi_cmd *cmd, struct iscsi_session *sess) @@ -57,9 +57,6 @@ void iscsit_increment_maxcmdsn(struct iscsi_cmd *cmd, struct iscsi_session *sess cmd->maxcmdsn_inc = 1; - mutex_lock(&sess->cmdsn_mutex); - sess->max_cmd_sn += 1; - pr_debug("Updated MaxCmdSN to 0x%08x\n", sess->max_cmd_sn); - mutex_unlock(&sess->cmdsn_mutex); + pr_debug("Updated MaxCmdSN to 0x%08x\n", atomic_inc_return(&sess->max_cmd_sn)); } EXPORT_SYMBOL(iscsit_increment_maxcmdsn); diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 3d0fe4ff5590..bd192f88e1e6 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -330,7 +330,7 @@ static int iscsi_login_zero_tsih_s1( * The FFP CmdSN window values will be allocated from the TPG's * Initiator Node's ACL once the login has been successfully completed. */ - sess->max_cmd_sn = be32_to_cpu(pdu->cmdsn); + atomic_set(&sess->max_cmd_sn, be32_to_cpu(pdu->cmdsn)); sess->sess_ops = kzalloc(sizeof(struct iscsi_sess_ops), GFP_KERNEL); if (!sess->sess_ops) { diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 8c02fa34716f..74d041e815f4 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -340,7 +340,6 @@ static int iscsi_target_check_first_request( static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_login *login) { u32 padding = 0; - struct iscsi_session *sess = conn->sess; struct iscsi_login_rsp *login_rsp; login_rsp = (struct iscsi_login_rsp *) login->rsp; @@ -352,7 +351,7 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log login_rsp->itt = login->init_task_tag; login_rsp->statsn = cpu_to_be32(conn->stat_sn++); login_rsp->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - login_rsp->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); + login_rsp->max_cmdsn = cpu_to_be32((u32) atomic_read(&conn->sess->max_cmd_sn)); pr_debug("Sending Login Response, Flags: 0x%02x, ITT: 0x%08x," " ExpCmdSN; 0x%08x, MaxCmdSN: 0x%08x, StatSN: 0x%08x, Length:" @@ -367,10 +366,8 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log return -1; login->rsp_length = 0; - mutex_lock(&sess->cmdsn_mutex); - login_rsp->exp_cmdsn = cpu_to_be32(sess->exp_cmd_sn); - login_rsp->max_cmdsn = cpu_to_be32(sess->max_cmd_sn); - mutex_unlock(&sess->cmdsn_mutex); + login_rsp->exp_cmdsn = cpu_to_be32(login_rsp->exp_cmdsn); + login_rsp->max_cmdsn = cpu_to_be32(login_rsp->max_cmdsn); return 0; } diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index cf59c397007b..11320df939f7 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c @@ -50,7 +50,7 @@ u8 iscsit_tmr_abort_task( pr_err("Unable to locate RefTaskTag: 0x%08x on CID:" " %hu.\n", hdr->rtt, conn->cid); return (iscsi_sna_gte(be32_to_cpu(hdr->refcmdsn), conn->sess->exp_cmd_sn) && - iscsi_sna_lte(be32_to_cpu(hdr->refcmdsn), conn->sess->max_cmd_sn)) ? + iscsi_sna_lte(be32_to_cpu(hdr->refcmdsn), (u32) atomic_read(&conn->sess->max_cmd_sn))) ? ISCSI_TMF_RSP_COMPLETE : ISCSI_TMF_RSP_NO_TASK; } if (ref_cmd->cmd_sn != be32_to_cpu(hdr->refcmdsn)) { diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index a2bff0702eb2..7df4fac69f39 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -233,6 +233,7 @@ struct iscsi_r2t *iscsit_get_holder_for_r2tsn( static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cmdsn) { + u32 max_cmdsn; int ret; /* @@ -241,10 +242,10 @@ static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cm * or order CmdSNs due to multiple connection sessions and/or * CRC failures. */ - if (iscsi_sna_gt(cmdsn, sess->max_cmd_sn)) { + max_cmdsn = atomic_read(&sess->max_cmd_sn); + if (iscsi_sna_gt(cmdsn, max_cmdsn)) { pr_err("Received CmdSN: 0x%08x is greater than" - " MaxCmdSN: 0x%08x, ignoring.\n", cmdsn, - sess->max_cmd_sn); + " MaxCmdSN: 0x%08x, ignoring.\n", cmdsn, max_cmdsn); ret = CMDSN_MAXCMDSN_OVERRUN; } else if (cmdsn == sess->exp_cmd_sn) { diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index ab465858f462..d4616ef12e04 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -637,7 +637,7 @@ struct iscsi_session { /* session wide counter: expected command sequence number */ u32 exp_cmd_sn; /* session wide counter: maximum allowed command sequence number */ - u32 max_cmd_sn; + atomic_t max_cmd_sn; struct list_head sess_ooo_cmdsn_list; /* LIO specific session ID */ -- cgit v1.3-6-gb490 From 25eafe1a813681849ad3fb9effdfdce3e1b4335a Mon Sep 17 00:00:00 2001 From: Benjamin Randazzo Date: Sat, 25 Jul 2015 16:36:50 +0200 Subject: md: simplify get_bitmap_file now that "file" is zeroed. There is no point assigning '\0' to file->pathname[0] as file is now zeroed out, so remove that branch and simplify the code. [Original patch combined this with the change to use kzalloc. I split the two so that the change to kzalloc is easier to backport. - neilb] Signed-off-by: Benjamin Randazzo Signed-off-by: NeilBrown --- drivers/md/md.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index e25f00f0138a..4d47a9ab8228 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5765,16 +5765,16 @@ static int get_bitmap_file(struct mddev *mddev, void __user * arg) err = 0; spin_lock(&mddev->lock); - /* bitmap disabled, zero the first byte and copy out */ - if (!mddev->bitmap_info.file) - file->pathname[0] = '\0'; - else if ((ptr = file_path(mddev->bitmap_info.file, - file->pathname, sizeof(file->pathname))), - IS_ERR(ptr)) - err = PTR_ERR(ptr); - else - memmove(file->pathname, ptr, - sizeof(file->pathname)-(ptr-file->pathname)); + /* bitmap enabled */ + if (mddev->bitmap_info.file) { + ptr = file_path(mddev->bitmap_info.file, file->pathname, + sizeof(file->pathname)); + if (IS_ERR(ptr)) + err = PTR_ERR(ptr); + else + memmove(file->pathname, ptr, + sizeof(file->pathname)-(ptr-file->pathname)); + } spin_unlock(&mddev->lock); if (err == 0 && -- cgit v1.3-6-gb490 From 199dc6ed5179251fa6158a461499c24bdd99c836 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Aug 2015 13:11:47 +1000 Subject: md/raid0: update queue parameter in a safer location. When a (e.g.) RAID5 array is reshaped to RAID0, the updating of queue parameters (e.g. max number of sectors per bio) is done in the wrong place. It should be part of ->run, but it is actually part of ->takeover. This means it happens before level_store() calls: blk_set_stacking_limits(&mddev->queue->limits); and so it ineffective. This can lead to errors from underlying devices. So move all the relevant settings out of create_stripe_zones() and into raid0_run(). As this can lead to a bug-on it is suitable for any -stable kernel which supports reshape to RAID0. So 2.6.35 or later. As the bug has been present for five years there is no urgency, so no need to rush into -stable. Fixes: 9af204cf720c ("md: Add support for Raid5->Raid0 and Raid10->Raid0 takeover") Cc: stable@vger.kernel.org (v2.6.35+ - please delay until after -final release). Reported-by: Yi Zhang Signed-off-by: NeilBrown --- drivers/md/raid0.c | 75 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index efb654eb5399..4a13c3cb940b 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -83,7 +83,7 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) char b[BDEVNAME_SIZE]; char b2[BDEVNAME_SIZE]; struct r0conf *conf = kzalloc(sizeof(*conf), GFP_KERNEL); - bool discard_supported = false; + unsigned short blksize = 512; if (!conf) return -ENOMEM; @@ -98,6 +98,9 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) sector_div(sectors, mddev->chunk_sectors); rdev1->sectors = sectors * mddev->chunk_sectors; + blksize = max(blksize, queue_logical_block_size( + rdev1->bdev->bd_disk->queue)); + rdev_for_each(rdev2, mddev) { pr_debug("md/raid0:%s: comparing %s(%llu)" " with %s(%llu)\n", @@ -134,6 +137,18 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) } pr_debug("md/raid0:%s: FINAL %d zones\n", mdname(mddev), conf->nr_strip_zones); + /* + * now since we have the hard sector sizes, we can make sure + * chunk size is a multiple of that sector size + */ + if ((mddev->chunk_sectors << 9) % blksize) { + printk(KERN_ERR "md/raid0:%s: chunk_size of %d not multiple of block size %d\n", + mdname(mddev), + mddev->chunk_sectors << 9, blksize); + err = -EINVAL; + goto abort; + } + err = -ENOMEM; conf->strip_zone = kzalloc(sizeof(struct strip_zone)* conf->nr_strip_zones, GFP_KERNEL); @@ -188,19 +203,12 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) } dev[j] = rdev1; - if (mddev->queue) - disk_stack_limits(mddev->gendisk, rdev1->bdev, - rdev1->data_offset << 9); - if (rdev1->bdev->bd_disk->queue->merge_bvec_fn) conf->has_merge_bvec = 1; if (!smallest || (rdev1->sectors < smallest->sectors)) smallest = rdev1; cnt++; - - if (blk_queue_discard(bdev_get_queue(rdev1->bdev))) - discard_supported = true; } if (cnt != mddev->raid_disks) { printk(KERN_ERR "md/raid0:%s: too few disks (%d of %d) - " @@ -261,28 +269,6 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) (unsigned long long)smallest->sectors); } - /* - * now since we have the hard sector sizes, we can make sure - * chunk size is a multiple of that sector size - */ - if ((mddev->chunk_sectors << 9) % queue_logical_block_size(mddev->queue)) { - printk(KERN_ERR "md/raid0:%s: chunk_size of %d not valid\n", - mdname(mddev), - mddev->chunk_sectors << 9); - goto abort; - } - - if (mddev->queue) { - blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9); - blk_queue_io_opt(mddev->queue, - (mddev->chunk_sectors << 9) * mddev->raid_disks); - - if (!discard_supported) - queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue); - else - queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue); - } - pr_debug("md/raid0:%s: done.\n", mdname(mddev)); *private_conf = conf; @@ -433,12 +419,6 @@ static int raid0_run(struct mddev *mddev) if (md_check_no_bitmap(mddev)) return -EINVAL; - if (mddev->queue) { - blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors); - blk_queue_max_write_same_sectors(mddev->queue, mddev->chunk_sectors); - blk_queue_max_discard_sectors(mddev->queue, mddev->chunk_sectors); - } - /* if private is not null, we are here after takeover */ if (mddev->private == NULL) { ret = create_strip_zones(mddev, &conf); @@ -447,6 +427,29 @@ static int raid0_run(struct mddev *mddev) mddev->private = conf; } conf = mddev->private; + if (mddev->queue) { + struct md_rdev *rdev; + bool discard_supported = false; + + rdev_for_each(rdev, mddev) { + disk_stack_limits(mddev->gendisk, rdev->bdev, + rdev->data_offset << 9); + if (blk_queue_discard(bdev_get_queue(rdev->bdev))) + discard_supported = true; + } + blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors); + blk_queue_max_write_same_sectors(mddev->queue, mddev->chunk_sectors); + blk_queue_max_discard_sectors(mddev->queue, mddev->chunk_sectors); + + blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9); + blk_queue_io_opt(mddev->queue, + (mddev->chunk_sectors << 9) * mddev->raid_disks); + + if (!discard_supported) + queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue); + else + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue); + } /* calculate array device size */ md_set_array_sectors(mddev, raid0_size(mddev, 0, 0)); -- cgit v1.3-6-gb490 From ca67f10f27b6aace4a87713f038577994ec578af Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 30 Jul 2015 17:27:44 +0900 Subject: pinctrl: join dev_dbg strings into a single line These are user-visible strings, so can exceed 80 columns. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 078e58d74fc0..29a7bb17a42f 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -61,8 +61,8 @@ int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, const struct pinconf_ops *ops = pctldev->desc->confops; if (!ops || !ops->pin_config_get) { - dev_dbg(pctldev->dev, "cannot get pin configuration, missing " - "pin_config_get() function in driver\n"); + dev_dbg(pctldev->dev, + "cannot get pin configuration, .pin_config_get missing in driver\n"); return -ENOTSUPP; } -- cgit v1.3-6-gb490 From 8b67a1f0ad1f260f1a4032d5f7b032ac113bfa7d Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 31 Jul 2015 14:48:56 +0200 Subject: gpio: don't override irq_*_resources() callbacks If the driver has specified its own irq_{request/release}_resources() functions, don't override them. The gpio-etraxfs driver will use this. Signed-off-by: Rabin Vincent [Added a small comment blurb] Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 1b5b8da71154..34f95fbc884a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -641,8 +641,16 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, gpiochip->irqchip = NULL; return -EINVAL; } - irqchip->irq_request_resources = gpiochip_irq_reqres; - irqchip->irq_release_resources = gpiochip_irq_relres; + + /* + * It is possible for a driver to override this, but only if the + * alternative functions are both implemented. + */ + if (!irqchip->irq_request_resources && + !irqchip->irq_release_resources) { + irqchip->irq_request_resources = gpiochip_irq_reqres; + irqchip->irq_release_resources = gpiochip_irq_relres; + } /* * Prepare the mapping since the irqchip shall be orthogonal to -- cgit v1.3-6-gb490 From 29b5357d25ba1528531ef9532b5743a32fdf8cd2 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 31 Jul 2015 14:48:57 +0200 Subject: gpio: etraxfs: add interrupt support On ETRAX FS, all pins on the first port (and only the first port) have interrupt support. On ARTPEC-3, all pins on all ports have interrupt support. However, there are only eight interrupts. Each of the interrupts is associated with a group of pins and for each interrupt the one pin from the group which will trigger it can be selected. Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-etraxfs.c | 259 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 253 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3a9dc1a8f56e..37d9418c5a2d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -171,6 +171,7 @@ config GPIO_ETRAXFS depends on CRIS || COMPILE_TEST depends on OF select GPIO_GENERIC + select GPIOLIB_IRQCHIP help Say yes here to support the GPIO controller on Axis ETRAX FS SoCs. diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c index 27e5d8855205..2ffcd9fdd1f2 100644 --- a/drivers/gpio/gpio-etraxfs.c +++ b/drivers/gpio/gpio-etraxfs.c @@ -1,8 +1,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -13,6 +15,7 @@ #define ETRAX_FS_rw_intr_mask 16 #define ETRAX_FS_rw_ack_intr 20 #define ETRAX_FS_r_intr 24 +#define ETRAX_FS_r_masked_intr 28 #define ETRAX_FS_rw_pb_dout 32 #define ETRAX_FS_r_pb_din 36 #define ETRAX_FS_rw_pb_oe 40 @@ -36,6 +39,37 @@ #define ARTPEC3_rw_pc_dout 92 #define ARTPEC3_rw_pc_oe 96 #define ARTPEC3_r_pd_din 116 +#define ARTPEC3_rw_intr_cfg 120 +#define ARTPEC3_rw_intr_pins 124 +#define ARTPEC3_rw_intr_mask 128 +#define ARTPEC3_rw_ack_intr 132 +#define ARTPEC3_r_masked_intr 140 + +#define GIO_CFG_OFF 0 +#define GIO_CFG_HI 1 +#define GIO_CFG_LO 2 +#define GIO_CFG_SET 3 +#define GIO_CFG_POSEDGE 5 +#define GIO_CFG_NEGEDGE 6 +#define GIO_CFG_ANYEDGE 7 + +struct etraxfs_gpio_info; + +struct etraxfs_gpio_block { + spinlock_t lock; + u32 mask; + u32 cfg; + u32 pins; + unsigned int group[8]; + + void __iomem *regs; + const struct etraxfs_gpio_info *info; +}; + +struct etraxfs_gpio_chip { + struct bgpio_chip bgc; + struct etraxfs_gpio_block *block; +}; struct etraxfs_gpio_port { const char *label; @@ -48,6 +82,12 @@ struct etraxfs_gpio_port { struct etraxfs_gpio_info { unsigned int num_ports; const struct etraxfs_gpio_port *ports; + + unsigned int rw_ack_intr; + unsigned int rw_intr_mask; + unsigned int rw_intr_cfg; + unsigned int rw_intr_pins; + unsigned int r_masked_intr; }; static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = { @@ -91,6 +131,10 @@ static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = { static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = { .num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports), .ports = etraxfs_gpio_etraxfs_ports, + .rw_ack_intr = ETRAX_FS_rw_ack_intr, + .rw_intr_mask = ETRAX_FS_rw_intr_mask, + .rw_intr_cfg = ETRAX_FS_rw_intr_cfg, + .r_masked_intr = ETRAX_FS_r_masked_intr, }; static const struct etraxfs_gpio_port etraxfs_gpio_artpec3_ports[] = { @@ -125,8 +169,18 @@ static const struct etraxfs_gpio_port etraxfs_gpio_artpec3_ports[] = { static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = { .num_ports = ARRAY_SIZE(etraxfs_gpio_artpec3_ports), .ports = etraxfs_gpio_artpec3_ports, + .rw_ack_intr = ARTPEC3_rw_ack_intr, + .rw_intr_mask = ARTPEC3_rw_intr_mask, + .rw_intr_cfg = ARTPEC3_rw_intr_cfg, + .r_masked_intr = ARTPEC3_r_masked_intr, + .rw_intr_pins = ARTPEC3_rw_intr_pins, }; +static unsigned int etraxfs_gpio_chip_to_port(struct gpio_chip *gc) +{ + return gc->label[0] - 'A'; +} + static int etraxfs_gpio_of_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags) @@ -135,7 +189,7 @@ static int etraxfs_gpio_of_xlate(struct gpio_chip *gc, * Port numbers are A to E, and the properties are integers, so we * specify them as 0xA - 0xE. */ - if (gc->label[0] - 'A' + 0xA != gpiospec->args[2]) + if (etraxfs_gpio_chip_to_port(gc) + 0xA != gpiospec->args[2]) return -EINVAL; return of_gpio_simple_xlate(gc, gpiospec, flags); @@ -153,13 +207,159 @@ static const struct of_device_id etraxfs_gpio_of_table[] = { {}, }; +static unsigned int etraxfs_gpio_to_group_irq(unsigned int gpio) +{ + return gpio % 8; +} + +static unsigned int etraxfs_gpio_to_group_pin(struct etraxfs_gpio_chip *chip, + unsigned int gpio) +{ + return 4 * etraxfs_gpio_chip_to_port(&chip->bgc.gc) + gpio / 8; +} + +static void etraxfs_gpio_irq_ack(struct irq_data *d) +{ + struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + + writel(BIT(grpirq), block->regs + block->info->rw_ack_intr); +} + +static void etraxfs_gpio_irq_mask(struct irq_data *d) +{ + struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + + spin_lock(&block->lock); + block->mask &= ~BIT(grpirq); + writel(block->mask, block->regs + block->info->rw_intr_mask); + spin_unlock(&block->lock); +} + +static void etraxfs_gpio_irq_unmask(struct irq_data *d) +{ + struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + + spin_lock(&block->lock); + block->mask |= BIT(grpirq); + writel(block->mask, block->regs + block->info->rw_intr_mask); + spin_unlock(&block->lock); +} + +static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type) +{ + struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + u32 cfg; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + cfg = GIO_CFG_POSEDGE; + break; + case IRQ_TYPE_EDGE_FALLING: + cfg = GIO_CFG_NEGEDGE; + break; + case IRQ_TYPE_EDGE_BOTH: + cfg = GIO_CFG_ANYEDGE; + break; + case IRQ_TYPE_LEVEL_LOW: + cfg = GIO_CFG_LO; + break; + case IRQ_TYPE_LEVEL_HIGH: + cfg = GIO_CFG_HI; + break; + default: + return -EINVAL; + } + + spin_lock(&block->lock); + block->cfg &= ~(0x7 << (grpirq * 3)); + block->cfg |= (cfg << (grpirq * 3)); + writel(block->cfg, block->regs + block->info->rw_intr_cfg); + spin_unlock(&block->lock); + + return 0; +} + +static int etraxfs_gpio_irq_request_resources(struct irq_data *d) +{ + struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + int ret = -EBUSY; + + spin_lock(&block->lock); + if (block->group[grpirq]) + goto out; + + ret = gpiochip_lock_as_irq(&chip->bgc.gc, d->hwirq); + if (ret) + goto out; + + block->group[grpirq] = d->irq; + if (block->info->rw_intr_pins) { + unsigned int pin = etraxfs_gpio_to_group_pin(chip, d->hwirq); + + block->pins &= ~(0xf << (grpirq * 4)); + block->pins |= (pin << (grpirq * 4)); + + writel(block->pins, block->regs + block->info->rw_intr_pins); + } + +out: + spin_unlock(&block->lock); + return ret; +} + +static void etraxfs_gpio_irq_release_resources(struct irq_data *d) +{ + struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct etraxfs_gpio_block *block = chip->block; + unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + + spin_lock(&block->lock); + block->group[grpirq] = 0; + gpiochip_unlock_as_irq(&chip->bgc.gc, d->hwirq); + spin_unlock(&block->lock); +} + +static struct irq_chip etraxfs_gpio_irq_chip = { + .name = "gpio-etraxfs", + .irq_ack = etraxfs_gpio_irq_ack, + .irq_mask = etraxfs_gpio_irq_mask, + .irq_unmask = etraxfs_gpio_irq_unmask, + .irq_set_type = etraxfs_gpio_irq_set_type, + .irq_request_resources = etraxfs_gpio_irq_request_resources, + .irq_release_resources = etraxfs_gpio_irq_release_resources, +}; + +static irqreturn_t etraxfs_gpio_interrupt(int irq, void *dev_id) +{ + struct etraxfs_gpio_block *block = dev_id; + unsigned long intr = readl(block->regs + block->info->r_masked_intr); + int bit; + + for_each_set_bit(bit, &intr, 8) + generic_handle_irq(block->group[bit]); + + return IRQ_RETVAL(intr & 0xff); +} + static int etraxfs_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct etraxfs_gpio_info *info; const struct of_device_id *match; - struct bgpio_chip *chips; - struct resource *res; + struct etraxfs_gpio_block *block; + struct etraxfs_gpio_chip *chips; + struct resource *res, *irq; + bool allportsirq = false; void __iomem *regs; int ret; int i; @@ -179,14 +379,44 @@ static int etraxfs_gpio_probe(struct platform_device *pdev) if (!chips) return -ENOMEM; + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) + return -EINVAL; + + block = devm_kzalloc(dev, sizeof(*block), GFP_KERNEL); + if (!block) + return -ENOMEM; + + spin_lock_init(&block->lock); + + block->regs = regs; + block->info = info; + + writel(0, block->regs + info->rw_intr_mask); + writel(0, block->regs + info->rw_intr_cfg); + if (info->rw_intr_pins) { + allportsirq = true; + writel(0, block->regs + info->rw_intr_pins); + } + + ret = devm_request_irq(dev, irq->start, etraxfs_gpio_interrupt, + IRQF_SHARED, dev_name(dev), block); + if (ret) { + dev_err(dev, "Unable to request irq %d\n", ret); + return ret; + } + for (i = 0; i < info->num_ports; i++) { - struct bgpio_chip *bgc = &chips[i]; + struct etraxfs_gpio_chip *chip = &chips[i]; + struct bgpio_chip *bgc = &chip->bgc; const struct etraxfs_gpio_port *port = &info->ports[i]; unsigned long flags = BGPIOF_READ_OUTPUT_REG_SET; void __iomem *dat = regs + port->din; void __iomem *set = regs + port->dout; void __iomem *dirout = regs + port->oe; + chip->block = block; + if (dirout == set) { dirout = set = NULL; flags = BGPIOF_NO_OUTPUT; @@ -195,8 +425,11 @@ static int etraxfs_gpio_probe(struct platform_device *pdev) ret = bgpio_init(bgc, dev, 4, dat, set, NULL, dirout, NULL, flags); - if (ret) - return ret; + if (ret) { + dev_err(dev, "Unable to init port %s\n", + port->label); + continue; + } bgc->gc.ngpio = port->ngpio; bgc->gc.label = port->label; @@ -206,9 +439,21 @@ static int etraxfs_gpio_probe(struct platform_device *pdev) bgc->gc.of_xlate = etraxfs_gpio_of_xlate; ret = gpiochip_add(&bgc->gc); - if (ret) + if (ret) { dev_err(dev, "Unable to register port %s\n", bgc->gc.label); + continue; + } + + if (i > 0 && !allportsirq) + continue; + + ret = gpiochip_irqchip_add(&bgc->gc, &etraxfs_gpio_irq_chip, 0, + handle_level_irq, IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "Unable to add irqchip to port %s\n", + bgc->gc.label); + } } return 0; -- cgit v1.3-6-gb490 From 0fa2f5cb2b0ecd8d56baa51f35f09aab234eb0bf Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Wed, 15 Jul 2015 12:52:01 +0300 Subject: sched/preempt, xen: Use need_resched() instead of should_resched() This code is used only when CONFIG_PREEMPT=n and only in non-atomic context: xen_in_preemptible_hcall is set only in privcmd_ioctl_hypercall(). Thus preempt_count is zero and should_resched() is equal to need_resched(). Signed-off-by: Konstantin Khlebnikov Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Graf Cc: Boris Ostrovsky Cc: David Vrabel Cc: Linus Torvalds Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20150715095201.12246.49283.stgit@buzz Signed-off-by: Ingo Molnar --- drivers/xen/preempt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/preempt.c b/drivers/xen/preempt.c index a1800c150839..08cb419eb4e6 100644 --- a/drivers/xen/preempt.c +++ b/drivers/xen/preempt.c @@ -31,7 +31,7 @@ EXPORT_SYMBOL_GPL(xen_in_preemptible_hcall); asmlinkage __visible void xen_maybe_preempt_hcall(void) { if (unlikely(__this_cpu_read(xen_in_preemptible_hcall) - && should_resched())) { + && need_resched())) { /* * Clear flag as we may be rescheduled on a different * cpu. -- cgit v1.3-6-gb490 From efdf5aa8f175c18def6407bb2b51643e4da88259 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 13 Feb 2015 12:20:49 +0100 Subject: ARM: STi: DT: Move reset controller constants into common location By popular vote, the DT binding includes for reset controllers are located in include/dt-bindings/reset/. Move the STi reset constants in there, too, to avoid confusion. Signed-off-by: Philipp Zabel Acked-by: Patrice Chotard --- .../bindings/reset/st,sti-picophyreset.txt | 2 +- .../devicetree/bindings/reset/st,sti-powerdown.txt | 4 +- .../devicetree/bindings/reset/st,sti-softreset.txt | 4 +- arch/arm/boot/dts/stih407-family.dtsi | 2 +- arch/arm/boot/dts/stih415.dtsi | 2 +- arch/arm/boot/dts/stih416.dtsi | 2 +- drivers/reset/sti/reset-stih407.c | 2 +- drivers/reset/sti/reset-stih415.c | 2 +- drivers/reset/sti/reset-stih416.c | 2 +- .../dt-bindings/reset-controller/stih407-resets.h | 61 ---------------------- .../dt-bindings/reset-controller/stih415-resets.h | 27 ---------- .../dt-bindings/reset-controller/stih416-resets.h | 51 ------------------ include/dt-bindings/reset/stih407-resets.h | 61 ++++++++++++++++++++++ include/dt-bindings/reset/stih415-resets.h | 27 ++++++++++ include/dt-bindings/reset/stih416-resets.h | 51 ++++++++++++++++++ 15 files changed, 150 insertions(+), 150 deletions(-) delete mode 100644 include/dt-bindings/reset-controller/stih407-resets.h delete mode 100644 include/dt-bindings/reset-controller/stih415-resets.h delete mode 100644 include/dt-bindings/reset-controller/stih416-resets.h create mode 100644 include/dt-bindings/reset/stih407-resets.h create mode 100644 include/dt-bindings/reset/stih415-resets.h create mode 100644 include/dt-bindings/reset/stih416-resets.h (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt b/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt index 54ae9f747e45..9ca27761f811 100644 --- a/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt +++ b/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt @@ -39,4 +39,4 @@ Example: }; Macro definitions for the supported reset channels can be found in: -include/dt-bindings/reset-controller/stih407-resets.h +include/dt-bindings/reset/stih407-resets.h diff --git a/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt b/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt index 5ab26b7e9d35..1cfd21d1dfa1 100644 --- a/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt +++ b/Documentation/devicetree/bindings/reset/st,sti-powerdown.txt @@ -43,5 +43,5 @@ example: 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 +include/dt-bindings/reset/stih415-resets.h +include/dt-bindings/reset/stih416-resets.h diff --git a/Documentation/devicetree/bindings/reset/st,sti-softreset.txt b/Documentation/devicetree/bindings/reset/st,sti-softreset.txt index a8d3d3c25ca2..891a2fd85ed6 100644 --- a/Documentation/devicetree/bindings/reset/st,sti-softreset.txt +++ b/Documentation/devicetree/bindings/reset/st,sti-softreset.txt @@ -42,5 +42,5 @@ example: 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 +include/dt-bindings/reset/stih415-resets.h +include/dt-bindings/reset/stih416-resets.h diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi index 838b812cbda1..eab3477e0a0e 100644 --- a/arch/arm/boot/dts/stih407-family.dtsi +++ b/arch/arm/boot/dts/stih407-family.dtsi @@ -9,7 +9,7 @@ #include "stih407-pinctrl.dtsi" #include #include -#include +#include #include / { #address-cells = <1>; diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi index 19b019b5f30e..12427e651e5e 100644 --- a/arch/arm/boot/dts/stih415.dtsi +++ b/arch/arm/boot/dts/stih415.dtsi @@ -10,7 +10,7 @@ #include "stih415-clock.dtsi" #include "stih415-pinctrl.dtsi" #include -#include +#include / { L2: cache-controller { diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi index 9dca173e694a..9e3170ccd18c 100644 --- a/arch/arm/boot/dts/stih416.dtsi +++ b/arch/arm/boot/dts/stih416.dtsi @@ -12,7 +12,7 @@ #include #include -#include +#include #include / { L2: cache-controller { diff --git a/drivers/reset/sti/reset-stih407.c b/drivers/reset/sti/reset-stih407.c index d83db5d72d08..f7a6cb093983 100644 --- a/drivers/reset/sti/reset-stih407.c +++ b/drivers/reset/sti/reset-stih407.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include "reset-syscfg.h" /* STiH407 Peripheral powerdown definitions. */ diff --git a/drivers/reset/sti/reset-stih415.c b/drivers/reset/sti/reset-stih415.c index 8dad603d863c..f7b49d5a62dc 100644 --- a/drivers/reset/sti/reset-stih415.c +++ b/drivers/reset/sti/reset-stih415.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include "reset-syscfg.h" diff --git a/drivers/reset/sti/reset-stih416.c b/drivers/reset/sti/reset-stih416.c index 79aed70a26c0..d65a82e74004 100644 --- a/drivers/reset/sti/reset-stih416.c +++ b/drivers/reset/sti/reset-stih416.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include "reset-syscfg.h" diff --git a/include/dt-bindings/reset-controller/stih407-resets.h b/include/dt-bindings/reset-controller/stih407-resets.h deleted file mode 100644 index 02d4328fe479..000000000000 --- a/include/dt-bindings/reset-controller/stih407-resets.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This header provides constants for the reset controller - * based peripheral powerdown requests on the STMicroelectronics - * STiH407 SoC. - */ -#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH407 -#define _DT_BINDINGS_RESET_CONTROLLER_STIH407 - -/* Powerdown requests control 0 */ -#define STIH407_EMISS_POWERDOWN 0 -#define STIH407_NAND_POWERDOWN 1 - -/* Synp GMAC PowerDown */ -#define STIH407_ETH1_POWERDOWN 2 - -/* Powerdown requests control 1 */ -#define STIH407_USB3_POWERDOWN 3 -#define STIH407_USB2_PORT1_POWERDOWN 4 -#define STIH407_USB2_PORT0_POWERDOWN 5 -#define STIH407_PCIE1_POWERDOWN 6 -#define STIH407_PCIE0_POWERDOWN 7 -#define STIH407_SATA1_POWERDOWN 8 -#define STIH407_SATA0_POWERDOWN 9 - -/* Reset defines */ -#define STIH407_ETH1_SOFTRESET 0 -#define STIH407_MMC1_SOFTRESET 1 -#define STIH407_PICOPHY_SOFTRESET 2 -#define STIH407_IRB_SOFTRESET 3 -#define STIH407_PCIE0_SOFTRESET 4 -#define STIH407_PCIE1_SOFTRESET 5 -#define STIH407_SATA0_SOFTRESET 6 -#define STIH407_SATA1_SOFTRESET 7 -#define STIH407_MIPHY0_SOFTRESET 8 -#define STIH407_MIPHY1_SOFTRESET 9 -#define STIH407_MIPHY2_SOFTRESET 10 -#define STIH407_SATA0_PWR_SOFTRESET 11 -#define STIH407_SATA1_PWR_SOFTRESET 12 -#define STIH407_DELTA_SOFTRESET 13 -#define STIH407_BLITTER_SOFTRESET 14 -#define STIH407_HDTVOUT_SOFTRESET 15 -#define STIH407_HDQVDP_SOFTRESET 16 -#define STIH407_VDP_AUX_SOFTRESET 17 -#define STIH407_COMPO_SOFTRESET 18 -#define STIH407_HDMI_TX_PHY_SOFTRESET 19 -#define STIH407_JPEG_DEC_SOFTRESET 20 -#define STIH407_VP8_DEC_SOFTRESET 21 -#define STIH407_GPU_SOFTRESET 22 -#define STIH407_HVA_SOFTRESET 23 -#define STIH407_ERAM_HVA_SOFTRESET 24 -#define STIH407_LPM_SOFTRESET 25 -#define STIH407_KEYSCAN_SOFTRESET 26 -#define STIH407_USB2_PORT0_SOFTRESET 27 -#define STIH407_USB2_PORT1_SOFTRESET 28 - -/* Picophy reset defines */ -#define STIH407_PICOPHY0_RESET 0 -#define STIH407_PICOPHY1_RESET 1 -#define STIH407_PICOPHY2_RESET 2 - -#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH407 */ diff --git a/include/dt-bindings/reset-controller/stih415-resets.h b/include/dt-bindings/reset-controller/stih415-resets.h deleted file mode 100644 index c2329fe29cf6..000000000000 --- a/include/dt-bindings/reset-controller/stih415-resets.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 - -#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 -#define STIH415_KEYSCAN_SOFTRESET 6 - -#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH415 */ diff --git a/include/dt-bindings/reset-controller/stih416-resets.h b/include/dt-bindings/reset-controller/stih416-resets.h deleted file mode 100644 index fcf9af1ac0b2..000000000000 --- a/include/dt-bindings/reset-controller/stih416-resets.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 - -#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 -#define STIH416_KEYSCAN_SOFTRESET 28 - -#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH416 */ diff --git a/include/dt-bindings/reset/stih407-resets.h b/include/dt-bindings/reset/stih407-resets.h new file mode 100644 index 000000000000..02d4328fe479 --- /dev/null +++ b/include/dt-bindings/reset/stih407-resets.h @@ -0,0 +1,61 @@ +/* + * This header provides constants for the reset controller + * based peripheral powerdown requests on the STMicroelectronics + * STiH407 SoC. + */ +#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH407 +#define _DT_BINDINGS_RESET_CONTROLLER_STIH407 + +/* Powerdown requests control 0 */ +#define STIH407_EMISS_POWERDOWN 0 +#define STIH407_NAND_POWERDOWN 1 + +/* Synp GMAC PowerDown */ +#define STIH407_ETH1_POWERDOWN 2 + +/* Powerdown requests control 1 */ +#define STIH407_USB3_POWERDOWN 3 +#define STIH407_USB2_PORT1_POWERDOWN 4 +#define STIH407_USB2_PORT0_POWERDOWN 5 +#define STIH407_PCIE1_POWERDOWN 6 +#define STIH407_PCIE0_POWERDOWN 7 +#define STIH407_SATA1_POWERDOWN 8 +#define STIH407_SATA0_POWERDOWN 9 + +/* Reset defines */ +#define STIH407_ETH1_SOFTRESET 0 +#define STIH407_MMC1_SOFTRESET 1 +#define STIH407_PICOPHY_SOFTRESET 2 +#define STIH407_IRB_SOFTRESET 3 +#define STIH407_PCIE0_SOFTRESET 4 +#define STIH407_PCIE1_SOFTRESET 5 +#define STIH407_SATA0_SOFTRESET 6 +#define STIH407_SATA1_SOFTRESET 7 +#define STIH407_MIPHY0_SOFTRESET 8 +#define STIH407_MIPHY1_SOFTRESET 9 +#define STIH407_MIPHY2_SOFTRESET 10 +#define STIH407_SATA0_PWR_SOFTRESET 11 +#define STIH407_SATA1_PWR_SOFTRESET 12 +#define STIH407_DELTA_SOFTRESET 13 +#define STIH407_BLITTER_SOFTRESET 14 +#define STIH407_HDTVOUT_SOFTRESET 15 +#define STIH407_HDQVDP_SOFTRESET 16 +#define STIH407_VDP_AUX_SOFTRESET 17 +#define STIH407_COMPO_SOFTRESET 18 +#define STIH407_HDMI_TX_PHY_SOFTRESET 19 +#define STIH407_JPEG_DEC_SOFTRESET 20 +#define STIH407_VP8_DEC_SOFTRESET 21 +#define STIH407_GPU_SOFTRESET 22 +#define STIH407_HVA_SOFTRESET 23 +#define STIH407_ERAM_HVA_SOFTRESET 24 +#define STIH407_LPM_SOFTRESET 25 +#define STIH407_KEYSCAN_SOFTRESET 26 +#define STIH407_USB2_PORT0_SOFTRESET 27 +#define STIH407_USB2_PORT1_SOFTRESET 28 + +/* Picophy reset defines */ +#define STIH407_PICOPHY0_RESET 0 +#define STIH407_PICOPHY1_RESET 1 +#define STIH407_PICOPHY2_RESET 2 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH407 */ diff --git a/include/dt-bindings/reset/stih415-resets.h b/include/dt-bindings/reset/stih415-resets.h new file mode 100644 index 000000000000..c2329fe29cf6 --- /dev/null +++ b/include/dt-bindings/reset/stih415-resets.h @@ -0,0 +1,27 @@ +/* + * 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 + +#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 +#define STIH415_KEYSCAN_SOFTRESET 6 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH415 */ diff --git a/include/dt-bindings/reset/stih416-resets.h b/include/dt-bindings/reset/stih416-resets.h new file mode 100644 index 000000000000..fcf9af1ac0b2 --- /dev/null +++ b/include/dt-bindings/reset/stih416-resets.h @@ -0,0 +1,51 @@ +/* + * 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 + +#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 +#define STIH416_KEYSCAN_SOFTRESET 28 + +#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH416 */ -- cgit v1.3-6-gb490 From a518db45c2580fd726f6578539482596f46a8219 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Mon, 16 Mar 2015 20:54:37 +0100 Subject: reset: sti: constify of_device_id array of_device_id is always used as const. (See driver.of_match_table and open firmware functions) Signed-off-by: Fabian Frederick Acked-by: Maxime Coquelin Acked-by: Patrice Chotard Signed-off-by: Philipp Zabel --- drivers/reset/sti/reset-stih407.c | 2 +- drivers/reset/sti/reset-stih415.c | 2 +- drivers/reset/sti/reset-stih416.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/reset/sti/reset-stih407.c b/drivers/reset/sti/reset-stih407.c index f7a6cb093983..827eb3dae47d 100644 --- a/drivers/reset/sti/reset-stih407.c +++ b/drivers/reset/sti/reset-stih407.c @@ -126,7 +126,7 @@ static const struct syscfg_reset_controller_data stih407_picophyreset_controller .channels = stih407_picophyresets, }; -static struct of_device_id stih407_reset_match[] = { +static const struct of_device_id stih407_reset_match[] = { { .compatible = "st,stih407-powerdown", .data = &stih407_powerdown_controller, diff --git a/drivers/reset/sti/reset-stih415.c b/drivers/reset/sti/reset-stih415.c index f7b49d5a62dc..6f220cdbef46 100644 --- a/drivers/reset/sti/reset-stih415.c +++ b/drivers/reset/sti/reset-stih415.c @@ -89,7 +89,7 @@ static struct syscfg_reset_controller_data stih415_softreset_controller = { .channels = stih415_softresets, }; -static struct of_device_id stih415_reset_match[] = { +static const struct of_device_id stih415_reset_match[] = { { .compatible = "st,stih415-powerdown", .data = &stih415_powerdown_controller, }, { .compatible = "st,stih415-softreset", diff --git a/drivers/reset/sti/reset-stih416.c b/drivers/reset/sti/reset-stih416.c index d65a82e74004..c581d606ef0f 100644 --- a/drivers/reset/sti/reset-stih416.c +++ b/drivers/reset/sti/reset-stih416.c @@ -120,7 +120,7 @@ static struct syscfg_reset_controller_data stih416_softreset_controller = { .channels = stih416_softresets, }; -static struct of_device_id stih416_reset_match[] = { +static const struct of_device_id stih416_reset_match[] = { { .compatible = "st,stih416-powerdown", .data = &stih416_powerdown_controller, }, { .compatible = "st,stih416-softreset", -- cgit v1.3-6-gb490 From c392b65ba853f653cff3d1c7de2138bd6906d536 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 6 May 2015 00:10:26 +0200 Subject: reset: add driver for lpc18xx rgu Add reset driver for the Reset Generation Unit (RGU) found on NXP LPC18xx and LPC43xx devies. This reset controller features up to 64 reset lines connected to different blocks and peripheral in the SoC. Most reset lines on the controller are self clearing except for those dealing with the Cortex-M0 cores on LPC43xx devices. This driver also registers a restart handler that can be used to reset the entire device. Signed-off-by: Joachim Eastwood Signed-off-by: Philipp Zabel --- drivers/reset/Makefile | 1 + drivers/reset/reset-lpc18xx.c | 258 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 drivers/reset/reset-lpc18xx.c (limited to 'drivers') diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 157d421f755b..1d41feeb2dce 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_RESET_CONTROLLER) += core.o +obj-$(CONFIG_ARCH_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o diff --git a/drivers/reset/reset-lpc18xx.c b/drivers/reset/reset-lpc18xx.c new file mode 100644 index 000000000000..70922e9ac27f --- /dev/null +++ b/drivers/reset/reset-lpc18xx.c @@ -0,0 +1,258 @@ +/* + * Reset driver for NXP LPC18xx/43xx Reset Generation Unit (RGU). + * + * Copyright (C) 2015 Joachim Eastwood + * + * 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 + +/* LPC18xx RGU registers */ +#define LPC18XX_RGU_CTRL0 0x100 +#define LPC18XX_RGU_CTRL1 0x104 +#define LPC18XX_RGU_ACTIVE_STATUS0 0x150 +#define LPC18XX_RGU_ACTIVE_STATUS1 0x154 + +#define LPC18XX_RGU_RESETS_PER_REG 32 + +/* Internal reset outputs */ +#define LPC18XX_RGU_CORE_RST 0 +#define LPC43XX_RGU_M0SUB_RST 12 +#define LPC43XX_RGU_M0APP_RST 56 + +struct lpc18xx_rgu_data { + struct reset_controller_dev rcdev; + struct clk *clk_delay; + struct clk *clk_reg; + void __iomem *base; + spinlock_t lock; + u32 delay_us; +}; + +#define to_rgu_data(p) container_of(p, struct lpc18xx_rgu_data, rcdev) + +static void __iomem *rgu_base; + +static int lpc18xx_rgu_restart(struct notifier_block *this, unsigned long mode, + void *cmd) +{ + writel(BIT(LPC18XX_RGU_CORE_RST), rgu_base + LPC18XX_RGU_CTRL0); + mdelay(2000); + + pr_emerg("%s: unable to restart system\n", __func__); + + return NOTIFY_DONE; +} + +static struct notifier_block lpc18xx_rgu_restart_nb = { + .notifier_call = lpc18xx_rgu_restart, + .priority = 192, +}; + +/* + * The LPC18xx RGU has mostly self-deasserting resets except for the + * two reset lines going to the internal Cortex-M0 cores. + * + * To prevent the M0 core resets from accidentally getting deasserted + * status register must be check and bits in control register set to + * preserve the state. + */ +static int lpc18xx_rgu_setclear_reset(struct reset_controller_dev *rcdev, + unsigned long id, bool set) +{ + struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); + u32 stat_offset = LPC18XX_RGU_ACTIVE_STATUS0; + u32 ctrl_offset = LPC18XX_RGU_CTRL0; + unsigned long flags; + u32 stat, rst_bit; + + stat_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); + ctrl_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); + rst_bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG); + + spin_lock_irqsave(&rc->lock, flags); + stat = ~readl(rc->base + stat_offset); + if (set) + writel(stat | rst_bit, rc->base + ctrl_offset); + else + writel(stat & ~rst_bit, rc->base + ctrl_offset); + spin_unlock_irqrestore(&rc->lock, flags); + + return 0; +} + +static int lpc18xx_rgu_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return lpc18xx_rgu_setclear_reset(rcdev, id, true); +} + +static int lpc18xx_rgu_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return lpc18xx_rgu_setclear_reset(rcdev, id, false); +} + +/* Only M0 cores require explicit reset deassert */ +static int lpc18xx_rgu_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); + + lpc18xx_rgu_assert(rcdev, id); + udelay(rc->delay_us); + + switch (id) { + case LPC43XX_RGU_M0SUB_RST: + case LPC43XX_RGU_M0APP_RST: + lpc18xx_rgu_setclear_reset(rcdev, id, false); + } + + return 0; +} + +static int lpc18xx_rgu_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev); + u32 bit, offset = LPC18XX_RGU_ACTIVE_STATUS0; + + offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32); + bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG); + + return !(readl(rc->base + offset) & bit); +} + +static struct reset_control_ops lpc18xx_rgu_ops = { + .reset = lpc18xx_rgu_reset, + .assert = lpc18xx_rgu_assert, + .deassert = lpc18xx_rgu_deassert, + .status = lpc18xx_rgu_status, +}; + +static int lpc18xx_rgu_probe(struct platform_device *pdev) +{ + struct lpc18xx_rgu_data *rc; + struct resource *res; + u32 fcclk, firc; + int ret; + + rc = devm_kzalloc(&pdev->dev, sizeof(*rc), GFP_KERNEL); + if (!rc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rc->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rc->base)) + return PTR_ERR(rc->base); + + rc->clk_reg = devm_clk_get(&pdev->dev, "reg"); + if (IS_ERR(rc->clk_reg)) { + dev_err(&pdev->dev, "reg clock not found\n"); + return PTR_ERR(rc->clk_reg); + } + + rc->clk_delay = devm_clk_get(&pdev->dev, "delay"); + if (IS_ERR(rc->clk_delay)) { + dev_err(&pdev->dev, "delay clock not found\n"); + return PTR_ERR(rc->clk_delay); + } + + ret = clk_prepare_enable(rc->clk_reg); + if (ret) { + dev_err(&pdev->dev, "unable to enable reg clock\n"); + return ret; + } + + ret = clk_prepare_enable(rc->clk_delay); + if (ret) { + dev_err(&pdev->dev, "unable to enable delay clock\n"); + goto dis_clk_reg; + } + + fcclk = clk_get_rate(rc->clk_reg) / USEC_PER_SEC; + firc = clk_get_rate(rc->clk_delay) / USEC_PER_SEC; + if (fcclk == 0 || firc == 0) + rc->delay_us = 2; + else + rc->delay_us = DIV_ROUND_UP(fcclk, firc * firc); + + spin_lock_init(&rc->lock); + + rc->rcdev.owner = THIS_MODULE; + rc->rcdev.nr_resets = 64; + rc->rcdev.ops = &lpc18xx_rgu_ops; + rc->rcdev.of_node = pdev->dev.of_node; + + platform_set_drvdata(pdev, rc); + + ret = reset_controller_register(&rc->rcdev); + if (ret) { + dev_err(&pdev->dev, "unable to register device\n"); + goto dis_clks; + } + + rgu_base = rc->base; + ret = register_restart_handler(&lpc18xx_rgu_restart_nb); + if (ret) + dev_warn(&pdev->dev, "failed to register restart handler\n"); + + return 0; + +dis_clks: + clk_disable_unprepare(rc->clk_delay); +dis_clk_reg: + clk_disable_unprepare(rc->clk_reg); + + return ret; +} + +static int lpc18xx_rgu_remove(struct platform_device *pdev) +{ + struct lpc18xx_rgu_data *rc = platform_get_drvdata(pdev); + int ret; + + ret = unregister_restart_handler(&lpc18xx_rgu_restart_nb); + if (ret) + dev_warn(&pdev->dev, "failed to unregister restart handler\n"); + + reset_controller_unregister(&rc->rcdev); + + clk_disable_unprepare(rc->clk_delay); + clk_disable_unprepare(rc->clk_reg); + + return 0; +} + +static const struct of_device_id lpc18xx_rgu_match[] = { + { .compatible = "nxp,lpc1850-rgu" }, + { } +}; +MODULE_DEVICE_TABLE(of, lpc18xx_rgu_match); + +static struct platform_driver lpc18xx_rgu_driver = { + .probe = lpc18xx_rgu_probe, + .remove = lpc18xx_rgu_remove, + .driver = { + .name = "lpc18xx-reset", + .of_match_table = lpc18xx_rgu_match, + }, +}; +module_platform_driver(lpc18xx_rgu_driver); + +MODULE_AUTHOR("Joachim Eastwood "); +MODULE_DESCRIPTION("Reset driver for LPC18xx/43xx RGU"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From 27e44646dc0083c931b71bbb8e179aeb38010d31 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Fri, 31 Jul 2015 16:03:10 -0500 Subject: reset: socfpga: Update reset-socfpga to read the altr,modrst-offset property In order for the Arria10 to be able to re-use the reset driver for SoCFPGA Cyclone5/Arria5, we need to read the 'altr,modrst-offset' property from the device tree entry. The 'altr,modrst-offset' property is the first register into the reset manager that is used for bringing peripherals out of reset. The driver assumes a modrst-offset of 0x10 in order to support legacy Cyclone5/Arria5 hardware. Signed-off-by: Dinh Nguyen --- drivers/reset/reset-socfpga.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c index 0a8def35ea2e..1a6c5d66c83b 100644 --- a/drivers/reset/reset-socfpga.c +++ b/drivers/reset/reset-socfpga.c @@ -24,11 +24,11 @@ #include #define NR_BANKS 4 -#define OFFSET_MODRST 0x10 struct socfpga_reset_data { spinlock_t lock; void __iomem *membase; + u32 modrst_offset; struct reset_controller_dev rcdev; }; @@ -45,8 +45,8 @@ static int socfpga_reset_assert(struct reset_controller_dev *rcdev, spin_lock_irqsave(&data->lock, flags); - reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS)); - writel(reg | BIT(offset), data->membase + OFFSET_MODRST + + reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS)); + writel(reg | BIT(offset), data->membase + data->modrst_offset + (bank * NR_BANKS)); spin_unlock_irqrestore(&data->lock, flags); @@ -67,8 +67,8 @@ static int socfpga_reset_deassert(struct reset_controller_dev *rcdev, spin_lock_irqsave(&data->lock, flags); - reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS)); - writel(reg & ~BIT(offset), data->membase + OFFSET_MODRST + + reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS)); + writel(reg & ~BIT(offset), data->membase + data->modrst_offset + (bank * NR_BANKS)); spin_unlock_irqrestore(&data->lock, flags); @@ -85,7 +85,7 @@ static int socfpga_reset_status(struct reset_controller_dev *rcdev, int offset = id % BITS_PER_LONG; u32 reg; - reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS)); + reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS)); return !(reg & BIT(offset)); } @@ -100,6 +100,8 @@ static int socfpga_reset_probe(struct platform_device *pdev) { struct socfpga_reset_data *data; struct resource *res; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; /* * The binding was mainlined without the required property. @@ -120,6 +122,11 @@ static int socfpga_reset_probe(struct platform_device *pdev) if (IS_ERR(data->membase)) return PTR_ERR(data->membase); + if (of_property_read_u32(np, "altr,modrst-offset", &data->modrst_offset)) { + dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n"); + data->modrst_offset = 0x10; + } + spin_lock_init(&data->lock); data->rcdev.owner = THIS_MODULE; -- cgit v1.3-6-gb490 From bff60792f994a87324ab57e89e945b4572b1ef77 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Fri, 31 Jul 2015 15:46:16 +0100 Subject: arm64: psci: factor invocation code to drivers To enable sharing with arm, move the core PSCI framework code to drivers/firmware. This results in a minor gain in lines of code, but this will quickly be amortised by the removal of code currently duplicated in arch/arm. Signed-off-by: Mark Rutland Acked-by: Catalin Marinas Reviewed-by: Hanjun Guo Tested-by: Hanjun Guo Cc: Lorenzo Pieralisi Cc: Will Deacon Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/acpi.h | 4 +- arch/arm64/include/asm/psci.h | 28 ---- arch/arm64/kernel/psci.c | 361 +---------------------------------------- arch/arm64/kernel/setup.c | 2 +- drivers/firmware/Kconfig | 3 + drivers/firmware/Makefile | 1 + drivers/firmware/psci.c | 369 ++++++++++++++++++++++++++++++++++++++++++ include/linux/psci.h | 52 ++++++ 9 files changed, 431 insertions(+), 390 deletions(-) delete mode 100644 arch/arm64/include/asm/psci.h create mode 100644 drivers/firmware/psci.c create mode 100644 include/linux/psci.h (limited to 'drivers') diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 318175f62c24..7c55a632c08b 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -20,6 +20,7 @@ config ARM64 select ARM_GIC_V2M if PCI_MSI select ARM_GIC_V3 select ARM_GIC_V3_ITS if PCI_MSI + select ARM_PSCI_FW select BUILDTIME_EXTABLE_SORT select CLONE_BACKWARDS select COMMON_CLK diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 406485ed110a..208cec08a74f 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -12,11 +12,11 @@ #ifndef _ASM_ACPI_H #define _ASM_ACPI_H -#include #include +#include +#include #include -#include #include /* Macros for consistency checks of the GICC subtable of MADT */ diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h deleted file mode 100644 index 49d7e1aaebdc..000000000000 --- a/arch/arm64/include/asm/psci.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2013 ARM Limited - */ - -#ifndef __ASM_PSCI_H -#define __ASM_PSCI_H - -int __init psci_dt_init(void); - -#ifdef CONFIG_ACPI -int __init psci_acpi_init(void); -bool __init acpi_psci_present(void); -bool __init acpi_psci_use_hvc(void); -#else -static inline int psci_acpi_init(void) { return 0; } -static inline bool acpi_psci_present(void) { return false; } -#endif - -#endif /* __ASM_PSCI_H */ diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 869f202748e8..51fd15a16461 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -18,23 +18,17 @@ #include #include #include -#include -#include #include +#include #include + #include #include -#include #include #include -#include #include #include -#include - -#define PSCI_POWER_STATE_TYPE_STANDBY 0 -#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 static bool psci_power_state_loses_context(u32 state) { @@ -50,122 +44,8 @@ static bool psci_power_state_is_valid(u32 state) return !(state & ~valid_mask); } -/* - * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF - * calls to its resident CPU, so we must avoid issuing those. We never migrate - * a Trusted OS even if it claims to be capable of migration -- doing so will - * require cooperation with a Trusted OS driver. - */ -static int resident_cpu = -1; - -struct psci_operations { - int (*cpu_suspend)(u32 state, unsigned long entry_point); - int (*cpu_off)(u32 state); - int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); - int (*migrate)(unsigned long cpuid); - int (*affinity_info)(unsigned long target_affinity, - unsigned long lowest_affinity_level); - int (*migrate_info_type)(void); -}; - -static struct psci_operations psci_ops; - -typedef unsigned long (psci_fn)(unsigned long, unsigned long, - unsigned long, unsigned long); -asmlinkage psci_fn __invoke_psci_fn_hvc; -asmlinkage psci_fn __invoke_psci_fn_smc; -static psci_fn *invoke_psci_fn; - -enum psci_function { - PSCI_FN_CPU_SUSPEND, - PSCI_FN_CPU_ON, - PSCI_FN_CPU_OFF, - PSCI_FN_MIGRATE, - PSCI_FN_MAX, -}; - static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); -static u32 psci_function_id[PSCI_FN_MAX]; - -static int psci_to_linux_errno(int errno) -{ - switch (errno) { - case PSCI_RET_SUCCESS: - return 0; - case PSCI_RET_NOT_SUPPORTED: - return -EOPNOTSUPP; - case PSCI_RET_INVALID_PARAMS: - return -EINVAL; - case PSCI_RET_DENIED: - return -EPERM; - }; - - return -EINVAL; -} - -static u32 psci_get_version(void) -{ - return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); -} - -static int psci_cpu_suspend(u32 state, unsigned long entry_point) -{ - int err; - u32 fn; - - fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; - err = invoke_psci_fn(fn, state, entry_point, 0); - return psci_to_linux_errno(err); -} - -static int psci_cpu_off(u32 state) -{ - int err; - u32 fn; - - fn = psci_function_id[PSCI_FN_CPU_OFF]; - err = invoke_psci_fn(fn, state, 0, 0); - return psci_to_linux_errno(err); -} - -static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point) -{ - int err; - u32 fn; - - fn = psci_function_id[PSCI_FN_CPU_ON]; - err = invoke_psci_fn(fn, cpuid, entry_point, 0); - return psci_to_linux_errno(err); -} - -static int psci_migrate(unsigned long cpuid) -{ - int err; - u32 fn; - - fn = psci_function_id[PSCI_FN_MIGRATE]; - err = invoke_psci_fn(fn, cpuid, 0, 0); - return psci_to_linux_errno(err); -} - -static int psci_affinity_info(unsigned long target_affinity, - unsigned long lowest_affinity_level) -{ - return invoke_psci_fn(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, - lowest_affinity_level, 0); -} - -static int psci_migrate_info_type(void) -{ - return invoke_psci_fn(PSCI_0_2_FN_MIGRATE_INFO_TYPE, 0, 0, 0); -} - -static unsigned long psci_migrate_info_up_cpu(void) -{ - return invoke_psci_fn(PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU, 0, 0, 0); -} - static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu) { int i, ret, count = 0; @@ -230,238 +110,6 @@ free_mem: return ret; } -static int get_set_conduit_method(struct device_node *np) -{ - const char *method; - - pr_info("probing for conduit method from DT.\n"); - - if (of_property_read_string(np, "method", &method)) { - pr_warn("missing \"method\" property\n"); - return -ENXIO; - } - - if (!strcmp("hvc", method)) { - invoke_psci_fn = __invoke_psci_fn_hvc; - } else if (!strcmp("smc", method)) { - invoke_psci_fn = __invoke_psci_fn_smc; - } else { - pr_warn("invalid \"method\" property: %s\n", method); - return -EINVAL; - } - return 0; -} - -static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd) -{ - invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); -} - -static void psci_sys_poweroff(void) -{ - invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); -} - -/* - * Detect the presence of a resident Trusted OS which may cause CPU_OFF to - * return DENIED (which would be fatal). - */ -static void __init psci_init_migrate(void) -{ - unsigned long cpuid; - int type, cpu; - - type = psci_ops.migrate_info_type(); - - if (type == PSCI_0_2_TOS_MP) { - pr_info("Trusted OS migration not required\n"); - return; - } - - if (type == PSCI_RET_NOT_SUPPORTED) { - pr_info("MIGRATE_INFO_TYPE not supported.\n"); - return; - } - - if (type != PSCI_0_2_TOS_UP_MIGRATE && - type != PSCI_0_2_TOS_UP_NO_MIGRATE) { - pr_err("MIGRATE_INFO_TYPE returned unknown type (%d)\n", type); - return; - } - - cpuid = psci_migrate_info_up_cpu(); - if (cpuid & ~MPIDR_HWID_BITMASK) { - pr_warn("MIGRATE_INFO_UP_CPU reported invalid physical ID (0x%lx)\n", - cpuid); - return; - } - - cpu = get_logical_index(cpuid); - resident_cpu = cpu >= 0 ? cpu : -1; - - pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid); -} - -static void __init psci_0_2_set_functions(void) -{ - pr_info("Using standard PSCI v0.2 function IDs\n"); - psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; - psci_ops.cpu_suspend = psci_cpu_suspend; - - psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; - psci_ops.cpu_off = psci_cpu_off; - - psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON; - psci_ops.cpu_on = psci_cpu_on; - - psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE; - psci_ops.migrate = psci_migrate; - - psci_ops.affinity_info = psci_affinity_info; - - psci_ops.migrate_info_type = psci_migrate_info_type; - - arm_pm_restart = psci_sys_reset; - - pm_power_off = psci_sys_poweroff; -} - -/* - * Probe function for PSCI firmware versions >= 0.2 - */ -static int __init psci_probe(void) -{ - u32 ver = psci_get_version(); - - pr_info("PSCIv%d.%d detected in firmware.\n", - PSCI_VERSION_MAJOR(ver), - PSCI_VERSION_MINOR(ver)); - - if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) { - pr_err("Conflicting PSCI version detected.\n"); - return -EINVAL; - } - - psci_0_2_set_functions(); - - psci_init_migrate(); - - return 0; -} - -typedef int (*psci_initcall_t)(const struct device_node *); - -/* - * PSCI init function for PSCI versions >=0.2 - * - * Probe based on PSCI PSCI_VERSION function - */ -static int __init psci_0_2_init(struct device_node *np) -{ - int err; - - err = get_set_conduit_method(np); - - if (err) - goto out_put_node; - /* - * Starting with v0.2, the PSCI specification introduced a call - * (PSCI_VERSION) that allows probing the firmware version, so - * that PSCI function IDs and version specific initialization - * can be carried out according to the specific version reported - * by firmware - */ - err = psci_probe(); - -out_put_node: - of_node_put(np); - return err; -} - -/* - * PSCI < v0.2 get PSCI Function IDs via DT. - */ -static int __init psci_0_1_init(struct device_node *np) -{ - u32 id; - int err; - - err = get_set_conduit_method(np); - - if (err) - goto out_put_node; - - pr_info("Using PSCI v0.1 Function IDs from DT\n"); - - if (!of_property_read_u32(np, "cpu_suspend", &id)) { - psci_function_id[PSCI_FN_CPU_SUSPEND] = id; - psci_ops.cpu_suspend = psci_cpu_suspend; - } - - if (!of_property_read_u32(np, "cpu_off", &id)) { - psci_function_id[PSCI_FN_CPU_OFF] = id; - psci_ops.cpu_off = psci_cpu_off; - } - - if (!of_property_read_u32(np, "cpu_on", &id)) { - psci_function_id[PSCI_FN_CPU_ON] = id; - psci_ops.cpu_on = psci_cpu_on; - } - - if (!of_property_read_u32(np, "migrate", &id)) { - psci_function_id[PSCI_FN_MIGRATE] = id; - psci_ops.migrate = psci_migrate; - } - -out_put_node: - of_node_put(np); - return err; -} - -static const struct of_device_id psci_of_match[] __initconst = { - { .compatible = "arm,psci", .data = psci_0_1_init}, - { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, - {}, -}; - -int __init psci_dt_init(void) -{ - struct device_node *np; - const struct of_device_id *matched_np; - psci_initcall_t init_fn; - - np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np); - - if (!np) - return -ENODEV; - - init_fn = (psci_initcall_t)matched_np->data; - return init_fn(np); -} - -#ifdef CONFIG_ACPI -/* - * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's - * explicitly clarified in SBBR - */ -int __init psci_acpi_init(void) -{ - if (!acpi_psci_present()) { - pr_info("is not implemented in ACPI.\n"); - return -EOPNOTSUPP; - } - - pr_info("probing for conduit method from ACPI.\n"); - - if (acpi_psci_use_hvc()) - invoke_psci_fn = __invoke_psci_fn_hvc; - else - invoke_psci_fn = __invoke_psci_fn_smc; - - return psci_probe(); -} -#endif - #ifdef CONFIG_SMP static int __init cpu_psci_cpu_init(unsigned int cpu) @@ -489,11 +137,6 @@ static int cpu_psci_cpu_boot(unsigned int cpu) } #ifdef CONFIG_HOTPLUG_CPU -static bool psci_tos_resident_on(int cpu) -{ - return cpu == resident_cpu; -} - static int cpu_psci_cpu_disable(unsigned int cpu) { /* Fail early if we don't have CPU_OFF support */ diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index f3067d4d4e35..96ce26428f82 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -61,7 +62,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 99c69a3205c4..d8de6a8dd4de 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -5,6 +5,9 @@ menu "Firmware Drivers" +config ARM_PSCI_FW + bool + config EDD tristate "BIOS Enhanced Disk Drive calls determine boot disk" depends on X86 diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 4a4b897f9314..000830fc6707 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -1,6 +1,7 @@ # # Makefile for the linux kernel. # +obj-$(CONFIG_ARM_PSCI_FW) += psci.o obj-$(CONFIG_DMI) += dmi_scan.o obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o obj-$(CONFIG_EDD) += edd.o diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c new file mode 100644 index 000000000000..36e2cea3809b --- /dev/null +++ b/drivers/firmware/psci.c @@ -0,0 +1,369 @@ +/* + * 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. + * + * Copyright (C) 2015 ARM Limited + */ + +#define pr_fmt(fmt) "psci: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +/* + * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF + * calls to its resident CPU, so we must avoid issuing those. We never migrate + * a Trusted OS even if it claims to be capable of migration -- doing so will + * require cooperation with a Trusted OS driver. + */ +static int resident_cpu = -1; + +bool psci_tos_resident_on(int cpu) +{ + return cpu == resident_cpu; +} + +struct psci_operations psci_ops; + +typedef unsigned long (psci_fn)(unsigned long, unsigned long, + unsigned long, unsigned long); +asmlinkage psci_fn __invoke_psci_fn_hvc; +asmlinkage psci_fn __invoke_psci_fn_smc; +static psci_fn *invoke_psci_fn; + +enum psci_function { + PSCI_FN_CPU_SUSPEND, + PSCI_FN_CPU_ON, + PSCI_FN_CPU_OFF, + PSCI_FN_MIGRATE, + PSCI_FN_MAX, +}; + +static u32 psci_function_id[PSCI_FN_MAX]; + +static int psci_to_linux_errno(int errno) +{ + switch (errno) { + case PSCI_RET_SUCCESS: + return 0; + case PSCI_RET_NOT_SUPPORTED: + return -EOPNOTSUPP; + case PSCI_RET_INVALID_PARAMS: + return -EINVAL; + case PSCI_RET_DENIED: + return -EPERM; + }; + + return -EINVAL; +} + +static u32 psci_get_version(void) +{ + return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); +} + +static int psci_cpu_suspend(u32 state, unsigned long entry_point) +{ + int err; + u32 fn; + + fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; + err = invoke_psci_fn(fn, state, entry_point, 0); + return psci_to_linux_errno(err); +} + +static int psci_cpu_off(u32 state) +{ + int err; + u32 fn; + + fn = psci_function_id[PSCI_FN_CPU_OFF]; + err = invoke_psci_fn(fn, state, 0, 0); + return psci_to_linux_errno(err); +} + +static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point) +{ + int err; + u32 fn; + + fn = psci_function_id[PSCI_FN_CPU_ON]; + err = invoke_psci_fn(fn, cpuid, entry_point, 0); + return psci_to_linux_errno(err); +} + +static int psci_migrate(unsigned long cpuid) +{ + int err; + u32 fn; + + fn = psci_function_id[PSCI_FN_MIGRATE]; + err = invoke_psci_fn(fn, cpuid, 0, 0); + return psci_to_linux_errno(err); +} + +static int psci_affinity_info(unsigned long target_affinity, + unsigned long lowest_affinity_level) +{ + return invoke_psci_fn(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, + lowest_affinity_level, 0); +} + +static int psci_migrate_info_type(void) +{ + return invoke_psci_fn(PSCI_0_2_FN_MIGRATE_INFO_TYPE, 0, 0, 0); +} + +static unsigned long psci_migrate_info_up_cpu(void) +{ + return invoke_psci_fn(PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU, 0, 0, 0); +} + +static int get_set_conduit_method(struct device_node *np) +{ + const char *method; + + pr_info("probing for conduit method from DT.\n"); + + if (of_property_read_string(np, "method", &method)) { + pr_warn("missing \"method\" property\n"); + return -ENXIO; + } + + if (!strcmp("hvc", method)) { + invoke_psci_fn = __invoke_psci_fn_hvc; + } else if (!strcmp("smc", method)) { + invoke_psci_fn = __invoke_psci_fn_smc; + } else { + pr_warn("invalid \"method\" property: %s\n", method); + return -EINVAL; + } + return 0; +} + +static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd) +{ + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); +} + +static void psci_sys_poweroff(void) +{ + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); +} + +/* + * Detect the presence of a resident Trusted OS which may cause CPU_OFF to + * return DENIED (which would be fatal). + */ +static void __init psci_init_migrate(void) +{ + unsigned long cpuid; + int type, cpu = -1; + + type = psci_ops.migrate_info_type(); + + if (type == PSCI_0_2_TOS_MP) { + pr_info("Trusted OS migration not required\n"); + return; + } + + if (type == PSCI_RET_NOT_SUPPORTED) { + pr_info("MIGRATE_INFO_TYPE not supported.\n"); + return; + } + + if (type != PSCI_0_2_TOS_UP_MIGRATE && + type != PSCI_0_2_TOS_UP_NO_MIGRATE) { + pr_err("MIGRATE_INFO_TYPE returned unknown type (%d)\n", type); + return; + } + + cpuid = psci_migrate_info_up_cpu(); + if (cpuid & ~MPIDR_HWID_BITMASK) { + pr_warn("MIGRATE_INFO_UP_CPU reported invalid physical ID (0x%lx)\n", + cpuid); + return; + } + + cpu = get_logical_index(cpuid); + resident_cpu = cpu >= 0 ? cpu : -1; + + pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid); +} + +static void __init psci_0_2_set_functions(void) +{ + pr_info("Using standard PSCI v0.2 function IDs\n"); + psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; + psci_ops.cpu_suspend = psci_cpu_suspend; + + psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; + psci_ops.cpu_off = psci_cpu_off; + + psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON; + psci_ops.cpu_on = psci_cpu_on; + + psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE; + psci_ops.migrate = psci_migrate; + + psci_ops.affinity_info = psci_affinity_info; + + psci_ops.migrate_info_type = psci_migrate_info_type; + + arm_pm_restart = psci_sys_reset; + + pm_power_off = psci_sys_poweroff; +} + +/* + * Probe function for PSCI firmware versions >= 0.2 + */ +static int __init psci_probe(void) +{ + u32 ver = psci_get_version(); + + pr_info("PSCIv%d.%d detected in firmware.\n", + PSCI_VERSION_MAJOR(ver), + PSCI_VERSION_MINOR(ver)); + + if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) { + pr_err("Conflicting PSCI version detected.\n"); + return -EINVAL; + } + + psci_0_2_set_functions(); + + psci_init_migrate(); + + return 0; +} + +typedef int (*psci_initcall_t)(const struct device_node *); + +/* + * PSCI init function for PSCI versions >=0.2 + * + * Probe based on PSCI PSCI_VERSION function + */ +static int __init psci_0_2_init(struct device_node *np) +{ + int err; + + err = get_set_conduit_method(np); + + if (err) + goto out_put_node; + /* + * Starting with v0.2, the PSCI specification introduced a call + * (PSCI_VERSION) that allows probing the firmware version, so + * that PSCI function IDs and version specific initialization + * can be carried out according to the specific version reported + * by firmware + */ + err = psci_probe(); + +out_put_node: + of_node_put(np); + return err; +} + +/* + * PSCI < v0.2 get PSCI Function IDs via DT. + */ +static int __init psci_0_1_init(struct device_node *np) +{ + u32 id; + int err; + + err = get_set_conduit_method(np); + + if (err) + goto out_put_node; + + pr_info("Using PSCI v0.1 Function IDs from DT\n"); + + if (!of_property_read_u32(np, "cpu_suspend", &id)) { + psci_function_id[PSCI_FN_CPU_SUSPEND] = id; + psci_ops.cpu_suspend = psci_cpu_suspend; + } + + if (!of_property_read_u32(np, "cpu_off", &id)) { + psci_function_id[PSCI_FN_CPU_OFF] = id; + psci_ops.cpu_off = psci_cpu_off; + } + + if (!of_property_read_u32(np, "cpu_on", &id)) { + psci_function_id[PSCI_FN_CPU_ON] = id; + psci_ops.cpu_on = psci_cpu_on; + } + + if (!of_property_read_u32(np, "migrate", &id)) { + psci_function_id[PSCI_FN_MIGRATE] = id; + psci_ops.migrate = psci_migrate; + } + +out_put_node: + of_node_put(np); + return err; +} + +static const struct of_device_id psci_of_match[] __initconst = { + { .compatible = "arm,psci", .data = psci_0_1_init}, + { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, + {}, +}; + +int __init psci_dt_init(void) +{ + struct device_node *np; + const struct of_device_id *matched_np; + psci_initcall_t init_fn; + + np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np); + + if (!np) + return -ENODEV; + + init_fn = (psci_initcall_t)matched_np->data; + return init_fn(np); +} + +#ifdef CONFIG_ACPI +/* + * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's + * explicitly clarified in SBBR + */ +int __init psci_acpi_init(void) +{ + if (!acpi_psci_present()) { + pr_info("is not implemented in ACPI.\n"); + return -EOPNOTSUPP; + } + + pr_info("probing for conduit method from ACPI.\n"); + + if (acpi_psci_use_hvc()) + invoke_psci_fn = __invoke_psci_fn_hvc; + else + invoke_psci_fn = __invoke_psci_fn_smc; + + return psci_probe(); +} +#endif diff --git a/include/linux/psci.h b/include/linux/psci.h new file mode 100644 index 000000000000..a682fcc91c33 --- /dev/null +++ b/include/linux/psci.h @@ -0,0 +1,52 @@ +/* + * 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. + * + * Copyright (C) 2015 ARM Limited + */ + +#ifndef __LINUX_PSCI_H +#define __LINUX_PSCI_H + +#include +#include + +#define PSCI_POWER_STATE_TYPE_STANDBY 0 +#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 + +bool psci_tos_resident_on(int cpu); + +struct psci_operations { + int (*cpu_suspend)(u32 state, unsigned long entry_point); + int (*cpu_off)(u32 state); + int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); + int (*migrate)(unsigned long cpuid); + int (*affinity_info)(unsigned long target_affinity, + unsigned long lowest_affinity_level); + int (*migrate_info_type)(void); +}; + +extern struct psci_operations psci_ops; + +#if defined(CONFIG_ARM_PSCI_FW) +int __init psci_dt_init(void); +#else +static inline int psci_dt_init(void) { return 0; } +#endif + +#if defined(CONFIG_ARM_PSCI_FW) && defined(CONFIG_ACPI) +int __init psci_acpi_init(void); +bool __init acpi_psci_present(void); +bool __init acpi_psci_use_hvc(void); +#else +static inline int psci_acpi_init(void) { return 0; } +static inline bool acpi_psci_present(void) { return false; } +#endif + +#endif /* __LINUX_PSCI_H */ -- cgit v1.3-6-gb490 From 5211df00a4b595b96a7721a1253074b327945d33 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Fri, 31 Jul 2015 15:46:17 +0100 Subject: drivers: psci: support native SMC{32,64} calls A 32-bit OS cannot make calls with SMC64 IDs, while a 64-bit OS must invoke some PSCI functions with SMC64 IDs. This patch introduces and makes use of a new macro to choose the appropriate IDs based on the register width of the OS, which will allow 32-bit callers to use the PSCI client code. Signed-off-by: Mark Rutland Tested-by: Hanjun Guo Cc: Lorenzo Pieralisi Signed-off-by: Will Deacon --- drivers/firmware/psci.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 36e2cea3809b..a6956007dd38 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -27,6 +27,18 @@ #include #include +/* + * While a 64-bit OS can make calls with SMC32 calling conventions, for some + * calls it is necessary to use SMC64 to pass or return 64-bit values. For such + * calls PSCI_0_2_FN_NATIVE(x) will choose the appropriate (native-width) + * function ID. + */ +#ifdef CONFIG_64BIT +#define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN64_##name +#else +#define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN_##name +#endif + /* * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF * calls to its resident CPU, so we must avoid issuing those. We never migrate @@ -122,8 +134,8 @@ static int psci_migrate(unsigned long cpuid) static int psci_affinity_info(unsigned long target_affinity, unsigned long lowest_affinity_level) { - return invoke_psci_fn(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, - lowest_affinity_level, 0); + return invoke_psci_fn(PSCI_0_2_FN_NATIVE(AFFINITY_INFO), + target_affinity, lowest_affinity_level, 0); } static int psci_migrate_info_type(void) @@ -133,7 +145,8 @@ static int psci_migrate_info_type(void) static unsigned long psci_migrate_info_up_cpu(void) { - return invoke_psci_fn(PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU, 0, 0, 0); + return invoke_psci_fn(PSCI_0_2_FN_NATIVE(MIGRATE_INFO_UP_CPU), + 0, 0, 0); } static int get_set_conduit_method(struct device_node *np) @@ -211,16 +224,16 @@ static void __init psci_init_migrate(void) static void __init psci_0_2_set_functions(void) { pr_info("Using standard PSCI v0.2 function IDs\n"); - psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; + psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN_NATIVE(CPU_SUSPEND); psci_ops.cpu_suspend = psci_cpu_suspend; psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; psci_ops.cpu_off = psci_cpu_off; - psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON; + psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN_NATIVE(CPU_ON); psci_ops.cpu_on = psci_cpu_on; - psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE; + psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN_NATIVE(MIGRATE); psci_ops.migrate = psci_migrate; psci_ops.affinity_info = psci_affinity_info; -- cgit v1.3-6-gb490 From 53bdcf5f026c565e605ff4ced9178f85d48f69c5 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Fri, 17 Jul 2015 12:06:11 +0200 Subject: drm: sti: fix sub-components bind Fix misunderstanding in how use component framework. drm_platform_init() is now call only when all the sub-components are register themselves instead of the previous broken two stages mechanism. Update bindings documentation. Signed-off-by: Benjamin Gaignard --- .../devicetree/bindings/gpu/st,stih4xx.txt | 72 +++++++++++----------- drivers/gpu/drm/sti/sti_drm_drv.c | 45 ++------------ drivers/gpu/drm/sti/sti_hdmi.c | 25 ++++---- drivers/gpu/drm/sti/sti_tvout.c | 46 ++------------ 4 files changed, 57 insertions(+), 131 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt index 6b1d75f1a529..a36dfce0032e 100644 --- a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt +++ b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt @@ -52,10 +52,9 @@ STMicroelectronics stih4xx platforms See ../reset/reset.txt for details. - reset-names: names of the resets listed in resets property in the same order. - - ranges: to allow probing of subdevices - sti-hdmi: hdmi output block - must be a child of sti-tvout + must be a child of sti-display-subsystem Required properties: - compatible: "st,stih-hdmi"; - reg: Physical base address of the IP registers and length of memory mapped region. @@ -72,7 +71,7 @@ STMicroelectronics stih4xx platforms sti-hda: Required properties: - must be a child of sti-tvout + must be a child of sti-display-subsystem - compatible: "st,stih-hda" - reg: Physical base address of the IP registers and length of memory mapped region. - reg-names: names of the mapped memory regions listed in regs property in @@ -85,7 +84,7 @@ sti-hda: sti-dvo: Required properties: - must be a child of sti-tvout + must be a child of sti-display-subsystem - compatible: "st,stih-dvo" - reg: Physical base address of the IP registers and length of memory mapped region. - reg-names: names of the mapped memory regions listed in regs property in @@ -195,38 +194,37 @@ Example: reg-names = "tvout-reg", "hda-reg", "syscfg"; reset-names = "tvout"; resets = <&softreset STIH416_HDTVOUT_SOFTRESET>; - ranges; - - sti-hdmi@fe85c000 { - compatible = "st,stih416-hdmi"; - reg = <0xfe85c000 0x1000>, <0xfe830000 0x10000>; - reg-names = "hdmi-reg", "syscfg"; - interrupts = ; - interrupt-names = "irq"; - clock-names = "pix", "tmds", "phy", "audio"; - clocks = <&clockgen_c_vcc CLK_S_PIX_HDMI>, <&clockgen_c_vcc CLK_S_TMDS_HDMI>, <&clockgen_c_vcc CLK_S_HDMI_REJECT_PLL>, <&clockgen_b1 CLK_S_PCM_0>; - }; - - sti-hda@fe85a000 { - compatible = "st,stih416-hda"; - reg = <0xfe85a000 0x400>, <0xfe83085c 0x4>; - reg-names = "hda-reg", "video-dacs-ctrl"; - clock-names = "pix", "hddac"; - clocks = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>; - }; - - sti-dvo@8d00400 { - compatible = "st,stih407-dvo"; - reg = <0x8d00400 0x200>; - reg-names = "dvo-reg"; - clock-names = "dvo_pix", "dvo", - "main_parent", "aux_parent"; - clocks = <&clk_s_d2_flexgen CLK_PIX_DVO>, <&clk_s_d2_flexgen CLK_DVO>, - <&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_dvo>; - sti,panel = <&panel_dvo>; - }; + }; + + sti-hdmi@fe85c000 { + compatible = "st,stih416-hdmi"; + reg = <0xfe85c000 0x1000>, <0xfe830000 0x10000>; + reg-names = "hdmi-reg", "syscfg"; + interrupts = ; + interrupt-names = "irq"; + clock-names = "pix", "tmds", "phy", "audio"; + clocks = <&clockgen_c_vcc CLK_S_PIX_HDMI>, <&clockgen_c_vcc CLK_S_TMDS_HDMI>, <&clockgen_c_vcc CLK_S_HDMI_REJECT_PLL>, <&clockgen_b1 CLK_S_PCM_0>; + }; + + sti-hda@fe85a000 { + compatible = "st,stih416-hda"; + reg = <0xfe85a000 0x400>, <0xfe83085c 0x4>; + reg-names = "hda-reg", "video-dacs-ctrl"; + clock-names = "pix", "hddac"; + clocks = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>; + }; + + sti-dvo@8d00400 { + compatible = "st,stih407-dvo"; + reg = <0x8d00400 0x200>; + reg-names = "dvo-reg"; + clock-names = "dvo_pix", "dvo", + "main_parent", "aux_parent"; + clocks = <&clk_s_d2_flexgen CLK_PIX_DVO>, <&clk_s_d2_flexgen CLK_DVO>, + <&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dvo>; + sti,panel = <&panel_dvo>; }; sti-hqvdp@9c000000 { @@ -237,7 +235,7 @@ Example: reset-names = "hqvdp"; resets = <&softreset STIH407_HDQVDP_SOFTRESET>; st,vtg = <&vtg_main>; - }; + }; }; ... }; diff --git a/drivers/gpu/drm/sti/sti_drm_drv.c b/drivers/gpu/drm/sti/sti_drm_drv.c index 59d558b400b3..8ad9fe68335f 100644 --- a/drivers/gpu/drm/sti/sti_drm_drv.c +++ b/drivers/gpu/drm/sti/sti_drm_drv.c @@ -242,15 +242,17 @@ static const struct component_master_ops sti_drm_ops = { .unbind = sti_drm_unbind, }; -static int sti_drm_master_probe(struct platform_device *pdev) +static int sti_drm_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *node = dev->parent->of_node; + struct device_node *node = dev->of_node; struct device_node *child_np; struct component_match *match = NULL; dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); + of_platform_populate(node, NULL, NULL, dev); + child_np = of_get_next_available_child(node, NULL); while (child_np) { @@ -262,46 +264,11 @@ static int sti_drm_master_probe(struct platform_device *pdev) return component_master_add_with_match(dev, &sti_drm_ops, match); } -static int sti_drm_master_remove(struct platform_device *pdev) -{ - component_master_del(&pdev->dev, &sti_drm_ops); - return 0; -} - -static struct platform_driver sti_drm_master_driver = { - .probe = sti_drm_master_probe, - .remove = sti_drm_master_remove, - .driver = { - .name = DRIVER_NAME "__master", - }, -}; - -static int sti_drm_platform_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; - struct platform_device *master; - - of_platform_populate(node, NULL, NULL, dev); - - platform_driver_register(&sti_drm_master_driver); - master = platform_device_register_resndata(dev, - DRIVER_NAME "__master", -1, - NULL, 0, NULL, 0); - if (IS_ERR(master)) - return PTR_ERR(master); - - platform_set_drvdata(pdev, master); - return 0; -} - static int sti_drm_platform_remove(struct platform_device *pdev) { - struct platform_device *master = platform_get_drvdata(pdev); - + component_master_del(&pdev->dev, &sti_drm_ops); of_platform_depopulate(&pdev->dev); - platform_device_unregister(master); - platform_driver_unregister(&sti_drm_master_driver); + return 0; } diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index f28a4d54487c..06595e902526 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -693,21 +693,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) struct sti_hdmi_connector *connector; struct drm_connector *drm_connector; struct drm_bridge *bridge; - struct device_node *ddc; int err; - ddc = of_parse_phandle(dev->of_node, "ddc", 0); - if (ddc) { - hdmi->ddc_adapt = of_find_i2c_adapter_by_node(ddc); - if (!hdmi->ddc_adapt) { - err = -EPROBE_DEFER; - of_node_put(ddc); - return err; - } - - of_node_put(ddc); - } - /* Set the drm device handle */ hdmi->drm_dev = drm_dev; @@ -796,6 +783,7 @@ static int sti_hdmi_probe(struct platform_device *pdev) struct sti_hdmi *hdmi; struct device_node *np = dev->of_node; struct resource *res; + struct device_node *ddc; int ret; DRM_INFO("%s\n", __func__); @@ -804,6 +792,17 @@ static int sti_hdmi_probe(struct platform_device *pdev) if (!hdmi) return -ENOMEM; + ddc = of_parse_phandle(pdev->dev.of_node, "ddc", 0); + if (ddc) { + hdmi->ddc_adapt = of_find_i2c_adapter_by_node(ddc); + if (!hdmi->ddc_adapt) { + of_node_put(ddc); + return -EPROBE_DEFER; + } + + of_node_put(ddc); + } + hdmi->dev = pdev->dev; /* Get resources */ diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index 5cc53116508e..576b5becdf5f 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c @@ -644,7 +644,6 @@ static int sti_tvout_bind(struct device *dev, struct device *master, void *data) struct sti_tvout *tvout = dev_get_drvdata(dev); struct drm_device *drm_dev = data; unsigned int i; - int ret; tvout->drm_dev = drm_dev; @@ -658,17 +657,15 @@ static int sti_tvout_bind(struct device *dev, struct device *master, void *data) sti_tvout_create_encoders(drm_dev, tvout); - ret = component_bind_all(dev, drm_dev); - if (ret) - sti_tvout_destroy_encoders(tvout); - - return ret; + return 0; } static void sti_tvout_unbind(struct device *dev, struct device *master, void *data) { - /* do nothing */ + struct sti_tvout *tvout = dev_get_drvdata(dev); + + sti_tvout_destroy_encoders(tvout); } static const struct component_ops sti_tvout_ops = { @@ -676,34 +673,12 @@ static const struct component_ops sti_tvout_ops = { .unbind = sti_tvout_unbind, }; -static int compare_of(struct device *dev, void *data) -{ - return dev->of_node == data; -} - -static int sti_tvout_master_bind(struct device *dev) -{ - return 0; -} - -static void sti_tvout_master_unbind(struct device *dev) -{ - /* do nothing */ -} - -static const struct component_master_ops sti_tvout_master_ops = { - .bind = sti_tvout_master_bind, - .unbind = sti_tvout_master_unbind, -}; - static int sti_tvout_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; struct sti_tvout *tvout; struct resource *res; - struct device_node *child_np; - struct component_match *match = NULL; DRM_INFO("%s\n", __func__); @@ -734,24 +709,11 @@ static int sti_tvout_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tvout); - of_platform_populate(node, NULL, NULL, dev); - - child_np = of_get_next_available_child(node, NULL); - - while (child_np) { - component_match_add(dev, &match, compare_of, child_np); - of_node_put(child_np); - child_np = of_get_next_available_child(node, child_np); - } - - component_master_add_with_match(dev, &sti_tvout_master_ops, match); - return component_add(dev, &sti_tvout_ops); } static int sti_tvout_remove(struct platform_device *pdev) { - component_master_del(&pdev->dev, &sti_tvout_master_ops); component_del(&pdev->dev, &sti_tvout_ops); return 0; } -- cgit v1.3-6-gb490 From bf60b29f8e811c9593dcabaa4d25e412f9e10b73 Mon Sep 17 00:00:00 2001 From: Vincent Abriou Date: Fri, 31 Jul 2015 11:31:38 +0200 Subject: drm/sti: fix dynamic z-ordering Apply the plane depth when the plane is updated. If the depth is different from the previous plane update, the register controlling the plane depth is cleaned and updated with the new depth. Signed-off-by: Vincent Abriou Reviewed-by: Benjamin Gaignard --- drivers/gpu/drm/sti/sti_drm_plane.c | 23 +++++++++-------------- drivers/gpu/drm/sti/sti_mixer.c | 19 ++++++++++++++----- drivers/gpu/drm/sti/sti_mixer.h | 2 +- 3 files changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sti/sti_drm_plane.c b/drivers/gpu/drm/sti/sti_drm_plane.c index 64d4ed43dda3..5427bc28f205 100644 --- a/drivers/gpu/drm/sti/sti_drm_plane.c +++ b/drivers/gpu/drm/sti/sti_drm_plane.c @@ -15,17 +15,16 @@ #include "sti_drm_plane.h" #include "sti_vtg.h" +/* (Background) < GDP0 < GDP1 < VID0 < VID1 < GDP2 < GDP3 < (ForeGround) */ enum sti_layer_desc sti_layer_default_zorder[] = { STI_GDP_0, - STI_VID_0, STI_GDP_1, + STI_VID_0, STI_VID_1, STI_GDP_2, STI_GDP_3, }; -/* (Background) < GDP0 < VID0 < GDP1 < VID1 < GDP2 < GDP3 < (ForeGround) */ - static int sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, @@ -191,8 +190,7 @@ static const struct drm_plane_helper_funcs sti_drm_plane_helpers_funcs = { .atomic_disable = sti_drm_plane_atomic_disable, }; -static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane, - uint64_t default_val) +static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane) { struct drm_device *dev = plane->dev; struct sti_drm_private *private = dev->dev_private; @@ -201,16 +199,15 @@ static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane, prop = private->plane_zorder_property; if (!prop) { - prop = drm_property_create_range(dev, 0, "zpos", 0, - GAM_MIXER_NB_DEPTH_LEVEL - 1); + prop = drm_property_create_range(dev, 0, "zpos", 1, + GAM_MIXER_NB_DEPTH_LEVEL); if (!prop) return; private->plane_zorder_property = prop; } - drm_object_attach_property(&plane->base, prop, default_val); - layer->zorder = default_val; + drm_object_attach_property(&plane->base, prop, layer->zorder); } struct drm_plane *sti_drm_plane_init(struct drm_device *dev, @@ -219,7 +216,6 @@ struct drm_plane *sti_drm_plane_init(struct drm_device *dev, enum drm_plane_type type) { int err, i; - uint64_t default_zorder = 0; err = drm_universal_plane_init(dev, &layer->plane, possible_crtcs, &sti_drm_plane_funcs, @@ -236,15 +232,14 @@ struct drm_plane *sti_drm_plane_init(struct drm_device *dev, if (sti_layer_default_zorder[i] == layer->desc) break; - default_zorder = i + 1; + layer->zorder = i + 1; if (type == DRM_PLANE_TYPE_OVERLAY) - sti_drm_plane_attach_zorder_property(&layer->plane, - default_zorder); + sti_drm_plane_attach_zorder_property(&layer->plane); DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%llu\n", layer->plane.base.id, - sti_layer_to_str(layer), default_zorder); + sti_layer_to_str(layer), layer->zorder); return &layer->plane; } diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c index 13a4b84deab6..61a2048cf5d6 100644 --- a/drivers/gpu/drm/sti/sti_mixer.c +++ b/drivers/gpu/drm/sti/sti_mixer.c @@ -103,10 +103,11 @@ static void sti_mixer_set_background_area(struct sti_mixer *mixer, int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer) { - int layer_id = 0, depth = layer->zorder; + int layer_id, depth = layer->zorder; + unsigned int i; u32 mask, val; - if (depth >= GAM_MIXER_NB_DEPTH_LEVEL) + if ((depth < 1) || (depth > GAM_MIXER_NB_DEPTH_LEVEL)) return 1; switch (layer->desc) { @@ -136,15 +137,23 @@ int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer) DRM_ERROR("Unknown layer %d\n", layer->desc); return 1; } - mask = GAM_DEPTH_MASK_ID << (3 * depth); - layer_id = layer_id << (3 * depth); + + /* Search if a previous depth was already assigned to the layer */ + val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB); + for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) { + mask = GAM_DEPTH_MASK_ID << (3 * i); + if ((val & mask) == layer_id << (3 * i)) + break; + } + + mask |= GAM_DEPTH_MASK_ID << (3 * (depth - 1)); + layer_id = layer_id << (3 * (depth - 1)); DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer), sti_layer_to_str(layer), depth); dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n", layer_id, mask); - val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB); val &= ~mask; val |= layer_id; sti_mixer_reg_write(mixer, GAM_MIXER_CRB, val); diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h index b97282182908..eb663f65f814 100644 --- a/drivers/gpu/drm/sti/sti_mixer.h +++ b/drivers/gpu/drm/sti/sti_mixer.h @@ -49,7 +49,7 @@ int sti_mixer_active_video_area(struct sti_mixer *mixer, void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable); /* depth in Cross-bar control = z order */ -#define GAM_MIXER_NB_DEPTH_LEVEL 7 +#define GAM_MIXER_NB_DEPTH_LEVEL 6 #define STI_MIXER_MAIN 0 #define STI_MIXER_AUX 1 -- cgit v1.3-6-gb490 From 871bcdfea68560991bd650406e47a801ab9d635d Mon Sep 17 00:00:00 2001 From: Vincent Abriou Date: Fri, 31 Jul 2015 11:32:13 +0200 Subject: drm/sti: code clean up Purpose is to simplify the STI driver: - remove layer structure - consider video subdev as part of the compositor (like mixer subdev) - remove useless STI_VID0 and STI_VID1 enum Signed-off-by: Vincent Abriou Reviewed-by: Benjamin Gaignard --- drivers/gpu/drm/sti/Makefile | 1 - drivers/gpu/drm/sti/sti_compositor.c | 135 ++++++++------- drivers/gpu/drm/sti/sti_compositor.h | 12 +- drivers/gpu/drm/sti/sti_cursor.c | 108 ++++++------ drivers/gpu/drm/sti/sti_cursor.h | 3 +- drivers/gpu/drm/sti/sti_drm_crtc.c | 34 ++-- drivers/gpu/drm/sti/sti_drm_plane.c | 322 +++++++++++++++++++++++------------ drivers/gpu/drm/sti/sti_drm_plane.h | 91 +++++++++- drivers/gpu/drm/sti/sti_gdp.c | 185 ++++++++++---------- drivers/gpu/drm/sti/sti_gdp.h | 3 +- drivers/gpu/drm/sti/sti_hdmi.c | 2 +- drivers/gpu/drm/sti/sti_hqvdp.c | 201 +++++++++++----------- drivers/gpu/drm/sti/sti_hqvdp.h | 12 -- drivers/gpu/drm/sti/sti_layer.c | 213 ----------------------- drivers/gpu/drm/sti/sti_layer.h | 131 -------------- drivers/gpu/drm/sti/sti_mixer.c | 55 +++--- drivers/gpu/drm/sti/sti_mixer.h | 16 +- drivers/gpu/drm/sti/sti_vid.c | 57 ++----- drivers/gpu/drm/sti/sti_vid.h | 18 +- 19 files changed, 713 insertions(+), 886 deletions(-) delete mode 100644 drivers/gpu/drm/sti/sti_hqvdp.h delete mode 100644 drivers/gpu/drm/sti/sti_layer.c delete mode 100644 drivers/gpu/drm/sti/sti_layer.h (limited to 'drivers') diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile index f0f1e4ee2d92..505b3ba287ce 100644 --- a/drivers/gpu/drm/sti/Makefile +++ b/drivers/gpu/drm/sti/Makefile @@ -1,5 +1,4 @@ sticompositor-y := \ - sti_layer.o \ sti_mixer.o \ sti_gdp.o \ sti_vid.o \ diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index 43215d3020fb..68c5c954ce9a 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c @@ -14,10 +14,12 @@ #include #include "sti_compositor.h" +#include "sti_cursor.h" #include "sti_drm_crtc.h" #include "sti_drm_drv.h" #include "sti_drm_plane.h" #include "sti_gdp.h" +#include "sti_vid.h" #include "sti_vtg.h" /* @@ -31,7 +33,7 @@ struct sti_compositor_data stih407_compositor_data = { {STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200}, {STI_GPD_SUBDEV, (int)STI_GDP_2, 0x300}, {STI_GPD_SUBDEV, (int)STI_GDP_3, 0x400}, - {STI_VID_SUBDEV, (int)STI_VID_0, 0x700}, + {STI_VID_SUBDEV, (int)STI_HQVDP_0, 0x700}, {STI_MIXER_MAIN_SUBDEV, STI_MIXER_MAIN, 0xC00}, {STI_MIXER_AUX_SUBDEV, STI_MIXER_AUX, 0xD00}, }, @@ -53,14 +55,31 @@ struct sti_compositor_data stih416_compositor_data = { }, }; -static int sti_compositor_init_subdev(struct sti_compositor *compo, - struct sti_compositor_subdev_descriptor *desc, - unsigned int array_size) +static int sti_compositor_bind(struct device *dev, + struct device *master, + void *data) { - unsigned int i, mixer_id = 0, layer_id = 0; + struct sti_compositor *compo = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; + unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0, plane_id = 0; + struct sti_drm_private *dev_priv = drm_dev->dev_private; + struct drm_plane *cursor = NULL; + struct drm_plane *primary = NULL; + struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc; + unsigned int array_size = compo->data.nb_subdev; + + struct sti_plane *plane; + dev_priv->compo = compo; + + /* Register mixer subdev and video subdev first */ for (i = 0; i < array_size; i++) { switch (desc[i].type) { + case STI_VID_SUBDEV: + compo->vid[vid_id++] = + sti_vid_create(compo->dev, desc[i].id, + compo->regs + desc[i].offset); + break; case STI_MIXER_MAIN_SUBDEV: case STI_MIXER_AUX_SUBDEV: compo->mixer[mixer_id++] = @@ -68,81 +87,72 @@ static int sti_compositor_init_subdev(struct sti_compositor *compo, compo->regs + desc[i].offset); break; case STI_GPD_SUBDEV: - case STI_VID_SUBDEV: case STI_CURSOR_SUBDEV: - compo->layer[layer_id++] = - sti_layer_create(compo->dev, desc[i].id, - compo->regs + desc[i].offset); + /* Nothing to do, wait for the second round */ break; default: DRM_ERROR("Unknow subdev compoment type\n"); return 1; } - } - compo->nb_mixers = mixer_id; - compo->nb_layers = layer_id; - - return 0; -} -static int sti_compositor_bind(struct device *dev, struct device *master, - void *data) -{ - struct sti_compositor *compo = dev_get_drvdata(dev); - struct drm_device *drm_dev = data; - unsigned int i, crtc = 0, plane = 0; - struct sti_drm_private *dev_priv = drm_dev->dev_private; - struct drm_plane *cursor = NULL; - struct drm_plane *primary = NULL; - - dev_priv->compo = compo; - - for (i = 0; i < compo->nb_layers; i++) { - if (compo->layer[i]) { - enum sti_layer_desc desc = compo->layer[i]->desc; - enum sti_layer_type type = desc & STI_LAYER_TYPE_MASK; - enum drm_plane_type plane_type = DRM_PLANE_TYPE_OVERLAY; + /* Register the other subdevs, create crtc and planes */ + for (i = 0; i < array_size; i++) { + enum drm_plane_type plane_type = DRM_PLANE_TYPE_OVERLAY; - if (crtc < compo->nb_mixers) - plane_type = DRM_PLANE_TYPE_PRIMARY; + if (crtc_id < mixer_id) + plane_type = DRM_PLANE_TYPE_PRIMARY; - switch (type) { - case STI_CUR: - cursor = sti_drm_plane_init(drm_dev, - compo->layer[i], - 1, DRM_PLANE_TYPE_CURSOR); - break; - case STI_GDP: - case STI_VID: - primary = sti_drm_plane_init(drm_dev, - compo->layer[i], - (1 << compo->nb_mixers) - 1, - plane_type); - plane++; + switch (desc[i].type) { + case STI_MIXER_MAIN_SUBDEV: + case STI_MIXER_AUX_SUBDEV: + case STI_VID_SUBDEV: + /* Nothing to do, already done at the first round */ + break; + case STI_CURSOR_SUBDEV: + plane = sti_cursor_create(compo->dev, desc[i].id, + compo->regs + desc[i].offset); + if (!plane) { + DRM_ERROR("Can't create CURSOR plane\n"); break; - case STI_BCK: - case STI_VDP: + } + cursor = sti_drm_plane_init(drm_dev, plane, 1, + DRM_PLANE_TYPE_CURSOR); + plane_id++; + break; + case STI_GPD_SUBDEV: + plane = sti_gdp_create(compo->dev, desc[i].id, + compo->regs + desc[i].offset); + if (!plane) { + DRM_ERROR("Can't create GDP plane\n"); break; } + primary = sti_drm_plane_init(drm_dev, plane, + (1 << mixer_id) - 1, + plane_type); + plane_id++; + break; + default: + DRM_ERROR("Unknown subdev compoment type\n"); + return 1; + } - /* The first planes are reserved for primary planes*/ - if (crtc < compo->nb_mixers && primary) { - sti_drm_crtc_init(drm_dev, compo->mixer[crtc], - primary, cursor); - crtc++; - cursor = NULL; - primary = NULL; - } + /* The first planes are reserved for primary planes*/ + if (crtc_id < mixer_id && primary) { + sti_drm_crtc_init(drm_dev, compo->mixer[crtc_id], + primary, cursor); + crtc_id++; + cursor = NULL; + primary = NULL; } } - drm_vblank_init(drm_dev, crtc); + drm_vblank_init(drm_dev, crtc_id); /* Allow usage of vblank without having to call drm_irq_install */ drm_dev->irq_enabled = 1; DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n", - crtc, plane); + crtc_id, plane_id); DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n"); return 0; @@ -179,7 +189,6 @@ static int sti_compositor_probe(struct platform_device *pdev) struct device_node *vtg_np; struct sti_compositor *compo; struct resource *res; - int err; compo = devm_kzalloc(dev, sizeof(*compo), GFP_KERNEL); if (!compo) { @@ -251,12 +260,6 @@ static int sti_compositor_probe(struct platform_device *pdev) if (vtg_np) compo->vtg_aux = of_vtg_find(vtg_np); - /* Initialize compositor subdevices */ - err = sti_compositor_init_subdev(compo, compo->data.subdev_desc, - compo->data.nb_subdev); - if (err) - return err; - platform_set_drvdata(pdev, compo); return component_add(&pdev->dev, &sti_compositor_ops); diff --git a/drivers/gpu/drm/sti/sti_compositor.h b/drivers/gpu/drm/sti/sti_compositor.h index 019eb44c62cc..77f99780313a 100644 --- a/drivers/gpu/drm/sti/sti_compositor.h +++ b/drivers/gpu/drm/sti/sti_compositor.h @@ -12,13 +12,13 @@ #include #include -#include "sti_layer.h" +#include "sti_drm_plane.h" #include "sti_mixer.h" #define WAIT_NEXT_VSYNC_MS 50 /*ms*/ -#define STI_MAX_LAYER 8 #define STI_MAX_MIXER 2 +#define STI_MAX_VID 1 enum sti_compositor_subdev_type { STI_MIXER_MAIN_SUBDEV, @@ -59,11 +59,9 @@ struct sti_compositor_data { * @rst_main: reset control of the main path * @rst_aux: reset control of the aux path * @mixer: array of mixers + * @vid: array of vids * @vtg_main: vtg for main data path * @vtg_aux: vtg for auxillary data path - * @layer: array of layers - * @nb_mixers: number of mixers for this compositor - * @nb_layers: number of layers (GDP,VID,...) for this compositor * @vtg_vblank_nb: callback for VTG VSYNC notification */ struct sti_compositor { @@ -77,11 +75,9 @@ struct sti_compositor { struct reset_control *rst_main; struct reset_control *rst_aux; struct sti_mixer *mixer[STI_MAX_MIXER]; + struct sti_vid *vid[STI_MAX_VID]; struct sti_vtg *vtg_main; struct sti_vtg *vtg_aux; - struct sti_layer *layer[STI_MAX_LAYER]; - int nb_mixers; - int nb_layers; struct notifier_block vtg_vblank_nb; }; diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index 010eaee60bf7..cd12403dadcf 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -8,7 +8,7 @@ #include #include "sti_cursor.h" -#include "sti_layer.h" +#include "sti_drm_plane.h" #include "sti_vtg.h" /* Registers */ @@ -42,7 +42,9 @@ struct dma_pixmap { /** * STI Cursor structure * - * @layer: layer structure + * @sti_plane: sti_plane structure + * @dev: driver device + * @regs: cursor registers * @width: cursor width * @height: cursor height * @clut: color look up table @@ -50,7 +52,9 @@ struct dma_pixmap { * @pixmap: pixmap dma buffer (clut8-format cursor) */ struct sti_cursor { - struct sti_layer layer; + struct sti_plane plane; + struct device *dev; + void __iomem *regs; unsigned int width; unsigned int height; unsigned short *clut; @@ -62,22 +66,22 @@ static const uint32_t cursor_supported_formats[] = { DRM_FORMAT_ARGB8888, }; -#define to_sti_cursor(x) container_of(x, struct sti_cursor, layer) +#define to_sti_cursor(x) container_of(x, struct sti_cursor, plane) -static const uint32_t *sti_cursor_get_formats(struct sti_layer *layer) +static const uint32_t *sti_cursor_get_formats(struct sti_plane *plane) { return cursor_supported_formats; } -static unsigned int sti_cursor_get_nb_formats(struct sti_layer *layer) +static unsigned int sti_cursor_get_nb_formats(struct sti_plane *plane) { return ARRAY_SIZE(cursor_supported_formats); } -static void sti_cursor_argb8888_to_clut8(struct sti_layer *layer) +static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane) { - struct sti_cursor *cursor = to_sti_cursor(layer); - u32 *src = layer->vaddr; + struct sti_cursor *cursor = to_sti_cursor(plane); + u32 *src = plane->vaddr; u8 *dst = cursor->pixmap.base; unsigned int i, j; u32 a, r, g, b; @@ -96,42 +100,42 @@ static void sti_cursor_argb8888_to_clut8(struct sti_layer *layer) } } -static int sti_cursor_prepare_layer(struct sti_layer *layer, bool first_prepare) +static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare) { - struct sti_cursor *cursor = to_sti_cursor(layer); - struct drm_display_mode *mode = layer->mode; + struct sti_cursor *cursor = to_sti_cursor(plane); + struct drm_display_mode *mode = plane->mode; u32 y, x; u32 val; DRM_DEBUG_DRIVER("\n"); - dev_dbg(layer->dev, "%s %s\n", __func__, sti_layer_to_str(layer)); + dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); - if (layer->src_w < STI_CURS_MIN_SIZE || - layer->src_h < STI_CURS_MIN_SIZE || - layer->src_w > STI_CURS_MAX_SIZE || - layer->src_h > STI_CURS_MAX_SIZE) { + if (plane->src_w < STI_CURS_MIN_SIZE || + plane->src_h < STI_CURS_MIN_SIZE || + plane->src_w > STI_CURS_MAX_SIZE || + plane->src_h > STI_CURS_MAX_SIZE) { DRM_ERROR("Invalid cursor size (%dx%d)\n", - layer->src_w, layer->src_h); + plane->src_w, plane->src_h); return -EINVAL; } /* If the cursor size has changed, re-allocated the pixmap */ if (!cursor->pixmap.base || - (cursor->width != layer->src_w) || - (cursor->height != layer->src_h)) { - cursor->width = layer->src_w; - cursor->height = layer->src_h; + (cursor->width != plane->src_w) || + (cursor->height != plane->src_h)) { + cursor->width = plane->src_w; + cursor->height = plane->src_h; if (cursor->pixmap.base) - dma_free_writecombine(layer->dev, + dma_free_writecombine(cursor->dev, cursor->pixmap.size, cursor->pixmap.base, cursor->pixmap.paddr); cursor->pixmap.size = cursor->width * cursor->height; - cursor->pixmap.base = dma_alloc_writecombine(layer->dev, + cursor->pixmap.base = dma_alloc_writecombine(cursor->dev, cursor->pixmap.size, &cursor->pixmap.paddr, GFP_KERNEL | GFP_DMA); @@ -142,55 +146,54 @@ static int sti_cursor_prepare_layer(struct sti_layer *layer, bool first_prepare) } /* Convert ARGB8888 to CLUT8 */ - sti_cursor_argb8888_to_clut8(layer); + sti_cursor_argb8888_to_clut8(plane); /* AWS and AWE depend on the mode */ y = sti_vtg_get_line_number(*mode, 0); x = sti_vtg_get_pixel_number(*mode, 0); val = y << 16 | x; - writel(val, layer->regs + CUR_AWS); + writel(val, cursor->regs + CUR_AWS); y = sti_vtg_get_line_number(*mode, mode->vdisplay - 1); x = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1); val = y << 16 | x; - writel(val, layer->regs + CUR_AWE); + writel(val, cursor->regs + CUR_AWE); if (first_prepare) { /* Set and fetch CLUT */ - writel(cursor->clut_paddr, layer->regs + CUR_CML); - writel(CUR_CTL_CLUT_UPDATE, layer->regs + CUR_CTL); + writel(cursor->clut_paddr, cursor->regs + CUR_CML); + writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL); } return 0; } -static int sti_cursor_commit_layer(struct sti_layer *layer) +static int sti_cursor_commit_plane(struct sti_plane *plane) { - struct sti_cursor *cursor = to_sti_cursor(layer); - struct drm_display_mode *mode = layer->mode; + struct sti_cursor *cursor = to_sti_cursor(plane); + struct drm_display_mode *mode = plane->mode; u32 ydo, xdo; - dev_dbg(layer->dev, "%s %s\n", __func__, sti_layer_to_str(layer)); + dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); /* Set memory location, size, and position */ - writel(cursor->pixmap.paddr, layer->regs + CUR_PML); - writel(cursor->width, layer->regs + CUR_PMP); - writel(cursor->height << 16 | cursor->width, layer->regs + CUR_SIZE); + writel(cursor->pixmap.paddr, cursor->regs + CUR_PML); + writel(cursor->width, cursor->regs + CUR_PMP); + writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE); - ydo = sti_vtg_get_line_number(*mode, layer->dst_y); - xdo = sti_vtg_get_pixel_number(*mode, layer->dst_y); - writel((ydo << 16) | xdo, layer->regs + CUR_VPO); + ydo = sti_vtg_get_line_number(*mode, plane->dst_y); + xdo = sti_vtg_get_pixel_number(*mode, plane->dst_y); + writel((ydo << 16) | xdo, cursor->regs + CUR_VPO); return 0; } -static int sti_cursor_disable_layer(struct sti_layer *layer) +static int sti_cursor_disable_plane(struct sti_plane *plane) { return 0; } -static void sti_cursor_init(struct sti_layer *layer) +static void sti_cursor_init(struct sti_cursor *cursor) { - struct sti_cursor *cursor = to_sti_cursor(layer); unsigned short *base = cursor->clut; unsigned int a, r, g, b; @@ -205,16 +208,16 @@ static void sti_cursor_init(struct sti_layer *layer) (b * 5); } -static const struct sti_layer_funcs cursor_ops = { +static const struct sti_plane_funcs cursor_plane_ops = { .get_formats = sti_cursor_get_formats, .get_nb_formats = sti_cursor_get_nb_formats, - .init = sti_cursor_init, - .prepare = sti_cursor_prepare_layer, - .commit = sti_cursor_commit_layer, - .disable = sti_cursor_disable_layer, + .prepare = sti_cursor_prepare_plane, + .commit = sti_cursor_commit_plane, + .disable = sti_cursor_disable_plane, }; -struct sti_layer *sti_cursor_create(struct device *dev) +struct sti_plane *sti_cursor_create(struct device *dev, int desc, + void __iomem *baseaddr) { struct sti_cursor *cursor; @@ -236,7 +239,12 @@ struct sti_layer *sti_cursor_create(struct device *dev) return NULL; } - cursor->layer.ops = &cursor_ops; + cursor->dev = dev; + cursor->regs = baseaddr; + cursor->plane.desc = desc; + cursor->plane.ops = &cursor_plane_ops; - return (struct sti_layer *)cursor; + sti_cursor_init(cursor); + + return &cursor->plane; } diff --git a/drivers/gpu/drm/sti/sti_cursor.h b/drivers/gpu/drm/sti/sti_cursor.h index 3c9827404f27..db973b705d92 100644 --- a/drivers/gpu/drm/sti/sti_cursor.h +++ b/drivers/gpu/drm/sti/sti_cursor.h @@ -7,6 +7,7 @@ #ifndef _STI_CURSOR_H_ #define _STI_CURSOR_H_ -struct sti_layer *sti_cursor_create(struct device *dev); +struct sti_plane *sti_cursor_create(struct device *dev, int desc, + void __iomem *baseaddr); #endif diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c index 6b641c5a2ec7..a489b04a9abe 100644 --- a/drivers/gpu/drm/sti/sti_drm_crtc.c +++ b/drivers/gpu/drm/sti/sti_drm_crtc.c @@ -41,7 +41,7 @@ static void sti_drm_crtc_prepare(struct drm_crtc *crtc) DRM_INFO("Failed to prepare/enable compo_aux clk\n"); } - sti_mixer_clear_all_layers(mixer); + sti_mixer_clear_all_planes(mixer); } static void sti_drm_crtc_commit(struct drm_crtc *crtc) @@ -49,23 +49,21 @@ static void sti_drm_crtc_commit(struct drm_crtc *crtc) struct sti_mixer *mixer = to_sti_mixer(crtc); struct device *dev = mixer->dev; struct sti_compositor *compo = dev_get_drvdata(dev); - struct sti_layer *layer; + struct sti_plane *plane; if ((!mixer || !compo)) { - DRM_ERROR("Can not find mixer or compositor)\n"); + DRM_ERROR("Can't find mixer or compositor)\n"); return; } /* get GDP which is reserved to the CRTC FB */ - layer = to_sti_layer(crtc->primary); - if (layer) - sti_layer_commit(layer); - else - DRM_ERROR("Can not find CRTC dedicated plane (GDP0)\n"); + plane = to_sti_plane(crtc->primary); + if (!plane) + DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n"); - /* Enable layer on mixer */ - if (sti_mixer_set_layer_status(mixer, layer, true)) - DRM_ERROR("Can not enable layer at mixer\n"); + /* Enable plane on mixer */ + if (sti_mixer_set_plane_status(mixer, plane, true)) + DRM_ERROR("Cannot enable plane at mixer\n"); drm_crtc_vblank_on(crtc); } @@ -122,7 +120,7 @@ sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) res = sti_mixer_active_video_area(mixer, &crtc->mode); if (res) { - DRM_ERROR("Can not set active video area\n"); + DRM_ERROR("Can't set active video area\n"); return -EINVAL; } @@ -164,7 +162,7 @@ sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode); } -static void sti_drm_atomic_begin(struct drm_crtc *crtc) +static void sti_drm_crtc_atomic_begin(struct drm_crtc *crtc) { struct sti_mixer *mixer = to_sti_mixer(crtc); @@ -178,7 +176,7 @@ static void sti_drm_atomic_begin(struct drm_crtc *crtc) } } -static void sti_drm_atomic_flush(struct drm_crtc *crtc) +static void sti_drm_crtc_atomic_flush(struct drm_crtc *crtc) { } @@ -191,8 +189,8 @@ static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { .mode_set_nofb = sti_drm_crtc_mode_set_nofb, .mode_set_base = drm_helper_crtc_mode_set_base, .disable = sti_drm_crtc_disable, - .atomic_begin = sti_drm_atomic_begin, - .atomic_flush = sti_drm_atomic_flush, + .atomic_begin = sti_drm_crtc_atomic_begin, + .atomic_flush = sti_drm_crtc_atomic_flush, }; static void sti_drm_crtc_destroy(struct drm_crtc *crtc) @@ -248,6 +246,8 @@ int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) struct sti_compositor *compo = dev_priv->compo; struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; + DRM_DEBUG_DRIVER("\n"); + if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ? compo->vtg_main : compo->vtg_aux, vtg_vblank_nb, crtc)) { @@ -309,7 +309,7 @@ int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, &sti_crtc_funcs); if (res) { - DRM_ERROR("Can not initialze CRTC\n"); + DRM_ERROR("Can't initialze CRTC\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/sti/sti_drm_plane.c b/drivers/gpu/drm/sti/sti_drm_plane.c index 5427bc28f205..0d1672204b01 100644 --- a/drivers/gpu/drm/sti/sti_drm_plane.c +++ b/drivers/gpu/drm/sti/sti_drm_plane.c @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include "sti_compositor.h" @@ -15,120 +17,165 @@ #include "sti_drm_plane.h" #include "sti_vtg.h" -/* (Background) < GDP0 < GDP1 < VID0 < VID1 < GDP2 < GDP3 < (ForeGround) */ -enum sti_layer_desc sti_layer_default_zorder[] = { +/* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */ +enum sti_plane_desc sti_plane_default_zorder[] = { STI_GDP_0, STI_GDP_1, - STI_VID_0, - STI_VID_1, + STI_HQVDP_0, STI_GDP_2, STI_GDP_3, }; -static int -sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, - struct drm_framebuffer *fb, int crtc_x, int crtc_y, - unsigned int crtc_w, unsigned int crtc_h, - uint32_t src_x, uint32_t src_y, - uint32_t src_w, uint32_t src_h) +const char *sti_plane_to_str(struct sti_plane *plane) { - struct sti_layer *layer = to_sti_layer(plane); - struct sti_mixer *mixer = to_sti_mixer(crtc); + switch (plane->desc) { + case STI_GDP_0: + return "GDP0"; + case STI_GDP_1: + return "GDP1"; + case STI_GDP_2: + return "GDP2"; + case STI_GDP_3: + return "GDP3"; + case STI_HQVDP_0: + return "HQVDP0"; + case STI_CURSOR: + return "CURSOR"; + default: + return ""; + } +} +EXPORT_SYMBOL(sti_plane_to_str); + +static int sti_plane_prepare(struct sti_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_display_mode *mode, int mixer_id, + int dest_x, int dest_y, int dest_w, int dest_h, + int src_x, int src_y, int src_w, int src_h) +{ + struct drm_gem_cma_object *cma_obj; + unsigned int i; int res; - DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", - crtc->base.id, sti_mixer_to_str(mixer), - plane->base.id, sti_layer_to_str(layer)); - DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", crtc_w, crtc_h, crtc_x, crtc_y); + if (!plane || !fb || !mode) { + DRM_ERROR("Null fb, plane or mode\n"); + return 1; + } - res = sti_mixer_set_layer_depth(mixer, layer); - if (res) { - DRM_ERROR("Can not set layer depth\n"); - return res; + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + if (!cma_obj) { + DRM_ERROR("Can't get CMA GEM object for fb\n"); + return 1; } - /* src_x are in 16.16 format. */ - res = sti_layer_prepare(layer, crtc, fb, - &crtc->mode, mixer->id, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x >> 16, src_y >> 16, - src_w >> 16, src_h >> 16); - if (res) { - DRM_ERROR("Layer prepare failed\n"); - return res; + plane->fb = fb; + plane->mode = mode; + plane->mixer_id = mixer_id; + plane->dst_x = dest_x; + plane->dst_y = dest_y; + plane->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x); + plane->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y); + plane->src_x = src_x; + plane->src_y = src_y; + plane->src_w = src_w; + plane->src_h = src_h; + plane->format = fb->pixel_format; + plane->vaddr = cma_obj->vaddr; + plane->paddr = cma_obj->paddr; + for (i = 0; i < 4; i++) { + plane->pitches[i] = fb->pitches[i]; + plane->offsets[i] = fb->offsets[i]; } - res = sti_layer_commit(layer); - if (res) { - DRM_ERROR("Layer commit failed\n"); - return res; + DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n", + sti_plane_to_str(plane), + plane->mixer_id); + DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", + sti_plane_to_str(plane), + plane->dst_w, plane->dst_h, plane->dst_x, plane->dst_y, + plane->src_w, plane->src_h, plane->src_x, + plane->src_y); + + DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, + (char *)&plane->format, (unsigned long)plane->paddr); + + if (!plane->ops->prepare) { + DRM_ERROR("Cannot prepare\n"); + return 1; } - res = sti_mixer_set_layer_status(mixer, layer, true); + res = plane->ops->prepare(plane, !plane->enabled); if (res) { - DRM_ERROR("Can not enable layer at mixer\n"); + DRM_ERROR("Plane prepare failed\n"); return res; } + plane->enabled = true; + return 0; } -static int sti_drm_disable_plane(struct drm_plane *plane) +static int sti_plane_commit(struct sti_plane *plane) { - struct sti_layer *layer; - struct sti_mixer *mixer; - int lay_res, mix_res; + if (!plane) + return 1; - if (!plane->crtc) { - DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", plane->base.id); - return 0; + if (!plane->ops->commit) { + DRM_ERROR("Cannot commit\n"); + return 1; } - layer = to_sti_layer(plane); - mixer = to_sti_mixer(plane->crtc); - DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", - plane->crtc->base.id, sti_mixer_to_str(mixer), - plane->base.id, sti_layer_to_str(layer)); + return plane->ops->commit(plane); +} - /* Disable layer at mixer level */ - mix_res = sti_mixer_set_layer_status(mixer, layer, false); - if (mix_res) - DRM_ERROR("Can not disable layer at mixer\n"); +static int sti_plane_disable(struct sti_plane *plane) +{ + int res; - /* Wait a while to be sure that a Vsync event is received */ - msleep(WAIT_NEXT_VSYNC_MS); + DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); + if (!plane) + return 1; - /* Then disable layer itself */ - lay_res = sti_layer_disable(layer); - if (lay_res) - DRM_ERROR("Layer disable failed\n"); + if (!plane->enabled) + return 0; - if (lay_res || mix_res) - return -EINVAL; + if (!plane->ops->disable) { + DRM_ERROR("Cannot disable\n"); + return 1; + } + + res = plane->ops->disable(plane); + if (res) { + DRM_ERROR("Plane disable failed\n"); + return res; + } + + plane->enabled = false; return 0; } -static void sti_drm_plane_destroy(struct drm_plane *plane) +static void sti_drm_plane_destroy(struct drm_plane *drm_plane) { DRM_DEBUG_DRIVER("\n"); - drm_plane_helper_disable(plane); - drm_plane_cleanup(plane); + drm_plane_helper_disable(drm_plane); + drm_plane_cleanup(drm_plane); } -static int sti_drm_plane_set_property(struct drm_plane *plane, +static int sti_drm_plane_set_property(struct drm_plane *drm_plane, struct drm_property *property, uint64_t val) { - struct drm_device *dev = plane->dev; + struct drm_device *dev = drm_plane->dev; struct sti_drm_private *private = dev->dev_private; - struct sti_layer *layer = to_sti_layer(plane); + struct sti_plane *plane = to_sti_plane(drm_plane); DRM_DEBUG_DRIVER("\n"); if (property == private->plane_zorder_property) { - layer->zorder = val; + plane->zorder = val; return 0; } @@ -145,57 +192,105 @@ static struct drm_plane_funcs sti_drm_plane_funcs = { .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, }; -static int sti_drm_plane_prepare_fb(struct drm_plane *plane, - struct drm_framebuffer *fb, - const struct drm_plane_state *new_state) -{ - return 0; -} - -static void sti_drm_plane_cleanup_fb(struct drm_plane *plane, - struct drm_framebuffer *fb, - const struct drm_plane_state *old_fb) -{ -} - -static int sti_drm_plane_atomic_check(struct drm_plane *plane, +static int sti_drm_plane_atomic_check(struct drm_plane *drm_plane, struct drm_plane_state *state) { return 0; } -static void sti_drm_plane_atomic_update(struct drm_plane *plane, +static void sti_drm_plane_atomic_update(struct drm_plane *drm_plane, struct drm_plane_state *oldstate) { - struct drm_plane_state *state = plane->state; + struct drm_plane_state *state = drm_plane->state; + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_mixer *mixer = to_sti_mixer(state->crtc); + int res; + + DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", + state->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", + state->crtc_w, state->crtc_h, + state->crtc_x, state->crtc_y); + + res = sti_mixer_set_plane_depth(mixer, plane); + if (res) { + DRM_ERROR("Cannot set plane depth\n"); + return; + } - sti_drm_update_plane(plane, state->crtc, state->fb, - state->crtc_x, state->crtc_y, - state->crtc_w, state->crtc_h, - state->src_x, state->src_y, - state->src_w, state->src_h); + /* src_x are in 16.16 format */ + res = sti_plane_prepare(plane, state->crtc, state->fb, + &state->crtc->mode, mixer->id, + state->crtc_x, state->crtc_y, + state->crtc_w, state->crtc_h, + state->src_x >> 16, state->src_y >> 16, + state->src_w >> 16, state->src_h >> 16); + if (res) { + DRM_ERROR("Plane prepare failed\n"); + return; + } + + res = sti_plane_commit(plane); + if (res) { + DRM_ERROR("Plane commit failed\n"); + return; + } + + res = sti_mixer_set_plane_status(mixer, plane, true); + if (res) { + DRM_ERROR("Cannot enable plane at mixer\n"); + return; + } } -static void sti_drm_plane_atomic_disable(struct drm_plane *plane, +static void sti_drm_plane_atomic_disable(struct drm_plane *drm_plane, struct drm_plane_state *oldstate) { - sti_drm_disable_plane(plane); + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); + int res; + + if (!drm_plane->crtc) { + DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", + drm_plane->base.id); + return; + } + + DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", + drm_plane->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + + /* Disable plane at mixer level */ + res = sti_mixer_set_plane_status(mixer, plane, false); + if (res) { + DRM_ERROR("Cannot disable plane at mixer\n"); + return; + } + + /* Wait a while to be sure that a Vsync event is received */ + msleep(WAIT_NEXT_VSYNC_MS); + + /* Then disable plane itself */ + res = sti_plane_disable(plane); + if (res) { + DRM_ERROR("Plane disable failed\n"); + return; + } } static const struct drm_plane_helper_funcs sti_drm_plane_helpers_funcs = { - .prepare_fb = sti_drm_plane_prepare_fb, - .cleanup_fb = sti_drm_plane_cleanup_fb, .atomic_check = sti_drm_plane_atomic_check, .atomic_update = sti_drm_plane_atomic_update, .atomic_disable = sti_drm_plane_atomic_disable, }; -static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane) +static void sti_drm_plane_attach_zorder_property(struct drm_plane *drm_plane) { - struct drm_device *dev = plane->dev; + struct drm_device *dev = drm_plane->dev; struct sti_drm_private *private = dev->dev_private; + struct sti_plane *plane = to_sti_plane(drm_plane); struct drm_property *prop; - struct sti_layer *layer = to_sti_layer(plane); prop = private->plane_zorder_property; if (!prop) { @@ -207,40 +302,43 @@ static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane) private->plane_zorder_property = prop; } - drm_object_attach_property(&plane->base, prop, layer->zorder); + drm_object_attach_property(&drm_plane->base, prop, plane->zorder); } struct drm_plane *sti_drm_plane_init(struct drm_device *dev, - struct sti_layer *layer, - unsigned int possible_crtcs, - enum drm_plane_type type) + struct sti_plane *plane, + unsigned int possible_crtcs, + enum drm_plane_type type) { int err, i; - err = drm_universal_plane_init(dev, &layer->plane, possible_crtcs, - &sti_drm_plane_funcs, - sti_layer_get_formats(layer), - sti_layer_get_nb_formats(layer), type); + err = drm_universal_plane_init(dev, &plane->drm_plane, + possible_crtcs, + &sti_drm_plane_funcs, + plane->ops->get_formats(plane), + plane->ops->get_nb_formats(plane), + type); if (err) { - DRM_ERROR("Failed to initialize plane\n"); + DRM_ERROR("Failed to initialize universal plane\n"); return NULL; } - drm_plane_helper_add(&layer->plane, &sti_drm_plane_helpers_funcs); + drm_plane_helper_add(&plane->drm_plane, + &sti_drm_plane_helpers_funcs); - for (i = 0; i < ARRAY_SIZE(sti_layer_default_zorder); i++) - if (sti_layer_default_zorder[i] == layer->desc) + for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++) + if (sti_plane_default_zorder[i] == plane->desc) break; - layer->zorder = i + 1; + plane->zorder = i + 1; if (type == DRM_PLANE_TYPE_OVERLAY) - sti_drm_plane_attach_zorder_property(&layer->plane); + sti_drm_plane_attach_zorder_property(&plane->drm_plane); - DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%llu\n", - layer->plane.base.id, - sti_layer_to_str(layer), layer->zorder); + DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n", + plane->drm_plane.base.id, + sti_plane_to_str(plane), plane->zorder); - return &layer->plane; + return &plane->drm_plane; } EXPORT_SYMBOL(sti_drm_plane_init); diff --git a/drivers/gpu/drm/sti/sti_drm_plane.h b/drivers/gpu/drm/sti/sti_drm_plane.h index 4f191839f2a7..e5473661c85a 100644 --- a/drivers/gpu/drm/sti/sti_drm_plane.h +++ b/drivers/gpu/drm/sti/sti_drm_plane.h @@ -9,10 +9,97 @@ #include -struct sti_layer; +#define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) + +#define STI_PLANE_TYPE_SHIFT 8 +#define STI_PLANE_TYPE_MASK (~((1 << STI_PLANE_TYPE_SHIFT) - 1)) + +enum sti_plane_type { + STI_GDP = 1 << STI_PLANE_TYPE_SHIFT, + STI_VDP = 2 << STI_PLANE_TYPE_SHIFT, + STI_CUR = 3 << STI_PLANE_TYPE_SHIFT, + STI_BCK = 4 << STI_PLANE_TYPE_SHIFT +}; + +enum sti_plane_id_of_type { + STI_ID_0 = 0, + STI_ID_1 = 1, + STI_ID_2 = 2, + STI_ID_3 = 3 +}; + +enum sti_plane_desc { + STI_GDP_0 = STI_GDP | STI_ID_0, + STI_GDP_1 = STI_GDP | STI_ID_1, + STI_GDP_2 = STI_GDP | STI_ID_2, + STI_GDP_3 = STI_GDP | STI_ID_3, + STI_HQVDP_0 = STI_VDP | STI_ID_0, + STI_CURSOR = STI_CUR, + STI_BACK = STI_BCK +}; + +/** + * STI plane structure + * + * @plane: drm plane it is bound to (if any) + * @fb: drm fb it is bound to + * @mode: display mode + * @desc: plane type & id + * @ops: plane functions + * @zorder: plane z-order + * @mixer_id: id of the mixer used to display the plane + * @enabled: to know if the plane is active or not + * @src_x src_y: coordinates of the input (fb) area + * @src_w src_h: size of the input (fb) area + * @dst_x dst_y: coordinates of the output (crtc) area + * @dst_w dst_h: size of the output (crtc) area + * @format: format + * @pitches: pitch of 'planes' (eg: Y, U, V) + * @offsets: offset of 'planes' + * @vaddr: virtual address of the input buffer + * @paddr: physical address of the input buffer + */ +struct sti_plane { + struct drm_plane drm_plane; + struct drm_framebuffer *fb; + struct drm_display_mode *mode; + enum sti_plane_desc desc; + const struct sti_plane_funcs *ops; + int zorder; + int mixer_id; + bool enabled; + int src_x, src_y; + int src_w, src_h; + int dst_x, dst_y; + int dst_w, dst_h; + uint32_t format; + unsigned int pitches[4]; + unsigned int offsets[4]; + void *vaddr; + dma_addr_t paddr; +}; + +/** + * STI plane functions structure + * + * @get_formats: get plane supported formats + * @get_nb_formats: get number of format supported + * @prepare: prepare plane before rendering + * @commit: set plane for rendering + * @disable: disable plane + */ +struct sti_plane_funcs { + const uint32_t* (*get_formats)(struct sti_plane *plane); + unsigned int (*get_nb_formats)(struct sti_plane *plane); + int (*prepare)(struct sti_plane *plane, bool first_prepare); + int (*commit)(struct sti_plane *plane); + int (*disable)(struct sti_plane *plane); +}; struct drm_plane *sti_drm_plane_init(struct drm_device *dev, - struct sti_layer *layer, + struct sti_plane *sti_plane, unsigned int possible_crtcs, enum drm_plane_type type); +const char *sti_plane_to_str(struct sti_plane *plane); + #endif diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index 087906fd8846..e94d0be3c84f 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -10,8 +10,8 @@ #include #include "sti_compositor.h" +#include "sti_drm_plane.h" #include "sti_gdp.h" -#include "sti_layer.h" #include "sti_vtg.h" #define ALPHASWITCH BIT(6) @@ -85,16 +85,20 @@ struct sti_gdp_node_list { /** * STI GDP structure * - * @layer: layer structure + * @sti_plane: sti_plane structure + * @dev: driver device + * @regs: gdp registers * @clk_pix: pixel clock for the current gdp * @clk_main_parent: gdp parent clock if main path used * @clk_aux_parent: gdp parent clock if aux path used * @vtg_field_nb: callback for VTG FIELD (top or bottom) notification * @is_curr_top: true if the current node processed is the top field - * @node_list: array of node list + * @node_list: array of node list */ struct sti_gdp { - struct sti_layer layer; + struct sti_plane plane; + struct device *dev; + void __iomem *regs; struct clk *clk_pix; struct clk *clk_main_parent; struct clk *clk_aux_parent; @@ -103,7 +107,7 @@ struct sti_gdp { struct sti_gdp_node_list node_list[GDP_NODE_NB_BANK]; }; -#define to_sti_gdp(x) container_of(x, struct sti_gdp, layer) +#define to_sti_gdp(x) container_of(x, struct sti_gdp, plane) static const uint32_t gdp_supported_formats[] = { DRM_FORMAT_XRGB8888, @@ -120,12 +124,12 @@ static const uint32_t gdp_supported_formats[] = { DRM_FORMAT_C8, }; -static const uint32_t *sti_gdp_get_formats(struct sti_layer *layer) +static const uint32_t *sti_gdp_get_formats(struct sti_plane *plane) { return gdp_supported_formats; } -static unsigned int sti_gdp_get_nb_formats(struct sti_layer *layer) +static unsigned int sti_gdp_get_nb_formats(struct sti_plane *plane) { return ARRAY_SIZE(gdp_supported_formats); } @@ -175,20 +179,20 @@ static int sti_gdp_get_alpharange(int format) /** * sti_gdp_get_free_nodes - * @layer: gdp layer + * @plane: gdp plane * * Look for a GDP node list that is not currently read by the HW. * * RETURNS: * Pointer to the free GDP node list */ -static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_layer *layer) +static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane) { int hw_nvn; - struct sti_gdp *gdp = to_sti_gdp(layer); + struct sti_gdp *gdp = to_sti_gdp(plane); unsigned int i; - hw_nvn = readl(layer->regs + GAM_GDP_NVN_OFFSET); + hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); if (!hw_nvn) goto end; @@ -199,7 +203,7 @@ static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_layer *layer) /* in hazardious cases restart with the first node */ DRM_ERROR("inconsistent NVN for %s: 0x%08X\n", - sti_layer_to_str(layer), hw_nvn); + sti_plane_to_str(plane), hw_nvn); end: return &gdp->node_list[0]; @@ -207,7 +211,7 @@ end: /** * sti_gdp_get_current_nodes - * @layer: GDP layer + * @plane: GDP plane * * Look for GDP nodes that are currently read by the HW. * @@ -215,13 +219,13 @@ end: * Pointer to the current GDP node list */ static -struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_layer *layer) +struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane) { int hw_nvn; - struct sti_gdp *gdp = to_sti_gdp(layer); + struct sti_gdp *gdp = to_sti_gdp(plane); unsigned int i; - hw_nvn = readl(layer->regs + GAM_GDP_NVN_OFFSET); + hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); if (!hw_nvn) goto end; @@ -232,28 +236,28 @@ struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_layer *layer) end: DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n", - hw_nvn, sti_layer_to_str(layer)); + hw_nvn, sti_plane_to_str(plane)); return NULL; } /** - * sti_gdp_prepare_layer - * @lay: gdp layer + * sti_gdp_prepare + * @plane: gdp plane * @first_prepare: true if it is the first time this function is called * - * Update the free GDP node list according to the layer properties. + * Update the free GDP node list according to the plane properties. * * RETURNS: * 0 on success. */ -static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare) +static int sti_gdp_prepare(struct sti_plane *plane, bool first_prepare) { struct sti_gdp_node_list *list; struct sti_gdp_node *top_field, *btm_field; - struct drm_display_mode *mode = layer->mode; - struct device *dev = layer->dev; - struct sti_gdp *gdp = to_sti_gdp(layer); + struct drm_display_mode *mode = plane->mode; + struct sti_gdp *gdp = to_sti_gdp(plane); + struct device *dev = gdp->dev; struct sti_compositor *compo = dev_get_drvdata(dev); int format; unsigned int depth, bpp; @@ -261,20 +265,20 @@ static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare) int res; u32 ydo, xdo, yds, xds; - list = sti_gdp_get_free_nodes(layer); + list = sti_gdp_get_free_nodes(plane); top_field = list->top_field; btm_field = list->btm_field; dev_dbg(dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__, - sti_layer_to_str(layer), top_field, btm_field); + sti_plane_to_str(plane), top_field, btm_field); - /* Build the top field from layer params */ + /* Build the top field from plane params */ top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE; top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; - format = sti_gdp_fourcc2format(layer->format); + format = sti_gdp_fourcc2format(plane->format); if (format == -1) { DRM_ERROR("Format not supported by GDP %.4s\n", - (char *)&layer->format); + (char *)&plane->format); return 1; } top_field->gam_gdp_ctl |= format; @@ -282,22 +286,22 @@ static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare) top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE; /* pixel memory location */ - drm_fb_get_bpp_depth(layer->format, &depth, &bpp); - top_field->gam_gdp_pml = (u32) layer->paddr + layer->offsets[0]; - top_field->gam_gdp_pml += layer->src_x * (bpp >> 3); - top_field->gam_gdp_pml += layer->src_y * layer->pitches[0]; + drm_fb_get_bpp_depth(plane->format, &depth, &bpp); + top_field->gam_gdp_pml = (u32)plane->paddr + plane->offsets[0]; + top_field->gam_gdp_pml += plane->src_x * (bpp >> 3); + top_field->gam_gdp_pml += plane->src_y * plane->pitches[0]; /* input parameters */ - top_field->gam_gdp_pmp = layer->pitches[0]; + top_field->gam_gdp_pmp = plane->pitches[0]; top_field->gam_gdp_size = - clamp_val(layer->src_h, 0, GAM_GDP_SIZE_MAX) << 16 | - clamp_val(layer->src_w, 0, GAM_GDP_SIZE_MAX); + clamp_val(plane->src_h, 0, GAM_GDP_SIZE_MAX) << 16 | + clamp_val(plane->src_w, 0, GAM_GDP_SIZE_MAX); /* output parameters */ - ydo = sti_vtg_get_line_number(*mode, layer->dst_y); - yds = sti_vtg_get_line_number(*mode, layer->dst_y + layer->dst_h - 1); - xdo = sti_vtg_get_pixel_number(*mode, layer->dst_x); - xds = sti_vtg_get_pixel_number(*mode, layer->dst_x + layer->dst_w - 1); + ydo = sti_vtg_get_line_number(*mode, plane->dst_y); + yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1); + xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x); + xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1); top_field->gam_gdp_vpo = (ydo << 16) | xdo; top_field->gam_gdp_vps = (yds << 16) | xds; @@ -307,15 +311,15 @@ static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare) btm_field->gam_gdp_nvn = list->top_field_paddr; /* Interlaced mode */ - if (layer->mode->flags & DRM_MODE_FLAG_INTERLACE) + if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE) btm_field->gam_gdp_pml = top_field->gam_gdp_pml + - layer->pitches[0]; + plane->pitches[0]; if (first_prepare) { /* Register gdp callback */ - if (sti_vtg_register_client(layer->mixer_id == STI_MIXER_MAIN ? + if (sti_vtg_register_client(plane->mixer_id == STI_MIXER_MAIN ? compo->vtg_main : compo->vtg_aux, - &gdp->vtg_field_nb, layer->mixer_id)) { + &gdp->vtg_field_nb, plane->mixer_id)) { DRM_ERROR("Cannot register VTG notifier\n"); return 1; } @@ -325,7 +329,7 @@ static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare) struct clk *clkp; /* According to the mixer used, the gdp pixel clock * should have a different parent clock. */ - if (layer->mixer_id == STI_MIXER_MAIN) + if (plane->mixer_id == STI_MIXER_MAIN) clkp = gdp->clk_main_parent; else clkp = gdp->clk_aux_parent; @@ -351,8 +355,8 @@ static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare) } /** - * sti_gdp_commit_layer - * @lay: gdp layer + * sti_gdp_commit + * @plane: gdp plane * * Update the NVN field of the 'right' field of the current GDP node (being * used by the HW) with the address of the updated ('free') top field GDP node. @@ -365,38 +369,38 @@ static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare) * RETURNS: * 0 on success. */ -static int sti_gdp_commit_layer(struct sti_layer *layer) +static int sti_gdp_commit(struct sti_plane *plane) { - struct sti_gdp_node_list *updated_list = sti_gdp_get_free_nodes(layer); + struct sti_gdp_node_list *updated_list = sti_gdp_get_free_nodes(plane); struct sti_gdp_node *updated_top_node = updated_list->top_field; struct sti_gdp_node *updated_btm_node = updated_list->btm_field; - struct sti_gdp *gdp = to_sti_gdp(layer); + struct sti_gdp *gdp = to_sti_gdp(plane); u32 dma_updated_top = updated_list->top_field_paddr; u32 dma_updated_btm = updated_list->btm_field_paddr; - struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(layer); + struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(plane); - dev_dbg(layer->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__, - sti_layer_to_str(layer), - updated_top_node, updated_btm_node); - dev_dbg(layer->dev, "Current NVN:0x%X\n", - readl(layer->regs + GAM_GDP_NVN_OFFSET)); - dev_dbg(layer->dev, "Posted buff: %lx current buff: %x\n", - (unsigned long)layer->paddr, - readl(layer->regs + GAM_GDP_PML_OFFSET)); + dev_dbg(gdp->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__, + sti_plane_to_str(plane), + updated_top_node, updated_btm_node); + dev_dbg(gdp->dev, "Current NVN:0x%X\n", + readl(gdp->regs + GAM_GDP_NVN_OFFSET)); + dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n", + (unsigned long)plane->paddr, + readl(gdp->regs + GAM_GDP_PML_OFFSET)); if (curr_list == NULL) { /* First update or invalid node should directly write in the * hw register */ DRM_DEBUG_DRIVER("%s first update (or invalid node)", - sti_layer_to_str(layer)); + sti_plane_to_str(plane)); writel(gdp->is_curr_top == true ? dma_updated_btm : dma_updated_top, - layer->regs + GAM_GDP_NVN_OFFSET); + gdp->regs + GAM_GDP_NVN_OFFSET); return 0; } - if (layer->mode->flags & DRM_MODE_FLAG_INTERLACE) { + if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE) { if (gdp->is_curr_top == true) { /* Do not update in the middle of the frame, but * postpone the update after the bottom field has @@ -405,32 +409,32 @@ static int sti_gdp_commit_layer(struct sti_layer *layer) } else { /* Direct update to avoid one frame delay */ writel(dma_updated_top, - layer->regs + GAM_GDP_NVN_OFFSET); + gdp->regs + GAM_GDP_NVN_OFFSET); } } else { /* Direct update for progressive to avoid one frame delay */ - writel(dma_updated_top, layer->regs + GAM_GDP_NVN_OFFSET); + writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET); } return 0; } /** - * sti_gdp_disable_layer - * @lay: gdp layer + * sti_gdp_disable + * @plane: gdp plane * * Disable a GDP. * * RETURNS: * 0 on success. */ -static int sti_gdp_disable_layer(struct sti_layer *layer) +static int sti_gdp_disable(struct sti_plane *plane) { unsigned int i; - struct sti_gdp *gdp = to_sti_gdp(layer); - struct sti_compositor *compo = dev_get_drvdata(layer->dev); + struct sti_gdp *gdp = to_sti_gdp(plane); + struct sti_compositor *compo = dev_get_drvdata(gdp->dev); - DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer)); + DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); /* Set the nodes as 'to be ignored on mixer' */ for (i = 0; i < GDP_NODE_NB_BANK; i++) { @@ -438,7 +442,7 @@ static int sti_gdp_disable_layer(struct sti_layer *layer) gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; } - if (sti_vtg_unregister_client(layer->mixer_id == STI_MIXER_MAIN ? + if (sti_vtg_unregister_client(plane->mixer_id == STI_MIXER_MAIN ? compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb)) DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); @@ -479,10 +483,9 @@ int sti_gdp_field_cb(struct notifier_block *nb, return 0; } -static void sti_gdp_init(struct sti_layer *layer) +static void sti_gdp_init(struct sti_gdp *gdp) { - struct sti_gdp *gdp = to_sti_gdp(layer); - struct device_node *np = layer->dev->of_node; + struct device_node *np = gdp->dev->of_node; dma_addr_t dma_addr; void *base; unsigned int i, size; @@ -490,8 +493,8 @@ static void sti_gdp_init(struct sti_layer *layer) /* Allocate all the nodes within a single memory page */ size = sizeof(struct sti_gdp_node) * GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK; - base = dma_alloc_writecombine(layer->dev, - size, &dma_addr, GFP_KERNEL | GFP_DMA); + base = dma_alloc_writecombine(gdp->dev, + size, &dma_addr, GFP_KERNEL | GFP_DMA); if (!base) { DRM_ERROR("Failed to allocate memory for GDP node\n"); @@ -526,7 +529,7 @@ static void sti_gdp_init(struct sti_layer *layer) /* GDP of STiH407 chip have its own pixel clock */ char *clk_name; - switch (layer->desc) { + switch (gdp->plane.desc) { case STI_GDP_0: clk_name = "pix_gdp1"; break; @@ -544,30 +547,30 @@ static void sti_gdp_init(struct sti_layer *layer) return; } - gdp->clk_pix = devm_clk_get(layer->dev, clk_name); + gdp->clk_pix = devm_clk_get(gdp->dev, clk_name); if (IS_ERR(gdp->clk_pix)) DRM_ERROR("Cannot get %s clock\n", clk_name); - gdp->clk_main_parent = devm_clk_get(layer->dev, "main_parent"); + gdp->clk_main_parent = devm_clk_get(gdp->dev, "main_parent"); if (IS_ERR(gdp->clk_main_parent)) DRM_ERROR("Cannot get main_parent clock\n"); - gdp->clk_aux_parent = devm_clk_get(layer->dev, "aux_parent"); + gdp->clk_aux_parent = devm_clk_get(gdp->dev, "aux_parent"); if (IS_ERR(gdp->clk_aux_parent)) DRM_ERROR("Cannot get aux_parent clock\n"); } } -static const struct sti_layer_funcs gdp_ops = { +static const struct sti_plane_funcs gdp_plane_ops = { .get_formats = sti_gdp_get_formats, .get_nb_formats = sti_gdp_get_nb_formats, - .init = sti_gdp_init, - .prepare = sti_gdp_prepare_layer, - .commit = sti_gdp_commit_layer, - .disable = sti_gdp_disable_layer, + .prepare = sti_gdp_prepare, + .commit = sti_gdp_commit, + .disable = sti_gdp_disable, }; -struct sti_layer *sti_gdp_create(struct device *dev, int id) +struct sti_plane *sti_gdp_create(struct device *dev, int desc, + void __iomem *baseaddr) { struct sti_gdp *gdp; @@ -577,8 +580,14 @@ struct sti_layer *sti_gdp_create(struct device *dev, int id) return NULL; } - gdp->layer.ops = &gdp_ops; + gdp->dev = dev; + gdp->regs = baseaddr; + gdp->plane.desc = desc; + gdp->plane.ops = &gdp_plane_ops; + gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb; - return (struct sti_layer *)gdp; + sti_gdp_init(gdp); + + return &gdp->plane; } diff --git a/drivers/gpu/drm/sti/sti_gdp.h b/drivers/gpu/drm/sti/sti_gdp.h index 1dab68274ad3..01818ea72125 100644 --- a/drivers/gpu/drm/sti/sti_gdp.h +++ b/drivers/gpu/drm/sti/sti_gdp.h @@ -11,6 +11,7 @@ #include -struct sti_layer *sti_gdp_create(struct device *dev, int id); +struct sti_plane *sti_gdp_create(struct device *dev, int desc, + void __iomem *baseaddr); #endif diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 06595e902526..09e29e43423e 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -588,7 +588,7 @@ static int sti_hdmi_connector_get_modes(struct drm_connector *connector) return count; fail: - DRM_ERROR("Can not read HDMI EDID\n"); + DRM_ERROR("Can't read HDMI EDID\n"); return 0; } diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index b0eb62de1b2e..54e8c2f06cf4 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -14,9 +14,7 @@ #include #include "sti_drm_plane.h" -#include "sti_hqvdp.h" #include "sti_hqvdp_lut.h" -#include "sti_layer.h" #include "sti_vtg.h" /* Firmware name */ @@ -322,8 +320,7 @@ struct sti_hqvdp_cmd { * @dev: driver device * @drm_dev: the drm device * @regs: registers - * @layer: layer structure for hqvdp it self - * @vid_plane: VID plug used as link with compositor IP + * @plane: plane structure for hqvdp it self * @clk: IP clock * @clk_pix_main: pix main clock * @reset: reset control @@ -334,13 +331,13 @@ struct sti_hqvdp_cmd { * @hqvdp_cmd: buffer of commands * @hqvdp_cmd_paddr: physical address of hqvdp_cmd * @vtg: vtg for main data path + * @xp70_initialized: true if xp70 is already initialized */ struct sti_hqvdp { struct device *dev; struct drm_device *drm_dev; void __iomem *regs; - struct sti_layer layer; - struct drm_plane *vid_plane; + struct sti_plane plane; struct clk *clk; struct clk *clk_pix_main; struct reset_control *reset; @@ -351,20 +348,21 @@ struct sti_hqvdp { void *hqvdp_cmd; dma_addr_t hqvdp_cmd_paddr; struct sti_vtg *vtg; + bool xp70_initialized; }; -#define to_sti_hqvdp(x) container_of(x, struct sti_hqvdp, layer) +#define to_sti_hqvdp(x) container_of(x, struct sti_hqvdp, plane) static const uint32_t hqvdp_supported_formats[] = { DRM_FORMAT_NV12, }; -static const uint32_t *sti_hqvdp_get_formats(struct sti_layer *layer) +static const uint32_t *sti_hqvdp_get_formats(struct sti_plane *plane) { return hqvdp_supported_formats; } -static unsigned int sti_hqvdp_get_nb_formats(struct sti_layer *layer) +static unsigned int sti_hqvdp_get_nb_formats(struct sti_plane *plane) { return ARRAY_SIZE(hqvdp_supported_formats); } @@ -484,7 +482,7 @@ static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale, /** * sti_hqvdp_check_hw_scaling - * @layer: hqvdp layer + * @plane: hqvdp plane * * Check if the HW is able to perform the scaling request * The firmware scaling limitation is "CEIL(1/Zy) <= FLOOR(LFW)" where: @@ -498,23 +496,23 @@ static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale, * RETURNS: * True if the HW can scale. */ -static bool sti_hqvdp_check_hw_scaling(struct sti_layer *layer) +static bool sti_hqvdp_check_hw_scaling(struct sti_plane *plane) { - struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer); + struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); unsigned long lfw; unsigned int inv_zy; - lfw = layer->mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000); - lfw /= max(layer->src_w, layer->dst_w) * layer->mode->clock / 1000; + lfw = plane->mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000); + lfw /= max(plane->src_w, plane->dst_w) * plane->mode->clock / 1000; - inv_zy = DIV_ROUND_UP(layer->src_h, layer->dst_h); + inv_zy = DIV_ROUND_UP(plane->src_h, plane->dst_h); return (inv_zy <= lfw) ? true : false; } /** - * sti_hqvdp_prepare_layer - * @layer: hqvdp layer + * sti_hqvdp_prepare + * @plane: hqvdp plane * @first_prepare: true if it is the first time this function is called * * Prepares a command for the firmware @@ -522,22 +520,14 @@ static bool sti_hqvdp_check_hw_scaling(struct sti_layer *layer) * RETURNS: * 0 on success. */ -static int sti_hqvdp_prepare_layer(struct sti_layer *layer, bool first_prepare) +static int sti_hqvdp_prepare(struct sti_plane *plane, bool first_prepare) { - struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer); + struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); struct sti_hqvdp_cmd *cmd; int scale_h, scale_v; int cmd_offset; - dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_layer_to_str(layer)); - - /* prepare and commit VID plane */ - hqvdp->vid_plane->funcs->update_plane(hqvdp->vid_plane, - layer->crtc, layer->fb, - layer->dst_x, layer->dst_y, - layer->dst_w, layer->dst_h, - layer->src_x, layer->src_y, - layer->src_w, layer->src_h); + dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); if (cmd_offset == -1) { @@ -546,7 +536,7 @@ static int sti_hqvdp_prepare_layer(struct sti_layer *layer, bool first_prepare) } cmd = hqvdp->hqvdp_cmd + cmd_offset; - if (!sti_hqvdp_check_hw_scaling(layer)) { + if (!sti_hqvdp_check_hw_scaling(plane)) { DRM_ERROR("Scaling beyond HW capabilities\n"); return -EINVAL; } @@ -565,42 +555,42 @@ static int sti_hqvdp_prepare_layer(struct sti_layer *layer, bool first_prepare) cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT; /* Buffer planes address */ - cmd->top.current_luma = (u32) layer->paddr + layer->offsets[0]; - cmd->top.current_chroma = (u32) layer->paddr + layer->offsets[1]; + cmd->top.current_luma = (u32)plane->paddr + plane->offsets[0]; + cmd->top.current_chroma = (u32)plane->paddr + plane->offsets[1]; /* Pitches */ cmd->top.luma_processed_pitch = cmd->top.luma_src_pitch = - layer->pitches[0]; + plane->pitches[0]; cmd->top.chroma_processed_pitch = cmd->top.chroma_src_pitch = - layer->pitches[1]; + plane->pitches[1]; /* Input / output size * Align to upper even value */ - layer->dst_w = ALIGN(layer->dst_w, 2); - layer->dst_h = ALIGN(layer->dst_h, 2); + plane->dst_w = ALIGN(plane->dst_w, 2); + plane->dst_h = ALIGN(plane->dst_h, 2); - if ((layer->src_w > MAX_WIDTH) || (layer->src_w < MIN_WIDTH) || - (layer->src_h > MAX_HEIGHT) || (layer->src_h < MIN_HEIGHT) || - (layer->dst_w > MAX_WIDTH) || (layer->dst_w < MIN_WIDTH) || - (layer->dst_h > MAX_HEIGHT) || (layer->dst_h < MIN_HEIGHT)) { + if ((plane->src_w > MAX_WIDTH) || (plane->src_w < MIN_WIDTH) || + (plane->src_h > MAX_HEIGHT) || (plane->src_h < MIN_HEIGHT) || + (plane->dst_w > MAX_WIDTH) || (plane->dst_w < MIN_WIDTH) || + (plane->dst_h > MAX_HEIGHT) || (plane->dst_h < MIN_HEIGHT)) { DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n", - layer->src_w, layer->src_h, - layer->dst_w, layer->dst_h); + plane->src_w, plane->src_h, + plane->dst_w, plane->dst_h); return -EINVAL; } cmd->top.input_viewport_size = cmd->top.input_frame_size = - layer->src_h << 16 | layer->src_w; - cmd->hvsrc.output_picture_size = layer->dst_h << 16 | layer->dst_w; - cmd->top.input_viewport_ori = layer->src_y << 16 | layer->src_x; + plane->src_h << 16 | plane->src_w; + cmd->hvsrc.output_picture_size = plane->dst_h << 16 | plane->dst_w; + cmd->top.input_viewport_ori = plane->src_y << 16 | plane->src_x; /* Handle interlaced */ - if (layer->fb->flags & DRM_MODE_FB_INTERLACED) { + if (plane->fb->flags & DRM_MODE_FB_INTERLACED) { /* Top field to display */ cmd->top.config = TOP_CONFIG_INTER_TOP; /* Update pitches and vert size */ - cmd->top.input_frame_size = (layer->src_h / 2) << 16 | - layer->src_w; + cmd->top.input_frame_size = (plane->src_h / 2) << 16 | + plane->src_w; cmd->top.luma_processed_pitch *= 2; cmd->top.luma_src_pitch *= 2; cmd->top.chroma_processed_pitch *= 2; @@ -613,10 +603,10 @@ static int sti_hqvdp_prepare_layer(struct sti_layer *layer, bool first_prepare) } /* Update hvsrc lut coef */ - scale_h = SCALE_FACTOR * layer->dst_w / layer->src_w; + scale_h = SCALE_FACTOR * plane->dst_w / plane->src_w; sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc); - scale_v = SCALE_FACTOR * layer->dst_h / layer->src_h; + scale_v = SCALE_FACTOR * plane->dst_h / plane->src_h; sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc); if (first_prepare) { @@ -627,9 +617,9 @@ static int sti_hqvdp_prepare_layer(struct sti_layer *layer, bool first_prepare) } /* Register VTG Vsync callback to handle bottom fields */ - if ((layer->fb->flags & DRM_MODE_FB_INTERLACED) && - sti_vtg_register_client(hqvdp->vtg, - &hqvdp->vtg_nb, layer->mixer_id)) { + if ((plane->fb->flags & DRM_MODE_FB_INTERLACED) && + sti_vtg_register_client(hqvdp->vtg, &hqvdp->vtg_nb, + plane->mixer_id)) { DRM_ERROR("Cannot register VTG notifier\n"); return -ENXIO; } @@ -638,12 +628,21 @@ static int sti_hqvdp_prepare_layer(struct sti_layer *layer, bool first_prepare) return 0; } -static int sti_hqvdp_commit_layer(struct sti_layer *layer) +/** + * sti_hqvdp_commit + * @plane: hqvdp plane + * + * Enables the HQVDP plane + * + * RETURNS: + * 0 on success. + */ +static int sti_hqvdp_commit(struct sti_plane *plane) { - struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer); + struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); int cmd_offset; - dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_layer_to_str(layer)); + dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); if (cmd_offset == -1) { @@ -657,7 +656,7 @@ static int sti_hqvdp_commit_layer(struct sti_layer *layer) hqvdp->curr_field_count++; /* Interlaced : get ready to display the bottom field at next Vsync */ - if (layer->fb->flags & DRM_MODE_FB_INTERLACED) + if (plane->fb->flags & DRM_MODE_FB_INTERLACED) hqvdp->btm_field_pending = true; dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n", @@ -666,16 +665,25 @@ static int sti_hqvdp_commit_layer(struct sti_layer *layer) return 0; } -static int sti_hqvdp_disable_layer(struct sti_layer *layer) +/** + * sti_hqvdp_disable + * @plane: hqvdp plane + * + * Disables the HQVDP plane + * + * RETURNS: + * 0 on success. + */ +static int sti_hqvdp_disable(struct sti_plane *plane) { - struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer); + struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); int i; - DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer)); + DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); /* Unregister VTG Vsync callback */ - if ((layer->fb->flags & DRM_MODE_FB_INTERLACED) && - sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb)) + if ((plane->fb->flags & DRM_MODE_FB_INTERLACED) && + sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb)) DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); /* Set next cmd to NULL */ @@ -696,9 +704,6 @@ static int sti_hqvdp_disable_layer(struct sti_layer *layer) return -ENXIO; } - /* disable VID plane */ - hqvdp->vid_plane->funcs->disable_plane(hqvdp->vid_plane); - return 0; } @@ -758,32 +763,10 @@ int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data) return 0; } -static struct drm_plane *sti_hqvdp_find_vid(struct drm_device *dev, int id) -{ - struct drm_plane *plane; - - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { - struct sti_layer *layer = to_sti_layer(plane); - - if (layer->desc == id) - return plane; - } - - return NULL; -} - -static void sti_hqvd_init(struct sti_layer *layer) +static void sti_hqvdp_init(struct sti_hqvdp *hqvdp) { - struct sti_hqvdp *hqvdp = to_sti_hqvdp(layer); int size; - /* find the plane macthing with vid 0 */ - hqvdp->vid_plane = sti_hqvdp_find_vid(hqvdp->drm_dev, STI_VID_0); - if (!hqvdp->vid_plane) { - DRM_ERROR("Cannot find Main video layer\n"); - return; - } - hqvdp->vtg_nb.notifier_call = sti_hqvdp_vtg_cb; /* Allocate memory for the VDP commands */ @@ -799,24 +782,25 @@ static void sti_hqvd_init(struct sti_layer *layer) memset(hqvdp->hqvdp_cmd, 0, size); } -static const struct sti_layer_funcs hqvdp_ops = { +static const struct sti_plane_funcs hqvdp_plane_ops = { .get_formats = sti_hqvdp_get_formats, .get_nb_formats = sti_hqvdp_get_nb_formats, - .init = sti_hqvd_init, - .prepare = sti_hqvdp_prepare_layer, - .commit = sti_hqvdp_commit_layer, - .disable = sti_hqvdp_disable_layer, + .prepare = sti_hqvdp_prepare, + .commit = sti_hqvdp_commit, + .disable = sti_hqvdp_disable, }; -struct sti_layer *sti_hqvdp_create(struct device *dev) +struct sti_plane *sti_hqvdp_create(struct device *dev, int desc) { struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); - hqvdp->layer.ops = &hqvdp_ops; + hqvdp->plane.desc = desc; + hqvdp->plane.ops = &hqvdp_plane_ops; - return &hqvdp->layer; + sti_hqvdp_init(hqvdp); + + return &hqvdp->plane; } -EXPORT_SYMBOL(sti_hqvdp_create); static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp) { @@ -859,6 +843,12 @@ static void sti_hqvdp_start_xp70(const struct firmware *firmware, void *ctxt) } *header; DRM_DEBUG_DRIVER("\n"); + + if (hqvdp->xp70_initialized) { + DRM_INFO("HQVDP XP70 already initialized\n"); + return; + } + /* Check firmware parts */ if (!firmware) { DRM_ERROR("Firmware not available\n"); @@ -946,7 +936,10 @@ static void sti_hqvdp_start_xp70(const struct firmware *firmware, void *ctxt) /* Launch Vsync */ writel(SOFT_VSYNC_HW, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC); - DRM_INFO("HQVDP XP70 started\n"); + DRM_INFO("HQVDP XP70 initialized\n"); + + hqvdp->xp70_initialized = true; + out: release_firmware(firmware); } @@ -955,7 +948,7 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data) { struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - struct sti_layer *layer; + struct sti_plane *plane; int err; DRM_DEBUG_DRIVER("\n"); @@ -971,13 +964,13 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data) return err; } - layer = sti_layer_create(hqvdp->dev, STI_HQVDP_0, hqvdp->regs); - if (!layer) { + /* Create HQVDP plane once xp70 is initialized */ + plane = sti_hqvdp_create(hqvdp->dev, STI_HQVDP_0); + if (plane) + sti_drm_plane_init(hqvdp->drm_dev, plane, 1, + DRM_PLANE_TYPE_OVERLAY); + else DRM_ERROR("Can't create HQVDP plane\n"); - return -ENOMEM; - } - - sti_drm_plane_init(drm_dev, layer, 1, DRM_PLANE_TYPE_OVERLAY); return 0; } diff --git a/drivers/gpu/drm/sti/sti_hqvdp.h b/drivers/gpu/drm/sti/sti_hqvdp.h deleted file mode 100644 index cd5ecd0a6dea..000000000000 --- a/drivers/gpu/drm/sti/sti_hqvdp.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Authors: Fabien Dessenne for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#ifndef _STI_HQVDP_H_ -#define _STI_HQVDP_H_ - -struct sti_layer *sti_hqvdp_create(struct device *dev); - -#endif diff --git a/drivers/gpu/drm/sti/sti_layer.c b/drivers/gpu/drm/sti/sti_layer.c deleted file mode 100644 index 899104f9d4bc..000000000000 --- a/drivers/gpu/drm/sti/sti_layer.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Authors: Benjamin Gaignard - * Fabien Dessenne - * for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#include -#include -#include - -#include "sti_compositor.h" -#include "sti_cursor.h" -#include "sti_gdp.h" -#include "sti_hqvdp.h" -#include "sti_layer.h" -#include "sti_vid.h" - -const char *sti_layer_to_str(struct sti_layer *layer) -{ - switch (layer->desc) { - case STI_GDP_0: - return "GDP0"; - case STI_GDP_1: - return "GDP1"; - case STI_GDP_2: - return "GDP2"; - case STI_GDP_3: - return "GDP3"; - case STI_VID_0: - return "VID0"; - case STI_VID_1: - return "VID1"; - case STI_CURSOR: - return "CURSOR"; - case STI_HQVDP_0: - return "HQVDP0"; - default: - return ""; - } -} -EXPORT_SYMBOL(sti_layer_to_str); - -struct sti_layer *sti_layer_create(struct device *dev, int desc, - void __iomem *baseaddr) -{ - - struct sti_layer *layer = NULL; - - switch (desc & STI_LAYER_TYPE_MASK) { - case STI_GDP: - layer = sti_gdp_create(dev, desc); - break; - case STI_VID: - layer = sti_vid_create(dev); - break; - case STI_CUR: - layer = sti_cursor_create(dev); - break; - case STI_VDP: - layer = sti_hqvdp_create(dev); - break; - } - - if (!layer) { - DRM_ERROR("Failed to create layer\n"); - return NULL; - } - - layer->desc = desc; - layer->dev = dev; - layer->regs = baseaddr; - - layer->ops->init(layer); - - DRM_DEBUG_DRIVER("%s created\n", sti_layer_to_str(layer)); - - return layer; -} -EXPORT_SYMBOL(sti_layer_create); - -int sti_layer_prepare(struct sti_layer *layer, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_display_mode *mode, int mixer_id, - int dest_x, int dest_y, int dest_w, int dest_h, - int src_x, int src_y, int src_w, int src_h) -{ - int ret; - unsigned int i; - struct drm_gem_cma_object *cma_obj; - - if (!layer || !fb || !mode) { - DRM_ERROR("Null fb, layer or mode\n"); - return 1; - } - - cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - if (!cma_obj) { - DRM_ERROR("Can't get CMA GEM object for fb\n"); - return 1; - } - - layer->crtc = crtc; - layer->fb = fb; - layer->mode = mode; - layer->mixer_id = mixer_id; - layer->dst_x = dest_x; - layer->dst_y = dest_y; - layer->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x); - layer->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y); - layer->src_x = src_x; - layer->src_y = src_y; - layer->src_w = src_w; - layer->src_h = src_h; - layer->format = fb->pixel_format; - layer->vaddr = cma_obj->vaddr; - layer->paddr = cma_obj->paddr; - for (i = 0; i < 4; i++) { - layer->pitches[i] = fb->pitches[i]; - layer->offsets[i] = fb->offsets[i]; - } - - DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n", - sti_layer_to_str(layer), - layer->mixer_id); - DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", - sti_layer_to_str(layer), - layer->dst_w, layer->dst_h, layer->dst_x, layer->dst_y, - layer->src_w, layer->src_h, layer->src_x, - layer->src_y); - - DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, - (char *)&layer->format, (unsigned long)layer->paddr); - - if (!layer->ops->prepare) - goto err_no_prepare; - - ret = layer->ops->prepare(layer, !layer->enabled); - if (!ret) - layer->enabled = true; - - return ret; - -err_no_prepare: - DRM_ERROR("Cannot prepare\n"); - return 1; -} - -int sti_layer_commit(struct sti_layer *layer) -{ - if (!layer) - return 1; - - if (!layer->ops->commit) - goto err_no_commit; - - return layer->ops->commit(layer); - -err_no_commit: - DRM_ERROR("Cannot commit\n"); - return 1; -} - -int sti_layer_disable(struct sti_layer *layer) -{ - int ret; - - DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer)); - if (!layer) - return 1; - - if (!layer->enabled) - return 0; - - if (!layer->ops->disable) - goto err_no_disable; - - ret = layer->ops->disable(layer); - if (!ret) - layer->enabled = false; - else - DRM_ERROR("Disable failed\n"); - - return ret; - -err_no_disable: - DRM_ERROR("Cannot disable\n"); - return 1; -} - -const uint32_t *sti_layer_get_formats(struct sti_layer *layer) -{ - if (!layer) - return NULL; - - if (!layer->ops->get_formats) - return NULL; - - return layer->ops->get_formats(layer); -} - -unsigned int sti_layer_get_nb_formats(struct sti_layer *layer) -{ - if (!layer) - return 0; - - if (!layer->ops->get_nb_formats) - return 0; - - return layer->ops->get_nb_formats(layer); -} diff --git a/drivers/gpu/drm/sti/sti_layer.h b/drivers/gpu/drm/sti/sti_layer.h deleted file mode 100644 index ceff497f557e..000000000000 --- a/drivers/gpu/drm/sti/sti_layer.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Authors: Benjamin Gaignard - * Fabien Dessenne - * for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#ifndef _STI_LAYER_H_ -#define _STI_LAYER_H_ - -#include - -#define to_sti_layer(x) container_of(x, struct sti_layer, plane) - -#define STI_LAYER_TYPE_SHIFT 8 -#define STI_LAYER_TYPE_MASK (~((1<zorder; + int plane_id, depth = plane->zorder; unsigned int i; u32 mask, val; if ((depth < 1) || (depth > GAM_MIXER_NB_DEPTH_LEVEL)) return 1; - switch (layer->desc) { + switch (plane->desc) { case STI_GDP_0: - layer_id = GAM_DEPTH_GDP0_ID; + plane_id = GAM_DEPTH_GDP0_ID; break; case STI_GDP_1: - layer_id = GAM_DEPTH_GDP1_ID; + plane_id = GAM_DEPTH_GDP1_ID; break; case STI_GDP_2: - layer_id = GAM_DEPTH_GDP2_ID; + plane_id = GAM_DEPTH_GDP2_ID; break; case STI_GDP_3: - layer_id = GAM_DEPTH_GDP3_ID; + plane_id = GAM_DEPTH_GDP3_ID; break; - case STI_VID_0: case STI_HQVDP_0: - layer_id = GAM_DEPTH_VID0_ID; - break; - case STI_VID_1: - layer_id = GAM_DEPTH_VID1_ID; + plane_id = GAM_DEPTH_VID0_ID; break; case STI_CURSOR: /* no need to set depth for cursor */ return 0; default: - DRM_ERROR("Unknown layer %d\n", layer->desc); + DRM_ERROR("Unknown plane %d\n", plane->desc); return 1; } - /* Search if a previous depth was already assigned to the layer */ + /* Search if a previous depth was already assigned to the plane */ val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB); for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) { mask = GAM_DEPTH_MASK_ID << (3 * i); - if ((val & mask) == layer_id << (3 * i)) + if ((val & mask) == plane_id << (3 * i)) break; } mask |= GAM_DEPTH_MASK_ID << (3 * (depth - 1)); - layer_id = layer_id << (3 * (depth - 1)); + plane_id = plane_id << (3 * (depth - 1)); DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer), - sti_layer_to_str(layer), depth); + sti_plane_to_str(plane), depth); dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n", - layer_id, mask); + plane_id, mask); val &= ~mask; - val |= layer_id; + val |= plane_id; sti_mixer_reg_write(mixer, GAM_MIXER_CRB, val); dev_dbg(mixer->dev, "Read GAM_MIXER_CRB 0x%x\n", @@ -185,9 +181,9 @@ int sti_mixer_active_video_area(struct sti_mixer *mixer, return 0; } -static u32 sti_mixer_get_layer_mask(struct sti_layer *layer) +static u32 sti_mixer_get_plane_mask(struct sti_plane *plane) { - switch (layer->desc) { + switch (plane->desc) { case STI_BACK: return GAM_CTL_BACK_MASK; case STI_GDP_0: @@ -198,11 +194,8 @@ static u32 sti_mixer_get_layer_mask(struct sti_layer *layer) return GAM_CTL_GDP2_MASK; case STI_GDP_3: return GAM_CTL_GDP3_MASK; - case STI_VID_0: case STI_HQVDP_0: return GAM_CTL_VID0_MASK; - case STI_VID_1: - return GAM_CTL_VID1_MASK; case STI_CURSOR: return GAM_CTL_CURSOR_MASK; default: @@ -210,17 +203,17 @@ static u32 sti_mixer_get_layer_mask(struct sti_layer *layer) } } -int sti_mixer_set_layer_status(struct sti_mixer *mixer, - struct sti_layer *layer, bool status) +int sti_mixer_set_plane_status(struct sti_mixer *mixer, + struct sti_plane *plane, bool status) { u32 mask, val; DRM_DEBUG_DRIVER("%s %s %s\n", status ? "enable" : "disable", - sti_mixer_to_str(mixer), sti_layer_to_str(layer)); + sti_mixer_to_str(mixer), sti_plane_to_str(plane)); - mask = sti_mixer_get_layer_mask(layer); + mask = sti_mixer_get_plane_mask(plane); if (!mask) { - DRM_ERROR("Can not find layer mask\n"); + DRM_ERROR("Can't find layer mask\n"); return -EINVAL; } @@ -232,11 +225,11 @@ int sti_mixer_set_layer_status(struct sti_mixer *mixer, return 0; } -void sti_mixer_clear_all_layers(struct sti_mixer *mixer) +void sti_mixer_clear_all_planes(struct sti_mixer *mixer) { u32 val; - DRM_DEBUG_DRIVER("%s clear all layer\n", sti_mixer_to_str(mixer)); + DRM_DEBUG_DRIVER("%s clear all planes\n", sti_mixer_to_str(mixer)); val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL) & 0xFFFF0000; sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val); } diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h index eb663f65f814..9d51eac26e90 100644 --- a/drivers/gpu/drm/sti/sti_mixer.h +++ b/drivers/gpu/drm/sti/sti_mixer.h @@ -11,7 +11,7 @@ #include -#include "sti_layer.h" +#include "sti_drm_plane.h" #define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc) @@ -29,7 +29,7 @@ struct sti_mixer { struct device *dev; void __iomem *regs; int id; - struct drm_crtc drm_crtc; + struct drm_crtc drm_crtc; struct drm_pending_vblank_event *pending_event; bool enabled; }; @@ -37,14 +37,14 @@ struct sti_mixer { const char *sti_mixer_to_str(struct sti_mixer *mixer); struct sti_mixer *sti_mixer_create(struct device *dev, int id, - void __iomem *baseaddr); + void __iomem *baseaddr); -int sti_mixer_set_layer_status(struct sti_mixer *mixer, - struct sti_layer *layer, bool status); -void sti_mixer_clear_all_layers(struct sti_mixer *mixer); -int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer); +int sti_mixer_set_plane_status(struct sti_mixer *mixer, + struct sti_plane *plane, bool status); +void sti_mixer_clear_all_planes(struct sti_mixer *mixer); +int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane); int sti_mixer_active_video_area(struct sti_mixer *mixer, - struct drm_display_mode *mode); + struct drm_display_mode *mode); void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable); diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c index 10ced6a479f4..b82a34f2a60e 100644 --- a/drivers/gpu/drm/sti/sti_vid.c +++ b/drivers/gpu/drm/sti/sti_vid.c @@ -6,7 +6,7 @@ #include -#include "sti_layer.h" +#include "sti_drm_plane.h" #include "sti_vid.h" #include "sti_vtg.h" @@ -43,27 +43,20 @@ #define VID_MPR2_BT709 0x07150545 #define VID_MPR3_BT709 0x00000AE8 -static int sti_vid_prepare_layer(struct sti_layer *vid, bool first_prepare) +int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane) { - u32 val; + struct drm_display_mode *mode = plane->mode; + u32 val, ydo, xdo, yds, xds; /* Unmask */ val = readl(vid->regs + VID_CTL); val &= ~VID_CTL_IGNORE; writel(val, vid->regs + VID_CTL); - return 0; -} - -static int sti_vid_commit_layer(struct sti_layer *vid) -{ - struct drm_display_mode *mode = vid->mode; - u32 ydo, xdo, yds, xds; - - ydo = sti_vtg_get_line_number(*mode, vid->dst_y); - yds = sti_vtg_get_line_number(*mode, vid->dst_y + vid->dst_h - 1); - xdo = sti_vtg_get_pixel_number(*mode, vid->dst_x); - xds = sti_vtg_get_pixel_number(*mode, vid->dst_x + vid->dst_w - 1); + ydo = sti_vtg_get_line_number(*mode, plane->dst_y); + yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1); + xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x); + xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1); writel((ydo << 16) | xdo, vid->regs + VID_VPO); writel((yds << 16) | xds, vid->regs + VID_VPS); @@ -71,7 +64,7 @@ static int sti_vid_commit_layer(struct sti_layer *vid) return 0; } -static int sti_vid_disable_layer(struct sti_layer *vid) +int sti_vid_disable(struct sti_vid *vid) { u32 val; @@ -83,17 +76,7 @@ static int sti_vid_disable_layer(struct sti_layer *vid) return 0; } -static const uint32_t *sti_vid_get_formats(struct sti_layer *layer) -{ - return NULL; -} - -static unsigned int sti_vid_get_nb_formats(struct sti_layer *layer) -{ - return 0; -} - -static void sti_vid_init(struct sti_layer *vid) +static void sti_vid_init(struct sti_vid *vid) { /* Enable PSI, Mask layer */ writel(VID_CTL_PSI_ENABLE | VID_CTL_IGNORE, vid->regs + VID_CTL); @@ -113,18 +96,10 @@ static void sti_vid_init(struct sti_layer *vid) writel(VID_CSAT_DFLT, vid->regs + VID_CSAT); } -static const struct sti_layer_funcs vid_ops = { - .get_formats = sti_vid_get_formats, - .get_nb_formats = sti_vid_get_nb_formats, - .init = sti_vid_init, - .prepare = sti_vid_prepare_layer, - .commit = sti_vid_commit_layer, - .disable = sti_vid_disable_layer, -}; - -struct sti_layer *sti_vid_create(struct device *dev) +struct sti_vid *sti_vid_create(struct device *dev, int id, + void __iomem *baseaddr) { - struct sti_layer *vid; + struct sti_vid *vid; vid = devm_kzalloc(dev, sizeof(*vid), GFP_KERNEL); if (!vid) { @@ -132,7 +107,11 @@ struct sti_layer *sti_vid_create(struct device *dev) return NULL; } - vid->ops = &vid_ops; + vid->dev = dev; + vid->regs = baseaddr; + vid->id = id; + + sti_vid_init(vid); return vid; } diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h index 2c0aecd63294..cc680a23cc5d 100644 --- a/drivers/gpu/drm/sti/sti_vid.h +++ b/drivers/gpu/drm/sti/sti_vid.h @@ -7,6 +7,22 @@ #ifndef _STI_VID_H_ #define _STI_VID_H_ -struct sti_layer *sti_vid_create(struct device *dev); +/** + * STI VID structure + * + * @dev: driver device + * @regs: vid registers + * @id: id of the vid + */ +struct sti_vid { + struct device *dev; + void __iomem *regs; + int id; +}; + +int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane); +int sti_vid_disable(struct sti_vid *vid); +struct sti_vid *sti_vid_create(struct device *dev, int id, + void __iomem *baseaddr); #endif -- cgit v1.3-6-gb490 From 9e1f05b28009ca7de50fb92c227c8046f686e2c5 Mon Sep 17 00:00:00 2001 From: Vincent Abriou Date: Fri, 31 Jul 2015 11:32:34 +0200 Subject: drm/sti: rename files and functions replace all "sti_drm_" occurences by "sti_" Signed-off-by: Vincent Abriou Reviewed-by: Benjamin Gaignard --- drivers/gpu/drm/sti/Makefile | 6 +- drivers/gpu/drm/sti/sti_compositor.c | 24 +-- drivers/gpu/drm/sti/sti_compositor.h | 2 +- drivers/gpu/drm/sti/sti_crtc.c | 322 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/sti/sti_crtc.h | 22 +++ drivers/gpu/drm/sti/sti_cursor.c | 2 +- drivers/gpu/drm/sti/sti_drm_crtc.c | 322 -------------------------------- drivers/gpu/drm/sti/sti_drm_crtc.h | 22 --- drivers/gpu/drm/sti/sti_drm_drv.c | 294 ------------------------------ drivers/gpu/drm/sti/sti_drm_drv.h | 35 ---- drivers/gpu/drm/sti/sti_drm_plane.c | 344 ----------------------------------- drivers/gpu/drm/sti/sti_drm_plane.h | 105 ----------- drivers/gpu/drm/sti/sti_drv.c | 294 ++++++++++++++++++++++++++++++ drivers/gpu/drm/sti/sti_drv.h | 35 ++++ drivers/gpu/drm/sti/sti_gdp.c | 2 +- drivers/gpu/drm/sti/sti_hqvdp.c | 6 +- drivers/gpu/drm/sti/sti_mixer.h | 2 +- drivers/gpu/drm/sti/sti_plane.c | 343 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sti/sti_plane.h | 105 +++++++++++ drivers/gpu/drm/sti/sti_tvout.c | 8 +- drivers/gpu/drm/sti/sti_vid.c | 2 +- 21 files changed, 1148 insertions(+), 1149 deletions(-) create mode 100644 drivers/gpu/drm/sti/sti_crtc.c create mode 100644 drivers/gpu/drm/sti/sti_crtc.h delete mode 100644 drivers/gpu/drm/sti/sti_drm_crtc.c delete mode 100644 drivers/gpu/drm/sti/sti_drm_crtc.h delete mode 100644 drivers/gpu/drm/sti/sti_drm_drv.c delete mode 100644 drivers/gpu/drm/sti/sti_drm_drv.h delete mode 100644 drivers/gpu/drm/sti/sti_drm_plane.c delete mode 100644 drivers/gpu/drm/sti/sti_drm_plane.h create mode 100644 drivers/gpu/drm/sti/sti_drv.c create mode 100644 drivers/gpu/drm/sti/sti_drv.h create mode 100644 drivers/gpu/drm/sti/sti_plane.c create mode 100644 drivers/gpu/drm/sti/sti_plane.h (limited to 'drivers') diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile index 505b3ba287ce..e27490b492a5 100644 --- a/drivers/gpu/drm/sti/Makefile +++ b/drivers/gpu/drm/sti/Makefile @@ -4,8 +4,8 @@ sticompositor-y := \ sti_vid.o \ sti_cursor.o \ sti_compositor.o \ - sti_drm_crtc.o \ - sti_drm_plane.o + sti_crtc.o \ + sti_plane.o stihdmi-y := sti_hdmi.o \ sti_hdmi_tx3g0c55phy.o \ @@ -23,4 +23,4 @@ obj-$(CONFIG_DRM_STI) = \ sticompositor.o \ sti_hqvdp.o \ stidvo.o \ - sti_drm_drv.o + sti_drv.o diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index 68c5c954ce9a..d62ed7f4cb2c 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c @@ -14,11 +14,11 @@ #include #include "sti_compositor.h" +#include "sti_crtc.h" #include "sti_cursor.h" -#include "sti_drm_crtc.h" -#include "sti_drm_drv.h" -#include "sti_drm_plane.h" +#include "sti_drv.h" #include "sti_gdp.h" +#include "sti_plane.h" #include "sti_vid.h" #include "sti_vtg.h" @@ -62,7 +62,7 @@ static int sti_compositor_bind(struct device *dev, struct sti_compositor *compo = dev_get_drvdata(dev); struct drm_device *drm_dev = data; unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0, plane_id = 0; - struct sti_drm_private *dev_priv = drm_dev->dev_private; + struct sti_private *dev_priv = drm_dev->dev_private; struct drm_plane *cursor = NULL; struct drm_plane *primary = NULL; struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc; @@ -116,8 +116,8 @@ static int sti_compositor_bind(struct device *dev, DRM_ERROR("Can't create CURSOR plane\n"); break; } - cursor = sti_drm_plane_init(drm_dev, plane, 1, - DRM_PLANE_TYPE_CURSOR); + cursor = sti_plane_init(drm_dev, plane, 1, + DRM_PLANE_TYPE_CURSOR); plane_id++; break; case STI_GPD_SUBDEV: @@ -127,9 +127,9 @@ static int sti_compositor_bind(struct device *dev, DRM_ERROR("Can't create GDP plane\n"); break; } - primary = sti_drm_plane_init(drm_dev, plane, - (1 << mixer_id) - 1, - plane_type); + primary = sti_plane_init(drm_dev, plane, + (1 << mixer_id) - 1, + plane_type); plane_id++; break; default: @@ -139,8 +139,8 @@ static int sti_compositor_bind(struct device *dev, /* The first planes are reserved for primary planes*/ if (crtc_id < mixer_id && primary) { - sti_drm_crtc_init(drm_dev, compo->mixer[crtc_id], - primary, cursor); + sti_crtc_init(drm_dev, compo->mixer[crtc_id], + primary, cursor); crtc_id++; cursor = NULL; primary = NULL; @@ -196,7 +196,7 @@ static int sti_compositor_probe(struct platform_device *pdev) return -ENOMEM; } compo->dev = dev; - compo->vtg_vblank_nb.notifier_call = sti_drm_crtc_vblank_cb; + compo->vtg_vblank_nb.notifier_call = sti_crtc_vblank_cb; /* populate data structure depending on compatibility */ BUG_ON(!of_match_node(compositor_of_match, np)->data); diff --git a/drivers/gpu/drm/sti/sti_compositor.h b/drivers/gpu/drm/sti/sti_compositor.h index 77f99780313a..1a4a73dab11e 100644 --- a/drivers/gpu/drm/sti/sti_compositor.h +++ b/drivers/gpu/drm/sti/sti_compositor.h @@ -12,8 +12,8 @@ #include #include -#include "sti_drm_plane.h" #include "sti_mixer.h" +#include "sti_plane.h" #define WAIT_NEXT_VSYNC_MS 50 /*ms*/ diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c new file mode 100644 index 000000000000..27b3ef207617 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -0,0 +1,322 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Benjamin Gaignard + * Fabien Dessenne + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include + +#include +#include +#include +#include +#include + +#include "sti_compositor.h" +#include "sti_crtc.h" +#include "sti_drv.h" +#include "sti_vtg.h" + +static void sti_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + DRM_DEBUG_KMS("\n"); +} + +static void sti_crtc_prepare(struct drm_crtc *crtc) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct device *dev = mixer->dev; + struct sti_compositor *compo = dev_get_drvdata(dev); + + mixer->enabled = true; + + /* Prepare and enable the compo IP clock */ + if (mixer->id == STI_MIXER_MAIN) { + if (clk_prepare_enable(compo->clk_compo_main)) + DRM_INFO("Failed to prepare/enable compo_main clk\n"); + } else { + if (clk_prepare_enable(compo->clk_compo_aux)) + DRM_INFO("Failed to prepare/enable compo_aux clk\n"); + } + + sti_mixer_clear_all_planes(mixer); +} + +static void sti_crtc_commit(struct drm_crtc *crtc) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct device *dev = mixer->dev; + struct sti_compositor *compo = dev_get_drvdata(dev); + struct sti_plane *plane; + + if ((!mixer || !compo)) { + DRM_ERROR("Can't find mixer or compositor)\n"); + return; + } + + /* get GDP which is reserved to the CRTC FB */ + plane = to_sti_plane(crtc->primary); + if (!plane) + DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n"); + + /* Enable plane on mixer */ + if (sti_mixer_set_plane_status(mixer, plane, true)) + DRM_ERROR("Cannot enable plane at mixer\n"); + + drm_crtc_vblank_on(crtc); +} + +static bool sti_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* accept the provided drm_display_mode, do not fix it up */ + return true; +} + +static int +sti_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct device *dev = mixer->dev; + struct sti_compositor *compo = dev_get_drvdata(dev); + struct clk *clk; + int rate = mode->clock * 1000; + int res; + + DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", + crtc->base.id, sti_mixer_to_str(mixer), + mode->base.id, mode->name); + + DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", + mode->vrefresh, mode->clock, + mode->hdisplay, + mode->hsync_start, mode->hsync_end, + mode->htotal, + mode->vdisplay, + mode->vsync_start, mode->vsync_end, + mode->vtotal, mode->type, mode->flags); + + /* Set rate and prepare/enable pixel clock */ + if (mixer->id == STI_MIXER_MAIN) + clk = compo->clk_pix_main; + else + clk = compo->clk_pix_aux; + + res = clk_set_rate(clk, rate); + if (res < 0) { + DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate); + return -EINVAL; + } + if (clk_prepare_enable(clk)) { + DRM_ERROR("Failed to prepare/enable pix clk\n"); + return -EINVAL; + } + + sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? + compo->vtg_main : compo->vtg_aux, &crtc->mode); + + res = sti_mixer_active_video_area(mixer, &crtc->mode); + if (res) { + DRM_ERROR("Can't set active video area\n"); + return -EINVAL; + } + + return res; +} + +static void sti_crtc_disable(struct drm_crtc *crtc) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct device *dev = mixer->dev; + struct sti_compositor *compo = dev_get_drvdata(dev); + + if (!mixer->enabled) + return; + + DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); + + /* Disable Background */ + sti_mixer_set_background_status(mixer, false); + + drm_crtc_vblank_off(crtc); + + /* Disable pixel clock and compo IP clocks */ + if (mixer->id == STI_MIXER_MAIN) { + clk_disable_unprepare(compo->clk_pix_main); + clk_disable_unprepare(compo->clk_compo_main); + } else { + clk_disable_unprepare(compo->clk_pix_aux); + clk_disable_unprepare(compo->clk_compo_aux); + } + + mixer->enabled = false; +} + +static void +sti_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ + sti_crtc_prepare(crtc); + sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode); +} + +static void sti_crtc_atomic_begin(struct drm_crtc *crtc) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + + if (crtc->state->event) { + crtc->state->event->pipe = drm_crtc_index(crtc); + + WARN_ON(drm_crtc_vblank_get(crtc) != 0); + + mixer->pending_event = crtc->state->event; + crtc->state->event = NULL; + } +} + +static void sti_crtc_atomic_flush(struct drm_crtc *crtc) +{ +} + +static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { + .dpms = sti_crtc_dpms, + .prepare = sti_crtc_prepare, + .commit = sti_crtc_commit, + .mode_fixup = sti_crtc_mode_fixup, + .mode_set = drm_helper_crtc_mode_set, + .mode_set_nofb = sti_crtc_mode_set_nofb, + .mode_set_base = drm_helper_crtc_mode_set_base, + .disable = sti_crtc_disable, + .atomic_begin = sti_crtc_atomic_begin, + .atomic_flush = sti_crtc_atomic_flush, +}; + +static void sti_crtc_destroy(struct drm_crtc *crtc) +{ + DRM_DEBUG_KMS("\n"); + drm_crtc_cleanup(crtc); +} + +static int sti_crtc_set_property(struct drm_crtc *crtc, + struct drm_property *property, + uint64_t val) +{ + DRM_DEBUG_KMS("\n"); + return 0; +} + +int sti_crtc_vblank_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct drm_device *drm_dev; + struct sti_compositor *compo = + container_of(nb, struct sti_compositor, vtg_vblank_nb); + int *crtc = data; + unsigned long flags; + struct sti_private *priv; + + drm_dev = compo->mixer[*crtc]->drm_crtc.dev; + priv = drm_dev->dev_private; + + if ((event != VTG_TOP_FIELD_EVENT) && + (event != VTG_BOTTOM_FIELD_EVENT)) { + DRM_ERROR("unknown event: %lu\n", event); + return -EINVAL; + } + + drm_handle_vblank(drm_dev, *crtc); + + spin_lock_irqsave(&drm_dev->event_lock, flags); + if (compo->mixer[*crtc]->pending_event) { + drm_send_vblank_event(drm_dev, -1, + compo->mixer[*crtc]->pending_event); + drm_vblank_put(drm_dev, *crtc); + compo->mixer[*crtc]->pending_event = NULL; + } + spin_unlock_irqrestore(&drm_dev->event_lock, flags); + + return 0; +} + +int sti_crtc_enable_vblank(struct drm_device *dev, int crtc) +{ + struct sti_private *dev_priv = dev->dev_private; + struct sti_compositor *compo = dev_priv->compo; + struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; + + DRM_DEBUG_DRIVER("\n"); + + if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ? + compo->vtg_main : compo->vtg_aux, + vtg_vblank_nb, crtc)) { + DRM_ERROR("Cannot register VTG notifier\n"); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(sti_crtc_enable_vblank); + +void sti_crtc_disable_vblank(struct drm_device *dev, int crtc) +{ + struct sti_private *priv = dev->dev_private; + struct sti_compositor *compo = priv->compo; + struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; + + DRM_DEBUG_DRIVER("\n"); + + if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ? + compo->vtg_main : compo->vtg_aux, vtg_vblank_nb)) + DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); + + /* free the resources of the pending requests */ + if (compo->mixer[crtc]->pending_event) { + drm_vblank_put(dev, crtc); + compo->mixer[crtc]->pending_event = NULL; + } +} +EXPORT_SYMBOL(sti_crtc_disable_vblank); + +static struct drm_crtc_funcs sti_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .destroy = sti_crtc_destroy, + .set_property = sti_crtc_set_property, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +bool sti_crtc_is_main(struct drm_crtc *crtc) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + + if (mixer->id == STI_MIXER_MAIN) + return true; + + return false; +} +EXPORT_SYMBOL(sti_crtc_is_main); + +int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, + struct drm_plane *primary, struct drm_plane *cursor) +{ + struct drm_crtc *crtc = &mixer->drm_crtc; + int res; + + res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, + &sti_crtc_funcs); + if (res) { + DRM_ERROR("Can't initialze CRTC\n"); + return -EINVAL; + } + + drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs); + + DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n", + crtc->base.id, sti_mixer_to_str(mixer)); + + return 0; +} diff --git a/drivers/gpu/drm/sti/sti_crtc.h b/drivers/gpu/drm/sti/sti_crtc.h new file mode 100644 index 000000000000..51963e6ddbe7 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_crtc.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Author: Benjamin Gaignard for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_CRTC_H_ +#define _STI_CRTC_H_ + +#include + +struct sti_mixer; + +int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, + struct drm_plane *primary, struct drm_plane *cursor); +int sti_crtc_enable_vblank(struct drm_device *dev, int crtc); +void sti_crtc_disable_vblank(struct drm_device *dev, int crtc); +int sti_crtc_vblank_cb(struct notifier_block *nb, + unsigned long event, void *data); +bool sti_crtc_is_main(struct drm_crtc *drm_crtc); + +#endif diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index cd12403dadcf..2868909aa926 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -8,7 +8,7 @@ #include #include "sti_cursor.h" -#include "sti_drm_plane.h" +#include "sti_plane.h" #include "sti_vtg.h" /* Registers */ diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c deleted file mode 100644 index a489b04a9abe..000000000000 --- a/drivers/gpu/drm/sti/sti_drm_crtc.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Authors: Benjamin Gaignard - * Fabien Dessenne - * for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#include - -#include -#include -#include -#include -#include - -#include "sti_compositor.h" -#include "sti_drm_drv.h" -#include "sti_drm_crtc.h" -#include "sti_vtg.h" - -static void sti_drm_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - DRM_DEBUG_KMS("\n"); -} - -static void sti_drm_crtc_prepare(struct drm_crtc *crtc) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - struct device *dev = mixer->dev; - struct sti_compositor *compo = dev_get_drvdata(dev); - - mixer->enabled = true; - - /* Prepare and enable the compo IP clock */ - if (mixer->id == STI_MIXER_MAIN) { - if (clk_prepare_enable(compo->clk_compo_main)) - DRM_INFO("Failed to prepare/enable compo_main clk\n"); - } else { - if (clk_prepare_enable(compo->clk_compo_aux)) - DRM_INFO("Failed to prepare/enable compo_aux clk\n"); - } - - sti_mixer_clear_all_planes(mixer); -} - -static void sti_drm_crtc_commit(struct drm_crtc *crtc) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - struct device *dev = mixer->dev; - struct sti_compositor *compo = dev_get_drvdata(dev); - struct sti_plane *plane; - - if ((!mixer || !compo)) { - DRM_ERROR("Can't find mixer or compositor)\n"); - return; - } - - /* get GDP which is reserved to the CRTC FB */ - plane = to_sti_plane(crtc->primary); - if (!plane) - DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n"); - - /* Enable plane on mixer */ - if (sti_mixer_set_plane_status(mixer, plane, true)) - DRM_ERROR("Cannot enable plane at mixer\n"); - - drm_crtc_vblank_on(crtc); -} - -static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - /* accept the provided drm_display_mode, do not fix it up */ - return true; -} - -static int -sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - struct device *dev = mixer->dev; - struct sti_compositor *compo = dev_get_drvdata(dev); - struct clk *clk; - int rate = mode->clock * 1000; - int res; - - DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", - crtc->base.id, sti_mixer_to_str(mixer), - mode->base.id, mode->name); - - DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", - mode->vrefresh, mode->clock, - mode->hdisplay, - mode->hsync_start, mode->hsync_end, - mode->htotal, - mode->vdisplay, - mode->vsync_start, mode->vsync_end, - mode->vtotal, mode->type, mode->flags); - - /* Set rate and prepare/enable pixel clock */ - if (mixer->id == STI_MIXER_MAIN) - clk = compo->clk_pix_main; - else - clk = compo->clk_pix_aux; - - res = clk_set_rate(clk, rate); - if (res < 0) { - DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate); - return -EINVAL; - } - if (clk_prepare_enable(clk)) { - DRM_ERROR("Failed to prepare/enable pix clk\n"); - return -EINVAL; - } - - sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? - compo->vtg_main : compo->vtg_aux, &crtc->mode); - - res = sti_mixer_active_video_area(mixer, &crtc->mode); - if (res) { - DRM_ERROR("Can't set active video area\n"); - return -EINVAL; - } - - return res; -} - -static void sti_drm_crtc_disable(struct drm_crtc *crtc) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - struct device *dev = mixer->dev; - struct sti_compositor *compo = dev_get_drvdata(dev); - - if (!mixer->enabled) - return; - - DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); - - /* Disable Background */ - sti_mixer_set_background_status(mixer, false); - - drm_crtc_vblank_off(crtc); - - /* Disable pixel clock and compo IP clocks */ - if (mixer->id == STI_MIXER_MAIN) { - clk_disable_unprepare(compo->clk_pix_main); - clk_disable_unprepare(compo->clk_compo_main); - } else { - clk_disable_unprepare(compo->clk_pix_aux); - clk_disable_unprepare(compo->clk_compo_aux); - } - - mixer->enabled = false; -} - -static void -sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) -{ - sti_drm_crtc_prepare(crtc); - sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode); -} - -static void sti_drm_crtc_atomic_begin(struct drm_crtc *crtc) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - - if (crtc->state->event) { - crtc->state->event->pipe = drm_crtc_index(crtc); - - WARN_ON(drm_crtc_vblank_get(crtc) != 0); - - mixer->pending_event = crtc->state->event; - crtc->state->event = NULL; - } -} - -static void sti_drm_crtc_atomic_flush(struct drm_crtc *crtc) -{ -} - -static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { - .dpms = sti_drm_crtc_dpms, - .prepare = sti_drm_crtc_prepare, - .commit = sti_drm_crtc_commit, - .mode_fixup = sti_drm_crtc_mode_fixup, - .mode_set = drm_helper_crtc_mode_set, - .mode_set_nofb = sti_drm_crtc_mode_set_nofb, - .mode_set_base = drm_helper_crtc_mode_set_base, - .disable = sti_drm_crtc_disable, - .atomic_begin = sti_drm_crtc_atomic_begin, - .atomic_flush = sti_drm_crtc_atomic_flush, -}; - -static void sti_drm_crtc_destroy(struct drm_crtc *crtc) -{ - DRM_DEBUG_KMS("\n"); - drm_crtc_cleanup(crtc); -} - -static int sti_drm_crtc_set_property(struct drm_crtc *crtc, - struct drm_property *property, - uint64_t val) -{ - DRM_DEBUG_KMS("\n"); - return 0; -} - -int sti_drm_crtc_vblank_cb(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct drm_device *drm_dev; - struct sti_compositor *compo = - container_of(nb, struct sti_compositor, vtg_vblank_nb); - int *crtc = data; - unsigned long flags; - struct sti_drm_private *priv; - - drm_dev = compo->mixer[*crtc]->drm_crtc.dev; - priv = drm_dev->dev_private; - - if ((event != VTG_TOP_FIELD_EVENT) && - (event != VTG_BOTTOM_FIELD_EVENT)) { - DRM_ERROR("unknown event: %lu\n", event); - return -EINVAL; - } - - drm_handle_vblank(drm_dev, *crtc); - - spin_lock_irqsave(&drm_dev->event_lock, flags); - if (compo->mixer[*crtc]->pending_event) { - drm_send_vblank_event(drm_dev, -1, - compo->mixer[*crtc]->pending_event); - drm_vblank_put(drm_dev, *crtc); - compo->mixer[*crtc]->pending_event = NULL; - } - spin_unlock_irqrestore(&drm_dev->event_lock, flags); - - return 0; -} - -int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) -{ - struct sti_drm_private *dev_priv = dev->dev_private; - struct sti_compositor *compo = dev_priv->compo; - struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; - - DRM_DEBUG_DRIVER("\n"); - - if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ? - compo->vtg_main : compo->vtg_aux, - vtg_vblank_nb, crtc)) { - DRM_ERROR("Cannot register VTG notifier\n"); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL(sti_drm_crtc_enable_vblank); - -void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) -{ - struct sti_drm_private *priv = dev->dev_private; - struct sti_compositor *compo = priv->compo; - struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; - - DRM_DEBUG_DRIVER("\n"); - - if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ? - compo->vtg_main : compo->vtg_aux, vtg_vblank_nb)) - DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); - - /* free the resources of the pending requests */ - if (compo->mixer[crtc]->pending_event) { - drm_vblank_put(dev, crtc); - compo->mixer[crtc]->pending_event = NULL; - } -} -EXPORT_SYMBOL(sti_drm_crtc_disable_vblank); - -static struct drm_crtc_funcs sti_crtc_funcs = { - .set_config = drm_atomic_helper_set_config, - .page_flip = drm_atomic_helper_page_flip, - .destroy = sti_drm_crtc_destroy, - .set_property = sti_drm_crtc_set_property, - .reset = drm_atomic_helper_crtc_reset, - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, -}; - -bool sti_drm_crtc_is_main(struct drm_crtc *crtc) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - - if (mixer->id == STI_MIXER_MAIN) - return true; - - return false; -} -EXPORT_SYMBOL(sti_drm_crtc_is_main); - -int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, - struct drm_plane *primary, struct drm_plane *cursor) -{ - struct drm_crtc *crtc = &mixer->drm_crtc; - int res; - - res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, - &sti_crtc_funcs); - if (res) { - DRM_ERROR("Can't initialze CRTC\n"); - return -EINVAL; - } - - drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs); - - DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n", - crtc->base.id, sti_mixer_to_str(mixer)); - - return 0; -} diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.h b/drivers/gpu/drm/sti/sti_drm_crtc.h deleted file mode 100644 index caca8b14f017..000000000000 --- a/drivers/gpu/drm/sti/sti_drm_crtc.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Author: Benjamin Gaignard for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#ifndef _STI_DRM_CRTC_H_ -#define _STI_DRM_CRTC_H_ - -#include - -struct sti_mixer; - -int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer, - struct drm_plane *primary, struct drm_plane *cursor); -int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc); -void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc); -int sti_drm_crtc_vblank_cb(struct notifier_block *nb, - unsigned long event, void *data); -bool sti_drm_crtc_is_main(struct drm_crtc *drm_crtc); - -#endif diff --git a/drivers/gpu/drm/sti/sti_drm_drv.c b/drivers/gpu/drm/sti/sti_drm_drv.c deleted file mode 100644 index 8ad9fe68335f..000000000000 --- a/drivers/gpu/drm/sti/sti_drm_drv.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Author: Benjamin Gaignard for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "sti_drm_drv.h" -#include "sti_drm_crtc.h" - -#define DRIVER_NAME "sti" -#define DRIVER_DESC "STMicroelectronics SoC DRM" -#define DRIVER_DATE "20140601" -#define DRIVER_MAJOR 1 -#define DRIVER_MINOR 0 - -#define STI_MAX_FB_HEIGHT 4096 -#define STI_MAX_FB_WIDTH 4096 - -static void sti_drm_atomic_schedule(struct sti_drm_private *private, - struct drm_atomic_state *state) -{ - private->commit.state = state; - schedule_work(&private->commit.work); -} - -static void sti_drm_atomic_complete(struct sti_drm_private *private, - struct drm_atomic_state *state) -{ - struct drm_device *drm = private->drm_dev; - - /* - * Everything below can be run asynchronously without the need to grab - * any modeset locks at all under one condition: It must be guaranteed - * that the asynchronous work has either been cancelled (if the driver - * supports it, which at least requires that the framebuffers get - * cleaned up with drm_atomic_helper_cleanup_planes()) or completed - * before the new state gets committed on the software side with - * drm_atomic_helper_swap_state(). - * - * This scheme allows new atomic state updates to be prepared and - * checked in parallel to the asynchronous completion of the previous - * update. Which is important since compositors need to figure out the - * composition of the next frame right after having submitted the - * current layout. - */ - - drm_atomic_helper_commit_modeset_disables(drm, state); - drm_atomic_helper_commit_planes(drm, state); - drm_atomic_helper_commit_modeset_enables(drm, state); - - drm_atomic_helper_wait_for_vblanks(drm, state); - - drm_atomic_helper_cleanup_planes(drm, state); - drm_atomic_state_free(state); -} - -static void sti_drm_atomic_work(struct work_struct *work) -{ - struct sti_drm_private *private = container_of(work, - struct sti_drm_private, commit.work); - - sti_drm_atomic_complete(private, private->commit.state); -} - -static int sti_drm_atomic_commit(struct drm_device *drm, - struct drm_atomic_state *state, bool async) -{ - struct sti_drm_private *private = drm->dev_private; - int err; - - err = drm_atomic_helper_prepare_planes(drm, state); - if (err) - return err; - - /* serialize outstanding asynchronous commits */ - mutex_lock(&private->commit.lock); - flush_work(&private->commit.work); - - /* - * This is the point of no return - everything below never fails except - * when the hw goes bonghits. Which means we can commit the new state on - * the software side now. - */ - - drm_atomic_helper_swap_state(drm, state); - - if (async) - sti_drm_atomic_schedule(private, state); - else - sti_drm_atomic_complete(private, state); - - mutex_unlock(&private->commit.lock); - return 0; -} - -static struct drm_mode_config_funcs sti_drm_mode_config_funcs = { - .fb_create = drm_fb_cma_create, - .atomic_check = drm_atomic_helper_check, - .atomic_commit = sti_drm_atomic_commit, -}; - -static void sti_drm_mode_config_init(struct drm_device *dev) -{ - dev->mode_config.min_width = 0; - dev->mode_config.min_height = 0; - - /* - * set max width and height as default value. - * this value would be used to check framebuffer size limitation - * at drm_mode_addfb(). - */ - dev->mode_config.max_width = STI_MAX_FB_HEIGHT; - dev->mode_config.max_height = STI_MAX_FB_WIDTH; - - dev->mode_config.funcs = &sti_drm_mode_config_funcs; -} - -static int sti_drm_load(struct drm_device *dev, unsigned long flags) -{ - struct sti_drm_private *private; - int ret; - - private = kzalloc(sizeof(struct sti_drm_private), GFP_KERNEL); - if (!private) { - DRM_ERROR("Failed to allocate private\n"); - return -ENOMEM; - } - dev->dev_private = (void *)private; - private->drm_dev = dev; - - mutex_init(&private->commit.lock); - INIT_WORK(&private->commit.work, sti_drm_atomic_work); - - drm_mode_config_init(dev); - drm_kms_helper_poll_init(dev); - - sti_drm_mode_config_init(dev); - - ret = component_bind_all(dev->dev, dev); - if (ret) { - drm_kms_helper_poll_fini(dev); - drm_mode_config_cleanup(dev); - kfree(private); - return ret; - } - - drm_mode_config_reset(dev); - -#ifdef CONFIG_DRM_STI_FBDEV - drm_fbdev_cma_init(dev, 32, - dev->mode_config.num_crtc, - dev->mode_config.num_connector); -#endif - return 0; -} - -static const struct file_operations sti_drm_driver_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .mmap = drm_gem_cma_mmap, - .poll = drm_poll, - .read = drm_read, - .unlocked_ioctl = drm_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = drm_compat_ioctl, -#endif - .release = drm_release, -}; - -static struct dma_buf *sti_drm_gem_prime_export(struct drm_device *dev, - struct drm_gem_object *obj, - int flags) -{ - /* we want to be able to write in mmapped buffer */ - flags |= O_RDWR; - return drm_gem_prime_export(dev, obj, flags); -} - -static struct drm_driver sti_drm_driver = { - .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | - DRIVER_GEM | DRIVER_PRIME, - .load = sti_drm_load, - .gem_free_object = drm_gem_cma_free_object, - .gem_vm_ops = &drm_gem_cma_vm_ops, - .dumb_create = drm_gem_cma_dumb_create, - .dumb_map_offset = drm_gem_cma_dumb_map_offset, - .dumb_destroy = drm_gem_dumb_destroy, - .fops = &sti_drm_driver_fops, - - .get_vblank_counter = drm_vblank_count, - .enable_vblank = sti_drm_crtc_enable_vblank, - .disable_vblank = sti_drm_crtc_disable_vblank, - - .prime_handle_to_fd = drm_gem_prime_handle_to_fd, - .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_export = sti_drm_gem_prime_export, - .gem_prime_import = drm_gem_prime_import, - .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, - .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, - .gem_prime_vmap = drm_gem_cma_prime_vmap, - .gem_prime_vunmap = drm_gem_cma_prime_vunmap, - .gem_prime_mmap = drm_gem_cma_prime_mmap, - - .name = DRIVER_NAME, - .desc = DRIVER_DESC, - .date = DRIVER_DATE, - .major = DRIVER_MAJOR, - .minor = DRIVER_MINOR, -}; - -static int compare_of(struct device *dev, void *data) -{ - return dev->of_node == data; -} - -static int sti_drm_bind(struct device *dev) -{ - return drm_platform_init(&sti_drm_driver, to_platform_device(dev)); -} - -static void sti_drm_unbind(struct device *dev) -{ - drm_put_dev(dev_get_drvdata(dev)); -} - -static const struct component_master_ops sti_drm_ops = { - .bind = sti_drm_bind, - .unbind = sti_drm_unbind, -}; - -static int sti_drm_platform_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; - struct device_node *child_np; - struct component_match *match = NULL; - - dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); - - of_platform_populate(node, NULL, NULL, dev); - - child_np = of_get_next_available_child(node, NULL); - - while (child_np) { - component_match_add(dev, &match, compare_of, child_np); - of_node_put(child_np); - child_np = of_get_next_available_child(node, child_np); - } - - return component_master_add_with_match(dev, &sti_drm_ops, match); -} - -static int sti_drm_platform_remove(struct platform_device *pdev) -{ - component_master_del(&pdev->dev, &sti_drm_ops); - of_platform_depopulate(&pdev->dev); - - return 0; -} - -static const struct of_device_id sti_drm_dt_ids[] = { - { .compatible = "st,sti-display-subsystem", }, - { /* end node */ }, -}; -MODULE_DEVICE_TABLE(of, sti_drm_dt_ids); - -static struct platform_driver sti_drm_platform_driver = { - .probe = sti_drm_platform_probe, - .remove = sti_drm_platform_remove, - .driver = { - .name = DRIVER_NAME, - .of_match_table = sti_drm_dt_ids, - }, -}; - -module_platform_driver(sti_drm_platform_driver); - -MODULE_AUTHOR("Benjamin Gaignard "); -MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_drm_drv.h b/drivers/gpu/drm/sti/sti_drm_drv.h deleted file mode 100644 index c413aa3ff402..000000000000 --- a/drivers/gpu/drm/sti/sti_drm_drv.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Author: Benjamin Gaignard for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#ifndef _STI_DRM_DRV_H_ -#define _STI_DRM_DRV_H_ - -#include - -struct sti_compositor; -struct sti_tvout; - -/** - * STI drm private structure - * This structure is stored as private in the drm_device - * - * @compo: compositor - * @plane_zorder_property: z-order property for CRTC planes - * @drm_dev: drm device - */ -struct sti_drm_private { - struct sti_compositor *compo; - struct drm_property *plane_zorder_property; - struct drm_device *drm_dev; - - struct { - struct drm_atomic_state *state; - struct work_struct work; - struct mutex lock; - } commit; -}; - -#endif diff --git a/drivers/gpu/drm/sti/sti_drm_plane.c b/drivers/gpu/drm/sti/sti_drm_plane.c deleted file mode 100644 index 0d1672204b01..000000000000 --- a/drivers/gpu/drm/sti/sti_drm_plane.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Authors: Benjamin Gaignard - * Fabien Dessenne - * for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#include -#include -#include -#include -#include - -#include "sti_compositor.h" -#include "sti_drm_drv.h" -#include "sti_drm_plane.h" -#include "sti_vtg.h" - -/* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */ -enum sti_plane_desc sti_plane_default_zorder[] = { - STI_GDP_0, - STI_GDP_1, - STI_HQVDP_0, - STI_GDP_2, - STI_GDP_3, -}; - -const char *sti_plane_to_str(struct sti_plane *plane) -{ - switch (plane->desc) { - case STI_GDP_0: - return "GDP0"; - case STI_GDP_1: - return "GDP1"; - case STI_GDP_2: - return "GDP2"; - case STI_GDP_3: - return "GDP3"; - case STI_HQVDP_0: - return "HQVDP0"; - case STI_CURSOR: - return "CURSOR"; - default: - return ""; - } -} -EXPORT_SYMBOL(sti_plane_to_str); - -static int sti_plane_prepare(struct sti_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_display_mode *mode, int mixer_id, - int dest_x, int dest_y, int dest_w, int dest_h, - int src_x, int src_y, int src_w, int src_h) -{ - struct drm_gem_cma_object *cma_obj; - unsigned int i; - int res; - - if (!plane || !fb || !mode) { - DRM_ERROR("Null fb, plane or mode\n"); - return 1; - } - - cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - if (!cma_obj) { - DRM_ERROR("Can't get CMA GEM object for fb\n"); - return 1; - } - - plane->fb = fb; - plane->mode = mode; - plane->mixer_id = mixer_id; - plane->dst_x = dest_x; - plane->dst_y = dest_y; - plane->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x); - plane->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y); - plane->src_x = src_x; - plane->src_y = src_y; - plane->src_w = src_w; - plane->src_h = src_h; - plane->format = fb->pixel_format; - plane->vaddr = cma_obj->vaddr; - plane->paddr = cma_obj->paddr; - for (i = 0; i < 4; i++) { - plane->pitches[i] = fb->pitches[i]; - plane->offsets[i] = fb->offsets[i]; - } - - DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n", - sti_plane_to_str(plane), - plane->mixer_id); - DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", - sti_plane_to_str(plane), - plane->dst_w, plane->dst_h, plane->dst_x, plane->dst_y, - plane->src_w, plane->src_h, plane->src_x, - plane->src_y); - - DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, - (char *)&plane->format, (unsigned long)plane->paddr); - - if (!plane->ops->prepare) { - DRM_ERROR("Cannot prepare\n"); - return 1; - } - - res = plane->ops->prepare(plane, !plane->enabled); - if (res) { - DRM_ERROR("Plane prepare failed\n"); - return res; - } - - plane->enabled = true; - - return 0; -} - -static int sti_plane_commit(struct sti_plane *plane) -{ - if (!plane) - return 1; - - if (!plane->ops->commit) { - DRM_ERROR("Cannot commit\n"); - return 1; - } - - return plane->ops->commit(plane); -} - -static int sti_plane_disable(struct sti_plane *plane) -{ - int res; - - DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); - if (!plane) - return 1; - - if (!plane->enabled) - return 0; - - if (!plane->ops->disable) { - DRM_ERROR("Cannot disable\n"); - return 1; - } - - res = plane->ops->disable(plane); - if (res) { - DRM_ERROR("Plane disable failed\n"); - return res; - } - - plane->enabled = false; - - return 0; -} - -static void sti_drm_plane_destroy(struct drm_plane *drm_plane) -{ - DRM_DEBUG_DRIVER("\n"); - - drm_plane_helper_disable(drm_plane); - drm_plane_cleanup(drm_plane); -} - -static int sti_drm_plane_set_property(struct drm_plane *drm_plane, - struct drm_property *property, - uint64_t val) -{ - struct drm_device *dev = drm_plane->dev; - struct sti_drm_private *private = dev->dev_private; - struct sti_plane *plane = to_sti_plane(drm_plane); - - DRM_DEBUG_DRIVER("\n"); - - if (property == private->plane_zorder_property) { - plane->zorder = val; - return 0; - } - - return -EINVAL; -} - -static struct drm_plane_funcs sti_drm_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = sti_drm_plane_destroy, - .set_property = sti_drm_plane_set_property, - .reset = drm_atomic_helper_plane_reset, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, -}; - -static int sti_drm_plane_atomic_check(struct drm_plane *drm_plane, - struct drm_plane_state *state) -{ - return 0; -} - -static void sti_drm_plane_atomic_update(struct drm_plane *drm_plane, - struct drm_plane_state *oldstate) -{ - struct drm_plane_state *state = drm_plane->state; - struct sti_plane *plane = to_sti_plane(drm_plane); - struct sti_mixer *mixer = to_sti_mixer(state->crtc); - int res; - - DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", - state->crtc->base.id, sti_mixer_to_str(mixer), - drm_plane->base.id, sti_plane_to_str(plane)); - DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", - state->crtc_w, state->crtc_h, - state->crtc_x, state->crtc_y); - - res = sti_mixer_set_plane_depth(mixer, plane); - if (res) { - DRM_ERROR("Cannot set plane depth\n"); - return; - } - - /* src_x are in 16.16 format */ - res = sti_plane_prepare(plane, state->crtc, state->fb, - &state->crtc->mode, mixer->id, - state->crtc_x, state->crtc_y, - state->crtc_w, state->crtc_h, - state->src_x >> 16, state->src_y >> 16, - state->src_w >> 16, state->src_h >> 16); - if (res) { - DRM_ERROR("Plane prepare failed\n"); - return; - } - - res = sti_plane_commit(plane); - if (res) { - DRM_ERROR("Plane commit failed\n"); - return; - } - - res = sti_mixer_set_plane_status(mixer, plane, true); - if (res) { - DRM_ERROR("Cannot enable plane at mixer\n"); - return; - } -} - -static void sti_drm_plane_atomic_disable(struct drm_plane *drm_plane, - struct drm_plane_state *oldstate) -{ - struct sti_plane *plane = to_sti_plane(drm_plane); - struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); - int res; - - if (!drm_plane->crtc) { - DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", - drm_plane->base.id); - return; - } - - DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", - drm_plane->crtc->base.id, sti_mixer_to_str(mixer), - drm_plane->base.id, sti_plane_to_str(plane)); - - /* Disable plane at mixer level */ - res = sti_mixer_set_plane_status(mixer, plane, false); - if (res) { - DRM_ERROR("Cannot disable plane at mixer\n"); - return; - } - - /* Wait a while to be sure that a Vsync event is received */ - msleep(WAIT_NEXT_VSYNC_MS); - - /* Then disable plane itself */ - res = sti_plane_disable(plane); - if (res) { - DRM_ERROR("Plane disable failed\n"); - return; - } -} - -static const struct drm_plane_helper_funcs sti_drm_plane_helpers_funcs = { - .atomic_check = sti_drm_plane_atomic_check, - .atomic_update = sti_drm_plane_atomic_update, - .atomic_disable = sti_drm_plane_atomic_disable, -}; - -static void sti_drm_plane_attach_zorder_property(struct drm_plane *drm_plane) -{ - struct drm_device *dev = drm_plane->dev; - struct sti_drm_private *private = dev->dev_private; - struct sti_plane *plane = to_sti_plane(drm_plane); - struct drm_property *prop; - - prop = private->plane_zorder_property; - if (!prop) { - prop = drm_property_create_range(dev, 0, "zpos", 1, - GAM_MIXER_NB_DEPTH_LEVEL); - if (!prop) - return; - - private->plane_zorder_property = prop; - } - - drm_object_attach_property(&drm_plane->base, prop, plane->zorder); -} - -struct drm_plane *sti_drm_plane_init(struct drm_device *dev, - struct sti_plane *plane, - unsigned int possible_crtcs, - enum drm_plane_type type) -{ - int err, i; - - err = drm_universal_plane_init(dev, &plane->drm_plane, - possible_crtcs, - &sti_drm_plane_funcs, - plane->ops->get_formats(plane), - plane->ops->get_nb_formats(plane), - type); - if (err) { - DRM_ERROR("Failed to initialize universal plane\n"); - return NULL; - } - - drm_plane_helper_add(&plane->drm_plane, - &sti_drm_plane_helpers_funcs); - - for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++) - if (sti_plane_default_zorder[i] == plane->desc) - break; - - plane->zorder = i + 1; - - if (type == DRM_PLANE_TYPE_OVERLAY) - sti_drm_plane_attach_zorder_property(&plane->drm_plane); - - DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n", - plane->drm_plane.base.id, - sti_plane_to_str(plane), plane->zorder); - - return &plane->drm_plane; -} -EXPORT_SYMBOL(sti_drm_plane_init); diff --git a/drivers/gpu/drm/sti/sti_drm_plane.h b/drivers/gpu/drm/sti/sti_drm_plane.h deleted file mode 100644 index e5473661c85a..000000000000 --- a/drivers/gpu/drm/sti/sti_drm_plane.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) STMicroelectronics SA 2014 - * Author: Benjamin Gaignard for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 - */ - -#ifndef _STI_DRM_PLANE_H_ -#define _STI_DRM_PLANE_H_ - -#include - -#define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) - -#define STI_PLANE_TYPE_SHIFT 8 -#define STI_PLANE_TYPE_MASK (~((1 << STI_PLANE_TYPE_SHIFT) - 1)) - -enum sti_plane_type { - STI_GDP = 1 << STI_PLANE_TYPE_SHIFT, - STI_VDP = 2 << STI_PLANE_TYPE_SHIFT, - STI_CUR = 3 << STI_PLANE_TYPE_SHIFT, - STI_BCK = 4 << STI_PLANE_TYPE_SHIFT -}; - -enum sti_plane_id_of_type { - STI_ID_0 = 0, - STI_ID_1 = 1, - STI_ID_2 = 2, - STI_ID_3 = 3 -}; - -enum sti_plane_desc { - STI_GDP_0 = STI_GDP | STI_ID_0, - STI_GDP_1 = STI_GDP | STI_ID_1, - STI_GDP_2 = STI_GDP | STI_ID_2, - STI_GDP_3 = STI_GDP | STI_ID_3, - STI_HQVDP_0 = STI_VDP | STI_ID_0, - STI_CURSOR = STI_CUR, - STI_BACK = STI_BCK -}; - -/** - * STI plane structure - * - * @plane: drm plane it is bound to (if any) - * @fb: drm fb it is bound to - * @mode: display mode - * @desc: plane type & id - * @ops: plane functions - * @zorder: plane z-order - * @mixer_id: id of the mixer used to display the plane - * @enabled: to know if the plane is active or not - * @src_x src_y: coordinates of the input (fb) area - * @src_w src_h: size of the input (fb) area - * @dst_x dst_y: coordinates of the output (crtc) area - * @dst_w dst_h: size of the output (crtc) area - * @format: format - * @pitches: pitch of 'planes' (eg: Y, U, V) - * @offsets: offset of 'planes' - * @vaddr: virtual address of the input buffer - * @paddr: physical address of the input buffer - */ -struct sti_plane { - struct drm_plane drm_plane; - struct drm_framebuffer *fb; - struct drm_display_mode *mode; - enum sti_plane_desc desc; - const struct sti_plane_funcs *ops; - int zorder; - int mixer_id; - bool enabled; - int src_x, src_y; - int src_w, src_h; - int dst_x, dst_y; - int dst_w, dst_h; - uint32_t format; - unsigned int pitches[4]; - unsigned int offsets[4]; - void *vaddr; - dma_addr_t paddr; -}; - -/** - * STI plane functions structure - * - * @get_formats: get plane supported formats - * @get_nb_formats: get number of format supported - * @prepare: prepare plane before rendering - * @commit: set plane for rendering - * @disable: disable plane - */ -struct sti_plane_funcs { - const uint32_t* (*get_formats)(struct sti_plane *plane); - unsigned int (*get_nb_formats)(struct sti_plane *plane); - int (*prepare)(struct sti_plane *plane, bool first_prepare); - int (*commit)(struct sti_plane *plane); - int (*disable)(struct sti_plane *plane); -}; - -struct drm_plane *sti_drm_plane_init(struct drm_device *dev, - struct sti_plane *sti_plane, - unsigned int possible_crtcs, - enum drm_plane_type type); -const char *sti_plane_to_str(struct sti_plane *plane); - -#endif diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c new file mode 100644 index 000000000000..6f4af6a8ba1b --- /dev/null +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -0,0 +1,294 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Author: Benjamin Gaignard for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sti_crtc.h" +#include "sti_drv.h" + +#define DRIVER_NAME "sti" +#define DRIVER_DESC "STMicroelectronics SoC DRM" +#define DRIVER_DATE "20140601" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 + +#define STI_MAX_FB_HEIGHT 4096 +#define STI_MAX_FB_WIDTH 4096 + +static void sti_atomic_schedule(struct sti_private *private, + struct drm_atomic_state *state) +{ + private->commit.state = state; + schedule_work(&private->commit.work); +} + +static void sti_atomic_complete(struct sti_private *private, + struct drm_atomic_state *state) +{ + struct drm_device *drm = private->drm_dev; + + /* + * Everything below can be run asynchronously without the need to grab + * any modeset locks at all under one condition: It must be guaranteed + * that the asynchronous work has either been cancelled (if the driver + * supports it, which at least requires that the framebuffers get + * cleaned up with drm_atomic_helper_cleanup_planes()) or completed + * before the new state gets committed on the software side with + * drm_atomic_helper_swap_state(). + * + * This scheme allows new atomic state updates to be prepared and + * checked in parallel to the asynchronous completion of the previous + * update. Which is important since compositors need to figure out the + * composition of the next frame right after having submitted the + * current layout. + */ + + drm_atomic_helper_commit_modeset_disables(drm, state); + drm_atomic_helper_commit_planes(drm, state); + drm_atomic_helper_commit_modeset_enables(drm, state); + + drm_atomic_helper_wait_for_vblanks(drm, state); + + drm_atomic_helper_cleanup_planes(drm, state); + drm_atomic_state_free(state); +} + +static void sti_atomic_work(struct work_struct *work) +{ + struct sti_private *private = container_of(work, + struct sti_private, commit.work); + + sti_atomic_complete(private, private->commit.state); +} + +static int sti_atomic_commit(struct drm_device *drm, + struct drm_atomic_state *state, bool async) +{ + struct sti_private *private = drm->dev_private; + int err; + + err = drm_atomic_helper_prepare_planes(drm, state); + if (err) + return err; + + /* serialize outstanding asynchronous commits */ + mutex_lock(&private->commit.lock); + flush_work(&private->commit.work); + + /* + * This is the point of no return - everything below never fails except + * when the hw goes bonghits. Which means we can commit the new state on + * the software side now. + */ + + drm_atomic_helper_swap_state(drm, state); + + if (async) + sti_atomic_schedule(private, state); + else + sti_atomic_complete(private, state); + + mutex_unlock(&private->commit.lock); + return 0; +} + +static struct drm_mode_config_funcs sti_mode_config_funcs = { + .fb_create = drm_fb_cma_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = sti_atomic_commit, +}; + +static void sti_mode_config_init(struct drm_device *dev) +{ + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + + /* + * set max width and height as default value. + * this value would be used to check framebuffer size limitation + * at drm_mode_addfb(). + */ + dev->mode_config.max_width = STI_MAX_FB_HEIGHT; + dev->mode_config.max_height = STI_MAX_FB_WIDTH; + + dev->mode_config.funcs = &sti_mode_config_funcs; +} + +static int sti_load(struct drm_device *dev, unsigned long flags) +{ + struct sti_private *private; + int ret; + + private = kzalloc(sizeof(*private), GFP_KERNEL); + if (!private) { + DRM_ERROR("Failed to allocate private\n"); + return -ENOMEM; + } + dev->dev_private = (void *)private; + private->drm_dev = dev; + + mutex_init(&private->commit.lock); + INIT_WORK(&private->commit.work, sti_atomic_work); + + drm_mode_config_init(dev); + drm_kms_helper_poll_init(dev); + + sti_mode_config_init(dev); + + ret = component_bind_all(dev->dev, dev); + if (ret) { + drm_kms_helper_poll_fini(dev); + drm_mode_config_cleanup(dev); + kfree(private); + return ret; + } + + drm_mode_config_reset(dev); + +#ifdef CONFIG_DRM_STI_FBDEV + drm_fbdev_cma_init(dev, 32, + dev->mode_config.num_crtc, + dev->mode_config.num_connector); +#endif + return 0; +} + +static const struct file_operations sti_driver_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .mmap = drm_gem_cma_mmap, + .poll = drm_poll, + .read = drm_read, + .unlocked_ioctl = drm_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .release = drm_release, +}; + +static struct dma_buf *sti_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *obj, + int flags) +{ + /* we want to be able to write in mmapped buffer */ + flags |= O_RDWR; + return drm_gem_prime_export(dev, obj, flags); +} + +static struct drm_driver sti_driver = { + .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | + DRIVER_GEM | DRIVER_PRIME, + .load = sti_load, + .gem_free_object = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .dumb_create = drm_gem_cma_dumb_create, + .dumb_map_offset = drm_gem_cma_dumb_map_offset, + .dumb_destroy = drm_gem_dumb_destroy, + .fops = &sti_driver_fops, + + .get_vblank_counter = drm_vblank_count, + .enable_vblank = sti_crtc_enable_vblank, + .disable_vblank = sti_crtc_disable_vblank, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_export = sti_gem_prime_export, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, +}; + +static int compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static int sti_bind(struct device *dev) +{ + return drm_platform_init(&sti_driver, to_platform_device(dev)); +} + +static void sti_unbind(struct device *dev) +{ + drm_put_dev(dev_get_drvdata(dev)); +} + +static const struct component_master_ops sti_ops = { + .bind = sti_bind, + .unbind = sti_unbind, +}; + +static int sti_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct device_node *child_np; + struct component_match *match = NULL; + + dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); + + of_platform_populate(node, NULL, NULL, dev); + + child_np = of_get_next_available_child(node, NULL); + + while (child_np) { + component_match_add(dev, &match, compare_of, child_np); + of_node_put(child_np); + child_np = of_get_next_available_child(node, child_np); + } + + return component_master_add_with_match(dev, &sti_ops, match); +} + +static int sti_platform_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &sti_ops); + of_platform_depopulate(&pdev->dev); + + return 0; +} + +static const struct of_device_id sti_dt_ids[] = { + { .compatible = "st,sti-display-subsystem", }, + { /* end node */ }, +}; +MODULE_DEVICE_TABLE(of, sti_dt_ids); + +static struct platform_driver sti_platform_driver = { + .probe = sti_platform_probe, + .remove = sti_platform_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = sti_dt_ids, + }, +}; + +module_platform_driver(sti_platform_driver); + +MODULE_AUTHOR("Benjamin Gaignard "); +MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/sti/sti_drv.h b/drivers/gpu/drm/sti/sti_drv.h new file mode 100644 index 000000000000..9372f69e1859 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_drv.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Author: Benjamin Gaignard for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_DRV_H_ +#define _STI_DRV_H_ + +#include + +struct sti_compositor; +struct sti_tvout; + +/** + * STI drm private structure + * This structure is stored as private in the drm_device + * + * @compo: compositor + * @plane_zorder_property: z-order property for CRTC planes + * @drm_dev: drm device + */ +struct sti_private { + struct sti_compositor *compo; + struct drm_property *plane_zorder_property; + struct drm_device *drm_dev; + + struct { + struct drm_atomic_state *state; + struct work_struct work; + struct mutex lock; + } commit; +}; + +#endif diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index e94d0be3c84f..e323310bfa73 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -10,8 +10,8 @@ #include #include "sti_compositor.h" -#include "sti_drm_plane.h" #include "sti_gdp.h" +#include "sti_plane.h" #include "sti_vtg.h" #define ALPHASWITCH BIT(6) diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index 54e8c2f06cf4..b91a009f0d5d 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -13,8 +13,8 @@ #include -#include "sti_drm_plane.h" #include "sti_hqvdp_lut.h" +#include "sti_plane.h" #include "sti_vtg.h" /* Firmware name */ @@ -967,8 +967,8 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data) /* Create HQVDP plane once xp70 is initialized */ plane = sti_hqvdp_create(hqvdp->dev, STI_HQVDP_0); if (plane) - sti_drm_plane_init(hqvdp->drm_dev, plane, 1, - DRM_PLANE_TYPE_OVERLAY); + sti_plane_init(hqvdp->drm_dev, plane, 1, + DRM_PLANE_TYPE_OVERLAY); else DRM_ERROR("Can't create HQVDP plane\n"); diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h index 9d51eac26e90..2f69b007e7c8 100644 --- a/drivers/gpu/drm/sti/sti_mixer.h +++ b/drivers/gpu/drm/sti/sti_mixer.h @@ -11,7 +11,7 @@ #include -#include "sti_drm_plane.h" +#include "sti_plane.h" #define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc) diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c new file mode 100644 index 000000000000..6a38521ca9b4 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_plane.c @@ -0,0 +1,343 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Authors: Benjamin Gaignard + * Fabien Dessenne + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include +#include + +#include "sti_compositor.h" +#include "sti_drv.h" +#include "sti_plane.h" +#include "sti_vtg.h" + +/* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */ +enum sti_plane_desc sti_plane_default_zorder[] = { + STI_GDP_0, + STI_GDP_1, + STI_HQVDP_0, + STI_GDP_2, + STI_GDP_3, +}; + +const char *sti_plane_to_str(struct sti_plane *plane) +{ + switch (plane->desc) { + case STI_GDP_0: + return "GDP0"; + case STI_GDP_1: + return "GDP1"; + case STI_GDP_2: + return "GDP2"; + case STI_GDP_3: + return "GDP3"; + case STI_HQVDP_0: + return "HQVDP0"; + case STI_CURSOR: + return "CURSOR"; + default: + return ""; + } +} +EXPORT_SYMBOL(sti_plane_to_str); + +static int sti_plane_prepare(struct sti_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_display_mode *mode, int mixer_id, + int dest_x, int dest_y, int dest_w, int dest_h, + int src_x, int src_y, int src_w, int src_h) +{ + struct drm_gem_cma_object *cma_obj; + unsigned int i; + int res; + + if (!plane || !fb || !mode) { + DRM_ERROR("Null fb, plane or mode\n"); + return 1; + } + + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + if (!cma_obj) { + DRM_ERROR("Can't get CMA GEM object for fb\n"); + return 1; + } + + plane->fb = fb; + plane->mode = mode; + plane->mixer_id = mixer_id; + plane->dst_x = dest_x; + plane->dst_y = dest_y; + plane->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x); + plane->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y); + plane->src_x = src_x; + plane->src_y = src_y; + plane->src_w = src_w; + plane->src_h = src_h; + plane->format = fb->pixel_format; + plane->vaddr = cma_obj->vaddr; + plane->paddr = cma_obj->paddr; + for (i = 0; i < 4; i++) { + plane->pitches[i] = fb->pitches[i]; + plane->offsets[i] = fb->offsets[i]; + } + + DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n", + sti_plane_to_str(plane), + plane->mixer_id); + DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", + sti_plane_to_str(plane), + plane->dst_w, plane->dst_h, plane->dst_x, plane->dst_y, + plane->src_w, plane->src_h, plane->src_x, + plane->src_y); + + DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, + (char *)&plane->format, (unsigned long)plane->paddr); + + if (!plane->ops->prepare) { + DRM_ERROR("Cannot prepare\n"); + return 1; + } + + res = plane->ops->prepare(plane, !plane->enabled); + if (res) { + DRM_ERROR("Plane prepare failed\n"); + return res; + } + + plane->enabled = true; + + return 0; +} + +static int sti_plane_commit(struct sti_plane *plane) +{ + if (!plane) + return 1; + + if (!plane->ops->commit) { + DRM_ERROR("Cannot commit\n"); + return 1; + } + + return plane->ops->commit(plane); +} + +static int sti_plane_disable(struct sti_plane *plane) +{ + int res; + + DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); + if (!plane) + return 1; + + if (!plane->enabled) + return 0; + + if (!plane->ops->disable) { + DRM_ERROR("Cannot disable\n"); + return 1; + } + + res = plane->ops->disable(plane); + if (res) { + DRM_ERROR("Plane disable failed\n"); + return res; + } + + plane->enabled = false; + + return 0; +} + +static void sti_plane_destroy(struct drm_plane *drm_plane) +{ + DRM_DEBUG_DRIVER("\n"); + + drm_plane_helper_disable(drm_plane); + drm_plane_cleanup(drm_plane); +} + +static int sti_plane_set_property(struct drm_plane *drm_plane, + struct drm_property *property, + uint64_t val) +{ + struct drm_device *dev = drm_plane->dev; + struct sti_private *private = dev->dev_private; + struct sti_plane *plane = to_sti_plane(drm_plane); + + DRM_DEBUG_DRIVER("\n"); + + if (property == private->plane_zorder_property) { + plane->zorder = val; + return 0; + } + + return -EINVAL; +} + +static struct drm_plane_funcs sti_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = sti_plane_destroy, + .set_property = sti_plane_set_property, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static int sti_plane_atomic_check(struct drm_plane *drm_plane, + struct drm_plane_state *state) +{ + return 0; +} + +static void sti_plane_atomic_update(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) +{ + struct drm_plane_state *state = drm_plane->state; + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_mixer *mixer = to_sti_mixer(state->crtc); + int res; + + DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", + state->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", + state->crtc_w, state->crtc_h, + state->crtc_x, state->crtc_y); + + res = sti_mixer_set_plane_depth(mixer, plane); + if (res) { + DRM_ERROR("Cannot set plane depth\n"); + return; + } + + /* src_x are in 16.16 format */ + res = sti_plane_prepare(plane, state->crtc, state->fb, + &state->crtc->mode, mixer->id, + state->crtc_x, state->crtc_y, + state->crtc_w, state->crtc_h, + state->src_x >> 16, state->src_y >> 16, + state->src_w >> 16, state->src_h >> 16); + if (res) { + DRM_ERROR("Plane prepare failed\n"); + return; + } + + res = sti_plane_commit(plane); + if (res) { + DRM_ERROR("Plane commit failed\n"); + return; + } + + res = sti_mixer_set_plane_status(mixer, plane, true); + if (res) { + DRM_ERROR("Cannot enable plane at mixer\n"); + return; + } +} + +static void sti_plane_atomic_disable(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) +{ + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); + int res; + + if (!drm_plane->crtc) { + DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", + drm_plane->base.id); + return; + } + + DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", + drm_plane->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + + /* Disable plane at mixer level */ + res = sti_mixer_set_plane_status(mixer, plane, false); + if (res) { + DRM_ERROR("Cannot disable plane at mixer\n"); + return; + } + + /* Wait a while to be sure that a Vsync event is received */ + msleep(WAIT_NEXT_VSYNC_MS); + + /* Then disable plane itself */ + res = sti_plane_disable(plane); + if (res) { + DRM_ERROR("Plane disable failed\n"); + return; + } +} + +static const struct drm_plane_helper_funcs sti_plane_helpers_funcs = { + .atomic_check = sti_plane_atomic_check, + .atomic_update = sti_plane_atomic_update, + .atomic_disable = sti_plane_atomic_disable, +}; + +static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane) +{ + struct drm_device *dev = drm_plane->dev; + struct sti_private *private = dev->dev_private; + struct sti_plane *plane = to_sti_plane(drm_plane); + struct drm_property *prop; + + prop = private->plane_zorder_property; + if (!prop) { + prop = drm_property_create_range(dev, 0, "zpos", 1, + GAM_MIXER_NB_DEPTH_LEVEL); + if (!prop) + return; + + private->plane_zorder_property = prop; + } + + drm_object_attach_property(&drm_plane->base, prop, plane->zorder); +} + +struct drm_plane *sti_plane_init(struct drm_device *dev, + struct sti_plane *plane, + unsigned int possible_crtcs, + enum drm_plane_type type) +{ + int err, i; + + err = drm_universal_plane_init(dev, &plane->drm_plane, + possible_crtcs, + &sti_plane_funcs, + plane->ops->get_formats(plane), + plane->ops->get_nb_formats(plane), + type); + if (err) { + DRM_ERROR("Failed to initialize universal plane\n"); + return NULL; + } + + drm_plane_helper_add(&plane->drm_plane, &sti_plane_helpers_funcs); + + for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++) + if (sti_plane_default_zorder[i] == plane->desc) + break; + + plane->zorder = i + 1; + + if (type == DRM_PLANE_TYPE_OVERLAY) + sti_plane_attach_zorder_property(&plane->drm_plane); + + DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n", + plane->drm_plane.base.id, + sti_plane_to_str(plane), plane->zorder); + + return &plane->drm_plane; +} +EXPORT_SYMBOL(sti_plane_init); diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h new file mode 100644 index 000000000000..bd527543bb1c --- /dev/null +++ b/drivers/gpu/drm/sti/sti_plane.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) STMicroelectronics SA 2014 + * Author: Benjamin Gaignard for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef _STI_PLANE_H_ +#define _STI_PLANE_H_ + +#include + +#define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) + +#define STI_PLANE_TYPE_SHIFT 8 +#define STI_PLANE_TYPE_MASK (~((1 << STI_PLANE_TYPE_SHIFT) - 1)) + +enum sti_plane_type { + STI_GDP = 1 << STI_PLANE_TYPE_SHIFT, + STI_VDP = 2 << STI_PLANE_TYPE_SHIFT, + STI_CUR = 3 << STI_PLANE_TYPE_SHIFT, + STI_BCK = 4 << STI_PLANE_TYPE_SHIFT +}; + +enum sti_plane_id_of_type { + STI_ID_0 = 0, + STI_ID_1 = 1, + STI_ID_2 = 2, + STI_ID_3 = 3 +}; + +enum sti_plane_desc { + STI_GDP_0 = STI_GDP | STI_ID_0, + STI_GDP_1 = STI_GDP | STI_ID_1, + STI_GDP_2 = STI_GDP | STI_ID_2, + STI_GDP_3 = STI_GDP | STI_ID_3, + STI_HQVDP_0 = STI_VDP | STI_ID_0, + STI_CURSOR = STI_CUR, + STI_BACK = STI_BCK +}; + +/** + * STI plane structure + * + * @plane: drm plane it is bound to (if any) + * @fb: drm fb it is bound to + * @mode: display mode + * @desc: plane type & id + * @ops: plane functions + * @zorder: plane z-order + * @mixer_id: id of the mixer used to display the plane + * @enabled: to know if the plane is active or not + * @src_x src_y: coordinates of the input (fb) area + * @src_w src_h: size of the input (fb) area + * @dst_x dst_y: coordinates of the output (crtc) area + * @dst_w dst_h: size of the output (crtc) area + * @format: format + * @pitches: pitch of 'planes' (eg: Y, U, V) + * @offsets: offset of 'planes' + * @vaddr: virtual address of the input buffer + * @paddr: physical address of the input buffer + */ +struct sti_plane { + struct drm_plane drm_plane; + struct drm_framebuffer *fb; + struct drm_display_mode *mode; + enum sti_plane_desc desc; + const struct sti_plane_funcs *ops; + int zorder; + int mixer_id; + bool enabled; + int src_x, src_y; + int src_w, src_h; + int dst_x, dst_y; + int dst_w, dst_h; + uint32_t format; + unsigned int pitches[4]; + unsigned int offsets[4]; + void *vaddr; + dma_addr_t paddr; +}; + +/** + * STI plane functions structure + * + * @get_formats: get plane supported formats + * @get_nb_formats: get number of format supported + * @prepare: prepare plane before rendering + * @commit: set plane for rendering + * @disable: disable plane + */ +struct sti_plane_funcs { + const uint32_t* (*get_formats)(struct sti_plane *plane); + unsigned int (*get_nb_formats)(struct sti_plane *plane); + int (*prepare)(struct sti_plane *plane, bool first_prepare); + int (*commit)(struct sti_plane *plane); + int (*disable)(struct sti_plane *plane); +}; + +struct drm_plane *sti_plane_init(struct drm_device *dev, + struct sti_plane *sti_plane, + unsigned int possible_crtcs, + enum drm_plane_type type); +const char *sti_plane_to_str(struct sti_plane *plane); + +#endif diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index 576b5becdf5f..c1aac8e66fb5 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c @@ -16,7 +16,7 @@ #include #include -#include "sti_drm_crtc.h" +#include "sti_crtc.h" /* glue registers */ #define TVO_CSC_MAIN_M0 0x000 @@ -473,7 +473,7 @@ static void sti_dvo_encoder_commit(struct drm_encoder *encoder) { struct sti_tvout *tvout = to_sti_tvout(encoder); - tvout_dvo_start(tvout, sti_drm_crtc_is_main(encoder->crtc)); + tvout_dvo_start(tvout, sti_crtc_is_main(encoder->crtc)); } static void sti_dvo_encoder_disable(struct drm_encoder *encoder) @@ -523,7 +523,7 @@ static void sti_hda_encoder_commit(struct drm_encoder *encoder) { struct sti_tvout *tvout = to_sti_tvout(encoder); - tvout_hda_start(tvout, sti_drm_crtc_is_main(encoder->crtc)); + tvout_hda_start(tvout, sti_crtc_is_main(encoder->crtc)); } static void sti_hda_encoder_disable(struct drm_encoder *encoder) @@ -575,7 +575,7 @@ static void sti_hdmi_encoder_commit(struct drm_encoder *encoder) { struct sti_tvout *tvout = to_sti_tvout(encoder); - tvout_hdmi_start(tvout, sti_drm_crtc_is_main(encoder->crtc)); + tvout_hdmi_start(tvout, sti_crtc_is_main(encoder->crtc)); } static void sti_hdmi_encoder_disable(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c index b82a34f2a60e..1e7e1d776adb 100644 --- a/drivers/gpu/drm/sti/sti_vid.c +++ b/drivers/gpu/drm/sti/sti_vid.c @@ -6,7 +6,7 @@ #include -#include "sti_drm_plane.h" +#include "sti_plane.h" #include "sti_vid.h" #include "sti_vtg.h" -- cgit v1.3-6-gb490 From 29d1dc62e1618192a25bd2eae9617529b9930cfc Mon Sep 17 00:00:00 2001 From: Vincent Abriou Date: Mon, 3 Aug 2015 14:22:16 +0200 Subject: drm/sti: atomic crtc/plane update Better fit STI hardware structure. Planes are no more responsible of updating mixer information such as z-order and status. It is now up to the CRTC atomic flush to do it. Plane actions (enable or disable) are performed atomically. Disabling of a plane is synchronize with the vsync event. Signed-off-by: Vincent Abriou Reviewed-by: Benjamin Gaignard --- drivers/gpu/drm/sti/sti_compositor.c | 32 +-- drivers/gpu/drm/sti/sti_crtc.c | 133 +++++++--- drivers/gpu/drm/sti/sti_cursor.c | 211 +++++++++------ drivers/gpu/drm/sti/sti_cursor.h | 6 +- drivers/gpu/drm/sti/sti_gdp.c | 493 +++++++++++++++++++---------------- drivers/gpu/drm/sti/sti_gdp.h | 8 +- drivers/gpu/drm/sti/sti_hqvdp.c | 429 ++++++++++++++++-------------- drivers/gpu/drm/sti/sti_mixer.c | 10 +- drivers/gpu/drm/sti/sti_mixer.h | 11 +- drivers/gpu/drm/sti/sti_plane.c | 253 ++---------------- drivers/gpu/drm/sti/sti_plane.h | 66 ++--- drivers/gpu/drm/sti/sti_vid.c | 29 ++- drivers/gpu/drm/sti/sti_vid.h | 5 +- 13 files changed, 809 insertions(+), 877 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index d62ed7f4cb2c..c652627b1bca 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c @@ -61,15 +61,13 @@ static int sti_compositor_bind(struct device *dev, { struct sti_compositor *compo = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0, plane_id = 0; + unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0; struct sti_private *dev_priv = drm_dev->dev_private; struct drm_plane *cursor = NULL; struct drm_plane *primary = NULL; struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc; unsigned int array_size = compo->data.nb_subdev; - struct sti_plane *plane; - dev_priv->compo = compo; /* Register mixer subdev and video subdev first */ @@ -110,27 +108,25 @@ static int sti_compositor_bind(struct device *dev, /* Nothing to do, already done at the first round */ break; case STI_CURSOR_SUBDEV: - plane = sti_cursor_create(compo->dev, desc[i].id, - compo->regs + desc[i].offset); - if (!plane) { + cursor = sti_cursor_create(drm_dev, compo->dev, + desc[i].id, + compo->regs + desc[i].offset, + 1); + if (!cursor) { DRM_ERROR("Can't create CURSOR plane\n"); break; } - cursor = sti_plane_init(drm_dev, plane, 1, - DRM_PLANE_TYPE_CURSOR); - plane_id++; break; case STI_GPD_SUBDEV: - plane = sti_gdp_create(compo->dev, desc[i].id, - compo->regs + desc[i].offset); - if (!plane) { + primary = sti_gdp_create(drm_dev, compo->dev, + desc[i].id, + compo->regs + desc[i].offset, + (1 << mixer_id) - 1, + plane_type); + if (!primary) { DRM_ERROR("Can't create GDP plane\n"); break; } - primary = sti_plane_init(drm_dev, plane, - (1 << mixer_id) - 1, - plane_type); - plane_id++; break; default: DRM_ERROR("Unknown subdev compoment type\n"); @@ -151,10 +147,6 @@ static int sti_compositor_bind(struct device *dev, /* Allow usage of vblank without having to call drm_irq_install */ drm_dev->irq_enabled = 1; - DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n", - crtc_id, plane_id); - DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n"); - return 0; } diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index 27b3ef207617..23fc2db50d17 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -17,20 +17,18 @@ #include "sti_compositor.h" #include "sti_crtc.h" #include "sti_drv.h" +#include "sti_vid.h" #include "sti_vtg.h" -static void sti_crtc_dpms(struct drm_crtc *crtc, int mode) -{ - DRM_DEBUG_KMS("\n"); -} - -static void sti_crtc_prepare(struct drm_crtc *crtc) +static void sti_crtc_enable(struct drm_crtc *crtc) { struct sti_mixer *mixer = to_sti_mixer(crtc); struct device *dev = mixer->dev; struct sti_compositor *compo = dev_get_drvdata(dev); - mixer->enabled = true; + DRM_DEBUG_DRIVER("\n"); + + mixer->status = STI_MIXER_READY; /* Prepare and enable the compo IP clock */ if (mixer->id == STI_MIXER_MAIN) { @@ -41,31 +39,16 @@ static void sti_crtc_prepare(struct drm_crtc *crtc) DRM_INFO("Failed to prepare/enable compo_aux clk\n"); } - sti_mixer_clear_all_planes(mixer); + drm_crtc_vblank_on(crtc); } -static void sti_crtc_commit(struct drm_crtc *crtc) +static void sti_crtc_disabling(struct drm_crtc *crtc) { struct sti_mixer *mixer = to_sti_mixer(crtc); - struct device *dev = mixer->dev; - struct sti_compositor *compo = dev_get_drvdata(dev); - struct sti_plane *plane; - - if ((!mixer || !compo)) { - DRM_ERROR("Can't find mixer or compositor)\n"); - return; - } - - /* get GDP which is reserved to the CRTC FB */ - plane = to_sti_plane(crtc->primary); - if (!plane) - DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n"); - /* Enable plane on mixer */ - if (sti_mixer_set_plane_status(mixer, plane, true)) - DRM_ERROR("Cannot enable plane at mixer\n"); + DRM_DEBUG_DRIVER("\n"); - drm_crtc_vblank_on(crtc); + mixer->status = STI_MIXER_DISABLING; } static bool sti_crtc_mode_fixup(struct drm_crtc *crtc, @@ -133,9 +116,6 @@ static void sti_crtc_disable(struct drm_crtc *crtc) struct device *dev = mixer->dev; struct sti_compositor *compo = dev_get_drvdata(dev); - if (!mixer->enabled) - return; - DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer)); /* Disable Background */ @@ -152,13 +132,13 @@ static void sti_crtc_disable(struct drm_crtc *crtc) clk_disable_unprepare(compo->clk_compo_aux); } - mixer->enabled = false; + mixer->status = STI_MIXER_DISABLED; } static void sti_crtc_mode_set_nofb(struct drm_crtc *crtc) { - sti_crtc_prepare(crtc); + sti_crtc_enable(crtc); sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode); } @@ -178,17 +158,79 @@ static void sti_crtc_atomic_begin(struct drm_crtc *crtc) static void sti_crtc_atomic_flush(struct drm_crtc *crtc) { + struct drm_device *drm_dev = crtc->dev; + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct sti_compositor *compo = dev_get_drvdata(mixer->dev); + struct drm_plane *p; + + DRM_DEBUG_DRIVER("\n"); + + /* perform plane actions */ + list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) { + struct sti_plane *plane = to_sti_plane(p); + + switch (plane->status) { + case STI_PLANE_UPDATED: + /* update planes tag as updated */ + DRM_DEBUG_DRIVER("update plane %s\n", + sti_plane_to_str(plane)); + + if (sti_mixer_set_plane_depth(mixer, plane)) { + DRM_ERROR("Cannot set plane %s depth\n", + sti_plane_to_str(plane)); + break; + } + + if (sti_mixer_set_plane_status(mixer, plane, true)) { + DRM_ERROR("Cannot enable plane %s at mixer\n", + sti_plane_to_str(plane)); + break; + } + + /* if plane is HQVDP_0 then commit the vid[0] */ + if (plane->desc == STI_HQVDP_0) + sti_vid_commit(compo->vid[0], p->state); + + plane->status = STI_PLANE_READY; + + break; + case STI_PLANE_DISABLING: + /* disabling sequence for planes tag as disabling */ + DRM_DEBUG_DRIVER("disable plane %s from mixer\n", + sti_plane_to_str(plane)); + + if (sti_mixer_set_plane_status(mixer, plane, false)) { + DRM_ERROR("Cannot disable plane %s at mixer\n", + sti_plane_to_str(plane)); + continue; + } + + if (plane->desc == STI_CURSOR) + /* tag plane status for disabled */ + plane->status = STI_PLANE_DISABLED; + else + /* tag plane status for flushing */ + plane->status = STI_PLANE_FLUSHING; + + /* if plane is HQVDP_0 then disable the vid[0] */ + if (plane->desc == STI_HQVDP_0) + sti_vid_disable(compo->vid[0]); + + break; + default: + /* Other status case are not handled */ + break; + } + } } static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { - .dpms = sti_crtc_dpms, - .prepare = sti_crtc_prepare, - .commit = sti_crtc_commit, + .enable = sti_crtc_enable, + .disable = sti_crtc_disabling, .mode_fixup = sti_crtc_mode_fixup, .mode_set = drm_helper_crtc_mode_set, .mode_set_nofb = sti_crtc_mode_set_nofb, .mode_set_base = drm_helper_crtc_mode_set_base, - .disable = sti_crtc_disable, .atomic_begin = sti_crtc_atomic_begin, .atomic_flush = sti_crtc_atomic_flush, }; @@ -237,6 +279,21 @@ int sti_crtc_vblank_cb(struct notifier_block *nb, } spin_unlock_irqrestore(&drm_dev->event_lock, flags); + if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) { + struct drm_plane *p; + + /* Disable mixer only if all overlay planes (GDP and VDP) + * are disabled */ + list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) { + struct sti_plane *plane = to_sti_plane(p); + + if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP) + if (plane->status != STI_PLANE_DISABLED) + return 0; + } + sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc); + } + return 0; } @@ -259,9 +316,9 @@ int sti_crtc_enable_vblank(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(sti_crtc_enable_vblank); -void sti_crtc_disable_vblank(struct drm_device *dev, int crtc) +void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc) { - struct sti_private *priv = dev->dev_private; + struct sti_private *priv = drm_dev->dev_private; struct sti_compositor *compo = priv->compo; struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb; @@ -273,7 +330,7 @@ void sti_crtc_disable_vblank(struct drm_device *dev, int crtc) /* free the resources of the pending requests */ if (compo->mixer[crtc]->pending_event) { - drm_vblank_put(dev, crtc); + drm_vblank_put(drm_dev, crtc); compo->mixer[crtc]->pending_event = NULL; } } diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index 2868909aa926..dd1032195051 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -7,6 +7,12 @@ */ #include +#include +#include +#include +#include + +#include "sti_compositor.h" #include "sti_cursor.h" #include "sti_plane.h" #include "sti_vtg.h" @@ -42,14 +48,14 @@ struct dma_pixmap { /** * STI Cursor structure * - * @sti_plane: sti_plane structure - * @dev: driver device - * @regs: cursor registers - * @width: cursor width - * @height: cursor height - * @clut: color look up table - * @clut_paddr: color look up table physical address - * @pixmap: pixmap dma buffer (clut8-format cursor) + * @sti_plane: sti_plane structure + * @dev: driver device + * @regs: cursor registers + * @width: cursor width + * @height: cursor height + * @clut: color look up table + * @clut_paddr: color look up table physical address + * @pixmap: pixmap dma buffer (clut8-format cursor) */ struct sti_cursor { struct sti_plane plane; @@ -68,20 +74,8 @@ static const uint32_t cursor_supported_formats[] = { #define to_sti_cursor(x) container_of(x, struct sti_cursor, plane) -static const uint32_t *sti_cursor_get_formats(struct sti_plane *plane) -{ - return cursor_supported_formats; -} - -static unsigned int sti_cursor_get_nb_formats(struct sti_plane *plane) -{ - return ARRAY_SIZE(cursor_supported_formats); -} - -static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane) +static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src) { - struct sti_cursor *cursor = to_sti_cursor(plane); - u32 *src = plane->vaddr; u8 *dst = cursor->pixmap.base; unsigned int i, j; u32 a, r, g, b; @@ -100,32 +94,67 @@ static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane) } } -static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare) +static void sti_cursor_init(struct sti_cursor *cursor) +{ + unsigned short *base = cursor->clut; + unsigned int a, r, g, b; + + /* Assign CLUT values, ARGB444 format */ + for (a = 0; a < 4; a++) + for (r = 0; r < 4; r++) + for (g = 0; g < 4; g++) + for (b = 0; b < 4; b++) + *base++ = (a * 5) << 12 | + (r * 5) << 8 | + (g * 5) << 4 | + (b * 5); +} + +static void sti_cursor_atomic_update(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) { + struct drm_plane_state *state = drm_plane->state; + struct sti_plane *plane = to_sti_plane(drm_plane); struct sti_cursor *cursor = to_sti_cursor(plane); - struct drm_display_mode *mode = plane->mode; + struct drm_crtc *crtc = state->crtc; + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct drm_framebuffer *fb = state->fb; + struct drm_display_mode *mode = &crtc->mode; + int dst_x = state->crtc_x; + int dst_y = state->crtc_y; + int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); + int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); + /* src_x are in 16.16 format */ + int src_w = state->src_w >> 16; + int src_h = state->src_h >> 16; + bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; + struct drm_gem_cma_object *cma_obj; u32 y, x; u32 val; - DRM_DEBUG_DRIVER("\n"); + DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", + crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y); - dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); + dev_dbg(cursor->dev, "%s %s\n", __func__, + sti_plane_to_str(plane)); - if (plane->src_w < STI_CURS_MIN_SIZE || - plane->src_h < STI_CURS_MIN_SIZE || - plane->src_w > STI_CURS_MAX_SIZE || - plane->src_h > STI_CURS_MAX_SIZE) { + if (src_w < STI_CURS_MIN_SIZE || + src_h < STI_CURS_MIN_SIZE || + src_w > STI_CURS_MAX_SIZE || + src_h > STI_CURS_MAX_SIZE) { DRM_ERROR("Invalid cursor size (%dx%d)\n", - plane->src_w, plane->src_h); - return -EINVAL; + src_w, src_h); + return; } /* If the cursor size has changed, re-allocated the pixmap */ if (!cursor->pixmap.base || - (cursor->width != plane->src_w) || - (cursor->height != plane->src_h)) { - cursor->width = plane->src_w; - cursor->height = plane->src_h; + (cursor->width != src_w) || + (cursor->height != src_h)) { + cursor->width = src_w; + cursor->height = src_h; if (cursor->pixmap.base) dma_free_writecombine(cursor->dev, @@ -141,12 +170,18 @@ static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare) GFP_KERNEL | GFP_DMA); if (!cursor->pixmap.base) { DRM_ERROR("Failed to allocate memory for pixmap\n"); - return -ENOMEM; + return; } } + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + if (!cma_obj) { + DRM_ERROR("Can't get CMA GEM object for fb\n"); + return; + } + /* Convert ARGB8888 to CLUT8 */ - sti_cursor_argb8888_to_clut8(plane); + sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr); /* AWS and AWE depend on the mode */ y = sti_vtg_get_line_number(*mode, 0); @@ -164,62 +199,50 @@ static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare) writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL); } - return 0; -} - -static int sti_cursor_commit_plane(struct sti_plane *plane) -{ - struct sti_cursor *cursor = to_sti_cursor(plane); - struct drm_display_mode *mode = plane->mode; - u32 ydo, xdo; - - dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); - /* Set memory location, size, and position */ writel(cursor->pixmap.paddr, cursor->regs + CUR_PML); writel(cursor->width, cursor->regs + CUR_PMP); writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE); - ydo = sti_vtg_get_line_number(*mode, plane->dst_y); - xdo = sti_vtg_get_pixel_number(*mode, plane->dst_y); - writel((ydo << 16) | xdo, cursor->regs + CUR_VPO); + y = sti_vtg_get_line_number(*mode, dst_y); + x = sti_vtg_get_pixel_number(*mode, dst_y); + writel((y << 16) | x, cursor->regs + CUR_VPO); - return 0; + plane->status = STI_PLANE_UPDATED; } -static int sti_cursor_disable_plane(struct sti_plane *plane) +static void sti_cursor_atomic_disable(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) { - return 0; -} + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); -static void sti_cursor_init(struct sti_cursor *cursor) -{ - unsigned short *base = cursor->clut; - unsigned int a, r, g, b; + if (!drm_plane->crtc) { + DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", + drm_plane->base.id); + return; + } - /* Assign CLUT values, ARGB444 format */ - for (a = 0; a < 4; a++) - for (r = 0; r < 4; r++) - for (g = 0; g < 4; g++) - for (b = 0; b < 4; b++) - *base++ = (a * 5) << 12 | - (r * 5) << 8 | - (g * 5) << 4 | - (b * 5); + DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", + drm_plane->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + + plane->status = STI_PLANE_DISABLING; } -static const struct sti_plane_funcs cursor_plane_ops = { - .get_formats = sti_cursor_get_formats, - .get_nb_formats = sti_cursor_get_nb_formats, - .prepare = sti_cursor_prepare_plane, - .commit = sti_cursor_commit_plane, - .disable = sti_cursor_disable_plane, +static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = { + .atomic_update = sti_cursor_atomic_update, + .atomic_disable = sti_cursor_atomic_disable, }; -struct sti_plane *sti_cursor_create(struct device *dev, int desc, - void __iomem *baseaddr) +struct drm_plane *sti_cursor_create(struct drm_device *drm_dev, + struct device *dev, int desc, + void __iomem *baseaddr, + unsigned int possible_crtcs) { struct sti_cursor *cursor; + size_t size; + int res; cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL); if (!cursor) { @@ -228,23 +251,43 @@ struct sti_plane *sti_cursor_create(struct device *dev, int desc, } /* Allocate clut buffer */ - cursor->clut = dma_alloc_writecombine(dev, - 0x100 * sizeof(unsigned short), - &cursor->clut_paddr, - GFP_KERNEL | GFP_DMA); + size = 0x100 * sizeof(unsigned short); + cursor->clut = dma_alloc_writecombine(dev, size, &cursor->clut_paddr, + GFP_KERNEL | GFP_DMA); if (!cursor->clut) { DRM_ERROR("Failed to allocate memory for cursor clut\n"); - devm_kfree(dev, cursor); - return NULL; + goto err_clut; } cursor->dev = dev; cursor->regs = baseaddr; cursor->plane.desc = desc; - cursor->plane.ops = &cursor_plane_ops; + cursor->plane.status = STI_PLANE_DISABLED; sti_cursor_init(cursor); - return &cursor->plane; + res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane, + possible_crtcs, + &sti_plane_helpers_funcs, + cursor_supported_formats, + ARRAY_SIZE(cursor_supported_formats), + DRM_PLANE_TYPE_CURSOR); + if (res) { + DRM_ERROR("Failed to initialize universal plane\n"); + goto err_plane; + } + + drm_plane_helper_add(&cursor->plane.drm_plane, + &sti_cursor_helpers_funcs); + + sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR); + + return &cursor->plane.drm_plane; + +err_plane: + dma_free_writecombine(dev, size, cursor->clut, cursor->clut_paddr); +err_clut: + devm_kfree(dev, cursor); + return NULL; } diff --git a/drivers/gpu/drm/sti/sti_cursor.h b/drivers/gpu/drm/sti/sti_cursor.h index db973b705d92..2ee5c10e8b33 100644 --- a/drivers/gpu/drm/sti/sti_cursor.h +++ b/drivers/gpu/drm/sti/sti_cursor.h @@ -7,7 +7,9 @@ #ifndef _STI_CURSOR_H_ #define _STI_CURSOR_H_ -struct sti_plane *sti_cursor_create(struct device *dev, int desc, - void __iomem *baseaddr); +struct drm_plane *sti_cursor_create(struct drm_device *drm_dev, + struct device *dev, int desc, + void __iomem *baseaddr, + unsigned int possible_crtcs); #endif diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index e323310bfa73..9365670427ad 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -9,6 +9,9 @@ #include #include +#include +#include + #include "sti_compositor.h" #include "sti_gdp.h" #include "sti_plane.h" @@ -26,7 +29,7 @@ #define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH) #define GDP_ARGB8565 0x04 #define GDP_ARGB8888 0x05 -#define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH) +#define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH) #define GDP_ARGB1555 0x06 #define GDP_ARGB4444 0x07 #define GDP_CLUT8 0x0B @@ -53,8 +56,8 @@ #define GAM_GDP_PPT_IGNORE (BIT(1) | BIT(0)) #define GAM_GDP_SIZE_MAX 0x7FF -#define GDP_NODE_NB_BANK 2 -#define GDP_NODE_PER_FIELD 2 +#define GDP_NODE_NB_BANK 2 +#define GDP_NODE_PER_FIELD 2 struct sti_gdp_node { u32 gam_gdp_ctl; @@ -124,16 +127,6 @@ static const uint32_t gdp_supported_formats[] = { DRM_FORMAT_C8, }; -static const uint32_t *sti_gdp_get_formats(struct sti_plane *plane) -{ - return gdp_supported_formats; -} - -static unsigned int sti_gdp_get_nb_formats(struct sti_plane *plane) -{ - return ARRAY_SIZE(gdp_supported_formats); -} - static int sti_gdp_fourcc2format(int fourcc) { switch (fourcc) { @@ -179,17 +172,16 @@ static int sti_gdp_get_alpharange(int format) /** * sti_gdp_get_free_nodes - * @plane: gdp plane + * @gdp: gdp pointer * * Look for a GDP node list that is not currently read by the HW. * * RETURNS: * Pointer to the free GDP node list */ -static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane) +static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_gdp *gdp) { int hw_nvn; - struct sti_gdp *gdp = to_sti_gdp(plane); unsigned int i; hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); @@ -203,7 +195,7 @@ static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_plane *plane) /* in hazardious cases restart with the first node */ DRM_ERROR("inconsistent NVN for %s: 0x%08X\n", - sti_plane_to_str(plane), hw_nvn); + sti_plane_to_str(&gdp->plane), hw_nvn); end: return &gdp->node_list[0]; @@ -211,7 +203,7 @@ end: /** * sti_gdp_get_current_nodes - * @plane: GDP plane + * @gdp: gdp pointer * * Look for GDP nodes that are currently read by the HW. * @@ -219,10 +211,9 @@ end: * Pointer to the current GDP node list */ static -struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane) +struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_gdp *gdp) { int hw_nvn; - struct sti_gdp *gdp = to_sti_gdp(plane); unsigned int i; hw_nvn = readl(gdp->regs + GAM_GDP_NVN_OFFSET); @@ -236,205 +227,25 @@ struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_plane *plane) end: DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n", - hw_nvn, sti_plane_to_str(plane)); + hw_nvn, sti_plane_to_str(&gdp->plane)); return NULL; } -/** - * sti_gdp_prepare - * @plane: gdp plane - * @first_prepare: true if it is the first time this function is called - * - * Update the free GDP node list according to the plane properties. - * - * RETURNS: - * 0 on success. - */ -static int sti_gdp_prepare(struct sti_plane *plane, bool first_prepare) -{ - struct sti_gdp_node_list *list; - struct sti_gdp_node *top_field, *btm_field; - struct drm_display_mode *mode = plane->mode; - struct sti_gdp *gdp = to_sti_gdp(plane); - struct device *dev = gdp->dev; - struct sti_compositor *compo = dev_get_drvdata(dev); - int format; - unsigned int depth, bpp; - int rate = mode->clock * 1000; - int res; - u32 ydo, xdo, yds, xds; - - list = sti_gdp_get_free_nodes(plane); - top_field = list->top_field; - btm_field = list->btm_field; - - dev_dbg(dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__, - sti_plane_to_str(plane), top_field, btm_field); - - /* Build the top field from plane params */ - top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE; - top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; - format = sti_gdp_fourcc2format(plane->format); - if (format == -1) { - DRM_ERROR("Format not supported by GDP %.4s\n", - (char *)&plane->format); - return 1; - } - top_field->gam_gdp_ctl |= format; - top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format); - top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE; - - /* pixel memory location */ - drm_fb_get_bpp_depth(plane->format, &depth, &bpp); - top_field->gam_gdp_pml = (u32)plane->paddr + plane->offsets[0]; - top_field->gam_gdp_pml += plane->src_x * (bpp >> 3); - top_field->gam_gdp_pml += plane->src_y * plane->pitches[0]; - - /* input parameters */ - top_field->gam_gdp_pmp = plane->pitches[0]; - top_field->gam_gdp_size = - clamp_val(plane->src_h, 0, GAM_GDP_SIZE_MAX) << 16 | - clamp_val(plane->src_w, 0, GAM_GDP_SIZE_MAX); - - /* output parameters */ - ydo = sti_vtg_get_line_number(*mode, plane->dst_y); - yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1); - xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x); - xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1); - top_field->gam_gdp_vpo = (ydo << 16) | xdo; - top_field->gam_gdp_vps = (yds << 16) | xds; - - /* Same content and chained together */ - memcpy(btm_field, top_field, sizeof(*btm_field)); - top_field->gam_gdp_nvn = list->btm_field_paddr; - btm_field->gam_gdp_nvn = list->top_field_paddr; - - /* Interlaced mode */ - if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE) - btm_field->gam_gdp_pml = top_field->gam_gdp_pml + - plane->pitches[0]; - - if (first_prepare) { - /* Register gdp callback */ - if (sti_vtg_register_client(plane->mixer_id == STI_MIXER_MAIN ? - compo->vtg_main : compo->vtg_aux, - &gdp->vtg_field_nb, plane->mixer_id)) { - DRM_ERROR("Cannot register VTG notifier\n"); - return 1; - } - - /* Set and enable gdp clock */ - if (gdp->clk_pix) { - struct clk *clkp; - /* According to the mixer used, the gdp pixel clock - * should have a different parent clock. */ - if (plane->mixer_id == STI_MIXER_MAIN) - clkp = gdp->clk_main_parent; - else - clkp = gdp->clk_aux_parent; - - if (clkp) - clk_set_parent(gdp->clk_pix, clkp); - - res = clk_set_rate(gdp->clk_pix, rate); - if (res < 0) { - DRM_ERROR("Cannot set rate (%dHz) for gdp\n", - rate); - return 1; - } - - if (clk_prepare_enable(gdp->clk_pix)) { - DRM_ERROR("Failed to prepare/enable gdp\n"); - return 1; - } - } - } - - return 0; -} - -/** - * sti_gdp_commit - * @plane: gdp plane - * - * Update the NVN field of the 'right' field of the current GDP node (being - * used by the HW) with the address of the updated ('free') top field GDP node. - * - In interlaced mode the 'right' field is the bottom field as we update - * frames starting from their top field - * - In progressive mode, we update both bottom and top fields which are - * equal nodes. - * At the next VSYNC, the updated node list will be used by the HW. - * - * RETURNS: - * 0 on success. - */ -static int sti_gdp_commit(struct sti_plane *plane) -{ - struct sti_gdp_node_list *updated_list = sti_gdp_get_free_nodes(plane); - struct sti_gdp_node *updated_top_node = updated_list->top_field; - struct sti_gdp_node *updated_btm_node = updated_list->btm_field; - struct sti_gdp *gdp = to_sti_gdp(plane); - u32 dma_updated_top = updated_list->top_field_paddr; - u32 dma_updated_btm = updated_list->btm_field_paddr; - struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(plane); - - dev_dbg(gdp->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__, - sti_plane_to_str(plane), - updated_top_node, updated_btm_node); - dev_dbg(gdp->dev, "Current NVN:0x%X\n", - readl(gdp->regs + GAM_GDP_NVN_OFFSET)); - dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n", - (unsigned long)plane->paddr, - readl(gdp->regs + GAM_GDP_PML_OFFSET)); - - if (curr_list == NULL) { - /* First update or invalid node should directly write in the - * hw register */ - DRM_DEBUG_DRIVER("%s first update (or invalid node)", - sti_plane_to_str(plane)); - - writel(gdp->is_curr_top == true ? - dma_updated_btm : dma_updated_top, - gdp->regs + GAM_GDP_NVN_OFFSET); - return 0; - } - - if (plane->mode->flags & DRM_MODE_FLAG_INTERLACE) { - if (gdp->is_curr_top == true) { - /* Do not update in the middle of the frame, but - * postpone the update after the bottom field has - * been displayed */ - curr_list->btm_field->gam_gdp_nvn = dma_updated_top; - } else { - /* Direct update to avoid one frame delay */ - writel(dma_updated_top, - gdp->regs + GAM_GDP_NVN_OFFSET); - } - } else { - /* Direct update for progressive to avoid one frame delay */ - writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET); - } - - return 0; -} - /** * sti_gdp_disable - * @plane: gdp plane + * @gdp: gdp pointer * * Disable a GDP. - * - * RETURNS: - * 0 on success. */ -static int sti_gdp_disable(struct sti_plane *plane) +static void sti_gdp_disable(struct sti_gdp *gdp) { - unsigned int i; - struct sti_gdp *gdp = to_sti_gdp(plane); + struct drm_plane *drm_plane = &gdp->plane.drm_plane; + struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); struct sti_compositor *compo = dev_get_drvdata(gdp->dev); + unsigned int i; - DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); + DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&gdp->plane)); /* Set the nodes as 'to be ignored on mixer' */ for (i = 0; i < GDP_NODE_NB_BANK; i++) { @@ -442,14 +253,14 @@ static int sti_gdp_disable(struct sti_plane *plane) gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE; } - if (sti_vtg_unregister_client(plane->mixer_id == STI_MIXER_MAIN ? + if (sti_vtg_unregister_client(mixer->id == STI_MIXER_MAIN ? compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb)) DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); if (gdp->clk_pix) clk_disable_unprepare(gdp->clk_pix); - return 0; + gdp->plane.status = STI_PLANE_DISABLED; } /** @@ -468,6 +279,14 @@ int sti_gdp_field_cb(struct notifier_block *nb, { struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb); + if (gdp->plane.status == STI_PLANE_FLUSHING) { + /* disable need to be synchronize on vsync event */ + DRM_DEBUG_DRIVER("Vsync event received => disable %s\n", + sti_plane_to_str(&gdp->plane)); + + sti_gdp_disable(gdp); + } + switch (event) { case VTG_TOP_FIELD_EVENT: gdp->is_curr_top = true; @@ -561,18 +380,235 @@ static void sti_gdp_init(struct sti_gdp *gdp) } } -static const struct sti_plane_funcs gdp_plane_ops = { - .get_formats = sti_gdp_get_formats, - .get_nb_formats = sti_gdp_get_nb_formats, - .prepare = sti_gdp_prepare, - .commit = sti_gdp_commit, - .disable = sti_gdp_disable, +static void sti_gdp_atomic_update(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) +{ + struct drm_plane_state *state = drm_plane->state; + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_gdp *gdp = to_sti_gdp(plane); + struct drm_crtc *crtc = state->crtc; + struct sti_compositor *compo = dev_get_drvdata(gdp->dev); + struct drm_framebuffer *fb = state->fb; + bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; + struct sti_mixer *mixer; + struct drm_display_mode *mode; + int dst_x, dst_y, dst_w, dst_h; + int src_x, src_y, src_w, src_h; + struct drm_gem_cma_object *cma_obj; + struct sti_gdp_node_list *list; + struct sti_gdp_node_list *curr_list; + struct sti_gdp_node *top_field, *btm_field; + u32 dma_updated_top; + u32 dma_updated_btm; + int format; + unsigned int depth, bpp; + u32 ydo, xdo, yds, xds; + int res; + + /* Manage the case where crtc is null (disabled) */ + if (!crtc) + return; + + mixer = to_sti_mixer(crtc); + mode = &crtc->mode; + dst_x = state->crtc_x; + dst_y = state->crtc_y; + dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); + dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); + /* src_x are in 16.16 format */ + src_x = state->src_x >> 16; + src_y = state->src_y >> 16; + src_w = state->src_w >> 16; + src_h = state->src_h >> 16; + + DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", + crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", + sti_plane_to_str(plane), + dst_w, dst_h, dst_x, dst_y, + src_w, src_h, src_x, src_y); + + list = sti_gdp_get_free_nodes(gdp); + top_field = list->top_field; + btm_field = list->btm_field; + + dev_dbg(gdp->dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__, + sti_plane_to_str(plane), top_field, btm_field); + + /* build the top field */ + top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE; + top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC; + format = sti_gdp_fourcc2format(fb->pixel_format); + if (format == -1) { + DRM_ERROR("Format not supported by GDP %.4s\n", + (char *)&fb->pixel_format); + return; + } + top_field->gam_gdp_ctl |= format; + top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format); + top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE; + + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + if (!cma_obj) { + DRM_ERROR("Can't get CMA GEM object for fb\n"); + return; + } + + DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, + (char *)&fb->pixel_format, + (unsigned long)cma_obj->paddr); + + /* pixel memory location */ + drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); + top_field->gam_gdp_pml = (u32)cma_obj->paddr + fb->offsets[0]; + top_field->gam_gdp_pml += src_x * (bpp >> 3); + top_field->gam_gdp_pml += src_y * fb->pitches[0]; + + /* input parameters */ + top_field->gam_gdp_pmp = fb->pitches[0]; + top_field->gam_gdp_size = clamp_val(src_h, 0, GAM_GDP_SIZE_MAX) << 16 | + clamp_val(src_w, 0, GAM_GDP_SIZE_MAX); + + /* output parameters */ + ydo = sti_vtg_get_line_number(*mode, dst_y); + yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1); + xdo = sti_vtg_get_pixel_number(*mode, dst_x); + xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1); + top_field->gam_gdp_vpo = (ydo << 16) | xdo; + top_field->gam_gdp_vps = (yds << 16) | xds; + + /* Same content and chained together */ + memcpy(btm_field, top_field, sizeof(*btm_field)); + top_field->gam_gdp_nvn = list->btm_field_paddr; + btm_field->gam_gdp_nvn = list->top_field_paddr; + + /* Interlaced mode */ + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + btm_field->gam_gdp_pml = top_field->gam_gdp_pml + + fb->pitches[0]; + + if (first_prepare) { + /* Register gdp callback */ + if (sti_vtg_register_client(mixer->id == STI_MIXER_MAIN ? + compo->vtg_main : compo->vtg_aux, + &gdp->vtg_field_nb, mixer->id)) { + DRM_ERROR("Cannot register VTG notifier\n"); + return; + } + + /* Set and enable gdp clock */ + if (gdp->clk_pix) { + struct clk *clkp; + int rate = mode->clock * 1000; + + /* According to the mixer used, the gdp pixel clock + * should have a different parent clock. */ + if (mixer->id == STI_MIXER_MAIN) + clkp = gdp->clk_main_parent; + else + clkp = gdp->clk_aux_parent; + + if (clkp) + clk_set_parent(gdp->clk_pix, clkp); + + res = clk_set_rate(gdp->clk_pix, rate); + if (res < 0) { + DRM_ERROR("Cannot set rate (%dHz) for gdp\n", + rate); + return; + } + + if (clk_prepare_enable(gdp->clk_pix)) { + DRM_ERROR("Failed to prepare/enable gdp\n"); + return; + } + } + } + + /* Update the NVN field of the 'right' field of the current GDP node + * (being used by the HW) with the address of the updated ('free') top + * field GDP node. + * - In interlaced mode the 'right' field is the bottom field as we + * update frames starting from their top field + * - In progressive mode, we update both bottom and top fields which + * are equal nodes. + * At the next VSYNC, the updated node list will be used by the HW. + */ + curr_list = sti_gdp_get_current_nodes(gdp); + dma_updated_top = list->top_field_paddr; + dma_updated_btm = list->btm_field_paddr; + + dev_dbg(gdp->dev, "Current NVN:0x%X\n", + readl(gdp->regs + GAM_GDP_NVN_OFFSET)); + dev_dbg(gdp->dev, "Posted buff: %lx current buff: %x\n", + (unsigned long)cma_obj->paddr, + readl(gdp->regs + GAM_GDP_PML_OFFSET)); + + if (!curr_list) { + /* First update or invalid node should directly write in the + * hw register */ + DRM_DEBUG_DRIVER("%s first update (or invalid node)", + sti_plane_to_str(plane)); + + writel(gdp->is_curr_top ? + dma_updated_btm : dma_updated_top, + gdp->regs + GAM_GDP_NVN_OFFSET); + goto end; + } + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + if (gdp->is_curr_top) { + /* Do not update in the middle of the frame, but + * postpone the update after the bottom field has + * been displayed */ + curr_list->btm_field->gam_gdp_nvn = dma_updated_top; + } else { + /* Direct update to avoid one frame delay */ + writel(dma_updated_top, + gdp->regs + GAM_GDP_NVN_OFFSET); + } + } else { + /* Direct update for progressive to avoid one frame delay */ + writel(dma_updated_top, gdp->regs + GAM_GDP_NVN_OFFSET); + } + +end: + plane->status = STI_PLANE_UPDATED; +} + +static void sti_gdp_atomic_disable(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) +{ + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); + + if (!drm_plane->crtc) { + DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", + drm_plane->base.id); + return; + } + + DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", + drm_plane->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + + plane->status = STI_PLANE_DISABLING; +} + +static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = { + .atomic_update = sti_gdp_atomic_update, + .atomic_disable = sti_gdp_atomic_disable, }; -struct sti_plane *sti_gdp_create(struct device *dev, int desc, - void __iomem *baseaddr) +struct drm_plane *sti_gdp_create(struct drm_device *drm_dev, + struct device *dev, int desc, + void __iomem *baseaddr, + unsigned int possible_crtcs, + enum drm_plane_type type) { struct sti_gdp *gdp; + int res; gdp = devm_kzalloc(dev, sizeof(*gdp), GFP_KERNEL); if (!gdp) { @@ -583,11 +619,30 @@ struct sti_plane *sti_gdp_create(struct device *dev, int desc, gdp->dev = dev; gdp->regs = baseaddr; gdp->plane.desc = desc; - gdp->plane.ops = &gdp_plane_ops; + gdp->plane.status = STI_PLANE_DISABLED; gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb; sti_gdp_init(gdp); - return &gdp->plane; + res = drm_universal_plane_init(drm_dev, &gdp->plane.drm_plane, + possible_crtcs, + &sti_plane_helpers_funcs, + gdp_supported_formats, + ARRAY_SIZE(gdp_supported_formats), + type); + if (res) { + DRM_ERROR("Failed to initialize universal plane\n"); + goto err; + } + + drm_plane_helper_add(&gdp->plane.drm_plane, &sti_gdp_helpers_funcs); + + sti_plane_init_property(&gdp->plane, type); + + return &gdp->plane.drm_plane; + +err: + devm_kfree(dev, gdp); + return NULL; } diff --git a/drivers/gpu/drm/sti/sti_gdp.h b/drivers/gpu/drm/sti/sti_gdp.h index 01818ea72125..73947a4a8004 100644 --- a/drivers/gpu/drm/sti/sti_gdp.h +++ b/drivers/gpu/drm/sti/sti_gdp.h @@ -11,7 +11,9 @@ #include -struct sti_plane *sti_gdp_create(struct device *dev, int desc, - void __iomem *baseaddr); - +struct drm_plane *sti_gdp_create(struct drm_device *drm_dev, + struct device *dev, int desc, + void __iomem *baseaddr, + unsigned int possible_crtcs, + enum drm_plane_type type); #endif diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index b91a009f0d5d..7c8f9b8bfae1 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -12,7 +12,10 @@ #include #include +#include +#include +#include "sti_compositor.h" #include "sti_hqvdp_lut.h" #include "sti_plane.h" #include "sti_vtg.h" @@ -357,16 +360,6 @@ static const uint32_t hqvdp_supported_formats[] = { DRM_FORMAT_NV12, }; -static const uint32_t *sti_hqvdp_get_formats(struct sti_plane *plane) -{ - return hqvdp_supported_formats; -} - -static unsigned int sti_hqvdp_get_nb_formats(struct sti_plane *plane) -{ - return ARRAY_SIZE(hqvdp_supported_formats); -} - /** * sti_hqvdp_get_free_cmd * @hqvdp: hqvdp structure @@ -482,7 +475,12 @@ static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale, /** * sti_hqvdp_check_hw_scaling - * @plane: hqvdp plane + * @hqvdp: hqvdp pointer + * @mode: display mode with timing constraints + * @src_w: source width + * @src_h: source height + * @dst_w: destination width + * @dst_h: destination height * * Check if the HW is able to perform the scaling request * The firmware scaling limitation is "CEIL(1/Zy) <= FLOOR(LFW)" where: @@ -496,194 +494,36 @@ static void sti_hqvdp_update_hvsrc(enum sti_hvsrc_orient orient, int scale, * RETURNS: * True if the HW can scale. */ -static bool sti_hqvdp_check_hw_scaling(struct sti_plane *plane) +static bool sti_hqvdp_check_hw_scaling(struct sti_hqvdp *hqvdp, + struct drm_display_mode *mode, + int src_w, int src_h, + int dst_w, int dst_h) { - struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); unsigned long lfw; unsigned int inv_zy; - lfw = plane->mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000); - lfw /= max(plane->src_w, plane->dst_w) * plane->mode->clock / 1000; + lfw = mode->htotal * (clk_get_rate(hqvdp->clk) / 1000000); + lfw /= max(src_w, dst_w) * mode->clock / 1000; - inv_zy = DIV_ROUND_UP(plane->src_h, plane->dst_h); + inv_zy = DIV_ROUND_UP(src_h, dst_h); return (inv_zy <= lfw) ? true : false; } -/** - * sti_hqvdp_prepare - * @plane: hqvdp plane - * @first_prepare: true if it is the first time this function is called - * - * Prepares a command for the firmware - * - * RETURNS: - * 0 on success. - */ -static int sti_hqvdp_prepare(struct sti_plane *plane, bool first_prepare) -{ - struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); - struct sti_hqvdp_cmd *cmd; - int scale_h, scale_v; - int cmd_offset; - - dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); - - cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); - if (cmd_offset == -1) { - DRM_ERROR("No available hqvdp_cmd now\n"); - return -EBUSY; - } - cmd = hqvdp->hqvdp_cmd + cmd_offset; - - if (!sti_hqvdp_check_hw_scaling(plane)) { - DRM_ERROR("Scaling beyond HW capabilities\n"); - return -EINVAL; - } - - /* Static parameters, defaulting to progressive mode */ - cmd->top.config = TOP_CONFIG_PROGRESSIVE; - cmd->top.mem_format = TOP_MEM_FORMAT_DFLT; - cmd->hvsrc.param_ctrl = HVSRC_PARAM_CTRL_DFLT; - cmd->csdi.config = CSDI_CONFIG_PROG; - - /* VC1RE, FMD bypassed : keep everything set to 0 - * IQI/P2I bypassed */ - cmd->iqi.config = IQI_CONFIG_DFLT; - cmd->iqi.con_bri = IQI_CON_BRI_DFLT; - cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT; - cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT; - - /* Buffer planes address */ - cmd->top.current_luma = (u32)plane->paddr + plane->offsets[0]; - cmd->top.current_chroma = (u32)plane->paddr + plane->offsets[1]; - - /* Pitches */ - cmd->top.luma_processed_pitch = cmd->top.luma_src_pitch = - plane->pitches[0]; - cmd->top.chroma_processed_pitch = cmd->top.chroma_src_pitch = - plane->pitches[1]; - - /* Input / output size - * Align to upper even value */ - plane->dst_w = ALIGN(plane->dst_w, 2); - plane->dst_h = ALIGN(plane->dst_h, 2); - - if ((plane->src_w > MAX_WIDTH) || (plane->src_w < MIN_WIDTH) || - (plane->src_h > MAX_HEIGHT) || (plane->src_h < MIN_HEIGHT) || - (plane->dst_w > MAX_WIDTH) || (plane->dst_w < MIN_WIDTH) || - (plane->dst_h > MAX_HEIGHT) || (plane->dst_h < MIN_HEIGHT)) { - DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n", - plane->src_w, plane->src_h, - plane->dst_w, plane->dst_h); - return -EINVAL; - } - cmd->top.input_viewport_size = cmd->top.input_frame_size = - plane->src_h << 16 | plane->src_w; - cmd->hvsrc.output_picture_size = plane->dst_h << 16 | plane->dst_w; - cmd->top.input_viewport_ori = plane->src_y << 16 | plane->src_x; - - /* Handle interlaced */ - if (plane->fb->flags & DRM_MODE_FB_INTERLACED) { - /* Top field to display */ - cmd->top.config = TOP_CONFIG_INTER_TOP; - - /* Update pitches and vert size */ - cmd->top.input_frame_size = (plane->src_h / 2) << 16 | - plane->src_w; - cmd->top.luma_processed_pitch *= 2; - cmd->top.luma_src_pitch *= 2; - cmd->top.chroma_processed_pitch *= 2; - cmd->top.chroma_src_pitch *= 2; - - /* Enable directional deinterlacing processing */ - cmd->csdi.config = CSDI_CONFIG_INTER_DIR; - cmd->csdi.config2 = CSDI_CONFIG2_DFLT; - cmd->csdi.dcdi_config = CSDI_DCDI_CONFIG_DFLT; - } - - /* Update hvsrc lut coef */ - scale_h = SCALE_FACTOR * plane->dst_w / plane->src_w; - sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc); - - scale_v = SCALE_FACTOR * plane->dst_h / plane->src_h; - sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc); - - if (first_prepare) { - /* Prevent VTG shutdown */ - if (clk_prepare_enable(hqvdp->clk_pix_main)) { - DRM_ERROR("Failed to prepare/enable pix main clk\n"); - return -ENXIO; - } - - /* Register VTG Vsync callback to handle bottom fields */ - if ((plane->fb->flags & DRM_MODE_FB_INTERLACED) && - sti_vtg_register_client(hqvdp->vtg, &hqvdp->vtg_nb, - plane->mixer_id)) { - DRM_ERROR("Cannot register VTG notifier\n"); - return -ENXIO; - } - } - - return 0; -} - -/** - * sti_hqvdp_commit - * @plane: hqvdp plane - * - * Enables the HQVDP plane - * - * RETURNS: - * 0 on success. - */ -static int sti_hqvdp_commit(struct sti_plane *plane) -{ - struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); - int cmd_offset; - - dev_dbg(hqvdp->dev, "%s %s\n", __func__, sti_plane_to_str(plane)); - - cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); - if (cmd_offset == -1) { - DRM_ERROR("No available hqvdp_cmd now\n"); - return -EBUSY; - } - - writel(hqvdp->hqvdp_cmd_paddr + cmd_offset, - hqvdp->regs + HQVDP_MBX_NEXT_CMD); - - hqvdp->curr_field_count++; - - /* Interlaced : get ready to display the bottom field at next Vsync */ - if (plane->fb->flags & DRM_MODE_FB_INTERLACED) - hqvdp->btm_field_pending = true; - - dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n", - __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset); - - return 0; -} - /** * sti_hqvdp_disable - * @plane: hqvdp plane + * @hqvdp: hqvdp pointer * * Disables the HQVDP plane - * - * RETURNS: - * 0 on success. */ -static int sti_hqvdp_disable(struct sti_plane *plane) +static void sti_hqvdp_disable(struct sti_hqvdp *hqvdp) { - struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); int i; - DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); + DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(&hqvdp->plane)); /* Unregister VTG Vsync callback */ - if ((plane->fb->flags & DRM_MODE_FB_INTERLACED) && - sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb)) + if (sti_vtg_unregister_client(hqvdp->vtg, &hqvdp->vtg_nb)) DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n"); /* Set next cmd to NULL */ @@ -699,12 +539,10 @@ static int sti_hqvdp_disable(struct sti_plane *plane) /* VTG can stop now */ clk_disable_unprepare(hqvdp->clk_pix_main); - if (i == POLL_MAX_ATTEMPT) { + if (i == POLL_MAX_ATTEMPT) DRM_ERROR("XP70 could not revert to idle\n"); - return -ENXIO; - } - return 0; + hqvdp->plane.status = STI_PLANE_DISABLED; } /** @@ -729,6 +567,14 @@ int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data) return 0; } + if (hqvdp->plane.status == STI_PLANE_FLUSHING) { + /* disable need to be synchronize on vsync event */ + DRM_DEBUG_DRIVER("Vsync event received => disable %s\n", + sti_plane_to_str(&hqvdp->plane)); + + sti_hqvdp_disable(hqvdp); + } + if (hqvdp->btm_field_pending) { /* Create the btm field command from the current one */ btm_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); @@ -782,24 +628,212 @@ static void sti_hqvdp_init(struct sti_hqvdp *hqvdp) memset(hqvdp->hqvdp_cmd, 0, size); } -static const struct sti_plane_funcs hqvdp_plane_ops = { - .get_formats = sti_hqvdp_get_formats, - .get_nb_formats = sti_hqvdp_get_nb_formats, - .prepare = sti_hqvdp_prepare, - .commit = sti_hqvdp_commit, - .disable = sti_hqvdp_disable, +static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) +{ + struct drm_plane_state *state = drm_plane->state; + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); + struct drm_crtc *crtc = state->crtc; + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct drm_framebuffer *fb = state->fb; + struct drm_display_mode *mode = &crtc->mode; + int dst_x = state->crtc_x; + int dst_y = state->crtc_y; + int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); + int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); + /* src_x are in 16.16 format */ + int src_x = state->src_x >> 16; + int src_y = state->src_y >> 16; + int src_w = state->src_w >> 16; + int src_h = state->src_h >> 16; + bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false; + struct drm_gem_cma_object *cma_obj; + struct sti_hqvdp_cmd *cmd; + int scale_h, scale_v; + int cmd_offset; + + DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", + crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + DRM_DEBUG_KMS("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", + sti_plane_to_str(plane), + dst_w, dst_h, dst_x, dst_y, + src_w, src_h, src_x, src_y); + + cmd_offset = sti_hqvdp_get_free_cmd(hqvdp); + if (cmd_offset == -1) { + DRM_ERROR("No available hqvdp_cmd now\n"); + return; + } + cmd = hqvdp->hqvdp_cmd + cmd_offset; + + if (!sti_hqvdp_check_hw_scaling(hqvdp, mode, + src_w, src_h, + dst_w, dst_h)) { + DRM_ERROR("Scaling beyond HW capabilities\n"); + return; + } + + /* Static parameters, defaulting to progressive mode */ + cmd->top.config = TOP_CONFIG_PROGRESSIVE; + cmd->top.mem_format = TOP_MEM_FORMAT_DFLT; + cmd->hvsrc.param_ctrl = HVSRC_PARAM_CTRL_DFLT; + cmd->csdi.config = CSDI_CONFIG_PROG; + + /* VC1RE, FMD bypassed : keep everything set to 0 + * IQI/P2I bypassed */ + cmd->iqi.config = IQI_CONFIG_DFLT; + cmd->iqi.con_bri = IQI_CON_BRI_DFLT; + cmd->iqi.sat_gain = IQI_SAT_GAIN_DFLT; + cmd->iqi.pxf_conf = IQI_PXF_CONF_DFLT; + + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + if (!cma_obj) { + DRM_ERROR("Can't get CMA GEM object for fb\n"); + return; + } + + DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, + (char *)&fb->pixel_format, + (unsigned long)cma_obj->paddr); + + /* Buffer planes address */ + cmd->top.current_luma = (u32)cma_obj->paddr + fb->offsets[0]; + cmd->top.current_chroma = (u32)cma_obj->paddr + fb->offsets[1]; + + /* Pitches */ + cmd->top.luma_processed_pitch = fb->pitches[0]; + cmd->top.luma_src_pitch = fb->pitches[0]; + cmd->top.chroma_processed_pitch = fb->pitches[1]; + cmd->top.chroma_src_pitch = fb->pitches[1]; + + /* Input / output size + * Align to upper even value */ + dst_w = ALIGN(dst_w, 2); + dst_h = ALIGN(dst_h, 2); + + if ((src_w > MAX_WIDTH) || (src_w < MIN_WIDTH) || + (src_h > MAX_HEIGHT) || (src_h < MIN_HEIGHT) || + (dst_w > MAX_WIDTH) || (dst_w < MIN_WIDTH) || + (dst_h > MAX_HEIGHT) || (dst_h < MIN_HEIGHT)) { + DRM_ERROR("Invalid in/out size %dx%d -> %dx%d\n", + src_w, src_h, + dst_w, dst_h); + return; + } + + cmd->top.input_viewport_size = src_h << 16 | src_w; + cmd->top.input_frame_size = src_h << 16 | src_w; + cmd->hvsrc.output_picture_size = dst_h << 16 | dst_w; + cmd->top.input_viewport_ori = src_y << 16 | src_x; + + /* Handle interlaced */ + if (fb->flags & DRM_MODE_FB_INTERLACED) { + /* Top field to display */ + cmd->top.config = TOP_CONFIG_INTER_TOP; + + /* Update pitches and vert size */ + cmd->top.input_frame_size = (src_h / 2) << 16 | src_w; + cmd->top.luma_processed_pitch *= 2; + cmd->top.luma_src_pitch *= 2; + cmd->top.chroma_processed_pitch *= 2; + cmd->top.chroma_src_pitch *= 2; + + /* Enable directional deinterlacing processing */ + cmd->csdi.config = CSDI_CONFIG_INTER_DIR; + cmd->csdi.config2 = CSDI_CONFIG2_DFLT; + cmd->csdi.dcdi_config = CSDI_DCDI_CONFIG_DFLT; + } + + /* Update hvsrc lut coef */ + scale_h = SCALE_FACTOR * dst_w / src_w; + sti_hqvdp_update_hvsrc(HVSRC_HORI, scale_h, &cmd->hvsrc); + + scale_v = SCALE_FACTOR * dst_h / src_h; + sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc); + + if (first_prepare) { + /* Prevent VTG shutdown */ + if (clk_prepare_enable(hqvdp->clk_pix_main)) { + DRM_ERROR("Failed to prepare/enable pix main clk\n"); + return; + } + + /* Register VTG Vsync callback to handle bottom fields */ + if (sti_vtg_register_client(hqvdp->vtg, + &hqvdp->vtg_nb, + mixer->id)) { + DRM_ERROR("Cannot register VTG notifier\n"); + return; + } + } + + writel(hqvdp->hqvdp_cmd_paddr + cmd_offset, + hqvdp->regs + HQVDP_MBX_NEXT_CMD); + + hqvdp->curr_field_count++; + + /* Interlaced : get ready to display the bottom field at next Vsync */ + if (fb->flags & DRM_MODE_FB_INTERLACED) + hqvdp->btm_field_pending = true; + + dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n", + __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset); + + plane->status = STI_PLANE_UPDATED; +} + +static void sti_hqvdp_atomic_disable(struct drm_plane *drm_plane, + struct drm_plane_state *oldstate) +{ + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); + + if (!drm_plane->crtc) { + DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", + drm_plane->base.id); + return; + } + + DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", + drm_plane->crtc->base.id, sti_mixer_to_str(mixer), + drm_plane->base.id, sti_plane_to_str(plane)); + + plane->status = STI_PLANE_DISABLING; +} + +static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = { + .atomic_update = sti_hqvdp_atomic_update, + .atomic_disable = sti_hqvdp_atomic_disable, }; -struct sti_plane *sti_hqvdp_create(struct device *dev, int desc) +static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev, + struct device *dev, int desc) { struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); + int res; hqvdp->plane.desc = desc; - hqvdp->plane.ops = &hqvdp_plane_ops; + hqvdp->plane.status = STI_PLANE_DISABLED; sti_hqvdp_init(hqvdp); - return &hqvdp->plane; + res = drm_universal_plane_init(drm_dev, &hqvdp->plane.drm_plane, 1, + &sti_plane_helpers_funcs, + hqvdp_supported_formats, + ARRAY_SIZE(hqvdp_supported_formats), + DRM_PLANE_TYPE_OVERLAY); + if (res) { + DRM_ERROR("Failed to initialize universal plane\n"); + return NULL; + } + + drm_plane_helper_add(&hqvdp->plane.drm_plane, &sti_hqvdp_helpers_funcs); + + sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY); + + return &hqvdp->plane.drm_plane; } static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp) @@ -948,7 +982,7 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data) { struct sti_hqvdp *hqvdp = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - struct sti_plane *plane; + struct drm_plane *plane; int err; DRM_DEBUG_DRIVER("\n"); @@ -965,11 +999,8 @@ int sti_hqvdp_bind(struct device *dev, struct device *master, void *data) } /* Create HQVDP plane once xp70 is initialized */ - plane = sti_hqvdp_create(hqvdp->dev, STI_HQVDP_0); - if (plane) - sti_plane_init(hqvdp->drm_dev, plane, 1, - DRM_PLANE_TYPE_OVERLAY); - else + plane = sti_hqvdp_create(drm_dev, hqvdp->dev, STI_HQVDP_0); + if (!plane) DRM_ERROR("Can't create HQVDP plane\n"); return 0; diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c index d5a96561c8ce..0182e9365004 100644 --- a/drivers/gpu/drm/sti/sti_mixer.c +++ b/drivers/gpu/drm/sti/sti_mixer.c @@ -58,6 +58,7 @@ const char *sti_mixer_to_str(struct sti_mixer *mixer) return ""; } } +EXPORT_SYMBOL(sti_mixer_to_str); static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id) { @@ -225,15 +226,6 @@ int sti_mixer_set_plane_status(struct sti_mixer *mixer, return 0; } -void sti_mixer_clear_all_planes(struct sti_mixer *mixer) -{ - u32 val; - - DRM_DEBUG_DRIVER("%s clear all planes\n", sti_mixer_to_str(mixer)); - val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL) & 0xFFFF0000; - sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val); -} - void sti_mixer_set_matrix(struct sti_mixer *mixer) { unsigned int i; diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h index 2f69b007e7c8..efb1a9a5ba86 100644 --- a/drivers/gpu/drm/sti/sti_mixer.h +++ b/drivers/gpu/drm/sti/sti_mixer.h @@ -15,6 +15,12 @@ #define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc) +enum sti_mixer_status { + STI_MIXER_READY, + STI_MIXER_DISABLING, + STI_MIXER_DISABLED, +}; + /** * STI Mixer subdevice structure * @@ -23,7 +29,7 @@ * @id: id of the mixer * @drm_crtc: crtc object link to the mixer * @pending_event: set if a flip event is pending on crtc - * @enabled: to know if the mixer is active or not + * @status: to know the status of the mixer */ struct sti_mixer { struct device *dev; @@ -31,7 +37,7 @@ struct sti_mixer { int id; struct drm_crtc drm_crtc; struct drm_pending_vblank_event *pending_event; - bool enabled; + enum sti_mixer_status status; }; const char *sti_mixer_to_str(struct sti_mixer *mixer); @@ -41,7 +47,6 @@ struct sti_mixer *sti_mixer_create(struct device *dev, int id, int sti_mixer_set_plane_status(struct sti_mixer *mixer, struct sti_plane *plane, bool status); -void sti_mixer_clear_all_planes(struct sti_mixer *mixer); int sti_mixer_set_plane_depth(struct sti_mixer *mixer, struct sti_plane *plane); int sti_mixer_active_video_area(struct sti_mixer *mixer, struct drm_display_mode *mode); diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c index 6a38521ca9b4..d5c5e91f2956 100644 --- a/drivers/gpu/drm/sti/sti_plane.c +++ b/drivers/gpu/drm/sti/sti_plane.c @@ -7,15 +7,12 @@ */ #include -#include -#include #include -#include +#include #include "sti_compositor.h" #include "sti_drv.h" #include "sti_plane.h" -#include "sti_vtg.h" /* (Background) < GDP0 < GDP1 < HQVDP0 < GDP2 < GDP3 < (ForeGround) */ enum sti_plane_desc sti_plane_default_zorder[] = { @@ -47,115 +44,6 @@ const char *sti_plane_to_str(struct sti_plane *plane) } EXPORT_SYMBOL(sti_plane_to_str); -static int sti_plane_prepare(struct sti_plane *plane, - struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_display_mode *mode, int mixer_id, - int dest_x, int dest_y, int dest_w, int dest_h, - int src_x, int src_y, int src_w, int src_h) -{ - struct drm_gem_cma_object *cma_obj; - unsigned int i; - int res; - - if (!plane || !fb || !mode) { - DRM_ERROR("Null fb, plane or mode\n"); - return 1; - } - - cma_obj = drm_fb_cma_get_gem_obj(fb, 0); - if (!cma_obj) { - DRM_ERROR("Can't get CMA GEM object for fb\n"); - return 1; - } - - plane->fb = fb; - plane->mode = mode; - plane->mixer_id = mixer_id; - plane->dst_x = dest_x; - plane->dst_y = dest_y; - plane->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x); - plane->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y); - plane->src_x = src_x; - plane->src_y = src_y; - plane->src_w = src_w; - plane->src_h = src_h; - plane->format = fb->pixel_format; - plane->vaddr = cma_obj->vaddr; - plane->paddr = cma_obj->paddr; - for (i = 0; i < 4; i++) { - plane->pitches[i] = fb->pitches[i]; - plane->offsets[i] = fb->offsets[i]; - } - - DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n", - sti_plane_to_str(plane), - plane->mixer_id); - DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n", - sti_plane_to_str(plane), - plane->dst_w, plane->dst_h, plane->dst_x, plane->dst_y, - plane->src_w, plane->src_h, plane->src_x, - plane->src_y); - - DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id, - (char *)&plane->format, (unsigned long)plane->paddr); - - if (!plane->ops->prepare) { - DRM_ERROR("Cannot prepare\n"); - return 1; - } - - res = plane->ops->prepare(plane, !plane->enabled); - if (res) { - DRM_ERROR("Plane prepare failed\n"); - return res; - } - - plane->enabled = true; - - return 0; -} - -static int sti_plane_commit(struct sti_plane *plane) -{ - if (!plane) - return 1; - - if (!plane->ops->commit) { - DRM_ERROR("Cannot commit\n"); - return 1; - } - - return plane->ops->commit(plane); -} - -static int sti_plane_disable(struct sti_plane *plane) -{ - int res; - - DRM_DEBUG_DRIVER("%s\n", sti_plane_to_str(plane)); - if (!plane) - return 1; - - if (!plane->enabled) - return 0; - - if (!plane->ops->disable) { - DRM_ERROR("Cannot disable\n"); - return 1; - } - - res = plane->ops->disable(plane); - if (res) { - DRM_ERROR("Plane disable failed\n"); - return res; - } - - plane->enabled = false; - - return 0; -} - static void sti_plane_destroy(struct drm_plane *drm_plane) { DRM_DEBUG_DRIVER("\n"); @@ -182,109 +70,6 @@ static int sti_plane_set_property(struct drm_plane *drm_plane, return -EINVAL; } -static struct drm_plane_funcs sti_plane_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = sti_plane_destroy, - .set_property = sti_plane_set_property, - .reset = drm_atomic_helper_plane_reset, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, -}; - -static int sti_plane_atomic_check(struct drm_plane *drm_plane, - struct drm_plane_state *state) -{ - return 0; -} - -static void sti_plane_atomic_update(struct drm_plane *drm_plane, - struct drm_plane_state *oldstate) -{ - struct drm_plane_state *state = drm_plane->state; - struct sti_plane *plane = to_sti_plane(drm_plane); - struct sti_mixer *mixer = to_sti_mixer(state->crtc); - int res; - - DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", - state->crtc->base.id, sti_mixer_to_str(mixer), - drm_plane->base.id, sti_plane_to_str(plane)); - DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", - state->crtc_w, state->crtc_h, - state->crtc_x, state->crtc_y); - - res = sti_mixer_set_plane_depth(mixer, plane); - if (res) { - DRM_ERROR("Cannot set plane depth\n"); - return; - } - - /* src_x are in 16.16 format */ - res = sti_plane_prepare(plane, state->crtc, state->fb, - &state->crtc->mode, mixer->id, - state->crtc_x, state->crtc_y, - state->crtc_w, state->crtc_h, - state->src_x >> 16, state->src_y >> 16, - state->src_w >> 16, state->src_h >> 16); - if (res) { - DRM_ERROR("Plane prepare failed\n"); - return; - } - - res = sti_plane_commit(plane); - if (res) { - DRM_ERROR("Plane commit failed\n"); - return; - } - - res = sti_mixer_set_plane_status(mixer, plane, true); - if (res) { - DRM_ERROR("Cannot enable plane at mixer\n"); - return; - } -} - -static void sti_plane_atomic_disable(struct drm_plane *drm_plane, - struct drm_plane_state *oldstate) -{ - struct sti_plane *plane = to_sti_plane(drm_plane); - struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc); - int res; - - if (!drm_plane->crtc) { - DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", - drm_plane->base.id); - return; - } - - DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n", - drm_plane->crtc->base.id, sti_mixer_to_str(mixer), - drm_plane->base.id, sti_plane_to_str(plane)); - - /* Disable plane at mixer level */ - res = sti_mixer_set_plane_status(mixer, plane, false); - if (res) { - DRM_ERROR("Cannot disable plane at mixer\n"); - return; - } - - /* Wait a while to be sure that a Vsync event is received */ - msleep(WAIT_NEXT_VSYNC_MS); - - /* Then disable plane itself */ - res = sti_plane_disable(plane); - if (res) { - DRM_ERROR("Plane disable failed\n"); - return; - } -} - -static const struct drm_plane_helper_funcs sti_plane_helpers_funcs = { - .atomic_check = sti_plane_atomic_check, - .atomic_update = sti_plane_atomic_update, - .atomic_disable = sti_plane_atomic_disable, -}; - static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane) { struct drm_device *dev = drm_plane->dev; @@ -305,25 +90,10 @@ static void sti_plane_attach_zorder_property(struct drm_plane *drm_plane) drm_object_attach_property(&drm_plane->base, prop, plane->zorder); } -struct drm_plane *sti_plane_init(struct drm_device *dev, - struct sti_plane *plane, - unsigned int possible_crtcs, - enum drm_plane_type type) +void sti_plane_init_property(struct sti_plane *plane, + enum drm_plane_type type) { - int err, i; - - err = drm_universal_plane_init(dev, &plane->drm_plane, - possible_crtcs, - &sti_plane_funcs, - plane->ops->get_formats(plane), - plane->ops->get_nb_formats(plane), - type); - if (err) { - DRM_ERROR("Failed to initialize universal plane\n"); - return NULL; - } - - drm_plane_helper_add(&plane->drm_plane, &sti_plane_helpers_funcs); + unsigned int i; for (i = 0; i < ARRAY_SIZE(sti_plane_default_zorder); i++) if (sti_plane_default_zorder[i] == plane->desc) @@ -337,7 +107,16 @@ struct drm_plane *sti_plane_init(struct drm_device *dev, DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%d\n", plane->drm_plane.base.id, sti_plane_to_str(plane), plane->zorder); - - return &plane->drm_plane; } -EXPORT_SYMBOL(sti_plane_init); +EXPORT_SYMBOL(sti_plane_init_property); + +struct drm_plane_funcs sti_plane_helpers_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = sti_plane_destroy, + .set_property = sti_plane_set_property, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; +EXPORT_SYMBOL(sti_plane_helpers_funcs); diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h index bd527543bb1c..86f1e6fc81b9 100644 --- a/drivers/gpu/drm/sti/sti_plane.h +++ b/drivers/gpu/drm/sti/sti_plane.h @@ -8,6 +8,10 @@ #define _STI_PLANE_H_ #include +#include +#include + +extern struct drm_plane_funcs sti_plane_helpers_funcs; #define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane) @@ -38,68 +42,30 @@ enum sti_plane_desc { STI_BACK = STI_BCK }; +enum sti_plane_status { + STI_PLANE_READY, + STI_PLANE_UPDATED, + STI_PLANE_DISABLING, + STI_PLANE_FLUSHING, + STI_PLANE_DISABLED, +}; + /** * STI plane structure * * @plane: drm plane it is bound to (if any) - * @fb: drm fb it is bound to - * @mode: display mode * @desc: plane type & id - * @ops: plane functions + * @status: to know the status of the plane * @zorder: plane z-order - * @mixer_id: id of the mixer used to display the plane - * @enabled: to know if the plane is active or not - * @src_x src_y: coordinates of the input (fb) area - * @src_w src_h: size of the input (fb) area - * @dst_x dst_y: coordinates of the output (crtc) area - * @dst_w dst_h: size of the output (crtc) area - * @format: format - * @pitches: pitch of 'planes' (eg: Y, U, V) - * @offsets: offset of 'planes' - * @vaddr: virtual address of the input buffer - * @paddr: physical address of the input buffer */ struct sti_plane { struct drm_plane drm_plane; - struct drm_framebuffer *fb; - struct drm_display_mode *mode; enum sti_plane_desc desc; - const struct sti_plane_funcs *ops; + enum sti_plane_status status; int zorder; - int mixer_id; - bool enabled; - int src_x, src_y; - int src_w, src_h; - int dst_x, dst_y; - int dst_w, dst_h; - uint32_t format; - unsigned int pitches[4]; - unsigned int offsets[4]; - void *vaddr; - dma_addr_t paddr; }; -/** - * STI plane functions structure - * - * @get_formats: get plane supported formats - * @get_nb_formats: get number of format supported - * @prepare: prepare plane before rendering - * @commit: set plane for rendering - * @disable: disable plane - */ -struct sti_plane_funcs { - const uint32_t* (*get_formats)(struct sti_plane *plane); - unsigned int (*get_nb_formats)(struct sti_plane *plane); - int (*prepare)(struct sti_plane *plane, bool first_prepare); - int (*commit)(struct sti_plane *plane); - int (*disable)(struct sti_plane *plane); -}; - -struct drm_plane *sti_plane_init(struct drm_device *dev, - struct sti_plane *sti_plane, - unsigned int possible_crtcs, - enum drm_plane_type type); const char *sti_plane_to_str(struct sti_plane *plane); - +void sti_plane_init_property(struct sti_plane *plane, + enum drm_plane_type type); #endif diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c index 1e7e1d776adb..a8254cc362a1 100644 --- a/drivers/gpu/drm/sti/sti_vid.c +++ b/drivers/gpu/drm/sti/sti_vid.c @@ -43,28 +43,37 @@ #define VID_MPR2_BT709 0x07150545 #define VID_MPR3_BT709 0x00000AE8 -int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane) +void sti_vid_commit(struct sti_vid *vid, + struct drm_plane_state *state) { - struct drm_display_mode *mode = plane->mode; + struct drm_crtc *crtc = state->crtc; + struct drm_display_mode *mode = &crtc->mode; + int dst_x = state->crtc_x; + int dst_y = state->crtc_y; + int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); + int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); u32 val, ydo, xdo, yds, xds; + /* Input / output size + * Align to upper even value */ + dst_w = ALIGN(dst_w, 2); + dst_h = ALIGN(dst_h, 2); + /* Unmask */ val = readl(vid->regs + VID_CTL); val &= ~VID_CTL_IGNORE; writel(val, vid->regs + VID_CTL); - ydo = sti_vtg_get_line_number(*mode, plane->dst_y); - yds = sti_vtg_get_line_number(*mode, plane->dst_y + plane->dst_h - 1); - xdo = sti_vtg_get_pixel_number(*mode, plane->dst_x); - xds = sti_vtg_get_pixel_number(*mode, plane->dst_x + plane->dst_w - 1); + ydo = sti_vtg_get_line_number(*mode, dst_y); + yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1); + xdo = sti_vtg_get_pixel_number(*mode, dst_x); + xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1); writel((ydo << 16) | xdo, vid->regs + VID_VPO); writel((yds << 16) | xds, vid->regs + VID_VPS); - - return 0; } -int sti_vid_disable(struct sti_vid *vid) +void sti_vid_disable(struct sti_vid *vid) { u32 val; @@ -72,8 +81,6 @@ int sti_vid_disable(struct sti_vid *vid) val = readl(vid->regs + VID_CTL); val |= VID_CTL_IGNORE; writel(val, vid->regs + VID_CTL); - - return 0; } static void sti_vid_init(struct sti_vid *vid) diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h index cc680a23cc5d..5dea4791f1d6 100644 --- a/drivers/gpu/drm/sti/sti_vid.h +++ b/drivers/gpu/drm/sti/sti_vid.h @@ -20,8 +20,9 @@ struct sti_vid { int id; }; -int sti_vid_commit(struct sti_vid *vid, struct sti_plane *plane); -int sti_vid_disable(struct sti_vid *vid); +void sti_vid_commit(struct sti_vid *vid, + struct drm_plane_state *state); +void sti_vid_disable(struct sti_vid *vid); struct sti_vid *sti_vid_create(struct device *dev, int id, void __iomem *baseaddr); -- cgit v1.3-6-gb490 From 3d772c4adbf94ce6971be2e9272157f831bccb8f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 31 Jul 2015 10:01:41 +0200 Subject: phy-sun4i-sub: Move vbus-detect helper functions up in the file Move vbus-detect helper functions up in the file, just moving some code around, no functional changes what so ever. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 48 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 5138843ec42d..27ae89e0d3ca 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -294,6 +294,30 @@ static int sun4i_usb_phy_exit(struct phy *_phy) return 0; } +static int sun4i_usb_phy0_get_vbus_det(struct sun4i_usb_phy_data *data) +{ + if (data->vbus_det_gpio) + return gpiod_get_value_cansleep(data->vbus_det_gpio); + + if (data->vbus_power_supply) { + union power_supply_propval val; + int r; + + r = power_supply_get_property(data->vbus_power_supply, + POWER_SUPPLY_PROP_PRESENT, &val); + if (r == 0) + return val.intval; + } + + /* Fallback: report vbus as high */ + return 1; +} + +static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data) +{ + return data->vbus_det_gpio || data->vbus_power_supply; +} + static int sun4i_usb_phy_power_on(struct phy *_phy) { struct sun4i_usb_phy *phy = phy_get_drvdata(_phy); @@ -356,30 +380,6 @@ static struct phy_ops sun4i_usb_phy_ops = { .owner = THIS_MODULE, }; -static int sun4i_usb_phy0_get_vbus_det(struct sun4i_usb_phy_data *data) -{ - if (data->vbus_det_gpio) - return gpiod_get_value_cansleep(data->vbus_det_gpio); - - if (data->vbus_power_supply) { - union power_supply_propval val; - int r; - - r = power_supply_get_property(data->vbus_power_supply, - POWER_SUPPLY_PROP_PRESENT, &val); - if (r == 0) - return val.intval; - } - - /* Fallback: report vbus as high */ - return 1; -} - -static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data) -{ - return data->vbus_det_gpio || data->vbus_power_supply; -} - static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) { struct sun4i_usb_phy_data *data = -- cgit v1.3-6-gb490 From 8083526e0585e23447ac9ea94ca3f6d32d6dee8f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 31 Jul 2015 10:01:42 +0200 Subject: phy-sun4i-usb: Only check vbus-det on power-on on boards with vbus-det data->vbus_det is always 1 on boards without a (working) vbus-det, skip the vbus_det test on such boards. This fixes the sun4i usb phy code never turning on Vbus on such boards. Signed-off-by: Hans de Goede Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-sun4i-usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index 27ae89e0d3ca..e2eb688d82f5 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -328,7 +328,8 @@ static int sun4i_usb_phy_power_on(struct phy *_phy) return 0; /* For phy0 only turn on Vbus if we don't have an ext. Vbus */ - if (phy->index == 0 && data->vbus_det) + if (phy->index == 0 && sun4i_usb_phy0_have_vbus_det(data) && + data->vbus_det) return 0; ret = regulator_enable(phy->vbus); -- cgit v1.3-6-gb490 From 42ad8f6721720513f3569a67b157fcff068aa92d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 5 Jun 2015 08:27:03 +0800 Subject: phy: ulpi_phy: Add const qualifier to ops The ops is never changed in ulpi_phy_create(), so make it const. Signed-off-by: Axel Lin Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/ulpi_phy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/phy/ulpi_phy.h b/drivers/phy/ulpi_phy.h index ac49fb6285ee..f2ebe490a4bc 100644 --- a/drivers/phy/ulpi_phy.h +++ b/drivers/phy/ulpi_phy.h @@ -5,7 +5,7 @@ * and it's controller, which is always the parent. */ static inline struct phy -*ulpi_phy_create(struct ulpi *ulpi, struct phy_ops *ops) +*ulpi_phy_create(struct ulpi *ulpi, const struct phy_ops *ops) { struct phy *phy; int ret; -- cgit v1.3-6-gb490 From 4a9e5ca1a54a3cb4a5f85359f646638cec567607 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jul 2015 15:33:51 +0800 Subject: phy: Constify struct phy_ops variables The phy_ops variables are never modified after initialized in these drivers, so make them const. Signed-off-by: Axel Lin Acked-by: Patrice Chotard Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-armada375-usb2.c | 2 +- drivers/phy/phy-bcm-kona-usb2.c | 2 +- drivers/phy/phy-berlin-sata.c | 2 +- drivers/phy/phy-berlin-usb.c | 2 +- drivers/phy/phy-brcmstb-sata.c | 2 +- drivers/phy/phy-dm816x-usb.c | 2 +- drivers/phy/phy-exynos-dp-video.c | 2 +- drivers/phy/phy-exynos-mipi-video.c | 2 +- drivers/phy/phy-exynos5-usbdrd.c | 2 +- drivers/phy/phy-exynos5250-sata.c | 2 +- drivers/phy/phy-hix5hd2-sata.c | 2 +- drivers/phy/phy-miphy28lp.c | 2 +- drivers/phy/phy-miphy365x.c | 2 +- drivers/phy/phy-mvebu-sata.c | 2 +- drivers/phy/phy-omap-usb2.c | 2 +- drivers/phy/phy-qcom-apq8064-sata.c | 2 +- drivers/phy/phy-qcom-ipq806x-sata.c | 2 +- drivers/phy/phy-qcom-ufs-i.h | 2 +- drivers/phy/phy-qcom-ufs-qmp-14nm.c | 2 +- drivers/phy/phy-qcom-ufs-qmp-20nm.c | 2 +- drivers/phy/phy-qcom-ufs.c | 2 +- drivers/phy/phy-rcar-gen2.c | 2 +- drivers/phy/phy-rockchip-usb.c | 2 +- drivers/phy/phy-samsung-usb2.c | 2 +- drivers/phy/phy-spear1310-miphy.c | 2 +- drivers/phy/phy-spear1340-miphy.c | 2 +- drivers/phy/phy-stih41x-usb.c | 2 +- drivers/phy/phy-sun4i-usb.c | 2 +- drivers/phy/phy-sun9i-usb.c | 2 +- drivers/phy/phy-ti-pipe3.c | 2 +- drivers/phy/phy-tusb1210.c | 2 +- 31 files changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-armada375-usb2.c b/drivers/phy/phy-armada375-usb2.c index 39c7d21f12da..1a3db288c0a9 100644 --- a/drivers/phy/phy-armada375-usb2.c +++ b/drivers/phy/phy-armada375-usb2.c @@ -51,7 +51,7 @@ static int armada375_usb_phy_init(struct phy *phy) return 0; } -static struct phy_ops armada375_usb_phy_ops = { +static const struct phy_ops armada375_usb_phy_ops = { .init = armada375_usb_phy_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-bcm-kona-usb2.c b/drivers/phy/phy-bcm-kona-usb2.c index ef2dc1aab2b9..7b67fe49e30b 100644 --- a/drivers/phy/phy-bcm-kona-usb2.c +++ b/drivers/phy/phy-bcm-kona-usb2.c @@ -91,7 +91,7 @@ static int bcm_kona_usb_phy_power_off(struct phy *gphy) return 0; } -static struct phy_ops ops = { +static const struct phy_ops ops = { .init = bcm_kona_usb_phy_init, .power_on = bcm_kona_usb_phy_power_on, .power_off = bcm_kona_usb_phy_power_off, diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c index 6f3e06d687de..0062027afb1e 100644 --- a/drivers/phy/phy-berlin-sata.c +++ b/drivers/phy/phy-berlin-sata.c @@ -176,7 +176,7 @@ static struct phy *phy_berlin_sata_phy_xlate(struct device *dev, return priv->phys[i]->phy; } -static struct phy_ops phy_berlin_sata_ops = { +static const struct phy_ops phy_berlin_sata_ops = { .power_on = phy_berlin_sata_power_on, .power_off = phy_berlin_sata_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/phy-berlin-usb.c index 0fe0d81c29ee..204ee5952fb3 100644 --- a/drivers/phy/phy-berlin-usb.c +++ b/drivers/phy/phy-berlin-usb.c @@ -147,7 +147,7 @@ static int phy_berlin_usb_power_on(struct phy *phy) return 0; } -static struct phy_ops phy_berlin_usb_ops = { +static const struct phy_ops phy_berlin_usb_ops = { .power_on = phy_berlin_usb_power_on, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-brcmstb-sata.c b/drivers/phy/phy-brcmstb-sata.c index b7e303d28caf..8a2cb16a1937 100644 --- a/drivers/phy/phy-brcmstb-sata.c +++ b/drivers/phy/phy-brcmstb-sata.c @@ -122,7 +122,7 @@ static int brcm_sata_phy_init(struct phy *phy) return 0; } -static struct phy_ops phy_ops_28nm = { +static const struct phy_ops phy_ops_28nm = { .init = brcm_sata_phy_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-dm816x-usb.c b/drivers/phy/phy-dm816x-usb.c index 7b42555ddd51..b4bbef664d20 100644 --- a/drivers/phy/phy-dm816x-usb.c +++ b/drivers/phy/phy-dm816x-usb.c @@ -113,7 +113,7 @@ static int dm816x_usb_phy_init(struct phy *x) return 0; } -static struct phy_ops ops = { +static const struct phy_ops ops = { .init = dm816x_usb_phy_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c index 179cbf9451aa..34b06154e5d9 100644 --- a/drivers/phy/phy-exynos-dp-video.c +++ b/drivers/phy/phy-exynos-dp-video.c @@ -48,7 +48,7 @@ static int exynos_dp_video_phy_power_off(struct phy *phy) EXYNOS5_PHY_ENABLE, 0); } -static struct phy_ops exynos_dp_video_phy_ops = { +static const struct phy_ops exynos_dp_video_phy_ops = { .power_on = exynos_dp_video_phy_power_on, .power_off = exynos_dp_video_phy_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index df7519a39ba0..2a54caba93b4 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c @@ -124,7 +124,7 @@ static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, return state->phys[args->args[0]].phy; } -static struct phy_ops exynos_mipi_video_phy_ops = { +static const struct phy_ops exynos_mipi_video_phy_ops = { .power_on = exynos_mipi_video_phy_power_on, .power_off = exynos_mipi_video_phy_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index d72ef15b0d68..20696f53303f 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c @@ -537,7 +537,7 @@ static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev, return phy_drd->phys[args->args[0]].phy; } -static struct phy_ops exynos5_usbdrd_phy_ops = { +static const struct phy_ops exynos5_usbdrd_phy_ops = { .init = exynos5_usbdrd_phy_init, .exit = exynos5_usbdrd_phy_exit, .power_on = exynos5_usbdrd_phy_power_on, diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/phy-exynos5250-sata.c index bc858cc800a1..60e13afcd9b8 100644 --- a/drivers/phy/phy-exynos5250-sata.c +++ b/drivers/phy/phy-exynos5250-sata.c @@ -154,7 +154,7 @@ static int exynos_sata_phy_init(struct phy *phy) return ret; } -static struct phy_ops exynos_sata_phy_ops = { +static const struct phy_ops exynos_sata_phy_ops = { .init = exynos_sata_phy_init, .power_on = exynos_sata_phy_power_on, .power_off = exynos_sata_phy_power_off, diff --git a/drivers/phy/phy-hix5hd2-sata.c b/drivers/phy/phy-hix5hd2-sata.c index d6b22659cac1..e5ab3aa78b9d 100644 --- a/drivers/phy/phy-hix5hd2-sata.c +++ b/drivers/phy/phy-hix5hd2-sata.c @@ -129,7 +129,7 @@ static int hix5hd2_sata_phy_init(struct phy *phy) return 0; } -static struct phy_ops hix5hd2_sata_phy_ops = { +static const struct phy_ops hix5hd2_sata_phy_ops = { .init = hix5hd2_sata_phy_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c index 677c290f4b14..c47b56b4a2b8 100644 --- a/drivers/phy/phy-miphy28lp.c +++ b/drivers/phy/phy-miphy28lp.c @@ -1132,7 +1132,7 @@ static struct phy *miphy28lp_xlate(struct device *dev, return miphy_phy->phy; } -static struct phy_ops miphy28lp_ops = { +static const struct phy_ops miphy28lp_ops = { .init = miphy28lp_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c index 0ff354d6e183..00a686a073ed 100644 --- a/drivers/phy/phy-miphy365x.c +++ b/drivers/phy/phy-miphy365x.c @@ -510,7 +510,7 @@ static struct phy *miphy365x_xlate(struct device *dev, return miphy_phy->phy; } -static struct phy_ops miphy365x_ops = { +static const struct phy_ops miphy365x_ops = { .init = miphy365x_init, .owner = THIS_MODULE, }; diff --git a/drivers/phy/phy-mvebu-sata.c b/drivers/phy/phy-mvebu-sata.c index 03b94f92e6f1..768ce92e81ce 100644 --- a/drivers/phy/phy-mvebu-sata.c +++ b/drivers/phy/phy-mvebu-sata.c @@ -75,7 +75,7 @@ static int phy_mvebu_sata_power_off(struct phy *phy) return 0; } -static struct phy_ops phy_mvebu_sata_ops = { +static const struct phy_ops phy_mvebu_sata_ops = { .power_on = phy_mvebu_sata_power_on, .power_off = phy_mvebu_sata_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index c1a468686bdc..0fe80589ffbe 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c @@ -137,7 +137,7 @@ static int omap_usb_init(struct phy *x) return 0; } -static struct phy_ops ops = { +static const struct phy_ops ops = { .init = omap_usb_init, .power_on = omap_usb_power_on, .power_off = omap_usb_power_off, diff --git a/drivers/phy/phy-qcom-apq8064-sata.c b/drivers/phy/phy-qcom-apq8064-sata.c index 4b243f7a10e4..69ce2afac015 100644 --- a/drivers/phy/phy-qcom-apq8064-sata.c +++ b/drivers/phy/phy-qcom-apq8064-sata.c @@ -204,7 +204,7 @@ static int qcom_apq8064_sata_phy_exit(struct phy *generic_phy) return 0; } -static struct phy_ops qcom_apq8064_sata_phy_ops = { +static const struct phy_ops qcom_apq8064_sata_phy_ops = { .init = qcom_apq8064_sata_phy_init, .exit = qcom_apq8064_sata_phy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-qcom-ipq806x-sata.c b/drivers/phy/phy-qcom-ipq806x-sata.c index 6f2fe2627916..0ad127cc9298 100644 --- a/drivers/phy/phy-qcom-ipq806x-sata.c +++ b/drivers/phy/phy-qcom-ipq806x-sata.c @@ -126,7 +126,7 @@ static int qcom_ipq806x_sata_phy_exit(struct phy *generic_phy) return 0; } -static struct phy_ops qcom_ipq806x_sata_phy_ops = { +static const struct phy_ops qcom_ipq806x_sata_phy_ops = { .init = qcom_ipq806x_sata_phy_init, .exit = qcom_ipq806x_sata_phy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h index 591a39175e8a..2bd5ce43a724 100644 --- a/drivers/phy/phy-qcom-ufs-i.h +++ b/drivers/phy/phy-qcom-ufs-i.h @@ -150,7 +150,7 @@ int ufs_qcom_phy_remove(struct phy *generic_phy, struct ufs_qcom_phy *ufs_qcom_phy); struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, struct ufs_qcom_phy *common_cfg, - struct phy_ops *ufs_qcom_phy_gen_ops, + const struct phy_ops *ufs_qcom_phy_gen_ops, struct ufs_qcom_phy_specific_ops *phy_spec_ops); int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A, diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/phy-qcom-ufs-qmp-14nm.c index e1eea1b379fc..56631e77c11d 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c @@ -115,7 +115,7 @@ static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common) return err; } -static struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = { +static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = { .init = ufs_qcom_phy_qmp_14nm_init, .exit = ufs_qcom_phy_exit, .power_on = ufs_qcom_phy_power_on, diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c index fde8c876823b..b16ea77d07b9 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -171,7 +171,7 @@ static int ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common) return err; } -static struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = { +static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = { .init = ufs_qcom_phy_qmp_20nm_init, .exit = ufs_qcom_phy_exit, .power_on = ufs_qcom_phy_power_on, diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c index f9c618f0ab6e..49a1ed0cef56 100644 --- a/drivers/phy/phy-qcom-ufs.c +++ b/drivers/phy/phy-qcom-ufs.c @@ -77,7 +77,7 @@ EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate); struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, struct ufs_qcom_phy *common_cfg, - struct phy_ops *ufs_qcom_phy_gen_ops, + const struct phy_ops *ufs_qcom_phy_gen_ops, struct ufs_qcom_phy_specific_ops *phy_spec_ops) { int err; diff --git a/drivers/phy/phy-rcar-gen2.c b/drivers/phy/phy-rcar-gen2.c index 39d9b2995435..6e0d9fa8e1d1 100644 --- a/drivers/phy/phy-rcar-gen2.c +++ b/drivers/phy/phy-rcar-gen2.c @@ -184,7 +184,7 @@ static int rcar_gen2_phy_power_off(struct phy *p) return 0; } -static struct phy_ops rcar_gen2_phy_ops = { +static const struct phy_ops rcar_gen2_phy_ops = { .init = rcar_gen2_phy_init, .exit = rcar_gen2_phy_exit, .power_on = rcar_gen2_phy_power_on, diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c index bf78721b58f4..5a5c073e72fe 100644 --- a/drivers/phy/phy-rockchip-usb.c +++ b/drivers/phy/phy-rockchip-usb.c @@ -84,7 +84,7 @@ static int rockchip_usb_phy_power_on(struct phy *_phy) return 0; } -static struct phy_ops ops = { +static const struct phy_ops ops = { .power_on = rockchip_usb_phy_power_on, .power_off = rockchip_usb_phy_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c index 55b6994932e3..f278a9c547e1 100644 --- a/drivers/phy/phy-samsung-usb2.c +++ b/drivers/phy/phy-samsung-usb2.c @@ -71,7 +71,7 @@ static int samsung_usb2_phy_power_off(struct phy *phy) return 0; } -static struct phy_ops samsung_usb2_phy_ops = { +static const struct phy_ops samsung_usb2_phy_ops = { .power_on = samsung_usb2_phy_power_on, .power_off = samsung_usb2_phy_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-spear1310-miphy.c b/drivers/phy/phy-spear1310-miphy.c index 45d0005b2203..ed67e98e54ca 100644 --- a/drivers/phy/phy-spear1310-miphy.c +++ b/drivers/phy/phy-spear1310-miphy.c @@ -179,7 +179,7 @@ static const struct of_device_id spear1310_miphy_of_match[] = { }; MODULE_DEVICE_TABLE(of, spear1310_miphy_of_match); -static struct phy_ops spear1310_miphy_ops = { +static const struct phy_ops spear1310_miphy_ops = { .init = spear1310_miphy_init, .exit = spear1310_miphy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-spear1340-miphy.c b/drivers/phy/phy-spear1340-miphy.c index 494240da4a39..97280c0cf612 100644 --- a/drivers/phy/phy-spear1340-miphy.c +++ b/drivers/phy/phy-spear1340-miphy.c @@ -189,7 +189,7 @@ static const struct of_device_id spear1340_miphy_of_match[] = { }; MODULE_DEVICE_TABLE(of, spear1340_miphy_of_match); -static struct phy_ops spear1340_miphy_ops = { +static const struct phy_ops spear1340_miphy_ops = { .init = spear1340_miphy_init, .exit = spear1340_miphy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-stih41x-usb.c b/drivers/phy/phy-stih41x-usb.c index c093b472b57d..0ac74639ad02 100644 --- a/drivers/phy/phy-stih41x-usb.c +++ b/drivers/phy/phy-stih41x-usb.c @@ -112,7 +112,7 @@ static int stih41x_usb_phy_power_off(struct phy *phy) return 0; } -static struct phy_ops stih41x_usb_phy_ops = { +static const struct phy_ops stih41x_usb_phy_ops = { .init = stih41x_usb_phy_init, .power_on = stih41x_usb_phy_power_on, .power_off = stih41x_usb_phy_power_off, diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index e2eb688d82f5..623c7143152e 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -373,7 +373,7 @@ void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled) sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2); } -static struct phy_ops sun4i_usb_phy_ops = { +static const struct phy_ops sun4i_usb_phy_ops = { .init = sun4i_usb_phy_init, .exit = sun4i_usb_phy_exit, .power_on = sun4i_usb_phy_power_on, diff --git a/drivers/phy/phy-sun9i-usb.c b/drivers/phy/phy-sun9i-usb.c index 0095914a662c..ac4f31abefe3 100644 --- a/drivers/phy/phy-sun9i-usb.c +++ b/drivers/phy/phy-sun9i-usb.c @@ -114,7 +114,7 @@ static int sun9i_usb_phy_exit(struct phy *_phy) return 0; } -static struct phy_ops sun9i_usb_phy_ops = { +static const struct phy_ops sun9i_usb_phy_ops = { .init = sun9i_usb_phy_init, .exit = sun9i_usb_phy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 53f295c1bab1..2038f1945f2c 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -279,7 +279,7 @@ static int ti_pipe3_exit(struct phy *x) return 0; } -static struct phy_ops ops = { +static const struct phy_ops ops = { .init = ti_pipe3_init, .exit = ti_pipe3_exit, .power_on = ti_pipe3_power_on, diff --git a/drivers/phy/phy-tusb1210.c b/drivers/phy/phy-tusb1210.c index 07efdd318bdc..2535d792d57a 100644 --- a/drivers/phy/phy-tusb1210.c +++ b/drivers/phy/phy-tusb1210.c @@ -53,7 +53,7 @@ static int tusb1210_power_off(struct phy *phy) return 0; } -static struct phy_ops phy_ops = { +static const struct phy_ops phy_ops = { .power_on = tusb1210_power_on, .power_off = tusb1210_power_off, .owner = THIS_MODULE, -- cgit v1.3-6-gb490 From 0cdbf727167a2fcc9ba2aaea98e2a76124ba072e Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 20 Jul 2015 17:33:24 -0500 Subject: iommu/omap: Remove all module references The OMAP IOMMU driver has been adapted to the IOMMU framework for a while now, and it does not support being built as a module anymore. So, remove all the module references from the OMAP IOMMU driver. While at it, also relocate a comment around the subsys_initcall to avoid a checkpatch strict warning about using a blank line after function/struct/union/enum declarations. Signed-off-by: Suman Anna Reviewed-by: Laurent Pinchart Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index a22c33d6a486..eeecfc4073af 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include @@ -1089,7 +1088,6 @@ static const struct of_device_id omap_iommu_of_match[] = { { .compatible = "ti,dra7-iommu" }, {}, }; -MODULE_DEVICE_TABLE(of, omap_iommu_of_match); static struct platform_driver omap_iommu_driver = { .probe = omap_iommu_probe, @@ -1405,20 +1403,5 @@ static int __init omap_iommu_init(void) return platform_driver_register(&omap_iommu_driver); } -/* must be ready before omap3isp is probed */ subsys_initcall(omap_iommu_init); - -static void __exit omap_iommu_exit(void) -{ - kmem_cache_destroy(iopte_cachep); - - platform_driver_unregister(&omap_iommu_driver); - - omap_iommu_debugfs_exit(); -} -module_exit(omap_iommu_exit); - -MODULE_DESCRIPTION("omap iommu: tlb and pagetable primitives"); -MODULE_ALIAS("platform:omap-iommu"); -MODULE_AUTHOR("Hiroshi DOYU, Paul Mundt and Toshihiro Kobayashi"); -MODULE_LICENSE("GPL v2"); +/* must be ready before omap3isp is probed */ -- cgit v1.3-6-gb490 From 69c2c196328e73d3091dd0be89ab4b0c2af4b210 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 20 Jul 2015 17:33:25 -0500 Subject: iommu/omap: Move debugfs functions to omap-iommu-debug.c The main OMAP IOMMU driver file has some helper functions used by the OMAP IOMMU debugfs functionality, and there is already a dedicated source file omap-iommu-debug.c dealing with these debugfs routines. Move all these functions to the omap-iommu-debug.c file, so that all the debugfs related routines are in one place. The move required exposing some new functions and moving some definitions to the internal omap-iommu.h header file. Signed-off-by: Suman Anna Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu-debug.c | 111 +++++++++++++++++++++++++++++ drivers/iommu/omap-iommu.c | 148 +-------------------------------------- drivers/iommu/omap-iommu.h | 28 ++++++-- 3 files changed, 137 insertions(+), 150 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c index f3d20a2039d2..b4b96db37e6a 100644 --- a/drivers/iommu/omap-iommu-debug.c +++ b/drivers/iommu/omap-iommu-debug.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,59 @@ static inline bool is_omap_iommu_detached(struct omap_iommu *obj) return !obj->domain; } +#define pr_reg(name) \ + do { \ + ssize_t bytes; \ + const char *str = "%20s: %08x\n"; \ + const int maxcol = 32; \ + bytes = snprintf(p, maxcol, str, __stringify(name), \ + iommu_read_reg(obj, MMU_##name)); \ + p += bytes; \ + len -= bytes; \ + if (len < maxcol) \ + goto out; \ + } while (0) + +static ssize_t +omap2_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len) +{ + char *p = buf; + + pr_reg(REVISION); + pr_reg(IRQSTATUS); + pr_reg(IRQENABLE); + pr_reg(WALKING_ST); + pr_reg(CNTL); + pr_reg(FAULT_AD); + pr_reg(TTB); + pr_reg(LOCK); + pr_reg(LD_TLB); + pr_reg(CAM); + pr_reg(RAM); + pr_reg(GFLUSH); + pr_reg(FLUSH_ENTRY); + pr_reg(READ_CAM); + pr_reg(READ_RAM); + pr_reg(EMU_FAULT_AD); +out: + return p - buf; +} + +static ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, + ssize_t bytes) +{ + if (!obj || !buf) + return -EINVAL; + + pm_runtime_get_sync(obj->dev); + + bytes = omap2_iommu_dump_ctx(obj, buf, bytes); + + pm_runtime_put_sync(obj->dev); + + return bytes; +} + static ssize_t debug_read_regs(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -55,6 +109,63 @@ static ssize_t debug_read_regs(struct file *file, char __user *userbuf, return bytes; } +static int +__dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num) +{ + int i; + struct iotlb_lock saved; + struct cr_regs tmp; + struct cr_regs *p = crs; + + pm_runtime_get_sync(obj->dev); + iotlb_lock_get(obj, &saved); + + for_each_iotlb_cr(obj, num, i, tmp) { + if (!iotlb_cr_valid(&tmp)) + continue; + *p++ = tmp; + } + + iotlb_lock_set(obj, &saved); + pm_runtime_put_sync(obj->dev); + + return p - crs; +} + +static ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr, + char *buf) +{ + char *p = buf; + + /* FIXME: Need more detail analysis of cam/ram */ + p += sprintf(p, "%08x %08x %01x\n", cr->cam, cr->ram, + (cr->cam & MMU_CAM_P) ? 1 : 0); + + return p - buf; +} + +static size_t omap_dump_tlb_entries(struct omap_iommu *obj, char *buf, + ssize_t bytes) +{ + int i, num; + struct cr_regs *cr; + char *p = buf; + + num = bytes / sizeof(*cr); + num = min(obj->nr_tlb_entries, num); + + cr = kcalloc(num, sizeof(*cr), GFP_KERNEL); + if (!cr) + return 0; + + num = __dump_tlb_entries(obj, cr, num); + for (i = 0; i < num; i++) + p += iotlb_dump_cr(obj, cr + i, p); + kfree(cr); + + return p - buf; +} + static ssize_t debug_read_tlb(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index eeecfc4073af..0fc00f31c39d 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -37,11 +37,6 @@ #define to_iommu(dev) \ ((struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))) -#define for_each_iotlb_cr(obj, n, __i, cr) \ - for (__i = 0; \ - (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true); \ - __i++) - /* bitmap of the page sizes currently supported */ #define OMAP_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M) @@ -71,11 +66,6 @@ struct omap_iommu_domain { #define MMU_LOCK_VICT(x) \ ((x & MMU_LOCK_VICT_MASK) >> MMU_LOCK_VICT_SHIFT) -struct iotlb_lock { - short base; - short vict; -}; - static struct platform_driver omap_iommu_driver; static struct kmem_cache *iopte_cachep; @@ -212,14 +202,6 @@ static void iommu_disable(struct omap_iommu *obj) /* * TLB operations */ -static inline int iotlb_cr_valid(struct cr_regs *cr) -{ - if (!cr) - return -EINVAL; - - return cr->cam & MMU_CAM_V; -} - static u32 iotlb_cr_to_virt(struct cr_regs *cr) { u32 page_size = cr->cam & MMU_CAM_PGSZ_MASK; @@ -259,7 +241,7 @@ static u32 iommu_report_fault(struct omap_iommu *obj, u32 *da) return status; } -static void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l) +void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l) { u32 val; @@ -267,10 +249,9 @@ static void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l) l->base = MMU_LOCK_BASE(val); l->vict = MMU_LOCK_VICT(val); - } -static void iotlb_lock_set(struct omap_iommu *obj, struct iotlb_lock *l) +void iotlb_lock_set(struct omap_iommu *obj, struct iotlb_lock *l) { u32 val; @@ -296,7 +277,7 @@ static void iotlb_load_cr(struct omap_iommu *obj, struct cr_regs *cr) } /* only used in iotlb iteration for-loop */ -static struct cr_regs __iotlb_read_cr(struct omap_iommu *obj, int n) +struct cr_regs __iotlb_read_cr(struct omap_iommu *obj, int n) { struct cr_regs cr; struct iotlb_lock l; @@ -467,129 +448,6 @@ static void flush_iotlb_all(struct omap_iommu *obj) pm_runtime_put_sync(obj->dev); } -#ifdef CONFIG_OMAP_IOMMU_DEBUG - -#define pr_reg(name) \ - do { \ - ssize_t bytes; \ - const char *str = "%20s: %08x\n"; \ - const int maxcol = 32; \ - bytes = snprintf(p, maxcol, str, __stringify(name), \ - iommu_read_reg(obj, MMU_##name)); \ - p += bytes; \ - len -= bytes; \ - if (len < maxcol) \ - goto out; \ - } while (0) - -static ssize_t -omap2_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len) -{ - char *p = buf; - - pr_reg(REVISION); - pr_reg(IRQSTATUS); - pr_reg(IRQENABLE); - pr_reg(WALKING_ST); - pr_reg(CNTL); - pr_reg(FAULT_AD); - pr_reg(TTB); - pr_reg(LOCK); - pr_reg(LD_TLB); - pr_reg(CAM); - pr_reg(RAM); - pr_reg(GFLUSH); - pr_reg(FLUSH_ENTRY); - pr_reg(READ_CAM); - pr_reg(READ_RAM); - pr_reg(EMU_FAULT_AD); -out: - return p - buf; -} - -ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t bytes) -{ - if (!obj || !buf) - return -EINVAL; - - pm_runtime_get_sync(obj->dev); - - bytes = omap2_iommu_dump_ctx(obj, buf, bytes); - - pm_runtime_put_sync(obj->dev); - - return bytes; -} - -static int -__dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num) -{ - int i; - struct iotlb_lock saved; - struct cr_regs tmp; - struct cr_regs *p = crs; - - pm_runtime_get_sync(obj->dev); - iotlb_lock_get(obj, &saved); - - for_each_iotlb_cr(obj, num, i, tmp) { - if (!iotlb_cr_valid(&tmp)) - continue; - *p++ = tmp; - } - - iotlb_lock_set(obj, &saved); - pm_runtime_put_sync(obj->dev); - - return p - crs; -} - -/** - * iotlb_dump_cr - Dump an iommu tlb entry into buf - * @obj: target iommu - * @cr: contents of cam and ram register - * @buf: output buffer - **/ -static ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr, - char *buf) -{ - char *p = buf; - - /* FIXME: Need more detail analysis of cam/ram */ - p += sprintf(p, "%08x %08x %01x\n", cr->cam, cr->ram, - (cr->cam & MMU_CAM_P) ? 1 : 0); - - return p - buf; -} - -/** - * omap_dump_tlb_entries - dump cr arrays to given buffer - * @obj: target iommu - * @buf: output buffer - **/ -size_t omap_dump_tlb_entries(struct omap_iommu *obj, char *buf, ssize_t bytes) -{ - int i, num; - struct cr_regs *cr; - char *p = buf; - - num = bytes / sizeof(*cr); - num = min(obj->nr_tlb_entries, num); - - cr = kcalloc(num, sizeof(*cr), GFP_KERNEL); - if (!cr) - return 0; - - num = __dump_tlb_entries(obj, cr, num); - for (i = 0; i < num; i++) - p += iotlb_dump_cr(obj, cr + i, p); - kfree(cr); - - return p - buf; -} - -#endif /* CONFIG_OMAP_IOMMU_DEBUG */ - /* * H/W pagetable operations */ diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h index d736630df3c8..b6cc90b2ba41 100644 --- a/drivers/iommu/omap-iommu.h +++ b/drivers/iommu/omap-iommu.h @@ -13,6 +13,11 @@ #ifndef _OMAP_IOMMU_H #define _OMAP_IOMMU_H +#define for_each_iotlb_cr(obj, n, __i, cr) \ + for (__i = 0; \ + (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true); \ + __i++) + struct iotlb_entry { u32 da; u32 pa; @@ -65,6 +70,11 @@ struct cr_regs { }; }; +struct iotlb_lock { + short base; + short vict; +}; + /** * dev_to_omap_iommu() - retrieves an omap iommu object from a user device * @dev: iommu client device @@ -190,12 +200,12 @@ static inline struct omap_iommu *dev_to_omap_iommu(struct device *dev) /* * global functions */ -#ifdef CONFIG_OMAP_IOMMU_DEBUG -extern ssize_t -omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len); -extern size_t -omap_dump_tlb_entries(struct omap_iommu *obj, char *buf, ssize_t len); +struct cr_regs __iotlb_read_cr(struct omap_iommu *obj, int n); +void iotlb_lock_get(struct omap_iommu *obj, struct iotlb_lock *l); +void iotlb_lock_set(struct omap_iommu *obj, struct iotlb_lock *l); + +#ifdef CONFIG_OMAP_IOMMU_DEBUG void omap_iommu_debugfs_init(void); void omap_iommu_debugfs_exit(void); @@ -222,4 +232,12 @@ static inline void iommu_write_reg(struct omap_iommu *obj, u32 val, size_t offs) __raw_writel(val, obj->regbase + offs); } +static inline int iotlb_cr_valid(struct cr_regs *cr) +{ + if (!cr) + return -EINVAL; + + return cr->cam & MMU_CAM_V; +} + #endif /* _OMAP_IOMMU_H */ -- cgit v1.3-6-gb490 From ad8e29a0804494bff5f0059df3805423ed2020b8 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 20 Jul 2015 17:33:26 -0500 Subject: iommu/omap: Protect omap-iopgtable.h against double inclusion Protect the omap-pgtable.h header against double inclusion in source code by using the standard include guard mechanism. Signed-off-by: Suman Anna Reviewed-by: Laurent Pinchart Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iopgtable.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h index f891683e3f05..bfde5405f514 100644 --- a/drivers/iommu/omap-iopgtable.h +++ b/drivers/iommu/omap-iopgtable.h @@ -10,6 +10,9 @@ * published by the Free Software Foundation. */ +#ifndef _OMAP_IOPGTABLE_H +#define _OMAP_IOPGTABLE_H + /* * "L2 table" address mask and size definitions. */ @@ -93,3 +96,5 @@ static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask) /* to find an entry in the second-level page table. */ #define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1)) #define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da)) + +#endif /* _OMAP_IOPGTABLE_H */ -- cgit v1.3-6-gb490 From dc308f9f92b084a25989fd2002fac06cbf4a73d4 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 20 Jul 2015 17:33:27 -0500 Subject: iommu/omap: Remove unused union fields There are couple of unions defined in the structures iotlb_entry and cr_regs. There are no usage/references to some of these union fields in the code, so clean them up and simplify the structures. Signed-off-by: Suman Anna Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu.h | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h index b6cc90b2ba41..5b98408c18bf 100644 --- a/drivers/iommu/omap-iommu.h +++ b/drivers/iommu/omap-iommu.h @@ -22,12 +22,7 @@ struct iotlb_entry { u32 da; u32 pa; u32 pgsz, prsvd, valid; - union { - u16 ap; - struct { - u32 endian, elsz, mixed; - }; - }; + u32 endian, elsz, mixed; }; struct omap_iommu { @@ -54,20 +49,8 @@ struct omap_iommu { }; struct cr_regs { - union { - struct { - u16 cam_l; - u16 cam_h; - }; - u32 cam; - }; - union { - struct { - u16 ram_l; - u16 ram_h; - }; - u32 ram; - }; + u32 cam; + u32 ram; }; struct iotlb_lock { -- cgit v1.3-6-gb490 From 5b39a37abc007542995506ad0d8e4c3991e6970a Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 20 Jul 2015 17:33:28 -0500 Subject: iommu/omap: Remove trailing semi-colon from a macro Remove the trailing semi-colon in the DEBUG_FOPS_RO macro definition. This fixes the checking warning, "WARNING: macros should not use a trailing semicolon" Signed-off-by: Suman Anna Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu-debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c index b4b96db37e6a..e9f116f18531 100644 --- a/drivers/iommu/omap-iommu-debug.c +++ b/drivers/iommu/omap-iommu-debug.c @@ -265,7 +265,7 @@ static int debug_read_pagetable(struct seq_file *s, void *data) .open = simple_open, \ .read = debug_read_##name, \ .llseek = generic_file_llseek, \ - }; + } DEBUG_FOPS_RO(regs); DEBUG_FOPS_RO(tlb); -- cgit v1.3-6-gb490 From 99ee98d6ac964f1a2412d9fe08e577aa4f13905d Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 20 Jul 2015 17:33:29 -0500 Subject: iommu/omap: Remove unnecessary error traces on alloc failures Fix couple of checkpatch warnings of the type, "WARNING: Possible unnecessary 'out of memory' message" Signed-off-by: Suman Anna Reviewed-by: Laurent Pinchart Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 0fc00f31c39d..4328d9855edb 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1093,16 +1093,12 @@ static struct iommu_domain *omap_iommu_domain_alloc(unsigned type) return NULL; omap_domain = kzalloc(sizeof(*omap_domain), GFP_KERNEL); - if (!omap_domain) { - pr_err("kzalloc failed\n"); + if (!omap_domain) goto out; - } omap_domain->pgtable = kzalloc(IOPGD_TABLE_SIZE, GFP_KERNEL); - if (!omap_domain->pgtable) { - pr_err("kzalloc failed\n"); + if (!omap_domain->pgtable) goto fail_nomem; - } /* * should never fail, but please keep this around to ensure -- cgit v1.3-6-gb490 From 5ff98fa68c88d7babf96b7df7c713aaf2ed6558a Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 20 Jul 2015 17:33:30 -0500 Subject: iommu/omap: Use BIT(x) macros in omap-iopgtable.h Switch to using the BIT(x) macros in omap-iopgtable.h where possible. This eliminates the following checkpatch check warning: "CHECK: Prefer using the BIT macro" A couple of macros that used zero bit shifting are defined directly to avoid the above warning on one of the macros. Signed-off-by: Suman Anna Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iopgtable.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h index bfde5405f514..01a315227bf0 100644 --- a/drivers/iommu/omap-iopgtable.h +++ b/drivers/iommu/omap-iopgtable.h @@ -13,25 +13,27 @@ #ifndef _OMAP_IOPGTABLE_H #define _OMAP_IOPGTABLE_H +#include + /* * "L2 table" address mask and size definitions. */ #define IOPGD_SHIFT 20 -#define IOPGD_SIZE (1UL << IOPGD_SHIFT) +#define IOPGD_SIZE BIT(IOPGD_SHIFT) #define IOPGD_MASK (~(IOPGD_SIZE - 1)) /* * "section" address mask and size definitions. */ #define IOSECTION_SHIFT 20 -#define IOSECTION_SIZE (1UL << IOSECTION_SHIFT) +#define IOSECTION_SIZE BIT(IOSECTION_SHIFT) #define IOSECTION_MASK (~(IOSECTION_SIZE - 1)) /* * "supersection" address mask and size definitions. */ #define IOSUPER_SHIFT 24 -#define IOSUPER_SIZE (1UL << IOSUPER_SHIFT) +#define IOSUPER_SIZE BIT(IOSUPER_SHIFT) #define IOSUPER_MASK (~(IOSUPER_SIZE - 1)) #define PTRS_PER_IOPGD (1UL << (32 - IOPGD_SHIFT)) @@ -41,14 +43,14 @@ * "small page" address mask and size definitions. */ #define IOPTE_SHIFT 12 -#define IOPTE_SIZE (1UL << IOPTE_SHIFT) +#define IOPTE_SIZE BIT(IOPTE_SHIFT) #define IOPTE_MASK (~(IOPTE_SIZE - 1)) /* * "large page" address mask and size definitions. */ #define IOLARGE_SHIFT 16 -#define IOLARGE_SIZE (1UL << IOLARGE_SHIFT) +#define IOLARGE_SIZE BIT(IOLARGE_SHIFT) #define IOLARGE_MASK (~(IOLARGE_SIZE - 1)) #define PTRS_PER_IOPTE (1UL << (IOPGD_SHIFT - IOPTE_SHIFT)) @@ -72,16 +74,16 @@ static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask) /* * some descriptor attributes. */ -#define IOPGD_TABLE (1 << 0) -#define IOPGD_SECTION (2 << 0) -#define IOPGD_SUPER (1 << 18 | 2 << 0) +#define IOPGD_TABLE (1) +#define IOPGD_SECTION (2) +#define IOPGD_SUPER (BIT(18) | IOPGD_SECTION) #define iopgd_is_table(x) (((x) & 3) == IOPGD_TABLE) #define iopgd_is_section(x) (((x) & (1 << 18 | 3)) == IOPGD_SECTION) #define iopgd_is_super(x) (((x) & (1 << 18 | 3)) == IOPGD_SUPER) -#define IOPTE_SMALL (2 << 0) -#define IOPTE_LARGE (1 << 0) +#define IOPTE_SMALL (2) +#define IOPTE_LARGE (1) #define iopte_is_small(x) (((x) & 2) == IOPTE_SMALL) #define iopte_is_large(x) (((x) & 3) == IOPTE_LARGE) -- cgit v1.3-6-gb490 From eb642a3f5afdb13aa2b7ba0bda314b0d2b62165d Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 20 Jul 2015 17:33:31 -0500 Subject: iommu/omap: Use BIT(x) macros in omap-iommu.h Switch to using the BIT(x) macros in omap-iommu.h where possible. This eliminates the following checkpatch check warning: "CHECK: Prefer using the BIT macro" A couple of the warnings were ignored for better readability of the bit-shift for the different values. Signed-off-by: Suman Anna Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu.h | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/omap-iommu.h b/drivers/iommu/omap-iommu.h index 5b98408c18bf..a656df2f9e03 100644 --- a/drivers/iommu/omap-iommu.h +++ b/drivers/iommu/omap-iommu.h @@ -13,6 +13,8 @@ #ifndef _OMAP_IOMMU_H #define _OMAP_IOMMU_H +#include + #define for_each_iotlb_cr(obj, n, __i, cr) \ for (__i = 0; \ (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true); \ @@ -96,11 +98,11 @@ static inline struct omap_iommu *dev_to_omap_iommu(struct device *dev) * MMU Register bit definitions */ /* IRQSTATUS & IRQENABLE */ -#define MMU_IRQ_MULTIHITFAULT (1 << 4) -#define MMU_IRQ_TABLEWALKFAULT (1 << 3) -#define MMU_IRQ_EMUMISS (1 << 2) -#define MMU_IRQ_TRANSLATIONFAULT (1 << 1) -#define MMU_IRQ_TLBMISS (1 << 0) +#define MMU_IRQ_MULTIHITFAULT BIT(4) +#define MMU_IRQ_TABLEWALKFAULT BIT(3) +#define MMU_IRQ_EMUMISS BIT(2) +#define MMU_IRQ_TRANSLATIONFAULT BIT(1) +#define MMU_IRQ_TLBMISS BIT(0) #define __MMU_IRQ_FAULT \ (MMU_IRQ_MULTIHITFAULT | MMU_IRQ_EMUMISS | MMU_IRQ_TRANSLATIONFAULT) @@ -112,16 +114,16 @@ static inline struct omap_iommu *dev_to_omap_iommu(struct device *dev) /* MMU_CNTL */ #define MMU_CNTL_SHIFT 1 #define MMU_CNTL_MASK (7 << MMU_CNTL_SHIFT) -#define MMU_CNTL_EML_TLB (1 << 3) -#define MMU_CNTL_TWL_EN (1 << 2) -#define MMU_CNTL_MMU_EN (1 << 1) +#define MMU_CNTL_EML_TLB BIT(3) +#define MMU_CNTL_TWL_EN BIT(2) +#define MMU_CNTL_MMU_EN BIT(1) /* CAM */ #define MMU_CAM_VATAG_SHIFT 12 #define MMU_CAM_VATAG_MASK \ ((~0UL >> MMU_CAM_VATAG_SHIFT) << MMU_CAM_VATAG_SHIFT) -#define MMU_CAM_P (1 << 3) -#define MMU_CAM_V (1 << 2) +#define MMU_CAM_P BIT(3) +#define MMU_CAM_V BIT(2) #define MMU_CAM_PGSZ_MASK 3 #define MMU_CAM_PGSZ_1M (0 << 0) #define MMU_CAM_PGSZ_64K (1 << 0) @@ -134,9 +136,9 @@ static inline struct omap_iommu *dev_to_omap_iommu(struct device *dev) ((~0UL >> MMU_RAM_PADDR_SHIFT) << MMU_RAM_PADDR_SHIFT) #define MMU_RAM_ENDIAN_SHIFT 9 -#define MMU_RAM_ENDIAN_MASK (1 << MMU_RAM_ENDIAN_SHIFT) +#define MMU_RAM_ENDIAN_MASK BIT(MMU_RAM_ENDIAN_SHIFT) #define MMU_RAM_ENDIAN_LITTLE (0 << MMU_RAM_ENDIAN_SHIFT) -#define MMU_RAM_ENDIAN_BIG (1 << MMU_RAM_ENDIAN_SHIFT) +#define MMU_RAM_ENDIAN_BIG BIT(MMU_RAM_ENDIAN_SHIFT) #define MMU_RAM_ELSZ_SHIFT 7 #define MMU_RAM_ELSZ_MASK (3 << MMU_RAM_ELSZ_SHIFT) @@ -145,7 +147,7 @@ static inline struct omap_iommu *dev_to_omap_iommu(struct device *dev) #define MMU_RAM_ELSZ_32 (2 << MMU_RAM_ELSZ_SHIFT) #define MMU_RAM_ELSZ_NONE (3 << MMU_RAM_ELSZ_SHIFT) #define MMU_RAM_MIXED_SHIFT 6 -#define MMU_RAM_MIXED_MASK (1 << MMU_RAM_MIXED_SHIFT) +#define MMU_RAM_MIXED_MASK BIT(MMU_RAM_MIXED_SHIFT) #define MMU_RAM_MIXED MMU_RAM_MIXED_MASK #define MMU_GP_REG_BUS_ERR_BACK_EN 0x1 -- cgit v1.3-6-gb490 From 5835b6a64ce39434d5cc9857769c73982d488b42 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Mon, 20 Jul 2015 17:33:32 -0500 Subject: iommu/omap: Align code with open parenthesis Fix all the occurrences of the following check warning generated with the checkpatch --strict option: "CHECK: Alignment should match open parenthesis" Signed-off-by: Suman Anna Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 4328d9855edb..36d0033c2ccb 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -787,14 +787,14 @@ static irqreturn_t iommu_fault_handler(int irq, void *data) if (!iopgd_is_table(*iopgd)) { dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:px%08x\n", - obj->name, errs, da, iopgd, *iopgd); + obj->name, errs, da, iopgd, *iopgd); return IRQ_NONE; } iopte = iopte_offset(iopgd, da); dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x pte:0x%p *pte:0x%08x\n", - obj->name, errs, da, iopgd, *iopgd, iopte, *iopte); + obj->name, errs, da, iopgd, *iopgd, iopte, *iopte); return IRQ_NONE; } @@ -820,9 +820,8 @@ static struct omap_iommu *omap_iommu_attach(const char *name, u32 *iopgd) struct device *dev; struct omap_iommu *obj; - dev = driver_find_device(&omap_iommu_driver.driver, NULL, - (void *)name, - device_match_by_alias); + dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name, + device_match_by_alias); if (!dev) return ERR_PTR(-ENODEV); @@ -977,7 +976,7 @@ static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, int pgsz) } static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, - phys_addr_t pa, size_t bytes, int prot) + phys_addr_t pa, size_t bytes, int prot) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); struct omap_iommu *oiommu = omap_domain->iommu_dev; @@ -1004,7 +1003,7 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, } static size_t omap_iommu_unmap(struct iommu_domain *domain, unsigned long da, - size_t size) + size_t size) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); struct omap_iommu *oiommu = omap_domain->iommu_dev; @@ -1055,7 +1054,7 @@ out: } static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain, - struct device *dev) + struct device *dev) { struct omap_iommu *oiommu = dev_to_omap_iommu(dev); struct omap_iommu_arch_data *arch_data = dev->archdata.iommu; @@ -1076,7 +1075,7 @@ static void _omap_iommu_detach_dev(struct omap_iommu_domain *omap_domain, } static void omap_iommu_detach_dev(struct iommu_domain *domain, - struct device *dev) + struct device *dev) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); @@ -1137,7 +1136,7 @@ static void omap_iommu_domain_free(struct iommu_domain *domain) } static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain, - dma_addr_t da) + dma_addr_t da) { struct omap_iommu_domain *omap_domain = to_omap_domain(domain); struct omap_iommu *oiommu = omap_domain->iommu_dev; @@ -1154,7 +1153,7 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain, ret = omap_iommu_translate(*pte, da, IOLARGE_MASK); else dev_err(dev, "bogus pte 0x%x, da 0x%llx", *pte, - (unsigned long long)da); + (unsigned long long)da); } else { if (iopgd_is_section(*pgd)) ret = omap_iommu_translate(*pgd, da, IOSECTION_MASK); @@ -1162,7 +1161,7 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain, ret = omap_iommu_translate(*pgd, da, IOSUPER_MASK); else dev_err(dev, "bogus pgd 0x%x, da 0x%llx", *pgd, - (unsigned long long)da); + (unsigned long long)da); } return ret; -- cgit v1.3-6-gb490 From 7b0ce727bf7ac5240a433109f53bf78788f9159b Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 22 Jul 2015 18:47:00 +0100 Subject: of: iommu: Silence misleading warning Printing "IOMMU is currently not supported for PCI" for every PCI device probed on a DT-based system proves to be both irritatingly noisy and confusing to users who have misinterpreted it to mean they can no longer use VFIO device assignment. Since configuring DMA masks for PCI devices via of_dma_configure() has not in fact changed anything with regard to IOMMUs there really is nothing to warn about here; shut it up. Signed-off-by: Robin Murphy Acked-by: Marc Zyngier Signed-off-by: Joerg Roedel --- drivers/iommu/of_iommu.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 43429ab62228..60ba238090d9 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -141,10 +141,12 @@ struct iommu_ops *of_iommu_configure(struct device *dev, struct iommu_ops *ops = NULL; int idx = 0; - if (dev_is_pci(dev)) { - dev_err(dev, "IOMMU is currently not supported for PCI\n"); + /* + * We can't do much for PCI devices without knowing how + * device IDs are wired up from the PCI bus to the IOMMU. + */ + if (dev_is_pci(dev)) return NULL; - } /* * We don't currently walk up the tree looking for a parent IOMMU. -- cgit v1.3-6-gb490 From 2439d4aa9247f4c94351d0cf7d75c16146785eb8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 24 Jul 2015 16:27:57 -0700 Subject: iommu/vt-d: Avoid format string leaks into iommu_device_create This makes sure it won't be possible to accidentally leak format strings into iommu device names. Current name allocations are safe, but this makes the "%s" explicit. Signed-off-by: Kees Cook Signed-off-by: Joerg Roedel --- drivers/iommu/dmar.c | 2 +- drivers/iommu/intel-iommu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index c9db04d4ef39..8757f8dfc4e5 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1068,7 +1068,7 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd) if (intel_iommu_enabled) iommu->iommu_dev = iommu_device_create(NULL, iommu, intel_iommu_groups, - iommu->name); + "%s", iommu->name); return 0; diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 0649b94f5958..0be23c589d3b 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -4533,7 +4533,7 @@ int __init intel_iommu_init(void) for_each_active_iommu(iommu, drhd) iommu->iommu_dev = iommu_device_create(NULL, iommu, intel_iommu_groups, - iommu->name); + "%s", iommu->name); bus_set_iommu(&pci_bus_type, &intel_iommu_ops); bus_register_notifier(&pci_bus_type, &device_nb); -- cgit v1.3-6-gb490 From 50690762cfe32abadbaa5b22bebe3855e5b8ede8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 30 Jul 2015 12:54:01 -0400 Subject: iommu/vt-d: Fix leaked ioremap mapping iommu_load_old_irte() appears to leak the old_irte mapping after use. Cc: Joerg Roedel Signed-off-by: Dan Williams Signed-off-by: Joerg Roedel --- drivers/iommu/intel_irq_remapping.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index f15692a410c7..27cdfa84ec5b 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -426,6 +426,8 @@ static int iommu_load_old_irte(struct intel_iommu *iommu) bitmap_set(iommu->ir_table->bitmap, i, 1); } + iounmap(old_ir_table); + return 0; } -- cgit v1.3-6-gb490 From 2238c0827a9bfa8d517e3175110ed603fb7b9537 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 14 Jul 2015 15:24:53 -0600 Subject: iommu/vt-d: Report domain usage in sysfs Debugging domain ID leakage typically requires long running tests in order to exhaust the domain ID space or kernel instrumentation to track the setting and clearing of bits. A couple trivial intel-iommu specific sysfs extensions make it much easier to expose the IOMMU capabilities and current usage. Signed-off-by: Alex Williamson Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 0be23c589d3b..013cbc200579 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -4449,11 +4449,32 @@ static ssize_t intel_iommu_show_ecap(struct device *dev, } static DEVICE_ATTR(ecap, S_IRUGO, intel_iommu_show_ecap, NULL); +static ssize_t intel_iommu_show_ndoms(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct intel_iommu *iommu = dev_get_drvdata(dev); + return sprintf(buf, "%ld\n", cap_ndoms(iommu->cap)); +} +static DEVICE_ATTR(domains_supported, S_IRUGO, intel_iommu_show_ndoms, NULL); + +static ssize_t intel_iommu_show_ndoms_used(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct intel_iommu *iommu = dev_get_drvdata(dev); + return sprintf(buf, "%d\n", bitmap_weight(iommu->domain_ids, + cap_ndoms(iommu->cap))); +} +static DEVICE_ATTR(domains_used, S_IRUGO, intel_iommu_show_ndoms_used, NULL); + static struct attribute *intel_iommu_attrs[] = { &dev_attr_version.attr, &dev_attr_address.attr, &dev_attr_cap.attr, &dev_attr_ecap.attr, + &dev_attr_domains_supported.attr, + &dev_attr_domains_used.attr, NULL, }; -- cgit v1.3-6-gb490 From be120397e7709d9d5ed88317a385ce864a2603bc Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Fri, 31 Jul 2015 15:46:19 +0100 Subject: ARM: migrate to common PSCI client code Now that the common PSCI client code has been factored out to drivers/firmware, and made safe for 32-bit use, move the 32-bit ARM code over to it. This results in a moderate reduction of duplicated lines, and will prevent further duplication as the PSCI client code is updated for PSCI 1.0 and beyond. The two legacy platform users of the PSCI invocation code are updated to account for interface changes. In both cases the power state parameter (which is constant) is now generated using macros, so that the pack/unpack logic can be killed in preparation for PSCI 1.0 power state changes. Signed-off-by: Mark Rutland Acked-by: Rob Herring Cc: Catalin Marinas Cc: Ashwin Chaugule Cc: Lorenzo Pieralisi Cc: Russell King Cc: Will Deacon Signed-off-by: Will Deacon --- arch/arm/Kconfig | 1 + arch/arm/include/asm/psci.h | 23 --- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/psci.c | 299 -------------------------------------- arch/arm/kernel/psci_smp.c | 29 +++- arch/arm/kernel/setup.c | 3 +- arch/arm/mach-highbank/highbank.c | 2 +- arch/arm/mach-highbank/pm.c | 16 +- drivers/cpuidle/cpuidle-calxeda.c | 15 +- 9 files changed, 46 insertions(+), 344 deletions(-) delete mode 100644 arch/arm/kernel/psci.c (limited to 'drivers') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 1c5021002fe4..f5cd68425d8d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1496,6 +1496,7 @@ config HOTPLUG_CPU config ARM_PSCI bool "Support for the ARM Power State Coordination Interface (PSCI)" depends on CPU_V7 + select ARM_PSCI_FW help Say Y here if you want Linux to communicate with system firmware implementing the PSCI specification for CPU-centric power diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h index c25ef3ec6d1f..68ee3ce17b82 100644 --- a/arch/arm/include/asm/psci.h +++ b/arch/arm/include/asm/psci.h @@ -14,34 +14,11 @@ #ifndef __ASM_ARM_PSCI_H #define __ASM_ARM_PSCI_H -#define PSCI_POWER_STATE_TYPE_STANDBY 0 -#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 - -struct psci_power_state { - u16 id; - u8 type; - u8 affinity_level; -}; - -struct psci_operations { - int (*cpu_suspend)(struct psci_power_state state, - unsigned long entry_point); - int (*cpu_off)(struct psci_power_state state); - int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); - int (*migrate)(unsigned long cpuid); - int (*affinity_info)(unsigned long target_affinity, - unsigned long lowest_affinity_level); - int (*migrate_info_type)(void); -}; - -extern struct psci_operations psci_ops; extern struct smp_operations psci_smp_ops; #ifdef CONFIG_ARM_PSCI -int psci_init(void); bool psci_smp_available(void); #else -static inline int psci_init(void) { return 0; } static inline bool psci_smp_available(void) { return false; } #endif diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index e69f7a19735d..3b995f5c524d 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -89,7 +89,7 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o ifeq ($(CONFIG_ARM_PSCI),y) -obj-y += psci.o psci-call.o +obj-y += psci-call.o obj-$(CONFIG_SMP) += psci_smp.o endif diff --git a/arch/arm/kernel/psci.c b/arch/arm/kernel/psci.c deleted file mode 100644 index f90fdf4ce7c7..000000000000 --- a/arch/arm/kernel/psci.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2012 ARM Limited - * - * Author: Will Deacon - */ - -#define pr_fmt(fmt) "psci: " fmt - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -struct psci_operations psci_ops; - -static int (*invoke_psci_fn)(u32, u32, u32, u32); -typedef int (*psci_initcall_t)(const struct device_node *); - -asmlinkage int __invoke_psci_fn_hvc(u32, u32, u32, u32); -asmlinkage int __invoke_psci_fn_smc(u32, u32, u32, u32); - -enum psci_function { - PSCI_FN_CPU_SUSPEND, - PSCI_FN_CPU_ON, - PSCI_FN_CPU_OFF, - PSCI_FN_MIGRATE, - PSCI_FN_AFFINITY_INFO, - PSCI_FN_MIGRATE_INFO_TYPE, - PSCI_FN_MAX, -}; - -static u32 psci_function_id[PSCI_FN_MAX]; - -static int psci_to_linux_errno(int errno) -{ - switch (errno) { - case PSCI_RET_SUCCESS: - return 0; - case PSCI_RET_NOT_SUPPORTED: - return -EOPNOTSUPP; - case PSCI_RET_INVALID_PARAMS: - return -EINVAL; - case PSCI_RET_DENIED: - return -EPERM; - }; - - return -EINVAL; -} - -static u32 psci_power_state_pack(struct psci_power_state state) -{ - return ((state.id << PSCI_0_2_POWER_STATE_ID_SHIFT) - & PSCI_0_2_POWER_STATE_ID_MASK) | - ((state.type << PSCI_0_2_POWER_STATE_TYPE_SHIFT) - & PSCI_0_2_POWER_STATE_TYPE_MASK) | - ((state.affinity_level << PSCI_0_2_POWER_STATE_AFFL_SHIFT) - & PSCI_0_2_POWER_STATE_AFFL_MASK); -} - -static int psci_get_version(void) -{ - int err; - - err = invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); - return err; -} - -static int psci_cpu_suspend(struct psci_power_state state, - unsigned long entry_point) -{ - int err; - u32 fn, power_state; - - fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; - power_state = psci_power_state_pack(state); - err = invoke_psci_fn(fn, power_state, entry_point, 0); - return psci_to_linux_errno(err); -} - -static int psci_cpu_off(struct psci_power_state state) -{ - int err; - u32 fn, power_state; - - fn = psci_function_id[PSCI_FN_CPU_OFF]; - power_state = psci_power_state_pack(state); - err = invoke_psci_fn(fn, power_state, 0, 0); - return psci_to_linux_errno(err); -} - -static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point) -{ - int err; - u32 fn; - - fn = psci_function_id[PSCI_FN_CPU_ON]; - err = invoke_psci_fn(fn, cpuid, entry_point, 0); - return psci_to_linux_errno(err); -} - -static int psci_migrate(unsigned long cpuid) -{ - int err; - u32 fn; - - fn = psci_function_id[PSCI_FN_MIGRATE]; - err = invoke_psci_fn(fn, cpuid, 0, 0); - return psci_to_linux_errno(err); -} - -static int psci_affinity_info(unsigned long target_affinity, - unsigned long lowest_affinity_level) -{ - int err; - u32 fn; - - fn = psci_function_id[PSCI_FN_AFFINITY_INFO]; - err = invoke_psci_fn(fn, target_affinity, lowest_affinity_level, 0); - return err; -} - -static int psci_migrate_info_type(void) -{ - int err; - u32 fn; - - fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE]; - err = invoke_psci_fn(fn, 0, 0, 0); - return err; -} - -static int get_set_conduit_method(struct device_node *np) -{ - const char *method; - - pr_info("probing for conduit method from DT.\n"); - - if (of_property_read_string(np, "method", &method)) { - pr_warn("missing \"method\" property\n"); - return -ENXIO; - } - - if (!strcmp("hvc", method)) { - invoke_psci_fn = __invoke_psci_fn_hvc; - } else if (!strcmp("smc", method)) { - invoke_psci_fn = __invoke_psci_fn_smc; - } else { - pr_warn("invalid \"method\" property: %s\n", method); - return -EINVAL; - } - return 0; -} - -static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd) -{ - invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); -} - -static void psci_sys_poweroff(void) -{ - invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); -} - -/* - * PSCI Function IDs for v0.2+ are well defined so use - * standard values. - */ -static int psci_0_2_init(struct device_node *np) -{ - int err, ver; - - err = get_set_conduit_method(np); - - if (err) - goto out_put_node; - - ver = psci_get_version(); - - if (ver == PSCI_RET_NOT_SUPPORTED) { - /* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */ - pr_err("PSCI firmware does not comply with the v0.2 spec.\n"); - err = -EOPNOTSUPP; - goto out_put_node; - } else { - pr_info("PSCIv%d.%d detected in firmware.\n", - PSCI_VERSION_MAJOR(ver), - PSCI_VERSION_MINOR(ver)); - - if (PSCI_VERSION_MAJOR(ver) == 0 && - PSCI_VERSION_MINOR(ver) < 2) { - err = -EINVAL; - pr_err("Conflicting PSCI version detected.\n"); - goto out_put_node; - } - } - - pr_info("Using standard PSCI v0.2 function IDs\n"); - psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN_CPU_SUSPEND; - psci_ops.cpu_suspend = psci_cpu_suspend; - - psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; - psci_ops.cpu_off = psci_cpu_off; - - psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN_CPU_ON; - psci_ops.cpu_on = psci_cpu_on; - - psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN_MIGRATE; - psci_ops.migrate = psci_migrate; - - psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN_AFFINITY_INFO; - psci_ops.affinity_info = psci_affinity_info; - - psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] = - PSCI_0_2_FN_MIGRATE_INFO_TYPE; - psci_ops.migrate_info_type = psci_migrate_info_type; - - arm_pm_restart = psci_sys_reset; - - pm_power_off = psci_sys_poweroff; - -out_put_node: - of_node_put(np); - return err; -} - -/* - * PSCI < v0.2 get PSCI Function IDs via DT. - */ -static int psci_0_1_init(struct device_node *np) -{ - u32 id; - int err; - - err = get_set_conduit_method(np); - - if (err) - goto out_put_node; - - pr_info("Using PSCI v0.1 Function IDs from DT\n"); - - if (!of_property_read_u32(np, "cpu_suspend", &id)) { - psci_function_id[PSCI_FN_CPU_SUSPEND] = id; - psci_ops.cpu_suspend = psci_cpu_suspend; - } - - if (!of_property_read_u32(np, "cpu_off", &id)) { - psci_function_id[PSCI_FN_CPU_OFF] = id; - psci_ops.cpu_off = psci_cpu_off; - } - - if (!of_property_read_u32(np, "cpu_on", &id)) { - psci_function_id[PSCI_FN_CPU_ON] = id; - psci_ops.cpu_on = psci_cpu_on; - } - - if (!of_property_read_u32(np, "migrate", &id)) { - psci_function_id[PSCI_FN_MIGRATE] = id; - psci_ops.migrate = psci_migrate; - } - -out_put_node: - of_node_put(np); - return err; -} - -static const struct of_device_id psci_of_match[] __initconst = { - { .compatible = "arm,psci", .data = psci_0_1_init}, - { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, - {}, -}; - -int __init psci_init(void) -{ - struct device_node *np; - const struct of_device_id *matched_np; - psci_initcall_t init_fn; - - np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np); - if (!np) - return -ENODEV; - - init_fn = (psci_initcall_t)matched_np->data; - return init_fn(np); -} diff --git a/arch/arm/kernel/psci_smp.c b/arch/arm/kernel/psci_smp.c index 244aaddfbfda..61c04b02faeb 100644 --- a/arch/arm/kernel/psci_smp.c +++ b/arch/arm/kernel/psci_smp.c @@ -17,6 +17,8 @@ #include #include #include +#include + #include #include @@ -56,17 +58,29 @@ static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle) } #ifdef CONFIG_HOTPLUG_CPU +int psci_cpu_disable(unsigned int cpu) +{ + /* Fail early if we don't have CPU_OFF support */ + if (!psci_ops.cpu_off) + return -EOPNOTSUPP; + + /* Trusted OS will deny CPU_OFF */ + if (psci_tos_resident_on(cpu)) + return -EPERM; + + return 0; +} + void __ref psci_cpu_die(unsigned int cpu) { - const struct psci_power_state ps = { - .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, - }; + u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN << + PSCI_0_2_POWER_STATE_TYPE_SHIFT; - if (psci_ops.cpu_off) - psci_ops.cpu_off(ps); + if (psci_ops.cpu_off) + psci_ops.cpu_off(state); - /* We should never return */ - panic("psci: cpu %d failed to shutdown\n", cpu); + /* We should never return */ + panic("psci: cpu %d failed to shutdown\n", cpu); } int __ref psci_cpu_kill(unsigned int cpu) @@ -109,6 +123,7 @@ bool __init psci_smp_available(void) struct smp_operations __initdata psci_smp_ops = { .smp_boot_secondary = psci_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU + .cpu_disable = psci_cpu_disable, .cpu_die = psci_cpu_die, .cpu_kill = psci_cpu_kill, #endif diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 36c18b73c1f4..9c38bd42f04b 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -972,7 +973,7 @@ void __init setup_arch(char **cmdline_p) unflatten_device_tree(); arm_dt_init_cpu_maps(); - psci_init(); + psci_dt_init(); xen_early_init(); #ifdef CONFIG_SMP if (is_smp()) { diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index 231fba0d03e5..6050a14faee6 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c @@ -28,8 +28,8 @@ #include #include #include +#include -#include #include #include #include diff --git a/arch/arm/mach-highbank/pm.c b/arch/arm/mach-highbank/pm.c index 7f2bd85eb935..400311695548 100644 --- a/arch/arm/mach-highbank/pm.c +++ b/arch/arm/mach-highbank/pm.c @@ -16,19 +16,21 @@ #include #include +#include #include #include -#include + +#include + +#define HIGHBANK_SUSPEND_PARAM \ + ((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) static int highbank_suspend_finish(unsigned long val) { - const struct psci_power_state ps = { - .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, - .affinity_level = 1, - }; - - return psci_ops.cpu_suspend(ps, __pa(cpu_resume)); + return psci_ops.cpu_suspend(HIGHBANK_SUSPEND_PARAM, __pa(cpu_resume)); } static int highbank_pm_enter(suspend_state_t state) diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c index c13feec89ea1..ea9728fde9b3 100644 --- a/drivers/cpuidle/cpuidle-calxeda.c +++ b/drivers/cpuidle/cpuidle-calxeda.c @@ -25,16 +25,21 @@ #include #include #include +#include + #include #include -#include + +#include + +#define CALXEDA_IDLE_PARAM \ + ((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ + (0 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) static int calxeda_idle_finish(unsigned long val) { - const struct psci_power_state ps = { - .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, - }; - return psci_ops.cpu_suspend(ps, __pa(cpu_resume)); + return psci_ops.cpu_suspend(CALXEDA_IDLE_PARAM, __pa(cpu_resume)); } static int calxeda_pwrdown_idle(struct cpuidle_device *dev, -- cgit v1.3-6-gb490 From d3cb25a12138a09bc948c0091d3d42e519980659 Mon Sep 17 00:00:00 2001 From: Pengyu Ma Date: Mon, 3 Aug 2015 11:28:24 +0800 Subject: usb: gadget: udc: fix spin_lock in pch_udc When remove module g_serial on quark platform, the following Warning on: Modules linked in: usb_f_acm u_serial g_serial(-) pch_udc libcomposite configfs udc_core ad7298 industrialio_triggered_buffer kfifo_buf tpm_i2c_infineon indus CPU: 0 PID: 369 Comm: modprobe Not tainted 3.14.29ltsi-WR7.0.0.0_standard #6 Hardware name: Intel Corp. QUARK/CrossHill, BIOS 0x010100F5 01/01/2014 f641df0c f641df0c f641dec8 c15ac7fa f641defc c103084f c16c2356 f641df28 00000171 c16b855c 000009dd c15b2d6f 000009dd c15b2d6f f6bd2000 faae5480 00000000 f641df14 c10308a3 00000009 f641df0c c16c2356 f641df28 f641df2c Call Trace: [] dump_stack+0x16/0x18 [] warn_slowpath_common+0x7f/0xa0 [] ? preempt_count_sub+0x6f/0xc0 [] ? preempt_count_sub+0x6f/0xc0 [] warn_slowpath_fmt+0x33/0x40 [] preempt_count_sub+0x6f/0xc0 [] pch_udc_pcd_pullup+0x32/0xa0 [pch_udc] [] usb_gadget_remove_driver+0x29/0x60 [udc_core] [] usb_gadget_unregister_driver+0x59/0x80 [udc_core] [] usb_composite_unregister+0x10/0x20 [libcomposite] [] cleanup+0xd/0xf [g_serial] [] SyS_delete_module+0xf7/0x150 [] ? ____fput+0xd/0x10 [] ? task_work_run+0x6e/0xa0 [] syscall_call+0x7/0x7 g_serial module on quark is depended on pch_udc module, ttyGSX cann't recieve data and warning on when remove g_serial. It was unlocked before the modification of the structure it was protecting, fix it as "lock -> unlock" to resolve this. Signed-off-by: Pengyu Ma Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index dcf5defdb9e5..e071c62d7f24 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -620,9 +620,9 @@ static inline void pch_udc_vbus_session(struct pch_udc_dev *dev, dev->vbus_session = 1; } else { if (dev->driver && dev->driver->disconnect) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); spin_lock(&dev->lock); + dev->driver->disconnect(&dev->gadget); + spin_unlock(&dev->lock); } pch_udc_set_disconnect(dev); dev->vbus_session = 0; @@ -1191,9 +1191,9 @@ static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on) pch_udc_reconnect(dev); } else { if (dev->driver && dev->driver->disconnect) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); spin_lock(&dev->lock); + dev->driver->disconnect(&dev->gadget); + spin_unlock(&dev->lock); } pch_udc_set_disconnect(dev); } @@ -1488,11 +1488,11 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req, req->dma_mapped = 0; } ep->halted = 1; - spin_unlock(&dev->lock); + spin_lock(&dev->lock); if (!ep->in) pch_udc_ep_clear_rrdy(ep); usb_gadget_giveback_request(&ep->ep, &req->req); - spin_lock(&dev->lock); + spin_unlock(&dev->lock); ep->halted = halted; } @@ -2414,7 +2414,7 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep; else /* OUT */ dev->gadget.ep0 = &ep->ep; - spin_unlock(&dev->lock); + spin_lock(&dev->lock); /* If Mass storage Reset */ if ((dev->setup_data.bRequestType == 0x21) && (dev->setup_data.bRequest == 0xFF)) @@ -2422,7 +2422,7 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) /* call gadget with setup data received */ setup_supported = dev->driver->setup(&dev->gadget, &dev->setup_data); - spin_lock(&dev->lock); + spin_unlock(&dev->lock); if (dev->setup_data.bRequestType & USB_DIR_IN) { ep->td_data->status = (ep->td_data->status & @@ -2594,9 +2594,9 @@ static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev) empty_req_queue(ep); } if (dev->driver) { - spin_unlock(&dev->lock); - usb_gadget_udc_reset(&dev->gadget, dev->driver); spin_lock(&dev->lock); + usb_gadget_udc_reset(&dev->gadget, dev->driver); + spin_unlock(&dev->lock); } } @@ -2675,9 +2675,9 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) dev->ep[i].halted = 0; } dev->stall = 0; - spin_unlock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); spin_lock(&dev->lock); + ret = dev->driver->setup(&dev->gadget, &dev->setup_data); + spin_unlock(&dev->lock); } /** @@ -2712,9 +2712,9 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) dev->stall = 0; /* call gadget zero with setup data received */ - spin_unlock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); spin_lock(&dev->lock); + ret = dev->driver->setup(&dev->gadget, &dev->setup_data); + spin_unlock(&dev->lock); } /** @@ -2747,18 +2747,18 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr) if (dev_intr & UDC_DEVINT_US) { if (dev->driver && dev->driver->suspend) { - spin_unlock(&dev->lock); - dev->driver->suspend(&dev->gadget); spin_lock(&dev->lock); + dev->driver->suspend(&dev->gadget); + spin_unlock(&dev->lock); } vbus = pch_vbus_gpio_get_value(dev); if ((dev->vbus_session == 0) && (vbus != 1)) { if (dev->driver && dev->driver->disconnect) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); spin_lock(&dev->lock); + dev->driver->disconnect(&dev->gadget); + spin_unlock(&dev->lock); } pch_udc_reconnect(dev); } else if ((dev->vbus_session == 0) -- cgit v1.3-6-gb490 From 2f0bb2a0e7f5161e83615fb1283c5079566ed6a7 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 3 Aug 2015 05:37:10 -0700 Subject: usb: musb: Allow building in all the DMA code With recent changes to MUSB code, we can now now get rid of the Kconfig choise for the DMA code and allow building in any of the desired DMA code. This makes life easier for distros. Signed-off-by: Tony Lindgren Signed-off-by: Felipe Balbi --- drivers/usb/musb/Kconfig | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 37081ed8f295..1f2037bbeb0d 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -124,19 +124,20 @@ config USB_MUSB_JZ4740 config USB_MUSB_AM335X_CHILD tristate -choice - prompt 'MUSB DMA mode' - default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM || USB_MUSB_JZ4740 - default USB_UX500_DMA if USB_MUSB_UX500 - default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN - default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI - default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010 - default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X \ - || USB_MUSB_DSPS +comment "MUSB DMA mode" + +config MUSB_PIO_ONLY + bool 'Disable DMA (always use PIO)' help - Unfortunately, only one option can be enabled here. Ideally one - should be able to build all these drivers into one kernel to - allow using DMA on multiplatform kernels. + All data is copied between memory and FIFO by the CPU. + DMA controllers are ignored. + + Do not choose this unless DMA support for your SOC or board + is unavailable (or unstable). When DMA is enabled at compile time, + you can still disable it at run time using the "use_dma=n" module + parameter. + +if !MUSB_PIO_ONLY config USB_UX500_DMA bool 'ST Ericsson Ux500' @@ -168,17 +169,6 @@ config USB_TUSB_OMAP_DMA help Enable DMA transfers on TUSB 6010 when OMAP DMA is available. -config MUSB_PIO_ONLY - bool 'Disable DMA (always use PIO)' - help - All data is copied between memory and FIFO by the CPU. - DMA controllers are ignored. - - Do not choose this unless DMA support for your SOC or board - is unavailable (or unstable). When DMA is enabled at compile time, - you can still disable it at run time using the "use_dma=n" module - parameter. - -endchoice +endif # !MUSB_PIO_ONLY endif # USB_MUSB_HDRC -- cgit v1.3-6-gb490 From a24b071bb4ac37ef51a0ed4765f89be05a617677 Mon Sep 17 00:00:00 2001 From: Fupan Li Date: Mon, 3 Aug 2015 19:19:43 +0800 Subject: usb: gadget: f_printer: fix deadlock caused by nested spinlock Function printer_func_disable() has called spinlock on printer_dev->lock, and it'll call function chain of printer_reset_interface() | +---dwc3_gadget_ep_disable() | +---__dwc3_gadget_ep_disable() | +---dwc3_remove_requests() | +---dwc3_gadget_giveback() | +---rx_complete() in the protected block. However, rx_complete() in f_printer.c calls spinlock on printer_dev->lock again, which will cause system hang. The following steps can reproduce this hang: 1. Build the test program from Documentation/usb/gadget_printer.txt as g_printer 2. Plug in the USB device to a host(such as Ubuntu). 3. on the USB device system run: #modprobe g_printer.ko #./g_printer -read_data 4. Unplug the USB device from the host The system will hang later. In order to avoid this deadlock, moving the spinlock from printer_func_disable() into printer_reset_interface() and excluding the block of calling dwc3_gadget_ep_disable(), in which the critical resource will be protected by its spinlock in rx_complete(). This commit will fix the system hang with the following calltrace: INFO: rcu_preempt detected stalls on CPUs/tasks: { 3} (detected by 0, t=21006 jiffies, g=524, c=523, q=2) sending NMI to all CPUs: NMI backtrace for cpu 3 CPU: 3 PID: 718 Comm: irq/22-dwc3 Not tainted 3.10.38-ltsi-WR6.0.0.11_standard #2 Hardware name: Intel Corp. VALLEYVIEW B3 PLATFORM/NOTEBOOK, BIOS BYTICRB1.86C.0092.R32.1410021707 10/02/2014 task: f44f4c20 ti: f40f6000 task.ti: f40f6000 EIP: 0060:[] EFLAGS: 00000097 CPU: 3 EIP is at _raw_spin_lock_irqsave+0x35/0x40 EAX: 00000076 EBX: f80fad00 ECX: 00000076 EDX: 00000075 ESI: 00000096 EDI: ffffff94 EBP: f40f7e20 ESP: f40f7e18 DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 CR0: 8005003b CR2: b77ac000 CR3: 01c30000 CR4: 001007f0 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Stack: f474a720 f80fad00 f40f7e3c f80f93cc c135d486 00000000 f474a720 f468fb00 f4bea894 f40f7e54 f7e35f19 ffffff00 f468fb00 f468fb24 00000086 f40f7e64 f7e36577 f468fb00 f4bea810 f40f7e74 f7e365a8 f468fb00 f4bea894 f40f7e9c Call Trace: [] rx_complete+0x1c/0xb0 [g_printer] [] ? vsnprintf+0x166/0x390 [] dwc3_gadget_giveback+0xc9/0xf0 [dwc3] [] dwc3_remove_requests+0x57/0x70 [dwc3] [] __dwc3_gadget_ep_disable+0x18/0x60 [dwc3] [] dwc3_gadget_ep_disable+0x89/0xf0 [dwc3] [] printer_reset_interface+0x31/0x50 [g_printer] [] printer_func_disable+0x20/0x30 [g_printer] [] composite_disconnect+0x4b/0x90 [libcomposite] [] dwc3_disconnect_gadget+0x38/0x43 [dwc3] [] dwc3_gadget_disconnect_interrupt+0x3e/0x5a [dwc3] [] dwc3_thread_interrupt+0x5c8/0x610 [dwc3] [] irq_thread_fn+0x18/0x30 [] irq_thread+0x100/0x130 [] ? irq_finalize_oneshot.part.29+0xb0/0xb0 [] ? wake_threads_waitq+0x40/0x40 [] ? irq_thread_dtor+0xb0/0xb0 [] kthread+0x94/0xa0 [] ret_from_kernel_thread+0x1b/0x28 [] ? kthread_create_on_node+0xc0/0xc0 Signed-off-by: Fupan Li Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_printer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 44173df27273..a91c18a585b5 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -804,6 +804,8 @@ done: static void printer_reset_interface(struct printer_dev *dev) { + unsigned long flags; + if (dev->interface < 0) return; @@ -815,9 +817,11 @@ static void printer_reset_interface(struct printer_dev *dev) if (dev->out_ep->desc) usb_ep_disable(dev->out_ep); + spin_lock_irqsave(&dev->lock, flags); dev->in_ep->desc = NULL; dev->out_ep->desc = NULL; dev->interface = -1; + spin_unlock_irqrestore(&dev->lock, flags); } /* Change our operational Interface. */ @@ -1131,13 +1135,10 @@ static int printer_func_set_alt(struct usb_function *f, static void printer_func_disable(struct usb_function *f) { struct printer_dev *dev = func_to_printer(f); - unsigned long flags; DBG(dev, "%s\n", __func__); - spin_lock_irqsave(&dev->lock, flags); printer_reset_interface(dev); - spin_unlock_irqrestore(&dev->lock, flags); } static inline struct f_printer_opts -- cgit v1.3-6-gb490 From 3f217e9e96daa3d7741bab705fe9c7798d9951a9 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Fri, 31 Jul 2015 10:41:00 +0800 Subject: usb: chipidea: add ci->is_otg condition for otg judgement Since some chipidea based controller is not otg capable, add ci->is_otg condition when setting is_otg flag for gadget. Signed-off-by: Li Jun Reviewed-by: Roger Quadros Acked-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/chipidea/udc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index b7cca3e597bf..f5fbe78e8e6a 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1838,8 +1838,8 @@ static int udc_start(struct ci_hdrc *ci) ci->gadget.name = ci->platdata->name; ci->gadget.otg_caps = otg_caps; - if (otg_caps->hnp_support || otg_caps->srp_support || - otg_caps->adp_support) + if (ci->is_otg && (otg_caps->hnp_support || otg_caps->srp_support || + otg_caps->adp_support)) ci->gadget.is_otg = 1; INIT_LIST_HEAD(&ci->gadget.ep_list); -- cgit v1.3-6-gb490 From 286272137f66199f87ea254397181b9bab5e5467 Mon Sep 17 00:00:00 2001 From: Radivoje Jovanovic Date: Fri, 31 Jul 2015 08:07:45 -0700 Subject: thermal/powerclamp: add cpu id for skylake h/s Add support for Intel Skylake H/S Signed-off-by: Radivoje Jovanovic Signed-off-by: Zhang Rui --- drivers/thermal/intel_powerclamp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index 5820e8513927..63879a10f5c5 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -698,6 +698,7 @@ static const struct x86_cpu_id intel_powerclamp_ids[] __initconst = { { X86_VENDOR_INTEL, 6, 0x4f}, { X86_VENDOR_INTEL, 6, 0x56}, { X86_VENDOR_INTEL, 6, 0x57}, + { X86_VENDOR_INTEL, 6, 0x5e}, {} }; MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids); -- cgit v1.3-6-gb490 From 35676de2164ff37209431e7e0e49a7466720d9be Mon Sep 17 00:00:00 2001 From: Radivoje Jovanovic Date: Fri, 31 Jul 2015 08:07:54 -0700 Subject: thermal/powerclamp: add cpu id for Skylake u/y Add support for Intel Skylake u/y Signed-off-by: Radivoje Jovanovic Signed-off-by: Zhang Rui --- drivers/thermal/intel_powerclamp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index 63879a10f5c5..6e017238c1fa 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -695,6 +695,7 @@ static const struct x86_cpu_id intel_powerclamp_ids[] __initconst = { { X86_VENDOR_INTEL, 6, 0x46}, { X86_VENDOR_INTEL, 6, 0x4c}, { X86_VENDOR_INTEL, 6, 0x4d}, + { X86_VENDOR_INTEL, 6, 0x4e}, { X86_VENDOR_INTEL, 6, 0x4f}, { X86_VENDOR_INTEL, 6, 0x56}, { X86_VENDOR_INTEL, 6, 0x57}, -- cgit v1.3-6-gb490 From 1f22dc4494e203d6987fc708f414b4adf8614036 Mon Sep 17 00:00:00 2001 From: Jacob Pan Date: Mon, 29 Jun 2015 08:53:18 -0700 Subject: thermal/powerclamp: add cpu id for denlow platform Add support for Intel Denlow UP server platform. Signed-off-by: Jacob Pan Signed-off-by: Zhang Rui --- drivers/thermal/intel_powerclamp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index 6e017238c1fa..a42e8a39f808 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -693,6 +693,7 @@ static const struct x86_cpu_id intel_powerclamp_ids[] __initconst = { { X86_VENDOR_INTEL, 6, 0x3f}, { X86_VENDOR_INTEL, 6, 0x45}, { X86_VENDOR_INTEL, 6, 0x46}, + { X86_VENDOR_INTEL, 6, 0x47}, { X86_VENDOR_INTEL, 6, 0x4c}, { X86_VENDOR_INTEL, 6, 0x4d}, { X86_VENDOR_INTEL, 6, 0x4e}, -- cgit v1.3-6-gb490 From b5e578631e5c1d77f58727ea0769dd55c462b572 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 28 Jul 2015 20:44:41 +0200 Subject: rx51-battery: Set name to rx51-battery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For compatibility between board code and DT, set battery name to same value. Signed-off-by: Pali Rohár Acked-by: Pavel Machek Signed-off-by: Sebastian Reichel --- drivers/power/rx51_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/rx51_battery.c b/drivers/power/rx51_battery.c index ac6206951d58..af9383d23d12 100644 --- a/drivers/power/rx51_battery.c +++ b/drivers/power/rx51_battery.c @@ -215,7 +215,7 @@ static int rx51_battery_probe(struct platform_device *pdev) platform_set_drvdata(pdev, di); di->dev = &pdev->dev; - di->bat_desc.name = dev_name(&pdev->dev); + di->bat_desc.name = "rx51-battery"; di->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; di->bat_desc.properties = rx51_battery_props; di->bat_desc.num_properties = ARRAY_SIZE(rx51_battery_props); -- cgit v1.3-6-gb490 From 25a0a5ce16ecd7e60c4cf1436892433873e9d99d Mon Sep 17 00:00:00 2001 From: Ni Wade Date: Tue, 14 Jul 2015 15:40:56 +0800 Subject: thermal: add available policies sysfs attribute The Linux thermal framework support to change thermal governor policy in userspace, but it can't show what available policies supported. This patch adds available_policies attribute to the thermal framework, it can list the thermal governors which can be used for a particular zone. This attribute is read only. Signed-off-by: Wei Ni Reviewed-by: Javi Merino Signed-off-by: Zhang Rui --- Documentation/thermal/sysfs-api.txt | 6 ++++++ drivers/thermal/thermal_core.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'drivers') diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt index c1f6864a8c5d..10f062ea6bc2 100644 --- a/Documentation/thermal/sysfs-api.txt +++ b/Documentation/thermal/sysfs-api.txt @@ -180,6 +180,7 @@ Thermal zone device sys I/F, created once it's registered: |---temp: Current temperature |---mode: Working mode of the thermal zone |---policy: Thermal governor used for this zone + |---available_policies: Available thermal governors for this zone |---trip_point_[0-*]_temp: Trip point temperature |---trip_point_[0-*]_type: Trip point type |---trip_point_[0-*]_hyst: Hysteresis value for this trip point @@ -256,6 +257,10 @@ policy One of the various thermal governors used for a particular zone. RW, Required +available_policies + Available thermal governors which can be used for a particular zone. + RO, Required + trip_point_[0-*]_temp The temperature above which trip point will be fired. Unit: millidegree Celsius @@ -417,6 +422,7 @@ method, the sys I/F structure will be built like this: |---temp: 37000 |---mode: enabled |---policy: step_wise + |---available_policies: step_wise fair_share |---trip_point_0_temp: 100000 |---trip_point_0_type: critical |---trip_point_1_temp: 80000 diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 04659bfb888b..c4700950e42e 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -847,6 +847,27 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf) return sprintf(buf, "%s\n", tz->governor->name); } +static ssize_t +available_policies_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct thermal_governor *pos; + ssize_t count = 0; + ssize_t size = PAGE_SIZE; + + mutex_lock(&thermal_governor_lock); + + list_for_each_entry(pos, &thermal_governor_list, governor_list) { + size = PAGE_SIZE - count; + count += scnprintf(buf + count, size, "%s ", pos->name); + } + count += scnprintf(buf + count, size, "\n"); + + mutex_unlock(&thermal_governor_lock); + + return count; +} + #ifdef CONFIG_THERMAL_EMULATION static ssize_t emul_temp_store(struct device *dev, struct device_attribute *attr, @@ -1032,6 +1053,7 @@ static DEVICE_ATTR(temp, 0444, temp_show, NULL); static DEVICE_ATTR(mode, 0644, mode_show, mode_store); static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store); static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store); +static DEVICE_ATTR(available_policies, S_IRUGO, available_policies_show, NULL); /* sys I/F for cooling device */ #define to_cooling_device(_dev) \ @@ -1817,6 +1839,11 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type, if (result) goto unregister; + /* Create available_policies attribute */ + result = device_create_file(&tz->device, &dev_attr_available_policies); + if (result) + goto unregister; + /* Update 'this' zone's governor information */ mutex_lock(&thermal_governor_lock); @@ -1917,6 +1944,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) if (tz->ops->get_mode) device_remove_file(&tz->device, &dev_attr_mode); device_remove_file(&tz->device, &dev_attr_policy); + device_remove_file(&tz->device, &dev_attr_available_policies); remove_trip_attrs(tz); thermal_set_governor(tz, NULL); -- cgit v1.3-6-gb490 From 17e8351a77397e8a83727eb17e3a3e9b8ab5257a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 24 Jul 2015 08:12:54 +0200 Subject: thermal: consistently use int for temperatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The thermal code uses int, long and unsigned long for temperatures in different places. Using an unsigned type limits the thermal framework to positive temperatures without need. Also several drivers currently will report temperatures near UINT_MAX for temperatures below 0°C. This will probably immediately shut the machine down due to overtemperature if started below 0°C. 'long' is 64bit on several architectures. This is not needed since INT_MAX °mC is above the melting point of all known materials. Consistently use a plain 'int' for temperatures throughout the thermal code and the drivers. This only changes the places in the drivers where the temperature is passed around as pointer, when drivers internally use another type this is not changed. Signed-off-by: Sascha Hauer Acked-by: Geert Uytterhoeven Reviewed-by: Jean Delvare Reviewed-by: Lukasz Majewski Reviewed-by: Darren Hart Reviewed-by: Heiko Stuebner Reviewed-by: Peter Feuerer Cc: Punit Agrawal Cc: Zhang Rui Cc: Eduardo Valentin Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: Jean Delvare Cc: Peter Feuerer Cc: Heiko Stuebner Cc: Lukasz Majewski Cc: Stephen Warren Cc: Thierry Reding Cc: linux-acpi@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-omap@vger.kernel.org Cc: linux-samsung-soc@vger.kernel.org Cc: Guenter Roeck Cc: Rafael J. Wysocki Cc: Maxime Ripard Cc: Darren Hart Cc: lm-sensors@lm-sensors.org Signed-off-by: Zhang Rui --- drivers/acpi/thermal.c | 12 +++++----- drivers/hwmon/lm75.c | 2 +- drivers/hwmon/ntc_thermistor.c | 2 +- drivers/hwmon/tmp102.c | 2 +- drivers/input/touchscreen/sun4i-ts.c | 8 +++---- drivers/platform/x86/acerhdf.c | 9 ++++---- drivers/platform/x86/intel_mid_thermal.c | 9 ++++---- drivers/power/charger-manager.c | 2 +- drivers/power/power_supply_core.c | 2 +- drivers/thermal/armada_thermal.c | 2 +- drivers/thermal/db8500_thermal.c | 7 +++--- drivers/thermal/dove_thermal.c | 2 +- drivers/thermal/fair_share.c | 2 +- drivers/thermal/gov_bang_bang.c | 5 ++-- drivers/thermal/hisi_thermal.c | 4 ++-- drivers/thermal/imx_thermal.c | 27 +++++++++++----------- drivers/thermal/int340x_thermal/int3400_thermal.c | 2 +- .../thermal/int340x_thermal/int340x_thermal_zone.c | 10 ++++---- .../thermal/int340x_thermal/int340x_thermal_zone.h | 8 +++---- .../int340x_thermal/processor_thermal_device.c | 4 ++-- drivers/thermal/intel_quark_dts_thermal.c | 13 +++++------ drivers/thermal/intel_soc_dts_iosf.c | 8 +++---- drivers/thermal/kirkwood_thermal.c | 2 +- drivers/thermal/of-thermal.c | 14 +++++------ drivers/thermal/power_allocator.c | 16 ++++++------- drivers/thermal/qcom-spmi-temp-alarm.c | 2 +- drivers/thermal/rcar_thermal.c | 7 +++--- drivers/thermal/rockchip_thermal.c | 10 ++++---- drivers/thermal/samsung/exynos_tmu.c | 23 +++++++++--------- drivers/thermal/spear_thermal.c | 2 +- drivers/thermal/st/st_thermal.c | 5 ++-- drivers/thermal/step_wise.c | 4 ++-- drivers/thermal/tegra_soctherm.c | 4 ++-- drivers/thermal/thermal_core.c | 26 ++++++++++----------- drivers/thermal/thermal_hwmon.c | 10 ++++---- drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 10 ++++---- drivers/thermal/x86_pkg_temp_thermal.c | 10 ++++---- include/linux/thermal.h | 26 +++++++++------------ include/trace/events/thermal_power_allocator.h | 6 ++--- 39 files changed, 152 insertions(+), 167 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 6d4e44ea74ac..e66ad25d112f 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -529,8 +529,7 @@ static void acpi_thermal_check(void *data) /* sys I/F for generic thermal sysfs support */ -static int thermal_get_temp(struct thermal_zone_device *thermal, - unsigned long *temp) +static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp) { struct acpi_thermal *tz = thermal->devdata; int result; @@ -637,7 +636,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal, } static int thermal_get_trip_temp(struct thermal_zone_device *thermal, - int trip, unsigned long *temp) + int trip, int *temp) { struct acpi_thermal *tz = thermal->devdata; int i; @@ -690,7 +689,8 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal, } static int thermal_get_crit_temp(struct thermal_zone_device *thermal, - unsigned long *temperature) { + int *temperature) +{ struct acpi_thermal *tz = thermal->devdata; if (tz->trips.critical.flags.valid) { @@ -713,8 +713,8 @@ static int thermal_get_trend(struct thermal_zone_device *thermal, return -EINVAL; if (type == THERMAL_TRIP_ACTIVE) { - unsigned long trip_temp; - unsigned long temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET( + int trip_temp; + int temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET( tz->temperature, tz->kelvin_offset); if (thermal_get_trip_temp(thermal, trip, &trip_temp)) return -EINVAL; diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index fe41d5ae7cb2..e4e57bbafb10 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -104,7 +104,7 @@ static inline long lm75_reg_to_mc(s16 temp, u8 resolution) /* sysfs attributes for hwmon */ -static int lm75_read_temp(void *dev, long *temp) +static int lm75_read_temp(void *dev, int *temp) { struct lm75_data *data = lm75_update_device(dev); diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index dc0b76c5e302..feed30646d91 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -477,7 +477,7 @@ static int ntc_thermistor_get_ohm(struct ntc_data *data) return -EINVAL; } -static int ntc_read_temp(void *dev, long *temp) +static int ntc_read_temp(void *dev, int *temp) { struct ntc_data *data = dev_get_drvdata(dev); int ohm; diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 9da2735f1424..65482624ea2c 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -98,7 +98,7 @@ static struct tmp102 *tmp102_update_device(struct device *dev) return tmp102; } -static int tmp102_read_temp(void *dev, long *temp) +static int tmp102_read_temp(void *dev, int *temp) { struct tmp102 *tmp102 = tmp102_update_device(dev); diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index c0116994067d..485794376ee5 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -191,7 +191,7 @@ static void sun4i_ts_close(struct input_dev *dev) writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); } -static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp) +static int sun4i_get_temp(const struct sun4i_ts_data *ts, int *temp) { /* No temp_data until the first irq */ if (ts->temp_data == -1) @@ -202,7 +202,7 @@ static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp) return 0; } -static int sun4i_get_tz_temp(void *data, long *temp) +static int sun4i_get_tz_temp(void *data, int *temp) { return sun4i_get_temp(data, temp); } @@ -215,14 +215,14 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, char *buf) { struct sun4i_ts_data *ts = dev_get_drvdata(dev); - long temp; + int temp; int error; error = sun4i_get_temp(ts, &temp); if (error) return error; - return sprintf(buf, "%ld\n", temp); + return sprintf(buf, "%d\n", temp); } static ssize_t show_temp_label(struct device *dev, diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index 1ef02daddb60..460fa6708bfc 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c @@ -346,8 +346,7 @@ static void acerhdf_check_param(struct thermal_zone_device *thermal) * as late as the polling interval is since we can't do that in the respective * accessors of the module parameters. */ -static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal, - unsigned long *t) +static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal, int *t) { int temp, err = 0; @@ -453,7 +452,7 @@ static int acerhdf_get_trip_type(struct thermal_zone_device *thermal, int trip, } static int acerhdf_get_trip_hyst(struct thermal_zone_device *thermal, int trip, - unsigned long *temp) + int *temp) { if (trip != 0) return -EINVAL; @@ -464,7 +463,7 @@ static int acerhdf_get_trip_hyst(struct thermal_zone_device *thermal, int trip, } static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip, - unsigned long *temp) + int *temp) { if (trip == 0) *temp = fanon; @@ -477,7 +476,7 @@ static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip, } static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal, - unsigned long *temperature) + int *temperature) { *temperature = ACERHDF_TEMP_CRIT; return 0; diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index 0944e834af8d..9f713b832ba3 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c @@ -132,7 +132,7 @@ static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max) * to achieve very close approximate temp value with less than * 0.5C error */ -static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp) +static int adc_to_temp(int direct, uint16_t adc_val, int *tp) { int temp; @@ -174,14 +174,13 @@ static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp) * * Can sleep */ -static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp) +static int mid_read_temp(struct thermal_zone_device *tzd, int *temp) { struct thermal_device_info *td_info = tzd->devdata; uint16_t adc_val, addr; uint8_t data = 0; int ret; - unsigned long curr_temp; - + int curr_temp; addr = td_info->chnl_addr; @@ -453,7 +452,7 @@ static SIMPLE_DEV_PM_OPS(mid_thermal_pm, * * Can sleep */ -static int read_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp) +static int read_curr_temp(struct thermal_zone_device *tzd, int *temp) { WARN_ON(tzd == NULL); return mid_read_temp(tzd, temp); diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index 1c202ccbd2a6..907293e6f2a4 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c @@ -619,7 +619,7 @@ static int cm_get_battery_temperature(struct charger_manager *cm, #ifdef CONFIG_THERMAL if (cm->tzd_batt) { - ret = thermal_zone_get_temp(cm->tzd_batt, (unsigned long *)temp); + ret = thermal_zone_get_temp(cm->tzd_batt, temp); if (!ret) /* Calibrate temperature unit */ *temp /= 100; diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 869284c2e1e8..456987c88baa 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -557,7 +557,7 @@ EXPORT_SYMBOL_GPL(power_supply_unreg_notifier); #ifdef CONFIG_THERMAL static int power_supply_read_temp(struct thermal_zone_device *tzd, - unsigned long *temp) + int *temp) { struct power_supply *psy; union power_supply_propval val; diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c index 01255fd65135..26b8d326546a 100644 --- a/drivers/thermal/armada_thermal.c +++ b/drivers/thermal/armada_thermal.c @@ -155,7 +155,7 @@ static bool armada_is_valid(struct armada_thermal_priv *priv) } static int armada_get_temp(struct thermal_zone_device *thermal, - unsigned long *temp) + int *temp) { struct armada_thermal_priv *priv = thermal->devdata; unsigned long reg; diff --git a/drivers/thermal/db8500_thermal.c b/drivers/thermal/db8500_thermal.c index 2fb273c4baa9..652acd8fbe48 100644 --- a/drivers/thermal/db8500_thermal.c +++ b/drivers/thermal/db8500_thermal.c @@ -107,8 +107,7 @@ static int db8500_cdev_unbind(struct thermal_zone_device *thermal, } /* Callback to get current temperature */ -static int db8500_sys_get_temp(struct thermal_zone_device *thermal, - unsigned long *temp) +static int db8500_sys_get_temp(struct thermal_zone_device *thermal, int *temp) { struct db8500_thermal_zone *pzone = thermal->devdata; @@ -180,7 +179,7 @@ static int db8500_sys_get_trip_type(struct thermal_zone_device *thermal, /* Callback to get trip point temperature */ static int db8500_sys_get_trip_temp(struct thermal_zone_device *thermal, - int trip, unsigned long *temp) + int trip, int *temp) { struct db8500_thermal_zone *pzone = thermal->devdata; struct db8500_thsens_platform_data *ptrips = pzone->trip_tab; @@ -195,7 +194,7 @@ static int db8500_sys_get_trip_temp(struct thermal_zone_device *thermal, /* Callback to get critical trip point temperature */ static int db8500_sys_get_crit_temp(struct thermal_zone_device *thermal, - unsigned long *temp) + int *temp) { struct db8500_thermal_zone *pzone = thermal->devdata; struct db8500_thsens_platform_data *ptrips = pzone->trip_tab; diff --git a/drivers/thermal/dove_thermal.c b/drivers/thermal/dove_thermal.c index 09f6e304c274..a0bc9de42553 100644 --- a/drivers/thermal/dove_thermal.c +++ b/drivers/thermal/dove_thermal.c @@ -93,7 +93,7 @@ static int dove_init_sensor(const struct dove_thermal_priv *priv) } static int dove_get_temp(struct thermal_zone_device *thermal, - unsigned long *temp) + int *temp) { unsigned long reg; struct dove_thermal_priv *priv = thermal->devdata; diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c index c2c10bbe24d6..34fe36504a55 100644 --- a/drivers/thermal/fair_share.c +++ b/drivers/thermal/fair_share.c @@ -34,7 +34,7 @@ static int get_trip_level(struct thermal_zone_device *tz) { int count = 0; - unsigned long trip_temp; + int trip_temp; enum thermal_trip_type trip_type; if (tz->trips == 0 || !tz->ops->get_trip_temp) diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c index c5dd76b2ee74..70836c5b89bc 100644 --- a/drivers/thermal/gov_bang_bang.c +++ b/drivers/thermal/gov_bang_bang.c @@ -25,14 +25,13 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) { - long trip_temp; - unsigned long trip_hyst; + int trip_temp, trip_hyst; struct thermal_instance *instance; tz->ops->get_trip_temp(tz, trip, &trip_temp); tz->ops->get_trip_hyst(tz, trip, &trip_hyst); - dev_dbg(&tz->device, "Trip%d[temp=%ld]:temp=%d:hyst=%ld\n", + dev_dbg(&tz->device, "Trip%d[temp=%d]:temp=%d:hyst=%d\n", trip, trip_temp, tz->temperature, trip_hyst); diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index d5dd357ba57c..49aa068d1603 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -155,7 +155,7 @@ static void hisi_thermal_disable_sensor(struct hisi_thermal_data *data) mutex_unlock(&data->thermal_lock); } -static int hisi_thermal_get_temp(void *_sensor, long *temp) +static int hisi_thermal_get_temp(void *_sensor, int *temp) { struct hisi_thermal_sensor *sensor = _sensor; struct hisi_thermal_data *data = sensor->thermal; @@ -178,7 +178,7 @@ static int hisi_thermal_get_temp(void *_sensor, long *temp) data->irq_bind_sensor = sensor_id; mutex_unlock(&data->thermal_lock); - dev_dbg(&data->pdev->dev, "id=%d, irq=%d, temp=%ld, thres=%d\n", + dev_dbg(&data->pdev->dev, "id=%d, irq=%d, temp=%d, thres=%d\n", sensor->id, data->irq_enabled, *temp, sensor->thres_temp); /* * Bind irq to sensor for two cases: diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index fde4c2876d14..4bec1d3c3d27 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -98,10 +98,10 @@ struct imx_thermal_data { enum thermal_device_mode mode; struct regmap *tempmon; u32 c1, c2; /* See formula in imx_get_sensor_data() */ - unsigned long temp_passive; - unsigned long temp_critical; - unsigned long alarm_temp; - unsigned long last_temp; + int temp_passive; + int temp_critical; + int alarm_temp; + int last_temp; bool irq_enabled; int irq; struct clk *thermal_clk; @@ -109,7 +109,7 @@ struct imx_thermal_data { }; static void imx_set_panic_temp(struct imx_thermal_data *data, - signed long panic_temp) + int panic_temp) { struct regmap *map = data->tempmon; int critical_value; @@ -121,7 +121,7 @@ static void imx_set_panic_temp(struct imx_thermal_data *data, } static void imx_set_alarm_temp(struct imx_thermal_data *data, - signed long alarm_temp) + int alarm_temp) { struct regmap *map = data->tempmon; int alarm_value; @@ -133,7 +133,7 @@ static void imx_set_alarm_temp(struct imx_thermal_data *data, TEMPSENSE0_ALARM_VALUE_SHIFT); } -static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp) +static int imx_get_temp(struct thermal_zone_device *tz, int *temp) { struct imx_thermal_data *data = tz->devdata; struct regmap *map = data->tempmon; @@ -189,13 +189,13 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp) if (data->alarm_temp == data->temp_critical && *temp < data->temp_passive) { imx_set_alarm_temp(data, data->temp_passive); - dev_dbg(&tz->device, "thermal alarm off: T < %lu\n", + dev_dbg(&tz->device, "thermal alarm off: T < %d\n", data->alarm_temp / 1000); } } if (*temp != data->last_temp) { - dev_dbg(&tz->device, "millicelsius: %ld\n", *temp); + dev_dbg(&tz->device, "millicelsius: %d\n", *temp); data->last_temp = *temp; } @@ -262,8 +262,7 @@ static int imx_get_trip_type(struct thermal_zone_device *tz, int trip, return 0; } -static int imx_get_crit_temp(struct thermal_zone_device *tz, - unsigned long *temp) +static int imx_get_crit_temp(struct thermal_zone_device *tz, int *temp) { struct imx_thermal_data *data = tz->devdata; @@ -272,7 +271,7 @@ static int imx_get_crit_temp(struct thermal_zone_device *tz, } static int imx_get_trip_temp(struct thermal_zone_device *tz, int trip, - unsigned long *temp) + int *temp) { struct imx_thermal_data *data = tz->devdata; @@ -282,7 +281,7 @@ static int imx_get_trip_temp(struct thermal_zone_device *tz, int trip, } static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip, - unsigned long temp) + int temp) { struct imx_thermal_data *data = tz->devdata; @@ -434,7 +433,7 @@ static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev) { struct imx_thermal_data *data = dev; - dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n", + dev_dbg(&data->tz->device, "THERMAL ALARM: T > %d\n", data->alarm_temp / 1000); thermal_zone_device_update(data->tz); diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c index 031018e7a65b..5836e5554433 100644 --- a/drivers/thermal/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/int340x_thermal/int3400_thermal.c @@ -186,7 +186,7 @@ static int int3400_thermal_run_osc(acpi_handle handle, } static int int3400_thermal_get_temp(struct thermal_zone_device *thermal, - unsigned long *temp) + int *temp) { *temp = 20 * 1000; /* faked temp sensor with 20C */ return 0; diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c index 1e25133d35e2..b9b2666aa94c 100644 --- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c @@ -20,7 +20,7 @@ #include "int340x_thermal_zone.h" static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone, - unsigned long *temp) + int *temp) { struct int34x_thermal_zone *d = zone->devdata; unsigned long long tmp; @@ -49,7 +49,7 @@ static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone, } static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone, - int trip, unsigned long *temp) + int trip, int *temp) { struct int34x_thermal_zone *d = zone->devdata; int i; @@ -114,7 +114,7 @@ static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone, } static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone, - int trip, unsigned long temp) + int trip, int temp) { struct int34x_thermal_zone *d = zone->devdata; acpi_status status; @@ -136,7 +136,7 @@ static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone, static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone, - int trip, unsigned long *temp) + int trip, int *temp) { struct int34x_thermal_zone *d = zone->devdata; acpi_status status; @@ -163,7 +163,7 @@ static struct thermal_zone_device_ops int340x_thermal_zone_ops = { }; static int int340x_thermal_get_trip_config(acpi_handle handle, char *name, - unsigned long *temp) + int *temp) { unsigned long long r; acpi_status status; diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h index 9f38ab72c4bf..aaadf724ff2e 100644 --- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h +++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h @@ -21,7 +21,7 @@ #define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10 struct active_trip { - unsigned long temp; + int temp; int id; bool valid; }; @@ -31,11 +31,11 @@ struct int34x_thermal_zone { struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT]; unsigned long *aux_trips; int aux_trip_nr; - unsigned long psv_temp; + int psv_temp; int psv_trip_id; - unsigned long crt_temp; + int crt_temp; int crt_trip_id; - unsigned long hot_temp; + int hot_temp; int hot_trip_id; struct thermal_zone_device *zone; struct thermal_zone_device_ops *override_ops; diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c index 3df3dc34b124..ccc0ad02d066 100644 --- a/drivers/thermal/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c @@ -145,7 +145,7 @@ static int get_tjmax(void) return -EINVAL; } -static int read_temp_msr(unsigned long *temp) +static int read_temp_msr(int *temp) { int cpu; u32 eax, edx; @@ -177,7 +177,7 @@ err_ret: } static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone, - unsigned long *temp) + int *temp) { int ret; diff --git a/drivers/thermal/intel_quark_dts_thermal.c b/drivers/thermal/intel_quark_dts_thermal.c index 4434ec812cb7..5ed90e6c8a64 100644 --- a/drivers/thermal/intel_quark_dts_thermal.c +++ b/drivers/thermal/intel_quark_dts_thermal.c @@ -186,7 +186,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd) return ret; } -static int _get_trip_temp(int trip, unsigned long *temp) +static int _get_trip_temp(int trip, int *temp) { int status; u32 out; @@ -212,19 +212,18 @@ static int _get_trip_temp(int trip, unsigned long *temp) } static inline int sys_get_trip_temp(struct thermal_zone_device *tzd, - int trip, unsigned long *temp) + int trip, int *temp) { return _get_trip_temp(trip, temp); } -static inline int sys_get_crit_temp(struct thermal_zone_device *tzd, - unsigned long *temp) +static inline int sys_get_crit_temp(struct thermal_zone_device *tzd, int *temp) { return _get_trip_temp(QRK_DTS_ID_TP_CRITICAL, temp); } static int update_trip_temp(struct soc_sensor_entry *aux_entry, - int trip, unsigned long temp) + int trip, int temp) { u32 out; u32 temp_out; @@ -272,7 +271,7 @@ failed: } static inline int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, - unsigned long temp) + int temp) { return update_trip_temp(tzd->devdata, trip, temp); } @@ -289,7 +288,7 @@ static int sys_get_trip_type(struct thermal_zone_device *thermal, } static int sys_get_curr_temp(struct thermal_zone_device *tzd, - unsigned long *temp) + int *temp) { u32 out; int ret; diff --git a/drivers/thermal/intel_soc_dts_iosf.c b/drivers/thermal/intel_soc_dts_iosf.c index 42e4b6ac3875..5841d1d72996 100644 --- a/drivers/thermal/intel_soc_dts_iosf.c +++ b/drivers/thermal/intel_soc_dts_iosf.c @@ -80,7 +80,7 @@ err_ret: } static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip, - unsigned long *temp) + int *temp) { int status; u32 out; @@ -106,7 +106,7 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip, } static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts, - int thres_index, unsigned long temp, + int thres_index, int temp, enum thermal_trip_type trip_type) { int status; @@ -196,7 +196,7 @@ err_restore_ptps: } static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, - unsigned long temp) + int temp) { struct intel_soc_dts_sensor_entry *dts = tzd->devdata; struct intel_soc_dts_sensors *sensors = dts->sensors; @@ -226,7 +226,7 @@ static int sys_get_trip_type(struct thermal_zone_device *tzd, } static int sys_get_curr_temp(struct thermal_zone_device *tzd, - unsigned long *temp) + int *temp) { int status; u32 out; diff --git a/drivers/thermal/kirkwood_thermal.c b/drivers/thermal/kirkwood_thermal.c index 11041fe63dc2..892236621767 100644 --- a/drivers/thermal/kirkwood_thermal.c +++ b/drivers/thermal/kirkwood_thermal.c @@ -33,7 +33,7 @@ struct kirkwood_thermal_priv { }; static int kirkwood_get_temp(struct thermal_zone_device *thermal, - unsigned long *temp) + int *temp) { unsigned long reg; struct kirkwood_thermal_priv *priv = thermal->devdata; diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index b295b2b6c191..42b7d4253b94 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -91,7 +91,7 @@ struct __thermal_zone { /*** DT thermal zone device callbacks ***/ static int of_thermal_get_temp(struct thermal_zone_device *tz, - unsigned long *temp) + int *temp) { struct __thermal_zone *data = tz->devdata; @@ -177,7 +177,7 @@ EXPORT_SYMBOL_GPL(of_thermal_get_trip_points); * Return: zero on success, error code otherwise */ static int of_thermal_set_emul_temp(struct thermal_zone_device *tz, - unsigned long temp) + int temp) { struct __thermal_zone *data = tz->devdata; @@ -311,7 +311,7 @@ static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip, } static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip, - unsigned long *temp) + int *temp) { struct __thermal_zone *data = tz->devdata; @@ -324,7 +324,7 @@ static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip, } static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip, - unsigned long temp) + int temp) { struct __thermal_zone *data = tz->devdata; @@ -338,7 +338,7 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip, } static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip, - unsigned long *hyst) + int *hyst) { struct __thermal_zone *data = tz->devdata; @@ -351,7 +351,7 @@ static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip, } static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip, - unsigned long hyst) + int hyst) { struct __thermal_zone *data = tz->devdata; @@ -365,7 +365,7 @@ static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip, } static int of_thermal_get_crit_temp(struct thermal_zone_device *tz, - unsigned long *temp) + int *temp) { struct __thermal_zone *data = tz->devdata; int i; diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c index 4672250b329f..045aea59ce9d 100644 --- a/drivers/thermal/power_allocator.c +++ b/drivers/thermal/power_allocator.c @@ -92,8 +92,8 @@ struct power_allocator_params { * Return: The power budget for the next period. */ static u32 pid_controller(struct thermal_zone_device *tz, - unsigned long current_temp, - unsigned long control_temp, + int current_temp, + int control_temp, u32 max_allocatable_power) { s64 p, i, d, power_range; @@ -102,7 +102,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, max_power_frac = int_to_frac(max_allocatable_power); - err = ((s32)control_temp - (s32)current_temp); + err = control_temp - current_temp; err = int_to_frac(err); /* Calculate the proportional term */ @@ -223,8 +223,8 @@ static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors, } static int allocate_power(struct thermal_zone_device *tz, - unsigned long current_temp, - unsigned long control_temp) + int current_temp, + int control_temp) { struct thermal_instance *instance; struct power_allocator_params *params = tz->governor_data; @@ -326,7 +326,7 @@ static int allocate_power(struct thermal_zone_device *tz, granted_power, total_granted_power, num_actors, power_range, max_allocatable_power, current_temp, - (s32)control_temp - (s32)current_temp); + control_temp - current_temp); devm_kfree(&tz->device, req_power); unlock: @@ -411,7 +411,7 @@ static int power_allocator_bind(struct thermal_zone_device *tz) { int ret; struct power_allocator_params *params; - unsigned long switch_on_temp, control_temp; + int switch_on_temp, control_temp; u32 temperature_threshold; if (!tz->tzp || !tz->tzp->sustainable_power) { @@ -476,7 +476,7 @@ static void power_allocator_unbind(struct thermal_zone_device *tz) static int power_allocator_throttle(struct thermal_zone_device *tz, int trip) { int ret; - unsigned long switch_on_temp, control_temp, current_temp; + int switch_on_temp, control_temp, current_temp; struct power_allocator_params *params = tz->governor_data; /* diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c index c8d27b8fb9ec..b677aada5b52 100644 --- a/drivers/thermal/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom-spmi-temp-alarm.c @@ -117,7 +117,7 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip) return 0; } -static int qpnp_tm_get_temp(void *data, long *temp) +static int qpnp_tm_get_temp(void *data, int *temp) { struct qpnp_tm_chip *chip = data; int ret, mili_celsius; diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index fe4e767018c4..5d4ae7d705e0 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -200,8 +200,7 @@ err_out_unlock: return ret; } -static int rcar_thermal_get_temp(struct thermal_zone_device *zone, - unsigned long *temp) +static int rcar_thermal_get_temp(struct thermal_zone_device *zone, int *temp) { struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); @@ -235,7 +234,7 @@ static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone, } static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone, - int trip, unsigned long *temp) + int trip, int *temp) { struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); struct device *dev = rcar_priv_to_dev(priv); @@ -299,7 +298,7 @@ static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable) static void rcar_thermal_work(struct work_struct *work) { struct rcar_thermal_priv *priv; - unsigned long cctemp, nctemp; + int cctemp, nctemp; priv = container_of(work, struct rcar_thermal_priv, work.work); diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index cd8f5f93b42c..c89ffb26a354 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -64,7 +64,7 @@ struct rockchip_tsadc_chip { void (*control)(void __iomem *reg, bool on); /* Per-sensor methods */ - int (*get_temp)(int chn, void __iomem *reg, long *temp); + int (*get_temp)(int chn, void __iomem *reg, int *temp); void (*set_tshut_temp)(int chn, void __iomem *reg, long temp); void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m); }; @@ -191,7 +191,7 @@ static u32 rk_tsadcv2_temp_to_code(long temp) return 0; } -static long rk_tsadcv2_code_to_temp(u32 code) +static int rk_tsadcv2_code_to_temp(u32 code) { unsigned int low = 0; unsigned int high = ARRAY_SIZE(v2_code_table) - 1; @@ -277,7 +277,7 @@ static void rk_tsadcv2_control(void __iomem *regs, bool enable) writel_relaxed(val, regs + TSADCV2_AUTO_CON); } -static int rk_tsadcv2_get_temp(int chn, void __iomem *regs, long *temp) +static int rk_tsadcv2_get_temp(int chn, void __iomem *regs, int *temp) { u32 val; @@ -366,7 +366,7 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev) return IRQ_HANDLED; } -static int rockchip_thermal_get_temp(void *_sensor, long *out_temp) +static int rockchip_thermal_get_temp(void *_sensor, int *out_temp) { struct rockchip_thermal_sensor *sensor = _sensor; struct rockchip_thermal_data *thermal = sensor->thermal; @@ -374,7 +374,7 @@ static int rockchip_thermal_get_temp(void *_sensor, long *out_temp) int retval; retval = tsadc->get_temp(sensor->id, thermal->regs, out_temp); - dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %ld, retval: %d\n", + dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n", sensor->id, *out_temp, retval); return retval; diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 531f4b179871..9ec29a33aeea 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -207,8 +207,7 @@ struct exynos_tmu_data { int (*tmu_initialize)(struct platform_device *pdev); void (*tmu_control)(struct platform_device *pdev, bool on); int (*tmu_read)(struct exynos_tmu_data *data); - void (*tmu_set_emulation)(struct exynos_tmu_data *data, - unsigned long temp); + void (*tmu_set_emulation)(struct exynos_tmu_data *data, int temp); void (*tmu_clear_irqs)(struct exynos_tmu_data *data); }; @@ -216,7 +215,7 @@ static void exynos_report_trigger(struct exynos_tmu_data *p) { char data[10], *envp[] = { data, NULL }; struct thermal_zone_device *tz = p->tzd; - unsigned long temp; + int temp; unsigned int i; if (!tz) { @@ -517,7 +516,7 @@ static int exynos5433_tmu_initialize(struct platform_device *pdev) struct thermal_zone_device *tz = data->tzd; unsigned int status, trim_info; unsigned int rising_threshold = 0, falling_threshold = 0; - unsigned long temp, temp_hist; + int temp, temp_hist; int ret = 0, threshold_code, i, sensor_id, cal_type; status = readb(data->base + EXYNOS_TMU_REG_STATUS); @@ -610,7 +609,7 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev) struct exynos_tmu_data *data = platform_get_drvdata(pdev); unsigned int trim_info = 0, con, rising_threshold; int ret = 0, threshold_code; - unsigned long crit_temp = 0; + int crit_temp = 0; /* * For exynos5440 soc triminfo value is swapped between TMU0 and @@ -663,7 +662,7 @@ static int exynos7_tmu_initialize(struct platform_device *pdev) unsigned int status, trim_info; unsigned int rising_threshold = 0, falling_threshold = 0; int ret = 0, threshold_code, i; - unsigned long temp, temp_hist; + int temp, temp_hist; unsigned int reg_off, bit_off; status = readb(data->base + EXYNOS_TMU_REG_STATUS); @@ -876,7 +875,7 @@ static void exynos7_tmu_control(struct platform_device *pdev, bool on) writel(con, data->base + EXYNOS_TMU_REG_CONTROL); } -static int exynos_get_temp(void *p, long *temp) +static int exynos_get_temp(void *p, int *temp) { struct exynos_tmu_data *data = p; @@ -896,7 +895,7 @@ static int exynos_get_temp(void *p, long *temp) #ifdef CONFIG_THERMAL_EMULATION static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val, - unsigned long temp) + int temp) { if (temp) { temp /= MCELSIUS; @@ -926,7 +925,7 @@ static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val, } static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data, - unsigned long temp) + int temp) { unsigned int val; u32 emul_con; @@ -946,7 +945,7 @@ static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data, } static void exynos5440_tmu_set_emulation(struct exynos_tmu_data *data, - unsigned long temp) + int temp) { unsigned int val; @@ -955,7 +954,7 @@ static void exynos5440_tmu_set_emulation(struct exynos_tmu_data *data, writel(val, data->base + EXYNOS5440_TMU_S0_7_DEBUG); } -static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp) +static int exynos_tmu_set_emulation(void *drv_data, int temp) { struct exynos_tmu_data *data = drv_data; int ret = -EINVAL; @@ -978,7 +977,7 @@ out: #else #define exynos4412_tmu_set_emulation NULL #define exynos5440_tmu_set_emulation NULL -static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp) +static int exynos_tmu_set_emulation(void *drv_data, int temp) { return -EINVAL; } #endif /* CONFIG_THERMAL_EMULATION */ diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c index bddb71744a6c..534dd9136662 100644 --- a/drivers/thermal/spear_thermal.c +++ b/drivers/thermal/spear_thermal.c @@ -38,7 +38,7 @@ struct spear_thermal_dev { }; static inline int thermal_get_temp(struct thermal_zone_device *thermal, - unsigned long *temp) + int *temp) { struct spear_thermal_dev *stdev = thermal->devdata; diff --git a/drivers/thermal/st/st_thermal.c b/drivers/thermal/st/st_thermal.c index 76c515dd802b..44cbba99716a 100644 --- a/drivers/thermal/st/st_thermal.c +++ b/drivers/thermal/st/st_thermal.c @@ -111,8 +111,7 @@ static int st_thermal_calibration(struct st_thermal_sensor *sensor) } /* Callback to get temperature from HW*/ -static int st_thermal_get_temp(struct thermal_zone_device *th, - unsigned long *temperature) +static int st_thermal_get_temp(struct thermal_zone_device *th, int *temperature) { struct st_thermal_sensor *sensor = th->devdata; struct device *dev = sensor->dev; @@ -159,7 +158,7 @@ static int st_thermal_get_trip_type(struct thermal_zone_device *th, } static int st_thermal_get_trip_temp(struct thermal_zone_device *th, - int trip, unsigned long *temp) + int trip, int *temp) { struct st_thermal_sensor *sensor = th->devdata; struct device *dev = sensor->dev; diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c index 5a0f12d08e8b..2f9f7086ac3d 100644 --- a/drivers/thermal/step_wise.c +++ b/drivers/thermal/step_wise.c @@ -113,7 +113,7 @@ static void update_passive_instance(struct thermal_zone_device *tz, static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) { - long trip_temp; + int trip_temp; enum thermal_trip_type trip_type; enum thermal_trend trend; struct thermal_instance *instance; @@ -135,7 +135,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) trace_thermal_zone_trip(tz, trip, trip_type); } - dev_dbg(&tz->device, "Trip%d[type=%d,temp=%ld]:trend=%d,throttle=%d\n", + dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n", trip, trip_type, trip_temp, trend, throttle); mutex_lock(&tz->lock); diff --git a/drivers/thermal/tegra_soctherm.c b/drivers/thermal/tegra_soctherm.c index 9197fc05c5cc..74ea5765938b 100644 --- a/drivers/thermal/tegra_soctherm.c +++ b/drivers/thermal/tegra_soctherm.c @@ -293,7 +293,7 @@ static int enable_tsensor(struct tegra_soctherm *tegra, * H denotes an addition of 0.5 Celsius and N denotes negation * of the final value. */ -static long translate_temp(u16 val) +static int translate_temp(u16 val) { long t; @@ -306,7 +306,7 @@ static long translate_temp(u16 val) return t; } -static int tegra_thermctl_get_temp(void *data, long *out_temp) +static int tegra_thermctl_get_temp(void *data, int *out_temp) { struct tegra_thermctl_zone *zone = data; u32 val; diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index c4700950e42e..387c4287fc74 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -426,7 +426,7 @@ static void handle_non_critical_trips(struct thermal_zone_device *tz, static void handle_critical_trips(struct thermal_zone_device *tz, int trip, enum thermal_trip_type trip_type) { - long trip_temp; + int trip_temp; tz->ops->get_trip_temp(tz, trip, &trip_temp); @@ -474,12 +474,12 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) * * Return: On success returns 0, an error code otherwise */ -int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp) +int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) { int ret = -EINVAL; #ifdef CONFIG_THERMAL_EMULATION int count; - unsigned long crit_temp = -1UL; + int crit_temp = INT_MAX; enum thermal_trip_type type; #endif @@ -516,8 +516,7 @@ EXPORT_SYMBOL_GPL(thermal_zone_get_temp); static void update_temperature(struct thermal_zone_device *tz) { - long temp; - int ret; + int temp, ret; ret = thermal_zone_get_temp(tz, &temp); if (ret) { @@ -577,15 +576,14 @@ static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf) { struct thermal_zone_device *tz = to_thermal_zone(dev); - long temperature; - int ret; + int temperature, ret; ret = thermal_zone_get_temp(tz, &temperature); if (ret) return ret; - return sprintf(buf, "%ld\n", temperature); + return sprintf(buf, "%d\n", temperature); } static ssize_t @@ -689,7 +687,7 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr, { struct thermal_zone_device *tz = to_thermal_zone(dev); int trip, ret; - long temperature; + int temperature; if (!tz->ops->get_trip_temp) return -EPERM; @@ -702,7 +700,7 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr, if (ret) return ret; - return sprintf(buf, "%ld\n", temperature); + return sprintf(buf, "%d\n", temperature); } static ssize_t @@ -711,7 +709,7 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, { struct thermal_zone_device *tz = to_thermal_zone(dev); int trip, ret; - unsigned long temperature; + int temperature; if (!tz->ops->set_trip_hyst) return -EPERM; @@ -719,7 +717,7 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip)) return -EINVAL; - if (kstrtoul(buf, 10, &temperature)) + if (kstrtoint(buf, 10, &temperature)) return -EINVAL; /* @@ -738,7 +736,7 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr, { struct thermal_zone_device *tz = to_thermal_zone(dev); int trip, ret; - unsigned long temperature; + int temperature; if (!tz->ops->get_trip_hyst) return -EPERM; @@ -748,7 +746,7 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr, ret = tz->ops->get_trip_hyst(tz, trip, &temperature); - return ret ? ret : sprintf(buf, "%ld\n", temperature); + return ret ? ret : sprintf(buf, "%d\n", temperature); } static ssize_t diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c index 1967bee4f076..06fd2ed9ef9d 100644 --- a/drivers/thermal/thermal_hwmon.c +++ b/drivers/thermal/thermal_hwmon.c @@ -69,7 +69,7 @@ static DEVICE_ATTR(name, 0444, name_show, NULL); static ssize_t temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) { - long temperature; + int temperature; int ret; struct thermal_hwmon_attr *hwmon_attr = container_of(attr, struct thermal_hwmon_attr, attr); @@ -83,7 +83,7 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) if (ret) return ret; - return sprintf(buf, "%ld\n", temperature); + return sprintf(buf, "%d\n", temperature); } static ssize_t @@ -95,14 +95,14 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, char *buf) = container_of(hwmon_attr, struct thermal_hwmon_temp, temp_crit); struct thermal_zone_device *tz = temp->tz; - long temperature; + int temperature; int ret; ret = tz->ops->get_trip_temp(tz, 0, &temperature); if (ret) return ret; - return sprintf(buf, "%ld\n", temperature); + return sprintf(buf, "%d\n", temperature); } @@ -142,7 +142,7 @@ thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon, static bool thermal_zone_crit_temp_valid(struct thermal_zone_device *tz) { - unsigned long temp; + int temp; return tz->ops->get_crit_temp && !tz->ops->get_crit_temp(tz, &temp); } diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c index c7c5b3779dac..b213a1222295 100644 --- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c +++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c @@ -76,14 +76,14 @@ static inline int ti_thermal_hotspot_temperature(int t, int s, int c) /* thermal zone ops */ /* Get temperature callback function for thermal zone */ -static inline int __ti_thermal_get_temp(void *devdata, long *temp) +static inline int __ti_thermal_get_temp(void *devdata, int *temp) { struct thermal_zone_device *pcb_tz = NULL; struct ti_thermal_data *data = devdata; struct ti_bandgap *bgp; const struct ti_temp_sensor *s; int ret, tmp, slope, constant; - unsigned long pcb_temp; + int pcb_temp; if (!data) return 0; @@ -119,7 +119,7 @@ static inline int __ti_thermal_get_temp(void *devdata, long *temp) } static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal, - unsigned long *temp) + int *temp) { struct ti_thermal_data *data = thermal->devdata; @@ -229,7 +229,7 @@ static int ti_thermal_get_trip_type(struct thermal_zone_device *thermal, /* Get trip temperature callback functions for thermal zone */ static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal, - int trip, unsigned long *temp) + int trip, int *temp) { if (!ti_thermal_is_valid_trip(trip)) return -EINVAL; @@ -280,7 +280,7 @@ static int ti_thermal_get_trend(struct thermal_zone_device *thermal, /* Get critical temperature callback functions for thermal zone */ static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal, - unsigned long *temp) + int *temp) { /* shutdown zone */ return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp); diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c index 50d1d2cb091a..7fc919f7da4d 100644 --- a/drivers/thermal/x86_pkg_temp_thermal.c +++ b/drivers/thermal/x86_pkg_temp_thermal.c @@ -164,7 +164,7 @@ err_ret: return err; } -static int sys_get_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp) +static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp) { u32 eax, edx; struct phy_dev_entry *phy_dev_entry; @@ -175,7 +175,7 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, unsigned long *tem if (eax & 0x80000000) { *temp = phy_dev_entry->tj_max - ((eax >> 16) & 0x7f) * 1000; - pr_debug("sys_get_curr_temp %ld\n", *temp); + pr_debug("sys_get_curr_temp %d\n", *temp); return 0; } @@ -183,7 +183,7 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd, unsigned long *tem } static int sys_get_trip_temp(struct thermal_zone_device *tzd, - int trip, unsigned long *temp) + int trip, int *temp) { u32 eax, edx; struct phy_dev_entry *phy_dev_entry; @@ -214,13 +214,13 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd, *temp = phy_dev_entry->tj_max - thres_reg_value * 1000; else *temp = 0; - pr_debug("sys_get_trip_temp %ld\n", *temp); + pr_debug("sys_get_trip_temp %d\n", *temp); return 0; } static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, - unsigned long temp) + int temp) { u32 l, h; struct phy_dev_entry *phy_dev_entry; diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 037e9df2f610..17292fee8686 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -92,23 +92,19 @@ struct thermal_zone_device_ops { struct thermal_cooling_device *); int (*unbind) (struct thermal_zone_device *, struct thermal_cooling_device *); - int (*get_temp) (struct thermal_zone_device *, unsigned long *); + int (*get_temp) (struct thermal_zone_device *, int *); int (*get_mode) (struct thermal_zone_device *, enum thermal_device_mode *); int (*set_mode) (struct thermal_zone_device *, enum thermal_device_mode); int (*get_trip_type) (struct thermal_zone_device *, int, enum thermal_trip_type *); - int (*get_trip_temp) (struct thermal_zone_device *, int, - unsigned long *); - int (*set_trip_temp) (struct thermal_zone_device *, int, - unsigned long); - int (*get_trip_hyst) (struct thermal_zone_device *, int, - unsigned long *); - int (*set_trip_hyst) (struct thermal_zone_device *, int, - unsigned long); - int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *); - int (*set_emul_temp) (struct thermal_zone_device *, unsigned long); + int (*get_trip_temp) (struct thermal_zone_device *, int, int *); + int (*set_trip_temp) (struct thermal_zone_device *, int, int); + int (*get_trip_hyst) (struct thermal_zone_device *, int, int *); + int (*set_trip_hyst) (struct thermal_zone_device *, int, int); + int (*get_crit_temp) (struct thermal_zone_device *, int *); + int (*set_emul_temp) (struct thermal_zone_device *, int); int (*get_trend) (struct thermal_zone_device *, int, enum thermal_trend *); int (*notify) (struct thermal_zone_device *, int, @@ -332,9 +328,9 @@ struct thermal_genl_event { * temperature. */ struct thermal_zone_of_device_ops { - int (*get_temp)(void *, long *); + int (*get_temp)(void *, int *); int (*get_trend)(void *, long *); - int (*set_emul_temp)(void *, unsigned long); + int (*set_emul_temp)(void *, int); }; /** @@ -406,7 +402,7 @@ thermal_of_cooling_device_register(struct device_node *np, char *, void *, const struct thermal_cooling_device_ops *); void thermal_cooling_device_unregister(struct thermal_cooling_device *); struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name); -int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp); +int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp); int get_tz_trend(struct thermal_zone_device *, int); struct thermal_instance *get_thermal_instance(struct thermal_zone_device *, @@ -457,7 +453,7 @@ static inline struct thermal_zone_device *thermal_zone_get_zone_by_name( const char *name) { return ERR_PTR(-ENODEV); } static inline int thermal_zone_get_temp( - struct thermal_zone_device *tz, unsigned long *temp) + struct thermal_zone_device *tz, int *temp) { return -ENODEV; } static inline int get_tz_trend(struct thermal_zone_device *tz, int trip) { return -ENODEV; } diff --git a/include/trace/events/thermal_power_allocator.h b/include/trace/events/thermal_power_allocator.h index 12e1321c4e0c..5afae8fe3795 100644 --- a/include/trace/events/thermal_power_allocator.h +++ b/include/trace/events/thermal_power_allocator.h @@ -11,7 +11,7 @@ TRACE_EVENT(thermal_power_allocator, u32 total_req_power, u32 *granted_power, u32 total_granted_power, size_t num_actors, u32 power_range, u32 max_allocatable_power, - unsigned long current_temp, s32 delta_temp), + int current_temp, s32 delta_temp), TP_ARGS(tz, req_power, total_req_power, granted_power, total_granted_power, num_actors, power_range, max_allocatable_power, current_temp, delta_temp), @@ -24,7 +24,7 @@ TRACE_EVENT(thermal_power_allocator, __field(size_t, num_actors ) __field(u32, power_range ) __field(u32, max_allocatable_power ) - __field(unsigned long, current_temp ) + __field(int, current_temp ) __field(s32, delta_temp ) ), TP_fast_assign( @@ -42,7 +42,7 @@ TRACE_EVENT(thermal_power_allocator, __entry->delta_temp = delta_temp; ), - TP_printk("thermal_zone_id=%d req_power={%s} total_req_power=%u granted_power={%s} total_granted_power=%u power_range=%u max_allocatable_power=%u current_temperature=%lu delta_temperature=%d", + TP_printk("thermal_zone_id=%d req_power={%s} total_req_power=%u granted_power={%s} total_granted_power=%u power_range=%u max_allocatable_power=%u current_temperature=%d delta_temperature=%d", __entry->tz_id, __print_array(__get_dynamic_array(req_power), __entry->num_actors, 4), -- cgit v1.3-6-gb490 From f6be0584930995f88ea3381cbcbcb315c2a184ad Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 6 Jul 2015 09:46:14 +0200 Subject: thermal: trivial: fix typo in comment Signed-off-by: Sascha Hauer Acked-by: Eduardo Valentin Signed-off-by: Zhang Rui --- drivers/thermal/thermal_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 387c4287fc74..fcd1c176c160 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -465,7 +465,7 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) } /** - * thermal_zone_get_temp() - returns its the temperature of thermal zone + * thermal_zone_get_temp() - returns the temperature of a thermal zone * @tz: a valid pointer to a struct thermal_zone_device * @temp: a valid pointer to where to store the resulting temperature. * -- cgit v1.3-6-gb490 From dbdf2532b46256584447cd7e742bfb1b31ac56c4 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 6 Jul 2015 09:46:15 +0200 Subject: thermal: remove unnecessary call to thermal_zone_device_set_polling When the thermal zone has no get_temp callback then thermal_zone_device_register() calls thermal_zone_device_set_polling() with a polling delay of 0. This only cancels the poll_queue. Since the poll_queue hasn't been scheduled this is a no-op. Remove it. Signed-off-by: Sascha Hauer Acked-by: Eduardo Valentin Signed-off-by: Zhang Rui --- drivers/thermal/thermal_core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index fcd1c176c160..305e381d8b0c 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1873,9 +1873,6 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type, INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check); - if (!tz->ops->get_temp) - thermal_zone_device_set_polling(tz, 0); - thermal_zone_device_update(tz); return tz; -- cgit v1.3-6-gb490 From 79e5421cf0bd9b3e56f523e95e3511757edb9616 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 6 Jul 2015 09:46:16 +0200 Subject: thermal: Use IS_ENABLED instead of #ifdef Use IS_ENABLED(CONFIG_THERMAL_EMULATION) to make the code more readable and to get rid of the addtional #ifdef around the variable definitions in thermal_zone_get_temp(). Signed-off-by: Sascha Hauer Reviewed-by: Lukasz Majewski Signed-off-by: Zhang Rui --- drivers/thermal/thermal_core.c | 45 ++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 305e381d8b0c..9599465abeac 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -477,11 +477,9 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) { int ret = -EINVAL; -#ifdef CONFIG_THERMAL_EMULATION int count; int crit_temp = INT_MAX; enum thermal_trip_type type; -#endif if (!tz || IS_ERR(tz) || !tz->ops->get_temp) goto exit; @@ -489,25 +487,21 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) mutex_lock(&tz->lock); ret = tz->ops->get_temp(tz, temp); -#ifdef CONFIG_THERMAL_EMULATION - if (!tz->emul_temperature) - goto skip_emul; - - for (count = 0; count < tz->trips; count++) { - ret = tz->ops->get_trip_type(tz, count, &type); - if (!ret && type == THERMAL_TRIP_CRITICAL) { - ret = tz->ops->get_trip_temp(tz, count, &crit_temp); - break; - } - } - if (ret) - goto skip_emul; + if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) { + for (count = 0; count < tz->trips; count++) { + ret = tz->ops->get_trip_type(tz, count, &type); + if (!ret && type == THERMAL_TRIP_CRITICAL) { + ret = tz->ops->get_trip_temp(tz, count, + &crit_temp); + break; + } + } - if (*temp < crit_temp) - *temp = tz->emul_temperature; -skip_emul: -#endif + if (!ret && *temp < crit_temp) + *temp = tz->emul_temperature; + } + mutex_unlock(&tz->lock); exit: return ret; @@ -866,7 +860,6 @@ available_policies_show(struct device *dev, struct device_attribute *devattr, return count; } -#ifdef CONFIG_THERMAL_EMULATION static ssize_t emul_temp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -892,7 +885,6 @@ emul_temp_store(struct device *dev, struct device_attribute *attr, return ret ? ret : count; } static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store); -#endif/*CONFIG_THERMAL_EMULATION*/ static ssize_t sustainable_power_show(struct device *dev, struct device_attribute *devattr, @@ -1822,11 +1814,12 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type, goto unregister; } -#ifdef CONFIG_THERMAL_EMULATION - result = device_create_file(&tz->device, &dev_attr_emul_temp); - if (result) - goto unregister; -#endif + if (IS_ENABLED(CONFIG_THERMAL_EMULATION)) { + result = device_create_file(&tz->device, &dev_attr_emul_temp); + if (result) + goto unregister; + } + /* Create policy attribute */ result = device_create_file(&tz->device, &dev_attr_policy); if (result) -- cgit v1.3-6-gb490 From 934c93b8c193b62fc86256ea64aef65e9a7b4e9e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 6 Jul 2015 09:46:17 +0200 Subject: thermal: Add comment explaining test for critical temperature The code testing if a temperature should be emulated or not is not obvious. Add a comment explaining why this test is done. Signed-off-by: Sascha Hauer Reviewed-by: Mikko Perttunen Signed-off-by: Zhang Rui --- drivers/thermal/thermal_core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 9599465abeac..6a707789746b 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -498,6 +498,11 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) } } + /* + * Only allow emulating a temperature when the real temperature + * is below the critical temperature so that the emulation code + * cannot hide critical conditions. + */ if (!ret && *temp < crit_temp) *temp = tz->emul_temperature; } -- cgit v1.3-6-gb490 From e203db293863fa15b4b1917d4398fb5bd63c4e88 Mon Sep 17 00:00:00 2001 From: Salva Peiró Date: Thu, 23 Jul 2015 14:26:19 +0200 Subject: iommu/omap: Fix debug_read_tlb() to use seq_printf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The debug_read_tlb() uses the sprintf() functions directly on the buffer allocated by buf = kmalloc(count), without taking into account the size of the buffer, with the consequence corrupting the heap, depending on the count requested by the user. The patch fixes the issue replacing sprintf() by seq_printf(). Signed-off-by: Salva Peiró Signed-off-by: Joerg Roedel --- drivers/iommu/omap-iommu-debug.c | 48 ++++++++++++---------------------------- 1 file changed, 14 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c index e9f116f18531..0717aa96ce39 100644 --- a/drivers/iommu/omap-iommu-debug.c +++ b/drivers/iommu/omap-iommu-debug.c @@ -133,26 +133,18 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num) } static ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr, - char *buf) + struct seq_file *s) { - char *p = buf; - - /* FIXME: Need more detail analysis of cam/ram */ - p += sprintf(p, "%08x %08x %01x\n", cr->cam, cr->ram, - (cr->cam & MMU_CAM_P) ? 1 : 0); - - return p - buf; + return seq_printf(s, "%08x %08x %01x\n", cr->cam, cr->ram, + (cr->cam & MMU_CAM_P) ? 1 : 0); } -static size_t omap_dump_tlb_entries(struct omap_iommu *obj, char *buf, - ssize_t bytes) +static size_t omap_dump_tlb_entries(struct omap_iommu *obj, struct seq_file *s) { int i, num; struct cr_regs *cr; - char *p = buf; - num = bytes / sizeof(*cr); - num = min(obj->nr_tlb_entries, num); + num = obj->nr_tlb_entries; cr = kcalloc(num, sizeof(*cr), GFP_KERNEL); if (!cr) @@ -160,40 +152,28 @@ static size_t omap_dump_tlb_entries(struct omap_iommu *obj, char *buf, num = __dump_tlb_entries(obj, cr, num); for (i = 0; i < num; i++) - p += iotlb_dump_cr(obj, cr + i, p); + iotlb_dump_cr(obj, cr + i, s); kfree(cr); - return p - buf; + return 0; } -static ssize_t debug_read_tlb(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) +static int debug_read_tlb(struct seq_file *s, void *data) { - struct omap_iommu *obj = file->private_data; - char *p, *buf; - ssize_t bytes, rest; + struct omap_iommu *obj = s->private; if (is_omap_iommu_detached(obj)) return -EPERM; - buf = kmalloc(count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - p = buf; - mutex_lock(&iommu_debug_lock); - p += sprintf(p, "%8s %8s\n", "cam:", "ram:"); - p += sprintf(p, "-----------------------------------------\n"); - rest = count - (p - buf); - p += omap_dump_tlb_entries(obj, p, rest); - - bytes = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); + seq_printf(s, "%8s %8s\n", "cam:", "ram:"); + seq_puts(s, "-----------------------------------------\n"); + omap_dump_tlb_entries(obj, s); mutex_unlock(&iommu_debug_lock); - kfree(buf); - return bytes; + return 0; } static void dump_ioptable(struct seq_file *s) @@ -268,7 +248,7 @@ static int debug_read_pagetable(struct seq_file *s, void *data) } DEBUG_FOPS_RO(regs); -DEBUG_FOPS_RO(tlb); +DEBUG_SEQ_FOPS_RO(tlb); DEBUG_SEQ_FOPS_RO(pagetable); #define __DEBUG_ADD_FILE(attr, mode) \ -- cgit v1.3-6-gb490 From 53e381627d34c4c7a3ea00c041c38f447828f755 Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Mon, 3 Aug 2015 22:15:51 +0800 Subject: regulator: mt6311: Modify the maximum voltage of buck. The maximum voltage of buck should be 1.39375V. 1.39375V = 0.6V + 0.00625V * 127, 127 is the max_sel of linear range. Reported-by: Axel Lin signed-off-by: Henry Chen Signed-off-by: Mark Brown --- drivers/regulator/mt6311-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c index 096e6202be1c..b140da04a657 100644 --- a/drivers/regulator/mt6311-regulator.c +++ b/drivers/regulator/mt6311-regulator.c @@ -34,7 +34,7 @@ static const struct regmap_config mt6311_regmap_config = { /* Default limits measured in millivolts and milliamps */ #define MT6311_MIN_UV 600000 -#define MT6311_MAX_UV 1400000 +#define MT6311_MAX_UV 1393750 #define MT6311_STEP_UV 6250 static const struct regulator_linear_range buck_volt_range[] = { -- cgit v1.3-6-gb490 From f47da2400e8828eda2ed4208fb312031f8b7d2ae Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 3 Aug 2015 13:41:11 +0300 Subject: spi: spi-pxa2xx: Remove unused legacy PXA DMA API channel numbers These became unused by the commit 6356437e65c2 ("spi: spi-pxa2xx: remove legacy PXA DMA bits"). Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 2 -- drivers/spi/spi-pxa2xx.h | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 2c9fa409d2bf..e924710e126c 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1475,8 +1475,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) } /* Setup DMA if requested */ - drv_data->tx_channel = -1; - drv_data->rx_channel = -1; if (platform_info->enable_dma) { status = pxa2xx_spi_dma_setup(drv_data); if (status) { diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 9f01e9c9aa75..3b69c46bfbc9 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -37,8 +37,6 @@ struct driver_data { struct pxa2xx_spi_master *master_info; /* PXA private DMA setup stuff */ - int rx_channel; - int tx_channel; u32 *null_dma_buf; /* SSP register addresses */ -- cgit v1.3-6-gb490 From 08b472f7b602c60c69f278ba1e15535f5c86ee24 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 30 Jul 2015 21:06:43 +0800 Subject: regulator: mt6311: Trivial clean up Make mt6311_buck_ops, mt6311_ldo_ops and mt6311_regulators const and remove unneeded error variable in mt6311_i2c_probe(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/mt6311-regulator.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c index b140da04a657..2c2c85bf08c5 100644 --- a/drivers/regulator/mt6311-regulator.c +++ b/drivers/regulator/mt6311-regulator.c @@ -41,7 +41,7 @@ static const struct regulator_linear_range buck_volt_range[] = { REGULATOR_LINEAR_RANGE(MT6311_MIN_UV, 0, 0x7f, MT6311_STEP_UV), }; -static struct regulator_ops mt6311_buck_ops = { +static const struct regulator_ops mt6311_buck_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -52,7 +52,7 @@ static struct regulator_ops mt6311_buck_ops = { .is_enabled = regulator_is_enabled_regmap, }; -static struct regulator_ops mt6311_ldo_ops = { +static const struct regulator_ops mt6311_ldo_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -91,7 +91,7 @@ static struct regulator_ops mt6311_ldo_ops = { .enable_mask = MT6311_PMIC_RG_VBIASN_EN_MASK,\ } -static struct regulator_desc mt6311_regulators[] = { +static const struct regulator_desc mt6311_regulators[] = { MT6311_BUCK(VDVFS), MT6311_LDO(VBIASN), }; @@ -105,15 +105,15 @@ static int mt6311_i2c_probe(struct i2c_client *i2c, struct regulator_config config = { }; struct regulator_dev *rdev; struct regmap *regmap; - int error, i, ret; + int i, ret; unsigned int data; regmap = devm_regmap_init_i2c(i2c, &mt6311_regmap_config); if (IS_ERR(regmap)) { - error = PTR_ERR(regmap); + ret = PTR_ERR(regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - error); - return error; + ret); + return ret; } ret = regmap_read(regmap, MT6311_SWCID, &data); -- cgit v1.3-6-gb490 From 62f46669688bf13643b91bbc30f19da1095a5ed6 Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Mon, 3 Aug 2015 13:03:09 -0700 Subject: Input: zforce - make the interrupt GPIO optional Add support for hardware which uses an I2C Serializer / Deserializer (SerDes) to communicate with the zFroce touch driver. In this case the SerDes will be configured as an interrupt controller and the zForce driver will have no access to poll the GPIO line. To support this, we add two dedicated new GPIOs in the device tree: reset-gpios and irq-gpios, with the irq-gpios being optional. To not break the existing device trees, the index based 'gpios' entries are still supported, but marked as deprecated. With this, if the interrupt GPIO is available, either via the old or new device tree style, the while loop will read and handle the packets as long as the GPIO indicates that the interrupt is asserted (existing, unchanged driver behavior). If the interrupt GPIO isn't available, i.e. not configured via the new device tree style, we are falling back to one read per ISR invocation (new behavior to support the SerDes). Note that the gpiod functions help to handle the optional GPIO: devm_gpiod_get_index_optional() will return NULL in case the interrupt GPIO isn't available. And gpiod_get_value_cansleep() does cover this, too, by returning 0 in this case. Signed-off-by: Dirk Behme Reviewed-by: Heiko Stuebner Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/zforce_ts.txt | 8 +-- drivers/input/touchscreen/zforce_ts.c | 63 +++++++++++++++++----- 2 files changed, 53 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt index 80c37df940a7..e3c27c4fd9c8 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt @@ -4,12 +4,12 @@ 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 +- reset-gpios: reset gpio the chip is connected to - x-size: horizontal resolution of touchscreen - y-size: vertical resolution of touchscreen Optional properties: +- irq-gpios : interrupt gpio the chip is connected to - vdd-supply: Regulator controlling the controller supply Example: @@ -23,8 +23,8 @@ Example: interrupts = <2 0>; vdd-supply = <®_zforce_vdd>; - gpios = <&gpio5 6 0>, /* INT */ - <&gpio5 9 0>; /* RST */ + reset-gpios = <&gpio5 9 0>; /* RST */ + irq-gpios = <&gpio5 6 0>; /* IRQ, optional */ x-size = <800>; y-size = <600>; diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 0aa934c3540e..781d0f83050a 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -510,7 +510,16 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) if (!ts->suspending && device_may_wakeup(&client->dev)) pm_stay_awake(&client->dev); - while (gpiod_get_value_cansleep(ts->gpio_int)) { + /* + * Run at least once and exit the loop if + * - the optional interrupt GPIO isn't specified + * (there is only one packet read per ISR invocation, then) + * or + * - the GPIO isn't active any more + * (packet read until the level GPIO indicates that there is + * no IRQ any more) + */ + do { ret = zforce_read_packet(ts, payload_buffer); if (ret < 0) { dev_err(&client->dev, @@ -577,7 +586,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) payload[RESPONSE_ID]); break; } - } + } while (gpiod_get_value_cansleep(ts->gpio_int)); if (!ts->suspending && device_may_wakeup(&client->dev)) pm_relax(&client->dev); @@ -754,18 +763,8 @@ static int zforce_probe(struct i2c_client *client, if (!ts) return -ENOMEM; - /* INT GPIO */ - ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0, GPIOD_IN); - if (IS_ERR(ts->gpio_int)) { - ret = PTR_ERR(ts->gpio_int); - dev_err(&client->dev, - "failed to request interrupt GPIO: %d\n", ret); - return ret; - } - - /* RST GPIO */ - ts->gpio_rst = devm_gpiod_get_index(&client->dev, NULL, 1, - GPIOD_OUT_HIGH); + ts->gpio_rst = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); if (IS_ERR(ts->gpio_rst)) { ret = PTR_ERR(ts->gpio_rst); dev_err(&client->dev, @@ -773,6 +772,42 @@ static int zforce_probe(struct i2c_client *client, return ret; } + if (ts->gpio_rst) { + ts->gpio_int = devm_gpiod_get_optional(&client->dev, "irq", + GPIOD_IN); + if (IS_ERR(ts->gpio_int)) { + ret = PTR_ERR(ts->gpio_int); + dev_err(&client->dev, + "failed to request interrupt GPIO: %d\n", ret); + return ret; + } + } else { + /* + * Deprecated GPIO handling for compatibility + * with legacy binding. + */ + + /* INT GPIO */ + ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0, + GPIOD_IN); + if (IS_ERR(ts->gpio_int)) { + ret = PTR_ERR(ts->gpio_int); + dev_err(&client->dev, + "failed to request interrupt GPIO: %d\n", ret); + return ret; + } + + /* RST GPIO */ + ts->gpio_rst = devm_gpiod_get_index(&client->dev, NULL, 1, + GPIOD_OUT_HIGH); + if (IS_ERR(ts->gpio_rst)) { + ret = PTR_ERR(ts->gpio_rst); + dev_err(&client->dev, + "failed to request reset GPIO: %d\n", ret); + return ret; + } + } + ts->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd"); if (IS_ERR(ts->reg_vdd)) { ret = PTR_ERR(ts->reg_vdd); -- cgit v1.3-6-gb490 From 21518a6eb92afa9c285ae7b33dd9357a99224b8f Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 2 Aug 2015 20:56:37 +0200 Subject: rocker: enable support for scattered packets rocker supports the transmission of scattered packets, so let the kernel know about it by setting the NETIF_F_SG bit in the device's features. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Acked-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 7b4c3474acfe..730bdc01b944 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4970,7 +4970,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) NAPI_POLL_WEIGHT); rocker_carrier_init(rocker_port); - dev->features |= NETIF_F_NETNS_LOCAL; + dev->features |= NETIF_F_NETNS_LOCAL | NETIF_F_SG; err = register_netdev(dev); if (err) { -- cgit v1.3-6-gb490 From 95b9be64d1683c4552ab94d94c08bf833561b1c4 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sun, 2 Aug 2015 20:56:38 +0200 Subject: rocker: linearize skb in case frags would not fit into tx descriptor Suggested-by: Scott Feldman Signed-off-by: Jiri Pirko Acked-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 730bdc01b944..4cd5a71ad45e 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4157,8 +4157,11 @@ static netdev_tx_t rocker_port_xmit(struct sk_buff *skb, struct net_device *dev) skb->data, skb_headlen(skb)); if (err) goto nest_cancel; - if (skb_shinfo(skb)->nr_frags > ROCKER_TX_FRAGS_MAX) - goto nest_cancel; + if (skb_shinfo(skb)->nr_frags > ROCKER_TX_FRAGS_MAX) { + err = skb_linearize(skb); + if (err) + goto unmap_frags; + } for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; -- cgit v1.3-6-gb490 From 0fbd050a7d262b74527a289ae75a33626d1060a8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 31 Jul 2015 18:25:17 +0200 Subject: virtio_net: add gro capability Straightforward patch to add GRO processing to virtio_net. napi_complete_done() usage allows more aggressive aggregation, opted-in by setting /sys/class/net/xxx/gro_flush_timeout Tested: Setting /sys/class/net/xxx/gro_flush_timeout to 1000 nsec, Rick Jones reported following results. One VM of each on a pair of OpenStack compute nodes with E5-2650Lv3 CPUs and Intel 82599ES-based NICs. So, two "before" and two "after" VMs. The OpenStack compute nodes were running OpenStack Kilo, with VxLAN encapsulation being used through OVS so no GRO coming-up the host stack. The compute nodes themselves were running a 3.14-based kernel. Single-stream netperf, CPU utilizations and thus service demands are based on intra-guest reported CPU. Throughput Mbit/s, bigger is better Min Median Average Max 4.2.0-rc3+ 1364 1686 1678 1938 4.2.0-rc3+flush1k 1824 2269 2275 2647 Send Service Demand, smaller is better Min Median Average Max 4.2.0-rc3+ 0.236 0.558 0.524 0.802 4.2.0-rc3+flush1k 0.176 0.503 0.471 0.738 Receive Service Demand, smaller is better. Min Median Average Max 4.2.0-rc3+ 1.906 2.188 2.191 2.531 4.2.0-rc3+flush1k 0.448 0.529 0.533 0.692 Signed-off-by: Eric Dumazet Tested-by: Rick Jones Cc: "Michael S. Tsirkin" Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 7fbca37a1adf..66f08f622dc6 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -518,7 +518,7 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq, skb_mark_napi_id(skb, &rq->napi); - netif_receive_skb(skb); + napi_gro_receive(&rq->napi, skb); return; frame_err: @@ -756,7 +756,7 @@ static int virtnet_poll(struct napi_struct *napi, int budget) /* Out of packets? */ if (received < budget) { r = virtqueue_enable_cb_prepare(rq->vq); - napi_complete(napi); + napi_complete_done(napi, received); if (unlikely(virtqueue_poll(rq->vq, r)) && napi_schedule_prep(napi)) { virtqueue_disable_cb(rq->vq); -- cgit v1.3-6-gb490 From f56e67b5154561dea2bac649085ee1fcb51006f8 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Fri, 31 Jul 2015 15:03:24 +0900 Subject: macvlan: Don't segment multiple tagged packets on macvlan device Macvlan/macvtap devices don't need to segment multiple tagged packets since the lower devices can segment them. Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 9f59f17dc317..47da43595ac2 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1047,6 +1047,7 @@ static const struct net_device_ops macvlan_netdev_ops = { .ndo_netpoll_cleanup = macvlan_dev_netpoll_cleanup, #endif .ndo_get_iflink = macvlan_dev_get_iflink, + .ndo_features_check = passthru_features_check, }; void macvlan_common_setup(struct net_device *dev) -- cgit v1.3-6-gb490 From 1a04a82156ec31542b956548f9549339de8511d4 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Fri, 31 Jul 2015 15:03:25 +0900 Subject: veth: Don't segment multiple tagged packets on veth device Veth devices don't need to segment multiple tagged packets. Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller --- drivers/net/veth.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/veth.c b/drivers/net/veth.c index c8186ffda1a3..343592c4315f 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -290,6 +290,7 @@ static const struct net_device_ops veth_netdev_ops = { .ndo_poll_controller = veth_poll_controller, #endif .ndo_get_iflink = veth_get_iflink, + .ndo_features_check = passthru_features_check, }; #define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \ -- cgit v1.3-6-gb490 From 5e52796a9a3d56298273030cd438e8015a8d5683 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Fri, 31 Jul 2015 15:03:27 +0900 Subject: tuntap: Don't segment multiple tagged packets on tap device Tap devices don't need to segment multiple tagged packets. Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller --- drivers/net/tun.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 06a039414628..976aa9704297 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -961,6 +961,7 @@ static const struct net_device_ops tap_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = tun_poll_controller, #endif + .ndo_features_check = passthru_features_check, }; static void tun_flow_init(struct tun_struct *tun) -- cgit v1.3-6-gb490 From 1fb6dd9da6ed4f2953b62162f3c498a1f6d7bfca Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Mon, 3 Aug 2015 09:13:34 +0800 Subject: clk: hisi: refine parameter checking for init *of_iomap()* will check the device node pointer, and if the pointer is NULL it will return error code. So refine clock's init flow by checking the device node with this simple way; and polish a little for the print out message. Signed-off-by: Leo Yan Signed-off-by: Stephen Boyd --- drivers/clk/hisilicon/clk.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c index 155e2e6c8316..9f8e76676553 100644 --- a/drivers/clk/hisilicon/clk.c +++ b/drivers/clk/hisilicon/clk.c @@ -44,14 +44,9 @@ struct hisi_clock_data __init *hisi_clk_init(struct device_node *np, 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"); + base = of_iomap(np, 0); + if (!base) { + pr_err("%s: failed to map clock registers\n", __func__); goto err; } -- cgit v1.3-6-gb490 From a3a10ce3429e5dee623ad5c8407ea58e204fcb0a Mon Sep 17 00:00:00 2001 From: Richard Watts Date: Tue, 19 May 2015 16:06:53 +0100 Subject: Avoid usb reset crashes by making tty_io cdevs truly dynamic Avoid usb reset crashes by making tty_io cdevs truly dynamic Signed-off-by: Richard Watts Reported-by: Duncan Mackintosh Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 24 ++++++++++++++++-------- include/linux/tty_driver.h | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index c37a215177c0..02785d844354 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3152,9 +3152,12 @@ static int tty_cdev_add(struct tty_driver *driver, dev_t dev, unsigned int index, unsigned int count) { /* init here, since reused cdevs cause crashes */ - cdev_init(&driver->cdevs[index], &tty_fops); - driver->cdevs[index].owner = driver->owner; - return cdev_add(&driver->cdevs[index], dev, count); + driver->cdevs[index] = cdev_alloc(); + if (!driver->cdevs[index]) + return -ENOMEM; + cdev_init(driver->cdevs[index], &tty_fops); + driver->cdevs[index]->owner = driver->owner; + return cdev_add(driver->cdevs[index], dev, count); } /** @@ -3260,8 +3263,10 @@ struct device *tty_register_device_attr(struct tty_driver *driver, error: put_device(dev); - if (cdev) - cdev_del(&driver->cdevs[index]); + if (cdev) { + cdev_del(driver->cdevs[index]); + driver->cdevs[index] = NULL; + } return ERR_PTR(retval); } EXPORT_SYMBOL_GPL(tty_register_device_attr); @@ -3281,8 +3286,10 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) { device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); - if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) - cdev_del(&driver->cdevs[index]); + if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { + cdev_del(driver->cdevs[index]); + driver->cdevs[index] = NULL; + } } EXPORT_SYMBOL(tty_unregister_device); @@ -3347,6 +3354,7 @@ err_free_all: kfree(driver->ports); kfree(driver->ttys); kfree(driver->termios); + kfree(driver->cdevs); kfree(driver); return ERR_PTR(err); } @@ -3375,7 +3383,7 @@ static void destruct_tty_driver(struct kref *kref) } proc_tty_unregister_driver(driver); if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) - cdev_del(&driver->cdevs[0]); + cdev_del(driver->cdevs[0]); } kfree(driver->cdevs); kfree(driver->ports); diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 92e337c18839..161052477f77 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -296,7 +296,7 @@ struct tty_operations { struct tty_driver { int magic; /* magic number for this structure */ struct kref kref; /* Reference management */ - struct cdev *cdevs; + struct cdev **cdevs; struct module *owner; const char *driver_name; const char *name; -- cgit v1.3-6-gb490 From fecf27a373f5a6b393e93b14f8460299b8abd6f9 Mon Sep 17 00:00:00 2001 From: Peter Hung Date: Tue, 28 Jul 2015 11:59:24 +0800 Subject: serial: 8250_pci: add RS485 for F81504/508/512 Add RS485 control for Fintek F81504/508/512 F81504/508/512 can control their RTS with H/W mode. PCI configuration space for each port is 0x40 + idx * 8 + 7. When it set with 0x01, it's configured with RS232 mode. RTS is controlled by MCR. When it set with 0x11, it's configured with RS485 mode. RTS is controlled by H/W, RTS low with idle & RX, high with TX. When it set with 0x31, it's configured with RS485 mode. RTS is controlled by H/W, RTS high with idle & RX, low with TX. We will force 0x01 on pci_fintek_setup(). Signed-off-by: Peter Hung Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 61 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e55f18b93fe7..df2e61e206fa 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1685,11 +1685,60 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } +/* RTS will control by MCR if this bit is 0 */ +#define FINTEK_RTS_CONTROL_BY_HW BIT(4) +/* only worked with FINTEK_RTS_CONTROL_BY_HW on */ +#define FINTEK_RTS_INVERT BIT(5) + +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int pci_fintek_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + u8 setting; + u8 *index = (u8 *) port->private_data; + struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev, + dev); + + pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting); + + if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + /* F81504/508/512 not support RTS delay before or after send */ + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= FINTEK_RTS_CONTROL_BY_HW; + + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting &= ~FINTEK_RTS_INVERT; + } else { + /* RTS driving low on TX */ + setting |= FINTEK_RTS_INVERT; + } + + rs485->delay_rts_after_send = 0; + rs485->delay_rts_before_send = 0; + } else { + /* Disable RTS H/W control mode */ + setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); + } + + pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); + port->rs485 = *rs485; + return 0; +} + static int pci_fintek_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { struct pci_dev *pdev = priv->dev; + u8 *data; u8 config_base; u16 iobase; @@ -1702,6 +1751,15 @@ static int pci_fintek_setup(struct serial_private *priv, port->port.iotype = UPIO_PORT; port->port.iobase = iobase; + port->port.rs485_config = pci_fintek_rs485_config; + + data = devm_kzalloc(&pdev->dev, sizeof(u8), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* preserve index in PCI configuration space */ + *data = idx; + port->port.private_data = data; return 0; } @@ -1752,6 +1810,9 @@ static int pci_fintek_init(struct pci_dev *dev) (u8)((iobase & 0xff00) >> 8)); pci_write_config_byte(dev, config_base + 0x06, dev->irq); + + /* force init to RS232 Mode */ + pci_write_config_byte(dev, config_base + 0x07, 0x01); } return max_port; -- cgit v1.3-6-gb490 From 24751e29fe313105c9dd5f9d1f27028c553381f6 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 3 Aug 2015 09:17:44 -0400 Subject: net: dsa: mv88e6xxx: call _mv88e6xxx_stats_wait with SMI lock held At switch setup, _mv88e6xxx_stats_wait was called without holding the SMI mutex. Fix this by requesting the lock for this call. Also, return the _mv88e6xxx_stats_wait code, since it may fail. Signed-off-by: Vivien Didelot Reviewed-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 61ce4cf120a6..109452056eff 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1881,6 +1881,7 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds) int mv88e6xxx_setup_global(struct dsa_switch *ds) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int ret; int i; /* Set the default address aging time to 5 minutes, and @@ -1979,9 +1980,11 @@ int mv88e6xxx_setup_global(struct dsa_switch *ds) REG_WRITE(REG_GLOBAL, GLOBAL_STATS_OP, GLOBAL_STATS_OP_FLUSH_ALL); /* Wait for the flush to complete. */ - _mv88e6xxx_stats_wait(ds); + mutex_lock(&ps->smi_mutex); + ret = _mv88e6xxx_stats_wait(ds); + mutex_unlock(&ps->smi_mutex); - return 0; + return ret; } int mv88e6xxx_switch_reset(struct dsa_switch *ds, bool ppu_active) -- cgit v1.3-6-gb490 From e70e69bf205e6d1f742f1cf1935b155417c9e29a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 24 Jul 2015 15:58:28 +0900 Subject: serial: 8250_uniphier: call clk_disable_unprepare() on failure path If serial8250_register_8250_port() fails, disable and unprepare the clock before exiting. Fixes: 1a8d2903cb6a ("serial: 8250_uniphier: add UniPhier serial driver") Signed-off-by: Masahiro Yamada Reviewed-by: Matthias Brugger Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_uniphier.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 7d79425c2b09..d11621e2cf1d 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -218,6 +218,7 @@ static int uniphier_uart_probe(struct platform_device *pdev) ret = serial8250_register_8250_port(&up); if (ret < 0) { dev_err(dev, "failed to register 8250 port\n"); + clk_disable_unprepare(priv->clk); return ret; } -- cgit v1.3-6-gb490 From 90bb6bd385638f37d30dcc7342a62aff80089def Mon Sep 17 00:00:00 2001 From: Shenwei Wang Date: Thu, 30 Jul 2015 10:32:36 -0500 Subject: Serial: imx: add dev_pm_ops to support suspend to ram/disk When system goes into low power states like SUSPEND_MEM and HIBERNATION, the hardware IP block may be powered off to reduce the power consumption. This power down may cause problems on some imx platforms, because the hardware settings are reset to its power on default values which may differ from the ones when it power off. This patch added the dev_pm_ops and implemented two callbacks: suspend_noirq and resume_noirq, which will save the necessory hardware parameters right before power down and recover them before system uses the hardware. Because added the dev_pm_ops, the old suspend/resume callbacks under platform_driver will not be called any more. Changed their prototypes and moved those two callbacks into dev_pm_ops too. Signed-off-by: Shenwei Wang Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 126 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index cf594ce7c54c..9a248eb11308 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -216,6 +216,7 @@ struct imx_port { unsigned int tx_bytes; unsigned int dma_tx_nents; wait_queue_head_t dma_wait; + unsigned int saved_reg[10]; }; struct imx_port_ucrs { @@ -1815,36 +1816,6 @@ static struct uart_driver imx_reg = { .cons = IMX_CONSOLE, }; -static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) -{ - struct imx_port *sport = platform_get_drvdata(dev); - unsigned int val; - - /* enable wakeup from i.MX UART */ - val = readl(sport->port.membase + UCR3); - val |= UCR3_AWAKEN; - writel(val, sport->port.membase + UCR3); - - uart_suspend_port(&imx_reg, &sport->port); - - return 0; -} - -static int serial_imx_resume(struct platform_device *dev) -{ - struct imx_port *sport = platform_get_drvdata(dev); - unsigned int val; - - /* disable wakeup from i.MX UART */ - val = readl(sport->port.membase + UCR3); - val &= ~UCR3_AWAKEN; - writel(val, sport->port.membase + UCR3); - - uart_resume_port(&imx_reg, &sport->port); - - return 0; -} - #ifdef CONFIG_OF /* * This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it @@ -2009,16 +1980,107 @@ static int serial_imx_remove(struct platform_device *pdev) return uart_remove_one_port(&imx_reg, &sport->port); } +static int imx_serial_port_suspend_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + int ret; + + ret = clk_enable(sport->clk_ipg); + if (ret) + return ret; + + /* Save necessary regs */ + sport->saved_reg[0] = readl(sport->port.membase + UCR1); + sport->saved_reg[1] = readl(sport->port.membase + UCR2); + sport->saved_reg[2] = readl(sport->port.membase + UCR3); + sport->saved_reg[3] = readl(sport->port.membase + UCR4); + sport->saved_reg[4] = readl(sport->port.membase + UFCR); + sport->saved_reg[5] = readl(sport->port.membase + UESC); + sport->saved_reg[6] = readl(sport->port.membase + UTIM); + sport->saved_reg[7] = readl(sport->port.membase + UBIR); + sport->saved_reg[8] = readl(sport->port.membase + UBMR); + sport->saved_reg[9] = readl(sport->port.membase + IMX21_UTS); + + clk_disable(sport->clk_ipg); + + return 0; +} + +static int imx_serial_port_resume_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + int ret; + + ret = clk_enable(sport->clk_ipg); + if (ret) + return ret; + + writel(sport->saved_reg[4], sport->port.membase + UFCR); + writel(sport->saved_reg[5], sport->port.membase + UESC); + writel(sport->saved_reg[6], sport->port.membase + UTIM); + writel(sport->saved_reg[7], sport->port.membase + UBIR); + writel(sport->saved_reg[8], sport->port.membase + UBMR); + writel(sport->saved_reg[9], sport->port.membase + IMX21_UTS); + writel(sport->saved_reg[0], sport->port.membase + UCR1); + writel(sport->saved_reg[1] | UCR2_SRST, sport->port.membase + UCR2); + writel(sport->saved_reg[2], sport->port.membase + UCR3); + writel(sport->saved_reg[3], sport->port.membase + UCR4); + + clk_disable(sport->clk_ipg); + + return 0; +} + +static int imx_serial_port_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + unsigned int val; + + /* enable wakeup from i.MX UART */ + val = readl(sport->port.membase + UCR3); + val |= UCR3_AWAKEN; + writel(val, sport->port.membase + UCR3); + + uart_suspend_port(&imx_reg, &sport->port); + + return 0; +} + +static int imx_serial_port_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + unsigned int val; + + /* disable wakeup from i.MX UART */ + val = readl(sport->port.membase + UCR3); + val &= ~UCR3_AWAKEN; + writel(val, sport->port.membase + UCR3); + + uart_resume_port(&imx_reg, &sport->port); + + return 0; +} + +static const struct dev_pm_ops imx_serial_port_pm_ops = { + .suspend_noirq = imx_serial_port_suspend_noirq, + .resume_noirq = imx_serial_port_resume_noirq, + .suspend = imx_serial_port_suspend, + .resume = imx_serial_port_resume, +}; + static struct platform_driver serial_imx_driver = { .probe = serial_imx_probe, .remove = serial_imx_remove, - .suspend = serial_imx_suspend, - .resume = serial_imx_resume, .id_table = imx_uart_devtype, .driver = { .name = "imx-uart", .of_match_table = imx_uart_dt_ids, + .pm = &imx_serial_port_pm_ops, }, }; -- cgit v1.3-6-gb490 From 23253c31c6a7a3c5a437ec31830e2100484c0748 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Thu, 23 Jul 2015 10:43:11 +0300 Subject: mei: do not access freed cb in blocking write The mei_cl_write function is giving up on a write cb ownership after it was sent or queued. The write cb is then freed in the completion handler. Especially during blocking write mei_cl_write function waits for the completion handler and then access the freed memory to fetch the written size. The quick fix is to store the buffer size prior to sending, the size is not altered during the flow. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 6decbe136ea7..1987a201c7f3 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -1356,6 +1356,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) struct mei_device *dev; struct mei_msg_data *buf; struct mei_msg_hdr mei_hdr; + int size; int rets; @@ -1367,10 +1368,10 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) dev = cl->dev; - buf = &cb->buf; + size = buf->size; - cl_dbg(dev, cl, "size=%d\n", buf->size); + cl_dbg(dev, cl, "size=%d\n", size); rets = pm_runtime_get(dev->dev); if (rets < 0 && rets != -EINPROGRESS) { @@ -1394,21 +1395,21 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) if (rets == 0) { cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); - rets = buf->size; + rets = size; goto out; } if (!mei_hbuf_acquire(dev)) { cl_dbg(dev, cl, "Cannot acquire the host buffer: not sending.\n"); - rets = buf->size; + rets = size; goto out; } /* Check for a maximum length */ - if (buf->size > mei_hbuf_max_len(dev)) { + if (size > mei_hbuf_max_len(dev)) { mei_hdr.length = mei_hbuf_max_len(dev); mei_hdr.msg_complete = 0; } else { - mei_hdr.length = buf->size; + mei_hdr.length = size; mei_hdr.msg_complete = 1; } @@ -1430,6 +1431,7 @@ out: else list_add_tail(&cb->list, &dev->write_list.list); + cb = NULL; if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) { mutex_unlock(&dev->device_lock); @@ -1444,7 +1446,7 @@ out: } } - rets = buf->size; + rets = size; err: cl_dbg(dev, cl, "rpm: autosuspend\n"); pm_runtime_mark_last_busy(dev->dev); -- cgit v1.3-6-gb490 From b37719c31f8448ba36abc218a96663b4a6c66eb6 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:33 +0300 Subject: mei: bus: fix drivers and devices names confusion In the mei bus layer there is use of different variables of driver and device types with no clear naming convention. There are generic struct device and struct driver, then mei_cl_{device, driver}, and finally mei_device which in this context serves as a bus device. The patch sets following naming convention: the variables of type struct device remains dev the variables of type struct driver remains drv the variables of type struct mei_cl_device are now cldev the variables of type struct mei_cl_driver are now cldrv the variables of type struct mei_device are now bus, in bus layer context Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 260 ++++++++++++++++++++++----------------------- drivers/misc/mei/mei_dev.h | 12 +-- drivers/misc/mei/nfc.c | 80 +++++++------- 3 files changed, 176 insertions(+), 176 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 458aa5a09c52..18c37af22f07 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -32,22 +32,22 @@ static int mei_cl_device_match(struct device *dev, struct device_driver *drv) { - struct mei_cl_device *device = to_mei_cl_device(dev); - struct mei_cl_driver *driver = to_mei_cl_driver(drv); + struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct mei_cl_driver *cldrv = to_mei_cl_driver(drv); const struct mei_cl_device_id *id; const uuid_le *uuid; const char *name; - if (!device) + if (!cldev) return 0; - uuid = mei_me_cl_uuid(device->me_cl); - name = device->name; + uuid = mei_me_cl_uuid(cldev->me_cl); + name = cldev->name; - if (!driver || !driver->id_table) + if (!cldrv || !cldrv->id_table) return 0; - id = driver->id_table; + id = cldrv->id_table; while (uuid_le_cmp(NULL_UUID_LE, id->uuid)) { @@ -68,54 +68,54 @@ static int mei_cl_device_match(struct device *dev, struct device_driver *drv) static int mei_cl_device_probe(struct device *dev) { - struct mei_cl_device *device = to_mei_cl_device(dev); - struct mei_cl_driver *driver; + struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct mei_cl_driver *cldrv; struct mei_cl_device_id id; - if (!device) + if (!cldev) return 0; - driver = to_mei_cl_driver(dev->driver); - if (!driver || !driver->probe) + cldrv = to_mei_cl_driver(dev->driver); + if (!cldrv || !cldrv->probe) return -ENODEV; dev_dbg(dev, "Device probe\n"); - strlcpy(id.name, device->name, sizeof(id.name)); + strlcpy(id.name, cldev->name, sizeof(id.name)); - return driver->probe(device, &id); + return cldrv->probe(cldev, &id); } static int mei_cl_device_remove(struct device *dev) { - struct mei_cl_device *device = to_mei_cl_device(dev); - struct mei_cl_driver *driver; + struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct mei_cl_driver *cldrv; - if (!device || !dev->driver) + if (!cldev || !dev->driver) return 0; - if (device->event_cb) { - device->event_cb = NULL; - cancel_work_sync(&device->event_work); + if (cldev->event_cb) { + cldev->event_cb = NULL; + cancel_work_sync(&cldev->event_work); } - driver = to_mei_cl_driver(dev->driver); - if (!driver->remove) { + cldrv = to_mei_cl_driver(dev->driver); + if (!cldrv->remove) { dev->driver = NULL; return 0; } - return driver->remove(device); + return cldrv->remove(cldev); } static ssize_t name_show(struct device *dev, struct device_attribute *a, char *buf) { - struct mei_cl_device *device = to_mei_cl_device(dev); + struct mei_cl_device *cldev = to_mei_cl_device(dev); size_t len; - len = snprintf(buf, PAGE_SIZE, "%s", device->name); + len = snprintf(buf, PAGE_SIZE, "%s", cldev->name); return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } @@ -124,8 +124,8 @@ static DEVICE_ATTR_RO(name); static ssize_t uuid_show(struct device *dev, struct device_attribute *a, char *buf) { - struct mei_cl_device *device = to_mei_cl_device(dev); - const uuid_le *uuid = mei_me_cl_uuid(device->me_cl); + struct mei_cl_device *cldev = to_mei_cl_device(dev); + const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); size_t len; len = snprintf(buf, PAGE_SIZE, "%pUl", uuid); @@ -137,12 +137,12 @@ static DEVICE_ATTR_RO(uuid); static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) { - struct mei_cl_device *device = to_mei_cl_device(dev); - const uuid_le *uuid = mei_me_cl_uuid(device->me_cl); + struct mei_cl_device *cldev = to_mei_cl_device(dev); + const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); size_t len; len = snprintf(buf, PAGE_SIZE, "mei:%s:" MEI_CL_UUID_FMT ":", - device->name, MEI_CL_UUID_ARGS(uuid->b)); + cldev->name, MEI_CL_UUID_ARGS(uuid->b)); return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } @@ -158,17 +158,17 @@ ATTRIBUTE_GROUPS(mei_cl_dev); static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env) { - struct mei_cl_device *device = to_mei_cl_device(dev); - const uuid_le *uuid = mei_me_cl_uuid(device->me_cl); + struct mei_cl_device *cldev = to_mei_cl_device(dev); + const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); if (add_uevent_var(env, "MEI_CL_UUID=%pUl", uuid)) return -ENOMEM; - if (add_uevent_var(env, "MEI_CL_NAME=%s", device->name)) + if (add_uevent_var(env, "MEI_CL_NAME=%s", cldev->name)) return -ENOMEM; if (add_uevent_var(env, "MODALIAS=mei:%s:" MEI_CL_UUID_FMT ":", - device->name, MEI_CL_UUID_ARGS(uuid->b))) + cldev->name, MEI_CL_UUID_ARGS(uuid->b))) return -ENOMEM; return 0; @@ -185,121 +185,121 @@ static struct bus_type mei_cl_bus_type = { static void mei_cl_dev_release(struct device *dev) { - struct mei_cl_device *device = to_mei_cl_device(dev); + struct mei_cl_device *cldev = to_mei_cl_device(dev); - if (!device) + if (!cldev) return; - mei_me_cl_put(device->me_cl); - kfree(device); + mei_me_cl_put(cldev->me_cl); + kfree(cldev); } static struct device_type mei_cl_device_type = { .release = mei_cl_dev_release, }; -struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *dev, +struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus, uuid_le uuid) { struct mei_cl *cl; - list_for_each_entry(cl, &dev->device_list, device_link) { - if (cl->device && cl->device->me_cl && - !uuid_le_cmp(uuid, *mei_me_cl_uuid(cl->device->me_cl))) + list_for_each_entry(cl, &bus->device_list, device_link) { + if (cl->cldev && cl->cldev->me_cl && + !uuid_le_cmp(uuid, *mei_me_cl_uuid(cl->cldev->me_cl))) return cl; } return NULL; } -struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, +struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, struct mei_me_client *me_cl, struct mei_cl *cl, char *name) { - struct mei_cl_device *device; + struct mei_cl_device *cldev; int status; - device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL); - if (!device) + cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL); + if (!cldev) return NULL; - device->me_cl = mei_me_cl_get(me_cl); - if (!device->me_cl) { - kfree(device); + cldev->me_cl = mei_me_cl_get(me_cl); + if (!cldev->me_cl) { + kfree(cldev); return NULL; } - device->cl = cl; - device->dev.parent = dev->dev; - device->dev.bus = &mei_cl_bus_type; - device->dev.type = &mei_cl_device_type; + cldev->cl = cl; + cldev->dev.parent = bus->dev; + cldev->dev.bus = &mei_cl_bus_type; + cldev->dev.type = &mei_cl_device_type; - strlcpy(device->name, name, sizeof(device->name)); + strlcpy(cldev->name, name, sizeof(cldev->name)); - dev_set_name(&device->dev, "mei:%s:%pUl", name, mei_me_cl_uuid(me_cl)); + dev_set_name(&cldev->dev, "mei:%s:%pUl", name, mei_me_cl_uuid(me_cl)); - status = device_register(&device->dev); + status = device_register(&cldev->dev); if (status) { - dev_err(dev->dev, "Failed to register MEI device\n"); - mei_me_cl_put(device->me_cl); - kfree(device); + dev_err(bus->dev, "Failed to register MEI device\n"); + mei_me_cl_put(cldev->me_cl); + kfree(cldev); return NULL; } - cl->device = device; + cl->cldev = cldev; - dev_dbg(&device->dev, "client %s registered\n", name); + dev_dbg(&cldev->dev, "client %s registered\n", name); - return device; + return cldev; } EXPORT_SYMBOL_GPL(mei_cl_add_device); -void mei_cl_remove_device(struct mei_cl_device *device) +void mei_cl_remove_device(struct mei_cl_device *cldev) { - device_unregister(&device->dev); + device_unregister(&cldev->dev); } EXPORT_SYMBOL_GPL(mei_cl_remove_device); -int __mei_cl_driver_register(struct mei_cl_driver *driver, struct module *owner) +int __mei_cl_driver_register(struct mei_cl_driver *cldrv, struct module *owner) { int err; - driver->driver.name = driver->name; - driver->driver.owner = owner; - driver->driver.bus = &mei_cl_bus_type; + cldrv->driver.name = cldrv->name; + cldrv->driver.owner = owner; + cldrv->driver.bus = &mei_cl_bus_type; - err = driver_register(&driver->driver); + err = driver_register(&cldrv->driver); if (err) return err; - pr_debug("mei: driver [%s] registered\n", driver->driver.name); + pr_debug("mei: driver [%s] registered\n", cldrv->driver.name); return 0; } EXPORT_SYMBOL_GPL(__mei_cl_driver_register); -void mei_cl_driver_unregister(struct mei_cl_driver *driver) +void mei_cl_driver_unregister(struct mei_cl_driver *cldrv) { - driver_unregister(&driver->driver); + driver_unregister(&cldrv->driver); - pr_debug("mei: driver [%s] unregistered\n", driver->driver.name); + pr_debug("mei: driver [%s] unregistered\n", cldrv->driver.name); } EXPORT_SYMBOL_GPL(mei_cl_driver_unregister); ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, bool blocking) { - struct mei_device *dev; + struct mei_device *bus; struct mei_cl_cb *cb = NULL; ssize_t rets; if (WARN_ON(!cl || !cl->dev)) return -ENODEV; - dev = cl->dev; + bus = cl->dev; - mutex_lock(&dev->device_lock); + mutex_lock(&bus->device_lock); if (!mei_cl_is_connected(cl)) { rets = -ENODEV; goto out; @@ -327,7 +327,7 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, rets = mei_cl_write(cl, cb, blocking); out: - mutex_unlock(&dev->device_lock); + mutex_unlock(&bus->device_lock); if (rets < 0) mei_io_cb_free(cb); @@ -336,7 +336,7 @@ out: ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) { - struct mei_device *dev; + struct mei_device *bus; struct mei_cl_cb *cb; size_t r_length; ssize_t rets; @@ -344,9 +344,9 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) if (WARN_ON(!cl || !cl->dev)) return -ENODEV; - dev = cl->dev; + bus = cl->dev; - mutex_lock(&dev->device_lock); + mutex_lock(&bus->device_lock); cb = mei_cl_read_cb(cl, NULL); if (cb) @@ -358,7 +358,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) { - mutex_unlock(&dev->device_lock); + mutex_unlock(&bus->device_lock); if (wait_event_interruptible(cl->rx_wait, (!list_empty(&cl->rd_completed)) || @@ -369,7 +369,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) return -ERESTARTSYS; } - mutex_lock(&dev->device_lock); + mutex_lock(&bus->device_lock); if (!mei_cl_is_connected(cl)) { rets = -EBUSY; @@ -396,14 +396,14 @@ copy: free: mei_io_cb_free(cb); out: - mutex_unlock(&dev->device_lock); + mutex_unlock(&bus->device_lock); return rets; } -ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length) +ssize_t mei_cl_send(struct mei_cl_device *cldev, u8 *buf, size_t length) { - struct mei_cl *cl = device->cl; + struct mei_cl *cl = cldev->cl; if (cl == NULL) return -ENODEV; @@ -412,9 +412,9 @@ ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length) } EXPORT_SYMBOL_GPL(mei_cl_send); -ssize_t mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length) +ssize_t mei_cl_recv(struct mei_cl_device *cldev, u8 *buf, size_t length) { - struct mei_cl *cl = device->cl; + struct mei_cl *cl = cldev->cl; if (cl == NULL) return -ENODEV; @@ -425,108 +425,108 @@ EXPORT_SYMBOL_GPL(mei_cl_recv); static void mei_bus_event_work(struct work_struct *work) { - struct mei_cl_device *device; + struct mei_cl_device *cldev; - device = container_of(work, struct mei_cl_device, event_work); + cldev = container_of(work, struct mei_cl_device, event_work); - if (device->event_cb) - device->event_cb(device, device->events, device->event_context); + if (cldev->event_cb) + cldev->event_cb(cldev, cldev->events, cldev->event_context); - device->events = 0; + cldev->events = 0; /* Prepare for the next read */ - mei_cl_read_start(device->cl, 0, NULL); + mei_cl_read_start(cldev->cl, 0, NULL); } -int mei_cl_register_event_cb(struct mei_cl_device *device, +int mei_cl_register_event_cb(struct mei_cl_device *cldev, mei_cl_event_cb_t event_cb, void *context) { - if (device->event_cb) + if (cldev->event_cb) return -EALREADY; - device->events = 0; - device->event_cb = event_cb; - device->event_context = context; - INIT_WORK(&device->event_work, mei_bus_event_work); + cldev->events = 0; + cldev->event_cb = event_cb; + cldev->event_context = context; + INIT_WORK(&cldev->event_work, mei_bus_event_work); - mei_cl_read_start(device->cl, 0, NULL); + mei_cl_read_start(cldev->cl, 0, NULL); return 0; } EXPORT_SYMBOL_GPL(mei_cl_register_event_cb); -void *mei_cl_get_drvdata(const struct mei_cl_device *device) +void *mei_cl_get_drvdata(const struct mei_cl_device *cldev) { - return dev_get_drvdata(&device->dev); + return dev_get_drvdata(&cldev->dev); } EXPORT_SYMBOL_GPL(mei_cl_get_drvdata); -void mei_cl_set_drvdata(struct mei_cl_device *device, void *data) +void mei_cl_set_drvdata(struct mei_cl_device *cldev, void *data) { - dev_set_drvdata(&device->dev, data); + dev_set_drvdata(&cldev->dev, data); } EXPORT_SYMBOL_GPL(mei_cl_set_drvdata); -int mei_cl_enable_device(struct mei_cl_device *device) +int mei_cl_enable_device(struct mei_cl_device *cldev) { int err; - struct mei_device *dev; - struct mei_cl *cl = device->cl; + struct mei_device *bus; + struct mei_cl *cl = cldev->cl; if (cl == NULL) return -ENODEV; - dev = cl->dev; + bus = cl->dev; - mutex_lock(&dev->device_lock); + mutex_lock(&bus->device_lock); if (mei_cl_is_connected(cl)) { - mutex_unlock(&dev->device_lock); - dev_warn(dev->dev, "Already connected"); + mutex_unlock(&bus->device_lock); + dev_warn(bus->dev, "Already connected"); return -EBUSY; } - err = mei_cl_connect(cl, device->me_cl, NULL); + err = mei_cl_connect(cl, cldev->me_cl, NULL); if (err < 0) { - mutex_unlock(&dev->device_lock); - dev_err(dev->dev, "Could not connect to the ME client"); + mutex_unlock(&bus->device_lock); + dev_err(bus->dev, "Could not connect to the ME client"); return err; } - mutex_unlock(&dev->device_lock); + mutex_unlock(&bus->device_lock); - if (device->event_cb) - mei_cl_read_start(device->cl, 0, NULL); + if (cldev->event_cb) + mei_cl_read_start(cldev->cl, 0, NULL); return 0; } EXPORT_SYMBOL_GPL(mei_cl_enable_device); -int mei_cl_disable_device(struct mei_cl_device *device) +int mei_cl_disable_device(struct mei_cl_device *cldev) { int err; - struct mei_device *dev; - struct mei_cl *cl = device->cl; + struct mei_device *bus; + struct mei_cl *cl = cldev->cl; if (cl == NULL) return -ENODEV; - dev = cl->dev; + bus = cl->dev; - device->event_cb = NULL; + cldev->event_cb = NULL; - mutex_lock(&dev->device_lock); + mutex_lock(&bus->device_lock); if (!mei_cl_is_connected(cl)) { - dev_err(dev->dev, "Already disconnected"); + dev_err(bus->dev, "Already disconnected"); err = 0; goto out; } err = mei_cl_disconnect(cl); if (err < 0) { - dev_err(dev->dev, "Could not disconnect from the ME client"); + dev_err(bus->dev, "Could not disconnect from the ME client"); goto out; } @@ -534,7 +534,7 @@ int mei_cl_disable_device(struct mei_cl_device *device) mei_cl_flush_queues(cl, NULL); out: - mutex_unlock(&dev->device_lock); + mutex_unlock(&bus->device_lock); return err; } @@ -542,14 +542,14 @@ EXPORT_SYMBOL_GPL(mei_cl_disable_device); void mei_cl_bus_rx_event(struct mei_cl *cl) { - struct mei_cl_device *device = cl->device; + struct mei_cl_device *cldev = cl->cldev; - if (!device || !device->event_cb) + if (!cldev || !cldev->event_cb) return; - set_bit(MEI_CL_EVENT_RX, &device->events); + set_bit(MEI_CL_EVENT_RX, &cldev->events); - schedule_work(&device->event_work); + schedule_work(&cldev->event_work); } int __init mei_cl_bus_init(void) diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 453f6a333b42..bc65fb42aea9 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -240,7 +240,7 @@ struct mei_cl_cb { * @rd_pending: pending read credits * @rd_completed: completed read * - * @device: device on the mei client bus + * @cldev: device on the mei client bus * @device_link: link to bus clients */ struct mei_cl { @@ -261,7 +261,7 @@ struct mei_cl { struct list_head rd_completed; /* MEI CL bus data */ - struct mei_cl_device *device; + struct mei_cl_device *cldev; struct list_head device_link; }; @@ -330,20 +330,20 @@ struct mei_hw_ops { /* MEI bus API*/ -struct mei_cl_device *mei_cl_add_device(struct mei_device *dev, +struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, struct mei_me_client *me_cl, struct mei_cl *cl, char *name); -void mei_cl_remove_device(struct mei_cl_device *device); +void mei_cl_remove_device(struct mei_cl_device *cldev); ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, bool blocking); ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); void mei_cl_bus_rx_event(struct mei_cl *cl); -void mei_cl_bus_remove_devices(struct mei_device *dev); +void mei_cl_bus_remove_devices(struct mei_device *bus); int mei_cl_bus_init(void); void mei_cl_bus_exit(void); -struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *dev, uuid_le uuid); +struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus, uuid_le uuid); /** * enum mei_pg_event - power gating transition events diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c index 290ef3037437..47aa1523d9e1 100644 --- a/drivers/misc/mei/nfc.c +++ b/drivers/misc/mei/nfc.c @@ -152,12 +152,12 @@ static void mei_nfc_free(struct mei_nfc_dev *ndev) static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev) { - struct mei_device *dev; + struct mei_device *bus; if (!ndev->cl) return -ENODEV; - dev = ndev->cl->dev; + bus = ndev->cl->dev; switch (ndev->vendor_id) { case MEI_NFC_VENDOR_INSIDE: @@ -167,7 +167,7 @@ static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev) return 0; default: - dev_err(dev->dev, "Unknown radio type 0x%x\n", + dev_err(bus->dev, "Unknown radio type 0x%x\n", ndev->radio_type); return -EINVAL; @@ -179,14 +179,14 @@ static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev) ndev->bus_name = "pn544"; return 0; default: - dev_err(dev->dev, "Unknown radio type 0x%x\n", + dev_err(bus->dev, "Unknown radio type 0x%x\n", ndev->radio_type); return -EINVAL; } default: - dev_err(dev->dev, "Unknown vendor ID 0x%x\n", + dev_err(bus->dev, "Unknown vendor ID 0x%x\n", ndev->vendor_id); return -EINVAL; @@ -197,7 +197,7 @@ static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev) static int mei_nfc_if_version(struct mei_nfc_dev *ndev) { - struct mei_device *dev; + struct mei_device *bus; struct mei_cl *cl; struct mei_nfc_cmd cmd; @@ -207,7 +207,7 @@ static int mei_nfc_if_version(struct mei_nfc_dev *ndev) int bytes_recv, ret; cl = ndev->cl_info; - dev = cl->dev; + bus = cl->dev; memset(&cmd, 0, sizeof(struct mei_nfc_cmd)); cmd.command = MEI_NFC_CMD_MAINTENANCE; @@ -216,7 +216,7 @@ static int mei_nfc_if_version(struct mei_nfc_dev *ndev) ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd), 1); if (ret < 0) { - dev_err(dev->dev, "Could not send IF version cmd\n"); + dev_err(bus->dev, "Could not send IF version cmd\n"); return ret; } @@ -230,7 +230,7 @@ static int mei_nfc_if_version(struct mei_nfc_dev *ndev) bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length); if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) { - dev_err(dev->dev, "Could not read IF version\n"); + dev_err(bus->dev, "Could not read IF version\n"); ret = -EIO; goto err; } @@ -248,7 +248,7 @@ err: static void mei_nfc_init(struct work_struct *work) { - struct mei_device *dev; + struct mei_device *bus; struct mei_cl_device *cldev; struct mei_nfc_dev *ndev; struct mei_cl *cl_info; @@ -257,57 +257,57 @@ static void mei_nfc_init(struct work_struct *work) ndev = container_of(work, struct mei_nfc_dev, init_work); cl_info = ndev->cl_info; - dev = cl_info->dev; + bus = cl_info->dev; - mutex_lock(&dev->device_lock); + mutex_lock(&bus->device_lock); /* check for valid client id */ - me_cl_info = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid); + me_cl_info = mei_me_cl_by_uuid(bus, &mei_nfc_info_guid); if (!me_cl_info) { - mutex_unlock(&dev->device_lock); - dev_info(dev->dev, "nfc: failed to find the info client\n"); + mutex_unlock(&bus->device_lock); + dev_info(bus->dev, "nfc: failed to find the info client\n"); goto err; } if (mei_cl_connect(cl_info, me_cl_info, NULL) < 0) { mei_me_cl_put(me_cl_info); - mutex_unlock(&dev->device_lock); - dev_err(dev->dev, "Could not connect to the NFC INFO ME client"); + mutex_unlock(&bus->device_lock); + dev_err(bus->dev, "Could not connect to the NFC INFO ME client"); goto err; } mei_me_cl_put(me_cl_info); - mutex_unlock(&dev->device_lock); + mutex_unlock(&bus->device_lock); if (mei_nfc_if_version(ndev) < 0) { - dev_err(dev->dev, "Could not get the NFC interface version"); + dev_err(bus->dev, "Could not get the NFC interface version"); goto err; } - dev_info(dev->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n", + dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n", ndev->fw_ivn, ndev->vendor_id, ndev->radio_type); - mutex_lock(&dev->device_lock); + mutex_lock(&bus->device_lock); if (mei_cl_disconnect(cl_info) < 0) { - mutex_unlock(&dev->device_lock); - dev_err(dev->dev, "Could not disconnect the NFC INFO ME client"); + mutex_unlock(&bus->device_lock); + dev_err(bus->dev, "Could not disconnect the NFC INFO ME client"); goto err; } - mutex_unlock(&dev->device_lock); + mutex_unlock(&bus->device_lock); if (mei_nfc_build_bus_name(ndev) < 0) { - dev_err(dev->dev, "Could not build the bus ID name\n"); + dev_err(bus->dev, "Could not build the bus ID name\n"); return; } - cldev = mei_cl_add_device(dev, ndev->me_cl, ndev->cl, + cldev = mei_cl_add_device(bus, ndev->me_cl, ndev->cl, ndev->bus_name); if (!cldev) { - dev_err(dev->dev, "Could not add the NFC device to the MEI bus\n"); + dev_err(bus->dev, "Could not add the NFC device to the MEI bus\n"); goto err; } @@ -318,14 +318,14 @@ static void mei_nfc_init(struct work_struct *work) return; err: - mutex_lock(&dev->device_lock); + mutex_lock(&bus->device_lock); mei_nfc_free(ndev); - mutex_unlock(&dev->device_lock); + mutex_unlock(&bus->device_lock); } -int mei_nfc_host_init(struct mei_device *dev, struct mei_me_client *me_cl) +int mei_nfc_host_init(struct mei_device *bus, struct mei_me_client *me_cl) { struct mei_nfc_dev *ndev; struct mei_cl *cl_info, *cl; @@ -335,7 +335,7 @@ int mei_nfc_host_init(struct mei_device *dev, struct mei_me_client *me_cl) /* in case of internal reset bail out * as the device is already setup */ - cl = mei_cl_bus_find_cl_by_uuid(dev, mei_nfc_guid); + cl = mei_cl_bus_find_cl_by_uuid(bus, mei_nfc_guid); if (cl) return 0; @@ -351,23 +351,23 @@ int mei_nfc_host_init(struct mei_device *dev, struct mei_me_client *me_cl) goto err; } - cl_info = mei_cl_alloc_linked(dev, MEI_HOST_CLIENT_ID_ANY); + cl_info = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY); if (IS_ERR(cl_info)) { ret = PTR_ERR(cl_info); goto err; } - list_add_tail(&cl_info->device_link, &dev->device_list); + list_add_tail(&cl_info->device_link, &bus->device_list); ndev->cl_info = cl_info; - cl = mei_cl_alloc_linked(dev, MEI_HOST_CLIENT_ID_ANY); + cl = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY); if (IS_ERR(cl)) { ret = PTR_ERR(cl); goto err; } - list_add_tail(&cl->device_link, &dev->device_list); + list_add_tail(&cl->device_link, &bus->device_list); ndev->cl = cl; @@ -382,17 +382,17 @@ err: return ret; } -void mei_nfc_host_exit(struct mei_device *dev) +void mei_nfc_host_exit(struct mei_device *bus) { struct mei_nfc_dev *ndev; struct mei_cl *cl; struct mei_cl_device *cldev; - cl = mei_cl_bus_find_cl_by_uuid(dev, mei_nfc_guid); + cl = mei_cl_bus_find_cl_by_uuid(bus, mei_nfc_guid); if (!cl) return; - cldev = cl->device; + cldev = cl->cldev; if (!cldev) return; @@ -407,9 +407,9 @@ void mei_nfc_host_exit(struct mei_device *dev) */ mei_cl_remove_device(cldev); - mutex_lock(&dev->device_lock); + mutex_lock(&bus->device_lock); mei_nfc_free(ndev); - mutex_unlock(&dev->device_lock); + mutex_unlock(&bus->device_lock); } -- cgit v1.3-6-gb490 From a0a785c4ab91656a5413b4cd5bb8ed59f39f7446 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:34 +0300 Subject: mei: bus: rename nfc.c to bus-fixup.c The bus-fixup.c will be a place for fixups and quirks for all types of me client devices. As for now it contians only the fixup for setting the nfc device name on the me client bus. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/Makefile | 2 +- drivers/misc/mei/bus-fixup.c | 415 +++++++++++++++++++++++++++++++++++++++++++ drivers/misc/mei/nfc.c | 415 ------------------------------------------- 3 files changed, 416 insertions(+), 416 deletions(-) create mode 100644 drivers/misc/mei/bus-fixup.c delete mode 100644 drivers/misc/mei/nfc.c (limited to 'drivers') diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile index 518914a82b83..01447ca21c26 100644 --- a/drivers/misc/mei/Makefile +++ b/drivers/misc/mei/Makefile @@ -11,7 +11,7 @@ mei-objs += main.o mei-objs += amthif.o mei-objs += wd.o mei-objs += bus.o -mei-objs += nfc.o +mei-objs += bus-fixup.o mei-$(CONFIG_DEBUG_FS) += debugfs.o obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c new file mode 100644 index 000000000000..47aa1523d9e1 --- /dev/null +++ b/drivers/misc/mei/bus-fixup.c @@ -0,0 +1,415 @@ +/* + * + * Intel Management Engine Interface (Intel MEI) Linux driver + * Copyright (c) 2003-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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "mei_dev.h" +#include "client.h" + +struct mei_nfc_cmd { + u8 command; + u8 status; + u16 req_id; + u32 reserved; + u16 data_size; + u8 sub_command; + u8 data[]; +} __packed; + +struct mei_nfc_reply { + u8 command; + u8 status; + u16 req_id; + u32 reserved; + u16 data_size; + u8 sub_command; + u8 reply_status; + u8 data[]; +} __packed; + +struct mei_nfc_if_version { + u8 radio_version_sw[3]; + u8 reserved[3]; + u8 radio_version_hw[3]; + u8 i2c_addr; + u8 fw_ivn; + u8 vendor_id; + u8 radio_type; +} __packed; + +struct mei_nfc_connect { + u8 fw_ivn; + u8 vendor_id; +} __packed; + +struct mei_nfc_connect_resp { + u8 fw_ivn; + u8 vendor_id; + u16 me_major; + u16 me_minor; + u16 me_hotfix; + u16 me_build; +} __packed; + +struct mei_nfc_hci_hdr { + u8 cmd; + u8 status; + u16 req_id; + u32 reserved; + u16 data_size; +} __packed; + +#define MEI_NFC_CMD_MAINTENANCE 0x00 +#define MEI_NFC_CMD_HCI_SEND 0x01 +#define MEI_NFC_CMD_HCI_RECV 0x02 + +#define MEI_NFC_SUBCMD_CONNECT 0x00 +#define MEI_NFC_SUBCMD_IF_VERSION 0x01 + +#define MEI_NFC_HEADER_SIZE 10 + +/** + * struct mei_nfc_dev - NFC mei device + * + * @me_cl: NFC me client + * @cl: NFC host client + * @cl_info: NFC info host client + * @init_work: perform connection to the info client + * @fw_ivn: NFC Interface Version Number + * @vendor_id: NFC manufacturer ID + * @radio_type: NFC radio type + * @bus_name: bus name + * + */ +struct mei_nfc_dev { + struct mei_me_client *me_cl; + struct mei_cl *cl; + struct mei_cl *cl_info; + struct work_struct init_work; + u8 fw_ivn; + u8 vendor_id; + u8 radio_type; + char *bus_name; +}; + +/* UUIDs for NFC F/W clients */ +const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, + 0x94, 0xd4, 0x50, 0x26, + 0x67, 0x23, 0x77, 0x5c); + +static const uuid_le mei_nfc_info_guid = UUID_LE(0xd2de1625, 0x382d, 0x417d, + 0x48, 0xa4, 0xef, 0xab, + 0xba, 0x8a, 0x12, 0x06); + +/* Vendors */ +#define MEI_NFC_VENDOR_INSIDE 0x00 +#define MEI_NFC_VENDOR_NXP 0x01 + +/* Radio types */ +#define MEI_NFC_VENDOR_INSIDE_UREAD 0x00 +#define MEI_NFC_VENDOR_NXP_PN544 0x01 + +static void mei_nfc_free(struct mei_nfc_dev *ndev) +{ + if (!ndev) + return; + + if (ndev->cl) { + list_del(&ndev->cl->device_link); + mei_cl_unlink(ndev->cl); + kfree(ndev->cl); + } + + if (ndev->cl_info) { + list_del(&ndev->cl_info->device_link); + mei_cl_unlink(ndev->cl_info); + kfree(ndev->cl_info); + } + + mei_me_cl_put(ndev->me_cl); + kfree(ndev); +} + +static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev) +{ + struct mei_device *bus; + + if (!ndev->cl) + return -ENODEV; + + bus = ndev->cl->dev; + + switch (ndev->vendor_id) { + case MEI_NFC_VENDOR_INSIDE: + switch (ndev->radio_type) { + case MEI_NFC_VENDOR_INSIDE_UREAD: + ndev->bus_name = "microread"; + return 0; + + default: + dev_err(bus->dev, "Unknown radio type 0x%x\n", + ndev->radio_type); + + return -EINVAL; + } + + case MEI_NFC_VENDOR_NXP: + switch (ndev->radio_type) { + case MEI_NFC_VENDOR_NXP_PN544: + ndev->bus_name = "pn544"; + return 0; + default: + dev_err(bus->dev, "Unknown radio type 0x%x\n", + ndev->radio_type); + + return -EINVAL; + } + + default: + dev_err(bus->dev, "Unknown vendor ID 0x%x\n", + ndev->vendor_id); + + return -EINVAL; + } + + return 0; +} + +static int mei_nfc_if_version(struct mei_nfc_dev *ndev) +{ + struct mei_device *bus; + struct mei_cl *cl; + + struct mei_nfc_cmd cmd; + struct mei_nfc_reply *reply = NULL; + struct mei_nfc_if_version *version; + size_t if_version_length; + int bytes_recv, ret; + + cl = ndev->cl_info; + bus = cl->dev; + + memset(&cmd, 0, sizeof(struct mei_nfc_cmd)); + cmd.command = MEI_NFC_CMD_MAINTENANCE; + cmd.data_size = 1; + cmd.sub_command = MEI_NFC_SUBCMD_IF_VERSION; + + ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd), 1); + if (ret < 0) { + dev_err(bus->dev, "Could not send IF version cmd\n"); + return ret; + } + + /* to be sure on the stack we alloc memory */ + if_version_length = sizeof(struct mei_nfc_reply) + + sizeof(struct mei_nfc_if_version); + + reply = kzalloc(if_version_length, GFP_KERNEL); + if (!reply) + return -ENOMEM; + + bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length); + if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) { + dev_err(bus->dev, "Could not read IF version\n"); + ret = -EIO; + goto err; + } + + version = (struct mei_nfc_if_version *)reply->data; + + ndev->fw_ivn = version->fw_ivn; + ndev->vendor_id = version->vendor_id; + ndev->radio_type = version->radio_type; + +err: + kfree(reply); + return ret; +} + +static void mei_nfc_init(struct work_struct *work) +{ + struct mei_device *bus; + struct mei_cl_device *cldev; + struct mei_nfc_dev *ndev; + struct mei_cl *cl_info; + struct mei_me_client *me_cl_info; + + ndev = container_of(work, struct mei_nfc_dev, init_work); + + cl_info = ndev->cl_info; + bus = cl_info->dev; + + mutex_lock(&bus->device_lock); + + /* check for valid client id */ + me_cl_info = mei_me_cl_by_uuid(bus, &mei_nfc_info_guid); + if (!me_cl_info) { + mutex_unlock(&bus->device_lock); + dev_info(bus->dev, "nfc: failed to find the info client\n"); + goto err; + } + + if (mei_cl_connect(cl_info, me_cl_info, NULL) < 0) { + mei_me_cl_put(me_cl_info); + mutex_unlock(&bus->device_lock); + dev_err(bus->dev, "Could not connect to the NFC INFO ME client"); + + goto err; + } + mei_me_cl_put(me_cl_info); + mutex_unlock(&bus->device_lock); + + if (mei_nfc_if_version(ndev) < 0) { + dev_err(bus->dev, "Could not get the NFC interface version"); + + goto err; + } + + dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n", + ndev->fw_ivn, ndev->vendor_id, ndev->radio_type); + + mutex_lock(&bus->device_lock); + + if (mei_cl_disconnect(cl_info) < 0) { + mutex_unlock(&bus->device_lock); + dev_err(bus->dev, "Could not disconnect the NFC INFO ME client"); + + goto err; + } + + mutex_unlock(&bus->device_lock); + + if (mei_nfc_build_bus_name(ndev) < 0) { + dev_err(bus->dev, "Could not build the bus ID name\n"); + return; + } + + cldev = mei_cl_add_device(bus, ndev->me_cl, ndev->cl, + ndev->bus_name); + if (!cldev) { + dev_err(bus->dev, "Could not add the NFC device to the MEI bus\n"); + + goto err; + } + + cldev->priv_data = ndev; + + + return; + +err: + mutex_lock(&bus->device_lock); + mei_nfc_free(ndev); + mutex_unlock(&bus->device_lock); + +} + + +int mei_nfc_host_init(struct mei_device *bus, struct mei_me_client *me_cl) +{ + struct mei_nfc_dev *ndev; + struct mei_cl *cl_info, *cl; + int ret; + + + /* in case of internal reset bail out + * as the device is already setup + */ + cl = mei_cl_bus_find_cl_by_uuid(bus, mei_nfc_guid); + if (cl) + return 0; + + ndev = kzalloc(sizeof(struct mei_nfc_dev), GFP_KERNEL); + if (!ndev) { + ret = -ENOMEM; + goto err; + } + + ndev->me_cl = mei_me_cl_get(me_cl); + if (!ndev->me_cl) { + ret = -ENODEV; + goto err; + } + + cl_info = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY); + if (IS_ERR(cl_info)) { + ret = PTR_ERR(cl_info); + goto err; + } + + list_add_tail(&cl_info->device_link, &bus->device_list); + + ndev->cl_info = cl_info; + + cl = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY); + if (IS_ERR(cl)) { + ret = PTR_ERR(cl); + goto err; + } + + list_add_tail(&cl->device_link, &bus->device_list); + + ndev->cl = cl; + + INIT_WORK(&ndev->init_work, mei_nfc_init); + schedule_work(&ndev->init_work); + + return 0; + +err: + mei_nfc_free(ndev); + + return ret; +} + +void mei_nfc_host_exit(struct mei_device *bus) +{ + struct mei_nfc_dev *ndev; + struct mei_cl *cl; + struct mei_cl_device *cldev; + + cl = mei_cl_bus_find_cl_by_uuid(bus, mei_nfc_guid); + if (!cl) + return; + + cldev = cl->cldev; + if (!cldev) + return; + + ndev = (struct mei_nfc_dev *)cldev->priv_data; + if (ndev) + cancel_work_sync(&ndev->init_work); + + cldev->priv_data = NULL; + + /* Need to remove the device here + * since mei_nfc_free will unlink the clients + */ + mei_cl_remove_device(cldev); + + mutex_lock(&bus->device_lock); + mei_nfc_free(ndev); + mutex_unlock(&bus->device_lock); +} + + diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c deleted file mode 100644 index 47aa1523d9e1..000000000000 --- a/drivers/misc/mei/nfc.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-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. - * - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "mei_dev.h" -#include "client.h" - -struct mei_nfc_cmd { - u8 command; - u8 status; - u16 req_id; - u32 reserved; - u16 data_size; - u8 sub_command; - u8 data[]; -} __packed; - -struct mei_nfc_reply { - u8 command; - u8 status; - u16 req_id; - u32 reserved; - u16 data_size; - u8 sub_command; - u8 reply_status; - u8 data[]; -} __packed; - -struct mei_nfc_if_version { - u8 radio_version_sw[3]; - u8 reserved[3]; - u8 radio_version_hw[3]; - u8 i2c_addr; - u8 fw_ivn; - u8 vendor_id; - u8 radio_type; -} __packed; - -struct mei_nfc_connect { - u8 fw_ivn; - u8 vendor_id; -} __packed; - -struct mei_nfc_connect_resp { - u8 fw_ivn; - u8 vendor_id; - u16 me_major; - u16 me_minor; - u16 me_hotfix; - u16 me_build; -} __packed; - -struct mei_nfc_hci_hdr { - u8 cmd; - u8 status; - u16 req_id; - u32 reserved; - u16 data_size; -} __packed; - -#define MEI_NFC_CMD_MAINTENANCE 0x00 -#define MEI_NFC_CMD_HCI_SEND 0x01 -#define MEI_NFC_CMD_HCI_RECV 0x02 - -#define MEI_NFC_SUBCMD_CONNECT 0x00 -#define MEI_NFC_SUBCMD_IF_VERSION 0x01 - -#define MEI_NFC_HEADER_SIZE 10 - -/** - * struct mei_nfc_dev - NFC mei device - * - * @me_cl: NFC me client - * @cl: NFC host client - * @cl_info: NFC info host client - * @init_work: perform connection to the info client - * @fw_ivn: NFC Interface Version Number - * @vendor_id: NFC manufacturer ID - * @radio_type: NFC radio type - * @bus_name: bus name - * - */ -struct mei_nfc_dev { - struct mei_me_client *me_cl; - struct mei_cl *cl; - struct mei_cl *cl_info; - struct work_struct init_work; - u8 fw_ivn; - u8 vendor_id; - u8 radio_type; - char *bus_name; -}; - -/* UUIDs for NFC F/W clients */ -const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, - 0x94, 0xd4, 0x50, 0x26, - 0x67, 0x23, 0x77, 0x5c); - -static const uuid_le mei_nfc_info_guid = UUID_LE(0xd2de1625, 0x382d, 0x417d, - 0x48, 0xa4, 0xef, 0xab, - 0xba, 0x8a, 0x12, 0x06); - -/* Vendors */ -#define MEI_NFC_VENDOR_INSIDE 0x00 -#define MEI_NFC_VENDOR_NXP 0x01 - -/* Radio types */ -#define MEI_NFC_VENDOR_INSIDE_UREAD 0x00 -#define MEI_NFC_VENDOR_NXP_PN544 0x01 - -static void mei_nfc_free(struct mei_nfc_dev *ndev) -{ - if (!ndev) - return; - - if (ndev->cl) { - list_del(&ndev->cl->device_link); - mei_cl_unlink(ndev->cl); - kfree(ndev->cl); - } - - if (ndev->cl_info) { - list_del(&ndev->cl_info->device_link); - mei_cl_unlink(ndev->cl_info); - kfree(ndev->cl_info); - } - - mei_me_cl_put(ndev->me_cl); - kfree(ndev); -} - -static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev) -{ - struct mei_device *bus; - - if (!ndev->cl) - return -ENODEV; - - bus = ndev->cl->dev; - - switch (ndev->vendor_id) { - case MEI_NFC_VENDOR_INSIDE: - switch (ndev->radio_type) { - case MEI_NFC_VENDOR_INSIDE_UREAD: - ndev->bus_name = "microread"; - return 0; - - default: - dev_err(bus->dev, "Unknown radio type 0x%x\n", - ndev->radio_type); - - return -EINVAL; - } - - case MEI_NFC_VENDOR_NXP: - switch (ndev->radio_type) { - case MEI_NFC_VENDOR_NXP_PN544: - ndev->bus_name = "pn544"; - return 0; - default: - dev_err(bus->dev, "Unknown radio type 0x%x\n", - ndev->radio_type); - - return -EINVAL; - } - - default: - dev_err(bus->dev, "Unknown vendor ID 0x%x\n", - ndev->vendor_id); - - return -EINVAL; - } - - return 0; -} - -static int mei_nfc_if_version(struct mei_nfc_dev *ndev) -{ - struct mei_device *bus; - struct mei_cl *cl; - - struct mei_nfc_cmd cmd; - struct mei_nfc_reply *reply = NULL; - struct mei_nfc_if_version *version; - size_t if_version_length; - int bytes_recv, ret; - - cl = ndev->cl_info; - bus = cl->dev; - - memset(&cmd, 0, sizeof(struct mei_nfc_cmd)); - cmd.command = MEI_NFC_CMD_MAINTENANCE; - cmd.data_size = 1; - cmd.sub_command = MEI_NFC_SUBCMD_IF_VERSION; - - ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd), 1); - if (ret < 0) { - dev_err(bus->dev, "Could not send IF version cmd\n"); - return ret; - } - - /* to be sure on the stack we alloc memory */ - if_version_length = sizeof(struct mei_nfc_reply) + - sizeof(struct mei_nfc_if_version); - - reply = kzalloc(if_version_length, GFP_KERNEL); - if (!reply) - return -ENOMEM; - - bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length); - if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) { - dev_err(bus->dev, "Could not read IF version\n"); - ret = -EIO; - goto err; - } - - version = (struct mei_nfc_if_version *)reply->data; - - ndev->fw_ivn = version->fw_ivn; - ndev->vendor_id = version->vendor_id; - ndev->radio_type = version->radio_type; - -err: - kfree(reply); - return ret; -} - -static void mei_nfc_init(struct work_struct *work) -{ - struct mei_device *bus; - struct mei_cl_device *cldev; - struct mei_nfc_dev *ndev; - struct mei_cl *cl_info; - struct mei_me_client *me_cl_info; - - ndev = container_of(work, struct mei_nfc_dev, init_work); - - cl_info = ndev->cl_info; - bus = cl_info->dev; - - mutex_lock(&bus->device_lock); - - /* check for valid client id */ - me_cl_info = mei_me_cl_by_uuid(bus, &mei_nfc_info_guid); - if (!me_cl_info) { - mutex_unlock(&bus->device_lock); - dev_info(bus->dev, "nfc: failed to find the info client\n"); - goto err; - } - - if (mei_cl_connect(cl_info, me_cl_info, NULL) < 0) { - mei_me_cl_put(me_cl_info); - mutex_unlock(&bus->device_lock); - dev_err(bus->dev, "Could not connect to the NFC INFO ME client"); - - goto err; - } - mei_me_cl_put(me_cl_info); - mutex_unlock(&bus->device_lock); - - if (mei_nfc_if_version(ndev) < 0) { - dev_err(bus->dev, "Could not get the NFC interface version"); - - goto err; - } - - dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n", - ndev->fw_ivn, ndev->vendor_id, ndev->radio_type); - - mutex_lock(&bus->device_lock); - - if (mei_cl_disconnect(cl_info) < 0) { - mutex_unlock(&bus->device_lock); - dev_err(bus->dev, "Could not disconnect the NFC INFO ME client"); - - goto err; - } - - mutex_unlock(&bus->device_lock); - - if (mei_nfc_build_bus_name(ndev) < 0) { - dev_err(bus->dev, "Could not build the bus ID name\n"); - return; - } - - cldev = mei_cl_add_device(bus, ndev->me_cl, ndev->cl, - ndev->bus_name); - if (!cldev) { - dev_err(bus->dev, "Could not add the NFC device to the MEI bus\n"); - - goto err; - } - - cldev->priv_data = ndev; - - - return; - -err: - mutex_lock(&bus->device_lock); - mei_nfc_free(ndev); - mutex_unlock(&bus->device_lock); - -} - - -int mei_nfc_host_init(struct mei_device *bus, struct mei_me_client *me_cl) -{ - struct mei_nfc_dev *ndev; - struct mei_cl *cl_info, *cl; - int ret; - - - /* in case of internal reset bail out - * as the device is already setup - */ - cl = mei_cl_bus_find_cl_by_uuid(bus, mei_nfc_guid); - if (cl) - return 0; - - ndev = kzalloc(sizeof(struct mei_nfc_dev), GFP_KERNEL); - if (!ndev) { - ret = -ENOMEM; - goto err; - } - - ndev->me_cl = mei_me_cl_get(me_cl); - if (!ndev->me_cl) { - ret = -ENODEV; - goto err; - } - - cl_info = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY); - if (IS_ERR(cl_info)) { - ret = PTR_ERR(cl_info); - goto err; - } - - list_add_tail(&cl_info->device_link, &bus->device_list); - - ndev->cl_info = cl_info; - - cl = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY); - if (IS_ERR(cl)) { - ret = PTR_ERR(cl); - goto err; - } - - list_add_tail(&cl->device_link, &bus->device_list); - - ndev->cl = cl; - - INIT_WORK(&ndev->init_work, mei_nfc_init); - schedule_work(&ndev->init_work); - - return 0; - -err: - mei_nfc_free(ndev); - - return ret; -} - -void mei_nfc_host_exit(struct mei_device *bus) -{ - struct mei_nfc_dev *ndev; - struct mei_cl *cl; - struct mei_cl_device *cldev; - - cl = mei_cl_bus_find_cl_by_uuid(bus, mei_nfc_guid); - if (!cl) - return; - - cldev = cl->cldev; - if (!cldev) - return; - - ndev = (struct mei_nfc_dev *)cldev->priv_data; - if (ndev) - cancel_work_sync(&ndev->init_work); - - cldev->priv_data = NULL; - - /* Need to remove the device here - * since mei_nfc_free will unlink the clients - */ - mei_cl_remove_device(cldev); - - mutex_lock(&bus->device_lock); - mei_nfc_free(ndev); - mutex_unlock(&bus->device_lock); -} - - -- cgit v1.3-6-gb490 From 6238299774377b12c3e24507b100b2687eb5ea32 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:35 +0300 Subject: mei: bus: move driver api functions at the start of the file To make the file more organize move mei client driver api to the start of the file and add Kdoc. There are no functional changes in this patch. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 799 +++++++++++++++++++++++++++---------------------- 1 file changed, 444 insertions(+), 355 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 18c37af22f07..6ea8a408f477 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -30,527 +30,616 @@ #define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver) #define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev) -static int mei_cl_device_match(struct device *dev, struct device_driver *drv) +/** + * __mei_cl_send - internal client send (write) + * + * @cl: host client + * @buf: buffer to send + * @length: buffer length + * @blocking: wait for write completion + * + * Return: written size bytes or < 0 on error + */ +ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, + bool blocking) { - struct mei_cl_device *cldev = to_mei_cl_device(dev); - struct mei_cl_driver *cldrv = to_mei_cl_driver(drv); - const struct mei_cl_device_id *id; - const uuid_le *uuid; - const char *name; - - if (!cldev) - return 0; + struct mei_device *bus; + struct mei_cl_cb *cb = NULL; + ssize_t rets; - uuid = mei_me_cl_uuid(cldev->me_cl); - name = cldev->name; + if (WARN_ON(!cl || !cl->dev)) + return -ENODEV; - if (!cldrv || !cldrv->id_table) - return 0; + bus = cl->dev; - id = cldrv->id_table; + mutex_lock(&bus->device_lock); + if (!mei_cl_is_connected(cl)) { + rets = -ENODEV; + goto out; + } - while (uuid_le_cmp(NULL_UUID_LE, id->uuid)) { + /* Check if we have an ME client device */ + if (!mei_me_cl_is_active(cl->me_cl)) { + rets = -ENOTTY; + goto out; + } - if (!uuid_le_cmp(*uuid, id->uuid)) { - if (id->name[0]) { - if (!strncmp(name, id->name, sizeof(id->name))) - return 1; - } else { - return 1; - } - } + if (length > mei_cl_mtu(cl)) { + rets = -EFBIG; + goto out; + } - id++; + cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, NULL); + if (!cb) { + rets = -ENOMEM; + goto out; } - return 0; + memcpy(cb->buf.data, buf, length); + + rets = mei_cl_write(cl, cb, blocking); + +out: + mutex_unlock(&bus->device_lock); + if (rets < 0) + mei_io_cb_free(cb); + + return rets; } -static int mei_cl_device_probe(struct device *dev) +/** + * __mei_cl_recv - internal client receive (read) + * + * @cl: host client + * @buf: buffer to send + * @length: buffer length + * + * Return: read size in bytes of < 0 on error + */ +ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) { - struct mei_cl_device *cldev = to_mei_cl_device(dev); - struct mei_cl_driver *cldrv; - struct mei_cl_device_id id; - - if (!cldev) - return 0; + struct mei_device *bus; + struct mei_cl_cb *cb; + size_t r_length; + ssize_t rets; - cldrv = to_mei_cl_driver(dev->driver); - if (!cldrv || !cldrv->probe) + if (WARN_ON(!cl || !cl->dev)) return -ENODEV; - dev_dbg(dev, "Device probe\n"); + bus = cl->dev; - strlcpy(id.name, cldev->name, sizeof(id.name)); + mutex_lock(&bus->device_lock); - return cldrv->probe(cldev, &id); -} + cb = mei_cl_read_cb(cl, NULL); + if (cb) + goto copy; -static int mei_cl_device_remove(struct device *dev) -{ - struct mei_cl_device *cldev = to_mei_cl_device(dev); - struct mei_cl_driver *cldrv; + rets = mei_cl_read_start(cl, length, NULL); + if (rets && rets != -EBUSY) + goto out; - if (!cldev || !dev->driver) - return 0; + /* wait on event only if there is no other waiter */ + if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) { - if (cldev->event_cb) { - cldev->event_cb = NULL; - cancel_work_sync(&cldev->event_work); - } + mutex_unlock(&bus->device_lock); - cldrv = to_mei_cl_driver(dev->driver); - if (!cldrv->remove) { - dev->driver = NULL; + if (wait_event_interruptible(cl->rx_wait, + (!list_empty(&cl->rd_completed)) || + (!mei_cl_is_connected(cl)))) { - return 0; + if (signal_pending(current)) + return -EINTR; + return -ERESTARTSYS; + } + + mutex_lock(&bus->device_lock); + + if (!mei_cl_is_connected(cl)) { + rets = -EBUSY; + goto out; + } } - return cldrv->remove(cldev); -} + cb = mei_cl_read_cb(cl, NULL); + if (!cb) { + rets = 0; + goto out; + } -static ssize_t name_show(struct device *dev, struct device_attribute *a, - char *buf) -{ - struct mei_cl_device *cldev = to_mei_cl_device(dev); - size_t len; +copy: + if (cb->status) { + rets = cb->status; + goto free; + } - len = snprintf(buf, PAGE_SIZE, "%s", cldev->name); + r_length = min_t(size_t, length, cb->buf_idx); + memcpy(buf, cb->buf.data, r_length); + rets = r_length; - return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; +free: + mei_io_cb_free(cb); +out: + mutex_unlock(&bus->device_lock); + + return rets; } -static DEVICE_ATTR_RO(name); -static ssize_t uuid_show(struct device *dev, struct device_attribute *a, - char *buf) +/** + * mei_cl_send - me device send (write) + * + * @cldev: me client device + * @buf: buffer to send + * @length: buffer length + * + * Return: written size in bytes or < 0 on error + */ +ssize_t mei_cl_send(struct mei_cl_device *cldev, u8 *buf, size_t length) { - struct mei_cl_device *cldev = to_mei_cl_device(dev); - const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); - size_t len; + struct mei_cl *cl = cldev->cl; - len = snprintf(buf, PAGE_SIZE, "%pUl", uuid); + if (cl == NULL) + return -ENODEV; - return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; + return __mei_cl_send(cl, buf, length, 1); } -static DEVICE_ATTR_RO(uuid); +EXPORT_SYMBOL_GPL(mei_cl_send); -static ssize_t modalias_show(struct device *dev, struct device_attribute *a, - char *buf) +/** + * mei_cl_recv - client receive (read) + * + * @cldev: me client device + * @buf: buffer to send + * @length: buffer length + * + * Return: read size in bytes of < 0 on error + */ +ssize_t mei_cl_recv(struct mei_cl_device *cldev, u8 *buf, size_t length) { - struct mei_cl_device *cldev = to_mei_cl_device(dev); - const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); - size_t len; + struct mei_cl *cl = cldev->cl; - len = snprintf(buf, PAGE_SIZE, "mei:%s:" MEI_CL_UUID_FMT ":", - cldev->name, MEI_CL_UUID_ARGS(uuid->b)); + if (cl == NULL) + return -ENODEV; - return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; + return __mei_cl_recv(cl, buf, length); } -static DEVICE_ATTR_RO(modalias); - -static struct attribute *mei_cl_dev_attrs[] = { - &dev_attr_name.attr, - &dev_attr_uuid.attr, - &dev_attr_modalias.attr, - NULL, -}; -ATTRIBUTE_GROUPS(mei_cl_dev); +EXPORT_SYMBOL_GPL(mei_cl_recv); -static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env) +/** + * mei_bus_event_work - dispatch rx event for a bus device + * and schedule new work + * + * @work: work + */ +static void mei_bus_event_work(struct work_struct *work) { - struct mei_cl_device *cldev = to_mei_cl_device(dev); - const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); + struct mei_cl_device *cldev; - if (add_uevent_var(env, "MEI_CL_UUID=%pUl", uuid)) - return -ENOMEM; + cldev = container_of(work, struct mei_cl_device, event_work); - if (add_uevent_var(env, "MEI_CL_NAME=%s", cldev->name)) - return -ENOMEM; + if (cldev->event_cb) + cldev->event_cb(cldev, cldev->events, cldev->event_context); - if (add_uevent_var(env, "MODALIAS=mei:%s:" MEI_CL_UUID_FMT ":", - cldev->name, MEI_CL_UUID_ARGS(uuid->b))) - return -ENOMEM; + cldev->events = 0; - return 0; + /* Prepare for the next read */ + mei_cl_read_start(cldev->cl, 0, NULL); } -static struct bus_type mei_cl_bus_type = { - .name = "mei", - .dev_groups = mei_cl_dev_groups, - .match = mei_cl_device_match, - .probe = mei_cl_device_probe, - .remove = mei_cl_device_remove, - .uevent = mei_cl_uevent, -}; - -static void mei_cl_dev_release(struct device *dev) +/** + * mei_cl_bus_rx_event - schedule rx evenet + * + * @cl: host client + */ +void mei_cl_bus_rx_event(struct mei_cl *cl) { - struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct mei_cl_device *cldev = cl->cldev; - if (!cldev) + if (!cldev || !cldev->event_cb) return; - mei_me_cl_put(cldev->me_cl); - kfree(cldev); -} - -static struct device_type mei_cl_device_type = { - .release = mei_cl_dev_release, -}; - -struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus, - uuid_le uuid) -{ - struct mei_cl *cl; - - list_for_each_entry(cl, &bus->device_list, device_link) { - if (cl->cldev && cl->cldev->me_cl && - !uuid_le_cmp(uuid, *mei_me_cl_uuid(cl->cldev->me_cl))) - return cl; - } + set_bit(MEI_CL_EVENT_RX, &cldev->events); - return NULL; + schedule_work(&cldev->event_work); } -struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, - struct mei_me_client *me_cl, - struct mei_cl *cl, - char *name) +/** + * mei_cl_register_event_cb - register event callback + * + * @cldev: me client devices + * @event_cb: callback function + * @context: driver context data + * + * Return: 0 on success + * -EALREADY if an callback is already registered + * <0 on other errors + */ +int mei_cl_register_event_cb(struct mei_cl_device *cldev, + mei_cl_event_cb_t event_cb, void *context) { - struct mei_cl_device *cldev; - int status; - - cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL); - if (!cldev) - return NULL; - - cldev->me_cl = mei_me_cl_get(me_cl); - if (!cldev->me_cl) { - kfree(cldev); - return NULL; - } - - cldev->cl = cl; - cldev->dev.parent = bus->dev; - cldev->dev.bus = &mei_cl_bus_type; - cldev->dev.type = &mei_cl_device_type; - - strlcpy(cldev->name, name, sizeof(cldev->name)); - - dev_set_name(&cldev->dev, "mei:%s:%pUl", name, mei_me_cl_uuid(me_cl)); + if (cldev->event_cb) + return -EALREADY; - status = device_register(&cldev->dev); - if (status) { - dev_err(bus->dev, "Failed to register MEI device\n"); - mei_me_cl_put(cldev->me_cl); - kfree(cldev); - return NULL; - } + cldev->events = 0; + cldev->event_cb = event_cb; + cldev->event_context = context; + INIT_WORK(&cldev->event_work, mei_bus_event_work); - cl->cldev = cldev; + mei_cl_read_start(cldev->cl, 0, NULL); - dev_dbg(&cldev->dev, "client %s registered\n", name); + return 0; +} +EXPORT_SYMBOL_GPL(mei_cl_register_event_cb); - return cldev; +/** + * mei_cl_get_drvdata - driver data getter + * + * @cldev: mei client device + * + * Return: driver private data + */ +void *mei_cl_get_drvdata(const struct mei_cl_device *cldev) +{ + return dev_get_drvdata(&cldev->dev); } -EXPORT_SYMBOL_GPL(mei_cl_add_device); +EXPORT_SYMBOL_GPL(mei_cl_get_drvdata); -void mei_cl_remove_device(struct mei_cl_device *cldev) +/** + * mei_cl_set_drvdata - driver data setter + * + * @cldev: mei client device + * @data: data to store + */ +void mei_cl_set_drvdata(struct mei_cl_device *cldev, void *data) { - device_unregister(&cldev->dev); + dev_set_drvdata(&cldev->dev, data); } -EXPORT_SYMBOL_GPL(mei_cl_remove_device); +EXPORT_SYMBOL_GPL(mei_cl_set_drvdata); -int __mei_cl_driver_register(struct mei_cl_driver *cldrv, struct module *owner) +/** + * mei_cl_enable_device - enable me client device + * create connection with me client + * + * @cldev: me client device + * + * Return: 0 on success and < 0 on error + */ +int mei_cl_enable_device(struct mei_cl_device *cldev) { int err; + struct mei_device *bus; + struct mei_cl *cl = cldev->cl; - cldrv->driver.name = cldrv->name; - cldrv->driver.owner = owner; - cldrv->driver.bus = &mei_cl_bus_type; + if (cl == NULL) + return -ENODEV; - err = driver_register(&cldrv->driver); - if (err) - return err; + bus = cl->dev; - pr_debug("mei: driver [%s] registered\n", cldrv->driver.name); + mutex_lock(&bus->device_lock); - return 0; -} -EXPORT_SYMBOL_GPL(__mei_cl_driver_register); + if (mei_cl_is_connected(cl)) { + mutex_unlock(&bus->device_lock); + dev_warn(bus->dev, "Already connected"); + return -EBUSY; + } -void mei_cl_driver_unregister(struct mei_cl_driver *cldrv) -{ - driver_unregister(&cldrv->driver); + err = mei_cl_connect(cl, cldev->me_cl, NULL); + if (err < 0) { + mutex_unlock(&bus->device_lock); + dev_err(bus->dev, "Could not connect to the ME client"); - pr_debug("mei: driver [%s] unregistered\n", cldrv->driver.name); + return err; + } + + mutex_unlock(&bus->device_lock); + + if (cldev->event_cb) + mei_cl_read_start(cldev->cl, 0, NULL); + + return 0; } -EXPORT_SYMBOL_GPL(mei_cl_driver_unregister); +EXPORT_SYMBOL_GPL(mei_cl_enable_device); -ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, - bool blocking) +/** + * mei_cl_disable_device - disable me client device + * disconnect form the me client + * + * @cldev: me client device + * + * Return: 0 on success and < 0 on error + */ +int mei_cl_disable_device(struct mei_cl_device *cldev) { + int err; struct mei_device *bus; - struct mei_cl_cb *cb = NULL; - ssize_t rets; + struct mei_cl *cl = cldev->cl; - if (WARN_ON(!cl || !cl->dev)) + if (cl == NULL) return -ENODEV; bus = cl->dev; - mutex_lock(&bus->device_lock); - if (!mei_cl_is_connected(cl)) { - rets = -ENODEV; - goto out; - } + cldev->event_cb = NULL; - /* Check if we have an ME client device */ - if (!mei_me_cl_is_active(cl->me_cl)) { - rets = -ENOTTY; - goto out; - } + mutex_lock(&bus->device_lock); - if (length > mei_cl_mtu(cl)) { - rets = -EFBIG; + if (!mei_cl_is_connected(cl)) { + dev_err(bus->dev, "Already disconnected"); + err = 0; goto out; } - cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, NULL); - if (!cb) { - rets = -ENOMEM; + err = mei_cl_disconnect(cl); + if (err < 0) { + dev_err(bus->dev, "Could not disconnect from the ME client"); goto out; } - memcpy(cb->buf.data, buf, length); - - rets = mei_cl_write(cl, cb, blocking); + /* Flush queues and remove any pending read */ + mei_cl_flush_queues(cl, NULL); out: mutex_unlock(&bus->device_lock); - if (rets < 0) - mei_io_cb_free(cb); + return err; - return rets; } +EXPORT_SYMBOL_GPL(mei_cl_disable_device); -ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) +static int mei_cl_device_match(struct device *dev, struct device_driver *drv) { - struct mei_device *bus; - struct mei_cl_cb *cb; - size_t r_length; - ssize_t rets; + struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct mei_cl_driver *cldrv = to_mei_cl_driver(drv); + const struct mei_cl_device_id *id; + const uuid_le *uuid; + const char *name; - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; + if (!cldev) + return 0; - bus = cl->dev; + uuid = mei_me_cl_uuid(cldev->me_cl); + name = cldev->name; - mutex_lock(&bus->device_lock); + if (!cldrv || !cldrv->id_table) + return 0; - cb = mei_cl_read_cb(cl, NULL); - if (cb) - goto copy; + id = cldrv->id_table; - rets = mei_cl_read_start(cl, length, NULL); - if (rets && rets != -EBUSY) - goto out; + while (uuid_le_cmp(NULL_UUID_LE, id->uuid)) { - if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) { + if (!uuid_le_cmp(*uuid, id->uuid)) { + if (id->name[0]) { + if (!strncmp(name, id->name, sizeof(id->name))) + return 1; + } else { + return 1; + } + } - mutex_unlock(&bus->device_lock); + id++; + } - if (wait_event_interruptible(cl->rx_wait, - (!list_empty(&cl->rd_completed)) || - (!mei_cl_is_connected(cl)))) { + return 0; +} - if (signal_pending(current)) - return -EINTR; - return -ERESTARTSYS; - } +static int mei_cl_device_probe(struct device *dev) +{ + struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct mei_cl_driver *cldrv; + struct mei_cl_device_id id; - mutex_lock(&bus->device_lock); + if (!cldev) + return 0; - if (!mei_cl_is_connected(cl)) { - rets = -EBUSY; - goto out; - } - } + cldrv = to_mei_cl_driver(dev->driver); + if (!cldrv || !cldrv->probe) + return -ENODEV; + + dev_dbg(dev, "Device probe\n"); + + strlcpy(id.name, cldev->name, sizeof(id.name)); + + return cldrv->probe(cldev, &id); +} - cb = mei_cl_read_cb(cl, NULL); - if (!cb) { - rets = 0; - goto out; - } +static int mei_cl_device_remove(struct device *dev) +{ + struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct mei_cl_driver *cldrv; -copy: - if (cb->status) { - rets = cb->status; - goto free; + if (!cldev || !dev->driver) + return 0; + + if (cldev->event_cb) { + cldev->event_cb = NULL; + cancel_work_sync(&cldev->event_work); } - r_length = min_t(size_t, length, cb->buf_idx); - memcpy(buf, cb->buf.data, r_length); - rets = r_length; + cldrv = to_mei_cl_driver(dev->driver); + if (!cldrv->remove) { + dev->driver = NULL; -free: - mei_io_cb_free(cb); -out: - mutex_unlock(&bus->device_lock); + return 0; + } - return rets; + return cldrv->remove(cldev); } -ssize_t mei_cl_send(struct mei_cl_device *cldev, u8 *buf, size_t length) +static ssize_t name_show(struct device *dev, struct device_attribute *a, + char *buf) { - struct mei_cl *cl = cldev->cl; + struct mei_cl_device *cldev = to_mei_cl_device(dev); + size_t len; - if (cl == NULL) - return -ENODEV; + len = snprintf(buf, PAGE_SIZE, "%s", cldev->name); - return __mei_cl_send(cl, buf, length, 1); + return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } -EXPORT_SYMBOL_GPL(mei_cl_send); +static DEVICE_ATTR_RO(name); -ssize_t mei_cl_recv(struct mei_cl_device *cldev, u8 *buf, size_t length) +static ssize_t uuid_show(struct device *dev, struct device_attribute *a, + char *buf) { - struct mei_cl *cl = cldev->cl; + struct mei_cl_device *cldev = to_mei_cl_device(dev); + const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); + size_t len; - if (cl == NULL) - return -ENODEV; + len = snprintf(buf, PAGE_SIZE, "%pUl", uuid); - return __mei_cl_recv(cl, buf, length); + return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } -EXPORT_SYMBOL_GPL(mei_cl_recv); +static DEVICE_ATTR_RO(uuid); -static void mei_bus_event_work(struct work_struct *work) +static ssize_t modalias_show(struct device *dev, struct device_attribute *a, + char *buf) { - struct mei_cl_device *cldev; - - cldev = container_of(work, struct mei_cl_device, event_work); - - if (cldev->event_cb) - cldev->event_cb(cldev, cldev->events, cldev->event_context); + struct mei_cl_device *cldev = to_mei_cl_device(dev); + const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); + size_t len; - cldev->events = 0; + len = snprintf(buf, PAGE_SIZE, "mei:%s:" MEI_CL_UUID_FMT ":", + cldev->name, MEI_CL_UUID_ARGS(uuid->b)); - /* Prepare for the next read */ - mei_cl_read_start(cldev->cl, 0, NULL); + return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; } +static DEVICE_ATTR_RO(modalias); -int mei_cl_register_event_cb(struct mei_cl_device *cldev, - mei_cl_event_cb_t event_cb, void *context) +static struct attribute *mei_cl_dev_attrs[] = { + &dev_attr_name.attr, + &dev_attr_uuid.attr, + &dev_attr_modalias.attr, + NULL, +}; +ATTRIBUTE_GROUPS(mei_cl_dev); + +static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env) { - if (cldev->event_cb) - return -EALREADY; + struct mei_cl_device *cldev = to_mei_cl_device(dev); + const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); - cldev->events = 0; - cldev->event_cb = event_cb; - cldev->event_context = context; - INIT_WORK(&cldev->event_work, mei_bus_event_work); + if (add_uevent_var(env, "MEI_CL_UUID=%pUl", uuid)) + return -ENOMEM; - mei_cl_read_start(cldev->cl, 0, NULL); + if (add_uevent_var(env, "MEI_CL_NAME=%s", cldev->name)) + return -ENOMEM; + + if (add_uevent_var(env, "MODALIAS=mei:%s:" MEI_CL_UUID_FMT ":", + cldev->name, MEI_CL_UUID_ARGS(uuid->b))) + return -ENOMEM; return 0; } -EXPORT_SYMBOL_GPL(mei_cl_register_event_cb); -void *mei_cl_get_drvdata(const struct mei_cl_device *cldev) +static struct bus_type mei_cl_bus_type = { + .name = "mei", + .dev_groups = mei_cl_dev_groups, + .match = mei_cl_device_match, + .probe = mei_cl_device_probe, + .remove = mei_cl_device_remove, + .uevent = mei_cl_uevent, +}; + +static void mei_cl_dev_release(struct device *dev) { - return dev_get_drvdata(&cldev->dev); + struct mei_cl_device *cldev = to_mei_cl_device(dev); + + if (!cldev) + return; + + mei_me_cl_put(cldev->me_cl); + kfree(cldev); } -EXPORT_SYMBOL_GPL(mei_cl_get_drvdata); -void mei_cl_set_drvdata(struct mei_cl_device *cldev, void *data) +static struct device_type mei_cl_device_type = { + .release = mei_cl_dev_release, +}; + +struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus, + uuid_le uuid) { - dev_set_drvdata(&cldev->dev, data); + struct mei_cl *cl; + + list_for_each_entry(cl, &bus->device_list, device_link) { + if (cl->cldev && cl->cldev->me_cl && + !uuid_le_cmp(uuid, *mei_me_cl_uuid(cl->cldev->me_cl))) + return cl; + } + + return NULL; } -EXPORT_SYMBOL_GPL(mei_cl_set_drvdata); -int mei_cl_enable_device(struct mei_cl_device *cldev) +struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, + struct mei_me_client *me_cl, + struct mei_cl *cl, + char *name) { - int err; - struct mei_device *bus; - struct mei_cl *cl = cldev->cl; + struct mei_cl_device *cldev; + int status; - if (cl == NULL) - return -ENODEV; + cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL); + if (!cldev) + return NULL; - bus = cl->dev; + cldev->me_cl = mei_me_cl_get(me_cl); + if (!cldev->me_cl) { + kfree(cldev); + return NULL; + } - mutex_lock(&bus->device_lock); + cldev->cl = cl; + cldev->dev.parent = bus->dev; + cldev->dev.bus = &mei_cl_bus_type; + cldev->dev.type = &mei_cl_device_type; - if (mei_cl_is_connected(cl)) { - mutex_unlock(&bus->device_lock); - dev_warn(bus->dev, "Already connected"); - return -EBUSY; - } + strlcpy(cldev->name, name, sizeof(cldev->name)); - err = mei_cl_connect(cl, cldev->me_cl, NULL); - if (err < 0) { - mutex_unlock(&bus->device_lock); - dev_err(bus->dev, "Could not connect to the ME client"); + dev_set_name(&cldev->dev, "mei:%s:%pUl", name, mei_me_cl_uuid(me_cl)); - return err; + status = device_register(&cldev->dev); + if (status) { + dev_err(bus->dev, "Failed to register MEI device\n"); + mei_me_cl_put(cldev->me_cl); + kfree(cldev); + return NULL; } - mutex_unlock(&bus->device_lock); + cl->cldev = cldev; - if (cldev->event_cb) - mei_cl_read_start(cldev->cl, 0, NULL); + dev_dbg(&cldev->dev, "client %s registered\n", name); - return 0; + return cldev; } -EXPORT_SYMBOL_GPL(mei_cl_enable_device); +EXPORT_SYMBOL_GPL(mei_cl_add_device); -int mei_cl_disable_device(struct mei_cl_device *cldev) +void mei_cl_remove_device(struct mei_cl_device *cldev) { - int err; - struct mei_device *bus; - struct mei_cl *cl = cldev->cl; - - if (cl == NULL) - return -ENODEV; - - bus = cl->dev; - - cldev->event_cb = NULL; - - mutex_lock(&bus->device_lock); + device_unregister(&cldev->dev); +} +EXPORT_SYMBOL_GPL(mei_cl_remove_device); - if (!mei_cl_is_connected(cl)) { - dev_err(bus->dev, "Already disconnected"); - err = 0; - goto out; - } +int __mei_cl_driver_register(struct mei_cl_driver *cldrv, struct module *owner) +{ + int err; - err = mei_cl_disconnect(cl); - if (err < 0) { - dev_err(bus->dev, "Could not disconnect from the ME client"); - goto out; - } + cldrv->driver.name = cldrv->name; + cldrv->driver.owner = owner; + cldrv->driver.bus = &mei_cl_bus_type; - /* Flush queues and remove any pending read */ - mei_cl_flush_queues(cl, NULL); + err = driver_register(&cldrv->driver); + if (err) + return err; -out: - mutex_unlock(&bus->device_lock); - return err; + pr_debug("mei: driver [%s] registered\n", cldrv->driver.name); + return 0; } -EXPORT_SYMBOL_GPL(mei_cl_disable_device); +EXPORT_SYMBOL_GPL(__mei_cl_driver_register); -void mei_cl_bus_rx_event(struct mei_cl *cl) +void mei_cl_driver_unregister(struct mei_cl_driver *cldrv) { - struct mei_cl_device *cldev = cl->cldev; - - if (!cldev || !cldev->event_cb) - return; - - set_bit(MEI_CL_EVENT_RX, &cldev->events); + driver_unregister(&cldrv->driver); - schedule_work(&cldev->event_work); + pr_debug("mei: driver [%s] unregistered\n", cldrv->driver.name); } +EXPORT_SYMBOL_GPL(mei_cl_driver_unregister); int __init mei_cl_bus_init(void) { -- cgit v1.3-6-gb490 From 38d3c00d3f312989e50aaf6f4a4b490b4e1e4c37 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:36 +0300 Subject: mei: bus: rename uevent handler to mei_cl_device_uevent Rename mei_cl_uevent to mei_cl_device_uevent to match the naming convention of mei_cl_bus_type functions Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 6ea8a408f477..bec213b92550 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -510,7 +510,15 @@ static struct attribute *mei_cl_dev_attrs[] = { }; ATTRIBUTE_GROUPS(mei_cl_dev); -static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env) +/** + * mei_cl_device_uevent - me client bus uevent handler + * + * @dev: device + * @env: uevent kobject + * + * Return: 0 on success -ENOMEM on when add_uevent_var fails + */ +static int mei_cl_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct mei_cl_device *cldev = to_mei_cl_device(dev); const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); @@ -534,7 +542,7 @@ static struct bus_type mei_cl_bus_type = { .match = mei_cl_device_match, .probe = mei_cl_device_probe, .remove = mei_cl_device_remove, - .uevent = mei_cl_uevent, + .uevent = mei_cl_device_uevent, }; static void mei_cl_dev_release(struct device *dev) -- cgit v1.3-6-gb490 From 7e280ab694e2885ee300de9cf5e7047c68230148 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:37 +0300 Subject: mei: bus: don't enable events implicitly in device enable Do not enable events implicitly in mei_cl_enable_device, it should be done explicitly using mei_cl_register_event_cb so the events are enabled only when needed. The NFC drivers has been already using it that way so no need for further changes just remove the code from mei_cl_enable_device. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index bec213b92550..257e200b5343 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -332,9 +332,6 @@ int mei_cl_enable_device(struct mei_cl_device *cldev) mutex_unlock(&bus->device_lock); - if (cldev->event_cb) - mei_cl_read_start(cldev->cl, 0, NULL); - return 0; } EXPORT_SYMBOL_GPL(mei_cl_enable_device); -- cgit v1.3-6-gb490 From 48168f4561f479403dbd38379dc8793488a22a6a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:38 +0300 Subject: mei: bus: report if event registration failed If event registeration has failed, the caller should know about it. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 257e200b5343..aba7688d1ddd 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -256,6 +256,8 @@ void mei_cl_bus_rx_event(struct mei_cl *cl) int mei_cl_register_event_cb(struct mei_cl_device *cldev, mei_cl_event_cb_t event_cb, void *context) { + int ret; + if (cldev->event_cb) return -EALREADY; @@ -264,7 +266,9 @@ int mei_cl_register_event_cb(struct mei_cl_device *cldev, cldev->event_context = context; INIT_WORK(&cldev->event_work, mei_bus_event_work); - mei_cl_read_start(cldev->cl, 0, NULL); + ret = mei_cl_read_start(cldev->cl, 0, NULL); + if (ret && ret != -EBUSY) + return ret; return 0; } -- cgit v1.3-6-gb490 From 688a9cce0c8e9116038586ae1cd6adabb10fa5aa Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:39 +0300 Subject: mei: bus: revamp device matching mei_cl_device_match now calls mei_cl_device_find that returns the matching device id in the device id table. We will utilize the mei_cl_device_find during probing to locate the matching entry. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 63 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index aba7688d1ddd..4955a0908d04 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -385,39 +385,64 @@ out: } EXPORT_SYMBOL_GPL(mei_cl_disable_device); -static int mei_cl_device_match(struct device *dev, struct device_driver *drv) +/** + * mei_cl_device_find - find matching entry in the driver id table + * + * @cldev: me client device + * @cldrv: me client driver + * + * Return: id on success; NULL if no id is matching + */ +static const +struct mei_cl_device_id *mei_cl_device_find(struct mei_cl_device *cldev, + struct mei_cl_driver *cldrv) { - struct mei_cl_device *cldev = to_mei_cl_device(dev); - struct mei_cl_driver *cldrv = to_mei_cl_driver(drv); const struct mei_cl_device_id *id; const uuid_le *uuid; - const char *name; - - if (!cldev) - return 0; uuid = mei_me_cl_uuid(cldev->me_cl); - name = cldev->name; - - if (!cldrv || !cldrv->id_table) - return 0; id = cldrv->id_table; - while (uuid_le_cmp(NULL_UUID_LE, id->uuid)) { - if (!uuid_le_cmp(*uuid, id->uuid)) { - if (id->name[0]) { - if (!strncmp(name, id->name, sizeof(id->name))) - return 1; - } else { - return 1; - } + + if (!cldev->name[0]) + return id; + + if (!strncmp(cldev->name, id->name, sizeof(id->name))) + return id; } id++; } + return NULL; +} + +/** + * mei_cl_device_match - device match function + * + * @dev: device + * @drv: driver + * + * Return: 1 if matching device was found 0 otherwise + */ +static int mei_cl_device_match(struct device *dev, struct device_driver *drv) +{ + struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct mei_cl_driver *cldrv = to_mei_cl_driver(drv); + const struct mei_cl_device_id *found_id; + + if (!cldev) + return 0; + + if (!cldrv || !cldrv->id_table) + return 0; + + found_id = mei_cl_device_find(cldev, cldrv); + if (found_id) + return 1; + return 0; } -- cgit v1.3-6-gb490 From feb8cd0fe7d63fd259c28f8a52fc88745717c9ec Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:40 +0300 Subject: mei: bus: revamp probe and remove functions Instead of generating device id on the fly during probing we find the matching id entry on the device id table. Get bus the module reference counter so it cannot be unloaded after the driver has bounded to the client device Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 4955a0908d04..1d9ce9c491cf 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -446,30 +446,49 @@ static int mei_cl_device_match(struct device *dev, struct device_driver *drv) return 0; } +/** + * mei_cl_device_probe - bus probe function + * + * @dev: device + * + * Return: 0 on success; < 0 otherwise + */ static int mei_cl_device_probe(struct device *dev) { - struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct mei_cl_device *cldev; struct mei_cl_driver *cldrv; - struct mei_cl_device_id id; + const struct mei_cl_device_id *id; + + cldev = to_mei_cl_device(dev); + cldrv = to_mei_cl_driver(dev->driver); if (!cldev) return 0; - cldrv = to_mei_cl_driver(dev->driver); if (!cldrv || !cldrv->probe) return -ENODEV; - dev_dbg(dev, "Device probe\n"); + id = mei_cl_device_find(cldev, cldrv); + if (!id) + return -ENODEV; - strlcpy(id.name, cldev->name, sizeof(id.name)); + __module_get(THIS_MODULE); - return cldrv->probe(cldev, &id); + return cldrv->probe(cldev, id); } +/** + * mei_cl_device_remove - remove device from the bus + * + * @dev: device + * + * Return: 0 on success; < 0 otherwise + */ static int mei_cl_device_remove(struct device *dev) { struct mei_cl_device *cldev = to_mei_cl_device(dev); struct mei_cl_driver *cldrv; + int ret = 0; if (!cldev || !dev->driver) return 0; @@ -480,13 +499,13 @@ static int mei_cl_device_remove(struct device *dev) } cldrv = to_mei_cl_driver(dev->driver); - if (!cldrv->remove) { - dev->driver = NULL; + if (cldrv->remove) + ret = cldrv->remove(cldev); - return 0; - } + module_put(THIS_MODULE); + dev->driver = NULL; + return ret; - return cldrv->remove(cldev); } static ssize_t name_show(struct device *dev, struct device_attribute *a, -- cgit v1.3-6-gb490 From 512f64d9f7467597388ffbd5a21589ee3f375d8b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:41 +0300 Subject: mei: bus: add reference to bus device in struct mei_cl_client Add reference to the bus device (mei_device) for easier access. To ensures that referencing cldev->bus is valid during cldev life time we increase the bus ref counter on a client device creation and drop it on the device release. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 17 +++++++++++++++++ include/linux/mei_cl_bus.h | 3 +++ 2 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 1d9ce9c491cf..963731eb4383 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -590,6 +590,20 @@ static struct bus_type mei_cl_bus_type = { .uevent = mei_cl_device_uevent, }; +static struct mei_device *mei_dev_bus_get(struct mei_device *bus) +{ + if (bus) + get_device(bus->dev); + + return bus; +} + +static void mei_dev_bus_put(struct mei_device *bus) +{ + if (bus) + put_device(bus->dev); +} + static void mei_cl_dev_release(struct device *dev) { struct mei_cl_device *cldev = to_mei_cl_device(dev); @@ -598,6 +612,7 @@ static void mei_cl_dev_release(struct device *dev) return; mei_me_cl_put(cldev->me_cl); + mei_dev_bus_put(cldev->bus); kfree(cldev); } @@ -641,6 +656,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, cldev->dev.parent = bus->dev; cldev->dev.bus = &mei_cl_bus_type; cldev->dev.type = &mei_cl_device_type; + cldev->bus = mei_dev_bus_get(bus); strlcpy(cldev->name, name, sizeof(cldev->name)); @@ -650,6 +666,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, if (status) { dev_err(bus->dev, "Failed to register MEI device\n"); mei_me_cl_put(cldev->me_cl); + mei_dev_bus_put(bus); kfree(cldev); return NULL; } diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index a16b1f9c1aca..4c5c25b3222c 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -6,6 +6,7 @@ #include struct mei_cl_device; +struct mei_device; typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device, u32 events, void *context); @@ -17,6 +18,7 @@ typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device, * Drivers for MEI devices will get an mei_cl_device pointer * when being probed and shall use it for doing ME bus I/O. * + * @bus: parent mei device * @dev: linux driver model device pointer * @me_cl: me client * @cl: mei client @@ -29,6 +31,7 @@ typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device, * @priv_data: client private data */ struct mei_cl_device { + struct mei_device *bus; struct device dev; struct mei_me_client *me_cl; -- cgit v1.3-6-gb490 From 0ff0a8d853039aa60bba3ca3e04e4fb74584a736 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:42 +0300 Subject: mei: bus: add me client device list infrastructure Instead of holding the list of host clients (me_cl) we want to keep the list me client devices (mei_cl_device) This way we can create host to me client connection only when needed. Add list head to mei_cl_device and cl_bus_lock Add bus_added flag to the me client (mei_me_client) to track if the appropriate mei_cl_device was already created and is_added flag to mei_cl_device to track if it was already added to the device list across the bus rescans Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 1 + drivers/misc/mei/init.c | 1 + drivers/misc/mei/mei_dev.h | 6 ++++-- include/linux/mei_cl_bus.h | 4 ++++ 4 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 963731eb4383..34b14dda050c 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -657,6 +657,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, cldev->dev.bus = &mei_cl_bus_type; cldev->dev.type = &mei_cl_device_type; cldev->bus = mei_dev_bus_get(bus); + INIT_LIST_HEAD(&cldev->bus_list); strlcpy(cldev->name, name, sizeof(cldev->name)); diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 00c3865ca3b1..15000e9231b1 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -390,6 +390,7 @@ void mei_device_init(struct mei_device *dev, INIT_LIST_HEAD(&dev->me_clients); mutex_init(&dev->device_lock); init_rwsem(&dev->me_clients_rwsem); + mutex_init(&dev->cl_bus_lock); init_waitqueue_head(&dev->wait_hw_ready); init_waitqueue_head(&dev->wait_pg); init_waitqueue_head(&dev->wait_hbm_start); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index bc65fb42aea9..882e6f77084a 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -178,7 +178,7 @@ struct mei_fw_status { * @client_id: me client id * @mei_flow_ctrl_creds: flow control credits * @connect_count: number connections to this client - * @reserved: reserved + * @bus_added: added to bus */ struct mei_me_client { struct list_head list; @@ -187,7 +187,7 @@ struct mei_me_client { u8 client_id; u8 mei_flow_ctrl_creds; u8 connect_count; - u8 reserved; + u8 bus_added; }; @@ -447,6 +447,7 @@ const char *mei_pg_state_str(enum mei_pg_state state); * @reset_work : work item for the device reset * * @device_list : mei client bus list + * @cl_bus_lock : client bus list lock * * @dbgfs_dir : debugfs mei root directory * @@ -543,6 +544,7 @@ struct mei_device { /* List of bus devices */ struct list_head device_list; + struct mutex cl_bus_lock; #if IS_ENABLED(CONFIG_DEBUG_FS) struct dentry *dbgfs_dir; diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index 4c5c25b3222c..85239138251c 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -18,6 +18,7 @@ typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device, * Drivers for MEI devices will get an mei_cl_device pointer * when being probed and shall use it for doing ME bus I/O. * + * @bus_list: device on the bus list * @bus: parent mei device * @dev: linux driver model device pointer * @me_cl: me client @@ -28,9 +29,11 @@ typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device, * events (e.g. Rx buffer pending) notifications. * @event_context: event callback run context * @events: Events bitmask sent to the driver. + * @is_added: device is already scanned * @priv_data: client private data */ struct mei_cl_device { + struct list_head bus_list; struct mei_device *bus; struct device dev; @@ -42,6 +45,7 @@ struct mei_cl_device { mei_cl_event_cb_t event_cb; void *event_context; unsigned long events; + unsigned int is_added:1; void *priv_data; }; -- cgit v1.3-6-gb490 From 71ce789115f878a07e4a6c43d6006cea6aee1078 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:43 +0300 Subject: mei: bus: enable running fixup routines before device registration Split the device registration into allocation and device struct initialization, device setup, and the final device registration. This why it is possible to run fixups and quirks during the setup stage on an initialized device. Each fixup routine effects do_match flag. If the flag is set to false at the end the device won't be registered on the bus. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus-fixup.c | 30 +++++++++++++++ drivers/misc/mei/bus.c | 91 ++++++++++++++++++++++++++++++++++++-------- drivers/misc/mei/mei_dev.h | 2 +- include/linux/mei_cl_bus.h | 4 ++ 4 files changed, 111 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 47aa1523d9e1..865e33bcd226 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -20,12 +20,15 @@ #include #include #include +#include #include #include "mei_dev.h" #include "client.h" +#define MEI_UUID_ANY NULL_UUID_LE + struct mei_nfc_cmd { u8 command; u8 status; @@ -412,4 +415,31 @@ void mei_nfc_host_exit(struct mei_device *bus) mutex_unlock(&bus->device_lock); } +#define MEI_FIXUP(_uuid, _hook) { _uuid, _hook } + +static struct mei_fixup { + + const uuid_le uuid; + void (*hook)(struct mei_cl_device *cldev); +} mei_fixups[] = {}; + +/** + * mei_cl_dev_fixup - run fixup handlers + * + * @cldev: me client device + */ +void mei_cl_dev_fixup(struct mei_cl_device *cldev) +{ + struct mei_fixup *f; + const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); + int i; + + for (i = 0; i < ARRAY_SIZE(mei_fixups); i++) { + + f = &mei_fixups[i]; + if (uuid_le_cmp(f->uuid, MEI_UUID_ANY) == 0 || + uuid_le_cmp(f->uuid, *uuid) == 0) + f->hook(cldev); + } +} diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 34b14dda050c..68b7756bf384 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -436,6 +436,9 @@ static int mei_cl_device_match(struct device *dev, struct device_driver *drv) if (!cldev) return 0; + if (!cldev->do_match) + return 0; + if (!cldrv || !cldrv->id_table) return 0; @@ -634,6 +637,76 @@ struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus, return NULL; } +/** + * mei_cl_dev_alloc - initialize and allocate mei client device + * + * @bus: mei device + * @me_cl: me client + * + * Return: allocated device structur or NULL on allocation failure + */ +static struct mei_cl_device *mei_cl_dev_alloc(struct mei_device *bus, + struct mei_me_client *me_cl) +{ + struct mei_cl_device *cldev; + + cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL); + if (!cldev) + return NULL; + + device_initialize(&cldev->dev); + cldev->dev.parent = bus->dev; + cldev->dev.bus = &mei_cl_bus_type; + cldev->dev.type = &mei_cl_device_type; + cldev->bus = mei_dev_bus_get(bus); + cldev->me_cl = mei_me_cl_get(me_cl); + cldev->is_added = 0; + INIT_LIST_HEAD(&cldev->bus_list); + + return cldev; +} + +/** + * mei_cl_dev_setup - setup me client device + * run fix up routines and set the device name + * + * @bus: mei device + * @cldev: me client device + * + * Return: true if the device is eligible for enumeration + */ +static bool mei_cl_dev_setup(struct mei_device *bus, + struct mei_cl_device *cldev) +{ + cldev->do_match = 1; + mei_cl_dev_fixup(cldev); + + if (cldev->do_match) + dev_set_name(&cldev->dev, "mei:%s:%pUl", + cldev->name, mei_me_cl_uuid(cldev->me_cl)); + + return cldev->do_match == 1; +} + +/** + * mei_cl_bus_dev_add - add me client devices + * + * @cldev: me client device + * + * Return: 0 on success; < 0 on failre + */ +static int mei_cl_bus_dev_add(struct mei_cl_device *cldev) +{ + int ret; + + dev_dbg(cldev->bus->dev, "adding %pUL\n", mei_me_cl_uuid(cldev->me_cl)); + ret = device_add(&cldev->dev); + if (!ret) + cldev->is_added = 1; + + return ret; +} + struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, struct mei_me_client *me_cl, struct mei_cl *cl, @@ -642,28 +715,16 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, struct mei_cl_device *cldev; int status; - cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL); + cldev = mei_cl_dev_alloc(bus, me_cl); if (!cldev) return NULL; - cldev->me_cl = mei_me_cl_get(me_cl); - if (!cldev->me_cl) { - kfree(cldev); - return NULL; - } - cldev->cl = cl; - cldev->dev.parent = bus->dev; - cldev->dev.bus = &mei_cl_bus_type; - cldev->dev.type = &mei_cl_device_type; - cldev->bus = mei_dev_bus_get(bus); - INIT_LIST_HEAD(&cldev->bus_list); - strlcpy(cldev->name, name, sizeof(cldev->name)); - dev_set_name(&cldev->dev, "mei:%s:%pUl", name, mei_me_cl_uuid(me_cl)); + mei_cl_dev_setup(bus, cldev); - status = device_register(&cldev->dev); + status = mei_cl_bus_dev_add(cldev); if (status) { dev_err(bus->dev, "Failed to register MEI device\n"); mei_me_cl_put(cldev->me_cl); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 882e6f77084a..ad59ab776f2d 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -335,7 +335,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, struct mei_cl *cl, char *name); void mei_cl_remove_device(struct mei_cl_device *cldev); - +void mei_cl_dev_fixup(struct mei_cl_device *dev); ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, bool blocking); ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index 85239138251c..81ab56dd0ae0 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -29,6 +29,8 @@ typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device, * events (e.g. Rx buffer pending) notifications. * @event_context: event callback run context * @events: Events bitmask sent to the driver. + * + * @do_match: wheather device can be matched with a driver * @is_added: device is already scanned * @priv_data: client private data */ @@ -45,6 +47,8 @@ struct mei_cl_device { mei_cl_event_cb_t event_cb; void *event_context; unsigned long events; + + unsigned int do_match:1; unsigned int is_added:1; void *priv_data; -- cgit v1.3-6-gb490 From 5b6dca29b416d8992d52d814aa4be5d7fc97799d Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:44 +0300 Subject: mei: bus: blacklist the nfc info client Blacklist nfc info client which is only used for retrieval of the NFC radio version Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus-fixup.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 865e33bcd226..696918a6fa4f 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -27,8 +27,23 @@ #include "mei_dev.h" #include "client.h" +#define MEI_UUID_NFC_INFO UUID_LE(0xd2de1625, 0x382d, 0x417d, \ + 0x48, 0xa4, 0xef, 0xab, 0xba, 0x8a, 0x12, 0x06) + #define MEI_UUID_ANY NULL_UUID_LE +/** + * blacklist - blacklist a client from the bus + * + * @cldev: me clients device + */ +static void blacklist(struct mei_cl_device *cldev) +{ + dev_dbg(&cldev->dev, "running hook %s on %pUl\n", + __func__, mei_me_cl_uuid(cldev->me_cl)); + cldev->do_match = 0; +} + struct mei_nfc_cmd { u8 command; u8 status; @@ -120,9 +135,7 @@ const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c); -static const uuid_le mei_nfc_info_guid = UUID_LE(0xd2de1625, 0x382d, 0x417d, - 0x48, 0xa4, 0xef, 0xab, - 0xba, 0x8a, 0x12, 0x06); +static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO; /* Vendors */ #define MEI_NFC_VENDOR_INSIDE 0x00 @@ -421,7 +434,9 @@ static struct mei_fixup { const uuid_le uuid; void (*hook)(struct mei_cl_device *cldev); -} mei_fixups[] = {}; +} mei_fixups[] = { + MEI_FIXUP(MEI_UUID_NFC_INFO, blacklist), +}; /** * mei_cl_dev_fixup - run fixup handlers -- cgit v1.3-6-gb490 From dd070a1694c563bd7ba5239dd3038ff1420cf856 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:45 +0300 Subject: mei: bus: blacklist clients by number of connections Currently we support only clients with single connection and fixed address clients so all other clients are blacklisted Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus-fixup.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 696918a6fa4f..fd6470f42671 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -32,6 +32,24 @@ #define MEI_UUID_ANY NULL_UUID_LE +/** + * number_of_connections - determine whether an client be on the bus + * according number of connections + * We support only clients: + * 1. with single connection + * 2. and fixed clients (max_number_of_connections == 0) + * + * @cldev: me clients device + */ +static void number_of_connections(struct mei_cl_device *cldev) +{ + dev_dbg(&cldev->dev, "running hook %s on %pUl\n", + __func__, mei_me_cl_uuid(cldev->me_cl)); + + if (cldev->me_cl->props.max_number_of_connections > 1) + cldev->do_match = 0; +} + /** * blacklist - blacklist a client from the bus * @@ -435,6 +453,7 @@ static struct mei_fixup { const uuid_le uuid; void (*hook)(struct mei_cl_device *cldev); } mei_fixups[] = { + MEI_FIXUP(MEI_UUID_ANY, number_of_connections), MEI_FIXUP(MEI_UUID_NFC_INFO, blacklist), }; -- cgit v1.3-6-gb490 From b39910c2e0ac7c3d0e2f1999b04308c771b1d8fc Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:46 +0300 Subject: mei: bus: simplify how we build nfc bus name Remove the dependency on struct ndev from the nfc device name creation function so it is possible to use it in a fixup routine Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus-fixup.c | 115 ++++++++++++++++++++----------------------- drivers/misc/mei/bus.c | 2 +- drivers/misc/mei/mei_dev.h | 2 +- 3 files changed, 55 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index fd6470f42671..a4c6719d36b4 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -145,7 +145,7 @@ struct mei_nfc_dev { u8 fw_ivn; u8 vendor_id; u8 radio_type; - char *bus_name; + const char *bus_name; }; /* UUIDs for NFC F/W clients */ @@ -184,69 +184,30 @@ static void mei_nfc_free(struct mei_nfc_dev *ndev) kfree(ndev); } -static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev) -{ - struct mei_device *bus; - - if (!ndev->cl) - return -ENODEV; - - bus = ndev->cl->dev; - - switch (ndev->vendor_id) { - case MEI_NFC_VENDOR_INSIDE: - switch (ndev->radio_type) { - case MEI_NFC_VENDOR_INSIDE_UREAD: - ndev->bus_name = "microread"; - return 0; - - default: - dev_err(bus->dev, "Unknown radio type 0x%x\n", - ndev->radio_type); - - return -EINVAL; - } - - case MEI_NFC_VENDOR_NXP: - switch (ndev->radio_type) { - case MEI_NFC_VENDOR_NXP_PN544: - ndev->bus_name = "pn544"; - return 0; - default: - dev_err(bus->dev, "Unknown radio type 0x%x\n", - ndev->radio_type); - - return -EINVAL; - } - - default: - dev_err(bus->dev, "Unknown vendor ID 0x%x\n", - ndev->vendor_id); - - return -EINVAL; - } - - return 0; -} - -static int mei_nfc_if_version(struct mei_nfc_dev *ndev) +/** + * mei_nfc_if_version - get NFC interface version + * + * @cl: host client (nfc info) + * @ver: NFC interface version to be filled in + * + * Return: 0 on success; < 0 otherwise + */ +static int mei_nfc_if_version(struct mei_cl *cl, + struct mei_nfc_if_version *ver) { struct mei_device *bus; - struct mei_cl *cl; - - struct mei_nfc_cmd cmd; + struct mei_nfc_cmd cmd = { + .command = MEI_NFC_CMD_MAINTENANCE, + .data_size = 1, + .sub_command = MEI_NFC_SUBCMD_IF_VERSION, + }; struct mei_nfc_reply *reply = NULL; - struct mei_nfc_if_version *version; size_t if_version_length; int bytes_recv, ret; - cl = ndev->cl_info; bus = cl->dev; - memset(&cmd, 0, sizeof(struct mei_nfc_cmd)); - cmd.command = MEI_NFC_CMD_MAINTENANCE; - cmd.data_size = 1; - cmd.sub_command = MEI_NFC_SUBCMD_IF_VERSION; + WARN_ON(mutex_is_locked(&bus->device_lock)); ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd), 1); if (ret < 0) { @@ -262,6 +223,7 @@ static int mei_nfc_if_version(struct mei_nfc_dev *ndev) if (!reply) return -ENOMEM; + ret = 0; bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length); if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) { dev_err(bus->dev, "Could not read IF version\n"); @@ -269,17 +231,39 @@ static int mei_nfc_if_version(struct mei_nfc_dev *ndev) goto err; } - version = (struct mei_nfc_if_version *)reply->data; + memcpy(ver, reply->data, sizeof(struct mei_nfc_if_version)); - ndev->fw_ivn = version->fw_ivn; - ndev->vendor_id = version->vendor_id; - ndev->radio_type = version->radio_type; + dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n", + ver->fw_ivn, ver->vendor_id, ver->radio_type); err: kfree(reply); return ret; } +/** + * mei_nfc_radio_name - derive nfc radio name from the interface version + * + * @ver: NFC radio version + * + * Return: radio name string + */ +static const char *mei_nfc_radio_name(struct mei_nfc_if_version *ver) +{ + + if (ver->vendor_id == MEI_NFC_VENDOR_INSIDE) { + if (ver->radio_type == MEI_NFC_VENDOR_INSIDE_UREAD) + return "microread"; + } + + if (ver->vendor_id == MEI_NFC_VENDOR_NXP) { + if (ver->radio_type == MEI_NFC_VENDOR_NXP_PN544) + return "pn544"; + } + + return NULL; +} + static void mei_nfc_init(struct work_struct *work) { struct mei_device *bus; @@ -287,6 +271,7 @@ static void mei_nfc_init(struct work_struct *work) struct mei_nfc_dev *ndev; struct mei_cl *cl_info; struct mei_me_client *me_cl_info; + struct mei_nfc_if_version version; ndev = container_of(work, struct mei_nfc_dev, init_work); @@ -313,12 +298,16 @@ static void mei_nfc_init(struct work_struct *work) mei_me_cl_put(me_cl_info); mutex_unlock(&bus->device_lock); - if (mei_nfc_if_version(ndev) < 0) { + if (mei_nfc_if_version(cl_info, &version) < 0) { dev_err(bus->dev, "Could not get the NFC interface version"); goto err; } + ndev->fw_ivn = version.fw_ivn; + ndev->vendor_id = version.vendor_id; + ndev->radio_type = version.radio_type; + dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n", ndev->fw_ivn, ndev->vendor_id, ndev->radio_type); @@ -333,7 +322,9 @@ static void mei_nfc_init(struct work_struct *work) mutex_unlock(&bus->device_lock); - if (mei_nfc_build_bus_name(ndev) < 0) { + ndev->bus_name = mei_nfc_radio_name(&version); + + if (!ndev->bus_name) { dev_err(bus->dev, "Could not build the bus ID name\n"); return; } diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 68b7756bf384..7e51700515f4 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -710,7 +710,7 @@ static int mei_cl_bus_dev_add(struct mei_cl_device *cldev) struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, struct mei_me_client *me_cl, struct mei_cl *cl, - char *name) + const char *name) { struct mei_cl_device *cldev; int status; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index ad59ab776f2d..7098dcaccc96 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -333,7 +333,7 @@ struct mei_hw_ops { struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, struct mei_me_client *me_cl, struct mei_cl *cl, - char *name); + const char *name); void mei_cl_remove_device(struct mei_cl_device *cldev); void mei_cl_dev_fixup(struct mei_cl_device *dev); ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, -- cgit v1.3-6-gb490 From 6009595a66e460af0b170d736398c49395cb4499 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 15:08:47 +0300 Subject: mei: bus: link client devices instead of host clients MEI bus was designed around nfc and was hard to extend. Instead of the hard coded way of adding the devices on the mei bus we scan the whole me client list and create a device for each eligible me client (mei_cl_bus_rescan); currently we support only clients with single connection and fixed address clients. NFC radio name detection is run as a fixup routine The patch replaces handling the device list based on struct me_cl to device list based on me_cl_devices. The creating a connection is pushed from the device creation time to device enablement. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus-fixup.c | 288 ++++++++++--------------------------------- drivers/misc/mei/bus.c | 213 ++++++++++++++++++++++---------- drivers/misc/mei/client.c | 9 +- drivers/misc/mei/init.c | 2 +- drivers/misc/mei/mei_dev.h | 11 +- 5 files changed, 213 insertions(+), 310 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index a4c6719d36b4..3e536ca85f7d 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -30,6 +30,11 @@ #define MEI_UUID_NFC_INFO UUID_LE(0xd2de1625, 0x382d, 0x417d, \ 0x48, 0xa4, 0xef, 0xab, 0xba, 0x8a, 0x12, 0x06) +static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO; + +#define MEI_UUID_NFC_HCI UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, \ + 0x94, 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c) + #define MEI_UUID_ANY NULL_UUID_LE /** @@ -93,68 +98,10 @@ struct mei_nfc_if_version { u8 radio_type; } __packed; -struct mei_nfc_connect { - u8 fw_ivn; - u8 vendor_id; -} __packed; - -struct mei_nfc_connect_resp { - u8 fw_ivn; - u8 vendor_id; - u16 me_major; - u16 me_minor; - u16 me_hotfix; - u16 me_build; -} __packed; - -struct mei_nfc_hci_hdr { - u8 cmd; - u8 status; - u16 req_id; - u32 reserved; - u16 data_size; -} __packed; #define MEI_NFC_CMD_MAINTENANCE 0x00 -#define MEI_NFC_CMD_HCI_SEND 0x01 -#define MEI_NFC_CMD_HCI_RECV 0x02 - -#define MEI_NFC_SUBCMD_CONNECT 0x00 #define MEI_NFC_SUBCMD_IF_VERSION 0x01 -#define MEI_NFC_HEADER_SIZE 10 - -/** - * struct mei_nfc_dev - NFC mei device - * - * @me_cl: NFC me client - * @cl: NFC host client - * @cl_info: NFC info host client - * @init_work: perform connection to the info client - * @fw_ivn: NFC Interface Version Number - * @vendor_id: NFC manufacturer ID - * @radio_type: NFC radio type - * @bus_name: bus name - * - */ -struct mei_nfc_dev { - struct mei_me_client *me_cl; - struct mei_cl *cl; - struct mei_cl *cl_info; - struct work_struct init_work; - u8 fw_ivn; - u8 vendor_id; - u8 radio_type; - const char *bus_name; -}; - -/* UUIDs for NFC F/W clients */ -const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, - 0x94, 0xd4, 0x50, 0x26, - 0x67, 0x23, 0x77, 0x5c); - -static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO; - /* Vendors */ #define MEI_NFC_VENDOR_INSIDE 0x00 #define MEI_NFC_VENDOR_NXP 0x01 @@ -163,27 +110,6 @@ static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO; #define MEI_NFC_VENDOR_INSIDE_UREAD 0x00 #define MEI_NFC_VENDOR_NXP_PN544 0x01 -static void mei_nfc_free(struct mei_nfc_dev *ndev) -{ - if (!ndev) - return; - - if (ndev->cl) { - list_del(&ndev->cl->device_link); - mei_cl_unlink(ndev->cl); - kfree(ndev->cl); - } - - if (ndev->cl_info) { - list_del(&ndev->cl_info->device_link); - mei_cl_unlink(ndev->cl_info); - kfree(ndev->cl_info); - } - - mei_me_cl_put(ndev->me_cl); - kfree(ndev); -} - /** * mei_nfc_if_version - get NFC interface version * @@ -264,177 +190,86 @@ static const char *mei_nfc_radio_name(struct mei_nfc_if_version *ver) return NULL; } -static void mei_nfc_init(struct work_struct *work) +/** + * mei_nfc - The nfc fixup function. The function retrieves nfc radio + * name and set is as device attribute so we can load + * the proper device driver for it + * + * @cldev: me client device (nfc) + */ +static void mei_nfc(struct mei_cl_device *cldev) { struct mei_device *bus; - struct mei_cl_device *cldev; - struct mei_nfc_dev *ndev; - struct mei_cl *cl_info; - struct mei_me_client *me_cl_info; - struct mei_nfc_if_version version; + struct mei_cl *cl; + struct mei_me_client *me_cl = NULL; + struct mei_nfc_if_version ver; + const char *radio_name = NULL; + int ret; - ndev = container_of(work, struct mei_nfc_dev, init_work); + bus = cldev->bus; - cl_info = ndev->cl_info; - bus = cl_info->dev; + dev_dbg(bus->dev, "running hook %s: %pUl match=%d\n", + __func__, mei_me_cl_uuid(cldev->me_cl), cldev->do_match); mutex_lock(&bus->device_lock); - - /* check for valid client id */ - me_cl_info = mei_me_cl_by_uuid(bus, &mei_nfc_info_guid); - if (!me_cl_info) { - mutex_unlock(&bus->device_lock); - dev_info(bus->dev, "nfc: failed to find the info client\n"); - goto err; - } - - if (mei_cl_connect(cl_info, me_cl_info, NULL) < 0) { - mei_me_cl_put(me_cl_info); - mutex_unlock(&bus->device_lock); - dev_err(bus->dev, "Could not connect to the NFC INFO ME client"); - - goto err; + /* we need to connect to INFO GUID */ + cl = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY); + if (IS_ERR(cl)) { + ret = PTR_ERR(cl); + cl = NULL; + dev_err(bus->dev, "nfc hook alloc failed %d\n", ret); + goto out; } - mei_me_cl_put(me_cl_info); - mutex_unlock(&bus->device_lock); - if (mei_nfc_if_version(cl_info, &version) < 0) { - dev_err(bus->dev, "Could not get the NFC interface version"); - - goto err; + me_cl = mei_me_cl_by_uuid(bus, &mei_nfc_info_guid); + if (!me_cl) { + ret = -ENOTTY; + dev_err(bus->dev, "Cannot find nfc info %d\n", ret); + goto out; } - ndev->fw_ivn = version.fw_ivn; - ndev->vendor_id = version.vendor_id; - ndev->radio_type = version.radio_type; - - dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n", - ndev->fw_ivn, ndev->vendor_id, ndev->radio_type); - - mutex_lock(&bus->device_lock); - - if (mei_cl_disconnect(cl_info) < 0) { - mutex_unlock(&bus->device_lock); - dev_err(bus->dev, "Could not disconnect the NFC INFO ME client"); - - goto err; + ret = mei_cl_connect(cl, me_cl, NULL); + if (ret < 0) { + dev_err(&cldev->dev, "Can't connect to the NFC INFO ME ret = %d\n", + ret); + goto out; } mutex_unlock(&bus->device_lock); - ndev->bus_name = mei_nfc_radio_name(&version); + ret = mei_nfc_if_version(cl, &ver); + if (ret) + goto disconnect; - if (!ndev->bus_name) { - dev_err(bus->dev, "Could not build the bus ID name\n"); - return; - } + radio_name = mei_nfc_radio_name(&ver); - cldev = mei_cl_add_device(bus, ndev->me_cl, ndev->cl, - ndev->bus_name); - if (!cldev) { - dev_err(bus->dev, "Could not add the NFC device to the MEI bus\n"); - - goto err; + if (!radio_name) { + ret = -ENOENT; + dev_err(&cldev->dev, "Can't get the NFC interface version ret = %d\n", + ret); + goto disconnect; } - cldev->priv_data = ndev; - - - return; + dev_dbg(bus->dev, "nfc radio %s\n", radio_name); + strlcpy(cldev->name, radio_name, sizeof(cldev->name)); -err: +disconnect: mutex_lock(&bus->device_lock); - mei_nfc_free(ndev); - mutex_unlock(&bus->device_lock); + if (mei_cl_disconnect(cl) < 0) + dev_err(bus->dev, "Can't disconnect the NFC INFO ME\n"); -} + mei_cl_flush_queues(cl, NULL); +out: + mei_cl_unlink(cl); + mutex_unlock(&bus->device_lock); + mei_me_cl_put(me_cl); + kfree(cl); -int mei_nfc_host_init(struct mei_device *bus, struct mei_me_client *me_cl) -{ - struct mei_nfc_dev *ndev; - struct mei_cl *cl_info, *cl; - int ret; - - - /* in case of internal reset bail out - * as the device is already setup - */ - cl = mei_cl_bus_find_cl_by_uuid(bus, mei_nfc_guid); - if (cl) - return 0; - - ndev = kzalloc(sizeof(struct mei_nfc_dev), GFP_KERNEL); - if (!ndev) { - ret = -ENOMEM; - goto err; - } - - ndev->me_cl = mei_me_cl_get(me_cl); - if (!ndev->me_cl) { - ret = -ENODEV; - goto err; - } - - cl_info = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY); - if (IS_ERR(cl_info)) { - ret = PTR_ERR(cl_info); - goto err; - } - - list_add_tail(&cl_info->device_link, &bus->device_list); - - ndev->cl_info = cl_info; - - cl = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY); - if (IS_ERR(cl)) { - ret = PTR_ERR(cl); - goto err; - } - - list_add_tail(&cl->device_link, &bus->device_list); - - ndev->cl = cl; - - INIT_WORK(&ndev->init_work, mei_nfc_init); - schedule_work(&ndev->init_work); - - return 0; - -err: - mei_nfc_free(ndev); - - return ret; -} - -void mei_nfc_host_exit(struct mei_device *bus) -{ - struct mei_nfc_dev *ndev; - struct mei_cl *cl; - struct mei_cl_device *cldev; - - cl = mei_cl_bus_find_cl_by_uuid(bus, mei_nfc_guid); - if (!cl) - return; - - cldev = cl->cldev; - if (!cldev) - return; - - ndev = (struct mei_nfc_dev *)cldev->priv_data; - if (ndev) - cancel_work_sync(&ndev->init_work); - - cldev->priv_data = NULL; - - /* Need to remove the device here - * since mei_nfc_free will unlink the clients - */ - mei_cl_remove_device(cldev); + if (ret) + cldev->do_match = 0; - mutex_lock(&bus->device_lock); - mei_nfc_free(ndev); - mutex_unlock(&bus->device_lock); + dev_dbg(bus->dev, "end of fixup match = %d\n", cldev->do_match); } #define MEI_FIXUP(_uuid, _hook) { _uuid, _hook } @@ -446,6 +281,7 @@ static struct mei_fixup { } mei_fixups[] = { MEI_FIXUP(MEI_UUID_ANY, number_of_connections), MEI_FIXUP(MEI_UUID_NFC_INFO, blacklist), + MEI_FIXUP(MEI_UUID_NFC_HCI, mei_nfc), }; /** diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 7e51700515f4..3ab08e522fb8 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -309,34 +309,43 @@ EXPORT_SYMBOL_GPL(mei_cl_set_drvdata); */ int mei_cl_enable_device(struct mei_cl_device *cldev) { - int err; - struct mei_device *bus; - struct mei_cl *cl = cldev->cl; + struct mei_device *bus = cldev->bus; + struct mei_cl *cl; + int ret; - if (cl == NULL) - return -ENODEV; + cl = cldev->cl; - bus = cl->dev; + if (!cl) { + mutex_lock(&bus->device_lock); + cl = mei_cl_alloc_linked(bus, MEI_HOST_CLIENT_ID_ANY); + mutex_unlock(&bus->device_lock); + if (IS_ERR(cl)) + return PTR_ERR(cl); + /* update pointers */ + cldev->cl = cl; + cl->cldev = cldev; + } mutex_lock(&bus->device_lock); - if (mei_cl_is_connected(cl)) { - mutex_unlock(&bus->device_lock); - dev_warn(bus->dev, "Already connected"); - return -EBUSY; + ret = 0; + goto out; } - err = mei_cl_connect(cl, cldev->me_cl, NULL); - if (err < 0) { - mutex_unlock(&bus->device_lock); - dev_err(bus->dev, "Could not connect to the ME client"); - - return err; + if (!mei_me_cl_is_active(cldev->me_cl)) { + dev_err(&cldev->dev, "me client is not active\n"); + ret = -ENOTTY; + goto out; } + ret = mei_cl_connect(cl, cldev->me_cl, NULL); + if (ret < 0) + dev_err(&cldev->dev, "cannot connect\n"); + +out: mutex_unlock(&bus->device_lock); - return 0; + return ret; } EXPORT_SYMBOL_GPL(mei_cl_enable_device); @@ -350,14 +359,16 @@ EXPORT_SYMBOL_GPL(mei_cl_enable_device); */ int mei_cl_disable_device(struct mei_cl_device *cldev) { - int err; struct mei_device *bus; - struct mei_cl *cl = cldev->cl; + struct mei_cl *cl; + int err; - if (cl == NULL) + if (!cldev || !cldev->cl) return -ENODEV; - bus = cl->dev; + cl = cldev->cl; + + bus = cldev->bus; cldev->event_cb = NULL; @@ -370,18 +381,19 @@ int mei_cl_disable_device(struct mei_cl_device *cldev) } err = mei_cl_disconnect(cl); - if (err < 0) { + if (err < 0) dev_err(bus->dev, "Could not disconnect from the ME client"); - goto out; - } +out: /* Flush queues and remove any pending read */ mei_cl_flush_queues(cl, NULL); + mei_cl_unlink(cl); + + kfree(cl); + cldev->cl = NULL; -out: mutex_unlock(&bus->device_lock); return err; - } EXPORT_SYMBOL_GPL(mei_cl_disable_device); @@ -623,20 +635,6 @@ static struct device_type mei_cl_device_type = { .release = mei_cl_dev_release, }; -struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus, - uuid_le uuid) -{ - struct mei_cl *cl; - - list_for_each_entry(cl, &bus->device_list, device_link) { - if (cl->cldev && cl->cldev->me_cl && - !uuid_le_cmp(uuid, *mei_me_cl_uuid(cl->cldev->me_cl))) - return cl; - } - - return NULL; -} - /** * mei_cl_dev_alloc - initialize and allocate mei client device * @@ -707,45 +705,127 @@ static int mei_cl_bus_dev_add(struct mei_cl_device *cldev) return ret; } -struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, - struct mei_me_client *me_cl, - struct mei_cl *cl, - const char *name) +/** + * mei_cl_bus_dev_stop - stop the driver + * + * @cldev: me client device + */ +static void mei_cl_bus_dev_stop(struct mei_cl_device *cldev) +{ + if (cldev->is_added) + device_release_driver(&cldev->dev); +} + +/** + * mei_cl_bus_dev_destroy - destroy me client devices object + * + * @cldev: me client device + */ +static void mei_cl_bus_dev_destroy(struct mei_cl_device *cldev) +{ + if (!cldev->is_added) + return; + + device_del(&cldev->dev); + + mutex_lock(&cldev->bus->cl_bus_lock); + list_del_init(&cldev->bus_list); + mutex_unlock(&cldev->bus->cl_bus_lock); + + cldev->is_added = 0; + put_device(&cldev->dev); +} + +/** + * mei_cl_bus_remove_device - remove a devices form the bus + * + * @cldev: me client device + */ +static void mei_cl_bus_remove_device(struct mei_cl_device *cldev) +{ + mei_cl_bus_dev_stop(cldev); + mei_cl_bus_dev_destroy(cldev); +} + +/** + * mei_cl_bus_remove_devices - remove all devices form the bus + * + * @bus: mei device + */ +void mei_cl_bus_remove_devices(struct mei_device *bus) +{ + struct mei_cl_device *cldev, *next; + + list_for_each_entry_safe(cldev, next, &bus->device_list, bus_list) + mei_cl_bus_remove_device(cldev); +} + + +/** + * mei_cl_dev_init - allocate and initializes an mei client devices + * based on me client + * + * @bus: mei device + * @me_cl: me client + */ +static void mei_cl_dev_init(struct mei_device *bus, struct mei_me_client *me_cl) { struct mei_cl_device *cldev; - int status; + + dev_dbg(bus->dev, "initializing %pUl", mei_me_cl_uuid(me_cl)); + + if (me_cl->bus_added) + return; cldev = mei_cl_dev_alloc(bus, me_cl); if (!cldev) - return NULL; + return; - cldev->cl = cl; - strlcpy(cldev->name, name, sizeof(cldev->name)); + mutex_lock(&cldev->bus->cl_bus_lock); + me_cl->bus_added = true; + list_add_tail(&cldev->bus_list, &bus->device_list); + mutex_unlock(&cldev->bus->cl_bus_lock); - mei_cl_dev_setup(bus, cldev); +} - status = mei_cl_bus_dev_add(cldev); - if (status) { - dev_err(bus->dev, "Failed to register MEI device\n"); - mei_me_cl_put(cldev->me_cl); - mei_dev_bus_put(bus); - kfree(cldev); - return NULL; - } +/** + * mei_cl_bus_rescan - scan me clients list and add create + * devices for eligible clients + * + * @bus: mei device + */ +void mei_cl_bus_rescan(struct mei_device *bus) +{ + struct mei_cl_device *cldev, *n; + struct mei_me_client *me_cl; - cl->cldev = cldev; + down_read(&bus->me_clients_rwsem); + list_for_each_entry(me_cl, &bus->me_clients, list) + mei_cl_dev_init(bus, me_cl); + up_read(&bus->me_clients_rwsem); - dev_dbg(&cldev->dev, "client %s registered\n", name); + mutex_lock(&bus->cl_bus_lock); + list_for_each_entry_safe(cldev, n, &bus->device_list, bus_list) { - return cldev; -} -EXPORT_SYMBOL_GPL(mei_cl_add_device); + if (!mei_me_cl_is_active(cldev->me_cl)) { + mei_cl_bus_remove_device(cldev); + continue; + } -void mei_cl_remove_device(struct mei_cl_device *cldev) -{ - device_unregister(&cldev->dev); + if (cldev->is_added) + continue; + + if (mei_cl_dev_setup(bus, cldev)) + mei_cl_bus_dev_add(cldev); + else { + list_del_init(&cldev->bus_list); + put_device(&cldev->dev); + } + } + mutex_unlock(&bus->cl_bus_lock); + + dev_dbg(bus->dev, "rescan end"); } -EXPORT_SYMBOL_GPL(mei_cl_remove_device); int __mei_cl_driver_register(struct mei_cl_driver *cldrv, struct module *owner) { @@ -773,6 +853,7 @@ void mei_cl_driver_unregister(struct mei_cl_driver *cldrv) } EXPORT_SYMBOL_GPL(mei_cl_driver_unregister); + int __init mei_cl_bus_init(void) { return bus_register(&mei_cl_bus_type); diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 1987a201c7f3..9dacea7a9a60 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -558,7 +558,6 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) INIT_LIST_HEAD(&cl->rd_completed); INIT_LIST_HEAD(&cl->rd_pending); INIT_LIST_HEAD(&cl->link); - INIT_LIST_HEAD(&cl->device_link); cl->writing_state = MEI_IDLE; cl->state = MEI_FILE_INITIALIZING; cl->dev = dev; @@ -690,16 +689,12 @@ void mei_host_client_init(struct work_struct *work) mei_wd_host_init(dev, me_cl); mei_me_cl_put(me_cl); - me_cl = mei_me_cl_by_uuid(dev, &mei_nfc_guid); - if (me_cl) - mei_nfc_host_init(dev, me_cl); - mei_me_cl_put(me_cl); - - dev->dev_state = MEI_DEV_ENABLED; dev->reset_count = 0; mutex_unlock(&dev->device_lock); + mei_cl_bus_rescan(dev); + pm_runtime_mark_last_busy(dev->dev); dev_dbg(dev->dev, "rpm: autosuspend\n"); pm_runtime_autosuspend(dev->dev); diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 15000e9231b1..e374661652cd 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -331,7 +331,7 @@ void mei_stop(struct mei_device *dev) mei_cancel_work(dev); - mei_nfc_host_exit(dev); + mei_cl_bus_remove_devices(dev); mutex_lock(&dev->device_lock); diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 7098dcaccc96..71c55f4cabb4 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -241,7 +241,6 @@ struct mei_cl_cb { * @rd_completed: completed read * * @cldev: device on the mei client bus - * @device_link: link to bus clients */ struct mei_cl { struct list_head link; @@ -260,9 +259,7 @@ struct mei_cl { struct list_head rd_pending; struct list_head rd_completed; - /* MEI CL bus data */ struct mei_cl_device *cldev; - struct list_head device_link; }; /** struct mei_hw_ops @@ -329,12 +326,7 @@ struct mei_hw_ops { }; /* MEI bus API*/ - -struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, - struct mei_me_client *me_cl, - struct mei_cl *cl, - const char *name); -void mei_cl_remove_device(struct mei_cl_device *cldev); +void mei_cl_bus_rescan(struct mei_device *bus); void mei_cl_dev_fixup(struct mei_cl_device *dev); ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, bool blocking); @@ -343,7 +335,6 @@ void mei_cl_bus_rx_event(struct mei_cl *cl); void mei_cl_bus_remove_devices(struct mei_device *bus); int mei_cl_bus_init(void); void mei_cl_bus_exit(void); -struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus, uuid_le uuid); /** * enum mei_pg_event - power gating transition events -- cgit v1.3-6-gb490 From 70ef835c84b3b88e274a53bf80a70940ae178a91 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 23 Jul 2015 21:37:12 +0300 Subject: mei: support for dynamic clients HBM version 2.0 and above allows ME clients in the system to register/unregister after the system is fully initialized. Clients may be added or removed after enum_resp message was received 1. To preserve backward compatibility the driver can opt-in to receive client add messages by setting allow_add field in enum_req 2. A new client is added upon reception of MEI_HBM_ADD_CLIENT_REQ_CMD 3. A client is removed in a lazy manner when connection request respond with MEI_HBMS_CLIENT_NOT_FOUND status Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/debugfs.c | 2 + drivers/misc/mei/hbm.c | 92 +++++++++++++++++++++++++++++++++++++++++++++- drivers/misc/mei/hw.h | 50 ++++++++++++++++++++++++- drivers/misc/mei/mei_dev.h | 2 + 4 files changed, 144 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c index eb868341247f..a65a1e6f386f 100644 --- a/drivers/misc/mei/debugfs.c +++ b/drivers/misc/mei/debugfs.c @@ -154,6 +154,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf, pos += scnprintf(buf + pos, bufsz - pos, "hbm features:\n"); pos += scnprintf(buf + pos, bufsz - pos, "\tPG: %01d\n", dev->hbm_f_pg_supported); + pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n", + dev->hbm_f_dc_supported); } pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n", diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index a4f283165a33..d4dba639db37 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -299,6 +299,7 @@ static int mei_hbm_enum_clients_req(struct mei_device *dev) enum_req = (struct hbm_host_enum_request *)dev->wr_msg.data; memset(enum_req, 0, len); enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; + enum_req->allow_add = dev->hbm_f_dc_supported; ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); if (ret) { @@ -343,6 +344,64 @@ static int mei_hbm_me_cl_add(struct mei_device *dev, return 0; } +/** + * mei_hbm_add_cl_resp - send response to fw on client add request + * + * @dev: the device structure + * @addr: me address + * @status: response status + * + * Return: 0 on success and < 0 on failure + */ +static int mei_hbm_add_cl_resp(struct mei_device *dev, u8 addr, u8 status) +{ + struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; + struct hbm_add_client_response *resp; + const size_t len = sizeof(struct hbm_add_client_response); + int ret; + + dev_dbg(dev->dev, "adding client response\n"); + + resp = (struct hbm_add_client_response *)dev->wr_msg.data; + + mei_hbm_hdr(mei_hdr, len); + memset(resp, 0, sizeof(struct hbm_add_client_response)); + + resp->hbm_cmd = MEI_HBM_ADD_CLIENT_RES_CMD; + resp->me_addr = addr; + resp->status = status; + + ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + if (ret) + dev_err(dev->dev, "add client response write failed: ret = %d\n", + ret); + return ret; +} + +/** + * mei_hbm_fw_add_cl_req - request from the fw to add a client + * + * @dev: the device structure + * @req: add client request + * + * Return: 0 on success and < 0 on failure + */ +static int mei_hbm_fw_add_cl_req(struct mei_device *dev, + struct hbm_add_client_request *req) +{ + int ret; + u8 status = MEI_HBMS_SUCCESS; + + BUILD_BUG_ON(sizeof(struct hbm_add_client_request) != + sizeof(struct hbm_props_response)); + + ret = mei_hbm_me_cl_add(dev, (struct hbm_props_response *)req); + if (ret) + status = !MEI_HBMS_SUCCESS; + + return mei_hbm_add_cl_resp(dev, req->me_addr, status); +} + /** * mei_hbm_prop_req - request property for a single client * @@ -610,8 +669,11 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev, struct mei_cl *cl, if (rs->status == MEI_CL_CONN_SUCCESS) cl->state = MEI_FILE_CONNECTED; - else + else { cl->state = MEI_FILE_DISCONNECT_REPLY; + if (rs->status == MEI_CL_CONN_NOT_FOUND) + mei_me_cl_del(dev, cl->me_cl); + } cl->status = mei_cl_conn_status_to_errno(rs->status); } @@ -709,6 +771,9 @@ static void mei_hbm_config_features(struct mei_device *dev) if (dev->version.major_version == HBM_MAJOR_VERSION_PGI && dev->version.minor_version >= HBM_MINOR_VERSION_PGI) dev->hbm_f_pg_supported = 1; + + if (dev->version.major_version >= HBM_MAJOR_VERSION_DC) + dev->hbm_f_dc_supported = 1; } /** @@ -740,6 +805,8 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) struct hbm_host_version_response *version_res; struct hbm_props_response *props_res; struct hbm_host_enum_response *enum_res; + struct hbm_add_client_request *add_cl_req; + int ret; struct mei_hbm_cl_cmd *cl_cmd; struct hbm_client_connect_request *disconnect_req; @@ -937,6 +1004,29 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) return -EIO; } break; + + case MEI_HBM_ADD_CLIENT_REQ_CMD: + dev_dbg(dev->dev, "hbm: add client request received\n"); + /* + * after the host receives the enum_resp + * message clients may be added or removed + */ + if (dev->hbm_state <= MEI_HBM_ENUM_CLIENTS && + dev->hbm_state >= MEI_HBM_STOPPED) { + dev_err(dev->dev, "hbm: add client: state mismatch, [%d, %d]\n", + dev->dev_state, dev->hbm_state); + return -EPROTO; + } + add_cl_req = (struct hbm_add_client_request *)mei_msg; + ret = mei_hbm_fw_add_cl_req(dev, add_cl_req); + if (ret) { + dev_err(dev->dev, "hbm: add client: failed to send response %d\n", + ret); + return -EIO; + } + dev_dbg(dev->dev, "hbm: add client request processed\n"); + break; + default: BUG(); break; diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 16fef6dc4dd7..815f40a604b9 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -46,6 +46,12 @@ #define HBM_MINOR_VERSION_PGI 1 #define HBM_MAJOR_VERSION_PGI 1 +/* + * MEI version with Dynamic clients support + */ +#define HBM_MINOR_VERSION_DC 0 +#define HBM_MAJOR_VERSION_DC 2 + /* Host bus message command opcode */ #define MEI_HBM_CMD_OP_MSK 0x7f /* Host bus message command RESPONSE */ @@ -81,6 +87,8 @@ #define MEI_PG_ISOLATION_EXIT_REQ_CMD 0x0b #define MEI_PG_ISOLATION_EXIT_RES_CMD 0x8b +#define MEI_HBM_ADD_CLIENT_REQ_CMD 0x0f +#define MEI_HBM_ADD_CLIENT_RES_CMD 0x8f /* * MEI Stop Reason * used by hbm_host_stop_request.reason @@ -213,9 +221,17 @@ struct hbm_me_stop_request { u8 reserved[2]; } __packed; +/** + * struct hbm_host_enum_request - enumeration request from host to fw + * + * @hbm_cmd: bus message command header + * @allow_add: allow dynamic clients add HBM version >= 2.0 + * @reserved: reserved + */ struct hbm_host_enum_request { u8 hbm_cmd; - u8 reserved[3]; + u8 allow_add; + u8 reserved[2]; } __packed; struct hbm_host_enum_response { @@ -247,6 +263,38 @@ struct hbm_props_response { struct mei_client_properties client_properties; } __packed; +/** + * struct hbm_add_client_request - request to add a client + * might be sent by fw after enumeration has already completed + * + * @hbm_cmd: bus message command header + * @me_addr: address of the client in ME + * @reserved: reserved + * @client_properties: client properties + */ +struct hbm_add_client_request { + u8 hbm_cmd; + u8 me_addr; + u8 reserved[2]; + struct mei_client_properties client_properties; +} __packed; + +/** + * struct hbm_add_client_response - response to add a client + * sent by the host to report client addition status to fw + * + * @hbm_cmd: bus message command header + * @me_addr: address of the client in ME + * @status: if HBMS_SUCCESS then the client can now accept connections. + * @reserved: reserved + */ +struct hbm_add_client_response { + u8 hbm_cmd; + u8 me_addr; + u8 status; + u8 reserved[1]; +} __packed; + /** * struct hbm_power_gate - power gate request/response * diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 71c55f4cabb4..33823f4a1cf2 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -408,6 +408,7 @@ const char *mei_pg_state_str(enum mei_pg_state state); * * @version : HBM protocol version in use * @hbm_f_pg_supported : hbm feature pgi protocol + * @hbm_f_dc_supported : hbm feature dynamic clients * * @me_clients_rwsem: rw lock over me_clients list * @me_clients : list of FW clients @@ -501,6 +502,7 @@ struct mei_device { struct hbm_version version; unsigned int hbm_f_pg_supported:1; + unsigned int hbm_f_dc_supported:1; struct rw_semaphore me_clients_rwsem; struct list_head me_clients; -- cgit v1.3-6-gb490 From 18901357e70ae29e3fd1c58712a6847c2ae52eae Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Thu, 23 Jul 2015 21:37:13 +0300 Subject: mei: disconnect on connection request timeout For the FW with HBM version >= 2.0 we don't need to reset the whole device in case of a particular client failing to connect, it is enough to send disconnect a request to bring the device to the stable state. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 85 ++++++++++++++++++++++++++++++-------------- drivers/misc/mei/debugfs.c | 2 ++ drivers/misc/mei/hbm.c | 4 +++ drivers/misc/mei/hw.h | 6 ++++ drivers/misc/mei/interrupt.c | 20 ++++++++++- drivers/misc/mei/mei_dev.h | 7 ++-- 6 files changed, 95 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 9dacea7a9a60..40285e02b612 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -836,44 +836,24 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, return ret; } - - /** - * mei_cl_disconnect - disconnect host client from the me one + * __mei_cl_disconnect - disconnect host client from the me one + * internal function runtime pm has to be already acquired * * @cl: host client * - * Locking: called under "dev->device_lock" lock - * * Return: 0 on success, <0 on failure. */ -int mei_cl_disconnect(struct mei_cl *cl) +static int __mei_cl_disconnect(struct mei_cl *cl) { struct mei_device *dev; struct mei_cl_cb *cb; int rets; - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; - dev = cl->dev; - cl_dbg(dev, cl, "disconnecting"); - - if (!mei_cl_is_connected(cl)) - return 0; - - if (mei_cl_is_fixed_address(cl)) { - mei_cl_set_disconnected(cl); - return 0; - } - - rets = pm_runtime_get(dev->dev); - if (rets < 0 && rets != -EINPROGRESS) { - pm_runtime_put_noidle(dev->dev); - cl_err(dev, cl, "rpm: get failed %d\n", rets); - return rets; - } + if (WARN_ON(!pm_runtime_active(dev->dev))) + return -EFAULT; cl->state = MEI_FILE_DISCONNECTING; @@ -910,11 +890,52 @@ out: if (!rets) cl_dbg(dev, cl, "successfully disconnected from FW client.\n"); + mei_io_cb_free(cb); + return rets; +} + +/** + * mei_cl_disconnect - disconnect host client from the me one + * + * @cl: host client + * + * Locking: called under "dev->device_lock" lock + * + * Return: 0 on success, <0 on failure. + */ +int mei_cl_disconnect(struct mei_cl *cl) +{ + struct mei_device *dev; + int rets; + + if (WARN_ON(!cl || !cl->dev)) + return -ENODEV; + + dev = cl->dev; + + cl_dbg(dev, cl, "disconnecting"); + + if (!mei_cl_is_connected(cl)) + return 0; + + if (mei_cl_is_fixed_address(cl)) { + mei_cl_set_disconnected(cl); + return 0; + } + + rets = pm_runtime_get(dev->dev); + if (rets < 0 && rets != -EINPROGRESS) { + pm_runtime_put_noidle(dev->dev); + cl_err(dev, cl, "rpm: get failed %d\n", rets); + return rets; + } + + rets = __mei_cl_disconnect(cl); + cl_dbg(dev, cl, "rpm: autosuspend\n"); pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); - mei_io_cb_free(cb); return rets; } @@ -1059,11 +1080,23 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, mutex_unlock(&dev->device_lock); wait_event_timeout(cl->wait, (cl->state == MEI_FILE_CONNECTED || + cl->state == MEI_FILE_DISCONNECT_REQUIRED || cl->state == MEI_FILE_DISCONNECT_REPLY), mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); mutex_lock(&dev->device_lock); if (!mei_cl_is_connected(cl)) { + if (cl->state == MEI_FILE_DISCONNECT_REQUIRED) { + mei_io_list_flush(&dev->ctrl_rd_list, cl); + mei_io_list_flush(&dev->ctrl_wr_list, cl); + /* ignore disconnect return valuue; + * in case of failure reset will be invoked + */ + __mei_cl_disconnect(cl); + rets = -EFAULT; + goto out; + } + /* timeout or something went really wrong */ if (!cl->status) cl->status = -EFAULT; diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c index a65a1e6f386f..e39cfe6bc5bc 100644 --- a/drivers/misc/mei/debugfs.c +++ b/drivers/misc/mei/debugfs.c @@ -156,6 +156,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf, dev->hbm_f_pg_supported); pos += scnprintf(buf + pos, bufsz - pos, "\tDC: %01d\n", dev->hbm_f_dc_supported); + pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n", + dev->hbm_f_dot_supported); } pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n", diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index d4dba639db37..07a8ea8362a3 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -774,6 +774,10 @@ static void mei_hbm_config_features(struct mei_device *dev) if (dev->version.major_version >= HBM_MAJOR_VERSION_DC) dev->hbm_f_dc_supported = 1; + + /* disconnect on connect timeout instead of link reset */ + if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT) + dev->hbm_f_dot_supported = 1; } /** diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 815f40a604b9..e961be392fae 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -52,6 +52,12 @@ #define HBM_MINOR_VERSION_DC 0 #define HBM_MAJOR_VERSION_DC 2 +/* + * MEI version with disconnect on connection timeout support + */ +#define HBM_MINOR_VERSION_DOT 0 +#define HBM_MAJOR_VERSION_DOT 2 + /* Host bus message command opcode */ #define MEI_HBM_CMD_OP_MSK 0x7f /* Host bus message command RESPONSE */ diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 3f3405269c39..89d8e1304077 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -424,6 +424,24 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) EXPORT_SYMBOL_GPL(mei_irq_write_handler); +/** + * mei_connect_timeout - connect/disconnect timeouts + * + * @cl: host client + */ +static void mei_connect_timeout(struct mei_cl *cl) +{ + struct mei_device *dev = cl->dev; + + if (cl->state == MEI_FILE_CONNECTING) { + if (dev->hbm_f_dot_supported) { + cl->state = MEI_FILE_DISCONNECT_REQUIRED; + wake_up(&cl->wait); + return; + } + } + mei_reset(dev); +} /** * mei_timer - timer function. @@ -464,7 +482,7 @@ void mei_timer(struct work_struct *work) if (cl->timer_count) { if (--cl->timer_count == 0) { dev_err(dev->dev, "timer: connect/disconnect timeout.\n"); - mei_reset(dev); + mei_connect_timeout(cl); goto out; } } diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 33823f4a1cf2..8bd46cd95b7a 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -89,6 +89,7 @@ enum file_state { MEI_FILE_CONNECTED, MEI_FILE_DISCONNECTING, MEI_FILE_DISCONNECT_REPLY, + MEI_FILE_DISCONNECT_REQUIRED, MEI_FILE_DISCONNECTED, }; @@ -407,8 +408,9 @@ const char *mei_pg_state_str(enum mei_pg_state state); * @wr_msg : the buffer for hbm control messages * * @version : HBM protocol version in use - * @hbm_f_pg_supported : hbm feature pgi protocol - * @hbm_f_dc_supported : hbm feature dynamic clients + * @hbm_f_pg_supported : hbm feature pgi protocol + * @hbm_f_dc_supported : hbm feature dynamic clients + * @hbm_f_dot_supported : hbm feature disconnect on timeout * * @me_clients_rwsem: rw lock over me_clients list * @me_clients : list of FW clients @@ -503,6 +505,7 @@ struct mei_device { struct hbm_version version; unsigned int hbm_f_pg_supported:1; unsigned int hbm_f_dc_supported:1; + unsigned int hbm_f_dot_supported:1; struct rw_semaphore me_clients_rwsem; struct list_head me_clients; -- cgit v1.3-6-gb490 From d3c1c809c476ba248175a89156f7d625caf5f9a6 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 26 Jul 2015 09:54:15 +0300 Subject: mei: define async notification hbm commands FW has gained new capability where a FW client can asynchronously notify the host that an event has occurred in its process. The notification doesn't provide any data and host may need to query further the FW client in order to get details of the event. Host can subscribe or unsubscribe to the event notification via designated HBM commands, and also the notification is carried on a new HBM command. This patch adds definitions of asynchronous notification HBM commands. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index e961be392fae..a2c7aaba25d4 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -95,6 +95,11 @@ #define MEI_HBM_ADD_CLIENT_REQ_CMD 0x0f #define MEI_HBM_ADD_CLIENT_RES_CMD 0x8f + +#define MEI_HBM_NOTIFY_REQ_CMD 0x10 +#define MEI_HBM_NOTIFY_RES_CMD 0x90 +#define MEI_HBM_NOTIFICATION_CMD 0x11 + /* * MEI Stop Reason * used by hbm_host_stop_request.reason @@ -352,5 +357,62 @@ struct hbm_flow_control { u8 reserved[MEI_FC_MESSAGE_RESERVED_LENGTH]; } __packed; +#define MEI_HBM_NOTIFICATION_START 1 +#define MEI_HBM_NOTIFICATION_STOP 0 +/** + * struct hbm_notification_request - start/stop notification request + * + * @hbm_cmd: bus message command header + * @me_addr: address of the client in ME + * @host_addr: address of the client in the driver + * @start: start = 1 or stop = 0 asynchronous notifications + */ +struct hbm_notification_request { + u8 hbm_cmd; + u8 me_addr; + u8 host_addr; + u8 start; +} __packed; + +/** + * struct hbm_notification_response - start/stop notification response + * + * @hbm_cmd: bus message command header + * @me_addr: address of the client in ME + * @host_addr: - address of the client in the driver + * @status: (mei_hbm_status) response status for the request + * - MEI_HBMS_SUCCESS: successful stop/start + * - MEI_HBMS_CLIENT_NOT_FOUND: if the connection could not be found. + * - MEI_HBMS_ALREADY_STARTED: for start requests for a previously + * started notification. + * - MEI_HBMS_NOT_STARTED: for stop request for a connected client for whom + * asynchronous notifications are currently disabled. + * + * @start: start = 1 or stop = 0 asynchronous notifications + * @reserved: reserved + */ +struct hbm_notification_response { + u8 hbm_cmd; + u8 me_addr; + u8 host_addr; + u8 status; + u8 start; + u8 reserved[3]; +} __packed; + +/** + * struct hbm_notification - notification event + * + * @hbm_cmd: bus message command header + * @me_addr: address of the client in ME + * @host_addr: address of the client in the driver + * @reserved: reserved for alignment + */ +struct hbm_notification { + u8 hbm_cmd; + u8 me_addr; + u8 host_addr; + u8 reserved[1]; +} __packed; #endif -- cgit v1.3-6-gb490 From 965ae37ab86eb8cd327c5752dc9e2190d33db25c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 26 Jul 2015 09:54:16 +0300 Subject: mei: implement async notification hbm messages Implement sending and reception handlers for the async event notification hbm commands. Add client notification book keeping data required for the messages notify_en to indicate whether notification is enabled notify_ev to indicate whether an event is pending Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hbm.c | 135 +++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/mei/hbm.h | 2 + drivers/misc/mei/mei_dev.h | 8 +++ 3 files changed, 145 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 07a8ea8362a3..8a73fa06f3c4 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -402,6 +402,125 @@ static int mei_hbm_fw_add_cl_req(struct mei_device *dev, return mei_hbm_add_cl_resp(dev, req->me_addr, status); } +/** + * mei_hbm_cl_notify_req - send notification request + * + * @dev: the device structure + * @cl: a client to disconnect from + * @start: true for start false for stop + * + * Return: 0 on success and -EIO on write failure + */ +int mei_hbm_cl_notify_req(struct mei_device *dev, + struct mei_cl *cl, u8 start) +{ + + struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; + struct hbm_notification_request *req; + const size_t len = sizeof(struct hbm_notification_request); + int ret; + + mei_hbm_hdr(mei_hdr, len); + mei_hbm_cl_hdr(cl, MEI_HBM_NOTIFY_REQ_CMD, dev->wr_msg.data, len); + + req = (struct hbm_notification_request *)dev->wr_msg.data; + req->start = start; + + ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); + if (ret) + dev_err(dev->dev, "notify request failed: ret = %d\n", ret); + + return ret; +} + +/** + * notify_res_to_fop - convert notification response to the proper + * notification FOP + * + * @cmd: client notification start response command + * + * Return: MEI_FOP_NOTIFY_START or MEI_FOP_NOTIFY_STOP; + */ +static inline enum mei_cb_file_ops notify_res_to_fop(struct mei_hbm_cl_cmd *cmd) +{ + struct hbm_notification_response *rs = + (struct hbm_notification_response *)cmd; + + if (rs->start == MEI_HBM_NOTIFICATION_START) + return MEI_FOP_NOTIFY_START; + else + return MEI_FOP_NOTIFY_STOP; +} + +/** + * mei_hbm_cl_notify_start_res - update the client state according + * notify start response + * + * @dev: the device structure + * @cl: mei host client + * @cmd: client notification start response command + */ +static void mei_hbm_cl_notify_start_res(struct mei_device *dev, + struct mei_cl *cl, + struct mei_hbm_cl_cmd *cmd) +{ + struct hbm_notification_response *rs = + (struct hbm_notification_response *)cmd; + + cl_dbg(dev, cl, "hbm: notify start response status=%d\n", rs->status); + + if (rs->status == MEI_HBMS_SUCCESS || + rs->status == MEI_HBMS_ALREADY_STARTED) { + cl->notify_en = true; + cl->status = 0; + } else { + cl->status = -EINVAL; + } +} + +/** + * mei_hbm_cl_notify_stop_res - update the client state according + * notify stop response + * + * @dev: the device structure + * @cl: mei host client + * @cmd: client notification stop response command + */ +static void mei_hbm_cl_notify_stop_res(struct mei_device *dev, + struct mei_cl *cl, + struct mei_hbm_cl_cmd *cmd) +{ + struct hbm_notification_response *rs = + (struct hbm_notification_response *)cmd; + + cl_dbg(dev, cl, "hbm: notify stop response status=%d\n", rs->status); + + if (rs->status == MEI_HBMS_SUCCESS || + rs->status == MEI_HBMS_NOT_STARTED) { + cl->notify_en = false; + cl->status = 0; + } else { + /* TODO: spec is not clear yet about other possible issues */ + cl->status = -EINVAL; + } +} + +/** + * mei_hbm_cl_notify - signal notification event + * + * @dev: the device structure + * @cmd: notification client message + */ +static void mei_hbm_cl_notify(struct mei_device *dev, + struct mei_hbm_cl_cmd *cmd) +{ + struct mei_cl *cl; + + cl = mei_hbm_cl_find_by_cmd(dev, cmd); + if (cl && cl->notify_en) + cl->notify_ev = true; +} + /** * mei_hbm_prop_req - request property for a single client * @@ -716,6 +835,12 @@ static void mei_hbm_cl_res(struct mei_device *dev, case MEI_FOP_DISCONNECT: mei_hbm_cl_disconnect_res(dev, cl, rs); break; + case MEI_FOP_NOTIFY_START: + mei_hbm_cl_notify_start_res(dev, cl, rs); + break; + case MEI_FOP_NOTIFY_STOP: + mei_hbm_cl_notify_stop_res(dev, cl, rs); + break; default: return; } @@ -1031,6 +1156,16 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) dev_dbg(dev->dev, "hbm: add client request processed\n"); break; + case MEI_HBM_NOTIFY_RES_CMD: + dev_dbg(dev->dev, "hbm: notify response received\n"); + mei_hbm_cl_res(dev, cl_cmd, notify_res_to_fop(cl_cmd)); + break; + + case MEI_HBM_NOTIFICATION_CMD: + dev_dbg(dev->dev, "hbm: notification\n"); + mei_hbm_cl_notify(dev, cl_cmd); + break; + default: BUG(); break; diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h index 2544db7d1649..42d66d8fc1f7 100644 --- a/drivers/misc/mei/hbm.h +++ b/drivers/misc/mei/hbm.h @@ -54,6 +54,8 @@ int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl); int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl); bool mei_hbm_version_is_supported(struct mei_device *dev); int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd); +int mei_hbm_cl_notify_req(struct mei_device *dev, + struct mei_cl *cl, u8 request); #endif /* _MEI_HBM_H_ */ diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 8bd46cd95b7a..362ebb15ccd9 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -136,6 +136,8 @@ enum mei_wd_states { * @MEI_FOP_CONNECT: connect * @MEI_FOP_DISCONNECT: disconnect * @MEI_FOP_DISCONNECT_RSP: disconnect response + * @MEI_FOP_NOTIFY_START: start notification + * @MEI_FOP_NOTIFY_STOP: stop notification */ enum mei_cb_file_ops { MEI_FOP_READ = 0, @@ -143,6 +145,8 @@ enum mei_cb_file_ops { MEI_FOP_CONNECT, MEI_FOP_DISCONNECT, MEI_FOP_DISCONNECT_RSP, + MEI_FOP_NOTIFY_START, + MEI_FOP_NOTIFY_STOP, }; /* @@ -237,6 +241,8 @@ struct mei_cl_cb { * @mei_flow_ctrl_creds: transmit flow credentials * @timer_count: watchdog timer for operation completion * @reserved: reserved for alignment + * @notify_en: notification - enabled/disabled + * @notify_ev: pending notification event * @writing_state: state of the tx * @rd_pending: pending read credits * @rd_completed: completed read @@ -256,6 +262,8 @@ struct mei_cl { u8 mei_flow_ctrl_creds; u8 timer_count; u8 reserved; + u8 notify_en; + u8 notify_ev; enum mei_file_transaction_states writing_state; struct list_head rd_pending; struct list_head rd_completed; -- cgit v1.3-6-gb490 From 4d99877d871da0bbb924b2d7aa4ccb27e1ffa93a Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 26 Jul 2015 09:54:17 +0300 Subject: mei: enable async event notifications only from hbm version 2.0 Only FW version 2.0 and newer support the async event notification. For backward compatibility block the feature if the FW version is older then 2.0 Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/debugfs.c | 2 ++ drivers/misc/mei/hbm.c | 4 ++++ drivers/misc/mei/hw.h | 6 ++++++ drivers/misc/mei/mei_dev.h | 2 ++ 4 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c index e39cfe6bc5bc..4b469cf9e60f 100644 --- a/drivers/misc/mei/debugfs.c +++ b/drivers/misc/mei/debugfs.c @@ -158,6 +158,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf, dev->hbm_f_dc_supported); pos += scnprintf(buf + pos, bufsz - pos, "\tDOT: %01d\n", dev->hbm_f_dot_supported); + pos += scnprintf(buf + pos, bufsz - pos, "\tEV: %01d\n", + dev->hbm_f_ev_supported); } pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n", diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 8a73fa06f3c4..95e918c84a6c 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -903,6 +903,10 @@ static void mei_hbm_config_features(struct mei_device *dev) /* disconnect on connect timeout instead of link reset */ if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT) dev->hbm_f_dot_supported = 1; + + /* Notification Event Support */ + if (dev->version.major_version >= HBM_MAJOR_VERSION_EV) + dev->hbm_f_ev_supported = 1; } /** diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index a2c7aaba25d4..3f8901a503a6 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -58,6 +58,12 @@ #define HBM_MINOR_VERSION_DOT 0 #define HBM_MAJOR_VERSION_DOT 2 +/* + * MEI version with notifcation support + */ +#define HBM_MINOR_VERSION_EV 0 +#define HBM_MAJOR_VERSION_EV 2 + /* Host bus message command opcode */ #define MEI_HBM_CMD_OP_MSK 0x7f /* Host bus message command RESPONSE */ diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 362ebb15ccd9..e22bd21bb754 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -419,6 +419,7 @@ const char *mei_pg_state_str(enum mei_pg_state state); * @hbm_f_pg_supported : hbm feature pgi protocol * @hbm_f_dc_supported : hbm feature dynamic clients * @hbm_f_dot_supported : hbm feature disconnect on timeout + * @hbm_f_ev_supported : hbm feature event notification * * @me_clients_rwsem: rw lock over me_clients list * @me_clients : list of FW clients @@ -514,6 +515,7 @@ struct mei_device { unsigned int hbm_f_pg_supported:1; unsigned int hbm_f_dc_supported:1; unsigned int hbm_f_dot_supported:1; + unsigned int hbm_f_ev_supported:1; struct rw_semaphore me_clients_rwsem; struct list_head me_clients; -- cgit v1.3-6-gb490 From 51678ccb7b12dd428a84d466ff379a5e2d717f1f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 26 Jul 2015 09:54:18 +0300 Subject: mei: add mei_cl_notify_request command Add per client notification request infrastructure that allows client to enable or disable async event notification. Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 143 +++++++++++++++++++++++++++++++++++++++++++ drivers/misc/mei/client.h | 6 ++ drivers/misc/mei/hbm.c | 5 +- drivers/misc/mei/interrupt.c | 7 +++ 4 files changed, 157 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 40285e02b612..fae4050413a2 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -1208,6 +1208,147 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl) return 0; } +/** + * mei_cl_notify_fop2req - convert fop to proper request + * + * @fop: client notification start response command + * + * Return: MEI_HBM_NOTIFICATION_START/STOP + */ +u8 mei_cl_notify_fop2req(enum mei_cb_file_ops fop) +{ + if (fop == MEI_FOP_NOTIFY_START) + return MEI_HBM_NOTIFICATION_START; + else + return MEI_HBM_NOTIFICATION_STOP; +} + +/** + * mei_cl_notify_req2fop - convert notification request top file operation type + * + * @req: hbm notification request type + * + * Return: MEI_FOP_NOTIFY_START/STOP + */ +enum mei_cb_file_ops mei_cl_notify_req2fop(u8 req) +{ + if (req == MEI_HBM_NOTIFICATION_START) + return MEI_FOP_NOTIFY_START; + else + return MEI_FOP_NOTIFY_STOP; +} + +/** + * mei_cl_irq_notify - send notification request in irq_thread context + * + * @cl: client + * @cb: callback block. + * @cmpl_list: complete list. + * + * Return: 0 on such and error otherwise. + */ +int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, + struct mei_cl_cb *cmpl_list) +{ + struct mei_device *dev = cl->dev; + u32 msg_slots; + int slots; + int ret; + bool request; + + msg_slots = mei_data2slots(sizeof(struct hbm_client_connect_request)); + slots = mei_hbuf_empty_slots(dev); + + if (slots < msg_slots) + return -EMSGSIZE; + + request = mei_cl_notify_fop2req(cb->fop_type); + ret = mei_hbm_cl_notify_req(dev, cl, request); + if (ret) { + cl->status = ret; + list_move_tail(&cb->list, &cmpl_list->list); + return ret; + } + + list_move_tail(&cb->list, &dev->ctrl_rd_list.list); + return 0; +} + +/** + * mei_cl_notify_request - send notification stop/start request + * + * @cl: host client + * @file: associate request with file + * @request: 1 for start or 0 for stop + * + * Locking: called under "dev->device_lock" lock + * + * Return: 0 on such and error otherwise. + */ +int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request) +{ + struct mei_device *dev; + struct mei_cl_cb *cb; + enum mei_cb_file_ops fop_type; + int rets; + + if (WARN_ON(!cl || !cl->dev)) + return -ENODEV; + + dev = cl->dev; + + if (!dev->hbm_f_ev_supported) { + cl_dbg(dev, cl, "notifications not supported\n"); + return -EOPNOTSUPP; + } + + rets = pm_runtime_get(dev->dev); + if (rets < 0 && rets != -EINPROGRESS) { + pm_runtime_put_noidle(dev->dev); + cl_err(dev, cl, "rpm: get failed %d\n", rets); + return rets; + } + + fop_type = mei_cl_notify_req2fop(request); + cb = mei_io_cb_init(cl, fop_type, file); + if (!cb) { + rets = -ENOMEM; + goto out; + } + + if (mei_hbuf_acquire(dev)) { + if (mei_hbm_cl_notify_req(dev, cl, request)) { + rets = -ENODEV; + goto out; + } + list_add_tail(&cb->list, &dev->ctrl_rd_list.list); + } else { + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); + } + + mutex_unlock(&dev->device_lock); + wait_event_timeout(cl->wait, cl->notify_en == request, + mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); + mutex_lock(&dev->device_lock); + + if (cl->notify_en != request) { + mei_io_list_flush(&dev->ctrl_rd_list, cl); + mei_io_list_flush(&dev->ctrl_wr_list, cl); + if (!cl->status) + cl->status = -EFAULT; + } + + rets = cl->status; + +out: + cl_dbg(dev, cl, "rpm: autosuspend\n"); + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); + + mei_io_cb_free(cb); + return rets; +} + /** * mei_cl_read_start - the start read client message function. * @@ -1516,6 +1657,8 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb) case MEI_FOP_CONNECT: case MEI_FOP_DISCONNECT: + case MEI_FOP_NOTIFY_STOP: + case MEI_FOP_NOTIFY_START: if (waitqueue_active(&cl->wait)) wake_up(&cl->wait); diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 8d7f057f1045..506b7d40d427 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -219,6 +219,12 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb); void mei_host_client_init(struct work_struct *work); +u8 mei_cl_notify_fop2req(enum mei_cb_file_ops fop); +enum mei_cb_file_ops mei_cl_notify_req2fop(u8 request); +int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request); +int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, + struct mei_cl_cb *cmpl_list); + void mei_cl_all_disconnect(struct mei_device *dev); void mei_cl_all_wakeup(struct mei_device *dev); void mei_cl_all_write_clear(struct mei_device *dev); diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 95e918c84a6c..12229ff4bc7e 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -446,10 +446,7 @@ static inline enum mei_cb_file_ops notify_res_to_fop(struct mei_hbm_cl_cmd *cmd) struct hbm_notification_response *rs = (struct hbm_notification_response *)cmd; - if (rs->start == MEI_HBM_NOTIFICATION_START) - return MEI_FOP_NOTIFY_START; - else - return MEI_FOP_NOTIFY_STOP; + return mei_cl_notify_req2fop(rs->start); } /** diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 89d8e1304077..c418d7888994 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -403,6 +403,13 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) if (ret) return ret; break; + + case MEI_FOP_NOTIFY_START: + case MEI_FOP_NOTIFY_STOP: + ret = mei_cl_irq_notify(cl, cb, cmpl_list); + if (ret) + return ret; + break; default: BUG(); } -- cgit v1.3-6-gb490 From b38a362fad6686dd580a50590053a76ded601a0b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 26 Jul 2015 09:54:19 +0300 Subject: mei: add a handler that waits for notification on event mei_cl_notify_get is to be called by a host client to wait, receive, and ack the event notification. Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/misc/mei/client.h | 1 + drivers/misc/mei/hbm.c | 4 +++- drivers/misc/mei/mei_dev.h | 2 ++ 4 files changed, 58 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index fae4050413a2..d9396838774c 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -555,6 +555,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev) init_waitqueue_head(&cl->wait); init_waitqueue_head(&cl->rx_wait); init_waitqueue_head(&cl->tx_wait); + init_waitqueue_head(&cl->ev_wait); INIT_LIST_HEAD(&cl->rd_completed); INIT_LIST_HEAD(&cl->rd_pending); INIT_LIST_HEAD(&cl->link); @@ -1349,6 +1350,51 @@ out: return rets; } +/** + * mei_cl_notify_get - get or wait for notification event + * + * @cl: host client + * @block: this request is blocking + * @notify_ev: true if notification event was received + * + * Locking: called under "dev->device_lock" lock + * + * Return: 0 on such and error otherwise. + */ +int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev) +{ + struct mei_device *dev; + int rets; + + *notify_ev = false; + + if (WARN_ON(!cl || !cl->dev)) + return -ENODEV; + + dev = cl->dev; + + if (!mei_cl_is_connected(cl)) + return -ENODEV; + + if (cl->notify_ev) + goto out; + + if (!block) + return -EAGAIN; + + mutex_unlock(&dev->device_lock); + rets = wait_event_interruptible(cl->ev_wait, cl->notify_ev); + mutex_lock(&dev->device_lock); + + if (rets < 0) + return rets; + +out: + *notify_ev = cl->notify_ev; + cl->notify_ev = false; + return 0; +} + /** * mei_cl_read_start - the start read client message function. * @@ -1701,6 +1747,12 @@ void mei_cl_all_wakeup(struct mei_device *dev) cl_dbg(dev, cl, "Waking up writing client!\n"); wake_up_interruptible(&cl->tx_wait); } + + /* synchronized under device mutex */ + if (waitqueue_active(&cl->ev_wait)) { + cl_dbg(dev, cl, "Waking up waiting for event clients!\n"); + wake_up_interruptible(&cl->ev_wait); + } } } diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 506b7d40d427..58a4b49701fe 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -224,6 +224,7 @@ enum mei_cb_file_ops mei_cl_notify_req2fop(u8 request); int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request); int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); +int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev); void mei_cl_all_disconnect(struct mei_device *dev); void mei_cl_all_wakeup(struct mei_device *dev); diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 12229ff4bc7e..70c94a9cd905 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -514,8 +514,10 @@ static void mei_hbm_cl_notify(struct mei_device *dev, struct mei_cl *cl; cl = mei_hbm_cl_find_by_cmd(dev, cmd); - if (cl && cl->notify_en) + if (cl && cl->notify_en) { cl->notify_ev = true; + wake_up_interruptible(&cl->ev_wait); + } } /** diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index e22bd21bb754..6f8f5e1e909e 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -235,6 +235,7 @@ struct mei_cl_cb { * @tx_wait: wait queue for tx completion * @rx_wait: wait queue for rx completion * @wait: wait queue for management operation + * @ev_wait: notification wait queue * @status: connection status * @me_cl: fw client connected * @host_client_id: host id @@ -256,6 +257,7 @@ struct mei_cl { wait_queue_head_t tx_wait; wait_queue_head_t rx_wait; wait_queue_head_t wait; + wait_queue_head_t ev_wait; int status; struct mei_me_client *me_cl; u8 host_client_id; -- cgit v1.3-6-gb490 From 3c7c8468e5d993dfe377a67e41cbb23cda93af9e Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 26 Jul 2015 09:54:20 +0300 Subject: mei: add async event notification ioctls Add ioctl IOCTL_MEI_NOTIFY_SET for enabling and disabling async event notification. Add ioctl IOCTL_MEI_NOTIFY_GET for receiving and acking an event notification. Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman --- Documentation/ioctl/ioctl-number.txt | 2 + Documentation/misc-devices/mei/mei.txt | 45 ++++++++++++++++++++++- drivers/misc/mei/main.c | 67 ++++++++++++++++++++++++++++++++++ include/uapi/linux/mei.h | 19 ++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 611c52267d24..141f847c7648 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -124,6 +124,8 @@ Code Seq#(hex) Include File Comments 'H' 00-7F linux/hiddev.h conflict! 'H' 00-0F linux/hidraw.h conflict! 'H' 01 linux/mei.h conflict! +'H' 02 linux/mei.h conflict! +'H' 03 linux/mei.h conflict! 'H' 00-0F sound/asound.h conflict! 'H' 20-40 sound/asound_fm.h conflict! 'H' 80-8F sound/sfnt_info.h conflict! diff --git a/Documentation/misc-devices/mei/mei.txt b/Documentation/misc-devices/mei/mei.txt index 8d47501bba0a..91c1fa34f48b 100644 --- a/Documentation/misc-devices/mei/mei.txt +++ b/Documentation/misc-devices/mei/mei.txt @@ -96,7 +96,7 @@ A code snippet for an application communicating with Intel AMTHI client: IOCTL ===== -The Intel MEI Driver supports the following IOCTL command: +The Intel MEI Driver supports the following IOCTL commands: IOCTL_MEI_CONNECT_CLIENT Connect to firmware Feature (client). usage: @@ -125,6 +125,49 @@ The Intel MEI Driver supports the following IOCTL command: data that can be sent or received. (e.g. if MTU=2K, can send requests up to bytes 2k and received responses up to 2k bytes). + IOCTL_MEI_NOTIFY_SET: enable or disable event notifications + + Usage: + uint32_t enable; + ioctl(fd, IOCTL_MEI_NOTIFY_SET, &enable); + + Inputs: + uint32_t enable = 1; + or + uint32_t enable[disable] = 0; + + Error returns: + EINVAL Wrong IOCTL Number + ENODEV Device is not initialized or the client not connected + ENOMEM Unable to allocate memory to client internal data. + EFAULT Fatal Error (e.g. Unable to access user input data) + EOPNOTSUPP if the device doesn't support the feature + + Notes: + The client must be connected in order to enable notification events + + + IOCTL_MEI_NOTIFY_GET : retrieve event + + Usage: + uint32_t event; + ioctl(fd, IOCTL_MEI_NOTIFY_GET, &event); + + Outputs: + 1 - if an event is pending + 0 - if there is no even pending + + Error returns: + EINVAL Wrong IOCTL Number + ENODEV Device is not initialized or the client not connected + ENOMEM Unable to allocate memory to client internal data. + EFAULT Fatal Error (e.g. Unable to access user input data) + EOPNOTSUPP if the device doesn't support the feature + + Notes: + The client must be connected and event notification has to be enabled + in order to receive an event + Intel ME Applications ===================== diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index e9513d651cd3..ffa70035af29 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -445,6 +445,45 @@ end: return rets; } +/** + * mei_ioctl_client_notify_request - + * propagate event notification request to client + * + * @file: pointer to file structure + * @request: 0 - disable, 1 - enable + * + * Return: 0 on success , <0 on error + */ +static int mei_ioctl_client_notify_request(struct file *file, u32 request) +{ + struct mei_cl *cl = file->private_data; + + return mei_cl_notify_request(cl, file, request); +} + +/** + * mei_ioctl_client_notify_get - wait for notification request + * + * @file: pointer to file structure + * @notify_get: 0 - disable, 1 - enable + * + * Return: 0 on success , <0 on error + */ +static int mei_ioctl_client_notify_get(struct file *file, u32 *notify_get) +{ + struct mei_cl *cl = file->private_data; + bool notify_ev; + bool block = (file->f_flags & O_NONBLOCK) == 0; + int rets; + + rets = mei_cl_notify_get(cl, block, ¬ify_ev); + if (rets) + return rets; + + *notify_get = notify_ev ? 1 : 0; + return 0; +} + /** * mei_ioctl - the IOCTL function * @@ -459,6 +498,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) struct mei_device *dev; struct mei_cl *cl = file->private_data; struct mei_connect_client_data connect_data; + u32 notify_get, notify_req; int rets; @@ -499,6 +539,33 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) break; + case IOCTL_MEI_NOTIFY_SET: + dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_SET.\n"); + if (copy_from_user(¬ify_req, + (char __user *)data, sizeof(notify_req))) { + dev_dbg(dev->dev, "failed to copy data from userland\n"); + rets = -EFAULT; + goto out; + } + rets = mei_ioctl_client_notify_request(file, notify_req); + break; + + case IOCTL_MEI_NOTIFY_GET: + dev_dbg(dev->dev, ": IOCTL_MEI_NOTIFY_GET.\n"); + rets = mei_ioctl_client_notify_get(file, ¬ify_get); + if (rets) + goto out; + + dev_dbg(dev->dev, "copy connect data to user\n"); + if (copy_to_user((char __user *)data, + ¬ify_get, sizeof(notify_get))) { + dev_dbg(dev->dev, "failed to copy data to userland\n"); + rets = -EFAULT; + goto out; + + } + break; + default: dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd); rets = -ENOIOCTLCMD; diff --git a/include/uapi/linux/mei.h b/include/uapi/linux/mei.h index bc0d8b69c49e..7c3b64f6a215 100644 --- a/include/uapi/linux/mei.h +++ b/include/uapi/linux/mei.h @@ -107,4 +107,23 @@ struct mei_connect_client_data { }; }; +/** + * DOC: set and unset event notification for a connected client + * + * The IOCTL argument is 1 for enabling event notification and 0 for + * disabling the service + * Return: -EOPNOTSUPP if the devices doesn't support the feature + */ +#define IOCTL_MEI_NOTIFY_SET _IOW('H', 0x02, __u32) + +/** + * DOC: retrieve notification + * + * The IOCTL output argument is 1 if an event was is pending and 0 otherwise + * the ioctl has to be called in order to acknowledge pending event + * + * Return: -EOPNOTSUPP if the devices doesn't support the feature + */ +#define IOCTL_MEI_NOTIFY_GET _IOR('H', 0x03, __u32) + #endif /* _LINUX_MEI_H */ -- cgit v1.3-6-gb490 From 2c84c2970c1acf83827aa97ab0e6addc3d2aa960 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 26 Jul 2015 09:54:21 +0300 Subject: mei: support polling for event notification Polling on priority events is translated on waiting for event notification. One need to enable notification prior for calling select or poll system call otherwise process will not wait. Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index ffa70035af29..17b356f26686 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -608,6 +608,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) struct mei_cl *cl = file->private_data; struct mei_device *dev; unsigned int mask = 0; + bool notify_en; if (WARN_ON(!cl || !cl->dev)) return POLLERR; @@ -616,6 +617,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) mutex_lock(&dev->device_lock); + notify_en = cl->notify_en && (req_events & POLLPRI); if (dev->dev_state != MEI_DEV_ENABLED || !mei_cl_is_connected(cl)) { @@ -628,6 +630,12 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) goto out; } + if (notify_en) { + poll_wait(file, &cl->ev_wait, wait); + if (cl->notify_ev) + mask |= POLLPRI; + } + if (req_events & (POLLIN | POLLRDNORM)) { poll_wait(file, &cl->rx_wait, wait); -- cgit v1.3-6-gb490 From 237092bf034a648611f61eb1f0965e9ba1b08871 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 26 Jul 2015 09:54:22 +0300 Subject: mei: implement fasync for event notification A process can be informed about client notification also via SIGIO with POLL_PRI event. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 27 +++++++++++++++++++++++++++ drivers/misc/mei/client.h | 1 + drivers/misc/mei/hbm.c | 6 ++---- drivers/misc/mei/main.c | 21 +++++++++++++++++++++ drivers/misc/mei/mei_dev.h | 2 ++ 5 files changed, 53 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index d9396838774c..db2436aee2dc 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -1350,6 +1350,33 @@ out: return rets; } +/** + * mei_cl_notify - raise notification + * + * @cl: host client + * + * Locking: called under "dev->device_lock" lock + */ +void mei_cl_notify(struct mei_cl *cl) +{ + struct mei_device *dev; + + if (!cl || !cl->dev) + return; + + dev = cl->dev; + + if (!cl->notify_en) + return; + + cl_dbg(dev, cl, "notify event"); + cl->notify_ev = true; + wake_up_interruptible_all(&cl->ev_wait); + + if (cl->ev_async) + kill_fasync(&cl->ev_async, SIGIO, POLL_PRI); +} + /** * mei_cl_notify_get - get or wait for notification event * diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 58a4b49701fe..1c7cad07d731 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -225,6 +225,7 @@ int mei_cl_notify_request(struct mei_cl *cl, struct file *file, u8 request); int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev); +void mei_cl_notify(struct mei_cl *cl); void mei_cl_all_disconnect(struct mei_device *dev); void mei_cl_all_wakeup(struct mei_device *dev); diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 70c94a9cd905..7f53597e697a 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -514,10 +514,8 @@ static void mei_hbm_cl_notify(struct mei_device *dev, struct mei_cl *cl; cl = mei_hbm_cl_find_by_cmd(dev, cmd); - if (cl && cl->notify_en) { - cl->notify_ev = true; - wake_up_interruptible(&cl->ev_wait); - } + if (cl) + mei_cl_notify(cl); } /** diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 17b356f26686..b2f2486b3d75 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -650,6 +650,26 @@ out: return mask; } +/** + * mei_fasync - asynchronous io support + * + * @fd: file descriptor + * @file: pointer to file structure + * @band: band bitmap + * + * Return: poll mask + */ +static int mei_fasync(int fd, struct file *file, int band) +{ + + struct mei_cl *cl = file->private_data; + + if (!mei_cl_is_connected(cl)) + return POLLERR; + + return fasync_helper(fd, file, band, &cl->ev_async); +} + /** * fw_status_show - mei device attribute show method * @@ -702,6 +722,7 @@ static const struct file_operations mei_fops = { .release = mei_release, .write = mei_write, .poll = mei_poll, + .fasync = mei_fasync, .llseek = no_llseek }; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 6f8f5e1e909e..c960aaa538c0 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -236,6 +236,7 @@ struct mei_cl_cb { * @rx_wait: wait queue for rx completion * @wait: wait queue for management operation * @ev_wait: notification wait queue + * @ev_async: event async notification * @status: connection status * @me_cl: fw client connected * @host_client_id: host id @@ -258,6 +259,7 @@ struct mei_cl { wait_queue_head_t rx_wait; wait_queue_head_t wait; wait_queue_head_t ev_wait; + struct fasync_struct *ev_async; int status; struct mei_me_client *me_cl; u8 host_client_id; -- cgit v1.3-6-gb490 From bb2ef9c39db2e3c2562b4e439b2b00dc42e2c026 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 26 Jul 2015 09:54:23 +0300 Subject: mei: bus: add and call callback on notify event Enable drivers on mei client bus to subscribe to asynchronous event notifications. Introduce events_mask to the existing callback infrastructure so it is possible to handle both RX and event notification. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 50 ++++++++++++++++++++++++++++++++++++++++++---- drivers/misc/mei/client.c | 2 ++ drivers/misc/mei/mei_dev.h | 1 + drivers/nfc/mei_phy.c | 3 ++- include/linux/mei_cl_bus.h | 4 ++++ 5 files changed, 55 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 3ab08e522fb8..eef1c6b46ad8 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -222,7 +222,33 @@ static void mei_bus_event_work(struct work_struct *work) cldev->events = 0; /* Prepare for the next read */ - mei_cl_read_start(cldev->cl, 0, NULL); + if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) + mei_cl_read_start(cldev->cl, 0, NULL); +} + +/** + * mei_cl_bus_notify_event - schedule notify cb on bus client + * + * @cl: host client + */ +void mei_cl_bus_notify_event(struct mei_cl *cl) +{ + struct mei_cl_device *cldev = cl->cldev; + + if (!cldev || !cldev->event_cb) + return; + + if (!(cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF))) + return; + + if (!cl->notify_ev) + return; + + set_bit(MEI_CL_EVENT_NOTIF, &cldev->events); + + schedule_work(&cldev->event_work); + + cl->notify_ev = false; } /** @@ -237,6 +263,9 @@ void mei_cl_bus_rx_event(struct mei_cl *cl) if (!cldev || !cldev->event_cb) return; + if (!(cldev->events_mask & BIT(MEI_CL_EVENT_RX))) + return; + set_bit(MEI_CL_EVENT_RX, &cldev->events); schedule_work(&cldev->event_work); @@ -247,6 +276,7 @@ void mei_cl_bus_rx_event(struct mei_cl *cl) * * @cldev: me client devices * @event_cb: callback function + * @events_mask: requested events bitmask * @context: driver context data * * Return: 0 on success @@ -254,6 +284,7 @@ void mei_cl_bus_rx_event(struct mei_cl *cl) * <0 on other errors */ int mei_cl_register_event_cb(struct mei_cl_device *cldev, + unsigned long events_mask, mei_cl_event_cb_t event_cb, void *context) { int ret; @@ -262,13 +293,24 @@ int mei_cl_register_event_cb(struct mei_cl_device *cldev, return -EALREADY; cldev->events = 0; + cldev->events_mask = events_mask; cldev->event_cb = event_cb; cldev->event_context = context; INIT_WORK(&cldev->event_work, mei_bus_event_work); - ret = mei_cl_read_start(cldev->cl, 0, NULL); - if (ret && ret != -EBUSY) - return ret; + if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) { + ret = mei_cl_read_start(cldev->cl, 0, NULL); + if (ret && ret != -EBUSY) + return ret; + } + + if (cldev->events_mask & BIT(MEI_CL_EVENT_NOTIF)) { + mutex_lock(&cldev->cl->dev->device_lock); + ret = mei_cl_notify_request(cldev->cl, NULL, event_cb ? 1 : 0); + mutex_unlock(&cldev->cl->dev->device_lock); + if (ret) + return ret; + } return 0; } diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index db2436aee2dc..5fcd70bcdf96 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -1375,6 +1375,8 @@ void mei_cl_notify(struct mei_cl *cl) if (cl->ev_async) kill_fasync(&cl->ev_async, SIGIO, POLL_PRI); + + mei_cl_bus_notify_event(cl); } /** diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index c960aaa538c0..e25ee16c658e 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -345,6 +345,7 @@ ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, bool blocking); ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length); void mei_cl_bus_rx_event(struct mei_cl *cl); +void mei_cl_bus_notify_event(struct mei_cl *cl); void mei_cl_bus_remove_devices(struct mei_device *bus); int mei_cl_bus_init(void); void mei_cl_bus_exit(void); diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c index 2b77ccf77f81..754a9bb0f58d 100644 --- a/drivers/nfc/mei_phy.c +++ b/drivers/nfc/mei_phy.c @@ -355,7 +355,8 @@ static int nfc_mei_phy_enable(void *phy_id) goto err; } - r = mei_cl_register_event_cb(phy->device, nfc_mei_event_cb, phy); + r = mei_cl_register_event_cb(phy->device, BIT(MEI_CL_EVENT_RX), + nfc_mei_event_cb, phy); if (r) { pr_err("Event cb registration failed %d\n", r); goto err; diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index 81ab56dd0ae0..0962b2ca628a 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -28,6 +28,7 @@ typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device, * @event_cb: Drivers register this callback to get asynchronous ME * events (e.g. Rx buffer pending) notifications. * @event_context: event callback run context + * @events_mask: Events bit mask requested by driver. * @events: Events bitmask sent to the driver. * * @do_match: wheather device can be matched with a driver @@ -46,6 +47,7 @@ struct mei_cl_device { struct work_struct event_work; mei_cl_event_cb_t event_cb; void *event_context; + unsigned long events_mask; unsigned long events; unsigned int do_match:1; @@ -76,10 +78,12 @@ ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length); ssize_t mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length); int mei_cl_register_event_cb(struct mei_cl_device *device, + unsigned long event_mask, mei_cl_event_cb_t read_cb, void *context); #define MEI_CL_EVENT_RX 0 #define MEI_CL_EVENT_TX 1 +#define MEI_CL_EVENT_NOTIF 2 void *mei_cl_get_drvdata(const struct mei_cl_device *device); void mei_cl_set_drvdata(struct mei_cl_device *device, void *data); -- cgit v1.3-6-gb490 From 71e117f28a6782fa2d31cce63340a9f18417afa4 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Wed, 29 Jul 2015 14:59:33 +0300 Subject: mei: hbm: add new error code MEI_CL_CONN_NOT_ALLOWED The device can return error 5 (NOT_ALLOWED) on connection attempt. This error can happen if: 1. An another connection attempt is in progress 2. There is an attempt to connect a fixed (connectionless) client 3. The number of available connections is exceeded (new in HBM 2.0) We should not hit that error unless there is an internal book keeping hiccup except option (3), therefore we translate the error code to errno EBUSY; Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hbm.c | 2 ++ drivers/misc/mei/hw.h | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 7f53597e697a..7646569922fe 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -52,6 +52,7 @@ static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status) MEI_CL_CS(ALREADY_STARTED); MEI_CL_CS(OUT_OF_RESOURCES); MEI_CL_CS(MESSAGE_SMALL); + MEI_CL_CS(NOT_ALLOWED); default: return "unknown"; } #undef MEI_CL_CCS @@ -89,6 +90,7 @@ static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status) case MEI_CL_CONN_ALREADY_STARTED: return -EBUSY; case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY; case MEI_CL_CONN_MESSAGE_SMALL: return -EINVAL; + case MEI_CL_CONN_NOT_ALLOWED: return -EBUSY; default: return -EINVAL; } } diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 3f8901a503a6..c262d0bd5bd5 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -161,6 +161,7 @@ enum mei_cl_connect_status { MEI_CL_CONN_ALREADY_STARTED = MEI_HBMS_ALREADY_EXISTS, MEI_CL_CONN_OUT_OF_RESOURCES = MEI_HBMS_REJECTED, MEI_CL_CONN_MESSAGE_SMALL = MEI_HBMS_INVALID_PARAMETER, + MEI_CL_CONN_NOT_ALLOWED = MEI_HBMS_NOT_ALLOWED, }; /* -- cgit v1.3-6-gb490 From 11830486c5717c713bb363b14944cda39e3034f9 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 2 Aug 2015 22:20:50 +0300 Subject: mei: me: d0i3: add the control registers Starting with Intel Sunrisepoint (Skylake PCH) the MEI device supports D0i3 low power state. Add D0i3 control registers. Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 9eb7ed70ace2..6cfb198d5daf 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -140,7 +140,8 @@ #define ME_CSR_HA 0xC /* H_HGC_CSR - PGI register */ #define H_HPG_CSR 0x10 - +/* H_D0I3C - D0I3 Control */ +#define H_D0I3C 0x800 /* register bits of H_CSR (Host Control Status register) */ /* Host Circular Buffer Depth - maximum number of 32-bit entries in CB */ @@ -159,7 +160,10 @@ #define H_IS 0x00000002 /* Host Interrupt Enable */ #define H_IE 0x00000001 - +/* Host D0I3 Interrupt Enable */ +#define H_D0I3C_IE 0x00000020 +/* Host D0I3 Interrupt Status */ +#define H_D0I3C_IS 0x00000040 /* register bits of ME_CSR_HA (ME Control Status Host Access register) */ /* ME CB (Circular Buffer) Depth HRA (Host Read Access) - host read only @@ -183,8 +187,14 @@ access to ME_CBD */ #define ME_IE_HRA 0x00000001 -/* register bits - H_HPG_CSR */ -#define H_HPG_CSR_PGIHEXR 0x00000001 -#define H_HPG_CSR_PGI 0x00000002 +/* H_HPG_CSR register bits */ +#define H_HPG_CSR_PGIHEXR 0x00000001 +#define H_HPG_CSR_PGI 0x00000002 + +/* H_D0I3C register bits */ +#define H_D0I3C_CIP 0x00000001 +#define H_D0I3C_IR 0x00000002 +#define H_D0I3C_I3 0x00000004 +#define H_D0I3C_RR 0x00000008 #endif /* _MEI_HW_MEI_REGS_H_ */ -- cgit v1.3-6-gb490 From bb9f4d26dda7d2a875cadc0f7eedee3d65d3d1f5 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 2 Aug 2015 22:20:51 +0300 Subject: mei: me: d0i3: add flag to indicate D0i3 support Detect d0i3 low power state during hw configuration, the value is set in HFS_1 pci config reigister. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 1 + drivers/misc/mei/hw-me.c | 10 +++++++++- drivers/misc/mei/hw-me.h | 6 ++++-- 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 6cfb198d5daf..4c8f05ea3651 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -123,6 +123,7 @@ /* Host Firmware Status Registers in PCI Config Space */ #define PCI_CFG_HFS_1 0x40 +# define PCI_CFG_HFS_1_D0I3_MSK 0x80000000 #define PCI_CFG_HFS_2 0x48 #define PCI_CFG_HFS_3 0x60 #define PCI_CFG_HFS_4 0x64 diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 43d7101ff993..17d6894b0fd2 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -176,12 +176,20 @@ static int mei_me_fw_status(struct mei_device *dev, */ static void mei_me_hw_config(struct mei_device *dev) { + struct pci_dev *pdev = to_pci_dev(dev->dev); struct mei_me_hw *hw = to_me_hw(dev); - u32 hcsr = mei_hcsr_read(dev); + u32 hcsr, reg; + /* Doesn't change in runtime */ + hcsr = mei_hcsr_read(dev); dev->hbuf_depth = (hcsr & H_CBD) >> 24; hw->pg_state = MEI_PG_OFF; + + reg = 0; + pci_read_config_dword(pdev, PCI_CFG_HFS_1, ®); + hw->d0i3_supported = + ((reg & PCI_CFG_HFS_1_D0I3_MSK) == PCI_CFG_HFS_1_D0I3_MSK); } /** diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h index 6022d52af6f6..cf64847a35b9 100644 --- a/drivers/misc/mei/hw-me.h +++ b/drivers/misc/mei/hw-me.h @@ -50,13 +50,15 @@ struct mei_cfg { * struct mei_me_hw - me hw specific data * * @cfg: per device generation config and ops - * @mem_addr: io memory address - * @pg_state: power gating state + * @mem_addr: io memory address + * @pg_state: power gating state + * @d0i3_supported: di03 support */ struct mei_me_hw { const struct mei_cfg *cfg; void __iomem *mem_addr; enum mei_pg_state pg_state; + bool d0i3_supported; }; #define to_me_hw(dev) (struct mei_me_hw *)((dev)->hw) -- cgit v1.3-6-gb490 From 1fa55b4e0e161b3d16b52f5bab1b39b39607bc27 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 2 Aug 2015 22:20:52 +0300 Subject: mei: me: d0i3: enable d0i3 interrupts D0i3 adds additional interrupt reason bit, therefore we add a variable intr_source to save the interrupt causes for further dispatching. The interrupt cause is saved in the irq quick handler to achieve unified behavior for both MSI enabled and shared interrupt platforms. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 4 ++++ drivers/misc/mei/hw-me.c | 35 +++++++++++++++++------------------ drivers/misc/mei/hw-me.h | 2 ++ drivers/misc/mei/pci-me.c | 27 ++++++++++----------------- 4 files changed, 33 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 4c8f05ea3651..8793ccca12ad 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -166,6 +166,10 @@ /* Host D0I3 Interrupt Status */ #define H_D0I3C_IS 0x00000040 +/* H_CSR masks */ +#define H_CSR_IE_MASK (H_IE | H_D0I3C_IE) +#define H_CSR_IS_MASK (H_IS | H_D0I3C_IS) + /* register bits of ME_CSR_HA (ME Control Status Host Access register) */ /* ME CB (Circular Buffer) Depth HRA (Host Read Access) - host read only access to ME_CBD */ diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 17d6894b0fd2..910af88b3214 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -134,7 +134,7 @@ static inline void mei_hcsr_write(struct mei_device *dev, u32 reg) */ static inline void mei_hcsr_set(struct mei_device *dev, u32 reg) { - reg &= ~H_IS; + reg &= ~H_CSR_IS_MASK; mei_hcsr_write(dev, reg); } @@ -216,7 +216,7 @@ static void mei_me_intr_clear(struct mei_device *dev) { u32 hcsr = mei_hcsr_read(dev); - if ((hcsr & H_IS) == H_IS) + if (hcsr & H_CSR_IS_MASK) mei_hcsr_write(dev, hcsr); } /** @@ -228,7 +228,7 @@ static void mei_me_intr_enable(struct mei_device *dev) { u32 hcsr = mei_hcsr_read(dev); - hcsr |= H_IE; + hcsr |= H_CSR_IE_MASK; mei_hcsr_set(dev, hcsr); } @@ -241,7 +241,7 @@ static void mei_me_intr_disable(struct mei_device *dev) { u32 hcsr = mei_hcsr_read(dev); - hcsr &= ~H_IE; + hcsr &= ~H_CSR_IE_MASK; mei_hcsr_set(dev, hcsr); } @@ -285,12 +285,12 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) hcsr = mei_hcsr_read(dev); } - hcsr |= H_RST | H_IG | H_IS; + hcsr |= H_RST | H_IG | H_CSR_IS_MASK; if (intr_enable) - hcsr |= H_IE; + hcsr |= H_CSR_IE_MASK; else - hcsr &= ~H_IE; + hcsr &= ~H_CSR_IE_MASK; dev->recvd_hw_ready = false; mei_hcsr_write(dev, hcsr); @@ -322,7 +322,7 @@ static void mei_me_host_set_ready(struct mei_device *dev) { u32 hcsr = mei_hcsr_read(dev); - hcsr |= H_IE | H_IG | H_RDY; + hcsr |= H_CSR_IE_MASK | H_IG | H_RDY; mei_hcsr_set(dev, hcsr); } @@ -767,16 +767,20 @@ static void mei_me_pg_intr(struct mei_device *dev) * * Return: irqreturn_t */ - irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id) { - struct mei_device *dev = (struct mei_device *) dev_id; - u32 hcsr = mei_hcsr_read(dev); + struct mei_device *dev = (struct mei_device *)dev_id; + struct mei_me_hw *hw = to_me_hw(dev); + u32 hcsr; - if ((hcsr & H_IS) != H_IS) + hcsr = mei_hcsr_read(dev); + if (!(hcsr & H_CSR_IS_MASK)) return IRQ_NONE; - /* clear H_IS bit in H_CSR */ + hw->intr_source = hcsr & H_CSR_IS_MASK; + dev_dbg(dev->dev, "interrupt source 0x%08X.\n", hw->intr_source); + + /* clear H_IS and H_D0I3C_IS bits in H_CSR to clear the interrupts */ mei_hcsr_write(dev, hcsr); return IRQ_WAKE_THREAD; @@ -804,11 +808,6 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) mutex_lock(&dev->device_lock); mei_io_list_init(&complete_list); - /* Ack the interrupt here - * In case of MSI we don't go through the quick handler */ - if (pci_dev_msi_enabled(to_pci_dev(dev->dev))) - mei_clear_interrupts(dev); - /* check if ME wants a reset */ if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) { dev_warn(dev->dev, "FW not ready: resetting.\n"); diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h index cf64847a35b9..2ee14dc1b2ea 100644 --- a/drivers/misc/mei/hw-me.h +++ b/drivers/misc/mei/hw-me.h @@ -51,12 +51,14 @@ struct mei_cfg { * * @cfg: per device generation config and ops * @mem_addr: io memory address + * @intr_source: interrupt source * @pg_state: power gating state * @d0i3_supported: di03 support */ struct mei_me_hw { const struct mei_cfg *cfg; void __iomem *mem_addr; + u32 intr_source; enum mei_pg_state pg_state; bool d0i3_supported; }; diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 23f71f5ce4fb..7fee74abbc21 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -128,6 +128,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) const struct mei_cfg *cfg = (struct mei_cfg *)(ent->driver_data); struct mei_device *dev; struct mei_me_hw *hw; + unsigned int irqflags; int err; @@ -180,17 +181,12 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_enable_msi(pdev); /* request and enable interrupt */ - if (pci_dev_msi_enabled(pdev)) - err = request_threaded_irq(pdev->irq, - NULL, - mei_me_irq_thread_handler, - IRQF_ONESHOT, KBUILD_MODNAME, dev); - else - err = request_threaded_irq(pdev->irq, + irqflags = pci_dev_msi_enabled(pdev) ? IRQF_ONESHOT : IRQF_SHARED; + + err = request_threaded_irq(pdev->irq, mei_me_irq_quick_handler, mei_me_irq_thread_handler, - IRQF_SHARED, KBUILD_MODNAME, dev); - + irqflags, KBUILD_MODNAME, dev); if (err) { dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n", pdev->irq); @@ -319,6 +315,7 @@ static int mei_me_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct mei_device *dev; + unsigned int irqflags; int err; dev = pci_get_drvdata(pdev); @@ -327,17 +324,13 @@ static int mei_me_pci_resume(struct device *device) pci_enable_msi(pdev); + irqflags = pci_dev_msi_enabled(pdev) ? IRQF_ONESHOT : IRQF_SHARED; + /* request and enable interrupt */ - if (pci_dev_msi_enabled(pdev)) - err = request_threaded_irq(pdev->irq, - NULL, - mei_me_irq_thread_handler, - IRQF_ONESHOT, KBUILD_MODNAME, dev); - else - err = request_threaded_irq(pdev->irq, + err = request_threaded_irq(pdev->irq, mei_me_irq_quick_handler, mei_me_irq_thread_handler, - IRQF_SHARED, KBUILD_MODNAME, dev); + irqflags, KBUILD_MODNAME, dev); if (err) { dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n", -- cgit v1.3-6-gb490 From 63f75232dbb17badc31c3cc6cc1434763d5a6009 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 2 Aug 2015 22:20:53 +0300 Subject: mei: hbm: reorganize the power gating responses Before adding support for D0i3 we need to reorganize the hbm pg handling Move HBM PG response code to dedicated functions in order to unclutter hbm command switch. Add check for the right system state before message processing and return -EPROTO in state mismatch case. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hbm.c | 85 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 7646569922fe..21f40ce87ac8 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -879,6 +879,68 @@ static int mei_hbm_fw_disconnect_req(struct mei_device *dev, return 0; } +/** + * mei_hbm_pg_enter_res - PG enter response received + * + * @dev: the device structure. + * + * Return: 0 on success, -EPROTO on state mismatch + */ +static int mei_hbm_pg_enter_res(struct mei_device *dev) +{ + if (mei_pg_state(dev) != MEI_PG_OFF || + dev->pg_event != MEI_PG_EVENT_WAIT) { + dev_err(dev->dev, "hbm: pg entry response: state mismatch [%s, %d]\n", + mei_pg_state_str(mei_pg_state(dev)), dev->pg_event); + return -EPROTO; + } + + dev->pg_event = MEI_PG_EVENT_RECEIVED; + wake_up(&dev->wait_pg); + + return 0; +} + +/** + * mei_hbm_pg_exit_res - PG exit response received + * + * @dev: the device structure. + * + * Return: 0 on success, -EPROTO on state mismatch + */ +static int mei_hbm_pg_exit_res(struct mei_device *dev) +{ + if (mei_pg_state(dev) != MEI_PG_ON || + (dev->pg_event != MEI_PG_EVENT_WAIT && + dev->pg_event != MEI_PG_EVENT_IDLE)) { + dev_err(dev->dev, "hbm: pg exit response: state mismatch [%s, %d]\n", + mei_pg_state_str(mei_pg_state(dev)), dev->pg_event); + return -EPROTO; + } + + switch (dev->pg_event) { + case MEI_PG_EVENT_WAIT: + dev->pg_event = MEI_PG_EVENT_RECEIVED; + wake_up(&dev->wait_pg); + break; + case MEI_PG_EVENT_IDLE: + /* + * If the driver is not waiting on this then + * this is HW initiated exit from PG. + * Start runtime pm resume sequence to exit from PG. + */ + dev->pg_event = MEI_PG_EVENT_RECEIVED; + pm_request_resume(dev->dev); + break; + default: + WARN(1, "hbm: pg exit response: unexpected pg event = %d\n", + dev->pg_event); + return -EPROTO; + } + + return 0; +} + /** * mei_hbm_config_features - check what hbm features and commands * are supported by the fw @@ -1027,24 +1089,17 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) break; case MEI_PG_ISOLATION_ENTRY_RES_CMD: - dev_dbg(dev->dev, "power gate isolation entry response received\n"); - dev->pg_event = MEI_PG_EVENT_RECEIVED; - if (waitqueue_active(&dev->wait_pg)) - wake_up(&dev->wait_pg); + dev_dbg(dev->dev, "hbm: power gate isolation entry response received\n"); + ret = mei_hbm_pg_enter_res(dev); + if (ret) + return ret; break; case MEI_PG_ISOLATION_EXIT_REQ_CMD: - dev_dbg(dev->dev, "power gate isolation exit request received\n"); - dev->pg_event = MEI_PG_EVENT_RECEIVED; - if (waitqueue_active(&dev->wait_pg)) - wake_up(&dev->wait_pg); - else - /* - * If the driver is not waiting on this then - * this is HW initiated exit from PG. - * Start runtime pm resume sequence to exit from PG. - */ - pm_request_resume(dev->dev); + dev_dbg(dev->dev, "hbm: power gate isolation exit request received\n"); + ret = mei_hbm_pg_exit_res(dev); + if (ret) + return ret; break; case HOST_CLIENT_PROPERTIES_RES_CMD: -- cgit v1.3-6-gb490 From 859ef2ffbfa785d273567467088cc8743f80b5bd Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 2 Aug 2015 22:20:54 +0300 Subject: mei: me: d0i3: add d0i3 enter/exit state machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework mei power gating state machine to support entry and exit to and from D0i3 power state. The choice between legacy and D0i3 routines is conditioned on d0i3_supported flag. The patch introduces warning: drivers/misc/mei/hw-me.c:901:12: warning: ‘mei_me_d0i3_enter’ defined but not used [-Wunused-function] it will go away in consequent patch Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hbm.c | 13 +- drivers/misc/mei/hbm.h | 1 + drivers/misc/mei/hw-me.c | 337 ++++++++++++++++++++++++++++++++++++++++++++++- drivers/misc/mei/hw.h | 5 +- 4 files changed, 346 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 21f40ce87ac8..8eec887c8f70 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -901,6 +901,17 @@ static int mei_hbm_pg_enter_res(struct mei_device *dev) return 0; } +/** + * mei_hbm_pg_resume - process with PG resume + * + * @dev: the device structure. + */ +void mei_hbm_pg_resume(struct mei_device *dev) +{ + pm_request_resume(dev->dev); +} +EXPORT_SYMBOL_GPL(mei_hbm_pg_resume); + /** * mei_hbm_pg_exit_res - PG exit response received * @@ -930,7 +941,7 @@ static int mei_hbm_pg_exit_res(struct mei_device *dev) * Start runtime pm resume sequence to exit from PG. */ dev->pg_event = MEI_PG_EVENT_RECEIVED; - pm_request_resume(dev->dev); + mei_hbm_pg_resume(dev); break; default: WARN(1, "hbm: pg exit response: unexpected pg event = %d\n", diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h index 42d66d8fc1f7..a2025a5083a3 100644 --- a/drivers/misc/mei/hbm.h +++ b/drivers/misc/mei/hbm.h @@ -54,6 +54,7 @@ int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl); int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl); bool mei_hbm_version_is_supported(struct mei_device *dev); int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd); +void mei_hbm_pg_resume(struct mei_device *dev); int mei_hbm_cl_notify_req(struct mei_device *dev, struct mei_cl *cl, u8 request); diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 910af88b3214..bce465546158 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -138,6 +138,35 @@ static inline void mei_hcsr_set(struct mei_device *dev, u32 reg) mei_hcsr_write(dev, reg); } +/** + * mei_me_d0i3c_read - Reads 32bit data from the D0I3C register + * + * @dev: the device structure + * + * Return: H_D0I3C register value (u32) + */ +static inline u32 mei_me_d0i3c_read(const struct mei_device *dev) +{ + u32 reg; + + reg = mei_me_reg_read(to_me_hw(dev), H_D0I3C); + trace_mei_reg_read(dev->dev, "H_D0I3C", H_CSR, reg); + + return reg; +} + +/** + * mei_me_d0i3c_write - writes H_D0I3C register to device + * + * @dev: the device structure + * @reg: new register value + */ +static inline void mei_me_d0i3c_write(struct mei_device *dev, u32 reg) +{ + trace_mei_reg_write(dev->dev, "H_D0I3C", H_CSR, reg); + mei_me_reg_write(to_me_hw(dev), H_D0I3C, reg); +} + /** * mei_me_fw_status - read fw status register from pci config space * @@ -609,13 +638,13 @@ static void mei_me_pg_unset(struct mei_device *dev) } /** - * mei_me_pg_enter_sync - perform pg entry procedure + * mei_me_pg_legacy_enter_sync - perform legacy pg entry procedure * * @dev: the device structure * * Return: 0 on success an error code otherwise */ -int mei_me_pg_enter_sync(struct mei_device *dev) +static int mei_me_pg_legacy_enter_sync(struct mei_device *dev) { struct mei_me_hw *hw = to_me_hw(dev); unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); @@ -646,13 +675,13 @@ int mei_me_pg_enter_sync(struct mei_device *dev) } /** - * mei_me_pg_exit_sync - perform pg exit procedure + * mei_me_pg_legacy_exit_sync - perform legacy pg exit procedure * * @dev: the device structure * * Return: 0 on success an error code otherwise */ -int mei_me_pg_exit_sync(struct mei_device *dev) +static int mei_me_pg_legacy_exit_sync(struct mei_device *dev) { struct mei_me_hw *hw = to_me_hw(dev); unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); @@ -720,8 +749,12 @@ static bool mei_me_pg_in_transition(struct mei_device *dev) */ static bool mei_me_pg_is_enabled(struct mei_device *dev) { + struct mei_me_hw *hw = to_me_hw(dev); u32 reg = mei_me_mecsr_read(dev); + if (hw->d0i3_supported) + return true; + if ((reg & ME_PGIC_HRA) == 0) goto notsupported; @@ -731,7 +764,8 @@ static bool mei_me_pg_is_enabled(struct mei_device *dev) return true; notsupported: - dev_dbg(dev->dev, "pg: not supported: HGP = %d hbm version %d.%d ?= %d.%d\n", + dev_dbg(dev->dev, "pg: not supported: d0i3 = %d HGP = %d hbm version %d.%d ?= %d.%d\n", + hw->d0i3_supported, !!(reg & ME_PGIC_HRA), dev->version.major_version, dev->version.minor_version, @@ -742,11 +776,211 @@ notsupported: } /** - * mei_me_pg_intr - perform pg processing in interrupt thread handler + * mei_me_d0i3_set - write d0i3 register bit on mei device. * * @dev: the device structure + * @intr: ask for interrupt + * + * Return: D0I3C register value */ -static void mei_me_pg_intr(struct mei_device *dev) +static u32 mei_me_d0i3_set(struct mei_device *dev, bool intr) +{ + u32 reg = mei_me_d0i3c_read(dev); + + reg |= H_D0I3C_I3; + if (intr) + reg |= H_D0I3C_IR; + else + reg &= ~H_D0I3C_IR; + mei_me_d0i3c_write(dev, reg); + /* read it to ensure HW consistency */ + reg = mei_me_d0i3c_read(dev); + return reg; +} + +/** + * mei_me_d0i3_unset - clean d0i3 register bit on mei device. + * + * @dev: the device structure + * + * Return: D0I3C register value + */ +static u32 mei_me_d0i3_unset(struct mei_device *dev) +{ + u32 reg = mei_me_d0i3c_read(dev); + + reg &= ~H_D0I3C_I3; + reg |= H_D0I3C_IR; + mei_me_d0i3c_write(dev, reg); + /* read it to ensure HW consistency */ + reg = mei_me_d0i3c_read(dev); + return reg; +} + +/** + * mei_me_d0i3_enter_sync - perform d0i3 entry procedure + * + * @dev: the device structure + * + * Return: 0 on success an error code otherwise + */ +static int mei_me_d0i3_enter_sync(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + unsigned long d0i3_timeout = mei_secs_to_jiffies(MEI_D0I3_TIMEOUT); + unsigned long pgi_timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); + int ret; + u32 reg; + + reg = mei_me_d0i3c_read(dev); + if (reg & H_D0I3C_I3) { + /* we are in d0i3, nothing to do */ + dev_dbg(dev->dev, "d0i3 set not needed\n"); + ret = 0; + goto on; + } + + /* PGI entry procedure */ + dev->pg_event = MEI_PG_EVENT_WAIT; + + ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_ENTRY_REQ_CMD); + if (ret) + /* FIXME: should we reset here? */ + goto out; + + mutex_unlock(&dev->device_lock); + wait_event_timeout(dev->wait_pg, + dev->pg_event == MEI_PG_EVENT_RECEIVED, pgi_timeout); + mutex_lock(&dev->device_lock); + + if (dev->pg_event != MEI_PG_EVENT_RECEIVED) { + ret = -ETIME; + goto out; + } + /* end PGI entry procedure */ + + dev->pg_event = MEI_PG_EVENT_INTR_WAIT; + + reg = mei_me_d0i3_set(dev, true); + if (!(reg & H_D0I3C_CIP)) { + dev_dbg(dev->dev, "d0i3 enter wait not needed\n"); + ret = 0; + goto on; + } + + mutex_unlock(&dev->device_lock); + wait_event_timeout(dev->wait_pg, + dev->pg_event == MEI_PG_EVENT_INTR_RECEIVED, d0i3_timeout); + mutex_lock(&dev->device_lock); + + if (dev->pg_event != MEI_PG_EVENT_INTR_RECEIVED) { + reg = mei_me_d0i3c_read(dev); + if (!(reg & H_D0I3C_I3)) { + ret = -ETIME; + goto out; + } + } + + ret = 0; +on: + hw->pg_state = MEI_PG_ON; +out: + dev->pg_event = MEI_PG_EVENT_IDLE; + dev_dbg(dev->dev, "d0i3 enter ret = %d\n", ret); + return ret; +} + +/** + * mei_me_d0i3_enter - perform d0i3 entry procedure + * no hbm PG handshake + * no waiting for confirmation; runs with interrupts + * disabled + * + * @dev: the device structure + * + * Return: 0 on success an error code otherwise + */ +static int mei_me_d0i3_enter(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + u32 reg; + + reg = mei_me_d0i3c_read(dev); + if (reg & H_D0I3C_I3) { + /* we are in d0i3, nothing to do */ + dev_dbg(dev->dev, "already d0i3 : set not needed\n"); + goto on; + } + + mei_me_d0i3_set(dev, false); +on: + hw->pg_state = MEI_PG_ON; + dev->pg_event = MEI_PG_EVENT_IDLE; + dev_dbg(dev->dev, "d0i3 enter\n"); + return 0; +} + +/** + * mei_me_d0i3_exit_sync - perform d0i3 exit procedure + * + * @dev: the device structure + * + * Return: 0 on success an error code otherwise + */ +static int mei_me_d0i3_exit_sync(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + unsigned long timeout = mei_secs_to_jiffies(MEI_D0I3_TIMEOUT); + int ret; + u32 reg; + + dev->pg_event = MEI_PG_EVENT_INTR_WAIT; + + reg = mei_me_d0i3c_read(dev); + if (!(reg & H_D0I3C_I3)) { + /* we are not in d0i3, nothing to do */ + dev_dbg(dev->dev, "d0i3 exit not needed\n"); + ret = 0; + goto off; + } + + reg = mei_me_d0i3_unset(dev); + if (!(reg & H_D0I3C_CIP)) { + dev_dbg(dev->dev, "d0i3 exit wait not needed\n"); + ret = 0; + goto off; + } + + mutex_unlock(&dev->device_lock); + wait_event_timeout(dev->wait_pg, + dev->pg_event == MEI_PG_EVENT_INTR_RECEIVED, timeout); + mutex_lock(&dev->device_lock); + + if (dev->pg_event != MEI_PG_EVENT_INTR_RECEIVED) { + reg = mei_me_d0i3c_read(dev); + if (reg & H_D0I3C_I3) { + ret = -ETIME; + goto out; + } + } + + ret = 0; +off: + hw->pg_state = MEI_PG_OFF; +out: + dev->pg_event = MEI_PG_EVENT_IDLE; + + dev_dbg(dev->dev, "d0i3 exit ret = %d\n", ret); + return ret; +} + +/** + * mei_me_pg_legacy_intr - perform legacy pg processing + * in interrupt thread handler + * + * @dev: the device structure + */ +static void mei_me_pg_legacy_intr(struct mei_device *dev) { struct mei_me_hw *hw = to_me_hw(dev); @@ -759,6 +993,95 @@ static void mei_me_pg_intr(struct mei_device *dev) wake_up(&dev->wait_pg); } +/** + * mei_me_d0i3_intr - perform d0i3 processing in interrupt thread handler + * + * @dev: the device structure + */ +static void mei_me_d0i3_intr(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + + if (dev->pg_event == MEI_PG_EVENT_INTR_WAIT && + (hw->intr_source & H_D0I3C_IS)) { + dev->pg_event = MEI_PG_EVENT_INTR_RECEIVED; + if (hw->pg_state == MEI_PG_ON) { + hw->pg_state = MEI_PG_OFF; + if (dev->hbm_state != MEI_HBM_IDLE) { + /* + * force H_RDY because it could be + * wiped off during PG + */ + dev_dbg(dev->dev, "d0i3 set host ready\n"); + mei_me_host_set_ready(dev); + } + } else { + hw->pg_state = MEI_PG_ON; + } + + wake_up(&dev->wait_pg); + } + + if (hw->pg_state == MEI_PG_ON && (hw->intr_source & H_IS)) { + /* + * HW sent some data and we are in D0i3, so + * we got here because of HW initiated exit from D0i3. + * Start runtime pm resume sequence to exit low power state. + */ + dev_dbg(dev->dev, "d0i3 want resume\n"); + mei_hbm_pg_resume(dev); + } +} + +/** + * mei_me_pg_intr - perform pg processing in interrupt thread handler + * + * @dev: the device structure + */ +static void mei_me_pg_intr(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + + if (hw->d0i3_supported) + mei_me_d0i3_intr(dev); + else + mei_me_pg_legacy_intr(dev); +} + +/** + * mei_me_pg_enter_sync - perform runtime pm entry procedure + * + * @dev: the device structure + * + * Return: 0 on success an error code otherwise + */ +int mei_me_pg_enter_sync(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + + if (hw->d0i3_supported) + return mei_me_d0i3_enter_sync(dev); + else + return mei_me_pg_legacy_enter_sync(dev); +} + +/** + * mei_me_pg_exit_sync - perform runtime pm exit procedure + * + * @dev: the device structure + * + * Return: 0 on success an error code otherwise + */ +int mei_me_pg_exit_sync(struct mei_device *dev) +{ + struct mei_me_hw *hw = to_me_hw(dev); + + if (hw->d0i3_supported) + return mei_me_d0i3_exit_sync(dev); + else + return mei_me_pg_legacy_exit_sync(dev); +} + /** * mei_me_irq_quick_handler - The ISR of the MEI device * diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index c262d0bd5bd5..ad6fbcb27f43 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -31,8 +31,9 @@ #define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */ #define MEI_IAMTHIF_READ_TIMER 10 /* HPS */ -#define MEI_PGI_TIMEOUT 1 /* PG Isolation time response 1 sec */ -#define MEI_HBM_TIMEOUT 1 /* 1 second */ +#define MEI_PGI_TIMEOUT 1 /* PG Isolation time response 1 sec */ +#define MEI_D0I3_TIMEOUT 5 /* D0i3 set/unset max response time */ +#define MEI_HBM_TIMEOUT 1 /* 1 second */ /* * MEI Version -- cgit v1.3-6-gb490 From ebad6b945ee2e7e93454ba52030b93e08290317c Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 2 Aug 2015 22:20:55 +0300 Subject: mei: me: d0i3: move mei_me_hw_reset down in the file Move mei_me_hw_reset down in the source file to avoid forward declarations when introducing d0i3 flow in the next patch. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me.c | 103 ++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index bce465546158..448f28133489 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -290,57 +290,6 @@ static void mei_me_hw_reset_release(struct mei_device *dev) /* complete this write before we set host ready on another CPU */ mmiowb(); } -/** - * mei_me_hw_reset - resets fw via mei csr register. - * - * @dev: the device structure - * @intr_enable: if interrupt should be enabled after reset. - * - * Return: always 0 - */ -static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) -{ - u32 hcsr = mei_hcsr_read(dev); - - /* H_RST may be found lit before reset is started, - * for example if preceding reset flow hasn't completed. - * In that case asserting H_RST will be ignored, therefore - * we need to clean H_RST bit to start a successful reset sequence. - */ - if ((hcsr & H_RST) == H_RST) { - dev_warn(dev->dev, "H_RST is set = 0x%08X", hcsr); - hcsr &= ~H_RST; - mei_hcsr_set(dev, hcsr); - hcsr = mei_hcsr_read(dev); - } - - hcsr |= H_RST | H_IG | H_CSR_IS_MASK; - - if (intr_enable) - hcsr |= H_CSR_IE_MASK; - else - hcsr &= ~H_CSR_IE_MASK; - - dev->recvd_hw_ready = false; - mei_hcsr_write(dev, hcsr); - - /* - * Host reads the H_CSR once to ensure that the - * posted write to H_CSR completes. - */ - hcsr = mei_hcsr_read(dev); - - if ((hcsr & H_RST) == 0) - dev_warn(dev->dev, "H_RST is not set = 0x%08X", hcsr); - - if ((hcsr & H_RDY) == H_RDY) - dev_warn(dev->dev, "H_RDY is not cleared 0x%08X", hcsr); - - if (intr_enable == false) - mei_me_hw_reset_release(dev); - - return 0; -} /** * mei_me_host_set_ready - enable device @@ -1082,6 +1031,58 @@ int mei_me_pg_exit_sync(struct mei_device *dev) return mei_me_pg_legacy_exit_sync(dev); } +/** + * mei_me_hw_reset - resets fw via mei csr register. + * + * @dev: the device structure + * @intr_enable: if interrupt should be enabled after reset. + * + * Return: always 0 + */ +static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) +{ + u32 hcsr = mei_hcsr_read(dev); + + /* H_RST may be found lit before reset is started, + * for example if preceding reset flow hasn't completed. + * In that case asserting H_RST will be ignored, therefore + * we need to clean H_RST bit to start a successful reset sequence. + */ + if ((hcsr & H_RST) == H_RST) { + dev_warn(dev->dev, "H_RST is set = 0x%08X", hcsr); + hcsr &= ~H_RST; + mei_hcsr_set(dev, hcsr); + hcsr = mei_hcsr_read(dev); + } + + hcsr |= H_RST | H_IG | H_CSR_IS_MASK; + + if (intr_enable) + hcsr |= H_CSR_IE_MASK; + else + hcsr &= ~H_CSR_IE_MASK; + + dev->recvd_hw_ready = false; + mei_hcsr_write(dev, hcsr); + + /* + * Host reads the H_CSR once to ensure that the + * posted write to H_CSR completes. + */ + hcsr = mei_hcsr_read(dev); + + if ((hcsr & H_RST) == 0) + dev_warn(dev->dev, "H_RST is not set = 0x%08X", hcsr); + + if ((hcsr & H_RDY) == H_RDY) + dev_warn(dev->dev, "H_RDY is not cleared 0x%08X", hcsr); + + if (intr_enable == false) + mei_me_hw_reset_release(dev); + + return 0; +} + /** * mei_me_irq_quick_handler - The ISR of the MEI device * -- cgit v1.3-6-gb490 From b9a1fc99588c2861d4dc26d53b0f47b495cc2964 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 2 Aug 2015 22:20:56 +0300 Subject: mei: me: d0i3: exit d0i3 on driver start and enter it on stop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A BIOS may put the device in d0i3 on platform initialization so it won’t consume power even if the driver is not present, in turn the driver has to wake up the devices on load in order to perform the initialization sequence and move it back to low power state on driver remove. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 448f28133489..65511d39d89b 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -213,12 +213,17 @@ static void mei_me_hw_config(struct mei_device *dev) hcsr = mei_hcsr_read(dev); dev->hbuf_depth = (hcsr & H_CBD) >> 24; - hw->pg_state = MEI_PG_OFF; - reg = 0; pci_read_config_dword(pdev, PCI_CFG_HFS_1, ®); hw->d0i3_supported = ((reg & PCI_CFG_HFS_1_D0I3_MSK) == PCI_CFG_HFS_1_D0I3_MSK); + + hw->pg_state = MEI_PG_OFF; + if (hw->d0i3_supported) { + reg = mei_me_d0i3c_read(dev); + if (reg & H_D0I3C_I3) + hw->pg_state = MEI_PG_ON; + } } /** @@ -1037,12 +1042,24 @@ int mei_me_pg_exit_sync(struct mei_device *dev) * @dev: the device structure * @intr_enable: if interrupt should be enabled after reset. * - * Return: always 0 + * Return: 0 on success an error code otherwise */ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) { - u32 hcsr = mei_hcsr_read(dev); + struct mei_me_hw *hw = to_me_hw(dev); + int ret; + u32 hcsr; + + if (intr_enable) { + mei_me_intr_enable(dev); + if (hw->d0i3_supported) { + ret = mei_me_d0i3_exit_sync(dev); + if (ret) + return ret; + } + } + hcsr = mei_hcsr_read(dev); /* H_RST may be found lit before reset is started, * for example if preceding reset flow hasn't completed. * In that case asserting H_RST will be ignored, therefore @@ -1057,9 +1074,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) hcsr |= H_RST | H_IG | H_CSR_IS_MASK; - if (intr_enable) - hcsr |= H_CSR_IE_MASK; - else + if (!intr_enable) hcsr &= ~H_CSR_IE_MASK; dev->recvd_hw_ready = false; @@ -1077,9 +1092,14 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) if ((hcsr & H_RDY) == H_RDY) dev_warn(dev->dev, "H_RDY is not cleared 0x%08X", hcsr); - if (intr_enable == false) + if (!intr_enable) { mei_me_hw_reset_release(dev); - + if (hw->d0i3_supported) { + ret = mei_me_d0i3_enter(dev); + if (ret) + return ret; + } + } return 0; } -- cgit v1.3-6-gb490 From 1625c7ec96942b87eee1463aed6ec0595698b931 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 2 Aug 2015 22:20:57 +0300 Subject: mei: me: add sunrise point device ids Add MEI devices ids for Intel Sunrisepoint Skylake (PCH) Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 4 ++++ drivers/misc/mei/pci-me.c | 5 +++++ 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 8793ccca12ad..a8a68acd3267 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -117,6 +117,10 @@ #define MEI_DEV_ID_WPT_LP 0x9CBA /* Wildcat Point LP */ #define MEI_DEV_ID_WPT_LP_2 0x9CBB /* Wildcat Point LP 2 */ +#define MEI_DEV_ID_SPT 0x9D3A /* Sunrise Point */ +#define MEI_DEV_ID_SPT_2 0x9D3B /* Sunrise Point 2 */ +#define MEI_DEV_ID_SPT_H 0xA13A /* Sunrise Point H */ +#define MEI_DEV_ID_SPT_H_2 0xA13B /* Sunrise Point H 2 */ /* * MEI HW Section */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 7fee74abbc21..27678d8154e0 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -82,6 +82,11 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP, mei_me_pch8_cfg)}, {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP_2, mei_me_pch8_cfg)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT, mei_me_pch8_cfg)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, mei_me_pch8_cfg)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, mei_me_pch8_cfg)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, mei_me_pch8_cfg)}, + /* required last entry */ {0, } }; -- cgit v1.3-6-gb490 From 155718cfd1dd1a92b7dbf84db41fe15f6b219cc0 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 2 Aug 2015 22:20:58 +0300 Subject: mei: hbm: bump supported HBM version to 2.0 HBM 2.0 version for Sunrise point Skylake (PCH) based devices Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index ad6fbcb27f43..4cebde85924f 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -38,8 +38,8 @@ /* * MEI Version */ -#define HBM_MINOR_VERSION 1 -#define HBM_MAJOR_VERSION 1 +#define HBM_MINOR_VERSION 0 +#define HBM_MAJOR_VERSION 2 /* * MEI version with PGI support -- cgit v1.3-6-gb490 From 2ae0751007cdf2deaa87e160f28c50a00b478883 Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Mon, 3 Aug 2015 13:44:30 +0200 Subject: Staging: most: avoid possible integer overflow This patch prevents a potential integer overlow. Reported-by: Dan Carpenter Signed-off-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/mostcore/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/most/mostcore/core.c b/drivers/staging/most/mostcore/core.c index f872dc0bc118..f4fea8cf5560 100644 --- a/drivers/staging/most/mostcore/core.c +++ b/drivers/staging/most/mostcore/core.c @@ -1260,7 +1260,7 @@ int arm_mbo_chain(struct most_c_obj *c, int dir, void (*compl)(struct mbo *)) unsigned int i; int retval; struct mbo *mbo; - u16 coherent_buf_size = c->cfg.buffer_size + c->cfg.extra_len; + u32 coherent_buf_size = c->cfg.buffer_size + c->cfg.extra_len; atomic_set(&c->mbo_nq_level, 0); -- cgit v1.3-6-gb490 From f8ff8db038273c9b356c64857f396f037adaefca Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 3 Aug 2015 11:35:47 -0700 Subject: staging: most: fix aim-sound build errors Fix build errors: driver uses snd_pcm*() interfaces, so select SND_PCM. drivers/built-in.o: In function `audio_rx_completion': sound.c:(.text+0x3cd376): undefined reference to `snd_pcm_period_elapsed' drivers/built-in.o: In function `pcm_prepare': sound.c:(.text+0x3cd3b0): undefined reference to `snd_pcm_format_physical_width' sound.c:(.text+0x3cd3ce): undefined reference to `snd_pcm_format_big_endian' sound.c:(.text+0x3cd42c): undefined reference to `snd_pcm_format_big_endian' drivers/built-in.o: In function `pcm_hw_free': sound.c:(.text+0x3cd50a): undefined reference to `snd_pcm_lib_free_vmalloc_buffer' drivers/built-in.o: In function `pcm_hw_params': sound.c:(.text+0x3cd54c): undefined reference to `_snd_pcm_lib_alloc_vmalloc_buffer' drivers/built-in.o: In function `playback_thread': sound.c:(.text+0x3cd6a0): undefined reference to `snd_pcm_period_elapsed' drivers/built-in.o: In function `audio_probe_channel': sound.c:(.text+0x3cdc0b): undefined reference to `snd_pcm_new' sound.c:(.text+0x3cdc2b): undefined reference to `snd_pcm_set_ops' drivers/built-in.o:(.data+0x952d0): undefined reference to `snd_pcm_lib_ioctl' drivers/built-in.o:(.data+0x95318): undefined reference to `snd_pcm_lib_get_vmalloc_page' Signed-off-by: Randy Dunlap Acked-by: Christian Gromm Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/aim-sound/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/most/aim-sound/Kconfig b/drivers/staging/most/aim-sound/Kconfig index b9e499c77d00..3194c219ff14 100644 --- a/drivers/staging/most/aim-sound/Kconfig +++ b/drivers/staging/most/aim-sound/Kconfig @@ -5,6 +5,7 @@ config AIM_SOUND tristate "ALSA AIM" depends on SND + select SND_PCM ---help--- Say Y here if you want to commumicate via ALSA/sound devices. -- cgit v1.3-6-gb490 From bc7ac432536710193adfb7a05488f8c2e20fbbc2 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 3 Aug 2015 11:35:51 -0700 Subject: staging: most: fix hdm-dim2 build error Fix build of hdm-dim2. Since it calls a function that is provided by AIM_NETWORK, make it depend on that symbol. Also fix a misspelling in the Kconfig file. drivers/built-in.o: In function `deliver_netinfo_thread': dim2_hdm.c:(.text+0x3a9563): undefined reference to `most_deliver_netinfo' Signed-off-by: Randy Dunlap Cc: Jain Roy Ambi Cc: Andrey Shvetsov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/hdm-dim2/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/most/hdm-dim2/Kconfig b/drivers/staging/most/hdm-dim2/Kconfig index 4abeb545955e..1d4ad1d67758 100644 --- a/drivers/staging/most/hdm-dim2/Kconfig +++ b/drivers/staging/most/hdm-dim2/Kconfig @@ -4,9 +4,10 @@ config HDM_DIM2 tristate "DIM2 HDM" + depends on AIM_NETWORK ---help--- - Say Y here if you want to connect via MediaLB to network tranceiver. + Say Y here if you want to connect via MediaLB to network transceiver. This device driver is platform dependent and needs an addtional platform driver to be installed. For more information contact maintainer of this driver. -- cgit v1.3-6-gb490 From ad6d8812aa9574b11d5f7a0d322d3b42be24206d Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Thu, 30 Jul 2015 19:55:01 +0200 Subject: staging: fbtft: core: Don't set device platform_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass platform_data as an argument to fbtft_framebuffer_alloc() instead of using dev->platform_data. This fixes an issue where the device comes from Device Tree and fbtft_probe_common() sets dev->platform_data to allocated memory. When the module is reloaded, dev->platform_data points to freed memory. Signed-off-by: Noralf Trønnes Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/fbtft-core.c | 12 +++++------- drivers/staging/fbtft/fbtft.h | 5 +++-- drivers/staging/fbtft/flexfb.c | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index f04128fb0693..23392eb6799e 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -677,13 +677,13 @@ static void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src) * */ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, - struct device *dev) + struct device *dev, + struct fbtft_platform_data *pdata) { struct fb_info *info; struct fbtft_par *par; struct fb_ops *fbops = NULL; struct fb_deferred_io *fbdefio = NULL; - struct fbtft_platform_data *pdata = dev->platform_data; u8 *vmem = NULL; void *txbuf = NULL; void *buf = NULL; @@ -828,7 +828,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, par = info->par; par->info = info; - par->pdata = dev->platform_data; + par->pdata = pdata; par->debug = display->debug; par->buf = buf; spin_lock_init(&par->dirty_lock); @@ -1265,12 +1265,11 @@ EXPORT_SYMBOL(fbtft_init_display); */ static int fbtft_verify_gpios(struct fbtft_par *par) { - struct fbtft_platform_data *pdata; + struct fbtft_platform_data *pdata = par->pdata; int i; fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__); - pdata = par->info->device->platform_data; if (pdata->display.buswidth != 9 && par->startbyte == 0 && par->gpio.dc < 0) { dev_err(par->info->device, @@ -1388,10 +1387,9 @@ int fbtft_probe_common(struct fbtft_display *display, pdata = fbtft_probe_dt(dev); if (IS_ERR(pdata)) return PTR_ERR(pdata); - dev->platform_data = pdata; } - info = fbtft_framebuffer_alloc(display, dev); + info = fbtft_framebuffer_alloc(display, dev, pdata); if (!info) return -ENOMEM; diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h index 7d817eb26eab..ab4a65818786 100644 --- a/drivers/staging/fbtft/fbtft.h +++ b/drivers/staging/fbtft/fbtft.h @@ -264,8 +264,9 @@ struct fbtft_par { /* fbtft-core.c */ extern void fbtft_dbg_hex(const struct device *dev, int groupsize, void *buf, size_t len, const char *fmt, ...); -extern struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, - struct device *dev); +struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, + struct device *dev, + struct fbtft_platform_data *pdata); extern void fbtft_framebuffer_release(struct fb_info *info); extern int fbtft_register_framebuffer(struct fb_info *fb_info); extern int fbtft_unregister_framebuffer(struct fb_info *fb_info); diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c index ce6e3ae30a2e..5b4c7124a6ee 100644 --- a/drivers/staging/fbtft/flexfb.c +++ b/drivers/staging/fbtft/flexfb.c @@ -379,7 +379,7 @@ static int flexfb_probe_common(struct spi_device *sdev, fbtft_init_dbg(dev, "regwidth = %d\n", regwidth); fbtft_init_dbg(dev, "buswidth = %d\n", buswidth); - info = fbtft_framebuffer_alloc(&flex_display, dev); + info = fbtft_framebuffer_alloc(&flex_display, dev, dev->platform_data); if (!info) return -ENOMEM; -- cgit v1.3-6-gb490 From 24b7d011a65042a8bd2f3b93c812c7eae3ead2d8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 2 Aug 2015 11:09:52 +0200 Subject: staging: fbtft: Allow compile test of GPIO consumers if !GPIOLIB The GPIO subsystem provides dummy GPIO consumer functions if GPIOLIB is not enabled. Hence drivers that depend on GPIOLIB, but use GPIO consumer functionality only, can still be compiled if GPIOLIB is not enabled. Relax the dependency on GPIOLIB if COMPILE_TEST is enabled, where appropriate. Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig index f7e68fdd9904..d473010fa474 100644 --- a/drivers/staging/fbtft/Kconfig +++ b/drivers/staging/fbtft/Kconfig @@ -1,6 +1,7 @@ menuconfig FB_TFT tristate "Support for small TFT LCD display modules" - depends on FB && SPI && GPIOLIB + depends on FB && SPI + depends on GPIOLIB || COMPILE_TEST select FB_SYS_FILLRECT select FB_SYS_COPYAREA select FB_SYS_IMAGEBLIT -- cgit v1.3-6-gb490 From fd93b8059294146a1c3dc9cf6b5616c22b7b47f7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 2 Aug 2015 11:09:51 +0200 Subject: staging: android: Allow compile test of GPIO consumers if !GPIOLIB The GPIO subsystem provides dummy GPIO consumer functions if GPIOLIB is not enabled. Hence drivers that depend on GPIOLIB, but use GPIO consumer functionality only, can still be compiled if GPIOLIB is not enabled. Relax the dependency on GPIOLIB if COMPILE_TEST is enabled, where appropriate. Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 24d657b3ab99..68307121c9c1 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -20,7 +20,8 @@ config ANDROID_TIMED_OUTPUT config ANDROID_TIMED_GPIO tristate "Android timed gpio driver" - depends on GPIOLIB && ANDROID_TIMED_OUTPUT + depends on GPIOLIB || COMPILE_TEST + depends on ANDROID_TIMED_OUTPUT default n ---help--- Unlike generic gpio is to allow programs to access and manipulate gpio -- cgit v1.3-6-gb490 From fdc792cd1b5c86cb34770707aa1b04edce5288cf Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 31 Jul 2015 18:56:32 -0400 Subject: staging: unisys: visorchannel: Add peek function According to unisys, the s_par hypervisor has a bug in which it never triggers an interrupt. That makes the visornic effectively a 2ms poll loop. In order to just have the rx thread shceduling a napi poll every 2ms, lets instead give it the chance to check the response queue for data before we schedule. This helper provides that functionality Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/include/visorbus.h | 2 ++ drivers/staging/unisys/visorbus/visorchannel.c | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/unisys/include/visorbus.h b/drivers/staging/unisys/include/visorbus.h index a0144c6a8ad1..9235536fa75f 100644 --- a/drivers/staging/unisys/include/visorbus.h +++ b/drivers/staging/unisys/include/visorbus.h @@ -201,6 +201,8 @@ bool visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg); bool visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg); +bool visorchannel_signalempty(struct visorchannel *channel, u32 queue); + int visorchannel_signalqueue_slots_avail(struct visorchannel *channel, u32 queue); int visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue); diff --git a/drivers/staging/unisys/visorbus/visorchannel.c b/drivers/staging/unisys/visorbus/visorchannel.c index 242246492b7a..6da7e49a6627 100644 --- a/drivers/staging/unisys/visorbus/visorchannel.c +++ b/drivers/staging/unisys/visorbus/visorchannel.c @@ -430,6 +430,27 @@ visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg) } EXPORT_SYMBOL_GPL(visorchannel_signalremove); +bool +visorchannel_signalempty(struct visorchannel *channel, u32 queue) +{ + unsigned long flags = 0; + struct signal_queue_header sig_hdr; + bool rc = false; + + if (channel->needs_lock) + spin_lock_irqsave(&channel->remove_lock, flags); + + if (!sig_read_header(channel, queue, &sig_hdr)) + rc = true; + if (sig_hdr.head == sig_hdr.tail) + rc = true; + if (channel->needs_lock) + spin_unlock_irqrestore(&channel->remove_lock, flags); + + return rc; +} +EXPORT_SYMBOL_GPL(visorchannel_signalempty); + static bool signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg) { -- cgit v1.3-6-gb490 From 08582d83e5a23aa2f6316421a4f14a44be3c8e32 Mon Sep 17 00:00:00 2001 From: Mateusz Kulikowski Date: Thu, 30 Jul 2015 23:48:50 +0200 Subject: staging: rtl8192e: Rework EEPROM handling code Card configuration is stored in SPI EEPROM (93c46 or 93c56) working in 128|256x16 mode. Communication is handled using GPIO bitbang. >From behaviour perspective, delay after read was removed. It is not needed as we wait after reading GPIO mapped to PCI-E register - it should have no side effects. According to sample EEPROM datasheet (AT93Cx6), max frequency for worst case scenario (1.8V supply) is 250kHZ (vs. 1MHz for 5V). Driver generates ~50kHZ clock - margin should be big enough even for devices from other vendors. Signed-off-by: Mateusz Kulikowski Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h | 8 +- drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c | 120 ++++++++----------------- 2 files changed, 43 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h index 43c3fb859d10..c81832dcf181 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_hw.h @@ -119,10 +119,10 @@ enum _RTL8192Pci_HW { #define EPROM_CMD_NORMAL 0 #define EPROM_CMD_LOAD 1 #define EPROM_CMD_PROGRAM 2 -#define EPROM_CS_SHIFT 3 -#define EPROM_CK_SHIFT 2 -#define EPROM_W_SHIFT 1 -#define EPROM_R_SHIFT 0 +#define EPROM_CS_BIT 3 +#define EPROM_CK_BIT 2 +#define EPROM_W_BIT 1 +#define EPROM_R_BIT 0 AFR = 0x010, #define AFR_CardBEn (1<<0) diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c index ed54193b019a..039ccfd41230 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_eeprom.c @@ -25,115 +25,73 @@ #include "rtl_core.h" #include "rtl_eeprom.h" -static void eprom_cs(struct net_device *dev, short bit) +static void _rtl92e_gpio_write_bit(struct net_device *dev, int no, bool val) { - if (bit) - rtl92e_writeb(dev, EPROM_CMD, - (1 << EPROM_CS_SHIFT) | - rtl92e_readb(dev, EPROM_CMD)); + u8 reg = rtl92e_readb(dev, EPROM_CMD); + + if (val) + reg |= 1 << no; else - rtl92e_writeb(dev, EPROM_CMD, - rtl92e_readb(dev, EPROM_CMD) & - ~(1<> no) & 0x1; +} -static void eprom_w(struct net_device *dev, short bit) +static void _rtl92e_eeprom_ck_cycle(struct net_device *dev) { - if (bit) - rtl92e_writeb(dev, EPROM_CMD, (1<> tx_len) & 0x1); + _rtl92e_eeprom_ck_cycle(dev); + } -static void eprom_send_bits_string(struct net_device *dev, short b[], int len) -{ - int i; + _rtl92e_gpio_write_bit(dev, EPROM_W_BIT, 0); - for (i = 0; i < len; i++) { - eprom_w(dev, b[i]); - eprom_ck_cycle(dev); + while (rx_len--) { + _rtl92e_eeprom_ck_cycle(dev); + ret |= _rtl92e_gpio_get_bit(dev, EPROM_R_BIT) << rx_len; } + + _rtl92e_gpio_write_bit(dev, EPROM_CS_BIT, 0); + _rtl92e_eeprom_ck_cycle(dev); + + return ret; } u32 rtl92e_eeprom_read(struct net_device *dev, u32 addr) { struct r8192_priv *priv = rtllib_priv(dev); - short read_cmd[] = {1, 1, 0}; - short addr_str[8]; - int i; - int addr_len; - u32 ret; + u32 ret = 0; - ret = 0; rtl92e_writeb(dev, EPROM_CMD, (EPROM_CMD_PROGRAM << EPROM_CMD_OPERATING_MODE_SHIFT)); udelay(EPROM_DELAY); - if (priv->epromtype == EEPROM_93C56) { - addr_str[7] = addr & 1; - addr_str[6] = addr & (1<<1); - addr_str[5] = addr & (1<<2); - addr_str[4] = addr & (1<<3); - addr_str[3] = addr & (1<<4); - addr_str[2] = addr & (1<<5); - addr_str[1] = addr & (1<<6); - addr_str[0] = addr & (1<<7); - addr_len = 8; - } else { - addr_str[5] = addr & 1; - addr_str[4] = addr & (1<<1); - addr_str[3] = addr & (1<<2); - addr_str[2] = addr & (1<<3); - addr_str[1] = addr & (1<<4); - addr_str[0] = addr & (1<<5); - addr_len = 6; - } - eprom_cs(dev, 1); - eprom_ck_cycle(dev); - eprom_send_bits_string(dev, read_cmd, 3); - eprom_send_bits_string(dev, addr_str, addr_len); - - eprom_w(dev, 0); - - for (i = 0; i < 16; i++) { - eprom_ck_cycle(dev); - ret |= (eprom_r(dev)<<(15-i)); - } - - eprom_cs(dev, 0); - eprom_ck_cycle(dev); + /* EEPROM is configured as x16 */ + if (priv->epromtype == EEPROM_93C56) + ret = _rtl92e_eeprom_xfer(dev, (addr & 0xFF) | (0x6 << 8), 11); + else + ret = _rtl92e_eeprom_xfer(dev, (addr & 0x3F) | (0x6 << 6), 9); rtl92e_writeb(dev, EPROM_CMD, (EPROM_CMD_NORMAL< Date: Fri, 31 Jul 2015 19:42:54 -0400 Subject: staging/lustre: Drop SEEK_* definition checks SEEK_DATA and SEEK_HOLE are always defined in the kernel, drop the definition checks Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index f16ba9c8b214..502c7cce7e27 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -121,13 +121,6 @@ static inline int ll_quota_off(struct super_block *sb, int off, int remount) # define NO_QUOTA (-EDQUOT) #endif -#ifndef SEEK_DATA -#define SEEK_DATA 3 /* seek to the next data */ -#endif -#ifndef SEEK_HOLE -#define SEEK_HOLE 4 /* seek to the next hole */ -#endif - #ifndef FMODE_UNSIGNED_OFFSET #define FMODE_UNSIGNED_OFFSET ((__force fmode_t)0x2000) #endif -- cgit v1.3-6-gb490 From 1a3555cd3245b3204189a1118364ad41467b73ca Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Fri, 31 Jul 2015 19:42:55 -0400 Subject: staging/lustre: remove unused ll_quota_on and ll_quota_off They are not used anywhere, so safe to drop. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- .../lustre/lustre/include/linux/lustre_compat25.h | 31 ---------------------- 1 file changed, 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 502c7cce7e27..9739611091aa 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -69,37 +69,6 @@ # define inode_dio_read(i) atomic_inc(&(i)->i_dio_count) /* inode_dio_done(i) use as-is for read unlock */ -static inline int -ll_quota_on(struct super_block *sb, int off, int ver, char *name, int remount) -{ - int rc; - - if (sb->s_qcop->quota_on) { - struct path path; - - rc = kern_path(name, LOOKUP_FOLLOW, &path); - if (!rc) - return rc; - rc = sb->s_qcop->quota_on(sb, off, ver - , &path - ); - path_put(&path); - return rc; - } else - return -ENOSYS; -} - -static inline int ll_quota_off(struct super_block *sb, int off, int remount) -{ - if (sb->s_qcop->quota_off) { - return sb->s_qcop->quota_off(sb, off - ); - } else - return -ENOSYS; -} - - - #define ll_d_hlist_node hlist_node #define ll_d_hlist_empty(list) hlist_empty(list) #define ll_d_hlist_entry(ptr, type, name) hlist_entry(ptr.first, type, name) -- cgit v1.3-6-gb490 From 56ea686bb749d06bdb67cb95a873a87c5d1fc243 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Fri, 31 Jul 2015 19:42:56 -0400 Subject: staging/lustre: Drop FMODE_UNSIGNED_OFFSET define It's not really used anywhere. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 9739611091aa..b37856c66f03 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -90,10 +90,6 @@ # define NO_QUOTA (-EDQUOT) #endif -#ifndef FMODE_UNSIGNED_OFFSET -#define FMODE_UNSIGNED_OFFSET ((__force fmode_t)0x2000) -#endif - #if !defined(_ASM_GENERIC_BITOPS_EXT2_NON_ATOMIC_H_) && !defined(ext2_set_bit) # define ext2_set_bit __test_and_set_bit_le # define ext2_clear_bit __test_and_clear_bit_le -- cgit v1.3-6-gb490 From 9d5be52f985b3d0b0b6d0dcae8eb896418bd0d3a Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Fri, 31 Jul 2015 19:42:57 -0400 Subject: staging/lustre: Use hlist primitives directly Get rid of ll_d_hlist* compat defines. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 9 --------- drivers/staging/lustre/lustre/llite/dcache.c | 3 +-- drivers/staging/lustre/lustre/llite/namei.c | 10 ++++------ 3 files changed, 5 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index b37856c66f03..43fa2a954f03 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -69,15 +69,6 @@ # define inode_dio_read(i) atomic_inc(&(i)->i_dio_count) /* inode_dio_done(i) use as-is for read unlock */ -#define ll_d_hlist_node hlist_node -#define ll_d_hlist_empty(list) hlist_empty(list) -#define ll_d_hlist_entry(ptr, type, name) hlist_entry(ptr.first, type, name) -#define ll_d_hlist_for_each(tmp, i_dentry) hlist_for_each(tmp, i_dentry) -#define ll_d_hlist_for_each_entry(dentry, p, i_dentry, alias) \ - p = NULL; hlist_for_each_entry(dentry, i_dentry, alias) - - - #define ll_pagevec_init(pv, cold) do {} while (0) #define ll_pagevec_add(pv, pg) (0) #define ll_pagevec_lru_add_file(pv) do {} while (0) diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index 7b008a64707d..b86685912d28 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -250,7 +250,6 @@ void ll_intent_release(struct lookup_intent *it) void ll_invalidate_aliases(struct inode *inode) { struct dentry *dentry; - struct ll_d_hlist_node *p; LASSERT(inode != NULL); @@ -258,7 +257,7 @@ void ll_invalidate_aliases(struct inode *inode) inode->i_ino, inode->i_generation, inode); ll_lock_dcache(inode); - ll_d_hlist_for_each_entry(dentry, p, &inode->i_dentry, d_u.d_alias) { + hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { CDEBUG(D_DENTRY, "dentry in drop %pd (%p) parent %p inode %p flags %d\n", dentry, dentry, dentry->d_parent, d_inode(dentry), dentry->d_flags); diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 2ed1e0ac5553..05e7dc85989e 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -144,10 +144,9 @@ struct inode *ll_iget(struct super_block *sb, ino_t hash, static void ll_invalidate_negative_children(struct inode *dir) { struct dentry *dentry, *tmp_subdir; - struct ll_d_hlist_node *p; ll_lock_dcache(dir); - ll_d_hlist_for_each_entry(dentry, p, &dir->i_dentry, d_u.d_alias) { + hlist_for_each_entry(dentry, &dir->i_dentry, d_u.d_alias) { spin_lock(&dentry->d_lock); if (!list_empty(&dentry->d_subdirs)) { struct dentry *child; @@ -334,15 +333,14 @@ void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2) static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry) { struct dentry *alias, *discon_alias, *invalid_alias; - struct ll_d_hlist_node *p; - if (ll_d_hlist_empty(&inode->i_dentry)) + if (hlist_empty(&inode->i_dentry)) return NULL; discon_alias = invalid_alias = NULL; ll_lock_dcache(inode); - ll_d_hlist_for_each_entry(alias, p, &inode->i_dentry, d_u.d_alias) { + hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { LASSERT(alias != dentry); spin_lock(&alias->d_lock); @@ -690,7 +688,7 @@ static struct inode *ll_create_node(struct inode *dir, struct lookup_intent *it) goto out; } - LASSERT(ll_d_hlist_empty(&inode->i_dentry)); + LASSERT(hlist_empty(&inode->i_dentry)); /* We asked for a lock on the directory, but were granted a * lock on the inode. Since we finally have an inode pointer, -- cgit v1.3-6-gb490 From 66a23f0cc28b6257328aa2e17499a1f3bd0bd18d Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Fri, 31 Jul 2015 19:42:58 -0400 Subject: staging/lustre: Get rid of ll_pagevec_ macros They are noop anyways. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 5 ----- drivers/staging/lustre/lustre/llite/dir.c | 4 ---- 2 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 43fa2a954f03..157bafb08a5b 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -69,11 +69,6 @@ # define inode_dio_read(i) atomic_inc(&(i)->i_dio_count) /* inode_dio_done(i) use as-is for read unlock */ -#define ll_pagevec_init(pv, cold) do {} while (0) -#define ll_pagevec_add(pv, pg) (0) -#define ll_pagevec_lru_add_file(pv) do {} while (0) - - #ifndef QUOTA_OK # define QUOTA_OK 0 #endif diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 3d746a94f92e..769b61193d87 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -203,7 +203,6 @@ static int ll_dir_filler(void *_hash, struct page *page0) CDEBUG(D_VFSTRACE, "read %d/%d pages\n", nrdpgs, npages); - ll_pagevec_init(&lru_pvec, 0); for (i = 1; i < npages; i++) { unsigned long offset; int ret; @@ -228,15 +227,12 @@ static int ll_dir_filler(void *_hash, struct page *page0) GFP_KERNEL); if (ret == 0) { unlock_page(page); - if (ll_pagevec_add(&lru_pvec, page) == 0) - ll_pagevec_lru_add_file(&lru_pvec); } else { CDEBUG(D_VFSTRACE, "page %lu add to page cache failed: %d\n", offset, ret); } page_cache_release(page); } - ll_pagevec_lru_add_file(&lru_pvec); if (page_pool != &page0) kfree(page_pool); -- cgit v1.3-6-gb490 From 81e053c75a216573bbb10a0325832ca64bcb0404 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Fri, 31 Jul 2015 19:42:59 -0400 Subject: staging/lustre: Get rid of inode_dio_write_done and inode_dio_read These primitives are long deprecated and unused. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/linux/lustre_compat25.h | 5 ----- drivers/staging/lustre/lustre/llite/llite_lib.c | 5 +---- drivers/staging/lustre/lustre/llite/vvp_io.c | 5 ++--- 3 files changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h index 157bafb08a5b..6b14406b2920 100644 --- a/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h +++ b/drivers/staging/lustre/lustre/include/linux/lustre_compat25.h @@ -64,11 +64,6 @@ #define LTIME_S(time) (time.tv_sec) -/* inode_dio_wait(i) use as-is for write lock */ -# define inode_dio_write_done(i) do {} while (0) /* for write unlock */ -# define inode_dio_read(i) atomic_inc(&(i)->i_dio_count) -/* inode_dio_done(i) use as-is for read unlock */ - #ifndef QUOTA_OK # define QUOTA_OK 0 #endif diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 39f0b2a07aec..55e2dc6c1fbf 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -1356,11 +1356,8 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, bool hsm_import) if (!op_data) return -ENOMEM; - if (!S_ISDIR(inode->i_mode)) { - if (attr->ia_valid & ATTR_SIZE) - inode_dio_write_done(inode); + if (!S_ISDIR(inode->i_mode)) mutex_unlock(&inode->i_mutex); - } memcpy(&op_data->op_attr, attr, sizeof(*attr)); diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c index 91bba79678cf..a659962e09c8 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_io.c +++ b/drivers/staging/lustre/lustre/llite/vvp_io.c @@ -455,12 +455,11 @@ static void vvp_io_setattr_end(const struct lu_env *env, struct cl_io *io = ios->cis_io; struct inode *inode = ccc_object_inode(io->ci_obj); - if (cl_io_is_trunc(io)) { + if (cl_io_is_trunc(io)) /* Truncate in memory pages - they must be clean pages * because osc has already notified to destroy osc_extents. */ vvp_do_vmtruncate(inode, io->u.ci_setattr.sa_attr.lvb_size); - inode_dio_write_done(inode); - } + mutex_unlock(&inode->i_mutex); } -- cgit v1.3-6-gb490 From 5bb546f755380aa5129e480fb0cf04c0655ce13a Mon Sep 17 00:00:00 2001 From: Kent Gustavsson Date: Sun, 2 Aug 2015 18:14:50 +0200 Subject: staging: rtl8192u: r819xU_firmware: fix coding style Line over 80 characters. This is for Eudyptula Challenge Signed-off-by: Kent Gustavsson Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/r819xU_firmware.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c index a7d30339390b..08302dfb0d90 100644 --- a/drivers/staging/rtl8192u/r819xU_firmware.c +++ b/drivers/staging/rtl8192u/r819xU_firmware.c @@ -144,7 +144,8 @@ static bool CPUcheck_maincodeok_turnonCPU(struct net_device *dev) /* Turn On CPU */ read_nic_dword(dev, CPU_GEN, &CPU_status); - write_nic_byte(dev, CPU_GEN, (u8)((CPU_status|CPU_GEN_PWR_STB_CPU)&0xff)); + write_nic_byte(dev, CPU_GEN, + (u8)((CPU_status | CPU_GEN_PWR_STB_CPU) & 0xff)); mdelay(1000); /* Check whether CPU boot OK */ -- cgit v1.3-6-gb490 From 5b34cd299319584f9fd342a5c01af83440d512bd Mon Sep 17 00:00:00 2001 From: Zoltán Lajos Kis Date: Sun, 2 Aug 2015 19:22:30 +0200 Subject: staging: lustre: echo_client: fix sparse declaration warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following sparse warnings: drivers/staging/lustre/lustre/obdecho/echo_client.c:2142:5: warning: symbol 'echo_client_init' was not declared. Should it be static? drivers/staging/lustre/lustre/obdecho/echo_client.c:2157:6: warning: symbol 'echo_client_exit' was not declared. Should it be static? Signed-off-by: Zoltán Lajos Kis " Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdecho/echo_client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c index de6f795e05d1..27bd170c3a28 100644 --- a/drivers/staging/lustre/lustre/obdecho/echo_client.c +++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c @@ -2139,7 +2139,7 @@ static struct obd_ops echo_client_obd_ops = { .o_disconnect = echo_client_disconnect }; -int echo_client_init(void) +static int echo_client_init(void) { int rc; @@ -2154,7 +2154,7 @@ int echo_client_init(void) return rc; } -void echo_client_exit(void) +static void echo_client_exit(void) { class_unregister_type(LUSTRE_ECHO_CLIENT_NAME); lu_kmem_fini(echo_caches); -- cgit v1.3-6-gb490 From a96389d9add1bc9e32b73ead10cf255f7d598a0d Mon Sep 17 00:00:00 2001 From: Zoltán Lajos Kis Date: Sun, 2 Aug 2015 22:36:31 +0200 Subject: staging: lustre: service.c: make local functions static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes functions that are not used outside the file in which they are defined static, as reported by sparse: drivers/staging/lustre/lustre/ptlrpc/service.c:72:35: warning: symbol 'ptlrpc_alloc_rqbd' was not declared. Should it be static? 1065 drivers/staging/lustre/lustre/ptlrpc/service.c:105:1: warning: symbol 'ptlrpc_free_rqbd' was not declared. Should it be static? 1066 drivers/staging/lustre/lustre/ptlrpc/service.c:122:1: warning: symbol 'ptlrpc_grow_req_bufs' was not declared. Should it be static? 1067 drivers/staging/lustre/lustre/ptlrpc/service.c:3055:5: warning: symbol 'ptlrpc_svcpt_health_check' was not declared. Should it be static? Signed-off-by: Zoltán Lajos Kis " Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ptlrpc/service.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c index cf9477d4749b..d3265a89538a 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/service.c +++ b/drivers/staging/lustre/lustre/ptlrpc/service.c @@ -69,7 +69,7 @@ LIST_HEAD(ptlrpc_all_services); /** Used to protect the \e ptlrpc_all_services list */ struct mutex ptlrpc_all_services_mutex; -struct ptlrpc_request_buffer_desc * +static struct ptlrpc_request_buffer_desc * ptlrpc_alloc_rqbd(struct ptlrpc_service_part *svcpt) { struct ptlrpc_service *svc = svcpt->scp_service; @@ -101,7 +101,7 @@ ptlrpc_alloc_rqbd(struct ptlrpc_service_part *svcpt) return rqbd; } -void +static void ptlrpc_free_rqbd(struct ptlrpc_request_buffer_desc *rqbd) { struct ptlrpc_service_part *svcpt = rqbd->rqbd_svcpt; @@ -118,7 +118,7 @@ ptlrpc_free_rqbd(struct ptlrpc_request_buffer_desc *rqbd) kfree(rqbd); } -int +static int ptlrpc_grow_req_bufs(struct ptlrpc_service_part *svcpt, int post) { struct ptlrpc_service *svc = svcpt->scp_service; @@ -3052,7 +3052,7 @@ EXPORT_SYMBOL(ptlrpc_unregister_service); * Right now, it just checks to make sure that requests aren't languishing * in the queue. We'll use this health check to govern whether a node needs * to be shot, so it's intentionally non-aggressive. */ -int ptlrpc_svcpt_health_check(struct ptlrpc_service_part *svcpt) +static int ptlrpc_svcpt_health_check(struct ptlrpc_service_part *svcpt) { struct ptlrpc_request *request = NULL; struct timeval right_now; -- cgit v1.3-6-gb490 From 66e6d70df20046d3e2b04d9455dd68acfc5c61ef Mon Sep 17 00:00:00 2001 From: Yash Shah Date: Mon, 3 Aug 2015 11:18:31 +0000 Subject: Staging: rts5208: Fix code indentation warning as detected by checkpatch.pl Fixed code indentation warning as detected by checkpatch.pl. Signed-off-by: Yash Shah Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rts5208/ms.c | 5 ++--- drivers/staging/rts5208/sd.c | 10 ++++------ 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c index ee818b0dc401..cdaa1aba50ed 100644 --- a/drivers/staging/rts5208/ms.c +++ b/drivers/staging/rts5208/ms.c @@ -1121,11 +1121,10 @@ static int ms_read_attribute_info(struct rtsx_chip *chip) #ifdef SUPPORT_MSXC if ((buf[cur_addr_off + 8] == 0x10) || - (buf[cur_addr_off + 8] == 0x13)) + (buf[cur_addr_off + 8] == 0x13)) { #else - if (buf[cur_addr_off + 8] == 0x10) + if (buf[cur_addr_off + 8] == 0x10) { #endif - { sys_info_addr = ((u32)buf[cur_addr_off + 0] << 24) | ((u32)buf[cur_addr_off + 1] << 16) | ((u32)buf[cur_addr_off + 2] << 8) | diff --git a/drivers/staging/rts5208/sd.c b/drivers/staging/rts5208/sd.c index cb4157960fad..d6c498209b2c 100644 --- a/drivers/staging/rts5208/sd.c +++ b/drivers/staging/rts5208/sd.c @@ -246,11 +246,10 @@ RTY_SEND_CMD: } } #ifdef SUPPORT_SD_LOCK - if (ptr[1] & 0x7D) + if (ptr[1] & 0x7D) { #else - if (ptr[1] & 0x7F) + if (ptr[1] & 0x7F) { #endif - { dev_dbg(rtsx_dev(chip), "ptr[1]: 0x%02x\n", ptr[1]); rtsx_trace(chip); @@ -4148,11 +4147,10 @@ RTY_SEND_CMD: } } #ifdef SUPPORT_SD_LOCK - if (ptr[1] & 0x7D) + if (ptr[1] & 0x7D) { #else - if (ptr[1] & 0x7F) + if (ptr[1] & 0x7F) { #endif - { rtsx_trace(chip); return STATUS_FAIL; } -- cgit v1.3-6-gb490 From 4e0fa71c934287c160e264b3d5dd0e5c0824f6f9 Mon Sep 17 00:00:00 2001 From: Mayank Bareja Date: Mon, 3 Aug 2015 11:23:01 +0000 Subject: Staging: rtl8188eu/core: fixed code indentation warning as reported by checkpatch.pl fixed code indentation warning as detected with checkpatch.pl. Replaced spaces with tabs. Signed-off-by: Mayank Bareja Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_debug.c | 4 +-- drivers/staging/rtl8188eu/core/rtw_efuse.c | 2 +- drivers/staging/rtl8188eu/core/rtw_mlme.c | 4 +-- drivers/staging/rtl8188eu/core/rtw_mlme_ext.c | 8 +++--- drivers/staging/rtl8188eu/core/rtw_security.c | 2 +- drivers/staging/rtl8188eu/core/rtw_xmit.c | 36 +++++++++++++-------------- 6 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_debug.c b/drivers/staging/rtl8188eu/core/rtw_debug.c index 12beab046a4a..993c7db87a1a 100644 --- a/drivers/staging/rtl8188eu/core/rtw_debug.c +++ b/drivers/staging/rtl8188eu/core/rtw_debug.c @@ -919,7 +919,7 @@ int proc_get_best_channel(char *page, char **start, /* 5G */ if (pmlmeext->channel_set[i].ChannelNum >= 36 && pmlmeext->channel_set[i].ChannelNum < 140) { - /* Find primary channel */ + /* Find primary channel */ if (((pmlmeext->channel_set[i].ChannelNum - 36) % 8 == 0) && (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) { index_5G = i; @@ -929,7 +929,7 @@ int proc_get_best_channel(char *page, char **start, if (pmlmeext->channel_set[i].ChannelNum >= 149 && pmlmeext->channel_set[i].ChannelNum < 165) { - /* find primary channel */ + /* find primary channel */ if (((pmlmeext->channel_set[i].ChannelNum - 149) % 8 == 0) && (pmlmeext->channel_set[i].rx_count < pmlmeext->channel_set[index_5G].rx_count)) { index_5G = i; diff --git a/drivers/staging/rtl8188eu/core/rtw_efuse.c b/drivers/staging/rtl8188eu/core/rtw_efuse.c index dbaba2c6cce5..7b99ea91a9e6 100644 --- a/drivers/staging/rtl8188eu/core/rtw_efuse.c +++ b/drivers/staging/rtl8188eu/core/rtw_efuse.c @@ -551,7 +551,7 @@ int Efuse_PgPacketRead(struct adapter *pAdapter, u8 offset, u8 *data) bContinual = false; } } else if (ReadState & PG_STATE_DATA) { - /* Data section Read ------------- */ + /* Data section Read ------------- */ efuse_WordEnableDataRead(hworden, tmpdata, data); efuse_addr = efuse_addr + (word_cnts*2)+1; ReadState = PG_STATE_HEADER; diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index 71a7a85571aa..2b917a18e228 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -693,8 +693,8 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) pmlmepriv->to_join = false; s_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv); if (_SUCCESS == s_ret) { - mod_timer(&pmlmepriv->assoc_timer, - jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT)); + mod_timer(&pmlmepriv->assoc_timer, + jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT)); } else if (s_ret == 2) { /* there is no need to wait for join */ _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); rtw_indicate_connect(adapter); diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index ba8f9aa5d259..935b48eef8b1 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -1096,7 +1096,7 @@ static void issue_assocreq(struct adapter *padapter) /* Check if the AP's supported rates are also supported by STA. */ for (j = 0; j < sta_bssrate_len; j++) { - /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */ + /* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */ if ((pmlmeinfo->network.SupportedRates[i]|IEEE80211_BASIC_RATE_MASK) == (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)) break; @@ -2932,7 +2932,7 @@ static unsigned int OnAuthClient(struct adapter *padapter, if (seq == 2) { if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) { - /* legendary shared system */ + /* legendary shared system */ p = rtw_get_ie(pframe + WLAN_HDR_A3_LEN + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len, pkt_len - WLAN_HDR_A3_LEN - _AUTH_IE_OFFSET_); @@ -4155,8 +4155,8 @@ static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptabl u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; u8 *pframe = precv_frame->rx_data; - if (ptable->func) { - /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ + if (ptable->func) { + /* receive the frames that ra(a1) is my address or ra(a1) is bc address. */ if (memcmp(GetAddr1Ptr(pframe), myid(&padapter->eeprompriv), ETH_ALEN) && memcmp(GetAddr1Ptr(pframe), bc_addr, ETH_ALEN)) return; diff --git a/drivers/staging/rtl8188eu/core/rtw_security.c b/drivers/staging/rtl8188eu/core/rtw_security.c index d870a5ce8585..22839d57dc8c 100644 --- a/drivers/staging/rtl8188eu/core/rtw_security.c +++ b/drivers/staging/rtl8188eu/core/rtw_security.c @@ -1330,7 +1330,7 @@ static int aes_decipher(u8 *key, uint hdrlen, bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); for (j = 0; j < 16; j++) - pframe[payload_index++] = chain_buffer[j]; + pframe[payload_index++] = chain_buffer[j]; } if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c index fda169d37771..5dc0b90e8ab5 100644 --- a/drivers/staging/rtl8188eu/core/rtw_xmit.c +++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c @@ -868,7 +868,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr /* check if enable ampdu */ if (pattrib->ht_en && psta->htpriv.ampdu_enable) { if (psta->htpriv.agg_enable_bitmap & BIT(pattrib->priority)) - pattrib->ampdu_en = true; + pattrib->ampdu_en = true; } /* re-check if enable ampdu by BA_starting_seqctrl */ @@ -1026,22 +1026,22 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct /* adding icv, if necessary... */ if (pattrib->iv_len) { switch (pattrib->encrypt) { - case _WEP40_: - case _WEP104_: - WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); - break; - case _TKIP_: - if (bmcst) - TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); - else - TKIP_IV(pattrib->iv, psta->dot11txpn, 0); - break; - case _AES_: - if (bmcst) - AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); - else - AES_IV(pattrib->iv, psta->dot11txpn, 0); - break; + case _WEP40_: + case _WEP104_: + WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + break; + case _TKIP_: + if (bmcst) + TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + else + TKIP_IV(pattrib->iv, psta->dot11txpn, 0); + break; + case _AES_: + if (bmcst) + AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx); + else + AES_IV(pattrib->iv, psta->dot11txpn, 0); + break; } memcpy(pframe, pattrib->iv, pattrib->iv_len); @@ -1769,7 +1769,7 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra int bmcst = IS_MCAST(pattrib->ra); if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == false) - return ret; + return ret; if (pattrib->psta) psta = pattrib->psta; -- cgit v1.3-6-gb490 From d0a12625d2ff2c63321b3cf48c48184748ab577a Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Wed, 10 Jun 2015 13:34:24 -0700 Subject: thermal: Add Intel PCH thermal driver This change adds a thermal driver for Wildcat Point platform controller hub. This driver register PCH thermal sensor as a thermal zone and associate critical and hot trips if present. Signed-off-by: Tushar Dave Reviewed-by: Pandruvada, Srinivas Signed-off-by: Zhang Rui --- drivers/thermal/Kconfig | 8 + drivers/thermal/Makefile | 1 + drivers/thermal/intel_pch_thermal.c | 286 ++++++++++++++++++++++++++++++++++++ 3 files changed, 295 insertions(+) create mode 100644 drivers/thermal/intel_pch_thermal.c (limited to 'drivers') diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 118938ee8552..039004400987 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -340,6 +340,14 @@ config ACPI_THERMAL_REL tristate depends on ACPI +config INTEL_PCH_THERMAL + tristate "Intel PCH Thermal Reporting Driver" + depends on X86 && PCI + help + Enable this to support thermal reporting on certain intel PCHs. + Thermal reporting device will provide temperature reading, + programmable trip points and other information. + menu "Texas Instruments thermal drivers" source "drivers/thermal/ti-soc-thermal/Kconfig" endmenu diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 535dfee1496f..26f160809959 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o obj-$(CONFIG_INTEL_QUARK_DTS_THERMAL) += intel_quark_dts_thermal.o obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ +obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o obj-$(CONFIG_ST_THERMAL) += st/ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o diff --git a/drivers/thermal/intel_pch_thermal.c b/drivers/thermal/intel_pch_thermal.c new file mode 100644 index 000000000000..1650a62484bd --- /dev/null +++ b/drivers/thermal/intel_pch_thermal.c @@ -0,0 +1,286 @@ +/* intel_pch_thermal.c - Intel PCH Thermal driver + * + * Copyright (c) 2015, Intel Corporation. + * + * Authors: + * Tushar Dave + * + * 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 +#include +#include +#include + +/* Intel PCH thermal Device IDs */ +#define PCH_THERMAL_DID_WPT 0x9CA4 /* Wildcat Point */ + +/* Wildcat Point-LP PCH Thermal registers */ +#define WPT_TEMP 0x0000 /* Temperature */ +#define WPT_TSC 0x04 /* Thermal Sensor Control */ +#define WPT_TSS 0x06 /* Thermal Sensor Status */ +#define WPT_TSEL 0x08 /* Thermal Sensor Enable and Lock */ +#define WPT_TSREL 0x0A /* Thermal Sensor Report Enable and Lock */ +#define WPT_TSMIC 0x0C /* Thermal Sensor SMI Control */ +#define WPT_CTT 0x0010 /* Catastrophic Trip Point */ +#define WPT_TAHV 0x0014 /* Thermal Alert High Value */ +#define WPT_TALV 0x0018 /* Thermal Alert Low Value */ +#define WPT_TL 0x00000040 /* Throttle Value */ +#define WPT_PHL 0x0060 /* PCH Hot Level */ +#define WPT_PHLC 0x62 /* PHL Control */ +#define WPT_TAS 0x80 /* Thermal Alert Status */ +#define WPT_TSPIEN 0x82 /* PCI Interrupt Event Enables */ +#define WPT_TSGPEN 0x84 /* General Purpose Event Enables */ + +/* Wildcat Point-LP PCH Thermal Register bit definitions */ +#define WPT_TEMP_TSR 0x00ff /* Temp TS Reading */ +#define WPT_TSC_CPDE 0x01 /* Catastrophic Power-Down Enable */ +#define WPT_TSS_TSDSS 0x10 /* Thermal Sensor Dynamic Shutdown Status */ +#define WPT_TSS_GPES 0x08 /* GPE status */ +#define WPT_TSEL_ETS 0x01 /* Enable TS */ +#define WPT_TSEL_PLDB 0x80 /* TSEL Policy Lock-Down Bit */ +#define WPT_TL_TOL 0x000001FF /* T0 Level */ +#define WPT_TL_T1L 0x1ff00000 /* T1 Level */ +#define WPT_TL_TTEN 0x20000000 /* TT Enable */ + +static char driver_name[] = "Intel PCH thermal driver"; + +struct pch_thermal_device { + void __iomem *hw_base; + const struct pch_dev_ops *ops; + struct pci_dev *pdev; + struct thermal_zone_device *tzd; + int crt_trip_id; + unsigned long crt_temp; + int hot_trip_id; + unsigned long hot_temp; +}; + +static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips) +{ + u8 tsel; + u16 trip_temp; + + *nr_trips = 0; + + /* Check if BIOS has already enabled thermal sensor */ + if (WPT_TSS_TSDSS & readb(ptd->hw_base + WPT_TSS)) + goto read_trips; + + tsel = readb(ptd->hw_base + WPT_TSEL); + /* + * When TSEL's Policy Lock-Down bit is 1, TSEL become RO. + * If so, thermal sensor cannot enable. Bail out. + */ + if (tsel & WPT_TSEL_PLDB) { + dev_err(&ptd->pdev->dev, "Sensor can't be enabled\n"); + return -ENODEV; + } + + writeb(tsel|WPT_TSEL_ETS, ptd->hw_base + WPT_TSEL); + if (!(WPT_TSS_TSDSS & readb(ptd->hw_base + WPT_TSS))) { + dev_err(&ptd->pdev->dev, "Sensor can't be enabled\n"); + return -ENODEV; + } + +read_trips: + ptd->crt_trip_id = -1; + trip_temp = readw(ptd->hw_base + WPT_CTT); + trip_temp &= 0x1FF; + if (trip_temp) { + /* Resolution of 1/2 degree C and an offset of -50C */ + ptd->crt_temp = trip_temp * 1000 / 2 - 50000; + ptd->crt_trip_id = 0; + ++(*nr_trips); + } + + ptd->hot_trip_id = -1; + trip_temp = readw(ptd->hw_base + WPT_PHL); + trip_temp &= 0x1FF; + if (trip_temp) { + /* Resolution of 1/2 degree C and an offset of -50C */ + ptd->hot_temp = trip_temp * 1000 / 2 - 50000; + ptd->hot_trip_id = *nr_trips; + ++(*nr_trips); + } + + return 0; +} + +static int pch_wpt_get_temp(struct pch_thermal_device *ptd, + unsigned long *temp) +{ + u8 wpt_temp; + + wpt_temp = WPT_TEMP_TSR & readl(ptd->hw_base + WPT_TEMP); + + /* Resolution of 1/2 degree C and an offset of -50C */ + *temp = (wpt_temp * 1000 / 2 - 50000); + + return 0; +} + +struct pch_dev_ops { + int (*hw_init)(struct pch_thermal_device *ptd, int *nr_trips); + int (*get_temp)(struct pch_thermal_device *ptd, unsigned long *temp); +}; + + +/* dev ops for Wildcat Point */ +static struct pch_dev_ops pch_dev_ops_wpt = { + .hw_init = pch_wpt_init, + .get_temp = pch_wpt_get_temp, +}; + +static int pch_thermal_get_temp(struct thermal_zone_device *tzd, + unsigned long *temp) +{ + struct pch_thermal_device *ptd = tzd->devdata; + + return ptd->ops->get_temp(ptd, temp); +} + +static int pch_get_trip_type(struct thermal_zone_device *tzd, int trip, + enum thermal_trip_type *type) +{ + struct pch_thermal_device *ptd = tzd->devdata; + + if (ptd->crt_trip_id == trip) + *type = THERMAL_TRIP_CRITICAL; + else if (ptd->hot_trip_id == trip) + *type = THERMAL_TRIP_HOT; + else + return -EINVAL; + + return 0; +} + +static int pch_get_trip_temp(struct thermal_zone_device *tzd, int trip, + unsigned long *temp) +{ + struct pch_thermal_device *ptd = tzd->devdata; + + if (ptd->crt_trip_id == trip) + *temp = ptd->crt_temp; + else if (ptd->hot_trip_id == trip) + *temp = ptd->hot_temp; + else + return -EINVAL; + + return 0; +} + +static struct thermal_zone_device_ops tzd_ops = { + .get_temp = pch_thermal_get_temp, + .get_trip_type = pch_get_trip_type, + .get_trip_temp = pch_get_trip_temp, +}; + + +static int intel_pch_thermal_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pch_thermal_device *ptd; + int err; + int nr_trips; + char *dev_name; + + ptd = devm_kzalloc(&pdev->dev, sizeof(*ptd), GFP_KERNEL); + if (!ptd) + return -ENOMEM; + + switch (pdev->device) { + case PCH_THERMAL_DID_WPT: + ptd->ops = &pch_dev_ops_wpt; + dev_name = "pch_wildcat_point"; + break; + default: + dev_err(&pdev->dev, "unknown pch thermal device\n"); + return -ENODEV; + } + + pci_set_drvdata(pdev, ptd); + ptd->pdev = pdev; + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "failed to enable pci device\n"); + return err; + } + + err = pci_request_regions(pdev, driver_name); + if (err) { + dev_err(&pdev->dev, "failed to request pci region\n"); + goto error_disable; + } + + ptd->hw_base = pci_ioremap_bar(pdev, 0); + if (!ptd->hw_base) { + err = -ENOMEM; + dev_err(&pdev->dev, "failed to map mem base\n"); + goto error_release; + } + + err = ptd->ops->hw_init(ptd, &nr_trips); + if (err) + goto error_cleanup; + + ptd->tzd = thermal_zone_device_register(dev_name, nr_trips, 0, ptd, + &tzd_ops, NULL, 0, 0); + if (IS_ERR(ptd->tzd)) { + dev_err(&pdev->dev, "Failed to register thermal zone %s\n", + dev_name); + err = PTR_ERR(ptd->tzd); + goto error_cleanup; + } + + return 0; + +error_cleanup: + iounmap(ptd->hw_base); +error_release: + pci_release_regions(pdev); +error_disable: + pci_disable_device(pdev); + dev_err(&pdev->dev, "pci device failed to probe\n"); + return err; +} + +static void intel_pch_thermal_remove(struct pci_dev *pdev) +{ + struct pch_thermal_device *ptd = pci_get_drvdata(pdev); + + thermal_zone_device_unregister(ptd->tzd); + iounmap(ptd->hw_base); + pci_set_drvdata(pdev, NULL); + pci_release_region(pdev, 0); + pci_disable_device(pdev); +} + +static struct pci_device_id intel_pch_thermal_id[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WPT) }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id); + +static struct pci_driver intel_pch_thermal_driver = { + .name = "intel_pch_thermal", + .id_table = intel_pch_thermal_id, + .probe = intel_pch_thermal_probe, + .remove = intel_pch_thermal_remove, +}; + +module_pci_driver(intel_pch_thermal_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel PCH Thermal driver"); -- cgit v1.3-6-gb490 From 94ce9e5e73c71b26a19b83844f9840859f3b035b Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Sun, 14 Jun 2015 11:17:07 +0300 Subject: iwlwifi: pcie: Set scheduler to work on auto mode During NIC initialization shared HW is reset and this disables the scheduler. Some HW platforms do not activate the scheduler after it. Consequently all HCMD sent by the driver stay at the queues which cause to queue stuck. Set the scheduler to work on auto active mode so it would be activated upon change over one of the queues' write pointer. Signed-off-by: Haim Dreyfuss Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 1 + drivers/net/wireless/iwlwifi/pcie/tx.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 5af1c776d2d4..a8469041af09 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -253,6 +253,7 @@ #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) #define SCD_GP_CTRL_ENABLE_31_QUEUES BIT(0) +#define SCD_GP_CTRL_AUTO_ACTIVE_MODE BIT(18) /* Context Data */ #define SCD_CONTEXT_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x600) diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 2b86c2135de3..d711f0b8b62f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -915,6 +915,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) } } + iwl_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_AUTO_ACTIVE_MODE); if (trans->cfg->base_params->num_of_queues > 20) iwl_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_ENABLE_31_QUEUES); -- cgit v1.3-6-gb490 From 2dc2a15ebd12c44074d0ea2eef3e97956df4bb86 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2015 17:09:18 +0200 Subject: iwlwifi: mvm: LRU-assign key offsets The current key offset assignment algorithm always uses the lowest unused key offset, which will potentially lead to issues when the firmware will change to take the key material for TX from the key table rather than from the TX command. In order to avoid those issues (and avoid forgetting about them) change the key offset allocation algorithm now to avoid reusing key offsets quickly. The new algorithm always picks as the next offset the least recently freed offset, i.e. the offset that has been unused for the longest amount of time. This is implemented by having a generation counter for each key offset that is incremented every time a key is deleted, except for the one that's deleted, which is reset to zero. Thus the highest counter is the key that's been unused longest. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/sta.c | 32 ++++++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2d4bad5fe825..40d1bd7a200f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -686,6 +686,7 @@ struct iwl_mvm { * can hold 16 keys at most. Reflect this fact. */ unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)]; + u8 fw_key_deleted[STA_KEY_MAX_NUM]; /* references taken by the driver and spinlock protecting them */ spinlock_t refs_lock; diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index d68dc697a4a0..806b2c29b4dc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1148,18 +1148,31 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm) { - int i; + int i, max = -1, max_offs = -1; lockdep_assert_held(&mvm->mutex); - i = find_first_zero_bit(mvm->fw_key_table, STA_KEY_MAX_NUM); + /* Pick the unused key offset with the highest 'deleted' + * counter. Every time a key is deleted, all the counters + * are incremented and the one that was just deleted is + * reset to zero. Thus, the highest counter is the one + * that was deleted longest ago. Pick that one. + */ + for (i = 0; i < STA_KEY_MAX_NUM; i++) { + if (test_bit(i, mvm->fw_key_table)) + continue; + if (mvm->fw_key_deleted[i] > max) { + max = mvm->fw_key_deleted[i]; + max_offs = i; + } + } - if (i == STA_KEY_MAX_NUM) + if (max_offs < 0) return STA_KEY_IDX_INVALID; - __set_bit(i, mvm->fw_key_table); + __set_bit(max_offs, mvm->fw_key_table); - return i; + return max_offs; } static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif, @@ -1478,7 +1491,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, { bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE); u8 sta_id; - int ret; + int ret, i; lockdep_assert_held(&mvm->mutex); @@ -1497,6 +1510,13 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, return -ENOENT; } + /* track which key was deleted last */ + for (i = 0; i < STA_KEY_MAX_NUM; i++) { + if (mvm->fw_key_deleted[i] < U8_MAX) + mvm->fw_key_deleted[i]++; + } + mvm->fw_key_deleted[keyconf->hw_key_idx] = 0; + if (sta_id == IWL_MVM_STATION_COUNT) { IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n"); return 0; -- cgit v1.3-6-gb490 From 4492bb6b10b1fbbc3fd4e8ea1b1bef51a1b2b31a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 20:56:45 +0200 Subject: iwlwifi: dvm: move ADD_STA response handling to sync command This driver currently has some very confusing ADD_STA response handling that runs asynchronously in the background for all of the commands, but is only really necessary for synchronous ones (the really asynchronous ones can only be done for already existing stations), and for the sync ones it actually waits for the RX handler to return a status code. Rework this to keep the debug printing in the handler, but do the code that's supposed to have an effect only for sync commands in the command sending function. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/sta.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 6ec86adbe4a1..346077fad14a 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -66,12 +66,11 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, { struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data; u8 sta_id = addsta->sta.sta_id; - int ret = -EIO; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", pkt->hdr.flags); - return ret; + return 0; } IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", @@ -82,7 +81,6 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, switch (add_sta_resp->status) { case ADD_STA_SUCCESS_MSK: IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); - ret = iwl_sta_ucode_activate(priv, sta_id); break; case ADD_STA_NO_ROOM_IN_TABLE: IWL_ERR(priv, "Adding station %d failed, no room in table.\n", @@ -121,7 +119,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, addsta->sta.addr); spin_unlock_bh(&priv->sta_lock); - return ret; + return 0; } int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, @@ -146,6 +144,8 @@ int iwl_send_add_sta(struct iwl_priv *priv, .len = { sizeof(*sta), }, }; u8 sta_id __maybe_unused = sta->sta.sta_id; + struct iwl_rx_packet *pkt; + struct iwl_add_sta_resp *add_sta_resp; IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n", sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); @@ -159,16 +159,23 @@ int iwl_send_add_sta(struct iwl_priv *priv, if (ret || (flags & CMD_ASYNC)) return ret; - /*else the command was successfully sent in SYNC mode, need to free - * the reply page */ - iwl_free_resp(&cmd); + pkt = cmd.resp_pkt; + add_sta_resp = (void *)pkt->data; - if (cmd.handler_status) - IWL_ERR(priv, "%s - error in the CMD response %d\n", __func__, - cmd.handler_status); + /* debug messages are printed in the handler */ + if (!(pkt->hdr.flags & IWL_CMD_FAILED_MSK) && + add_sta_resp->status == ADD_STA_SUCCESS_MSK) { + spin_lock_bh(&priv->sta_lock); + ret = iwl_sta_ucode_activate(priv, sta_id); + spin_unlock_bh(&priv->sta_lock); + } else { + ret = -EIO; + } + + iwl_free_resp(&cmd); - return cmd.handler_status; + return ret; } bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, -- cgit v1.3-6-gb490 From 121b80091916a3fc401f515c8c6cbdfe9ece3576 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 21:01:44 +0200 Subject: iwlwifi: dvm: remove ADD_STA prints relying on station ID This makes the logging a little less useful, but as they're mostly synchronous commands it won't matter much. It gets rid of the dependency on the input command, which this is the only user of. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/sta.c | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 346077fad14a..6e1e23eff0db 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -61,11 +61,9 @@ static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) } static int iwl_process_add_sta_resp(struct iwl_priv *priv, - struct iwl_addsta_cmd *addsta, struct iwl_rx_packet *pkt) { struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data; - u8 sta_id = addsta->sta.sta_id; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", @@ -73,8 +71,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, return 0; } - IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", - sta_id); + IWL_DEBUG_INFO(priv, "Processing response for adding station\n"); spin_lock_bh(&priv->sta_lock); @@ -83,16 +80,14 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); break; case ADD_STA_NO_ROOM_IN_TABLE: - IWL_ERR(priv, "Adding station %d failed, no room in table.\n", - sta_id); + IWL_ERR(priv, "Adding station failed, no room in table.\n"); break; case ADD_STA_NO_BLOCK_ACK_RESOURCE: - IWL_ERR(priv, "Adding station %d failed, no block ack " - "resource.\n", sta_id); + IWL_ERR(priv, + "Adding station failed, no block ack resource.\n"); break; case ADD_STA_MODIFY_NON_EXIST_STA: - IWL_ERR(priv, "Attempting to modify non-existing station %d\n", - sta_id); + IWL_ERR(priv, "Attempting to modify non-existing station\n"); break; default: IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", @@ -100,23 +95,6 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, break; } - IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n", - priv->stations[sta_id].sta.mode == - STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", - sta_id, priv->stations[sta_id].sta.sta.addr); - - /* - * XXX: The MAC address in the command buffer is often changed from - * the original sent to the device. That is, the MAC address - * written to the command buffer often is not the same MAC address - * read from the command buffer when the command returns. This - * issue has not yet been resolved and this debugging is left to - * observe the problem. - */ - IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n", - priv->stations[sta_id].sta.mode == - STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", - addsta->sta.addr); spin_unlock_bh(&priv->sta_lock); return 0; @@ -130,7 +108,7 @@ int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, if (!cmd) return 0; - return iwl_process_add_sta_resp(priv, (void *)cmd->payload, pkt); + return iwl_process_add_sta_resp(priv, pkt); } int iwl_send_add_sta(struct iwl_priv *priv, -- cgit v1.3-6-gb490 From 73e686f399b3a11e4d26dc13b6f68380e31820dd Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 21:22:09 +0200 Subject: iwlwifi: dvm: remove command/return value from RX handlers After the previous patches, the command that's passed in nor the return value are used any more, so can be removed. While at it, make some functions static. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/agn.h | 14 ++--- drivers/net/wireless/iwlwifi/dvm/dev.h | 5 +- drivers/net/wireless/iwlwifi/dvm/lib.c | 8 +-- drivers/net/wireless/iwlwifi/dvm/rx.c | 103 ++++++++++++-------------------- drivers/net/wireless/iwlwifi/dvm/scan.c | 25 +++----- drivers/net/wireless/iwlwifi/dvm/sta.c | 16 ++--- drivers/net/wireless/iwlwifi/dvm/tx.c | 18 ++---- 7 files changed, 65 insertions(+), 124 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index c160dad03037..f549dc3852a6 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -216,11 +216,9 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); -int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb); +void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb); static inline u32 iwl_tx_status_to_mac80211(u32 status) { @@ -277,9 +275,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, /* bt coex */ void iwlagn_send_advance_bt_config(struct iwl_priv *priv); -int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv); void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv); void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv); @@ -332,8 +327,7 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_link_quality_cmd *lq, u8 flags, bool init); -int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb); int iwl_sta_update_ht(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct ieee80211_sta *sta); diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 3811878ab9cd..1f51757f4a93 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -678,9 +678,8 @@ struct iwl_priv { enum ieee80211_band band; u8 valid_contexts; - int (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); + void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb); struct iwl_notif_wait_data notif_wait; diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 1d2223df5cb0..ab45819c1fbb 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -659,9 +659,8 @@ static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv, return need_update; } -int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_bt_coex_profile_notif *coex = (void *)pkt->data; @@ -669,7 +668,7 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) { /* bt coex disabled */ - return 0; + return; } IWL_DEBUG_COEX(priv, "BT Coex notification:\n"); @@ -714,7 +713,6 @@ int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, /* FIXME: based on notification, adjust the prio_boost */ priv->bt_ci_compliance = coex->bt_ci_compliance; - return 0; } void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index debec963c610..ca270a6234e7 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -123,9 +123,8 @@ const char *const iwl_dvm_cmd_strings[REPLY_MAX] = { * ******************************************************************************/ -static int iwlagn_rx_reply_error(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_error(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_error_resp *err_resp = (void *)pkt->data; @@ -136,11 +135,9 @@ static int iwlagn_rx_reply_error(struct iwl_priv *priv, err_resp->cmd_id, le16_to_cpu(err_resp->bad_cmd_seq_num), le32_to_cpu(err_resp->error_info)); - return 0; } -static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_csa_notification *csa = (void *)pkt->data; @@ -152,7 +149,7 @@ static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, struct iwl_rxon_cmd *rxon = (void *)&ctx->active; if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) - return 0; + return; if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) { rxon->channel = csa->channel; @@ -165,13 +162,11 @@ static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, le16_to_cpu(csa->channel)); iwl_chswitch_done(priv, false); } - return 0; } -static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_spectrum_notification *report = (void *)pkt->data; @@ -179,17 +174,15 @@ static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv, if (!report->state) { IWL_DEBUG_11H(priv, "Spectrum Measure Notification: Start\n"); - return 0; + return; } memcpy(&priv->measure_report, report, sizeof(*report)); priv->measurement_status |= MEASUREMENT_READY; - return 0; } -static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -197,24 +190,20 @@ static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv, IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", sleep->pm_sleep_mode, sleep->pm_wakeup_src); #endif - return 0; } -static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 __maybe_unused len = iwl_rx_packet_len(pkt); IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " "notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len); iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len); - return 0; } -static int iwlagn_rx_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwlagn_beacon_notif *beacon = (void *)pkt->data; @@ -232,8 +221,6 @@ static int iwlagn_rx_beacon_notif(struct iwl_priv *priv, #endif priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); - - return 0; } /** @@ -448,9 +435,8 @@ iwlagn_accumulative_statistics(struct iwl_priv *priv, } #endif -static int iwlagn_rx_statistics(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { unsigned long stamp = jiffies; const int reg_recalib_period = 60; @@ -505,7 +491,7 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv, len, sizeof(struct iwl_bt_notif_statistics), sizeof(struct iwl_notif_statistics)); spin_unlock(&priv->statistics.lock); - return 0; + return; } change = common->temperature != priv->statistics.common.temperature || @@ -550,13 +536,10 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv, priv->lib->temperature(priv); spin_unlock(&priv->statistics.lock); - - return 0; } -static int iwlagn_rx_reply_statistics(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_statistics(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_notif_statistics *stats = (void *)pkt->data; @@ -572,15 +555,14 @@ static int iwlagn_rx_reply_statistics(struct iwl_priv *priv, #endif IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); } - iwlagn_rx_statistics(priv, rxb, cmd); - return 0; + + iwlagn_rx_statistics(priv, rxb); } /* Handle notification from uCode that card's power state is changing * due to software, hardware, or critical temperature RFKILL */ -static int iwlagn_rx_card_state_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_card_state_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_card_state_notif *card_state_notif = (void *)pkt->data; @@ -627,12 +609,10 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv, test_bit(STATUS_RF_KILL_HW, &priv->status))) wiphy_rfkill_set_hw_state(priv->hw->wiphy, test_bit(STATUS_RF_KILL_HW, &priv->status)); - return 0; } -static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -649,14 +629,12 @@ static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv, if (!test_bit(STATUS_SCANNING, &priv->status)) iwl_init_sensitivity(priv); } - return 0; } /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ -static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -664,7 +642,6 @@ static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, priv->ampdu_ref++; memcpy(&priv->last_phy_res, pkt->data, sizeof(struct iwl_rx_phy_res)); - return 0; } /* @@ -890,9 +867,8 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv, } /* Called for REPLY_RX_MPDU_CMD */ -static int iwlagn_rx_reply_rx(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status = {}; @@ -906,7 +882,7 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, if (!priv->last_phy_res_valid) { IWL_ERR(priv, "MPDU frame without cached PHY data\n"); - return 0; + return; } phy_res = &priv->last_phy_res; amsdu = (struct iwl_rx_mpdu_res_start *)pkt->data; @@ -919,14 +895,14 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, if ((unlikely(phy_res->cfg_phy_cnt > 20))) { IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d\n", phy_res->cfg_phy_cnt); - return 0; + return; } if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", le32_to_cpu(rx_pkt_status)); - return 0; + return; } /* This will be used in several places later */ @@ -998,12 +974,10 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status, rxb, &rx_status); - return 0; } -static int iwlagn_rx_noa_notification(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwlagn_rx_noa_notification(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_wipan_noa_data *new_data, *old_data; struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -1041,8 +1015,6 @@ static int iwlagn_rx_noa_notification(struct iwl_priv *priv, if (old_data) kfree_rcu(old_data, rcu_head); - - return 0; } /** @@ -1053,8 +1025,7 @@ static int iwlagn_rx_noa_notification(struct iwl_priv *priv, */ void iwl_setup_rx_handlers(struct iwl_priv *priv) { - int (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); + void (**handlers)(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb); handlers = priv->rx_handlers; @@ -1107,7 +1078,6 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); - int err = 0; /* * Do the notification wait before RX handlers so @@ -1121,12 +1091,13 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, * rx_handlers table. See iwl_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { priv->rx_handlers_stats[pkt->hdr.cmd]++; - err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd); + priv->rx_handlers[pkt->hdr.cmd](priv, rxb); } else { /* No handling needed */ IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n", iwl_dvm_get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); } - return err; + + return 0; } diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index 43bef901e8f9..648159495bbc 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c @@ -247,9 +247,8 @@ void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) } /* Service response to REPLY_SCAN_CMD (0x80) */ -static int iwl_rx_reply_scan(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwl_rx_reply_scan(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -257,13 +256,11 @@ static int iwl_rx_reply_scan(struct iwl_priv *priv, IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status); #endif - return 0; } /* Service SCAN_START_NOTIFICATION (0x82) */ -static int iwl_rx_scan_start_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwl_rx_scan_start_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scanstart_notification *notif = (void *)pkt->data; @@ -277,14 +274,11 @@ static int iwl_rx_scan_start_notif(struct iwl_priv *priv, le32_to_cpu(notif->tsf_high), le32_to_cpu(notif->tsf_low), notif->status, notif->beacon_timer); - - return 0; } /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ -static int iwl_rx_scan_results_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwl_rx_scan_results_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -303,13 +297,11 @@ static int iwl_rx_scan_results_notif(struct iwl_priv *priv, le32_to_cpu(notif->statistics[0]), le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf); #endif - return 0; } /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ -static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scancomplete_notification *scan_notif = (void *)pkt->data; @@ -356,7 +348,6 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, queue_work(priv->workqueue, &priv->bt_traffic_change_work); } - return 0; } void iwl_setup_rx_scan_handlers(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index 6e1e23eff0db..c18aa3e950d5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -60,15 +60,15 @@ static int iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) return 0; } -static int iwl_process_add_sta_resp(struct iwl_priv *priv, - struct iwl_rx_packet *pkt) +static void iwl_process_add_sta_resp(struct iwl_priv *priv, + struct iwl_rx_packet *pkt) { struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data; if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", pkt->hdr.flags); - return 0; + return; } IWL_DEBUG_INFO(priv, "Processing response for adding station\n"); @@ -96,19 +96,13 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, } spin_unlock_bh(&priv->sta_lock); - - return 0; } -int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - if (!cmd) - return 0; - - return iwl_process_add_sta_resp(priv, pkt); + iwl_process_add_sta_resp(priv, pkt); } int iwl_send_add_sta(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 275df12a6045..bddd19769035 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -1128,8 +1128,7 @@ static void iwl_check_abort_status(struct iwl_priv *priv, } } -int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); @@ -1273,8 +1272,6 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, skb = __skb_dequeue(&skbs); ieee80211_tx_status(priv->hw, skb); } - - return 0; } /** @@ -1283,9 +1280,8 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, * Handles block-acknowledge notification from device, which reports success * of frames sent via aggregation. */ -int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_compressed_ba_resp *ba_resp = (void *)pkt->data; @@ -1306,7 +1302,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, if (scd_flow >= priv->cfg->base_params->num_of_queues) { IWL_ERR(priv, "BUG_ON scd_flow is bigger than number of queues\n"); - return 0; + return; } sta_id = ba_resp->sta_id; @@ -1319,7 +1315,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, if (unlikely(ba_resp->bitmap)) IWL_ERR(priv, "Received BA when not expected\n"); spin_unlock_bh(&priv->sta_lock); - return 0; + return; } if (unlikely(scd_flow != agg->txq_id)) { @@ -1333,7 +1329,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n", scd_flow, sta_id, tid, agg->txq_id); spin_unlock_bh(&priv->sta_lock); - return 0; + return; } __skb_queue_head_init(&reclaimed_skbs); @@ -1413,6 +1409,4 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, skb = __skb_dequeue(&reclaimed_skbs); ieee80211_tx_status(priv->hw, skb); } - - return 0; } -- cgit v1.3-6-gb490 From 0416841d709e4d90913576cc43a397e450a745b1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 21:22:09 +0200 Subject: iwlwifi: mvm: remove command/return value from RX handlers In the mvm driver, neither the old command nor the return value are used, so remove them. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 44 +++++----- drivers/net/wireless/iwlwifi/mvm/coex_legacy.c | 31 +++---- drivers/net/wireless/iwlwifi/mvm/fw.c | 13 +-- drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 13 +-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 107 ++++++++++--------------- drivers/net/wireless/iwlwifi/mvm/nvm.c | 11 +-- drivers/net/wireless/iwlwifi/mvm/ops.c | 22 ++--- drivers/net/wireless/iwlwifi/mvm/power.c | 7 +- drivers/net/wireless/iwlwifi/mvm/rx.c | 20 ++--- drivers/net/wireless/iwlwifi/mvm/scan.c | 35 +++----- drivers/net/wireless/iwlwifi/mvm/sta.c | 9 +-- drivers/net/wireless/iwlwifi/mvm/sta.h | 5 +- drivers/net/wireless/iwlwifi/mvm/tdls.c | 12 +-- drivers/net/wireless/iwlwifi/mvm/time-event.c | 7 +- drivers/net/wireless/iwlwifi/mvm/time-event.h | 5 +- drivers/net/wireless/iwlwifi/mvm/tt.c | 10 +-- drivers/net/wireless/iwlwifi/mvm/tx.c | 16 ++-- drivers/net/wireless/iwlwifi/mvm/utils.c | 4 +- 18 files changed, 139 insertions(+), 232 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index b4737e296c92..e290ac67d975 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -725,15 +725,17 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) } } -int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *dev_cmd) +void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; - if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT)) - return iwl_mvm_rx_bt_coex_notif_old(mvm, rxb, dev_cmd); + if (!fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { + iwl_mvm_rx_bt_coex_notif_old(mvm, rxb); + return; + } IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); @@ -748,12 +750,6 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); iwl_mvm_bt_coex_notif_handle(mvm); - - /* - * This is an async handler for a notification, returning anything other - * than 0 doesn't make sense even if HCMD failed. - */ - return 0; } void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -947,9 +943,8 @@ 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) +void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 ant_isolation = le32_to_cpup((void *)pkt->data); @@ -957,20 +952,23 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, u8 __maybe_unused lower_bound, upper_bound; u8 lut; - if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BT_COEX_SPLIT)) - return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd); + if (!fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_BT_COEX_SPLIT)) { + iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb); + return; + } if (!iwl_mvm_bt_is_plcr_supported(mvm)) - return 0; + return; lockdep_assert_held(&mvm->mutex); /* Ignore updates if we are in force mode */ if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) - return 0; + return; if (ant_isolation == mvm->last_ant_isol) - return 0; + return; for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++) if (ant_isolation < antenna_coupling_ranges[lut + 1].range) @@ -989,7 +987,7 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, mvm->last_ant_isol = ant_isolation; if (mvm->last_corun_lut == lut) - return 0; + return; mvm->last_corun_lut = lut; @@ -1000,6 +998,8 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, memcpy(&cmd.corun_lut40, antenna_coupling_ranges[lut].lut20, sizeof(cmd.corun_lut40)); - return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_CORUN_LUT, 0, - sizeof(cmd), &cmd); + if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_CORUN_LUT, 0, + sizeof(cmd), &cmd)) + IWL_ERR(mvm, + "failed to send BT_COEX_UPDATE_CORUN_LUT command\n"); } diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c index 6ac6de2af977..61c07b05fcaa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c @@ -1058,9 +1058,8 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n"); } -int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *dev_cmd) +void iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_bt_coex_profile_notif_old *notif = (void *)pkt->data; @@ -1083,12 +1082,6 @@ int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, memcpy(&mvm->last_bt_notif_old, notif, sizeof(mvm->last_bt_notif_old)); iwl_mvm_bt_coex_notif_handle(mvm); - - /* - * This is an async handler for a notification, returning anything other - * than 0 doesn't make sense even if HCMD failed. - */ - return 0; } static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac, @@ -1250,14 +1243,12 @@ void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm) iwl_mvm_bt_coex_notif_handle(mvm); } -int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *dev_cmd) +void iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 ant_isolation = le32_to_cpup((void *)pkt->data); u8 __maybe_unused lower_bound, upper_bound; - int ret; u8 lut; struct iwl_bt_coex_cmd_old *bt_cmd; @@ -1268,16 +1259,16 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, }; if (!iwl_mvm_bt_is_plcr_supported(mvm)) - return 0; + return; lockdep_assert_held(&mvm->mutex); /* Ignore updates if we are in force mode */ if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) - return 0; + return; if (ant_isolation == mvm->last_ant_isol) - return 0; + return; for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++) if (ant_isolation < antenna_coupling_ranges[lut + 1].range) @@ -1296,13 +1287,13 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, mvm->last_ant_isol = ant_isolation; if (mvm->last_corun_lut == lut) - return 0; + return; mvm->last_corun_lut = lut; bt_cmd = kzalloc(sizeof(*bt_cmd), GFP_KERNEL); if (!bt_cmd) - return 0; + return; cmd.data[0] = bt_cmd; bt_cmd->flags = cpu_to_le32(BT_COEX_NW_OLD); @@ -1317,8 +1308,8 @@ int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20, sizeof(bt_cmd->bt4_corun_lut40)); - ret = iwl_mvm_send_cmd(mvm, &cmd); + if (iwl_mvm_send_cmd(mvm, &cmd)) + IWL_ERR(mvm, "failed to send BT_CONFIG command\n"); kfree(bt_cmd); - return ret; } diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index a482ce692f5f..a5dae09869fc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -814,9 +814,8 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm) return ret; } -int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_card_state_notif *card_state_notif = (void *)pkt->data; @@ -827,13 +826,10 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, (flags & SW_CARD_DISABLED) ? "Kill" : "On", (flags & CT_KILL_CARD_DISABLED) ? "Reached" : "Not reached"); - - return 0; } -int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data; @@ -844,5 +840,4 @@ int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, le32_to_cpu(mfuart_notif->external_ver), le32_to_cpu(mfuart_notif->status), le32_to_cpu(mfuart_notif->duration)); - return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 1812dd018af2..3424315dd876 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -1312,9 +1312,8 @@ static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, } } -int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; @@ -1365,8 +1364,6 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL); } } - - return 0; } static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, @@ -1415,9 +1412,8 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, iwl_mvm_fw_dbg_collect_trig(mvm, trigger, NULL); } -int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_missed_beacons_notif *mb = (void *)pkt->data; @@ -1434,5 +1430,4 @@ int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_beacon_loss_iterator, mb); - return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 40d1bd7a200f..1397e3e0d669 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1012,9 +1012,8 @@ static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm) /* Statistics */ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt); -int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); int iwl_mvm_request_statistics(struct iwl_mvm *mvm, bool clear); void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm); @@ -1060,27 +1059,19 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm, * FW notifications / CMD responses handlers * Convention: iwl_mvm_rx_ */ -int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -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_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, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /* MVM PHY */ int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, @@ -1107,12 +1098,10 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif); u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif); unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, @@ -1136,29 +1125,24 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm); void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm); /* Scheduled scan */ -int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, struct ieee80211_scan_ies *ies, int type); -int iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /* UMAC scan */ int iwl_mvm_config_scan(struct iwl_mvm *mvm); -int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); -int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /* MVM debugfs */ #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1197,9 +1181,8 @@ 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); +void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); #ifdef CONFIG_IWLWIFI_LEDS int iwl_mvm_leds_init(struct iwl_mvm *mvm); @@ -1255,9 +1238,8 @@ int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm); /* BT Coex */ int iwl_send_bt_init_conf(struct iwl_mvm *mvm); -int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event_data); void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm); @@ -1275,9 +1257,8 @@ u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm); void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm); int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm); -int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event_data); u16 iwl_mvm_coex_agg_time_limit_old(struct iwl_mvm *mvm, @@ -1286,9 +1267,8 @@ bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm, struct ieee80211_sta *sta); bool iwl_mvm_bt_coex_is_tpc_allowed_old(struct iwl_mvm *mvm, enum ieee80211_band band); -int iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_ant_coupling_notif_old(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /* beacon filtering */ #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -1377,9 +1357,8 @@ static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue, /* Thermal management and CT-kill */ void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff); void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp); -int iwl_mvm_temp_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_temp_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_tt_handler(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); @@ -1391,9 +1370,8 @@ struct iwl_mcc_update_resp * iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, enum iwl_mcc_source src_id); int iwl_mvm_init_mcc(struct iwl_mvm *mvm); -int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, const char *alpha2, enum iwl_mcc_source src_id, @@ -1432,8 +1410,7 @@ void iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw, void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta); -int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_tdls_ch_switch_work(struct work_struct *work); struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm); diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 2a6be350704a..6dcdee725ff8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -839,9 +839,8 @@ int iwl_mvm_init_mcc(struct iwl_mvm *mvm) return retval; } -int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mcc_chub_notif *notif = (void *)pkt->data; @@ -852,7 +851,7 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); if (WARN_ON_ONCE(!iwl_mvm_is_lar_supported(mvm))) - return 0; + return; mcc[0] = notif->mcc >> 8; mcc[1] = notif->mcc & 0xff; @@ -864,10 +863,8 @@ int iwl_mvm_rx_chub_update_mcc(struct iwl_mvm *mvm, mcc, src); regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, mcc, src, NULL); if (IS_ERR_OR_NULL(regd)) - return 0; + return; regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); kfree(regd); - - return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 8f896cd1c9cd..00ca24064c02 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -203,8 +203,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) struct iwl_rx_handlers { u8 cmd_id; bool async; - int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); + void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); }; #define RX_HANDLER(_cmd_id, _fn, _async) \ @@ -628,8 +627,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) struct iwl_async_handler_entry { struct list_head list; struct iwl_rx_cmd_buffer rxb; - int (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); + void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); }; void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm) @@ -666,9 +664,7 @@ static void iwl_mvm_async_handlers_wk(struct work_struct *wk) spin_unlock_bh(&mvm->async_handlers_lock); list_for_each_entry_safe(entry, tmp, &local_list, list) { - if (entry->fn(mvm, &entry->rxb, NULL)) - IWL_WARN(mvm, - "returned value from ASYNC handlers are ignored\n"); + entry->fn(mvm, &entry->rxb); iwl_free_rxb(&entry->rxb); list_del(&entry->list); kfree(entry); @@ -715,8 +711,10 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 i; - if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) - return iwl_mvm_rx_rx_mpdu(mvm, rxb, cmd); + if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) { + iwl_mvm_rx_rx_mpdu(mvm, rxb); + return 0; + } iwl_mvm_rx_check_trigger(mvm, pkt); @@ -734,8 +732,10 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, if (rx_h->cmd_id != pkt->hdr.cmd) continue; - if (!rx_h->async) - return rx_h->fn(mvm, rxb, cmd); + if (!rx_h->async) { + rx_h->fn(mvm, rxb); + return 0; + } entry = kzalloc(sizeof(*entry), GFP_ATOMIC); /* we can't do much... */ diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index d2c6ba9d326b..8e2490a1d743 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -509,9 +509,8 @@ static void iwl_mvm_power_uapsd_misbehav_ap_iterator(void *_data, u8 *mac, ETH_ALEN); } -int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data; @@ -520,8 +519,6 @@ int iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_power_uapsd_misbehav_ap_iterator, &ap_sta_id); - - return 0; } struct iwl_power_vifs { diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 8f1d93b7a13a..73054ddc5138 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -71,8 +71,7 @@ * Copies the phy information in mvm->last_phy_info, it will be used when the * actual data will come from the fw in the next packet. */ -int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -86,8 +85,6 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, spin_unlock(&mvm->drv_stats_lock); } #endif - - return 0; } /* @@ -242,8 +239,7 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, * * Handles the actual data of the Rx packet from the fw */ -int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct ieee80211_hdr *hdr; struct ieee80211_rx_status *rx_status; @@ -271,7 +267,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, skb = alloc_skb(128, GFP_ATOMIC); if (!skb) { IWL_ERR(mvm, "alloc_skb failed\n"); - return 0; + return; } rx_status = IEEE80211_SKB_RXCB(skb); @@ -284,14 +280,14 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n", rx_pkt_status); kfree_skb(skb); - return 0; + return; } if ((unlikely(phy_info->cfg_phy_cnt > 20))) { IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n", phy_info->cfg_phy_cnt); kfree_skb(skb); - return 0; + return; } /* @@ -431,7 +427,6 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, #endif iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status, crypt_len, rxb); - return 0; } static void iwl_mvm_update_rx_statistics(struct iwl_mvm *mvm, @@ -623,10 +618,7 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, iwl_rx_packet_payload_len(pkt)); } -int iwl_mvm_rx_statistics(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_statistics(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { iwl_mvm_handle_rx_statistics(mvm, rxb_addr(rxb)); - return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 5de144968723..9c70118841d7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -327,9 +327,8 @@ static u8 *iwl_mvm_dump_channel_list(struct iwl_scan_results_notif *res, return buf; } -int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_lmac_scan_complete_notif *notif = (void *)pkt->data; @@ -341,17 +340,13 @@ int iwl_mvm_rx_lmac_scan_iter_complete_notif(struct iwl_mvm *mvm, iwl_mvm_dump_channel_list(notif->results, notif->scanned_channels, buf, sizeof(buf))); - return 0; } -int iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_scan_match_found(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); ieee80211_sched_scan_results(mvm->hw); - - return 0; } static const char *iwl_mvm_ebs_status_str(enum iwl_scan_ebs_status status) @@ -368,9 +363,8 @@ static const char *iwl_mvm_ebs_status_str(enum iwl_scan_ebs_status status) } } -int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_periodic_scan_complete *scan_notif = (void *)pkt->data; @@ -426,8 +420,6 @@ int iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, mvm->last_ebs_successful = scan_notif->ebs_status == IWL_SCAN_EBS_SUCCESS || scan_notif->ebs_status == IWL_SCAN_EBS_INACTIVE; - - return 0; } static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list) @@ -1371,9 +1363,8 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, return ret; } -int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_umac_scan_complete *notif = (void *)pkt->data; @@ -1381,7 +1372,7 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED); if (WARN_ON(!(mvm->scan_uid_status[uid] & mvm->scan_status))) - return 0; + return; /* if the scan is already stopping, we don't need to notify mac80211 */ if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_REGULAR) { @@ -1405,13 +1396,10 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, mvm->last_ebs_successful = false; mvm->scan_uid_status[uid] = 0; - - return 0; } -int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data; @@ -1423,7 +1411,6 @@ int iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, iwl_mvm_dump_channel_list(notif->results, notif->scanned_channels, buf, sizeof(buf))); - return 0; } static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 806b2c29b4dc..f7d3921b982f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -1680,9 +1680,8 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, 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) +void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm_eosp_notification *notif = (void *)pkt->data; @@ -1690,15 +1689,13 @@ int iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, u32 sta_id = le32_to_cpu(notif->sta_id); if (WARN_ON_ONCE(sta_id >= IWL_MVM_STATION_COUNT)) - return 0; + return; 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; } void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 748f5dc3f9f4..eedb215eba3f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -378,9 +378,8 @@ 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); +void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /* AMPDU */ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index a87b506c8c72..71802e7f7448 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -261,8 +261,7 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm, mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT; } -int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_tdls_channel_switch_notif *notif = (void *)pkt->data; @@ -277,17 +276,17 @@ int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, /* can fail sometimes */ if (!le32_to_cpu(notif->status)) { iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE); - goto out; + return; } if (WARN_ON(sta_id >= IWL_MVM_STATION_COUNT)) - goto out; + return; sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], lockdep_is_held(&mvm->mutex)); /* the station may not be here, but if it is, it must be a TDLS peer */ if (IS_ERR_OR_NULL(sta) || WARN_ON(!sta->tdls)) - goto out; + return; mvmsta = iwl_mvm_sta_from_mac80211(sta); vif = mvmsta->vif; @@ -301,9 +300,6 @@ int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, msecs_to_jiffies(delay)); iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_ACTIVE); - -out: - return 0; } static int diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index d24b6a83e68c..6c0566996441 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -410,9 +410,8 @@ static int iwl_mvm_aux_roc_te_handle_notif(struct iwl_mvm *mvm, /* * The Rx handler for time event notifications */ -int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_time_event_notif *notif = (void *)pkt->data; @@ -433,8 +432,6 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, } unlock: spin_unlock_bh(&mvm->time_event_lock); - - return 0; } static bool iwl_mvm_te_notif(struct iwl_notif_wait_data *notif_wait, diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index de4fbc6d57f1..cbdf8e52a5f1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h @@ -157,9 +157,8 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, /* * iwl_mvm_rx_time_event_notif - handles %TIME_EVENT_NOTIFICATION. */ -int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); /** * iwl_mvm_start_p2p_roc - start remain on channel for p2p device functionality diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 80d07db6e7e8..7e88d3929119 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -154,24 +154,20 @@ static bool iwl_mvm_temp_notif_wait(struct iwl_notif_wait_data *notif_wait, return true; } -int iwl_mvm_temp_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); int temp; /* the notification is handled synchronously in ctkill, so skip here */ if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status)) - return 0; + return; temp = iwl_mvm_temp_notif_parse(mvm, pkt); if (temp < 0) - return 0; + return; iwl_mvm_tt_temp_changed(mvm, temp); - - return 0; } static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 7ba7a118ff5c..abde484436a8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -911,8 +911,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, rcu_read_unlock(); } -int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm_tx_resp *tx_resp = (void *)pkt->data; @@ -921,8 +920,6 @@ int iwl_mvm_rx_tx_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, iwl_mvm_rx_tx_cmd_single(mvm, pkt); else iwl_mvm_rx_tx_cmd_agg(mvm, pkt); - - return 0; } static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info, @@ -942,8 +939,7 @@ static void iwl_mvm_tx_info_from_ba_notif(struct ieee80211_tx_info *info, (void *)(uintptr_t)tid_data->rate_n_flags; } -int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm_ba_notif *ba_notif = (void *)pkt->data; @@ -965,7 +961,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT || tid >= IWL_MAX_TID_COUNT, "sta_id %d tid %d", sta_id, tid)) - return 0; + return; rcu_read_lock(); @@ -974,7 +970,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, /* Reclaiming frames for a station that has been deleted ? */ if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { rcu_read_unlock(); - return 0; + return; } mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -985,7 +981,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, "invalid BA notification: Q %d, tid %d, flow %d\n", tid_data->txq_id, tid, scd_flow); rcu_read_unlock(); - return 0; + return; } spin_lock_bh(&mvmsta->lock); @@ -1072,8 +1068,6 @@ out: skb = __skb_dequeue(&reclaimed_skbs); ieee80211_tx_status(mvm->hw, skb); } - - return 0; } /* diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 03f8e06dded7..3b016f95a8ed 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -243,8 +243,7 @@ u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx) return fw_rate_idx_to_plcp[rate_idx]; } -int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_error_resp *err_resp = (void *)pkt->data; @@ -256,7 +255,6 @@ int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, le32_to_cpu(err_resp->error_service)); IWL_ERR(mvm, "FW Error notification: timestamp 0x%16llX\n", le64_to_cpu(err_resp->timestamp)); - return 0; } /* -- cgit v1.3-6-gb490 From f7e6469fc90aa388ac5047e1ba914b31af9240ae Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 21:58:17 +0200 Subject: iwlwifi: remove command and return value from opmode RX With the previous patch series, no opmode continues using the command or handler_status (i.e. the return value from the RX) so it can be removed now. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/agn.h | 5 ++--- drivers/net/wireless/iwlwifi/dvm/rx.c | 5 +---- drivers/net/wireless/iwlwifi/iwl-op-mode.h | 10 ++++------ drivers/net/wireless/iwlwifi/iwl-trans.h | 3 --- drivers/net/wireless/iwlwifi/mvm/ops.c | 13 +++++-------- drivers/net/wireless/iwlwifi/pcie/internal.h | 2 +- drivers/net/wireless/iwlwifi/pcie/rx.c | 12 +++--------- drivers/net/wireless/iwlwifi/pcie/tx.c | 5 +---- 8 files changed, 17 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index f549dc3852a6..101ef3109292 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -122,9 +122,8 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) void iwl_down(struct iwl_priv *priv); void iwl_cancel_deferred_work(struct iwl_priv *priv); void iwlagn_prepare_restart(struct iwl_priv *priv); -int __must_check iwl_rx_dispatch(struct iwl_op_mode *op_mode, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); +void iwl_rx_dispatch(struct iwl_op_mode *op_mode, + struct iwl_rx_cmd_buffer *rxb); bool iwl_check_for_ct_kill(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index ca270a6234e7..c91374fe9a58 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -1073,8 +1073,7 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) iwlagn_bt_rx_handler_setup(priv); } -int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +void iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); @@ -1098,6 +1097,4 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, iwl_dvm_get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); } - - return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index ce1cdd7604e8..71b450adbda0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -148,8 +148,7 @@ struct iwl_op_mode_ops { const struct iwl_fw *fw, struct dentry *dbgfs_dir); void (*stop)(struct iwl_op_mode *op_mode); - int (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd); + void (*rx)(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb); void (*napi_add)(struct iwl_op_mode *op_mode, struct napi_struct *napi, struct net_device *napi_dev, @@ -188,11 +187,10 @@ static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode) op_mode->ops->stop(op_mode); } -static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static inline void iwl_op_mode_rx(struct iwl_op_mode *op_mode, + struct iwl_rx_cmd_buffer *rxb) { - return op_mode->ops->rx(op_mode, rxb, cmd); + return op_mode->ops->rx(op_mode, rxb); } static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 87a230a7f4b6..7b6f095bac48 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -261,8 +261,6 @@ enum iwl_hcmd_dataflag { * @resp_pkt: response packet, if %CMD_WANT_SKB was set * @_rx_page_order: (internally used to free response packet) * @_rx_page_addr: (internally used to free response packet) - * @handler_status: return value of the handler of the command - * (put in setup_rx_handlers) - valid for SYNC mode only * @flags: can be CMD_* * @len: array of the lengths of the chunks in data * @dataflags: IWL_HCMD_DFL_* @@ -273,7 +271,6 @@ struct iwl_host_cmd { struct iwl_rx_packet *resp_pkt; unsigned long _rx_page_addr; u32 _rx_page_order; - int handler_status; u32 flags; u16 len[IWL_MAX_CMD_TBS_PER_TFD]; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 00ca24064c02..51c2fd098c71 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -703,9 +703,8 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, } } -static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, - struct iwl_rx_cmd_buffer *rxb, - struct iwl_device_cmd *cmd) +static void iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); @@ -713,7 +712,7 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) { iwl_mvm_rx_rx_mpdu(mvm, rxb); - return 0; + return; } iwl_mvm_rx_check_trigger(mvm, pkt); @@ -734,13 +733,13 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, if (!rx_h->async) { rx_h->fn(mvm, rxb); - return 0; + return; } entry = kzalloc(sizeof(*entry), GFP_ATOMIC); /* we can't do much... */ if (!entry) - return 0; + return; entry->rxb._page = rxb_steal_page(rxb); entry->rxb._offset = rxb->_offset; @@ -752,8 +751,6 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, schedule_work(&mvm->async_handlers_wk); break; } - - return 0; } static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue) diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 4f0640767d30..e27d5a3dcb86 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -423,7 +423,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans); int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); void iwl_pcie_hcmd_complete(struct iwl_trans *trans, - struct iwl_rx_cmd_buffer *rxb, int handler_status); + struct iwl_rx_cmd_buffer *rxb); void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs); void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 93062f2e8f56..32ec95bd4973 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -823,10 +823,9 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, while (offset + sizeof(u32) + sizeof(struct iwl_cmd_header) < max_len) { struct iwl_rx_packet *pkt; - struct iwl_device_cmd *cmd; u16 sequence; bool reclaim; - int index, cmd_index, err, len; + int index, cmd_index, len; struct iwl_rx_cmd_buffer rxcb = { ._offset = offset, ._rx_page_order = trans_pcie->rx_page_order, @@ -874,12 +873,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, index = SEQ_TO_INDEX(sequence); cmd_index = get_cmd_index(&txq->q, index); - if (reclaim) - cmd = txq->entries[cmd_index].cmd; - else - cmd = NULL; - - err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd); + iwl_op_mode_rx(trans->op_mode, &rxcb); if (reclaim) { kzfree(txq->entries[cmd_index].free_buf); @@ -897,7 +891,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, * iwl_trans_send_cmd() * as we reclaim the driver command queue */ if (!rxcb._page_stolen) - iwl_pcie_hcmd_complete(trans, &rxcb, err); + iwl_pcie_hcmd_complete(trans, &rxcb); else IWL_WARN(trans, "Claim null rxb?\n"); } diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index d711f0b8b62f..c6572ffb8ae2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1553,15 +1553,13 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, /* * iwl_pcie_hcmd_complete - Pull unused buffers off the queue and reclaim them * @rxb: Rx buffer to reclaim - * @handler_status: return value of the handler of the command - * (put in setup_rx_handlers) * * If an Rx buffer has an async callback associated with it the callback * will be executed. The attached skb (if present) will only be freed * if the callback returns 1 */ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, - struct iwl_rx_cmd_buffer *rxb, int handler_status) + struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); @@ -1600,7 +1598,6 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, meta->source->resp_pkt = pkt; meta->source->_rx_page_addr = (unsigned long)page_address(p); meta->source->_rx_page_order = trans_pcie->rx_page_order; - meta->source->handler_status = handler_status; } iwl_pcie_cmdq_reclaim(trans, txq_id, index); -- cgit v1.3-6-gb490 From 5bf12f6096ad615c90accc1f37935423ea1a3c26 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 24 Jun 2015 10:25:26 +0300 Subject: iwlwifi: mvm: Do not sample the device time for session protection Since the time-event is sent with the immediate flag set, there is no need to sample the device time. Signed-off-by: Ilan Peer Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/time-event.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 6c0566996441..8fe7ecd75b92 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -596,8 +596,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); time_cmd.id = cpu_to_le32(TE_BSS_STA_AGGRESSIVE_ASSOC); - time_cmd.apply_time = - cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); + time_cmd.apply_time = cpu_to_le32(0); time_cmd.max_frags = TE_V2_FRAG_NONE; time_cmd.max_delay = cpu_to_le32(max_delay); -- cgit v1.3-6-gb490 From 1103323ca1aafb0aa32064abec736ea9f2ce66a6 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 24 Jun 2015 14:58:13 +0300 Subject: iwlwifi: pcie: cancel Tx timer upon firmware crash When the firmware crashes, we can't expect the Tx queues to progress. Cancel their timer. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/rx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 32ec95bd4973..5561dee7b62d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1014,6 +1014,7 @@ restart: static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int i; /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ if (trans->cfg->internal_wimax_coex && @@ -1037,6 +1038,9 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) iwl_trans_fw_error(trans); local_bh_enable(); + for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) + del_timer(&trans_pcie->txq[i].stuck_timer); + clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); wake_up(&trans_pcie->wait_command_queue); } -- cgit v1.3-6-gb490 From 33b56af188ddbd1027b7eaff7abb1507b708f155 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 25 Jun 2015 12:55:45 +0300 Subject: iwlwifi: pcie: add missing calls to synchronize_irq() In a few places, we were disabling interrupts but didn't make sure that the interrupt handler has finished running. Add calls to synchronize_irq() to ensure we finish handling the interrupts before we free resources or other things that could lead to a crash if the interrupt were to be handled later. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/trans.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 23f2824e8d56..4cdfb2fd992a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1178,6 +1178,8 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + iwl_disable_interrupts(trans); /* @@ -1189,6 +1191,8 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) iwl_pcie_disable_ict(trans); + synchronize_irq(trans_pcie->pci_dev->irq); + iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); iwl_clear_bit(trans, CSR_GP_CNTRL, @@ -1326,7 +1330,10 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) spin_unlock(&trans_pcie->irq_lock); iwl_pcie_disable_ict(trans); + mutex_unlock(&trans_pcie->mutex); + + synchronize_irq(trans_pcie->pci_dev->irq); } static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) -- cgit v1.3-6-gb490 From 31f920b63ae8ff5bf278a00dd8478e58ed89ff95 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 2 Jul 2015 14:53:02 +0300 Subject: iwlwifi: pcie: don't warn on long MPDUs when supported In iwlmvm firmwares, the Byte count written in the scheduler byte count table is in DWORDs and not in bytes. We should check that this value fits in the 12 bits and the value can be either in bits of in DWORD or bytes depending on the firmware. Check the value after the translation to DWORDs is done (if needed). Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/tx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index c6572ffb8ae2..90d02d5f4881 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -219,8 +219,6 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans, scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; - WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); - sta_id = tx_cmd->sta_id; sec_ctl = tx_cmd->sec_ctl; @@ -239,6 +237,9 @@ static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans, if (trans_pcie->bc_table_dword) len = DIV_ROUND_UP(len, 4); + if (WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX)) + return; + bc_ent = cpu_to_le16(len | (sta_id << 12)); scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; -- cgit v1.3-6-gb490 From 30f27df9ba44422b718d244a677b1cc6a5bd5ded Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 30 Jun 2015 14:45:40 +0200 Subject: iwlwifi: remove command header flags field The 'flags' field really has been reserved in the firmware API for a very long time, probably since 4965. As a consequence, the field is always 0 and checking for a IWL_CMD_FAILED_MSK flag makes no sense. Rename the field to 'reserved', get rid of IWL_CMD_FAILED_MSK and all the code for it. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/sta.c | 44 ++++++++++++-------------------- drivers/net/wireless/iwlwifi/iwl-trans.h | 6 +---- drivers/net/wireless/iwlwifi/mvm/fw.c | 7 ----- drivers/net/wireless/iwlwifi/mvm/nvm.c | 12 --------- drivers/net/wireless/iwlwifi/mvm/tdls.c | 9 +------ drivers/net/wireless/iwlwifi/mvm/utils.c | 5 ---- drivers/net/wireless/iwlwifi/pcie/tx.c | 2 +- 7 files changed, 19 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index c18aa3e950d5..0fa67d3b7235 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -65,12 +65,6 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv, { struct iwl_add_sta_resp *add_sta_resp = (void *)pkt->data; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", - pkt->hdr.flags); - return; - } - IWL_DEBUG_INFO(priv, "Processing response for adding station\n"); spin_lock_bh(&priv->sta_lock); @@ -136,8 +130,7 @@ int iwl_send_add_sta(struct iwl_priv *priv, add_sta_resp = (void *)pkt->data; /* debug messages are printed in the handler */ - if (!(pkt->hdr.flags & IWL_CMD_FAILED_MSK) && - add_sta_resp->status == ADD_STA_SUCCESS_MSK) { + if (add_sta_resp->status == ADD_STA_SUCCESS_MSK) { spin_lock_bh(&priv->sta_lock); ret = iwl_sta_ucode_activate(priv, sta_id); spin_unlock_bh(&priv->sta_lock); @@ -431,6 +424,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, struct iwl_rx_packet *pkt; int ret; struct iwl_rem_sta_cmd rm_sta_cmd; + struct iwl_rem_sta_resp *rem_sta_resp; struct iwl_host_cmd cmd = { .id = REPLY_REMOVE_STA, @@ -450,29 +444,23 @@ static int iwl_send_remove_station(struct iwl_priv *priv, return ret; pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", - pkt->hdr.flags); - ret = -EIO; - } + rem_sta_resp = (void *)pkt->data; - if (!ret) { - struct iwl_rem_sta_resp *rem_sta_resp = (void *)pkt->data; - switch (rem_sta_resp->status) { - case REM_STA_SUCCESS_MSK: - if (!temporary) { - spin_lock_bh(&priv->sta_lock); - iwl_sta_ucode_deactivate(priv, sta_id); - spin_unlock_bh(&priv->sta_lock); - } - IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); - break; - default: - ret = -EIO; - IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); - break; + switch (rem_sta_resp->status) { + case REM_STA_SUCCESS_MSK: + if (!temporary) { + spin_lock_bh(&priv->sta_lock); + iwl_sta_ucode_deactivate(priv, sta_id); + spin_unlock_bh(&priv->sta_lock); } + IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); + break; + default: + ret = -EIO; + IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); + break; } + iwl_free_resp(&cmd); return ret; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 7b6f095bac48..64769e44059e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -130,7 +130,7 @@ */ struct iwl_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ - u8 flags; /* 0:5 reserved, 6 abort, 7 internal */ + u8 reserved; /* * The driver sets up the sequence number to values of its choosing. * uCode does not use this value, but passes it back to the driver @@ -154,10 +154,6 @@ struct iwl_cmd_header { __le16 sequence; } __packed; -/* iwl_cmd_header flags value */ -#define IWL_CMD_FAILED_MSK 0x40 - - #define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */ #define FH_RSCSR_FRAME_INVALID 0x55550000 #define FH_RSCSR_FRAME_ALIGN 0x40 diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index a5dae09869fc..e905c07127fb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -444,12 +444,6 @@ static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm) return; pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(mvm, "Bad return from SHARED_MEM_CFG (0x%08X)\n", - pkt->hdr.flags); - goto exit; - } - mem_cfg = (void *)pkt->data; mvm->shared_mem_cfg.shared_mem_addr = @@ -473,7 +467,6 @@ static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm) le32_to_cpu(mem_cfg->page_buff_size); IWL_DEBUG_INFO(mvm, "SHARED MEM CFG: got memory offsets/sizes\n"); -exit: iwl_free_resp(&cmd); } diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 6dcdee725ff8..328187da7541 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -139,12 +139,6 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, return ret; pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(mvm, "Bad return from NVM_ACCES_COMMAND (0x%08X)\n", - pkt->hdr.flags); - ret = -EIO; - goto exit; - } /* Extract NVM response */ nvm_resp = (void *)pkt->data; @@ -652,12 +646,6 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2, return ERR_PTR(ret); pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(mvm, "Bad return from MCC_UPDATE_COMMAND (0x%08X)\n", - pkt->hdr.flags); - ret = -EIO; - goto exit; - } /* Extract MCC response */ mcc_resp = (void *)pkt->data; diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index 71802e7f7448..d44d02d16fe2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -169,18 +169,11 @@ static void iwl_mvm_tdls_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif) return; pkt = cmd.resp_pkt; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(mvm, "Bad return from TDLS_CONFIG_COMMAND (0x%08X)\n", - pkt->hdr.flags); - goto exit; - } - if (WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) != sizeof(*resp))) - goto exit; + WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) != sizeof(*resp)); /* we don't really care about the response at this point */ -exit: iwl_free_resp(&cmd); } diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index 3b016f95a8ed..f50ef822d65e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -166,11 +166,6 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, goto out_free_resp; } - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - ret = -EIO; - goto out_free_resp; - } - resp_len = iwl_rx_packet_payload_len(pkt); if (WARN_ON_ONCE(resp_len != sizeof(*resp))) { ret = -EIO; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 90d02d5f4881..553ae135464a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1420,7 +1420,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, /* set up the header */ out_cmd->hdr.cmd = cmd->id; - out_cmd->hdr.flags = 0; + out_cmd->hdr.reserved = 0; out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | INDEX_TO_SEQ(q->write_ptr)); -- cgit v1.3-6-gb490 From 6bcb00f6183d1eb5d9f8548fe823be7e6d95b912 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 7 Jun 2015 10:36:23 +0300 Subject: iwlwifi: mvm: remove IWL_UCODE_TLV_API_BASIC_DWELL All the supported firmwares support this API. This includes removing dwell per band, as band is no longer a factor in calculating the dwell. Only basic dwell is used and FW will calculate the actual dwell time. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 4 -- drivers/net/wireless/iwlwifi/mvm/scan.c | 86 +++++++----------------------- 2 files changed, 20 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index a9b5ae4ebec0..1c6f7b9588c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -247,9 +247,6 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR * @IWL_UCODE_TLV_API_TX_POWER_DEV: new API for tx power. - * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, - * regardless of the band or the number of the probes. FW will calculate - * the actual dwell time. * @IWL_UCODE_TLV_API_SCD_CFG: This firmware can configure the scheduler * through the dedicated host command. * @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too. @@ -266,7 +263,6 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = (__force iwl_ucode_tlv_api_t)9, IWL_UCODE_TLV_API_HDC_PHASE_0 = (__force iwl_ucode_tlv_api_t)10, IWL_UCODE_TLV_API_TX_POWER_DEV = (__force iwl_ucode_tlv_api_t)11, - IWL_UCODE_TLV_API_BASIC_DWELL = (__force iwl_ucode_tlv_api_t)13, IWL_UCODE_TLV_API_SCD_CFG = (__force iwl_ucode_tlv_api_t)15, IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = (__force iwl_ucode_tlv_api_t)16, IWL_UCODE_TLV_API_ASYNC_DTM = (__force iwl_ucode_tlv_api_t)17, diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 9c70118841d7..b891fa54fa4a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -90,11 +90,9 @@ struct iwl_mvm_scan_params { int n_match_sets; struct iwl_scan_probe_req preq; struct cfg80211_match_set *match_sets; - struct _dwell { - u16 passive; - u16 active; - u16 fragmented; - } dwell[IEEE80211_NUM_BANDS]; + u16 passive_dwell; + u16 active_dwell; + u16 fragmented_dwell; struct { u8 iterations; u8 full_scan_mul; /* not used for UMAC */ @@ -147,34 +145,6 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band, return cpu_to_le32(IWL_RATE_6M_PLCP | tx_ant); } -/* - * If req->n_ssids > 0, it means we should do an active scan. - * In case of active scan w/o directed scan, we receive a zero-length SSID - * just to notify that this scan is active and not passive. - * In order to notify the FW of the number of SSIDs we wish to scan (including - * the zero-length one), we need to set the corresponding bits in chan->type, - * one for each SSID, and set the active bit (first). If the first SSID is - * already included in the probe template, so we need to set only - * req->n_ssids - 1 bits in addition to the first bit. - */ -static u16 iwl_mvm_get_active_dwell(struct iwl_mvm *mvm, - enum ieee80211_band band, int n_ssids) -{ - if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BASIC_DWELL)) - return 10; - if (band == IEEE80211_BAND_2GHZ) - return 20 + 3 * (n_ssids + 1); - return 10 + 2 * (n_ssids + 1); -} - -static u16 iwl_mvm_get_passive_dwell(struct iwl_mvm *mvm, - enum ieee80211_band band) -{ - if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_BASIC_DWELL)) - return 110; - return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10; -} - static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -191,7 +161,6 @@ static void iwl_mvm_scan_calc_dwell(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params) { int global_cnt = 0; - enum ieee80211_band band; u8 frag_passive_dwell = 0; ieee80211_iterate_active_interfaces_atomic(mvm->hw, @@ -227,14 +196,10 @@ static void iwl_mvm_scan_calc_dwell(struct iwl_mvm *mvm, /* * P2P device scan should not be fragmented to avoid negative * impact on P2P device discovery. Configure max_out_time to be - * equal to dwell time on passive channel. Take a longest - * possible value, one that corresponds to 2GHz band + * equal to dwell time on passive channel. */ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { - u32 passive_dwell = - iwl_mvm_get_passive_dwell(mvm, - IEEE80211_BAND_2GHZ); - params->max_out_time = passive_dwell; + params->max_out_time = 120; } else { params->passive_fragmented = true; } @@ -246,30 +211,21 @@ static void iwl_mvm_scan_calc_dwell(struct iwl_mvm *mvm, not_bound: - for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) { - if (params->passive_fragmented) - params->dwell[band].fragmented = frag_passive_dwell; + if (params->passive_fragmented) + params->fragmented_dwell = frag_passive_dwell; + + /* + * use only basic dwell time in scan command, regardless of the band or + * the number of the probes. FW will calculate the actual dwell time. + */ + params->passive_dwell = 110; + params->active_dwell = 10; - params->dwell[band].passive = iwl_mvm_get_passive_dwell(mvm, - band); - params->dwell[band].active = - iwl_mvm_get_active_dwell(mvm, band, params->n_ssids); - } IWL_DEBUG_SCAN(mvm, "scan parameters: max_out_time %d, suspend_time %d, passive_fragmented %d\n", params->max_out_time, params->suspend_time, params->passive_fragmented); - IWL_DEBUG_SCAN(mvm, - "dwell[IEEE80211_BAND_2GHZ]: passive %d, active %d, fragmented %d\n", - params->dwell[IEEE80211_BAND_2GHZ].passive, - params->dwell[IEEE80211_BAND_2GHZ].active, - params->dwell[IEEE80211_BAND_2GHZ].fragmented); - IWL_DEBUG_SCAN(mvm, - "dwell[IEEE80211_BAND_5GHZ]: passive %d, active %d, fragmented %d\n", - params->dwell[IEEE80211_BAND_5GHZ].passive, - params->dwell[IEEE80211_BAND_5GHZ].active, - params->dwell[IEEE80211_BAND_5GHZ].fragmented); } static inline bool iwl_mvm_rrm_scan_needed(struct iwl_mvm *mvm) @@ -743,11 +699,10 @@ static void iwl_mvm_scan_lmac_dwell(struct iwl_mvm *mvm, struct iwl_scan_req_lmac *cmd, struct iwl_mvm_scan_params *params) { - cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active; - cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive; + cmd->active_dwell = params->active_dwell; + cmd->passive_dwell = params->passive_dwell; if (params->passive_fragmented) - cmd->fragmented_dwell = - params->dwell[IEEE80211_BAND_2GHZ].fragmented; + cmd->fragmented_dwell = params->fragmented_dwell; cmd->max_out_time = cpu_to_le32(params->max_out_time); cmd->suspend_time = cpu_to_le32(params->suspend_time); cmd->scan_prio = iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6); @@ -1005,11 +960,10 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, struct iwl_scan_req_umac *cmd, struct iwl_mvm_scan_params *params) { - cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active; - cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive; + cmd->active_dwell = params->active_dwell; + cmd->passive_dwell = params->passive_dwell; if (params->passive_fragmented) - cmd->fragmented_dwell = - params->dwell[IEEE80211_BAND_2GHZ].fragmented; + cmd->fragmented_dwell = params->fragmented_dwell; cmd->max_out_time = cpu_to_le32(params->max_out_time); cmd->suspend_time = cpu_to_le32(params->suspend_time); cmd->scan_priority = -- cgit v1.3-6-gb490 From ce7929186a390b8630953be6d8225a9ae88030af Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Tue, 2 Jun 2015 18:06:16 +0300 Subject: iwlwifi: mvm: add basic Time of Flight (802.11mc FTM) support ToF is a time based method for measurement of the WiFi device location within a WiFi environment. The driver functionality provided by this patch is the interface for communication with FW and receiving location related updates from the FW. The interface provided by this patch is via debugfs. Signed-off-by: Gregory Greenman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 + drivers/net/wireless/iwlwifi/mvm/Makefile | 1 + drivers/net/wireless/iwlwifi/mvm/constants.h | 1 + drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c | 751 +++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h | 391 +++++++++++++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 5 + drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 + drivers/net/wireless/iwlwifi/mvm/ops.c | 5 + drivers/net/wireless/iwlwifi/mvm/tof.c | 311 ++++++++++ drivers/net/wireless/iwlwifi/mvm/tof.h | 94 ++++ 10 files changed, 1563 insertions(+) create mode 100644 drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h create mode 100644 drivers/net/wireless/iwlwifi/mvm/tof.c create mode 100644 drivers/net/wireless/iwlwifi/mvm/tof.h (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 1c6f7b9588c4..c31cf828fb25 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -280,6 +280,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. * @IWL_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer + * @IWL_UCODE_TLV_CAPA_TOF_SUPPORT: supports Time of Flight (802.11mc FTM) * @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current * tx power value into TPC Report action frame and Link Measurement Report @@ -307,6 +308,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_LAR_SUPPORT = (__force iwl_ucode_tlv_capa_t)1, IWL_UCODE_TLV_CAPA_UMAC_SCAN = (__force iwl_ucode_tlv_capa_t)2, IWL_UCODE_TLV_CAPA_BEAMFORMER = (__force iwl_ucode_tlv_capa_t)3, + IWL_UCODE_TLV_CAPA_TOF_SUPPORT = (__force iwl_ucode_tlv_capa_t)5, IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = (__force iwl_ucode_tlv_capa_t)6, IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = (__force iwl_ucode_tlv_capa_t)8, IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = (__force iwl_ucode_tlv_capa_t)9, diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile index 2d7c3ea3c4f8..8c2c3d13b092 100644 --- a/drivers/net/wireless/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/iwlwifi/mvm/Makefile @@ -6,6 +6,7 @@ iwlmvm-y += power.o coex.o coex_legacy.o iwlmvm-y += tt.o offloading.o tdls.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o +iwlmvm-y += tof.o iwlmvm-$(CONFIG_PM_SLEEP) += d3.o ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index beba375489f1..b8ee3121fbd2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -102,6 +102,7 @@ #define IWL_MVM_QUOTA_THRESHOLD 4 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0 #define IWL_MVM_RS_DISABLE_P2P_MIMO 0 +#define IWL_MVM_TOF_IS_RESPONDER 0 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index 5c8a65de0e77..ddb1c844827b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -63,6 +63,7 @@ * *****************************************************************************/ #include "mvm.h" +#include "fw-api-tof.h" #include "debugfs.h" static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, @@ -497,6 +498,731 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static inline char *iwl_dbgfs_is_match(char *name, char *buf) +{ + int len = strlen(name); + + return !strncmp(name, buf, len) ? buf + len : NULL; +} + +static ssize_t iwl_dbgfs_tof_enable_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; + int value, ret = -EINVAL; + char *data; + + mutex_lock(&mvm->mutex); + + data = iwl_dbgfs_is_match("tof_disabled=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.tof_cfg.tof_disabled = value; + goto out; + } + + data = iwl_dbgfs_is_match("one_sided_disabled=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.tof_cfg.one_sided_disabled = value; + goto out; + } + + data = iwl_dbgfs_is_match("is_debug_mode=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.tof_cfg.is_debug_mode = value; + goto out; + } + + data = iwl_dbgfs_is_match("is_buf=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.tof_cfg.is_buf_required = value; + goto out; + } + + data = iwl_dbgfs_is_match("send_tof_cfg=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0 && value) { + ret = iwl_mvm_tof_config_cmd(mvm); + goto out; + } + } + +out: + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_enable_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); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[256]; + int pos = 0; + const size_t bufsz = sizeof(buf); + struct iwl_tof_config_cmd *cmd; + + cmd = &mvm->tof_data.tof_cfg; + + mutex_lock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, "tof_disabled = %d\n", + cmd->tof_disabled); + pos += scnprintf(buf + pos, bufsz - pos, "one_sided_disabled = %d\n", + cmd->one_sided_disabled); + pos += scnprintf(buf + pos, bufsz - pos, "is_debug_mode = %d\n", + cmd->is_debug_mode); + pos += scnprintf(buf + pos, bufsz - pos, "is_buf_required = %d\n", + cmd->is_buf_required); + + mutex_unlock(&mvm->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_responder_params_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; + int value, ret = 0; + char *data; + + mutex_lock(&mvm->mutex); + + data = iwl_dbgfs_is_match("burst_period=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (!ret) + mvm->tof_data.responder_cfg.burst_period = + cpu_to_le16(value); + goto out; + } + + data = iwl_dbgfs_is_match("min_delta_ftm=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.min_delta_ftm = value; + goto out; + } + + data = iwl_dbgfs_is_match("burst_duration=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.burst_duration = value; + goto out; + } + + data = iwl_dbgfs_is_match("num_of_burst_exp=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.num_of_burst_exp = value; + goto out; + } + + data = iwl_dbgfs_is_match("abort_responder=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.abort_responder = value; + goto out; + } + + data = iwl_dbgfs_is_match("get_ch_est=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.get_ch_est = value; + goto out; + } + + data = iwl_dbgfs_is_match("recv_sta_req_params=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.recv_sta_req_params = value; + goto out; + } + + data = iwl_dbgfs_is_match("channel_num=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.channel_num = value; + goto out; + } + + data = iwl_dbgfs_is_match("bandwidth=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.bandwidth = value; + goto out; + } + + data = iwl_dbgfs_is_match("rate=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.rate = value; + goto out; + } + + data = iwl_dbgfs_is_match("bssid=", buf); + if (data) { + u8 *mac = mvm->tof_data.responder_cfg.bssid; + + if (!mac_pton(data, mac)) { + ret = -EINVAL; + goto out; + } + } + + data = iwl_dbgfs_is_match("tsf_timer_offset_msecs=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.tsf_timer_offset_msecs = + cpu_to_le16(value); + goto out; + } + + data = iwl_dbgfs_is_match("toa_offset=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.toa_offset = + cpu_to_le16(value); + goto out; + } + + data = iwl_dbgfs_is_match("ctrl_ch_position=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.ctrl_ch_position = value; + goto out; + } + + data = iwl_dbgfs_is_match("ftm_per_burst=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.ftm_per_burst = value; + goto out; + } + + data = iwl_dbgfs_is_match("ftm_resp_ts_avail=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.ftm_resp_ts_avail = value; + goto out; + } + + data = iwl_dbgfs_is_match("asap_mode=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.responder_cfg.asap_mode = value; + goto out; + } + + data = iwl_dbgfs_is_match("send_responder_cfg=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0 && value) { + ret = iwl_mvm_tof_responder_cmd(mvm, vif); + goto out; + } + } + +out: + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_responder_params_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); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[256]; + int pos = 0; + const size_t bufsz = sizeof(buf); + struct iwl_tof_responder_config_cmd *cmd; + + cmd = &mvm->tof_data.responder_cfg; + + mutex_lock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, "burst_period = %d\n", + le16_to_cpu(cmd->burst_period)); + pos += scnprintf(buf + pos, bufsz - pos, "burst_duration = %d\n", + cmd->burst_duration); + pos += scnprintf(buf + pos, bufsz - pos, "bandwidth = %d\n", + cmd->bandwidth); + pos += scnprintf(buf + pos, bufsz - pos, "channel_num = %d\n", + cmd->channel_num); + pos += scnprintf(buf + pos, bufsz - pos, "ctrl_ch_position = 0x%x\n", + cmd->ctrl_ch_position); + pos += scnprintf(buf + pos, bufsz - pos, "bssid = %pM\n", + cmd->bssid); + pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %d\n", + cmd->min_delta_ftm); + pos += scnprintf(buf + pos, bufsz - pos, "num_of_burst_exp = %d\n", + cmd->num_of_burst_exp); + pos += scnprintf(buf + pos, bufsz - pos, "rate = %d\n", cmd->rate); + pos += scnprintf(buf + pos, bufsz - pos, "abort_responder = %d\n", + cmd->abort_responder); + pos += scnprintf(buf + pos, bufsz - pos, "get_ch_est = %d\n", + cmd->get_ch_est); + pos += scnprintf(buf + pos, bufsz - pos, "recv_sta_req_params = %d\n", + cmd->recv_sta_req_params); + pos += scnprintf(buf + pos, bufsz - pos, "ftm_per_burst = %d\n", + cmd->ftm_per_burst); + pos += scnprintf(buf + pos, bufsz - pos, "ftm_resp_ts_avail = %d\n", + cmd->ftm_resp_ts_avail); + pos += scnprintf(buf + pos, bufsz - pos, "asap_mode = %d\n", + cmd->asap_mode); + pos += scnprintf(buf + pos, bufsz - pos, + "tsf_timer_offset_msecs = %d\n", + le16_to_cpu(cmd->tsf_timer_offset_msecs)); + pos += scnprintf(buf + pos, bufsz - pos, "toa_offset = %d\n", + le16_to_cpu(cmd->toa_offset)); + + mutex_unlock(&mvm->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_request_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; + int value, ret = 0; + char *data; + + mutex_lock(&mvm->mutex); + + data = iwl_dbgfs_is_match("request_id=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.request_id = value; + goto out; + } + + data = iwl_dbgfs_is_match("initiator=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.initiator = value; + goto out; + } + + data = iwl_dbgfs_is_match("one_sided_los_disable=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.one_sided_los_disable = value; + goto out; + } + + data = iwl_dbgfs_is_match("req_timeout=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.req_timeout = value; + goto out; + } + + data = iwl_dbgfs_is_match("report_policy=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.report_policy = value; + goto out; + } + + data = iwl_dbgfs_is_match("macaddr_random=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.macaddr_random = value; + goto out; + } + + data = iwl_dbgfs_is_match("num_of_ap=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req.num_of_ap = value; + goto out; + } + + data = iwl_dbgfs_is_match("macaddr_template=", buf); + if (data) { + u8 mac[ETH_ALEN]; + + if (!mac_pton(data, mac)) { + ret = -EINVAL; + goto out; + } + memcpy(mvm->tof_data.range_req.macaddr_template, mac, ETH_ALEN); + } + + data = iwl_dbgfs_is_match("macaddr_mask=", buf); + if (data) { + u8 mac[ETH_ALEN]; + + if (!mac_pton(data, mac)) { + ret = -EINVAL; + goto out; + } + memcpy(mvm->tof_data.range_req.macaddr_mask, mac, ETH_ALEN); + } + + data = iwl_dbgfs_is_match("ap=", buf); + if (data) { + struct iwl_tof_range_req_ap_entry ap; + int size = sizeof(struct iwl_tof_range_req_ap_entry); + u16 burst_period; + u8 *mac = ap.bssid; + int i; + + if (sscanf(data, "%d %hhd %hhx %hhx" + "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx" + "%hhx %hhx %hx" + "%hhx %hhx %x" + "%hhx %hhx %hhx %hhx", + &i, &ap.channel_num, &ap.bandwidth, + &ap.ctrl_ch_position, + mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5, + &ap.measure_type, &ap.num_of_bursts, + &burst_period, + &ap.samples_per_burst, &ap.retries_per_sample, + &ap.tsf_delta, &ap.location_req, &ap.asap_mode, + &ap.enable_dyn_ack, &ap.rssi) != 20) { + ret = -EINVAL; + goto out; + } + if (i > IWL_MVM_TOF_MAX_APS) { + IWL_ERR(mvm, "Invalid AP index %d\n", i); + ret = -EINVAL; + goto out; + } + + ap.burst_period = cpu_to_le16(burst_period); + + memcpy(&mvm->tof_data.range_req.ap[i], &ap, size); + goto out; + } + + data = iwl_dbgfs_is_match("send_range_request=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0 && value) { + ret = iwl_mvm_tof_range_request_cmd(mvm, vif); + goto out; + } + } + +out: + mutex_unlock(&mvm->mutex); + return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_range_request_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); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[512]; + int pos = 0; + const size_t bufsz = sizeof(buf); + struct iwl_tof_range_req_cmd *cmd; + int i; + + cmd = &mvm->tof_data.range_req; + + mutex_lock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, "request_id= %d\n", + cmd->request_id); + pos += scnprintf(buf + pos, bufsz - pos, "initiator= %d\n", + cmd->initiator); + pos += scnprintf(buf + pos, bufsz - pos, "one_sided_los_disable = %d\n", + cmd->one_sided_los_disable); + pos += scnprintf(buf + pos, bufsz - pos, "req_timeout= %d\n", + cmd->req_timeout); + pos += scnprintf(buf + pos, bufsz - pos, "report_policy= %d\n", + cmd->report_policy); + pos += scnprintf(buf + pos, bufsz - pos, "macaddr_random= %d\n", + cmd->macaddr_random); + pos += scnprintf(buf + pos, bufsz - pos, "macaddr_template= %pM\n", + cmd->macaddr_template); + pos += scnprintf(buf + pos, bufsz - pos, "macaddr_mask= %pM\n", + cmd->macaddr_mask); + pos += scnprintf(buf + pos, bufsz - pos, "num_of_ap= %d\n", + cmd->num_of_ap); + for (i = 0; i < cmd->num_of_ap; i++) { + struct iwl_tof_range_req_ap_entry *ap = &cmd->ap[i]; + + pos += scnprintf(buf + pos, bufsz - pos, + "ap %.2d: channel_num=%hhx bw=%hhx" + " control=%hhx bssid=%pM type=%hhx" + " num_of_bursts=%hhx burst_period=%hx ftm=%hhx" + " retries=%hhx tsf_delta=%x location_req=%hhx " + " asap=%hhx enable=%hhx rssi=%hhx\n", + i, ap->channel_num, ap->bandwidth, + ap->ctrl_ch_position, ap->bssid, + ap->measure_type, ap->num_of_bursts, + ap->burst_period, ap->samples_per_burst, + ap->retries_per_sample, ap->tsf_delta, + ap->location_req, ap->asap_mode, + ap->enable_dyn_ack, ap->rssi); + } + + mutex_unlock(&mvm->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_req_ext_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; + int value, ret = 0; + char *data; + + mutex_lock(&mvm->mutex); + + data = iwl_dbgfs_is_match("tsf_timer_offset_msec=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req_ext.tsf_timer_offset_msec = + cpu_to_le16(value); + goto out; + } + + data = iwl_dbgfs_is_match("min_delta_ftm=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req_ext.min_delta_ftm = value; + goto out; + } + + data = iwl_dbgfs_is_match("ftm_format_and_bw20M=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req_ext.ftm_format_and_bw20M = + value; + goto out; + } + + data = iwl_dbgfs_is_match("ftm_format_and_bw40M=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req_ext.ftm_format_and_bw40M = + value; + goto out; + } + + data = iwl_dbgfs_is_match("ftm_format_and_bw80M=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.range_req_ext.ftm_format_and_bw80M = + value; + goto out; + } + + data = iwl_dbgfs_is_match("send_range_req_ext=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0 && value) { + ret = iwl_mvm_tof_range_request_ext_cmd(mvm, vif); + goto out; + } + } + +out: + mutex_unlock(&mvm->mutex); + return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_range_req_ext_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); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[256]; + int pos = 0; + const size_t bufsz = sizeof(buf); + struct iwl_tof_range_req_ext_cmd *cmd; + + cmd = &mvm->tof_data.range_req_ext; + + mutex_lock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, + "tsf_timer_offset_msec = %hx\n", + cmd->tsf_timer_offset_msec); + pos += scnprintf(buf + pos, bufsz - pos, "min_delta_ftm = %hhx\n", + cmd->min_delta_ftm); + pos += scnprintf(buf + pos, bufsz - pos, + "ftm_format_and_bw20M = %hhx\n", + cmd->ftm_format_and_bw20M); + pos += scnprintf(buf + pos, bufsz - pos, + "ftm_format_and_bw40M = %hhx\n", + cmd->ftm_format_and_bw40M); + pos += scnprintf(buf + pos, bufsz - pos, + "ftm_format_and_bw80M = %hhx\n", + cmd->ftm_format_and_bw80M); + + mutex_unlock(&mvm->mutex); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_abort_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; + int value, ret = 0; + int abort_id; + char *data; + + mutex_lock(&mvm->mutex); + + data = iwl_dbgfs_is_match("abort_id=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0) + mvm->tof_data.last_abort_id = value; + goto out; + } + + data = iwl_dbgfs_is_match("send_range_abort=", buf); + if (data) { + ret = kstrtou32(data, 10, &value); + if (ret == 0 && value) { + abort_id = mvm->tof_data.last_abort_id; + ret = iwl_mvm_tof_range_abort_cmd(mvm, abort_id); + goto out; + } + } + +out: + mutex_unlock(&mvm->mutex); + return ret ?: count; +} + +static ssize_t iwl_dbgfs_tof_range_abort_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); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[32]; + int pos = 0; + const size_t bufsz = sizeof(buf); + int last_abort_id; + + mutex_lock(&mvm->mutex); + last_abort_id = mvm->tof_data.last_abort_id; + mutex_unlock(&mvm->mutex); + + pos += scnprintf(buf + pos, bufsz - pos, "last_abort_id = %d\n", + last_abort_id); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_tof_range_response_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); + struct iwl_mvm *mvm = mvmvif->mvm; + char *buf; + int pos = 0; + const size_t bufsz = sizeof(struct iwl_tof_range_rsp_ntfy) + 256; + struct iwl_tof_range_rsp_ntfy *cmd; + int i, ret; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&mvm->mutex); + cmd = &mvm->tof_data.range_resp; + + pos += scnprintf(buf + pos, bufsz - pos, "request_id = %d\n", + cmd->request_id); + pos += scnprintf(buf + pos, bufsz - pos, "status = %d\n", + cmd->request_status); + pos += scnprintf(buf + pos, bufsz - pos, "last_in_batch = %d\n", + cmd->last_in_batch); + pos += scnprintf(buf + pos, bufsz - pos, "num_of_aps = %d\n", + cmd->num_of_aps); + for (i = 0; i < cmd->num_of_aps; i++) { + struct iwl_tof_range_rsp_ap_entry_ntfy *ap = &cmd->ap[i]; + + pos += scnprintf(buf + pos, bufsz - pos, + "ap %.2d: bssid=%pM status=%hhx bw=%hhx" + " rtt=%x rtt_var=%x rtt_spread=%x" + " rssi=%hhx rssi_spread=%hhx" + " range=%x range_var=%x" + " time_stamp=%x\n", + i, ap->bssid, ap->measure_status, + ap->measure_bw, + ap->rtt, ap->rtt_variance, ap->rtt_spread, + ap->rssi, ap->rssi_spread, ap->range, + ap->range_variance, ap->timestamp); + } + mutex_unlock(&mvm->mutex); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, size_t count, loff_t *ppos) { @@ -628,6 +1354,12 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256); MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_enable, 32); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_request, 512); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32); +MVM_DEBUGFS_READ_FILE_OPS(tof_range_response); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32); void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -671,6 +1403,25 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, S_IRUSR | S_IWUSR); + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) && + !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) { + if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP) + MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params, + mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); + + MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir, + S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir, + S_IRUSR); + } + /* * Create symlink for convenience pointing to interface specific * debugfs entries for the driver. For example, under diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h new file mode 100644 index 000000000000..287c9ecb0fb1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h @@ -0,0 +1,391 @@ +/****************************************************************************** + * + * 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) 2015 Intel Deutschland GmbH + * + * 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) 2015 Intel Deutschland GmbH + * 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_api_tof_h__ +#define __fw_api_tof_h__ + +#include "fw-api.h" + +/* ToF sub-group command IDs */ +enum iwl_mvm_tof_sub_grp_ids { + TOF_RANGE_REQ_CMD = 0x1, + TOF_CONFIG_CMD = 0x2, + TOF_RANGE_ABORT_CMD = 0x3, + TOF_RANGE_REQ_EXT_CMD = 0x4, + TOF_RESPONDER_CONFIG_CMD = 0x5, + TOF_NW_INITIATED_RES_SEND_CMD = 0x6, + TOF_NEIGHBOR_REPORT_REQ_CMD = 0x7, + TOF_NEIGHBOR_REPORT_RSP_NOTIF = 0xFC, + TOF_NW_INITIATED_REQ_RCVD_NOTIF = 0xFD, + TOF_RANGE_RESPONSE_NOTIF = 0xFE, + TOF_MCSI_DEBUG_NOTIF = 0xFB, +}; + +/** + * struct iwl_tof_config_cmd - ToF configuration + * @tof_disabled: 0 enabled, 1 - disabled + * @one_sided_disabled: 0 enabled, 1 - disabled + * @is_debug_mode: 1 debug mode, 0 - otherwise + * @is_buf_required: 1 channel estimation buffer required, 0 - otherwise + */ +struct iwl_tof_config_cmd { + struct iwl_mvm_umac_cmd_hdr hdr; + __le32 sub_grp_cmd_id; + u8 tof_disabled; + u8 one_sided_disabled; + u8 is_debug_mode; + u8 is_buf_required; +} __packed; + +/** + * struct iwl_tof_responder_config_cmd - ToF AP mode (for debug) + * @burst_period: future use: (currently hard coded in the LMAC) + * The interval between two sequential bursts. + * @min_delta_ftm: future use: (currently hard coded in the LMAC) + * The minimum delay between two sequential FTM Responses + * in the same burst. + * @burst_duration: future use: (currently hard coded in the LMAC) + * The total time for all FTMs handshake in the same burst. + * Affect the time events duration in the LMAC. + * @num_of_burst_exp: future use: (currently hard coded in the LMAC) + * The number of bursts for the current ToF request. Affect + * the number of events allocations in the current iteration. + * @get_ch_est: for xVT only, NA for driver + * @abort_responder: when set to '1' - Responder will terminate its activity + * (all other fields in the command are ignored) + * @recv_sta_req_params: 1 - Responder will ignore the other Responder's + * params and use the recomended Initiator params. + * 0 - otherwise + * @channel_num: current AP Channel + * @bandwidth: current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz + * @rate: current AP rate + * @ctrl_ch_position: coding of the control channel position relative to + * the center frequency. + * 40MHz 0 below center, 1 above center + * 80MHz bits [0..1]: 0 the near 20MHz to the center, + * 1 the far 20MHz to the center + * bit[2] as above 40MHz + * @ftm_per_burst: FTMs per Burst + * @ftm_resp_ts_avail: '0' - we don't measure over the Initial FTM Response, + * '1' - we measure over the Initial FTM Response + * @asap_mode: ASAP / Non ASAP mode for the current WLS station + * @sta_id: index of the AP STA when in AP mode + * @tsf_timer_offset_msecs: The dictated time offset (mSec) from the AP's TSF + * @toa_offset: Artificial addition [0.1nsec] for the ToA - to be used for debug + * purposes, simulating station movement by adding various values + * to this field + * @bssid: Current AP BSSID + */ +struct iwl_tof_responder_config_cmd { + struct iwl_mvm_umac_cmd_hdr hdr; + __le32 sub_grp_cmd_id; + __le16 burst_period; + u8 min_delta_ftm; + u8 burst_duration; + u8 num_of_burst_exp; + u8 get_ch_est; + u8 abort_responder; + u8 recv_sta_req_params; + u8 channel_num; + u8 bandwidth; + u8 rate; + u8 ctrl_ch_position; + u8 ftm_per_burst; + u8 ftm_resp_ts_avail; + u8 asap_mode; + u8 sta_id; + __le16 tsf_timer_offset_msecs; + __le16 toa_offset; + u8 bssid[ETH_ALEN]; +} __packed; + +/** + * struct iwl_tof_range_request_ext_cmd - extended range req for WLS + * @tsf_timer_offset_msec: the recommended time offset (mSec) from the AP's TSF + * @min_delta_ftm: Minimal time between two consecutive measurements, + * in units of 100us. 0 means no preference by station + * @ftm_format_and_bw20M: FTM Channel Spacing/Format for 20MHz: recommended + * value be sent to the AP + * @ftm_format_and_bw40M: FTM Channel Spacing/Format for 40MHz: recommended + * value to be sent to the AP + * @ftm_format_and_bw80M: FTM Channel Spacing/Format for 80MHz: recommended + * value to be sent to the AP + */ +struct iwl_tof_range_req_ext_cmd { + struct iwl_mvm_umac_cmd_hdr hdr; + __le32 sub_grp_cmd_id; + __le16 tsf_timer_offset_msec; + __le16 reserved; + u8 min_delta_ftm; + u8 ftm_format_and_bw20M; + u8 ftm_format_and_bw40M; + u8 ftm_format_and_bw80M; +} __packed; + +#define IWL_MVM_TOF_MAX_APS 21 + +/** + * struct iwl_tof_range_req_ap_entry - AP configuration parameters + * @channel_num: Current AP Channel + * @bandwidth: Current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz + * @tsf_delta_direction: TSF relatively to the subject AP + * @ctrl_ch_position: Coding of the control channel position relative to the + * center frequency. + * 40MHz 0 below center, 1 above center + * 80MHz bits [0..1]: 0 the near 20MHz to the center, + * 1 the far 20MHz to the center + * bit[2] as above 40MHz + * @bssid: AP's bss id + * @measure_type: Measurement type: 0 - two sided, 1 - One sided + * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of the + * number of measurement iterations (min 2^0 = 1, max 2^14) + * @burst_period: Recommended value to be sent to the AP. Measurement + * periodicity In units of 100ms. ignored if num_of_bursts = 0 + * @samples_per_burst: 2-sided: the number of FTMs pairs in single Burst (1-31) + * 1-sided: how many rts/cts pairs should be used per burst. + * @retries_per_sample: Max number of retries that the LMAC should send + * in case of no replies by the AP. + * @tsf_delta: TSF Delta in units of microseconds. + * The difference between the AP TSF and the device local clock. + * @location_req: Location Request Bit[0] LCI should be sent in the FTMR + * Bit[1] Civic should be sent in the FTMR + * @asap_mode: 0 - non asap mode, 1 - asap mode (not relevant for one sided) + * @enable_dyn_ack: Enable Dynamic ACK BW. + * 0 Initiator interact with regular AP + * 1 Initiator interact with Responder machine: need to send the + * Initiator Acks with HT 40MHz / 80MHz, since the Responder should + * use it for its ch est measurement (this flag will be set when we + * configure the opposite machine to be Responder). + * @rssi: Last received value + * leagal values: -128-0 (0x7f). above 0x0 indicating an invalid value. + */ +struct iwl_tof_range_req_ap_entry { + u8 channel_num; + u8 bandwidth; + u8 tsf_delta_direction; + u8 ctrl_ch_position; + u8 bssid[ETH_ALEN]; + u8 measure_type; + u8 num_of_bursts; + __le16 burst_period; + u8 samples_per_burst; + u8 retries_per_sample; + __le32 tsf_delta; + u8 location_req; + u8 asap_mode; + u8 enable_dyn_ack; + s8 rssi; +} __packed; + +/** + * enum iwl_tof_response_mode + * @IWL_MVM_TOF_RESPOSE_ASAP: report each AP measurement separately as soon as + * possible (not supported for this release) + * @IWL_MVM_TOF_RESPOSE_TIMEOUT: report all AP measurements as a batch upon + * timeout expiration + * @IWL_MVM_TOF_RESPOSE_COMPLETE: report all AP measurements as a batch at the + * earlier of: measurements completion / timeout + * expiration. + */ +enum iwl_tof_response_mode { + IWL_MVM_TOF_RESPOSE_ASAP = 1, + IWL_MVM_TOF_RESPOSE_TIMEOUT, + IWL_MVM_TOF_RESPOSE_COMPLETE, +}; + +/** + * struct iwl_tof_range_req_cmd - start measurement cmd + * @request_id: A Token incremented per request. The same Token will be + * sent back in the range response + * @initiator: 0- NW initiated, 1 - Client Initiated + * @one_sided_los_disable: '0'- run ML-Algo for both ToF/OneSided, + * '1' - run ML-Algo for ToF only + * @req_timeout: Requested timeout of the response in units of 100ms. + * This is equivalent to the session time configured to the + * LMAC in Initiator Request + * @report_policy: Supported partially for this release: For current release - + * the range report will be uploaded as a batch when ready or + * when the session is done (successfully / partially). + * one of iwl_tof_response_mode. + * @num_of_ap: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + * @macaddr_random: '0' Use default source MAC address (i.e. p2_p), + * '1' Use MAC Address randomization according to the below + * @macaddr_mask: Bits set to 0 shall be copied from the MAC address template. + * Bits set to 1 shall be randomized by the UMAC + */ +struct iwl_tof_range_req_cmd { + struct iwl_mvm_umac_cmd_hdr hdr; + __le32 sub_grp_cmd_id; + u8 request_id; + u8 initiator; + u8 one_sided_los_disable; + u8 req_timeout; + u8 report_policy; + u8 los_det_disable; + u8 num_of_ap; + u8 macaddr_random; + u8 macaddr_template[ETH_ALEN]; + u8 macaddr_mask[ETH_ALEN]; + struct iwl_tof_range_req_ap_entry ap[IWL_MVM_TOF_MAX_APS]; +} __packed; + +/** + * struct iwl_tof_gen_resp_cmd - generic ToF response + */ +struct iwl_tof_gen_resp_cmd { + __le32 sub_grp_cmd_id; + u8 data[]; +} __packed; + +/** + * struct iwl_tof_range_rsp_ap_entry_ntfy - AP parameters (response) + * @measure_status: current APs measurement status + * @measure_bw: Current AP Bandwidth: 0 20MHz, 1 40MHz, 2 80MHz + * @rtt: The Round Trip Time that took for the last measurement for + * current AP [nSec] + * @rtt_variance: The Variance of the RTT values measured for current AP + * @rtt_spread: The Difference between the maximum and the minimum RTT + * values measured for current AP in the current session [nsec] + * @rssi: RSSI as uploaded in the Channel Estimation notification + * @rssi_spread: The Difference between the maximum and the minimum RSSI values + * measured for current AP in the current session + * @range: Measured range [cm] + * @range_variance: Measured range variance [cm] + * @timestamp: The GP2 Clock [usec] where Channel Estimation notification was + * uploaded by the LMAC + */ +struct iwl_tof_range_rsp_ap_entry_ntfy { + u8 bssid[ETH_ALEN]; + u8 measure_status; + u8 measure_bw; + __le32 rtt; + __le32 rtt_variance; + __le32 rtt_spread; + s8 rssi; + u8 rssi_spread; + __le16 reserved; + __le32 range; + __le32 range_variance; + __le32 timestamp; +} __packed; + +/** + * struct iwl_tof_range_rsp_ntfy - + * @request_id: A Token ID of the corresponding Range request + * @request_status: status of current measurement session + * @last_in_batch: reprot policy (when not all responses are uploaded at once) + * @num_of_aps: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + */ +struct iwl_tof_range_rsp_ntfy { + u8 request_id; + u8 request_status; + u8 last_in_batch; + u8 num_of_aps; + struct iwl_tof_range_rsp_ap_entry_ntfy ap[IWL_MVM_TOF_MAX_APS]; +} __packed; + +#define IWL_MVM_TOF_MCSI_BUF_SIZE (245) +/** + * struct iwl_tof_mcsi_notif - used for debug + * @token: token ID for the current session + * @role: '0' - initiator, '1' - responder + * @initiator_bssid: initiator machine + * @responder_bssid: responder machine + * @mcsi_buffer: debug data + */ +struct iwl_tof_mcsi_notif { + u8 token; + u8 role; + __le16 reserved; + u8 initiator_bssid[ETH_ALEN]; + u8 responder_bssid[ETH_ALEN]; + u8 mcsi_buffer[IWL_MVM_TOF_MCSI_BUF_SIZE * 4]; +} __packed; + +/** + * struct iwl_tof_neighbor_report_notif + * @bssid: BSSID of the AP which sent the report + * @request_token: same token as the corresponding request + * @status: + * @report_ie_len: the length of the response frame starting from the Element ID + * @data: the IEs + */ +struct iwl_tof_neighbor_report { + u8 bssid[ETH_ALEN]; + u8 request_token; + u8 status; + __le16 report_ie_len; + u8 data[]; +} __packed; + +/** + * struct iwl_tof_range_abort_cmd + * @request_id: corresponds to a range request + */ +struct iwl_tof_range_abort_cmd { + struct iwl_mvm_umac_cmd_hdr hdr; + __le32 sub_grp_cmd_id; + u8 request_id; + u8 reserved[3]; +} __packed; + +#endif diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 16e9ef49397f..2bc33faae5b4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -75,6 +75,7 @@ #include "fw-api-coex.h" #include "fw-api-scan.h" #include "fw-api-stats.h" +#include "fw-api-tof.h" /* Tx queue numbers */ enum { @@ -163,6 +164,10 @@ enum { CALIB_RES_NOTIF_PHY_DB = 0x6b, /* PHY_DB_CMD = 0x6c, */ + /* ToF - 802.11mc FTM */ + TOF_CMD = 0x10, + TOF_NOTIFICATION = 0x11, + /* Power - legacy power table command */ POWER_TABLE_CMD = 0x77, PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 1397e3e0d669..c980e8d9ac5a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -80,6 +80,7 @@ #include "sta.h" #include "fw-api.h" #include "constants.h" +#include "tof.h" #define IWL_INVALID_MAC80211_QUEUE 0xff #define IWL_MVM_MAX_ADDRESSES 5 @@ -823,6 +824,7 @@ struct iwl_mvm { struct iwl_mvm_shared_mem_cfg shared_mem_cfg; u32 ciphers[6]; + struct iwl_mvm_tof_data tof_data; }; /* Extract MVM priv from op_mode and _hw */ diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 51c2fd098c71..76b5557c1dde 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -259,6 +259,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(TDLS_CHANNEL_SWITCH_NOTIFICATION, iwl_mvm_rx_tdls_notif, true), RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false), + RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, true), }; #undef RX_HANDLER @@ -574,6 +575,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, /* rpm starts with a taken ref. only set the appropriate bit here. */ mvm->refs[IWL_MVM_REF_UCODE_DOWN] = 1; + iwl_mvm_tof_init(mvm); + return op_mode; out_unregister: @@ -621,6 +624,8 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) for (i = 0; i < NVM_MAX_NUM_SECTIONS; i++) kfree(mvm->nvm_sections[i].data); + iwl_mvm_tof_clean(mvm); + ieee80211_free_hw(mvm->hw); } diff --git a/drivers/net/wireless/iwlwifi/mvm/tof.c b/drivers/net/wireless/iwlwifi/mvm/tof.c new file mode 100644 index 000000000000..5a8e96f0293d --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tof.c @@ -0,0 +1,311 @@ +/****************************************************************************** + * + * 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) 2015 Intel Deutschland GmbH + * + * 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) 2015 Intel Deutschland GmbH + * 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 "mvm.h" +#include "fw-api-tof.h" + +#define IWL_MVM_TOF_RANGE_REQ_MAX_ID 256 + +void iwl_mvm_tof_init(struct iwl_mvm *mvm) +{ + struct iwl_mvm_tof_data *tof_data = &mvm->tof_data; + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return; + + memset(tof_data, 0, sizeof(*tof_data)); + + tof_data->tof_cfg.hdr.size = + cpu_to_le16(sizeof(struct iwl_tof_config_cmd) - + sizeof(struct iwl_mvm_umac_cmd_hdr)); + tof_data->tof_cfg.sub_grp_cmd_id = cpu_to_le32(TOF_CONFIG_CMD); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (IWL_MVM_TOF_IS_RESPONDER) { + tof_data->responder_cfg.hdr.size = + cpu_to_le16(sizeof(struct iwl_tof_responder_config_cmd) - + sizeof(struct iwl_mvm_umac_cmd_hdr)); + tof_data->responder_cfg.sub_grp_cmd_id = + cpu_to_le32(TOF_RESPONDER_CONFIG_CMD); + tof_data->responder_cfg.sta_id = IWL_MVM_STATION_COUNT; + } +#endif + + tof_data->range_req.hdr.size = + cpu_to_le16(sizeof(struct iwl_tof_range_req_cmd) - + sizeof(struct iwl_mvm_umac_cmd_hdr)); + tof_data->range_req.sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_REQ_CMD); + tof_data->range_req.req_timeout = 1; + tof_data->range_req.initiator = 1; + tof_data->range_req.report_policy = 3; + + tof_data->range_req_ext.hdr.size = + cpu_to_le16(sizeof(struct iwl_tof_range_req_ext_cmd) - + sizeof(struct iwl_mvm_umac_cmd_hdr)); + tof_data->range_req_ext.sub_grp_cmd_id = + cpu_to_le32(TOF_RANGE_REQ_EXT_CMD); + + mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; +} + +void iwl_mvm_tof_clean(struct iwl_mvm *mvm) +{ + struct iwl_mvm_tof_data *tof_data = &mvm->tof_data; + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return; + + memset(tof_data, 0, sizeof(*tof_data)); + mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; +} + +static void iwl_tof_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + bool *enabled = _data; + + /* non bss vif exists */ + if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) + *enabled = false; +} + +int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm) +{ + struct iwl_tof_config_cmd *cmd = &mvm->tof_data.tof_cfg; + bool enabled; + + lockdep_assert_held(&mvm->mutex); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return -EINVAL; + + ieee80211_iterate_active_interfaces_atomic(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_tof_iterator, &enabled); + if (!enabled) { + IWL_DEBUG_INFO(mvm, "ToF is not supported (non bss vif)\n"); + return -EINVAL; + } + + mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(*cmd), cmd); +} + +int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id) +{ + struct iwl_tof_range_abort_cmd cmd = { + .sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_ABORT_CMD), + .hdr.size = cpu_to_le16(sizeof(struct iwl_tof_range_abort_cmd) - + sizeof(struct iwl_mvm_umac_cmd_hdr)), + .request_id = id, + }; + + lockdep_assert_held(&mvm->mutex); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return -EINVAL; + + if (id != mvm->tof_data.active_range_request) { + IWL_ERR(mvm, "Invalid range request id %d (active %d)\n", + id, mvm->tof_data.active_range_request); + return -EINVAL; + } + + /* after abort is sent there's no active request anymore */ + mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + + return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(cmd), &cmd); +} + +#ifdef CONFIG_IWLWIFI_DEBUGFS +int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_tof_responder_config_cmd *cmd = &mvm->tof_data.responder_cfg; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + lockdep_assert_held(&mvm->mutex); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return -EINVAL; + + if (vif->p2p || vif->type != NL80211_IFTYPE_AP) { + IWL_ERR(mvm, "Cannot start responder, not in AP mode\n"); + return -EIO; + } + + cmd->sta_id = mvmvif->bcast_sta.sta_id; + return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(*cmd), cmd); +} +#endif + +int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_host_cmd cmd = { + .id = TOF_CMD, + .len = { sizeof(mvm->tof_data.range_req), }, + /* no copy because of the command size */ + .dataflags = { IWL_HCMD_DFL_NOCOPY, }, + }; + + lockdep_assert_held(&mvm->mutex); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return -EINVAL; + + if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) { + IWL_ERR(mvm, "Cannot send range request, not STA mode\n"); + return -EIO; + } + + /* nesting of range requests is not supported in FW */ + if (mvm->tof_data.active_range_request != + IWL_MVM_TOF_RANGE_REQ_MAX_ID) { + IWL_ERR(mvm, "Cannot send range req, already active req %d\n", + mvm->tof_data.active_range_request); + return -EIO; + } + + mvm->tof_data.active_range_request = mvm->tof_data.range_req.request_id; + + cmd.data[0] = &mvm->tof_data.range_req; + return iwl_mvm_send_cmd(mvm, &cmd); +} + +int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + lockdep_assert_held(&mvm->mutex); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT)) + return -EINVAL; + + if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) { + IWL_ERR(mvm, "Cannot send ext range req, not in STA mode\n"); + return -EIO; + } + + return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, + sizeof(mvm->tof_data.range_req_ext), + &mvm->tof_data.range_req_ext); +} + +static int iwl_mvm_tof_range_resp(struct iwl_mvm *mvm, void *data) +{ + struct iwl_tof_range_rsp_ntfy *resp = (void *)data; + + if (resp->request_id != mvm->tof_data.active_range_request) { + IWL_ERR(mvm, "Request id mismatch, got %d, active %d\n", + resp->request_id, mvm->tof_data.active_range_request); + return -EIO; + } + + memcpy(&mvm->tof_data.range_resp, resp, + sizeof(struct iwl_tof_range_rsp_ntfy)); + mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; + + return 0; +} + +static int iwl_mvm_tof_mcsi_notif(struct iwl_mvm *mvm, void *data) +{ + struct iwl_tof_mcsi_notif *resp = (struct iwl_tof_mcsi_notif *)data; + + IWL_DEBUG_INFO(mvm, "MCSI notification, token %d\n", resp->token); + return 0; +} + +static int iwl_mvm_tof_nb_report_notif(struct iwl_mvm *mvm, void *data) +{ + struct iwl_tof_neighbor_report *report = + (struct iwl_tof_neighbor_report *)data; + + IWL_DEBUG_INFO(mvm, "NB report, bssid %pM, token %d, status 0x%x\n", + report->bssid, report->request_token, report->status); + return 0; +} + +void iwl_mvm_tof_resp_handler(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_tof_gen_resp_cmd *resp = (void *)pkt->data; + + lockdep_assert_held(&mvm->mutex); + + switch (le32_to_cpu(resp->sub_grp_cmd_id)) { + case TOF_RANGE_RESPONSE_NOTIF: + iwl_mvm_tof_range_resp(mvm, resp->data); + break; + case TOF_MCSI_DEBUG_NOTIF: + iwl_mvm_tof_mcsi_notif(mvm, resp->data); + break; + case TOF_NEIGHBOR_REPORT_RSP_NOTIF: + iwl_mvm_tof_nb_report_notif(mvm, resp->data); + break; + default: + IWL_ERR(mvm, "Unknown sub-group command 0x%x\n", + resp->sub_grp_cmd_id); + break; + } +} diff --git a/drivers/net/wireless/iwlwifi/mvm/tof.h b/drivers/net/wireless/iwlwifi/mvm/tof.h new file mode 100644 index 000000000000..50ae8adaaa6e --- /dev/null +++ b/drivers/net/wireless/iwlwifi/mvm/tof.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * 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) 2015 Intel Deutschland GmbH + * + * 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) 2015 Intel Deutschland GmbH + * 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 __tof +#define __tof_h__ + +#include "fw-api-tof.h" + +struct iwl_mvm_tof_data { + struct iwl_tof_config_cmd tof_cfg; + struct iwl_tof_range_req_cmd range_req; + struct iwl_tof_range_req_ext_cmd range_req_ext; +#ifdef CONFIG_IWLWIFI_DEBUGFS + struct iwl_tof_responder_config_cmd responder_cfg; +#endif + struct iwl_tof_range_rsp_ntfy range_resp; + u8 last_abort_id; + u16 active_range_request; +}; + +void iwl_mvm_tof_init(struct iwl_mvm *mvm); +void iwl_mvm_tof_clean(struct iwl_mvm *mvm); +int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm); +int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id); +int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); +void iwl_mvm_tof_resp_handler(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); +int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); +#ifdef CONFIG_IWLWIFI_DEBUGFS +int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); +#endif +#endif /* __tof_h__ */ -- cgit v1.3-6-gb490 From ab02165ccec4c78162501acedeef1a768acdb811 Mon Sep 17 00:00:00 2001 From: Aviya Erenfeld Date: Tue, 9 Jun 2015 16:45:52 +0300 Subject: iwlwifi: add wide firmware command infrastructure for TX As the firmware is slowly running out of command IDs and grouping of commands is desirable anyway, the firmware is extending the command header from 4 bytes to 8 bytes to introduce a group (in place of the former flags field, since that's always 0 on commands and thus can be easily used to distinguish between the two. In order to support this most easily in the driver widen the command command ID used in the command sending functions and encode the new values (group and version) in the ID. That way existing code doesn't have to be changed (since the higher bits are 0 automatically) and newer code can easily use the new ID generation function to create a value to use in place of just the command ID. Signed-off-by: Aviya Erenfeld Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- .../net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h | 14 +++-- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 + drivers/net/wireless/iwlwifi/iwl-trans.h | 66 ++++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 + drivers/net/wireless/iwlwifi/mvm/utils.c | 4 +- drivers/net/wireless/iwlwifi/pcie/internal.h | 2 + drivers/net/wireless/iwlwifi/pcie/trans.c | 1 + drivers/net/wireless/iwlwifi/pcie/tx.c | 53 ++++++++++++----- 9 files changed, 121 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h index 948ce0802fa7..eb4b99a1c8cd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace-iwlwifi.h @@ -36,7 +36,7 @@ TRACE_EVENT(iwlwifi_dev_hcmd, TP_PROTO(const struct device *dev, struct iwl_host_cmd *cmd, u16 total_size, - struct iwl_cmd_header *hdr), + struct iwl_cmd_header_wide *hdr), TP_ARGS(dev, cmd, total_size, hdr), TP_STRUCT__entry( DEV_ENTRY @@ -44,11 +44,14 @@ TRACE_EVENT(iwlwifi_dev_hcmd, __field(u32, flags) ), TP_fast_assign( - int i, offset = sizeof(*hdr); + int i, offset = sizeof(struct iwl_cmd_header); + + if (hdr->group_id) + offset = sizeof(struct iwl_cmd_header_wide); DEV_ASSIGN; __entry->flags = cmd->flags; - memcpy(__get_dynamic_array(hcmd), hdr, sizeof(*hdr)); + memcpy(__get_dynamic_array(hcmd), hdr, offset); for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { if (!cmd->len[i]) @@ -58,8 +61,9 @@ TRACE_EVENT(iwlwifi_dev_hcmd, offset += cmd->len[i]; } ), - TP_printk("[%s] hcmd %#.2x (%ssync)", - __get_str(dev), ((u8 *)__get_dynamic_array(hcmd))[0], + TP_printk("[%s] hcmd %#.2x.%#.2x (%ssync)", + __get_str(dev), ((u8 *)__get_dynamic_array(hcmd))[1], + ((u8 *)__get_dynamic_array(hcmd))[0], __entry->flags & CMD_ASYNC ? "a" : "") ); diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index c31cf828fb25..f99ec4e22052 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -247,6 +247,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR * @IWL_UCODE_TLV_API_TX_POWER_DEV: new API for tx power. + * @IWL_UCODE_TLV_API_WIDE_CMD_HDR: ucode supports wide command header * @IWL_UCODE_TLV_API_SCD_CFG: This firmware can configure the scheduler * through the dedicated host command. * @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too. @@ -263,6 +264,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = (__force iwl_ucode_tlv_api_t)9, IWL_UCODE_TLV_API_HDC_PHASE_0 = (__force iwl_ucode_tlv_api_t)10, IWL_UCODE_TLV_API_TX_POWER_DEV = (__force iwl_ucode_tlv_api_t)11, + IWL_UCODE_TLV_API_WIDE_CMD_HDR = (__force iwl_ucode_tlv_api_t)14, IWL_UCODE_TLV_API_SCD_CFG = (__force iwl_ucode_tlv_api_t)15, IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = (__force iwl_ucode_tlv_api_t)16, IWL_UCODE_TLV_API_ASYNC_DTM = (__force iwl_ucode_tlv_api_t)17, diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 64769e44059e..df71aa3e6401 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -122,6 +122,32 @@ #define INDEX_TO_SEQ(i) ((i) & 0xff) #define SEQ_RX_FRAME cpu_to_le16(0x8000) +/* + * those functions retrieve specific information from + * the id field in the iwl_host_cmd struct which contains + * the command id, the group id and the version of the command + * and vice versa +*/ +static inline u8 iwl_cmd_opcode(u32 cmdid) +{ + return cmdid & 0xFF; +} + +static inline u8 iwl_cmd_groupid(u32 cmdid) +{ + return ((cmdid & 0xFF00) >> 8); +} + +static inline u8 iwl_cmd_version(u32 cmdid) +{ + return ((cmdid & 0xFF0000) >> 16); +} + +static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) +{ + return opcode + (groupid << 8) + (version << 16); +} + /** * struct iwl_cmd_header * @@ -130,7 +156,7 @@ */ struct iwl_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ - u8 reserved; + u8 group_id; /* * The driver sets up the sequence number to values of its choosing. * uCode does not use this value, but passes it back to the driver @@ -154,6 +180,23 @@ struct iwl_cmd_header { __le16 sequence; } __packed; +/** + * struct iwl_cmd_header_wide + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + * this is the wide version that contains more information about the command + * like length, version and command type + */ +struct iwl_cmd_header_wide { + u8 cmd; + u8 group_id; + __le16 sequence; + __le16 length; + u8 reserved; + u8 version; +} __packed; + #define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */ #define FH_RSCSR_FRAME_INVALID 0x55550000 #define FH_RSCSR_FRAME_ALIGN 0x40 @@ -218,8 +261,18 @@ enum CMD_MODE { * aren't fully copied and use other TFD space. */ struct iwl_device_cmd { - struct iwl_cmd_header hdr; /* uCode API */ - u8 payload[DEF_CMD_PAYLOAD_SIZE]; + union { + struct { + struct iwl_cmd_header hdr; /* uCode API */ + u8 payload[DEF_CMD_PAYLOAD_SIZE]; + }; + struct { + struct iwl_cmd_header_wide hdr_wide; + u8 payload_wide[DEF_CMD_PAYLOAD_SIZE - + sizeof(struct iwl_cmd_header_wide) + + sizeof(struct iwl_cmd_header)]; + }; + }; } __packed; #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) @@ -260,7 +313,8 @@ enum iwl_hcmd_dataflag { * @flags: can be CMD_* * @len: array of the lengths of the chunks in data * @dataflags: IWL_HCMD_DFL_* - * @id: id of the host command + * @id: command id of the host command, for wide commands encoding the + * version and group as well */ struct iwl_host_cmd { const void *data[IWL_MAX_CMD_TBS_PER_TFD]; @@ -269,9 +323,9 @@ struct iwl_host_cmd { u32 _rx_page_order; u32 flags; + u32 id; u16 len[IWL_MAX_CMD_TBS_PER_TFD]; u8 dataflags[IWL_MAX_CMD_TBS_PER_TFD]; - u8 id; }; static inline void iwl_free_resp(struct iwl_host_cmd *cmd) @@ -372,6 +426,7 @@ enum iwl_trans_status { * @bc_table_dword: set to true if the BC table expects the byte count to be * in DWORD (as opposed to bytes) * @scd_set_active: should the transport configure the SCD for HCMD queue + * @wide_cmd_header: firmware supports wide host command header * @command_names: array of command names, must be 256 entries * (one for each command); for debugging only * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until @@ -389,6 +444,7 @@ struct iwl_trans_config { bool rx_buf_size_8k; bool bc_table_dword; bool scd_set_active; + bool wide_cmd_header; const char *const *command_names; u32 sdio_adma_addr; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index c980e8d9ac5a..d78af9f0f81b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -977,12 +977,12 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); /* Tx / Host Commands */ int __must_check iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd); -int __must_check iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id, +int __must_check iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id, u32 flags, u16 len, const void *data); int __must_check iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, u32 *status); -int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, +int __must_check iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id, u16 len, const void *data, u32 *status); int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 76b5557c1dde..c9b9c98c6ff8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -469,6 +469,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K; + trans_cfg.wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_WIDE_CMD_HDR); if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE) trans_cfg.bc_table_dword = true; diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index f50ef822d65e..a7d434256423 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -108,7 +108,7 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd) return ret; } -int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u8 id, +int iwl_mvm_send_cmd_pdu(struct iwl_mvm *mvm, u32 id, u32 flags, u16 len, const void *data) { struct iwl_host_cmd cmd = { @@ -182,7 +182,7 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, /* * We assume that the caller set the status to the sucess value */ -int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u8 id, u16 len, +int iwl_mvm_send_cmd_pdu_status(struct iwl_mvm *mvm, u32 id, u16 len, const void *data, u32 *status) { struct iwl_host_cmd cmd = { diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index e27d5a3dcb86..17f65dc89472 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -299,6 +299,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @rx_buf_size_8k: 8 kB RX buffer size * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) * @scd_set_active: should the transport configure the SCD for HCMD queue + * @wide_cmd_header: true when ucode supports wide command header format * @rx_page_order: page order for receive buffer size * @reg_lock: protect hw register access * @mutex: to protect stop_device / start_fw / start_hw @@ -352,6 +353,7 @@ struct iwl_trans_pcie { bool rx_buf_size_8k; bool bc_table_dword; bool scd_set_active; + bool wide_cmd_header; u32 rx_page_order; const char *const *command_names; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 4cdfb2fd992a..88ab79fc6249 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1394,6 +1394,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, else trans_pcie->rx_page_order = get_order(4 * 1024); + trans_pcie->wide_cmd_header = trans_cfg->wide_cmd_header; trans_pcie->command_names = trans_cfg->command_names; trans_pcie->bc_table_dword = trans_cfg->bc_table_dword; trans_pcie->scd_set_active = trans_cfg->scd_set_active; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 553ae135464a..3a5d54ed494f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1322,13 +1322,23 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, int idx; u16 copy_size, cmd_size, scratch_size; bool had_nocopy = false; + u8 group_id = iwl_cmd_groupid(cmd->id); int i, ret; u32 cmd_pos; const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; - copy_size = sizeof(out_cmd->hdr); - cmd_size = sizeof(out_cmd->hdr); + if (WARN(!trans_pcie->wide_cmd_header && group_id != 0, + "unsupported wide command %#x\n", cmd->id)) + return -EINVAL; + + if (group_id != 0) { + copy_size = sizeof(struct iwl_cmd_header_wide); + cmd_size = sizeof(struct iwl_cmd_header_wide); + } else { + copy_size = sizeof(struct iwl_cmd_header); + cmd_size = sizeof(struct iwl_cmd_header); + } /* need one for the header if the first is NOCOPY */ BUILD_BUG_ON(IWL_MAX_CMD_TBS_PER_TFD > IWL_NUM_OF_TBS - 1); @@ -1418,16 +1428,32 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, out_meta->source = cmd; /* set up the header */ - - out_cmd->hdr.cmd = cmd->id; - out_cmd->hdr.reserved = 0; - out_cmd->hdr.sequence = - cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | - INDEX_TO_SEQ(q->write_ptr)); + if (group_id != 0) { + out_cmd->hdr_wide.cmd = iwl_cmd_opcode(cmd->id); + out_cmd->hdr_wide.group_id = group_id; + out_cmd->hdr_wide.version = iwl_cmd_version(cmd->id); + out_cmd->hdr_wide.length = + cpu_to_le16(cmd_size - + sizeof(struct iwl_cmd_header_wide)); + out_cmd->hdr_wide.reserved = 0; + out_cmd->hdr_wide.sequence = + cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | + INDEX_TO_SEQ(q->write_ptr)); + + cmd_pos = sizeof(struct iwl_cmd_header_wide); + copy_size = sizeof(struct iwl_cmd_header_wide); + } else { + out_cmd->hdr.cmd = iwl_cmd_opcode(cmd->id); + out_cmd->hdr.sequence = + cpu_to_le16(QUEUE_TO_SEQ(trans_pcie->cmd_queue) | + INDEX_TO_SEQ(q->write_ptr)); + out_cmd->hdr.group_id = 0; + + cmd_pos = sizeof(struct iwl_cmd_header); + copy_size = sizeof(struct iwl_cmd_header); + } /* and copy the data that needs to be copied */ - cmd_pos = offsetof(struct iwl_device_cmd, payload); - copy_size = sizeof(out_cmd->hdr); for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) { int copy; @@ -1466,9 +1492,10 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, } IWL_DEBUG_HC(trans, - "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n", + "Sending command %s (%.2x.%.2x), seq: 0x%04X, %d bytes at %d[%d]:%d\n", get_cmd_string(trans_pcie, out_cmd->hdr.cmd), - out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), + group_id, out_cmd->hdr.cmd, + le16_to_cpu(out_cmd->hdr.sequence), cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue); /* start the TFD with the scratchbuf */ @@ -1523,7 +1550,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, kzfree(txq->entries[idx].free_buf); txq->entries[idx].free_buf = dup_buf; - trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr); + trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr_wide); /* start timer if queue currently empty */ if (q->read_ptr == q->write_ptr && txq->wd_timeout) -- cgit v1.3-6-gb490 From 88742c9e84f73eeea4abe967d751b0e6318c2c2e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 30 Jun 2015 15:31:22 +0200 Subject: iwlwifi: mvm: move existing UMAC commands to group 1 Existing UMAC commands already use the long header, but are sent with group 0 and the long header inserted manually. Move them to the group 1 to take advantage of the header building in the low- level transport. Existing firmware ignores the group_id field (it's reserved) and the first firmware that really supports long command headers can parse all commands in both group 0 (with short header) and group 1 (with long header.) Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 5 +++++ drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 18 --------------- drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h | 5 ----- drivers/net/wireless/iwlwifi/mvm/scan.c | 22 ++++++++---------- drivers/net/wireless/iwlwifi/mvm/tof.c | 31 ++++++++++---------------- drivers/net/wireless/iwlwifi/pcie/tx.c | 3 ++- 6 files changed, 28 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index df71aa3e6401..8f67004faf4d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -148,6 +148,11 @@ static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) return opcode + (groupid << 8) + (version << 16); } +/* due to the conversion, this group is special; new groups + * should be defined in the appropriate fw-api header files + */ +#define IWL_ALWAYS_LONG_GROUP 1 + /** * struct iwl_cmd_header * diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 5e4cbdb44c60..4787c32b3a61 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -550,18 +550,6 @@ struct iwl_periodic_scan_complete { /* UMAC Scan API */ -/** - * struct iwl_mvm_umac_cmd_hdr - Command header for UMAC commands - * @size: size of the command (not including header) - * @reserved0: for future use and alignment - * @ver: API version number - */ -struct iwl_mvm_umac_cmd_hdr { - __le16 size; - u8 reserved0; - u8 ver; -} __packed; - /* The maximum of either of these cannot exceed 8, because we use an * 8-bit mask (see IWL_MVM_SCAN_MASK in mvm.h). */ @@ -621,7 +609,6 @@ enum iwl_channel_flags { /** * struct iwl_scan_config - * @hdr: umac command header * @flags: enum scan_config_flags * @tx_chains: valid_tx antenna - ANT_* definitions * @rx_chains: valid_rx antenna - ANT_* definitions @@ -639,7 +626,6 @@ enum iwl_channel_flags { * @channel_array: default supported channels */ struct iwl_scan_config { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 flags; __le32 tx_chains; __le32 rx_chains; @@ -734,7 +720,6 @@ struct iwl_scan_req_umac_tail { /** * struct iwl_scan_req_umac - * @hdr: umac command header * @flags: &enum iwl_umac_scan_flags * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority @@ -753,7 +738,6 @@ struct iwl_scan_req_umac_tail { * &struct iwl_scan_req_umac_tail */ struct iwl_scan_req_umac { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 flags; __le32 uid; __le32 ooc_priority; @@ -775,12 +759,10 @@ struct iwl_scan_req_umac { /** * struct iwl_umac_scan_abort - * @hdr: umac command header * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @flags: reserved */ struct iwl_umac_scan_abort { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 uid; __le32 flags; } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */ diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h index 287c9ecb0fb1..eed6271d01a3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tof.h @@ -88,7 +88,6 @@ enum iwl_mvm_tof_sub_grp_ids { * @is_buf_required: 1 channel estimation buffer required, 0 - otherwise */ struct iwl_tof_config_cmd { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 sub_grp_cmd_id; u8 tof_disabled; u8 one_sided_disabled; @@ -136,7 +135,6 @@ struct iwl_tof_config_cmd { * @bssid: Current AP BSSID */ struct iwl_tof_responder_config_cmd { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 sub_grp_cmd_id; __le16 burst_period; u8 min_delta_ftm; @@ -171,7 +169,6 @@ struct iwl_tof_responder_config_cmd { * value to be sent to the AP */ struct iwl_tof_range_req_ext_cmd { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 sub_grp_cmd_id; __le16 tsf_timer_offset_msec; __le16 reserved; @@ -273,7 +270,6 @@ enum iwl_tof_response_mode { * Bits set to 1 shall be randomized by the UMAC */ struct iwl_tof_range_req_cmd { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 sub_grp_cmd_id; u8 request_id; u8 initiator; @@ -382,7 +378,6 @@ struct iwl_tof_neighbor_report { * @request_id: corresponds to a range request */ struct iwl_tof_range_abort_cmd { - struct iwl_mvm_umac_cmd_hdr hdr; __le32 sub_grp_cmd_id; u8 request_id; u8 reserved[3]; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index b891fa54fa4a..d34b2e578358 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -884,9 +884,9 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) int num_channels = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; - int ret, i, j = 0, cmd_size, data_size; + int ret, i, j = 0, cmd_size; struct iwl_host_cmd cmd = { - .id = SCAN_CFG_CMD, + .id = iwl_cmd_id(SCAN_CFG_CMD, IWL_ALWAYS_LONG_GROUP, 0), }; if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) @@ -898,8 +898,6 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) if (!scan_config) return -ENOMEM; - data_size = cmd_size - sizeof(struct iwl_mvm_umac_cmd_hdr); - scan_config->hdr.size = cpu_to_le16(data_size); scan_config->flags = cpu_to_le32(SCAN_CONFIG_FLAG_ACTIVATE | SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | SCAN_CONFIG_FLAG_SET_TX_CHAINS | @@ -1045,8 +1043,6 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return uid; memset(cmd, 0, ksize(cmd)); - cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) - - sizeof(struct iwl_mvm_umac_cmd_hdr)); iwl_mvm_scan_umac_dwell(mvm, cmd, params); @@ -1183,7 +1179,7 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { - hcmd.id = SCAN_REQ_UMAC; + hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); ret = iwl_mvm_scan_umac(mvm, vif, ¶ms, IWL_MVM_SCAN_REGULAR); } else { @@ -1291,7 +1287,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { - hcmd.id = SCAN_REQ_UMAC; + hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); ret = iwl_mvm_scan_umac(mvm, vif, ¶ms, IWL_MVM_SCAN_SCHED); } else { hcmd.id = SCAN_OFFLOAD_REQUEST_CMD; @@ -1369,10 +1365,7 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) { - struct iwl_umac_scan_abort cmd = { - .hdr.size = cpu_to_le16(sizeof(struct iwl_umac_scan_abort) - - sizeof(struct iwl_mvm_umac_cmd_hdr)), - }; + struct iwl_umac_scan_abort cmd = {}; int uid, ret; lockdep_assert_held(&mvm->mutex); @@ -1389,7 +1382,10 @@ static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid); - ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_UMAC, 0, sizeof(cmd), &cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, + iwl_cmd_id(SCAN_ABORT_UMAC, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(cmd), &cmd); if (!ret) mvm->scan_uid_status[uid] = type << IWL_MVM_SCAN_STOPPING_SHIFT; diff --git a/drivers/net/wireless/iwlwifi/mvm/tof.c b/drivers/net/wireless/iwlwifi/mvm/tof.c index 5a8e96f0293d..d060e12c3239 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tof.c +++ b/drivers/net/wireless/iwlwifi/mvm/tof.c @@ -74,33 +74,21 @@ void iwl_mvm_tof_init(struct iwl_mvm *mvm) memset(tof_data, 0, sizeof(*tof_data)); - tof_data->tof_cfg.hdr.size = - cpu_to_le16(sizeof(struct iwl_tof_config_cmd) - - sizeof(struct iwl_mvm_umac_cmd_hdr)); tof_data->tof_cfg.sub_grp_cmd_id = cpu_to_le32(TOF_CONFIG_CMD); #ifdef CONFIG_IWLWIFI_DEBUGFS if (IWL_MVM_TOF_IS_RESPONDER) { - tof_data->responder_cfg.hdr.size = - cpu_to_le16(sizeof(struct iwl_tof_responder_config_cmd) - - sizeof(struct iwl_mvm_umac_cmd_hdr)); tof_data->responder_cfg.sub_grp_cmd_id = cpu_to_le32(TOF_RESPONDER_CONFIG_CMD); tof_data->responder_cfg.sta_id = IWL_MVM_STATION_COUNT; } #endif - tof_data->range_req.hdr.size = - cpu_to_le16(sizeof(struct iwl_tof_range_req_cmd) - - sizeof(struct iwl_mvm_umac_cmd_hdr)); tof_data->range_req.sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_REQ_CMD); tof_data->range_req.req_timeout = 1; tof_data->range_req.initiator = 1; tof_data->range_req.report_policy = 3; - tof_data->range_req_ext.hdr.size = - cpu_to_le16(sizeof(struct iwl_tof_range_req_ext_cmd) - - sizeof(struct iwl_mvm_umac_cmd_hdr)); tof_data->range_req_ext.sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_REQ_EXT_CMD); @@ -147,15 +135,15 @@ int iwl_mvm_tof_config_cmd(struct iwl_mvm *mvm) } mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; - return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(*cmd), cmd); + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(*cmd), cmd); } int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id) { struct iwl_tof_range_abort_cmd cmd = { .sub_grp_cmd_id = cpu_to_le32(TOF_RANGE_ABORT_CMD), - .hdr.size = cpu_to_le16(sizeof(struct iwl_tof_range_abort_cmd) - - sizeof(struct iwl_mvm_umac_cmd_hdr)), .request_id = id, }; @@ -173,7 +161,9 @@ int iwl_mvm_tof_range_abort_cmd(struct iwl_mvm *mvm, u8 id) /* after abort is sent there's no active request anymore */ mvm->tof_data.active_range_request = IWL_MVM_TOF_RANGE_REQ_MAX_ID; - return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(cmd), &cmd); + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(cmd), &cmd); } #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -194,7 +184,9 @@ int iwl_mvm_tof_responder_cmd(struct iwl_mvm *mvm, } cmd->sta_id = mvmvif->bcast_sta.sta_id; - return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, sizeof(*cmd), cmd); + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(*cmd), cmd); } #endif @@ -245,8 +237,9 @@ int iwl_mvm_tof_range_request_ext_cmd(struct iwl_mvm *mvm, return -EIO; } - return iwl_mvm_send_cmd_pdu(mvm, TOF_CMD, 0, - sizeof(mvm->tof_data.range_req_ext), + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(TOF_CMD, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(mvm->tof_data.range_req_ext), &mvm->tof_data.range_req_ext); } diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 3a5d54ed494f..601eee1ad60b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1328,7 +1328,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; - if (WARN(!trans_pcie->wide_cmd_header && group_id != 0, + if (WARN(!trans_pcie->wide_cmd_header && + group_id > IWL_ALWAYS_LONG_GROUP, "unsupported wide command %#x\n", cmd->id)) return -EINVAL; -- cgit v1.3-6-gb490 From 2d42801bd62eb2018da914272fd505a6d32004a8 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 17 Jun 2015 15:32:37 +0300 Subject: Revert "iwlwifi: mvm: move deferred d0i3 exit to resume_complete op" This reverts commit 088070a2f6575402d3dd82e1c5a4a8e1941805f6. When working in d0i3_on_idle mode, we explicitly go out of d0i3 on resume (so other potential commands could be sent). However, D0I3_DEFER_WAKEUP is currently cleared on resume complete (which happens only later on), causing d0i3 exit to timeout. Since mac80211 was modified to accept incoming frames once drv_resume was called, we can safely revert this patch, and handle the pending work on iwl_mvm_resume(). Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 58 +++++++++++++++++++++-------- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 13 ------- 2 files changed, 43 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 4165d104e4c3..246e60aa2905 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1935,28 +1935,56 @@ out: return 1; } -int iwl_mvm_resume(struct ieee80211_hw *hw) +static int iwl_mvm_resume_d3(struct iwl_mvm *mvm) { - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + iwl_trans_resume(mvm->trans); + + return __iwl_mvm_resume(mvm, false); +} + +static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm) +{ + bool exit_now; + + /* + * make sure to clear D0I3_DEFER_WAKEUP before + * calling iwl_trans_resume(), which might wait + * for d0i3 exit completion. + */ + mutex_lock(&mvm->d0i3_suspend_mutex); + __clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); + exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP, + &mvm->d0i3_suspend_flags); + mutex_unlock(&mvm->d0i3_suspend_mutex); + if (exit_now) { + IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n"); + _iwl_mvm_exit_d0i3(mvm); + } iwl_trans_resume(mvm->trans); - if (mvm->hw->wiphy->wowlan_config->any) { - /* 'any' trigger means d0i3 usage */ - if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { - int ret = iwl_mvm_exit_d0i3(hw->priv); + if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { + int ret = iwl_mvm_exit_d0i3(mvm->hw->priv); - if (ret) - return ret; - /* - * d0i3 exit will be deferred until reconfig_complete. - * make sure there we are out of d0i3. - */ - } - return 0; + if (ret) + return ret; + /* + * d0i3 exit will be deferred until reconfig_complete. + * make sure there we are out of d0i3. + */ } + return 0; +} - return __iwl_mvm_resume(mvm, false); +int iwl_mvm_resume(struct ieee80211_hw *hw) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + + /* 'any' trigger means d0i3 was used */ + if (hw->wiphy->wowlan_config->any) + return iwl_mvm_resume_d0i3(mvm); + else + return iwl_mvm_resume_d3(mvm); } void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index dfdab38e2d4a..45e9913529b2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1433,22 +1433,9 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) static void iwl_mvm_resume_complete(struct iwl_mvm *mvm) { - bool exit_now; - if (!iwl_mvm_is_d0i3_supported(mvm)) return; - mutex_lock(&mvm->d0i3_suspend_mutex); - __clear_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); - exit_now = __test_and_clear_bit(D0I3_PENDING_WAKEUP, - &mvm->d0i3_suspend_flags); - mutex_unlock(&mvm->d0i3_suspend_mutex); - - if (exit_now) { - IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n"); - _iwl_mvm_exit_d0i3(mvm); - } - if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) if (!wait_event_timeout(mvm->d0i3_exit_waitq, !test_bit(IWL_MVM_STATUS_IN_D0I3, -- cgit v1.3-6-gb490 From c43fe907fec2c1925d423777ba14e0baf30c672c Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 4 Jun 2015 21:59:32 +0300 Subject: iwlwifi: return error if d0i3 was aborted Allow the transport layer to return an error upon suspend. Signed-off-by: Eliad Peller Reviewed-by: Luciano Coelho Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-trans.h | 10 ++++++---- drivers/net/wireless/iwlwifi/mvm/d3.c | 8 ++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 8f67004faf4d..e698ed5e34cc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -598,7 +598,7 @@ struct iwl_trans_ops { u32 value); void (*ref)(struct iwl_trans *trans); void (*unref)(struct iwl_trans *trans); - void (*suspend)(struct iwl_trans *trans); + int (*suspend)(struct iwl_trans *trans); void (*resume)(struct iwl_trans *trans); struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); @@ -807,10 +807,12 @@ static inline void iwl_trans_unref(struct iwl_trans *trans) trans->ops->unref(trans); } -static inline void iwl_trans_suspend(struct iwl_trans *trans) +static inline int iwl_trans_suspend(struct iwl_trans *trans) { - if (trans->ops->suspend) - trans->ops->suspend(trans); + if (!trans->ops->suspend) + return 0; + + return trans->ops->suspend(trans); } static inline void iwl_trans_resume(struct iwl_trans *trans) diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 246e60aa2905..68d721823645 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1168,13 +1168,17 @@ remove_notif: int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; + + ret = iwl_trans_suspend(mvm->trans); + if (ret) + return ret; - iwl_trans_suspend(mvm->trans); mvm->trans->wowlan_d0i3 = wowlan->any; if (mvm->trans->wowlan_d0i3) { /* 'any' trigger means d0i3 usage */ if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) { - int ret = iwl_mvm_enter_d0i3_sync(mvm); + ret = iwl_mvm_enter_d0i3_sync(mvm); if (ret) return ret; -- cgit v1.3-6-gb490 From d576cd9d599604b9b712939c2ddea0db90463126 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 28 Jun 2015 08:10:46 +0300 Subject: iwlwifi: mvm: update comment of power_scheme module parameter Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d78af9f0f81b..767880b86e23 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -123,8 +123,7 @@ extern const struct ieee80211_ops iwl_mvm_hw_ops; * be up'ed after the INIT fw asserted. This is useful to be able to use * proprietary tools over testmode to debug the INIT fw. * @tfd_q_hang_detect: enabled the detection of hung transmit queues - * @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power - * Save)-2(default), LP(Low Power)-3 + * @power_scheme: one of enum iwl_power_scheme */ struct iwl_mvm_mod_params { bool init_dbg; -- cgit v1.3-6-gb490 From d0ab08d05e5ae84edda5bf86797cbc2daee75db2 Mon Sep 17 00:00:00 2001 From: Ilan Peer Date: Wed, 24 Jun 2015 09:23:01 +0300 Subject: iwlwifi: mvm: Use the AP station for non_sta transmit In iwl_mvm_tx_skb_non_sta(), in case of managed interface, use the AP station for multicast frames instead of the auxiliary station as otherwise the frames can be sent to an absent P2P GO as the FW does not block transmissions for the auxiliary station since it is not associated with the station MAC context. Note that this is not possible for unicast frames, as a TDLS discovery response is sent without a station entry, and in this case the P2P GO NoA should not block transmission to the peer. Signed-off-by: Ilan Peer Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tx.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index abde484436a8..fa3eaf9a2fc6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -366,18 +366,29 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) IEEE80211_SKB_CB(skb)->hw_queue = mvm->aux_queue; /* - * If the interface on which frame is sent is the P2P_DEVICE + * If the interface on which the frame is sent is the P2P_DEVICE * or an AP/GO interface use the broadcast station associated - * with it; otherwise use the AUX station. + * with it; otherwise if the interface is a managed interface + * use the AP station associated with it for multicast traffic + * (this is not possible for unicast packets as a TLDS discovery + * response are sent without a station entry); otherwise use the + * AUX station. */ - if (info->control.vif && - (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE || - info->control.vif->type == NL80211_IFTYPE_AP)) { + sta_id = mvm->aux_sta.sta_id; + if (info->control.vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif); - sta_id = mvmvif->bcast_sta.sta_id; - } else { - sta_id = mvm->aux_sta.sta_id; + + if (info->control.vif->type == NL80211_IFTYPE_P2P_DEVICE || + info->control.vif->type == NL80211_IFTYPE_AP) + sta_id = mvmvif->bcast_sta.sta_id; + else if (info->control.vif->type == NL80211_IFTYPE_STATION && + is_multicast_ether_addr(hdr->addr1)) { + u8 ap_sta_id = ACCESS_ONCE(mvmvif->ap_sta_id); + + if (ap_sta_id != IWL_MVM_STATION_COUNT) + sta_id = ap_sta_id; + } } IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue); -- cgit v1.3-6-gb490 From 869f3b15c9fba037956f642b2023fd16d9ee2f56 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Mon, 20 Jul 2015 14:16:21 +0300 Subject: iwlwifi: pcie: provide a way to stop configuration if it is forbidden The firmware debug infrastructure allows the user to provide a firmware that will toggle a few registers to configure the debugging capabilities. On certain devices, certain operations are forbidden. Executing a forbidden operation will cause the hardware to die in a way that only driver unload / load will bring it back to life. Fortunately, there is a way to know in advance if those operations will be accepted by the device. This is where the new PRPH_BLOCKBIT operation plays its role. If the bit X from PRPH register Y is set, then we should prevent any further register configuration. When that happens, drop a line in the kernel log since this is really an error state: the user won't have his device configured as he expected. Add operations that will be used in the future: INDIRECT_ASSIGN, INDIRECT_SETBIT, and INDIRECT_CLEARBIT. Other debugging configurations (such as destination configuration for the monitor) will take place in any case. Signed-off-by: Haim Dreyfuss Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 6 ++++++ drivers/net/wireless/iwlwifi/pcie/trans.c | 9 +++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index f99ec4e22052..884825c70533 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -412,6 +412,12 @@ enum iwl_fw_dbg_reg_operator { PRPH_ASSIGN, PRPH_SETBIT, PRPH_CLEARBIT, + + INDIRECT_ASSIGN, + INDIRECT_SETBIT, + INDIRECT_CLEARBIT, + + PRPH_BLOCKBIT, }; /** diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 88ab79fc6249..46e900e860e8 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -881,6 +881,14 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans) case PRPH_CLEARBIT: iwl_clear_bits_prph(trans, addr, BIT(val)); break; + case PRPH_BLOCKBIT: + if (iwl_read_prph(trans, addr) & BIT(val)) { + IWL_ERR(trans, + "BIT(%u) in address 0x%x is 1, stopping FW configuration\n", + val, addr); + goto monitor; + } + break; default: IWL_ERR(trans, "FW debug - unknown OP %d\n", dest->reg_ops[i].op); @@ -888,6 +896,7 @@ static void iwl_pcie_apply_destination(struct iwl_trans *trans) } } +monitor: if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) { iwl_write_prph(trans, le32_to_cpu(dest->base_reg), trans_pcie->fw_mon_phys >> dest->base_shift); -- cgit v1.3-6-gb490 From 93190fb0589f97bd603bd545459122a8f5532080 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sat, 27 Dec 2014 09:09:47 +0200 Subject: iwlwifi: mvm: Enable Rx Checksum hw TCP software implementation on the host requires extensive computing power. Offloading even some of the TCP/IP stack to the NIC might save a significant overhead. In order to enable this feature on our hw, we need to configure it first. Once done, we mark this capability, to be advertised later to the OS via ieee80211_register_hw. The driver Rx indications for TCP Checksum is integrated within the standard Rx status. The driver responds to those indications as follows: If the frame was tested by hw and checksum ok report CHECKSUM_UNNECESSARY. Otherwise, report CHECKSUM_NONE. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 1 + drivers/net/wireless/iwlwifi/iwl-config.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-fw-file.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-prph.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 31 +++++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/fw.c | 4 ++++ drivers/net/wireless/iwlwifi/mvm/mac80211.c | 6 ++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 10 ++++++++++ drivers/net/wireless/iwlwifi/mvm/rx.c | 17 ++++++++++++++++ 9 files changed, 74 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 0de575124fa2..7caea69570d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -154,6 +154,7 @@ static const struct iwl_tt_params iwl8000_tt_params = { .led_mode = IWL_LED_RF_STATE, \ .nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \ .d0i3 = true, \ + .features = NETIF_F_RXCSUM, \ .non_shared_ant = ANT_A, \ .dccm_offset = IWL8260_DCCM_OFFSET, \ .dccm_len = IWL8260_DCCM_LEN, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 08c14afeb148..939fa229c038 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -297,6 +297,7 @@ struct iwl_pwr_tx_backoff { * mode set * @d0i3: device uses d0i3 instead of d3 * @nvm_hw_section_num: the ID of the HW NVM section + * @features: hw features, any combination of feature_whitelist * @pwr_tx_backoffs: translation table between power limits and backoffs * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response @@ -348,6 +349,7 @@ struct iwl_cfg { bool no_power_up_nic_in_init; const char *default_nvm_file_B_step; const char *default_nvm_file_C_step; + netdev_features_t features; unsigned int max_rx_agg_size; bool disable_dummy_notification; unsigned int max_tx_agg_size; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 884825c70533..926e4568d36c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -297,6 +297,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command + * @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running * @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different @@ -320,6 +321,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH = (__force iwl_ucode_tlv_capa_t)13, IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = (__force iwl_ucode_tlv_capa_t)18, IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT = (__force iwl_ucode_tlv_capa_t)19, + IWL_UCODE_TLV_CAPA_CSUM_SUPPORT = (__force iwl_ucode_tlv_capa_t)21, IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = (__force iwl_ucode_tlv_capa_t)22, IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = (__force iwl_ucode_tlv_capa_t)28, IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29, diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index a8469041af09..cd98b9f45415 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -292,6 +292,9 @@ /*********************** END TX SCHEDULER *************************************/ +/* tcp checksum offload */ +#define RX_EN_CSUM (0x00a00d88) + /* Oscillator clock */ #define OSC_CLK (0xa04068) #define OSC_CLK_FORCE_CONTROL (0x8) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 2bc33faae5b4..4e29c11cc969 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -1085,10 +1085,33 @@ struct iwl_rx_phy_info { __le16 frame_time; } __packed; +/* + * TCP offload Rx assist info + * + * bits 0:3 - reserved + * bits 4:7 - MIC CRC length + * bits 8:12 - MAC header length + * bit 13 - Padding indication + * bit 14 - A-AMSDU indication + * bit 15 - Offload enabled + */ +enum iwl_csum_rx_assist_info { + CSUM_RXA_RESERVED_MASK = 0x000f, + CSUM_RXA_MICSIZE_MASK = 0x00f0, + CSUM_RXA_HEADERLEN_MASK = 0x1f00, + CSUM_RXA_PADD = BIT(13), + CSUM_RXA_AMSDU = BIT(14), + CSUM_RXA_ENA = BIT(15) +}; + +/** + * struct iwl_rx_mpdu_res_start - phy info + * @assist: see CSUM_RX_ASSIST_ above + */ struct iwl_rx_mpdu_res_start { __le16 byte_count; - __le16 reserved; -} __packed; + __le16 assist; +} __packed; /* _RX_MPDU_RES_START_API_S_VER_2 */ /** * enum iwl_rx_phy_flags - to parse %iwl_rx_phy_info phy_flags @@ -1141,6 +1164,8 @@ enum iwl_rx_phy_flags { * @RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP: * @RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT: * @RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME: this frame is an 11w management frame + * @RX_MPDU_RES_STATUS_CSUM_DONE: checksum was done by the hw + * @RX_MPDU_RES_STATUS_CSUM_OK: checksum found no errors * @RX_MPDU_RES_STATUS_HASH_INDEX_MSK: * @RX_MPDU_RES_STATUS_STA_ID_MSK: * @RX_MPDU_RES_STATUS_RRF_KILL: @@ -1170,6 +1195,8 @@ enum iwl_mvm_rx_status { RX_MPDU_RES_STATUS_EXT_IV_BIT_CMP = BIT(13), RX_MPDU_RES_STATUS_KEY_ID_CMP_BIT = BIT(14), RX_MPDU_RES_STATUS_ROBUST_MNG_FRAME = BIT(15), + RX_MPDU_RES_STATUS_CSUM_DONE = BIT(16), + RX_MPDU_RES_STATUS_CSUM_OK = BIT(17), RX_MPDU_RES_STATUS_HASH_INDEX_MSK = (0x3F0000), RX_MPDU_RES_STATUS_STA_ID_MSK = (0x1f000000), RX_MPDU_RES_STATUS_RRF_KILL = BIT(29), diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index e905c07127fb..ebda61bc66d6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -752,6 +752,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } + if (iwl_mvm_is_csum_supported(mvm) && + mvm->cfg->features & NETIF_F_RXCSUM) + iwl_trans_write_prph(mvm->trans, RX_EN_CSUM, 0x3); + /* 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); diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 45e9913529b2..4264c52aa127 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -649,6 +649,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH; } + hw->netdev_features |= mvm->cfg->features; + if (!iwl_mvm_is_csum_supported(mvm)) + hw->netdev_features &= ~NETIF_F_RXCSUM; + ret = ieee80211_register_hw(mvm->hw); if (ret) iwl_mvm_leds_exit(mvm); @@ -1651,6 +1655,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, goto out_unlock; } + mvmvif->features |= hw->netdev_features; + ret = iwl_mvm_mac_ctxt_add(mvm, vif); if (ret) goto out_release; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 767880b86e23..c1f84ec93f40 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -357,6 +357,7 @@ struct iwl_mvm_vif_bf_data { * # of received beacons accumulated over FW restart, and the current * average signal of beacons retrieved from the firmware * @csa_failed: CSA failed to schedule time event, report an error later + * @features: hw features active for this vif */ struct iwl_mvm_vif { struct iwl_mvm *mvm; @@ -437,6 +438,9 @@ struct iwl_mvm_vif { /* Indicates that CSA countdown may be started */ bool csa_countdown; bool csa_failed; + + /* TCP Checksum Offload */ + netdev_features_t features; }; static inline struct iwl_mvm_vif * @@ -943,6 +947,12 @@ static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm) IWL_MVM_BT_COEX_RRC; } +static inline bool iwl_mvm_is_csum_supported(struct iwl_mvm *mvm) +{ + return fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CSUM_SUPPORT); +} + extern const u8 iwl_mvm_ac_to_tx_fifo[]; struct iwl_rate_info { diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 73054ddc5138..65746145273e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -61,6 +61,7 @@ * (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 "iwl-trans.h" #include "mvm.h" #include "fw-api.h" @@ -234,6 +235,19 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm, return 0; } +static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, + struct sk_buff *skb, + u32 status) +{ + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif); + + if (mvmvif->features & NETIF_F_RXCSUM && + status & RX_MPDU_RES_STATUS_CSUM_DONE && + status & RX_MPDU_RES_STATUS_CSUM_OK) + skb->ip_summed = CHECKSUM_UNNECESSARY; +} + /* * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler * @@ -362,6 +376,9 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) } } + if (sta && ieee80211_is_data(hdr->frame_control)) + iwl_mvm_rx_csum(sta, skb, rx_pkt_status); + rcu_read_unlock(); /* set the preamble flag if appropriate */ -- cgit v1.3-6-gb490 From f739c39ce630c97912a16639bd10231073aef6c8 Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Wed, 22 Jul 2015 15:46:37 +0300 Subject: iwlwifi: mvm: fix beacon filtering temperature thresholds for D0i3 The slow filtering threshold should be higher in D0i3 case. Signed-off-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-power.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index b1baa33cc19b..b86b1697d56f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -413,7 +413,7 @@ struct iwl_beacon_filter_cmd { #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_D0I3 20 #define IWL_BF_TEMP_SLOW_FILTER_MAX 255 #define IWL_BF_TEMP_SLOW_FILTER_MIN 0 -- cgit v1.3-6-gb490 From cdc306b2f604d59bb7fb558fadade195f1eb289e Mon Sep 17 00:00:00 2001 From: Gregory Greenman Date: Mon, 20 Jul 2015 12:55:34 +0300 Subject: iwlwifi: mvm: ignore CQM when setting beacon filtering in D0i3 enter flow CQM overwrites a few thresholds in the bf command. On the other hand, when entering D0i3 the thresholds are set to higher values on purpose, so ignore CQM in this case. Signed-off-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/power.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 8e2490a1d743..506294fc2f87 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -112,11 +112,12 @@ int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, static void iwl_mvm_beacon_filter_set_cqm_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_beacon_filter_cmd *cmd) + struct iwl_beacon_filter_cmd *cmd, + bool d0i3) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (vif->bss_conf.cqm_rssi_thold) { + if (vif->bss_conf.cqm_rssi_thold && !d0i3) { cmd->bf_energy_delta = cpu_to_le32(vif->bss_conf.cqm_rssi_hyst); /* fw uses an absolute value for this */ @@ -807,7 +808,7 @@ static int _iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm, vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; - iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd); + iwl_mvm_beacon_filter_set_cqm_params(mvm, vif, cmd, d0i3); if (!d0i3) iwl_mvm_beacon_filter_debugfs_parameters(vif, cmd); ret = iwl_mvm_beacon_filter_send_cmd(mvm, cmd, cmd_flags); -- cgit v1.3-6-gb490 From 6dfb36c89dc21c2c77a4b8ea48679cbb15d158b4 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 9 Jul 2015 14:17:24 +0300 Subject: iwlwifi: call d3_suspend/resume in d0i3 case as well Some CSR registers have to be configured also in case of suspend/resume with unified image (which doesn't includes reconfiguration flow). Reuse the existing d3_suspend/d3_resume trans ops, while making sure some configurations are a bit different, according to the wowlan type. After this change, we no longer need the special wowlan_d0i3 configurations done in iwl_pci_resume, as they are already being done in the d3_resume op. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/d3.c | 6 ++++++ drivers/net/wireless/iwlwifi/pcie/drv.c | 13 +++-------- drivers/net/wireless/iwlwifi/pcie/trans.c | 36 +++++++++++++++++++++---------- 3 files changed, 34 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 68d721823645..a85be4e9adcd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1187,6 +1187,9 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) mutex_lock(&mvm->d0i3_suspend_mutex); __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); mutex_unlock(&mvm->d0i3_suspend_mutex); + + iwl_trans_d3_suspend(mvm->trans, false); + return 0; } @@ -1949,6 +1952,9 @@ static int iwl_mvm_resume_d3(struct iwl_mvm *mvm) static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm) { bool exit_now; + enum iwl_d3_status d3_status; + + iwl_trans_d3_resume(mvm->trans, &d3_status, false); /* * make sure to clear D0I3_DEFER_WAKEUP before diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index dbd2a03a0f6d..cdf3a0c33902 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -631,17 +631,10 @@ static int iwl_pci_resume(struct device *device) return 0; /* - * On suspend, ict is disabled, and the interrupt mask - * gets cleared. Reconfigure them both in case of d0i3 - * image. Otherwise, only enable rfkill interrupt (in - * order to keep track of the rfkill status) + * Enable rfkill interrupt (in order to keep track of + * the rfkill status) */ - if (trans->wowlan_d0i3) { - iwl_pcie_reset_ict(trans); - iwl_enable_interrupts(trans); - } else { - iwl_enable_rfkill_int(trans); - } + iwl_enable_rfkill_int(trans); hw_rfkill = iwl_is_rfkill_set(trans); diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 46e900e860e8..cbc29ccc6a00 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1189,6 +1189,12 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + if (trans->wowlan_d0i3) { + /* Enable persistence mode to avoid reset */ + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PERSIST_MODE); + } + iwl_disable_interrupts(trans); /* @@ -1207,12 +1213,14 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - /* - * reset TX queues -- some of their registers reset during S3 - * so if we don't reset everything here the D3 image would try - * to execute some invalid memory upon resume - */ - iwl_trans_pcie_tx_reset(trans); + if (!trans->wowlan_d0i3) { + /* + * reset TX queues -- some of their registers reset during S3 + * so if we don't reset everything here the D3 image would try + * to execute some invalid memory upon resume + */ + iwl_trans_pcie_tx_reset(trans); + } iwl_pcie_set_pwr(trans, true); } @@ -1254,12 +1262,18 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_pcie_set_pwr(trans, false); - iwl_trans_pcie_tx_reset(trans); + if (trans->wowlan_d0i3) { + iwl_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + } else { + iwl_trans_pcie_tx_reset(trans); - ret = iwl_pcie_rx_init(trans); - if (ret) { - IWL_ERR(trans, "Failed to resume the device (RX reset)\n"); - return ret; + ret = iwl_pcie_rx_init(trans); + if (ret) { + IWL_ERR(trans, + "Failed to resume the device (RX reset)\n"); + return ret; + } } val = iwl_read32(trans, CSR_RESET); -- cgit v1.3-6-gb490 From 18f5a374b3db33720dc8c66cb94947585904d6c6 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 16 Jul 2015 20:17:42 +0300 Subject: iwlwifi: pcie: reset write pointer on ict reset Since the CSR_DRAM_INIT_TBL_WRITE_POINTER bit wasn't set on ict reset, in some flows (like disable ict followed by immediate reset ict) the driver and hardware went out of sync (the driver cleared the ict_index, while the hw kept it intact). Fix it by setting the flag when resetting ict. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-csr.h | 1 + drivers/net/wireless/iwlwifi/pcie/rx.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index faa17f2e352a..fa716618735e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -422,6 +422,7 @@ enum { /* DRAM INT TABLE */ #define CSR_DRAM_INT_TBL_ENABLE (1 << 31) +#define CSR_DRAM_INIT_TBL_WRITE_POINTER (1 << 28) #define CSR_DRAM_INIT_TBL_WRAP_CHECK (1 << 27) /* diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 5561dee7b62d..454ef1d9a76a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1443,8 +1443,9 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans) val = trans_pcie->ict_tbl_dma >> ICT_SHIFT; - val |= CSR_DRAM_INT_TBL_ENABLE; - val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; + val |= CSR_DRAM_INT_TBL_ENABLE | + CSR_DRAM_INIT_TBL_WRAP_CHECK | + CSR_DRAM_INIT_TBL_WRITE_POINTER; IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val); -- cgit v1.3-6-gb490 From 5888111cb8f7368304db42787c9495d4b2b82e06 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 4 Aug 2015 14:36:17 +0530 Subject: cxgb4: Add debugfs support to dump meminfo Add debug support to dump memory address ranges of various hardware modules of the adapter. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 285 +++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 122 +++++++++ 2 files changed, 407 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index f701a6f20c6a..b6577349cf4e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -2275,6 +2275,290 @@ static const struct file_operations blocked_fl_fops = { .llseek = generic_file_llseek, }; +struct mem_desc { + unsigned int base; + unsigned int limit; + unsigned int idx; +}; + +static int mem_desc_cmp(const void *a, const void *b) +{ + return ((const struct mem_desc *)a)->base - + ((const struct mem_desc *)b)->base; +} + +static void mem_region_show(struct seq_file *seq, const char *name, + unsigned int from, unsigned int to) +{ + char buf[40]; + + string_get_size((u64)to - from + 1, 1, STRING_UNITS_2, buf, + sizeof(buf)); + seq_printf(seq, "%-15s %#x-%#x [%s]\n", name, from, to, buf); +} + +static int meminfo_show(struct seq_file *seq, void *v) +{ + static const char * const memory[] = { "EDC0:", "EDC1:", "MC:", + "MC0:", "MC1:"}; + static const char * const region[] = { + "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", + "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", + "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", + "TDDP region:", "TPT region:", "STAG region:", "RQ region:", + "RQUDP region:", "PBL region:", "TXPBL region:", + "DBVFIFO region:", "ULPRX state:", "ULPTX state:", + "On-chip queues:" + }; + + int i, n; + u32 lo, hi, used, alloc; + struct mem_desc avail[4]; + struct mem_desc mem[ARRAY_SIZE(region) + 3]; /* up to 3 holes */ + struct mem_desc *md = mem; + struct adapter *adap = seq->private; + + for (i = 0; i < ARRAY_SIZE(mem); i++) { + mem[i].limit = 0; + mem[i].idx = i; + } + + /* Find and sort the populated memory ranges */ + i = 0; + lo = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A); + if (lo & EDRAM0_ENABLE_F) { + hi = t4_read_reg(adap, MA_EDRAM0_BAR_A); + avail[i].base = EDRAM0_BASE_G(hi) << 20; + avail[i].limit = avail[i].base + (EDRAM0_SIZE_G(hi) << 20); + avail[i].idx = 0; + i++; + } + if (lo & EDRAM1_ENABLE_F) { + hi = t4_read_reg(adap, MA_EDRAM1_BAR_A); + avail[i].base = EDRAM1_BASE_G(hi) << 20; + avail[i].limit = avail[i].base + (EDRAM1_SIZE_G(hi) << 20); + avail[i].idx = 1; + i++; + } + + if (is_t5(adap->params.chip)) { + if (lo & EXT_MEM0_ENABLE_F) { + hi = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A); + avail[i].base = EXT_MEM0_BASE_G(hi) << 20; + avail[i].limit = + avail[i].base + (EXT_MEM0_SIZE_G(hi) << 20); + avail[i].idx = 3; + i++; + } + if (lo & EXT_MEM1_ENABLE_F) { + hi = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A); + avail[i].base = EXT_MEM1_BASE_G(hi) << 20; + avail[i].limit = + avail[i].base + (EXT_MEM1_SIZE_G(hi) << 20); + avail[i].idx = 4; + i++; + } + } else { + if (lo & EXT_MEM_ENABLE_F) { + hi = t4_read_reg(adap, MA_EXT_MEMORY_BAR_A); + avail[i].base = EXT_MEM_BASE_G(hi) << 20; + avail[i].limit = + avail[i].base + (EXT_MEM_SIZE_G(hi) << 20); + avail[i].idx = 2; + i++; + } + } + if (!i) /* no memory available */ + return 0; + sort(avail, i, sizeof(struct mem_desc), mem_desc_cmp, NULL); + + (md++)->base = t4_read_reg(adap, SGE_DBQ_CTXT_BADDR_A); + (md++)->base = t4_read_reg(adap, SGE_IMSG_CTXT_BADDR_A); + (md++)->base = t4_read_reg(adap, SGE_FLM_CACHE_BADDR_A); + (md++)->base = t4_read_reg(adap, TP_CMM_TCB_BASE_A); + (md++)->base = t4_read_reg(adap, TP_CMM_MM_BASE_A); + (md++)->base = t4_read_reg(adap, TP_CMM_TIMER_BASE_A); + (md++)->base = t4_read_reg(adap, TP_CMM_MM_RX_FLST_BASE_A); + (md++)->base = t4_read_reg(adap, TP_CMM_MM_TX_FLST_BASE_A); + (md++)->base = t4_read_reg(adap, TP_CMM_MM_PS_FLST_BASE_A); + + /* the next few have explicit upper bounds */ + md->base = t4_read_reg(adap, TP_PMM_TX_BASE_A); + md->limit = md->base - 1 + + t4_read_reg(adap, TP_PMM_TX_PAGE_SIZE_A) * + PMTXMAXPAGE_G(t4_read_reg(adap, TP_PMM_TX_MAX_PAGE_A)); + md++; + + md->base = t4_read_reg(adap, TP_PMM_RX_BASE_A); + md->limit = md->base - 1 + + t4_read_reg(adap, TP_PMM_RX_PAGE_SIZE_A) * + PMRXMAXPAGE_G(t4_read_reg(adap, TP_PMM_RX_MAX_PAGE_A)); + md++; + + if (t4_read_reg(adap, LE_DB_CONFIG_A) & HASHEN_F) { + if (CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) { + hi = t4_read_reg(adap, LE_DB_TID_HASHBASE_A) / 4; + md->base = t4_read_reg(adap, LE_DB_HASH_TID_BASE_A); + } else { + hi = t4_read_reg(adap, LE_DB_HASH_TID_BASE_A); + md->base = t4_read_reg(adap, + LE_DB_HASH_TBL_BASE_ADDR_A); + } + md->limit = 0; + } else { + md->base = 0; + md->idx = ARRAY_SIZE(region); /* hide it */ + } + md++; + +#define ulp_region(reg) do { \ + md->base = t4_read_reg(adap, ULP_ ## reg ## _LLIMIT_A);\ + (md++)->limit = t4_read_reg(adap, ULP_ ## reg ## _ULIMIT_A); \ +} while (0) + + ulp_region(RX_ISCSI); + ulp_region(RX_TDDP); + ulp_region(TX_TPT); + ulp_region(RX_STAG); + ulp_region(RX_RQ); + ulp_region(RX_RQUDP); + ulp_region(RX_PBL); + ulp_region(TX_PBL); +#undef ulp_region + md->base = 0; + md->idx = ARRAY_SIZE(region); + if (!is_t4(adap->params.chip)) { + u32 size = 0; + u32 sge_ctrl = t4_read_reg(adap, SGE_CONTROL2_A); + u32 fifo_size = t4_read_reg(adap, SGE_DBVFIFO_SIZE_A); + + if (is_t5(adap->params.chip)) { + if (sge_ctrl & VFIFO_ENABLE_F) + size = DBVFIFO_SIZE_G(fifo_size); + } else { + size = T6_DBVFIFO_SIZE_G(fifo_size); + } + + if (size) { + md->base = BASEADDR_G(t4_read_reg(adap, + SGE_DBVFIFO_BADDR_A)); + md->limit = md->base + (size << 2) - 1; + } + } + + md++; + + md->base = t4_read_reg(adap, ULP_RX_CTX_BASE_A); + md->limit = 0; + md++; + md->base = t4_read_reg(adap, ULP_TX_ERR_TABLE_BASE_A); + md->limit = 0; + md++; + + md->base = adap->vres.ocq.start; + if (adap->vres.ocq.size) + md->limit = md->base + adap->vres.ocq.size - 1; + else + md->idx = ARRAY_SIZE(region); /* hide it */ + md++; + + /* add any address-space holes, there can be up to 3 */ + for (n = 0; n < i - 1; n++) + if (avail[n].limit < avail[n + 1].base) + (md++)->base = avail[n].limit; + if (avail[n].limit) + (md++)->base = avail[n].limit; + + n = md - mem; + sort(mem, n, sizeof(struct mem_desc), mem_desc_cmp, NULL); + + for (lo = 0; lo < i; lo++) + mem_region_show(seq, memory[avail[lo].idx], avail[lo].base, + avail[lo].limit - 1); + + seq_putc(seq, '\n'); + for (i = 0; i < n; i++) { + if (mem[i].idx >= ARRAY_SIZE(region)) + continue; /* skip holes */ + if (!mem[i].limit) + mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; + mem_region_show(seq, region[mem[i].idx], mem[i].base, + mem[i].limit); + } + + seq_putc(seq, '\n'); + lo = t4_read_reg(adap, CIM_SDRAM_BASE_ADDR_A); + hi = t4_read_reg(adap, CIM_SDRAM_ADDR_SIZE_A) + lo - 1; + mem_region_show(seq, "uP RAM:", lo, hi); + + lo = t4_read_reg(adap, CIM_EXTMEM2_BASE_ADDR_A); + hi = t4_read_reg(adap, CIM_EXTMEM2_ADDR_SIZE_A) + lo - 1; + mem_region_show(seq, "uP Extmem2:", lo, hi); + + lo = t4_read_reg(adap, TP_PMM_RX_MAX_PAGE_A); + seq_printf(seq, "\n%u Rx pages of size %uKiB for %u channels\n", + PMRXMAXPAGE_G(lo), + t4_read_reg(adap, TP_PMM_RX_PAGE_SIZE_A) >> 10, + (lo & PMRXNUMCHN_F) ? 2 : 1); + + lo = t4_read_reg(adap, TP_PMM_TX_MAX_PAGE_A); + hi = t4_read_reg(adap, TP_PMM_TX_PAGE_SIZE_A); + seq_printf(seq, "%u Tx pages of size %u%ciB for %u channels\n", + PMTXMAXPAGE_G(lo), + hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), + hi >= (1 << 20) ? 'M' : 'K', 1 << PMTXNUMCHN_G(lo)); + seq_printf(seq, "%u p-structs\n\n", + t4_read_reg(adap, TP_CMM_MM_MAX_PSTRUCT_A)); + + for (i = 0; i < 4; i++) { + if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) + lo = t4_read_reg(adap, MPS_RX_MAC_BG_PG_CNT0_A + i * 4); + else + lo = t4_read_reg(adap, MPS_RX_PG_RSV0_A + i * 4); + if (is_t5(adap->params.chip)) { + used = T5_USED_G(lo); + alloc = T5_ALLOC_G(lo); + } else { + used = USED_G(lo); + alloc = ALLOC_G(lo); + } + /* For T6 these are MAC buffer groups */ + seq_printf(seq, "Port %d using %u pages out of %u allocated\n", + i, used, alloc); + } + for (i = 0; i < adap->params.arch.nchan; i++) { + if (CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) + lo = t4_read_reg(adap, + MPS_RX_LPBK_BG_PG_CNT0_A + i * 4); + else + lo = t4_read_reg(adap, MPS_RX_PG_RSV4_A + i * 4); + if (is_t5(adap->params.chip)) { + used = T5_USED_G(lo); + alloc = T5_ALLOC_G(lo); + } else { + used = USED_G(lo); + alloc = ALLOC_G(lo); + } + /* For T6 these are MAC buffer groups */ + seq_printf(seq, + "Loopback %d using %u pages out of %u allocated\n", + i, used, alloc); + } + return 0; +} + +static int meminfo_open(struct inode *inode, struct file *file) +{ + return single_open(file, meminfo_show, inode->i_private); +} + +static const struct file_operations meminfo_fops = { + .owner = THIS_MODULE, + .open = meminfo_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; /* Add an array of Debug FS files. */ void add_debugfs_files(struct adapter *adap, @@ -2342,6 +2626,7 @@ int t4_setup_debugfs(struct adapter *adap) { "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 }, #endif { "blocked_fl", &blocked_fl_fops, S_IRUSR | S_IWUSR, 0 }, + { "meminfo", &meminfo_fops, S_IRUSR, 0 }, }; /* Debug FS nodes common to all T5 and later adapters. diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index ed8a8f350113..06268681a279 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -136,6 +136,20 @@ #define INGPACKBOUNDARY_G(x) (((x) >> INGPACKBOUNDARY_S) \ & INGPACKBOUNDARY_M) +#define VFIFO_ENABLE_S 10 +#define VFIFO_ENABLE_V(x) ((x) << VFIFO_ENABLE_S) +#define VFIFO_ENABLE_F VFIFO_ENABLE_V(1U) + +#define SGE_DBVFIFO_BADDR_A 0x1138 + +#define DBVFIFO_SIZE_S 6 +#define DBVFIFO_SIZE_M 0xfffU +#define DBVFIFO_SIZE_G(x) (((x) >> DBVFIFO_SIZE_S) & DBVFIFO_SIZE_M) + +#define T6_DBVFIFO_SIZE_S 0 +#define T6_DBVFIFO_SIZE_M 0x1fffU +#define T6_DBVFIFO_SIZE_G(x) (((x) >> T6_DBVFIFO_SIZE_S) & T6_DBVFIFO_SIZE_M) + #define GLOBALENABLE_S 0 #define GLOBALENABLE_V(x) ((x) << GLOBALENABLE_S) #define GLOBALENABLE_F GLOBALENABLE_V(1U) @@ -303,6 +317,8 @@ #define SGE_FL_BUFFER_SIZE7_A 0x1060 #define SGE_FL_BUFFER_SIZE8_A 0x1064 +#define SGE_IMSG_CTXT_BADDR_A 0x1088 +#define SGE_FLM_CACHE_BADDR_A 0x108c #define SGE_INGRESS_RX_THRESHOLD_A 0x10a0 #define THRESHOLD_0_S 24 @@ -357,6 +373,7 @@ #define TSVAL_G(x) (((x) >> TSVAL_S) & TSVAL_M) #define SGE_DBFIFO_STATUS_A 0x10a4 +#define SGE_DBVFIFO_SIZE_A 0x113c #define HP_INT_THRESH_S 28 #define HP_INT_THRESH_M 0xfU @@ -869,6 +886,10 @@ /* registers for module MA */ #define MA_EDRAM0_BAR_A 0x77c0 +#define EDRAM0_BASE_S 16 +#define EDRAM0_BASE_M 0xfffU +#define EDRAM0_BASE_G(x) (((x) >> EDRAM0_BASE_S) & EDRAM0_BASE_M) + #define EDRAM0_SIZE_S 0 #define EDRAM0_SIZE_M 0xfffU #define EDRAM0_SIZE_V(x) ((x) << EDRAM0_SIZE_S) @@ -876,6 +897,10 @@ #define MA_EDRAM1_BAR_A 0x77c4 +#define EDRAM1_BASE_S 16 +#define EDRAM1_BASE_M 0xfffU +#define EDRAM1_BASE_G(x) (((x) >> EDRAM1_BASE_S) & EDRAM1_BASE_M) + #define EDRAM1_SIZE_S 0 #define EDRAM1_SIZE_M 0xfffU #define EDRAM1_SIZE_V(x) ((x) << EDRAM1_SIZE_S) @@ -883,6 +908,11 @@ #define MA_EXT_MEMORY_BAR_A 0x77c8 +#define EXT_MEM_BASE_S 16 +#define EXT_MEM_BASE_M 0xfffU +#define EXT_MEM_BASE_V(x) ((x) << EXT_MEM_BASE_S) +#define EXT_MEM_BASE_G(x) (((x) >> EXT_MEM_BASE_S) & EXT_MEM_BASE_M) + #define EXT_MEM_SIZE_S 0 #define EXT_MEM_SIZE_M 0xfffU #define EXT_MEM_SIZE_V(x) ((x) << EXT_MEM_SIZE_S) @@ -890,6 +920,10 @@ #define MA_EXT_MEMORY1_BAR_A 0x7808 +#define EXT_MEM1_BASE_S 16 +#define EXT_MEM1_BASE_M 0xfffU +#define EXT_MEM1_BASE_G(x) (((x) >> EXT_MEM1_BASE_S) & EXT_MEM1_BASE_M) + #define EXT_MEM1_SIZE_S 0 #define EXT_MEM1_SIZE_M 0xfffU #define EXT_MEM1_SIZE_V(x) ((x) << EXT_MEM1_SIZE_S) @@ -897,6 +931,10 @@ #define MA_EXT_MEMORY0_BAR_A 0x77c8 +#define EXT_MEM0_BASE_S 16 +#define EXT_MEM0_BASE_M 0xfffU +#define EXT_MEM0_BASE_G(x) (((x) >> EXT_MEM0_BASE_S) & EXT_MEM0_BASE_M) + #define EXT_MEM0_SIZE_S 0 #define EXT_MEM0_SIZE_M 0xfffU #define EXT_MEM0_SIZE_V(x) ((x) << EXT_MEM0_SIZE_S) @@ -978,6 +1016,10 @@ /* registers for module CIM */ #define CIM_BOOT_CFG_A 0x7b00 +#define CIM_SDRAM_BASE_ADDR_A 0x7b14 +#define CIM_SDRAM_ADDR_SIZE_A 0x7b18 +#define CIM_EXTMEM2_BASE_ADDR_A 0x7b1c +#define CIM_EXTMEM2_ADDR_SIZE_A 0x7b20 #define CIM_PF_MAILBOX_CTRL_SHADOW_COPY_A 0x290 #define BOOTADDR_M 0xffffff00U @@ -1236,6 +1278,33 @@ #define TP_OUT_CONFIG_A 0x7d04 #define TP_GLOBAL_CONFIG_A 0x7d08 +#define TP_CMM_TCB_BASE_A 0x7d10 +#define TP_CMM_MM_BASE_A 0x7d14 +#define TP_CMM_TIMER_BASE_A 0x7d18 +#define TP_PMM_TX_BASE_A 0x7d20 +#define TP_PMM_RX_BASE_A 0x7d28 +#define TP_PMM_RX_PAGE_SIZE_A 0x7d2c +#define TP_PMM_RX_MAX_PAGE_A 0x7d30 +#define TP_PMM_TX_PAGE_SIZE_A 0x7d34 +#define TP_PMM_TX_MAX_PAGE_A 0x7d38 +#define TP_CMM_MM_MAX_PSTRUCT_A 0x7e6c + +#define PMRXNUMCHN_S 31 +#define PMRXNUMCHN_V(x) ((x) << PMRXNUMCHN_S) +#define PMRXNUMCHN_F PMRXNUMCHN_V(1U) + +#define PMTXNUMCHN_S 30 +#define PMTXNUMCHN_M 0x3U +#define PMTXNUMCHN_G(x) (((x) >> PMTXNUMCHN_S) & PMTXNUMCHN_M) + +#define PMTXMAXPAGE_S 0 +#define PMTXMAXPAGE_M 0x1fffffU +#define PMTXMAXPAGE_G(x) (((x) >> PMTXMAXPAGE_S) & PMTXMAXPAGE_M) + +#define PMRXMAXPAGE_S 0 +#define PMRXMAXPAGE_M 0x1fffffU +#define PMRXMAXPAGE_G(x) (((x) >> PMRXMAXPAGE_S) & PMRXMAXPAGE_M) + #define DBGLAMODE_S 14 #define DBGLAMODE_M 0x3U #define DBGLAMODE_G(x) (((x) >> DBGLAMODE_S) & DBGLAMODE_M) @@ -1343,6 +1412,9 @@ #define MTUVALUE_G(x) (((x) >> MTUVALUE_S) & MTUVALUE_M) #define TP_RSS_LKP_TABLE_A 0x7dec +#define TP_CMM_MM_RX_FLST_BASE_A 0x7e60 +#define TP_CMM_MM_TX_FLST_BASE_A 0x7e64 +#define TP_CMM_MM_PS_FLST_BASE_A 0x7e68 #define LKPTBLROWVLD_S 31 #define LKPTBLROWVLD_V(x) ((x) << LKPTBLROWVLD_S) @@ -1488,6 +1560,11 @@ #define TP_MIB_RQE_DFR_PKT_A 0x64 #define ULP_TX_INT_CAUSE_A 0x8dcc +#define ULP_TX_TPT_LLIMIT_A 0x8dd4 +#define ULP_TX_TPT_ULIMIT_A 0x8dd8 +#define ULP_TX_PBL_LLIMIT_A 0x8ddc +#define ULP_TX_PBL_ULIMIT_A 0x8de0 +#define ULP_TX_ERR_TABLE_BASE_A 0x8e04 #define PBL_BOUND_ERR_CH3_S 31 #define PBL_BOUND_ERR_CH3_V(x) ((x) << PBL_BOUND_ERR_CH3_S) @@ -2252,12 +2329,32 @@ #define MATCHSRAM_V(x) ((x) << MATCHSRAM_S) #define MATCHSRAM_F MATCHSRAM_V(1U) +#define MPS_RX_PG_RSV0_A 0x11010 +#define MPS_RX_PG_RSV4_A 0x11020 #define MPS_RX_PERR_INT_CAUSE_A 0x11074 +#define MPS_RX_MAC_BG_PG_CNT0_A 0x11208 +#define MPS_RX_LPBK_BG_PG_CNT0_A 0x11218 #define MPS_CLS_TCAM_Y_L_A 0xf000 #define MPS_CLS_TCAM_DATA0_A 0xf000 #define MPS_CLS_TCAM_DATA1_A 0xf004 +#define USED_S 16 +#define USED_M 0x7ffU +#define USED_G(x) (((x) >> USED_S) & USED_M) + +#define ALLOC_S 0 +#define ALLOC_M 0x7ffU +#define ALLOC_G(x) (((x) >> ALLOC_S) & ALLOC_M) + +#define T5_USED_S 16 +#define T5_USED_M 0xfffU +#define T5_USED_G(x) (((x) >> T5_USED_S) & T5_USED_M) + +#define T5_ALLOC_S 0 +#define T5_ALLOC_M 0xfffU +#define T5_ALLOC_G(x) (((x) >> T5_ALLOC_S) & T5_ALLOC_M) + #define DMACH_S 0 #define DMACH_M 0xffffU #define DMACH_G(x) (((x) >> DMACH_S) & DMACH_M) @@ -2415,8 +2512,21 @@ #define SLVFIFOPARINT_F SLVFIFOPARINT_V(1U) #define ULP_RX_INT_CAUSE_A 0x19158 +#define ULP_RX_ISCSI_LLIMIT_A 0x1915c +#define ULP_RX_ISCSI_ULIMIT_A 0x19160 #define ULP_RX_ISCSI_TAGMASK_A 0x19164 #define ULP_RX_ISCSI_PSZ_A 0x19168 +#define ULP_RX_TDDP_LLIMIT_A 0x1916c +#define ULP_RX_TDDP_ULIMIT_A 0x19170 +#define ULP_RX_STAG_LLIMIT_A 0x1917c +#define ULP_RX_STAG_ULIMIT_A 0x19180 +#define ULP_RX_RQ_LLIMIT_A 0x19184 +#define ULP_RX_RQ_ULIMIT_A 0x19188 +#define ULP_RX_PBL_LLIMIT_A 0x1918c +#define ULP_RX_PBL_ULIMIT_A 0x19190 +#define ULP_RX_CTX_BASE_A 0x19194 +#define ULP_RX_RQUDP_LLIMIT_A 0x191a4 +#define ULP_RX_RQUDP_ULIMIT_A 0x191a8 #define ULP_RX_LA_CTL_A 0x1923c #define ULP_RX_LA_RDPTR_A 0x19240 #define ULP_RX_LA_RDDATA_A 0x19244 @@ -2617,7 +2727,15 @@ #define T6_LIPMISS_V(x) ((x) << T6_LIPMISS_S) #define T6_LIPMISS_F T6_LIPMISS_V(1U) +#define LE_DB_CONFIG_A 0x19c04 +#define LE_DB_HASH_TID_BASE_A 0x19c30 +#define LE_DB_HASH_TBL_BASE_ADDR_A 0x19c30 #define LE_DB_INT_CAUSE_A 0x19c3c +#define LE_DB_TID_HASHBASE_A 0x19df8 + +#define HASHEN_S 20 +#define HASHEN_V(x) ((x) << HASHEN_S) +#define HASHEN_F HASHEN_V(1U) #define REQQPARERR_S 16 #define REQQPARERR_V(x) ((x) << REQQPARERR_S) @@ -2639,6 +2757,10 @@ #define LIP0_V(x) ((x) << LIP0_S) #define LIP0_F LIP0_V(1U) +#define BASEADDR_S 3 +#define BASEADDR_M 0x1fffffffU +#define BASEADDR_G(x) (((x) >> BASEADDR_S) & BASEADDR_M) + #define TCAMINTPERR_S 13 #define TCAMINTPERR_V(x) ((x) << TCAMINTPERR_S) #define TCAMINTPERR_F TCAMINTPERR_V(1U) -- cgit v1.3-6-gb490 From bf8ebb67dae0a07db7aebe7a65c178ff24d90842 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 4 Aug 2015 14:36:18 +0530 Subject: cxgb4: Add support to dump edc bist status Add support to dump edc bist status for ECC data errors Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 39 ++++++++++++++++++++++++++++ drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 5 ++-- 2 files changed, 42 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 800bd489dd75..b19329519dd5 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -345,6 +345,43 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size, FW_CMD_MAX_TIMEOUT); } +static int t4_edc_err_read(struct adapter *adap, int idx) +{ + u32 edc_ecc_err_addr_reg; + u32 rdata_reg; + + if (is_t4(adap->params.chip)) { + CH_WARN(adap, "%s: T4 NOT supported.\n", __func__); + return 0; + } + if (idx != 0 && idx != 1) { + CH_WARN(adap, "%s: idx %d NOT supported.\n", __func__, idx); + return 0; + } + + edc_ecc_err_addr_reg = EDC_T5_REG(EDC_H_ECC_ERR_ADDR_A, idx); + rdata_reg = EDC_T5_REG(EDC_H_BIST_STATUS_RDATA_A, idx); + + CH_WARN(adap, + "edc%d err addr 0x%x: 0x%x.\n", + idx, edc_ecc_err_addr_reg, + t4_read_reg(adap, edc_ecc_err_addr_reg)); + CH_WARN(adap, + "bist: 0x%x, status %llx %llx %llx %llx %llx %llx %llx %llx %llx.\n", + rdata_reg, + (unsigned long long)t4_read_reg64(adap, rdata_reg), + (unsigned long long)t4_read_reg64(adap, rdata_reg + 8), + (unsigned long long)t4_read_reg64(adap, rdata_reg + 16), + (unsigned long long)t4_read_reg64(adap, rdata_reg + 24), + (unsigned long long)t4_read_reg64(adap, rdata_reg + 32), + (unsigned long long)t4_read_reg64(adap, rdata_reg + 40), + (unsigned long long)t4_read_reg64(adap, rdata_reg + 48), + (unsigned long long)t4_read_reg64(adap, rdata_reg + 56), + (unsigned long long)t4_read_reg64(adap, rdata_reg + 64)); + + return 0; +} + /** * t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window * @adap: the adapter @@ -3283,6 +3320,8 @@ static void mem_intr_handler(struct adapter *adapter, int idx) if (v & ECC_CE_INT_CAUSE_F) { u32 cnt = ECC_CECNT_G(t4_read_reg(adapter, cnt_addr)); + t4_edc_err_read(adapter, idx); + t4_write_reg(adapter, cnt_addr, ECC_CECNT_V(ECC_CECNT_M)); if (printk_ratelimit()) dev_warn(adapter->pdev_dev, diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 06268681a279..13ce018a79ad 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -2867,10 +2867,11 @@ #define EDC_H_BIST_DATA_PATTERN_A 0x50010 #define EDC_H_BIST_STATUS_RDATA_A 0x50028 +#define EDC_H_ECC_ERR_ADDR_A 0x50084 #define EDC_T51_BASE_ADDR 0x50800 -#define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR) -#define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx) +#define EDC_T5_STRIDE (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR) +#define EDC_T5_REG(reg, idx) (reg + EDC_T5_STRIDE * idx) #define PL_VF_REV_A 0x4 #define PL_VF_WHOAMI_A 0x0 -- cgit v1.3-6-gb490 From d86bd29e0b31f30d5d85ab21385b59703ecc6464 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 4 Aug 2015 14:36:19 +0530 Subject: cxgb4/cxgb4vf: read the correct bits of PL Who Am I register Read the correct bits of PL Who Am I for the Source PF field which has changed in T6 Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 34 ++++++++++++++++++++++++- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 8 ++++-- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 4 +++ drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c | 3 ++- 4 files changed, 45 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index d582e175dfb6..27e87b6baa45 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4551,6 +4551,32 @@ static void free_some_resources(struct adapter *adapter) NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA) #define SEGMENT_SIZE 128 +static int get_chip_type(struct pci_dev *pdev, u32 pl_rev) +{ + int ver, chip; + u16 device_id; + + /* Retrieve adapter's device ID */ + pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); + ver = device_id >> 12; + switch (ver) { + case CHELSIO_T4: + chip |= CHELSIO_CHIP_CODE(CHELSIO_T4, pl_rev); + break; + case CHELSIO_T5: + chip |= CHELSIO_CHIP_CODE(CHELSIO_T5, pl_rev); + break; + case CHELSIO_T6: + chip |= CHELSIO_CHIP_CODE(CHELSIO_T6, pl_rev); + break; + default: + dev_err(&pdev->dev, "Device %d is not supported\n", + device_id); + return -EINVAL; + } + return chip; +} + static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int func, i, err, s_qpp, qpp, num_seg; @@ -4558,6 +4584,8 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) bool highdma = false; struct adapter *adapter = NULL; void __iomem *regs; + u32 whoami, pl_rev; + enum chip_type chip; printk_once(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION); @@ -4586,7 +4614,11 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_unmap_bar0; /* We control everything through one PF */ - func = SOURCEPF_G(readl(regs + PL_WHOAMI_A)); + whoami = readl(regs + PL_WHOAMI_A); + pl_rev = REV_G(readl(regs + PL_REV_A)); + chip = get_chip_type(pdev, pl_rev); + func = CHELSIO_CHIP_VERSION(chip) <= CHELSIO_T5 ? + SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami); if (func != ent->driver_data) { iounmap(regs); pci_disable_device(pdev); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index b19329519dd5..5c63ceb463d6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3529,7 +3529,9 @@ int t4_slow_intr_handler(struct adapter *adapter) void t4_intr_enable(struct adapter *adapter) { u32 val = 0; - u32 pf = SOURCEPF_G(t4_read_reg(adapter, PL_WHOAMI_A)); + u32 whoami = t4_read_reg(adapter, PL_WHOAMI_A); + u32 pf = CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ? + SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami); if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5) val = ERR_DROPPED_DB_F | ERR_EGR_CTXT_PRIO_F | DBFIFO_HP_INT_F; @@ -3554,7 +3556,9 @@ void t4_intr_enable(struct adapter *adapter) */ void t4_intr_disable(struct adapter *adapter) { - u32 pf = SOURCEPF_G(t4_read_reg(adapter, PL_WHOAMI_A)); + u32 whoami = t4_read_reg(adapter, PL_WHOAMI_A); + u32 pf = CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ? + SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami); t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), 0); t4_set_reg_field(adapter, PL_INT_MAP0_A, 1 << pf, 0); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 13ce018a79ad..e444dc4ebbd8 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -2588,6 +2588,10 @@ #define SOURCEPF_M 0x7U #define SOURCEPF_G(x) (((x) >> SOURCEPF_S) & SOURCEPF_M) +#define T6_SOURCEPF_S 9 +#define T6_SOURCEPF_M 0x7U +#define T6_SOURCEPF_G(x) (((x) >> T6_SOURCEPF_S) & T6_SOURCEPF_M) + #define PL_INT_CAUSE_A 0x1940c #define ULP_TX_S 27 diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c index 0db6dc9e9ed2..63dd5fdac5b9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c @@ -619,7 +619,8 @@ int t4vf_get_sge_params(struct adapter *adapter) */ whoami = t4_read_reg(adapter, T4VF_PL_BASE_ADDR + PL_VF_WHOAMI_A); - pf = SOURCEPF_G(whoami); + pf = CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5 ? + SOURCEPF_G(whoami) : T6_SOURCEPF_G(whoami); s_hps = (HOSTPAGESIZEPF0_S + (HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * pf); -- cgit v1.3-6-gb490 From f109ff110b0f3e34cea45996734da485a2fdaa42 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 4 Aug 2015 14:36:20 +0530 Subject: cxgb4: Update T6 register ranges Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 5c63ceb463d6..91750ad580ae 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -1359,9 +1359,10 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) }; static const unsigned int t6_reg_ranges[] = { - 0x1008, 0x114c, + 0x1008, 0x1124, + 0x1138, 0x114c, 0x1180, 0x11b4, - 0x11fc, 0x1250, + 0x11fc, 0x1254, 0x1280, 0x133c, 0x1800, 0x18fc, 0x3000, 0x302c, @@ -1384,16 +1385,16 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0x5c10, 0x5ec0, 0x5ec8, 0x5ecc, 0x6000, 0x6040, - 0x6058, 0x615c, + 0x6058, 0x619c, 0x7700, 0x7798, 0x77c0, 0x7880, 0x78cc, 0x78fc, 0x7b00, 0x7c54, 0x7d00, 0x7efc, - 0x8dc0, 0x8de0, + 0x8dc0, 0x8de4, 0x8df8, 0x8e84, 0x8ea0, 0x8f88, - 0x8fb8, 0x911c, + 0x8fb8, 0x9124, 0x9400, 0x9470, 0x9600, 0x971c, 0x9800, 0x9808, @@ -1413,9 +1414,8 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0xdfc0, 0xdfe0, 0xe000, 0xf008, 0x11000, 0x11014, - 0x11048, 0x11110, - 0x11118, 0x1117c, - 0x11190, 0x11264, + 0x11048, 0x1117c, + 0x11190, 0x11270, 0x11300, 0x1130c, 0x12000, 0x1206c, 0x19040, 0x1906c, @@ -1500,9 +1500,8 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0x1ff00, 0x1ff84, 0x1ffc0, 0x1ffc8, 0x30000, 0x30070, - 0x30100, 0x3015c, - 0x30190, 0x301d0, - 0x30200, 0x30318, + 0x30100, 0x301d0, + 0x30200, 0x30320, 0x30400, 0x3052c, 0x30540, 0x3061c, 0x30800, 0x30890, @@ -1578,9 +1577,8 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0x33c24, 0x33c50, 0x33cf0, 0x33cfc, 0x34000, 0x34070, - 0x34100, 0x3415c, - 0x34190, 0x341d0, - 0x34200, 0x34318, + 0x34100, 0x341d0, + 0x34200, 0x34320, 0x34400, 0x3452c, 0x34540, 0x3461c, 0x34800, 0x34890, -- cgit v1.3-6-gb490 From ff591a91225d3621a503bb18faa0f0d747a06e50 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Mon, 3 Aug 2015 19:23:52 +0200 Subject: reset: Add a driver for the reset controller on the AR71XX/AR9XXX The AR71XX/AR9XXX SoC have a simple reset controller with one bit per reset line. Signed-off-by: Alban Bedel Acked-by: Ralf Baechle Signed-off-by: Philipp Zabel --- arch/mips/Kconfig | 1 + drivers/reset/Makefile | 1 + drivers/reset/reset-ath79.c | 128 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 drivers/reset/reset-ath79.c (limited to 'drivers') diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index aab7e46cadd5..3a3548f267b4 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -118,6 +118,7 @@ config ATH25 config ATH79 bool "Atheros AR71XX/AR724X/AR913X based boards" + select ARCH_HAS_RESET_CONTROLLER select ARCH_REQUIRE_GPIOLIB select BOOT_RAW select CEVT_R4K diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 157d421f755b..f8db9b744b3a 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ +obj-$(CONFIG_ATH79) += reset-ath79.o diff --git a/drivers/reset/reset-ath79.c b/drivers/reset/reset-ath79.c new file mode 100644 index 000000000000..d2d290413113 --- /dev/null +++ b/drivers/reset/reset-ath79.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2015 Alban Bedel + * + * 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 + +struct ath79_reset { + struct reset_controller_dev rcdev; + void __iomem *base; + spinlock_t lock; +}; + +static int ath79_reset_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct ath79_reset *ath79_reset = + container_of(rcdev, struct ath79_reset, rcdev); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&ath79_reset->lock, flags); + val = readl(ath79_reset->base); + if (assert) + val |= BIT(id); + else + val &= ~BIT(id); + writel(val, ath79_reset->base); + spin_unlock_irqrestore(&ath79_reset->lock, flags); + + return 0; +} + +static int ath79_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return ath79_reset_update(rcdev, id, true); +} + +static int ath79_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return ath79_reset_update(rcdev, id, false); +} + +static int ath79_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct ath79_reset *ath79_reset = + container_of(rcdev, struct ath79_reset, rcdev); + u32 val; + + val = readl(ath79_reset->base); + + return !!(val & BIT(id)); +} + +static struct reset_control_ops ath79_reset_ops = { + .assert = ath79_reset_assert, + .deassert = ath79_reset_deassert, + .status = ath79_reset_status, +}; + +static int ath79_reset_probe(struct platform_device *pdev) +{ + struct ath79_reset *ath79_reset; + struct resource *res; + + ath79_reset = devm_kzalloc(&pdev->dev, + sizeof(*ath79_reset), GFP_KERNEL); + if (!ath79_reset) + return -ENOMEM; + + platform_set_drvdata(pdev, ath79_reset); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ath79_reset->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ath79_reset->base)) + return PTR_ERR(ath79_reset->base); + + ath79_reset->rcdev.ops = &ath79_reset_ops; + ath79_reset->rcdev.owner = THIS_MODULE; + ath79_reset->rcdev.of_node = pdev->dev.of_node; + ath79_reset->rcdev.of_reset_n_cells = 1; + ath79_reset->rcdev.nr_resets = 32; + + return reset_controller_register(&ath79_reset->rcdev); +} + +static int ath79_reset_remove(struct platform_device *pdev) +{ + struct ath79_reset *ath79_reset = platform_get_drvdata(pdev); + + reset_controller_unregister(&ath79_reset->rcdev); + + return 0; +} + +static const struct of_device_id ath79_reset_dt_ids[] = { + { .compatible = "qca,ar7100-reset", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ath79_reset_dt_ids); + +static struct platform_driver ath79_reset_driver = { + .probe = ath79_reset_probe, + .remove = ath79_reset_remove, + .driver = { + .name = "ath79-reset", + .of_match_table = ath79_reset_dt_ids, + }, +}; +module_platform_driver(ath79_reset_driver); + +MODULE_AUTHOR("Alban Bedel "); +MODULE_DESCRIPTION("AR71xx Reset Controller Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 327cbbabfb77c321fb9f21068c18e6bb951d07a7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 3 Aug 2015 00:05:03 +0100 Subject: crypto: img-hash - fix spelling mistake in dev_err error message Trival change, fix spelling mistake 'aquire' -> 'acquire' in dev_err message. Signed-off-by: Colin Ian King Signed-off-by: Herbert Xu --- drivers/crypto/img-hash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/img-hash.c b/drivers/crypto/img-hash.c index ad47d0d61098..68e8aa90fe01 100644 --- a/drivers/crypto/img-hash.c +++ b/drivers/crypto/img-hash.c @@ -334,7 +334,7 @@ static int img_hash_dma_init(struct img_hash_dev *hdev) hdev->dma_lch = dma_request_slave_channel(hdev->dev, "tx"); if (!hdev->dma_lch) { - dev_err(hdev->dev, "Couldn't aquire a slave DMA channel.\n"); + dev_err(hdev->dev, "Couldn't acquire a slave DMA channel.\n"); return -EBUSY; } dma_conf.direction = DMA_MEM_TO_DEV; -- cgit v1.3-6-gb490 From 76bea64c4c8d7fa911eb485c4c2b8583e813331e Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Mon, 3 Aug 2015 18:56:21 -0500 Subject: crypto: talitos - Remove zero_entry static initializer Compiling the talitos driver with my GCC 4.3.1 e500v2 cross-compiler resulted in a failed build due to the anonymous union/structures introduced in this commit: crypto: talitos - enhanced talitos_desc struct for SEC1 The build error was: drivers/crypto/talitos.h:56: error: unknown field 'len' specified in initializer drivers/crypto/talitos.h:56: warning: missing braces around initializer drivers/crypto/talitos.h:56: warning: (near initialization for 'zero_entry.') drivers/crypto/talitos.h:57: error: unknown field 'j_extent' specified in initializer drivers/crypto/talitos.h:58: error: unknown field 'eptr' specified in initializer drivers/crypto/talitos.h:58: warning: excess elements in struct initializer drivers/crypto/talitos.h:58: warning: (near initialization for 'zero_entry') make[2]: *** [drivers/crypto/talitos.o] Error 1 make[1]: *** [drivers/crypto] Error 2 make: *** [drivers] Error 2 This patch eliminates the errors by relying on the C standard's implicit assignment of zero to static variables. Signed-off-by: Aaron Sierra Signed-off-by: Herbert Xu --- drivers/crypto/talitos.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h index 314daf55e7f7..163cfe733bf0 100644 --- a/drivers/crypto/talitos.h +++ b/drivers/crypto/talitos.h @@ -52,12 +52,7 @@ struct talitos_ptr { __be32 ptr; /* address */ }; -static const struct talitos_ptr zero_entry = { - .len = 0, - .j_extent = 0, - .eptr = 0, - .ptr = 0 -}; +static const struct talitos_ptr zero_entry; /* descriptor */ struct talitos_desc { -- cgit v1.3-6-gb490 From c29a7baf091fc6b2c9e40561030f8c62e6145a19 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Thu, 6 Mar 2014 18:47:21 +0100 Subject: s390/numa: add emulation support NUMA emulation (aka fake NUMA) distributes the available memory to nodes without using real topology information about the physical memory of the machine. Splitting the system memory into nodes replicates the memory management structures for each node. Particularly each node has its own "mm locks" and its own "kswapd" task. For large systems, under certain conditions, this results in improved system performance and/or latency based on reduced pressure on the mm locks and the kswapd tasks. NUMA emulation distributes CPUs to nodes while respecting the original machine topology information. This is done by trying to avoid to separate CPUs which reside on the same book or even on the same MC. Because the current Linux scheduler code requires a stable cpu to node mapping, cores are pinned to nodes when the first CPU thread is set online. This patch is based on the initial implementation from Philipp Hachtmann. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- arch/s390/Kconfig | 37 ++++ arch/s390/include/asm/numa.h | 4 + arch/s390/numa/Makefile | 1 + arch/s390/numa/mode_emu.c | 511 +++++++++++++++++++++++++++++++++++++++++++ arch/s390/numa/numa.c | 4 + arch/s390/numa/numa_mode.h | 1 + drivers/s390/char/sclp_cmd.c | 18 +- 7 files changed, 569 insertions(+), 7 deletions(-) create mode 100644 arch/s390/numa/mode_emu.c (limited to 'drivers') diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 25510adb07d3..cb418dcc2d45 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -423,6 +423,43 @@ config NODES_SHIFT Specify the maximum number of NUMA nodes available on the target system. Increases memory reserved to accommodate various tables. +menu "Select NUMA modes" + depends on NUMA + +config NUMA_EMU + bool "NUMA emulation" + default y + help + Numa emulation mode will split the available system memory into + equal chunks which then are distributed over the configured number + of nodes in a round-robin manner. + + The number of fake nodes is limited by the number of available memory + chunks (i.e. memory size / fake size) and the number of supported + nodes in the kernel. + + The CPUs are assigned to the nodes in a way that partially respects + the original machine topology (if supported by the machine). + Fair distribution of the CPUs is not guaranteed. + +config EMU_SIZE + hex "NUMA emulation memory chunk size" + default 0x10000000 + range 0x400000 0x100000000 + depends on NUMA_EMU + help + Select the default size by which the memory is chopped and then + assigned to emulated NUMA nodes. + + This can be overridden by specifying + + emu_size= + + on the kernel command line where also suffixes K, M, G, and T are + supported. + +endmenu + config SCHED_MC def_bool n diff --git a/arch/s390/include/asm/numa.h b/arch/s390/include/asm/numa.h index ea4edbfba9f6..2a0efc63b9e5 100644 --- a/arch/s390/include/asm/numa.h +++ b/arch/s390/include/asm/numa.h @@ -26,6 +26,10 @@ extern int numa_debug_enabled; static inline void numa_setup(void) { } static inline void numa_update_cpu_topology(void) { } +static inline int numa_pfn_to_nid(unsigned long pfn) +{ + return 0; +} #endif /* CONFIG_NUMA */ #endif /* _ASM_S390_NUMA_H */ diff --git a/arch/s390/numa/Makefile b/arch/s390/numa/Makefile index 31372293b62e..f94ecaffa71b 100644 --- a/arch/s390/numa/Makefile +++ b/arch/s390/numa/Makefile @@ -1,2 +1,3 @@ obj-y += numa.o obj-y += toptree.o +obj-$(CONFIG_NUMA_EMU) += mode_emu.o diff --git a/arch/s390/numa/mode_emu.c b/arch/s390/numa/mode_emu.c new file mode 100644 index 000000000000..9d4e1e15a6f0 --- /dev/null +++ b/arch/s390/numa/mode_emu.c @@ -0,0 +1,511 @@ +/* + * NUMA support for s390 + * + * NUMA emulation (aka fake NUMA) distributes the available memory to nodes + * without using real topology information about the physical memory of the + * machine. + * + * It distributes the available CPUs to nodes while respecting the original + * machine topology information. This is done by trying to avoid to separate + * CPUs which reside on the same book or even on the same MC. + * + * Because the current Linux scheduler code requires a stable cpu to node + * mapping, cores are pinned to nodes when the first CPU thread is set online. + * + * Copyright IBM Corp. 2015 + */ + +#define KMSG_COMPONENT "numa_emu" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include "numa_mode.h" +#include "toptree.h" + +/* Distances between the different system components */ +#define DIST_EMPTY 0 +#define DIST_CORE 1 +#define DIST_MC 2 +#define DIST_BOOK 3 +#define DIST_MAX 4 + +/* Node distance reported to common code */ +#define EMU_NODE_DIST 10 + +/* Node ID for free (not yet pinned) cores */ +#define NODE_ID_FREE -1 + +/* Different levels of toptree */ +enum toptree_level {CORE, MC, BOOK, NODE, TOPOLOGY}; + +/* The two toptree IDs */ +enum {TOPTREE_ID_PHYS, TOPTREE_ID_NUMA}; + +/* Number of NUMA nodes */ +static int emu_nodes = 1; +/* NUMA stripe size */ +static unsigned long emu_size; +/* Pinned core to node mapping */ +static int cores_to_node_id[CONFIG_NR_CPUS]; +/* Total number of pinned cores */ +static int cores_total; +/* Number of cores per node without extra cores */ +static int cores_per_node_target; +/* Number of cores pinned to node */ +static int cores_per_node[MAX_NUMNODES]; + +/* + * Pin a core to a node + */ +static void pin_core_to_node(int core_id, int node_id) +{ + if (cores_to_node_id[core_id] == NODE_ID_FREE) { + cores_per_node[node_id]++; + cores_to_node_id[core_id] = node_id; + cores_total++; + } else { + WARN_ON(cores_to_node_id[core_id] != node_id); + } +} + +/* + * Number of pinned cores of a node + */ +static int cores_pinned(struct toptree *node) +{ + return cores_per_node[node->id]; +} + +/* + * ID of the node where the core is pinned (or NODE_ID_FREE) + */ +static int core_pinned_to_node_id(struct toptree *core) +{ + return cores_to_node_id[core->id]; +} + +/* + * Number of cores in the tree that are not yet pinned + */ +static int cores_free(struct toptree *tree) +{ + struct toptree *core; + int count = 0; + + toptree_for_each(core, tree, CORE) { + if (core_pinned_to_node_id(core) == NODE_ID_FREE) + count++; + } + return count; +} + +/* + * Return node of core + */ +static struct toptree *core_node(struct toptree *core) +{ + return core->parent->parent->parent; +} + +/* + * Return book of core + */ +static struct toptree *core_book(struct toptree *core) +{ + return core->parent->parent; +} + +/* + * Return mc of core + */ +static struct toptree *core_mc(struct toptree *core) +{ + return core->parent; +} + +/* + * Distance between two cores + */ +static int dist_core_to_core(struct toptree *core1, struct toptree *core2) +{ + if (core_book(core1)->id != core_book(core2)->id) + return DIST_BOOK; + if (core_mc(core1)->id != core_mc(core2)->id) + return DIST_MC; + /* Same core or sibling on same MC */ + return DIST_CORE; +} + +/* + * Distance of a node to a core + */ +static int dist_node_to_core(struct toptree *node, struct toptree *core) +{ + struct toptree *core_node; + int dist_min = DIST_MAX; + + toptree_for_each(core_node, node, CORE) + dist_min = min(dist_min, dist_core_to_core(core_node, core)); + return dist_min == DIST_MAX ? DIST_EMPTY : dist_min; +} + +/* + * Unify will delete empty nodes, therefore recreate nodes. + */ +static void toptree_unify_tree(struct toptree *tree) +{ + int nid; + + toptree_unify(tree); + for (nid = 0; nid < emu_nodes; nid++) + toptree_get_child(tree, nid); +} + +/* + * Find the best/nearest node for a given core and ensure that no node + * gets more than "cores_per_node_target + extra" cores. + */ +static struct toptree *node_for_core(struct toptree *numa, struct toptree *core, + int extra) +{ + struct toptree *node, *node_best = NULL; + int dist_cur, dist_best; + + dist_best = DIST_MAX; + node_best = NULL; + toptree_for_each(node, numa, NODE) { + /* Already pinned cores must use their nodes */ + if (core_pinned_to_node_id(core) == node->id) { + node_best = node; + break; + } + /* Skip nodes that already have enough cores */ + if (cores_pinned(node) >= cores_per_node_target + extra) + continue; + dist_cur = dist_node_to_core(node, core); + if (dist_cur < dist_best) { + dist_best = dist_cur; + node_best = node; + } + } + return node_best; +} + +/* + * Find the best node for each core with respect to "extra" core count + */ +static void toptree_to_numa_single(struct toptree *numa, struct toptree *phys, + int extra) +{ + struct toptree *node, *core, *tmp; + + toptree_for_each_safe(core, tmp, phys, CORE) { + node = node_for_core(numa, core, extra); + if (!node) + return; + toptree_move(core, node); + pin_core_to_node(core->id, node->id); + } +} + +/* + * Move structures of given level to specified NUMA node + */ +static void move_level_to_numa_node(struct toptree *node, struct toptree *phys, + enum toptree_level level, bool perfect) +{ + struct toptree *cur, *tmp; + int cores_free; + + toptree_for_each_safe(cur, tmp, phys, level) { + cores_free = cores_per_node_target - toptree_count(node, CORE); + if (perfect) { + if (cores_free == toptree_count(cur, CORE)) + toptree_move(cur, node); + } else { + if (cores_free >= toptree_count(cur, CORE)) + toptree_move(cur, node); + } + } +} + +/* + * Move structures of a given level to NUMA nodes. If "perfect" is specified + * move only perfectly fitting structures. Otherwise move also smaller + * than needed structures. + */ +static void move_level_to_numa(struct toptree *numa, struct toptree *phys, + enum toptree_level level, bool perfect) +{ + struct toptree *node; + + toptree_for_each(node, numa, NODE) + move_level_to_numa_node(node, phys, level, perfect); +} + +/* + * For the first run try to move the big structures + */ +static void toptree_to_numa_first(struct toptree *numa, struct toptree *phys) +{ + struct toptree *core; + + /* Always try to move perfectly fitting structures first */ + move_level_to_numa(numa, phys, BOOK, true); + move_level_to_numa(numa, phys, BOOK, false); + move_level_to_numa(numa, phys, MC, true); + move_level_to_numa(numa, phys, MC, false); + /* Now pin all the moved cores */ + toptree_for_each(core, numa, CORE) + pin_core_to_node(core->id, core_node(core)->id); +} + +/* + * Allocate new topology and create required nodes + */ +static struct toptree *toptree_new(int id, int nodes) +{ + struct toptree *tree; + int nid; + + tree = toptree_alloc(TOPOLOGY, id); + if (!tree) + goto fail; + for (nid = 0; nid < nodes; nid++) { + if (!toptree_get_child(tree, nid)) + goto fail; + } + return tree; +fail: + panic("NUMA emulation could not allocate topology"); +} + +/* + * Move cores from physical topology into NUMA target topology + * and try to keep as much of the physical topology as possible. + */ +static struct toptree *toptree_to_numa(struct toptree *phys) +{ + static int first = 1; + struct toptree *numa; + + cores_per_node_target = (cores_total + cores_free(phys)) / emu_nodes; + numa = toptree_new(TOPTREE_ID_NUMA, emu_nodes); + if (first) { + toptree_to_numa_first(numa, phys); + first = 0; + } + toptree_to_numa_single(numa, phys, 0); + toptree_to_numa_single(numa, phys, 1); + toptree_unify_tree(numa); + + WARN_ON(cpumask_weight(&phys->mask)); + return numa; +} + +/* + * Create a toptree out of the physical topology that we got from the hypervisor + */ +static struct toptree *toptree_from_topology(void) +{ + struct toptree *phys, *node, *book, *mc, *core; + struct cpu_topology_s390 *top; + int cpu; + + phys = toptree_new(TOPTREE_ID_PHYS, 1); + + for_each_online_cpu(cpu) { + top = &per_cpu(cpu_topology, cpu); + node = toptree_get_child(phys, 0); + book = toptree_get_child(node, top->book_id); + mc = toptree_get_child(book, top->socket_id); + core = toptree_get_child(mc, top->core_id); + if (!book || !mc || !core) + panic("NUMA emulation could not allocate memory"); + cpumask_set_cpu(cpu, &core->mask); + toptree_update_mask(mc); + } + return phys; +} + +/* + * Add toptree core to topology and create correct CPU masks + */ +static void topology_add_core(struct toptree *core) +{ + struct cpu_topology_s390 *top; + int cpu; + + for_each_cpu(cpu, &core->mask) { + top = &per_cpu(cpu_topology, cpu); + cpumask_copy(&top->thread_mask, &core->mask); + cpumask_copy(&top->core_mask, &core_mc(core)->mask); + cpumask_copy(&top->book_mask, &core_book(core)->mask); + cpumask_set_cpu(cpu, node_to_cpumask_map[core_node(core)->id]); + top->node_id = core_node(core)->id; + } +} + +/* + * Apply toptree to topology and create CPU masks + */ +static void toptree_to_topology(struct toptree *numa) +{ + struct toptree *core; + int i; + + /* Clear all node masks */ + for (i = 0; i < MAX_NUMNODES; i++) + cpumask_clear(node_to_cpumask_map[i]); + + /* Rebuild all masks */ + toptree_for_each(core, numa, CORE) + topology_add_core(core); +} + +/* + * Show the node to core mapping + */ +static void print_node_to_core_map(void) +{ + int nid, cid; + + if (!numa_debug_enabled) + return; + printk(KERN_DEBUG "NUMA node to core mapping\n"); + for (nid = 0; nid < emu_nodes; nid++) { + printk(KERN_DEBUG " node %3d: ", nid); + for (cid = 0; cid < ARRAY_SIZE(cores_to_node_id); cid++) { + if (cores_to_node_id[cid] == nid) + printk(KERN_CONT "%d ", cid); + } + printk(KERN_CONT "\n"); + } +} + +/* + * Transfer physical topology into a NUMA topology and modify CPU masks + * according to the NUMA topology. + * + * This function is called under the CPU hotplug lock. + */ +static void emu_update_cpu_topology(void) +{ + struct toptree *phys, *numa; + + phys = toptree_from_topology(); + numa = toptree_to_numa(phys); + toptree_free(phys); + toptree_to_topology(numa); + toptree_free(numa); + print_node_to_core_map(); +} + +/* + * If emu_size is not set, use CONFIG_EMU_SIZE. Then round to minimum + * alignment (needed for memory hotplug). + */ +static unsigned long emu_setup_size_adjust(unsigned long size) +{ + size = size ? : CONFIG_EMU_SIZE; + size = roundup(size, memory_block_size_bytes()); + return size; +} + +/* + * If we have not enough memory for the specified nodes, reduce the node count. + */ +static int emu_setup_nodes_adjust(int nodes) +{ + int nodes_max; + + nodes_max = memblock.memory.total_size / emu_size; + nodes_max = max(nodes_max, 1); + if (nodes_max >= nodes) + return nodes; + pr_warn("Not enough memory for %d nodes, reducing node count\n", nodes); + return nodes_max; +} + +/* + * Early emu setup + */ +static void emu_setup(void) +{ + int i; + + emu_size = emu_setup_size_adjust(emu_size); + emu_nodes = emu_setup_nodes_adjust(emu_nodes); + for (i = 0; i < ARRAY_SIZE(cores_to_node_id); i++) + cores_to_node_id[i] = NODE_ID_FREE; + pr_info("Creating %d nodes with memory stripe size %ld MB\n", + emu_nodes, emu_size >> 20); +} + +/* + * Return node id for given page number + */ +static int emu_pfn_to_nid(unsigned long pfn) +{ + return (pfn / (emu_size >> PAGE_SHIFT)) % emu_nodes; +} + +/* + * Return stripe size + */ +static unsigned long emu_align(void) +{ + return emu_size; +} + +/* + * Return distance between two nodes + */ +static int emu_distance(int node1, int node2) +{ + return (node1 != node2) * EMU_NODE_DIST; +} + +/* + * Define callbacks for generic s390 NUMA infrastructure + */ +const struct numa_mode numa_mode_emu = { + .name = "emu", + .setup = emu_setup, + .update_cpu_topology = emu_update_cpu_topology, + .__pfn_to_nid = emu_pfn_to_nid, + .align = emu_align, + .distance = emu_distance, +}; + +/* + * Kernel parameter: emu_nodes= + */ +static int __init early_parse_emu_nodes(char *p) +{ + int count; + + if (kstrtoint(p, 0, &count) != 0 || count <= 0) + return 0; + if (count <= 0) + return 0; + emu_nodes = min(count, MAX_NUMNODES); + return 0; +} +early_param("emu_nodes", early_parse_emu_nodes); + +/* + * Kernel parameter: emu_size=[[k|M|G|T]] + */ +static int __init early_parse_emu_size(char *p) +{ + emu_size = memparse(p, NULL); + return 0; +} +early_param("emu_size", early_parse_emu_size); diff --git a/arch/s390/numa/numa.c b/arch/s390/numa/numa.c index 0416a3671e33..09b1d2355bd9 100644 --- a/arch/s390/numa/numa.c +++ b/arch/s390/numa/numa.c @@ -175,6 +175,10 @@ static int __init parse_numa(char *parm) { if (strcmp(parm, numa_mode_plain.name) == 0) mode = &numa_mode_plain; +#ifdef CONFIG_NUMA_EMU + if (strcmp(parm, numa_mode_emu.name) == 0) + mode = &numa_mode_emu; +#endif return 0; } early_param("numa", parse_numa); diff --git a/arch/s390/numa/numa_mode.h b/arch/s390/numa/numa_mode.h index 775659848011..08953b0b1c7f 100644 --- a/arch/s390/numa/numa_mode.h +++ b/arch/s390/numa/numa_mode.h @@ -19,5 +19,6 @@ struct numa_mode { }; extern const struct numa_mode numa_mode_plain; +extern const struct numa_mode numa_mode_emu; #endif /* __S390_NUMA_MODE_H */ diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index e9485fbbb373..806239c2cf2f 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "sclp.h" @@ -388,11 +389,11 @@ static struct notifier_block sclp_mem_nb = { }; static void __init align_to_block_size(unsigned long long *start, - unsigned long long *size) + unsigned long long *size, + unsigned long long alignment) { - unsigned long long start_align, size_align, alignment; + unsigned long long start_align, size_align; - alignment = memory_block_size_bytes(); start_align = roundup(*start, alignment); size_align = rounddown(*start + *size, alignment) - start_align; @@ -404,8 +405,8 @@ static void __init align_to_block_size(unsigned long long *start, static void __init add_memory_merged(u16 rn) { + unsigned long long start, size, addr, block_size; static u16 first_rn, num; - unsigned long long start, size; if (rn && first_rn && (first_rn + num == rn)) { num++; @@ -423,9 +424,12 @@ static void __init add_memory_merged(u16 rn) goto skip_add; if (memory_end_set && (start + size > memory_end)) size = memory_end - start; - align_to_block_size(&start, &size); - if (size) - add_memory(0, start, size); + block_size = memory_block_size_bytes(); + align_to_block_size(&start, &size, block_size); + if (!size) + goto skip_add; + for (addr = start; addr < start + size; addr += block_size) + add_memory(numa_pfn_to_nid(PFN_DOWN(addr)), addr, block_size); skip_add: first_rn = rn; num = 1; -- cgit v1.3-6-gb490 From 567e5a014848c6aeb1d6fc862b1b5d0183760259 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 31 Jul 2015 09:44:11 +0100 Subject: irqchip/gic: Only allow the primary GIC to set the CPU map The gic_init_bases() function initialises an array that stores the mapping between the GIC and CPUs. This array is a global array that is unconditionally initialised on every call to gic_init_bases(). Although, it is not common for there to be more than one GIC instance, there are some devices that do support nested GIC controllers and gic_init_bases() can be called more than once. A 2nd call to gic_init_bases() will clear the previous CPU mapping and will only setup the mapping again for the CPU calling gic_init_bases(). Fix this by only allowing the CPU map to be configured for the primary GIC. For secondary GICs the CPU map is not relevant because these GICs do not directly route the interrupts to the main CPU(s) but to other GICs or devices. Signed-off-by: Jon Hunter Reviewed-by: Marc Zyngier Cc: Cc: Russell King Cc: Nicolas Pitre Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438332252-25248-1-git-send-email-jonathanh@nvidia.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic.c | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 29c544d0aaa9..84fc622d0309 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -402,19 +402,26 @@ static void gic_cpu_init(struct gic_chip_data *gic) int i; /* - * Get what the GIC says our CPU mask is. + * Setting up the CPU map is only relevant for the primary GIC + * because any nested/secondary GICs do not directly interface + * with the CPU(s). */ - BUG_ON(cpu >= NR_GIC_CPU_IF); - cpu_mask = gic_get_cpumask(gic); - gic_cpu_map[cpu] = cpu_mask; + if (gic == &gic_data[0]) { + /* + * Get what the GIC says our CPU mask is. + */ + BUG_ON(cpu >= NR_GIC_CPU_IF); + cpu_mask = gic_get_cpumask(gic); + gic_cpu_map[cpu] = cpu_mask; - /* - * Clear our mask from the other map entries in case they're - * still undefined. - */ - for (i = 0; i < NR_GIC_CPU_IF; i++) - if (i != cpu) - gic_cpu_map[i] &= ~cpu_mask; + /* + * Clear our mask from the other map entries in case they're + * still undefined. + */ + for (i = 0; i < NR_GIC_CPU_IF; i++) + if (i != cpu) + gic_cpu_map[i] &= ~cpu_mask; + } gic_cpu_config(dist_base, NULL); @@ -925,13 +932,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic_set_base_accessor(gic, gic_get_common_base); } - /* - * Initialize the CPU interface map to all CPUs. - * It will be refined as each CPU probes its ID. - */ - for (i = 0; i < NR_GIC_CPU_IF; i++) - gic_cpu_map[i] = 0xff; - /* * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources. @@ -977,6 +977,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, return; if (gic_nr == 0) { + /* + * Initialize the CPU interface map to all CPUs. + * It will be refined as each CPU probes its ID. + * This is only necessary for the primary GIC. + */ + for (i = 0; i < NR_GIC_CPU_IF; i++) + gic_cpu_map[i] = 0xff; #ifdef CONFIG_SMP set_smp_cross_call(gic_raise_softirq); register_cpu_notifier(&gic_cpu_notifier); -- cgit v1.3-6-gb490 From 4c2880b31c700b03f3f115b5ca64be615783aa9c Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 31 Jul 2015 09:44:12 +0100 Subject: irqchip/gic: Ensure gic_cpu_if_up/down() programs correct GIC instance Commit 3228950621d9 ("irqchip: gic: Preserve gic V2 bypass bits in cpu ctrl register") added a new function, gic_cpu_if_up(), to program the GIC CPU_CTRL register. This function assumes that there is only one GIC instance present and hence always uses the chip data for the primary GIC controller. Although it is not common for there to be a secondary, some devices do support a secondary. Therefore, fix this by passing gic_cpu_if_up() a pointer to the appropriate chip data structure. Similarly, the function gic_cpu_if_down() only assumes that there is a single GIC instance present. Update this function so that an instance number is passed for the appropriate GIC and return an error code on failure. The vexpress TC2 (which has a single GIC) is currently the only user of this function and so update it accordingly. Note that because the TC2 only has a single GIC, the call to gic_cpu_if_down() should always be successful. Signed-off-by: Jon Hunter Reviewed-by: Marc Zyngier Cc: Cc: Russell King Cc: Nicolas Pitre Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438332252-25248-2-git-send-email-jonathanh@nvidia.com Signed-off-by: Thomas Gleixner --- arch/arm/mach-vexpress/tc2_pm.c | 2 +- drivers/irqchip/irq-gic.c | 18 ++++++++++++------ include/linux/irqchip/arm-gic.h | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-vexpress/tc2_pm.c b/arch/arm/mach-vexpress/tc2_pm.c index b3328cd46c33..1aa4ccece69f 100644 --- a/arch/arm/mach-vexpress/tc2_pm.c +++ b/arch/arm/mach-vexpress/tc2_pm.c @@ -80,7 +80,7 @@ static void tc2_pm_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster) * to the CPU by disabling the GIC CPU IF to prevent wfi * from completing execution behind power controller back */ - gic_cpu_if_down(); + gic_cpu_if_down(0); } static void tc2_pm_cluster_powerdown_prepare(unsigned int cluster) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 84fc622d0309..aa3e7b8a69c4 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -356,9 +356,9 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic) return mask; } -static void gic_cpu_if_up(void) +static void gic_cpu_if_up(struct gic_chip_data *gic) { - void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]); + void __iomem *cpu_base = gic_data_cpu_base(gic); u32 bypass = 0; /* @@ -426,17 +426,23 @@ static void gic_cpu_init(struct gic_chip_data *gic) gic_cpu_config(dist_base, NULL); writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK); - gic_cpu_if_up(); + gic_cpu_if_up(gic); } -void gic_cpu_if_down(void) +int gic_cpu_if_down(unsigned int gic_nr) { - void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]); + void __iomem *cpu_base; u32 val = 0; + if (gic_nr >= MAX_GIC_NR) + return -EINVAL; + + cpu_base = gic_data_cpu_base(&gic_data[gic_nr]); val = readl(cpu_base + GIC_CPU_CTRL); val &= ~GICC_ENABLE; writel_relaxed(val, cpu_base + GIC_CPU_CTRL); + + return 0; } #ifdef CONFIG_CPU_PM @@ -572,7 +578,7 @@ static void gic_cpu_restore(unsigned int gic_nr) dist_base + GIC_DIST_PRI + i * 4); writel_relaxed(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK); - gic_cpu_if_up(); + gic_cpu_if_up(&gic_data[gic_nr]); } static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v) diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 61a2007eb49a..65da435d01c1 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -98,7 +98,7 @@ struct device_node; void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, u32 offset, struct device_node *); void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); -void gic_cpu_if_down(void); +int gic_cpu_if_down(unsigned int gic_nr); static inline void gic_init(unsigned int nr, int start, void __iomem *dist , void __iomem *cpu) -- cgit v1.3-6-gb490 From 479bcc7c5b9e1cbf3278462d786c37e468d5d404 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Jul 2015 17:53:17 +0800 Subject: crypto: caam - Convert authenc to new AEAD interface This patch converts the authenc implementations in caam to the new AEAD interface. The biggest change is that seqiv no longer generates a random IV. Instead the IPsec sequence number is used as the IV. Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 2603 +++++++++++++++++++++-------------------- 1 file changed, 1337 insertions(+), 1266 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index e49373409582..b09c1711b37c 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -68,19 +68,21 @@ #define AEAD_DESC_JOB_IO_LEN (DESC_JOB_IO_LEN + CAAM_CMD_SZ * 2) #define GCM_DESC_JOB_IO_LEN (AEAD_DESC_JOB_IO_LEN + \ CAAM_CMD_SZ * 4) +#define AUTHENC_DESC_JOB_IO_LEN (AEAD_DESC_JOB_IO_LEN + \ + CAAM_CMD_SZ * 5) /* length of descriptors text */ #define DESC_AEAD_BASE (4 * CAAM_CMD_SZ) -#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ) -#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 18 * CAAM_CMD_SZ) -#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 7 * CAAM_CMD_SZ) +#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 11 * CAAM_CMD_SZ) +#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ) +#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 9 * CAAM_CMD_SZ) /* Note: Nonce is counted in enckeylen */ -#define DESC_AEAD_CTR_RFC3686_LEN (6 * CAAM_CMD_SZ) +#define DESC_AEAD_CTR_RFC3686_LEN (4 * CAAM_CMD_SZ) #define DESC_AEAD_NULL_BASE (3 * CAAM_CMD_SZ) -#define DESC_AEAD_NULL_ENC_LEN (DESC_AEAD_NULL_BASE + 14 * CAAM_CMD_SZ) -#define DESC_AEAD_NULL_DEC_LEN (DESC_AEAD_NULL_BASE + 17 * CAAM_CMD_SZ) +#define DESC_AEAD_NULL_ENC_LEN (DESC_AEAD_NULL_BASE + 11 * CAAM_CMD_SZ) +#define DESC_AEAD_NULL_DEC_LEN (DESC_AEAD_NULL_BASE + 13 * CAAM_CMD_SZ) #define DESC_GCM_BASE (3 * CAAM_CMD_SZ) #define DESC_GCM_ENC_LEN (DESC_GCM_BASE + 16 * CAAM_CMD_SZ) @@ -111,6 +113,20 @@ #endif static struct list_head alg_list; +struct caam_alg_entry { + int class1_alg_type; + int class2_alg_type; + int alg_op; + bool rfc3686; + bool geniv; +}; + +struct caam_aead_alg { + struct aead_alg aead; + struct caam_alg_entry caam; + bool registered; +}; + /* Set DK bit in class 1 operation if shared */ static inline void append_dec_op1(u32 *desc, u32 type) { @@ -144,18 +160,6 @@ static inline void aead_append_src_dst(u32 *desc, u32 msg_type) KEY_VLF | msg_type | FIFOLD_TYPE_LASTBOTH); } -/* - * For aead encrypt and decrypt, read iv for both classes - */ -static inline void aead_append_ld_iv(u32 *desc, int ivsize, int ivoffset) -{ - append_seq_load(desc, ivsize, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - (ivoffset << LDST_OFFSET_SHIFT)); - append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | - (ivoffset << MOVE_OFFSET_SHIFT) | ivsize); -} - /* * For ablkcipher encrypt and decrypt, read from req->src and * write to req->dst @@ -169,13 +173,6 @@ static inline void ablkcipher_append_src_dst(u32 *desc) append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); } -/* - * If all data, including src (with assoc and iv) or dst (with iv only) are - * contiguous - */ -#define GIV_SRC_CONTIG 1 -#define GIV_DST_CONTIG (1 << 1) - /* * per-session context */ @@ -259,7 +256,6 @@ static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, static int aead_null_set_sh_desc(struct crypto_aead *aead) { - unsigned int ivsize = crypto_aead_ivsize(aead); struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; bool keys_fit_inline = false; @@ -270,11 +266,11 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - if (DESC_AEAD_NULL_ENC_LEN + DESC_JOB_IO_LEN + + if (DESC_AEAD_NULL_ENC_LEN + AEAD_DESC_JOB_IO_LEN + ctx->split_key_pad_len <= CAAM_DESC_BYTES_MAX) keys_fit_inline = true; - /* old_aead_encrypt shared descriptor */ + /* aead_encrypt shared descriptor */ desc = ctx->sh_desc_enc; init_sh_desc(desc, HDR_SHARE_SERIAL); @@ -291,20 +287,10 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) KEY_DEST_MDHA_SPLIT | KEY_ENC); set_jump_tgt_here(desc, key_jump_cmd); - /* cryptlen = seqoutlen - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); - - /* - * NULL encryption; IV is zero - * assoclen = (assoclen + cryptlen) - cryptlen - */ - append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG3, CAAM_CMD_SZ); - - /* read assoc before reading payload */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | - KEY_VLF); + /* assoclen + cryptlen = seqinlen */ + append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ); - /* Prepare to read and write cryptlen bytes */ + /* Prepare to read and write cryptlen + assoclen bytes */ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); @@ -363,7 +349,7 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) desc = ctx->sh_desc_dec; - /* old_aead_decrypt shared descriptor */ + /* aead_decrypt shared descriptor */ init_sh_desc(desc, HDR_SHARE_SERIAL); /* Skip if already shared */ @@ -382,18 +368,10 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) append_operation(desc, ctx->class2_alg_type | OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); - /* assoclen + cryptlen = seqinlen - ivsize - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, - ctx->authsize + ivsize); - /* assoclen = (assoclen + cryptlen) - cryptlen */ + /* assoclen + cryptlen = seqoutlen */ append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); - append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ); - /* read assoc before reading payload */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | - KEY_VLF); - - /* Prepare to read and write cryptlen bytes */ + /* Prepare to read and write cryptlen + assoclen bytes */ append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ); @@ -450,10 +428,10 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) static int aead_set_sh_desc(struct crypto_aead *aead) { + struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead), + struct caam_aead_alg, aead); unsigned int ivsize = crypto_aead_ivsize(aead); struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct crypto_tfm *ctfm = crypto_aead_tfm(aead); - const char *alg_name = crypto_tfm_alg_name(ctfm); struct device *jrdev = ctx->jrdev; bool keys_fit_inline; u32 geniv, moveiv; @@ -461,11 +439,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) u32 *desc; const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_CTR_MOD128); - const bool is_rfc3686 = (ctr_mode && - (strstr(alg_name, "rfc3686") != NULL)); - - if (!ctx->authsize) - return 0; + const bool is_rfc3686 = alg->caam.rfc3686; /* NULL encryption / decryption */ if (!ctx->enckeylen) @@ -486,18 +460,21 @@ static int aead_set_sh_desc(struct crypto_aead *aead) if (is_rfc3686) ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; + if (alg->caam.geniv) + goto skip_enc; + /* * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ keys_fit_inline = false; - if (DESC_AEAD_ENC_LEN + DESC_JOB_IO_LEN + + if (DESC_AEAD_ENC_LEN + AUTHENC_DESC_JOB_IO_LEN + ctx->split_key_pad_len + ctx->enckeylen + (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= CAAM_DESC_BYTES_MAX) keys_fit_inline = true; - /* old_aead_encrypt shared descriptor */ + /* aead_encrypt shared descriptor */ desc = ctx->sh_desc_enc; /* Note: Context registers are saved. */ @@ -507,19 +484,16 @@ static int aead_set_sh_desc(struct crypto_aead *aead) append_operation(desc, ctx->class2_alg_type | OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); - /* cryptlen = seqoutlen - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); - - /* assoclen + cryptlen = seqinlen - ivsize */ - append_math_sub_imm_u32(desc, REG2, SEQINLEN, IMM, ivsize); + /* Read and write assoclen bytes */ + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - /* assoclen = (assoclen + cryptlen) - cryptlen */ - append_math_sub(desc, VARSEQINLEN, REG2, REG3, CAAM_CMD_SZ); + /* Skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); /* read assoc before reading payload */ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | - KEY_VLF); - aead_append_ld_iv(desc, ivsize, ctx1_iv_off); + FIFOLDST_VLF); /* Load Counter into CONTEXT1 reg */ if (is_rfc3686) @@ -534,8 +508,8 @@ static int aead_set_sh_desc(struct crypto_aead *aead) OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); /* Read and write cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); aead_append_src_dst(desc, FIFOLD_TYPE_MSG1OUT2); /* Write ICV */ @@ -555,18 +529,19 @@ static int aead_set_sh_desc(struct crypto_aead *aead) desc_bytes(desc), 1); #endif +skip_enc: /* * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ keys_fit_inline = false; - if (DESC_AEAD_DEC_LEN + DESC_JOB_IO_LEN + + if (DESC_AEAD_DEC_LEN + AUTHENC_DESC_JOB_IO_LEN + ctx->split_key_pad_len + ctx->enckeylen + (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= CAAM_DESC_BYTES_MAX) keys_fit_inline = true; - /* old_aead_decrypt shared descriptor */ + /* aead_decrypt shared descriptor */ desc = ctx->sh_desc_dec; /* Note: Context registers are saved. */ @@ -576,19 +551,17 @@ static int aead_set_sh_desc(struct crypto_aead *aead) append_operation(desc, ctx->class2_alg_type | OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); - /* assoclen + cryptlen = seqinlen - ivsize - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, - ctx->authsize + ivsize); - /* assoclen = (assoclen + cryptlen) - cryptlen */ - append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); - append_math_sub(desc, VARSEQINLEN, REG3, REG2, CAAM_CMD_SZ); + /* Read and write assoclen bytes */ + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + + /* Skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); /* read assoc before reading payload */ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | KEY_VLF); - aead_append_ld_iv(desc, ivsize, ctx1_iv_off); - /* Load Counter into CONTEXT1 reg */ if (is_rfc3686) append_load_imm_u32(desc, be32_to_cpu(1), LDST_IMM | @@ -605,8 +578,8 @@ static int aead_set_sh_desc(struct crypto_aead *aead) append_dec_op1(desc, ctx->class1_alg_type); /* Read and write cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ); + append_math_add(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); aead_append_src_dst(desc, FIFOLD_TYPE_MSG); /* Load ICV */ @@ -626,12 +599,15 @@ static int aead_set_sh_desc(struct crypto_aead *aead) desc_bytes(desc), 1); #endif + if (!alg->caam.geniv) + goto skip_givenc; + /* * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ keys_fit_inline = false; - if (DESC_AEAD_GIVENC_LEN + DESC_JOB_IO_LEN + + if (DESC_AEAD_GIVENC_LEN + AUTHENC_DESC_JOB_IO_LEN + ctx->split_key_pad_len + ctx->enckeylen + (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= CAAM_DESC_BYTES_MAX) @@ -643,6 +619,9 @@ static int aead_set_sh_desc(struct crypto_aead *aead) /* Note: Context registers are saved. */ init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); + if (is_rfc3686) + goto copy_iv; + /* Generate IV */ geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | @@ -656,6 +635,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) (ivsize << MOVE_LEN_SHIFT)); append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); +copy_iv: /* Copy IV to class 1 context */ append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_OUTFIFO | (ctx1_iv_off << MOVE_OFFSET_SHIFT) | @@ -668,8 +648,12 @@ static int aead_set_sh_desc(struct crypto_aead *aead) /* ivsize + cryptlen = seqoutlen - authsize */ append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); - /* assoclen = seqinlen - (ivsize + cryptlen) */ - append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG3, CAAM_CMD_SZ); + /* Read and write assoclen bytes */ + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + + /* Skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); /* read assoc before reading payload */ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | @@ -710,9 +694,9 @@ static int aead_set_sh_desc(struct crypto_aead *aead) append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_CONTEXT); - ctx->sh_desc_givenc_dma = dma_map_single(jrdev, desc, - desc_bytes(desc), - DMA_TO_DEVICE); + ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, + desc_bytes(desc), + DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->sh_desc_givenc_dma)) { dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; @@ -723,6 +707,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) desc_bytes(desc), 1); #endif +skip_givenc: return 0; } @@ -1805,22 +1790,6 @@ static void aead_unmap(struct device *dev, edesc->sec4_sg_dma, edesc->sec4_sg_bytes); } -static void old_aead_unmap(struct device *dev, - struct aead_edesc *edesc, - struct aead_request *req) -{ - struct crypto_aead *aead = crypto_aead_reqtfm(req); - int ivsize = crypto_aead_ivsize(aead); - - dma_unmap_sg_chained(dev, req->assoc, edesc->assoc_nents, - DMA_TO_DEVICE, edesc->assoc_chained); - - caam_unmap(dev, req->src, req->dst, - edesc->src_nents, edesc->src_chained, edesc->dst_nents, - edesc->dst_chained, edesc->iv_dma, ivsize, - edesc->sec4_sg_dma, edesc->sec4_sg_bytes); -} - static void ablkcipher_unmap(struct device *dev, struct ablkcipher_edesc *edesc, struct ablkcipher_request *req) @@ -1856,45 +1825,6 @@ static void aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err, aead_request_complete(req, err); } -static void old_aead_encrypt_done(struct device *jrdev, u32 *desc, u32 err, - void *context) -{ - struct aead_request *req = context; - struct aead_edesc *edesc; -#ifdef DEBUG - struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct caam_ctx *ctx = crypto_aead_ctx(aead); - int ivsize = crypto_aead_ivsize(aead); - - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif - - edesc = (struct aead_edesc *)((char *)desc - - offsetof(struct aead_edesc, hw_desc)); - - if (err) - caam_jr_strstatus(jrdev, err); - - old_aead_unmap(jrdev, edesc, req); - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "assoc @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc), - req->assoclen , 1); - print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src) - ivsize, - edesc->src_nents ? 100 : ivsize, 1); - print_hex_dump(KERN_ERR, "dst @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - edesc->src_nents ? 100 : req->cryptlen + - ctx->authsize + 4, 1); -#endif - - kfree(edesc); - - aead_request_complete(req, err); -} - static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err, void *context) { @@ -1923,62 +1853,6 @@ static void aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err, aead_request_complete(req, err); } -static void old_aead_decrypt_done(struct device *jrdev, u32 *desc, u32 err, - void *context) -{ - struct aead_request *req = context; - struct aead_edesc *edesc; -#ifdef DEBUG - struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct caam_ctx *ctx = crypto_aead_ctx(aead); - int ivsize = crypto_aead_ivsize(aead); - - dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); -#endif - - edesc = (struct aead_edesc *)((char *)desc - - offsetof(struct aead_edesc, hw_desc)); - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->iv, - ivsize, 1); - print_hex_dump(KERN_ERR, "dst @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->dst), - req->cryptlen - ctx->authsize, 1); -#endif - - if (err) - caam_jr_strstatus(jrdev, err); - - old_aead_unmap(jrdev, edesc, req); - - /* - * verify hw auth check passed else return -EBADMSG - */ - if ((err & JRSTA_CCBERR_ERRID_MASK) == JRSTA_CCBERR_ERRID_ICVCHK) - err = -EBADMSG; - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "iphdrout@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, - ((char *)sg_virt(req->assoc) - sizeof(struct iphdr)), - sizeof(struct iphdr) + req->assoclen + - ((req->cryptlen > 1500) ? 1500 : req->cryptlen) + - ctx->authsize + 36, 1); - if (!err && edesc->sec4_sg_bytes) { - struct scatterlist *sg = sg_last(req->src, edesc->src_nents); - print_hex_dump(KERN_ERR, "sglastout@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(sg), - sg->length + ctx->authsize + 16, 1); - } -#endif - - kfree(edesc); - - aead_request_complete(req, err); -} - static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, void *context) { @@ -2044,91 +1918,6 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, ablkcipher_request_complete(req, err); } -/* - * Fill in aead job descriptor - */ -static void old_init_aead_job(u32 *sh_desc, dma_addr_t ptr, - struct aead_edesc *edesc, - struct aead_request *req, - bool all_contig, bool encrypt) -{ - struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct caam_ctx *ctx = crypto_aead_ctx(aead); - int ivsize = crypto_aead_ivsize(aead); - int authsize = ctx->authsize; - u32 *desc = edesc->hw_desc; - u32 out_options = 0, in_options; - dma_addr_t dst_dma, src_dma; - int len, sec4_sg_index = 0; - bool is_gcm = false; - -#ifdef DEBUG - debug("assoclen %d cryptlen %d authsize %d\n", - req->assoclen, req->cryptlen, authsize); - print_hex_dump(KERN_ERR, "assoc @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc), - req->assoclen , 1); - print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->iv, - edesc->src_nents ? 100 : ivsize, 1); - print_hex_dump(KERN_ERR, "src @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - edesc->src_nents ? 100 : req->cryptlen, 1); - print_hex_dump(KERN_ERR, "shrdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sh_desc, - desc_bytes(sh_desc), 1); -#endif - - if (((ctx->class1_alg_type & OP_ALG_ALGSEL_MASK) == - OP_ALG_ALGSEL_AES) && - ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_GCM)) - is_gcm = true; - - len = desc_len(sh_desc); - init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); - - if (all_contig) { - if (is_gcm) - src_dma = edesc->iv_dma; - else - src_dma = sg_dma_address(req->assoc); - in_options = 0; - } else { - src_dma = edesc->sec4_sg_dma; - sec4_sg_index += (edesc->assoc_nents ? : 1) + 1 + - (edesc->src_nents ? : 1); - in_options = LDST_SGF; - } - - append_seq_in_ptr(desc, src_dma, req->assoclen + ivsize + req->cryptlen, - in_options); - - if (likely(req->src == req->dst)) { - if (all_contig) { - dst_dma = sg_dma_address(req->src); - } else { - dst_dma = src_dma + sizeof(struct sec4_sg_entry) * - ((edesc->assoc_nents ? : 1) + 1); - out_options = LDST_SGF; - } - } else { - if (!edesc->dst_nents) { - dst_dma = sg_dma_address(req->dst); - } else { - dst_dma = edesc->sec4_sg_dma + - sec4_sg_index * - sizeof(struct sec4_sg_entry); - out_options = LDST_SGF; - } - } - if (encrypt) - append_seq_out_ptr(desc, dst_dma, req->cryptlen + authsize, - out_options); - else - append_seq_out_ptr(desc, dst_dma, req->cryptlen - authsize, - out_options); -} - /* * Fill in aead job descriptor */ @@ -2220,80 +2009,43 @@ static void init_gcm_job(struct aead_request *req, /* End of blank commands */ } -/* - * Fill in aead givencrypt job descriptor - */ -static void init_aead_giv_job(u32 *sh_desc, dma_addr_t ptr, - struct aead_edesc *edesc, - struct aead_request *req, - int contig) +static void init_authenc_job(struct aead_request *req, + struct aead_edesc *edesc, + bool all_contig, bool encrypt) { struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead), + struct caam_aead_alg, aead); + unsigned int ivsize = crypto_aead_ivsize(aead); struct caam_ctx *ctx = crypto_aead_ctx(aead); - int ivsize = crypto_aead_ivsize(aead); - int authsize = ctx->authsize; + const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == + OP_ALG_AAI_CTR_MOD128); + const bool is_rfc3686 = alg->caam.rfc3686; u32 *desc = edesc->hw_desc; - u32 out_options = 0, in_options; - dma_addr_t dst_dma, src_dma; - int len, sec4_sg_index = 0; - bool is_gcm = false; + u32 ivoffset = 0; -#ifdef DEBUG - debug("assoclen %d cryptlen %d authsize %d\n", - req->assoclen, req->cryptlen, authsize); - print_hex_dump(KERN_ERR, "assoc @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->assoc), - req->assoclen , 1); - print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, req->iv, ivsize, 1); - print_hex_dump(KERN_ERR, "src @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - edesc->src_nents > 1 ? 100 : req->cryptlen, 1); - print_hex_dump(KERN_ERR, "shrdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sh_desc, - desc_bytes(sh_desc), 1); -#endif - - if (((ctx->class1_alg_type & OP_ALG_ALGSEL_MASK) == - OP_ALG_ALGSEL_AES) && - ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_GCM)) - is_gcm = true; - - len = desc_len(sh_desc); - init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); + /* + * AES-CTR needs to load IV in CONTEXT1 reg + * at an offset of 128bits (16bytes) + * CONTEXT1[255:128] = IV + */ + if (ctr_mode) + ivoffset = 16; - if (contig & GIV_SRC_CONTIG) { - if (is_gcm) - src_dma = edesc->iv_dma; - else - src_dma = sg_dma_address(req->assoc); - in_options = 0; - } else { - src_dma = edesc->sec4_sg_dma; - sec4_sg_index += edesc->assoc_nents + 1 + edesc->src_nents; - in_options = LDST_SGF; - } - append_seq_in_ptr(desc, src_dma, req->assoclen + ivsize + req->cryptlen, - in_options); + /* + * RFC3686 specific: + * CONTEXT1[255:128] = {NONCE, IV, COUNTER} + */ + if (is_rfc3686) + ivoffset = 16 + CTR_RFC3686_NONCE_SIZE; - if (contig & GIV_DST_CONTIG) { - dst_dma = edesc->iv_dma; - } else { - if (likely(req->src == req->dst)) { - dst_dma = src_dma + sizeof(struct sec4_sg_entry) * - (edesc->assoc_nents + - (is_gcm ? 1 + edesc->src_nents : 0)); - out_options = LDST_SGF; - } else { - dst_dma = edesc->sec4_sg_dma + - sec4_sg_index * - sizeof(struct sec4_sg_entry); - out_options = LDST_SGF; - } - } + init_aead_job(req, edesc, all_contig, encrypt); - append_seq_out_ptr(desc, dst_dma, ivsize + req->cryptlen + authsize, - out_options); + if (ivsize && (is_rfc3686 || !(alg->caam.geniv && encrypt))) + append_load_as_imm(desc, req->iv, ivsize, + LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + (ivoffset << LDST_OFFSET_SHIFT)); } /* @@ -2404,177 +2156,33 @@ static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr, /* * allocate and map the aead extended descriptor */ -static struct aead_edesc *old_aead_edesc_alloc(struct aead_request *req, - int desc_bytes, - bool *all_contig_ptr, - bool encrypt) +static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, + int desc_bytes, bool *all_contig_ptr, + bool encrypt) { struct crypto_aead *aead = crypto_aead_reqtfm(req); struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; - int assoc_nents, src_nents, dst_nents = 0; + int src_nents, dst_nents = 0; struct aead_edesc *edesc; - dma_addr_t iv_dma = 0; int sgc; bool all_contig = true; - bool assoc_chained = false, src_chained = false, dst_chained = false; - int ivsize = crypto_aead_ivsize(aead); + bool src_chained = false, dst_chained = false; int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes; unsigned int authsize = ctx->authsize; - bool is_gcm = false; - - assoc_nents = sg_count(req->assoc, req->assoclen, &assoc_chained); if (unlikely(req->dst != req->src)) { - src_nents = sg_count(req->src, req->cryptlen, &src_chained); + src_nents = sg_count(req->src, req->assoclen + req->cryptlen, + &src_chained); dst_nents = sg_count(req->dst, - req->cryptlen + + req->assoclen + req->cryptlen + (encrypt ? authsize : (-authsize)), &dst_chained); } else { src_nents = sg_count(req->src, - req->cryptlen + - (encrypt ? authsize : 0), - &src_chained); - } - - sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1, - DMA_TO_DEVICE, assoc_chained); - if (likely(req->src == req->dst)) { - sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, - DMA_BIDIRECTIONAL, src_chained); - } else { - sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, - DMA_TO_DEVICE, src_chained); - sgc = dma_map_sg_chained(jrdev, req->dst, dst_nents ? : 1, - DMA_FROM_DEVICE, dst_chained); - } - - iv_dma = dma_map_single(jrdev, req->iv, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, iv_dma)) { - dev_err(jrdev, "unable to map IV\n"); - return ERR_PTR(-ENOMEM); - } - - if (((ctx->class1_alg_type & OP_ALG_ALGSEL_MASK) == - OP_ALG_ALGSEL_AES) && - ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_GCM)) - is_gcm = true; - - /* - * Check if data are contiguous. - * GCM expected input sequence: IV, AAD, text - * All other - expected input sequence: AAD, IV, text - */ - if (is_gcm) - all_contig = (!assoc_nents && - iv_dma + ivsize == sg_dma_address(req->assoc) && - !src_nents && sg_dma_address(req->assoc) + - req->assoclen == sg_dma_address(req->src)); - else - all_contig = (!assoc_nents && sg_dma_address(req->assoc) + - req->assoclen == iv_dma && !src_nents && - iv_dma + ivsize == sg_dma_address(req->src)); - if (!all_contig) { - assoc_nents = assoc_nents ? : 1; - src_nents = src_nents ? : 1; - sec4_sg_len = assoc_nents + 1 + src_nents; - } - - sec4_sg_len += dst_nents; - - sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); - - /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct aead_edesc) + desc_bytes + - sec4_sg_bytes, GFP_DMA | flags); - if (!edesc) { - dev_err(jrdev, "could not allocate extended descriptor\n"); - return ERR_PTR(-ENOMEM); - } - - edesc->assoc_nents = assoc_nents; - edesc->assoc_chained = assoc_chained; - edesc->src_nents = src_nents; - edesc->src_chained = src_chained; - edesc->dst_nents = dst_nents; - edesc->dst_chained = dst_chained; - edesc->iv_dma = iv_dma; - edesc->sec4_sg_bytes = sec4_sg_bytes; - edesc->sec4_sg = (void *)edesc + sizeof(struct aead_edesc) + - desc_bytes; - *all_contig_ptr = all_contig; - - sec4_sg_index = 0; - if (!all_contig) { - if (!is_gcm) { - sg_to_sec4_sg_len(req->assoc, req->assoclen, - edesc->sec4_sg + sec4_sg_index); - sec4_sg_index += assoc_nents; - } - - dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index, - iv_dma, ivsize, 0); - sec4_sg_index += 1; - - if (is_gcm) { - sg_to_sec4_sg_len(req->assoc, req->assoclen, - edesc->sec4_sg + sec4_sg_index); - sec4_sg_index += assoc_nents; - } - - sg_to_sec4_sg_last(req->src, - src_nents, - edesc->sec4_sg + - sec4_sg_index, 0); - sec4_sg_index += src_nents; - } - if (dst_nents) { - sg_to_sec4_sg_last(req->dst, dst_nents, - edesc->sec4_sg + sec4_sg_index, 0); - } - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return ERR_PTR(-ENOMEM); - } - - return edesc; -} - -/* - * allocate and map the aead extended descriptor - */ -static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, - int desc_bytes, bool *all_contig_ptr, - bool encrypt) -{ - struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; - int src_nents, dst_nents = 0; - struct aead_edesc *edesc; - int sgc; - bool all_contig = true; - bool src_chained = false, dst_chained = false; - int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes; - unsigned int authsize = ctx->authsize; - - if (unlikely(req->dst != req->src)) { - src_nents = sg_count(req->src, req->assoclen + req->cryptlen, - &src_chained); - dst_nents = sg_count(req->dst, - req->assoclen + req->cryptlen + - (encrypt ? authsize : (-authsize)), - &dst_chained); - } else { - src_nents = sg_count(req->src, - req->assoclen + req->cryptlen + + req->assoclen + req->cryptlen + (encrypt ? authsize : 0), &src_chained); } @@ -2705,7 +2313,7 @@ static int ipsec_gcm_encrypt(struct aead_request *req) return gcm_encrypt(req); } -static int old_aead_encrypt(struct aead_request *req) +static int aead_encrypt(struct aead_request *req) { struct aead_edesc *edesc; struct crypto_aead *aead = crypto_aead_reqtfm(req); @@ -2716,14 +2324,13 @@ static int old_aead_encrypt(struct aead_request *req) int ret = 0; /* allocate extended descriptor */ - edesc = old_aead_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &all_contig, true); + edesc = aead_edesc_alloc(req, AUTHENC_DESC_JOB_IO_LEN, + &all_contig, true); if (IS_ERR(edesc)) return PTR_ERR(edesc); /* Create and submit job descriptor */ - old_init_aead_job(ctx->sh_desc_enc, ctx->sh_desc_enc_dma, edesc, req, - all_contig, true); + init_authenc_job(req, edesc, all_contig, true); #ifdef DEBUG print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, @@ -2731,11 +2338,11 @@ static int old_aead_encrypt(struct aead_request *req) #endif desc = edesc->hw_desc; - ret = caam_jr_enqueue(jrdev, desc, old_aead_encrypt_done, req); + ret = caam_jr_enqueue(jrdev, desc, aead_encrypt_done, req); if (!ret) { ret = -EINPROGRESS; } else { - old_aead_unmap(jrdev, edesc, req); + aead_unmap(jrdev, edesc, req); kfree(edesc); } @@ -2785,7 +2392,7 @@ static int ipsec_gcm_decrypt(struct aead_request *req) return gcm_decrypt(req); } -static int old_aead_decrypt(struct aead_request *req) +static int aead_decrypt(struct aead_request *req) { struct aead_edesc *edesc; struct crypto_aead *aead = crypto_aead_reqtfm(req); @@ -2796,20 +2403,19 @@ static int old_aead_decrypt(struct aead_request *req) int ret = 0; /* allocate extended descriptor */ - edesc = old_aead_edesc_alloc(req, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &all_contig, false); + edesc = aead_edesc_alloc(req, AUTHENC_DESC_JOB_IO_LEN, + &all_contig, false); if (IS_ERR(edesc)) return PTR_ERR(edesc); #ifdef DEBUG print_hex_dump(KERN_ERR, "dec src@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - req->cryptlen, 1); + req->assoclen + req->cryptlen, 1); #endif /* Create and submit job descriptor*/ - old_init_aead_job(ctx->sh_desc_dec, - ctx->sh_desc_dec_dma, edesc, req, all_contig, false); + init_authenc_job(req, edesc, all_contig, false); #ifdef DEBUG print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, @@ -2817,232 +2423,29 @@ static int old_aead_decrypt(struct aead_request *req) #endif desc = edesc->hw_desc; - ret = caam_jr_enqueue(jrdev, desc, old_aead_decrypt_done, req); + ret = caam_jr_enqueue(jrdev, desc, aead_decrypt_done, req); if (!ret) { ret = -EINPROGRESS; } else { - old_aead_unmap(jrdev, edesc, req); + aead_unmap(jrdev, edesc, req); kfree(edesc); } return ret; } -/* - * allocate and map the aead extended descriptor for aead givencrypt - */ -static struct aead_edesc *aead_giv_edesc_alloc(struct aead_givcrypt_request - *greq, int desc_bytes, - u32 *contig_ptr) -{ - struct aead_request *req = &greq->areq; - struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; - int assoc_nents, src_nents, dst_nents = 0; - struct aead_edesc *edesc; - dma_addr_t iv_dma = 0; - int sgc; - u32 contig = GIV_SRC_CONTIG | GIV_DST_CONTIG; - int ivsize = crypto_aead_ivsize(aead); - bool assoc_chained = false, src_chained = false, dst_chained = false; - int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes; - bool is_gcm = false; - - assoc_nents = sg_count(req->assoc, req->assoclen, &assoc_chained); - src_nents = sg_count(req->src, req->cryptlen, &src_chained); - - if (unlikely(req->dst != req->src)) - dst_nents = sg_count(req->dst, req->cryptlen + ctx->authsize, - &dst_chained); - - sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1, - DMA_TO_DEVICE, assoc_chained); - if (likely(req->src == req->dst)) { - sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, - DMA_BIDIRECTIONAL, src_chained); - } else { - sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, - DMA_TO_DEVICE, src_chained); - sgc = dma_map_sg_chained(jrdev, req->dst, dst_nents ? : 1, - DMA_FROM_DEVICE, dst_chained); - } - - iv_dma = dma_map_single(jrdev, greq->giv, ivsize, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, iv_dma)) { - dev_err(jrdev, "unable to map IV\n"); - return ERR_PTR(-ENOMEM); - } - - if (((ctx->class1_alg_type & OP_ALG_ALGSEL_MASK) == - OP_ALG_ALGSEL_AES) && - ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_GCM)) - is_gcm = true; - - /* - * Check if data are contiguous. - * GCM expected input sequence: IV, AAD, text - * All other - expected input sequence: AAD, IV, text - */ - - if (is_gcm) { - if (assoc_nents || iv_dma + ivsize != - sg_dma_address(req->assoc) || src_nents || - sg_dma_address(req->assoc) + req->assoclen != - sg_dma_address(req->src)) - contig &= ~GIV_SRC_CONTIG; - } else { - if (assoc_nents || - sg_dma_address(req->assoc) + req->assoclen != iv_dma || - src_nents || iv_dma + ivsize != sg_dma_address(req->src)) - contig &= ~GIV_SRC_CONTIG; - } - - if (dst_nents || iv_dma + ivsize != sg_dma_address(req->dst)) - contig &= ~GIV_DST_CONTIG; - - if (!(contig & GIV_SRC_CONTIG)) { - assoc_nents = assoc_nents ? : 1; - src_nents = src_nents ? : 1; - sec4_sg_len += assoc_nents + 1 + src_nents; - if (req->src == req->dst && - (src_nents || iv_dma + ivsize != sg_dma_address(req->src))) - contig &= ~GIV_DST_CONTIG; - } - - /* - * Add new sg entries for GCM output sequence. - * Expected output sequence: IV, encrypted text. - */ - if (is_gcm && req->src == req->dst && !(contig & GIV_DST_CONTIG)) - sec4_sg_len += 1 + src_nents; - - if (unlikely(req->src != req->dst)) { - dst_nents = dst_nents ? : 1; - sec4_sg_len += 1 + dst_nents; - } - - sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); - - /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct aead_edesc) + desc_bytes + - sec4_sg_bytes, GFP_DMA | flags); - if (!edesc) { - dev_err(jrdev, "could not allocate extended descriptor\n"); - return ERR_PTR(-ENOMEM); - } - - edesc->assoc_nents = assoc_nents; - edesc->assoc_chained = assoc_chained; - edesc->src_nents = src_nents; - edesc->src_chained = src_chained; - edesc->dst_nents = dst_nents; - edesc->dst_chained = dst_chained; - edesc->iv_dma = iv_dma; - edesc->sec4_sg_bytes = sec4_sg_bytes; - edesc->sec4_sg = (void *)edesc + sizeof(struct aead_edesc) + - desc_bytes; - *contig_ptr = contig; - - sec4_sg_index = 0; - if (!(contig & GIV_SRC_CONTIG)) { - if (!is_gcm) { - sg_to_sec4_sg_len(req->assoc, req->assoclen, - edesc->sec4_sg + sec4_sg_index); - sec4_sg_index += assoc_nents; - } - - dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index, - iv_dma, ivsize, 0); - sec4_sg_index += 1; - - if (is_gcm) { - sg_to_sec4_sg_len(req->assoc, req->assoclen, - edesc->sec4_sg + sec4_sg_index); - sec4_sg_index += assoc_nents; - } - - sg_to_sec4_sg_last(req->src, src_nents, - edesc->sec4_sg + - sec4_sg_index, 0); - sec4_sg_index += src_nents; - } - - if (is_gcm && req->src == req->dst && !(contig & GIV_DST_CONTIG)) { - dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index, - iv_dma, ivsize, 0); - sec4_sg_index += 1; - sg_to_sec4_sg_last(req->src, src_nents, - edesc->sec4_sg + sec4_sg_index, 0); - } - - if (unlikely(req->src != req->dst && !(contig & GIV_DST_CONTIG))) { - dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index, - iv_dma, ivsize, 0); - sec4_sg_index += 1; - sg_to_sec4_sg_last(req->dst, dst_nents, - edesc->sec4_sg + sec4_sg_index, 0); - } - edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, - sec4_sg_bytes, DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { - dev_err(jrdev, "unable to map S/G table\n"); - return ERR_PTR(-ENOMEM); - } - - return edesc; -} - -static int old_aead_givencrypt(struct aead_givcrypt_request *areq) +static int aead_givdecrypt(struct aead_request *req) { - struct aead_request *req = &areq->areq; - struct aead_edesc *edesc; struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct caam_ctx *ctx = crypto_aead_ctx(aead); - struct device *jrdev = ctx->jrdev; - u32 contig; - u32 *desc; - int ret = 0; - - /* allocate extended descriptor */ - edesc = aead_giv_edesc_alloc(areq, DESC_JOB_IO_LEN * - CAAM_CMD_SZ, &contig); - - if (IS_ERR(edesc)) - return PTR_ERR(edesc); - -#ifdef DEBUG - print_hex_dump(KERN_ERR, "giv src@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(req->src), - req->cryptlen, 1); -#endif - - /* Create and submit job descriptor*/ - init_aead_giv_job(ctx->sh_desc_givenc, - ctx->sh_desc_givenc_dma, edesc, req, contig); -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead jobdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, edesc->hw_desc, - desc_bytes(edesc->hw_desc), 1); -#endif + unsigned int ivsize = crypto_aead_ivsize(aead); - desc = edesc->hw_desc; - ret = caam_jr_enqueue(jrdev, desc, old_aead_encrypt_done, req); - if (!ret) { - ret = -EINPROGRESS; - } else { - old_aead_unmap(jrdev, edesc, req); - kfree(edesc); - } + if (req->cryptlen < ivsize) + return -EINVAL; - return ret; -} + req->cryptlen -= ivsize; + req->assoclen += ivsize; -static int aead_null_givencrypt(struct aead_givcrypt_request *areq) -{ - return old_aead_encrypt(&areq->areq); + return aead_decrypt(req); } /* @@ -3375,7 +2778,6 @@ struct caam_alg_template { u32 type; union { struct ablkcipher_alg ablkcipher; - struct old_aead_alg aead; } template_u; u32 class1_alg_type; u32 class2_alg_type; @@ -3383,753 +2785,1426 @@ struct caam_alg_template { }; static struct caam_alg_template driver_algs[] = { - /* single-pass ipsec_esp descriptor */ - { - .name = "authenc(hmac(md5),ecb(cipher_null))", - .driver_name = "authenc-hmac-md5-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = aead_null_givencrypt, - .geniv = "", - .ivsize = NULL_IV_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, - }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, - }, + /* ablkcipher descriptor */ { - .name = "authenc(hmac(sha1),ecb(cipher_null))", - .driver_name = "authenc-hmac-sha1-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = aead_null_givencrypt, + .name = "cbc(aes)", + .driver_name = "cbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, + .type = CRYPTO_ALG_TYPE_GIVCIPHER, + .template_ablkcipher = { + .setkey = ablkcipher_setkey, + .encrypt = ablkcipher_encrypt, + .decrypt = ablkcipher_decrypt, + .givencrypt = ablkcipher_givencrypt, + .geniv = "", + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + }, + { + .name = "cbc(des3_ede)", + .driver_name = "cbc-3des-caam", + .blocksize = DES3_EDE_BLOCK_SIZE, + .type = CRYPTO_ALG_TYPE_GIVCIPHER, + .template_ablkcipher = { + .setkey = ablkcipher_setkey, + .encrypt = ablkcipher_encrypt, + .decrypt = ablkcipher_decrypt, + .givencrypt = ablkcipher_givencrypt, + .geniv = "", + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES3_EDE_BLOCK_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + }, + { + .name = "cbc(des)", + .driver_name = "cbc-des-caam", + .blocksize = DES_BLOCK_SIZE, + .type = CRYPTO_ALG_TYPE_GIVCIPHER, + .template_ablkcipher = { + .setkey = ablkcipher_setkey, + .encrypt = ablkcipher_encrypt, + .decrypt = ablkcipher_decrypt, + .givencrypt = ablkcipher_givencrypt, + .geniv = "", + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + }, + { + .name = "ctr(aes)", + .driver_name = "ctr-aes-caam", + .blocksize = 1, + .type = CRYPTO_ALG_TYPE_ABLKCIPHER, + .template_ablkcipher = { + .setkey = ablkcipher_setkey, + .encrypt = ablkcipher_encrypt, + .decrypt = ablkcipher_decrypt, + .geniv = "chainiv", + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, + }, + { + .name = "rfc3686(ctr(aes))", + .driver_name = "rfc3686-ctr-aes-caam", + .blocksize = 1, + .type = CRYPTO_ALG_TYPE_GIVCIPHER, + .template_ablkcipher = { + .setkey = ablkcipher_setkey, + .encrypt = ablkcipher_encrypt, + .decrypt = ablkcipher_decrypt, + .givencrypt = ablkcipher_givencrypt, .geniv = "", + .min_keysize = AES_MIN_KEY_SIZE + + CTR_RFC3686_NONCE_SIZE, + .max_keysize = AES_MAX_KEY_SIZE + + CTR_RFC3686_NONCE_SIZE, + .ivsize = CTR_RFC3686_IV_SIZE, + }, + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, + } +}; + +static struct caam_aead_alg driver_aeads[] = { + { + .aead = { + .base = { + .cra_name = "rfc4106(gcm(aes))", + .cra_driver_name = "rfc4106-gcm-aes-caam", + .cra_blocksize = 1, + }, + .setkey = rfc4106_setkey, + .setauthsize = rfc4106_setauthsize, + .encrypt = ipsec_gcm_encrypt, + .decrypt = ipsec_gcm_decrypt, + .ivsize = 8, + .maxauthsize = AES_BLOCK_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, + }, + }, + { + .aead = { + .base = { + .cra_name = "rfc4543(gcm(aes))", + .cra_driver_name = "rfc4543-gcm-aes-caam", + .cra_blocksize = 1, + }, + .setkey = rfc4543_setkey, + .setauthsize = rfc4543_setauthsize, + .encrypt = ipsec_gcm_encrypt, + .decrypt = ipsec_gcm_decrypt, + .ivsize = 8, + .maxauthsize = AES_BLOCK_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, + }, + }, + /* Galois Counter Mode */ + { + .aead = { + .base = { + .cra_name = "gcm(aes)", + .cra_driver_name = "gcm-aes-caam", + .cra_blocksize = 1, + }, + .setkey = gcm_setkey, + .setauthsize = gcm_setauthsize, + .encrypt = gcm_encrypt, + .decrypt = gcm_decrypt, + .ivsize = 12, + .maxauthsize = AES_BLOCK_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, + }, + }, + /* single-pass ipsec_esp descriptor */ + { + .aead = { + .base = { + .cra_name = "authenc(hmac(md5)," + "ecb(cipher_null))", + .cra_driver_name = "authenc-hmac-md5-" + "ecb-cipher_null-caam", + .cra_blocksize = NULL_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, .ivsize = NULL_IV_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha1)," + "ecb(cipher_null))", + .cra_driver_name = "authenc-hmac-sha1-" + "ecb-cipher_null-caam", + .cra_blocksize = NULL_BLOCK_SIZE, }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = NULL_IV_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha224),ecb(cipher_null))", - .driver_name = "authenc-hmac-sha224-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha224)," + "ecb(cipher_null))", + .cra_driver_name = "authenc-hmac-sha224-" + "ecb-cipher_null-caam", + .cra_blocksize = NULL_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = aead_null_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, .ivsize = NULL_IV_SIZE, .maxauthsize = SHA224_DIGEST_SIZE, - }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_SHA224 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha256),ecb(cipher_null))", - .driver_name = "authenc-hmac-sha256-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha256)," + "ecb(cipher_null))", + .cra_driver_name = "authenc-hmac-sha256-" + "ecb-cipher_null-caam", + .cra_blocksize = NULL_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = aead_null_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, .ivsize = NULL_IV_SIZE, .maxauthsize = SHA256_DIGEST_SIZE, - }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_SHA256 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha384),ecb(cipher_null))", - .driver_name = "authenc-hmac-sha384-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha384)," + "ecb(cipher_null))", + .cra_driver_name = "authenc-hmac-sha384-" + "ecb-cipher_null-caam", + .cra_blocksize = NULL_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = aead_null_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, .ivsize = NULL_IV_SIZE, .maxauthsize = SHA384_DIGEST_SIZE, - }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_SHA384 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha512),ecb(cipher_null))", - .driver_name = "authenc-hmac-sha512-ecb-cipher_null-caam", - .blocksize = NULL_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha512)," + "ecb(cipher_null))", + .cra_driver_name = "authenc-hmac-sha512-" + "ecb-cipher_null-caam", + .cra_blocksize = NULL_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = aead_null_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, .ivsize = NULL_IV_SIZE, .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(md5),cbc(aes))", + .cra_driver_name = "authenc-hmac-md5-" + "cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, }, - .class1_alg_type = 0, - .class2_alg_type = OP_ALG_ALGSEL_SHA512 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(md5),cbc(aes))", - .driver_name = "authenc-hmac-md5-cbc-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(md5)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-hmac-md5-" + "cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = AES_BLOCK_SIZE, .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha1),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha1-" + "cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha1),cbc(aes))", - .driver_name = "authenc-hmac-sha1-cbc-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha1)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha1-cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = AES_BLOCK_SIZE, .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha224),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha224-" + "cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha224),cbc(aes))", - .driver_name = "authenc-hmac-sha224-cbc-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha224)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha224-cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = AES_BLOCK_SIZE, .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha256),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha256-" + "cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA224 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha256),cbc(aes))", - .driver_name = "authenc-hmac-sha256-cbc-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha256)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha256-cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha384),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha384-" + "cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, + }, + { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha384)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha384-cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA256 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .geniv = true, + }, }, { - .name = "authenc(hmac(sha384),cbc(aes))", - .driver_name = "authenc-hmac-sha384-cbc-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha512),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha512-" + "cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA384_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA384 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, }, - { - .name = "authenc(hmac(sha512),cbc(aes))", - .driver_name = "authenc-hmac-sha512-cbc-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha512)," + "cbc(aes)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha512-cbc-aes-caam", + .cra_blocksize = AES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = AES_BLOCK_SIZE, .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(md5),cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-md5-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA512 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + } }, { - .name = "authenc(hmac(md5),cbc(des3_ede))", - .driver_name = "authenc-hmac-md5-cbc-des3_ede-caam", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(md5)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-hmac-md5-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES3_EDE_BLOCK_SIZE, .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .geniv = true, + } + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha1)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha1-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha1),cbc(des3_ede))", - .driver_name = "authenc-hmac-sha1-cbc-des3_ede-caam", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha1)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha1-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES3_EDE_BLOCK_SIZE, .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha224)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha224-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha224),cbc(des3_ede))", - .driver_name = "authenc-hmac-sha224-cbc-des3_ede-caam", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha224)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha224-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES3_EDE_BLOCK_SIZE, .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha256)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha256-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA224 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha256),cbc(des3_ede))", - .driver_name = "authenc-hmac-sha256-cbc-des3_ede-caam", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha256)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha256-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES3_EDE_BLOCK_SIZE, .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha384)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha384-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA256 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha384),cbc(des3_ede))", - .driver_name = "authenc-hmac-sha384-cbc-des3_ede-caam", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha384)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha384-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES3_EDE_BLOCK_SIZE, .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha512)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha512-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA384 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha512),cbc(des3_ede))", - .driver_name = "authenc-hmac-sha512-cbc-des3_ede-caam", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha512)," + "cbc(des3_ede)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha512-" + "cbc-des3_ede-caam", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES3_EDE_BLOCK_SIZE, .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(md5),cbc(des))", + .cra_driver_name = "authenc-hmac-md5-" + "cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA512 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(md5),cbc(des))", - .driver_name = "authenc-hmac-md5-cbc-des-caam", - .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(md5)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-hmac-md5-" + "cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES_BLOCK_SIZE, .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha1),cbc(des))", + .cra_driver_name = "authenc-hmac-sha1-" + "cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha1),cbc(des))", - .driver_name = "authenc-hmac-sha1-cbc-des-caam", - .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha1)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha1-cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES_BLOCK_SIZE, .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha224),cbc(des))", + .cra_driver_name = "authenc-hmac-sha224-" + "cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha224),cbc(des))", - .driver_name = "authenc-hmac-sha224-cbc-des-caam", - .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha224)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha224-cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES_BLOCK_SIZE, .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha256),cbc(des))", + .cra_driver_name = "authenc-hmac-sha256-" + "cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA224 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha256),cbc(des))", - .driver_name = "authenc-hmac-sha256-cbc-des-caam", - .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha256)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha256-cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES_BLOCK_SIZE, .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha384),cbc(des))", + .cra_driver_name = "authenc-hmac-sha384-" + "cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA256 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha384),cbc(des))", - .driver_name = "authenc-hmac-sha384-cbc-des-caam", - .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha384)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha384-cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES_BLOCK_SIZE, .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, + { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha512),cbc(des))", + .cra_driver_name = "authenc-hmac-sha512-" + "cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA384 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, }, { - .name = "authenc(hmac(sha512),cbc(des))", - .driver_name = "authenc-hmac-sha512-cbc-des-caam", - .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "echainiv(authenc(hmac(sha512)," + "cbc(des)))", + .cra_driver_name = "echainiv-authenc-" + "hmac-sha512-cbc-des-caam", + .cra_blocksize = DES_BLOCK_SIZE, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = DES_BLOCK_SIZE, .maxauthsize = SHA512_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA512 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .geniv = true, + }, }, { - .name = "authenc(hmac(md5),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-md5-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "authenc(hmac(md5)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-md5-" + "rfc3686-ctr-aes-caam", + .cra_blocksize = 1, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, .ivsize = CTR_RFC3686_IV_SIZE, .maxauthsize = MD5_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, - .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + }, }, { - .name = "authenc(hmac(sha1),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha1-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "seqiv(authenc(" + "hmac(md5),rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-md5-" + "rfc3686-ctr-aes-caam", + .cra_blocksize = 1, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, - .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .maxauthsize = MD5_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, + }, }, { - .name = "authenc(hmac(sha224),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha224-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha1)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-sha1-" + "rfc3686-ctr-aes-caam", + .cra_blocksize = 1, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA224_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, - .class2_alg_type = OP_ALG_ALGSEL_SHA224 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + }, }, { - .name = "authenc(hmac(sha256),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha256-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "seqiv(authenc(" + "hmac(sha1),rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-sha1-" + "rfc3686-ctr-aes-caam", + .cra_blocksize = 1, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, - .class2_alg_type = OP_ALG_ALGSEL_SHA256 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .maxauthsize = SHA1_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, + }, }, { - .name = "authenc(hmac(sha384),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha384-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "authenc(hmac(sha224)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-sha224-" + "rfc3686-ctr-aes-caam", + .cra_blocksize = 1, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA384_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, - .class2_alg_type = OP_ALG_ALGSEL_SHA384 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + }, }, { - .name = "authenc(hmac(sha512),rfc3686(ctr(aes)))", - .driver_name = "authenc-hmac-sha512-rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_AEAD, - .template_aead = { + .aead = { + .base = { + .cra_name = "seqiv(authenc(" + "hmac(sha224),rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-sha224-" + "rfc3686-ctr-aes-caam", + .cra_blocksize = 1, + }, .setkey = aead_setkey, .setauthsize = aead_setauthsize, - .encrypt = old_aead_encrypt, - .decrypt = old_aead_decrypt, - .givencrypt = old_aead_givencrypt, - .geniv = "", + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, .ivsize = CTR_RFC3686_IV_SIZE, - .maxauthsize = SHA512_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, - .class2_alg_type = OP_ALG_ALGSEL_SHA512 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, - }, - /* ablkcipher descriptor */ - { - .name = "cbc(aes)", - .driver_name = "cbc-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .maxauthsize = SHA224_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, + }, }, { - .name = "cbc(des3_ede)", - .driver_name = "cbc-3des-caam", - .blocksize = DES3_EDE_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .ivsize = DES3_EDE_BLOCK_SIZE, + .aead = { + .base = { + .cra_name = "authenc(hmac(sha256)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-sha256-" + "rfc3686-ctr-aes-caam", + .cra_blocksize = 1, }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + }, }, { - .name = "cbc(des)", - .driver_name = "cbc-des-caam", - .blocksize = DES_BLOCK_SIZE, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, + .aead = { + .base = { + .cra_name = "seqiv(authenc(hmac(sha256)," + "rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-sha256-" + "rfc3686-ctr-aes-caam", + .cra_blocksize = 1, }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, + }, }, { - .name = "ctr(aes)", - .driver_name = "ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_ABLKCIPHER, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .geniv = "chainiv", - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, + .aead = { + .base = { + .cra_name = "authenc(hmac(sha384)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-sha384-" + "rfc3686-ctr-aes-caam", + .cra_blocksize = 1, }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, - }, - { - .name = "rfc3686(ctr(aes))", - .driver_name = "rfc3686-ctr-aes-caam", - .blocksize = 1, - .type = CRYPTO_ALG_TYPE_GIVCIPHER, - .template_ablkcipher = { - .setkey = ablkcipher_setkey, - .encrypt = ablkcipher_encrypt, - .decrypt = ablkcipher_decrypt, - .givencrypt = ablkcipher_givencrypt, - .geniv = "", - .min_keysize = AES_MIN_KEY_SIZE + - CTR_RFC3686_NONCE_SIZE, - .max_keysize = AES_MAX_KEY_SIZE + - CTR_RFC3686_NONCE_SIZE, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, .ivsize = CTR_RFC3686_IV_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, - } -}; - -struct caam_alg_entry { - int class1_alg_type; - int class2_alg_type; - int alg_op; -}; - -struct caam_aead_alg { - struct aead_alg aead; - struct caam_alg_entry caam; - bool registered; -}; - -static struct caam_aead_alg driver_aeads[] = { + .maxauthsize = SHA384_DIGEST_SIZE, + }, + .caam = { + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + }, + }, { .aead = { .base = { - .cra_name = "rfc4106(gcm(aes))", - .cra_driver_name = "rfc4106-gcm-aes-caam", + .cra_name = "seqiv(authenc(hmac(sha384)," + "rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-sha384-" + "rfc3686-ctr-aes-caam", .cra_blocksize = 1, }, - .setkey = rfc4106_setkey, - .setauthsize = rfc4106_setauthsize, - .encrypt = ipsec_gcm_encrypt, - .decrypt = ipsec_gcm_decrypt, - .ivsize = 8, - .maxauthsize = AES_BLOCK_SIZE, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, }, .caam = { - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, }, }, { .aead = { .base = { - .cra_name = "rfc4543(gcm(aes))", - .cra_driver_name = "rfc4543-gcm-aes-caam", + .cra_name = "authenc(hmac(sha512)," + "rfc3686(ctr(aes)))", + .cra_driver_name = "authenc-hmac-sha512-" + "rfc3686-ctr-aes-caam", .cra_blocksize = 1, }, - .setkey = rfc4543_setkey, - .setauthsize = rfc4543_setauthsize, - .encrypt = ipsec_gcm_encrypt, - .decrypt = ipsec_gcm_decrypt, - .ivsize = 8, - .maxauthsize = AES_BLOCK_SIZE, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_decrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, }, .caam = { - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .rfc3686 = true, }, }, - /* Galois Counter Mode */ { .aead = { .base = { - .cra_name = "gcm(aes)", - .cra_driver_name = "gcm-aes-caam", + .cra_name = "seqiv(authenc(hmac(sha512)," + "rfc3686(ctr(aes))))", + .cra_driver_name = "seqiv-authenc-hmac-sha512-" + "rfc3686-ctr-aes-caam", .cra_blocksize = 1, }, - .setkey = gcm_setkey, - .setauthsize = gcm_setauthsize, - .encrypt = gcm_encrypt, - .decrypt = gcm_decrypt, - .ivsize = 12, - .maxauthsize = AES_BLOCK_SIZE, + .setkey = aead_setkey, + .setauthsize = aead_setauthsize, + .encrypt = aead_encrypt, + .decrypt = aead_givdecrypt, + .ivsize = CTR_RFC3686_IV_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, }, .caam = { - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, + .class1_alg_type = OP_ALG_ALGSEL_AES | + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, + .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, }, }, }; @@ -4268,10 +4343,6 @@ static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template alg->cra_type = &crypto_ablkcipher_type; alg->cra_ablkcipher = template->template_ablkcipher; break; - case CRYPTO_ALG_TYPE_AEAD: - alg->cra_type = &crypto_aead_type; - alg->cra_aead = template->template_aead; - break; } t_alg->caam.class1_alg_type = template->class1_alg_type; -- cgit v1.3-6-gb490 From d7295a8dc965ee0d5b3f9b1eb7f556c2bfa78420 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Jul 2015 17:53:18 +0800 Subject: crypto: ixp4xx - Convert to new AEAD interface This patch converts ixp4xx to the new AEAD interface. IV generation has been removed since it's a purely software implementation. Signed-off-by: Herbert Xu --- drivers/crypto/ixp4xx_crypto.c | 313 +++++++++++++++++++++-------------------- 1 file changed, 158 insertions(+), 155 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 402631a19a11..411de261e40c 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -156,7 +156,8 @@ struct ablk_ctx { }; struct aead_ctx { - struct buffer_desc *buffer; + struct buffer_desc *src; + struct buffer_desc *dst; struct scatterlist ivlist; /* used when the hmac is not on one sg entry */ u8 *hmac_virt; @@ -198,6 +199,15 @@ struct ixp_alg { int registered; }; +struct ixp_aead_alg { + struct aead_alg crypto; + const struct ix_hash_algo *hash; + u32 cfg_enc; + u32 cfg_dec; + + int registered; +}; + static const struct ix_hash_algo hash_alg_md5 = { .cfgword = 0xAA010004, .icv = "\x01\x23\x45\x67\x89\xAB\xCD\xEF" @@ -339,11 +349,11 @@ static void finish_scattered_hmac(struct crypt_ctl *crypt) struct aead_ctx *req_ctx = aead_request_ctx(req); struct crypto_aead *tfm = crypto_aead_reqtfm(req); int authsize = crypto_aead_authsize(tfm); - int decryptlen = req->cryptlen - authsize; + int decryptlen = req->assoclen + req->cryptlen - authsize; if (req_ctx->encrypt) { scatterwalk_map_and_copy(req_ctx->hmac_virt, - req->src, decryptlen, authsize, 1); + req->dst, decryptlen, authsize, 1); } dma_pool_free(buffer_pool, req_ctx->hmac_virt, crypt->icv_rev_aes); } @@ -364,7 +374,8 @@ static void one_packet(dma_addr_t phys) struct aead_request *req = crypt->data.aead_req; struct aead_ctx *req_ctx = aead_request_ctx(req); - free_buf_chain(dev, req_ctx->buffer, crypt->src_buf); + free_buf_chain(dev, req_ctx->src, crypt->src_buf); + free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); if (req_ctx->hmac_virt) { finish_scattered_hmac(crypt); } @@ -573,11 +584,10 @@ static int init_tfm_ablk(struct crypto_tfm *tfm) return init_tfm(tfm); } -static int init_tfm_aead(struct crypto_tfm *tfm) +static int init_tfm_aead(struct crypto_aead *tfm) { - crypto_aead_set_reqsize(__crypto_aead_cast(tfm), - sizeof(struct aead_ctx)); - return init_tfm(tfm); + crypto_aead_set_reqsize(tfm, sizeof(struct aead_ctx)); + return init_tfm(crypto_aead_tfm(tfm)); } static void exit_tfm(struct crypto_tfm *tfm) @@ -587,6 +597,11 @@ static void exit_tfm(struct crypto_tfm *tfm) free_sa_dir(&ctx->decrypt); } +static void exit_tfm_aead(struct crypto_aead *tfm) +{ + exit_tfm(crypto_aead_tfm(tfm)); +} + static int register_chain_var(struct crypto_tfm *tfm, u8 xpad, u32 target, int init_len, u32 ctx_addr, const u8 *key, int key_len) { @@ -969,24 +984,6 @@ static int ablk_rfc3686_crypt(struct ablkcipher_request *req) return ret; } -static int hmac_inconsistent(struct scatterlist *sg, unsigned start, - unsigned int nbytes) -{ - int offset = 0; - - if (!nbytes) - return 0; - - for (;;) { - if (start < offset + sg->length) - break; - - offset += sg->length; - sg = sg_next(sg); - } - return (start + nbytes > offset + sg->length); -} - static int aead_perform(struct aead_request *req, int encrypt, int cryptoffset, int eff_cryptlen, u8 *iv) { @@ -1002,6 +999,8 @@ static int aead_perform(struct aead_request *req, int encrypt, struct device *dev = &pdev->dev; gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC; + enum dma_data_direction src_direction = DMA_BIDIRECTIONAL; + unsigned int lastlen; if (qmgr_stat_full(SEND_QID)) return -EAGAIN; @@ -1030,35 +1029,55 @@ static int aead_perform(struct aead_request *req, int encrypt, crypt->crypt_len = eff_cryptlen; crypt->auth_offs = 0; - crypt->auth_len = req->assoclen + ivsize + cryptlen; + crypt->auth_len = req->assoclen + cryptlen; BUG_ON(ivsize && !req->iv); memcpy(crypt->iv, req->iv, ivsize); + req_ctx->dst = NULL; + if (req->src != req->dst) { - BUG(); /* -ENOTSUP because of my laziness */ + struct buffer_desc dst_hook; + + crypt->mode |= NPE_OP_NOT_IN_PLACE; + src_direction = DMA_TO_DEVICE; + + buf = chainup_buffers(dev, req->dst, crypt->auth_len, + &dst_hook, flags, DMA_FROM_DEVICE); + req_ctx->dst = dst_hook.next; + crypt->dst_buf = dst_hook.phys_next; + + if (!buf) + goto free_buf_dst; + + if (encrypt) { + lastlen = buf->buf_len; + if (lastlen >= authsize) + crypt->icv_rev_aes = buf->phys_addr + + buf->buf_len - authsize; + } } - /* ASSOC data */ - buf = chainup_buffers(dev, req->assoc, req->assoclen, &src_hook, - flags, DMA_TO_DEVICE); - req_ctx->buffer = src_hook.next; + buf = chainup_buffers(dev, req->src, crypt->auth_len, + &src_hook, flags, src_direction); + req_ctx->src = src_hook.next; crypt->src_buf = src_hook.phys_next; if (!buf) - goto out; - /* IV */ - sg_init_table(&req_ctx->ivlist, 1); - sg_set_buf(&req_ctx->ivlist, iv, ivsize); - buf = chainup_buffers(dev, &req_ctx->ivlist, ivsize, buf, flags, - DMA_BIDIRECTIONAL); - if (!buf) - goto free_chain; - if (unlikely(hmac_inconsistent(req->src, cryptlen, authsize))) { + goto free_buf_src; + + if (!encrypt || !req_ctx->dst) { + lastlen = buf->buf_len; + if (lastlen >= authsize) + crypt->icv_rev_aes = buf->phys_addr + + buf->buf_len - authsize; + } + + if (unlikely(lastlen < authsize)) { /* The 12 hmac bytes are scattered, * we need to copy them into a safe buffer */ req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags, &crypt->icv_rev_aes); if (unlikely(!req_ctx->hmac_virt)) - goto free_chain; + goto free_buf_src; if (!encrypt) { scatterwalk_map_and_copy(req_ctx->hmac_virt, req->src, cryptlen, authsize, 0); @@ -1067,27 +1086,16 @@ static int aead_perform(struct aead_request *req, int encrypt, } else { req_ctx->hmac_virt = NULL; } - /* Crypt */ - buf = chainup_buffers(dev, req->src, cryptlen + authsize, buf, flags, - DMA_BIDIRECTIONAL); - if (!buf) - goto free_hmac_virt; - if (!req_ctx->hmac_virt) { - crypt->icv_rev_aes = buf->phys_addr + buf->buf_len - authsize; - } crypt->ctl_flags |= CTL_FLAG_PERFORM_AEAD; qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt)); BUG_ON(qmgr_stat_overflow(SEND_QID)); return -EINPROGRESS; -free_hmac_virt: - if (req_ctx->hmac_virt) { - dma_pool_free(buffer_pool, req_ctx->hmac_virt, - crypt->icv_rev_aes); - } -free_chain: - free_buf_chain(dev, req_ctx->buffer, crypt->src_buf); -out: + +free_buf_src: + free_buf_chain(dev, req_ctx->src, crypt->src_buf); +free_buf_dst: + free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); crypt->ctl_flags = CTL_FLAG_UNUSED; return -ENOMEM; } @@ -1173,40 +1181,12 @@ badkey: static int aead_encrypt(struct aead_request *req) { - unsigned ivsize = crypto_aead_ivsize(crypto_aead_reqtfm(req)); - return aead_perform(req, 1, req->assoclen + ivsize, - req->cryptlen, req->iv); + return aead_perform(req, 1, req->assoclen, req->cryptlen, req->iv); } static int aead_decrypt(struct aead_request *req) { - unsigned ivsize = crypto_aead_ivsize(crypto_aead_reqtfm(req)); - return aead_perform(req, 0, req->assoclen + ivsize, - req->cryptlen, req->iv); -} - -static int aead_givencrypt(struct aead_givcrypt_request *req) -{ - struct crypto_aead *tfm = aead_givcrypt_reqtfm(req); - struct ixp_ctx *ctx = crypto_aead_ctx(tfm); - unsigned len, ivsize = crypto_aead_ivsize(tfm); - __be64 seq; - - /* copied from eseqiv.c */ - if (!ctx->salted) { - get_random_bytes(ctx->salt, ivsize); - ctx->salted = 1; - } - memcpy(req->areq.iv, ctx->salt, ivsize); - len = ivsize; - if (ivsize > sizeof(u64)) { - memset(req->giv, 0, ivsize - sizeof(u64)); - len = sizeof(u64); - } - seq = cpu_to_be64(req->seq); - memcpy(req->giv + ivsize - len, &seq, len); - return aead_perform(&req->areq, 1, req->areq.assoclen, - req->areq.cryptlen +ivsize, req->giv); + return aead_perform(req, 0, req->assoclen, req->cryptlen, req->iv); } static struct ixp_alg ixp4xx_algos[] = { @@ -1319,80 +1299,77 @@ static struct ixp_alg ixp4xx_algos[] = { }, .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CTR, .cfg_dec = CIPH_ENCR | MOD_AES | MOD_CTR, -}, { +} }; + +static struct ixp_aead_alg ixp4xx_aeads[] = { +{ .crypto = { - .cra_name = "authenc(hmac(md5),cbc(des))", - .cra_blocksize = DES_BLOCK_SIZE, - .cra_u = { .aead = { - .ivsize = DES_BLOCK_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, - } - } + .base = { + .cra_name = "authenc(hmac(md5),cbc(des))", + .cra_blocksize = DES_BLOCK_SIZE, + }, + .ivsize = DES_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, }, .hash = &hash_alg_md5, .cfg_enc = CIPH_ENCR | MOD_DES | MOD_CBC_ENC | KEYLEN_192, .cfg_dec = CIPH_DECR | MOD_DES | MOD_CBC_DEC | KEYLEN_192, }, { .crypto = { - .cra_name = "authenc(hmac(md5),cbc(des3_ede))", - .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_u = { .aead = { - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, - } - } + .base = { + .cra_name = "authenc(hmac(md5),cbc(des3_ede))", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, }, .hash = &hash_alg_md5, .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_CBC_ENC | KEYLEN_192, .cfg_dec = CIPH_DECR | MOD_3DES | MOD_CBC_DEC | KEYLEN_192, }, { .crypto = { - .cra_name = "authenc(hmac(sha1),cbc(des))", - .cra_blocksize = DES_BLOCK_SIZE, - .cra_u = { .aead = { + .base = { + .cra_name = "authenc(hmac(sha1),cbc(des))", + .cra_blocksize = DES_BLOCK_SIZE, + }, .ivsize = DES_BLOCK_SIZE, .maxauthsize = SHA1_DIGEST_SIZE, - } - } }, .hash = &hash_alg_sha1, .cfg_enc = CIPH_ENCR | MOD_DES | MOD_CBC_ENC | KEYLEN_192, .cfg_dec = CIPH_DECR | MOD_DES | MOD_CBC_DEC | KEYLEN_192, }, { .crypto = { - .cra_name = "authenc(hmac(sha1),cbc(des3_ede))", - .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_u = { .aead = { - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - } - } + .base = { + .cra_name = "authenc(hmac(sha1),cbc(des3_ede))", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + }, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, }, .hash = &hash_alg_sha1, .cfg_enc = CIPH_ENCR | MOD_3DES | MOD_CBC_ENC | KEYLEN_192, .cfg_dec = CIPH_DECR | MOD_3DES | MOD_CBC_DEC | KEYLEN_192, }, { .crypto = { - .cra_name = "authenc(hmac(md5),cbc(aes))", - .cra_blocksize = AES_BLOCK_SIZE, - .cra_u = { .aead = { - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, - } - } + .base = { + .cra_name = "authenc(hmac(md5),cbc(aes))", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, }, .hash = &hash_alg_md5, .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CBC_ENC, .cfg_dec = CIPH_DECR | MOD_AES | MOD_CBC_DEC, }, { .crypto = { - .cra_name = "authenc(hmac(sha1),cbc(aes))", - .cra_blocksize = AES_BLOCK_SIZE, - .cra_u = { .aead = { - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - } - } + .base = { + .cra_name = "authenc(hmac(sha1),cbc(aes))", + .cra_blocksize = AES_BLOCK_SIZE, + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, }, .hash = &hash_alg_sha1, .cfg_enc = CIPH_ENCR | MOD_AES | MOD_CBC_ENC, @@ -1436,32 +1413,20 @@ static int __init ixp_module_init(void) if (!support_aes && (ixp4xx_algos[i].cfg_enc & MOD_AES)) { continue; } - if (!ixp4xx_algos[i].hash) { - /* block ciphers */ - cra->cra_type = &crypto_ablkcipher_type; - cra->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC; - if (!cra->cra_ablkcipher.setkey) - cra->cra_ablkcipher.setkey = ablk_setkey; - if (!cra->cra_ablkcipher.encrypt) - cra->cra_ablkcipher.encrypt = ablk_encrypt; - if (!cra->cra_ablkcipher.decrypt) - cra->cra_ablkcipher.decrypt = ablk_decrypt; - cra->cra_init = init_tfm_ablk; - } else { - /* authenc */ - cra->cra_type = &crypto_aead_type; - cra->cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC; - cra->cra_aead.setkey = aead_setkey; - cra->cra_aead.setauthsize = aead_setauthsize; - cra->cra_aead.encrypt = aead_encrypt; - cra->cra_aead.decrypt = aead_decrypt; - cra->cra_aead.givencrypt = aead_givencrypt; - cra->cra_init = init_tfm_aead; - } + + /* block ciphers */ + cra->cra_type = &crypto_ablkcipher_type; + cra->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_ASYNC; + if (!cra->cra_ablkcipher.setkey) + cra->cra_ablkcipher.setkey = ablk_setkey; + if (!cra->cra_ablkcipher.encrypt) + cra->cra_ablkcipher.encrypt = ablk_encrypt; + if (!cra->cra_ablkcipher.decrypt) + cra->cra_ablkcipher.decrypt = ablk_decrypt; + cra->cra_init = init_tfm_ablk; + cra->cra_ctxsize = sizeof(struct ixp_ctx); cra->cra_module = THIS_MODULE; cra->cra_alignmask = 3; @@ -1473,6 +1438,39 @@ static int __init ixp_module_init(void) else ixp4xx_algos[i].registered = 1; } + + for (i = 0; i < ARRAY_SIZE(ixp4xx_aeads); i++) { + struct aead_alg *cra = &ixp4xx_aeads[i].crypto; + + if (snprintf(cra->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "%s"IXP_POSTFIX, cra->base.cra_name) >= + CRYPTO_MAX_ALG_NAME) + continue; + if (!support_aes && (ixp4xx_algos[i].cfg_enc & MOD_AES)) + continue; + + /* authenc */ + cra->base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_AEAD_NEW | + CRYPTO_ALG_ASYNC; + cra->setkey = aead_setkey; + cra->setauthsize = aead_setauthsize; + cra->encrypt = aead_encrypt; + cra->decrypt = aead_decrypt; + cra->init = init_tfm_aead; + cra->exit = exit_tfm_aead; + + cra->base.cra_ctxsize = sizeof(struct ixp_ctx); + cra->base.cra_module = THIS_MODULE; + cra->base.cra_alignmask = 3; + cra->base.cra_priority = 300; + + if (crypto_register_aead(cra)) + printk(KERN_ERR "Failed to register '%s'\n", + cra->base.cra_driver_name); + else + ixp4xx_aeads[i].registered = 1; + } return 0; } @@ -1481,6 +1479,11 @@ static void __exit ixp_module_exit(void) int num = ARRAY_SIZE(ixp4xx_algos); int i; + for (i = 0; i < ARRAY_SIZE(ixp4xx_aeads); i++) { + if (ixp4xx_aeads[i].registered) + crypto_unregister_aead(&ixp4xx_aeads[i].crypto); + } + for (i=0; i< num; i++) { if (ixp4xx_algos[i].registered) crypto_unregister_alg(&ixp4xx_algos[i].crypto); -- cgit v1.3-6-gb490 From c1359495c8a19fa686aa48512e0290d2f3846273 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Jul 2015 17:53:19 +0800 Subject: crypto: picoxcell - Convert to new AEAD interface This patch converts picoxcell to the new AEAD interface. IV generation has been removed since it's equivalent to a software implementation. As picoxcell cannot handle SG lists longer than 16 elements, this patch has made the software fallback mandatory. If an SG list comes in that exceeds the limit, we will simply use the fallback. Signed-off-by: Herbert Xu --- drivers/crypto/picoxcell_crypto.c | 678 +++++++++++++++++--------------------- 1 file changed, 311 insertions(+), 367 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c index 4f56f3681abd..e0f0c3497b12 100644 --- a/drivers/crypto/picoxcell_crypto.c +++ b/drivers/crypto/picoxcell_crypto.c @@ -99,11 +99,16 @@ struct spacc_req { dma_addr_t src_addr, dst_addr; struct spacc_ddt *src_ddt, *dst_ddt; void (*complete)(struct spacc_req *req); +}; - /* AEAD specific bits. */ - u8 *giv; - size_t giv_len; - dma_addr_t giv_pa; +struct spacc_aead { + unsigned long ctrl_default; + unsigned long type; + struct aead_alg alg; + struct spacc_engine *engine; + struct list_head entry; + int key_offs; + int iv_offs; }; struct spacc_engine { @@ -121,6 +126,9 @@ struct spacc_engine { struct spacc_alg *algs; unsigned num_algs; struct list_head registered_algs; + struct spacc_aead *aeads; + unsigned num_aeads; + struct list_head registered_aeads; size_t cipher_pg_sz; size_t hash_pg_sz; const char *name; @@ -174,8 +182,6 @@ struct spacc_aead_ctx { u8 cipher_key_len; u8 hash_key_len; struct crypto_aead *sw_cipher; - size_t auth_size; - u8 salt[AES_BLOCK_SIZE]; }; static int spacc_ablk_submit(struct spacc_req *req); @@ -185,6 +191,11 @@ static inline struct spacc_alg *to_spacc_alg(struct crypto_alg *alg) return alg ? container_of(alg, struct spacc_alg, alg) : NULL; } +static inline struct spacc_aead *to_spacc_aead(struct aead_alg *alg) +{ + return container_of(alg, struct spacc_aead, alg); +} + static inline int spacc_fifo_cmd_full(struct spacc_engine *engine) { u32 fifo_stat = readl(engine->regs + SPA_FIFO_STAT_REG_OFFSET); @@ -310,120 +321,117 @@ out: return NULL; } -static int spacc_aead_make_ddts(struct spacc_req *req, u8 *giv) +static int spacc_aead_make_ddts(struct aead_request *areq) { - struct aead_request *areq = container_of(req->req, struct aead_request, - base); + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct spacc_req *req = aead_request_ctx(areq); struct spacc_engine *engine = req->engine; struct spacc_ddt *src_ddt, *dst_ddt; - unsigned ivsize = crypto_aead_ivsize(crypto_aead_reqtfm(areq)); - unsigned nents = sg_count(areq->src, areq->cryptlen); unsigned total; - dma_addr_t iv_addr; + unsigned int src_nents, dst_nents; struct scatterlist *cur; - int i, dst_ents, src_ents, assoc_ents; - u8 *iv = giv ? giv : areq->iv; + int i, dst_ents, src_ents; + + total = areq->assoclen + areq->cryptlen; + if (req->is_encrypt) + total += crypto_aead_authsize(aead); + + src_nents = sg_count(areq->src, total); + if (src_nents + 1 > MAX_DDT_LEN) + return -E2BIG; + + dst_nents = 0; + if (areq->src != areq->dst) { + dst_nents = sg_count(areq->dst, total); + if (src_nents + 1 > MAX_DDT_LEN) + return -E2BIG; + } src_ddt = dma_pool_alloc(engine->req_pool, GFP_ATOMIC, &req->src_addr); if (!src_ddt) - return -ENOMEM; + goto err; dst_ddt = dma_pool_alloc(engine->req_pool, GFP_ATOMIC, &req->dst_addr); - if (!dst_ddt) { - dma_pool_free(engine->req_pool, src_ddt, req->src_addr); - return -ENOMEM; - } + if (!dst_ddt) + goto err_free_src; req->src_ddt = src_ddt; req->dst_ddt = dst_ddt; - assoc_ents = dma_map_sg(engine->dev, areq->assoc, - sg_count(areq->assoc, areq->assoclen), DMA_TO_DEVICE); - if (areq->src != areq->dst) { - src_ents = dma_map_sg(engine->dev, areq->src, nents, + if (dst_nents) { + src_ents = dma_map_sg(engine->dev, areq->src, src_nents, DMA_TO_DEVICE); - dst_ents = dma_map_sg(engine->dev, areq->dst, nents, + if (!src_ents) + goto err_free_dst; + + dst_ents = dma_map_sg(engine->dev, areq->dst, dst_nents, DMA_FROM_DEVICE); + + if (!dst_ents) { + dma_unmap_sg(engine->dev, areq->src, src_nents, + DMA_TO_DEVICE); + goto err_free_dst; + } } else { - src_ents = dma_map_sg(engine->dev, areq->src, nents, + src_ents = dma_map_sg(engine->dev, areq->src, src_nents, DMA_BIDIRECTIONAL); - dst_ents = 0; + if (!src_ents) + goto err_free_dst; + dst_ents = src_ents; } /* - * Map the IV/GIV. For the GIV it needs to be bidirectional as it is - * formed by the crypto block and sent as the ESP IV for IPSEC. + * Now map in the payload for the source and destination and terminate + * with the NULL pointers. */ - iv_addr = dma_map_single(engine->dev, iv, ivsize, - giv ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); - req->giv_pa = iv_addr; + for_each_sg(areq->src, cur, src_ents, i) + ddt_set(src_ddt++, sg_dma_address(cur), sg_dma_len(cur)); - /* - * Map the associated data. For decryption we don't copy the - * associated data. - */ - total = areq->assoclen; - for_each_sg(areq->assoc, cur, assoc_ents, i) { + /* For decryption we need to skip the associated data. */ + total = req->is_encrypt ? 0 : areq->assoclen; + for_each_sg(areq->dst, cur, dst_ents, i) { unsigned len = sg_dma_len(cur); - if (len > total) - len = total; - - total -= len; + if (len <= total) { + total -= len; + continue; + } - ddt_set(src_ddt++, sg_dma_address(cur), len); - if (req->is_encrypt) - ddt_set(dst_ddt++, sg_dma_address(cur), len); + ddt_set(dst_ddt++, sg_dma_address(cur) + total, len - total); } - ddt_set(src_ddt++, iv_addr, ivsize); - - if (giv || req->is_encrypt) - ddt_set(dst_ddt++, iv_addr, ivsize); - - /* - * Now map in the payload for the source and destination and terminate - * with the NULL pointers. - */ - for_each_sg(areq->src, cur, src_ents, i) { - ddt_set(src_ddt++, sg_dma_address(cur), sg_dma_len(cur)); - if (areq->src == areq->dst) - ddt_set(dst_ddt++, sg_dma_address(cur), - sg_dma_len(cur)); - } - - for_each_sg(areq->dst, cur, dst_ents, i) - ddt_set(dst_ddt++, sg_dma_address(cur), - sg_dma_len(cur)); ddt_set(src_ddt, 0, 0); ddt_set(dst_ddt, 0, 0); return 0; + +err_free_dst: + dma_pool_free(engine->req_pool, dst_ddt, req->dst_addr); +err_free_src: + dma_pool_free(engine->req_pool, src_ddt, req->src_addr); +err: + return -ENOMEM; } static void spacc_aead_free_ddts(struct spacc_req *req) { struct aead_request *areq = container_of(req->req, struct aead_request, base); - struct spacc_alg *alg = to_spacc_alg(req->req->tfm->__crt_alg); - struct spacc_ablk_ctx *aead_ctx = crypto_tfm_ctx(req->req->tfm); + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + unsigned total = areq->assoclen + areq->cryptlen + + (req->is_encrypt ? crypto_aead_authsize(aead) : 0); + struct spacc_aead_ctx *aead_ctx = crypto_aead_ctx(aead); struct spacc_engine *engine = aead_ctx->generic.engine; - unsigned ivsize = alg->alg.cra_aead.ivsize; - unsigned nents = sg_count(areq->src, areq->cryptlen); + unsigned nents = sg_count(areq->src, total); if (areq->src != areq->dst) { dma_unmap_sg(engine->dev, areq->src, nents, DMA_TO_DEVICE); dma_unmap_sg(engine->dev, areq->dst, - sg_count(areq->dst, areq->cryptlen), + sg_count(areq->dst, total), DMA_FROM_DEVICE); } else dma_unmap_sg(engine->dev, areq->src, nents, DMA_BIDIRECTIONAL); - dma_unmap_sg(engine->dev, areq->assoc, - sg_count(areq->assoc, areq->assoclen), DMA_TO_DEVICE); - - dma_unmap_single(engine->dev, req->giv_pa, ivsize, DMA_BIDIRECTIONAL); - dma_pool_free(engine->req_pool, req->src_ddt, req->src_addr); dma_pool_free(engine->req_pool, req->dst_ddt, req->dst_addr); } @@ -438,65 +446,22 @@ static void spacc_free_ddt(struct spacc_req *req, struct spacc_ddt *ddt, dma_pool_free(req->engine->req_pool, ddt, ddt_addr); } -/* - * Set key for a DES operation in an AEAD cipher. This also performs weak key - * checking if required. - */ -static int spacc_aead_des_setkey(struct crypto_aead *aead, const u8 *key, - unsigned int len) -{ - struct crypto_tfm *tfm = crypto_aead_tfm(aead); - struct spacc_aead_ctx *ctx = crypto_tfm_ctx(tfm); - u32 tmp[DES_EXPKEY_WORDS]; - - if (unlikely(!des_ekey(tmp, key)) && - (crypto_aead_get_flags(aead)) & CRYPTO_TFM_REQ_WEAK_KEY) { - tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; - return -EINVAL; - } - - memcpy(ctx->cipher_key, key, len); - ctx->cipher_key_len = len; - - return 0; -} - -/* Set the key for the AES block cipher component of the AEAD transform. */ -static int spacc_aead_aes_setkey(struct crypto_aead *aead, const u8 *key, - unsigned int len) -{ - struct crypto_tfm *tfm = crypto_aead_tfm(aead); - struct spacc_aead_ctx *ctx = crypto_tfm_ctx(tfm); - - /* - * IPSec engine only supports 128 and 256 bit AES keys. If we get a - * request for any other size (192 bits) then we need to do a software - * fallback. - */ - if (len != AES_KEYSIZE_128 && len != AES_KEYSIZE_256) { - /* - * Set the fallback transform to use the same request flags as - * the hardware transform. - */ - ctx->sw_cipher->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; - ctx->sw_cipher->base.crt_flags |= - tfm->crt_flags & CRYPTO_TFM_REQ_MASK; - return crypto_aead_setkey(ctx->sw_cipher, key, len); - } - - memcpy(ctx->cipher_key, key, len); - ctx->cipher_key_len = len; - - return 0; -} - static int spacc_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { struct spacc_aead_ctx *ctx = crypto_aead_ctx(tfm); - struct spacc_alg *alg = to_spacc_alg(tfm->base.__crt_alg); struct crypto_authenc_keys keys; - int err = -EINVAL; + int err; + + crypto_aead_clear_flags(ctx->sw_cipher, CRYPTO_TFM_REQ_MASK); + crypto_aead_set_flags(ctx->sw_cipher, crypto_aead_get_flags(tfm) & + CRYPTO_TFM_REQ_MASK); + err = crypto_aead_setkey(ctx->sw_cipher, key, keylen); + crypto_aead_clear_flags(tfm, CRYPTO_TFM_RES_MASK); + crypto_aead_set_flags(tfm, crypto_aead_get_flags(ctx->sw_cipher) & + CRYPTO_TFM_RES_MASK); + if (err) + return err; if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) goto badkey; @@ -507,14 +472,8 @@ static int spacc_aead_setkey(struct crypto_aead *tfm, const u8 *key, if (keys.authkeylen > sizeof(ctx->hash_ctx)) goto badkey; - if ((alg->ctrl_default & SPACC_CRYPTO_ALG_MASK) == - SPA_CTRL_CIPH_ALG_AES) - err = spacc_aead_aes_setkey(tfm, keys.enckey, keys.enckeylen); - else - err = spacc_aead_des_setkey(tfm, keys.enckey, keys.enckeylen); - - if (err) - goto badkey; + memcpy(ctx->cipher_key, keys.enckey, keys.enckeylen); + ctx->cipher_key_len = keys.enckeylen; memcpy(ctx->hash_ctx, keys.authkey, keys.authkeylen); ctx->hash_key_len = keys.authkeylen; @@ -531,9 +490,7 @@ static int spacc_aead_setauthsize(struct crypto_aead *tfm, { struct spacc_aead_ctx *ctx = crypto_tfm_ctx(crypto_aead_tfm(tfm)); - ctx->auth_size = authsize; - - return 0; + return crypto_aead_setauthsize(ctx->sw_cipher, authsize); } /* @@ -541,15 +498,13 @@ static int spacc_aead_setauthsize(struct crypto_aead *tfm, * be completed in hardware because the hardware may not support certain key * sizes. In these cases we need to complete the request in software. */ -static int spacc_aead_need_fallback(struct spacc_req *req) +static int spacc_aead_need_fallback(struct aead_request *aead_req) { - struct aead_request *aead_req; - struct crypto_tfm *tfm = req->req->tfm; - struct crypto_alg *alg = req->req->tfm->__crt_alg; - struct spacc_alg *spacc_alg = to_spacc_alg(alg); - struct spacc_aead_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_aead *aead = crypto_aead_reqtfm(aead_req); + struct aead_alg *alg = crypto_aead_alg(aead); + struct spacc_aead *spacc_alg = to_spacc_aead(alg); + struct spacc_aead_ctx *ctx = crypto_aead_ctx(aead); - aead_req = container_of(req->req, struct aead_request, base); /* * If we have a non-supported key-length, then we need to do a * software fallback. @@ -568,22 +523,17 @@ static int spacc_aead_do_fallback(struct aead_request *req, unsigned alg_type, { struct crypto_tfm *old_tfm = crypto_aead_tfm(crypto_aead_reqtfm(req)); struct spacc_aead_ctx *ctx = crypto_tfm_ctx(old_tfm); - int err; + struct aead_request *subreq = aead_request_ctx(req); - if (ctx->sw_cipher) { - /* - * Change the request to use the software fallback transform, - * and once the ciphering has completed, put the old transform - * back into the request. - */ - aead_request_set_tfm(req, ctx->sw_cipher); - err = is_encrypt ? crypto_aead_encrypt(req) : - crypto_aead_decrypt(req); - aead_request_set_tfm(req, __crypto_aead_cast(old_tfm)); - } else - err = -EINVAL; + aead_request_set_tfm(subreq, ctx->sw_cipher); + aead_request_set_callback(subreq, req->base.flags, + req->base.complete, req->base.data); + aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, + req->iv); + aead_request_set_ad(subreq, req->assoclen); - return err; + return is_encrypt ? crypto_aead_encrypt(subreq) : + crypto_aead_decrypt(subreq); } static void spacc_aead_complete(struct spacc_req *req) @@ -594,18 +544,19 @@ static void spacc_aead_complete(struct spacc_req *req) static int spacc_aead_submit(struct spacc_req *req) { - struct crypto_tfm *tfm = req->req->tfm; - struct spacc_aead_ctx *ctx = crypto_tfm_ctx(tfm); - struct crypto_alg *alg = req->req->tfm->__crt_alg; - struct spacc_alg *spacc_alg = to_spacc_alg(alg); - struct spacc_engine *engine = ctx->generic.engine; - u32 ctrl, proc_len, assoc_len; struct aead_request *aead_req = container_of(req->req, struct aead_request, base); + struct crypto_aead *aead = crypto_aead_reqtfm(aead_req); + unsigned int authsize = crypto_aead_authsize(aead); + struct spacc_aead_ctx *ctx = crypto_aead_ctx(aead); + struct aead_alg *alg = crypto_aead_alg(aead); + struct spacc_aead *spacc_alg = to_spacc_aead(alg); + struct spacc_engine *engine = ctx->generic.engine; + u32 ctrl, proc_len, assoc_len; req->result = -EINPROGRESS; req->ctx_id = spacc_load_ctx(&ctx->generic, ctx->cipher_key, - ctx->cipher_key_len, aead_req->iv, alg->cra_aead.ivsize, + ctx->cipher_key_len, aead_req->iv, crypto_aead_ivsize(aead), ctx->hash_ctx, ctx->hash_key_len); /* Set the source and destination DDT pointers. */ @@ -616,26 +567,16 @@ static int spacc_aead_submit(struct spacc_req *req) assoc_len = aead_req->assoclen; proc_len = aead_req->cryptlen + assoc_len; - /* - * If we aren't generating an IV, then we need to include the IV in the - * associated data so that it is included in the hash. - */ - if (!req->giv) { - assoc_len += crypto_aead_ivsize(crypto_aead_reqtfm(aead_req)); - proc_len += crypto_aead_ivsize(crypto_aead_reqtfm(aead_req)); - } else - proc_len += req->giv_len; - /* * If we are decrypting, we need to take the length of the ICV out of * the processing length. */ if (!req->is_encrypt) - proc_len -= ctx->auth_size; + proc_len -= authsize; writel(proc_len, engine->regs + SPA_PROC_LEN_REG_OFFSET); writel(assoc_len, engine->regs + SPA_AAD_LEN_REG_OFFSET); - writel(ctx->auth_size, engine->regs + SPA_ICV_LEN_REG_OFFSET); + writel(authsize, engine->regs + SPA_ICV_LEN_REG_OFFSET); writel(0, engine->regs + SPA_ICV_OFFSET_REG_OFFSET); writel(0, engine->regs + SPA_AUX_INFO_REG_OFFSET); @@ -674,32 +615,29 @@ static void spacc_push(struct spacc_engine *engine) /* * Setup an AEAD request for processing. This will configure the engine, load * the context and then start the packet processing. - * - * @giv Pointer to destination address for a generated IV. If the - * request does not need to generate an IV then this should be set to NULL. */ -static int spacc_aead_setup(struct aead_request *req, u8 *giv, +static int spacc_aead_setup(struct aead_request *req, unsigned alg_type, bool is_encrypt) { - struct crypto_alg *alg = req->base.tfm->__crt_alg; - struct spacc_engine *engine = to_spacc_alg(alg)->engine; + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct aead_alg *alg = crypto_aead_alg(aead); + struct spacc_engine *engine = to_spacc_aead(alg)->engine; struct spacc_req *dev_req = aead_request_ctx(req); - int err = -EINPROGRESS; + int err; unsigned long flags; - unsigned ivsize = crypto_aead_ivsize(crypto_aead_reqtfm(req)); - dev_req->giv = giv; - dev_req->giv_len = ivsize; dev_req->req = &req->base; dev_req->is_encrypt = is_encrypt; dev_req->result = -EBUSY; dev_req->engine = engine; dev_req->complete = spacc_aead_complete; - if (unlikely(spacc_aead_need_fallback(dev_req))) + if (unlikely(spacc_aead_need_fallback(req) || + ((err = spacc_aead_make_ddts(req)) == -E2BIG))) return spacc_aead_do_fallback(req, alg_type, is_encrypt); - spacc_aead_make_ddts(dev_req, dev_req->giv); + if (err) + goto out; err = -EINPROGRESS; spin_lock_irqsave(&engine->hw_lock, flags); @@ -728,70 +666,44 @@ out: static int spacc_aead_encrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct crypto_tfm *tfm = crypto_aead_tfm(aead); - struct spacc_alg *alg = to_spacc_alg(tfm->__crt_alg); + struct spacc_aead *alg = to_spacc_aead(crypto_aead_alg(aead)); - return spacc_aead_setup(req, NULL, alg->type, 1); -} - -static int spacc_aead_givencrypt(struct aead_givcrypt_request *req) -{ - struct crypto_aead *tfm = aead_givcrypt_reqtfm(req); - struct spacc_aead_ctx *ctx = crypto_aead_ctx(tfm); - size_t ivsize = crypto_aead_ivsize(tfm); - struct spacc_alg *alg = to_spacc_alg(tfm->base.__crt_alg); - unsigned len; - __be64 seq; - - memcpy(req->areq.iv, ctx->salt, ivsize); - len = ivsize; - if (ivsize > sizeof(u64)) { - memset(req->giv, 0, ivsize - sizeof(u64)); - len = sizeof(u64); - } - seq = cpu_to_be64(req->seq); - memcpy(req->giv + ivsize - len, &seq, len); - - return spacc_aead_setup(&req->areq, req->giv, alg->type, 1); + return spacc_aead_setup(req, alg->type, 1); } static int spacc_aead_decrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct crypto_tfm *tfm = crypto_aead_tfm(aead); - struct spacc_alg *alg = to_spacc_alg(tfm->__crt_alg); + struct spacc_aead *alg = to_spacc_aead(crypto_aead_alg(aead)); - return spacc_aead_setup(req, NULL, alg->type, 0); + return spacc_aead_setup(req, alg->type, 0); } /* * Initialise a new AEAD context. This is responsible for allocating the * fallback cipher and initialising the context. */ -static int spacc_aead_cra_init(struct crypto_tfm *tfm) +static int spacc_aead_cra_init(struct crypto_aead *tfm) { - struct spacc_aead_ctx *ctx = crypto_tfm_ctx(tfm); - struct crypto_alg *alg = tfm->__crt_alg; - struct spacc_alg *spacc_alg = to_spacc_alg(alg); + struct spacc_aead_ctx *ctx = crypto_aead_ctx(tfm); + struct aead_alg *alg = crypto_aead_alg(tfm); + struct spacc_aead *spacc_alg = to_spacc_aead(alg); struct spacc_engine *engine = spacc_alg->engine; ctx->generic.flags = spacc_alg->type; ctx->generic.engine = engine; - ctx->sw_cipher = crypto_alloc_aead(alg->cra_name, 0, - CRYPTO_ALG_ASYNC | + ctx->sw_cipher = crypto_alloc_aead(alg->base.cra_name, 0, CRYPTO_ALG_NEED_FALLBACK); - if (IS_ERR(ctx->sw_cipher)) { - dev_warn(engine->dev, "failed to allocate fallback for %s\n", - alg->cra_name); - ctx->sw_cipher = NULL; - } + if (IS_ERR(ctx->sw_cipher)) + return PTR_ERR(ctx->sw_cipher); ctx->generic.key_offs = spacc_alg->key_offs; ctx->generic.iv_offs = spacc_alg->iv_offs; - get_random_bytes(ctx->salt, sizeof(ctx->salt)); - - crypto_aead_set_reqsize(__crypto_aead_cast(tfm), - sizeof(struct spacc_req)); + crypto_aead_set_reqsize( + tfm, + max(sizeof(struct spacc_req), + sizeof(struct aead_request) + + crypto_aead_reqsize(ctx->sw_cipher))); return 0; } @@ -800,13 +712,11 @@ static int spacc_aead_cra_init(struct crypto_tfm *tfm) * Destructor for an AEAD context. This is called when the transform is freed * and must free the fallback cipher. */ -static void spacc_aead_cra_exit(struct crypto_tfm *tfm) +static void spacc_aead_cra_exit(struct crypto_aead *tfm) { - struct spacc_aead_ctx *ctx = crypto_tfm_ctx(tfm); + struct spacc_aead_ctx *ctx = crypto_aead_ctx(tfm); - if (ctx->sw_cipher) - crypto_free_aead(ctx->sw_cipher); - ctx->sw_cipher = NULL; + crypto_free_aead(ctx->sw_cipher); } /* @@ -1458,180 +1368,188 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_exit = spacc_ablk_cra_exit, }, }, +}; + +static struct spacc_aead ipsec_engine_aeads[] = { { - .ctrl_default = SPA_CTRL_CIPH_ALG_AES | SPA_CTRL_CIPH_MODE_CBC | - SPA_CTRL_HASH_ALG_SHA | SPA_CTRL_HASH_MODE_HMAC, + .ctrl_default = SPA_CTRL_CIPH_ALG_AES | + SPA_CTRL_CIPH_MODE_CBC | + SPA_CTRL_HASH_ALG_SHA | + SPA_CTRL_HASH_MODE_HMAC, .key_offs = 0, .iv_offs = AES_MAX_KEY_SIZE, .alg = { - .cra_name = "authenc(hmac(sha1),cbc(aes))", - .cra_driver_name = "authenc-hmac-sha1-cbc-aes-picoxcell", - .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct spacc_aead_ctx), - .cra_type = &crypto_aead_type, - .cra_module = THIS_MODULE, - .cra_aead = { - .setkey = spacc_aead_setkey, - .setauthsize = spacc_aead_setauthsize, - .encrypt = spacc_aead_encrypt, - .decrypt = spacc_aead_decrypt, - .givencrypt = spacc_aead_givencrypt, - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha1),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha1-" + "cbc-aes-picoxcell", + .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct spacc_aead_ctx), + .cra_module = THIS_MODULE, }, - .cra_init = spacc_aead_cra_init, - .cra_exit = spacc_aead_cra_exit, + .setkey = spacc_aead_setkey, + .setauthsize = spacc_aead_setauthsize, + .encrypt = spacc_aead_encrypt, + .decrypt = spacc_aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + .init = spacc_aead_cra_init, + .exit = spacc_aead_cra_exit, }, }, { - .ctrl_default = SPA_CTRL_CIPH_ALG_AES | SPA_CTRL_CIPH_MODE_CBC | + .ctrl_default = SPA_CTRL_CIPH_ALG_AES | + SPA_CTRL_CIPH_MODE_CBC | SPA_CTRL_HASH_ALG_SHA256 | SPA_CTRL_HASH_MODE_HMAC, .key_offs = 0, .iv_offs = AES_MAX_KEY_SIZE, .alg = { - .cra_name = "authenc(hmac(sha256),cbc(aes))", - .cra_driver_name = "authenc-hmac-sha256-cbc-aes-picoxcell", - .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct spacc_aead_ctx), - .cra_type = &crypto_aead_type, - .cra_module = THIS_MODULE, - .cra_aead = { - .setkey = spacc_aead_setkey, - .setauthsize = spacc_aead_setauthsize, - .encrypt = spacc_aead_encrypt, - .decrypt = spacc_aead_decrypt, - .givencrypt = spacc_aead_givencrypt, - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha256),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha256-" + "cbc-aes-picoxcell", + .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct spacc_aead_ctx), + .cra_module = THIS_MODULE, }, - .cra_init = spacc_aead_cra_init, - .cra_exit = spacc_aead_cra_exit, + .setkey = spacc_aead_setkey, + .setauthsize = spacc_aead_setauthsize, + .encrypt = spacc_aead_encrypt, + .decrypt = spacc_aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + .init = spacc_aead_cra_init, + .exit = spacc_aead_cra_exit, }, }, { .key_offs = 0, .iv_offs = AES_MAX_KEY_SIZE, - .ctrl_default = SPA_CTRL_CIPH_ALG_AES | SPA_CTRL_CIPH_MODE_CBC | - SPA_CTRL_HASH_ALG_MD5 | SPA_CTRL_HASH_MODE_HMAC, + .ctrl_default = SPA_CTRL_CIPH_ALG_AES | + SPA_CTRL_CIPH_MODE_CBC | + SPA_CTRL_HASH_ALG_MD5 | + SPA_CTRL_HASH_MODE_HMAC, .alg = { - .cra_name = "authenc(hmac(md5),cbc(aes))", - .cra_driver_name = "authenc-hmac-md5-cbc-aes-picoxcell", - .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct spacc_aead_ctx), - .cra_type = &crypto_aead_type, - .cra_module = THIS_MODULE, - .cra_aead = { - .setkey = spacc_aead_setkey, - .setauthsize = spacc_aead_setauthsize, - .encrypt = spacc_aead_encrypt, - .decrypt = spacc_aead_decrypt, - .givencrypt = spacc_aead_givencrypt, - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(md5),cbc(aes))", + .cra_driver_name = "authenc-hmac-md5-" + "cbc-aes-picoxcell", + .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct spacc_aead_ctx), + .cra_module = THIS_MODULE, }, - .cra_init = spacc_aead_cra_init, - .cra_exit = spacc_aead_cra_exit, + .setkey = spacc_aead_setkey, + .setauthsize = spacc_aead_setauthsize, + .encrypt = spacc_aead_encrypt, + .decrypt = spacc_aead_decrypt, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + .init = spacc_aead_cra_init, + .exit = spacc_aead_cra_exit, }, }, { .key_offs = DES_BLOCK_SIZE, .iv_offs = 0, - .ctrl_default = SPA_CTRL_CIPH_ALG_DES | SPA_CTRL_CIPH_MODE_CBC | - SPA_CTRL_HASH_ALG_SHA | SPA_CTRL_HASH_MODE_HMAC, + .ctrl_default = SPA_CTRL_CIPH_ALG_DES | + SPA_CTRL_CIPH_MODE_CBC | + SPA_CTRL_HASH_ALG_SHA | + SPA_CTRL_HASH_MODE_HMAC, .alg = { - .cra_name = "authenc(hmac(sha1),cbc(des3_ede))", - .cra_driver_name = "authenc-hmac-sha1-cbc-3des-picoxcell", - .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct spacc_aead_ctx), - .cra_type = &crypto_aead_type, - .cra_module = THIS_MODULE, - .cra_aead = { - .setkey = spacc_aead_setkey, - .setauthsize = spacc_aead_setauthsize, - .encrypt = spacc_aead_encrypt, - .decrypt = spacc_aead_decrypt, - .givencrypt = spacc_aead_givencrypt, - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha1),cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha1-" + "cbc-3des-picoxcell", + .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct spacc_aead_ctx), + .cra_module = THIS_MODULE, }, - .cra_init = spacc_aead_cra_init, - .cra_exit = spacc_aead_cra_exit, + .setkey = spacc_aead_setkey, + .setauthsize = spacc_aead_setauthsize, + .encrypt = spacc_aead_encrypt, + .decrypt = spacc_aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + .init = spacc_aead_cra_init, + .exit = spacc_aead_cra_exit, }, }, { .key_offs = DES_BLOCK_SIZE, .iv_offs = 0, - .ctrl_default = SPA_CTRL_CIPH_ALG_AES | SPA_CTRL_CIPH_MODE_CBC | + .ctrl_default = SPA_CTRL_CIPH_ALG_AES | + SPA_CTRL_CIPH_MODE_CBC | SPA_CTRL_HASH_ALG_SHA256 | SPA_CTRL_HASH_MODE_HMAC, .alg = { - .cra_name = "authenc(hmac(sha256),cbc(des3_ede))", - .cra_driver_name = "authenc-hmac-sha256-cbc-3des-picoxcell", - .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct spacc_aead_ctx), - .cra_type = &crypto_aead_type, - .cra_module = THIS_MODULE, - .cra_aead = { - .setkey = spacc_aead_setkey, - .setauthsize = spacc_aead_setauthsize, - .encrypt = spacc_aead_encrypt, - .decrypt = spacc_aead_decrypt, - .givencrypt = spacc_aead_givencrypt, - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(sha256)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha256-" + "cbc-3des-picoxcell", + .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct spacc_aead_ctx), + .cra_module = THIS_MODULE, }, - .cra_init = spacc_aead_cra_init, - .cra_exit = spacc_aead_cra_exit, + .setkey = spacc_aead_setkey, + .setauthsize = spacc_aead_setauthsize, + .encrypt = spacc_aead_encrypt, + .decrypt = spacc_aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + .init = spacc_aead_cra_init, + .exit = spacc_aead_cra_exit, }, }, { .key_offs = DES_BLOCK_SIZE, .iv_offs = 0, - .ctrl_default = SPA_CTRL_CIPH_ALG_DES | SPA_CTRL_CIPH_MODE_CBC | - SPA_CTRL_HASH_ALG_MD5 | SPA_CTRL_HASH_MODE_HMAC, + .ctrl_default = SPA_CTRL_CIPH_ALG_DES | + SPA_CTRL_CIPH_MODE_CBC | + SPA_CTRL_HASH_ALG_MD5 | + SPA_CTRL_HASH_MODE_HMAC, .alg = { - .cra_name = "authenc(hmac(md5),cbc(des3_ede))", - .cra_driver_name = "authenc-hmac-md5-cbc-3des-picoxcell", - .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct spacc_aead_ctx), - .cra_type = &crypto_aead_type, - .cra_module = THIS_MODULE, - .cra_aead = { - .setkey = spacc_aead_setkey, - .setauthsize = spacc_aead_setauthsize, - .encrypt = spacc_aead_encrypt, - .decrypt = spacc_aead_decrypt, - .givencrypt = spacc_aead_givencrypt, - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, + .base = { + .cra_name = "authenc(hmac(md5),cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-md5-" + "cbc-3des-picoxcell", + .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK | + CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct spacc_aead_ctx), + .cra_module = THIS_MODULE, }, - .cra_init = spacc_aead_cra_init, - .cra_exit = spacc_aead_cra_exit, + .setkey = spacc_aead_setkey, + .setauthsize = spacc_aead_setauthsize, + .encrypt = spacc_aead_encrypt, + .decrypt = spacc_aead_decrypt, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, + .init = spacc_aead_cra_init, + .exit = spacc_aead_cra_exit, }, }, }; @@ -1707,6 +1625,8 @@ static int spacc_probe(struct platform_device *pdev) engine->fifo_sz = SPACC_CRYPTO_IPSEC_FIFO_SZ; engine->algs = ipsec_engine_algs; engine->num_algs = ARRAY_SIZE(ipsec_engine_algs); + engine->aeads = ipsec_engine_aeads; + engine->num_aeads = ARRAY_SIZE(ipsec_engine_aeads); } else if (spacc_is_compatible(pdev, "picochip,spacc-l2")) { engine->max_ctxs = SPACC_CRYPTO_L2_MAX_CTXS; engine->cipher_pg_sz = SPACC_CRYPTO_L2_CIPHER_PG_SZ; @@ -1815,17 +1735,41 @@ static int spacc_probe(struct platform_device *pdev) engine->algs[i].alg.cra_name); } + INIT_LIST_HEAD(&engine->registered_aeads); + for (i = 0; i < engine->num_aeads; ++i) { + engine->aeads[i].engine = engine; + engine->aeads[i].alg.base.cra_flags |= CRYPTO_ALG_AEAD_NEW; + err = crypto_register_aead(&engine->aeads[i].alg); + if (!err) { + list_add_tail(&engine->aeads[i].entry, + &engine->registered_aeads); + ret = 0; + } + if (err) + dev_err(engine->dev, "failed to register alg \"%s\"\n", + engine->aeads[i].alg.base.cra_name); + else + dev_dbg(engine->dev, "registered alg \"%s\"\n", + engine->aeads[i].alg.base.cra_name); + } + return ret; } static int spacc_remove(struct platform_device *pdev) { + struct spacc_aead *aead, *an; struct spacc_alg *alg, *next; struct spacc_engine *engine = platform_get_drvdata(pdev); del_timer_sync(&engine->packet_timeout); device_remove_file(&pdev->dev, &dev_attr_stat_irq_thresh); + list_for_each_entry_safe(aead, an, &engine->registered_aeads, entry) { + list_del(&aead->entry); + crypto_unregister_aead(&aead->alg); + } + list_for_each_entry_safe(alg, next, &engine->registered_algs, entry) { list_del(&alg->entry); crypto_unregister_alg(&alg->alg); -- cgit v1.3-6-gb490 From e19ab1211d2848ebd028c824041d8ea249fa3aae Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Jul 2015 17:53:20 +0800 Subject: crypto: qat - Convert to new AEAD interface This patch converts qat to the new AEAD interface. IV generation has been removed since it's equivalent to a software implementation. Signed-off-by: Herbert Xu Tested-by: Tadeusz Struk --- drivers/crypto/qat/qat_common/qat_algs.c | 327 ++++++++++++------------------- 1 file changed, 123 insertions(+), 204 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c index 9b25ab1d30a4..1411e4c8bd22 100644 --- a/drivers/crypto/qat/qat_common/qat_algs.c +++ b/drivers/crypto/qat/qat_common/qat_algs.c @@ -53,7 +53,6 @@ #include #include #include -#include #include #include "adf_accel_devices.h" #include "adf_transport.h" @@ -113,9 +112,6 @@ struct qat_alg_aead_ctx { struct crypto_shash *hash_tfm; enum icp_qat_hw_auth_algo qat_hash_alg; struct qat_crypto_instance *inst; - struct crypto_tfm *tfm; - uint8_t salt[AES_BLOCK_SIZE]; - spinlock_t lock; /* protects qat_alg_aead_ctx struct */ }; struct qat_alg_ablkcipher_ctx { @@ -273,11 +269,11 @@ static void qat_alg_init_common_hdr(struct icp_qat_fw_comn_req_hdr *header) ICP_QAT_FW_LA_NO_UPDATE_STATE); } -static int qat_alg_aead_init_enc_session(struct qat_alg_aead_ctx *ctx, +static int qat_alg_aead_init_enc_session(struct crypto_aead *aead_tfm, int alg, struct crypto_authenc_keys *keys) { - struct crypto_aead *aead_tfm = __crypto_aead_cast(ctx->tfm); + struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(aead_tfm); unsigned int digestsize = crypto_aead_crt(aead_tfm)->authsize; struct qat_enc *enc_ctx = &ctx->enc_cd->qat_enc_cd; struct icp_qat_hw_cipher_algo_blk *cipher = &enc_ctx->cipher; @@ -353,11 +349,11 @@ static int qat_alg_aead_init_enc_session(struct qat_alg_aead_ctx *ctx, return 0; } -static int qat_alg_aead_init_dec_session(struct qat_alg_aead_ctx *ctx, +static int qat_alg_aead_init_dec_session(struct crypto_aead *aead_tfm, int alg, struct crypto_authenc_keys *keys) { - struct crypto_aead *aead_tfm = __crypto_aead_cast(ctx->tfm); + struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(aead_tfm); unsigned int digestsize = crypto_aead_crt(aead_tfm)->authsize; struct qat_dec *dec_ctx = &ctx->dec_cd->qat_dec_cd; struct icp_qat_hw_auth_algo_blk *hash = &dec_ctx->hash; @@ -510,30 +506,27 @@ static int qat_alg_validate_key(int key_len, int *alg) return 0; } -static int qat_alg_aead_init_sessions(struct qat_alg_aead_ctx *ctx, +static int qat_alg_aead_init_sessions(struct crypto_aead *tfm, const uint8_t *key, unsigned int keylen) { struct crypto_authenc_keys keys; int alg; - if (crypto_rng_get_bytes(crypto_default_rng, ctx->salt, AES_BLOCK_SIZE)) - return -EFAULT; - if (crypto_authenc_extractkeys(&keys, key, keylen)) goto bad_key; if (qat_alg_validate_key(keys.enckeylen, &alg)) goto bad_key; - if (qat_alg_aead_init_enc_session(ctx, alg, &keys)) + if (qat_alg_aead_init_enc_session(tfm, alg, &keys)) goto error; - if (qat_alg_aead_init_dec_session(ctx, alg, &keys)) + if (qat_alg_aead_init_dec_session(tfm, alg, &keys)) goto error; return 0; bad_key: - crypto_tfm_set_flags(ctx->tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; error: return -EFAULT; @@ -562,7 +555,6 @@ static int qat_alg_aead_setkey(struct crypto_aead *tfm, const uint8_t *key, struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm); struct device *dev; - spin_lock(&ctx->lock); if (ctx->enc_cd) { /* rekeying */ dev = &GET_DEV(ctx->inst->accel_dev); @@ -576,7 +568,6 @@ static int qat_alg_aead_setkey(struct crypto_aead *tfm, const uint8_t *key, struct qat_crypto_instance *inst = qat_crypto_get_instance_node(node); if (!inst) { - spin_unlock(&ctx->lock); return -EINVAL; } @@ -586,19 +577,16 @@ static int qat_alg_aead_setkey(struct crypto_aead *tfm, const uint8_t *key, &ctx->enc_cd_paddr, GFP_ATOMIC); if (!ctx->enc_cd) { - spin_unlock(&ctx->lock); return -ENOMEM; } ctx->dec_cd = dma_zalloc_coherent(dev, sizeof(*ctx->dec_cd), &ctx->dec_cd_paddr, GFP_ATOMIC); if (!ctx->dec_cd) { - spin_unlock(&ctx->lock); goto out_free_enc; } } - spin_unlock(&ctx->lock); - if (qat_alg_aead_init_sessions(ctx, key, keylen)) + if (qat_alg_aead_init_sessions(tfm, key, keylen)) goto out_free_all; return 0; @@ -649,22 +637,20 @@ static void qat_alg_free_bufl(struct qat_crypto_instance *inst, } static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, - struct scatterlist *assoc, int assoclen, struct scatterlist *sgl, - struct scatterlist *sglout, uint8_t *iv, - uint8_t ivlen, + struct scatterlist *sglout, struct qat_crypto_request *qat_req) { struct device *dev = &GET_DEV(inst->accel_dev); - int i, bufs = 0, sg_nctr = 0; - int n = sg_nents(sgl), assoc_n = sg_nents(assoc); + int i, sg_nctr = 0; + int n = sg_nents(sgl); struct qat_alg_buf_list *bufl; struct qat_alg_buf_list *buflout = NULL; dma_addr_t blp; dma_addr_t bloutp = 0; struct scatterlist *sg; size_t sz_out, sz = sizeof(struct qat_alg_buf_list) + - ((1 + n + assoc_n) * sizeof(struct qat_alg_buf)); + ((1 + n) * sizeof(struct qat_alg_buf)); if (unlikely(!n)) return -EINVAL; @@ -678,35 +664,8 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, if (unlikely(dma_mapping_error(dev, blp))) goto err; - for_each_sg(assoc, sg, assoc_n, i) { - if (!sg->length) - continue; - - if (!(assoclen > 0)) - break; - - bufl->bufers[bufs].addr = - dma_map_single(dev, sg_virt(sg), - min_t(int, assoclen, sg->length), - DMA_BIDIRECTIONAL); - bufl->bufers[bufs].len = min_t(int, assoclen, sg->length); - if (unlikely(dma_mapping_error(dev, bufl->bufers[bufs].addr))) - goto err; - bufs++; - assoclen -= sg->length; - } - - if (ivlen) { - bufl->bufers[bufs].addr = dma_map_single(dev, iv, ivlen, - DMA_BIDIRECTIONAL); - bufl->bufers[bufs].len = ivlen; - if (unlikely(dma_mapping_error(dev, bufl->bufers[bufs].addr))) - goto err; - bufs++; - } - for_each_sg(sgl, sg, n, i) { - int y = sg_nctr + bufs; + int y = sg_nctr; if (!sg->length) continue; @@ -719,7 +678,7 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, goto err; sg_nctr++; } - bufl->num_bufs = sg_nctr + bufs; + bufl->num_bufs = sg_nctr; qat_req->buf.bl = bufl; qat_req->buf.blp = blp; qat_req->buf.sz = sz; @@ -729,7 +688,7 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, n = sg_nents(sglout); sz_out = sizeof(struct qat_alg_buf_list) + - ((1 + n + assoc_n) * sizeof(struct qat_alg_buf)); + ((1 + n) * sizeof(struct qat_alg_buf)); sg_nctr = 0; buflout = kzalloc_node(sz_out, GFP_ATOMIC, dev_to_node(&GET_DEV(inst->accel_dev))); @@ -739,14 +698,8 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, if (unlikely(dma_mapping_error(dev, bloutp))) goto err; bufers = buflout->bufers; - /* For out of place operation dma map only data and - * reuse assoc mapping and iv */ - for (i = 0; i < bufs; i++) { - bufers[i].len = bufl->bufers[i].len; - bufers[i].addr = bufl->bufers[i].addr; - } for_each_sg(sglout, sg, n, i) { - int y = sg_nctr + bufs; + int y = sg_nctr; if (!sg->length) continue; @@ -759,7 +712,7 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, bufers[y].len = sg->length; sg_nctr++; } - buflout->num_bufs = sg_nctr + bufs; + buflout->num_bufs = sg_nctr; buflout->num_mapped_bufs = sg_nctr; qat_req->buf.blout = buflout; qat_req->buf.bloutp = bloutp; @@ -773,7 +726,7 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst, err: dev_err(dev, "Failed to map buf for dma\n"); sg_nctr = 0; - for (i = 0; i < n + bufs; i++) + for (i = 0; i < n; i++) if (!dma_mapping_error(dev, bufl->bufers[i].addr)) dma_unmap_single(dev, bufl->bufers[i].addr, bufl->bufers[i].len, @@ -784,7 +737,7 @@ err: kfree(bufl); if (sgl != sglout && buflout) { n = sg_nents(sglout); - for (i = bufs; i < n + bufs; i++) + for (i = 0; i < n; i++) if (!dma_mapping_error(dev, buflout->bufers[i].addr)) dma_unmap_single(dev, buflout->bufers[i].addr, buflout->bufers[i].len, @@ -847,9 +800,7 @@ static int qat_alg_aead_dec(struct aead_request *areq) int digst_size = crypto_aead_crt(aead_tfm)->authsize; int ret, ctr = 0; - ret = qat_alg_sgl_to_bufl(ctx->inst, areq->assoc, areq->assoclen, - areq->src, areq->dst, areq->iv, - AES_BLOCK_SIZE, qat_req); + ret = qat_alg_sgl_to_bufl(ctx->inst, areq->src, areq->dst, qat_req); if (unlikely(ret)) return ret; @@ -863,12 +814,11 @@ static int qat_alg_aead_dec(struct aead_request *areq) qat_req->req.comn_mid.dest_data_addr = qat_req->buf.bloutp; cipher_param = (void *)&qat_req->req.serv_specif_rqpars; cipher_param->cipher_length = areq->cryptlen - digst_size; - cipher_param->cipher_offset = areq->assoclen + AES_BLOCK_SIZE; + cipher_param->cipher_offset = areq->assoclen; memcpy(cipher_param->u.cipher_IV_array, areq->iv, AES_BLOCK_SIZE); auth_param = (void *)((uint8_t *)cipher_param + sizeof(*cipher_param)); auth_param->auth_off = 0; - auth_param->auth_len = areq->assoclen + - cipher_param->cipher_length + AES_BLOCK_SIZE; + auth_param->auth_len = areq->assoclen + cipher_param->cipher_length; do { ret = adf_send_message(ctx->inst->sym_tx, (uint32_t *)msg); } while (ret == -EAGAIN && ctr++ < 10); @@ -880,8 +830,7 @@ static int qat_alg_aead_dec(struct aead_request *areq) return -EINPROGRESS; } -static int qat_alg_aead_enc_internal(struct aead_request *areq, uint8_t *iv, - int enc_iv) +static int qat_alg_aead_enc(struct aead_request *areq) { struct crypto_aead *aead_tfm = crypto_aead_reqtfm(areq); struct crypto_tfm *tfm = crypto_aead_tfm(aead_tfm); @@ -890,11 +839,10 @@ static int qat_alg_aead_enc_internal(struct aead_request *areq, uint8_t *iv, struct icp_qat_fw_la_cipher_req_params *cipher_param; struct icp_qat_fw_la_auth_req_params *auth_param; struct icp_qat_fw_la_bulk_req *msg; + uint8_t *iv = areq->iv; int ret, ctr = 0; - ret = qat_alg_sgl_to_bufl(ctx->inst, areq->assoc, areq->assoclen, - areq->src, areq->dst, iv, AES_BLOCK_SIZE, - qat_req); + ret = qat_alg_sgl_to_bufl(ctx->inst, areq->src, areq->dst, qat_req); if (unlikely(ret)) return ret; @@ -909,16 +857,12 @@ static int qat_alg_aead_enc_internal(struct aead_request *areq, uint8_t *iv, cipher_param = (void *)&qat_req->req.serv_specif_rqpars; auth_param = (void *)((uint8_t *)cipher_param + sizeof(*cipher_param)); - if (enc_iv) { - cipher_param->cipher_length = areq->cryptlen + AES_BLOCK_SIZE; - cipher_param->cipher_offset = areq->assoclen; - } else { - memcpy(cipher_param->u.cipher_IV_array, iv, AES_BLOCK_SIZE); - cipher_param->cipher_length = areq->cryptlen; - cipher_param->cipher_offset = areq->assoclen + AES_BLOCK_SIZE; - } + memcpy(cipher_param->u.cipher_IV_array, iv, AES_BLOCK_SIZE); + cipher_param->cipher_length = areq->cryptlen; + cipher_param->cipher_offset = areq->assoclen; + auth_param->auth_off = 0; - auth_param->auth_len = areq->assoclen + areq->cryptlen + AES_BLOCK_SIZE; + auth_param->auth_len = areq->assoclen + areq->cryptlen; do { ret = adf_send_message(ctx->inst->sym_tx, (uint32_t *)msg); @@ -931,25 +875,6 @@ static int qat_alg_aead_enc_internal(struct aead_request *areq, uint8_t *iv, return -EINPROGRESS; } -static int qat_alg_aead_enc(struct aead_request *areq) -{ - return qat_alg_aead_enc_internal(areq, areq->iv, 0); -} - -static int qat_alg_aead_genivenc(struct aead_givcrypt_request *req) -{ - struct crypto_aead *aead_tfm = crypto_aead_reqtfm(&req->areq); - struct crypto_tfm *tfm = crypto_aead_tfm(aead_tfm); - struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm); - __be64 seq; - - memcpy(req->giv, ctx->salt, AES_BLOCK_SIZE); - seq = cpu_to_be64(req->seq); - memcpy(req->giv + AES_BLOCK_SIZE - sizeof(uint64_t), - &seq, sizeof(uint64_t)); - return qat_alg_aead_enc_internal(&req->areq, req->giv, 1); -} - static int qat_alg_ablkcipher_setkey(struct crypto_ablkcipher *tfm, const uint8_t *key, unsigned int keylen) @@ -1021,8 +946,7 @@ static int qat_alg_ablkcipher_encrypt(struct ablkcipher_request *req) struct icp_qat_fw_la_bulk_req *msg; int ret, ctr = 0; - ret = qat_alg_sgl_to_bufl(ctx->inst, NULL, 0, req->src, req->dst, - NULL, 0, qat_req); + ret = qat_alg_sgl_to_bufl(ctx->inst, req->src, req->dst, qat_req); if (unlikely(ret)) return ret; @@ -1059,8 +983,7 @@ static int qat_alg_ablkcipher_decrypt(struct ablkcipher_request *req) struct icp_qat_fw_la_bulk_req *msg; int ret, ctr = 0; - ret = qat_alg_sgl_to_bufl(ctx->inst, NULL, 0, req->src, req->dst, - NULL, 0, qat_req); + ret = qat_alg_sgl_to_bufl(ctx->inst, req->src, req->dst, qat_req); if (unlikely(ret)) return ret; @@ -1087,47 +1010,43 @@ static int qat_alg_ablkcipher_decrypt(struct ablkcipher_request *req) return -EINPROGRESS; } -static int qat_alg_aead_init(struct crypto_tfm *tfm, +static int qat_alg_aead_init(struct crypto_aead *tfm, enum icp_qat_hw_auth_algo hash, const char *hash_name) { - struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm); + struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm); ctx->hash_tfm = crypto_alloc_shash(hash_name, 0, 0); if (IS_ERR(ctx->hash_tfm)) - return -EFAULT; - spin_lock_init(&ctx->lock); + return PTR_ERR(ctx->hash_tfm); ctx->qat_hash_alg = hash; - crypto_aead_set_reqsize(__crypto_aead_cast(tfm), - sizeof(struct aead_request) + - sizeof(struct qat_crypto_request)); - ctx->tfm = tfm; + crypto_aead_set_reqsize(tfm, sizeof(struct aead_request) + + sizeof(struct qat_crypto_request)); return 0; } -static int qat_alg_aead_sha1_init(struct crypto_tfm *tfm) +static int qat_alg_aead_sha1_init(struct crypto_aead *tfm) { return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA1, "sha1"); } -static int qat_alg_aead_sha256_init(struct crypto_tfm *tfm) +static int qat_alg_aead_sha256_init(struct crypto_aead *tfm) { return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA256, "sha256"); } -static int qat_alg_aead_sha512_init(struct crypto_tfm *tfm) +static int qat_alg_aead_sha512_init(struct crypto_aead *tfm) { return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA512, "sha512"); } -static void qat_alg_aead_exit(struct crypto_tfm *tfm) +static void qat_alg_aead_exit(struct crypto_aead *tfm) { - struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm); + struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm); struct qat_crypto_instance *inst = ctx->inst; struct device *dev; - if (!IS_ERR(ctx->hash_tfm)) - crypto_free_shash(ctx->hash_tfm); + crypto_free_shash(ctx->hash_tfm); if (!inst) return; @@ -1184,73 +1103,61 @@ static void qat_alg_ablkcipher_exit(struct crypto_tfm *tfm) qat_crypto_put_instance(inst); } -static struct crypto_alg qat_algs[] = { { - .cra_name = "authenc(hmac(sha1),cbc(aes))", - .cra_driver_name = "qat_aes_cbc_hmac_sha1", - .cra_priority = 4001, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct qat_alg_aead_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_aead_type, - .cra_module = THIS_MODULE, - .cra_init = qat_alg_aead_sha1_init, - .cra_exit = qat_alg_aead_exit, - .cra_u = { - .aead = { - .setkey = qat_alg_aead_setkey, - .decrypt = qat_alg_aead_dec, - .encrypt = qat_alg_aead_enc, - .givencrypt = qat_alg_aead_genivenc, - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - }, + +static struct aead_alg qat_aeads[] = { { + .base = { + .cra_name = "authenc(hmac(sha1),cbc(aes))", + .cra_driver_name = "qat_aes_cbc_hmac_sha1", + .cra_priority = 4001, + .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_AEAD_NEW, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct qat_alg_aead_ctx), + .cra_module = THIS_MODULE, }, + .init = qat_alg_aead_sha1_init, + .exit = qat_alg_aead_exit, + .setkey = qat_alg_aead_setkey, + .decrypt = qat_alg_aead_dec, + .encrypt = qat_alg_aead_enc, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, }, { - .cra_name = "authenc(hmac(sha256),cbc(aes))", - .cra_driver_name = "qat_aes_cbc_hmac_sha256", - .cra_priority = 4001, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct qat_alg_aead_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_aead_type, - .cra_module = THIS_MODULE, - .cra_init = qat_alg_aead_sha256_init, - .cra_exit = qat_alg_aead_exit, - .cra_u = { - .aead = { - .setkey = qat_alg_aead_setkey, - .decrypt = qat_alg_aead_dec, - .encrypt = qat_alg_aead_enc, - .givencrypt = qat_alg_aead_genivenc, - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - }, + .base = { + .cra_name = "authenc(hmac(sha256),cbc(aes))", + .cra_driver_name = "qat_aes_cbc_hmac_sha256", + .cra_priority = 4001, + .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_AEAD_NEW, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct qat_alg_aead_ctx), + .cra_module = THIS_MODULE, }, + .init = qat_alg_aead_sha256_init, + .exit = qat_alg_aead_exit, + .setkey = qat_alg_aead_setkey, + .decrypt = qat_alg_aead_dec, + .encrypt = qat_alg_aead_enc, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, }, { - .cra_name = "authenc(hmac(sha512),cbc(aes))", - .cra_driver_name = "qat_aes_cbc_hmac_sha512", - .cra_priority = 4001, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct qat_alg_aead_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_aead_type, - .cra_module = THIS_MODULE, - .cra_init = qat_alg_aead_sha512_init, - .cra_exit = qat_alg_aead_exit, - .cra_u = { - .aead = { - .setkey = qat_alg_aead_setkey, - .decrypt = qat_alg_aead_dec, - .encrypt = qat_alg_aead_enc, - .givencrypt = qat_alg_aead_genivenc, - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA512_DIGEST_SIZE, - }, + .base = { + .cra_name = "authenc(hmac(sha512),cbc(aes))", + .cra_driver_name = "qat_aes_cbc_hmac_sha512", + .cra_priority = 4001, + .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_AEAD_NEW, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct qat_alg_aead_ctx), + .cra_module = THIS_MODULE, }, -}, { + .init = qat_alg_aead_sha512_init, + .exit = qat_alg_aead_exit, + .setkey = qat_alg_aead_setkey, + .decrypt = qat_alg_aead_dec, + .encrypt = qat_alg_aead_enc, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, +} }; + +static struct crypto_alg qat_algs[] = { { .cra_name = "cbc(aes)", .cra_driver_name = "qat_aes_cbc", .cra_priority = 4001, @@ -1276,42 +1183,54 @@ static struct crypto_alg qat_algs[] = { { int qat_algs_register(void) { - int ret = 0; + int ret = 0, i; mutex_lock(&algs_lock); - if (++active_devs == 1) { - int i; + if (++active_devs != 1) + goto unlock; - for (i = 0; i < ARRAY_SIZE(qat_algs); i++) - qat_algs[i].cra_flags = - (qat_algs[i].cra_type == &crypto_aead_type) ? - CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC : - CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC; + for (i = 0; i < ARRAY_SIZE(qat_algs); i++) + qat_algs[i].cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC; - ret = crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs)); - } + ret = crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs)); + if (ret) + goto unlock; + + for (i = 0; i < ARRAY_SIZE(qat_aeads); i++) + qat_aeads[i].base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_AEAD_NEW; + + ret = crypto_register_aeads(qat_aeads, ARRAY_SIZE(qat_aeads)); + if (ret) + goto unreg_algs; + +unlock: mutex_unlock(&algs_lock); return ret; + +unreg_algs: + crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs)); + goto unlock; } int qat_algs_unregister(void) { - int ret = 0; - mutex_lock(&algs_lock); - if (--active_devs == 0) - ret = crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs)); + if (--active_devs != 0) + goto unlock; + + crypto_unregister_aeads(qat_aeads, ARRAY_SIZE(qat_aeads)); + crypto_unregister_algs(qat_algs, ARRAY_SIZE(qat_algs)); + +unlock: mutex_unlock(&algs_lock); - return ret; + return 0; } int qat_algs_init(void) { - crypto_get_default_rng(); return 0; } void qat_algs_exit(void) { - crypto_put_default_rng(); } -- cgit v1.3-6-gb490 From aeb4c132f33d21f6cf37558a932e66e40dd8982e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 30 Jul 2015 17:53:22 +0800 Subject: crypto: talitos - Convert to new AEAD interface This patch converts talitos to the new AEAD interface. IV generation has been removed since it's equivalent to a software implementation. Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 606 ++++++++++++++++++++++------------------------- 1 file changed, 277 insertions(+), 329 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 83aca95a95bc..43727c915a59 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -799,7 +799,6 @@ struct talitos_ctx { unsigned int keylen; unsigned int enckeylen; unsigned int authkeylen; - unsigned int authsize; }; #define HASH_MAX_BLOCK_SIZE SHA512_BLOCK_SIZE @@ -819,16 +818,6 @@ struct talitos_ahash_req_ctx { struct scatterlist *psrc; }; -static int aead_setauthsize(struct crypto_aead *authenc, - unsigned int authsize) -{ - struct talitos_ctx *ctx = crypto_aead_ctx(authenc); - - ctx->authsize = authsize; - - return 0; -} - static int aead_setkey(struct crypto_aead *authenc, const u8 *key, unsigned int keylen) { @@ -857,12 +846,11 @@ badkey: /* * talitos_edesc - s/w-extended descriptor - * @assoc_nents: number of segments in associated data scatterlist * @src_nents: number of segments in input scatterlist * @dst_nents: number of segments in output scatterlist - * @assoc_chained: whether assoc is chained or not * @src_chained: whether src is chained or not * @dst_chained: whether dst is chained or not + * @icv_ool: whether ICV is out-of-line * @iv_dma: dma address of iv for checking continuity and link table * @dma_len: length of dma mapped link_tbl space * @dma_link_tbl: bus physical address of link_tbl/buf @@ -875,12 +863,11 @@ badkey: * of link_tbl data */ struct talitos_edesc { - int assoc_nents; int src_nents; int dst_nents; - bool assoc_chained; bool src_chained; bool dst_chained; + bool icv_ool; dma_addr_t iv_dma; int dma_len; dma_addr_t dma_link_tbl; @@ -952,14 +939,6 @@ static void ipsec_esp_unmap(struct device *dev, unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2], DMA_TO_DEVICE); unmap_single_talitos_ptr(dev, &edesc->desc.ptr[0], DMA_TO_DEVICE); - if (edesc->assoc_chained) - talitos_unmap_sg_chain(dev, areq->assoc, DMA_TO_DEVICE); - else if (areq->assoclen) - /* assoc_nents counts also for IV in non-contiguous cases */ - dma_unmap_sg(dev, areq->assoc, - edesc->assoc_nents ? edesc->assoc_nents - 1 : 1, - DMA_TO_DEVICE); - talitos_sg_unmap(dev, edesc, areq->src, areq->dst); if (edesc->dma_len) @@ -976,7 +955,7 @@ static void ipsec_esp_encrypt_done(struct device *dev, { struct aead_request *areq = context; struct crypto_aead *authenc = crypto_aead_reqtfm(areq); - struct talitos_ctx *ctx = crypto_aead_ctx(authenc); + unsigned int authsize = crypto_aead_authsize(authenc); struct talitos_edesc *edesc; struct scatterlist *sg; void *icvdata; @@ -986,13 +965,12 @@ static void ipsec_esp_encrypt_done(struct device *dev, ipsec_esp_unmap(dev, edesc, areq); /* copy the generated ICV to dst */ - if (edesc->dst_nents) { + if (edesc->icv_ool) { icvdata = &edesc->link_tbl[edesc->src_nents + - edesc->dst_nents + 2 + - edesc->assoc_nents]; + edesc->dst_nents + 2]; sg = sg_last(areq->dst, edesc->dst_nents); - memcpy((char *)sg_virt(sg) + sg->length - ctx->authsize, - icvdata, ctx->authsize); + memcpy((char *)sg_virt(sg) + sg->length - authsize, + icvdata, authsize); } kfree(edesc); @@ -1006,10 +984,10 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev, { struct aead_request *req = context; struct crypto_aead *authenc = crypto_aead_reqtfm(req); - struct talitos_ctx *ctx = crypto_aead_ctx(authenc); + unsigned int authsize = crypto_aead_authsize(authenc); struct talitos_edesc *edesc; struct scatterlist *sg; - void *icvdata; + char *oicv, *icv; edesc = container_of(desc, struct talitos_edesc, desc); @@ -1017,16 +995,18 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev, if (!err) { /* auth check */ - if (edesc->dma_len) - icvdata = &edesc->link_tbl[edesc->src_nents + - edesc->dst_nents + 2 + - edesc->assoc_nents]; - else - icvdata = &edesc->link_tbl[0]; - sg = sg_last(req->dst, edesc->dst_nents ? : 1); - err = memcmp(icvdata, (char *)sg_virt(sg) + sg->length - - ctx->authsize, ctx->authsize) ? -EBADMSG : 0; + icv = (char *)sg_virt(sg) + sg->length - authsize; + + if (edesc->dma_len) { + oicv = (char *)&edesc->link_tbl[edesc->src_nents + + edesc->dst_nents + 2]; + if (edesc->icv_ool) + icv = oicv + authsize; + } else + oicv = (char *)&edesc->link_tbl[0]; + + err = memcmp(oicv, icv, authsize) ? -EBADMSG : 0; } kfree(edesc); @@ -1059,53 +1039,69 @@ static void ipsec_esp_decrypt_hwauth_done(struct device *dev, * convert scatterlist to SEC h/w link table format * stop at cryptlen bytes */ -static int sg_to_link_tbl(struct scatterlist *sg, int sg_count, - int cryptlen, struct talitos_ptr *link_tbl_ptr) +static int sg_to_link_tbl_offset(struct scatterlist *sg, int sg_count, + unsigned int offset, int cryptlen, + struct talitos_ptr *link_tbl_ptr) { int n_sg = sg_count; + int count = 0; - while (sg && n_sg--) { - to_talitos_ptr(link_tbl_ptr, sg_dma_address(sg), 0); - link_tbl_ptr->len = cpu_to_be16(sg_dma_len(sg)); - link_tbl_ptr->j_extent = 0; - link_tbl_ptr++; - cryptlen -= sg_dma_len(sg); - sg = sg_next(sg); - } + while (cryptlen && sg && n_sg--) { + unsigned int len = sg_dma_len(sg); - /* adjust (decrease) last one (or two) entry's len to cryptlen */ - link_tbl_ptr--; - while (be16_to_cpu(link_tbl_ptr->len) <= (-cryptlen)) { - /* Empty this entry, and move to previous one */ - cryptlen += be16_to_cpu(link_tbl_ptr->len); - link_tbl_ptr->len = 0; - sg_count--; - link_tbl_ptr--; + if (offset >= len) { + offset -= len; + goto next; + } + + len -= offset; + + if (len > cryptlen) + len = cryptlen; + + to_talitos_ptr(link_tbl_ptr + count, + sg_dma_address(sg) + offset, 0); + link_tbl_ptr[count].len = cpu_to_be16(len); + link_tbl_ptr[count].j_extent = 0; + count++; + cryptlen -= len; + offset = 0; + +next: + sg = sg_next(sg); } - link_tbl_ptr->len = cpu_to_be16(be16_to_cpu(link_tbl_ptr->len) - + cryptlen); /* tag end of link table */ - link_tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN; + if (count > 0) + link_tbl_ptr[count - 1].j_extent = DESC_PTR_LNKTBL_RETURN; - return sg_count; + return count; +} + +static inline int sg_to_link_tbl(struct scatterlist *sg, int sg_count, + int cryptlen, + struct talitos_ptr *link_tbl_ptr) +{ + return sg_to_link_tbl_offset(sg, sg_count, 0, cryptlen, + link_tbl_ptr); } /* * fill in and submit ipsec_esp descriptor */ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, - u64 seq, void (*callback) (struct device *dev, - struct talitos_desc *desc, - void *context, int error)) + void (*callback)(struct device *dev, + struct talitos_desc *desc, + void *context, int error)) { struct crypto_aead *aead = crypto_aead_reqtfm(areq); + unsigned int authsize = crypto_aead_authsize(aead); struct talitos_ctx *ctx = crypto_aead_ctx(aead); struct device *dev = ctx->dev; struct talitos_desc *desc = &edesc->desc; unsigned int cryptlen = areq->cryptlen; - unsigned int authsize = ctx->authsize; unsigned int ivsize = crypto_aead_ivsize(aead); + int tbl_off = 0; int sg_count, ret; int sg_link_tbl_len; @@ -1113,36 +1109,27 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, map_single_talitos_ptr(dev, &desc->ptr[0], ctx->authkeylen, &ctx->key, DMA_TO_DEVICE); + sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ?: 1, + (areq->src == areq->dst) ? DMA_BIDIRECTIONAL + : DMA_TO_DEVICE, + edesc->src_chained); + /* hmac data */ - desc->ptr[1].len = cpu_to_be16(areq->assoclen + ivsize); - if (edesc->assoc_nents) { - int tbl_off = edesc->src_nents + edesc->dst_nents + 2; - struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off]; + desc->ptr[1].len = cpu_to_be16(areq->assoclen); + if (sg_count > 1 && + (ret = sg_to_link_tbl_offset(areq->src, sg_count, 0, + areq->assoclen, + &edesc->link_tbl[tbl_off])) > 1) { + tbl_off += ret; to_talitos_ptr(&desc->ptr[1], edesc->dma_link_tbl + tbl_off * sizeof(struct talitos_ptr), 0); desc->ptr[1].j_extent = DESC_PTR_LNKTBL_JUMP; - /* assoc_nents - 1 entries for assoc, 1 for IV */ - sg_count = sg_to_link_tbl(areq->assoc, edesc->assoc_nents - 1, - areq->assoclen, tbl_ptr); - - /* add IV to link table */ - tbl_ptr += sg_count - 1; - tbl_ptr->j_extent = 0; - tbl_ptr++; - to_talitos_ptr(tbl_ptr, edesc->iv_dma, 0); - tbl_ptr->len = cpu_to_be16(ivsize); - tbl_ptr->j_extent = DESC_PTR_LNKTBL_RETURN; - dma_sync_single_for_device(dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); } else { - if (areq->assoclen) - to_talitos_ptr(&desc->ptr[1], - sg_dma_address(areq->assoc), 0); - else - to_talitos_ptr(&desc->ptr[1], edesc->iv_dma, 0); + to_talitos_ptr(&desc->ptr[1], sg_dma_address(areq->src), 0); desc->ptr[1].j_extent = 0; } @@ -1150,8 +1137,6 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, to_talitos_ptr(&desc->ptr[2], edesc->iv_dma, 0); desc->ptr[2].len = cpu_to_be16(ivsize); desc->ptr[2].j_extent = 0; - /* Sync needed for the aead_givencrypt case */ - dma_sync_single_for_device(dev, edesc->iv_dma, ivsize, DMA_TO_DEVICE); /* cipher key */ map_single_talitos_ptr(dev, &desc->ptr[3], ctx->enckeylen, @@ -1167,33 +1152,24 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, desc->ptr[4].len = cpu_to_be16(cryptlen); desc->ptr[4].j_extent = authsize; - sg_count = talitos_map_sg(dev, areq->src, edesc->src_nents ? : 1, - (areq->src == areq->dst) ? DMA_BIDIRECTIONAL - : DMA_TO_DEVICE, - edesc->src_chained); - - if (sg_count == 1) { + sg_link_tbl_len = cryptlen; + if (edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV) + sg_link_tbl_len += authsize; + + if (sg_count > 1 && + (ret = sg_to_link_tbl_offset(areq->src, sg_count, areq->assoclen, + sg_link_tbl_len, + &edesc->link_tbl[tbl_off])) > 1) { + tbl_off += ret; + desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; + to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl + + tbl_off * + sizeof(struct talitos_ptr), 0); + dma_sync_single_for_device(dev, edesc->dma_link_tbl, + edesc->dma_len, + DMA_BIDIRECTIONAL); + } else to_talitos_ptr(&desc->ptr[4], sg_dma_address(areq->src), 0); - } else { - sg_link_tbl_len = cryptlen; - - if (edesc->desc.hdr & DESC_HDR_MODE1_MDEU_CICV) - sg_link_tbl_len = cryptlen + authsize; - - sg_count = sg_to_link_tbl(areq->src, sg_count, sg_link_tbl_len, - &edesc->link_tbl[0]); - if (sg_count > 1) { - desc->ptr[4].j_extent |= DESC_PTR_LNKTBL_JUMP; - to_talitos_ptr(&desc->ptr[4], edesc->dma_link_tbl, 0); - dma_sync_single_for_device(dev, edesc->dma_link_tbl, - edesc->dma_len, - DMA_BIDIRECTIONAL); - } else { - /* Only one segment now, so no link tbl needed */ - to_talitos_ptr(&desc->ptr[4], - sg_dma_address(areq->src), 0); - } - } /* cipher out */ desc->ptr[5].len = cpu_to_be16(cryptlen); @@ -1204,16 +1180,17 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, edesc->dst_nents ? : 1, DMA_FROM_DEVICE, edesc->dst_chained); - if (sg_count == 1) { - to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst), 0); - } else { - int tbl_off = edesc->src_nents + 1; + edesc->icv_ool = false; + + if (sg_count > 1 && + (sg_count = sg_to_link_tbl_offset(areq->dst, sg_count, + areq->assoclen, cryptlen, + &edesc->link_tbl[tbl_off])) > + 1) { struct talitos_ptr *tbl_ptr = &edesc->link_tbl[tbl_off]; to_talitos_ptr(&desc->ptr[5], edesc->dma_link_tbl + tbl_off * sizeof(struct talitos_ptr), 0); - sg_count = sg_to_link_tbl(areq->dst, sg_count, cryptlen, - tbl_ptr); /* Add an entry to the link table for ICV data */ tbl_ptr += sg_count - 1; @@ -1224,13 +1201,16 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq, /* icv data follows link tables */ to_talitos_ptr(tbl_ptr, edesc->dma_link_tbl + - (tbl_off + edesc->dst_nents + 1 + - edesc->assoc_nents) * - sizeof(struct talitos_ptr), 0); + (edesc->src_nents + edesc->dst_nents + + 2) * sizeof(struct talitos_ptr) + + authsize, 0); desc->ptr[5].j_extent |= DESC_PTR_LNKTBL_JUMP; dma_sync_single_for_device(ctx->dev, edesc->dma_link_tbl, edesc->dma_len, DMA_BIDIRECTIONAL); - } + + edesc->icv_ool = true; + } else + to_talitos_ptr(&desc->ptr[5], sg_dma_address(areq->dst), 0); /* iv out */ map_single_talitos_ptr(dev, &desc->ptr[6], ivsize, ctx->iv, @@ -1268,7 +1248,6 @@ static int sg_count(struct scatterlist *sg_list, int nbytes, bool *chained) * allocate and map the extended descriptor */ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, - struct scatterlist *assoc, struct scatterlist *src, struct scatterlist *dst, u8 *iv, @@ -1281,8 +1260,8 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, bool encrypt) { struct talitos_edesc *edesc; - int assoc_nents = 0, src_nents, dst_nents, alloc_len, dma_len; - bool assoc_chained = false, src_chained = false, dst_chained = false; + int src_nents, dst_nents, alloc_len, dma_len; + bool src_chained = false, dst_chained = false; dma_addr_t iv_dma = 0; gfp_t flags = cryptoflags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC; @@ -1298,48 +1277,35 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, if (ivsize) iv_dma = dma_map_single(dev, iv, ivsize, DMA_TO_DEVICE); - if (assoclen) { - /* - * Currently it is assumed that iv is provided whenever assoc - * is. - */ - BUG_ON(!iv); - - assoc_nents = sg_count(assoc, assoclen, &assoc_chained); - talitos_map_sg(dev, assoc, assoc_nents, DMA_TO_DEVICE, - assoc_chained); - assoc_nents = (assoc_nents == 1) ? 0 : assoc_nents; - - if (assoc_nents || sg_dma_address(assoc) + assoclen != iv_dma) - assoc_nents = assoc_nents ? assoc_nents + 1 : 2; - } - if (!dst || dst == src) { - src_nents = sg_count(src, cryptlen + authsize, &src_chained); + src_nents = sg_count(src, assoclen + cryptlen + authsize, + &src_chained); src_nents = (src_nents == 1) ? 0 : src_nents; dst_nents = dst ? src_nents : 0; } else { /* dst && dst != src*/ - src_nents = sg_count(src, cryptlen + (encrypt ? 0 : authsize), + src_nents = sg_count(src, assoclen + cryptlen + + (encrypt ? 0 : authsize), &src_chained); src_nents = (src_nents == 1) ? 0 : src_nents; - dst_nents = sg_count(dst, cryptlen + (encrypt ? authsize : 0), + dst_nents = sg_count(dst, assoclen + cryptlen + + (encrypt ? authsize : 0), &dst_chained); dst_nents = (dst_nents == 1) ? 0 : dst_nents; } /* * allocate space for base edesc plus the link tables, - * allowing for two separate entries for ICV and generated ICV (+ 2), - * and the ICV data itself + * allowing for two separate entries for AD and generated ICV (+ 2), + * and space for two sets of ICVs (stashed and generated) */ alloc_len = sizeof(struct talitos_edesc); - if (assoc_nents || src_nents || dst_nents) { + if (src_nents || dst_nents) { if (is_sec1) dma_len = (src_nents ? cryptlen : 0) + (dst_nents ? cryptlen : 0); else - dma_len = (src_nents + dst_nents + 2 + assoc_nents) * - sizeof(struct talitos_ptr) + authsize; + dma_len = (src_nents + dst_nents + 2) * + sizeof(struct talitos_ptr) + authsize * 2; alloc_len += dma_len; } else { dma_len = 0; @@ -1348,13 +1314,6 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, edesc = kmalloc(alloc_len, GFP_DMA | flags); if (!edesc) { - if (assoc_chained) - talitos_unmap_sg_chain(dev, assoc, DMA_TO_DEVICE); - else if (assoclen) - dma_unmap_sg(dev, assoc, - assoc_nents ? assoc_nents - 1 : 1, - DMA_TO_DEVICE); - if (iv_dma) dma_unmap_single(dev, iv_dma, ivsize, DMA_TO_DEVICE); @@ -1362,10 +1321,8 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev, return ERR_PTR(-ENOMEM); } - edesc->assoc_nents = assoc_nents; edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; - edesc->assoc_chained = assoc_chained; edesc->src_chained = src_chained; edesc->dst_chained = dst_chained; edesc->iv_dma = iv_dma; @@ -1382,12 +1339,13 @@ static struct talitos_edesc *aead_edesc_alloc(struct aead_request *areq, u8 *iv, int icv_stashing, bool encrypt) { struct crypto_aead *authenc = crypto_aead_reqtfm(areq); + unsigned int authsize = crypto_aead_authsize(authenc); struct talitos_ctx *ctx = crypto_aead_ctx(authenc); unsigned int ivsize = crypto_aead_ivsize(authenc); - return talitos_edesc_alloc(ctx->dev, areq->assoc, areq->src, areq->dst, + return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, iv, areq->assoclen, areq->cryptlen, - ctx->authsize, ivsize, icv_stashing, + authsize, ivsize, icv_stashing, areq->base.flags, encrypt); } @@ -1405,14 +1363,14 @@ static int aead_encrypt(struct aead_request *req) /* set encrypt */ edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT; - return ipsec_esp(edesc, req, 0, ipsec_esp_encrypt_done); + return ipsec_esp(edesc, req, ipsec_esp_encrypt_done); } static int aead_decrypt(struct aead_request *req) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); + unsigned int authsize = crypto_aead_authsize(authenc); struct talitos_ctx *ctx = crypto_aead_ctx(authenc); - unsigned int authsize = ctx->authsize; struct talitos_private *priv = dev_get_drvdata(ctx->dev); struct talitos_edesc *edesc; struct scatterlist *sg; @@ -1437,7 +1395,7 @@ static int aead_decrypt(struct aead_request *req) /* reset integrity check result bits */ edesc->desc.hdr_lo = 0; - return ipsec_esp(edesc, req, 0, ipsec_esp_decrypt_hwauth_done); + return ipsec_esp(edesc, req, ipsec_esp_decrypt_hwauth_done); } /* Have to check the ICV with software */ @@ -1445,40 +1403,16 @@ static int aead_decrypt(struct aead_request *req) /* stash incoming ICV for later cmp with ICV generated by the h/w */ if (edesc->dma_len) - icvdata = &edesc->link_tbl[edesc->src_nents + - edesc->dst_nents + 2 + - edesc->assoc_nents]; + icvdata = (char *)&edesc->link_tbl[edesc->src_nents + + edesc->dst_nents + 2]; else icvdata = &edesc->link_tbl[0]; sg = sg_last(req->src, edesc->src_nents ? : 1); - memcpy(icvdata, (char *)sg_virt(sg) + sg->length - ctx->authsize, - ctx->authsize); - - return ipsec_esp(edesc, req, 0, ipsec_esp_decrypt_swauth_done); -} - -static int aead_givencrypt(struct aead_givcrypt_request *req) -{ - struct aead_request *areq = &req->areq; - struct crypto_aead *authenc = crypto_aead_reqtfm(areq); - struct talitos_ctx *ctx = crypto_aead_ctx(authenc); - struct talitos_edesc *edesc; - - /* allocate extended descriptor */ - edesc = aead_edesc_alloc(areq, req->giv, 0, true); - if (IS_ERR(edesc)) - return PTR_ERR(edesc); + memcpy(icvdata, (char *)sg_virt(sg) + sg->length - authsize, authsize); - /* set encrypt */ - edesc->desc.hdr = ctx->desc_hdr_template | DESC_HDR_MODE0_ENCRYPT; - - memcpy(req->giv, ctx->iv, crypto_aead_ivsize(authenc)); - /* avoid consecutive packets going out with same IV */ - *(__be64 *)req->giv ^= cpu_to_be64(req->seq); - - return ipsec_esp(edesc, areq, req->seq, ipsec_esp_encrypt_done); + return ipsec_esp(edesc, req, ipsec_esp_decrypt_swauth_done); } static int ablkcipher_setkey(struct crypto_ablkcipher *cipher, @@ -1710,7 +1644,7 @@ static struct talitos_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request * struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher); unsigned int ivsize = crypto_ablkcipher_ivsize(cipher); - return talitos_edesc_alloc(ctx->dev, NULL, areq->src, areq->dst, + return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, areq->info, 0, areq->nbytes, 0, ivsize, 0, areq->base.flags, encrypt); } @@ -1895,7 +1829,7 @@ static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq, struct talitos_ctx *ctx = crypto_ahash_ctx(tfm); struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); - return talitos_edesc_alloc(ctx->dev, NULL, req_ctx->psrc, NULL, NULL, 0, + return talitos_edesc_alloc(ctx->dev, req_ctx->psrc, NULL, NULL, 0, nbytes, 0, 0, 0, areq->base.flags, false); } @@ -2161,6 +2095,7 @@ struct talitos_alg_template { union { struct crypto_alg crypto; struct ahash_alg hash; + struct aead_alg aead; } alg; __be32 desc_hdr_template; }; @@ -2168,15 +2103,16 @@ struct talitos_alg_template { static struct talitos_alg_template driver_algs[] = { /* AEAD algorithms. These use a single-pass ipsec_esp descriptor */ { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(sha1),cbc(aes))", - .cra_driver_name = "authenc-hmac-sha1-cbc-aes-talitos", - .cra_blocksize = AES_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha1),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha1-" + "cbc-aes-talitos", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_AESU | @@ -2187,15 +2123,17 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_SHA1_HMAC, }, { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(sha1),cbc(des3_ede))", - .cra_driver_name = "authenc-hmac-sha1-cbc-3des-talitos", - .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA1_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha1)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha1-" + "cbc-3des-talitos", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_DEU | @@ -2207,15 +2145,16 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_SHA1_HMAC, }, { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(sha224),cbc(aes))", - .cra_driver_name = "authenc-hmac-sha224-cbc-aes-talitos", - .cra_blocksize = AES_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA224_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha224),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha224-" + "cbc-aes-talitos", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_AESU | @@ -2226,15 +2165,17 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_SHA224_HMAC, }, { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(sha224),cbc(des3_ede))", - .cra_driver_name = "authenc-hmac-sha224-cbc-3des-talitos", - .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA224_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha224)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha224-" + "cbc-3des-talitos", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_DEU | @@ -2246,15 +2187,16 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_SHA224_HMAC, }, { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(sha256),cbc(aes))", - .cra_driver_name = "authenc-hmac-sha256-cbc-aes-talitos", - .cra_blocksize = AES_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha256),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha256-" + "cbc-aes-talitos", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_AESU | @@ -2265,15 +2207,17 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_SHA256_HMAC, }, { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(sha256),cbc(des3_ede))", - .cra_driver_name = "authenc-hmac-sha256-cbc-3des-talitos", - .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA256_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha256)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha256-" + "cbc-3des-talitos", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_DEU | @@ -2285,15 +2229,16 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_SHA256_HMAC, }, { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(sha384),cbc(aes))", - .cra_driver_name = "authenc-hmac-sha384-cbc-aes-talitos", - .cra_blocksize = AES_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA384_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha384),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha384-" + "cbc-aes-talitos", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_AESU | @@ -2304,15 +2249,17 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEUB_SHA384_HMAC, }, { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(sha384),cbc(des3_ede))", - .cra_driver_name = "authenc-hmac-sha384-cbc-3des-talitos", - .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA384_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha384)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha384-" + "cbc-3des-talitos", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_DEU | @@ -2324,15 +2271,16 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEUB_SHA384_HMAC, }, { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(sha512),cbc(aes))", - .cra_driver_name = "authenc-hmac-sha512-cbc-aes-talitos", - .cra_blocksize = AES_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA512_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha512),cbc(aes))", + .cra_driver_name = "authenc-hmac-sha512-" + "cbc-aes-talitos", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_AESU | @@ -2343,15 +2291,17 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEUB_SHA512_HMAC, }, { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(sha512),cbc(des3_ede))", - .cra_driver_name = "authenc-hmac-sha512-cbc-3des-talitos", - .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA512_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha512)," + "cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-sha512-" + "cbc-3des-talitos", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_DEU | @@ -2363,15 +2313,16 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEUB_SHA512_HMAC, }, { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(md5),cbc(aes))", - .cra_driver_name = "authenc-hmac-md5-cbc-aes-talitos", - .cra_blocksize = AES_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(md5),cbc(aes))", + .cra_driver_name = "authenc-hmac-md5-" + "cbc-aes-talitos", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_AESU | @@ -2382,15 +2333,16 @@ static struct talitos_alg_template driver_algs[] = { DESC_HDR_MODE1_MDEU_MD5_HMAC, }, { .type = CRYPTO_ALG_TYPE_AEAD, - .alg.crypto = { - .cra_name = "authenc(hmac(md5),cbc(des3_ede))", - .cra_driver_name = "authenc-hmac-md5-cbc-3des-talitos", - .cra_blocksize = DES3_EDE_BLOCK_SIZE, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, - .cra_aead = { - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = MD5_DIGEST_SIZE, - } + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(md5),cbc(des3_ede))", + .cra_driver_name = "authenc-hmac-md5-" + "cbc-3des-talitos", + .cra_blocksize = DES3_EDE_BLOCK_SIZE, + .cra_flags = CRYPTO_ALG_ASYNC, + }, + .ivsize = DES3_EDE_BLOCK_SIZE, + .maxauthsize = MD5_DIGEST_SIZE, }, .desc_hdr_template = DESC_HDR_TYPE_IPSEC_ESP | DESC_HDR_SEL0_DEU | @@ -2658,15 +2610,9 @@ static int talitos_cra_init(struct crypto_tfm *tfm) return 0; } -static int talitos_cra_init_aead(struct crypto_tfm *tfm) +static int talitos_cra_init_aead(struct crypto_aead *tfm) { - struct talitos_ctx *ctx = crypto_tfm_ctx(tfm); - - talitos_cra_init(tfm); - - /* random first IV */ - get_random_bytes(ctx->iv, TALITOS_MAX_IV_LENGTH); - + talitos_cra_init(crypto_aead_tfm(tfm)); return 0; } @@ -2713,9 +2659,9 @@ static int talitos_remove(struct platform_device *ofdev) list_for_each_entry_safe(t_alg, n, &priv->alg_list, entry) { switch (t_alg->algt.type) { case CRYPTO_ALG_TYPE_ABLKCIPHER: - case CRYPTO_ALG_TYPE_AEAD: - crypto_unregister_alg(&t_alg->algt.alg.crypto); break; + case CRYPTO_ALG_TYPE_AEAD: + crypto_unregister_aead(&t_alg->algt.alg.aead); case CRYPTO_ALG_TYPE_AHASH: crypto_unregister_ahash(&t_alg->algt.alg.hash); break; @@ -2774,15 +2720,12 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, alg->cra_ablkcipher.geniv = "eseqiv"; break; case CRYPTO_ALG_TYPE_AEAD: - alg = &t_alg->algt.alg.crypto; - alg->cra_init = talitos_cra_init_aead; - alg->cra_type = &crypto_aead_type; - alg->cra_aead.setkey = aead_setkey; - alg->cra_aead.setauthsize = aead_setauthsize; - alg->cra_aead.encrypt = aead_encrypt; - alg->cra_aead.decrypt = aead_decrypt; - alg->cra_aead.givencrypt = aead_givencrypt; - alg->cra_aead.geniv = ""; + alg = &t_alg->algt.alg.aead.base; + alg->cra_flags |= CRYPTO_ALG_AEAD_NEW; + t_alg->algt.alg.aead.init = talitos_cra_init_aead; + t_alg->algt.alg.aead.setkey = aead_setkey; + t_alg->algt.alg.aead.encrypt = aead_encrypt; + t_alg->algt.alg.aead.decrypt = aead_decrypt; break; case CRYPTO_ALG_TYPE_AHASH: alg = &t_alg->algt.alg.hash.halg.base; @@ -3041,7 +2984,7 @@ static int talitos_probe(struct platform_device *ofdev) for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { if (hw_supports(dev, driver_algs[i].desc_hdr_template)) { struct talitos_crypto_alg *t_alg; - char *name = NULL; + struct crypto_alg *alg = NULL; t_alg = talitos_alg_alloc(dev, &driver_algs[i]); if (IS_ERR(t_alg)) { @@ -3053,21 +2996,26 @@ static int talitos_probe(struct platform_device *ofdev) switch (t_alg->algt.type) { case CRYPTO_ALG_TYPE_ABLKCIPHER: - case CRYPTO_ALG_TYPE_AEAD: err = crypto_register_alg( &t_alg->algt.alg.crypto); - name = t_alg->algt.alg.crypto.cra_driver_name; + alg = &t_alg->algt.alg.crypto; break; + + case CRYPTO_ALG_TYPE_AEAD: + err = crypto_register_aead( + &t_alg->algt.alg.aead); + alg = &t_alg->algt.alg.aead.base; + break; + case CRYPTO_ALG_TYPE_AHASH: err = crypto_register_ahash( &t_alg->algt.alg.hash); - name = - t_alg->algt.alg.hash.halg.base.cra_driver_name; + alg = &t_alg->algt.alg.hash.halg.base; break; } if (err) { dev_err(dev, "%s alg registration failed\n", - name); + alg->cra_driver_name); kfree(t_alg); } else list_add_tail(&t_alg->entry, &priv->alg_list); -- cgit v1.3-6-gb490 From 8dc8641e619228153ab0bc609f9f534126e87c08 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 3 Aug 2015 10:17:03 -0700 Subject: HID: wacom: Use calculated pkglen for wireless touch interface Commit 01c846f introduced the 'wacom_compute_pktlen' function which automatically determines the correct value for an interface's pkglen by scanning the HID descriptor. This function returns the correct value for the wireless receiver's touch interface, removing the need for us to set it manually here. Signed-off-by: Jason Gerecke Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index d932349277cd..a334332fbb8f 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -457,7 +457,6 @@ static void wacom_retrieve_hid_descriptor(struct hid_device *hdev, features->device_type = WACOM_DEVICETYPE_NONE; } else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) { features->device_type |= WACOM_DEVICETYPE_TOUCH; - features->pktlen = WACOM_PKGLEN_BBTOUCH3; } } -- cgit v1.3-6-gb490 From ccad85cc1ee34509840e5af80a436ceaf0b71edb Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 3 Aug 2015 10:17:04 -0700 Subject: HID: wacom: Replace WACOM_QUIRK_MONITOR with WACOM_DEVICETYPE_WL_MONITOR The monitor interface on the wireless receiver is more logically expressed as a type of device instead of a quirk. Signed-off-by: Jason Gerecke Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 6 +++--- drivers/hid/wacom_wac.c | 4 +--- drivers/hid/wacom_wac.h | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index a334332fbb8f..13834bae227c 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -454,7 +454,7 @@ static void wacom_retrieve_hid_descriptor(struct hid_device *hdev, */ if (features->type == WIRELESS) { if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { - features->device_type = WACOM_DEVICETYPE_NONE; + features->device_type = WACOM_DEVICETYPE_WL_MONITOR; } else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) { features->device_type |= WACOM_DEVICETYPE_TOUCH; } @@ -1581,7 +1581,7 @@ static int wacom_probe(struct hid_device *hdev, if (error) goto fail_shared_data; - if (!(features->quirks & WACOM_QUIRK_MONITOR) && + if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) && (features->quirks & WACOM_QUIRK_BATTERY)) { error = wacom_initialize_battery(wacom); if (error) @@ -1615,7 +1615,7 @@ static int wacom_probe(struct hid_device *hdev, /* Note that if query fails it is not a hard failure */ wacom_query_tablet_data(hdev, features); - if (features->quirks & WACOM_QUIRK_MONITOR) + if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) error = hid_hw_open(hdev); if (wacom_wac->features.type == INTUOSHT && diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 280deb293ae2..82bb0d38fc8d 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2330,9 +2330,7 @@ void wacom_setup_device_quirks(struct wacom *wacom) /* monitor never has input and pen/touch have delayed create */ features->quirks |= WACOM_QUIRK_NO_INPUT; - /* must be monitor interface if no device_type set */ - if (features->device_type == WACOM_DEVICETYPE_NONE) { - features->quirks |= WACOM_QUIRK_MONITOR; + if (features->device_type == WACOM_DEVICETYPE_WL_MONITOR) { features->quirks |= WACOM_QUIRK_BATTERY; } } diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index c245a6628224..87df674e210c 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -69,7 +69,6 @@ /* device quirks */ #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001 #define WACOM_QUIRK_NO_INPUT 0x0002 -#define WACOM_QUIRK_MONITOR 0x0004 #define WACOM_QUIRK_BATTERY 0x0008 /* device types */ @@ -77,6 +76,7 @@ #define WACOM_DEVICETYPE_PEN 0x0001 #define WACOM_DEVICETYPE_TOUCH 0x0002 #define WACOM_DEVICETYPE_PAD 0x0004 +#define WACOM_DEVICETYPE_WL_MONITOR 0x0008 #define WACOM_VENDORDEFINED_PEN 0xff0d0001 -- cgit v1.3-6-gb490 From 3f14a63a544374225c17221a5058748360428dc3 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 3 Aug 2015 10:17:05 -0700 Subject: HID: wacom: Remove WACOM_QUIRK_NO_INPUT WACOM_QUIRK_NO_INPUT is a signal to the driver that input devices should not be created for a particular device. This quirk was used by the wireless receiver to prevent any devices from being created during the initial probe (defering it instead until we got a tablet connection event in 'wacom_wireless_work'). This quirk is not necessary now that a device_type is associated with each device. Any input device allocated by 'wacom_allocate_inputs' which is not necessary for a particular device is freed in 'wacom_register_inputs'. In particular, none of the wireless receivers devices have the pen, pad, or touch device types set so the same effect is achieved without the need to be explicit. We now return early in wacom_retrieve_hid_descriptor for wireless devices (to prevent the device_type from being overridden) but since we ignore the HID descriptor for the wireless reciever anyway, this is not an issue. Signed-off-by: Jason Gerecke Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 24 ++++++++++-------------- drivers/hid/wacom_wac.c | 4 ---- drivers/hid/wacom_wac.h | 1 - 3 files changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 13834bae227c..20d15c5fccec 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -453,11 +453,11 @@ static void wacom_retrieve_hid_descriptor(struct hid_device *hdev, * interface number. */ if (features->type == WIRELESS) { - if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { + if (intf->cur_altsetting->desc.bInterfaceNumber == 0) features->device_type = WACOM_DEVICETYPE_WL_MONITOR; - } else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) { - features->device_type |= WACOM_DEVICETYPE_TOUCH; - } + else + features->device_type = WACOM_DEVICETYPE_NONE; + return; } wacom_parse_hid(hdev, features); @@ -1531,11 +1531,9 @@ static int wacom_probe(struct hid_device *hdev, mutex_init(&wacom->lock); INIT_WORK(&wacom->work, wacom_wireless_work); - if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) { - error = wacom_allocate_inputs(wacom); - if (error) - goto fail_allocate_inputs; - } + error = wacom_allocate_inputs(wacom); + if (error) + goto fail_allocate_inputs; /* * Bamboo Pad has a generic hid handling for the Pen, and we switch it @@ -1588,11 +1586,9 @@ static int wacom_probe(struct hid_device *hdev, goto fail_battery; } - if (!(features->quirks & WACOM_QUIRK_NO_INPUT)) { - error = wacom_register_inputs(wacom); - if (error) - goto fail_register_inputs; - } + error = wacom_register_inputs(wacom); + if (error) + goto fail_register_inputs; if (hdev->bus == BUS_BLUETOOTH) { error = device_create_file(&hdev->dev, &dev_attr_speed); diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 82bb0d38fc8d..4d11c7857e70 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2326,10 +2326,6 @@ void wacom_setup_device_quirks(struct wacom *wacom) } if (features->type == WIRELESS) { - - /* monitor never has input and pen/touch have delayed create */ - features->quirks |= WACOM_QUIRK_NO_INPUT; - if (features->device_type == WACOM_DEVICETYPE_WL_MONITOR) { features->quirks |= WACOM_QUIRK_BATTERY; } diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 87df674e210c..6233eeab028d 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -68,7 +68,6 @@ /* device quirks */ #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001 -#define WACOM_QUIRK_NO_INPUT 0x0002 #define WACOM_QUIRK_BATTERY 0x0008 /* device types */ -- cgit v1.3-6-gb490 From fedf42b50d51758ce43fe0a652991dc01421f422 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Thu, 30 Jul 2015 18:13:56 -0700 Subject: reset: reset-zynq: Adding support for Xilinx Zynq reset controller. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a reset controller driver to control the Xilinx Zynq AP-SoC's various resets. Signed-off-by: Moritz Fischer Reviewed-by: Michal Simek Acked-by: Sören Brinkmann Signed-off-by: Philipp Zabel --- drivers/reset/Makefile | 1 + drivers/reset/reset-zynq.c | 155 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 drivers/reset/reset-zynq.c (limited to 'drivers') diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 1d41feeb2dce..ab06aa01cfc7 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o obj-$(CONFIG_ARCH_STI) += sti/ +obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o diff --git a/drivers/reset/reset-zynq.c b/drivers/reset/reset-zynq.c new file mode 100644 index 000000000000..89318a5d5bd7 --- /dev/null +++ b/drivers/reset/reset-zynq.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015, National Instruments Corp. + * + * Xilinx Zynq Reset controller driver + * + * 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 +#include +#include +#include +#include +#include +#include + +struct zynq_reset_data { + struct regmap *slcr; + struct reset_controller_dev rcdev; + u32 offset; +}; + +#define to_zynq_reset_data(p) \ + container_of((p), struct zynq_reset_data, rcdev) + +static int zynq_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct zynq_reset_data *priv = to_zynq_reset_data(rcdev); + + int bank = id / BITS_PER_LONG; + int offset = id % BITS_PER_LONG; + + pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__, + bank, offset); + + return regmap_update_bits(priv->slcr, + priv->offset + (bank * 4), + BIT(offset), + BIT(offset)); +} + +static int zynq_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct zynq_reset_data *priv = to_zynq_reset_data(rcdev); + + int bank = id / BITS_PER_LONG; + int offset = id % BITS_PER_LONG; + + pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__, + bank, offset); + + return regmap_update_bits(priv->slcr, + priv->offset + (bank * 4), + BIT(offset), + ~BIT(offset)); +} + +static int zynq_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct zynq_reset_data *priv = to_zynq_reset_data(rcdev); + + int bank = id / BITS_PER_LONG; + int offset = id % BITS_PER_LONG; + int ret; + u32 reg; + + pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__, + bank, offset); + + ret = regmap_read(priv->slcr, priv->offset + (bank * 4), ®); + if (ret) + return ret; + + return !!(reg & BIT(offset)); +} + +static struct reset_control_ops zynq_reset_ops = { + .assert = zynq_reset_assert, + .deassert = zynq_reset_deassert, + .status = zynq_reset_status, +}; + +static int zynq_reset_probe(struct platform_device *pdev) +{ + struct resource *res; + struct zynq_reset_data *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + platform_set_drvdata(pdev, priv); + + priv->slcr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "syscon"); + if (IS_ERR(priv->slcr)) { + dev_err(&pdev->dev, "unable to get zynq-slcr regmap"); + return PTR_ERR(priv->slcr); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "missing IO resource\n"); + return -ENODEV; + } + + priv->offset = res->start; + + priv->rcdev.owner = THIS_MODULE; + priv->rcdev.nr_resets = resource_size(res) / 4 * BITS_PER_LONG; + priv->rcdev.ops = &zynq_reset_ops; + priv->rcdev.of_node = pdev->dev.of_node; + reset_controller_register(&priv->rcdev); + + return 0; +} + +static int zynq_reset_remove(struct platform_device *pdev) +{ + struct zynq_reset_data *priv = platform_get_drvdata(pdev); + + reset_controller_unregister(&priv->rcdev); + + return 0; +} + +static const struct of_device_id zynq_reset_dt_ids[] = { + { .compatible = "xlnx,zynq-reset", }, + { /* sentinel */ }, +}; + +static struct platform_driver zynq_reset_driver = { + .probe = zynq_reset_probe, + .remove = zynq_reset_remove, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = zynq_reset_dt_ids, + }, +}; +module_platform_driver(zynq_reset_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Moritz Fischer "); +MODULE_DESCRIPTION("Zynq Reset Controller Driver"); -- cgit v1.3-6-gb490 From 4b68b50fd45e2f429da574c74d9a3788a861434f Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:01:31 +0000 Subject: usb: phy: phy-mxs-usb: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-mxs-usb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 3fcc0483a081..4d863ebc117c 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -506,11 +506,7 @@ static int mxs_phy_probe(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, true); - ret = usb_add_phy_dev(&mxs_phy->phy); - if (ret) - return ret; - - return 0; + return usb_add_phy_dev(&mxs_phy->phy); } static int mxs_phy_remove(struct platform_device *pdev) -- cgit v1.3-6-gb490 From c5673f5ce4c0faa97df419877bcdebbd76d43151 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:02:03 +0000 Subject: usb: phy: phy-keystone: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-keystone.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index e0556f7832b5..01d4e4cdbc79 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -96,11 +96,7 @@ static int keystone_usbphy_probe(struct platform_device *pdev) platform_set_drvdata(pdev, k_phy); - ret = usb_add_phy_dev(&k_phy->usb_phy_gen.phy); - if (ret) - return ret; - - return 0; + return usb_add_phy_dev(&k_phy->usb_phy_gen.phy); } static int keystone_usbphy_remove(struct platform_device *pdev) -- cgit v1.3-6-gb490 From 7f352964852ede9e95d18fd3825c5200fb48b3a5 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:02:28 +0000 Subject: usb: musb: musb_dsps: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 1334a3de31b8..a0cfead6150f 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -482,11 +482,7 @@ static int dsps_musb_init(struct musb *musb) dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val); } - ret = dsps_musb_dbg_init(musb, glue); - if (ret) - return ret; - - return 0; + return dsps_musb_dbg_init(musb, glue); } static int dsps_musb_exit(struct musb *musb) -- cgit v1.3-6-gb490 From 0f4315a8f1a73f130bbc5dde134b704ea6dda56c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 4 Aug 2015 11:02:45 -0500 Subject: usb: gadget: f_uac2: fix build warning commit 913e4a90b6f9 ("usb: gadget: f_uac2: finalize wMaxPacketSize according to bandwidth") added a possible build warning when calling min(). In order to fix the warning, we just make sure to call min_t() and tell that its arguments should be u16. Cc: Peter Chen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_uac2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index b5680246d6aa..c35a2a1157d5 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -994,7 +994,7 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, max_packet_size = num_channels(chmask) * ssize * DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1))); - ep_desc->wMaxPacketSize = cpu_to_le16(min(max_packet_size, + ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_packet_size, le16_to_cpu(ep_desc->wMaxPacketSize))); } -- cgit v1.3-6-gb490 From 89a6356676eba38e498507b5b67dcc07a714a149 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 31 Jul 2015 13:42:29 +0100 Subject: spi: spidev: fix inconsistent indenting Fix inconsistent indenting in spidev_open, no functional change. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 9d8841efffd8..029463ada19c 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -602,11 +602,11 @@ static int spidev_open(struct inode *inode, struct file *filp) if (!spidev->tx_buffer) { spidev->tx_buffer = kmalloc(bufsiz, GFP_KERNEL); if (!spidev->tx_buffer) { - dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); - status = -ENOMEM; + dev_dbg(&spidev->spi->dev, "open/ENOMEM\n"); + status = -ENOMEM; goto err_find_dev; - } } + } if (!spidev->rx_buffer) { spidev->rx_buffer = kmalloc(bufsiz, GFP_KERNEL); -- cgit v1.3-6-gb490 From 94e5c23d3c52f58f4051810a15aeacc085127ad1 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 4 Aug 2015 13:52:22 +0800 Subject: spi: pxa2xx: Add terminating entry for pxa2xx_spi_pci_compound_match Signed-off-by: Axel Lin Acked-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index e924710e126c..246ffabc72c9 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1300,6 +1300,7 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { /* SPT-H */ { PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP }, { PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP }, + { }, }; static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param) -- cgit v1.3-6-gb490 From cc476b42a39d5a66d94f46cade972dcb8ee278df Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:13 +0200 Subject: usb: gadget: encapsulate endpoint claiming mechanism So far it was necessary for usb functions to set ep->driver_data in endpoint obtained from autoconfig to non-null value, to indicate that endpoint is claimed by function (in autoconfig it was checked if endpoint has set this field to non-null value, and if it has, it was assumed that it is claimed). It could cause bugs because if some function doesn't set this field autoconfig could return the same endpoint more than one time. To help to avoid such bugs this patch adds claimed flag to struct usb_ep, and encapsulates endpoint claiming mechanism inside usb_ep_autoconfig_ss() and usb_ep_autoconfig_reset(), so now usb functions don't need to perform any additional actions to mark endpoint obtained from autoconfig as claimed. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 11 ++++++----- include/linux/usb/gadget.h | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 919cdfdda78b..8e00ca765549 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -53,7 +53,7 @@ ep_matches ( int num_req_streams = 0; /* endpoint already claimed? */ - if (NULL != ep->driver_data) + if (ep->claimed) return 0; /* only support ep0 for portable CONTROL traffic */ @@ -240,7 +240,7 @@ find_ep (struct usb_gadget *gadget, const char *name) * updated with the assigned number of streams if it is * different from the original value. To prevent the endpoint * from being returned by a later autoconfig call, claim it by - * assigning ep->driver_data to some non-null value. + * assigning ep->claimed to true. * * On failure, this returns a null endpoint descriptor. */ @@ -323,6 +323,7 @@ struct usb_ep *usb_ep_autoconfig_ss( found_ep: ep->desc = NULL; ep->comp_desc = NULL; + ep->claimed = true; return ep; } EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss); @@ -354,7 +355,7 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss); * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value * is initialized as if the endpoint were used at full speed. To prevent * the endpoint from being returned by a later autoconfig call, claim it - * by assigning ep->driver_data to some non-null value. + * by assigning ep->claimed to true. * * On failure, this returns a null endpoint descriptor. */ @@ -373,7 +374,7 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig); * * Use this for devices where one configuration may need to assign * endpoint resources very differently from the next one. It clears - * state such as ep->driver_data and the record of assigned endpoints + * state such as ep->claimed and the record of assigned endpoints * used by usb_ep_autoconfig(). */ void usb_ep_autoconfig_reset (struct usb_gadget *gadget) @@ -381,7 +382,7 @@ void usb_ep_autoconfig_reset (struct usb_gadget *gadget) struct usb_ep *ep; list_for_each_entry (ep, &gadget->ep_list, ep_list) { - ep->driver_data = NULL; + ep->claimed = false; } gadget->in_epnum = 0; gadget->out_epnum = 0; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 353a72096dda..68fb5e8b18c3 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -173,6 +173,7 @@ struct usb_ep { const char *name; const struct usb_ep_ops *ops; struct list_head ep_list; + bool claimed; unsigned maxpacket:16; unsigned maxpacket_limit:16; unsigned max_streams:16; -- cgit v1.3-6-gb490 From 68b5c947515a252b9e416e419fca4c1382912948 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:16 +0200 Subject: staging: emxx_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Fixed typo in "epc-nulk" to "epc-bulk". Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/staging/emxx_udc/emxx_udc.c | 73 +++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c index 3b7aa36b0486..b6b76ff09657 100644 --- a/drivers/staging/emxx_udc/emxx_udc.c +++ b/drivers/staging/emxx_udc/emxx_udc.c @@ -3153,36 +3153,46 @@ static const struct usb_gadget_ops nbu2ss_gadget_ops = { .ioctl = nbu2ss_gad_ioctl, }; -static const char g_ep0_name[] = "ep0"; -static const char g_ep1_name[] = "ep1-bulk"; -static const char g_ep2_name[] = "ep2-bulk"; -static const char g_ep3_name[] = "ep3in-int"; -static const char g_ep4_name[] = "ep4-iso"; -static const char g_ep5_name[] = "ep5-iso"; -static const char g_ep6_name[] = "ep6-bulk"; -static const char g_ep7_name[] = "ep7-bulk"; -static const char g_ep8_name[] = "ep8in-int"; -static const char g_ep9_name[] = "ep9-iso"; -static const char g_epa_name[] = "epa-iso"; -static const char g_epb_name[] = "epb-bulk"; -static const char g_epc_name[] = "epc-nulk"; -static const char g_epd_name[] = "epdin-int"; - -static const char *gp_ep_name[NUM_ENDPOINTS] = { - g_ep0_name, - g_ep1_name, - g_ep2_name, - g_ep3_name, - g_ep4_name, - g_ep5_name, - g_ep6_name, - g_ep7_name, - g_ep8_name, - g_ep9_name, - g_epa_name, - g_epb_name, - g_epc_name, - g_epd_name, +static const struct { + const char *name; + const struct usb_ep_caps caps; +} ep_info[NUM_ENDPOINTS] = { +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + + EP_INFO("ep0", + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep1-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep2-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep3in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep4-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep5-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep6-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep7-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep8in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep9-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)), + EP_INFO("epa-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)), + EP_INFO("epb-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("epc-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)), + EP_INFO("epdin-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + +#undef EP_INFO }; /*-------------------------------------------------------------------------*/ @@ -3200,7 +3210,8 @@ static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc) ep->desc = NULL; ep->ep.driver_data = NULL; - ep->ep.name = gp_ep_name[i]; + ep->ep.name = ep_info[i].name; + ep->ep.caps = ep_info[i].caps; ep->ep.ops = &nbu2ss_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, -- cgit v1.3-6-gb490 From a7e3f1410855db6b67ec29a386e74be2df3cc311 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:17 +0200 Subject: usb: chipidea: udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/chipidea/udc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index f5fbe78e8e6a..c592b6f0fe21 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1624,6 +1624,20 @@ static int init_eps(struct ci_hdrc *ci) hwep->ep.name = hwep->name; hwep->ep.ops = &usb_ep_ops; + + if (i == 0) { + hwep->ep.caps.type_control = true; + } else { + hwep->ep.caps.type_iso = true; + hwep->ep.caps.type_bulk = true; + hwep->ep.caps.type_int = true; + } + + if (j == TX) + hwep->ep.caps.dir_in = true; + else + hwep->ep.caps.dir_out = true; + /* * for ep0: maxP defined in desc, for other * eps, maxP is set by epautoconfig() called -- cgit v1.3-6-gb490 From 2954522f135246287c36524bc96e9dae8c40f8a9 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:18 +0200 Subject: usb: dwc2: gadget: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 731b13dfc512..3ee5b4c77a1f 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3289,6 +3289,19 @@ static void s3c_hsotg_initep(struct dwc2_hsotg *hsotg, usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT); hs_ep->ep.ops = &s3c_hsotg_ep_ops; + if (epnum == 0) { + hs_ep->ep.caps.type_control = true; + } else { + hs_ep->ep.caps.type_iso = true; + hs_ep->ep.caps.type_bulk = true; + hs_ep->ep.caps.type_int = true; + } + + if (dir_in) + hs_ep->ep.caps.dir_in = true; + else + hs_ep->ep.caps.dir_out = true; + /* * if we're using dma, we need to set the next-endpoint pointer * to be something valid. -- cgit v1.3-6-gb490 From a474d3b73ba7f22844e672ac004f01cd9b8be159 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:19 +0200 Subject: usb: dwc3: gadget: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2feed9e03583..0c25704dcb6b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1715,6 +1715,17 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, return ret; } + if (epnum == 0 || epnum == 1) { + dep->endpoint.caps.type_control = true; + } else { + dep->endpoint.caps.type_iso = true; + dep->endpoint.caps.type_bulk = true; + dep->endpoint.caps.type_int = true; + } + + dep->endpoint.caps.dir_in = !!direction; + dep->endpoint.caps.dir_out = !direction; + INIT_LIST_HEAD(&dep->request_list); INIT_LIST_HEAD(&dep->req_queued); } -- cgit v1.3-6-gb490 From 6f02ac5ac9bba538593e4359dd5e83c4d42822fe Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:20 +0200 Subject: usb: gadget: amd5536udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/amd5536udc.c | 88 ++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/amd5536udc.c b/drivers/usb/gadget/udc/amd5536udc.c index de7e5e2ccf1c..fdacddb18c00 100644 --- a/drivers/usb/gadget/udc/amd5536udc.c +++ b/drivers/usb/gadget/udc/amd5536udc.c @@ -138,15 +138,82 @@ static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect, /* endpoint names used for print */ static const char ep0_string[] = "ep0in"; -static const char *const ep_string[] = { - ep0_string, - "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk", - "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk", - "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk", - "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk", - "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk", - "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk", - "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk" +static const struct { + const char *name; + const struct usb_ep_caps caps; +} ep_info[] = { +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + + EP_INFO(ep0_string, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep1in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep2in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep3in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep4in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep5in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep6in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep7in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep8in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep9in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep10in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep11in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep12in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep13in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep14in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep15in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep0out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep1out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep2out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep3out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep4out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep5out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep6out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep7out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep8out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep9out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep10out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep11out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep12out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep13out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep14out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep15out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + +#undef EP_INFO }; /* DMA usage flag */ @@ -1517,7 +1584,8 @@ static void udc_setup_endpoints(struct udc *dev) for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { ep = &dev->ep[tmp]; ep->dev = dev; - ep->ep.name = ep_string[tmp]; + ep->ep.name = ep_info[tmp].name; + ep->ep.caps = ep_info[tmp].caps; ep->num = tmp; /* txfifo size is calculated at enable time */ ep->txfifo = dev->txfifo; -- cgit v1.3-6-gb490 From b9ed96d7d579416a8fd2e1cef66541bfdad2720f Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:21 +0200 Subject: usb: gadget: at91_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/at91_udc.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index 32f50a7944dd..d0d18947f58b 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -59,15 +59,34 @@ #define DRIVER_VERSION "3 May 2006" static const char driver_name [] = "at91_udc"; -static const char * const ep_names[] = { - "ep0", - "ep1", - "ep2", - "ep3-int", - "ep4", - "ep5", + +static const struct { + const char *name; + const struct usb_ep_caps caps; +} ep_info[] = { +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + + EP_INFO("ep0", + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep1", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep2", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep3-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep4", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep5", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + +#undef EP_INFO }; -#define ep0name ep_names[0] + +#define ep0name ep_info[0].name #define VBUS_POLL_TIMEOUT msecs_to_jiffies(1000) @@ -1831,7 +1850,8 @@ static int at91udc_probe(struct platform_device *pdev) for (i = 0; i < NUM_ENDPOINTS; i++) { ep = &udc->ep[i]; - ep->ep.name = ep_names[i]; + ep->ep.name = ep_info[i].name; + ep->ep.caps = ep_info[i].caps; ep->ep.ops = &at91_ep_ops; ep->udc = udc; ep->int_mask = BIT(i); -- cgit v1.3-6-gb490 From 1b0ba527702268992a62227dde4911477f057ca5 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:22 +0200 Subject: usb: gadget: bcm63xx_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/bcm63xx_udc.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index 9db968ba39f5..8cbb00325824 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -44,9 +44,29 @@ #define DRV_MODULE_NAME "bcm63xx_udc" static const char bcm63xx_ep0name[] = "ep0"; -static const char *const bcm63xx_ep_name[] = { - bcm63xx_ep0name, - "ep1in-bulk", "ep2out-bulk", "ep3in-int", "ep4out-int", + +static const struct { + const char *name; + const struct usb_ep_caps caps; +} bcm63xx_ep_info[] = { +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + + EP_INFO(bcm63xx_ep0name, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep1in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep2out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep3in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep4out-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_OUT)), + +#undef EP_INFO }; static bool use_fullspeed; @@ -943,7 +963,8 @@ static int bcm63xx_init_udc_hw(struct bcm63xx_udc *udc) for (i = 0; i < BCM63XX_NUM_EP; i++) { struct bcm63xx_ep *bep = &udc->bep[i]; - bep->ep.name = bcm63xx_ep_name[i]; + bep->ep.name = bcm63xx_ep_info[i].name; + bep->ep.caps = bcm63xx_ep_info[i].caps; bep->ep_num = i; bep->ep.ops = &bcm63xx_udc_ep_ops; list_add_tail(&bep->ep.ep_list, &udc->gadget.ep_list); -- cgit v1.3-6-gb490 From b079dd6156a6544e0383642a9ec97d17485aa244 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:23 +0200 Subject: usb: gadget: bdc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/bdc/bdc_ep.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index b04980cf6dc4..f9a8f57620e2 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -1952,12 +1952,18 @@ static int init_ep(struct bdc *bdc, u32 epnum, u32 dir) ep->bdc = bdc; ep->dir = dir; + if (dir) + ep->usb_ep.caps.dir_in = true; + else + ep->usb_ep.caps.dir_out = true; + /* ep->ep_num is the index inside bdc_ep */ if (epnum == 1) { ep->ep_num = 1; bdc->bdc_ep_array[ep->ep_num] = ep; snprintf(ep->name, sizeof(ep->name), "ep%d", epnum - 1); usb_ep_set_maxpacket_limit(&ep->usb_ep, EP0_MAX_PKT_SIZE); + ep->usb_ep.caps.type_control = true; ep->comp_desc = NULL; bdc->gadget.ep0 = &ep->usb_ep; } else { @@ -1971,6 +1977,9 @@ static int init_ep(struct bdc *bdc, u32 epnum, u32 dir) dir & 1 ? "in" : "out"); usb_ep_set_maxpacket_limit(&ep->usb_ep, 1024); + ep->usb_ep.caps.type_iso = true; + ep->usb_ep.caps.type_bulk = true; + ep->usb_ep.caps.type_int = true; ep->usb_ep.max_streams = 0; list_add_tail(&ep->usb_ep.ep_list, &bdc->gadget.ep_list); } -- cgit v1.3-6-gb490 From 7a3b8e7098946b44c014f3df0ceef27fb273c142 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:24 +0200 Subject: usb: gadget: dummy-hcd: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/dummy_hcd.c | 95 ++++++++++++++++++++++++++++++++------ 1 file changed, 80 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 181112c88f43..1379ad40d864 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -127,23 +127,87 @@ static inline struct dummy_request *usb_request_to_dummy_request static const char ep0name[] = "ep0"; -static const char *const ep_name[] = { - ep0name, /* everyone has ep0 */ +static const struct { + const char *name; + const struct usb_ep_caps caps; +} ep_info[] = { +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + /* everyone has ep0 */ + EP_INFO(ep0name, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), /* act like a pxa250: fifteen fixed function endpoints */ - "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", - "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", - "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", - "ep15in-int", - + EP_INFO("ep1in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep2out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep3in-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep4out-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep5in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep6in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep7out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep8in-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep9out-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep10in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep11in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep12out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep13in-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep14out-iso", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep15in-int", + USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)), /* or like sa1100: two fixed function endpoints */ - "ep1out-bulk", "ep2in-bulk", - + EP_INFO("ep1out-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep2in-bulk", + USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)), /* and now some generic EPs so we have enough in multi config */ - "ep3out", "ep4in", "ep5out", "ep6out", "ep7in", "ep8out", "ep9in", - "ep10out", "ep11out", "ep12in", "ep13out", "ep14in", "ep15out", + EP_INFO("ep3out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep4in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep5out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep6out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep7in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep8out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep9in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep10out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep11out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep12in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep13out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep14in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep15out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + +#undef EP_INFO }; -#define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) + +#define DUMMY_ENDPOINTS ARRAY_SIZE(ep_info) /*-------------------------------------------------------------------------*/ @@ -938,9 +1002,10 @@ static void init_dummy_udc_hw(struct dummy *dum) for (i = 0; i < DUMMY_ENDPOINTS; i++) { struct dummy_ep *ep = &dum->ep[i]; - if (!ep_name[i]) + if (!ep_info[i].name) break; - ep->ep.name = ep_name[i]; + ep->ep.name = ep_info[i].name; + ep->ep.caps = ep_info[i].caps; ep->ep.ops = &dummy_ep_ops; list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list); ep->halted = ep->wedged = ep->already_seen = @@ -1684,7 +1749,7 @@ static void dummy_timer(unsigned long _dum_hcd) } for (i = 0; i < DUMMY_ENDPOINTS; i++) { - if (!ep_name[i]) + if (!ep_info[i].name) break; dum->ep[i].already_seen = 0; } -- cgit v1.3-6-gb490 From 8d29237a436dc8e2b5c44dd0ca662a680f16deb5 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:25 +0200 Subject: usb: gadget: fotg210-udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fotg210-udc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index a99ed6d80e9a..6ba122cc7490 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -1143,6 +1143,17 @@ static int fotg210_udc_probe(struct platform_device *pdev) ep->ep.name = fotg210_ep_name[i]; ep->ep.ops = &fotg210_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); + + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } usb_ep_set_maxpacket_limit(&fotg210->ep[0]->ep, 0x40); fotg210->gadget.ep0 = &fotg210->ep[0]->ep; -- cgit v1.3-6-gb490 From e8fc42f6a19af320d7a4718c05c3f249bf5d3151 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:26 +0200 Subject: usb: gadget: fsl_qe_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fsl_qe_udc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index e0822f1b6639..5fb6f8b4f0b4 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -2417,6 +2417,17 @@ static int qe_ep_config(struct qe_udc *udc, unsigned char pipe_num) strcpy(ep->name, ep_name[pipe_num]); ep->ep.name = ep_name[pipe_num]; + if (pipe_num == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; + ep->ep.ops = &qe_ep_ops; ep->stopped = 1; usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); -- cgit v1.3-6-gb490 From 60a28c63712f190b45e9d8f0ca593c927970fd51 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:27 +0200 Subject: usb: gadget: fsl_udc_core: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fsl_udc_core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index c60022b46a48..aab5221d6c2e 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -2313,6 +2313,19 @@ static int struct_ep_setup(struct fsl_udc *udc, unsigned char index, ep->ep.ops = &fsl_ep_ops; ep->stopped = 0; + if (index == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + if (index & 1) + ep->ep.caps.dir_in = true; + else + ep->ep.caps.dir_out = true; + /* for ep0: maxP defined in desc * for other eps, maxP is set by epautoconfig() called by gadget layer */ -- cgit v1.3-6-gb490 From 455d11c93582c4167f55af0969b83821450be120 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:28 +0200 Subject: usb: gadget: fusb300_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/fusb300_udc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c index 3970f453de49..948845c90e47 100644 --- a/drivers/usb/gadget/udc/fusb300_udc.c +++ b/drivers/usb/gadget/udc/fusb300_udc.c @@ -1450,6 +1450,17 @@ static int fusb300_probe(struct platform_device *pdev) ep->ep.name = fusb300_ep_name[i]; ep->ep.ops = &fusb300_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE); + + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE); fusb300->ep[0]->epnum = 0; -- cgit v1.3-6-gb490 From b0bf5fbfbd30ffbb9e45169f78412f0596e16412 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:29 +0200 Subject: usb: gadget: goku_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/goku_udc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index 9e8d842e8c08..46b8d14998cf 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -1257,6 +1257,14 @@ static void udc_reinit (struct goku_udc *dev) INIT_LIST_HEAD (&ep->queue); ep_reset(NULL, ep); + + if (i == 0) + ep->ep.caps.type_control = true; + else + ep->ep.caps.type_bulk = true; + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } dev->ep[0].reg_mode = NULL; -- cgit v1.3-6-gb490 From 892269925991b449ae47dcc0debb324ae451022e Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:30 +0200 Subject: usb: gadget: gr_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/gr_udc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index c8868870e217..8aa2593c2c36 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -2018,12 +2018,23 @@ static int gr_ep_init(struct gr_udc *dev, int num, int is_in, u32 maxplimit) usb_ep_set_maxpacket_limit(&ep->ep, MAX_CTRL_PL_SIZE); ep->bytes_per_buffer = MAX_CTRL_PL_SIZE; + + ep->ep.caps.type_control = true; } else { usb_ep_set_maxpacket_limit(&ep->ep, (u16)maxplimit); list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); + + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; } list_add_tail(&ep->ep_list, &dev->ep_list); + if (is_in) + ep->ep.caps.dir_in = true; + else + ep->ep.caps.dir_out = true; + ep->tailbuf = dma_alloc_coherent(dev->dev, ep->ep.maxpacket_limit, &ep->tailbuf_paddr, GFP_ATOMIC); if (!ep->tailbuf) -- cgit v1.3-6-gb490 From 4d75c8bd613c5ba99ee02cfe38610c82e7fe8362 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:31 +0200 Subject: usb: gadget: lpc32xx_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/lpc32xx_udc.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 3b6a7852822d..00b5006baf15 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -2575,6 +2575,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep0", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 0, @@ -2586,6 +2588,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep1-int", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 2, @@ -2597,6 +2601,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep2-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 4, @@ -2608,6 +2614,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep3-iso", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 1023, .hwep_num_base = 6, @@ -2619,6 +2627,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep4-int", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 8, @@ -2630,6 +2640,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep5-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 10, @@ -2641,6 +2653,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep6-iso", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 1023, .hwep_num_base = 12, @@ -2652,6 +2666,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep7-int", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 14, @@ -2663,6 +2679,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep8-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 16, @@ -2674,6 +2692,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep9-iso", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 1023, .hwep_num_base = 18, @@ -2685,6 +2705,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep10-int", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 20, @@ -2696,6 +2718,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep11-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 22, @@ -2707,6 +2731,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep12-iso", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 1023, .hwep_num_base = 24, @@ -2718,6 +2744,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep13-int", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 26, @@ -2729,6 +2757,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep14-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 64, .hwep_num_base = 28, @@ -2740,6 +2770,8 @@ static const struct lpc32xx_udc controller_template = { .ep = { .name = "ep15-bulk", .ops = &lpc32xx_ep_ops, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .maxpacket = 1023, .hwep_num_base = 30, -- cgit v1.3-6-gb490 From 8ddbf94fd5b536b3adf5ffa631c5951718e7301d Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:32 +0200 Subject: usb: gadget: m66592-udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/m66592-udc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index 9704053dfe05..b1cfa96cc88f 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1644,6 +1644,17 @@ static int m66592_probe(struct platform_device *pdev) ep->ep.name = m66592_ep_name[i]; ep->ep.ops = &m66592_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, 512); + + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } usb_ep_set_maxpacket_limit(&m66592->ep[0].ep, 64); m66592->ep[0].pipenum = 0; -- cgit v1.3-6-gb490 From c12a30629f8b5fe8c2aba42c3128df702bbc9e83 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:33 +0200 Subject: usb: gadget: mv_u3d_core: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/mv_u3d_core.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index ea35a248c898..4c489692745e 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -1324,6 +1324,9 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d) ep->ep.ops = &mv_u3d_ep_ops; ep->wedge = 0; usb_ep_set_maxpacket_limit(&ep->ep, MV_U3D_EP0_MAX_PKT_SIZE); + ep->ep.caps.type_control = true; + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; ep->ep_num = 0; ep->ep.desc = &mv_u3d_ep0_desc; INIT_LIST_HEAD(&ep->queue); @@ -1339,14 +1342,20 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d) if (i & 1) { snprintf(name, sizeof(name), "ep%din", i >> 1); ep->direction = MV_U3D_EP_DIR_IN; + ep->ep.caps.dir_in = true; } else { snprintf(name, sizeof(name), "ep%dout", i >> 1); ep->direction = MV_U3D_EP_DIR_OUT; + ep->ep.caps.dir_out = true; } ep->u3d = u3d; strncpy(ep->name, name, sizeof(ep->name)); ep->ep.name = ep->name; + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + ep->ep.ops = &mv_u3d_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); ep->ep_num = i / 2; -- cgit v1.3-6-gb490 From 43710a8dba9ae607decdeaf7a56a51dd5b42184e Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:34 +0200 Subject: usb: gadget: mv_udc_core: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/mv_udc_core.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 5da37c957b53..339af51df57d 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -1257,6 +1257,9 @@ static int eps_init(struct mv_udc *udc) ep->wedge = 0; ep->stopped = 0; usb_ep_set_maxpacket_limit(&ep->ep, EP0_MAX_PKT_SIZE); + ep->ep.caps.type_control = true; + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; ep->ep_num = 0; ep->ep.desc = &mv_ep0_desc; INIT_LIST_HEAD(&ep->queue); @@ -1269,14 +1272,20 @@ static int eps_init(struct mv_udc *udc) if (i % 2) { snprintf(name, sizeof(name), "ep%din", i / 2); ep->direction = EP_DIR_IN; + ep->ep.caps.dir_in = true; } else { snprintf(name, sizeof(name), "ep%dout", i / 2); ep->direction = EP_DIR_OUT; + ep->ep.caps.dir_out = true; } ep->udc = udc; strncpy(ep->name, name, sizeof(ep->name)); ep->ep.name = ep->name; + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + ep->ep.ops = &mv_ep_ops; ep->stopped = 0; usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); -- cgit v1.3-6-gb490 From f95aec51da16250841a4254db36f9771446cdbb6 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:35 +0200 Subject: usb: gadget: net2272: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2272.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index c2ed5daebb75..18f5ebd447b8 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -1404,6 +1404,17 @@ net2272_usb_reinit(struct net2272 *dev) else ep->fifo_size = 64; net2272_ep_reset(ep); + + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 64); -- cgit v1.3-6-gb490 From c23c3c3c3059f3dc47268cd7a28b96b9efdbc1ea Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:36 +0200 Subject: usb: gadget: net2280: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/net2280.c | 67 +++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index 2bee912ca65b..872ca257cfa4 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -74,19 +74,58 @@ static const char driver_desc[] = DRIVER_DESC; static const u32 ep_bit[9] = { 0, 17, 2, 19, 4, 1, 18, 3, 20 }; static const char ep0name[] = "ep0"; -static const char *const ep_name[] = { - ep0name, - "ep-a", "ep-b", "ep-c", "ep-d", - "ep-e", "ep-f", "ep-g", "ep-h", -}; -/* Endpoint names for usb3380 advance mode */ -static const char *const ep_name_adv[] = { - ep0name, - "ep1in", "ep2out", "ep3in", "ep4out", - "ep1out", "ep2in", "ep3out", "ep4in", +#define EP_INFO(_name, _caps) \ + { \ + .name = _name, \ + .caps = _caps, \ + } + +static const struct { + const char *name; + const struct usb_ep_caps caps; +} ep_info_dft[] = { /* Default endpoint configuration */ + EP_INFO(ep0name, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-a", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-b", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-c", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-d", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-e", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-f", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-g", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep-h", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)), +}, ep_info_adv[] = { /* Endpoints for usb3380 advance mode */ + EP_INFO(ep0name, + USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)), + EP_INFO("ep1in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep2out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep3in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep4out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep1out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep2in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), + EP_INFO("ep3out", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)), + EP_INFO("ep4in", + USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)), }; +#undef EP_INFO + /* mode 0 == ep-{a,b,c,d} 1K fifo each * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable @@ -2055,7 +2094,8 @@ static void usb_reinit_228x(struct net2280 *dev) for (tmp = 0; tmp < 7; tmp++) { struct net2280_ep *ep = &dev->ep[tmp]; - ep->ep.name = ep_name[tmp]; + ep->ep.name = ep_info_dft[tmp].name; + ep->ep.caps = ep_info_dft[tmp].caps; ep->dev = dev; ep->num = tmp; @@ -2095,7 +2135,10 @@ static void usb_reinit_338x(struct net2280 *dev) for (i = 0; i < dev->n_ep; i++) { struct net2280_ep *ep = &dev->ep[i]; - ep->ep.name = dev->enhanced_mode ? ep_name_adv[i] : ep_name[i]; + ep->ep.name = dev->enhanced_mode ? ep_info_adv[i].name : + ep_info_dft[i].name; + ep->ep.caps = dev->enhanced_mode ? ep_info_adv[i].caps : + ep_info_dft[i].caps; ep->dev = dev; ep->num = i; -- cgit v1.3-6-gb490 From 7d4ba80d3a91222de577b652a8936f935de8b409 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:37 +0200 Subject: usb: gadget: omap_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/omap_udc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index e2fcdb8e5596..9b7d39484ed3 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -2579,6 +2579,28 @@ omap_ep_setup(char *name, u8 addr, u8 type, ep->double_buf = dbuf; ep->udc = udc; + switch (type) { + case USB_ENDPOINT_XFER_CONTROL: + ep->ep.caps.type_control = true; + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; + break; + case USB_ENDPOINT_XFER_ISOC: + ep->ep.caps.type_iso = true; + break; + case USB_ENDPOINT_XFER_BULK: + ep->ep.caps.type_bulk = true; + break; + case USB_ENDPOINT_XFER_INT: + ep->ep.caps.type_int = true; + break; + }; + + if (addr & USB_DIR_IN) + ep->ep.caps.dir_in = true; + else + ep->ep.caps.dir_out = true; + ep->ep.name = ep->name; ep->ep.ops = &omap_ep_ops; ep->maxpacket = maxp; -- cgit v1.3-6-gb490 From 85a4ed003b39f70ba478e613a9be2c334f1079e7 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:38 +0200 Subject: usb: gadget: pch_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index e071c62d7f24..e5f4c5274298 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -2895,11 +2895,21 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev) ep->in = ~i & 1; ep->ep.name = ep_string[i]; ep->ep.ops = &pch_udc_ep_ops; - if (ep->in) + if (ep->in) { ep->offset_addr = ep->num * UDC_EP_REG_SHIFT; - else + ep->ep.caps.dir_in = true; + } else { ep->offset_addr = (UDC_EPINT_OUT_SHIFT + ep->num) * UDC_EP_REG_SHIFT; + ep->ep.caps.dir_out = true; + } + if (i == UDC_EP0IN_IDX || i == UDC_EP0OUT_IDX) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } /* need to set ep->ep.maxpacket and set Default Configuration?*/ usb_ep_set_maxpacket_limit(&ep->ep, UDC_BULK_MAX_PKT_SIZE); list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); -- cgit v1.3-6-gb490 From 36411b6b042d350a43fe1e0d3ce78fbda30f4f02 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:39 +0200 Subject: usb: gadget: pxa25x_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pxa25x_udc.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index 27f944231477..b4d25dc4cb72 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1822,6 +1822,8 @@ static struct pxa25x_udc memory = { .name = ep0name, .ops = &pxa25x_ep_ops, .maxpacket = EP0_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, .reg_udccs = &UDCCS0, @@ -1834,6 +1836,8 @@ static struct pxa25x_udc memory = { .name = "ep1in-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -1847,6 +1851,8 @@ static struct pxa25x_udc memory = { .name = "ep2out-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -1862,6 +1868,8 @@ static struct pxa25x_udc memory = { .name = "ep3in-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -1875,6 +1883,8 @@ static struct pxa25x_udc memory = { .name = "ep4out-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -1889,6 +1899,8 @@ static struct pxa25x_udc memory = { .name = "ep5in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, @@ -1904,6 +1916,8 @@ static struct pxa25x_udc memory = { .name = "ep6in-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -1917,6 +1931,8 @@ static struct pxa25x_udc memory = { .name = "ep7out-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -1931,6 +1947,8 @@ static struct pxa25x_udc memory = { .name = "ep8in-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -1944,6 +1962,8 @@ static struct pxa25x_udc memory = { .name = "ep9out-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -1958,6 +1978,8 @@ static struct pxa25x_udc memory = { .name = "ep10in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, @@ -1973,6 +1995,8 @@ static struct pxa25x_udc memory = { .name = "ep11in-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -1986,6 +2010,8 @@ static struct pxa25x_udc memory = { .name = "ep12out-bulk", .ops = &pxa25x_ep_ops, .maxpacket = BULK_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = BULK_FIFO_SIZE, @@ -2000,6 +2026,8 @@ static struct pxa25x_udc memory = { .name = "ep13in-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -2013,6 +2041,8 @@ static struct pxa25x_udc memory = { .name = "ep14out-iso", .ops = &pxa25x_ep_ops, .maxpacket = ISO_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, + USB_EP_CAPS_DIR_OUT), }, .dev = &memory, .fifo_size = ISO_FIFO_SIZE, @@ -2027,6 +2057,8 @@ static struct pxa25x_udc memory = { .name = "ep15in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, + USB_EP_CAPS_DIR_IN), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, -- cgit v1.3-6-gb490 From a180e3da97a323510071b2b5e42b5dc07df239da Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:40 +0200 Subject: usb: gadget: pxa27x_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pxa27x_udc.h | 40 +++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/pxa27x_udc.h b/drivers/usb/gadget/udc/pxa27x_udc.h index 11e14232794b..cea2cb79b30c 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.h +++ b/drivers/usb/gadget/udc/pxa27x_udc.h @@ -234,25 +234,35 @@ /* * Endpoint definition helpers */ -#define USB_EP_DEF(addr, bname, dir, type, maxpkt) \ -{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, }, \ +#define USB_EP_DEF(addr, bname, dir, type, maxpkt, ctype, cdir) \ +{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, \ + .caps = USB_EP_CAPS(ctype, cdir), }, \ .desc = { .bEndpointAddress = addr | (dir ? USB_DIR_IN : 0), \ - .bmAttributes = type, \ + .bmAttributes = USB_ENDPOINT_XFER_ ## type, \ .wMaxPacketSize = maxpkt, }, \ .dev = &memory \ } -#define USB_EP_BULK(addr, bname, dir) \ - USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE) -#define USB_EP_ISO(addr, bname, dir) \ - USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE) -#define USB_EP_INT(addr, bname, dir) \ - USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE) -#define USB_EP_IN_BULK(n) USB_EP_BULK(n, "ep" #n "in-bulk", 1) -#define USB_EP_OUT_BULK(n) USB_EP_BULK(n, "ep" #n "out-bulk", 0) -#define USB_EP_IN_ISO(n) USB_EP_ISO(n, "ep" #n "in-iso", 1) -#define USB_EP_OUT_ISO(n) USB_EP_ISO(n, "ep" #n "out-iso", 0) -#define USB_EP_IN_INT(n) USB_EP_INT(n, "ep" #n "in-int", 1) -#define USB_EP_CTRL USB_EP_DEF(0, "ep0", 0, 0, EP0_FIFO_SIZE) +#define USB_EP_BULK(addr, bname, dir, cdir) \ + USB_EP_DEF(addr, bname, dir, BULK, BULK_FIFO_SIZE, \ + USB_EP_CAPS_TYPE_BULK, cdir) +#define USB_EP_ISO(addr, bname, dir, cdir) \ + USB_EP_DEF(addr, bname, dir, ISOC, ISO_FIFO_SIZE, \ + USB_EP_CAPS_TYPE_ISO, cdir) +#define USB_EP_INT(addr, bname, dir, cdir) \ + USB_EP_DEF(addr, bname, dir, INT, INT_FIFO_SIZE, \ + USB_EP_CAPS_TYPE_INT, cdir) +#define USB_EP_IN_BULK(n) USB_EP_BULK(n, "ep" #n "in-bulk", 1, \ + USB_EP_CAPS_DIR_IN) +#define USB_EP_OUT_BULK(n) USB_EP_BULK(n, "ep" #n "out-bulk", 0, \ + USB_EP_CAPS_DIR_OUT) +#define USB_EP_IN_ISO(n) USB_EP_ISO(n, "ep" #n "in-iso", 1, \ + USB_EP_CAPS_DIR_IN) +#define USB_EP_OUT_ISO(n) USB_EP_ISO(n, "ep" #n "out-iso", 0, \ + USB_EP_CAPS_DIR_OUT) +#define USB_EP_IN_INT(n) USB_EP_INT(n, "ep" #n "in-int", 1, \ + USB_EP_CAPS_DIR_IN) +#define USB_EP_CTRL USB_EP_DEF(0, "ep0", 0, CONTROL, EP0_FIFO_SIZE, \ + USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL) #define PXA_EP_DEF(_idx, _addr, dir, _type, maxpkt, _config, iface, altset) \ { \ -- cgit v1.3-6-gb490 From 0ec8026d7afee625f52631708d84435ea4735da6 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:41 +0200 Subject: usb: gadget: r8a66597-udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/r8a66597-udc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index 0293f7169dee..baa0609a429d 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1935,6 +1935,16 @@ static int r8a66597_probe(struct platform_device *pdev) ep->ep.name = r8a66597_ep_name[i]; ep->ep.ops = &r8a66597_ep_ops; usb_ep_set_maxpacket_limit(&ep->ep, 512); + + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; } usb_ep_set_maxpacket_limit(&r8a66597->ep[0].ep, 64); r8a66597->ep[0].pipenum = 0; -- cgit v1.3-6-gb490 From bc1b9f300ae06c64fcd056fb959b3d709ad2ef33 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:42 +0200 Subject: usb: gadget: s3c-hsudc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/s3c-hsudc.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c index 85a712a03343..e9def42ce50d 100644 --- a/drivers/usb/gadget/udc/s3c-hsudc.c +++ b/drivers/usb/gadget/udc/s3c-hsudc.c @@ -1005,6 +1005,21 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc, hsep->stopped = 0; hsep->wedge = 0; + if (epnum == 0) { + hsep->ep.caps.type_control = true; + hsep->ep.caps.dir_in = true; + hsep->ep.caps.dir_out = true; + } else { + hsep->ep.caps.type_iso = true; + hsep->ep.caps.type_bulk = true; + hsep->ep.caps.type_int = true; + } + + if (epnum & 1) + hsep->ep.caps.dir_in = true; + else + hsep->ep.caps.dir_out = true; + set_index(hsudc, epnum); writel(hsep->ep.maxpacket, hsudc->regs + S3C_MPR); } -- cgit v1.3-6-gb490 From 0648772d51c0ff3949397cb0cbcf2435ee32c550 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:43 +0200 Subject: usb: gadget: s3c2410_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/s3c2410_udc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index 5d9aa81969b4..eb3571ee59e3 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -1691,6 +1691,8 @@ static struct s3c2410_udc memory = { .name = ep0name, .ops = &s3c2410_ep_ops, .maxpacket = EP0_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, }, @@ -1702,6 +1704,8 @@ static struct s3c2410_udc memory = { .name = "ep1-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, @@ -1714,6 +1718,8 @@ static struct s3c2410_udc memory = { .name = "ep2-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, @@ -1726,6 +1732,8 @@ static struct s3c2410_udc memory = { .name = "ep3-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, @@ -1738,6 +1746,8 @@ static struct s3c2410_udc memory = { .name = "ep4-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, + .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, + USB_EP_CAPS_DIR_ALL), }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, -- cgit v1.3-6-gb490 From 927d9f77fe3d5f9261eeb465e2b60768e400ffc9 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:44 +0200 Subject: usb: gadget: udc-xilinx: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/udc-xilinx.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c index 1f24274477ab..1cbb0ac6b182 100644 --- a/drivers/usb/gadget/udc/udc-xilinx.c +++ b/drivers/usb/gadget/udc/udc-xilinx.c @@ -1317,12 +1317,21 @@ static void xudc_eps_init(struct xusb_udc *udc) snprintf(ep->name, EPNAME_SIZE, "ep%d", ep_number); ep->ep_usb.name = ep->name; ep->ep_usb.ops = &xusb_ep_ops; + + ep->ep_usb.caps.type_iso = true; + ep->ep_usb.caps.type_bulk = true; + ep->ep_usb.caps.type_int = true; } else { ep->ep_usb.name = ep0name; usb_ep_set_maxpacket_limit(&ep->ep_usb, EP0_MAX_PACKET); ep->ep_usb.ops = &xusb_ep0_ops; + + ep->ep_usb.caps.type_control = true; } + ep->ep_usb.caps.dir_in = true; + ep->ep_usb.caps.dir_out = true; + ep->udc = udc; ep->epnumber = ep_number; ep->desc = NULL; -- cgit v1.3-6-gb490 From eb4cbc19526d62657b838d6f0b694a000e5b4c81 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:45 +0200 Subject: usb: isp1760: udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/isp1760/isp1760-udc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c index 3699962987b2..1c3d0fd658fa 100644 --- a/drivers/usb/isp1760/isp1760-udc.c +++ b/drivers/usb/isp1760/isp1760-udc.c @@ -1383,13 +1383,24 @@ static void isp1760_udc_init_eps(struct isp1760_udc *udc) */ if (ep_num == 0) { usb_ep_set_maxpacket_limit(&ep->ep, 64); + ep->ep.caps.type_control = true; + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; ep->maxpacket = 64; udc->gadget.ep0 = &ep->ep; } else { usb_ep_set_maxpacket_limit(&ep->ep, 512); + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; ep->maxpacket = 0; list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); } + + if (is_in) + ep->ep.caps.dir_in = true; + else + ep->ep.caps.dir_out = true; } } -- cgit v1.3-6-gb490 From 8501955e888662ca56775eec2eb804e7bc7fce0d Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:46 +0200 Subject: usb: musb: gadget: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 9e18178f1d45..4150bafe6bf5 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1729,6 +1729,7 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in) INIT_LIST_HEAD(&ep->end_point.ep_list); if (!epnum) { usb_ep_set_maxpacket_limit(&ep->end_point, 64); + ep->end_point.caps.type_control = true; ep->end_point.ops = &musb_g_ep0_ops; musb->g.ep0 = &ep->end_point; } else { @@ -1736,9 +1737,20 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in) usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_tx); else usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_rx); + ep->end_point.caps.type_iso = true; + ep->end_point.caps.type_bulk = true; + ep->end_point.caps.type_int = true; ep->end_point.ops = &musb_ep_ops; list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list); } + + if (!epnum || hw_ep->is_shared_fifo) { + ep->end_point.caps.dir_in = true; + ep->end_point.caps.dir_out = true; + } else if (is_in) + ep->end_point.caps.dir_in = true; + else + ep->end_point.caps.dir_out = true; } /* -- cgit v1.3-6-gb490 From 916f7ac5dbc312969a90bc35a5f4fcbfc2965d60 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:47 +0200 Subject: usb: renesas: gadget: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 494dfe06bb27..de4f97d84a82 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -1103,12 +1103,18 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) if (usbhsg_is_dcp(uep)) { gpriv->gadget.ep0 = &uep->ep; usb_ep_set_maxpacket_limit(&uep->ep, 64); + uep->ep.caps.type_control = true; } /* init normal pipe */ else { usb_ep_set_maxpacket_limit(&uep->ep, 512); + uep->ep.caps.type_iso = true; + uep->ep.caps.type_bulk = true; + uep->ep.caps.type_int = true; list_add_tail(&uep->ep.ep_list, &gpriv->gadget.ep_list); } + uep->ep.caps.dir_in = true; + uep->ep.caps.dir_out = true; } ret = usb_add_gadget_udc(dev, &gpriv->gadget); -- cgit v1.3-6-gb490 From 47bef386511517449e2f24a89a41084af53616f8 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:48 +0200 Subject: usb: gadget: atmel_usba_udc: add ep capabilities support Convert endpoint configuration to new capabilities model. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/atmel_usba_udc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 37d414ec2d69..267d84f838e1 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -2067,6 +2067,17 @@ static struct usba_ep * usba_udc_pdata(struct platform_device *pdev, ep->can_dma = pdata->ep[i].can_dma; ep->can_isoc = pdata->ep[i].can_isoc; + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = ep->can_isoc; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; + if (i) list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); } -- cgit v1.3-6-gb490 From b86f33a3a371a4c3aa8dbb2f4125634a4e0d09dc Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:49 +0200 Subject: usb: gadget: epautoconf: add endpoint capabilities flags verification Introduce endpoint matching mechanism basing on endpoint capabilities flags. We check if endpoint supports transfer type and direction requested in ep descriptor. Since we have this new endpoint matching mechanism there is no need to have old code guessing endpoint capabilities basing on its name, so we are getting rid of it. Remove also the obsolete comment. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 96 +++++++++++++---------------------------- 1 file changed, 30 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 8e00ca765549..af4b10a9068e 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -22,22 +22,6 @@ #include "gadget_chips.h" -/* - * This should work with endpoints from controller drivers sharing the - * same endpoint naming convention. By example: - * - * - ep1, ep2, ... address is fixed, not direction or type - * - ep1in, ep2out, ... address and direction are fixed, not type - * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction - * - ep1in-bulk, ep2out-iso, ... all three are fixed - * - ep-* ... no functionality restrictions - * - * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal. - * Less common restrictions are implied by gadget_is_*(). - * - * NOTE: each endpoint is unidirectional, as specified by its USB - * descriptor; and isn't specific to a configuration or altsetting. - */ static int ep_matches ( struct usb_gadget *gadget, @@ -47,7 +31,6 @@ ep_matches ( ) { u8 type; - const char *tmp; u16 max; int num_req_streams = 0; @@ -56,58 +39,39 @@ ep_matches ( if (ep->claimed) return 0; - /* only support ep0 for portable CONTROL traffic */ type = usb_endpoint_type(desc); - if (USB_ENDPOINT_XFER_CONTROL == type) - return 0; - - /* some other naming convention */ - if ('e' != ep->name[0]) + switch (type) { + case USB_ENDPOINT_XFER_CONTROL: + /* only support ep0 for portable CONTROL traffic */ return 0; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->caps.type_iso) + return 0; + break; + case USB_ENDPOINT_XFER_BULK: + if (!ep->caps.type_bulk) + return 0; + break; + case USB_ENDPOINT_XFER_INT: + /* bulk endpoints handle interrupt transfers, + * except the toggle-quirky iso-synch kind + */ + if (!ep->caps.type_int && !ep->caps.type_bulk) + return 0; + /* for now, avoid PXA "interrupt-in"; + * it's documented as never using DATA1. + */ + if (gadget_is_pxa(gadget) && ep->caps.type_int) + return 0; + break; + } - /* type-restriction: "-iso", "-bulk", or "-int". - * direction-restriction: "in", "out". - */ - if ('-' != ep->name[2]) { - tmp = strrchr (ep->name, '-'); - if (tmp) { - switch (type) { - case USB_ENDPOINT_XFER_INT: - /* bulk endpoints handle interrupt transfers, - * except the toggle-quirky iso-synch kind - */ - if ('s' == tmp[2]) // == "-iso" - return 0; - /* for now, avoid PXA "interrupt-in"; - * it's documented as never using DATA1. - */ - if (gadget_is_pxa (gadget) - && 'i' == tmp [1]) - return 0; - break; - case USB_ENDPOINT_XFER_BULK: - if ('b' != tmp[1]) // != "-bulk" - return 0; - break; - case USB_ENDPOINT_XFER_ISOC: - if ('s' != tmp[2]) // != "-iso" - return 0; - } - } else { - tmp = ep->name + strlen (ep->name); - } - - /* direction-restriction: "..in-..", "out-.." */ - tmp--; - if (!isdigit (*tmp)) { - if (desc->bEndpointAddress & USB_DIR_IN) { - if ('n' != *tmp) - return 0; - } else { - if ('t' != *tmp) - return 0; - } - } + if (usb_endpoint_dir_in(desc)) { + if (!ep->caps.dir_in) + return 0; + } else { + if (!ep->caps.dir_out) + return 0; } /* -- cgit v1.3-6-gb490 From b58713d53a8f41d57b24c93de0b1c7e9550ba70f Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:50 +0200 Subject: usb: gadget: epautoconf: remove pxa quirk from ep_matches() The same effect can be achieved by using capabilities flags, so now we can get rid of handling of hardware specific limitations in generic code. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 5 ----- drivers/usb/gadget/udc/pxa25x_udc.c | 9 +++------ 2 files changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index af4b10a9068e..4f66e9d733cd 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -58,11 +58,6 @@ ep_matches ( */ if (!ep->caps.type_int && !ep->caps.type_bulk) return 0; - /* for now, avoid PXA "interrupt-in"; - * it's documented as never using DATA1. - */ - if (gadget_is_pxa(gadget) && ep->caps.type_int) - return 0; break; } diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c index b4d25dc4cb72..b82cb14850b6 100644 --- a/drivers/usb/gadget/udc/pxa25x_udc.c +++ b/drivers/usb/gadget/udc/pxa25x_udc.c @@ -1899,8 +1899,7 @@ static struct pxa25x_udc memory = { .name = "ep5in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, - .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, - USB_EP_CAPS_DIR_IN), + .caps = USB_EP_CAPS(0, 0), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, @@ -1978,8 +1977,7 @@ static struct pxa25x_udc memory = { .name = "ep10in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, - .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, - USB_EP_CAPS_DIR_IN), + .caps = USB_EP_CAPS(0, 0), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, @@ -2057,8 +2055,7 @@ static struct pxa25x_udc memory = { .name = "ep15in-int", .ops = &pxa25x_ep_ops, .maxpacket = INT_FIFO_SIZE, - .caps = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, - USB_EP_CAPS_DIR_IN), + .caps = USB_EP_CAPS(0, 0), }, .dev = &memory, .fifo_size = INT_FIFO_SIZE, -- cgit v1.3-6-gb490 From 5dbe135a153837ce9367bdfacf7aabfc6fb76f4b Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 16:00:51 +0200 Subject: usb: gadget: epautoconf: remove ep and desc configuration from ep_matches() As function ep_matches() is used to match endpoint with usb descriptor it's highly unintuitive that it modifies endpoint and descriptor structures fields. This patch moves code configuring ep and desc from ep_matches() to usb_ep_autoconfig_ss(), so now function ep_matches() does nothing more than its name suggests. [ balbi@ti.com : fix build warning ] Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 66 +++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 4f66e9d733cd..52658fe761d4 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -82,13 +82,6 @@ ep_matches ( } - /* - * If the protocol driver hasn't yet decided on wMaxPacketSize - * and wants to know the maximum possible, provide the info. - */ - if (desc->wMaxPacketSize == 0) - desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit); - /* endpoint maxpacket size is an input parameter, except for bulk * where it's an output parameter representing the full speed limit. * the usb spec fixes high speed bulk maxpacket at 512 bytes. @@ -119,31 +112,6 @@ ep_matches ( /* MATCH!! */ - /* report address */ - desc->bEndpointAddress &= USB_DIR_IN; - if (isdigit (ep->name [2])) { - u8 num = simple_strtoul (&ep->name [2], NULL, 10); - desc->bEndpointAddress |= num; - } else if (desc->bEndpointAddress & USB_DIR_IN) { - if (++gadget->in_epnum > 15) - return 0; - desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum; - } else { - if (++gadget->out_epnum > 15) - return 0; - desc->bEndpointAddress |= gadget->out_epnum; - } - - /* report (variable) full speed bulk maxpacket */ - if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) { - int size = ep->maxpacket_limit; - - /* min() doesn't work on bitfields with gcc-3.5 */ - if (size > 64) - size = 64; - desc->wMaxPacketSize = cpu_to_le16(size); - } - ep->address = desc->bEndpointAddress; return 1; } @@ -280,6 +248,40 @@ struct usb_ep *usb_ep_autoconfig_ss( /* Fail */ return NULL; found_ep: + + /* + * If the protocol driver hasn't yet decided on wMaxPacketSize + * and wants to know the maximum possible, provide the info. + */ + if (desc->wMaxPacketSize == 0) + desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit); + + /* report address */ + desc->bEndpointAddress &= USB_DIR_IN; + if (isdigit(ep->name[2])) { + u8 num = simple_strtoul(&ep->name[2], NULL, 10); + desc->bEndpointAddress |= num; + } else if (desc->bEndpointAddress & USB_DIR_IN) { + if (++gadget->in_epnum > 15) + return NULL; + desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum; + } else { + if (++gadget->out_epnum > 15) + return NULL; + desc->bEndpointAddress |= gadget->out_epnum; + } + + /* report (variable) full speed bulk maxpacket */ + if ((type == USB_ENDPOINT_XFER_BULK) && !ep_comp) { + int size = ep->maxpacket_limit; + + /* min() doesn't work on bitfields with gcc-3.5 */ + if (size > 64) + size = 64; + desc->wMaxPacketSize = cpu_to_le16(size); + } + + ep->address = desc->bEndpointAddress; ep->desc = NULL; ep->comp_desc = NULL; ep->claimed = true; -- cgit v1.3-6-gb490 From d4ea7d86457a8d0ea40ce77bdeda1fc966cc35ec Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Sat, 1 Aug 2015 18:13:25 +0100 Subject: regulator: axp20x: Add module alias This allows the module to be autoloaded. Together with 07949bf9c63c ("cpufreq: dt: allow driver to boot automatically") this is sufficient to allow a modular kernel (such as Debian's) to enable cpufreq on a Cubietruck. Signed-off-by: Ian Campbell Signed-off-by: Mark Brown --- drivers/regulator/axp20x-regulator.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 646829132b59..01bf3476a791 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -405,3 +405,4 @@ module_platform_driver(axp20x_regulator_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Carlo Caione "); MODULE_DESCRIPTION("Regulator Driver for AXP20X PMIC"); +MODULE_ALIAS("platform:axp20x-regulator"); -- cgit v1.3-6-gb490 From b03ba9e314c12b2127243145b5c1f41b2408de62 Mon Sep 17 00:00:00 2001 From: Sifan Naeem Date: Wed, 29 Jul 2015 11:55:26 +0100 Subject: spi: img-spfi: fix multiple calls to request gpio spfi_setup may be called many times by the spi framework, but gpio_request_one can only be called once without freeing, repeatedly calling gpio_request_one will cause an error to be thrown, which causes the request to spi_setup to be marked as failed. We can have a per-spi_device flag that indicates whether or not the gpio has been requested. If the gpio has already been requested use gpio_direction_output to set the direction of the gpio. Fixes: 8c2c8c03cdcb ("spi: img-spfi: Control CS lines with GPIO") Signed-off-by: Sifan Naeem Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-img-spfi.c | 49 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index 83b97418fc8d..1ba90562d72a 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -104,6 +104,10 @@ struct img_spfi { bool rx_dma_busy; }; +struct img_spfi_device_data { + bool gpio_requested; +}; + static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg) { return readl(spfi->regs + reg); @@ -440,20 +444,49 @@ static int img_spfi_unprepare(struct spi_master *master, static int img_spfi_setup(struct spi_device *spi) { int ret; - - ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ? - GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, - dev_name(&spi->dev)); - if (ret) - dev_err(&spi->dev, "can't request chipselect gpio %d\n", + struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi); + + if (!spfi_data) { + spfi_data = kzalloc(sizeof(*spfi_data), GFP_KERNEL); + if (!spfi_data) + return -ENOMEM; + spfi_data->gpio_requested = false; + spi_set_ctldata(spi, spfi_data); + } + if (!spfi_data->gpio_requested) { + ret = gpio_request_one(spi->cs_gpio, + (spi->mode & SPI_CS_HIGH) ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, + dev_name(&spi->dev)); + if (ret) + dev_err(&spi->dev, "can't request chipselect gpio %d\n", spi->cs_gpio); - + else + spfi_data->gpio_requested = true; + } else { + if (gpio_is_valid(spi->cs_gpio)) { + int mode = ((spi->mode & SPI_CS_HIGH) ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH); + + ret = gpio_direction_output(spi->cs_gpio, mode); + if (ret) + dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n", + spi->cs_gpio, ret); + } + } return ret; } static void img_spfi_cleanup(struct spi_device *spi) { - gpio_free(spi->cs_gpio); + struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi); + + if (spfi_data) { + if (spfi_data->gpio_requested) + gpio_free(spi->cs_gpio); + kfree(spfi_data); + spi_set_ctldata(spi, NULL); + } } static void img_spfi_config(struct spi_master *master, struct spi_device *spi, -- cgit v1.3-6-gb490 From ca8c0f4bede6098f9d531365d2ad9d7a598327f6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 20 Apr 2015 17:54:54 +0200 Subject: iwlwifi: mvm: move TX PN assignment for CCMP to the driver Move the TX PN assignment (for CCMP only) to the driver. This prepares the driver for future DSO (driver segmentation offload) where it will split an SKB into multiple MPDUs by itself. For TDLS, split out the CCMP TX command handling so that it won't get a PN assigned, the firmware assigns the PN in that case. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 5 ++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 15 ++++++++--- drivers/net/wireless/iwlwifi/mvm/tdls.c | 12 ++++++--- drivers/net/wireless/iwlwifi/mvm/tx.c | 41 +++++++++++++++++++---------- 4 files changed, 50 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 4264c52aa127..5a4bf84aa260 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -2873,10 +2873,11 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - /* fall-through */ - case WLAN_CIPHER_SUITE_CCMP: key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; break; + case WLAN_CIPHER_SUITE_CCMP: + key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; + break; case WLAN_CIPHER_SUITE_AES_CMAC: WARN_ON_ONCE(!ieee80211_hw_check(hw, MFP_CAPABLE)); break; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index c1f84ec93f40..95f326dc0b1f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -1000,10 +1000,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb); void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, u8 sta_id); -void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, - struct ieee80211_tx_info *info, - struct iwl_tx_cmd *tx_cmd, - struct sk_buff *skb_frag); void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, __le16 fc); @@ -1015,6 +1011,17 @@ 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_set_tx_cmd_ccmp(struct ieee80211_tx_info *info, + struct iwl_tx_cmd *tx_cmd) +{ + struct ieee80211_key_conf *keyconf = info->control.hw_key; + + tx_cmd->sec_ctl = TX_CMD_SEC_CCM; + memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); + if (info->flags & IEEE80211_TX_CTL_AMPDU) + tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_CCMP_AGG); +} + static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm) { flush_work(&mvm->async_handlers_wk); diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index d44d02d16fe2..fe2fa5650443 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -460,13 +460,19 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, cmd.frame.switch_time_offset = cpu_to_le32(ch_sw_tm_ie + 2); info = IEEE80211_SKB_CB(skb); - if (info->control.hw_key) - iwl_mvm_set_tx_cmd_crypto(mvm, info, &cmd.frame.tx_cmd, skb); + hdr = (void *)skb->data; + if (info->control.hw_key) { + if (info->control.hw_key->cipher != WLAN_CIPHER_SUITE_CCMP) { + rcu_read_unlock(); + ret = -EINVAL; + goto out; + } + iwl_mvm_set_tx_cmd_ccmp(info, &cmd.frame.tx_cmd); + } iwl_mvm_set_tx_cmd(mvm, skb, &cmd.frame.tx_cmd, info, mvmsta->sta_id); - hdr = (void *)skb->data; iwl_mvm_set_tx_cmd_rate(mvm, &cmd.frame.tx_cmd, info, sta, hdr->frame_control); rcu_read_unlock(); diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index fa3eaf9a2fc6..eac511aebae0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -268,19 +268,29 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd, /* * Sets the fields in the Tx cmd that are crypto related */ -void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, - struct ieee80211_tx_info *info, - struct iwl_tx_cmd *tx_cmd, - struct sk_buff *skb_frag) +static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, + struct ieee80211_tx_info *info, + struct iwl_tx_cmd *tx_cmd, + struct sk_buff *skb_frag, + int hdrlen) { struct ieee80211_key_conf *keyconf = info->control.hw_key; + u8 *crypto_hdr = skb_frag->data + hdrlen; + u64 pn; switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_CCMP: - tx_cmd->sec_ctl = TX_CMD_SEC_CCM; - memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); - if (info->flags & IEEE80211_TX_CTL_AMPDU) - tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_CCMP_AGG); + case WLAN_CIPHER_SUITE_CCMP_256: + iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd); + pn = atomic64_inc_return(&keyconf->tx_pn); + crypto_hdr[0] = pn; + crypto_hdr[2] = 0; + crypto_hdr[3] = 0x20 | (keyconf->keyidx << 6); + crypto_hdr[1] = pn >> 8; + crypto_hdr[4] = pn >> 16; + crypto_hdr[5] = pn >> 24; + crypto_hdr[6] = pn >> 32; + crypto_hdr[7] = pn >> 40; break; case WLAN_CIPHER_SUITE_TKIP: @@ -308,7 +318,7 @@ void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, */ static struct iwl_device_cmd * iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, - struct ieee80211_sta *sta, u8 sta_id) + int hdrlen, struct ieee80211_sta *sta, u8 sta_id) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -325,7 +335,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; if (info->control.hw_key) - iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb); + iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb, hdrlen); iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id); @@ -346,6 +356,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) struct iwl_device_cmd *dev_cmd; struct iwl_tx_cmd *tx_cmd; u8 sta_id; + int hdrlen = ieee80211_hdrlen(hdr->frame_control); if (WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU)) return -1; @@ -393,7 +404,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, info->hw_queue); - dev_cmd = iwl_mvm_set_tx_params(mvm, skb, NULL, sta_id); + dev_cmd = iwl_mvm_set_tx_params(mvm, skb, hdrlen, NULL, sta_id); if (!dev_cmd) return -1; @@ -401,7 +412,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(hdr->frame_control)); + memcpy(tx_cmd->hdr, hdr, hdrlen); if (iwl_trans_tx(mvm->trans, skb, dev_cmd, info->hw_queue)) { iwl_trans_free_tx_cmd(mvm->trans, dev_cmd); @@ -427,9 +438,11 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, u8 tid = IWL_MAX_TID_COUNT; u8 txq_id = info->hw_queue; bool is_data_qos = false, is_ampdu = false; + int hdrlen; mvmsta = iwl_mvm_sta_from_mac80211(sta); fc = hdr->frame_control; + hdrlen = ieee80211_hdrlen(fc); if (WARN_ON_ONCE(!mvmsta)) return -1; @@ -437,7 +450,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) return -1; - dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id); + dev_cmd = iwl_mvm_set_tx_params(mvm, skb, hdrlen, sta, mvmsta->sta_id); if (!dev_cmd) goto drop; @@ -469,7 +482,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb, } /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, ieee80211_hdrlen(fc)); + memcpy(tx_cmd->hdr, hdr, hdrlen); WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); -- cgit v1.3-6-gb490 From 48ed7040315636f825c989e0752125ea275da82f Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Wed, 8 Jul 2015 11:02:15 -0400 Subject: iwlwifi: make various functions void in the file rs.c This makes various functions in the file rs.c void due to these functions never returning a error code to signal to their callers if and how they have failed to complete their intended work. Signed-off-by: Nicholas Krause Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/rs.c | 51 +++++++++++++++-------------------- 1 file changed, 21 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index 3bd7c86e90d9..cef921c1a623 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c @@ -1416,11 +1416,11 @@ static int rs_switch_to_siso(struct iwl_priv *priv, /* * Try to switch to new modulation mode from legacy */ -static int rs_move_legacy_other(struct iwl_priv *priv, - struct iwl_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct ieee80211_sta *sta, - int index) +static void rs_move_legacy_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct ieee80211_sta *sta, + int index) { struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); struct iwl_scale_tbl_info *search_tbl = @@ -1575,7 +1575,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv, } search_tbl->lq_type = LQ_NONE; - return 0; + return; out: lq_sta->search_better_tbl = 1; @@ -1584,17 +1584,15 @@ out: tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; if (update_search_tbl_counter) search_tbl->action = tbl->action; - return 0; - } /* * Try to switch to new modulation mode from SISO */ -static int rs_move_siso_to_other(struct iwl_priv *priv, - struct iwl_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct ieee80211_sta *sta, int index) +static void rs_move_siso_to_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct ieee80211_sta *sta, int index) { u8 is_green = lq_sta->is_green; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1747,7 +1745,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, break; } search_tbl->lq_type = LQ_NONE; - return 0; + return; out: lq_sta->search_better_tbl = 1; @@ -1756,17 +1754,15 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, tbl->action = IWL_SISO_SWITCH_ANTENNA1; if (update_search_tbl_counter) search_tbl->action = tbl->action; - - return 0; } /* * Try to switch to new modulation mode from MIMO2 */ -static int rs_move_mimo2_to_other(struct iwl_priv *priv, - struct iwl_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct ieee80211_sta *sta, int index) +static void rs_move_mimo2_to_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct ieee80211_sta *sta, int index) { s8 is_green = lq_sta->is_green; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -1917,7 +1913,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, break; } search_tbl->lq_type = LQ_NONE; - return 0; + return; out: lq_sta->search_better_tbl = 1; tbl->action++; @@ -1926,17 +1922,15 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, if (update_search_tbl_counter) search_tbl->action = tbl->action; - return 0; - } /* * Try to switch to new modulation mode from MIMO3 */ -static int rs_move_mimo3_to_other(struct iwl_priv *priv, - struct iwl_lq_sta *lq_sta, - struct ieee80211_conf *conf, - struct ieee80211_sta *sta, int index) +static void rs_move_mimo3_to_other(struct iwl_priv *priv, + struct iwl_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct ieee80211_sta *sta, int index) { s8 is_green = lq_sta->is_green; struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]); @@ -2093,7 +2087,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, break; } search_tbl->lq_type = LQ_NONE; - return 0; + return; out: lq_sta->search_better_tbl = 1; tbl->action++; @@ -2101,9 +2095,6 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, tbl->action = IWL_MIMO3_SWITCH_ANTENNA1; if (update_search_tbl_counter) search_tbl->action = tbl->action; - - return 0; - } /* -- cgit v1.3-6-gb490 From 6eb031d2fe2d9a3d7eaaba151c64e20bd0220fc9 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 13 Jul 2015 14:50:47 +0300 Subject: iwlwifi: add wide firmware command support for notifications Add support for extended command id in notification system. Extended command id header contains group id in addition to command id. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/dvm/rxon.c | 3 ++- drivers/net/wireless/iwlwifi/dvm/ucode.c | 5 +++-- drivers/net/wireless/iwlwifi/iwl-notif-wait.c | 8 +++++--- drivers/net/wireless/iwlwifi/iwl-notif-wait.h | 5 +++-- drivers/net/wireless/iwlwifi/iwl-trans.h | 3 +++ drivers/net/wireless/iwlwifi/mvm/d3.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/iwlwifi/mvm/scan.c | 2 +- drivers/net/wireless/iwlwifi/mvm/time-event.c | 4 ++-- drivers/net/wireless/iwlwifi/mvm/tt.c | 3 ++- 12 files changed, 26 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index f603fb3122f7..453f7c315ab5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -444,7 +444,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) u32 error_id; } err_info; struct iwl_notification_wait status_wait; - static const u8 status_cmd[] = { + static const u16 status_cmd[] = { REPLY_WOWLAN_GET_STATUS, }; struct iwlagn_wowlan_status status_data = {}; diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index ed50de6362ed..85ceceb34fcc 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH * * 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 @@ -123,7 +124,7 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, __le32 old_filter = send->filter_flags; u8 old_dev_type = send->dev_type; int ret; - static const u8 deactivate_cmd[] = { + static const u16 deactivate_cmd[] = { REPLY_WIPAN_DEACTIVATION_COMPLETE }; diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 5244e43bfafb..931a8e4269ef 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -3,6 +3,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH * * 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 @@ -327,7 +328,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv, const struct fw_img *fw; int ret; enum iwl_ucode_type old_type; - static const u8 alive_cmd[] = { REPLY_ALIVE }; + static const u16 alive_cmd[] = { REPLY_ALIVE }; fw = iwl_get_ucode_image(priv, ucode_type); if (WARN_ON(!fw)) @@ -406,7 +407,7 @@ static bool iwlagn_wait_calib(struct iwl_notif_wait_data *notif_wait, int iwl_run_init_ucode(struct iwl_priv *priv) { struct iwl_notification_wait calib_wait; - static const u8 calib_complete[] = { + static const u16 calib_complete[] = { CALIBRATION_RES_NOTIFICATION, CALIBRATION_COMPLETE_NOTIFICATION }; diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c index b5bc959b1dfe..6caf2affbbb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c +++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH * * 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 @@ -98,7 +99,8 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait, continue; for (i = 0; i < w->n_cmds; i++) { - if (w->cmds[i] == pkt->hdr.cmd) { + if (w->cmds[i] == + WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) { found = true; break; } @@ -136,7 +138,7 @@ IWL_EXPORT_SYMBOL(iwl_abort_notification_waits); void iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait, struct iwl_notification_wait *wait_entry, - const u8 *cmds, int n_cmds, + const u16 *cmds, int n_cmds, bool (*fn)(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt, void *data), void *fn_data) @@ -147,7 +149,7 @@ iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait, wait_entry->fn = fn; wait_entry->fn_data = fn_data; wait_entry->n_cmds = n_cmds; - memcpy(wait_entry->cmds, cmds, n_cmds); + memcpy(wait_entry->cmds, cmds, n_cmds * sizeof(u16)); wait_entry->triggered = false; wait_entry->aborted = false; diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h index 95af97a6c2cf..dbe8234521de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h +++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Deutschland GmbH * * 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 @@ -105,7 +106,7 @@ struct iwl_notification_wait { struct iwl_rx_packet *pkt, void *data); void *fn_data; - u8 cmds[MAX_NOTIF_CMDS]; + u16 cmds[MAX_NOTIF_CMDS]; u8 n_cmds; bool triggered, aborted; }; @@ -121,7 +122,7 @@ void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_data); void __acquires(wait_entry) iwl_init_notification_wait(struct iwl_notif_wait_data *notif_data, struct iwl_notification_wait *wait_entry, - const u8 *cmds, int n_cmds, + const u16 *cmds, int n_cmds, bool (*fn)(struct iwl_notif_wait_data *notif_data, struct iwl_rx_packet *pkt, void *data), void *fn_data); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index e698ed5e34cc..2f79e54823c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -148,6 +148,9 @@ static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) return opcode + (groupid << 8) + (version << 16); } +/* make u16 wide id out of u8 group and opcode */ +#define WIDE_ID(grp, opcode) ((grp << 8) | opcode) + /* due to the conversion, this group is special; new groups * should be defined in the appropriate fw-api header files */ diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index a85be4e9adcd..04264e417c1c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1145,7 +1145,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, static int iwl_mvm_enter_d0i3_sync(struct iwl_mvm *mvm) { struct iwl_notification_wait wait_d3; - static const u8 d3_notif[] = { D3_CONFIG_CMD }; + static const u16 d3_notif[] = { D3_CONFIG_CMD }; int ret; iwl_init_notification_wait(&mvm->notif_wait, &wait_d3, diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index ebda61bc66d6..106edc78c8bc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -213,7 +213,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, const struct fw_img *fw; int ret, i; enum iwl_ucode_type old_type = mvm->cur_ucode; - static const u8 alive_cmd[] = { MVM_ALIVE }; + static const u16 alive_cmd[] = { MVM_ALIVE }; struct iwl_sf_region st_fwrd_space; if (ucode_type == IWL_UCODE_REGULAR && @@ -314,7 +314,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) { struct iwl_notification_wait calib_wait; - static const u8 init_complete[] = { + static const u16 init_complete[] = { INIT_COMPLETE_NOTIF, CALIB_RES_NOTIF_PHY_DB }; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 5a4bf84aa260..9e641847c047 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -3019,7 +3019,7 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, int res, time_reg = DEVICE_SYSTEM_TIME_REG; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data; - static const u8 time_event_response[] = { HOT_SPOT_CMD }; + static const u16 time_event_response[] = { HOT_SPOT_CMD }; struct iwl_notification_wait wait_time_event; struct iwl_hs20_roc_req aux_roc_req = { .action = cpu_to_le32(FW_CTXT_ACTION_ADD), diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index d34b2e578358..8d7fefe77ddd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -1395,7 +1395,7 @@ static int iwl_mvm_umac_scan_abort(struct iwl_mvm *mvm, int type) static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) { struct iwl_notification_wait wait_scan_done; - static const u8 scan_done_notif[] = { SCAN_COMPLETE_UMAC, + static const u16 scan_done_notif[] = { SCAN_COMPLETE_UMAC, SCAN_OFFLOAD_COMPLETE, }; int ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 8fe7ecd75b92..c0d09af5b1f7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -500,7 +500,7 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, struct iwl_mvm_time_event_data *te_data, struct iwl_time_event_cmd *te_cmd) { - static const u8 time_event_response[] = { TIME_EVENT_CMD }; + static const u16 time_event_response[] = { TIME_EVENT_CMD }; struct iwl_notification_wait wait_time_event; int ret; @@ -563,7 +563,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; - const u8 te_notif_response[] = { TIME_EVENT_NOTIFICATION }; + const u16 te_notif_response[] = { TIME_EVENT_NOTIFICATION }; struct iwl_notification_wait wait_te_notif; struct iwl_time_event_cmd time_cmd = {}; diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index 7e88d3929119..fe7145c2c98a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -33,6 +33,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -183,7 +184,7 @@ static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) int iwl_mvm_get_temp(struct iwl_mvm *mvm) { struct iwl_notification_wait wait_temp_notif; - static const u8 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION }; + static const u16 temp_notif[] = { DTS_MEASUREMENT_NOTIFICATION }; int ret, temp; lockdep_assert_held(&mvm->mutex); -- cgit v1.3-6-gb490 From 1230b16b448acfdfe7d0cac940311c9363861c03 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Thu, 9 Jul 2015 17:17:03 +0300 Subject: iwlwifi: mvm: add wide firmware command infrastructure for RX Add support for extended firmware event header that contains a group id as well as the command id. Signed-off-by: Avraham Stern Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index c9b9c98c6ff8..a424d95a1965 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -201,13 +201,15 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) } struct iwl_rx_handlers { - u8 cmd_id; + u16 cmd_id; bool async; void (*fn)(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); }; #define RX_HANDLER(_cmd_id, _fn, _async) \ { .cmd_id = _cmd_id , .fn = _fn , .async = _async } +#define RX_HANDLER_GRP(_grp, _cmd, _fn, _async) \ + { .cmd_id = WIDE_ID(_grp, _cmd), .fn = _fn, .async = _async } /* * Handlers for fw notifications @@ -263,6 +265,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { }; #undef RX_HANDLER +#undef RX_HANDLER_GRP #define CMD(x) [x] = #x static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { @@ -735,7 +738,7 @@ static void iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i]; struct iwl_async_handler_entry *entry; - if (rx_h->cmd_id != pkt->hdr.cmd) + if (rx_h->cmd_id != WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) continue; if (!rx_h->async) { -- cgit v1.3-6-gb490 From 0ab66e6d28f52677067a905ff2aac3367f8118ee Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Mon, 13 Jul 2015 14:23:59 +0300 Subject: iwlwifi: mvm: add wide firmware command support for debug triggers Add support for extended command id in triggers handling. Extended command id header contains group id in addition to command id. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index a424d95a1965..6957d026e4bd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -703,12 +703,13 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, if (!cmds_trig->cmds[i].cmd_id) break; - if (cmds_trig->cmds[i].cmd_id != pkt->hdr.cmd) + if (cmds_trig->cmds[i].cmd_id != pkt->hdr.cmd || + cmds_trig->cmds[i].group_id != pkt->hdr.group_id) continue; iwl_mvm_fw_dbg_collect_trig(mvm, trig, - "CMD 0x%02x received", - pkt->hdr.cmd); + "CMD 0x%02x.%02x received", + pkt->hdr.group_id, pkt->hdr.cmd); break; } } -- cgit v1.3-6-gb490 From a6c4fb4441f4641609bbb3e40da438ed57629db0 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Wed, 15 Jul 2015 16:19:29 +0300 Subject: iwlwifi: mvm: Add FW paging mechanism for the UMAC on PCI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Family 8000 products has 2 embedded processors, the first known as LMAC (lower MAC) and implements the functionality from previous products, the second one is known as UMAC (upper MAC) and is used mainly for driver offloads as well as new features. The UMAC is typically “less” real-time than the LMAC and is used for higher level controls. The UMAC's code/data size is estimated to be in the mega-byte arena, taking into account the code it needs to replace in the driver and the set of new features. In order to allow the UMAC to execute code that is bigger than its code memory, we allow the UMAC embedded processor to page out code pages on DRAM. When the device is master on the bus(PCI) the driver saves the UMAC's image pages in blocks of 32K in the DRAM and sends the layout of the pages to the FW. The FW can load / unload the pages on its own. The driver can support up to 1 MB of pages. Add paging mechanism for the UMAC on PCI in order to allow the program to use a larger virtual space while using less physical memory on the device. Signed-off-by: Eran Harary Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 32 +++- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 4 +- drivers/net/wireless/iwlwifi/iwl-fw.h | 40 +++++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 24 +++ drivers/net/wireless/iwlwifi/mvm/fw.c | 258 +++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/mvm.h | 5 + drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + drivers/net/wireless/iwlwifi/pcie/trans.c | 18 +- 8 files changed, 378 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 6685259927f8..721d3cb94386 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -573,10 +573,11 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, size_t len = ucode_raw->size; const u8 *data; u32 tlv_len; + u32 usniffer_img; enum iwl_ucode_tlv_type tlv_type; const u8 *tlv_data; char buildstr[25]; - u32 build; + u32 build, paging_mem_size; int num_of_cpus; bool usniffer_images = false; bool usniffer_req = false; @@ -955,6 +956,35 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, IWL_UCODE_REGULAR_USNIFFER, tlv_len); break; + case IWL_UCODE_TLV_PAGING: + if (tlv_len != sizeof(u32)) + goto invalid_tlv_len; + paging_mem_size = le32_to_cpup((__le32 *)tlv_data); + + IWL_DEBUG_FW(drv, + "Paging: paging enabled (size = %u bytes)\n", + paging_mem_size); + + if (paging_mem_size > MAX_PAGING_IMAGE_SIZE) { + IWL_ERR(drv, + "Paging: driver supports up to %lu bytes for paging image\n", + MAX_PAGING_IMAGE_SIZE); + return -EINVAL; + } + + if (paging_mem_size & (FW_PAGING_SIZE - 1)) { + IWL_ERR(drv, + "Paging: image isn't multiple %lu\n", + FW_PAGING_SIZE); + return -EINVAL; + } + + drv->fw.img[IWL_UCODE_REGULAR].paging_mem_size = + paging_mem_size; + usniffer_img = IWL_UCODE_REGULAR_USNIFFER; + drv->fw.img[usniffer_img].paging_mem_size = + paging_mem_size; + break; case IWL_UCODE_TLV_SDIO_ADMA_ADDR: if (tlv_len != sizeof(u32)) goto invalid_tlv_len; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 926e4568d36c..5d7f2d9cf180 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -132,6 +132,7 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_API_CHANGES_SET = 29, IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30, IWL_UCODE_TLV_N_SCAN_CHANNELS = 31, + IWL_UCODE_TLV_PAGING = 32, IWL_UCODE_TLV_SEC_RT_USNIFFER = 34, IWL_UCODE_TLV_SDIO_ADMA_ADDR = 35, IWL_UCODE_TLV_FW_VERSION = 36, @@ -343,8 +344,9 @@ enum iwl_ucode_tlv_capa { * For 16.0 uCode and above, there is no differentiation between sections, * just an offset to the HW address. */ -#define IWL_UCODE_SECTION_MAX 12 +#define IWL_UCODE_SECTION_MAX 16 #define CPU1_CPU2_SEPARATOR_SECTION 0xFFFFCCCC +#define PAGING_SEPARATOR_SECTION 0xAAAABBBB /* uCode version contains 4 values: Major/Minor/API/Serial */ #define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 3e3c9d8b3c37..224c7f45d2f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -133,6 +133,7 @@ struct fw_desc { struct fw_img { struct fw_desc sec[IWL_UCODE_SECTION_MAX]; bool is_dual_cpus; + u32 paging_mem_size; }; struct iwl_sf_region { @@ -140,6 +141,45 @@ struct iwl_sf_region { u32 size; }; +/* + * Block paging calculations + */ +#define PAGE_2_EXP_SIZE 12 /* 4K == 2^12 */ +#define FW_PAGING_SIZE BIT(PAGE_2_EXP_SIZE) /* page size is 4KB */ +#define PAGE_PER_GROUP_2_EXP_SIZE 3 +/* 8 pages per group */ +#define NUM_OF_PAGE_PER_GROUP BIT(PAGE_PER_GROUP_2_EXP_SIZE) +/* don't change, support only 32KB size */ +#define PAGING_BLOCK_SIZE (NUM_OF_PAGE_PER_GROUP * FW_PAGING_SIZE) +/* 32K == 2^15 */ +#define BLOCK_2_EXP_SIZE (PAGE_2_EXP_SIZE + PAGE_PER_GROUP_2_EXP_SIZE) + +/* + * Image paging calculations + */ +#define BLOCK_PER_IMAGE_2_EXP_SIZE 5 +/* 2^5 == 32 blocks per image */ +#define NUM_OF_BLOCK_PER_IMAGE BIT(BLOCK_PER_IMAGE_2_EXP_SIZE) +/* maximum image size 1024KB */ +#define MAX_PAGING_IMAGE_SIZE (NUM_OF_BLOCK_PER_IMAGE * PAGING_BLOCK_SIZE) + +#define PAGING_CMD_IS_SECURED BIT(9) +#define PAGING_CMD_IS_ENABLED BIT(8) +#define PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS 0 +#define PAGING_TLV_SECURE_MASK 1 + +/** + * struct iwl_fw_paging + * @fw_paging_phys: page phy pointer + * @fw_paging_block: pointer to the allocated block + * @fw_paging_size: page size + */ +struct iwl_fw_paging { + dma_addr_t fw_paging_phys; + struct page *fw_paging_block; + u32 fw_paging_size; +}; + /** * struct iwl_fw_cscheme_list - a cipher scheme list * @size: a number of entries diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 4e29c11cc969..9c6b153f2e12 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -149,6 +149,9 @@ enum { LQ_CMD = 0x4e, + /* paging block to FW cpu2 */ + FW_PAGING_BLOCK_CMD = 0x4f, + /* Scan offload */ SCAN_OFFLOAD_REQUEST_CMD = 0x51, SCAN_OFFLOAD_ABORT_CMD = 0x52, @@ -370,6 +373,27 @@ struct iwl_nvm_access_cmd { u8 data[]; } __packed; /* NVM_ACCESS_CMD_API_S_VER_2 */ +#define NUM_OF_FW_PAGING_BLOCKS 33 /* 32 for data and 1 block for CSS */ + +/* + * struct iwl_fw_paging_cmd - paging layout + * + * (FW_PAGING_BLOCK_CMD = 0x4f) + * + * Send to FW the paging layout in the driver. + * + * @flags: various flags for the command + * @block_size: the block size in powers of 2 + * @block_num: number of blocks specified in the command. + * @device_phy_addr: virtual addresses from device side +*/ +struct iwl_fw_paging_cmd { + __le32 flags; + __le32 block_size; + __le32 block_num; + __le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; +} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */ + /** * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD * @offset: offset in bytes into the section diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 106edc78c8bc..acb402b3e6ee 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -106,6 +106,244 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) sizeof(tx_ant_cmd), &tx_ant_cmd); } +static void iwl_free_fw_paging(struct iwl_mvm *mvm) +{ + int i; + + if (!mvm->fw_paging_db[0].fw_paging_block) + return; + + for (i = 0; i < NUM_OF_FW_PAGING_BLOCKS; i++) { + if (!mvm->fw_paging_db[i].fw_paging_block) { + IWL_DEBUG_FW(mvm, + "Paging: block %d already freed, continue to next page\n", + i); + + continue; + } + + __free_pages(mvm->fw_paging_db[i].fw_paging_block, + get_order(mvm->fw_paging_db[i].fw_paging_size)); + } + memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db)); +} + +static int iwl_fill_paging_mem(struct iwl_mvm *mvm, const struct fw_img *image) +{ + int sec_idx, idx; + u32 offset = 0; + + /* + * find where is the paging image start point: + * if CPU2 exist and it's in paging format, then the image looks like: + * CPU1 sections (2 or more) + * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between CPU1 to CPU2 + * CPU2 sections (not paged) + * PAGING_SEPARATOR_SECTION delimiter - separate between CPU2 + * non paged to CPU2 paging sec + * CPU2 paging CSS + * CPU2 paging image (including instruction and data) + */ + for (sec_idx = 0; sec_idx < IWL_UCODE_SECTION_MAX; sec_idx++) { + if (image->sec[sec_idx].offset == PAGING_SEPARATOR_SECTION) { + sec_idx++; + break; + } + } + + if (sec_idx >= IWL_UCODE_SECTION_MAX) { + IWL_ERR(mvm, "driver didn't find paging image\n"); + iwl_free_fw_paging(mvm); + return -EINVAL; + } + + /* copy the CSS block to the dram */ + IWL_DEBUG_FW(mvm, "Paging: load paging CSS to FW, sec = %d\n", + sec_idx); + + memcpy(page_address(mvm->fw_paging_db[0].fw_paging_block), + image->sec[sec_idx].data, + mvm->fw_paging_db[0].fw_paging_size); + + IWL_DEBUG_FW(mvm, + "Paging: copied %d CSS bytes to first block\n", + mvm->fw_paging_db[0].fw_paging_size); + + sec_idx++; + + /* + * copy the paging blocks to the dram + * loop index start from 1 since that CSS block already copied to dram + * and CSS index is 0. + * loop stop at num_of_paging_blk since that last block is not full. + */ + for (idx = 1; idx < mvm->num_of_paging_blk; idx++) { + memcpy(page_address(mvm->fw_paging_db[idx].fw_paging_block), + image->sec[sec_idx].data + offset, + mvm->fw_paging_db[idx].fw_paging_size); + + IWL_DEBUG_FW(mvm, + "Paging: copied %d paging bytes to block %d\n", + mvm->fw_paging_db[idx].fw_paging_size, + idx); + + offset += mvm->fw_paging_db[idx].fw_paging_size; + } + + /* copy the last paging block */ + if (mvm->num_of_pages_in_last_blk > 0) { + memcpy(page_address(mvm->fw_paging_db[idx].fw_paging_block), + image->sec[sec_idx].data + offset, + FW_PAGING_SIZE * mvm->num_of_pages_in_last_blk); + + IWL_DEBUG_FW(mvm, + "Paging: copied %d pages in the last block %d\n", + mvm->num_of_pages_in_last_blk, idx); + } + + return 0; +} + +static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm, + const struct fw_img *image) +{ + struct page *block; + dma_addr_t phys = 0; + int blk_idx = 0; + int order, num_of_pages; + int dma_enabled; + + if (mvm->fw_paging_db[0].fw_paging_block) + return 0; + + dma_enabled = is_device_dma_capable(mvm->trans->dev); + + /* ensure BLOCK_2_EXP_SIZE is power of 2 of PAGING_BLOCK_SIZE */ + BUILD_BUG_ON(BIT(BLOCK_2_EXP_SIZE) != PAGING_BLOCK_SIZE); + + num_of_pages = image->paging_mem_size / FW_PAGING_SIZE; + mvm->num_of_paging_blk = ((num_of_pages - 1) / + NUM_OF_PAGE_PER_GROUP) + 1; + + mvm->num_of_pages_in_last_blk = + num_of_pages - + NUM_OF_PAGE_PER_GROUP * (mvm->num_of_paging_blk - 1); + + IWL_DEBUG_FW(mvm, + "Paging: allocating mem for %d paging blocks, each block holds 8 pages, last block holds %d pages\n", + mvm->num_of_paging_blk, + mvm->num_of_pages_in_last_blk); + + /* allocate block of 4Kbytes for paging CSS */ + order = get_order(FW_PAGING_SIZE); + block = alloc_pages(GFP_KERNEL, order); + if (!block) { + /* free all the previous pages since we failed */ + iwl_free_fw_paging(mvm); + return -ENOMEM; + } + + mvm->fw_paging_db[blk_idx].fw_paging_block = block; + mvm->fw_paging_db[blk_idx].fw_paging_size = FW_PAGING_SIZE; + + if (dma_enabled) { + phys = dma_map_page(mvm->trans->dev, block, 0, + PAGE_SIZE << order, DMA_BIDIRECTIONAL); + if (dma_mapping_error(mvm->trans->dev, phys)) { + /* + * free the previous pages and the current one since + * we failed to map_page. + */ + iwl_free_fw_paging(mvm); + return -ENOMEM; + } + mvm->fw_paging_db[blk_idx].fw_paging_phys = phys; + } + + IWL_DEBUG_FW(mvm, + "Paging: allocated 4K(CSS) bytes (order %d) for firmware paging.\n", + order); + + /* + * allocate blocks in dram. + * since that CSS allocated in fw_paging_db[0] loop start from index 1 + */ + for (blk_idx = 1; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) { + /* allocate block of PAGING_BLOCK_SIZE (32K) */ + order = get_order(PAGING_BLOCK_SIZE); + block = alloc_pages(GFP_KERNEL, order); + if (!block) { + /* free all the previous pages since we failed */ + iwl_free_fw_paging(mvm); + return -ENOMEM; + } + + mvm->fw_paging_db[blk_idx].fw_paging_block = block; + mvm->fw_paging_db[blk_idx].fw_paging_size = PAGING_BLOCK_SIZE; + + if (dma_enabled) { + phys = dma_map_page(mvm->trans->dev, block, 0, + PAGE_SIZE << order, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(mvm->trans->dev, phys)) { + /* + * free the previous pages and the current one + * since we failed to map_page. + */ + iwl_free_fw_paging(mvm); + return -ENOMEM; + } + mvm->fw_paging_db[blk_idx].fw_paging_phys = phys; + } + + IWL_DEBUG_FW(mvm, + "Paging: allocated 32K bytes (order %d) for firmware paging.\n", + order); + } + + return 0; +} + +static int iwl_save_fw_paging(struct iwl_mvm *mvm, + const struct fw_img *fw) +{ + int ret; + + ret = iwl_alloc_fw_paging_mem(mvm, fw); + if (ret) + return ret; + + return iwl_fill_paging_mem(mvm, fw); +} + +/* send paging cmd to FW in case CPU2 has paging image */ +static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw) +{ + int blk_idx; + __le32 dev_phy_addr; + struct iwl_fw_paging_cmd fw_paging_cmd = { + .flags = + cpu_to_le32(PAGING_CMD_IS_SECURED | + PAGING_CMD_IS_ENABLED | + (mvm->num_of_pages_in_last_blk << + PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), + .block_size = cpu_to_le32(BLOCK_2_EXP_SIZE), + .block_num = cpu_to_le32(mvm->num_of_paging_blk), + }; + + /* loop for for all paging blocks + CSS block */ + for (blk_idx = 0; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) { + dev_phy_addr = + cpu_to_le32(mvm->fw_paging_db[blk_idx].fw_paging_phys >> + PAGE_2_EXP_SIZE); + fw_paging_cmd.device_phy_addr[blk_idx] = dev_phy_addr; + } + + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(FW_PAGING_BLOCK_CMD, + IWL_ALWAYS_LONG_GROUP, 0), + 0, sizeof(fw_paging_cmd), &fw_paging_cmd); +} + static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt, void *data) { @@ -268,6 +506,26 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, iwl_trans_fw_alive(mvm->trans, alive_data.scd_base_addr); + /* + * configure and operate fw paging mechanism. + * driver configures the paging flow only once, CPU2 paging image + * included in the IWL_UCODE_INIT image. + */ + if (fw->paging_mem_size) { + ret = iwl_save_fw_paging(mvm, fw); + if (ret) { + IWL_ERR(mvm, "failed to save the FW paging image\n"); + return ret; + } + + ret = iwl_send_paging_cmd(mvm, fw); + if (ret) { + IWL_ERR(mvm, "failed to send the paging cmd\n"); + iwl_free_fw_paging(mvm); + return ret; + } + } + /* * Note: all the queues are enabled as part of the interface * initialization, but in firmware restart scenarios they diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 95f326dc0b1f..fdf401b696a4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -610,6 +610,11 @@ struct iwl_mvm { /* NVM sections */ struct iwl_nvm_section nvm_sections[NVM_MAX_NUM_SECTIONS]; + /* Paging section */ + struct iwl_fw_paging fw_paging_db[NUM_OF_FW_PAGING_BLOCKS]; + u16 num_of_paging_blk; + u16 num_of_pages_in_last_blk; + /* EEPROM MAC addresses */ struct mac_address addresses[IWL_MVM_MAX_ADDRESSES]; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 6957d026e4bd..ef09a05b6ddb 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -288,6 +288,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(PHY_CONFIGURATION_CMD), CMD(CALIB_RES_NOTIF_PHY_DB), CMD(SET_CALIB_DEFAULT_CMD), + CMD(FW_PAGING_BLOCK_CMD), CMD(ADD_STA_KEY), CMD(ADD_STA), CMD(REMOVE_STA), diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index cbc29ccc6a00..8cc8f2b703a2 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -764,8 +764,15 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans, for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) { last_read_idx = i; + /* + * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between + * CPU1 to CPU2. + * PAGING_SEPARATOR_SECTION delimiter - separate between + * CPU2 non paged to CPU2 paging sec. + */ if (!image->sec[i].data || - image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) { + image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION || + image->sec[i].offset == PAGING_SEPARATOR_SECTION) { IWL_DEBUG_FW(trans, "Break since Data not valid or Empty section, sec = %d\n", i); @@ -813,8 +820,15 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, for (i = *first_ucode_section; i < IWL_UCODE_SECTION_MAX; i++) { last_read_idx = i; + /* + * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between + * CPU1 to CPU2. + * PAGING_SEPARATOR_SECTION delimiter - separate between + * CPU2 non paged to CPU2 paging sec. + */ if (!image->sec[i].data || - image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION) { + image->sec[i].offset == CPU1_CPU2_SEPARATOR_SECTION || + image->sec[i].offset == PAGING_SEPARATOR_SECTION) { IWL_DEBUG_FW(trans, "Break since Data not valid or Empty section, sec = %d\n", i); -- cgit v1.3-6-gb490 From 75118fdb63496e4611ab50380499ddd62b9de69f Mon Sep 17 00:00:00 2001 From: David Spinadel Date: Wed, 24 Jun 2015 11:03:56 +0300 Subject: iwlwifi: mvm: clean up fw-api-scan.h Remove outdated and unused definitions Signed-off-by: David Spinadel Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 129 ------------------------- 1 file changed, 129 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 4787c32b3a61..be9b66560801 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -87,41 +87,6 @@ struct iwl_ssid_ie { u8 ssid[IEEE80211_MAX_SSID_LEN]; } __packed; /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */ -/* How many statistics are gathered for each channel */ -#define SCAN_RESULTS_STATISTICS 1 - -/** - * enum iwl_scan_complete_status - status codes for scan complete notifications - * @SCAN_COMP_STATUS_OK: scan completed successfully - * @SCAN_COMP_STATUS_ABORT: scan was aborted by user - * @SCAN_COMP_STATUS_ERR_SLEEP: sending null sleep packet failed - * @SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT: timeout before channel is ready - * @SCAN_COMP_STATUS_ERR_PROBE: sending probe request failed - * @SCAN_COMP_STATUS_ERR_WAKEUP: sending null wakeup packet failed - * @SCAN_COMP_STATUS_ERR_ANTENNAS: invalid antennas chosen at scan command - * @SCAN_COMP_STATUS_ERR_INTERNAL: internal error caused scan abort - * @SCAN_COMP_STATUS_ERR_COEX: medium was lost ot WiMax - * @SCAN_COMP_STATUS_P2P_ACTION_OK: P2P public action frame TX was successful - * (not an error!) - * @SCAN_COMP_STATUS_ITERATION_END: indicates end of one repetition the driver - * asked for - * @SCAN_COMP_STATUS_ERR_ALLOC_TE: scan could not allocate time events -*/ -enum iwl_scan_complete_status { - SCAN_COMP_STATUS_OK = 0x1, - SCAN_COMP_STATUS_ABORT = 0x2, - SCAN_COMP_STATUS_ERR_SLEEP = 0x3, - SCAN_COMP_STATUS_ERR_CHAN_TIMEOUT = 0x4, - SCAN_COMP_STATUS_ERR_PROBE = 0x5, - SCAN_COMP_STATUS_ERR_WAKEUP = 0x6, - SCAN_COMP_STATUS_ERR_ANTENNAS = 0x7, - SCAN_COMP_STATUS_ERR_INTERNAL = 0x8, - SCAN_COMP_STATUS_ERR_COEX = 0x9, - SCAN_COMP_STATUS_P2P_ACTION_OK = 0xA, - SCAN_COMP_STATUS_ITERATION_END = 0x0B, - SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C, -}; - /* scan offload */ #define IWL_SCAN_MAX_BLACKLIST_LEN 64 #define IWL_SCAN_SHORT_BLACKLIST_LEN 16 @@ -143,71 +108,6 @@ enum scan_framework_client { SCAN_CLIENT_ASSET_TRACKING = BIT(2), }; -/** - * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6 - * @scan_flags: see enum iwl_scan_flags - * @channel_count: channels in channel list - * @quiet_time: dwell time, in milliseconds, on quiet channel - * @quiet_plcp_th: quiet channel num of packets threshold - * @good_CRC_th: passive to active promotion threshold - * @rx_chain: RXON rx chain. - * @max_out_time: max TUs to be out of associated channel - * @suspend_time: pause scan this TUs when returning to service channel - * @flags: RXON flags - * @filter_flags: RXONfilter - * @tx_cmd: tx command for active scan; for 2GHz and for 5GHz. - * @direct_scan: list of SSIDs for directed active scan - * @scan_type: see enum iwl_scan_type. - * @rep_count: repetition count for each scheduled scan iteration. - */ -struct iwl_scan_offload_cmd { - __le16 len; - u8 scan_flags; - u8 channel_count; - __le16 quiet_time; - __le16 quiet_plcp_th; - __le16 good_CRC_th; - __le16 rx_chain; - __le32 max_out_time; - __le32 suspend_time; - /* RX_ON_FLAGS_API_S_VER_1 */ - __le32 flags; - __le32 filter_flags; - struct iwl_tx_cmd tx_cmd[2]; - /* SCAN_DIRECT_SSID_IE_API_S_VER_1 */ - struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; - __le32 scan_type; - __le32 rep_count; -} __packed; - -enum iwl_scan_offload_channel_flags { - IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE = BIT(0), - IWL_SCAN_OFFLOAD_CHANNEL_NARROW = BIT(22), - IWL_SCAN_OFFLOAD_CHANNEL_FULL = BIT(24), - IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL = BIT(25), -}; - -/* channel configuration for struct iwl_scan_offload_cfg. Each channels needs: - * __le32 type: bitmap; bits 1-20 are for directed scan to i'th ssid and - * see enum iwl_scan_offload_channel_flags. - * __le16 channel_number: channel number 1-13 etc. - * __le16 iter_count: repetition count for the channel. - * __le32 iter_interval: interval between two iterations on one channel. - * u8 active_dwell. - * u8 passive_dwell. - */ -#define IWL_SCAN_CHAN_SIZE 14 - -/** - * iwl_scan_offload_cfg - SCAN_OFFLOAD_CONFIG_API_S - * @scan_cmd: scan command fixed part - * @data: scan channel configuration and probe request frames - */ -struct iwl_scan_offload_cfg { - struct iwl_scan_offload_cmd scan_cmd; - u8 data[0]; -} __packed; - /** * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S * @ssid: MAC address to filter out @@ -297,35 +197,6 @@ enum iwl_scan_ebs_status { IWL_SCAN_EBS_INACTIVE, }; -/** - * iwl_scan_offload_complete - SCAN_OFFLOAD_COMPLETE_NTF_API_S_VER_1 - * @last_schedule_line: last schedule line executed (fast or regular) - * @last_schedule_iteration: last scan iteration executed before scan abort - * @status: enum iwl_scan_offload_compleate_status - * @ebs_status: last EBS status, see IWL_SCAN_EBS_* - */ -struct iwl_scan_offload_complete { - u8 last_schedule_line; - u8 last_schedule_iteration; - u8 status; - u8 ebs_status; -} __packed; - -/** - * iwl_sched_scan_results - SCAN_OFFLOAD_MATCH_FOUND_NTF_API_S_VER_1 - * @ssid_bitmap: SSIDs indexes found in this iteration - * @client_bitmap: clients that are active and wait for this notification - */ -struct iwl_sched_scan_results { - __le16 ssid_bitmap; - u8 client_bitmap; - u8 reserved; -}; - -/* Unified LMAC scan API */ - -#define IWL_MVM_BASIC_PASSIVE_DWELL 110 - /** * iwl_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S * @tx_flags: combination of TX_CMD_FLG_* -- cgit v1.3-6-gb490 From 192de2b406ab5cab0b87be6d8015dcfbec936e37 Mon Sep 17 00:00:00 2001 From: Dor Shaish Date: Wed, 15 Jul 2015 11:41:21 +0300 Subject: iwlwifi: mvm: print secboot status registers on alive timeout Print the CPU1 and CPU2 secured boot status registers from the NIC to indicate a SYSASSERT during secured engine unlocking process on init/protocol image. Signed-off-by: Dor Shaish Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-prph.h | 2 ++ drivers/net/wireless/iwlwifi/mvm/fw.c | 5 +++++ 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index cd98b9f45415..c4e7a713af0f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -383,6 +383,8 @@ enum aux_misc_master1_en { #define AUX_MISC_MASTER1_SMPHR_STATUS 0xA20800 #define RSA_ENABLE 0xA24B08 #define PREG_AUX_BUS_WPROT_0 0xA04CC0 +#define SB_CPU_1_STATUS 0xA01E30 +#define SB_CPU_2_STATUS 0xA01E34 /* FW chicken bits */ #define LMPM_CHICK 0xA01FF8 diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index acb402b3e6ee..e65a65337792 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -482,6 +482,11 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, ret = iwl_wait_notification(&mvm->notif_wait, &alive_wait, MVM_UCODE_ALIVE_TIMEOUT); if (ret) { + if (mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + IWL_ERR(mvm, + "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", + iwl_read_prph(mvm->trans, SB_CPU_1_STATUS), + iwl_read_prph(mvm->trans, SB_CPU_2_STATUS)); mvm->cur_ucode = old_type; return ret; } -- cgit v1.3-6-gb490 From bd7fc617af118531e364d727ed02b0ded2bb4fc0 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 15 Jul 2015 23:15:08 +0300 Subject: iwlwifi: pcie: dump RBs when FW error occurs Add support for dumping all the RBs in the RX queue when FW error occurs. This will assist debugging. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h | 17 +++++++ drivers/net/wireless/iwlwifi/pcie/trans.c | 59 +++++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h index e57dbd0ef2e1..af5b3201492c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h @@ -84,6 +84,8 @@ * @IWL_FW_ERROR_DUMP_MEM: chunk of memory * @IWL_FW_ERROR_DUMP_ERROR_INFO: description of what triggered this dump. * Structured as &struct iwl_fw_error_dump_trigger_desc. + * @IWL_FW_ERROR_DUMP_RB: the content of an RB structured as + * &struct iwl_fw_error_dump_rb */ enum iwl_fw_error_dump_type { /* 0 is deprecated */ @@ -97,6 +99,7 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_FH_REGS = 8, IWL_FW_ERROR_DUMP_MEM = 9, IWL_FW_ERROR_DUMP_ERROR_INFO = 10, + IWL_FW_ERROR_DUMP_RB = 11, IWL_FW_ERROR_DUMP_MAX, }; @@ -222,6 +225,20 @@ struct iwl_fw_error_dump_mem { u8 data[]; }; +/** + * struct iwl_fw_error_dump_rb - content of an Receive Buffer + * @index: the index of the Receive Buffer in the Rx queue + * @rxq: the RB's Rx queue + * @reserved: + * @data: the content of the Receive Buffer + */ +struct iwl_fw_error_dump_rb { + __le32 index; + __le32 rxq; + __le32 reserved; + u8 data[]; +}; + /** * iwl_fw_error_next_data - advance fw error dump data pointer * @data: previous data block diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 8cc8f2b703a2..9ebdd8009717 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2275,6 +2275,47 @@ static u32 iwl_trans_pcie_dump_prph(struct iwl_trans *trans, return prph_len; } +static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans, + struct iwl_fw_error_dump_data **data, + int allocated_rb_nums) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int max_len = PAGE_SIZE << trans_pcie->rx_page_order; + struct iwl_rxq *rxq = &trans_pcie->rxq; + u32 i, r, j, rb_len = 0; + + spin_lock(&rxq->lock); + + r = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num)) & 0x0FFF; + + for (i = rxq->read, j = 0; + i != r && j < allocated_rb_nums; + i = (i + 1) & RX_QUEUE_MASK, j++) { + struct iwl_rx_mem_buffer *rxb = rxq->queue[i]; + struct iwl_fw_error_dump_rb *rb; + + dma_unmap_page(trans->dev, rxb->page_dma, max_len, + DMA_FROM_DEVICE); + + rb_len += sizeof(**data) + sizeof(*rb) + max_len; + + (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RB); + (*data)->len = cpu_to_le32(sizeof(*rb) + max_len); + rb = (void *)(*data)->data; + rb->index = cpu_to_le32(i); + memcpy(rb->data, page_address(rxb->page), max_len); + /* remap the page for the free benefit */ + rxb->page_dma = dma_map_page(trans->dev, rxb->page, 0, + max_len, + DMA_FROM_DEVICE); + + *data = iwl_fw_error_next_data(*data); + } + + spin_unlock(&rxq->lock); + + return rb_len; +} #define IWL_CSR_TO_DUMP (0x250) static u32 iwl_trans_pcie_dump_csr(struct iwl_trans *trans, @@ -2352,9 +2393,10 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) struct iwl_txq *cmdq = &trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_fw_error_dump_txcmd *txcmd; struct iwl_trans_dump_data *dump_data; - u32 len; + u32 len, num_rbs; u32 monitor_len; int i, ptr; + bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status); /* transport dump header */ len = sizeof(*dump_data); @@ -2379,6 +2421,17 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) /* FH registers */ len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); + if (dump_rbs) { + /* RBs */ + num_rbs = le16_to_cpu(ACCESS_ONCE( + trans_pcie->rxq.rb_stts->closed_rb_num)) + & 0x0FFF; + num_rbs = (num_rbs - trans_pcie->rxq.read) & RX_QUEUE_MASK; + len += num_rbs * (sizeof(*data) + + sizeof(struct iwl_fw_error_dump_rb) + + (PAGE_SIZE << trans_pcie->rx_page_order)); + } + /* FW monitor */ if (trans_pcie->fw_mon_page) { len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + @@ -2442,8 +2495,10 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) len += iwl_trans_pcie_dump_prph(trans, &data); len += iwl_trans_pcie_dump_csr(trans, &data); len += iwl_trans_pcie_fh_regs_dump(trans, &data); - /* data is already pointing to the next section */ + if (dump_rbs) + len += iwl_trans_pcie_dump_rbs(trans, &data, num_rbs); + /* data is already pointing to the next section */ if ((trans_pcie->fw_mon_page && trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || trans->dbg_dest_tlv) { -- cgit v1.3-6-gb490 From be681c7d103c4b3df5c51acaba5a578002a16488 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Thu, 18 Jun 2015 06:39:41 +0300 Subject: iwlwifi: mvm: revert to our old skip over dtim policy Our firmware scheduler used to suffer from false wake-up on 500 time units. We had to came up with a formula to address this buggy behavior. Now that our firmware is fixed, we can go back to our old policy. Signed-off-by: Avri Altman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/power.c | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 506294fc2f87..c4e08903366c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -288,27 +288,6 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm, return true; } -static int iwl_mvm_power_get_skip_over_dtim(int dtimper, int bi) -{ - int numerator; - int dtim_interval = dtimper * bi; - - if (WARN_ON(!dtim_interval)) - return 0; - - if (dtimper == 1) { - if (bi > 100) - numerator = 408; - else - numerator = 510; - } else if (dtimper < 10) { - numerator = 612; - } else { - return 0; - } - return max(1, (numerator / dtim_interval)); -} - static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif) { struct ieee80211_chanctx_conf *chanctx_conf; @@ -378,11 +357,8 @@ static void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, if (!radar_detect && (dtimper < 10) && (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP || mvm->cur_ucode == IWL_UCODE_WOWLAN)) { - cmd->skip_dtim_periods = - iwl_mvm_power_get_skip_over_dtim(dtimper, bi); - if (cmd->skip_dtim_periods) - cmd->flags |= - cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); + cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); + cmd->skip_dtim_periods = 3; } if (mvm->cur_ucode != IWL_UCODE_WOWLAN) { -- cgit v1.3-6-gb490 From 9d012d0dbee1dcc4f7491925de41b4249b2cfb31 Mon Sep 17 00:00:00 2001 From: Alexander Bondar Date: Thu, 4 Jun 2015 10:32:43 +0300 Subject: iwlwifi: Add max TX aggregation size for 8260 SDIO devices series Set max TX aggregation size for 8260 SDIO devices series to 40 frames. Fine tune max RX aggregation size - change it to 21. Signed-off-by: Alexander Bondar Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-8000.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 7caea69570d4..92709ad5de44 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -97,8 +97,9 @@ #define DEFAULT_NVM_FILE_FAMILY_8000B "nvmData-8000B" #define DEFAULT_NVM_FILE_FAMILY_8000C "nvmData-8000C" -/* Max SDIO RX aggregation size of the ADDBA request/response */ -#define MAX_RX_AGG_SIZE_8260_SDIO 28 +/* Max SDIO RX/TX aggregation sizes of the ADDBA request/response */ +#define MAX_RX_AGG_SIZE_8260_SDIO 21 +#define MAX_TX_AGG_SIZE_8260_SDIO 40 /* Max A-MPDU exponent for HT and VHT */ #define MAX_HT_AMPDU_EXPONENT_8260_SDIO IEEE80211_HT_MAX_AMPDU_32K @@ -204,6 +205,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = { .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, + .max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO, .disable_dummy_notification = true, .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, .max_vht_ampdu_exponent = MAX_VHT_AMPDU_EXPONENT_8260_SDIO, @@ -217,6 +219,7 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = { .nvm_ver = IWL8000_NVM_VERSION, .nvm_calib_ver = IWL8000_TX_POWER_VERSION, .max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO, + .max_tx_agg_size = MAX_TX_AGG_SIZE_8260_SDIO, .bt_shared_single_ant = true, .disable_dummy_notification = true, .max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO, -- cgit v1.3-6-gb490 From 17564dde6024fcfe74cc0512e7837175aa5283d9 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Sun, 22 Mar 2015 13:11:01 +0200 Subject: iwlwifi: add new TLV capability flag for gscan support Gscan is a scan feature which is supported on certain devices only, hence the need for a TLV flag for it. For devices that support gscan store the gscan capabilities advertised by the FW so the driver can report it to upper layers. Signed-off-by: Avraham Stern Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-drv.c | 40 ++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-fw-file.h | 27 ++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-fw.h | 25 +++++++++++++++++++ 3 files changed, 92 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 721d3cb94386..a86aa5bcee7d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -372,6 +372,30 @@ static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len) return 0; } +static int iwl_store_gscan_capa(struct iwl_fw *fw, const u8 *data, + const u32 len) +{ + struct iwl_fw_gscan_capabilities *fw_capa = (void *)data; + struct iwl_gscan_capabilities *capa = &fw->gscan_capa; + + if (len < sizeof(*fw_capa)) + return -EINVAL; + + capa->max_scan_cache_size = le32_to_cpu(fw_capa->max_scan_cache_size); + capa->max_scan_buckets = le32_to_cpu(fw_capa->max_scan_buckets); + capa->max_ap_cache_per_scan = + le32_to_cpu(fw_capa->max_ap_cache_per_scan); + capa->max_rssi_sample_size = le32_to_cpu(fw_capa->max_rssi_sample_size); + capa->max_scan_reporting_threshold = + le32_to_cpu(fw_capa->max_scan_reporting_threshold); + capa->max_hotlist_aps = le32_to_cpu(fw_capa->max_hotlist_aps); + capa->max_significant_change_aps = + le32_to_cpu(fw_capa->max_significant_change_aps); + capa->max_bssid_history_entries = + le32_to_cpu(fw_capa->max_bssid_history_entries); + return 0; +} + /* * Gets uCode section from tlv. */ @@ -581,6 +605,7 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, int num_of_cpus; bool usniffer_images = false; bool usniffer_req = false; + bool gscan_capa = false; if (len < sizeof(*ucode)) { IWL_ERR(drv, "uCode has invalid length: %zd\n", len); @@ -991,6 +1016,11 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, drv->fw.sdio_adma_addr = le32_to_cpup((__le32 *)tlv_data); break; + case IWL_UCODE_TLV_FW_GSCAN_CAPA: + if (iwl_store_gscan_capa(&drv->fw, tlv_data, tlv_len)) + goto invalid_tlv_len; + gscan_capa = true; + break; default: IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); break; @@ -1009,6 +1039,16 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, return -EINVAL; } + /* + * If ucode advertises that it supports GSCAN but GSCAN + * capabilities TLV is not present, warn and continue without GSCAN. + */ + if (fw_has_capa(capa, IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT) && + WARN(!gscan_capa, + "GSCAN is supported but capabilities TLV is unavailable\n")) + __clear_bit((__force long)IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT, + capa->_capa); + return 0; invalid_tlv_len: diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 5d7f2d9cf180..d1c5b90eb6b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -139,6 +139,7 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_FW_DBG_DEST = 38, IWL_UCODE_TLV_FW_DBG_CONF = 39, IWL_UCODE_TLV_FW_DBG_TRIGGER = 40, + IWL_UCODE_TLV_FW_GSCAN_CAPA = 50, }; struct iwl_ucode_tlv { @@ -306,6 +307,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; * IWL_UCODE_TLV_API_WIFI_MCC_UPDATE. When either is set, multi-source LAR * is supported. * @IWL_UCODE_TLV_CAPA_BT_COEX_RRC: supports BT Coex RRC + * @IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT: supports gscan */ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = (__force iwl_ucode_tlv_capa_t)0, @@ -327,6 +329,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = (__force iwl_ucode_tlv_capa_t)28, IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29, IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30, + IWL_UCODE_TLV_CAPA_GSCAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)31, }; /* The default calibrate table size if not specified by firmware file */ @@ -728,4 +731,28 @@ struct iwl_fw_dbg_conf_tlv { struct iwl_fw_dbg_conf_hcmd hcmd; } __packed; +/** + * struct iwl_fw_gscan_capabilities - gscan capabilities supported by FW + * @max_scan_cache_size: total space allocated for scan results (in bytes). + * @max_scan_buckets: maximum number of channel buckets. + * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan. + * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI. + * @max_scan_reporting_threshold: max possible report threshold. in percentage. + * @max_hotlist_aps: maximum number of entries for hotlist APs. + * @max_significant_change_aps: maximum number of entries for significant + * change APs. + * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can + * hold. + */ +struct iwl_fw_gscan_capabilities { + __le32 max_scan_cache_size; + __le32 max_scan_buckets; + __le32 max_ap_cache_per_scan; + __le32 max_rssi_sample_size; + __le32 max_scan_reporting_threshold; + __le32 max_hotlist_aps; + __le32 max_significant_change_aps; + __le32 max_bssid_history_entries; +} __packed; + #endif /* __iwl_fw_file_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 224c7f45d2f1..0d9d6f51766e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -190,6 +190,30 @@ struct iwl_fw_cscheme_list { struct iwl_fw_cipher_scheme cs[]; } __packed; +/** + * struct iwl_gscan_capabilities - gscan capabilities supported by FW + * @max_scan_cache_size: total space allocated for scan results (in bytes). + * @max_scan_buckets: maximum number of channel buckets. + * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan. + * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI. + * @max_scan_reporting_threshold: max possible report threshold. in percentage. + * @max_hotlist_aps: maximum number of entries for hotlist APs. + * @max_significant_change_aps: maximum number of entries for significant + * change APs. + * @max_bssid_history_entries: number of BSSID/RSSI entries that the device can + * hold. + */ +struct iwl_gscan_capabilities { + u32 max_scan_cache_size; + u32 max_scan_buckets; + u32 max_ap_cache_per_scan; + u32 max_rssi_sample_size; + u32 max_scan_reporting_threshold; + u32 max_hotlist_aps; + u32 max_significant_change_aps; + u32 max_bssid_history_entries; +}; + /** * struct iwl_fw - variables associated with the firmware * @@ -248,6 +272,7 @@ struct iwl_fw { struct iwl_fw_dbg_trigger_tlv *dbg_trigger_tlv[FW_DBG_TRIGGER_MAX]; size_t dbg_trigger_tlv_len[FW_DBG_TRIGGER_MAX]; u8 dbg_dest_reg_num; + struct iwl_gscan_capabilities gscan_capa; }; static inline const char *get_fw_dbg_mode_string(int mode) -- cgit v1.3-6-gb490 From 206eea7833859f9e39c8a7439196743a2d8dfc9b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 17 Apr 2015 16:38:31 +0200 Subject: iwlwifi: pcie: support frag SKBs Allow frag SKBs in PCIe and advertise the maximum number of frags to the opmode. As a fallback. linearize the SKB if it exceeds the maximum number of fragments. This allows using the hardware better (filling more TBs) and should improve performance when used by the opmode. Also adjust tracing to be able to deal with this. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-devtrace-data.h | 7 ++- drivers/net/wireless/iwlwifi/iwl-trans.h | 7 +++ drivers/net/wireless/iwlwifi/pcie/internal.h | 6 ++ drivers/net/wireless/iwlwifi/pcie/trans.c | 2 + drivers/net/wireless/iwlwifi/pcie/tx.c | 70 ++++++++++++++++++++---- 5 files changed, 77 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h index 04e6649340b8..71a78cede9b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace-data.h @@ -35,8 +35,8 @@ TRACE_EVENT(iwlwifi_dev_tx_data, TP_PROTO(const struct device *dev, struct sk_buff *skb, - void *data, size_t data_len), - TP_ARGS(dev, skb, data, data_len), + u8 hdr_len, size_t data_len), + TP_ARGS(dev, skb, hdr_len, data_len), TP_STRUCT__entry( DEV_ENTRY @@ -45,7 +45,8 @@ TRACE_EVENT(iwlwifi_dev_tx_data, TP_fast_assign( DEV_ASSIGN; if (iwl_trace_data(skb)) - memcpy(__get_dynamic_array(data), data, data_len); + skb_copy_bits(skb, hdr_len, + __get_dynamic_array(data), data_len); ), TP_printk("[%s] TX frame data", __get_str(dev)) ); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 2f79e54823c4..e68497acf9b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -248,6 +248,8 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt) * @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). + * @CMD_TB_BITMAP_POS: Position of the first bit for the TB bitmap. We need to + * check that we leave enough room for the TBs bitmap which needs 20 bits. */ enum CMD_MODE { CMD_ASYNC = BIT(0), @@ -257,6 +259,8 @@ enum CMD_MODE { CMD_SEND_IN_IDLE = BIT(4), CMD_MAKE_TRANS_IDLE = BIT(5), CMD_WAKE_UP_TRANS = BIT(6), + + CMD_TB_BITMAP_POS = 11, }; #define DEF_CMD_PAYLOAD_SIZE 320 @@ -641,6 +645,8 @@ enum iwl_d0i3_mode { * @cfg - pointer to the configuration * @status: a bit-mask of transport status flags * @dev - pointer to struct device * that represents the device + * @max_skb_frags: maximum number of fragments an SKB can have when transmitted. + * 0 indicates that frag SKBs (NETIF_F_SG) aren't supported. * @hw_id: a u32 with the ID of the device / sub-device. * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. @@ -669,6 +675,7 @@ struct iwl_trans { unsigned long status; struct device *dev; + u32 max_skb_frags; u32 hw_rev; u32 hw_id; char hw_id_str[52]; diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 17f65dc89472..feb2f7e81134 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -44,6 +44,12 @@ #include "iwl-io.h" #include "iwl-op-mode.h" +/* We need 2 entries for the TX command and header, and another one might + * be needed for potential data in the SKB's head. The remaining ones can + * be used for frags. + */ +#define IWL_PCIE_MAX_FRAGS (IWL_NUM_OF_TBS - 3) + /* * RX related structures and functions */ diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 9ebdd8009717..fb55810f5aae 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2627,6 +2627,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, if (!trans) return ERR_PTR(-ENOMEM); + trans->max_skb_frags = IWL_PCIE_MAX_FRAGS; + trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); trans_pcie->trans = trans; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 601eee1ad60b..b7d1268bf969 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -388,11 +388,18 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans, /* first TB is never freed - it's the scratchbuf data */ - for (i = 1; i < num_tbs; i++) - dma_unmap_single(trans->dev, iwl_pcie_tfd_tb_get_addr(tfd, i), - iwl_pcie_tfd_tb_get_len(tfd, i), - DMA_TO_DEVICE); - + for (i = 1; i < num_tbs; i++) { + if (meta->flags & BIT(i + CMD_TB_BITMAP_POS)) + dma_unmap_page(trans->dev, + iwl_pcie_tfd_tb_get_addr(tfd, i), + iwl_pcie_tfd_tb_get_len(tfd, i), + DMA_TO_DEVICE); + else + dma_unmap_single(trans->dev, + iwl_pcie_tfd_tb_get_addr(tfd, i), + iwl_pcie_tfd_tb_get_len(tfd, i), + DMA_TO_DEVICE); + } tfd->num_tbs = 0; } @@ -468,7 +475,7 @@ static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq, iwl_pcie_tfd_set_tb(tfd, num_tbs, addr, len); - return 0; + return num_tbs; } static int iwl_pcie_txq_alloc(struct iwl_trans *trans, @@ -1546,6 +1553,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmdlen[i], false); } + BUILD_BUG_ON(IWL_NUM_OF_TBS + CMD_TB_BITMAP_POS > + sizeof(out_meta->flags) * BITS_PER_BYTE); out_meta->flags = cmd->flags; if (WARN_ON_ONCE(txq->entries[idx].free_buf)) kzfree(txq->entries[idx].free_buf); @@ -1789,7 +1798,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_cmd *dev_cmd, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_hdr *hdr; struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload; struct iwl_cmd_meta *out_meta; struct iwl_txq *txq; @@ -1798,9 +1807,10 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, void *tb1_addr; u16 len, tb1_len, tb2_len; bool wait_write_ptr; - __le16 fc = hdr->frame_control; - u8 hdr_len = ieee80211_hdrlen(fc); + __le16 fc; + u8 hdr_len; u16 wifi_seq; + int i; txq = &trans_pcie->txq[txq_id]; q = &txq->q; @@ -1809,6 +1819,18 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, "TX on unused queue %d\n", txq_id)) return -EINVAL; + if (skb_is_nonlinear(skb) && + skb_shinfo(skb)->nr_frags > IWL_PCIE_MAX_FRAGS && + __skb_linearize(skb)) + return -ENOMEM; + + /* mac80211 always puts the full header into the SKB's head, + * so there's no need to check if it's readable there + */ + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + hdr_len = ieee80211_hdrlen(fc); + spin_lock(&txq->lock); /* In AGG mode, the index in the ring must correspond to the WiFi @@ -1839,6 +1861,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_meta = &txq->entries[q->write_ptr].meta; + out_meta->flags = 0; /* * The second TB (tb1) points to the remainder of the TX command @@ -1872,9 +1895,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* * Set up TFD's third entry to point directly to remainder - * of skb, if any (802.11 null frames have no payload). + * of skb's head, if any */ - tb2_len = skb->len - hdr_len; + tb2_len = skb_headlen(skb) - hdr_len; if (tb2_len > 0) { dma_addr_t tb2_phys = dma_map_single(trans->dev, skb->data + hdr_len, @@ -1887,6 +1910,29 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, iwl_pcie_txq_build_tfd(trans, txq, tb2_phys, tb2_len, false); } + /* set up the remaining entries to point to the data */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + dma_addr_t tb_phys; + int tb_idx; + + if (!skb_frag_size(frag)) + continue; + + tb_phys = skb_frag_dma_map(trans->dev, frag, 0, + skb_frag_size(frag), DMA_TO_DEVICE); + + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { + iwl_pcie_tfd_unmap(trans, out_meta, + &txq->tfds[q->write_ptr]); + goto out_err; + } + tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys, + skb_frag_size(frag), false); + + out_meta->flags |= BIT(tb_idx + CMD_TB_BITMAP_POS); + } + /* Set up entry for this TFD in Tx byte-count array */ iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); @@ -1896,7 +1942,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, &dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len, skb->data + hdr_len, tb2_len); trace_iwlwifi_dev_tx_data(trans->dev, skb, - skb->data + hdr_len, tb2_len); + hdr_len, skb->len - hdr_len); wait_write_ptr = ieee80211_has_morefrags(fc); -- cgit v1.3-6-gb490 From 36fb90172688c8eeac67e1ef01d232549c9a6131 Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Wed, 15 Jul 2015 15:47:28 +0300 Subject: iwlwifi: mvm: add the ability to trigger only monitor dumps Change the FW debug trigger tlv to include a monitor only option. Setting this option to true will cause fw dump triggers to only collect monitor data and skip other dumps such as SMEM, SRAM, CSR, PRPH, etc. This option is used when accessing the different parts of the firmware memory is not wanted and can cause unwanted behavior like when debugging TX latency. Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 3 + drivers/net/wireless/iwlwifi/iwl-trans.h | 9 +- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw.c | 19 ++- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 36 +++-- drivers/net/wireless/iwlwifi/mvm/mvm.h | 6 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 3 +- drivers/net/wireless/iwlwifi/pcie/trans.c | 217 ++++++++++++++++------------ 8 files changed, 177 insertions(+), 118 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index d1c5b90eb6b4..75809abee759 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -498,10 +498,13 @@ struct iwl_fw_dbg_conf_hcmd { * * @IWL_FW_DBG_TRIGGER_START: when trigger occurs re-conf the dbg mechanism * @IWL_FW_DBG_TRIGGER_STOP: when trigger occurs pull the dbg data + * @IWL_FW_DBG_TRIGGER_MONITOR_ONLY: when trigger occurs trigger is set to + * collect only monitor data */ enum iwl_fw_dbg_trigger_mode { IWL_FW_DBG_TRIGGER_START = BIT(0), IWL_FW_DBG_TRIGGER_STOP = BIT(1), + IWL_FW_DBG_TRIGGER_MONITOR_ONLY = BIT(2), }; /** diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index e68497acf9b3..151e3de2247f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -608,7 +608,9 @@ struct iwl_trans_ops { int (*suspend)(struct iwl_trans *trans); void (*resume)(struct iwl_trans *trans); - struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans); + struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans, + struct iwl_fw_dbg_trigger_tlv + *trigger); }; /** @@ -832,11 +834,12 @@ static inline void iwl_trans_resume(struct iwl_trans *trans) } static inline struct iwl_trans_dump_data * -iwl_trans_dump_data(struct iwl_trans *trans) +iwl_trans_dump_data(struct iwl_trans *trans, + struct iwl_fw_dbg_trigger_tlv *trigger) { if (!trans->ops->dump_data) return NULL; - return trans->ops->dump_data(trans); + return trans->ops->dump_data(trans, trigger); } static inline int iwl_trans_send_cmd(struct iwl_trans *trans, diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index ffb4b5cef275..17d7a05006fa 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -974,7 +974,7 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, if (ret) return ret; - iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, NULL, 0, 0); + iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, NULL, 0, NULL); iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index e65a65337792..aff5bbf3f141 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -735,8 +735,13 @@ static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm) int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, struct iwl_mvm_dump_desc *desc, - unsigned int delay) + struct iwl_fw_dbg_trigger_tlv *trigger) { + unsigned int delay = 0; + + if (trigger) + delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); + if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status)) return -EBUSY; @@ -747,6 +752,7 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, le32_to_cpu(desc->trig_desc.type)); mvm->fw_dump_desc = desc; + mvm->fw_dump_trig = trigger; queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay); @@ -754,7 +760,8 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, } int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, - const char *str, size_t len, unsigned int delay) + const char *str, size_t len, + struct iwl_fw_dbg_trigger_tlv *trigger) { struct iwl_mvm_dump_desc *desc; @@ -766,14 +773,13 @@ int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, desc->trig_desc.type = cpu_to_le32(trig); memcpy(desc->trig_desc.data, str, len); - return iwl_mvm_fw_dbg_collect_desc(mvm, desc, delay); + return iwl_mvm_fw_dbg_collect_desc(mvm, desc, trigger); } int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_tlv *trigger, const char *fmt, ...) { - unsigned int delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); u16 occurrences = le16_to_cpu(trigger->occurrences); int ret, len = 0; char buf[64]; @@ -797,8 +803,9 @@ int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, len = strlen(buf) + 1; } - ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), buf, - len, delay); + ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), buf, len, + trigger); + if (ret) return ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 9e641847c047..08dd67435189 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1124,9 +1124,14 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) u32 file_len, fifo_data_len = 0; u32 smem_len = mvm->cfg->smem_len; u32 sram2_len = mvm->cfg->dccm2_len; + bool monitor_dump_only = false; lockdep_assert_held(&mvm->mutex); + if (mvm->fw_dump_trig && + mvm->fw_dump_trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY) + monitor_dump_only = true; + fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); if (!fw_error_dump) return; @@ -1178,6 +1183,20 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) fifo_data_len + sizeof(*dump_info); + /* Make room for the SMEM, if it exists */ + if (smem_len) + file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len; + + /* Make room for the secondary SRAM, if it exists */ + if (sram2_len) + file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len; + + /* If we only want a monitor dump, reset the file length */ + if (monitor_dump_only) { + file_len = sizeof(*dump_file) + sizeof(*dump_data) + + sizeof(*dump_info); + } + /* * In 8000 HW family B-step include the ICCM (which resides separately) */ @@ -1190,14 +1209,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) file_len += sizeof(*dump_data) + sizeof(*dump_trig) + mvm->fw_dump_desc->len; - /* Make room for the SMEM, if it exists */ - if (smem_len) - file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len; - - /* Make room for the secondary SRAM, if it exists */ - if (sram2_len) - file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len; - dump_file = vzalloc(file_len); if (!dump_file) { kfree(fw_error_dump); @@ -1243,6 +1254,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_data = iwl_fw_error_next_data(dump_data); } + /* In case we only want monitor dump, skip to dump trasport data */ + if (monitor_dump_only) + goto dump_trans_data; + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); dump_mem = (void *)dump_data->data; @@ -1286,7 +1301,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_mem->data, IWL8260_ICCM_LEN); } - fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans); +dump_trans_data: + fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans, + mvm->fw_dump_trig); fw_error_dump->op_mode_len = file_len; if (fw_error_dump->trans_ptr) file_len += fw_error_dump->trans_ptr->len; @@ -1295,6 +1312,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0, GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump); + mvm->fw_dump_trig = NULL; clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status); } diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fdf401b696a4..2b2e2996ccb9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -708,6 +708,7 @@ struct iwl_mvm { u8 fw_dbg_conf; struct delayed_work fw_dump_wk; struct iwl_mvm_dump_desc *fw_dump_desc; + struct iwl_fw_dbg_trigger_tlv *fw_dump_trig; #ifdef CONFIG_IWLWIFI_LEDS struct led_classdev led; @@ -1443,10 +1444,11 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 id); int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, - const char *str, size_t len, unsigned int delay); + const char *str, size_t len, + struct iwl_fw_dbg_trigger_tlv *trigger); int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, struct iwl_mvm_dump_desc *desc, - unsigned int delay); + struct iwl_fw_dbg_trigger_tlv *trigger); void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm); int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, struct iwl_fw_dbg_trigger_tlv *trigger, diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index ef09a05b6ddb..48731124afe1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -914,7 +914,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) * can't recover this since we're already half suspended. */ if (!mvm->restart_fw && fw_error) { - iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert, 0); + iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert, + NULL); } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { struct iwl_mvm_reprobe *reprobe; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index fb55810f5aae..6a3ee04c5222 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2385,8 +2385,87 @@ iwl_trans_pci_dump_marbh_monitor(struct iwl_trans *trans, return monitor_len; } -static -struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) +static u32 +iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, + struct iwl_fw_error_dump_data **data, + u32 monitor_len) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 len = 0; + + if ((trans_pcie->fw_mon_page && + trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || + trans->dbg_dest_tlv) { + struct iwl_fw_error_dump_fw_mon *fw_mon_data; + u32 base, write_ptr, wrap_cnt; + + /* If there was a dest TLV - use the values from there */ + if (trans->dbg_dest_tlv) { + write_ptr = + le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg); + wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count); + base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); + } else { + base = MON_BUFF_BASE_ADDR; + write_ptr = MON_BUFF_WRPTR; + wrap_cnt = MON_BUFF_CYCLE_CNT; + } + + (*data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); + fw_mon_data = (void *)(*data)->data; + fw_mon_data->fw_mon_wr_ptr = + cpu_to_le32(iwl_read_prph(trans, write_ptr)); + fw_mon_data->fw_mon_cycle_cnt = + cpu_to_le32(iwl_read_prph(trans, wrap_cnt)); + fw_mon_data->fw_mon_base_ptr = + cpu_to_le32(iwl_read_prph(trans, base)); + + len += sizeof(**data) + sizeof(*fw_mon_data); + if (trans_pcie->fw_mon_page) { + /* + * The firmware is now asserted, it won't write anything + * to the buffer. CPU can take ownership to fetch the + * data. The buffer will be handed back to the device + * before the firmware will be restarted. + */ + dma_sync_single_for_cpu(trans->dev, + trans_pcie->fw_mon_phys, + trans_pcie->fw_mon_size, + DMA_FROM_DEVICE); + memcpy(fw_mon_data->data, + page_address(trans_pcie->fw_mon_page), + trans_pcie->fw_mon_size); + + monitor_len = trans_pcie->fw_mon_size; + } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) { + /* + * Update pointers to reflect actual values after + * shifting + */ + base = iwl_read_prph(trans, base) << + trans->dbg_dest_tlv->base_shift; + iwl_trans_read_mem(trans, base, fw_mon_data->data, + monitor_len / sizeof(u32)); + } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) { + monitor_len = + iwl_trans_pci_dump_marbh_monitor(trans, + fw_mon_data, + monitor_len); + } else { + /* Didn't match anything - output no monitor data */ + monitor_len = 0; + } + + len += monitor_len; + (*data)->len = cpu_to_le32(monitor_len + sizeof(*fw_mon_data)); + } + + return len; +} + +static struct iwl_trans_dump_data +*iwl_trans_pcie_dump_data(struct iwl_trans *trans, + struct iwl_fw_dbg_trigger_tlv *trigger) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_fw_error_dump_data *data; @@ -2405,33 +2484,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) len += sizeof(*data) + cmdq->q.n_window * (sizeof(*txcmd) + TFD_MAX_PAYLOAD_SIZE); - /* CSR registers */ - len += sizeof(*data) + IWL_CSR_TO_DUMP; - - /* PRPH registers */ - for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { - /* The range includes both boundaries */ - int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - - iwl_prph_dump_addr[i].start + 4; - - len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) + - num_bytes_in_chunk; - } - - /* FH registers */ - len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); - - if (dump_rbs) { - /* RBs */ - num_rbs = le16_to_cpu(ACCESS_ONCE( - trans_pcie->rxq.rb_stts->closed_rb_num)) - & 0x0FFF; - num_rbs = (num_rbs - trans_pcie->rxq.read) & RX_QUEUE_MASK; - len += num_rbs * (sizeof(*data) + - sizeof(struct iwl_fw_error_dump_rb) + - (PAGE_SIZE << trans_pcie->rx_page_order)); - } - /* FW monitor */ if (trans_pcie->fw_mon_page) { len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_fw_mon) + @@ -2459,6 +2511,45 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) monitor_len = 0; } + if (trigger && (trigger->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY)) { + dump_data = vzalloc(len); + if (!dump_data) + return NULL; + + data = (void *)dump_data->data; + len = iwl_trans_pcie_dump_monitor(trans, &data, monitor_len); + dump_data->len = len; + + return dump_data; + } + + /* CSR registers */ + len += sizeof(*data) + IWL_CSR_TO_DUMP; + + /* PRPH registers */ + for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr); i++) { + /* The range includes both boundaries */ + int num_bytes_in_chunk = iwl_prph_dump_addr[i].end - + iwl_prph_dump_addr[i].start + 4; + + len += sizeof(*data) + sizeof(struct iwl_fw_error_dump_prph) + + num_bytes_in_chunk; + } + + /* FH registers */ + len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND); + + if (dump_rbs) { + /* RBs */ + num_rbs = le16_to_cpu(ACCESS_ONCE( + trans_pcie->rxq.rb_stts->closed_rb_num)) + & 0x0FFF; + num_rbs = (num_rbs - trans_pcie->rxq.read) & RX_QUEUE_MASK; + len += num_rbs * (sizeof(*data) + + sizeof(struct iwl_fw_error_dump_rb) + + (PAGE_SIZE << trans_pcie->rx_page_order)); + } + dump_data = vzalloc(len); if (!dump_data) return NULL; @@ -2498,73 +2589,7 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans) if (dump_rbs) len += iwl_trans_pcie_dump_rbs(trans, &data, num_rbs); - /* data is already pointing to the next section */ - if ((trans_pcie->fw_mon_page && - trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) || - trans->dbg_dest_tlv) { - struct iwl_fw_error_dump_fw_mon *fw_mon_data; - u32 base, write_ptr, wrap_cnt; - - /* If there was a dest TLV - use the values from there */ - if (trans->dbg_dest_tlv) { - write_ptr = - le32_to_cpu(trans->dbg_dest_tlv->write_ptr_reg); - wrap_cnt = le32_to_cpu(trans->dbg_dest_tlv->wrap_count); - base = le32_to_cpu(trans->dbg_dest_tlv->base_reg); - } else { - base = MON_BUFF_BASE_ADDR; - write_ptr = MON_BUFF_WRPTR; - wrap_cnt = MON_BUFF_CYCLE_CNT; - } - - data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_FW_MONITOR); - fw_mon_data = (void *)data->data; - fw_mon_data->fw_mon_wr_ptr = - cpu_to_le32(iwl_read_prph(trans, write_ptr)); - fw_mon_data->fw_mon_cycle_cnt = - cpu_to_le32(iwl_read_prph(trans, wrap_cnt)); - fw_mon_data->fw_mon_base_ptr = - cpu_to_le32(iwl_read_prph(trans, base)); - - len += sizeof(*data) + sizeof(*fw_mon_data); - if (trans_pcie->fw_mon_page) { - /* - * The firmware is now asserted, it won't write anything - * to the buffer. CPU can take ownership to fetch the - * data. The buffer will be handed back to the device - * before the firmware will be restarted. - */ - dma_sync_single_for_cpu(trans->dev, - trans_pcie->fw_mon_phys, - trans_pcie->fw_mon_size, - DMA_FROM_DEVICE); - memcpy(fw_mon_data->data, - page_address(trans_pcie->fw_mon_page), - trans_pcie->fw_mon_size); - - monitor_len = trans_pcie->fw_mon_size; - } else if (trans->dbg_dest_tlv->monitor_mode == SMEM_MODE) { - /* - * Update pointers to reflect actual values after - * shifting - */ - base = iwl_read_prph(trans, base) << - trans->dbg_dest_tlv->base_shift; - iwl_trans_read_mem(trans, base, fw_mon_data->data, - monitor_len / sizeof(u32)); - } else if (trans->dbg_dest_tlv->monitor_mode == MARBH_MODE) { - monitor_len = - iwl_trans_pci_dump_marbh_monitor(trans, - fw_mon_data, - monitor_len); - } else { - /* Didn't match anything - output no monitor data */ - monitor_len = 0; - } - - len += monitor_len; - data->len = cpu_to_le32(monitor_len + sizeof(*fw_mon_data)); - } + len += iwl_trans_pcie_dump_monitor(trans, &data, monitor_len); dump_data->len = len; -- cgit v1.3-6-gb490 From 26d535aedc0e9fcf2c8bee65b33cecb58ee8e8ed Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Tue, 28 Apr 2015 12:56:54 +0300 Subject: iwlwifi: pcie: New RBD allocation model As a preperation for multiple RX queues change the RBD allocation model. The new model includes a background allocator. The allocator is called by the interrupt handler when there are two released buffers by the queue, and the allocator starts allocating eight pages per request. When the queue has released 8 pages it tries claiming the request. If the pages are not ready - it keeps claiming. This new model should make sure that RBDs are always available across the multiple queues. The RBDs are transferred between the allocator and the queue. The queue moves the free RBDs upon freeing them to the allocator. The allocator moves them back to the queue's possession when the request is claimed. The allocator has an initial pool to make sure there are always RBDs available for the request completion. Release of the buffers at exit is done per pools - the allocator frees its own initial pool and the queue frees its own pool. Existing code refactor - -Queue's initial pool is the size of the queue only as the allocation of the new buffers no longer uses this pool. -Removal of replenish background work, and replenish calls in the interrupt handler and restock(). -The replenish() and the rxq used_list are used only during initialization. -Moved page allocation to a new function for code reuse. New code - Allocator code - new structure and functions. Interrupt handler uses the allocator functions for replenishing buffers. Reuse of the restock() method. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fh.h | 6 - drivers/net/wireless/iwlwifi/pcie/internal.h | 51 ++- drivers/net/wireless/iwlwifi/pcie/rx.c | 473 ++++++++++++++++++++++----- 3 files changed, 435 insertions(+), 95 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index d45dc021cda2..d56064861a9c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -438,12 +438,6 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl) #define RX_QUEUE_MASK 255 #define RX_QUEUE_SIZE_LOG 8 -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 64 -#define RX_LOW_WATERMARK 8 - /** * struct iwl_rb_status - reserve buffer status * host memory mapped FH registers diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 2de3d9a4fa7c..feb2f7e81134 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -50,6 +50,15 @@ */ #define IWL_PCIE_MAX_FRAGS (IWL_NUM_OF_TBS - 3) +/* + * RX related structures and functions + */ +#define RX_NUM_QUEUES 1 +#define RX_POST_REQ_ALLOC 2 +#define RX_CLAIM_REQ_ALLOC 8 +#define RX_POOL_SIZE ((RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC) * RX_NUM_QUEUES) +#define RX_LOW_WATERMARK 8 + struct iwl_host_cmd; /*This file includes the declaration that are internal to the @@ -83,29 +92,29 @@ struct isr_statistics { * struct iwl_rxq - Rx queue * @bd: driver's pointer to buffer of receive buffer descriptors (rbd) * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) - * @pool: - * @queue: * @read: Shared index to newest available Rx buffer * @write: Shared index to oldest written Rx packet * @free_count: Number of pre-allocated buffers in rx_free + * @used_count: Number of RBDs handled to allocator to use for allocation * @write_actual: - * @rx_free: list of free SKBs for use - * @rx_used: List of Rx buffers with no SKB + * @rx_free: list of RBDs with allocated RB ready for use + * @rx_used: list of RBDs with no RB attached * @need_update: flag to indicate we need to update read/write index * @rb_stts: driver's pointer to receive buffer status * @rb_stts_dma: bus address of receive buffer status * @lock: + * @pool: initial pool of iwl_rx_mem_buffer for the queue + * @queue: actual rx queue * * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers */ struct iwl_rxq { __le32 *bd; dma_addr_t bd_dma; - struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; - struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; u32 read; u32 write; u32 free_count; + u32 used_count; u32 write_actual; struct list_head rx_free; struct list_head rx_used; @@ -113,6 +122,32 @@ struct iwl_rxq { struct iwl_rb_status *rb_stts; dma_addr_t rb_stts_dma; spinlock_t lock; + struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE]; + struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; +}; + +/** + * struct iwl_rb_allocator - Rx allocator + * @pool: initial pool of allocator + * @req_pending: number of requests the allcator had not processed yet + * @req_ready: number of requests honored and ready for claiming + * @rbd_allocated: RBDs with pages allocated and ready to be handled to + * the queue. This is a list of &struct iwl_rx_mem_buffer + * @rbd_empty: RBDs with no page attached for allocator use. This is a list + * of &struct iwl_rx_mem_buffer + * @lock: protects the rbd_allocated and rbd_empty lists + * @alloc_wq: work queue for background calls + * @rx_alloc: work struct for background calls + */ +struct iwl_rb_allocator { + struct iwl_rx_mem_buffer pool[RX_POOL_SIZE]; + atomic_t req_pending; + atomic_t req_ready; + struct list_head rbd_allocated; + struct list_head rbd_empty; + spinlock_t lock; + struct workqueue_struct *alloc_wq; + struct work_struct rx_alloc; }; struct iwl_dma_ptr { @@ -256,7 +291,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) /** * struct iwl_trans_pcie - PCIe transport specific data * @rxq: all the RX queue data - * @rx_replenish: work that will be called when buffers need to be allocated + * @rba: allocator for RX replenishing * @drv - pointer to iwl_drv * @trans: pointer to the generic transport area * @scd_base_addr: scheduler sram base address in SRAM @@ -281,7 +316,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) */ struct iwl_trans_pcie { struct iwl_rxq rxq; - struct work_struct rx_replenish; + struct iwl_rb_allocator rba; struct iwl_trans *trans; struct iwl_drv *drv; diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index e1af0fffedd8..5643ace7b15a 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1,7 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -74,16 +74,29 @@ * resets the Rx queue buffers with new memory. * * The management in the driver is as follows: - * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When - * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled - * to replenish the iwl->rxq->rx_free. - * + In iwl_pcie_rx_replenish (scheduled) if 'processed' != 'read' then the - * iwl->rxq is replenished and the READ INDEX is updated (updating the - * 'processed' and 'read' driver indexes as well) + * + A list of pre-allocated RBDs is stored in iwl->rxq->rx_free. + * When the interrupt handler is called, the request is processed. + * The page is either stolen - transferred to the upper layer + * or reused - added immediately to the iwl->rxq->rx_free list. + * + When the page is stolen - the driver updates the matching queue's used + * count, detaches the RBD and transfers it to the queue used list. + * When there are two used RBDs - they are transferred to the allocator empty + * list. Work is then scheduled for the allocator to start allocating + * eight buffers. + * When there are another 6 used RBDs - they are transferred to the allocator + * empty list and the driver tries to claim the pre-allocated buffers and + * add them to iwl->rxq->rx_free. If it fails - it continues to claim them + * until ready. + * When there are 8+ buffers in the free list - either from allocation or from + * 8 reused unstolen pages - restock is called to update the FW and indexes. + * + In order to make sure the allocator always has RBDs to use for allocation + * the allocator has initial pool in the size of num_queues*(8-2) - the + * maximum missing RBDs per allocation request (request posted with 2 + * empty RBDs, there is no guarantee when the other 6 RBDs are supplied). + * The queues supplies the recycle of the rest of the RBDs. * + A received packet is processed and handed to the kernel network stack, * detached from the iwl->rxq. The driver 'processed' index is updated. - * + The Host/Firmware iwl->rxq is replenished at irq thread time from the - * rx_free list. If there are no allocated buffers in iwl->rxq->rx_free, + * + If there are no allocated buffers in iwl->rxq->rx_free, * the READ INDEX is not incremented and iwl->status(RX_STALLED) is set. * If there were enough free buffers and RX_STALLED is set it is cleared. * @@ -92,18 +105,32 @@ * * iwl_rxq_alloc() Allocates rx_free * iwl_pcie_rx_replenish() Replenishes rx_free list from rx_used, and calls - * iwl_pcie_rxq_restock + * iwl_pcie_rxq_restock. + * Used only during initialization. * iwl_pcie_rxq_restock() Moves available buffers from rx_free into Rx * queue, updates firmware pointers, and updates - * the WRITE index. If insufficient rx_free buffers - * are available, schedules iwl_pcie_rx_replenish + * the WRITE index. + * iwl_pcie_rx_allocator() Background work for allocating pages. * * -- enable interrupts -- * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the * READ INDEX, detaching the SKB from the pool. * Moves the packet buffer from queue to rx_used. + * Posts and claims requests to the allocator. * Calls iwl_pcie_rxq_restock to refill any empty * slots. + * + * RBD life-cycle: + * + * Init: + * rxq.pool -> rxq.rx_used -> rxq.rx_free -> rxq.queue + * + * Regular Receive interrupt: + * Page Stolen: + * rxq.queue -> rxq.rx_used -> allocator.rbd_empty -> + * allocator.rbd_allocated -> rxq.rx_free -> rxq.queue + * Page not Stolen: + * rxq.queue -> rxq.rx_free -> rxq.queue * ... * */ @@ -240,10 +267,6 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) rxq->free_count--; } spin_unlock(&rxq->lock); - /* If the pre-allocated buffer pool is dropping low, schedule to - * refill it */ - if (rxq->free_count <= RX_LOW_WATERMARK) - schedule_work(&trans_pcie->rx_replenish); /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ @@ -254,6 +277,45 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) } } +/* + * iwl_pcie_rx_alloc_page - allocates and returns a page. + * + */ +static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans, + gfp_t priority) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rxq *rxq = &trans_pcie->rxq; + struct page *page; + gfp_t gfp_mask = priority; + + if (rxq->free_count > RX_LOW_WATERMARK) + gfp_mask |= __GFP_NOWARN; + + if (trans_pcie->rx_page_order > 0) + gfp_mask |= __GFP_COMP; + + /* Alloc a new receive buffer */ + page = alloc_pages(gfp_mask, trans_pcie->rx_page_order); + if (!page) { + if (net_ratelimit()) + IWL_DEBUG_INFO(trans, "alloc_pages failed, order: %d\n", + trans_pcie->rx_page_order); + /* Issue an error if the hardware has consumed more than half + * of its free buffer list and we don't have enough + * pre-allocated buffers. +` */ + if (rxq->free_count <= RX_LOW_WATERMARK && + iwl_rxq_space(rxq) > (RX_QUEUE_SIZE / 2) && + net_ratelimit()) + IWL_CRIT(trans, + "Failed to alloc_pages with GFP_KERNEL. Only %u free buffers remaining.\n", + rxq->free_count); + return NULL; + } + return page; +} + /* * iwl_pcie_rxq_alloc_rbs - allocate a page for each used RBD * @@ -269,7 +331,6 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rx_mem_buffer *rxb; struct page *page; - gfp_t gfp_mask = priority; while (1) { spin_lock(&rxq->lock); @@ -279,32 +340,10 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) } spin_unlock(&rxq->lock); - if (rxq->free_count > RX_LOW_WATERMARK) - gfp_mask |= __GFP_NOWARN; - - if (trans_pcie->rx_page_order > 0) - gfp_mask |= __GFP_COMP; - /* Alloc a new receive buffer */ - page = alloc_pages(gfp_mask, trans_pcie->rx_page_order); - if (!page) { - if (net_ratelimit()) - IWL_DEBUG_INFO(trans, "alloc_pages failed, " - "order: %d\n", - trans_pcie->rx_page_order); - - if ((rxq->free_count <= RX_LOW_WATERMARK) && - net_ratelimit()) - IWL_CRIT(trans, "Failed to alloc_pages with %s." - "Only %u free buffers remaining.\n", - priority == GFP_ATOMIC ? - "GFP_ATOMIC" : "GFP_KERNEL", - rxq->free_count); - /* We don't reschedule replenish work here -- we will - * call the restock method and if it still needs - * more buffers it will schedule replenish */ + page = iwl_pcie_rx_alloc_page(trans, priority); + if (!page) return; - } spin_lock(&rxq->lock); @@ -355,7 +394,7 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans) lockdep_assert_held(&rxq->lock); - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + for (i = 0; i < RX_QUEUE_SIZE; i++) { if (!rxq->pool[i].page) continue; dma_unmap_page(trans->dev, rxq->pool[i].page_dma, @@ -372,32 +411,164 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans) * When moving to rx_free an page is allocated for the slot. * * Also restock the Rx queue via iwl_pcie_rxq_restock. - * This is called as a scheduled work item (except for during initialization) + * This is called only during initialization */ -static void iwl_pcie_rx_replenish(struct iwl_trans *trans, gfp_t gfp) +static void iwl_pcie_rx_replenish(struct iwl_trans *trans) { - iwl_pcie_rxq_alloc_rbs(trans, gfp); + iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL); iwl_pcie_rxq_restock(trans); } -static void iwl_pcie_rx_replenish_work(struct work_struct *data) +/* + * iwl_pcie_rx_allocator - Allocates pages in the background for RX queues + * + * Allocates for each received request 8 pages + * Called as a scheduled work item. + */ +static void iwl_pcie_rx_allocator(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rb_allocator *rba = &trans_pcie->rba; + struct list_head local_empty; + int pending = atomic_xchg(&rba->req_pending, 0); + + IWL_DEBUG_RX(trans, "Pending allocation requests = %d\n", pending); + + /* If we were scheduled - there is at least one request */ + spin_lock(&rba->lock); + /* swap out the rba->rbd_empty to a local list */ + list_replace_init(&rba->rbd_empty, &local_empty); + spin_unlock(&rba->lock); + + while (pending) { + int i; + struct list_head local_allocated; + + INIT_LIST_HEAD(&local_allocated); + + for (i = 0; i < RX_CLAIM_REQ_ALLOC;) { + struct iwl_rx_mem_buffer *rxb; + struct page *page; + + /* List should never be empty - each reused RBD is + * returned to the list, and initial pool covers any + * possible gap between the time the page is allocated + * to the time the RBD is added. + */ + BUG_ON(list_empty(&local_empty)); + /* Get the first rxb from the rbd list */ + rxb = list_first_entry(&local_empty, + struct iwl_rx_mem_buffer, list); + BUG_ON(rxb->page); + + /* Alloc a new receive buffer */ + page = iwl_pcie_rx_alloc_page(trans, GFP_KERNEL); + if (!page) + continue; + rxb->page = page; + + /* Get physical address of the RB */ + rxb->page_dma = dma_map_page(trans->dev, page, 0, + PAGE_SIZE << trans_pcie->rx_page_order, + DMA_FROM_DEVICE); + if (dma_mapping_error(trans->dev, rxb->page_dma)) { + rxb->page = NULL; + __free_pages(page, trans_pcie->rx_page_order); + continue; + } + /* dma address must be no more than 36 bits */ + BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); + /* and also 256 byte aligned! */ + BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); + + /* move the allocated entry to the out list */ + list_move(&rxb->list, &local_allocated); + i++; + } + + pending--; + if (!pending) { + pending = atomic_xchg(&rba->req_pending, 0); + IWL_DEBUG_RX(trans, + "Pending allocation requests = %d\n", + pending); + } + + spin_lock(&rba->lock); + /* add the allocated rbds to the allocator allocated list */ + list_splice_tail(&local_allocated, &rba->rbd_allocated); + /* get more empty RBDs for current pending requests */ + list_splice_tail_init(&rba->rbd_empty, &local_empty); + spin_unlock(&rba->lock); + + atomic_inc(&rba->req_ready); + } + + spin_lock(&rba->lock); + /* return unused rbds to the allocator empty list */ + list_splice_tail(&local_empty, &rba->rbd_empty); + spin_unlock(&rba->lock); +} + +/* + * iwl_pcie_rx_allocator_get - Returns the pre-allocated pages +.* +.* Called by queue when the queue posted allocation request and + * has freed 8 RBDs in order to restock itself. + */ +static int iwl_pcie_rx_allocator_get(struct iwl_trans *trans, + struct iwl_rx_mem_buffer + *out[RX_CLAIM_REQ_ALLOC]) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rb_allocator *rba = &trans_pcie->rba; + int i; + + /* + * atomic_dec_if_positive returns req_ready - 1 for any scenario. + * If req_ready is 0 atomic_dec_if_positive will return -1 and this + * function will return -ENOMEM, as there are no ready requests. + * atomic_dec_if_positive will perofrm the *actual* decrement only if + * req_ready > 0, i.e. - there are ready requests and the function + * hands one request to the caller. + */ + if (atomic_dec_if_positive(&rba->req_ready) < 0) + return -ENOMEM; + + spin_lock(&rba->lock); + for (i = 0; i < RX_CLAIM_REQ_ALLOC; i++) { + /* Get next free Rx buffer, remove it from free list */ + out[i] = list_first_entry(&rba->rbd_allocated, + struct iwl_rx_mem_buffer, list); + list_del(&out[i]->list); + } + spin_unlock(&rba->lock); + + return 0; +} + +static void iwl_pcie_rx_allocator_work(struct work_struct *data) { + struct iwl_rb_allocator *rba_p = + container_of(data, struct iwl_rb_allocator, rx_alloc); struct iwl_trans_pcie *trans_pcie = - container_of(data, struct iwl_trans_pcie, rx_replenish); + container_of(rba_p, struct iwl_trans_pcie, rba); - iwl_pcie_rx_replenish(trans_pcie->trans, GFP_KERNEL); + iwl_pcie_rx_allocator(trans_pcie->trans); } static int iwl_pcie_rx_alloc(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; + struct iwl_rb_allocator *rba = &trans_pcie->rba; struct device *dev = trans->dev; memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq)); spin_lock_init(&rxq->lock); + spin_lock_init(&rba->lock); if (WARN_ON(rxq->bd || rxq->rb_stts)) return -EINVAL; @@ -487,15 +658,49 @@ static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq) INIT_LIST_HEAD(&rxq->rx_free); INIT_LIST_HEAD(&rxq->rx_used); rxq->free_count = 0; + rxq->used_count = 0; - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) + for (i = 0; i < RX_QUEUE_SIZE; i++) list_add(&rxq->pool[i].list, &rxq->rx_used); } +static void iwl_pcie_rx_init_rba(struct iwl_rb_allocator *rba) +{ + int i; + + lockdep_assert_held(&rba->lock); + + INIT_LIST_HEAD(&rba->rbd_allocated); + INIT_LIST_HEAD(&rba->rbd_empty); + + for (i = 0; i < RX_POOL_SIZE; i++) + list_add(&rba->pool[i].list, &rba->rbd_empty); +} + +static void iwl_pcie_rx_free_rba(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rb_allocator *rba = &trans_pcie->rba; + int i; + + lockdep_assert_held(&rba->lock); + + for (i = 0; i < RX_POOL_SIZE; i++) { + if (!rba->pool[i].page) + continue; + dma_unmap_page(trans->dev, rba->pool[i].page_dma, + PAGE_SIZE << trans_pcie->rx_page_order, + DMA_FROM_DEVICE); + __free_pages(rba->pool[i].page, trans_pcie->rx_page_order); + rba->pool[i].page = NULL; + } +} + int iwl_pcie_rx_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; + struct iwl_rb_allocator *rba = &trans_pcie->rba; int i, err; if (!rxq->bd) { @@ -503,11 +708,21 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) if (err) return err; } + if (!rba->alloc_wq) + rba->alloc_wq = alloc_workqueue("rb_allocator", + WQ_HIGHPRI | WQ_UNBOUND, 1); + INIT_WORK(&rba->rx_alloc, iwl_pcie_rx_allocator_work); + + spin_lock(&rba->lock); + atomic_set(&rba->req_pending, 0); + atomic_set(&rba->req_ready, 0); + /* free all first - we might be reconfigured for a different size */ + iwl_pcie_rx_free_rba(trans); + iwl_pcie_rx_init_rba(rba); + spin_unlock(&rba->lock); spin_lock(&rxq->lock); - INIT_WORK(&trans_pcie->rx_replenish, iwl_pcie_rx_replenish_work); - /* free all first - we might be reconfigured for a different size */ iwl_pcie_rxq_free_rbs(trans); iwl_pcie_rx_init_rxb_lists(rxq); @@ -522,7 +737,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); spin_unlock(&rxq->lock); - iwl_pcie_rx_replenish(trans, GFP_KERNEL); + iwl_pcie_rx_replenish(trans); iwl_pcie_rx_hw_init(trans, rxq); @@ -537,6 +752,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; + struct iwl_rb_allocator *rba = &trans_pcie->rba; /*if rxq->bd is NULL, it means that nothing has been allocated, * exit now */ @@ -545,7 +761,15 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) return; } - cancel_work_sync(&trans_pcie->rx_replenish); + cancel_work_sync(&rba->rx_alloc); + if (rba->alloc_wq) { + destroy_workqueue(rba->alloc_wq); + rba->alloc_wq = NULL; + } + + spin_lock(&rba->lock); + iwl_pcie_rx_free_rba(trans); + spin_unlock(&rba->lock); spin_lock(&rxq->lock); iwl_pcie_rxq_free_rbs(trans); @@ -566,8 +790,49 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) rxq->rb_stts = NULL; } +/* + * iwl_pcie_rx_reuse_rbd - Recycle used RBDs + * + * Called when a RBD can be reused. The RBD is transferred to the allocator. + * When there are 2 empty RBDs - a request for allocation is posted + */ +static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans, + struct iwl_rx_mem_buffer *rxb, + struct iwl_rxq *rxq, bool emergency) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rb_allocator *rba = &trans_pcie->rba; + + /* Move the RBD to the used list, will be moved to allocator in batches + * before claiming or posting a request*/ + list_add_tail(&rxb->list, &rxq->rx_used); + + if (unlikely(emergency)) + return; + + /* Count the allocator owned RBDs */ + rxq->used_count++; + + /* If we have RX_POST_REQ_ALLOC new released rx buffers - + * issue a request for allocator. Modulo RX_CLAIM_REQ_ALLOC is + * used for the case we failed to claim RX_CLAIM_REQ_ALLOC, + * after but we still need to post another request. + */ + if ((rxq->used_count % RX_CLAIM_REQ_ALLOC) == RX_POST_REQ_ALLOC) { + /* Move the 2 RBDs to the allocator ownership. + Allocator has another 6 from pool for the request completion*/ + spin_lock(&rba->lock); + list_splice_tail_init(&rxq->rx_used, &rba->rbd_empty); + spin_unlock(&rba->lock); + + atomic_inc(&rba->req_pending); + queue_work(rba->alloc_wq, &rba->rx_alloc); + } +} + static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, - struct iwl_rx_mem_buffer *rxb) + struct iwl_rx_mem_buffer *rxb, + bool emergency) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; @@ -682,13 +947,13 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, */ __free_pages(rxb->page, trans_pcie->rx_page_order); rxb->page = NULL; - list_add_tail(&rxb->list, &rxq->rx_used); + iwl_pcie_rx_reuse_rbd(trans, rxb, rxq, emergency); } else { list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; } } else - list_add_tail(&rxb->list, &rxq->rx_used); + iwl_pcie_rx_reuse_rbd(trans, rxb, rxq, emergency); } /* @@ -698,10 +963,8 @@ static void iwl_pcie_rx_handle(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; - u32 r, i; - u8 fill_rx = 0; - u32 count = 8; - int total_empty; + u32 r, i, j, count = 0; + bool emergency = false; restart: spin_lock(&rxq->lock); @@ -714,47 +977,95 @@ restart: if (i == r) IWL_DEBUG_RX(trans, "HW = SW = %d\n", r); - /* calculate total frames need to be restock after handling RX */ - total_empty = r - rxq->write_actual; - if (total_empty < 0) - total_empty += RX_QUEUE_SIZE; - - if (total_empty > (RX_QUEUE_SIZE / 2)) - fill_rx = 1; - while (i != r) { struct iwl_rx_mem_buffer *rxb; + if (unlikely(rxq->used_count == RX_QUEUE_SIZE / 2)) + emergency = true; + rxb = rxq->queue[i]; rxq->queue[i] = NULL; IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d (%p)\n", r, i, rxb); - iwl_pcie_rx_handle_rb(trans, rxb); + iwl_pcie_rx_handle_rb(trans, rxb, emergency); i = (i + 1) & RX_QUEUE_MASK; - /* If there are a lot of unused frames, - * restock the Rx queue so ucode wont assert. */ - if (fill_rx) { + + /* If we have RX_CLAIM_REQ_ALLOC released rx buffers - + * try to claim the pre-allocated buffers from the allocator */ + if (rxq->used_count >= RX_CLAIM_REQ_ALLOC) { + struct iwl_rb_allocator *rba = &trans_pcie->rba; + struct iwl_rx_mem_buffer *out[RX_CLAIM_REQ_ALLOC]; + + if (rxq->used_count % RX_CLAIM_REQ_ALLOC == 0 && + !emergency) { + /* Add the remaining 6 empty RBDs + * for allocator use + */ + spin_lock(&rba->lock); + list_splice_tail_init(&rxq->rx_used, + &rba->rbd_empty); + spin_unlock(&rba->lock); + } + + /* If not ready - continue, will try to reclaim later. + * No need to reschedule work - allocator exits only on + * success */ + if (!iwl_pcie_rx_allocator_get(trans, out)) { + /* If success - then RX_CLAIM_REQ_ALLOC + * buffers were retrieved and should be added + * to free list */ + rxq->used_count -= RX_CLAIM_REQ_ALLOC; + for (j = 0; j < RX_CLAIM_REQ_ALLOC; j++) { + list_add_tail(&out[j]->list, + &rxq->rx_free); + rxq->free_count++; + } + } + } + if (emergency) { count++; - if (count >= 8) { - rxq->read = i; - spin_unlock(&rxq->lock); - iwl_pcie_rx_replenish(trans, GFP_ATOMIC); + if (count == 8) { count = 0; - goto restart; + if (rxq->used_count < RX_QUEUE_SIZE / 3) + emergency = false; + spin_unlock(&rxq->lock); + iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC); + spin_lock(&rxq->lock); } } + /* handle restock for three cases, can be all of them at once: + * - we just pulled buffers from the allocator + * - we have 8+ unstolen pages accumulated + * - we are in emergency and allocated buffers + */ + if (rxq->free_count >= RX_CLAIM_REQ_ALLOC) { + rxq->read = i; + spin_unlock(&rxq->lock); + iwl_pcie_rxq_restock(trans); + goto restart; + } } /* Backtrack one entry */ rxq->read = i; spin_unlock(&rxq->lock); - if (fill_rx) - iwl_pcie_rx_replenish(trans, GFP_ATOMIC); - else - iwl_pcie_rxq_restock(trans); + /* + * handle a case where in emergency there are some unallocated RBDs. + * those RBDs are in the used list, but are not tracked by the queue's + * used_count which counts allocator owned RBDs. + * unallocated emergency RBDs must be allocated on exit, otherwise + * when called again the function may not be in emergency mode and + * they will be handed to the allocator with no tracking in the RBD + * allocator counters, which will lead to them never being claimed back + * by the queue. + * by allocating them here, they are now in the queue free list, and + * will be restocked by the next call of iwl_pcie_rxq_restock. + */ + if (unlikely(emergency && count)) + iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC); if (trans_pcie->napi.poll) napi_gro_flush(&trans_pcie->napi, false); -- cgit v1.3-6-gb490 From e112018776a88b1e9c31fff3c6a9341c4f37c358 Mon Sep 17 00:00:00 2001 From: Matti Gottlieb Date: Sun, 19 Jul 2015 11:15:07 +0300 Subject: iwlwifi: mvm: Add FW paging mechanism for the UMAC on SDIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Family 8000 products has 2 embedded processors, the first known as LMAC (lower MAC) and implements the functionality from previous products, the second one is known as UMAC (upper MAC) and is used mainly for driver offloads as well as new features. The UMAC is typically “less” real-time than the LMAC and is used for higher level controls. The UMAC's code/data size is estimated to be in the mega-byte arena, taking into account the code it needs to replace in the driver and the set of new features. In order to allow the UMAC to execute code that is bigger than its code memory, we allow the UMAC embedded processor to page out code pages on DRAM. When the device is slave on the bus(SDIO) the driver saves the UMAC's image pages in blocks of 32K in the DRAM and sends the layout of the pages to the FW. When the FW wants load / unload pages, it creates an interrupt, and the driver uploads / downloads the page to an address in the a specific address on the device's memory. The driver can support up to 1 MB of pages. Add paging mechanism for the UMAC on SDIO in order to allow the program to use a larger virtual space while using less physical memory on the device itself. Signed-off-by: Matti Gottlieb Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-csr.h | 2 + drivers/net/wireless/iwlwifi/iwl-fw.h | 3 ++ drivers/net/wireless/iwlwifi/iwl-prph.h | 6 +++ drivers/net/wireless/iwlwifi/iwl-trans.h | 14 ++++++ drivers/net/wireless/iwlwifi/mvm/fw-api.h | 26 +++++++++++ drivers/net/wireless/iwlwifi/mvm/fw.c | 76 +++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/mvm/ops.c | 1 + 7 files changed, 128 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index fa716618735e..543abeaffcf0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -200,6 +200,7 @@ #define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ #define CSR_INT_BIT_SCD (1 << 26) /* TXQ pointer advanced */ #define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ +#define CSR_INT_BIT_PAGING (1 << 24) /* SDIO PAGING */ #define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ #define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ #define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */ @@ -210,6 +211,7 @@ CSR_INT_BIT_HW_ERR | \ CSR_INT_BIT_FH_TX | \ CSR_INT_BIT_SW_ERR | \ + CSR_INT_BIT_PAGING | \ CSR_INT_BIT_RF_KILL | \ CSR_INT_BIT_SW_RX | \ CSR_INT_BIT_WAKEUP | \ diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 0d9d6f51766e..45e732150d28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -163,6 +163,9 @@ struct iwl_sf_region { /* maximum image size 1024KB */ #define MAX_PAGING_IMAGE_SIZE (NUM_OF_BLOCK_PER_IMAGE * PAGING_BLOCK_SIZE) +/* Virtual address signature */ +#define PAGING_ADDR_SIG 0xAA000000 + #define PAGING_CMD_IS_SECURED BIT(9) #define PAGING_CMD_IS_ENABLED BIT(8) #define PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS 0 diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index c4e7a713af0f..3ab777f79e4f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -392,4 +392,10 @@ enum { LMPM_CHICK_EXTENDED_ADDR_SPACE = BIT(0), }; +/* FW chicken bits */ +#define LMPM_PAGE_PASS_NOTIF 0xA03824 +enum { + LMPM_PAGE_PASS_NOTIF_POS = BIT(20), +}; + #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 151e3de2247f..9d8b5cb06343 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -668,6 +668,12 @@ enum iwl_d0i3_mode { * @dbg_conf_tlv: array of pointers to configuration TLVs for debug * @dbg_trigger_tlv: array of pointers to triggers TLVs for debug * @dbg_dest_reg_num: num of reg_ops in %dbg_dest_tlv + * @paging_req_addr: The location were the FW will upload / download the pages + * from. The address is set by the opmode + * @paging_db: Pointer to the opmode paging data base, the pointer is set by + * the opmode. + * @paging_download_buf: Buffer used for copying all of the pages before + * downloading them to the FW. The buffer is allocated in the opmode */ struct iwl_trans { const struct iwl_trans_ops *ops; @@ -705,6 +711,14 @@ struct iwl_trans { struct iwl_fw_dbg_trigger_tlv * const *dbg_trigger_tlv; u8 dbg_dest_reg_num; + /* + * Paging parameters - All of the parameters should be set by the + * opmode when paging is enabled + */ + u32 paging_req_addr; + struct iwl_fw_paging *paging_db; + void *paging_download_buf; + enum iwl_d0i3_mode d0i3_mode; bool wowlan_d0i3; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 9c6b153f2e12..4af7513adda2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -120,6 +120,9 @@ enum { ADD_STA = 0x18, REMOVE_STA = 0x19, + /* paging get item */ + FW_GET_ITEM_CMD = 0x1a, + /* TX */ TX_CMD = 0x1c, TXPATH_FLUSH = 0x1e, @@ -394,6 +397,29 @@ struct iwl_fw_paging_cmd { __le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; } __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */ +/* + * Fw items ID's + * + * @IWL_FW_ITEM_ID_PAGING: Address of the pages that the FW will upload + * download + */ +enum iwl_fw_item_id { + IWL_FW_ITEM_ID_PAGING = 3, +}; + +/* + * struct iwl_fw_get_item_cmd - get an item from the fw + */ +struct iwl_fw_get_item_cmd { + __le32 item_id; +} __packed; /* FW_GET_ITEM_CMD_API_S_VER_1 */ + +struct iwl_fw_get_item_resp { + __le32 item_id; + __le32 item_byte_cnt; + __le32 item_val; +} __packed; /* FW_GET_ITEM_RSP_S_VER_1 */ + /** * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD * @offset: offset in bytes into the section diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index aff5bbf3f141..4a0ce83315bd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -125,6 +125,7 @@ static void iwl_free_fw_paging(struct iwl_mvm *mvm) __free_pages(mvm->fw_paging_db[i].fw_paging_block, get_order(mvm->fw_paging_db[i].fw_paging_size)); } + kfree(mvm->trans->paging_download_buf); memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db)); } @@ -258,6 +259,9 @@ static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm, return -ENOMEM; } mvm->fw_paging_db[blk_idx].fw_paging_phys = phys; + } else { + mvm->fw_paging_db[blk_idx].fw_paging_phys = PAGING_ADDR_SIG | + blk_idx << BLOCK_2_EXP_SIZE; } IWL_DEBUG_FW(mvm, @@ -294,6 +298,10 @@ static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm, return -ENOMEM; } mvm->fw_paging_db[blk_idx].fw_paging_phys = phys; + } else { + mvm->fw_paging_db[blk_idx].fw_paging_phys = + PAGING_ADDR_SIG | + blk_idx << BLOCK_2_EXP_SIZE; } IWL_DEBUG_FW(mvm, @@ -344,6 +352,60 @@ static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw) 0, sizeof(fw_paging_cmd), &fw_paging_cmd); } +/* + * Send paging item cmd to FW in case CPU2 has paging image + */ +static int iwl_trans_get_paging_item(struct iwl_mvm *mvm) +{ + int ret; + struct iwl_fw_get_item_cmd fw_get_item_cmd = { + .item_id = cpu_to_le32(IWL_FW_ITEM_ID_PAGING), + }; + + struct iwl_fw_get_item_resp *item_resp; + struct iwl_host_cmd cmd = { + .id = iwl_cmd_id(FW_GET_ITEM_CMD, IWL_ALWAYS_LONG_GROUP, 0), + .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, + .data = { &fw_get_item_cmd, }, + }; + + cmd.len[0] = sizeof(struct iwl_fw_get_item_cmd); + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) { + IWL_ERR(mvm, + "Paging: Failed to send FW_GET_ITEM_CMD cmd (err = %d)\n", + ret); + return ret; + } + + item_resp = (void *)((struct iwl_rx_packet *)cmd.resp_pkt)->data; + if (item_resp->item_id != cpu_to_le32(IWL_FW_ITEM_ID_PAGING)) { + IWL_ERR(mvm, + "Paging: got wrong item in FW_GET_ITEM_CMD resp (item_id = %u)\n", + le32_to_cpu(item_resp->item_id)); + ret = -EIO; + goto exit; + } + + mvm->trans->paging_download_buf = kzalloc(MAX_PAGING_IMAGE_SIZE, + GFP_KERNEL); + if (!mvm->trans->paging_download_buf) { + ret = -ENOMEM; + goto exit; + } + mvm->trans->paging_req_addr = le32_to_cpu(item_resp->item_val); + mvm->trans->paging_db = mvm->fw_paging_db; + IWL_DEBUG_FW(mvm, + "Paging: got paging request address (paging_req_addr 0x%08x)\n", + mvm->trans->paging_req_addr); + +exit: + iwl_free_resp(&cmd); + + return ret; +} + static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt, void *data) { @@ -517,6 +579,20 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, * included in the IWL_UCODE_INIT image. */ if (fw->paging_mem_size) { + /* + * When dma is not enabled, the driver needs to copy / write + * the downloaded / uploaded page to / from the smem. + * This gets the location of the place were the pages are + * stored. + */ + if (!is_device_dma_capable(mvm->trans->dev)) { + ret = iwl_trans_get_paging_item(mvm); + if (ret) { + IWL_ERR(mvm, "failed to get FW paging item\n"); + return ret; + } + } + ret = iwl_save_fw_paging(mvm, fw); if (ret) { IWL_ERR(mvm, "failed to save the FW paging image\n"); diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 48731124afe1..5d577c13db5b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -291,6 +291,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { CMD(FW_PAGING_BLOCK_CMD), CMD(ADD_STA_KEY), CMD(ADD_STA), + CMD(FW_GET_ITEM_CMD), CMD(REMOVE_STA), CMD(LQ_CMD), CMD(SCAN_OFFLOAD_CONFIG_CMD), -- cgit v1.3-6-gb490 From eed6e971973667d067d510e9540773ff0f9fe8fd Mon Sep 17 00:00:00 2001 From: Assaf Krauss Date: Wed, 22 Jul 2015 14:21:31 +0300 Subject: iwlwifi: mvm: ToF - Set correct range request cmd id Command ID of ToF range request command adapted to new FW commands grouping scheme. Signed-off-by: Assaf Krauss Reviewed-by: Gregory Greenman Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/tof.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/tof.c b/drivers/net/wireless/iwlwifi/mvm/tof.c index d060e12c3239..380972f8fb82 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tof.c +++ b/drivers/net/wireless/iwlwifi/mvm/tof.c @@ -194,7 +194,7 @@ int iwl_mvm_tof_range_request_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_host_cmd cmd = { - .id = TOF_CMD, + .id = iwl_cmd_id(TOF_CMD, IWL_ALWAYS_LONG_GROUP, 0), .len = { sizeof(mvm->tof_data.range_req), }, /* no copy because of the command size */ .dataflags = { IWL_HCMD_DFL_NOCOPY, }, -- cgit v1.3-6-gb490 From b084a35663c3f1f7de1c45c4ae3006864c940fe7 Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Sun, 12 Jul 2015 09:10:05 +0300 Subject: iwlwifi: mvm: set different pm_timeout for action frames When building a Tx Command for management frames, we are lacking a check for action frames, for which we should set a different pm_timeout. This cause the fw to stay awake for 100TU after each such frame is transmitted, resulting an excessive power consumption. Signed-off-by: Avri Altman Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h | 12 ++++++++++++ drivers/net/wireless/iwlwifi/mvm/tx.c | 10 ++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 81c4ea3c6958..853698ab8b05 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h @@ -124,6 +124,18 @@ enum iwl_tx_flags { TX_CMD_FLG_HCCA_CHUNK = BIT(31) }; /* TX_FLAGS_BITS_API_S_VER_1 */ +/** + * enum iwl_tx_pm_timeouts - pm timeout values in TX command + * @PM_FRAME_NONE: no need to suspend sleep mode + * @PM_FRAME_MGMT: fw suspend sleep mode for 100TU + * @PM_FRAME_ASSOC: fw suspend sleep mode for 10sec + */ +enum iwl_tx_pm_timeouts { + PM_FRAME_NONE = 0, + PM_FRAME_MGMT = 2, + PM_FRAME_ASSOC = 3, +}; + /* * TX command security control */ diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 15bf36ad3809..6df5aada4f16 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -153,18 +153,20 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, 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); + tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_ASSOC); + else if (ieee80211_is_action(fc)) + tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); else - tx_cmd->pm_frame_timeout = cpu_to_le16(2); + tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); /* The spec allows Action frames in A-MPDU, we don't support * it */ WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); } else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) { - tx_cmd->pm_frame_timeout = cpu_to_le16(2); + tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); } else { - tx_cmd->pm_frame_timeout = 0; + tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); } if (ieee80211_is_data(fc) && len > mvm->rts_threshold && -- cgit v1.3-6-gb490 From 7d6548abcf4ea4845db8a62a5875d93e2c1bf882 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Aug 2015 11:43:40 -0700 Subject: Input: Allow compile test of GPIO consumers if !GPIOLIB The GPIO subsystem provides dummy GPIO consumer functions if GPIOLIB is not enabled. Hence drivers that depend on GPIOLIB, but use GPIO consumer functionality only, can still be compiled if GPIOLIB is not enabled. Relax the dependency on GPIOLIB if COMPILE_TEST is enabled, where appropriate. Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 4 ++-- drivers/input/misc/Kconfig | 11 ++++++----- drivers/input/mouse/Kconfig | 2 +- drivers/input/touchscreen/Kconfig | 8 ++++---- 4 files changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 4cd94fd6cbad..10dfa23b11a8 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -187,7 +187,7 @@ config KEYBOARD_EP93XX config KEYBOARD_GPIO tristate "GPIO Buttons" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help This driver implements support for buttons connected to GPIO pins of various CPUs (and some other chips). @@ -253,7 +253,7 @@ config KEYBOARD_TCA8418 config KEYBOARD_MATRIX tristate "GPIO driven matrix keypad support" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST select INPUT_MATRIXKMAP help Enable support for GPIO driven matrix keypad. diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index d4f0a817e858..dade381c7da8 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -259,7 +259,7 @@ config INPUT_APANEL config INPUT_GP2A tristate "Sharp GP2AP002A00F I2C Proximity/Opto sensor driver" depends on I2C - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y here if you have a Sharp GP2AP002A00F proximity/als combo-chip hooked to an I2C bus. @@ -269,7 +269,7 @@ config INPUT_GP2A config INPUT_GPIO_BEEPER tristate "Generic GPIO Beeper support" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y here if you have a beeper connected to a GPIO pin. @@ -278,7 +278,7 @@ config INPUT_GPIO_BEEPER config INPUT_GPIO_TILT_POLLED tristate "Polled GPIO tilt switch" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST select INPUT_POLLDEV help This driver implements support for tilt switches connected @@ -569,7 +569,7 @@ config INPUT_PWM_BEEPER config INPUT_GPIO_ROTARY_ENCODER tristate "Rotary encoders connected to GPIO pins" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y here to add support for rotary encoders connected to GPIO lines. Check file:Documentation/input/rotary-encoder.txt for more @@ -776,7 +776,8 @@ config INPUT_SOC_BUTTON_ARRAY config INPUT_DRV260X_HAPTICS tristate "TI DRV260X haptics support" - depends on INPUT && I2C && GPIOLIB + depends on INPUT && I2C + depends on GPIOLIB || COMPILE_TEST select INPUT_FF_MEMLESS select REGMAP_I2C help diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index d7820d1152d2..17f97e5e11e7 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -341,7 +341,7 @@ config MOUSE_VSXXXAA config MOUSE_GPIO tristate "GPIO mouse" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST select INPUT_POLLDEV help This driver simulates a mouse on GPIO lines of various CPUs (and some diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 860d426c480e..059edeb7f04a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -118,7 +118,7 @@ config TOUCHSCREEN_ATMEL_MXT config TOUCHSCREEN_AUO_PIXCIR tristate "AUO in-cell touchscreen using Pixcir ICs" depends on I2C - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y here if you have a AUO display with in-cell touchscreen using Pixcir ICs. @@ -142,7 +142,7 @@ config TOUCHSCREEN_BU21013 config TOUCHSCREEN_CHIPONE_ICN8318 tristate "chipone icn8318 touchscreen controller" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST depends on I2C depends on OF help @@ -156,7 +156,7 @@ config TOUCHSCREEN_CHIPONE_ICN8318 config TOUCHSCREEN_CY8CTMG110 tristate "cy8ctmg110 touchscreen" depends on I2C - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y here if you have a cy8ctmg110 capacitive touchscreen on an AAVA device. @@ -1030,7 +1030,7 @@ config TOUCHSCREEN_TPS6507X config TOUCHSCREEN_ZFORCE tristate "Neonode zForce infrared touchscreens" depends on I2C - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y here if you have a touchscreen using the zforce infraread technology from Neonode. -- cgit v1.3-6-gb490 From 7f3884f7de89c49439fdaa115f6d1caec3256cc3 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:36:29 -0700 Subject: Input: atmel_mxt_ts - use deep sleep mode when stopped The hardcoded 0x83 CTRL setting overrides other settings in that byte, enabling extra reporting that may not be useful on a particular platform. Implement improved suspend mechanism via deep sleep. By writing zero to both the active and idle cycle times the maXTouch device can be put into a deep sleep mode, using minimal power. It is necessary to issue a calibrate command after the chip has spent any time in deep sleep, however a soft reset is unnecessary. Use the old method on Chromebook Pixel via platform data option. This patch also deals with the situation where the power configuration is zero on probe, which would mean that the device never wakes up to execute commands. After a config download, the T7 power configuration may have changed so it is necessary to re-read it. Signed-off-by: Nick Dyer Acked-by: Benson Leung Acked-by: Yufeng Shen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 119 ++++++++++++++++++++++++++--- drivers/platform/chrome/chromeos_laptop.c | 4 +- include/linux/i2c/atmel_mxt_ts.h | 25 ------ include/linux/platform_data/atmel_mxt_ts.h | 31 ++++++++ 4 files changed, 142 insertions(+), 37 deletions(-) delete mode 100644 include/linux/i2c/atmel_mxt_ts.h create mode 100644 include/linux/platform_data/atmel_mxt_ts.h (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 8efe7a002f1e..0e743b3a691b 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -103,9 +103,13 @@ #define MXT_T6_STATUS_COMSERR (1 << 2) /* MXT_GEN_POWER_T7 field */ -#define MXT_POWER_IDLEACQINT 0 -#define MXT_POWER_ACTVACQINT 1 -#define MXT_POWER_ACTV2IDLETO 2 +struct t7_config { + u8 idle; + u8 active; +} __packed; + +#define MXT_POWER_CFG_RUN 0 +#define MXT_POWER_CFG_DEEPSLEEP 1 /* MXT_GEN_ACQUIRE_T8 field */ #define MXT_ACQUIRE_CHRGTIME 0 @@ -117,7 +121,7 @@ #define MXT_ACQUIRE_ATCHCALSTHR 7 /* MXT_TOUCH_MULTI_T9 field */ -#define MXT_TOUCH_CTRL 0 +#define MXT_T9_CTRL 0 #define MXT_T9_ORIENT 9 #define MXT_T9_RANGE 18 @@ -291,6 +295,7 @@ struct mxt_data { u8 last_message_count; u8 num_touchids; u8 multitouch; + struct t7_config t7_cfg; /* Cached parameters from object table */ u16 T5_address; @@ -1361,6 +1366,8 @@ static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start, return 0; } +static int mxt_init_t7_power_cfg(struct mxt_data *data); + /* * mxt_update_cfg - download configuration to chip * @@ -1508,6 +1515,9 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) dev_info(dev, "Config successfully updated\n"); + /* T7 config may have changed */ + mxt_init_t7_power_cfg(data); + release_mem: kfree(config_mem); return ret; @@ -2051,6 +2061,60 @@ err_free_object_table: return error; } +static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep) +{ + struct device *dev = &data->client->dev; + int error; + struct t7_config *new_config; + struct t7_config deepsleep = { .active = 0, .idle = 0 }; + + if (sleep == MXT_POWER_CFG_DEEPSLEEP) + new_config = &deepsleep; + else + new_config = &data->t7_cfg; + + error = __mxt_write_reg(data->client, data->T7_address, + sizeof(data->t7_cfg), new_config); + if (error) + return error; + + dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n", + new_config->active, new_config->idle); + + return 0; +} + +static int mxt_init_t7_power_cfg(struct mxt_data *data) +{ + struct device *dev = &data->client->dev; + int error; + bool retry = false; + +recheck: + error = __mxt_read_reg(data->client, data->T7_address, + sizeof(data->t7_cfg), &data->t7_cfg); + if (error) + return error; + + if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) { + if (!retry) { + dev_dbg(dev, "T7 cfg zero, resetting\n"); + mxt_soft_reset(data); + retry = true; + goto recheck; + } else { + dev_dbg(dev, "T7 cfg zero after reset, overriding\n"); + data->t7_cfg.active = 20; + data->t7_cfg.idle = 100; + return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); + } + } + + dev_dbg(dev, "Initialized power cfg: ACTV %d, IDLE %d\n", + data->t7_cfg.active, data->t7_cfg.idle); + return 0; +} + static int mxt_configure_objects(struct mxt_data *data, const struct firmware *cfg) { @@ -2058,6 +2122,12 @@ static int mxt_configure_objects(struct mxt_data *data, struct mxt_info *info = &data->info; int error; + error = mxt_init_t7_power_cfg(data); + if (error) { + dev_err(dev, "Failed to initialize power cfg\n"); + return error; + } + if (cfg) { error = mxt_update_cfg(data, cfg); if (error) @@ -2346,14 +2416,41 @@ static const struct attribute_group mxt_attr_group = { static void mxt_start(struct mxt_data *data) { - /* Touch enable */ - mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0x83); + switch (data->pdata->suspend_mode) { + case MXT_SUSPEND_T9_CTRL: + mxt_soft_reset(data); + + /* Touch enable */ + /* 0x83 = SCANEN | RPTEN | ENABLE */ + mxt_write_object(data, + MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83); + break; + + case MXT_SUSPEND_DEEP_SLEEP: + default: + mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); + + /* Recalibrate since chip has been in deep sleep */ + mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false); + break; + } + } static void mxt_stop(struct mxt_data *data) { - /* Touch disable */ - mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0); + switch (data->pdata->suspend_mode) { + case MXT_SUSPEND_T9_CTRL: + /* Touch disable */ + mxt_write_object(data, + MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0); + break; + + case MXT_SUSPEND_DEEP_SLEEP: + default: + mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP); + break; + } } static int mxt_input_open(struct input_dev *dev) @@ -2409,6 +2506,8 @@ static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) pdata->t19_keymap = keymap; } + pdata->suspend_mode = MXT_SUSPEND_DEEP_SLEEP; + return pdata; } #else @@ -2625,8 +2724,6 @@ static int __maybe_unused mxt_resume(struct device *dev) struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; - mxt_soft_reset(data); - mutex_lock(&input_dev->mutex); if (input_dev->users) diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c index a04019ab9feb..02072749fff3 100644 --- a/drivers/platform/chrome/chromeos_laptop.c +++ b/drivers/platform/chrome/chromeos_laptop.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -111,6 +111,7 @@ static struct mxt_platform_data atmel_224s_tp_platform_data = { .irqflags = IRQF_TRIGGER_FALLING, .t19_num_keys = ARRAY_SIZE(mxt_t19_keys), .t19_keymap = mxt_t19_keys, + .suspend_mode = MXT_SUSPEND_T9_CTRL, }; static struct i2c_board_info atmel_224s_tp_device = { @@ -121,6 +122,7 @@ static struct i2c_board_info atmel_224s_tp_device = { static struct mxt_platform_data atmel_1664s_platform_data = { .irqflags = IRQF_TRIGGER_FALLING, + .suspend_mode = MXT_SUSPEND_T9_CTRL, }; static struct i2c_board_info atmel_1664s_device = { diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h deleted file mode 100644 index 02bf6ea31701..000000000000 --- a/include/linux/i2c/atmel_mxt_ts.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Atmel maXTouch Touchscreen driver - * - * Copyright (C) 2010 Samsung Electronics Co.Ltd - * Author: Joonyoung Shim - * - * 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 __LINUX_ATMEL_MXT_TS_H -#define __LINUX_ATMEL_MXT_TS_H - -#include - -/* The platform data for the Atmel maXTouch touchscreen driver */ -struct mxt_platform_data { - unsigned long irqflags; - u8 t19_num_keys; - const unsigned int *t19_keymap; -}; - -#endif /* __LINUX_ATMEL_MXT_TS_H */ diff --git a/include/linux/platform_data/atmel_mxt_ts.h b/include/linux/platform_data/atmel_mxt_ts.h new file mode 100644 index 000000000000..695035a8d7fb --- /dev/null +++ b/include/linux/platform_data/atmel_mxt_ts.h @@ -0,0 +1,31 @@ +/* + * Atmel maXTouch Touchscreen driver + * + * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * + * 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 __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H +#define __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H + +#include + +enum mxt_suspend_mode { + MXT_SUSPEND_DEEP_SLEEP = 0, + MXT_SUSPEND_T9_CTRL = 1, +}; + +/* The platform data for the Atmel maXTouch touchscreen driver */ +struct mxt_platform_data { + unsigned long irqflags; + u8 t19_num_keys; + const unsigned int *t19_keymap; + enum mxt_suspend_mode suspend_mode; +}; + +#endif /* __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H */ -- cgit v1.3-6-gb490 From 146c6a662f6b16536581afc8ed4c11460301a82d Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:49:34 -0700 Subject: Input: atmel_mxt_ts - remove unused defines Many of these values are out of date and they aren't used in the driver - all they do is increase the size of the kernel source. Signed-off-by: Nick Dyer Acked-by: Benson Leung Acked-by: Yufeng Shen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 66 +------------------------------- 1 file changed, 1 insertion(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 0e743b3a691b..d53d4ac57f33 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -29,27 +29,13 @@ #include #include -/* Version */ -#define MXT_VER_20 20 -#define MXT_VER_21 21 -#define MXT_VER_22 22 - /* Firmware files */ #define MXT_FW_NAME "maxtouch.fw" #define MXT_CFG_NAME "maxtouch.cfg" #define MXT_CFG_MAGIC "OBP_RAW V1" /* Registers */ -#define MXT_INFO 0x00 -#define MXT_FAMILY_ID 0x00 -#define MXT_VARIANT_ID 0x01 -#define MXT_VERSION 0x02 -#define MXT_BUILD 0x03 -#define MXT_MATRIX_X_SIZE 0x04 -#define MXT_MATRIX_Y_SIZE 0x05 -#define MXT_OBJECT_NUM 0x06 #define MXT_OBJECT_START 0x07 - #define MXT_OBJECT_SIZE 6 #define MXT_INFO_CHECKSUM_SIZE 3 #define MXT_MAX_BLOCK_WRITE 256 @@ -111,15 +97,6 @@ struct t7_config { #define MXT_POWER_CFG_RUN 0 #define MXT_POWER_CFG_DEEPSLEEP 1 -/* MXT_GEN_ACQUIRE_T8 field */ -#define MXT_ACQUIRE_CHRGTIME 0 -#define MXT_ACQUIRE_TCHDRIFT 2 -#define MXT_ACQUIRE_DRIFTST 3 -#define MXT_ACQUIRE_TCHAUTOCAL 4 -#define MXT_ACQUIRE_SYNC 5 -#define MXT_ACQUIRE_ATCHCALST 6 -#define MXT_ACQUIRE_ATCHCALSTHR 7 - /* MXT_TOUCH_MULTI_T9 field */ #define MXT_T9_CTRL 0 #define MXT_T9_ORIENT 9 @@ -143,51 +120,10 @@ struct t9_range { /* MXT_TOUCH_MULTI_T9 orient */ #define MXT_T9_ORIENT_SWITCH (1 << 0) -/* MXT_PROCI_GRIPFACE_T20 field */ -#define MXT_GRIPFACE_CTRL 0 -#define MXT_GRIPFACE_XLOGRIP 1 -#define MXT_GRIPFACE_XHIGRIP 2 -#define MXT_GRIPFACE_YLOGRIP 3 -#define MXT_GRIPFACE_YHIGRIP 4 -#define MXT_GRIPFACE_MAXTCHS 5 -#define MXT_GRIPFACE_SZTHR1 7 -#define MXT_GRIPFACE_SZTHR2 8 -#define MXT_GRIPFACE_SHPTHR1 9 -#define MXT_GRIPFACE_SHPTHR2 10 -#define MXT_GRIPFACE_SUPEXTTO 11 - -/* MXT_PROCI_NOISE field */ -#define MXT_NOISE_CTRL 0 -#define MXT_NOISE_OUTFLEN 1 -#define MXT_NOISE_GCAFUL_LSB 3 -#define MXT_NOISE_GCAFUL_MSB 4 -#define MXT_NOISE_GCAFLL_LSB 5 -#define MXT_NOISE_GCAFLL_MSB 6 -#define MXT_NOISE_ACTVGCAFVALID 7 -#define MXT_NOISE_NOISETHR 8 -#define MXT_NOISE_FREQHOPSCALE 10 -#define MXT_NOISE_FREQ0 11 -#define MXT_NOISE_FREQ1 12 -#define MXT_NOISE_FREQ2 13 -#define MXT_NOISE_FREQ3 14 -#define MXT_NOISE_FREQ4 15 -#define MXT_NOISE_IDLEGCAFVALID 16 - /* MXT_SPT_COMMSCONFIG_T18 */ #define MXT_COMMS_CTRL 0 #define MXT_COMMS_CMD 1 -/* MXT_SPT_CTECONFIG_T28 field */ -#define MXT_CTE_CTRL 0 -#define MXT_CTE_CMD 1 -#define MXT_CTE_MODE 2 -#define MXT_CTE_IDLEGCAFDEPTH 3 -#define MXT_CTE_ACTVGCAFDEPTH 4 -#define MXT_CTE_VOLTAGE 5 - -#define MXT_VOLTAGE_DEFAULT 2700000 -#define MXT_VOLTAGE_STEP 10000 - /* Define for MXT_GEN_COMMAND_T6 */ #define MXT_BOOT_VALUE 0xa5 #define MXT_RESET_VALUE 0x01 @@ -1543,7 +1479,7 @@ static int mxt_get_info(struct mxt_data *data) int error; /* Read 7-byte info block starting at address 0 */ - error = __mxt_read_reg(client, MXT_INFO, sizeof(*info), info); + error = __mxt_read_reg(client, 0, sizeof(*info), info); if (error) return error; -- cgit v1.3-6-gb490 From 50fabb02c7c08dace3562c05797a3c92591a9803 Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Tue, 4 Aug 2015 16:53:04 -0700 Subject: Input: atmel_mxt_ts - suspend/resume causes panic if input_dev fails to init input_dev may be NULL if mxt_initialize_input_device fails. But pm ops is still available and suspend/resume assume input_dev is not NULL. To fix this issue, we add a check if (!input_dev). Signed-off-by: Pan Xinhui Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index d53d4ac57f33..cf66ba1bbf0c 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2644,6 +2644,9 @@ static int __maybe_unused mxt_suspend(struct device *dev) struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; + if (!input_dev) + return 0; + mutex_lock(&input_dev->mutex); if (input_dev->users) @@ -2660,6 +2663,9 @@ static int __maybe_unused mxt_resume(struct device *dev) struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; + if (!input_dev) + return 0; + mutex_lock(&input_dev->mutex); if (input_dev->users) -- cgit v1.3-6-gb490 From 204476642db2ca3cd2e9b8380b58dc9f21a1e773 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:53:16 -0700 Subject: Input: atmel_mxt_ts - improve device tree parsing Use function rather than loop, define np to reduce wrapping. Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index cf66ba1bbf0c..08d9a0921798 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2409,19 +2409,18 @@ static void mxt_input_close(struct input_dev *dev) static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) { struct mxt_platform_data *pdata; + struct device_node *np = client->dev.of_node; u32 *keymap; - u32 keycode; - int proplen, i, ret; + int proplen, ret; - if (!client->dev.of_node) + if (!np) return ERR_PTR(-ENOENT); pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); - if (of_find_property(client->dev.of_node, "linux,gpio-keymap", - &proplen)) { + if (of_find_property(np, "linux,gpio-keymap", &proplen)) { pdata->t19_num_keys = proplen / sizeof(u32); keymap = devm_kzalloc(&client->dev, @@ -2430,14 +2429,11 @@ static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) if (!keymap) return ERR_PTR(-ENOMEM); - for (i = 0; i < pdata->t19_num_keys; i++) { - ret = of_property_read_u32_index(client->dev.of_node, - "linux,gpio-keymap", i, &keycode); - if (ret) - keycode = KEY_RESERVED; - - keymap[i] = keycode; - } + ret = of_property_read_u32_array(np, "linux,gpio-keymap", + keymap, pdata->t19_num_keys); + if (ret) + dev_warn(&client->dev, + "Couldn't read linux,gpio-keymap: %d\n", ret); pdata->t19_keymap = keymap; } -- cgit v1.3-6-gb490 From 885f3fb9fa1f9e185e8a4e905157087495734349 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:57:25 -0700 Subject: Input: atmel_mxt_ts - disable interrupt for 50ms after reset The CHG/interrupt line is momentarily set (approximately 100 ms) as an input after power-up or reset for diagnostic purposes. This may cause spurious interrupts, so disable interrupt handler during this period. Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 08d9a0921798..d36da65f8c72 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1098,7 +1098,9 @@ static int mxt_soft_reset(struct mxt_data *data) struct device *dev = &data->client->dev; int ret = 0; - dev_info(dev, "Resetting chip\n"); + dev_info(dev, "Resetting device\n"); + + disable_irq(data->irq); reinit_completion(&data->reset_completion); @@ -1106,6 +1108,11 @@ static int mxt_soft_reset(struct mxt_data *data) if (ret) return ret; + /* Ignore CHG line for 100ms after reset */ + msleep(100); + + enable_irq(data->irq); + ret = mxt_wait_for_completion(data, &data->reset_completion, MXT_RESET_TIMEOUT); if (ret) -- cgit v1.3-6-gb490 From eafc0c8783f091ae9426fc8288054a99eb39207f Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:57:40 -0700 Subject: Input: atmel_mxt_ts - initialise input slots with INPUT_MT_DIRECT This indicates the device coordinates should be directly mapped to screen. This is valid since scaling/flipping/rotation should be done by configuring the MXT device. It also flags to Android using INPUT_PROP_DIRECT that the device should be treated as a touch screen by default, and removes the necessity for a default IDC file. Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index d36da65f8c72..0ea9903dde27 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1858,6 +1858,8 @@ static int mxt_initialize_input_device(struct mxt_data *data) if (pdata->t19_num_keys) { mxt_set_up_as_touchpad(input_dev, data); mt_flags |= INPUT_MT_POINTER; + } else { + mt_flags |= INPUT_MT_DIRECT; } /* For multi touch */ -- cgit v1.3-6-gb490 From 507584e202c598b5ba2c3cf5fa283ebbda9edc26 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:58:05 -0700 Subject: Input: atmel_mxt_ts - remove warning on zero T44 count Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 0ea9903dde27..c5622058c22b 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -938,16 +938,15 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data) count = data->msg_buf[0]; - if (count == 0) { - /* - * This condition is caused by the CHG line being configured - * in Mode 0. It results in unnecessary I2C operations but it - * is benign. - */ - dev_dbg(dev, "Interrupt triggered but zero messages\n"); + /* + * This condition may be caused by the CHG line being configured in + * Mode 0. It results in unnecessary I2C operations but it is benign. + */ + if (count == 0) return IRQ_NONE; - } else if (count > data->max_reportid) { - dev_err(dev, "T44 count %d exceeded max report id\n", count); + + if (count > data->max_reportid) { + dev_warn(dev, "T44 count %d exceeded max report id\n", count); count = data->max_reportid; } -- cgit v1.3-6-gb490 From e57c4a67d71275e4a15b9f0f92a322ea27b26a6e Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: use runtime_pm to keep usb phy active while charging. The twl4030 usb phy needs to be active while we are using the USB VBUS as a current source for charging. In particular, the usb3v1 regulator must be enabled and the PHY_PWR_PHYPWD bit must be set to keep the phy powered. commit ab37813f4093a5f59cb8e083cde277289dc72ed3 twl4030_charger: Allow charger to control the regulator that feeds it gave the charger control over the regulator, but didn't resolve the PHY_PWR_PHYPWD issue. Now that both of these are controlled by runtime_pm in phy-twl4030-usb, we can simply take a runtime_pm reference to the USB phy whenever the charger wants to use it as a current source. So this patch reverts the above commit, and adds the necessary runtime_pm calls. Acked-by: Lee Jones Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- drivers/mfd/twl-core.c | 9 ++++----- drivers/power/twl4030_charger.c | 18 +++++------------- 2 files changed, 9 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 489674a2497e..831696ee2472 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -788,9 +788,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, static struct regulator_consumer_supply usb1v8 = { .supply = "usb1v8", }; - static struct regulator_consumer_supply usb3v1[] = { - { .supply = "usb3v1" }, - { .supply = "bci3v1" }, + static struct regulator_consumer_supply usb3v1 = { + .supply = "usb3v1", }; /* First add the regulators so that they can be used by transceiver */ @@ -818,7 +817,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); child = add_regulator_linked(TWL4030_REG_VUSB3V1, - &usb_fixed, usb3v1, 2, + &usb_fixed, &usb3v1, 1, features); if (IS_ERR(child)) return PTR_ERR(child); @@ -838,7 +837,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) { usb1v5.dev_name = dev_name(child); usb1v8.dev_name = dev_name(child); - usb3v1[0].dev_name = dev_name(child); + usb3v1.dev_name = dev_name(child); } } diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 709d90dc75f1..fe71c61109f5 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -22,7 +22,6 @@ #include #include #include -#include #define TWL4030_BCIMSTATEC 0x02 #define TWL4030_BCIICHG 0x08 @@ -94,7 +93,6 @@ struct twl4030_bci { struct work_struct work; int irq_chg; int irq_bci; - struct regulator *usb_reg; int usb_enabled; unsigned long event; @@ -208,7 +206,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) { int ret; - if (enable) { + if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { /* Check for USB charger connected */ if (!twl4030_bci_have_vbus(bci)) return -ENODEV; @@ -222,14 +220,9 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) return -EACCES; } - /* Need to keep regulator on */ + /* Need to keep phy powered */ if (!bci->usb_enabled) { - ret = regulator_enable(bci->usb_reg); - if (ret) { - dev_err(bci->dev, - "Failed to enable regulator\n"); - return ret; - } + pm_runtime_get_sync(bci->transceiver->dev); bci->usb_enabled = 1; } @@ -244,7 +237,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) } else { ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0); if (bci->usb_enabled) { - regulator_disable(bci->usb_reg); + pm_runtime_mark_last_busy(bci->transceiver->dev); + pm_runtime_put_autosuspend(bci->transceiver->dev); bci->usb_enabled = 0; } } @@ -609,8 +603,6 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) return ret; } - bci->usb_reg = regulator_get(bci->dev, "bci3v1"); - bci->usb = devm_power_supply_register(&pdev->dev, &twl4030_bci_usb_desc, NULL); if (IS_ERR(bci->usb)) { -- cgit v1.3-6-gb490 From 7396f708b9f1d8874dda9c6386c37b065d99b68f Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: convert to module_platform_driver instead of ..._probe. Drivers using module_platform_driver_probe cannot return EPROBE_DEFER from the probe function, which makes them rather useless these days... Convert to module_platform_driver() so EPROBE_DEFER can be used. Signed-off-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- drivers/power/twl4030_charger.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index fe71c61109f5..045238370d3f 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -568,7 +568,7 @@ static const struct power_supply_desc twl4030_bci_usb_desc = { .get_property = twl4030_bci_get_property, }; -static int __init twl4030_bci_probe(struct platform_device *pdev) +static int twl4030_bci_probe(struct platform_device *pdev) { struct twl4030_bci *bci; const struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data; @@ -692,14 +692,14 @@ static const struct of_device_id twl_bci_of_match[] = { MODULE_DEVICE_TABLE(of, twl_bci_of_match); static struct platform_driver twl4030_bci_driver = { + .probe = twl4030_bci_probe, .driver = { .name = "twl4030_bci", .of_match_table = of_match_ptr(twl_bci_of_match), }, .remove = __exit_p(twl4030_bci_remove), }; - -module_platform_driver_probe(twl4030_bci_driver, twl4030_bci_probe); +module_platform_driver(twl4030_bci_driver); MODULE_AUTHOR("Gražvydas Ignotas"); MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver"); -- cgit v1.3-6-gb490 From 3fc3895e4fe17ee92ae1d1bb9f04da6069e8c370 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: correctly handle -EPROBE_DEFER from devm_usb_get_phy_by_node Now that twl4030_bci_probe can safely return -EPROBE_DEFER, do so when devm_usb_get_phy_by_node returns that error. Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- drivers/power/twl4030_charger.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 045238370d3f..ffc123fb7158 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -636,9 +636,13 @@ static int twl4030_bci_probe(struct platform_device *pdev) phynode = of_find_compatible_node(bci->dev->of_node->parent, NULL, "ti,twl4030-usb"); - if (phynode) + if (phynode) { bci->transceiver = devm_usb_get_phy_by_node( bci->dev, phynode, &bci->usb_nb); + if (IS_ERR(bci->transceiver) && + PTR_ERR(bci->transceiver) == -EPROBE_DEFER) + return -EPROBE_DEFER; + } } /* Enable interrupts now. */ -- cgit v1.3-6-gb490 From 6e37ec8c77e3e6580cbb844dfeea0fb3970c0a35 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: trust phy to determine when USB power is available. The usb phy driver already determines when VBUS is available, so repeating the test in the charger driver is pointless duplication. On probe, process the last event from the phy, and from then on, do whatever the phy tells us without double-checking. Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- drivers/power/twl4030_charger.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index ffc123fb7158..a075216d65ed 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -177,28 +177,6 @@ static int twl4030_is_battery_present(struct twl4030_bci *bci) return -ENODEV; } -/* - * Check if VBUS power is present - */ -static int twl4030_bci_have_vbus(struct twl4030_bci *bci) -{ - int ret; - u8 hwsts; - - ret = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &hwsts, - TWL4030_PM_MASTER_STS_HW_CONDITIONS); - if (ret < 0) - return 0; - - dev_dbg(bci->dev, "check_vbus: HW_CONDITIONS %02x\n", hwsts); - - /* in case we also have STS_USB_ID, VBUS is driven by TWL itself */ - if ((hwsts & TWL4030_STS_VBUS) && !(hwsts & TWL4030_STS_USB_ID)) - return 1; - - return 0; -} - /* * Enable/Disable USB Charge functionality. */ @@ -207,10 +185,6 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) int ret; if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { - /* Check for USB charger connected */ - if (!twl4030_bci_have_vbus(bci)) - return -ENODEV; - /* * Until we can find out what current the device can provide, * require a module param to enable USB charging. @@ -662,7 +636,12 @@ static int twl4030_bci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret); twl4030_charger_enable_ac(true); - twl4030_charger_enable_usb(bci, true); + if (!IS_ERR_OR_NULL(bci->transceiver)) + twl4030_bci_usb_ncb(&bci->usb_nb, + bci->transceiver->last_event, + NULL); + else + twl4030_charger_enable_usb(bci, false); if (pdata) twl4030_charger_enable_backup(pdata->bb_uvolt, pdata->bb_uamp); -- cgit v1.3-6-gb490 From 3b542f089dcbdcf1c21a01927fbc6d5116af01f6 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: split uA calculation into a function. We will need this calculation in other places, so create functions to map between register value and uA value. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- drivers/power/twl4030_charger.c | 48 ++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index a075216d65ed..29984b263a35 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -177,6 +177,40 @@ static int twl4030_is_battery_present(struct twl4030_bci *bci) return -ENODEV; } +/* + * TI provided formulas: + * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85 + * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7 + * Here we use integer approximation of: + * CGAIN == 0: val * 1.6618 - 0.85 * 1000 + * CGAIN == 1: (val * 1.6618 - 0.85 * 1000) * 2 + */ +/* + * convert twl register value for currents into uA + */ +static int regval2ua(int regval, bool cgain) +{ + if (cgain) + return (regval * 16618 - 8500 * 1000) / 5; + else + return (regval * 16618 - 8500 * 1000) / 10; +} + +/* + * convert uA currents into twl register value + */ +static int ua2regval(int ua, bool cgain) +{ + int ret; + if (cgain) + ua /= 2; + ret = (ua * 10 + 8500 * 1000) / 16618; + /* rounding problems */ + if (ret < 512) + ret = 512; + return ret; +} + /* * Enable/Disable USB Charge functionality. */ @@ -366,14 +400,6 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, return NOTIFY_OK; } -/* - * TI provided formulas: - * CGAIN == 0: ICHG = (BCIICHG * 1.7) / (2^10 - 1) - 0.85 - * CGAIN == 1: ICHG = (BCIICHG * 3.4) / (2^10 - 1) - 1.7 - * Here we use integer approximation of: - * CGAIN == 0: val * 1.6618 - 0.85 - * CGAIN == 1: (val * 1.6618 - 0.85) * 2 - */ static int twl4030_charger_get_current(void) { int curr; @@ -388,11 +414,7 @@ static int twl4030_charger_get_current(void) if (ret) return ret; - ret = (curr * 16618 - 850 * 10000) / 10; - if (bcictl1 & TWL4030_CGAIN) - ret *= 2; - - return ret; + return regval2ua(curr, bcictl1 & TWL4030_CGAIN); } /* -- cgit v1.3-6-gb490 From 1098cb58aed8eb4e06302d947a38bbfb69c8b4ba Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: allow fine control of charger current. The twl4030 allows control of the incoming current. Part of this control is a 'CGAIN' setting which doubles the range for half the precision. This control affects several different current setting, so all need to be updated at once when CGAIN is changed. With this patch, all of these current setting are managed by the driver, but most are left at their default settings. The current drawn is set to 500mA if the allow_usb module parameter is set, and to 100mA otherwise. More fine control will appear in later patches. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- drivers/power/twl4030_charger.c | 168 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 160 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 29984b263a35..3b7cc631bb8a 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -31,6 +31,11 @@ #define TWL4030_BCIMFSTS4 0x10 #define TWL4030_BCICTL1 0x23 #define TWL4030_BB_CFG 0x12 +#define TWL4030_BCIIREF1 0x27 +#define TWL4030_BCIIREF2 0x28 +#define TWL4030_BCIMFKEY 0x11 +#define TWL4030_BCIMFTH8 0x1d +#define TWL4030_BCIMFTH9 0x1e #define TWL4030_BCIMFSTS1 0x01 @@ -95,6 +100,12 @@ struct twl4030_bci { int irq_bci; int usb_enabled; + /* + * ichg values in uA. If any are 'large', we set CGAIN to + * '1' which doubles the range for half the precision. + */ + unsigned int ichg_eoc, ichg_lo, ichg_hi, cur; + unsigned long event; }; @@ -211,6 +222,146 @@ static int ua2regval(int ua, bool cgain) return ret; } +static int twl4030_charger_update_current(struct twl4030_bci *bci) +{ + int status; + unsigned reg, cur_reg; + u8 bcictl1, oldreg, fullreg; + bool cgain = false; + u8 boot_bci; + + /* First, check thresholds and see if cgain is needed */ + if (bci->ichg_eoc >= 200000) + cgain = true; + if (bci->ichg_lo >= 400000) + cgain = true; + if (bci->ichg_hi >= 820000) + cgain = true; + if (bci->cur > 852000) + cgain = true; + + status = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1); + if (status < 0) + return status; + if (twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &boot_bci, + TWL4030_PM_MASTER_BOOT_BCI) < 0) + boot_bci = 0; + boot_bci &= 7; + + if ((!!cgain) != !!(bcictl1 & TWL4030_CGAIN)) + /* Need to turn for charging while we change the + * CGAIN bit. Leave it off while everything is + * updated. + */ + twl4030_clear_set_boot_bci(boot_bci, 0); + + /* + * For ichg_eoc, the hardware only supports reg values matching + * 100XXXX000, and requires the XXXX be stored in the high nibble + * of TWL4030_BCIMFTH8. + */ + reg = ua2regval(bci->ichg_eoc, cgain); + if (reg > 0x278) + reg = 0x278; + if (reg < 0x200) + reg = 0x200; + reg = (reg >> 3) & 0xf; + fullreg = reg << 4; + + /* + * For ichg_lo, reg value must match 10XXXX0000. + * XXXX is stored in low nibble of TWL4030_BCIMFTH8. + */ + reg = ua2regval(bci->ichg_lo, cgain); + if (reg > 0x2F0) + reg = 0x2F0; + if (reg < 0x200) + reg = 0x200; + reg = (reg >> 4) & 0xf; + fullreg |= reg; + + /* ichg_eoc and ichg_lo live in same register */ + status = twl4030_bci_read(TWL4030_BCIMFTH8, &oldreg); + if (status < 0) + return status; + if (oldreg != fullreg) { + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xF4, + TWL4030_BCIMFKEY); + if (status < 0) + return status; + twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, + fullreg, TWL4030_BCIMFTH8); + } + + /* ichg_hi threshold must be 1XXXX01100 (I think) */ + reg = ua2regval(bci->ichg_hi, cgain); + if (reg > 0x3E0) + reg = 0x3E0; + if (reg < 0x200) + reg = 0x200; + fullreg = (reg >> 5) & 0xF; + fullreg <<= 4; + status = twl4030_bci_read(TWL4030_BCIMFTH9, &oldreg); + if (status < 0) + return status; + if ((oldreg & 0xF0) != fullreg) { + fullreg |= (oldreg & 0x0F); + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7, + TWL4030_BCIMFKEY); + if (status < 0) + return status; + twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, + fullreg, TWL4030_BCIMFTH9); + } + + /* + * And finally, set the current. This is stored in + * two registers. + */ + reg = ua2regval(bci->cur, cgain); + /* we have only 10 bits */ + if (reg > 0x3ff) + reg = 0x3ff; + status = twl4030_bci_read(TWL4030_BCIIREF1, &oldreg); + if (status < 0) + return status; + cur_reg = oldreg; + status = twl4030_bci_read(TWL4030_BCIIREF2, &oldreg); + if (status < 0) + return status; + cur_reg |= oldreg << 8; + if (reg != oldreg) { + /* disable write protection for one write access for + * BCIIREF */ + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7, + TWL4030_BCIMFKEY); + if (status < 0) + return status; + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, + (reg & 0x100) ? 3 : 2, + TWL4030_BCIIREF2); + if (status < 0) + return status; + /* disable write protection for one write access for + * BCIIREF */ + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xE7, + TWL4030_BCIMFKEY); + if (status < 0) + return status; + status = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, + reg & 0xff, + TWL4030_BCIIREF1); + } + if ((!!cgain) != !!(bcictl1 & TWL4030_CGAIN)) { + /* Flip CGAIN and re-enable charging */ + bcictl1 ^= TWL4030_CGAIN; + twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, + bcictl1, TWL4030_BCICTL1); + twl4030_clear_set_boot_bci(0, boot_bci); + } + return 0; +} + /* * Enable/Disable USB Charge functionality. */ @@ -219,14 +370,6 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) int ret; if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { - /* - * Until we can find out what current the device can provide, - * require a module param to enable USB charging. - */ - if (!allow_usb) { - dev_warn(bci->dev, "USB charging is disabled.\n"); - return -EACCES; - } /* Need to keep phy powered */ if (!bci->usb_enabled) { @@ -578,6 +721,14 @@ static int twl4030_bci_probe(struct platform_device *pdev) if (!pdata) pdata = twl4030_bci_parse_dt(&pdev->dev); + bci->ichg_eoc = 80100; /* Stop charging when current drops to here */ + bci->ichg_lo = 241000; /* Low threshold */ + bci->ichg_hi = 500000; /* High threshold */ + if (allow_usb) + bci->cur = 500000; /* 500mA */ + else + bci->cur = 100000; /* 100mA */ + bci->dev = &pdev->dev; bci->irq_chg = platform_get_irq(pdev, 0); bci->irq_bci = platform_get_irq(pdev, 1); @@ -657,6 +808,7 @@ static int twl4030_bci_probe(struct platform_device *pdev) if (ret < 0) dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret); + twl4030_charger_update_current(bci); twl4030_charger_enable_ac(true); if (!IS_ERR_OR_NULL(bci->transceiver)) twl4030_bci_usb_ncb(&bci->usb_nb, -- cgit v1.3-6-gb490 From 8391ecf465ec5c8ccef547267df6d40beb8999a4 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 10 Jul 2015 17:08:16 +0800 Subject: dmaengine: imx-sdma: Add device to device support This patch adds DEV_TO_DEV support for i.MX SDMA driver to support data transfer between two peripheral FIFOs. The per_2_per script requires two peripheral addresses and two DMA requests, and it need to check the src addr and dst addr is in the SPBA bus space or in the AIPS bus space. Signed-off-by: Shengjiu Wang Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 152 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 140 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 77b6aab04f47..34dece3af192 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -123,6 +124,56 @@ */ #define CHANGE_ENDIANNESS 0x80 +/* + * p_2_p watermark_level description + * Bits Name Description + * 0-7 Lower WML Lower watermark level + * 8 PS 1: Pad Swallowing + * 0: No Pad Swallowing + * 9 PA 1: Pad Adding + * 0: No Pad Adding + * 10 SPDIF If this bit is set both source + * and destination are on SPBA + * 11 Source Bit(SP) 1: Source on SPBA + * 0: Source on AIPS + * 12 Destination Bit(DP) 1: Destination on SPBA + * 0: Destination on AIPS + * 13-15 --------- MUST BE 0 + * 16-23 Higher WML HWML + * 24-27 N Total number of samples after + * which Pad adding/Swallowing + * must be done. It must be odd. + * 28 Lower WML Event(LWE) SDMA events reg to check for + * LWML event mask + * 0: LWE in EVENTS register + * 1: LWE in EVENTS2 register + * 29 Higher WML Event(HWE) SDMA events reg to check for + * HWML event mask + * 0: HWE in EVENTS register + * 1: HWE in EVENTS2 register + * 30 --------- MUST BE 0 + * 31 CONT 1: Amount of samples to be + * transferred is unknown and + * script will keep on + * transferring samples as long as + * both events are detected and + * script must be manually stopped + * by the application + * 0: The amount of samples to be + * transferred is equal to the + * count field of mode word + */ +#define SDMA_WATERMARK_LEVEL_LWML 0xFF +#define SDMA_WATERMARK_LEVEL_PS BIT(8) +#define SDMA_WATERMARK_LEVEL_PA BIT(9) +#define SDMA_WATERMARK_LEVEL_SPDIF BIT(10) +#define SDMA_WATERMARK_LEVEL_SP BIT(11) +#define SDMA_WATERMARK_LEVEL_DP BIT(12) +#define SDMA_WATERMARK_LEVEL_HWML (0xFF << 16) +#define SDMA_WATERMARK_LEVEL_LWE BIT(28) +#define SDMA_WATERMARK_LEVEL_HWE BIT(29) +#define SDMA_WATERMARK_LEVEL_CONT BIT(31) + /* * Mode/Count of data node descriptors - IPCv2 */ @@ -259,8 +310,9 @@ struct sdma_channel { struct sdma_buffer_descriptor *bd; dma_addr_t bd_phys; unsigned int pc_from_device, pc_to_device; + unsigned int device_to_device; unsigned long flags; - dma_addr_t per_address; + dma_addr_t per_address, per_address2; unsigned long event_mask[2]; unsigned long watermark_level; u32 shp_addr, per_addr; @@ -328,6 +380,8 @@ struct sdma_engine { u32 script_number; struct sdma_script_start_addrs *script_addrs; const struct sdma_driver_data *drvdata; + u32 spba_start_addr; + u32 spba_end_addr; }; static struct sdma_driver_data sdma_imx31 = { @@ -705,6 +759,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac, sdmac->pc_from_device = 0; sdmac->pc_to_device = 0; + sdmac->device_to_device = 0; switch (peripheral_type) { case IMX_DMATYPE_MEMORY: @@ -780,6 +835,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac, sdmac->pc_from_device = per_2_emi; sdmac->pc_to_device = emi_2_per; + sdmac->device_to_device = per_2_per; } static int sdma_load_context(struct sdma_channel *sdmac) @@ -792,11 +848,12 @@ static int sdma_load_context(struct sdma_channel *sdmac) int ret; unsigned long flags; - if (sdmac->direction == DMA_DEV_TO_MEM) { + if (sdmac->direction == DMA_DEV_TO_MEM) load_address = sdmac->pc_from_device; - } else { + else if (sdmac->direction == DMA_DEV_TO_DEV) + load_address = sdmac->device_to_device; + else load_address = sdmac->pc_to_device; - } if (load_address < 0) return load_address; @@ -851,6 +908,46 @@ static int sdma_disable_channel(struct dma_chan *chan) return 0; } +static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac) +{ + struct sdma_engine *sdma = sdmac->sdma; + + int lwml = sdmac->watermark_level & SDMA_WATERMARK_LEVEL_LWML; + int hwml = (sdmac->watermark_level & SDMA_WATERMARK_LEVEL_HWML) >> 16; + + set_bit(sdmac->event_id0 % 32, &sdmac->event_mask[1]); + set_bit(sdmac->event_id1 % 32, &sdmac->event_mask[0]); + + if (sdmac->event_id0 > 31) + sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_LWE; + + if (sdmac->event_id1 > 31) + sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_HWE; + + /* + * If LWML(src_maxburst) > HWML(dst_maxburst), we need + * swap LWML and HWML of INFO(A.3.2.5.1), also need swap + * r0(event_mask[1]) and r1(event_mask[0]). + */ + if (lwml > hwml) { + sdmac->watermark_level &= ~(SDMA_WATERMARK_LEVEL_LWML | + SDMA_WATERMARK_LEVEL_HWML); + sdmac->watermark_level |= hwml; + sdmac->watermark_level |= lwml << 16; + swap(sdmac->event_mask[0], sdmac->event_mask[1]); + } + + if (sdmac->per_address2 >= sdma->spba_start_addr && + sdmac->per_address2 <= sdma->spba_end_addr) + sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SP; + + if (sdmac->per_address >= sdma->spba_start_addr && + sdmac->per_address <= sdma->spba_end_addr) + sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_DP; + + sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_CONT; +} + static int sdma_config_channel(struct dma_chan *chan) { struct sdma_channel *sdmac = to_sdma_chan(chan); @@ -869,6 +966,12 @@ static int sdma_config_channel(struct dma_chan *chan) sdma_event_enable(sdmac, sdmac->event_id0); } + if (sdmac->event_id1) { + if (sdmac->event_id1 >= sdmac->sdma->drvdata->num_events) + return -EINVAL; + sdma_event_enable(sdmac, sdmac->event_id1); + } + switch (sdmac->peripheral_type) { case IMX_DMATYPE_DSP: sdma_config_ownership(sdmac, false, true, true); @@ -887,19 +990,17 @@ static int sdma_config_channel(struct dma_chan *chan) (sdmac->peripheral_type != IMX_DMATYPE_DSP)) { /* Handle multiple event channels differently */ if (sdmac->event_id1) { - sdmac->event_mask[1] = BIT(sdmac->event_id1 % 32); - if (sdmac->event_id1 > 31) - __set_bit(31, &sdmac->watermark_level); - sdmac->event_mask[0] = BIT(sdmac->event_id0 % 32); - if (sdmac->event_id0 > 31) - __set_bit(30, &sdmac->watermark_level); - } else { + if (sdmac->peripheral_type == IMX_DMATYPE_ASRC_SP || + sdmac->peripheral_type == IMX_DMATYPE_ASRC) + sdma_set_watermarklevel_for_p2p(sdmac); + } else __set_bit(sdmac->event_id0, sdmac->event_mask); - } + /* Watermark Level */ sdmac->watermark_level |= sdmac->watermark_level; /* Address */ sdmac->shp_addr = sdmac->per_address; + sdmac->per_addr = sdmac->per_address2; } else { sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */ } @@ -987,6 +1088,7 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan) sdmac->peripheral_type = data->peripheral_type; sdmac->event_id0 = data->dma_request; + sdmac->event_id1 = data->dma_request2; clk_enable(sdmac->sdma->clk_ipg); clk_enable(sdmac->sdma->clk_ahb); @@ -1221,6 +1323,14 @@ static int sdma_config(struct dma_chan *chan, sdmac->watermark_level = dmaengine_cfg->src_maxburst * dmaengine_cfg->src_addr_width; sdmac->word_size = dmaengine_cfg->src_addr_width; + } else if (dmaengine_cfg->direction == DMA_DEV_TO_DEV) { + sdmac->per_address2 = dmaengine_cfg->src_addr; + sdmac->per_address = dmaengine_cfg->dst_addr; + sdmac->watermark_level = dmaengine_cfg->src_maxburst & + SDMA_WATERMARK_LEVEL_LWML; + sdmac->watermark_level |= (dmaengine_cfg->dst_maxburst << 16) & + SDMA_WATERMARK_LEVEL_HWML; + sdmac->word_size = dmaengine_cfg->dst_addr_width; } else { sdmac->per_address = dmaengine_cfg->dst_addr; sdmac->watermark_level = dmaengine_cfg->dst_maxburst * @@ -1444,6 +1554,14 @@ static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec, data.dma_request = dma_spec->args[0]; data.peripheral_type = dma_spec->args[1]; data.priority = dma_spec->args[2]; + /* + * init dma_request2 to zero, which is not used by the dts. + * For P2P, dma_request2 is init from dma_request_channel(), + * chan->private will point to the imx_dma_data, and in + * device_alloc_chan_resources(), imx_dma_data.dma_request2 will + * be set to sdmac->event_id1. + */ + data.dma_request2 = 0; return dma_request_channel(mask, sdma_filter_fn, &data); } @@ -1453,10 +1571,12 @@ static int sdma_probe(struct platform_device *pdev) const struct of_device_id *of_id = of_match_device(sdma_dt_ids, &pdev->dev); struct device_node *np = pdev->dev.of_node; + struct device_node *spba_bus; const char *fw_name; int ret; int irq; struct resource *iores; + struct resource spba_res; struct sdma_platform_data *pdata = dev_get_platdata(&pdev->dev); int i; struct sdma_engine *sdma; @@ -1608,6 +1728,14 @@ static int sdma_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to register controller\n"); goto err_register; } + + spba_bus = of_find_compatible_node(NULL, NULL, "fsl,spba-bus"); + ret = of_address_to_resource(spba_bus, 0, &spba_res); + if (!ret) { + sdma->spba_start_addr = spba_res.start; + sdma->spba_end_addr = spba_res.end; + } + of_node_put(spba_bus); } dev_info(sdma->dev, "initialized\n"); -- cgit v1.3-6-gb490 From e4ae537e0482e99eeaa5373d39932fe65a477c21 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: distinguish between USB current and 'AC' current The twl4030 charger has two current sources, 'USB' and 'AC' (presumably "Accessory Charger" because it isn't Alternating Current). If 'AC' is providing current, we should set the current limit differently to when it isn't (and so USB is used). So split 'cur' into 'usb_cur' and 'ac_cur' and use accordingly. Now we must review the current setting on any interrupt or USB event which might indicate that the charger-source has changed. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- drivers/power/twl4030_charger.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 3b7cc631bb8a..982675df21b7 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -22,6 +22,7 @@ #include #include #include +#include #define TWL4030_BCIMSTATEC 0x02 #define TWL4030_BCIICHG 0x08 @@ -101,10 +102,13 @@ struct twl4030_bci { int usb_enabled; /* - * ichg values in uA. If any are 'large', we set CGAIN to - * '1' which doubles the range for half the precision. + * ichg_* and *_cur values in uA. If any are 'large', we set + * CGAIN to '1' which doubles the range for half the + * precision. */ - unsigned int ichg_eoc, ichg_lo, ichg_hi, cur; + unsigned int ichg_eoc, ichg_lo, ichg_hi; + unsigned int usb_cur, ac_cur; + bool ac_is_active; unsigned long event; }; @@ -225,11 +229,24 @@ static int ua2regval(int ua, bool cgain) static int twl4030_charger_update_current(struct twl4030_bci *bci) { int status; + int cur; unsigned reg, cur_reg; u8 bcictl1, oldreg, fullreg; bool cgain = false; u8 boot_bci; + /* + * If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11) + * and AC is enabled, set current for 'ac' + */ + if (twl4030_get_madc_conversion(11) > 4500) { + cur = bci->ac_cur; + bci->ac_is_active = true; + } else { + cur = bci->usb_cur; + bci->ac_is_active = false; + } + /* First, check thresholds and see if cgain is needed */ if (bci->ichg_eoc >= 200000) cgain = true; @@ -237,7 +254,7 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) cgain = true; if (bci->ichg_hi >= 820000) cgain = true; - if (bci->cur > 852000) + if (cur > 852000) cgain = true; status = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1); @@ -318,7 +335,7 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) * And finally, set the current. This is stored in * two registers. */ - reg = ua2regval(bci->cur, cgain); + reg = ua2regval(cur, cgain); /* we have only 10 bits */ if (reg > 0x3ff) reg = 0x3ff; @@ -371,6 +388,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { + twl4030_charger_update_current(bci); + /* Need to keep phy powered */ if (!bci->usb_enabled) { pm_runtime_get_sync(bci->transceiver->dev); @@ -463,6 +482,7 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) struct twl4030_bci *bci = arg; dev_dbg(bci->dev, "CHG_PRES irq\n"); + twl4030_charger_update_current(bci); power_supply_changed(bci->ac); power_supply_changed(bci->usb); @@ -495,6 +515,7 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg) power_supply_changed(bci->ac); power_supply_changed(bci->usb); } + twl4030_charger_update_current(bci); /* various monitoring events, for now we just log them here */ if (irqs1 & (TWL4030_TBATOR2 | TWL4030_TBATOR1)) @@ -724,10 +745,11 @@ static int twl4030_bci_probe(struct platform_device *pdev) bci->ichg_eoc = 80100; /* Stop charging when current drops to here */ bci->ichg_lo = 241000; /* Low threshold */ bci->ichg_hi = 500000; /* High threshold */ + bci->ac_cur = 500000; /* 500mA */ if (allow_usb) - bci->cur = 500000; /* 500mA */ + bci->usb_cur = 500000; /* 500mA */ else - bci->cur = 100000; /* 100mA */ + bci->usb_cur = 100000; /* 100mA */ bci->dev = &pdev->dev; bci->irq_chg = platform_get_irq(pdev, 0); -- cgit v1.3-6-gb490 From aca3c3546396b305fff79f09883cff48a908aac0 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: allow max_current to be managed via sysfs. 'max_current' sysfs attributes are created which allow the max to be set. Whenever a current source changes, the default is restored. This will be followed by a uevent, so user-space can decide to update again. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- .../ABI/testing/sysfs-class-power-twl4030 | 15 +++++ drivers/power/twl4030_charger.c | 72 ++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-power-twl4030 (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 new file mode 100644 index 000000000000..0331bba4605d --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -0,0 +1,15 @@ +What: /sys/class/power_supply/twl4030_ac/max_current + /sys/class/power_supply/twl4030_usb/max_current +Description: + Read/Write limit on current which may + be drawn from the ac (Accessory Charger) or + USB port. + + Value is in micro-Amps. + + Value is set automatically to an appropriate + value when a cable is plugged or unplugged. + + Value can the set by writing to the attribute. + The change will only persist until the next + plug event. These event are reported via udev. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 982675df21b7..b0a50adebfda 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -482,6 +482,8 @@ static irqreturn_t twl4030_charger_interrupt(int irq, void *arg) struct twl4030_bci *bci = arg; dev_dbg(bci->dev, "CHG_PRES irq\n"); + /* reset current on each 'plug' event */ + bci->ac_cur = 500000; twl4030_charger_update_current(bci); power_supply_changed(bci->ac); power_supply_changed(bci->usb); @@ -536,6 +538,63 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg) return IRQ_HANDLED; } +/* + * Provide "max_current" attribute in sysfs. + */ +static ssize_t +twl4030_bci_max_current_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + int cur = 0; + int status = 0; + status = kstrtoint(buf, 10, &cur); + if (status) + return status; + if (cur < 0) + return -EINVAL; + if (dev == &bci->ac->dev) + bci->ac_cur = cur; + else + bci->usb_cur = cur; + + twl4030_charger_update_current(bci); + return n; +} + +/* + * sysfs max_current show + */ +static ssize_t twl4030_bci_max_current_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int status = 0; + int cur = -1; + u8 bcictl1; + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + + if (dev == &bci->ac->dev) { + if (!bci->ac_is_active) + cur = bci->ac_cur; + } else { + if (bci->ac_is_active) + cur = bci->usb_cur; + } + if (cur < 0) { + cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1); + if (cur < 0) + return cur; + status = twl4030_bci_read(TWL4030_BCICTL1, &bcictl1); + if (status < 0) + return status; + cur = regval2ua(cur, bcictl1 & TWL4030_CGAIN); + } + return scnprintf(buf, PAGE_SIZE, "%u\n", cur); +} + +static DEVICE_ATTR(max_current, 0644, twl4030_bci_max_current_show, + twl4030_bci_max_current_store); + static void twl4030_bci_usb_work(struct work_struct *data) { struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work); @@ -558,6 +617,12 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, dev_dbg(bci->dev, "OTG notify %lu\n", val); + /* reset current on each 'plug' event */ + if (allow_usb) + bci->usb_cur = 500000; + else + bci->usb_cur = 100000; + bci->event = val; schedule_work(&bci->work); @@ -831,6 +896,11 @@ static int twl4030_bci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to unmask interrupts: %d\n", ret); twl4030_charger_update_current(bci); + if (device_create_file(&bci->usb->dev, &dev_attr_max_current)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); + if (device_create_file(&bci->ac->dev, &dev_attr_max_current)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); + twl4030_charger_enable_ac(true); if (!IS_ERR_OR_NULL(bci->transceiver)) twl4030_bci_usb_ncb(&bci->usb_nb, @@ -855,6 +925,8 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) twl4030_charger_enable_usb(bci, false); twl4030_charger_enable_backup(0, 0); + device_remove_file(&bci->usb->dev, &dev_attr_max_current); + device_remove_file(&bci->ac->dev, &dev_attr_max_current); /* mask interrupts */ twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, TWL4030_INTERRUPTS_BCIIMR1A); -- cgit v1.3-6-gb490 From 22d4c33f7335ddf6deda26630c78650e133bfe72 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: enable manual enable/disable of usb charging. 'off' or 'auto' to /sys/class/power/twl4030_usb/mode will now enable or disable charging from USB port. Normally this is enabled on 'plug' and disabled on 'unplug'. Unplug will still disable charging. 'plug' will only enable it if 'auto' if selected. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- .../ABI/testing/sysfs-class-power-twl4030 | 11 ++++ drivers/power/twl4030_charger.c | 59 ++++++++++++++++++++++ 2 files changed, 70 insertions(+) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 index 0331bba4605d..40e0f919cbde 100644 --- a/Documentation/ABI/testing/sysfs-class-power-twl4030 +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -13,3 +13,14 @@ Description: Value can the set by writing to the attribute. The change will only persist until the next plug event. These event are reported via udev. + + +What: /sys/class/power_supply/twl4030_usb/mode +Description: + Changing mode for USB port. + Writing to this can disable charging. + + Possible values are: + "auto" - draw power as appropriate for detected + power source and battery status. + "off" - do not draw any power. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index b0a50adebfda..6fa928ed3128 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -109,10 +109,16 @@ struct twl4030_bci { unsigned int ichg_eoc, ichg_lo, ichg_hi; unsigned int usb_cur, ac_cur; bool ac_is_active; + int usb_mode; /* charging mode requested */ +#define CHARGE_OFF 0 +#define CHARGE_AUTO 1 unsigned long event; }; +/* strings for 'usb_mode' values */ +static char *modes[] = { "off", "auto" }; + /* * clear and set bits on an given register on a given module */ @@ -386,6 +392,8 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) { int ret; + if (bci->usb_mode == CHARGE_OFF) + enable = false; if (enable && !IS_ERR_OR_NULL(bci->transceiver)) { twl4030_charger_update_current(bci); @@ -629,6 +637,53 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, return NOTIFY_OK; } +/* + * sysfs charger enabled store + */ +static ssize_t +twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + int mode; + int status; + + if (sysfs_streq(buf, modes[0])) + mode = 0; + else if (sysfs_streq(buf, modes[1])) + mode = 1; + else + return -EINVAL; + twl4030_charger_enable_usb(bci, false); + bci->usb_mode = mode; + status = twl4030_charger_enable_usb(bci, true); + return (status == 0) ? n : status; +} + +/* + * sysfs charger enabled show + */ +static ssize_t +twl4030_bci_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct twl4030_bci *bci = dev_get_drvdata(dev->parent); + int len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(modes); i++) + if (bci->usb_mode == i) + len += snprintf(buf+len, PAGE_SIZE-len, + "[%s] ", modes[i]); + else + len += snprintf(buf+len, PAGE_SIZE-len, + "%s ", modes[i]); + buf[len-1] = '\n'; + return len; +} +static DEVICE_ATTR(mode, 0644, twl4030_bci_mode_show, + twl4030_bci_mode_store); + static int twl4030_charger_get_current(void) { int curr; @@ -815,6 +870,7 @@ static int twl4030_bci_probe(struct platform_device *pdev) bci->usb_cur = 500000; /* 500mA */ else bci->usb_cur = 100000; /* 100mA */ + bci->usb_mode = CHARGE_AUTO; bci->dev = &pdev->dev; bci->irq_chg = platform_get_irq(pdev, 0); @@ -898,6 +954,8 @@ static int twl4030_bci_probe(struct platform_device *pdev) twl4030_charger_update_current(bci); if (device_create_file(&bci->usb->dev, &dev_attr_max_current)) dev_warn(&pdev->dev, "could not create sysfs file\n"); + if (device_create_file(&bci->usb->dev, &dev_attr_mode)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); if (device_create_file(&bci->ac->dev, &dev_attr_max_current)) dev_warn(&pdev->dev, "could not create sysfs file\n"); @@ -926,6 +984,7 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) twl4030_charger_enable_backup(0, 0); device_remove_file(&bci->usb->dev, &dev_attr_max_current); + device_remove_file(&bci->usb->dev, &dev_attr_mode); device_remove_file(&bci->ac->dev, &dev_attr_max_current); /* mask interrupts */ twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, -- cgit v1.3-6-gb490 From 7f4a633d21331155ee06c5ee44749ed35a3a3cc5 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: add software controlled linear charging mode. Add a 'continuous' option for usb charging which enables the "linear" charging mode of the twl4030. Linear charging does a good job with not-so-reliable power sources. Auto mode does not work well as it switches off when voltage drops momentarily. Care must be taken not to over-charge. It was used with a bike hub dynamo since a year or so. In that case there are automatically charging stops when the cyclist needs a break. Original-by: Andreas Kemnade Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- .../ABI/testing/sysfs-class-power-twl4030 | 9 ++++ drivers/power/twl4030_charger.c | 55 ++++++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 index 40e0f919cbde..e8baa36aaa2b 100644 --- a/Documentation/ABI/testing/sysfs-class-power-twl4030 +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -24,3 +24,12 @@ Description: "auto" - draw power as appropriate for detected power source and battery status. "off" - do not draw any power. + "continuous" + - activate mode described as "linear" in + TWL data sheets. This uses whatever + current is available and doesn't switch off + when voltage drops. + + This is useful for unstable power sources + such as bicycle dynamo, but care should + be taken that battery is not over-charged. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 6fa928ed3128..de5430deaf23 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -24,6 +24,8 @@ #include #include +#define TWL4030_BCIMDEN 0x00 +#define TWL4030_BCIMDKEY 0x01 #define TWL4030_BCIMSTATEC 0x02 #define TWL4030_BCIICHG 0x08 #define TWL4030_BCIVAC 0x0a @@ -35,13 +37,16 @@ #define TWL4030_BCIIREF1 0x27 #define TWL4030_BCIIREF2 0x28 #define TWL4030_BCIMFKEY 0x11 +#define TWL4030_BCIMFEN3 0x14 #define TWL4030_BCIMFTH8 0x1d #define TWL4030_BCIMFTH9 0x1e +#define TWL4030_BCIWDKEY 0x21 #define TWL4030_BCIMFSTS1 0x01 #define TWL4030_BCIAUTOWEN BIT(5) #define TWL4030_CONFIG_DONE BIT(4) +#define TWL4030_CVENAC BIT(2) #define TWL4030_BCIAUTOUSB BIT(1) #define TWL4030_BCIAUTOAC BIT(0) #define TWL4030_CGAIN BIT(5) @@ -112,12 +117,13 @@ struct twl4030_bci { int usb_mode; /* charging mode requested */ #define CHARGE_OFF 0 #define CHARGE_AUTO 1 +#define CHARGE_LINEAR 2 unsigned long event; }; /* strings for 'usb_mode' values */ -static char *modes[] = { "off", "auto" }; +static char *modes[] = { "off", "auto", "continuous" }; /* * clear and set bits on an given register on a given module @@ -404,16 +410,42 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) bci->usb_enabled = 1; } - /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ - ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); - if (ret < 0) - return ret; + if (bci->usb_mode == CHARGE_AUTO) + /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */ + ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOUSB); /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */ ret = twl4030_clear_set(TWL_MODULE_MAIN_CHARGE, 0, TWL4030_USBFASTMCHG, TWL4030_BCIMFSTS4); + if (bci->usb_mode == CHARGE_LINEAR) { + twl4030_clear_set_boot_bci(TWL4030_BCIAUTOAC|TWL4030_CVENAC, 0); + /* Watch dog key: WOVF acknowledge */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x33, + TWL4030_BCIWDKEY); + /* 0x24 + EKEY6: off mode */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a, + TWL4030_BCIMDKEY); + /* EKEY2: Linear charge: USB path */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x26, + TWL4030_BCIMDKEY); + /* WDKEY5: stop watchdog count */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf3, + TWL4030_BCIWDKEY); + /* enable MFEN3 access */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x9c, + TWL4030_BCIMFKEY); + /* ICHGEOCEN - end-of-charge monitor (current < 80mA) + * (charging continues) + * ICHGLOWEN - current level monitor (charge continues) + * don't monitor over-current or heat save + */ + ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0xf0, + TWL4030_BCIMFEN3); + } } else { ret = twl4030_clear_set_boot_bci(TWL4030_BCIAUTOUSB, 0); + ret |= twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, 0x2a, + TWL4030_BCIMDKEY); if (bci->usb_enabled) { pm_runtime_mark_last_busy(bci->transceiver->dev); pm_runtime_put_autosuspend(bci->transceiver->dev); @@ -652,6 +684,8 @@ twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr, mode = 0; else if (sysfs_streq(buf, modes[1])) mode = 1; + else if (sysfs_streq(buf, modes[2])) + mode = 2; else return -EINVAL; twl4030_charger_enable_usb(bci, false); @@ -750,6 +784,17 @@ static int twl4030_bci_get_property(struct power_supply *psy, is_charging = state & TWL4030_MSTATEC_USB; else is_charging = state & TWL4030_MSTATEC_AC; + if (!is_charging) { + u8 s; + twl4030_bci_read(TWL4030_BCIMDEN, &s); + if (psy->desc->type == POWER_SUPPLY_TYPE_USB) + is_charging = s & 1; + else + is_charging = s & 2; + if (is_charging) + /* A little white lie */ + state = TWL4030_MSTATEC_QUICK1; + } switch (psp) { case POWER_SUPPLY_PROP_STATUS: -- cgit v1.3-6-gb490 From b04b908d8a2901c2cc59db87defd9c08bd4293cc Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: add ac/mode to match usb/mode This allows AC charging to be turned off, much like usb charging. "continuous" mode is not available though. Acked-by: Pavel Machek Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- .../ABI/testing/sysfs-class-power-twl4030 | 10 +++++++ drivers/power/twl4030_charger.c | 35 +++++++++++++++++----- 2 files changed, 37 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-class-power-twl4030 b/Documentation/ABI/testing/sysfs-class-power-twl4030 index e8baa36aaa2b..be26af0f1895 100644 --- a/Documentation/ABI/testing/sysfs-class-power-twl4030 +++ b/Documentation/ABI/testing/sysfs-class-power-twl4030 @@ -33,3 +33,13 @@ Description: This is useful for unstable power sources such as bicycle dynamo, but care should be taken that battery is not over-charged. + +What: /sys/class/power_supply/twl4030_ac/mode +Description: + Changing mode for 'ac' port. + Writing to this can disable charging. + + Possible values are: + "auto" - draw power as appropriate for detected + power source and battery status. + "off" - do not draw any power. diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index de5430deaf23..68117ad23564 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -114,7 +114,7 @@ struct twl4030_bci { unsigned int ichg_eoc, ichg_lo, ichg_hi; unsigned int usb_cur, ac_cur; bool ac_is_active; - int usb_mode; /* charging mode requested */ + int usb_mode, ac_mode; /* charging mode requested */ #define CHARGE_OFF 0 #define CHARGE_AUTO 1 #define CHARGE_LINEAR 2 @@ -459,10 +459,13 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) /* * Enable/Disable AC Charge funtionality. */ -static int twl4030_charger_enable_ac(bool enable) +static int twl4030_charger_enable_ac(struct twl4030_bci *bci, bool enable) { int ret; + if (bci->ac_mode == CHARGE_OFF) + enable = false; + if (enable) ret = twl4030_clear_set_boot_bci(0, TWL4030_BCIAUTOAC); else @@ -688,9 +691,17 @@ twl4030_bci_mode_store(struct device *dev, struct device_attribute *attr, mode = 2; else return -EINVAL; - twl4030_charger_enable_usb(bci, false); - bci->usb_mode = mode; - status = twl4030_charger_enable_usb(bci, true); + if (dev == &bci->ac->dev) { + if (mode == 2) + return -EINVAL; + twl4030_charger_enable_ac(bci, false); + bci->ac_mode = mode; + status = twl4030_charger_enable_ac(bci, true); + } else { + twl4030_charger_enable_usb(bci, false); + bci->usb_mode = mode; + status = twl4030_charger_enable_usb(bci, true); + } return (status == 0) ? n : status; } @@ -704,9 +715,13 @@ twl4030_bci_mode_show(struct device *dev, struct twl4030_bci *bci = dev_get_drvdata(dev->parent); int len = 0; int i; + int mode = bci->usb_mode; + + if (dev == &bci->ac->dev) + mode = bci->ac_mode; for (i = 0; i < ARRAY_SIZE(modes); i++) - if (bci->usb_mode == i) + if (mode == i) len += snprintf(buf+len, PAGE_SIZE-len, "[%s] ", modes[i]); else @@ -916,6 +931,7 @@ static int twl4030_bci_probe(struct platform_device *pdev) else bci->usb_cur = 100000; /* 100mA */ bci->usb_mode = CHARGE_AUTO; + bci->ac_mode = CHARGE_AUTO; bci->dev = &pdev->dev; bci->irq_chg = platform_get_irq(pdev, 0); @@ -1001,10 +1017,12 @@ static int twl4030_bci_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "could not create sysfs file\n"); if (device_create_file(&bci->usb->dev, &dev_attr_mode)) dev_warn(&pdev->dev, "could not create sysfs file\n"); + if (device_create_file(&bci->ac->dev, &dev_attr_mode)) + dev_warn(&pdev->dev, "could not create sysfs file\n"); if (device_create_file(&bci->ac->dev, &dev_attr_max_current)) dev_warn(&pdev->dev, "could not create sysfs file\n"); - twl4030_charger_enable_ac(true); + twl4030_charger_enable_ac(bci, true); if (!IS_ERR_OR_NULL(bci->transceiver)) twl4030_bci_usb_ncb(&bci->usb_nb, bci->transceiver->last_event, @@ -1024,13 +1042,14 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev) { struct twl4030_bci *bci = platform_get_drvdata(pdev); - twl4030_charger_enable_ac(false); + twl4030_charger_enable_ac(bci, false); twl4030_charger_enable_usb(bci, false); twl4030_charger_enable_backup(0, 0); device_remove_file(&bci->usb->dev, &dev_attr_max_current); device_remove_file(&bci->usb->dev, &dev_attr_mode); device_remove_file(&bci->ac->dev, &dev_attr_max_current); + device_remove_file(&bci->ac->dev, &dev_attr_mode); /* mask interrupts */ twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff, TWL4030_INTERRUPTS_BCIIMR1A); -- cgit v1.3-6-gb490 From 21ae40404f3ca66fb37dd26e7b67eb109f2453ab Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 30 Jul 2015 10:11:24 +1000 Subject: twl4030_charger: Increase current carefully while watching voltage. The USB Battery Charging spec (BC1.2) suggests a dedicated charging port can deliver from 0.5 to 5.0A at between 4.75 and 5.25 volts. To choose the "correct" current voltage setting requires a trial and error approach: try to draw current and see if the voltage drops too low. Even with a configured Standard Downstream Port, it may not be possible to reliably pull 500mA - depending on cable quality and source quality I have reports of charging failure due to the voltage dropping too low. To address both these concerns, this patch introduce incremental current setting. The current pull from VBUS is increased in steps of 20mA every 100ms until the target is reached or until the measure voltage drops below 4.75V. If the voltage does go too low, the target current is reduced by 20mA and kept there. This applies to currents selected automatically, or to values set via sysfs. So setting a large value will cause the maximum available to be used - up to the limit of 1.7A imposed by the hardware. Signed-off-by: NeilBrown Signed-off-by: Sebastian Reichel --- drivers/power/twl4030_charger.c | 67 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 68117ad23564..2c537ee11bbe 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -119,6 +119,18 @@ struct twl4030_bci { #define CHARGE_AUTO 1 #define CHARGE_LINEAR 2 + /* When setting the USB current we slowly increase the + * requested current until target is reached or the voltage + * drops below 4.75V. In the latter case we step back one + * step. + */ + unsigned int usb_cur_target; + struct delayed_work current_worker; +#define USB_CUR_STEP 20000 /* 20mA at a time */ +#define USB_MIN_VOLT 4750000 /* 4.75V */ +#define USB_CUR_DELAY msecs_to_jiffies(100) +#define USB_MAX_CURRENT 1700000 /* TWL4030 caps at 1.7A */ + unsigned long event; }; @@ -257,6 +269,12 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) } else { cur = bci->usb_cur; bci->ac_is_active = false; + if (cur > bci->usb_cur_target) { + cur = bci->usb_cur_target; + bci->usb_cur = cur; + } + if (cur < bci->usb_cur_target) + schedule_delayed_work(&bci->current_worker, USB_CUR_DELAY); } /* First, check thresholds and see if cgain is needed */ @@ -391,6 +409,41 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) return 0; } +static int twl4030_charger_get_current(void); + +static void twl4030_current_worker(struct work_struct *data) +{ + int v, curr; + int res; + struct twl4030_bci *bci = container_of(data, struct twl4030_bci, + current_worker.work); + + res = twl4030bci_read_adc_val(TWL4030_BCIVBUS); + if (res < 0) + v = 0; + else + /* BCIVBUS uses ADCIN8, 7/1023 V/step */ + v = res * 6843; + curr = twl4030_charger_get_current(); + + dev_dbg(bci->dev, "v=%d cur=%d limit=%d target=%d\n", v, curr, + bci->usb_cur, bci->usb_cur_target); + + if (v < USB_MIN_VOLT) { + /* Back up and stop adjusting. */ + bci->usb_cur -= USB_CUR_STEP; + bci->usb_cur_target = bci->usb_cur; + } else if (bci->usb_cur >= bci->usb_cur_target || + bci->usb_cur + USB_CUR_STEP > USB_MAX_CURRENT) { + /* Reached target and voltage is OK - stop */ + return; + } else { + bci->usb_cur += USB_CUR_STEP; + schedule_delayed_work(&bci->current_worker, USB_CUR_DELAY); + } + twl4030_charger_update_current(bci); +} + /* * Enable/Disable USB Charge functionality. */ @@ -451,6 +504,7 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable) pm_runtime_put_autosuspend(bci->transceiver->dev); bci->usb_enabled = 0; } + bci->usb_cur = 0; } return ret; @@ -599,7 +653,7 @@ twl4030_bci_max_current_store(struct device *dev, struct device_attribute *attr, if (dev == &bci->ac->dev) bci->ac_cur = cur; else - bci->usb_cur = cur; + bci->usb_cur_target = cur; twl4030_charger_update_current(bci); return n; @@ -621,7 +675,7 @@ static ssize_t twl4030_bci_max_current_show(struct device *dev, cur = bci->ac_cur; } else { if (bci->ac_is_active) - cur = bci->usb_cur; + cur = bci->usb_cur_target; } if (cur < 0) { cur = twl4030bci_read_adc_val(TWL4030_BCIIREF1); @@ -662,9 +716,9 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, /* reset current on each 'plug' event */ if (allow_usb) - bci->usb_cur = 500000; + bci->usb_cur_target = 500000; else - bci->usb_cur = 100000; + bci->usb_cur_target = 100000; bci->event = val; schedule_work(&bci->work); @@ -927,9 +981,9 @@ static int twl4030_bci_probe(struct platform_device *pdev) bci->ichg_hi = 500000; /* High threshold */ bci->ac_cur = 500000; /* 500mA */ if (allow_usb) - bci->usb_cur = 500000; /* 500mA */ + bci->usb_cur_target = 500000; /* 500mA */ else - bci->usb_cur = 100000; /* 100mA */ + bci->usb_cur_target = 100000; /* 100mA */ bci->usb_mode = CHARGE_AUTO; bci->ac_mode = CHARGE_AUTO; @@ -980,6 +1034,7 @@ static int twl4030_bci_probe(struct platform_device *pdev) } INIT_WORK(&bci->work, twl4030_bci_usb_work); + INIT_DELAYED_WORK(&bci->current_worker, twl4030_current_worker); bci->usb_nb.notifier_call = twl4030_bci_usb_ncb; if (bci->dev->of_node) { -- cgit v1.3-6-gb490 From 2f2560e348a875104a0d5394c938da2a41e47228 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Tue, 21 Jul 2015 11:01:06 +0800 Subject: dmaengine: zxdma: Support cyclic dma Support cyclic dma for audio playback Signed-off-by: Jun Nie Signed-off-by: Vinod Koul --- drivers/dma/zx296702_dma.c | 93 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx296702_dma.c index ec470bc74df8..0d55c8fc4951 100644 --- a/drivers/dma/zx296702_dma.c +++ b/drivers/dma/zx296702_dma.c @@ -101,6 +101,7 @@ struct zx_dma_chan { struct dma_slave_config slave_cfg; int id; /* Request phy chan id */ u32 ccfg; + u32 cyclic; struct virt_dma_chan vc; struct zx_dma_phy *phy; struct list_head node; @@ -278,7 +279,7 @@ static irqreturn_t zx_dma_int_handler(int irq, void *dev_id) u32 serr = readl_relaxed(d->base + REG_ZX_SRC_ERR_IRQ); u32 derr = readl_relaxed(d->base + REG_ZX_DST_ERR_IRQ); u32 cfg = readl_relaxed(d->base + REG_ZX_CFG_ERR_IRQ); - u32 i, irq_chan = 0; + u32 i, irq_chan = 0, task = 0; while (tc) { i = __ffs(tc); @@ -289,11 +290,16 @@ static irqreturn_t zx_dma_int_handler(int irq, void *dev_id) unsigned long flags; spin_lock_irqsave(&c->vc.lock, flags); - vchan_cookie_complete(&p->ds_run->vd); - p->ds_done = p->ds_run; + if (c->cyclic) { + vchan_cyclic_callback(&p->ds_run->vd); + } else { + vchan_cookie_complete(&p->ds_run->vd); + p->ds_done = p->ds_run; + task = 1; + } spin_unlock_irqrestore(&c->vc.lock, flags); + irq_chan |= BIT(i); } - irq_chan |= BIT(i); } if (serr || derr || cfg) @@ -305,12 +311,9 @@ static irqreturn_t zx_dma_int_handler(int irq, void *dev_id) writel_relaxed(derr, d->base + REG_ZX_DST_ERR_IRQ_RAW); writel_relaxed(cfg, d->base + REG_ZX_CFG_ERR_IRQ_RAW); - if (irq_chan) { + if (task) zx_dma_task(d); - return IRQ_HANDLED; - } else { - return IRQ_NONE; - } + return IRQ_HANDLED; } static void zx_dma_free_chan_resources(struct dma_chan *chan) @@ -534,6 +537,7 @@ static struct dma_async_tx_descriptor *zx_dma_prep_memcpy( len -= copy; } while (len); + c->cyclic = 0; ds->desc_hw[num - 1].lli = 0; /* end of link */ ds->desc_hw[num - 1].ctr |= ZX_IRQ_ENABLE_ALL; return vchan_tx_prep(&c->vc, &ds->vd, flags); @@ -566,6 +570,7 @@ static struct dma_async_tx_descriptor *zx_dma_prep_slave_sg( if (!ds) return NULL; + c->cyclic = 0; num = 0; for_each_sg(sgl, sg, sglen, i) { addr = sg_dma_address(sg); @@ -596,6 +601,49 @@ static struct dma_async_tx_descriptor *zx_dma_prep_slave_sg( return vchan_tx_prep(&c->vc, &ds->vd, flags); } +static struct dma_async_tx_descriptor *zx_dma_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction dir, + unsigned long flags) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_desc_sw *ds; + dma_addr_t src = 0, dst = 0; + int num_periods = buf_len / period_len; + int buf = 0, num = 0; + + if (period_len > DMA_MAX_SIZE) { + dev_err(chan->device->dev, "maximum period size exceeded\n"); + return NULL; + } + + if (zx_pre_config(c, dir)) + return NULL; + + ds = zx_alloc_desc_resource(num_periods, chan); + if (!ds) + return NULL; + c->cyclic = 1; + + while (buf < buf_len) { + if (dir == DMA_MEM_TO_DEV) { + src = dma_addr; + dst = c->dev_addr; + } else if (dir == DMA_DEV_TO_MEM) { + src = c->dev_addr; + dst = dma_addr; + } + zx_dma_fill_desc(ds, dst, src, period_len, num++, + c->ccfg | ZX_IRQ_ENABLE_ALL); + dma_addr += period_len; + buf += period_len; + } + + ds->desc_hw[num - 1].lli = ds->desc_hw_lli; + ds->size = buf_len; + return vchan_tx_prep(&c->vc, &ds->vd, flags); +} + static int zx_dma_config(struct dma_chan *chan, struct dma_slave_config *cfg) { @@ -641,6 +689,30 @@ static int zx_dma_terminate_all(struct dma_chan *chan) return 0; } +static int zx_dma_transfer_pause(struct dma_chan *chan) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + u32 val = 0; + + val = readl_relaxed(c->phy->base + REG_ZX_CTRL); + val &= ~ZX_CH_ENABLE; + writel_relaxed(val, c->phy->base + REG_ZX_CTRL); + + return 0; +} + +static int zx_dma_transfer_resume(struct dma_chan *chan) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + u32 val = 0; + + val = readl_relaxed(c->phy->base + REG_ZX_CTRL); + val |= ZX_CH_ENABLE; + writel_relaxed(val, c->phy->base + REG_ZX_CTRL); + + return 0; +} + static void zx_dma_free_desc(struct virt_dma_desc *vd) { struct zx_dma_desc_sw *ds = @@ -745,9 +817,12 @@ static int zx_dma_probe(struct platform_device *op) d->slave.device_tx_status = zx_dma_tx_status; d->slave.device_prep_dma_memcpy = zx_dma_prep_memcpy; d->slave.device_prep_slave_sg = zx_dma_prep_slave_sg; + d->slave.device_prep_dma_cyclic = zx_dma_prep_dma_cyclic; d->slave.device_issue_pending = zx_dma_issue_pending; d->slave.device_config = zx_dma_config; d->slave.device_terminate_all = zx_dma_terminate_all; + d->slave.device_pause = zx_dma_transfer_pause; + d->slave.device_resume = zx_dma_transfer_resume; d->slave.copy_align = DMA_ALIGN; d->slave.src_addr_widths = ZX_DMA_BUSWIDTHS; d->slave.dst_addr_widths = ZX_DMA_BUSWIDTHS; -- cgit v1.3-6-gb490 From 63369b2b99d718ca2777bf8d71360de75888f05b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:33 +0200 Subject: power: Export I2C module alias information in missing drivers The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Sebastian Reichel --- drivers/power/bq24190_charger.c | 1 + drivers/power/rt5033_battery.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c index 703ebecaf38b..bb6d85bd6e56 100644 --- a/drivers/power/bq24190_charger.c +++ b/drivers/power/bq24190_charger.c @@ -1515,6 +1515,7 @@ static const struct i2c_device_id bq24190_i2c_ids[] = { { "bq24190", BQ24190_REG_VPRS_PN_24190 }, { }, }; +MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids); #ifdef CONFIG_OF static const struct of_device_id bq24190_of_match[] = { diff --git a/drivers/power/rt5033_battery.c b/drivers/power/rt5033_battery.c index a7a6877b4e16..bcdd83048492 100644 --- a/drivers/power/rt5033_battery.c +++ b/drivers/power/rt5033_battery.c @@ -165,7 +165,7 @@ static const struct i2c_device_id rt5033_battery_id[] = { { "rt5033-battery", }, { } }; -MODULE_DEVICE_TABLE(platform, rt5033_battery_id); +MODULE_DEVICE_TABLE(i2c, rt5033_battery_id); static struct i2c_driver rt5033_battery_driver = { .driver = { -- cgit v1.3-6-gb490 From 1e8b82c1ff3bc52c5e4265d66fe5c6da9a66e2e6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 2 Aug 2015 11:09:50 +0200 Subject: power: Allow compile test of GPIO consumers if !GPIOLIB The GPIO subsystem provides dummy GPIO consumer functions if GPIOLIB is not enabled. Hence drivers that depend on GPIOLIB, but use GPIO consumer functionality only, can still be compiled if GPIOLIB is not enabled. Relax the dependency on GPIOLIB if COMPILE_TEST is enabled, where appropriate. Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Signed-off-by: Sebastian Reichel --- drivers/power/Kconfig | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 08beeed5485d..f8758d6febf8 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -333,7 +333,7 @@ config CHARGER_LP8788 config CHARGER_GPIO tristate "GPIO charger" - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Say Y to include support for chargers which report their online status through a GPIO pin. @@ -391,26 +391,30 @@ config CHARGER_BQ2415X config CHARGER_BQ24190 tristate "TI BQ24190 battery charger driver" - depends on I2C && GPIOLIB + depends on I2C + depends on GPIOLIB || COMPILE_TEST help Say Y to enable support for the TI BQ24190 battery charger. config CHARGER_BQ24257 tristate "TI BQ24257 battery charger driver" - depends on I2C && GPIOLIB + depends on I2C + depends on GPIOLIB || COMPILE_TEST depends on REGMAP_I2C help Say Y to enable support for the TI BQ24257 battery charger. config CHARGER_BQ24735 tristate "TI BQ24735 battery charger support" - depends on I2C && GPIOLIB + depends on I2C + depends on GPIOLIB || COMPILE_TEST help Say Y to enable support for the TI BQ24735 battery charger. config CHARGER_BQ25890 tristate "TI BQ25890 battery charger driver" - depends on I2C && GPIOLIB + depends on I2C + depends on GPIOLIB || COMPILE_TEST select REGMAP_I2C help Say Y to enable support for the TI BQ25890 battery charger. @@ -462,7 +466,8 @@ config BATTERY_RT5033 config CHARGER_RT9455 tristate "Richtek RT9455 battery charger driver" - depends on I2C && GPIOLIB + depends on I2C + depends on GPIOLIB || COMPILE_TEST select REGMAP_I2C help Say Y to enable support for Richtek RT9455 battery charger. -- cgit v1.3-6-gb490 From c9f85a90d41476aca2d3b60f98ab87d7ae1b8612 Mon Sep 17 00:00:00 2001 From: Andreas Dannenberg Date: Tue, 4 Aug 2015 11:36:17 -0500 Subject: power: bq24190_charger: Fix charge type sysfs property Access to the BQ24190's configurable charge type property (none, trickle, fast) is being masked by an incorrect power_supply_property entry. After applying this patch a new 'charge_type' property will appear in the bq24190-charger sysfs folder backed up by getters/setters already present in the driver. Signed-off-by: Andreas Dannenberg Acked-by: Dan Murphy Acked-by: Andrew F. Davis Signed-off-by: Sebastian Reichel --- drivers/power/bq24190_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c index bb6d85bd6e56..469a452cbe10 100644 --- a/drivers/power/bq24190_charger.c +++ b/drivers/power/bq24190_charger.c @@ -902,7 +902,7 @@ static int bq24190_charger_property_is_writeable(struct power_supply *psy, } static enum power_supply_property bq24190_charger_properties[] = { - POWER_SUPPLY_PROP_TYPE, + POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, -- cgit v1.3-6-gb490 From eead035a35b59df9f956139cb2c73141751a246e Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 4 Aug 2015 14:30:11 +0300 Subject: mei: remove check on pm_runtime_active in __mei_cl_disconnect Remove bogus check on pm_runtime_active that prevented disconnection from a client in case the device was resuming from power gating but not yet active. Fix regression introduced by 18901357e70ae29e3fd1c58712a6847c2ae52eae mei: disconnect on connection request timeout Signed-off-by: Tomas Winkler Signed-off-by: Alexander Usyskin Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 5fcd70bcdf96..a6c87c713193 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -853,9 +853,6 @@ static int __mei_cl_disconnect(struct mei_cl *cl) dev = cl->dev; - if (WARN_ON(!pm_runtime_active(dev->dev))) - return -EFAULT; - cl->state = MEI_FILE_DISCONNECTING; cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL); -- cgit v1.3-6-gb490 From 9625734ff75af35d9878c693e3f92237aa3c1ae6 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Sat, 25 Jul 2015 02:00:40 +0200 Subject: serial: etraxfs-uart: remove empty functions Implementing enable_ms is optional by serial_core. check_modem_status is just an empty local function. Signed-off-by: Niklas Cassel Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/etraxfs-uart.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/etraxfs-uart.c b/drivers/tty/serial/etraxfs-uart.c index 72d89a8ff27e..8f242dc84cea 100644 --- a/drivers/tty/serial/etraxfs-uart.c +++ b/drivers/tty/serial/etraxfs-uart.c @@ -366,14 +366,6 @@ static void etraxfs_uart_stop_rx(struct uart_port *port) REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl); } -static void etraxfs_uart_enable_ms(struct uart_port *port) -{ -} - -static void check_modem_status(struct uart_cris_port *up) -{ -} - static unsigned int etraxfs_uart_tx_empty(struct uart_port *port) { struct uart_cris_port *up = (struct uart_cris_port *)port; @@ -591,7 +583,6 @@ ser_interrupt(int irq, void *dev_id) receive_chars_no_dma(up); handled = 1; } - check_modem_status(up); if (masked_intr.tr_rdy) { transmit_chars_no_dma(up); @@ -855,7 +846,6 @@ static const struct uart_ops etraxfs_uart_pops = { .start_tx = etraxfs_uart_start_tx, .send_xchar = etraxfs_uart_send_xchar, .stop_rx = etraxfs_uart_stop_rx, - .enable_ms = etraxfs_uart_enable_ms, .break_ctl = etraxfs_uart_break_ctl, .startup = etraxfs_uart_startup, .shutdown = etraxfs_uart_shutdown, -- cgit v1.3-6-gb490 From 7b9c5162c1829686baea1962177842c3fa1ea81c Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Sat, 25 Jul 2015 02:02:46 +0200 Subject: serial: etraxfs-uart: use mctrl_gpio helpers for handling modem signals In order to use the mctrl_gpio helpers, we change the DT bindings: ri-gpios renamed to rng-gpios. cd-gpios renamed to dcd-gpios. However, no in-tree dts/dtsi specifies these, so no worries. Signed-off-by: Niklas Cassel Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Acked-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- .../bindings/serial/axis,etraxfs-uart.txt | 6 +++- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/etraxfs-uart.c | 40 ++++++---------------- 3 files changed, 16 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt b/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt index ebcbb62c0a76..51b3c9e80ad9 100644 --- a/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt +++ b/Documentation/devicetree/bindings/serial/axis,etraxfs-uart.txt @@ -6,7 +6,7 @@ Required properties: - interrupts: device interrupt Optional properties: -- {dtr,dsr,ri,cd}-gpios: specify a GPIO for DTR/DSR/RI/CD +- {dtr,dsr,rng,dcd}-gpios: specify a GPIO for DTR/DSR/RI/DCD line respectively. Example: @@ -16,4 +16,8 @@ serial@b00260000 { reg = <0xb0026000 0x1000>; interrupts = <68>; status = "disabled"; + dtr-gpios = <&sysgpio 0 GPIO_ACTIVE_LOW>; + dsr-gpios = <&sysgpio 1 GPIO_ACTIVE_LOW>; + rng-gpios = <&sysgpio 2 GPIO_ACTIVE_LOW>; + dcd-gpios = <&sysgpio 3 GPIO_ACTIVE_LOW>; }; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 4c8662ea7bb0..cbde6b77ef77 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1067,6 +1067,7 @@ config SERIAL_ETRAXFS bool "ETRAX FS serial port support" depends on ETRAX_ARCH_V32 && OF select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB config SERIAL_ETRAXFS_CONSOLE bool "ETRAX FS serial console support" diff --git a/drivers/tty/serial/etraxfs-uart.c b/drivers/tty/serial/etraxfs-uart.c index 8f242dc84cea..6813e316e9ff 100644 --- a/drivers/tty/serial/etraxfs-uart.c +++ b/drivers/tty/serial/etraxfs-uart.c @@ -10,6 +10,8 @@ #include #include +#include "serial_mctrl_gpio.h" + #define DRV_NAME "etraxfs-uart" #define UART_NR CONFIG_ETRAX_SERIAL_PORTS @@ -28,10 +30,7 @@ struct uart_cris_port { void __iomem *regi_ser; - struct gpio_desc *dtr_pin; - struct gpio_desc *dsr_pin; - struct gpio_desc *ri_pin; - struct gpio_desc *cd_pin; + struct mctrl_gpios *gpios; int write_ongoing; }; @@ -389,21 +388,9 @@ static unsigned int etraxfs_uart_get_mctrl(struct uart_port *port) ret = 0; if (crisv32_serial_get_rts(up)) ret |= TIOCM_RTS; - /* DTR is active low */ - if (up->dtr_pin && !gpiod_get_raw_value(up->dtr_pin)) - ret |= TIOCM_DTR; - /* CD is active low */ - if (up->cd_pin && !gpiod_get_raw_value(up->cd_pin)) - ret |= TIOCM_CD; - /* RI is active low */ - if (up->ri_pin && !gpiod_get_raw_value(up->ri_pin)) - ret |= TIOCM_RI; - /* DSR is active low */ - if (up->dsr_pin && !gpiod_get_raw_value(up->dsr_pin)) - ret |= TIOCM_DSR; if (crisv32_serial_get_cts(up)) ret |= TIOCM_CTS; - return ret; + return mctrl_gpio_get(up->gpios, &ret); } static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -411,15 +398,7 @@ static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) struct uart_cris_port *up = (struct uart_cris_port *)port; crisv32_serial_set_rts(up, mctrl & TIOCM_RTS ? 1 : 0, 0); - /* DTR is active low */ - if (up->dtr_pin) - gpiod_set_raw_value(up->dtr_pin, mctrl & TIOCM_DTR ? 0 : 1); - /* RI is active low */ - if (up->ri_pin) - gpiod_set_raw_value(up->ri_pin, mctrl & TIOCM_RNG ? 0 : 1); - /* CD is active low */ - if (up->cd_pin) - gpiod_set_raw_value(up->cd_pin, mctrl & TIOCM_CD ? 0 : 1); + mctrl_gpio_set(up->gpios, mctrl); } static void etraxfs_uart_break_ctl(struct uart_port *port, int break_state) @@ -913,11 +892,12 @@ static int etraxfs_uart_probe(struct platform_device *pdev) up->irq = irq_of_parse_and_map(np, 0); up->regi_ser = of_iomap(np, 0); - up->dtr_pin = devm_gpiod_get_optional(&pdev->dev, "dtr"); - up->dsr_pin = devm_gpiod_get_optional(&pdev->dev, "dsr"); - up->ri_pin = devm_gpiod_get_optional(&pdev->dev, "ri"); - up->cd_pin = devm_gpiod_get_optional(&pdev->dev, "cd"); up->port.dev = &pdev->dev; + + up->gpios = mctrl_gpio_init(&pdev->dev, 0); + if (IS_ERR(up->gpios)) + return PTR_ERR(up->gpios); + cris_serial_port_init(&up->port, dev_id); etraxfs_uart_ports[dev_id] = up; -- cgit v1.3-6-gb490 From 7d07ada047a4e1f5ff98757ce34c0fdd13d8ec93 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 27 Jul 2015 18:09:33 +0200 Subject: serial: mpc52xx: let tx_empty callback return either 0 or TIOCSER_TEMT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documenation/serial/driver requests that the tx_empty callback should return 0 if there are still chars in the fifo or shifter or TIOCSER_TEMT (0x01) if no character is pending to be sent. Fix the mpc52xx serial driver to not return MPC52xx_PSC_SR_TXEMP (i.e. 0x0800) but TIOCSER_TEMT as documented. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mpc52xx_uart.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 6fc07eb9d74e..41de374d9784 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -239,8 +239,9 @@ static int mpc52xx_psc_tx_rdy(struct uart_port *port) static int mpc52xx_psc_tx_empty(struct uart_port *port) { - return in_be16(&PSC(port)->mpc52xx_psc_status) - & MPC52xx_PSC_SR_TXEMP; + u16 sts = in_be16(&PSC(port)->mpc52xx_psc_status); + + return (sts & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0; } static void mpc52xx_psc_start_tx(struct uart_port *port) -- cgit v1.3-6-gb490 From 0a6c301a2db2f9af0478a83c15d8ec5cdac65eb9 Mon Sep 17 00:00:00 2001 From: Qipeng Zha Date: Wed, 29 Jul 2015 18:23:32 +0800 Subject: serial: 8250: Auto CTS control by HW if AFE enabled According to DesignWare 8250 spec, if auto flow control mode is enabled, a change in CTS does not cause an interrupt, so sw-assisted CTS flow control mode will not work properly. There reported an GPS firmware download failure issue, and we verified the root cause is, the default sw-assisted CTS flow control mode can not work properly since no interrupt when got CTS signal. This patch is to enable auto CTS mode by defaut if CRTSCTS is enable for DesignWare 8250 controller. Signed-off-by: Huiquan Zhong Signed-off-by: Qipeng Zha Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 5 +++++ drivers/tty/serial/8250/8250_pci.c | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index d48b50641e9a..8d04ea781de4 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -257,6 +257,11 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, if (!ret) p->uartclk = rate; + + p->status &= ~UPSTAT_AUTOCTS; + if (termios->c_cflag & CRTSCTS) + p->status |= UPSTAT_AUTOCTS; + out: serial8250_do_set_termios(p, termios, old); } diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index df2e61e206fa..dd4483f1d329 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1417,6 +1417,10 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios, reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; writel(reg, p->membase + BYT_PRV_CLK); + p->status &= ~UPSTAT_AUTOCTS; + if (termios->c_cflag & CRTSCTS) + p->status |= UPSTAT_AUTOCTS; + serial8250_do_set_termios(p, termios, old); } -- cgit v1.3-6-gb490 From b737eeb09e3068b092e116f855aa1973fa24c88c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 2 Aug 2015 11:09:52 +0200 Subject: serial: Allow compile test of GPIO consumers if !GPIOLIB The GPIO subsystem provides dummy GPIO consumer functions if GPIOLIB is not enabled. Hence drivers that depend on GPIOLIB, but use GPIO consumer functionality only, can still be compiled if GPIOLIB is not enabled. Relax the dependency on GPIOLIB if COMPILE_TEST is enabled, where appropriate. Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index cbde6b77ef77..687b1ea294b7 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1377,7 +1377,8 @@ config SERIAL_ALTERA_UART_CONSOLE config SERIAL_IFX6X60 tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)" - depends on GPIOLIB && SPI && HAS_DMA + depends on GPIOLIB || COMPILE_TEST + depends on SPI && HAS_DMA help Support for the IFX6x60 modem devices on Intel MID platforms. -- cgit v1.3-6-gb490 From a649943522de07e67a5981b1ff227684b94bada4 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 30 Jul 2015 16:33:38 +0200 Subject: tty/serial: at91: fix I/O accesses on RHR and THR for AVR32 This patch fixes I/O accesses on the Receiver Holding Register and on the Transmitter Holding Register. Indeed AVR32 can only perform 32bit I/O accesses on registers: using 8bit I/O accesses would read or write garbage data. Fixes: commit b5199d468177 ("tty/serial: at91: add support to FIFOs") Signed-off-by: Cyrille Pitchen Tested-by: Andy Shevchenko Acked-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index e91b3b2f0590..5ca5cf3e9359 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -204,16 +204,33 @@ static inline void atmel_uart_writel(struct uart_port *port, u32 reg, u32 value) __raw_writel(value, port->membase + reg); } -static inline u8 atmel_uart_readb(struct uart_port *port, u32 reg) +#ifdef CONFIG_AVR32 + +/* AVR32 cannot handle 8 or 16bit I/O accesses but only 32bit I/O accesses */ +static inline u8 atmel_uart_read_char(struct uart_port *port) +{ + return __raw_readl(port->membase + ATMEL_US_RHR); +} + +static inline void atmel_uart_write_char(struct uart_port *port, u8 value) { - return __raw_readb(port->membase + reg); + __raw_writel(value, port->membase + ATMEL_US_THR); } -static inline void atmel_uart_writeb(struct uart_port *port, u32 reg, u8 value) +#else + +static inline u8 atmel_uart_read_char(struct uart_port *port) { - __raw_writeb(value, port->membase + reg); + return __raw_readb(port->membase + ATMEL_US_RHR); } +static inline void atmel_uart_write_char(struct uart_port *port, u8 value) +{ + __raw_writeb(value, port->membase + ATMEL_US_THR); +} + +#endif + #ifdef CONFIG_SERIAL_ATMEL_PDC static bool atmel_use_pdc_rx(struct uart_port *port) { @@ -658,7 +675,7 @@ static void atmel_rx_chars(struct uart_port *port) status = atmel_uart_readl(port, ATMEL_US_CSR); while (status & ATMEL_US_RXRDY) { - ch = atmel_uart_readb(port, ATMEL_US_RHR); + ch = atmel_uart_read_char(port); /* * note that the error handling code is @@ -709,7 +726,7 @@ static void atmel_tx_chars(struct uart_port *port) if (port->x_char && (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask)) { - atmel_uart_writeb(port, ATMEL_US_THR, port->x_char); + atmel_uart_write_char(port, port->x_char); port->icount.tx++; port->x_char = 0; } @@ -718,7 +735,7 @@ static void atmel_tx_chars(struct uart_port *port) while (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask) { - atmel_uart_writeb(port, ATMEL_US_THR, xmit->buf[xmit->tail]); + atmel_uart_write_char(port, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) @@ -2294,7 +2311,7 @@ static int atmel_poll_get_char(struct uart_port *port) while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_RXRDY)) cpu_relax(); - return atmel_uart_readb(port, ATMEL_US_RHR); + return atmel_uart_read_char(port); } static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) @@ -2302,7 +2319,7 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - atmel_uart_writeb(port, ATMEL_US_THR, ch); + atmel_uart_write_char(port, ch); } #endif @@ -2409,7 +2426,7 @@ static void atmel_console_putchar(struct uart_port *port, int ch) { while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - atmel_uart_writeb(port, ATMEL_US_THR, ch); + atmel_uart_write_char(port, ch); } /* -- cgit v1.3-6-gb490 From 6fb98fb3031359af42a6ee6984b477cbcfdca7bd Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Fri, 31 Jul 2015 16:59:51 -0400 Subject: serial: core: Use proper spinlock flavor in uart_close() uart_close() runs in non-atomic context only; use spin_lock/unlock_irq instead of saving the interrupt state (which == on). Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f36852067f20..6ae7cc118ac4 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1377,7 +1377,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp) struct uart_state *state = tty->driver_data; struct tty_port *port; struct uart_port *uport; - unsigned long flags; if (!state) { struct uart_driver *drv = tty->driver->driver_state; @@ -1403,10 +1402,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * disable the receive line status interrupts. */ if (port->flags & ASYNC_INITIALIZED) { - unsigned long flags; - spin_lock_irqsave(&uport->lock, flags); + spin_lock_irq(&uport->lock); uport->ops->stop_rx(uport); - spin_unlock_irqrestore(&uport->lock, flags); + spin_unlock_irq(&uport->lock); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially @@ -1419,17 +1417,17 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uart_shutdown(tty, state); tty_port_tty_set(port, NULL); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irq(&port->lock); if (port->blocked_open) { - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irq(&port->lock); if (port->close_delay) msleep_interruptible(jiffies_to_msecs(port->close_delay)); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irq(&port->lock); } else if (!uart_console(uport)) { - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irq(&port->lock); uart_change_pm(state, UART_PM_STATE_OFF); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irq(&port->lock); } /* @@ -1437,7 +1435,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) */ clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); clear_bit(ASYNCB_CLOSING, &port->flags); - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irq(&port->lock); wake_up_interruptible(&port->open_wait); wake_up_interruptible(&port->close_wait); -- cgit v1.3-6-gb490 From 9e31364fc3272073ec8c5fac18a3e01d4f013418 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Fri, 31 Jul 2015 16:59:52 -0400 Subject: serial: core: Remove tty port activate() and shutdown() methods serial core does not use tty_port_open() or tty_port_close(); serial core defines and extends it's own tty open() and close() methods (uart_open() and uart_close(), respectively). Remove the tty_port activate() and shutdown() initializations, and the uart_port_activate() function, which is never called. NB: uart_port_shutdown() is used by uart_close() => uart_shutdown() call chain (but not via the tty_port methods). Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 6ae7cc118ac4..603d2cc3f424 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1530,11 +1530,6 @@ static void uart_hangup(struct tty_struct *tty) mutex_unlock(&port->mutex); } -static int uart_port_activate(struct tty_port *port, struct tty_struct *tty) -{ - return 0; -} - static void uart_port_shutdown(struct tty_port *port) { struct uart_state *state = container_of(port, struct uart_state, port); @@ -2377,8 +2372,6 @@ static const struct tty_operations uart_ops = { }; static const struct tty_port_operations uart_port_ops = { - .activate = uart_port_activate, - .shutdown = uart_port_shutdown, .carrier_raised = uart_carrier_raised, .dtr_rts = uart_dtr_rts, }; -- cgit v1.3-6-gb490 From 81ccb2a69f76b88295a1da9fc9484df715fe3bfa Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 31 Jul 2015 10:58:27 +0200 Subject: serial: samsung: fix DMA mode enter condition for small FIFO sizes Due to some of serial ports can have FIFO size smaller than cache line size, and because of need to align DMA buffer address to cache line size, it's necessary to calculate minimum number of bytes for which we want to start DMA transaction to be at least cache line size. The simplest way to meet this requirement is to get maximum of cache line size and FIFO size. Cc: # v3.18+ Reported-by: Krzysztof Kozlowski Signed-off-by: Marek Szyprowski Signed-off-by: Robert Baldyga Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 13 +++++++++++-- drivers/tty/serial/samsung.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 8c963d6d9074..faee021c27b0 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -341,7 +341,8 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport) return; } - if (!ourport->dma || !ourport->dma->tx_chan || count < port->fifosize) + if (!ourport->dma || !ourport->dma->tx_chan || + count < ourport->min_dma_size) s3c24xx_serial_start_tx_pio(ourport); else s3c24xx_serial_start_tx_dma(ourport, count); @@ -741,7 +742,8 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - if (ourport->dma && ourport->dma->tx_chan && count >= port->fifosize) { + if (ourport->dma && ourport->dma->tx_chan && + count >= ourport->min_dma_size) { s3c24xx_serial_start_tx_dma(ourport, count); goto out; } @@ -1837,6 +1839,13 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) else if (ourport->info->fifosize) ourport->port.fifosize = ourport->info->fifosize; + /* + * DMA transfers must be aligned at least to cache line size, + * so find minimal transfer size suitable for DMA mode + */ + ourport->min_dma_size = max_t(int, ourport->port.fifosize, + dma_get_cache_alignment()); + probe_index++; dbg("%s: initialising port %p...\n", __func__, ourport); diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h index d275032aa68d..fc5deaa4f382 100644 --- a/drivers/tty/serial/samsung.h +++ b/drivers/tty/serial/samsung.h @@ -82,6 +82,7 @@ struct s3c24xx_uart_port { unsigned char tx_claimed; unsigned int pm_level; unsigned long baudclk_rate; + unsigned int min_dma_size; unsigned int rx_irq; unsigned int tx_irq; -- cgit v1.3-6-gb490 From 736cd79f483fd7a1e0b71e6eaddf01d8d87fbbbb Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 31 Jul 2015 10:58:28 +0200 Subject: serial: samsung: fix DMA for FIFO smaller than cache line size So far DMA mode were activated when only number of bytes to send was equal or greater than min_dma_size. Due to requirement that DMA transaction buffer should be aligned to cache line size, the excessive bytes were written to FIFO before starting DMA transaction. The problem occurred when FIFO size were smaller than cache alignment, because writing all excessive bytes to FIFO would fail. It happened in DMA mode when PIO interrupts disabled, which caused driver hung. The solution is to test if buffer is alligned to cache line size before activating DMA mode, and if it's not, running PIO mode to align buffer and then starting DMA transaction. In PIO mode, when interrupts are enabled, lack of space in FIFO isn't the problem, so buffer aligning will always finish with success. Cc: # v3.18+ Reported-by: Krzysztof Kozlowski Signed-off-by: Robert Baldyga Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index faee021c27b0..856686d6dcdb 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -294,15 +294,6 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport, if (ourport->tx_mode != S3C24XX_TX_DMA) enable_tx_dma(ourport); - while (xmit->tail & (dma_get_cache_alignment() - 1)) { - if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull) - return 0; - wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - count--; - } - dma->tx_size = count & ~(dma_get_cache_alignment() - 1); dma->tx_transfer_addr = dma->tx_addr + xmit->tail; @@ -342,7 +333,8 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport) } if (!ourport->dma || !ourport->dma->tx_chan || - count < ourport->min_dma_size) + count < ourport->min_dma_size || + xmit->tail & (dma_get_cache_alignment() - 1)) s3c24xx_serial_start_tx_pio(ourport); else s3c24xx_serial_start_tx_dma(ourport, count); @@ -736,7 +728,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) struct uart_port *port = &ourport->port; struct circ_buf *xmit = &port->state->xmit; unsigned long flags; - int count; + int count, dma_count = 0; spin_lock_irqsave(&port->lock, flags); @@ -744,8 +736,12 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) if (ourport->dma && ourport->dma->tx_chan && count >= ourport->min_dma_size) { - s3c24xx_serial_start_tx_dma(ourport, count); - goto out; + int align = dma_get_cache_alignment() - + (xmit->tail & (dma_get_cache_alignment() - 1)); + if (count-align >= ourport->min_dma_size) { + dma_count = count-align; + count = align; + } } if (port->x_char) { @@ -766,14 +762,24 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) /* try and drain the buffer... */ - count = port->fifosize; - while (!uart_circ_empty(xmit) && count-- > 0) { + if (count > port->fifosize) { + count = port->fifosize; + dma_count = 0; + } + + while (!uart_circ_empty(xmit) && count > 0) { if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull) break; wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; + count--; + } + + if (!count && dma_count) { + s3c24xx_serial_start_tx_dma(ourport, dma_count); + goto out; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { -- cgit v1.3-6-gb490 From 89c043a6cb2d4525d48a38ed78d5f0f5672338b3 Mon Sep 17 00:00:00 2001 From: Adam Lee Date: Mon, 3 Aug 2015 13:28:13 +0800 Subject: serial: 8250_pci: Add support for Pericom PI7C9X795[1248] Pericom PI7C9X795[1248] are Uno/Dual/Quad/Octal UART devices, this patch enables them, also defines PCI_VENDOR_ID_PERICOM here. Signed-off-by: Adam Lee Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 82 ++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index dd4483f1d329..e12e91181781 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -2082,6 +2082,12 @@ pci_wch_ch38x_setup(struct serial_private *priv, #define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 #define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470 +#define PCI_VENDOR_ID_PERICOM 0x12D8 +#define PCI_DEVICE_ID_PERICOM_PI7C9X7951 0x7951 +#define PCI_DEVICE_ID_PERICOM_PI7C9X7952 0x7952 +#define PCI_DEVICE_ID_PERICOM_PI7C9X7954 0x7954 +#define PCI_DEVICE_ID_PERICOM_PI7C9X7958 0x7958 + /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1588 0x1588 @@ -2396,27 +2402,12 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { * Pericom */ { - .vendor = 0x12d8, - .device = 0x7952, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, - }, - { - .vendor = 0x12d8, - .device = 0x7954, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, - }, - { - .vendor = 0x12d8, - .device = 0x7958, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .vendor = PCI_VENDOR_ID_PERICOM, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, }, - /* * PLX */ @@ -3121,6 +3112,10 @@ enum pci_board_num_t { pbn_fintek_8, pbn_fintek_12, pbn_wch384_4, + pbn_pericom_PI7C9X7951, + pbn_pericom_PI7C9X7952, + pbn_pericom_PI7C9X7954, + pbn_pericom_PI7C9X7958, }; /* @@ -3946,7 +3941,6 @@ static struct pciserial_board pci_boards[] = { .base_baud = 115200, .first_offset = 0x40, }, - [pbn_wch384_4] = { .flags = FL_BASE0, .num_ports = 4, @@ -3954,6 +3948,33 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 8, .first_offset = 0xC0, }, + /* + * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART + */ + [pbn_pericom_PI7C9X7951] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_pericom_PI7C9X7952] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_pericom_PI7C9X7954] = { + .flags = FL_BASE0, + .num_ports = 4, + .base_baud = 921600, + .uart_offset = 0x8, + }, + [pbn_pericom_PI7C9X7958] = { + .flags = FL_BASE0, + .num_ports = 8, + .base_baud = 921600, + .uart_offset = 0x8, + }, }; static const struct pci_device_id blacklist[] = { @@ -5218,6 +5239,25 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_exar_XR17V8358 }, + /* + * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART + */ + { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7951, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_pericom_PI7C9X7951 }, + { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7952, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_pericom_PI7C9X7952 }, + { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7954, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_pericom_PI7C9X7954 }, + { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7958, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_pericom_PI7C9X7958 }, /* * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) */ -- cgit v1.3-6-gb490 From 534e14e2293d8cd714b94513686228453b21fae2 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Fri, 31 Jul 2015 15:49:15 +0800 Subject: uart: pl011: Rename regs with enumeration Rename regs with enumeration to generalize register names. Signed-off-by: Jun Nie Reviewed-by: Peter Hurley Signed-off-by: Jun Nie Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 207 ++++++++++++++++++++++------------------ 1 file changed, 114 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index fd27e986b1dd..ee57e2bee9a1 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -85,6 +85,25 @@ struct vendor_data { unsigned int (*get_fifosize)(struct amba_device *dev); }; +enum reg_idx { + REG_DR = UART01x_DR, + REG_RSR = UART01x_RSR, + REG_ST_DMAWM = ST_UART011_DMAWM, + REG_FR = UART01x_FR, + REG_ST_LCRH_RX = ST_UART011_LCRH_RX, + REG_ILPR = UART01x_ILPR, + REG_IBRD = UART011_IBRD, + REG_FBRD = UART011_FBRD, + REG_LCRH = UART011_LCRH, + REG_CR = UART011_CR, + REG_IFLS = UART011_IFLS, + REG_IMSC = UART011_IMSC, + REG_RIS = UART011_RIS, + REG_MIS = UART011_MIS, + REG_ICR = UART011_ICR, + REG_DMACR = UART011_DMACR, +}; + static unsigned int get_fifosize_arm(struct amba_device *dev) { return amba_rev(dev) < 3 ? 16 : 32; @@ -92,8 +111,8 @@ static unsigned int get_fifosize_arm(struct amba_device *dev) static struct vendor_data vendor_arm = { .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, - .lcrh_tx = UART011_LCRH, - .lcrh_rx = UART011_LCRH, + .lcrh_tx = REG_LCRH, + .lcrh_rx = REG_LCRH, .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, @@ -117,8 +136,8 @@ static unsigned int get_fifosize_st(struct amba_device *dev) static struct vendor_data vendor_st = { .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, - .lcrh_tx = ST_UART011_LCRH_TX, - .lcrh_rx = ST_UART011_LCRH_RX, + .lcrh_tx = REG_LCRH, + .lcrh_rx = REG_ST_LCRH_RX, .oversampling = true, .dma_threshold = true, .cts_event_workaround = true, @@ -196,12 +215,12 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) int fifotaken = 0; while (max_count--) { - status = readw(uap->port.membase + UART01x_FR); + status = readw(uap->port.membase + REG_FR); if (status & UART01x_FR_RXFE) break; /* Take chars from the FIFO and update status */ - ch = readw(uap->port.membase + UART01x_DR) | + ch = readw(uap->port.membase + REG_DR) | UART_DUMMY_DR_RX; flag = TTY_NORMAL; uap->port.icount.rx++; @@ -284,7 +303,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev); struct device *dev = uap->port.dev; struct dma_slave_config tx_conf = { - .dst_addr = uap->port.mapbase + UART01x_DR, + .dst_addr = uap->port.mapbase + REG_DR, .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, .direction = DMA_MEM_TO_DEV, .dst_maxburst = uap->fifosize >> 1, @@ -339,7 +358,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) if (chan) { struct dma_slave_config rx_conf = { - .src_addr = uap->port.mapbase + UART01x_DR, + .src_addr = uap->port.mapbase + REG_DR, .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, .direction = DMA_DEV_TO_MEM, .src_maxburst = uap->fifosize >> 2, @@ -438,7 +457,7 @@ static void pl011_dma_tx_callback(void *data) dmacr = uap->dmacr; uap->dmacr = dmacr & ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); /* * If TX DMA was disabled, it means that we've stopped the DMA for @@ -552,7 +571,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) dma_dev->device_issue_pending(chan); uap->dmacr |= UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); uap->dmatx.queued = true; /* @@ -588,9 +607,9 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap) */ if (uap->dmatx.queued) { uap->dmacr |= UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); return true; } @@ -600,7 +619,7 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap) */ if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); return true; } return false; @@ -614,7 +633,7 @@ static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) { if (uap->dmatx.queued) { uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); } } @@ -641,13 +660,13 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; writew(uap->im, uap->port.membase + - UART011_IMSC); + REG_IMSC); } else ret = false; } else if (!(uap->dmacr & UART011_TXDMAE)) { uap->dmacr |= UART011_TXDMAE; writew(uap->dmacr, - uap->port.membase + UART011_DMACR); + uap->port.membase + REG_DMACR); } return ret; } @@ -658,9 +677,9 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) */ dmacr = uap->dmacr; uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); - if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { + if (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) { /* * No space in the FIFO, so enable the transmit interrupt * so we know when there is space. Note that once we've @@ -669,13 +688,13 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) return false; } - writew(uap->port.x_char, uap->port.membase + UART01x_DR); + writew(uap->port.x_char, uap->port.membase + REG_DR); uap->port.icount.tx++; uap->port.x_char = 0; /* Success - restore the DMA state */ uap->dmacr = dmacr; - writew(dmacr, uap->port.membase + UART011_DMACR); + writew(dmacr, uap->port.membase + REG_DMACR); return true; } @@ -703,7 +722,7 @@ __acquires(&uap->port.lock) DMA_TO_DEVICE); uap->dmatx.queued = false; uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); } } @@ -743,11 +762,11 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap) dma_async_issue_pending(rxchan); uap->dmacr |= UART011_RXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); uap->dmarx.running = true; uap->im &= ~UART011_RXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); return 0; } @@ -806,7 +825,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, if (dma_count == pending && readfifo) { /* Clear any error flags */ writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, - uap->port.membase + UART011_ICR); + uap->port.membase + REG_ICR); /* * If we read all the DMA'd characters, and we had an @@ -854,7 +873,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap) /* Disable RX DMA - incoming data will wait in the FIFO */ uap->dmacr &= ~UART011_RXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); uap->dmarx.running = false; pending = sgbuf->sg.length - state.residue; @@ -874,7 +893,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap) dev_dbg(uap->port.dev, "could not retrigger RX DMA job " "fall back to interrupt mode\n"); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); } } @@ -922,7 +941,7 @@ static void pl011_dma_rx_callback(void *data) dev_dbg(uap->port.dev, "could not retrigger RX DMA job " "fall back to interrupt mode\n"); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); } } @@ -935,7 +954,7 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap) { /* FIXME. Just disable the DMA enable */ uap->dmacr &= ~UART011_RXDMAE; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); } /* @@ -979,7 +998,7 @@ static void pl011_dma_rx_poll(unsigned long args) spin_lock_irqsave(&uap->port.lock, flags); pl011_dma_rx_stop(uap); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); spin_unlock_irqrestore(&uap->port.lock, flags); uap->dmarx.running = false; @@ -1041,7 +1060,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap) skip_rx: /* Turn on DMA error (RX/TX will be enabled on demand) */ uap->dmacr |= UART011_DMAONERR; - writew(uap->dmacr, uap->port.membase + UART011_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); /* * ST Micro variants has some specific dma burst threshold @@ -1050,7 +1069,8 @@ skip_rx: */ if (uap->vendor->dma_threshold) writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16, - uap->port.membase + ST_UART011_DMAWM); + uap->port.membase + REG_ST_DMAWM); + if (uap->using_rx_dma) { if (pl011_dma_rx_trigger_dma(uap)) @@ -1075,12 +1095,12 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) return; /* Disable RX and TX DMA */ - while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) + while (readw(uap->port.membase + REG_FR) & UART01x_FR_BUSY) barrier(); spin_lock_irq(&uap->port.lock); uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); - writew(uap->dmacr, uap->port.membase + UART011_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); spin_unlock_irq(&uap->port.lock); if (uap->using_tx_dma) { @@ -1181,7 +1201,7 @@ static void pl011_stop_tx(struct uart_port *port) container_of(port, struct uart_amba_port, port); uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); pl011_dma_tx_stop(uap); } @@ -1191,7 +1211,7 @@ static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq); static void pl011_start_tx_pio(struct uart_amba_port *uap) { uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); pl011_tx_chars(uap, false); } @@ -1211,7 +1231,7 @@ static void pl011_stop_rx(struct uart_port *port) uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| UART011_PEIM|UART011_BEIM|UART011_OEIM); - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); pl011_dma_rx_stop(uap); } @@ -1222,7 +1242,7 @@ static void pl011_enable_ms(struct uart_port *port) container_of(port, struct uart_amba_port, port); uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); } static void pl011_rx_chars(struct uart_amba_port *uap) @@ -1242,7 +1262,7 @@ __acquires(&uap->port.lock) dev_dbg(uap->port.dev, "could not trigger RX DMA job " "fall back to interrupt mode again\n"); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); } else { #ifdef CONFIG_DMA_ENGINE /* Start Rx DMA poll */ @@ -1263,10 +1283,10 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, bool from_irq) { if (unlikely(!from_irq) && - readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) + readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) return false; /* unable to transmit character */ - writew(c, uap->port.membase + UART01x_DR); + writew(c, uap->port.membase + REG_DR); uap->port.icount.tx++; return true; @@ -1313,7 +1333,7 @@ static void pl011_modem_status(struct uart_amba_port *uap) { unsigned int status, delta; - status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; + status = readw(uap->port.membase + REG_FR) & UART01x_FR_MODEM_ANY; delta = status ^ uap->old_status; uap->old_status = status; @@ -1341,15 +1361,15 @@ static void check_apply_cts_event_workaround(struct uart_amba_port *uap) return; /* workaround to make sure that all bits are unlocked.. */ - writew(0x00, uap->port.membase + UART011_ICR); + writew(0x00, uap->port.membase + REG_ICR); /* * WA: introduce 26ns(1 uart clk) delay before W1C; * single apb access will incur 2 pclk(133.12Mhz) delay, * so add 2 dummy reads */ - dummy_read = readw(uap->port.membase + UART011_ICR); - dummy_read = readw(uap->port.membase + UART011_ICR); + dummy_read = readw(uap->port.membase + REG_ICR); + dummy_read = readw(uap->port.membase + REG_ICR); } static irqreturn_t pl011_int(int irq, void *dev_id) @@ -1361,15 +1381,15 @@ static irqreturn_t pl011_int(int irq, void *dev_id) int handled = 0; spin_lock_irqsave(&uap->port.lock, flags); - imsc = readw(uap->port.membase + UART011_IMSC); - status = readw(uap->port.membase + UART011_RIS) & imsc; + imsc = readw(uap->port.membase + REG_IMSC); + status = readw(uap->port.membase + REG_RIS) & imsc; if (status) { do { check_apply_cts_event_workaround(uap); writew(status & ~(UART011_TXIS|UART011_RTIS| UART011_RXIS), - uap->port.membase + UART011_ICR); + uap->port.membase + REG_ICR); if (status & (UART011_RTIS|UART011_RXIS)) { if (pl011_dma_rx_running(uap)) @@ -1386,7 +1406,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (pass_counter-- == 0) break; - status = readw(uap->port.membase + UART011_RIS) & imsc; + status = readw(uap->port.membase + REG_RIS) & imsc; } while (status != 0); handled = 1; } @@ -1400,7 +1420,7 @@ static unsigned int pl011_tx_empty(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - unsigned int status = readw(uap->port.membase + UART01x_FR); + unsigned int status = readw(uap->port.membase + REG_FR); return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; } @@ -1409,7 +1429,7 @@ static unsigned int pl011_get_mctrl(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); unsigned int result = 0; - unsigned int status = readw(uap->port.membase + UART01x_FR); + unsigned int status = readw(uap->port.membase + REG_FR); #define TIOCMBIT(uartbit, tiocmbit) \ if (status & uartbit) \ @@ -1429,7 +1449,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) container_of(port, struct uart_amba_port, port); unsigned int cr; - cr = readw(uap->port.membase + UART011_CR); + cr = readw(uap->port.membase + REG_CR); #define TIOCMBIT(tiocmbit, uartbit) \ if (mctrl & tiocmbit) \ @@ -1449,7 +1469,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) } #undef TIOCMBIT - writew(cr, uap->port.membase + UART011_CR); + writew(cr, uap->port.membase + REG_CR); } static void pl011_break_ctl(struct uart_port *port, int break_state) @@ -1477,7 +1497,7 @@ static void pl011_quiesce_irqs(struct uart_port *port) container_of(port, struct uart_amba_port, port); unsigned char __iomem *regs = uap->port.membase; - writew(readw(regs + UART011_MIS), regs + UART011_ICR); + writew(readw(regs + REG_MIS), regs + REG_ICR); /* * There is no way to clear TXIM as this is "ready to transmit IRQ", so * we simply mask it. start_tx() will unmask it. @@ -1491,7 +1511,7 @@ static void pl011_quiesce_irqs(struct uart_port *port) * (including tx queue), so we're also fine with start_tx()'s caller * side. */ - writew(readw(regs + UART011_IMSC) & ~UART011_TXIM, regs + UART011_IMSC); + writew(readw(regs + REG_IMSC) & ~UART011_TXIM, regs + REG_IMSC); } static int pl011_get_poll_char(struct uart_port *port) @@ -1506,11 +1526,11 @@ static int pl011_get_poll_char(struct uart_port *port) */ pl011_quiesce_irqs(port); - status = readw(uap->port.membase + UART01x_FR); + status = readw(uap->port.membase + REG_FR); if (status & UART01x_FR_RXFE) return NO_POLL_CHAR; - return readw(uap->port.membase + UART01x_DR); + return readw(uap->port.membase + REG_DR); } static void pl011_put_poll_char(struct uart_port *port, @@ -1519,10 +1539,10 @@ static void pl011_put_poll_char(struct uart_port *port, struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) + while (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) barrier(); - writew(ch, uap->port.membase + UART01x_DR); + writew(ch, uap->port.membase + REG_DR); } #endif /* CONFIG_CONSOLE_POLL */ @@ -1547,14 +1567,14 @@ static int pl011_hwinit(struct uart_port *port) /* Clear pending error and receive interrupts */ writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS | - UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR); + UART011_RTIS | UART011_RXIS, uap->port.membase + REG_ICR); /* * Save interrupts enable mask, and enable RX interrupts in case if * the interrupt is used for NMI entry. */ - uap->im = readw(uap->port.membase + UART011_IMSC); - writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC); + uap->im = readw(uap->port.membase + REG_IMSC); + writew(UART011_RTIM | UART011_RXIM, uap->port.membase + REG_IMSC); if (dev_get_platdata(uap->port.dev)) { struct amba_pl011_data *plat; @@ -1576,14 +1596,14 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) * to get this delay write read only register 10 times */ for (i = 0; i < 10; ++i) - writew(0xff, uap->port.membase + UART011_MIS); + writew(0xff, uap->port.membase + REG_MIS); writew(lcr_h, uap->port.membase + uap->lcrh_tx); } } static int pl011_allocate_irq(struct uart_amba_port *uap) { - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); } @@ -1599,11 +1619,11 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap) /* Clear out any spuriously appearing RX interrupts */ writew(UART011_RTIS | UART011_RXIS, - uap->port.membase + UART011_ICR); + uap->port.membase + REG_ICR); uap->im = UART011_RTIM; if (!pl011_dma_rx_running(uap)) uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); spin_unlock_irq(&uap->port.lock); } @@ -1622,21 +1642,22 @@ static int pl011_startup(struct uart_port *port) if (retval) goto clk_dis; - writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); + writew(uap->vendor->ifls, uap->port.membase + REG_IFLS); spin_lock_irq(&uap->port.lock); /* restore RTS and DTR */ cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; - writew(cr, uap->port.membase + UART011_CR); + writew(cr, uap->port.membase + REG_CR); spin_unlock_irq(&uap->port.lock); /* * initialise the old status of the modem signals */ - uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; + uap->old_status = readw(uap->port.membase + REG_FR) & + UART01x_FR_MODEM_ANY; /* Startup DMA */ pl011_dma_startup(uap); @@ -1693,11 +1714,11 @@ static void pl011_disable_uart(struct uart_amba_port *uap) uap->autorts = false; spin_lock_irq(&uap->port.lock); - cr = readw(uap->port.membase + UART011_CR); + cr = readw(uap->port.membase + REG_CR); uap->old_cr = cr; cr &= UART011_CR_RTS | UART011_CR_DTR; cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - writew(cr, uap->port.membase + UART011_CR); + writew(cr, uap->port.membase + REG_CR); spin_unlock_irq(&uap->port.lock); /* @@ -1714,8 +1735,8 @@ static void pl011_disable_interrupts(struct uart_amba_port *uap) /* mask all interrupts and clear all pending ones */ uap->im = 0; - writew(uap->im, uap->port.membase + UART011_IMSC); - writew(0xffff, uap->port.membase + UART011_ICR); + writew(uap->im, uap->port.membase + REG_IMSC); + writew(0xffff, uap->port.membase + REG_ICR); spin_unlock_irq(&uap->port.lock); } @@ -1867,8 +1888,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, pl011_enable_ms(port); /* first, disable everything */ - old_cr = readw(port->membase + UART011_CR); - writew(0, port->membase + UART011_CR); + old_cr = readw(port->membase + REG_CR); + writew(0, port->membase + REG_CR); if (termios->c_cflag & CRTSCTS) { if (old_cr & UART011_CR_RTS) @@ -1901,17 +1922,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, quot -= 2; } /* Set baud rate */ - writew(quot & 0x3f, port->membase + UART011_FBRD); - writew(quot >> 6, port->membase + UART011_IBRD); + writew(quot & 0x3f, port->membase + REG_FBRD); + writew(quot >> 6, port->membase + REG_IBRD); /* * ----------v----------v----------v----------v----- * NOTE: lcrh_tx and lcrh_rx MUST BE WRITTEN AFTER - * UART011_FBRD & UART011_IBRD. + * REG_FBRD & REG_IBRD. * ----------^----------^----------^----------^----- */ pl011_write_lcr_h(uap, lcr_h); - writew(old_cr, port->membase + UART011_CR); + writew(old_cr, port->membase + REG_CR); spin_unlock_irqrestore(&port->lock, flags); } @@ -2052,9 +2073,9 @@ static void pl011_console_putchar(struct uart_port *port, int ch) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) + while (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) barrier(); - writew(ch, uap->port.membase + UART01x_DR); + writew(ch, uap->port.membase + REG_DR); } static void @@ -2079,10 +2100,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) * First save the CR then disable the interrupts */ if (!uap->vendor->always_enabled) { - old_cr = readw(uap->port.membase + UART011_CR); + old_cr = readw(uap->port.membase + REG_CR); new_cr = old_cr & ~UART011_CR_CTSEN; new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - writew(new_cr, uap->port.membase + UART011_CR); + writew(new_cr, uap->port.membase + REG_CR); } uart_console_write(&uap->port, s, count, pl011_console_putchar); @@ -2092,10 +2113,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) * and restore the TCR */ do { - status = readw(uap->port.membase + UART01x_FR); + status = readw(uap->port.membase + REG_FR); } while (status & UART01x_FR_BUSY); if (!uap->vendor->always_enabled) - writew(old_cr, uap->port.membase + UART011_CR); + writew(old_cr, uap->port.membase + REG_CR); if (locked) spin_unlock(&uap->port.lock); @@ -2108,7 +2129,7 @@ static void __init pl011_console_get_options(struct uart_amba_port *uap, int *baud, int *parity, int *bits) { - if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) { + if (readw(uap->port.membase + REG_CR) & UART01x_CR_UARTEN) { unsigned int lcr_h, ibrd, fbrd; lcr_h = readw(uap->port.membase + uap->lcrh_tx); @@ -2126,13 +2147,13 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, else *bits = 8; - ibrd = readw(uap->port.membase + UART011_IBRD); - fbrd = readw(uap->port.membase + UART011_FBRD); + ibrd = readw(uap->port.membase + REG_IBRD); + fbrd = readw(uap->port.membase + REG_FBRD); *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); if (uap->vendor->oversampling) { - if (readw(uap->port.membase + UART011_CR) + if (readw(uap->port.membase + REG_CR) & ST_UART011_CR_OVSFACT) *baud *= 2; } @@ -2204,10 +2225,10 @@ static struct console amba_console = { static void pl011_putc(struct uart_port *port, int c) { - while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) + while (readl(port->membase + REG_FR) & UART01x_FR_TXFF) ; - writeb(c, port->membase + UART01x_DR); - while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY) + writeb(c, port->membase + REG_DR); + while (readl(port->membase + REG_FR) & UART01x_FR_BUSY) ; } @@ -2334,8 +2355,8 @@ static int pl011_register_port(struct uart_amba_port *uap) int ret; /* Ensure interrupts from this UART are masked and cleared */ - writew(0, uap->port.membase + UART011_IMSC); - writew(0xffff, uap->port.membase + UART011_ICR); + writew(0, uap->port.membase + REG_IMSC); + writew(0xffff, uap->port.membase + REG_ICR); if (!amba_reg.state) { ret = uart_register_driver(&amba_reg); -- cgit v1.3-6-gb490 From 7b753f318d1456c8e7740f3bd96d1dbb362d5449 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Fri, 31 Jul 2015 15:49:16 +0800 Subject: uart: pl011: Introduce register accessor Introduce register accessor to ease loop up table access in later patch. Signed-off-by: Jun Nie Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 263 +++++++++++++++++++++------------------- 1 file changed, 141 insertions(+), 122 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index ee57e2bee9a1..29a291d3bf24 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -85,23 +85,26 @@ struct vendor_data { unsigned int (*get_fifosize)(struct amba_device *dev); }; +/* Max address offset of register in use is 0x48 */ +#define REG_NR (0x48 >> 2) +#define IDX(x) (x >> 2) enum reg_idx { - REG_DR = UART01x_DR, - REG_RSR = UART01x_RSR, - REG_ST_DMAWM = ST_UART011_DMAWM, - REG_FR = UART01x_FR, - REG_ST_LCRH_RX = ST_UART011_LCRH_RX, - REG_ILPR = UART01x_ILPR, - REG_IBRD = UART011_IBRD, - REG_FBRD = UART011_FBRD, - REG_LCRH = UART011_LCRH, - REG_CR = UART011_CR, - REG_IFLS = UART011_IFLS, - REG_IMSC = UART011_IMSC, - REG_RIS = UART011_RIS, - REG_MIS = UART011_MIS, - REG_ICR = UART011_ICR, - REG_DMACR = UART011_DMACR, + REG_DR = IDX(UART01x_DR), + REG_RSR = IDX(UART01x_RSR), + REG_ST_DMAWM = IDX(ST_UART011_DMAWM), + REG_FR = IDX(UART01x_FR), + REG_ST_LCRH_RX = IDX(ST_UART011_LCRH_RX), + REG_ILPR = IDX(UART01x_ILPR), + REG_IBRD = IDX(UART011_IBRD), + REG_FBRD = IDX(UART011_FBRD), + REG_LCRH = IDX(UART011_LCRH), + REG_CR = IDX(UART011_CR), + REG_IFLS = IDX(UART011_IFLS), + REG_IMSC = IDX(UART011_IMSC), + REG_RIS = IDX(UART011_RIS), + REG_MIS = IDX(UART011_MIS), + REG_ICR = IDX(UART011_ICR), + REG_DMACR = IDX(UART011_DMACR), }; static unsigned int get_fifosize_arm(struct amba_device *dev) @@ -203,6 +206,24 @@ struct uart_amba_port { #endif }; +static unsigned int pl011_readw(struct uart_amba_port *uap, int index) +{ + WARN_ON(index > REG_NR); + return readw_relaxed(uap->port.membase + (index << 2)); +} + +static void pl011_writew(struct uart_amba_port *uap, int val, int index) +{ + WARN_ON(index > REG_NR); + writew_relaxed(val, uap->port.membase + (index << 2)); +} + +static void pl011_writeb(struct uart_amba_port *uap, u8 val, int index) +{ + WARN_ON(index > REG_NR); + writeb_relaxed(val, uap->port.membase + (index << 2)); +} + /* * Reads up to 256 characters from the FIFO or until it's empty and * inserts them into the TTY layer. Returns the number of characters @@ -215,12 +236,12 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) int fifotaken = 0; while (max_count--) { - status = readw(uap->port.membase + REG_FR); + status = pl011_readw(uap, REG_FR); if (status & UART01x_FR_RXFE) break; /* Take chars from the FIFO and update status */ - ch = readw(uap->port.membase + REG_DR) | + ch = pl011_readw(uap, REG_DR) | UART_DUMMY_DR_RX; flag = TTY_NORMAL; uap->port.icount.rx++; @@ -457,7 +478,7 @@ static void pl011_dma_tx_callback(void *data) dmacr = uap->dmacr; uap->dmacr = dmacr & ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); /* * If TX DMA was disabled, it means that we've stopped the DMA for @@ -571,7 +592,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) dma_dev->device_issue_pending(chan); uap->dmacr |= UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); uap->dmatx.queued = true; /* @@ -607,9 +628,9 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap) */ if (uap->dmatx.queued) { uap->dmacr |= UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); return true; } @@ -619,7 +640,7 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap) */ if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); return true; } return false; @@ -633,7 +654,7 @@ static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) { if (uap->dmatx.queued) { uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); } } @@ -659,14 +680,12 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) if (!uap->dmatx.queued) { if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + - REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); } else ret = false; } else if (!(uap->dmacr & UART011_TXDMAE)) { uap->dmacr |= UART011_TXDMAE; - writew(uap->dmacr, - uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); } return ret; } @@ -677,9 +696,9 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) */ dmacr = uap->dmacr; uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); - if (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) { + if (pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) { /* * No space in the FIFO, so enable the transmit interrupt * so we know when there is space. Note that once we've @@ -688,13 +707,13 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) return false; } - writew(uap->port.x_char, uap->port.membase + REG_DR); + pl011_writew(uap, uap->port.x_char, REG_DR); uap->port.icount.tx++; uap->port.x_char = 0; /* Success - restore the DMA state */ uap->dmacr = dmacr; - writew(dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, dmacr, REG_DMACR); return true; } @@ -722,7 +741,7 @@ __acquires(&uap->port.lock) DMA_TO_DEVICE); uap->dmatx.queued = false; uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); } } @@ -762,11 +781,11 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap) dma_async_issue_pending(rxchan); uap->dmacr |= UART011_RXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); uap->dmarx.running = true; uap->im &= ~UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); return 0; } @@ -824,8 +843,9 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, */ if (dma_count == pending && readfifo) { /* Clear any error flags */ - writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, - uap->port.membase + REG_ICR); + pl011_writew(uap, + UART011_OEIS | UART011_BEIS | UART011_PEIS + | UART011_FEIS, REG_ICR); /* * If we read all the DMA'd characters, and we had an @@ -873,7 +893,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap) /* Disable RX DMA - incoming data will wait in the FIFO */ uap->dmacr &= ~UART011_RXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); uap->dmarx.running = false; pending = sgbuf->sg.length - state.residue; @@ -893,7 +913,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap) dev_dbg(uap->port.dev, "could not retrigger RX DMA job " "fall back to interrupt mode\n"); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); } } @@ -941,7 +961,7 @@ static void pl011_dma_rx_callback(void *data) dev_dbg(uap->port.dev, "could not retrigger RX DMA job " "fall back to interrupt mode\n"); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); } } @@ -954,7 +974,7 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap) { /* FIXME. Just disable the DMA enable */ uap->dmacr &= ~UART011_RXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); } /* @@ -998,7 +1018,7 @@ static void pl011_dma_rx_poll(unsigned long args) spin_lock_irqsave(&uap->port.lock, flags); pl011_dma_rx_stop(uap); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); spin_unlock_irqrestore(&uap->port.lock, flags); uap->dmarx.running = false; @@ -1060,7 +1080,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap) skip_rx: /* Turn on DMA error (RX/TX will be enabled on demand) */ uap->dmacr |= UART011_DMAONERR; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); /* * ST Micro variants has some specific dma burst threshold @@ -1068,9 +1088,9 @@ skip_rx: * be issued above/below 16 bytes. */ if (uap->vendor->dma_threshold) - writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16, - uap->port.membase + REG_ST_DMAWM); - + pl011_writew(uap, + ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16, + REG_ST_DMAWM); if (uap->using_rx_dma) { if (pl011_dma_rx_trigger_dma(uap)) @@ -1095,12 +1115,12 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) return; /* Disable RX and TX DMA */ - while (readw(uap->port.membase + REG_FR) & UART01x_FR_BUSY) + while (pl011_readw(uap, REG_FR) & UART01x_FR_BUSY) barrier(); spin_lock_irq(&uap->port.lock); uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); - writew(uap->dmacr, uap->port.membase + REG_DMACR); + pl011_writew(uap, uap->dmacr, REG_DMACR); spin_unlock_irq(&uap->port.lock); if (uap->using_tx_dma) { @@ -1201,7 +1221,7 @@ static void pl011_stop_tx(struct uart_port *port) container_of(port, struct uart_amba_port, port); uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); pl011_dma_tx_stop(uap); } @@ -1211,7 +1231,7 @@ static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq); static void pl011_start_tx_pio(struct uart_amba_port *uap) { uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); pl011_tx_chars(uap, false); } @@ -1231,7 +1251,7 @@ static void pl011_stop_rx(struct uart_port *port) uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| UART011_PEIM|UART011_BEIM|UART011_OEIM); - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); pl011_dma_rx_stop(uap); } @@ -1242,7 +1262,7 @@ static void pl011_enable_ms(struct uart_port *port) container_of(port, struct uart_amba_port, port); uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM; - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); } static void pl011_rx_chars(struct uart_amba_port *uap) @@ -1262,7 +1282,7 @@ __acquires(&uap->port.lock) dev_dbg(uap->port.dev, "could not trigger RX DMA job " "fall back to interrupt mode again\n"); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); } else { #ifdef CONFIG_DMA_ENGINE /* Start Rx DMA poll */ @@ -1283,10 +1303,10 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, bool from_irq) { if (unlikely(!from_irq) && - readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) + pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) return false; /* unable to transmit character */ - writew(c, uap->port.membase + REG_DR); + pl011_writew(uap, c, REG_DR); uap->port.icount.tx++; return true; @@ -1333,7 +1353,7 @@ static void pl011_modem_status(struct uart_amba_port *uap) { unsigned int status, delta; - status = readw(uap->port.membase + REG_FR) & UART01x_FR_MODEM_ANY; + status = pl011_readw(uap, REG_FR) & UART01x_FR_MODEM_ANY; delta = status ^ uap->old_status; uap->old_status = status; @@ -1361,15 +1381,15 @@ static void check_apply_cts_event_workaround(struct uart_amba_port *uap) return; /* workaround to make sure that all bits are unlocked.. */ - writew(0x00, uap->port.membase + REG_ICR); + pl011_writew(uap, 0x00, REG_ICR); /* * WA: introduce 26ns(1 uart clk) delay before W1C; * single apb access will incur 2 pclk(133.12Mhz) delay, * so add 2 dummy reads */ - dummy_read = readw(uap->port.membase + REG_ICR); - dummy_read = readw(uap->port.membase + REG_ICR); + dummy_read = pl011_readw(uap, REG_ICR); + dummy_read = pl011_readw(uap, REG_ICR); } static irqreturn_t pl011_int(int irq, void *dev_id) @@ -1381,15 +1401,13 @@ static irqreturn_t pl011_int(int irq, void *dev_id) int handled = 0; spin_lock_irqsave(&uap->port.lock, flags); - imsc = readw(uap->port.membase + REG_IMSC); - status = readw(uap->port.membase + REG_RIS) & imsc; + imsc = pl011_readw(uap, REG_IMSC); + status = pl011_readw(uap, REG_RIS) & imsc; if (status) { do { check_apply_cts_event_workaround(uap); - - writew(status & ~(UART011_TXIS|UART011_RTIS| - UART011_RXIS), - uap->port.membase + REG_ICR); + pl011_writew(uap, status & ~(UART011_TXIS|UART011_RTIS| + UART011_RXIS), REG_ICR); if (status & (UART011_RTIS|UART011_RXIS)) { if (pl011_dma_rx_running(uap)) @@ -1406,7 +1424,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (pass_counter-- == 0) break; - status = readw(uap->port.membase + REG_RIS) & imsc; + status = pl011_readw(uap, REG_RIS) & imsc; } while (status != 0); handled = 1; } @@ -1420,7 +1438,7 @@ static unsigned int pl011_tx_empty(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - unsigned int status = readw(uap->port.membase + REG_FR); + unsigned int status = pl011_readw(uap, REG_FR); return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; } @@ -1429,7 +1447,7 @@ static unsigned int pl011_get_mctrl(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); unsigned int result = 0; - unsigned int status = readw(uap->port.membase + REG_FR); + unsigned int status = pl011_readw(uap, REG_FR); #define TIOCMBIT(uartbit, tiocmbit) \ if (status & uartbit) \ @@ -1449,7 +1467,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) container_of(port, struct uart_amba_port, port); unsigned int cr; - cr = readw(uap->port.membase + REG_CR); + cr = pl011_readw(uap, REG_CR); #define TIOCMBIT(tiocmbit, uartbit) \ if (mctrl & tiocmbit) \ @@ -1469,7 +1487,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) } #undef TIOCMBIT - writew(cr, uap->port.membase + REG_CR); + pl011_writew(uap, cr, REG_CR); } static void pl011_break_ctl(struct uart_port *port, int break_state) @@ -1480,12 +1498,12 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) unsigned int lcr_h; spin_lock_irqsave(&uap->port.lock, flags); - lcr_h = readw(uap->port.membase + uap->lcrh_tx); + lcr_h = pl011_readw(uap, uap->lcrh_tx); if (break_state == -1) lcr_h |= UART01x_LCRH_BRK; else lcr_h &= ~UART01x_LCRH_BRK; - writew(lcr_h, uap->port.membase + uap->lcrh_tx); + pl011_writew(uap, lcr_h, uap->lcrh_tx); spin_unlock_irqrestore(&uap->port.lock, flags); } @@ -1495,9 +1513,8 @@ static void pl011_quiesce_irqs(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - unsigned char __iomem *regs = uap->port.membase; - writew(readw(regs + REG_MIS), regs + REG_ICR); + pl011_writew(uap, pl011_readw(uap, REG_MIS), REG_ICR); /* * There is no way to clear TXIM as this is "ready to transmit IRQ", so * we simply mask it. start_tx() will unmask it. @@ -1511,7 +1528,7 @@ static void pl011_quiesce_irqs(struct uart_port *port) * (including tx queue), so we're also fine with start_tx()'s caller * side. */ - writew(readw(regs + REG_IMSC) & ~UART011_TXIM, regs + REG_IMSC); + pl011_writew(uap, pl011_readw(uap, REG_IMSC) & ~UART011_TXIM, REG_IMSC); } static int pl011_get_poll_char(struct uart_port *port) @@ -1526,11 +1543,11 @@ static int pl011_get_poll_char(struct uart_port *port) */ pl011_quiesce_irqs(port); - status = readw(uap->port.membase + REG_FR); + status = pl011_readw(uap, REG_FR); if (status & UART01x_FR_RXFE) return NO_POLL_CHAR; - return readw(uap->port.membase + REG_DR); + return pl011_readw(uap, REG_DR); } static void pl011_put_poll_char(struct uart_port *port, @@ -1539,10 +1556,10 @@ static void pl011_put_poll_char(struct uart_port *port, struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - while (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) + while (pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) barrier(); - writew(ch, uap->port.membase + REG_DR); + pl011_writew(uap, ch, REG_DR); } #endif /* CONFIG_CONSOLE_POLL */ @@ -1566,15 +1583,15 @@ static int pl011_hwinit(struct uart_port *port) uap->port.uartclk = clk_get_rate(uap->clk); /* Clear pending error and receive interrupts */ - writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS | - UART011_RTIS | UART011_RXIS, uap->port.membase + REG_ICR); + pl011_writew(uap, UART011_OEIS | UART011_BEIS | UART011_PEIS | + UART011_FEIS | UART011_RTIS | UART011_RXIS, REG_ICR); /* * Save interrupts enable mask, and enable RX interrupts in case if * the interrupt is used for NMI entry. */ - uap->im = readw(uap->port.membase + REG_IMSC); - writew(UART011_RTIM | UART011_RXIM, uap->port.membase + REG_IMSC); + uap->im = pl011_readw(uap, REG_IMSC); + pl011_writew(uap, UART011_RTIM | UART011_RXIM, REG_IMSC); if (dev_get_platdata(uap->port.dev)) { struct amba_pl011_data *plat; @@ -1588,7 +1605,7 @@ static int pl011_hwinit(struct uart_port *port) static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) { - writew(lcr_h, uap->port.membase + uap->lcrh_rx); + pl011_writew(uap, lcr_h, uap->lcrh_rx); if (uap->lcrh_rx != uap->lcrh_tx) { int i; /* @@ -1596,14 +1613,14 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) * to get this delay write read only register 10 times */ for (i = 0; i < 10; ++i) - writew(0xff, uap->port.membase + REG_MIS); - writew(lcr_h, uap->port.membase + uap->lcrh_tx); + pl011_writew(uap, 0xff, REG_MIS); + pl011_writew(uap, lcr_h, uap->lcrh_tx); } } static int pl011_allocate_irq(struct uart_amba_port *uap) { - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); } @@ -1618,12 +1635,11 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap) spin_lock_irq(&uap->port.lock); /* Clear out any spuriously appearing RX interrupts */ - writew(UART011_RTIS | UART011_RXIS, - uap->port.membase + REG_ICR); + pl011_writew(uap, UART011_RTIS | UART011_RXIS, REG_ICR); uap->im = UART011_RTIM; if (!pl011_dma_rx_running(uap)) uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + pl011_writew(uap, uap->im, REG_IMSC); spin_unlock_irq(&uap->port.lock); } @@ -1642,21 +1658,21 @@ static int pl011_startup(struct uart_port *port) if (retval) goto clk_dis; - writew(uap->vendor->ifls, uap->port.membase + REG_IFLS); + pl011_writew(uap, uap->vendor->ifls, REG_IFLS); spin_lock_irq(&uap->port.lock); /* restore RTS and DTR */ cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; - writew(cr, uap->port.membase + REG_CR); + pl011_writew(uap, cr, REG_CR); spin_unlock_irq(&uap->port.lock); /* * initialise the old status of the modem signals */ - uap->old_status = readw(uap->port.membase + REG_FR) & + uap->old_status = pl011_readw(uap, REG_FR) & UART01x_FR_MODEM_ANY; /* Startup DMA */ @@ -1696,11 +1712,11 @@ static int sbsa_uart_startup(struct uart_port *port) static void pl011_shutdown_channel(struct uart_amba_port *uap, unsigned int lcrh) { - unsigned long val; + unsigned long val; - val = readw(uap->port.membase + lcrh); - val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); - writew(val, uap->port.membase + lcrh); + val = pl011_readw(uap, lcrh); + val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); + pl011_writew(uap, val, lcrh); } /* @@ -1714,11 +1730,11 @@ static void pl011_disable_uart(struct uart_amba_port *uap) uap->autorts = false; spin_lock_irq(&uap->port.lock); - cr = readw(uap->port.membase + REG_CR); + cr = pl011_readw(uap, REG_CR); uap->old_cr = cr; cr &= UART011_CR_RTS | UART011_CR_DTR; cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - writew(cr, uap->port.membase + REG_CR); + pl011_writew(uap, cr, REG_CR); spin_unlock_irq(&uap->port.lock); /* @@ -1735,8 +1751,8 @@ static void pl011_disable_interrupts(struct uart_amba_port *uap) /* mask all interrupts and clear all pending ones */ uap->im = 0; - writew(uap->im, uap->port.membase + REG_IMSC); - writew(0xffff, uap->port.membase + REG_ICR); + pl011_writew(uap, uap->im, REG_IMSC); + pl011_writew(0xffff, REG_ICR); spin_unlock_irq(&uap->port.lock); } @@ -1888,8 +1904,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, pl011_enable_ms(port); /* first, disable everything */ - old_cr = readw(port->membase + REG_CR); - writew(0, port->membase + REG_CR); + old_cr = pl011_readw(uap, REG_CR); + pl011_writew(uap, 0, REG_CR); if (termios->c_cflag & CRTSCTS) { if (old_cr & UART011_CR_RTS) @@ -1922,8 +1938,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, quot -= 2; } /* Set baud rate */ - writew(quot & 0x3f, port->membase + REG_FBRD); - writew(quot >> 6, port->membase + REG_IBRD); + pl011_writew(uap, quot & 0x3f, REG_FBRD); + pl011_writew(uap, quot >> 6, REG_IBRD); /* * ----------v----------v----------v----------v----- @@ -1932,7 +1948,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, * ----------^----------^----------^----------^----- */ pl011_write_lcr_h(uap, lcr_h); - writew(old_cr, port->membase + REG_CR); + pl011_writew(uap, old_cr, REG_CR); spin_unlock_irqrestore(&port->lock, flags); } @@ -2073,9 +2089,9 @@ static void pl011_console_putchar(struct uart_port *port, int ch) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - while (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) + while (pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) barrier(); - writew(ch, uap->port.membase + REG_DR); + pl011_writew(uap, ch, REG_DR); } static void @@ -2100,10 +2116,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) * First save the CR then disable the interrupts */ if (!uap->vendor->always_enabled) { - old_cr = readw(uap->port.membase + REG_CR); + old_cr = pl011_readw(uap, REG_CR); new_cr = old_cr & ~UART011_CR_CTSEN; new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - writew(new_cr, uap->port.membase + REG_CR); + pl011_writew(uap, new_cr, REG_CR); } uart_console_write(&uap->port, s, count, pl011_console_putchar); @@ -2113,10 +2129,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) * and restore the TCR */ do { - status = readw(uap->port.membase + REG_FR); + status = pl011_readw(uap, REG_FR); } while (status & UART01x_FR_BUSY); if (!uap->vendor->always_enabled) - writew(old_cr, uap->port.membase + REG_CR); + pl011_writew(uap, old_cr, REG_CR); if (locked) spin_unlock(&uap->port.lock); @@ -2129,10 +2145,10 @@ static void __init pl011_console_get_options(struct uart_amba_port *uap, int *baud, int *parity, int *bits) { - if (readw(uap->port.membase + REG_CR) & UART01x_CR_UARTEN) { + if (pl011_readw(uap, REG_CR) & UART01x_CR_UARTEN) { unsigned int lcr_h, ibrd, fbrd; - lcr_h = readw(uap->port.membase + uap->lcrh_tx); + lcr_h = pl011_readw(uap, uap->lcrh_tx); *parity = 'n'; if (lcr_h & UART01x_LCRH_PEN) { @@ -2147,13 +2163,13 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, else *bits = 8; - ibrd = readw(uap->port.membase + REG_IBRD); - fbrd = readw(uap->port.membase + REG_FBRD); + ibrd = pl011_readw(uap, REG_IBRD); + fbrd = pl011_readw(uap, REG_FBRD); *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); if (uap->vendor->oversampling) { - if (readw(uap->port.membase + REG_CR) + if (pl011_readw(uap, REG_CR) & ST_UART011_CR_OVSFACT) *baud *= 2; } @@ -2225,10 +2241,13 @@ static struct console amba_console = { static void pl011_putc(struct uart_port *port, int c) { - while (readl(port->membase + REG_FR) & UART01x_FR_TXFF) + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + + while (pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) ; - writeb(c, port->membase + REG_DR); - while (readl(port->membase + REG_FR) & UART01x_FR_BUSY) + pl011_writeb(uap, c, REG_DR); + while (pl011_readw(uap, REG_FR) & UART01x_FR_BUSY) ; } @@ -2355,8 +2374,8 @@ static int pl011_register_port(struct uart_amba_port *uap) int ret; /* Ensure interrupts from this UART are masked and cleared */ - writew(0, uap->port.membase + REG_IMSC); - writew(0xffff, uap->port.membase + REG_ICR); + pl011_writew(uap, 0, REG_IMSC); + pl011_writew(uap, 0xffff, REG_ICR); if (!amba_reg.state) { ret = uart_register_driver(&amba_reg); -- cgit v1.3-6-gb490 From 2c096a9eedc6841d3610545f4e6c3d72bd0962be Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Fri, 31 Jul 2015 15:49:17 +0800 Subject: uart: pl011: Introduce register look up table Introduce register look up table as different SOC venders may have different register offset for the some register. Signed-off-by: Jun Nie Reviewed-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 55 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 29a291d3bf24..e1f3bd5afad6 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -76,6 +76,7 @@ struct vendor_data { unsigned int ifls; unsigned int lcrh_tx; unsigned int lcrh_rx; + u16 *reg_lut; bool oversampling; bool dma_threshold; bool cts_event_workaround; @@ -107,6 +108,25 @@ enum reg_idx { REG_DMACR = IDX(UART011_DMACR), }; +static u16 arm_reg[] = { + [REG_DR] = UART01x_DR, + [REG_RSR] = UART01x_RSR, + [REG_ST_DMAWM] = ~0, + [REG_FR] = UART01x_FR, + [REG_ST_LCRH_RX] = ~0, + [REG_ILPR] = UART01x_ILPR, + [REG_IBRD] = UART011_IBRD, + [REG_FBRD] = UART011_FBRD, + [REG_LCRH] = UART011_LCRH, + [REG_CR] = UART011_CR, + [REG_IFLS] = UART011_IFLS, + [REG_IMSC] = UART011_IMSC, + [REG_RIS] = UART011_RIS, + [REG_MIS] = UART011_MIS, + [REG_ICR] = UART011_ICR, + [REG_DMACR] = UART011_DMACR, +}; + static unsigned int get_fifosize_arm(struct amba_device *dev) { return amba_rev(dev) < 3 ? 16 : 32; @@ -116,6 +136,7 @@ static struct vendor_data vendor_arm = { .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, .lcrh_tx = REG_LCRH, .lcrh_rx = REG_LCRH, + .reg_lut = arm_reg, .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, @@ -125,6 +146,7 @@ static struct vendor_data vendor_arm = { }; static struct vendor_data vendor_sbsa = { + .reg_lut = arm_reg, .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, @@ -132,6 +154,25 @@ static struct vendor_data vendor_sbsa = { .fixed_options = true, }; +static u16 st_reg[] = { + [REG_DR] = UART01x_DR, + [REG_RSR] = UART01x_RSR, + [REG_ST_DMAWM] = ST_UART011_DMAWM, + [REG_FR] = UART01x_FR, + [REG_ST_LCRH_RX] = ST_UART011_LCRH_RX, + [REG_ILPR] = UART01x_ILPR, + [REG_IBRD] = UART011_IBRD, + [REG_FBRD] = UART011_FBRD, + [REG_LCRH] = UART011_LCRH, + [REG_CR] = UART011_CR, + [REG_IFLS] = UART011_IFLS, + [REG_IMSC] = UART011_IMSC, + [REG_RIS] = UART011_RIS, + [REG_MIS] = UART011_MIS, + [REG_ICR] = UART011_ICR, + [REG_DMACR] = UART011_DMACR, +}; + static unsigned int get_fifosize_st(struct amba_device *dev) { return 64; @@ -141,6 +182,7 @@ static struct vendor_data vendor_st = { .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, .lcrh_tx = REG_LCRH, .lcrh_rx = REG_ST_LCRH_RX, + .reg_lut = st_reg, .oversampling = true, .dma_threshold = true, .cts_event_workaround = true, @@ -186,6 +228,7 @@ struct uart_amba_port { struct uart_port port; struct clk *clk; const struct vendor_data *vendor; + u16 *reg_lut; unsigned int dmacr; /* dma control reg */ unsigned int im; /* interrupt mask */ unsigned int old_status; @@ -209,19 +252,19 @@ struct uart_amba_port { static unsigned int pl011_readw(struct uart_amba_port *uap, int index) { WARN_ON(index > REG_NR); - return readw_relaxed(uap->port.membase + (index << 2)); + return readw_relaxed(uap->port.membase + uap->reg_lut[index]); } static void pl011_writew(struct uart_amba_port *uap, int val, int index) { WARN_ON(index > REG_NR); - writew_relaxed(val, uap->port.membase + (index << 2)); + writew_relaxed(val, uap->port.membase + uap->reg_lut[index]); } static void pl011_writeb(struct uart_amba_port *uap, u8 val, int index) { WARN_ON(index > REG_NR); - writeb_relaxed(val, uap->port.membase + (index << 2)); + writeb_relaxed(val, uap->port.membase + uap->reg_lut[index]); } /* @@ -324,7 +367,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev); struct device *dev = uap->port.dev; struct dma_slave_config tx_conf = { - .dst_addr = uap->port.mapbase + REG_DR, + .dst_addr = uap->port.mapbase + uap->reg_lut[REG_DR], .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, .direction = DMA_MEM_TO_DEV, .dst_maxburst = uap->fifosize >> 1, @@ -379,7 +422,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) if (chan) { struct dma_slave_config rx_conf = { - .src_addr = uap->port.mapbase + REG_DR, + .src_addr = uap->port.mapbase + uap->reg_lut[REG_DR], .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, .direction = DMA_DEV_TO_MEM, .src_maxburst = uap->fifosize >> 2, @@ -2413,6 +2456,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) return PTR_ERR(uap->clk); uap->vendor = vendor; + uap->reg_lut = vendor->reg_lut; uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_tx = vendor->lcrh_tx; uap->fifosize = vendor->get_fifosize(dev); @@ -2494,6 +2538,7 @@ static int sbsa_uart_probe(struct platform_device *pdev) return -ENOMEM; uap->vendor = &vendor_sbsa; + uap->reg_lut = vendor_sbsa.reg_lut; uap->fifosize = 32; uap->port.irq = platform_get_irq(pdev, 0); uap->port.ops = &sbsa_uart_pops; -- cgit v1.3-6-gb490 From 09dcc7dfc05b31bf0bbcd1511cd1a2644908d5c8 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Fri, 31 Jul 2015 15:49:18 +0800 Subject: uart: pl011: Improve LCRH register access decision Improve LCRH register access decision as ARM PL011 lcrh register serve as both TX and RX, while other SOC may implement TX and RX function with separated register. Signed-off-by: Jun Nie Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index e1f3bd5afad6..017443d092c1 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -249,6 +249,11 @@ struct uart_amba_port { #endif }; +static bool is_implemented(struct uart_amba_port *uap, unsigned int reg) +{ + return uap->reg_lut[reg] != (u16)~0; +} + static unsigned int pl011_readw(struct uart_amba_port *uap, int index) { WARN_ON(index > REG_NR); @@ -1649,7 +1654,7 @@ static int pl011_hwinit(struct uart_port *port) static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) { pl011_writew(uap, lcr_h, uap->lcrh_rx); - if (uap->lcrh_rx != uap->lcrh_tx) { + if (is_implemented(uap, REG_ST_LCRH_RX)) { int i; /* * Wait 10 PCLKs before writing LCRH_TX register, @@ -1784,7 +1789,7 @@ static void pl011_disable_uart(struct uart_amba_port *uap) * disable break condition and fifos */ pl011_shutdown_channel(uap, uap->lcrh_rx); - if (uap->lcrh_rx != uap->lcrh_tx) + if (is_implemented(uap, REG_ST_LCRH_RX)) pl011_shutdown_channel(uap, uap->lcrh_tx); } -- cgit v1.3-6-gb490 From 8cd90e50d1408c65c355084b1c7f8f9085f49c6b Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Fri, 31 Jul 2015 15:49:19 +0800 Subject: uart: pl011: Add support to ZTE ZX296702 uart Support ZTE uart with some registers differing offset. Probe as platform device for not AMBA IP ID is available on ZTE uart. Signed-off-by: Jun Nie Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 4 +- drivers/tty/serial/amba-pl011.c | 195 +++++++++++++++++++++++++++++++++++++--- include/linux/amba/serial.h | 14 +++ 3 files changed, 197 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 687b1ea294b7..ed299b9e6375 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -47,12 +47,12 @@ config SERIAL_AMBA_PL010_CONSOLE config SERIAL_AMBA_PL011 tristate "ARM AMBA PL011 serial port support" - depends on ARM_AMBA + depends on ARM_AMBA || SOC_ZX296702 select SERIAL_CORE help This selects the ARM(R) AMBA(R) PrimeCell PL011 UART. If you have an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M - here. + here. Say Y or M if you have SOC_ZX296702. If unsure, say N. diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 017443d092c1..2af09ab153b6 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -74,6 +74,10 @@ /* There is by now at least one vendor with differing details, so handle it */ struct vendor_data { unsigned int ifls; + unsigned int fr_busy; + unsigned int fr_dsr; + unsigned int fr_cts; + unsigned int fr_ri; unsigned int lcrh_tx; unsigned int lcrh_rx; u16 *reg_lut; @@ -127,6 +131,7 @@ static u16 arm_reg[] = { [REG_DMACR] = UART011_DMACR, }; +#ifdef CONFIG_ARM_AMBA static unsigned int get_fifosize_arm(struct amba_device *dev) { return amba_rev(dev) < 3 ? 16 : 32; @@ -134,6 +139,10 @@ static unsigned int get_fifosize_arm(struct amba_device *dev) static struct vendor_data vendor_arm = { .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, + .fr_busy = UART01x_FR_BUSY, + .fr_dsr = UART01x_FR_DSR, + .fr_cts = UART01x_FR_CTS, + .fr_ri = UART011_FR_RI, .lcrh_tx = REG_LCRH, .lcrh_rx = REG_LCRH, .reg_lut = arm_reg, @@ -144,8 +153,13 @@ static struct vendor_data vendor_arm = { .fixed_options = false, .get_fifosize = get_fifosize_arm, }; +#endif static struct vendor_data vendor_sbsa = { + .fr_busy = UART01x_FR_BUSY, + .fr_dsr = UART01x_FR_DSR, + .fr_cts = UART01x_FR_CTS, + .fr_ri = UART011_FR_RI, .reg_lut = arm_reg, .oversampling = false, .dma_threshold = false, @@ -154,6 +168,7 @@ static struct vendor_data vendor_sbsa = { .fixed_options = true, }; +#ifdef CONFIG_ARM_AMBA static u16 st_reg[] = { [REG_DR] = UART01x_DR, [REG_RSR] = UART01x_RSR, @@ -180,6 +195,10 @@ static unsigned int get_fifosize_st(struct amba_device *dev) static struct vendor_data vendor_st = { .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, + .fr_busy = UART01x_FR_BUSY, + .fr_dsr = UART01x_FR_DSR, + .fr_cts = UART01x_FR_CTS, + .fr_ri = UART011_FR_RI, .lcrh_tx = REG_LCRH, .lcrh_rx = REG_ST_LCRH_RX, .reg_lut = st_reg, @@ -190,6 +209,43 @@ static struct vendor_data vendor_st = { .fixed_options = false, .get_fifosize = get_fifosize_st, }; +#endif + +#ifdef CONFIG_SOC_ZX296702 +static u16 zte_reg[] = { + [REG_DR] = ZX_UART01x_DR, + [REG_RSR] = UART01x_RSR, + [REG_ST_DMAWM] = ST_UART011_DMAWM, + [REG_FR] = ZX_UART01x_FR, + [REG_ST_LCRH_RX] = ST_UART011_LCRH_RX, + [REG_ILPR] = UART01x_ILPR, + [REG_IBRD] = UART011_IBRD, + [REG_FBRD] = UART011_FBRD, + [REG_LCRH] = ZX_UART011_LCRH_TX, + [REG_CR] = ZX_UART011_CR, + [REG_IFLS] = ZX_UART011_IFLS, + [REG_IMSC] = ZX_UART011_IMSC, + [REG_RIS] = ZX_UART011_RIS, + [REG_MIS] = ZX_UART011_MIS, + [REG_ICR] = ZX_UART011_ICR, + [REG_DMACR] = ZX_UART011_DMACR, +}; + +static struct vendor_data vendor_zte = { + .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, + .fr_busy = ZX_UART01x_FR_BUSY, + .fr_dsr = ZX_UART01x_FR_DSR, + .fr_cts = ZX_UART01x_FR_CTS, + .fr_ri = ZX_UART011_FR_RI, + .lcrh_tx = REG_LCRH, + .lcrh_rx = REG_ST_LCRH_RX, + .reg_lut = zte_reg, + .oversampling = false, + .dma_threshold = false, + .cts_event_workaround = false, + .fixed_options = false, +}; +#endif /* Deals with DMA transactions */ @@ -233,6 +289,10 @@ struct uart_amba_port { unsigned int im; /* interrupt mask */ unsigned int old_status; unsigned int fifosize; /* vendor-specific */ + unsigned int fr_busy; /* vendor-specific */ + unsigned int fr_dsr; /* vendor-specific */ + unsigned int fr_cts; /* vendor-specific */ + unsigned int fr_ri; /* vendor-specific */ unsigned int lcrh_tx; /* vendor-specific */ unsigned int lcrh_rx; /* vendor-specific */ unsigned int old_cr; /* state during shutdown */ @@ -1163,7 +1223,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) return; /* Disable RX and TX DMA */ - while (pl011_readw(uap, REG_FR) & UART01x_FR_BUSY) + while (pl011_readw(uap, REG_FR) & uap->fr_busy) barrier(); spin_lock_irq(&uap->port.lock); @@ -1412,11 +1472,11 @@ static void pl011_modem_status(struct uart_amba_port *uap) if (delta & UART01x_FR_DCD) uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); - if (delta & UART01x_FR_DSR) + if (delta & uap->fr_dsr) uap->port.icount.dsr++; - if (delta & UART01x_FR_CTS) - uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); + if (delta & uap->fr_cts) + uart_handle_cts_change(&uap->port, status & uap->fr_cts); wake_up_interruptible(&uap->port.state->port.delta_msr_wait); } @@ -1487,7 +1547,7 @@ static unsigned int pl011_tx_empty(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); unsigned int status = pl011_readw(uap, REG_FR); - return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; + return status & (uap->fr_busy|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; } static unsigned int pl011_get_mctrl(struct uart_port *port) @@ -1502,9 +1562,9 @@ static unsigned int pl011_get_mctrl(struct uart_port *port) result |= tiocmbit TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR); - TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR); - TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS); - TIOCMBIT(UART011_FR_RI, TIOCM_RNG); + TIOCMBIT(uap->fr_dsr, TIOCM_DSR); + TIOCMBIT(uap->fr_cts, TIOCM_CTS); + TIOCMBIT(uap->fr_ri, TIOCM_RNG); #undef TIOCMBIT return result; } @@ -1720,8 +1780,7 @@ static int pl011_startup(struct uart_port *port) /* * initialise the old status of the modem signals */ - uap->old_status = pl011_readw(uap, REG_FR) & - UART01x_FR_MODEM_ANY; + uap->old_status = pl011_readw(uap, REG_FR) & UART01x_FR_MODEM_ANY; /* Startup DMA */ pl011_dma_startup(uap); @@ -1800,7 +1859,7 @@ static void pl011_disable_interrupts(struct uart_amba_port *uap) /* mask all interrupts and clear all pending ones */ uap->im = 0; pl011_writew(uap, uap->im, REG_IMSC); - pl011_writew(0xffff, REG_ICR); + pl011_writew(uap, 0xffff, REG_ICR); spin_unlock_irq(&uap->port.lock); } @@ -2178,7 +2237,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) */ do { status = pl011_readw(uap, REG_FR); - } while (status & UART01x_FR_BUSY); + } while (status & uap->fr_busy); if (!uap->vendor->always_enabled) pl011_writew(uap, old_cr, REG_CR); @@ -2295,7 +2354,7 @@ static void pl011_putc(struct uart_port *port, int c) while (pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) ; pl011_writeb(uap, c, REG_DR); - while (pl011_readw(uap, REG_FR) & UART01x_FR_BUSY) + while (pl011_readw(uap, REG_FR) & uap->fr_busy) ; } @@ -2441,6 +2500,7 @@ static int pl011_register_port(struct uart_amba_port *uap) return ret; } +#ifdef CONFIG_ARM_AMBA static int pl011_probe(struct amba_device *dev, const struct amba_id *id) { struct uart_amba_port *uap; @@ -2464,6 +2524,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->reg_lut = vendor->reg_lut; uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_tx = vendor->lcrh_tx; + uap->fr_busy = vendor->fr_busy; + uap->fr_dsr = vendor->fr_dsr; + uap->fr_cts = vendor->fr_cts; + uap->fr_ri = vendor->fr_ri; uap->fifosize = vendor->get_fifosize(dev); uap->port.irq = dev->irq[0]; uap->port.ops = &amba_pl011_pops; @@ -2487,6 +2551,67 @@ static int pl011_remove(struct amba_device *dev) pl011_unregister_port(uap); return 0; } +#endif + +#ifdef CONFIG_SOC_ZX296702 +static int zx_uart_probe(struct platform_device *pdev) +{ + struct uart_amba_port *uap; + struct vendor_data *vendor = &vendor_zte; + struct resource *res; + int portnr, ret; + + portnr = pl011_find_free_port(); + if (portnr < 0) + return portnr; + + uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port), + GFP_KERNEL); + if (!uap) { + ret = -ENOMEM; + goto out; + } + + uap->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(uap->clk)) { + ret = PTR_ERR(uap->clk); + goto out; + } + + uap->vendor = vendor; + uap->reg_lut = vendor->reg_lut; + uap->lcrh_rx = vendor->lcrh_rx; + uap->lcrh_tx = vendor->lcrh_tx; + uap->fr_busy = vendor->fr_busy; + uap->fr_dsr = vendor->fr_dsr; + uap->fr_cts = vendor->fr_cts; + uap->fr_ri = vendor->fr_ri; + uap->fifosize = 16; + uap->port.irq = platform_get_irq(pdev, 0); + uap->port.ops = &amba_pl011_pops; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + ret = pl011_setup_port(&pdev->dev, uap, res, portnr); + if (ret) + return ret; + + platform_set_drvdata(pdev, uap); + + return pl011_register_port(uap); +out: + return ret; +} + +static int zx_uart_remove(struct platform_device *pdev) +{ + struct uart_amba_port *uap = platform_get_drvdata(pdev); + + uart_remove_one_port(&amba_reg, &uap->port); + pl011_unregister_port(uap); + return 0; +} +#endif #ifdef CONFIG_PM_SLEEP static int pl011_suspend(struct device *dev) @@ -2544,6 +2669,10 @@ static int sbsa_uart_probe(struct platform_device *pdev) uap->vendor = &vendor_sbsa; uap->reg_lut = vendor_sbsa.reg_lut; + uap->fr_busy = vendor_sbsa.fr_busy; + uap->fr_dsr = vendor_sbsa.fr_dsr; + uap->fr_cts = vendor_sbsa.fr_cts; + uap->fr_ri = vendor_sbsa.fr_ri; uap->fifosize = 32; uap->port.irq = platform_get_irq(pdev, 0); uap->port.ops = &sbsa_uart_pops; @@ -2593,6 +2722,7 @@ static struct platform_driver arm_sbsa_uart_platform_driver = { }, }; +#ifdef CONFIG_ARM_AMBA static struct amba_id pl011_ids[] = { { .id = 0x00041011, @@ -2618,20 +2748,57 @@ static struct amba_driver pl011_driver = { .probe = pl011_probe, .remove = pl011_remove, }; +#endif + +#ifdef CONFIG_SOC_ZX296702 +static const struct of_device_id zx_uart_dt_ids[] = { + { .compatible = "zte,zx296702-uart", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, zx_uart_dt_ids); + +static struct platform_driver zx_uart_driver = { + .driver = { + .name = "zx-uart", + .owner = THIS_MODULE, + .pm = &pl011_dev_pm_ops, + .of_match_table = zx_uart_dt_ids, + }, + .probe = zx_uart_probe, + .remove = zx_uart_remove, +}; +#endif + static int __init pl011_init(void) { + int ret; printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); if (platform_driver_register(&arm_sbsa_uart_platform_driver)) pr_warn("could not register SBSA UART platform driver\n"); - return amba_driver_register(&pl011_driver); + +#ifdef CONFIG_SOC_ZX296702 + ret = platform_driver_register(&zx_uart_driver); + if (ret) + pr_warn("could not register ZX UART platform driver\n"); +#endif + +#ifdef CONFIG_ARM_AMBA + ret = amba_driver_register(&pl011_driver); +#endif + return ret; } static void __exit pl011_exit(void) { platform_driver_unregister(&arm_sbsa_uart_platform_driver); +#ifdef CONFIG_SOC_ZX296702 + platform_driver_unregister(&zx_uart_driver); +#endif +#ifdef CONFIG_ARM_AMBA amba_driver_unregister(&pl011_driver); +#endif } /* diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index 0ddb5c02ad8b..6a0a89ed7f81 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h @@ -33,12 +33,14 @@ #define UART01x_DR 0x00 /* Data read or written from the interface. */ #define UART01x_RSR 0x04 /* Receive status register (Read). */ #define UART01x_ECR 0x04 /* Error clear register (Write). */ +#define ZX_UART01x_DR 0x04 /* Data read or written from the interface. */ #define UART010_LCRH 0x08 /* Line control register, high byte. */ #define ST_UART011_DMAWM 0x08 /* DMA watermark configure register. */ #define UART010_LCRM 0x0C /* Line control register, middle byte. */ #define ST_UART011_TIMEOUT 0x0C /* Timeout period register. */ #define UART010_LCRL 0x10 /* Line control register, low byte. */ #define UART010_CR 0x14 /* Control register. */ +#define ZX_UART01x_FR 0x14 /* Flag register (Read only). */ #define UART01x_FR 0x18 /* Flag register (Read only). */ #define UART010_IIR 0x1C /* Interrupt identification register (Read). */ #define UART010_ICR 0x1C /* Interrupt clear register (Write). */ @@ -49,13 +51,21 @@ #define UART011_LCRH 0x2c /* Line control register. */ #define ST_UART011_LCRH_TX 0x2c /* Tx Line control register. */ #define UART011_CR 0x30 /* Control register. */ +#define ZX_UART011_LCRH_TX 0x30 /* Tx Line control register. */ #define UART011_IFLS 0x34 /* Interrupt fifo level select. */ +#define ZX_UART011_CR 0x34 /* Control register. */ +#define ZX_UART011_IFLS 0x38 /* Interrupt fifo level select. */ #define UART011_IMSC 0x38 /* Interrupt mask. */ #define UART011_RIS 0x3c /* Raw interrupt status. */ #define UART011_MIS 0x40 /* Masked interrupt status. */ +#define ZX_UART011_IMSC 0x40 /* Interrupt mask. */ #define UART011_ICR 0x44 /* Interrupt clear register. */ +#define ZX_UART011_RIS 0x44 /* Raw interrupt status. */ #define UART011_DMACR 0x48 /* DMA control register. */ +#define ZX_UART011_MIS 0x48 /* Masked interrupt status. */ +#define ZX_UART011_ICR 0x4c /* Interrupt clear register. */ #define ST_UART011_XFCR 0x50 /* XON/XOFF control register. */ +#define ZX_UART011_DMACR 0x50 /* DMA control register. */ #define ST_UART011_XON1 0x54 /* XON1 register. */ #define ST_UART011_XON2 0x58 /* XON2 register. */ #define ST_UART011_XOFF1 0x5C /* XON1 register. */ @@ -75,15 +85,19 @@ #define UART01x_RSR_PE 0x02 #define UART01x_RSR_FE 0x01 +#define ZX_UART01x_FR_BUSY 0x300 #define UART011_FR_RI 0x100 #define UART011_FR_TXFE 0x080 #define UART011_FR_RXFF 0x040 #define UART01x_FR_TXFF 0x020 #define UART01x_FR_RXFE 0x010 #define UART01x_FR_BUSY 0x008 +#define ZX_UART01x_FR_DSR 0x008 #define UART01x_FR_DCD 0x004 #define UART01x_FR_DSR 0x002 +#define ZX_UART01x_FR_CTS 0x002 #define UART01x_FR_CTS 0x001 +#define ZX_UART011_FR_RI 0x001 #define UART01x_FR_TMSK (UART01x_FR_TXFF + UART01x_FR_BUSY) #define UART011_CR_CTSEN 0x8000 /* CTS hardware flow control */ -- cgit v1.3-6-gb490 From e92a886bf7841cd163860165db680cfbca5c7f0d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 31 Jul 2015 14:44:22 +0200 Subject: sc16is7xx: save and use per-chip line number In preparation of supporting multiple devices we should save the per-chip line number (0 or 1), because the uart_port line will reflect system-wide uart number and will be offseted for chips other than the first to register. Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 0ecc6a854ec1..b968cc5e09bb 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -312,6 +312,7 @@ struct sc16is7xx_one_config { struct sc16is7xx_one { struct uart_port port; + u8 line; struct kthread_work tx_work; struct kthread_work reg_work; struct sc16is7xx_one_config config; @@ -335,13 +336,20 @@ struct sc16is7xx_port { #define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e))) #define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e))) +static int sc16is7xx_line(struct uart_port *port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + return one->line; +} + static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); unsigned int val = 0; + const u8 line = sc16is7xx_line(port); - regmap_read(s->regmap, - (reg << SC16IS7XX_REG_SHIFT) | port->line, &val); + regmap_read(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, &val); return val; } @@ -349,15 +357,16 @@ static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + const u8 line = sc16is7xx_line(port); - regmap_write(s->regmap, - (reg << SC16IS7XX_REG_SHIFT) | port->line, val); + regmap_write(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, val); } static void sc16is7xx_fifo_read(struct uart_port *port, unsigned int rxlen) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - u8 addr = (SC16IS7XX_RHR_REG << SC16IS7XX_REG_SHIFT) | port->line; + const u8 line = sc16is7xx_line(port); + u8 addr = (SC16IS7XX_RHR_REG << SC16IS7XX_REG_SHIFT) | line; regcache_cache_bypass(s->regmap, true); regmap_raw_read(s->regmap, addr, s->buf, rxlen); @@ -367,7 +376,8 @@ static void sc16is7xx_fifo_read(struct uart_port *port, unsigned int rxlen) static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); - u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | port->line; + const u8 line = sc16is7xx_line(port); + u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | line; regcache_cache_bypass(s->regmap, true); regmap_raw_write(s->regmap, addr, s->buf, to_send); @@ -378,9 +388,9 @@ static void sc16is7xx_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + const u8 line = sc16is7xx_line(port); - regmap_update_bits(s->regmap, - (reg << SC16IS7XX_REG_SHIFT) | port->line, + regmap_update_bits(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, mask, val); } @@ -508,7 +518,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, if (unlikely(rxlen >= sizeof(s->buf))) { dev_warn_ratelimited(port->dev, - "Port %i: Possible RX FIFO overrun: %d\n", + "ttySC%i: Possible RX FIFO overrun: %d\n", port->line, rxlen); port->icount.buf_overrun++; /* Ensure sanity of RX level */ @@ -649,7 +659,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) break; default: dev_err_ratelimited(port->dev, - "Port %i: Unexpected interrupt: %x", + "ttySC%i: Unexpected interrupt: %x", port->line, iir); break; } @@ -1174,6 +1184,7 @@ static int sc16is7xx_probe(struct device *dev, #endif for (i = 0; i < devtype->nr_uart; ++i) { + s->p[i].line = i; /* Initialize port data */ s->p[i].port.line = i; s->p[i].port.dev = dev; -- cgit v1.3-6-gb490 From c64349722d141712d8500b5ad377d3117be46ba8 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 31 Jul 2015 14:44:23 +0200 Subject: sc16is7xx: support multiple devices We currently register the uart driver during device probe which makes it hard to support more than one chip. Move the driver registration to module init/exit time and preallocate space for up to 8 lines (4-8 chips). Reported-by: Michael Allwright Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 73 ++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index b968cc5e09bb..15610cb1f295 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -11,6 +11,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -29,6 +31,7 @@ #include #define SC16IS7XX_NAME "sc16is7xx" +#define SC16IS7XX_MAX_DEVS 8 /* SC16IS7XX register definitions */ #define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */ @@ -319,7 +322,6 @@ struct sc16is7xx_one { }; struct sc16is7xx_port { - struct uart_driver uart; struct sc16is7xx_devtype *devtype; struct regmap *regmap; struct clk *clk; @@ -333,6 +335,14 @@ struct sc16is7xx_port { struct sc16is7xx_one p[0]; }; +static unsigned long sc16is7xx_lines; + +static struct uart_driver sc16is7xx_uart = { + .owner = THIS_MODULE, + .dev_name = "ttySC", + .nr = SC16IS7XX_MAX_DEVS, +}; + #define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e))) #define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e))) @@ -394,6 +404,18 @@ static void sc16is7xx_port_update(struct uart_port *port, u8 reg, mask, val); } +static int sc16is7xx_alloc_line(void) +{ + int i; + + BUILD_BUG_ON(SC16IS7XX_MAX_DEVS > BITS_PER_LONG); + + for (i = 0; i < SC16IS7XX_MAX_DEVS; i++) + if (!test_and_set_bit(i, &sc16is7xx_lines)) + break; + + return i; +} static void sc16is7xx_power(struct uart_port *port, int on) { @@ -671,7 +693,7 @@ static void sc16is7xx_ist(struct kthread_work *ws) struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work); int i; - for (i = 0; i < s->uart.nr; ++i) + for (i = 0; i < s->devtype->nr_uart; ++i) sc16is7xx_port_irq(s, i); } @@ -1144,23 +1166,13 @@ static int sc16is7xx_probe(struct device *dev, s->devtype = devtype; dev_set_drvdata(dev, s); - /* Register UART driver */ - s->uart.owner = THIS_MODULE; - s->uart.dev_name = "ttySC"; - s->uart.nr = devtype->nr_uart; - ret = uart_register_driver(&s->uart); - if (ret) { - dev_err(dev, "Registering UART driver failed\n"); - goto out_clk; - } - init_kthread_worker(&s->kworker); init_kthread_work(&s->irq_work, sc16is7xx_ist); s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker, "sc16is7xx"); if (IS_ERR(s->kworker_task)) { ret = PTR_ERR(s->kworker_task); - goto out_uart; + goto out_clk; } sched_setscheduler(s->kworker_task, SCHED_FIFO, &sched_param); @@ -1186,7 +1198,6 @@ static int sc16is7xx_probe(struct device *dev, for (i = 0; i < devtype->nr_uart; ++i) { s->p[i].line = i; /* Initialize port data */ - s->p[i].port.line = i; s->p[i].port.dev = dev; s->p[i].port.irq = irq; s->p[i].port.type = PORT_SC16IS7XX; @@ -1196,6 +1207,12 @@ static int sc16is7xx_probe(struct device *dev, s->p[i].port.uartclk = freq; s->p[i].port.rs485_config = sc16is7xx_config_rs485; s->p[i].port.ops = &sc16is7xx_ops; + s->p[i].port.line = sc16is7xx_alloc_line(); + if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) { + ret = -ENOMEM; + goto out_ports; + } + /* Disable all interrupts */ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0); /* Disable TX/RX */ @@ -1206,7 +1223,7 @@ static int sc16is7xx_probe(struct device *dev, init_kthread_work(&s->p[i].tx_work, sc16is7xx_tx_proc); init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc); /* Register port */ - uart_add_one_port(&s->uart, &s->p[i].port); + uart_add_one_port(&sc16is7xx_uart, &s->p[i].port); /* Go to suspend mode */ sc16is7xx_power(&s->p[i].port, 0); } @@ -1217,8 +1234,11 @@ static int sc16is7xx_probe(struct device *dev, if (!ret) return 0; - for (i = 0; i < s->uart.nr; i++) - uart_remove_one_port(&s->uart, &s->p[i].port); +out_ports: + for (i--; i >= 0; i--) { + uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, &sc16is7xx_lines); + } #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) @@ -1228,9 +1248,6 @@ out_thread: #endif kthread_stop(s->kworker_task); -out_uart: - uart_unregister_driver(&s->uart); - out_clk: if (!IS_ERR(s->clk)) clk_disable_unprepare(s->clk); @@ -1248,15 +1265,15 @@ static int sc16is7xx_remove(struct device *dev) gpiochip_remove(&s->gpio); #endif - for (i = 0; i < s->uart.nr; i++) { - uart_remove_one_port(&s->uart, &s->p[i].port); + for (i = 0; i < s->devtype->nr_uart; i++) { + uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, &sc16is7xx_lines); sc16is7xx_power(&s->p[i].port, 0); } flush_kthread_worker(&s->kworker); kthread_stop(s->kworker_task); - uart_unregister_driver(&s->uart); if (!IS_ERR(s->clk)) clk_disable_unprepare(s->clk); @@ -1408,7 +1425,14 @@ MODULE_ALIAS("i2c:sc16is7xx"); static int __init sc16is7xx_init(void) { - int ret = 0; + int ret; + + ret = uart_register_driver(&sc16is7xx_uart); + if (ret) { + pr_err("Registering UART driver failed\n"); + return ret; + } + #ifdef CONFIG_SERIAL_SC16IS7XX_I2C ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver); if (ret < 0) { @@ -1437,6 +1461,7 @@ static void __exit sc16is7xx_exit(void) #ifdef CONFIG_SERIAL_SC16IS7XX_SPI spi_unregister_driver(&sc16is7xx_spi_uart_driver); #endif + uart_unregister_driver(&sc16is7xx_uart); } module_exit(sc16is7xx_exit); -- cgit v1.3-6-gb490 From 68be64ca7e2adc4f16077c3b0feb8719f89119bd Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 31 Jul 2015 14:44:24 +0200 Subject: sc16is7xx: constify devtype devtype structures are all declared as const. Compiler does not complain because we cast their pointers to save them in .driver_data. Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sc16is7xx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 15610cb1f295..72ffd0dcab78 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -322,7 +322,7 @@ struct sc16is7xx_one { }; struct sc16is7xx_port { - struct sc16is7xx_devtype *devtype; + const struct sc16is7xx_devtype *devtype; struct regmap *regmap; struct clk *clk; #ifdef CONFIG_GPIOLIB @@ -1131,7 +1131,7 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, #endif static int sc16is7xx_probe(struct device *dev, - struct sc16is7xx_devtype *devtype, + const struct sc16is7xx_devtype *devtype, struct regmap *regmap, int irq, unsigned long flags) { struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 }; @@ -1303,7 +1303,7 @@ static struct regmap_config regcfg = { #ifdef CONFIG_SERIAL_SC16IS7XX_SPI static int sc16is7xx_spi_probe(struct spi_device *spi) { - struct sc16is7xx_devtype *devtype; + const struct sc16is7xx_devtype *devtype; unsigned long flags = 0; struct regmap *regmap; int ret; @@ -1372,7 +1372,7 @@ MODULE_ALIAS("spi:sc16is7xx"); static int sc16is7xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct sc16is7xx_devtype *devtype; + const struct sc16is7xx_devtype *devtype; unsigned long flags = 0; struct regmap *regmap; -- cgit v1.3-6-gb490 From 28eb232f217583e7bece8e9d6b26cf55a694ceae Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 10 Jul 2015 22:13:19 +0800 Subject: dmaengine: ti-dma-crossbar: Fix checking return value of devm_ioremap_resource devm_ioremap_resource returns ERR_PTR on failure. Signed-off-by: Axel Lin Acked-by: Peter Ujfalusi Signed-off-by: Vinod Koul --- drivers/dma/ti-dma-crossbar.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c index 10487d91e60d..5cce8c9d0026 100644 --- a/drivers/dma/ti-dma-crossbar.c +++ b/drivers/dma/ti-dma-crossbar.c @@ -162,12 +162,9 @@ static int ti_dma_xbar_probe(struct platform_device *pdev) xbar->safe_val = (u16)safe_val; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - iomem = devm_ioremap_resource(&pdev->dev, res); - if (!iomem) - return -ENOMEM; + if (IS_ERR(iomem)) + return PTR_ERR(iomem); xbar->iomem = iomem; -- cgit v1.3-6-gb490 From 77a68e56aae141d3e9c740a0ac43362af75d4890 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 20 Jul 2015 10:41:32 +0200 Subject: dmaengine: Add an enum for the dmaengine alignment constraints Most drivers need to set constraints on the buffer alignment for async tx operations. However, even though it is documented, some drivers either use a defined constant that is not matching what the alignment variable expects (like DMA_BUSWIDTH_* constants) or fill the alignment in bytes instead of power of two. Add a new enum for these alignments that matches what the framework expects, and convert the drivers to it. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- drivers/dma/coh901318.c | 2 +- drivers/dma/dma-jz4780.c | 2 +- drivers/dma/edma.c | 2 +- drivers/dma/imx-dma.c | 2 +- drivers/dma/k3dma.c | 3 +-- drivers/dma/mic_x100_dma.h | 2 +- drivers/dma/mmp_pdma.c | 3 +-- drivers/dma/mmp_tdma.c | 3 +-- drivers/dma/ste_dma40.c | 2 +- drivers/dma/sun6i-dma.c | 2 +- drivers/dma/xgene-dma.c | 5 ++--- include/linux/dmaengine.h | 25 ++++++++++++++++++++----- 12 files changed, 32 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index fd22dd36985f..c340ca9bd2b5 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -2730,7 +2730,7 @@ static int __init coh901318_probe(struct platform_device *pdev) * This controller can only access address at even 32bit boundaries, * i.e. 2^2 */ - base->dma_memcpy.copy_align = 2; + base->dma_memcpy.copy_align = DMAENGINE_ALIGN_4_BYTES; err = dma_async_device_register(&base->dma_memcpy); if (err) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 26d2f0e09ea3..c29569ac9e4f 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -775,7 +775,7 @@ static int jz4780_dma_probe(struct platform_device *pdev) dma_cap_set(DMA_CYCLIC, dd->cap_mask); dd->dev = dev; - dd->copy_align = 2; /* 2^2 = 4 byte alignment */ + dd->copy_align = DMAENGINE_ALIGN_4_BYTES; dd->device_alloc_chan_resources = jz4780_dma_alloc_chan_resources; dd->device_free_chan_resources = jz4780_dma_free_chan_resources; dd->device_prep_slave_sg = jz4780_dma_prep_slave_sg; diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 88853af69489..3e5d4f193005 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -1000,7 +1000,7 @@ static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma, * code using dma memcpy must make sure alignment of * length is at dma->copy_align boundary. */ - dma->copy_align = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma->copy_align = DMAENGINE_ALIGN_4_BYTES; INIT_LIST_HEAD(&dma->channels); } diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 139c5676cd74..48d85f8b95fe 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -1187,7 +1187,7 @@ static int __init imxdma_probe(struct platform_device *pdev) platform_set_drvdata(pdev, imxdma); - imxdma->dma_device.copy_align = 2; /* 2^2 = 4 bytes alignment */ + imxdma->dma_device.copy_align = DMAENGINE_ALIGN_4_BYTES; imxdma->dma_device.dev->dma_parms = &imxdma->dma_parms; dma_set_max_seg_size(imxdma->dma_device.dev, 0xffffff); diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index 647e362f01fd..1ba2fd73852d 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -24,7 +24,6 @@ #include "virt-dma.h" #define DRIVER_NAME "k3-dma" -#define DMA_ALIGN 3 #define DMA_MAX_SIZE 0x1ffc #define INT_STAT 0x00 @@ -732,7 +731,7 @@ static int k3_dma_probe(struct platform_device *op) d->slave.device_pause = k3_dma_transfer_pause; d->slave.device_resume = k3_dma_transfer_resume; d->slave.device_terminate_all = k3_dma_terminate_all; - d->slave.copy_align = DMA_ALIGN; + d->slave.copy_align = DMAENGINE_ALIGN_8_BYTES; /* init virtual channel */ d->chans = devm_kzalloc(&op->dev, diff --git a/drivers/dma/mic_x100_dma.h b/drivers/dma/mic_x100_dma.h index f663b0bdd11d..d89982034e68 100644 --- a/drivers/dma/mic_x100_dma.h +++ b/drivers/dma/mic_x100_dma.h @@ -39,7 +39,7 @@ */ #define MIC_DMA_MAX_NUM_CHAN 8 #define MIC_DMA_NUM_CHAN 4 -#define MIC_DMA_ALIGN_SHIFT 6 +#define MIC_DMA_ALIGN_SHIFT DMAENGINE_ALIGN_64_BYTES #define MIC_DMA_ALIGN_BYTES (1 << MIC_DMA_ALIGN_SHIFT) #define MIC_DMA_DESC_RX_SIZE (128 * 1024 - 4) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 462a0229a743..e39457f13d4d 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -72,7 +72,6 @@ #define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */ #define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ -#define PDMA_ALIGNMENT 3 #define PDMA_MAX_DESC_BYTES DCMD_LENGTH struct mmp_pdma_desc_hw { @@ -1071,7 +1070,7 @@ static int mmp_pdma_probe(struct platform_device *op) pdev->device.device_issue_pending = mmp_pdma_issue_pending; pdev->device.device_config = mmp_pdma_config; pdev->device.device_terminate_all = mmp_pdma_terminate_all; - pdev->device.copy_align = PDMA_ALIGNMENT; + pdev->device.copy_align = DMAENGINE_ALIGN_8_BYTES; pdev->device.src_addr_widths = widths; pdev->device.dst_addr_widths = widths; pdev->device.directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM); diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index e683761e0f8f..3df0422607d5 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -100,7 +100,6 @@ enum mmp_tdma_type { PXA910_SQU, }; -#define TDMA_ALIGNMENT 3 #define TDMA_MAX_XFER_BYTES SZ_64K struct mmp_tdma_chan { @@ -695,7 +694,7 @@ static int mmp_tdma_probe(struct platform_device *pdev) tdev->device.device_pause = mmp_tdma_pause_chan; tdev->device.device_resume = mmp_tdma_resume_chan; tdev->device.device_terminate_all = mmp_tdma_terminate_all; - tdev->device.copy_align = TDMA_ALIGNMENT; + tdev->device.copy_align = DMAENGINE_ALIGN_8_BYTES; dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); platform_set_drvdata(pdev, tdev); diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 3c10f034d4b9..750d1b313684 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -2853,7 +2853,7 @@ static void d40_ops_init(struct d40_base *base, struct dma_device *dev) * This controller can only access address at even * 32bit boundaries, i.e. 2^2 */ - dev->copy_align = 2; + dev->copy_align = DMAENGINE_ALIGN_4_BYTES; } if (dma_has_cap(DMA_SG, dev->cap_mask)) diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index 842ff97c2cfb..73e0be6e2100 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -969,7 +969,7 @@ static int sun6i_dma_probe(struct platform_device *pdev) sdc->slave.device_issue_pending = sun6i_dma_issue_pending; sdc->slave.device_prep_slave_sg = sun6i_dma_prep_slave_sg; sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy; - sdc->slave.copy_align = 4; + sdc->slave.copy_align = DMAENGINE_ALIGN_4_BYTES; sdc->slave.device_config = sun6i_dma_config; sdc->slave.device_pause = sun6i_dma_pause; sdc->slave.device_resume = sun6i_dma_resume; diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c index 620fd55ec766..fe87a634b145 100644 --- a/drivers/dma/xgene-dma.c +++ b/drivers/dma/xgene-dma.c @@ -150,7 +150,6 @@ #define XGENE_DMA_PQ_CHANNEL 1 #define XGENE_DMA_MAX_BYTE_CNT 0x4000 /* 16 KB */ #define XGENE_DMA_MAX_64B_DESC_BYTE_CNT 0x14000 /* 80 KB */ -#define XGENE_DMA_XOR_ALIGNMENT 6 /* 64 Bytes */ #define XGENE_DMA_MAX_XOR_SRC 5 #define XGENE_DMA_16K_BUFFER_LEN_CODE 0x0 #define XGENE_DMA_INVALID_LEN_CODE 0x7800000000000000ULL @@ -1740,13 +1739,13 @@ static void xgene_dma_set_caps(struct xgene_dma_chan *chan, if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { dma_dev->device_prep_dma_xor = xgene_dma_prep_xor; dma_dev->max_xor = XGENE_DMA_MAX_XOR_SRC; - dma_dev->xor_align = XGENE_DMA_XOR_ALIGNMENT; + dma_dev->xor_align = DMAENGINE_ALIGN_64_BYTES; } if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) { dma_dev->device_prep_dma_pq = xgene_dma_prep_pq; dma_dev->max_pq = XGENE_DMA_MAX_XOR_SRC; - dma_dev->pq_align = XGENE_DMA_XOR_ALIGNMENT; + dma_dev->pq_align = DMAENGINE_ALIGN_64_BYTES; } } diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index e2f5eb419976..03ed832adbc2 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -584,6 +584,20 @@ struct dma_tx_state { u32 residue; }; +/** + * enum dmaengine_alignment - defines alignment of the DMA async tx + * buffers + */ +enum dmaengine_alignment { + DMAENGINE_ALIGN_1_BYTE = 0, + DMAENGINE_ALIGN_2_BYTES = 1, + DMAENGINE_ALIGN_4_BYTES = 2, + DMAENGINE_ALIGN_8_BYTES = 3, + DMAENGINE_ALIGN_16_BYTES = 4, + DMAENGINE_ALIGN_32_BYTES = 5, + DMAENGINE_ALIGN_64_BYTES = 6, +}; + /** * struct dma_device - info on the entity supplying DMA services * @chancnt: how many DMA channels are supported @@ -645,10 +659,10 @@ struct dma_device { dma_cap_mask_t cap_mask; unsigned short max_xor; unsigned short max_pq; - u8 copy_align; - u8 xor_align; - u8 pq_align; - u8 fill_align; + enum dmaengine_alignment copy_align; + enum dmaengine_alignment xor_align; + enum dmaengine_alignment pq_align; + enum dmaengine_alignment fill_align; #define DMA_HAS_PQ_CONTINUE (1 << 15) int dev_id; @@ -833,7 +847,8 @@ static inline dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc return desc->tx_submit(desc); } -static inline bool dmaengine_check_align(u8 align, size_t off1, size_t off2, size_t len) +static inline bool dmaengine_check_align(enum dmaengine_alignment align, + size_t off1, size_t off2, size_t len) { size_t mask; -- cgit v1.3-6-gb490 From 06210b42f33ea1c29a90f4db2d88be91c511154b Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Sat, 1 Aug 2015 16:08:05 -0700 Subject: Drivers: hv: vmbus: remove hv_synic_free_cpu() call from hv_synic_cleanup() We already have hv_synic_free() which frees all per-cpu pages for all CPUs, let's remove the hv_synic_free_cpu() call from hv_synic_cleanup() so it will be possible to do separate cleanup (writing to MSRs) and final freeing. This is going to be used to assist kexec. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv.c | 2 -- drivers/hv/vmbus_drv.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index d3943bceecc3..5b870424b502 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -530,6 +530,4 @@ void hv_synic_cleanup(void *arg) rdmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64); sctrl.enable = 0; wrmsrl(HV_X64_MSR_SCONTROL, sctrl.as_uint64); - - hv_synic_free_cpu(cpu); } diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index cf204005ee78..00d5158b4ac7 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1120,6 +1120,7 @@ static void __exit vmbus_exit(void) tasklet_kill(hv_context.event_dpc[cpu]); smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); } + hv_synic_free(); acpi_bus_unregister_driver(&vmbus_acpi_driver); hv_cpu_hotplug_quirk(false); } -- cgit v1.3-6-gb490 From 2517281d63a2b09d94aedfb522943617048f337e Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Sat, 1 Aug 2015 16:08:07 -0700 Subject: Drivers: hv: vmbus: add special kexec handler When general-purpose kexec (not kdump) is being performed in Hyper-V guest the newly booted kernel fails with an MCE error coming from the host. It is the same error which was fixed in the "Drivers: hv: vmbus: Implement the protocol for tearing down vmbus state" commit - monitor pages remain special and when they're being written to (as the new kernel doesn't know these pages are special) bad things happen. We need to perform some minimalistic cleanup before booting a new kernel on kexec. To do so we need to register a special machine_ops.shutdown handler to be executed before the native_machine_shutdown(). Registering a shutdown notification handler via the register_reboot_notifier() call is not sufficient as it happens to early for our purposes. machine_ops is not being exported to modules (and I don't think we want to export it) so let's do this in mshyperv.c The minimalistic cleanup consists of cleaning up clockevents, synic MSRs, guest os id MSR, and hypercall MSR. Kdump doesn't require all this stuff as it lives in a separate memory space. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/mshyperv.h | 2 ++ arch/x86/kernel/cpu/mshyperv.c | 24 ++++++++++++++++++++++++ drivers/hv/vmbus_drv.c | 14 ++++++++++++++ 3 files changed, 40 insertions(+) (limited to 'drivers') diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index c163215abb9a..d3db9108346b 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -20,4 +20,6 @@ void hyperv_vector_handler(struct pt_regs *regs); void hv_setup_vmbus_irq(void (*handler)(void)); void hv_remove_vmbus_irq(void); +void hv_setup_kexec_handler(void (*handler)(void)); +void hv_remove_kexec_handler(void); #endif diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index aad4bd84b475..fa483ed4756e 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -28,10 +29,13 @@ #include #include #include +#include struct ms_hyperv_info ms_hyperv; EXPORT_SYMBOL_GPL(ms_hyperv); +static void (*hv_kexec_handler)(void); + #if IS_ENABLED(CONFIG_HYPERV) static void (*vmbus_handler)(void); @@ -67,8 +71,27 @@ void hv_remove_vmbus_irq(void) } EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq); EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq); + +void hv_setup_kexec_handler(void (*handler)(void)) +{ + hv_kexec_handler = handler; +} +EXPORT_SYMBOL_GPL(hv_setup_kexec_handler); + +void hv_remove_kexec_handler(void) +{ + hv_kexec_handler = NULL; +} +EXPORT_SYMBOL_GPL(hv_remove_kexec_handler); #endif +static void hv_machine_shutdown(void) +{ + if (kexec_in_progress && hv_kexec_handler) + hv_kexec_handler(); + native_machine_shutdown(); +} + static uint32_t __init ms_hyperv_platform(void) { u32 eax; @@ -141,6 +164,7 @@ static void __init ms_hyperv_init_platform(void) no_timer_check = 1; #endif + machine_ops.shutdown = hv_machine_shutdown; } const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 00d5158b4ac7..31748a21d8f9 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1060,6 +1060,17 @@ static struct acpi_driver vmbus_acpi_driver = { }, }; +static void hv_kexec_handler(void) +{ + int cpu; + + hv_synic_clockevents_cleanup(); + vmbus_initiate_unload(); + for_each_online_cpu(cpu) + smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); + hv_cleanup(); +}; + static int __init hv_acpi_init(void) { int ret, t; @@ -1092,6 +1103,8 @@ static int __init hv_acpi_init(void) if (ret) goto cleanup; + hv_setup_kexec_handler(hv_kexec_handler); + return 0; cleanup: @@ -1104,6 +1117,7 @@ static void __exit vmbus_exit(void) { int cpu; + hv_remove_kexec_handler(); vmbus_connection.conn_state = DISCONNECTED; hv_synic_clockevents_cleanup(); vmbus_disconnect(); -- cgit v1.3-6-gb490 From d7646eaa7678fe5adc42247b4bdfbe9d9db8c253 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Sat, 1 Aug 2015 16:08:08 -0700 Subject: Drivers: hv: don't do hypercalls when hypercall_page is NULL At the very late stage of kexec a driver (which are not being unloaded) can try to post a message or signal an event. This will crash the kernel as we already did hv_cleanup() and the hypercall page is NULL. Move all common (between 32 and 64 bit code) declarations to the beginning of the do_hypercall() function. Unfortunately we have to write the !hypercall_page check twice to not mix declarations and code. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 5b870424b502..41d8072d61d9 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -93,11 +93,14 @@ static int query_hypervisor_info(void) */ static u64 do_hypercall(u64 control, void *input, void *output) { -#ifdef CONFIG_X86_64 - u64 hv_status = 0; u64 input_address = (input) ? virt_to_phys(input) : 0; u64 output_address = (output) ? virt_to_phys(output) : 0; void *hypercall_page = hv_context.hypercall_page; +#ifdef CONFIG_X86_64 + u64 hv_status = 0; + + if (!hypercall_page) + return (u64)ULLONG_MAX; __asm__ __volatile__("mov %0, %%r8" : : "r" (output_address) : "r8"); __asm__ __volatile__("call *%3" : "=a" (hv_status) : @@ -112,13 +115,13 @@ static u64 do_hypercall(u64 control, void *input, void *output) u32 control_lo = control & 0xFFFFFFFF; u32 hv_status_hi = 1; u32 hv_status_lo = 1; - u64 input_address = (input) ? virt_to_phys(input) : 0; u32 input_address_hi = input_address >> 32; u32 input_address_lo = input_address & 0xFFFFFFFF; - u64 output_address = (output) ? virt_to_phys(output) : 0; u32 output_address_hi = output_address >> 32; u32 output_address_lo = output_address & 0xFFFFFFFF; - void *hypercall_page = hv_context.hypercall_page; + + if (!hypercall_page) + return (u64)ULLONG_MAX; __asm__ __volatile__ ("call *%8" : "=d"(hv_status_hi), "=a"(hv_status_lo) : "d" (control_hi), -- cgit v1.3-6-gb490 From b4370df2b1f5158de028e167974263c5757b34a6 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Sat, 1 Aug 2015 16:08:09 -0700 Subject: Drivers: hv: vmbus: add special crash handler Full kernel hang is observed when kdump kernel starts after a crash. This hang happens in vmbus_negotiate_version() function on wait_for_completion() as Hyper-V host (Win2012R2 in my testing) never responds to CHANNELMSG_INITIATE_CONTACT as it thinks the connection is already established. We need to perform some mandatory minimalistic cleanup before we start new kernel. Reported-by: K. Y. Srinivasan Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/mshyperv.h | 2 ++ arch/x86/kernel/cpu/mshyperv.c | 22 ++++++++++++++++++++++ drivers/hv/vmbus_drv.c | 14 ++++++++++++++ 3 files changed, 38 insertions(+) (limited to 'drivers') diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index d3db9108346b..d02f9c9a6592 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -22,4 +22,6 @@ void hv_remove_vmbus_irq(void); void hv_setup_kexec_handler(void (*handler)(void)); void hv_remove_kexec_handler(void); +void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); +void hv_remove_crash_handler(void); #endif diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index fa483ed4756e..5ea5bbcc85b3 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -35,6 +35,7 @@ struct ms_hyperv_info ms_hyperv; EXPORT_SYMBOL_GPL(ms_hyperv); static void (*hv_kexec_handler)(void); +static void (*hv_crash_handler)(struct pt_regs *regs); #if IS_ENABLED(CONFIG_HYPERV) static void (*vmbus_handler)(void); @@ -83,6 +84,18 @@ void hv_remove_kexec_handler(void) hv_kexec_handler = NULL; } EXPORT_SYMBOL_GPL(hv_remove_kexec_handler); + +void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)) +{ + hv_crash_handler = handler; +} +EXPORT_SYMBOL_GPL(hv_setup_crash_handler); + +void hv_remove_crash_handler(void) +{ + hv_crash_handler = NULL; +} +EXPORT_SYMBOL_GPL(hv_remove_crash_handler); #endif static void hv_machine_shutdown(void) @@ -92,6 +105,14 @@ static void hv_machine_shutdown(void) native_machine_shutdown(); } +static void hv_machine_crash_shutdown(struct pt_regs *regs) +{ + if (hv_crash_handler) + hv_crash_handler(regs); + native_machine_crash_shutdown(regs); +} + + static uint32_t __init ms_hyperv_platform(void) { u32 eax; @@ -165,6 +186,7 @@ static void __init ms_hyperv_init_platform(void) #endif machine_ops.shutdown = hv_machine_shutdown; + machine_ops.crash_shutdown = hv_machine_crash_shutdown; } const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 31748a21d8f9..1ed9b32853a1 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1071,6 +1071,18 @@ static void hv_kexec_handler(void) hv_cleanup(); }; +static void hv_crash_handler(struct pt_regs *regs) +{ + vmbus_initiate_unload(); + /* + * In crash handler we can't schedule synic cleanup for all CPUs, + * doing the cleanup for current CPU only. This should be sufficient + * for kdump. + */ + hv_synic_cleanup(NULL); + hv_cleanup(); +}; + static int __init hv_acpi_init(void) { int ret, t; @@ -1104,6 +1116,7 @@ static int __init hv_acpi_init(void) goto cleanup; hv_setup_kexec_handler(hv_kexec_handler); + hv_setup_crash_handler(hv_crash_handler); return 0; @@ -1118,6 +1131,7 @@ static void __exit vmbus_exit(void) int cpu; hv_remove_kexec_handler(); + hv_remove_crash_handler(); vmbus_connection.conn_state = DISCONNECTED; hv_synic_clockevents_cleanup(); vmbus_disconnect(); -- cgit v1.3-6-gb490 From 510f7aef65bb7ed22cf9c7f94f955727f963ede4 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Sat, 1 Aug 2015 16:08:10 -0700 Subject: Drivers: hv: vmbus: prefer 'die' notification chain to 'panic' current_pt_regs() sometimes returns regs of the userspace process and in case of a kernel crash this is not what we need to report. E.g. when we trigger crash with sysrq we see the following: ... RIP: 0010:[] [] sysrq_handle_crash+0x16/0x20 RSP: 0018:ffff8800db0a7d88 EFLAGS: 00010246 RAX: 000000000000000f RBX: ffffffff820a0660 RCX: 0000000000000000 ... at the same time current_pt_regs() give us: ip=7f899ea7e9e0, ax=ffffffffffffffda, bx=26c81a0, cx=7f899ea7e9e0, ... These registers come from the userspace process triggered the crash. As we don't even know which process it was this information is rather useless. When kernel crash happens through 'die' proper regs are being passed to all receivers on the die_chain (and panic_notifier_list is being notified with the string passed to panic() only). If panic() is called manually (e.g. on BUG()) we won't get 'die' notification so keep the 'panic' notification reporter as well but guard against double reporting. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 1ed9b32853a1..b6114cc89aeb 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "hyperv_vmbus.h" static struct acpi_device *hv_acpi_dev; @@ -48,12 +49,18 @@ static struct completion probe_event; static int irq; -static int hyperv_panic_event(struct notifier_block *nb, - unsigned long event, void *ptr) +static void hyperv_report_panic(struct pt_regs *regs) { - struct pt_regs *regs; + static bool panic_reported; - regs = current_pt_regs(); + /* + * We prefer to report panic on 'die' chain as we have proper + * registers to report, but if we miss it (e.g. on BUG()) we need + * to report it on 'panic'. + */ + if (panic_reported) + return; + panic_reported = true; wrmsrl(HV_X64_MSR_CRASH_P0, regs->ip); wrmsrl(HV_X64_MSR_CRASH_P1, regs->ax); @@ -65,9 +72,32 @@ static int hyperv_panic_event(struct notifier_block *nb, * Let Hyper-V know there is crash data available */ wrmsrl(HV_X64_MSR_CRASH_CTL, HV_CRASH_CTL_CRASH_NOTIFY); +} + +static int hyperv_panic_event(struct notifier_block *nb, unsigned long val, + void *args) +{ + struct pt_regs *regs; + + regs = current_pt_regs(); + + hyperv_report_panic(regs); return NOTIFY_DONE; } +static int hyperv_die_event(struct notifier_block *nb, unsigned long val, + void *args) +{ + struct die_args *die = (struct die_args *)args; + struct pt_regs *regs = die->regs; + + hyperv_report_panic(regs); + return NOTIFY_DONE; +} + +static struct notifier_block hyperv_die_block = { + .notifier_call = hyperv_die_event, +}; static struct notifier_block hyperv_panic_block = { .notifier_call = hyperv_panic_event, }; @@ -842,6 +872,7 @@ static int vmbus_bus_init(int irq) * Only register if the crash MSRs are available */ if (ms_hyperv.features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { + register_die_notifier(&hyperv_die_block); atomic_notifier_chain_register(&panic_notifier_list, &hyperv_panic_block); } @@ -1139,6 +1170,7 @@ static void __exit vmbus_exit(void) tasklet_kill(&msg_dpc); vmbus_free_channels(); if (ms_hyperv.features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { + unregister_die_notifier(&hyperv_die_block); atomic_notifier_chain_unregister(&panic_notifier_list, &hyperv_panic_block); } -- cgit v1.3-6-gb490 From b36fda339729a974a8838978dcdc581d8ce68fd9 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Sat, 1 Aug 2015 16:08:11 -0700 Subject: Drivers: hv: kvp: check kzalloc return value kzalloc() return value check was accidentally lost in 11bc3a5fa91f: "Drivers: hv: kvp: convert to hv_utils_transport" commit. We don't need to reset kvp_transaction.state here as we have the kvp_timeout_func() timeout function and in case we're in OOM situation it is preferable to wait. Reported-by: Dan Carpenter Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_kvp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index d85798d5992c..74c38a9f34a6 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -353,6 +353,9 @@ kvp_send_key(struct work_struct *dummy) return; message = kzalloc(sizeof(*message), GFP_KERNEL); + if (!message) + return; + message->kvp_hdr.operation = operation; message->kvp_hdr.pool = pool; in_msg = kvp_transaction.kvp_msg; -- cgit v1.3-6-gb490 From 25ef06fe27a292ad33155045ef7a123be4c0b6ab Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Sat, 1 Aug 2015 16:08:12 -0700 Subject: Drivers: hv: fcopy: dynamically allocate smsg_out in fcopy_send_data() struct hv_start_fcopy is too big to be on stack on i386, the following warning is reported: >> drivers/hv/hv_fcopy.c:159:1: warning: the frame size of 1088 bytes is larger than 1024 bytes [-Wframe-larger-than=] Reported-by: kbuild test robot Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_fcopy.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c index b50dd330cf31..db4b887b889d 100644 --- a/drivers/hv/hv_fcopy.c +++ b/drivers/hv/hv_fcopy.c @@ -116,7 +116,7 @@ static int fcopy_handle_handshake(u32 version) static void fcopy_send_data(struct work_struct *dummy) { - struct hv_start_fcopy smsg_out; + struct hv_start_fcopy *smsg_out = NULL; int operation = fcopy_transaction.fcopy_msg->operation; struct hv_start_fcopy *smsg_in; void *out_src; @@ -136,21 +136,24 @@ static void fcopy_send_data(struct work_struct *dummy) switch (operation) { case START_FILE_COPY: out_len = sizeof(struct hv_start_fcopy); - memset(&smsg_out, 0, out_len); - smsg_out.hdr.operation = operation; + smsg_out = kzalloc(sizeof(*smsg_out), GFP_KERNEL); + if (!smsg_out) + return; + + smsg_out->hdr.operation = operation; smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg; utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH, UTF16_LITTLE_ENDIAN, - (__u8 *)&smsg_out.file_name, W_MAX_PATH - 1); + (__u8 *)&smsg_out->file_name, W_MAX_PATH - 1); utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH, UTF16_LITTLE_ENDIAN, - (__u8 *)&smsg_out.path_name, W_MAX_PATH - 1); + (__u8 *)&smsg_out->path_name, W_MAX_PATH - 1); - smsg_out.copy_flags = smsg_in->copy_flags; - smsg_out.file_size = smsg_in->file_size; - out_src = &smsg_out; + smsg_out->copy_flags = smsg_in->copy_flags; + smsg_out->file_size = smsg_in->file_size; + out_src = smsg_out; break; default: @@ -168,6 +171,8 @@ static void fcopy_send_data(struct work_struct *dummy) fcopy_transaction.state = HVUTIL_READY; } } + kfree(smsg_out); + return; } -- cgit v1.3-6-gb490 From b6ddeae1603dfa55e857ba1520f5acea83f8cf1c Mon Sep 17 00:00:00 2001 From: Alex Ng Date: Sat, 1 Aug 2015 16:08:13 -0700 Subject: Drivers: hv: balloon: Enable dynamic memory protocol negotiation with Windows 10 hosts Support Win10 protocol for Dynamic Memory. Thia patch allows guests on Win10 hosts to hot-add memory even when dynamic memory is not enabled on the guest. Signed-off-by: Alex Ng Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_balloon.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index 8a725cd69ad7..b853b4b083bd 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -62,11 +62,13 @@ enum { DYNMEM_PROTOCOL_VERSION_1 = DYNMEM_MAKE_VERSION(0, 3), DYNMEM_PROTOCOL_VERSION_2 = DYNMEM_MAKE_VERSION(1, 0), + DYNMEM_PROTOCOL_VERSION_3 = DYNMEM_MAKE_VERSION(2, 0), DYNMEM_PROTOCOL_VERSION_WIN7 = DYNMEM_PROTOCOL_VERSION_1, DYNMEM_PROTOCOL_VERSION_WIN8 = DYNMEM_PROTOCOL_VERSION_2, + DYNMEM_PROTOCOL_VERSION_WIN10 = DYNMEM_PROTOCOL_VERSION_3, - DYNMEM_PROTOCOL_VERSION_CURRENT = DYNMEM_PROTOCOL_VERSION_WIN8 + DYNMEM_PROTOCOL_VERSION_CURRENT = DYNMEM_PROTOCOL_VERSION_WIN10 }; @@ -1296,13 +1298,25 @@ static void version_resp(struct hv_dynmem_device *dm, if (dm->next_version == 0) goto version_error; - dm->next_version = 0; memset(&version_req, 0, sizeof(struct dm_version_request)); version_req.hdr.type = DM_VERSION_REQUEST; version_req.hdr.size = sizeof(struct dm_version_request); version_req.hdr.trans_id = atomic_inc_return(&trans_id); - version_req.version.version = DYNMEM_PROTOCOL_VERSION_WIN7; - version_req.is_last_attempt = 1; + version_req.version.version = dm->next_version; + + /* + * Set the next version to try in case current version fails. + * Win7 protocol ought to be the last one to try. + */ + switch (version_req.version.version) { + case DYNMEM_PROTOCOL_VERSION_WIN8: + dm->next_version = DYNMEM_PROTOCOL_VERSION_WIN7; + version_req.is_last_attempt = 0; + break; + default: + dm->next_version = 0; + version_req.is_last_attempt = 1; + } ret = vmbus_sendpacket(dm->dev->channel, &version_req, sizeof(struct dm_version_request), @@ -1442,7 +1456,7 @@ static int balloon_probe(struct hv_device *dev, dm_device.dev = dev; dm_device.state = DM_INITIALIZING; - dm_device.next_version = DYNMEM_PROTOCOL_VERSION_WIN7; + dm_device.next_version = DYNMEM_PROTOCOL_VERSION_WIN8; init_completion(&dm_device.host_event); init_completion(&dm_device.config_event); INIT_LIST_HEAD(&dm_device.ha_region_list); @@ -1474,7 +1488,7 @@ static int balloon_probe(struct hv_device *dev, version_req.hdr.type = DM_VERSION_REQUEST; version_req.hdr.size = sizeof(struct dm_version_request); version_req.hdr.trans_id = atomic_inc_return(&trans_id); - version_req.version.version = DYNMEM_PROTOCOL_VERSION_WIN8; + version_req.version.version = DYNMEM_PROTOCOL_VERSION_WIN10; version_req.is_last_attempt = 0; ret = vmbus_sendpacket(dev->channel, &version_req, -- cgit v1.3-6-gb490 From b81658cf5d44e07c70c93e3b2aefe848eaaba99f Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Sat, 1 Aug 2015 16:08:14 -0700 Subject: Drivers: hv: vmbus: Permit sending of packets without payload The guest may have to send a completion packet back to the host. To support this usage, permit sending a packet without a payload - we would be only sending the descriptor in this case. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 603ce97e9027..c4dcab048cb8 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -601,6 +601,7 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer, u64 aligned_data = 0; int ret; bool signal = false; + int num_vecs = ((bufferlen != 0) ? 3 : 1); /* Setup the descriptor */ @@ -618,7 +619,8 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer, bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_len = (packetlen_aligned - packetlen); - ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal); + ret = hv_ringbuffer_write(&channel->outbound, bufferlist, num_vecs, + &signal); /* * Signalling the host is conditional on many factors: -- cgit v1.3-6-gb490 From 9dd6a06430c94299651d74b9ed5ca8396ab8ff1f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 1 Aug 2015 16:08:17 -0700 Subject: hv: util: checking the wrong variable We don't catch this allocation failure because there is a typo and we check the wrong variable. Fixes: 14b50f80c32d ('Drivers: hv: util: introduce hv_utils_transport abstraction') Signed-off-by: Dan Carpenter Reviewed-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_utils_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index ea7ba5ef16a9..6a9d80a5332d 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c @@ -186,7 +186,7 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) return -EINVAL; } else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) { cn_msg = kzalloc(sizeof(*cn_msg) + len, GFP_ATOMIC); - if (!msg) + if (!cn_msg) return -ENOMEM; cn_msg->id.idx = hvt->cn_id.idx; cn_msg->id.val = hvt->cn_id.val; -- cgit v1.3-6-gb490 From e26009aad095feae45a6e79bb022c55a969ecded Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Sat, 1 Aug 2015 16:08:18 -0700 Subject: Drivers: hv: vmbus: fix typo in hv_port_info struct This fixes a typo: base_flag_bumber to base_flag_number Signed-off-by: Nik Nyby Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hyperv_vmbus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index cddc0c9f6bf9..638370701657 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -141,7 +141,7 @@ struct hv_port_info { struct { u32 target_sint; u32 target_vp; - u16 base_flag_bumber; + u16 base_flag_number; u16 flag_count; u32 rsvdz; } event_port_info; -- cgit v1.3-6-gb490 From 4a54243fc08f0edda1303bb666f0da68c378c036 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Sat, 1 Aug 2015 16:08:19 -0700 Subject: Drivers: hv: vmbus: don't send CHANNELMSG_UNLOAD on pre-Win2012R2 hosts Pre-Win2012R2 hosts don't properly handle CHANNELMSG_UNLOAD and wait_for_completion() hangs. Avoid sending such request on old hosts. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 4506a6623618..00ba3f36f193 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -469,6 +469,10 @@ void vmbus_initiate_unload(void) { struct vmbus_channel_message_header hdr; + /* Pre-Win2012R2 hosts don't support reconnect */ + if (vmbus_proto_version < VERSION_WIN8_1) + return; + init_completion(&vmbus_connection.unload_event); memset(&hdr, 0, sizeof(struct vmbus_channel_message_header)); hdr.msgtype = CHANNELMSG_UNLOAD; -- cgit v1.3-6-gb490 From cc2dd4027a43bb36c846f195a764edabc0828602 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sat, 1 Aug 2015 16:08:20 -0700 Subject: mshyperv: fix recognition of Hyper-V guest crash MSR's Hypervisor Top Level Functional Specification v3.1/4.0 notes that cpuid (0x40000003) EDX's 10th bit should be used to check that Hyper-V guest crash MSR's functionality available. This patch should fix this recognition. Currently the code checks EAX register instead of EDX. Signed-off-by: Andrey Smetanin Signed-off-by: Denis V. Lunev Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/mshyperv.h | 1 + arch/x86/kernel/cpu/mshyperv.c | 1 + drivers/hv/vmbus_drv.c | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index d02f9c9a6592..aaf59b7da98a 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -7,6 +7,7 @@ struct ms_hyperv_info { u32 features; + u32 misc_features; u32 hints; }; diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 5ea5bbcc85b3..f794bfa3c138 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -158,6 +158,7 @@ static void __init ms_hyperv_init_platform(void) * Extract the features and hints */ ms_hyperv.features = cpuid_eax(HYPERV_CPUID_FEATURES); + ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES); ms_hyperv.hints = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO); printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n", diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index b6114cc89aeb..e7b0bcd453e7 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -871,7 +871,7 @@ static int vmbus_bus_init(int irq) /* * Only register if the crash MSRs are available */ - if (ms_hyperv.features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { + if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { register_die_notifier(&hyperv_die_block); atomic_notifier_chain_register(&panic_notifier_list, &hyperv_panic_block); @@ -1169,7 +1169,7 @@ static void __exit vmbus_exit(void) hv_remove_vmbus_irq(); tasklet_kill(&msg_dpc); vmbus_free_channels(); - if (ms_hyperv.features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { + if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) { unregister_die_notifier(&hyperv_die_block); atomic_notifier_chain_unregister(&panic_notifier_list, &hyperv_panic_block); -- cgit v1.3-6-gb490 From 379e4f756b915bcc35958365e5d1326b3b54efce Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Sat, 1 Aug 2015 16:08:21 -0700 Subject: Drivers: hv: vmbus: Consider ND NIC in binding channels to CPUs We cycle through all the "high performance" channels to distribute load across the available CPUs. Process the NetworkDirect as a high performance device. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 00ba3f36f193..30613dfa38b3 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -347,6 +347,7 @@ enum { IDE = 0, SCSI, NIC, + ND_NIC, MAX_PERF_CHN, }; -- cgit v1.3-6-gb490 From 2092539b7735906deda8b1fca4b31b4c4eb65e0d Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Wed, 5 Aug 2015 13:23:26 +0800 Subject: dmaengine: zxdma: Fix data width bug Align src and dst width to fix data alignment issue as trailing single transaction that does not fill a full burst require identical src/dst data width. Burst length limitation can be addressed well too. Signed-off-by: Jun Nie Signed-off-by: Vinod Koul --- drivers/dma/zx296702_dma.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx296702_dma.c index 0d55c8fc4951..103691c61613 100644 --- a/drivers/dma/zx296702_dma.c +++ b/drivers/dma/zx296702_dma.c @@ -476,15 +476,16 @@ static int zx_pre_config(struct zx_dma_chan *c, enum dma_transfer_direction dir) c->dev_addr = cfg->dst_addr; /* dst len is calculated from src width, len and dst width. * We need make sure dst len not exceed MAX LEN. + * Trailing single transaction that does not fill a full + * burst also require identical src/dst data width. */ dst_width = zx_dma_burst_width(cfg->dst_addr_width); - maxburst = cfg->dst_maxburst * cfg->dst_addr_width - / DMA_SLAVE_BUSWIDTH_8_BYTES; + maxburst = cfg->dst_maxburst; maxburst = maxburst < ZX_MAX_BURST_LEN ? maxburst : ZX_MAX_BURST_LEN; c->ccfg = ZX_DST_FIFO_MODE | ZX_CH_ENABLE | ZX_SRC_BURST_LEN(maxburst - 1) - | ZX_SRC_BURST_WIDTH(ZX_DMA_WIDTH_64BIT) + | ZX_SRC_BURST_WIDTH(dst_width) | ZX_DST_BURST_WIDTH(dst_width); break; case DMA_DEV_TO_MEM: @@ -496,7 +497,7 @@ static int zx_pre_config(struct zx_dma_chan *c, enum dma_transfer_direction dir) c->ccfg = ZX_SRC_FIFO_MODE | ZX_CH_ENABLE | ZX_SRC_BURST_LEN(maxburst - 1) | ZX_SRC_BURST_WIDTH(src_width) - | ZX_DST_BURST_WIDTH(ZX_DMA_WIDTH_64BIT); + | ZX_DST_BURST_WIDTH(src_width); break; default: return -EINVAL; -- cgit v1.3-6-gb490 From ed9c87b33147e5b007e66a282b9c8c307fbf8bf9 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Wed, 5 Aug 2015 13:23:27 +0800 Subject: dmaengine: zxdma: Fix force stop bug DMA will not stop when clearing enable bit till all transaction is done. The bug is exposed in audio playback because ring DMA chain never stop. Force hardware to stop with setting FORCE bit. Signed-off-by: Jun Nie Signed-off-by: Vinod Koul --- drivers/dma/zx296702_dma.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx296702_dma.c index 103691c61613..39915a6b7986 100644 --- a/drivers/dma/zx296702_dma.c +++ b/drivers/dma/zx296702_dma.c @@ -144,6 +144,7 @@ static void zx_dma_terminate_chan(struct zx_dma_phy *phy, struct zx_dma_dev *d) val = readl_relaxed(phy->base + REG_ZX_CTRL); val &= ~ZX_CH_ENABLE; + val |= ZX_FORCE_CLOSE; writel_relaxed(val, phy->base + REG_ZX_CTRL); val = 0x1 << phy->idx; -- cgit v1.3-6-gb490 From 6f4551fe8e7f3561b97b7f74d8f4af08db01de6f Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 14 Jul 2015 16:29:10 -0300 Subject: drm/i915: fix FBC frontbuffer tracking flushing code Due to the way busy_bits was handled, we were not doing any flushes if we didn't previously get an invalidate. Since it's possible to get flushes without an invalidate first, remove the busy_bits early return. So now that we don't have the busy_bits guard anymore we'll need the origin check for the GTT tracking (we were not doing anything on GTT flushes due to the GTT check at invalidate()). As a last detail, since we can get multiple consecutive flushes, disable FBC before updating it, otherwise intel_fbc_update() will just keep FBC enabled instead of restarting it. Notice that this does not fix any of the current IGT tests due to the fact that we still have a few intel_fbc() calls at points where we also have the frontbuffer tracking calls: we didn't fully convert to frontbuffer tracking yet. Once we remove those calls and start relying only on the frontbuffer tracking infrastructure we'll need this patch. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_fbc.c | 13 +++++++------ drivers/gpu/drm/i915/intel_frontbuffer.c | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3b00d00c0bc0..817a4169d3b8 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1239,7 +1239,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin); void intel_fbc_flush(struct drm_i915_private *dev_priv, - unsigned int frontbuffer_bits); + unsigned int frontbuffer_bits, enum fb_op_origin origin); const char *intel_no_fbc_reason_str(enum no_fbc_reason reason); void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index c271af767981..1f97fb548c2a 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -884,22 +884,23 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, } void intel_fbc_flush(struct drm_i915_private *dev_priv, - unsigned int frontbuffer_bits) + unsigned int frontbuffer_bits, enum fb_op_origin origin) { if (!dev_priv->fbc.enable_fbc) return; - mutex_lock(&dev_priv->fbc.lock); + if (origin == ORIGIN_GTT) + return; - if (!dev_priv->fbc.busy_bits) - goto out; + mutex_lock(&dev_priv->fbc.lock); dev_priv->fbc.busy_bits &= ~frontbuffer_bits; - if (!dev_priv->fbc.busy_bits) + if (!dev_priv->fbc.busy_bits) { + __intel_fbc_disable(dev_priv); __intel_fbc_update(dev_priv); + } -out: mutex_unlock(&dev_priv->fbc.lock); } diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 777b1d3ccd41..ac85357010b4 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -129,7 +129,7 @@ static void intel_frontbuffer_flush(struct drm_device *dev, intel_edp_drrs_flush(dev, frontbuffer_bits); intel_psr_flush(dev, frontbuffer_bits, origin); - intel_fbc_flush(dev_priv, frontbuffer_bits); + intel_fbc_flush(dev_priv, frontbuffer_bits, origin); } /** -- cgit v1.3-6-gb490 From 698e84ed89ffa09c6f00148c72b058302c311b5d Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 14 Jul 2015 16:29:11 -0300 Subject: drm/i915: don't call intel_fbc_update() at intel_unpin_work_fn() Because intel_unpin_work_fn() already calls intel_frontbuffer_flip_complete() which will call intel_fbc_flush() which will call intel_fbc_update() when needed. We couldn't fix this previously due to the fact that FBC was not properly behaving as intended on frontbuffer flushes, but now that this is fixed, we can remove the additional call. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index af0bcfee4771..3dbe3162c848 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10762,15 +10762,12 @@ static void intel_unpin_work_fn(struct work_struct *__work) container_of(__work, struct intel_unpin_work, work); struct intel_crtc *crtc = to_intel_crtc(work->crtc); struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_plane *primary = crtc->base.primary; mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(work->old_fb, primary->state); drm_gem_object_unreference(&work->pending_flip_obj->base); - intel_fbc_update(dev_priv); - if (work->flip_queued_req) i915_gem_request_assign(&work->flip_queued_req, NULL); mutex_unlock(&dev->struct_mutex); -- cgit v1.3-6-gb490 From 4e1e26f1b09398fad93ba24be816368714bede7c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 14 Jul 2015 16:29:13 -0300 Subject: drm/i915: don't disable FBC for pipe A when flipping pipe B Use the appropriate call. I know there's a discussion about whether we need this call here at all, but removing the call means we'll only update FBC after we get the page flip IRQ. So the user may only see the new frame a little after it should. Let's wait just a little bit more before removing this call since we can rely in the HW tracking for accurate flips. Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3dbe3162c848..b25f3cac021a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11539,7 +11539,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, to_intel_plane(primary)->frontbuffer_bit); mutex_unlock(&dev->struct_mutex); - intel_fbc_disable(dev_priv); + intel_fbc_disable_crtc(intel_crtc); intel_frontbuffer_flip_prepare(dev, to_intel_plane(primary)->frontbuffer_bit); -- cgit v1.3-6-gb490 From 74b4ea1e4e8a5134b8a201e7fd6a3b529f7d0035 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 14 Jul 2015 16:29:14 -0300 Subject: drm/i915: special-case dirtyfb for frontbuffer tracking First, an introduction. We currently have two types of GTT mmaps: the "normal" old mmap, and the WC mmap. For frontbuffer-related features that have automatic hardware tracking, only the non-WC mmap writes are detected by the hardware. Since inside the Kernel both are treated as ORIGIN_GTT, any features ignoring ORIGIN_GTT because of the hardware tracking are destined to fail. One of the special rules defined for the WC mmaps is that the user should call the dirtyfb IOCTL after he is done using the pointers, so that results in an intel_fb_obj_flush() call. The problem is that the dirtyfb is passing ORIGIN_GTT, so it is being ignored by FBC - even though the hardware tracking is not detecing the WC mmap operations. So in order to fix that without having to give up the automatic hardware tracking for GTT mmaps we transform the flush operation from dirtyfb into a special operation: ORIGIN_DIRTYFB. This commit fixes all the kms_frontbuffer_tracking subtests that contain "fbc" and "mmap-wc" in their names and are currently failing (for a total of 16 subtests). Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 86e69f1ad3ee..994c411f095d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -894,6 +894,7 @@ enum fb_op_origin { ORIGIN_CPU, ORIGIN_CS, ORIGIN_FLIP, + ORIGIN_DIRTYFB, }; struct i915_fbc { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b25f3cac021a..f4ed4f13646c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14271,7 +14271,7 @@ static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, struct drm_i915_gem_object *obj = intel_fb->obj; mutex_lock(&dev->struct_mutex); - intel_fb_obj_flush(obj, false, ORIGIN_GTT); + intel_fb_obj_flush(obj, false, ORIGIN_DIRTYFB); mutex_unlock(&dev->struct_mutex); return 0; -- cgit v1.3-6-gb490 From 082dcc7c0c666df9a37879d79a15a8115f05a08f Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 30 Jul 2015 16:26:39 -0700 Subject: drm/i915: Split sink_crc function in start, stop and read. This is just a preparation patch to make clear what operation we are performing. There is no functional change on the sink crc logic. hsw_disable_ips has been moved a bit further in the start function to avoid disabling ips when sink crc is not going to be started. and to avoid goto on this function. v2: explain why hsw_disable_ips() call place has changed. Cc: Daniel Vetter Reviewed-by: Rafael Antognolli Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 89 +++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 44f8a32e4d1e..10cbc9879e00 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3958,40 +3958,64 @@ intel_dp_probe_mst(struct intel_dp *intel_dp) return intel_dp->is_mst; } -int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) +static void intel_dp_sink_crc_stop(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; - struct intel_crtc *intel_crtc = - to_intel_crtc(intel_dig_port->base.base.crtc); + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc); u8 buf; - int test_crc_count; - int attempts = 6; - int ret = 0; - - hsw_disable_ips(intel_crtc); - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0) { - ret = -EIO; - goto out; + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) { + DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n"); + return; } - if (!(buf & DP_TEST_CRC_SUPPORTED)) { - ret = -ENOTTY; - goto out; - } + if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, + buf & ~DP_TEST_SINK_START) < 0) + DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n"); - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) { - ret = -EIO; - goto out; - } + hsw_enable_ips(intel_crtc); +} + +static int intel_dp_sink_crc_start(struct intel_dp *intel_dp) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc); + u8 buf; + + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0) + return -EIO; + + if (!(buf & DP_TEST_CRC_SUPPORTED)) + return -ENOTTY; + + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) + return -EIO; + + hsw_disable_ips(intel_crtc); if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, - buf | DP_TEST_SINK_START) < 0) { - ret = -EIO; - goto out; + buf | DP_TEST_SINK_START) < 0) { + hsw_enable_ips(intel_crtc); + return -EIO; } + return 0; +} + +int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = dig_port->base.base.dev; + struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc); + u8 buf; + int test_crc_count; + int attempts = 6; + int ret; + + ret = intel_dp_sink_crc_start(intel_dp); + if (ret) + return ret; + if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0) { ret = -EIO; goto stop; @@ -4014,23 +4038,10 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) goto stop; } - if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) { + if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) ret = -EIO; - goto stop; - } - stop: - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) { - DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n"); - goto out; - } - if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, - buf & ~DP_TEST_SINK_START) < 0) { - DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n"); - goto out; - } -out: - hsw_enable_ips(intel_crtc); + intel_dp_sink_crc_stop(intel_dp); return ret; } -- cgit v1.3-6-gb490 From 30886c5afbb446ec1e3616beb2858fba74a23d14 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 30 Jul 2015 17:07:55 -0700 Subject: drm/i915: VLV/CHV PSR: Increase wait delay time before active PSR. Since active function on VLV immediately activate PSR let's give more time for idleness. Different from core platforms where we have idle_frames count. Also kms_psr_sink_crc now is automated and always get this: [drm:intel_enable_pipe] enabling pipe A [drm:intel_edp_backlight_on] [drm:intel_panel_enable_backlight] pipe [drm:intel_panel_enable_backlight] pipe A [drm:intel_panel_actually_set_backlight] set backlight PWM = 7812 PSR gets enabled somewhere here after backlight. [drm:intel_get_hpd_pins] hotplug event received, stat 0x00000000, dig 0x0 [drm:vlv_pipe_set_fifo_size] Pipe A FIFO split 511 / 511 / 511 [drm:vlv_update_wm] Setting FIFO watermarks - A: plane=391, cursor=63, sp PSR gets flushed around here by intel_atomic_commit [drm:vlv_pipe_set_fifo_size] Pipe A FIFO split 511 / 511 / 511 [drm:vlv_update_wm] Setting FIFO watermarks - A: plane=391, cursor=63, sp [drm:intel_set_memory_cxsr] memory self-refresh is enabled [drm:intel_connector_check_state] [CONNECTOR:39:eDP-1] [drm:check_encoder_state] [ENCODER:30:DAC-30] [drm:check_encoder_state] [ENCODER:31:TMDS-31] [drm:check_encoder_state] [ENCODER:36:TMDS-36] [drm:check_encoder_state] [ENCODER:38:TMDS-38] [drm:check_crtc_state] [CRTC:21] [drm:check_crtc_state] [CRTC:26] [drm:intel_psr_activate [i915]] *ERROR* PSR Active [drm:intel_get_hpd_pins] hotplug event received, stat 0x00000000, dig 0x [drm:intel_set_cpu_fifo_underrun_reporting [i915]] *ERROR* pipe A underrun [drm:intel_cpu_fifo_underrun_irq_handler [i915]] *ERROR* CPU pipe A FIFO Underrun. It is true that in a product we won't keep disabling and enabling planes so frequently, but for safeness let's stay conservative. It is also true that 500ms is an etternity. But PSR is anyway a power saving feature for idle scenario. So if it is idle feature stays on and 500ms to get it reanabled is not that insane. v2: Rebase over intel_psr.c and fix typo. v3: Revival: Manual tests indicated that this is needed. With a short delay there is a huge risk of getting blank screens when planes are being enabled. v4: Revival 2 with reasonable delay. 1/2 sec instead of 5. VBT is 10 sec but actually time for link training what we aren't doing, but with only 100 sec in some cases kms_psr_sink_crc manual was showing blank screen, so let's use this for now. Also changed comment by a FIXME. v5: Rebase after a long time, remove FIXME and update comment above. v6: msecs_to_jiffies is already on delay. remove duplication. v7: use msecs_to_jiffies on schedule_delayed_work call. Reviewed-by: Durgadoss R (v4) Signed-off-by: Rodrigo Vivi Tested-By: Intel Graphics QA PRTS (Patch Regression Test System Contact: shuang.he@intel.com) Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_psr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index acd8ec859f71..a04b4dc5ed9b 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -698,6 +698,7 @@ void intel_psr_flush(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; enum pipe pipe; + int delay_ms = HAS_DDI(dev) ? 100 : 500; mutex_lock(&dev_priv->psr.lock); if (!dev_priv->psr.enabled) { @@ -733,7 +734,7 @@ void intel_psr_flush(struct drm_device *dev, if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) schedule_delayed_work(&dev_priv->psr.work, - msecs_to_jiffies(100)); + msecs_to_jiffies(delay_ms)); mutex_unlock(&dev_priv->psr.lock); } -- cgit v1.3-6-gb490 From 0667405b6061be2949d841f05647e550d48c2765 Mon Sep 17 00:00:00 2001 From: Marc Herbert Date: Wed, 29 Jul 2015 12:21:22 -0700 Subject: drm/i915/skl: revert duplicated WaBarrierPerformanceFixDisable:skl With this simple git diff command one can see that skl_init_workarounds() got two copies of WaBarrierPerformanceFixDisable:skl: git diff -U21 ca6e4405779e^1 ca6e4405779e drivers/gpu/drm/i915/intel_ringbuffer.c This happened when the backmerge of drm-intel-fixes-2015-07-15 Merged the same fix on both sides. Same fix but not identical enough for git: with a different surrounding context; hence the code duplication. This commit merely reverts the output of the git command above = the duplication introduced in the backmerge. (This duplication was found while running git sanity checks on a _linearized_ i915 forklift for ChromeOS.) Signed-off-by: Marc Herbert Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 177f7ed16cf0..1c14233d179f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1041,13 +1041,6 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(HIZ_CHICKEN, BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE); - if (INTEL_REVID(dev) == SKL_REVID_C0 || - INTEL_REVID(dev) == SKL_REVID_D0) - /* WaBarrierPerformanceFixDisable:skl */ - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FENCE_DEST_SLM_DISABLE | - HDC_BARRIER_PERFORMANCE_DISABLE); - if (INTEL_REVID(dev) <= SKL_REVID_D0) { /* *Use Force Non-Coherent whenever executing a 3D context. This -- cgit v1.3-6-gb490 From e8ca932056c22dfce2fac00058203386b41f3af4 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 30 Jul 2015 18:20:26 -0300 Subject: drm/i915: Extract a intel_power_well_enable() function We need a bit book keeping around power wells' ops->enable(), namely a nice debug message and updating hw_enabled. Let's introduce a intel_power_well_enable() function to make sure all the callers do the same things. v2 (from Paulo): - s/i915_power_well_enable/intel_power_well_enable/ since everything else on this file uses intel_ instead of i915_. - Fix typo in commit message. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 6393b76f87ff..a52574d4afbf 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -68,6 +68,14 @@ bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, int power_well_id); +static void intel_power_well_enable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + DRM_DEBUG_KMS("enabling %s\n", power_well->name); + power_well->ops->enable(dev_priv, power_well); + power_well->hw_enabled = true; +} + /* * We should only use the power well if we explicitly asked the hardware to * enable it, so check if it's enabled and also check if we've requested it to @@ -1104,11 +1112,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++) { - DRM_DEBUG_KMS("enabling %s\n", power_well->name); - power_well->ops->enable(dev_priv, power_well); - power_well->hw_enabled = true; - } + if (!power_well->count++) + intel_power_well_enable(dev_priv, power_well); } power_domains->domain_use_count[domain]++; -- cgit v1.3-6-gb490 From dcddab3aa025b161239ec309f1d4f199d91aca11 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 30 Jul 2015 18:20:27 -0300 Subject: drm/i915: Extract a intel_power_well_disable() function Similar to the ->enable vfunc in patch "drm/i915: Extract a intel_power_well_enable() function". v2 (from Paulo): - Same s/i915_/intel_/ bikeshed as the previous patch. - Update the commit hash. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index a52574d4afbf..821644d1b544 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -76,6 +76,14 @@ static void intel_power_well_enable(struct drm_i915_private *dev_priv, power_well->hw_enabled = true; } +static void intel_power_well_disable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + DRM_DEBUG_KMS("disabling %s\n", power_well->name); + power_well->hw_enabled = false; + power_well->ops->disable(dev_priv, power_well); +} + /* * We should only use the power well if we explicitly asked the hardware to * enable it, so check if it's enabled and also check if we've requested it to @@ -1147,11 +1155,8 @@ 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) { - DRM_DEBUG_KMS("disabling %s\n", power_well->name); - power_well->hw_enabled = false; - power_well->ops->disable(dev_priv, power_well); - } + if (!--power_well->count && i915.disable_power_well) + intel_power_well_disable(dev_priv, power_well); } mutex_unlock(&power_domains->lock); -- cgit v1.3-6-gb490 From d37ae19a6c21bc358f69e1dca410743c98347fe2 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 30 Jul 2015 18:20:29 -0300 Subject: drm/i915/skl: send opregion_nofify_adapter(PCI_D1) instead of PCI_D3 I was told that the "repurposed D1 definition" is still valid for SKL. It is BDW that is special due to its hotplug bug, so let's special-case BDW instead of HSW. Cc: Kristen Carlson Accardi Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 151263b433e6..1d887459e37f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1489,7 +1489,15 @@ static int intel_runtime_suspend(struct device *device) * FIXME: We really should find a document that references the arguments * used below! */ - if (IS_HASWELL(dev)) { + if (IS_BROADWELL(dev)) { + /* + * On Broadwell, if we use PCI_D1 the PCH DDI ports will stop + * being detected, and the call we do at intel_runtime_resume() + * won't be able to restore them. Since PCI_D3hot matches the + * actual specification and appears to be working, use it. + */ + intel_opregion_notify_adapter(dev, PCI_D3hot); + } else { /* * current versions of firmware which depend on this opregion * notification have repurposed the D1 definition to mean @@ -1498,16 +1506,6 @@ static int intel_runtime_suspend(struct device *device) * the suspend path. */ intel_opregion_notify_adapter(dev, PCI_D1); - } else { - /* - * On Broadwell, if we use PCI_D1 the PCH DDI ports will stop - * being detected, and the call we do at intel_runtime_resume() - * won't be able to restore them. Since PCI_D3hot matches the - * actual specification and appears to be working, use it. Let's - * assume the other non-Haswell platforms will stay the same as - * Broadwell. - */ - intel_opregion_notify_adapter(dev, PCI_D3hot); } assert_forcewakes_inactive(dev_priv); -- cgit v1.3-6-gb490 From 22ce5628a1df81b50fc86fb686f470f15c1c96ef Mon Sep 17 00:00:00 2001 From: "Thulasimani,Sivakumar" Date: Fri, 31 Jul 2015 11:05:27 +0530 Subject: drm/i915: read bpp from vbt only for older panels BPP bits defined in VBT should be used only on panels whose edid version is 1.3 or older. EDID version 1.4 introduced offsets where bpp is defined and read into display_info, hence bpp from VBT will be used only when bpc in display_info is zero. v2: use display_info.bpc for deciding when to use vbt_bpp (Jani) Signed-off-by: Sivakumar Thulasimani Reviewed-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 10cbc9879e00..df7e2cfef38d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1409,7 +1409,10 @@ intel_dp_compute_config(struct intel_encoder *encoder, * bpc in between. */ bpp = pipe_config->pipe_bpp; if (is_edp(intel_dp)) { - if (dev_priv->vbt.edp_bpp && dev_priv->vbt.edp_bpp < bpp) { + + /* Get bpp from vbt only for panels that dont have bpp in edid */ + if (intel_connector->base.display_info.bpc == 0 && + (dev_priv->vbt.edp_bpp && dev_priv->vbt.edp_bpp < bpp)) { DRM_DEBUG_KMS("clamping bpp for eDP panel to BIOS-provided %i\n", dev_priv->vbt.edp_bpp); bpp = dev_priv->vbt.edp_bpp; -- cgit v1.3-6-gb490 From a7f749f9c7e8222405740f6081bd183137d1d6f2 Mon Sep 17 00:00:00 2001 From: Animesh Manna Date: Mon, 3 Aug 2015 21:55:32 +0530 Subject: drm/i915/gen9: Removed byte swapping for csr firmware This patch contains the changes to remove the byte swapping logic introduced with old dmc firmware. While debugging PC10 entry issue for skylake found with latest dmc firmware version 1.18 without byte swapping dmc is working fine and able to enter PC10. Note that apparently this was changed with dmc version 1.0 and earlier ones indeed are byteswapped like this ... v1: Initial version. v2: Corrected firmware size during memcpy(). (Suggested by Sunil) Cc: Daniel Vetter Cc: Damien Lespiau Cc: Imre Deak Cc: Sunil Kamath Signed-off-by: Animesh Manna Signed-off-by: Vathsala Nagaraju Reviewed-by: A.Sunil Kamath [danvet: Add note that this only holds for released dmc firmware.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_csr.c | 16 ++++------------ 2 files changed, 5 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 994c411f095d..4e9f7b16a729 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -742,7 +742,7 @@ enum csr_state { struct intel_csr { const char *fw_path; - __be32 *dmc_payload; + uint32_t *dmc_payload; uint32_t dmc_fw_size; uint32_t mmio_count; uint32_t mmioaddr[8]; diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index 6d8a7bf06dfc..ba1ae031e6fd 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -244,7 +244,7 @@ void intel_csr_load_status_set(struct drm_i915_private *dev_priv, void intel_csr_load_program(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - __be32 *payload = dev_priv->csr.dmc_payload; + u32 *payload = dev_priv->csr.dmc_payload; uint32_t i, fw_size; if (!IS_GEN9(dev)) { @@ -256,7 +256,7 @@ void intel_csr_load_program(struct drm_device *dev) fw_size = dev_priv->csr.dmc_fw_size; for (i = 0; i < fw_size; i++) I915_WRITE(CSR_PROGRAM_BASE + i * 4, - (u32 __force)payload[i]); + payload[i]); for (i = 0; i < dev_priv->csr.mmio_count; i++) { I915_WRITE(dev_priv->csr.mmioaddr[i], @@ -279,7 +279,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) char substepping = intel_get_substepping(dev); uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes; uint32_t i; - __be32 *dmc_payload; + uint32_t *dmc_payload; bool fw_loaded = false; if (!fw) { @@ -375,15 +375,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) } dmc_payload = csr->dmc_payload; - for (i = 0; i < dmc_header->fw_size; i++) { - uint32_t *tmp = (u32 *)&fw->data[readcount + i * 4]; - /* - * The firmware payload is an array of 32 bit words stored in - * little-endian format in the firmware image and programmed - * as 32 bit big-endian format to memory. - */ - dmc_payload[i] = cpu_to_be32(*tmp); - } + memcpy(dmc_payload, &fw->data[readcount], nbytes); /* load csr program during system boot, as needed for DC states */ intel_csr_load_program(dev); -- cgit v1.3-6-gb490 From ea215a3f909c570521a9cc276163837ffa2c621a Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Fri, 31 Jul 2015 21:58:12 -0600 Subject: toshiba_acpi: Change *available functions return type This patch changes the *available functions return type from int to void. The checks for support of their respective features are done inside such functions and there was no need to return anything as we can flag the queried feature as supported inside these functions. The code was adapted accordingly to these changes and two new variables were created and another was changed from uint to bool. Also, the function toshiba_acceleremoter_supported was renamed to toshiba_accelerometer_available to maintain the naming consistency on the driver. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 129 +++++++++++++++++------------------- 1 file changed, 62 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index f7228987bd50..d983dc45f30d 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -187,7 +187,6 @@ struct toshiba_acpi_dev { unsigned int info_supported:1; unsigned int tr_backlight_supported:1; unsigned int kbd_illum_supported:1; - unsigned int kbd_led_registered:1; unsigned int touchpad_supported:1; unsigned int eco_supported:1; unsigned int accelerometer_supported:1; @@ -198,6 +197,10 @@ struct toshiba_acpi_dev { unsigned int panel_power_on_supported:1; unsigned int usb_three_supported:1; unsigned int sysfs_created:1; + + bool kbd_led_registered; + bool illumination_led_registered; + bool eco_led_registered; }; static struct toshiba_acpi_dev *toshiba_acpi; @@ -439,26 +442,26 @@ static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) } /* Illumination support */ -static int toshiba_illumination_available(struct toshiba_acpi_dev *dev) +static void toshiba_illumination_available(struct toshiba_acpi_dev *dev) { u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; u32 out[TCI_WORDS]; acpi_status status; + dev->illumination_supported = 0; + dev->illumination_led_registered = false; + if (!sci_open(dev)) - return 0; + return; status = tci_raw(dev, in, out); sci_close(dev); - if (ACPI_FAILURE(status)) { + if (ACPI_FAILURE(status)) pr_err("ACPI call to query Illumination support failed\n"); - return 0; - } else if (out[0] == TOS_NOT_SUPPORTED) { + else if (out[0] == TOS_NOT_SUPPORTED) pr_info("Illumination device not available\n"); - return 0; - } - - return 1; + else if (out[0] == TOS_SUCCESS) + dev->illumination_supported = 1; } static void toshiba_illumination_set(struct led_classdev *cdev, @@ -510,41 +513,42 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) } /* KBD Illumination */ -static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) +static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) { u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; u32 out[TCI_WORDS]; acpi_status status; + dev->kbd_illum_supported = 0; + dev->kbd_led_registered = false; + if (!sci_open(dev)) - return 0; + return; status = tci_raw(dev, in, out); sci_close(dev); if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { pr_err("ACPI call to query kbd illumination support failed\n"); - return 0; } else if (out[0] == TOS_NOT_SUPPORTED) { pr_info("Keyboard illumination not available\n"); - return 0; + } else if (out[0] == TOS_SUCCESS) { + /* + * Check for keyboard backlight timeout max value, + * previous kbd backlight implementation set this to + * 0x3c0003, and now the new implementation set this + * to 0x3c001a, use this to distinguish between them. + */ + if (out[3] == SCI_KBD_TIME_MAX) + dev->kbd_type = 2; + else + dev->kbd_type = 1; + /* Get the current keyboard backlight mode */ + dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; + /* Get the current time (1-60 seconds) */ + dev->kbd_time = out[2] >> HCI_MISC_SHIFT; + /* Flag as supported */ + dev->kbd_illum_supported = 1; } - - /* - * Check for keyboard backlight timeout max value, - * previous kbd backlight implementation set this to - * 0x3c0003, and now the new implementation set this - * to 0x3c001a, use this to distinguish between them. - */ - if (out[3] == SCI_KBD_TIME_MAX) - dev->kbd_type = 2; - else - dev->kbd_type = 1; - /* Get the current keyboard backlight mode */ - dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; - /* Get the current time (1-60 seconds) */ - dev->kbd_time = out[2] >> HCI_MISC_SHIFT; - - return 1; } static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) @@ -665,12 +669,15 @@ static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) } /* Eco Mode support */ -static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) +static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) { acpi_status status; u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; u32 out[TCI_WORDS]; + dev->eco_supported = 0; + dev->eco_led_registered = false; + status = tci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get ECO led failed\n"); @@ -691,10 +698,8 @@ static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) pr_err("ACPI call to get ECO led failed\n"); else if (out[0] == TOS_SUCCESS) - return 1; + dev->eco_supported = 1; } - - return 0; } static enum led_brightness @@ -734,30 +739,28 @@ static void toshiba_eco_mode_set_status(struct led_classdev *cdev, } /* Accelerometer support */ -static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev) +static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) { u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; u32 out[TCI_WORDS]; acpi_status status; + dev->accelerometer_supported = 0; + /* * Check if the accelerometer call exists, * this call also serves as initialization */ status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { + if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) pr_err("ACPI call to query the accelerometer failed\n"); - return -EIO; - } else if (out[0] == TOS_DATA_NOT_AVAILABLE || - out[0] == TOS_NOT_INITIALIZED) { + else if (out[0] == TOS_DATA_NOT_AVAILABLE || + out[0] == TOS_NOT_INITIALIZED) pr_err("Accelerometer not initialized\n"); - return -EIO; - } else if (out[0] == TOS_NOT_SUPPORTED) { + else if (out[0] == TOS_NOT_SUPPORTED) pr_info("Accelerometer not supported\n"); - return -ENODEV; - } - - return 0; + else if (out[0] == TOS_SUCCESS) + dev->accelerometer_supported = 1; } static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, @@ -787,7 +790,6 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) u32 out[TCI_WORDS]; acpi_status status; - /* Set the feature to "not supported" in case of error */ dev->usb_sleep_charge_supported = 0; if (!sci_open(dev)) @@ -808,25 +810,17 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) in[5] = SCI_USB_CHARGE_BAT_LVL; status = tci_raw(dev, in, out); + sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); - sci_close(dev); - return; } else if (out[0] == TOS_NOT_SUPPORTED) { pr_info("USB Sleep and Charge not supported\n"); - sci_close(dev); - return; } else if (out[0] == TOS_SUCCESS) { dev->usbsc_bat_level = out[2]; - /* - * If we reach this point, it means that the laptop has support - * for this feature and all values are initialized. - * Set it as supported. - */ + /* Flag as supported */ dev->usb_sleep_charge_supported = 1; } - sci_close(dev); } static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, @@ -2639,13 +2633,13 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev) backlight_device_unregister(dev->backlight_dev); - if (dev->illumination_supported) + if (dev->illumination_led_registered) led_classdev_unregister(&dev->led_dev); if (dev->kbd_led_registered) led_classdev_unregister(&dev->kbd_led); - if (dev->eco_supported) + if (dev->eco_led_registered) led_classdev_unregister(&dev->eco_led); if (toshiba_acpi) @@ -2727,25 +2721,27 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) if (ret) goto error; - if (toshiba_illumination_available(dev)) { + toshiba_illumination_available(dev); + if (dev->illumination_supported) { dev->led_dev.name = "toshiba::illumination"; dev->led_dev.max_brightness = 1; dev->led_dev.brightness_set = toshiba_illumination_set; dev->led_dev.brightness_get = toshiba_illumination_get; if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) - dev->illumination_supported = 1; + dev->illumination_led_registered = true; } - if (toshiba_eco_mode_available(dev)) { + toshiba_eco_mode_available(dev); + if (dev->eco_supported) { dev->eco_led.name = "toshiba::eco_mode"; dev->eco_led.max_brightness = 1; dev->eco_led.brightness_set = toshiba_eco_mode_set_status; dev->eco_led.brightness_get = toshiba_eco_mode_get_status; if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) - dev->eco_supported = 1; + dev->eco_led_registered = true; } - dev->kbd_illum_supported = toshiba_kbd_illum_available(dev); + toshiba_kbd_illum_available(dev); /* * Only register the LED if KBD illumination is supported * and the keyboard backlight operation mode is set to FN-Z @@ -2756,14 +2752,13 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) - dev->kbd_led_registered = 1; + dev->kbd_led_registered = true; } ret = toshiba_touchpad_get(dev, &dummy); dev->touchpad_supported = !ret; - ret = toshiba_accelerometer_supported(dev); - dev->accelerometer_supported = !ret; + toshiba_accelerometer_available(dev); toshiba_usb_sleep_charge_available(dev); -- cgit v1.3-6-gb490 From 0409cbced3c9ab975e300584b6cc036c26974b43 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Fri, 31 Jul 2015 21:58:13 -0600 Subject: toshiba_acpi: Remove "*not supported" feature prints Currently the driver prints "*not supported" if any of the features queried are in fact not supported, let us print the available features instead. This patch removes all instances pr_info printing "*not supported", and add a new function called "print_supported_features", which will print the available laptop features. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 72 +++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index d983dc45f30d..66b596a7f710 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -459,7 +459,7 @@ static void toshiba_illumination_available(struct toshiba_acpi_dev *dev) if (ACPI_FAILURE(status)) pr_err("ACPI call to query Illumination support failed\n"); else if (out[0] == TOS_NOT_SUPPORTED) - pr_info("Illumination device not available\n"); + return; else if (out[0] == TOS_SUCCESS) dev->illumination_supported = 1; } @@ -483,7 +483,6 @@ static void toshiba_illumination_set(struct led_classdev *cdev, pr_err("ACPI call for illumination failed\n"); return; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("Illumination not supported\n"); return; } } @@ -505,7 +504,6 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) pr_err("ACPI call for illumination failed\n"); return LED_OFF; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("Illumination not supported\n"); return LED_OFF; } @@ -530,7 +528,7 @@ static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { pr_err("ACPI call to query kbd illumination support failed\n"); } else if (out[0] == TOS_NOT_SUPPORTED) { - pr_info("Keyboard illumination not available\n"); + return; } else if (out[0] == TOS_SUCCESS) { /* * Check for keyboard backlight timeout max value, @@ -564,7 +562,6 @@ static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) pr_err("ACPI call to set KBD backlight status failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("Keyboard backlight status not supported\n"); return -ENODEV; } @@ -584,7 +581,6 @@ static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) pr_err("ACPI call to get KBD backlight status failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("Keyboard backlight status not supported\n"); return -ENODEV; } @@ -603,7 +599,6 @@ static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) pr_err("ACPI call to get the keyboard backlight failed\n"); return LED_OFF; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("Keyboard backlight not supported\n"); return LED_OFF; } @@ -624,7 +619,6 @@ static void toshiba_kbd_backlight_set(struct led_classdev *cdev, pr_err("ACPI call to set KBD Illumination mode failed\n"); return; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("Keyboard backlight not supported\n"); return; } } @@ -758,7 +752,7 @@ static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) out[0] == TOS_NOT_INITIALIZED) pr_err("Accelerometer not initialized\n"); else if (out[0] == TOS_NOT_SUPPORTED) - pr_info("Accelerometer not supported\n"); + return; else if (out[0] == TOS_SUCCESS) dev->accelerometer_supported = 1; } @@ -801,7 +795,6 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) sci_close(dev); return; } else if (out[0] == TOS_NOT_SUPPORTED) { - pr_info("USB Sleep and Charge not supported\n"); sci_close(dev); return; } else if (out[0] == TOS_SUCCESS) { @@ -814,7 +807,7 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) if (ACPI_FAILURE(status)) { pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); } else if (out[0] == TOS_NOT_SUPPORTED) { - pr_info("USB Sleep and Charge not supported\n"); + return; } else if (out[0] == TOS_SUCCESS) { dev->usbsc_bat_level = out[2]; /* Flag as supported */ @@ -837,7 +830,6 @@ static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, pr_err("ACPI call to set USB S&C mode failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("USB Sleep and Charge not supported\n"); return -ENODEV; } else if (result == TOS_INPUT_DATA_ERROR) { return -EIO; @@ -860,7 +852,6 @@ static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, pr_err("ACPI call to set USB S&C mode failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("USB Sleep and Charge not supported\n"); return -ENODEV; } else if (result == TOS_INPUT_DATA_ERROR) { return -EIO; @@ -886,7 +877,6 @@ static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, pr_err("ACPI call to get USB S&C battery level failed\n"); return -EIO; } else if (out[0] == TOS_NOT_SUPPORTED) { - pr_info("USB Sleep and Charge not supported\n"); return -ENODEV; } else if (out[0] == TOS_INPUT_DATA_ERROR) { return -EIO; @@ -915,7 +905,6 @@ static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, pr_err("ACPI call to set USB S&C battery level failed\n"); return -EIO; } else if (out[0] == TOS_NOT_SUPPORTED) { - pr_info("USB Sleep and Charge not supported\n"); return -ENODEV; } else if (out[0] == TOS_INPUT_DATA_ERROR) { return -EIO; @@ -942,7 +931,6 @@ static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, return -EIO; } else if (out[0] == TOS_NOT_SUPPORTED || out[0] == TOS_INPUT_DATA_ERROR) { - pr_info("USB Rapid Charge not supported\n"); return -ENODEV; } @@ -969,7 +957,6 @@ static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, pr_err("ACPI call to set USB Rapid Charge failed\n"); return -EIO; } else if (out[0] == TOS_NOT_SUPPORTED) { - pr_info("USB Rapid Charge not supported\n"); return -ENODEV; } else if (out[0] == TOS_INPUT_DATA_ERROR) { return -EIO; @@ -991,7 +978,6 @@ static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) pr_err("ACPI call to get Sleep and Music failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("Sleep and Music not supported\n"); return -ENODEV; } else if (result == TOS_INPUT_DATA_ERROR) { return -EIO; @@ -1013,7 +999,6 @@ static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) pr_err("ACPI call to set Sleep and Music failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("Sleep and Music not supported\n"); return -ENODEV; } else if (result == TOS_INPUT_DATA_ERROR) { return -EIO; @@ -1036,7 +1021,6 @@ static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) pr_err("ACPI call to get KBD function keys failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("KBD function keys not supported\n"); return -ENODEV; } @@ -1056,7 +1040,6 @@ static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) pr_err("ACPI call to set KBD function keys failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("KBD function keys not supported\n"); return -ENODEV; } @@ -1077,7 +1060,6 @@ static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) pr_err("ACPI call to get Panel Power ON failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("Panel Power on not supported\n"); return -ENODEV; } else if (result == TOS_INPUT_DATA_ERROR) { return -EIO; @@ -1099,7 +1081,6 @@ static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) pr_err("ACPI call to set Panel Power ON failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("Panel Power ON not supported\n"); return -ENODEV; } else if (result == TOS_INPUT_DATA_ERROR) { return -EIO; @@ -1122,7 +1103,6 @@ static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) pr_err("ACPI call to get USB 3 failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("USB 3 not supported\n"); return -ENODEV; } else if (result == TOS_INPUT_DATA_ERROR) { return -EIO; @@ -1144,7 +1124,6 @@ static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) pr_err("ACPI call to set USB 3 failed\n"); return -EIO; } else if (result == TOS_NOT_SUPPORTED) { - pr_info("USB 3 not supported\n"); return -ENODEV; } else if (result == TOS_INPUT_DATA_ERROR) { return -EIO; @@ -1166,7 +1145,6 @@ static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, pr_err("ACPI call to get System type failed\n"); return -EIO; } else if (out[0] == TOS_NOT_SUPPORTED) { - pr_info("System type not supported\n"); return -ENODEV; } @@ -2609,6 +2587,46 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) return 0; } +static void print_supported_features(struct toshiba_acpi_dev *dev) +{ + pr_info("Supported laptop features:"); + + if (dev->hotkey_dev) + pr_cont(" hotkeys"); + if (dev->backlight_dev) + pr_cont(" backlight"); + if (dev->video_supported) + pr_cont(" video-out"); + if (dev->fan_supported) + pr_cont(" fan"); + if (dev->tr_backlight_supported) + pr_cont(" transflective-backlight"); + if (dev->illumination_supported) + pr_cont(" illumination"); + if (dev->kbd_illum_supported) + pr_cont(" keyboard-backlight"); + if (dev->touchpad_supported) + pr_cont(" touchpad"); + if (dev->eco_supported) + pr_cont(" eco-led"); + if (dev->accelerometer_supported) + pr_cont(" accelerometer-axes"); + if (dev->usb_sleep_charge_supported) + pr_cont(" usb-sleep-charge"); + if (dev->usb_rapid_charge_supported) + pr_cont(" usb-rapid-charge"); + if (dev->usb_sleep_music_supported) + pr_cont(" usb-sleep-music"); + if (dev->kbd_function_keys_supported) + pr_cont(" special-function-keys"); + if (dev->panel_power_on_supported) + pr_cont(" panel-power-on"); + if (dev->usb_three_supported) + pr_cont(" usb3"); + + pr_cont("\n"); +} + static int toshiba_acpi_remove(struct acpi_device *acpi_dev) { struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); @@ -2780,6 +2798,8 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) ret = get_fan_status(dev, &dummy); dev->fan_supported = !ret; + print_supported_features(dev); + /* * Enable the "Special Functions" mode only if they are * supported and if they are activated. -- cgit v1.3-6-gb490 From e1a949c1b9883d1d0586b0cbdd2c0cc3f55514bd Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Fri, 31 Jul 2015 21:58:14 -0600 Subject: toshiba_acpi: Refactor *{get, set} functions return value This patch refactors the return value of the driver *{get, set} functions, since the driver default error value is -EIO. All the functions now check for TOS_FAILURE, TOS_NOT_SUPPORTED and TOS_SUCCESS. On TOS_FAILURE a pr_err message is printed informing the user of the error (no change was made to this, except the check was added to the functions not checking for this). On TOS_NOT_SUPPORTED we now return -ENODEV immediately (some functions were returning -EIO and some other were not checking) On TOS_SUCCESS* we now return 0 (as a side effect, a new success value was added, since some functions return one instead of zero to indicate success). As a special case, the LED functions now check for *FAILURE on *set, and check for TOS_FAILURE and TOS_SUCCESS on *get with their "default" return value set to LED_OFF. Also the {lcd, video}_proc* functions were adapted to reflect these changes to their parent HCI functions. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 177 +++++++++++++++++++++--------------- 1 file changed, 104 insertions(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 66b596a7f710..65adb122189f 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -93,6 +93,7 @@ MODULE_LICENSE("GPL"); /* Return codes */ #define TOS_SUCCESS 0x0000 +#define TOS_SUCCESS2 0x0001 #define TOS_OPEN_CLOSE_OK 0x0044 #define TOS_FAILURE 0x1000 #define TOS_NOT_SUPPORTED 0x8000 @@ -469,7 +470,8 @@ static void toshiba_illumination_set(struct led_classdev *cdev, { struct toshiba_acpi_dev *dev = container_of(cdev, struct toshiba_acpi_dev, led_dev); - u32 state, result; + u32 result; + u32 state; /* First request : initialize communication. */ if (!sci_open(dev)) @@ -503,7 +505,7 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { pr_err("ACPI call for illumination failed\n"); return LED_OFF; - } else if (result == TOS_NOT_SUPPORTED) { + } else if (result != TOS_SUCCESS) { return LED_OFF; } @@ -565,7 +567,7 @@ static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) return -ENODEV; } - return 0; + return result == TOS_SUCCESS ? 0 : -EIO; } static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) @@ -584,21 +586,22 @@ static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) return -ENODEV; } - return 0; + return result == TOS_SUCCESS ? 0 : -EIO; } static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) { struct toshiba_acpi_dev *dev = container_of(cdev, struct toshiba_acpi_dev, kbd_led); - u32 state, result; + u32 result; + u32 state; /* Check the keyboard backlight state */ result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { pr_err("ACPI call to get the keyboard backlight failed\n"); return LED_OFF; - } else if (result == TOS_NOT_SUPPORTED) { + } else if (result != TOS_SUCCESS) { return LED_OFF; } @@ -610,7 +613,8 @@ static void toshiba_kbd_backlight_set(struct led_classdev *cdev, { struct toshiba_acpi_dev *dev = container_of(cdev, struct toshiba_acpi_dev, kbd_led); - u32 state, result; + u32 result; + u32 state; /* Set the keyboard backlight state */ state = brightness ? 1 : 0; @@ -640,7 +644,7 @@ static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) return -ENODEV; } - return 0; + return result == TOS_SUCCESS ? 0 : -EIO; } static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) @@ -659,7 +663,7 @@ static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) return -ENODEV; } - return 0; + return result == TOS_SUCCESS ? 0 : -EIO; } /* Eco Mode support */ @@ -709,6 +713,8 @@ toshiba_eco_mode_get_status(struct led_classdev *cdev) if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { pr_err("ACPI call to get ECO led failed\n"); return LED_OFF; + } else if (out[0] != TOS_SUCCESS) { + return LED_OFF; } return out[2] ? LED_FULL : LED_OFF; @@ -769,12 +775,15 @@ static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { pr_err("ACPI call to query the accelerometer failed\n"); return -EIO; + } else if (out[0] == TOS_NOT_SUPPORTED) { + return -ENODEV; + } else if (out[0] == TOS_SUCCESS) { + *xy = out[2]; + *z = out[4]; + return 0; } - *xy = out[2]; - *z = out[4]; - - return 0; + return -EIO; } /* Sleep (Charge and Music) utilities support */ @@ -835,7 +844,7 @@ static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, return -EIO; } - return 0; + return result == TOS_SUCCESS ? 0 : -EIO; } static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, @@ -857,7 +866,7 @@ static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, return -EIO; } - return 0; + return result == TOS_SUCCESS ? 0 : -EIO; } static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, @@ -880,11 +889,12 @@ static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, return -ENODEV; } else if (out[0] == TOS_INPUT_DATA_ERROR) { return -EIO; + } else if (out[0] == TOS_SUCCESS) { + *mode = out[2]; + return 0; } - *mode = out[2]; - - return 0; + return -EIO; } static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, @@ -910,7 +920,7 @@ static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, return -EIO; } - return 0; + return out[0] == TOS_SUCCESS ? 0 : -EIO; } static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, @@ -932,11 +942,12 @@ static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, } else if (out[0] == TOS_NOT_SUPPORTED || out[0] == TOS_INPUT_DATA_ERROR) { return -ENODEV; + } else if (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) { + *state = out[2]; + return 0; } - *state = out[2]; - - return 0; + return -EIO; } static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, @@ -962,7 +973,7 @@ static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, return -EIO; } - return 0; + return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO; } static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) @@ -983,7 +994,7 @@ static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) return -EIO; } - return 0; + return result = TOS_SUCCESS ? 0 : -EIO; } static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) @@ -1004,7 +1015,7 @@ static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) return -EIO; } - return 0; + return result == TOS_SUCCESS ? 0 : -EIO; } /* Keyboard function keys */ @@ -1024,7 +1035,7 @@ static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) return -ENODEV; } - return 0; + return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; } static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) @@ -1043,7 +1054,7 @@ static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) return -ENODEV; } - return 0; + return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; } /* Panel Power ON */ @@ -1065,7 +1076,7 @@ static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) return -EIO; } - return 0; + return result == TOS_SUCCESS ? 0 : -EIO; } static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) @@ -1086,7 +1097,7 @@ static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) return -EIO; } - return 0; + return result == TOS_SUCCESS ? 0 : -EIO; } /* USB Three */ @@ -1108,7 +1119,7 @@ static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) return -EIO; } - return 0; + return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; } static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) @@ -1129,7 +1140,7 @@ static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) return -EIO; } - return 0; + return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; } /* Hotkey Event type */ @@ -1146,26 +1157,37 @@ static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, return -EIO; } else if (out[0] == TOS_NOT_SUPPORTED) { return -ENODEV; + } else if (out[0] == TOS_SUCCESS) { + *type = out[3]; + return 0; } - *type = out[3]; - - return 0; + return -EIO; } /* Transflective Backlight */ static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) { - u32 hci_result = hci_read(dev, HCI_TR_BACKLIGHT, status); + u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status); + + if (result == TOS_FAILURE) + pr_err("ACPI call to get Transflective Backlight failed\n"); + else if (result == TOS_NOT_SUPPORTED) + return -ENODEV; - return hci_result == TOS_SUCCESS ? 0 : -EIO; + return result == TOS_SUCCESS ? 0 : -EIO; } static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status) { - u32 hci_result = hci_write(dev, HCI_TR_BACKLIGHT, !status); + u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status); + + if (result == TOS_FAILURE) + pr_err("ACPI call to set Transflective Backlight failed\n"); + else if (result == TOS_NOT_SUPPORTED) + return -ENODEV; - return hci_result == TOS_SUCCESS ? 0 : -EIO; + return result == TOS_SUCCESS ? 0 : -EIO; } static struct proc_dir_entry *toshiba_proc_dir; @@ -1173,7 +1195,7 @@ static struct proc_dir_entry *toshiba_proc_dir; /* LCD Brightness */ static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) { - u32 hci_result; + u32 result; u32 value; int brightness = 0; @@ -1187,8 +1209,12 @@ static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) brightness++; } - hci_result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); - if (hci_result == TOS_SUCCESS) + result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); + if (result == TOS_FAILURE) + pr_err("ACPI call to get LCD Brightness failed\n"); + else if (result == TOS_NOT_SUPPORTED) + return -ENODEV; + if (result == TOS_SUCCESS) return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); return -EIO; @@ -1204,8 +1230,8 @@ static int get_lcd_brightness(struct backlight_device *bd) static int lcd_proc_show(struct seq_file *m, void *v) { struct toshiba_acpi_dev *dev = m->private; - int value; int levels; + int value; if (!dev->backlight_dev) return -ENODEV; @@ -1219,6 +1245,7 @@ static int lcd_proc_show(struct seq_file *m, void *v) } pr_err("Error reading LCD brightness\n"); + return -EIO; } @@ -1229,7 +1256,7 @@ static int lcd_proc_open(struct inode *inode, struct file *file) static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) { - u32 hci_result; + u32 result; if (dev->tr_backlight_supported) { int ret = set_tr_backlight_status(dev, !value); @@ -1241,8 +1268,13 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) } value = value << HCI_LCD_BRIGHTNESS_SHIFT; - hci_result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); - return hci_result == TOS_SUCCESS ? 0 : -EIO; + result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); + if (result == TOS_FAILURE) + pr_err("ACPI call to set LCD Brightness failed\n"); + else if (result == TOS_NOT_SUPPORTED) + return -ENODEV; + + return result == TOS_SUCCESS ? 0 : -EIO; } static int set_lcd_status(struct backlight_device *bd) @@ -1258,24 +1290,22 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf, struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); char cmd[42]; size_t len; - int value; - int ret; int levels = dev->backlight_dev->props.max_brightness + 1; + int value; len = min(count, sizeof(cmd) - 1); if (copy_from_user(cmd, buf, len)) return -EFAULT; cmd[len] = '\0'; - if (sscanf(cmd, " brightness : %i", &value) == 1 && - value >= 0 && value < levels) { - ret = set_lcd_brightness(dev, value); - if (ret == 0) - ret = count; - } else { - ret = -EINVAL; - } - return ret; + if (sscanf(cmd, " brightness : %i", &value) != 1 && + value < 0 && value > levels) + return -EINVAL; + + if (set_lcd_brightness(dev, value)) + return -EIO; + + return count; } static const struct file_operations lcd_proc_fops = { @@ -1287,22 +1317,25 @@ static const struct file_operations lcd_proc_fops = { .write = lcd_proc_write, }; +/* Video-Out */ static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) { - u32 hci_result; + u32 result = hci_read(dev, HCI_VIDEO_OUT, status); + + if (result == TOS_FAILURE) + pr_err("ACPI call to get Video-Out failed\n"); + else if (result == TOS_NOT_SUPPORTED) + return -ENODEV; - hci_result = hci_read(dev, HCI_VIDEO_OUT, status); - return hci_result == TOS_SUCCESS ? 0 : -EIO; + return result == TOS_SUCCESS ? 0 : -EIO; } static int video_proc_show(struct seq_file *m, void *v) { struct toshiba_acpi_dev *dev = m->private; u32 value; - int ret; - ret = get_video_status(dev, &value); - if (!ret) { + if (!get_video_status(dev, &value)) { int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; @@ -1310,9 +1343,10 @@ static int video_proc_show(struct seq_file *m, void *v) seq_printf(m, "lcd_out: %d\n", is_lcd); seq_printf(m, "crt_out: %d\n", is_crt); seq_printf(m, "tv_out: %d\n", is_tv); + return 0; } - return ret; + return -EIO; } static int video_proc_open(struct inode *inode, struct file *file) @@ -1324,13 +1358,14 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); - char *cmd, *buffer; - int ret; - int value; + char *buffer; + char *cmd; int remain = count; int lcd_out = -1; int crt_out = -1; int tv_out = -1; + int value; + int ret; u32 video_out; cmd = kmalloc(count + 1, GFP_KERNEL); @@ -1382,7 +1417,7 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf, ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); } - return ret ? ret : count; + return ret ? -EIO : count; } static const struct file_operations video_proc_fops = { @@ -1403,10 +1438,8 @@ static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) pr_err("ACPI call to get Fan status failed\n"); else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - else if (result == TOS_SUCCESS) - return 0; - return -EIO; + return result == TOS_SUCCESS ? 0 : -EIO; } static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status) @@ -1417,10 +1450,8 @@ static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status) pr_err("ACPI call to set Fan status failed\n"); else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - else if (result == TOS_SUCCESS) - return 0; - return -EIO; + return result == TOS_SUCCESS ? 0 : -EIO; } static int fan_proc_show(struct seq_file *m, void *v) -- cgit v1.3-6-gb490 From a6b5354f422a1f1cd48a94ed64e54989f9ea7ee2 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Fri, 31 Jul 2015 21:58:15 -0600 Subject: toshiba_acpi: Remove unnecessary checks and returns in HCI/SCI functions A previous patch added explicit feature checks for support, *SUCCESS* and *FAILURE to the HCI/SCI *{get, set} functions. This patch removes some unnedded checks to the driver HCI/SCI functions given that the default error return value is now set to -EIO, there is no need to check for other error values other than the ones currently checking for. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 169 ++++++++++-------------------------- 1 file changed, 44 insertions(+), 125 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 65adb122189f..c18469903eee 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -459,8 +459,6 @@ static void toshiba_illumination_available(struct toshiba_acpi_dev *dev) sci_close(dev); if (ACPI_FAILURE(status)) pr_err("ACPI call to query Illumination support failed\n"); - else if (out[0] == TOS_NOT_SUPPORTED) - return; else if (out[0] == TOS_SUCCESS) dev->illumination_supported = 1; } @@ -481,12 +479,8 @@ static void toshiba_illumination_set(struct led_classdev *cdev, state = brightness ? 1 : 0; result = sci_write(dev, SCI_ILLUMINATION, state); sci_close(dev); - if (result == TOS_FAILURE) { + if (result == TOS_FAILURE) pr_err("ACPI call for illumination failed\n"); - return; - } else if (result == TOS_NOT_SUPPORTED) { - return; - } } static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) @@ -502,7 +496,7 @@ static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) /* Check the illumination */ result = sci_read(dev, SCI_ILLUMINATION, &state); sci_close(dev); - if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { + if (result == TOS_FAILURE) { pr_err("ACPI call for illumination failed\n"); return LED_OFF; } else if (result != TOS_SUCCESS) { @@ -527,10 +521,8 @@ static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) status = tci_raw(dev, in, out); sci_close(dev); - if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { + if (ACPI_FAILURE(status)) { pr_err("ACPI call to query kbd illumination support failed\n"); - } else if (out[0] == TOS_NOT_SUPPORTED) { - return; } else if (out[0] == TOS_SUCCESS) { /* * Check for keyboard backlight timeout max value, @@ -560,12 +552,10 @@ static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); sci_close(dev); - if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { + if (result == TOS_FAILURE) pr_err("ACPI call to set KBD backlight status failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } return result == TOS_SUCCESS ? 0 : -EIO; } @@ -579,12 +569,10 @@ static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); sci_close(dev); - if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { + if (result == TOS_FAILURE) pr_err("ACPI call to get KBD backlight status failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } return result == TOS_SUCCESS ? 0 : -EIO; } @@ -598,7 +586,7 @@ static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) /* Check the keyboard backlight state */ result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); - if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { + if (result == TOS_FAILURE) { pr_err("ACPI call to get the keyboard backlight failed\n"); return LED_OFF; } else if (result != TOS_SUCCESS) { @@ -619,12 +607,8 @@ static void toshiba_kbd_backlight_set(struct led_classdev *cdev, /* Set the keyboard backlight state */ state = brightness ? 1 : 0; result = hci_write(dev, HCI_KBD_ILLUMINATION, state); - if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { + if (result == TOS_FAILURE) pr_err("ACPI call to set KBD Illumination mode failed\n"); - return; - } else if (result == TOS_NOT_SUPPORTED) { - return; - } } /* TouchPad support */ @@ -637,12 +621,10 @@ static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) result = sci_write(dev, SCI_TOUCHPAD, state); sci_close(dev); - if (result == TOS_FAILURE) { + if (result == TOS_FAILURE) pr_err("ACPI call to set the touchpad failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } return result == TOS_SUCCESS ? 0 : -EIO; } @@ -656,12 +638,10 @@ static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) result = sci_read(dev, SCI_TOUCHPAD, state); sci_close(dev); - if (result == TOS_FAILURE) { + if (result == TOS_FAILURE) pr_err("ACPI call to query the touchpad failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } return result == TOS_SUCCESS ? 0 : -EIO; } @@ -679,8 +659,6 @@ static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) status = tci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get ECO led failed\n"); - } else if (out[0] == TOS_NOT_INSTALLED) { - pr_info("ECO led not installed"); } else if (out[0] == TOS_INPUT_DATA_ERROR) { /* * If we receive 0x8300 (Input Data Error), it means that the @@ -693,7 +671,7 @@ static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) */ in[3] = 1; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) + if (ACPI_FAILURE(status)) pr_err("ACPI call to get ECO led failed\n"); else if (out[0] == TOS_SUCCESS) dev->eco_supported = 1; @@ -710,7 +688,7 @@ toshiba_eco_mode_get_status(struct led_classdev *cdev) acpi_status status; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { + if (ACPI_FAILURE(status)) { pr_err("ACPI call to get ECO led failed\n"); return LED_OFF; } else if (out[0] != TOS_SUCCESS) { @@ -732,10 +710,8 @@ static void toshiba_eco_mode_set_status(struct led_classdev *cdev, /* Switch the Eco Mode led on/off */ in[2] = (brightness) ? 1 : 0; status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { + if (ACPI_FAILURE(status)) pr_err("ACPI call to set ECO led failed\n"); - return; - } } /* Accelerometer support */ @@ -752,19 +728,14 @@ static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) * this call also serves as initialization */ status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) + if (ACPI_FAILURE(status)) pr_err("ACPI call to query the accelerometer failed\n"); - else if (out[0] == TOS_DATA_NOT_AVAILABLE || - out[0] == TOS_NOT_INITIALIZED) - pr_err("Accelerometer not initialized\n"); - else if (out[0] == TOS_NOT_SUPPORTED) - return; else if (out[0] == TOS_SUCCESS) dev->accelerometer_supported = 1; } static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, - u32 *xy, u32 *z) + u32 *xy, u32 *z) { u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; u32 out[TCI_WORDS]; @@ -772,7 +743,7 @@ static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, /* Check the Accelerometer status */ status = tci_raw(dev, in, out); - if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { + if (ACPI_FAILURE(status)) { pr_err("ACPI call to query the accelerometer failed\n"); return -EIO; } else if (out[0] == TOS_NOT_SUPPORTED) { @@ -815,8 +786,6 @@ static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); - } else if (out[0] == TOS_NOT_SUPPORTED) { - return; } else if (out[0] == TOS_SUCCESS) { dev->usbsc_bat_level = out[2]; /* Flag as supported */ @@ -835,14 +804,10 @@ static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); sci_close(dev); - if (result == TOS_FAILURE) { + if (result == TOS_FAILURE) pr_err("ACPI call to set USB S&C mode failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } else if (result == TOS_INPUT_DATA_ERROR) { - return -EIO; - } return result == TOS_SUCCESS ? 0 : -EIO; } @@ -857,14 +822,10 @@ static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); sci_close(dev); - if (result == TOS_FAILURE) { + if (result == TOS_FAILURE) pr_err("ACPI call to set USB S&C mode failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } else if (result == TOS_INPUT_DATA_ERROR) { - return -EIO; - } return result == TOS_SUCCESS ? 0 : -EIO; } @@ -884,11 +845,8 @@ static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get USB S&C battery level failed\n"); - return -EIO; } else if (out[0] == TOS_NOT_SUPPORTED) { return -ENODEV; - } else if (out[0] == TOS_INPUT_DATA_ERROR) { - return -EIO; } else if (out[0] == TOS_SUCCESS) { *mode = out[2]; return 0; @@ -911,14 +869,10 @@ static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, in[5] = SCI_USB_CHARGE_BAT_LVL; status = tci_raw(dev, in, out); sci_close(dev); - if (ACPI_FAILURE(status)) { + if (ACPI_FAILURE(status)) pr_err("ACPI call to set USB S&C battery level failed\n"); - return -EIO; - } else if (out[0] == TOS_NOT_SUPPORTED) { + else if (out[0] == TOS_NOT_SUPPORTED) return -ENODEV; - } else if (out[0] == TOS_INPUT_DATA_ERROR) { - return -EIO; - } return out[0] == TOS_SUCCESS ? 0 : -EIO; } @@ -938,9 +892,7 @@ static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, sci_close(dev); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get USB Rapid Charge failed\n"); - return -EIO; - } else if (out[0] == TOS_NOT_SUPPORTED || - out[0] == TOS_INPUT_DATA_ERROR) { + } else if (out[0] == TOS_NOT_SUPPORTED) { return -ENODEV; } else if (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) { *state = out[2]; @@ -964,14 +916,10 @@ static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, in[5] = SCI_USB_CHARGE_RAPID_DSP; status = tci_raw(dev, in, out); sci_close(dev); - if (ACPI_FAILURE(status)) { + if (ACPI_FAILURE(status)) pr_err("ACPI call to set USB Rapid Charge failed\n"); - return -EIO; - } else if (out[0] == TOS_NOT_SUPPORTED) { + else if (out[0] == TOS_NOT_SUPPORTED) return -ENODEV; - } else if (out[0] == TOS_INPUT_DATA_ERROR) { - return -EIO; - } return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO; } @@ -985,14 +933,10 @@ static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); sci_close(dev); - if (result == TOS_FAILURE) { + if (result == TOS_FAILURE) pr_err("ACPI call to get Sleep and Music failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } else if (result == TOS_INPUT_DATA_ERROR) { - return -EIO; - } return result = TOS_SUCCESS ? 0 : -EIO; } @@ -1006,14 +950,10 @@ static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); sci_close(dev); - if (result == TOS_FAILURE) { + if (result == TOS_FAILURE) pr_err("ACPI call to set Sleep and Music failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } else if (result == TOS_INPUT_DATA_ERROR) { - return -EIO; - } return result == TOS_SUCCESS ? 0 : -EIO; } @@ -1028,12 +968,10 @@ static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); sci_close(dev); - if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { + if (result == TOS_FAILURE) pr_err("ACPI call to get KBD function keys failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; } @@ -1047,12 +985,10 @@ static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); sci_close(dev); - if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { + if (result == TOS_FAILURE) pr_err("ACPI call to set KBD function keys failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; } @@ -1067,14 +1003,10 @@ static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) result = sci_read(dev, SCI_PANEL_POWER_ON, state); sci_close(dev); - if (result == TOS_FAILURE) { + if (result == TOS_FAILURE) pr_err("ACPI call to get Panel Power ON failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } else if (result == TOS_INPUT_DATA_ERROR) { - return -EIO; - } return result == TOS_SUCCESS ? 0 : -EIO; } @@ -1088,14 +1020,10 @@ static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) result = sci_write(dev, SCI_PANEL_POWER_ON, state); sci_close(dev); - if (result == TOS_FAILURE) { + if (result == TOS_FAILURE) pr_err("ACPI call to set Panel Power ON failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } else if (result == TOS_INPUT_DATA_ERROR) { - return -EIO; - } return result == TOS_SUCCESS ? 0 : -EIO; } @@ -1110,14 +1038,10 @@ static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) result = sci_read(dev, SCI_USB_THREE, state); sci_close(dev); - if (result == TOS_FAILURE) { + if (result == TOS_FAILURE) pr_err("ACPI call to get USB 3 failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } else if (result == TOS_INPUT_DATA_ERROR) { - return -EIO; - } return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; } @@ -1131,14 +1055,10 @@ static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) result = sci_write(dev, SCI_USB_THREE, state); sci_close(dev); - if (result == TOS_FAILURE) { + if (result == TOS_FAILURE) pr_err("ACPI call to set USB 3 failed\n"); - return -EIO; - } else if (result == TOS_NOT_SUPPORTED) { + else if (result == TOS_NOT_SUPPORTED) return -ENODEV; - } else if (result == TOS_INPUT_DATA_ERROR) { - return -EIO; - } return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; } @@ -1154,7 +1074,6 @@ static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, status = tci_raw(dev, in, out); if (ACPI_FAILURE(status)) { pr_err("ACPI call to get System type failed\n"); - return -EIO; } else if (out[0] == TOS_NOT_SUPPORTED) { return -ENODEV; } else if (out[0] == TOS_SUCCESS) { -- cgit v1.3-6-gb490 From 495078f892eef0ac791fd2b32393e1501b5c1c5e Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Fri, 31 Jul 2015 21:58:16 -0600 Subject: toshiba_acpi: Bump driver version to 0.23 Given that some features were added (/dev/toshiba_acpi device), some clean-ups and minor (cosmetic) changes all over the driver code, bump the driver version to 0.23 to reflect these overall changes. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index c18469903eee..6740c513919c 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -31,7 +31,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#define TOSHIBA_ACPI_VERSION "0.22" +#define TOSHIBA_ACPI_VERSION "0.23" #define PROC_INTERFACE_VERSION 1 #include -- cgit v1.3-6-gb490 From 9dd068a4b85a68733213c874d08ef768bbec8d01 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Fri, 31 Jul 2015 17:03:13 +0200 Subject: soc: mediatek: Fix SCPSYS compilation SCPSYS driver misses the module.h include which makes it fail when compiling with allmodconf. This patch fixes this. Signed-off-by: Matthias Brugger Acked-by: Sascha Hauer Signed-off-by: Olof Johansson --- drivers/soc/mediatek/mtk-scpsys.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index 43a79ed761c4..164a7d8439b1 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include -- cgit v1.3-6-gb490 From 245d96670d2655f70f4445d5247f26afbe705c84 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Mon, 3 Aug 2015 20:24:56 +0100 Subject: drm/i915:skl: Add WaEnableGapsTsvCreditFix Cc: Ben Widawsky Cc: Joonas Lahtinen Signed-off-by: Arun Siluvery Tested-by: Ben Widawsky Reviewed-by: Ben Widawsky Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90854 Tested-by: Mika Kuoppala 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(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8cf77568f7e1..0f67f3da0762 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6851,6 +6851,9 @@ enum skl_disp_power_wells { #define GEN7_MISCCPCTL (0x9424) #define GEN7_DOP_CLOCK_GATE_ENABLE (1<<0) +#define GEN8_GARBCNTL 0xB004 +#define GEN9_GAPS_TSV_CREDIT_DISABLE (1<<7) + /* IVYBRIDGE DPF */ #define GEN7_L3CDERRST1 0xB008 /* L3CD Error Status 1 */ #define HSW_L3CDERRST11 0xB208 /* L3CD Error Status register 1 slice 1 */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a1d92b7f3e35..f7f01dc05c4e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -102,6 +102,12 @@ static void skl_init_clock_gating(struct drm_device *dev) /* WaDisableLSQCROPERFforOCL:skl */ I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | GEN8_LQSC_RO_PERF_DIS); + + /* WaEnableGapsTsvCreditFix:skl */ + if (IS_SKYLAKE(dev) && (INTEL_REVID(dev) >= SKL_REVID_C0)) { + I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | + GEN9_GAPS_TSV_CREDIT_DISABLE)); + } } static void bxt_init_clock_gating(struct drm_device *dev) -- cgit v1.3-6-gb490 From 80aa93128653c5f2502053c0d9740b336d975667 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 3 Aug 2015 13:09:11 -0700 Subject: drm/i915: disable_shared_pll doesn't work on pre-gen5 Looks like commit eddfcbcdc27fbecb33bff098967bbdd7ca75bfa6 Author: Maarten Lankhorst Date: Mon Jun 15 12:33:53 2015 +0200 drm/i915: Update less state during modeset. introduced the unconditional calling of disable_shared_dpll, but didn't fix up pre-gen5 to avoid the BUG_ON at the top of the function. So change the BUG_ON into a gen check (alternately we could move the BUG_ON until later, since we shouldn't have a pll struct here either, but this seems clearer to read). This fixes a crash on load on my x200s platform. Signed-off-by: Jesse Barnes Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f4ed4f13646c..9e4ced583ef0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1936,7 +1936,9 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); /* PCH only available on ILK+ */ - BUG_ON(INTEL_INFO(dev)->gen < 5); + if (INTEL_INFO(dev)->gen < 5) + return; + if (pll == NULL) return; -- cgit v1.3-6-gb490 From 757fe8d514a9bab55156dfb2c4a03e56ba96a028 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 5 Aug 2015 10:04:05 +0300 Subject: spi: spi-pxa2xx: Remove unused legacy null dma buffer and allocation for it Remove null_dma_buf variable and extra allocation for it. It is not needed since commit 6356437e65c2 ("spi: spi-pxa2xx: remove legacy PXA DMA bits"). Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- drivers/spi/spi-pxa2xx.c | 4 +--- drivers/spi/spi-pxa2xx.h | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 246ffabc72c9..fdd791977041 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1414,8 +1414,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) return -ENODEV; } - /* Allocate master with space for drv_data and null dma buffer */ - master = spi_alloc_master(dev, sizeof(struct driver_data) + 16); + master = spi_alloc_master(dev, sizeof(struct driver_data)); if (!master) { dev_err(&pdev->dev, "cannot alloc spi_master\n"); pxa_ssp_free(ssp); @@ -1442,7 +1441,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) master->auto_runtime_pm = true; drv_data->ssp_type = ssp->type; - drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT); drv_data->ioaddr = ssp->mmio_base; drv_data->ssdr_physical = ssp->phys_base + SSDR; diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h index 3b69c46bfbc9..0a9b6390a817 100644 --- a/drivers/spi/spi-pxa2xx.h +++ b/drivers/spi/spi-pxa2xx.h @@ -36,9 +36,6 @@ struct driver_data { /* PXA hookup */ struct pxa2xx_spi_master *master_info; - /* PXA private DMA setup stuff */ - u32 *null_dma_buf; - /* SSP register addresses */ void __iomem *ioaddr; u32 ssdr_physical; -- cgit v1.3-6-gb490 From 63d5e127de8287c4ae80f43cda8cb9c06e612929 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:01:10 +0900 Subject: mailbox: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Acked-by: Lee Jones Reviewed-by: Eric Anholt Signed-off-by: Jassi Brar --- drivers/mailbox/bcm2835-mailbox.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm2835-mailbox.c b/drivers/mailbox/bcm2835-mailbox.c index 0b47dd42f3bd..cfb4b4496dd9 100644 --- a/drivers/mailbox/bcm2835-mailbox.c +++ b/drivers/mailbox/bcm2835-mailbox.c @@ -204,7 +204,6 @@ MODULE_DEVICE_TABLE(of, bcm2835_mbox_of_match); static struct platform_driver bcm2835_mbox_driver = { .driver = { .name = "bcm2835-mbox", - .owner = THIS_MODULE, .of_match_table = bcm2835_mbox_of_match, }, .probe = bcm2835_mbox_probe, -- cgit v1.3-6-gb490 From 12617971c443c50750a12a77ea0e08319d161975 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 25 Jun 2015 10:10:36 -0700 Subject: drm/vmwgfx: Fix an fb unlocking bug A regression introduced when the master ttm lock was split into two. Reported-and-tested-by: Brian Paul Signed-off-by: Thomas Hellstrom Reviewed-by: Brian Paul --- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 0a474f391fad..e2d40ebd5455 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -402,12 +402,12 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv, *out = vmw_bo; - ttm_write_unlock(&vmw_priv->fbdev_master.lock); + ttm_write_unlock(&vmw_priv->reservation_sem); return 0; err_unlock: - ttm_write_unlock(&vmw_priv->fbdev_master.lock); + ttm_write_unlock(&vmw_priv->reservation_sem); return ret; } -- cgit v1.3-6-gb490 From 153b3d5b037eeb01d1e5610958a5bbd79885b2be Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 25 Jun 2015 10:47:43 -0700 Subject: vmwgfx: Rework device initialization This commit reworks device initialization so that we always enable the FIFO at driver load, deferring SVGA enable until either first modeset or fbdev enable. This should always leave the fifo properly enabled for render- and control nodes. In addition, *) We disable the use of VRAM when SVGA is not enabled. *) We simplify PM support so that we only throw out resources on hibernate, not on suspend, since the device keeps its state on suspend. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_context.c | 8 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 337 ++++++++++++++++++-------------- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 19 +- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 4 + drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 12 +- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_mob.c | 6 +- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 12 +- 10 files changed, 230 insertions(+), 174 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index 5ac92874404d..a8e370a55e90 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -140,7 +140,7 @@ static void vmw_hw_context_destroy(struct vmw_resource *res) cmd->body.cid = cpu_to_le32(res->id); vmw_fifo_commit(dev_priv, sizeof(*cmd)); - vmw_3d_resource_dec(dev_priv, false); + vmw_fifo_resource_dec(dev_priv); } static int vmw_gb_context_init(struct vmw_private *dev_priv, @@ -220,7 +220,7 @@ static int vmw_context_init(struct vmw_private *dev_priv, cmd->body.cid = cpu_to_le32(res->id); vmw_fifo_commit(dev_priv, sizeof(*cmd)); - (void) vmw_3d_resource_inc(dev_priv, false); + vmw_fifo_resource_inc(dev_priv); vmw_resource_activate(res, vmw_hw_context_destroy); return 0; @@ -281,7 +281,7 @@ static int vmw_gb_context_create(struct vmw_resource *res) cmd->header.size = sizeof(cmd->body); cmd->body.cid = res->id; vmw_fifo_commit(dev_priv, sizeof(*cmd)); - (void) vmw_3d_resource_inc(dev_priv, false); + vmw_fifo_resource_inc(dev_priv); return 0; @@ -414,7 +414,7 @@ static int vmw_gb_context_destroy(struct vmw_resource *res) if (dev_priv->query_cid == res->id) dev_priv->query_cid_valid = false; vmw_resource_release_id(res); - vmw_3d_resource_dec(dev_priv, false); + vmw_fifo_resource_dec(dev_priv); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 620bb5cf617c..a4766acd0ea2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -339,24 +339,47 @@ static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) return ret; } -static int vmw_request_device(struct vmw_private *dev_priv) +/** + * vmw_request_device_late - Perform late device setup + * + * @dev_priv: Pointer to device private. + * + * This function performs setup of otables and enables large command + * buffer submission. These tasks are split out to a separate function + * because it reverts vmw_release_device_early and is intended to be used + * by an error path in the hibernation code. + */ +static int vmw_request_device_late(struct vmw_private *dev_priv) { int ret; - ret = vmw_fifo_init(dev_priv, &dev_priv->fifo); - if (unlikely(ret != 0)) { - DRM_ERROR("Unable to initialize FIFO.\n"); - return ret; - } - vmw_fence_fifo_up(dev_priv->fman); if (dev_priv->has_mob) { ret = vmw_otables_setup(dev_priv); if (unlikely(ret != 0)) { DRM_ERROR("Unable to initialize " "guest Memory OBjects.\n"); - goto out_no_mob; + return ret; } } + + return 0; +} + +static int vmw_request_device(struct vmw_private *dev_priv) +{ + int ret; + + ret = vmw_fifo_init(dev_priv, &dev_priv->fifo); + if (unlikely(ret != 0)) { + DRM_ERROR("Unable to initialize FIFO.\n"); + return ret; + } + vmw_fence_fifo_up(dev_priv->fman); + + ret = vmw_request_device_late(dev_priv); + if (ret) + goto out_no_mob; + ret = vmw_dummy_query_bo_create(dev_priv); if (unlikely(ret != 0)) goto out_no_query_bo; @@ -364,15 +387,25 @@ static int vmw_request_device(struct vmw_private *dev_priv) return 0; out_no_query_bo: - if (dev_priv->has_mob) + if (dev_priv->has_mob) { + (void) ttm_bo_evict_mm(&dev_priv->bdev, VMW_PL_MOB); vmw_otables_takedown(dev_priv); + } out_no_mob: vmw_fence_fifo_down(dev_priv->fman); vmw_fifo_release(dev_priv, &dev_priv->fifo); return ret; } -static void vmw_release_device(struct vmw_private *dev_priv) +/** + * vmw_release_device_early - Early part of fifo takedown. + * + * @dev_priv: Pointer to device private struct. + * + * This is the first part of command submission takedown, to be called before + * buffer management is taken down. + */ +static void vmw_release_device_early(struct vmw_private *dev_priv) { /* * Previous destructions should've released @@ -382,64 +415,24 @@ static void vmw_release_device(struct vmw_private *dev_priv) BUG_ON(dev_priv->pinned_bo != NULL); ttm_bo_unref(&dev_priv->dummy_query_bo); - if (dev_priv->has_mob) + if (dev_priv->has_mob) { + ttm_bo_evict_mm(&dev_priv->bdev, VMW_PL_MOB); vmw_otables_takedown(dev_priv); - vmw_fence_fifo_down(dev_priv->fman); - vmw_fifo_release(dev_priv, &dev_priv->fifo); -} - - -/** - * Increase the 3d resource refcount. - * If the count was prevously zero, initialize the fifo, switching to svga - * mode. Note that the master holds a ref as well, and may request an - * explicit switch to svga mode if fb is not running, using @unhide_svga. - */ -int vmw_3d_resource_inc(struct vmw_private *dev_priv, - bool unhide_svga) -{ - int ret = 0; - - mutex_lock(&dev_priv->release_mutex); - if (unlikely(dev_priv->num_3d_resources++ == 0)) { - ret = vmw_request_device(dev_priv); - if (unlikely(ret != 0)) - --dev_priv->num_3d_resources; - } else if (unhide_svga) { - vmw_write(dev_priv, SVGA_REG_ENABLE, - vmw_read(dev_priv, SVGA_REG_ENABLE) & - ~SVGA_REG_ENABLE_HIDE); } - - mutex_unlock(&dev_priv->release_mutex); - return ret; } /** - * Decrease the 3d resource refcount. - * If the count reaches zero, disable the fifo, switching to vga mode. - * Note that the master holds a refcount as well, and may request an - * explicit switch to vga mode when it releases its refcount to account - * for the situation of an X server vt switch to VGA with 3d resources - * active. + * vmw_release_device_late - Late part of fifo takedown. + * + * @dev_priv: Pointer to device private struct. + * + * This is the last part of the command submission takedown, to be called when + * command submission is no longer needed. It may wait on pending fences. */ -void vmw_3d_resource_dec(struct vmw_private *dev_priv, - bool hide_svga) +static void vmw_release_device_late(struct vmw_private *dev_priv) { - int32_t n3d; - - mutex_lock(&dev_priv->release_mutex); - if (unlikely(--dev_priv->num_3d_resources == 0)) - vmw_release_device(dev_priv); - else if (hide_svga) - vmw_write(dev_priv, SVGA_REG_ENABLE, - vmw_read(dev_priv, SVGA_REG_ENABLE) | - SVGA_REG_ENABLE_HIDE); - - n3d = (int32_t) dev_priv->num_3d_resources; - mutex_unlock(&dev_priv->release_mutex); - - BUG_ON(n3d < 0); + vmw_fence_fifo_down(dev_priv->fman); + vmw_fifo_release(dev_priv, &dev_priv->fifo); } /** @@ -603,6 +596,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) spin_lock_init(&dev_priv->hw_lock); spin_lock_init(&dev_priv->waiter_lock); spin_lock_init(&dev_priv->cap_lock); + spin_lock_init(&dev_priv->svga_lock); for (i = vmw_res_context; i < vmw_res_max; ++i) { idr_init(&dev_priv->res_idr[i]); @@ -714,17 +708,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->active_master = &dev_priv->fbdev_master; - ret = ttm_bo_device_init(&dev_priv->bdev, - dev_priv->bo_global_ref.ref.object, - &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"); - goto out_err1; - } - dev_priv->mmio_mtrr = arch_phys_wc_add(dev_priv->mmio_start, dev_priv->mmio_size); @@ -787,13 +770,28 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) goto out_no_fman; } + ret = ttm_bo_device_init(&dev_priv->bdev, + dev_priv->bo_global_ref.ref.object, + &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"); + goto out_no_bdev; + } + /* + * Enable VRAM, but initially don't use it until SVGA is enabled and + * unhidden. + */ ret = ttm_bo_init_mm(&dev_priv->bdev, TTM_PL_VRAM, (dev_priv->vram_size >> PAGE_SHIFT)); if (unlikely(ret != 0)) { DRM_ERROR("Failed initializing memory manager for VRAM.\n"); goto out_no_vram; } + dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; dev_priv->has_gmr = true; if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) || @@ -814,18 +812,18 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) } } - vmw_kms_save_vga(dev_priv); - - /* Start kms and overlay systems, needs fifo. */ ret = vmw_kms_init(dev_priv); if (unlikely(ret != 0)) goto out_no_kms; vmw_overlay_init(dev_priv); + ret = vmw_request_device(dev_priv); + if (ret) + goto out_no_fifo; + if (dev_priv->enable_fb) { - ret = vmw_3d_resource_inc(dev_priv, true); - if (unlikely(ret != 0)) - goto out_no_fifo; + vmw_fifo_resource_inc(dev_priv); + vmw_svga_enable(dev_priv); vmw_fb_init(dev_priv); } @@ -838,13 +836,14 @@ out_no_fifo: vmw_overlay_close(dev_priv); vmw_kms_close(dev_priv); out_no_kms: - vmw_kms_restore_vga(dev_priv); if (dev_priv->has_mob) (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); if (dev_priv->has_gmr) (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); out_no_vram: + (void)ttm_bo_device_release(&dev_priv->bdev); +out_no_bdev: vmw_fence_manager_takedown(dev_priv->fman); out_no_fman: if (dev_priv->capabilities & SVGA_CAP_IRQMASK) @@ -860,8 +859,6 @@ out_err4: iounmap(dev_priv->mmio_virt); out_err3: arch_phys_wc_del(dev_priv->mmio_mtrr); - (void)ttm_bo_device_release(&dev_priv->bdev); -out_err1: vmw_ttm_global_release(dev_priv); out_err0: for (i = vmw_res_context; i < vmw_res_max; ++i) @@ -883,18 +880,22 @@ static int vmw_driver_unload(struct drm_device *dev) vfree(dev_priv->ctx.cmd_bounce); if (dev_priv->enable_fb) { vmw_fb_close(dev_priv); - vmw_kms_restore_vga(dev_priv); - vmw_3d_resource_dec(dev_priv, false); + vmw_fifo_resource_dec(dev_priv); + vmw_svga_disable(dev_priv); } + vmw_kms_close(dev_priv); vmw_overlay_close(dev_priv); - if (dev_priv->has_mob) - (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); if (dev_priv->has_gmr) (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR); (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM); + vmw_release_device_early(dev_priv); + if (dev_priv->has_mob) + (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB); + (void) ttm_bo_device_release(&dev_priv->bdev); + vmw_release_device_late(dev_priv); vmw_fence_manager_takedown(dev_priv->fman); if (dev_priv->capabilities & SVGA_CAP_IRQMASK) drm_irq_uninstall(dev_priv->dev); @@ -1148,27 +1149,13 @@ static int vmw_master_set(struct drm_device *dev, struct vmw_master *vmaster = vmw_master(file_priv->master); int ret = 0; - if (!dev_priv->enable_fb) { - ret = vmw_3d_resource_inc(dev_priv, true); - if (unlikely(ret != 0)) - return ret; - vmw_kms_save_vga(dev_priv); - vmw_write(dev_priv, SVGA_REG_TRACES, 0); - } - if (active) { BUG_ON(active != &dev_priv->fbdev_master); ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile); if (unlikely(ret != 0)) - goto out_no_active_lock; + return ret; ttm_lock_set_kill(&active->lock, true, SIGTERM); - ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM); - if (unlikely(ret != 0)) { - DRM_ERROR("Unable to clean VRAM on " - "master drop.\n"); - } - dev_priv->active_master = NULL; } @@ -1182,14 +1169,6 @@ static int vmw_master_set(struct drm_device *dev, dev_priv->active_master = vmaster; return 0; - -out_no_active_lock: - if (!dev_priv->enable_fb) { - vmw_kms_restore_vga(dev_priv); - vmw_3d_resource_dec(dev_priv, true); - vmw_write(dev_priv, SVGA_REG_TRACES, 1); - } - return ret; } static void vmw_master_drop(struct drm_device *dev, @@ -1214,16 +1193,9 @@ static void vmw_master_drop(struct drm_device *dev, } ttm_lock_set_kill(&vmaster->lock, false, SIGTERM); - vmw_execbuf_release_pinned_bo(dev_priv); - if (!dev_priv->enable_fb) { - ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM); - if (unlikely(ret != 0)) - DRM_ERROR("Unable to clean VRAM on master drop.\n"); - vmw_kms_restore_vga(dev_priv); - vmw_3d_resource_dec(dev_priv, true); - vmw_write(dev_priv, SVGA_REG_TRACES, 1); - } + if (!dev_priv->enable_fb) + vmw_svga_disable(dev_priv); dev_priv->active_master = &dev_priv->fbdev_master; ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM); @@ -1233,6 +1205,74 @@ static void vmw_master_drop(struct drm_device *dev, vmw_fb_on(dev_priv); } +/** + * __vmw_svga_enable - Enable SVGA mode, FIFO and use of VRAM. + * + * @dev_priv: Pointer to device private struct. + * Needs the reservation sem to be held in non-exclusive mode. + */ +void __vmw_svga_enable(struct vmw_private *dev_priv) +{ + spin_lock(&dev_priv->svga_lock); + if (!dev_priv->bdev.man[TTM_PL_VRAM].use_type) { + vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE); + dev_priv->bdev.man[TTM_PL_VRAM].use_type = true; + } + spin_unlock(&dev_priv->svga_lock); +} + +/** + * vmw_svga_enable - Enable SVGA mode, FIFO and use of VRAM. + * + * @dev_priv: Pointer to device private struct. + */ +void vmw_svga_enable(struct vmw_private *dev_priv) +{ + ttm_read_lock(&dev_priv->reservation_sem, false); + __vmw_svga_enable(dev_priv); + ttm_read_unlock(&dev_priv->reservation_sem); +} + +/** + * __vmw_svga_disable - Disable SVGA mode and use of VRAM. + * + * @dev_priv: Pointer to device private struct. + * Needs the reservation sem to be held in exclusive mode. + * Will not empty VRAM. VRAM must be emptied by caller. + */ +void __vmw_svga_disable(struct vmw_private *dev_priv) +{ + spin_lock(&dev_priv->svga_lock); + if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) { + dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; + vmw_write(dev_priv, SVGA_REG_ENABLE, + SVGA_REG_ENABLE_ENABLE_HIDE); + } + spin_unlock(&dev_priv->svga_lock); +} + +/** + * vmw_svga_disable - Disable SVGA_MODE, and use of VRAM. Keep the fifo + * running. + * + * @dev_priv: Pointer to device private struct. + * Will empty VRAM. + */ +void vmw_svga_disable(struct vmw_private *dev_priv) +{ + ttm_write_lock(&dev_priv->reservation_sem, false); + spin_lock(&dev_priv->svga_lock); + if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) { + dev_priv->bdev.man[TTM_PL_VRAM].use_type = false; + vmw_write(dev_priv, SVGA_REG_ENABLE, + SVGA_REG_ENABLE_ENABLE_HIDE); + spin_unlock(&dev_priv->svga_lock); + if (ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM)) + DRM_ERROR("Failed evicting VRAM buffers.\n"); + } else + spin_unlock(&dev_priv->svga_lock); + ttm_write_unlock(&dev_priv->reservation_sem); +} static void vmw_remove(struct pci_dev *pdev) { @@ -1250,21 +1290,21 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, switch (val) { case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: ttm_suspend_lock(&dev_priv->reservation_sem); - /** + /* * This empties VRAM and unbinds all GMR bindings. * Buffer contents is moved to swappable memory. */ vmw_execbuf_release_pinned_bo(dev_priv); vmw_resource_evict_all(dev_priv); + vmw_release_device_early(dev_priv); ttm_bo_swapout_all(&dev_priv->bdev); - + vmw_fence_fifo_down(dev_priv->fman); break; case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: case PM_POST_RESTORE: + vmw_fence_fifo_up(dev_priv->fman); ttm_suspend_unlock(&dev_priv->reservation_sem); break; @@ -1276,20 +1316,13 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, return 0; } -/** - * These might not be needed with the virtual SVGA device. - */ - static int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct drm_device *dev = pci_get_drvdata(pdev); struct vmw_private *dev_priv = vmw_priv(dev); - if (dev_priv->num_3d_resources != 0) { - DRM_INFO("Can't suspend or hibernate " - "while 3D resources are active.\n"); + if (dev_priv->refuse_hibernation) return -EBUSY; - } pci_save_state(pdev); pci_disable_device(pdev); @@ -1321,56 +1354,62 @@ static int vmw_pm_resume(struct device *kdev) return vmw_pci_resume(pdev); } -static int vmw_pm_prepare(struct device *kdev) +static int vmw_pm_freeze(struct device *kdev) { struct pci_dev *pdev = to_pci_dev(kdev); struct drm_device *dev = pci_get_drvdata(pdev); struct vmw_private *dev_priv = vmw_priv(dev); - /** - * Release 3d reference held by fbdev and potentially - * stop fifo. - */ dev_priv->suspended = true; if (dev_priv->enable_fb) - vmw_3d_resource_dec(dev_priv, true); - - if (dev_priv->num_3d_resources != 0) { - - DRM_INFO("Can't suspend or hibernate " - "while 3D resources are active.\n"); + vmw_fifo_resource_dec(dev_priv); + if (atomic_read(&dev_priv->num_fifo_resources) != 0) { + DRM_ERROR("Can't hibernate while 3D resources are active.\n"); if (dev_priv->enable_fb) - vmw_3d_resource_inc(dev_priv, true); + vmw_fifo_resource_inc(dev_priv); + WARN_ON(vmw_request_device_late(dev_priv)); dev_priv->suspended = false; return -EBUSY; } + if (dev_priv->enable_fb) + __vmw_svga_disable(dev_priv); + + vmw_release_device_late(dev_priv); + return 0; } -static void vmw_pm_complete(struct device *kdev) +static int vmw_pm_restore(struct device *kdev) { struct pci_dev *pdev = to_pci_dev(kdev); struct drm_device *dev = pci_get_drvdata(pdev); struct vmw_private *dev_priv = vmw_priv(dev); + int ret; vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); (void) vmw_read(dev_priv, SVGA_REG_ID); - /** - * Reclaim 3d reference held by fbdev and potentially - * start fifo. - */ if (dev_priv->enable_fb) - vmw_3d_resource_inc(dev_priv, false); + vmw_fifo_resource_inc(dev_priv); + + ret = vmw_request_device(dev_priv); + if (ret) + return ret; + + if (dev_priv->enable_fb) + __vmw_svga_enable(dev_priv); dev_priv->suspended = false; + + return 0; } static const struct dev_pm_ops vmw_pm_ops = { - .prepare = vmw_pm_prepare, - .complete = vmw_pm_complete, + .freeze = vmw_pm_freeze, + .thaw = vmw_pm_restore, + .restore = vmw_pm_restore, .suspend = vmw_pm_suspend, .resume = vmw_pm_resume, }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d26a6daa9719..a5f221eaf076 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -484,6 +484,7 @@ struct vmw_private { bool stealth; bool enable_fb; + spinlock_t svga_lock; /** * Master management. @@ -493,9 +494,10 @@ struct vmw_private { struct vmw_master fbdev_master; struct notifier_block pm_nb; bool suspended; + bool refuse_hibernation; struct mutex release_mutex; - uint32_t num_3d_resources; + atomic_t num_fifo_resources; /* * Replace this with an rwsem as soon as we have down_xx_interruptible() @@ -587,8 +589,9 @@ static inline uint32_t vmw_read(struct vmw_private *dev_priv, return val; } -int vmw_3d_resource_inc(struct vmw_private *dev_priv, bool unhide_svga); -void vmw_3d_resource_dec(struct vmw_private *dev_priv, bool hide_svga); +extern void vmw_svga_enable(struct vmw_private *dev_priv); +extern void vmw_svga_disable(struct vmw_private *dev_priv); + /** * GMR utilities - vmwgfx_gmr.c @@ -1116,4 +1119,14 @@ static inline struct ttm_mem_global *vmw_mem_glob(struct vmw_private *dev_priv) { return (struct ttm_mem_global *) dev_priv->mem_global_ref.object; } + +static inline void vmw_fifo_resource_inc(struct vmw_private *dev_priv) +{ + atomic_inc(&dev_priv->num_fifo_resources); +} + +static inline void vmw_fifo_resource_dec(struct vmw_private *dev_priv) +{ + atomic_dec(&dev_priv->num_fifo_resources); +} #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index e2d40ebd5455..ecdc8d99f2fb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -596,7 +596,10 @@ int vmw_fb_off(struct vmw_private *vmw_priv) info = vmw_priv->fb_info; par = info->par; + if (!par->bo_ptr) + return 0; + vmw_kms_save_vga(vmw_priv); spin_lock_irqsave(&par->dirty.lock, flags); par->dirty.active = false; spin_unlock_irqrestore(&par->dirty.lock, flags); @@ -648,6 +651,7 @@ int vmw_fb_on(struct vmw_private *vmw_priv) spin_lock_irqsave(&par->dirty.lock, flags); par->dirty.active = true; spin_unlock_irqrestore(&par->dirty.lock, flags); + vmw_kms_restore_vga(vmw_priv); err_no_buffer: vmw_fb_set_par(info); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 39f2b03888e7..cd5d9f3fe0e0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -98,7 +98,6 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) __le32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t max; uint32_t min; - uint32_t dummy; fifo->static_buffer_size = VMWGFX_FIFO_STATIC_SIZE; fifo->static_buffer = vmalloc(fifo->static_buffer_size); @@ -112,10 +111,6 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) mutex_init(&fifo->fifo_mutex); init_rwsem(&fifo->rwsem); - /* - * Allow mapping the first page read-only to user-space. - */ - DRM_INFO("width %d\n", vmw_read(dev_priv, SVGA_REG_WIDTH)); DRM_INFO("height %d\n", vmw_read(dev_priv, SVGA_REG_HEIGHT)); DRM_INFO("bpp %d\n", vmw_read(dev_priv, SVGA_REG_BITS_PER_PIXEL)); @@ -123,7 +118,9 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE); dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE); dev_priv->traces_state = vmw_read(dev_priv, SVGA_REG_TRACES); - vmw_write(dev_priv, SVGA_REG_ENABLE, 1); + + vmw_write(dev_priv, SVGA_REG_ENABLE, SVGA_REG_ENABLE_ENABLE_HIDE); + vmw_write(dev_priv, SVGA_REG_TRACES, 0); min = 4; if (dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO) @@ -155,7 +152,8 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) atomic_set(&dev_priv->marker_seq, dev_priv->last_read_seqno); iowrite32(dev_priv->last_read_seqno, fifo_mem + SVGA_FIFO_FENCE); vmw_marker_queue_init(&fifo->marker_queue); - return vmw_fifo_send_fence(dev_priv, &dummy); + + return 0; } void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 5c289f748ab4..53579f278b63 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -280,6 +280,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) } vmw_fb_off(dev_priv); + vmw_svga_enable(dev_priv); crtc->primary->fb = fb; encoder->crtc = crtc; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index 04a64b8cd3cd..f06d60f41fa7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -574,7 +574,7 @@ void vmw_mob_unbind(struct vmw_private *dev_priv, vmw_fence_single_bo(bo, NULL); ttm_bo_unreserve(bo); } - vmw_3d_resource_dec(dev_priv, false); + vmw_fifo_resource_dec(dev_priv); } /* @@ -627,7 +627,7 @@ int vmw_mob_bind(struct vmw_private *dev_priv, mob->pt_level += VMW_MOBFMT_PTDEPTH_1 - SVGA3D_MOBFMT_PTDEPTH_1; } - (void) vmw_3d_resource_inc(dev_priv, false); + vmw_fifo_resource_inc(dev_priv); cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); if (unlikely(cmd == NULL)) { @@ -648,7 +648,7 @@ int vmw_mob_bind(struct vmw_private *dev_priv, return 0; out_no_cmd_space: - vmw_3d_resource_dec(dev_priv, false); + vmw_fifo_resource_dec(dev_priv); if (pt_set_up) ttm_bo_unref(&mob->pt_bo); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 7dc591d04d9a..9e8eb364a6ac 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -332,6 +332,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) } vmw_fb_off(dev_priv); + vmw_svga_enable(dev_priv); if (mode->hdisplay != crtc->mode.hdisplay || mode->vdisplay != crtc->mode.vdisplay) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index 6a4584a43aa6..6110a433ebfe 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -165,7 +165,7 @@ static int vmw_gb_shader_create(struct vmw_resource *res) cmd->body.type = shader->type; cmd->body.sizeInBytes = shader->size; vmw_fifo_commit(dev_priv, sizeof(*cmd)); - (void) vmw_3d_resource_inc(dev_priv, false); + vmw_fifo_resource_inc(dev_priv); return 0; @@ -275,7 +275,7 @@ static int vmw_gb_shader_destroy(struct vmw_resource *res) vmw_fifo_commit(dev_priv, sizeof(*cmd)); mutex_unlock(&dev_priv->binding_mutex); vmw_resource_release_id(res); - vmw_3d_resource_dec(dev_priv, false); + vmw_fifo_resource_dec(dev_priv); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 4ecdbf3e59da..4d0c98edeb6a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -340,7 +340,7 @@ static void vmw_hw_surface_destroy(struct vmw_resource *res) dev_priv->used_memory_size -= res->backup_size; mutex_unlock(&dev_priv->cmdbuf_mutex); } - vmw_3d_resource_dec(dev_priv, false); + vmw_fifo_resource_dec(dev_priv); } /** @@ -576,14 +576,14 @@ static int vmw_surface_init(struct vmw_private *dev_priv, BUG_ON(res_free == NULL); if (!dev_priv->has_mob) - (void) vmw_3d_resource_inc(dev_priv, false); + vmw_fifo_resource_inc(dev_priv); ret = vmw_resource_init(dev_priv, res, true, res_free, (dev_priv->has_mob) ? &vmw_gb_surface_func : &vmw_legacy_surface_func); if (unlikely(ret != 0)) { if (!dev_priv->has_mob) - vmw_3d_resource_dec(dev_priv, false); + vmw_fifo_resource_dec(dev_priv); res_free(res); return ret; } @@ -1028,7 +1028,7 @@ static int vmw_gb_surface_create(struct vmw_resource *res) if (likely(res->id != -1)) return 0; - (void) vmw_3d_resource_inc(dev_priv, false); + vmw_fifo_resource_inc(dev_priv); ret = vmw_resource_alloc_id(res); if (unlikely(ret != 0)) { DRM_ERROR("Failed to allocate a surface id.\n"); @@ -1068,7 +1068,7 @@ static int vmw_gb_surface_create(struct vmw_resource *res) out_no_fifo: vmw_resource_release_id(res); out_no_id: - vmw_3d_resource_dec(dev_priv, false); + vmw_fifo_resource_dec(dev_priv); return ret; } @@ -1213,7 +1213,7 @@ static int vmw_gb_surface_destroy(struct vmw_resource *res) vmw_fifo_commit(dev_priv, sizeof(*cmd)); mutex_unlock(&dev_priv->binding_mutex); vmw_resource_release_id(res); - vmw_3d_resource_dec(dev_priv, false); + vmw_fifo_resource_dec(dev_priv); return 0; } -- cgit v1.3-6-gb490 From 13eec7eaae00276c952852f4c2723cd55ac0fb8c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 25 Jun 2015 11:12:17 -0700 Subject: drm/vmwgfx: Fix OTABLE takedown Don't fence and free the BO if command submission fails. Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_mob.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index f06d60f41fa7..46f975e57d06 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -191,17 +191,18 @@ static void vmw_takedown_otable_base(struct vmw_private *dev_priv, if (unlikely(cmd == NULL)) { DRM_ERROR("Failed reserving FIFO space for OTable " "takedown.\n"); - } else { - memset(cmd, 0, sizeof(*cmd)); - cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE; - cmd->header.size = sizeof(cmd->body); - cmd->body.type = type; - cmd->body.baseAddress = 0; - cmd->body.sizeInBytes = 0; - cmd->body.validSizeInBytes = 0; - cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID; - vmw_fifo_commit(dev_priv, sizeof(*cmd)); + return; } + + memset(cmd, 0, sizeof(*cmd)); + cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE; + cmd->header.size = sizeof(cmd->body); + cmd->body.type = type; + cmd->body.baseAddress = 0; + cmd->body.sizeInBytes = 0; + cmd->body.validSizeInBytes = 0; + cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); if (bo) { int ret; -- cgit v1.3-6-gb490 From cb09bbcc429a290d01ebf23b9f0193dee0da6779 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 25 Jun 2015 11:15:11 -0700 Subject: vmwgfx: Update device headers for command buffers. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/svga3d_reg.h | 2 - drivers/gpu/drm/vmwgfx/svga_reg.h | 187 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/svga_types.h | 3 + 3 files changed, 190 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/svga3d_reg.h b/drivers/gpu/drm/vmwgfx/svga3d_reg.h index f58dc7dd15c5..e50d20c9cfe8 100644 --- a/drivers/gpu/drm/vmwgfx/svga3d_reg.h +++ b/drivers/gpu/drm/vmwgfx/svga3d_reg.h @@ -1928,8 +1928,6 @@ struct { * Guest-backed surface definitions. */ -typedef uint32 SVGAMobId; - typedef enum SVGAMobFormat { SVGA3D_MOBFMT_INVALID = SVGA3D_INVALID_ID, SVGA3D_MOBFMT_PTDEPTH_0 = 0, diff --git a/drivers/gpu/drm/vmwgfx/svga_reg.h b/drivers/gpu/drm/vmwgfx/svga_reg.h index e4259c2c1acc..3763d5bac47b 100644 --- a/drivers/gpu/drm/vmwgfx/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/svga_reg.h @@ -106,6 +106,8 @@ #define SVGA_IRQFLAG_ANY_FENCE 0x1 /* Any fence was passed */ #define SVGA_IRQFLAG_FIFO_PROGRESS 0x2 /* Made forward progress in the FIFO */ #define SVGA_IRQFLAG_FENCE_GOAL 0x4 /* SVGA_FIFO_FENCE_GOAL reached */ +#define SVGA_IRQFLAG_COMMAND_BUFFER 0x8 /* Command buffer completed */ +#define SVGA_IRQFLAG_ERROR 0x10 /* Error while processing commands */ /* * Registers @@ -299,6 +301,190 @@ struct SVGAGuestPtr { uint32 offset; } SVGAGuestPtr; +/* + * Register based command buffers -- + * + * Provide an SVGA device interface that allows the guest to submit + * command buffers to the SVGA device through an SVGA device register. + * The metadata for each command buffer is contained in the + * SVGACBHeader structure along with the return status codes. + * + * The SVGA device supports command buffers if + * SVGA_CAP_COMMAND_BUFFERS is set in the device caps register. The + * fifo must be enabled for command buffers to be submitted. + * + * Command buffers are submitted when the guest writing the 64 byte + * aligned physical address into the SVGA_REG_COMMAND_LOW and + * SVGA_REG_COMMAND_HIGH. SVGA_REG_COMMAND_HIGH contains the upper 32 + * bits of the physical address. SVGA_REG_COMMAND_LOW contains the + * lower 32 bits of the physical address, since the command buffer + * headers are required to be 64 byte aligned the lower 6 bits are + * used for the SVGACBContext value. Writing to SVGA_REG_COMMAND_LOW + * submits the command buffer to the device and queues it for + * execution. The SVGA device supports at least + * SVGA_CB_MAX_QUEUED_PER_CONTEXT command buffers that can be queued + * per context and if that limit is reached the device will write the + * status SVGA_CB_STATUS_QUEUE_FULL to the status value of the command + * buffer header synchronously and not raise any IRQs. + * + * It is invalid to submit a command buffer without a valid physical + * address and results are undefined. + * + * The device guarantees that command buffers of size SVGA_CB_MAX_SIZE + * will be supported. If a larger command buffer is submitted results + * are unspecified and the device will either complete the command + * buffer or return an error. + * + * The device guarantees that any individual command in a command + * buffer can be up to SVGA_CB_MAX_COMMAND_SIZE in size which is + * enough to fit a 64x64 color-cursor definition. If the command is + * too large the device is allowed to process the command or return an + * error. + * + * The device context is a special SVGACBContext that allows for + * synchronous register like accesses with the flexibility of + * commands. There is a different command set defined by + * SVGADeviceContextCmdId. The commands in each command buffer is not + * allowed to straddle physical pages. + * + * The offset field which is available starting with the + * SVGA_CAP_CMD_BUFFERS_2 cap bit can be set by the guest to bias the + * start of command processing into the buffer. If an error is + * encountered the errorOffset will still be relative to the specific + * PA, not biased by the offset. When the command buffer is finished + * the guest should not read the offset field as there is no guarantee + * what it will set to. + */ + +#define SVGA_CB_MAX_SIZE (512 * 1024) // 512 KB +#define SVGA_CB_MAX_QUEUED_PER_CONTEXT 32 +#define SVGA_CB_MAX_COMMAND_SIZE (32 * 1024) // 32 KB + +#define SVGA_CB_CONTEXT_MASK 0x3f +typedef enum { + SVGA_CB_CONTEXT_DEVICE = 0x3f, + SVGA_CB_CONTEXT_0 = 0x0, + SVGA_CB_CONTEXT_MAX = 0x1, +} SVGACBContext; + + +typedef enum { + /* + * The guest is supposed to write SVGA_CB_STATUS_NONE to the status + * field before submitting the command buffer header, the host will + * change the value when it is done with the command buffer. + */ + SVGA_CB_STATUS_NONE = 0, + + /* + * Written by the host when a command buffer completes successfully. + * The device raises an IRQ with SVGA_IRQFLAG_COMMAND_BUFFER unless + * the SVGA_CB_FLAG_NO_IRQ flag is set. + */ + SVGA_CB_STATUS_COMPLETED = 1, + + /* + * Written by the host synchronously with the command buffer + * submission to indicate the command buffer was not submitted. No + * IRQ is raised. + */ + SVGA_CB_STATUS_QUEUE_FULL = 2, + + /* + * Written by the host when an error was detected parsing a command + * in the command buffer, errorOffset is written to contain the + * offset to the first byte of the failing command. The device + * raises the IRQ with both SVGA_IRQFLAG_ERROR and + * SVGA_IRQFLAG_COMMAND_BUFFER. Some of the commands may have been + * processed. + */ + SVGA_CB_STATUS_COMMAND_ERROR = 3, + + /* + * Written by the host if there is an error parsing the command + * buffer header. The device raises the IRQ with both + * SVGA_IRQFLAG_ERROR and SVGA_IRQFLAG_COMMAND_BUFFER. The device + * did not processes any of the command buffer. + */ + SVGA_CB_STATUS_CB_HEADER_ERROR = 4, + + /* + * Written by the host if the guest requested the host to preempt + * the command buffer. The device will not raise any IRQs and the + * command buffer was not processed. + */ + SVGA_CB_STATUS_PREEMPTED = 5, + + /* + * Written by the host synchronously with the command buffer + * submission to indicate the the command buffer was not submitted + * due to an error. No IRQ is raised. + */ + SVGA_CB_STATUS_SUBMISSION_ERROR = 6, +} SVGACBStatus; + +typedef enum { + SVGA_CB_FLAG_NONE = 0, + SVGA_CB_FLAG_NO_IRQ = 1 << 0, + SVGA_CB_FLAG_DX_CONTEXT = 1 << 1, + SVGA_CB_FLAG_MOB = 1 << 2, +} SVGACBFlags; + +typedef +struct { + volatile SVGACBStatus status; /* Modified by device. */ + volatile uint32 errorOffset; /* Modified by device. */ + uint64 id; + SVGACBFlags flags; + uint32 length; + union { + PA pa; + struct { + SVGAMobId mobid; + uint32 mobOffset; + } mob; + } ptr; + uint32 offset; /* Valid if CMD_BUFFERS_2 cap set, must be zero otherwise, + * modified by device. + */ + uint32 dxContext; /* Valid if DX_CONTEXT flag set, must be zero otherwise */ + uint32 mustBeZero[6]; +} +__attribute__((__packed__)) +SVGACBHeader; + +typedef enum { + SVGA_DC_CMD_NOP = 0, + SVGA_DC_CMD_START_STOP_CONTEXT = 1, + SVGA_DC_CMD_PREEMPT = 2, + SVGA_DC_CMD_MAX = 3, +} SVGADeviceContextCmdId; + + +typedef struct { + uint32 enable; + SVGACBContext context; +} SVGADCCmdStartStop; + +/* + * SVGADCCmdPreempt -- + * + * This command allows the guest to request that all command buffers + * on the specified context be preempted that can be. After execution + * of this command all command buffers that were preempted will + * already have SVGA_CB_STATUS_PREEMPTED written into the status + * field. The device might still be processing a command buffer, + * assuming execution of it started before the preemption request was + * received. Specifying the ignoreIDZero flag to TRUE will cause the + * device to not preempt command buffers with the id field in the + * command buffer header set to zero. + */ + +typedef struct { + SVGACBContext context; + uint32 ignoreIDZero; +} SVGADCCmdPreempt; + /* * SVGAGMRImageFormat -- @@ -444,6 +630,7 @@ struct SVGASignedPoint { #define SVGA_CAP_DEAD1 0x02000000 #define SVGA_CAP_CMD_BUFFERS_2 0x04000000 #define SVGA_CAP_GBOBJECTS 0x08000000 +#define SVGA_CAP_CMD_BUFFERS_3 0x10000000 /* * FIFO register indices. diff --git a/drivers/gpu/drm/vmwgfx/svga_types.h b/drivers/gpu/drm/vmwgfx/svga_types.h index 55836dedcfc2..1186898208ed 100644 --- a/drivers/gpu/drm/vmwgfx/svga_types.h +++ b/drivers/gpu/drm/vmwgfx/svga_types.h @@ -40,6 +40,9 @@ typedef uint16_t uint16; typedef uint32_t uint32; typedef uint8_t uint8; typedef int32_t int32; +typedef uint64_t uint64; typedef bool Bool; +typedef uint64 PA; +typedef uint32 SVGAMobId; #endif -- cgit v1.3-6-gb490 From 3eab3d9eef65041952fd7b15a2eba13cb308968d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 25 Jun 2015 11:57:56 -0700 Subject: drm/vmwgfx: Add command buffer support v3 Add command buffer support. Currently we don't implement preemption or fancy error handling. Tested with a couple of mesa-demos, compiz/unity and viewperf maya-03. v2: - Synchronize with pending work at command buffer manager takedown. - Add an interface to flush the current command buffer for latency-critical command batches and apply it to framebuffer dirtying. v3: - Minor fixes of definitions and typos to address reviews. - Removed new or moved branch predictor hints. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/Makefile | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c | 13 + drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c | 1315 +++++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 26 + drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 40 + drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 180 ++++- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 67 +- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 41 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 4 + 10 files changed, 1656 insertions(+), 33 deletions(-) create mode 100644 drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index ce0ab951f507..529bc7217c72 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -7,6 +7,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \ vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \ vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \ - vmwgfx_cmdbuf_res.o \ + vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o \ obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c index cff2bf9db9d2..3b349fd2d12d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c @@ -72,6 +72,12 @@ static struct ttm_place mob_placement_flags = { .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED }; +static struct ttm_place mob_ne_placement_flags = { + .fpfn = 0, + .lpfn = 0, + .flags = VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED | TTM_PL_FLAG_NO_EVICT +}; + struct ttm_placement vmw_vram_placement = { .num_placement = 1, .placement = &vram_placement_flags, @@ -200,6 +206,13 @@ struct ttm_placement vmw_mob_placement = { .busy_placement = &mob_placement_flags }; +struct ttm_placement vmw_mob_ne_placement = { + .num_placement = 1, + .num_busy_placement = 1, + .placement = &mob_ne_placement_flags, + .busy_placement = &mob_ne_placement_flags +}; + struct vmw_ttm_tt { struct ttm_dma_tt dma_ttm; struct vmw_private *dev_priv; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c new file mode 100644 index 000000000000..b044bf530974 --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -0,0 +1,1315 @@ +/************************************************************************** + * + * Copyright © 2015 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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 "vmwgfx_drv.h" +#include "ttm/ttm_bo_api.h" + +/* + * Size of inline command buffers. Try to make sure that a page size is a + * multiple of the DMA pool allocation size. + */ +#define VMW_CMDBUF_INLINE_ALIGN 64 +#define VMW_CMDBUF_INLINE_SIZE (1024 - VMW_CMDBUF_INLINE_ALIGN) + +/** + * struct vmw_cmdbuf_context - Command buffer context queues + * + * @submitted: List of command buffers that have been submitted to the + * manager but not yet submitted to hardware. + * @hw_submitted: List of command buffers submitted to hardware. + * @preempted: List of preempted command buffers. + * @num_hw_submitted: Number of buffers currently being processed by hardware + */ +struct vmw_cmdbuf_context { + struct list_head submitted; + struct list_head hw_submitted; + struct list_head preempted; + unsigned num_hw_submitted; +}; + +/** + * struct vmw_cmdbuf_man: - Command buffer manager + * + * @cur_mutex: Mutex protecting the command buffer used for incremental small + * kernel command submissions, @cur. + * @space_mutex: Mutex to protect against starvation when we allocate + * main pool buffer space. + * @work: A struct work_struct implementeing command buffer error handling. + * Immutable. + * @dev_priv: Pointer to the device private struct. Immutable. + * @ctx: Array of command buffer context queues. The queues and the context + * data is protected by @lock. + * @error: List of command buffers that have caused device errors. + * Protected by @lock. + * @mm: Range manager for the command buffer space. Manager allocations and + * frees are protected by @lock. + * @cmd_space: Buffer object for the command buffer space, unless we were + * able to make a contigous coherent DMA memory allocation, @handle. Immutable. + * @map_obj: Mapping state for @cmd_space. Immutable. + * @map: Pointer to command buffer space. May be a mapped buffer object or + * a contigous coherent DMA memory allocation. Immutable. + * @cur: Command buffer for small kernel command submissions. Protected by + * the @cur_mutex. + * @cur_pos: Space already used in @cur. Protected by @cur_mutex. + * @default_size: Default size for the @cur command buffer. Immutable. + * @max_hw_submitted: Max number of in-flight command buffers the device can + * handle. Immutable. + * @lock: Spinlock protecting command submission queues. + * @header: Pool of DMA memory for device command buffer headers. + * Internal protection. + * @dheaders: Pool of DMA memory for device command buffer headers with trailing + * space for inline data. Internal protection. + * @tasklet: Tasklet struct for irq processing. Immutable. + * @alloc_queue: Wait queue for processes waiting to allocate command buffer + * space. + * @idle_queue: Wait queue for processes waiting for command buffer idle. + * @irq_on: Whether the process function has requested irq to be turned on. + * Protected by @lock. + * @using_mob: Whether the command buffer space is a MOB or a contigous DMA + * allocation. Immutable. + * @has_pool: Has a large pool of DMA memory which allows larger allocations. + * Typically this is false only during bootstrap. + * @handle: DMA address handle for the command buffer space if @using_mob is + * false. Immutable. + * @size: The size of the command buffer space. Immutable. + */ +struct vmw_cmdbuf_man { + struct mutex cur_mutex; + struct mutex space_mutex; + struct work_struct work; + struct vmw_private *dev_priv; + struct vmw_cmdbuf_context ctx[SVGA_CB_CONTEXT_MAX]; + struct list_head error; + struct drm_mm mm; + struct ttm_buffer_object *cmd_space; + struct ttm_bo_kmap_obj map_obj; + u8 *map; + struct vmw_cmdbuf_header *cur; + size_t cur_pos; + size_t default_size; + unsigned max_hw_submitted; + spinlock_t lock; + struct dma_pool *headers; + struct dma_pool *dheaders; + struct tasklet_struct tasklet; + wait_queue_head_t alloc_queue; + wait_queue_head_t idle_queue; + bool irq_on; + bool using_mob; + bool has_pool; + dma_addr_t handle; + size_t size; +}; + +/** + * struct vmw_cmdbuf_header - Command buffer metadata + * + * @man: The command buffer manager. + * @cb_header: Device command buffer header, allocated from a DMA pool. + * @cb_context: The device command buffer context. + * @list: List head for attaching to the manager lists. + * @node: The range manager node. + * @handle. The DMA address of @cb_header. Handed to the device on command + * buffer submission. + * @cmd: Pointer to the command buffer space of this buffer. + * @size: Size of the command buffer space of this buffer. + * @reserved: Reserved space of this buffer. + * @inline_space: Whether inline command buffer space is used. + */ +struct vmw_cmdbuf_header { + struct vmw_cmdbuf_man *man; + SVGACBHeader *cb_header; + SVGACBContext cb_context; + struct list_head list; + struct drm_mm_node *node; + dma_addr_t handle; + u8 *cmd; + size_t size; + size_t reserved; + bool inline_space; +}; + +/** + * struct vmw_cmdbuf_dheader - Device command buffer header with inline + * command buffer space. + * + * @cb_header: Device command buffer header. + * @cmd: Inline command buffer space. + */ +struct vmw_cmdbuf_dheader { + SVGACBHeader cb_header; + u8 cmd[VMW_CMDBUF_INLINE_SIZE] __aligned(VMW_CMDBUF_INLINE_ALIGN); +}; + +/** + * struct vmw_cmdbuf_alloc_info - Command buffer space allocation metadata + * + * @page_size: Size of requested command buffer space in pages. + * @node: The range manager node if allocation succeeded. + * @ret: Error code if failure. Otherwise 0. + */ +struct vmw_cmdbuf_alloc_info { + size_t page_size; + struct drm_mm_node *node; + int ret; +}; + +/* Loop over each context in the command buffer manager. */ +#define for_each_cmdbuf_ctx(_man, _i, _ctx) \ + for (_i = 0, _ctx = &(_man)->ctx[0]; (_i) < SVGA_CB_CONTEXT_MAX; \ + ++(_i), ++(_ctx)) + +static int vmw_cmdbuf_startstop(struct vmw_cmdbuf_man *man, bool enable); + + +/** + * vmw_cmdbuf_cur_lock - Helper to lock the cur_mutex. + * + * @man: The range manager. + * @interruptible: Whether to wait interruptible when locking. + */ +static int vmw_cmdbuf_cur_lock(struct vmw_cmdbuf_man *man, bool interruptible) +{ + if (interruptible) { + if (mutex_lock_interruptible(&man->cur_mutex)) + return -ERESTARTSYS; + } else { + mutex_lock(&man->cur_mutex); + } + + return 0; +} + +/** + * vmw_cmdbuf_cur_unlock - Helper to unlock the cur_mutex. + * + * @man: The range manager. + */ +static void vmw_cmdbuf_cur_unlock(struct vmw_cmdbuf_man *man) +{ + mutex_unlock(&man->cur_mutex); +} + +/** + * vmw_cmdbuf_header_inline_free - Free a struct vmw_cmdbuf_header that has + * been used for the device context with inline command buffers. + * Need not be called locked. + * + * @header: Pointer to the header to free. + */ +static void vmw_cmdbuf_header_inline_free(struct vmw_cmdbuf_header *header) +{ + struct vmw_cmdbuf_dheader *dheader; + + if (WARN_ON_ONCE(!header->inline_space)) + return; + + dheader = container_of(header->cb_header, struct vmw_cmdbuf_dheader, + cb_header); + dma_pool_free(header->man->dheaders, dheader, header->handle); + kfree(header); +} + +/** + * __vmw_cmdbuf_header_free - Free a struct vmw_cmdbuf_header and its + * associated structures. + * + * header: Pointer to the header to free. + * + * For internal use. Must be called with man::lock held. + */ +static void __vmw_cmdbuf_header_free(struct vmw_cmdbuf_header *header) +{ + struct vmw_cmdbuf_man *man = header->man; + + BUG_ON(!spin_is_locked(&man->lock)); + + if (header->inline_space) { + vmw_cmdbuf_header_inline_free(header); + return; + } + + drm_mm_remove_node(header->node); + kfree(header->node); + header->node = NULL; + wake_up_all(&man->alloc_queue); + if (header->cb_header) + dma_pool_free(man->headers, header->cb_header, + header->handle); + kfree(header); +} + +/** + * vmw_cmdbuf_header_free - Free a struct vmw_cmdbuf_header and its + * associated structures. + * + * @header: Pointer to the header to free. + */ +void vmw_cmdbuf_header_free(struct vmw_cmdbuf_header *header) +{ + struct vmw_cmdbuf_man *man = header->man; + + /* Avoid locking if inline_space */ + if (header->inline_space) { + vmw_cmdbuf_header_inline_free(header); + return; + } + spin_lock_bh(&man->lock); + __vmw_cmdbuf_header_free(header); + spin_unlock_bh(&man->lock); +} + + +/** + * vmw_cmbuf_header_submit: Submit a command buffer to hardware. + * + * @header: The header of the buffer to submit. + */ +static int vmw_cmdbuf_header_submit(struct vmw_cmdbuf_header *header) +{ + struct vmw_cmdbuf_man *man = header->man; + u32 val; + + val = (header->handle >> 32); + vmw_write(man->dev_priv, SVGA_REG_COMMAND_HIGH, val); + val = (header->handle & 0xFFFFFFFFULL); + val |= header->cb_context & SVGA_CB_CONTEXT_MASK; + vmw_write(man->dev_priv, SVGA_REG_COMMAND_LOW, val); + + return header->cb_header->status; +} + +/** + * vmw_cmdbuf_ctx_init: Initialize a command buffer context. + * + * @ctx: The command buffer context to initialize + */ +static void vmw_cmdbuf_ctx_init(struct vmw_cmdbuf_context *ctx) +{ + INIT_LIST_HEAD(&ctx->hw_submitted); + INIT_LIST_HEAD(&ctx->submitted); + INIT_LIST_HEAD(&ctx->preempted); + ctx->num_hw_submitted = 0; +} + +/** + * vmw_cmdbuf_ctx_submit: Submit command buffers from a command buffer + * context. + * + * @man: The command buffer manager. + * @ctx: The command buffer context. + * + * Submits command buffers to hardware until there are no more command + * buffers to submit or the hardware can't handle more command buffers. + */ +static void vmw_cmdbuf_ctx_submit(struct vmw_cmdbuf_man *man, + struct vmw_cmdbuf_context *ctx) +{ + while (ctx->num_hw_submitted < man->max_hw_submitted && + !list_empty(&ctx->submitted)) { + struct vmw_cmdbuf_header *entry; + SVGACBStatus status; + + entry = list_first_entry(&ctx->submitted, + struct vmw_cmdbuf_header, + list); + + status = vmw_cmdbuf_header_submit(entry); + + /* This should never happen */ + if (WARN_ON_ONCE(status == SVGA_CB_STATUS_QUEUE_FULL)) { + entry->cb_header->status = SVGA_CB_STATUS_NONE; + break; + } + + list_del(&entry->list); + list_add_tail(&entry->list, &ctx->hw_submitted); + ctx->num_hw_submitted++; + } + +} + +/** + * vmw_cmdbuf_ctx_submit: Process a command buffer context. + * + * @man: The command buffer manager. + * @ctx: The command buffer context. + * + * Submit command buffers to hardware if possible, and process finished + * buffers. Typically freeing them, but on preemption or error take + * appropriate action. Wake up waiters if appropriate. + */ +static void vmw_cmdbuf_ctx_process(struct vmw_cmdbuf_man *man, + struct vmw_cmdbuf_context *ctx, + int *notempty) +{ + struct vmw_cmdbuf_header *entry, *next; + + vmw_cmdbuf_ctx_submit(man, ctx); + + list_for_each_entry_safe(entry, next, &ctx->hw_submitted, list) { + SVGACBStatus status = entry->cb_header->status; + + if (status == SVGA_CB_STATUS_NONE) + break; + + list_del(&entry->list); + wake_up_all(&man->idle_queue); + ctx->num_hw_submitted--; + switch (status) { + case SVGA_CB_STATUS_COMPLETED: + __vmw_cmdbuf_header_free(entry); + break; + case SVGA_CB_STATUS_COMMAND_ERROR: + case SVGA_CB_STATUS_CB_HEADER_ERROR: + list_add_tail(&entry->list, &man->error); + schedule_work(&man->work); + break; + case SVGA_CB_STATUS_PREEMPTED: + list_add(&entry->list, &ctx->preempted); + break; + default: + WARN_ONCE(true, "Undefined command buffer status.\n"); + __vmw_cmdbuf_header_free(entry); + break; + } + } + + vmw_cmdbuf_ctx_submit(man, ctx); + if (!list_empty(&ctx->submitted)) + (*notempty)++; +} + +/** + * vmw_cmdbuf_man_process - Process all command buffer contexts and + * switch on and off irqs as appropriate. + * + * @man: The command buffer manager. + * + * Calls vmw_cmdbuf_ctx_process() on all contexts. If any context has + * command buffers left that are not submitted to hardware, Make sure + * IRQ handling is turned on. Otherwise, make sure it's turned off. This + * function may return -EAGAIN to indicate it should be rerun due to + * possibly missed IRQs if IRQs has just been turned on. + */ +static int vmw_cmdbuf_man_process(struct vmw_cmdbuf_man *man) +{ + int notempty = 0; + struct vmw_cmdbuf_context *ctx; + int i; + + for_each_cmdbuf_ctx(man, i, ctx) + vmw_cmdbuf_ctx_process(man, ctx, ¬empty); + + if (man->irq_on && !notempty) { + vmw_generic_waiter_remove(man->dev_priv, + SVGA_IRQFLAG_COMMAND_BUFFER, + &man->dev_priv->cmdbuf_waiters); + man->irq_on = false; + } else if (!man->irq_on && notempty) { + vmw_generic_waiter_add(man->dev_priv, + SVGA_IRQFLAG_COMMAND_BUFFER, + &man->dev_priv->cmdbuf_waiters); + man->irq_on = true; + + /* Rerun in case we just missed an irq. */ + return -EAGAIN; + } + + return 0; +} + +/** + * vmw_cmdbuf_ctx_add - Schedule a command buffer for submission on a + * command buffer context + * + * @man: The command buffer manager. + * @header: The header of the buffer to submit. + * @cb_context: The command buffer context to use. + * + * This function adds @header to the "submitted" queue of the command + * buffer context identified by @cb_context. It then calls the command buffer + * manager processing to potentially submit the buffer to hardware. + * @man->lock needs to be held when calling this function. + */ +static void vmw_cmdbuf_ctx_add(struct vmw_cmdbuf_man *man, + struct vmw_cmdbuf_header *header, + SVGACBContext cb_context) +{ + if (!(header->cb_header->flags & SVGA_CB_FLAG_DX_CONTEXT)) + header->cb_header->dxContext = 0; + header->cb_context = cb_context; + list_add_tail(&header->list, &man->ctx[cb_context].submitted); + + if (vmw_cmdbuf_man_process(man) == -EAGAIN) + vmw_cmdbuf_man_process(man); +} + +/** + * vmw_cmdbuf_man_tasklet - The main part of the command buffer interrupt + * handler implemented as a tasklet. + * + * @data: Tasklet closure. A pointer to the command buffer manager cast to + * an unsigned long. + * + * The bottom half (tasklet) of the interrupt handler simply calls into the + * command buffer processor to free finished buffers and submit any + * queued buffers to hardware. + */ +static void vmw_cmdbuf_man_tasklet(unsigned long data) +{ + struct vmw_cmdbuf_man *man = (struct vmw_cmdbuf_man *) data; + + spin_lock(&man->lock); + if (vmw_cmdbuf_man_process(man) == -EAGAIN) + (void) vmw_cmdbuf_man_process(man); + spin_unlock(&man->lock); +} + +/** + * vmw_cmdbuf_work_func - The deferred work function that handles + * command buffer errors. + * + * @work: The work func closure argument. + * + * Restarting the command buffer context after an error requires process + * context, so it is deferred to this work function. + */ +static void vmw_cmdbuf_work_func(struct work_struct *work) +{ + struct vmw_cmdbuf_man *man = + container_of(work, struct vmw_cmdbuf_man, work); + struct vmw_cmdbuf_header *entry, *next; + bool restart; + + spin_lock_bh(&man->lock); + list_for_each_entry_safe(entry, next, &man->error, list) { + restart = true; + DRM_ERROR("Command buffer error.\n"); + + list_del(&entry->list); + __vmw_cmdbuf_header_free(entry); + wake_up_all(&man->idle_queue); + } + spin_unlock_bh(&man->lock); + + if (restart && vmw_cmdbuf_startstop(man, true)) + DRM_ERROR("Failed restarting command buffer context 0.\n"); + +} + +/** + * vmw_cmdbuf_man idle - Check whether the command buffer manager is idle. + * + * @man: The command buffer manager. + * @check_preempted: Check also the preempted queue for pending command buffers. + * + */ +static bool vmw_cmdbuf_man_idle(struct vmw_cmdbuf_man *man, + bool check_preempted) +{ + struct vmw_cmdbuf_context *ctx; + bool idle = false; + int i; + + spin_lock_bh(&man->lock); + vmw_cmdbuf_man_process(man); + for_each_cmdbuf_ctx(man, i, ctx) { + if (!list_empty(&ctx->submitted) || + !list_empty(&ctx->hw_submitted) || + (check_preempted && !list_empty(&ctx->preempted))) + goto out_unlock; + } + + idle = list_empty(&man->error); + +out_unlock: + spin_unlock_bh(&man->lock); + + return idle; +} + +/** + * __vmw_cmdbuf_cur_flush - Flush the current command buffer for small kernel + * command submissions + * + * @man: The command buffer manager. + * + * Flushes the current command buffer without allocating a new one. A new one + * is automatically allocated when needed. Call with @man->cur_mutex held. + */ +static void __vmw_cmdbuf_cur_flush(struct vmw_cmdbuf_man *man) +{ + struct vmw_cmdbuf_header *cur = man->cur; + + WARN_ON(!mutex_is_locked(&man->cur_mutex)); + + if (!cur) + return; + + spin_lock_bh(&man->lock); + if (man->cur_pos == 0) { + __vmw_cmdbuf_header_free(cur); + goto out_unlock; + } + + man->cur->cb_header->length = man->cur_pos; + vmw_cmdbuf_ctx_add(man, man->cur, SVGA_CB_CONTEXT_0); +out_unlock: + spin_unlock_bh(&man->lock); + man->cur = NULL; + man->cur_pos = 0; +} + +/** + * vmw_cmdbuf_cur_flush - Flush the current command buffer for small kernel + * command submissions + * + * @man: The command buffer manager. + * @interruptible: Whether to sleep interruptible when sleeping. + * + * Flushes the current command buffer without allocating a new one. A new one + * is automatically allocated when needed. + */ +int vmw_cmdbuf_cur_flush(struct vmw_cmdbuf_man *man, + bool interruptible) +{ + int ret = vmw_cmdbuf_cur_lock(man, interruptible); + + if (ret) + return ret; + + __vmw_cmdbuf_cur_flush(man); + vmw_cmdbuf_cur_unlock(man); + + return 0; +} + +/** + * vmw_cmdbuf_idle - Wait for command buffer manager idle. + * + * @man: The command buffer manager. + * @interruptible: Sleep interruptible while waiting. + * @timeout: Time out after this many ticks. + * + * Wait until the command buffer manager has processed all command buffers, + * or until a timeout occurs. If a timeout occurs, the function will return + * -EBUSY. + */ +int vmw_cmdbuf_idle(struct vmw_cmdbuf_man *man, bool interruptible, + unsigned long timeout) +{ + int ret; + + ret = vmw_cmdbuf_cur_flush(man, interruptible); + vmw_generic_waiter_add(man->dev_priv, + SVGA_IRQFLAG_COMMAND_BUFFER, + &man->dev_priv->cmdbuf_waiters); + + if (interruptible) { + ret = wait_event_interruptible_timeout + (man->idle_queue, vmw_cmdbuf_man_idle(man, true), + timeout); + } else { + ret = wait_event_timeout + (man->idle_queue, vmw_cmdbuf_man_idle(man, true), + timeout); + } + vmw_generic_waiter_remove(man->dev_priv, + SVGA_IRQFLAG_COMMAND_BUFFER, + &man->dev_priv->cmdbuf_waiters); + if (ret == 0) { + if (!vmw_cmdbuf_man_idle(man, true)) + ret = -EBUSY; + else + ret = 0; + } + if (ret > 0) + ret = 0; + + return ret; +} + +/** + * vmw_cmdbuf_try_alloc - Try to allocate buffer space from the main pool. + * + * @man: The command buffer manager. + * @info: Allocation info. Will hold the size on entry and allocated mm node + * on successful return. + * + * Try to allocate buffer space from the main pool. Returns true if succeeded. + * If a fatal error was hit, the error code is returned in @info->ret. + */ +static bool vmw_cmdbuf_try_alloc(struct vmw_cmdbuf_man *man, + struct vmw_cmdbuf_alloc_info *info) +{ + int ret; + + if (info->node) + return true; + + info->node = kzalloc(sizeof(*info->node), GFP_KERNEL); + if (!info->node) { + info->ret = -ENOMEM; + return true; + } + + spin_lock_bh(&man->lock); + ret = drm_mm_insert_node_generic(&man->mm, info->node, info->page_size, 0, 0, + DRM_MM_SEARCH_DEFAULT, + DRM_MM_CREATE_DEFAULT); + spin_unlock_bh(&man->lock); + if (ret) { + kfree(info->node); + info->node = NULL; + } + + return !!info->node; +} + +/** + * vmw_cmdbuf_alloc_space - Allocate buffer space from the main pool. + * + * @man: The command buffer manager. + * @size: The size of the allocation. + * @interruptible: Whether to sleep interruptible while waiting for space. + * + * This function allocates buffer space from the main pool, and if there is + * no space available ATM, it turns on IRQ handling and sleeps waiting for it to + * become available. + */ +static struct drm_mm_node *vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, + size_t size, + bool interruptible) +{ + struct vmw_cmdbuf_alloc_info info; + + info.page_size = PAGE_ALIGN(size) >> PAGE_SHIFT; + info.node = NULL; + info.ret = 0; + + /* + * To prevent starvation of large requests, only one allocating call + * at a time waiting for space. + */ + if (interruptible) { + if (mutex_lock_interruptible(&man->space_mutex)) + return ERR_PTR(-ERESTARTSYS); + } else { + mutex_lock(&man->space_mutex); + } + + /* Try to allocate space without waiting. */ + (void) vmw_cmdbuf_try_alloc(man, &info); + if (info.ret && !info.node) { + mutex_unlock(&man->space_mutex); + return ERR_PTR(info.ret); + } + + if (info.node) { + mutex_unlock(&man->space_mutex); + return info.node; + } + + vmw_generic_waiter_add(man->dev_priv, + SVGA_IRQFLAG_COMMAND_BUFFER, + &man->dev_priv->cmdbuf_waiters); + + if (interruptible) { + int ret; + + ret = wait_event_interruptible + (man->alloc_queue, vmw_cmdbuf_try_alloc(man, &info)); + if (ret) { + vmw_generic_waiter_remove + (man->dev_priv, SVGA_IRQFLAG_COMMAND_BUFFER, + &man->dev_priv->cmdbuf_waiters); + mutex_unlock(&man->space_mutex); + return ERR_PTR(ret); + } + } else { + wait_event(man->alloc_queue, vmw_cmdbuf_try_alloc(man, &info)); + } + vmw_generic_waiter_remove(man->dev_priv, + SVGA_IRQFLAG_COMMAND_BUFFER, + &man->dev_priv->cmdbuf_waiters); + mutex_unlock(&man->space_mutex); + if (info.ret && !info.node) + return ERR_PTR(info.ret); + + return info.node; +} + +/** + * vmw_cmdbuf_space_pool - Set up a command buffer header with command buffer + * space from the main pool. + * + * @man: The command buffer manager. + * @header: Pointer to the header to set up. + * @size: The requested size of the buffer space. + * @interruptible: Whether to sleep interruptible while waiting for space. + */ +static int vmw_cmdbuf_space_pool(struct vmw_cmdbuf_man *man, + struct vmw_cmdbuf_header *header, + size_t size, + bool interruptible) +{ + SVGACBHeader *cb_hdr; + size_t offset; + int ret; + + if (!man->has_pool) + return -ENOMEM; + + header->node = vmw_cmdbuf_alloc_space(man, size, interruptible); + + if (IS_ERR(header->node)) + return PTR_ERR(header->node); + + header->cb_header = dma_pool_alloc(man->headers, GFP_KERNEL, + &header->handle); + if (!header->cb_header) { + ret = -ENOMEM; + goto out_no_cb_header; + } + + header->size = header->node->size << PAGE_SHIFT; + cb_hdr = header->cb_header; + offset = header->node->start << PAGE_SHIFT; + header->cmd = man->map + offset; + memset(cb_hdr, 0, sizeof(*cb_hdr)); + if (man->using_mob) { + cb_hdr->flags = SVGA_CB_FLAG_MOB; + cb_hdr->ptr.mob.mobid = man->cmd_space->mem.start; + cb_hdr->ptr.mob.mobOffset = offset; + } else { + cb_hdr->ptr.pa = (u64)man->handle + (u64)offset; + } + + return 0; + +out_no_cb_header: + spin_lock_bh(&man->lock); + drm_mm_remove_node(header->node); + spin_unlock_bh(&man->lock); + kfree(header->node); + + return ret; +} + +/** + * vmw_cmdbuf_space_inline - Set up a command buffer header with + * inline command buffer space. + * + * @man: The command buffer manager. + * @header: Pointer to the header to set up. + * @size: The requested size of the buffer space. + */ +static int vmw_cmdbuf_space_inline(struct vmw_cmdbuf_man *man, + struct vmw_cmdbuf_header *header, + int size) +{ + struct vmw_cmdbuf_dheader *dheader; + SVGACBHeader *cb_hdr; + + if (WARN_ON_ONCE(size > VMW_CMDBUF_INLINE_SIZE)) + return -ENOMEM; + + dheader = dma_pool_alloc(man->dheaders, GFP_KERNEL, + &header->handle); + if (!dheader) + return -ENOMEM; + + header->inline_space = true; + header->size = VMW_CMDBUF_INLINE_SIZE; + cb_hdr = &dheader->cb_header; + header->cb_header = cb_hdr; + header->cmd = dheader->cmd; + memset(dheader, 0, sizeof(*dheader)); + cb_hdr->status = SVGA_CB_STATUS_NONE; + cb_hdr->flags = SVGA_CB_FLAG_NONE; + cb_hdr->ptr.pa = (u64)header->handle + + (u64)offsetof(struct vmw_cmdbuf_dheader, cmd); + + return 0; +} + +/** + * vmw_cmdbuf_alloc - Allocate a command buffer header complete with + * command buffer space. + * + * @man: The command buffer manager. + * @size: The requested size of the buffer space. + * @interruptible: Whether to sleep interruptible while waiting for space. + * @p_header: points to a header pointer to populate on successful return. + * + * Returns a pointer to command buffer space if successful. Otherwise + * returns an error pointer. The header pointer returned in @p_header should + * be used for upcoming calls to vmw_cmdbuf_reserve() and vmw_cmdbuf_commit(). + */ +void *vmw_cmdbuf_alloc(struct vmw_cmdbuf_man *man, + size_t size, bool interruptible, + struct vmw_cmdbuf_header **p_header) +{ + struct vmw_cmdbuf_header *header; + int ret = 0; + + *p_header = NULL; + + header = kzalloc(sizeof(*header), GFP_KERNEL); + if (!header) + return ERR_PTR(-ENOMEM); + + if (size <= VMW_CMDBUF_INLINE_SIZE) + ret = vmw_cmdbuf_space_inline(man, header, size); + else + ret = vmw_cmdbuf_space_pool(man, header, size, interruptible); + + if (ret) { + kfree(header); + return ERR_PTR(ret); + } + + header->man = man; + INIT_LIST_HEAD(&header->list); + header->cb_header->status = SVGA_CB_STATUS_NONE; + *p_header = header; + + return header->cmd; +} + +/** + * vmw_cmdbuf_reserve_cur - Reserve space for commands in the current + * command buffer. + * + * @man: The command buffer manager. + * @size: The requested size of the commands. + * @ctx_id: The context id if any. Otherwise set to SVGA3D_REG_INVALID. + * @interruptible: Whether to sleep interruptible while waiting for space. + * + * Returns a pointer to command buffer space if successful. Otherwise + * returns an error pointer. + */ +static void *vmw_cmdbuf_reserve_cur(struct vmw_cmdbuf_man *man, + size_t size, + int ctx_id, + bool interruptible) +{ + struct vmw_cmdbuf_header *cur; + void *ret; + + if (vmw_cmdbuf_cur_lock(man, interruptible)) + return ERR_PTR(-ERESTARTSYS); + + cur = man->cur; + if (cur && (size + man->cur_pos > cur->size || + (ctx_id != SVGA3D_INVALID_ID && + (cur->cb_header->flags & SVGA_CB_FLAG_DX_CONTEXT) && + ctx_id != cur->cb_header->dxContext))) + __vmw_cmdbuf_cur_flush(man); + + if (!man->cur) { + ret = vmw_cmdbuf_alloc(man, + max_t(size_t, size, man->default_size), + interruptible, &man->cur); + if (IS_ERR(ret)) { + vmw_cmdbuf_cur_unlock(man); + return ret; + } + + cur = man->cur; + } + + if (ctx_id != SVGA3D_INVALID_ID) { + cur->cb_header->flags |= SVGA_CB_FLAG_DX_CONTEXT; + cur->cb_header->dxContext = ctx_id; + } + + cur->reserved = size; + + return (void *) (man->cur->cmd + man->cur_pos); +} + +/** + * vmw_cmdbuf_commit_cur - Commit commands in the current command buffer. + * + * @man: The command buffer manager. + * @size: The size of the commands actually written. + * @flush: Whether to flush the command buffer immediately. + */ +static void vmw_cmdbuf_commit_cur(struct vmw_cmdbuf_man *man, + size_t size, bool flush) +{ + struct vmw_cmdbuf_header *cur = man->cur; + + WARN_ON(!mutex_is_locked(&man->cur_mutex)); + + WARN_ON(size > cur->reserved); + man->cur_pos += size; + if (!size) + cur->cb_header->flags &= ~SVGA_CB_FLAG_DX_CONTEXT; + if (flush) + __vmw_cmdbuf_cur_flush(man); + vmw_cmdbuf_cur_unlock(man); +} + +/** + * vmw_cmdbuf_reserve - Reserve space for commands in a command buffer. + * + * @man: The command buffer manager. + * @size: The requested size of the commands. + * @ctx_id: The context id if any. Otherwise set to SVGA3D_REG_INVALID. + * @interruptible: Whether to sleep interruptible while waiting for space. + * @header: Header of the command buffer. NULL if the current command buffer + * should be used. + * + * Returns a pointer to command buffer space if successful. Otherwise + * returns an error pointer. + */ +void *vmw_cmdbuf_reserve(struct vmw_cmdbuf_man *man, size_t size, + int ctx_id, bool interruptible, + struct vmw_cmdbuf_header *header) +{ + if (!header) + return vmw_cmdbuf_reserve_cur(man, size, ctx_id, interruptible); + + if (size > header->size) + return ERR_PTR(-EINVAL); + + if (ctx_id != SVGA3D_INVALID_ID) { + header->cb_header->flags |= SVGA_CB_FLAG_DX_CONTEXT; + header->cb_header->dxContext = ctx_id; + } + + header->reserved = size; + return header->cmd; +} + +/** + * vmw_cmdbuf_commit - Commit commands in a command buffer. + * + * @man: The command buffer manager. + * @size: The size of the commands actually written. + * @header: Header of the command buffer. NULL if the current command buffer + * should be used. + * @flush: Whether to flush the command buffer immediately. + */ +void vmw_cmdbuf_commit(struct vmw_cmdbuf_man *man, size_t size, + struct vmw_cmdbuf_header *header, bool flush) +{ + if (!header) { + vmw_cmdbuf_commit_cur(man, size, flush); + return; + } + + (void) vmw_cmdbuf_cur_lock(man, false); + __vmw_cmdbuf_cur_flush(man); + WARN_ON(size > header->reserved); + man->cur = header; + man->cur_pos = size; + if (!size) + header->cb_header->flags &= ~SVGA_CB_FLAG_DX_CONTEXT; + if (flush) + __vmw_cmdbuf_cur_flush(man); + vmw_cmdbuf_cur_unlock(man); +} + +/** + * vmw_cmdbuf_tasklet_schedule - Schedule the interrupt handler bottom half. + * + * @man: The command buffer manager. + */ +void vmw_cmdbuf_tasklet_schedule(struct vmw_cmdbuf_man *man) +{ + if (!man) + return; + + tasklet_schedule(&man->tasklet); +} + +/** + * vmw_cmdbuf_send_device_command - Send a command through the device context. + * + * @man: The command buffer manager. + * @command: Pointer to the command to send. + * @size: Size of the command. + * + * Synchronously sends a device context command. + */ +static int vmw_cmdbuf_send_device_command(struct vmw_cmdbuf_man *man, + const void *command, + size_t size) +{ + struct vmw_cmdbuf_header *header; + int status; + void *cmd = vmw_cmdbuf_alloc(man, size, false, &header); + + if (IS_ERR(cmd)) + return PTR_ERR(cmd); + + memcpy(cmd, command, size); + header->cb_header->length = size; + header->cb_context = SVGA_CB_CONTEXT_DEVICE; + spin_lock_bh(&man->lock); + status = vmw_cmdbuf_header_submit(header); + spin_unlock_bh(&man->lock); + vmw_cmdbuf_header_free(header); + + if (status != SVGA_CB_STATUS_COMPLETED) { + DRM_ERROR("Device context command failed with status %d\n", + status); + return -EINVAL; + } + + return 0; +} + +/** + * vmw_cmdbuf_startstop - Send a start / stop command through the device + * context. + * + * @man: The command buffer manager. + * @enable: Whether to enable or disable the context. + * + * Synchronously sends a device start / stop context command. + */ +static int vmw_cmdbuf_startstop(struct vmw_cmdbuf_man *man, + bool enable) +{ + struct { + uint32 id; + SVGADCCmdStartStop body; + } __packed cmd; + + cmd.id = SVGA_DC_CMD_START_STOP_CONTEXT; + cmd.body.enable = (enable) ? 1 : 0; + cmd.body.context = SVGA_CB_CONTEXT_0; + + return vmw_cmdbuf_send_device_command(man, &cmd, sizeof(cmd)); +} + +/** + * vmw_cmdbuf_set_pool_size - Set command buffer manager sizes + * + * @man: The command buffer manager. + * @size: The size of the main space pool. + * @default_size: The default size of the command buffer for small kernel + * submissions. + * + * Set the size and allocate the main command buffer space pool, + * as well as the default size of the command buffer for + * small kernel submissions. If successful, this enables large command + * submissions. Note that this function requires that rudimentary command + * submission is already available and that the MOB memory manager is alive. + * Returns 0 on success. Negative error code on failure. + */ +int vmw_cmdbuf_set_pool_size(struct vmw_cmdbuf_man *man, + size_t size, size_t default_size) +{ + struct vmw_private *dev_priv = man->dev_priv; + bool dummy; + int ret; + + if (man->has_pool) + return -EINVAL; + + /* First, try to allocate a huge chunk of DMA memory */ + size = PAGE_ALIGN(size); + man->map = dma_alloc_coherent(&dev_priv->dev->pdev->dev, size, + &man->handle, GFP_KERNEL); + if (man->map) { + man->using_mob = false; + } else { + /* + * DMA memory failed. If we can have command buffers in a + * MOB, try to use that instead. Note that this will + * actually call into the already enabled manager, when + * binding the MOB. + */ + if (!(dev_priv->capabilities & SVGA_CAP_CMD_BUFFERS_3)) + return -ENOMEM; + + ret = ttm_bo_create(&dev_priv->bdev, size, ttm_bo_type_device, + &vmw_mob_ne_placement, 0, false, NULL, + &man->cmd_space); + if (ret) + return ret; + + man->using_mob = true; + ret = ttm_bo_kmap(man->cmd_space, 0, size >> PAGE_SHIFT, + &man->map_obj); + if (ret) + goto out_no_map; + + man->map = ttm_kmap_obj_virtual(&man->map_obj, &dummy); + } + + man->size = size; + drm_mm_init(&man->mm, 0, size >> PAGE_SHIFT); + + man->has_pool = true; + man->default_size = default_size; + DRM_INFO("Using command buffers with %s pool.\n", + (man->using_mob) ? "MOB" : "DMA"); + + return 0; + +out_no_map: + if (man->using_mob) + ttm_bo_unref(&man->cmd_space); + + return ret; +} + +/** + * vmw_cmdbuf_man_create: Create a command buffer manager and enable it for + * inline command buffer submissions only. + * + * @dev_priv: Pointer to device private structure. + * + * Returns a pointer to a cummand buffer manager to success or error pointer + * on failure. The command buffer manager will be enabled for submissions of + * size VMW_CMDBUF_INLINE_SIZE only. + */ +struct vmw_cmdbuf_man *vmw_cmdbuf_man_create(struct vmw_private *dev_priv) +{ + struct vmw_cmdbuf_man *man; + struct vmw_cmdbuf_context *ctx; + int i; + int ret; + + if (!(dev_priv->capabilities & SVGA_CAP_COMMAND_BUFFERS)) + return ERR_PTR(-ENOSYS); + + man = kzalloc(sizeof(*man), GFP_KERNEL); + if (!man) + return ERR_PTR(-ENOMEM); + + man->headers = dma_pool_create("vmwgfx cmdbuf", + &dev_priv->dev->pdev->dev, + sizeof(SVGACBHeader), + 64, PAGE_SIZE); + if (!man->headers) { + ret = -ENOMEM; + goto out_no_pool; + } + + man->dheaders = dma_pool_create("vmwgfx inline cmdbuf", + &dev_priv->dev->pdev->dev, + sizeof(struct vmw_cmdbuf_dheader), + 64, PAGE_SIZE); + if (!man->dheaders) { + ret = -ENOMEM; + goto out_no_dpool; + } + + for_each_cmdbuf_ctx(man, i, ctx) + vmw_cmdbuf_ctx_init(ctx); + + INIT_LIST_HEAD(&man->error); + spin_lock_init(&man->lock); + mutex_init(&man->cur_mutex); + mutex_init(&man->space_mutex); + tasklet_init(&man->tasklet, vmw_cmdbuf_man_tasklet, + (unsigned long) man); + man->default_size = VMW_CMDBUF_INLINE_SIZE; + init_waitqueue_head(&man->alloc_queue); + init_waitqueue_head(&man->idle_queue); + man->dev_priv = dev_priv; + man->max_hw_submitted = SVGA_CB_MAX_QUEUED_PER_CONTEXT - 1; + INIT_WORK(&man->work, &vmw_cmdbuf_work_func); + vmw_generic_waiter_add(dev_priv, SVGA_IRQFLAG_ERROR, + &dev_priv->error_waiters); + ret = vmw_cmdbuf_startstop(man, true); + if (ret) { + DRM_ERROR("Failed starting command buffer context 0.\n"); + vmw_cmdbuf_man_destroy(man); + return ERR_PTR(ret); + } + + return man; + +out_no_dpool: + dma_pool_destroy(man->headers); +out_no_pool: + kfree(man); + + return ERR_PTR(ret); +} + +/** + * vmw_cmdbuf_remove_pool - Take down the main buffer space pool. + * + * @man: Pointer to a command buffer manager. + * + * This function removes the main buffer space pool, and should be called + * before MOB memory management is removed. When this function has been called, + * only small command buffer submissions of size VMW_CMDBUF_INLINE_SIZE or + * less are allowed, and the default size of the command buffer for small kernel + * submissions is also set to this size. + */ +void vmw_cmdbuf_remove_pool(struct vmw_cmdbuf_man *man) +{ + if (!man->has_pool) + return; + + man->has_pool = false; + man->default_size = VMW_CMDBUF_INLINE_SIZE; + (void) vmw_cmdbuf_idle(man, false, 10*HZ); + if (man->using_mob) { + (void) ttm_bo_kunmap(&man->map_obj); + ttm_bo_unref(&man->cmd_space); + } else { + dma_free_coherent(&man->dev_priv->dev->pdev->dev, + man->size, man->map, man->handle); + } +} + +/** + * vmw_cmdbuf_man_destroy - Take down a command buffer manager. + * + * @man: Pointer to a command buffer manager. + * + * This function idles and then destroys a command buffer manager. + */ +void vmw_cmdbuf_man_destroy(struct vmw_cmdbuf_man *man) +{ + WARN_ON_ONCE(man->has_pool); + (void) vmw_cmdbuf_idle(man, false, 10*HZ); + if (vmw_cmdbuf_startstop(man, false)) + DRM_ERROR("Failed stopping command buffer context 0.\n"); + + vmw_generic_waiter_remove(man->dev_priv, SVGA_IRQFLAG_ERROR, + &man->dev_priv->error_waiters); + tasklet_kill(&man->tasklet); + (void) cancel_work_sync(&man->work); + dma_pool_destroy(man->dheaders); + dma_pool_destroy(man->headers); + mutex_destroy(&man->cur_mutex); + mutex_destroy(&man->space_mutex); + kfree(man); +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index a4766acd0ea2..7e2b3c84119b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -278,6 +278,8 @@ static void vmw_print_capabilities(uint32_t capabilities) DRM_INFO(" Command Buffers 2.\n"); if (capabilities & SVGA_CAP_GBOBJECTS) DRM_INFO(" Guest Backed Resources.\n"); + if (capabilities & SVGA_CAP_CMD_BUFFERS_3) + DRM_INFO(" Command Buffers 3.\n"); } /** @@ -362,6 +364,17 @@ static int vmw_request_device_late(struct vmw_private *dev_priv) } } + if (dev_priv->cman) { + ret = vmw_cmdbuf_set_pool_size(dev_priv->cman, + 256*4096, 2*4096); + if (ret) { + struct vmw_cmdbuf_man *man = dev_priv->cman; + + dev_priv->cman = NULL; + vmw_cmdbuf_man_destroy(man); + } + } + return 0; } @@ -375,6 +388,9 @@ static int vmw_request_device(struct vmw_private *dev_priv) return ret; } vmw_fence_fifo_up(dev_priv->fman); + dev_priv->cman = vmw_cmdbuf_man_create(dev_priv); + if (IS_ERR(dev_priv->cman)) + dev_priv->cman = NULL; ret = vmw_request_device_late(dev_priv); if (ret) @@ -387,10 +403,14 @@ static int vmw_request_device(struct vmw_private *dev_priv) return 0; out_no_query_bo: + if (dev_priv->cman) + vmw_cmdbuf_remove_pool(dev_priv->cman); if (dev_priv->has_mob) { (void) ttm_bo_evict_mm(&dev_priv->bdev, VMW_PL_MOB); vmw_otables_takedown(dev_priv); } + if (dev_priv->cman) + vmw_cmdbuf_man_destroy(dev_priv->cman); out_no_mob: vmw_fence_fifo_down(dev_priv->fman); vmw_fifo_release(dev_priv, &dev_priv->fifo); @@ -415,6 +435,9 @@ static void vmw_release_device_early(struct vmw_private *dev_priv) BUG_ON(dev_priv->pinned_bo != NULL); ttm_bo_unref(&dev_priv->dummy_query_bo); + if (dev_priv->cman) + vmw_cmdbuf_remove_pool(dev_priv->cman); + if (dev_priv->has_mob) { ttm_bo_evict_mm(&dev_priv->bdev, VMW_PL_MOB); vmw_otables_takedown(dev_priv); @@ -432,6 +455,9 @@ static void vmw_release_device_early(struct vmw_private *dev_priv) static void vmw_release_device_late(struct vmw_private *dev_priv) { vmw_fence_fifo_down(dev_priv->fman); + if (dev_priv->cman) + vmw_cmdbuf_man_destroy(dev_priv->cman); + vmw_fifo_release(dev_priv, &dev_priv->fifo); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index a5f221eaf076..8fd40c6bad06 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -453,6 +453,8 @@ struct vmw_private { spinlock_t waiter_lock; int fence_queue_waiters; /* Protected by waiter_lock */ int goal_queue_waiters; /* Protected by waiter_lock */ + int cmdbuf_waiters; /* Protected by irq_lock */ + int error_waiters; /* Protected by irq_lock */ atomic_t fifo_queue_waiters; uint32_t last_read_seqno; spinlock_t irq_lock; @@ -535,6 +537,8 @@ struct vmw_private { */ struct ttm_buffer_object *otable_bo; struct vmw_otable *otables; + + struct vmw_cmdbuf_man *cman; }; static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res) @@ -729,6 +733,8 @@ extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv); extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv); extern int vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv, uint32_t cid); +extern int vmw_fifo_flush(struct vmw_private *dev_priv, + bool interruptible); /** * TTM glue - vmwgfx_ttm_glue.c @@ -753,6 +759,7 @@ extern struct ttm_placement vmw_sys_ne_placement; extern struct ttm_placement vmw_evictable_placement; extern struct ttm_placement vmw_srf_placement; extern struct ttm_placement vmw_mob_placement; +extern struct ttm_placement vmw_mob_ne_placement; extern struct ttm_bo_driver vmw_bo_driver; extern int vmw_dma_quiescent(struct drm_device *dev); extern int vmw_bo_map_dma(struct ttm_buffer_object *bo); @@ -855,6 +862,10 @@ extern void vmw_seqno_waiter_add(struct vmw_private *dev_priv); extern void vmw_seqno_waiter_remove(struct vmw_private *dev_priv); extern void vmw_goal_waiter_add(struct vmw_private *dev_priv); extern void vmw_goal_waiter_remove(struct vmw_private *dev_priv); +extern void vmw_generic_waiter_add(struct vmw_private *dev_priv, u32 flag, + int *waiter_count); +extern void vmw_generic_waiter_remove(struct vmw_private *dev_priv, + u32 flag, int *waiter_count); /** * Rudimentary fence-like objects currently used only for throttling - @@ -1077,6 +1088,35 @@ extern int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man, struct list_head *list); +/* + * Command buffer managerment vmwgfx_cmdbuf.c + */ +struct vmw_cmdbuf_man; +struct vmw_cmdbuf_header; + +extern struct vmw_cmdbuf_man * +vmw_cmdbuf_man_create(struct vmw_private *dev_priv); +extern int vmw_cmdbuf_set_pool_size(struct vmw_cmdbuf_man *man, + size_t size, size_t default_size); +extern void vmw_cmdbuf_remove_pool(struct vmw_cmdbuf_man *man); +extern void vmw_cmdbuf_man_destroy(struct vmw_cmdbuf_man *man); +extern int vmw_cmdbuf_idle(struct vmw_cmdbuf_man *man, bool interruptible, + unsigned long timeout); +extern void *vmw_cmdbuf_reserve(struct vmw_cmdbuf_man *man, size_t size, + int ctx_id, bool interruptible, + struct vmw_cmdbuf_header *header); +extern void vmw_cmdbuf_commit(struct vmw_cmdbuf_man *man, size_t size, + struct vmw_cmdbuf_header *header, + bool flush); +extern void vmw_cmdbuf_tasklet_schedule(struct vmw_cmdbuf_man *man); +extern void *vmw_cmdbuf_alloc(struct vmw_cmdbuf_man *man, + size_t size, bool interruptible, + struct vmw_cmdbuf_header **p_header); +extern void vmw_cmdbuf_header_free(struct vmw_cmdbuf_header *header); +extern int vmw_cmdbuf_cur_flush(struct vmw_cmdbuf_man *man, + bool interruptible); + + /** * Inline helper functions */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 654c8daeb5ab..0792d8d59315 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -2417,7 +2417,126 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, } } +/** + * vmw_execbuf_submit_fifo - Patch a command batch and submit it using + * the fifo. + * + * @dev_priv: Pointer to a device private structure. + * @kernel_commands: Pointer to the unpatched command batch. + * @command_size: Size of the unpatched command batch. + * @sw_context: Structure holding the relocation lists. + * + * Side effects: If this function returns 0, then the command batch + * pointed to by @kernel_commands will have been modified. + */ +static int vmw_execbuf_submit_fifo(struct vmw_private *dev_priv, + void *kernel_commands, + u32 command_size, + struct vmw_sw_context *sw_context) +{ + void *cmd = vmw_fifo_reserve(dev_priv, command_size); + + if (!cmd) { + DRM_ERROR("Failed reserving fifo space for commands.\n"); + return -ENOMEM; + } + + vmw_apply_relocations(sw_context); + memcpy(cmd, kernel_commands, command_size); + vmw_resource_relocations_apply(cmd, &sw_context->res_relocations); + vmw_resource_relocations_free(&sw_context->res_relocations); + vmw_fifo_commit(dev_priv, command_size); + + return 0; +} +/** + * vmw_execbuf_submit_cmdbuf - Patch a command batch and submit it using + * the command buffer manager. + * + * @dev_priv: Pointer to a device private structure. + * @header: Opaque handle to the command buffer allocation. + * @command_size: Size of the unpatched command batch. + * @sw_context: Structure holding the relocation lists. + * + * Side effects: If this function returns 0, then the command buffer + * represented by @header will have been modified. + */ +static int vmw_execbuf_submit_cmdbuf(struct vmw_private *dev_priv, + struct vmw_cmdbuf_header *header, + u32 command_size, + struct vmw_sw_context *sw_context) +{ + void *cmd = vmw_cmdbuf_reserve(dev_priv->cman, command_size, + SVGA3D_INVALID_ID, false, header); + + vmw_apply_relocations(sw_context); + vmw_resource_relocations_apply(cmd, &sw_context->res_relocations); + vmw_resource_relocations_free(&sw_context->res_relocations); + vmw_cmdbuf_commit(dev_priv->cman, command_size, header, false); + + return 0; +} + +/** + * vmw_execbuf_cmdbuf - Prepare, if possible, a user-space command batch for + * submission using a command buffer. + * + * @dev_priv: Pointer to a device private structure. + * @user_commands: User-space pointer to the commands to be submitted. + * @command_size: Size of the unpatched command batch. + * @header: Out parameter returning the opaque pointer to the command buffer. + * + * This function checks whether we can use the command buffer manager for + * submission and if so, creates a command buffer of suitable size and + * copies the user data into that buffer. + * + * On successful return, the function returns a pointer to the data in the + * command buffer and *@header is set to non-NULL. + * If command buffers could not be used, the function will return the value + * of @kernel_commands on function call. That value may be NULL. In that case, + * the value of *@header will be set to NULL. + * If an error is encountered, the function will return a pointer error value. + * If the function is interrupted by a signal while sleeping, it will return + * -ERESTARTSYS casted to a pointer error value. + */ +void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv, + void __user *user_commands, + void *kernel_commands, + u32 command_size, + struct vmw_cmdbuf_header **header) +{ + size_t cmdbuf_size; + int ret; + + *header = NULL; + if (!dev_priv->cman || kernel_commands) + return kernel_commands; + + if (command_size > SVGA_CB_MAX_SIZE) { + DRM_ERROR("Command buffer is too large.\n"); + return ERR_PTR(-EINVAL); + } + + /* If possible, add a little space for fencing. */ + cmdbuf_size = command_size + 512; + cmdbuf_size = min_t(size_t, cmdbuf_size, SVGA_CB_MAX_SIZE); + kernel_commands = vmw_cmdbuf_alloc(dev_priv->cman, cmdbuf_size, + true, header); + if (IS_ERR(kernel_commands)) + return kernel_commands; + + ret = copy_from_user(kernel_commands, user_commands, + command_size); + if (ret) { + DRM_ERROR("Failed copying commands.\n"); + vmw_cmdbuf_header_free(*header); + *header = NULL; + return ERR_PTR(-EFAULT); + } + + return kernel_commands; +} int vmw_execbuf_process(struct drm_file *file_priv, struct vmw_private *dev_priv, @@ -2432,18 +2551,33 @@ int vmw_execbuf_process(struct drm_file *file_priv, struct vmw_fence_obj *fence = NULL; struct vmw_resource *error_resource; struct list_head resource_list; + struct vmw_cmdbuf_header *header; struct ww_acquire_ctx ticket; uint32_t handle; - void *cmd; int ret; + if (throttle_us) { + ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.marker_queue, + throttle_us); + + if (ret) + return ret; + } + + kernel_commands = vmw_execbuf_cmdbuf(dev_priv, user_commands, + kernel_commands, command_size, + &header); + if (IS_ERR(kernel_commands)) + return PTR_ERR(kernel_commands); + ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex); - if (unlikely(ret != 0)) - return -ERESTARTSYS; + if (ret) { + ret = -ERESTARTSYS; + goto out_free_header; + } + sw_context->kernel = false; if (kernel_commands == NULL) { - sw_context->kernel = false; - ret = vmw_resize_cmd_bounce(sw_context, command_size); if (unlikely(ret != 0)) goto out_unlock; @@ -2458,7 +2592,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, goto out_unlock; } kernel_commands = sw_context->cmd_bounce; - } else + } else if (!header) sw_context->kernel = true; sw_context->fp = vmw_fpriv(file_priv); @@ -2478,7 +2612,6 @@ int vmw_execbuf_process(struct drm_file *file_priv, sw_context->res_ht_initialized = true; } INIT_LIST_HEAD(&sw_context->staged_cmd_res); - INIT_LIST_HEAD(&resource_list); ret = vmw_cmd_check_all(dev_priv, sw_context, kernel_commands, command_size); @@ -2502,14 +2635,6 @@ int vmw_execbuf_process(struct drm_file *file_priv, if (unlikely(ret != 0)) goto out_err; - if (throttle_us) { - ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.marker_queue, - throttle_us); - - if (unlikely(ret != 0)) - goto out_err; - } - ret = mutex_lock_interruptible(&dev_priv->binding_mutex); if (unlikely(ret != 0)) { ret = -ERESTARTSYS; @@ -2522,20 +2647,16 @@ int vmw_execbuf_process(struct drm_file *file_priv, goto out_unlock_binding; } - cmd = vmw_fifo_reserve(dev_priv, command_size); - if (unlikely(cmd == NULL)) { - DRM_ERROR("Failed reserving fifo space for commands.\n"); - ret = -ENOMEM; - goto out_unlock_binding; + if (!header) { + ret = vmw_execbuf_submit_fifo(dev_priv, kernel_commands, + command_size, sw_context); + } else { + ret = vmw_execbuf_submit_cmdbuf(dev_priv, header, command_size, + sw_context); + header = NULL; } - - vmw_apply_relocations(sw_context); - memcpy(cmd, kernel_commands, command_size); - - vmw_resource_relocations_apply(cmd, &sw_context->res_relocations); - vmw_resource_relocations_free(&sw_context->res_relocations); - - vmw_fifo_commit(dev_priv, command_size); + if (ret) + goto out_unlock_binding; vmw_query_bo_switch_commit(dev_priv, sw_context); ret = vmw_execbuf_fence_commands(file_priv, dev_priv, @@ -2610,6 +2731,9 @@ out_unlock: vmw_resource_list_unreference(&resource_list); if (unlikely(error_resource != NULL)) vmw_resource_unreference(&error_resource); +out_free_header: + if (header) + vmw_cmdbuf_header_free(header); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index ecdc8d99f2fb..d0a3bcf5c0d2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -257,6 +257,7 @@ static void vmw_fb_dirty_flush(struct vmw_fb_par *par) cmd->body.width = cpu_to_le32(w); cmd->body.height = cpu_to_le32(h); vmw_fifo_commit(vmw_priv, sizeof(*cmd)); + vmw_fifo_flush(vmw_priv, false); } static void vmw_fb_dirty_mark(struct vmw_fb_par *par, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index cd5d9f3fe0e0..189102d0ac8b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -310,7 +310,8 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv, * Returns: * Pointer to the fifo, or null on error (possible hardware hang). */ -void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes) +static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv, + uint32_t bytes) { struct vmw_fifo_state *fifo_state = &dev_priv->fifo; __le32 __iomem *fifo_mem = dev_priv->mmio_virt; @@ -389,9 +390,29 @@ void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes) out_err: fifo_state->reserved_size = 0; mutex_unlock(&fifo_state->fifo_mutex); + return NULL; } +void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes) +{ + void *ret; + + if (dev_priv->cman) + ret = vmw_cmdbuf_reserve(dev_priv->cman, bytes, + SVGA3D_INVALID_ID, false, NULL); + else + ret = vmw_local_fifo_reserve(dev_priv, bytes); + if (IS_ERR_OR_NULL(ret)) { + DRM_ERROR("Fifo reserve failure of %u bytes.\n", + (unsigned) bytes); + dump_stack(); + return NULL; + } + + return ret; +} + static void vmw_fifo_res_copy(struct vmw_fifo_state *fifo_state, __le32 __iomem *fifo_mem, uint32_t next_cmd, @@ -434,7 +455,7 @@ static void vmw_fifo_slow_copy(struct vmw_fifo_state *fifo_state, } } -void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) +void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) { struct vmw_fifo_state *fifo_state = &dev_priv->fifo; __le32 __iomem *fifo_mem = dev_priv->mmio_virt; @@ -480,6 +501,46 @@ void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) mutex_unlock(&fifo_state->fifo_mutex); } +void vmw_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) +{ + if (dev_priv->cman) + vmw_cmdbuf_commit(dev_priv->cman, bytes, NULL, false); + else + vmw_local_fifo_commit(dev_priv, bytes); +} + + +/** + * vmw_fifo_commit_flush - Commit fifo space and flush any buffered commands. + * + * @dev_priv: Pointer to device private structure. + * @bytes: Number of bytes to commit. + */ +static void vmw_fifo_commit_flush(struct vmw_private *dev_priv, uint32_t bytes) +{ + if (dev_priv->cman) + vmw_cmdbuf_commit(dev_priv->cman, bytes, NULL, true); + else + vmw_local_fifo_commit(dev_priv, bytes); +} + +/** + * vmw_fifo_flush - Flush any buffered commands and make sure command processing + * starts. + * + * @dev_priv: Pointer to device private structure. + * @interruptible: Whether to wait interruptible if function needs to sleep. + */ +int vmw_fifo_flush(struct vmw_private *dev_priv, bool interruptible) +{ + might_sleep(); + + if (dev_priv->cman) + return vmw_cmdbuf_cur_flush(dev_priv->cman, interruptible); + else + return 0; +} + int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) { struct vmw_fifo_state *fifo_state = &dev_priv->fifo; @@ -517,7 +578,7 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) ((unsigned long)fm + sizeof(__le32)); iowrite32(*seqno, &cmd_fence->fence); - vmw_fifo_commit(dev_priv, bytes); + vmw_fifo_commit_flush(dev_priv, bytes); (void) vmw_marker_push(&fifo_state->marker_queue, *seqno); vmw_update_seqno(dev_priv, fifo_state); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index 9fe9827ee499..87964bb0704e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -56,6 +56,9 @@ irqreturn_t vmw_irq_handler(int irq, void *arg) if (masked_status & SVGA_IRQFLAG_FIFO_PROGRESS) wake_up_all(&dev_priv->fifo_queue); + if (masked_status & (SVGA_IRQFLAG_COMMAND_BUFFER | + SVGA_IRQFLAG_ERROR)) + vmw_cmdbuf_tasklet_schedule(dev_priv->cman); return IRQ_HANDLED; } @@ -131,8 +134,16 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, * Block command submission while waiting for idle. */ - if (fifo_idle) + if (fifo_idle) { down_read(&fifo_state->rwsem); + if (dev_priv->cman) { + ret = vmw_cmdbuf_idle(dev_priv->cman, interruptible, + 10*HZ); + if (ret) + goto out_err; + } + } + signal_seq = atomic_read(&dev_priv->marker_seq); ret = 0; @@ -171,6 +182,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, iowrite32(signal_seq, fifo_mem + SVGA_FIFO_FENCE); } wake_up_all(&dev_priv->fence_queue); +out_err: if (fifo_idle) up_read(&fifo_state->rwsem); @@ -315,3 +327,30 @@ void vmw_irq_uninstall(struct drm_device *dev) status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); } + +void vmw_generic_waiter_add(struct vmw_private *dev_priv, + u32 flag, int *waiter_count) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&dev_priv->irq_lock, irq_flags); + if ((*waiter_count)++ == 0) { + outl(flag, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); + dev_priv->irq_mask |= flag; + vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); + } + spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); +} + +void vmw_generic_waiter_remove(struct vmw_private *dev_priv, + u32 flag, int *waiter_count) +{ + unsigned long irq_flags; + + spin_lock_irqsave(&dev_priv->irq_lock, irq_flags); + if (--(*waiter_count) == 0) { + dev_priv->irq_mask &= ~flag; + vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask); + } + spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags); +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 07cda8cbbddb..b5632c25d94e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -631,6 +631,7 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, flags, color, clips, num_clips, inc, NULL); + vmw_fifo_flush(dev_priv, false); ttm_read_unlock(&dev_priv->reservation_sem); drm_modeset_unlock_all(dev_priv->dev); @@ -987,6 +988,7 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, clips, num_clips, increment, NULL); } + vmw_fifo_flush(dev_priv, false); ttm_read_unlock(&dev_priv->reservation_sem); drm_modeset_unlock_all(dev_priv->dev); @@ -1347,6 +1349,8 @@ int vmw_kms_present(struct vmw_private *dev_priv, break; } + vmw_fifo_flush(dev_priv, false); + kfree(cmd); out_free_tmp: kfree(tmp); -- cgit v1.3-6-gb490 From ee511a835a681ee147666a0c85b96f8a43aae2d5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 25 Jun 2015 12:00:39 -0700 Subject: drm/vmwgfx: Fix an overlay lockdep error Fix a circular locking dependency between struct vmw_overlay::mutex and struct vmw_private::reservation_sem Signed-off-by: Thomas Hellstrom Reviewed-by: Brian Paul --- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 210ef15b1d09..3fd80701771a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -900,20 +900,21 @@ int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), vmw_user_stream_size, false, true); + ttm_read_unlock(&dev_priv->reservation_sem); if (unlikely(ret != 0)) { if (ret != -ERESTARTSYS) DRM_ERROR("Out of graphics memory for stream" " creation.\n"); - goto out_unlock; - } + goto out_ret; + } stream = kmalloc(sizeof(*stream), GFP_KERNEL); if (unlikely(stream == NULL)) { ttm_mem_global_free(vmw_mem_glob(dev_priv), vmw_user_stream_size); ret = -ENOMEM; - goto out_unlock; + goto out_ret; } res = &stream->stream.res; @@ -926,7 +927,7 @@ int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, ret = vmw_stream_init(dev_priv, &stream->stream, vmw_user_stream_free); if (unlikely(ret != 0)) - goto out_unlock; + goto out_ret; tmp = vmw_resource_reference(res); ret = ttm_base_object_init(tfile, &stream->base, false, VMW_RES_STREAM, @@ -940,8 +941,7 @@ int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, arg->stream_id = res->id; out_err: vmw_resource_unreference(&res); -out_unlock: - ttm_read_unlock(&dev_priv->reservation_sem); +out_ret: return ret; } -- cgit v1.3-6-gb490 From ed93394c14ba50e3e53ef289116625f0f05f8616 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Mar 2015 23:26:06 -0800 Subject: drm/vmwgfx: Add an interface to pin a resource v3 For screen targets it appears we need to pin surfaces while they are bound as screen targets, so add a small interface to do that. v2: Always increase pin_count on pin. v3: Add missing reservation sem. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 ++ drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 91 +++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 8fd40c6bad06..338dce3607fb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -113,6 +113,7 @@ struct vmw_resource { bool backup_dirty; /* Protected by backup buffer reserved */ struct vmw_dma_buffer *backup; unsigned long backup_offset; + unsigned long pin_count; /* Protected by resource reserved */ const struct vmw_res_func *func; struct list_head lru_head; /* Protected by the resource lock */ struct list_head mob_head; /* Protected by @backup reserved */ @@ -941,6 +942,9 @@ int vmw_dumb_map_offset(struct drm_file *file_priv, int vmw_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle); +extern int vmw_resource_pin(struct vmw_resource *res); +extern void vmw_resource_unpin(struct vmw_resource *res); + /** * Overlay control - vmwgfx_overlay.c */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 3fd80701771a..6738c1ebf09a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -1183,7 +1183,7 @@ void vmw_resource_unreserve(struct vmw_resource *res, if (new_backup) res->backup_offset = new_backup_offset; - if (!res->func->may_evict || res->id == -1) + if (!res->func->may_evict || res->id == -1 || res->pin_count) return; write_lock(&dev_priv->resource_lock); @@ -1573,3 +1573,92 @@ void vmw_resource_evict_all(struct vmw_private *dev_priv) mutex_unlock(&dev_priv->cmdbuf_mutex); } + +/** + * vmw_resource_pin - Add a pin reference on a resource + * + * @res: The resource to add a pin reference on + * + * This function adds a pin reference, and if needed validates the resource. + * Having a pin reference means that the resource can never be evicted, and + * its id will never change as long as there is a pin reference. + * This function returns 0 on success and a negative error code on failure. + */ +int vmw_resource_pin(struct vmw_resource *res) +{ + struct vmw_private *dev_priv = res->dev_priv; + int ret; + + ttm_write_lock(&dev_priv->reservation_sem, false); + mutex_lock(&dev_priv->cmdbuf_mutex); + ret = vmw_resource_reserve(res, false); + if (ret) + goto out_no_reserve; + + if (res->pin_count == 0) { + struct ttm_buffer_object *bo = NULL; + + if (res->backup) { + bo = &res->backup->base; + + ttm_bo_reserve(bo, false, false, false, NULL); + ret = ttm_bo_validate(bo, res->func->backup_placement, + false, false); + if (ret) { + ttm_bo_unreserve(bo); + goto out_no_validate; + } + + /* Do we really need to pin the MOB as well? */ + vmw_bo_pin(bo, true); + } + ret = vmw_resource_validate(res); + if (bo) + ttm_bo_unreserve(bo); + if (ret) + goto out_no_validate; + } + res->pin_count++; + +out_no_validate: + vmw_resource_unreserve(res, NULL, 0UL); +out_no_reserve: + mutex_unlock(&dev_priv->cmdbuf_mutex); + ttm_write_unlock(&dev_priv->reservation_sem); + + return ret; +} + +/** + * vmw_resource_unpin - Remove a pin reference from a resource + * + * @res: The resource to remove a pin reference from + * + * Having a pin reference means that the resource can never be evicted, and + * its id will never change as long as there is a pin reference. + */ +void vmw_resource_unpin(struct vmw_resource *res) +{ + struct vmw_private *dev_priv = res->dev_priv; + int ret; + + ttm_read_lock(&dev_priv->reservation_sem, false); + mutex_lock(&dev_priv->cmdbuf_mutex); + + ret = vmw_resource_reserve(res, true); + WARN_ON(ret); + + WARN_ON(res->pin_count == 0); + if (--res->pin_count == 0 && res->backup) { + struct ttm_buffer_object *bo = &res->backup->base; + + ttm_bo_reserve(bo, false, false, false, NULL); + vmw_bo_pin(bo, false); + ttm_bo_unreserve(bo); + } + + vmw_resource_unreserve(res, NULL, 0UL); + + mutex_unlock(&dev_priv->cmdbuf_mutex); + ttm_read_unlock(&dev_priv->reservation_sem); +} -- cgit v1.3-6-gb490 From 7b64115fc79c766ba2f89ec822427d720f395f3f Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Fri, 27 Feb 2015 04:44:24 -0800 Subject: drm/vmwgfx: SVGA device definition update Update device definition headers to support screen targets. Signed-off-by: Sinclair Yeh Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/svga3d_reg.h | 56 ++++++++++++++++++++++-- drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h | 67 +++++++++++++++++++++++++++-- 2 files changed, 117 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/svga3d_reg.h b/drivers/gpu/drm/vmwgfx/svga3d_reg.h index e50d20c9cfe8..c9a595a78f2e 100644 --- a/drivers/gpu/drm/vmwgfx/svga3d_reg.h +++ b/drivers/gpu/drm/vmwgfx/svga3d_reg.h @@ -1,5 +1,5 @@ /********************************************************** - * Copyright 1998-2009 VMware, Inc. All rights reserved. + * Copyright 1998-2014 VMware, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -224,7 +224,7 @@ typedef enum SVGA3dSurfaceFormat { SVGA3D_R8_SNORM = 95, SVGA3D_R8_SINT = 96, SVGA3D_A8_UNORM = 32, - SVGA3D_R1_UNORM = 97, + SVGA3D_P8 = 97, SVGA3D_R9G9B9E5_SHAREDEXP = 98, SVGA3D_R8G8_B8G8_UNORM = 99, SVGA3D_G8R8_G8B8_UNORM = 100, @@ -1312,6 +1312,11 @@ struct { typedef enum { SVGA3D_SURFACE_CUBEMAP = (1 << 0), + + /* + * HINT flags are not enforced by the device but are useful for + * performance. + */ SVGA3D_SURFACE_HINT_STATIC = (1 << 1), SVGA3D_SURFACE_HINT_DYNAMIC = (1 << 2), SVGA3D_SURFACE_HINT_INDEXBUFFER = (1 << 3), @@ -1322,6 +1327,50 @@ typedef enum { SVGA3D_SURFACE_HINT_WRITEONLY = (1 << 8), SVGA3D_SURFACE_MASKABLE_ANTIALIAS = (1 << 9), SVGA3D_SURFACE_AUTOGENMIPMAPS = (1 << 10), + SVGA3D_SURFACE_DECODE_RENDERTARGET = (1 << 11), + + /* + * Is this surface using a base-level pitch for it's mob backing? + * + * This flag is not intended to be set by guest-drivers, but is instead + * set by the device when the surface is bound to a mob with a specified + * pitch. + */ + SVGA3D_SURFACE_MOB_PITCH = (1 << 12), + + SVGA3D_SURFACE_INACTIVE = (1 << 13), + SVGA3D_SURFACE_HINT_RT_LOCKABLE = (1 << 14), + SVGA3D_SURFACE_VOLUME = (1 << 15), + + /* + * Required to be set on a surface to bind it to a screen target. + */ + SVGA3D_SURFACE_SCREENTARGET = (1 << 16), + + /* + * Align images in the guest-backing mob to 16-bytes. + */ + SVGA3D_SURFACE_ALIGN16 = (1 << 17), + + SVGA3D_SURFACE_1D = (1 << 18), + SVGA3D_SURFACE_ARRAY = (1 << 19), + + /* + * Bind flags. + * These are enforced for any surface defined with DefineGBSurface_v2. + */ + SVGA3D_SURFACE_BIND_VERTEX_BUFFER = (1 << 20), + SVGA3D_SURFACE_BIND_INDEX_BUFFER = (1 << 21), + SVGA3D_SURFACE_BIND_CONSTANT_BUFFER = (1 << 22), + SVGA3D_SURFACE_BIND_SHADER_RESOURCE = (1 << 23), + SVGA3D_SURFACE_BIND_RENDER_TARGET = (1 << 24), + SVGA3D_SURFACE_BIND_DEPTH_STENCIL = (1 << 25), + SVGA3D_SURFACE_BIND_STREAM_OUTPUT = (1 << 26), + + /* + * Marker for the last defined bit. + */ + SVGA3D_SURFACE_FLAG_MAX = (1 << 27), } SVGA3dSurfaceFlags; typedef @@ -2400,6 +2449,7 @@ struct { int32 xRoot; int32 yRoot; uint32 flags; + uint32 dpi; } __packed SVGA3dCmdDefineGBScreenTarget; /* SVGA_3D_CMD_DEFINE_GB_SCREENTARGET */ @@ -2419,7 +2469,7 @@ SVGA3dCmdBindGBScreenTarget; /* SVGA_3D_CMD_BIND_GB_SCREENTARGET */ typedef struct { uint32 stid; - SVGA3dBox box; + SVGA3dRect rect; } __packed SVGA3dCmdUpdateGBScreenTarget; /* SVGA_3D_CMD_UPDATE_GB_SCREENTARGET */ diff --git a/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h b/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h index ef3385096145..d55ab01d4c45 100644 --- a/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h +++ b/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h @@ -608,9 +608,9 @@ static const struct svga3d_surface_desc svga3d_surface_descs[] = { {1, 1, 1}, 1, 1, {8, {{0}, {0}, {8}, {0} } }, {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R8_SINT */ - {SVGA3DBLOCKDESC_RED, - {8, 1, 1}, 1, 1, {8, {{0}, {0}, {8}, {0} } }, - {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_R1_UNORM */ + {SVGA3DBLOCKDESC_NONE, + {1, 1, 1}, 1, 1, {8, {{0}, {0}, {8}, {0} } }, + {{{0}, {0}, {0}, {0} } } }, /* SVGA3D_P8 */ {SVGA3DBLOCKDESC_RGBE, {1, 1, 1}, 4, 4, {32, {{9}, {9}, {9}, {5} } }, @@ -910,3 +910,64 @@ svga3dsurface_get_image_offset(SVGA3dSurfaceFormat format, return offset; } + + +/** + * svga3dsurface_is_gb_screen_target_format - Is the specified format usable as + * a ScreenTarget? + * (with just the GBObjects cap-bit + * set) + * @format: format to queried + * + * RETURNS: + * true if queried format is valid for screen targets + */ +static inline bool +svga3dsurface_is_gb_screen_target_format(SVGA3dSurfaceFormat format) +{ + return (format == SVGA3D_X8R8G8B8 || + format == SVGA3D_A8R8G8B8 || + format == SVGA3D_R5G6B5 || + format == SVGA3D_X1R5G5B5 || + format == SVGA3D_A1R5G5B5 || + format == SVGA3D_P8); +} + + +/** + * svga3dsurface_is_dx_screen_target_format - Is the specified format usable as + * a ScreenTarget? + * (with DX10 enabled) + * + * @format: format to queried + * + * Results: + * true if queried format is valid for screen targets + */ +static inline bool +svga3dsurface_is_dx_screen_target_format(SVGA3dSurfaceFormat format) +{ + return (format == SVGA3D_R8G8B8A8_UNORM || + format == SVGA3D_B8G8R8A8_UNORM || + format == SVGA3D_B8G8R8X8_UNORM); +} + + +/** + * svga3dsurface_is_screen_target_format - Is the specified format usable as a + * ScreenTarget? + * (for some combination of caps) + * + * @format: format to queried + * + * Results: + * true if queried format is valid for screen targets + */ +static inline bool +svga3dsurface_is_screen_target_format(SVGA3dSurfaceFormat format) +{ + if (svga3dsurface_is_gb_screen_target_format(format)) { + return true; + } + return svga3dsurface_is_dx_screen_target_format(format); +} -- cgit v1.3-6-gb490 From 233826a74881e38aca20ced22842322269877612 Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Thu, 5 Mar 2015 01:06:13 -0800 Subject: drm/vmwgfx: Refactor vmw_gb_surface_define_ioctl() Refactored vmw_gb_surface_define_ioctl() and made the surface definition part a separate function. This way other parts of vmwgfx can use it to allocate kernel-visible GB surfaces. Signed-off-by: Sinclair Yeh Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 9 ++ drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 195 ++++++++++++++++++++++---------- 2 files changed, 143 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 338dce3607fb..c300a0a1dd8a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1043,6 +1043,15 @@ extern int vmw_surface_check(struct vmw_private *dev_priv, uint32_t handle, int *id); extern int vmw_surface_validate(struct vmw_private *dev_priv, struct vmw_surface *srf); +int vmw_surface_gb_priv_define(struct drm_device *dev, + uint32_t user_accounting_size, + uint32_t svga3d_flags, + SVGA3dSurfaceFormat format, + bool for_scanout, + uint32_t num_mip_levels, + uint32_t multisample_count, + struct drm_vmw_size size, + struct vmw_surface **srf_out); /* * Shader management - vmwgfx_shader.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 4d0c98edeb6a..fb54ccd4e87d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright © 2009-2012 VMware, Inc., Palo Alto, CA., USA + * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -36,7 +36,7 @@ * @base: The TTM base object handling user-space visibility. * @srf: The surface metadata. * @size: TTM accounting size for the surface. - * @master: master of the creating client. Used for security check. + * @master: master of the creating client. Used for security check. */ struct vmw_user_surface { struct ttm_prime_object prime; @@ -1218,6 +1218,7 @@ static int vmw_gb_surface_destroy(struct vmw_resource *res) return 0; } + /** * vmw_gb_surface_define_ioctl - Ioctl function implementing * the user surface define functionality. @@ -1241,77 +1242,43 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; int ret; uint32_t size; - const struct svga3d_surface_desc *desc; uint32_t backup_handle; + if (unlikely(vmw_user_surface_size == 0)) vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) + 128; size = vmw_user_surface_size + 128; - desc = svga3dsurface_get_desc(req->format); - if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) { - DRM_ERROR("Invalid surface format for surface creation.\n"); - return -EINVAL; - } - - ret = ttm_read_lock(&dev_priv->reservation_sem, true); + /* Define a surface based on the parameters. */ + ret = vmw_surface_gb_priv_define(dev, + size, + req->svga3d_flags, + req->format, + req->drm_surface_flags & drm_vmw_surface_flag_scanout, + req->mip_levels, + req->multisample_count, + req->base_size, + &srf); if (unlikely(ret != 0)) return ret; - ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), - size, false, true); - if (unlikely(ret != 0)) { - if (ret != -ERESTARTSYS) - DRM_ERROR("Out of graphics memory for surface" - " creation.\n"); - goto out_unlock; - } - - user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); - if (unlikely(user_srf == NULL)) { - ret = -ENOMEM; - goto out_no_user_srf; - } - - srf = &user_srf->srf; - res = &srf->res; - - srf->flags = req->svga3d_flags; - srf->format = req->format; - srf->scanout = req->drm_surface_flags & drm_vmw_surface_flag_scanout; - srf->mip_levels[0] = req->mip_levels; - srf->num_sizes = 1; - srf->sizes = NULL; - srf->offsets = NULL; - user_srf->size = size; - srf->base_size = req->base_size; - srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; - srf->multisample_count = req->multisample_count; - res->backup_size = svga3dsurface_get_serialized_size - (srf->format, srf->base_size, srf->mip_levels[0], - srf->flags & SVGA3D_SURFACE_CUBEMAP); - - user_srf->prime.base.shareable = false; - user_srf->prime.base.tfile = NULL; + user_srf = container_of(srf, struct vmw_user_surface, srf); if (drm_is_primary_client(file_priv)) user_srf->master = drm_master_get(file_priv->master); - /** - * From this point, the generic resource management functions - * destroy the object on failure. - */ - - ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) - goto out_unlock; + return ret; + + res = &user_srf->srf.res; - if (req->buffer_handle != SVGA3D_INVALID_ID) { + + if (req->buffer_handle != SVGA3D_INVALID_ID) ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle, &res->backup); - } else if (req->drm_surface_flags & - drm_vmw_surface_flag_create_buffer) + else if (req->drm_surface_flags & drm_vmw_surface_flag_create_buffer) ret = vmw_user_dmabuf_alloc(dev_priv, tfile, res->backup_size, req->drm_surface_flags & @@ -1324,7 +1291,7 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, goto out_unlock; } - tmp = vmw_resource_reference(&srf->res); + tmp = vmw_resource_reference(res); ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime, req->drm_surface_flags & drm_vmw_surface_flag_shareable, @@ -1337,7 +1304,7 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, goto out_unlock; } - rep->handle = user_srf->prime.base.hash.key; + rep->handle = user_srf->prime.base.hash.key; rep->backup_size = res->backup_size; if (res->backup) { rep->buffer_map_handle = @@ -1352,10 +1319,6 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, vmw_resource_unreference(&res); - ttm_read_unlock(&dev_priv->reservation_sem); - return 0; -out_no_user_srf: - ttm_mem_global_free(vmw_mem_glob(dev_priv), size); out_unlock: ttm_read_unlock(&dev_priv->reservation_sem); return ret; @@ -1429,3 +1392,113 @@ out_bad_resource: return ret; } + +/** + * vmw_surface_gb_priv_define - Define a private GB surface + * + * @dev: Pointer to a struct drm_device + * @user_accounting_size: Used to track user-space memory usage, set + * to 0 for kernel mode only memory + * @svga3d_flags: SVGA3d surface flags for the device + * @format: requested surface format + * @for_scanout: true if inteded to be used for scanout buffer + * @num_mip_levels: number of MIP levels + * @multisample_count: + * @size: width, heigh, depth of the surface requested + * @user_srf_out: allocated user_srf. Set to NULL on failure. + * + * GB surfaces allocated by this function will not have a user mode handle, and + * thus will only be visible to vmwgfx. For optimization reasons the + * surface may later be given a user mode handle by another function to make + * it available to user mode drivers. + */ +int vmw_surface_gb_priv_define(struct drm_device *dev, + uint32_t user_accounting_size, + uint32_t svga3d_flags, + SVGA3dSurfaceFormat format, + bool for_scanout, + uint32_t num_mip_levels, + uint32_t multisample_count, + struct drm_vmw_size size, + struct vmw_surface **srf_out) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct vmw_user_surface *user_srf; + struct vmw_surface *srf; + int ret; + + + *srf_out = NULL; + + if (for_scanout) { + if (!svga3dsurface_is_screen_target_format(format)) { + DRM_ERROR("Invalid Screen Target surface format."); + return -EINVAL; + } + } else { + const struct svga3d_surface_desc *desc; + + desc = svga3dsurface_get_desc(format); + if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) { + DRM_ERROR("Invalid surface format.\n"); + return -EINVAL; + } + } + + ret = ttm_read_lock(&dev_priv->reservation_sem, true); + if (unlikely(ret != 0)) + return ret; + + ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv), + user_accounting_size, false, true); + if (unlikely(ret != 0)) { + if (ret != -ERESTARTSYS) + DRM_ERROR("Out of graphics memory for surface" + " creation.\n"); + goto out_unlock; + } + + user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL); + if (unlikely(user_srf == NULL)) { + ret = -ENOMEM; + goto out_no_user_srf; + } + + *srf_out = &user_srf->srf; + user_srf->size = user_accounting_size; + user_srf->prime.base.shareable = false; + user_srf->prime.base.tfile = NULL; + + srf = &user_srf->srf; + srf->flags = svga3d_flags; + srf->format = format; + srf->scanout = for_scanout; + srf->mip_levels[0] = num_mip_levels; + srf->num_sizes = 1; + srf->sizes = NULL; + srf->offsets = NULL; + srf->base_size = size; + srf->autogen_filter = SVGA3D_TEX_FILTER_NONE; + srf->multisample_count = multisample_count; + + srf->res.backup_size = svga3dsurface_get_serialized_size(srf->format, + srf->base_size, + srf->mip_levels[0], + srf->flags & SVGA3D_SURFACE_CUBEMAP); + + /* + * From this point, the generic resource management functions + * destroy the object on failure. + */ + ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free); + + ttm_read_unlock(&dev_priv->reservation_sem); + return ret; + +out_no_user_srf: + ttm_mem_global_free(vmw_mem_glob(dev_priv), user_accounting_size); + +out_unlock: + ttm_read_unlock(&dev_priv->reservation_sem); + return ret; +} -- cgit v1.3-6-gb490 From c8261a961ece4206bd60708eafa24ab81347f87c Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Fri, 26 Jun 2015 01:23:42 -0700 Subject: vmwgfx: Major KMS refactoring / cleanup in preparation of screen targets Signed-off-by: Sinclair Yeh Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 22 +- drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 562 +++++--------------------------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 80 +++-- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 45 ++- drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 6 +- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 424 ++++++++++++++++++++++-- 7 files changed, 597 insertions(+), 546 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index c300a0a1dd8a..b65eb02e483e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA + * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -330,6 +330,17 @@ struct vmw_ctx_binding_state { struct vmw_ctx_binding shaders[SVGA3D_SHADERTYPE_MAX]; }; + +/* + * enum vmw_display_unit_type - Describes the display unit + */ +enum vmw_display_unit_type { + vmw_du_invalid = 0, + vmw_du_legacy, + vmw_du_screen_object +}; + + struct vmw_sw_context{ struct drm_open_hash res_ht; bool res_ht_initialized; @@ -421,6 +432,7 @@ struct vmw_private { */ void *fb_info; + enum vmw_display_unit_type active_display_unit; struct vmw_legacy_display *ldu_priv; struct vmw_screen_object_display *sou_priv; struct vmw_overlay *overlay_priv; @@ -844,8 +856,8 @@ extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, extern irqreturn_t vmw_irq_handler(int irq, void *arg); extern int vmw_wait_seqno(struct vmw_private *dev_priv, bool lazy, - uint32_t seqno, bool interruptible, - unsigned long timeout); + uint32_t seqno, bool interruptible, + unsigned long timeout); extern void vmw_irq_preinstall(struct drm_device *dev); extern int vmw_irq_postinstall(struct drm_device *dev); extern void vmw_irq_uninstall(struct drm_device *dev); @@ -876,9 +888,9 @@ extern void vmw_generic_waiter_remove(struct vmw_private *dev_priv, extern void vmw_marker_queue_init(struct vmw_marker_queue *queue); extern void vmw_marker_queue_takedown(struct vmw_marker_queue *queue); extern int vmw_marker_push(struct vmw_marker_queue *queue, - uint32_t seqno); + uint32_t seqno); extern int vmw_marker_pull(struct vmw_marker_queue *queue, - uint32_t signaled_seqno); + uint32_t signaled_seqno); extern int vmw_wait_lag(struct vmw_private *dev_priv, struct vmw_marker_queue *queue, uint32_t us); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 189102d0ac8b..239815c8b073 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -71,8 +71,8 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) if (hwversion < SVGA3D_HWVERSION_WS8_B1) return false; - /* Non-Screen Object path does not support surfaces */ - if (!dev_priv->sou_priv) + /* Legacy Display Unit does not support surfaces */ + if (dev_priv->active_display_unit == vmw_du_legacy) return false; return true; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index b5632c25d94e..cac17c240ec0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA + * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -32,15 +32,12 @@ #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) -struct vmw_clip_rect { - int x1, x2, y1, y2; -}; /** * Clip @num_rects number of @rects against @clip storing the * results in @out_rects and the number of passed rects in @out_num. */ -static void vmw_clip_cliprects(struct drm_clip_rect *rects, +void vmw_clip_cliprects(struct drm_clip_rect *rects, int num_rects, struct vmw_clip_rect clip, SVGASignedRect *out_rects, @@ -69,7 +66,7 @@ static void vmw_clip_cliprects(struct drm_clip_rect *rects, *out_num = k; } -void vmw_display_unit_cleanup(struct vmw_display_unit *du) +void vmw_du_cleanup(struct vmw_display_unit *du) { if (du->cursor_surface) vmw_surface_unreference(&du->cursor_surface); @@ -367,15 +364,6 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, srf->snooper.age++; - /* we can't call this function from this function since execbuf has - * reserved fifo space. - * - * if (srf->snooper.crtc) - * vmw_ldu_crtc_cursor_update_image(dev_priv, - * srf->snooper.image, 64, 64, - * du->hotspot_x, du->hotspot_y); - */ - ttm_bo_kunmap(&map); err_unreserve: ttm_bo_unreserve(bo); @@ -412,17 +400,6 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv) * Surface framebuffer code */ -#define vmw_framebuffer_to_vfbs(x) \ - container_of(x, struct vmw_framebuffer_surface, base.base) - -struct vmw_framebuffer_surface { - struct vmw_framebuffer base; - struct vmw_surface *surface; - struct vmw_dma_buffer *buffer; - struct list_head head; - struct drm_master *master; -}; - static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) { struct vmw_framebuffer_surface *vfbs = @@ -442,153 +419,6 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) kfree(vfbs); } -static int do_surface_dirty_sou(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *framebuffer, - unsigned flags, unsigned color, - struct drm_clip_rect *clips, - unsigned num_clips, int inc, - struct vmw_fence_obj **out_fence) -{ - struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; - struct drm_clip_rect *clips_ptr; - struct drm_clip_rect *tmp; - struct drm_crtc *crtc; - size_t fifo_size; - int i, num_units; - int ret = 0; /* silence warning */ - int left, right, top, bottom; - - struct { - SVGA3dCmdHeader header; - SVGA3dCmdBlitSurfaceToScreen body; - } *cmd; - SVGASignedRect *blits; - - num_units = 0; - list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, - head) { - if (crtc->primary->fb != &framebuffer->base) - continue; - units[num_units++] = vmw_crtc_to_du(crtc); - } - - BUG_ON(!clips || !num_clips); - - tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); - if (unlikely(tmp == NULL)) { - DRM_ERROR("Temporary cliprect memory alloc failed.\n"); - return -ENOMEM; - } - - fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; - cmd = kzalloc(fifo_size, GFP_KERNEL); - if (unlikely(cmd == NULL)) { - DRM_ERROR("Temporary fifo memory alloc failed.\n"); - ret = -ENOMEM; - goto out_free_tmp; - } - - /* setup blits pointer */ - blits = (SVGASignedRect *)&cmd[1]; - - /* initial clip region */ - left = clips->x1; - right = clips->x2; - top = clips->y1; - bottom = clips->y2; - - /* skip the first clip rect */ - for (i = 1, clips_ptr = clips + inc; - i < num_clips; i++, clips_ptr += inc) { - left = min_t(int, left, (int)clips_ptr->x1); - right = max_t(int, right, (int)clips_ptr->x2); - top = min_t(int, top, (int)clips_ptr->y1); - bottom = max_t(int, bottom, (int)clips_ptr->y2); - } - - /* only need to do this once */ - cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); - cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); - - cmd->body.srcRect.left = left; - cmd->body.srcRect.right = right; - cmd->body.srcRect.top = top; - cmd->body.srcRect.bottom = bottom; - - clips_ptr = clips; - for (i = 0; i < num_clips; i++, clips_ptr += inc) { - tmp[i].x1 = clips_ptr->x1 - left; - tmp[i].x2 = clips_ptr->x2 - left; - tmp[i].y1 = clips_ptr->y1 - top; - tmp[i].y2 = clips_ptr->y2 - top; - } - - /* do per unit writing, reuse fifo for each */ - for (i = 0; i < num_units; i++) { - struct vmw_display_unit *unit = units[i]; - struct vmw_clip_rect clip; - int num; - - clip.x1 = left - unit->crtc.x; - clip.y1 = top - unit->crtc.y; - clip.x2 = right - unit->crtc.x; - clip.y2 = bottom - unit->crtc.y; - - /* skip any crtcs that misses the clip region */ - if (clip.x1 >= unit->crtc.mode.hdisplay || - clip.y1 >= unit->crtc.mode.vdisplay || - clip.x2 <= 0 || clip.y2 <= 0) - continue; - - /* - * In order for the clip rects to be correctly scaled - * the src and dest rects needs to be the same size. - */ - cmd->body.destRect.left = clip.x1; - cmd->body.destRect.right = clip.x2; - cmd->body.destRect.top = clip.y1; - cmd->body.destRect.bottom = clip.y2; - - /* create a clip rect of the crtc in dest coords */ - clip.x2 = unit->crtc.mode.hdisplay - clip.x1; - clip.y2 = unit->crtc.mode.vdisplay - clip.y1; - clip.x1 = 0 - clip.x1; - clip.y1 = 0 - clip.y1; - - /* need to reset sid as it is changed by execbuf */ - cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle); - cmd->body.destScreenId = unit->unit; - - /* clip and write blits to cmd stream */ - vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); - - /* if no cliprects hit skip this */ - if (num == 0) - continue; - - /* only return the last fence */ - if (out_fence && *out_fence) - vmw_fence_obj_unreference(out_fence); - - /* recalculate package length */ - fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; - cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, - fifo_size, 0, NULL, out_fence); - - if (unlikely(ret != 0)) - break; - } - - - kfree(cmd); -out_free_tmp: - kfree(tmp); - - return ret; -} - static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, struct drm_file *file_priv, unsigned flags, unsigned color, @@ -604,8 +434,8 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, if (unlikely(vfbs->master != file_priv->master)) return -EINVAL; - /* Require ScreenObject support for 3D */ - if (!dev_priv->sou_priv) + /* Legacy Display Unit does not support 3D */ + if (dev_priv->active_display_unit == vmw_du_legacy) return -EINVAL; drm_modeset_lock_all(dev_priv->dev); @@ -627,9 +457,12 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, inc = 2; /* skip source rects */ } - ret = do_surface_dirty_sou(dev_priv, file_priv, &vfbs->base, - flags, color, - clips, num_clips, inc, NULL); + if (dev_priv->active_display_unit == vmw_du_screen_object) + ret = vmw_kms_sou_do_surface_dirty(dev_priv, file_priv, + &vfbs->base, + flags, color, + clips, num_clips, + inc, NULL); vmw_fifo_flush(dev_priv, false); ttm_read_unlock(&dev_priv->reservation_sem); @@ -658,8 +491,8 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, struct vmw_master *vmaster = vmw_master(file_priv->master); int ret; - /* 3D is only supported on HWv8 hosts which supports screen objects */ - if (!dev_priv->sou_priv) + /* 3D is only supported on HWv8 and newer hosts */ + if (dev_priv->active_display_unit == vmw_du_legacy) return -ENOSYS; /* @@ -693,9 +526,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, case 15: format = SVGA3D_A1R5G5B5; break; - case 8: - format = SVGA3D_LUMINANCE8; - break; default: DRM_ERROR("Invalid color depth: %d\n", mode_cmd->depth); return -EINVAL; @@ -753,14 +583,6 @@ out_err1: * Dmabuf framebuffer code */ -#define vmw_framebuffer_to_vfbd(x) \ - container_of(x, struct vmw_framebuffer_dmabuf, base.base) - -struct vmw_framebuffer_dmabuf { - struct vmw_framebuffer base; - struct vmw_dma_buffer *buffer; -}; - static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) { struct vmw_framebuffer_dmabuf *vfbd = @@ -773,180 +595,6 @@ static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) kfree(vfbd); } -static int do_dmabuf_dirty_ldu(struct vmw_private *dev_priv, - struct vmw_framebuffer *framebuffer, - unsigned flags, unsigned color, - struct drm_clip_rect *clips, - unsigned num_clips, int increment) -{ - size_t fifo_size; - int i; - - struct { - uint32_t header; - SVGAFifoCmdUpdate body; - } *cmd; - - fifo_size = sizeof(*cmd) * num_clips; - cmd = vmw_fifo_reserve(dev_priv, fifo_size); - if (unlikely(cmd == NULL)) { - DRM_ERROR("Fifo reserve failed.\n"); - return -ENOMEM; - } - - memset(cmd, 0, fifo_size); - for (i = 0; i < num_clips; i++, clips += increment) { - cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE); - cmd[i].body.x = cpu_to_le32(clips->x1); - cmd[i].body.y = cpu_to_le32(clips->y1); - cmd[i].body.width = cpu_to_le32(clips->x2 - clips->x1); - cmd[i].body.height = cpu_to_le32(clips->y2 - clips->y1); - } - - vmw_fifo_commit(dev_priv, fifo_size); - return 0; -} - -static int do_dmabuf_define_gmrfb(struct drm_file *file_priv, - struct vmw_private *dev_priv, - struct vmw_framebuffer *framebuffer) -{ - int depth = framebuffer->base.depth; - size_t fifo_size; - int ret; - - struct { - uint32_t header; - SVGAFifoCmdDefineGMRFB body; - } *cmd; - - /* Emulate RGBA support, contrary to svga_reg.h this is not - * supported by hosts. This is only a problem if we are reading - * this value later and expecting what we uploaded back. - */ - if (depth == 32) - depth = 24; - - fifo_size = sizeof(*cmd); - cmd = kmalloc(fifo_size, GFP_KERNEL); - if (unlikely(cmd == NULL)) { - DRM_ERROR("Failed to allocate temporary cmd buffer.\n"); - return -ENOMEM; - } - - memset(cmd, 0, fifo_size); - cmd->header = SVGA_CMD_DEFINE_GMRFB; - cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel; - cmd->body.format.colorDepth = depth; - cmd->body.format.reserved = 0; - cmd->body.bytesPerLine = framebuffer->base.pitches[0]; - cmd->body.ptr.gmrId = framebuffer->user_handle; - cmd->body.ptr.offset = 0; - - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, - fifo_size, 0, NULL, NULL); - - kfree(cmd); - - return ret; -} - -static int do_dmabuf_dirty_sou(struct drm_file *file_priv, - struct vmw_private *dev_priv, - struct vmw_framebuffer *framebuffer, - unsigned flags, unsigned color, - struct drm_clip_rect *clips, - unsigned num_clips, int increment, - struct vmw_fence_obj **out_fence) -{ - struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; - struct drm_clip_rect *clips_ptr; - int i, k, num_units, ret; - struct drm_crtc *crtc; - size_t fifo_size; - - struct { - uint32_t header; - SVGAFifoCmdBlitGMRFBToScreen body; - } *blits; - - ret = do_dmabuf_define_gmrfb(file_priv, dev_priv, framebuffer); - if (unlikely(ret != 0)) - return ret; /* define_gmrfb prints warnings */ - - fifo_size = sizeof(*blits) * num_clips; - blits = kmalloc(fifo_size, GFP_KERNEL); - if (unlikely(blits == NULL)) { - DRM_ERROR("Failed to allocate temporary cmd buffer.\n"); - return -ENOMEM; - } - - num_units = 0; - list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->primary->fb != &framebuffer->base) - continue; - units[num_units++] = vmw_crtc_to_du(crtc); - } - - for (k = 0; k < num_units; k++) { - struct vmw_display_unit *unit = units[k]; - int hit_num = 0; - - clips_ptr = clips; - for (i = 0; i < num_clips; i++, clips_ptr += increment) { - int clip_x1 = clips_ptr->x1 - unit->crtc.x; - int clip_y1 = clips_ptr->y1 - unit->crtc.y; - int clip_x2 = clips_ptr->x2 - unit->crtc.x; - int clip_y2 = clips_ptr->y2 - unit->crtc.y; - int move_x, move_y; - - /* skip any crtcs that misses the clip region */ - if (clip_x1 >= unit->crtc.mode.hdisplay || - clip_y1 >= unit->crtc.mode.vdisplay || - clip_x2 <= 0 || clip_y2 <= 0) - continue; - - /* clip size to crtc size */ - clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay); - clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay); - - /* translate both src and dest to bring clip into screen */ - move_x = min_t(int, clip_x1, 0); - move_y = min_t(int, clip_y1, 0); - - /* actual translate done here */ - blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; - blits[hit_num].body.destScreenId = unit->unit; - blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x; - blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y; - blits[hit_num].body.destRect.left = clip_x1 - move_x; - blits[hit_num].body.destRect.top = clip_y1 - move_y; - blits[hit_num].body.destRect.right = clip_x2; - blits[hit_num].body.destRect.bottom = clip_y2; - hit_num++; - } - - /* no clips hit the crtc */ - if (hit_num == 0) - continue; - - /* only return the last fence */ - if (out_fence && *out_fence) - vmw_fence_obj_unreference(out_fence); - - fifo_size = sizeof(*blits) * hit_num; - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, blits, - fifo_size, 0, NULL, out_fence); - - if (unlikely(ret != 0)) - break; - } - - kfree(blits); - - return ret; -} - static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, struct drm_file *file_priv, unsigned flags, unsigned color, @@ -979,13 +627,15 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, } if (dev_priv->ldu_priv) { - ret = do_dmabuf_dirty_ldu(dev_priv, &vfbd->base, - flags, color, - clips, num_clips, increment); - } else { - ret = do_dmabuf_dirty_sou(file_priv, dev_priv, &vfbd->base, - flags, color, - clips, num_clips, increment, NULL); + ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, + flags, color, + clips, num_clips, increment); + } else if (dev_priv->active_display_unit == vmw_du_screen_object) { + ret = vmw_kms_sou_do_dmabuf_dirty(file_priv, dev_priv, + &vfbd->base, + flags, color, + clips, num_clips, increment, + NULL); } vmw_fifo_flush(dev_priv, false); @@ -1011,8 +661,8 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) vmw_framebuffer_to_vfbd(&vfb->base); int ret; - /* This code should not be used with screen objects */ - BUG_ON(dev_priv->sou_priv); + /* This code should only be used with Legacy Display Unit */ + BUG_ON(dev_priv->active_display_unit != vmw_du_legacy); vmw_overlay_pause_all(dev_priv); @@ -1059,7 +709,7 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, } /* Limited framebuffer color depth support for screen objects */ - if (dev_priv->sou_priv) { + if (dev_priv->active_display_unit == vmw_du_screen_object) { switch (mode_cmd->depth) { case 32: case 24: @@ -1102,7 +752,7 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, vfbd->base.base.depth = mode_cmd->depth; vfbd->base.base.width = mode_cmd->width; vfbd->base.base.height = mode_cmd->height; - if (!dev_priv->sou_priv) { + if (dev_priv->active_display_unit == vmw_du_legacy) { vfbd->base.pin = vmw_framebuffer_dmabuf_pin; vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin; } @@ -1159,7 +809,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, if (!vmw_kms_validate_mode_vram(dev_priv, mode_cmd.pitch, mode_cmd.height)) { - DRM_ERROR("VRAM size is too small for requested mode.\n"); + DRM_ERROR("Requested mode exceed bounding box limit.\n"); return ERR_PTR(-ENOMEM); } @@ -1220,7 +870,7 @@ static const struct drm_mode_config_funcs vmw_kms_funcs = { .fb_create = vmw_kms_fb_create, }; -int vmw_kms_present(struct vmw_private *dev_priv, +int vmw_kms_generic_present(struct vmw_private *dev_priv, struct drm_file *file_priv, struct vmw_framebuffer *vfb, struct vmw_surface *surface, @@ -1358,6 +1008,19 @@ out_free_tmp: return ret; } +int vmw_kms_present(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct vmw_surface *surface, + uint32_t sid, + int32_t destX, int32_t destY, + struct drm_vmw_rect *clips, + uint32_t num_clips) +{ + return vmw_kms_generic_present(dev_priv, file_priv, vfb, surface, sid, + destX, destY, clips, num_clips); +} + int vmw_kms_readback(struct vmw_private *dev_priv, struct drm_file *file_priv, struct vmw_framebuffer *vfb, @@ -1478,26 +1141,29 @@ int vmw_kms_init(struct vmw_private *dev_priv) dev->mode_config.max_width = 8192; dev->mode_config.max_height = 8192; - ret = vmw_kms_init_screen_object_display(dev_priv); + ret = vmw_kms_sou_init_display(dev_priv); if (ret) /* Fallback */ - (void)vmw_kms_init_legacy_display_system(dev_priv); + ret = vmw_kms_ldu_init_display(dev_priv); - return 0; + return ret; } int vmw_kms_close(struct vmw_private *dev_priv) { + int ret; + /* * Docs says we should take the lock before calling this function * but since it destroys encoders and our destructor calls * drm_encoder_cleanup which takes the lock we deadlock. */ drm_mode_config_cleanup(dev_priv->dev); - if (dev_priv->sou_priv) - vmw_kms_close_screen_object_display(dev_priv); + if (dev_priv->active_display_unit == vmw_du_screen_object) + ret = vmw_kms_sou_close_display(dev_priv); else - vmw_kms_close_legacy_display_system(dev_priv); - return 0; + ret = vmw_kms_ldu_close_display(dev_priv); + + return ret; } int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data, @@ -1573,7 +1239,7 @@ int vmw_kms_save_vga(struct vmw_private *vmw_priv) vmw_read(vmw_priv, SVGA_REG_PITCHLOCK); else if (vmw_fifo_have_pitchlock(vmw_priv)) vmw_priv->vga_pitchlock = ioread32(vmw_priv->mmio_virt + - SVGA_FIFO_PITCHLOCK); + SVGA_FIFO_PITCHLOCK); if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) return 0; @@ -1719,75 +1385,6 @@ static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, return 0; } -int vmw_du_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t page_flip_flags) -{ - struct vmw_private *dev_priv = vmw_priv(crtc->dev); - struct drm_framebuffer *old_fb = crtc->primary->fb; - struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb); - struct drm_file *file_priv ; - struct vmw_fence_obj *fence = NULL; - struct drm_clip_rect clips; - int ret; - - if (event == NULL) - return -EINVAL; - - /* require ScreenObject support for page flipping */ - if (!dev_priv->sou_priv) - return -ENOSYS; - - file_priv = event->base.file_priv; - if (!vmw_kms_screen_object_flippable(dev_priv, crtc)) - return -EINVAL; - - crtc->primary->fb = fb; - - /* do a full screen dirty update */ - clips.x1 = clips.y1 = 0; - clips.x2 = fb->width; - clips.y2 = fb->height; - - if (vfb->dmabuf) - ret = do_dmabuf_dirty_sou(file_priv, dev_priv, vfb, - 0, 0, &clips, 1, 1, &fence); - else - ret = do_surface_dirty_sou(dev_priv, file_priv, vfb, - 0, 0, &clips, 1, 1, &fence); - - - if (ret != 0) - goto out_no_fence; - if (!fence) { - ret = -EINVAL; - goto out_no_fence; - } - - ret = vmw_event_fence_action_queue(file_priv, fence, - &event->base, - &event->event.tv_sec, - &event->event.tv_usec, - true); - - /* - * No need to hold on to this now. The only cleanup - * we need to do if we fail is unref the fence. - */ - vmw_fence_obj_unreference(&fence); - - if (vmw_crtc_to_du(crtc)->is_implicit) - vmw_kms_screen_object_update_implicit_fb(dev_priv, crtc); - - return ret; - -out_no_fence: - crtc->primary->fb = old_fb; - return ret; -} - - void vmw_du_crtc_save(struct drm_crtc *crtc) { } @@ -1958,36 +1555,34 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, * If using screen objects, then assume 32-bpp because that's what the * SVGA device is assuming */ - if (dev_priv->sou_priv) + if (dev_priv->active_display_unit == vmw_du_screen_object) assumed_bpp = 4; /* Add preferred mode */ - { - mode = drm_mode_duplicate(dev, &prefmode); - if (!mode) - return 0; - mode->hdisplay = du->pref_width; - mode->vdisplay = du->pref_height; - vmw_guess_mode_timing(mode); - - if (vmw_kms_validate_mode_vram(dev_priv, - mode->hdisplay * assumed_bpp, - mode->vdisplay)) { - drm_mode_probed_add(connector, mode); - } else { - drm_mode_destroy(dev, mode); - mode = NULL; - } + mode = drm_mode_duplicate(dev, &prefmode); + if (!mode) + return 0; + mode->hdisplay = du->pref_width; + mode->vdisplay = du->pref_height; + vmw_guess_mode_timing(mode); - if (du->pref_mode) { - list_del_init(&du->pref_mode->head); - drm_mode_destroy(dev, du->pref_mode); - } + if (vmw_kms_validate_mode_vram(dev_priv, + mode->hdisplay * assumed_bpp, + mode->vdisplay)) { + drm_mode_probed_add(connector, mode); + } else { + drm_mode_destroy(dev, mode); + mode = NULL; + } - /* mode might be null here, this is intended */ - du->pref_mode = mode; + if (du->pref_mode) { + list_del_init(&du->pref_mode->head); + drm_mode_destroy(dev, du->pref_mode); } + /* mode might be null here, this is intended */ + du->pref_mode = mode; + for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) { bmode = &vmw_kms_connector_builtin[i]; if (bmode->hdisplay > max_width || @@ -2036,6 +1631,7 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, int ret; int i; struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_vmw_rect bounding_box = {0}; if (!arg->num_outputs) { struct drm_vmw_rect def_rect = {0, 0, 800, 600}; @@ -2066,6 +1662,16 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, ret = -EINVAL; goto out_free; } + + /* + * bounding_box.w and bunding_box.h are used as + * lower-right coordinates + */ + if (rects[i].x + rects[i].w > bounding_box.w) + bounding_box.w = rects[i].x + rects[i].w; + + if (rects[i].y + rects[i].h > bounding_box.h) + bounding_box.h = rects[i].y + rects[i].h; } vmw_du_update_layout(dev_priv, arg->num_outputs, rects); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 8d038c36bd57..0f2c29166f7c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA + * Copyright © 2009-2014 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -32,11 +32,17 @@ #include #include "vmwgfx_drv.h" + + #define VMWGFX_NUM_DISPLAY_UNITS 8 #define vmw_framebuffer_to_vfb(x) \ container_of(x, struct vmw_framebuffer, base) +#define vmw_framebuffer_to_vfbs(x) \ + container_of(x, struct vmw_framebuffer_surface, base.base) +#define vmw_framebuffer_to_vfbd(x) \ + container_of(x, struct vmw_framebuffer_dmabuf, base.base) /** * Base class for framebuffers @@ -53,9 +59,36 @@ struct vmw_framebuffer { uint32_t user_handle; }; +/* + * Clip rectangle + */ +struct vmw_clip_rect { + int x1, x2, y1, y2; +}; + +struct vmw_framebuffer_surface { + struct vmw_framebuffer base; + struct vmw_surface *surface; + struct vmw_dma_buffer *buffer; + struct list_head head; + struct drm_master *master; +}; -#define vmw_crtc_to_du(x) \ - container_of(x, struct vmw_display_unit, crtc) + +struct vmw_framebuffer_dmabuf { + struct vmw_framebuffer base; + struct vmw_dma_buffer *buffer; +}; + + +/* + * Basic clip rect manipulation + */ +void vmw_clip_cliprects(struct drm_clip_rect *rects, + int num_rects, + struct vmw_clip_rect clip, + SVGASignedRect *out_rects, + int *out_num); /* * Basic cursor manipulation @@ -120,11 +153,7 @@ struct vmw_display_unit { /* * Shared display unit functions - vmwgfx_kms.c */ -void vmw_display_unit_cleanup(struct vmw_display_unit *du); -int vmw_du_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t page_flip_flags); +void vmw_du_cleanup(struct vmw_display_unit *du); void vmw_du_crtc_save(struct drm_crtc *crtc); void vmw_du_crtc_restore(struct drm_crtc *crtc); void vmw_du_crtc_gamma_set(struct drm_crtc *crtc, @@ -148,20 +177,31 @@ int vmw_du_connector_set_property(struct drm_connector *connector, /* * Legacy display unit functions - vmwgfx_ldu.c */ -int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv); -int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv); +int vmw_kms_ldu_init_display(struct vmw_private *dev_priv); +int vmw_kms_ldu_close_display(struct vmw_private *dev_priv); +int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + unsigned flags, unsigned color, + struct drm_clip_rect *clips, + unsigned num_clips, int increment); /* * Screen Objects display functions - vmwgfx_scrn.c */ -int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv); -int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv); -int vmw_kms_sou_update_layout(struct vmw_private *dev_priv, unsigned num, - struct drm_vmw_rect *rects); -bool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv, - struct drm_crtc *crtc); -void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv, - struct drm_crtc *crtc); - - +int vmw_kms_sou_init_display(struct vmw_private *dev_priv); +int vmw_kms_sou_close_display(struct vmw_private *dev_priv); +int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *framebuffer, + unsigned flags, unsigned color, + struct drm_clip_rect *clips, + unsigned num_clips, int inc, + struct vmw_fence_obj **out_fence); +int vmw_kms_sou_do_dmabuf_dirty(struct drm_file *file_priv, + struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + unsigned flags, unsigned color, + struct drm_clip_rect *clips, + unsigned num_clips, int increment, + struct vmw_fence_obj **out_fence); #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 53579f278b63..f0fd565c4e19 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -57,7 +57,7 @@ struct vmw_legacy_display_unit { static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu) { list_del_init(&ldu->active); - vmw_display_unit_cleanup(&ldu->base); + vmw_du_cleanup(&ldu->base); kfree(ldu); } @@ -386,7 +386,7 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) return 0; } -int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv) +int vmw_kms_ldu_init_display(struct vmw_private *dev_priv) { struct drm_device *dev = dev_priv->dev; int i, ret; @@ -423,6 +423,10 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv) else vmw_ldu_init(dev_priv, 0); + dev_priv->active_display_unit = vmw_du_legacy; + + DRM_INFO("Legacy Display Unit initialized\n"); + return 0; err_vblank_cleanup: @@ -433,7 +437,7 @@ err_free: return ret; } -int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv) +int vmw_kms_ldu_close_display(struct vmw_private *dev_priv) { struct drm_device *dev = dev_priv->dev; @@ -448,3 +452,38 @@ int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv) return 0; } + + +int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + unsigned flags, unsigned color, + struct drm_clip_rect *clips, + unsigned num_clips, int increment) +{ + size_t fifo_size; + int i; + + struct { + uint32_t header; + SVGAFifoCmdUpdate body; + } *cmd; + + fifo_size = sizeof(*cmd) * num_clips; + cmd = vmw_fifo_reserve(dev_priv, fifo_size); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Fifo reserve failed.\n"); + return -ENOMEM; + } + + memset(cmd, 0, fifo_size); + for (i = 0; i < num_clips; i++, clips += increment) { + cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE); + cmd[i].body.x = cpu_to_le32(clips->x1); + cmd[i].body.y = cpu_to_le32(clips->y1); + cmd[i].body.width = cpu_to_le32(clips->x2 - clips->x1); + cmd[i].body.height = cpu_to_le32(clips->y2 - clips->y1); + } + + vmw_fifo_commit(dev_priv, fifo_size); + return 0; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index 87e39f68e9d0..7f4b2f072c6f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -100,7 +100,7 @@ static int vmw_overlay_send_put(struct vmw_private *dev_priv, { struct vmw_escape_video_flush *flush; size_t fifo_size; - bool have_so = dev_priv->sou_priv ? true : false; + bool have_so = (dev_priv->active_display_unit == vmw_du_screen_object); int i, num_items; SVGAGuestPtr ptr; @@ -231,7 +231,7 @@ static int vmw_overlay_move_buffer(struct vmw_private *dev_priv, if (!pin) return vmw_dmabuf_unpin(dev_priv, buf, inter); - if (!dev_priv->sou_priv) + if (dev_priv->active_display_unit == vmw_du_legacy) return vmw_dmabuf_to_vram(dev_priv, buf, true, inter); return vmw_dmabuf_to_vram_or_gmr(dev_priv, buf, true, inter); @@ -453,7 +453,7 @@ int vmw_overlay_pause_all(struct vmw_private *dev_priv) static bool vmw_overlay_available(const struct vmw_private *dev_priv) { - return (dev_priv->overlay_priv != NULL && + return (dev_priv->overlay_priv != NULL && ((dev_priv->fifo.capabilities & VMW_OVERLAY_CAP_MASK) == VMW_OVERLAY_CAP_MASK)); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 9e8eb364a6ac..807fc87c0c96 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright © 2011 VMware, Inc., Palo Alto, CA., USA + * Copyright © 2011-2014 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -57,7 +57,7 @@ struct vmw_screen_object_unit { static void vmw_sou_destroy(struct vmw_screen_object_unit *sou) { - vmw_display_unit_cleanup(&sou->base); + vmw_du_cleanup(&sou->base); kfree(sou); } @@ -72,7 +72,7 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc) } static void vmw_sou_del_active(struct vmw_private *vmw_priv, - struct vmw_screen_object_unit *sou) + struct vmw_screen_object_unit *sou) { struct vmw_screen_object_display *ld = vmw_priv->sou_priv; @@ -84,8 +84,8 @@ static void vmw_sou_del_active(struct vmw_private *vmw_priv, } static void vmw_sou_add_active(struct vmw_private *vmw_priv, - struct vmw_screen_object_unit *sou, - struct vmw_framebuffer *vfb) + struct vmw_screen_object_unit *sou, + struct vmw_framebuffer *vfb) { struct vmw_screen_object_display *ld = vmw_priv->sou_priv; @@ -274,13 +274,13 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) dev_priv = vmw_priv(crtc->dev); if (set->num_connectors > 1) { - DRM_ERROR("to many connectors\n"); + DRM_ERROR("Too many connectors\n"); return -EINVAL; } if (set->num_connectors == 1 && set->connectors[0] != &sou->base.connector) { - DRM_ERROR("connector doesn't match %p %p\n", + DRM_ERROR("Connector doesn't match %p %p\n", set->connectors[0], &sou->base.connector); return -EINVAL; } @@ -391,6 +391,250 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) return 0; } +/** + * Returns if this unit can be page flipped. + * Must be called with the mode_config mutex held. + */ +static bool vmw_sou_screen_object_flippable(struct vmw_private *dev_priv, + struct drm_crtc *crtc) +{ + struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); + + if (!sou->base.is_implicit) + return true; + + if (dev_priv->sou_priv->num_implicit != 1) + return false; + + return true; +} + +/** + * Update the implicit fb to the current fb of this crtc. + * Must be called with the mode_config mutex held. + */ +void vmw_sou_update_implicit_fb(struct vmw_private *dev_priv, + struct drm_crtc *crtc) +{ + struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); + + BUG_ON(!sou->base.is_implicit); + + dev_priv->sou_priv->implicit_fb = + vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb); +} + +static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event, + uint32_t flags) +{ + struct vmw_private *dev_priv = vmw_priv(crtc->dev); + struct drm_framebuffer *old_fb = crtc->primary->fb; + struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb); + struct drm_file *file_priv = event->base.file_priv; + struct vmw_fence_obj *fence = NULL; + struct drm_clip_rect clips; + int ret; + + /* require ScreenObject support for page flipping */ + if (!dev_priv->sou_priv) + return -ENOSYS; + + if (!vmw_sou_screen_object_flippable(dev_priv, crtc)) + return -EINVAL; + + crtc->primary->fb = fb; + + /* do a full screen dirty update */ + clips.x1 = clips.y1 = 0; + clips.x2 = fb->width; + clips.y2 = fb->height; + + if (vfb->dmabuf) + ret = vmw_kms_sou_do_dmabuf_dirty(file_priv, dev_priv, vfb, + 0, 0, &clips, 1, 1, &fence); + else + ret = vmw_kms_sou_do_surface_dirty(dev_priv, file_priv, vfb, + 0, 0, &clips, 1, 1, &fence); + + + if (ret != 0) + goto out_no_fence; + if (!fence) { + ret = -EINVAL; + goto out_no_fence; + } + + ret = vmw_event_fence_action_queue(file_priv, fence, + &event->base, + &event->event.tv_sec, + &event->event.tv_usec, + true); + + /* + * No need to hold on to this now. The only cleanup + * we need to do if we fail is unref the fence. + */ + vmw_fence_obj_unreference(&fence); + + if (vmw_crtc_to_du(crtc)->is_implicit) + vmw_sou_update_implicit_fb(dev_priv, crtc); + + return ret; + +out_no_fence: + crtc->primary->fb = old_fb; + return ret; +} + +int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *framebuffer, + unsigned flags, unsigned color, + struct drm_clip_rect *clips, + unsigned num_clips, int inc, + struct vmw_fence_obj **out_fence) +{ + struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; + struct drm_clip_rect *clips_ptr; + struct drm_clip_rect *tmp; + struct drm_crtc *crtc; + size_t fifo_size; + int i, num_units; + int ret = 0; /* silence warning */ + int left, right, top, bottom; + + struct { + SVGA3dCmdHeader header; + SVGA3dCmdBlitSurfaceToScreen body; + } *cmd; + SVGASignedRect *blits; + + num_units = 0; + list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, + head) { + if (crtc->primary->fb != &framebuffer->base) + continue; + units[num_units++] = vmw_crtc_to_du(crtc); + } + + BUG_ON(!clips || !num_clips); + + tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); + if (unlikely(tmp == NULL)) { + DRM_ERROR("Temporary cliprect memory alloc failed.\n"); + return -ENOMEM; + } + + fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; + cmd = kzalloc(fifo_size, GFP_KERNEL); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Temporary fifo memory alloc failed.\n"); + ret = -ENOMEM; + goto out_free_tmp; + } + + /* setup blits pointer */ + blits = (SVGASignedRect *)&cmd[1]; + + /* initial clip region */ + left = clips->x1; + right = clips->x2; + top = clips->y1; + bottom = clips->y2; + + /* skip the first clip rect */ + for (i = 1, clips_ptr = clips + inc; + i < num_clips; i++, clips_ptr += inc) { + left = min_t(int, left, (int)clips_ptr->x1); + right = max_t(int, right, (int)clips_ptr->x2); + top = min_t(int, top, (int)clips_ptr->y1); + bottom = max_t(int, bottom, (int)clips_ptr->y2); + } + + /* only need to do this once */ + cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); + cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); + + cmd->body.srcRect.left = left; + cmd->body.srcRect.right = right; + cmd->body.srcRect.top = top; + cmd->body.srcRect.bottom = bottom; + + clips_ptr = clips; + for (i = 0; i < num_clips; i++, clips_ptr += inc) { + tmp[i].x1 = clips_ptr->x1 - left; + tmp[i].x2 = clips_ptr->x2 - left; + tmp[i].y1 = clips_ptr->y1 - top; + tmp[i].y2 = clips_ptr->y2 - top; + } + + /* do per unit writing, reuse fifo for each */ + for (i = 0; i < num_units; i++) { + struct vmw_display_unit *unit = units[i]; + struct vmw_clip_rect clip; + int num; + + clip.x1 = left - unit->crtc.x; + clip.y1 = top - unit->crtc.y; + clip.x2 = right - unit->crtc.x; + clip.y2 = bottom - unit->crtc.y; + + /* skip any crtcs that misses the clip region */ + if (clip.x1 >= unit->crtc.mode.hdisplay || + clip.y1 >= unit->crtc.mode.vdisplay || + clip.x2 <= 0 || clip.y2 <= 0) + continue; + + /* + * In order for the clip rects to be correctly scaled + * the src and dest rects needs to be the same size. + */ + cmd->body.destRect.left = clip.x1; + cmd->body.destRect.right = clip.x2; + cmd->body.destRect.top = clip.y1; + cmd->body.destRect.bottom = clip.y2; + + /* create a clip rect of the crtc in dest coords */ + clip.x2 = unit->crtc.mode.hdisplay - clip.x1; + clip.y2 = unit->crtc.mode.vdisplay - clip.y1; + clip.x1 = 0 - clip.x1; + clip.y1 = 0 - clip.y1; + + /* need to reset sid as it is changed by execbuf */ + cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle); + cmd->body.destScreenId = unit->unit; + + /* clip and write blits to cmd stream */ + vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); + + /* if no cliprects hit skip this */ + if (num == 0) + continue; + + /* only return the last fence */ + if (out_fence && *out_fence) + vmw_fence_obj_unreference(out_fence); + + /* recalculate package length */ + fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; + cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); + ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, + fifo_size, 0, NULL, out_fence); + + if (unlikely(ret != 0)) + break; + } + + + kfree(cmd); +out_free_tmp: + kfree(tmp); + + return ret; +} + static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { .save = vmw_du_crtc_save, .restore = vmw_du_crtc_restore, @@ -399,7 +643,7 @@ static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { .gamma_set = vmw_du_crtc_gamma_set, .destroy = vmw_sou_crtc_destroy, .set_config = vmw_sou_crtc_set_config, - .page_flip = vmw_du_page_flip, + .page_flip = vmw_sou_crtc_page_flip, }; /* @@ -424,7 +668,7 @@ static void vmw_sou_connector_destroy(struct drm_connector *connector) vmw_sou_destroy(vmw_connector_to_sou(connector)); } -static struct drm_connector_funcs vmw_legacy_connector_funcs = { +static struct drm_connector_funcs vmw_sou_connector_funcs = { .dpms = vmw_du_connector_dpms, .save = vmw_du_connector_save, .restore = vmw_du_connector_restore, @@ -459,7 +703,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) sou->base.pref_mode = NULL; sou->base.is_implicit = true; - drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, + drm_connector_init(dev, connector, &vmw_sou_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); connector->status = vmw_du_connector_detect(connector, true); @@ -482,7 +726,7 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) return 0; } -int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) +int vmw_kms_sou_init_display(struct vmw_private *dev_priv) { struct drm_device *dev = dev_priv->dev; int i, ret; @@ -517,7 +761,9 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) vmw_sou_init(dev_priv, i); - DRM_INFO("Screen objects system initialized\n"); + dev_priv->active_display_unit = vmw_du_screen_object; + + DRM_INFO("Screen Objects Display Unit initialized\n"); return 0; @@ -530,7 +776,7 @@ err_no_mem: return ret; } -int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv) +int vmw_kms_sou_close_display(struct vmw_private *dev_priv) { struct drm_device *dev = dev_priv->dev; @@ -544,35 +790,143 @@ int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv) return 0; } -/** - * Returns if this unit can be page flipped. - * Must be called with the mode_config mutex held. - */ -bool vmw_kms_screen_object_flippable(struct vmw_private *dev_priv, - struct drm_crtc *crtc) +static int do_dmabuf_define_gmrfb(struct drm_file *file_priv, + struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer) { - struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); + int depth = framebuffer->base.depth; + size_t fifo_size; + int ret; - if (!sou->base.is_implicit) - return true; + struct { + uint32_t header; + SVGAFifoCmdDefineGMRFB body; + } *cmd; - if (dev_priv->sou_priv->num_implicit != 1) - return false; + /* Emulate RGBA support, contrary to svga_reg.h this is not + * supported by hosts. This is only a problem if we are reading + * this value later and expecting what we uploaded back. + */ + if (depth == 32) + depth = 24; - return true; + fifo_size = sizeof(*cmd); + cmd = kmalloc(fifo_size, GFP_KERNEL); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed to allocate temporary cmd buffer.\n"); + return -ENOMEM; + } + + memset(cmd, 0, fifo_size); + cmd->header = SVGA_CMD_DEFINE_GMRFB; + cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel; + cmd->body.format.colorDepth = depth; + cmd->body.format.reserved = 0; + cmd->body.bytesPerLine = framebuffer->base.pitches[0]; + cmd->body.ptr.gmrId = framebuffer->user_handle; + cmd->body.ptr.offset = 0; + + ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, + fifo_size, 0, NULL, NULL); + + kfree(cmd); + + return ret; } -/** - * Update the implicit fb to the current fb of this crtc. - * Must be called with the mode_config mutex held. - */ -void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv, - struct drm_crtc *crtc) +int vmw_kms_sou_do_dmabuf_dirty(struct drm_file *file_priv, + struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + unsigned flags, unsigned color, + struct drm_clip_rect *clips, + unsigned num_clips, int increment, + struct vmw_fence_obj **out_fence) { - struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); + struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; + struct drm_clip_rect *clips_ptr; + int i, k, num_units, ret; + struct drm_crtc *crtc; + size_t fifo_size; - BUG_ON(!sou->base.is_implicit); + struct { + uint32_t header; + SVGAFifoCmdBlitGMRFBToScreen body; + } *blits; - dev_priv->sou_priv->implicit_fb = - vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb); + ret = do_dmabuf_define_gmrfb(file_priv, dev_priv, framebuffer); + if (unlikely(ret != 0)) + return ret; /* define_gmrfb prints warnings */ + + fifo_size = sizeof(*blits) * num_clips; + blits = kmalloc(fifo_size, GFP_KERNEL); + if (unlikely(blits == NULL)) { + DRM_ERROR("Failed to allocate temporary cmd buffer.\n"); + return -ENOMEM; + } + + num_units = 0; + list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { + if (crtc->primary->fb != &framebuffer->base) + continue; + units[num_units++] = vmw_crtc_to_du(crtc); + } + + for (k = 0; k < num_units; k++) { + struct vmw_display_unit *unit = units[k]; + int hit_num = 0; + + clips_ptr = clips; + for (i = 0; i < num_clips; i++, clips_ptr += increment) { + int clip_x1 = clips_ptr->x1 - unit->crtc.x; + int clip_y1 = clips_ptr->y1 - unit->crtc.y; + int clip_x2 = clips_ptr->x2 - unit->crtc.x; + int clip_y2 = clips_ptr->y2 - unit->crtc.y; + int move_x, move_y; + + /* skip any crtcs that misses the clip region */ + if (clip_x1 >= unit->crtc.mode.hdisplay || + clip_y1 >= unit->crtc.mode.vdisplay || + clip_x2 <= 0 || clip_y2 <= 0) + continue; + + /* clip size to crtc size */ + clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay); + clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay); + + /* translate both src and dest to bring clip into screen */ + move_x = min_t(int, clip_x1, 0); + move_y = min_t(int, clip_y1, 0); + + /* actual translate done here */ + blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; + blits[hit_num].body.destScreenId = unit->unit; + blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x; + blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y; + blits[hit_num].body.destRect.left = clip_x1 - move_x; + blits[hit_num].body.destRect.top = clip_y1 - move_y; + blits[hit_num].body.destRect.right = clip_x2; + blits[hit_num].body.destRect.bottom = clip_y2; + hit_num++; + } + + /* no clips hit the crtc */ + if (hit_num == 0) + continue; + + /* only return the last fence */ + if (out_fence && *out_fence) + vmw_fence_obj_unreference(out_fence); + + fifo_size = sizeof(*blits) * hit_num; + ret = vmw_execbuf_process(file_priv, dev_priv, NULL, blits, + fifo_size, 0, NULL, out_fence); + + if (unlikely(ret != 0)) + break; + } + + kfree(blits); + + return ret; } + -- cgit v1.3-6-gb490 From c9146cd918852ba6ec1af3bb376ac88edc15e3d9 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Mar 2015 23:45:04 -0800 Subject: drm/vmwgfx: Add "quirk" to handling command verification exceptions For certain surface copies, we don't have a user space handle for the destination surface. In such cases, we are going to trust that our caller is giving us the right surface ID. To do this case, we created a quirk flag that may be useful in the future for handling other cases. Signed-off-by: Thomas Hellstrom Signed-off-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 4 ++++ drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 10 ++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 6 +++--- 4 files changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index b65eb02e483e..c3f8fc97b336 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -341,6 +341,8 @@ enum vmw_display_unit_type { }; +#define VMW_QUIRK_SCREENTARGET (1U << 0) + struct vmw_sw_context{ struct drm_open_hash res_ht; bool res_ht_initialized; @@ -363,6 +365,7 @@ struct vmw_sw_context{ struct vmw_resource *error_resource; struct vmw_ctx_binding_state staged_bindings; struct list_head staged_cmd_res; + uint32_t quirks; }; struct vmw_legacy_display; @@ -831,6 +834,7 @@ extern int vmw_execbuf_process(struct drm_file *file_priv, void *kernel_commands, uint32_t command_size, uint64_t throttle_us, + uint32_t quirks, struct drm_vmw_fence_rep __user *user_fence_rep, struct vmw_fence_obj **out_fence); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 0792d8d59315..497ad6aecfbb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -679,6 +679,10 @@ static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv, &cmd->body.src.sid, NULL); if (unlikely(ret != 0)) return ret; + + if (sw_context->quirks & VMW_QUIRK_SCREENTARGET) + return 0; + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, &cmd->body.dest.sid, NULL); @@ -1260,6 +1264,9 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, if (unlikely(suffix->maximumOffset > bo_size)) suffix->maximumOffset = bo_size; + if (sw_context->quirks & VMW_QUIRK_SCREENTARGET) + goto out_no_surface; + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, &cmd->dma.host.sid, NULL); @@ -2544,6 +2551,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, void *kernel_commands, uint32_t command_size, uint64_t throttle_us, + uint32_t quirks, struct drm_vmw_fence_rep __user *user_fence_rep, struct vmw_fence_obj **out_fence) { @@ -2598,6 +2606,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, sw_context->fp = vmw_fpriv(file_priv); sw_context->cur_reloc = 0; sw_context->cur_val_buf = 0; + sw_context->quirks = quirks; INIT_LIST_HEAD(&sw_context->resource_list); sw_context->cur_query_bo = dev_priv->pinned_bo; sw_context->last_query_ctx = NULL; @@ -2904,6 +2913,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ret = vmw_execbuf_process(file_priv, dev_priv, (void __user *)(unsigned long)arg->commands, NULL, arg->command_size, arg->throttle_us, + 0, (void __user *)(unsigned long)arg->fence_rep, NULL); ttm_read_unlock(&dev_priv->reservation_sem); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index cac17c240ec0..7566a5a14004 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -993,7 +993,7 @@ int vmw_kms_generic_present(struct vmw_private *dev_priv, fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, - fifo_size, 0, NULL, NULL); + fifo_size, 0, 0, NULL, NULL); if (unlikely(ret != 0)) break; @@ -1121,7 +1121,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv, fifo_size = sizeof(*cmd) + sizeof(*blits) * blits_pos; ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, fifo_size, - 0, user_fence_rep, NULL); + 0, 0, user_fence_rep, NULL); kfree(cmd); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 807fc87c0c96..0d06d86e432a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -621,7 +621,7 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, - fifo_size, 0, NULL, out_fence); + fifo_size, 0, 0, NULL, out_fence); if (unlikely(ret != 0)) break; @@ -827,7 +827,7 @@ static int do_dmabuf_define_gmrfb(struct drm_file *file_priv, cmd->body.ptr.offset = 0; ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, - fifo_size, 0, NULL, NULL); + fifo_size, 0, 0, NULL, NULL); kfree(cmd); @@ -919,7 +919,7 @@ int vmw_kms_sou_do_dmabuf_dirty(struct drm_file *file_priv, fifo_size = sizeof(*blits) * hit_num; ret = vmw_execbuf_process(file_priv, dev_priv, NULL, blits, - fifo_size, 0, NULL, out_fence); + fifo_size, 0, 0, NULL, out_fence); if (unlikely(ret != 0)) break; -- cgit v1.3-6-gb490 From 35c051258e8fd7cb97222f4aa887bcd404c156d0 Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Fri, 26 Jun 2015 01:42:06 -0700 Subject: drm/vmwgfx: Implement screen targets Add support for the screen target device interface. Add a getparam parameter and bump minor to signal availability. Signed-off-by: Sinclair Yeh Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/Makefile | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 24 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 15 +- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 4 + drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 62 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 20 + drivers/gpu/drm/vmwgfx/vmwgfx_mob.c | 3 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 1364 +++++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 4 + include/uapi/drm/vmwgfx_drm.h | 1 + 10 files changed, 1475 insertions(+), 24 deletions(-) create mode 100644 drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile index 529bc7217c72..484093986d5a 100644 --- a/drivers/gpu/drm/vmwgfx/Makefile +++ b/drivers/gpu/drm/vmwgfx/Makefile @@ -7,6 +7,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \ vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \ vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o \ - vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o \ + vmwgfx_cmdbuf_res.o vmwgfx_cmdbuf.o vmwgfx_stdu.o \ obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 7e2b3c84119b..ab1b70ce19c1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -693,22 +693,28 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM); dev_priv->max_mob_size = vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); + dev_priv->stdu_max_width = + vmw_read(dev_priv, SVGA_REG_SCREENTARGET_MAX_WIDTH); + dev_priv->stdu_max_height = + vmw_read(dev_priv, SVGA_REG_SCREENTARGET_MAX_HEIGHT); + + vmw_write(dev_priv, SVGA_REG_DEV_CAP, + SVGA3D_DEVCAP_MAX_TEXTURE_WIDTH); + dev_priv->texture_max_width = vmw_read(dev_priv, + SVGA_REG_DEV_CAP); + vmw_write(dev_priv, SVGA_REG_DEV_CAP, + SVGA3D_DEVCAP_MAX_TEXTURE_HEIGHT); + dev_priv->texture_max_height = vmw_read(dev_priv, + SVGA_REG_DEV_CAP); } else dev_priv->prim_bb_mem = dev_priv->vram_size; + + vmw_print_capabilities(dev_priv->capabilities); ret = vmw_dma_masks(dev_priv); if (unlikely(ret != 0)) goto out_err0; - /* - * Limit back buffer size to VRAM size. Remove this once - * screen targets are implemented. - */ - if (dev_priv->prim_bb_mem > dev_priv->vram_size) - dev_priv->prim_bb_mem = dev_priv->vram_size; - - vmw_print_capabilities(dev_priv->capabilities); - if (dev_priv->capabilities & SVGA_CAP_GMR2) { DRM_INFO("Max GMR ids is %u\n", (unsigned)dev_priv->max_gmr_ids); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index c3f8fc97b336..04f8bf21557f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -40,17 +40,17 @@ #include #include "vmwgfx_fence.h" -#define VMWGFX_DRIVER_DATE "20140704" +#define VMWGFX_DRIVER_DATE "20150626" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 6 -#define VMWGFX_DRIVER_PATCHLEVEL 1 +#define VMWGFX_DRIVER_MINOR 7 +#define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) #define VMWGFX_MAX_RELOCATIONS 2048 #define VMWGFX_MAX_VALIDATIONS 2048 #define VMWGFX_MAX_DISPLAYS 16 #define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768 -#define VMWGFX_ENABLE_SCREEN_TARGET_OTABLE 0 +#define VMWGFX_ENABLE_SCREEN_TARGET_OTABLE 1 /* * Perhaps we should have sysfs entries for these. @@ -337,7 +337,8 @@ struct vmw_ctx_binding_state { enum vmw_display_unit_type { vmw_du_invalid = 0, vmw_du_legacy, - vmw_du_screen_object + vmw_du_screen_object, + vmw_du_screen_target }; @@ -402,6 +403,10 @@ struct vmw_private { uint32_t mmio_size; uint32_t fb_max_width; uint32_t fb_max_height; + uint32_t texture_max_width; + uint32_t texture_max_height; + uint32_t stdu_max_width; + uint32_t stdu_max_height; uint32_t initial_width; uint32_t initial_height; __le32 __iomem *mmio_virt; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 69c8ce23123c..55940bc0eb07 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -105,6 +105,10 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_MAX_MOB_SIZE: param->value = dev_priv->max_mob_size; break; + case DRM_VMW_PARAM_SCREEN_TARGET: + param->value = + (dev_priv->active_display_unit == vmw_du_screen_target); + break; default: DRM_ERROR("Illegal vmwgfx get param request: %d\n", param->param); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 7566a5a14004..6680aa67386f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -463,6 +463,11 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, flags, color, clips, num_clips, inc, NULL); + else + ret = vmw_kms_stdu_do_surface_dirty(dev_priv, file_priv, + &vfbs->base, + clips, num_clips, + inc); vmw_fifo_flush(dev_priv, false); ttm_read_unlock(&dev_priv->reservation_sem); @@ -636,6 +641,11 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, flags, color, clips, num_clips, increment, NULL); + } else { + ret = vmw_kms_stdu_do_surface_dirty(dev_priv, file_priv, + &vfbd->base, + clips, num_clips, + increment); } vmw_fifo_flush(dev_priv, false); @@ -999,8 +1009,6 @@ int vmw_kms_generic_present(struct vmw_private *dev_priv, break; } - vmw_fifo_flush(dev_priv, false); - kfree(cmd); out_free_tmp: kfree(tmp); @@ -1017,8 +1025,21 @@ int vmw_kms_present(struct vmw_private *dev_priv, struct drm_vmw_rect *clips, uint32_t num_clips) { - return vmw_kms_generic_present(dev_priv, file_priv, vfb, surface, sid, - destX, destY, clips, num_clips); + int ret; + + if (dev_priv->active_display_unit == vmw_du_screen_target) + ret = vmw_kms_stdu_present(dev_priv, file_priv, vfb, sid, + destX, destY, clips, num_clips); + else + ret = vmw_kms_generic_present(dev_priv, file_priv, vfb, + surface, sid, destX, destY, + clips, num_clips); + if (ret) + return ret; + + vmw_fifo_flush(dev_priv, false); + + return 0; } int vmw_kms_readback(struct vmw_private *dev_priv, @@ -1141,9 +1162,12 @@ int vmw_kms_init(struct vmw_private *dev_priv) dev->mode_config.max_width = 8192; dev->mode_config.max_height = 8192; - ret = vmw_kms_sou_init_display(dev_priv); - if (ret) /* Fallback */ - ret = vmw_kms_ldu_init_display(dev_priv); + ret = vmw_kms_stdu_init_display(dev_priv); + if (ret) { + ret = vmw_kms_sou_init_display(dev_priv); + if (ret) /* Fallback */ + ret = vmw_kms_ldu_init_display(dev_priv); + } return ret; } @@ -1160,6 +1184,8 @@ int vmw_kms_close(struct vmw_private *dev_priv) drm_mode_config_cleanup(dev_priv->dev); if (dev_priv->active_display_unit == vmw_du_screen_object) ret = vmw_kms_sou_close_display(dev_priv); + else if (dev_priv->active_display_unit == vmw_du_screen_target) + ret = vmw_kms_stdu_close_display(dev_priv); else ret = vmw_kms_ldu_close_display(dev_priv); @@ -1311,7 +1337,9 @@ bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv, uint32_t pitch, uint32_t height) { - return ((u64) pitch * (u64) height) < (u64) dev_priv->prim_bb_mem; + return ((u64) pitch * (u64) height) < (u64) + ((dev_priv->active_display_unit == vmw_du_screen_target) ? + dev_priv->prim_bb_mem : dev_priv->vram_size); } @@ -1558,6 +1586,11 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, if (dev_priv->active_display_unit == vmw_du_screen_object) assumed_bpp = 4; + if (dev_priv->active_display_unit == vmw_du_screen_target) { + max_width = min(max_width, dev_priv->stdu_max_width); + max_height = min(max_height, dev_priv->stdu_max_height); + } + /* Add preferred mode */ mode = drm_mode_duplicate(dev, &prefmode); if (!mode) @@ -1674,6 +1707,19 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, bounding_box.h = rects[i].y + rects[i].h; } + /* + * For Screen Target Display Unit, all the displays must fit + * inside of maximum texture size. + */ + if (dev_priv->active_display_unit == vmw_du_screen_target) + if (bounding_box.w > dev_priv->texture_max_width || + bounding_box.h > dev_priv->texture_max_height) { + DRM_ERROR("Layout exceeds maximum texture size\n"); + ret = -EINVAL; + goto out_free; + } + + vmw_du_update_layout(dev_priv, arg->num_outputs, rects); out_free: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 0f2c29166f7c..548fa872b39c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -204,4 +204,24 @@ int vmw_kms_sou_do_dmabuf_dirty(struct drm_file *file_priv, struct drm_clip_rect *clips, unsigned num_clips, int increment, struct vmw_fence_obj **out_fence); + + +/* + * Screen Target Display Unit functions - vmwgfx_stdu.c + */ +int vmw_kms_stdu_init_display(struct vmw_private *dev_priv); +int vmw_kms_stdu_close_display(struct vmw_private *dev_priv); +int vmw_kms_stdu_do_surface_dirty(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *framebuffer, + struct drm_clip_rect *clips, + unsigned num_clips, int increment); +int vmw_kms_stdu_present(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + uint32_t user_handle, + int32_t dest_x, int32_t dest_y, + struct drm_vmw_rect *clips, + uint32_t num_clips); + #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index 46f975e57d06..0feac5675c51 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -31,7 +31,8 @@ * If we set up the screen target otable, screen objects stop working. */ -#define VMW_OTABLE_SETUP_SUB ((VMWGFX_ENABLE_SCREEN_TARGET_OTABLE) ? 0 : 1) +#define VMW_OTABLE_SETUP_SUB ((VMWGFX_ENABLE_SCREEN_TARGET_OTABLE && \ + (dev_priv->capabilities & SVGA_CAP_3D)) ? 0 : 1) #ifdef CONFIG_64BIT #define VMW_PPN_SIZE 8 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c new file mode 100644 index 000000000000..3b8235c7ee42 --- /dev/null +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -0,0 +1,1364 @@ +/****************************************************************************** + * + * Copyright © 2014 VMware, Inc., Palo Alto, CA., USA + * All Rights Reserved. + * + * 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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 "vmwgfx_kms.h" +#include "svga3d_surfacedefs.h" +#include + +#define vmw_crtc_to_stdu(x) \ + container_of(x, struct vmw_screen_target_display_unit, base.crtc) +#define vmw_encoder_to_stdu(x) \ + container_of(x, struct vmw_screen_target_display_unit, base.encoder) +#define vmw_connector_to_stdu(x) \ + container_of(x, struct vmw_screen_target_display_unit, base.connector) + + + +enum stdu_content_type { + SAME_AS_DISPLAY = 0, + SEPARATE_SURFACE, + SEPARATE_DMA +}; + + + +/** + * struct vmw_screen_target_display_unit + * + * @base: VMW specific DU structure + * @display_srf: surface to be displayed. The dimension of this will always + * match the display mode. If the display mode matches + * content_vfbs dimensions, then this is a pointer into the + * corresponding field in content_vfbs. If not, then this + * is a separate buffer to which content_vfbs will blit to. + * @content_fb: holds the rendered content, can be a surface or DMA buffer + * @content_type: content_fb type + * @defined: true if the current display unit has been initialized + */ +struct vmw_screen_target_display_unit { + struct vmw_display_unit base; + + struct vmw_surface *display_srf; + struct drm_framebuffer *content_fb; + + enum stdu_content_type content_fb_type; + + bool defined; +}; + + + +static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu); + + + +/****************************************************************************** + * Screen Target Display Unit helper Functions + *****************************************************************************/ + +/** + * vmw_stdu_pin_display - pins the resource associated with the display surface + * + * @stdu: contains the display surface + * + * Since the display surface can either be a private surface allocated by us, + * or it can point to the content surface, we use this function to not pin the + * same resource twice. + */ +static int vmw_stdu_pin_display(struct vmw_screen_target_display_unit *stdu) +{ + return vmw_resource_pin(&stdu->display_srf->res); +} + + + +/** + * vmw_stdu_unpin_display - unpins the resource associated with display surface + * + * @stdu: contains the display surface + * + * If the display surface was privatedly allocated by + * vmw_surface_gb_priv_define() and not registered as a framebuffer, then it + * won't be automatically cleaned up when all the framebuffers are freed. As + * such, we have to explicitly call vmw_resource_unreference() to get it freed. + */ +static void vmw_stdu_unpin_display(struct vmw_screen_target_display_unit *stdu) +{ + if (stdu->display_srf) { + struct vmw_resource *res = &stdu->display_srf->res; + + vmw_resource_unpin(res); + + if (stdu->content_fb_type != SAME_AS_DISPLAY) { + vmw_resource_unreference(&res); + stdu->content_fb_type = SAME_AS_DISPLAY; + } + + stdu->display_srf = NULL; + } +} + + + +/****************************************************************************** + * Screen Target Display Unit CRTC Functions + *****************************************************************************/ + + +/** + * vmw_stdu_crtc_destroy - cleans up the STDU + * + * @crtc: used to get a reference to the containing STDU + */ +static void vmw_stdu_crtc_destroy(struct drm_crtc *crtc) +{ + vmw_stdu_destroy(vmw_crtc_to_stdu(crtc)); +} + + + +/** + * vmw_stdu_content_copy - copies an area from the content to display surface + * + * @dev_priv: VMW DRM device + * @file_priv: Pointer to a drm file private structure + * @stdu: STDU whose display surface will be blitted to + * @content_x: top/left corner of the content area to blit from + * @content_y: top/left corner of the content area to blit from + * @width: width of the blit area + * @height: height of the blit area + * @display_x: top/left corner of the display area to blit to + * @display_y: top/left corner of the display area to blit to + * + * Copies an area from the content surface to the display surface. + * + * RETURNs: + * 0 on success, error code on failure + */ +static int vmw_stdu_content_copy(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_screen_target_display_unit *stdu, + uint32_t content_x, uint32_t content_y, + uint32_t width, uint32_t height, + uint32_t display_x, uint32_t display_y) +{ + size_t fifo_size; + int ret; + void *cmd; + + struct vmw_surface_dma { + SVGA3dCmdHeader header; + SVGA3dCmdSurfaceDMA body; + SVGA3dCopyBox area; + SVGA3dCmdSurfaceDMASuffix suffix; + } surface_dma_cmd; + + struct { + SVGA3dCmdHeader header; + SVGA3dCmdSurfaceCopy body; + SVGA3dCopyBox area; + } surface_cpy_cmd; + + + /* + * Can only copy if content and display surfaces exist and are not + * the same surface + */ + if (stdu->display_srf == NULL || stdu->content_fb == NULL || + stdu->content_fb_type == SAME_AS_DISPLAY) { + return -EINVAL; + } + + if (stdu->content_fb_type == SEPARATE_DMA) { + struct vmw_framebuffer *content_vfb; + struct vmw_framebuffer_dmabuf *content_vfbd; + struct vmw_framebuffer_surface *content_vfbs; + struct drm_vmw_size cur_size = {0}; + const struct svga3d_surface_desc *desc; + SVGA3dCmdSurfaceDMASuffix *suffix; + SVGAGuestPtr ptr; + + content_vfb = vmw_framebuffer_to_vfb(stdu->content_fb); + content_vfbd = vmw_framebuffer_to_vfbd(stdu->content_fb); + content_vfbs = vmw_framebuffer_to_vfbs(stdu->content_fb); + + cur_size.width = width; + cur_size.height = height; + cur_size.depth = 1; + + desc = svga3dsurface_get_desc(content_vfbs->surface->format); + + + fifo_size = sizeof(surface_dma_cmd); + + memset(&surface_dma_cmd, 0, fifo_size); + + ptr.gmrId = content_vfb->user_handle; + ptr.offset = 0; + + surface_dma_cmd.header.id = SVGA_3D_CMD_SURFACE_DMA; + surface_dma_cmd.header.size = sizeof(surface_dma_cmd.body) + + sizeof(surface_dma_cmd.area) + + sizeof(surface_dma_cmd.suffix); + + surface_dma_cmd.body.guest.ptr = ptr; + surface_dma_cmd.body.guest.pitch = stdu->content_fb->pitches[0]; + surface_dma_cmd.body.host.sid = stdu->display_srf->res.id; + surface_dma_cmd.body.host.face = 0; + surface_dma_cmd.body.host.mipmap = 0; + surface_dma_cmd.body.transfer = SVGA3D_WRITE_HOST_VRAM; + + surface_dma_cmd.area.srcx = content_x; + surface_dma_cmd.area.srcy = content_y; + surface_dma_cmd.area.x = display_x; + surface_dma_cmd.area.y = display_y; + surface_dma_cmd.area.d = 1; + surface_dma_cmd.area.w = width; + surface_dma_cmd.area.h = height; + + suffix = &surface_dma_cmd.suffix; + + suffix->suffixSize = sizeof(*suffix); + suffix->maximumOffset = svga3dsurface_get_image_buffer_size( + desc, + &cur_size, + stdu->content_fb->pitches[0]); + + cmd = (void *) &surface_dma_cmd; + } else { + struct vmw_framebuffer *content_vfb; + + content_vfb = vmw_framebuffer_to_vfb(stdu->content_fb); + + fifo_size = sizeof(surface_cpy_cmd); + + memset(&surface_cpy_cmd, 0, sizeof(surface_cpy_cmd)); + + surface_cpy_cmd.header.id = SVGA_3D_CMD_SURFACE_COPY; + surface_cpy_cmd.header.size = sizeof(surface_cpy_cmd.body) + + sizeof(surface_cpy_cmd.area); + + surface_cpy_cmd.body.src.sid = content_vfb->user_handle; + surface_cpy_cmd.body.dest.sid = stdu->display_srf->res.id; + + surface_cpy_cmd.area.srcx = content_x; + surface_cpy_cmd.area.srcy = content_y; + surface_cpy_cmd.area.x = display_x; + surface_cpy_cmd.area.y = display_y; + surface_cpy_cmd.area.d = 1; + surface_cpy_cmd.area.w = width; + surface_cpy_cmd.area.h = height; + + cmd = (void *) &surface_cpy_cmd; + } + + ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, + fifo_size, 0, VMW_QUIRK_SCREENTARGET, + NULL, NULL); + + return ret; +} + + + +/** + * vmw_stdu_define_st - Defines a Screen Target + * + * @dev_priv: VMW DRM device + * @stdu: display unit to create a Screen Target for + * + * Creates a STDU that we can used later. This function is called whenever the + * framebuffer size changes. + * + * RETURNs: + * 0 on success, error code on failure + */ +static int vmw_stdu_define_st(struct vmw_private *dev_priv, + struct vmw_screen_target_display_unit *stdu) +{ + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDefineGBScreenTarget body; + } *cmd; + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + + if (unlikely(cmd == NULL)) { + DRM_ERROR("Out of FIFO space defining Screen Target\n"); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SCREENTARGET; + cmd->header.size = sizeof(cmd->body); + + cmd->body.stid = stdu->base.unit; + cmd->body.width = stdu->display_srf->base_size.width; + cmd->body.height = stdu->display_srf->base_size.height; + cmd->body.flags = (0 == cmd->body.stid) ? SVGA_STFLAG_PRIMARY : 0; + cmd->body.dpi = 0; + cmd->body.xRoot = stdu->base.crtc.x; + cmd->body.yRoot = stdu->base.crtc.y; + + if (!stdu->base.is_implicit) { + cmd->body.xRoot = stdu->base.gui_x; + cmd->body.yRoot = stdu->base.gui_y; + } + + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + stdu->defined = true; + + return 0; +} + + + +/** + * vmw_stdu_bind_st - Binds a surface to a Screen Target + * + * @dev_priv: VMW DRM device + * @stdu: display unit affected + * @res: Buffer to bind to the screen target. Set to NULL to blank screen. + * + * Binding a surface to a Screen Target the same as flipping + */ +static int vmw_stdu_bind_st(struct vmw_private *dev_priv, + struct vmw_screen_target_display_unit *stdu, + struct vmw_resource *res) +{ + SVGA3dSurfaceImageId image; + + struct { + SVGA3dCmdHeader header; + SVGA3dCmdBindGBScreenTarget body; + } *cmd; + + + if (!stdu->defined) { + DRM_ERROR("No screen target defined\n"); + return -EINVAL; + } + + /* Set up image using information in vfb */ + memset(&image, 0, sizeof(image)); + image.sid = res ? res->id : SVGA3D_INVALID_ID; + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + + if (unlikely(cmd == NULL)) { + DRM_ERROR("Out of FIFO space binding a screen target\n"); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_BIND_GB_SCREENTARGET; + cmd->header.size = sizeof(cmd->body); + + cmd->body.stid = stdu->base.unit; + cmd->body.image = image; + + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + return 0; +} + + + +/** + * vmw_stdu_update_st - Updates a Screen Target + * + * @dev_priv: VMW DRM device + * @file_priv: Pointer to a drm file private structure + * @stdu: display unit affected + * @update_area: area that needs to be updated + * + * This function needs to be called whenever the content of a screen + * target changes. + * If the display and content buffers are different, then this function does + * a blit first from the content buffer to the display buffer before issuing + * the Screen Target update command. + * + * RETURNS: + * 0 on success, error code on failure + */ +static int vmw_stdu_update_st(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_screen_target_display_unit *stdu, + struct drm_clip_rect *update_area) +{ + u32 width, height; + u32 display_update_x, display_update_y; + unsigned short display_x1, display_y1, display_x2, display_y2; + + struct { + SVGA3dCmdHeader header; + SVGA3dCmdUpdateGBScreenTarget body; + } *cmd; + + + if (!stdu->defined) { + DRM_ERROR("No screen target defined"); + return -EINVAL; + } + + /* Display coordinates relative to its position in content surface */ + display_x1 = stdu->base.crtc.x; + display_y1 = stdu->base.crtc.y; + display_x2 = display_x1 + stdu->display_srf->base_size.width; + display_y2 = display_y1 + stdu->display_srf->base_size.height; + + /* Do nothing if the update area is outside of the display surface */ + if (update_area->x2 <= display_x1 || update_area->x1 >= display_x2 || + update_area->y2 <= display_y1 || update_area->y1 >= display_y2) + return 0; + + /* The top-left hand corner of the update area in display surface */ + display_update_x = max(update_area->x1 - display_x1, 0); + display_update_y = max(update_area->y1 - display_y1, 0); + + width = min(update_area->x2, display_x2) - + max(update_area->x1, display_x1); + height = min(update_area->y2, display_y2) - + max(update_area->y1, display_y1); + + if (file_priv && stdu->content_fb_type != SAME_AS_DISPLAY) { + int ret; + + ret = vmw_stdu_content_copy(dev_priv, file_priv, + stdu, + max(update_area->x1, display_x1), + max(update_area->y1, display_y1), + width, height, + display_update_x, display_update_y); + if (unlikely(ret != 0)) { + DRM_ERROR("Failed to blit content\n"); + return ret; + } + } + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + + if (unlikely(cmd == NULL)) { + DRM_ERROR("Out of FIFO space updating a Screen Target\n"); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_UPDATE_GB_SCREENTARGET; + cmd->header.size = sizeof(cmd->body); + + cmd->body.stid = stdu->base.unit; + cmd->body.rect.x = display_update_x; + cmd->body.rect.y = display_update_y; + cmd->body.rect.w = width; + cmd->body.rect.h = height; + + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + return 0; +} + + + +/** + * vmw_stdu_destroy_st - Destroy a Screen Target + * + * @dev_priv: VMW DRM device + * @stdu: display unit to destroy + */ +static int vmw_stdu_destroy_st(struct vmw_private *dev_priv, + struct vmw_screen_target_display_unit *stdu) +{ + int ret; + + struct { + SVGA3dCmdHeader header; + SVGA3dCmdDestroyGBScreenTarget body; + } *cmd; + + + /* Nothing to do if not successfully defined */ + if (unlikely(!stdu->defined)) + return 0; + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + + if (unlikely(cmd == NULL)) { + DRM_ERROR("Out of FIFO space, screen target not destroyed\n"); + return -ENOMEM; + } + + cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SCREENTARGET; + cmd->header.size = sizeof(cmd->body); + + cmd->body.stid = stdu->base.unit; + + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + /* Force sync */ + ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ); + if (unlikely(ret != 0)) + DRM_ERROR("Failed to sync with HW"); + + stdu->defined = false; + + return ret; +} + + + +/** + * vmw_stdu_crtc_set_config - Sets a mode + * + * @set: mode parameters + * + * This function is the device-specific portion of the DRM CRTC mode set. + * For the SVGA device, we do this by defining a Screen Target, binding a + * GB Surface to that target, and finally update the screen target. + * + * RETURNS: + * 0 on success, error code otherwise + */ +static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) +{ + struct vmw_private *dev_priv; + struct vmw_screen_target_display_unit *stdu; + struct vmw_framebuffer *vfb; + struct vmw_framebuffer_surface *new_vfbs; + struct drm_display_mode *mode; + struct drm_framebuffer *new_fb; + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; + struct drm_clip_rect update_area = {0}; + int ret; + + + if (!set || !set->crtc) + return -EINVAL; + + crtc = set->crtc; + crtc->x = set->x; + crtc->y = set->y; + stdu = vmw_crtc_to_stdu(crtc); + mode = set->mode; + new_fb = set->fb; + dev_priv = vmw_priv(crtc->dev); + + + if (set->num_connectors > 1) { + DRM_ERROR("Too many connectors\n"); + return -EINVAL; + } + + if (set->num_connectors == 1 && + set->connectors[0] != &stdu->base.connector) { + DRM_ERROR("Connectors don't match %p %p\n", + set->connectors[0], &stdu->base.connector); + return -EINVAL; + } + + + /* Since they always map one to one these are safe */ + connector = &stdu->base.connector; + encoder = &stdu->base.encoder; + + + /* + * After this point the CRTC will be considered off unless a new fb + * is bound + */ + if (stdu->defined) { + /* Unbind current surface by binding an invalid one */ + ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); + if (unlikely(ret != 0)) + return ret; + + /* Update Screen Target, display will now be blank */ + if (crtc->primary->fb) { + update_area.x2 = crtc->primary->fb->width; + update_area.y2 = crtc->primary->fb->height; + + ret = vmw_stdu_update_st(dev_priv, NULL, + stdu, + &update_area); + if (unlikely(ret != 0)) + return ret; + } + + crtc->primary->fb = NULL; + crtc->enabled = false; + encoder->crtc = NULL; + connector->encoder = NULL; + + vmw_stdu_unpin_display(stdu); + stdu->content_fb = NULL; + stdu->content_fb_type = SAME_AS_DISPLAY; + + ret = vmw_stdu_destroy_st(dev_priv, stdu); + /* The hardware is hung, give up */ + if (unlikely(ret != 0)) + return ret; + } + + + /* Any of these conditions means the caller wants CRTC off */ + if (set->num_connectors == 0 || !mode || !new_fb) + return 0; + + + if (set->x + mode->hdisplay > new_fb->width || + set->y + mode->vdisplay > new_fb->height) { + DRM_ERROR("Set outside of framebuffer\n"); + return -EINVAL; + } + + stdu->content_fb = new_fb; + vfb = vmw_framebuffer_to_vfb(stdu->content_fb); + + if (vfb->dmabuf) + stdu->content_fb_type = SEPARATE_DMA; + + /* + * If the requested mode is different than the width and height + * of the FB or if the content buffer is a DMA buf, then allocate + * a display FB that matches the dimension of the mode + */ + if (mode->hdisplay != new_fb->width || + mode->vdisplay != new_fb->height || + stdu->content_fb_type != SAME_AS_DISPLAY) { + struct vmw_surface content_srf; + struct drm_vmw_size display_base_size = {0}; + struct vmw_surface *display_srf; + + + display_base_size.width = mode->hdisplay; + display_base_size.height = mode->vdisplay; + display_base_size.depth = 1; + + /* + * If content buffer is a DMA buf, then we have to construct + * surface info + */ + if (stdu->content_fb_type == SEPARATE_DMA) { + + switch (new_fb->bits_per_pixel) { + case 32: + content_srf.format = SVGA3D_X8R8G8B8; + break; + + case 16: + content_srf.format = SVGA3D_R5G6B5; + break; + + case 8: + content_srf.format = SVGA3D_P8; + break; + + default: + DRM_ERROR("Invalid format\n"); + ret = -EINVAL; + goto err_unref_content; + } + + content_srf.flags = 0; + content_srf.mip_levels[0] = 1; + content_srf.multisample_count = 0; + } else { + + stdu->content_fb_type = SEPARATE_SURFACE; + + new_vfbs = vmw_framebuffer_to_vfbs(new_fb); + content_srf = *new_vfbs->surface; + } + + + ret = vmw_surface_gb_priv_define(crtc->dev, + 0, /* because kernel visible only */ + content_srf.flags, + content_srf.format, + true, /* a scanout buffer */ + content_srf.mip_levels[0], + content_srf.multisample_count, + display_base_size, + &display_srf); + if (unlikely(ret != 0)) { + DRM_ERROR("Cannot allocate a display FB.\n"); + goto err_unref_content; + } + + stdu->display_srf = display_srf; + } else { + new_vfbs = vmw_framebuffer_to_vfbs(new_fb); + stdu->display_srf = new_vfbs->surface; + } + + + ret = vmw_stdu_pin_display(stdu); + if (unlikely(ret != 0)) { + stdu->display_srf = NULL; + goto err_unref_content; + } + + vmw_fb_off(dev_priv); + vmw_svga_enable(dev_priv); + + /* + * Steps to displaying a surface, assume surface is already + * bound: + * 1. define a screen target + * 2. bind a fb to the screen target + * 3. update that screen target (this is done later by + * vmw_kms_stdu_do_surface_dirty_or_present) + */ + ret = vmw_stdu_define_st(dev_priv, stdu); + if (unlikely(ret != 0)) + goto err_unpin_display_and_content; + + ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); + if (unlikely(ret != 0)) + goto err_unpin_destroy_st; + + + connector->encoder = encoder; + encoder->crtc = crtc; + + crtc->mode = *mode; + crtc->primary->fb = new_fb; + crtc->enabled = true; + + return ret; + +err_unpin_destroy_st: + vmw_stdu_destroy_st(dev_priv, stdu); +err_unpin_display_and_content: + vmw_stdu_unpin_display(stdu); +err_unref_content: + stdu->content_fb = NULL; + return ret; +} + + + +/** + * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target + * + * @crtc: CRTC to attach FB to + * @fb: FB to attach + * @event: Event to be posted. This event should've been alloced + * using k[mz]alloc, and should've been completely initialized. + * @page_flip_flags: Input flags. + * + * If the STDU uses the same display and content buffers, i.e. a true flip, + * this function will replace the existing display buffer with the new content + * buffer. + * + * If the STDU uses different display and content buffers, i.e. a blit, then + * only the content buffer will be updated. + * + * RETURNS: + * 0 on success, error code on failure + */ +static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *new_fb, + struct drm_pending_vblank_event *event, + uint32_t flags) + +{ + struct vmw_private *dev_priv = vmw_priv(crtc->dev); + struct vmw_screen_target_display_unit *stdu; + struct drm_file *file_priv; + struct drm_clip_rect update_area = {0}; + int ret; + + /* + * Temporarily don't support event == NULL. We need the + * @file_priv pointer! + */ + if (event == NULL) + return -EINVAL; + + if (crtc == NULL) + return -EINVAL; + + dev_priv = vmw_priv(crtc->dev); + stdu = vmw_crtc_to_stdu(crtc); + crtc->primary->fb = new_fb; + stdu->content_fb = new_fb; + + if (stdu->display_srf) { + update_area.x2 = stdu->display_srf->base_size.width; + update_area.y2 = stdu->display_srf->base_size.height; + + /* + * If the display surface is the same as the content surface + * then remove the reference + */ + if (stdu->content_fb_type == SAME_AS_DISPLAY) { + if (stdu->defined) { + /* Unbind the current surface */ + ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); + if (unlikely(ret != 0)) + goto err_out; + } + vmw_stdu_unpin_display(stdu); + stdu->display_srf = NULL; + } + } + + + if (!new_fb) { + /* Blanks the display */ + (void) vmw_stdu_update_st(dev_priv, NULL, stdu, &update_area); + + return 0; + } + + + if (stdu->content_fb_type == SAME_AS_DISPLAY) { + stdu->display_srf = vmw_framebuffer_to_vfbs(new_fb)->surface; + ret = vmw_stdu_pin_display(stdu); + if (ret) { + stdu->display_srf = NULL; + goto err_out; + } + + /* Bind display surface */ + ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); + if (unlikely(ret != 0)) + goto err_unpin_display_and_content; + } + + /* Update display surface: after this point everything is bound */ + update_area.x2 = stdu->display_srf->base_size.width; + update_area.y2 = stdu->display_srf->base_size.height; + + file_priv = event->base.file_priv; + ret = vmw_stdu_update_st(dev_priv, file_priv, stdu, &update_area); + if (unlikely(ret != 0)) + return ret; + + if (event) { + struct vmw_fence_obj *fence = NULL; + + vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); + if (!fence) + return -ENOMEM; + + ret = vmw_event_fence_action_queue(file_priv, fence, + &event->base, + &event->event.tv_sec, + &event->event.tv_usec, + true); + vmw_fence_obj_unreference(&fence); + } + + return ret; + +err_unpin_display_and_content: + vmw_stdu_unpin_display(stdu); +err_out: + crtc->primary->fb = NULL; + stdu->content_fb = NULL; + return ret; +} + + + +/* + * Screen Target CRTC dispatch table + */ +static struct drm_crtc_funcs vmw_stdu_crtc_funcs = { + .save = vmw_du_crtc_save, + .restore = vmw_du_crtc_restore, + .cursor_set = vmw_du_crtc_cursor_set, + .cursor_move = vmw_du_crtc_cursor_move, + .gamma_set = vmw_du_crtc_gamma_set, + .destroy = vmw_stdu_crtc_destroy, + .set_config = vmw_stdu_crtc_set_config, + .page_flip = vmw_stdu_crtc_page_flip, +}; + + + +/****************************************************************************** + * Screen Target Display Unit Encoder Functions + *****************************************************************************/ + +/** + * vmw_stdu_encoder_destroy - cleans up the STDU + * + * @encoder: used the get the containing STDU + * + * vmwgfx cleans up crtc/encoder/connector all at the same time so technically + * this can be a no-op. Nevertheless, it doesn't hurt of have this in case + * the common KMS code changes and somehow vmw_stdu_crtc_destroy() doesn't + * get called. + */ +static void vmw_stdu_encoder_destroy(struct drm_encoder *encoder) +{ + vmw_stdu_destroy(vmw_encoder_to_stdu(encoder)); +} + +static struct drm_encoder_funcs vmw_stdu_encoder_funcs = { + .destroy = vmw_stdu_encoder_destroy, +}; + + + +/****************************************************************************** + * Screen Target Display Unit Connector Functions + *****************************************************************************/ + +/** + * vmw_stdu_connector_destroy - cleans up the STDU + * + * @connector: used to get the containing STDU + * + * vmwgfx cleans up crtc/encoder/connector all at the same time so technically + * this can be a no-op. Nevertheless, it doesn't hurt of have this in case + * the common KMS code changes and somehow vmw_stdu_crtc_destroy() doesn't + * get called. + */ +static void vmw_stdu_connector_destroy(struct drm_connector *connector) +{ + vmw_stdu_destroy(vmw_connector_to_stdu(connector)); +} + + + +static struct drm_connector_funcs vmw_stdu_connector_funcs = { + .dpms = vmw_du_connector_dpms, + .save = vmw_du_connector_save, + .restore = vmw_du_connector_restore, + .detect = vmw_du_connector_detect, + .fill_modes = vmw_du_connector_fill_modes, + .set_property = vmw_du_connector_set_property, + .destroy = vmw_stdu_connector_destroy, +}; + + + +/** + * vmw_stdu_init - Sets up a Screen Target Display Unit + * + * @dev_priv: VMW DRM device + * @unit: unit number range from 0 to VMWGFX_NUM_DISPLAY_UNITS + * + * This function is called once per CRTC, and allocates one Screen Target + * display unit to represent that CRTC. Since the SVGA device does not separate + * out encoder and connector, they are represented as part of the STDU as well. + */ +static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) +{ + struct vmw_screen_target_display_unit *stdu; + struct drm_device *dev = dev_priv->dev; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct drm_crtc *crtc; + + + stdu = kzalloc(sizeof(*stdu), GFP_KERNEL); + if (!stdu) + return -ENOMEM; + + stdu->base.unit = unit; + crtc = &stdu->base.crtc; + encoder = &stdu->base.encoder; + connector = &stdu->base.connector; + + stdu->base.pref_active = (unit == 0); + stdu->base.pref_width = dev_priv->initial_width; + stdu->base.pref_height = dev_priv->initial_height; + stdu->base.pref_mode = NULL; + stdu->base.is_implicit = true; + + drm_connector_init(dev, connector, &vmw_stdu_connector_funcs, + DRM_MODE_CONNECTOR_VIRTUAL); + connector->status = vmw_du_connector_detect(connector, false); + + drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs, + DRM_MODE_ENCODER_VIRTUAL); + drm_mode_connector_attach_encoder(connector, encoder); + encoder->possible_crtcs = (1 << unit); + encoder->possible_clones = 0; + + (void) drm_connector_register(connector); + + drm_crtc_init(dev, crtc, &vmw_stdu_crtc_funcs); + + drm_mode_crtc_set_gamma_size(crtc, 256); + + drm_object_attach_property(&connector->base, + dev->mode_config.dirty_info_property, + 1); + + return 0; +} + + + +/** + * vmw_stdu_destroy - Cleans up a vmw_screen_target_display_unit + * + * @stdu: Screen Target Display Unit to be destroyed + * + * Clean up after vmw_stdu_init + */ +static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu) +{ + vmw_stdu_unpin_display(stdu); + + vmw_du_cleanup(&stdu->base); + kfree(stdu); +} + + + +/****************************************************************************** + * Screen Target Display KMS Functions + * + * These functions are called by the common KMS code in vmwgfx_kms.c + *****************************************************************************/ + +/** + * vmw_kms_stdu_init_display - Initializes a Screen Target based display + * + * @dev_priv: VMW DRM device + * + * This function initialize a Screen Target based display device. It checks + * the capability bits to make sure the underlying hardware can support + * screen targets, and then creates the maximum number of CRTCs, a.k.a Display + * Units, as supported by the display hardware. + * + * RETURNS: + * 0 on success, error code otherwise + */ +int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + int i, ret; + + + /* Do nothing if Screen Target support is turned off */ + if (!VMWGFX_ENABLE_SCREEN_TARGET_OTABLE) + return -ENOSYS; + + if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS) || + !(dev_priv->capabilities & SVGA_CAP_3D)) + return -ENOSYS; + + ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); + if (unlikely(ret != 0)) + return ret; + + ret = drm_mode_create_dirty_info_property(dev); + if (unlikely(ret != 0)) + goto err_vblank_cleanup; + + for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { + ret = vmw_stdu_init(dev_priv, i); + + if (unlikely(ret != 0)) { + DRM_ERROR("Failed to initialize STDU %d", i); + goto err_vblank_cleanup; + } + } + + dev_priv->active_display_unit = vmw_du_screen_target; + + DRM_INFO("Screen Target Display device initialized\n"); + + return 0; + +err_vblank_cleanup: + drm_vblank_cleanup(dev); + return ret; +} + + + +/** + * vmw_kms_stdu_close_display - Cleans up after vmw_kms_stdu_init_display + * + * @dev_priv: VMW DRM device + * + * Frees up any resources allocated by vmw_kms_stdu_init_display + * + * RETURNS: + * 0 on success + */ +int vmw_kms_stdu_close_display(struct vmw_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + + drm_vblank_cleanup(dev); + + return 0; +} + + + +/** + * vmw_kms_stdu_do_surface_dirty - updates a dirty rectange to SVGA device + * + * @dev_priv: VMW DRM device + * @file_priv: Pointer to a drm file private structure + * @framebuffer: FB with the new content to be copied to SVGA device + * @clip_rects: array of dirty rectanges + * @num_of_clip_rects: number of rectanges in @clips + * @increment: increment to the next dirty rect in @clips + * + * This function sends an Update command to the SVGA device. This will notify + * the device that a region needs to be copied to the screen. At this time + * we are not coalescing clip rects into one large clip rect because the SVGA + * device will do it for us. + * + * RETURNS: + * 0 on success, error code otherwise + */ +int vmw_kms_stdu_do_surface_dirty(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *framebuffer, + struct drm_clip_rect *clip_rects, + unsigned num_of_clip_rects, int increment) +{ + struct vmw_screen_target_display_unit *stdu[VMWGFX_NUM_DISPLAY_UNITS]; + struct drm_clip_rect *cur_rect; + struct drm_crtc *crtc; + + unsigned num_of_du = 0, cur_du, count = 0; + int ret = 0; + + + BUG_ON(!clip_rects || !num_of_clip_rects); + + /* Figure out all the DU affected by this surface */ + list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, + head) { + if (crtc->primary->fb != &framebuffer->base) + continue; + + stdu[num_of_du++] = vmw_crtc_to_stdu(crtc); + } + + for (cur_du = 0; cur_du < num_of_du; cur_du++) + for (cur_rect = clip_rects, count = 0; + count < num_of_clip_rects && ret == 0; + cur_rect += increment, count++) { + ret = vmw_stdu_update_st(dev_priv, file_priv, + stdu[cur_du], + cur_rect); + } + + return ret; +} + + + +/** + * vmw_kms_stdu_present - present a surface to the display surface + * + * @dev_priv: VMW DRM device + * @file_priv: Pointer to a drm file private structure + * @vfb: Used to pick which STDU(s) is affected + * @user_handle: user handle for the source surface + * @dest_x: top/left corner of the display area to blit to + * @dest_y: top/left corner of the display area to blit to + * @clip_rects: array of dirty rectanges + * @num_of_clip_rects: number of rectanges in @clips + * + * This function copies a surface onto the display surface, and + * updates the screen target. Strech blit is currently not + * supported. + * + * RETURNS: + * 0 on success, error code otherwise + */ +int vmw_kms_stdu_present(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + uint32_t user_handle, + int32_t dest_x, int32_t dest_y, + struct drm_vmw_rect *clip_rects, + uint32_t num_of_clip_rects) +{ + struct vmw_screen_target_display_unit *stdu[VMWGFX_NUM_DISPLAY_UNITS]; + struct drm_clip_rect *update_area; + struct drm_crtc *crtc; + size_t fifo_size; + int num_of_du = 0, cur_du, i; + int ret = 0; + struct vmw_clip_rect src_bb; + + struct { + SVGA3dCmdHeader header; + SVGA3dCmdSurfaceCopy body; + } *cmd; + SVGA3dCopyBox *blits; + + + BUG_ON(!clip_rects || !num_of_clip_rects); + + list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { + if (crtc->primary->fb != &vfb->base) + continue; + + stdu[num_of_du++] = vmw_crtc_to_stdu(crtc); + } + + + update_area = kcalloc(num_of_clip_rects, sizeof(*update_area), + GFP_KERNEL); + if (unlikely(update_area == NULL)) { + DRM_ERROR("Temporary clip rect memory alloc failed.\n"); + return -ENOMEM; + } + + + fifo_size = sizeof(*cmd) + sizeof(SVGA3dCopyBox) * num_of_clip_rects; + + cmd = kmalloc(fifo_size, GFP_KERNEL); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed to allocate memory for surface copy.\n"); + ret = -ENOMEM; + goto out_free_update_area; + } + + memset(cmd, 0, fifo_size); + cmd->header.id = SVGA_3D_CMD_SURFACE_COPY; + + blits = (SVGA3dCopyBox *)&cmd[1]; + + + /* Figure out the source bounding box */ + src_bb.x1 = clip_rects->x; + src_bb.y1 = clip_rects->y; + src_bb.x2 = clip_rects->x + clip_rects->w; + src_bb.y2 = clip_rects->y + clip_rects->h; + + for (i = 1; i < num_of_clip_rects; i++) { + src_bb.x1 = min_t(int, src_bb.x1, clip_rects[i].x); + src_bb.x2 = max_t(int, src_bb.x2, + clip_rects[i].x + (int) clip_rects[i].w); + src_bb.y1 = min_t(int, src_bb.y1, clip_rects[i].y); + src_bb.y2 = max_t(int, src_bb.y2, + clip_rects[i].y + (int) clip_rects[i].h); + } + + for (i = 0; i < num_of_clip_rects; i++) { + update_area[i].x1 = clip_rects[i].x - src_bb.x1; + update_area[i].x2 = update_area[i].x1 + clip_rects[i].w; + update_area[i].y1 = clip_rects[i].y - src_bb.y1; + update_area[i].y2 = update_area[i].y1 + clip_rects[i].h; + } + + + for (cur_du = 0; cur_du < num_of_du; cur_du++) { + struct vmw_clip_rect dest_bb; + int num_of_blits; + + crtc = &stdu[cur_du]->base.crtc; + + dest_bb.x1 = src_bb.x1 + dest_x - crtc->x; + dest_bb.y1 = src_bb.y1 + dest_y - crtc->y; + dest_bb.x2 = src_bb.x2 + dest_x - crtc->x; + dest_bb.y2 = src_bb.y2 + dest_y - crtc->y; + + /* Skip any STDU outside of the destination bounding box */ + if (dest_bb.x1 >= crtc->mode.hdisplay || + dest_bb.y1 >= crtc->mode.vdisplay || + dest_bb.x2 <= 0 || dest_bb.y2 <= 0) + continue; + + /* Normalize to top-left of src bounding box in dest coord */ + dest_bb.x2 = crtc->mode.hdisplay - dest_bb.x1; + dest_bb.y2 = crtc->mode.vdisplay - dest_bb.y1; + dest_bb.x1 = 0 - dest_bb.x1; + dest_bb.y1 = 0 - dest_bb.y1; + + for (i = 0, num_of_blits = 0; i < num_of_clip_rects; i++) { + int x1 = max_t(int, dest_bb.x1, (int)update_area[i].x1); + int y1 = max_t(int, dest_bb.y1, (int)update_area[i].y1); + int x2 = min_t(int, dest_bb.x2, (int)update_area[i].x2); + int y2 = min_t(int, dest_bb.y2, (int)update_area[i].y2); + + if (x1 >= x2) + continue; + + if (y1 >= y2) + continue; + + blits[num_of_blits].srcx = src_bb.x1 + x1; + blits[num_of_blits].srcy = src_bb.y1 + y1; + blits[num_of_blits].x = -dest_bb.x1 + x1; + blits[num_of_blits].y = -dest_bb.y1 + y1; + blits[num_of_blits].d = 1; + blits[num_of_blits].w = x2 - x1; + blits[num_of_blits].h = y2 - y1; + num_of_blits++; + } + + if (num_of_blits == 0) + continue; + + /* Calculate new command size */ + fifo_size = sizeof(*cmd) + sizeof(SVGA3dCopyBox) * num_of_blits; + + cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); + + cmd->body.src.sid = user_handle; + cmd->body.dest.sid = stdu[cur_du]->display_srf->res.id; + + ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, + fifo_size, 0, VMW_QUIRK_SCREENTARGET, + NULL, NULL); + + if (unlikely(ret != 0)) + break; + + for (i = 0; i < num_of_blits; i++) { + struct drm_clip_rect blit_area; + + /* + * Add crtc offset because vmw_stdu_update_st expects + * desktop coordinates + */ + blit_area.x1 = blits[i].x + crtc->x; + blit_area.x2 = blit_area.x1 + blits[i].w; + blit_area.y1 = blits[i].y + crtc->y; + blit_area.y2 = blit_area.y1 + blits[i].h; + (void) vmw_stdu_update_st(dev_priv, NULL, stdu[cur_du], + &blit_area); + } + } + + kfree(cmd); + +out_free_update_area: + kfree(update_area); + + return ret; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index fb54ccd4e87d..835f3431574f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -1486,6 +1486,10 @@ int vmw_surface_gb_priv_define(struct drm_device *dev, srf->mip_levels[0], srf->flags & SVGA3D_SURFACE_CUBEMAP); + if (dev_priv->active_display_unit == vmw_du_screen_target && + for_scanout) + srf->flags |= SVGA3D_SURFACE_SCREENTARGET; + /* * From this point, the generic resource management functions * destroy the object on failure. diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index c472bedbe38e..c8a863180174 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -88,6 +88,7 @@ #define DRM_VMW_PARAM_3D_CAPS_SIZE 8 #define DRM_VMW_PARAM_MAX_MOB_MEMORY 9 #define DRM_VMW_PARAM_MAX_MOB_SIZE 10 +#define DRM_VMW_PARAM_SCREEN_TARGET 11 /** * enum drm_vmw_handle_type - handle type for ref ioctls -- cgit v1.3-6-gb490 From f89c6c321c4a7c0188922f331b70d83af01ab53e Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Fri, 26 Jun 2015 01:54:28 -0700 Subject: drm/vmwgfx: Replace SurfaceDMA usage with SurfaceCopy in 2D VMs This patch address the following underlying issues with SurfaceDMA * SurfaceDMA command does not work in a 2D VM, but we can wrap a proxy surface around the same DMA buffer and use the SurfaceCopy command which does work in a 2D VM. * Wrapping a DMA buffer with a proxy surface also gives us an added optimization path for the case when the DMA buf dimensions match the mode. In this case, the DMA buf can be pinned as the display surface, saving an extra copy. This only works in a 2D VM because we won't be doing any rendering operations directly to the display surface. v2 * Moved is_dmabuf_proxy field to vmw_framebuffer_surface * Undone coding style changes * Addressed other issues from review Signed-off-by: Sinclair Yeh Reviewed-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 3 +- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 20 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 107 ++++++++++++++++++-- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 1 + drivers/gpu/drm/vmwgfx/vmwgfx_mob.c | 3 +- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 165 +++++++++++++++++++++++++++---- 7 files changed, 266 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 04f8bf21557f..5d04859a472d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -342,7 +342,8 @@ enum vmw_display_unit_type { }; -#define VMW_QUIRK_SCREENTARGET (1U << 0) +#define VMW_QUIRK_DST_SID_OK (1U << 0) +#define VMW_QUIRK_SRC_SID_OK (1U << 1) struct vmw_sw_context{ struct drm_open_hash res_ht; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 497ad6aecfbb..0ec5fd6c71f4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -674,13 +674,16 @@ static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv, int ret; cmd = container_of(header, struct vmw_sid_cmd, header); - ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, - user_surface_converter, - &cmd->body.src.sid, NULL); - if (unlikely(ret != 0)) - return ret; - if (sw_context->quirks & VMW_QUIRK_SCREENTARGET) + if (!(sw_context->quirks & VMW_QUIRK_SRC_SID_OK)) { + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.src.sid, NULL); + if (ret != 0) + return ret; + } + + if (sw_context->quirks & VMW_QUIRK_DST_SID_OK) return 0; return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, @@ -1264,7 +1267,7 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, if (unlikely(suffix->maximumOffset > bo_size)) suffix->maximumOffset = bo_size; - if (sw_context->quirks & VMW_QUIRK_SCREENTARGET) + if (sw_context->quirks & VMW_QUIRK_DST_SID_OK) goto out_no_surface; ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, @@ -1505,6 +1508,9 @@ static int vmw_cmd_update_gb_image(struct vmw_private *dev_priv, cmd = container_of(header, struct vmw_gb_surface_cmd, header); + if (sw_context->quirks & VMW_QUIRK_SRC_SID_OK) + return 0; + return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, &cmd->body.image.sid, NULL); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 6680aa67386f..615ff6cfc4f9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -487,7 +487,8 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, struct vmw_surface *surface, struct vmw_framebuffer **out, const struct drm_mode_fb_cmd - *mode_cmd) + *mode_cmd, + bool is_dmabuf_proxy) { struct drm_device *dev = dev_priv->dev; @@ -562,6 +563,7 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, vfbs->surface = surface; vfbs->base.user_handle = mode_cmd->handle; vfbs->master = drm_master_get(file_priv->master); + vfbs->is_dmabuf_proxy = is_dmabuf_proxy; mutex_lock(&vmaster->fb_surf_mutex); list_add_tail(&vfbs->head, &vmaster->fb_surf); @@ -699,6 +701,82 @@ static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb) return vmw_dmabuf_unpin(dev_priv, vfbd->buffer, false); } +/** + * vmw_create_dmabuf_proxy - create a proxy surface for the DMA buf + * + * @dev: DRM device + * @mode_cmd: parameters for the new surface + * @dmabuf_mob: MOB backing the DMA buf + * @srf_out: newly created surface + * + * When the content FB is a DMA buf, we create a surface as a proxy to the + * same buffer. This way we can do a surface copy rather than a surface DMA. + * This is a more efficient approach + * + * RETURNS: + * 0 on success, error code otherwise + */ +static int vmw_create_dmabuf_proxy(struct drm_device *dev, + struct drm_mode_fb_cmd *mode_cmd, + struct vmw_dma_buffer *dmabuf_mob, + struct vmw_surface **srf_out) +{ + uint32_t format; + struct drm_vmw_size content_base_size; + int ret; + + + switch (mode_cmd->depth) { + case 32: + case 24: + format = SVGA3D_X8R8G8B8; + break; + + case 16: + case 15: + format = SVGA3D_R5G6B5; + break; + + case 8: + format = SVGA3D_P8; + break; + + default: + DRM_ERROR("Invalid framebuffer format %d\n", mode_cmd->depth); + return -EINVAL; + } + + content_base_size.width = mode_cmd->width; + content_base_size.height = mode_cmd->height; + content_base_size.depth = 1; + + ret = vmw_surface_gb_priv_define(dev, + 0, /* kernel visible only */ + 0, /* flags */ + format, + true, /* can be a scanout buffer */ + 1, /* num of mip levels */ + 0, + content_base_size, + srf_out); + if (ret) { + DRM_ERROR("Failed to allocate proxy content buffer\n"); + return ret; + } + + /* Use the same MOB backing for surface */ + vmw_dmabuf_reference(dmabuf_mob); + + (*srf_out)->res.backup = dmabuf_mob; + + /* FIXME: Waiting for fbdev rework to do a proper reserve/pin */ + ret = vmw_resource_validate(&(*srf_out)->res); + + return ret; +} + + + static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, struct vmw_dma_buffer *dmabuf, struct vmw_framebuffer **out, @@ -801,6 +879,7 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, struct vmw_dma_buffer *bo = NULL; struct ttm_base_object *user_obj; struct drm_mode_fb_cmd mode_cmd; + bool is_dmabuf_proxy = false; int ret; mode_cmd.width = mode_cmd2->width; @@ -849,13 +928,29 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, if (ret) goto err_out; - /* Create the new framebuffer depending one what we got back */ - if (bo) + /* + * We cannot use the SurfaceDMA command in an non-accelerated VM, + * therefore, wrap the DMA buf in a surface so we can use the + * SurfaceCopy command. + */ + if (bo && !(dev_priv->capabilities & SVGA_CAP_3D) && + dev_priv->active_display_unit == vmw_du_screen_target) { + ret = vmw_create_dmabuf_proxy(dev_priv->dev, &mode_cmd, bo, + &surface); + if (ret) + goto err_out; + + is_dmabuf_proxy = true; + } + + /* Create the new framebuffer depending one what we have */ + if (surface) + ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, + surface, &vfb, &mode_cmd, + is_dmabuf_proxy); + else if (bo) ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, &mode_cmd); - else if (surface) - ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, - surface, &vfb, &mode_cmd); else BUG(); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 548fa872b39c..db8ae94c403c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -72,6 +72,7 @@ struct vmw_framebuffer_surface { struct vmw_dma_buffer *buffer; struct list_head head; struct drm_master *master; + bool is_dmabuf_proxy; /* true if this is proxy surface for DMA buf */ }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index 0feac5675c51..e0fc2485ddb1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -31,8 +31,7 @@ * If we set up the screen target otable, screen objects stop working. */ -#define VMW_OTABLE_SETUP_SUB ((VMWGFX_ENABLE_SCREEN_TARGET_OTABLE && \ - (dev_priv->capabilities & SVGA_CAP_3D)) ? 0 : 1) +#define VMW_OTABLE_SETUP_SUB ((VMWGFX_ENABLE_SCREEN_TARGET_OTABLE ? 0 : 1)) #ifdef CONFIG_64BIT #define VMW_PPN_SIZE 8 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 6738c1ebf09a..9dcbe8ba08ea 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -497,7 +497,7 @@ int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv, ret = vmw_dmabuf_init(dev_priv, &user_bo->dma, size, (dev_priv->has_mob) ? - &vmw_sys_placement : + &vmw_mob_placement : &vmw_vram_sys_placement, true, &vmw_user_dmabuf_destroy); if (unlikely(ret != 0)) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 3b8235c7ee42..ef99df7463f3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -141,6 +141,63 @@ static void vmw_stdu_crtc_destroy(struct drm_crtc *crtc) +/** + * vmw_stdu_dma_update - Update DMA buf dirty region on the SVGA device + * + * @dev_priv: VMW DRM device + * @file_priv: Pointer to a drm file private structure + * @vfbs: VMW framebuffer surface that may need a DMA buf update + * @x: top/left corner of the content area to blit from + * @y: top/left corner of the content area to blit from + * @width: width of the blit area + * @height: height of the blit area + * + * The SVGA device may have the DMA buf cached, so before letting the + * device use it as the source image for a subsequent operation, we + * update the cached copy. + * + * RETURNs: + * 0 on success, error code on failure + */ +static int vmw_stdu_dma_update(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer_surface *vfbs, + uint32_t x, uint32_t y, + uint32_t width, uint32_t height) +{ + size_t fifo_size; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdUpdateGBImage body; + } img_update_cmd; + + + /* Only need to do this if the surface is a DMA buf proxy */ + if (!vfbs->is_dmabuf_proxy) + return 0; + + fifo_size = sizeof(img_update_cmd); + + memset(&img_update_cmd, 0, fifo_size); + img_update_cmd.header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; + img_update_cmd.header.size = sizeof(img_update_cmd.body); + + img_update_cmd.body.image.sid = vfbs->surface->res.id; + + img_update_cmd.body.box.x = x; + img_update_cmd.body.box.y = y; + img_update_cmd.body.box.w = width; + img_update_cmd.body.box.h = height; + img_update_cmd.body.box.d = 1; + + return vmw_execbuf_process(file_priv, dev_priv, NULL, + (void *) &img_update_cmd, + fifo_size, 0, VMW_QUIRK_SRC_SID_OK, + NULL, NULL); +} + + + /** * vmw_stdu_content_copy - copies an area from the content to display surface * @@ -166,11 +223,13 @@ static int vmw_stdu_content_copy(struct vmw_private *dev_priv, uint32_t width, uint32_t height, uint32_t display_x, uint32_t display_y) { - size_t fifo_size; + struct vmw_framebuffer_surface *content_vfbs; + size_t fifo_size; int ret; void *cmd; + u32 quirks = VMW_QUIRK_DST_SID_OK; - struct vmw_surface_dma { + struct { SVGA3dCmdHeader header; SVGA3dCmdSurfaceDMA body; SVGA3dCopyBox area; @@ -193,24 +252,43 @@ static int vmw_stdu_content_copy(struct vmw_private *dev_priv, return -EINVAL; } + if (stdu->content_fb_type == SEPARATE_DMA) { struct vmw_framebuffer *content_vfb; - struct vmw_framebuffer_dmabuf *content_vfbd; - struct vmw_framebuffer_surface *content_vfbs; struct drm_vmw_size cur_size = {0}; const struct svga3d_surface_desc *desc; + enum SVGA3dSurfaceFormat format; SVGA3dCmdSurfaceDMASuffix *suffix; SVGAGuestPtr ptr; + content_vfb = vmw_framebuffer_to_vfb(stdu->content_fb); - content_vfbd = vmw_framebuffer_to_vfbd(stdu->content_fb); - content_vfbs = vmw_framebuffer_to_vfbs(stdu->content_fb); cur_size.width = width; cur_size.height = height; cur_size.depth = 1; - desc = svga3dsurface_get_desc(content_vfbs->surface->format); + /* Derive a SVGA3dSurfaceFormat for the DMA buf */ + switch (content_vfb->base.bits_per_pixel) { + case 32: + format = SVGA3D_A8R8G8B8; + break; + case 24: + format = SVGA3D_X8R8G8B8; + break; + case 16: + format = SVGA3D_R5G6B5; + break; + case 15: + format = SVGA3D_A1R5G5B5; + break; + default: + DRM_ERROR("Invalid color depth: %d\n", + content_vfb->base.depth); + return -EINVAL; + } + + desc = svga3dsurface_get_desc(format); fifo_size = sizeof(surface_dma_cmd); @@ -250,19 +328,40 @@ static int vmw_stdu_content_copy(struct vmw_private *dev_priv, cmd = (void *) &surface_dma_cmd; } else { - struct vmw_framebuffer *content_vfb; + u32 src_id; + + + content_vfbs = vmw_framebuffer_to_vfbs(stdu->content_fb); + + if (content_vfbs->is_dmabuf_proxy) { + ret = vmw_stdu_dma_update(dev_priv, file_priv, + content_vfbs, + content_x, content_y, + width, height); + + if (ret != 0) { + DRM_ERROR("Failed to update cached DMA buf\n"); + return ret; + } - content_vfb = vmw_framebuffer_to_vfb(stdu->content_fb); + quirks |= VMW_QUIRK_SRC_SID_OK; + src_id = content_vfbs->surface->res.id; + } else { + struct vmw_framebuffer *content_vfb; + content_vfb = vmw_framebuffer_to_vfb(stdu->content_fb); + src_id = content_vfb->user_handle; + } + fifo_size = sizeof(surface_cpy_cmd); - memset(&surface_cpy_cmd, 0, sizeof(surface_cpy_cmd)); + memset(&surface_cpy_cmd, 0, fifo_size); surface_cpy_cmd.header.id = SVGA_3D_CMD_SURFACE_COPY; surface_cpy_cmd.header.size = sizeof(surface_cpy_cmd.body) + sizeof(surface_cpy_cmd.area); - surface_cpy_cmd.body.src.sid = content_vfb->user_handle; + surface_cpy_cmd.body.src.sid = src_id; surface_cpy_cmd.body.dest.sid = stdu->display_srf->res.id; surface_cpy_cmd.area.srcx = content_x; @@ -276,8 +375,11 @@ static int vmw_stdu_content_copy(struct vmw_private *dev_priv, cmd = (void *) &surface_cpy_cmd; } - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, - fifo_size, 0, VMW_QUIRK_SCREENTARGET, + + + ret = vmw_execbuf_process(file_priv, dev_priv, NULL, + (void *) cmd, + fifo_size, 0, quirks, NULL, NULL); return ret; @@ -391,7 +493,8 @@ static int vmw_stdu_bind_st(struct vmw_private *dev_priv, * vmw_stdu_update_st - Updates a Screen Target * * @dev_priv: VMW DRM device - * @file_priv: Pointer to a drm file private structure + * @file_priv: Pointer to DRM file private structure. Set to NULL when + * we want to blank display. * @stdu: display unit affected * @update_area: area that needs to be updated * @@ -412,6 +515,7 @@ static int vmw_stdu_update_st(struct vmw_private *dev_priv, u32 width, height; u32 display_update_x, display_update_y; unsigned short display_x1, display_y1, display_x2, display_y2; + int ret; struct { SVGA3dCmdHeader header; @@ -444,8 +548,11 @@ static int vmw_stdu_update_st(struct vmw_private *dev_priv, height = min(update_area->y2, display_y2) - max(update_area->y1, display_y1); + /* + * If content is on a separate surface, then copy the dirty area to + * the display surface + */ if (file_priv && stdu->content_fb_type != SAME_AS_DISPLAY) { - int ret; ret = vmw_stdu_content_copy(dev_priv, file_priv, stdu, @@ -459,6 +566,29 @@ static int vmw_stdu_update_st(struct vmw_private *dev_priv, } } + + /* + * If the display surface is the same as the content surface, then + * it may be backed by a DMA buf. If it is then we need to update + * the device's cached copy of the DMA buf before issuing the screen + * target update. + */ + if (file_priv && stdu->content_fb_type == SAME_AS_DISPLAY) { + struct vmw_framebuffer_surface *vfbs; + + vfbs = vmw_framebuffer_to_vfbs(stdu->content_fb); + ret = vmw_stdu_dma_update(dev_priv, file_priv, + vfbs, + max(update_area->x1, display_x1), + max(update_area->y1, display_y1), + width, height); + + if (ret != 0) { + DRM_ERROR("Failed to update cached DMA buffer\n"); + return ret; + } + } + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); if (unlikely(cmd == NULL)) { @@ -1066,8 +1196,7 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) if (!VMWGFX_ENABLE_SCREEN_TARGET_OTABLE) return -ENOSYS; - if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS) || - !(dev_priv->capabilities & SVGA_CAP_3D)) + if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) return -ENOSYS; ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); @@ -1333,7 +1462,7 @@ int vmw_kms_stdu_present(struct vmw_private *dev_priv, cmd->body.dest.sid = stdu[cur_du]->display_srf->res.id; ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, - fifo_size, 0, VMW_QUIRK_SCREENTARGET, + fifo_size, 0, VMW_QUIRK_DST_SID_OK, NULL, NULL); if (unlikely(ret != 0)) -- cgit v1.3-6-gb490 From 459d0fa7359654e5e076e84fc58512f00f70fee9 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 26 Jun 2015 00:25:37 -0700 Subject: drm/vmwgfx: Introduce a pin count to allow for recursive pinning v2 v2: Fix dma buffer validation on resource pinning. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c | 182 ++++++++++++++----------------- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 31 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 33 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 81 +++++++------- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c | 4 +- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 36 +++--- 9 files changed, 179 insertions(+), 196 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c index 914b375763dc..4b9344dd6c27 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c @@ -32,25 +32,20 @@ /** - * vmw_dmabuf_to_placement - Validate a buffer to placement. + * vmw_dmabuf_pin_in_placement - Validate a buffer to placement. * * @dev_priv: Driver private. * @buf: DMA buffer to move. - * @pin: Pin buffer if true. + * @placement: The placement to pin it. * @interruptible: Use interruptible wait. * - * May only be called by the current master since it assumes that the - * master lock is the current master's lock. - * This function takes the master's lock in write mode. - * Flushes and unpins the query bo to avoid failures. - * * Returns * -ERESTARTSYS if interrupted by a signal. */ -int vmw_dmabuf_to_placement(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - struct ttm_placement *placement, - bool interruptible) +int vmw_dmabuf_pin_in_placement(struct vmw_private *dev_priv, + struct vmw_dma_buffer *buf, + struct ttm_placement *placement, + bool interruptible) { struct ttm_buffer_object *bo = &buf->base; int ret; @@ -66,6 +61,8 @@ int vmw_dmabuf_to_placement(struct vmw_private *dev_priv, goto err; ret = ttm_bo_validate(bo, placement, interruptible, false); + if (!ret) + vmw_bo_pin_reserved(buf, true); ttm_bo_unreserve(bo); @@ -75,12 +72,10 @@ err: } /** - * vmw_dmabuf_to_vram_or_gmr - Move a buffer to vram or gmr. + * vmw_dmabuf_pin_in_vram_or_gmr - Move a buffer to vram or gmr. * - * May only be called by the current master since it assumes that the - * master lock is the current master's lock. - * This function takes the master's lock in write mode. - * Flushes and unpins the query bo if @pin == true to avoid failures. + * This function takes the reservation_sem in write mode. + * Flushes and unpins the query bo to avoid failures. * * @dev_priv: Driver private. * @buf: DMA buffer to move. @@ -90,55 +85,34 @@ err: * Returns * -ERESTARTSYS if interrupted by a signal. */ -int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool pin, bool interruptible) +int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv, + struct vmw_dma_buffer *buf, + bool interruptible) { struct ttm_buffer_object *bo = &buf->base; - struct ttm_placement *placement; int ret; ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); if (unlikely(ret != 0)) return ret; - if (pin) - vmw_execbuf_release_pinned_bo(dev_priv); + vmw_execbuf_release_pinned_bo(dev_priv); ret = ttm_bo_reserve(bo, interruptible, false, false, NULL); if (unlikely(ret != 0)) goto err; - /** - * Put BO in VRAM if there is space, otherwise as a GMR. - * If there is no space in VRAM and GMR ids are all used up, - * start evicting GMRs to make room. If the DMA buffer can't be - * used as a GMR, this will return -ENOMEM. - */ - - if (pin) - placement = &vmw_vram_gmr_ne_placement; - else - placement = &vmw_vram_gmr_placement; - - ret = ttm_bo_validate(bo, placement, interruptible, false); + ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, interruptible, + false); if (likely(ret == 0) || ret == -ERESTARTSYS) - goto err_unreserve; - + goto out_unreserve; - /** - * If that failed, try VRAM again, this time evicting - * previous contents. - */ - - if (pin) - placement = &vmw_vram_ne_placement; - else - placement = &vmw_vram_placement; + ret = ttm_bo_validate(bo, &vmw_vram_placement, interruptible, false); - ret = ttm_bo_validate(bo, placement, interruptible, false); +out_unreserve: + if (!ret) + vmw_bo_pin_reserved(buf, true); -err_unreserve: ttm_bo_unreserve(bo); err: ttm_write_unlock(&dev_priv->reservation_sem); @@ -146,67 +120,50 @@ err: } /** - * vmw_dmabuf_to_vram - Move a buffer to vram. + * vmw_dmabuf_pin_in_vram - Move a buffer to vram. * - * May only be called by the current master since it assumes that the - * master lock is the current master's lock. - * This function takes the master's lock in write mode. + * This function takes the reservation_sem in write mode. + * Flushes and unpins the query bo to avoid failures. * * @dev_priv: Driver private. * @buf: DMA buffer to move. - * @pin: Pin buffer in vram if true. * @interruptible: Use interruptible wait. * * Returns * -ERESTARTSYS if interrupted by a signal. */ -int vmw_dmabuf_to_vram(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool pin, bool interruptible) +int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, + struct vmw_dma_buffer *buf, + bool interruptible) { - struct ttm_placement *placement; - - if (pin) - placement = &vmw_vram_ne_placement; - else - placement = &vmw_vram_placement; - - return vmw_dmabuf_to_placement(dev_priv, buf, - placement, - interruptible); + return vmw_dmabuf_pin_in_placement(dev_priv, buf, &vmw_vram_placement, + interruptible); } /** - * vmw_dmabuf_to_start_of_vram - Move a buffer to start of vram. + * vmw_dmabuf_pin_in_start_of_vram - Move a buffer to start of vram. * - * May only be called by the current master since it assumes that the - * master lock is the current master's lock. - * This function takes the master's lock in write mode. - * Flushes and unpins the query bo if @pin == true to avoid failures. + * This function takes the reservation_sem in write mode. + * Flushes and unpins the query bo to avoid failures. * * @dev_priv: Driver private. - * @buf: DMA buffer to move. - * @pin: Pin buffer in vram if true. + * @buf: DMA buffer to pin. * @interruptible: Use interruptible wait. * * Returns * -ERESTARTSYS if interrupted by a signal. */ -int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool pin, bool interruptible) +int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *dev_priv, + struct vmw_dma_buffer *buf, + bool interruptible) { struct ttm_buffer_object *bo = &buf->base; struct ttm_placement placement; struct ttm_place place; int ret = 0; - if (pin) - place = vmw_vram_ne_placement.placement[0]; - else - place = vmw_vram_placement.placement[0]; + place = vmw_vram_placement.placement[0]; place.lpfn = bo->num_pages; - placement.num_placement = 1; placement.placement = &place; placement.num_busy_placement = 1; @@ -216,13 +173,16 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv, if (unlikely(ret != 0)) return ret; - if (pin) - vmw_execbuf_release_pinned_bo(dev_priv); + vmw_execbuf_release_pinned_bo(dev_priv); ret = ttm_bo_reserve(bo, interruptible, false, false, NULL); if (unlikely(ret != 0)) goto err_unlock; - /* Is this buffer already in vram but not at the start of it? */ + /* + * Is this buffer already in vram but not at the start of it? + * In that case, evict it first because TTM isn't good at handling + * that situation. + */ if (bo->mem.mem_type == TTM_PL_VRAM && bo->mem.start < bo->num_pages && bo->mem.start > 0) @@ -230,8 +190,10 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv, ret = ttm_bo_validate(bo, &placement, interruptible, false); - /* For some reason we didn't up at the start of vram */ + /* For some reason we didn't end up at the start of vram */ WARN_ON(ret == 0 && bo->offset != 0); + if (!ret) + vmw_bo_pin_reserved(buf, true); ttm_bo_unreserve(bo); err_unlock: @@ -240,13 +202,10 @@ err_unlock: return ret; } - /** - * vmw_dmabuf_upin - Unpin the buffer given buffer, does not move the buffer. + * vmw_dmabuf_unpin - Unpin the buffer given buffer, does not move the buffer. * - * May only be called by the current master since it assumes that the - * master lock is the current master's lock. - * This function takes the master's lock in write mode. + * This function takes the reservation_sem in write mode. * * @dev_priv: Driver private. * @buf: DMA buffer to unpin. @@ -259,16 +218,25 @@ int vmw_dmabuf_unpin(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, bool interruptible) { - /* - * We could in theory early out if the buffer is - * unpinned but we need to lock and reserve the buffer - * anyways so we don't gain much by that. - */ - return vmw_dmabuf_to_placement(dev_priv, buf, - &vmw_evictable_placement, - interruptible); -} + struct ttm_buffer_object *bo = &buf->base; + int ret; + ret = ttm_read_lock(&dev_priv->reservation_sem, interruptible); + if (unlikely(ret != 0)) + return ret; + + ret = ttm_bo_reserve(bo, interruptible, false, false, 0); + if (unlikely(ret != 0)) + goto err; + + vmw_bo_pin_reserved(buf, false); + + ttm_bo_unreserve(bo); + +err: + ttm_read_unlock(&dev_priv->reservation_sem); + return ret; +} /** * vmw_bo_get_guest_ptr - Get the guest ptr representing the current placement @@ -291,21 +259,31 @@ void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *bo, /** - * vmw_bo_pin - Pin or unpin a buffer object without moving it. + * vmw_bo_pin_reserved - Pin or unpin a buffer object without moving it. * - * @bo: The buffer object. Must be reserved. + * @vbo: The buffer object. Must be reserved. * @pin: Whether to pin or unpin. * */ -void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin) +void vmw_bo_pin_reserved(struct vmw_dma_buffer *vbo, bool pin) { struct ttm_place pl; struct ttm_placement placement; + struct ttm_buffer_object *bo = &vbo->base; uint32_t old_mem_type = bo->mem.mem_type; int ret; lockdep_assert_held(&bo->resv->lock.base); + if (pin) { + if (vbo->pin_count++ > 0) + return; + } else { + WARN_ON(vbo->pin_count <= 0); + if (--vbo->pin_count > 0) + return; + } + pl.fpfn = 0; pl.lpfn = 0; pl.flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index ab1b70ce19c1..e55db3fdf601 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -298,30 +298,31 @@ static void vmw_print_capabilities(uint32_t capabilities) static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) { int ret; - struct ttm_buffer_object *bo; + struct vmw_dma_buffer *vbo; struct ttm_bo_kmap_obj map; volatile SVGA3dQueryResult *result; bool dummy; /* - * Create the bo as pinned, so that a tryreserve will + * Create the vbo as pinned, so that a tryreserve will * immediately succeed. This is because we're the only * user of the bo currently. */ - ret = ttm_bo_create(&dev_priv->bdev, - PAGE_SIZE, - ttm_bo_type_device, - &vmw_sys_ne_placement, - 0, false, NULL, - &bo); + vbo = kzalloc(sizeof(*vbo), GFP_KERNEL); + if (!vbo) + return -ENOMEM; + ret = vmw_dmabuf_init(dev_priv, vbo, PAGE_SIZE, + &vmw_sys_ne_placement, false, + &vmw_dmabuf_bo_free); if (unlikely(ret != 0)) return ret; - ret = ttm_bo_reserve(bo, false, true, false, NULL); + ret = ttm_bo_reserve(&vbo->base, false, true, false, NULL); BUG_ON(ret != 0); + vmw_bo_pin_reserved(vbo, true); - ret = ttm_bo_kmap(bo, 0, 1, &map); + ret = ttm_bo_kmap(&vbo->base, 0, 1, &map); if (likely(ret == 0)) { result = ttm_kmap_obj_virtual(&map, &dummy); result->totalSize = sizeof(*result); @@ -329,14 +330,14 @@ static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv) result->result32 = 0xff; ttm_bo_kunmap(&map); } - vmw_bo_pin(bo, false); - ttm_bo_unreserve(bo); + vmw_bo_pin_reserved(vbo, false); + ttm_bo_unreserve(&vbo->base); if (unlikely(ret != 0)) { DRM_ERROR("Dummy query buffer map failed.\n"); - ttm_bo_unref(&bo); + vmw_dmabuf_unreference(&vbo); } else - dev_priv->dummy_query_bo = bo; + dev_priv->dummy_query_bo = vbo; return ret; } @@ -434,7 +435,7 @@ static void vmw_release_device_early(struct vmw_private *dev_priv) BUG_ON(dev_priv->pinned_bo != NULL); - ttm_bo_unref(&dev_priv->dummy_query_bo); + vmw_dmabuf_unreference(&dev_priv->dummy_query_bo); if (dev_priv->cman) vmw_cmdbuf_remove_pool(dev_priv->cman); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 5d04859a472d..12eaa6c805d8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -85,6 +85,7 @@ struct vmw_fpriv { struct vmw_dma_buffer { struct ttm_buffer_object base; struct list_head res_list; + s32 pin_count; }; /** @@ -358,7 +359,7 @@ struct vmw_sw_context{ uint32_t *cmd_bounce; uint32_t cmd_bounce_size; struct list_head resource_list; - struct ttm_buffer_object *cur_query_bo; + struct vmw_dma_buffer *cur_query_bo; struct list_head res_relocations; uint32_t *buf_start; struct vmw_res_cache_entry res_cache[vmw_res_max]; @@ -533,8 +534,8 @@ struct vmw_private { * are protected by the cmdbuf mutex. */ - struct ttm_buffer_object *dummy_query_bo; - struct ttm_buffer_object *pinned_bo; + struct vmw_dma_buffer *dummy_query_bo; + struct vmw_dma_buffer *pinned_bo; uint32_t query_cid; uint32_t query_cid_valid; bool dummy_query_bo_pinned; @@ -700,25 +701,25 @@ extern void vmw_resource_evict_all(struct vmw_private *dev_priv); /** * DMA buffer helper routines - vmwgfx_dmabuf.c */ -extern int vmw_dmabuf_to_placement(struct vmw_private *vmw_priv, - struct vmw_dma_buffer *bo, - struct ttm_placement *placement, - bool interruptible); -extern int vmw_dmabuf_to_vram(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool pin, bool interruptible); -extern int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buf, - bool pin, bool interruptible); -extern int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv, +extern int vmw_dmabuf_pin_in_placement(struct vmw_private *vmw_priv, struct vmw_dma_buffer *bo, - bool pin, bool interruptible); + struct ttm_placement *placement, + bool interruptible); +extern int vmw_dmabuf_pin_in_vram(struct vmw_private *dev_priv, + struct vmw_dma_buffer *buf, + bool interruptible); +extern int vmw_dmabuf_pin_in_vram_or_gmr(struct vmw_private *dev_priv, + struct vmw_dma_buffer *buf, + bool interruptible); +extern int vmw_dmabuf_pin_in_start_of_vram(struct vmw_private *vmw_priv, + struct vmw_dma_buffer *bo, + bool interruptible); extern int vmw_dmabuf_unpin(struct vmw_private *vmw_priv, struct vmw_dma_buffer *bo, bool interruptible); extern void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *buf, SVGAGuestPtr *ptr); -extern void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin); +extern void vmw_bo_pin_reserved(struct vmw_dma_buffer *bo, bool pin); /** * Misc Ioctl functionality - vmwgfx_ioctl.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 0ec5fd6c71f4..92e89987b0d7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -308,7 +308,7 @@ static int vmw_cmd_ok(struct vmw_private *dev_priv, * submission is reached. */ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, - struct ttm_buffer_object *bo, + struct vmw_dma_buffer *vbo, bool validate_as_mob, uint32_t *p_val_node) { @@ -318,7 +318,7 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, struct drm_hash_item *hash; int ret; - if (likely(drm_ht_find_item(&sw_context->res_ht, (unsigned long) bo, + if (likely(drm_ht_find_item(&sw_context->res_ht, (unsigned long) vbo, &hash) == 0)) { vval_buf = container_of(hash, struct vmw_validate_buffer, hash); @@ -336,7 +336,7 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, return -EINVAL; } vval_buf = &sw_context->val_bufs[val_node]; - vval_buf->hash.key = (unsigned long) bo; + vval_buf->hash.key = (unsigned long) vbo; ret = drm_ht_insert_item(&sw_context->res_ht, &vval_buf->hash); if (unlikely(ret != 0)) { DRM_ERROR("Failed to initialize a buffer validation " @@ -345,7 +345,7 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context, } ++sw_context->cur_val_buf; val_buf = &vval_buf->base; - val_buf->bo = ttm_bo_reference(bo); + val_buf->bo = ttm_bo_reference(&vbo->base); val_buf->shared = false; list_add_tail(&val_buf->head, &sw_context->validate_nodes); vval_buf->validate_as_mob = validate_as_mob; @@ -380,10 +380,10 @@ static int vmw_resources_reserve(struct vmw_sw_context *sw_context) return ret; if (res->backup) { - struct ttm_buffer_object *bo = &res->backup->base; + struct vmw_dma_buffer *vbo = res->backup; ret = vmw_bo_to_validate_list - (sw_context, bo, + (sw_context, vbo, vmw_resource_needs_backup(res), NULL); if (unlikely(ret != 0)) @@ -759,7 +759,7 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv, * command batch. */ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv, - struct ttm_buffer_object *new_query_bo, + struct vmw_dma_buffer *new_query_bo, struct vmw_sw_context *sw_context) { struct vmw_res_cache_entry *ctx_entry = @@ -771,7 +771,7 @@ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv, if (unlikely(new_query_bo != sw_context->cur_query_bo)) { - if (unlikely(new_query_bo->num_pages > 4)) { + if (unlikely(new_query_bo->base.num_pages > 4)) { DRM_ERROR("Query buffer too large.\n"); return -EINVAL; } @@ -840,12 +840,12 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv, if (dev_priv->pinned_bo != sw_context->cur_query_bo) { if (dev_priv->pinned_bo) { - vmw_bo_pin(dev_priv->pinned_bo, false); - ttm_bo_unref(&dev_priv->pinned_bo); + vmw_bo_pin_reserved(dev_priv->pinned_bo, false); + vmw_dmabuf_unreference(&dev_priv->pinned_bo); } if (!sw_context->needs_post_query_barrier) { - vmw_bo_pin(sw_context->cur_query_bo, true); + vmw_bo_pin_reserved(sw_context->cur_query_bo, true); /* * We pin also the dummy_query_bo buffer so that we @@ -853,14 +853,17 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv, * dummy queries in context destroy paths. */ - vmw_bo_pin(dev_priv->dummy_query_bo, true); - dev_priv->dummy_query_bo_pinned = true; + if (!dev_priv->dummy_query_bo_pinned) { + vmw_bo_pin_reserved(dev_priv->dummy_query_bo, + true); + dev_priv->dummy_query_bo_pinned = true; + } BUG_ON(sw_context->last_query_ctx == NULL); dev_priv->query_cid = sw_context->last_query_ctx->id; dev_priv->query_cid_valid = true; dev_priv->pinned_bo = - ttm_bo_reference(sw_context->cur_query_bo); + vmw_dmabuf_reference(sw_context->cur_query_bo); } } } @@ -889,7 +892,6 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, struct vmw_dma_buffer **vmw_bo_p) { struct vmw_dma_buffer *vmw_bo = NULL; - struct ttm_buffer_object *bo; uint32_t handle = *id; struct vmw_relocation *reloc; int ret; @@ -900,7 +902,6 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, ret = -EINVAL; goto out_no_reloc; } - bo = &vmw_bo->base; if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) { DRM_ERROR("Max number relocations per submission" @@ -913,7 +914,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv, reloc->mob_loc = id; reloc->location = NULL; - ret = vmw_bo_to_validate_list(sw_context, bo, true, &reloc->index); + ret = vmw_bo_to_validate_list(sw_context, vmw_bo, true, &reloc->index); if (unlikely(ret != 0)) goto out_no_reloc; @@ -951,7 +952,6 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, struct vmw_dma_buffer **vmw_bo_p) { struct vmw_dma_buffer *vmw_bo = NULL; - struct ttm_buffer_object *bo; uint32_t handle = ptr->gmrId; struct vmw_relocation *reloc; int ret; @@ -962,7 +962,6 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, ret = -EINVAL; goto out_no_reloc; } - bo = &vmw_bo->base; if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) { DRM_ERROR("Max number relocations per submission" @@ -974,7 +973,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, reloc = &sw_context->relocs[sw_context->cur_reloc++]; reloc->location = ptr; - ret = vmw_bo_to_validate_list(sw_context, bo, false, &reloc->index); + ret = vmw_bo_to_validate_list(sw_context, vmw_bo, false, &reloc->index); if (unlikely(ret != 0)) goto out_no_reloc; @@ -1081,7 +1080,7 @@ static int vmw_cmd_end_gb_query(struct vmw_private *dev_priv, if (unlikely(ret != 0)) return ret; - ret = vmw_query_bo_switch_prepare(dev_priv, &vmw_bo->base, sw_context); + ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context); vmw_dmabuf_unreference(&vmw_bo); return ret; @@ -1135,7 +1134,7 @@ static int vmw_cmd_end_query(struct vmw_private *dev_priv, if (unlikely(ret != 0)) return ret; - ret = vmw_query_bo_switch_prepare(dev_priv, &vmw_bo->base, sw_context); + ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context); vmw_dmabuf_unreference(&vmw_bo); return ret; @@ -2239,16 +2238,11 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv, struct ttm_buffer_object *bo, bool validate_as_mob) { + struct vmw_dma_buffer *vbo = container_of(bo, struct vmw_dma_buffer, + base); int ret; - - /* - * Don't validate pinned buffers. - */ - - if (bo == dev_priv->pinned_bo || - (bo == dev_priv->dummy_query_bo && - dev_priv->dummy_query_bo_pinned)) + if (vbo->pin_count > 0) return 0; if (validate_as_mob) @@ -2767,9 +2761,11 @@ static void vmw_execbuf_unpin_panic(struct vmw_private *dev_priv) DRM_ERROR("Can't unpin query buffer. Trying to recover.\n"); (void) vmw_fallback_wait(dev_priv, false, true, 0, false, 10*HZ); - vmw_bo_pin(dev_priv->pinned_bo, false); - vmw_bo_pin(dev_priv->dummy_query_bo, false); - dev_priv->dummy_query_bo_pinned = false; + vmw_bo_pin_reserved(dev_priv->pinned_bo, false); + if (dev_priv->dummy_query_bo_pinned) { + vmw_bo_pin_reserved(dev_priv->dummy_query_bo, false); + dev_priv->dummy_query_bo_pinned = false; + } } @@ -2811,11 +2807,11 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv, INIT_LIST_HEAD(&validate_list); - pinned_val.bo = ttm_bo_reference(dev_priv->pinned_bo); + pinned_val.bo = ttm_bo_reference(&dev_priv->pinned_bo->base); pinned_val.shared = false; list_add_tail(&pinned_val.head, &validate_list); - query_val.bo = ttm_bo_reference(dev_priv->dummy_query_bo); + query_val.bo = ttm_bo_reference(&dev_priv->dummy_query_bo->base); query_val.shared = false; list_add_tail(&query_val.head, &validate_list); @@ -2836,10 +2832,11 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv, dev_priv->query_cid_valid = false; } - vmw_bo_pin(dev_priv->pinned_bo, false); - vmw_bo_pin(dev_priv->dummy_query_bo, false); - dev_priv->dummy_query_bo_pinned = false; - + vmw_bo_pin_reserved(dev_priv->pinned_bo, false); + if (dev_priv->dummy_query_bo_pinned) { + vmw_bo_pin_reserved(dev_priv->dummy_query_bo, false); + dev_priv->dummy_query_bo_pinned = false; + } if (fence == NULL) { (void) vmw_execbuf_fence_commands(NULL, dev_priv, &lfence, NULL); @@ -2851,7 +2848,9 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv, ttm_bo_unref(&query_val.bo); ttm_bo_unref(&pinned_val.bo); - ttm_bo_unref(&dev_priv->pinned_bo); + vmw_dmabuf_unreference(&dev_priv->pinned_bo); + DRM_INFO("Dummy query bo pin count: %d\n", + dev_priv->dummy_query_bo->pin_count); out_unlock: return; @@ -2861,7 +2860,7 @@ out_no_emit: out_no_reserve: ttm_bo_unref(&query_val.bo); ttm_bo_unref(&pinned_val.bo); - ttm_bo_unref(&dev_priv->pinned_bo); + vmw_dmabuf_unreference(&dev_priv->pinned_bo); } /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index d0a3bcf5c0d2..b54d99bca9bf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -636,7 +636,7 @@ int vmw_fb_on(struct vmw_private *vmw_priv) /* Make sure that all overlays are stoped when we take over */ vmw_overlay_stop_all(vmw_priv); - ret = vmw_dmabuf_to_start_of_vram(vmw_priv, par->vmw_bo, true, false); + ret = vmw_dmabuf_pin_in_start_of_vram(vmw_priv, par->vmw_bo, false); if (unlikely(ret != 0)) { DRM_ERROR("could not move buffer to start of VRAM\n"); goto err_no_buffer; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 239815c8b073..9b8b09f8135b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -604,7 +604,7 @@ static int vmw_fifo_emit_dummy_legacy_query(struct vmw_private *dev_priv, * without writing to the query result structure. */ - struct ttm_buffer_object *bo = dev_priv->dummy_query_bo; + struct ttm_buffer_object *bo = &dev_priv->dummy_query_bo->base; struct { SVGA3dCmdHeader header; SVGA3dCmdWaitForQuery body; @@ -653,7 +653,7 @@ static int vmw_fifo_emit_dummy_gb_query(struct vmw_private *dev_priv, * without writing to the query result structure. */ - struct ttm_buffer_object *bo = dev_priv->dummy_query_bo; + struct ttm_buffer_object *bo = &dev_priv->dummy_query_bo->base; struct { SVGA3dCmdHeader header; SVGA3dCmdWaitForGBQuery body; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 615ff6cfc4f9..99e2f5b9a023 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -678,7 +678,7 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) vmw_overlay_pause_all(dev_priv); - ret = vmw_dmabuf_to_start_of_vram(dev_priv, vfbd->buffer, true, false); + ret = vmw_dmabuf_pin_in_start_of_vram(dev_priv, vfbd->buffer, false); vmw_overlay_resume_all(dev_priv); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c index 7f4b2f072c6f..d839051cc1cb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c @@ -232,9 +232,9 @@ static int vmw_overlay_move_buffer(struct vmw_private *dev_priv, return vmw_dmabuf_unpin(dev_priv, buf, inter); if (dev_priv->active_display_unit == vmw_du_legacy) - return vmw_dmabuf_to_vram(dev_priv, buf, true, inter); + return vmw_dmabuf_pin_in_vram(dev_priv, buf, inter); - return vmw_dmabuf_to_vram_or_gmr(dev_priv, buf, true, inter); + return vmw_dmabuf_pin_in_vram_or_gmr(dev_priv, buf, inter); } /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 9dcbe8ba08ea..271bc900d83a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -1596,25 +1596,29 @@ int vmw_resource_pin(struct vmw_resource *res) goto out_no_reserve; if (res->pin_count == 0) { - struct ttm_buffer_object *bo = NULL; + struct vmw_dma_buffer *vbo = NULL; if (res->backup) { - bo = &res->backup->base; - - ttm_bo_reserve(bo, false, false, false, NULL); - ret = ttm_bo_validate(bo, res->func->backup_placement, - false, false); - if (ret) { - ttm_bo_unreserve(bo); - goto out_no_validate; + vbo = res->backup; + + ttm_bo_reserve(&vbo->base, false, false, false, NULL); + if (!vbo->pin_count) { + ret = ttm_bo_validate + (&vbo->base, + res->func->backup_placement, + false, false); + if (ret) { + ttm_bo_unreserve(&vbo->base); + goto out_no_validate; + } } /* Do we really need to pin the MOB as well? */ - vmw_bo_pin(bo, true); + vmw_bo_pin_reserved(vbo, true); } ret = vmw_resource_validate(res); - if (bo) - ttm_bo_unreserve(bo); + if (vbo) + ttm_bo_unreserve(&vbo->base); if (ret) goto out_no_validate; } @@ -1650,11 +1654,11 @@ void vmw_resource_unpin(struct vmw_resource *res) WARN_ON(res->pin_count == 0); if (--res->pin_count == 0 && res->backup) { - struct ttm_buffer_object *bo = &res->backup->base; + struct vmw_dma_buffer *vbo = res->backup; - ttm_bo_reserve(bo, false, false, false, NULL); - vmw_bo_pin(bo, false); - ttm_bo_unreserve(bo); + ttm_bo_reserve(&vbo->base, false, false, false, NULL); + vmw_bo_pin_reserved(vbo, false); + ttm_bo_unreserve(&vbo->base); } vmw_resource_unreserve(res, NULL, 0UL); -- cgit v1.3-6-gb490 From 1a4b172ac96edd7f571772e83c09c5a18718a4fa Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 26 Jun 2015 02:03:53 -0700 Subject: drm/vmwgfx: Add kms helpers for dirty- and readback functions We need to make the dirty- and readback functions callable without a struct drm_file pointer. We also need to unify the handling of dirty- and readback cliprects that are now implemented in various places across the kms system, som add helpers to facilitate this. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 10 +- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 19 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 292 +++++++++++++++++++++++++++++++ drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 71 +++++++- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 18 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 2 +- 6 files changed, 391 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 12eaa6c805d8..7504f92c767c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -640,7 +640,8 @@ extern struct vmw_resource *vmw_resource_reference(struct vmw_resource *res); extern struct vmw_resource * vmw_resource_reference_unless_doomed(struct vmw_resource *res); extern int vmw_resource_validate(struct vmw_resource *res); -extern int vmw_resource_reserve(struct vmw_resource *res, bool no_backup); +extern int vmw_resource_reserve(struct vmw_resource *res, bool interruptible, + bool no_backup); extern bool vmw_resource_needs_backup(const struct vmw_resource *res); extern int vmw_user_lookup_handle(struct vmw_private *dev_priv, struct ttm_object_file *tfile, @@ -860,6 +861,11 @@ extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, *user_fence_rep, struct vmw_fence_obj *fence, uint32_t fence_handle); +extern int vmw_validate_single_buffer(struct vmw_private *dev_priv, + struct ttm_buffer_object *bo, + bool interruptible, + bool validate_as_mob); + /** * IRQs and wating - vmwgfx_irq.c @@ -965,7 +971,7 @@ int vmw_dumb_map_offset(struct drm_file *file_priv, int vmw_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle); -extern int vmw_resource_pin(struct vmw_resource *res); +extern int vmw_resource_pin(struct vmw_resource *res, bool interruptible); extern void vmw_resource_unpin(struct vmw_resource *res); /** diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 92e89987b0d7..698a0e2add53 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -375,7 +375,7 @@ static int vmw_resources_reserve(struct vmw_sw_context *sw_context) list_for_each_entry(val, &sw_context->resource_list, head) { struct vmw_resource *res = val->res; - ret = vmw_resource_reserve(res, val->no_buffer_needed); + ret = vmw_resource_reserve(res, true, val->no_buffer_needed); if (unlikely(ret != 0)) return ret; @@ -2234,9 +2234,10 @@ static void vmw_clear_validations(struct vmw_sw_context *sw_context) (void) drm_ht_remove_item(&sw_context->res_ht, &val->hash); } -static int vmw_validate_single_buffer(struct vmw_private *dev_priv, - struct ttm_buffer_object *bo, - bool validate_as_mob) +int vmw_validate_single_buffer(struct vmw_private *dev_priv, + struct ttm_buffer_object *bo, + bool interruptible, + bool validate_as_mob) { struct vmw_dma_buffer *vbo = container_of(bo, struct vmw_dma_buffer, base); @@ -2246,7 +2247,8 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv, return 0; if (validate_as_mob) - return ttm_bo_validate(bo, &vmw_mob_placement, true, false); + return ttm_bo_validate(bo, &vmw_mob_placement, interruptible, + false); /** * Put BO in VRAM if there is space, otherwise as a GMR. @@ -2255,7 +2257,8 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv, * used as a GMR, this will return -ENOMEM. */ - ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, true, false); + ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, interruptible, + false); if (likely(ret == 0 || ret == -ERESTARTSYS)) return ret; @@ -2264,8 +2267,7 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv, * previous contents. */ - DRM_INFO("Falling through to VRAM.\n"); - ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false); + ret = ttm_bo_validate(bo, &vmw_vram_placement, interruptible, false); return ret; } @@ -2277,6 +2279,7 @@ static int vmw_validate_buffers(struct vmw_private *dev_priv, list_for_each_entry(entry, &sw_context->validate_nodes, base.head) { ret = vmw_validate_single_buffer(dev_priv, entry->base.bo, + true, entry->validate_as_mob); if (unlikely(ret != 0)) return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 99e2f5b9a023..c46c68846f0e 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1821,3 +1821,295 @@ out_free: kfree(rects); return ret; } + +/** + * vmw_kms_helper_dirty - Helper to build commands and perform actions based + * on a set of cliprects and a set of display units. + * + * @dev_priv: Pointer to a device private structure. + * @framebuffer: Pointer to the framebuffer on which to perform the actions. + * @clips: A set of struct drm_clip_rect. Either this os @vclips must be NULL. + * Cliprects are given in framebuffer coordinates. + * @vclips: A set of struct drm_vmw_rect cliprects. Either this or @clips must + * be NULL. Cliprects are given in source coordinates. + * @dest_x: X coordinate offset for the crtc / destination clip rects. + * @dest_y: Y coordinate offset for the crtc / destination clip rects. + * @num_clips: Number of cliprects in the @clips or @vclips array. + * @increment: Integer with which to increment the clip counter when looping. + * Used to skip a predetermined number of clip rects. + * @dirty: Closure structure. See the description of struct vmw_kms_dirty. + */ +int vmw_kms_helper_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + const struct drm_clip_rect *clips, + const struct drm_vmw_rect *vclips, + s32 dest_x, s32 dest_y, + int num_clips, + int increment, + struct vmw_kms_dirty *dirty) +{ + struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; + struct drm_crtc *crtc; + u32 num_units = 0; + u32 i, k; + int ret; + + dirty->dev_priv = dev_priv; + + list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { + if (crtc->primary->fb != &framebuffer->base) + continue; + units[num_units++] = vmw_crtc_to_du(crtc); + } + + for (k = 0; k < num_units; k++) { + struct vmw_display_unit *unit = units[k]; + s32 crtc_x = unit->crtc.x; + s32 crtc_y = unit->crtc.y; + s32 crtc_width = unit->crtc.mode.hdisplay; + s32 crtc_height = unit->crtc.mode.vdisplay; + const struct drm_clip_rect *clips_ptr = clips; + const struct drm_vmw_rect *vclips_ptr = vclips; + + dirty->unit = unit; + if (dirty->fifo_reserve_size > 0) { + dirty->cmd = vmw_fifo_reserve(dev_priv, + dirty->fifo_reserve_size); + if (!dirty->cmd) { + DRM_ERROR("Couldn't reserve fifo space " + "for dirty blits.\n"); + return ret; + } + memset(dirty->cmd, 0, dirty->fifo_reserve_size); + } + dirty->num_hits = 0; + for (i = 0; i < num_clips; i++, clips_ptr += increment, + vclips_ptr += increment) { + s32 clip_left; + s32 clip_top; + + /* + * Select clip array type. Note that integer type + * in @clips is unsigned short, whereas in @vclips + * it's 32-bit. + */ + if (clips) { + dirty->fb_x = (s32) clips_ptr->x1; + dirty->fb_y = (s32) clips_ptr->y1; + dirty->unit_x2 = (s32) clips_ptr->x2 + dest_x - + crtc_x; + dirty->unit_y2 = (s32) clips_ptr->y2 + dest_y - + crtc_y; + } else { + dirty->fb_x = vclips_ptr->x; + dirty->fb_y = vclips_ptr->y; + dirty->unit_x2 = dirty->fb_x + vclips_ptr->w + + dest_x - crtc_x; + dirty->unit_y2 = dirty->fb_y + vclips_ptr->h + + dest_y - crtc_y; + } + + dirty->unit_x1 = dirty->fb_x + dest_x - crtc_x; + dirty->unit_y1 = dirty->fb_y + dest_y - crtc_y; + + /* Skip this clip if it's outside the crtc region */ + if (dirty->unit_x1 >= crtc_width || + dirty->unit_y1 >= crtc_height || + dirty->unit_x2 <= 0 || dirty->unit_y2 <= 0) + continue; + + /* Clip right and bottom to crtc limits */ + dirty->unit_x2 = min_t(s32, dirty->unit_x2, + crtc_width); + dirty->unit_y2 = min_t(s32, dirty->unit_y2, + crtc_height); + + /* Clip left and top to crtc limits */ + clip_left = min_t(s32, dirty->unit_x1, 0); + clip_top = min_t(s32, dirty->unit_y1, 0); + dirty->unit_x1 -= clip_left; + dirty->unit_y1 -= clip_top; + dirty->fb_x -= clip_left; + dirty->fb_y -= clip_top; + + dirty->clip(dirty); + } + + dirty->fifo_commit(dirty); + } + + return 0; +} + +/** + * vmw_kms_helper_buffer_prepare - Reserve and validate a buffer object before + * command submission. + * + * @dev_priv. Pointer to a device private structure. + * @buf: The buffer object + * @interruptible: Whether to perform waits as interruptible. + * @validate_as_mob: Whether the buffer should be validated as a MOB. If false, + * The buffer will be validated as a GMR. Already pinned buffers will not be + * validated. + * + * Returns 0 on success, negative error code on failure, -ERESTARTSYS if + * interrupted by a signal. + */ +int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, + struct vmw_dma_buffer *buf, + bool interruptible, + bool validate_as_mob) +{ + struct ttm_buffer_object *bo = &buf->base; + int ret; + + ttm_bo_reserve(bo, false, false, interruptible, 0); + ret = vmw_validate_single_buffer(dev_priv, bo, interruptible, + validate_as_mob); + if (ret) + ttm_bo_unreserve(bo); + + return ret; +} + +/** + * vmw_kms_helper_buffer_revert - Undo the actions of + * vmw_kms_helper_buffer_prepare. + * + * @res: Pointer to the buffer object. + * + * Helper to be used if an error forces the caller to undo the actions of + * vmw_kms_helper_buffer_prepare. + */ +void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf) +{ + if (buf) + ttm_bo_unreserve(&buf->base); +} + +/** + * vmw_kms_helper_buffer_finish - Unreserve and fence a buffer object after + * kms command submission. + * + * @dev_priv: Pointer to a device private structure. + * @file_priv: Pointer to a struct drm_file representing the caller's + * connection. Must be set to NULL if @user_fence_rep is NULL, and conversely + * if non-NULL, @user_fence_rep must be non-NULL. + * @buf: The buffer object. + * @out_fence: Optional pointer to a fence pointer. If non-NULL, a + * ref-counted fence pointer is returned here. + * @user_fence_rep: Optional pointer to a user-space provided struct + * drm_vmw_fence_rep. If provided, @file_priv must also be provided and the + * function copies fence data to user-space in a fail-safe manner. + */ +void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_dma_buffer *buf, + struct vmw_fence_obj **out_fence, + struct drm_vmw_fence_rep __user * + user_fence_rep) +{ + struct vmw_fence_obj *fence; + uint32_t handle; + int ret; + + ret = vmw_execbuf_fence_commands(file_priv, dev_priv, &fence, + file_priv ? &handle : NULL); + if (buf) + vmw_fence_single_bo(&buf->base, fence); + if (file_priv) + vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), + ret, user_fence_rep, fence, + handle); + if (out_fence) + *out_fence = fence; + else + vmw_fence_obj_unreference(&fence); + + vmw_kms_helper_buffer_revert(buf); +} + + +/** + * vmw_kms_helper_resource_revert - Undo the actions of + * vmw_kms_helper_resource_prepare. + * + * @res: Pointer to the resource. Typically a surface. + * + * Helper to be used if an error forces the caller to undo the actions of + * vmw_kms_helper_resource_prepare. + */ +void vmw_kms_helper_resource_revert(struct vmw_resource *res) +{ + vmw_kms_helper_buffer_revert(res->backup); + vmw_resource_unreserve(res, NULL, 0); + mutex_unlock(&res->dev_priv->cmdbuf_mutex); +} + +/** + * vmw_kms_helper_resource_prepare - Reserve and validate a resource before + * command submission. + * + * @res: Pointer to the resource. Typically a surface. + * @interruptible: Whether to perform waits as interruptible. + * + * Reserves and validates also the backup buffer if a guest-backed resource. + * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * interrupted by a signal. + */ +int vmw_kms_helper_resource_prepare(struct vmw_resource *res, + bool interruptible) +{ + int ret = 0; + + if (interruptible) + ret = mutex_lock_interruptible(&res->dev_priv->cmdbuf_mutex); + else + mutex_lock(&res->dev_priv->cmdbuf_mutex); + + if (unlikely(ret != 0)) + return -ERESTARTSYS; + + ret = vmw_resource_reserve(res, interruptible, false); + if (ret) + goto out_unlock; + + if (res->backup) { + ret = vmw_kms_helper_buffer_prepare(res->dev_priv, res->backup, + interruptible, + res->dev_priv->has_mob); + if (ret) + goto out_unreserve; + } + ret = vmw_resource_validate(res); + if (ret) + goto out_revert; + return 0; + +out_revert: + vmw_kms_helper_buffer_revert(res->backup); +out_unreserve: + vmw_resource_unreserve(res, NULL, 0); +out_unlock: + mutex_unlock(&res->dev_priv->cmdbuf_mutex); + return ret; +} + +/** + * vmw_kms_helper_resource_finish - Unreserve and fence a resource after + * kms command submission. + * + * @res: Pointer to the resource. Typically a surface. + * @out_fence: Optional pointer to a fence pointer. If non-NULL, a + * ref-counted fence pointer is returned here. + */ +void vmw_kms_helper_resource_finish(struct vmw_resource *res, + struct vmw_fence_obj **out_fence) +{ + if (res->backup || out_fence) + vmw_kms_helper_buffer_finish(res->dev_priv, NULL, res->backup, + out_fence, NULL); + + vmw_resource_unreserve(res, NULL, 0); + mutex_unlock(&res->dev_priv->cmdbuf_mutex); +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index db8ae94c403c..c19a515b139b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -32,7 +32,50 @@ #include #include "vmwgfx_drv.h" - +/** + * struct vmw_kms_dirty - closure structure for the vmw_kms_helper_dirty + * function. + * + * @fifo_commit: Callback that is called once for each display unit after + * all clip rects. This function must commit the fifo space reserved by the + * helper. Set up by the caller. + * @clip: Callback that is called for each cliprect on each display unit. + * Set up by the caller. + * @fifo_reserve_size: Fifo size that the helper should try to allocat for + * each display unit. Set up by the caller. + * @dev_priv: Pointer to the device private. Set up by the helper. + * @unit: The current display unit. Set up by the helper before a call to @clip. + * @cmd: The allocated fifo space. Set up by the helper before the first @clip + * call. + * @num_hits: Number of clip rect commands for this display unit. + * Cleared by the helper before the first @clip call. Updated by the @clip + * callback. + * @fb_x: Clip rect left side in framebuffer coordinates. + * @fb_y: Clip rect right side in framebuffer coordinates. + * @unit_x1: Clip rect left side in crtc coordinates. + * @unit_y1: Clip rect top side in crtc coordinates. + * @unit_x2: Clip rect right side in crtc coordinates. + * @unit_y2: Clip rect bottom side in crtc coordinates. + * + * The clip rect coordinates are updated by the helper for each @clip call. + * Note that this may be derived from if more info needs to be passed between + * helper caller and helper callbacks. + */ +struct vmw_kms_dirty { + void (*fifo_commit)(struct vmw_kms_dirty *); + void (*clip)(struct vmw_kms_dirty *); + size_t fifo_reserve_size; + struct vmw_private *dev_priv; + struct vmw_display_unit *unit; + void *cmd; + u32 num_hits; + s32 fb_x; + s32 fb_y; + s32 unit_x1; + s32 unit_y1; + s32 unit_x2; + s32 unit_y2; +}; #define VMWGFX_NUM_DISPLAY_UNITS 8 @@ -173,7 +216,31 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, int vmw_du_connector_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val); - +int vmw_kms_helper_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + const struct drm_clip_rect *clips, + const struct drm_vmw_rect *vclips, + s32 dest_x, s32 dest_y, + int num_clips, + int increment, + struct vmw_kms_dirty *dirty); + +int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, + struct vmw_dma_buffer *buf, + bool interruptible, + bool validate_as_mob); +void vmw_kms_helper_buffer_revert(struct vmw_dma_buffer *buf); +void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_dma_buffer *buf, + struct vmw_fence_obj **out_fence, + struct drm_vmw_fence_rep __user * + user_fence_rep); +int vmw_kms_helper_resource_prepare(struct vmw_resource *res, + bool interruptible); +void vmw_kms_helper_resource_revert(struct vmw_resource *res); +void vmw_kms_helper_resource_finish(struct vmw_resource *res, + struct vmw_fence_obj **out_fence); /* * Legacy display unit functions - vmwgfx_ldu.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 271bc900d83a..521f1947b4e9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -1259,7 +1259,8 @@ out_no_reserve: * the buffer may not be bound to the resource at this point. * */ -int vmw_resource_reserve(struct vmw_resource *res, bool no_backup) +int vmw_resource_reserve(struct vmw_resource *res, bool interruptible, + bool no_backup) { struct vmw_private *dev_priv = res->dev_priv; int ret; @@ -1270,7 +1271,7 @@ int vmw_resource_reserve(struct vmw_resource *res, bool no_backup) if (res->func->needs_backup && res->backup == NULL && !no_backup) { - ret = vmw_resource_buf_alloc(res, true); + ret = vmw_resource_buf_alloc(res, interruptible); if (unlikely(ret != 0)) return ret; } @@ -1584,14 +1585,14 @@ void vmw_resource_evict_all(struct vmw_private *dev_priv) * its id will never change as long as there is a pin reference. * This function returns 0 on success and a negative error code on failure. */ -int vmw_resource_pin(struct vmw_resource *res) +int vmw_resource_pin(struct vmw_resource *res, bool interruptible) { struct vmw_private *dev_priv = res->dev_priv; int ret; - ttm_write_lock(&dev_priv->reservation_sem, false); + ttm_write_lock(&dev_priv->reservation_sem, interruptible); mutex_lock(&dev_priv->cmdbuf_mutex); - ret = vmw_resource_reserve(res, false); + ret = vmw_resource_reserve(res, interruptible, false); if (ret) goto out_no_reserve; @@ -1601,12 +1602,13 @@ int vmw_resource_pin(struct vmw_resource *res) if (res->backup) { vbo = res->backup; - ttm_bo_reserve(&vbo->base, false, false, false, NULL); + ttm_bo_reserve(&vbo->base, interruptible, false, false, + NULL); if (!vbo->pin_count) { ret = ttm_bo_validate (&vbo->base, res->func->backup_placement, - false, false); + interruptible, false); if (ret) { ttm_bo_unreserve(&vbo->base); goto out_no_validate; @@ -1649,7 +1651,7 @@ void vmw_resource_unpin(struct vmw_resource *res) ttm_read_lock(&dev_priv->reservation_sem, false); mutex_lock(&dev_priv->cmdbuf_mutex); - ret = vmw_resource_reserve(res, true); + ret = vmw_resource_reserve(res, false, true); WARN_ON(ret); WARN_ON(res->pin_count == 0); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index ef99df7463f3..becf9650c228 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -91,7 +91,7 @@ static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu); */ static int vmw_stdu_pin_display(struct vmw_screen_target_display_unit *stdu) { - return vmw_resource_pin(&stdu->display_srf->res); + return vmw_resource_pin(&stdu->display_srf->res, false); } -- cgit v1.3-6-gb490 From 10b1e0ca9c32deb3a9b0ecc93fc4920fc24b4a57 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 26 Jun 2015 02:14:27 -0700 Subject: drm/vmwgfx: Convert screen objects to the new helpers This makes it possible to use the same function for surface dirty and present. Also fixes page flip without events. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 - drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 319 +++-------------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 33 +- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 642 +++++++++++++++++++++-------------- 4 files changed, 444 insertions(+), 556 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 7504f92c767c..d60ae207136c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -952,12 +952,6 @@ int vmw_kms_present(struct vmw_private *dev_priv, uint32_t sid, int32_t destX, int32_t destY, struct drm_vmw_rect *clips, uint32_t num_clips); -int vmw_kms_readback(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *vfb, - struct drm_vmw_fence_rep __user *user_fence_rep, - struct drm_vmw_rect *clips, - uint32_t num_clips); int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index c46c68846f0e..5901d32d0273 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -31,41 +31,6 @@ /* Might need a hrtimer here? */ #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) - - -/** - * Clip @num_rects number of @rects against @clip storing the - * results in @out_rects and the number of passed rects in @out_num. - */ -void vmw_clip_cliprects(struct drm_clip_rect *rects, - int num_rects, - struct vmw_clip_rect clip, - SVGASignedRect *out_rects, - int *out_num) -{ - int i, k; - - for (i = 0, k = 0; i < num_rects; i++) { - int x1 = max_t(int, clip.x1, rects[i].x1); - int y1 = max_t(int, clip.y1, rects[i].y1); - int x2 = min_t(int, clip.x2, rects[i].x2); - int y2 = min_t(int, clip.y2, rects[i].y2); - - if (x1 >= x2) - continue; - if (y1 >= y2) - continue; - - out_rects[k].left = x1; - out_rects[k].top = y1; - out_rects[k].right = x2; - out_rects[k].bottom = y2; - k++; - } - - *out_num = k; -} - void vmw_du_cleanup(struct vmw_display_unit *du) { if (du->cursor_surface) @@ -458,11 +423,9 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, } if (dev_priv->active_display_unit == vmw_du_screen_object) - ret = vmw_kms_sou_do_surface_dirty(dev_priv, file_priv, - &vfbs->base, - flags, color, - clips, num_clips, - inc, NULL); + ret = vmw_kms_sou_do_surface_dirty(dev_priv, &vfbs->base, + clips, NULL, NULL, 0, 0, + num_clips, inc, NULL); else ret = vmw_kms_stdu_do_surface_dirty(dev_priv, file_priv, &vfbs->base, @@ -477,6 +440,42 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, return 0; } +/** + * vmw_kms_readback - Perform a readback from the screen system to + * a dma-buffer backed framebuffer. + * + * @dev_priv: Pointer to the device private structure. + * @file_priv: Pointer to a struct drm_file identifying the caller. + * Must be set to NULL if @user_fence_rep is NULL. + * @vfb: Pointer to the dma-buffer backed framebuffer. + * @user_fence_rep: User-space provided structure for fence information. + * Must be set to non-NULL if @file_priv is non-NULL. + * @vclips: Array of clip rects. + * @num_clips: Number of clip rects in @vclips. + * + * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * interrupted. + */ +int vmw_kms_readback(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct drm_vmw_fence_rep __user *user_fence_rep, + struct drm_vmw_rect *vclips, + uint32_t num_clips) +{ + switch (dev_priv->active_display_unit) { + case vmw_du_screen_object: + return vmw_kms_sou_readback(dev_priv, file_priv, vfb, + user_fence_rep, vclips, num_clips); + default: + WARN_ONCE(true, + "Readback called with invalid display system.\n"); + } + + return -ENOSYS; +} + + static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { .destroy = vmw_framebuffer_surface_destroy, .dirty = vmw_framebuffer_surface_dirty, @@ -638,10 +637,9 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, flags, color, clips, num_clips, increment); } else if (dev_priv->active_display_unit == vmw_du_screen_object) { - ret = vmw_kms_sou_do_dmabuf_dirty(file_priv, dev_priv, - &vfbd->base, - flags, color, + ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, clips, num_clips, increment, + true, NULL); } else { ret = vmw_kms_stdu_do_surface_dirty(dev_priv, file_priv, @@ -984,131 +982,9 @@ int vmw_kms_generic_present(struct vmw_private *dev_priv, struct drm_vmw_rect *clips, uint32_t num_clips) { - struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; - struct drm_clip_rect *tmp; - struct drm_crtc *crtc; - size_t fifo_size; - int i, k, num_units; - int ret = 0; /* silence warning */ - int left, right, top, bottom; - - struct { - SVGA3dCmdHeader header; - SVGA3dCmdBlitSurfaceToScreen body; - } *cmd; - SVGASignedRect *blits; - - num_units = 0; - list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->primary->fb != &vfb->base) - continue; - units[num_units++] = vmw_crtc_to_du(crtc); - } - - BUG_ON(surface == NULL); - BUG_ON(!clips || !num_clips); - - tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); - if (unlikely(tmp == NULL)) { - DRM_ERROR("Temporary cliprect memory alloc failed.\n"); - return -ENOMEM; - } - - fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; - cmd = kmalloc(fifo_size, GFP_KERNEL); - if (unlikely(cmd == NULL)) { - DRM_ERROR("Failed to allocate temporary fifo memory.\n"); - ret = -ENOMEM; - goto out_free_tmp; - } - - left = clips->x; - right = clips->x + clips->w; - top = clips->y; - bottom = clips->y + clips->h; - - for (i = 1; i < num_clips; i++) { - left = min_t(int, left, (int)clips[i].x); - right = max_t(int, right, (int)clips[i].x + clips[i].w); - top = min_t(int, top, (int)clips[i].y); - bottom = max_t(int, bottom, (int)clips[i].y + clips[i].h); - } - - /* only need to do this once */ - memset(cmd, 0, fifo_size); - cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); - - blits = (SVGASignedRect *)&cmd[1]; - - cmd->body.srcRect.left = left; - cmd->body.srcRect.right = right; - cmd->body.srcRect.top = top; - cmd->body.srcRect.bottom = bottom; - - for (i = 0; i < num_clips; i++) { - tmp[i].x1 = clips[i].x - left; - tmp[i].x2 = clips[i].x + clips[i].w - left; - tmp[i].y1 = clips[i].y - top; - tmp[i].y2 = clips[i].y + clips[i].h - top; - } - - for (k = 0; k < num_units; k++) { - struct vmw_display_unit *unit = units[k]; - struct vmw_clip_rect clip; - int num; - - clip.x1 = left + destX - unit->crtc.x; - clip.y1 = top + destY - unit->crtc.y; - clip.x2 = right + destX - unit->crtc.x; - clip.y2 = bottom + destY - unit->crtc.y; - - /* skip any crtcs that misses the clip region */ - if (clip.x1 >= unit->crtc.mode.hdisplay || - clip.y1 >= unit->crtc.mode.vdisplay || - clip.x2 <= 0 || clip.y2 <= 0) - continue; - - /* - * In order for the clip rects to be correctly scaled - * the src and dest rects needs to be the same size. - */ - cmd->body.destRect.left = clip.x1; - cmd->body.destRect.right = clip.x2; - cmd->body.destRect.top = clip.y1; - cmd->body.destRect.bottom = clip.y2; - - /* create a clip rect of the crtc in dest coords */ - clip.x2 = unit->crtc.mode.hdisplay - clip.x1; - clip.y2 = unit->crtc.mode.vdisplay - clip.y1; - clip.x1 = 0 - clip.x1; - clip.y1 = 0 - clip.y1; - - /* need to reset sid as it is changed by execbuf */ - cmd->body.srcImage.sid = sid; - cmd->body.destScreenId = unit->unit; - - /* clip and write blits to cmd stream */ - vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); - - /* if no cliprects hit skip this */ - if (num == 0) - continue; - - /* recalculate package length */ - fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; - cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, - fifo_size, 0, 0, NULL, NULL); - - if (unlikely(ret != 0)) - break; - } - - kfree(cmd); -out_free_tmp: - kfree(tmp); - - return ret; + return vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, clips, + &surface->res, destX, destY, + num_clips, 1, NULL); } int vmw_kms_present(struct vmw_private *dev_priv, @@ -1137,113 +1013,6 @@ int vmw_kms_present(struct vmw_private *dev_priv, return 0; } -int vmw_kms_readback(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *vfb, - struct drm_vmw_fence_rep __user *user_fence_rep, - struct drm_vmw_rect *clips, - uint32_t num_clips) -{ - struct vmw_framebuffer_dmabuf *vfbd = - vmw_framebuffer_to_vfbd(&vfb->base); - struct vmw_dma_buffer *dmabuf = vfbd->buffer; - struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; - struct drm_crtc *crtc; - size_t fifo_size; - int i, k, ret, num_units, blits_pos; - - struct { - uint32_t header; - SVGAFifoCmdDefineGMRFB body; - } *cmd; - struct { - uint32_t header; - SVGAFifoCmdBlitScreenToGMRFB body; - } *blits; - - num_units = 0; - list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->primary->fb != &vfb->base) - continue; - units[num_units++] = vmw_crtc_to_du(crtc); - } - - BUG_ON(dmabuf == NULL); - BUG_ON(!clips || !num_clips); - - /* take a safe guess at fifo size */ - fifo_size = sizeof(*cmd) + sizeof(*blits) * num_clips * num_units; - cmd = kmalloc(fifo_size, GFP_KERNEL); - if (unlikely(cmd == NULL)) { - DRM_ERROR("Failed to allocate temporary fifo memory.\n"); - return -ENOMEM; - } - - memset(cmd, 0, fifo_size); - cmd->header = SVGA_CMD_DEFINE_GMRFB; - cmd->body.format.bitsPerPixel = vfb->base.bits_per_pixel; - cmd->body.format.colorDepth = vfb->base.depth; - cmd->body.format.reserved = 0; - cmd->body.bytesPerLine = vfb->base.pitches[0]; - cmd->body.ptr.gmrId = vfb->user_handle; - cmd->body.ptr.offset = 0; - - blits = (void *)&cmd[1]; - blits_pos = 0; - for (i = 0; i < num_units; i++) { - struct drm_vmw_rect *c = clips; - for (k = 0; k < num_clips; k++, c++) { - /* transform clip coords to crtc origin based coords */ - int clip_x1 = c->x - units[i]->crtc.x; - int clip_x2 = c->x - units[i]->crtc.x + c->w; - int clip_y1 = c->y - units[i]->crtc.y; - int clip_y2 = c->y - units[i]->crtc.y + c->h; - int dest_x = c->x; - int dest_y = c->y; - - /* compensate for clipping, we negate - * a negative number and add that. - */ - if (clip_x1 < 0) - dest_x += -clip_x1; - if (clip_y1 < 0) - dest_y += -clip_y1; - - /* clip */ - clip_x1 = max(clip_x1, 0); - clip_y1 = max(clip_y1, 0); - clip_x2 = min(clip_x2, units[i]->crtc.mode.hdisplay); - clip_y2 = min(clip_y2, units[i]->crtc.mode.vdisplay); - - /* and cull any rects that misses the crtc */ - if (clip_x1 >= units[i]->crtc.mode.hdisplay || - clip_y1 >= units[i]->crtc.mode.vdisplay || - clip_x2 <= 0 || clip_y2 <= 0) - continue; - - blits[blits_pos].header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB; - blits[blits_pos].body.srcScreenId = units[i]->unit; - blits[blits_pos].body.destOrigin.x = dest_x; - blits[blits_pos].body.destOrigin.y = dest_y; - - blits[blits_pos].body.srcRect.left = clip_x1; - blits[blits_pos].body.srcRect.top = clip_y1; - blits[blits_pos].body.srcRect.right = clip_x2; - blits[blits_pos].body.srcRect.bottom = clip_y2; - blits_pos++; - } - } - /* reset size here and use calculated exact size from loops */ - fifo_size = sizeof(*cmd) + sizeof(*blits) * blits_pos; - - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, fifo_size, - 0, 0, user_fence_rep, NULL); - - kfree(cmd); - - return ret; -} - int vmw_kms_init(struct vmw_private *dev_priv) { struct drm_device *dev = dev_priv->dev; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index c19a515b139b..8a8203c66adc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -125,15 +125,6 @@ struct vmw_framebuffer_dmabuf { }; -/* - * Basic clip rect manipulation - */ -void vmw_clip_cliprects(struct drm_clip_rect *rects, - int num_rects, - struct vmw_clip_rect clip, - SVGASignedRect *out_rects, - int *out_num); - /* * Basic cursor manipulation */ @@ -241,6 +232,12 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res, void vmw_kms_helper_resource_revert(struct vmw_resource *res); void vmw_kms_helper_resource_finish(struct vmw_resource *res, struct vmw_fence_obj **out_fence); +int vmw_kms_readback(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct drm_vmw_fence_rep __user *user_fence_rep, + struct drm_vmw_rect *vclips, + uint32_t num_clips); /* * Legacy display unit functions - vmwgfx_ldu.c @@ -259,20 +256,26 @@ int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv, int vmw_kms_sou_init_display(struct vmw_private *dev_priv); int vmw_kms_sou_close_display(struct vmw_private *dev_priv); int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, - struct drm_file *file_priv, struct vmw_framebuffer *framebuffer, - unsigned flags, unsigned color, struct drm_clip_rect *clips, + struct drm_vmw_rect *vclips, + struct vmw_resource *srf, + s32 dest_x, + s32 dest_y, unsigned num_clips, int inc, struct vmw_fence_obj **out_fence); -int vmw_kms_sou_do_dmabuf_dirty(struct drm_file *file_priv, - struct vmw_private *dev_priv, +int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer, - unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips, int increment, + bool interruptible, struct vmw_fence_obj **out_fence); - +int vmw_kms_sou_readback(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct drm_vmw_fence_rep __user *user_fence_rep, + struct drm_vmw_rect *vclips, + uint32_t num_clips); /* * Screen Target Display Unit functions - vmwgfx_stdu.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 0d06d86e432a..73fe20ef1d10 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -36,10 +36,55 @@ #define vmw_connector_to_sou(x) \ container_of(x, struct vmw_screen_object_unit, base.connector) +/** + * struct vmw_kms_sou_surface_dirty - Closure structure for + * blit surface to screen command. + * @base: The base type we derive from. Used by vmw_kms_helper_dirty(). + * @left: Left side of bounding box. + * @right: Right side of bounding box. + * @top: Top side of bounding box. + * @bottom: Bottom side of bounding box. + * @dst_x: Difference between source clip rects and framebuffer coordinates. + * @dst_y: Difference between source clip rects and framebuffer coordinates. + * @sid: Surface id of surface to copy from. + */ +struct vmw_kms_sou_surface_dirty { + struct vmw_kms_dirty base; + s32 left, right, top, bottom; + s32 dst_x, dst_y; + u32 sid; +}; + +/* + * SVGA commands that are used by this code. Please see the device headers + * for explanation. + */ +struct vmw_kms_sou_readback_blit { + uint32 header; + SVGAFifoCmdBlitScreenToGMRFB body; +}; + +struct vmw_kms_sou_dmabuf_blit { + uint32 header; + SVGAFifoCmdBlitGMRFBToScreen body; +}; + +struct vmw_kms_sou_dirty_cmd { + SVGA3dCmdHeader header; + SVGA3dCmdBlitSurfaceToScreen body; +}; + + +/* + * Other structs. + */ + struct vmw_screen_object_display { unsigned num_implicit; struct vmw_framebuffer *implicit_fb; + SVGAFifoCmdDefineGMRFB cur; + struct vmw_dma_buffer *pinned_gmrfb; }; /** @@ -202,14 +247,7 @@ static int vmw_sou_fifo_destroy(struct vmw_private *dev_priv, static void vmw_sou_backing_free(struct vmw_private *dev_priv, struct vmw_screen_object_unit *sou) { - struct ttm_buffer_object *bo; - - if (unlikely(sou->buffer == NULL)) - return; - - bo = &sou->buffer->base; - ttm_bo_unref(&bo); - sou->buffer = NULL; + vmw_dmabuf_unreference(&sou->buffer); sou->buffer_size = 0; } @@ -432,7 +470,6 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct drm_framebuffer *old_fb = crtc->primary->fb; struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb); - struct drm_file *file_priv = event->base.file_priv; struct vmw_fence_obj *fence = NULL; struct drm_clip_rect clips; int ret; @@ -452,11 +489,13 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, clips.y2 = fb->height; if (vfb->dmabuf) - ret = vmw_kms_sou_do_dmabuf_dirty(file_priv, dev_priv, vfb, - 0, 0, &clips, 1, 1, &fence); + ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, vfb, + &clips, 1, 1, + true, &fence); else - ret = vmw_kms_sou_do_surface_dirty(dev_priv, file_priv, vfb, - 0, 0, &clips, 1, 1, &fence); + ret = vmw_kms_sou_do_surface_dirty(dev_priv, vfb, + &clips, NULL, NULL, + 0, 0, 1, 1, &fence); if (ret != 0) @@ -466,11 +505,15 @@ static int vmw_sou_crtc_page_flip(struct drm_crtc *crtc, goto out_no_fence; } - ret = vmw_event_fence_action_queue(file_priv, fence, - &event->base, - &event->event.tv_sec, - &event->event.tv_usec, - true); + if (event) { + struct drm_file *file_priv = event->base.file_priv; + + ret = vmw_event_fence_action_queue(file_priv, fence, + &event->base, + &event->event.tv_sec, + &event->event.tv_usec, + true); + } /* * No need to hold on to this now. The only cleanup @@ -488,153 +531,6 @@ out_no_fence: return ret; } -int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *framebuffer, - unsigned flags, unsigned color, - struct drm_clip_rect *clips, - unsigned num_clips, int inc, - struct vmw_fence_obj **out_fence) -{ - struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; - struct drm_clip_rect *clips_ptr; - struct drm_clip_rect *tmp; - struct drm_crtc *crtc; - size_t fifo_size; - int i, num_units; - int ret = 0; /* silence warning */ - int left, right, top, bottom; - - struct { - SVGA3dCmdHeader header; - SVGA3dCmdBlitSurfaceToScreen body; - } *cmd; - SVGASignedRect *blits; - - num_units = 0; - list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, - head) { - if (crtc->primary->fb != &framebuffer->base) - continue; - units[num_units++] = vmw_crtc_to_du(crtc); - } - - BUG_ON(!clips || !num_clips); - - tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); - if (unlikely(tmp == NULL)) { - DRM_ERROR("Temporary cliprect memory alloc failed.\n"); - return -ENOMEM; - } - - fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; - cmd = kzalloc(fifo_size, GFP_KERNEL); - if (unlikely(cmd == NULL)) { - DRM_ERROR("Temporary fifo memory alloc failed.\n"); - ret = -ENOMEM; - goto out_free_tmp; - } - - /* setup blits pointer */ - blits = (SVGASignedRect *)&cmd[1]; - - /* initial clip region */ - left = clips->x1; - right = clips->x2; - top = clips->y1; - bottom = clips->y2; - - /* skip the first clip rect */ - for (i = 1, clips_ptr = clips + inc; - i < num_clips; i++, clips_ptr += inc) { - left = min_t(int, left, (int)clips_ptr->x1); - right = max_t(int, right, (int)clips_ptr->x2); - top = min_t(int, top, (int)clips_ptr->y1); - bottom = max_t(int, bottom, (int)clips_ptr->y2); - } - - /* only need to do this once */ - cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); - cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); - - cmd->body.srcRect.left = left; - cmd->body.srcRect.right = right; - cmd->body.srcRect.top = top; - cmd->body.srcRect.bottom = bottom; - - clips_ptr = clips; - for (i = 0; i < num_clips; i++, clips_ptr += inc) { - tmp[i].x1 = clips_ptr->x1 - left; - tmp[i].x2 = clips_ptr->x2 - left; - tmp[i].y1 = clips_ptr->y1 - top; - tmp[i].y2 = clips_ptr->y2 - top; - } - - /* do per unit writing, reuse fifo for each */ - for (i = 0; i < num_units; i++) { - struct vmw_display_unit *unit = units[i]; - struct vmw_clip_rect clip; - int num; - - clip.x1 = left - unit->crtc.x; - clip.y1 = top - unit->crtc.y; - clip.x2 = right - unit->crtc.x; - clip.y2 = bottom - unit->crtc.y; - - /* skip any crtcs that misses the clip region */ - if (clip.x1 >= unit->crtc.mode.hdisplay || - clip.y1 >= unit->crtc.mode.vdisplay || - clip.x2 <= 0 || clip.y2 <= 0) - continue; - - /* - * In order for the clip rects to be correctly scaled - * the src and dest rects needs to be the same size. - */ - cmd->body.destRect.left = clip.x1; - cmd->body.destRect.right = clip.x2; - cmd->body.destRect.top = clip.y1; - cmd->body.destRect.bottom = clip.y2; - - /* create a clip rect of the crtc in dest coords */ - clip.x2 = unit->crtc.mode.hdisplay - clip.x1; - clip.y2 = unit->crtc.mode.vdisplay - clip.y1; - clip.x1 = 0 - clip.x1; - clip.y1 = 0 - clip.y1; - - /* need to reset sid as it is changed by execbuf */ - cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle); - cmd->body.destScreenId = unit->unit; - - /* clip and write blits to cmd stream */ - vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); - - /* if no cliprects hit skip this */ - if (num == 0) - continue; - - /* only return the last fence */ - if (out_fence && *out_fence) - vmw_fence_obj_unreference(out_fence); - - /* recalculate package length */ - fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; - cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, - fifo_size, 0, 0, NULL, out_fence); - - if (unlikely(ret != 0)) - break; - } - - - kfree(cmd); -out_free_tmp: - kfree(tmp); - - return ret; -} - static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { .save = vmw_du_crtc_save, .restore = vmw_du_crtc_restore, @@ -790,14 +686,13 @@ int vmw_kms_sou_close_display(struct vmw_private *dev_priv) return 0; } -static int do_dmabuf_define_gmrfb(struct drm_file *file_priv, - struct vmw_private *dev_priv, +static int do_dmabuf_define_gmrfb(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer) { + struct vmw_dma_buffer *buf = + container_of(framebuffer, struct vmw_framebuffer_dmabuf, + base)->buffer; int depth = framebuffer->base.depth; - size_t fifo_size; - int ret; - struct { uint32_t header; SVGAFifoCmdDefineGMRFB body; @@ -810,123 +705,350 @@ static int do_dmabuf_define_gmrfb(struct drm_file *file_priv, if (depth == 32) depth = 24; - fifo_size = sizeof(*cmd); - cmd = kmalloc(fifo_size, GFP_KERNEL); - if (unlikely(cmd == NULL)) { - DRM_ERROR("Failed to allocate temporary cmd buffer.\n"); + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); + if (!cmd) { + DRM_ERROR("Out of fifo space for dirty framebuffer command.\n"); return -ENOMEM; } - memset(cmd, 0, fifo_size); cmd->header = SVGA_CMD_DEFINE_GMRFB; cmd->body.format.bitsPerPixel = framebuffer->base.bits_per_pixel; cmd->body.format.colorDepth = depth; cmd->body.format.reserved = 0; cmd->body.bytesPerLine = framebuffer->base.pitches[0]; - cmd->body.ptr.gmrId = framebuffer->user_handle; - cmd->body.ptr.offset = 0; + /* Buffer is reserved in vram or GMR */ + vmw_bo_get_guest_ptr(&buf->base, &cmd->body.ptr); + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + + return 0; +} + +/** + * vmw_sou_surface_fifo_commit - Callback to fill in and submit a + * blit surface to screen command. + * + * @dirty: The closure structure. + * + * Fills in the missing fields in the command, and translates the cliprects + * to match the destination bounding box encoded. + */ +static void vmw_sou_surface_fifo_commit(struct vmw_kms_dirty *dirty) +{ + struct vmw_kms_sou_surface_dirty *sdirty = + container_of(dirty, typeof(*sdirty), base); + struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd; + s32 trans_x = dirty->unit->crtc.x - sdirty->dst_x; + s32 trans_y = dirty->unit->crtc.y - sdirty->dst_y; + size_t region_size = dirty->num_hits * sizeof(SVGASignedRect); + SVGASignedRect *blit = (SVGASignedRect *) &cmd[1]; + int i; + + cmd->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN; + cmd->header.size = sizeof(cmd->body) + region_size; + + /* + * Use the destination bounding box to specify destination - and + * source bounding regions. + */ + cmd->body.destRect.left = sdirty->left; + cmd->body.destRect.right = sdirty->right; + cmd->body.destRect.top = sdirty->top; + cmd->body.destRect.bottom = sdirty->bottom; + + cmd->body.srcRect.left = sdirty->left + trans_x; + cmd->body.srcRect.right = sdirty->right + trans_x; + cmd->body.srcRect.top = sdirty->top + trans_y; + cmd->body.srcRect.bottom = sdirty->bottom + trans_y; + + cmd->body.srcImage.sid = sdirty->sid; + cmd->body.destScreenId = dirty->unit->unit; + + /* Blits are relative to the destination rect. Translate. */ + for (i = 0; i < dirty->num_hits; ++i, ++blit) { + blit->left -= sdirty->left; + blit->right -= sdirty->left; + blit->top -= sdirty->top; + blit->bottom -= sdirty->top; + } + + vmw_fifo_commit(dirty->dev_priv, region_size + sizeof(*cmd)); + + sdirty->left = sdirty->top = S32_MAX; + sdirty->right = sdirty->bottom = S32_MIN; +} + +/** + * vmw_sou_surface_clip - Callback to encode a blit surface to screen cliprect. + * + * @dirty: The closure structure + * + * Encodes a SVGASignedRect cliprect and updates the bounding box of the + * BLIT_SURFACE_TO_SCREEN command. + */ +static void vmw_sou_surface_clip(struct vmw_kms_dirty *dirty) +{ + struct vmw_kms_sou_surface_dirty *sdirty = + container_of(dirty, typeof(*sdirty), base); + struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd; + SVGASignedRect *blit = (SVGASignedRect *) &cmd[1]; + + /* Destination rect. */ + blit += dirty->num_hits; + blit->left = dirty->unit_x1; + blit->top = dirty->unit_y1; + blit->right = dirty->unit_x2; + blit->bottom = dirty->unit_y2; + + /* Destination bounding box */ + sdirty->left = min_t(s32, sdirty->left, dirty->unit_x1); + sdirty->top = min_t(s32, sdirty->top, dirty->unit_y1); + sdirty->right = max_t(s32, sdirty->right, dirty->unit_x2); + sdirty->bottom = max_t(s32, sdirty->bottom, dirty->unit_y2); + + dirty->num_hits++; +} + +/** + * vmw_kms_sou_do_surface_dirty - Dirty part of a surface backed framebuffer + * + * @dev_priv: Pointer to the device private structure. + * @framebuffer: Pointer to the surface-buffer backed framebuffer. + * @clips: Array of clip rects. Either @clips or @vclips must be NULL. + * @vclips: Alternate array of clip rects. Either @clips or @vclips must + * be NULL. + * @srf: Pointer to surface to blit from. If NULL, the surface attached + * to @framebuffer will be used. + * @dest_x: X coordinate offset to align @srf with framebuffer coordinates. + * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates. + * @num_clips: Number of clip rects in @clips. + * @inc: Increment to use when looping over @clips. + * @out_fence: If non-NULL, will return a ref-counted pointer to a + * struct vmw_fence_obj. The returned fence pointer may be NULL in which + * case the device has already synchronized. + * + * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * interrupted. + */ +int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + struct drm_clip_rect *clips, + struct drm_vmw_rect *vclips, + struct vmw_resource *srf, + s32 dest_x, + s32 dest_y, + unsigned num_clips, int inc, + struct vmw_fence_obj **out_fence) +{ + struct vmw_framebuffer_surface *vfbs = + container_of(framebuffer, typeof(*vfbs), base); + struct vmw_kms_sou_surface_dirty sdirty; + int ret; + + if (!srf) + srf = &vfbs->surface->res; + + ret = vmw_kms_helper_resource_prepare(srf, true); + if (ret) + return ret; + + sdirty.base.fifo_commit = vmw_sou_surface_fifo_commit; + sdirty.base.clip = vmw_sou_surface_clip; + sdirty.base.dev_priv = dev_priv; + sdirty.base.fifo_reserve_size = sizeof(struct vmw_kms_sou_dirty_cmd) + + sizeof(SVGASignedRect) * num_clips; - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, - fifo_size, 0, 0, NULL, NULL); + sdirty.sid = srf->id; + sdirty.left = sdirty.top = S32_MAX; + sdirty.right = sdirty.bottom = S32_MIN; + sdirty.dst_x = dest_x; + sdirty.dst_y = dest_y; - kfree(cmd); + ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, + dest_x, dest_y, num_clips, inc, + &sdirty.base); + vmw_kms_helper_resource_finish(srf, out_fence); return ret; } -int vmw_kms_sou_do_dmabuf_dirty(struct drm_file *file_priv, - struct vmw_private *dev_priv, +/** + * vmw_sou_dmabuf_fifo_commit - Callback to submit a set of readback clips. + * + * @dirty: The closure structure. + * + * Commits a previously built command buffer of readback clips. + */ +static void vmw_sou_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) +{ + vmw_fifo_commit(dirty->dev_priv, + sizeof(struct vmw_kms_sou_dmabuf_blit) * + dirty->num_hits); +} + +/** + * vmw_sou_dmabuf_clip - Callback to encode a readback cliprect. + * + * @dirty: The closure structure + * + * Encodes a BLIT_GMRFB_TO_SCREEN cliprect. + */ +static void vmw_sou_dmabuf_clip(struct vmw_kms_dirty *dirty) +{ + struct vmw_kms_sou_dmabuf_blit *blit = dirty->cmd; + + blit += dirty->num_hits; + blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; + blit->body.destScreenId = dirty->unit->unit; + blit->body.srcOrigin.x = dirty->fb_x; + blit->body.srcOrigin.y = dirty->fb_y; + blit->body.destRect.left = dirty->unit_x1; + blit->body.destRect.top = dirty->unit_y1; + blit->body.destRect.right = dirty->unit_x2; + blit->body.destRect.bottom = dirty->unit_y2; + dirty->num_hits++; +} + +/** + * vmw_kms_do_dmabuf_dirty - Dirty part of a dma-buffer backed framebuffer + * + * @dev_priv: Pointer to the device private structure. + * @framebuffer: Pointer to the dma-buffer backed framebuffer. + * @clips: Array of clip rects. + * @num_clips: Number of clip rects in @clips. + * @increment: Increment to use when looping over @clips. + * @interruptible: Whether to perform waits interruptible if possible. + * @out_fence: If non-NULL, will return a ref-counted pointer to a + * struct vmw_fence_obj. The returned fence pointer may be NULL in which + * case the device has already synchronized. + * + * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * interrupted. + */ +int vmw_kms_sou_do_dmabuf_dirty(struct vmw_private *dev_priv, struct vmw_framebuffer *framebuffer, - unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips, int increment, + bool interruptible, struct vmw_fence_obj **out_fence) { - struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; - struct drm_clip_rect *clips_ptr; - int i, k, num_units, ret; - struct drm_crtc *crtc; - size_t fifo_size; + struct vmw_dma_buffer *buf = + container_of(framebuffer, struct vmw_framebuffer_dmabuf, + base)->buffer; + struct vmw_kms_dirty dirty; + int ret; - struct { - uint32_t header; - SVGAFifoCmdBlitGMRFBToScreen body; - } *blits; + ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible, + false); + if (ret) + return ret; - ret = do_dmabuf_define_gmrfb(file_priv, dev_priv, framebuffer); + ret = do_dmabuf_define_gmrfb(dev_priv, framebuffer); if (unlikely(ret != 0)) - return ret; /* define_gmrfb prints warnings */ + goto out_revert; - fifo_size = sizeof(*blits) * num_clips; - blits = kmalloc(fifo_size, GFP_KERNEL); - if (unlikely(blits == NULL)) { - DRM_ERROR("Failed to allocate temporary cmd buffer.\n"); - return -ENOMEM; - } + dirty.fifo_commit = vmw_sou_dmabuf_fifo_commit; + dirty.clip = vmw_sou_dmabuf_clip; + dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_dmabuf_blit) * + num_clips; + ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, NULL, + 0, 0, num_clips, increment, &dirty); + vmw_kms_helper_buffer_finish(dev_priv, NULL, buf, out_fence, NULL); - num_units = 0; - list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->primary->fb != &framebuffer->base) - continue; - units[num_units++] = vmw_crtc_to_du(crtc); - } + return ret; - for (k = 0; k < num_units; k++) { - struct vmw_display_unit *unit = units[k]; - int hit_num = 0; - - clips_ptr = clips; - for (i = 0; i < num_clips; i++, clips_ptr += increment) { - int clip_x1 = clips_ptr->x1 - unit->crtc.x; - int clip_y1 = clips_ptr->y1 - unit->crtc.y; - int clip_x2 = clips_ptr->x2 - unit->crtc.x; - int clip_y2 = clips_ptr->y2 - unit->crtc.y; - int move_x, move_y; - - /* skip any crtcs that misses the clip region */ - if (clip_x1 >= unit->crtc.mode.hdisplay || - clip_y1 >= unit->crtc.mode.vdisplay || - clip_x2 <= 0 || clip_y2 <= 0) - continue; - - /* clip size to crtc size */ - clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay); - clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay); - - /* translate both src and dest to bring clip into screen */ - move_x = min_t(int, clip_x1, 0); - move_y = min_t(int, clip_y1, 0); - - /* actual translate done here */ - blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; - blits[hit_num].body.destScreenId = unit->unit; - blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x; - blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y; - blits[hit_num].body.destRect.left = clip_x1 - move_x; - blits[hit_num].body.destRect.top = clip_y1 - move_y; - blits[hit_num].body.destRect.right = clip_x2; - blits[hit_num].body.destRect.bottom = clip_y2; - hit_num++; - } - - /* no clips hit the crtc */ - if (hit_num == 0) - continue; - - /* only return the last fence */ - if (out_fence && *out_fence) - vmw_fence_obj_unreference(out_fence); - - fifo_size = sizeof(*blits) * hit_num; - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, blits, - fifo_size, 0, 0, NULL, out_fence); +out_revert: + vmw_kms_helper_buffer_revert(buf); - if (unlikely(ret != 0)) - break; - } + return ret; +} - kfree(blits); - return ret; +/** + * vmw_sou_readback_fifo_commit - Callback to submit a set of readback clips. + * + * @dirty: The closure structure. + * + * Commits a previously built command buffer of readback clips. + */ +static void vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty) +{ + vmw_fifo_commit(dirty->dev_priv, + sizeof(struct vmw_kms_sou_readback_blit) * + dirty->num_hits); } +/** + * vmw_sou_readback_clip - Callback to encode a readback cliprect. + * + * @dirty: The closure structure + * + * Encodes a BLIT_SCREEN_TO_GMRFB cliprect. + */ +static void vmw_sou_readback_clip(struct vmw_kms_dirty *dirty) +{ + struct vmw_kms_sou_readback_blit *blit = dirty->cmd; + + blit += dirty->num_hits; + blit->header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB; + blit->body.srcScreenId = dirty->unit->unit; + blit->body.destOrigin.x = dirty->fb_x; + blit->body.destOrigin.y = dirty->fb_y; + blit->body.srcRect.left = dirty->unit_x1; + blit->body.srcRect.top = dirty->unit_y1; + blit->body.srcRect.right = dirty->unit_x2; + blit->body.srcRect.bottom = dirty->unit_y2; + dirty->num_hits++; +} + +/** + * vmw_kms_sou_readback - Perform a readback from the screen object system to + * a dma-buffer backed framebuffer. + * + * @dev_priv: Pointer to the device private structure. + * @file_priv: Pointer to a struct drm_file identifying the caller. + * Must be set to NULL if @user_fence_rep is NULL. + * @vfb: Pointer to the dma-buffer backed framebuffer. + * @user_fence_rep: User-space provided structure for fence information. + * Must be set to non-NULL if @file_priv is non-NULL. + * @vclips: Array of clip rects. + * @num_clips: Number of clip rects in @vclips. + * + * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * interrupted. + */ +int vmw_kms_sou_readback(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct drm_vmw_fence_rep __user *user_fence_rep, + struct drm_vmw_rect *vclips, + uint32_t num_clips) +{ + struct vmw_dma_buffer *buf = + container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; + struct vmw_kms_dirty dirty; + int ret; + + ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, true, false); + if (ret) + return ret; + + ret = do_dmabuf_define_gmrfb(dev_priv, vfb); + if (unlikely(ret != 0)) + goto out_revert; + + dirty.fifo_commit = vmw_sou_readback_fifo_commit; + dirty.clip = vmw_sou_readback_clip; + dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_readback_blit) * + num_clips; + ret = vmw_kms_helper_dirty(dev_priv, vfb, NULL, vclips, + 0, 0, num_clips, 1, &dirty); + vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL, + user_fence_rep); + + return ret; + +out_revert: + vmw_kms_helper_buffer_revert(buf); + + return ret; +} -- cgit v1.3-6-gb490 From 6bf6bf03b37b5ba0f3399fa9bb3d62edfa117c87 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 26 Jun 2015 02:22:40 -0700 Subject: drm/vmwgfx: Convert screen targets to new helpers v3 Also implements the missing readback function and fixes page flip in case of no event. v2: - Adapt to the work done for screen targets for 2d, in particular Handle proxy surface updates. - Remove execbuf quirks since we now use fifo reserve / commit. - Revert the initial placement of vmw dma buffers. v3: Address review comments. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 5 - drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 24 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 149 ++++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 37 +- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 996 ++++++++++++------------------- 6 files changed, 534 insertions(+), 679 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d60ae207136c..d6b247b1994a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -343,9 +343,6 @@ enum vmw_display_unit_type { }; -#define VMW_QUIRK_DST_SID_OK (1U << 0) -#define VMW_QUIRK_SRC_SID_OK (1U << 1) - struct vmw_sw_context{ struct drm_open_hash res_ht; bool res_ht_initialized; @@ -368,7 +365,6 @@ struct vmw_sw_context{ struct vmw_resource *error_resource; struct vmw_ctx_binding_state staged_bindings; struct list_head staged_cmd_res; - uint32_t quirks; }; struct vmw_legacy_display; @@ -842,7 +838,6 @@ extern int vmw_execbuf_process(struct drm_file *file_priv, void *kernel_commands, uint32_t command_size, uint64_t throttle_us, - uint32_t quirks, struct drm_vmw_fence_rep __user *user_fence_rep, struct vmw_fence_obj **out_fence); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 698a0e2add53..64dba53ca54c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -675,16 +675,11 @@ static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv, cmd = container_of(header, struct vmw_sid_cmd, header); - if (!(sw_context->quirks & VMW_QUIRK_SRC_SID_OK)) { - ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, - user_surface_converter, - &cmd->body.src.sid, NULL); - if (ret != 0) - return ret; - } - - if (sw_context->quirks & VMW_QUIRK_DST_SID_OK) - return 0; + ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, + user_surface_converter, + &cmd->body.src.sid, NULL); + if (ret) + return ret; return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, @@ -1266,9 +1261,6 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv, if (unlikely(suffix->maximumOffset > bo_size)) suffix->maximumOffset = bo_size; - if (sw_context->quirks & VMW_QUIRK_DST_SID_OK) - goto out_no_surface; - ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, &cmd->dma.host.sid, NULL); @@ -1507,9 +1499,6 @@ static int vmw_cmd_update_gb_image(struct vmw_private *dev_priv, cmd = container_of(header, struct vmw_gb_surface_cmd, header); - if (sw_context->quirks & VMW_QUIRK_SRC_SID_OK) - return 0; - return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface, user_surface_converter, &cmd->body.image.sid, NULL); @@ -2554,7 +2543,6 @@ int vmw_execbuf_process(struct drm_file *file_priv, void *kernel_commands, uint32_t command_size, uint64_t throttle_us, - uint32_t quirks, struct drm_vmw_fence_rep __user *user_fence_rep, struct vmw_fence_obj **out_fence) { @@ -2609,7 +2597,6 @@ int vmw_execbuf_process(struct drm_file *file_priv, sw_context->fp = vmw_fpriv(file_priv); sw_context->cur_reloc = 0; sw_context->cur_val_buf = 0; - sw_context->quirks = quirks; INIT_LIST_HEAD(&sw_context->resource_list); sw_context->cur_query_bo = dev_priv->pinned_bo; sw_context->last_query_ctx = NULL; @@ -2921,7 +2908,6 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ret = vmw_execbuf_process(file_priv, dev_priv, (void __user *)(unsigned long)arg->commands, NULL, arg->command_size, arg->throttle_us, - 0, (void __user *)(unsigned long)arg->fence_rep, NULL); ttm_read_unlock(&dev_priv->reservation_sem); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 5901d32d0273..234a3cef1c25 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -427,10 +427,9 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, clips, NULL, NULL, 0, 0, num_clips, inc, NULL); else - ret = vmw_kms_stdu_do_surface_dirty(dev_priv, file_priv, - &vfbs->base, - clips, num_clips, - inc); + ret = vmw_kms_stdu_surface_dirty(dev_priv, &vfbs->base, + clips, NULL, NULL, 0, 0, + num_clips, inc, NULL); vmw_fifo_flush(dev_priv, false); ttm_read_unlock(&dev_priv->reservation_sem); @@ -467,10 +466,14 @@ int vmw_kms_readback(struct vmw_private *dev_priv, case vmw_du_screen_object: return vmw_kms_sou_readback(dev_priv, file_priv, vfb, user_fence_rep, vclips, num_clips); + case vmw_du_screen_target: + return vmw_kms_stdu_dma(dev_priv, file_priv, vfb, + user_fence_rep, NULL, vclips, num_clips, + 1, false, true); default: WARN_ONCE(true, "Readback called with invalid display system.\n"); - } +} return -ENOSYS; } @@ -632,20 +635,23 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, increment = 2; } - if (dev_priv->ldu_priv) { - ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, - flags, color, - clips, num_clips, increment); - } else if (dev_priv->active_display_unit == vmw_du_screen_object) { + switch (dev_priv->active_display_unit) { + case vmw_du_screen_target: + ret = vmw_kms_stdu_dma(dev_priv, NULL, &vfbd->base, NULL, + clips, NULL, num_clips, increment, + true, true); + break; + case vmw_du_screen_object: ret = vmw_kms_sou_do_dmabuf_dirty(dev_priv, &vfbd->base, clips, num_clips, increment, true, NULL); - } else { - ret = vmw_kms_stdu_do_surface_dirty(dev_priv, file_priv, - &vfbd->base, - clips, num_clips, - increment); + break; + default: + ret = -ENOSYS; + WARN_ONCE(true, + "Dirty called with invalid display system.\n"); + break; } vmw_fifo_flush(dev_priv, false); @@ -721,9 +727,9 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, { uint32_t format; struct drm_vmw_size content_base_size; + struct vmw_resource *res; int ret; - switch (mode_cmd->depth) { case 32: case 24: @@ -762,15 +768,18 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, return ret; } - /* Use the same MOB backing for surface */ - vmw_dmabuf_reference(dmabuf_mob); - - (*srf_out)->res.backup = dmabuf_mob; + res = &(*srf_out)->res; - /* FIXME: Waiting for fbdev rework to do a proper reserve/pin */ - ret = vmw_resource_validate(&(*srf_out)->res); + /* Reserve and switch the backing mob. */ + mutex_lock(&res->dev_priv->cmdbuf_mutex); + (void) vmw_resource_reserve(res, false, true); + vmw_dmabuf_unreference(&res->backup); + res->backup = vmw_dmabuf_reference(dmabuf_mob); + res->backup_offset = 0; + vmw_resource_unreserve(res, NULL, 0); + mutex_unlock(&res->dev_priv->cmdbuf_mutex); - return ret; + return 0; } @@ -987,6 +996,7 @@ int vmw_kms_generic_present(struct vmw_private *dev_priv, num_clips, 1, NULL); } + int vmw_kms_present(struct vmw_private *dev_priv, struct drm_file *file_priv, struct vmw_framebuffer *vfb, @@ -998,13 +1008,23 @@ int vmw_kms_present(struct vmw_private *dev_priv, { int ret; - if (dev_priv->active_display_unit == vmw_du_screen_target) - ret = vmw_kms_stdu_present(dev_priv, file_priv, vfb, sid, - destX, destY, clips, num_clips); - else - ret = vmw_kms_generic_present(dev_priv, file_priv, vfb, - surface, sid, destX, destY, - clips, num_clips); + switch (dev_priv->active_display_unit) { + case vmw_du_screen_target: + ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, clips, + &surface->res, destX, destY, + num_clips, 1, NULL); + break; + case vmw_du_screen_object: + ret = vmw_kms_generic_present(dev_priv, file_priv, vfb, surface, + sid, destX, destY, clips, + num_clips); + break; + default: + WARN_ONCE(true, + "Present called with invalid display system.\n"); + ret = -ENOSYS; + break; + } if (ret) return ret; @@ -1882,3 +1902,72 @@ void vmw_kms_helper_resource_finish(struct vmw_resource *res, vmw_resource_unreserve(res, NULL, 0); mutex_unlock(&res->dev_priv->cmdbuf_mutex); } + +/** + * vmw_kms_update_proxy - Helper function to update a proxy surface from + * its backing MOB. + * + * @res: Pointer to the surface resource + * @clips: Clip rects in framebuffer (surface) space. + * @num_clips: Number of clips in @clips. + * @increment: Integer with which to increment the clip counter when looping. + * Used to skip a predetermined number of clip rects. + * + * This function makes sure the proxy surface is updated from its backing MOB + * using the region given by @clips. The surface resource @res and its backing + * MOB needs to be reserved and validated on call. + */ +int vmw_kms_update_proxy(struct vmw_resource *res, + const struct drm_clip_rect *clips, + unsigned num_clips, + int increment) +{ + struct vmw_private *dev_priv = res->dev_priv; + struct drm_vmw_size *size = &vmw_res_to_srf(res)->base_size; + struct { + SVGA3dCmdHeader header; + SVGA3dCmdUpdateGBImage body; + } *cmd; + SVGA3dBox *box; + size_t copy_size = 0; + int i; + + if (!clips) + return 0; + + cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd) * num_clips); + if (!cmd) { + DRM_ERROR("Couldn't reserve fifo space for proxy surface " + "update.\n"); + return -ENOMEM; + } + + for (i = 0; i < num_clips; ++i, clips += increment, ++cmd) { + box = &cmd->body.box; + + cmd->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; + cmd->header.size = sizeof(cmd->body); + cmd->body.image.sid = res->id; + cmd->body.image.face = 0; + cmd->body.image.mipmap = 0; + + if (clips->x1 > size->width || clips->x2 > size->width || + clips->y1 > size->height || clips->y2 > size->height) { + DRM_ERROR("Invalid clips outsize of framebuffer.\n"); + return -EINVAL; + } + + box->x = clips->x1; + box->y = clips->y1; + box->z = 0; + box->w = clips->x2 - clips->x1; + box->h = clips->y2 - clips->y1; + box->d = 1; + + copy_size += sizeof(*cmd); + } + + vmw_fifo_commit(dev_priv, copy_size); + + return 0; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 8a8203c66adc..f941f92338a6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -239,6 +239,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv, struct drm_vmw_rect *vclips, uint32_t num_clips); + /* * Legacy display unit functions - vmwgfx_ldu.c */ @@ -249,6 +250,10 @@ int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips, int increment); +int vmw_kms_update_proxy(struct vmw_resource *res, + const struct drm_clip_rect *clips, + unsigned num_clips, + int increment); /* * Screen Objects display functions - vmwgfx_scrn.c @@ -282,17 +287,25 @@ int vmw_kms_sou_readback(struct vmw_private *dev_priv, */ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv); int vmw_kms_stdu_close_display(struct vmw_private *dev_priv); -int vmw_kms_stdu_do_surface_dirty(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *framebuffer, - struct drm_clip_rect *clips, - unsigned num_clips, int increment); -int vmw_kms_stdu_present(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *vfb, - uint32_t user_handle, - int32_t dest_x, int32_t dest_y, - struct drm_vmw_rect *clips, - uint32_t num_clips); +int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + struct drm_clip_rect *clips, + struct drm_vmw_rect *vclips, + struct vmw_resource *srf, + s32 dest_x, + s32 dest_y, + unsigned num_clips, int inc, + struct vmw_fence_obj **out_fence); +int vmw_kms_stdu_dma(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct drm_vmw_fence_rep __user *user_fence_rep, + struct drm_clip_rect *clips, + struct drm_vmw_rect *vclips, + uint32_t num_clips, + int increment, + bool to_surface, + bool interruptible); + #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 521f1947b4e9..69b471af0130 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -497,7 +497,7 @@ int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv, ret = vmw_dmabuf_init(dev_priv, &user_bo->dma, size, (dev_priv->has_mob) ? - &vmw_mob_placement : + &vmw_sys_placement : &vmw_vram_sys_placement, true, &vmw_user_dmabuf_destroy); if (unlikely(ret != 0)) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index becf9650c228..493fcd1eb803 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright © 2014 VMware, Inc., Palo Alto, CA., USA + * COPYRIGHT © 2014 VMware, Inc., Palo Alto, CA., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -44,6 +44,47 @@ enum stdu_content_type { SEPARATE_DMA }; +/** + * struct vmw_stdu_dirty - closure structure for the update functions + * + * @base: The base type we derive from. Used by vmw_kms_helper_dirty(). + * @transfer: Transfer direction for DMA command. + * @left: Left side of bounding box. + * @right: Right side of bounding box. + * @top: Top side of bounding box. + * @bottom: Bottom side of bounding box. + * @buf: DMA buffer when DMA-ing between buffer and screen targets. + * @sid: Surface ID when copying between surface and screen targets. + */ +struct vmw_stdu_dirty { + struct vmw_kms_dirty base; + SVGA3dTransferType transfer; + s32 left, right, top, bottom; + u32 pitch; + union { + struct vmw_dma_buffer *buf; + u32 sid; + }; +}; + +/* + * SVGA commands that are used by this code. Please see the device headers + * for explanation. + */ +struct vmw_stdu_update { + SVGA3dCmdHeader header; + SVGA3dCmdUpdateGBScreenTarget body; +}; + +struct vmw_stdu_dma { + SVGA3dCmdHeader header; + SVGA3dCmdSurfaceDMA body; +}; + +struct vmw_stdu_surface_copy { + SVGA3dCmdHeader header; + SVGA3dCmdSurfaceCopy body; +}; /** @@ -139,254 +180,6 @@ static void vmw_stdu_crtc_destroy(struct drm_crtc *crtc) vmw_stdu_destroy(vmw_crtc_to_stdu(crtc)); } - - -/** - * vmw_stdu_dma_update - Update DMA buf dirty region on the SVGA device - * - * @dev_priv: VMW DRM device - * @file_priv: Pointer to a drm file private structure - * @vfbs: VMW framebuffer surface that may need a DMA buf update - * @x: top/left corner of the content area to blit from - * @y: top/left corner of the content area to blit from - * @width: width of the blit area - * @height: height of the blit area - * - * The SVGA device may have the DMA buf cached, so before letting the - * device use it as the source image for a subsequent operation, we - * update the cached copy. - * - * RETURNs: - * 0 on success, error code on failure - */ -static int vmw_stdu_dma_update(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer_surface *vfbs, - uint32_t x, uint32_t y, - uint32_t width, uint32_t height) -{ - size_t fifo_size; - struct { - SVGA3dCmdHeader header; - SVGA3dCmdUpdateGBImage body; - } img_update_cmd; - - - /* Only need to do this if the surface is a DMA buf proxy */ - if (!vfbs->is_dmabuf_proxy) - return 0; - - fifo_size = sizeof(img_update_cmd); - - memset(&img_update_cmd, 0, fifo_size); - img_update_cmd.header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; - img_update_cmd.header.size = sizeof(img_update_cmd.body); - - img_update_cmd.body.image.sid = vfbs->surface->res.id; - - img_update_cmd.body.box.x = x; - img_update_cmd.body.box.y = y; - img_update_cmd.body.box.w = width; - img_update_cmd.body.box.h = height; - img_update_cmd.body.box.d = 1; - - return vmw_execbuf_process(file_priv, dev_priv, NULL, - (void *) &img_update_cmd, - fifo_size, 0, VMW_QUIRK_SRC_SID_OK, - NULL, NULL); -} - - - -/** - * vmw_stdu_content_copy - copies an area from the content to display surface - * - * @dev_priv: VMW DRM device - * @file_priv: Pointer to a drm file private structure - * @stdu: STDU whose display surface will be blitted to - * @content_x: top/left corner of the content area to blit from - * @content_y: top/left corner of the content area to blit from - * @width: width of the blit area - * @height: height of the blit area - * @display_x: top/left corner of the display area to blit to - * @display_y: top/left corner of the display area to blit to - * - * Copies an area from the content surface to the display surface. - * - * RETURNs: - * 0 on success, error code on failure - */ -static int vmw_stdu_content_copy(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_screen_target_display_unit *stdu, - uint32_t content_x, uint32_t content_y, - uint32_t width, uint32_t height, - uint32_t display_x, uint32_t display_y) -{ - struct vmw_framebuffer_surface *content_vfbs; - size_t fifo_size; - int ret; - void *cmd; - u32 quirks = VMW_QUIRK_DST_SID_OK; - - struct { - SVGA3dCmdHeader header; - SVGA3dCmdSurfaceDMA body; - SVGA3dCopyBox area; - SVGA3dCmdSurfaceDMASuffix suffix; - } surface_dma_cmd; - - struct { - SVGA3dCmdHeader header; - SVGA3dCmdSurfaceCopy body; - SVGA3dCopyBox area; - } surface_cpy_cmd; - - - /* - * Can only copy if content and display surfaces exist and are not - * the same surface - */ - if (stdu->display_srf == NULL || stdu->content_fb == NULL || - stdu->content_fb_type == SAME_AS_DISPLAY) { - return -EINVAL; - } - - - if (stdu->content_fb_type == SEPARATE_DMA) { - struct vmw_framebuffer *content_vfb; - struct drm_vmw_size cur_size = {0}; - const struct svga3d_surface_desc *desc; - enum SVGA3dSurfaceFormat format; - SVGA3dCmdSurfaceDMASuffix *suffix; - SVGAGuestPtr ptr; - - - content_vfb = vmw_framebuffer_to_vfb(stdu->content_fb); - - cur_size.width = width; - cur_size.height = height; - cur_size.depth = 1; - - /* Derive a SVGA3dSurfaceFormat for the DMA buf */ - switch (content_vfb->base.bits_per_pixel) { - case 32: - format = SVGA3D_A8R8G8B8; - break; - case 24: - format = SVGA3D_X8R8G8B8; - break; - case 16: - format = SVGA3D_R5G6B5; - break; - case 15: - format = SVGA3D_A1R5G5B5; - break; - default: - DRM_ERROR("Invalid color depth: %d\n", - content_vfb->base.depth); - return -EINVAL; - } - - desc = svga3dsurface_get_desc(format); - - - fifo_size = sizeof(surface_dma_cmd); - - memset(&surface_dma_cmd, 0, fifo_size); - - ptr.gmrId = content_vfb->user_handle; - ptr.offset = 0; - - surface_dma_cmd.header.id = SVGA_3D_CMD_SURFACE_DMA; - surface_dma_cmd.header.size = sizeof(surface_dma_cmd.body) + - sizeof(surface_dma_cmd.area) + - sizeof(surface_dma_cmd.suffix); - - surface_dma_cmd.body.guest.ptr = ptr; - surface_dma_cmd.body.guest.pitch = stdu->content_fb->pitches[0]; - surface_dma_cmd.body.host.sid = stdu->display_srf->res.id; - surface_dma_cmd.body.host.face = 0; - surface_dma_cmd.body.host.mipmap = 0; - surface_dma_cmd.body.transfer = SVGA3D_WRITE_HOST_VRAM; - - surface_dma_cmd.area.srcx = content_x; - surface_dma_cmd.area.srcy = content_y; - surface_dma_cmd.area.x = display_x; - surface_dma_cmd.area.y = display_y; - surface_dma_cmd.area.d = 1; - surface_dma_cmd.area.w = width; - surface_dma_cmd.area.h = height; - - suffix = &surface_dma_cmd.suffix; - - suffix->suffixSize = sizeof(*suffix); - suffix->maximumOffset = svga3dsurface_get_image_buffer_size( - desc, - &cur_size, - stdu->content_fb->pitches[0]); - - cmd = (void *) &surface_dma_cmd; - } else { - u32 src_id; - - - content_vfbs = vmw_framebuffer_to_vfbs(stdu->content_fb); - - if (content_vfbs->is_dmabuf_proxy) { - ret = vmw_stdu_dma_update(dev_priv, file_priv, - content_vfbs, - content_x, content_y, - width, height); - - if (ret != 0) { - DRM_ERROR("Failed to update cached DMA buf\n"); - return ret; - } - - quirks |= VMW_QUIRK_SRC_SID_OK; - src_id = content_vfbs->surface->res.id; - } else { - struct vmw_framebuffer *content_vfb; - - content_vfb = vmw_framebuffer_to_vfb(stdu->content_fb); - src_id = content_vfb->user_handle; - } - - fifo_size = sizeof(surface_cpy_cmd); - - memset(&surface_cpy_cmd, 0, fifo_size); - - surface_cpy_cmd.header.id = SVGA_3D_CMD_SURFACE_COPY; - surface_cpy_cmd.header.size = sizeof(surface_cpy_cmd.body) + - sizeof(surface_cpy_cmd.area); - - surface_cpy_cmd.body.src.sid = src_id; - surface_cpy_cmd.body.dest.sid = stdu->display_srf->res.id; - - surface_cpy_cmd.area.srcx = content_x; - surface_cpy_cmd.area.srcy = content_y; - surface_cpy_cmd.area.x = display_x; - surface_cpy_cmd.area.y = display_y; - surface_cpy_cmd.area.d = 1; - surface_cpy_cmd.area.w = width; - surface_cpy_cmd.area.h = height; - - cmd = (void *) &surface_cpy_cmd; - } - - - - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, - (void *) cmd, - fifo_size, 0, quirks, - NULL, NULL); - - return ret; -} - - - /** * vmw_stdu_define_st - Defines a Screen Target * @@ -487,108 +280,56 @@ static int vmw_stdu_bind_st(struct vmw_private *dev_priv, return 0; } +/** + * vmw_stdu_populate_update - populate an UPDATE_GB_SCREENTARGET command with a + * bounding box. + * + * @cmd: Pointer to command stream. + * @unit: Screen target unit. + * @left: Left side of bounding box. + * @right: Right side of bounding box. + * @top: Top side of bounding box. + * @bottom: Bottom side of bounding box. + */ +static void vmw_stdu_populate_update(void *cmd, int unit, + s32 left, s32 right, s32 top, s32 bottom) +{ + struct vmw_stdu_update *update = cmd; + + update->header.id = SVGA_3D_CMD_UPDATE_GB_SCREENTARGET; + update->header.size = sizeof(update->body); + update->body.stid = unit; + update->body.rect.x = left; + update->body.rect.y = top; + update->body.rect.w = right - left; + update->body.rect.h = bottom - top; +} /** - * vmw_stdu_update_st - Updates a Screen Target + * vmw_stdu_update_st - Full update of a Screen Target * * @dev_priv: VMW DRM device - * @file_priv: Pointer to DRM file private structure. Set to NULL when - * we want to blank display. * @stdu: display unit affected - * @update_area: area that needs to be updated * * This function needs to be called whenever the content of a screen - * target changes. - * If the display and content buffers are different, then this function does - * a blit first from the content buffer to the display buffer before issuing - * the Screen Target update command. + * target has changed completely. Typically as a result of a backing + * surface change. * * RETURNS: * 0 on success, error code on failure */ static int vmw_stdu_update_st(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_screen_target_display_unit *stdu, - struct drm_clip_rect *update_area) + struct vmw_screen_target_display_unit *stdu) { - u32 width, height; - u32 display_update_x, display_update_y; - unsigned short display_x1, display_y1, display_x2, display_y2; - int ret; - - struct { - SVGA3dCmdHeader header; - SVGA3dCmdUpdateGBScreenTarget body; - } *cmd; - + struct vmw_stdu_update *cmd; + struct drm_crtc *crtc = &stdu->base.crtc; if (!stdu->defined) { DRM_ERROR("No screen target defined"); return -EINVAL; } - /* Display coordinates relative to its position in content surface */ - display_x1 = stdu->base.crtc.x; - display_y1 = stdu->base.crtc.y; - display_x2 = display_x1 + stdu->display_srf->base_size.width; - display_y2 = display_y1 + stdu->display_srf->base_size.height; - - /* Do nothing if the update area is outside of the display surface */ - if (update_area->x2 <= display_x1 || update_area->x1 >= display_x2 || - update_area->y2 <= display_y1 || update_area->y1 >= display_y2) - return 0; - - /* The top-left hand corner of the update area in display surface */ - display_update_x = max(update_area->x1 - display_x1, 0); - display_update_y = max(update_area->y1 - display_y1, 0); - - width = min(update_area->x2, display_x2) - - max(update_area->x1, display_x1); - height = min(update_area->y2, display_y2) - - max(update_area->y1, display_y1); - - /* - * If content is on a separate surface, then copy the dirty area to - * the display surface - */ - if (file_priv && stdu->content_fb_type != SAME_AS_DISPLAY) { - - ret = vmw_stdu_content_copy(dev_priv, file_priv, - stdu, - max(update_area->x1, display_x1), - max(update_area->y1, display_y1), - width, height, - display_update_x, display_update_y); - if (unlikely(ret != 0)) { - DRM_ERROR("Failed to blit content\n"); - return ret; - } - } - - - /* - * If the display surface is the same as the content surface, then - * it may be backed by a DMA buf. If it is then we need to update - * the device's cached copy of the DMA buf before issuing the screen - * target update. - */ - if (file_priv && stdu->content_fb_type == SAME_AS_DISPLAY) { - struct vmw_framebuffer_surface *vfbs; - - vfbs = vmw_framebuffer_to_vfbs(stdu->content_fb); - ret = vmw_stdu_dma_update(dev_priv, file_priv, - vfbs, - max(update_area->x1, display_x1), - max(update_area->y1, display_y1), - width, height); - - if (ret != 0) { - DRM_ERROR("Failed to update cached DMA buffer\n"); - return ret; - } - } - cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); if (unlikely(cmd == NULL)) { @@ -596,14 +337,8 @@ static int vmw_stdu_update_st(struct vmw_private *dev_priv, return -ENOMEM; } - cmd->header.id = SVGA_3D_CMD_UPDATE_GB_SCREENTARGET; - cmd->header.size = sizeof(cmd->body); - - cmd->body.stid = stdu->base.unit; - cmd->body.rect.x = display_update_x; - cmd->body.rect.y = display_update_y; - cmd->body.rect.w = width; - cmd->body.rect.h = height; + vmw_stdu_populate_update(cmd, stdu->base.unit, 0, crtc->mode.hdisplay, + 0, crtc->mode.vdisplay); vmw_fifo_commit(dev_priv, sizeof(*cmd)); @@ -682,7 +417,6 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) struct drm_crtc *crtc; struct drm_encoder *encoder; struct drm_connector *connector; - struct drm_clip_rect update_area = {0}; int ret; @@ -728,12 +462,7 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) /* Update Screen Target, display will now be blank */ if (crtc->primary->fb) { - update_area.x2 = crtc->primary->fb->width; - update_area.y2 = crtc->primary->fb->height; - - ret = vmw_stdu_update_st(dev_priv, NULL, - stdu, - &update_area); + vmw_stdu_update_st(dev_priv, stdu); if (unlikely(ret != 0)) return ret; } @@ -852,7 +581,6 @@ static int vmw_stdu_crtc_set_config(struct drm_mode_set *set) goto err_unref_content; } - vmw_fb_off(dev_priv); vmw_svga_enable(dev_priv); /* @@ -919,17 +647,8 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, { struct vmw_private *dev_priv = vmw_priv(crtc->dev); struct vmw_screen_target_display_unit *stdu; - struct drm_file *file_priv; - struct drm_clip_rect update_area = {0}; int ret; - /* - * Temporarily don't support event == NULL. We need the - * @file_priv pointer! - */ - if (event == NULL) - return -EINVAL; - if (crtc == NULL) return -EINVAL; @@ -939,9 +658,6 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, stdu->content_fb = new_fb; if (stdu->display_srf) { - update_area.x2 = stdu->display_srf->base_size.width; - update_area.y2 = stdu->display_srf->base_size.height; - /* * If the display surface is the same as the content surface * then remove the reference @@ -961,7 +677,7 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, if (!new_fb) { /* Blanks the display */ - (void) vmw_stdu_update_st(dev_priv, NULL, stdu, &update_area); + (void) vmw_stdu_update_st(dev_priv, stdu); return 0; } @@ -982,16 +698,13 @@ static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc, } /* Update display surface: after this point everything is bound */ - update_area.x2 = stdu->display_srf->base_size.width; - update_area.y2 = stdu->display_srf->base_size.height; - - file_priv = event->base.file_priv; - ret = vmw_stdu_update_st(dev_priv, file_priv, stdu, &update_area); + ret = vmw_stdu_update_st(dev_priv, stdu); if (unlikely(ret != 0)) return ret; if (event) { struct vmw_fence_obj *fence = NULL; + struct drm_file *file_priv = event->base.file_priv; vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL); if (!fence) @@ -1016,6 +729,310 @@ err_out: } +/** + * vmw_stdu_dmabuf_clip - Callback to encode a suface DMA command cliprect + * + * @dirty: The closure structure. + * + * Encodes a surface DMA command cliprect and updates the bounding box + * for the DMA. + */ +static void vmw_stdu_dmabuf_clip(struct vmw_kms_dirty *dirty) +{ + struct vmw_stdu_dirty *ddirty = + container_of(dirty, struct vmw_stdu_dirty, base); + struct vmw_stdu_dma *cmd = dirty->cmd; + struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; + + blit += dirty->num_hits; + blit->srcx = dirty->fb_x; + blit->srcy = dirty->fb_y; + blit->x = dirty->unit_x1; + blit->y = dirty->unit_y1; + blit->d = 1; + blit->w = dirty->unit_x2 - dirty->unit_x1; + blit->h = dirty->unit_y2 - dirty->unit_y1; + dirty->num_hits++; + + if (ddirty->transfer != SVGA3D_WRITE_HOST_VRAM) + return; + + /* Destination bounding box */ + ddirty->left = min_t(s32, ddirty->left, dirty->unit_x1); + ddirty->top = min_t(s32, ddirty->top, dirty->unit_y1); + ddirty->right = max_t(s32, ddirty->right, dirty->unit_x2); + ddirty->bottom = max_t(s32, ddirty->bottom, dirty->unit_y2); +} + +/** + * vmw_stdu_dmabuf_fifo_commit - Callback to fill in and submit a DMA command. + * + * @dirty: The closure structure. + * + * Fills in the missing fields in a DMA command, and optionally encodes + * a screen target update command, depending on transfer direction. + */ +static void vmw_stdu_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty) +{ + struct vmw_stdu_dirty *ddirty = + container_of(dirty, struct vmw_stdu_dirty, base); + struct vmw_screen_target_display_unit *stdu = + container_of(dirty->unit, typeof(*stdu), base); + struct vmw_stdu_dma *cmd = dirty->cmd; + struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; + SVGA3dCmdSurfaceDMASuffix *suffix = + (SVGA3dCmdSurfaceDMASuffix *) &blit[dirty->num_hits]; + size_t blit_size = sizeof(*blit) * dirty->num_hits + sizeof(*suffix); + + if (!dirty->num_hits) { + vmw_fifo_commit(dirty->dev_priv, 0); + return; + } + + cmd->header.id = SVGA_3D_CMD_SURFACE_DMA; + cmd->header.size = sizeof(cmd->body) + blit_size; + vmw_bo_get_guest_ptr(&ddirty->buf->base, &cmd->body.guest.ptr); + cmd->body.guest.pitch = ddirty->pitch; + cmd->body.host.sid = stdu->display_srf->res.id; + cmd->body.host.face = 0; + cmd->body.host.mipmap = 0; + cmd->body.transfer = ddirty->transfer; + suffix->suffixSize = sizeof(*suffix); + suffix->maximumOffset = ddirty->buf->base.num_pages * PAGE_SIZE; + + if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) { + blit_size += sizeof(struct vmw_stdu_update); + + vmw_stdu_populate_update(&suffix[1], stdu->base.unit, + ddirty->left, ddirty->right, + ddirty->top, ddirty->bottom); + } + + vmw_fifo_commit(dirty->dev_priv, sizeof(*cmd) + blit_size); + + ddirty->left = ddirty->top = S32_MAX; + ddirty->right = ddirty->bottom = S32_MIN; +} + +/** + * vmw_kms_stdu_dma - Perform a DMA transfer between a dma-buffer backed + * framebuffer and the screen target system. + * + * @dev_priv: Pointer to the device private structure. + * @file_priv: Pointer to a struct drm-file identifying the caller. May be + * set to NULL, but then @user_fence_rep must also be set to NULL. + * @vfb: Pointer to the dma-buffer backed framebuffer. + * @clips: Array of clip rects. Either @clips or @vclips must be NULL. + * @vclips: Alternate array of clip rects. Either @clips or @vclips must + * be NULL. + * @num_clips: Number of clip rects in @clips or @vclips. + * @increment: Increment to use when looping over @clips or @vclips. + * @to_surface: Whether to DMA to the screen target system as opposed to + * from the screen target system. + * @interruptible: Whether to perform waits interruptible if possible. + * + * If DMA-ing till the screen target system, the function will also notify + * the screen target system that a bounding box of the cliprects has been + * updated. + * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * interrupted. + */ +int vmw_kms_stdu_dma(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct drm_vmw_fence_rep __user *user_fence_rep, + struct drm_clip_rect *clips, + struct drm_vmw_rect *vclips, + uint32_t num_clips, + int increment, + bool to_surface, + bool interruptible) +{ + struct vmw_dma_buffer *buf = + container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer; + struct vmw_stdu_dirty ddirty; + int ret; + + ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible, + false); + if (ret) + return ret; + + ddirty.transfer = (to_surface) ? SVGA3D_WRITE_HOST_VRAM : + SVGA3D_READ_HOST_VRAM; + ddirty.left = ddirty.top = S32_MAX; + ddirty.right = ddirty.bottom = S32_MIN; + ddirty.pitch = vfb->base.pitches[0]; + ddirty.buf = buf; + ddirty.base.fifo_commit = vmw_stdu_dmabuf_fifo_commit; + ddirty.base.clip = vmw_stdu_dmabuf_clip; + ddirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_dma) + + num_clips * sizeof(SVGA3dCopyBox) + + sizeof(SVGA3dCmdSurfaceDMASuffix); + if (to_surface) + ddirty.base.fifo_reserve_size += sizeof(struct vmw_stdu_update); + + ret = vmw_kms_helper_dirty(dev_priv, vfb, clips, vclips, + 0, 0, num_clips, increment, &ddirty.base); + vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL, + user_fence_rep); + + return ret; +} + +/** + * vmw_stdu_surface_clip - Callback to encode a surface copy command cliprect + * + * @dirty: The closure structure. + * + * Encodes a surface copy command cliprect and updates the bounding box + * for the copy. + */ +static void vmw_kms_stdu_surface_clip(struct vmw_kms_dirty *dirty) +{ + struct vmw_stdu_dirty *sdirty = + container_of(dirty, struct vmw_stdu_dirty, base); + struct vmw_stdu_surface_copy *cmd = dirty->cmd; + struct vmw_screen_target_display_unit *stdu = + container_of(dirty->unit, typeof(*stdu), base); + + if (sdirty->sid != stdu->display_srf->res.id) { + struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; + + blit += dirty->num_hits; + blit->srcx = dirty->fb_x; + blit->srcy = dirty->fb_y; + blit->x = dirty->unit_x1; + blit->y = dirty->unit_y1; + blit->d = 1; + blit->w = dirty->unit_x2 - dirty->unit_x1; + blit->h = dirty->unit_y2 - dirty->unit_y1; + } + + dirty->num_hits++; + + /* Destination bounding box */ + sdirty->left = min_t(s32, sdirty->left, dirty->unit_x1); + sdirty->top = min_t(s32, sdirty->top, dirty->unit_y1); + sdirty->right = max_t(s32, sdirty->right, dirty->unit_x2); + sdirty->bottom = max_t(s32, sdirty->bottom, dirty->unit_y2); +} + +/** + * vmw_stdu_surface_fifo_commit - Callback to fill in and submit a surface + * copy command. + * + * @dirty: The closure structure. + * + * Fills in the missing fields in a surface copy command, and encodes a screen + * target update command. + */ +static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty) +{ + struct vmw_stdu_dirty *sdirty = + container_of(dirty, struct vmw_stdu_dirty, base); + struct vmw_screen_target_display_unit *stdu = + container_of(dirty->unit, typeof(*stdu), base); + struct vmw_stdu_surface_copy *cmd = dirty->cmd; + struct vmw_stdu_update *update; + size_t blit_size = sizeof(SVGA3dCopyBox) * dirty->num_hits; + size_t commit_size; + + if (!dirty->num_hits) { + vmw_fifo_commit(dirty->dev_priv, 0); + return; + } + + if (sdirty->sid != stdu->display_srf->res.id) { + struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; + + cmd->header.id = SVGA_3D_CMD_SURFACE_COPY; + cmd->header.size = sizeof(cmd->body) + blit_size; + cmd->body.src.sid = sdirty->sid; + cmd->body.dest.sid = stdu->display_srf->res.id; + update = (struct vmw_stdu_update *) &blit[dirty->num_hits]; + commit_size = sizeof(*cmd) + blit_size + sizeof(*update); + } else { + update = dirty->cmd; + commit_size = sizeof(*update); + } + + vmw_stdu_populate_update(update, stdu->base.unit, sdirty->left, + sdirty->right, sdirty->top, sdirty->bottom); + + vmw_fifo_commit(dirty->dev_priv, commit_size); + + sdirty->left = sdirty->top = S32_MAX; + sdirty->right = sdirty->bottom = S32_MIN; +} + +/** + * vmw_kms_stdu_surface_dirty - Dirty part of a surface backed framebuffer + * + * @dev_priv: Pointer to the device private structure. + * @framebuffer: Pointer to the surface-buffer backed framebuffer. + * @clips: Array of clip rects. Either @clips or @vclips must be NULL. + * @vclips: Alternate array of clip rects. Either @clips or @vclips must + * be NULL. + * @srf: Pointer to surface to blit from. If NULL, the surface attached + * to @framebuffer will be used. + * @dest_x: X coordinate offset to align @srf with framebuffer coordinates. + * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates. + * @num_clips: Number of clip rects in @clips. + * @inc: Increment to use when looping over @clips. + * @out_fence: If non-NULL, will return a ref-counted pointer to a + * struct vmw_fence_obj. The returned fence pointer may be NULL in which + * case the device has already synchronized. + * + * Returns 0 on success, negative error code on failure. -ERESTARTSYS if + * interrupted. + */ +int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, + struct vmw_framebuffer *framebuffer, + struct drm_clip_rect *clips, + struct drm_vmw_rect *vclips, + struct vmw_resource *srf, + s32 dest_x, + s32 dest_y, + unsigned num_clips, int inc, + struct vmw_fence_obj **out_fence) +{ + struct vmw_framebuffer_surface *vfbs = + container_of(framebuffer, typeof(*vfbs), base); + struct vmw_stdu_dirty sdirty; + int ret; + + if (!srf) + srf = &vfbs->surface->res; + + ret = vmw_kms_helper_resource_prepare(srf, true); + if (ret) + return ret; + + if (vfbs->is_dmabuf_proxy) { + ret = vmw_kms_update_proxy(srf, clips, num_clips, inc); + if (ret) + goto out_finish; + } + + sdirty.base.fifo_commit = vmw_kms_stdu_surface_fifo_commit; + sdirty.base.clip = vmw_kms_stdu_surface_clip; + sdirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_surface_copy) + + sizeof(SVGA3dCopyBox) * num_clips + + sizeof(struct vmw_stdu_update); + sdirty.sid = srf->id; + sdirty.left = sdirty.top = S32_MAX; + sdirty.right = sdirty.bottom = S32_MIN; + + ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, + dest_x, dest_y, num_clips, inc, + &sdirty.base); +out_finish: + vmw_kms_helper_resource_finish(srf, out_fence); + + return ret; +} + /* * Screen Target CRTC dispatch table @@ -1122,7 +1139,6 @@ static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) stdu->base.pref_active = (unit == 0); stdu->base.pref_width = dev_priv->initial_width; stdu->base.pref_height = dev_priv->initial_height; - stdu->base.pref_mode = NULL; stdu->base.is_implicit = true; drm_connector_init(dev, connector, &vmw_stdu_connector_funcs, @@ -1207,6 +1223,8 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) if (unlikely(ret != 0)) goto err_vblank_cleanup; + dev_priv->active_display_unit = vmw_du_screen_target; + for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { ret = vmw_stdu_init(dev_priv, i); @@ -1216,8 +1234,6 @@ int vmw_kms_stdu_init_display(struct vmw_private *dev_priv) } } - dev_priv->active_display_unit = vmw_du_screen_target; - DRM_INFO("Screen Target Display device initialized\n"); return 0; @@ -1247,247 +1263,3 @@ int vmw_kms_stdu_close_display(struct vmw_private *dev_priv) return 0; } - - - -/** - * vmw_kms_stdu_do_surface_dirty - updates a dirty rectange to SVGA device - * - * @dev_priv: VMW DRM device - * @file_priv: Pointer to a drm file private structure - * @framebuffer: FB with the new content to be copied to SVGA device - * @clip_rects: array of dirty rectanges - * @num_of_clip_rects: number of rectanges in @clips - * @increment: increment to the next dirty rect in @clips - * - * This function sends an Update command to the SVGA device. This will notify - * the device that a region needs to be copied to the screen. At this time - * we are not coalescing clip rects into one large clip rect because the SVGA - * device will do it for us. - * - * RETURNS: - * 0 on success, error code otherwise - */ -int vmw_kms_stdu_do_surface_dirty(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *framebuffer, - struct drm_clip_rect *clip_rects, - unsigned num_of_clip_rects, int increment) -{ - struct vmw_screen_target_display_unit *stdu[VMWGFX_NUM_DISPLAY_UNITS]; - struct drm_clip_rect *cur_rect; - struct drm_crtc *crtc; - - unsigned num_of_du = 0, cur_du, count = 0; - int ret = 0; - - - BUG_ON(!clip_rects || !num_of_clip_rects); - - /* Figure out all the DU affected by this surface */ - list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, - head) { - if (crtc->primary->fb != &framebuffer->base) - continue; - - stdu[num_of_du++] = vmw_crtc_to_stdu(crtc); - } - - for (cur_du = 0; cur_du < num_of_du; cur_du++) - for (cur_rect = clip_rects, count = 0; - count < num_of_clip_rects && ret == 0; - cur_rect += increment, count++) { - ret = vmw_stdu_update_st(dev_priv, file_priv, - stdu[cur_du], - cur_rect); - } - - return ret; -} - - - -/** - * vmw_kms_stdu_present - present a surface to the display surface - * - * @dev_priv: VMW DRM device - * @file_priv: Pointer to a drm file private structure - * @vfb: Used to pick which STDU(s) is affected - * @user_handle: user handle for the source surface - * @dest_x: top/left corner of the display area to blit to - * @dest_y: top/left corner of the display area to blit to - * @clip_rects: array of dirty rectanges - * @num_of_clip_rects: number of rectanges in @clips - * - * This function copies a surface onto the display surface, and - * updates the screen target. Strech blit is currently not - * supported. - * - * RETURNS: - * 0 on success, error code otherwise - */ -int vmw_kms_stdu_present(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *vfb, - uint32_t user_handle, - int32_t dest_x, int32_t dest_y, - struct drm_vmw_rect *clip_rects, - uint32_t num_of_clip_rects) -{ - struct vmw_screen_target_display_unit *stdu[VMWGFX_NUM_DISPLAY_UNITS]; - struct drm_clip_rect *update_area; - struct drm_crtc *crtc; - size_t fifo_size; - int num_of_du = 0, cur_du, i; - int ret = 0; - struct vmw_clip_rect src_bb; - - struct { - SVGA3dCmdHeader header; - SVGA3dCmdSurfaceCopy body; - } *cmd; - SVGA3dCopyBox *blits; - - - BUG_ON(!clip_rects || !num_of_clip_rects); - - list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->primary->fb != &vfb->base) - continue; - - stdu[num_of_du++] = vmw_crtc_to_stdu(crtc); - } - - - update_area = kcalloc(num_of_clip_rects, sizeof(*update_area), - GFP_KERNEL); - if (unlikely(update_area == NULL)) { - DRM_ERROR("Temporary clip rect memory alloc failed.\n"); - return -ENOMEM; - } - - - fifo_size = sizeof(*cmd) + sizeof(SVGA3dCopyBox) * num_of_clip_rects; - - cmd = kmalloc(fifo_size, GFP_KERNEL); - if (unlikely(cmd == NULL)) { - DRM_ERROR("Failed to allocate memory for surface copy.\n"); - ret = -ENOMEM; - goto out_free_update_area; - } - - memset(cmd, 0, fifo_size); - cmd->header.id = SVGA_3D_CMD_SURFACE_COPY; - - blits = (SVGA3dCopyBox *)&cmd[1]; - - - /* Figure out the source bounding box */ - src_bb.x1 = clip_rects->x; - src_bb.y1 = clip_rects->y; - src_bb.x2 = clip_rects->x + clip_rects->w; - src_bb.y2 = clip_rects->y + clip_rects->h; - - for (i = 1; i < num_of_clip_rects; i++) { - src_bb.x1 = min_t(int, src_bb.x1, clip_rects[i].x); - src_bb.x2 = max_t(int, src_bb.x2, - clip_rects[i].x + (int) clip_rects[i].w); - src_bb.y1 = min_t(int, src_bb.y1, clip_rects[i].y); - src_bb.y2 = max_t(int, src_bb.y2, - clip_rects[i].y + (int) clip_rects[i].h); - } - - for (i = 0; i < num_of_clip_rects; i++) { - update_area[i].x1 = clip_rects[i].x - src_bb.x1; - update_area[i].x2 = update_area[i].x1 + clip_rects[i].w; - update_area[i].y1 = clip_rects[i].y - src_bb.y1; - update_area[i].y2 = update_area[i].y1 + clip_rects[i].h; - } - - - for (cur_du = 0; cur_du < num_of_du; cur_du++) { - struct vmw_clip_rect dest_bb; - int num_of_blits; - - crtc = &stdu[cur_du]->base.crtc; - - dest_bb.x1 = src_bb.x1 + dest_x - crtc->x; - dest_bb.y1 = src_bb.y1 + dest_y - crtc->y; - dest_bb.x2 = src_bb.x2 + dest_x - crtc->x; - dest_bb.y2 = src_bb.y2 + dest_y - crtc->y; - - /* Skip any STDU outside of the destination bounding box */ - if (dest_bb.x1 >= crtc->mode.hdisplay || - dest_bb.y1 >= crtc->mode.vdisplay || - dest_bb.x2 <= 0 || dest_bb.y2 <= 0) - continue; - - /* Normalize to top-left of src bounding box in dest coord */ - dest_bb.x2 = crtc->mode.hdisplay - dest_bb.x1; - dest_bb.y2 = crtc->mode.vdisplay - dest_bb.y1; - dest_bb.x1 = 0 - dest_bb.x1; - dest_bb.y1 = 0 - dest_bb.y1; - - for (i = 0, num_of_blits = 0; i < num_of_clip_rects; i++) { - int x1 = max_t(int, dest_bb.x1, (int)update_area[i].x1); - int y1 = max_t(int, dest_bb.y1, (int)update_area[i].y1); - int x2 = min_t(int, dest_bb.x2, (int)update_area[i].x2); - int y2 = min_t(int, dest_bb.y2, (int)update_area[i].y2); - - if (x1 >= x2) - continue; - - if (y1 >= y2) - continue; - - blits[num_of_blits].srcx = src_bb.x1 + x1; - blits[num_of_blits].srcy = src_bb.y1 + y1; - blits[num_of_blits].x = -dest_bb.x1 + x1; - blits[num_of_blits].y = -dest_bb.y1 + y1; - blits[num_of_blits].d = 1; - blits[num_of_blits].w = x2 - x1; - blits[num_of_blits].h = y2 - y1; - num_of_blits++; - } - - if (num_of_blits == 0) - continue; - - /* Calculate new command size */ - fifo_size = sizeof(*cmd) + sizeof(SVGA3dCopyBox) * num_of_blits; - - cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); - - cmd->body.src.sid = user_handle; - cmd->body.dest.sid = stdu[cur_du]->display_srf->res.id; - - ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, - fifo_size, 0, VMW_QUIRK_DST_SID_OK, - NULL, NULL); - - if (unlikely(ret != 0)) - break; - - for (i = 0; i < num_of_blits; i++) { - struct drm_clip_rect blit_area; - - /* - * Add crtc offset because vmw_stdu_update_st expects - * desktop coordinates - */ - blit_area.x1 = blits[i].x + crtc->x; - blit_area.x2 = blit_area.x1 + blits[i].w; - blit_area.y1 = blits[i].y + crtc->y; - blit_area.y2 = blit_area.y1 + blits[i].h; - (void) vmw_stdu_update_st(dev_priv, NULL, stdu[cur_du], - &blit_area); - } - } - - kfree(cmd); - -out_free_update_area: - kfree(update_area); - - return ret; -} -- cgit v1.3-6-gb490 From 9b590783b3d6d2e06516788d1061176109677409 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 26 Jun 2015 04:46:52 -0700 Subject: drm/vmwgfx: Avoid cmdbuf alloc sleeping if !TASK_RUNNING If the command buffer pool is out of space, the code waits until space is available. However since the condition code tries to allocate a range manager node while !TASK_RUNNING we get a kernel warning. Avoid this by pre-allocating the mm node. This will also probably be more efficient. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c | 83 ++++++++++++++-------------------- 1 file changed, 34 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index b044bf530974..e94feb338f89 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -33,7 +33,8 @@ * multiple of the DMA pool allocation size. */ #define VMW_CMDBUF_INLINE_ALIGN 64 -#define VMW_CMDBUF_INLINE_SIZE (1024 - VMW_CMDBUF_INLINE_ALIGN) +#define VMW_CMDBUF_INLINE_SIZE \ + (1024 - ALIGN(sizeof(SVGACBHeader), VMW_CMDBUF_INLINE_ALIGN)) /** * struct vmw_cmdbuf_context - Command buffer context queues @@ -145,7 +146,7 @@ struct vmw_cmdbuf_header { SVGACBHeader *cb_header; SVGACBContext cb_context; struct list_head list; - struct drm_mm_node *node; + struct drm_mm_node node; dma_addr_t handle; u8 *cmd; size_t size; @@ -169,13 +170,13 @@ struct vmw_cmdbuf_dheader { * struct vmw_cmdbuf_alloc_info - Command buffer space allocation metadata * * @page_size: Size of requested command buffer space in pages. - * @node: The range manager node if allocation succeeded. - * @ret: Error code if failure. Otherwise 0. + * @node: Pointer to the range manager node. + * @done: True if this allocation has succeeded. */ struct vmw_cmdbuf_alloc_info { size_t page_size; struct drm_mm_node *node; - int ret; + bool done; }; /* Loop over each context in the command buffer manager. */ @@ -253,9 +254,7 @@ static void __vmw_cmdbuf_header_free(struct vmw_cmdbuf_header *header) return; } - drm_mm_remove_node(header->node); - kfree(header->node); - header->node = NULL; + drm_mm_remove_node(&header->node); wake_up_all(&man->alloc_queue); if (header->cb_header) dma_pool_free(man->headers, header->cb_header, @@ -669,32 +668,26 @@ static bool vmw_cmdbuf_try_alloc(struct vmw_cmdbuf_man *man, { int ret; - if (info->node) + if (info->done) return true; - - info->node = kzalloc(sizeof(*info->node), GFP_KERNEL); - if (!info->node) { - info->ret = -ENOMEM; - return true; - } - + + memset(info->node, 0, sizeof(*info->node)); spin_lock_bh(&man->lock); - ret = drm_mm_insert_node_generic(&man->mm, info->node, info->page_size, 0, 0, + ret = drm_mm_insert_node_generic(&man->mm, info->node, info->page_size, + 0, 0, DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT); spin_unlock_bh(&man->lock); - if (ret) { - kfree(info->node); - info->node = NULL; - } + info->done = !ret; - return !!info->node; + return info->done; } /** * vmw_cmdbuf_alloc_space - Allocate buffer space from the main pool. * * @man: The command buffer manager. + * @node: Pointer to pre-allocated range-manager node. * @size: The size of the allocation. * @interruptible: Whether to sleep interruptible while waiting for space. * @@ -702,15 +695,16 @@ static bool vmw_cmdbuf_try_alloc(struct vmw_cmdbuf_man *man, * no space available ATM, it turns on IRQ handling and sleeps waiting for it to * become available. */ -static struct drm_mm_node *vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, - size_t size, - bool interruptible) +int vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, + struct drm_mm_node *node, + size_t size, + bool interruptible) { struct vmw_cmdbuf_alloc_info info; info.page_size = PAGE_ALIGN(size) >> PAGE_SHIFT; - info.node = NULL; - info.ret = 0; + info.node = node; + info.done = false; /* * To prevent starvation of large requests, only one allocating call @@ -718,22 +712,14 @@ static struct drm_mm_node *vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, */ if (interruptible) { if (mutex_lock_interruptible(&man->space_mutex)) - return ERR_PTR(-ERESTARTSYS); + return -ERESTARTSYS; } else { mutex_lock(&man->space_mutex); } /* Try to allocate space without waiting. */ - (void) vmw_cmdbuf_try_alloc(man, &info); - if (info.ret && !info.node) { - mutex_unlock(&man->space_mutex); - return ERR_PTR(info.ret); - } - - if (info.node) { - mutex_unlock(&man->space_mutex); - return info.node; - } + if (vmw_cmdbuf_try_alloc(man, &info)) + goto out_unlock; vmw_generic_waiter_add(man->dev_priv, SVGA_IRQFLAG_COMMAND_BUFFER, @@ -749,7 +735,7 @@ static struct drm_mm_node *vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, (man->dev_priv, SVGA_IRQFLAG_COMMAND_BUFFER, &man->dev_priv->cmdbuf_waiters); mutex_unlock(&man->space_mutex); - return ERR_PTR(ret); + return ret; } } else { wait_event(man->alloc_queue, vmw_cmdbuf_try_alloc(man, &info)); @@ -757,11 +743,11 @@ static struct drm_mm_node *vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, vmw_generic_waiter_remove(man->dev_priv, SVGA_IRQFLAG_COMMAND_BUFFER, &man->dev_priv->cmdbuf_waiters); + +out_unlock: mutex_unlock(&man->space_mutex); - if (info.ret && !info.node) - return ERR_PTR(info.ret); - return info.node; + return 0; } /** @@ -785,10 +771,10 @@ static int vmw_cmdbuf_space_pool(struct vmw_cmdbuf_man *man, if (!man->has_pool) return -ENOMEM; - header->node = vmw_cmdbuf_alloc_space(man, size, interruptible); + ret = vmw_cmdbuf_alloc_space(man, &header->node, size, interruptible); - if (IS_ERR(header->node)) - return PTR_ERR(header->node); + if (ret) + return ret; header->cb_header = dma_pool_alloc(man->headers, GFP_KERNEL, &header->handle); @@ -797,9 +783,9 @@ static int vmw_cmdbuf_space_pool(struct vmw_cmdbuf_man *man, goto out_no_cb_header; } - header->size = header->node->size << PAGE_SHIFT; + header->size = header->node.size << PAGE_SHIFT; cb_hdr = header->cb_header; - offset = header->node->start << PAGE_SHIFT; + offset = header->node.start << PAGE_SHIFT; header->cmd = man->map + offset; memset(cb_hdr, 0, sizeof(*cb_hdr)); if (man->using_mob) { @@ -814,9 +800,8 @@ static int vmw_cmdbuf_space_pool(struct vmw_cmdbuf_man *man, out_no_cb_header: spin_lock_bh(&man->lock); - drm_mm_remove_node(header->node); + drm_mm_remove_node(&header->node); spin_unlock_bh(&man->lock); - kfree(header->node); return ret; } -- cgit v1.3-6-gb490 From fd006a43a8c4c9356ace60eacd8ae68954fa25e0 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 28 Jun 2015 02:50:56 -0700 Subject: drm/vmwgfx: Add a kernel interface to create a framebuffer v2 The kernel interface is needed for fbdev, and needs to be free from a file_priv member. To accomplish this, remove the fb surface mutex and list which isn't used anymore, anyway. Finally, make the pin() and unpin() pin the framebuffer for all display system backends, so that fbdev can pin its framebuffer before mapping it. v2: Address review comments: - Fix vmw_framebuffer_unpin() to handle also the surface framebuffer case. - Fix vmw_kms_new_framebuffer() to actually use the only_2d parameter. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 - drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 - drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 162 +++++++++++++++++++++--------------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 8 +- 4 files changed, 102 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index e55db3fdf601..bcf1962ecf06 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1142,8 +1142,6 @@ static void vmw_lastclose(struct drm_device *dev) static void vmw_master_init(struct vmw_master *vmaster) { ttm_lock_init(&vmaster->lock); - INIT_LIST_HEAD(&vmaster->fb_surf); - mutex_init(&vmaster->fb_surf_mutex); } static int vmw_master_create(struct drm_device *dev, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d6b247b1994a..9ae573640156 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -372,8 +372,6 @@ struct vmw_overlay; struct vmw_master { struct ttm_lock lock; - struct mutex fb_surf_mutex; - struct list_head fb_surf; }; struct vmw_vga_topology_state { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 234a3cef1c25..dc9f7d0166c4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -369,14 +369,7 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) { struct vmw_framebuffer_surface *vfbs = vmw_framebuffer_to_vfbs(framebuffer); - struct vmw_master *vmaster = vmw_master(vfbs->master); - - mutex_lock(&vmaster->fb_surf_mutex); - list_del(&vfbs->head); - mutex_unlock(&vmaster->fb_surf_mutex); - - drm_master_put(&vfbs->master); drm_framebuffer_cleanup(framebuffer); vmw_surface_unreference(&vfbs->surface); ttm_base_object_unref(&vfbs->base.user_obj); @@ -396,9 +389,6 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, struct drm_clip_rect norect; int ret, inc = 1; - if (unlikely(vfbs->master != file_priv->master)) - return -EINVAL; - /* Legacy Display Unit does not support 3D */ if (dev_priv->active_display_unit == vmw_du_legacy) return -EINVAL; @@ -485,7 +475,6 @@ static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = { }; static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, - struct drm_file *file_priv, struct vmw_surface *surface, struct vmw_framebuffer **out, const struct drm_mode_fb_cmd @@ -496,7 +485,6 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, struct drm_device *dev = dev_priv->dev; struct vmw_framebuffer_surface *vfbs; enum SVGA3dSurfaceFormat format; - struct vmw_master *vmaster = vmw_master(file_priv->master); int ret; /* 3D is only supported on HWv8 and newer hosts */ @@ -564,13 +552,8 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, vfbs->base.base.height = mode_cmd->height; vfbs->surface = surface; vfbs->base.user_handle = mode_cmd->handle; - vfbs->master = drm_master_get(file_priv->master); vfbs->is_dmabuf_proxy = is_dmabuf_proxy; - mutex_lock(&vmaster->fb_surf_mutex); - list_add_tail(&vfbs->head, &vmaster->fb_surf); - mutex_unlock(&vmaster->fb_surf_mutex); - *out = &vfbs->base; ret = drm_framebuffer_init(dev, &vfbs->base.base, @@ -670,39 +653,51 @@ static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = { /** * Pin the dmabuffer to the start of vram. */ -static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb) +static int vmw_framebuffer_pin(struct vmw_framebuffer *vfb) { struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); - struct vmw_framebuffer_dmabuf *vfbd = - vmw_framebuffer_to_vfbd(&vfb->base); + struct vmw_dma_buffer *buf; int ret; - /* This code should only be used with Legacy Display Unit */ - BUG_ON(dev_priv->active_display_unit != vmw_du_legacy); - - vmw_overlay_pause_all(dev_priv); + buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : + vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.backup; - ret = vmw_dmabuf_pin_in_start_of_vram(dev_priv, vfbd->buffer, false); + if (!buf) + return 0; - vmw_overlay_resume_all(dev_priv); + switch (dev_priv->active_display_unit) { + case vmw_du_legacy: + vmw_overlay_pause_all(dev_priv); + ret = vmw_dmabuf_pin_in_start_of_vram(dev_priv, buf, false); + vmw_overlay_resume_all(dev_priv); + break; + case vmw_du_screen_object: + case vmw_du_screen_target: + if (vfb->dmabuf) + return vmw_dmabuf_pin_in_vram_or_gmr(dev_priv, buf, + false); - WARN_ON(ret != 0); + return vmw_dmabuf_pin_in_placement(dev_priv, buf, + &vmw_mob_placement, false); + default: + return -EINVAL; + } - return 0; + return ret; } -static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb) +static int vmw_framebuffer_unpin(struct vmw_framebuffer *vfb) { struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); - struct vmw_framebuffer_dmabuf *vfbd = - vmw_framebuffer_to_vfbd(&vfb->base); + struct vmw_dma_buffer *buf; - if (!vfbd->buffer) { - WARN_ON(!vfbd->buffer); + buf = vfb->dmabuf ? vmw_framebuffer_to_vfbd(&vfb->base)->buffer : + vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.backup; + + if (WARN_ON(!buf)) return 0; - } - return vmw_dmabuf_unpin(dev_priv, vfbd->buffer, false); + return vmw_dmabuf_unpin(dev_priv, buf, false); } /** @@ -721,7 +716,7 @@ static int vmw_framebuffer_dmabuf_unpin(struct vmw_framebuffer *vfb) * 0 on success, error code otherwise */ static int vmw_create_dmabuf_proxy(struct drm_device *dev, - struct drm_mode_fb_cmd *mode_cmd, + const struct drm_mode_fb_cmd *mode_cmd, struct vmw_dma_buffer *dmabuf_mob, struct vmw_surface **srf_out) { @@ -847,10 +842,6 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv, vfbd->base.base.depth = mode_cmd->depth; vfbd->base.base.width = mode_cmd->width; vfbd->base.base.height = mode_cmd->height; - if (dev_priv->active_display_unit == vmw_du_legacy) { - vfbd->base.pin = vmw_framebuffer_dmabuf_pin; - vfbd->base.unpin = vmw_framebuffer_dmabuf_unpin; - } vfbd->base.dmabuf = true; vfbd->buffer = dmabuf; vfbd->base.user_handle = mode_cmd->handle; @@ -871,6 +862,64 @@ out_err1: return ret; } +/** + * vmw_kms_new_framebuffer - Create a new framebuffer. + * + * @dev_priv: Pointer to device private struct. + * @dmabuf: Pointer to dma buffer to wrap the kms framebuffer around. + * Either @dmabuf or @surface must be NULL. + * @surface: Pointer to a surface to wrap the kms framebuffer around. + * Either @dmabuf or @surface must be NULL. + * @only_2d: No presents will occur to this dma buffer based framebuffer. This + * Helps the code to do some important optimizations. + * @mode_cmd: Frame-buffer metadata. + */ +struct vmw_framebuffer * +vmw_kms_new_framebuffer(struct vmw_private *dev_priv, + struct vmw_dma_buffer *dmabuf, + struct vmw_surface *surface, + bool only_2d, + const struct drm_mode_fb_cmd *mode_cmd) +{ + struct vmw_framebuffer *vfb; + bool is_dmabuf_proxy = false; + int ret; + + /* + * We cannot use the SurfaceDMA command in an non-accelerated VM, + * therefore, wrap the DMA buf in a surface so we can use the + * SurfaceCopy command. + */ + if (dmabuf && only_2d && + dev_priv->active_display_unit == vmw_du_screen_target) { + ret = vmw_create_dmabuf_proxy(dev_priv->dev, mode_cmd, + dmabuf, &surface); + if (ret) + return ERR_PTR(ret); + + is_dmabuf_proxy = true; + } + + /* Create the new framebuffer depending one what we have */ + if (surface) + ret = vmw_kms_new_framebuffer_surface(dev_priv, surface, &vfb, + mode_cmd, + is_dmabuf_proxy); + else if (dmabuf) + ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, dmabuf, &vfb, + mode_cmd); + else + BUG(); + + if (ret) + return ERR_PTR(ret); + + vfb->pin = vmw_framebuffer_pin; + vfb->unpin = vmw_framebuffer_unpin; + + return vfb; +} + /* * Generic Kernel modesetting functions */ @@ -886,7 +935,6 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, struct vmw_dma_buffer *bo = NULL; struct ttm_base_object *user_obj; struct drm_mode_fb_cmd mode_cmd; - bool is_dmabuf_proxy = false; int ret; mode_cmd.width = mode_cmd2->width; @@ -935,31 +983,13 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, if (ret) goto err_out; - /* - * We cannot use the SurfaceDMA command in an non-accelerated VM, - * therefore, wrap the DMA buf in a surface so we can use the - * SurfaceCopy command. - */ - if (bo && !(dev_priv->capabilities & SVGA_CAP_3D) && - dev_priv->active_display_unit == vmw_du_screen_target) { - ret = vmw_create_dmabuf_proxy(dev_priv->dev, &mode_cmd, bo, - &surface); - if (ret) - goto err_out; - - is_dmabuf_proxy = true; - } - - /* Create the new framebuffer depending one what we have */ - if (surface) - ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, - surface, &vfb, &mode_cmd, - is_dmabuf_proxy); - else if (bo) - ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, - &mode_cmd); - else - BUG(); + vfb = vmw_kms_new_framebuffer(dev_priv, bo, surface, + !(dev_priv->capabilities & SVGA_CAP_3D), + &mode_cmd); + if (IS_ERR(vfb)) { + ret = PTR_ERR(vfb); + goto err_out; + } err_out: /* vmw_user_lookup_handle takes one ref so does new_fb */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index f941f92338a6..311effc7ee74 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -114,7 +114,6 @@ struct vmw_framebuffer_surface { struct vmw_surface *surface; struct vmw_dma_buffer *buffer; struct list_head head; - struct drm_master *master; bool is_dmabuf_proxy; /* true if this is proxy surface for DMA buf */ }; @@ -238,7 +237,12 @@ int vmw_kms_readback(struct vmw_private *dev_priv, struct drm_vmw_fence_rep __user *user_fence_rep, struct drm_vmw_rect *vclips, uint32_t num_clips); - +struct vmw_framebuffer * +vmw_kms_new_framebuffer(struct vmw_private *dev_priv, + struct vmw_dma_buffer *dmabuf, + struct vmw_surface *surface, + bool only_2d, + const struct drm_mode_fb_cmd *mode_cmd); /* * Legacy display unit functions - vmwgfx_ldu.c -- cgit v1.3-6-gb490 From a278724aa23c544c2087cb7537db6b950877c291 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 29 Jun 2015 12:55:07 -0700 Subject: drm/vmwgfx: Implement fbdev on kms v2 With screen targets the old legacy display system fbdev doesn't work satisfactory anymore. At best the resolution is severely restricted. Therefore implement fbdev on top of the kms system. With this change, fbdev will be using whatever KMS backend is chosen. There are helpers available for this, so in the future we'd probably want to implement the helper callbacks instead of calling into our KMS implementation directly. v2: Make sure we take the mode_config mutex around modesetting, Also clear the initial framebuffer using vzalloc instead of vmalloc. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 22 +- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 555 +++++++++++++++++++++++------------ drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 63 +++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 8 + drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 1 - drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 1 - 6 files changed, 436 insertions(+), 214 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index bcf1962ecf06..18921444672f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1120,23 +1120,6 @@ static long vmw_compat_ioctl(struct file *filp, unsigned int cmd, static void vmw_lastclose(struct drm_device *dev) { - struct drm_crtc *crtc; - struct drm_mode_set set; - int ret; - - set.x = 0; - set.y = 0; - set.fb = NULL; - set.mode = NULL; - set.connectors = NULL; - set.num_connectors = 0; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - set.crtc = crtc; - ret = drm_mode_set_config_internal(&set); - WARN_ON(ret != 0); - } - } static void vmw_master_init(struct vmw_master *vmaster) @@ -1321,6 +1304,8 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, switch (val) { case PM_HIBERNATION_PREPARE: + if (dev_priv->enable_fb) + vmw_fb_off(dev_priv); ttm_suspend_lock(&dev_priv->reservation_sem); /* @@ -1337,7 +1322,8 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, case PM_POST_RESTORE: vmw_fence_fifo_up(dev_priv->fman); ttm_suspend_unlock(&dev_priv->reservation_sem); - + if (dev_priv->enable_fb) + vmw_fb_on(dev_priv); break; case PM_RESTORE_PREPARE: break; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index b54d99bca9bf..9dbb2031a017 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -30,6 +30,7 @@ #include #include "vmwgfx_drv.h" +#include "vmwgfx_kms.h" #include @@ -40,21 +41,22 @@ struct vmw_fb_par { void *vmalloc; + struct mutex bo_mutex; struct vmw_dma_buffer *vmw_bo; struct ttm_bo_kmap_obj map; + void *bo_ptr; + unsigned bo_size; + struct drm_framebuffer *set_fb; + struct drm_display_mode *set_mode; + u32 fb_x; + u32 fb_y; + bool bo_iowrite; u32 pseudo_palette[17]; - unsigned depth; - unsigned bpp; - unsigned max_width; unsigned max_height; - void *bo_ptr; - unsigned bo_size; - bool bo_iowrite; - struct { spinlock_t lock; bool active; @@ -63,6 +65,11 @@ struct vmw_fb_par { unsigned x2; unsigned y2; } dirty; + + struct drm_crtc *crtc; + struct drm_connector *con; + + bool local_mode; }; static int vmw_fb_setcolreg(unsigned regno, unsigned red, unsigned green, @@ -77,7 +84,7 @@ static int vmw_fb_setcolreg(unsigned regno, unsigned red, unsigned green, return 1; } - switch (par->depth) { + switch (par->set_fb->depth) { case 24: case 32: pal[regno] = ((red & 0xff00) << 8) | @@ -85,7 +92,8 @@ static int vmw_fb_setcolreg(unsigned regno, unsigned red, unsigned green, ((blue & 0xff00) >> 8); break; default: - DRM_ERROR("Bad depth %u, bpp %u.\n", par->depth, par->bpp); + DRM_ERROR("Bad depth %u, bpp %u.\n", par->set_fb->depth, + par->set_fb->bits_per_pixel); return 1; } @@ -134,12 +142,6 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var, return -EINVAL; } - if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) && - (var->xoffset != 0 || var->yoffset != 0)) { - DRM_ERROR("Can not handle panning without display topology\n"); - return -EINVAL; - } - if ((var->xoffset + var->xres) > par->max_width || (var->yoffset + var->yres) > par->max_height) { DRM_ERROR("Requested geom can not fit in framebuffer\n"); @@ -156,46 +158,6 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var, return 0; } -static int vmw_fb_set_par(struct fb_info *info) -{ - struct vmw_fb_par *par = info->par; - struct vmw_private *vmw_priv = par->vmw_priv; - int ret; - - info->fix.line_length = info->var.xres * info->var.bits_per_pixel/8; - - ret = vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, - info->fix.line_length, - par->bpp, par->depth); - if (ret) - return ret; - - if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) { - /* TODO check if pitch and offset changes */ - vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, info->var.xoffset); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, info->var.yoffset); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres); - vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); - } - - /* This is really helpful since if this fails the user - * can probably not see anything on the screen. - */ - WARN_ON(vmw_read(vmw_priv, SVGA_REG_FB_OFFSET) != 0); - - return 0; -} - -static int vmw_fb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - return 0; -} - static int vmw_fb_blank(int blank, struct fb_info *info) { return 0; @@ -209,55 +171,77 @@ static void vmw_fb_dirty_flush(struct vmw_fb_par *par) { struct vmw_private *vmw_priv = par->vmw_priv; struct fb_info *info = vmw_priv->fb_info; - int stride = (info->fix.line_length / 4); - int *src = (int *)info->screen_base; - __le32 __iomem *vram_mem = par->bo_ptr; - unsigned long flags; - unsigned x, y, w, h; - int i, k; - struct { - uint32_t header; - SVGAFifoCmdUpdate body; - } *cmd; + unsigned long irq_flags; + s32 dst_x1, dst_x2, dst_y1, dst_y2, w, h; + u32 cpp, max_x, max_y; + struct drm_clip_rect clip; + struct drm_framebuffer *cur_fb; + u8 *src_ptr, *dst_ptr; if (vmw_priv->suspended) return; - spin_lock_irqsave(&par->dirty.lock, flags); - if (!par->dirty.active) { - spin_unlock_irqrestore(&par->dirty.lock, flags); - return; - } - x = par->dirty.x1; - y = par->dirty.y1; - w = min(par->dirty.x2, info->var.xres) - x; - h = min(par->dirty.y2, info->var.yres) - y; - par->dirty.x1 = par->dirty.x2 = 0; - par->dirty.y1 = par->dirty.y2 = 0; - spin_unlock_irqrestore(&par->dirty.lock, flags); + mutex_lock(&par->bo_mutex); + cur_fb = par->set_fb; + if (!cur_fb) + goto out_unlock; - for (i = y * stride; i < info->fix.smem_len / 4; i += stride) { - for (k = i+x; k < i+x+w && k < info->fix.smem_len / 4; k++) - iowrite32(src[k], vram_mem + k); + spin_lock_irqsave(&par->dirty.lock, irq_flags); + if (!par->dirty.active) { + spin_unlock_irqrestore(&par->dirty.lock, irq_flags); + goto out_unlock; } -#if 0 - DRM_INFO("%s, (%u, %u) (%ux%u)\n", __func__, x, y, w, h); -#endif + /* + * Handle panning when copying from vmalloc to framebuffer. + * Clip dirty area to framebuffer. + */ + cpp = (cur_fb->bits_per_pixel + 7) / 8; + max_x = par->fb_x + cur_fb->width; + max_y = par->fb_y + cur_fb->height; + + dst_x1 = par->dirty.x1 - par->fb_x; + dst_y1 = par->dirty.y1 - par->fb_y; + dst_x1 = max_t(s32, dst_x1, 0); + dst_y1 = max_t(s32, dst_y1, 0); + + dst_x2 = par->dirty.x2 - par->fb_x; + dst_y2 = par->dirty.y2 - par->fb_y; + dst_x2 = min_t(s32, dst_x2, max_x); + dst_y2 = min_t(s32, dst_y2, max_y); + w = dst_x2 - dst_x1; + h = dst_y2 - dst_y1; + w = max_t(s32, 0, w); + h = max_t(s32, 0, h); - cmd = vmw_fifo_reserve(vmw_priv, sizeof(*cmd)); - if (unlikely(cmd == NULL)) { - DRM_ERROR("Fifo reserve failed.\n"); - return; + par->dirty.x1 = par->dirty.x2 = 0; + par->dirty.y1 = par->dirty.y2 = 0; + spin_unlock_irqrestore(&par->dirty.lock, irq_flags); + + if (w && h) { + dst_ptr = (u8 *)par->bo_ptr + + (dst_y1 * par->set_fb->pitches[0] + dst_x1 * cpp); + src_ptr = (u8 *)par->vmalloc + + ((dst_y1 + par->fb_y) * info->fix.line_length + + (dst_x1 + par->fb_x) * cpp); + + while (h-- > 0) { + memcpy(dst_ptr, src_ptr, w*cpp); + dst_ptr += par->set_fb->pitches[0]; + src_ptr += info->fix.line_length; + } + + clip.x1 = dst_x1; + clip.x2 = dst_x2; + clip.y1 = dst_y1; + clip.y2 = dst_y2; + + WARN_ON_ONCE(par->set_fb->funcs->dirty(cur_fb, NULL, 0, 0, + &clip, 1)); + vmw_fifo_flush(vmw_priv, false); } - - cmd->header = cpu_to_le32(SVGA_CMD_UPDATE); - cmd->body.x = cpu_to_le32(x); - cmd->body.y = cpu_to_le32(y); - cmd->body.width = cpu_to_le32(w); - cmd->body.height = cpu_to_le32(h); - vmw_fifo_commit(vmw_priv, sizeof(*cmd)); - vmw_fifo_flush(vmw_priv, false); +out_unlock: + mutex_unlock(&par->bo_mutex); } static void vmw_fb_dirty_mark(struct vmw_fb_par *par, @@ -292,6 +276,28 @@ static void vmw_fb_dirty_mark(struct vmw_fb_par *par, spin_unlock_irqrestore(&par->dirty.lock, flags); } +static int vmw_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct vmw_fb_par *par = info->par; + + if ((var->xoffset + var->xres) > var->xres_virtual || + (var->yoffset + var->yres) > var->yres_virtual) { + DRM_ERROR("Requested panning can not fit in framebuffer\n"); + return -EINVAL; + } + + mutex_lock(&par->bo_mutex); + par->fb_x = var->xoffset; + par->fb_y = var->yoffset; + if (par->set_fb) + vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, par->set_fb->width, + par->set_fb->height); + mutex_unlock(&par->bo_mutex); + + return 0; +} + static void vmw_deferred_io(struct fb_info *info, struct list_head *pagelist) { @@ -359,33 +365,12 @@ static void vmw_fb_imageblit(struct fb_info *info, const struct fb_image *image) * Bring up code */ -static struct fb_ops vmw_fb_ops = { - .owner = THIS_MODULE, - .fb_check_var = vmw_fb_check_var, - .fb_set_par = vmw_fb_set_par, - .fb_setcolreg = vmw_fb_setcolreg, - .fb_fillrect = vmw_fb_fillrect, - .fb_copyarea = vmw_fb_copyarea, - .fb_imageblit = vmw_fb_imageblit, - .fb_pan_display = vmw_fb_pan_display, - .fb_blank = vmw_fb_blank, -}; - static int vmw_fb_create_bo(struct vmw_private *vmw_priv, size_t size, struct vmw_dma_buffer **out) { struct vmw_dma_buffer *vmw_bo; - struct ttm_place ne_place = vmw_vram_ne_placement.placement[0]; - struct ttm_placement ne_placement; int ret; - ne_placement.num_placement = 1; - ne_placement.placement = &ne_place; - ne_placement.num_busy_placement = 1; - ne_placement.busy_placement = &ne_place; - - ne_place.lpfn = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - (void) ttm_write_lock(&vmw_priv->reservation_sem, false); vmw_bo = kmalloc(sizeof(*vmw_bo), GFP_KERNEL); @@ -395,14 +380,13 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv, } ret = vmw_dmabuf_init(vmw_priv, vmw_bo, size, - &ne_placement, + &vmw_sys_placement, false, &vmw_dmabuf_bo_free); if (unlikely(ret != 0)) goto err_unlock; /* init frees the buffer on failure */ *out = vmw_bo; - ttm_write_unlock(&vmw_priv->reservation_sem); return 0; @@ -412,14 +396,249 @@ err_unlock: return ret; } +static int vmw_fb_compute_depth(struct fb_var_screeninfo *var, + int *depth) +{ + switch (var->bits_per_pixel) { + case 32: + *depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + DRM_ERROR("Bad bpp %u.\n", var->bits_per_pixel); + return -EINVAL; + } + + return 0; +} + +static int vmw_fb_kms_detach(struct vmw_fb_par *par, + bool detach_bo, + bool unref_bo) +{ + struct drm_framebuffer *cur_fb = par->set_fb; + int ret; + + /* Detach the KMS framebuffer from crtcs */ + if (par->set_mode) { + struct drm_mode_set set; + + set.crtc = par->crtc; + set.x = 0; + set.y = 0; + set.mode = NULL; + set.fb = NULL; + set.num_connectors = 1; + set.connectors = &par->con; + ret = drm_mode_set_config_internal(&set); + if (ret) { + DRM_ERROR("Could not unset a mode.\n"); + return ret; + } + drm_mode_destroy(par->vmw_priv->dev, par->set_mode); + par->set_mode = NULL; + } + + if (cur_fb) { + drm_framebuffer_unreference(cur_fb); + par->set_fb = NULL; + } + + if (par->vmw_bo && detach_bo) { + if (par->bo_ptr) { + ttm_bo_kunmap(&par->map); + par->bo_ptr = NULL; + } + if (unref_bo) + vmw_dmabuf_unreference(&par->vmw_bo); + else + vmw_dmabuf_unpin(par->vmw_priv, par->vmw_bo, false); + } + + return 0; +} + +static int vmw_fb_kms_framebuffer(struct fb_info *info) +{ + struct drm_mode_fb_cmd mode_cmd; + struct vmw_fb_par *par = info->par; + struct fb_var_screeninfo *var = &info->var; + struct drm_framebuffer *cur_fb; + struct vmw_framebuffer *vfb; + int ret = 0; + size_t new_bo_size; + + ret = vmw_fb_compute_depth(var, &mode_cmd.depth); + if (ret) + return ret; + + mode_cmd.width = var->xres; + mode_cmd.height = var->yres; + mode_cmd.bpp = var->bits_per_pixel; + mode_cmd.pitch = ((mode_cmd.bpp + 7) / 8) * mode_cmd.width; + + cur_fb = par->set_fb; + if (cur_fb && cur_fb->width == mode_cmd.width && + cur_fb->height == mode_cmd.height && + cur_fb->bits_per_pixel == mode_cmd.bpp && + cur_fb->depth == mode_cmd.depth && + cur_fb->pitches[0] == mode_cmd.pitch) + return 0; + + /* Need new buffer object ? */ + new_bo_size = (size_t) mode_cmd.pitch * (size_t) mode_cmd.height; + ret = vmw_fb_kms_detach(par, + par->bo_size < new_bo_size || + par->bo_size > 2*new_bo_size, + true); + if (ret) + return ret; + + if (!par->vmw_bo) { + ret = vmw_fb_create_bo(par->vmw_priv, new_bo_size, + &par->vmw_bo); + if (ret) { + DRM_ERROR("Failed creating a buffer object for " + "fbdev.\n"); + return ret; + } + par->bo_size = new_bo_size; + } + + vfb = vmw_kms_new_framebuffer(par->vmw_priv, par->vmw_bo, NULL, + true, &mode_cmd); + if (IS_ERR(vfb)) + return PTR_ERR(vfb); + + par->set_fb = &vfb->base; + + if (!par->bo_ptr) { + /* + * Pin before mapping. Since we don't know in what placement + * to pin, call into KMS to do it for us. + */ + ret = vfb->pin(vfb); + if (ret) { + DRM_ERROR("Could not pin the fbdev framebuffer.\n"); + return ret; + } + + ret = ttm_bo_kmap(&par->vmw_bo->base, 0, + par->vmw_bo->base.num_pages, &par->map); + if (ret) { + vfb->unpin(vfb); + DRM_ERROR("Could not map the fbdev framebuffer.\n"); + return ret; + } + + par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite); + } + + return 0; +} + +static int vmw_fb_set_par(struct fb_info *info) +{ + struct vmw_fb_par *par = info->par; + struct vmw_private *vmw_priv = par->vmw_priv; + struct drm_mode_set set; + struct fb_var_screeninfo *var = &info->var; + struct drm_display_mode new_mode = { DRM_MODE("fb_mode", + DRM_MODE_TYPE_DRIVER, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) + }; + struct drm_display_mode *old_mode; + struct drm_display_mode *mode; + int ret; + + old_mode = par->set_mode; + mode = drm_mode_duplicate(vmw_priv->dev, &new_mode); + if (!mode) { + DRM_ERROR("Could not create new fb mode.\n"); + return -ENOMEM; + } + + mode->hdisplay = var->xres; + mode->vdisplay = var->yres; + vmw_guess_mode_timing(mode); + + if (old_mode && drm_mode_equal(old_mode, mode)) { + drm_mode_destroy(vmw_priv->dev, mode); + mode = old_mode; + old_mode = NULL; + } else if (!vmw_kms_validate_mode_vram(vmw_priv, + mode->hdisplay * + (var->bits_per_pixel + 7) / 8, + mode->vdisplay)) { + drm_mode_destroy(vmw_priv->dev, mode); + return -EINVAL; + } + + mutex_lock(&par->bo_mutex); + drm_modeset_lock_all(vmw_priv->dev); + ret = vmw_fb_kms_framebuffer(info); + if (ret) + goto out_unlock; + + par->fb_x = var->xoffset; + par->fb_y = var->yoffset; + + set.crtc = par->crtc; + set.x = 0; + set.y = 0; + set.mode = mode; + set.fb = par->set_fb; + set.num_connectors = 1; + set.connectors = &par->con; + + ret = drm_mode_set_config_internal(&set); + if (ret) + goto out_unlock; + + vmw_fb_dirty_mark(par, par->fb_x, par->fb_y, + par->set_fb->width, par->set_fb->height); + + /* If there already was stuff dirty we wont + * schedule a new work, so lets do it now */ + +#if (defined(VMWGFX_STANDALONE) && defined(VMWGFX_FB_DEFERRED)) + schedule_delayed_work(&par->def_par.deferred_work, 0); +#else + schedule_delayed_work(&info->deferred_work, 0); +#endif + +out_unlock: + if (old_mode) + drm_mode_destroy(vmw_priv->dev, old_mode); + par->set_mode = mode; + + drm_modeset_unlock_all(vmw_priv->dev); + mutex_unlock(&par->bo_mutex); + + return ret; +} + + +static struct fb_ops vmw_fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = vmw_fb_check_var, + .fb_set_par = vmw_fb_set_par, + .fb_setcolreg = vmw_fb_setcolreg, + .fb_fillrect = vmw_fb_fillrect, + .fb_copyarea = vmw_fb_copyarea, + .fb_imageblit = vmw_fb_imageblit, + .fb_pan_display = vmw_fb_pan_display, + .fb_blank = vmw_fb_blank, +}; + int vmw_fb_init(struct vmw_private *vmw_priv) { struct device *device = &vmw_priv->dev->pdev->dev; struct vmw_fb_par *par; struct fb_info *info; - unsigned initial_width, initial_height; unsigned fb_width, fb_height; unsigned fb_bpp, fb_depth, fb_offset, fb_pitch, fb_size; + struct drm_display_mode *init_mode; int ret; fb_bpp = 32; @@ -429,9 +648,6 @@ int vmw_fb_init(struct vmw_private *vmw_priv) fb_width = min(vmw_priv->fb_max_width, (unsigned)2048); fb_height = min(vmw_priv->fb_max_height, (unsigned)2048); - initial_width = min(vmw_priv->initial_width, fb_width); - initial_height = min(vmw_priv->initial_height, fb_height); - fb_pitch = fb_width * fb_bpp / 8; fb_size = fb_pitch * fb_height; fb_offset = vmw_read(vmw_priv, SVGA_REG_FB_OFFSET); @@ -445,35 +661,34 @@ int vmw_fb_init(struct vmw_private *vmw_priv) */ vmw_priv->fb_info = info; par = info->par; + memset(par, 0, sizeof(*par)); par->vmw_priv = vmw_priv; - par->depth = fb_depth; - par->bpp = fb_bpp; par->vmalloc = NULL; par->max_width = fb_width; par->max_height = fb_height; + drm_modeset_lock_all(vmw_priv->dev); + ret = vmw_kms_fbdev_init_data(vmw_priv, 0, par->max_width, + par->max_height, &par->con, + &par->crtc, &init_mode); + if (ret) { + drm_modeset_unlock_all(vmw_priv->dev); + goto err_kms; + } + + info->var.xres = init_mode->hdisplay; + info->var.yres = init_mode->vdisplay; + drm_modeset_unlock_all(vmw_priv->dev); + /* * Create buffers and alloc memory */ - par->vmalloc = vmalloc(fb_size); + par->vmalloc = vzalloc(fb_size); if (unlikely(par->vmalloc == NULL)) { ret = -ENOMEM; goto err_free; } - ret = vmw_fb_create_bo(vmw_priv, fb_size, &par->vmw_bo); - if (unlikely(ret != 0)) - goto err_free; - - ret = ttm_bo_kmap(&par->vmw_bo->base, - 0, - par->vmw_bo->base.num_pages, - &par->map); - if (unlikely(ret != 0)) - goto err_unref; - par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &par->bo_iowrite); - par->bo_size = fb_size; - /* * Fixed and var */ @@ -509,18 +724,14 @@ int vmw_fb_init(struct vmw_private *vmw_priv) info->var.xres_virtual = fb_width; info->var.yres_virtual = fb_height; - info->var.bits_per_pixel = par->bpp; + info->var.bits_per_pixel = fb_bpp; info->var.xoffset = 0; info->var.yoffset = 0; info->var.activate = FB_ACTIVATE_NOW; info->var.height = -1; info->var.width = -1; - info->var.xres = initial_width; - info->var.yres = initial_height; - /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ - info->apertures = alloc_apertures(1); if (!info->apertures) { ret = -ENOMEM; @@ -536,6 +747,7 @@ int vmw_fb_init(struct vmw_private *vmw_priv) par->dirty.y1 = par->dirty.y2 = 0; par->dirty.active = true; spin_lock_init(&par->dirty.lock); + mutex_init(&par->bo_mutex); info->fbdefio = &vmw_defio; fb_deferred_io_init(info); @@ -543,16 +755,16 @@ int vmw_fb_init(struct vmw_private *vmw_priv) if (unlikely(ret != 0)) goto err_defio; + vmw_fb_set_par(info); + return 0; err_defio: fb_deferred_io_cleanup(info); err_aper: - ttm_bo_kunmap(&par->map); -err_unref: - ttm_bo_unref((struct ttm_buffer_object **)&par->vmw_bo); err_free: vfree(par->vmalloc); +err_kms: framebuffer_release(info); vmw_priv->fb_info = NULL; @@ -563,22 +775,18 @@ int vmw_fb_close(struct vmw_private *vmw_priv) { struct fb_info *info; struct vmw_fb_par *par; - struct ttm_buffer_object *bo; if (!vmw_priv->fb_info) return 0; info = vmw_priv->fb_info; par = info->par; - bo = &par->vmw_bo->base; - par->vmw_bo = NULL; /* ??? order */ fb_deferred_io_cleanup(info); unregister_framebuffer(info); - ttm_bo_kunmap(&par->map); - ttm_bo_unref(&bo); + (void) vmw_fb_kms_detach(par, true, true); vfree(par->vmalloc); framebuffer_release(info); @@ -597,20 +805,16 @@ int vmw_fb_off(struct vmw_private *vmw_priv) info = vmw_priv->fb_info; par = info->par; - if (!par->bo_ptr) - return 0; - vmw_kms_save_vga(vmw_priv); spin_lock_irqsave(&par->dirty.lock, flags); par->dirty.active = false; spin_unlock_irqrestore(&par->dirty.lock, flags); flush_delayed_work(&info->deferred_work); - par->bo_ptr = NULL; - ttm_bo_kunmap(&par->map); - - vmw_dmabuf_unpin(vmw_priv, par->vmw_bo, false); + mutex_lock(&par->bo_mutex); + (void) vmw_fb_kms_detach(par, true, false); + mutex_unlock(&par->bo_mutex); return 0; } @@ -620,8 +824,6 @@ int vmw_fb_on(struct vmw_private *vmw_priv) struct fb_info *info; struct vmw_fb_par *par; unsigned long flags; - bool dummy; - int ret; if (!vmw_priv->fb_info) return -EINVAL; @@ -629,39 +831,10 @@ int vmw_fb_on(struct vmw_private *vmw_priv) info = vmw_priv->fb_info; par = info->par; - /* we are already active */ - if (par->bo_ptr != NULL) - return 0; - - /* Make sure that all overlays are stoped when we take over */ - vmw_overlay_stop_all(vmw_priv); - - ret = vmw_dmabuf_pin_in_start_of_vram(vmw_priv, par->vmw_bo, false); - if (unlikely(ret != 0)) { - DRM_ERROR("could not move buffer to start of VRAM\n"); - goto err_no_buffer; - } - - ret = ttm_bo_kmap(&par->vmw_bo->base, - 0, - par->vmw_bo->base.num_pages, - &par->map); - BUG_ON(ret != 0); - par->bo_ptr = ttm_kmap_obj_virtual(&par->map, &dummy); - + vmw_fb_set_par(info); spin_lock_irqsave(&par->dirty.lock, flags); par->dirty.active = true; spin_unlock_irqrestore(&par->dirty.lock, flags); - vmw_kms_restore_vga(vmw_priv); - -err_no_buffer: - vmw_fb_set_par(info); - - vmw_fb_dirty_mark(par, 0, 0, info->var.xres, info->var.yres); - - /* If there already was stuff dirty we wont - * schedule a new work, so lets do it now */ - schedule_delayed_work(&info->deferred_work, 0); - + return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index dc9f7d0166c4..06ff7c87fe3b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -372,7 +372,8 @@ static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer) drm_framebuffer_cleanup(framebuffer); vmw_surface_unreference(&vfbs->surface); - ttm_base_object_unref(&vfbs->base.user_obj); + if (vfbs->base.user_obj) + ttm_base_object_unref(&vfbs->base.user_obj); kfree(vfbs); } @@ -582,7 +583,8 @@ static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer) drm_framebuffer_cleanup(framebuffer); vmw_dmabuf_unreference(&vfbd->buffer); - ttm_base_object_unref(&vfbd->base.user_obj); + if (vfbd->base.user_obj) + ttm_base_object_unref(&vfbd->base.user_obj); kfree(vfbd); } @@ -1462,7 +1464,7 @@ static struct drm_display_mode vmw_kms_connector_builtin[] = { * @mode - Pointer to a struct drm_display_mode with hdisplay and vdisplay * members filled in. */ -static void vmw_guess_mode_timing(struct drm_display_mode *mode) +void vmw_guess_mode_timing(struct drm_display_mode *mode) { mode->hsync_start = mode->hdisplay + 50; mode->hsync_end = mode->hsync_start + 50; @@ -2001,3 +2003,58 @@ int vmw_kms_update_proxy(struct vmw_resource *res, return 0; } + +int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, + unsigned unit, + u32 max_width, + u32 max_height, + struct drm_connector **p_con, + struct drm_crtc **p_crtc, + struct drm_display_mode **p_mode) +{ + struct drm_connector *con; + struct vmw_display_unit *du; + struct drm_display_mode *mode; + int i = 0; + + list_for_each_entry(con, &dev_priv->dev->mode_config.connector_list, + head) { + if (i == unit) + break; + + ++i; + } + + if (i != unit) { + DRM_ERROR("Could not find initial display unit.\n"); + return -EINVAL; + } + + if (list_empty(&con->modes)) + (void) vmw_du_connector_fill_modes(con, max_width, max_height); + + if (list_empty(&con->modes)) { + DRM_ERROR("Could not find initial display mode.\n"); + return -EINVAL; + } + + du = vmw_connector_to_du(con); + *p_con = con; + *p_crtc = &du->crtc; + + list_for_each_entry(mode, &con->modes, head) { + if (mode->type & DRM_MODE_TYPE_PREFERRED) + break; + } + + if (mode->type & DRM_MODE_TYPE_PREFERRED) + *p_mode = mode; + else { + WARN_ONCE(true, "Could not find initial preferred mode.\n"); + *p_mode = list_first_entry(&con->modes, + struct drm_display_mode, + head); + } + + return 0; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 311effc7ee74..eb6c8536866f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -243,6 +243,14 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv, struct vmw_surface *surface, bool only_2d, const struct drm_mode_fb_cmd *mode_cmd); +int vmw_kms_fbdev_init_data(struct vmw_private *dev_priv, + unsigned unit, + u32 max_width, + u32 max_height, + struct drm_connector **p_con, + struct drm_crtc **p_crtc, + struct drm_display_mode **p_mode); +void vmw_guess_mode_timing(struct drm_display_mode *mode); /* * Legacy display unit functions - vmwgfx_ldu.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index f0fd565c4e19..51721c37d15b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -279,7 +279,6 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) return -EINVAL; } - vmw_fb_off(dev_priv); vmw_svga_enable(dev_priv); crtc->primary->fb = fb; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 73fe20ef1d10..8b5bc170d5aa 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -369,7 +369,6 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) return -EINVAL; } - vmw_fb_off(dev_priv); vmw_svga_enable(dev_priv); if (mode->hdisplay != crtc->mode.hdisplay || -- cgit v1.3-6-gb490 From 352b20dc51488b264abe6b9755395c63c90e807b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 29 Jun 2015 12:57:37 -0700 Subject: drm/vmwgfx: Reinstate the legacy display system dirty callback It somehow got lost in a rewrite. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 06ff7c87fe3b..ae87e7ec06ef 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -632,10 +632,13 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, true, NULL); break; + case vmw_du_legacy: + ret = vmw_kms_ldu_do_dmabuf_dirty(dev_priv, &vfbd->base, 0, 0, + clips, num_clips, increment); + break; default: - ret = -ENOSYS; - WARN_ONCE(true, - "Dirty called with invalid display system.\n"); + ret = -EINVAL; + WARN_ONCE(true, "Dirty called with invalid display system.\n"); break; } -- cgit v1.3-6-gb490 From f6b05004538ab0933c7527f10a2a6ed88c620f99 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 29 Jun 2015 12:59:58 -0700 Subject: drm/vmwgfx: Fix kms preferred mode sorting The preferred mode typically didn't end up first, since the function drm_mode_connector_list_update() reordered the modes. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index ae87e7ec06ef..ef605b66458f 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1554,11 +1554,9 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, drm_mode_probed_add(connector, mode); } - /* Move the prefered mode first, help apps pick the right mode. */ - if (du->pref_mode) - list_move(&du->pref_mode->head, &connector->probed_modes); - drm_mode_connector_list_update(connector, true); + /* Move the prefered mode first, help apps pick the right mode. */ + drm_mode_sort(&connector->modes); return 1; } -- cgit v1.3-6-gb490 From b9eb1a6174e58eb8beea664ffc20d152230d8004 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 2 Apr 2015 02:39:45 -0700 Subject: drm/vmwgfx: Kill a bunch of sparse warnings We're giving up all attempts to keep cpu- and device byte ordering separate. This silences sparse when compiled using make C=2 CF="-D__CHECK_ENDIAN__" Signed-off-by: Thomas Hellstrom --- drivers/gpu/drm/vmwgfx/svga3d_reg.h | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c | 8 +++---- drivers/gpu/drm/vmwgfx/vmwgfx_context.c | 12 +++++------ drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | 18 ++++++++-------- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 8 +++---- drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c | 37 ++++++++++++++++---------------- drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c | 8 +++---- drivers/gpu/drm/vmwgfx/vmwgfx_irq.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 32 +++++++++++++-------------- drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 10 ++++----- drivers/gpu/drm/vmwgfx/vmwgfx_mob.c | 14 ++++++------ drivers/gpu/drm/vmwgfx/vmwgfx_reg.h | 6 +++--- drivers/gpu/drm/vmwgfx/vmwgfx_resource.c | 17 ++++++--------- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 10 ++++----- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 4 ++-- 20 files changed, 103 insertions(+), 107 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/svga3d_reg.h b/drivers/gpu/drm/vmwgfx/svga3d_reg.h index c9a595a78f2e..f4af9f1ef9be 100644 --- a/drivers/gpu/drm/vmwgfx/svga3d_reg.h +++ b/drivers/gpu/drm/vmwgfx/svga3d_reg.h @@ -35,7 +35,7 @@ #include "svga_reg.h" typedef uint32 PPN; -typedef __le64 PPN64; +typedef u64 PPN64; /* * 3D Hardware Version diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index e94feb338f89..32ec52eaedd8 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -695,10 +695,10 @@ static bool vmw_cmdbuf_try_alloc(struct vmw_cmdbuf_man *man, * no space available ATM, it turns on IRQ handling and sleeps waiting for it to * become available. */ -int vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, - struct drm_mm_node *node, - size_t size, - bool interruptible) +static int vmw_cmdbuf_alloc_space(struct vmw_cmdbuf_man *man, + struct drm_mm_node *node, + size_t size, + bool interruptible) { struct vmw_cmdbuf_alloc_info info; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index a8e370a55e90..2aa8bb818739 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -135,9 +135,9 @@ static void vmw_hw_context_destroy(struct vmw_resource *res) return; } - cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DESTROY); - cmd->header.size = cpu_to_le32(sizeof(cmd->body)); - cmd->body.cid = cpu_to_le32(res->id); + cmd->header.id = SVGA_3D_CMD_CONTEXT_DESTROY; + cmd->header.size = sizeof(cmd->body); + cmd->body.cid = res->id; vmw_fifo_commit(dev_priv, sizeof(*cmd)); vmw_fifo_resource_dec(dev_priv); @@ -215,9 +215,9 @@ static int vmw_context_init(struct vmw_private *dev_priv, return -ENOMEM; } - cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DEFINE); - cmd->header.size = cpu_to_le32(sizeof(cmd->body)); - cmd->body.cid = cpu_to_le32(res->id); + cmd->header.id = SVGA_3D_CMD_CONTEXT_DEFINE; + cmd->header.size = sizeof(cmd->body); + cmd->body.cid = res->id; vmw_fifo_commit(dev_priv, sizeof(*cmd)); vmw_fifo_resource_inc(dev_priv); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c index 4b9344dd6c27..9b4f0939d7bd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c @@ -225,7 +225,7 @@ int vmw_dmabuf_unpin(struct vmw_private *dev_priv, if (unlikely(ret != 0)) return ret; - ret = ttm_bo_reserve(bo, interruptible, false, false, 0); + ret = ttm_bo_reserve(bo, interruptible, false, false, NULL); if (unlikely(ret != 0)) goto err; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 18921444672f..ab67d2a73516 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1225,7 +1225,7 @@ static void vmw_master_drop(struct drm_device *dev, * @dev_priv: Pointer to device private struct. * Needs the reservation sem to be held in non-exclusive mode. */ -void __vmw_svga_enable(struct vmw_private *dev_priv) +static void __vmw_svga_enable(struct vmw_private *dev_priv) { spin_lock(&dev_priv->svga_lock); if (!dev_priv->bdev.man[TTM_PL_VRAM].use_type) { @@ -1254,7 +1254,7 @@ void vmw_svga_enable(struct vmw_private *dev_priv) * Needs the reservation sem to be held in exclusive mode. * Will not empty VRAM. VRAM must be emptied by caller. */ -void __vmw_svga_disable(struct vmw_private *dev_priv) +static void __vmw_svga_disable(struct vmw_private *dev_priv) { spin_lock(&dev_priv->svga_lock); if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 9ae573640156..c9ea9b1277b0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -178,8 +178,8 @@ struct vmw_marker_queue { struct vmw_fifo_state { unsigned long reserved_size; - __le32 *dynamic_buffer; - __le32 *static_buffer; + u32 *dynamic_buffer; + u32 *static_buffer; unsigned long static_buffer_size; bool using_bounce_buffer; uint32_t capabilities; @@ -405,7 +405,7 @@ struct vmw_private { uint32_t stdu_max_height; uint32_t initial_width; uint32_t initial_height; - __le32 __iomem *mmio_virt; + u32 __iomem *mmio_virt; int mmio_mtrr; uint32_t capabilities; uint32_t max_gmr_ids; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 64dba53ca54c..40fdd0258664 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -1850,7 +1850,7 @@ static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv, uint32_t size_remaining = *size; uint32_t cmd_id; - cmd_id = le32_to_cpu(((uint32_t *)buf)[0]); + cmd_id = ((uint32_t *)buf)[0]; switch (cmd_id) { case SVGA_CMD_UPDATE: *size = sizeof(uint32_t) + sizeof(SVGAFifoCmdUpdate); @@ -2066,14 +2066,14 @@ static int vmw_cmd_check(struct vmw_private *dev_priv, const struct vmw_cmd_entry *entry; bool gb = dev_priv->capabilities & SVGA_CAP_GBOBJECTS; - cmd_id = le32_to_cpu(((uint32_t *)buf)[0]); + cmd_id = ((uint32_t *)buf)[0]; /* Handle any none 3D commands */ if (unlikely(cmd_id < SVGA_CMD_MAX)) return vmw_cmd_check_not_3d(dev_priv, sw_context, buf, size); - cmd_id = le32_to_cpu(header->id); - *size = le32_to_cpu(header->size) + sizeof(SVGA3dCmdHeader); + cmd_id = header->id; + *size = header->size + sizeof(SVGA3dCmdHeader); cmd_id -= SVGA_3D_CMD_BASE; if (unlikely(*size > size_remaining)) @@ -2499,11 +2499,11 @@ static int vmw_execbuf_submit_cmdbuf(struct vmw_private *dev_priv, * If the function is interrupted by a signal while sleeping, it will return * -ERESTARTSYS casted to a pointer error value. */ -void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv, - void __user *user_commands, - void *kernel_commands, - u32 command_size, - struct vmw_cmdbuf_header **header) +static void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv, + void __user *user_commands, + void *kernel_commands, + u32 command_size, + struct vmw_cmdbuf_header **header) { size_t cmdbuf_size; int ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 9dbb2031a017..9856803e7aba 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -331,7 +331,7 @@ static void vmw_deferred_io(struct fb_info *info, vmw_fb_dirty_flush(par); }; -struct fb_deferred_io vmw_defio = { +static struct fb_deferred_io vmw_defio = { .delay = VMW_DIRTY_DELAY, .deferred_io = vmw_deferred_io, }; @@ -706,7 +706,7 @@ int vmw_fb_init(struct vmw_private *vmw_priv) info->fix.smem_len = fb_size; info->pseudo_palette = par->pseudo_palette; - info->screen_base = par->vmalloc; + info->screen_base = (char __iomem *)par->vmalloc; info->screen_size = fb_size; info->flags = FBINFO_DEFAULT; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index 945f1e0dad92..75d6222b510a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -142,7 +142,7 @@ static bool vmw_fence_enable_signaling(struct fence *f) struct vmw_fence_manager *fman = fman_from_fence(fence); struct vmw_private *dev_priv = fman->dev_priv; - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; u32 seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE); if (seqno - fence->base.seqno < VMW_FENCE_WRAP) return false; @@ -386,7 +386,7 @@ static bool vmw_fence_goal_new_locked(struct vmw_fence_manager *fman, u32 passed_seqno) { u32 goal_seqno; - __le32 __iomem *fifo_mem; + u32 __iomem *fifo_mem; struct vmw_fence_obj *fence; if (likely(!fman->seqno_valid)) @@ -430,7 +430,7 @@ static bool vmw_fence_goal_check_locked(struct vmw_fence_obj *fence) { struct vmw_fence_manager *fman = fman_from_fence(fence); u32 goal_seqno; - __le32 __iomem *fifo_mem; + u32 __iomem *fifo_mem; if (fence_is_signaled_locked(&fence->base)) return false; @@ -453,7 +453,7 @@ static void __vmw_fences_update(struct vmw_fence_manager *fman) struct list_head action_list; bool needs_rerun; uint32_t seqno, new_seqno; - __le32 __iomem *fifo_mem = fman->dev_priv->mmio_virt; + u32 __iomem *fifo_mem = fman->dev_priv->mmio_virt; seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE); rerun: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 9b8b09f8135b..7a6cf1700745 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -31,7 +31,7 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t fifo_min, hwversion; const struct vmw_fifo_state *fifo = &dev_priv->fifo; @@ -80,7 +80,7 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv) { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t caps; if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) @@ -95,7 +95,7 @@ bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv) int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t max; uint32_t min; @@ -158,7 +158,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason) { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; static DEFINE_SPINLOCK(ping_lock); unsigned long irq_flags; @@ -176,7 +176,7 @@ void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason) void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC); while (vmw_read(dev_priv, SVGA_REG_BUSY) != 0) @@ -206,7 +206,7 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo) static bool vmw_fifo_is_full(struct vmw_private *dev_priv, uint32_t bytes) { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t max = ioread32(fifo_mem + SVGA_FIFO_MAX); uint32_t next_cmd = ioread32(fifo_mem + SVGA_FIFO_NEXT_CMD); uint32_t min = ioread32(fifo_mem + SVGA_FIFO_MIN); @@ -314,7 +314,7 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes) { struct vmw_fifo_state *fifo_state = &dev_priv->fifo; - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t max; uint32_t min; uint32_t next_cmd; @@ -371,7 +371,8 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv, if (reserveable) iowrite32(bytes, fifo_mem + SVGA_FIFO_RESERVED); - return fifo_mem + (next_cmd >> 2); + return (void __force *) (fifo_mem + + (next_cmd >> 2)); } else { need_bounce = true; } @@ -414,7 +415,7 @@ void *vmw_fifo_reserve(struct vmw_private *dev_priv, uint32_t bytes) } static void vmw_fifo_res_copy(struct vmw_fifo_state *fifo_state, - __le32 __iomem *fifo_mem, + u32 __iomem *fifo_mem, uint32_t next_cmd, uint32_t max, uint32_t min, uint32_t bytes) { @@ -436,7 +437,7 @@ static void vmw_fifo_res_copy(struct vmw_fifo_state *fifo_state, } static void vmw_fifo_slow_copy(struct vmw_fifo_state *fifo_state, - __le32 __iomem *fifo_mem, + u32 __iomem *fifo_mem, uint32_t next_cmd, uint32_t max, uint32_t min, uint32_t bytes) { @@ -455,10 +456,10 @@ static void vmw_fifo_slow_copy(struct vmw_fifo_state *fifo_state, } } -void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) +static void vmw_local_fifo_commit(struct vmw_private *dev_priv, uint32_t bytes) { struct vmw_fifo_state *fifo_state = &dev_priv->fifo; - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t next_cmd = ioread32(fifo_mem + SVGA_FIFO_NEXT_CMD); uint32_t max = ioread32(fifo_mem + SVGA_FIFO_MAX); uint32_t min = ioread32(fifo_mem + SVGA_FIFO_MIN); @@ -545,9 +546,9 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) { struct vmw_fifo_state *fifo_state = &dev_priv->fifo; struct svga_fifo_cmd_fence *cmd_fence; - void *fm; + u32 *fm; int ret = 0; - uint32_t bytes = sizeof(__le32) + sizeof(*cmd_fence); + uint32_t bytes = sizeof(u32) + sizeof(*cmd_fence); fm = vmw_fifo_reserve(dev_priv, bytes); if (unlikely(fm == NULL)) { @@ -573,11 +574,9 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *seqno) return 0; } - *(__le32 *) fm = cpu_to_le32(SVGA_CMD_FENCE); - cmd_fence = (struct svga_fifo_cmd_fence *) - ((unsigned long)fm + sizeof(__le32)); - - iowrite32(*seqno, &cmd_fence->fence); + *fm++ = SVGA_CMD_FENCE; + cmd_fence = (struct svga_fifo_cmd_fence *) fm; + cmd_fence->fence = *seqno; vmw_fifo_commit_flush(dev_priv, bytes); (void) vmw_marker_push(&fifo_state->marker_queue, *seqno); vmw_update_seqno(dev_priv, fifo_state); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 55940bc0eb07..6db98289b8a4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -63,7 +63,7 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, break; case DRM_VMW_PARAM_FIFO_HW_VERSION: { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; const struct vmw_fifo_state *fifo = &dev_priv->fifo; if ((dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) { @@ -158,7 +158,7 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data, (struct drm_vmw_get_3d_cap_arg *) data; struct vmw_private *dev_priv = vmw_priv(dev); uint32_t size; - __le32 __iomem *fifo_mem; + u32 __iomem *fifo_mem; void __user *buffer = (void __user *)((unsigned long)(arg->buffer)); void *bounce; int ret; @@ -239,7 +239,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, int ret; num_clips = arg->num_clips; - clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr; + clips_ptr = (struct drm_vmw_rect __user *)(unsigned long)arg->clips_ptr; if (unlikely(num_clips == 0)) return 0; @@ -322,7 +322,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, int ret; num_clips = arg->num_clips; - clips_ptr = (struct drm_vmw_rect *)(unsigned long)arg->clips_ptr; + clips_ptr = (struct drm_vmw_rect __user *)(unsigned long)arg->clips_ptr; if (unlikely(num_clips == 0)) return 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c index 87964bb0704e..2c2bac4a0fd6 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c @@ -72,7 +72,7 @@ static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t seqno) void vmw_update_seqno(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo_state) { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE); if (dev_priv->last_read_seqno != seqno) { @@ -178,7 +178,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv, } finish_wait(&dev_priv->fence_queue, &__wait); if (ret == 0 && fifo_idle) { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; iowrite32(signal_seq, fifo_mem + SVGA_FIFO_FENCE); } wake_up_all(&dev_priv->fence_queue); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index ef605b66458f..ca69ed4a3926 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -71,12 +71,12 @@ int vmw_cursor_update_image(struct vmw_private *dev_priv, memcpy(&cmd[1], image, image_size); - cmd->cmd = cpu_to_le32(SVGA_CMD_DEFINE_ALPHA_CURSOR); - cmd->cursor.id = cpu_to_le32(0); - cmd->cursor.width = cpu_to_le32(width); - cmd->cursor.height = cpu_to_le32(height); - cmd->cursor.hotspotX = cpu_to_le32(hotspotX); - cmd->cursor.hotspotY = cpu_to_le32(hotspotY); + cmd->cmd = SVGA_CMD_DEFINE_ALPHA_CURSOR; + cmd->cursor.id = 0; + cmd->cursor.width = width; + cmd->cursor.height = height; + cmd->cursor.hotspotX = hotspotX; + cmd->cursor.hotspotY = hotspotY; vmw_fifo_commit(dev_priv, cmd_size); @@ -123,7 +123,7 @@ err_unreserve: void vmw_cursor_update_position(struct vmw_private *dev_priv, bool show, int x, int y) { - __le32 __iomem *fifo_mem = dev_priv->mmio_virt; + u32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t count; iowrite32(show ? 1 : 0, fifo_mem + SVGA_FIFO_CURSOR_ON); @@ -1017,14 +1017,14 @@ static const struct drm_mode_config_funcs vmw_kms_funcs = { .fb_create = vmw_kms_fb_create, }; -int vmw_kms_generic_present(struct vmw_private *dev_priv, - struct drm_file *file_priv, - struct vmw_framebuffer *vfb, - struct vmw_surface *surface, - uint32_t sid, - int32_t destX, int32_t destY, - struct drm_vmw_rect *clips, - uint32_t num_clips) +static int vmw_kms_generic_present(struct vmw_private *dev_priv, + struct drm_file *file_priv, + struct vmw_framebuffer *vfb, + struct vmw_surface *surface, + uint32_t sid, + int32_t destX, int32_t destY, + struct drm_vmw_rect *clips, + uint32_t num_clips) { return vmw_kms_sou_do_surface_dirty(dev_priv, vfb, NULL, clips, &surface->res, destX, destY, @@ -1785,7 +1785,7 @@ int vmw_kms_helper_buffer_prepare(struct vmw_private *dev_priv, struct ttm_buffer_object *bo = &buf->base; int ret; - ttm_bo_reserve(bo, false, false, interruptible, 0); + ttm_bo_reserve(bo, false, false, interruptible, NULL); ret = vmw_validate_single_buffer(dev_priv, bo, interruptible, validate_as_mob); if (ret) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 51721c37d15b..55038457a096 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -476,11 +476,11 @@ int vmw_kms_ldu_do_dmabuf_dirty(struct vmw_private *dev_priv, memset(cmd, 0, fifo_size); for (i = 0; i < num_clips; i++, clips += increment) { - cmd[i].header = cpu_to_le32(SVGA_CMD_UPDATE); - cmd[i].body.x = cpu_to_le32(clips->x1); - cmd[i].body.y = cpu_to_le32(clips->y1); - cmd[i].body.width = cpu_to_le32(clips->x2 - clips->x1); - cmd[i].body.height = cpu_to_le32(clips->y2 - clips->y1); + cmd[i].header = SVGA_CMD_UPDATE; + cmd[i].body.x = clips->x1; + cmd[i].body.y = clips->y1; + cmd[i].body.width = clips->x2 - clips->x1; + cmd[i].body.height = clips->y2 - clips->y1; } vmw_fifo_commit(dev_priv, fifo_size); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index e0fc2485ddb1..c5897cb4e4d5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -142,7 +142,7 @@ static int vmw_setup_otable_base(struct vmw_private *dev_priv, cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE64; cmd->header.size = sizeof(cmd->body); cmd->body.type = type; - cmd->body.baseAddress = cpu_to_le64(mob->pt_root_page >> PAGE_SHIFT); + cmd->body.baseAddress = mob->pt_root_page >> PAGE_SHIFT; cmd->body.sizeInBytes = otable->size; cmd->body.validSizeInBytes = 0; cmd->body.ptDepth = mob->pt_level; @@ -430,15 +430,15 @@ out_unreserve: * *@addr according to the page table entry size. */ #if (VMW_PPN_SIZE == 8) -static void vmw_mob_assign_ppn(__le32 **addr, dma_addr_t val) +static void vmw_mob_assign_ppn(u32 **addr, dma_addr_t val) { - *((__le64 *) *addr) = cpu_to_le64(val >> PAGE_SHIFT); + *((u64 *) *addr) = val >> PAGE_SHIFT; *addr += 2; } #else -static void vmw_mob_assign_ppn(__le32 **addr, dma_addr_t val) +static void vmw_mob_assign_ppn(u32 **addr, dma_addr_t val) { - *(*addr)++ = cpu_to_le32(val >> PAGE_SHIFT); + *(*addr)++ = val >> PAGE_SHIFT; } #endif @@ -460,7 +460,7 @@ static unsigned long vmw_mob_build_pt(struct vmw_piter *data_iter, unsigned long pt_size = num_data_pages * VMW_PPN_SIZE; unsigned long num_pt_pages = DIV_ROUND_UP(pt_size, PAGE_SIZE); unsigned long pt_page; - __le32 *addr, *save_addr; + u32 *addr, *save_addr; unsigned long i; struct page *page; @@ -641,7 +641,7 @@ int vmw_mob_bind(struct vmw_private *dev_priv, cmd->header.size = sizeof(cmd->body); cmd->body.mobid = mob_id; cmd->body.ptDepth = mob->pt_level; - cmd->body.base = cpu_to_le64(mob->pt_root_page >> PAGE_SHIFT); + cmd->body.base = mob->pt_root_page >> PAGE_SHIFT; cmd->body.sizeInBytes = num_data_pages * PAGE_SIZE; vmw_fifo_commit(dev_priv, sizeof(*cmd)); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h b/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h index 9d0dd3a342eb..29d06a4cf024 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_reg.h @@ -39,12 +39,12 @@ #define VMWGFX_IRQSTATUS_PORT 0x8 struct svga_guest_mem_descriptor { - __le32 ppn; - __le32 num_pages; + u32 ppn; + u32 num_pages; }; struct svga_fifo_cmd_fence { - __le32 fence; + u32 fence; }; #define SVGA_SYNC_GENERIC 1 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 69b471af0130..be2809aaa7cb 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -121,6 +121,7 @@ static void vmw_resource_release(struct kref *kref) int id; struct idr *idr = &dev_priv->res_idr[res->func->res_type]; + write_lock(&dev_priv->resource_lock); res->avail = false; list_del_init(&res->lru_head); write_unlock(&dev_priv->resource_lock); @@ -156,20 +157,17 @@ static void vmw_resource_release(struct kref *kref) kfree(res); write_lock(&dev_priv->resource_lock); - if (id != -1) idr_remove(idr, id); + write_unlock(&dev_priv->resource_lock); } void vmw_resource_unreference(struct vmw_resource **p_res) { struct vmw_resource *res = *p_res; - struct vmw_private *dev_priv = res->dev_priv; *p_res = NULL; - write_lock(&dev_priv->resource_lock); kref_put(&res->kref, vmw_resource_release); - write_unlock(&dev_priv->resource_lock); } @@ -260,17 +258,16 @@ void vmw_resource_activate(struct vmw_resource *res, write_unlock(&dev_priv->resource_lock); } -struct vmw_resource *vmw_resource_lookup(struct vmw_private *dev_priv, - struct idr *idr, int id) +static struct vmw_resource *vmw_resource_lookup(struct vmw_private *dev_priv, + struct idr *idr, int id) { struct vmw_resource *res; read_lock(&dev_priv->resource_lock); res = idr_find(idr, id); - if (res && res->avail) - kref_get(&res->kref); - else + if (!res || !res->avail || !kref_get_unless_zero(&res->kref)) res = NULL; + read_unlock(&dev_priv->resource_lock); if (unlikely(res == NULL)) @@ -1306,7 +1303,7 @@ vmw_resource_backoff_reservation(struct ttm_validate_buffer *val_buf) * @res: The resource to evict. * @interruptible: Whether to wait interruptible. */ -int vmw_resource_do_evict(struct vmw_resource *res, bool interruptible) +static int vmw_resource_do_evict(struct vmw_resource *res, bool interruptible) { struct ttm_validate_buffer val_buf; const struct vmw_res_func *func = res->func; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 8b5bc170d5aa..2af3fa1b1904 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -450,8 +450,8 @@ static bool vmw_sou_screen_object_flippable(struct vmw_private *dev_priv, * Update the implicit fb to the current fb of this crtc. * Must be called with the mode_config mutex held. */ -void vmw_sou_update_implicit_fb(struct vmw_private *dev_priv, - struct drm_crtc *crtc) +static void vmw_sou_update_implicit_fb(struct vmw_private *dev_priv, + struct drm_crtc *crtc) { struct vmw_screen_object_unit *sou = vmw_crtc_to_sou(crtc); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index 6110a433ebfe..11bc60c2771a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -407,11 +407,11 @@ out: } -struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buffer, - size_t shader_size, - size_t offset, - SVGA3dShaderType shader_type) +static struct vmw_resource *vmw_shader_alloc(struct vmw_private *dev_priv, + struct vmw_dma_buffer *buffer, + size_t shader_size, + size_t offset, + SVGA3dShaderType shader_type) { struct vmw_shader *shader; struct vmw_resource *res; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 835f3431574f..843d7e04b376 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -220,7 +220,7 @@ static void vmw_surface_define_encode(const struct vmw_surface *srf, cmd->header.size = cmd_len; cmd->body.sid = srf->res.id; cmd->body.surfaceFlags = srf->flags; - cmd->body.format = cpu_to_le32(srf->format); + cmd->body.format = srf->format; for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) cmd->body.face[i].numMipLevels = srf->mip_levels[i]; @@ -1054,7 +1054,7 @@ static int vmw_gb_surface_create(struct vmw_resource *res) cmd->header.size = cmd_len; cmd->body.sid = srf->res.id; cmd->body.surfaceFlags = srf->flags; - cmd->body.format = cpu_to_le32(srf->format); + cmd->body.format = srf->format; cmd->body.numMipLevels = srf->mip_levels[0]; cmd->body.multisampleCount = srf->multisample_count; cmd->body.autogenFilter = srf->autogen_filter; -- cgit v1.3-6-gb490 From 2e3cc8cff629c9697ac27c95a89dda7c7785b6b4 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 4 Aug 2015 15:34:14 +0200 Subject: drm/vmwgfx: Fix compiler warning with 32-bit dma_addr_t When the size of dma_addr_t was 32 bits, the compiler warned about the size of the 32 bit shift being larger than the size of the data type. Reported by Intel's kbuild robot. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh Reviewed-by: Brian Paul --- drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index 32ec52eaedd8..afc6d1df47d7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -293,8 +293,12 @@ static int vmw_cmdbuf_header_submit(struct vmw_cmdbuf_header *header) struct vmw_cmdbuf_man *man = header->man; u32 val; - val = (header->handle >> 32); + if (sizeof(header->handle) > 4) + val = (header->handle >> 32); + else + val = 0; vmw_write(man->dev_priv, SVGA_REG_COMMAND_HIGH, val); + val = (header->handle & 0xFFFFFFFFULL); val |= header->cb_context & SVGA_CB_CONTEXT_MASK; vmw_write(man->dev_priv, SVGA_REG_COMMAND_LOW, val); -- cgit v1.3-6-gb490 From 6a5278ee34e7fd4b051fd107a94a099778458d8c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 4 Aug 2015 15:37:16 +0200 Subject: drm/vmwgfx: Fix an uninitialized value Reported by Intel's kbuild robot. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh Reviewed-by: Brian Paul --- drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index afc6d1df47d7..5667c134e409 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -507,7 +507,7 @@ static void vmw_cmdbuf_work_func(struct work_struct *work) struct vmw_cmdbuf_man *man = container_of(work, struct vmw_cmdbuf_man, work); struct vmw_cmdbuf_header *entry, *next; - bool restart; + bool restart = false; spin_lock_bh(&man->lock); list_for_each_entry_safe(entry, next, &man->error, list) { -- cgit v1.3-6-gb490 From 00a48fe341ed497be64df2c6875af0da45d6ae90 Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Sun, 26 Jul 2015 23:37:48 +0200 Subject: clk: imx31: add a second rtc clock The mxc rtc driver needs two clock. It was defined only one clock, so we define the second clock. Signed-off-by: Philippe Reynes Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx31.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c index fe66c40b7be2..1f8383475bb3 100644 --- a/drivers/clk/imx/clk-imx31.c +++ b/drivers/clk/imx/clk-imx31.c @@ -147,7 +147,8 @@ int __init mx31_clocks_init(unsigned long fref) clk_register_clkdev(clk[cspi3_gate], NULL, "imx31-cspi.2"); clk_register_clkdev(clk[pwm_gate], "pwm", NULL); clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); - clk_register_clkdev(clk[rtc_gate], NULL, "imx21-rtc"); + clk_register_clkdev(clk[ckil], "ref", "imx21-rtc"); + clk_register_clkdev(clk[rtc_gate], "ipg", "imx21-rtc"); clk_register_clkdev(clk[epit1_gate], "epit", NULL); clk_register_clkdev(clk[epit2_gate], "epit", NULL); clk_register_clkdev(clk[nfc], NULL, "imx27-nand.0"); -- cgit v1.3-6-gb490 From 3713e3f5e9274bbe52e94716bde303071364c1ed Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Sun, 26 Jul 2015 23:37:49 +0200 Subject: clk: imx35: define two clocks for rtc The imx35 don't define clocks for rtc. This patch add two clocks, as needed by the mxc rtc driver. Signed-off-by: Philippe Reynes Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx35.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c index 69138ba3dec7..8623cd4e49fd 100644 --- a/drivers/clk/imx/clk-imx35.c +++ b/drivers/clk/imx/clk-imx35.c @@ -66,7 +66,7 @@ static const char *std_sel[] = {"ppll", "arm"}; static const char *ipg_per_sel[] = {"ahb_per_div", "arm_per_div"}; enum mx35_clks { - ckih, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg, + ckih, ckil, mpll, ppll, mpll_075, arm, hsp, hsp_div, hsp_sel, ahb, ipg, arm_per_div, ahb_per_div, ipg_per, uart_sel, uart_div, esdhc_sel, esdhc1_div, esdhc2_div, esdhc3_div, spdif_sel, spdif_div_pre, spdif_div_post, ssi_sel, ssi1_div_pre, ssi1_div_post, ssi2_div_pre, @@ -107,6 +107,7 @@ int __init mx35_clocks_init(void) } clk[ckih] = imx_clk_fixed("ckih", 24000000); + clk[ckil] = imx_clk_fixed("ckih", 32768); clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "mpll", "ckih", base + MX35_CCM_MPCTL); clk[ppll] = imx_clk_pllv1(IMX_PLLV1_IMX35, "ppll", "ckih", base + MX35_CCM_PPCTL); @@ -258,6 +259,9 @@ int __init mx35_clocks_init(void) clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1"); clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2"); clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2"); + /* i.mx35 has the i.mx21 type rtc */ + clk_register_clkdev(clk[ckil], "ref", "imx21-rtc"); + clk_register_clkdev(clk[rtc_gate], "ipg", "imx21-rtc"); clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0"); clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0"); clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.0"); -- cgit v1.3-6-gb490 From 8f5fe77828e16ef6fd8e4931ab177b41449ce8fc Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Sun, 26 Jul 2015 23:37:50 +0200 Subject: rtc: mxc: use a second rtc clock The mxc RTC needs two clocks, one for the input reference, and one for the IP. But this driver was only using one clock (for the reference). This patch add the second clock (for the IP). Acked-by: Alexandre Belloni Signed-off-by: Philippe Reynes Signed-off-by: Shawn Guo --- drivers/rtc/rtc-mxc.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 5fc292c2dfdf..880d485d5cc1 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -79,7 +79,8 @@ struct rtc_plat_data { struct rtc_device *rtc; void __iomem *ioaddr; int irq; - struct clk *clk; + struct clk *clk_ref; + struct clk *clk_ipg; struct rtc_time g_rtc_alarm; enum imx_rtc_type devtype; }; @@ -373,17 +374,28 @@ static int mxc_rtc_probe(struct platform_device *pdev) if (IS_ERR(pdata->ioaddr)) return PTR_ERR(pdata->ioaddr); - pdata->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(pdata->clk)) { - dev_err(&pdev->dev, "unable to get clock!\n"); - return PTR_ERR(pdata->clk); + pdata->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(pdata->clk_ipg)) { + dev_err(&pdev->dev, "unable to get ipg clock!\n"); + return PTR_ERR(pdata->clk_ipg); } - ret = clk_prepare_enable(pdata->clk); + ret = clk_prepare_enable(pdata->clk_ipg); if (ret) return ret; - rate = clk_get_rate(pdata->clk); + pdata->clk_ref = devm_clk_get(&pdev->dev, "ref"); + if (IS_ERR(pdata->clk_ref)) { + dev_err(&pdev->dev, "unable to get ref clock!\n"); + ret = PTR_ERR(pdata->clk_ref); + goto exit_put_clk_ipg; + } + + ret = clk_prepare_enable(pdata->clk_ref); + if (ret) + goto exit_put_clk_ipg; + + rate = clk_get_rate(pdata->clk_ref); if (rate == 32768) reg = RTC_INPUT_CLK_32768HZ; @@ -394,7 +406,7 @@ static int mxc_rtc_probe(struct platform_device *pdev) else { dev_err(&pdev->dev, "rtc clock is not valid (%lu)\n", rate); ret = -EINVAL; - goto exit_put_clk; + goto exit_put_clk_ref; } reg |= RTC_ENABLE_BIT; @@ -402,7 +414,7 @@ static int mxc_rtc_probe(struct platform_device *pdev) if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) { dev_err(&pdev->dev, "hardware module can't be enabled!\n"); ret = -EIO; - goto exit_put_clk; + goto exit_put_clk_ref; } platform_set_drvdata(pdev, pdata); @@ -424,15 +436,17 @@ static int mxc_rtc_probe(struct platform_device *pdev) THIS_MODULE); if (IS_ERR(rtc)) { ret = PTR_ERR(rtc); - goto exit_put_clk; + goto exit_put_clk_ref; } pdata->rtc = rtc; return 0; -exit_put_clk: - clk_disable_unprepare(pdata->clk); +exit_put_clk_ref: + clk_disable_unprepare(pdata->clk_ref); +exit_put_clk_ipg: + clk_disable_unprepare(pdata->clk_ipg); return ret; } @@ -441,7 +455,8 @@ static int mxc_rtc_remove(struct platform_device *pdev) { struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - clk_disable_unprepare(pdata->clk); + clk_disable_unprepare(pdata->clk_ref); + clk_disable_unprepare(pdata->clk_ipg); return 0; } -- cgit v1.3-6-gb490 From cec13c26e90e53015360c09574a7a2cde8d29495 Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Sun, 26 Jul 2015 23:37:52 +0200 Subject: rtc: mxc: add support of device tree Add device tree support for the mxc rtc driver. Acked-by: Alexandre Belloni Signed-off-by: Philippe Reynes Signed-off-by: Shawn Guo --- drivers/rtc/rtc-mxc.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 880d485d5cc1..7bd89d90048f 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #define RTC_INPUT_CLK_32768HZ (0x00 << 5) #define RTC_INPUT_CLK_32000HZ (0x01 << 5) @@ -98,6 +100,15 @@ static const struct platform_device_id imx_rtc_devtype[] = { }; MODULE_DEVICE_TABLE(platform, imx_rtc_devtype); +#ifdef CONFIG_OF +static const struct of_device_id imx_rtc_dt_ids[] = { + { .compatible = "fsl,imx1-rtc", .data = (const void *)IMX1_RTC }, + { .compatible = "fsl,imx21-rtc", .data = (const void *)IMX21_RTC }, + {} +}; +MODULE_DEVICE_TABLE(of, imx_rtc_dt_ids); +#endif + static inline int is_imx1_rtc(struct rtc_plat_data *data) { return data->devtype == IMX1_RTC; @@ -362,12 +373,17 @@ static int mxc_rtc_probe(struct platform_device *pdev) u32 reg; unsigned long rate; int ret; + const struct of_device_id *of_id; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->devtype = pdev->id_entry->driver_data; + of_id = of_match_device(imx_rtc_dt_ids, &pdev->dev); + if (of_id) + pdata->devtype = (enum imx_rtc_type)of_id->data; + else + pdata->devtype = pdev->id_entry->driver_data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); @@ -488,6 +504,7 @@ static SIMPLE_DEV_PM_OPS(mxc_rtc_pm_ops, mxc_rtc_suspend, mxc_rtc_resume); static struct platform_driver mxc_rtc_driver = { .driver = { .name = "mxc_rtc", + .of_match_table = of_match_ptr(imx_rtc_dt_ids), .pm = &mxc_rtc_pm_ops, }, .id_table = imx_rtc_devtype, -- cgit v1.3-6-gb490 From 44e259ac909f3b41786cf732a44b5cf8444e098a Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 15 Jul 2015 19:59:36 +0100 Subject: ARM: dove: create a proper PMU driver for power domains, PMU IRQs and resets The PMU device contains an interrupt controller, power control and resets. The interrupt controller is a little sub-standard in that there is no race free way to clear down pending interrupts, so we try to avoid problems by reducing the window as much as possible, and clearing as infrequently as possible. The interrupt support is implemented using an IRQ domain, and the parent interrupt referenced in the standard DT way. The power domains and reset support is closely related - there is a defined sequence for powering down a domain which is tightly coupled with asserting the reset. Hence, it makes sense to group these two together, and in order to avoid any locking contention disrupting this sequence, we avoid the use of syscon or regmap. This patch adds the core PMU driver: power domains must be defined in the DT file in order to make use of them. The reset controller can be referenced in the standard way for reset controllers. Signed-off-by: Russell King Signed-off-by: Andrew Lunn Signed-off-by: Gregory CLEMENT --- arch/arm/mach-mvebu/Kconfig | 1 + arch/arm/mach-mvebu/dove.c | 2 + drivers/soc/Makefile | 1 + drivers/soc/dove/Makefile | 1 + drivers/soc/dove/pmu.c | 412 +++++++++++++++++++++++++++++++++++++++++++ include/linux/soc/dove/pmu.h | 6 + 6 files changed, 423 insertions(+) create mode 100644 drivers/soc/dove/Makefile create mode 100644 drivers/soc/dove/pmu.c create mode 100644 include/linux/soc/dove/pmu.h (limited to 'drivers') diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 97473168d6b6..c86a5a0aefac 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -96,6 +96,7 @@ config MACH_DOVE select MACH_MVEBU_ANY select ORION_IRQCHIP select ORION_TIMER + select PM_GENERIC_DOMAINS if PM select PINCTRL_DOVE help Say 'Y' here if you want your kernel to support the diff --git a/arch/arm/mach-mvebu/dove.c b/arch/arm/mach-mvebu/dove.c index 5a1741500a30..1aebb82e3d7b 100644 --- a/arch/arm/mach-mvebu/dove.c +++ b/arch/arm/mach-mvebu/dove.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "common.h" @@ -24,6 +25,7 @@ static void __init dove_init(void) tauros2_init(0); #endif BUG_ON(mvebu_mbus_dt_init(false)); + dove_init_pmu(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 7dc7c0d8a2c1..0b12d777d3c4 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -2,6 +2,7 @@ # Makefile for the Linux Kernel SOC specific device drivers. # +obj-$(CONFIG_MACH_DOVE) += dove/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ obj-$(CONFIG_ARCH_QCOM) += qcom/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ diff --git a/drivers/soc/dove/Makefile b/drivers/soc/dove/Makefile new file mode 100644 index 000000000000..2db8e65513a3 --- /dev/null +++ b/drivers/soc/dove/Makefile @@ -0,0 +1 @@ +obj-y += pmu.o diff --git a/drivers/soc/dove/pmu.c b/drivers/soc/dove/pmu.c new file mode 100644 index 000000000000..6792aae9e2e5 --- /dev/null +++ b/drivers/soc/dove/pmu.c @@ -0,0 +1,412 @@ +/* + * Marvell Dove PMU support + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NR_PMU_IRQS 7 + +#define PMC_SW_RST 0x30 +#define PMC_IRQ_CAUSE 0x50 +#define PMC_IRQ_MASK 0x54 + +#define PMU_PWR 0x10 +#define PMU_ISO 0x58 + +struct pmu_data { + spinlock_t lock; + struct device_node *of_node; + void __iomem *pmc_base; + void __iomem *pmu_base; + struct irq_chip_generic *irq_gc; + struct irq_domain *irq_domain; +#ifdef CONFIG_RESET_CONTROLLER + struct reset_controller_dev reset; +#endif +}; + +/* + * The PMU contains a register to reset various subsystems within the + * SoC. Export this as a reset controller. + */ +#ifdef CONFIG_RESET_CONTROLLER +#define rcdev_to_pmu(rcdev) container_of(rcdev, struct pmu_data, reset) + +static int pmu_reset_reset(struct reset_controller_dev *rc, unsigned long id) +{ + struct pmu_data *pmu = rcdev_to_pmu(rc); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&pmu->lock, flags); + val = readl_relaxed(pmu->pmc_base + PMC_SW_RST); + writel_relaxed(val & ~BIT(id), pmu->pmc_base + PMC_SW_RST); + writel_relaxed(val | BIT(id), pmu->pmc_base + PMC_SW_RST); + spin_unlock_irqrestore(&pmu->lock, flags); + + return 0; +} + +static int pmu_reset_assert(struct reset_controller_dev *rc, unsigned long id) +{ + struct pmu_data *pmu = rcdev_to_pmu(rc); + unsigned long flags; + u32 val = ~BIT(id); + + spin_lock_irqsave(&pmu->lock, flags); + val &= readl_relaxed(pmu->pmc_base + PMC_SW_RST); + writel_relaxed(val, pmu->pmc_base + PMC_SW_RST); + spin_unlock_irqrestore(&pmu->lock, flags); + + return 0; +} + +static int pmu_reset_deassert(struct reset_controller_dev *rc, unsigned long id) +{ + struct pmu_data *pmu = rcdev_to_pmu(rc); + unsigned long flags; + u32 val = BIT(id); + + spin_lock_irqsave(&pmu->lock, flags); + val |= readl_relaxed(pmu->pmc_base + PMC_SW_RST); + writel_relaxed(val, pmu->pmc_base + PMC_SW_RST); + spin_unlock_irqrestore(&pmu->lock, flags); + + return 0; +} + +static struct reset_control_ops pmu_reset_ops = { + .reset = pmu_reset_reset, + .assert = pmu_reset_assert, + .deassert = pmu_reset_deassert, +}; + +static struct reset_controller_dev pmu_reset __initdata = { + .ops = &pmu_reset_ops, + .owner = THIS_MODULE, + .nr_resets = 32, +}; + +static void __init pmu_reset_init(struct pmu_data *pmu) +{ + int ret; + + pmu->reset = pmu_reset; + pmu->reset.of_node = pmu->of_node; + + ret = reset_controller_register(&pmu->reset); + if (ret) + pr_err("pmu: %s failed: %d\n", "reset_controller_register", ret); +} +#else +static void __init pmu_reset_init(struct pmu_data *pmu) +{ +} +#endif + +struct pmu_domain { + struct pmu_data *pmu; + u32 pwr_mask; + u32 rst_mask; + u32 iso_mask; + struct generic_pm_domain base; +}; + +#define to_pmu_domain(dom) container_of(dom, struct pmu_domain, base) + +/* + * This deals with the "old" Marvell sequence of bringing a power domain + * down/up, which is: apply power, release reset, disable isolators. + * + * Later devices apparantly use a different sequence: power up, disable + * isolators, assert repair signal, enable SRMA clock, enable AXI clock, + * enable module clock, deassert reset. + * + * Note: reading the assembly, it seems that the IO accessors have an + * unfortunate side-effect - they cause memory already read into registers + * for the if () to be re-read for the bit-set or bit-clear operation. + * The code is written to avoid this. + */ +static int pmu_domain_power_off(struct generic_pm_domain *domain) +{ + struct pmu_domain *pmu_dom = to_pmu_domain(domain); + struct pmu_data *pmu = pmu_dom->pmu; + unsigned long flags; + unsigned int val; + void __iomem *pmu_base = pmu->pmu_base; + void __iomem *pmc_base = pmu->pmc_base; + + spin_lock_irqsave(&pmu->lock, flags); + + /* Enable isolators */ + if (pmu_dom->iso_mask) { + val = ~pmu_dom->iso_mask; + val &= readl_relaxed(pmu_base + PMU_ISO); + writel_relaxed(val, pmu_base + PMU_ISO); + } + + /* Reset unit */ + if (pmu_dom->rst_mask) { + val = ~pmu_dom->rst_mask; + val &= readl_relaxed(pmc_base + PMC_SW_RST); + writel_relaxed(val, pmc_base + PMC_SW_RST); + } + + /* Power down */ + val = readl_relaxed(pmu_base + PMU_PWR) | pmu_dom->pwr_mask; + writel_relaxed(val, pmu_base + PMU_PWR); + + spin_unlock_irqrestore(&pmu->lock, flags); + + return 0; +} + +static int pmu_domain_power_on(struct generic_pm_domain *domain) +{ + struct pmu_domain *pmu_dom = to_pmu_domain(domain); + struct pmu_data *pmu = pmu_dom->pmu; + unsigned long flags; + unsigned int val; + void __iomem *pmu_base = pmu->pmu_base; + void __iomem *pmc_base = pmu->pmc_base; + + spin_lock_irqsave(&pmu->lock, flags); + + /* Power on */ + val = ~pmu_dom->pwr_mask & readl_relaxed(pmu_base + PMU_PWR); + writel_relaxed(val, pmu_base + PMU_PWR); + + /* Release reset */ + if (pmu_dom->rst_mask) { + val = pmu_dom->rst_mask; + val |= readl_relaxed(pmc_base + PMC_SW_RST); + writel_relaxed(val, pmc_base + PMC_SW_RST); + } + + /* Disable isolators */ + if (pmu_dom->iso_mask) { + val = pmu_dom->iso_mask; + val |= readl_relaxed(pmu_base + PMU_ISO); + writel_relaxed(val, pmu_base + PMU_ISO); + } + + spin_unlock_irqrestore(&pmu->lock, flags); + + return 0; +} + +static void __pmu_domain_register(struct pmu_domain *domain, + struct device_node *np) +{ + unsigned int val = readl_relaxed(domain->pmu->pmu_base + PMU_PWR); + + domain->base.power_off = pmu_domain_power_off; + domain->base.power_on = pmu_domain_power_on; + + pm_genpd_init(&domain->base, NULL, !(val & domain->pwr_mask)); + + if (np) + of_genpd_add_provider_simple(np, &domain->base); +} + +/* PMU IRQ controller */ +static void pmu_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct pmu_data *pmu = irq_get_handler_data(irq); + struct irq_chip_generic *gc = pmu->irq_gc; + struct irq_domain *domain = pmu->irq_domain; + void __iomem *base = gc->reg_base; + u32 stat = readl_relaxed(base + PMC_IRQ_CAUSE) & gc->mask_cache; + u32 done = ~0; + + if (stat == 0) { + handle_bad_irq(irq, desc); + return; + } + + while (stat) { + u32 hwirq = fls(stat) - 1; + + stat &= ~(1 << hwirq); + done &= ~(1 << hwirq); + + generic_handle_irq(irq_find_mapping(domain, hwirq)); + } + + /* + * The PMU mask register is not RW0C: it is RW. This means that + * the bits take whatever value is written to them; if you write + * a '1', you will set the interrupt. + * + * Unfortunately this means there is NO race free way to clear + * these interrupts. + * + * So, let's structure the code so that the window is as small as + * possible. + */ + irq_gc_lock(gc); + done &= readl_relaxed(base + PMC_IRQ_CAUSE); + writel_relaxed(done, base + PMC_IRQ_CAUSE); + irq_gc_unlock(gc); +} + +static int __init dove_init_pmu_irq(struct pmu_data *pmu, int irq) +{ + const char *name = "pmu_irq"; + struct irq_chip_generic *gc; + struct irq_domain *domain; + int ret; + + /* mask and clear all interrupts */ + writel(0, pmu->pmc_base + PMC_IRQ_MASK); + writel(0, pmu->pmc_base + PMC_IRQ_CAUSE); + + domain = irq_domain_add_linear(pmu->of_node, NR_PMU_IRQS, + &irq_generic_chip_ops, NULL); + if (!domain) { + pr_err("%s: unable to add irq domain\n", name); + return -ENOMEM; + } + + ret = irq_alloc_domain_generic_chips(domain, NR_PMU_IRQS, 1, name, + handle_level_irq, + IRQ_NOREQUEST | IRQ_NOPROBE, 0, + IRQ_GC_INIT_MASK_CACHE); + if (ret) { + pr_err("%s: unable to alloc irq domain gc: %d\n", name, ret); + irq_domain_remove(domain); + return ret; + } + + gc = irq_get_domain_generic_chip(domain, 0); + gc->reg_base = pmu->pmc_base; + gc->chip_types[0].regs.mask = PMC_IRQ_MASK; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; + + pmu->irq_domain = domain; + pmu->irq_gc = gc; + + irq_set_handler_data(irq, pmu); + irq_set_chained_handler(irq, pmu_irq_handler); + + return 0; +} + +/* + * pmu: power-manager@d0000 { + * compatible = "marvell,dove-pmu"; + * reg = <0xd0000 0x8000> <0xd8000 0x8000>; + * interrupts = <33>; + * interrupt-controller; + * #reset-cells = 1; + * vpu_domain: vpu-domain { + * #power-domain-cells = <0>; + * marvell,pmu_pwr_mask = <0x00000008>; + * marvell,pmu_iso_mask = <0x00000001>; + * resets = <&pmu 16>; + * }; + * gpu_domain: gpu-domain { + * #power-domain-cells = <0>; + * marvell,pmu_pwr_mask = <0x00000004>; + * marvell,pmu_iso_mask = <0x00000002>; + * resets = <&pmu 18>; + * }; + * }; + */ +int __init dove_init_pmu(void) +{ + struct device_node *np_pmu, *domains_node, *np; + struct pmu_data *pmu; + int ret, parent_irq; + + /* Lookup the PMU node */ + np_pmu = of_find_compatible_node(NULL, NULL, "marvell,dove-pmu"); + if (!np_pmu) + return 0; + + domains_node = of_get_child_by_name(np_pmu, "domains"); + if (!domains_node) { + pr_err("%s: failed to find domains sub-node\n", np_pmu->name); + return 0; + } + + pmu = kzalloc(sizeof(*pmu), GFP_KERNEL); + if (!pmu) + return -ENOMEM; + + spin_lock_init(&pmu->lock); + pmu->of_node = np_pmu; + pmu->pmc_base = of_iomap(pmu->of_node, 0); + pmu->pmu_base = of_iomap(pmu->of_node, 1); + if (!pmu->pmc_base || !pmu->pmu_base) { + pr_err("%s: failed to map PMU\n", np_pmu->name); + iounmap(pmu->pmu_base); + iounmap(pmu->pmc_base); + kfree(pmu); + return -ENOMEM; + } + + pmu_reset_init(pmu); + + for_each_available_child_of_node(domains_node, np) { + struct of_phandle_args args; + struct pmu_domain *domain; + + domain = kzalloc(sizeof(*domain), GFP_KERNEL); + if (!domain) + break; + + domain->pmu = pmu; + domain->base.name = kstrdup(np->name, GFP_KERNEL); + if (!domain->base.name) { + kfree(domain); + break; + } + + of_property_read_u32(np, "marvell,pmu_pwr_mask", + &domain->pwr_mask); + of_property_read_u32(np, "marvell,pmu_iso_mask", + &domain->iso_mask); + + /* + * We parse the reset controller property directly here + * to ensure that we can operate when the reset controller + * support is not configured into the kernel. + */ + ret = of_parse_phandle_with_args(np, "resets", "#reset-cells", + 0, &args); + if (ret == 0) { + if (args.np == pmu->of_node) + domain->rst_mask = BIT(args.args[0]); + of_node_put(args.np); + } + + __pmu_domain_register(domain, np); + } + pm_genpd_poweroff_unused(); + + /* Loss of the interrupt controller is not a fatal error. */ + parent_irq = irq_of_parse_and_map(pmu->of_node, 0); + if (!parent_irq) { + pr_err("%s: no interrupt specified\n", np_pmu->name); + } else { + ret = dove_init_pmu_irq(pmu, parent_irq); + if (ret) + pr_err("dove_init_pmu_irq() failed: %d\n", ret); + } + + return 0; +} diff --git a/include/linux/soc/dove/pmu.h b/include/linux/soc/dove/pmu.h new file mode 100644 index 000000000000..9c99f84bcc0e --- /dev/null +++ b/include/linux/soc/dove/pmu.h @@ -0,0 +1,6 @@ +#ifndef LINUX_SOC_DOVE_PMU_H +#define LINUX_SOC_DOVE_PMU_H + +int dove_init_pmu(void); + +#endif -- cgit v1.3-6-gb490 From f368ed6088ae9c1fbe1c897bb5f215ce5e63fa1e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 30 Jul 2015 15:59:57 -0700 Subject: char: make misc_deregister a void function With well over 200+ users of this api, there are a mere 12 users that actually checked the return value of this function. And all of them really didn't do anything with that information as the system or module was shutting down no matter what. So stop pretending like it matters, and just return void from misc_deregister(). If something goes wrong in the call, you will get a WARNING splat in the syslog so you know how to fix up your driver. Other than that, there's nothing that can go wrong. Cc: Alasdair Kergon Cc: Neil Brown Cc: Oleg Drokin Cc: Andreas Dilger Cc: "Michael S. Tsirkin" Cc: Wim Van Sebroeck Cc: Christine Caulfield Cc: David Teigland Cc: Mark Fasheh Acked-by: Joel Becker Acked-by: Alexandre Belloni Acked-by: Alessandro Zummo Acked-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman --- drivers/char/misc.c | 9 +++------ drivers/md/dm-ioctl.c | 4 +--- drivers/misc/vmw_vmci/vmci_host.c | 7 +------ drivers/rtc/rtc-ds1374.c | 5 ++--- drivers/staging/android/ashmem.c | 7 +------ drivers/staging/android/ion/ion_test.c | 3 ++- drivers/staging/lustre/lustre/libcfs/module.c | 4 +--- drivers/vhost/scsi.c | 4 ++-- drivers/watchdog/at91rm9200_wdt.c | 5 ++--- drivers/watchdog/ks8695_wdt.c | 9 +++------ drivers/watchdog/ts72xx_wdt.c | 3 ++- fs/btrfs/super.c | 3 +-- fs/dlm/plock.c | 3 +-- fs/dlm/user.c | 9 +++------ fs/ocfs2/stack_user.c | 9 +-------- include/linux/miscdevice.h | 2 +- 16 files changed, 27 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/char/misc.c b/drivers/char/misc.c index c83ef9652bc9..8069b361b8dd 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -243,17 +243,15 @@ int misc_register(struct miscdevice * misc) * @misc: device to unregister * * Unregister a miscellaneous device that was previously - * successfully registered with misc_register(). Success - * is indicated by a zero return, a negative errno code - * indicates an error. + * successfully registered with misc_register(). */ -int misc_deregister(struct miscdevice *misc) +void misc_deregister(struct miscdevice *misc) { int i = DYNAMIC_MINORS - misc->minor - 1; if (WARN_ON(list_empty(&misc->list))) - return -EINVAL; + return; mutex_lock(&misc_mtx); list_del(&misc->list); @@ -261,7 +259,6 @@ int misc_deregister(struct miscdevice *misc) if (i < DYNAMIC_MINORS && i >= 0) clear_bit(i, misc_minors); mutex_unlock(&misc_mtx); - return 0; } EXPORT_SYMBOL(misc_register); diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 720ceeb7fa9b..80a439543259 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1919,9 +1919,7 @@ int __init dm_interface_init(void) void dm_interface_exit(void) { - if (misc_deregister(&_dm_misc) < 0) - DMERR("misc_deregister failed for control device"); - + misc_deregister(&_dm_misc); dm_hash_exit(); } diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c index a721b5d8a9da..9ec262a52656 100644 --- a/drivers/misc/vmw_vmci/vmci_host.c +++ b/drivers/misc/vmw_vmci/vmci_host.c @@ -1031,14 +1031,9 @@ int __init vmci_host_init(void) void __exit vmci_host_exit(void) { - int error; - vmci_host_device_initialized = false; - error = misc_deregister(&vmci_host_miscdev); - if (error) - pr_warn("Error unregistering character device: %d\n", error); - + misc_deregister(&vmci_host_miscdev); vmci_ctx_destroy(host_context); vmci_qp_broker_exit(); diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 167783fa7ac1..72c933375233 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -666,9 +666,8 @@ static int ds1374_remove(struct i2c_client *client) #ifdef CONFIG_RTC_DRV_DS1374_WDT int res; - res = misc_deregister(&ds1374_miscdev); - if (!res) - ds1374_miscdev.parent = NULL; + misc_deregister(&ds1374_miscdev); + ds1374_miscdev.parent = NULL; unregister_reboot_notifier(&ds1374_wdt_notifier); #endif diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index c5c037ccf32c..2c75d90b26c8 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -863,14 +863,9 @@ static int __init ashmem_init(void) static void __exit ashmem_exit(void) { - int ret; - unregister_shrinker(&ashmem_shrinker); - ret = misc_deregister(&ashmem_misc); - if (unlikely(ret)) - pr_err("failed to unregister misc device!\n"); - + misc_deregister(&ashmem_misc); kmem_cache_destroy(ashmem_range_cachep); kmem_cache_destroy(ashmem_area_cachep); diff --git a/drivers/staging/android/ion/ion_test.c b/drivers/staging/android/ion/ion_test.c index 7d6e6b6bc894..b8dcf5a26cc4 100644 --- a/drivers/staging/android/ion/ion_test.c +++ b/drivers/staging/android/ion/ion_test.c @@ -269,7 +269,8 @@ static int ion_test_remove(struct platform_device *pdev) if (!testdev) return -ENODATA; - return misc_deregister(&testdev->misc); + misc_deregister(&testdev->misc); + return 0; } static struct platform_device *ion_test_pdev; diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c index e60b2e9b9194..e7074006e41b 100644 --- a/drivers/staging/lustre/lustre/libcfs/module.c +++ b/drivers/staging/lustre/lustre/libcfs/module.c @@ -467,9 +467,7 @@ static void exit_libcfs_module(void) cfs_crypto_unregister(); cfs_wi_shutdown(); - rc = misc_deregister(&libcfs_dev); - if (rc) - CERROR("misc_deregister error %d\n", rc); + misc_deregister(&libcfs_dev); cfs_cpu_fini(); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index dfcc02c93648..f114a9dbb48f 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1573,9 +1573,9 @@ static int __init vhost_scsi_register(void) return misc_register(&vhost_scsi_misc); } -static int vhost_scsi_deregister(void) +static void vhost_scsi_deregister(void) { - return misc_deregister(&vhost_scsi_misc); + misc_deregister(&vhost_scsi_misc); } static char *vhost_scsi_dump_proto_id(struct vhost_scsi_tport *tport) diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c index 41cecb55766c..9ba1153465ae 100644 --- a/drivers/watchdog/at91rm9200_wdt.c +++ b/drivers/watchdog/at91rm9200_wdt.c @@ -269,9 +269,8 @@ static int at91wdt_remove(struct platform_device *pdev) if (res) dev_warn(dev, "failed to unregister restart handler\n"); - res = misc_deregister(&at91wdt_miscdev); - if (!res) - at91wdt_miscdev.parent = NULL; + misc_deregister(&at91wdt_miscdev); + at91wdt_miscdev.parent = NULL; return res; } diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c index b7ea39b455c8..1e41818a44bc 100644 --- a/drivers/watchdog/ks8695_wdt.c +++ b/drivers/watchdog/ks8695_wdt.c @@ -254,13 +254,10 @@ static int ks8695wdt_probe(struct platform_device *pdev) static int ks8695wdt_remove(struct platform_device *pdev) { - int res; - - res = misc_deregister(&ks8695wdt_miscdev); - if (!res) - ks8695wdt_miscdev.parent = NULL; + misc_deregister(&ks8695wdt_miscdev); + ks8695wdt_miscdev.parent = NULL; - return res; + return 0; } static void ks8695wdt_shutdown(struct platform_device *pdev) diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c index 119beb7f6017..4b541934b6c5 100644 --- a/drivers/watchdog/ts72xx_wdt.c +++ b/drivers/watchdog/ts72xx_wdt.c @@ -428,7 +428,8 @@ static int ts72xx_wdt_probe(struct platform_device *pdev) static int ts72xx_wdt_remove(struct platform_device *pdev) { - return misc_deregister(&ts72xx_wdt_miscdev); + misc_deregister(&ts72xx_wdt_miscdev); + return 0; } static struct platform_driver ts72xx_wdt_driver = { diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index cd7ef34d2dce..6bad63379a4c 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2163,8 +2163,7 @@ static int btrfs_interface_init(void) static void btrfs_interface_exit(void) { - if (misc_deregister(&btrfs_misc) < 0) - printk(KERN_INFO "BTRFS: misc_deregister failed for control device\n"); + misc_deregister(&btrfs_misc); } static void btrfs_print_info(void) diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index e0ab3a93eeff..5532f097f6da 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c @@ -509,7 +509,6 @@ int dlm_plock_init(void) void dlm_plock_exit(void) { - if (misc_deregister(&plock_dev_misc) < 0) - log_print("dlm_plock_exit: misc_deregister failed"); + misc_deregister(&plock_dev_misc); } diff --git a/fs/dlm/user.c b/fs/dlm/user.c index fb85f32e9eca..75ecc0d3bc85 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -362,18 +362,15 @@ fail: int dlm_device_deregister(struct dlm_ls *ls) { - int error; - /* The device is not registered. This happens when the lockspace was never used from userspace, or when device_create_lockspace() calls dlm_release_lockspace() after the register fails. */ if (!ls->ls_device.name) return 0; - error = misc_deregister(&ls->ls_device); - if (!error) - kfree(ls->ls_device.name); - return error; + misc_deregister(&ls->ls_device); + kfree(ls->ls_device.name); + return 0; } static int device_user_purge(struct dlm_user_proc *proc, diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index 2768eb1da2b8..ced70c8139f7 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c @@ -655,14 +655,7 @@ static int ocfs2_control_init(void) static void ocfs2_control_exit(void) { - int rc; - - rc = misc_deregister(&ocfs2_control_device); - if (rc) - printk(KERN_ERR - "ocfs2: Unable to deregister ocfs2_control device " - "(errno %d)\n", - -rc); + misc_deregister(&ocfs2_control_device); } static void fsdlm_lock_ast_wrapper(void *astarg) diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index 819077c32690..81f6e427ba6b 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -67,7 +67,7 @@ struct miscdevice { }; extern int misc_register(struct miscdevice *misc); -extern int misc_deregister(struct miscdevice *misc); +extern void misc_deregister(struct miscdevice *misc); #define MODULE_ALIAS_MISCDEV(minor) \ MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) \ -- cgit v1.3-6-gb490 From 6fd3850227961d70594acd45d146ad28367415b5 Mon Sep 17 00:00:00 2001 From: James Chen Date: Mon, 20 Jul 2015 11:16:36 -0700 Subject: Input: elants_i2c - disable idle mode before updating firmware If the device is in idle mode and is in the middle of a scan it may not have a chance to react to the reset and then IAP commands within required time interval and firmware update may fail. Let's bring the device out of idle mode before attempting to reset it so that the scan period is smaller and thus it can react to the command quicker. Signed-off-by: James Chen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elants_i2c.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 746137694137..42e43f14602e 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -605,6 +605,7 @@ static int elants_i2c_do_update_firmware(struct i2c_client *client, const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 }; const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 }; const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc }; + const u8 close_idle[] = {0x54, 0x2c, 0x01, 0x01}; u8 buf[HEADER_SIZE]; u16 send_id; int page, n_fw_pages; @@ -617,8 +618,13 @@ static int elants_i2c_do_update_firmware(struct i2c_client *client, } else { /* Start IAP Procedure */ dev_dbg(&client->dev, "Normal IAP procedure\n"); + /* Close idle mode */ + error = elants_i2c_send(client, close_idle, sizeof(close_idle)); + if (error) + dev_err(&client->dev, "Failed close idle: %d\n", error); + msleep(60); elants_i2c_sw_reset(client); - + msleep(20); error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); } -- cgit v1.3-6-gb490 From 7f163a6fd957a85f7f66a129db1ad243a44399ee Mon Sep 17 00:00:00 2001 From: Jake Oshins Date: Wed, 5 Aug 2015 00:52:36 -0700 Subject: drivers:hv: Modify hv_vmbus to search for all MMIO ranges available. This patch changes the logic in hv_vmbus to record all of the ranges in the VM's firmware (BIOS or UEFI) that offer regions of memory-mapped I/O space for use by paravirtual front-end drivers. The old logic just found one range above 4GB and called it good. This logic will find any ranges above 1MB. It would have been possible with this patch to just use existing resource allocation functions, rather than keep track of the entire set of Hyper-V related MMIO regions in VMBus. This strategy, however, is not sufficient when the resource allocator needs to be aware of the constraints of a Hyper-V virtual machine, which is what happens in the next patch in the series. So this first patch exists to show the first steps in reworking the MMIO allocation paths for Hyper-V front-end drivers. Signed-off-by: Jake Oshins Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 116 +++++++++++++++++++++++++++++++--------- drivers/video/fbdev/hyperv_fb.c | 2 +- include/linux/hyperv.h | 2 +- 3 files changed, 92 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index e7b0bcd453e7..ee59e06c2194 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -102,10 +102,7 @@ static struct notifier_block hyperv_panic_block = { .notifier_call = hyperv_panic_event, }; -struct resource hyperv_mmio = { - .name = "hyperv mmio", - .flags = IORESOURCE_MEM, -}; +struct resource *hyperv_mmio; EXPORT_SYMBOL_GPL(hyperv_mmio); static int vmbus_exists(void) @@ -1013,30 +1010,105 @@ void vmbus_device_unregister(struct hv_device *device_obj) /* - * VMBUS is an acpi enumerated device. Get the the information we + * VMBUS is an acpi enumerated device. Get the information we * need from DSDT. */ - +#define VTPM_BASE_ADDRESS 0xfed40000 static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) { + resource_size_t start = 0; + resource_size_t end = 0; + struct resource *new_res; + struct resource **old_res = &hyperv_mmio; + struct resource **prev_res = NULL; + switch (res->type) { case ACPI_RESOURCE_TYPE_IRQ: irq = res->data.irq.interrupts[0]; + return AE_OK; + + /* + * "Address" descriptors are for bus windows. Ignore + * "memory" descriptors, which are for registers on + * devices. + */ + case ACPI_RESOURCE_TYPE_ADDRESS32: + start = res->data.address32.address.minimum; + end = res->data.address32.address.maximum; break; case ACPI_RESOURCE_TYPE_ADDRESS64: - hyperv_mmio.start = res->data.address64.address.minimum; - hyperv_mmio.end = res->data.address64.address.maximum; + start = res->data.address64.address.minimum; + end = res->data.address64.address.maximum; break; + + default: + /* Unused resource type */ + return AE_OK; + } + /* + * Ignore ranges that are below 1MB, as they're not + * necessary or useful here. + */ + if (end < 0x100000) + return AE_OK; + + new_res = kzalloc(sizeof(*new_res), GFP_ATOMIC); + if (!new_res) + return AE_NO_MEMORY; + + /* If this range overlaps the virtual TPM, truncate it. */ + if (end > VTPM_BASE_ADDRESS && start < VTPM_BASE_ADDRESS) + end = VTPM_BASE_ADDRESS; + + new_res->name = "hyperv mmio"; + new_res->flags = IORESOURCE_MEM; + new_res->start = start; + new_res->end = end; + + do { + if (!*old_res) { + *old_res = new_res; + break; + } + + if ((*old_res)->end < new_res->start) { + new_res->sibling = *old_res; + if (prev_res) + (*prev_res)->sibling = new_res; + *old_res = new_res; + break; + } + + prev_res = old_res; + old_res = &(*old_res)->sibling; + + } while (1); return AE_OK; } +static int vmbus_acpi_remove(struct acpi_device *device) +{ + struct resource *cur_res; + struct resource *next_res; + + if (hyperv_mmio) { + for (cur_res = hyperv_mmio; cur_res; cur_res = next_res) { + next_res = cur_res->sibling; + kfree(cur_res); + } + } + + return 0; +} + static int vmbus_acpi_add(struct acpi_device *device) { acpi_status result; int ret_val = -ENODEV; + struct acpi_device *ancestor; hv_acpi_dev = device; @@ -1046,35 +1118,27 @@ static int vmbus_acpi_add(struct acpi_device *device) if (ACPI_FAILURE(result)) goto acpi_walk_err; /* - * The parent of the vmbus acpi device (Gen2 firmware) is the VMOD that - * has the mmio ranges. Get that. + * Some ancestor of the vmbus acpi device (Gen1 or Gen2 + * firmware) is the VMOD that has the mmio ranges. Get that. */ - if (device->parent) { - result = acpi_walk_resources(device->parent->handle, - METHOD_NAME__CRS, - vmbus_walk_resources, NULL); + for (ancestor = device->parent; ancestor; ancestor = ancestor->parent) { + result = acpi_walk_resources(ancestor->handle, METHOD_NAME__CRS, + vmbus_walk_resources, NULL); if (ACPI_FAILURE(result)) - goto acpi_walk_err; - if (hyperv_mmio.start && hyperv_mmio.end) - request_resource(&iomem_resource, &hyperv_mmio); + continue; + if (hyperv_mmio) + break; } ret_val = 0; acpi_walk_err: complete(&probe_event); + if (ret_val) + vmbus_acpi_remove(device); return ret_val; } -static int vmbus_acpi_remove(struct acpi_device *device) -{ - int ret = 0; - - if (hyperv_mmio.start && hyperv_mmio.end) - ret = release_resource(&hyperv_mmio); - return ret; -} - static const struct acpi_device_id vmbus_acpi_device_ids[] = { {"VMBUS", 0}, {"VMBus", 0}, diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index 807ee22ef229..b54ee1c05a5f 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -688,7 +688,7 @@ static int hvfb_getmem(struct fb_info *info) par->mem.name = KBUILD_MODNAME; par->mem.flags = IORESOURCE_MEM | IORESOURCE_BUSY; if (gen2vm) { - ret = allocate_resource(&hyperv_mmio, &par->mem, + ret = allocate_resource(hyperv_mmio, &par->mem, screen_fb_size, 0, -1, screen_fb_size, diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 30d3a1f79450..217e14be77b9 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1233,7 +1233,7 @@ extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *, void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid); -extern struct resource hyperv_mmio; +extern struct resource *hyperv_mmio; /* * Negotiated version with the Host. -- cgit v1.3-6-gb490 From 3546448338e76a52d4f86eb3680cb2934e22d89b Mon Sep 17 00:00:00 2001 From: Jake Oshins Date: Wed, 5 Aug 2015 00:52:37 -0700 Subject: drivers:hv: Move MMIO range picking from hyper_fb to hv_vmbus This patch deletes the logic from hyperv_fb which picked a range of MMIO space for the frame buffer and adds new logic to hv_vmbus which picks ranges for child drivers. The new logic isn't quite the same as the old, as it considers more possible ranges. Signed-off-by: Jake Oshins Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 88 +++++++++++++++++++++++++++++++++++++++-- drivers/video/fbdev/hyperv_fb.c | 46 ++++++++++----------- include/linux/hyperv.h | 7 +++- 3 files changed, 110 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index ee59e06c2194..8c3eaee8c54c 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include "hyperv_vmbus.h" @@ -103,7 +104,6 @@ static struct notifier_block hyperv_panic_block = { }; struct resource *hyperv_mmio; -EXPORT_SYMBOL_GPL(hyperv_mmio); static int vmbus_exists(void) { @@ -891,8 +891,8 @@ err_cleanup: } /** - * __vmbus_child_driver_register - Register a vmbus's driver - * @drv: Pointer to driver structure you want to register + * __vmbus_child_driver_register() - Register a vmbus's driver + * @hv_driver: Pointer to driver structure you want to register * @owner: owner module of the drv * @mod_name: module name string * @@ -924,7 +924,8 @@ EXPORT_SYMBOL_GPL(__vmbus_driver_register); /** * vmbus_driver_unregister() - Unregister a vmbus's driver - * @drv: Pointer to driver structure you want to un-register + * @hv_driver: Pointer to driver structure you want to + * un-register * * Un-register the given driver that was previous registered with a call to * vmbus_driver_register() @@ -1104,6 +1105,85 @@ static int vmbus_acpi_remove(struct acpi_device *device) return 0; } +/** + * vmbus_allocate_mmio() - Pick a memory-mapped I/O range. + * @new: If successful, supplied a pointer to the + * allocated MMIO space. + * @device_obj: Identifies the caller + * @min: Minimum guest physical address of the + * allocation + * @max: Maximum guest physical address + * @size: Size of the range to be allocated + * @align: Alignment of the range to be allocated + * @fb_overlap_ok: Whether this allocation can be allowed + * to overlap the video frame buffer. + * + * This function walks the resources granted to VMBus by the + * _CRS object in the ACPI namespace underneath the parent + * "bridge" whether that's a root PCI bus in the Generation 1 + * case or a Module Device in the Generation 2 case. It then + * attempts to allocate from the global MMIO pool in a way that + * matches the constraints supplied in these parameters and by + * that _CRS. + * + * Return: 0 on success, -errno on failure + */ +int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, + resource_size_t min, resource_size_t max, + resource_size_t size, resource_size_t align, + bool fb_overlap_ok) +{ + struct resource *iter; + resource_size_t range_min, range_max, start, local_min, local_max; + const char *dev_n = dev_name(&device_obj->device); + u32 fb_end = screen_info.lfb_base + (screen_info.lfb_size << 1); + int i; + + for (iter = hyperv_mmio; iter; iter = iter->sibling) { + if ((iter->start >= max) || (iter->end <= min)) + continue; + + range_min = iter->start; + range_max = iter->end; + + /* If this range overlaps the frame buffer, split it into + two tries. */ + for (i = 0; i < 2; i++) { + local_min = range_min; + local_max = range_max; + if (fb_overlap_ok || (range_min >= fb_end) || + (range_max <= screen_info.lfb_base)) { + i++; + } else { + if ((range_min <= screen_info.lfb_base) && + (range_max >= screen_info.lfb_base)) { + /* + * The frame buffer is in this window, + * so trim this into the part that + * preceeds the frame buffer. + */ + local_max = screen_info.lfb_base - 1; + range_min = fb_end; + } else { + range_min = fb_end; + continue; + } + } + + start = (local_min + align - 1) & ~(align - 1); + for (; start + size - 1 <= local_max; start += align) { + *new = request_mem_region_exclusive(start, size, + dev_n); + if (*new) + return 0; + } + } + } + + return -ENXIO; +} +EXPORT_SYMBOL_GPL(vmbus_allocate_mmio); + static int vmbus_acpi_add(struct acpi_device *device) { acpi_status result; diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c index b54ee1c05a5f..e2451bdb4525 100644 --- a/drivers/video/fbdev/hyperv_fb.c +++ b/drivers/video/fbdev/hyperv_fb.c @@ -213,7 +213,7 @@ struct synthvid_msg { struct hvfb_par { struct fb_info *info; - struct resource mem; + struct resource *mem; bool fb_ready; /* fb device is ready */ struct completion wait; u32 synthvid_version; @@ -677,26 +677,18 @@ static void hvfb_get_option(struct fb_info *info) /* Get framebuffer memory from Hyper-V video pci space */ -static int hvfb_getmem(struct fb_info *info) +static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info) { struct hvfb_par *par = info->par; struct pci_dev *pdev = NULL; void __iomem *fb_virt; int gen2vm = efi_enabled(EFI_BOOT); + resource_size_t pot_start, pot_end; int ret; - par->mem.name = KBUILD_MODNAME; - par->mem.flags = IORESOURCE_MEM | IORESOURCE_BUSY; if (gen2vm) { - ret = allocate_resource(hyperv_mmio, &par->mem, - screen_fb_size, - 0, -1, - screen_fb_size, - NULL, NULL); - if (ret != 0) { - pr_err("Unable to allocate framebuffer memory\n"); - return -ENODEV; - } + pot_start = 0; + pot_end = -1; } else { pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT, PCI_DEVICE_ID_HYPERV_VIDEO, NULL); @@ -709,16 +701,18 @@ static int hvfb_getmem(struct fb_info *info) pci_resource_len(pdev, 0) < screen_fb_size) goto err1; - par->mem.end = pci_resource_end(pdev, 0); - par->mem.start = par->mem.end - screen_fb_size + 1; - ret = request_resource(&pdev->resource[0], &par->mem); - if (ret != 0) { - pr_err("Unable to request framebuffer memory\n"); - goto err1; - } + pot_end = pci_resource_end(pdev, 0); + pot_start = pot_end - screen_fb_size + 1; + } + + ret = vmbus_allocate_mmio(&par->mem, hdev, pot_start, pot_end, + screen_fb_size, 0x100000, true); + if (ret != 0) { + pr_err("Unable to allocate framebuffer memory\n"); + goto err1; } - fb_virt = ioremap(par->mem.start, screen_fb_size); + fb_virt = ioremap(par->mem->start, screen_fb_size); if (!fb_virt) goto err2; @@ -736,7 +730,7 @@ static int hvfb_getmem(struct fb_info *info) info->apertures->ranges[0].size = pci_resource_len(pdev, 0); } - info->fix.smem_start = par->mem.start; + info->fix.smem_start = par->mem->start; info->fix.smem_len = screen_fb_size; info->screen_base = fb_virt; info->screen_size = screen_fb_size; @@ -749,7 +743,8 @@ static int hvfb_getmem(struct fb_info *info) err3: iounmap(fb_virt); err2: - release_resource(&par->mem); + release_mem_region(par->mem->start, screen_fb_size); + par->mem = NULL; err1: if (!gen2vm) pci_dev_put(pdev); @@ -763,7 +758,8 @@ static void hvfb_putmem(struct fb_info *info) struct hvfb_par *par = info->par; iounmap(info->screen_base); - release_resource(&par->mem); + release_mem_region(par->mem->start, screen_fb_size); + par->mem = NULL; } @@ -794,7 +790,7 @@ static int hvfb_probe(struct hv_device *hdev, goto error1; } - ret = hvfb_getmem(info); + ret = hvfb_getmem(hdev, info); if (ret) { pr_err("No memory for framebuffer\n"); goto error2; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 217e14be77b9..54733d5b503e 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -977,6 +977,11 @@ int __must_check __vmbus_driver_register(struct hv_driver *hv_driver, const char *mod_name); void vmbus_driver_unregister(struct hv_driver *hv_driver); +int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, + resource_size_t min, resource_size_t max, + resource_size_t size, resource_size_t align, + bool fb_overlap_ok); + /** * VMBUS_DEVICE - macro used to describe a specific hyperv vmbus device * @@ -1233,8 +1238,6 @@ extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *, void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid); -extern struct resource *hyperv_mmio; - /* * Negotiated version with the Host. */ -- cgit v1.3-6-gb490 From 9f01ec53458d9e9b68f1c555e773b5d1a1f66e94 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 5 Aug 2015 00:52:38 -0700 Subject: Drivers: hv: vmbus: Improve the CPU affiliation for channels The current code tracks the assigned CPUs within a NUMA node in the context of the primary channel. So, if we have a VM with a single NUMA node with 8 VCPUs, we may end up unevenly distributing the channel load. Fix the issue by tracking affiliations globally. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 11 ++++++----- drivers/hv/hv.c | 9 +++++++++ drivers/hv/hyperv_vmbus.h | 5 +++++ include/linux/hyperv.h | 1 - 4 files changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 30613dfa38b3..39c5afc7970c 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -392,6 +392,7 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui struct vmbus_channel *primary = channel->primary_channel; int next_node; struct cpumask available_mask; + struct cpumask *alloced_mask; for (i = IDE; i < MAX_PERF_CHN; i++) { if (!memcmp(type_guid->b, hp_devs[i].guid, @@ -409,7 +410,6 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui * channel, bind it to cpu 0. */ channel->numa_node = 0; - cpumask_set_cpu(0, &channel->alloced_cpus_in_node); channel->target_cpu = 0; channel->target_vp = hv_context.vp_index[0]; return; @@ -434,21 +434,22 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui channel->numa_node = next_node; primary = channel; } + alloced_mask = &hv_context.hv_numa_map[primary->numa_node]; - if (cpumask_weight(&primary->alloced_cpus_in_node) == + if (cpumask_weight(alloced_mask) == cpumask_weight(cpumask_of_node(primary->numa_node))) { /* * We have cycled through all the CPUs in the node; * reset the alloced map. */ - cpumask_clear(&primary->alloced_cpus_in_node); + cpumask_clear(alloced_mask); } - cpumask_xor(&available_mask, &primary->alloced_cpus_in_node, + cpumask_xor(&available_mask, alloced_mask, cpumask_of_node(primary->numa_node)); cur_cpu = cpumask_next(-1, &available_mask); - cpumask_set_cpu(cur_cpu, &primary->alloced_cpus_in_node); + cpumask_set_cpu(cur_cpu, alloced_mask); channel->target_cpu = cur_cpu; channel->target_vp = hv_context.vp_index[cur_cpu]; diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 41d8072d61d9..fd93cfde96d0 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -332,6 +332,13 @@ int hv_synic_alloc(void) size_t ced_size = sizeof(struct clock_event_device); int cpu; + hv_context.hv_numa_map = kzalloc(sizeof(struct cpumask) * nr_node_ids, + GFP_ATOMIC); + if (hv_context.hv_numa_map == NULL) { + pr_err("Unable to allocate NUMA map\n"); + goto err; + } + for_each_online_cpu(cpu) { hv_context.event_dpc[cpu] = kmalloc(size, GFP_ATOMIC); if (hv_context.event_dpc[cpu] == NULL) { @@ -345,6 +352,7 @@ int hv_synic_alloc(void) pr_err("Unable to allocate clock event device\n"); goto err; } + hv_init_clockevent_device(hv_context.clk_evt[cpu], cpu); hv_context.synic_message_page[cpu] = @@ -393,6 +401,7 @@ void hv_synic_free(void) { int cpu; + kfree(hv_context.hv_numa_map); for_each_online_cpu(cpu) hv_synic_free_cpu(cpu); } diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 638370701657..6f258255ac94 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -551,6 +551,11 @@ struct hv_context { * Support PV clockevent device. */ struct clock_event_device *clk_evt[NR_CPUS]; + /* + * To manage allocations in a NUMA node. + * Array indexed by numa node ID. + */ + struct cpumask *hv_numa_map; }; extern struct hv_context hv_context; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 54733d5b503e..5a3df5a47c8f 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -699,7 +699,6 @@ struct vmbus_channel { /* * State to manage the CPU affiliation of channels. */ - struct cpumask alloced_cpus_in_node; int numa_node; /* * Support for sub-channels. For high performance devices, -- cgit v1.3-6-gb490 From 3b71107d73b16074afa7658f3f0fcf837aabfe24 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 5 Aug 2015 00:52:39 -0700 Subject: Drivers: hv: vmbus: Further improve CPU affiliation logic Keep track of CPU affiliations of sub-channels within the scope of the primary channel. This will allow us to better distribute the load amongst available CPUs. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 20 ++++++++++++++++++-- include/linux/hyperv.h | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 39c5afc7970c..2f9aead4ecfc 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -448,8 +448,24 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui cpumask_xor(&available_mask, alloced_mask, cpumask_of_node(primary->numa_node)); - cur_cpu = cpumask_next(-1, &available_mask); - cpumask_set_cpu(cur_cpu, alloced_mask); + cur_cpu = -1; + while (true) { + cur_cpu = cpumask_next(cur_cpu, &available_mask); + if (cur_cpu >= nr_cpu_ids) { + cur_cpu = -1; + cpumask_copy(&available_mask, + cpumask_of_node(primary->numa_node)); + continue; + } + + if (!cpumask_test_cpu(cur_cpu, + &primary->alloced_cpus_in_node)) { + cpumask_set_cpu(cur_cpu, + &primary->alloced_cpus_in_node); + cpumask_set_cpu(cur_cpu, alloced_mask); + break; + } + } channel->target_cpu = cur_cpu; channel->target_vp = hv_context.vp_index[cur_cpu]; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 5a3df5a47c8f..54733d5b503e 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -699,6 +699,7 @@ struct vmbus_channel { /* * State to manage the CPU affiliation of channels. */ + struct cpumask alloced_cpus_in_node; int numa_node; /* * Support for sub-channels. For high performance devices, -- cgit v1.3-6-gb490 From a5cca686ce0ef4909deaee4ed46dd991e3a9ece4 Mon Sep 17 00:00:00 2001 From: Christopher Oo Date: Wed, 5 Aug 2015 00:52:40 -0700 Subject: Drivers: hv_vmbus: Fix signal to host condition Fixes a bug where previously hv_ringbuffer_read would pass in the old number of bytes available to read instead of the expected old read index when calculating when to signal to the host that the ringbuffer is empty. Since the previous write size is already saved, also changes the hv_need_to_signal_on_read to use the previously read value rather than recalculating it. Signed-off-by: Christopher Oo Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/ring_buffer.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 6361d124f67d..70a1a9a22f87 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -103,10 +103,9 @@ static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi) * there is room for the producer to send the pending packet. */ -static bool hv_need_to_signal_on_read(u32 old_rd, - struct hv_ring_buffer_info *rbi) +static bool hv_need_to_signal_on_read(u32 prev_write_sz, + struct hv_ring_buffer_info *rbi) { - u32 prev_write_sz; u32 cur_write_sz; u32 r_size; u32 write_loc = rbi->ring_buffer->write_index; @@ -123,10 +122,6 @@ static bool hv_need_to_signal_on_read(u32 old_rd, cur_write_sz = write_loc >= read_loc ? r_size - (write_loc - read_loc) : read_loc - write_loc; - prev_write_sz = write_loc >= old_rd ? r_size - (write_loc - old_rd) : - old_rd - write_loc; - - if ((prev_write_sz < pending_sz) && (cur_write_sz >= pending_sz)) return true; @@ -517,7 +512,6 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, u32 next_read_location = 0; u64 prev_indices = 0; unsigned long flags; - u32 old_read; if (buflen <= 0) return -EINVAL; @@ -528,8 +522,6 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, &bytes_avail_toread, &bytes_avail_towrite); - old_read = bytes_avail_toread; - /* Make sure there is something to read */ if (bytes_avail_toread < buflen) { spin_unlock_irqrestore(&inring_info->ring_lock, flags); @@ -560,7 +552,7 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, spin_unlock_irqrestore(&inring_info->ring_lock, flags); - *signal = hv_need_to_signal_on_read(old_read, inring_info); + *signal = hv_need_to_signal_on_read(bytes_avail_towrite, inring_info); return 0; } -- cgit v1.3-6-gb490 From bc609cb47fb2e74654e23cef0a1d4db38b6570a3 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 5 Aug 2015 00:52:41 -0700 Subject: drivers/hv: Migrate to new 'set-state' interface Migrate hv driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: "K. Y. Srinivasan" Cc: Haiyang Zhang Cc: devel@linuxdriverproject.org Signed-off-by: Viresh Kumar Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv.c | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index fd93cfde96d0..c641faf92e60 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -274,7 +274,7 @@ static int hv_ce_set_next_event(unsigned long delta, { cycle_t current_tick; - WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT); + WARN_ON(!clockevent_state_oneshot(evt)); rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); current_tick += delta; @@ -282,31 +282,24 @@ static int hv_ce_set_next_event(unsigned long delta, return 0; } -static void hv_ce_setmode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int hv_ce_shutdown(struct clock_event_device *evt) +{ + wrmsrl(HV_X64_MSR_STIMER0_COUNT, 0); + wrmsrl(HV_X64_MSR_STIMER0_CONFIG, 0); + + return 0; +} + +static int hv_ce_set_oneshot(struct clock_event_device *evt) { union hv_timer_config timer_cfg; - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* unsupported */ - break; - - case CLOCK_EVT_MODE_ONESHOT: - timer_cfg.enable = 1; - timer_cfg.auto_enable = 1; - timer_cfg.sintx = VMBUS_MESSAGE_SINT; - wrmsrl(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64); - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - wrmsrl(HV_X64_MSR_STIMER0_COUNT, 0); - wrmsrl(HV_X64_MSR_STIMER0_CONFIG, 0); - break; - case CLOCK_EVT_MODE_RESUME: - break; - } + timer_cfg.enable = 1; + timer_cfg.auto_enable = 1; + timer_cfg.sintx = VMBUS_MESSAGE_SINT; + wrmsrl(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64); + + return 0; } static void hv_init_clockevent_device(struct clock_event_device *dev, int cpu) @@ -321,7 +314,8 @@ static void hv_init_clockevent_device(struct clock_event_device *dev, int cpu) * references to the hv_vmbus module making it impossible to unload. */ - dev->set_mode = hv_ce_setmode; + dev->set_state_shutdown = hv_ce_shutdown; + dev->set_state_oneshot = hv_ce_set_oneshot; dev->set_next_event = hv_ce_set_next_event; } @@ -515,8 +509,7 @@ void hv_synic_cleanup(void *arg) /* Turn off clockevent device */ if (ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE) - hv_ce_setmode(CLOCK_EVT_MODE_SHUTDOWN, - hv_context.clk_evt[cpu]); + hv_ce_shutdown(hv_context.clk_evt[cpu]); rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64); -- cgit v1.3-6-gb490 From ca9357bd26c2f8e7b909321eedd651f52cc30d04 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 5 Aug 2015 00:52:42 -0700 Subject: Drivers: hv: vmbus: Implement a clocksource based on the TSC page The current Hyper-V clock source is based on the per-partition reference counter and this counter is being accessed via s synthetic MSR - HV_X64_MSR_TIME_REF_COUNT. Hyper-V has a more efficient way of computing the per-partition reference counter value that does not involve reading a synthetic MSR. We implement a time source based on this mechanism. Tested-by: Vivek Yadav Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/uapi/asm/hyperv.h | 2 + drivers/hv/hv.c | 83 ++++++++++++++++++++++++++++++++++++++ drivers/hv/hyperv_vmbus.h | 9 +++++ 3 files changed, 94 insertions(+) (limited to 'drivers') diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index f36d56bd7632..f0412c50c47b 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -27,6 +27,8 @@ #define HV_X64_MSR_VP_RUNTIME_AVAILABLE (1 << 0) /* Partition Reference Counter (HV_X64_MSR_TIME_REF_COUNT) available*/ #define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1) +/* Partition reference TSC MSR is available */ +#define HV_X64_MSR_REFERENCE_TSC_AVAILABLE (1 << 9) /* A partition's reference time stamp counter (TSC) page */ #define HV_X64_MSR_REFERENCE_TSC 0x40000021 diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index c641faf92e60..6341be8739ae 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -133,6 +133,56 @@ static u64 do_hypercall(u64 control, void *input, void *output) #endif /* !x86_64 */ } +#ifdef CONFIG_X86_64 +static cycle_t read_hv_clock_tsc(struct clocksource *arg) +{ + cycle_t current_tick; + struct ms_hyperv_tsc_page *tsc_pg = hv_context.tsc_page; + + if (tsc_pg->tsc_sequence != -1) { + /* + * Use the tsc page to compute the value. + */ + + while (1) { + cycle_t tmp; + u32 sequence = tsc_pg->tsc_sequence; + u64 cur_tsc; + u64 scale = tsc_pg->tsc_scale; + s64 offset = tsc_pg->tsc_offset; + + rdtscll(cur_tsc); + /* current_tick = ((cur_tsc *scale) >> 64) + offset */ + asm("mulq %3" + : "=d" (current_tick), "=a" (tmp) + : "a" (cur_tsc), "r" (scale)); + + current_tick += offset; + if (tsc_pg->tsc_sequence == sequence) + return current_tick; + + if (tsc_pg->tsc_sequence != -1) + continue; + /* + * Fallback using MSR method. + */ + break; + } + } + rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); + return current_tick; +} + +static struct clocksource hyperv_cs_tsc = { + .name = "hyperv_clocksource_tsc_page", + .rating = 425, + .read = read_hv_clock_tsc, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; +#endif + + /* * hv_init - Main initialization routine. * @@ -142,7 +192,9 @@ int hv_init(void) { int max_leaf; union hv_x64_msr_hypercall_contents hypercall_msr; + union hv_x64_msr_hypercall_contents tsc_msr; void *virtaddr = NULL; + void *va_tsc = NULL; memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS); memset(hv_context.synic_message_page, 0, @@ -186,6 +238,22 @@ int hv_init(void) hv_context.hypercall_page = virtaddr; +#ifdef CONFIG_X86_64 + if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) { + va_tsc = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL); + if (!va_tsc) + goto cleanup; + hv_context.tsc_page = va_tsc; + + rdmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64); + + tsc_msr.enable = 1; + tsc_msr.guest_physical_address = vmalloc_to_pfn(va_tsc); + + wrmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64); + clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100); + } +#endif return 0; cleanup: @@ -219,6 +287,21 @@ void hv_cleanup(void) vfree(hv_context.hypercall_page); hv_context.hypercall_page = NULL; } + +#ifdef CONFIG_X86_64 + /* + * Cleanup the TSC page based CS. + */ + if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) { + clocksource_change_rating(&hyperv_cs_tsc, 10); + clocksource_unregister(&hyperv_cs_tsc); + + hypercall_msr.as_uint64 = 0; + wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64); + vfree(hv_context.tsc_page); + hv_context.tsc_page = NULL; + } +#endif } /* diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 6f258255ac94..3d70e36c918e 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -517,6 +517,7 @@ struct hv_context { u64 guestid; void *hypercall_page; + void *tsc_page; bool synic_initialized; @@ -560,6 +561,14 @@ struct hv_context { extern struct hv_context hv_context; +struct ms_hyperv_tsc_page { + volatile u32 tsc_sequence; + u32 reserved1; + volatile u64 tsc_scale; + volatile s64 tsc_offset; + u64 reserved2[509]; +}; + struct hv_ring_buffer_debug_info { u32 current_interrupt_mask; u32 current_read_index; -- cgit v1.3-6-gb490 From 042ab0313bbb7e776e9510da3f07fb300d08a8ba Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Wed, 5 Aug 2015 00:52:43 -0700 Subject: Drivers: hv: vmbus: add a sysfs attr to show the binding of channel/VP This is useful to analyze performance issue. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'drivers') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 8c3eaee8c54c..45d6d7a0ed89 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -441,6 +441,43 @@ static ssize_t in_write_bytes_avail_show(struct device *dev, } static DEVICE_ATTR_RO(in_write_bytes_avail); +static ssize_t channel_vp_mapping_show(struct device *dev, + struct device_attribute *dev_attr, + char *buf) +{ + struct hv_device *hv_dev = device_to_hv_device(dev); + struct vmbus_channel *channel = hv_dev->channel, *cur_sc; + unsigned long flags; + int buf_size = PAGE_SIZE, n_written, tot_written; + struct list_head *cur; + + if (!channel) + return -ENODEV; + + tot_written = snprintf(buf, buf_size, "%u:%u\n", + channel->offermsg.child_relid, channel->target_cpu); + + spin_lock_irqsave(&channel->lock, flags); + + list_for_each(cur, &channel->sc_list) { + if (tot_written >= buf_size - 1) + break; + + cur_sc = list_entry(cur, struct vmbus_channel, sc_list); + n_written = scnprintf(buf + tot_written, + buf_size - tot_written, + "%u:%u\n", + cur_sc->offermsg.child_relid, + cur_sc->target_cpu); + tot_written += n_written; + } + + spin_unlock_irqrestore(&channel->lock, flags); + + return tot_written; +} +static DEVICE_ATTR_RO(channel_vp_mapping); + /* Set up per device attributes in /sys/bus/vmbus/devices/ */ static struct attribute *vmbus_attrs[] = { &dev_attr_id.attr, @@ -465,6 +502,7 @@ static struct attribute *vmbus_attrs[] = { &dev_attr_in_write_index.attr, &dev_attr_in_read_bytes_avail.attr, &dev_attr_in_write_bytes_avail.attr, + &dev_attr_channel_vp_mapping.attr, NULL, }; ATTRIBUTE_GROUPS(vmbus); -- cgit v1.3-6-gb490 From f39c4280a3872b0e6c7b01076132c12ad7a90392 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 5 Aug 2015 00:52:48 -0700 Subject: Drivers: hv: vmbus: use cpu_hotplug_enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit e513229b4c38 ("Drivers: hv: vmbus: prevent cpu offlining on newer hypervisors") was altering smp_ops.cpu_disable to prevent CPU offlining. We can bo better by using cpu_hotplug_enable/disable functions instead of such hard-coding. Reported-by: Radim Kr.má Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 38 ++++---------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 45d6d7a0ed89..f19b6f7a467a 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -828,38 +828,6 @@ static void vmbus_isr(void) } } -#ifdef CONFIG_HOTPLUG_CPU -static int hyperv_cpu_disable(void) -{ - return -ENOSYS; -} - -static void hv_cpu_hotplug_quirk(bool vmbus_loaded) -{ - static void *previous_cpu_disable; - - /* - * Offlining a CPU when running on newer hypervisors (WS2012R2, Win8, - * ...) is not supported at this moment as channel interrupts are - * distributed across all of them. - */ - - if ((vmbus_proto_version == VERSION_WS2008) || - (vmbus_proto_version == VERSION_WIN7)) - return; - - if (vmbus_loaded) { - previous_cpu_disable = smp_ops.cpu_disable; - smp_ops.cpu_disable = hyperv_cpu_disable; - pr_notice("CPU offlining is not supported by hypervisor\n"); - } else if (previous_cpu_disable) - smp_ops.cpu_disable = previous_cpu_disable; -} -#else -static void hv_cpu_hotplug_quirk(bool vmbus_loaded) -{ -} -#endif /* * vmbus_bus_init -Main vmbus driver initialization routine. @@ -901,7 +869,8 @@ static int vmbus_bus_init(int irq) if (ret) goto err_alloc; - hv_cpu_hotplug_quirk(true); + if (vmbus_proto_version > VERSION_WIN7) + cpu_hotplug_disable(); /* * Only register if the crash MSRs are available @@ -1364,7 +1333,8 @@ static void __exit vmbus_exit(void) } hv_synic_free(); acpi_bus_unregister_driver(&vmbus_acpi_driver); - hv_cpu_hotplug_quirk(false); + if (vmbus_proto_version > VERSION_WIN7) + cpu_hotplug_enable(); } -- cgit v1.3-6-gb490 From 2537468cee9ff2b9d4c425e2f8141aaa274dc495 Mon Sep 17 00:00:00 2001 From: Jandy Gou Date: Wed, 5 Aug 2015 10:09:02 +0800 Subject: Staging: android: timed_gpio.c: fix coding style errors remove extra space and replace tab to space after a variable Signed-off-by: Jandy Gou Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/timed_gpio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c index 938a35cd99bb..ce11726f1a6c 100644 --- a/drivers/staging/android/timed_gpio.c +++ b/drivers/staging/android/timed_gpio.c @@ -61,9 +61,9 @@ static int gpio_get_time(struct timed_output_dev *dev) static void gpio_enable(struct timed_output_dev *dev, int value) { - struct timed_gpio_data *data = + struct timed_gpio_data *data = container_of(dev, struct timed_gpio_data, dev); - unsigned long flags; + unsigned long flags; spin_lock_irqsave(&data->lock, flags); -- cgit v1.3-6-gb490 From 1a59adb222bc4758241eb4ff253faa5b1ebd4cab Mon Sep 17 00:00:00 2001 From: Ted Chen Date: Wed, 5 Aug 2015 01:18:46 +0800 Subject: staging: comedi: do not return -ENOSYS. fixed coding style issue by replacing ENOSYS with EIO because it means 'invalid syscall nr' and nothing else. Signed-off-by: Ted Chen Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index ed0b60c925de..b03bc6639f79 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -820,7 +820,7 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) "driver '%s' does not support attach using comedi_config\n", driv->driver_name); module_put(driv->module); - ret = -ENOSYS; + ret = -EIO; goto out; } dev->driver = driv; -- cgit v1.3-6-gb490 From d27da4dae5f487d64ba52c3d505cc587c19af578 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Wed, 5 Aug 2015 18:13:26 +0100 Subject: staging: comedi: improve comedi_check_chanlist() documentation Signed-off-by: Ian Abbott Reviewed-by: H Hartley Sweeten Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/range.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c index 6a393b24bdd9..ce3a58a7a171 100644 --- a/drivers/staging/comedi/range.c +++ b/drivers/staging/comedi/range.c @@ -102,7 +102,18 @@ int do_rangeinfo_ioctl(struct comedi_device *dev, * @s: comedi_subdevice struct * @n: number of elements in the chanlist * @chanlist: the chanlist to validate -*/ + * + * Each element consists of a channel number, a range index, an analog + * reference type and some flags, all packed into an unsigned int. + * + * This checks that the channel number and range index are supported by + * the comedi subdevice. It does not check whether the analog reference + * type and the flags are supported. Drivers that care should check those + * themselves. + * + * Return: %0 if all @chanlist elements are valid (success), + * %-EINVAL if one or more elements are invalid. + */ int comedi_check_chanlist(struct comedi_subdevice *s, int n, unsigned int *chanlist) { -- cgit v1.3-6-gb490 From 967ef593bf26bdd9ddabef8eb8c1ddd8f5d2074a Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 3 Aug 2015 21:57:44 -0400 Subject: staging/lustre/ptlrpc: Remove stray cfs_daemonize comment Ever since daemonize was removed in 3.18, there are no longer any flags passed to kthread_run. Most of the comments were deleted, but this one lingered on until now. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ptlrpc/pinger.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/ptlrpc/pinger.c b/drivers/staging/lustre/lustre/ptlrpc/pinger.c index d05c37c1fd30..f8edb791a998 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pinger.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pinger.c @@ -318,8 +318,6 @@ int ptlrpc_start_pinger(void) strcpy(pinger_thread.t_name, "ll_ping"); - /* CLONE_VM and CLONE_FILES just avoid a needless copy, because we - * just drop the VM and FILES in cfs_daemonize_ctxt() right away. */ rc = PTR_ERR(kthread_run(ptlrpc_pinger_main, &pinger_thread, "%s", pinger_thread.t_name)); if (IS_ERR_VALUE(rc)) { -- cgit v1.3-6-gb490 From f72f130d87ff05144553af4894c0c52c57d60930 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Mon, 3 Aug 2015 21:57:45 -0400 Subject: staging/lustre: Properly reference kthread_run instead of cfs_daemonize cfs_daemonize is long gone and replaced by a proper call to kthread_run, so update the comment to reflect that fact. Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/include/lustre_net.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index 77a7de98fc8e..3bb2f8b0c309 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -2183,7 +2183,7 @@ struct ptlrpcd_ctl { */ struct ptlrpc_request_set *pc_set; /** - * Thread name used in cfs_daemonize() + * Thread name used in kthread_run() */ char pc_name[16]; /** -- cgit v1.3-6-gb490 From c9a47627f7988470ad391091ed9334018e5144a2 Mon Sep 17 00:00:00 2001 From: Ting-Chih Hsiao Date: Tue, 4 Aug 2015 11:21:10 +0800 Subject: staging: rtl8723au: fix up coding style warnings reported by checkpatch.pl. remove spaces at the start of a line align enum variable with other parameters Signed-off-by: Ting-Chih Hsiao Acked-by: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c b/drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c index 342dec3e939f..a63c6cb88bc9 100644 --- a/drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c +++ b/drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c @@ -21,7 +21,7 @@ odm_ConfigRFReg_8723A( struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data, - enum RF_RADIO_PATH RF_PATH, + enum RF_RADIO_PATH RF_PATH, u32 RegAddr ) { -- cgit v1.3-6-gb490 From fce7f39356c511e263e97094bd18dee40fca6511 Mon Sep 17 00:00:00 2001 From: Lior Pugatch Date: Tue, 4 Aug 2015 22:18:04 +0300 Subject: staging: vt6655: Fixed C99 style comment to C89 style. Patch created to satisfy checkpatch.pl Signed-off-by: Lior Pugatch Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/rxtx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/rxtx.h b/drivers/staging/vt6655/rxtx.h index b9bd1639b13e..54694df14e44 100644 --- a/drivers/staging/vt6655/rxtx.h +++ b/drivers/staging/vt6655/rxtx.h @@ -197,4 +197,4 @@ int vnt_beacon_make(struct vnt_private *, struct ieee80211_vif *); int vnt_beacon_enable(struct vnt_private *, struct ieee80211_vif *, struct ieee80211_bss_conf *); -#endif // __RXTX_H__ +#endif /* __RXTX_H__ */ -- cgit v1.3-6-gb490 From 2cb1df7ebd8b8807a204ffb0692751b15d4cb1bf Mon Sep 17 00:00:00 2001 From: Lars Svensson Date: Wed, 5 Aug 2015 14:15:12 +0200 Subject: staging: iio_simple_dummy: Fix indentation errors Fixing indentation errors in drivers/staging/iio/iio_simple_dummy_events.c. Signed-off-by: Lars Svensson Acked-by: Daniel Baluta Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/iio_simple_dummy_events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c index ecc563cb6cb9..73108baf80ad 100644 --- a/drivers/staging/iio/iio_simple_dummy_events.c +++ b/drivers/staging/iio/iio_simple_dummy_events.c @@ -120,7 +120,7 @@ int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - enum iio_event_info info, + enum iio_event_info info, int *val, int *val2) { struct iio_dummy_state *st = iio_priv(indio_dev); @@ -143,7 +143,7 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - enum iio_event_info info, + enum iio_event_info info, int val, int val2) { struct iio_dummy_state *st = iio_priv(indio_dev); -- cgit v1.3-6-gb490 From eeb1c0629539b1393d0b5ffea9cc2d71e6e933bf Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Wed, 5 Aug 2015 01:29:22 +0530 Subject: Staging: wilc1000: Remove typedefs for struct The Linux kernel coding style guidelines suggest not using typedefs for structure and enum types. This patch gets rid of the typedefs for Ack_session_info_t. The following Coccinelle semantic patch detects the cases for struct type: @tn@ identifier i; type td; @@ -typedef struct i { ... } -td ; @@ type tn.td; identifier tn.i; @@ -td + struct i Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wlan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index def72fd1236d..1eb13f90d0e4 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -291,13 +291,13 @@ uint32_t Statisitcs_totalAcks = 0, Statisitcs_DroppedAcks = 0; #ifdef TCP_ACK_FILTER struct Ack_session_info; -typedef struct Ack_session_info { +struct Ack_session_info { uint32_t Ack_seq_num; uint32_t Bigger_Ack_num; uint16_t src_port; uint16_t dst_port; uint16_t status; -} Ack_session_info_t; +}; typedef struct { uint32_t ack_num; @@ -318,7 +318,7 @@ struct Ack_session_info *Alloc_head; #define MAX_TCP_SESSION 25 #define MAX_PENDING_ACKS 256 -Ack_session_info_t Acks_keep_track_info[2 * MAX_TCP_SESSION]; +struct Ack_session_info Acks_keep_track_info[2 * MAX_TCP_SESSION]; Pending_Acks_info_t Pending_Acks_info[MAX_PENDING_ACKS]; uint32_t PendingAcks_arrBase; -- cgit v1.3-6-gb490 From 1913221c0e3025a93c3c106ec0167f8240df4d35 Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Wed, 5 Aug 2015 08:18:31 +0200 Subject: staging: wilc1000: wilc_cfgoperations.c: Fixed coding styles issues. Fixed coding styles issues with braces. Signed-off-by: Daniel Machon Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index c2ef46f4740b..d261e599f13d 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -1205,8 +1205,7 @@ static int WILC_WFI_add_key(struct wiphy *wiphy, struct net_device *netdev, u8 k - if (!pairwise) - { + if (!pairwise) { if (params->cipher == WLAN_CIPHER_SUITE_TKIP) u8gmode = ENCRYPT_ENABLED | WPA | TKIP; else @@ -1304,8 +1303,7 @@ static int WILC_WFI_add_key(struct wiphy *wiphy, struct net_device *netdev, u8 k { u8mode = 0; - if (!pairwise) - { + if (!pairwise) { if (params->key_len > 16 && params->cipher == WLAN_CIPHER_SUITE_TKIP) { /* swap the tx mic by rx mic */ pu8RxMic = params->key + 24; -- cgit v1.3-6-gb490 From a96c47e1978a874e87e7fea3ebb178eaf8730d46 Mon Sep 17 00:00:00 2001 From: Chandra S Gorentla Date: Wed, 5 Aug 2015 22:11:55 +0530 Subject: drivers: staging: wilc1000: use 'void' for no arguments functions Added 'void' keyword in the paranthesis of function definitions, when there are no arguments to the functions. This fixes the checkpatch.pl error - "Bad function definition 'function()' should probably be function(void)". Signed-off-by: Chandra S Gorentla Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/linux_mon.c | 2 +- drivers/staging/wilc1000/linux_wlan.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/linux_mon.c b/drivers/staging/wilc1000/linux_mon.c index aa20421021fa..123468a9582f 100644 --- a/drivers/staging/wilc1000/linux_mon.c +++ b/drivers/staging/wilc1000/linux_mon.c @@ -558,7 +558,7 @@ struct net_device *WILC_WFI_init_mon_interface(const char *name, struct net_devi * @date 12 JUL 2012 * @version 1.0 */ -int WILC_WFI_deinit_mon_interface() +int WILC_WFI_deinit_mon_interface(void) { bool rollback_lock = false; diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 3e55a8ac2966..0a8052e717c2 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -202,7 +202,7 @@ void printk_later(const char *format, ...) } -void dump_logs() +void dump_logs(void) { if (DebugBuffer[0]) { DebugBuffer[DEGUG_BUFFER_LENGTH] = 0; @@ -216,7 +216,7 @@ void dump_logs() } } -void Reset_WatchDogdebugger() +void Reset_WatchDogdebugger(void) { WatchDogdebuggerCounter = 0; } -- cgit v1.3-6-gb490 From 6212990a87588869aa9a93fa5b861d3abf1be783 Mon Sep 17 00:00:00 2001 From: Chandra S Gorentla Date: Wed, 5 Aug 2015 22:11:57 +0530 Subject: drivers: staging: wilc1000: remove space after '(' The character ' ' is removed after the character '('. This fixes the checkpatch.pl error - "space prohibited after that open parenthesis '('". Signed-off-by: Chandra S Gorentla Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index d261e599f13d..da9c12f9b443 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -1676,7 +1676,7 @@ static int WILC_WFI_get_station(struct wiphy *wiphy, struct net_device *dev, * kernel version 3.0.0 */ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL) | - BIT( NL80211_STA_INFO_RX_PACKETS) | + BIT(NL80211_STA_INFO_RX_PACKETS) | BIT(NL80211_STA_INFO_TX_PACKETS) | BIT(NL80211_STA_INFO_TX_FAILED) | BIT(NL80211_STA_INFO_TX_BITRATE); -- cgit v1.3-6-gb490 From 946b254697655f0ea0c54b1b0e20fb3b9aab99da Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 4 Aug 2015 15:09:47 -0400 Subject: staging: unisys: visornic: Convert to using napi Switch the visornic over to use napi. Currently there is a kernel thread that sits and waits on a wait queue to get notified of incoming virtual interrupts. It would be nice if we could handle frame reception using the standard napi processing instead. This patch creates our napi instance and has the rx thread schedule it Given that the unisys hypervisor currently requires that queue servicing be done by a polling loop that wakes up every 2ms, lets instead also convert that to a timer, which is simpler, and allows us to remove all the thread starting and stopping code. Signed-off-by: Neil Horman Signed-off-by: Benjamin Romer Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visornic/visornic_main.c | 202 ++++++++++-------------- 1 file changed, 82 insertions(+), 120 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visornic/visornic_main.c b/drivers/staging/unisys/visornic/visornic_main.c index 7d4602973bbb..63d90f599158 100644 --- a/drivers/staging/unisys/visornic/visornic_main.c +++ b/drivers/staging/unisys/visornic/visornic_main.c @@ -89,11 +89,6 @@ static struct visor_driver visornic_driver = { .channel_interrupt = NULL, }; -struct visor_thread_info { - struct task_struct *task; - int id; -}; - struct chanstat { unsigned long got_rcv; unsigned long got_enbdisack; @@ -110,7 +105,6 @@ struct chanstat { struct visornic_devdata { int devnum; - int thread_wait_ms; unsigned short enabled; /* 0 disabled 1 enabled to receive */ unsigned short enab_dis_acked; /* NET_RCV_ENABLE/DISABLE acked by * IOPART @@ -162,7 +156,6 @@ struct visornic_devdata { bool server_change_state; /* Processing SERVER_CHANGESTATE msg */ bool going_away; /* device is being torn down */ struct dentry *eth_debugfs_dir; - struct visor_thread_info threadinfo; u64 interrupts_rcvd; u64 interrupts_notme; u64 interrupts_disabled; @@ -194,6 +187,9 @@ struct visornic_devdata { int queuefullmsg_logged; struct chanstat chstat; + struct timer_list irq_poll_timer; + struct napi_struct napi; + struct uiscmdrsp cmdrsp[SIZEOF_CMDRSP]; }; @@ -202,6 +198,8 @@ struct visornic_devdata { */ static LIST_HEAD(list_all_devices); static DEFINE_SPINLOCK(lock_all_devices); +static int visornic_poll(struct napi_struct *napi, int budget); +static void poll_for_irq(unsigned long v); /** * visor_copy_fragsinfo_from_skb( @@ -301,49 +299,6 @@ visor_copy_fragsinfo_from_skb(struct sk_buff *skb, unsigned int firstfraglen, return count; } -/** - * visort_thread_start - starts thread for the device - * @thrinfo: The thread to start - * @threadfn: Function the thread starts - * @thrcontext: Context to pass to the thread, i.e. devdata - * @name: string describing name of thread - * - * Starts a thread for the device, currently only thread is - * process_incoming_rsps - * Returns 0 on success; - */ -static int visor_thread_start(struct visor_thread_info *thrinfo, - int (*threadfn)(void *), - void *thrcontext, char *name) -{ - /* used to stop the thread */ - thrinfo->task = kthread_run(threadfn, thrcontext, "%s", name); - if (IS_ERR(thrinfo->task)) { - pr_debug("%s failed (%ld)\n", - __func__, PTR_ERR(thrinfo->task)); - thrinfo->id = 0; - return -EINVAL; - } - thrinfo->id = thrinfo->task->pid; - return 0; -} - -/** - * visor_thread_stop - stop a thread for the device - * @thrinfo: The thread to stop - * - * Stop the thread and wait for completion for a minute - * Returns void. - */ -static void visor_thread_stop(struct visor_thread_info *thrinfo) -{ - if (!thrinfo->id) - return; /* thread not running */ - - BUG_ON(kthread_stop(thrinfo->task)); - thrinfo->id = 0; -} - static ssize_t enable_ints_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) @@ -373,8 +328,8 @@ visornic_serverdown_complete(struct visornic_devdata *devdata) netdev = devdata->netdev; - /* Stop using datachan */ - visor_thread_stop(&devdata->threadinfo); + /* Stop polling for interrupts */ + del_timer_sync(&devdata->irq_poll_timer); rtnl_lock(); dev_close(netdev); @@ -538,9 +493,6 @@ visornic_disable_with_timeout(struct net_device *netdev, const int timeout) unsigned long flags; int wait = 0; - /* stop the transmit queue so nothing more can be transmitted */ - netif_stop_queue(netdev); - /* send a msg telling the other end we are stopping incoming pkts */ spin_lock_irqsave(&devdata->priv_lock, flags); devdata->enabled = 0; @@ -586,10 +538,14 @@ visornic_disable_with_timeout(struct net_device *netdev, const int timeout) break; } } - /* we've set enabled to 0, so we can give up the lock. */ spin_unlock_irqrestore(&devdata->priv_lock, flags); + /* stop the transmit queue so nothing more can be transmitted */ + netif_stop_queue(netdev); + + napi_disable(&devdata->napi); + skb_queue_purge(&devdata->xmitbufhead); /* Free rcv buffers - other end has automatically unposed them on @@ -692,6 +648,7 @@ visornic_enable_with_timeout(struct net_device *netdev, const int timeout) /* send enable and wait for ack -- don't hold lock when sending enable * because if the queue is full, insert might sleep. */ + napi_enable(&devdata->napi); send_enbdis(netdev, 1, devdata); spin_lock_irqsave(&devdata->priv_lock, flags); @@ -719,6 +676,7 @@ visornic_enable_with_timeout(struct net_device *netdev, const int timeout) } netif_start_queue(netdev); + return 0; } @@ -1198,15 +1156,16 @@ repost_return(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata, * it up the stack. * Returns void */ -static void +static int visornic_rx(struct uiscmdrsp *cmdrsp) { struct visornic_devdata *devdata; struct sk_buff *skb, *prev, *curr; struct net_device *netdev; - int cc, currsize, off, status; + int cc, currsize, off; struct ethhdr *eth; unsigned long flags; + int rx_count = 0; /* post new rcv buf to the other end using the cmdrsp we have at hand * post it without holding lock - but we'll use the signal lock to @@ -1238,7 +1197,7 @@ visornic_rx(struct uiscmdrsp *cmdrsp) */ spin_unlock_irqrestore(&devdata->priv_lock, flags); repost_return(cmdrsp, devdata, skb, netdev); - return; + return rx_count; } spin_unlock_irqrestore(&devdata->priv_lock, flags); @@ -1257,7 +1216,7 @@ visornic_rx(struct uiscmdrsp *cmdrsp) if (repost_return(cmdrsp, devdata, skb, netdev) < 0) dev_err(&devdata->netdev->dev, "repost_return failed"); - return; + return rx_count; } /* length rcvd is greater than firstfrag in this skb rcv buf */ skb->tail += RCVPOST_BUF_SIZE; /* amount in skb->data */ @@ -1272,7 +1231,7 @@ visornic_rx(struct uiscmdrsp *cmdrsp) if (repost_return(cmdrsp, devdata, skb, netdev) < 0) dev_err(&devdata->netdev->dev, "repost_return failed"); - return; + return rx_count; } skb->tail += skb->len; skb->data_len = 0; /* nothing rcvd in frag_list */ @@ -1291,7 +1250,7 @@ visornic_rx(struct uiscmdrsp *cmdrsp) if (cmdrsp->net.rcv.rcvbuf[0] != skb) { if (repost_return(cmdrsp, devdata, skb, netdev) < 0) dev_err(&devdata->netdev->dev, "repost_return failed"); - return; + return rx_count; } if (cmdrsp->net.rcv.numrcvbufs > 1) { @@ -1374,10 +1333,11 @@ visornic_rx(struct uiscmdrsp *cmdrsp) /* drop packet - don't forward it up to OS */ devdata->n_rcv_packets_not_accepted++; repost_return(cmdrsp, devdata, skb, netdev); - return; + return rx_count; } while (0); - status = netif_rx(skb); + rx_count++; + netif_receive_skb(skb); /* netif_rx returns various values, but "in practice most drivers * ignore the return value */ @@ -1389,6 +1349,7 @@ visornic_rx(struct uiscmdrsp *cmdrsp) * new rcv buffer. */ repost_return(cmdrsp, devdata, skb, netdev); + return rx_count; } /** @@ -1593,9 +1554,6 @@ static ssize_t info_debugfs_read(struct file *file, char __user *buf, str_pos += scnprintf(vbuf + str_pos, len - str_pos, " flow_control_lower_hits = %llu\n", devdata->flow_control_lower_hits); - str_pos += scnprintf(vbuf + str_pos, len - str_pos, - " thread_wait_ms = %d\n", - devdata->thread_wait_ms); str_pos += scnprintf(vbuf + str_pos, len - str_pos, " netif_queue = %s\n", netif_queue_stopped(devdata->netdev) ? @@ -1663,7 +1621,8 @@ send_rcv_posts_if_needed(struct visornic_devdata *devdata) * Returns when response queue is empty or when the threadd stops. */ static void -drain_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata) +service_resp_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata, + int *rx_work_done) { unsigned long flags; struct net_device *netdev; @@ -1680,7 +1639,7 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata) case NET_RCV: devdata->chstat.got_rcv++; /* process incoming packet */ - visornic_rx(cmdrsp); + *rx_work_done += visornic_rx(cmdrsp); break; case NET_XMIT_DONE: spin_lock_irqsave(&devdata->priv_lock, flags); @@ -1717,8 +1676,6 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata) devdata->enab_dis_acked = 1; spin_unlock_irqrestore(&devdata->priv_lock, flags); - if (kthread_should_stop()) - break; if (devdata->server_down && devdata->server_change_state) { /* Inform Linux that the link is up */ @@ -1753,42 +1710,48 @@ drain_queue(struct uiscmdrsp *cmdrsp, struct visornic_devdata *devdata) } } +static int visornic_poll(struct napi_struct *napi, int budget) +{ + struct visornic_devdata *devdata = container_of(napi, + struct visornic_devdata, + napi); + int rx_count = 0; + + send_rcv_posts_if_needed(devdata); + service_resp_queue(devdata->cmdrsp, devdata, &rx_count); + + /* + * If there aren't any more packets to receive + * stop the poll + */ + if (rx_count < budget) + napi_complete(napi); + + return rx_count; +} + /** - * process_incoming_rsps - Checks the status of the response queue. + * poll_for_irq - Checks the status of the response queue. * @v: void pointer to the visronic devdata * * Main function of the vnic_incoming thread. Peridocially check the * response queue and drain it if needed. * Returns when thread has stopped. */ -static int -process_incoming_rsps(void *v) +static void +poll_for_irq(unsigned long v) { - struct visornic_devdata *devdata = v; - struct uiscmdrsp *cmdrsp = NULL; - const int SZ = SIZEOF_CMDRSP; + struct visornic_devdata *devdata = (struct visornic_devdata *)v; - cmdrsp = kmalloc(SZ, GFP_ATOMIC); - if (!cmdrsp) - return 0; + if (!visorchannel_signalempty( + devdata->dev->visorchannel, + IOCHAN_FROM_IOPART)) + napi_schedule(&devdata->napi); - while (!kthread_should_stop()) { - wait_event_interruptible_timeout( - devdata->rsp_queue, (atomic_read( - &devdata->interrupt_rcvd) == 1), - msecs_to_jiffies(devdata->thread_wait_ms)); + atomic_set(&devdata->interrupt_rcvd, 0); - /* periodically check to see if there are any rcf bufs which - * need to get sent to the IOSP. This can only happen if - * we run out of memory when trying to allocate skbs. - */ - atomic_set(&devdata->interrupt_rcvd, 0); - send_rcv_posts_if_needed(devdata); - drain_queue(cmdrsp, devdata); - } + mod_timer(&devdata->irq_poll_timer, msecs_to_jiffies(2)); - kfree(cmdrsp); - return 0; } /** @@ -1907,6 +1870,17 @@ static int visornic_probe(struct visor_device *dev) /* TODO: Setup Interrupt information */ /* Let's start our threads to get responses */ + netif_napi_add(netdev, &devdata->napi, visornic_poll, 64); + + setup_timer(&devdata->irq_poll_timer, poll_for_irq, + (unsigned long)devdata); + /* + * Note: This time has to start running before the while + * loop below because the napi routine is responsible for + * setting enab_dis_acked + */ + mod_timer(&devdata->irq_poll_timer, msecs_to_jiffies(2)); + channel_offset = offsetof(struct spar_io_channel_protocol, channel_header.features); err = visorbus_read_channel(dev, channel_offset, &features, 8); @@ -1914,7 +1888,7 @@ static int visornic_probe(struct visor_device *dev) dev_err(&dev->device, "%s failed to get features from chan (%d)\n", __func__, err); - goto cleanup_xmit_cmdrsp; + goto cleanup_napi_add; } features |= ULTRA_IO_CHANNEL_IS_POLLING; @@ -1923,14 +1897,14 @@ static int visornic_probe(struct visor_device *dev) dev_err(&dev->device, "%s failed to set features in chan (%d)\n", __func__, err); - goto cleanup_xmit_cmdrsp; + goto cleanup_napi_add; } err = register_netdev(netdev); if (err) { dev_err(&dev->device, "%s register_netdev failed (%d)\n", __func__, err); - goto cleanup_xmit_cmdrsp; + goto cleanup_napi_add; } /* create debgug/sysfs directories */ @@ -1944,14 +1918,14 @@ static int visornic_probe(struct visor_device *dev) goto cleanup_xmit_cmdrsp; } - devdata->thread_wait_ms = 2; - visor_thread_start(&devdata->threadinfo, process_incoming_rsps, - devdata, "vnic_incoming"); - dev_info(&dev->device, "%s success netdev=%s\n", __func__, netdev->name); return 0; +cleanup_napi_add: + del_timer_sync(&devdata->irq_poll_timer); + netif_napi_del(&devdata->napi); + cleanup_xmit_cmdrsp: kfree(devdata->xmit_cmdrsp); @@ -2021,18 +1995,8 @@ static void visornic_remove(struct visor_device *dev) unregister_netdev(netdev); /* this will call visornic_close() */ - /* this had to wait until last because visornic_close() / - * visornic_disable_with_timeout() polls waiting for state that is - * only updated by the thread - */ - if (devdata->threadinfo.id) { - visor_thread_stop(&devdata->threadinfo); - if (devdata->threadinfo.id) { - dev_err(&dev->device, "%s cannot stop worker thread\n", - __func__); - return; - } - } + del_timer_sync(&devdata->irq_poll_timer); + netif_napi_del(&devdata->napi); dev_set_drvdata(&dev->device, NULL); host_side_disappeared(devdata); @@ -2102,16 +2066,14 @@ static int visornic_resume(struct visor_device *dev, } devdata->server_change_state = true; spin_unlock_irqrestore(&devdata->priv_lock, flags); + /* Must transition channel to ATTACHED state BEFORE * we can start using the device again. * TODO: State transitions */ - if (!devdata->threadinfo.id) - visor_thread_start(&devdata->threadinfo, - process_incoming_rsps, - devdata, "vnic_incoming"); - else - pr_warn("vnic_incoming already running!\n"); + mod_timer(&devdata->irq_poll_timer, msecs_to_jiffies(2)); + + init_rcv_bufs(netdev, devdata); rtnl_lock(); dev_open(netdev); -- cgit v1.3-6-gb490 From a12aaa92f3ccd15015e01373c2b60a3841aaebbb Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Tue, 4 Aug 2015 23:02:33 +0530 Subject: Staging: lustre: libcfs: Drop unnecessary cast on void* This patch does away with the cast on void * as it is unnecessary. Semantic patch used is as follows: @r@ expression x; void* e; type T; identifier f; @@ ( *((T *)e) | ((T *)x)[...] | ((T *)x)->f | - (T *) e ) Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/linux/linux-module.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c index e962f89683a6..78acff068217 100644 --- a/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c +++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-module.c @@ -49,7 +49,7 @@ int libcfs_ioctl_getdata(char *buf, char *end, void *arg) hdr = (struct libcfs_ioctl_hdr *)buf; data = (struct libcfs_ioctl_data *)buf; - if (copy_from_user(buf, (void *)arg, sizeof(*hdr))) + if (copy_from_user(buf, arg, sizeof(*hdr))) return -EFAULT; if (hdr->ioc_version != LIBCFS_IOCTL_VERSION) { @@ -69,7 +69,7 @@ int libcfs_ioctl_getdata(char *buf, char *end, void *arg) } orig_len = hdr->ioc_len; - if (copy_from_user(buf, (void *)arg, hdr->ioc_len)) + if (copy_from_user(buf, arg, hdr->ioc_len)) return -EFAULT; if (orig_len != data->ioc_len) return -EINVAL; -- cgit v1.3-6-gb490 From 45b30514a34fa7fcb7a84be799ca5fc53d33a4d7 Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Tue, 4 Aug 2015 23:02:35 +0530 Subject: Staging: lustre: lov: Drop unnecessary cast on void * This patch does away with the cast on void * as it is unnecessary. Semantic patch used is as follows: @r@ expression x; void* e; type T; identifier f; @@ ( *((T *)e) | ((T *)x)[...] | ((T *)x)->f | - (T *) e ) Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/lov/lov_obd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/lov/lov_obd.c b/drivers/staging/lustre/lustre/lov/lov_obd.c index 5f4c115f4ff4..c5c67d982ef2 100644 --- a/drivers/staging/lustre/lustre/lov/lov_obd.c +++ b/drivers/staging/lustre/lustre/lov/lov_obd.c @@ -1440,7 +1440,7 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len, __u32 *genp; len = 0; - if (obd_ioctl_getdata(&buf, &len, (void *)uarg)) + if (obd_ioctl_getdata(&buf, &len, uarg)) return -EINVAL; data = (struct obd_ioctl_data *)buf; @@ -1473,7 +1473,7 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len, *genp = lov->lov_tgts[i]->ltd_gen; } - if (copy_to_user((void *)uarg, buf, len)) + if (copy_to_user(uarg, buf, len)) rc = -EFAULT; obd_ioctl_freedata(buf, len); break; -- cgit v1.3-6-gb490 From b7856753856b4e6a20c1c91c6db03852e90de273 Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Tue, 4 Aug 2015 23:02:34 +0530 Subject: Staging: lustre: osc: Drop unnecessary cast on void * This patch does away with the cast on void * as it is unnecessary. Semantic patch used is as follows: @r@ expression x; void* e; type T; identifier f; @@ ( *((T *)e) | ((T *)x)[...] | ((T *)x)->f | - (T *) e ) Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/osc/osc_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index 96c80e9bf92d..12113dfd87b8 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -2665,7 +2665,7 @@ static int osc_iocontrol(unsigned int cmd, struct obd_export *exp, int len, buf = NULL; len = 0; - if (obd_ioctl_getdata(&buf, &len, (void *)uarg)) { + if (obd_ioctl_getdata(&buf, &len, uarg)) { err = -EINVAL; goto out; } @@ -2695,7 +2695,7 @@ static int osc_iocontrol(unsigned int cmd, struct obd_export *exp, int len, memcpy(data->ioc_inlbuf2, &obd->obd_uuid, sizeof(uuid)); - err = copy_to_user((void *)uarg, buf, len); + err = copy_to_user(uarg, buf, len); if (err) err = -EFAULT; obd_ioctl_freedata(buf, len); -- cgit v1.3-6-gb490 From 9b37465e40915a657e60593e068aa3ab447931b1 Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Tue, 4 Aug 2015 23:20:50 +0530 Subject: Staging: lustre: libcfs: Replace comma with a semicolon Replace comma between expression statements by a semicolon. The semantic patch used is as follows: @@ expression e1,e2; @@ e1 - , + ; e2; Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/libcfs/libcfs_string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c index 4dde8e08c0ba..efe5e667a2e5 100644 --- a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c +++ b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c @@ -400,7 +400,7 @@ cfs_expr_list_free(struct cfs_expr_list *expr_list) struct cfs_range_expr *expr; expr = list_entry(expr_list->el_exprs.next, - struct cfs_range_expr, re_link), + struct cfs_range_expr, re_link); list_del(&expr->re_link); LIBCFS_FREE(expr, sizeof(*expr)); } -- cgit v1.3-6-gb490 From 48177898f05916b64935118633353dbc448d3c24 Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Tue, 4 Aug 2015 23:20:52 +0530 Subject: Staging: netlogic: Replace comma with a semicolon Replace comma between expression statements by a semicolon. The semantic patch used is as follows: @@ expression e1,e2; @@ e1 - , + ; e2; Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/netlogic/platform_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/netlogic/platform_net.c b/drivers/staging/netlogic/platform_net.c index 77c3c3522afa..e914147d7379 100644 --- a/drivers/staging/netlogic/platform_net.c +++ b/drivers/staging/netlogic/platform_net.c @@ -163,7 +163,7 @@ static void xls_gmac_init(void) switch (nlm_prom_info.board_major_version) { case 12: /* first block RGMII or XAUI, use RGMII */ - ndata0.phy_interface = PHY_INTERFACE_MODE_RGMII, + ndata0.phy_interface = PHY_INTERFACE_MODE_RGMII; ndata0.tx_stnid[0] = FMN_STNID_GMAC0_TX0; ndata0.phy_addr[0] = 0; -- cgit v1.3-6-gb490 From 91f2208c37ab08343b118601eaa0d9bb76fc8762 Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Tue, 4 Aug 2015 23:20:51 +0530 Subject: Staging: lustre: mgc: Replace comma with a semicolon Replace comma between expression statements by a semicolon. The semantic patch used is as follows: @@ expression e1,e2; @@ e1 - , + ; e2; Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/mgc/mgc_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/mgc/mgc_request.c b/drivers/staging/lustre/lustre/mgc/mgc_request.c index 562bd95bdcb9..019ee2f256aa 100644 --- a/drivers/staging/lustre/lustre/mgc/mgc_request.c +++ b/drivers/staging/lustre/lustre/mgc/mgc_request.c @@ -1232,7 +1232,7 @@ static int mgc_apply_recover_logs(struct obd_device *mgc, pos += sprintf(obdname + pos, "-%s%04x", is_ost ? "OST" : "MDT", entry->mne_index); - cname = is_ost ? "osc" : "mdc", + cname = is_ost ? "osc" : "mdc"; pos += sprintf(obdname + pos, "-%s-%s", cname, inst); lustre_cfg_bufs_reset(&bufs, obdname); -- cgit v1.3-6-gb490 From 4f016420d368480762061632f9a9254fd3a89239 Mon Sep 17 00:00:00 2001 From: Shraddha Barke Date: Wed, 5 Aug 2015 01:52:45 +0530 Subject: Staging: lustre: obdclass: Use kasprintf This patch uses kasprintf which combines kzalloc and sprintf. kasprintf also takes care of the size calculation. Semantic patch used is as follows: @@ expression a,flag; expression list args; statement S; @@ a = - \(kmalloc\|kzalloc\)(...,flag) + kasprintf (flag,args) <... when != a if (a == NULL || ...) S ...> - sprintf(a,args); Signed-off-by: Shraddha Barke Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/obd_mount.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c index 40ab7b272d03..7c5bab377f5c 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c @@ -247,13 +247,13 @@ int lustre_start_mgc(struct super_block *sb) mutex_lock(&mgc_start_lock); len = strlen(LUSTRE_MGC_OBDNAME) + strlen(libcfs_nid2str(nid)) + 1; - mgcname = kzalloc(len, GFP_NOFS); - niduuid = kzalloc(len + 2, GFP_NOFS); + mgcname = kasprintf(GFP_NOFS, + "%s%s", LUSTRE_MGC_OBDNAME, libcfs_nid2str(nid)); + niduuid = kasprintf(GFP_NOFS, "%s_%x", mgcname, i); if (!mgcname || !niduuid) { rc = -ENOMEM; goto out_free; } - sprintf(mgcname, "%s%s", LUSTRE_MGC_OBDNAME, libcfs_nid2str(nid)); mgssec = lsi->lsi_lmd->lmd_mgssec ? lsi->lsi_lmd->lmd_mgssec : ""; @@ -326,7 +326,6 @@ int lustre_start_mgc(struct super_block *sb) /* Add the primary nids for the MGS */ i = 0; - sprintf(niduuid, "%s_%x", mgcname, i); if (IS_SERVER(lsi)) { ptr = lsi->lsi_lmd->lmd_mgs; if (IS_MGS(lsi)) { @@ -1120,10 +1119,9 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd) /* Remove leading /s from fsname */ while (*++s1 == '/') ; /* Freed in lustre_free_lsi */ - lmd->lmd_profile = kzalloc(strlen(s1) + 8, GFP_NOFS); + lmd->lmd_profile = kasprintf(GFP_NOFS, "%s-client", s1); if (!lmd->lmd_profile) return -ENOMEM; - sprintf(lmd->lmd_profile, "%s-client", s1); } /* Freed in lustre_free_lsi */ -- cgit v1.3-6-gb490 From 6255049d397b28fdedab0b6c5f85072b3177e4a4 Mon Sep 17 00:00:00 2001 From: Miguel Bernabeu Diaz Date: Wed, 5 Aug 2015 22:33:23 +0200 Subject: staging: lustre: Fix style warning on header Fix checkpatch.pl warning: WARNING: Use #include instead of Signed-off-by: Miguel Bernabeu Diaz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index 0d8fa3a62c83..8bc05770382c 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -48,7 +48,7 @@ #include #include -#include +#include #include #include -- cgit v1.3-6-gb490 From d3159455bf46b71d0a4f2bb5d9cb92b64056e2b1 Mon Sep 17 00:00:00 2001 From: Peter Hung Date: Wed, 5 Aug 2015 14:44:53 +0800 Subject: serial: 8250_pci: fix mode after S3/S4 resume for F81504/508/512 Fix RS232/485 mode incorrect setting after S3/S4 resume for F81504/508/512 We had add RS232/485 RTS control with fecf27a373f5. But when it resume from S3/S4, the mode register 0x40 + 0x08 * idx + 7 will rewrite to 0x01 (RS232 mode). This patch will modify 2 sections. One is pci_fintek_init(), if it called when first init, it will write mode register with 0x01. If it called from S3/S4 resume, it's will get the relative port data and pass it to pci_fintek_rs485_config() with NULL rs485 parameter. The another modification is in pci_fintek_rs485_config(). It'll re-apply old configuration when the parameter rs485 is NULL. Signed-off-by: Peter Hung Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e12e91181781..68042dd1c525 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1705,7 +1705,9 @@ static int pci_fintek_rs485_config(struct uart_port *port, pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting); - if (rs485->flags & SER_RS485_ENABLED) + if (!rs485) + rs485 = &port->rs485; + else if (rs485->flags & SER_RS485_ENABLED) memset(rs485->padding, 0, sizeof(rs485->padding)); else memset(rs485, 0, sizeof(*rs485)); @@ -1733,7 +1735,10 @@ static int pci_fintek_rs485_config(struct uart_port *port, } pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - port->rs485 = *rs485; + + if (rs485 != &port->rs485) + port->rs485 = *rs485; + return 0; } @@ -1774,6 +1779,8 @@ static int pci_fintek_init(struct pci_dev *dev) u32 max_port, i; u32 bar_data[3]; u8 config_base; + struct serial_private *priv = pci_get_drvdata(dev); + struct uart_8250_port *port; switch (dev->device) { case 0x1104: /* 4 ports */ @@ -1815,8 +1822,18 @@ static int pci_fintek_init(struct pci_dev *dev) pci_write_config_byte(dev, config_base + 0x06, dev->irq); - /* force init to RS232 Mode */ - pci_write_config_byte(dev, config_base + 0x07, 0x01); + if (priv) { + /* re-apply RS232/485 mode when + * pciserial_resume_ports() + */ + port = serial8250_get_port(priv->line[i]); + pci_fintek_rs485_config(&port->port, NULL); + } else { + /* First init without port data + * force init to RS232 Mode + */ + pci_write_config_byte(dev, config_base + 0x07, 0x01); + } } return max_port; -- cgit v1.3-6-gb490 From 6497a8757361a88b73fc3814d2ee9b9fc105fa42 Mon Sep 17 00:00:00 2001 From: Eli Billauer Date: Wed, 5 Aug 2015 13:03:26 +0300 Subject: char: xillybus: Allow 64-bit DMA on PCIe interface Until now, only 32-bit DMA addressing was allowed, following a report on some old Intel machine that dropped 64-bit PCIe packets, even though pci_set_dma_mask() was successful with DMA_BIT_MASK(64). But then came TI's Keystone II chip (ARM Cortex A15 + DSPs), which refuses 32-bit DMA addressing (for good reasons). So 64-bit DMA is allowed as a fallback option. Signed-off-by: Eli Billauer Signed-off-by: Greg Kroah-Hartman --- drivers/char/xillybus/xillybus_pcie.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/xillybus/xillybus_pcie.c b/drivers/char/xillybus/xillybus_pcie.c index d8266bc2ae35..9418300214e9 100644 --- a/drivers/char/xillybus/xillybus_pcie.c +++ b/drivers/char/xillybus/xillybus_pcie.c @@ -193,14 +193,16 @@ static int xilly_probe(struct pci_dev *pdev, } /* - * In theory, an attempt to set the DMA mask to 64 and dma_using_dac=1 - * is the right thing. But some unclever PCIe drivers report it's OK - * when the hardware drops those 64-bit PCIe packets. So trust - * nobody and use 32 bits DMA addressing in any case. + * Some (old and buggy?) hardware drops 64-bit addressed PCIe packets, + * even when the PCIe driver claims that a 64-bit mask is OK. On the + * other hand, on some architectures, 64-bit addressing is mandatory. + * So go for the 64-bit mask only when failing is the other option. */ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { endpoint->dma_using_dac = 0; + } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + endpoint->dma_using_dac = 1; } else { dev_err(endpoint->dev, "Failed to set DMA mask. Aborting.\n"); return -ENODEV; -- cgit v1.3-6-gb490 From a9fce374815d8ab94a3e6259802a944e2cc21408 Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Mon, 22 Jun 2015 16:38:46 -0600 Subject: spmi: add command tracepoints for SPMI Add tracepoints to retrieve information about read, write and non-data commands. For performance measurement support tracepoints are added at the beginning and at the end of transfers. Following is a list showing the new tracepoint events. The "cmd" parameter here represents the opcode, SID, and full 16-bit address. spmi_write_begin: cmd and data buffer. spmi_write_end : cmd and return value. spmi_read_begin : cmd. spmi_read_end : cmd, return value and data buffer. spmi_cmd : cmd. The reason that cmd appears at both the beginning and at the end event is that SPMI drivers can request commands concurrently. cmd helps in matching the corresponding events. SPMI tracepoints can be enabled like: echo 1 >/sys/kernel/debug/tracing/events/spmi/enable and will dump messages that can be viewed in /sys/kernel/debug/tracing/trace that look like: ... spmi_read_begin: opc=56 sid=00 addr=0x0000 ... spmi_read_end: opc=56 sid=00 addr=0x0000 ret=0 len=02 buf=0x[01-40] ... spmi_write_begin: opc=48 sid=00 addr=0x0000 len=3 buf=0x[ff-ff-ff] Suggested-by: Sagar Dharia Acked-by: Steven Rostedt Reviewed-by: Stephen Boyd Signed-off-by: Gilad Avidov Signed-off-by: Ankit Gupta Signed-off-by: Greg Kroah-Hartman --- drivers/spmi/spmi.c | 22 +++++++- include/trace/events/spmi.h | 135 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 include/trace/events/spmi.h (limited to 'drivers') diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c index 94938436aef9..11467e17bdd8 100644 --- a/drivers/spmi/spmi.c +++ b/drivers/spmi/spmi.c @@ -22,6 +22,8 @@ #include #include +#define CREATE_TRACE_POINTS +#include static DEFINE_IDA(ctrl_ida); @@ -96,28 +98,42 @@ EXPORT_SYMBOL_GPL(spmi_device_remove); static inline int spmi_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid) { + int ret; + if (!ctrl || !ctrl->cmd || ctrl->dev.type != &spmi_ctrl_type) return -EINVAL; - return ctrl->cmd(ctrl, opcode, sid); + ret = ctrl->cmd(ctrl, opcode, sid); + trace_spmi_cmd(opcode, sid, ret); + return ret; } static inline int spmi_read_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid, u16 addr, u8 *buf, size_t len) { + int ret; + if (!ctrl || !ctrl->read_cmd || ctrl->dev.type != &spmi_ctrl_type) return -EINVAL; - return ctrl->read_cmd(ctrl, opcode, sid, addr, buf, len); + trace_spmi_read_begin(opcode, sid, addr); + ret = ctrl->read_cmd(ctrl, opcode, sid, addr, buf, len); + trace_spmi_read_end(opcode, sid, addr, ret, len, buf); + return ret; } static inline int spmi_write_cmd(struct spmi_controller *ctrl, u8 opcode, u8 sid, u16 addr, const u8 *buf, size_t len) { + int ret; + if (!ctrl || !ctrl->write_cmd || ctrl->dev.type != &spmi_ctrl_type) return -EINVAL; - return ctrl->write_cmd(ctrl, opcode, sid, addr, buf, len); + trace_spmi_write_begin(opcode, sid, addr, len, buf); + ret = ctrl->write_cmd(ctrl, opcode, sid, addr, buf, len); + trace_spmi_write_end(opcode, sid, addr, ret); + return ret; } /** diff --git a/include/trace/events/spmi.h b/include/trace/events/spmi.h new file mode 100644 index 000000000000..62f005ef4c7e --- /dev/null +++ b/include/trace/events/spmi.h @@ -0,0 +1,135 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM spmi + +#if !defined(_TRACE_SPMI_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_SPMI_H + +#include +#include + +/* + * drivers/spmi/spmi.c + */ + +TRACE_EVENT(spmi_write_begin, + TP_PROTO(u8 opcode, u8 sid, u16 addr, u8 len, const u8 *buf), + TP_ARGS(opcode, sid, addr, len, buf), + + TP_STRUCT__entry( + __field ( u8, opcode ) + __field ( u8, sid ) + __field ( u16, addr ) + __field ( u8, len ) + __dynamic_array ( u8, buf, len + 1 ) + ), + + TP_fast_assign( + __entry->opcode = opcode; + __entry->sid = sid; + __entry->addr = addr; + __entry->len = len + 1; + memcpy(__get_dynamic_array(buf), buf, len + 1); + ), + + TP_printk("opc=%d sid=%02d addr=0x%04x len=%d buf=0x[%*phD]", + (int)__entry->opcode, (int)__entry->sid, + (int)__entry->addr, (int)__entry->len, + (int)__entry->len, __get_dynamic_array(buf)) +); + +TRACE_EVENT(spmi_write_end, + TP_PROTO(u8 opcode, u8 sid, u16 addr, int ret), + TP_ARGS(opcode, sid, addr, ret), + + TP_STRUCT__entry( + __field ( u8, opcode ) + __field ( u8, sid ) + __field ( u16, addr ) + __field ( int, ret ) + ), + + TP_fast_assign( + __entry->opcode = opcode; + __entry->sid = sid; + __entry->addr = addr; + __entry->ret = ret; + ), + + TP_printk("opc=%d sid=%02d addr=0x%04x ret=%d", + (int)__entry->opcode, (int)__entry->sid, + (int)__entry->addr, __entry->ret) +); + +TRACE_EVENT(spmi_read_begin, + TP_PROTO(u8 opcode, u8 sid, u16 addr), + TP_ARGS(opcode, sid, addr), + + TP_STRUCT__entry( + __field ( u8, opcode ) + __field ( u8, sid ) + __field ( u16, addr ) + ), + + TP_fast_assign( + __entry->opcode = opcode; + __entry->sid = sid; + __entry->addr = addr; + ), + + TP_printk("opc=%d sid=%02d addr=0x%04x", + (int)__entry->opcode, (int)__entry->sid, + (int)__entry->addr) +); + +TRACE_EVENT(spmi_read_end, + TP_PROTO(u8 opcode, u8 sid, u16 addr, int ret, u8 len, const u8 *buf), + TP_ARGS(opcode, sid, addr, ret, len, buf), + + TP_STRUCT__entry( + __field ( u8, opcode ) + __field ( u8, sid ) + __field ( u16, addr ) + __field ( int, ret ) + __field ( u8, len ) + __dynamic_array ( u8, buf, len + 1 ) + ), + + TP_fast_assign( + __entry->opcode = opcode; + __entry->sid = sid; + __entry->addr = addr; + __entry->ret = ret; + __entry->len = len + 1; + memcpy(__get_dynamic_array(buf), buf, len + 1); + ), + + TP_printk("opc=%d sid=%02d addr=0x%04x ret=%d len=%02d buf=0x[%*phD]", + (int)__entry->opcode, (int)__entry->sid, + (int)__entry->addr, __entry->ret, (int)__entry->len, + (int)__entry->len, __get_dynamic_array(buf)) +); + +TRACE_EVENT(spmi_cmd, + TP_PROTO(u8 opcode, u8 sid, int ret), + TP_ARGS(opcode, sid, ret), + + TP_STRUCT__entry( + __field ( u8, opcode ) + __field ( u8, sid ) + __field ( int, ret ) + ), + + TP_fast_assign( + __entry->opcode = opcode; + __entry->sid = sid; + __entry->ret = ret; + ), + + TP_printk("opc=%d sid=%02d ret=%d", (int)__entry->opcode, + (int)__entry->sid, ret) +); + +#endif /* _TRACE_SPMI_H */ + +/* This part must be outside protection */ +#include -- cgit v1.3-6-gb490 From 60be42306f838d9231398bdb7d4ff3451ae13601 Mon Sep 17 00:00:00 2001 From: Courtney Cavin Date: Thu, 30 Jul 2015 10:53:54 -0700 Subject: spmi: pmic-arb: add support for irq_get_irqchip_state Reviewed-by: Andy Gross Signed-off-by: Courtney Cavin Signed-off-by: Bjorn Andersson Tested-by: Tim Bird Signed-off-by: Greg Kroah-Hartman --- drivers/spmi/spmi-pmic-arb.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index d7119db49cfe..a4d8c043a710 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -575,6 +575,22 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) return 0; } +static int qpnpint_get_irqchip_state(struct irq_data *d, + enum irqchip_irq_state which, + bool *state) +{ + u8 irq = d->hwirq >> 8; + u8 status = 0; + + if (which != IRQCHIP_STATE_LINE_LEVEL) + return -EINVAL; + + qpnpint_spmi_read(d, QPNPINT_REG_RT_STS, &status, 1); + *state = !!(status & BIT(irq)); + + return 0; +} + static struct irq_chip pmic_arb_irqchip = { .name = "pmic_arb", .irq_enable = qpnpint_irq_enable, @@ -582,6 +598,7 @@ static struct irq_chip pmic_arb_irqchip = { .irq_mask = qpnpint_irq_mask, .irq_unmask = qpnpint_irq_unmask, .irq_set_type = qpnpint_irq_set_type, + .irq_get_irqchip_state = qpnpint_get_irqchip_state, .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, }; -- cgit v1.3-6-gb490 From d719b76c1306370d146c517e33b25f756b9a12d5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2015 11:37:16 -0700 Subject: spmi: Select IRQ_DOMAIN instead of depend on it IRQ_DOMAIN is a hidden config option, so depending on it doesn't make any sense. Select the config option because it's required to compile this driver. Signed-off-by: Stephen Boyd Reviewed-by: Andy Gross Signed-off-by: Greg Kroah-Hartman --- drivers/spmi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig index 982580af1d16..0d3b70b3bda8 100644 --- a/drivers/spmi/Kconfig +++ b/drivers/spmi/Kconfig @@ -12,7 +12,7 @@ if SPMI config SPMI_MSM_PMIC_ARB tristate "Qualcomm MSM SPMI Controller (PMIC Arbiter)" - depends on IRQ_DOMAIN + select IRQ_DOMAIN depends on ARCH_QCOM || COMPILE_TEST depends on HAS_IOMEM default ARCH_QCOM -- cgit v1.3-6-gb490 From b4629a7bdfd8fcafc90ded7e6a1f88099105842d Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Tue, 4 Aug 2015 10:59:17 +0200 Subject: usb: ehci-platform: Fix using multiple controllers from OF When using OF defined controllers the platform data struct is shared between all devices, so it can't be used for device specific settings. However it is currently used for the OF properties needs-reset-on-resume and has-transaction-translator. To fix this issue move setting hcd->has_tt to the probe and move pdata->reset_on_resume to the private data. Signed-off-by: Alban Bedel Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-platform.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 2593def13cea..5c3c08598682 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -45,6 +45,7 @@ struct ehci_platform_priv { struct reset_control *rst; struct phy **phys; int num_phys; + bool reset_on_resume; }; static const char hcd_name[] = "ehci-platform"; @@ -56,7 +57,6 @@ static int ehci_platform_reset(struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval; - hcd->has_tt = pdata->has_tt; ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug; if (pdata->pre_setup) { @@ -193,11 +193,11 @@ static int ehci_platform_probe(struct platform_device *dev) if (of_property_read_bool(dev->dev.of_node, "needs-reset-on-resume")) - pdata->reset_on_resume = 1; + priv->reset_on_resume = true; if (of_property_read_bool(dev->dev.of_node, "has-transaction-translator")) - pdata->has_tt = 1; + hcd->has_tt = 1; priv->num_phys = of_count_phandle_with_args(dev->dev.of_node, "phys", "#phy-cells"); @@ -247,6 +247,10 @@ static int ehci_platform_probe(struct platform_device *dev) ehci->big_endian_desc = 1; if (pdata->big_endian_mmio) ehci->big_endian_mmio = 1; + if (pdata->has_tt) + hcd->has_tt = 1; + if (pdata->reset_on_resume) + priv->reset_on_resume = true; #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO if (ehci->big_endian_mmio) { @@ -359,6 +363,7 @@ static int ehci_platform_resume(struct device *dev) struct usb_ehci_pdata *pdata = dev_get_platdata(dev); struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); if (pdata->power_on) { int err = pdata->power_on(pdev); @@ -366,7 +371,7 @@ static int ehci_platform_resume(struct device *dev) return err; } - ehci_resume(hcd, pdata->reset_on_resume); + ehci_resume(hcd, priv->reset_on_resume); return 0; } #endif /* CONFIG_PM_SLEEP */ -- cgit v1.3-6-gb490 From 135551ea1abd5038d14825514df7e259fd500033 Mon Sep 17 00:00:00 2001 From: Kris Borer Date: Tue, 4 Aug 2015 08:39:31 -0400 Subject: usb: devio: remove assignment from if condition Fix five occurrences of the checkpatch.pl error: ERROR: do not use assignment in if condition The semantic patch that makes this change is: // @@ identifier i; expression E; statement S1, S2; @@ + i = E; if ( - (i = E) + i ) S1 else S2 @@ identifier i; expression E; statement S; constant c; binary operator b; @@ + i = E; if ( - (i = E) + i b c ) S // Signed-off-by: Kris Borer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 986abde07683..ed6d1d5031f1 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1082,7 +1082,8 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg) ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); if (ret) return ret; - if (!(tbuf = kmalloc(len1, GFP_KERNEL))) { + tbuf = kmalloc(len1, GFP_KERNEL); + if (!tbuf) { ret = -ENOMEM; goto done; } @@ -1224,7 +1225,8 @@ static int proc_setintf(struct usb_dev_state *ps, void __user *arg) if (copy_from_user(&setintf, arg, sizeof(setintf))) return -EFAULT; - if ((ret = checkintf(ps, setintf.interface))) + ret = checkintf(ps, setintf.interface); + if (ret) return ret; destroy_async_on_interface(ps, setintf.interface); @@ -1393,7 +1395,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb number_of_packets = uurb->number_of_packets; isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * number_of_packets; - if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) + isopkt = kmalloc(isofrmlen, GFP_KERNEL); + if (!isopkt) return -ENOMEM; if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { ret = -EFAULT; @@ -1904,7 +1907,8 @@ static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg) if (get_user(ifnum, (unsigned int __user *)arg)) return -EFAULT; - if ((ret = releaseintf(ps, ifnum)) < 0) + ret = releaseintf(ps, ifnum); + if (ret < 0) return ret; destroy_async_on_interface (ps, ifnum); return 0; @@ -1919,7 +1923,8 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl) struct usb_driver *driver = NULL; /* alloc buffer */ - if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) { + size = _IOC_SIZE(ctl->ioctl_code); + if (size > 0) { buf = kmalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; -- cgit v1.3-6-gb490 From 082155eabfabd9148cc7e81c995e2c482075ccc3 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:01:31 +0000 Subject: usb: phy: phy-mxs-usb: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-mxs-usb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 3fcc0483a081..4d863ebc117c 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -506,11 +506,7 @@ static int mxs_phy_probe(struct platform_device *pdev) device_set_wakeup_capable(&pdev->dev, true); - ret = usb_add_phy_dev(&mxs_phy->phy); - if (ret) - return ret; - - return 0; + return usb_add_phy_dev(&mxs_phy->phy); } static int mxs_phy_remove(struct platform_device *pdev) -- cgit v1.3-6-gb490 From a9c5d8feb9e751a7521f1a5fa0d56901824e2ad8 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:02:03 +0000 Subject: usb: phy: phy-keystone: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-keystone.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index e0556f7832b5..01d4e4cdbc79 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -96,11 +96,7 @@ static int keystone_usbphy_probe(struct platform_device *pdev) platform_set_drvdata(pdev, k_phy); - ret = usb_add_phy_dev(&k_phy->usb_phy_gen.phy); - if (ret) - return ret; - - return 0; + return usb_add_phy_dev(&k_phy->usb_phy_gen.phy); } static int keystone_usbphy_remove(struct platform_device *pdev) -- cgit v1.3-6-gb490 From e94a7369a9293de2674de322d1e5253d63ba42ff Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:02:28 +0000 Subject: usb: musb: musb_dsps: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_dsps.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 1334a3de31b8..a0cfead6150f 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -482,11 +482,7 @@ static int dsps_musb_init(struct musb *musb) dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val); } - ret = dsps_musb_dbg_init(musb, glue); - if (ret) - return ret; - - return 0; + return dsps_musb_dbg_init(musb, glue); } static int dsps_musb_exit(struct musb *musb) -- cgit v1.3-6-gb490 From 16f9c3fd25b957f4df0fd5d9bf70249495c1a421 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:02:55 +0000 Subject: usb: host: ehci-st: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-st.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-st.c b/drivers/usb/host/ehci-st.c index 7e4bd39cf757..b7c5cfa37a83 100644 --- a/drivers/usb/host/ehci-st.c +++ b/drivers/usb/host/ehci-st.c @@ -54,7 +54,6 @@ static int st_ehci_platform_reset(struct usb_hcd *hcd) struct platform_device *pdev = to_platform_device(hcd->self.controller); struct usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; u32 threshold; /* Set EHCI packet buffer IN/OUT threshold to 128 bytes */ @@ -62,11 +61,7 @@ static int st_ehci_platform_reset(struct usb_hcd *hcd) writel(threshold, hcd->regs + AHB2STBUS_INSREG01); ehci->caps = hcd->regs + pdata->caps_offset; - retval = ehci_setup(hcd); - if (retval) - return retval; - - return 0; + return ehci_setup(hcd); } static int st_ehci_platform_power_on(struct platform_device *dev) -- cgit v1.3-6-gb490 From aa31a0909cc44bf2f75c14e800caff2d06ff725e Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:03:20 +0000 Subject: usb: host: oxu210hp-hcd: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/oxu210hp-hcd.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 6352f54e65a1..fe3bd1cb8b6b 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -2670,7 +2670,6 @@ static int oxu_hcd_init(struct usb_hcd *hcd) static int oxu_reset(struct usb_hcd *hcd) { struct oxu_hcd *oxu = hcd_to_oxu(hcd); - int ret; spin_lock_init(&oxu->mem_lock); INIT_LIST_HEAD(&oxu->urb_list); @@ -2696,11 +2695,7 @@ static int oxu_reset(struct usb_hcd *hcd) oxu->hcs_params = readl(&oxu->caps->hcs_params); oxu->sbrn = 0x20; - ret = oxu_hcd_init(hcd); - if (ret) - return ret; - - return 0; + return oxu_hcd_init(hcd); } static int oxu_run(struct usb_hcd *hcd) -- cgit v1.3-6-gb490 From 8602b08ab641a6004efa553c8089180c40bc1f72 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:03:45 +0000 Subject: usb: host: u132-hcd: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/u132-hcd.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index d51687780b61..a67bd5090330 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -1542,11 +1542,8 @@ static int u132_periodic_reinit(struct u132 *u132) (fit ^ FIT) | u132->hc_fminterval); if (retval) return retval; - retval = u132_write_pcimem(u132, periodicstart, - ((9 * fi) / 10) & 0x3fff); - if (retval) - return retval; - return 0; + return u132_write_pcimem(u132, periodicstart, + ((9 * fi) / 10) & 0x3fff); } static char *hcfs2string(int state) @@ -2701,28 +2698,18 @@ static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue, if (wIndex == 0 || wIndex > u132->num_ports) { return -EINVAL; } else { - int retval; int port_index = wIndex - 1; struct u132_port *port = &u132->port[port_index]; port->Status &= ~(1 << wValue); switch (wValue) { case USB_PORT_FEAT_SUSPEND: - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PSS); - if (retval) - return retval; - return 0; + return u132_write_pcimem(u132, + roothub.portstatus[port_index], RH_PS_PSS); case USB_PORT_FEAT_POWER: - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PPS); - if (retval) - return retval; - return 0; + return u132_write_pcimem(u132, + roothub.portstatus[port_index], RH_PS_PPS); case USB_PORT_FEAT_RESET: - retval = u132_roothub_portreset(u132, port_index); - if (retval) - return retval; - return 0; + return u132_roothub_portreset(u132, port_index); default: return -EPIPE; } @@ -2737,7 +2724,6 @@ static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, } else { int port_index = wIndex - 1; u32 temp; - int retval; struct u132_port *port = &u132->port[port_index]; port->Status &= ~(1 << wValue); switch (wValue) { @@ -2773,11 +2759,8 @@ static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, default: return -EPIPE; } - retval = u132_write_pcimem(u132, roothub.portstatus[port_index], - temp); - if (retval) - return retval; - return 0; + return u132_write_pcimem(u132, roothub.portstatus[port_index], + temp); } } -- cgit v1.3-6-gb490 From f1cda54cfb71720058cd65b2f1be7f2a86889935 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:04:09 +0000 Subject: usb: host: xhci: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index c3ac0a2aac37..91fd32835312 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4678,7 +4678,6 @@ int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, { struct xhci_hcd *xhci; u16 mel; - int ret; xhci = hcd_to_xhci(hcd); if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) || @@ -4686,10 +4685,7 @@ int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, return 0; mel = calculate_max_exit_latency(udev, state, USB3_LPM_DISABLED); - ret = xhci_change_max_exit_latency(xhci, udev, mel); - if (ret) - return ret; - return 0; + return xhci_change_max_exit_latency(xhci, udev, mel); } #else /* CONFIG_PM */ -- cgit v1.3-6-gb490 From eb82122a665b31ff9c40f1b4b66be71f0ef21bd3 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:04:35 +0000 Subject: usb: serial: mxuport: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/mxuport.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c index 460a40669967..31a8b47f1ac6 100644 --- a/drivers/usb/serial/mxuport.c +++ b/drivers/usb/serial/mxuport.c @@ -1137,13 +1137,9 @@ static int mxuport_port_probe(struct usb_serial_port *port) return err; /* Set interface (RS-232) */ - err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_INTERFACE, - MX_INT_RS232, - port->port_number); - if (err) - return err; - - return 0; + return mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_INTERFACE, + MX_INT_RS232, + port->port_number); } static int mxuport_alloc_write_urb(struct usb_serial *serial, -- cgit v1.3-6-gb490 From a53870c0ebe0b84a6e1a09785d24b0f0e6729962 Mon Sep 17 00:00:00 2001 From: Saurabh Karajgaonkar Date: Tue, 4 Aug 2015 14:05:03 +0000 Subject: usb: misc: ftdi-elan: Simplify return statement Replace redundant variable use in return statement. Signed-off-by: Saurabh Karajgaonkar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 8ab1f8f3c26e..52c27cab78c3 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -2568,11 +2568,7 @@ static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn) 0x00); if (UxxxStatus) return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - return 0; + return ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, &pcidata); } static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk) @@ -2695,11 +2691,7 @@ static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) } } if (ftdi->function > 0) { - UxxxStatus = ftdi_elan_setup_controller(ftdi, - ftdi->function - 1); - if (UxxxStatus) - return UxxxStatus; - return 0; + return ftdi_elan_setup_controller(ftdi, ftdi->function - 1); } else if (controllers > 0) { return -ENXIO; } else if (unrecognized > 0) { -- cgit v1.3-6-gb490 From ef0f8f1129844cab9b0fb14aab0d7d7598d81103 Mon Sep 17 00:00:00 2001 From: Xavier Deguillard Date: Fri, 12 Jun 2015 11:43:22 -0700 Subject: VMware balloon: partially inline vmballoon_reserve_page. This split the function in two: the allocation part is inlined into the inflate function and the lock part is kept into his own function. This change is needed in order to be able to allocate more than one page before doing the hypervisor call. Signed-off-by: Xavier Deguillard Acked-by: Dmitry Torokhov Signed-off-by: Philip P. Moltmann Acked-by: Andy King Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 98 ++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 191617492181..2799c46fd11f 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -46,7 +46,7 @@ MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); -MODULE_VERSION("1.2.1.3-k"); +MODULE_VERSION("1.2.2.0-k"); MODULE_ALIAS("dmi:*:svnVMware*:*"); MODULE_ALIAS("vmware_vmmemctl"); MODULE_LICENSE("GPL"); @@ -402,55 +402,37 @@ static void vmballoon_reset(struct vmballoon *b) } /* - * Allocate (or reserve) a page for the balloon and notify the host. If host - * refuses the page put it on "refuse" list and allocate another one until host - * is satisfied. "Refused" pages are released at the end of inflation cycle - * (when we allocate b->rate_alloc pages). + * Notify the host of a ballooned page. If host rejects the page put it on the + * refuse list, those refused page are then released at the end of the + * inflation cycle. */ -static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep) +static int vmballoon_lock_page(struct vmballoon *b, struct page *page) { - struct page *page; - gfp_t flags; - unsigned int hv_status; - int locked; - flags = can_sleep ? VMW_PAGE_ALLOC_CANSLEEP : VMW_PAGE_ALLOC_NOSLEEP; - - do { - if (!can_sleep) - STATS_INC(b->stats.alloc); - else - STATS_INC(b->stats.sleep_alloc); - - page = alloc_page(flags); - if (!page) { - if (!can_sleep) - STATS_INC(b->stats.alloc_fail); - else - STATS_INC(b->stats.sleep_alloc_fail); - return -ENOMEM; - } + int locked, hv_status; - /* inform monitor */ - locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status); - if (locked > 0) { - STATS_INC(b->stats.refused_alloc); + locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status); + if (locked > 0) { + STATS_INC(b->stats.refused_alloc); - if (hv_status == VMW_BALLOON_ERROR_RESET || - hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED) { - __free_page(page); - return -EIO; - } + if (hv_status == VMW_BALLOON_ERROR_RESET || + hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED) { + __free_page(page); + return -EIO; + } - /* - * Place page on the list of non-balloonable pages - * and retry allocation, unless we already accumulated - * too many of them, in which case take a breather. - */ + /* + * Place page on the list of non-balloonable pages + * and retry allocation, unless we already accumulated + * too many of them, in which case take a breather. + */ + if (b->n_refused_pages < VMW_BALLOON_MAX_REFUSED) { + b->n_refused_pages++; list_add(&page->lru, &b->refused_pages); - if (++b->n_refused_pages >= VMW_BALLOON_MAX_REFUSED) - return -EIO; + } else { + __free_page(page); } - } while (locked != 0); + return -EIO; + } /* track allocated page */ list_add(&page->lru, &b->pages); @@ -512,7 +494,7 @@ static void vmballoon_inflate(struct vmballoon *b) unsigned int i; unsigned int allocations = 0; int error = 0; - bool alloc_can_sleep = false; + gfp_t flags = VMW_PAGE_ALLOC_NOSLEEP; pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target); @@ -543,19 +525,16 @@ static void vmballoon_inflate(struct vmballoon *b) __func__, goal, rate, b->rate_alloc); for (i = 0; i < goal; i++) { + struct page *page; - error = vmballoon_reserve_page(b, alloc_can_sleep); - if (error) { - if (error != -ENOMEM) { - /* - * Not a page allocation failure, stop this - * cycle. Maybe we'll get new target from - * the host soon. - */ - break; - } + if (flags == VMW_PAGE_ALLOC_NOSLEEP) + STATS_INC(b->stats.alloc); + else + STATS_INC(b->stats.sleep_alloc); - if (alloc_can_sleep) { + page = alloc_page(flags); + if (!page) { + if (flags == VMW_PAGE_ALLOC_CANSLEEP) { /* * CANSLEEP page allocation failed, so guest * is under severe memory pressure. Quickly @@ -563,8 +542,10 @@ static void vmballoon_inflate(struct vmballoon *b) */ b->rate_alloc = max(b->rate_alloc / 2, VMW_BALLOON_RATE_ALLOC_MIN); + STATS_INC(b->stats.sleep_alloc_fail); break; } + STATS_INC(b->stats.alloc_fail); /* * NOSLEEP page allocation failed, so the guest is @@ -579,11 +560,16 @@ static void vmballoon_inflate(struct vmballoon *b) if (i >= b->rate_alloc) break; - alloc_can_sleep = true; + flags = VMW_PAGE_ALLOC_CANSLEEP; /* Lower rate for sleeping allocations. */ rate = b->rate_alloc; + continue; } + error = vmballoon_lock_page(b, page); + if (error) + break; + if (++allocations > VMW_BALLOON_YIELD_THRESHOLD) { cond_resched(); allocations = 0; -- cgit v1.3-6-gb490 From eb79100fe6a696bfbad21aaf8e373d72763c7462 Mon Sep 17 00:00:00 2001 From: Xavier Deguillard Date: Fri, 12 Jun 2015 11:43:23 -0700 Subject: VMware balloon: Add support for balloon capabilities. In order to extend the balloon protocol, the hypervisor and the guest driver need to agree on a set of supported functionality to use. Signed-off-by: Xavier Deguillard Acked-by: Dmitry Torokhov Signed-off-by: Philip P. Moltmann Acked-by: Andy King Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_balloon.c | 74 +++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 2799c46fd11f..ffb56340d0c7 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -46,7 +46,7 @@ MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); -MODULE_VERSION("1.2.2.0-k"); +MODULE_VERSION("1.3.0.0-k"); MODULE_ALIAS("dmi:*:svnVMware*:*"); MODULE_ALIAS("vmware_vmmemctl"); MODULE_LICENSE("GPL"); @@ -110,9 +110,18 @@ MODULE_LICENSE("GPL"); */ #define VMW_BALLOON_HV_PORT 0x5670 #define VMW_BALLOON_HV_MAGIC 0x456c6d6f -#define VMW_BALLOON_PROTOCOL_VERSION 2 #define VMW_BALLOON_GUEST_ID 1 /* Linux */ +enum vmwballoon_capabilities { + /* + * Bit 0 is reserved and not associated to any capability. + */ + VMW_BALLOON_BASIC_CMDS = (1 << 1), + VMW_BALLOON_BATCHED_CMDS = (1 << 2) +}; + +#define VMW_BALLOON_CAPABILITIES (VMW_BALLOON_BASIC_CMDS) + #define VMW_BALLOON_CMD_START 0 #define VMW_BALLOON_CMD_GET_TARGET 1 #define VMW_BALLOON_CMD_LOCK 2 @@ -120,32 +129,36 @@ MODULE_LICENSE("GPL"); #define VMW_BALLOON_CMD_GUEST_ID 4 /* error codes */ -#define VMW_BALLOON_SUCCESS 0 -#define VMW_BALLOON_FAILURE -1 -#define VMW_BALLOON_ERROR_CMD_INVALID 1 -#define VMW_BALLOON_ERROR_PPN_INVALID 2 -#define VMW_BALLOON_ERROR_PPN_LOCKED 3 -#define VMW_BALLOON_ERROR_PPN_UNLOCKED 4 -#define VMW_BALLOON_ERROR_PPN_PINNED 5 -#define VMW_BALLOON_ERROR_PPN_NOTNEEDED 6 -#define VMW_BALLOON_ERROR_RESET 7 -#define VMW_BALLOON_ERROR_BUSY 8 - -#define VMWARE_BALLOON_CMD(cmd, data, result) \ -({ \ - unsigned long __stat, __dummy1, __dummy2; \ - __asm__ __volatile__ ("inl %%dx" : \ - "=a"(__stat), \ - "=c"(__dummy1), \ - "=d"(__dummy2), \ - "=b"(result) : \ - "0"(VMW_BALLOON_HV_MAGIC), \ - "1"(VMW_BALLOON_CMD_##cmd), \ - "2"(VMW_BALLOON_HV_PORT), \ - "3"(data) : \ - "memory"); \ - result &= -1UL; \ - __stat & -1UL; \ +#define VMW_BALLOON_SUCCESS 0 +#define VMW_BALLOON_FAILURE -1 +#define VMW_BALLOON_ERROR_CMD_INVALID 1 +#define VMW_BALLOON_ERROR_PPN_INVALID 2 +#define VMW_BALLOON_ERROR_PPN_LOCKED 3 +#define VMW_BALLOON_ERROR_PPN_UNLOCKED 4 +#define VMW_BALLOON_ERROR_PPN_PINNED 5 +#define VMW_BALLOON_ERROR_PPN_NOTNEEDED 6 +#define VMW_BALLOON_ERROR_RESET 7 +#define VMW_BALLOON_ERROR_BUSY 8 + +#define VMW_BALLOON_SUCCESS_WITH_CAPABILITIES (0x03000000) + +#define VMWARE_BALLOON_CMD(cmd, data, result) \ +({ \ + unsigned long __status, __dummy1, __dummy2; \ + __asm__ __volatile__ ("inl %%dx" : \ + "=a"(__status), \ + "=c"(__dummy1), \ + "=d"(__dummy2), \ + "=b"(result) : \ + "0"(VMW_BALLOON_HV_MAGIC), \ + "1"(VMW_BALLOON_CMD_##cmd), \ + "2"(VMW_BALLOON_HV_PORT), \ + "3"(data) : \ + "memory"); \ + if (VMW_BALLOON_CMD_##cmd == VMW_BALLOON_CMD_START) \ + result = __dummy1; \ + result &= -1UL; \ + __status & -1UL; \ }) #ifdef CONFIG_DEBUG_FS @@ -223,11 +236,12 @@ static struct vmballoon balloon; */ static bool vmballoon_send_start(struct vmballoon *b) { - unsigned long status, dummy; + unsigned long status, capabilities; STATS_INC(b->stats.start); - status = VMWARE_BALLOON_CMD(START, VMW_BALLOON_PROTOCOL_VERSION, dummy); + status = VMWARE_BALLOON_CMD(START, VMW_BALLOON_CAPABILITIES, + capabilities); if (status == VMW_BALLOON_SUCCESS) return true; -- cgit v1.3-6-gb490 From 1241d7bf2ac8838d0d2d0b54a6173ac3eb3747a4 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 3 Aug 2015 13:04:54 -0400 Subject: core: Remove the ib_reg_phys_mr() and ib_rereg_phys_mr() verbs The verbs are obsolete. The ib_rereg_phys_mr() verb is not used by kernel ULPs, and the last ib_reg_phys_mr() call site in the kernel tree has now been removed. Two staging tree call sites remain in the Lustre client. The Lustre team has been notified of the deprecation of reg_phys_mr. Signed-off-by: Chuck Lever Acked-by: Doug Ledford Signed-off-by: Anna Schumaker --- drivers/infiniband/core/verbs.c | 67 ----------------------------------------- include/rdma/ib_verbs.h | 46 ---------------------------- 2 files changed, 113 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index bac3fb406a74..30eb2457000c 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1144,73 +1144,6 @@ struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags) } EXPORT_SYMBOL(ib_get_dma_mr); -struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd, - struct ib_phys_buf *phys_buf_array, - int num_phys_buf, - int mr_access_flags, - u64 *iova_start) -{ - struct ib_mr *mr; - int err; - - err = ib_check_mr_access(mr_access_flags); - if (err) - return ERR_PTR(err); - - if (!pd->device->reg_phys_mr) - return ERR_PTR(-ENOSYS); - - mr = pd->device->reg_phys_mr(pd, phys_buf_array, num_phys_buf, - mr_access_flags, iova_start); - - 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_reg_phys_mr); - -int ib_rereg_phys_mr(struct ib_mr *mr, - int mr_rereg_mask, - struct ib_pd *pd, - struct ib_phys_buf *phys_buf_array, - int num_phys_buf, - int mr_access_flags, - u64 *iova_start) -{ - struct ib_pd *old_pd; - int ret; - - ret = ib_check_mr_access(mr_access_flags); - if (ret) - return ret; - - if (!mr->device->rereg_phys_mr) - return -ENOSYS; - - if (atomic_read(&mr->usecnt)) - return -EBUSY; - - old_pd = mr->pd; - - ret = mr->device->rereg_phys_mr(mr, mr_rereg_mask, pd, - phys_buf_array, num_phys_buf, - mr_access_flags, iova_start); - - if (!ret && (mr_rereg_mask & IB_MR_REREG_PD)) { - atomic_dec(&old_pd->usecnt); - atomic_inc(&pd->usecnt); - } - - return ret; -} -EXPORT_SYMBOL(ib_rereg_phys_mr); - int ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr) { return mr->device->query_mr ? diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index b0f898e3b2e7..43c1cf01c84b 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2759,52 +2759,6 @@ static inline void ib_dma_free_coherent(struct ib_device *dev, dma_free_coherent(dev->dma_device, size, cpu_addr, dma_handle); } -/** - * ib_reg_phys_mr - Prepares a virtually addressed memory region for use - * by an HCA. - * @pd: The protection domain associated assigned to the registered region. - * @phys_buf_array: Specifies a list of physical buffers to use in the - * memory region. - * @num_phys_buf: Specifies the size of the phys_buf_array. - * @mr_access_flags: Specifies the memory access rights. - * @iova_start: The offset of the region's starting I/O virtual address. - */ -struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd, - struct ib_phys_buf *phys_buf_array, - int num_phys_buf, - int mr_access_flags, - u64 *iova_start); - -/** - * ib_rereg_phys_mr - Modifies the attributes of an existing memory region. - * Conceptually, this call performs the functions deregister memory region - * followed by register physical memory region. Where possible, - * resources are reused instead of deallocated and reallocated. - * @mr: The memory region to modify. - * @mr_rereg_mask: A bit-mask used to indicate which of the following - * properties of the memory region are being modified. - * @pd: If %IB_MR_REREG_PD is set in mr_rereg_mask, this field specifies - * the new protection domain to associated with the memory region, - * otherwise, this parameter is ignored. - * @phys_buf_array: If %IB_MR_REREG_TRANS is set in mr_rereg_mask, this - * field specifies a list of physical buffers to use in the new - * translation, otherwise, this parameter is ignored. - * @num_phys_buf: If %IB_MR_REREG_TRANS is set in mr_rereg_mask, this - * field specifies the size of the phys_buf_array, otherwise, this - * parameter is ignored. - * @mr_access_flags: If %IB_MR_REREG_ACCESS is set in mr_rereg_mask, this - * field specifies the new memory access rights, otherwise, this - * parameter is ignored. - * @iova_start: The offset of the region's starting I/O virtual address. - */ -int ib_rereg_phys_mr(struct ib_mr *mr, - int mr_rereg_mask, - struct ib_pd *pd, - struct ib_phys_buf *phys_buf_array, - int num_phys_buf, - int mr_access_flags, - u64 *iova_start); - /** * ib_query_mr - Retrieves information about a specific memory region. * @mr: The memory region to retrieve information about. -- cgit v1.3-6-gb490 From c0bd1b9e58959c51a4c939505f89721dfbc73c44 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 22 Jul 2015 13:17:15 -0500 Subject: Revert "ti-st: add device tree support" This reverts commit 46d0d33350e9b32642d745a8b46a954910196b4d. This binding is horrible and never should have been merged. It is not documented nor are there any in tree users, so reverting it will not break anything we care about. Lets revert it before we do have users. The problems with it are: - It is not documented. - The GPIO connection is described with a custom property and uses Linux GPIO numbering. - The UART connection is described using the Linux tty device name. Cc: Gigi Joseph Cc: Greg Kroah-Hartman Signed-off-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 94 ++++---------------------------------------- drivers/misc/ti-st/st_ll.c | 17 +------- include/linux/ti_wilink_st.h | 1 - 3 files changed, 9 insertions(+), 103 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index c84093e639e0..c828282af38a 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -36,8 +36,6 @@ #include #include #include -#include -#include #define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */ static struct platform_device *st_kim_devices[MAX_ST_DEVICES]; @@ -45,9 +43,6 @@ static struct platform_device *st_kim_devices[MAX_ST_DEVICES]; /**********************************************************************/ /* internal functions */ -struct ti_st_plat_data *dt_pdata; -static struct ti_st_plat_data *get_platform_data(struct device *dev); - /** * st_get_plat_device - * function which returns the reference to the platform device @@ -469,12 +464,7 @@ long st_kim_start(void *kim_data) struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; pr_info(" %s", __func__); - if (kim_gdata->kim_pdev->dev.of_node) { - pr_debug("use device tree data"); - pdata = dt_pdata; - } else { - pdata = kim_gdata->kim_pdev->dev.platform_data; - } + pdata = kim_gdata->kim_pdev->dev.platform_data; do { /* platform specific enabling code here */ @@ -534,18 +524,12 @@ long st_kim_stop(void *kim_data) { long err = 0; struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; - struct ti_st_plat_data *pdata; + struct ti_st_plat_data *pdata = + kim_gdata->kim_pdev->dev.platform_data; struct tty_struct *tty = kim_gdata->core_data->tty; reinit_completion(&kim_gdata->ldisc_installed); - if (kim_gdata->kim_pdev->dev.of_node) { - pr_debug("use device tree data"); - pdata = dt_pdata; - } else - pdata = kim_gdata->kim_pdev->dev.platform_data; - - if (tty) { /* can be called before ldisc is installed */ /* Flush any pending characters in the driver and discipline. */ tty_ldisc_flush(tty); @@ -737,52 +721,13 @@ static const struct file_operations list_debugfs_fops = { * board-*.c file */ -static const struct of_device_id kim_of_match[] = { -{ - .compatible = "kim", - }, - {} -}; -MODULE_DEVICE_TABLE(of, kim_of_match); - -static struct ti_st_plat_data *get_platform_data(struct device *dev) -{ - struct device_node *np = dev->of_node; - const u32 *dt_property; - int len; - - dt_pdata = kzalloc(sizeof(*dt_pdata), GFP_KERNEL); - if (!dt_pdata) - return NULL; - - dt_property = of_get_property(np, "dev_name", &len); - if (dt_property) - memcpy(&dt_pdata->dev_name, dt_property, len); - of_property_read_u32(np, "nshutdown_gpio", - &dt_pdata->nshutdown_gpio); - of_property_read_u32(np, "flow_cntrl", &dt_pdata->flow_cntrl); - of_property_read_u32(np, "baud_rate", &dt_pdata->baud_rate); - - return dt_pdata; -} - static struct dentry *kim_debugfs_dir; static int kim_probe(struct platform_device *pdev) { struct kim_data_s *kim_gdata; - struct ti_st_plat_data *pdata; + struct ti_st_plat_data *pdata = pdev->dev.platform_data; int err; - if (pdev->dev.of_node) - pdata = get_platform_data(&pdev->dev); - else - pdata = pdev->dev.platform_data; - - if (pdata == NULL) { - dev_err(&pdev->dev, "Platform Data is missing\n"); - return -ENXIO; - } - if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { /* multiple devices could exist */ st_kim_devices[pdev->id] = pdev; @@ -863,16 +808,9 @@ err_core_init: static int kim_remove(struct platform_device *pdev) { /* free the GPIOs requested */ - struct ti_st_plat_data *pdata; + struct ti_st_plat_data *pdata = pdev->dev.platform_data; struct kim_data_s *kim_gdata; - if (pdev->dev.of_node) { - pr_debug("use device tree data"); - pdata = dt_pdata; - } else { - pdata = pdev->dev.platform_data; - } - kim_gdata = platform_get_drvdata(pdev); /* Free the Bluetooth/FM/GPIO @@ -890,22 +828,12 @@ static int kim_remove(struct platform_device *pdev) kfree(kim_gdata); kim_gdata = NULL; - kfree(dt_pdata); - dt_pdata = NULL; - return 0; } static int kim_suspend(struct platform_device *pdev, pm_message_t state) { - struct ti_st_plat_data *pdata; - - if (pdev->dev.of_node) { - pr_debug("use device tree data"); - pdata = dt_pdata; - } else { - pdata = pdev->dev.platform_data; - } + struct ti_st_plat_data *pdata = pdev->dev.platform_data; if (pdata->suspend) return pdata->suspend(pdev, state); @@ -915,14 +843,7 @@ static int kim_suspend(struct platform_device *pdev, pm_message_t state) static int kim_resume(struct platform_device *pdev) { - struct ti_st_plat_data *pdata; - - if (pdev->dev.of_node) { - pr_debug("use device tree data"); - pdata = dt_pdata; - } else { - pdata = pdev->dev.platform_data; - } + struct ti_st_plat_data *pdata = pdev->dev.platform_data; if (pdata->resume) return pdata->resume(pdev); @@ -939,7 +860,6 @@ static struct platform_driver kim_platform_driver = { .resume = kim_resume, .driver = { .name = "kim", - .of_match_table = of_match_ptr(kim_of_match), }, }; diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c index 518e1b7f2f95..93b4d67cc4a3 100644 --- a/drivers/misc/ti-st/st_ll.c +++ b/drivers/misc/ti-st/st_ll.c @@ -26,7 +26,6 @@ #include /**********************************************************************/ - /* internal functions */ static void send_ll_cmd(struct st_data_s *st_data, unsigned char cmd) @@ -54,13 +53,7 @@ static void ll_device_want_to_sleep(struct st_data_s *st_data) /* communicate to platform about chip asleep */ kim_data = st_data->kim_data; - if (kim_data->kim_pdev->dev.of_node) { - pr_debug("use device tree data"); - pdata = dt_pdata; - } else { - pdata = kim_data->kim_pdev->dev.platform_data; - } - + pdata = kim_data->kim_pdev->dev.platform_data; if (pdata->chip_asleep) pdata->chip_asleep(NULL); } @@ -93,13 +86,7 @@ static void ll_device_want_to_wakeup(struct st_data_s *st_data) /* communicate to platform about chip wakeup */ kim_data = st_data->kim_data; - if (kim_data->kim_pdev->dev.of_node) { - pr_debug("use device tree data"); - pdata = dt_pdata; - } else { - pdata = kim_data->kim_pdev->dev.platform_data; - } - + pdata = kim_data->kim_pdev->dev.platform_data; if (pdata->chip_awake) pdata->chip_awake(NULL); } diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h index c78dcfeaf25f..d4217eff489f 100644 --- a/include/linux/ti_wilink_st.h +++ b/include/linux/ti_wilink_st.h @@ -86,7 +86,6 @@ struct st_proto_s { extern long st_register(struct st_proto_s *); extern long st_unregister(struct st_proto_s *); -extern struct ti_st_plat_data *dt_pdata; /* * header information used by st_core.c -- cgit v1.3-6-gb490 From 513da46d4b72bf6c4c956c57044fcbcfe321deeb Mon Sep 17 00:00:00 2001 From: Jürg Billeter Date: Wed, 24 Jun 2015 12:24:06 +0200 Subject: ti-st: st_kim: use gpio_set_value_cansleep to fix warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPIO accessor functions may sleep. Signed-off-by: Jürg Billeter Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ti-st/st_kim.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index c828282af38a..71b64550b591 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -472,9 +472,9 @@ long st_kim_start(void *kim_data) pdata->chip_enable(kim_gdata); /* Configure BT nShutdown to HIGH state */ - gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); + gpio_set_value_cansleep(kim_gdata->nshutdown, GPIO_LOW); mdelay(5); /* FIXME: a proper toggle */ - gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH); + gpio_set_value_cansleep(kim_gdata->nshutdown, GPIO_HIGH); mdelay(100); /* re-initialize the completion */ reinit_completion(&kim_gdata->ldisc_installed); @@ -550,11 +550,11 @@ long st_kim_stop(void *kim_data) } /* By default configure BT nShutdown to LOW state */ - gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); + gpio_set_value_cansleep(kim_gdata->nshutdown, GPIO_LOW); mdelay(1); - gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH); + gpio_set_value_cansleep(kim_gdata->nshutdown, GPIO_HIGH); mdelay(1); - gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); + gpio_set_value_cansleep(kim_gdata->nshutdown, GPIO_LOW); /* platform specific disable */ if (pdata->chip_disable) -- cgit v1.3-6-gb490 From e2ef93930326134001523016782daddf1a4b78a2 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 8 Jul 2015 17:24:46 +0200 Subject: uio: Destroy uio_idr on module exit Destroy uio_idr on module exit, reclaiming the allocated memory. This was detected by the following semantic patch (written by Luis Rodriguez ) @ defines_module_init @ declarer name module_init, module_exit; declarer name DEFINE_IDR; identifier init; @@ module_init(init); @ defines_module_exit @ identifier exit; @@ module_exit(exit); @ declares_idr depends on defines_module_init && defines_module_exit @ identifier idr; @@ DEFINE_IDR(idr); @ on_exit_calls_destroy depends on declares_idr && defines_module_exit @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... idr_destroy(&idr); ... } @ missing_module_idr_destroy depends on declares_idr && defines_module_exit && !on_exit_calls_destroy @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... +idr_destroy(&idr); } Signed-off-by: Johannes Thumshirn Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 3257d4220d01..8196581f54c2 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -896,6 +896,7 @@ static int __init uio_init(void) static void __exit uio_exit(void) { release_uio_class(); + idr_destroy(&uio_idr); } module_init(uio_init) -- cgit v1.3-6-gb490 From d12f569c9b57ecdb18631d0b54c5224da5a1c233 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Wed, 8 Jul 2015 10:24:27 +0530 Subject: uio: uio_fsl_elbc_gpcm: Use module_platform_driver Use module_platform_driver for drivers whose init and exit functions only register and unregister, respectively. A simplified version of the Coccinelle semantic patch that performs this transformation is as follows: @a@ identifier f, x; @@ -static f(...) { return platform_driver_register(&x); } @b depends on a@ identifier e, a.x; @@ -static e(...) { platform_driver_unregister(&x); } @c depends on a && b@ identifier a.f; declarer name module_init; @@ -module_init(f); @d depends on a && b && c@ identifier b.e, a.x; declarer name module_exit; declarer name module_platform_driver; @@ -module_exit(e); +module_platform_driver(x); Signed-off-by: Vaishali Thakkar Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_fsl_elbc_gpcm.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/uio/uio_fsl_elbc_gpcm.c b/drivers/uio/uio_fsl_elbc_gpcm.c index b6cac91c2ced..2bcf80c159c1 100644 --- a/drivers/uio/uio_fsl_elbc_gpcm.c +++ b/drivers/uio/uio_fsl_elbc_gpcm.c @@ -480,19 +480,7 @@ static struct platform_driver uio_fsl_elbc_gpcm_driver = { .probe = uio_fsl_elbc_gpcm_probe, .remove = uio_fsl_elbc_gpcm_remove, }; - -static int __init uio_fsl_elbc_gpcm_init(void) -{ - return platform_driver_register(&uio_fsl_elbc_gpcm_driver); -} - -static void __exit uio_fsl_elbc_gpcm_exit(void) -{ - platform_driver_unregister(&uio_fsl_elbc_gpcm_driver); -} - -module_init(uio_fsl_elbc_gpcm_init); -module_exit(uio_fsl_elbc_gpcm_exit); +module_platform_driver(uio_fsl_elbc_gpcm_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("John Ogness "); -- cgit v1.3-6-gb490 From 686079c9b71a4673d0068ea4538f22359070ee33 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 29 Jun 2015 09:12:38 +0200 Subject: uio: UIO_PRUSS should depend on HAS_DMA If NO_DMA=y: ERROR: "dma_alloc_coherent" [drivers/uio/uio_pruss.ko] undefined! ERROR: "dma_free_coherent" [drivers/uio/uio_pruss.ko] undefined! Add a dependency on HAS_DMA to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/uio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 48fb1d983f6c..52c98ce1b6fe 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -127,7 +127,7 @@ config UIO_FSL_ELBC_GPCM_NETX5152 config UIO_PRUSS tristate "Texas Instruments PRUSS driver" select GENERIC_ALLOCATOR - depends on HAS_IOMEM + depends on HAS_IOMEM && HAS_DMA help PRUSS driver for OMAPL138/DA850/AM18XX devices PRUSS driver requires user space components, examples and user space -- cgit v1.3-6-gb490 From 27d3fd3d0d89030798121718637d6b0ed59e0ca5 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Fri, 31 Jul 2015 09:37:22 -0600 Subject: coresight-etm3x: Add Qualcomm PTM v1.1 peripheral ID Add Qualcomm's PTM v1.1 peripheral ID to supported devices. This device could be found at least in MSM8974 and APQ8064 chipsets. Signed-off-by: Ivan T. Ivanov Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm3x.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index 018a00fda611..cca98a8b2527 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c @@ -1912,6 +1912,11 @@ static struct amba_id etm_ids[] = { .mask = 0x0003ffff, .data = "PTM 1.1", }, + { /* PTM 1.1 Qualcomm */ + .id = 0x0003006f, + .mask = 0x0003ffff, + .data = "PTM 1.1", + }, { 0, 0}, }; -- cgit v1.3-6-gb490 From c35aaa13794a0c5b752af19993222d08497e7036 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Fri, 31 Jul 2015 09:37:23 -0600 Subject: coresight: replicator: Use builtin_platform_driver() Macro builtin_platform_driver can be used for builtin drivers that don't do anything in driver init. This file depends on Kconfig CONFIG_CORESIGHT_LINKS_AND_SINKS which eventually depends on CORESIGHT. Both CONFIG_CORESIGHT_LINKS_AND_SINKS and CORESIGHT are bool. So, use builtin_platform_driver and remove some boilerplate code. Also, remove header file init.h as functionality like module_init and module_exit is now relocated to module.h. Signed-off-by: Vaishali Thakkar Suggested-by: Paul Bolle Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-replicator.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c index 7974b7c3da6b..963ac197c253 100644 --- a/drivers/hwtracing/coresight/coresight-replicator.c +++ b/drivers/hwtracing/coresight/coresight-replicator.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -184,17 +183,7 @@ static struct platform_driver replicator_driver = { }, }; -static int __init replicator_init(void) -{ - return platform_driver_register(&replicator_driver); -} -module_init(replicator_init); - -static void __exit replicator_exit(void) -{ - platform_driver_unregister(&replicator_driver); -} -module_exit(replicator_exit); +builtin_platform_driver(replicator_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("CoreSight Replicator driver"); -- cgit v1.3-6-gb490 From 414a1417d7b35e0e72edb16e45840e242cb6b52e Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 31 Jul 2015 09:37:24 -0600 Subject: coresight-etm3x: Change the name of the ctxid_val to ctxid_pid 'ctxid_val' array was used to store the value of ETM context ID comparator which actually stores the process ID to be traced, so using 'ctxid_pid' as its name instead make it easier to understand. This patch also changes the ABI, it is normally not allowed, but fortunately it is a testing ABI and very new for now. Nevertheless, if you don't think it should be changed, we could always add an alias for userspace. Signed-off-by: Chunyan Zhang Reviewed-by: Mark Brown Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-bus-coresight-devices-etm3x | 2 +- drivers/hwtracing/coresight/coresight-etm.h | 4 ++-- drivers/hwtracing/coresight/coresight-etm3x.c | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x index b4d0b99afffb..d72ca1736ba4 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm3x @@ -112,7 +112,7 @@ KernelVersion: 3.19 Contact: Mathieu Poirier Description: (RW) Mask to apply to all the context ID comparator. -What: /sys/bus/coresight/devices/.[etm|ptm]/ctxid_val +What: /sys/bus/coresight/devices/.[etm|ptm]/ctxid_pid Date: November 2014 KernelVersion: 3.19 Contact: Mathieu Poirier diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h index 098ffbec0a44..52af5f0adbed 100644 --- a/drivers/hwtracing/coresight/coresight-etm.h +++ b/drivers/hwtracing/coresight/coresight-etm.h @@ -183,7 +183,7 @@ * @seq_13_event: event causing the transition from 1 to 3. * @seq_curr_state: current value of the sequencer register. * @ctxid_idx: index for the context ID registers. - * @ctxid_val: value for the context ID to trigger on. + * @ctxid_pid: value for the context ID to trigger on. * @ctxid_mask: mask applicable to all the context IDs. * @sync_freq: Synchronisation frequency. * @timestamp_event: Defines an event that requests the insertion @@ -235,7 +235,7 @@ struct etm_drvdata { u32 seq_13_event; u32 seq_curr_state; u8 ctxid_idx; - u32 ctxid_val[ETM_MAX_CTXID_CMP]; + u32 ctxid_pid[ETM_MAX_CTXID_CMP]; u32 ctxid_mask; u32 sync_freq; u32 timestamp_event; diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index cca98a8b2527..361b82068dda 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c @@ -238,7 +238,7 @@ static void etm_set_default(struct etm_drvdata *drvdata) drvdata->seq_curr_state = 0x0; drvdata->ctxid_idx = 0x0; for (i = 0; i < drvdata->nr_ctxid_cmp; i++) - drvdata->ctxid_val[i] = 0x0; + drvdata->ctxid_pid[i] = 0x0; drvdata->ctxid_mask = 0x0; } @@ -289,7 +289,7 @@ static void etm_enable_hw(void *info) for (i = 0; i < drvdata->nr_ext_out; i++) etm_writel(drvdata, ETM_DEFAULT_EVENT_VAL, ETMEXTOUTEVRn(i)); for (i = 0; i < drvdata->nr_ctxid_cmp; i++) - etm_writel(drvdata, drvdata->ctxid_val[i], ETMCIDCVRn(i)); + etm_writel(drvdata, drvdata->ctxid_pid[i], ETMCIDCVRn(i)); etm_writel(drvdata, drvdata->ctxid_mask, ETMCIDCMR); etm_writel(drvdata, drvdata->sync_freq, ETMSYNCFR); /* No external input selected */ @@ -1386,20 +1386,20 @@ static ssize_t ctxid_idx_store(struct device *dev, } static DEVICE_ATTR_RW(ctxid_idx); -static ssize_t ctxid_val_show(struct device *dev, +static ssize_t ctxid_pid_show(struct device *dev, struct device_attribute *attr, char *buf) { unsigned long val; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); spin_lock(&drvdata->spinlock); - val = drvdata->ctxid_val[drvdata->ctxid_idx]; + val = drvdata->ctxid_pid[drvdata->ctxid_idx]; spin_unlock(&drvdata->spinlock); return sprintf(buf, "%#lx\n", val); } -static ssize_t ctxid_val_store(struct device *dev, +static ssize_t ctxid_pid_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { @@ -1412,12 +1412,12 @@ static ssize_t ctxid_val_store(struct device *dev, return ret; spin_lock(&drvdata->spinlock); - drvdata->ctxid_val[drvdata->ctxid_idx] = val; + drvdata->ctxid_pid[drvdata->ctxid_idx] = val; spin_unlock(&drvdata->spinlock); return size; } -static DEVICE_ATTR_RW(ctxid_val); +static DEVICE_ATTR_RW(ctxid_pid); static ssize_t ctxid_mask_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1609,7 +1609,7 @@ static struct attribute *coresight_etm_attrs[] = { &dev_attr_seq_13_event.attr, &dev_attr_seq_curr_state.attr, &dev_attr_ctxid_idx.attr, - &dev_attr_ctxid_val.attr, + &dev_attr_ctxid_pid.attr, &dev_attr_ctxid_mask.attr, &dev_attr_sync_freq.attr, &dev_attr_timestamp_event.attr, -- cgit v1.3-6-gb490 From cd196ac3fa5a574f3ddf37b66fbe8c58225c3355 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 31 Jul 2015 09:37:25 -0600 Subject: coresight-etm4x: Change the name of the ctxid_val to ctxid_pid 'ctxid_val' array was used to store the value of ETM context ID comparator which actually stores the process ID to be traced, so using 'ctxid_pid' as its name instead make it easier to understand. This patch also changes the ABI, it is normally not allowed, but fortunately it is a testing ABI and very new for now. Nevertheless, if you don't think it should be changed, we could always add an alias for userspace. Signed-off-by: Chunyan Zhang Reviewed-by: Mark Brown Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- .../ABI/testing/sysfs-bus-coresight-devices-etm4x | 2 +- drivers/hwtracing/coresight/coresight-etm4x.c | 20 ++++++++++---------- drivers/hwtracing/coresight/coresight-etm4x.h | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x index 2fe2e3dae487..2355ed8ae31f 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-etm4x @@ -249,7 +249,7 @@ KernelVersion: 4.01 Contact: Mathieu Poirier Description: (RW) Select which context ID comparator to work with. -What: /sys/bus/coresight/devices/.etm/ctxid_val +What: /sys/bus/coresight/devices/.etm/ctxid_pid Date: April 2015 KernelVersion: 4.01 Contact: Mathieu Poirier diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index 1312e993c501..9afbda54b013 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -155,7 +155,7 @@ static void etm4_enable_hw(void *info) drvdata->base + TRCACATRn(i)); } for (i = 0; i < drvdata->numcidc; i++) - writeq_relaxed(drvdata->ctxid_val[i], + writeq_relaxed(drvdata->ctxid_pid[i], drvdata->base + TRCCIDCVRn(i)); writel_relaxed(drvdata->ctxid_mask0, drvdata->base + TRCCIDCCTLR0); writel_relaxed(drvdata->ctxid_mask1, drvdata->base + TRCCIDCCTLR1); @@ -507,7 +507,7 @@ static ssize_t reset_store(struct device *dev, drvdata->ctxid_idx = 0x0; for (i = 0; i < drvdata->numcidc; i++) - drvdata->ctxid_val[i] = 0x0; + drvdata->ctxid_pid[i] = 0x0; drvdata->ctxid_mask0 = 0x0; drvdata->ctxid_mask1 = 0x0; @@ -1815,7 +1815,7 @@ static ssize_t ctxid_idx_store(struct device *dev, } static DEVICE_ATTR_RW(ctxid_idx); -static ssize_t ctxid_val_show(struct device *dev, +static ssize_t ctxid_pid_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1825,12 +1825,12 @@ static ssize_t ctxid_val_show(struct device *dev, spin_lock(&drvdata->spinlock); idx = drvdata->ctxid_idx; - val = (unsigned long)drvdata->ctxid_val[idx]; + val = (unsigned long)drvdata->ctxid_pid[idx]; spin_unlock(&drvdata->spinlock); return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); } -static ssize_t ctxid_val_store(struct device *dev, +static ssize_t ctxid_pid_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { @@ -1850,11 +1850,11 @@ static ssize_t ctxid_val_store(struct device *dev, spin_lock(&drvdata->spinlock); idx = drvdata->ctxid_idx; - drvdata->ctxid_val[idx] = (u64)val; + drvdata->ctxid_pid[idx] = (u64)val; spin_unlock(&drvdata->spinlock); return size; } -static DEVICE_ATTR_RW(ctxid_val); +static DEVICE_ATTR_RW(ctxid_pid); static ssize_t ctxid_masks_show(struct device *dev, struct device_attribute *attr, @@ -1949,7 +1949,7 @@ static ssize_t ctxid_masks_store(struct device *dev, */ for (j = 0; j < 8; j++) { if (maskbyte & 1) - drvdata->ctxid_val[i] &= ~(0xFF << (j * 8)); + drvdata->ctxid_pid[i] &= ~(0xFF << (j * 8)); maskbyte >>= 1; } /* Select the next ctxid comparator mask value */ @@ -2193,7 +2193,7 @@ static struct attribute *coresight_etmv4_attrs[] = { &dev_attr_res_idx.attr, &dev_attr_res_ctrl.attr, &dev_attr_ctxid_idx.attr, - &dev_attr_ctxid_val.attr, + &dev_attr_ctxid_pid.attr, &dev_attr_ctxid_masks.attr, &dev_attr_vmid_idx.attr, &dev_attr_vmid_val.attr, @@ -2514,7 +2514,7 @@ static void etm4_init_default_data(struct etmv4_drvdata *drvdata) } for (i = 0; i < drvdata->numcidc; i++) - drvdata->ctxid_val[i] = 0x0; + drvdata->ctxid_pid[i] = 0x0; drvdata->ctxid_mask0 = 0x0; drvdata->ctxid_mask1 = 0x0; diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index e08e983dd2d9..1e8fb369daaf 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -265,7 +265,7 @@ * @addr_type: Current status of the comparator register. * @ctxid_idx: Context ID index selector. * @ctxid_size: Size of the context ID field to consider. - * @ctxid_val: Value of the context ID comparator. + * @ctxid_pid: Value of the context ID comparator. * @ctxid_mask0:Context ID comparator mask for comparator 0-3. * @ctxid_mask1:Context ID comparator mask for comparator 4-7. * @vmid_idx: VM ID index selector. @@ -352,7 +352,7 @@ struct etmv4_drvdata { u8 addr_type[ETM_MAX_SINGLE_ADDR_CMP]; u8 ctxid_idx; u8 ctxid_size; - u64 ctxid_val[ETMv4_MAX_CTXID_CMP]; + u64 ctxid_pid[ETMv4_MAX_CTXID_CMP]; u32 ctxid_mask0; u32 ctxid_mask1; u8 vmid_idx; -- cgit v1.3-6-gb490 From a440617e0d882a35accdd32dd7ae180885c6b28c Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 31 Jul 2015 09:37:27 -0600 Subject: coresight-etm3x: Support context-ID tracing when PID namespace is enabled The Coresight ETM drivers already support context-ID tracing, but it won't work when PID namespace is enabled. This is because when using PID namespace a process id (ie. VPID) seen from the current namespace differs from the id (ie. PID) seen by kernel. So when users write the process id seen by themselves to ETM, there needs to be a translation from VPID to PID, as such ETM drivers will write the PID into the Context ID register correctly. Signed-off-by: Chunyan Zhang Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm.h | 3 +++ drivers/hwtracing/coresight/coresight-etm3x.c | 16 +++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h index 52af5f0adbed..b4481eb29304 100644 --- a/drivers/hwtracing/coresight/coresight-etm.h +++ b/drivers/hwtracing/coresight/coresight-etm.h @@ -184,6 +184,8 @@ * @seq_curr_state: current value of the sequencer register. * @ctxid_idx: index for the context ID registers. * @ctxid_pid: value for the context ID to trigger on. + * @ctxid_vpid: Virtual PID seen by users if PID namespace is enabled, otherwise + * the same value of ctxid_pid. * @ctxid_mask: mask applicable to all the context IDs. * @sync_freq: Synchronisation frequency. * @timestamp_event: Defines an event that requests the insertion @@ -236,6 +238,7 @@ struct etm_drvdata { u32 seq_curr_state; u8 ctxid_idx; u32 ctxid_pid[ETM_MAX_CTXID_CMP]; + u32 ctxid_vpid[ETM_MAX_CTXID_CMP]; u32 ctxid_mask; u32 sync_freq; u32 timestamp_event; diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index 361b82068dda..bf2476ed9356 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c @@ -237,8 +237,11 @@ static void etm_set_default(struct etm_drvdata *drvdata) drvdata->seq_curr_state = 0x0; drvdata->ctxid_idx = 0x0; - for (i = 0; i < drvdata->nr_ctxid_cmp; i++) + for (i = 0; i < drvdata->nr_ctxid_cmp; i++) { drvdata->ctxid_pid[i] = 0x0; + drvdata->ctxid_vpid[i] = 0x0; + } + drvdata->ctxid_mask = 0x0; } @@ -1393,7 +1396,7 @@ static ssize_t ctxid_pid_show(struct device *dev, struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); spin_lock(&drvdata->spinlock); - val = drvdata->ctxid_pid[drvdata->ctxid_idx]; + val = drvdata->ctxid_vpid[drvdata->ctxid_idx]; spin_unlock(&drvdata->spinlock); return sprintf(buf, "%#lx\n", val); @@ -1404,15 +1407,18 @@ static ssize_t ctxid_pid_store(struct device *dev, const char *buf, size_t size) { int ret; - unsigned long val; + unsigned long vpid, pid; struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent); - ret = kstrtoul(buf, 16, &val); + ret = kstrtoul(buf, 16, &vpid); if (ret) return ret; + pid = coresight_vpid_to_pid(vpid); + spin_lock(&drvdata->spinlock); - drvdata->ctxid_pid[drvdata->ctxid_idx] = val; + drvdata->ctxid_pid[drvdata->ctxid_idx] = pid; + drvdata->ctxid_vpid[drvdata->ctxid_idx] = vpid; spin_unlock(&drvdata->spinlock); return size; -- cgit v1.3-6-gb490 From f67b467aab10685f695190d2f471221e7a314374 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 31 Jul 2015 09:37:28 -0600 Subject: coresight-etm4x: Support context-ID tracing when PID namespace is enabled Like ETTv3, ETMv4 also needs the similar modifications to support Context ID tracing when PID namespace is enabled. Signed-off-by: Chunyan Zhang Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm4x.c | 21 +++++++++++++++------ drivers/hwtracing/coresight/coresight-etm4x.h | 3 +++ 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index 9afbda54b013..254a81a4e6f4 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -506,8 +506,11 @@ static ssize_t reset_store(struct device *dev, } drvdata->ctxid_idx = 0x0; - for (i = 0; i < drvdata->numcidc; i++) + for (i = 0; i < drvdata->numcidc; i++) { drvdata->ctxid_pid[i] = 0x0; + drvdata->ctxid_vpid[i] = 0x0; + } + drvdata->ctxid_mask0 = 0x0; drvdata->ctxid_mask1 = 0x0; @@ -1825,7 +1828,7 @@ static ssize_t ctxid_pid_show(struct device *dev, spin_lock(&drvdata->spinlock); idx = drvdata->ctxid_idx; - val = (unsigned long)drvdata->ctxid_pid[idx]; + val = (unsigned long)drvdata->ctxid_vpid[idx]; spin_unlock(&drvdata->spinlock); return scnprintf(buf, PAGE_SIZE, "%#lx\n", val); } @@ -1835,7 +1838,7 @@ static ssize_t ctxid_pid_store(struct device *dev, const char *buf, size_t size) { u8 idx; - unsigned long val; + unsigned long vpid, pid; struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent); /* @@ -1845,12 +1848,15 @@ static ssize_t ctxid_pid_store(struct device *dev, */ if (!drvdata->ctxid_size || !drvdata->numcidc) return -EINVAL; - if (kstrtoul(buf, 16, &val)) + if (kstrtoul(buf, 16, &vpid)) return -EINVAL; + pid = coresight_vpid_to_pid(vpid); + spin_lock(&drvdata->spinlock); idx = drvdata->ctxid_idx; - drvdata->ctxid_pid[idx] = (u64)val; + drvdata->ctxid_pid[idx] = (u64)pid; + drvdata->ctxid_vpid[idx] = (u64)vpid; spin_unlock(&drvdata->spinlock); return size; } @@ -2513,8 +2519,11 @@ static void etm4_init_default_data(struct etmv4_drvdata *drvdata) drvdata->addr_type[1] = ETM_ADDR_TYPE_RANGE; } - for (i = 0; i < drvdata->numcidc; i++) + for (i = 0; i < drvdata->numcidc; i++) { drvdata->ctxid_pid[i] = 0x0; + drvdata->ctxid_vpid[i] = 0x0; + } + drvdata->ctxid_mask0 = 0x0; drvdata->ctxid_mask1 = 0x0; diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h index 1e8fb369daaf..c34100205ca9 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.h +++ b/drivers/hwtracing/coresight/coresight-etm4x.h @@ -266,6 +266,8 @@ * @ctxid_idx: Context ID index selector. * @ctxid_size: Size of the context ID field to consider. * @ctxid_pid: Value of the context ID comparator. + * @ctxid_vpid: Virtual PID seen by users if PID namespace is enabled, otherwise + * the same value of ctxid_pid. * @ctxid_mask0:Context ID comparator mask for comparator 0-3. * @ctxid_mask1:Context ID comparator mask for comparator 4-7. * @vmid_idx: VM ID index selector. @@ -353,6 +355,7 @@ struct etmv4_drvdata { u8 ctxid_idx; u8 ctxid_size; u64 ctxid_pid[ETMv4_MAX_CTXID_CMP]; + u64 ctxid_vpid[ETMv4_MAX_CTXID_CMP]; u32 ctxid_mask0; u32 ctxid_mask1; u8 vmid_idx; -- cgit v1.3-6-gb490 From d25ded8d3c6ecc3043763d4330c964603dc61bd4 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Fri, 3 Jul 2015 13:35:36 +1000 Subject: char/nvram: Use bitwise OR to obtain Atari video mode data Signed-off-by: Finn Thain Acked-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/char/nvram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 9df78e2cc45d..97c2d8d433d6 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -702,7 +702,7 @@ static void atari_proc_infos(unsigned char *nvram, struct seq_file *seq, seq_printf(seq, "%ds%s\n", nvram[10], nvram[10] < 8 ? ", no memory test" : ""); - vmode = (nvram[14] << 8) || nvram[15]; + vmode = (nvram[14] << 8) | nvram[15]; seq_printf(seq, "Video mode : %s colors, %d columns, %s %s monitor\n", colors[vmode & 7], -- cgit v1.3-6-gb490 From bab383de3b84e584b0f09227151020b2a43dc34c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 20 Jul 2015 17:27:21 +0530 Subject: auxdisplay: ks0108: fix refcount parport_find_base() will implicitly do parport_get_port() which increases the refcount. Then parport_register_device() will again increment the refcount. But while unloading the module we are only doing parport_unregister_device() decrementing the refcount only once. We add an parport_put_port() to neutralize the effect of parport_get_port(). Cc: # 2.6.32+ Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/auxdisplay/ks0108.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c index 5b93852392b8..0d752851a1ee 100644 --- a/drivers/auxdisplay/ks0108.c +++ b/drivers/auxdisplay/ks0108.c @@ -139,6 +139,7 @@ static int __init ks0108_init(void) ks0108_pardevice = parport_register_device(ks0108_parport, KS0108_NAME, NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); + parport_put_port(ks0108_parport); if (ks0108_pardevice == NULL) { printk(KERN_ERR KS0108_NAME ": ERROR: " "parport didn't register new device\n"); -- cgit v1.3-6-gb490 From 7faad1dfbbe008fe564d94c1b154695fcc13d748 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 20 Jul 2015 17:27:22 +0530 Subject: auxdisplay: ks0108: start using pr_* Start using pr_* macros instead of using printk and in the process define pr_fmt. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/auxdisplay/ks0108.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c index 0d752851a1ee..30d6d0e4d766 100644 --- a/drivers/auxdisplay/ks0108.c +++ b/drivers/auxdisplay/ks0108.c @@ -23,6 +23,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -132,8 +134,7 @@ static int __init ks0108_init(void) ks0108_parport = parport_find_base(ks0108_port); if (ks0108_parport == NULL) { - printk(KERN_ERR KS0108_NAME ": ERROR: " - "parport didn't find %i port\n", ks0108_port); + pr_err("ERROR: parport didn't find %i port\n", ks0108_port); goto none; } @@ -141,15 +142,14 @@ static int __init ks0108_init(void) NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); parport_put_port(ks0108_parport); if (ks0108_pardevice == NULL) { - printk(KERN_ERR KS0108_NAME ": ERROR: " - "parport didn't register new device\n"); + pr_err("ERROR: parport didn't register new device\n"); goto none; } result = parport_claim(ks0108_pardevice); if (result != 0) { - printk(KERN_ERR KS0108_NAME ": ERROR: " - "can't claim %i parport, maybe in use\n", ks0108_port); + pr_err("ERROR: can't claim %i parport, maybe in use\n", + ks0108_port); ret = result; goto registered; } -- cgit v1.3-6-gb490 From c9efdbe63410984668a4983cc46e31a7b3f0c74e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 20 Jul 2015 17:27:23 +0530 Subject: auxdisplay: ks0108: use min_t Using min_t() is preffered than using min(). Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/auxdisplay/ks0108.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c index 30d6d0e4d766..ce00e95040bf 100644 --- a/drivers/auxdisplay/ks0108.c +++ b/drivers/auxdisplay/ks0108.c @@ -92,17 +92,19 @@ void ks0108_displaystate(unsigned char state) void ks0108_startline(unsigned char startline) { - ks0108_writedata(min(startline,(unsigned char)63) | bit(6) | bit(7)); + ks0108_writedata(min_t(unsigned char, startline, 63) | bit(6) | + bit(7)); } void ks0108_address(unsigned char address) { - ks0108_writedata(min(address,(unsigned char)63) | bit(6)); + ks0108_writedata(min_t(unsigned char, address, 63) | bit(6)); } void ks0108_page(unsigned char page) { - ks0108_writedata(min(page,(unsigned char)7) | bit(3) | bit(4) | bit(5) | bit(7)); + ks0108_writedata(min_t(unsigned char, page, 7) | bit(3) | bit(4) | + bit(5) | bit(7)); } EXPORT_SYMBOL_GPL(ks0108_writedata); -- cgit v1.3-6-gb490 From 4edd70c133f3921c594883d8f9da31a7261f8b4f Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Mon, 20 Jul 2015 17:27:24 +0530 Subject: auxdisplay: ks0108: use new parport device model Modify auxdisplay driver to use the new parallel port device model. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/auxdisplay/ks0108.c | 76 ++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c index ce00e95040bf..4c471bd8c2f7 100644 --- a/drivers/auxdisplay/ks0108.c +++ b/drivers/auxdisplay/ks0108.c @@ -125,51 +125,69 @@ unsigned char ks0108_isinited(void) } EXPORT_SYMBOL_GPL(ks0108_isinited); -/* - * Module Init & Exit - */ - -static int __init ks0108_init(void) +static void ks0108_parport_attach(struct parport *port) { - int result; - int ret = -EINVAL; + struct pardev_cb ks0108_cb; - ks0108_parport = parport_find_base(ks0108_port); - if (ks0108_parport == NULL) { - pr_err("ERROR: parport didn't find %i port\n", ks0108_port); - goto none; - } + if (port->base != ks0108_port) + return; - ks0108_pardevice = parport_register_device(ks0108_parport, KS0108_NAME, - NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - parport_put_port(ks0108_parport); - if (ks0108_pardevice == NULL) { + memset(&ks0108_cb, 0, sizeof(ks0108_cb)); + ks0108_cb.flags = PARPORT_DEV_EXCL; + ks0108_pardevice = parport_register_dev_model(port, KS0108_NAME, + &ks0108_cb, 0); + if (!ks0108_pardevice) { pr_err("ERROR: parport didn't register new device\n"); - goto none; + return; } - - result = parport_claim(ks0108_pardevice); - if (result != 0) { - pr_err("ERROR: can't claim %i parport, maybe in use\n", + if (parport_claim(ks0108_pardevice)) { + pr_err("could not claim access to parport %i. Aborting.\n", ks0108_port); - ret = result; - goto registered; + goto err_unreg_device; } ks0108_inited = 1; - return 0; + return; -registered: +err_unreg_device: parport_unregister_device(ks0108_pardevice); - -none: - return ret; + ks0108_pardevice = NULL; } -static void __exit ks0108_exit(void) +static void ks0108_parport_detach(struct parport *port) { + if (port->base != ks0108_port) + return; + + if (!ks0108_pardevice) { + pr_err("%s: already unregistered.\n", KS0108_NAME); + return; + } + parport_release(ks0108_pardevice); parport_unregister_device(ks0108_pardevice); + ks0108_pardevice = NULL; +} + +/* + * Module Init & Exit + */ + +static struct parport_driver ks0108_parport_driver = { + .name = "ks0108", + .match_port = ks0108_parport_attach, + .detach = ks0108_parport_detach, + .devmodel = true, +}; + +static int __init ks0108_init(void) +{ + return parport_register_driver(&ks0108_parport_driver); +} + +static void __exit ks0108_exit(void) +{ + parport_unregister_driver(&ks0108_parport_driver); } module_init(ks0108_init); -- cgit v1.3-6-gb490 From eace75cfdcf7d9937d8c1fb226780123c64d72c4 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Jul 2015 12:13:19 +0100 Subject: nvmem: Add a simple NVMEM framework for nvmem providers This patch adds just providers part of the framework just to enable easy review. Up until now, NVMEM drivers like eeprom were stored in drivers/misc, where they all had to duplicate pretty much the same code to register a sysfs file, allow in-kernel users to access the content of the devices they were driving, etc. This was also a problem as far as other in-kernel users were involved, since the solutions used were pretty much different from on driver to another, there was a rather big abstraction leak. This introduction of this framework aims at solving this. It also introduces DT representation for consumer devices to go get the data they require (MAC Addresses, SoC/Revision ID, part numbers, and so on) from the nvmems. Having regmap interface to this framework would give much better abstraction for nvmems on different buses. Signed-off-by: Maxime Ripard [Maxime Ripard: intial version of eeprom framework] Signed-off-by: Srinivas Kandagatla Tested-by: Stefan Wahren Tested-by: Philipp Zabel Tested-by: Rajendra Nayak Signed-off-by: Greg Kroah-Hartman --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/nvmem/Kconfig | 13 ++ drivers/nvmem/Makefile | 6 + drivers/nvmem/core.c | 406 +++++++++++++++++++++++++++++++++++++++++ include/linux/nvmem-consumer.h | 23 +++ include/linux/nvmem-provider.h | 47 +++++ 7 files changed, 498 insertions(+) create mode 100644 drivers/nvmem/Kconfig create mode 100644 drivers/nvmem/Makefile create mode 100644 drivers/nvmem/core.c create mode 100644 include/linux/nvmem-consumer.h create mode 100644 include/linux/nvmem-provider.h (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index 6e973b8e3a3b..4e2e6aaf0b88 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -184,4 +184,6 @@ source "drivers/android/Kconfig" source "drivers/nvdimm/Kconfig" +source "drivers/nvmem/Kconfig" + endmenu diff --git a/drivers/Makefile b/drivers/Makefile index b64b49f6e01b..4c270f5414f0 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -165,3 +165,4 @@ obj-$(CONFIG_RAS) += ras/ obj-$(CONFIG_THUNDERBOLT) += thunderbolt/ obj-$(CONFIG_CORESIGHT) += hwtracing/coresight/ obj-$(CONFIG_ANDROID) += android/ +obj-$(CONFIG_NVMEM) += nvmem/ diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig new file mode 100644 index 000000000000..de90c82d891b --- /dev/null +++ b/drivers/nvmem/Kconfig @@ -0,0 +1,13 @@ +menuconfig NVMEM + tristate "NVMEM Support" + select REGMAP + help + Support for NVMEM(Non Volatile Memory) devices like EEPROM, EFUSES... + + This framework is designed to provide a generic interface to NVMEM + from both the Linux Kernel and the userspace. + + This driver can also be built as a module. If so, the module + will be called nvmem_core. + + If unsure, say no. diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile new file mode 100644 index 000000000000..6df2c6952ad5 --- /dev/null +++ b/drivers/nvmem/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for nvmem drivers. +# + +obj-$(CONFIG_NVMEM) += nvmem_core.o +nvmem_core-y := core.o diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c new file mode 100644 index 000000000000..2b024915e224 --- /dev/null +++ b/drivers/nvmem/core.c @@ -0,0 +1,406 @@ +/* + * nvmem framework core. + * + * Copyright (C) 2015 Srinivas Kandagatla + * Copyright (C) 2013 Maxime Ripard + * + * 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 + * only 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 +#include +#include +#include +#include +#include + +struct nvmem_device { + const char *name; + struct regmap *regmap; + struct module *owner; + struct device dev; + int stride; + int word_size; + int ncells; + int id; + int users; + size_t size; + bool read_only; +}; + +struct nvmem_cell { + const char *name; + int offset; + int bytes; + int bit_offset; + int nbits; + struct nvmem_device *nvmem; + struct list_head node; +}; + +static DEFINE_MUTEX(nvmem_mutex); +static DEFINE_IDA(nvmem_ida); + +static LIST_HEAD(nvmem_cells); +static DEFINE_MUTEX(nvmem_cells_mutex); + +#define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) + +static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t pos, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nvmem_device *nvmem = to_nvmem_device(dev); + int rc; + + /* Stop the user from reading */ + if (pos > nvmem->size) + return 0; + + if (pos + count > nvmem->size) + count = nvmem->size - pos; + + count = round_down(count, nvmem->word_size); + + rc = regmap_raw_read(nvmem->regmap, pos, buf, count); + + if (IS_ERR_VALUE(rc)) + return rc; + + return count; +} + +static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t pos, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct nvmem_device *nvmem = to_nvmem_device(dev); + int rc; + + /* Stop the user from writing */ + if (pos > nvmem->size) + return 0; + + if (pos + count > nvmem->size) + count = nvmem->size - pos; + + count = round_down(count, nvmem->word_size); + + rc = regmap_raw_write(nvmem->regmap, pos, buf, count); + + if (IS_ERR_VALUE(rc)) + return rc; + + return count; +} + +/* default read/write permissions */ +static struct bin_attribute bin_attr_rw_nvmem = { + .attr = { + .name = "nvmem", + .mode = S_IWUSR | S_IRUGO, + }, + .read = bin_attr_nvmem_read, + .write = bin_attr_nvmem_write, +}; + +static struct bin_attribute *nvmem_bin_rw_attributes[] = { + &bin_attr_rw_nvmem, + NULL, +}; + +static const struct attribute_group nvmem_bin_rw_group = { + .bin_attrs = nvmem_bin_rw_attributes, +}; + +static const struct attribute_group *nvmem_rw_dev_groups[] = { + &nvmem_bin_rw_group, + NULL, +}; + +/* read only permission */ +static struct bin_attribute bin_attr_ro_nvmem = { + .attr = { + .name = "nvmem", + .mode = S_IRUGO, + }, + .read = bin_attr_nvmem_read, +}; + +static struct bin_attribute *nvmem_bin_ro_attributes[] = { + &bin_attr_ro_nvmem, + NULL, +}; + +static const struct attribute_group nvmem_bin_ro_group = { + .bin_attrs = nvmem_bin_ro_attributes, +}; + +static const struct attribute_group *nvmem_ro_dev_groups[] = { + &nvmem_bin_ro_group, + NULL, +}; + +static void nvmem_release(struct device *dev) +{ + struct nvmem_device *nvmem = to_nvmem_device(dev); + + ida_simple_remove(&nvmem_ida, nvmem->id); + kfree(nvmem); +} + +static const struct device_type nvmem_provider_type = { + .release = nvmem_release, +}; + +static struct bus_type nvmem_bus_type = { + .name = "nvmem", +}; + +static int of_nvmem_match(struct device *dev, void *nvmem_np) +{ + return dev->of_node == nvmem_np; +} + +static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np) +{ + struct device *d; + + if (!nvmem_np) + return NULL; + + d = bus_find_device(&nvmem_bus_type, NULL, nvmem_np, of_nvmem_match); + + if (!d) + return NULL; + + return to_nvmem_device(d); +} + +static struct nvmem_cell *nvmem_find_cell(const char *cell_id) +{ + struct nvmem_cell *p; + + list_for_each_entry(p, &nvmem_cells, node) + if (p && !strcmp(p->name, cell_id)) + return p; + + return NULL; +} + +static void nvmem_cell_drop(struct nvmem_cell *cell) +{ + mutex_lock(&nvmem_cells_mutex); + list_del(&cell->node); + mutex_unlock(&nvmem_cells_mutex); + kfree(cell); +} + +static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) +{ + struct nvmem_cell *cell; + struct list_head *p, *n; + + list_for_each_safe(p, n, &nvmem_cells) { + cell = list_entry(p, struct nvmem_cell, node); + if (cell->nvmem == nvmem) + nvmem_cell_drop(cell); + } +} + +static void nvmem_cell_add(struct nvmem_cell *cell) +{ + mutex_lock(&nvmem_cells_mutex); + list_add_tail(&cell->node, &nvmem_cells); + mutex_unlock(&nvmem_cells_mutex); +} + +static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, + const struct nvmem_cell_info *info, + struct nvmem_cell *cell) +{ + cell->nvmem = nvmem; + cell->offset = info->offset; + cell->bytes = info->bytes; + cell->name = info->name; + + cell->bit_offset = info->bit_offset; + cell->nbits = info->nbits; + + if (cell->nbits) + cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, + BITS_PER_BYTE); + + if (!IS_ALIGNED(cell->offset, nvmem->stride)) { + dev_err(&nvmem->dev, + "cell %s unaligned to nvmem stride %d\n", + cell->name, nvmem->stride); + return -EINVAL; + } + + return 0; +} + +static int nvmem_add_cells(struct nvmem_device *nvmem, + const struct nvmem_config *cfg) +{ + struct nvmem_cell **cells; + const struct nvmem_cell_info *info = cfg->cells; + int i, rval; + + cells = kcalloc(cfg->ncells, sizeof(*cells), GFP_KERNEL); + if (!cells) + return -ENOMEM; + + for (i = 0; i < cfg->ncells; i++) { + cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); + if (!cells[i]) { + rval = -ENOMEM; + goto err; + } + + rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); + if (IS_ERR_VALUE(rval)) { + kfree(cells[i]); + goto err; + } + + nvmem_cell_add(cells[i]); + } + + nvmem->ncells = cfg->ncells; + /* remove tmp array */ + kfree(cells); + + return 0; +err: + while (--i) + nvmem_cell_drop(cells[i]); + + return rval; +} + +/** + * nvmem_register() - Register a nvmem device for given nvmem_config. + * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem + * + * @config: nvmem device configuration with which nvmem device is created. + * + * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device + * on success. + */ + +struct nvmem_device *nvmem_register(const struct nvmem_config *config) +{ + struct nvmem_device *nvmem; + struct device_node *np; + struct regmap *rm; + int rval; + + if (!config->dev) + return ERR_PTR(-EINVAL); + + rm = dev_get_regmap(config->dev, NULL); + if (!rm) { + dev_err(config->dev, "Regmap not found\n"); + return ERR_PTR(-EINVAL); + } + + nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL); + if (!nvmem) + return ERR_PTR(-ENOMEM); + + rval = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL); + if (rval < 0) { + kfree(nvmem); + return ERR_PTR(rval); + } + + nvmem->id = rval; + nvmem->regmap = rm; + nvmem->owner = config->owner; + nvmem->stride = regmap_get_reg_stride(rm); + nvmem->word_size = regmap_get_val_bytes(rm); + nvmem->size = regmap_get_max_register(rm) + nvmem->stride; + nvmem->dev.type = &nvmem_provider_type; + nvmem->dev.bus = &nvmem_bus_type; + nvmem->dev.parent = config->dev; + np = config->dev->of_node; + nvmem->dev.of_node = np; + dev_set_name(&nvmem->dev, "%s%d", + config->name ? : "nvmem", config->id); + + nvmem->read_only = of_property_read_bool(np, "read-only") | + config->read_only; + + nvmem->dev.groups = nvmem->read_only ? nvmem_ro_dev_groups : + nvmem_rw_dev_groups; + + device_initialize(&nvmem->dev); + + dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); + + rval = device_add(&nvmem->dev); + if (rval) { + ida_simple_remove(&nvmem_ida, nvmem->id); + kfree(nvmem); + return ERR_PTR(rval); + } + + if (config->cells) + nvmem_add_cells(nvmem, config); + + return nvmem; +} +EXPORT_SYMBOL_GPL(nvmem_register); + +/** + * nvmem_unregister() - Unregister previously registered nvmem device + * + * @nvmem: Pointer to previously registered nvmem device. + * + * Return: Will be an negative on error or a zero on success. + */ +int nvmem_unregister(struct nvmem_device *nvmem) +{ + if (nvmem->users) + return -EBUSY; + + nvmem_device_remove_all_cells(nvmem); + device_del(&nvmem->dev); + + return 0; +} +EXPORT_SYMBOL_GPL(nvmem_unregister); + +static int __init nvmem_init(void) +{ + return bus_register(&nvmem_bus_type); +} + +static void __exit nvmem_exit(void) +{ + bus_unregister(&nvmem_bus_type); +} + +subsys_initcall(nvmem_init); +module_exit(nvmem_exit); + +MODULE_AUTHOR("Srinivas Kandagatla + * Copyright (C) 2013 Maxime Ripard + * + * 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 _LINUX_NVMEM_CONSUMER_H +#define _LINUX_NVMEM_CONSUMER_H + +struct nvmem_cell_info { + const char *name; + unsigned int offset; + unsigned int bytes; + unsigned int bit_offset; + unsigned int nbits; +}; + +#endif /* ifndef _LINUX_NVMEM_CONSUMER_H */ diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h new file mode 100644 index 000000000000..0b68caff1b3c --- /dev/null +++ b/include/linux/nvmem-provider.h @@ -0,0 +1,47 @@ +/* + * nvmem framework provider. + * + * Copyright (C) 2015 Srinivas Kandagatla + * Copyright (C) 2013 Maxime Ripard + * + * 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 _LINUX_NVMEM_PROVIDER_H +#define _LINUX_NVMEM_PROVIDER_H + +struct nvmem_device; +struct nvmem_cell_info; + +struct nvmem_config { + struct device *dev; + const char *name; + int id; + struct module *owner; + const struct nvmem_cell_info *cells; + int ncells; + bool read_only; +}; + +#if IS_ENABLED(CONFIG_NVMEM) + +struct nvmem_device *nvmem_register(const struct nvmem_config *cfg); +int nvmem_unregister(struct nvmem_device *nvmem); + +#else + +static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c) +{ + return ERR_PTR(-ENOSYS); +} + +static inline int nvmem_unregister(struct nvmem_device *nvmem) +{ + return -ENOSYS; +} + +#endif /* CONFIG_NVMEM */ + +#endif /* ifndef _LINUX_NVMEM_PROVIDER_H */ -- cgit v1.3-6-gb490 From 69aba7948cbe53f2f1827e84e9dd0ae470a5072e Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Jul 2015 12:13:34 +0100 Subject: nvmem: Add a simple NVMEM framework for consumers This patch adds just consumers part of the framework just to enable easy review. Up until now, nvmem drivers were stored in drivers/misc, where they all had to duplicate pretty much the same code to register a sysfs file, allow in-kernel users to access the content of the devices they were driving, etc. This was also a problem as far as other in-kernel users were involved, since the solutions used were pretty much different from on driver to another, there was a rather big abstraction leak. This introduction of this framework aims at solving this. It also introduces DT representation for consumer devices to go get the data they require (MAC Addresses, SoC/Revision ID, part numbers, and so on) from the nvmems. Having regmap interface to this framework would give much better abstraction for nvmems on different buses. Signed-off-by: Maxime Ripard [Maxime Ripard: intial version of the framework] Signed-off-by: Srinivas Kandagatla Tested-by: Stefan Wahren Tested-by: Philipp Zabel Tested-by: Rajendra Nayak Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 421 ++++++++++++++++++++++++++++++++++++++++- include/linux/nvmem-consumer.h | 61 ++++++ 2 files changed, 481 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 2b024915e224..8c16ae2e1308 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -377,8 +377,12 @@ EXPORT_SYMBOL_GPL(nvmem_register); */ int nvmem_unregister(struct nvmem_device *nvmem) { - if (nvmem->users) + mutex_lock(&nvmem_mutex); + if (nvmem->users) { + mutex_unlock(&nvmem_mutex); return -EBUSY; + } + mutex_unlock(&nvmem_mutex); nvmem_device_remove_all_cells(nvmem); device_del(&nvmem->dev); @@ -387,6 +391,421 @@ int nvmem_unregister(struct nvmem_device *nvmem) } EXPORT_SYMBOL_GPL(nvmem_unregister); +static struct nvmem_device *__nvmem_device_get(struct device_node *np, + struct nvmem_cell **cellp, + const char *cell_id) +{ + struct nvmem_device *nvmem = NULL; + + mutex_lock(&nvmem_mutex); + + if (np) { + nvmem = of_nvmem_find(np); + if (!nvmem) { + mutex_unlock(&nvmem_mutex); + return ERR_PTR(-EPROBE_DEFER); + } + } else { + struct nvmem_cell *cell = nvmem_find_cell(cell_id); + + if (cell) { + nvmem = cell->nvmem; + *cellp = cell; + } + + if (!nvmem) { + mutex_unlock(&nvmem_mutex); + return ERR_PTR(-ENOENT); + } + } + + nvmem->users++; + mutex_unlock(&nvmem_mutex); + + if (!try_module_get(nvmem->owner)) { + dev_err(&nvmem->dev, + "could not increase module refcount for cell %s\n", + nvmem->name); + + mutex_lock(&nvmem_mutex); + nvmem->users--; + mutex_unlock(&nvmem_mutex); + + return ERR_PTR(-EINVAL); + } + + return nvmem; +} + +static void __nvmem_device_put(struct nvmem_device *nvmem) +{ + module_put(nvmem->owner); + mutex_lock(&nvmem_mutex); + nvmem->users--; + mutex_unlock(&nvmem_mutex); +} + +static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id) +{ + struct nvmem_cell *cell = NULL; + struct nvmem_device *nvmem; + + nvmem = __nvmem_device_get(NULL, &cell, cell_id); + if (IS_ERR(nvmem)) + return ERR_CAST(nvmem); + + return cell; +} + +#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) +/** + * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id + * + * @dev node: Device tree node that uses the nvmem cell + * @id: nvmem cell name from nvmem-cell-names property. + * + * Return: Will be an ERR_PTR() on error or a valid pointer + * to a struct nvmem_cell. The nvmem_cell will be freed by the + * nvmem_cell_put(). + */ +struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, + const char *name) +{ + struct device_node *cell_np, *nvmem_np; + struct nvmem_cell *cell; + struct nvmem_device *nvmem; + const __be32 *addr; + int rval, len, index; + + index = of_property_match_string(np, "nvmem-cell-names", name); + + cell_np = of_parse_phandle(np, "nvmem-cells", index); + if (!cell_np) + return ERR_PTR(-EINVAL); + + nvmem_np = of_get_next_parent(cell_np); + if (!nvmem_np) + return ERR_PTR(-EINVAL); + + nvmem = __nvmem_device_get(nvmem_np, NULL, NULL); + if (IS_ERR(nvmem)) + return ERR_CAST(nvmem); + + addr = of_get_property(cell_np, "reg", &len); + if (!addr || (len < 2 * sizeof(u32))) { + dev_err(&nvmem->dev, "nvmem: invalid reg on %s\n", + cell_np->full_name); + rval = -EINVAL; + goto err_mem; + } + + cell = kzalloc(sizeof(*cell), GFP_KERNEL); + if (!cell) { + rval = -ENOMEM; + goto err_mem; + } + + cell->nvmem = nvmem; + cell->offset = be32_to_cpup(addr++); + cell->bytes = be32_to_cpup(addr); + cell->name = cell_np->name; + + addr = of_get_property(cell_np, "bits", &len); + if (addr && len == (2 * sizeof(u32))) { + cell->bit_offset = be32_to_cpup(addr++); + cell->nbits = be32_to_cpup(addr); + } + + if (cell->nbits) + cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, + BITS_PER_BYTE); + + if (!IS_ALIGNED(cell->offset, nvmem->stride)) { + dev_err(&nvmem->dev, + "cell %s unaligned to nvmem stride %d\n", + cell->name, nvmem->stride); + rval = -EINVAL; + goto err_sanity; + } + + nvmem_cell_add(cell); + + return cell; + +err_sanity: + kfree(cell); + +err_mem: + __nvmem_device_put(nvmem); + + return ERR_PTR(rval); +} +EXPORT_SYMBOL_GPL(of_nvmem_cell_get); +#endif + +/** + * nvmem_cell_get() - Get nvmem cell of device form a given cell name + * + * @dev node: Device tree node that uses the nvmem cell + * @id: nvmem cell name to get. + * + * Return: Will be an ERR_PTR() on error or a valid pointer + * to a struct nvmem_cell. The nvmem_cell will be freed by the + * nvmem_cell_put(). + */ +struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id) +{ + struct nvmem_cell *cell; + + if (dev->of_node) { /* try dt first */ + cell = of_nvmem_cell_get(dev->of_node, cell_id); + if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) + return cell; + } + + return nvmem_cell_get_from_list(cell_id); +} +EXPORT_SYMBOL_GPL(nvmem_cell_get); + +static void devm_nvmem_cell_release(struct device *dev, void *res) +{ + nvmem_cell_put(*(struct nvmem_cell **)res); +} + +/** + * devm_nvmem_cell_get() - Get nvmem cell of device form a given id + * + * @dev node: Device tree node that uses the nvmem cell + * @id: nvmem id in nvmem-names property. + * + * Return: Will be an ERR_PTR() on error or a valid pointer + * to a struct nvmem_cell. The nvmem_cell will be freed by the + * automatically once the device is freed. + */ +struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id) +{ + struct nvmem_cell **ptr, *cell; + + ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + cell = nvmem_cell_get(dev, id); + if (!IS_ERR(cell)) { + *ptr = cell; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return cell; +} +EXPORT_SYMBOL_GPL(devm_nvmem_cell_get); + +static int devm_nvmem_cell_match(struct device *dev, void *res, void *data) +{ + struct nvmem_cell **c = res; + + if (WARN_ON(!c || !*c)) + return 0; + + return *c == data; +} + +/** + * devm_nvmem_cell_put() - Release previously allocated nvmem cell + * from devm_nvmem_cell_get. + * + * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get() + */ +void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell) +{ + int ret; + + ret = devres_release(dev, devm_nvmem_cell_release, + devm_nvmem_cell_match, cell); + + WARN_ON(ret); +} +EXPORT_SYMBOL(devm_nvmem_cell_put); + +/** + * nvmem_cell_put() - Release previously allocated nvmem cell. + * + * @cell: Previously allocated nvmem cell by nvmem_cell_get() + */ +void nvmem_cell_put(struct nvmem_cell *cell) +{ + struct nvmem_device *nvmem = cell->nvmem; + + __nvmem_device_put(nvmem); + nvmem_cell_drop(cell); +} +EXPORT_SYMBOL_GPL(nvmem_cell_put); + +static inline void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, + void *buf) +{ + u8 *p, *b; + int i, bit_offset = cell->bit_offset; + + p = b = buf; + if (bit_offset) { + /* First shift */ + *b++ >>= bit_offset; + + /* setup rest of the bytes if any */ + for (i = 1; i < cell->bytes; i++) { + /* Get bits from next byte and shift them towards msb */ + *p |= *b << (BITS_PER_BYTE - bit_offset); + + p = b; + *b++ >>= bit_offset; + } + + /* result fits in less bytes */ + if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE)) + *p-- = 0; + } + /* clear msb bits if any leftover in the last byte */ + *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0); +} + +static int __nvmem_cell_read(struct nvmem_device *nvmem, + struct nvmem_cell *cell, + void *buf, size_t *len) +{ + int rc; + + rc = regmap_raw_read(nvmem->regmap, cell->offset, buf, cell->bytes); + + if (IS_ERR_VALUE(rc)) + return rc; + + /* shift bits in-place */ + if (cell->bit_offset || cell->bit_offset) + nvmem_shift_read_buffer_in_place(cell, buf); + + *len = cell->bytes; + + return 0; +} + +/** + * nvmem_cell_read() - Read a given nvmem cell + * + * @cell: nvmem cell to be read. + * @len: pointer to length of cell which will be populated on successful read. + * + * Return: ERR_PTR() on error or a valid pointer to a char * buffer on success. + * The buffer should be freed by the consumer with a kfree(). + */ +void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) +{ + struct nvmem_device *nvmem = cell->nvmem; + u8 *buf; + int rc; + + if (!nvmem || !nvmem->regmap) + return ERR_PTR(-EINVAL); + + buf = kzalloc(cell->bytes, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + rc = __nvmem_cell_read(nvmem, cell, buf, len); + if (IS_ERR_VALUE(rc)) { + kfree(buf); + return ERR_PTR(rc); + } + + return buf; +} +EXPORT_SYMBOL_GPL(nvmem_cell_read); + +static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, + u8 *_buf, int len) +{ + struct nvmem_device *nvmem = cell->nvmem; + int i, rc, nbits, bit_offset = cell->bit_offset; + u8 v, *p, *buf, *b, pbyte, pbits; + + nbits = cell->nbits; + buf = kzalloc(cell->bytes, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + memcpy(buf, _buf, len); + p = b = buf; + + if (bit_offset) { + pbyte = *b; + *b <<= bit_offset; + + /* setup the first byte with lsb bits from nvmem */ + rc = regmap_raw_read(nvmem->regmap, cell->offset, &v, 1); + *b++ |= GENMASK(bit_offset - 1, 0) & v; + + /* setup rest of the byte if any */ + for (i = 1; i < cell->bytes; i++) { + /* Get last byte bits and shift them towards lsb */ + pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset); + pbyte = *b; + p = b; + *b <<= bit_offset; + *b++ |= pbits; + } + } + + /* if it's not end on byte boundary */ + if ((nbits + bit_offset) % BITS_PER_BYTE) { + /* setup the last byte with msb bits from nvmem */ + rc = regmap_raw_read(nvmem->regmap, + cell->offset + cell->bytes - 1, &v, 1); + *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v; + + } + + return buf; +} + +/** + * nvmem_cell_write() - Write to a given nvmem cell + * + * @cell: nvmem cell to be written. + * @buf: Buffer to be written. + * @len: length of buffer to be written to nvmem cell. + * + * Return: length of bytes written or negative on failure. + */ +int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) +{ + struct nvmem_device *nvmem = cell->nvmem; + int rc; + + if (!nvmem || !nvmem->regmap || nvmem->read_only || + (cell->bit_offset == 0 && len != cell->bytes)) + return -EINVAL; + + if (cell->bit_offset || cell->nbits) { + buf = nvmem_cell_prepare_write_buffer(cell, buf, len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + } + + rc = regmap_raw_write(nvmem->regmap, cell->offset, buf, cell->bytes); + + /* free the tmp buffer */ + if (cell->bit_offset) + kfree(buf); + + if (IS_ERR_VALUE(rc)) + return rc; + + return len; +} +EXPORT_SYMBOL_GPL(nvmem_cell_write); + static int __init nvmem_init(void) { return bus_register(&nvmem_bus_type); diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index 1e9e7678a501..297cc67b7211 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -12,6 +12,11 @@ #ifndef _LINUX_NVMEM_CONSUMER_H #define _LINUX_NVMEM_CONSUMER_H +struct device; +struct device_node; +/* consumer cookie */ +struct nvmem_cell; + struct nvmem_cell_info { const char *name; unsigned int offset; @@ -20,4 +25,60 @@ struct nvmem_cell_info { unsigned int nbits; }; +#if IS_ENABLED(CONFIG_NVMEM) + +/* Cell based interface */ +struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name); +struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *name); +void nvmem_cell_put(struct nvmem_cell *cell); +void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); +void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len); +int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len); + +#else + +static inline struct nvmem_cell *nvmem_cell_get(struct device *dev, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} + +static inline void devm_nvmem_cell_put(struct device *dev, + struct nvmem_cell *cell) +{ + +} +static inline void nvmem_cell_put(struct nvmem_cell *cell) +{ +} + +static inline char *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) +{ + return ERR_PTR(-ENOSYS); +} + +static inline int nvmem_cell_write(struct nvmem_cell *cell, + const char *buf, size_t len) +{ + return -ENOSYS; +} +#endif /* CONFIG_NVMEM */ + +#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) +struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, + const char *name); +#else +static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} +#endif /* CONFIG_NVMEM && CONFIG_OF */ + #endif /* ifndef _LINUX_NVMEM_CONSUMER_H */ -- cgit v1.3-6-gb490 From e2a5402ec7c6d0442cca370a0097e75750f81398 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Jul 2015 12:13:45 +0100 Subject: nvmem: Add nvmem_device based consumer apis. This patch adds read/write apis which are based on nvmem_device. It is common that the drivers like omap cape manager or qcom cpr driver to access bytes directly at particular offset in the eeprom and not from nvmem cell info in DT. These driver would need to get access to the nvmem directly, which is what these new APIS provide. These wrapper apis would help such users to avoid code duplication in there drivers and also avoid them reading a big eeprom blob and parsing it internally in there driver. Signed-off-by: Srinivas Kandagatla Tested-by: Stefan Wahren Tested-by: Philipp Zabel Tested-by: Rajendra Nayak Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 258 +++++++++++++++++++++++++++++++++++++++++ include/linux/nvmem-consumer.h | 73 ++++++++++++ 2 files changed, 331 insertions(+) (limited to 'drivers') diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 8c16ae2e1308..d3c6676b3c0c 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -445,6 +445,148 @@ static void __nvmem_device_put(struct nvmem_device *nvmem) mutex_unlock(&nvmem_mutex); } +static int nvmem_match(struct device *dev, void *data) +{ + return !strcmp(dev_name(dev), data); +} + +static struct nvmem_device *nvmem_find(const char *name) +{ + struct device *d; + + d = bus_find_device(&nvmem_bus_type, NULL, (void *)name, nvmem_match); + + if (!d) + return NULL; + + return to_nvmem_device(d); +} + +#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) +/** + * of_nvmem_device_get() - Get nvmem device from a given id + * + * @dev node: Device tree node that uses the nvmem device + * @id: nvmem name from nvmem-names property. + * + * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device + * on success. + */ +struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id) +{ + + struct device_node *nvmem_np; + int index; + + index = of_property_match_string(np, "nvmem-names", id); + + nvmem_np = of_parse_phandle(np, "nvmem", index); + if (!nvmem_np) + return ERR_PTR(-EINVAL); + + return __nvmem_device_get(nvmem_np, NULL, NULL); +} +EXPORT_SYMBOL_GPL(of_nvmem_device_get); +#endif + +/** + * nvmem_device_get() - Get nvmem device from a given id + * + * @dev : Device that uses the nvmem device + * @id: nvmem name from nvmem-names property. + * + * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device + * on success. + */ +struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name) +{ + if (dev->of_node) { /* try dt first */ + struct nvmem_device *nvmem; + + nvmem = of_nvmem_device_get(dev->of_node, dev_name); + + if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER) + return nvmem; + + } + + return nvmem_find(dev_name); +} +EXPORT_SYMBOL_GPL(nvmem_device_get); + +static int devm_nvmem_device_match(struct device *dev, void *res, void *data) +{ + struct nvmem_device **nvmem = res; + + if (WARN_ON(!nvmem || !*nvmem)) + return 0; + + return *nvmem == data; +} + +static void devm_nvmem_device_release(struct device *dev, void *res) +{ + nvmem_device_put(*(struct nvmem_device **)res); +} + +/** + * devm_nvmem_device_put() - put alredy got nvmem device + * + * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(), + * that needs to be released. + */ +void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem) +{ + int ret; + + ret = devres_release(dev, devm_nvmem_device_release, + devm_nvmem_device_match, nvmem); + + WARN_ON(ret); +} +EXPORT_SYMBOL_GPL(devm_nvmem_device_put); + +/** + * nvmem_device_put() - put alredy got nvmem device + * + * @nvmem: pointer to nvmem device that needs to be released. + */ +void nvmem_device_put(struct nvmem_device *nvmem) +{ + __nvmem_device_put(nvmem); +} +EXPORT_SYMBOL_GPL(nvmem_device_put); + +/** + * devm_nvmem_device_get() - Get nvmem cell of device form a given id + * + * @dev node: Device tree node that uses the nvmem cell + * @id: nvmem name in nvmems property. + * + * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell + * on success. The nvmem_cell will be freed by the automatically once the + * device is freed. + */ +struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) +{ + struct nvmem_device **ptr, *nvmem; + + ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + nvmem = nvmem_device_get(dev, id); + if (!IS_ERR(nvmem)) { + *ptr = nvmem; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return nvmem; +} +EXPORT_SYMBOL_GPL(devm_nvmem_device_get); + static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id) { struct nvmem_cell *cell = NULL; @@ -806,6 +948,122 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) } EXPORT_SYMBOL_GPL(nvmem_cell_write); +/** + * nvmem_device_cell_read() - Read a given nvmem device and cell + * + * @nvmem: nvmem device to read from. + * @info: nvmem cell info to be read. + * @buf: buffer pointer which will be populated on successful read. + * + * Return: length of successful bytes read on success and negative + * error code on error. + */ +ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, + struct nvmem_cell_info *info, void *buf) +{ + struct nvmem_cell cell; + int rc; + ssize_t len; + + if (!nvmem || !nvmem->regmap) + return -EINVAL; + + rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); + if (IS_ERR_VALUE(rc)) + return rc; + + rc = __nvmem_cell_read(nvmem, &cell, buf, &len); + if (IS_ERR_VALUE(rc)) + return rc; + + return len; +} +EXPORT_SYMBOL_GPL(nvmem_device_cell_read); + +/** + * nvmem_device_cell_write() - Write cell to a given nvmem device + * + * @nvmem: nvmem device to be written to. + * @info: nvmem cell info to be written + * @buf: buffer to be written to cell. + * + * Return: length of bytes written or negative error code on failure. + * */ +int nvmem_device_cell_write(struct nvmem_device *nvmem, + struct nvmem_cell_info *info, void *buf) +{ + struct nvmem_cell cell; + int rc; + + if (!nvmem || !nvmem->regmap) + return -EINVAL; + + rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); + if (IS_ERR_VALUE(rc)) + return rc; + + return nvmem_cell_write(&cell, buf, cell.bytes); +} +EXPORT_SYMBOL_GPL(nvmem_device_cell_write); + +/** + * nvmem_device_read() - Read from a given nvmem device + * + * @nvmem: nvmem device to read from. + * @offset: offset in nvmem device. + * @bytes: number of bytes to read. + * @buf: buffer pointer which will be populated on successful read. + * + * Return: length of successful bytes read on success and negative + * error code on error. + */ +int nvmem_device_read(struct nvmem_device *nvmem, + unsigned int offset, + size_t bytes, void *buf) +{ + int rc; + + if (!nvmem || !nvmem->regmap) + return -EINVAL; + + rc = regmap_raw_read(nvmem->regmap, offset, buf, bytes); + + if (IS_ERR_VALUE(rc)) + return rc; + + return bytes; +} +EXPORT_SYMBOL_GPL(nvmem_device_read); + +/** + * nvmem_device_write() - Write cell to a given nvmem device + * + * @nvmem: nvmem device to be written to. + * @offset: offset in nvmem device. + * @bytes: number of bytes to write. + * @buf: buffer to be written. + * + * Return: length of bytes written or negative error code on failure. + * */ +int nvmem_device_write(struct nvmem_device *nvmem, + unsigned int offset, + size_t bytes, void *buf) +{ + int rc; + + if (!nvmem || !nvmem->regmap) + return -EINVAL; + + rc = regmap_raw_write(nvmem->regmap, offset, buf, bytes); + + if (IS_ERR_VALUE(rc)) + return rc; + + + return bytes; +} +EXPORT_SYMBOL_GPL(nvmem_device_write); + static int __init nvmem_init(void) { return bus_register(&nvmem_bus_type); diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h index 297cc67b7211..9bb77d3ed6e0 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -16,6 +16,7 @@ struct device; struct device_node; /* consumer cookie */ struct nvmem_cell; +struct nvmem_device; struct nvmem_cell_info { const char *name; @@ -35,6 +36,21 @@ void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len); int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len); +/* direct nvmem device read/write interface */ +struct nvmem_device *nvmem_device_get(struct device *dev, const char *name); +struct nvmem_device *devm_nvmem_device_get(struct device *dev, + const char *name); +void nvmem_device_put(struct nvmem_device *nvmem); +void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem); +int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset, + size_t bytes, void *buf); +int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset, + size_t bytes, void *buf); +ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, + struct nvmem_cell_info *info, void *buf); +int nvmem_device_cell_write(struct nvmem_device *nvmem, + struct nvmem_cell_info *info, void *buf); + #else static inline struct nvmem_cell *nvmem_cell_get(struct device *dev, @@ -68,17 +84,74 @@ static inline int nvmem_cell_write(struct nvmem_cell *cell, { return -ENOSYS; } + +static inline struct nvmem_device *nvmem_device_get(struct device *dev, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} + +static inline struct nvmem_device *devm_nvmem_device_get(struct device *dev, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} + +static inline void nvmem_device_put(struct nvmem_device *nvmem) +{ +} + +static inline void devm_nvmem_device_put(struct device *dev, + struct nvmem_device *nvmem) +{ +} + +static inline ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, + struct nvmem_cell_info *info, + void *buf) +{ + return -ENOSYS; +} + +static inline int nvmem_device_cell_write(struct nvmem_device *nvmem, + struct nvmem_cell_info *info, + void *buf) +{ + return -ENOSYS; +} + +static inline int nvmem_device_read(struct nvmem_device *nvmem, + unsigned int offset, size_t bytes, + void *buf) +{ + return -ENOSYS; +} + +static inline int nvmem_device_write(struct nvmem_device *nvmem, + unsigned int offset, size_t bytes, + void *buf) +{ + return -ENOSYS; +} #endif /* CONFIG_NVMEM */ #if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF) struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *name); +struct nvmem_device *of_nvmem_device_get(struct device_node *np, + const char *name); #else static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *name) { return ERR_PTR(-ENOSYS); } + +static inline struct nvmem_device *of_nvmem_device_get(struct device_node *np, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} #endif /* CONFIG_NVMEM && CONFIG_OF */ #endif /* ifndef _LINUX_NVMEM_CONSUMER_H */ -- cgit v1.3-6-gb490 From 4ab11996b489ad65092216315484824ed32018f8 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 27 Jul 2015 12:15:00 +0100 Subject: nvmem: qfprom: Add Qualcomm QFPROM support. This patch adds QFPROM support driver which is used by other drivers like thermal sensor and cpufreq. On MSM parts there are some efuses (called qfprom) these fuses store things like calibration data, speed bins.. etc. Drivers like cpufreq, thermal sensors would read out this data for configuring the driver. Signed-off-by: Srinivas Kandagatla Reviewed-by: Stephen Boyd Tested-by: Philipp Zabel Tested-by: Rajendra Nayak Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/Kconfig | 15 +++++++++ drivers/nvmem/Makefile | 4 +++ drivers/nvmem/qfprom.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 drivers/nvmem/qfprom.c (limited to 'drivers') diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index de90c82d891b..fa85805bbdb7 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -11,3 +11,18 @@ menuconfig NVMEM will be called nvmem_core. If unsure, say no. + +if NVMEM + +config QCOM_QFPROM + tristate "QCOM QFPROM Support" + depends on ARCH_QCOM || COMPILE_TEST + select REGMAP_MMIO + help + Say y here to enable QFPROM support. The QFPROM provides access + functions for QFPROM data to rest of the drivers via nvmem interface. + + This driver can also be built as a module. If so, the module + will be called nvmem_qfprom. + +endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 6df2c6952ad5..ff44fe99c7d2 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -4,3 +4,7 @@ obj-$(CONFIG_NVMEM) += nvmem_core.o nvmem_core-y := core.o + +# Devices +obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o +nvmem_qfprom-y := qfprom.o diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c new file mode 100644 index 000000000000..afb67e7eeee4 --- /dev/null +++ b/drivers/nvmem/qfprom.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 Srinivas Kandagatla + * + * 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 + * only 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 + +static struct regmap_config qfprom_regmap_config = { + .reg_bits = 32, + .val_bits = 8, + .reg_stride = 1, +}; + +static struct nvmem_config econfig = { + .name = "qfprom", + .owner = THIS_MODULE, +}; + +static int qfprom_remove(struct platform_device *pdev) +{ + struct nvmem_device *nvmem = platform_get_drvdata(pdev); + + return nvmem_unregister(nvmem); +} + +static int qfprom_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct nvmem_device *nvmem; + struct regmap *regmap; + void __iomem *base; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + qfprom_regmap_config.max_register = resource_size(res) - 1; + + regmap = devm_regmap_init_mmio(dev, base, &qfprom_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(regmap); + } + econfig.dev = dev; + nvmem = nvmem_register(&econfig); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); + + platform_set_drvdata(pdev, nvmem); + + return 0; +} + +static const struct of_device_id qfprom_of_match[] = { + { .compatible = "qcom,qfprom",}, + {/* sentinel */}, +}; +MODULE_DEVICE_TABLE(of, qfprom_of_match); + +static struct platform_driver qfprom_driver = { + .probe = qfprom_probe, + .remove = qfprom_remove, + .driver = { + .name = "qcom,qfprom", + .of_match_table = qfprom_of_match, + }, +}; +module_platform_driver(qfprom_driver); +MODULE_AUTHOR("Srinivas Kandagatla "); +MODULE_DESCRIPTION("Qualcomm QFPROM driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.3-6-gb490 From 3d0b16a66c8a9d10294572c6f79df4f15a27825d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 27 Jul 2015 12:17:09 +0100 Subject: nvmem: sunxi: Move the SID driver to the nvmem framework Now that we have the nvmem framework, we can consolidate the common driver code. Move the driver to the framework, and hopefully, it will fix the sysfs file creation race. Signed-off-by: Maxime Ripard [srinivas.kandagatla: Moved to regmap based EEPROM framework] Signed-off-by: Srinivas Kandagatla Tested-by: Philipp Zabel Tested-by: Rajendra Nayak Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-driver-sunxi-sid | 22 --- .../bindings/misc/allwinner,sunxi-sid.txt | 17 -- .../bindings/nvmem/allwinner,sunxi-sid.txt | 21 +++ drivers/misc/eeprom/Kconfig | 13 -- drivers/misc/eeprom/Makefile | 1 - drivers/misc/eeprom/sunxi_sid.c | 156 ------------------- drivers/nvmem/Kconfig | 11 ++ drivers/nvmem/Makefile | 2 + drivers/nvmem/sunxi_sid.c | 171 +++++++++++++++++++++ 9 files changed, 205 insertions(+), 209 deletions(-) delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt create mode 100644 Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt delete mode 100644 drivers/misc/eeprom/sunxi_sid.c create mode 100644 drivers/nvmem/sunxi_sid.c (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid deleted file mode 100644 index ffb9536f6ecc..000000000000 --- a/Documentation/ABI/testing/sysfs-driver-sunxi-sid +++ /dev/null @@ -1,22 +0,0 @@ -What: /sys/devices/*//eeprom -Date: August 2013 -Contact: Oliver Schinagl -Description: read-only access to the SID (Security-ID) on current - A-series SoC's from Allwinner. Currently supports A10, A10s, A13 - and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes, - whereas the newer A20 SoC exposes 512 bytes split into sections. - Besides the 16 bytes of SID, there's also an SJTAG area, - HDMI-HDCP key and some custom keys. Below a quick overview, for - details see the user manual: - 0x000 128 bit root-key (sun[457]i) - 0x010 128 bit boot-key (sun7i) - 0x020 64 bit security-jtag-key (sun7i) - 0x028 16 bit key configuration (sun7i) - 0x02b 16 bit custom-vendor-key (sun7i) - 0x02c 320 bit low general key (sun7i) - 0x040 32 bit read-control access (sun7i) - 0x064 224 bit low general key (sun7i) - 0x080 2304 bit HDCP-key (sun7i) - 0x1a0 768 bit high general key (sun7i) -Users: any user space application which wants to read the SID on - Allwinner's A-series of CPU's. diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt deleted file mode 100644 index fabdf64a5737..000000000000 --- a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt +++ /dev/null @@ -1,17 +0,0 @@ -Allwinner sunxi-sid - -Required properties: -- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid" -- reg: Should contain registers location and length - -Example for sun4i: - sid@01c23800 { - compatible = "allwinner,sun4i-a10-sid"; - reg = <0x01c23800 0x10> - }; - -Example for sun7i: - sid@01c23800 { - compatible = "allwinner,sun7i-a20-sid"; - reg = <0x01c23800 0x200> - }; diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt new file mode 100644 index 000000000000..d543ed3f5363 --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt @@ -0,0 +1,21 @@ +Allwinner sunxi-sid + +Required properties: +- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid" +- reg: Should contain registers location and length + += Data cells = +Are child nodes of qfprom, bindings of which as described in +bindings/nvmem/nvmem.txt + +Example for sun4i: + sid@01c23800 { + compatible = "allwinner,sun4i-a10-sid"; + reg = <0x01c23800 0x10> + }; + +Example for sun7i: + sid@01c23800 { + compatible = "allwinner,sun7i-a20-sid"; + reg = <0x01c23800 0x200> + }; diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 9536852fd4c6..04f2e1fa9dd1 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -96,17 +96,4 @@ config EEPROM_DIGSY_MTC_CFG If unsure, say N. -config EEPROM_SUNXI_SID - tristate "Allwinner sunxi security ID support" - depends on ARCH_SUNXI && SYSFS - help - This is a driver for the 'security ID' available on various Allwinner - devices. - - Due to the potential risks involved with changing e-fuses, - this driver is read-only. - - This driver can also be built as a module. If so, the module - will be called sunxi_sid. - endmenu diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index 9507aec95e94..fc1e81d29267 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile @@ -4,5 +4,4 @@ obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o obj-$(CONFIG_EEPROM_MAX6875) += max6875.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o -obj-$(CONFIG_EEPROM_SUNXI_SID) += sunxi_sid.o obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c deleted file mode 100644 index 8385177ff32b..000000000000 --- a/drivers/misc/eeprom/sunxi_sid.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2013 Oliver Schinagl - * http://www.linux-sunxi.org - * - * 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. - * - * This driver exposes the Allwinner security ID, efuses exported in byte- - * sized chunks. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "sunxi-sid" - -struct sunxi_sid_data { - void __iomem *reg_base; - unsigned int keysize; -}; - -/* We read the entire key, due to a 32 bit read alignment requirement. Since we - * want to return the requested byte, this results in somewhat slower code and - * uses 4 times more reads as needed but keeps code simpler. Since the SID is - * only very rarely probed, this is not really an issue. - */ -static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data, - const unsigned int offset) -{ - u32 sid_key; - - if (offset >= sid_data->keysize) - return 0; - - sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4)); - sid_key >>= (offset % 4) * 8; - - return sid_key; /* Only return the last byte */ -} - -static ssize_t sid_read(struct file *fd, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t pos, size_t size) -{ - struct platform_device *pdev; - struct sunxi_sid_data *sid_data; - int i; - - pdev = to_platform_device(kobj_to_dev(kobj)); - sid_data = platform_get_drvdata(pdev); - - if (pos < 0 || pos >= sid_data->keysize) - return 0; - if (size > sid_data->keysize - pos) - size = sid_data->keysize - pos; - - for (i = 0; i < size; i++) - buf[i] = sunxi_sid_read_byte(sid_data, pos + i); - - return i; -} - -static struct bin_attribute sid_bin_attr = { - .attr = { .name = "eeprom", .mode = S_IRUGO, }, - .read = sid_read, -}; - -static int sunxi_sid_remove(struct platform_device *pdev) -{ - device_remove_bin_file(&pdev->dev, &sid_bin_attr); - dev_dbg(&pdev->dev, "driver unloaded\n"); - - return 0; -} - -static const struct of_device_id sunxi_sid_of_match[] = { - { .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16}, - { .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512}, - {/* sentinel */}, -}; -MODULE_DEVICE_TABLE(of, sunxi_sid_of_match); - -static int sunxi_sid_probe(struct platform_device *pdev) -{ - struct sunxi_sid_data *sid_data; - struct resource *res; - const struct of_device_id *of_dev_id; - u8 *entropy; - unsigned int i; - - sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data), - GFP_KERNEL); - if (!sid_data) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(sid_data->reg_base)) - return PTR_ERR(sid_data->reg_base); - - of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev); - if (!of_dev_id) - return -ENODEV; - sid_data->keysize = (int)of_dev_id->data; - - platform_set_drvdata(pdev, sid_data); - - sid_bin_attr.size = sid_data->keysize; - if (device_create_bin_file(&pdev->dev, &sid_bin_attr)) - return -ENODEV; - - entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL); - for (i = 0; i < sid_data->keysize; i++) - entropy[i] = sunxi_sid_read_byte(sid_data, i); - add_device_randomness(entropy, sid_data->keysize); - kfree(entropy); - - dev_dbg(&pdev->dev, "loaded\n"); - - return 0; -} - -static struct platform_driver sunxi_sid_driver = { - .probe = sunxi_sid_probe, - .remove = sunxi_sid_remove, - .driver = { - .name = DRV_NAME, - .of_match_table = sunxi_sid_of_match, - }, -}; -module_platform_driver(sunxi_sid_driver); - -MODULE_AUTHOR("Oliver Schinagl "); -MODULE_DESCRIPTION("Allwinner sunxi security id driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index fa85805bbdb7..8db297821f78 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -25,4 +25,15 @@ config QCOM_QFPROM This driver can also be built as a module. If so, the module will be called nvmem_qfprom. +config NVMEM_SUNXI_SID + tristate "Allwinner SoCs SID support" + depends on ARCH_SUNXI + select REGMAP_MMIO + help + This is a driver for the 'security ID' available on various Allwinner + devices. + + This driver can also be built as a module. If so, the module + will be called nvmem_sunxi_sid. + endif diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index ff44fe99c7d2..4328b930ad9a 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -8,3 +8,5 @@ nvmem_core-y := core.o # Devices obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o nvmem_qfprom-y := qfprom.o +obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o +nvmem_sunxi_sid-y := sunxi_sid.o diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c new file mode 100644 index 000000000000..14777dd5212d --- /dev/null +++ b/drivers/nvmem/sunxi_sid.c @@ -0,0 +1,171 @@ +/* + * Allwinner sunXi SoCs Security ID support. + * + * Copyright (c) 2013 Oliver Schinagl + * Copyright (C) 2014 Maxime Ripard + * + * 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 +#include +#include +#include +#include +#include + + +static struct nvmem_config econfig = { + .name = "sunxi-sid", + .read_only = true, + .owner = THIS_MODULE, +}; + +struct sunxi_sid { + void __iomem *base; +}; + +/* We read the entire key, due to a 32 bit read alignment requirement. Since we + * want to return the requested byte, this results in somewhat slower code and + * uses 4 times more reads as needed but keeps code simpler. Since the SID is + * only very rarely probed, this is not really an issue. + */ +static u8 sunxi_sid_read_byte(const struct sunxi_sid *sid, + const unsigned int offset) +{ + u32 sid_key; + + sid_key = ioread32be(sid->base + round_down(offset, 4)); + sid_key >>= (offset % 4) * 8; + + return sid_key; /* Only return the last byte */ +} + +static int sunxi_sid_read(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct sunxi_sid *sid = context; + unsigned int offset = *(u32 *)reg; + u8 *buf = val; + + while (val_size) { + *buf++ = sunxi_sid_read_byte(sid, offset); + val_size--; + offset++; + } + + return 0; +} + +static int sunxi_sid_write(void *context, const void *data, size_t count) +{ + /* Unimplemented, dummy to keep regmap core happy */ + return 0; +} + +static struct regmap_bus sunxi_sid_bus = { + .read = sunxi_sid_read, + .write = sunxi_sid_write, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg) +{ + return false; +} + +static struct regmap_config sunxi_sid_regmap_config = { + .reg_bits = 32, + .val_bits = 8, + .reg_stride = 1, + .writeable_reg = sunxi_sid_writeable_reg, +}; + +static int sunxi_sid_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct nvmem_device *nvmem; + struct regmap *regmap; + struct sunxi_sid *sid; + int i, size; + char *randomness; + + sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL); + if (!sid) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sid->base = devm_ioremap_resource(dev, res); + if (IS_ERR(sid->base)) + return PTR_ERR(sid->base); + + size = resource_size(res) - 1; + sunxi_sid_regmap_config.max_register = size; + + regmap = devm_regmap_init(dev, &sunxi_sid_bus, sid, + &sunxi_sid_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(regmap); + } + + econfig.dev = dev; + nvmem = nvmem_register(&econfig); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); + + randomness = kzalloc(sizeof(u8) * size, GFP_KERNEL); + for (i = 0; i < size; i++) + randomness[i] = sunxi_sid_read_byte(sid, i); + + add_device_randomness(randomness, size); + kfree(randomness); + + platform_set_drvdata(pdev, nvmem); + + return 0; +} + +static int sunxi_sid_remove(struct platform_device *pdev) +{ + struct nvmem_device *nvmem = platform_get_drvdata(pdev); + + return nvmem_unregister(nvmem); +} + +static const struct of_device_id sunxi_sid_of_match[] = { + { .compatible = "allwinner,sun4i-a10-sid" }, + { .compatible = "allwinner,sun7i-a20-sid" }, + {/* sentinel */}, +}; +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match); + +static struct platform_driver sunxi_sid_driver = { + .probe = sunxi_sid_probe, + .remove = sunxi_sid_remove, + .driver = { + .name = "eeprom-sunxi-sid", + .of_match_table = sunxi_sid_of_match, + }, +}; +module_platform_driver(sunxi_sid_driver); + +MODULE_AUTHOR("Oliver Schinagl "); +MODULE_DESCRIPTION("Allwinner sunxi security id driver"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 01c48a59bae36f08ba27ed6bfe789aa0d14ee2a1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:38:10 +0900 Subject: w1: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Acked-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman --- drivers/w1/masters/ds2482.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c index a674409edfb3..b05e8fefbabd 100644 --- a/drivers/w1/masters/ds2482.c +++ b/drivers/w1/masters/ds2482.c @@ -97,7 +97,6 @@ MODULE_DEVICE_TABLE(i2c, ds2482_id); static struct i2c_driver ds2482_driver = { .driver = { - .owner = THIS_MODULE, .name = "ds2482", }, .probe = ds2482_probe, -- cgit v1.3-6-gb490 From e7390d7c52684ea338621eb3826a60e33a2bab9d Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Tue, 7 Jul 2015 12:23:49 +0530 Subject: w1: Use module_pci_driver Use module_pci_driver for drivers whose init and exit functions only register and unregister, respectively. A simplified version of the Coccinelle semantic patch that performs this transformation is as follows: @a@ identifier f, x; @@ -static f(...) { return pci_register_driver(&x); } @b depends on a@ identifier e, a.x; @@ -static e(...) { pci_unregister_driver(&x); } @c depends on a && b@ identifier a.f; declarer name module_init; @@ -module_init(f); @d depends on a && b && c@ identifier b.e, a.x; declarer name module_exit; declarer name module_pci_driver; @@ -module_exit(e); +module_pci_driver(x); Signed-off-by: Vaishali Thakkar Acked-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman --- drivers/w1/masters/matrox_w1.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index d8667b0212d7..684bc9d861cb 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c @@ -232,16 +232,4 @@ static void matrox_w1_remove(struct pci_dev *pdev) } kfree(dev); } - -static int __init matrox_w1_init(void) -{ - return pci_register_driver(&matrox_w1_pci_driver); -} - -static void __exit matrox_w1_fini(void) -{ - pci_unregister_driver(&matrox_w1_pci_driver); -} - -module_init(matrox_w1_init); -module_exit(matrox_w1_fini); +module_pci_driver(matrox_w1_pci_driver); -- cgit v1.3-6-gb490 From acb921a5a1e5fb2b864be25caf7317531f91a832 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:18:46 +0300 Subject: misc: cxl: clean up afu_read_config() The sanity checks for overflow are not needed, because this is done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Cc: Ian Munsie Acked-by: Michael Neuling Reviewed-by: Daniel Axtens Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cxl/sysfs.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c index 31f38bc71a3d..87cd747bb511 100644 --- a/drivers/misc/cxl/sysfs.c +++ b/drivers/misc/cxl/sysfs.c @@ -443,12 +443,7 @@ static ssize_t afu_read_config(struct file *filp, struct kobject *kobj, struct afu_config_record *cr = to_cr(kobj); struct cxl_afu *afu = to_cxl_afu(container_of(kobj->parent, struct device, kobj)); - u64 i, j, val, size = afu->crs_len; - - if (off > size) - return 0; - if (off + count > size) - count = size - off; + u64 i, j, val; for (i = 0; i < count;) { val = cxl_afu_cr_read64(afu, cr->cr, off & ~0x7); -- cgit v1.3-6-gb490 From 2b6e5ba3d2ed958f6c32bfc84cdab3377e391f02 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:18:47 +0300 Subject: misc: ds1682: clean up ds1682_eeprom_read() and ds1682_eeprom_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ds1682.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c index b909fb30232a..c7112276a039 100644 --- a/drivers/misc/ds1682.c +++ b/drivers/misc/ds1682.c @@ -148,12 +148,6 @@ static ssize_t ds1682_eeprom_read(struct file *filp, struct kobject *kobj, dev_dbg(&client->dev, "ds1682_eeprom_read(p=%p, off=%lli, c=%zi)\n", buf, off, count); - if (off >= DS1682_EEPROM_SIZE) - return 0; - - if (off + count > DS1682_EEPROM_SIZE) - count = DS1682_EEPROM_SIZE - off; - rc = i2c_smbus_read_i2c_block_data(client, DS1682_REG_EEPROM + off, count, buf); if (rc < 0) @@ -171,12 +165,6 @@ static ssize_t ds1682_eeprom_write(struct file *filp, struct kobject *kobj, dev_dbg(&client->dev, "ds1682_eeprom_write(p=%p, off=%lli, c=%zi)\n", buf, off, count); - if (off >= DS1682_EEPROM_SIZE) - return -ENOSPC; - - if (off + count > DS1682_EEPROM_SIZE) - count = DS1682_EEPROM_SIZE - off; - /* Write out to the device */ if (i2c_smbus_write_i2c_block_data(client, DS1682_REG_EEPROM + off, count, buf) < 0) -- cgit v1.3-6-gb490 From b5da83d4a9c929ac197313b5d6c5d771447fb59e Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:18:48 +0300 Subject: misc: eeprom: 93xx46: clean up eeprom_93xx46_bin_read/write The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom_93xx46.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index 9ebeacdb8ec4..a6bd9e3fe9d3 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -48,13 +48,6 @@ eeprom_93xx46_bin_read(struct file *filp, struct kobject *kobj, dev = container_of(kobj, struct device, kobj); edev = dev_get_drvdata(dev); - if (unlikely(off >= edev->bin.size)) - return 0; - if ((off + count) > edev->bin.size) - count = edev->bin.size - off; - if (unlikely(!count)) - return count; - cmd_addr = OP_READ << edev->addrlen; if (edev->addrlen == 7) { @@ -200,13 +193,6 @@ eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj, dev = container_of(kobj, struct device, kobj); edev = dev_get_drvdata(dev); - if (unlikely(off >= edev->bin.size)) - return -EFBIG; - if ((off + count) > edev->bin.size) - count = edev->bin.size - off; - if (unlikely(!count)) - return count; - /* only write even number of bytes on 16-bit devices */ if (edev->addrlen == 6) { step = 2; -- cgit v1.3-6-gb490 From 79dedbddd0eea471d78ef82eb7c42b8fb1bdef65 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:18:49 +0300 Subject: misc: eeprom: clean up eeprom_read() The change removes redundant sysfs binary file boundary check, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Reviewed-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/eeprom.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/eeprom.c b/drivers/misc/eeprom/eeprom.c index b432873def96..7342fd637031 100644 --- a/drivers/misc/eeprom/eeprom.c +++ b/drivers/misc/eeprom/eeprom.c @@ -88,11 +88,6 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, struct eeprom_data *data = i2c_get_clientdata(client); u8 slice; - if (off > EEPROM_SIZE) - return 0; - if (off + count > EEPROM_SIZE) - count = EEPROM_SIZE - off; - /* Only refresh slices which contain requested bytes */ for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++) eeprom_update_client(client, slice); -- cgit v1.3-6-gb490 From 2664e0386e813158b599a73164f8f7ddb2b0eb6d Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:18:50 +0300 Subject: misc: eeprom: max6875: clean up max6875_read() The change removes redundant sysfs binary file boundary check, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/max6875.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c index 580ff9df5529..9aa4332a6b04 100644 --- a/drivers/misc/eeprom/max6875.c +++ b/drivers/misc/eeprom/max6875.c @@ -114,12 +114,6 @@ static ssize_t max6875_read(struct file *filp, struct kobject *kobj, struct max6875_data *data = i2c_get_clientdata(client); int slice, max_slice; - if (off > USER_EEPROM_SIZE) - return 0; - - if (off + count > USER_EEPROM_SIZE) - count = USER_EEPROM_SIZE - off; - /* refresh slices which contain requested bytes */ max_slice = (off + count - 1) >> SLICE_BITS; for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++) -- cgit v1.3-6-gb490 From 64526370d11ce8868ca495723d595b61e8697fbf Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 15 Jul 2015 10:29:00 +0900 Subject: devres: fix devres_get() Currently, devres_get() passes devres_free() the pointer to devres, but devres_free() should be given with the pointer to resource data. Fixes: 9ac7849e35f7 ("devres: device resource management") Signed-off-by: Masahiro Yamada Acked-by: Tejun Heo Cc: stable # 2.6.21+ Signed-off-by: Greg Kroah-Hartman --- drivers/base/devres.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/devres.c b/drivers/base/devres.c index c8a53d1e019f..875464690117 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -297,10 +297,10 @@ void * devres_get(struct device *dev, void *new_res, if (!dr) { add_dr(dev, &new_dr->node); dr = new_dr; - new_dr = NULL; + new_res = NULL; } spin_unlock_irqrestore(&dev->devres_lock, flags); - devres_free(new_dr); + devres_free(new_res); return dr->data; } -- cgit v1.3-6-gb490 From a885de67157e8e65b92af2e0a77f6eadd112d0b7 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 29 Jul 2015 23:26:28 +0300 Subject: firmware: fix wrong memory deallocation in fw_add_devm_name() Device resource data allocated with devres_alloc() must be deallocated by devres_free(). Signed-off-by: Vladimir Zapolskiy Acked-by: Ming Lei Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 894bda114224..8524450e75bd 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -443,7 +443,7 @@ static int fw_add_devm_name(struct device *dev, const char *name) return -ENOMEM; fwn->name = kstrdup_const(name, GFP_KERNEL); if (!fwn->name) { - kfree(fwn); + devres_free(fwn); return -ENOMEM; } -- cgit v1.3-6-gb490 From eda5867b6992e3de888b516c0ff0fa1f1ee881af Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sun, 19 Jul 2015 20:06:21 +0200 Subject: cpu: Remove bogus __ref annotation of cpu_subsys_online() In commit 0db0628d9012 ("kernel: delete __cpuinit usage from all core kernel files") cpu_up() lost its __cpuinit annotation, vanishing the need for cpu_subsys_online() to have a __ref annotation. Just drop it to be able to catch real section mismatches in the future. Signed-off-by: Mathias Krause Cc: Paul Gortmaker Signed-off-by: Greg Kroah-Hartman --- drivers/base/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 78720e706176..91bbb1959d8d 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -41,7 +41,7 @@ static void change_cpu_under_node(struct cpu *cpu, cpu->node_id = to_nid; } -static int __ref cpu_subsys_online(struct device *dev) +static int cpu_subsys_online(struct device *dev) { struct cpu *cpu = container_of(dev, struct cpu, dev); int cpuid = dev->id; -- cgit v1.3-6-gb490 From ecc87eed7beeb50c0be0b73322d62135277ea2b0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 5 Aug 2015 16:51:11 +0300 Subject: device property: fix potential NULL pointer dereference In device_add_property_set() we check pset parameter for a NULL, but few lines later we do a pointer arithmetic without check that will crash kernel in the set_secondary_fwnode(). Here we check if pset parameter is NULL and return immediately. Fixes: 16ba08d5c9ec (device property: Introduce firmware node type for platform data) Signed-off-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/property.c b/drivers/base/property.c index f3f6d167f3f1..37a7bb7b239d 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -27,9 +27,10 @@ */ void device_add_property_set(struct device *dev, struct property_set *pset) { - if (pset) - pset->fwnode.type = FWNODE_PDATA; + if (!pset) + return; + pset->fwnode.type = FWNODE_PDATA; set_secondary_fwnode(dev, &pset->fwnode); } EXPORT_SYMBOL_GPL(device_add_property_set); -- cgit v1.3-6-gb490 From 87e6c1d78706b97018de3169d0edd661f640a425 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 5 Jun 2015 12:20:25 -0400 Subject: i40e/i40evf: Add device ids for X722 Adding device ids for new hardware X722 Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 10 ++++++++++ drivers/net/ethernet/intel/i40e/i40e_main.c | 3 +++ drivers/net/ethernet/intel/i40e/i40e_type.h | 10 +++++++++- drivers/net/ethernet/intel/i40evf/i40e_common.c | 9 +++++++++ drivers/net/ethernet/intel/i40evf/i40e_type.h | 10 +++++++++- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 1 + 6 files changed, 41 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 167ca0d752ea..11ec264120f0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -54,6 +54,15 @@ static i40e_status i40e_set_mac_type(struct i40e_hw *hw) case I40E_DEV_ID_20G_KR2: hw->mac.type = I40E_MAC_XL710; break; + case I40E_DEV_ID_SFP_X722: + case I40E_DEV_ID_1G_BASE_T_X722: + case I40E_DEV_ID_10G_BASE_T_X722: + hw->mac.type = I40E_MAC_X722; + break; + case I40E_DEV_ID_X722_VF: + case I40E_DEV_ID_X722_VF_HV: + hw->mac.type = I40E_MAC_X722_VF; + break; case I40E_DEV_ID_VF: case I40E_DEV_ID_VF_HV: hw->mac.type = I40E_MAC_VF; @@ -769,6 +778,7 @@ i40e_status i40e_init_shared_code(struct i40e_hw *hw) switch (hw->mac.type) { case I40E_MAC_XL710: + case I40E_MAC_X722: break; default: return I40E_ERR_DEVICE_NOT_SUPPORTED; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 857d294d2a45..9c96706dd53f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -76,6 +76,9 @@ static const struct pci_device_id i40e_pci_tbl[] = { {PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_C), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T), 0}, {PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2), 0}, + {PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_X722), 0}, + {PCI_VDEVICE(INTEL, I40E_DEV_ID_1G_BASE_T_X722), 0}, + {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T_X722), 0}, /* required last entry */ {0, } }; diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index a20128b82b62..778266fa4104 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -47,6 +47,11 @@ #define I40E_DEV_ID_20G_KR2 0x1587 #define I40E_DEV_ID_VF 0x154C #define I40E_DEV_ID_VF_HV 0x1571 +#define I40E_DEV_ID_SFP_X722 0x37D0 +#define I40E_DEV_ID_1G_BASE_T_X722 0x37D1 +#define I40E_DEV_ID_10G_BASE_T_X722 0x37D2 +#define I40E_DEV_ID_X722_VF 0x37CD +#define I40E_DEV_ID_X722_VF_HV 0x37D9 #define i40e_is_40G_device(d) ((d) == I40E_DEV_ID_QSFP_A || \ (d) == I40E_DEV_ID_QSFP_B || \ @@ -120,6 +125,8 @@ enum i40e_mac_type { I40E_MAC_X710, I40E_MAC_XL710, I40E_MAC_VF, + I40E_MAC_X722, + I40E_MAC_X722_VF, I40E_MAC_GENERIC, }; @@ -502,7 +509,8 @@ struct i40e_hw { static inline bool i40e_is_vf(struct i40e_hw *hw) { - return hw->mac.type == I40E_MAC_VF; + return (hw->mac.type == I40E_MAC_VF || + hw->mac.type == I40E_MAC_X722_VF); } struct i40e_driver_version { diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 56c7e751149b..eb54e8dc5e45 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -54,6 +54,15 @@ i40e_status i40e_set_mac_type(struct i40e_hw *hw) case I40E_DEV_ID_20G_KR2: hw->mac.type = I40E_MAC_XL710; break; + case I40E_DEV_ID_SFP_X722: + case I40E_DEV_ID_1G_BASE_T_X722: + case I40E_DEV_ID_10G_BASE_T_X722: + hw->mac.type = I40E_MAC_X722; + break; + case I40E_DEV_ID_X722_VF: + case I40E_DEV_ID_X722_VF_HV: + hw->mac.type = I40E_MAC_X722_VF; + break; case I40E_DEV_ID_VF: case I40E_DEV_ID_VF_HV: hw->mac.type = I40E_MAC_VF; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 4ba9a012dcba..c50536b0e15c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -47,6 +47,11 @@ #define I40E_DEV_ID_20G_KR2 0x1587 #define I40E_DEV_ID_VF 0x154C #define I40E_DEV_ID_VF_HV 0x1571 +#define I40E_DEV_ID_SFP_X722 0x37D0 +#define I40E_DEV_ID_1G_BASE_T_X722 0x37D1 +#define I40E_DEV_ID_10G_BASE_T_X722 0x37D2 +#define I40E_DEV_ID_X722_VF 0x37CD +#define I40E_DEV_ID_X722_VF_HV 0x37D9 #define i40e_is_40G_device(d) ((d) == I40E_DEV_ID_QSFP_A || \ (d) == I40E_DEV_ID_QSFP_B || \ @@ -120,6 +125,8 @@ enum i40e_mac_type { I40E_MAC_X710, I40E_MAC_XL710, I40E_MAC_VF, + I40E_MAC_X722, + I40E_MAC_X722_VF, I40E_MAC_GENERIC, }; @@ -496,7 +503,8 @@ struct i40e_hw { static inline bool i40e_is_vf(struct i40e_hw *hw) { - return hw->mac.type == I40E_MAC_VF; + return (hw->mac.type == I40E_MAC_VF || + hw->mac.type == I40E_MAC_X722_VF); } struct i40e_driver_version { diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 1503cad918d8..642944e622af 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -49,6 +49,7 @@ static const char i40evf_copyright[] = */ static const struct pci_device_id i40evf_pci_tbl[] = { {PCI_VDEVICE(INTEL, I40E_DEV_ID_VF), 0}, + {PCI_VDEVICE(INTEL, I40E_DEV_ID_X722_VF), 0}, /* required last entry */ {0, } }; -- cgit v1.3-6-gb490 From d502ce01d21bf4092f282cae5817e7d140e21816 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 5 Jun 2015 12:20:26 -0400 Subject: i40e/i40evf: Add flags for X722 capabilities Add capabilities flags specific to X722. Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 7 +++++++ drivers/net/ethernet/intel/i40e/i40e_main.c | 8 ++++++++ drivers/net/ethernet/intel/i40evf/i40evf.h | 7 ++++++- 3 files changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 281fd8456146..99148861b1c0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -298,6 +298,7 @@ struct i40e_pf { #define I40E_FLAG_VMDQ_ENABLED BIT_ULL(7) #define I40E_FLAG_FDIR_REQUIRES_REINIT BIT_ULL(8) #define I40E_FLAG_NEED_LINK_UPDATE BIT_ULL(9) +#define I40E_FLAG_IWARP_ENABLED BIT_ULL(10) #ifdef I40E_FCOE #define I40E_FLAG_FCOE_ENABLED BIT_ULL(11) #endif /* I40E_FCOE */ @@ -318,6 +319,12 @@ struct i40e_pf { #endif #define I40E_FLAG_PORT_ID_VALID BIT_ULL(28) #define I40E_FLAG_DCB_CAPABLE BIT_ULL(29) +#define I40E_FLAG_RSS_AQ_CAPABLE BIT_ULL(31) +#define I40E_FLAG_HW_ATR_EVICT_CAPABLE BIT_ULL(32) +#define I40E_FLAG_OUTER_UDP_CSUM_CAPABLE BIT_ULL(33) +#define I40E_FLAG_128_QP_RSS_CAPABLE BIT_ULL(34) +#define I40E_FLAG_WB_ON_ITR_CAPABLE BIT_ULL(35) +#define I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE BIT_ULL(38) #define I40E_FLAG_VEB_MODE_ENABLED BIT_ULL(40) /* tracks features that get auto disabled by errors */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 9c96706dd53f..3269b059762e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7785,6 +7785,14 @@ static int i40e_sw_init(struct i40e_pf *pf) I40E_MAX_VF_COUNT); } #endif /* CONFIG_PCI_IOV */ + if (pf->hw.mac.type == I40E_MAC_X722) { + pf->flags |= I40E_FLAG_RSS_AQ_CAPABLE | + I40E_FLAG_128_QP_RSS_CAPABLE | + I40E_FLAG_HW_ATR_EVICT_CAPABLE | + I40E_FLAG_OUTER_UDP_CSUM_CAPABLE | + I40E_FLAG_WB_ON_ITR_CAPABLE | + I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE; + } pf->eeprom_version = 0xDEAD; pf->lan_veb = I40E_NO_VEB; pf->lan_vsi = I40E_NO_VSI; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index c33c7cce52fe..bd227b39ac55 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -218,11 +218,15 @@ struct i40evf_adapter { #define I40EVF_FLAG_PF_COMMS_FAILED BIT(8) #define I40EVF_FLAG_RESET_PENDING BIT(9) #define I40EVF_FLAG_RESET_NEEDED BIT(10) -/* duplcates for common code */ +#define I40EVF_FLAG_WB_ON_ITR_CAPABLE BIT(11) +#define I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE BIT(12) +/* duplicates for common code */ #define I40E_FLAG_FDIR_ATR_ENABLED 0 #define I40E_FLAG_DCB_ENABLED 0 #define I40E_FLAG_IN_NETPOLL I40EVF_FLAG_IN_NETPOLL #define I40E_FLAG_RX_CSUM_ENABLED I40EVF_FLAG_RX_CSUM_ENABLED +#define I40E_FLAG_WB_ON_ITR_CAPABLE I40EVF_FLAG_WB_ON_ITR_CAPABLE +#define I40E_FLAG_OUTER_UDP_CSUM_CAPABLE I40EVF_FLAG_OUTER_UDP_CSUM_CAPABLE /* flags for admin queue service task */ u32 aq_required; #define I40EVF_FLAG_AQ_ENABLE_QUEUES BIT(0) @@ -234,6 +238,7 @@ struct i40evf_adapter { #define I40EVF_FLAG_AQ_CONFIGURE_QUEUES BIT(6) #define I40EVF_FLAG_AQ_MAP_VECTORS BIT(7) #define I40EVF_FLAG_AQ_HANDLE_RESET BIT(8) +#define I40EVF_FLAG_AQ_CONFIGURE_RSS BIT(9) #define I40EVF_FLAG_AQ_GET_CONFIG BIT(10) /* OS defined structs */ -- cgit v1.3-6-gb490 From e50c8d6d3d3f5807aaaeaaec42774cd02fd5076f Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 5 Jun 2015 12:20:27 -0400 Subject: i40e/i40evf: Update FW API with X722 support This patch does the firmware API update to support the new X722 device. Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 48 ++++++ drivers/net/ethernet/intel/i40e/i40e_common.c | 163 +++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_prototype.h | 11 ++ .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 49 ++++++- drivers/net/ethernet/intel/i40evf/i40e_common.c | 163 +++++++++++++++++++++ drivers/net/ethernet/intel/i40evf/i40e_prototype.h | 11 ++ 6 files changed, 444 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 9101f5c00f37..95d23bfbcbf1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -257,6 +257,10 @@ enum i40e_admin_queue_opc { /* Tunnel commands */ i40e_aqc_opc_add_udp_tunnel = 0x0B00, i40e_aqc_opc_del_udp_tunnel = 0x0B01, + i40e_aqc_opc_set_rss_key = 0x0B02, + i40e_aqc_opc_set_rss_lut = 0x0B03, + i40e_aqc_opc_get_rss_key = 0x0B04, + i40e_aqc_opc_get_rss_lut = 0x0B05, /* Async Events */ i40e_aqc_opc_event_lan_overflow = 0x1001, @@ -821,8 +825,12 @@ struct i40e_aqc_vsi_properties_data { I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT) /* queueing option section */ u8 queueing_opt_flags; +#define I40E_AQ_VSI_QUE_OPT_MULTICAST_UDP_ENA 0x04 +#define I40E_AQ_VSI_QUE_OPT_UNICAST_UDP_ENA 0x08 #define I40E_AQ_VSI_QUE_OPT_TCP_ENA 0x10 #define I40E_AQ_VSI_QUE_OPT_FCOE_ENA 0x20 +#define I40E_AQ_VSI_QUE_OPT_RSS_LUT_PF 0x00 +#define I40E_AQ_VSI_QUE_OPT_RSS_LUT_VSI 0x40 u8 queueing_opt_reserved[3]; /* scheduler section */ u8 up_enable_bits; @@ -2179,6 +2187,46 @@ struct i40e_aqc_del_udp_tunnel_completion { I40E_CHECK_CMD_LENGTH(i40e_aqc_del_udp_tunnel_completion); +struct i40e_aqc_get_set_rss_key { +#define I40E_AQC_SET_RSS_KEY_VSI_VALID (0x1 << 15) +#define I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT 0 +#define I40E_AQC_SET_RSS_KEY_VSI_ID_MASK (0x3FF << \ + I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT) + __le16 vsi_id; + u8 reserved[6]; + __le32 addr_high; + __le32 addr_low; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_key); + +struct i40e_aqc_get_set_rss_key_data { + u8 standard_rss_key[0x28]; + u8 extended_hash_key[0xc]; +}; + +I40E_CHECK_STRUCT_LEN(0x34, i40e_aqc_get_set_rss_key_data); + +struct i40e_aqc_get_set_rss_lut { +#define I40E_AQC_SET_RSS_LUT_VSI_VALID (0x1 << 15) +#define I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT 0 +#define I40E_AQC_SET_RSS_LUT_VSI_ID_MASK (0x3FF << \ + I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT) + __le16 vsi_id; +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT 0 +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK (0x1 << \ + I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) + +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI 0 +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF 1 + __le16 flags; + u8 reserved[4]; + __le32 addr_high; + __le32 addr_low; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_lut); + /* tunnel key structure 0x0B10 */ struct i40e_aqc_tunnel_key_structure { diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 11ec264120f0..114dc6450183 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -392,6 +392,169 @@ i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw, return status; } +/** + * i40e_aq_get_set_rss_lut + * @hw: pointer to the hardware structure + * @vsi_id: vsi fw index + * @pf_lut: for PF table set true, for VSI table set false + * @lut: pointer to the lut buffer provided by the caller + * @lut_size: size of the lut buffer + * @set: set true to set the table, false to get the table + * + * Internal function to get or set RSS look up table + **/ +static i40e_status i40e_aq_get_set_rss_lut(struct i40e_hw *hw, + u16 vsi_id, bool pf_lut, + u8 *lut, u16 lut_size, + bool set) +{ + i40e_status status; + struct i40e_aq_desc desc; + struct i40e_aqc_get_set_rss_lut *cmd_resp = + (struct i40e_aqc_get_set_rss_lut *)&desc.params.raw; + + if (set) + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_set_rss_lut); + else + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_get_rss_lut); + + /* Indirect command */ + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF); + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD); + + cmd_resp->vsi_id = + cpu_to_le16((u16)((vsi_id << + I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT) & + I40E_AQC_SET_RSS_LUT_VSI_ID_MASK)); + cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_LUT_VSI_VALID); + + if (pf_lut) + cmd_resp->flags |= cpu_to_le16((u16) + ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF << + I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) & + I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK)); + else + cmd_resp->flags |= cpu_to_le16((u16) + ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI << + I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) & + I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK)); + + cmd_resp->addr_high = cpu_to_le32(high_16_bits((u64)lut)); + cmd_resp->addr_low = cpu_to_le32(lower_32_bits((u64)lut)); + + status = i40e_asq_send_command(hw, &desc, lut, lut_size, NULL); + + return status; +} + +/** + * i40e_aq_get_rss_lut + * @hw: pointer to the hardware structure + * @vsi_id: vsi fw index + * @pf_lut: for PF table set true, for VSI table set false + * @lut: pointer to the lut buffer provided by the caller + * @lut_size: size of the lut buffer + * + * get the RSS lookup table, PF or VSI type + **/ +i40e_status i40e_aq_get_rss_lut(struct i40e_hw *hw, u16 vsi_id, + bool pf_lut, u8 *lut, u16 lut_size) +{ + return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, + false); +} + +/** + * i40e_aq_set_rss_lut + * @hw: pointer to the hardware structure + * @vsi_id: vsi fw index + * @pf_lut: for PF table set true, for VSI table set false + * @lut: pointer to the lut buffer provided by the caller + * @lut_size: size of the lut buffer + * + * set the RSS lookup table, PF or VSI type + **/ +i40e_status i40e_aq_set_rss_lut(struct i40e_hw *hw, u16 vsi_id, + bool pf_lut, u8 *lut, u16 lut_size) +{ + return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, true); +} + +/** + * i40e_aq_get_set_rss_key + * @hw: pointer to the hw struct + * @vsi_id: vsi fw index + * @key: pointer to key info struct + * @set: set true to set the key, false to get the key + * + * get the RSS key per VSI + **/ +static i40e_status i40e_aq_get_set_rss_key(struct i40e_hw *hw, + u16 vsi_id, + struct i40e_aqc_get_set_rss_key_data *key, + bool set) +{ + i40e_status status; + struct i40e_aq_desc desc; + struct i40e_aqc_get_set_rss_key *cmd_resp = + (struct i40e_aqc_get_set_rss_key *)&desc.params.raw; + u16 key_size = sizeof(struct i40e_aqc_get_set_rss_key_data); + + if (set) + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_set_rss_key); + else + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_get_rss_key); + + /* Indirect command */ + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF); + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD); + + cmd_resp->vsi_id = + cpu_to_le16((u16)((vsi_id << + I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT) & + I40E_AQC_SET_RSS_KEY_VSI_ID_MASK)); + cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_KEY_VSI_VALID); + cmd_resp->addr_high = cpu_to_le32(high_16_bits((u64)key)); + cmd_resp->addr_low = cpu_to_le32(lower_32_bits((u64)key)); + + status = i40e_asq_send_command(hw, &desc, key, key_size, NULL); + + return status; +} + +/** + * i40e_aq_get_rss_key + * @hw: pointer to the hw struct + * @vsi_id: vsi fw index + * @key: pointer to key info struct + * + **/ +i40e_status i40e_aq_get_rss_key(struct i40e_hw *hw, + u16 vsi_id, + struct i40e_aqc_get_set_rss_key_data *key) +{ + return i40e_aq_get_set_rss_key(hw, vsi_id, key, false); +} + +/** + * i40e_aq_set_rss_key + * @hw: pointer to the hw struct + * @vsi_id: vsi fw index + * @key: pointer to key info struct + * + * set the RSS key per VSI + **/ +i40e_status i40e_aq_set_rss_key(struct i40e_hw *hw, + u16 vsi_id, + struct i40e_aqc_get_set_rss_key_data *key) +{ + return i40e_aq_get_set_rss_key(hw, vsi_id, key, true); +} + /* 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. diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index d52a9f7873b0..dcb72a8ee8e5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -61,6 +61,17 @@ i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw, bool unloading); char *i40e_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err); char *i40e_stat_str(struct i40e_hw *hw, i40e_status stat_err); +i40e_status i40e_aq_get_rss_lut(struct i40e_hw *hw, u16 seid, + bool pf_lut, u8 *lut, u16 lut_size); +i40e_status i40e_aq_set_rss_lut(struct i40e_hw *hw, u16 seid, + bool pf_lut, u8 *lut, u16 lut_size); +i40e_status i40e_aq_get_rss_key(struct i40e_hw *hw, + u16 seid, + struct i40e_aqc_get_set_rss_key_data *key); +i40e_status i40e_aq_set_rss_key(struct i40e_hw *hw, + u16 seid, + struct i40e_aqc_get_set_rss_key_data *key); + u32 i40e_led_get(struct i40e_hw *hw); void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index d5bd6f066921..c8022092d369 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -35,7 +35,6 @@ #define I40E_FW_API_VERSION_MAJOR 0x0001 #define I40E_FW_API_VERSION_MINOR 0x0004 -#define I40E_FW_API_VERSION_A0_MINOR 0x0000 struct i40e_aq_desc { __le16 flags; @@ -255,6 +254,10 @@ enum i40e_admin_queue_opc { /* Tunnel commands */ i40e_aqc_opc_add_udp_tunnel = 0x0B00, i40e_aqc_opc_del_udp_tunnel = 0x0B01, + i40e_aqc_opc_set_rss_key = 0x0B02, + i40e_aqc_opc_set_rss_lut = 0x0B03, + i40e_aqc_opc_get_rss_key = 0x0B04, + i40e_aqc_opc_get_rss_lut = 0x0B05, /* Async Events */ i40e_aqc_opc_event_lan_overflow = 0x1001, @@ -819,8 +822,12 @@ struct i40e_aqc_vsi_properties_data { I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT) /* queueing option section */ u8 queueing_opt_flags; +#define I40E_AQ_VSI_QUE_OPT_MULTICAST_UDP_ENA 0x04 +#define I40E_AQ_VSI_QUE_OPT_UNICAST_UDP_ENA 0x08 #define I40E_AQ_VSI_QUE_OPT_TCP_ENA 0x10 #define I40E_AQ_VSI_QUE_OPT_FCOE_ENA 0x20 +#define I40E_AQ_VSI_QUE_OPT_RSS_LUT_PF 0x00 +#define I40E_AQ_VSI_QUE_OPT_RSS_LUT_VSI 0x40 u8 queueing_opt_reserved[3]; /* scheduler section */ u8 up_enable_bits; @@ -2089,6 +2096,46 @@ struct i40e_aqc_del_udp_tunnel_completion { I40E_CHECK_CMD_LENGTH(i40e_aqc_del_udp_tunnel_completion); +struct i40e_aqc_get_set_rss_key { +#define I40E_AQC_SET_RSS_KEY_VSI_VALID (0x1 << 15) +#define I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT 0 +#define I40E_AQC_SET_RSS_KEY_VSI_ID_MASK (0x3FF << \ + I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT) + __le16 vsi_id; + u8 reserved[6]; + __le32 addr_high; + __le32 addr_low; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_key); + +struct i40e_aqc_get_set_rss_key_data { + u8 standard_rss_key[0x28]; + u8 extended_hash_key[0xc]; +}; + +I40E_CHECK_STRUCT_LEN(0x34, i40e_aqc_get_set_rss_key_data); + +struct i40e_aqc_get_set_rss_lut { +#define I40E_AQC_SET_RSS_LUT_VSI_VALID (0x1 << 15) +#define I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT 0 +#define I40E_AQC_SET_RSS_LUT_VSI_ID_MASK (0x3FF << \ + I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT) + __le16 vsi_id; +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT 0 +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK (0x1 << \ + I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) + +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI 0 +#define I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF 1 + __le16 flags; + u8 reserved[4]; + __le32 addr_high; + __le32 addr_low; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_get_set_rss_lut); + /* tunnel key structure 0x0B10 */ struct i40e_aqc_tunnel_key_structure_A0 { diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index eb54e8dc5e45..023d32d090ce 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -392,6 +392,169 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, return status; } +/** + * i40e_aq_get_set_rss_lut + * @hw: pointer to the hardware structure + * @vsi_id: vsi fw index + * @pf_lut: for PF table set true, for VSI table set false + * @lut: pointer to the lut buffer provided by the caller + * @lut_size: size of the lut buffer + * @set: set true to set the table, false to get the table + * + * Internal function to get or set RSS look up table + **/ +static i40e_status i40e_aq_get_set_rss_lut(struct i40e_hw *hw, + u16 vsi_id, bool pf_lut, + u8 *lut, u16 lut_size, + bool set) +{ + i40e_status status; + struct i40e_aq_desc desc; + struct i40e_aqc_get_set_rss_lut *cmd_resp = + (struct i40e_aqc_get_set_rss_lut *)&desc.params.raw; + + if (set) + i40evf_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_set_rss_lut); + else + i40evf_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_get_rss_lut); + + /* Indirect command */ + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF); + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD); + + cmd_resp->vsi_id = + cpu_to_le16((u16)((vsi_id << + I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT) & + I40E_AQC_SET_RSS_LUT_VSI_ID_MASK)); + cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_LUT_VSI_VALID); + + if (pf_lut) + cmd_resp->flags |= cpu_to_le16((u16) + ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF << + I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) & + I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK)); + else + cmd_resp->flags |= cpu_to_le16((u16) + ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI << + I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) & + I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK)); + + cmd_resp->addr_high = cpu_to_le32(high_16_bits((u64)lut)); + cmd_resp->addr_low = cpu_to_le32(lower_32_bits((u64)lut)); + + status = i40evf_asq_send_command(hw, &desc, lut, lut_size, NULL); + + return status; +} + +/** + * i40evf_aq_get_rss_lut + * @hw: pointer to the hardware structure + * @vsi_id: vsi fw index + * @pf_lut: for PF table set true, for VSI table set false + * @lut: pointer to the lut buffer provided by the caller + * @lut_size: size of the lut buffer + * + * get the RSS lookup table, PF or VSI type + **/ +i40e_status i40evf_aq_get_rss_lut(struct i40e_hw *hw, u16 vsi_id, + bool pf_lut, u8 *lut, u16 lut_size) +{ + return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, + false); +} + +/** + * i40evf_aq_set_rss_lut + * @hw: pointer to the hardware structure + * @vsi_id: vsi fw index + * @pf_lut: for PF table set true, for VSI table set false + * @lut: pointer to the lut buffer provided by the caller + * @lut_size: size of the lut buffer + * + * set the RSS lookup table, PF or VSI type + **/ +i40e_status i40evf_aq_set_rss_lut(struct i40e_hw *hw, u16 vsi_id, + bool pf_lut, u8 *lut, u16 lut_size) +{ + return i40e_aq_get_set_rss_lut(hw, vsi_id, pf_lut, lut, lut_size, true); +} + +/** + * i40e_aq_get_set_rss_key + * @hw: pointer to the hw struct + * @vsi_id: vsi fw index + * @key: pointer to key info struct + * @set: set true to set the key, false to get the key + * + * get the RSS key per VSI + **/ +static i40e_status i40e_aq_get_set_rss_key(struct i40e_hw *hw, + u16 vsi_id, + struct i40e_aqc_get_set_rss_key_data *key, + bool set) +{ + i40e_status status; + struct i40e_aq_desc desc; + struct i40e_aqc_get_set_rss_key *cmd_resp = + (struct i40e_aqc_get_set_rss_key *)&desc.params.raw; + u16 key_size = sizeof(struct i40e_aqc_get_set_rss_key_data); + + if (set) + i40evf_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_set_rss_key); + else + i40evf_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_get_rss_key); + + /* Indirect command */ + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF); + desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD); + + cmd_resp->vsi_id = + cpu_to_le16((u16)((vsi_id << + I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT) & + I40E_AQC_SET_RSS_KEY_VSI_ID_MASK)); + cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_KEY_VSI_VALID); + cmd_resp->addr_high = cpu_to_le32(high_16_bits((u64)key)); + cmd_resp->addr_low = cpu_to_le32(lower_32_bits((u64)key)); + + status = i40evf_asq_send_command(hw, &desc, key, key_size, NULL); + + return status; +} + +/** + * i40evf_aq_get_rss_key + * @hw: pointer to the hw struct + * @vsi_id: vsi fw index + * @key: pointer to key info struct + * + **/ +i40e_status i40evf_aq_get_rss_key(struct i40e_hw *hw, + u16 vsi_id, + struct i40e_aqc_get_set_rss_key_data *key) +{ + return i40e_aq_get_set_rss_key(hw, vsi_id, key, false); +} + +/** + * i40evf_aq_set_rss_key + * @hw: pointer to the hw struct + * @vsi_id: vsi fw index + * @key: pointer to key info struct + * + * set the RSS key per VSI + **/ +i40e_status i40evf_aq_set_rss_key(struct i40e_hw *hw, + u16 vsi_id, + struct i40e_aqc_get_set_rss_key_data *key) +{ + return i40e_aq_get_set_rss_key(hw, vsi_id, key, true); +} + /* 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 diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h index 856eb9d06595..55ae4b0f8192 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h @@ -63,6 +63,17 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading); char *i40evf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err); char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err); +i40e_status i40evf_aq_get_rss_lut(struct i40e_hw *hw, u16 seid, + bool pf_lut, u8 *lut, u16 lut_size); +i40e_status i40evf_aq_set_rss_lut(struct i40e_hw *hw, u16 seid, + bool pf_lut, u8 *lut, u16 lut_size); +i40e_status i40evf_aq_get_rss_key(struct i40e_hw *hw, + u16 seid, + struct i40e_aqc_get_set_rss_key_data *key); +i40e_status i40evf_aq_set_rss_key(struct i40e_hw *hw, + u16 seid, + struct i40e_aqc_get_set_rss_key_data *key); + i40e_status i40e_set_mac_type(struct i40e_hw *hw); extern struct i40e_rx_ptype_decoded i40evf_ptype_lookup[]; -- cgit v1.3-6-gb490 From da48c9a2aa3a93b4f19e3a37b8fa1cd7fe7005bb Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 5 Jun 2015 12:20:28 -0400 Subject: i40e/i40evf: Update register.h file for X722 Update the i40e and i40evf register.h file with the registers for X722. Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_register.h | 1931 ++++++++++++++++++++- drivers/net/ethernet/intel/i40evf/i40e_register.h | 62 +- 2 files changed, 1991 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h index 522d6df51330..acae6c744bc2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_register.h +++ b/drivers/net/ethernet/intel/i40e/i40e_register.h @@ -3366,4 +3366,1933 @@ #define I40E_VFQF_HREGION_OVERRIDE_ENA_7_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT) #define I40E_VFQF_HREGION_REGION_7_SHIFT 29 #define I40E_VFQF_HREGION_REGION_7_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_7_SHIFT) -#endif + +#define I40E_MNGSB_FDCRC 0x000B7050 /* Reset: POR */ +#define I40E_MNGSB_FDCRC_CRC_RES_SHIFT 0 +#define I40E_MNGSB_FDCRC_CRC_RES_MASK I40E_MASK(0xFF, I40E_MNGSB_FDCRC_CRC_RES_SHIFT) +#define I40E_MNGSB_FDCS 0x000B7040 /* Reset: POR */ +#define I40E_MNGSB_FDCS_CRC_CONT_SHIFT 2 +#define I40E_MNGSB_FDCS_CRC_CONT_MASK I40E_MASK(0x1, I40E_MNGSB_FDCS_CRC_CONT_SHIFT) +#define I40E_MNGSB_FDCS_CRC_SEED_EN_SHIFT 3 +#define I40E_MNGSB_FDCS_CRC_SEED_EN_MASK I40E_MASK(0x1, I40E_MNGSB_FDCS_CRC_SEED_EN_SHIFT) +#define I40E_MNGSB_FDCS_CRC_WR_INH_SHIFT 4 +#define I40E_MNGSB_FDCS_CRC_WR_INH_MASK I40E_MASK(0x1, I40E_MNGSB_FDCS_CRC_WR_INH_SHIFT) +#define I40E_MNGSB_FDCS_CRC_SEED_SHIFT 8 +#define I40E_MNGSB_FDCS_CRC_SEED_MASK I40E_MASK(0xFF, I40E_MNGSB_FDCS_CRC_SEED_SHIFT) +#define I40E_MNGSB_FDS 0x000B7048 /* Reset: POR */ +#define I40E_MNGSB_FDS_START_BC_SHIFT 0 +#define I40E_MNGSB_FDS_START_BC_MASK I40E_MASK(0xFFF, I40E_MNGSB_FDS_START_BC_SHIFT) +#define I40E_MNGSB_FDS_LAST_BC_SHIFT 16 +#define I40E_MNGSB_FDS_LAST_BC_MASK I40E_MASK(0xFFF, I40E_MNGSB_FDS_LAST_BC_SHIFT) + +#define I40E_GL_VF_CTRL_RX(_VF) (0x00083600 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ +#define I40E_GL_VF_CTRL_RX_MAX_INDEX 127 +#define I40E_GL_VF_CTRL_RX_AQ_RX_EN_SHIFT 0 +#define I40E_GL_VF_CTRL_RX_AQ_RX_EN_MASK I40E_MASK(0x1, I40E_GL_VF_CTRL_RX_AQ_RX_EN_SHIFT) +#define I40E_GL_VF_CTRL_TX(_VF) (0x00083400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ +#define I40E_GL_VF_CTRL_TX_MAX_INDEX 127 +#define I40E_GL_VF_CTRL_TX_AQ_TX_EN_SHIFT 0 +#define I40E_GL_VF_CTRL_TX_AQ_TX_EN_MASK I40E_MASK(0x1, I40E_GL_VF_CTRL_TX_AQ_TX_EN_SHIFT) + +#define I40E_GLCM_LAN_CACHESIZE 0x0010C4D8 /* Reset: CORER */ +#define I40E_GLCM_LAN_CACHESIZE_WORD_SIZE_SHIFT 0 +#define I40E_GLCM_LAN_CACHESIZE_WORD_SIZE_MASK I40E_MASK(0xFFF, I40E_GLCM_LAN_CACHESIZE_WORD_SIZE_SHIFT) +#define I40E_GLCM_LAN_CACHESIZE_SETS_SHIFT 12 +#define I40E_GLCM_LAN_CACHESIZE_SETS_MASK I40E_MASK(0xF, I40E_GLCM_LAN_CACHESIZE_SETS_SHIFT) +#define I40E_GLCM_LAN_CACHESIZE_WAYS_SHIFT 16 +#define I40E_GLCM_LAN_CACHESIZE_WAYS_MASK I40E_MASK(0x3FF, I40E_GLCM_LAN_CACHESIZE_WAYS_SHIFT) +#define I40E_GLCM_PE_CACHESIZE 0x00138FE4 /* Reset: CORER */ +#define I40E_GLCM_PE_CACHESIZE_WORD_SIZE_SHIFT 0 +#define I40E_GLCM_PE_CACHESIZE_WORD_SIZE_MASK I40E_MASK(0xFFF, I40E_GLCM_PE_CACHESIZE_WORD_SIZE_SHIFT) +#define I40E_GLCM_PE_CACHESIZE_SETS_SHIFT 12 +#define I40E_GLCM_PE_CACHESIZE_SETS_MASK I40E_MASK(0xF, I40E_GLCM_PE_CACHESIZE_SETS_SHIFT) +#define I40E_GLCM_PE_CACHESIZE_WAYS_SHIFT 16 +#define I40E_GLCM_PE_CACHESIZE_WAYS_MASK I40E_MASK(0x1FF, I40E_GLCM_PE_CACHESIZE_WAYS_SHIFT) +#define I40E_PFCM_PE_ERRDATA 0x00138D00 /* Reset: PFR */ +#define I40E_PFCM_PE_ERRDATA_ERROR_CODE_SHIFT 0 +#define I40E_PFCM_PE_ERRDATA_ERROR_CODE_MASK I40E_MASK(0xF, I40E_PFCM_PE_ERRDATA_ERROR_CODE_SHIFT) +#define I40E_PFCM_PE_ERRDATA_Q_TYPE_SHIFT 4 +#define I40E_PFCM_PE_ERRDATA_Q_TYPE_MASK I40E_MASK(0x7, I40E_PFCM_PE_ERRDATA_Q_TYPE_SHIFT) +#define I40E_PFCM_PE_ERRDATA_Q_NUM_SHIFT 8 +#define I40E_PFCM_PE_ERRDATA_Q_NUM_MASK I40E_MASK(0x3FFFF, I40E_PFCM_PE_ERRDATA_Q_NUM_SHIFT) +#define I40E_PFCM_PE_ERRINFO 0x00138C80 /* Reset: PFR */ +#define I40E_PFCM_PE_ERRINFO_ERROR_VALID_SHIFT 0 +#define I40E_PFCM_PE_ERRINFO_ERROR_VALID_MASK I40E_MASK(0x1, I40E_PFCM_PE_ERRINFO_ERROR_VALID_SHIFT) +#define I40E_PFCM_PE_ERRINFO_ERROR_INST_SHIFT 4 +#define I40E_PFCM_PE_ERRINFO_ERROR_INST_MASK I40E_MASK(0x7, I40E_PFCM_PE_ERRINFO_ERROR_INST_SHIFT) +#define I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT 8 +#define I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT) +#define I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT 16 +#define I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT) +#define I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT 24 +#define I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT) + +#define I40E_PRTDCB_TFMSTC(_i) (0x000A0040 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ +#define I40E_PRTDCB_TFMSTC_MAX_INDEX 7 +#define I40E_PRTDCB_TFMSTC_MSTC_SHIFT 0 +#define I40E_PRTDCB_TFMSTC_MSTC_MASK I40E_MASK(0xFFFFF, I40E_PRTDCB_TFMSTC_MSTC_SHIFT) +#define I40E_GL_FWSTS_FWROWD_SHIFT 8 +#define I40E_GL_FWSTS_FWROWD_MASK I40E_MASK(0x1, I40E_GL_FWSTS_FWROWD_SHIFT) +#define I40E_GLFOC_CACHESIZE 0x000AA0DC /* Reset: CORER */ +#define I40E_GLFOC_CACHESIZE_WORD_SIZE_SHIFT 0 +#define I40E_GLFOC_CACHESIZE_WORD_SIZE_MASK I40E_MASK(0xFF, I40E_GLFOC_CACHESIZE_WORD_SIZE_SHIFT) +#define I40E_GLFOC_CACHESIZE_SETS_SHIFT 8 +#define I40E_GLFOC_CACHESIZE_SETS_MASK I40E_MASK(0xFFF, I40E_GLFOC_CACHESIZE_SETS_SHIFT) +#define I40E_GLFOC_CACHESIZE_WAYS_SHIFT 20 +#define I40E_GLFOC_CACHESIZE_WAYS_MASK I40E_MASK(0xF, I40E_GLFOC_CACHESIZE_WAYS_SHIFT) +#define I40E_GLHMC_APBVTINUSEBASE(_i) (0x000C4a00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_APBVTINUSEBASE_MAX_INDEX 15 +#define I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT 0 +#define I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT) +#define I40E_GLHMC_CEQPART(_i) (0x001312C0 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_CEQPART_MAX_INDEX 15 +#define I40E_GLHMC_CEQPART_PMCEQBASE_SHIFT 0 +#define I40E_GLHMC_CEQPART_PMCEQBASE_MASK I40E_MASK(0xFF, I40E_GLHMC_CEQPART_PMCEQBASE_SHIFT) +#define I40E_GLHMC_CEQPART_PMCEQSIZE_SHIFT 16 +#define I40E_GLHMC_CEQPART_PMCEQSIZE_MASK I40E_MASK(0x1FF, I40E_GLHMC_CEQPART_PMCEQSIZE_SHIFT) +#define I40E_GLHMC_DBCQMAX 0x000C20F0 /* Reset: CORER */ +#define I40E_GLHMC_DBCQMAX_GLHMC_DBCQMAX_SHIFT 0 +#define I40E_GLHMC_DBCQMAX_GLHMC_DBCQMAX_MASK I40E_MASK(0x3FFFF, I40E_GLHMC_DBCQMAX_GLHMC_DBCQMAX_SHIFT) +#define I40E_GLHMC_DBCQPART(_i) (0x00131240 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_DBCQPART_MAX_INDEX 15 +#define I40E_GLHMC_DBCQPART_PMDBCQBASE_SHIFT 0 +#define I40E_GLHMC_DBCQPART_PMDBCQBASE_MASK I40E_MASK(0x3FFF, I40E_GLHMC_DBCQPART_PMDBCQBASE_SHIFT) +#define I40E_GLHMC_DBCQPART_PMDBCQSIZE_SHIFT 16 +#define I40E_GLHMC_DBCQPART_PMDBCQSIZE_MASK I40E_MASK(0x7FFF, I40E_GLHMC_DBCQPART_PMDBCQSIZE_SHIFT) +#define I40E_GLHMC_DBQPMAX 0x000C20EC /* Reset: CORER */ +#define I40E_GLHMC_DBQPMAX_GLHMC_DBQPMAX_SHIFT 0 +#define I40E_GLHMC_DBQPMAX_GLHMC_DBQPMAX_MASK I40E_MASK(0x7FFFF, I40E_GLHMC_DBQPMAX_GLHMC_DBQPMAX_SHIFT) +#define I40E_GLHMC_DBQPPART(_i) (0x00138D80 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_DBQPPART_MAX_INDEX 15 +#define I40E_GLHMC_DBQPPART_PMDBQPBASE_SHIFT 0 +#define I40E_GLHMC_DBQPPART_PMDBQPBASE_MASK I40E_MASK(0x3FFF, I40E_GLHMC_DBQPPART_PMDBQPBASE_SHIFT) +#define I40E_GLHMC_DBQPPART_PMDBQPSIZE_SHIFT 16 +#define I40E_GLHMC_DBQPPART_PMDBQPSIZE_MASK I40E_MASK(0x7FFF, I40E_GLHMC_DBQPPART_PMDBQPSIZE_SHIFT) +#define I40E_GLHMC_PEARPBASE(_i) (0x000C4800 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEARPBASE_MAX_INDEX 15 +#define I40E_GLHMC_PEARPBASE_FPMPEARPBASE_SHIFT 0 +#define I40E_GLHMC_PEARPBASE_FPMPEARPBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PEARPBASE_FPMPEARPBASE_SHIFT) +#define I40E_GLHMC_PEARPCNT(_i) (0x000C4900 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEARPCNT_MAX_INDEX 15 +#define I40E_GLHMC_PEARPCNT_FPMPEARPCNT_SHIFT 0 +#define I40E_GLHMC_PEARPCNT_FPMPEARPCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PEARPCNT_FPMPEARPCNT_SHIFT) +#define I40E_GLHMC_PEARPMAX 0x000C2038 /* Reset: CORER */ +#define I40E_GLHMC_PEARPMAX_PMPEARPMAX_SHIFT 0 +#define I40E_GLHMC_PEARPMAX_PMPEARPMAX_MASK I40E_MASK(0x1FFFF, I40E_GLHMC_PEARPMAX_PMPEARPMAX_SHIFT) +#define I40E_GLHMC_PEARPOBJSZ 0x000C2034 /* Reset: CORER */ +#define I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_SHIFT 0 +#define I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_MASK I40E_MASK(0x7, I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_SHIFT) +#define I40E_GLHMC_PECQBASE(_i) (0x000C4200 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PECQBASE_MAX_INDEX 15 +#define I40E_GLHMC_PECQBASE_FPMPECQBASE_SHIFT 0 +#define I40E_GLHMC_PECQBASE_FPMPECQBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PECQBASE_FPMPECQBASE_SHIFT) +#define I40E_GLHMC_PECQCNT(_i) (0x000C4300 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PECQCNT_MAX_INDEX 15 +#define I40E_GLHMC_PECQCNT_FPMPECQCNT_SHIFT 0 +#define I40E_GLHMC_PECQCNT_FPMPECQCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PECQCNT_FPMPECQCNT_SHIFT) +#define I40E_GLHMC_PECQOBJSZ 0x000C2020 /* Reset: CORER */ +#define I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_SHIFT 0 +#define I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_SHIFT) +#define I40E_GLHMC_PEHTCNT(_i) (0x000C4700 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEHTCNT_MAX_INDEX 15 +#define I40E_GLHMC_PEHTCNT_FPMPEHTCNT_SHIFT 0 +#define I40E_GLHMC_PEHTCNT_FPMPEHTCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PEHTCNT_FPMPEHTCNT_SHIFT) +#define I40E_GLHMC_PEHTEBASE(_i) (0x000C4600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEHTEBASE_MAX_INDEX 15 +#define I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_SHIFT 0 +#define I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_SHIFT) +#define I40E_GLHMC_PEHTEOBJSZ 0x000C202c /* Reset: CORER */ +#define I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_SHIFT 0 +#define I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_SHIFT) +#define I40E_GLHMC_PEHTMAX 0x000C2030 /* Reset: CORER */ +#define I40E_GLHMC_PEHTMAX_PMPEHTMAX_SHIFT 0 +#define I40E_GLHMC_PEHTMAX_PMPEHTMAX_MASK I40E_MASK(0x1FFFFF, I40E_GLHMC_PEHTMAX_PMPEHTMAX_SHIFT) +#define I40E_GLHMC_PEMRBASE(_i) (0x000C4c00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEMRBASE_MAX_INDEX 15 +#define I40E_GLHMC_PEMRBASE_FPMPEMRBASE_SHIFT 0 +#define I40E_GLHMC_PEMRBASE_FPMPEMRBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PEMRBASE_FPMPEMRBASE_SHIFT) +#define I40E_GLHMC_PEMRCNT(_i) (0x000C4d00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEMRCNT_MAX_INDEX 15 +#define I40E_GLHMC_PEMRCNT_FPMPEMRSZ_SHIFT 0 +#define I40E_GLHMC_PEMRCNT_FPMPEMRSZ_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PEMRCNT_FPMPEMRSZ_SHIFT) +#define I40E_GLHMC_PEMRMAX 0x000C2040 /* Reset: CORER */ +#define I40E_GLHMC_PEMRMAX_PMPEMRMAX_SHIFT 0 +#define I40E_GLHMC_PEMRMAX_PMPEMRMAX_MASK I40E_MASK(0x7FFFFF, I40E_GLHMC_PEMRMAX_PMPEMRMAX_SHIFT) +#define I40E_GLHMC_PEMROBJSZ 0x000C203c /* Reset: CORER */ +#define I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_SHIFT 0 +#define I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_SHIFT) +#define I40E_GLHMC_PEPBLBASE(_i) (0x000C5800 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEPBLBASE_MAX_INDEX 15 +#define I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_SHIFT 0 +#define I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_SHIFT) +#define I40E_GLHMC_PEPBLCNT(_i) (0x000C5900 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEPBLCNT_MAX_INDEX 15 +#define I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_SHIFT 0 +#define I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_SHIFT) +#define I40E_GLHMC_PEPBLMAX 0x000C206c /* Reset: CORER */ +#define I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_SHIFT 0 +#define I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_SHIFT) +#define I40E_GLHMC_PEPFFIRSTSD 0x000C20E4 /* Reset: CORER */ +#define I40E_GLHMC_PEPFFIRSTSD_GLHMC_PEPFFIRSTSD_SHIFT 0 +#define I40E_GLHMC_PEPFFIRSTSD_GLHMC_PEPFFIRSTSD_MASK I40E_MASK(0xFFF, I40E_GLHMC_PEPFFIRSTSD_GLHMC_PEPFFIRSTSD_SHIFT) +#define I40E_GLHMC_PEQ1BASE(_i) (0x000C5200 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEQ1BASE_MAX_INDEX 15 +#define I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_SHIFT 0 +#define I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_SHIFT) +#define I40E_GLHMC_PEQ1CNT(_i) (0x000C5300 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEQ1CNT_MAX_INDEX 15 +#define I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_SHIFT 0 +#define I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_SHIFT) +#define I40E_GLHMC_PEQ1FLBASE(_i) (0x000C5400 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEQ1FLBASE_MAX_INDEX 15 +#define I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_SHIFT 0 +#define I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_SHIFT) +#define I40E_GLHMC_PEQ1FLMAX 0x000C2058 /* Reset: CORER */ +#define I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_SHIFT 0 +#define I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_MASK I40E_MASK(0x3FFFFFF, I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_SHIFT) +#define I40E_GLHMC_PEQ1MAX 0x000C2054 /* Reset: CORER */ +#define I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_SHIFT 0 +#define I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_MASK I40E_MASK(0x3FFFFFF, I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_SHIFT) +#define I40E_GLHMC_PEQ1OBJSZ 0x000C2050 /* Reset: CORER */ +#define I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_SHIFT 0 +#define I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_SHIFT) +#define I40E_GLHMC_PEQPBASE(_i) (0x000C4000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEQPBASE_MAX_INDEX 15 +#define I40E_GLHMC_PEQPBASE_FPMPEQPBASE_SHIFT 0 +#define I40E_GLHMC_PEQPBASE_FPMPEQPBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PEQPBASE_FPMPEQPBASE_SHIFT) +#define I40E_GLHMC_PEQPCNT(_i) (0x000C4100 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEQPCNT_MAX_INDEX 15 +#define I40E_GLHMC_PEQPCNT_FPMPEQPCNT_SHIFT 0 +#define I40E_GLHMC_PEQPCNT_FPMPEQPCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PEQPCNT_FPMPEQPCNT_SHIFT) +#define I40E_GLHMC_PEQPOBJSZ 0x000C201c /* Reset: CORER */ +#define I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_SHIFT 0 +#define I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_SHIFT) +#define I40E_GLHMC_PESRQBASE(_i) (0x000C4400 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PESRQBASE_MAX_INDEX 15 +#define I40E_GLHMC_PESRQBASE_FPMPESRQBASE_SHIFT 0 +#define I40E_GLHMC_PESRQBASE_FPMPESRQBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PESRQBASE_FPMPESRQBASE_SHIFT) +#define I40E_GLHMC_PESRQCNT(_i) (0x000C4500 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PESRQCNT_MAX_INDEX 15 +#define I40E_GLHMC_PESRQCNT_FPMPESRQCNT_SHIFT 0 +#define I40E_GLHMC_PESRQCNT_FPMPESRQCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PESRQCNT_FPMPESRQCNT_SHIFT) +#define I40E_GLHMC_PESRQMAX 0x000C2028 /* Reset: CORER */ +#define I40E_GLHMC_PESRQMAX_PMPESRQMAX_SHIFT 0 +#define I40E_GLHMC_PESRQMAX_PMPESRQMAX_MASK I40E_MASK(0xFFFF, I40E_GLHMC_PESRQMAX_PMPESRQMAX_SHIFT) +#define I40E_GLHMC_PESRQOBJSZ 0x000C2024 /* Reset: CORER */ +#define I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_SHIFT 0 +#define I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_SHIFT) +#define I40E_GLHMC_PETIMERBASE(_i) (0x000C5A00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PETIMERBASE_MAX_INDEX 15 +#define I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_SHIFT 0 +#define I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_SHIFT) +#define I40E_GLHMC_PETIMERCNT(_i) (0x000C5B00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PETIMERCNT_MAX_INDEX 15 +#define I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_SHIFT 0 +#define I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_SHIFT) +#define I40E_GLHMC_PETIMERMAX 0x000C2084 /* Reset: CORER */ +#define I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_SHIFT 0 +#define I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_SHIFT) +#define I40E_GLHMC_PETIMEROBJSZ 0x000C2080 /* Reset: CORER */ +#define I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_SHIFT 0 +#define I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_SHIFT) +#define I40E_GLHMC_PEXFBASE(_i) (0x000C4e00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEXFBASE_MAX_INDEX 15 +#define I40E_GLHMC_PEXFBASE_FPMPEXFBASE_SHIFT 0 +#define I40E_GLHMC_PEXFBASE_FPMPEXFBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PEXFBASE_FPMPEXFBASE_SHIFT) +#define I40E_GLHMC_PEXFCNT(_i) (0x000C4f00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEXFCNT_MAX_INDEX 15 +#define I40E_GLHMC_PEXFCNT_FPMPEXFCNT_SHIFT 0 +#define I40E_GLHMC_PEXFCNT_FPMPEXFCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_PEXFCNT_FPMPEXFCNT_SHIFT) +#define I40E_GLHMC_PEXFFLBASE(_i) (0x000C5000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PEXFFLBASE_MAX_INDEX 15 +#define I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_SHIFT 0 +#define I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_SHIFT) +#define I40E_GLHMC_PEXFFLMAX 0x000C204c /* Reset: CORER */ +#define I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_SHIFT 0 +#define I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_MASK I40E_MASK(0x1FFFFFF, I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_SHIFT) +#define I40E_GLHMC_PEXFMAX 0x000C2048 /* Reset: CORER */ +#define I40E_GLHMC_PEXFMAX_PMPEXFMAX_SHIFT 0 +#define I40E_GLHMC_PEXFMAX_PMPEXFMAX_MASK I40E_MASK(0x3FFFFFF, I40E_GLHMC_PEXFMAX_PMPEXFMAX_SHIFT) +#define I40E_GLHMC_PEXFOBJSZ 0x000C2044 /* Reset: CORER */ +#define I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_SHIFT 0 +#define I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_SHIFT) +#define I40E_GLHMC_PFPESDPART(_i) (0x000C0880 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLHMC_PFPESDPART_MAX_INDEX 15 +#define I40E_GLHMC_PFPESDPART_PMSDBASE_SHIFT 0 +#define I40E_GLHMC_PFPESDPART_PMSDBASE_MASK I40E_MASK(0xFFF, I40E_GLHMC_PFPESDPART_PMSDBASE_SHIFT) +#define I40E_GLHMC_PFPESDPART_PMSDSIZE_SHIFT 16 +#define I40E_GLHMC_PFPESDPART_PMSDSIZE_MASK I40E_MASK(0x1FFF, I40E_GLHMC_PFPESDPART_PMSDSIZE_SHIFT) +#define I40E_GLHMC_VFAPBVTINUSEBASE(_i) (0x000Cca00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFAPBVTINUSEBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT 0 +#define I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT) +#define I40E_GLHMC_VFCEQPART(_i) (0x00132240 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFCEQPART_MAX_INDEX 31 +#define I40E_GLHMC_VFCEQPART_PMCEQBASE_SHIFT 0 +#define I40E_GLHMC_VFCEQPART_PMCEQBASE_MASK I40E_MASK(0xFF, I40E_GLHMC_VFCEQPART_PMCEQBASE_SHIFT) +#define I40E_GLHMC_VFCEQPART_PMCEQSIZE_SHIFT 16 +#define I40E_GLHMC_VFCEQPART_PMCEQSIZE_MASK I40E_MASK(0x1FF, I40E_GLHMC_VFCEQPART_PMCEQSIZE_SHIFT) +#define I40E_GLHMC_VFDBCQPART(_i) (0x00132140 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFDBCQPART_MAX_INDEX 31 +#define I40E_GLHMC_VFDBCQPART_PMDBCQBASE_SHIFT 0 +#define I40E_GLHMC_VFDBCQPART_PMDBCQBASE_MASK I40E_MASK(0x3FFF, I40E_GLHMC_VFDBCQPART_PMDBCQBASE_SHIFT) +#define I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_SHIFT 16 +#define I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_MASK I40E_MASK(0x7FFF, I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_SHIFT) +#define I40E_GLHMC_VFDBQPPART(_i) (0x00138E00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFDBQPPART_MAX_INDEX 31 +#define I40E_GLHMC_VFDBQPPART_PMDBQPBASE_SHIFT 0 +#define I40E_GLHMC_VFDBQPPART_PMDBQPBASE_MASK I40E_MASK(0x3FFF, I40E_GLHMC_VFDBQPPART_PMDBQPBASE_SHIFT) +#define I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_SHIFT 16 +#define I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_MASK I40E_MASK(0x7FFF, I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_SHIFT) +#define I40E_GLHMC_VFFSIAVBASE(_i) (0x000Cd600 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFFSIAVBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_SHIFT 0 +#define I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_SHIFT) +#define I40E_GLHMC_VFFSIAVCNT(_i) (0x000Cd700 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFFSIAVCNT_MAX_INDEX 31 +#define I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_SHIFT 0 +#define I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_SHIFT) +#define I40E_GLHMC_VFPDINV(_i) (0x000C8300 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPDINV_MAX_INDEX 31 +#define I40E_GLHMC_VFPDINV_PMSDIDX_SHIFT 0 +#define I40E_GLHMC_VFPDINV_PMSDIDX_MASK I40E_MASK(0xFFF, I40E_GLHMC_VFPDINV_PMSDIDX_SHIFT) +#define I40E_GLHMC_VFPDINV_PMSDPARTSEL_SHIFT 15 +#define I40E_GLHMC_VFPDINV_PMSDPARTSEL_MASK I40E_MASK(0x1, I40E_GLHMC_VFPDINV_PMSDPARTSEL_SHIFT) +#define I40E_GLHMC_VFPDINV_PMPDIDX_SHIFT 16 +#define I40E_GLHMC_VFPDINV_PMPDIDX_MASK I40E_MASK(0x1FF, I40E_GLHMC_VFPDINV_PMPDIDX_SHIFT) +#define I40E_GLHMC_VFPEARPBASE(_i) (0x000Cc800 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEARPBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_SHIFT 0 +#define I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_SHIFT) +#define I40E_GLHMC_VFPEARPCNT(_i) (0x000Cc900 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEARPCNT_MAX_INDEX 31 +#define I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_SHIFT 0 +#define I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_SHIFT) +#define I40E_GLHMC_VFPECQBASE(_i) (0x000Cc200 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPECQBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPECQBASE_FPMPECQBASE_SHIFT 0 +#define I40E_GLHMC_VFPECQBASE_FPMPECQBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPECQBASE_FPMPECQBASE_SHIFT) +#define I40E_GLHMC_VFPECQCNT(_i) (0x000Cc300 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPECQCNT_MAX_INDEX 31 +#define I40E_GLHMC_VFPECQCNT_FPMPECQCNT_SHIFT 0 +#define I40E_GLHMC_VFPECQCNT_FPMPECQCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_VFPECQCNT_FPMPECQCNT_SHIFT) +#define I40E_GLHMC_VFPEHTCNT(_i) (0x000Cc700 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEHTCNT_MAX_INDEX 31 +#define I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_SHIFT 0 +#define I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_SHIFT) +#define I40E_GLHMC_VFPEHTEBASE(_i) (0x000Cc600 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEHTEBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_SHIFT 0 +#define I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_SHIFT) +#define I40E_GLHMC_VFPEMRBASE(_i) (0x000Ccc00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEMRBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_SHIFT 0 +#define I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_SHIFT) +#define I40E_GLHMC_VFPEMRCNT(_i) (0x000Ccd00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEMRCNT_MAX_INDEX 31 +#define I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_SHIFT 0 +#define I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_SHIFT) +#define I40E_GLHMC_VFPEPBLBASE(_i) (0x000Cd800 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEPBLBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_SHIFT 0 +#define I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_SHIFT) +#define I40E_GLHMC_VFPEPBLCNT(_i) (0x000Cd900 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEPBLCNT_MAX_INDEX 31 +#define I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_SHIFT 0 +#define I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_SHIFT) +#define I40E_GLHMC_VFPEQ1BASE(_i) (0x000Cd200 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEQ1BASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_SHIFT 0 +#define I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_SHIFT) +#define I40E_GLHMC_VFPEQ1CNT(_i) (0x000Cd300 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEQ1CNT_MAX_INDEX 31 +#define I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_SHIFT 0 +#define I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_SHIFT) +#define I40E_GLHMC_VFPEQ1FLBASE(_i) (0x000Cd400 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEQ1FLBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_SHIFT 0 +#define I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_SHIFT) +#define I40E_GLHMC_VFPEQPBASE(_i) (0x000Cc000 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEQPBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_SHIFT 0 +#define I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_SHIFT) +#define I40E_GLHMC_VFPEQPCNT(_i) (0x000Cc100 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEQPCNT_MAX_INDEX 31 +#define I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_SHIFT 0 +#define I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_SHIFT) +#define I40E_GLHMC_VFPESRQBASE(_i) (0x000Cc400 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPESRQBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_SHIFT 0 +#define I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_SHIFT) +#define I40E_GLHMC_VFPESRQCNT(_i) (0x000Cc500 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPESRQCNT_MAX_INDEX 31 +#define I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_SHIFT 0 +#define I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_SHIFT) +#define I40E_GLHMC_VFPETIMERBASE(_i) (0x000CDA00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPETIMERBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_SHIFT 0 +#define I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_SHIFT) +#define I40E_GLHMC_VFPETIMERCNT(_i) (0x000CDB00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPETIMERCNT_MAX_INDEX 31 +#define I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_SHIFT 0 +#define I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_SHIFT) +#define I40E_GLHMC_VFPEXFBASE(_i) (0x000Cce00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEXFBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_SHIFT 0 +#define I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_SHIFT) +#define I40E_GLHMC_VFPEXFCNT(_i) (0x000Ccf00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEXFCNT_MAX_INDEX 31 +#define I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_SHIFT 0 +#define I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_SHIFT) +#define I40E_GLHMC_VFPEXFFLBASE(_i) (0x000Cd000 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFPEXFFLBASE_MAX_INDEX 31 +#define I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_SHIFT 0 +#define I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_SHIFT) +#define I40E_GLHMC_VFSDPART(_i) (0x000C8800 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLHMC_VFSDPART_MAX_INDEX 31 +#define I40E_GLHMC_VFSDPART_PMSDBASE_SHIFT 0 +#define I40E_GLHMC_VFSDPART_PMSDBASE_MASK I40E_MASK(0xFFF, I40E_GLHMC_VFSDPART_PMSDBASE_SHIFT) +#define I40E_GLHMC_VFSDPART_PMSDSIZE_SHIFT 16 +#define I40E_GLHMC_VFSDPART_PMSDSIZE_MASK I40E_MASK(0x1FFF, I40E_GLHMC_VFSDPART_PMSDSIZE_SHIFT) +#define I40E_GLPBLOC_CACHESIZE 0x000A80BC /* Reset: CORER */ +#define I40E_GLPBLOC_CACHESIZE_WORD_SIZE_SHIFT 0 +#define I40E_GLPBLOC_CACHESIZE_WORD_SIZE_MASK I40E_MASK(0xFF, I40E_GLPBLOC_CACHESIZE_WORD_SIZE_SHIFT) +#define I40E_GLPBLOC_CACHESIZE_SETS_SHIFT 8 +#define I40E_GLPBLOC_CACHESIZE_SETS_MASK I40E_MASK(0xFFF, I40E_GLPBLOC_CACHESIZE_SETS_SHIFT) +#define I40E_GLPBLOC_CACHESIZE_WAYS_SHIFT 20 +#define I40E_GLPBLOC_CACHESIZE_WAYS_MASK I40E_MASK(0xF, I40E_GLPBLOC_CACHESIZE_WAYS_SHIFT) +#define I40E_GLPDOC_CACHESIZE 0x000D0088 /* Reset: CORER */ +#define I40E_GLPDOC_CACHESIZE_WORD_SIZE_SHIFT 0 +#define I40E_GLPDOC_CACHESIZE_WORD_SIZE_MASK I40E_MASK(0xFF, I40E_GLPDOC_CACHESIZE_WORD_SIZE_SHIFT) +#define I40E_GLPDOC_CACHESIZE_SETS_SHIFT 8 +#define I40E_GLPDOC_CACHESIZE_SETS_MASK I40E_MASK(0xFFF, I40E_GLPDOC_CACHESIZE_SETS_SHIFT) +#define I40E_GLPDOC_CACHESIZE_WAYS_SHIFT 20 +#define I40E_GLPDOC_CACHESIZE_WAYS_MASK I40E_MASK(0xF, I40E_GLPDOC_CACHESIZE_WAYS_SHIFT) +#define I40E_GLPEOC_CACHESIZE 0x000A60E8 /* Reset: CORER */ +#define I40E_GLPEOC_CACHESIZE_WORD_SIZE_SHIFT 0 +#define I40E_GLPEOC_CACHESIZE_WORD_SIZE_MASK I40E_MASK(0xFF, I40E_GLPEOC_CACHESIZE_WORD_SIZE_SHIFT) +#define I40E_GLPEOC_CACHESIZE_SETS_SHIFT 8 +#define I40E_GLPEOC_CACHESIZE_SETS_MASK I40E_MASK(0xFFF, I40E_GLPEOC_CACHESIZE_SETS_SHIFT) +#define I40E_GLPEOC_CACHESIZE_WAYS_SHIFT 20 +#define I40E_GLPEOC_CACHESIZE_WAYS_MASK I40E_MASK(0xF, I40E_GLPEOC_CACHESIZE_WAYS_SHIFT) +#define I40E_PFHMC_PDINV_PMSDPARTSEL_SHIFT 15 +#define I40E_PFHMC_PDINV_PMSDPARTSEL_MASK I40E_MASK(0x1, I40E_PFHMC_PDINV_PMSDPARTSEL_SHIFT) +#define I40E_PFHMC_SDCMD_PMSDPARTSEL_SHIFT 15 +#define I40E_PFHMC_SDCMD_PMSDPARTSEL_MASK I40E_MASK(0x1, I40E_PFHMC_SDCMD_PMSDPARTSEL_SHIFT) +#define I40E_GL_PPRS_SPARE 0x000856E0 /* Reset: CORER */ +#define I40E_GL_PPRS_SPARE_GL_PPRS_SPARE_SHIFT 0 +#define I40E_GL_PPRS_SPARE_GL_PPRS_SPARE_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_PPRS_SPARE_GL_PPRS_SPARE_SHIFT) +#define I40E_GL_TLAN_SPARE 0x000E64E0 /* Reset: CORER */ +#define I40E_GL_TLAN_SPARE_GL_TLAN_SPARE_SHIFT 0 +#define I40E_GL_TLAN_SPARE_GL_TLAN_SPARE_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_TLAN_SPARE_GL_TLAN_SPARE_SHIFT) +#define I40E_GL_TUPM_SPARE 0x000a2230 /* Reset: CORER */ +#define I40E_GL_TUPM_SPARE_GL_TUPM_SPARE_SHIFT 0 +#define I40E_GL_TUPM_SPARE_GL_TUPM_SPARE_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_TUPM_SPARE_GL_TUPM_SPARE_SHIFT) +#define I40E_GLGEN_CAR_DEBUG 0x000B81C0 /* Reset: POR */ +#define I40E_GLGEN_CAR_DEBUG_CAR_UPPER_CORE_CLK_EN_SHIFT 0 +#define I40E_GLGEN_CAR_DEBUG_CAR_UPPER_CORE_CLK_EN_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CAR_UPPER_CORE_CLK_EN_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_HIU_CLK_EN_SHIFT 1 +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_HIU_CLK_EN_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CAR_PCIE_HIU_CLK_EN_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CAR_PE_CLK_EN_SHIFT 2 +#define I40E_GLGEN_CAR_DEBUG_CAR_PE_CLK_EN_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CAR_PE_CLK_EN_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_PRIM_CLK_ACTIVE_SHIFT 3 +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_PRIM_CLK_ACTIVE_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CAR_PCIE_PRIM_CLK_ACTIVE_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CDC_PE_ACTIVE_SHIFT 4 +#define I40E_GLGEN_CAR_DEBUG_CDC_PE_ACTIVE_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CDC_PE_ACTIVE_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_PRST_RESET_N_SHIFT 5 +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_PRST_RESET_N_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_PRST_RESET_N_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_SCLR_RESET_N_SHIFT 6 +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_SCLR_RESET_N_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_SCLR_RESET_N_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_IB_RESET_N_SHIFT 7 +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_IB_RESET_N_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_IB_RESET_N_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_IMIB_RESET_N_SHIFT 8 +#define I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_IMIB_RESET_N_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CAR_PCIE_RAW_IMIB_RESET_N_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CAR_RAW_EMP_RESET_N_SHIFT 9 +#define I40E_GLGEN_CAR_DEBUG_CAR_RAW_EMP_RESET_N_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CAR_RAW_EMP_RESET_N_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CAR_RAW_GLOBAL_RESET_N_SHIFT 10 +#define I40E_GLGEN_CAR_DEBUG_CAR_RAW_GLOBAL_RESET_N_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CAR_RAW_GLOBAL_RESET_N_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CAR_RAW_LAN_POWER_GOOD_SHIFT 11 +#define I40E_GLGEN_CAR_DEBUG_CAR_RAW_LAN_POWER_GOOD_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CAR_RAW_LAN_POWER_GOOD_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_CDC_IOSF_PRIMERY_RST_B_SHIFT 12 +#define I40E_GLGEN_CAR_DEBUG_CDC_IOSF_PRIMERY_RST_B_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_CDC_IOSF_PRIMERY_RST_B_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_GBE_GLOBALRST_B_SHIFT 13 +#define I40E_GLGEN_CAR_DEBUG_GBE_GLOBALRST_B_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_GBE_GLOBALRST_B_SHIFT) +#define I40E_GLGEN_CAR_DEBUG_FLEEP_AL_GLOBR_DONE_SHIFT 14 +#define I40E_GLGEN_CAR_DEBUG_FLEEP_AL_GLOBR_DONE_MASK I40E_MASK(0x1, I40E_GLGEN_CAR_DEBUG_FLEEP_AL_GLOBR_DONE_SHIFT) +#define I40E_GLGEN_MISC_SPARE 0x000880E0 /* Reset: POR */ +#define I40E_GLGEN_MISC_SPARE_GLGEN_MISC_SPARE_SHIFT 0 +#define I40E_GLGEN_MISC_SPARE_GLGEN_MISC_SPARE_MASK I40E_MASK(0xFFFFFFFF, I40E_GLGEN_MISC_SPARE_GLGEN_MISC_SPARE_SHIFT) +#define I40E_GL_UFUSE_SOC 0x000BE550 /* Reset: POR */ +#define I40E_GL_UFUSE_SOC_PORT_MODE_SHIFT 0 +#define I40E_GL_UFUSE_SOC_PORT_MODE_MASK I40E_MASK(0x3, I40E_GL_UFUSE_SOC_PORT_MODE_SHIFT) +#define I40E_GL_UFUSE_SOC_NIC_ID_SHIFT 2 +#define I40E_GL_UFUSE_SOC_NIC_ID_MASK I40E_MASK(0x1, I40E_GL_UFUSE_SOC_NIC_ID_SHIFT) +#define I40E_GL_UFUSE_SOC_SPARE_FUSES_SHIFT 3 +#define I40E_GL_UFUSE_SOC_SPARE_FUSES_MASK I40E_MASK(0x1FFF, I40E_GL_UFUSE_SOC_SPARE_FUSES_SHIFT) +#define I40E_PFINT_DYN_CTL0_WB_ON_ITR_SHIFT 30 +#define I40E_PFINT_DYN_CTL0_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_WB_ON_ITR_SHIFT) +#define I40E_PFINT_DYN_CTLN_WB_ON_ITR_SHIFT 30 +#define I40E_PFINT_DYN_CTLN_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_WB_ON_ITR_SHIFT) +#define I40E_VFINT_DYN_CTL0_WB_ON_ITR_SHIFT 30 +#define I40E_VFINT_DYN_CTL0_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_WB_ON_ITR_SHIFT) +#define I40E_VFINT_DYN_CTLN_WB_ON_ITR_SHIFT 30 +#define I40E_VFINT_DYN_CTLN_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_WB_ON_ITR_SHIFT) +#define I40E_VPLAN_QBASE(_VF) (0x00074800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VPLAN_QBASE_MAX_INDEX 127 +#define I40E_VPLAN_QBASE_VFFIRSTQ_SHIFT 0 +#define I40E_VPLAN_QBASE_VFFIRSTQ_MASK I40E_MASK(0x7FF, I40E_VPLAN_QBASE_VFFIRSTQ_SHIFT) +#define I40E_VPLAN_QBASE_VFNUMQ_SHIFT 11 +#define I40E_VPLAN_QBASE_VFNUMQ_MASK I40E_MASK(0xFF, I40E_VPLAN_QBASE_VFNUMQ_SHIFT) +#define I40E_VPLAN_QBASE_VFQTABLE_ENA_SHIFT 31 +#define I40E_VPLAN_QBASE_VFQTABLE_ENA_MASK I40E_MASK(0x1, I40E_VPLAN_QBASE_VFQTABLE_ENA_SHIFT) +#define I40E_PRTMAC_LINK_DOWN_COUNTER 0x001E2440 /* Reset: GLOBR */ +#define I40E_PRTMAC_LINK_DOWN_COUNTER_LINK_DOWN_COUNTER_SHIFT 0 +#define I40E_PRTMAC_LINK_DOWN_COUNTER_LINK_DOWN_COUNTER_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_LINK_DOWN_COUNTER_LINK_DOWN_COUNTER_SHIFT) +#define I40E_GLNVM_AL_REQ 0x000B6164 /* Reset: POR */ +#define I40E_GLNVM_AL_REQ_POR_SHIFT 0 +#define I40E_GLNVM_AL_REQ_POR_MASK I40E_MASK(0x1, I40E_GLNVM_AL_REQ_POR_SHIFT) +#define I40E_GLNVM_AL_REQ_PCIE_IMIB_SHIFT 1 +#define I40E_GLNVM_AL_REQ_PCIE_IMIB_MASK I40E_MASK(0x1, I40E_GLNVM_AL_REQ_PCIE_IMIB_SHIFT) +#define I40E_GLNVM_AL_REQ_GLOBR_SHIFT 2 +#define I40E_GLNVM_AL_REQ_GLOBR_MASK I40E_MASK(0x1, I40E_GLNVM_AL_REQ_GLOBR_SHIFT) +#define I40E_GLNVM_AL_REQ_CORER_SHIFT 3 +#define I40E_GLNVM_AL_REQ_CORER_MASK I40E_MASK(0x1, I40E_GLNVM_AL_REQ_CORER_SHIFT) +#define I40E_GLNVM_AL_REQ_PE_SHIFT 4 +#define I40E_GLNVM_AL_REQ_PE_MASK I40E_MASK(0x1, I40E_GLNVM_AL_REQ_PE_SHIFT) +#define I40E_GLNVM_AL_REQ_PCIE_IMIB_ASSERT_SHIFT 5 +#define I40E_GLNVM_AL_REQ_PCIE_IMIB_ASSERT_MASK I40E_MASK(0x1, I40E_GLNVM_AL_REQ_PCIE_IMIB_ASSERT_SHIFT) +#define I40E_GLNVM_ALTIMERS 0x000B6140 /* Reset: POR */ +#define I40E_GLNVM_ALTIMERS_PCI_ALTIMER_SHIFT 0 +#define I40E_GLNVM_ALTIMERS_PCI_ALTIMER_MASK I40E_MASK(0xFFF, I40E_GLNVM_ALTIMERS_PCI_ALTIMER_SHIFT) +#define I40E_GLNVM_ALTIMERS_GEN_ALTIMER_SHIFT 12 +#define I40E_GLNVM_ALTIMERS_GEN_ALTIMER_MASK I40E_MASK(0xFFFFF, I40E_GLNVM_ALTIMERS_GEN_ALTIMER_SHIFT) +#define I40E_GLNVM_FLA 0x000B6108 /* Reset: POR */ +#define I40E_GLNVM_FLA_LOCKED_SHIFT 6 +#define I40E_GLNVM_FLA_LOCKED_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_LOCKED_SHIFT) + +#define I40E_GLNVM_ULD 0x000B6008 /* Reset: POR */ +#define I40E_GLNVM_ULD_PCIER_DONE_SHIFT 0 +#define I40E_GLNVM_ULD_PCIER_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_PCIER_DONE_SHIFT) +#define I40E_GLNVM_ULD_PCIER_DONE_1_SHIFT 1 +#define I40E_GLNVM_ULD_PCIER_DONE_1_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_PCIER_DONE_1_SHIFT) +#define I40E_GLNVM_ULD_CORER_DONE_SHIFT 3 +#define I40E_GLNVM_ULD_CORER_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CORER_DONE_SHIFT) +#define I40E_GLNVM_ULD_GLOBR_DONE_SHIFT 4 +#define I40E_GLNVM_ULD_GLOBR_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_GLOBR_DONE_SHIFT) +#define I40E_GLNVM_ULD_POR_DONE_SHIFT 5 +#define I40E_GLNVM_ULD_POR_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_POR_DONE_SHIFT) +#define I40E_GLNVM_ULD_POR_DONE_1_SHIFT 8 +#define I40E_GLNVM_ULD_POR_DONE_1_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_POR_DONE_1_SHIFT) +#define I40E_GLNVM_ULD_PCIER_DONE_2_SHIFT 9 +#define I40E_GLNVM_ULD_PCIER_DONE_2_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_PCIER_DONE_2_SHIFT) +#define I40E_GLNVM_ULD_PE_DONE_SHIFT 10 +#define I40E_GLNVM_ULD_PE_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_PE_DONE_SHIFT) +#define I40E_GLNVM_ULT 0x000B6154 /* Reset: POR */ +#define I40E_GLNVM_ULT_CONF_PCIR_AE_SHIFT 0 +#define I40E_GLNVM_ULT_CONF_PCIR_AE_MASK I40E_MASK(0x1, I40E_GLNVM_ULT_CONF_PCIR_AE_SHIFT) +#define I40E_GLNVM_ULT_CONF_PCIRTL_AE_SHIFT 1 +#define I40E_GLNVM_ULT_CONF_PCIRTL_AE_MASK I40E_MASK(0x1, I40E_GLNVM_ULT_CONF_PCIRTL_AE_SHIFT) +#define I40E_GLNVM_ULT_RESERVED_1_SHIFT 2 +#define I40E_GLNVM_ULT_RESERVED_1_MASK I40E_MASK(0x1, I40E_GLNVM_ULT_RESERVED_1_SHIFT) +#define I40E_GLNVM_ULT_CONF_CORE_AE_SHIFT 3 +#define I40E_GLNVM_ULT_CONF_CORE_AE_MASK I40E_MASK(0x1, I40E_GLNVM_ULT_CONF_CORE_AE_SHIFT) +#define I40E_GLNVM_ULT_CONF_GLOBAL_AE_SHIFT 4 +#define I40E_GLNVM_ULT_CONF_GLOBAL_AE_MASK I40E_MASK(0x1, I40E_GLNVM_ULT_CONF_GLOBAL_AE_SHIFT) +#define I40E_GLNVM_ULT_CONF_POR_AE_SHIFT 5 +#define I40E_GLNVM_ULT_CONF_POR_AE_MASK I40E_MASK(0x1, I40E_GLNVM_ULT_CONF_POR_AE_SHIFT) +#define I40E_GLNVM_ULT_RESERVED_2_SHIFT 6 +#define I40E_GLNVM_ULT_RESERVED_2_MASK I40E_MASK(0x1, I40E_GLNVM_ULT_RESERVED_2_SHIFT) +#define I40E_GLNVM_ULT_RESERVED_3_SHIFT 7 +#define I40E_GLNVM_ULT_RESERVED_3_MASK I40E_MASK(0x1, I40E_GLNVM_ULT_RESERVED_3_SHIFT) +#define I40E_GLNVM_ULT_CONF_EMP_AE_SHIFT 8 +#define I40E_GLNVM_ULT_CONF_EMP_AE_MASK I40E_MASK(0x1, I40E_GLNVM_ULT_CONF_EMP_AE_SHIFT) +#define I40E_GLNVM_ULT_CONF_PCIALT_AE_SHIFT 9 +#define I40E_GLNVM_ULT_CONF_PCIALT_AE_MASK I40E_MASK(0x1, I40E_GLNVM_ULT_CONF_PCIALT_AE_SHIFT) +#define I40E_GLNVM_ULT_RESERVED_4_SHIFT 10 +#define I40E_GLNVM_ULT_RESERVED_4_MASK I40E_MASK(0x3FFFFF, I40E_GLNVM_ULT_RESERVED_4_SHIFT) +#define I40E_MEM_INIT_DONE_STAT 0x000B615C /* Reset: POR */ +#define I40E_MEM_INIT_DONE_STAT_CMLAN_MEM_INIT_DONE_SHIFT 0 +#define I40E_MEM_INIT_DONE_STAT_CMLAN_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_CMLAN_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_PMAT_MEM_INIT_DONE_SHIFT 1 +#define I40E_MEM_INIT_DONE_STAT_PMAT_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_PMAT_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_RCU_MEM_INIT_DONE_SHIFT 2 +#define I40E_MEM_INIT_DONE_STAT_RCU_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_RCU_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_TDPU_MEM_INIT_DONE_SHIFT 3 +#define I40E_MEM_INIT_DONE_STAT_TDPU_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_TDPU_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_TLAN_MEM_INIT_DONE_SHIFT 4 +#define I40E_MEM_INIT_DONE_STAT_TLAN_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_TLAN_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_RLAN_MEM_INIT_DONE_SHIFT 5 +#define I40E_MEM_INIT_DONE_STAT_RLAN_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_RLAN_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_RDPU_MEM_INIT_DONE_SHIFT 6 +#define I40E_MEM_INIT_DONE_STAT_RDPU_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_RDPU_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_PPRS_MEM_INIT_DONE_SHIFT 7 +#define I40E_MEM_INIT_DONE_STAT_PPRS_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_PPRS_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_RPB_MEM_INIT_DONE_SHIFT 8 +#define I40E_MEM_INIT_DONE_STAT_RPB_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_RPB_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_TPB_MEM_INIT_DONE_SHIFT 9 +#define I40E_MEM_INIT_DONE_STAT_TPB_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_TPB_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_FOC_MEM_INIT_DONE_SHIFT 10 +#define I40E_MEM_INIT_DONE_STAT_FOC_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_FOC_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_TSCD_MEM_INIT_DONE_SHIFT 11 +#define I40E_MEM_INIT_DONE_STAT_TSCD_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_TSCD_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_TCB_MEM_INIT_DONE_SHIFT 12 +#define I40E_MEM_INIT_DONE_STAT_TCB_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_TCB_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_RCB_MEM_INIT_DONE_SHIFT 13 +#define I40E_MEM_INIT_DONE_STAT_RCB_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_RCB_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_WUC_MEM_INIT_DONE_SHIFT 14 +#define I40E_MEM_INIT_DONE_STAT_WUC_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_WUC_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_STAT_MEM_INIT_DONE_SHIFT 15 +#define I40E_MEM_INIT_DONE_STAT_STAT_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_STAT_MEM_INIT_DONE_SHIFT) +#define I40E_MEM_INIT_DONE_STAT_ITR_MEM_INIT_DONE_SHIFT 16 +#define I40E_MEM_INIT_DONE_STAT_ITR_MEM_INIT_DONE_MASK I40E_MASK(0x1, I40E_MEM_INIT_DONE_STAT_ITR_MEM_INIT_DONE_SHIFT) +#define I40E_MNGSB_DADD 0x000B7030 /* Reset: POR */ +#define I40E_MNGSB_DADD_ADDR_SHIFT 0 +#define I40E_MNGSB_DADD_ADDR_MASK I40E_MASK(0xFFFFFFFF, I40E_MNGSB_DADD_ADDR_SHIFT) +#define I40E_MNGSB_DCNT 0x000B7034 /* Reset: POR */ +#define I40E_MNGSB_DCNT_BYTE_CNT_SHIFT 0 +#define I40E_MNGSB_DCNT_BYTE_CNT_MASK I40E_MASK(0xFFFFFFFF, I40E_MNGSB_DCNT_BYTE_CNT_SHIFT) +#define I40E_MNGSB_MSGCTL 0x000B7020 /* Reset: POR */ +#define I40E_MNGSB_MSGCTL_HDR_DWS_SHIFT 0 +#define I40E_MNGSB_MSGCTL_HDR_DWS_MASK I40E_MASK(0x3, I40E_MNGSB_MSGCTL_HDR_DWS_SHIFT) +#define I40E_MNGSB_MSGCTL_EXP_RDW_SHIFT 8 +#define I40E_MNGSB_MSGCTL_EXP_RDW_MASK I40E_MASK(0x1FF, I40E_MNGSB_MSGCTL_EXP_RDW_SHIFT) +#define I40E_MNGSB_MSGCTL_MSG_MODE_SHIFT 26 +#define I40E_MNGSB_MSGCTL_MSG_MODE_MASK I40E_MASK(0x3, I40E_MNGSB_MSGCTL_MSG_MODE_SHIFT) +#define I40E_MNGSB_MSGCTL_TOKEN_MODE_SHIFT 28 +#define I40E_MNGSB_MSGCTL_TOKEN_MODE_MASK I40E_MASK(0x3, I40E_MNGSB_MSGCTL_TOKEN_MODE_SHIFT) +#define I40E_MNGSB_MSGCTL_BARCLR_SHIFT 30 +#define I40E_MNGSB_MSGCTL_BARCLR_MASK I40E_MASK(0x1, I40E_MNGSB_MSGCTL_BARCLR_SHIFT) +#define I40E_MNGSB_MSGCTL_CMDV_SHIFT 31 +#define I40E_MNGSB_MSGCTL_CMDV_MASK I40E_MASK(0x1, I40E_MNGSB_MSGCTL_CMDV_SHIFT) +#define I40E_MNGSB_RDATA 0x000B7300 /* Reset: POR */ +#define I40E_MNGSB_RDATA_DATA_SHIFT 0 +#define I40E_MNGSB_RDATA_DATA_MASK I40E_MASK(0xFFFFFFFF, I40E_MNGSB_RDATA_DATA_SHIFT) +#define I40E_MNGSB_RHDR0 0x000B72FC /* Reset: POR */ +#define I40E_MNGSB_RHDR0_DESTINATION_SHIFT 0 +#define I40E_MNGSB_RHDR0_DESTINATION_MASK I40E_MASK(0xFF, I40E_MNGSB_RHDR0_DESTINATION_SHIFT) +#define I40E_MNGSB_RHDR0_SOURCE_SHIFT 8 +#define I40E_MNGSB_RHDR0_SOURCE_MASK I40E_MASK(0xFF, I40E_MNGSB_RHDR0_SOURCE_SHIFT) +#define I40E_MNGSB_RHDR0_OPCODE_SHIFT 16 +#define I40E_MNGSB_RHDR0_OPCODE_MASK I40E_MASK(0xFF, I40E_MNGSB_RHDR0_OPCODE_SHIFT) +#define I40E_MNGSB_RHDR0_TAG_SHIFT 24 +#define I40E_MNGSB_RHDR0_TAG_MASK I40E_MASK(0x7, I40E_MNGSB_RHDR0_TAG_SHIFT) +#define I40E_MNGSB_RHDR0_RESPONSE_SHIFT 27 +#define I40E_MNGSB_RHDR0_RESPONSE_MASK I40E_MASK(0x7, I40E_MNGSB_RHDR0_RESPONSE_SHIFT) +#define I40E_MNGSB_RHDR0_EH_SHIFT 31 +#define I40E_MNGSB_RHDR0_EH_MASK I40E_MASK(0x1, I40E_MNGSB_RHDR0_EH_SHIFT) +#define I40E_MNGSB_RSPCTL 0x000B7024 /* Reset: POR */ +#define I40E_MNGSB_RSPCTL_DMA_MSG_DWORDS_SHIFT 0 +#define I40E_MNGSB_RSPCTL_DMA_MSG_DWORDS_MASK I40E_MASK(0x1FF, I40E_MNGSB_RSPCTL_DMA_MSG_DWORDS_SHIFT) +#define I40E_MNGSB_RSPCTL_RSP_MODE_SHIFT 26 +#define I40E_MNGSB_RSPCTL_RSP_MODE_MASK I40E_MASK(0x3, I40E_MNGSB_RSPCTL_RSP_MODE_SHIFT) +#define I40E_MNGSB_RSPCTL_RSP_BAD_LEN_SHIFT 30 +#define I40E_MNGSB_RSPCTL_RSP_BAD_LEN_MASK I40E_MASK(0x1, I40E_MNGSB_RSPCTL_RSP_BAD_LEN_SHIFT) +#define I40E_MNGSB_RSPCTL_RSP_ERR_SHIFT 31 +#define I40E_MNGSB_RSPCTL_RSP_ERR_MASK I40E_MASK(0x1, I40E_MNGSB_RSPCTL_RSP_ERR_SHIFT) +#define I40E_MNGSB_WDATA 0x000B7100 /* Reset: POR */ +#define I40E_MNGSB_WDATA_DATA_SHIFT 0 +#define I40E_MNGSB_WDATA_DATA_MASK I40E_MASK(0xFFFFFFFF, I40E_MNGSB_WDATA_DATA_SHIFT) +#define I40E_MNGSB_WHDR0 0x000B70F4 /* Reset: POR */ +#define I40E_MNGSB_WHDR0_RAW_DEST_SHIFT 0 +#define I40E_MNGSB_WHDR0_RAW_DEST_MASK I40E_MASK(0xFF, I40E_MNGSB_WHDR0_RAW_DEST_SHIFT) +#define I40E_MNGSB_WHDR0_DEST_SEL_SHIFT 12 +#define I40E_MNGSB_WHDR0_DEST_SEL_MASK I40E_MASK(0xF, I40E_MNGSB_WHDR0_DEST_SEL_SHIFT) +#define I40E_MNGSB_WHDR0_OPCODE_SEL_SHIFT 16 +#define I40E_MNGSB_WHDR0_OPCODE_SEL_MASK I40E_MASK(0xFF, I40E_MNGSB_WHDR0_OPCODE_SEL_SHIFT) +#define I40E_MNGSB_WHDR0_TAG_SHIFT 24 +#define I40E_MNGSB_WHDR0_TAG_MASK I40E_MASK(0x7F, I40E_MNGSB_WHDR0_TAG_SHIFT) +#define I40E_MNGSB_WHDR1 0x000B70F8 /* Reset: POR */ +#define I40E_MNGSB_WHDR1_ADDR_SHIFT 0 +#define I40E_MNGSB_WHDR1_ADDR_MASK I40E_MASK(0xFFFFFFFF, I40E_MNGSB_WHDR1_ADDR_SHIFT) +#define I40E_MNGSB_WHDR2 0x000B70FC /* Reset: POR */ +#define I40E_MNGSB_WHDR2_LENGTH_SHIFT 0 +#define I40E_MNGSB_WHDR2_LENGTH_MASK I40E_MASK(0xFFFFFFFF, I40E_MNGSB_WHDR2_LENGTH_SHIFT) + +#define I40E_GLPCI_CAPSUP_WAKUP_EN_SHIFT 21 +#define I40E_GLPCI_CAPSUP_WAKUP_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_WAKUP_EN_SHIFT) + +#define I40E_GLPCI_CUR_CLNT_COMMON 0x0009CA18 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_CLNT_COMMON_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_CLNT_COMMON_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_CLNT_COMMON_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_CLNT_COMMON_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_CLNT_COMMON_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_CLNT_COMMON_OSR_SHIFT) +#define I40E_GLPCI_CUR_CLNT_PIPEMON 0x0009CA20 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_CLNT_PIPEMON_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_CLNT_PIPEMON_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_CLNT_PIPEMON_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_MNG_ALWD 0x0009c514 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_MNG_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_MNG_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_MNG_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_MNG_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_MNG_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_MNG_ALWD_OSR_SHIFT) +#define I40E_GLPCI_CUR_MNG_RSVD 0x0009c594 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_MNG_RSVD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_MNG_RSVD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_MNG_RSVD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_MNG_RSVD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_MNG_RSVD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_MNG_RSVD_OSR_SHIFT) +#define I40E_GLPCI_CUR_PMAT_ALWD 0x0009c510 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_PMAT_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_PMAT_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_PMAT_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_PMAT_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_PMAT_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_PMAT_ALWD_OSR_SHIFT) +#define I40E_GLPCI_CUR_PMAT_RSVD 0x0009c590 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_PMAT_RSVD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_PMAT_RSVD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_PMAT_RSVD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_PMAT_RSVD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_PMAT_RSVD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_PMAT_RSVD_OSR_SHIFT) +#define I40E_GLPCI_CUR_RLAN_ALWD 0x0009c500 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_RLAN_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_RLAN_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_RLAN_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_RLAN_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_RLAN_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_RLAN_ALWD_OSR_SHIFT) +#define I40E_GLPCI_CUR_RLAN_RSVD 0x0009c580 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_RLAN_RSVD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_RLAN_RSVD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_RLAN_RSVD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_RLAN_RSVD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_RLAN_RSVD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_RLAN_RSVD_OSR_SHIFT) +#define I40E_GLPCI_CUR_RXPE_ALWD 0x0009c508 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_RXPE_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_RXPE_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_RXPE_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_RXPE_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_RXPE_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_RXPE_ALWD_OSR_SHIFT) +#define I40E_GLPCI_CUR_RXPE_RSVD 0x0009c588 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_RXPE_RSVD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_RXPE_RSVD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_RXPE_RSVD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_RXPE_RSVD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_RXPE_RSVD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_RXPE_RSVD_OSR_SHIFT) +#define I40E_GLPCI_CUR_TDPU_ALWD 0x0009c518 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_TDPU_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_TDPU_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TDPU_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_TDPU_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_TDPU_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TDPU_ALWD_OSR_SHIFT) +#define I40E_GLPCI_CUR_TDPU_RSVD 0x0009c598 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_TDPU_RSVD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_TDPU_RSVD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TDPU_RSVD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_TDPU_RSVD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_TDPU_RSVD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TDPU_RSVD_OSR_SHIFT) +#define I40E_GLPCI_CUR_TLAN_ALWD 0x0009c504 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_TLAN_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_TLAN_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TLAN_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_TLAN_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_TLAN_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TLAN_ALWD_OSR_SHIFT) +#define I40E_GLPCI_CUR_TLAN_RSVD 0x0009c584 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_TLAN_RSVD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_TLAN_RSVD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TLAN_RSVD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_TLAN_RSVD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_TLAN_RSVD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TLAN_RSVD_OSR_SHIFT) +#define I40E_GLPCI_CUR_TXPE_ALWD 0x0009c50C /* Reset: PCIR */ +#define I40E_GLPCI_CUR_TXPE_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_TXPE_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TXPE_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_TXPE_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_TXPE_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TXPE_ALWD_OSR_SHIFT) +#define I40E_GLPCI_CUR_TXPE_RSVD 0x0009c58c /* Reset: PCIR */ +#define I40E_GLPCI_CUR_TXPE_RSVD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_TXPE_RSVD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TXPE_RSVD_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_TXPE_RSVD_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_TXPE_RSVD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_TXPE_RSVD_OSR_SHIFT) +#define I40E_GLPCI_CUR_WATMK_CLNT_COMMON 0x0009CA28 /* Reset: PCIR */ +#define I40E_GLPCI_CUR_WATMK_CLNT_COMMON_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_CUR_WATMK_CLNT_COMMON_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_WATMK_CLNT_COMMON_DATA_LINES_SHIFT) +#define I40E_GLPCI_CUR_WATMK_CLNT_COMMON_OSR_SHIFT 16 +#define I40E_GLPCI_CUR_WATMK_CLNT_COMMON_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_CUR_WATMK_CLNT_COMMON_OSR_SHIFT) + +#define I40E_GLPCI_LBARCTRL_PE_DB_SIZE_SHIFT 4 +#define I40E_GLPCI_LBARCTRL_PE_DB_SIZE_MASK I40E_MASK(0x3, I40E_GLPCI_LBARCTRL_PE_DB_SIZE_SHIFT) +#define I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_SHIFT 10 +#define I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_SHIFT) +#define I40E_GLPCI_NPQ_CFG 0x0009CA00 /* Reset: PCIR */ +#define I40E_GLPCI_NPQ_CFG_EXTEND_TO_SHIFT 0 +#define I40E_GLPCI_NPQ_CFG_EXTEND_TO_MASK I40E_MASK(0x1, I40E_GLPCI_NPQ_CFG_EXTEND_TO_SHIFT) +#define I40E_GLPCI_NPQ_CFG_SMALL_TO_SHIFT 1 +#define I40E_GLPCI_NPQ_CFG_SMALL_TO_MASK I40E_MASK(0x1, I40E_GLPCI_NPQ_CFG_SMALL_TO_SHIFT) +#define I40E_GLPCI_NPQ_CFG_WEIGHT_AVG_SHIFT 2 +#define I40E_GLPCI_NPQ_CFG_WEIGHT_AVG_MASK I40E_MASK(0xF, I40E_GLPCI_NPQ_CFG_WEIGHT_AVG_SHIFT) +#define I40E_GLPCI_NPQ_CFG_NPQ_SPARE_SHIFT 6 +#define I40E_GLPCI_NPQ_CFG_NPQ_SPARE_MASK I40E_MASK(0x3FF, I40E_GLPCI_NPQ_CFG_NPQ_SPARE_SHIFT) +#define I40E_GLPCI_NPQ_CFG_NPQ_ERR_STAT_SHIFT 16 +#define I40E_GLPCI_NPQ_CFG_NPQ_ERR_STAT_MASK I40E_MASK(0xF, I40E_GLPCI_NPQ_CFG_NPQ_ERR_STAT_SHIFT) +#define I40E_GLPCI_WATMK_CLNT_PIPEMON 0x0009CA30 /* Reset: PCIR */ +#define I40E_GLPCI_WATMK_CLNT_PIPEMON_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_WATMK_CLNT_PIPEMON_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_CLNT_PIPEMON_DATA_LINES_SHIFT) +#define I40E_GLPCI_WATMK_MNG_ALWD 0x0009CB14 /* Reset: PCIR */ +#define I40E_GLPCI_WATMK_MNG_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_WATMK_MNG_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_MNG_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_WATMK_MNG_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_WATMK_MNG_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_MNG_ALWD_OSR_SHIFT) +#define I40E_GLPCI_WATMK_PMAT_ALWD 0x0009CB10 /* Reset: PCIR */ +#define I40E_GLPCI_WATMK_PMAT_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_WATMK_PMAT_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_PMAT_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_WATMK_PMAT_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_WATMK_PMAT_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_PMAT_ALWD_OSR_SHIFT) +#define I40E_GLPCI_WATMK_RLAN_ALWD 0x0009CB00 /* Reset: PCIR */ +#define I40E_GLPCI_WATMK_RLAN_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_WATMK_RLAN_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_RLAN_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_WATMK_RLAN_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_WATMK_RLAN_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_RLAN_ALWD_OSR_SHIFT) +#define I40E_GLPCI_WATMK_RXPE_ALWD 0x0009CB08 /* Reset: PCIR */ +#define I40E_GLPCI_WATMK_RXPE_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_WATMK_RXPE_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_RXPE_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_WATMK_RXPE_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_WATMK_RXPE_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_RXPE_ALWD_OSR_SHIFT) +#define I40E_GLPCI_WATMK_TLAN_ALWD 0x0009CB04 /* Reset: PCIR */ +#define I40E_GLPCI_WATMK_TLAN_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_WATMK_TLAN_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_TLAN_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_WATMK_TLAN_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_WATMK_TLAN_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_TLAN_ALWD_OSR_SHIFT) +#define I40E_GLPCI_WATMK_TPDU_ALWD 0x0009CB18 /* Reset: PCIR */ +#define I40E_GLPCI_WATMK_TPDU_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_WATMK_TPDU_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_TPDU_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_WATMK_TPDU_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_WATMK_TPDU_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_TPDU_ALWD_OSR_SHIFT) +#define I40E_GLPCI_WATMK_TXPE_ALWD 0x0009CB0c /* Reset: PCIR */ +#define I40E_GLPCI_WATMK_TXPE_ALWD_DATA_LINES_SHIFT 0 +#define I40E_GLPCI_WATMK_TXPE_ALWD_DATA_LINES_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_TXPE_ALWD_DATA_LINES_SHIFT) +#define I40E_GLPCI_WATMK_TXPE_ALWD_OSR_SHIFT 16 +#define I40E_GLPCI_WATMK_TXPE_ALWD_OSR_MASK I40E_MASK(0xFFFF, I40E_GLPCI_WATMK_TXPE_ALWD_OSR_SHIFT) +#define I40E_GLPE_CPUSTATUS0 0x0000D040 /* Reset: PE_CORER */ +#define I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_SHIFT 0 +#define I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_SHIFT) +#define I40E_GLPE_CPUSTATUS1 0x0000D044 /* Reset: PE_CORER */ +#define I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_SHIFT 0 +#define I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_SHIFT) +#define I40E_GLPE_CPUSTATUS2 0x0000D048 /* Reset: PE_CORER */ +#define I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_SHIFT 0 +#define I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_SHIFT) +#define I40E_GLPE_CPUTRIG0 0x0000D060 /* Reset: PE_CORER */ +#define I40E_GLPE_CPUTRIG0_PECPUTRIG0_SHIFT 0 +#define I40E_GLPE_CPUTRIG0_PECPUTRIG0_MASK I40E_MASK(0xFFFF, I40E_GLPE_CPUTRIG0_PECPUTRIG0_SHIFT) +#define I40E_GLPE_CPUTRIG0_TEPREQUEST0_SHIFT 17 +#define I40E_GLPE_CPUTRIG0_TEPREQUEST0_MASK I40E_MASK(0x1, I40E_GLPE_CPUTRIG0_TEPREQUEST0_SHIFT) +#define I40E_GLPE_CPUTRIG0_OOPREQUEST0_SHIFT 18 +#define I40E_GLPE_CPUTRIG0_OOPREQUEST0_MASK I40E_MASK(0x1, I40E_GLPE_CPUTRIG0_OOPREQUEST0_SHIFT) +#define I40E_GLPE_DUAL40_RUPM 0x0000DA04 /* Reset: PE_CORER */ +#define I40E_GLPE_DUAL40_RUPM_DUAL_40G_MODE_SHIFT 0 +#define I40E_GLPE_DUAL40_RUPM_DUAL_40G_MODE_MASK I40E_MASK(0x1, I40E_GLPE_DUAL40_RUPM_DUAL_40G_MODE_SHIFT) +#define I40E_GLPE_PFAEQEDROPCNT(_i) (0x00131440 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLPE_PFAEQEDROPCNT_MAX_INDEX 15 +#define I40E_GLPE_PFAEQEDROPCNT_AEQEDROPCNT_SHIFT 0 +#define I40E_GLPE_PFAEQEDROPCNT_AEQEDROPCNT_MASK I40E_MASK(0xFFFF, I40E_GLPE_PFAEQEDROPCNT_AEQEDROPCNT_SHIFT) +#define I40E_GLPE_PFCEQEDROPCNT(_i) (0x001313C0 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLPE_PFCEQEDROPCNT_MAX_INDEX 15 +#define I40E_GLPE_PFCEQEDROPCNT_CEQEDROPCNT_SHIFT 0 +#define I40E_GLPE_PFCEQEDROPCNT_CEQEDROPCNT_MASK I40E_MASK(0xFFFF, I40E_GLPE_PFCEQEDROPCNT_CEQEDROPCNT_SHIFT) +#define I40E_GLPE_PFCQEDROPCNT(_i) (0x00131340 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ +#define I40E_GLPE_PFCQEDROPCNT_MAX_INDEX 15 +#define I40E_GLPE_PFCQEDROPCNT_CQEDROPCNT_SHIFT 0 +#define I40E_GLPE_PFCQEDROPCNT_CQEDROPCNT_MASK I40E_MASK(0xFFFF, I40E_GLPE_PFCQEDROPCNT_CQEDROPCNT_SHIFT) +#define I40E_GLPE_RUPM_CQPPOOL 0x0000DACC /* Reset: PE_CORER */ +#define I40E_GLPE_RUPM_CQPPOOL_CQPSPADS_SHIFT 0 +#define I40E_GLPE_RUPM_CQPPOOL_CQPSPADS_MASK I40E_MASK(0xFF, I40E_GLPE_RUPM_CQPPOOL_CQPSPADS_SHIFT) +#define I40E_GLPE_RUPM_FLRPOOL 0x0000DAC4 /* Reset: PE_CORER */ +#define I40E_GLPE_RUPM_FLRPOOL_FLRSPADS_SHIFT 0 +#define I40E_GLPE_RUPM_FLRPOOL_FLRSPADS_MASK I40E_MASK(0xFF, I40E_GLPE_RUPM_FLRPOOL_FLRSPADS_SHIFT) +#define I40E_GLPE_RUPM_GCTL 0x0000DA00 /* Reset: PE_CORER */ +#define I40E_GLPE_RUPM_GCTL_ALLOFFTH_SHIFT 0 +#define I40E_GLPE_RUPM_GCTL_ALLOFFTH_MASK I40E_MASK(0xFF, I40E_GLPE_RUPM_GCTL_ALLOFFTH_SHIFT) +#define I40E_GLPE_RUPM_GCTL_RUPM_P0_DIS_SHIFT 26 +#define I40E_GLPE_RUPM_GCTL_RUPM_P0_DIS_MASK I40E_MASK(0x1, I40E_GLPE_RUPM_GCTL_RUPM_P0_DIS_SHIFT) +#define I40E_GLPE_RUPM_GCTL_RUPM_P1_DIS_SHIFT 27 +#define I40E_GLPE_RUPM_GCTL_RUPM_P1_DIS_MASK I40E_MASK(0x1, I40E_GLPE_RUPM_GCTL_RUPM_P1_DIS_SHIFT) +#define I40E_GLPE_RUPM_GCTL_RUPM_P2_DIS_SHIFT 28 +#define I40E_GLPE_RUPM_GCTL_RUPM_P2_DIS_MASK I40E_MASK(0x1, I40E_GLPE_RUPM_GCTL_RUPM_P2_DIS_SHIFT) +#define I40E_GLPE_RUPM_GCTL_RUPM_P3_DIS_SHIFT 29 +#define I40E_GLPE_RUPM_GCTL_RUPM_P3_DIS_MASK I40E_MASK(0x1, I40E_GLPE_RUPM_GCTL_RUPM_P3_DIS_SHIFT) +#define I40E_GLPE_RUPM_GCTL_RUPM_DIS_SHIFT 30 +#define I40E_GLPE_RUPM_GCTL_RUPM_DIS_MASK I40E_MASK(0x1, I40E_GLPE_RUPM_GCTL_RUPM_DIS_SHIFT) +#define I40E_GLPE_RUPM_GCTL_SWLB_MODE_SHIFT 31 +#define I40E_GLPE_RUPM_GCTL_SWLB_MODE_MASK I40E_MASK(0x1, I40E_GLPE_RUPM_GCTL_SWLB_MODE_SHIFT) +#define I40E_GLPE_RUPM_PTXPOOL 0x0000DAC8 /* Reset: PE_CORER */ +#define I40E_GLPE_RUPM_PTXPOOL_PTXSPADS_SHIFT 0 +#define I40E_GLPE_RUPM_PTXPOOL_PTXSPADS_MASK I40E_MASK(0xFF, I40E_GLPE_RUPM_PTXPOOL_PTXSPADS_SHIFT) +#define I40E_GLPE_RUPM_PUSHPOOL 0x0000DAC0 /* Reset: PE_CORER */ +#define I40E_GLPE_RUPM_PUSHPOOL_PUSHSPADS_SHIFT 0 +#define I40E_GLPE_RUPM_PUSHPOOL_PUSHSPADS_MASK I40E_MASK(0xFF, I40E_GLPE_RUPM_PUSHPOOL_PUSHSPADS_SHIFT) +#define I40E_GLPE_RUPM_TXHOST_EN 0x0000DA08 /* Reset: PE_CORER */ +#define I40E_GLPE_RUPM_TXHOST_EN_TXHOST_EN_SHIFT 0 +#define I40E_GLPE_RUPM_TXHOST_EN_TXHOST_EN_MASK I40E_MASK(0x1, I40E_GLPE_RUPM_TXHOST_EN_TXHOST_EN_SHIFT) +#define I40E_GLPE_VFAEQEDROPCNT(_i) (0x00132540 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLPE_VFAEQEDROPCNT_MAX_INDEX 31 +#define I40E_GLPE_VFAEQEDROPCNT_AEQEDROPCNT_SHIFT 0 +#define I40E_GLPE_VFAEQEDROPCNT_AEQEDROPCNT_MASK I40E_MASK(0xFFFF, I40E_GLPE_VFAEQEDROPCNT_AEQEDROPCNT_SHIFT) +#define I40E_GLPE_VFCEQEDROPCNT(_i) (0x00132440 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLPE_VFCEQEDROPCNT_MAX_INDEX 31 +#define I40E_GLPE_VFCEQEDROPCNT_CEQEDROPCNT_SHIFT 0 +#define I40E_GLPE_VFCEQEDROPCNT_CEQEDROPCNT_MASK I40E_MASK(0xFFFF, I40E_GLPE_VFCEQEDROPCNT_CEQEDROPCNT_SHIFT) +#define I40E_GLPE_VFCQEDROPCNT(_i) (0x00132340 + ((_i) * 4)) /* _i=0...31 */ /* Reset: CORER */ +#define I40E_GLPE_VFCQEDROPCNT_MAX_INDEX 31 +#define I40E_GLPE_VFCQEDROPCNT_CQEDROPCNT_SHIFT 0 +#define I40E_GLPE_VFCQEDROPCNT_CQEDROPCNT_MASK I40E_MASK(0xFFFF, I40E_GLPE_VFCQEDROPCNT_CQEDROPCNT_SHIFT) +#define I40E_GLPE_VFFLMOBJCTRL(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPE_VFFLMOBJCTRL_MAX_INDEX 31 +#define I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT 0 +#define I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_MASK I40E_MASK(0x7, I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT) +#define I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT 8 +#define I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_MASK I40E_MASK(0x7, I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT) +#define I40E_GLPE_VFFLMQ1ALLOCERR(_i) (0x0000C700 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPE_VFFLMQ1ALLOCERR_MAX_INDEX 31 +#define I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_SHIFT 0 +#define I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_MASK I40E_MASK(0xFFFF, I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_SHIFT) +#define I40E_GLPE_VFFLMXMITALLOCERR(_i) (0x0000C600 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPE_VFFLMXMITALLOCERR_MAX_INDEX 31 +#define I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_SHIFT 0 +#define I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_MASK I40E_MASK(0xFFFF, I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_SHIFT) +#define I40E_GLPE_VFUDACTRL(_i) (0x0000C000 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPE_VFUDACTRL_MAX_INDEX 31 +#define I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_SHIFT 0 +#define I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_MASK I40E_MASK(0x1, I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_SHIFT) +#define I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_SHIFT 1 +#define I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_MASK I40E_MASK(0x1, I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_SHIFT) +#define I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_SHIFT 2 +#define I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_MASK I40E_MASK(0x1, I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_SHIFT) +#define I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_SHIFT 3 +#define I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_MASK I40E_MASK(0x1, I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_SHIFT) +#define I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_SHIFT 4 +#define I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_MASK I40E_MASK(0x1, I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_SHIFT) +#define I40E_GLPE_VFUDAUCFBQPN(_i) (0x0000C100 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPE_VFUDAUCFBQPN_MAX_INDEX 31 +#define I40E_GLPE_VFUDAUCFBQPN_QPN_SHIFT 0 +#define I40E_GLPE_VFUDAUCFBQPN_QPN_MASK I40E_MASK(0x3FFFF, I40E_GLPE_VFUDAUCFBQPN_QPN_SHIFT) +#define I40E_GLPE_VFUDAUCFBQPN_VALID_SHIFT 31 +#define I40E_GLPE_VFUDAUCFBQPN_VALID_MASK I40E_MASK(0x1, I40E_GLPE_VFUDAUCFBQPN_VALID_SHIFT) +#define I40E_PFPE_AEQALLOC 0x00131180 /* Reset: PFR */ +#define I40E_PFPE_AEQALLOC_AECOUNT_SHIFT 0 +#define I40E_PFPE_AEQALLOC_AECOUNT_MASK I40E_MASK(0xFFFFFFFF, I40E_PFPE_AEQALLOC_AECOUNT_SHIFT) +#define I40E_PFPE_CCQPHIGH 0x00008200 /* Reset: PFR */ +#define I40E_PFPE_CCQPHIGH_PECCQPHIGH_SHIFT 0 +#define I40E_PFPE_CCQPHIGH_PECCQPHIGH_MASK I40E_MASK(0xFFFFFFFF, I40E_PFPE_CCQPHIGH_PECCQPHIGH_SHIFT) +#define I40E_PFPE_CCQPLOW 0x00008180 /* Reset: PFR */ +#define I40E_PFPE_CCQPLOW_PECCQPLOW_SHIFT 0 +#define I40E_PFPE_CCQPLOW_PECCQPLOW_MASK I40E_MASK(0xFFFFFFFF, I40E_PFPE_CCQPLOW_PECCQPLOW_SHIFT) +#define I40E_PFPE_CCQPSTATUS 0x00008100 /* Reset: PFR */ +#define I40E_PFPE_CCQPSTATUS_CCQP_DONE_SHIFT 0 +#define I40E_PFPE_CCQPSTATUS_CCQP_DONE_MASK I40E_MASK(0x1, I40E_PFPE_CCQPSTATUS_CCQP_DONE_SHIFT) +#define I40E_PFPE_CCQPSTATUS_HMC_PROFILE_SHIFT 4 +#define I40E_PFPE_CCQPSTATUS_HMC_PROFILE_MASK I40E_MASK(0x7, I40E_PFPE_CCQPSTATUS_HMC_PROFILE_SHIFT) +#define I40E_PFPE_CCQPSTATUS_RDMA_EN_VFS_SHIFT 16 +#define I40E_PFPE_CCQPSTATUS_RDMA_EN_VFS_MASK I40E_MASK(0x3F, I40E_PFPE_CCQPSTATUS_RDMA_EN_VFS_SHIFT) +#define I40E_PFPE_CCQPSTATUS_CCQP_ERR_SHIFT 31 +#define I40E_PFPE_CCQPSTATUS_CCQP_ERR_MASK I40E_MASK(0x1, I40E_PFPE_CCQPSTATUS_CCQP_ERR_SHIFT) +#define I40E_PFPE_CQACK 0x00131100 /* Reset: PFR */ +#define I40E_PFPE_CQACK_PECQID_SHIFT 0 +#define I40E_PFPE_CQACK_PECQID_MASK I40E_MASK(0x1FFFF, I40E_PFPE_CQACK_PECQID_SHIFT) +#define I40E_PFPE_CQARM 0x00131080 /* Reset: PFR */ +#define I40E_PFPE_CQARM_PECQID_SHIFT 0 +#define I40E_PFPE_CQARM_PECQID_MASK I40E_MASK(0x1FFFF, I40E_PFPE_CQARM_PECQID_SHIFT) +#define I40E_PFPE_CQPDB 0x00008000 /* Reset: PFR */ +#define I40E_PFPE_CQPDB_WQHEAD_SHIFT 0 +#define I40E_PFPE_CQPDB_WQHEAD_MASK I40E_MASK(0x7FF, I40E_PFPE_CQPDB_WQHEAD_SHIFT) +#define I40E_PFPE_CQPERRCODES 0x00008880 /* Reset: PFR */ +#define I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT 0 +#define I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_MASK I40E_MASK(0xFFFF, I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT) +#define I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT 16 +#define I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_MASK I40E_MASK(0xFFFF, I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT) +#define I40E_PFPE_CQPTAIL 0x00008080 /* Reset: PFR */ +#define I40E_PFPE_CQPTAIL_WQTAIL_SHIFT 0 +#define I40E_PFPE_CQPTAIL_WQTAIL_MASK I40E_MASK(0x7FF, I40E_PFPE_CQPTAIL_WQTAIL_SHIFT) +#define I40E_PFPE_CQPTAIL_CQP_OP_ERR_SHIFT 31 +#define I40E_PFPE_CQPTAIL_CQP_OP_ERR_MASK I40E_MASK(0x1, I40E_PFPE_CQPTAIL_CQP_OP_ERR_SHIFT) +#define I40E_PFPE_FLMQ1ALLOCERR 0x00008980 /* Reset: PFR */ +#define I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_SHIFT 0 +#define I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_MASK I40E_MASK(0xFFFF, I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_SHIFT) +#define I40E_PFPE_FLMXMITALLOCERR 0x00008900 /* Reset: PFR */ +#define I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_SHIFT 0 +#define I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_MASK I40E_MASK(0xFFFF, I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_SHIFT) +#define I40E_PFPE_IPCONFIG0 0x00008280 /* Reset: PFR */ +#define I40E_PFPE_IPCONFIG0_PEIPID_SHIFT 0 +#define I40E_PFPE_IPCONFIG0_PEIPID_MASK I40E_MASK(0xFFFF, I40E_PFPE_IPCONFIG0_PEIPID_SHIFT) +#define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16 +#define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_MASK I40E_MASK(0x1, I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT) +#define I40E_PFPE_MRTEIDXMASK 0x00008600 /* Reset: PFR */ +#define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0 +#define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_MASK I40E_MASK(0x1F, I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT) +#define I40E_PFPE_RCVUNEXPECTEDERROR 0x00008680 /* Reset: PFR */ +#define I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT 0 +#define I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_MASK I40E_MASK(0xFFFFFF, I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT) +#define I40E_PFPE_TCPNOWTIMER 0x00008580 /* Reset: PFR */ +#define I40E_PFPE_TCPNOWTIMER_TCP_NOW_SHIFT 0 +#define I40E_PFPE_TCPNOWTIMER_TCP_NOW_MASK I40E_MASK(0xFFFFFFFF, I40E_PFPE_TCPNOWTIMER_TCP_NOW_SHIFT) +#define I40E_PFPE_UDACTRL 0x00008700 /* Reset: PFR */ +#define I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_SHIFT 0 +#define I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_MASK I40E_MASK(0x1, I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_SHIFT) +#define I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_SHIFT 1 +#define I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_MASK I40E_MASK(0x1, I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_SHIFT) +#define I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_SHIFT 2 +#define I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_MASK I40E_MASK(0x1, I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_SHIFT) +#define I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_SHIFT 3 +#define I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_MASK I40E_MASK(0x1, I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_SHIFT) +#define I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_SHIFT 4 +#define I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_MASK I40E_MASK(0x1, I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_SHIFT) +#define I40E_PFPE_UDAUCFBQPN 0x00008780 /* Reset: PFR */ +#define I40E_PFPE_UDAUCFBQPN_QPN_SHIFT 0 +#define I40E_PFPE_UDAUCFBQPN_QPN_MASK I40E_MASK(0x3FFFF, I40E_PFPE_UDAUCFBQPN_QPN_SHIFT) +#define I40E_PFPE_UDAUCFBQPN_VALID_SHIFT 31 +#define I40E_PFPE_UDAUCFBQPN_VALID_MASK I40E_MASK(0x1, I40E_PFPE_UDAUCFBQPN_VALID_SHIFT) +#define I40E_PFPE_WQEALLOC 0x00138C00 /* Reset: PFR */ +#define I40E_PFPE_WQEALLOC_PEQPID_SHIFT 0 +#define I40E_PFPE_WQEALLOC_PEQPID_MASK I40E_MASK(0x3FFFF, I40E_PFPE_WQEALLOC_PEQPID_SHIFT) +#define I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT 20 +#define I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_MASK I40E_MASK(0xFFF, I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT) +#define I40E_PRTDCB_RLPMC 0x0001F140 /* Reset: PE_CORER */ +#define I40E_PRTDCB_RLPMC_TC2PFC_SHIFT 0 +#define I40E_PRTDCB_RLPMC_TC2PFC_MASK I40E_MASK(0xFF, I40E_PRTDCB_RLPMC_TC2PFC_SHIFT) +#define I40E_PRTDCB_TCMSTC_RLPM(_i) (0x0001F040 + ((_i) * 32)) /* _i=0...7 */ /* Reset: PE_CORER */ +#define I40E_PRTDCB_TCMSTC_RLPM_MAX_INDEX 7 +#define I40E_PRTDCB_TCMSTC_RLPM_MSTC_SHIFT 0 +#define I40E_PRTDCB_TCMSTC_RLPM_MSTC_MASK I40E_MASK(0xFFFFF, I40E_PRTDCB_TCMSTC_RLPM_MSTC_SHIFT) +#define I40E_PRTDCB_TCPMC_RLPM 0x0001F1A0 /* Reset: PE_CORER */ +#define I40E_PRTDCB_TCPMC_RLPM_CPM_SHIFT 0 +#define I40E_PRTDCB_TCPMC_RLPM_CPM_MASK I40E_MASK(0x1FFF, I40E_PRTDCB_TCPMC_RLPM_CPM_SHIFT) +#define I40E_PRTDCB_TCPMC_RLPM_LLTC_SHIFT 13 +#define I40E_PRTDCB_TCPMC_RLPM_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TCPMC_RLPM_LLTC_SHIFT) +#define I40E_PRTDCB_TCPMC_RLPM_TCPM_MODE_SHIFT 30 +#define I40E_PRTDCB_TCPMC_RLPM_TCPM_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_TCPMC_RLPM_TCPM_MODE_SHIFT) +#define I40E_PRTE_RUPM_TCCNTR03 0x0000DAE0 /* Reset: PE_CORER */ +#define I40E_PRTE_RUPM_TCCNTR03_TC0COUNT_SHIFT 0 +#define I40E_PRTE_RUPM_TCCNTR03_TC0COUNT_MASK I40E_MASK(0xFF, I40E_PRTE_RUPM_TCCNTR03_TC0COUNT_SHIFT) +#define I40E_PRTE_RUPM_TCCNTR03_TC1COUNT_SHIFT 8 +#define I40E_PRTE_RUPM_TCCNTR03_TC1COUNT_MASK I40E_MASK(0xFF, I40E_PRTE_RUPM_TCCNTR03_TC1COUNT_SHIFT) +#define I40E_PRTE_RUPM_TCCNTR03_TC2COUNT_SHIFT 16 +#define I40E_PRTE_RUPM_TCCNTR03_TC2COUNT_MASK I40E_MASK(0xFF, I40E_PRTE_RUPM_TCCNTR03_TC2COUNT_SHIFT) +#define I40E_PRTE_RUPM_TCCNTR03_TC3COUNT_SHIFT 24 +#define I40E_PRTE_RUPM_TCCNTR03_TC3COUNT_MASK I40E_MASK(0xFF, I40E_PRTE_RUPM_TCCNTR03_TC3COUNT_SHIFT) +#define I40E_PRTPE_RUPM_CNTR 0x0000DB20 /* Reset: PE_CORER */ +#define I40E_PRTPE_RUPM_CNTR_COUNT_SHIFT 0 +#define I40E_PRTPE_RUPM_CNTR_COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_CNTR_COUNT_SHIFT) +#define I40E_PRTPE_RUPM_CTL 0x0000DA40 /* Reset: PE_CORER */ +#define I40E_PRTPE_RUPM_CTL_LLTC_SHIFT 13 +#define I40E_PRTPE_RUPM_CTL_LLTC_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_CTL_LLTC_SHIFT) +#define I40E_PRTPE_RUPM_CTL_RUPM_MODE_SHIFT 30 +#define I40E_PRTPE_RUPM_CTL_RUPM_MODE_MASK I40E_MASK(0x1, I40E_PRTPE_RUPM_CTL_RUPM_MODE_SHIFT) +#define I40E_PRTPE_RUPM_PFCCTL 0x0000DA60 /* Reset: PE_CORER */ +#define I40E_PRTPE_RUPM_PFCCTL_TC2PFC_SHIFT 0 +#define I40E_PRTPE_RUPM_PFCCTL_TC2PFC_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PFCCTL_TC2PFC_SHIFT) +#define I40E_PRTPE_RUPM_PFCPC 0x0000DA80 /* Reset: PE_CORER */ +#define I40E_PRTPE_RUPM_PFCPC_PORTOFFTH_SHIFT 0 +#define I40E_PRTPE_RUPM_PFCPC_PORTOFFTH_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PFCPC_PORTOFFTH_SHIFT) +#define I40E_PRTPE_RUPM_PFCTCC 0x0000DAA0 /* Reset: PE_CORER */ +#define I40E_PRTPE_RUPM_PFCTCC_TCOFFTH_SHIFT 0 +#define I40E_PRTPE_RUPM_PFCTCC_TCOFFTH_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PFCTCC_TCOFFTH_SHIFT) +#define I40E_PRTPE_RUPM_PFCTCC_LL_PRI_TH_SHIFT 16 +#define I40E_PRTPE_RUPM_PFCTCC_LL_PRI_TH_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PFCTCC_LL_PRI_TH_SHIFT) +#define I40E_PRTPE_RUPM_PFCTCC_LL_PRI_EN_SHIFT 31 +#define I40E_PRTPE_RUPM_PFCTCC_LL_PRI_EN_MASK I40E_MASK(0x1, I40E_PRTPE_RUPM_PFCTCC_LL_PRI_EN_SHIFT) +#define I40E_PRTPE_RUPM_PTCTCCNTR47 0x0000DB60 /* Reset: PE_CORER */ +#define I40E_PRTPE_RUPM_PTCTCCNTR47_TC4COUNT_SHIFT 0 +#define I40E_PRTPE_RUPM_PTCTCCNTR47_TC4COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PTCTCCNTR47_TC4COUNT_SHIFT) +#define I40E_PRTPE_RUPM_PTCTCCNTR47_TC5COUNT_SHIFT 8 +#define I40E_PRTPE_RUPM_PTCTCCNTR47_TC5COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PTCTCCNTR47_TC5COUNT_SHIFT) +#define I40E_PRTPE_RUPM_PTCTCCNTR47_TC6COUNT_SHIFT 16 +#define I40E_PRTPE_RUPM_PTCTCCNTR47_TC6COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PTCTCCNTR47_TC6COUNT_SHIFT) +#define I40E_PRTPE_RUPM_PTCTCCNTR47_TC7COUNT_SHIFT 24 +#define I40E_PRTPE_RUPM_PTCTCCNTR47_TC7COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PTCTCCNTR47_TC7COUNT_SHIFT) +#define I40E_PRTPE_RUPM_PTXTCCNTR03 0x0000DB40 /* Reset: PE_CORER */ +#define I40E_PRTPE_RUPM_PTXTCCNTR03_TC0COUNT_SHIFT 0 +#define I40E_PRTPE_RUPM_PTXTCCNTR03_TC0COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PTXTCCNTR03_TC0COUNT_SHIFT) +#define I40E_PRTPE_RUPM_PTXTCCNTR03_TC1COUNT_SHIFT 8 +#define I40E_PRTPE_RUPM_PTXTCCNTR03_TC1COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PTXTCCNTR03_TC1COUNT_SHIFT) +#define I40E_PRTPE_RUPM_PTXTCCNTR03_TC2COUNT_SHIFT 16 +#define I40E_PRTPE_RUPM_PTXTCCNTR03_TC2COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PTXTCCNTR03_TC2COUNT_SHIFT) +#define I40E_PRTPE_RUPM_PTXTCCNTR03_TC3COUNT_SHIFT 24 +#define I40E_PRTPE_RUPM_PTXTCCNTR03_TC3COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_PTXTCCNTR03_TC3COUNT_SHIFT) +#define I40E_PRTPE_RUPM_TCCNTR47 0x0000DB00 /* Reset: PE_CORER */ +#define I40E_PRTPE_RUPM_TCCNTR47_TC4COUNT_SHIFT 0 +#define I40E_PRTPE_RUPM_TCCNTR47_TC4COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_TCCNTR47_TC4COUNT_SHIFT) +#define I40E_PRTPE_RUPM_TCCNTR47_TC5COUNT_SHIFT 8 +#define I40E_PRTPE_RUPM_TCCNTR47_TC5COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_TCCNTR47_TC5COUNT_SHIFT) +#define I40E_PRTPE_RUPM_TCCNTR47_TC6COUNT_SHIFT 16 +#define I40E_PRTPE_RUPM_TCCNTR47_TC6COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_TCCNTR47_TC6COUNT_SHIFT) +#define I40E_PRTPE_RUPM_TCCNTR47_TC7COUNT_SHIFT 24 +#define I40E_PRTPE_RUPM_TCCNTR47_TC7COUNT_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_TCCNTR47_TC7COUNT_SHIFT) +#define I40E_PRTPE_RUPM_THRES 0x0000DA20 /* Reset: PE_CORER */ +#define I40E_PRTPE_RUPM_THRES_MINSPADSPERTC_SHIFT 0 +#define I40E_PRTPE_RUPM_THRES_MINSPADSPERTC_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_THRES_MINSPADSPERTC_SHIFT) +#define I40E_PRTPE_RUPM_THRES_MAXSPADS_SHIFT 8 +#define I40E_PRTPE_RUPM_THRES_MAXSPADS_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_THRES_MAXSPADS_SHIFT) +#define I40E_PRTPE_RUPM_THRES_MAXSPADSPERTC_SHIFT 16 +#define I40E_PRTPE_RUPM_THRES_MAXSPADSPERTC_MASK I40E_MASK(0xFF, I40E_PRTPE_RUPM_THRES_MAXSPADSPERTC_SHIFT) +#define I40E_VFPE_AEQALLOC(_VF) (0x00130C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_AEQALLOC_MAX_INDEX 127 +#define I40E_VFPE_AEQALLOC_AECOUNT_SHIFT 0 +#define I40E_VFPE_AEQALLOC_AECOUNT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_AEQALLOC_AECOUNT_SHIFT) +#define I40E_VFPE_CCQPHIGH(_VF) (0x00001000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_CCQPHIGH_MAX_INDEX 127 +#define I40E_VFPE_CCQPHIGH_PECCQPHIGH_SHIFT 0 +#define I40E_VFPE_CCQPHIGH_PECCQPHIGH_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_CCQPHIGH_PECCQPHIGH_SHIFT) +#define I40E_VFPE_CCQPLOW(_VF) (0x00000C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_CCQPLOW_MAX_INDEX 127 +#define I40E_VFPE_CCQPLOW_PECCQPLOW_SHIFT 0 +#define I40E_VFPE_CCQPLOW_PECCQPLOW_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_CCQPLOW_PECCQPLOW_SHIFT) +#define I40E_VFPE_CCQPSTATUS(_VF) (0x00000800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_CCQPSTATUS_MAX_INDEX 127 +#define I40E_VFPE_CCQPSTATUS_CCQP_DONE_SHIFT 0 +#define I40E_VFPE_CCQPSTATUS_CCQP_DONE_MASK I40E_MASK(0x1, I40E_VFPE_CCQPSTATUS_CCQP_DONE_SHIFT) +#define I40E_VFPE_CCQPSTATUS_HMC_PROFILE_SHIFT 4 +#define I40E_VFPE_CCQPSTATUS_HMC_PROFILE_MASK I40E_MASK(0x7, I40E_VFPE_CCQPSTATUS_HMC_PROFILE_SHIFT) +#define I40E_VFPE_CCQPSTATUS_RDMA_EN_VFS_SHIFT 16 +#define I40E_VFPE_CCQPSTATUS_RDMA_EN_VFS_MASK I40E_MASK(0x3F, I40E_VFPE_CCQPSTATUS_RDMA_EN_VFS_SHIFT) +#define I40E_VFPE_CCQPSTATUS_CCQP_ERR_SHIFT 31 +#define I40E_VFPE_CCQPSTATUS_CCQP_ERR_MASK I40E_MASK(0x1, I40E_VFPE_CCQPSTATUS_CCQP_ERR_SHIFT) +#define I40E_VFPE_CQACK(_VF) (0x00130800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_CQACK_MAX_INDEX 127 +#define I40E_VFPE_CQACK_PECQID_SHIFT 0 +#define I40E_VFPE_CQACK_PECQID_MASK I40E_MASK(0x1FFFF, I40E_VFPE_CQACK_PECQID_SHIFT) +#define I40E_VFPE_CQARM(_VF) (0x00130400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_CQARM_MAX_INDEX 127 +#define I40E_VFPE_CQARM_PECQID_SHIFT 0 +#define I40E_VFPE_CQARM_PECQID_MASK I40E_MASK(0x1FFFF, I40E_VFPE_CQARM_PECQID_SHIFT) +#define I40E_VFPE_CQPDB(_VF) (0x00000000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_CQPDB_MAX_INDEX 127 +#define I40E_VFPE_CQPDB_WQHEAD_SHIFT 0 +#define I40E_VFPE_CQPDB_WQHEAD_MASK I40E_MASK(0x7FF, I40E_VFPE_CQPDB_WQHEAD_SHIFT) +#define I40E_VFPE_CQPERRCODES(_VF) (0x00001800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_CQPERRCODES_MAX_INDEX 127 +#define I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT 0 +#define I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_MASK I40E_MASK(0xFFFF, I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT) +#define I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT 16 +#define I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_MASK I40E_MASK(0xFFFF, I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT) +#define I40E_VFPE_CQPTAIL(_VF) (0x00000400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_CQPTAIL_MAX_INDEX 127 +#define I40E_VFPE_CQPTAIL_WQTAIL_SHIFT 0 +#define I40E_VFPE_CQPTAIL_WQTAIL_MASK I40E_MASK(0x7FF, I40E_VFPE_CQPTAIL_WQTAIL_SHIFT) +#define I40E_VFPE_CQPTAIL_CQP_OP_ERR_SHIFT 31 +#define I40E_VFPE_CQPTAIL_CQP_OP_ERR_MASK I40E_MASK(0x1, I40E_VFPE_CQPTAIL_CQP_OP_ERR_SHIFT) +#define I40E_VFPE_IPCONFIG0(_VF) (0x00001400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_IPCONFIG0_MAX_INDEX 127 +#define I40E_VFPE_IPCONFIG0_PEIPID_SHIFT 0 +#define I40E_VFPE_IPCONFIG0_PEIPID_MASK I40E_MASK(0xFFFF, I40E_VFPE_IPCONFIG0_PEIPID_SHIFT) +#define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16 +#define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_MASK I40E_MASK(0x1, I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT) +#define I40E_VFPE_MRTEIDXMASK(_VF) (0x00003000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_MRTEIDXMASK_MAX_INDEX 127 +#define I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0 +#define I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_MASK I40E_MASK(0x1F, I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT) +#define I40E_VFPE_RCVUNEXPECTEDERROR(_VF) (0x00003400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_RCVUNEXPECTEDERROR_MAX_INDEX 127 +#define I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT 0 +#define I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_MASK I40E_MASK(0xFFFFFF, I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT) +#define I40E_VFPE_TCPNOWTIMER(_VF) (0x00002C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_TCPNOWTIMER_MAX_INDEX 127 +#define I40E_VFPE_TCPNOWTIMER_TCP_NOW_SHIFT 0 +#define I40E_VFPE_TCPNOWTIMER_TCP_NOW_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_TCPNOWTIMER_TCP_NOW_SHIFT) +#define I40E_VFPE_WQEALLOC(_VF) (0x00138000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ +#define I40E_VFPE_WQEALLOC_MAX_INDEX 127 +#define I40E_VFPE_WQEALLOC_PEQPID_SHIFT 0 +#define I40E_VFPE_WQEALLOC_PEQPID_MASK I40E_MASK(0x3FFFF, I40E_VFPE_WQEALLOC_PEQPID_SHIFT) +#define I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT 20 +#define I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_MASK I40E_MASK(0xFFF, I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT) +#define I40E_GLPES_PFIP4RXDISCARD(_i) (0x00010600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXDISCARD_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_SHIFT 0 +#define I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_SHIFT) +#define I40E_GLPES_PFIP4RXFRAGSHI(_i) (0x00010804 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXFRAGSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT 0 +#define I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT) +#define I40E_GLPES_PFIP4RXFRAGSLO(_i) (0x00010800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXFRAGSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT 0 +#define I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT) +#define I40E_GLPES_PFIP4RXMCOCTSHI(_i) (0x00010A04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXMCOCTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT 0 +#define I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT) +#define I40E_GLPES_PFIP4RXMCOCTSLO(_i) (0x00010A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXMCOCTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT 0 +#define I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT) +#define I40E_GLPES_PFIP4RXMCPKTSHI(_i) (0x00010C04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXMCPKTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT 0 +#define I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT) +#define I40E_GLPES_PFIP4RXMCPKTSLO(_i) (0x00010C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXMCPKTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT 0 +#define I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT) +#define I40E_GLPES_PFIP4RXOCTSHI(_i) (0x00010204 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXOCTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT 0 +#define I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT) +#define I40E_GLPES_PFIP4RXOCTSLO(_i) (0x00010200 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXOCTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT 0 +#define I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT) +#define I40E_GLPES_PFIP4RXPKTSHI(_i) (0x00010404 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXPKTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT 0 +#define I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT) +#define I40E_GLPES_PFIP4RXPKTSLO(_i) (0x00010400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXPKTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT 0 +#define I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT) +#define I40E_GLPES_PFIP4RXTRUNC(_i) (0x00010700 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4RXTRUNC_MAX_INDEX 15 +#define I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_SHIFT 0 +#define I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_SHIFT) +#define I40E_GLPES_PFIP4TXFRAGSHI(_i) (0x00011E04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4TXFRAGSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT 0 +#define I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT) +#define I40E_GLPES_PFIP4TXFRAGSLO(_i) (0x00011E00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4TXFRAGSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT 0 +#define I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT) +#define I40E_GLPES_PFIP4TXMCOCTSHI(_i) (0x00012004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4TXMCOCTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT 0 +#define I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT) +#define I40E_GLPES_PFIP4TXMCOCTSLO(_i) (0x00012000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4TXMCOCTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT 0 +#define I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT) +#define I40E_GLPES_PFIP4TXMCPKTSHI(_i) (0x00012204 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4TXMCPKTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT 0 +#define I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT) +#define I40E_GLPES_PFIP4TXMCPKTSLO(_i) (0x00012200 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4TXMCPKTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT 0 +#define I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT) +#define I40E_GLPES_PFIP4TXNOROUTE(_i) (0x00012E00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4TXNOROUTE_MAX_INDEX 15 +#define I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT 0 +#define I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT) +#define I40E_GLPES_PFIP4TXOCTSHI(_i) (0x00011A04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4TXOCTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT 0 +#define I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT) +#define I40E_GLPES_PFIP4TXOCTSLO(_i) (0x00011A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4TXOCTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT 0 +#define I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT) +#define I40E_GLPES_PFIP4TXPKTSHI(_i) (0x00011C04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4TXPKTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT 0 +#define I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT) +#define I40E_GLPES_PFIP4TXPKTSLO(_i) (0x00011C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP4TXPKTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT 0 +#define I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT) +#define I40E_GLPES_PFIP6RXDISCARD(_i) (0x00011200 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXDISCARD_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_SHIFT 0 +#define I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_SHIFT) +#define I40E_GLPES_PFIP6RXFRAGSHI(_i) (0x00011404 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXFRAGSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT 0 +#define I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT) +#define I40E_GLPES_PFIP6RXFRAGSLO(_i) (0x00011400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXFRAGSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT 0 +#define I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT) +#define I40E_GLPES_PFIP6RXMCOCTSHI(_i) (0x00011604 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXMCOCTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT 0 +#define I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT) +#define I40E_GLPES_PFIP6RXMCOCTSLO(_i) (0x00011600 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXMCOCTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT 0 +#define I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT) +#define I40E_GLPES_PFIP6RXMCPKTSHI(_i) (0x00011804 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXMCPKTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT 0 +#define I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT) +#define I40E_GLPES_PFIP6RXMCPKTSLO(_i) (0x00011800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXMCPKTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT 0 +#define I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT) +#define I40E_GLPES_PFIP6RXOCTSHI(_i) (0x00010E04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXOCTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT 0 +#define I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT) +#define I40E_GLPES_PFIP6RXOCTSLO(_i) (0x00010E00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXOCTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT 0 +#define I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT) +#define I40E_GLPES_PFIP6RXPKTSHI(_i) (0x00011004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXPKTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT 0 +#define I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT) +#define I40E_GLPES_PFIP6RXPKTSLO(_i) (0x00011000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXPKTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT 0 +#define I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT) +#define I40E_GLPES_PFIP6RXTRUNC(_i) (0x00011300 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6RXTRUNC_MAX_INDEX 15 +#define I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_SHIFT 0 +#define I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_SHIFT) +#define I40E_GLPES_PFIP6TXFRAGSHI(_i) (0x00012804 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6TXFRAGSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT 0 +#define I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT) +#define I40E_GLPES_PFIP6TXFRAGSLO(_i) (0x00012800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6TXFRAGSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT 0 +#define I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT) +#define I40E_GLPES_PFIP6TXMCOCTSHI(_i) (0x00012A04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6TXMCOCTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT 0 +#define I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT) +#define I40E_GLPES_PFIP6TXMCOCTSLO(_i) (0x00012A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6TXMCOCTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT 0 +#define I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT) +#define I40E_GLPES_PFIP6TXMCPKTSHI(_i) (0x00012C04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6TXMCPKTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT 0 +#define I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT) +#define I40E_GLPES_PFIP6TXMCPKTSLO(_i) (0x00012C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6TXMCPKTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT 0 +#define I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT) +#define I40E_GLPES_PFIP6TXNOROUTE(_i) (0x00012F00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6TXNOROUTE_MAX_INDEX 15 +#define I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT 0 +#define I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT) +#define I40E_GLPES_PFIP6TXOCTSHI(_i) (0x00012404 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6TXOCTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT 0 +#define I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT) +#define I40E_GLPES_PFIP6TXOCTSLO(_i) (0x00012400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6TXOCTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT 0 +#define I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT) +#define I40E_GLPES_PFIP6TXPKTSHI(_i) (0x00012604 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6TXPKTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT 0 +#define I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT) +#define I40E_GLPES_PFIP6TXPKTSLO(_i) (0x00012600 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFIP6TXPKTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT 0 +#define I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT) +#define I40E_GLPES_PFRDMARXRDSHI(_i) (0x00013E04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMARXRDSHI_MAX_INDEX 15 +#define I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_SHIFT 0 +#define I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_SHIFT) +#define I40E_GLPES_PFRDMARXRDSLO(_i) (0x00013E00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMARXRDSLO_MAX_INDEX 15 +#define I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_SHIFT 0 +#define I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_SHIFT) +#define I40E_GLPES_PFRDMARXSNDSHI(_i) (0x00014004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMARXSNDSHI_MAX_INDEX 15 +#define I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT 0 +#define I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT) +#define I40E_GLPES_PFRDMARXSNDSLO(_i) (0x00014000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMARXSNDSLO_MAX_INDEX 15 +#define I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT 0 +#define I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT) +#define I40E_GLPES_PFRDMARXWRSHI(_i) (0x00013C04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMARXWRSHI_MAX_INDEX 15 +#define I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_SHIFT 0 +#define I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_SHIFT) +#define I40E_GLPES_PFRDMARXWRSLO(_i) (0x00013C00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMARXWRSLO_MAX_INDEX 15 +#define I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_SHIFT 0 +#define I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_SHIFT) +#define I40E_GLPES_PFRDMATXRDSHI(_i) (0x00014404 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMATXRDSHI_MAX_INDEX 15 +#define I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_SHIFT 0 +#define I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_SHIFT) +#define I40E_GLPES_PFRDMATXRDSLO(_i) (0x00014400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMATXRDSLO_MAX_INDEX 15 +#define I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_SHIFT 0 +#define I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_SHIFT) +#define I40E_GLPES_PFRDMATXSNDSHI(_i) (0x00014604 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMATXSNDSHI_MAX_INDEX 15 +#define I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT 0 +#define I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT) +#define I40E_GLPES_PFRDMATXSNDSLO(_i) (0x00014600 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMATXSNDSLO_MAX_INDEX 15 +#define I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT 0 +#define I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT) +#define I40E_GLPES_PFRDMATXWRSHI(_i) (0x00014204 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMATXWRSHI_MAX_INDEX 15 +#define I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_SHIFT 0 +#define I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_SHIFT) +#define I40E_GLPES_PFRDMATXWRSLO(_i) (0x00014200 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMATXWRSLO_MAX_INDEX 15 +#define I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_SHIFT 0 +#define I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_SHIFT) +#define I40E_GLPES_PFRDMAVBNDHI(_i) (0x00014804 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMAVBNDHI_MAX_INDEX 15 +#define I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_SHIFT 0 +#define I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_SHIFT) +#define I40E_GLPES_PFRDMAVBNDLO(_i) (0x00014800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMAVBNDLO_MAX_INDEX 15 +#define I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_SHIFT 0 +#define I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_SHIFT) +#define I40E_GLPES_PFRDMAVINVHI(_i) (0x00014A04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMAVINVHI_MAX_INDEX 15 +#define I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_SHIFT 0 +#define I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_SHIFT) +#define I40E_GLPES_PFRDMAVINVLO(_i) (0x00014A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRDMAVINVLO_MAX_INDEX 15 +#define I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_SHIFT 0 +#define I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_SHIFT) +#define I40E_GLPES_PFRXVLANERR(_i) (0x00010000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFRXVLANERR_MAX_INDEX 15 +#define I40E_GLPES_PFRXVLANERR_RXVLANERR_SHIFT 0 +#define I40E_GLPES_PFRXVLANERR_RXVLANERR_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_PFRXVLANERR_RXVLANERR_SHIFT) +#define I40E_GLPES_PFTCPRTXSEG(_i) (0x00013600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFTCPRTXSEG_MAX_INDEX 15 +#define I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_SHIFT 0 +#define I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_SHIFT) +#define I40E_GLPES_PFTCPRXOPTERR(_i) (0x00013200 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFTCPRXOPTERR_MAX_INDEX 15 +#define I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_SHIFT 0 +#define I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_SHIFT) +#define I40E_GLPES_PFTCPRXPROTOERR(_i) (0x00013300 + ((_i) * 4)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFTCPRXPROTOERR_MAX_INDEX 15 +#define I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT 0 +#define I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT) +#define I40E_GLPES_PFTCPRXSEGSHI(_i) (0x00013004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFTCPRXSEGSHI_MAX_INDEX 15 +#define I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT 0 +#define I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT) +#define I40E_GLPES_PFTCPRXSEGSLO(_i) (0x00013000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFTCPRXSEGSLO_MAX_INDEX 15 +#define I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT 0 +#define I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT) +#define I40E_GLPES_PFTCPTXSEGHI(_i) (0x00013404 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFTCPTXSEGHI_MAX_INDEX 15 +#define I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_SHIFT 0 +#define I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_SHIFT) +#define I40E_GLPES_PFTCPTXSEGLO(_i) (0x00013400 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFTCPTXSEGLO_MAX_INDEX 15 +#define I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_SHIFT 0 +#define I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_SHIFT) +#define I40E_GLPES_PFUDPRXPKTSHI(_i) (0x00013804 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFUDPRXPKTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT 0 +#define I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT) +#define I40E_GLPES_PFUDPRXPKTSLO(_i) (0x00013800 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFUDPRXPKTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT 0 +#define I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT) +#define I40E_GLPES_PFUDPTXPKTSHI(_i) (0x00013A04 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFUDPTXPKTSHI_MAX_INDEX 15 +#define I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT 0 +#define I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT) +#define I40E_GLPES_PFUDPTXPKTSLO(_i) (0x00013A00 + ((_i) * 8)) /* _i=0...15 */ /* Reset: PE_CORER */ +#define I40E_GLPES_PFUDPTXPKTSLO_MAX_INDEX 15 +#define I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT 0 +#define I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT) +#define I40E_GLPES_RDMARXMULTFPDUSHI 0x0001E014 /* Reset: PE_CORER */ +#define I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_SHIFT 0 +#define I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_SHIFT) +#define I40E_GLPES_RDMARXMULTFPDUSLO 0x0001E010 /* Reset: PE_CORER */ +#define I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_SHIFT 0 +#define I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_SHIFT) +#define I40E_GLPES_RDMARXOOODDPHI 0x0001E01C /* Reset: PE_CORER */ +#define I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_SHIFT 0 +#define I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_SHIFT) +#define I40E_GLPES_RDMARXOOODDPLO 0x0001E018 /* Reset: PE_CORER */ +#define I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_SHIFT 0 +#define I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_SHIFT) +#define I40E_GLPES_RDMARXOOONOMARK 0x0001E004 /* Reset: PE_CORER */ +#define I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_SHIFT 0 +#define I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_SHIFT) +#define I40E_GLPES_RDMARXUNALIGN 0x0001E000 /* Reset: PE_CORER */ +#define I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_SHIFT 0 +#define I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_SHIFT) +#define I40E_GLPES_TCPRXFOURHOLEHI 0x0001E044 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_SHIFT 0 +#define I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_SHIFT) +#define I40E_GLPES_TCPRXFOURHOLELO 0x0001E040 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_SHIFT 0 +#define I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_SHIFT) +#define I40E_GLPES_TCPRXONEHOLEHI 0x0001E02C /* Reset: PE_CORER */ +#define I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_SHIFT 0 +#define I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_SHIFT) +#define I40E_GLPES_TCPRXONEHOLELO 0x0001E028 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_SHIFT 0 +#define I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_SHIFT) +#define I40E_GLPES_TCPRXPUREACKHI 0x0001E024 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_SHIFT 0 +#define I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_SHIFT) +#define I40E_GLPES_TCPRXPUREACKSLO 0x0001E020 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_SHIFT 0 +#define I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_SHIFT) +#define I40E_GLPES_TCPRXTHREEHOLEHI 0x0001E03C /* Reset: PE_CORER */ +#define I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_SHIFT 0 +#define I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_SHIFT) +#define I40E_GLPES_TCPRXTHREEHOLELO 0x0001E038 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_SHIFT 0 +#define I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_SHIFT) +#define I40E_GLPES_TCPRXTWOHOLEHI 0x0001E034 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_SHIFT 0 +#define I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_SHIFT) +#define I40E_GLPES_TCPRXTWOHOLELO 0x0001E030 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_SHIFT 0 +#define I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_SHIFT) +#define I40E_GLPES_TCPTXRETRANSFASTHI 0x0001E04C /* Reset: PE_CORER */ +#define I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_SHIFT 0 +#define I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_SHIFT) +#define I40E_GLPES_TCPTXRETRANSFASTLO 0x0001E048 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_SHIFT 0 +#define I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_SHIFT) +#define I40E_GLPES_TCPTXTOUTSFASTHI 0x0001E054 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_SHIFT 0 +#define I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_SHIFT) +#define I40E_GLPES_TCPTXTOUTSFASTLO 0x0001E050 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_SHIFT 0 +#define I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_SHIFT) +#define I40E_GLPES_TCPTXTOUTSHI 0x0001E05C /* Reset: PE_CORER */ +#define I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_SHIFT 0 +#define I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_SHIFT) +#define I40E_GLPES_TCPTXTOUTSLO 0x0001E058 /* Reset: PE_CORER */ +#define I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_SHIFT 0 +#define I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_SHIFT) +#define I40E_GLPES_VFIP4RXDISCARD(_i) (0x00018600 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXDISCARD_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_SHIFT 0 +#define I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_SHIFT) +#define I40E_GLPES_VFIP4RXFRAGSHI(_i) (0x00018804 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXFRAGSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT 0 +#define I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT) +#define I40E_GLPES_VFIP4RXFRAGSLO(_i) (0x00018800 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXFRAGSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT 0 +#define I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT) +#define I40E_GLPES_VFIP4RXMCOCTSHI(_i) (0x00018A04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXMCOCTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT 0 +#define I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT) +#define I40E_GLPES_VFIP4RXMCOCTSLO(_i) (0x00018A00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXMCOCTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT 0 +#define I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT) +#define I40E_GLPES_VFIP4RXMCPKTSHI(_i) (0x00018C04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXMCPKTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT 0 +#define I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT) +#define I40E_GLPES_VFIP4RXMCPKTSLO(_i) (0x00018C00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXMCPKTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT 0 +#define I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT) +#define I40E_GLPES_VFIP4RXOCTSHI(_i) (0x00018204 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXOCTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT 0 +#define I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT) +#define I40E_GLPES_VFIP4RXOCTSLO(_i) (0x00018200 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXOCTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT 0 +#define I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT) +#define I40E_GLPES_VFIP4RXPKTSHI(_i) (0x00018404 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXPKTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT 0 +#define I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT) +#define I40E_GLPES_VFIP4RXPKTSLO(_i) (0x00018400 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXPKTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT 0 +#define I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT) +#define I40E_GLPES_VFIP4RXTRUNC(_i) (0x00018700 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4RXTRUNC_MAX_INDEX 31 +#define I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_SHIFT 0 +#define I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_SHIFT) +#define I40E_GLPES_VFIP4TXFRAGSHI(_i) (0x00019E04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4TXFRAGSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT 0 +#define I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT) +#define I40E_GLPES_VFIP4TXFRAGSLO(_i) (0x00019E00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4TXFRAGSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT 0 +#define I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT) +#define I40E_GLPES_VFIP4TXMCOCTSHI(_i) (0x0001A004 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4TXMCOCTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT 0 +#define I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT) +#define I40E_GLPES_VFIP4TXMCOCTSLO(_i) (0x0001A000 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4TXMCOCTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT 0 +#define I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT) +#define I40E_GLPES_VFIP4TXMCPKTSHI(_i) (0x0001A204 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4TXMCPKTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT 0 +#define I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT) +#define I40E_GLPES_VFIP4TXMCPKTSLO(_i) (0x0001A200 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4TXMCPKTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT 0 +#define I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT) +#define I40E_GLPES_VFIP4TXNOROUTE(_i) (0x0001AE00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4TXNOROUTE_MAX_INDEX 31 +#define I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT 0 +#define I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT) +#define I40E_GLPES_VFIP4TXOCTSHI(_i) (0x00019A04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4TXOCTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT 0 +#define I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT) +#define I40E_GLPES_VFIP4TXOCTSLO(_i) (0x00019A00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4TXOCTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT 0 +#define I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT) +#define I40E_GLPES_VFIP4TXPKTSHI(_i) (0x00019C04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4TXPKTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT 0 +#define I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT) +#define I40E_GLPES_VFIP4TXPKTSLO(_i) (0x00019C00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP4TXPKTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT 0 +#define I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT) +#define I40E_GLPES_VFIP6RXDISCARD(_i) (0x00019200 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXDISCARD_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_SHIFT 0 +#define I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_SHIFT) +#define I40E_GLPES_VFIP6RXFRAGSHI(_i) (0x00019404 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXFRAGSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT 0 +#define I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT) +#define I40E_GLPES_VFIP6RXFRAGSLO(_i) (0x00019400 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXFRAGSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT 0 +#define I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT) +#define I40E_GLPES_VFIP6RXMCOCTSHI(_i) (0x00019604 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXMCOCTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT 0 +#define I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT) +#define I40E_GLPES_VFIP6RXMCOCTSLO(_i) (0x00019600 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXMCOCTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT 0 +#define I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT) +#define I40E_GLPES_VFIP6RXMCPKTSHI(_i) (0x00019804 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXMCPKTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT 0 +#define I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT) +#define I40E_GLPES_VFIP6RXMCPKTSLO(_i) (0x00019800 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXMCPKTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT 0 +#define I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT) +#define I40E_GLPES_VFIP6RXOCTSHI(_i) (0x00018E04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXOCTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT 0 +#define I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT) +#define I40E_GLPES_VFIP6RXOCTSLO(_i) (0x00018E00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXOCTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT 0 +#define I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT) +#define I40E_GLPES_VFIP6RXPKTSHI(_i) (0x00019004 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXPKTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT 0 +#define I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT) +#define I40E_GLPES_VFIP6RXPKTSLO(_i) (0x00019000 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXPKTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT 0 +#define I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT) +#define I40E_GLPES_VFIP6RXTRUNC(_i) (0x00019300 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6RXTRUNC_MAX_INDEX 31 +#define I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_SHIFT 0 +#define I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_SHIFT) +#define I40E_GLPES_VFIP6TXFRAGSHI(_i) (0x0001A804 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6TXFRAGSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT 0 +#define I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT) +#define I40E_GLPES_VFIP6TXFRAGSLO(_i) (0x0001A800 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6TXFRAGSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT 0 +#define I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT) +#define I40E_GLPES_VFIP6TXMCOCTSHI(_i) (0x0001AA04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6TXMCOCTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT 0 +#define I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT) +#define I40E_GLPES_VFIP6TXMCOCTSLO(_i) (0x0001AA00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6TXMCOCTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT 0 +#define I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT) +#define I40E_GLPES_VFIP6TXMCPKTSHI(_i) (0x0001AC04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6TXMCPKTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT 0 +#define I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT) +#define I40E_GLPES_VFIP6TXMCPKTSLO(_i) (0x0001AC00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6TXMCPKTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT 0 +#define I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT) +#define I40E_GLPES_VFIP6TXNOROUTE(_i) (0x0001AF00 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6TXNOROUTE_MAX_INDEX 31 +#define I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT 0 +#define I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT) +#define I40E_GLPES_VFIP6TXOCTSHI(_i) (0x0001A404 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6TXOCTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT 0 +#define I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT) +#define I40E_GLPES_VFIP6TXOCTSLO(_i) (0x0001A400 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6TXOCTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT 0 +#define I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT) +#define I40E_GLPES_VFIP6TXPKTSHI(_i) (0x0001A604 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6TXPKTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT 0 +#define I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT) +#define I40E_GLPES_VFIP6TXPKTSLO(_i) (0x0001A600 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFIP6TXPKTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT 0 +#define I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT) +#define I40E_GLPES_VFRDMARXRDSHI(_i) (0x0001BE04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMARXRDSHI_MAX_INDEX 31 +#define I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_SHIFT 0 +#define I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_SHIFT) +#define I40E_GLPES_VFRDMARXRDSLO(_i) (0x0001BE00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMARXRDSLO_MAX_INDEX 31 +#define I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_SHIFT 0 +#define I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_SHIFT) +#define I40E_GLPES_VFRDMARXSNDSHI(_i) (0x0001C004 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMARXSNDSHI_MAX_INDEX 31 +#define I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT 0 +#define I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT) +#define I40E_GLPES_VFRDMARXSNDSLO(_i) (0x0001C000 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMARXSNDSLO_MAX_INDEX 31 +#define I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT 0 +#define I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT) +#define I40E_GLPES_VFRDMARXWRSHI(_i) (0x0001BC04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMARXWRSHI_MAX_INDEX 31 +#define I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_SHIFT 0 +#define I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_SHIFT) +#define I40E_GLPES_VFRDMARXWRSLO(_i) (0x0001BC00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMARXWRSLO_MAX_INDEX 31 +#define I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_SHIFT 0 +#define I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_SHIFT) +#define I40E_GLPES_VFRDMATXRDSHI(_i) (0x0001C404 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMATXRDSHI_MAX_INDEX 31 +#define I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_SHIFT 0 +#define I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_SHIFT) +#define I40E_GLPES_VFRDMATXRDSLO(_i) (0x0001C400 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMATXRDSLO_MAX_INDEX 31 +#define I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_SHIFT 0 +#define I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_SHIFT) +#define I40E_GLPES_VFRDMATXSNDSHI(_i) (0x0001C604 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMATXSNDSHI_MAX_INDEX 31 +#define I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT 0 +#define I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT) +#define I40E_GLPES_VFRDMATXSNDSLO(_i) (0x0001C600 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMATXSNDSLO_MAX_INDEX 31 +#define I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT 0 +#define I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT) +#define I40E_GLPES_VFRDMATXWRSHI(_i) (0x0001C204 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMATXWRSHI_MAX_INDEX 31 +#define I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_SHIFT 0 +#define I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_SHIFT) +#define I40E_GLPES_VFRDMATXWRSLO(_i) (0x0001C200 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMATXWRSLO_MAX_INDEX 31 +#define I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_SHIFT 0 +#define I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_SHIFT) +#define I40E_GLPES_VFRDMAVBNDHI(_i) (0x0001C804 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMAVBNDHI_MAX_INDEX 31 +#define I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_SHIFT 0 +#define I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_SHIFT) +#define I40E_GLPES_VFRDMAVBNDLO(_i) (0x0001C800 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMAVBNDLO_MAX_INDEX 31 +#define I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_SHIFT 0 +#define I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_SHIFT) +#define I40E_GLPES_VFRDMAVINVHI(_i) (0x0001CA04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMAVINVHI_MAX_INDEX 31 +#define I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_SHIFT 0 +#define I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_SHIFT) +#define I40E_GLPES_VFRDMAVINVLO(_i) (0x0001CA00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRDMAVINVLO_MAX_INDEX 31 +#define I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_SHIFT 0 +#define I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_SHIFT) +#define I40E_GLPES_VFRXVLANERR(_i) (0x00018000 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFRXVLANERR_MAX_INDEX 31 +#define I40E_GLPES_VFRXVLANERR_RXVLANERR_SHIFT 0 +#define I40E_GLPES_VFRXVLANERR_RXVLANERR_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_VFRXVLANERR_RXVLANERR_SHIFT) +#define I40E_GLPES_VFTCPRTXSEG(_i) (0x0001B600 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFTCPRTXSEG_MAX_INDEX 31 +#define I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_SHIFT 0 +#define I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_SHIFT) +#define I40E_GLPES_VFTCPRXOPTERR(_i) (0x0001B200 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFTCPRXOPTERR_MAX_INDEX 31 +#define I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_SHIFT 0 +#define I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_SHIFT) +#define I40E_GLPES_VFTCPRXPROTOERR(_i) (0x0001B300 + ((_i) * 4)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFTCPRXPROTOERR_MAX_INDEX 31 +#define I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT 0 +#define I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_MASK I40E_MASK(0xFFFFFF, I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT) +#define I40E_GLPES_VFTCPRXSEGSHI(_i) (0x0001B004 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFTCPRXSEGSHI_MAX_INDEX 31 +#define I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT 0 +#define I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT) +#define I40E_GLPES_VFTCPRXSEGSLO(_i) (0x0001B000 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFTCPRXSEGSLO_MAX_INDEX 31 +#define I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT 0 +#define I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT) +#define I40E_GLPES_VFTCPTXSEGHI(_i) (0x0001B404 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFTCPTXSEGHI_MAX_INDEX 31 +#define I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_SHIFT 0 +#define I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_SHIFT) +#define I40E_GLPES_VFTCPTXSEGLO(_i) (0x0001B400 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFTCPTXSEGLO_MAX_INDEX 31 +#define I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_SHIFT 0 +#define I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_SHIFT) +#define I40E_GLPES_VFUDPRXPKTSHI(_i) (0x0001B804 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFUDPRXPKTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT 0 +#define I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT) +#define I40E_GLPES_VFUDPRXPKTSLO(_i) (0x0001B800 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFUDPRXPKTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT 0 +#define I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT) +#define I40E_GLPES_VFUDPTXPKTSHI(_i) (0x0001BA04 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFUDPTXPKTSHI_MAX_INDEX 31 +#define I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT 0 +#define I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_MASK I40E_MASK(0xFFFF, I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT) +#define I40E_GLPES_VFUDPTXPKTSLO(_i) (0x0001BA00 + ((_i) * 8)) /* _i=0...31 */ /* Reset: PE_CORER */ +#define I40E_GLPES_VFUDPTXPKTSLO_MAX_INDEX 31 +#define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT 0 +#define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT) +#define I40E_GLGEN_PME_TO 0x000B81BC /* Reset: POR */ +#define I40E_GLGEN_PME_TO_PME_TO_FOR_PE_SHIFT 0 +#define I40E_GLGEN_PME_TO_PME_TO_FOR_PE_MASK I40E_MASK(0x1, I40E_GLGEN_PME_TO_PME_TO_FOR_PE_SHIFT) +#define I40E_GLQF_APBVT(_i) (0x00260000 + ((_i) * 4)) /* _i=0...2047 */ /* Reset: CORER */ +#define I40E_GLQF_APBVT_MAX_INDEX 2047 +#define I40E_GLQF_APBVT_APBVT_SHIFT 0 +#define I40E_GLQF_APBVT_APBVT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLQF_APBVT_APBVT_SHIFT) +#define I40E_GLQF_FD_PCTYPES(_i) (0x00268000 + ((_i) * 4)) /* _i=0...63 */ /* Reset: POR */ +#define I40E_GLQF_FD_PCTYPES_MAX_INDEX 63 +#define I40E_GLQF_FD_PCTYPES_FD_PCTYPE_SHIFT 0 +#define I40E_GLQF_FD_PCTYPES_FD_PCTYPE_MASK I40E_MASK(0x3F, I40E_GLQF_FD_PCTYPES_FD_PCTYPE_SHIFT) +#define I40E_GLQF_FDEVICTENA(_i) (0x00270384 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */ +#define I40E_GLQF_FDEVICTENA_MAX_INDEX 1 +#define I40E_GLQF_FDEVICTENA_GLQF_FDEVICTENA_SHIFT 0 +#define I40E_GLQF_FDEVICTENA_GLQF_FDEVICTENA_MASK I40E_MASK(0xFFFFFFFF, I40E_GLQF_FDEVICTENA_GLQF_FDEVICTENA_SHIFT) +#define I40E_GLQF_FDEVICTFLAG 0x00270280 /* Reset: CORER */ +#define I40E_GLQF_FDEVICTFLAG_TX_FLAGS_SHIFT 0 +#define I40E_GLQF_FDEVICTFLAG_TX_FLAGS_MASK I40E_MASK(0xFF, I40E_GLQF_FDEVICTFLAG_TX_FLAGS_SHIFT) +#define I40E_GLQF_FDEVICTFLAG_RX_FLAGS_SHIFT 8 +#define I40E_GLQF_FDEVICTFLAG_RX_FLAGS_MASK I40E_MASK(0xFF, I40E_GLQF_FDEVICTFLAG_RX_FLAGS_SHIFT) +#define I40E_PFQF_CTL_2 0x00270300 /* Reset: CORER */ +#define I40E_PFQF_CTL_2_PEHSIZE_SHIFT 0 +#define I40E_PFQF_CTL_2_PEHSIZE_MASK I40E_MASK(0x1F, I40E_PFQF_CTL_2_PEHSIZE_SHIFT) +#define I40E_PFQF_CTL_2_PEDSIZE_SHIFT 5 +#define I40E_PFQF_CTL_2_PEDSIZE_MASK I40E_MASK(0x1F, I40E_PFQF_CTL_2_PEDSIZE_SHIFT) +/* Redefined for X722 family */ +#define I40E_X722_PFQF_HLUT(_i) (0x00240000 + ((_i) * 128)) /* _i=0...127 */ /* Reset: CORER */ +#define I40E_X722_PFQF_HLUT_MAX_INDEX 127 +#define I40E_X722_PFQF_HLUT_LUT0_SHIFT 0 +#define I40E_X722_PFQF_HLUT_LUT0_MASK I40E_MASK(0x7F, I40E_X722_PFQF_HLUT_LUT0_SHIFT) +#define I40E_X722_PFQF_HLUT_LUT1_SHIFT 8 +#define I40E_X722_PFQF_HLUT_LUT1_MASK I40E_MASK(0x7F, I40E_X722_PFQF_HLUT_LUT1_SHIFT) +#define I40E_X722_PFQF_HLUT_LUT2_SHIFT 16 +#define I40E_X722_PFQF_HLUT_LUT2_MASK I40E_MASK(0x7F, I40E_X722_PFQF_HLUT_LUT2_SHIFT) +#define I40E_X722_PFQF_HLUT_LUT3_SHIFT 24 +#define I40E_X722_PFQF_HLUT_LUT3_MASK I40E_MASK(0x7F, I40E_X722_PFQF_HLUT_LUT3_SHIFT) +#define I40E_PFQF_HREGION(_i) (0x00245400 + ((_i) * 128)) /* _i=0...7 */ /* Reset: CORER */ +#define I40E_PFQF_HREGION_MAX_INDEX 7 +#define I40E_PFQF_HREGION_OVERRIDE_ENA_0_SHIFT 0 +#define I40E_PFQF_HREGION_OVERRIDE_ENA_0_MASK I40E_MASK(0x1, I40E_PFQF_HREGION_OVERRIDE_ENA_0_SHIFT) +#define I40E_PFQF_HREGION_REGION_0_SHIFT 1 +#define I40E_PFQF_HREGION_REGION_0_MASK I40E_MASK(0x7, I40E_PFQF_HREGION_REGION_0_SHIFT) +#define I40E_PFQF_HREGION_OVERRIDE_ENA_1_SHIFT 4 +#define I40E_PFQF_HREGION_OVERRIDE_ENA_1_MASK I40E_MASK(0x1, I40E_PFQF_HREGION_OVERRIDE_ENA_1_SHIFT) +#define I40E_PFQF_HREGION_REGION_1_SHIFT 5 +#define I40E_PFQF_HREGION_REGION_1_MASK I40E_MASK(0x7, I40E_PFQF_HREGION_REGION_1_SHIFT) +#define I40E_PFQF_HREGION_OVERRIDE_ENA_2_SHIFT 8 +#define I40E_PFQF_HREGION_OVERRIDE_ENA_2_MASK I40E_MASK(0x1, I40E_PFQF_HREGION_OVERRIDE_ENA_2_SHIFT) +#define I40E_PFQF_HREGION_REGION_2_SHIFT 9 +#define I40E_PFQF_HREGION_REGION_2_MASK I40E_MASK(0x7, I40E_PFQF_HREGION_REGION_2_SHIFT) +#define I40E_PFQF_HREGION_OVERRIDE_ENA_3_SHIFT 12 +#define I40E_PFQF_HREGION_OVERRIDE_ENA_3_MASK I40E_MASK(0x1, I40E_PFQF_HREGION_OVERRIDE_ENA_3_SHIFT) +#define I40E_PFQF_HREGION_REGION_3_SHIFT 13 +#define I40E_PFQF_HREGION_REGION_3_MASK I40E_MASK(0x7, I40E_PFQF_HREGION_REGION_3_SHIFT) +#define I40E_PFQF_HREGION_OVERRIDE_ENA_4_SHIFT 16 +#define I40E_PFQF_HREGION_OVERRIDE_ENA_4_MASK I40E_MASK(0x1, I40E_PFQF_HREGION_OVERRIDE_ENA_4_SHIFT) +#define I40E_PFQF_HREGION_REGION_4_SHIFT 17 +#define I40E_PFQF_HREGION_REGION_4_MASK I40E_MASK(0x7, I40E_PFQF_HREGION_REGION_4_SHIFT) +#define I40E_PFQF_HREGION_OVERRIDE_ENA_5_SHIFT 20 +#define I40E_PFQF_HREGION_OVERRIDE_ENA_5_MASK I40E_MASK(0x1, I40E_PFQF_HREGION_OVERRIDE_ENA_5_SHIFT) +#define I40E_PFQF_HREGION_REGION_5_SHIFT 21 +#define I40E_PFQF_HREGION_REGION_5_MASK I40E_MASK(0x7, I40E_PFQF_HREGION_REGION_5_SHIFT) +#define I40E_PFQF_HREGION_OVERRIDE_ENA_6_SHIFT 24 +#define I40E_PFQF_HREGION_OVERRIDE_ENA_6_MASK I40E_MASK(0x1, I40E_PFQF_HREGION_OVERRIDE_ENA_6_SHIFT) +#define I40E_PFQF_HREGION_REGION_6_SHIFT 25 +#define I40E_PFQF_HREGION_REGION_6_MASK I40E_MASK(0x7, I40E_PFQF_HREGION_REGION_6_SHIFT) +#define I40E_PFQF_HREGION_OVERRIDE_ENA_7_SHIFT 28 +#define I40E_PFQF_HREGION_OVERRIDE_ENA_7_MASK I40E_MASK(0x1, I40E_PFQF_HREGION_OVERRIDE_ENA_7_SHIFT) +#define I40E_PFQF_HREGION_REGION_7_SHIFT 29 +#define I40E_PFQF_HREGION_REGION_7_MASK I40E_MASK(0x7, I40E_PFQF_HREGION_REGION_7_SHIFT) +#define I40E_VSIQF_CTL_RSS_LUT_TYPE_SHIFT 8 +#define I40E_VSIQF_CTL_RSS_LUT_TYPE_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_RSS_LUT_TYPE_SHIFT) +#define I40E_VSIQF_HKEY(_i, _VSI) (0x002A0000 + ((_i) * 2048 + (_VSI) * 4)) /* _i=0...12, _VSI=0...383 */ /* Reset: CORER */ +#define I40E_VSIQF_HKEY_MAX_INDEX 12 +#define I40E_VSIQF_HKEY_KEY_0_SHIFT 0 +#define I40E_VSIQF_HKEY_KEY_0_MASK I40E_MASK(0xFF, I40E_VSIQF_HKEY_KEY_0_SHIFT) +#define I40E_VSIQF_HKEY_KEY_1_SHIFT 8 +#define I40E_VSIQF_HKEY_KEY_1_MASK I40E_MASK(0xFF, I40E_VSIQF_HKEY_KEY_1_SHIFT) +#define I40E_VSIQF_HKEY_KEY_2_SHIFT 16 +#define I40E_VSIQF_HKEY_KEY_2_MASK I40E_MASK(0xFF, I40E_VSIQF_HKEY_KEY_2_SHIFT) +#define I40E_VSIQF_HKEY_KEY_3_SHIFT 24 +#define I40E_VSIQF_HKEY_KEY_3_MASK I40E_MASK(0xFF, I40E_VSIQF_HKEY_KEY_3_SHIFT) +#define I40E_VSIQF_HLUT(_i, _VSI) (0x00220000 + ((_i) * 2048 + (_VSI) * 4)) /* _i=0...15, _VSI=0...383 */ /* Reset: CORER */ +#define I40E_VSIQF_HLUT_MAX_INDEX 15 +#define I40E_VSIQF_HLUT_LUT0_SHIFT 0 +#define I40E_VSIQF_HLUT_LUT0_MASK I40E_MASK(0xF, I40E_VSIQF_HLUT_LUT0_SHIFT) +#define I40E_VSIQF_HLUT_LUT1_SHIFT 8 +#define I40E_VSIQF_HLUT_LUT1_MASK I40E_MASK(0xF, I40E_VSIQF_HLUT_LUT1_SHIFT) +#define I40E_VSIQF_HLUT_LUT2_SHIFT 16 +#define I40E_VSIQF_HLUT_LUT2_MASK I40E_MASK(0xF, I40E_VSIQF_HLUT_LUT2_SHIFT) +#define I40E_VSIQF_HLUT_LUT3_SHIFT 24 +#define I40E_VSIQF_HLUT_LUT3_MASK I40E_MASK(0xF, I40E_VSIQF_HLUT_LUT3_SHIFT) +#define I40E_GLGEN_STAT_CLEAR 0x00390004 /* Reset: CORER */ +#define I40E_GLGEN_STAT_CLEAR_GLGEN_STAT_CLEAR_SHIFT 0 +#define I40E_GLGEN_STAT_CLEAR_GLGEN_STAT_CLEAR_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_CLEAR_GLGEN_STAT_CLEAR_SHIFT) +#define I40E_GLGEN_STAT_HALT 0x00390000 /* Reset: CORER */ +#define I40E_GLGEN_STAT_HALT_HALT_CELLS_SHIFT 0 +#define I40E_GLGEN_STAT_HALT_HALT_CELLS_MASK I40E_MASK(0x3FFFFFFF, I40E_GLGEN_STAT_HALT_HALT_CELLS_SHIFT) +#define I40E_VFINT_DYN_CTL01_WB_ON_ITR_SHIFT 30 +#define I40E_VFINT_DYN_CTL01_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_WB_ON_ITR_SHIFT) +#define I40E_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT 30 +#define I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT) +#define I40E_VFPE_AEQALLOC1 0x0000A400 /* Reset: VFR */ +#define I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT 0 +#define I40E_VFPE_AEQALLOC1_AECOUNT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT) +#define I40E_VFPE_CCQPHIGH1 0x00009800 /* Reset: VFR */ +#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT 0 +#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT) +#define I40E_VFPE_CCQPLOW1 0x0000AC00 /* Reset: VFR */ +#define I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT 0 +#define I40E_VFPE_CCQPLOW1_PECCQPLOW_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT) +#define I40E_VFPE_CCQPSTATUS1 0x0000B800 /* Reset: VFR */ +#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT 0 +#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_MASK I40E_MASK(0x1, I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT) +#define I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_SHIFT 4 +#define I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_MASK I40E_MASK(0x7, I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_SHIFT) +#define I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_SHIFT 16 +#define I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_MASK I40E_MASK(0x3F, I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_SHIFT) +#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT 31 +#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_MASK I40E_MASK(0x1, I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT) +#define I40E_VFPE_CQACK1 0x0000B000 /* Reset: VFR */ +#define I40E_VFPE_CQACK1_PECQID_SHIFT 0 +#define I40E_VFPE_CQACK1_PECQID_MASK I40E_MASK(0x1FFFF, I40E_VFPE_CQACK1_PECQID_SHIFT) +#define I40E_VFPE_CQARM1 0x0000B400 /* Reset: VFR */ +#define I40E_VFPE_CQARM1_PECQID_SHIFT 0 +#define I40E_VFPE_CQARM1_PECQID_MASK I40E_MASK(0x1FFFF, I40E_VFPE_CQARM1_PECQID_SHIFT) +#define I40E_VFPE_CQPDB1 0x0000BC00 /* Reset: VFR */ +#define I40E_VFPE_CQPDB1_WQHEAD_SHIFT 0 +#define I40E_VFPE_CQPDB1_WQHEAD_MASK I40E_MASK(0x7FF, I40E_VFPE_CQPDB1_WQHEAD_SHIFT) +#define I40E_VFPE_CQPERRCODES1 0x00009C00 /* Reset: VFR */ +#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT 0 +#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_MASK I40E_MASK(0xFFFF, I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT) +#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT 16 +#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_MASK I40E_MASK(0xFFFF, I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT) +#define I40E_VFPE_CQPTAIL1 0x0000A000 /* Reset: VFR */ +#define I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT 0 +#define I40E_VFPE_CQPTAIL1_WQTAIL_MASK I40E_MASK(0x7FF, I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT) +#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT 31 +#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_MASK I40E_MASK(0x1, I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT) +#define I40E_VFPE_IPCONFIG01 0x00008C00 /* Reset: VFR */ +#define I40E_VFPE_IPCONFIG01_PEIPID_SHIFT 0 +#define I40E_VFPE_IPCONFIG01_PEIPID_MASK I40E_MASK(0xFFFF, I40E_VFPE_IPCONFIG01_PEIPID_SHIFT) +#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT 16 +#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_MASK I40E_MASK(0x1, I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT) +#define I40E_VFPE_MRTEIDXMASK1 0x00009000 /* Reset: VFR */ +#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT 0 +#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_MASK I40E_MASK(0x1F, I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT) +#define I40E_VFPE_RCVUNEXPECTEDERROR1 0x00009400 /* Reset: VFR */ +#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT 0 +#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_MASK I40E_MASK(0xFFFFFF, I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT) +#define I40E_VFPE_TCPNOWTIMER1 0x0000A800 /* Reset: VFR */ +#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT 0 +#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT) +#define I40E_VFPE_WQEALLOC1 0x0000C000 /* Reset: VFR */ +#define I40E_VFPE_WQEALLOC1_PEQPID_SHIFT 0 +#define I40E_VFPE_WQEALLOC1_PEQPID_MASK I40E_MASK(0x3FFFF, I40E_VFPE_WQEALLOC1_PEQPID_SHIFT) +#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT 20 +#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_MASK I40E_MASK(0xFFF, I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT) +#endif /* _I40E_REGISTER_H_ */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_register.h b/drivers/net/ethernet/intel/i40evf/i40e_register.h index 3cc737629bf7..2e2ccc1719b6 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_register.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_register.h @@ -3366,4 +3366,64 @@ #define I40E_VFQF_HREGION_OVERRIDE_ENA_7_MASK I40E_MASK(0x1, I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT) #define I40E_VFQF_HREGION_REGION_7_SHIFT 29 #define I40E_VFQF_HREGION_REGION_7_MASK I40E_MASK(0x7, I40E_VFQF_HREGION_REGION_7_SHIFT) -#endif +#define I40E_VFINT_DYN_CTL01_WB_ON_ITR_SHIFT 30 +#define I40E_VFINT_DYN_CTL01_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL01_WB_ON_ITR_SHIFT) +#define I40E_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT 30 +#define I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN1_WB_ON_ITR_SHIFT) +#define I40E_VFPE_AEQALLOC1 0x0000A400 /* Reset: VFR */ +#define I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT 0 +#define I40E_VFPE_AEQALLOC1_AECOUNT_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT) +#define I40E_VFPE_CCQPHIGH1 0x00009800 /* Reset: VFR */ +#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT 0 +#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT) +#define I40E_VFPE_CCQPLOW1 0x0000AC00 /* Reset: VFR */ +#define I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT 0 +#define I40E_VFPE_CCQPLOW1_PECCQPLOW_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT) +#define I40E_VFPE_CCQPSTATUS1 0x0000B800 /* Reset: VFR */ +#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT 0 +#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_MASK I40E_MASK(0x1, I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT) +#define I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_SHIFT 4 +#define I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_MASK I40E_MASK(0x7, I40E_VFPE_CCQPSTATUS1_HMC_PROFILE_SHIFT) +#define I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_SHIFT 16 +#define I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_MASK I40E_MASK(0x3F, I40E_VFPE_CCQPSTATUS1_RDMA_EN_VFS_SHIFT) +#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT 31 +#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_MASK I40E_MASK(0x1, I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT) +#define I40E_VFPE_CQACK1 0x0000B000 /* Reset: VFR */ +#define I40E_VFPE_CQACK1_PECQID_SHIFT 0 +#define I40E_VFPE_CQACK1_PECQID_MASK I40E_MASK(0x1FFFF, I40E_VFPE_CQACK1_PECQID_SHIFT) +#define I40E_VFPE_CQARM1 0x0000B400 /* Reset: VFR */ +#define I40E_VFPE_CQARM1_PECQID_SHIFT 0 +#define I40E_VFPE_CQARM1_PECQID_MASK I40E_MASK(0x1FFFF, I40E_VFPE_CQARM1_PECQID_SHIFT) +#define I40E_VFPE_CQPDB1 0x0000BC00 /* Reset: VFR */ +#define I40E_VFPE_CQPDB1_WQHEAD_SHIFT 0 +#define I40E_VFPE_CQPDB1_WQHEAD_MASK I40E_MASK(0x7FF, I40E_VFPE_CQPDB1_WQHEAD_SHIFT) +#define I40E_VFPE_CQPERRCODES1 0x00009C00 /* Reset: VFR */ +#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT 0 +#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_MASK I40E_MASK(0xFFFF, I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT) +#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT 16 +#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_MASK I40E_MASK(0xFFFF, I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT) +#define I40E_VFPE_CQPTAIL1 0x0000A000 /* Reset: VFR */ +#define I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT 0 +#define I40E_VFPE_CQPTAIL1_WQTAIL_MASK I40E_MASK(0x7FF, I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT) +#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT 31 +#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_MASK I40E_MASK(0x1, I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT) +#define I40E_VFPE_IPCONFIG01 0x00008C00 /* Reset: VFR */ +#define I40E_VFPE_IPCONFIG01_PEIPID_SHIFT 0 +#define I40E_VFPE_IPCONFIG01_PEIPID_MASK I40E_MASK(0xFFFF, I40E_VFPE_IPCONFIG01_PEIPID_SHIFT) +#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT 16 +#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_MASK I40E_MASK(0x1, I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT) +#define I40E_VFPE_MRTEIDXMASK1 0x00009000 /* Reset: VFR */ +#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT 0 +#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_MASK I40E_MASK(0x1F, I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT) +#define I40E_VFPE_RCVUNEXPECTEDERROR1 0x00009400 /* Reset: VFR */ +#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT 0 +#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_MASK I40E_MASK(0xFFFFFF, I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT) +#define I40E_VFPE_TCPNOWTIMER1 0x0000A800 /* Reset: VFR */ +#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT 0 +#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_MASK I40E_MASK(0xFFFFFFFF, I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT) +#define I40E_VFPE_WQEALLOC1 0x0000C000 /* Reset: VFR */ +#define I40E_VFPE_WQEALLOC1_PEQPID_SHIFT 0 +#define I40E_VFPE_WQEALLOC1_PEQPID_MASK I40E_MASK(0x3FFFF, I40E_VFPE_WQEALLOC1_PEQPID_SHIFT) +#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT 20 +#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_MASK I40E_MASK(0xFFF, I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT) +#endif /* _I40E_REGISTER_H_ */ -- cgit v1.3-6-gb490 From e25d00b87b26f96f91434e6608dc4b05f5ef5498 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Tue, 23 Jun 2015 19:00:04 -0400 Subject: i40e/i40evf: RSS changes for X722 X722 uses the admin queue to configure RSS. This patch adds the necessary flow changes to configure RSS through AQ. It also adds the separate VMDQ2 lookup tables and hash key programming for X722. X722 also exposes a different set of PCTYPES for RSS, this patch accommodates those changes. Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 7 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 156 ++++++++++++++----- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 12 ++ drivers/net/ethernet/intel/i40e/i40e_type.h | 15 +- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 11 +- drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 12 ++ drivers/net/ethernet/intel/i40evf/i40e_type.h | 15 +- drivers/net/ethernet/intel/i40evf/i40evf.h | 2 + drivers/net/ethernet/intel/i40evf/i40evf_main.c | 166 ++++++++++++++++----- 9 files changed, 307 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 99148861b1c0..66d0780f1297 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -79,10 +79,13 @@ #define I40E_MIN_MSIX 2 #define I40E_DEFAULT_NUM_VMDQ_VSI 8 /* max 256 VSIs */ #define I40E_MIN_VSI_ALLOC 51 /* LAN, ATR, FCOE, 32 VF, 16 VMDQ */ -#define I40E_DEFAULT_QUEUES_PER_VMDQ 2 /* max 16 qps */ +/* max 16 qps */ +#define i40e_default_queues_per_vmdq(pf) \ + (((pf)->flags & I40E_FLAG_RSS_AQ_CAPABLE) ? 4 : 1) #define I40E_DEFAULT_QUEUES_PER_VF 4 #define I40E_DEFAULT_QUEUES_PER_TC 1 /* should be a power of 2 */ -#define I40E_MAX_QUEUES_PER_TC 64 /* should be a power of 2 */ +#define i40e_pf_get_max_q_per_tc(pf) \ + (((pf)->flags & I40E_FLAG_128_QP_RSS_CAPABLE) ? 128 : 64) #define I40E_FDIR_RING 0 #define I40E_FDIR_RING_COUNT 32 #ifdef I40E_FCOE diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 3269b059762e..2e8416560632 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1550,7 +1550,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, */ qcount = min_t(int, vsi->alloc_queue_pairs, pf->num_lan_msix); num_tc_qps = qcount / numtc; - num_tc_qps = min_t(int, num_tc_qps, I40E_MAX_QUEUES_PER_TC); + num_tc_qps = min_t(int, num_tc_qps, i40e_pf_get_max_q_per_tc(pf)); /* Setup queue offset/count for all TCs for given VSI */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { @@ -7469,62 +7469,139 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf) } /** - * i40e_config_rss - Prepare for RSS if used + * i40e_config_rss_aq - Prepare for RSS using AQ commands + * @vsi: vsi structure + * @seed: RSS hash seed + **/ +static int i40e_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed) +{ + struct i40e_aqc_get_set_rss_key_data rss_key; + struct i40e_pf *pf = vsi->back; + struct i40e_hw *hw = &pf->hw; + bool pf_lut = false; + u8 *rss_lut; + int ret, i; + + memset(&rss_key, 0, sizeof(rss_key)); + memcpy(&rss_key, seed, sizeof(rss_key)); + + rss_lut = kzalloc(pf->rss_table_size, GFP_KERNEL); + if (!rss_lut) + return -ENOMEM; + + /* Populate the LUT with max no. of queues in round robin fashion */ + for (i = 0; i < vsi->rss_table_size; i++) + rss_lut[i] = i % vsi->rss_size; + + ret = i40e_aq_set_rss_key(hw, vsi->id, &rss_key); + if (ret) { + dev_info(&pf->pdev->dev, + "Cannot set RSS key, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); + return ret; + } + + if (vsi->type == I40E_VSI_MAIN) + pf_lut = true; + + ret = i40e_aq_set_rss_lut(hw, vsi->id, pf_lut, rss_lut, + vsi->rss_table_size); + if (ret) + dev_info(&pf->pdev->dev, + "Cannot set RSS lut, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); + + return ret; +} + +/** + * i40e_vsi_config_rss - Prepare for VSI(VMDq) RSS if used + * @vsi: VSI structure + **/ +static int i40e_vsi_config_rss(struct i40e_vsi *vsi) +{ + u8 seed[I40E_HKEY_ARRAY_SIZE]; + struct i40e_pf *pf = vsi->back; + + netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE); + vsi->rss_size = min_t(int, pf->rss_size, vsi->num_queue_pairs); + + if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) + return i40e_config_rss_aq(vsi, seed); + + return 0; +} + +/** + * i40e_config_rss_reg - Prepare for RSS if used * @pf: board private structure + * @seed: RSS hash seed **/ -static int i40e_config_rss(struct i40e_pf *pf) +static int i40e_config_rss_reg(struct i40e_pf *pf, const u8 *seed) { - u32 rss_key[I40E_PFQF_HKEY_MAX_INDEX + 1]; struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; struct i40e_hw *hw = &pf->hw; + u32 *seed_dw = (u32 *)seed; + u32 current_queue = 0; u32 lut = 0; int i, j; - u64 hena; - u32 reg_val; - netdev_rss_key_fill(rss_key, sizeof(rss_key)); + /* Fill out hash function seed */ for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) - wr32(hw, I40E_PFQF_HKEY(i), rss_key[i]); + wr32(hw, I40E_PFQF_HKEY(i), seed_dw[i]); + + for (i = 0; i <= I40E_PFQF_HLUT_MAX_INDEX; i++) { + lut = 0; + for (j = 0; j < 4; j++) { + if (current_queue == vsi->rss_size) + current_queue = 0; + lut |= ((current_queue) << (8 * j)); + current_queue++; + } + wr32(&pf->hw, I40E_PFQF_HLUT(i), lut); + } + i40e_flush(hw); + + return 0; +} + +/** + * i40e_config_rss - Prepare for RSS if used + * @pf: board private structure + **/ +static int i40e_config_rss(struct i40e_pf *pf) +{ + struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; + u8 seed[I40E_HKEY_ARRAY_SIZE]; + struct i40e_hw *hw = &pf->hw; + u32 reg_val; + u64 hena; + + netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE); /* By default we enable TCP/UDP with IPv4/IPv6 ptypes */ hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) | ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32); - hena |= I40E_DEFAULT_RSS_HENA; + hena |= i40e_pf_get_default_rss_hena(pf); + wr32(hw, I40E_PFQF_HENA(0), (u32)hena); wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); vsi->rss_size = min_t(int, pf->rss_size, vsi->num_queue_pairs); - /* Check capability and Set table size and register per hw expectation*/ + /* Determine the RSS table size based on the hardware capabilities */ reg_val = rd32(hw, I40E_PFQF_CTL_0); - if (pf->rss_table_size == 512) - reg_val |= I40E_PFQF_CTL_0_HASHLUTSIZE_512; - else - reg_val &= ~I40E_PFQF_CTL_0_HASHLUTSIZE_512; + reg_val = (pf->rss_table_size == 512) ? + (reg_val | I40E_PFQF_CTL_0_HASHLUTSIZE_512) : + (reg_val & ~I40E_PFQF_CTL_0_HASHLUTSIZE_512); wr32(hw, I40E_PFQF_CTL_0, reg_val); - /* Populate the LUT with max no. of queues in round robin fashion */ - for (i = 0, j = 0; i < pf->rss_table_size; i++, j++) { - - /* The assumption is that lan qp count will be the highest - * qp count for any PF VSI that needs RSS. - * If multiple VSIs need RSS support, all the qp counts - * for those VSIs should be a power of 2 for RSS to work. - * If LAN VSI is the only consumer for RSS then this requirement - * is not necessary. - */ - if (j == vsi->rss_size) - j = 0; - /* lut = 4-byte sliding window of 4 lut entries */ - lut = (lut << 8) | (j & - (BIT(pf->hw.func_caps.rss_table_entry_width) - 1)); - /* On i = 3, we have 4 entries in lut; write to the register */ - if ((i & 3) == 3) - wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); - } - i40e_flush(hw); - - return 0; + if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) + return i40e_config_rss_aq(pf->vsi[pf->lan_vsi], seed); + else + return i40e_config_rss_reg(pf, seed); } /** @@ -7765,9 +7842,8 @@ static int i40e_sw_init(struct i40e_pf *pf) } if (pf->hw.func_caps.vmdq) { - pf->flags |= I40E_FLAG_VMDQ_ENABLED; pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI; - pf->num_vmdq_qps = I40E_DEFAULT_QUEUES_PER_VMDQ; + pf->flags |= I40E_FLAG_VMDQ_ENABLED; } #ifdef I40E_FCOE @@ -8948,6 +9024,10 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type, break; } + if ((pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) && + (vsi->type == I40E_VSI_VMDQ2)) { + ret = i40e_vsi_config_rss(vsi); + } return vsi; err_rings: diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 429833c47245..8b618d0151cd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -78,6 +78,18 @@ enum i40e_dyn_idx_t { BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6) | \ BIT_ULL(I40E_FILTER_PCTYPE_L2_PAYLOAD)) +#define I40E_DEFAULT_RSS_HENA_EXPANDED (I40E_DEFAULT_RSS_HENA | \ + BIT(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \ + BIT(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \ + BIT(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \ + BIT(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \ + BIT(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \ + BIT(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP)) + +#define i40e_pf_get_default_rss_hena(pf) \ + (((pf)->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE) ? \ + I40E_DEFAULT_RSS_HENA_EXPANDED : I40E_DEFAULT_RSS_HENA) + /* Supported Rx Buffer Sizes */ #define I40E_RXBUFFER_512 512 /* Used for packet split */ #define I40E_RXBUFFER_2048 2048 diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 778266fa4104..1ffd27143a3c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -973,15 +973,24 @@ struct i40e_filter_program_desc { /* Packet Classifier Types for filters */ enum i40e_filter_pctype { - /* Note: Values 0-30 are reserved for future use */ + /* Note: Values 0-28 are reserved for future use. + * Value 29, 30, 32 are not supported on XL710 and X710. + */ + I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP = 29, + I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP = 30, I40E_FILTER_PCTYPE_NONF_IPV4_UDP = 31, - /* Note: Value 32 is reserved for future use */ + I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK = 32, I40E_FILTER_PCTYPE_NONF_IPV4_TCP = 33, I40E_FILTER_PCTYPE_NONF_IPV4_SCTP = 34, I40E_FILTER_PCTYPE_NONF_IPV4_OTHER = 35, I40E_FILTER_PCTYPE_FRAG_IPV4 = 36, - /* Note: Values 37-40 are reserved for future use */ + /* Note: Values 37-38 are reserved for future use. + * Value 39, 40, 42 are not supported on XL710 and X710. + */ + I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP = 39, + I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP = 40, I40E_FILTER_PCTYPE_NONF_IPV6_UDP = 41, + I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK = 42, I40E_FILTER_PCTYPE_NONF_IPV6_TCP = 43, I40E_FILTER_PCTYPE_NONF_IPV6_SCTP = 44, I40E_FILTER_PCTYPE_NONF_IPV6_OTHER = 45, diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index d29d4062addf..8a7607c6e142 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1177,9 +1177,14 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) vfres->vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2; vsi = pf->vsi[vf->lan_vsi_idx]; if (!vsi->info.pvid) - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN | - I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG; - + vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN; + if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) { + if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ) + vfres->vf_offload_flags |= + I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ; + } else { + vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG; + } vfres->num_vsis = num_vsis; vfres->num_queue_pairs = vf->num_queue_pairs; vfres->max_vectors = pf->hw.func_caps.num_msix_vectors_vf; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h index 6b47c818d1f0..b2f9b8203c67 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h @@ -78,6 +78,18 @@ enum i40e_dyn_idx_t { BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6) | \ BIT_ULL(I40E_FILTER_PCTYPE_L2_PAYLOAD)) +#define I40E_DEFAULT_RSS_HENA_EXPANDED (I40E_DEFAULT_RSS_HENA | \ + BIT(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \ + BIT(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \ + BIT(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \ + BIT(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \ + BIT(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \ + BIT(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP)) + +#define i40e_pf_get_default_rss_hena(pf) \ + (((pf)->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE) ? \ + I40E_DEFAULT_RSS_HENA_EXPANDED : I40E_DEFAULT_RSS_HENA) + /* Supported Rx Buffer Sizes */ #define I40E_RXBUFFER_512 512 /* Used for packet split */ #define I40E_RXBUFFER_2048 2048 diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index c50536b0e15c..627bf7689bbc 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -967,15 +967,24 @@ struct i40e_filter_program_desc { /* Packet Classifier Types for filters */ enum i40e_filter_pctype { - /* Note: Values 0-30 are reserved for future use */ + /* Note: Values 0-28 are reserved for future use. + * Value 29, 30, 32 are not supported on XL710 and X710. + */ + I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP = 29, + I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP = 30, I40E_FILTER_PCTYPE_NONF_IPV4_UDP = 31, - /* Note: Value 32 is reserved for future use */ + I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK = 32, I40E_FILTER_PCTYPE_NONF_IPV4_TCP = 33, I40E_FILTER_PCTYPE_NONF_IPV4_SCTP = 34, I40E_FILTER_PCTYPE_NONF_IPV4_OTHER = 35, I40E_FILTER_PCTYPE_FRAG_IPV4 = 36, - /* Note: Values 37-40 are reserved for future use */ + /* Note: Values 37-38 are reserved for future use. + * Value 39, 40, 42 are not supported on XL710 and X710. + */ + I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP = 39, + I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP = 40, I40E_FILTER_PCTYPE_NONF_IPV6_UDP = 41, + I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK = 42, I40E_FILTER_PCTYPE_NONF_IPV6_TCP = 43, I40E_FILTER_PCTYPE_NONF_IPV6_SCTP = 44, I40E_FILTER_PCTYPE_NONF_IPV6_OTHER = 45, diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index bd227b39ac55..fa421d6020be 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -101,6 +101,8 @@ struct i40e_vsi { #define MAX_RX_QUEUES 8 #define MAX_TX_QUEUES MAX_RX_QUEUES +#define I40EVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4) + /* MAX_MSIX_Q_VECTORS of these are allocated, * but we only use one per queue-specific vector. */ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 642944e622af..2a6063a3a14d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1172,6 +1172,113 @@ out: return err; } +/** + * i40e_configure_rss_aq - Prepare for RSS using AQ commands + * @vsi: vsi structure + * @seed: RSS hash seed + **/ +static void i40evf_configure_rss_aq(struct i40e_vsi *vsi, const u8 *seed) +{ + struct i40e_aqc_get_set_rss_key_data rss_key; + struct i40evf_adapter *adapter = vsi->back; + struct i40e_hw *hw = &adapter->hw; + int ret = 0, i; + u8 *rss_lut; + + if (!vsi->id) + return; + + if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) { + /* bail because we already have a command pending */ + dev_err(&adapter->pdev->dev, "Cannot confiure RSS, command %d pending\n", + adapter->current_op); + return; + } + + memset(&rss_key, 0, sizeof(rss_key)); + memcpy(&rss_key, seed, sizeof(rss_key)); + + rss_lut = kzalloc(((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4), GFP_KERNEL); + if (!rss_lut) + return; + + /* Populate the LUT with max no. PF queues in round robin fashion */ + for (i = 0; i <= (I40E_VFQF_HLUT_MAX_INDEX * 4); i++) + rss_lut[i] = i % adapter->num_active_queues; + + ret = i40evf_aq_set_rss_key(hw, vsi->id, &rss_key); + if (ret) { + dev_err(&adapter->pdev->dev, + "Cannot set RSS key, err %s aq_err %s\n", + i40evf_stat_str(hw, ret), + i40evf_aq_str(hw, hw->aq.asq_last_status)); + return; + } + + ret = i40evf_aq_set_rss_lut(hw, vsi->id, false, rss_lut, + (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4); + if (ret) + dev_err(&adapter->pdev->dev, + "Cannot set RSS lut, err %s aq_err %s\n", + i40evf_stat_str(hw, ret), + i40evf_aq_str(hw, hw->aq.asq_last_status)); +} + +/** + * i40e_configure_rss_reg - Prepare for RSS if used + * @adapter: board private structure + * @seed: RSS hash seed + **/ +static void i40evf_configure_rss_reg(struct i40evf_adapter *adapter, + const u8 *seed) +{ + struct i40e_hw *hw = &adapter->hw; + u32 *seed_dw = (u32 *)seed; + u32 cqueue = 0; + u32 lut = 0; + int i, j; + + /* Fill out hash function seed */ + for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++) + wr32(hw, I40E_VFQF_HKEY(i), seed_dw[i]); + + /* Populate the LUT with max no. PF queues in round robin fashion */ + for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) { + lut = 0; + for (j = 0; j < 4; j++) { + if (cqueue == adapter->num_active_queues) + cqueue = 0; + lut |= ((cqueue) << (8 * j)); + cqueue++; + } + wr32(hw, I40E_VFQF_HLUT(i), lut); + } + i40e_flush(hw); +} + +/** + * i40evf_configure_rss - Prepare for RSS + * @adapter: board private structure + **/ +static void i40evf_configure_rss(struct i40evf_adapter *adapter) +{ + struct i40e_hw *hw = &adapter->hw; + u8 seed[I40EVF_HKEY_ARRAY_SIZE]; + u64 hena; + + netdev_rss_key_fill((void *)seed, I40EVF_HKEY_ARRAY_SIZE); + + /* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */ + hena = I40E_DEFAULT_RSS_HENA; + wr32(hw, I40E_VFQF_HENA(0), (u32)hena); + wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32)); + + if (RSS_AQ(adapter)) + i40evf_configure_rss_aq(&adapter->vsi, seed); + else + i40evf_configure_rss_reg(adapter, seed); +} + /** * i40evf_alloc_q_vectors - Allocate memory for interrupt vectors * @adapter: board private structure to initialize @@ -1417,6 +1524,16 @@ static void i40evf_watchdog_task(struct work_struct *work) goto watchdog_done; } + if (adapter->aq_required & I40EVF_FLAG_AQ_CONFIGURE_RSS) { + /* This message goes straight to the firmware, not the + * PF, so we don't have to set current_op as we will + * not get a response through the ARQ. + */ + i40evf_configure_rss(adapter); + adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_RSS; + goto watchdog_done; + } + if (adapter->state == __I40EVF_RUNNING) i40evf_request_stats(adapter); watchdog_done: @@ -1439,45 +1556,6 @@ restart_watchdog: schedule_work(&adapter->adminq_task); } -/** - * i40evf_configure_rss - Prepare for RSS - * @adapter: board private structure - **/ -static void i40evf_configure_rss(struct i40evf_adapter *adapter) -{ - u32 rss_key[I40E_VFQF_HKEY_MAX_INDEX + 1]; - struct i40e_hw *hw = &adapter->hw; - u32 cqueue = 0; - u32 lut = 0; - int i, j; - u64 hena; - - /* Hash type is configured by the PF - we just supply the key */ - netdev_rss_key_fill(rss_key, sizeof(rss_key)); - - /* Fill out hash function seed */ - for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++) - wr32(hw, I40E_VFQF_HKEY(i), rss_key[i]); - - /* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */ - hena = I40E_DEFAULT_RSS_HENA; - wr32(hw, I40E_VFQF_HENA(0), (u32)hena); - wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32)); - - /* Populate the LUT with max no. of queues in round robin fashion */ - for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) { - lut = 0; - for (j = 0; j < 4; j++) { - if (cqueue == adapter->num_active_queues) - cqueue = 0; - lut |= ((cqueue) << (8 * j)); - cqueue++; - } - wr32(hw, I40E_VFQF_HLUT(i), lut); - } - i40e_flush(hw); -} - #define I40EVF_RESET_WAIT_MS 10 #define I40EVF_RESET_WAIT_COUNT 500 /** @@ -2187,7 +2265,8 @@ static void i40evf_init_task(struct work_struct *work) if (err) goto err_sw_init; i40evf_map_rings_to_vectors(adapter); - i40evf_configure_rss(adapter); + if (!RSS_AQ(adapter)) + i40evf_configure_rss(adapter); err = i40evf_request_misc_irq(adapter); if (err) goto err_sw_init; @@ -2212,6 +2291,13 @@ static void i40evf_init_task(struct work_struct *work) adapter->state = __I40EVF_DOWN; set_bit(__I40E_DOWN, &adapter->vsi.state); i40evf_misc_irq_enable(adapter); + + if (RSS_AQ(adapter)) { + adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_RSS; + mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); + } else { + i40evf_configure_rss(adapter); + } return; restart: schedule_delayed_work(&adapter->init_task, -- cgit v1.3-6-gb490 From 8e0764b4d6be42459b6f517e199b8c7df43cc15c Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 5 Jun 2015 12:20:30 -0400 Subject: i40e/i40evf: Add support for writeback on ITR feature for X722 X722 fixes an issue from X710 where TX descriptor WB would not happen if the interrupts were disabled. In order for the write backs to happen a bit needs to be set in the dynamic interrupt control register called WB_ON_ITR. With this feature, the SW driver need not arm SW interrupts to work around the issue in X710. Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_main.c | 2 ++ drivers/net/ethernet/intel/i40e/i40e_txrx.c | 46 +++++++++++++++++++++------ drivers/net/ethernet/intel/i40e/i40e_txrx.h | 2 ++ drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 38 ++++++++++++++++------ drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 2 ++ drivers/net/ethernet/intel/i40evf/i40evf.h | 1 + 7 files changed, 74 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 66d0780f1297..0f97883c1493 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -560,6 +560,7 @@ struct i40e_q_vector { cpumask_t affinity_mask; struct rcu_head rcu; /* to avoid race with update stats on free */ char name[I40E_INT_NAME_STR_LEN]; + bool arm_wb_state; } ____cacheline_internodealigned_in_smp; /* lan device */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 2e8416560632..28f547ce4eb5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7071,6 +7071,8 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi) tx_ring->count = vsi->num_desc; tx_ring->size = 0; tx_ring->dcb_tc = 0; + if (vsi->back->flags & I40E_FLAG_WB_ON_ITR_CAPABLE) + tx_ring->flags = I40E_TXR_FLAGS_WB_ON_ITR; vsi->tx_rings[i] = tx_ring; rx_ring = &tx_ring[1]; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 330e4ef43cd8..7d0a5ea08656 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -853,15 +853,40 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) **/ static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) { - u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK | - I40E_PFINT_DYN_CTLN_ITR_INDX_MASK | /* set noitr */ - I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK | - I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK; - /* allow 00 to be written to the index */ - - wr32(&vsi->back->hw, - I40E_PFINT_DYN_CTLN(q_vector->v_idx + vsi->base_vector - 1), - val); + u16 flags = q_vector->tx.ring[0].flags; + + if (flags & I40E_TXR_FLAGS_WB_ON_ITR) { + u32 val; + + if (q_vector->arm_wb_state) + return; + + val = I40E_PFINT_DYN_CTLN_WB_ON_ITR_MASK; + + wr32(&vsi->back->hw, + I40E_PFINT_DYN_CTLN(q_vector->v_idx + + vsi->base_vector - 1), + val); + q_vector->arm_wb_state = true; + } else if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) { + u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_ITR_INDX_MASK | /* set noitr */ + I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK | + I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK; + /* allow 00 to be written to the index */ + + wr32(&vsi->back->hw, + I40E_PFINT_DYN_CTLN(q_vector->v_idx + + vsi->base_vector - 1), val); + } else { + u32 val = I40E_PFINT_DYN_CTL0_INTENA_MASK | + I40E_PFINT_DYN_CTL0_ITR_INDX_MASK | /* set noitr */ + I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK | + I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK; + /* allow 00 to be written to the index */ + + wr32(&vsi->back->hw, I40E_PFINT_DYN_CTL0, val); + } } /** @@ -1918,6 +1943,9 @@ int i40e_napi_poll(struct napi_struct *napi, int budget) return budget; } + if (vsi->back->flags & I40E_TXR_FLAGS_WB_ON_ITR) + q_vector->arm_wb_state = false; + /* Work is done so exit the polling mode and re-enable the interrupt */ napi_complete(napi); if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 8b618d0151cd..0e40994500c1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -265,6 +265,8 @@ struct i40e_ring { bool ring_active; /* is ring online or not */ bool arm_wb; /* do something to arm write back */ + u16 flags; +#define I40E_TXR_FLAGS_WB_ON_ITR BIT(0) /* stats structs */ struct i40e_queue_stats stats; struct u64_stats_sync syncp; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 60f88e4ad065..6dbcbca77279 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -366,15 +366,32 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget) **/ static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) { - u32 val = I40E_VFINT_DYN_CTLN_INTENA_MASK | - I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */ - I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK | - I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK; - /* allow 00 to be written to the index */ - - wr32(&vsi->back->hw, - I40E_VFINT_DYN_CTLN1(q_vector->v_idx + vsi->base_vector - 1), - val); + u16 flags = q_vector->tx.ring[0].flags; + + if (flags & I40E_TXR_FLAGS_WB_ON_ITR) { + u32 val; + + if (q_vector->arm_wb_state) + return; + + val = I40E_VFINT_DYN_CTLN1_WB_ON_ITR_MASK; + + wr32(&vsi->back->hw, + I40E_VFINT_DYN_CTLN1(q_vector->v_idx + + vsi->base_vector - 1), + val); + q_vector->arm_wb_state = true; + } else { + u32 val = I40E_VFINT_DYN_CTLN1_INTENA_MASK | + I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | /* set noitr */ + I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK | + I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK; + /* allow 00 to be written to the index */ + + wr32(&vsi->back->hw, + I40E_VFINT_DYN_CTLN1(q_vector->v_idx + + vsi->base_vector - 1), val); + } } /** @@ -1372,6 +1389,9 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget) return budget; } + if (vsi->back->flags & I40E_TXR_FLAGS_WB_ON_ITR) + q_vector->arm_wb_state = false; + /* Work is done so exit the polling mode and re-enable the interrupt */ napi_complete(napi); i40e_update_enable_itr(vsi, q_vector); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h index b2f9b8203c67..17bb59d3016c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h @@ -262,6 +262,8 @@ struct i40e_ring { bool ring_active; /* is ring online or not */ bool arm_wb; /* do something to arm write back */ + u16 flags; +#define I40E_TXR_FLAGS_WB_ON_ITR BIT(0) /* stats structs */ struct i40e_queue_stats stats; struct u64_stats_sync syncp; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index fa421d6020be..3817cbbf45e6 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -117,6 +117,7 @@ struct i40e_q_vector { u8 num_ringpairs; /* total number of ring pairs in vector */ int v_idx; /* vector index in list */ char name[IFNAMSIZ + 9]; + bool arm_wb_state; cpumask_var_t affinity_mask; }; -- cgit v1.3-6-gb490 From 527274c78ea7e0cad8b44ea25509c42aa605634e Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 5 Jun 2015 12:20:31 -0400 Subject: i40e/i40evf: Add TX/RX outer UDP checksum support for X722 X722 supports offloading of outer UDP TX and RX checksum for tunneled packets. This patch exposes the support and leaves it enabled by default. Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 ++ drivers/net/ethernet/intel/i40e/i40e_txrx.c | 16 +++++++++++++++- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 2 ++ drivers/net/ethernet/intel/i40e/i40e_type.h | 10 ++++++++-- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 13 +++++++++++++ drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 2 ++ drivers/net/ethernet/intel/i40evf/i40e_type.h | 10 ++++++++-- 7 files changed, 50 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 28f547ce4eb5..d9cb87f383dd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7073,6 +7073,8 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi) tx_ring->dcb_tc = 0; if (vsi->back->flags & I40E_FLAG_WB_ON_ITR_CAPABLE) tx_ring->flags = I40E_TXR_FLAGS_WB_ON_ITR; + if (vsi->back->flags & I40E_FLAG_OUTER_UDP_CSUM_CAPABLE) + tx_ring->flags |= I40E_TXR_FLAGS_OUTER_UDP_CSUM; vsi->tx_rings[i] = tx_ring; rx_ring = &tx_ring[1]; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 7d0a5ea08656..57dc5d23a808 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1429,7 +1429,8 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, * so the total length of IPv4 header is IHL*4 bytes * The UDP_0 bit *may* bet set if the *inner* header is UDP */ - if (ipv4_tunnel) { + if (!(vsi->back->flags & I40E_FLAG_OUTER_UDP_CSUM_CAPABLE) && + (ipv4_tunnel)) { skb->transport_header = skb->mac_header + sizeof(struct ethhdr) + (ip_hdr(skb)->ihl * 4); @@ -2301,11 +2302,15 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, struct iphdr *this_ip_hdr; u32 network_hdr_len; u8 l4_hdr = 0; + struct udphdr *oudph; + struct iphdr *oiph; u32 l4_tunnel = 0; if (skb->encapsulation) { switch (ip_hdr(skb)->protocol) { case IPPROTO_UDP: + oudph = udp_hdr(skb); + oiph = ip_hdr(skb); l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING; *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL; break; @@ -2342,6 +2347,15 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, *tx_flags &= ~I40E_TX_FLAGS_IPV4; *tx_flags |= I40E_TX_FLAGS_IPV6; } + if ((tx_ring->flags & I40E_TXR_FLAGS_OUTER_UDP_CSUM) && + (l4_tunnel == I40E_TXD_CTX_UDP_TUNNELING) && + (*cd_tunneling & I40E_TXD_CTX_QW0_EXT_IP_MASK)) { + oudph->check = ~csum_tcpudp_magic(oiph->saddr, + oiph->daddr, + (skb->len - skb_transport_offset(skb)), + IPPROTO_UDP, 0); + *cd_tunneling |= I40E_TXD_CTX_QW0_L4T_CS_MASK; + } } else { network_hdr_len = skb_network_header_len(skb); this_ip_hdr = ip_hdr(skb); diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 0e40994500c1..f1385a1989fa 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -267,6 +267,8 @@ struct i40e_ring { u16 flags; #define I40E_TXR_FLAGS_WB_ON_ITR BIT(0) +#define I40E_TXR_FLAGS_OUTER_UDP_CSUM BIT(1) + /* stats structs */ struct i40e_queue_stats stats; struct u64_stats_sync syncp; diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 1ffd27143a3c..b93357dddb28 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -607,14 +607,18 @@ enum i40e_rx_desc_status_bits { I40E_RX_DESC_STATUS_CRCP_SHIFT = 4, I40E_RX_DESC_STATUS_TSYNINDX_SHIFT = 5, /* 2 BITS */ I40E_RX_DESC_STATUS_TSYNVALID_SHIFT = 7, - I40E_RX_DESC_STATUS_PIF_SHIFT = 8, + /* Note: Bit 8 is reserved in X710 and XL710 */ + I40E_RX_DESC_STATUS_EXT_UDP_0_SHIFT = 8, I40E_RX_DESC_STATUS_UMBCAST_SHIFT = 9, /* 2 BITS */ I40E_RX_DESC_STATUS_FLM_SHIFT = 11, I40E_RX_DESC_STATUS_FLTSTAT_SHIFT = 12, /* 2 BITS */ I40E_RX_DESC_STATUS_LPBK_SHIFT = 14, I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT = 15, I40E_RX_DESC_STATUS_RESERVED_SHIFT = 16, /* 2 BITS */ - I40E_RX_DESC_STATUS_UDP_0_SHIFT = 18, + /* Note: For non-tunnel packets INT_UDP_0 is the right status for + * UDP header + */ + I40E_RX_DESC_STATUS_INT_UDP_0_SHIFT = 18, I40E_RX_DESC_STATUS_LAST /* this entry must be last!!! */ }; @@ -955,6 +959,8 @@ enum i40e_tx_ctx_desc_eipt_offload { #define I40E_TXD_CTX_QW0_DECTTL_MASK (0xFULL << \ I40E_TXD_CTX_QW0_DECTTL_SHIFT) +#define I40E_TXD_CTX_QW0_L4T_CS_SHIFT 23 +#define I40E_TXD_CTX_QW0_L4T_CS_MASK BIT_ULL(I40E_TXD_CTX_QW0_L4T_CS_SHIFT) struct i40e_filter_program_desc { __le32 qindex_flex_ptype_vsi; __le32 rsvd; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 6dbcbca77279..7309479a0764 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1528,11 +1528,15 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, struct iphdr *this_ip_hdr; u32 network_hdr_len; u8 l4_hdr = 0; + struct udphdr *oudph; + struct iphdr *oiph; u32 l4_tunnel = 0; if (skb->encapsulation) { switch (ip_hdr(skb)->protocol) { case IPPROTO_UDP: + oudph = udp_hdr(skb); + oiph = ip_hdr(skb); l4_tunnel = I40E_TXD_CTX_UDP_TUNNELING; *tx_flags |= I40E_TX_FLAGS_VXLAN_TUNNEL; break; @@ -1571,6 +1575,15 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, } + if ((tx_ring->flags & I40E_TXR_FLAGS_OUTER_UDP_CSUM) && + (l4_tunnel == I40E_TXD_CTX_UDP_TUNNELING) && + (*cd_tunneling & I40E_TXD_CTX_QW0_EXT_IP_MASK)) { + oudph->check = ~csum_tcpudp_magic(oiph->saddr, + oiph->daddr, + (skb->len - skb_transport_offset(skb)), + IPPROTO_UDP, 0); + *cd_tunneling |= I40E_TXD_CTX_QW0_L4T_CS_MASK; + } } else { network_hdr_len = skb_network_header_len(skb); this_ip_hdr = ip_hdr(skb); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h index 17bb59d3016c..9a30f5d8c089 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h @@ -264,6 +264,8 @@ struct i40e_ring { u16 flags; #define I40E_TXR_FLAGS_WB_ON_ITR BIT(0) +#define I40E_TXR_FLAGS_OUTER_UDP_CSUM BIT(1) + /* stats structs */ struct i40e_queue_stats stats; struct u64_stats_sync syncp; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 627bf7689bbc..e32dc0b3616d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -601,14 +601,18 @@ enum i40e_rx_desc_status_bits { I40E_RX_DESC_STATUS_CRCP_SHIFT = 4, I40E_RX_DESC_STATUS_TSYNINDX_SHIFT = 5, /* 2 BITS */ I40E_RX_DESC_STATUS_TSYNVALID_SHIFT = 7, - I40E_RX_DESC_STATUS_PIF_SHIFT = 8, + /* Note: Bit 8 is reserved in X710 and XL710 */ + I40E_RX_DESC_STATUS_EXT_UDP_0_SHIFT = 8, I40E_RX_DESC_STATUS_UMBCAST_SHIFT = 9, /* 2 BITS */ I40E_RX_DESC_STATUS_FLM_SHIFT = 11, I40E_RX_DESC_STATUS_FLTSTAT_SHIFT = 12, /* 2 BITS */ I40E_RX_DESC_STATUS_LPBK_SHIFT = 14, I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT = 15, I40E_RX_DESC_STATUS_RESERVED_SHIFT = 16, /* 2 BITS */ - I40E_RX_DESC_STATUS_UDP_0_SHIFT = 18, + /* Note: For non-tunnel packets INT_UDP_0 is the right status for + * UDP header + */ + I40E_RX_DESC_STATUS_INT_UDP_0_SHIFT = 18, I40E_RX_DESC_STATUS_LAST /* this entry must be last!!! */ }; @@ -949,6 +953,8 @@ enum i40e_tx_ctx_desc_eipt_offload { #define I40E_TXD_CTX_QW0_DECTTL_MASK (0xFULL << \ I40E_TXD_CTX_QW0_DECTTL_SHIFT) +#define I40E_TXD_CTX_QW0_L4T_CS_SHIFT 23 +#define I40E_TXD_CTX_QW0_L4T_CS_MASK BIT_ULL(I40E_TXD_CTX_QW0_L4T_CS_SHIFT) struct i40e_filter_program_desc { __le32 qindex_flex_ptype_vsi; __le32 rsvd; -- cgit v1.3-6-gb490 From 0d8e14392f7697e5ee241d49fce3355f22406d3e Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 5 Jun 2015 12:20:32 -0400 Subject: i40e: Add IWARP support for X722 X722 supports IWARP, this patch handles checking for PE critical errors. Since the driver doesn't support the IWARP interface for now, this patch just does bare minimum to log a message oif a PE critical error happens. Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d9cb87f383dd..3bb832a2ec51 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2908,6 +2908,9 @@ static void i40e_enable_misc_int_causes(struct i40e_pf *pf) I40E_PFINT_ICR0_ENA_VFLR_MASK | I40E_PFINT_ICR0_ENA_ADMINQ_MASK; + if (pf->flags & I40E_FLAG_IWARP_ENABLED) + val |= I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK; + if (pf->flags & I40E_FLAG_PTP) val |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; @@ -3198,6 +3201,13 @@ static irqreturn_t i40e_intr(int irq, void *data) (icr0 & I40E_PFINT_ICR0_SWINT_MASK)) pf->sw_int_count++; + if ((pf->flags & I40E_FLAG_IWARP_ENABLED) && + (ena_mask & I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK)) { + ena_mask &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK; + icr0 &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK; + dev_info(&pf->pdev->dev, "cleared PE_CRITERR\n"); + } + /* only q0 is used in MSI/Legacy mode, and none are used in MSIX */ if (icr0 & I40E_PFINT_ICR0_QUEUE_0_MASK) { -- cgit v1.3-6-gb490 From 52eb95ef3286f10c4584c3dcb25d4be7d8e1faeb Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 5 Jun 2015 12:20:33 -0400 Subject: i40e/i40evf: Add ATR HW eviction support for X722 X722 supports evicting ATR filters in the HW. With this patch, we enable the feature in the driver and avoid filter deletion by the driver. Signed-off-by: Anjali Singhai Jain Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 10 ++++++++++ drivers/net/ethernet/intel/i40e/i40e_type.h | 4 ++++ 2 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 57dc5d23a808..738aca68f665 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2040,6 +2040,13 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, /* 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; + if (pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) { + /* HW ATR eviction will take care of removing filters on FIN + * and RST packets. + */ + if (th->fin || th->rst) + return; + } tx_ring->atr_count++; @@ -2095,6 +2102,9 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb, I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) & I40E_TXD_FLTR_QW1_CNTINDEX_MASK; + if (pf->flags & I40E_FLAG_HW_ATR_EVICT_CAPABLE) + dtype_cmd |= I40E_TXD_FLTR_QW1_ATR_MASK; + fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype); fdir_desc->rsvd = cpu_to_le32(0); fdir_desc->dtype_cmd_cntindex = cpu_to_le32(dtype_cmd); diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index b93357dddb28..61b6b114b4bc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -1049,6 +1049,10 @@ enum i40e_filter_program_desc_pcmd { #define I40E_TXD_FLTR_QW1_FD_STATUS_MASK (0x3ULL << \ I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT) +#define I40E_TXD_FLTR_QW1_ATR_SHIFT (0xEULL + \ + I40E_TXD_FLTR_QW1_CMD_SHIFT) +#define I40E_TXD_FLTR_QW1_ATR_MASK BIT_ULL(I40E_TXD_FLTR_QW1_ATR_SHIFT) + #define I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT 20 #define I40E_TXD_FLTR_QW1_CNTINDEX_MASK (0x1FFUL << \ I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) -- cgit v1.3-6-gb490 From 7073f46e443ecb5a48221160aa39773ccb520b0f Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Fri, 5 Jun 2015 12:20:34 -0400 Subject: i40e: Add AQ commands for NVM Update for X722 X722 does NVM update via the adminq queue, so we need to add support for that. Signed-off-by: Shannon Nelson Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_nvm.c | 129 +++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index ce986af213d2..9b83abc0e774 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -211,6 +211,74 @@ read_nvm_exit: return ret_code; } +/** + * i40e_read_nvm_aq - Read Shadow RAM. + * @hw: pointer to the HW structure. + * @module_pointer: module pointer location in words from the NVM beginning + * @offset: offset in words from module start + * @words: number of words to write + * @data: buffer with words to write to the Shadow RAM + * @last_command: tells the AdminQ that this is the last command + * + * Writes a 16 bit words buffer to the Shadow RAM using the admin command. + **/ +static i40e_status i40e_read_nvm_aq(struct i40e_hw *hw, u8 module_pointer, + u32 offset, u16 words, void *data, + bool last_command) +{ + i40e_status ret_code = I40E_ERR_NVM; + struct i40e_asq_cmd_details cmd_details; + + memset(&cmd_details, 0, sizeof(cmd_details)); + + /* Here we are checking the SR limit only for the flat memory model. + * We cannot do it for the module-based model, as we did not acquire + * the NVM resource yet (we cannot get the module pointer value). + * Firmware will check the module-based model. + */ + if ((offset + words) > hw->nvm.sr_size) + i40e_debug(hw, I40E_DEBUG_NVM, + "NVM write error: offset %d beyond Shadow RAM limit %d\n", + (offset + words), hw->nvm.sr_size); + else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS) + /* We can write only up to 4KB (one sector), in one AQ write */ + i40e_debug(hw, I40E_DEBUG_NVM, + "NVM write fail error: tried to write %d words, limit is %d.\n", + words, I40E_SR_SECTOR_SIZE_IN_WORDS); + else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS) + != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS)) + /* A single write cannot spread over two sectors */ + i40e_debug(hw, I40E_DEBUG_NVM, + "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n", + offset, words); + else + ret_code = i40e_aq_read_nvm(hw, module_pointer, + 2 * offset, /*bytes*/ + 2 * words, /*bytes*/ + data, last_command, &cmd_details); + + return ret_code; +} + +/** + * i40e_read_nvm_word_aq - Reads Shadow RAM via AQ + * @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 one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. + **/ +static i40e_status i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset, + u16 *data) +{ + i40e_status ret_code = I40E_ERR_TIMEOUT; + + ret_code = i40e_read_nvm_aq(hw, 0x0, offset, 1, data, true); + *data = le16_to_cpu(*(__le16 *)data); + + return ret_code; +} + /** * i40e_read_nvm_word - Reads Shadow RAM * @hw: pointer to the HW structure @@ -222,6 +290,8 @@ read_nvm_exit: i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, u16 *data) { + if (hw->mac.type == I40E_MAC_X722) + return i40e_read_nvm_word_aq(hw, offset, data); return i40e_read_nvm_word_srctl(hw, offset, data); } @@ -256,6 +326,63 @@ static i40e_status i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset, return ret_code; } +/** + * i40e_read_nvm_buffer_aq - Reads Shadow RAM buffer via AQ + * @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_aq() + * method. The buffer read is preceded by the NVM ownership take + * and followed by the release. + **/ +static i40e_status i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset, + u16 *words, u16 *data) +{ + i40e_status ret_code; + u16 read_size = *words; + bool last_cmd = false; + u16 words_read = 0; + u16 i = 0; + + do { + /* Calculate number of bytes we should read in this step. + * FVL AQ do not allow to read more than one page at a time or + * to cross page boundaries. + */ + if (offset % I40E_SR_SECTOR_SIZE_IN_WORDS) + read_size = min(*words, + (u16)(I40E_SR_SECTOR_SIZE_IN_WORDS - + (offset % I40E_SR_SECTOR_SIZE_IN_WORDS))); + else + read_size = min((*words - words_read), + I40E_SR_SECTOR_SIZE_IN_WORDS); + + /* Check if this is last command, if so set proper flag */ + if ((words_read + read_size) >= *words) + last_cmd = true; + + ret_code = i40e_read_nvm_aq(hw, 0x0, offset, read_size, + data + words_read, last_cmd); + if (ret_code) + goto read_nvm_buffer_aq_exit; + + /* Increment counter for words already read and move offset to + * new read location + */ + words_read += read_size; + offset += read_size; + } while (words_read < *words); + + for (i = 0; i < *words; i++) + data[i] = le16_to_cpu(((__le16 *)data)[i]); + +read_nvm_buffer_aq_exit: + *words = words_read; + return ret_code; +} + /** * i40e_read_nvm_buffer - Reads Shadow RAM buffer * @hw: pointer to the HW structure @@ -270,6 +397,8 @@ static i40e_status i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset, i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, u16 *words, u16 *data) { + if (hw->mac.type == I40E_MAC_X722) + return i40e_read_nvm_buffer_aq(hw, offset, words, data); return i40e_read_nvm_buffer_srctl(hw, offset, words, data); } -- cgit v1.3-6-gb490 From f5ac7445ebdbfa8cd2d90ef2a58b8f4455bcb664 Mon Sep 17 00:00:00 2001 From: Raanan Avargil Date: Mon, 6 Jul 2015 16:48:00 +0300 Subject: e1000e: Fix EEE in Sx implementation This patch implements the EEE in Sx code so that it only applies to parts that support EEE in Sx (as opposed to all parts that support EEE). It also uses the existing eee_advert and eee_lp_abiliity to set just the bits (100/1000) that should be set. Signed-off-by: Raanan Avargil Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index fea1601f32a3..b32bc4848ae3 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6317,6 +6317,33 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) return retval; } + /* Ensure that the appropriate bits are set in LPI_CTRL + * for EEE in Sx + */ + if ((hw->phy.type >= e1000_phy_i217) && + adapter->eee_advert && hw->dev_spec.ich8lan.eee_lp_ability) { + u16 lpi_ctrl = 0; + + retval = hw->phy.ops.acquire(hw); + if (!retval) { + retval = e1e_rphy_locked(hw, I82579_LPI_CTRL, + &lpi_ctrl); + if (!retval) { + if (adapter->eee_advert & + hw->dev_spec.ich8lan.eee_lp_ability & + I82579_EEE_100_SUPPORTED) + lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE; + if (adapter->eee_advert & + hw->dev_spec.ich8lan.eee_lp_ability & + I82579_EEE_1000_SUPPORTED) + lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE; + + retval = e1e_wphy_locked(hw, I82579_LPI_CTRL, + lpi_ctrl); + } + } + hw->phy.ops.release(hw); + } /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. -- cgit v1.3-6-gb490 From d582891594104adeea89307ddd31b31bcf2d95fa Mon Sep 17 00:00:00 2001 From: Raanan Avargil Date: Mon, 6 Jul 2015 16:58:54 +0300 Subject: e1000e: Cosmetic changes 1) Replace spaces with tab. 2) Move ich8lan related define to the proper context. Signed-off-by: Raanan Avargil Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ich8lan.h | 4 ++-- drivers/net/ethernet/intel/e1000e/regs.h | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h index 26459853c6be..34c551e322eb 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h @@ -106,14 +106,14 @@ #define E1000_FEXTNVM11_DISABLE_MULR_FIX 0x00002000 /* bit24: RXDCTL thresholds granularity: 0 - cache lines, 1 - descriptors */ -#define E1000_RXDCTL_THRESH_UNIT_DESC 0x01000000 +#define E1000_RXDCTL_THRESH_UNIT_DESC 0x01000000 #define K1_ENTRY_LATENCY 0 #define K1_MIN_TIME 1 #define NVM_SIZE_MULTIPLIER 4096 /*multiplier for NVMS field */ #define E1000_FLASH_BASE_ADDR 0xE000 /*offset of NVM access regs */ #define E1000_CTRL_EXT_NVMVS 0x3 /*NVM valid sector */ - +#define E1000_TARC0_CB_MULTIQ_3_REQ (1 << 28 | 1 << 29) #define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL #define E1000_ICH_RAR_ENTRIES 7 diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h index b24e5fee17f2..1d5e0b77062a 100644 --- a/drivers/net/ethernet/intel/e1000e/regs.h +++ b/drivers/net/ethernet/intel/e1000e/regs.h @@ -38,8 +38,8 @@ #define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */ #define E1000_FEXTNVM6 0x00010 /* Future Extended NVM 6 - RW */ #define E1000_FEXTNVM7 0x000E4 /* Future Extended NVM 7 - RW */ -#define E1000_FEXTNVM9 0x5BB4 /* Future Extended NVM 9 - RW */ -#define E1000_FEXTNVM11 0x5BBC /* Future Extended NVM 11 - RW */ +#define E1000_FEXTNVM9 0x5BB4 /* Future Extended NVM 9 - RW */ +#define E1000_FEXTNVM11 0x5BBC /* Future Extended NVM 11 - RW */ #define E1000_PCIEANACFG 0x00F18 /* PCIE Analog Config */ #define E1000_FCT 0x00030 /* Flow Control Type - RW */ #define E1000_VET 0x00038 /* VLAN Ether Type - RW */ @@ -125,7 +125,6 @@ (0x054E4 + ((_i - 16) * 8))) #define E1000_SHRAL(_i) (0x05438 + ((_i) * 8)) #define E1000_SHRAH(_i) (0x0543C + ((_i) * 8)) -#define E1000_TARC0_CB_MULTIQ_3_REQ (1 << 28 | 1 << 29) #define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */ #define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */ #define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */ -- cgit v1.3-6-gb490 From 2758f9edb7bd5a06a2ecee83cc2ebaf8822a0cb5 Mon Sep 17 00:00:00 2001 From: Raanan Avargil Date: Mon, 6 Jul 2015 17:57:36 +0300 Subject: e1000e: Fix incorrect ASPM locking This patch fixes wrong locking usage. In the context of slot reset, we should use lock. And during resume, there is no need of lock. Reported-by: Bjorn Helgaas Signed-off-by: Raanan Avargil Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index b32bc4848ae3..24b7269ff929 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6493,7 +6493,7 @@ static int __e1000_resume(struct pci_dev *pdev) if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) aspm_disable_flag |= PCIE_LINK_STATE_L1; if (aspm_disable_flag) - e1000e_disable_aspm_locked(pdev, aspm_disable_flag); + e1000e_disable_aspm(pdev, aspm_disable_flag); pci_set_master(pdev); @@ -6771,7 +6771,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1) aspm_disable_flag |= PCIE_LINK_STATE_L1; if (aspm_disable_flag) - e1000e_disable_aspm(pdev, aspm_disable_flag); + e1000e_disable_aspm_locked(pdev, aspm_disable_flag); err = pci_enable_device_mem(pdev); if (err) { -- cgit v1.3-6-gb490 From 37b12910dd11d9ab969f2c310dc9160b7f3e3405 Mon Sep 17 00:00:00 2001 From: Raanan Avargil Date: Sun, 19 Jul 2015 16:33:20 +0300 Subject: e1000e: Fix tight loop implementation of systime read algorithm Change the algorithm. Read systimel twice and check for overflow. If there was no overflow, use the first value. If there was an overflow, read systimeh again and use the second systimel value. Signed-off-by: Raanan Avargil Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 31 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 24b7269ff929..96a816683698 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -4280,18 +4280,29 @@ static cycle_t e1000e_cyclecounter_read(const struct cyclecounter *cc) struct e1000_adapter *adapter = container_of(cc, struct e1000_adapter, cc); struct e1000_hw *hw = &adapter->hw; + u32 systimel_1, systimel_2, systimeh; cycle_t systim, systim_next; - /* SYSTIMH latching upon SYSTIML read does not work well. To fix that - * we don't want to allow overflow of SYSTIML and a change to SYSTIMH - * to occur between reads, so if we read a vale close to overflow, we - * wait for overflow to occur and read both registers when its safe. + /* SYSTIMH latching upon SYSTIML read does not work well. + * This means that if SYSTIML overflows after we read it but before + * we read SYSTIMH, the value of SYSTIMH has been incremented and we + * will experience a huge non linear increment in the systime value + * to fix that we test for overflow and if true, we re-read systime. */ - u32 systim_overflow_latch_fix = 0x3FFFFFFF; - - do { - systim = (cycle_t)er32(SYSTIML); - } while (systim > systim_overflow_latch_fix); - systim |= (cycle_t)er32(SYSTIMH) << 32; + systimel_1 = er32(SYSTIML); + systimeh = er32(SYSTIMH); + systimel_2 = er32(SYSTIML); + /* Check for overflow. If there was no overflow, use the values */ + if (systimel_1 < systimel_2) { + systim = (cycle_t)systimel_1; + systim |= (cycle_t)systimeh << 32; + } else { + /* There was an overflow, read again SYSTIMH, and use + * systimel_2 + */ + systimeh = er32(SYSTIMH); + systim = (cycle_t)systimel_2; + systim |= (cycle_t)systimeh << 32; + } if ((hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82583)) { u64 incvalue, time_delta, rem, temp; -- cgit v1.3-6-gb490 From d2d7d4e4a60f1aeefb38d7a0bede3742ddb76a68 Mon Sep 17 00:00:00 2001 From: Raanan Avargil Date: Sun, 19 Jul 2015 16:33:21 +0300 Subject: e1000e: Increase driver version number Signed-off-by: Raanan Avargil Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 96a816683698..546b5da168dc 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -48,7 +48,7 @@ #define DRV_EXTRAVERSION "-k" -#define DRV_VERSION "3.2.5" DRV_EXTRAVERSION +#define DRV_VERSION "3.2.6" DRV_EXTRAVERSION char e1000e_driver_name[] = "e1000e"; const char e1000e_driver_version[] = DRV_VERSION; -- cgit v1.3-6-gb490 From 82b2c3c5b838b4fac9471eab320670aff5a822e0 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Mon, 29 Jun 2015 16:59:02 +0200 Subject: driver core: fix docbook for device_private.device This field refers to the public device struct, not to classes. Signed-off-by: Tomeu Vizoso Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/base.h b/drivers/base/base.h index fd3347d9f153..29c985eb9f4c 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -63,7 +63,7 @@ struct driver_private { * binding of drivers which were unable to get all the resources needed by * the device; typically because it depends on another driver getting * probed first. - * @device - pointer back to the struct class that this structure is + * @device - pointer back to the struct device that this structure is * associated with. * * Nothing outside of the driver core should ever touch these fields. -- cgit v1.3-6-gb490 From 52cdbdd49853dfa856082edb0f4c4c0249d9df07 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 27 Jul 2015 20:43:01 +0300 Subject: driver core: correct device's shutdown order Now device's shutdown sequence is performed in reverse order of their registration in devices_kset list and this sequence corresponds to the reverse device's creation order. So, devices_kset data tracks "parent<-child" device's dependencies only. Unfortunately, that's not enough and causes problems in case of implementing board's specific shutdown procedures. For example [1]: "DRA7XX_evm uses PCF8575 and one of the PCF output lines feeds to MMC/SD and this line should be driven high in order for the MMC/SD to be detected. This line is modelled as regulator and the hsmmc driver takes care of enabling and disabling it. In the case of 'reboot', during shutdown path as part of it's cleanup process the hsmmc driver disables this regulator. This makes MMC boot not functional." To handle this issue the .shutdown() callback could be implemented for PCF8575 device where corresponding GPIO pins will be configured to states, required for correct warm/cold reset. This can be achieved only when all .shutdown() callbacks have been called already for all PCF8575's consumers. But devices_kset is not filled correctly now: devices_kset: Device61 4e000000.dmm devices_kset: Device62 48070000.i2c devices_kset: Device63 48072000.i2c devices_kset: Device64 48060000.i2c devices_kset: Device65 4809c000.mmc ... devices_kset: Device102 fixedregulator-sd ... devices_kset: Device181 0-0020 // PCF8575 devices_kset: Device182 gpiochip496 devices_kset: Device183 0-0021 // PCF8575 devices_kset: Device184 gpiochip480 As can be seen from above .shutdown() callback for PCF8575 will be called before its consumers, which, in turn means, that any changes of PCF8575 GPIO's pins will be or unsafe or overwritten later by GPIO's consumers. The problem can be solved if devices_kset list will be filled not only according device creation order, but also according device's probing order to track "supplier<-consumer" dependencies also. Hence, as a fix, lets add devices_kset_move_last(), devices_kset_move_before(), devices_kset_move_after() and call them from device_move() and also add call of devices_kset_move_last() in really_probe(). After this change all entries in devices_kset will be sorted according to device's creation ("parent<-child") and probing ("supplier<-consumer") order. devices_kset after: devices_kset: Device121 48070000.i2c devices_kset: Device122 i2c-0 ... devices_kset: Device147 regulator.24 devices_kset: Device148 0-0020 devices_kset: Device149 gpiochip496 devices_kset: Device150 0-0021 devices_kset: Device151 gpiochip480 devices_kset: Device152 0-0019 ... devices_kset: Device372 fixedregulator-sd devices_kset: Device373 regulator.29 devices_kset: Device374 4809c000.mmc devices_kset: Device375 mmc0 [1] http://www.spinics.net/lists/linux-mmc/msg29825.html Cc: Sekhar Nori Signed-off-by: Grygorii Strashko Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 1 + drivers/base/core.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/base/dd.c | 8 ++++++++ 3 files changed, 58 insertions(+) (limited to 'drivers') diff --git a/drivers/base/base.h b/drivers/base/base.h index 29c985eb9f4c..1782f3aa386e 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -134,6 +134,7 @@ extern int devres_release_all(struct device *dev); /* /sys/devices directory */ extern struct kset *devices_kset; +extern void devices_kset_move_last(struct device *dev); #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) extern void module_add_driver(struct module *mod, struct device_driver *drv); diff --git a/drivers/base/core.c b/drivers/base/core.c index dafae6d2f7ac..fc5a558f62f9 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -533,6 +533,52 @@ static DEVICE_ATTR_RO(dev); /* /sys/devices/ */ struct kset *devices_kset; +/** + * devices_kset_move_before - Move device in the devices_kset's list. + * @deva: Device to move. + * @devb: Device @deva should come before. + */ +static void devices_kset_move_before(struct device *deva, struct device *devb) +{ + if (!devices_kset) + return; + pr_debug("devices_kset: Moving %s before %s\n", + dev_name(deva), dev_name(devb)); + spin_lock(&devices_kset->list_lock); + list_move_tail(&deva->kobj.entry, &devb->kobj.entry); + spin_unlock(&devices_kset->list_lock); +} + +/** + * devices_kset_move_after - Move device in the devices_kset's list. + * @deva: Device to move + * @devb: Device @deva should come after. + */ +static void devices_kset_move_after(struct device *deva, struct device *devb) +{ + if (!devices_kset) + return; + pr_debug("devices_kset: Moving %s after %s\n", + dev_name(deva), dev_name(devb)); + spin_lock(&devices_kset->list_lock); + list_move(&deva->kobj.entry, &devb->kobj.entry); + spin_unlock(&devices_kset->list_lock); +} + +/** + * devices_kset_move_last - move the device to the end of devices_kset's list. + * @dev: device to move + */ +void devices_kset_move_last(struct device *dev) +{ + if (!devices_kset) + return; + pr_debug("devices_kset: Moving %s to end of list\n", dev_name(dev)); + spin_lock(&devices_kset->list_lock); + list_move_tail(&dev->kobj.entry, &devices_kset->list); + spin_unlock(&devices_kset->list_lock); +} + /** * device_create_file - create sysfs attribute file for device. * @dev: device. @@ -1923,12 +1969,15 @@ int device_move(struct device *dev, struct device *new_parent, break; case DPM_ORDER_DEV_AFTER_PARENT: device_pm_move_after(dev, new_parent); + devices_kset_move_after(dev, new_parent); break; case DPM_ORDER_PARENT_BEFORE_DEV: device_pm_move_before(new_parent, dev); + devices_kset_move_before(new_parent, dev); break; case DPM_ORDER_DEV_LAST: device_pm_move_last(dev); + devices_kset_move_last(dev); break; } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a638bbb1a27a..cc2b1d4801fd 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -304,6 +304,14 @@ static int really_probe(struct device *dev, struct device_driver *drv) goto probe_failed; } + /* + * Ensure devices are listed in devices_kset in correct order + * It's important to move Dev to the end of devices_kset before + * calling .probe, because it could be recursive and parent Dev + * should always go first + */ + devices_kset_move_last(dev); + if (dev->bus->probe) { ret = dev->bus->probe(dev); if (ret) -- cgit v1.3-6-gb490 From 71db87ba570038497db1227b7dc61113c4156565 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 30 Jul 2015 15:04:01 +0530 Subject: bus: subsys: update return type of ->remove_dev() to void Its return value is not used by the subsys core and nothing meaningful can be done with it, even if we want to use it. The subsys device is anyway getting removed. Update prototype of ->remove_dev() to make its return type as void. Fix all usage sites as well. Signed-off-by: Viresh Kumar Signed-off-by: Greg Kroah-Hartman --- arch/sh/kernel/cpu/sh4/sq.c | 3 +-- arch/tile/kernel/sysfs.c | 11 ++++------- arch/x86/kernel/cpu/microcode/core.c | 5 ++--- drivers/cpufreq/cpufreq.c | 12 +++++------- drivers/net/rionet.c | 4 +--- include/linux/device.h | 2 +- 6 files changed, 14 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c index 0a47bd3e7bee..4ca78ed71ad2 100644 --- a/arch/sh/kernel/cpu/sh4/sq.c +++ b/arch/sh/kernel/cpu/sh4/sq.c @@ -355,13 +355,12 @@ static int sq_dev_add(struct device *dev, struct subsys_interface *sif) return error; } -static int sq_dev_remove(struct device *dev, struct subsys_interface *sif) +static void sq_dev_remove(struct device *dev, struct subsys_interface *sif) { unsigned int cpu = dev->id; struct kobject *kobj = sq_kobject[cpu]; kobject_put(kobj); - return 0; } static struct subsys_interface sq_interface = { diff --git a/arch/tile/kernel/sysfs.c b/arch/tile/kernel/sysfs.c index a3ed12f8f83b..825867c53853 100644 --- a/arch/tile/kernel/sysfs.c +++ b/arch/tile/kernel/sysfs.c @@ -198,16 +198,13 @@ static int hv_stats_device_add(struct device *dev, struct subsys_interface *sif) return err; } -static int hv_stats_device_remove(struct device *dev, - struct subsys_interface *sif) +static void hv_stats_device_remove(struct device *dev, + struct subsys_interface *sif) { int cpu = dev->id; - if (!cpu_online(cpu)) - return 0; - - sysfs_remove_file(&dev->kobj, &dev_attr_hv_stats.attr); - return 0; + if (cpu_online(cpu)) + sysfs_remove_file(&dev->kobj, &dev_attr_hv_stats.attr); } diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 6236a54a63f4..3c986390058a 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -377,17 +377,16 @@ static int mc_device_add(struct device *dev, struct subsys_interface *sif) return err; } -static int mc_device_remove(struct device *dev, struct subsys_interface *sif) +static void mc_device_remove(struct device *dev, struct subsys_interface *sif) { int cpu = dev->id; if (!cpu_online(cpu)) - return 0; + return; pr_debug("CPU%d removed\n", cpu); microcode_fini_cpu(cpu); sysfs_remove_group(&dev->kobj, &mc_attr_group); - return 0; } static struct subsys_interface mc_cpu_interface = { diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 26063afb3eba..6da25c10bdfd 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1518,7 +1518,7 @@ static int __cpufreq_remove_dev_finish(struct device *dev, * * Removes the cpufreq interface for a CPU device. */ -static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) +static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) { unsigned int cpu = dev->id; int ret; @@ -1533,7 +1533,7 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) struct cpumask mask; if (!policy) - return 0; + return; cpumask_copy(&mask, policy->related_cpus); cpumask_clear_cpu(cpu, &mask); @@ -1544,19 +1544,17 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) */ if (cpumask_intersects(&mask, cpu_present_mask)) { remove_cpu_dev_symlink(policy, cpu); - return 0; + return; } cpufreq_policy_free(policy, true); - return 0; + return; } ret = __cpufreq_remove_dev_prepare(dev, sif); if (!ret) - ret = __cpufreq_remove_dev_finish(dev, sif); - - return ret; + __cpufreq_remove_dev_finish(dev, sif); } static void handle_update(struct work_struct *work) diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index dac7a0d9bb46..01f08a7751f7 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -396,7 +396,7 @@ static int rionet_close(struct net_device *ndev) return 0; } -static int rionet_remove_dev(struct device *dev, struct subsys_interface *sif) +static void rionet_remove_dev(struct device *dev, struct subsys_interface *sif) { struct rio_dev *rdev = to_rio_dev(dev); unsigned char netid = rdev->net->hport->id; @@ -416,8 +416,6 @@ static int rionet_remove_dev(struct device *dev, struct subsys_interface *sif) } } } - - return 0; } static void rionet_get_drvinfo(struct net_device *ndev, diff --git a/include/linux/device.h b/include/linux/device.h index a2b4ea70a946..1225f98e9240 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -341,7 +341,7 @@ struct subsys_interface { struct bus_type *subsys; struct list_head node; int (*add_dev)(struct device *dev, struct subsys_interface *sif); - int (*remove_dev)(struct device *dev, struct subsys_interface *sif); + void (*remove_dev)(struct device *dev, struct subsys_interface *sif); }; int subsys_interface_register(struct subsys_interface *sif); -- cgit v1.3-6-gb490 From 4816693286d4ff9219b1cc72c2ab9c589448ebcb Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 30 Jul 2015 12:54:40 -0400 Subject: toshiba laptop: replace ioremap_cache with ioremap With ioremap_cache being replaced with memremap there is no longer a guarantee that a mapping will silently fall back to an uncached mapping. Explicitly use a vanilla ioremap() for this short lived mapping. Cc: Arnd Bergmann Cc: Jonathan Buzzard Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/char/toshiba.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index 014c9d90d297..f5a45d887a37 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -430,7 +430,7 @@ static int tosh_probe(void) int i,major,minor,day,year,month,flag; unsigned char signature[7] = { 0x54,0x4f,0x53,0x48,0x49,0x42,0x41 }; SMMRegisters regs; - void __iomem *bios = ioremap_cache(0xf0000, 0x10000); + void __iomem *bios = ioremap(0xf0000, 0x10000); if (!bios) return -ENOMEM; -- cgit v1.3-6-gb490 From 7fc80964e80bcf93cff0f7ba2aa8095d48f940d6 Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Wed, 5 Aug 2015 00:09:35 +0200 Subject: wilc1000: wilc_wfi_cfgoperations.c: Fixed initialization of global boolean. Globals are initialized to zero or NULL by GCC. No need to explicitly initialize them. Signed-off-by: Daniel Machon Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index da9c12f9b443..2c0789e499d4 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -112,7 +112,7 @@ u8 u8P2P_oui[] = {0x50, 0x6f, 0x9A, 0x09}; u8 u8P2Plocalrandom = 0x01; u8 u8P2Precvrandom = 0x00; u8 u8P2P_vendorspec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03}; -bool bWilc_ie = false; +bool bWilc_ie; #endif static struct ieee80211_supported_band WILC_WFI_band_2ghz = { @@ -135,9 +135,9 @@ struct add_key_params g_add_ptk_key_params; struct wilc_wfi_key g_key_ptk_params; struct wilc_wfi_wep_key g_key_wep_params; u8 g_flushing_in_progress; -bool g_ptk_keys_saved = false; -bool g_gtk_keys_saved = false; -bool g_wep_keys_saved = false; +bool g_ptk_keys_saved; +bool g_gtk_keys_saved; +bool g_wep_keys_saved; #define AGING_TIME (9 * 1000) #define duringIP_TIME 15000 -- cgit v1.3-6-gb490 From e91a398c31cef2d51786642e372c503cd43fba90 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 1 Aug 2015 02:39:43 +0200 Subject: ACPI / bus: Move duplicate code to a separate new function After merging commit 712e960f0ee9 (ACPI / PM: Attach ACPI power domain only once) with commit 1dcc3d3362b0 (ACPI / bus: Move ACPI bus type registration) there is some duplicate code in acpi_device_is_first_physical_node() and acpi_companion_match() that can be moved to a separate routine and called from both places. Signed-off-by: Rafael J. Wysocki Reviewed-by: Mika Westerberg Reviewed-by: Hanjun Guo --- drivers/acpi/bus.c | 51 ++++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a23903c8bea9..f39f686ed2df 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -486,6 +486,26 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device) Device Matching -------------------------------------------------------------------------- */ +static struct acpi_device *acpi_primary_dev_companion(struct acpi_device *adev, + const struct device *dev) +{ + struct mutex *physical_node_lock = &adev->physical_node_lock; + + mutex_lock(physical_node_lock); + if (list_empty(&adev->physical_node_list)) { + adev = NULL; + } else { + const struct acpi_device_physical_node *node; + + node = list_first_entry(&adev->physical_node_list, + struct acpi_device_physical_node, node); + if (node->dev != dev) + adev = NULL; + } + mutex_unlock(physical_node_lock); + return adev; +} + /** * acpi_device_is_first_physical_node - Is given dev first physical node * @adev: ACPI companion device @@ -500,19 +520,7 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device) bool acpi_device_is_first_physical_node(struct acpi_device *adev, const struct device *dev) { - bool ret = false; - - mutex_lock(&adev->physical_node_lock); - if (!list_empty(&adev->physical_node_list)) { - const struct acpi_device_physical_node *node; - - node = list_first_entry(&adev->physical_node_list, - struct acpi_device_physical_node, node); - ret = node->dev == dev; - } - mutex_unlock(&adev->physical_node_lock); - - return ret; + return !!acpi_primary_dev_companion(adev, dev); } /* @@ -539,7 +547,6 @@ bool acpi_device_is_first_physical_node(struct acpi_device *adev, struct acpi_device *acpi_companion_match(const struct device *dev) { struct acpi_device *adev; - struct mutex *physical_node_lock; adev = ACPI_COMPANION(dev); if (!adev) @@ -548,21 +555,7 @@ struct acpi_device *acpi_companion_match(const struct device *dev) if (list_empty(&adev->pnp.ids)) return NULL; - physical_node_lock = &adev->physical_node_lock; - mutex_lock(physical_node_lock); - if (list_empty(&adev->physical_node_list)) { - adev = NULL; - } else { - const struct acpi_device_physical_node *node; - - node = list_first_entry(&adev->physical_node_list, - struct acpi_device_physical_node, node); - if (node->dev != dev) - adev = NULL; - } - mutex_unlock(physical_node_lock); - - return adev; + return acpi_primary_dev_companion(adev, dev); } /** -- cgit v1.3-6-gb490 From 67a6eedc4d2cc609620d27e33f72b8f90e61e0a7 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 6 Jul 2015 12:19:24 +0200 Subject: dmaengine: xdmac: Add scatter gathered memset support The XDMAC also supports memset operations over discontiguous areas. Add the necessary logic to support this. Signed-off-by: Maxime Ripard Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index cf1213de7865..1a2d9a39ff25 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1133,7 +1133,7 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan, * SAMA5D4x), so we can use the same interface for source and dest, * that solves the fact we don't know the direction. */ - u32 chan_cc = AT_XDMAC_CC_DAM_INCREMENTED_AM + u32 chan_cc = AT_XDMAC_CC_DAM_UBS_AM | AT_XDMAC_CC_SAM_INCREMENTED_AM | AT_XDMAC_CC_DIF(0) | AT_XDMAC_CC_SIF(0) @@ -1201,6 +1201,168 @@ at_xdmac_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value, return &desc->tx_dma_desc; } +static struct dma_async_tx_descriptor * +at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, int value, + unsigned long flags) +{ + struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); + struct at_xdmac_desc *desc, *pdesc = NULL, + *ppdesc = NULL, *first = NULL; + struct scatterlist *sg, *psg = NULL, *ppsg = NULL; + size_t stride = 0, pstride = 0, len = 0; + int i; + + if (!sgl) + return NULL; + + dev_dbg(chan2dev(chan), "%s: sg_len=%d, value=0x%x, flags=0x%lx\n", + __func__, sg_len, value, flags); + + /* Prepare descriptors. */ + for_each_sg(sgl, sg, sg_len, i) { + dev_dbg(chan2dev(chan), "%s: dest=0x%08x, len=%d, pattern=0x%x, flags=0x%lx\n", + __func__, sg_dma_address(sg), sg_dma_len(sg), + value, flags); + desc = at_xdmac_memset_create_desc(chan, atchan, + sg_dma_address(sg), + sg_dma_len(sg), + value); + if (!desc && first) + list_splice_init(&first->descs_list, + &atchan->free_descs_list); + + if (!first) + first = desc; + + /* Update our strides */ + pstride = stride; + if (psg) + stride = sg_dma_address(sg) - + (sg_dma_address(psg) + sg_dma_len(psg)); + + /* + * The scatterlist API gives us only the address and + * length of each elements. + * + * Unfortunately, we don't have the stride, which we + * will need to compute. + * + * That make us end up in a situation like this one: + * len stride len stride len + * +-------+ +-------+ +-------+ + * | N-2 | | N-1 | | N | + * +-------+ +-------+ +-------+ + * + * We need all these three elements (N-2, N-1 and N) + * to actually take the decision on whether we need to + * queue N-1 or reuse N-2. + * + * We will only consider N if it is the last element. + */ + if (ppdesc && pdesc) { + if ((stride == pstride) && + (sg_dma_len(ppsg) == sg_dma_len(psg))) { + dev_dbg(chan2dev(chan), + "%s: desc 0x%p can be merged with desc 0x%p\n", + __func__, pdesc, ppdesc); + + /* + * Increment the block count of the + * N-2 descriptor + */ + at_xdmac_increment_block_count(chan, ppdesc); + ppdesc->lld.mbr_dus = stride; + + /* + * Put back the N-1 descriptor in the + * free descriptor list + */ + list_add_tail(&pdesc->desc_node, + &atchan->free_descs_list); + + /* + * Make our N-1 descriptor pointer + * point to the N-2 since they were + * actually merged. + */ + pdesc = ppdesc; + + /* + * Rule out the case where we don't have + * pstride computed yet (our second sg + * element) + * + * We also want to catch the case where there + * would be a negative stride, + */ + } else if (pstride || + sg_dma_address(sg) < sg_dma_address(psg)) { + /* + * Queue the N-1 descriptor after the + * N-2 + */ + at_xdmac_queue_desc(chan, ppdesc, pdesc); + + /* + * Add the N-1 descriptor to the list + * of the descriptors used for this + * transfer + */ + list_add_tail(&desc->desc_node, + &first->descs_list); + dev_dbg(chan2dev(chan), + "%s: add desc 0x%p to descs_list 0x%p\n", + __func__, desc, first); + } + } + + /* + * If we are the last element, just see if we have the + * same size than the previous element. + * + * If so, we can merge it with the previous descriptor + * since we don't care about the stride anymore. + */ + if ((i == (sg_len - 1)) && + sg_dma_len(ppsg) == sg_dma_len(psg)) { + dev_dbg(chan2dev(chan), + "%s: desc 0x%p can be merged with desc 0x%p\n", + __func__, desc, pdesc); + + /* + * Increment the block count of the N-1 + * descriptor + */ + at_xdmac_increment_block_count(chan, pdesc); + pdesc->lld.mbr_dus = stride; + + /* + * Put back the N descriptor in the free + * descriptor list + */ + list_add_tail(&desc->desc_node, + &atchan->free_descs_list); + } + + /* Update our descriptors */ + ppdesc = pdesc; + pdesc = desc; + + /* Update our scatter pointers */ + ppsg = psg; + psg = sg; + + len += sg_dma_len(sg); + } + + first->tx_dma_desc.cookie = -EBUSY; + first->tx_dma_desc.flags = flags; + first->xfer_size = len; + + return &first->tx_dma_desc; +} + static enum dma_status at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct dma_tx_state *txstate) @@ -1734,6 +1896,7 @@ static int at_xdmac_probe(struct platform_device *pdev) dma_cap_set(DMA_INTERLEAVE, atxdmac->dma.cap_mask); dma_cap_set(DMA_MEMCPY, atxdmac->dma.cap_mask); dma_cap_set(DMA_MEMSET, atxdmac->dma.cap_mask); + dma_cap_set(DMA_MEMSET_SG, atxdmac->dma.cap_mask); dma_cap_set(DMA_SLAVE, atxdmac->dma.cap_mask); /* * Without DMA_PRIVATE the driver is not able to allocate more than @@ -1749,6 +1912,7 @@ static int at_xdmac_probe(struct platform_device *pdev) atxdmac->dma.device_prep_interleaved_dma = at_xdmac_prep_interleaved; atxdmac->dma.device_prep_dma_memcpy = at_xdmac_prep_dma_memcpy; atxdmac->dma.device_prep_dma_memset = at_xdmac_prep_dma_memset; + atxdmac->dma.device_prep_dma_memset_sg = at_xdmac_prep_dma_memset_sg; atxdmac->dma.device_prep_slave_sg = at_xdmac_prep_slave_sg; atxdmac->dma.device_config = at_xdmac_device_config; atxdmac->dma.device_pause = at_xdmac_device_pause; -- cgit v1.3-6-gb490 From 425e20fd08a53ad06c562960d594505813c7910c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 1 Aug 2015 07:06:58 +0000 Subject: dmaengine: ipu: Prepare irq handlers for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Vinod Koul Cc: Dan Williams Cc: dmaengine@vger.kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ipu/ipu_irq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index 4357063980e1..9f95940d3fe2 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -266,7 +266,7 @@ int ipu_irq_unmap(unsigned int source) } /* Chained IRQ handler for IPU error interrupt */ -static void ipu_irq_err(unsigned int irq, struct irq_desc *desc) +static void ipu_irq_err(unsigned int __irq, struct irq_desc *desc) { struct ipu *ipu = irq_desc_get_handler_data(desc); u32 status; @@ -286,6 +286,7 @@ static void ipu_irq_err(unsigned int irq, struct irq_desc *desc) raw_spin_unlock(&bank_lock); while ((line = ffs(status))) { struct ipu_irq_map *map; + unsigned int irq; line--; status &= ~(1UL << line); @@ -307,7 +308,7 @@ static void ipu_irq_err(unsigned int irq, struct irq_desc *desc) } /* Chained IRQ handler for IPU function interrupt */ -static void ipu_irq_fn(unsigned int irq, struct irq_desc *desc) +static void ipu_irq_fn(unsigned int __irq, struct irq_desc *desc) { struct ipu *ipu = irq_desc_get_handler_data(desc); u32 status; @@ -323,6 +324,7 @@ static void ipu_irq_fn(unsigned int irq, struct irq_desc *desc) raw_spin_unlock(&bank_lock); while ((line = ffs(status))) { struct ipu_irq_map *map; + unsigned int irq; line--; status &= ~(1UL << line); -- cgit v1.3-6-gb490 From 3d8cc00073d6750ffe883685e49b2e4a0f596370 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 1 Aug 2015 07:06:58 +0000 Subject: dmaengine: ipu: Consolidate duplicated irq handlers The functions irq_irq_err and ipu_irq_fn are identical plus/minus the comments. Remove one. Signed-off-by: Thomas Gleixner Cc: Vinod Koul Cc: Dan Williams Cc: dmaengine@vger.kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ipu/ipu_irq.c | 46 ++++------------------------------------------ 1 file changed, 4 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index 9f95940d3fe2..fc6506b12278 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -265,8 +265,8 @@ int ipu_irq_unmap(unsigned int source) return ret; } -/* Chained IRQ handler for IPU error interrupt */ -static void ipu_irq_err(unsigned int __irq, struct irq_desc *desc) +/* Chained IRQ handler for IPU function and error interrupt */ +static void ipu_irq_handler(unsigned int __irq, struct irq_desc *desc) { struct ipu *ipu = irq_desc_get_handler_data(desc); u32 status; @@ -307,44 +307,6 @@ static void ipu_irq_err(unsigned int __irq, struct irq_desc *desc) } } -/* Chained IRQ handler for IPU function interrupt */ -static void ipu_irq_fn(unsigned int __irq, struct irq_desc *desc) -{ - struct ipu *ipu = irq_desc_get_handler_data(desc); - u32 status; - int i, line; - - for (i = 0; i < IPU_IRQ_NR_FN_BANKS; i++) { - struct ipu_irq_bank *bank = irq_bank + i; - - raw_spin_lock(&bank_lock); - status = ipu_read_reg(ipu, bank->status); - /* Not clearing all interrupts, see above */ - status &= ipu_read_reg(ipu, bank->control); - raw_spin_unlock(&bank_lock); - while ((line = ffs(status))) { - struct ipu_irq_map *map; - unsigned int irq; - - line--; - status &= ~(1UL << line); - - raw_spin_lock(&bank_lock); - map = src2map(32 * i + line); - if (map) - irq = map->irq; - raw_spin_unlock(&bank_lock); - - if (!map) { - pr_err("IPU: Interrupt on unmapped source %u bank %d\n", - line, i); - continue; - } - generic_handle_irq(irq); - } - } -} - static struct irq_chip ipu_irq_chip = { .name = "ipu_irq", .irq_ack = ipu_irq_ack, @@ -384,9 +346,9 @@ int __init ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev) #endif } - irq_set_chained_handler_and_data(ipu->irq_fn, ipu_irq_fn, ipu); + irq_set_chained_handler_and_data(ipu->irq_fn, ipu_irq_handler, ipu); - irq_set_chained_handler_and_data(ipu->irq_err, ipu_irq_err, ipu); + irq_set_chained_handler_and_data(ipu->irq_err, ipu_irq_handler, ipu); ipu->irq_base = irq_base; -- cgit v1.3-6-gb490 From 368857c16c595eb7537cc0846708ddaa57a3a25b Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Wed, 29 Jul 2015 14:07:22 +1000 Subject: cxl: Don't ignore add_process_element() result when attaching context Currently when attaching a context in dedicated mode, we ignore the result of add_process_element(), which could potentially fail. If add_process_element() returns an error, pass it back to the caller. Signed-off-by: Daniel Axtens Signed-off-by: Michael Ellerman --- drivers/misc/cxl/native.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index fc9310dd2367..f74ff80266c8 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -492,9 +492,7 @@ static int attach_afu_directed(struct cxl_context *ctx, u64 wed, u64 amr) if ((result = cxl_afu_check_and_enable(ctx->afu))) return result; - add_process_element(ctx); - - return 0; + return add_process_element(ctx); } static int deactivate_afu_directed(struct cxl_afu *afu) -- cgit v1.3-6-gb490 From fe2b592173ff0274e70dc44d1d28c19bb995aa7c Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Fri, 31 Jul 2015 14:08:58 +0200 Subject: windfarm: decrement client count when unregistering wf_unregister_client() increments the client count when a client unregisters. That is obviously incorrect. Decrement that client count instead. Fixes: 75722d3992f5 ("[PATCH] ppc64: Thermal control for SMU based machines") Signed-off-by: Paul Bolle Signed-off-by: Michael Ellerman --- drivers/macintosh/windfarm_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index 3ee198b65843..cc7ece1712b5 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -435,7 +435,7 @@ int wf_unregister_client(struct notifier_block *nb) { mutex_lock(&wf_lock); blocking_notifier_chain_unregister(&wf_client_list, nb); - wf_client_count++; + wf_client_count--; if (wf_client_count == 0) wf_stop_thread(); mutex_unlock(&wf_lock); -- cgit v1.3-6-gb490 From ca94bbab1a0336f34066f27c503767b8181db5b1 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Fri, 31 Jul 2015 14:12:20 +0200 Subject: windfarm: make wf_critical_overtemp() static wf_critical_overtemp() is exported. But nothing uses that export. That's unsurprising because there's no header that defines it. Stop exporting that function and make it static. Signed-off-by: Paul Bolle Signed-off-by: Michael Ellerman --- drivers/macintosh/windfarm_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index cc7ece1712b5..681e5b4d4b6a 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -72,7 +72,7 @@ static inline void wf_notify(int event, void *param) blocking_notifier_call_chain(&wf_client_list, event, param); } -int wf_critical_overtemp(void) +static int wf_critical_overtemp(void) { static char * critical_overtemp_path = "/sbin/critical_overtemp"; char *argv[] = { critical_overtemp_path, NULL }; @@ -84,7 +84,6 @@ int wf_critical_overtemp(void) return call_usermodehelper(critical_overtemp_path, argv, envp, UMH_WAIT_EXEC); } -EXPORT_SYMBOL_GPL(wf_critical_overtemp); static int wf_thread_func(void *data) { -- cgit v1.3-6-gb490 From a368c29cf105485d2c34fb5d09d2dbe813e483e1 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Fri, 31 Jul 2015 14:14:20 +0200 Subject: windfarm: remove three exported but unused functions wf_find_control(), wf_find_sensor(), and wf_is_overtemp() are exported but unused. Remove these three functions. Signed-off-by: Paul Bolle Signed-off-by: Michael Ellerman --- drivers/macintosh/windfarm.h | 4 ---- drivers/macintosh/windfarm_core.c | 42 --------------------------------------- 2 files changed, 46 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/windfarm.h b/drivers/macintosh/windfarm.h index 028cdac2d33d..901c42f71b5a 100644 --- a/drivers/macintosh/windfarm.h +++ b/drivers/macintosh/windfarm.h @@ -53,11 +53,9 @@ struct wf_control { * the kref and wf_unregister_control will decrement it, thus the * object creating/disposing a given control shouldn't assume it * still exists after wf_unregister_control has been called. - * wf_find_control will inc the refcount for you */ extern int wf_register_control(struct wf_control *ct); extern void wf_unregister_control(struct wf_control *ct); -extern struct wf_control * wf_find_control(const char *name); extern int wf_get_control(struct wf_control *ct); extern void wf_put_control(struct wf_control *ct); @@ -117,7 +115,6 @@ struct wf_sensor { /* Same lifetime rules as controls */ extern int wf_register_sensor(struct wf_sensor *sr); extern void wf_unregister_sensor(struct wf_sensor *sr); -extern struct wf_sensor * wf_find_sensor(const char *name); extern int wf_get_sensor(struct wf_sensor *sr); extern void wf_put_sensor(struct wf_sensor *sr); @@ -144,7 +141,6 @@ extern int wf_unregister_client(struct notifier_block *nb); /* Overtemp conditions. Those are refcounted */ extern void wf_set_overtemp(void); extern void wf_clear_overtemp(void); -extern int wf_is_overtemp(void); #define WF_EVENT_NEW_CONTROL 0 /* param is wf_control * */ #define WF_EVENT_NEW_SENSOR 1 /* param is wf_sensor * */ diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c index 681e5b4d4b6a..465d770ab0bb 100644 --- a/drivers/macintosh/windfarm_core.c +++ b/drivers/macintosh/windfarm_core.c @@ -254,24 +254,6 @@ void wf_unregister_control(struct wf_control *ct) } EXPORT_SYMBOL_GPL(wf_unregister_control); -struct wf_control * wf_find_control(const char *name) -{ - struct wf_control *ct; - - mutex_lock(&wf_lock); - list_for_each_entry(ct, &wf_controls, link) { - if (!strcmp(ct->name, name)) { - if (wf_get_control(ct)) - ct = NULL; - mutex_unlock(&wf_lock); - return ct; - } - } - mutex_unlock(&wf_lock); - return NULL; -} -EXPORT_SYMBOL_GPL(wf_find_control); - int wf_get_control(struct wf_control *ct) { if (!try_module_get(ct->ops->owner)) @@ -367,24 +349,6 @@ void wf_unregister_sensor(struct wf_sensor *sr) } EXPORT_SYMBOL_GPL(wf_unregister_sensor); -struct wf_sensor * wf_find_sensor(const char *name) -{ - struct wf_sensor *sr; - - mutex_lock(&wf_lock); - list_for_each_entry(sr, &wf_sensors, link) { - if (!strcmp(sr->name, name)) { - if (wf_get_sensor(sr)) - sr = NULL; - mutex_unlock(&wf_lock); - return sr; - } - } - mutex_unlock(&wf_lock); - return NULL; -} -EXPORT_SYMBOL_GPL(wf_find_sensor); - int wf_get_sensor(struct wf_sensor *sr) { if (!try_module_get(sr->ops->owner)) @@ -473,12 +437,6 @@ void wf_clear_overtemp(void) } EXPORT_SYMBOL_GPL(wf_clear_overtemp); -int wf_is_overtemp(void) -{ - return (wf_overtemp != 0); -} -EXPORT_SYMBOL_GPL(wf_is_overtemp); - static int __init windfarm_core_init(void) { DBG("wf: core loaded\n"); -- cgit v1.3-6-gb490 From f1ad8c9346de80c91d7f35d4a1b0d1f2b93b3661 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:49 +0300 Subject: wil6210: support boot loader struct v0 & v1 There are 2 versions of boot loader struct: v0 and v1. In the v1, boot loader build version added; as well as RF status. Support both versions. Boot loader structure v1 has RF status; ignore RF error if firmware not going to be loaded; driver can still be used to interact with the HW Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/boot_loader.h | 56 +++++++++++++++++ drivers/net/wireless/ath/wil6210/main.c | 85 ++++++++++++++++++++------ drivers/net/wireless/ath/wil6210/wil6210.h | 10 --- 3 files changed, 124 insertions(+), 27 deletions(-) create mode 100644 drivers/net/wireless/ath/wil6210/boot_loader.h (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/boot_loader.h b/drivers/net/wireless/ath/wil6210/boot_loader.h new file mode 100644 index 000000000000..1b4fd402cba2 --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/boot_loader.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2015 Qualcomm Atheros, 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. + */ + +/* This file contains the definitions for the boot loader + * for the Qualcomm "Sparrow" 60 Gigabit wireless solution. + */ +#ifndef BOOT_LOADER_EXPORT_H_ +#define BOOT_LOADER_EXPORT_H_ + +struct bl_dedicated_registers_v1 { + __le32 boot_loader_ready; /* 0x880A3C driver will poll + * this Dword until BL will + * set it to 1 (initial value + * should be 0) + */ + __le32 boot_loader_struct_version; /* 0x880A40 BL struct ver. */ + __le16 rf_type; /* 0x880A44 connected RF ID */ + __le16 rf_status; /* 0x880A46 RF status, + * 0 is OK else error + */ + __le32 baseband_type; /* 0x880A48 board type ID */ + u8 mac_address[6]; /* 0x880A4c BL mac address */ + u8 bl_version_major; /* 0x880A52 BL ver. major */ + u8 bl_version_minor; /* 0x880A53 BL ver. minor */ + __le16 bl_version_subminor; /* 0x880A54 BL ver. subminor */ + __le16 bl_version_build; /* 0x880A56 BL ver. build */ +} __packed; + +/* the following struct is the version 0 struct */ + +struct bl_dedicated_registers_v0 { + __le32 boot_loader_ready; /* 0x880A3C driver will poll + * this Dword until BL will + * set it to 1 (initial value + * should be 0) + */ +#define BL_READY (1) /* ready indication */ + __le32 boot_loader_struct_version; /* 0x880A40 BL struct ver. */ + __le32 rf_type; /* 0x880A44 connected RF ID */ + __le32 baseband_type; /* 0x880A48 board type ID */ + u8 mac_address[6]; /* 0x880A4c BL mac address */ +} __packed; + +#endif /* BOOT_LOADER_EXPORT_H_ */ diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 6ca6193ab8a6..ae0df3588e5d 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -21,6 +21,7 @@ #include "wil6210.h" #include "txrx.h" #include "wmi.h" +#include "boot_loader.h" #define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000 #define WAIT_FOR_DISCONNECT_INTERVAL_MS 10 @@ -565,7 +566,8 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_halt_cpu(wil); /* clear all boot loader "ready" bits */ - W(RGF_USER_BL + offsetof(struct RGF_BL, ready), 0); + W(RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); /* Clear Fw Download notification */ C(RGF_USER_USAGE_6, BIT(0)); @@ -607,7 +609,8 @@ static int wil_target_reset(struct wil6210_priv *wil) /* wait until device ready. typical time is 20..80 msec */ do { msleep(RST_DELAY); - x = R(RGF_USER_BL + offsetof(struct RGF_BL, ready)); + x = R(RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, + boot_loader_ready)); if (x1 != x) { wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x); x1 = x; @@ -617,7 +620,7 @@ static int wil_target_reset(struct wil6210_priv *wil) x); return -ETIME; } - } while (x != BIT_BL_READY); + } while (x != BL_READY); C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); @@ -641,25 +644,71 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) static int wil_get_bl_info(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); - struct RGF_BL bl; - - wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), sizeof(bl)); - le32_to_cpus(&bl.ready); - le32_to_cpus(&bl.version); - le32_to_cpus(&bl.rf_type); - le32_to_cpus(&bl.baseband_type); + union { + struct bl_dedicated_registers_v0 bl0; + struct bl_dedicated_registers_v1 bl1; + } bl; + u32 bl_ver; + u8 *mac; + u16 rf_status; + + bl_ver = R(RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, + boot_loader_struct_version)); + switch (bl_ver) { + case 0: + wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), + sizeof(bl.bl0)); + le32_to_cpus(&bl.bl0.boot_loader_ready); + le32_to_cpus(&bl.bl0.boot_loader_struct_version); + le32_to_cpus(&bl.bl0.rf_type); + le32_to_cpus(&bl.bl0.baseband_type); + mac = bl.bl0.mac_address; + rf_status = 0; /* actually, unknown */ + wil_info(wil, + "Boot Loader struct v%d: MAC = %pM RF = 0x%08x bband = 0x%08x\n", + bl_ver, mac, + bl.bl0.rf_type, bl.bl0.baseband_type); + wil_info(wil, "Boot Loader build unknown for struct v0\n"); + break; + case 1: + wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), + sizeof(bl.bl1)); + le32_to_cpus(&bl.bl1.boot_loader_ready); + le32_to_cpus(&bl.bl1.boot_loader_struct_version); + le16_to_cpus(&bl.bl1.rf_type); + rf_status = le16_to_cpu(bl.bl1.rf_status); + le32_to_cpus(&bl.bl1.baseband_type); + le16_to_cpus(&bl.bl1.bl_version_subminor); + le16_to_cpus(&bl.bl1.bl_version_build); + mac = bl.bl1.mac_address; + wil_info(wil, + "Boot Loader struct v%d: MAC = %pM RF = 0x%04x (status 0x%04x) bband = 0x%08x\n", + bl_ver, mac, + bl.bl1.rf_type, rf_status, + bl.bl1.baseband_type); + wil_info(wil, "Boot Loader build %d.%d.%d.%d\n", + bl.bl1.bl_version_major, bl.bl1.bl_version_minor, + bl.bl1.bl_version_subminor, bl.bl1.bl_version_build); + break; + default: + wil_err(wil, "BL: unsupported struct version 0x%08x\n", bl_ver); + return -EINVAL; + } - if (!is_valid_ether_addr(bl.mac_address)) { - wil_err(wil, "BL: Invalid MAC %pM\n", bl.mac_address); + if (!is_valid_ether_addr(mac)) { + wil_err(wil, "BL: Invalid MAC %pM\n", mac); return -EINVAL; } - ether_addr_copy(ndev->perm_addr, bl.mac_address); + ether_addr_copy(ndev->perm_addr, mac); if (!is_valid_ether_addr(ndev->dev_addr)) - ether_addr_copy(ndev->dev_addr, bl.mac_address); - wil_info(wil, - "Boot Loader: ver = %d MAC = %pM RF = 0x%08x bband = 0x%08x\n", - bl.version, bl.mac_address, bl.rf_type, bl.baseband_type); + ether_addr_copy(ndev->dev_addr, mac); + + if (rf_status) {/* bad RF cable? */ + wil_err(wil, "RF communication error 0x%04x", + rf_status); + return -EAGAIN; + } return 0; } @@ -735,6 +784,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; rc = wil_get_bl_info(wil); + if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ + rc = 0; if (rc) return rc; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c63e4a35eaa0..b79ba4994d0c 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -127,16 +127,6 @@ struct RGF_ICR { u32 IMC; /* Mask Clear, write 1 to clear */ } __packed; -struct RGF_BL { - u32 ready; /* 0x880A3C bit [0] */ -#define BIT_BL_READY BIT(0) - u32 version; /* 0x880A40 version of the BL struct */ - u32 rf_type; /* 0x880A44 ID of the connected RF */ - u32 baseband_type; /* 0x880A48 ID of the baseband */ - u8 mac_address[ETH_ALEN]; /* 0x880A4C permanent MAC */ - u8 pad[2]; -} __packed; - /* registers - FW addresses */ #define RGF_USER_USAGE_1 (0x880004) #define RGF_USER_USAGE_6 (0x880018) -- cgit v1.3-6-gb490 From 6093e66b6b456f4526e190b00d362520b787889b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:50 +0300 Subject: wil6210: count drops in Rx block ack reorder When performing Rx reordering, count skb's dropped per reorder buffer; and print dropped packets count on the "stations" debugfs entry Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 2 +- drivers/net/wireless/ath/wil6210/rx_reorder.c | 2 ++ drivers/net/wireless/ath/wil6210/wil6210.h | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 75219a1b8805..b862676de577 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1353,7 +1353,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) else seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); } - seq_printf(s, "] last drop 0x%03x\n", r->ssn_last_drop); + seq_printf(s, "] drop %llu last 0x%03x\n", r->drop, r->ssn_last_drop); } static int wil_sta_debugfs_show(struct seq_file *s, void *data) diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index ca10dcf0986e..e4ac11cf0f50 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -153,6 +153,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) /* frame with out of date sequence number */ if (seq_less(seq, r->head_seq_num)) { r->ssn_last_drop = seq; + r->drop++; dev_kfree_skb(skb); goto out; } @@ -173,6 +174,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) /* check if we already stored this frame */ if (r->reorder_buf[index]) { + r->drop++; dev_kfree_skb(skb); goto out; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index b79ba4994d0c..54f16732d226 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -426,6 +426,7 @@ struct pci_dev; * @timeout: reset timer value (in TUs). * @dialog_token: dialog token for aggregation session * @rcu_head: RCU head used for freeing this struct + * @drop: total frames dropped for this reorder buffer * * This structure's lifetime is managed by RCU, assignments to * the array holding it must hold the aggregation mutex. @@ -443,6 +444,7 @@ struct wil_tid_ampdu_rx { u16 buf_size; u16 timeout; u16 ssn_last_drop; + unsigned long long drop; u8 dialog_token; bool first_time; /* is it 1-st time this buffer used? */ }; -- cgit v1.3-6-gb490 From 8ea06188fd8cb4c6bb85663b6dedcab22f7ffba7 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:51 +0300 Subject: wil6210: print "ulong" fields in hex format in the debugfs In the debugfs, there is "ulong" attribute printing. It is used for bitmap printing, and more appropriate format would be hexadecimal, not decimal. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index b862676de577..2651ec4fb620 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -306,7 +306,7 @@ static int wil_debugfs_ulong_get(void *data, u64 *val) } DEFINE_SIMPLE_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, - wil_debugfs_ulong_set, "%llu\n"); + wil_debugfs_ulong_set, "0x%llx\n"); static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, -- cgit v1.3-6-gb490 From 8a9d1dc5741da8575e3393de392cc1704ecd4fe7 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:52 +0300 Subject: wil6210: use <> vs. "" for global include linux/device.h should be included using <>, not "" since it is not local include Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wil_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c index de15f1422fe9..2e831bf20117 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.c +++ b/drivers/net/wireless/ath/wil6210/wil_platform.c @@ -14,7 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "linux/device.h" +#include #include "wil_platform.h" int __init wil_platform_modinit(void) -- cgit v1.3-6-gb490 From 3e9191fce2d6b36a429dc046cdc1f7e8ec70465c Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:53 +0300 Subject: wil6210: wait for del_station to complete Multiple del_station requests may be sent to the driver by the supplicant when turning down AP. This may overflow mailbox between the FW and ucode Wait till disconnect of one STA completed before sending next command. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index c759759afbb2..362ce7a257e8 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1129,15 +1129,42 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason) { + int rc; + u16 reason_code; struct wmi_disconnect_sta_cmd cmd = { .disconnect_reason = cpu_to_le16(reason), }; + struct { + struct wil6210_mbox_hdr_wmi wmi; + struct wmi_disconnect_event evt; + } __packed reply; ether_addr_copy(cmd.dst_mac, mac); wil_dbg_wmi(wil, "%s(%pM, reason %d)\n", __func__, mac, reason); - return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd)); + rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd), + WMI_DISCONNECT_EVENTID, &reply, sizeof(reply), 1000); + /* failure to disconnect in reasonable time treated as FW error */ + if (rc) { + wil_fw_error_recovery(wil); + return rc; + } + + /* call event handler manually after processing wmi_call, + * to avoid deadlock - disconnect event handler acquires wil->mutex + * while it is already held here + */ + reason_code = le16_to_cpu(reply.evt.protocol_reason_status); + + wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n", + reply.evt.bssid, reason_code, + reply.evt.disconnect_reason); + + wil->sinfo_gen++; + wil6210_disconnect(wil, reply.evt.bssid, reason_code, true); + + return 0; } int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout) -- cgit v1.3-6-gb490 From 8ad6600fbdd699f0d7a3ec250d20256a7ec98889 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:54 +0300 Subject: wil6210: use wil_fw_error_recovery() Use function wil_fw_error_recovery() instead of inline equivalent code Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index ae0df3588e5d..c77ae1739afc 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -271,8 +271,7 @@ static void wil_scan_timer_fn(ulong x) clear_bit(wil_status_fwready, wil->status); wil_err(wil, "Scan timeout detected, start fw error recovery\n"); - wil->recovery_state = fw_recovery_pending; - schedule_work(&wil->fw_error_worker); + wil_fw_error_recovery(wil); } static int wil_wait_for_recovery(struct wil6210_priv *wil) -- cgit v1.3-6-gb490 From 67131a1dba5f45cee78e9de09605cbdda1a1ce6c Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:55 +0300 Subject: wil6210: skip HW version check for chip debugging When loading with debug_fw flag, do not bail out on unknown chipId Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index c77ae1739afc..33a3e9b136d9 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -738,9 +738,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) wil_dbg_misc(wil, "%s()\n", __func__); - if (wil->hw_version == HW_VER_UNKNOWN) - return -ENODEV; - WARN_ON(!mutex_is_locked(&wil->mutex)); WARN_ON(test_bit(wil_status_napi_en, wil->status)); @@ -755,6 +752,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return 0; } + if (wil->hw_version == HW_VER_UNKNOWN) + return -ENODEV; + cancel_work_sync(&wil->disconnect_worker); wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); wil_bcast_fini(wil); -- cgit v1.3-6-gb490 From 3d4bde15315605d2490eafe9f763897e69f9125e Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:56 +0300 Subject: wil6210: TSO implementation Driver report supported TSO (v4 & v6) and IP checksum offload in addition to previously supported features. In data path skbs are checked for non-zero gso_size, and when detected sent to additional function for processing TSO SKBs. Since HW does not fully support TSO, additional effort is required from the driver. Driver partitions the data into mss sized descriptors which are then DMAed to the HW. Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/netdev.c | 4 +- drivers/net/wireless/ath/wil6210/txrx.c | 371 +++++++++++++++++++++++++++++- drivers/net/wireless/ath/wil6210/txrx.h | 8 + 3 files changed, 371 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 8ef18ace110f..25c51167adff 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -173,7 +173,9 @@ void *wil_if_alloc(struct device *dev) wil_set_ethtoolops(ndev); ndev->ieee80211_ptr = wdev; ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | - NETIF_F_SG | NETIF_F_GRO; + NETIF_F_SG | NETIF_F_GRO | + NETIF_F_TSO | NETIF_F_TSO6; + 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 aa20af86e1d6..7722df78b267 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1058,14 +1058,52 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len, 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); + d->mac.d[2] |= (nr_frags << 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) +/** + * Sets the descriptor @d up for csum and/or TSO offloading. The corresponding + * @skb is used to obtain the protocol and headers length. + * @tso_desc_type is a descriptor type for TSO: 0 - a header, 1 - first data, + * 2 - middle, 3 - last descriptor. + */ + +static void wil_tx_desc_offload_setup_tso(struct vring_tx_desc *d, + struct sk_buff *skb, + int tso_desc_type, bool is_ipv4, + int tcp_hdr_len, int skb_net_hdr_len) { + d->dma.b11 = ETH_HLEN; /* MAC header length */ + d->dma.b11 |= is_ipv4 << DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS; + + d->dma.d0 |= (2 << DMA_CFG_DESC_TX_0_L4_TYPE_POS); + /* L4 header len: TCP header length */ + d->dma.d0 |= (tcp_hdr_len & DMA_CFG_DESC_TX_0_L4_LENGTH_MSK); + + /* Setup TSO: bit and desc type */ + d->dma.d0 |= (BIT(DMA_CFG_DESC_TX_0_TCP_SEG_EN_POS)) | + (tso_desc_type << DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS); + d->dma.d0 |= (is_ipv4 << DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_POS); + + d->dma.ip_length = skb_net_hdr_len; + /* Enable TCP/UDP checksum */ + d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS); + /* Calculate pseudo-header */ + d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_POS); +} + +/** + * Sets the descriptor @d up for csum. The corresponding + * @skb is used to obtain the protocol and headers length. + * Returns the protocol: 0 - not TCP, 1 - TCPv4, 2 - TCPv6. + * Note, if d==NULL, the function only returns the protocol result. + * + * It is very similar to previous wil_tx_desc_offload_setup_tso. This + * is "if unrolling" to optimize the critical path. + */ + +static int wil_tx_desc_offload_setup(struct vring_tx_desc *d, + struct sk_buff *skb){ int protocol; if (skb->ip_summed != CHECKSUM_PARTIAL) @@ -1110,6 +1148,305 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, return 0; } +static inline void wil_tx_last_desc(struct vring_tx_desc *d) +{ + d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS) | + BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS) | + BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS); +} + +static inline void wil_set_tx_desc_last_tso(volatile struct vring_tx_desc *d) +{ + d->dma.d0 |= wil_tso_type_lst << + DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS; +} + +static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring, + struct sk_buff *skb) +{ + struct device *dev = wil_to_dev(wil); + + /* point to descriptors in shared memory */ + volatile struct vring_tx_desc *_desc = NULL, *_hdr_desc, + *_first_desc = NULL; + + /* pointers to shadow descriptors */ + struct vring_tx_desc desc_mem, hdr_desc_mem, first_desc_mem, + *d = &hdr_desc_mem, *hdr_desc = &hdr_desc_mem, + *first_desc = &first_desc_mem; + + /* pointer to shadow descriptors' context */ + struct wil_ctx *hdr_ctx, *first_ctx = NULL; + + int descs_used = 0; /* total number of used descriptors */ + int sg_desc_cnt = 0; /* number of descriptors for current mss*/ + + u32 swhead = vring->swhead; + int used, avail = wil_vring_avail_tx(vring); + int nr_frags = skb_shinfo(skb)->nr_frags; + int min_desc_required = nr_frags + 1; + int mss = skb_shinfo(skb)->gso_size; /* payload size w/o headers */ + int f, len, hdrlen, headlen; + int vring_index = vring - wil->vring_tx; + struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; + uint i = swhead; + dma_addr_t pa; + const skb_frag_t *frag = NULL; + int rem_data = mss; + int lenmss; + int hdr_compensation_need = true; + int desc_tso_type = wil_tso_type_first; + bool is_ipv4; + int tcp_hdr_len; + int skb_net_hdr_len; + int gso_type; + + wil_dbg_txrx(wil, "%s() %d bytes to vring %d\n", + __func__, skb->len, vring_index); + + if (unlikely(!txdata->enabled)) + return -EINVAL; + + /* A typical page 4K is 3-4 payloads, we assume each fragment + * is a full payload, that's how min_desc_required has been + * calculated. In real we might need more or less descriptors, + * this is the initial check only. + */ + if (unlikely(avail < min_desc_required)) { + wil_err_ratelimited(wil, + "TSO: Tx ring[%2d] full. No space for %d fragments\n", + vring_index, min_desc_required); + return -ENOMEM; + } + + /* Header Length = MAC header len + IP header len + TCP header len*/ + hdrlen = ETH_HLEN + + (int)skb_network_header_len(skb) + + tcp_hdrlen(skb); + + gso_type = skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV6 | SKB_GSO_TCPV4); + switch (gso_type) { + case SKB_GSO_TCPV4: + /* TCP v4, zero out the IP length and IPv4 checksum fields + * as required by the offloading doc + */ + ip_hdr(skb)->tot_len = 0; + ip_hdr(skb)->check = 0; + is_ipv4 = true; + break; + case SKB_GSO_TCPV6: + /* TCP v6, zero out the payload length */ + ipv6_hdr(skb)->payload_len = 0; + is_ipv4 = false; + break; + default: + /* other than TCPv4 or TCPv6 types are not supported for TSO. + * It is also illegal for both to be set simultaneously + */ + return -EINVAL; + } + + if (skb->ip_summed != CHECKSUM_PARTIAL) + return -EINVAL; + + /* tcp header length and skb network header length are fixed for all + * packet's descriptors - read then once here + */ + tcp_hdr_len = tcp_hdrlen(skb); + skb_net_hdr_len = skb_network_header_len(skb); + + _hdr_desc = &vring->va[i].tx; + + pa = dma_map_single(dev, skb->data, hdrlen, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(dev, pa))) { + wil_err(wil, "TSO: Skb head DMA map error\n"); + goto err_exit; + } + + wil_tx_desc_map(hdr_desc, pa, hdrlen, vring_index); + wil_tx_desc_offload_setup_tso(hdr_desc, skb, wil_tso_type_hdr, is_ipv4, + tcp_hdr_len, skb_net_hdr_len); + wil_tx_last_desc(hdr_desc); + + vring->ctx[i].mapped_as = wil_mapped_as_single; + hdr_ctx = &vring->ctx[i]; + + descs_used++; + headlen = skb_headlen(skb) - hdrlen; + + for (f = headlen ? -1 : 0; f < nr_frags; f++) { + if (headlen) { + len = headlen; + wil_dbg_txrx(wil, "TSO: process skb head, len %u\n", + len); + } else { + frag = &skb_shinfo(skb)->frags[f]; + len = frag->size; + wil_dbg_txrx(wil, "TSO: frag[%d]: len %u\n", f, len); + } + + while (len) { + wil_dbg_txrx(wil, + "TSO: len %d, rem_data %d, descs_used %d\n", + len, rem_data, descs_used); + + if (descs_used == avail) { + wil_err(wil, "TSO: ring overflow\n"); + goto dma_error; + } + + lenmss = min_t(int, rem_data, len); + i = (swhead + descs_used) % vring->size; + wil_dbg_txrx(wil, "TSO: lenmss %d, i %d\n", lenmss, i); + + if (!headlen) { + pa = skb_frag_dma_map(dev, frag, + frag->size - len, lenmss, + DMA_TO_DEVICE); + vring->ctx[i].mapped_as = wil_mapped_as_page; + } else { + pa = dma_map_single(dev, + skb->data + + skb_headlen(skb) - headlen, + lenmss, + DMA_TO_DEVICE); + vring->ctx[i].mapped_as = wil_mapped_as_single; + headlen -= lenmss; + } + + if (unlikely(dma_mapping_error(dev, pa))) + goto dma_error; + + _desc = &vring->va[i].tx; + + if (!_first_desc) { + _first_desc = _desc; + first_ctx = &vring->ctx[i]; + d = first_desc; + } else { + d = &desc_mem; + } + + wil_tx_desc_map(d, pa, lenmss, vring_index); + wil_tx_desc_offload_setup_tso(d, skb, desc_tso_type, + is_ipv4, tcp_hdr_len, + skb_net_hdr_len); + + /* use tso_type_first only once */ + desc_tso_type = wil_tso_type_mid; + + descs_used++; /* desc used so far */ + sg_desc_cnt++; /* desc used for this segment */ + len -= lenmss; + rem_data -= lenmss; + + wil_dbg_txrx(wil, + "TSO: len %d, rem_data %d, descs_used %d, sg_desc_cnt %d,\n", + len, rem_data, descs_used, sg_desc_cnt); + + /* Close the segment if reached mss size or last frag*/ + if (rem_data == 0 || (f == nr_frags - 1 && len == 0)) { + if (hdr_compensation_need) { + /* first segment include hdr desc for + * release + */ + hdr_ctx->nr_frags = sg_desc_cnt; + wil_tx_desc_set_nr_frags(first_desc, + sg_desc_cnt + + 1); + hdr_compensation_need = false; + } else { + wil_tx_desc_set_nr_frags(first_desc, + sg_desc_cnt); + } + first_ctx->nr_frags = sg_desc_cnt - 1; + + wil_tx_last_desc(d); + + /* first descriptor may also be the last + * for this mss - make sure not to copy + * it twice + */ + if (first_desc != d) + *_first_desc = *first_desc; + + /*last descriptor will be copied at the end + * of this TS processing + */ + if (f < nr_frags - 1 || len > 0) + *_desc = *d; + + rem_data = mss; + _first_desc = NULL; + sg_desc_cnt = 0; + } else if (first_desc != d) /* update mid descriptor */ + *_desc = *d; + } + } + + /* first descriptor may also be the last. + * in this case d pointer is invalid + */ + if (_first_desc == _desc) + d = first_desc; + + /* Last data descriptor */ + wil_set_tx_desc_last_tso(d); + *_desc = *d; + + /* Fill the total number of descriptors in first desc (hdr)*/ + wil_tx_desc_set_nr_frags(hdr_desc, descs_used); + *_hdr_desc = *hdr_desc; + + /* hold reference to skb + * to prevent skb release before accounting + * in case of immediate "tx done" + */ + vring->ctx[i].skb = skb_get(skb); + + /* performance monitoring */ + used = wil_vring_used_tx(vring); + if (wil_val_in_range(vring_idle_trsh, + used, used + descs_used)) { + txdata->idle += get_cycles() - txdata->last_idle; + wil_dbg_txrx(wil, "Ring[%2d] not idle %d -> %d\n", + vring_index, used, used + descs_used); + } + + /* advance swhead */ + wil_dbg_txrx(wil, "TSO: Tx swhead %d -> %d\n", swhead, vring->swhead); + wil_vring_advance_head(vring, descs_used); + + /* make sure all writes to descriptors (shared memory) are done before + * committing them to HW + */ + wmb(); + + iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); + return 0; + +dma_error: + wil_err(wil, "TSO: DMA map page error\n"); + while (descs_used > 0) { + struct wil_ctx *ctx; + + i = (swhead + descs_used) % vring->size; + d = (struct vring_tx_desc *)&vring->va[i].tx; + _desc = &vring->va[i].tx; + *d = *_desc; + _desc->dma.status = TX_DMA_STATUS_DU; + ctx = &vring->ctx[i]; + wil_txdesc_unmap(dev, d, ctx); + if (ctx->skb) + dev_kfree_skb_any(ctx->skb); + memset(ctx, 0, sizeof(*ctx)); + descs_used--; + } + +err_exit: + return -EINVAL; +} + static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, struct sk_buff *skb) { @@ -1128,7 +1465,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, bool mcast = (vring_index == wil->bcast_vring); uint len = skb_headlen(skb); - wil_dbg_txrx(wil, "%s()\n", __func__); + wil_dbg_txrx(wil, "%s() %d bytes to vring %d\n", + __func__, skb->len, vring_index); if (unlikely(!txdata->enabled)) return -EINVAL; @@ -1159,14 +1497,14 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, d->mac.d[0] |= (1 << MAC_CFG_DESC_TX_0_MCS_INDEX_POS); } /* Process TCP/UDP checksum offloading */ - if (unlikely(wil_tx_desc_offload_cksum_set(wil, d, skb))) { + if (unlikely(wil_tx_desc_offload_setup(d, skb))) { wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n", vring_index); goto dma_error; } vring->ctx[i].nr_frags = nr_frags; - wil_tx_desc_set_nr_frags(d, nr_frags); + wil_tx_desc_set_nr_frags(d, nr_frags + 1); /* middle segments */ for (; f < nr_frags; f++) { @@ -1190,7 +1528,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, * if it succeeded for 1-st descriptor, * it will succeed here too */ - wil_tx_desc_offload_cksum_set(wil, d, skb); + wil_tx_desc_offload_setup(d, skb); } /* for the last seg only */ d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS); @@ -1221,6 +1559,12 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead, vring->swhead); trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags); + + /* make sure all writes to descriptors (shared memory) are done before + * committing them to HW + */ + wmb(); + iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); return 0; @@ -1254,8 +1598,12 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, int rc; spin_lock(&txdata->lock); - rc = __wil_tx_vring(wil, vring, skb); + + rc = (skb_is_gso(skb) ? __wil_tx_vring_tso : __wil_tx_vring) + (wil, vring, skb); + spin_unlock(&txdata->lock); + return rc; } @@ -1382,7 +1730,8 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) struct wil_ctx *ctx = &vring->ctx[vring->swtail]; /** * For the fragmented skb, HW will set DU bit only for the - * last fragment. look for it + * last fragment. look for it. + * In TSO the first DU will include hdr desc */ int lf = (vring->swtail + ctx->nr_frags) % vring->size; /* TODO: check we are not past head */ diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 0c4638487c74..82a8f9a030e7 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -291,6 +291,14 @@ struct vring_tx_dma { __le16 length; } __packed; +/* TSO type used in dma descriptor d0 bits 11-12 */ +enum { + wil_tso_type_hdr = 0, + wil_tso_type_first = 1, + wil_tso_type_mid = 2, + wil_tso_type_lst = 3, +}; + /* Rx descriptor - MAC part * [dword 0] * bit 0.. 3 : tid:4 The QoS (b3-0) TID Field -- cgit v1.3-6-gb490 From 90d89e9aaa9923cd44bd5bf8a26abb7834581ba6 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:57 +0300 Subject: wil6210: improve mgmt frame handling Check event length; hex dump both Rx and Tx frames Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 54 +++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 362ce7a257e8..349f14ae9944 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -312,22 +312,44 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) struct wiphy *wiphy = wil_to_wiphy(wil); struct ieee80211_mgmt *rx_mgmt_frame = (struct ieee80211_mgmt *)data->payload; - int ch_no = data->info.channel+1; - u32 freq = ieee80211_channel_to_frequency(ch_no, - IEEE80211_BAND_60GHZ); - struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq); - s32 signal = data->info.sqi; - __le16 fc = rx_mgmt_frame->frame_control; - u32 d_len = le32_to_cpu(data->info.len); - u16 d_status = le16_to_cpu(data->info.status); - - wil_dbg_wmi(wil, "MGMT: channel %d MCS %d SNR %d SQI %d%%\n", + int flen = len - offsetof(struct wmi_rx_mgmt_packet_event, payload); + int ch_no; + u32 freq; + struct ieee80211_channel *channel; + s32 signal; + __le16 fc; + u32 d_len; + u16 d_status; + + if (flen < 0) { + wil_err(wil, "MGMT Rx: short event, len %d\n", len); + return; + } + + d_len = le32_to_cpu(data->info.len); + if (d_len != flen) { + wil_err(wil, + "MGMT Rx: length mismatch, d_len %d should be %d\n", + d_len, flen); + return; + } + + ch_no = data->info.channel + 1; + freq = ieee80211_channel_to_frequency(ch_no, IEEE80211_BAND_60GHZ); + channel = ieee80211_get_channel(wiphy, freq); + signal = data->info.sqi; + d_status = le16_to_cpu(data->info.status); + fc = rx_mgmt_frame->frame_control; + + wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d SNR %d SQI %d%%\n", data->info.channel, data->info.mcs, data->info.snr, data->info.sqi); wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len, le16_to_cpu(fc)); wil_dbg_wmi(wil, "qid %d mid %d cid %d\n", data->info.qid, data->info.mid, data->info.cid); + wil_hex_dump_wmi("MGMT Rx ", DUMP_PREFIX_OFFSET, 16, 1, rx_mgmt_frame, + d_len, true); if (!channel) { wil_err(wil, "Frame on unsupported channel\n"); @@ -363,6 +385,17 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) } } +static void wmi_evt_tx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) +{ + struct wmi_tx_mgmt_packet_event *data = d; + struct ieee80211_mgmt *mgmt_frame = + (struct ieee80211_mgmt *)data->payload; + int flen = len - offsetof(struct wmi_tx_mgmt_packet_event, payload); + + wil_hex_dump_wmi("MGMT Tx ", DUMP_PREFIX_OFFSET, 16, 1, mgmt_frame, + flen, true); +} + static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, void *d, int len) { @@ -659,6 +692,7 @@ static const struct { {WMI_READY_EVENTID, wmi_evt_ready}, {WMI_FW_READY_EVENTID, wmi_evt_fw_ready}, {WMI_RX_MGMT_PACKET_EVENTID, wmi_evt_rx_mgmt}, + {WMI_TX_MGMT_PACKET_EVENTID, wmi_evt_tx_mgmt}, {WMI_SCAN_COMPLETE_EVENTID, wmi_evt_scan_complete}, {WMI_CONNECT_EVENTID, wmi_evt_connect}, {WMI_DISCONNECT_EVENTID, wmi_evt_disconnect}, -- cgit v1.3-6-gb490 From a3ce5ccd50ee24313fa3e55d2cafc6da7dfcbe18 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Thu, 30 Jul 2015 13:51:58 +0300 Subject: wil6210: treat "unhandled event" as warning instead of error FW is allowed to generate WMI events that are not handled by this driver. Treat such case as warning instead of error. Signed-off-by: Dedy Lansky Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 349f14ae9944..fbcea838ccfa 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1340,7 +1340,7 @@ static void wmi_event_handle(struct wil6210_priv *wil, /* search for handler */ if (!wmi_evt_call_handler(wil, id, evt_data, len - sizeof(*wmi))) { - wil_err(wil, "Unhandled event 0x%04x\n", id); + wil_info(wil, "Unhandled event 0x%04x\n", id); } } else { wil_err(wil, "Unknown event type\n"); -- cgit v1.3-6-gb490 From cab5abbf9d0ef8b36d5f5181f0087ed3836385d0 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:51:59 +0300 Subject: wil6210: sort IEs handling sort overall IE's handling prepare code (disabled for now) to add IEs for the beacon Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 78 +++++++++++------------------ 1 file changed, 29 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index e4be2d9bbac4..8811174e51c3 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -722,46 +722,51 @@ static int wil_fix_bcon(struct wil6210_priv *wil, { struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - int rc = 0; if (bcon->probe_resp_len <= hlen) return 0; +/* always use IE's from full probe frame, they has more info + * notable RSN + */ + bcon->proberesp_ies = f->u.probe_resp.variable; + bcon->proberesp_ies_len = bcon->probe_resp_len - hlen; if (!bcon->assocresp_ies) { - bcon->assocresp_ies = f->u.probe_resp.variable; - bcon->assocresp_ies_len = bcon->probe_resp_len - hlen; - rc = 1; + bcon->assocresp_ies = bcon->proberesp_ies; + bcon->assocresp_ies_len = bcon->proberesp_ies_len; } - return rc; + return 1; } /* internal functions for device reset and starting AP */ static int _wil_cfg80211_set_ies(struct wiphy *wiphy, - size_t probe_ies_len, const u8 *probe_ies, - size_t assoc_ies_len, const u8 *assoc_ies) - + struct cfg80211_beacon_data *bcon) { int rc; struct wil6210_priv *wil = wiphy_to_wil(wiphy); - /* FW do not form regular beacon, so bcon IE's are not set - * For the DMG bcon, when it will be supported, bcon IE's will - * be reused; add something like: - * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, - * bcon->beacon_ies); - */ - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, probe_ies_len, probe_ies); + rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, + bcon->proberesp_ies); if (rc) { wil_err(wil, "set_ie(PROBE_RESP) failed\n"); return rc; } - rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, assoc_ies_len, assoc_ies); + rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, + bcon->assocresp_ies); if (rc) { wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); return rc; } +#if 0 /* to use beacon IE's, remove this #if 0 */ + rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, + bcon->tail); + if (rc) { + wil_err(wil, "set_ie(BEACON) failed\n"); + return rc; + } +#endif return 0; } @@ -770,8 +775,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, const u8 *ssid, size_t ssid_len, u32 privacy, int bi, u8 chan, - size_t probe_ies_len, const u8 *probe_ies, - size_t assoc_ies_len, const u8 *assoc_ies, + struct cfg80211_beacon_data *bcon, u8 hidden_ssid) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); @@ -792,8 +796,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, if (rc) goto out; - rc = _wil_cfg80211_set_ies(wiphy, probe_ies_len, probe_ies, - assoc_ies_len, assoc_ies); + rc = _wil_cfg80211_set_ies(wiphy, bcon); if (rc) goto out; @@ -827,27 +830,20 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, struct cfg80211_beacon_data *bcon) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); - struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; - size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - const u8 *pr_ies = NULL; - size_t pr_ies_len = 0; int rc; u32 privacy = 0; wil_dbg_misc(wil, "%s()\n", __func__); wil_print_bcon_data(bcon); - if (bcon->probe_resp_len > hlen) { - pr_ies = f->u.probe_resp.variable; - pr_ies_len = bcon->probe_resp_len - hlen; - } - if (wil_fix_bcon(wil, bcon)) { wil_dbg_misc(wil, "Fixed bcon\n"); wil_print_bcon_data(bcon); } - if (pr_ies && cfg80211_find_ie(WLAN_EID_RSN, pr_ies, pr_ies_len)) + if (bcon->proberesp_ies && + cfg80211_find_ie(WLAN_EID_RSN, bcon->proberesp_ies, + bcon->proberesp_ies_len)) privacy = 1; /* in case privacy has changed, need to restart the AP */ @@ -860,14 +856,10 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid, wdev->ssid_len, privacy, wdev->beacon_interval, - wil->channel, pr_ies_len, pr_ies, - bcon->assocresp_ies_len, - bcon->assocresp_ies, + wil->channel, bcon, wil->hidden_ssid); } else { - rc = _wil_cfg80211_set_ies(wiphy, pr_ies_len, pr_ies, - bcon->assocresp_ies_len, - bcon->assocresp_ies); + rc = _wil_cfg80211_set_ies(wiphy, bcon); } return rc; @@ -882,10 +874,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct ieee80211_channel *channel = info->chandef.chan; struct cfg80211_beacon_data *bcon = &info->beacon; struct cfg80211_crypto_settings *crypto = &info->crypto; - struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; - size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - const u8 *pr_ies = NULL; - size_t pr_ies_len = 0; u8 hidden_ssid; wil_dbg_misc(wil, "%s()\n", __func__); @@ -925,11 +913,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_print_bcon_data(bcon); wil_print_crypto(wil, crypto); - if (bcon->probe_resp_len > hlen) { - pr_ies = f->u.probe_resp.variable; - pr_ies_len = bcon->probe_resp_len - hlen; - } - if (wil_fix_bcon(wil, bcon)) { wil_dbg_misc(wil, "Fixed bcon\n"); wil_print_bcon_data(bcon); @@ -938,10 +921,7 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, rc = _wil_cfg80211_start_ap(wiphy, ndev, info->ssid, info->ssid_len, info->privacy, info->beacon_interval, channel->hw_value, - pr_ies_len, pr_ies, - bcon->assocresp_ies_len, - bcon->assocresp_ies, - hidden_ssid); + bcon, hidden_ssid); return rc; } -- cgit v1.3-6-gb490 From 5421bf0c1e37642f42758fe1c73e43b27901dd61 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:00 +0300 Subject: wil6210: unify wmi_set_ie() error handling When printing error message, provide string describing IE kind. Derive it from IE type This allows removing of error messages printing in callers Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 29 ++++++++--------------------- drivers/net/wireless/ath/wil6210/wmi.c | 19 +++++++++++++++++-- 2 files changed, 25 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 8811174e51c3..20d07ef679e8 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -336,12 +336,9 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, else wil_dbg_misc(wil, "Scan has no IE's\n"); - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, - request->ie); - if (rc) { - wil_err(wil, "Aborting scan, set_ie failed: %d\n", rc); + rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie); + if (rc) goto out; - } rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); @@ -462,10 +459,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, * ies in FW. */ rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); - if (rc) { - wil_err(wil, "WMI_SET_APPIE_CMD failed\n"); + if (rc) goto out; - } /* WMI_CONNECT_CMD */ memset(&conn, 0, sizeof(conn)); @@ -748,27 +743,19 @@ static int _wil_cfg80211_set_ies(struct wiphy *wiphy, rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, bcon->proberesp_ies); - if (rc) { - wil_err(wil, "set_ie(PROBE_RESP) failed\n"); + if (rc) return rc; - } rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, bcon->assocresp_ies); - if (rc) { - wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); - return rc; - } #if 0 /* to use beacon IE's, remove this #if 0 */ - rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, - bcon->tail); - if (rc) { - wil_err(wil, "set_ie(BEACON) failed\n"); + if (rc) return rc; - } + + rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, bcon->tail); #endif - return 0; + return rc; } static int _wil_cfg80211_start_ap(struct wiphy *wiphy, diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index fbcea838ccfa..b9cf9a68d565 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1022,12 +1022,21 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) { + static const char *const names[] = { + [WMI_FRAME_BEACON] = "BEACON", + [WMI_FRAME_PROBE_REQ] = "PROBE_REQ", + [WMI_FRAME_PROBE_RESP] = "WMI_FRAME_PROBE_RESP", + [WMI_FRAME_ASSOC_REQ] = "WMI_FRAME_ASSOC_REQ", + [WMI_FRAME_ASSOC_RESP] = "WMI_FRAME_ASSOC_RESP", + }; int rc; u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len; struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL); - if (!cmd) - return -ENOMEM; + if (!cmd) { + rc = -ENOMEM; + goto out; + } if (!ie) ie_len = 0; @@ -1037,6 +1046,12 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) memcpy(cmd->ie_info, ie, ie_len); rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len); kfree(cmd); +out: + if (rc) { + const char *name = type < ARRAY_SIZE(names) ? + names[type] : "??"; + wil_err(wil, "set_ie(%d %s) failed : %d\n", type, name, rc); + } return rc; } -- cgit v1.3-6-gb490 From 91a8edcc3173958fd8102343a8a7919a7b703ef0 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:01 +0300 Subject: wil6210: detailed statistics for Rx reorder drop Rx drops may be for 2 reasons: frame is old, or it is duplicate. On the debugfs "stations" entry, provide counters per reorder buffer for total frames processed, drops for these 2 reasons. Also add debug print for dropped frames. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 6 +++++- drivers/net/wireless/ath/wil6210/rx_reorder.c | 8 ++++++-- drivers/net/wireless/ath/wil6210/wil6210.h | 15 ++++++++------- 3 files changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 2651ec4fb620..05b550f32914 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1344,6 +1344,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) { int i; u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size; + unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old; seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout, r->head_seq_num); @@ -1353,7 +1354,10 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r) else seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_'); } - seq_printf(s, "] drop %llu last 0x%03x\n", r->drop, r->ssn_last_drop); + seq_printf(s, + "] total %llu drop %llu (dup %llu + old %llu) last 0x%03x\n", + r->total, drop_dup + drop_old, drop_dup, drop_old, + r->ssn_last_drop); } static int wil_sta_debugfs_show(struct seq_file *s, void *data) diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index e4ac11cf0f50..9238c1ac23dd 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -121,6 +121,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) goto out; } + r->total++; hseq = r->head_seq_num; /** Due to the race between WMI events, where BACK establishment @@ -153,7 +154,9 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) /* frame with out of date sequence number */ if (seq_less(seq, r->head_seq_num)) { r->ssn_last_drop = seq; - r->drop++; + r->drop_old++; + wil_dbg_txrx(wil, "Rx drop: old seq 0x%03x head 0x%03x\n", + seq, r->head_seq_num); dev_kfree_skb(skb); goto out; } @@ -174,7 +177,8 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) /* check if we already stored this frame */ if (r->reorder_buf[index]) { - r->drop++; + r->drop_dup++; + wil_dbg_txrx(wil, "Rx drop: dup seq 0x%03x\n", seq); dev_kfree_skb(skb); goto out; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 54f16732d226..c72272449652 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -424,13 +424,12 @@ struct pci_dev; * @ssn: Starting Sequence Number expected to be aggregated. * @buf_size: buffer size for incoming A-MPDUs * @timeout: reset timer value (in TUs). + * @ssn_last_drop: SSN of the last dropped frame + * @total: total number of processed incoming frames + * @drop_dup: duplicate frames dropped for this reorder buffer + * @drop_old: old frames dropped for this reorder buffer * @dialog_token: dialog token for aggregation session - * @rcu_head: RCU head used for freeing this struct - * @drop: total frames dropped for this reorder buffer - * - * This structure's lifetime is managed by RCU, assignments to - * the array holding it must hold the aggregation mutex. - * + * @first_time: true when this buffer used 1-st time */ struct wil_tid_ampdu_rx { struct sk_buff **reorder_buf; @@ -444,7 +443,9 @@ struct wil_tid_ampdu_rx { u16 buf_size; u16 timeout; u16 ssn_last_drop; - unsigned long long drop; + unsigned long long total; /* frames processed */ + unsigned long long drop_dup; + unsigned long long drop_old; u8 dialog_token; bool first_time; /* is it 1-st time this buffer used? */ }; -- cgit v1.3-6-gb490 From bd2d18b50631c027af7674c3f328913c3b87d422 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:02 +0300 Subject: wil6210: remove 3-MSI support In the recent kernel versions, multiple MSI is not well supported. In particular, it is not supported on x86 and ARM architectures. Also, internal interrupt handling logic is simpler and more effective when using single interrupt. Remove support for 3 MSI, convert module parameter "use_msi" from int with range [0,1,3] to boolean. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/interrupt.c | 55 +++------------------------ drivers/net/wireless/ath/wil6210/pcie_bus.c | 56 ++++++---------------------- drivers/net/wireless/ath/wil6210/wil6210.h | 3 +- 3 files changed, 18 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 28ffc18466c4..596d09b8c60a 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -541,42 +541,6 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) return rc; } -static int wil6210_request_3msi(struct wil6210_priv *wil, int irq) -{ - int rc; - /* - * IRQ's are in the following order: - * - Tx - * - Rx - * - Misc - */ - - rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED, - WIL_NAME"_tx", wil); - if (rc) - return rc; - - rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED, - WIL_NAME"_rx", wil); - if (rc) - goto free0; - - rc = request_threaded_irq(irq + 2, wil6210_irq_misc, - wil6210_irq_misc_thread, - IRQF_SHARED, WIL_NAME"_misc", wil); - if (rc) - goto free1; - - return 0; - /* error branch */ -free1: - free_irq(irq + 1, wil); -free0: - free_irq(irq, wil); - - return rc; -} - /* can't use wil_ioread32_and_clear because ICC value is not set yet */ static inline void wil_clear32(void __iomem *addr) { @@ -596,19 +560,16 @@ void wil6210_clear_irq(struct wil6210_priv *wil) wmb(); /* make sure write completed */ } -int wil6210_init_irq(struct wil6210_priv *wil, int irq) +int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi) { int rc; - wil_dbg_misc(wil, "%s() n_msi=%d\n", __func__, wil->n_msi); + wil_dbg_misc(wil, "%s(%s)\n", __func__, use_msi ? "MSI" : "INTx"); - if (wil->n_msi == 3) - rc = wil6210_request_3msi(wil, irq); - else - rc = request_threaded_irq(irq, wil6210_hardirq, - wil6210_thread_irq, - wil->n_msi ? 0 : IRQF_SHARED, - WIL_NAME, wil); + rc = request_threaded_irq(irq, wil6210_hardirq, + wil6210_thread_irq, + use_msi ? 0 : IRQF_SHARED, + WIL_NAME, wil); return rc; } @@ -618,8 +579,4 @@ void wil6210_fini_irq(struct wil6210_priv *wil, int irq) wil_mask_irq(wil); free_irq(irq, wil); - if (wil->n_msi == 3) { - free_irq(irq + 1, wil); - free_irq(irq + 2, wil); - } } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index aa3ecc607ca3..d065b796d67e 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -21,11 +21,9 @@ #include "wil6210.h" -static int use_msi = 1; -module_param(use_msi, int, S_IRUGO); -MODULE_PARM_DESC(use_msi, - " Use MSI interrupt: " - "0 - don't, 1 - (default) - single, or 3"); +static bool use_msi = true; +module_param(use_msi, bool, S_IRUGO); +MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true"); static void wil_set_capabilities(struct wil6210_priv *wil) @@ -50,24 +48,12 @@ void wil_set_capabilities(struct wil6210_priv *wil) void wil_disable_irq(struct wil6210_priv *wil) { - int irq = wil->pdev->irq; - - disable_irq(irq); - if (wil->n_msi == 3) { - disable_irq(irq + 1); - disable_irq(irq + 2); - } + disable_irq(wil->pdev->irq); } void wil_enable_irq(struct wil6210_priv *wil) { - int irq = wil->pdev->irq; - - enable_irq(irq); - if (wil->n_msi == 3) { - enable_irq(irq + 1); - enable_irq(irq + 2); - } + enable_irq(wil->pdev->irq); } /* Bus ops */ @@ -80,6 +66,7 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) * and only MSI should be used */ int msi_only = pdev->msi_enabled; + bool _use_msi = use_msi; wil_dbg_misc(wil, "%s()\n", __func__); @@ -87,41 +74,20 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) pci_set_master(pdev); - /* - * how many MSI interrupts to request? - */ - switch (use_msi) { - case 3: - case 1: - wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); - break; - case 0: - wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); - break; - default: - wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi); - use_msi = 1; - } - - if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) { - wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); - use_msi = 1; - } + wil_dbg_misc(wil, "Setup %s interrupt\n", use_msi ? "MSI" : "INTx"); - if (use_msi == 1 && pci_enable_msi(pdev)) { + if (use_msi && pci_enable_msi(pdev)) { wil_err(wil, "pci_enable_msi failed, use INTx\n"); - use_msi = 0; + _use_msi = false; } - wil->n_msi = use_msi; - - if ((wil->n_msi == 0) && msi_only) { + if (!_use_msi && msi_only) { wil_err(wil, "Interrupt pin not routed, unable to use INTx\n"); rc = -ENODEV; goto stop_master; } - rc = wil6210_init_irq(wil, pdev->irq); + rc = wil6210_init_irq(wil, pdev->irq, _use_msi); if (rc) goto stop_master; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c72272449652..3c22178f6729 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -536,7 +536,6 @@ struct pmc_ctx { struct wil6210_priv { struct pci_dev *pdev; - int n_msi; struct wireless_dev *wdev; void __iomem *csr; DECLARE_BITMAP(status, wil_status_last); @@ -739,7 +738,7 @@ void wil_back_tx_worker(struct work_struct *work); void wil_back_tx_flush(struct wil6210_priv *wil); void wil6210_clear_irq(struct wil6210_priv *wil); -int wil6210_init_irq(struct wil6210_priv *wil, int irq); +int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi); void wil6210_fini_irq(struct wil6210_priv *wil, int irq); void wil_mask_irq(struct wil6210_priv *wil); void wil_unmask_irq(struct wil6210_priv *wil); -- cgit v1.3-6-gb490 From b9eeb512496f1b1b5a6e0748c947277d95003af5 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:03 +0300 Subject: wil6210: use inline functions for register access Replace macros like "R", "W", "S", "C", defined multiple times, with inline functions "wil_[rwsc]". Use "readl" and "writel" instead of "ioread32" and "iowrite32" since it is granted that memory transactions are used, not port ones like IN/OUT Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/debugfs.c | 8 +- drivers/net/wireless/ath/wil6210/ethtool.c | 14 +--- drivers/net/wireless/ath/wil6210/fw.c | 10 --- drivers/net/wireless/ath/wil6210/fw_inc.c | 16 ++-- drivers/net/wireless/ath/wil6210/interrupt.c | 110 ++++++++++++--------------- drivers/net/wireless/ath/wil6210/ioctl.c | 4 +- drivers/net/wireless/ath/wil6210/main.c | 94 ++++++++++------------- drivers/net/wireless/ath/wil6210/pcie_bus.c | 2 +- drivers/net/wireless/ath/wil6210/txrx.c | 6 +- drivers/net/wireless/ath/wil6210/wil6210.h | 31 +++++++- drivers/net/wireless/ath/wil6210/wmi.c | 26 +++---- 11 files changed, 151 insertions(+), 170 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 05b550f32914..613ca2b2527b 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -62,7 +62,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil, seq_printf(s, " swhead = %d\n", vring->swhead); seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail); if (x) { - v = ioread32(x); + v = readl(x); seq_printf(s, "0x%08x = %d\n", v, v); } else { seq_puts(s, "???\n"); @@ -268,7 +268,7 @@ static const struct file_operations fops_mbox = { static int wil_debugfs_iomem_x32_set(void *data, u64 val) { - iowrite32(val, (void __iomem *)data); + writel(val, (void __iomem *)data); wmb(); /* make sure write propagated to HW */ return 0; @@ -276,7 +276,7 @@ static int wil_debugfs_iomem_x32_set(void *data, u64 val) static int wil_debugfs_iomem_x32_get(void *data, u64 *val) { - *val = ioread32((void __iomem *)data); + *val = readl((void __iomem *)data); return 0; } @@ -477,7 +477,7 @@ static int wil_memread_debugfs_show(struct seq_file *s, void *data) void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr)); if (a) - seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a)); + seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a)); else seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index 0ea695ff98ad..7053b62ca8d3 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -50,19 +50,13 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev, wil_dbg_misc(wil, "%s()\n", __func__); - tx_itr_en = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL)); + tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL); if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) - tx_itr_val = - ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH)); + tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH); - rx_itr_en = ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL)); + rx_itr_en = wil_r(wil, RGF_DMA_ITR_RX_CNT_CTL); if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) - rx_itr_val = - ioread32(wil->csr + - HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH)); + rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH); cp->tx_coalesce_usecs = tx_itr_val; cp->rx_coalesce_usecs = rx_itr_val; diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c index 4428345e5a47..82aae2d705b4 100644 --- a/drivers/net/wireless/ath/wil6210/fw.c +++ b/drivers/net/wireless/ath/wil6210/fw.c @@ -22,16 +22,6 @@ MODULE_FIRMWARE(WIL_FW_NAME); MODULE_FIRMWARE(WIL_FW2_NAME); -/* target operations */ -/* register read */ -#define R(a) ioread32(wil->csr + HOSTADDR(a)) -/* register write. wmb() to make sure it is completed */ -#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) -/* register set = read, OR, write */ -#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) - static void wil_memset_toio_32(volatile void __iomem *dst, u32 val, size_t count) diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index 157f5ef384e0..d30657ee7e83 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -221,12 +221,12 @@ static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data, FW_ADDR_CHECK(dst, block[i].addr, "address"); - x = ioread32(dst); + x = readl(dst); y = (x & m) | (v & ~m); wil_dbg_fw(wil, "write [0x%08x] <== 0x%08x " "(old 0x%08x val 0x%08x mask 0x%08x)\n", le32_to_cpu(block[i].addr), y, x, v, m); - iowrite32(y, dst); + writel(y, dst); wmb(); /* finish before processing next record */ } @@ -239,18 +239,18 @@ static int gw_write(struct wil6210_priv *wil, void __iomem *gwa_addr, { unsigned delay = 0; - iowrite32(a, gwa_addr); - iowrite32(gw_cmd, gwa_cmd); + writel(a, gwa_addr); + writel(gw_cmd, gwa_cmd); wmb(); /* finish before activate gw */ - iowrite32(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */ + writel(WIL_FW_GW_CTL_RUN, gwa_ctl); /* activate gw */ do { udelay(1); /* typical time is few usec */ if (delay++ > 100) { wil_err_fw(wil, "gw timeout\n"); return -EINVAL; } - } while (ioread32(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */ + } while (readl(gwa_ctl) & WIL_FW_GW_CTL_BUSY); /* gw done? */ return 0; } @@ -305,7 +305,7 @@ static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data, wil_dbg_fw(wil, " gw write[%3d] [0x%08x] <== 0x%08x\n", i, a, v); - iowrite32(v, gwa_val); + writel(v, gwa_val); rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a); if (rc) return rc; @@ -372,7 +372,7 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data, sizeof(v), false); for (k = 0; k < ARRAY_SIZE(block->value); k++) - iowrite32(v[k], gwa_val[k]); + writel(v[k], gwa_val[k]); rc = gw_write(wil, gwa_addr, gwa_cmd, gwa_ctl, gw_cmd, a); if (rc) return rc; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 596d09b8c60a..a371f036d054 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -61,13 +61,13 @@ static inline void wil_icr_clear(u32 x, void __iomem *addr) static inline void wil_icr_clear(u32 x, void __iomem *addr) { - iowrite32(x, addr); + writel(x, addr); } #endif /* defined(CONFIG_WIL6210_ISR_COR) */ static inline u32 wil_ioread32_and_clear(void __iomem *addr) { - u32 x = ioread32(addr); + u32 x = readl(addr); wil_icr_clear(x, addr); @@ -76,54 +76,47 @@ static inline u32 wil_ioread32_and_clear(void __iomem *addr) static void wil6210_mask_irq_tx(struct wil6210_priv *wil) { - iowrite32(WIL6210_IRQ_DISABLE, wil->csr + - HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, IMS)); + wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMS), + WIL6210_IRQ_DISABLE); } static void wil6210_mask_irq_rx(struct wil6210_priv *wil) { - iowrite32(WIL6210_IRQ_DISABLE, wil->csr + - HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, IMS)); + wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMS), + WIL6210_IRQ_DISABLE); } static void wil6210_mask_irq_misc(struct wil6210_priv *wil) { - iowrite32(WIL6210_IRQ_DISABLE, wil->csr + - HOSTADDR(RGF_DMA_EP_MISC_ICR) + - offsetof(struct RGF_ICR, IMS)); + wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMS), + WIL6210_IRQ_DISABLE); } static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); - iowrite32(WIL6210_IRQ_DISABLE, wil->csr + - HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); + wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_DISABLE); clear_bit(wil_status_irqen, wil->status); } void wil6210_unmask_irq_tx(struct wil6210_priv *wil) { - iowrite32(WIL6210_IMC_TX, wil->csr + - HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, IMC)); + wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, IMC), + WIL6210_IMC_TX); } void wil6210_unmask_irq_rx(struct wil6210_priv *wil) { - iowrite32(WIL6210_IMC_RX, wil->csr + - HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, IMC)); + wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC), + WIL6210_IMC_RX); } static void wil6210_unmask_irq_misc(struct wil6210_priv *wil) { - iowrite32(WIL6210_IMC_MISC, wil->csr + - HOSTADDR(RGF_DMA_EP_MISC_ICR) + - offsetof(struct RGF_ICR, IMC)); + wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, IMC), + WIL6210_IMC_MISC); } static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) @@ -132,8 +125,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil) set_bit(wil_status_irqen, wil->status); - iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr + - HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW)); + wil_w(wil, RGF_DMA_PSEUDO_CAUSE_MASK_SW, WIL6210_IRQ_PSEUDO_MASK); } void wil_mask_irq(struct wil6210_priv *wil) @@ -150,12 +142,12 @@ void wil_unmask_irq(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); - iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, ICC)); - iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, ICC)); - iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + - offsetof(struct RGF_ICR, ICC)); + wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); + wil_w(wil, RGF_DMA_EP_TX_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); + wil_w(wil, RGF_DMA_EP_MISC_ICR + offsetof(struct RGF_ICR, ICC), + WIL_ICR_ICC_VALUE); wil6210_unmask_irq_pseudo(wil); wil6210_unmask_irq_tx(wil); @@ -163,9 +155,6 @@ void wil_unmask_irq(struct wil6210_priv *wil) wil6210_unmask_irq_misc(wil); } -/* target write operation */ -#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) - void wil_configure_interrupt_moderation(struct wil6210_priv *wil) { wil_dbg_irq(wil, "%s()\n", __func__); @@ -177,44 +166,42 @@ void wil_configure_interrupt_moderation(struct wil6210_priv *wil) return; /* Disable and clear tx counter before (re)configuration */ - W(RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR); - W(RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration); + wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR); + wil_w(wil, RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration); wil_info(wil, "set ITR_TX_CNT_TRSH = %d usec\n", wil->tx_max_burst_duration); /* Configure TX max burst duration timer to use usec units */ - W(RGF_DMA_ITR_TX_CNT_CTL, - BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL); + wil_w(wil, RGF_DMA_ITR_TX_CNT_CTL, + BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL); /* Disable and clear tx idle counter before (re)configuration */ - W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR); - W(RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout); + wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR); + wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout); wil_info(wil, "set ITR_TX_IDL_CNT_TRSH = %d usec\n", wil->tx_interframe_timeout); /* Configure TX max burst duration timer to use usec units */ - W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN | - BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL); + wil_w(wil, RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN | + BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL); /* Disable and clear rx counter before (re)configuration */ - W(RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR); - W(RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration); + wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR); + wil_w(wil, RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration); wil_info(wil, "set ITR_RX_CNT_TRSH = %d usec\n", wil->rx_max_burst_duration); /* Configure TX max burst duration timer to use usec units */ - W(RGF_DMA_ITR_RX_CNT_CTL, - BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL); + wil_w(wil, RGF_DMA_ITR_RX_CNT_CTL, + BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL); /* Disable and clear rx idle counter before (re)configuration */ - W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR); - W(RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout); + wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR); + wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout); wil_info(wil, "set ITR_RX_IDL_CNT_TRSH = %d usec\n", wil->rx_interframe_timeout); /* Configure TX max burst duration timer to use usec units */ - W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN | - BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL); + wil_w(wil, RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN | + BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL); } -#undef W - static irqreturn_t wil6210_irq_rx(int irq, void *cookie) { struct wil6210_priv *wil = cookie; @@ -452,27 +439,24 @@ static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause) u32 icr_rx = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) + offsetof(struct RGF_ICR, ICR)); - u32 imv_rx = ioread32(wil->csr + - HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, IMV)); + u32 imv_rx = wil_r(wil, RGF_DMA_EP_RX_ICR + + offsetof(struct RGF_ICR, IMV)); u32 icm_tx = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + offsetof(struct RGF_ICR, ICM)); u32 icr_tx = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) + offsetof(struct RGF_ICR, ICR)); - u32 imv_tx = ioread32(wil->csr + - HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, IMV)); + u32 imv_tx = wil_r(wil, RGF_DMA_EP_TX_ICR + + offsetof(struct RGF_ICR, IMV)); u32 icm_misc = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICM)); u32 icr_misc = wil_ioread32_and_clear(wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICR)); - u32 imv_misc = ioread32(wil->csr + - HOSTADDR(RGF_DMA_EP_MISC_ICR) + - offsetof(struct RGF_ICR, IMV)); + u32 imv_misc = wil_r(wil, RGF_DMA_EP_MISC_ICR + + offsetof(struct RGF_ICR, IMV)); wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n" "Rx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" "Tx icm:icr:imv 0x%08x 0x%08x 0x%08x\n" @@ -492,7 +476,7 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) { irqreturn_t rc = IRQ_HANDLED; struct wil6210_priv *wil = cookie; - u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE)); + u32 pseudo_cause = wil_r(wil, RGF_DMA_PSEUDO_CAUSE); /** * pseudo_cause is Clear-On-Read, no need to ACK @@ -544,9 +528,9 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie) /* can't use wil_ioread32_and_clear because ICC value is not set yet */ static inline void wil_clear32(void __iomem *addr) { - u32 x = ioread32(addr); + u32 x = readl(addr); - iowrite32(x, addr); + writel(x, addr); } void wil6210_clear_irq(struct wil6210_priv *wil) diff --git a/drivers/net/wireless/ath/wil6210/ioctl.c b/drivers/net/wireless/ath/wil6210/ioctl.c index e9c0673819c6..f7f948621951 100644 --- a/drivers/net/wireless/ath/wil6210/ioctl.c +++ b/drivers/net/wireless/ath/wil6210/ioctl.c @@ -76,11 +76,11 @@ static int wil_ioc_memio_dword(struct wil6210_priv *wil, void __user *data) /* operation */ switch (io.op & wil_mmio_op_mask) { case wil_mmio_read: - io.val = ioread32(a); + io.val = readl(a); need_copy = true; break; case wil_mmio_write: - iowrite32(io.val, a); + writel(io.val, a); wmb(); /* make sure write propagated to HW */ break; default: diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 33a3e9b136d9..44223236a629 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -528,26 +528,16 @@ void wil_priv_deinit(struct wil6210_priv *wil) destroy_workqueue(wil->wmi_wq); } -/* target operations */ -/* register read */ -#define R(a) ioread32(wil->csr + HOSTADDR(a)) -/* register write. wmb() to make sure it is completed */ -#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0) -/* register set = read, OR, write */ -#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) - static inline void wil_halt_cpu(struct wil6210_priv *wil) { - W(RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST); - W(RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST); + wil_w(wil, RGF_USER_USER_CPU_0, BIT_USER_USER_CPU_MAN_RST); + wil_w(wil, RGF_USER_MAC_CPU_0, BIT_USER_MAC_CPU_MAN_RST); } static inline void wil_release_cpu(struct wil6210_priv *wil) { /* Start CPU */ - W(RGF_USER_USER_CPU_0, 1); + wil_w(wil, RGF_USER_USER_CPU_0, 1); } static int wil_target_reset(struct wil6210_priv *wil) @@ -558,58 +548,60 @@ static int wil_target_reset(struct wil6210_priv *wil) wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name); /* Clear MAC link up */ - S(RGF_HP_CTRL, BIT(15)); - S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD); - S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST); + wil_s(wil, RGF_HP_CTRL, BIT(15)); + wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_HPAL_PERST_FROM_PAD); + wil_s(wil, RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST); wil_halt_cpu(wil); /* clear all boot loader "ready" bits */ - W(RGF_USER_BL + - offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); + wil_w(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0); /* Clear Fw Download notification */ - C(RGF_USER_USAGE_6, BIT(0)); + wil_c(wil, RGF_USER_USAGE_6, BIT(0)); - S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); + wil_s(wil, RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); /* XTAL stabilization should take about 3ms */ usleep_range(5000, 7000); - x = R(RGF_CAF_PLL_LOCK_STATUS); + x = wil_r(wil, RGF_CAF_PLL_LOCK_STATUS); if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { wil_err(wil, "Xtal stabilization timeout\n" "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); return -ETIME; } /* switch 10k to XTAL*/ - C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); + wil_c(wil, RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); /* 40 MHz */ - C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); + wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); + wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); + wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); - 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, 0x000000f0); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x000000f0); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); - W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); + wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0); + wil_w(wil, RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0); - 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); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); /* reset A2 PCIE AHB */ + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003); + /* reset A2 PCIE AHB */ + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000); - W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); + wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0); /* wait until device ready. typical time is 20..80 msec */ do { msleep(RST_DELAY); - x = R(RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, - boot_loader_ready)); + x = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, + boot_loader_ready)); if (x1 != x) { wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x); x1 = x; @@ -621,11 +613,11 @@ static int wil_target_reset(struct wil6210_priv *wil) } } while (x != BL_READY); - C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); + wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD); /* enable fix for HW bug related to the SA/DA swap in AP Rx */ - S(RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | - BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); + wil_s(wil, RGF_DMA_OFUL_NID_0, BIT_DMA_OFUL_NID_0_RX_EXT_TR_EN | + BIT_DMA_OFUL_NID_0_RX_EXT_A3_SRC); wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY); return 0; @@ -651,8 +643,9 @@ static int wil_get_bl_info(struct wil6210_priv *wil) u8 *mac; u16 rf_status; - bl_ver = R(RGF_USER_BL + offsetof(struct bl_dedicated_registers_v0, - boot_loader_struct_version)); + bl_ver = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, + boot_loader_struct_version)); switch (bl_ver) { case 0: wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), @@ -802,7 +795,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; /* Mark FW as loaded from host */ - S(RGF_USER_USAGE_6, 1); + wil_s(wil, RGF_USER_USAGE_6, 1); /* clear any interrupts which on-card-firmware * may have set @@ -810,8 +803,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) wil6210_clear_irq(wil); /* CAF_ICR - clear and mask */ /* it is W1C, clear by writing back same value */ - S(RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); - W(RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); + wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); + wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); wil_release_cpu(wil); } @@ -835,11 +828,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } -#undef R -#undef W -#undef S -#undef C - void wil_fw_error_recovery(struct wil6210_priv *wil) { wil_dbg_misc(wil, "starting fw error recovery\n"); diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index d065b796d67e..c37838dfe38a 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -28,7 +28,7 @@ MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true"); static void wil_set_capabilities(struct wil6210_priv *wil) { - u32 rev_id = ioread32(wil->csr + HOSTADDR(RGF_USER_JTAG_DEV_ID)); + u32 rev_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); bitmap_zero(wil->hw_capabilities, hw_capability_last); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 7722df78b267..359121f18674 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -509,7 +509,7 @@ static int wil_rx_refill(struct wil6210_priv *wil, int count) break; } } - iowrite32(v->swtail, wil->csr + HOSTADDR(v->hwtail)); + wil_w(wil, v->hwtail, v->swtail); return rc; } @@ -1422,7 +1422,7 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring, */ wmb(); - iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); + wil_w(wil, vring->hwtail, vring->swhead); return 0; dma_error: @@ -1565,7 +1565,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, */ wmb(); - iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail)); + wil_w(wil, vring->hwtail, vring->swhead); return 0; dma_error: diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 3c22178f6729..c6b0fa26c403 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -252,9 +252,8 @@ enum { }; /* popular locations */ -#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) -#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \ - offsetof(struct RGF_ICR, ICS)) +#define RGF_MBOX RGF_USER_USER_SCRATCH_PAD +#define HOST_MBOX HOSTADDR(RGF_MBOX) #define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2 /* ISR register bits */ @@ -649,6 +648,32 @@ void wil_info(struct wil6210_priv *wil, const char *fmt, ...); #define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) #define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg) +/* target operations */ +/* register read */ +static inline u32 wil_r(struct wil6210_priv *wil, u32 reg) +{ + return readl(wil->csr + HOSTADDR(reg)); +} + +/* register write. wmb() to make sure it is completed */ +static inline void wil_w(struct wil6210_priv *wil, u32 reg, u32 val) +{ + writel(val, wil->csr + HOSTADDR(reg)); + wmb(); /* wait for write to propagate to the HW */ +} + +/* register set = read, OR, write */ +static inline void wil_s(struct wil6210_priv *wil, u32 reg, u32 val) +{ + wil_w(wil, reg, wil_r(wil, reg) | val); +} + +/* register clear = read, AND with inverted, write */ +static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val) +{ + wil_w(wil, reg, wil_r(wil, reg) & ~val); +} + #if defined(CONFIG_DYNAMIC_DEBUG) #define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) \ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index b9cf9a68d565..7a257360c420 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -228,8 +228,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head); /* wait till FW finish with previous command */ for (retry = 5; retry > 0; retry--) { - r->tail = ioread32(wil->csr + HOST_MBOX + - offsetof(struct wil6210_mbox_ctl, tx.tail)); + r->tail = wil_r(wil, RGF_MBOX + + offsetof(struct wil6210_mbox_ctl, tx.tail)); if (next_head != r->tail) break; msleep(20); @@ -254,16 +254,16 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) wil_memcpy_toio_32(dst, &cmd, sizeof(cmd)); wil_memcpy_toio_32(dst + sizeof(cmd), buf, len); /* mark entry as full */ - iowrite32(1, wil->csr + HOSTADDR(r->head) + - offsetof(struct wil6210_mbox_ring_desc, sync)); + wil_w(wil, r->head + offsetof(struct wil6210_mbox_ring_desc, sync), 1); /* advance next ptr */ - iowrite32(r->head = next_head, wil->csr + HOST_MBOX + - offsetof(struct wil6210_mbox_ctl, tx.head)); + wil_w(wil, RGF_MBOX + offsetof(struct wil6210_mbox_ctl, tx.head), + r->head = next_head); trace_wil6210_wmi_cmd(&cmd.wmi, buf, len); /* interrupt to FW */ - iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT); + wil_w(wil, RGF_USER_USER_ICR + offsetof(struct RGF_ICR, ICS), + SW_INT_MBOX); return 0; } @@ -729,8 +729,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil) u16 len; bool q; - r->head = ioread32(wil->csr + HOST_MBOX + - offsetof(struct wil6210_mbox_ctl, rx.head)); + r->head = wil_r(wil, RGF_MBOX + + offsetof(struct wil6210_mbox_ctl, rx.head)); if (r->tail == r->head) break; @@ -768,8 +768,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil) cmd = (void *)&evt->event.wmi; wil_memcpy_fromio_32(cmd, src, len); /* mark entry as empty */ - iowrite32(0, wil->csr + HOSTADDR(r->tail) + - offsetof(struct wil6210_mbox_ring_desc, sync)); + wil_w(wil, r->tail + + offsetof(struct wil6210_mbox_ring_desc, sync), 0); /* indicate */ if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) && (len >= sizeof(struct wil6210_mbox_hdr_wmi))) { @@ -788,8 +788,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil) /* advance tail */ r->tail = r->base + ((r->tail - r->base + sizeof(struct wil6210_mbox_ring_desc)) % r->size); - iowrite32(r->tail, wil->csr + HOST_MBOX + - offsetof(struct wil6210_mbox_ctl, rx.tail)); + wil_w(wil, RGF_MBOX + + offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail); /* add to the pending list */ spin_lock_irqsave(&wil->wmi_ev_lock, flags); -- cgit v1.3-6-gb490 From 0553640d28baf77cf0fb91c8a834059f0b9be972 Mon Sep 17 00:00:00 2001 From: Vladimir Shulman Date: Thu, 30 Jul 2015 13:52:04 +0300 Subject: wil6210: allow to handle Rx on 2 cores Allow network stack part of Rx processing to run on separate core, relaxing CPU utilization on the core used for Rx NAPI. If RXHASH feature is enabled, the driver sets rxhash of each skb to 1 to enable RPS. The core for processing the rx skb is determined by RPS mechanism according to rx_cpus bit mask which is configured at user level. For processing skbs on different core from the core which processes the interrupts, it is recommended not to enable core 0 in rx_cpus bit mask. Signed-off-by: Vladimir Shulman Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/netdev.c | 3 ++- drivers/net/wireless/ath/wil6210/txrx.c | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 25c51167adff..e3b3c8fb4605 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -174,7 +174,8 @@ void *wil_if_alloc(struct device *dev) ndev->ieee80211_ptr = wdev; ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GRO | - NETIF_F_TSO | NETIF_F_TSO6; + NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_RXHASH; ndev->features |= ndev->hw_features; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 359121f18674..6229110d558a 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -541,6 +541,14 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) [GRO_DROP] = "GRO_DROP", }; + if (ndev->features & NETIF_F_RXHASH) + /* fake L4 to ensure it won't be re-calculated later + * set hash to any non-zero value to activate rps + * mechanism, core will be chosen according + * to user-level rps configuration. + */ + skb_set_hash(skb, 1, PKT_HASH_TYPE_L4); + skb_orphan(skb); if (wdev->iftype == NL80211_IFTYPE_AP && !wil->ap_isolate) { -- cgit v1.3-6-gb490 From 93cb679a768bb526a60a9c4ce30beb45465334be Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:05 +0300 Subject: wil6210: system power management Support for the system suspend/resume. In preparation for the run-time PM, implementation made run-time PM friendly: common for system and run-time PM code factored out as generic functions, albeit is_runtime parameter value is always false currently. For debug purposes, "PM" debug category introduced. Policy: AP-like interface can't be suspended; otherwise suspend is allowed. Hardware brought down if interface was up. Connection, if existed, get lost. Interface will be brought up upon resume if it was up before suspend. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/Makefile | 1 + drivers/net/wireless/ath/wil6210/pcie_bus.c | 69 ++++++++++++++++++++ drivers/net/wireless/ath/wil6210/pm.c | 98 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 5 ++ 4 files changed, 173 insertions(+) create mode 100644 drivers/net/wireless/ath/wil6210/pm.c (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 050506f842e9..64b432625fbb 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -12,6 +12,7 @@ wil6210-y += debug.o wil6210-y += rx_reorder.o wil6210-y += ioctl.o wil6210-y += fw.o +wil6210-y += pm.o wil6210-y += pmc.o wil6210-$(CONFIG_WIL6210_TRACING) += trace.o wil6210-y += wil_platform.o diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index c37838dfe38a..feff1ef10fb3 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -259,11 +259,80 @@ static const struct pci_device_id wil6210_pcie_ids[] = { }; MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); +#ifdef CONFIG_PM + +static int wil6210_suspend(struct device *dev, bool is_runtime) +{ + int rc = 0; + struct pci_dev *pdev = to_pci_dev(dev); + struct wil6210_priv *wil = pci_get_drvdata(pdev); + + wil_dbg_pm(wil, "%s(%s)\n", __func__, + is_runtime ? "runtime" : "system"); + + rc = wil_can_suspend(wil, is_runtime); + if (rc) + goto out; + + rc = wil_suspend(wil, is_runtime); + if (rc) + goto out; + + /* TODO: how do I bring card in low power state? */ + + /* disable bus mastering */ + pci_clear_master(pdev); + /* PCI will call pci_save_state(pdev) and pci_prepare_to_sleep(pdev) */ + +out: + return rc; +} + +static int wil6210_resume(struct device *dev, bool is_runtime) +{ + int rc = 0; + struct pci_dev *pdev = to_pci_dev(dev); + struct wil6210_priv *wil = pci_get_drvdata(pdev); + + wil_dbg_pm(wil, "%s(%s)\n", __func__, + is_runtime ? "runtime" : "system"); + + /* allow master */ + pci_set_master(pdev); + + rc = wil_resume(wil, is_runtime); + if (rc) + pci_clear_master(pdev); + + return rc; +} + +#ifdef CONFIG_PM_SLEEP +static int wil6210_pm_suspend(struct device *dev) +{ + return wil6210_suspend(dev, false); +} + +static int wil6210_pm_resume(struct device *dev) +{ + return wil6210_resume(dev, false); +} +#endif /* CONFIG_PM_SLEEP */ + +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops wil6210_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume) +}; + static struct pci_driver wil6210_driver = { .probe = wil_pcie_probe, .remove = wil_pcie_remove, .id_table = wil6210_pcie_ids, .name = WIL_NAME, + .driver = { + .pm = &wil6210_pm_ops, + }, }; static int __init wil6210_driver_init(void) diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c new file mode 100644 index 000000000000..0b7ecbcac19c --- /dev/null +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014 Qualcomm Atheros, 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 "wil6210.h" + +int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) +{ + int rc = 0; + struct wireless_dev *wdev = wil->wdev; + + wil_dbg_pm(wil, "%s(%s)\n", __func__, + is_runtime ? "runtime" : "system"); + + switch (wdev->iftype) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + break; + /* AP-like interface - can't suspend */ + default: + wil_dbg_pm(wil, "AP-like interface\n"); + rc = -EBUSY; + break; + } + + wil_dbg_pm(wil, "%s(%s) => %s (%d)\n", __func__, + is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc); + + return rc; +} + +int wil_suspend(struct wil6210_priv *wil, bool is_runtime) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + + wil_dbg_pm(wil, "%s(%s)\n", __func__, + is_runtime ? "runtime" : "system"); + + /* if netif up, hardware is alive, shut it down */ + if (ndev->flags & IFF_UP) { + rc = wil_down(wil); + if (rc) { + wil_err(wil, "wil_down : %d\n", rc); + goto out; + } + } + + if (wil->platform_ops.suspend) + rc = wil->platform_ops.suspend(wil->platform_handle); + +out: + wil_dbg_pm(wil, "%s(%s) => %d\n", __func__, + is_runtime ? "runtime" : "system", rc); + return rc; +} + +int wil_resume(struct wil6210_priv *wil, bool is_runtime) +{ + int rc = 0; + struct net_device *ndev = wil_to_ndev(wil); + + wil_dbg_pm(wil, "%s(%s)\n", __func__, + is_runtime ? "runtime" : "system"); + + if (wil->platform_ops.resume) { + rc = wil->platform_ops.resume(wil->platform_handle); + if (rc) { + wil_err(wil, "platform_ops.resume : %d\n", rc); + goto out; + } + } + + /* if netif up, bring hardware up + * During open(), IFF_UP set after actual device method + * invocation. This prevent recursive call to wil_up() + */ + if (ndev->flags & IFF_UP) + rc = wil_up(wil); + +out: + wil_dbg_pm(wil, "%s(%s) => %d\n", __func__, + is_runtime ? "runtime" : "system", rc); + return rc; +} diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c6b0fa26c403..dd4ea926b8e3 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -647,6 +647,7 @@ void wil_info(struct wil6210_priv *wil, const char *fmt, ...); #define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg) #define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg) #define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg) +#define wil_dbg_pm(wil, fmt, arg...) wil_dbg(wil, "DBG[ PM ]" fmt, ##arg) /* target operations */ /* register read */ @@ -815,4 +816,8 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type); int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd); int wil_request_firmware(struct wil6210_priv *wil, const char *name); +int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime); +int wil_suspend(struct wil6210_priv *wil, bool is_runtime); +int wil_resume(struct wil6210_priv *wil, bool is_runtime); + #endif /* __WIL6210_H__ */ -- cgit v1.3-6-gb490 From 409ead544d747a5e80fdd3626a7fd75d6990a2fb Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:06 +0300 Subject: wil6210: report boot loader error Boot loader reports error starting from the struct v2. Print error info before reset (power up state) in debug mode, and print same info as error if target reset timed out. Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/boot_loader.h | 5 ++++ drivers/net/wireless/ath/wil6210/main.c | 37 +++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/boot_loader.h b/drivers/net/wireless/ath/wil6210/boot_loader.h index 1b4fd402cba2..c131b5e1292f 100644 --- a/drivers/net/wireless/ath/wil6210/boot_loader.h +++ b/drivers/net/wireless/ath/wil6210/boot_loader.h @@ -36,6 +36,11 @@ struct bl_dedicated_registers_v1 { u8 bl_version_minor; /* 0x880A53 BL ver. minor */ __le16 bl_version_subminor; /* 0x880A54 BL ver. subminor */ __le16 bl_version_build; /* 0x880A56 BL ver. build */ + /* valid only for version 2 and above */ + __le32 bl_assert_code; /* 0x880A58 BL Assert code */ + __le32 bl_assert_blink; /* 0x880A5C BL Assert Branch */ + __le32 bl_reserved[22]; /* 0x880A60 - 0x880AB4 */ + __le32 bl_magic_number; /* 0x880AB8 BL Magic number */ } __packed; /* the following struct is the version 0 struct */ diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 44223236a629..d11a147489bf 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -663,6 +663,7 @@ static int wil_get_bl_info(struct wil6210_priv *wil) wil_info(wil, "Boot Loader build unknown for struct v0\n"); break; case 1: + case 2: wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), sizeof(bl.bl1)); le32_to_cpus(&bl.bl1.boot_loader_ready); @@ -705,6 +706,37 @@ static int wil_get_bl_info(struct wil6210_priv *wil) return 0; } +static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err) +{ + u32 bl_assert_code, bl_assert_blink, bl_magic_number; + u32 bl_ver = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v0, + boot_loader_struct_version)); + + if (bl_ver < 2) + return; + + bl_assert_code = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v1, + bl_assert_code)); + bl_assert_blink = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v1, + bl_assert_blink)); + bl_magic_number = wil_r(wil, RGF_USER_BL + + offsetof(struct bl_dedicated_registers_v1, + bl_magic_number)); + + if (is_err) { + wil_err(wil, + "BL assert code 0x%08x blink 0x%08x magic 0x%08x\n", + bl_assert_code, bl_assert_blink, bl_magic_number); + } else { + wil_dbg_misc(wil, + "BL assert code 0x%08x blink 0x%08x magic 0x%08x\n", + bl_assert_code, bl_assert_blink, bl_magic_number); + } +} + static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { ulong to = msecs_to_jiffies(1000); @@ -770,10 +802,13 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) flush_workqueue(wil->wq_service); flush_workqueue(wil->wmi_wq); + wil_bl_crash_info(wil, false); rc = wil_target_reset(wil); wil_rx_fini(wil); - if (rc) + if (rc) { + wil_bl_crash_info(wil, true); return rc; + } rc = wil_get_bl_info(wil); if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ -- cgit v1.3-6-gb490 From 19c871ce3ac5f99d4354b0345c7560f6d0f760bd Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 30 Jul 2015 13:52:07 +0300 Subject: wil6210: support future boot loaders Boot loader versions as backward compatible, starting from v1 Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/main.c | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index d11a147489bf..2fb04c51da53 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -643,37 +643,26 @@ static int wil_get_bl_info(struct wil6210_priv *wil) u8 *mac; u16 rf_status; - bl_ver = wil_r(wil, RGF_USER_BL + - offsetof(struct bl_dedicated_registers_v0, - boot_loader_struct_version)); - switch (bl_ver) { - case 0: - wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), - sizeof(bl.bl0)); - le32_to_cpus(&bl.bl0.boot_loader_ready); - le32_to_cpus(&bl.bl0.boot_loader_struct_version); + wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), + sizeof(bl)); + bl_ver = le32_to_cpu(bl.bl0.boot_loader_struct_version); + mac = bl.bl0.mac_address; + + if (bl_ver == 0) { le32_to_cpus(&bl.bl0.rf_type); le32_to_cpus(&bl.bl0.baseband_type); - mac = bl.bl0.mac_address; rf_status = 0; /* actually, unknown */ wil_info(wil, "Boot Loader struct v%d: MAC = %pM RF = 0x%08x bband = 0x%08x\n", bl_ver, mac, bl.bl0.rf_type, bl.bl0.baseband_type); wil_info(wil, "Boot Loader build unknown for struct v0\n"); - break; - case 1: - case 2: - wil_memcpy_fromio_32(&bl, wil->csr + HOSTADDR(RGF_USER_BL), - sizeof(bl.bl1)); - le32_to_cpus(&bl.bl1.boot_loader_ready); - le32_to_cpus(&bl.bl1.boot_loader_struct_version); + } else { le16_to_cpus(&bl.bl1.rf_type); rf_status = le16_to_cpu(bl.bl1.rf_status); le32_to_cpus(&bl.bl1.baseband_type); le16_to_cpus(&bl.bl1.bl_version_subminor); le16_to_cpus(&bl.bl1.bl_version_build); - mac = bl.bl1.mac_address; wil_info(wil, "Boot Loader struct v%d: MAC = %pM RF = 0x%04x (status 0x%04x) bband = 0x%08x\n", bl_ver, mac, @@ -682,10 +671,6 @@ static int wil_get_bl_info(struct wil6210_priv *wil) wil_info(wil, "Boot Loader build %d.%d.%d.%d\n", bl.bl1.bl_version_major, bl.bl1.bl_version_minor, bl.bl1.bl_version_subminor, bl.bl1.bl_version_build); - break; - default: - wil_err(wil, "BL: unsupported struct version 0x%08x\n", bl_ver); - return -EINVAL; } if (!is_valid_ether_addr(mac)) { -- cgit v1.3-6-gb490 From b4336a282db86b298b70563f8ed51782b36b772c Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Thu, 16 Jul 2015 18:50:01 +0200 Subject: mwifiex: sdio: reset adapter using mmc_hw_reset Since 1fb654fd97ff("mmc: sdio: add reset callback to bus operations"), sdio cards can be power cycled using mmc_hw_reset. The use mmc_remove_host/mmc_add_host is discouraged, because these are internal functions to the mmc core and should only be used by mmc hosts Signed-off-by: Andreas Fenkart Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sdio.c | 51 ++++++++++++++++++++++++++----------- drivers/net/wireless/mwifiex/sdio.h | 3 +++ 2 files changed, 39 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index a0b121f3460c..e4c35ee12782 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -91,6 +91,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) return -ENOMEM; card->func = func; + card->device_id = id; func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; @@ -2107,26 +2108,46 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) port, card->mp_data_port_mask); } +static void mwifiex_recreate_adapter(struct sdio_mmc_card *card) +{ + struct sdio_func *func = card->func; + const struct sdio_device_id *device_id = card->device_id; + + /* TODO mmc_hw_reset does not require destroying and re-probing the + * whole adapter. Hence there was no need to for this rube-goldberg + * design to reload the fw from an external workqueue. If we don't + * destroy the adapter we could reload the fw from + * mwifiex_main_work_queue directly. + * The real difficulty with fw reset is to restore all the user + * settings applied through ioctl. By destroying and recreating the + * adapter, we take the easy way out, since we rely on user space to + * restore them. We assume that user space will treat the new + * incarnation of the adapter(interfaces) as if they had been just + * discovered and initializes them from scratch. + */ + + mwifiex_sdio_remove(func); + + /* power cycle the adapter */ + sdio_claim_host(func); + mmc_hw_reset(func->card->host); + sdio_release_host(func); + + mwifiex_sdio_probe(func, device_id); +} + static struct mwifiex_adapter *save_adapter; static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) { struct sdio_mmc_card *card = adapter->card; - struct mmc_host *target = card->func->card->host; - - /* The actual reset operation must be run outside of driver thread. - * This is because mmc_remove_host() will cause the device to be - * instantly destroyed, and the driver then needs to end its thread, - * leading to a deadlock. - * - * We run it in a totally independent workqueue. - */ - mwifiex_dbg(adapter, WARN, "Resetting card...\n"); - mmc_remove_host(target); - /* 200ms delay is based on experiment with sdhci controller */ - mdelay(200); - target->rescan_entered = 0; /* rescan non-removable cards */ - mmc_add_host(target); + /* TODO card pointer is unprotected. If the adapter is removed + * physically, sdio core might trigger mwifiex_sdio_remove, before this + * workqueue is run, which will destroy the adapter struct. When this + * workqueue eventually exceutes it will dereference an invalid adapter + * pointer + */ + mwifiex_recreate_adapter(card); } /* This function read/write firmware */ diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 6f645cf47369..c44da610541a 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -262,6 +262,9 @@ struct sdio_mmc_card { struct mwifiex_sdio_mpa_tx mpa_tx; struct mwifiex_sdio_mpa_rx mpa_rx; + + /* needed for card reset */ + const struct sdio_device_id *device_id; }; struct mwifiex_sdio_device { -- cgit v1.3-6-gb490 From e3a3ef25b8cb6d7a20b52dfdadd56516041ffb51 Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Fri, 17 Jul 2015 09:13:03 +0200 Subject: mwifiex: remove explicit mwifiex_complete_cmd calls standard call chain when releasing a cmd node: mwifiex_recycle_cmd_node -> mwifiex_insert_cmd_to_free_q -> mwifiex_complete_cmd, if wait_q_enabled calling mwifiex_complete_cmd explicitly and setting wait_q_enabled = false is redundant Signed-off-by: Andreas Fenkart Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 207da40500f4..2f4715e45664 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -167,8 +167,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, mwifiex_dbg(adapter, ERROR, "DNLD_CMD: FW in reset state, ignore cmd %#x\n", cmd_code); - if (cmd_node->wait_q_enabled) - mwifiex_complete_cmd(adapter, cmd_node); mwifiex_recycle_cmd_node(adapter, cmd_node); queue_work(adapter->workqueue, &adapter->main_work); return -1; @@ -1024,6 +1022,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) adapter->curr_cmd->wait_q_enabled = false; adapter->cmd_wait_q.status = -1; mwifiex_complete_cmd(adapter, adapter->curr_cmd); + /* no recycle probably wait for response */ } /* Cancel all pending command */ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); @@ -1032,11 +1031,8 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags); - if (cmd_node->wait_q_enabled) { + if (cmd_node->wait_q_enabled) adapter->cmd_wait_q.status = -1; - mwifiex_complete_cmd(adapter, cmd_node); - cmd_node->wait_q_enabled = false; - } mwifiex_recycle_cmd_node(adapter, cmd_node); spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); } @@ -1094,10 +1090,8 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) (adapter->curr_cmd->wait_q_enabled)) { spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); cmd_node = adapter->curr_cmd; - cmd_node->wait_q_enabled = false; cmd_node->cmd_flag |= CMD_F_CANCELED; mwifiex_recycle_cmd_node(adapter, cmd_node); - mwifiex_complete_cmd(adapter, adapter->curr_cmd); adapter->curr_cmd = NULL; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } -- cgit v1.3-6-gb490 From aeb03000837eec7df4f57034106542efd60be02b Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Fri, 17 Jul 2015 09:13:04 +0200 Subject: mwifiex: remove redundant reset of cmd_wait_q status mwifiex_cancel_pending_ioctl is called only from mwifiex_cmd_timeout_func. There the wait_q status is set to -ETIMEDWAIT before calling this function. Whether we reset the status to -1 or leave it at -ETIMEDWAIT at end doesn't matter since both are != 0 hence mean failure Signed-off-by: Andreas Fenkart Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 2f4715e45664..87b6dee2b049 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -1123,7 +1123,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) } } } - adapter->cmd_wait_q.status = -1; } /* -- cgit v1.3-6-gb490 From e9f21d403699a4d299a02df107326f11acecd13e Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Fri, 17 Jul 2015 09:13:05 +0200 Subject: mwifiex: remove CMD_F_CANCELED flag CMD_F_CANCELED was used to abort mwifiex_process_cmdresp in case it already started or starts processing the cmd. But this was probably not working the way intended: - it is racy: mwifiex_process_cmdresp might already have passed that test and is continuing to use the cmd node being recycled - mwifiex_process_cmdresp repeatedly uses adapter->curr_cmd which we just set to NULL - mwifiex_recycle_cmd_node will clear the flag The reason why it probably works is that mwifiex_cancel_pending_ioctl is only called from mwifiex_cmd_timeout_func, where the there is little chance of a command response still arriving Signed-off-by: Andreas Fenkart Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 23 ++++++++++------------- drivers/net/wireless/mwifiex/fw.h | 1 - 2 files changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 87b6dee2b049..6458e17304ca 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -807,17 +807,6 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter) adapter->is_cmd_timedout = 0; resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data; - if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) { - mwifiex_dbg(adapter, ERROR, - "CMD_RESP: %#x been canceled\n", - le16_to_cpu(resp->command)); - mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd); - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); - adapter->curr_cmd = NULL; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - return -1; - } - if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) { /* Copy original response back to response buffer */ struct mwifiex_ds_misc_cmd *hostcmd; @@ -1090,10 +1079,18 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) (adapter->curr_cmd->wait_q_enabled)) { spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags); cmd_node = adapter->curr_cmd; - cmd_node->cmd_flag |= CMD_F_CANCELED; - mwifiex_recycle_cmd_node(adapter, cmd_node); + /* setting curr_cmd to NULL is quite dangerous, because + * mwifiex_process_cmdresp checks curr_cmd to be != NULL + * at the beginning then relies on it and dereferences + * it at will + * this probably works since mwifiex_cmd_timeout_func + * is the only caller of this function and responses + * at that point + */ adapter->curr_cmd = NULL; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); + + mwifiex_recycle_cmd_node(adapter, cmd_node); } /* Cancel all pending scan command */ diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index cff38ad129aa..9a8c1832d068 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -438,7 +438,6 @@ enum P2P_MODES { #define CMD_F_HOSTCMD (1 << 0) -#define CMD_F_CANCELED (1 << 1) #define HostCmd_CMD_ID_MASK 0x0fff -- cgit v1.3-6-gb490 From c5bc15fce6aa33b7aeba4e049ceacfab66fa4a9f Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Fri, 17 Jul 2015 09:13:06 +0200 Subject: mwifiex: simplify mwifiex_complete_cmd 600f5d909a54("mwifiex: cleanup ioctl wait queue and abstraction layer") introduced the wakeup_interruptible suppression in mwifiex_complete_cmd b1a47aa5e1e1("mwifiex: fix system hang issue in cmd timeout error case") then added wakup_interruptible to mwifiex_cmd_timeout_func the single place setting a status of ETIMEDOUT. Instead of doing extra work, using the standard call-chain will have the same effect: mwifiex_cancel_pending_ioctl -> mwifiex_recycle_cmd_node -> mwifiex_insert_cmd_to_free_q -> mwifiex_complete_cmd -> wake_up_interruptible The difference is that previously the condition was not set to true, but that's probably just an oversight in b1a47aa5e1e1 and shouldn't have any consequence Signed-off-by: Andreas Fenkart Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 1 - drivers/net/wireless/mwifiex/sta_ioctl.c | 4 ++-- drivers/net/wireless/mwifiex/util.c | 12 ++++-------- 3 files changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 6458e17304ca..27b778d5164e 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -976,7 +976,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) if (cmd_node->wait_q_enabled) { adapter->cmd_wait_q.status = -ETIMEDOUT; - wake_up_interruptible(&adapter->cmd_wait_q.wait); mwifiex_cancel_pending_ioctl(adapter); } } diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index d8b7d9c20450..a6c8a4f7bfe9 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -66,8 +66,8 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, if (status <= 0) { if (status == 0) status = -ETIMEDOUT; - mwifiex_dbg(adapter, ERROR, - "cmd_wait_q terminated: %d\n", status); + mwifiex_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n", + status); mwifiex_cancel_all_pending_cmd(adapter); return status; } diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 2504e422364a..a5f34f2c1086 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -496,16 +496,12 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb) int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, struct cmd_ctrl_node *cmd_node) { - mwifiex_dbg(adapter, CMD, - "cmd completed: status=%d\n", + WARN_ON(!cmd_node->wait_q_enabled); + mwifiex_dbg(adapter, CMD, "cmd completed: status=%d\n", adapter->cmd_wait_q.status); - *(cmd_node->condition) = true; - - if (adapter->cmd_wait_q.status == -ETIMEDOUT) - mwifiex_dbg(adapter, ERROR, "cmd timeout\n"); - else - wake_up_interruptible(&adapter->cmd_wait_q.wait); + *cmd_node->condition = true; + wake_up_interruptible(&adapter->cmd_wait_q.wait); return 0; } -- cgit v1.3-6-gb490 From eb61f9f623f78f463ec08b1c4a1defea9b511312 Mon Sep 17 00:00:00 2001 From: "Janusz.Dziedzic@tieto.com" Date: Tue, 21 Jul 2015 11:11:40 +0200 Subject: ath9k: advertise p2p dev support when chanctx Advertise p2p device support when ath9k loaded with use_chanctx=1. This will fix problem, when first interface is an AP and next we would like to run p2p_find. Before p2p find (scan phase) failed with EOPNOTSUPP. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/init.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index eff0e5325e6a..89a457d02453 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -736,13 +736,14 @@ static const struct ieee80211_iface_limit if_limits_multi[] = { BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, }; static const struct ieee80211_iface_combination if_comb_multi[] = { { .limits = if_limits_multi, .n_limits = ARRAY_SIZE(if_limits_multi), - .max_interfaces = 2, + .max_interfaces = 3, .num_different_channels = 2, .beacon_int_infra_match = true, }, @@ -855,6 +856,10 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_MESH_POINT) | BIT(NL80211_IFTYPE_WDS); + if (ath9k_is_chanctx_enabled()) + hw->wiphy->interface_modes |= + BIT(NL80211_IFTYPE_P2P_DEVICE); + hw->wiphy->iface_combinations = if_comb; hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); } -- cgit v1.3-6-gb490 From d83520b7cd6e8c5399b1bd0d2f6f9ce733b10454 Mon Sep 17 00:00:00 2001 From: "Janusz.Dziedzic@tieto.com" Date: Tue, 21 Jul 2015 11:11:41 +0200 Subject: ath9k: handle RoC cancel correctly In case we will get ROC cancel from mac80211 we should not call ieee80211_remain_on_channel_expired(). In other case I hit such warning on MIPS and p2p negotiation failed (tested with use_chanctx=1). ath: phy0: Starting RoC period ath: phy0: Channel definition created: 2412 MHz ath: phy0: Assigned next_chan to 2412 MHz ath: phy0: Offchannel duration for chan 2412 MHz : 506632 ath: phy0: ath_chanctx_set_next: current: 2412 MHz, next: 2412 MHz ath: phy0: Stopping current chanctx: 2412 ath: phy0: Flush timeout: 200 ath: phy0: ath_chanctx_set_next: Set channel 2412 MHz ath: phy0: Set channel: 2412 MHz width: 0 ath: phy0: Reset to 2412 MHz, HT40: 0 fastcc: 0 ath: phy0: cur_chan: 2412 MHz, event: ATH_CHANCTX_EVENT_TSF_TIMER, state: ATH_CHANCTX_STATE_IDLE ath: phy0: ath_offchannel_channel_change: offchannel state: ATH_OFFCHANNEL_ROC_START ath: phy0: cur_chan: 2412 MHz, event: ATH_CHANCTX_EVENT_SWITCH, state: ATH_CHANCTX_STATE_IDLE ath: phy0: Cancel RoC ath: phy0: RoC aborted ath: phy0: RoC request on vif: 00:03:7f:4e:a0:cd, type: 1 duration: 500 ath: phy0: Starting RoC period ath: phy0: Channel definition created: 2412 MHz ath: phy0: Assigned next_chan to 2412 MHz ath: phy0: Offchannel duration for chan 2412 MHz : 506705 ath: phy0: ath_chanctx_set_next: current: 2412 MHz, next: 2412 MHz ath: phy0: ath_offchannel_channel_change: offchannel state: ATH_OFFCHANNEL_ROC_START ath: phy0: cur_chan: 2412 MHz, event: ATH_CHANCTX_EVENT_SWITCH, state: ATH_CHANCTX_STATE_IDLE ------------[ cut here ]------------ WARNING: CPU: 0 PID: 3312 at drivers/net/wireless/ath/ath9k/main.c:2319 Modules linked in: ath9k ath9k_common ath9k_hw ath mac80211 cfg80211 Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 9 ++++++++- drivers/net/wireless/ath/ath9k/channel.c | 23 ++++++++++++++++------- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- 3 files changed, 26 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a7a81b3969ce..db7a7b64bcdf 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -410,6 +410,12 @@ enum ath_offchannel_state { ATH_OFFCHANNEL_ROC_DONE, }; +enum ath_roc_complete_reason { + ATH_ROC_COMPLETE_EXPIRE, + ATH_ROC_COMPLETE_ABORT, + ATH_ROC_COMPLETE_CANCEL, +}; + struct ath_offchannel { struct ath_chanctx chan; struct timer_list timer; @@ -471,7 +477,8 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, void ath_chanctx_set_next(struct ath_softc *sc, bool force); void ath_offchannel_next(struct ath_softc *sc); void ath_scan_complete(struct ath_softc *sc, bool abort); -void ath_roc_complete(struct ath_softc *sc, bool abort); +void ath_roc_complete(struct ath_softc *sc, + enum ath_roc_complete_reason reason); struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc); #else diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 206665059d66..90f5773a1a61 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -915,18 +915,27 @@ void ath_offchannel_next(struct ath_softc *sc) } } -void ath_roc_complete(struct ath_softc *sc, bool abort) +void ath_roc_complete(struct ath_softc *sc, enum ath_roc_complete_reason reason) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - if (abort) + sc->offchannel.roc_vif = NULL; + sc->offchannel.roc_chan = NULL; + + switch (reason) { + case ATH_ROC_COMPLETE_ABORT: ath_dbg(common, CHAN_CTX, "RoC aborted\n"); - else + ieee80211_remain_on_channel_expired(sc->hw); + break; + case ATH_ROC_COMPLETE_EXPIRE: ath_dbg(common, CHAN_CTX, "RoC expired\n"); + ieee80211_remain_on_channel_expired(sc->hw); + break; + case ATH_ROC_COMPLETE_CANCEL: + ath_dbg(common, CHAN_CTX, "RoC canceled\n"); + break; + } - sc->offchannel.roc_vif = NULL; - sc->offchannel.roc_chan = NULL; - ieee80211_remain_on_channel_expired(sc->hw); ath_offchannel_next(sc); ath9k_ps_restore(sc); } @@ -1058,7 +1067,7 @@ static void ath_offchannel_timer(unsigned long data) case ATH_OFFCHANNEL_ROC_START: case ATH_OFFCHANNEL_ROC_WAIT: sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; - ath_roc_complete(sc, false); + ath_roc_complete(sc, ATH_ROC_COMPLETE_EXPIRE); break; default: break; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cfd45cb8ccfc..b7b77e000507 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2246,7 +2246,7 @@ static void ath9k_cancel_pending_offchannel(struct ath_softc *sc) del_timer_sync(&sc->offchannel.timer); if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) - ath_roc_complete(sc, true); + ath_roc_complete(sc, ATH_ROC_COMPLETE_ABORT); } if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { @@ -2355,7 +2355,7 @@ static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw) if (sc->offchannel.roc_vif) { if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) - ath_roc_complete(sc, true); + ath_roc_complete(sc, ATH_ROC_COMPLETE_CANCEL); } mutex_unlock(&sc->mutex); -- cgit v1.3-6-gb490 From f3771c08282afa1354c2e5a2fdade587f30db4fd Mon Sep 17 00:00:00 2001 From: "Janusz.Dziedzic@tieto.com" Date: Tue, 21 Jul 2015 11:11:42 +0200 Subject: ath9k: setup rxfilter for all chanctx While mac80211 setup this per HW, set same rxfilter configuration for all chanctx. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b7b77e000507..3de829f13747 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1459,13 +1459,15 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct ath_softc *sc = hw->priv; + struct ath_chanctx *ctx; u32 rfilt; changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; spin_lock_bh(&sc->chan_lock); - sc->cur_chan->rxfilter = *total_flags; + ath_for_each_chanctx(sc, ctx) + ctx->rxfilter = *total_flags; spin_unlock_bh(&sc->chan_lock); ath9k_ps_wakeup(sc); -- cgit v1.3-6-gb490 From 1738203ee7291b5e93670d19a663fae03155aebc Mon Sep 17 00:00:00 2001 From: "Janusz.Dziedzic@tieto.com" Date: Tue, 21 Jul 2015 11:11:43 +0200 Subject: ath9k: setup rxfilter when offchannel Setup rxfiler correctly for offchannel ctx. This fix problem we didn't configure rxfilter, next didn't receive probe requests and next failed p2p_find. This was seen when ath9k loaded with use_chanctx=1 Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 3de829f13747..c27143ba9ffb 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1468,6 +1468,9 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, spin_lock_bh(&sc->chan_lock); ath_for_each_chanctx(sc, ctx) ctx->rxfilter = *total_flags; +#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT + sc->offchannel.chan.rxfilter = *total_flags; +#endif spin_unlock_bh(&sc->chan_lock); ath9k_ps_wakeup(sc); -- cgit v1.3-6-gb490 From f419c5f1d8d28391a025618dee7e1a4fdc7a5654 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Jul 2015 13:06:12 +0200 Subject: ath9k: add fast-xmit support Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/init.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 89a457d02453..57f95f2dca5b 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -827,6 +827,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, RX_INCLUDES_FCS); ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); if (ath9k_ps_enable) ieee80211_hw_set(hw, SUPPORTS_PS); -- cgit v1.3-6-gb490 From 592fa228f213932dc5ec433aade654d7352b3e08 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Jul 2015 13:06:13 +0200 Subject: ath9k: remove struct ath_atx_ac struct ath_atx_ac contains a list of active TIDs belonging to one WMM AC. This patch changes the code to track active station TIDs in the txq directly. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 12 +--- drivers/net/wireless/ath/ath9k/xmit.c | 128 ++++++++++----------------------- 2 files changed, 41 insertions(+), 99 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index db7a7b64bcdf..ac1f10028fe7 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -172,14 +172,6 @@ struct ath_txq { struct sk_buff_head complete_q; }; -struct ath_atx_ac { - struct ath_txq *txq; - struct list_head list; - struct list_head tid_q; - bool clear_ps_filter; - bool sched; -}; - struct ath_frame_info { struct ath_buf *bf; u16 framelen; @@ -242,7 +234,7 @@ struct ath_atx_tid { struct sk_buff_head buf_q; struct sk_buff_head retry_q; struct ath_node *an; - struct ath_atx_ac *ac; + struct ath_txq *txq; unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; u16 seq_start; u16 seq_next; @@ -254,6 +246,7 @@ struct ath_atx_tid { s8 bar_index; bool sched; bool active; + bool clear_ps_filter; }; struct ath_node { @@ -261,7 +254,6 @@ struct ath_node { struct ieee80211_sta *sta; /* station struct we're part of */ struct ieee80211_vif *vif; /* interface with which we're associated */ struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; - struct ath_atx_ac ac[IEEE80211_NUM_ACS]; u16 maxampdu; u8 mpdudensity; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index b766a7fc60aa..f7d6a85433ed 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -106,7 +106,6 @@ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid) { - struct ath_atx_ac *ac = tid->ac; struct list_head *list; struct ath_vif *avp = (struct ath_vif *) tid->an->vif->drv_priv; struct ath_chanctx *ctx = avp->chanctx; @@ -118,15 +117,8 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq, return; tid->sched = true; - list_add_tail(&tid->list, &ac->tid_q); - - if (ac->sched) - return; - - ac->sched = true; - list = &ctx->acq[TID_TO_WME_AC(tid->tidno)]; - list_add_tail(&ac->list, list); + list_add_tail(&tid->list, list); } static struct ath_frame_info *get_frame_info(struct sk_buff *skb) @@ -208,7 +200,7 @@ static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) static void ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = tid->ac->txq; + struct ath_txq *txq = tid->txq; struct ieee80211_tx_info *tx_info; struct sk_buff *skb, *tskb; struct ath_buf *bf; @@ -237,7 +229,7 @@ ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid) static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = tid->ac->txq; + struct ath_txq *txq = tid->txq; struct sk_buff *skb; struct ath_buf *bf; struct list_head bf_head; @@ -644,7 +636,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ath_tx_queue_tid(sc, txq, tid); if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) - tid->ac->clear_ps_filter = true; + tid->clear_ps_filter = true; } } @@ -734,7 +726,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ieee80211_tx_rate *rates; u32 max_4ms_framelen, frmlen; u16 aggr_limit, bt_aggr_limit, legacy = 0; - int q = tid->ac->txq->mac80211_qnum; + int q = tid->txq->mac80211_qnum; int i; skb = bf->bf_mpdu; @@ -1471,8 +1463,8 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, if (list_empty(&bf_q)) return false; - if (tid->ac->clear_ps_filter || tid->an->no_ps_filter) { - tid->ac->clear_ps_filter = false; + if (tid->clear_ps_filter || tid->an->no_ps_filter) { + tid->clear_ps_filter = false; tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; } @@ -1491,7 +1483,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, an = (struct ath_node *)sta->drv_priv; txtid = ATH_AN_2_TID(an, tid); - txq = txtid->ac->txq; + txq = txtid->txq; ath_txq_lock(sc, txq); @@ -1525,7 +1517,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); - struct ath_txq *txq = txtid->ac->txq; + struct ath_txq *txq = txtid->txq; ath_txq_lock(sc, txq); txtid->active = false; @@ -1538,7 +1530,6 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, struct ath_node *an) { struct ath_atx_tid *tid; - struct ath_atx_ac *ac; struct ath_txq *txq; bool buffered; int tidno; @@ -1546,8 +1537,7 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - ac = tid->ac; - txq = ac->txq; + txq = tid->txq; ath_txq_lock(sc, txq); @@ -1561,11 +1551,6 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, tid->sched = false; list_del(&tid->list); - if (ac->sched) { - ac->sched = false; - list_del(&ac->list); - } - ath_txq_unlock(sc, txq); ieee80211_sta_set_buffered(sta, tidno, buffered); @@ -1575,18 +1560,16 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) { struct ath_atx_tid *tid; - struct ath_atx_ac *ac; struct ath_txq *txq; int tidno; for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - ac = tid->ac; - txq = ac->txq; + txq = tid->txq; ath_txq_lock(sc, txq); - ac->clear_ps_filter = true; + tid->clear_ps_filter = true; if (ath_tid_has_buffered(tid)) { ath_tx_queue_tid(sc, txq, tid); @@ -1606,7 +1589,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, an = (struct ath_node *)sta->drv_priv; tid = ATH_AN_2_TID(an, tidno); - txq = tid->ac->txq; + txq = tid->txq; ath_txq_lock(sc, txq); @@ -1645,7 +1628,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, tid = ATH_AN_2_TID(an, i); - ath_txq_lock(sc, tid->ac->txq); + ath_txq_lock(sc, tid->txq); while (nframes > 0) { bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q); if (!bf) @@ -1669,7 +1652,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, if (an->sta && !ath_tid_has_buffered(tid)) ieee80211_sta_set_buffered(an->sta, i, false); } - ath_txq_unlock_complete(sc, tid->ac->txq); + ath_txq_unlock_complete(sc, tid->txq); } if (list_empty(&bf_q)) @@ -1918,9 +1901,8 @@ 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; - struct list_head *ac_list; + struct list_head *tid_list; bool sent = false; if (txq->mac80211_qnum < 0) @@ -1930,63 +1912,46 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) return; spin_lock_bh(&sc->chan_lock); - ac_list = &sc->cur_chan->acq[txq->mac80211_qnum]; + tid_list = &sc->cur_chan->acq[txq->mac80211_qnum]; - if (list_empty(ac_list)) { + if (list_empty(tid_list)) { spin_unlock_bh(&sc->chan_lock); return; } rcu_read_lock(); - last_ac = list_entry(ac_list->prev, struct ath_atx_ac, list); - while (!list_empty(ac_list)) { + last_tid = list_entry(tid_list->prev, struct ath_atx_tid, list); + while (!list_empty(tid_list)) { bool stop = false; if (sc->cur_chan->stopped) break; - ac = list_first_entry(ac_list, struct ath_atx_ac, list); - last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list); - list_del(&ac->list); - ac->sched = false; - - while (!list_empty(&ac->tid_q)) { - - tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, - list); - list_del(&tid->list); - tid->sched = false; - - if (ath_tx_sched_aggr(sc, txq, tid, &stop)) - sent = true; - - /* - * add tid to round-robin queue if more frames - * are pending for the tid - */ - if (ath_tid_has_buffered(tid)) - ath_tx_queue_tid(sc, txq, tid); + tid = list_first_entry(tid_list, struct ath_atx_tid, list); + list_del(&tid->list); + tid->sched = false; - if (stop || tid == last_tid) - break; - } + if (ath_tx_sched_aggr(sc, txq, tid, &stop)) + sent = true; - if (!list_empty(&ac->tid_q) && !ac->sched) { - ac->sched = true; - list_add_tail(&ac->list, ac_list); - } + /* + * add tid to round-robin queue if more frames + * are pending for the tid + */ + if (ath_tid_has_buffered(tid)) + ath_tx_queue_tid(sc, txq, tid); if (stop) break; - if (ac == last_ac) { + if (tid == last_tid) { if (!sent) break; sent = false; - last_ac = list_entry(ac_list->prev, - struct ath_atx_ac, list); + last_tid = list_entry(tid_list->prev, + struct ath_atx_tid, list); } } @@ -2376,10 +2341,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, txq = sc->tx.uapsdq; ath_txq_lock(sc, txq); } else if (txctl->an && queue) { - WARN_ON(tid->ac->txq != txctl->txq); + WARN_ON(tid->txq != txctl->txq); if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) - tid->ac->clear_ps_filter = true; + tid->clear_ps_filter = true; /* * Add this frame to software queue for scheduling later @@ -2873,7 +2838,6 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) { struct ath_atx_tid *tid; - struct ath_atx_ac *ac; int tidno, acno; for (tidno = 0, tid = &an->tid[tidno]; @@ -2886,24 +2850,16 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->baw_head = tid->baw_tail = 0; tid->sched = false; tid->active = false; + tid->clear_ps_filter = true; __skb_queue_head_init(&tid->buf_q); __skb_queue_head_init(&tid->retry_q); acno = TID_TO_WME_AC(tidno); - tid->ac = &an->ac[acno]; - } - - for (acno = 0, ac = &an->ac[acno]; - acno < IEEE80211_NUM_ACS; acno++, ac++) { - ac->sched = false; - ac->clear_ps_filter = true; - ac->txq = sc->tx.txq_map[acno]; - INIT_LIST_HEAD(&ac->tid_q); + tid->txq = sc->tx.txq_map[acno]; } } void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) { - struct ath_atx_ac *ac; struct ath_atx_tid *tid; struct ath_txq *txq; int tidno; @@ -2911,8 +2867,7 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - ac = tid->ac; - txq = ac->txq; + txq = tid->txq; ath_txq_lock(sc, txq); @@ -2921,11 +2876,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) tid->sched = false; } - if (ac->sched) { - list_del(&ac->list); - tid->ac->sched = false; - } - ath_tid_drain(sc, txq, tid); tid->active = false; -- cgit v1.3-6-gb490 From d70d848a75fd65b28835a843bcc4faec2f5803ea Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 22 Jul 2015 13:06:14 +0200 Subject: ath9k: remove the sched field in struct ath_atx_tid Use list_empty(&tid->list) instead Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/xmit.c | 23 ++++++++--------------- 2 files changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index ac1f10028fe7..c85c47978e1e 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -244,7 +244,6 @@ struct ath_atx_tid { int baw_tail; /* next unused tx buffer slot */ s8 bar_index; - bool sched; bool active; bool clear_ps_filter; }; diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f7d6a85433ed..3e3dac3d7060 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -113,12 +113,9 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq, if (!ctx) return; - if (tid->sched) - return; - - tid->sched = true; list = &ctx->acq[TID_TO_WME_AC(tid->tidno)]; - list_add_tail(&tid->list, list); + if (list_empty(&tid->list)) + list_add_tail(&tid->list, list); } static struct ath_frame_info *get_frame_info(struct sk_buff *skb) @@ -1541,15 +1538,14 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, ath_txq_lock(sc, txq); - if (!tid->sched) { + if (list_empty(&tid->list)) { ath_txq_unlock(sc, txq); continue; } buffered = ath_tid_has_buffered(tid); - tid->sched = false; - list_del(&tid->list); + list_del_init(&tid->list); ath_txq_unlock(sc, txq); @@ -1929,8 +1925,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) break; tid = list_first_entry(tid_list, struct ath_atx_tid, list); - list_del(&tid->list); - tid->sched = false; + list_del_init(&tid->list); if (ath_tx_sched_aggr(sc, txq, tid, &stop)) sent = true; @@ -2848,11 +2843,11 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->seq_start = tid->seq_next = 0; tid->baw_size = WME_MAX_BA; tid->baw_head = tid->baw_tail = 0; - tid->sched = false; tid->active = false; tid->clear_ps_filter = true; __skb_queue_head_init(&tid->buf_q); __skb_queue_head_init(&tid->retry_q); + INIT_LIST_HEAD(&tid->list); acno = TID_TO_WME_AC(tidno); tid->txq = sc->tx.txq_map[acno]; } @@ -2871,10 +2866,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) ath_txq_lock(sc, txq); - if (tid->sched) { - list_del(&tid->list); - tid->sched = false; - } + if (!list_empty(&tid->list)) + list_del_init(&tid->list); ath_tid_drain(sc, txq, tid); tid->active = false; -- cgit v1.3-6-gb490 From 3afafd6dcc0cb894a2a6cc1a42bb6f84a0519f16 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Wed, 22 Jul 2015 04:53:42 -0700 Subject: mwifiex: using right aid value for tdls action frame Variable pos is u8 here, so memcpy is needed to store u16 aid. At the same time, aid should be platform independent, upper layer utility(wpa_supplicant,etc.,) parse it as le16, so keep it le16 here. Signed-off-by: Xinming Hu Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/tdls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index aa3d3c5ed07b..b3e163de9899 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -164,7 +164,7 @@ static void mwifiex_tdls_add_aid(struct mwifiex_private *priv, pos = (void *)skb_put(skb, 4); *pos++ = WLAN_EID_AID; *pos++ = 2; - *pos++ = le16_to_cpu(assoc_rsp->a_id); + memcpy(pos, &assoc_rsp->a_id, sizeof(assoc_rsp->a_id)); return; } -- cgit v1.3-6-gb490 From 398750992ebe8a3f26d9c1c978911b55c2b2ff8b Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Wed, 22 Jul 2015 04:53:43 -0700 Subject: mwifiex: fix command timeout for PCIe chipsets When WLAN interface is up and running, driver unload and load was causing command timeout error. We enable Rx data by updating RX ring read pointer in init_fw_port(). It should be done when FW is completely intialialised. Command timeout is fixed in this patch by moving init_fw_port() call to mwifiex_init_fw_complete(). Signed-off-by: Zhaoyang Liu Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/init.c | 5 ----- drivers/net/wireless/mwifiex/util.c | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 8fa363add970..7a970c28c557 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -551,11 +551,6 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter) } } - if (adapter->if_ops.init_fw_port) { - if (adapter->if_ops.init_fw_port(adapter)) - return -1; - } - for (i = 0; i < adapter->priv_num; i++) { if (adapter->priv[i]) { ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta, diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index a5f34f2c1086..0cec8a64473e 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -126,6 +126,10 @@ static int num_of_items = ARRAY_SIZE(items); int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter) { + if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) + if (adapter->if_ops.init_fw_port) + adapter->if_ops.init_fw_port(adapter); + adapter->init_wait_q_woken = true; wake_up_interruptible(&adapter->init_wait_q); return 0; -- cgit v1.3-6-gb490 From d788ac29793ae591801103b714c20ca3ae311c21 Mon Sep 17 00:00:00 2001 From: Zhaoyang Liu Date: Wed, 22 Jul 2015 04:53:44 -0700 Subject: mwifiex: fix system crash observed during initialisation System crash was observed if one of the driver initialisation commands is timed out. The reason is our timeout handler triggers firmware dump, meanwhile driver initialisation error paths have already freed the adapter structure. Firmware hasn't yet completely initialized. So collecting firmware dump is not needed in this case. Command timeout handler is modified in this patch to fix the crash issue. Signed-off-by: Zhaoyang Liu Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cmdevt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 27b778d5164e..45ae38e32621 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -979,8 +979,10 @@ mwifiex_cmd_timeout_func(unsigned long function_context) mwifiex_cancel_pending_ioctl(adapter); } } - if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) + if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) { mwifiex_init_fw_complete(adapter); + return; + } if (adapter->if_ops.device_dump) adapter->if_ops.device_dump(adapter); -- cgit v1.3-6-gb490 From 2728cecdc7d6bf3d216fc406718d88c35f4d09eb Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Wed, 22 Jul 2015 04:53:45 -0700 Subject: mwifiex: corrections in PCIe event skb handling Preallocated event SKBs are getting reused for PCIe chipset. Their physical addresses are shared with firmware so that firmware can write data into them. This patch makes sure that SKB is cleared and length is set to default while submitting it to firmware. Signed-off-by: Amitkumar Karwar Signed-off-by: Zhaoyang Liu Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/pcie.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c index 77b9055a2d14..33c75d741017 100644 --- a/drivers/net/wireless/mwifiex/pcie.c +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -1807,6 +1807,8 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, if (!card->evt_buf_list[rdptr]) { skb_push(skb, INTF_HEADER_LEN); + skb_put(skb, MAX_EVENT_SIZE - skb->len); + memset(skb->data, 0, MAX_EVENT_SIZE); if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, PCI_DMA_FROMDEVICE)) -- cgit v1.3-6-gb490 From d1c5409612ad25d8a35a49a89ad302fc797eeb8e Mon Sep 17 00:00:00 2001 From: Guy Mishol Date: Mon, 27 Jul 2015 09:46:02 +0300 Subject: wl18xx: add dynamic fw traces add option to dynamically configure the fw which debug traces to open Signed-off-by: Guy Mishol Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/acx.c | 27 +++++++++++++++++ drivers/net/wireless/ti/wl18xx/acx.h | 13 ++++++++- drivers/net/wireless/ti/wl18xx/debugfs.c | 50 ++++++++++++++++++++++++++++++++ drivers/net/wireless/ti/wl18xx/main.c | 5 ++++ drivers/net/wireless/ti/wlcore/wlcore.h | 3 ++ 5 files changed, 97 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c index 67f2a0eec854..4be0409308cb 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.c +++ b/drivers/net/wireless/ti/wl18xx/acx.c @@ -282,3 +282,30 @@ out: kfree(acx); return ret; } + +int wl18xx_acx_dynamic_fw_traces(struct wl1271 *wl) +{ + struct acx_dynamic_fw_traces_cfg *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx dynamic fw traces config %d", + wl->dynamic_fw_traces); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->dynamic_fw_traces = cpu_to_le32(wl->dynamic_fw_traces); + + ret = wl1271_cmd_configure(wl, ACX_DYNAMIC_TRACES_CFG, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx config dynamic fw traces failed: %d", ret); + goto out; + } +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h index 4afccd4b9467..c8a33f43916e 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.h +++ b/drivers/net/wireless/ti/wl18xx/acx.h @@ -35,7 +35,8 @@ enum { ACX_PEER_CAP = 0x0056, ACX_INTERRUPT_NOTIFY = 0x0057, ACX_RX_BA_FILTER = 0x0058, - ACX_AP_SLEEP_CFG = 0x0059 + ACX_AP_SLEEP_CFG = 0x0059, + ACX_DYNAMIC_TRACES_CFG = 0x005A, }; /* numbers of bits the length field takes (add 1 for the actual number) */ @@ -367,6 +368,15 @@ struct acx_ap_sleep_cfg { u8 idle_conn_thresh; } __packed; +/* + * ACX_DYNAMIC_TRACES_CFG + * configure the FW dynamic traces + */ +struct acx_dynamic_fw_traces_cfg { + struct acx_header header; + __le32 dynamic_fw_traces; +} __packed; + int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap, u32 sdio_blk_size, u32 extra_mem_blks, u32 len_field_size); @@ -380,5 +390,6 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl, int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action); int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action); int wl18xx_acx_ap_sleep(struct wl1271 *wl); +int wl18xx_acx_dynamic_fw_traces(struct wl1271 *wl); #endif /* __WL18XX_ACX_H__ */ diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c index 5fbd2230f372..8c6a1c86f526 100644 --- a/drivers/net/wireless/ti/wl18xx/debugfs.c +++ b/drivers/net/wireless/ti/wl18xx/debugfs.c @@ -281,6 +281,55 @@ static const struct file_operations radar_detection_ops = { .llseek = default_llseek, }; +static ssize_t dynamic_fw_traces_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + unsigned long value; + int ret; + + ret = kstrtoul_from_user(user_buf, count, 0, &value); + if (ret < 0) + return ret; + + mutex_lock(&wl->mutex); + + wl->dynamic_fw_traces = value; + + if (unlikely(wl->state != WLCORE_STATE_ON)) + goto out; + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl18xx_acx_dynamic_fw_traces(wl); + if (ret < 0) + count = ret; + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return count; +} + +static ssize_t dynamic_fw_traces_read(struct file *file, + char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + return wl1271_format_buffer(userbuf, count, ppos, + "%d\n", wl->dynamic_fw_traces); +} + +static const struct file_operations dynamic_fw_traces_ops = { + .read = dynamic_fw_traces_read, + .write = dynamic_fw_traces_write, + .open = simple_open, + .llseek = default_llseek, +}; + int wl18xx_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -433,6 +482,7 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(conf, moddir); DEBUGFS_ADD(radar_detection, moddir); + DEBUGFS_ADD(dynamic_fw_traces, moddir); return 0; diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 49aca2cf7605..8ce9825ee577 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1159,6 +1159,11 @@ static int wl18xx_hw_init(struct wl1271 *wl) if (ret < 0) return ret; + /* set the dynamic fw traces bitmap */ + ret = wl18xx_acx_dynamic_fw_traces(wl); + if (ret < 0) + return ret; + if (checksum_param) { ret = wl18xx_acx_set_checksum_state(wl); if (ret != 0) diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 7f363fa566a3..a1b6040e6491 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -500,6 +500,9 @@ struct wl1271 { /* interface combinations supported by the hw */ const struct ieee80211_iface_combination *iface_combinations; u8 n_iface_combinations; + + /* dynamic fw traces */ + u32 dynamic_fw_traces; }; int wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); -- cgit v1.3-6-gb490 From 6c6317321107bee5aad2d85d848b0597428343d8 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 27 Jul 2015 05:02:27 -0700 Subject: mwifiex: add missing skb_push() in mwifiex_check_uap_capabilties For PCIe/USB chipsets, preallocated skb buffers are reused for event handling. mwifiex_check_uap_capabilties() performs skb_pull(). This patch adds missing skb_push() to restore skb's data pointer/length. This bug was introduced by commit debfc6008169 ("mwifiex: update AP WMM settings from BSS_START event") Signed-off-by: Amitkumar Karwar Signed-off-by: Nishant Sarmukadam Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/uap_event.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 492a8b3c636e..46c972a650a4 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -41,6 +41,8 @@ static int mwifiex_check_uap_capabilties(struct mwifiex_private *priv, mwifiex_dbg_dump(priv->adapter, EVT_D, "uap capabilties:", event->data, event->len); + skb_push(event, MWIFIEX_BSS_START_EVT_FIX_SIZE); + while ((evt_len >= sizeof(tlv_hdr->header))) { tlv_hdr = (struct mwifiex_ie_types_data *)curr; tlv_len = le16_to_cpu(tlv_hdr->header.len); -- cgit v1.3-6-gb490 From 5d7e73ba2fd54b17aa8a9f0bcc228a4200d094ad Mon Sep 17 00:00:00 2001 From: Guy Mishol Date: Mon, 27 Jul 2015 17:25:49 +0300 Subject: wlcore: add antenna diversity reading comments add comments to the antenna diversity reading Signed-off-by: Guy Mishol Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/rx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index 7df672a84530..5b2927391d1c 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -74,6 +74,12 @@ static void wl1271_rx_status(struct wl1271 *wl, if (desc->rate <= wl->hw_min_ht_rate) status->flag |= RX_FLAG_HT; + /* + * Read the signal level and antenna diversity indication. + * The msb in the signal level is always set as it is a + * negative number. + * The antenna indication is the msb of the rssi. + */ status->signal = ((desc->rssi & RSSI_LEVEL_BITMASK) | BIT(7)); status->antenna = ((desc->rssi & ANT_DIVERSITY_BITMASK) >> 7); -- cgit v1.3-6-gb490 From 46c5bfdda3de91ba4324d73403af7dfb60f5ee38 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 12 Jun 2015 13:30:12 +0530 Subject: clockevents/drivers/arm_arch_timer: Migrate to new 'set-state' interface Migrate arm_arch_timer driver to the new 'set-state' interface provided by the clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Marc Zyngier Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/arm_arch_timer.c | 52 +++++++++++++++--------------------- 1 file changed, 22 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 0aa135ddbf80..d6e3e49399dd 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -181,44 +181,36 @@ static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id) return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt); } -static __always_inline void timer_set_mode(const int access, int mode, - struct clock_event_device *clk) +static __always_inline int timer_shutdown(const int access, + struct clock_event_device *clk) { unsigned long ctrl; - switch (mode) { - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); - ctrl &= ~ARCH_TIMER_CTRL_ENABLE; - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); - break; - default: - break; - } + + ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); + ctrl &= ~ARCH_TIMER_CTRL_ENABLE; + arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); + + return 0; } -static void arch_timer_set_mode_virt(enum clock_event_mode mode, - struct clock_event_device *clk) +static int arch_timer_shutdown_virt(struct clock_event_device *clk) { - timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode, clk); + return timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk); } -static void arch_timer_set_mode_phys(enum clock_event_mode mode, - struct clock_event_device *clk) +static int arch_timer_shutdown_phys(struct clock_event_device *clk) { - timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode, clk); + return timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk); } -static void arch_timer_set_mode_virt_mem(enum clock_event_mode mode, - struct clock_event_device *clk) +static int arch_timer_shutdown_virt_mem(struct clock_event_device *clk) { - timer_set_mode(ARCH_TIMER_MEM_VIRT_ACCESS, mode, clk); + return timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk); } -static void arch_timer_set_mode_phys_mem(enum clock_event_mode mode, - struct clock_event_device *clk) +static int arch_timer_shutdown_phys_mem(struct clock_event_device *clk) { - timer_set_mode(ARCH_TIMER_MEM_PHYS_ACCESS, mode, clk); + return timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk); } static __always_inline void set_next_event(const int access, unsigned long evt, @@ -273,11 +265,11 @@ static void __arch_timer_setup(unsigned type, clk->cpumask = cpumask_of(smp_processor_id()); if (arch_timer_use_virtual) { clk->irq = arch_timer_ppi[VIRT_PPI]; - clk->set_mode = arch_timer_set_mode_virt; + clk->set_state_shutdown = arch_timer_shutdown_virt; clk->set_next_event = arch_timer_set_next_event_virt; } else { clk->irq = arch_timer_ppi[PHYS_SECURE_PPI]; - clk->set_mode = arch_timer_set_mode_phys; + clk->set_state_shutdown = arch_timer_shutdown_phys; clk->set_next_event = arch_timer_set_next_event_phys; } } else { @@ -286,17 +278,17 @@ static void __arch_timer_setup(unsigned type, clk->rating = 400; clk->cpumask = cpu_all_mask; if (arch_timer_mem_use_virtual) { - clk->set_mode = arch_timer_set_mode_virt_mem; + clk->set_state_shutdown = arch_timer_shutdown_virt_mem; clk->set_next_event = arch_timer_set_next_event_virt_mem; } else { - clk->set_mode = arch_timer_set_mode_phys_mem; + clk->set_state_shutdown = arch_timer_shutdown_phys_mem; clk->set_next_event = arch_timer_set_next_event_phys_mem; } } - clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, clk); + clk->set_state_shutdown(clk); clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); } @@ -506,7 +498,7 @@ static void arch_timer_stop(struct clock_event_device *clk) disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]); } - clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk); + clk->set_state_shutdown(clk); } static int arch_timer_cpu_notify(struct notifier_block *self, -- cgit v1.3-6-gb490 From e511e6c3cd9baa3177f29aeb30c4ac7150c5f93b Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 12 Jun 2015 13:30:13 +0530 Subject: clockevents/drivers/arm_global_timer: Migrate to new 'set-state' interface Migrate arm_global_timer driver to the new 'set-state' interface provided by the clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Acked-by: Daniel Lezcano Acked-by: Maxime Coquelin Acked-by: Srinivas Kandagatla Cc: Srinivas Kandagatla Cc: Maxime Coquelin Cc: Patrice Chotard Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/arm_global_timer.c | 37 ++++++++++++++++------------------ 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index e6833771a716..29ea50ac366a 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -107,26 +107,21 @@ static void gt_compare_set(unsigned long delta, int periodic) writel(ctrl, gt_base + GT_CONTROL); } -static void gt_clockevent_set_mode(enum clock_event_mode mode, - struct clock_event_device *clk) +static int gt_clockevent_shutdown(struct clock_event_device *evt) { unsigned long ctrl; - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - gt_compare_set(DIV_ROUND_CLOSEST(gt_clk_rate, HZ), 1); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - ctrl = readl(gt_base + GT_CONTROL); - ctrl &= ~(GT_CONTROL_COMP_ENABLE | - GT_CONTROL_IRQ_ENABLE | GT_CONTROL_AUTO_INC); - writel(ctrl, gt_base + GT_CONTROL); - break; - default: - break; - } + ctrl = readl(gt_base + GT_CONTROL); + ctrl &= ~(GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE | + GT_CONTROL_AUTO_INC); + writel(ctrl, gt_base + GT_CONTROL); + return 0; +} + +static int gt_clockevent_set_periodic(struct clock_event_device *evt) +{ + gt_compare_set(DIV_ROUND_CLOSEST(gt_clk_rate, HZ), 1); + return 0; } static int gt_clockevent_set_next_event(unsigned long evt, @@ -155,7 +150,7 @@ static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id) * the Global Timer flag _after_ having incremented * the Comparator register value to a higher value. */ - if (evt->mode == CLOCK_EVT_MODE_ONESHOT) + if (clockevent_state_oneshot(evt)) gt_compare_set(ULONG_MAX, 0); writel_relaxed(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS); @@ -171,7 +166,9 @@ static int gt_clockevents_init(struct clock_event_device *clk) clk->name = "arm_global_timer"; clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERCPU; - clk->set_mode = gt_clockevent_set_mode; + clk->set_state_shutdown = gt_clockevent_shutdown; + clk->set_state_periodic = gt_clockevent_set_periodic; + clk->set_state_oneshot = gt_clockevent_shutdown; clk->set_next_event = gt_clockevent_set_next_event; clk->cpumask = cpumask_of(cpu); clk->rating = 300; @@ -184,7 +181,7 @@ static int gt_clockevents_init(struct clock_event_device *clk) static void gt_clockevents_stop(struct clock_event_device *clk) { - gt_clockevent_set_mode(CLOCK_EVT_MODE_UNUSED, clk); + gt_clockevent_shutdown(clk); disable_percpu_irq(clk->irq); } -- cgit v1.3-6-gb490 From 4996978490f7e48f29408e499c7e542ac1e2c5b8 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 12 Jun 2015 13:30:14 +0530 Subject: clockevents/drivers/bcm2835: Migrate to new 'set-state' interface Migrate bcm2835 driver to the new 'set-state' interface provided by the clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Acked-by: Daniel Lezcano Tested-by: Stephen Warren Cc: Stephen Warren Cc: Lee Jones Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/bcm2835_timer.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 26ed331b1aad..6f2822928963 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -54,21 +54,6 @@ static u64 notrace bcm2835_sched_read(void) return readl_relaxed(system_clock); } -static void bcm2835_time_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt_dev) -{ - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - break; - default: - WARN(1, "%s: unhandled event mode %d\n", __func__, mode); - break; - } -} - static int bcm2835_time_set_next_event(unsigned long event, struct clock_event_device *evt_dev) { @@ -129,7 +114,6 @@ static void __init bcm2835_timer_init(struct device_node *node) timer->evt.name = node->name; timer->evt.rating = 300; timer->evt.features = CLOCK_EVT_FEAT_ONESHOT; - timer->evt.set_mode = bcm2835_time_set_mode; timer->evt.set_next_event = bcm2835_time_set_next_event; timer->evt.cpumask = cpumask_of(0); timer->act.name = node->name; -- cgit v1.3-6-gb490 From b4cf5d710fdf297692d5c0f36cddbbeaa690e323 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 12 Jun 2015 13:30:15 +0530 Subject: clockevents/drivers/bcm_kona: Migrate to new 'set-state' interface Migrate bcm_kona driver to the new 'set-state' interface provided by the clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Oneshot callback isn't required as it was empty. Acked-by: Ray Jui Cc: Florian Fainelli Cc: Ray Jui Cc: Scott Branden Cc: bcm-kernel-feedback-list@broadcom.com Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/bcm_kona_timer.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index f1e33d08dd83..e717e87df9bc 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -127,25 +127,18 @@ static int kona_timer_set_next_event(unsigned long clc, return 0; } -static void kona_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *unused) +static int kona_timer_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - /* by default mode is one shot don't do any thing */ - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - kona_timer_disable_and_clear(timers.tmr_regs); - } + kona_timer_disable_and_clear(timers.tmr_regs); + return 0; } static struct clock_event_device kona_clockevent_timer = { .name = "timer 1", .features = CLOCK_EVT_FEAT_ONESHOT, .set_next_event = kona_timer_set_next_event, - .set_mode = kona_timer_set_mode + .set_state_shutdown = kona_timer_shutdown, + .tick_resume = kona_timer_shutdown, }; static void __init kona_timer_clockevents_init(void) -- cgit v1.3-6-gb490 From 8f9327cbb6e87ce1bed3e5dfbac70d8a96c6d1cc Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 12 Jun 2015 13:30:16 +0530 Subject: clockevents/drivers/cs5535: Migrate to new 'set-state' interface Migrate cs5535 driver to the new 'set-state' interface provided by the clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Acked-by: Daniel Lezcano Cc: Andres Salomon Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/cs5535-clockevt.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/cs5535-clockevt.c index db2105290898..9a7e37cf56b0 100644 --- a/drivers/clocksource/cs5535-clockevt.c +++ b/drivers/clocksource/cs5535-clockevt.c @@ -42,7 +42,6 @@ MODULE_PARM_DESC(irq, "Which IRQ to use for the clock source MFGPT ticks."); * 256 128 .125 512.000 */ -static unsigned int cs5535_tick_mode = CLOCK_EVT_MODE_SHUTDOWN; static struct cs5535_mfgpt_timer *cs5535_event_clock; /* Selected from the table above */ @@ -77,15 +76,17 @@ static void start_timer(struct cs5535_mfgpt_timer *timer, uint16_t delta) MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); } -static void mfgpt_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int mfgpt_shutdown(struct clock_event_device *evt) { disable_timer(cs5535_event_clock); + return 0; +} - if (mode == CLOCK_EVT_MODE_PERIODIC) - start_timer(cs5535_event_clock, MFGPT_PERIODIC); - - cs5535_tick_mode = mode; +static int mfgpt_set_periodic(struct clock_event_device *evt) +{ + disable_timer(cs5535_event_clock); + start_timer(cs5535_event_clock, MFGPT_PERIODIC); + return 0; } static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) @@ -97,7 +98,10 @@ static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) static struct clock_event_device cs5535_clockevent = { .name = DRV_NAME, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = mfgpt_set_mode, + .set_state_shutdown = mfgpt_shutdown, + .set_state_periodic = mfgpt_set_periodic, + .set_state_oneshot = mfgpt_shutdown, + .tick_resume = mfgpt_shutdown, .set_next_event = mfgpt_next_event, .rating = 250, }; @@ -113,7 +117,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id) /* Turn off the clock (and clear the event) */ disable_timer(cs5535_event_clock); - if (cs5535_tick_mode == CLOCK_EVT_MODE_SHUTDOWN) + if (clockevent_state_shutdown(&cs5535_clockevent)) return IRQ_HANDLED; /* Clear the counter */ @@ -121,7 +125,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id) /* Restart the clock in periodic mode */ - if (cs5535_tick_mode == CLOCK_EVT_MODE_PERIODIC) + if (clockevent_state_periodic(&cs5535_clockevent)) cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); -- cgit v1.3-6-gb490 From 75f940615aa93cb681b36e355b3f9509d955f547 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 12 Jun 2015 13:30:17 +0530 Subject: clockevents/drivers/em_sti: Migrate to new 'set-state' interface Migrate em_sti driver to the new 'set-state' interface provided by the clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. NOTE: This also drops a special check: if (old_mode == CLOCK_EVT_MODE_ONESHOT) em_sti_stop(p, USER_CLOCKEVENT); as it doesn't look like that important. This driver only supports ONESHOT and we can only move only to SHUTDOWN from ONESHOT and. Also on second call (on shutdown), em_sti_stop() would return without disabling the device again. Acked-by: Daniel Lezcano Cc: Magnus Damm Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/em_sti.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index dc3c6ee04aaa..7a97a34dba70 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c @@ -251,33 +251,21 @@ static struct em_sti_priv *ced_to_em_sti(struct clock_event_device *ced) return container_of(ced, struct em_sti_priv, ced); } -static void em_sti_clock_event_mode(enum clock_event_mode mode, - struct clock_event_device *ced) +static int em_sti_clock_event_shutdown(struct clock_event_device *ced) { struct em_sti_priv *p = ced_to_em_sti(ced); + em_sti_stop(p, USER_CLOCKEVENT); + return 0; +} - /* deal with old setting first */ - switch (ced->mode) { - case CLOCK_EVT_MODE_ONESHOT: - em_sti_stop(p, USER_CLOCKEVENT); - break; - default: - break; - } +static int em_sti_clock_event_set_oneshot(struct clock_event_device *ced) +{ + struct em_sti_priv *p = ced_to_em_sti(ced); - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - dev_info(&p->pdev->dev, "used for oneshot clock events\n"); - em_sti_start(p, USER_CLOCKEVENT); - clockevents_config(&p->ced, p->rate); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - em_sti_stop(p, USER_CLOCKEVENT); - break; - default: - break; - } + dev_info(&p->pdev->dev, "used for oneshot clock events\n"); + em_sti_start(p, USER_CLOCKEVENT); + clockevents_config(&p->ced, p->rate); + return 0; } static int em_sti_clock_event_next(unsigned long delta, @@ -303,11 +291,12 @@ static void em_sti_register_clockevent(struct em_sti_priv *p) ced->rating = 200; ced->cpumask = cpu_possible_mask; ced->set_next_event = em_sti_clock_event_next; - ced->set_mode = em_sti_clock_event_mode; + ced->set_state_shutdown = em_sti_clock_event_shutdown; + ced->set_state_oneshot = em_sti_clock_event_set_oneshot; dev_info(&p->pdev->dev, "used for clock events\n"); - /* Register with dummy 1 Hz value, gets updated in ->set_mode() */ + /* Register with dummy 1 Hz value, gets updated in ->set_state_oneshot() */ clockevents_config_and_register(ced, 1, 2, 0xffffffff); } -- cgit v1.3-6-gb490 From 9176c6657b5c313cf504d157e6d91496ee5c8708 Mon Sep 17 00:00:00 2001 From: Sifan Naeem Date: Thu, 6 Aug 2015 10:33:01 +0100 Subject: spi: img-spfi: fix kbuild test robot warning drivers/spi/spi-img-spfi.c: In function 'img_spfi_setup': drivers/spi/spi-img-spfi.c:446: warning: 'ret' may be used uninitialized in this function. Fixes: commit b03ba9e314c1 ("spi: img-spfi: fix multiple calls to request gpio") Signed-off-by: Sifan Naeem Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-img-spfi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index 1ba90562d72a..61f7748aba4d 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -443,7 +443,7 @@ static int img_spfi_unprepare(struct spi_master *master, static int img_spfi_setup(struct spi_device *spi) { - int ret; + int ret = -EINVAL; struct img_spfi_device_data *spfi_data = spi_get_ctldata(spi); if (!spfi_data) { -- cgit v1.3-6-gb490 From c201d00f4a4c004482aec7de1bffdfe2d85e65cf Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 6 Aug 2015 14:09:35 +0200 Subject: drm/omap: Fixup compile fail Maarten didn't fully test his patches on all drm drivers and apparently missed a few places when grepping. Cc: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/omapdrm/omap_crtc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 23d9c928cdc9..9a4ba4f03567 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -388,11 +388,13 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc) copy_timings_drm_to_omap(&omap_crtc->timings, mode); } -static void omap_crtc_atomic_begin(struct drm_crtc *crtc) +static void omap_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { } -static void omap_crtc_atomic_flush(struct drm_crtc *crtc) +static void omap_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -- cgit v1.3-6-gb490 From b8017d6c33be9862505a9154e302c4b00cbfca43 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:57:56 +0530 Subject: drm/fb_helper: Add drm_fb_helper functions to manage fb_info creation Every drm driver calls framebuffer_alloc, fb_alloc_cmap, unregister_framebuffer, fb_dealloc_cmap and framebuffer_release in order to emulate fbdev support. Create drm_fb_helper functions that perform the above operations. This is part of an effort to prevent drm drivers from calling fbdev functions directly. It also removes repetitive code from drivers. There are some drivers that call alloc_apertures after framebuffer_alloc and some that don't. Make the helper always call alloc_apertures. This would make certain drivers allocate memory for apertures but not use them. Since it's a small amount of memory, it shouldn't be an issue. v2: - Added kerneldocs - Added a check for non-NULL fb_helper before proceeding. This will make the helpers work when we have a module param for fbdev emulation Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 80 +++++++++++++++++++++++++++++++++++++++++ include/drm/drm_fb_helper.h | 4 +++ 2 files changed, 84 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 73f90f7e2f74..714c8af80180 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -654,6 +654,86 @@ out_free: } EXPORT_SYMBOL(drm_fb_helper_init); +/** + * drm_fb_helper_alloc_fbi - allocate fb_info and some of its members + * @fb_helper: driver-allocated fbdev helper + * + * A helper to alloc fb_info and the members cmap and apertures. Called + * by the driver within the fb_probe fb_helper callback function. + * + * RETURNS: + * fb_info pointer if things went okay, pointer containing error code + * otherwise + */ +struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper) +{ + struct device *dev = fb_helper->dev->dev; + struct fb_info *info; + int ret; + + info = framebuffer_alloc(0, dev); + if (!info) + return ERR_PTR(-ENOMEM); + + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) + goto err_release; + + info->apertures = alloc_apertures(1); + if (!info->apertures) { + ret = -ENOMEM; + goto err_free_cmap; + } + + fb_helper->fbdev = info; + + return info; + +err_free_cmap: + fb_dealloc_cmap(&info->cmap); +err_release: + framebuffer_release(info); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(drm_fb_helper_alloc_fbi); + +/** + * drm_fb_helper_unregister_fbi - unregister fb_info framebuffer device + * @fb_helper: driver-allocated fbdev helper + * + * A wrapper around unregister_framebuffer, to release the fb_info + * framebuffer device + */ +void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper) +{ + if (fb_helper && fb_helper->fbdev) + unregister_framebuffer(fb_helper->fbdev); +} +EXPORT_SYMBOL(drm_fb_helper_unregister_fbi); + +/** + * drm_fb_helper_release_fbi - dealloc fb_info and its members + * @fb_helper: driver-allocated fbdev helper + * + * A helper to free memory taken by fb_info and the members cmap and + * apertures + */ +void drm_fb_helper_release_fbi(struct drm_fb_helper *fb_helper) +{ + if (fb_helper) { + struct fb_info *info = fb_helper->fbdev; + + if (info) { + if (info->cmap.len) + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + } + + fb_helper->fbdev = NULL; + } +} +EXPORT_SYMBOL(drm_fb_helper_release_fbi); + void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) { if (!list_empty(&fb_helper->kernel_fb_list)) { diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 0dfd94def593..2ee4ec53efc1 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -136,6 +136,10 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, struct fb_info *info); bool drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper); + +struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper); +void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper); +void drm_fb_helper_release_fbi(struct drm_fb_helper *fb_helper); void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, uint32_t fb_width, uint32_t fb_height); void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, -- cgit v1.3-6-gb490 From 47074ab7951c1fcfc3ff637eb8401c3a71272057 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:57:57 +0530 Subject: drm/fb_helper: Create a wrapper for unlink_framebuffer Some drm drivers call unlink_framebuffer. Create a drm_fb_helper function that wraps around these calls. This is part of an effort to prevent drm drivers from calling fbdev functions directly, in order to make fbdev emulation a top level drm option. v2: - Added kerneldocs - Added a check for non-NULL fb_helper before proceeding. This will make the helpers work when we have a module param for fbdev emulation Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 13 +++++++++++++ include/drm/drm_fb_helper.h | 2 ++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 714c8af80180..5383c3f7d0ec 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -748,6 +748,19 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_fini); +/** + * drm_fb_helper_unlink_fbi - wrapper around unlink_framebuffer + * @fb_helper: driver-allocated fbdev helper + * + * A wrapper around unlink_framebuffer implemented by fbdev core + */ +void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper) +{ + if (fb_helper && fb_helper->fbdev) + unlink_framebuffer(fb_helper->fbdev); +} +EXPORT_SYMBOL(drm_fb_helper_unlink_fbi); + static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, u16 regno, struct fb_info *info) { diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 2ee4ec53efc1..4c908370a61e 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -145,6 +145,8 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, uint32_t depth); +void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper); + int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); -- cgit v1.3-6-gb490 From cbb1a82e5608fd6511940d27c231f0f4e2495b04 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:21:41 +0530 Subject: drm/fb_helper: Create wrappers for fb_sys_read/write funcs Some drm drivers populate their fb_ops with fb_sys_read/write fb sysfs ops. Create a drm_fb_helper function that wraps around these calls. This is part of an effort to prevent drm drivers from calling fbdev functions directly, in order to make fbdev emulation a top level drm option. v3: - Fix kerneldoc errors v2: - Added kerneldocs - Follow the drm way of aligning of arguments in func definitions - Remove unnecessary checks for non NULL fb_info Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/drm/drm_fb_helper.c | 32 ++++++++++++++++++++++++++++++++ include/drm/drm_fb_helper.h | 5 +++++ 3 files changed, 38 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index c46ca311d8c3..6ab503b387db 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -37,6 +37,7 @@ config DRM_KMS_FB_HELPER select FB select FRAMEBUFFER_CONSOLE if !EXPERT select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE + select FB_SYS_FOPS help FBDEV helpers for KMS drivers. diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 5383c3f7d0ec..39f3be2f37a2 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -761,6 +761,38 @@ void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_unlink_fbi); +/** + * drm_fb_helper_sys_read - wrapper around fb_sys_read + * @info: fb_info struct pointer + * @buf: userspace buffer to read from framebuffer memory + * @count: number of bytes to read from framebuffer memory + * @ppos: read offset within framebuffer memory + * + * A wrapper around fb_sys_read implemented by fbdev core + */ +ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, + size_t count, loff_t *ppos) +{ + return fb_sys_read(info, buf, count, ppos); +} +EXPORT_SYMBOL(drm_fb_helper_sys_read); + +/** + * drm_fb_helper_sys_write - wrapper around fb_sys_write + * @info: fb_info struct pointer + * @buf: userspace buffer to write to framebuffer memory + * @count: number of bytes to write to framebuffer memory + * @ppos: write offset within framebuffer memory + * + * A wrapper around fb_sys_write implemented by fbdev core + */ +ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) +{ + return fb_sys_write(info, buf, count, ppos); +} +EXPORT_SYMBOL(drm_fb_helper_sys_write); + static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, u16 regno, struct fb_info *info) { diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 4c908370a61e..fc123685baf4 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -147,6 +147,11 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper); +ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, + size_t count, loff_t *ppos); +ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos); + int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); -- cgit v1.3-6-gb490 From 742547b73d27e7bce2d0dd0f1b95692436f30950 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:21:42 +0530 Subject: drm/fb_helper: Create wrappers for blit, copyarea and fillrect funcs drm drivers that emulate fbdev populate their fb_fillrect, fb_copyarea and fb_imageblit fb_ops with the help of cfb_* or sys_* fbdev core helper functions. Create drm_fb_helper functions that wrap around these calls. This is part of an effort to prevent drm drivers from calling fbdev functions directly, in order to make fbdev emulation a top level drm option. v3: - Fixed kerneldoc errors v2: - Added kerneldocs - Follow the drm way of aligning of arguments in func definitions - Remove unnecessary checks for non NULL fb_info Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/Kconfig | 6 +++ drivers/gpu/drm/drm_fb_helper.c | 84 +++++++++++++++++++++++++++++++++++++++++ include/drm/drm_fb_helper.h | 14 +++++++ 3 files changed, 104 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 6ab503b387db..35a8c0bf360f 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -38,6 +38,12 @@ config DRM_KMS_FB_HELPER select FRAMEBUFFER_CONSOLE if !EXPERT select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE select FB_SYS_FOPS + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT help FBDEV helpers for KMS drivers. diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 39f3be2f37a2..e63350114c06 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -793,6 +793,90 @@ ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, } EXPORT_SYMBOL(drm_fb_helper_sys_write); +/** + * drm_fb_helper_sys_fillrect - wrapper around sys_fillrect + * @info: fbdev registered by the helper + * @rect: info about rectangle to fill + * + * A wrapper around sys_fillrect implemented by fbdev core + */ +void drm_fb_helper_sys_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + sys_fillrect(info, rect); +} +EXPORT_SYMBOL(drm_fb_helper_sys_fillrect); + +/** + * drm_fb_helper_sys_copyarea - wrapper around sys_copyarea + * @info: fbdev registered by the helper + * @area: info about area to copy + * + * A wrapper around sys_copyarea implemented by fbdev core + */ +void drm_fb_helper_sys_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + sys_copyarea(info, area); +} +EXPORT_SYMBOL(drm_fb_helper_sys_copyarea); + +/** + * drm_fb_helper_sys_imageblit - wrapper around sys_imageblit + * @info: fbdev registered by the helper + * @image: info about image to blit + * + * A wrapper around sys_imageblit implemented by fbdev core + */ +void drm_fb_helper_sys_imageblit(struct fb_info *info, + const struct fb_image *image) +{ + sys_imageblit(info, image); +} +EXPORT_SYMBOL(drm_fb_helper_sys_imageblit); + +/** + * drm_fb_helper_cfb_fillrect - wrapper around cfb_fillrect + * @info: fbdev registered by the helper + * @rect: info about rectangle to fill + * + * A wrapper around cfb_imageblit implemented by fbdev core + */ +void drm_fb_helper_cfb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ + cfb_fillrect(info, rect); +} +EXPORT_SYMBOL(drm_fb_helper_cfb_fillrect); + +/** + * drm_fb_helper_cfb_copyarea - wrapper around cfb_copyarea + * @info: fbdev registered by the helper + * @area: info about area to copy + * + * A wrapper around cfb_copyarea implemented by fbdev core + */ +void drm_fb_helper_cfb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ + cfb_copyarea(info, area); +} +EXPORT_SYMBOL(drm_fb_helper_cfb_copyarea); + +/** + * drm_fb_helper_cfb_imageblit - wrapper around cfb_imageblit + * @info: fbdev registered by the helper + * @image: info about image to blit + * + * A wrapper around cfb_imageblit implemented by fbdev core + */ +void drm_fb_helper_cfb_imageblit(struct fb_info *info, + const struct fb_image *image) +{ + cfb_imageblit(info, image); +} +EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit); + static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, u16 regno, struct fb_info *info) { diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index fc123685baf4..180290e62918 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -152,6 +152,20 @@ ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf, ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos); +void drm_fb_helper_sys_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +void drm_fb_helper_sys_copyarea(struct fb_info *info, + const struct fb_copyarea *area); +void drm_fb_helper_sys_imageblit(struct fb_info *info, + const struct fb_image *image); + +void drm_fb_helper_cfb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +void drm_fb_helper_cfb_copyarea(struct fb_info *info, + const struct fb_copyarea *area); +void drm_fb_helper_cfb_imageblit(struct fb_info *info, + const struct fb_image *image); + int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); -- cgit v1.3-6-gb490 From fdefa58a5097b397ce2d3f6b6f8caa14aacfb70d Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:21:43 +0530 Subject: drm/fb_helper: Create a wrapper for fb_set_suspend Some drm drivers call fb_set_suspend. Create a drm_fb_helper function that wraps around these calls. This is part of an effort to prevent drm drivers from calling fbdev functions directly, in order to make fbdev emulation a top level drm option. v3: - Fixed kerneldoc errors v2: - Added kerneldocs - Added a check for non-NULL fb_helper before proceeding. This will make the helpers work when we have a module param for fbdev emulation - Follow the drm way of aligning of arguments in func definitions Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 14 ++++++++++++++ include/drm/drm_fb_helper.h | 2 ++ 2 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index e63350114c06..c1cb7537a18f 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -877,6 +877,20 @@ void drm_fb_helper_cfb_imageblit(struct fb_info *info, } EXPORT_SYMBOL(drm_fb_helper_cfb_imageblit); +/** + * drm_fb_helper_set_suspend - wrapper around fb_set_suspend + * @fb_helper: driver-allocated fbdev helper + * @state: desired state, zero to resume, non-zero to suspend + * + * A wrapper around fb_set_suspend implemented by fbdev core + */ +void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state) +{ + if (fb_helper && fb_helper->fbdev) + fb_set_suspend(fb_helper->fbdev, state); +} +EXPORT_SYMBOL(drm_fb_helper_set_suspend); + static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, u16 regno, struct fb_info *info) { diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 180290e62918..ef32500e07fc 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -166,6 +166,8 @@ void drm_fb_helper_cfb_copyarea(struct fb_info *info, void drm_fb_helper_cfb_imageblit(struct fb_info *info, const struct fb_image *image); +void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, int state); + int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); -- cgit v1.3-6-gb490 From df3b031cef742e924aa96fec7fc128d2611e4c1f Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:58:03 +0530 Subject: drm/rockchip: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. This is an effort to create a top level drm fbdev emulation option. Cc: Mark Yao Cc: Daniel Vetter Cc: Rob Clark Cc: Daniel Kurtz Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c | 47 +++++++-------------------- 1 file changed, 12 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c index 5b0dc0f6fd94..f261512bb4a0 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c @@ -37,9 +37,9 @@ static int rockchip_fbdev_mmap(struct fb_info *info, static struct fb_ops rockchip_drm_fbdev_ops = { .owner = THIS_MODULE, .fb_mmap = rockchip_fbdev_mmap, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, .fb_blank = drm_fb_helper_blank, @@ -77,10 +77,10 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, private->fbdev_bo = &rk_obj->base; - fbi = framebuffer_alloc(0, dev->dev); - if (!fbi) { - dev_err(dev->dev, "Failed to allocate framebuffer info.\n"); - ret = -ENOMEM; + fbi = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(fbi)) { + dev_err(dev->dev, "Failed to create framebuffer info.\n"); + ret = PTR_ERR(fbi); goto err_rockchip_gem_free_object; } @@ -89,21 +89,13 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, if (IS_ERR(helper->fb)) { dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n"); ret = PTR_ERR(helper->fb); - goto err_framebuffer_release; + goto err_release_fbi; } - helper->fbdev = fbi; - fbi->par = helper; fbi->flags = FBINFO_FLAG_DEFAULT; fbi->fbops = &rockchip_drm_fbdev_ops; - ret = fb_alloc_cmap(&fbi->cmap, 256, 0); - if (ret) { - dev_err(dev->dev, "Failed to allocate color map.\n"); - goto err_drm_framebuffer_unref; - } - fb = helper->fb; drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); @@ -124,10 +116,8 @@ static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper, return 0; -err_drm_framebuffer_unref: - drm_framebuffer_unreference(helper->fb); -err_framebuffer_release: - framebuffer_release(fbi); +err_release_fbi: + drm_fb_helper_release_fbi(helper); err_rockchip_gem_free_object: rockchip_gem_free_object(&rk_obj->base); return ret; @@ -190,21 +180,8 @@ void rockchip_drm_fbdev_fini(struct drm_device *dev) helper = &private->fbdev_helper; - if (helper->fbdev) { - struct fb_info *info; - int ret; - - info = helper->fbdev; - ret = unregister_framebuffer(info); - if (ret < 0) - DRM_DEBUG_KMS("failed unregister_framebuffer() - %d\n", - ret); - - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(helper); + drm_fb_helper_release_fbi(helper); if (helper->fb) drm_framebuffer_unreference(helper->fb); -- cgit v1.3-6-gb490 From e8b70e4dd7b5dad7c2379de6e0851587bf86bfd6 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:58:04 +0530 Subject: drm/armada: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. Cc: Russell King Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/armada/armada_fbdev.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/armada/armada_fbdev.c b/drivers/gpu/drm/armada/armada_fbdev.c index 7838e731b0de..7d03c51abcb9 100644 --- a/drivers/gpu/drm/armada/armada_fbdev.c +++ b/drivers/gpu/drm/armada/armada_fbdev.c @@ -22,9 +22,9 @@ static /*const*/ struct fb_ops armada_fb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_pan_display = drm_fb_helper_pan_display, .fb_blank = drm_fb_helper_blank, .fb_setcmap = drm_fb_helper_setcmap, @@ -80,18 +80,12 @@ static int armada_fb_create(struct drm_fb_helper *fbh, if (IS_ERR(dfb)) return PTR_ERR(dfb); - info = framebuffer_alloc(0, dev->dev); - if (!info) { - ret = -ENOMEM; + info = drm_fb_helper_alloc_fbi(fbh); + if (IS_ERR(info)) { + ret = PTR_ERR(info); goto err_fballoc; } - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto err_fbcmap; - } - strlcpy(info->fix.id, "armada-drmfb", sizeof(info->fix.id)); info->par = fbh; info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; @@ -101,7 +95,7 @@ static int armada_fb_create(struct drm_fb_helper *fbh, info->screen_size = obj->obj.size; info->screen_base = ptr; fbh->fb = &dfb->fb; - fbh->fbdev = info; + drm_fb_helper_fill_fix(info, dfb->fb.pitches[0], dfb->fb.depth); drm_fb_helper_fill_var(info, fbh, sizes->fb_width, sizes->fb_height); @@ -111,8 +105,6 @@ static int armada_fb_create(struct drm_fb_helper *fbh, return 0; - err_fbcmap: - framebuffer_release(info); err_fballoc: dfb->fb.funcs->destroy(&dfb->fb); return ret; @@ -171,6 +163,7 @@ int armada_fbdev_init(struct drm_device *dev) return 0; err_fb_setup: + drm_fb_helper_release_fbi(fbh); drm_fb_helper_fini(fbh); err_fb_helper: priv->fbdev = NULL; @@ -191,14 +184,8 @@ void armada_fbdev_fini(struct drm_device *dev) struct drm_fb_helper *fbh = priv->fbdev; if (fbh) { - struct fb_info *info = fbh->fbdev; - - if (info) { - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(fbh); + drm_fb_helper_release_fbi(fbh); drm_fb_helper_fini(fbh); -- cgit v1.3-6-gb490 From 990e8440f2f8b9428125a32805c67ab22e78a7d9 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:58:05 +0530 Subject: drm/ast: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. Cleaned up the error handling in astfb_create a bit. v2: - removed unused variable 'device' in astfb_create Cc: David Airlie Cc: "Y.C. Chen" Cc: Alex Deucher Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/ast/ast_fb.c | 48 ++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index ff68eefae273..f31db28a684b 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c @@ -125,7 +125,7 @@ static void ast_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct ast_fbdev *afbdev = info->par; - sys_fillrect(info, rect); + drm_fb_helper_sys_fillrect(info, rect); ast_dirty_update(afbdev, rect->dx, rect->dy, rect->width, rect->height); } @@ -134,7 +134,7 @@ static void ast_copyarea(struct fb_info *info, const struct fb_copyarea *area) { struct ast_fbdev *afbdev = info->par; - sys_copyarea(info, area); + drm_fb_helper_sys_copyarea(info, area); ast_dirty_update(afbdev, area->dx, area->dy, area->width, area->height); } @@ -143,7 +143,7 @@ static void ast_imageblit(struct fb_info *info, const struct fb_image *image) { struct ast_fbdev *afbdev = info->par; - sys_imageblit(info, image); + drm_fb_helper_sys_imageblit(info, image); ast_dirty_update(afbdev, image->dx, image->dy, image->width, image->height); } @@ -193,7 +193,6 @@ static int astfb_create(struct drm_fb_helper *helper, struct drm_framebuffer *fb; struct fb_info *info; int size, ret; - struct device *device = &dev->pdev->dev; void *sysram; struct drm_gem_object *gobj = NULL; struct ast_bo *bo = NULL; @@ -217,40 +216,28 @@ static int astfb_create(struct drm_fb_helper *helper, if (!sysram) return -ENOMEM; - info = framebuffer_alloc(0, device); - if (!info) { - ret = -ENOMEM; - goto out; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) { + ret = PTR_ERR(info); + goto err_free_vram; } info->par = afbdev; ret = ast_framebuffer_init(dev, &afbdev->afb, &mode_cmd, gobj); if (ret) - goto out; + goto err_release_fbi; afbdev->sysram = sysram; afbdev->size = size; fb = &afbdev->afb.base; afbdev->helper.fb = fb; - afbdev->helper.fbdev = info; strcpy(info->fix.id, "astdrmfb"); info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; info->fbops = &astfb_ops; - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto out; - } - - info->apertures = alloc_apertures(1); - if (!info->apertures) { - ret = -ENOMEM; - goto out; - } info->apertures->ranges[0].base = pci_resource_start(dev->pdev, 0); info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0); @@ -266,7 +253,11 @@ static int astfb_create(struct drm_fb_helper *helper, fb->width, fb->height); return 0; -out: + +err_release_fbi: + drm_fb_helper_release_fbi(helper); +err_free_vram: + vfree(afbdev->sysram); return ret; } @@ -297,15 +288,10 @@ static const struct drm_fb_helper_funcs ast_fb_helper_funcs = { static void ast_fbdev_destroy(struct drm_device *dev, struct ast_fbdev *afbdev) { - struct fb_info *info; struct ast_framebuffer *afb = &afbdev->afb; - if (afbdev->helper.fbdev) { - info = afbdev->helper.fbdev; - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + + drm_fb_helper_unregister_fbi(&afbdev->helper); + drm_fb_helper_release_fbi(&afbdev->helper); if (afb->obj) { drm_gem_object_unreference_unlocked(afb->obj); @@ -377,5 +363,5 @@ void ast_fbdev_set_suspend(struct drm_device *dev, int state) if (!ast->fbdev) return; - fb_set_suspend(ast->fbdev->helper.fbdev, state); + drm_fb_helper_set_suspend(&ast->fbdev->helper, state); } -- cgit v1.3-6-gb490 From 0f7d9052fb705e629c3f998051e835c97eb44749 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:58:07 +0530 Subject: drm/tegra: Use new drm_fb_helper functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v2: - Fix up error handling path in tegra_fbdev_probe Cc: Thierry Reding Cc: "Terje Bergström" Cc: Stephen Warren Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/tegra/fb.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 397fb34d5d5b..07c844b746b4 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -184,9 +184,9 @@ unreference: #ifdef CONFIG_DRM_TEGRA_FBDEV static struct fb_ops tegra_fb_ops = { .owner = THIS_MODULE, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + .fb_fillrect = drm_fb_helper_sys_fillrect, + .fb_copyarea = drm_fb_helper_sys_copyarea, + .fb_imageblit = drm_fb_helper_sys_imageblit, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, .fb_blank = drm_fb_helper_blank, @@ -224,11 +224,11 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, if (IS_ERR(bo)) return PTR_ERR(bo); - info = framebuffer_alloc(0, drm->dev); - if (!info) { + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) { dev_err(drm->dev, "failed to allocate framebuffer info\n"); drm_gem_object_unreference_unlocked(&bo->gem); - return -ENOMEM; + return PTR_ERR(info); } fbdev->fb = tegra_fb_alloc(drm, &cmd, &bo, 1); @@ -248,12 +248,6 @@ static int tegra_fbdev_probe(struct drm_fb_helper *helper, info->flags = FBINFO_FLAG_DEFAULT; info->fbops = &tegra_fb_ops; - err = fb_alloc_cmap(&info->cmap, 256, 0); - if (err < 0) { - dev_err(drm->dev, "failed to allocate color map: %d\n", err); - goto destroy; - } - drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, helper, fb->width, fb->height); @@ -282,7 +276,7 @@ destroy: drm_framebuffer_unregister_private(fb); tegra_fb_destroy(fb); release: - framebuffer_release(info); + drm_fb_helper_release_fbi(helper); return err; } @@ -347,20 +341,9 @@ fini: static void tegra_fbdev_exit(struct tegra_fbdev *fbdev) { - struct fb_info *info = fbdev->base.fbdev; - - if (info) { - int err; - err = unregister_framebuffer(info); - if (err < 0) - DRM_DEBUG_KMS("failed to unregister framebuffer\n"); - - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&fbdev->base); + drm_fb_helper_release_fbi(&fbdev->base); if (fbdev->fb) { drm_framebuffer_unregister_private(&fbdev->fb->base); -- cgit v1.3-6-gb490 From 778014f0c80815e5e1ff079343da9673cb4db1a4 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:58:08 +0530 Subject: drm/msm: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. Cc: Rob Clark Cc: Stephane Viau Cc: Hai Li Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/msm/msm_fbdev.c | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c index 95f6532df02d..f97a1964ef39 100644 --- a/drivers/gpu/drm/msm/msm_fbdev.c +++ b/drivers/gpu/drm/msm/msm_fbdev.c @@ -43,11 +43,11 @@ static struct fb_ops msm_fb_ops = { /* Note: to properly handle manual update displays, we wrap the * basic fbdev ops which write to the framebuffer */ - .fb_read = fb_sys_read, - .fb_write = fb_sys_write, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + .fb_read = drm_fb_helper_sys_read, + .fb_write = drm_fb_helper_sys_write, + .fb_fillrect = drm_fb_helper_sys_fillrect, + .fb_copyarea = drm_fb_helper_sys_copyarea, + .fb_imageblit = drm_fb_helper_sys_imageblit, .fb_mmap = msm_fbdev_mmap, .fb_check_var = drm_fb_helper_check_var, @@ -144,10 +144,10 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, goto fail_unlock; } - fbi = framebuffer_alloc(0, dev->dev); - if (!fbi) { + fbi = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(fbi)) { dev_err(dev->dev, "failed to allocate fb info\n"); - ret = -ENOMEM; + ret = PTR_ERR(fbi); goto fail_unlock; } @@ -155,7 +155,6 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, fbdev->fb = fb; helper->fb = fb; - helper->fbdev = fbi; fbi->par = helper; fbi->flags = FBINFO_DEFAULT; @@ -163,12 +162,6 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, strcpy(fbi->fix.id, "msm"); - ret = fb_alloc_cmap(&fbi->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto fail_unlock; - } - drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); @@ -191,7 +184,6 @@ fail_unlock: fail: if (ret) { - framebuffer_release(fbi); if (fb) { drm_framebuffer_unregister_private(fb); drm_framebuffer_remove(fb); @@ -266,17 +258,11 @@ void msm_fbdev_free(struct drm_device *dev) struct msm_drm_private *priv = dev->dev_private; struct drm_fb_helper *helper = priv->fbdev; struct msm_fbdev *fbdev; - struct fb_info *fbi; DBG(); - fbi = helper->fbdev; - - /* only cleanup framebuffer if it is present */ - if (fbi) { - unregister_framebuffer(fbi); - framebuffer_release(fbi); - } + drm_fb_helper_unregister_fbi(helper); + drm_fb_helper_release_fbi(helper); drm_fb_helper_fini(helper); -- cgit v1.3-6-gb490 From 7c7d4507fb04bbeab44755162394951bc29146fb Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:58:09 +0530 Subject: drm/exynos: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v2: - Remove unnecessary dealloc cmap in error handling path Cc: Inki Dae Cc: Joonyoung Shim Cc: Seung-Woo Kim Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 47 ++++++++----------------------- 1 file changed, 12 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index e0b085b4bdfa..dd64bc04ffbb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -65,9 +65,9 @@ static int exynos_drm_fb_mmap(struct fb_info *info, static struct fb_ops exynos_drm_fb_ops = { .owner = THIS_MODULE, .fb_mmap = exynos_drm_fb_mmap, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, .fb_blank = drm_fb_helper_blank, @@ -142,10 +142,10 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, mutex_lock(&dev->struct_mutex); - fbi = framebuffer_alloc(0, &pdev->dev); - if (!fbi) { + fbi = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(fbi)) { DRM_ERROR("failed to allocate fb info.\n"); - ret = -ENOMEM; + ret = PTR_ERR(fbi); goto out; } @@ -165,7 +165,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, if (IS_ERR(exynos_gem_obj)) { ret = PTR_ERR(exynos_gem_obj); - goto err_release_framebuffer; + goto err_release_fbi; } exynos_fbdev->exynos_gem_obj = exynos_gem_obj; @@ -178,33 +178,23 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, goto err_destroy_gem; } - helper->fbdev = fbi; - fbi->par = helper; fbi->flags = FBINFO_FLAG_DEFAULT; fbi->fbops = &exynos_drm_fb_ops; - ret = fb_alloc_cmap(&fbi->cmap, 256, 0); - if (ret) { - DRM_ERROR("failed to allocate cmap.\n"); - goto err_destroy_framebuffer; - } - ret = exynos_drm_fbdev_update(helper, sizes, helper->fb); if (ret < 0) - goto err_dealloc_cmap; + goto err_destroy_framebuffer; mutex_unlock(&dev->struct_mutex); return ret; -err_dealloc_cmap: - fb_dealloc_cmap(&fbi->cmap); err_destroy_framebuffer: drm_framebuffer_cleanup(helper->fb); err_destroy_gem: exynos_drm_gem_destroy(exynos_gem_obj); -err_release_framebuffer: - framebuffer_release(fbi); +err_release_fbi: + drm_fb_helper_release_fbi(helper); /* * if failed, all resources allocated above would be released by @@ -312,21 +302,8 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev, } } - /* release linux framebuffer */ - if (fb_helper->fbdev) { - struct fb_info *info; - int ret; - - info = fb_helper->fbdev; - ret = unregister_framebuffer(info); - if (ret < 0) - DRM_DEBUG_KMS("failed unregister_framebuffer()\n"); - - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(fb_helper); + drm_fb_helper_release_fbi(fb_helper); drm_fb_helper_fini(fb_helper); } -- cgit v1.3-6-gb490 From 546187c85d4d4eab6f71dabbfda76672a69af434 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:58:10 +0530 Subject: drm/gma500: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v2: - removed unused variable 'device' in psbfb_create Cc: Patrik Jakobsson Cc: Daniel Vetter Signed-off-by: Archit Taneja Reviewed-by: Patrik Jakobsson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/gma500/accel_2d.c | 6 ++--- drivers/gpu/drm/gma500/framebuffer.c | 48 ++++++++++++------------------------ 2 files changed, 19 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/gma500/accel_2d.c b/drivers/gpu/drm/gma500/accel_2d.c index de6f62a6ceb7..db9f7d011832 100644 --- a/drivers/gpu/drm/gma500/accel_2d.c +++ b/drivers/gpu/drm/gma500/accel_2d.c @@ -276,12 +276,12 @@ static void psbfb_copyarea_accel(struct fb_info *info, break; default: /* software fallback */ - cfb_copyarea(info, a); + drm_fb_helper_cfb_copyarea(info, a); return; } if (!gma_power_begin(dev, false)) { - cfb_copyarea(info, a); + drm_fb_helper_cfb_copyarea(info, a); return; } psb_accel_2d_copy(dev_priv, @@ -308,7 +308,7 @@ void psbfb_copyarea(struct fb_info *info, /* Avoid the 8 pixel erratum */ if (region->width == 8 || region->height == 8 || (info->flags & FBINFO_HWACCEL_DISABLED)) - return cfb_copyarea(info, region); + return drm_fb_helper_cfb_copyarea(info, region); psbfb_copyarea_accel(info, region); } diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 2d42ce6d3757..2eaf1b31c7bd 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -194,9 +194,9 @@ static struct fb_ops psbfb_ops = { .fb_set_par = drm_fb_helper_set_par, .fb_blank = drm_fb_helper_blank, .fb_setcolreg = psbfb_setcolreg, - .fb_fillrect = cfb_fillrect, + .fb_fillrect = drm_fb_helper_cfb_fillrect, .fb_copyarea = psbfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_mmap = psbfb_mmap, .fb_sync = psbfb_sync, .fb_ioctl = psbfb_ioctl, @@ -208,9 +208,9 @@ static struct fb_ops psbfb_roll_ops = { .fb_set_par = drm_fb_helper_set_par, .fb_blank = drm_fb_helper_blank, .fb_setcolreg = psbfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_pan_display = psbfb_pan, .fb_mmap = psbfb_mmap, .fb_ioctl = psbfb_ioctl, @@ -222,9 +222,9 @@ static struct fb_ops psbfb_unaccel_ops = { .fb_set_par = drm_fb_helper_set_par, .fb_blank = drm_fb_helper_blank, .fb_setcolreg = psbfb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_mmap = psbfb_mmap, .fb_ioctl = psbfb_ioctl, }; @@ -343,7 +343,6 @@ static int psbfb_create(struct psb_fbdev *fbdev, struct drm_framebuffer *fb; struct psb_framebuffer *psbfb = &fbdev->pfb; struct drm_mode_fb_cmd2 mode_cmd; - struct device *device = &dev->pdev->dev; int size; int ret; struct gtt_range *backing; @@ -409,9 +408,9 @@ static int psbfb_create(struct psb_fbdev *fbdev, mutex_lock(&dev->struct_mutex); - info = framebuffer_alloc(0, device); - if (!info) { - ret = -ENOMEM; + info = drm_fb_helper_alloc_fbi(&fbdev->psb_fb_helper); + if (IS_ERR(info)) { + ret = PTR_ERR(info); goto out_err1; } info->par = fbdev; @@ -426,7 +425,6 @@ static int psbfb_create(struct psb_fbdev *fbdev, psbfb->fbdev = info; fbdev->psb_fb_helper.fb = fb; - fbdev->psb_fb_helper.fbdev = info; drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); strcpy(info->fix.id, "psbdrmfb"); @@ -440,12 +438,6 @@ static int psbfb_create(struct psb_fbdev *fbdev, } else /* Software */ info->fbops = &psbfb_unaccel_ops; - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto out_unref; - } - info->fix.smem_start = dev->mode_config.fb_base; info->fix.smem_len = size; info->fix.ywrapstep = gtt_roll; @@ -456,11 +448,6 @@ static int psbfb_create(struct psb_fbdev *fbdev, info->screen_size = size; if (dev_priv->gtt.stolen_size) { - info->apertures = alloc_apertures(1); - if (!info->apertures) { - ret = -ENOMEM; - goto out_unref; - } info->apertures->ranges[0].base = dev->mode_config.fb_base; info->apertures->ranges[0].size = dev_priv->gtt.stolen_size; } @@ -483,6 +470,8 @@ out_unref: psb_gtt_free_range(dev, backing); else drm_gem_object_unreference(&backing->gem); + + drm_fb_helper_release_fbi(&fbdev->psb_fb_helper); out_err1: mutex_unlock(&dev->struct_mutex); psb_gtt_free_range(dev, backing); @@ -570,16 +559,11 @@ static const struct drm_fb_helper_funcs psb_fb_helper_funcs = { static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev) { - struct fb_info *info; struct psb_framebuffer *psbfb = &fbdev->pfb; - if (fbdev->psb_fb_helper.fbdev) { - info = fbdev->psb_fb_helper.fbdev; - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&fbdev->psb_fb_helper); + drm_fb_helper_release_fbi(&fbdev->psb_fb_helper); + drm_fb_helper_fini(&fbdev->psb_fb_helper); drm_framebuffer_unregister_private(&psbfb->base); drm_framebuffer_cleanup(&psbfb->base); -- cgit v1.3-6-gb490 From e7cd84cf7da4e28749ae8b05fcd706db32496320 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:58:13 +0530 Subject: drm/qxl: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. Cc: David Airlie Cc: Frediano Ziglio Cc: Maarten Lankhorst Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/qxl/qxl_fb.c | 40 +++++++++++++--------------------------- 1 file changed, 13 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index 6b6e57e8c2d6..41c422fee31a 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -197,7 +197,7 @@ static void qxl_fb_fillrect(struct fb_info *info, { struct qxl_fbdev *qfbdev = info->par; - sys_fillrect(info, rect); + drm_fb_helper_sys_fillrect(info, rect); qxl_dirty_update(qfbdev, rect->dx, rect->dy, rect->width, rect->height); } @@ -207,7 +207,7 @@ static void qxl_fb_copyarea(struct fb_info *info, { struct qxl_fbdev *qfbdev = info->par; - sys_copyarea(info, area); + drm_fb_helper_sys_copyarea(info, area); qxl_dirty_update(qfbdev, area->dx, area->dy, area->width, area->height); } @@ -217,7 +217,7 @@ static void qxl_fb_imageblit(struct fb_info *info, { struct qxl_fbdev *qfbdev = info->par; - sys_imageblit(info, image); + drm_fb_helper_sys_imageblit(info, image); qxl_dirty_update(qfbdev, image->dx, image->dy, image->width, image->height); } @@ -345,7 +345,6 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev, struct drm_mode_fb_cmd2 mode_cmd; struct drm_gem_object *gobj = NULL; struct qxl_bo *qbo = NULL; - struct device *device = &qdev->pdev->dev; int ret; int size; int bpp = sizes->surface_bpp; @@ -374,9 +373,9 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev, shadow); size = mode_cmd.pitches[0] * mode_cmd.height; - info = framebuffer_alloc(0, device); - if (info == NULL) { - ret = -ENOMEM; + info = drm_fb_helper_alloc_fbi(&qfbdev->helper); + if (IS_ERR(info)) { + ret = PTR_ERR(info); goto out_unref; } @@ -388,7 +387,7 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev, /* setup helper with fb data */ qfbdev->helper.fb = fb; - qfbdev->helper.fbdev = info; + qfbdev->shadow = shadow; strcpy(info->fix.id, "qxldrmfb"); @@ -410,11 +409,6 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev, sizes->fb_height); /* setup aperture base/size for vesafb takeover */ - info->apertures = alloc_apertures(1); - if (!info->apertures) { - ret = -ENOMEM; - goto out_unref; - } info->apertures->ranges[0].base = qdev->ddev->mode_config.fb_base; info->apertures->ranges[0].size = qdev->vram_size; @@ -423,13 +417,7 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev, if (info->screen_base == NULL) { ret = -ENOSPC; - goto out_unref; - } - - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto out_unref; + goto out_destroy_fbi; } info->fbdefio = &qxl_defio; @@ -441,6 +429,8 @@ static int qxlfb_create(struct qxl_fbdev *qfbdev, DRM_INFO("fb: depth %d, pitch %d, width %d, height %d\n", fb->depth, fb->pitches[0], fb->width, fb->height); return 0; +out_destroy_fbi: + drm_fb_helper_release_fbi(&qfbdev->helper); out_unref: if (qbo) { ret = qxl_bo_reserve(qbo, false); @@ -479,15 +469,11 @@ static int qxl_fb_find_or_create_single( static int qxl_fbdev_destroy(struct drm_device *dev, struct qxl_fbdev *qfbdev) { - struct fb_info *info; struct qxl_framebuffer *qfb = &qfbdev->qfb; - if (qfbdev->helper.fbdev) { - info = qfbdev->helper.fbdev; + drm_fb_helper_unregister_fbi(&qfbdev->helper); + drm_fb_helper_release_fbi(&qfbdev->helper); - unregister_framebuffer(info); - framebuffer_release(info); - } if (qfb->obj) { qxlfb_destroy_pinned_object(qfb->obj); qfb->obj = NULL; @@ -557,7 +543,7 @@ void qxl_fbdev_fini(struct qxl_device *qdev) void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state) { - fb_set_suspend(qdev->mode_info.qfbdev->helper.fbdev, state); + drm_fb_helper_set_suspend(&qdev->mode_info.qfbdev->helper, state); } bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj) -- cgit v1.3-6-gb490 From 41ba2f3415741c28c589fd5734237d062c3d54fc Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:58:16 +0530 Subject: drm/udl: Use new drm_fb_helper functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v2: - remove unused variable device in udlfb_create Cc: David Airlie Cc: Haixia Shi Cc: "Stéphane Marchesin" Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/udl/udl_fb.c | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 5fc16cecd3ba..62c7b1dafaa4 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -288,7 +288,7 @@ static void udl_fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect { struct udl_fbdev *ufbdev = info->par; - sys_fillrect(info, rect); + drm_fb_helper_sys_fillrect(info, rect); udl_handle_damage(&ufbdev->ufb, rect->dx, rect->dy, rect->width, rect->height); @@ -298,7 +298,7 @@ static void udl_fb_copyarea(struct fb_info *info, const struct fb_copyarea *regi { struct udl_fbdev *ufbdev = info->par; - sys_copyarea(info, region); + drm_fb_helper_sys_copyarea(info, region); udl_handle_damage(&ufbdev->ufb, region->dx, region->dy, region->width, region->height); @@ -308,7 +308,7 @@ static void udl_fb_imageblit(struct fb_info *info, const struct fb_image *image) { struct udl_fbdev *ufbdev = info->par; - sys_imageblit(info, image); + drm_fb_helper_sys_imageblit(info, image); udl_handle_damage(&ufbdev->ufb, image->dx, image->dy, image->width, image->height); @@ -476,7 +476,6 @@ static int udlfb_create(struct drm_fb_helper *helper, container_of(helper, struct udl_fbdev, helper); struct drm_device *dev = ufbdev->helper.dev; struct fb_info *info; - struct device *device = dev->dev; struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd; struct udl_gem_object *obj; @@ -506,21 +505,20 @@ static int udlfb_create(struct drm_fb_helper *helper, goto out_gfree; } - info = framebuffer_alloc(0, device); - if (!info) { - ret = -ENOMEM; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) { + ret = PTR_ERR(info); goto out_gfree; } info->par = ufbdev; ret = udl_framebuffer_init(dev, &ufbdev->ufb, &mode_cmd, obj); if (ret) - goto out_gfree; + goto out_destroy_fbi; fb = &ufbdev->ufb.base; ufbdev->helper.fb = fb; - ufbdev->helper.fbdev = info; strcpy(info->fix.id, "udldrmfb"); @@ -533,18 +531,13 @@ static int udlfb_create(struct drm_fb_helper *helper, drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, &ufbdev->helper, sizes->fb_width, sizes->fb_height); - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto out_gfree; - } - - DRM_DEBUG_KMS("allocated %dx%d vmal %p\n", fb->width, fb->height, ufbdev->ufb.obj->vmapping); return ret; +out_destroy_fbi: + drm_fb_helper_release_fbi(helper); out_gfree: drm_gem_object_unreference(&ufbdev->ufb.obj->base); out: @@ -558,14 +551,8 @@ static const struct drm_fb_helper_funcs udl_fb_helper_funcs = { static void udl_fbdev_destroy(struct drm_device *dev, struct udl_fbdev *ufbdev) { - struct fb_info *info; - if (ufbdev->helper.fbdev) { - info = ufbdev->helper.fbdev; - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&ufbdev->helper); + drm_fb_helper_release_fbi(&ufbdev->helper); drm_fb_helper_fini(&ufbdev->helper); drm_framebuffer_unregister_private(&ufbdev->ufb.base); drm_framebuffer_cleanup(&ufbdev->ufb.base); @@ -631,11 +618,7 @@ void udl_fbdev_unplug(struct drm_device *dev) return; ufbdev = udl->fbdev; - if (ufbdev->helper.fbdev) { - struct fb_info *info; - info = ufbdev->helper.fbdev; - unlink_framebuffer(info); - } + drm_fb_helper_unlink_fbi(&ufbdev->helper); } struct drm_framebuffer * -- cgit v1.3-6-gb490 From 85f2edf2115d6aa0d7613f96dd3903b8d5f4a56d Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 22 Jul 2015 14:58:20 +0530 Subject: drm/fb_cma_helper: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. Cc: Lars-Peter Clausen Cc: Daniel Vetter Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_cma_helper.c | 45 +++++++++---------------------------- 1 file changed, 11 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index f01dc25df2dc..c19a62561183 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -222,9 +222,9 @@ EXPORT_SYMBOL_GPL(drm_fb_cma_debugfs_show); static struct fb_ops drm_fbdev_cma_ops = { .owner = THIS_MODULE, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + .fb_fillrect = drm_fb_helper_sys_fillrect, + .fb_copyarea = drm_fb_helper_sys_copyarea, + .fb_imageblit = drm_fb_helper_sys_imageblit, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, .fb_blank = drm_fb_helper_blank, @@ -263,10 +263,9 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, if (IS_ERR(obj)) return -ENOMEM; - fbi = framebuffer_alloc(0, dev->dev); - if (!fbi) { - dev_err(dev->dev, "Failed to allocate framebuffer info.\n"); - ret = -ENOMEM; + fbi = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(fbi)) { + ret = PTR_ERR(fbi); goto err_drm_gem_cma_free_object; } @@ -274,23 +273,16 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, if (IS_ERR(fbdev_cma->fb)) { dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n"); ret = PTR_ERR(fbdev_cma->fb); - goto err_framebuffer_release; + goto err_fb_info_destroy; } fb = &fbdev_cma->fb->fb; helper->fb = fb; - helper->fbdev = fbi; fbi->par = helper; fbi->flags = FBINFO_FLAG_DEFAULT; fbi->fbops = &drm_fbdev_cma_ops; - ret = fb_alloc_cmap(&fbi->cmap, 256, 0); - if (ret) { - dev_err(dev->dev, "Failed to allocate color map.\n"); - goto err_drm_fb_cma_destroy; - } - drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); @@ -305,11 +297,8 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper, return 0; -err_drm_fb_cma_destroy: - drm_framebuffer_unregister_private(fb); - drm_fb_cma_destroy(fb); -err_framebuffer_release: - framebuffer_release(fbi); +err_fb_info_destroy: + drm_fb_helper_release_fbi(helper); err_drm_gem_cma_free_object: drm_gem_cma_free_object(&obj->base); return ret; @@ -385,20 +374,8 @@ EXPORT_SYMBOL_GPL(drm_fbdev_cma_init); */ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma) { - if (fbdev_cma->fb_helper.fbdev) { - struct fb_info *info; - int ret; - - info = fbdev_cma->fb_helper.fbdev; - ret = unregister_framebuffer(info); - if (ret < 0) - DRM_DEBUG_KMS("failed unregister_framebuffer()\n"); - - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&fbdev_cma->fb_helper); + drm_fb_helper_release_fbi(&fbdev_cma->fb_helper); if (fbdev_cma->fb) { drm_framebuffer_unregister_private(&fbdev_cma->fb->fb); -- cgit v1.3-6-gb490 From c50bfd08d60cefbe1714c4a53b1c325982858549 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 28 Jul 2015 13:18:40 +0200 Subject: drm/fbdev: Return -EBUSY when oopsing Trying to do anything with kms drivers when oopsing has become a failing proposition. But since we can end up in the fbdev code simply due to the console unblanking that's done unconditionally just removing our panic handler isn't enough. We need to block all fbdev callbacks when oopsing. There was already one in the blank handler, but it failed silently. That makes it impossible for drivers (like i915) who subclass these functions to figure this out. Instead consistently return -EBUSY so that everyone knows that we really don't want to be bothered right now. This also allows us to remove a pile of FIXMEs from the i915 fbdev code (since due to the failure code they now won't attempt to grab dangerous locks any more). Cc: Dave Airlie Cc: Rodrigo Vivi Reviewed-by: Rob Clark Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 24 ++++++++++++------------ drivers/gpu/drm/i915/intel_fbdev.c | 21 --------------------- 2 files changed, 12 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index c1cb7537a18f..f16eed0489f8 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -490,14 +490,6 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) struct drm_connector *connector; int i, j; - /* - * fbdev->blank can be called from irq context in case of a panic. - * Since we already have our own special panic handler which will - * restore the fbdev console mode completely, just bail out early. - */ - if (oops_in_progress) - return; - /* * For each CRTC in this fb, turn the connectors on/off. */ @@ -531,6 +523,9 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) */ int drm_fb_helper_blank(int blank, struct fb_info *info) { + if (oops_in_progress) + return -EBUSY; + switch (blank) { /* Display: On; HSync: On, VSync: On */ case FB_BLANK_UNBLANK: @@ -978,9 +973,10 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) int i, j, rc = 0; int start; - if (__drm_modeset_lock_all(dev, !!oops_in_progress)) { + if (oops_in_progress) return -EBUSY; - } + + drm_modeset_lock_all(dev); if (!drm_fb_helper_is_bound(fb_helper)) { drm_modeset_unlock_all(dev); return -EBUSY; @@ -1129,6 +1125,9 @@ int drm_fb_helper_set_par(struct fb_info *info) struct drm_fb_helper *fb_helper = info->par; struct fb_var_screeninfo *var = &info->var; + if (oops_in_progress) + return -EBUSY; + if (var->pixclock != 0) { DRM_ERROR("PIXEL CLOCK SET\n"); return -EINVAL; @@ -1154,9 +1153,10 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, int ret = 0; int i; - if (__drm_modeset_lock_all(dev, !!oops_in_progress)) { + if (oops_in_progress) return -EBUSY; - } + + drm_modeset_lock_all(dev); if (!drm_fb_helper_is_bound(fb_helper)) { drm_modeset_unlock_all(dev); return -EBUSY; diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 7eff33ff84f6..f786c9b8927e 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -55,13 +55,6 @@ static int intel_fbdev_set_par(struct fb_info *info) ret = drm_fb_helper_set_par(info); if (ret == 0) { - /* - * FIXME: fbdev presumes that all callbacks also work from - * atomic contexts and relies on that for emergency oops - * printing. KMS totally doesn't do that and the locking here is - * by far not the only place this goes wrong. Ignore this for - * now until we solve this for real. - */ mutex_lock(&fb_helper->dev->struct_mutex); intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT); mutex_unlock(&fb_helper->dev->struct_mutex); @@ -80,13 +73,6 @@ static int intel_fbdev_blank(int blank, struct fb_info *info) ret = drm_fb_helper_blank(blank, info); if (ret == 0) { - /* - * FIXME: fbdev presumes that all callbacks also work from - * atomic contexts and relies on that for emergency oops - * printing. KMS totally doesn't do that and the locking here is - * by far not the only place this goes wrong. Ignore this for - * now until we solve this for real. - */ mutex_lock(&fb_helper->dev->struct_mutex); intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT); mutex_unlock(&fb_helper->dev->struct_mutex); @@ -106,13 +92,6 @@ static int intel_fbdev_pan_display(struct fb_var_screeninfo *var, ret = drm_fb_helper_pan_display(var, info); if (ret == 0) { - /* - * FIXME: fbdev presumes that all callbacks also work from - * atomic contexts and relies on that for emergency oops - * printing. KMS totally doesn't do that and the locking here is - * by far not the only place this goes wrong. Ignore this for - * now until we solve this for real. - */ mutex_lock(&fb_helper->dev->struct_mutex); intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT); mutex_unlock(&fb_helper->dev->struct_mutex); -- cgit v1.3-6-gb490 From dd908c864d9a8347216291b4b61074777458373a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 28 Jul 2015 13:18:41 +0200 Subject: drm/fb-helper: Stop using trylocks in force_restore Since the panic handling is gone this is only used for force-restoring the fbdev/fbcon from sysrq, and that's done with a work item. No need any more to do trylocks, we can just do normal locking. Reviewed-by: Rob Clark Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index f16eed0489f8..e4bbb5309602 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -416,19 +416,10 @@ static bool drm_fb_helper_force_kernel_mode(void) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) continue; - /* - * NOTE: Use trylock mode to avoid deadlocks and sleeping in - * panic context. - */ - if (__drm_modeset_lock_all(dev, true) != 0) { - error = true; - continue; - } - + drm_modeset_lock_all(dev); ret = drm_fb_helper_restore_fbdev_mode(helper); if (ret) error = true; - drm_modeset_unlock_all(dev); } return error; -- cgit v1.3-6-gb490 From bf9e37baac6db7318862447973bd68b5acae4bef Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 28 Jul 2015 13:18:42 +0200 Subject: drm: Remove __drm_modeset_lock_all The last user is gone, no need for trylocking any more in this legacy helper. Reviewed-by: Rob Clark Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_modeset_lock.c | 52 ++++++++------------------------------ include/drm/drm_modeset_lock.h | 1 - 2 files changed, 11 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 744dfbc6a329..fba321ca4344 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -55,41 +55,27 @@ * drm_modeset_acquire_fini(&ctx); */ - /** - * __drm_modeset_lock_all - internal helper to grab all modeset locks - * @dev: DRM device - * @trylock: trylock mode for atomic contexts - * - * This is a special version of drm_modeset_lock_all() which can also be used in - * atomic contexts. Then @trylock must be set to true. + * drm_modeset_lock_all - take all modeset locks + * @dev: drm device * - * Returns: - * 0 on success or negative error code on failure. + * This function takes all modeset locks, suitable where a more fine-grained + * scheme isn't (yet) implemented. Locks must be dropped with + * drm_modeset_unlock_all. */ -int __drm_modeset_lock_all(struct drm_device *dev, - bool trylock) +void drm_modeset_lock_all(struct drm_device *dev) { struct drm_mode_config *config = &dev->mode_config; struct drm_modeset_acquire_ctx *ctx; int ret; - ctx = kzalloc(sizeof(*ctx), - trylock ? GFP_ATOMIC : GFP_KERNEL); - if (!ctx) - return -ENOMEM; + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (WARN_ON(!ctx)) + return; - if (trylock) { - if (!mutex_trylock(&config->mutex)) { - ret = -EBUSY; - goto out; - } - } else { - mutex_lock(&config->mutex); - } + mutex_lock(&config->mutex); drm_modeset_acquire_init(ctx, 0); - ctx->trylock_only = trylock; retry: ret = drm_modeset_lock(&config->connection_mutex, ctx); @@ -108,7 +94,7 @@ retry: drm_warn_on_modeset_not_all_locked(dev); - return 0; + return; fail: if (ret == -EDEADLK) { @@ -116,23 +102,7 @@ fail: goto retry; } -out: kfree(ctx); - return ret; -} -EXPORT_SYMBOL(__drm_modeset_lock_all); - -/** - * drm_modeset_lock_all - take all modeset locks - * @dev: drm device - * - * This function takes all modeset locks, suitable where a more fine-grained - * scheme isn't (yet) implemented. Locks must be dropped with - * drm_modeset_unlock_all. - */ -void drm_modeset_lock_all(struct drm_device *dev) -{ - WARN_ON(__drm_modeset_lock_all(dev, false) != 0); } EXPORT_SYMBOL(drm_modeset_lock_all); diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index 70595ff565ba..5dd18bfdf601 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -130,7 +130,6 @@ struct drm_crtc; struct drm_plane; void drm_modeset_lock_all(struct drm_device *dev); -int __drm_modeset_lock_all(struct drm_device *dev, bool trylock); void drm_modeset_unlock_all(struct drm_device *dev); void drm_modeset_lock_crtc(struct drm_crtc *crtc, struct drm_plane *plane); -- cgit v1.3-6-gb490 From f8c2ba316b64b02e43738c41b07a5d9319165f99 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 29 Jul 2015 08:32:43 +0200 Subject: drm: Fixup locking WARNINGs in drm_mode_config_reset With commit 7a3f3d6667f5f9ffd1517f6b21d64bbf5312042c Author: Daniel Vetter Date: Thu Jul 9 23:44:28 2015 +0200 drm: Check locking in drm_for_each_connector we started checking the locking in drm_for_each_connector but somehow I totally missed drm_mode_config_reset. There's no problem there since this function should only be called in single-threaded contexts (driver load or resume), so just wrap the loop with the right lock. v2: Drink coffee and all that ... Cc: Laurent Pinchart Reported-by: Laurent Pinchart Tested-by: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index dfac394d0602..7d02e32b4e94 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -5273,12 +5273,14 @@ void drm_mode_config_reset(struct drm_device *dev) if (encoder->funcs->reset) encoder->funcs->reset(encoder); + mutex_lock(&dev->mode_config.mutex); drm_for_each_connector(connector, dev) { connector->status = connector_status_unknown; if (connector->funcs->reset) connector->funcs->reset(connector); } + mutex_unlock(&dev->mode_config.mutex); } EXPORT_SYMBOL(drm_mode_config_reset); -- cgit v1.3-6-gb490 From 2b9e6e376af5171444a1cdcc134ed502e33d1fb2 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:21:44 +0530 Subject: drm/cirrus: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. v3: - Don't touch remove_conflicting_framebuffers v2: - Remove stray goto label out_iounmap Cc: Thierry Reding Cc: Zach Reizner Cc: Russell King Cc: Fabian Frederick Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/cirrus/cirrus_drv.c | 4 ++-- drivers/gpu/drm/cirrus/cirrus_fbdev.c | 41 +++++++---------------------------- 2 files changed, 10 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c index b9140032962d..b1619e29a564 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.c +++ b/drivers/gpu/drm/cirrus/cirrus_drv.c @@ -92,7 +92,7 @@ static int cirrus_pm_suspend(struct device *dev) if (cdev->mode_info.gfbdev) { console_lock(); - fb_set_suspend(cdev->mode_info.gfbdev->helper.fbdev, 1); + drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 1); console_unlock(); } @@ -109,7 +109,7 @@ static int cirrus_pm_resume(struct device *dev) if (cdev->mode_info.gfbdev) { console_lock(); - fb_set_suspend(cdev->mode_info.gfbdev->helper.fbdev, 0); + drm_fb_helper_set_suspend(&cdev->mode_info.gfbdev->helper, 0); console_unlock(); } diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index 13ddf1c4bb8e..589103bcc06c 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -98,7 +98,7 @@ static void cirrus_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct cirrus_fbdev *afbdev = info->par; - sys_fillrect(info, rect); + drm_fb_helper_sys_fillrect(info, rect); cirrus_dirty_update(afbdev, rect->dx, rect->dy, rect->width, rect->height); } @@ -107,7 +107,7 @@ static void cirrus_copyarea(struct fb_info *info, const struct fb_copyarea *area) { struct cirrus_fbdev *afbdev = info->par; - sys_copyarea(info, area); + drm_fb_helper_sys_copyarea(info, area); cirrus_dirty_update(afbdev, area->dx, area->dy, area->width, area->height); } @@ -116,7 +116,7 @@ static void cirrus_imageblit(struct fb_info *info, const struct fb_image *image) { struct cirrus_fbdev *afbdev = info->par; - sys_imageblit(info, image); + drm_fb_helper_sys_imageblit(info, image); cirrus_dirty_update(afbdev, image->dx, image->dy, image->width, image->height); } @@ -165,12 +165,10 @@ static int cirrusfb_create(struct drm_fb_helper *helper, { struct cirrus_fbdev *gfbdev = container_of(helper, struct cirrus_fbdev, helper); - struct drm_device *dev = gfbdev->helper.dev; struct cirrus_device *cdev = gfbdev->helper.dev->dev_private; struct fb_info *info; struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd; - struct device *device = &dev->pdev->dev; void *sysram; struct drm_gem_object *gobj = NULL; struct cirrus_bo *bo = NULL; @@ -195,9 +193,9 @@ static int cirrusfb_create(struct drm_fb_helper *helper, if (!sysram) return -ENOMEM; - info = framebuffer_alloc(0, device); - if (info == NULL) - return -ENOMEM; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) + return PTR_ERR(info); info->par = gfbdev; @@ -216,11 +214,9 @@ static int cirrusfb_create(struct drm_fb_helper *helper, /* setup helper */ gfbdev->helper.fb = fb; - gfbdev->helper.fbdev = info; strcpy(info->fix.id, "cirrusdrmfb"); - info->flags = FBINFO_DEFAULT; info->fbops = &cirrusfb_ops; @@ -229,11 +225,6 @@ static int cirrusfb_create(struct drm_fb_helper *helper, sizes->fb_height); /* setup aperture base/size for vesafb takeover */ - info->apertures = alloc_apertures(1); - if (!info->apertures) { - ret = -ENOMEM; - goto out_iounmap; - } info->apertures->ranges[0].base = cdev->dev->mode_config.fb_base; info->apertures->ranges[0].size = cdev->mc.vram_size; @@ -246,13 +237,6 @@ static int cirrusfb_create(struct drm_fb_helper *helper, info->fix.mmio_start = 0; info->fix.mmio_len = 0; - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - DRM_ERROR("%s: can't allocate color map\n", info->fix.id); - ret = -ENOMEM; - goto out_iounmap; - } - DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); DRM_INFO("vram aper at 0x%lX\n", (unsigned long)info->fix.smem_start); DRM_INFO("size %lu\n", (unsigned long)info->fix.smem_len); @@ -260,24 +244,15 @@ static int cirrusfb_create(struct drm_fb_helper *helper, DRM_INFO(" pitch is %d\n", fb->pitches[0]); return 0; -out_iounmap: - return ret; } static int cirrus_fbdev_destroy(struct drm_device *dev, struct cirrus_fbdev *gfbdev) { - struct fb_info *info; struct cirrus_framebuffer *gfb = &gfbdev->gfb; - if (gfbdev->helper.fbdev) { - info = gfbdev->helper.fbdev; - - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&gfbdev->helper); + drm_fb_helper_release_fbi(&gfbdev->helper); if (gfb->obj) { drm_gem_object_unreference_unlocked(gfb->obj); -- cgit v1.3-6-gb490 From 231e6faf027ae5e86539bb5a3cdb2b22a96dae8c Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:21:48 +0530 Subject: drm/omap: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v3: - Update error handling for new drm_fb_helper funcs. Check using IS_ERR() instead of checking for NULL. Reported-by: Dan Carpenter v2: - No changes Cc: Tomi Valkeinen Cc: Laurent Pinchart Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/omapdrm/omap_fbdev.c | 38 ++++++++++++------------------------ 1 file changed, 13 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 720d16bce7e8..b8e4cdec28c3 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -86,11 +86,11 @@ static struct fb_ops omap_fb_ops = { /* Note: to properly handle manual update displays, we wrap the * basic fbdev ops which write to the framebuffer */ - .fb_read = fb_sys_read, - .fb_write = fb_sys_write, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + .fb_read = drm_fb_helper_sys_read, + .fb_write = drm_fb_helper_sys_write, + .fb_fillrect = drm_fb_helper_sys_fillrect, + .fb_copyarea = drm_fb_helper_sys_copyarea, + .fb_imageblit = drm_fb_helper_sys_imageblit, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, @@ -179,10 +179,10 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, mutex_lock(&dev->struct_mutex); - fbi = framebuffer_alloc(0, dev->dev); - if (!fbi) { + fbi = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(fbi)) { dev_err(dev->dev, "failed to allocate fb info\n"); - ret = -ENOMEM; + ret = PTR_ERR(fbi); goto fail_unlock; } @@ -190,7 +190,6 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, fbdev->fb = fb; helper->fb = fb; - helper->fbdev = fbi; fbi->par = helper; fbi->flags = FBINFO_DEFAULT; @@ -198,12 +197,6 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, strcpy(fbi->fix.id, MODULE_NAME); - ret = fb_alloc_cmap(&fbi->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto fail_unlock; - } - drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); @@ -236,8 +229,9 @@ fail_unlock: fail: if (ret) { - if (fbi) - framebuffer_release(fbi); + + drm_fb_helper_release_fbi(helper); + if (fb) { drm_framebuffer_unregister_private(fb); drm_framebuffer_remove(fb); @@ -312,17 +306,11 @@ void omap_fbdev_free(struct drm_device *dev) struct omap_drm_private *priv = dev->dev_private; struct drm_fb_helper *helper = priv->fbdev; struct omap_fbdev *fbdev; - struct fb_info *fbi; DBG(); - fbi = helper->fbdev; - - /* only cleanup framebuffer if it is present */ - if (fbi) { - unregister_framebuffer(fbi); - framebuffer_release(fbi); - } + drm_fb_helper_unregister_fbi(helper); + drm_fb_helper_release_fbi(helper); drm_fb_helper_fini(helper); -- cgit v1.3-6-gb490 From 4f72a6eaedf71f3d7729086ca34703b3615f59d0 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:21:53 +0530 Subject: drm/mgag200: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v3: - Don't touch remove_conflicting_framebuffers v2: - remove unused goto label 'out' Cc: Daniel Vetter Cc: David Airlie Cc: Alex Deucher Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/mgag200/mgag200_fb.c | 39 ++++++++---------------------------- 1 file changed, 8 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c index 958cf3cf082d..87de15ea1f93 100644 --- a/drivers/gpu/drm/mgag200/mgag200_fb.c +++ b/drivers/gpu/drm/mgag200/mgag200_fb.c @@ -101,7 +101,7 @@ static void mga_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct mga_fbdev *mfbdev = info->par; - sys_fillrect(info, rect); + drm_fb_helper_sys_fillrect(info, rect); mga_dirty_update(mfbdev, rect->dx, rect->dy, rect->width, rect->height); } @@ -110,7 +110,7 @@ static void mga_copyarea(struct fb_info *info, const struct fb_copyarea *area) { struct mga_fbdev *mfbdev = info->par; - sys_copyarea(info, area); + drm_fb_helper_sys_copyarea(info, area); mga_dirty_update(mfbdev, area->dx, area->dy, area->width, area->height); } @@ -119,7 +119,7 @@ static void mga_imageblit(struct fb_info *info, const struct fb_image *image) { struct mga_fbdev *mfbdev = info->par; - sys_imageblit(info, image); + drm_fb_helper_sys_imageblit(info, image); mga_dirty_update(mfbdev, image->dx, image->dy, image->width, image->height); } @@ -166,7 +166,6 @@ static int mgag200fb_create(struct drm_fb_helper *helper, struct fb_info *info; struct drm_framebuffer *fb; struct drm_gem_object *gobj = NULL; - struct device *device = &dev->pdev->dev; int ret; void *sysram; int size; @@ -189,9 +188,9 @@ static int mgag200fb_create(struct drm_fb_helper *helper, if (!sysram) return -ENOMEM; - info = framebuffer_alloc(0, device); - if (info == NULL) - return -ENOMEM; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) + return PTR_ERR(info); info->par = mfbdev; @@ -206,14 +205,6 @@ static int mgag200fb_create(struct drm_fb_helper *helper, /* setup helper */ mfbdev->helper.fb = fb; - mfbdev->helper.fbdev = info; - - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - DRM_ERROR("%s: can't allocate color map\n", info->fix.id); - ret = -ENOMEM; - goto out; - } strcpy(info->fix.id, "mgadrmfb"); @@ -221,11 +212,6 @@ static int mgag200fb_create(struct drm_fb_helper *helper, info->fbops = &mgag200fb_ops; /* setup aperture base/size for vesafb takeover */ - info->apertures = alloc_apertures(1); - if (!info->apertures) { - ret = -ENOMEM; - goto out; - } info->apertures->ranges[0].base = mdev->dev->mode_config.fb_base; info->apertures->ranges[0].size = mdev->mc.vram_size; @@ -240,24 +226,15 @@ static int mgag200fb_create(struct drm_fb_helper *helper, DRM_DEBUG_KMS("allocated %dx%d\n", fb->width, fb->height); return 0; -out: - return ret; } static int mga_fbdev_destroy(struct drm_device *dev, struct mga_fbdev *mfbdev) { - struct fb_info *info; struct mga_framebuffer *mfb = &mfbdev->mfb; - if (mfbdev->helper.fbdev) { - info = mfbdev->helper.fbdev; - - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&mfbdev->helper); + drm_fb_helper_release_fbi(&mfbdev->helper); if (mfb->obj) { drm_gem_object_unreference_unlocked(mfb->obj); -- cgit v1.3-6-gb490 From 00450052436f87742bfb9edfb325e1337a79489c Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:21:54 +0530 Subject: drm/radeon: Use new drm_fb_helper functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v3: - Don't touch remove_conflicting_framebuffers v2: - Fix build break because of missing include of drm_fb_helper in radeon_drv.c Cc: Alex Deucher Cc: "Christian König" Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/radeon/radeon_fb.c | 42 +++++++++++--------------------------- 1 file changed, 12 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index aeb676708e60..7214858ffcea 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -82,9 +82,9 @@ static struct fb_ops radeonfb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = radeon_fb_helper_set_par, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_pan_display = drm_fb_helper_pan_display, .fb_blank = drm_fb_helper_blank, .fb_setcmap = drm_fb_helper_setcmap, @@ -227,7 +227,6 @@ static int radeonfb_create(struct drm_fb_helper *helper, struct drm_mode_fb_cmd2 mode_cmd; struct drm_gem_object *gobj = NULL; struct radeon_bo *rbo = NULL; - struct device *device = &rdev->pdev->dev; int ret; unsigned long tmp; @@ -250,9 +249,9 @@ static int radeonfb_create(struct drm_fb_helper *helper, rbo = gem_to_radeon_bo(gobj); /* okay we have an object now allocate the framebuffer */ - info = framebuffer_alloc(0, device); - if (info == NULL) { - ret = -ENOMEM; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) { + ret = PTR_ERR(info); goto out_unref; } @@ -262,14 +261,13 @@ static int radeonfb_create(struct drm_fb_helper *helper, ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj); if (ret) { DRM_ERROR("failed to initialize framebuffer %d\n", ret); - goto out_unref; + goto out_destroy_fbi; } fb = &rfbdev->rfb.base; /* setup helper */ rfbdev->helper.fb = fb; - rfbdev->helper.fbdev = info; memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo)); @@ -289,11 +287,6 @@ static int radeonfb_create(struct drm_fb_helper *helper, drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height); /* setup aperture base/size for vesafb takeover */ - info->apertures = alloc_apertures(1); - if (!info->apertures) { - ret = -ENOMEM; - goto out_unref; - } info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base; info->apertures->ranges[0].size = rdev->mc.aper_size; @@ -301,13 +294,7 @@ static int radeonfb_create(struct drm_fb_helper *helper, if (info->screen_base == NULL) { ret = -ENOSPC; - goto out_unref; - } - - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto out_unref; + goto out_destroy_fbi; } DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); @@ -319,6 +306,8 @@ static int radeonfb_create(struct drm_fb_helper *helper, vga_switcheroo_client_fb_set(rdev->ddev->pdev, info); return 0; +out_destroy_fbi: + drm_fb_helper_release_fbi(helper); out_unref: if (rbo) { @@ -339,17 +328,10 @@ void radeon_fb_output_poll_changed(struct radeon_device *rdev) static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) { - struct fb_info *info; struct radeon_framebuffer *rfb = &rfbdev->rfb; - if (rfbdev->helper.fbdev) { - info = rfbdev->helper.fbdev; - - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&rfbdev->helper); + drm_fb_helper_release_fbi(&rfbdev->helper); if (rfb->obj) { radeonfb_destroy_pinned_object(rfb->obj); -- cgit v1.3-6-gb490 From 21cff14847421ff75d110890ccea729d8ad1b174 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:21:56 +0530 Subject: drm/i915: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v3: - Don't touch remove_conflicting_framebuffers v2: - No changes Cc: Daniel Vetter Cc: Jani Nikula Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 40 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index f786c9b8927e..8c6a6fa46005 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -104,9 +104,9 @@ static struct fb_ops intelfb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = intel_fbdev_set_par, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_pan_display = intel_fbdev_pan_display, .fb_blank = intel_fbdev_blank, .fb_setcmap = drm_fb_helper_setcmap, @@ -215,9 +215,9 @@ static int intelfb_create(struct drm_fb_helper *helper, obj = intel_fb->obj; size = obj->base.size; - info = framebuffer_alloc(0, &dev->pdev->dev); - if (!info) { - ret = -ENOMEM; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) { + ret = PTR_ERR(info); goto out_unpin; } @@ -226,24 +226,13 @@ static int intelfb_create(struct drm_fb_helper *helper, fb = &ifbdev->fb->base; ifbdev->helper.fb = fb; - ifbdev->helper.fbdev = info; strcpy(info->fix.id, "inteldrmfb"); info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT; info->fbops = &intelfb_ops; - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto out_unpin; - } /* setup aperture base/size for vesafb takeover */ - info->apertures = alloc_apertures(1); - if (!info->apertures) { - ret = -ENOMEM; - goto out_unpin; - } info->apertures->ranges[0].base = dev->mode_config.fb_base; info->apertures->ranges[0].size = dev_priv->gtt.mappable_end; @@ -255,7 +244,7 @@ static int intelfb_create(struct drm_fb_helper *helper, size); if (!info->screen_base) { ret = -ENOSPC; - goto out_unpin; + goto out_destroy_fbi; } info->screen_size = size; @@ -282,6 +271,8 @@ static int intelfb_create(struct drm_fb_helper *helper, vga_switcheroo_client_fb_set(dev->pdev, info); return 0; +out_destroy_fbi: + drm_fb_helper_release_fbi(helper); out_unpin: i915_gem_object_ggtt_unpin(obj); drm_gem_object_unreference(&obj->base); @@ -523,16 +514,9 @@ static const struct drm_fb_helper_funcs intel_fb_helper_funcs = { static void intel_fbdev_destroy(struct drm_device *dev, struct intel_fbdev *ifbdev) { - if (ifbdev->helper.fbdev) { - struct fb_info *info = ifbdev->helper.fbdev; - unregister_framebuffer(info); - iounmap(info->screen_base); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&ifbdev->helper); + drm_fb_helper_release_fbi(&ifbdev->helper); drm_fb_helper_fini(&ifbdev->helper); @@ -781,7 +765,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous if (state == FBINFO_STATE_RUNNING && ifbdev->fb->obj->stolen) memset_io(info->screen_base, 0, info->screen_size); - fb_set_suspend(info, state); + drm_fb_helper_set_suspend(&ifbdev->helper, state); console_unlock(); } -- cgit v1.3-6-gb490 From b166aeb99faa0b42f75ab4f48e98afa44d6a8958 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:21:57 +0530 Subject: drm/nouveau: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v3: - Don't touch remove_conflicting_framebuffers v2: - remove unused variable pdev in nouveau_fbcon_create Cc: David Airlie Cc: Ben Skeggs Cc: Alexandre Courbot Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 39 ++++++++++----------------------- 1 file changed, 12 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 6751553abe4a..2791701685dc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -84,7 +84,7 @@ nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) if (ret != -ENODEV) nouveau_fbcon_gpu_lockup(info); - cfb_fillrect(info, rect); + drm_fb_helper_cfb_fillrect(info, rect); } static void @@ -116,7 +116,7 @@ nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image) if (ret != -ENODEV) nouveau_fbcon_gpu_lockup(info); - cfb_copyarea(info, image); + drm_fb_helper_cfb_copyarea(info, image); } static void @@ -148,7 +148,7 @@ nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) if (ret != -ENODEV) nouveau_fbcon_gpu_lockup(info); - cfb_imageblit(info, image); + drm_fb_helper_cfb_imageblit(info, image); } static int @@ -197,9 +197,9 @@ static struct fb_ops nouveau_fbcon_sw_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_pan_display = drm_fb_helper_pan_display, .fb_blank = drm_fb_helper_blank, .fb_setcmap = drm_fb_helper_setcmap, @@ -319,7 +319,6 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, struct nouveau_channel *chan; struct nouveau_bo *nvbo; struct drm_mode_fb_cmd2 mode_cmd; - struct pci_dev *pdev = dev->pdev; int size, ret; mode_cmd.width = sizes->surface_width; @@ -365,20 +364,13 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, mutex_lock(&dev->struct_mutex); - info = framebuffer_alloc(0, &pdev->dev); - if (!info) { - ret = -ENOMEM; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) { + ret = PTR_ERR(info); goto out_unlock; } info->skip_vt_switch = 1; - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - framebuffer_release(info); - goto out_unlock; - } - info->par = fbcon; nouveau_framebuffer_init(dev, &fbcon->nouveau_fb, &mode_cmd, nvbo); @@ -388,7 +380,6 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, /* setup helper */ fbcon->helper.fb = fb; - fbcon->helper.fbdev = info; strcpy(info->fix.id, "nouveaufb"); if (!chan) @@ -450,15 +441,9 @@ static int nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon) { struct nouveau_framebuffer *nouveau_fb = &fbcon->nouveau_fb; - struct fb_info *info; - if (fbcon->helper.fbdev) { - info = fbcon->helper.fbdev; - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&fbcon->helper); + drm_fb_helper_release_fbi(&fbcon->helper); if (nouveau_fb->nvbo) { nouveau_bo_unmap(nouveau_fb->nvbo); @@ -496,7 +481,7 @@ nouveau_fbcon_set_suspend(struct drm_device *dev, int state) console_lock(); if (state == FBINFO_STATE_RUNNING) nouveau_fbcon_accel_restore(dev); - fb_set_suspend(drm->fbcon->helper.fbdev, state); + drm_fb_helper_set_suspend(&drm->fbcon->helper, state); if (state != FBINFO_STATE_RUNNING) nouveau_fbcon_accel_save_disable(dev); console_unlock(); -- cgit v1.3-6-gb490 From 6a752972a33f7763453134a09ed8091bbeea55fc Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:21:59 +0530 Subject: drm/bochs: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v3: - Don't touch remove_conflicting_framebuffers v2: - remove unused variable device in bochsfb_create Cc: David Airlie Cc: Gerd Hoffmann Cc: Daniel Vetter Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/bochs/bochs_drv.c | 4 ++-- drivers/gpu/drm/bochs/bochs_fbdev.c | 36 +++++++++++------------------------- 2 files changed, 13 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c index 98837bde2d25..7f1a3604b19f 100644 --- a/drivers/gpu/drm/bochs/bochs_drv.c +++ b/drivers/gpu/drm/bochs/bochs_drv.c @@ -109,7 +109,7 @@ static int bochs_pm_suspend(struct device *dev) if (bochs->fb.initialized) { console_lock(); - fb_set_suspend(bochs->fb.helper.fbdev, 1); + drm_fb_helper_set_suspend(&bochs->fb.helper, 1); console_unlock(); } @@ -126,7 +126,7 @@ static int bochs_pm_resume(struct device *dev) if (bochs->fb.initialized) { console_lock(); - fb_set_suspend(bochs->fb.helper.fbdev, 0); + drm_fb_helper_set_suspend(&bochs->fb.helper, 0); console_unlock(); } diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c index 976d9798dc99..09a0637aab3e 100644 --- a/drivers/gpu/drm/bochs/bochs_fbdev.c +++ b/drivers/gpu/drm/bochs/bochs_fbdev.c @@ -24,9 +24,9 @@ static struct fb_ops bochsfb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + .fb_fillrect = drm_fb_helper_sys_fillrect, + .fb_copyarea = drm_fb_helper_sys_copyarea, + .fb_imageblit = drm_fb_helper_sys_imageblit, .fb_pan_display = drm_fb_helper_pan_display, .fb_blank = drm_fb_helper_blank, .fb_setcmap = drm_fb_helper_setcmap, @@ -56,11 +56,9 @@ static int bochsfb_create(struct drm_fb_helper *helper, { struct bochs_device *bochs = container_of(helper, struct bochs_device, fb.helper); - struct drm_device *dev = bochs->dev; struct fb_info *info; struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd; - struct device *device = &dev->pdev->dev; struct drm_gem_object *gobj = NULL; struct bochs_bo *bo = NULL; int size, ret; @@ -106,22 +104,23 @@ static int bochsfb_create(struct drm_fb_helper *helper, ttm_bo_unreserve(&bo->bo); /* init fb device */ - info = framebuffer_alloc(0, device); - if (info == NULL) - return -ENOMEM; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) + return PTR_ERR(info); info->par = &bochs->fb.helper; ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj); - if (ret) + if (ret) { + drm_fb_helper_release_fbi(helper); return ret; + } bochs->fb.size = size; /* setup helper */ fb = &bochs->fb.gfb.base; bochs->fb.helper.fb = fb; - bochs->fb.helper.fbdev = info; strcpy(info->fix.id, "bochsdrmfb"); @@ -139,30 +138,17 @@ static int bochsfb_create(struct drm_fb_helper *helper, info->fix.smem_start = 0; info->fix.smem_len = size; - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - DRM_ERROR("%s: can't allocate color map\n", info->fix.id); - return -ENOMEM; - } - return 0; } static int bochs_fbdev_destroy(struct bochs_device *bochs) { struct bochs_framebuffer *gfb = &bochs->fb.gfb; - struct fb_info *info; DRM_DEBUG_DRIVER("\n"); - if (bochs->fb.helper.fbdev) { - info = bochs->fb.helper.fbdev; - - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&bochs->fb.helper); + drm_fb_helper_release_fbi(&bochs->fb.helper); if (gfb->obj) { drm_gem_object_unreference_unlocked(gfb->obj); -- cgit v1.3-6-gb490 From 2dbaf392d27e8072268595fba557cbe4f4d43f01 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:22:00 +0530 Subject: drm/amdgpu: Use new drm_fb_helper functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v3: - Don't touch remove_conflicting_framebuffers v2: - Fixed PTR_ERR issue mentioned by kbuild bot Cc: Fengguang Wu Cc: Alex Deucher Cc: Oded Gabbay Cc: "Christian König" Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c | 45 +++++++++++----------------------- 1 file changed, 14 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index c1645d21f8e2..81b821247dde 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -53,9 +53,9 @@ static struct fb_ops amdgpufb_ops = { .owner = THIS_MODULE, .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = drm_fb_helper_cfb_fillrect, + .fb_copyarea = drm_fb_helper_cfb_copyarea, + .fb_imageblit = drm_fb_helper_cfb_imageblit, .fb_pan_display = drm_fb_helper_pan_display, .fb_blank = drm_fb_helper_blank, .fb_setcmap = drm_fb_helper_setcmap, @@ -179,7 +179,6 @@ static int amdgpufb_create(struct drm_fb_helper *helper, struct drm_mode_fb_cmd2 mode_cmd; struct drm_gem_object *gobj = NULL; struct amdgpu_bo *rbo = NULL; - struct device *device = &adev->pdev->dev; int ret; unsigned long tmp; @@ -201,9 +200,9 @@ static int amdgpufb_create(struct drm_fb_helper *helper, rbo = gem_to_amdgpu_bo(gobj); /* okay we have an object now allocate the framebuffer */ - info = framebuffer_alloc(0, device); - if (info == NULL) { - ret = -ENOMEM; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) { + ret = PTR_ERR(info); goto out_unref; } @@ -212,14 +211,13 @@ static int amdgpufb_create(struct drm_fb_helper *helper, ret = amdgpu_framebuffer_init(adev->ddev, &rfbdev->rfb, &mode_cmd, gobj); if (ret) { DRM_ERROR("failed to initialize framebuffer %d\n", ret); - goto out_unref; + goto out_destroy_fbi; } fb = &rfbdev->rfb.base; /* setup helper */ rfbdev->helper.fb = fb; - rfbdev->helper.fbdev = info; memset_io(rbo->kptr, 0x0, amdgpu_bo_size(rbo)); @@ -239,11 +237,6 @@ static int amdgpufb_create(struct drm_fb_helper *helper, drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height); /* setup aperture base/size for vesafb takeover */ - info->apertures = alloc_apertures(1); - if (!info->apertures) { - ret = -ENOMEM; - goto out_unref; - } info->apertures->ranges[0].base = adev->ddev->mode_config.fb_base; info->apertures->ranges[0].size = adev->mc.aper_size; @@ -251,13 +244,7 @@ static int amdgpufb_create(struct drm_fb_helper *helper, if (info->screen_base == NULL) { ret = -ENOSPC; - goto out_unref; - } - - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto out_unref; + goto out_destroy_fbi; } DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); @@ -269,6 +256,8 @@ static int amdgpufb_create(struct drm_fb_helper *helper, vga_switcheroo_client_fb_set(adev->ddev->pdev, info); return 0; +out_destroy_fbi: + drm_fb_helper_release_fbi(helper); out_unref: if (rbo) { @@ -290,17 +279,10 @@ void amdgpu_fb_output_poll_changed(struct amdgpu_device *adev) static int amdgpu_fbdev_destroy(struct drm_device *dev, struct amdgpu_fbdev *rfbdev) { - struct fb_info *info; struct amdgpu_framebuffer *rfb = &rfbdev->rfb; - if (rfbdev->helper.fbdev) { - info = rfbdev->helper.fbdev; - - unregister_framebuffer(info); - if (info->cmap.len) - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); - } + drm_fb_helper_unregister_fbi(&rfbdev->helper); + drm_fb_helper_release_fbi(&rfbdev->helper); if (rfb->obj) { amdgpufb_destroy_pinned_object(rfb->obj); @@ -395,7 +377,8 @@ void amdgpu_fbdev_fini(struct amdgpu_device *adev) void amdgpu_fbdev_set_suspend(struct amdgpu_device *adev, int state) { if (adev->mode_info.rfbdev) - fb_set_suspend(adev->mode_info.rfbdev->helper.fbdev, state); + drm_fb_helper_set_suspend(&adev->mode_info.rfbdev->helper, + state); } int amdgpu_fbdev_total_size(struct amdgpu_device *adev) -- cgit v1.3-6-gb490 From 0843010bbd60acf9e5a588828ad227937085e7b1 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 31 Jul 2015 16:22:01 +0530 Subject: drm/virtio: Use new drm_fb_helper functions Use the newly created wrapper drm_fb_helper functions instead of calling core fbdev functions directly. They also simplify the fb_info creation. v3: - Don't touch remove_conflicting_framebuffers v2: - add missing header for virtgpu_fb.c Cc: David Airlie Cc: Gerd Hoffmann Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/virtio/virtgpu_fb.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c index df198d9e770c..6a81e084593b 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fb.c +++ b/drivers/gpu/drm/virtio/virtgpu_fb.c @@ -173,7 +173,7 @@ static void virtio_gpu_3d_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct virtio_gpu_fbdev *vfbdev = info->par; - sys_fillrect(info, rect); + drm_fb_helper_sys_fillrect(info, rect); virtio_gpu_dirty_update(&vfbdev->vgfb, true, rect->dx, rect->dy, rect->width, rect->height); schedule_delayed_work(&vfbdev->work, VIRTIO_GPU_FBCON_POLL_PERIOD); @@ -183,7 +183,7 @@ static void virtio_gpu_3d_copyarea(struct fb_info *info, const struct fb_copyarea *area) { struct virtio_gpu_fbdev *vfbdev = info->par; - sys_copyarea(info, area); + drm_fb_helper_sys_copyarea(info, area); virtio_gpu_dirty_update(&vfbdev->vgfb, true, area->dx, area->dy, area->width, area->height); schedule_delayed_work(&vfbdev->work, VIRTIO_GPU_FBCON_POLL_PERIOD); @@ -193,7 +193,7 @@ static void virtio_gpu_3d_imageblit(struct fb_info *info, const struct fb_image *image) { struct virtio_gpu_fbdev *vfbdev = info->par; - sys_imageblit(info, image); + drm_fb_helper_sys_imageblit(info, image); virtio_gpu_dirty_update(&vfbdev->vgfb, true, image->dx, image->dy, image->width, image->height); schedule_delayed_work(&vfbdev->work, VIRTIO_GPU_FBCON_POLL_PERIOD); @@ -230,7 +230,6 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper, struct drm_framebuffer *fb; struct drm_mode_fb_cmd2 mode_cmd = {}; struct virtio_gpu_object *obj; - struct device *device = vgdev->dev; uint32_t resid, format, size; int ret; @@ -317,18 +316,12 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper, if (ret) goto err_obj_attach; - info = framebuffer_alloc(0, device); - if (!info) { - ret = -ENOMEM; + info = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(info)) { + ret = PTR_ERR(info); goto err_fb_alloc; } - ret = fb_alloc_cmap(&info->cmap, 256, 0); - if (ret) { - ret = -ENOMEM; - goto err_fb_alloc_cmap; - } - info->par = helper; ret = virtio_gpu_framebuffer_init(dev, &vfbdev->vgfb, @@ -339,7 +332,6 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper, fb = &vfbdev->vgfb.base; vfbdev->helper.fb = fb; - vfbdev->helper.fbdev = info; strcpy(info->fix.id, "virtiodrmfb"); info->flags = FBINFO_DEFAULT; @@ -357,9 +349,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper, return 0; err_fb_init: - fb_dealloc_cmap(&info->cmap); -err_fb_alloc_cmap: - framebuffer_release(info); + drm_fb_helper_release_fbi(helper); err_fb_alloc: virtio_gpu_cmd_resource_inval_backing(vgdev, resid); err_obj_attach: @@ -371,15 +361,11 @@ err_obj_vmap: static int virtio_gpu_fbdev_destroy(struct drm_device *dev, struct virtio_gpu_fbdev *vgfbdev) { - struct fb_info *info; struct virtio_gpu_framebuffer *vgfb = &vgfbdev->vgfb; - if (vgfbdev->helper.fbdev) { - info = vgfbdev->helper.fbdev; + drm_fb_helper_unregister_fbi(&vgfbdev->helper); + drm_fb_helper_release_fbi(&vgfbdev->helper); - unregister_framebuffer(info); - framebuffer_release(info); - } if (vgfb->obj) vgfb->obj = NULL; drm_fb_helper_fini(&vgfbdev->helper); -- cgit v1.3-6-gb490 From 55579cfe67d76394be46f00acef8854d08db5362 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 31 Jul 2015 14:08:24 +0530 Subject: drivers: gpu: Drop unlikely before IS_ERR(_OR_NULL) IS_ERR(_OR_NULL) already contain an 'unlikely' compiler flag and there is no need to do that again from its callers. Drop it. Signed-off-by: Viresh Kumar Reviewed-by: Sinclair Yeh Signed-off-by: Daniel Vetter --- drivers/gpu/drm/ttm/ttm_tt.c | 4 ++-- drivers/gpu/drm/vmwgfx/vmwgfx_context.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index bf080abc86d1..4e19d0f9cc30 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -340,7 +340,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage) swap_storage = shmem_file_setup("ttm swap", ttm->num_pages << PAGE_SHIFT, 0); - if (unlikely(IS_ERR(swap_storage))) { + if (IS_ERR(swap_storage)) { pr_err("Failed allocating swap storage\n"); return PTR_ERR(swap_storage); } @@ -354,7 +354,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage) if (unlikely(from_page == NULL)) continue; to_page = shmem_read_mapping_page(swap_space, i); - if (unlikely(IS_ERR(to_page))) { + if (IS_ERR(to_page)) { ret = PTR_ERR(to_page); goto out_err; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index 5ac92874404d..44e6ecba3de7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -159,7 +159,7 @@ static int vmw_gb_context_init(struct vmw_private *dev_priv, if (dev_priv->has_mob) { uctx->man = vmw_cmdbuf_res_man_create(dev_priv); - if (unlikely(IS_ERR(uctx->man))) { + if (IS_ERR(uctx->man)) { ret = PTR_ERR(uctx->man); uctx->man = NULL; goto out_err; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 620bb5cf617c..6218a36cf01a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1054,7 +1054,7 @@ static long vmw_generic_ioctl(struct file *filp, unsigned int cmd, return -EINVAL; vmaster = vmw_master_check(dev, file_priv, flags); - if (unlikely(IS_ERR(vmaster))) { + if (IS_ERR(vmaster)) { ret = PTR_ERR(vmaster); if (ret != -ERESTARTSYS) -- cgit v1.3-6-gb490 From 3d9e35a92e935e1f968e79f0e0b72ce4b9f14c3e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Aug 2015 15:22:10 +0200 Subject: drm/fb-helper: Clarify drm_fb_helper_restore_fbdev_mode*() As of commit 5ea1f752ae04be40 ("drm: add drm_fb_helper_restore_fbdev_mode_unlocked()"), drm_fb_helper_restore_fbdev_mode() is no longer public, and drivers should call drm_fb_helper_restore_fbdev_mode_unlocked() from their ->lastclose callbacks instead. Update the documentation to reflect this, and absorb the one liner drm_fb_helper_restore_fbdev_mode() into its single caller. Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index e4bbb5309602..7278c23ea98b 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -56,8 +56,8 @@ static LIST_HEAD(kernel_fb_helper_list); * Teardown is done with drm_fb_helper_fini(). * * At runtime drivers should restore the fbdev console by calling - * drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They - * should also notify the fb helper code from updates to the output + * drm_fb_helper_restore_fbdev_mode_unlocked() from their ->lastclose callback. + * They should also notify the fb helper code from updates to the output * configuration by calling drm_fb_helper_hotplug_event(). For easier * integration with the output polling code in drm_crtc_helper.c the modeset * code provides a ->output_poll_changed callback. @@ -354,21 +354,6 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper) } return error; } -/** - * drm_fb_helper_restore_fbdev_mode - restore fbdev configuration - * @fb_helper: fbcon to restore - * - * This should be called from driver's drm ->lastclose callback - * when implementing an fbcon on top of kms using this helper. This ensures that - * the user isn't greeted with a black screen when e.g. X dies. - * - * Use this variant if you need to bypass locking (panic), or already - * hold all modeset locks. Otherwise use drm_fb_helper_restore_fbdev_mode_unlocked() - */ -static bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) -{ - return restore_fbdev_mode(fb_helper); -} /** * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration @@ -417,7 +402,7 @@ static bool drm_fb_helper_force_kernel_mode(void) continue; drm_modeset_lock_all(dev); - ret = drm_fb_helper_restore_fbdev_mode(helper); + ret = restore_fbdev_mode(helper); if (ret) error = true; drm_modeset_unlock_all(dev); -- cgit v1.3-6-gb490 From 2c4124fdeaea4b70120da3bddf90c4587e65bbc6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Aug 2015 15:22:11 +0200 Subject: drm/fb-helper: Move drm_fb_helper_force_kernel_mode() inside #ifdef If CONFIG_MAGIC_SYSRQ is not set: drivers/gpu/drm/drm_fb_helper.c:390:13: warning: 'drm_fb_helper_force_kernel_mode' defined but not used [-Wunused-function] static bool drm_fb_helper_force_kernel_mode(void) ^ Move drm_fb_helper_force_kernel_mode() inside the existing #ifdef to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 50 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 7278c23ea98b..5875059a7625 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -383,6 +383,31 @@ bool drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) } EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked); +static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) +{ + struct drm_device *dev = fb_helper->dev; + struct drm_crtc *crtc; + int bound = 0, crtcs_bound = 0; + + /* Sometimes user space wants everything disabled, so don't steal the + * display if there's a master. */ + if (dev->primary->master) + return false; + + drm_for_each_crtc(crtc, dev) { + if (crtc->primary->fb) + crtcs_bound++; + if (crtc->primary->fb == fb_helper->fb) + bound++; + } + + if (bound < crtcs_bound) + return false; + + return true; +} + +#ifdef CONFIG_MAGIC_SYSRQ /* * restore fbcon display for all kms driver's using this helper, used for sysrq * and panic handling. @@ -410,31 +435,6 @@ static bool drm_fb_helper_force_kernel_mode(void) return error; } -static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) -{ - struct drm_device *dev = fb_helper->dev; - struct drm_crtc *crtc; - int bound = 0, crtcs_bound = 0; - - /* Sometimes user space wants everything disabled, so don't steal the - * display if there's a master. */ - if (dev->primary->master) - return false; - - drm_for_each_crtc(crtc, dev) { - if (crtc->primary->fb) - crtcs_bound++; - if (crtc->primary->fb == fb_helper->fb) - bound++; - } - - if (bound < crtcs_bound) - return false; - - return true; -} - -#ifdef CONFIG_MAGIC_SYSRQ static void drm_fb_helper_restore_work_fn(struct work_struct *ignored) { bool ret; -- cgit v1.3-6-gb490 From a03fdcb1863297481a4b817c2a759cafcbdfa0ae Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 5 Aug 2015 12:28:57 +0530 Subject: drm: Add top level Kconfig option for DRM fbdev emulation Legacy fbdev emulation support via DRM is achieved through KMS FB helpers. Most modesetting drivers enable provide fbdev emulation by default by selecting KMS FB helpers. A few provide a separate Kconfig option for the user to enable or disbale fbdev emulation. Enabling fbdev emulation is finally a distro-level decision. Having a top level Kconfig option for fbdev emulation helps by providing a uniform way to enable/disable fbdev emulation for any modesetting driver. It also lets us remove unnecessary driver specific Kconfig options that causes bloat. With a top level Kconfig in place, we can stub out the fb helper functions when not needed without breaking functionality. Having stub functions also prevents drivers to require wrapping fb helper function calls with #ifdefs. DRM_FBDEV_EMULATION defaults to y since many drivers enable fbdev emulation by default and majority of distributions expect the fbdev interface in the kernel. Signed-off-by: Archit Taneja Signed-off-by: Daniel Vetter --- drivers/gpu/drm/Kconfig | 13 ++++ drivers/gpu/drm/Makefile | 2 +- include/drm/drm_fb_helper.h | 185 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 35a8c0bf360f..06ae5008c5ed 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -47,6 +47,19 @@ config DRM_KMS_FB_HELPER help FBDEV helpers for KMS drivers. +config DRM_FBDEV_EMULATION + bool "Enable legacy fbdev support for your modesetting driver" + depends on DRM + select DRM_KMS_HELPER + select DRM_KMS_FB_HELPER + default y + help + Choose this option if you have a need for the legacy fbdev + support. Note that this support also provides the linux console + support on top of your modesetting driver. + + If in doubt, say "Y". + config DRM_LOAD_EDID_FIRMWARE bool "Allow to specify an EDID data set instead of probing for it" depends on DRM_KMS_HELPER diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 5713d0534504..8858510437ea 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -23,7 +23,7 @@ drm-$(CONFIG_OF) += drm_of.o drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o -drm_kms_helper-$(CONFIG_DRM_KMS_FB_HELPER) += drm_fb_helper.o +drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index ef32500e07fc..dbab4622b58f 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -122,6 +122,7 @@ struct drm_fb_helper { bool delayed_hotplug; }; +#ifdef CONFIG_DRM_FBDEV_EMULATION void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper, const struct drm_fb_helper_funcs *funcs); int drm_fb_helper_init(struct drm_device *dev, @@ -185,4 +186,188 @@ drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector); int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector); +#else +static inline void drm_fb_helper_prepare(struct drm_device *dev, + struct drm_fb_helper *helper, + const struct drm_fb_helper_funcs *funcs) +{ +} + +static inline int drm_fb_helper_init(struct drm_device *dev, + struct drm_fb_helper *helper, int crtc_count, + int max_conn) +{ + return 0; +} + +static inline void drm_fb_helper_fini(struct drm_fb_helper *helper) +{ +} + +static inline int drm_fb_helper_blank(int blank, struct fb_info *info) +{ + return 0; +} + +static inline int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + return 0; +} + +static inline int drm_fb_helper_set_par(struct fb_info *info) +{ + return 0; +} + +static inline int drm_fb_helper_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + return 0; +} + +static inline bool +drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) +{ + return true; +} + +static inline struct fb_info * +drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper) +{ + return NULL; +} + +static inline void drm_fb_helper_unregister_fbi(struct drm_fb_helper *fb_helper) +{ +} +static inline void drm_fb_helper_release_fbi(struct drm_fb_helper *fb_helper) +{ +} + +static inline void drm_fb_helper_fill_var(struct fb_info *info, + struct drm_fb_helper *fb_helper, + uint32_t fb_width, uint32_t fb_height) +{ +} + +static inline void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, + uint32_t depth) +{ +} + +static inline int drm_fb_helper_setcmap(struct fb_cmap *cmap, + struct fb_info *info) +{ + return 0; +} + +static inline void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper) +{ +} + +static inline ssize_t drm_fb_helper_sys_read(struct fb_info *info, + char __user *buf, size_t count, + loff_t *ppos) +{ + return -ENODEV; +} + +static inline ssize_t drm_fb_helper_sys_write(struct fb_info *info, + const char __user *buf, + size_t count, loff_t *ppos) +{ + return -ENODEV; +} + +static inline void drm_fb_helper_sys_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ +} + +static inline void drm_fb_helper_sys_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ +} + +static inline void drm_fb_helper_sys_imageblit(struct fb_info *info, + const struct fb_image *image) +{ +} + +static inline void drm_fb_helper_cfb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect) +{ +} + +static inline void drm_fb_helper_cfb_copyarea(struct fb_info *info, + const struct fb_copyarea *area) +{ +} + +static inline void drm_fb_helper_cfb_imageblit(struct fb_info *info, + const struct fb_image *image) +{ +} + +static inline void drm_fb_helper_set_suspend(struct drm_fb_helper *fb_helper, + int state) +{ +} + +static inline int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) +{ + return 0; +} + +static inline int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, + int bpp_sel) +{ + return 0; +} + +static inline int +drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) +{ + return 0; +} + +static inline int drm_fb_helper_debug_enter(struct fb_info *info) +{ + return 0; +} + +static inline int drm_fb_helper_debug_leave(struct fb_info *info) +{ + return 0; +} + +static inline struct drm_display_mode * +drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, + int width, int height) +{ + return NULL; +} + +static inline struct drm_display_mode * +drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn, + int width, int height) +{ + return NULL; +} + +static inline int +drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, + struct drm_connector *connector) +{ + return 0; +} + +static inline int +drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, + struct drm_connector *connector) +{ + return 0; +} +#endif #endif -- cgit v1.3-6-gb490 From 85430968ae72650a63f77f05a29d5c56e41581db Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 3 Aug 2015 10:35:40 +0100 Subject: iommu/arm-smmu: Treat unknown OAS as 48-bit A late change to the SMMUv3 architecture ensures that the OAS field will be monotonically increasing, so we can assume that an unknown OAS is at least 48-bit and use that, rather than fail the device probe. Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 4f093373f4c3..e51646a3b973 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -2550,12 +2550,12 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu) case IDR5_OAS_44_BIT: smmu->oas = 44; break; + default: + dev_info(smmu->dev, + "unknown output address size. Truncating to 48-bit\n"); + /* Fallthrough */ case IDR5_OAS_48_BIT: smmu->oas = 48; - break; - default: - dev_err(smmu->dev, "unknown output address size!\n"); - return -ENXIO; } /* Set the DMA mask for our table walker */ -- cgit v1.3-6-gb490 From f8d5496131554f61b0fd931fa046f0233fe2aac2 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 29 Jul 2015 19:46:04 +0100 Subject: iommu/io-pgtable-arm: Allow appropriate DMA API use Currently, users of the LPAE page table code are (ab)using dma_map_page() as a means to flush page table updates for non-coherent IOMMUs. Since from the CPU's point of view, creating IOMMU page tables *is* passing DMA buffers to a device (the IOMMU's page table walker), there's little reason not to use the DMA API correctly. Allow IOMMU drivers to opt into DMA API operations for page table allocation and updates by providing their appropriate device pointer. The expectation is that an LPAE IOMMU should have a full view of system memory, so use streaming mappings to avoid unnecessary pressure on ZONE_DMA, and treat any DMA translation as a warning sign. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/Kconfig | 3 +- drivers/iommu/io-pgtable-arm.c | 107 ++++++++++++++++++++++++++++++++--------- drivers/iommu/io-pgtable.h | 3 ++ 3 files changed, 89 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index f1fb1d3ccc56..d77a848d50de 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -23,7 +23,8 @@ config IOMMU_IO_PGTABLE config IOMMU_IO_PGTABLE_LPAE bool "ARMv7/v8 Long Descriptor Format" select IOMMU_IO_PGTABLE - depends on ARM || ARM64 || COMPILE_TEST + # SWIOTLB guarantees a dma_to_phys() implementation + depends on ARM || ARM64 || (COMPILE_TEST && SWIOTLB) help Enable support for the ARM long descriptor pagetable format. This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 4e460216bd16..28cca8a652f9 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -200,12 +200,76 @@ typedef u64 arm_lpae_iopte; static bool selftest_running = false; +static dma_addr_t __arm_lpae_dma_addr(struct device *dev, void *pages) +{ + return phys_to_dma(dev, virt_to_phys(pages)); +} + +static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp, + struct io_pgtable_cfg *cfg) +{ + struct device *dev = cfg->iommu_dev; + dma_addr_t dma; + void *pages = alloc_pages_exact(size, gfp | __GFP_ZERO); + + if (!pages) + return NULL; + + if (dev) { + dma = dma_map_single(dev, pages, size, DMA_TO_DEVICE); + if (dma_mapping_error(dev, dma)) + goto out_free; + /* + * We depend on the IOMMU being able to work with any physical + * address directly, so if the DMA layer suggests it can't by + * giving us back some translation, that bodes very badly... + */ + if (dma != __arm_lpae_dma_addr(dev, pages)) + goto out_unmap; + } + + return pages; + +out_unmap: + dev_err(dev, "Cannot accommodate DMA translation for IOMMU page tables\n"); + dma_unmap_single(dev, dma, size, DMA_TO_DEVICE); +out_free: + free_pages_exact(pages, size); + return NULL; +} + +static void __arm_lpae_free_pages(void *pages, size_t size, + struct io_pgtable_cfg *cfg) +{ + struct device *dev = cfg->iommu_dev; + + if (dev) + dma_unmap_single(dev, __arm_lpae_dma_addr(dev, pages), + size, DMA_TO_DEVICE); + free_pages_exact(pages, size); +} + +static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, arm_lpae_iopte pte, + struct io_pgtable_cfg *cfg, void *cookie) +{ + struct device *dev = cfg->iommu_dev; + + *ptep = pte; + + if (dev) + dma_sync_single_for_device(dev, __arm_lpae_dma_addr(dev, ptep), + sizeof(pte), DMA_TO_DEVICE); + else if (cfg->tlb->flush_pgtable) + cfg->tlb->flush_pgtable(ptep, sizeof(pte), cookie); +} + static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, unsigned long iova, phys_addr_t paddr, arm_lpae_iopte prot, int lvl, arm_lpae_iopte *ptep) { arm_lpae_iopte pte = prot; + struct io_pgtable_cfg *cfg = &data->iop.cfg; /* We require an unmap first */ if (iopte_leaf(*ptep, lvl)) { @@ -213,7 +277,7 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, return -EEXIST; } - if (data->iop.cfg.quirks & IO_PGTABLE_QUIRK_ARM_NS) + if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS) pte |= ARM_LPAE_PTE_NS; if (lvl == ARM_LPAE_MAX_LEVELS - 1) @@ -224,8 +288,7 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, pte |= ARM_LPAE_PTE_AF | ARM_LPAE_PTE_SH_IS; pte |= pfn_to_iopte(paddr >> data->pg_shift, data); - *ptep = pte; - data->iop.cfg.tlb->flush_pgtable(ptep, sizeof(*ptep), data->iop.cookie); + __arm_lpae_set_pte(ptep, pte, cfg, data->iop.cookie); return 0; } @@ -236,12 +299,13 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, arm_lpae_iopte *cptep, pte; void *cookie = data->iop.cookie; size_t block_size = ARM_LPAE_BLOCK_SIZE(lvl, data); + struct io_pgtable_cfg *cfg = &data->iop.cfg; /* Find our entry at the current level */ ptep += ARM_LPAE_LVL_IDX(iova, lvl, data); /* If we can install a leaf entry at this level, then do so */ - if (size == block_size && (size & data->iop.cfg.pgsize_bitmap)) + if (size == block_size && (size & cfg->pgsize_bitmap)) return arm_lpae_init_pte(data, iova, paddr, prot, lvl, ptep); /* We can't allocate tables at the final level */ @@ -251,18 +315,15 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, /* Grab a pointer to the next level */ pte = *ptep; if (!pte) { - cptep = alloc_pages_exact(1UL << data->pg_shift, - GFP_ATOMIC | __GFP_ZERO); + cptep = __arm_lpae_alloc_pages(1UL << data->pg_shift, + GFP_ATOMIC, cfg); if (!cptep) return -ENOMEM; - data->iop.cfg.tlb->flush_pgtable(cptep, 1UL << data->pg_shift, - cookie); pte = __pa(cptep) | ARM_LPAE_PTE_TYPE_TABLE; - if (data->iop.cfg.quirks & IO_PGTABLE_QUIRK_ARM_NS) + if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS) pte |= ARM_LPAE_PTE_NSTABLE; - *ptep = pte; - data->iop.cfg.tlb->flush_pgtable(ptep, sizeof(*ptep), cookie); + __arm_lpae_set_pte(ptep, pte, cfg, cookie); } else { cptep = iopte_deref(pte, data); } @@ -347,7 +408,7 @@ static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl, __arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data)); } - free_pages_exact(start, table_size); + __arm_lpae_free_pages(start, table_size, &data->iop.cfg); } static void arm_lpae_free_pgtable(struct io_pgtable *iop) @@ -366,8 +427,8 @@ static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, unsigned long blk_start, blk_end; phys_addr_t blk_paddr; arm_lpae_iopte table = 0; + struct io_pgtable_cfg *cfg = &data->iop.cfg; void *cookie = data->iop.cookie; - const struct iommu_gather_ops *tlb = data->iop.cfg.tlb; blk_start = iova & ~(blk_size - 1); blk_end = blk_start + blk_size; @@ -393,10 +454,9 @@ static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, } } - *ptep = table; - tlb->flush_pgtable(ptep, sizeof(*ptep), cookie); + __arm_lpae_set_pte(ptep, table, cfg, cookie); iova &= ~(blk_size - 1); - tlb->tlb_add_flush(iova, blk_size, true, cookie); + cfg->tlb->tlb_add_flush(iova, blk_size, true, cookie); return size; } @@ -418,13 +478,12 @@ static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, /* If the size matches this level, we're in the right place */ if (size == blk_size) { - *ptep = 0; - tlb->flush_pgtable(ptep, sizeof(*ptep), cookie); + __arm_lpae_set_pte(ptep, 0, &data->iop.cfg, cookie); if (!iopte_leaf(pte, lvl)) { /* Also flush any partial walks */ tlb->tlb_add_flush(iova, size, false, cookie); - tlb->tlb_sync(data->iop.cookie); + tlb->tlb_sync(cookie); ptep = iopte_deref(pte, data); __arm_lpae_free_pgtable(data, lvl + 1, ptep); } else { @@ -640,11 +699,12 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) cfg->arm_lpae_s1_cfg.mair[1] = 0; /* Looking good; allocate a pgd */ - data->pgd = alloc_pages_exact(data->pgd_size, GFP_KERNEL | __GFP_ZERO); + data->pgd = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg); if (!data->pgd) goto out_free_data; - cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); + if (cfg->tlb->flush_pgtable) + cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); /* TTBRs */ cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd); @@ -728,11 +788,12 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) cfg->arm_lpae_s2_cfg.vtcr = reg; /* Allocate pgd pages */ - data->pgd = alloc_pages_exact(data->pgd_size, GFP_KERNEL | __GFP_ZERO); + data->pgd = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg); if (!data->pgd) goto out_free_data; - cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); + if (cfg->tlb->flush_pgtable) + cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); /* VTTBR */ cfg->arm_lpae_s2_cfg.vttbr = virt_to_phys(data->pgd); diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h index 10e32f69c668..c69529c78914 100644 --- a/drivers/iommu/io-pgtable.h +++ b/drivers/iommu/io-pgtable.h @@ -41,6 +41,8 @@ struct iommu_gather_ops { * @ias: Input address (iova) size, in bits. * @oas: Output address (paddr) size, in bits. * @tlb: TLB management callbacks for this set of tables. + * @iommu_dev: The device representing the DMA configuration for the + * page table walker. */ struct io_pgtable_cfg { #define IO_PGTABLE_QUIRK_ARM_NS (1 << 0) /* Set NS bit in PTEs */ @@ -49,6 +51,7 @@ struct io_pgtable_cfg { unsigned int ias; unsigned int oas; const struct iommu_gather_ops *tlb; + struct device *iommu_dev; /* Low-level data specific to the table format */ union { -- cgit v1.3-6-gb490 From 2df7a25ce4a79092946330ac4b7a2fbb5944d1d6 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 29 Jul 2015 19:46:06 +0100 Subject: iommu/arm-smmu: Clean up DMA API usage With the correct DMA API calls now integrated into the io-pgtable code, let that handle the flushing of non-coherent page table updates. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 0583ed2f33c0..5770ab98fa38 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -611,24 +611,13 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, static void arm_smmu_flush_pgtable(void *addr, size_t size, void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; - struct arm_smmu_device *smmu = smmu_domain->smmu; - unsigned long offset = (unsigned long)addr & ~PAGE_MASK; - - /* Ensure new page tables are visible to the hardware walker */ - if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) { + /* + * Ensure new page tables are visible to a coherent hardware walker. + * The page table code deals with flushing for the non-coherent case. + */ + if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) dsb(ishst); - } else { - /* - * If the SMMU can't walk tables in the CPU caches, treat them - * like non-coherent DMA since we need to flush the new entries - * all the way out to memory. There's no possibility of - * recursion here as the SMMU table walker will not be wired - * through another SMMU. - */ - dma_map_page(smmu->dev, virt_to_page(addr), offset, size, - DMA_TO_DEVICE); - } } static struct iommu_gather_ops arm_smmu_gather_ops = { @@ -899,6 +888,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, .ias = ias, .oas = oas, .tlb = &arm_smmu_gather_ops, + .iommu_dev = smmu->dev, }; smmu_domain->smmu = smmu; -- cgit v1.3-6-gb490 From bdc6d973473f32891a8518c51b210ce7daaa10ac Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 29 Jul 2015 19:46:07 +0100 Subject: iommu/arm-smmu: Clean up DMA API usage With the correct DMA API calls now integrated into the io-pgtable code, let that handle the flushing of non-coherent page table updates. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index e51646a3b973..54c68d123a6d 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1334,23 +1334,10 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, static void arm_smmu_flush_pgtable(void *addr, size_t size, void *cookie) { struct arm_smmu_domain *smmu_domain = cookie; - struct arm_smmu_device *smmu = smmu_domain->smmu; - unsigned long offset = (unsigned long)addr & ~PAGE_MASK; - if (smmu->features & ARM_SMMU_FEAT_COHERENCY) { + /* The page table code handles flushing in the non-coherent case */ + if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENCY) dsb(ishst); - } else { - dma_addr_t dma_addr; - struct device *dev = smmu->dev; - - dma_addr = dma_map_page(dev, virt_to_page(addr), offset, size, - DMA_TO_DEVICE); - - if (dma_mapping_error(dev, dma_addr)) - dev_err(dev, "failed to flush pgtable at %p\n", addr); - else - dma_unmap_page(dev, dma_addr, size, DMA_TO_DEVICE); - } } static struct iommu_gather_ops arm_smmu_gather_ops = { @@ -1532,6 +1519,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain) .ias = ias, .oas = oas, .tlb = &arm_smmu_gather_ops, + .iommu_dev = smmu->dev, }; pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain); -- cgit v1.3-6-gb490 From ff2ed96dde3b30d8f1b2ab0d9b164140f2278e6e Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 29 Jul 2015 19:46:08 +0100 Subject: iommu/ipmmu-vmsa: Clean up DMA API usage With the correct DMA API calls now integrated into the io-pgtable code, let that handle the flushing of non-coherent page table updates. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/ipmmu-vmsa.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 1a67c531a07e..8cf605fa9946 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -283,24 +283,10 @@ static void ipmmu_tlb_add_flush(unsigned long iova, size_t size, bool leaf, /* The hardware doesn't support selective TLB flush. */ } -static void ipmmu_flush_pgtable(void *ptr, size_t size, void *cookie) -{ - unsigned long offset = (unsigned long)ptr & ~PAGE_MASK; - struct ipmmu_vmsa_domain *domain = cookie; - - /* - * TODO: Add support for coherent walk through CCI with DVM and remove - * cache handling. - */ - dma_map_page(domain->mmu->dev, virt_to_page(ptr), offset, size, - DMA_TO_DEVICE); -} - static struct iommu_gather_ops ipmmu_gather_ops = { .tlb_flush_all = ipmmu_tlb_flush_all, .tlb_add_flush = ipmmu_tlb_add_flush, .tlb_sync = ipmmu_tlb_flush_all, - .flush_pgtable = ipmmu_flush_pgtable, }; /* ----------------------------------------------------------------------------- @@ -327,6 +313,11 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) domain->cfg.ias = 32; domain->cfg.oas = 40; domain->cfg.tlb = &ipmmu_gather_ops; + /* + * TODO: Add support for coherent walk through CCI with DVM and remove + * cache handling. For now, delegate it to the io-pgtable code. + */ + domain->cfg.iommu_dev = domain->mmu->dev; domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &domain->cfg, domain); -- cgit v1.3-6-gb490 From 87a91b15d691d6f4aa0a5baffb5767bbc6e4a8c4 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 29 Jul 2015 19:46:09 +0100 Subject: iommu/io-pgtable-arm: Centralise sync points With all current users now opted in to DMA API operations, make the iommu_dev pointer mandatory, rendering the flush_pgtable callback redundant for cache maintenance. However, since the DMA calls could be nops in the case of a coherent IOMMU, we still need to ensure the page table updates are fully synchronised against a subsequent page table walk. In the unmap path, the TLB sync will usually need to do this anyway, so just cement that requirement; in the map path which may consist solely of cacheable memory writes (in the coherent case), insert an appropriate barrier at the end of the operation, and obviate the need to call flush_pgtable on every individual update for synchronisation. Signed-off-by: Robin Murphy [will: slight clarification to tlb_sync comment] Signed-off-by: Will Deacon --- drivers/iommu/io-pgtable-arm.c | 43 +++++++++++++++++++++++------------------- drivers/iommu/io-pgtable.h | 4 +++- 2 files changed, 27 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 28cca8a652f9..06176872fb78 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -26,6 +26,8 @@ #include #include +#include + #include "io-pgtable.h" #define ARM_LPAE_MAX_ADDR_BITS 48 @@ -215,7 +217,7 @@ static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp, if (!pages) return NULL; - if (dev) { + if (!selftest_running) { dma = dma_map_single(dev, pages, size, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma)) goto out_free; @@ -243,24 +245,22 @@ static void __arm_lpae_free_pages(void *pages, size_t size, { struct device *dev = cfg->iommu_dev; - if (dev) + if (!selftest_running) dma_unmap_single(dev, __arm_lpae_dma_addr(dev, pages), size, DMA_TO_DEVICE); free_pages_exact(pages, size); } static void __arm_lpae_set_pte(arm_lpae_iopte *ptep, arm_lpae_iopte pte, - struct io_pgtable_cfg *cfg, void *cookie) + struct io_pgtable_cfg *cfg) { struct device *dev = cfg->iommu_dev; *ptep = pte; - if (dev) + if (!selftest_running) dma_sync_single_for_device(dev, __arm_lpae_dma_addr(dev, ptep), sizeof(pte), DMA_TO_DEVICE); - else if (cfg->tlb->flush_pgtable) - cfg->tlb->flush_pgtable(ptep, sizeof(pte), cookie); } static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, @@ -288,7 +288,7 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, pte |= ARM_LPAE_PTE_AF | ARM_LPAE_PTE_SH_IS; pte |= pfn_to_iopte(paddr >> data->pg_shift, data); - __arm_lpae_set_pte(ptep, pte, cfg, data->iop.cookie); + __arm_lpae_set_pte(ptep, pte, cfg); return 0; } @@ -297,7 +297,6 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, int lvl, arm_lpae_iopte *ptep) { arm_lpae_iopte *cptep, pte; - void *cookie = data->iop.cookie; size_t block_size = ARM_LPAE_BLOCK_SIZE(lvl, data); struct io_pgtable_cfg *cfg = &data->iop.cfg; @@ -323,7 +322,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, pte = __pa(cptep) | ARM_LPAE_PTE_TYPE_TABLE; if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS) pte |= ARM_LPAE_PTE_NSTABLE; - __arm_lpae_set_pte(ptep, pte, cfg, cookie); + __arm_lpae_set_pte(ptep, pte, cfg); } else { cptep = iopte_deref(pte, data); } @@ -370,7 +369,7 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, { struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); arm_lpae_iopte *ptep = data->pgd; - int lvl = ARM_LPAE_START_LVL(data); + int ret, lvl = ARM_LPAE_START_LVL(data); arm_lpae_iopte prot; /* If no access, then nothing to do */ @@ -378,7 +377,14 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, return 0; prot = arm_lpae_prot_to_pte(data, iommu_prot); - return __arm_lpae_map(data, iova, paddr, size, prot, lvl, ptep); + ret = __arm_lpae_map(data, iova, paddr, size, prot, lvl, ptep); + /* + * Synchronise all PTE updates for the new mapping before there's + * a chance for anything to kick off a table walk for the new iova. + */ + wmb(); + + return ret; } static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl, @@ -428,7 +434,6 @@ static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, phys_addr_t blk_paddr; arm_lpae_iopte table = 0; struct io_pgtable_cfg *cfg = &data->iop.cfg; - void *cookie = data->iop.cookie; blk_start = iova & ~(blk_size - 1); blk_end = blk_start + blk_size; @@ -454,9 +459,9 @@ static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data, } } - __arm_lpae_set_pte(ptep, table, cfg, cookie); + __arm_lpae_set_pte(ptep, table, cfg); iova &= ~(blk_size - 1); - cfg->tlb->tlb_add_flush(iova, blk_size, true, cookie); + cfg->tlb->tlb_add_flush(iova, blk_size, true, data->iop.cookie); return size; } @@ -478,7 +483,7 @@ static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, /* If the size matches this level, we're in the right place */ if (size == blk_size) { - __arm_lpae_set_pte(ptep, 0, &data->iop.cfg, cookie); + __arm_lpae_set_pte(ptep, 0, &data->iop.cfg); if (!iopte_leaf(pte, lvl)) { /* Also flush any partial walks */ @@ -703,8 +708,8 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) if (!data->pgd) goto out_free_data; - if (cfg->tlb->flush_pgtable) - cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); + /* Ensure the empty pgd is visible before any actual TTBR write */ + wmb(); /* TTBRs */ cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd); @@ -792,8 +797,8 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) if (!data->pgd) goto out_free_data; - if (cfg->tlb->flush_pgtable) - cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie); + /* Ensure the empty pgd is visible before any actual TTBR write */ + wmb(); /* VTTBR */ cfg->arm_lpae_s2_cfg.vttbr = virt_to_phys(data->pgd); diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h index c69529c78914..e8fadb012ed2 100644 --- a/drivers/iommu/io-pgtable.h +++ b/drivers/iommu/io-pgtable.h @@ -17,7 +17,9 @@ enum io_pgtable_fmt { * * @tlb_flush_all: Synchronously invalidate the entire TLB context. * @tlb_add_flush: Queue up a TLB invalidation for a virtual address range. - * @tlb_sync: Ensure any queue TLB invalidation has taken effect. + * @tlb_sync: Ensure any queued TLB invalidation has taken effect, and + * any corresponding page table updates are visible to the + * IOMMU. * @flush_pgtable: Ensure page table updates are visible to the IOMMU. * * Note that these can all be called in atomic context and must therefore -- cgit v1.3-6-gb490 From 4103d662cbd0c045d7a44a18c82172220478b20c Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 29 Jul 2015 19:46:10 +0100 Subject: iommu/arm-smmu: Remove arm_smmu_flush_pgtable() With the io-pgtable code now enforcing its own appropriate sync points, the vestigial flush_pgtable callback becomes entirely redundant, so remove it altogether. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 5770ab98fa38..48a39dfa9777 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -608,23 +608,10 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, } } -static void arm_smmu_flush_pgtable(void *addr, size_t size, void *cookie) -{ - struct arm_smmu_domain *smmu_domain = cookie; - - /* - * Ensure new page tables are visible to a coherent hardware walker. - * The page table code deals with flushing for the non-coherent case. - */ - if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) - dsb(ishst); -} - static struct iommu_gather_ops arm_smmu_gather_ops = { .tlb_flush_all = arm_smmu_tlb_inv_context, .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, .tlb_sync = arm_smmu_tlb_sync, - .flush_pgtable = arm_smmu_flush_pgtable, }; static irqreturn_t arm_smmu_context_fault(int irq, void *dev) -- cgit v1.3-6-gb490 From 857c88ca62f1e2594e1e760ef9a45ec1961f2a53 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 29 Jul 2015 19:46:11 +0100 Subject: iommu/arm-smmu: Remove arm_smmu_flush_pgtable() With the io-pgtable code now enforcing its own appropriate sync points, the vestigial flush_pgtable callback becomes entirely redundant, so remove it altogether. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 54c68d123a6d..dafaf59dc3b8 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1331,20 +1331,10 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, arm_smmu_cmdq_issue_cmd(smmu, &cmd); } -static void arm_smmu_flush_pgtable(void *addr, size_t size, void *cookie) -{ - struct arm_smmu_domain *smmu_domain = cookie; - - /* The page table code handles flushing in the non-coherent case */ - if (smmu_domain->smmu->features & ARM_SMMU_FEAT_COHERENCY) - dsb(ishst); -} - static struct iommu_gather_ops arm_smmu_gather_ops = { .tlb_flush_all = arm_smmu_tlb_inv_context, .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, .tlb_sync = arm_smmu_tlb_sync, - .flush_pgtable = arm_smmu_flush_pgtable, }; /* IOMMU API */ -- cgit v1.3-6-gb490 From f5b831907da3e64bfb0288089a5c07124266b1a5 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Wed, 29 Jul 2015 19:46:12 +0100 Subject: iommu/io-pgtable: Remove flush_pgtable callback With the users fully converted to DMA API operations, it's dead, Jim. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/io-pgtable-arm.c | 6 ------ drivers/iommu/io-pgtable.h | 2 -- 2 files changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 06176872fb78..e4bc2b23ab96 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -884,16 +884,10 @@ static void dummy_tlb_sync(void *cookie) WARN_ON(cookie != cfg_cookie); } -static void dummy_flush_pgtable(void *ptr, size_t size, void *cookie) -{ - WARN_ON(cookie != cfg_cookie); -} - static struct iommu_gather_ops dummy_tlb_ops __initdata = { .tlb_flush_all = dummy_tlb_flush_all, .tlb_add_flush = dummy_tlb_add_flush, .tlb_sync = dummy_tlb_sync, - .flush_pgtable = dummy_flush_pgtable, }; static void __init arm_lpae_dump_ops(struct io_pgtable_ops *ops) diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h index e8fadb012ed2..48538a35d078 100644 --- a/drivers/iommu/io-pgtable.h +++ b/drivers/iommu/io-pgtable.h @@ -20,7 +20,6 @@ enum io_pgtable_fmt { * @tlb_sync: Ensure any queued TLB invalidation has taken effect, and * any corresponding page table updates are visible to the * IOMMU. - * @flush_pgtable: Ensure page table updates are visible to the IOMMU. * * Note that these can all be called in atomic context and must therefore * not block. @@ -30,7 +29,6 @@ struct iommu_gather_ops { void (*tlb_add_flush)(unsigned long iova, size_t size, bool leaf, void *cookie); void (*tlb_sync)(void *cookie); - void (*flush_pgtable)(void *ptr, size_t size, void *cookie); }; /** -- cgit v1.3-6-gb490 From 26bf956aa9952a8141a12f314df70dcd020572d6 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:09 +0200 Subject: usb: gadget: epautoconf: rework ep_matches() function Rework ep_matches() function to make it shorter and more readable. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 81 ++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 52658fe761d4..95e12759af4d 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -32,7 +32,6 @@ ep_matches ( { u8 type; u16 max; - int num_req_streams = 0; /* endpoint already claimed? */ @@ -40,6 +39,20 @@ ep_matches ( return 0; type = usb_endpoint_type(desc); + max = 0x7ff & usb_endpoint_maxp(desc); + + if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) + return 0; + if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) + return 0; + + if (max > ep->maxpacket_limit) + return 0; + + /* "high bandwidth" works only at high speed */ + if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11)) + return 0; + switch (type) { case USB_ENDPOINT_XFER_CONTROL: /* only support ep0 for portable CONTROL traffic */ @@ -47,66 +60,36 @@ ep_matches ( case USB_ENDPOINT_XFER_ISOC: if (!ep->caps.type_iso) return 0; + /* ISO: limit 1023 bytes full speed, + * 1024 high/super speed + */ + if (!gadget_is_dualspeed(gadget) && max > 1023) + return 0; break; case USB_ENDPOINT_XFER_BULK: if (!ep->caps.type_bulk) return 0; + if (ep_comp && gadget_is_superspeed(gadget)) { + /* Get the number of required streams from the + * EP companion descriptor and see if the EP + * matches it + */ + num_req_streams = ep_comp->bmAttributes & 0x1f; + if (num_req_streams > ep->max_streams) + return 0; + } break; case USB_ENDPOINT_XFER_INT: - /* bulk endpoints handle interrupt transfers, + /* Bulk endpoints handle interrupt transfers, * except the toggle-quirky iso-synch kind */ if (!ep->caps.type_int && !ep->caps.type_bulk) return 0; - break; - } - - if (usb_endpoint_dir_in(desc)) { - if (!ep->caps.dir_in) - return 0; - } else { - if (!ep->caps.dir_out) - return 0; - } - - /* - * Get the number of required streams from the EP companion - * descriptor and see if the EP matches it - */ - if (usb_endpoint_xfer_bulk(desc)) { - if (ep_comp && gadget->max_speed >= USB_SPEED_SUPER) { - num_req_streams = ep_comp->bmAttributes & 0x1f; - if (num_req_streams > ep->max_streams) - return 0; - } - - } - - /* endpoint maxpacket size is an input parameter, except for bulk - * where it's an output parameter representing the full speed limit. - * the usb spec fixes high speed bulk maxpacket at 512 bytes. - */ - max = 0x7ff & usb_endpoint_maxp(desc); - switch (type) { - case USB_ENDPOINT_XFER_INT: - /* INT: limit 64 bytes full speed, 1024 high/super speed */ + /* INT: limit 64 bytes full speed, + * 1024 high/super speed + */ if (!gadget_is_dualspeed(gadget) && max > 64) return 0; - /* FALLTHROUGH */ - - case USB_ENDPOINT_XFER_ISOC: - /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ - if (ep->maxpacket_limit < max) - return 0; - if (!gadget_is_dualspeed(gadget) && max > 1023) - return 0; - - /* BOTH: "high bandwidth" works only at high speed */ - if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) { - if (!gadget_is_dualspeed(gadget)) - return 0; - /* configure your hardware with enough buffering!! */ - } break; } -- cgit v1.3-6-gb490 From 596c154d62330ea0bb4e3c3e50afa3682e50b617 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:10 +0200 Subject: usb: gadget: add 'ep_match' callback to usb_gadget_ops Add callback that is called by epautoconf to allow UDC driver match the best endpoint for specific descriptor. It's intended to supply mechanism which allows to get rid of chip-specific endpoint matching code from epautoconf. If gadget has set 'ep_match' callback we prefer to call it first, and if it fails to find matching endpoint, then we try to use default matching algorithm. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 6 ++++++ include/linux/usb/gadget.h | 3 +++ 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 95e12759af4d..f000c73319f4 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -165,6 +165,12 @@ struct usb_ep *usb_ep_autoconfig_ss( type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + if (gadget->ops->match_ep) { + ep = gadget->ops->match_ep(gadget, desc, ep_comp); + if (ep) + goto found_ep; + } + /* First, apply chip-specific "best usage" knowledge. * This might make a good usb_gadget_ops hook ... */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 82b5bcbd2c98..303214bb2f8b 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -534,6 +534,9 @@ struct usb_gadget_ops { int (*udc_start)(struct usb_gadget *, struct usb_gadget_driver *); int (*udc_stop)(struct usb_gadget *); + struct usb_ep *(*match_ep)(struct usb_gadget *, + struct usb_endpoint_descriptor *, + struct usb_ss_ep_comp_descriptor *); }; /** -- cgit v1.3-6-gb490 From 4278c687f697b651ab0c771114564da5ed006f22 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:11 +0200 Subject: usb: gadget: move ep_matches() from epautoconf to udc-core Move ep_matches() function to udc-core and rename it to usb_gadget_ep_match_desc(). This function can be used by UDC drivers in 'match_ep' callback to avoid writing lots of repetitive code. Replace all calls of ep_matches() with usb_gadget_ep_match_desc(). Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 95 +++++---------------------------------- drivers/usb/gadget/udc/udc-core.c | 69 ++++++++++++++++++++++++++++ include/linux/usb/gadget.h | 8 ++++ 3 files changed, 88 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index f000c73319f4..d49af4fc8667 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -22,82 +22,6 @@ #include "gadget_chips.h" -static int -ep_matches ( - struct usb_gadget *gadget, - struct usb_ep *ep, - struct usb_endpoint_descriptor *desc, - struct usb_ss_ep_comp_descriptor *ep_comp -) -{ - u8 type; - u16 max; - int num_req_streams = 0; - - /* endpoint already claimed? */ - if (ep->claimed) - return 0; - - type = usb_endpoint_type(desc); - max = 0x7ff & usb_endpoint_maxp(desc); - - if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) - return 0; - if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) - return 0; - - if (max > ep->maxpacket_limit) - return 0; - - /* "high bandwidth" works only at high speed */ - if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11)) - return 0; - - switch (type) { - case USB_ENDPOINT_XFER_CONTROL: - /* only support ep0 for portable CONTROL traffic */ - return 0; - case USB_ENDPOINT_XFER_ISOC: - if (!ep->caps.type_iso) - return 0; - /* ISO: limit 1023 bytes full speed, - * 1024 high/super speed - */ - if (!gadget_is_dualspeed(gadget) && max > 1023) - return 0; - break; - case USB_ENDPOINT_XFER_BULK: - if (!ep->caps.type_bulk) - return 0; - if (ep_comp && gadget_is_superspeed(gadget)) { - /* Get the number of required streams from the - * EP companion descriptor and see if the EP - * matches it - */ - num_req_streams = ep_comp->bmAttributes & 0x1f; - if (num_req_streams > ep->max_streams) - return 0; - } - break; - case USB_ENDPOINT_XFER_INT: - /* Bulk endpoints handle interrupt transfers, - * except the toggle-quirky iso-synch kind - */ - if (!ep->caps.type_int && !ep->caps.type_bulk) - return 0; - /* INT: limit 64 bytes full speed, - * 1024 high/super speed - */ - if (!gadget_is_dualspeed(gadget) && max > 64) - return 0; - break; - } - - /* MATCH!! */ - - return 1; -} - static struct usb_ep * find_ep (struct usb_gadget *gadget, const char *name) { @@ -180,10 +104,12 @@ struct usb_ep *usb_ep_autoconfig_ss( if (type == USB_ENDPOINT_XFER_INT) { /* ep-e, ep-f are PIO with only 64 byte fifos */ ep = find_ep(gadget, "ep-e"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, + ep, desc, ep_comp)) goto found_ep; ep = find_ep(gadget, "ep-f"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, + ep, desc, ep_comp)) goto found_ep; } @@ -191,20 +117,21 @@ struct usb_ep *usb_ep_autoconfig_ss( snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc), usb_endpoint_dir_in(desc) ? "in" : "out"); ep = find_ep(gadget, name); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; } else if (gadget_is_goku (gadget)) { if (USB_ENDPOINT_XFER_INT == type) { /* single buffering is enough */ ep = find_ep(gadget, "ep3-bulk"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, + ep, desc, ep_comp)) goto found_ep; } else if (USB_ENDPOINT_XFER_BULK == type && (USB_DIR_IN & desc->bEndpointAddress)) { /* DMA may be available */ ep = find_ep(gadget, "ep2-bulk"); - if (ep && ep_matches(gadget, ep, desc, - ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, + ep, desc, ep_comp)) goto found_ep; } @@ -223,14 +150,14 @@ struct usb_ep *usb_ep_autoconfig_ss( ep = find_ep(gadget, "ep2out"); } else ep = NULL; - if (ep && ep_matches(gadget, ep, desc, ep_comp)) + if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; #endif } /* Second, look at endpoints until an unclaimed one looks usable */ list_for_each_entry (ep, &gadget->ep_list, ep_list) { - if (ep_matches(gadget, ep, desc, ep_comp)) + if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; } diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index 362ee8af5fce..b6427d1e9a6c 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -131,6 +131,75 @@ EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); /* ------------------------------------------------------------------------- */ +int usb_gadget_ep_match_desc(struct usb_gadget *gadget, + struct usb_ep *ep, struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + u8 type; + u16 max; + int num_req_streams = 0; + + /* endpoint already claimed? */ + if (ep->claimed) + return 0; + + type = usb_endpoint_type(desc); + max = 0x7ff & usb_endpoint_maxp(desc); + + if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) + return 0; + if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) + return 0; + + if (max > ep->maxpacket_limit) + return 0; + + /* "high bandwidth" works only at high speed */ + if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11)) + return 0; + + switch (type) { + case USB_ENDPOINT_XFER_CONTROL: + /* only support ep0 for portable CONTROL traffic */ + return 0; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->caps.type_iso) + return 0; + /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ + if (!gadget_is_dualspeed(gadget) && max > 1023) + return 0; + break; + case USB_ENDPOINT_XFER_BULK: + if (!ep->caps.type_bulk) + return 0; + if (ep_comp && gadget_is_superspeed(gadget)) { + /* Get the number of required streams from the + * EP companion descriptor and see if the EP + * matches it + */ + num_req_streams = ep_comp->bmAttributes & 0x1f; + if (num_req_streams > ep->max_streams) + return 0; + } + break; + case USB_ENDPOINT_XFER_INT: + /* Bulk endpoints handle interrupt transfers, + * except the toggle-quirky iso-synch kind + */ + if (!ep->caps.type_int && !ep->caps.type_bulk) + return 0; + /* INT: limit 64 bytes full speed, 1024 high/super speed */ + if (!gadget_is_dualspeed(gadget) && max > 64) + return 0; + break; + } + + return 1; +} +EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc); + +/* ------------------------------------------------------------------------- */ + static void usb_gadget_state_work(struct work_struct *work) { struct usb_gadget *gadget = work_to_gadget(work); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 303214bb2f8b..e04fd6381ae8 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -1204,6 +1204,14 @@ extern void usb_gadget_giveback_request(struct usb_ep *ep, /*-------------------------------------------------------------------------*/ +/* utility to check if endpoint caps match descriptor needs */ + +extern int usb_gadget_ep_match_desc(struct usb_gadget *gadget, + struct usb_ep *ep, struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp); + +/*-------------------------------------------------------------------------*/ + /* utility to update vbus status for udc core, it may be scheduled */ extern void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status); -- cgit v1.3-6-gb490 From b0aea0037c8896b8e69cad3f6e828782789c1edf Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:12 +0200 Subject: usb: gadget: move find_ep() from epautoconf to udc-core Move find_ep() to udc-core and rename it to gadget_find_ep_by_name(). It can be used in UDC drivers, especially in 'match_ep' callback after moving chip-specific endpoint matching logic from epautoconf to UDC drivers. Replace all calls of find_ep() function with gadget_find_ep_by_name(). Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 30 +++++++++--------------------- drivers/usb/gadget/udc/udc-core.c | 21 +++++++++++++++++++++ include/linux/usb/gadget.h | 8 +++++++- 3 files changed, 37 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index d49af4fc8667..a39ca033b9ce 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -22,18 +22,6 @@ #include "gadget_chips.h" -static struct usb_ep * -find_ep (struct usb_gadget *gadget, const char *name) -{ - struct usb_ep *ep; - - list_for_each_entry (ep, &gadget->ep_list, ep_list) { - if (0 == strcmp (ep->name, name)) - return ep; - } - return NULL; -} - /** * usb_ep_autoconfig_ss() - choose an endpoint matching the ep * descriptor and ep companion descriptor @@ -103,11 +91,11 @@ struct usb_ep *usb_ep_autoconfig_ss( if (type == USB_ENDPOINT_XFER_INT) { /* ep-e, ep-f are PIO with only 64 byte fifos */ - ep = find_ep(gadget, "ep-e"); + ep = gadget_find_ep_by_name(gadget, "ep-e"); if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; - ep = find_ep(gadget, "ep-f"); + ep = gadget_find_ep_by_name(gadget, "ep-f"); if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; @@ -116,20 +104,20 @@ struct usb_ep *usb_ep_autoconfig_ss( /* USB3380: use same address for usb and hardware endpoints */ snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc), usb_endpoint_dir_in(desc) ? "in" : "out"); - ep = find_ep(gadget, name); + ep = gadget_find_ep_by_name(gadget, name); if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; } else if (gadget_is_goku (gadget)) { if (USB_ENDPOINT_XFER_INT == type) { /* single buffering is enough */ - ep = find_ep(gadget, "ep3-bulk"); + ep = gadget_find_ep_by_name(gadget, "ep3-bulk"); if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; } else if (USB_ENDPOINT_XFER_BULK == type && (USB_DIR_IN & desc->bEndpointAddress)) { /* DMA may be available */ - ep = find_ep(gadget, "ep2-bulk"); + ep = gadget_find_ep_by_name(gadget, "ep2-bulk"); if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; @@ -140,14 +128,14 @@ struct usb_ep *usb_ep_autoconfig_ss( if ((USB_ENDPOINT_XFER_BULK == type) || (USB_ENDPOINT_XFER_ISOC == type)) { if (USB_DIR_IN & desc->bEndpointAddress) - ep = find_ep (gadget, "ep5in"); + ep = gadget_find_ep_by_name(gadget, "ep5in"); else - ep = find_ep (gadget, "ep6out"); + ep = gadget_find_ep_by_name(gadget, "ep6out"); } else if (USB_ENDPOINT_XFER_INT == type) { if (USB_DIR_IN & desc->bEndpointAddress) - ep = find_ep(gadget, "ep1in"); + ep = gadget_find_ep_by_name(gadget, "ep1in"); else - ep = find_ep(gadget, "ep2out"); + ep = gadget_find_ep_by_name(gadget, "ep2out"); } else ep = NULL; if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index b6427d1e9a6c..3c954b5fe4f3 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -131,6 +131,27 @@ EXPORT_SYMBOL_GPL(usb_gadget_giveback_request); /* ------------------------------------------------------------------------- */ +/** + * gadget_find_ep_by_name - returns ep whose name is the same as sting passed + * in second parameter or NULL if searched endpoint not found + * @g: controller to check for quirk + * @name: name of searched endpoint + */ +struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, const char *name) +{ + struct usb_ep *ep; + + gadget_for_each_ep(ep, g) { + if (!strcmp(ep->name, name)) + return ep; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(gadget_find_ep_by_name); + +/* ------------------------------------------------------------------------- */ + int usb_gadget_ep_match_desc(struct usb_gadget *gadget, struct usb_ep *ep, struct usb_endpoint_descriptor *desc, struct usb_ss_ep_comp_descriptor *ep_comp) diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index e04fd6381ae8..c14a69b36d27 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -639,7 +639,6 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev) #define gadget_for_each_ep(tmp, gadget) \ list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) - /** * usb_ep_align_maybe - returns @len aligned to ep's maxpacketsize if gadget * requires quirk_ep_out_aligned_size, otherwise reguens len. @@ -1204,6 +1203,13 @@ extern void usb_gadget_giveback_request(struct usb_ep *ep, /*-------------------------------------------------------------------------*/ +/* utility to find endpoint by name */ + +extern struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, + const char *name); + +/*-------------------------------------------------------------------------*/ + /* utility to check if endpoint caps match descriptor needs */ extern int usb_gadget_ep_match_desc(struct usb_gadget *gadget, -- cgit v1.3-6-gb490 From 3e8b231818c25a250c36f8bfb944aa1fd2b13396 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:13 +0200 Subject: usb: gadget: net2280: add net2280_match_ep() function Add 'match_ep' callback to utilize chip-specific knowledge in endpoint matching process. Function does the same that was done by chip-specific code inside of epautoconf. Now this code can be removed from there to separate generic code from platform specific logic. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 23 +---------------------- drivers/usb/gadget/udc/net2280.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index a39ca033b9ce..0ff513400ecf 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -86,28 +86,7 @@ struct usb_ep *usb_ep_autoconfig_ss( /* First, apply chip-specific "best usage" knowledge. * This might make a good usb_gadget_ops hook ... */ - if (gadget_is_net2280(gadget)) { - char name[8]; - - if (type == USB_ENDPOINT_XFER_INT) { - /* ep-e, ep-f are PIO with only 64 byte fifos */ - ep = gadget_find_ep_by_name(gadget, "ep-e"); - if (ep && usb_gadget_ep_match_desc(gadget, - ep, desc, ep_comp)) - goto found_ep; - ep = gadget_find_ep_by_name(gadget, "ep-f"); - if (ep && usb_gadget_ep_match_desc(gadget, - ep, desc, ep_comp)) - goto found_ep; - } - - /* USB3380: use same address for usb and hardware endpoints */ - snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc), - usb_endpoint_dir_in(desc) ? "in" : "out"); - ep = gadget_find_ep_by_name(gadget, name); - if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) - goto found_ep; - } else if (gadget_is_goku (gadget)) { + if (gadget_is_goku(gadget)) { if (USB_ENDPOINT_XFER_INT == type) { /* single buffering is enough */ ep = gadget_find_ep_by_name(gadget, "ep3-bulk"); diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index 872ca257cfa4..cf0ed42f5591 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -1550,6 +1550,33 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) return 0; } +static struct usb_ep *net2280_match_ep(struct usb_gadget *_gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + char name[8]; + struct usb_ep *ep; + + if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT) { + /* ep-e, ep-f are PIO with only 64 byte fifos */ + ep = gadget_find_ep_by_name(_gadget, "ep-e"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + ep = gadget_find_ep_by_name(_gadget, "ep-f"); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + } + + /* USB3380: use same address for usb and hardware endpoints */ + snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc), + usb_endpoint_dir_in(desc) ? "in" : "out"); + ep = gadget_find_ep_by_name(_gadget, name); + if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp)) + return ep; + + return NULL; +} + static int net2280_start(struct usb_gadget *_gadget, struct usb_gadget_driver *driver); static int net2280_stop(struct usb_gadget *_gadget); @@ -1561,6 +1588,7 @@ static const struct usb_gadget_ops net2280_ops = { .pullup = net2280_pullup, .udc_start = net2280_start, .udc_stop = net2280_stop, + .match_ep = net2280_match_ep, }; /*-------------------------------------------------------------------------*/ -- cgit v1.3-6-gb490 From 8cc67b7bff2fc1adfd080233d35aacba4411cf87 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:14 +0200 Subject: usb: gadget: goku_udc: add goku_match_ep() function Add 'match_ep' callback to utilize chip-specific knowledge in endpoint matching process. Function does the same that was done by chip-specific code inside of epautoconf. Now this code can be removed from there to separate generic code from platform specific logic. [ balbi@ti.com : fix build breakage ] Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 20 ++------------------ drivers/usb/gadget/udc/goku_udc.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 0ff513400ecf..574b6a4df646 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -86,24 +86,8 @@ struct usb_ep *usb_ep_autoconfig_ss( /* First, apply chip-specific "best usage" knowledge. * This might make a good usb_gadget_ops hook ... */ - if (gadget_is_goku(gadget)) { - if (USB_ENDPOINT_XFER_INT == type) { - /* single buffering is enough */ - ep = gadget_find_ep_by_name(gadget, "ep3-bulk"); - if (ep && usb_gadget_ep_match_desc(gadget, - ep, desc, ep_comp)) - goto found_ep; - } else if (USB_ENDPOINT_XFER_BULK == type - && (USB_DIR_IN & desc->bEndpointAddress)) { - /* DMA may be available */ - ep = gadget_find_ep_by_name(gadget, "ep2-bulk"); - if (ep && usb_gadget_ep_match_desc(gadget, - ep, desc, ep_comp)) - goto found_ep; - } - #ifdef CONFIG_BLACKFIN - } else if (gadget_is_musbhdrc(gadget)) { + if (gadget_is_musbhdrc(gadget)) { if ((USB_ENDPOINT_XFER_BULK == type) || (USB_ENDPOINT_XFER_ISOC == type)) { if (USB_DIR_IN & desc->bEndpointAddress) @@ -119,8 +103,8 @@ struct usb_ep *usb_ep_autoconfig_ss( ep = NULL; if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) goto found_ep; -#endif } +#endif /* Second, look at endpoints until an unclaimed one looks usable */ list_for_each_entry (ep, &gadget->ep_list, ep_list) { diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index 46b8d14998cf..1fdfec14a3ba 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -990,6 +990,35 @@ static int goku_get_frame(struct usb_gadget *_gadget) return -EOPNOTSUPP; } +static struct usb_ep *goku_match_ep(struct usb_gadget *g, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + struct goku_udc *dev = to_goku_udc(g); + struct usb_ep *ep; + + switch (usb_endpoint_type(desc)) { + case USB_ENDPOINT_XFER_INT: + /* single buffering is enough */ + ep = &dev->ep[3].ep; + if (usb_gadget_ep_match_desc(g, ep, desc, ep_comp)) + return ep; + break; + case USB_ENDPOINT_XFER_BULK: + if (usb_endpoint_dir_in(desc)) { + /* DMA may be available */ + ep = &dev->ep[2].ep; + if (usb_gadget_ep_match_desc(g, ep, desc, ep_comp)) + return ep; + } + break; + default: + /* nothing */ ; + } + + return NULL; +} + static int goku_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); static int goku_udc_stop(struct usb_gadget *g); @@ -998,6 +1027,7 @@ static const struct usb_gadget_ops goku_ops = { .get_frame = goku_get_frame, .udc_start = goku_udc_start, .udc_stop = goku_udc_stop, + .match_ep = goku_match_ep, // no remote wakeup // not selfpowered }; -- cgit v1.3-6-gb490 From 26b8aa458c7d99181ceb07f27da9bd7d94185e35 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:15 +0200 Subject: usb: musb: gadget: add musb_match_ep() function Add 'match_ep' callback to utilize chip-specific knowledge in endpoint matching process. Function does the same that was done by chip-specific code inside of epautoconf. Now this code can be removed from there to separate generic code from platform specific logic. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 23 ----------------------- drivers/usb/musb/musb_gadget.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 574b6a4df646..16c1cc90c406 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -83,29 +83,6 @@ struct usb_ep *usb_ep_autoconfig_ss( goto found_ep; } - /* First, apply chip-specific "best usage" knowledge. - * This might make a good usb_gadget_ops hook ... - */ -#ifdef CONFIG_BLACKFIN - if (gadget_is_musbhdrc(gadget)) { - if ((USB_ENDPOINT_XFER_BULK == type) || - (USB_ENDPOINT_XFER_ISOC == type)) { - if (USB_DIR_IN & desc->bEndpointAddress) - ep = gadget_find_ep_by_name(gadget, "ep5in"); - else - ep = gadget_find_ep_by_name(gadget, "ep6out"); - } else if (USB_ENDPOINT_XFER_INT == type) { - if (USB_DIR_IN & desc->bEndpointAddress) - ep = gadget_find_ep_by_name(gadget, "ep1in"); - else - ep = gadget_find_ep_by_name(gadget, "ep2out"); - } else - ep = NULL; - if (ep && usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) - goto found_ep; - } -#endif - /* Second, look at endpoints until an unclaimed one looks usable */ list_for_each_entry (ep, &gadget->ep_list, ep_list) { if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp)) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 4150bafe6bf5..5f52bcb4bf78 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1684,6 +1684,39 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) return 0; } +#ifdef CONFIG_BLACKFIN +static struct usb_ep *musb_match_ep(struct usb_gadget *g, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp) +{ + struct usb_ep *ep = NULL; + + switch (usb_endpoint_type(desc)) { + case USB_ENDPOINT_XFER_ISOC: + case USB_ENDPOINT_XFER_BULK: + if (usb_endpoint_dir_in(desc)) + ep = gadget_find_ep_by_name(g, "ep5in"); + else + ep = gadget_find_ep_by_name(g, "ep6out"); + break; + case USB_ENDPOINT_XFER_INT: + if (usb_endpoint_dir_in(desc)) + ep = gadget_find_ep_by_name(g, "ep1in"); + else + ep = gadget_find_ep_by_name(g, "ep2out"); + break; + default: + } + + if (ep && usb_gadget_ep_match_desc(g, ep, desc, ep_comp)) + return ep; + + return NULL; +} +#else +#define musb_match_ep NULL +#endif + static int musb_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver); static int musb_gadget_stop(struct usb_gadget *g); @@ -1697,6 +1730,7 @@ static const struct usb_gadget_ops musb_gadget_operations = { .pullup = musb_gadget_pullup, .udc_start = musb_gadget_start, .udc_stop = musb_gadget_stop, + .match_ep = musb_match_ep, }; /* ----------------------------------------------------------------------- */ -- cgit v1.3-6-gb490 From adab43396ed4830c7cee29837e8cedcddb2b5315 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 6 Aug 2015 14:11:16 +0200 Subject: usb: gadget: remove gadget_chips.h This header file contains helpers for quirks based on UDC controller name. Since we have generic quirk bitfields in usb_gadget structure for all of these quirks we don't need to have this header any longer. This patch removes gadget_chips.h file and makes sure that it's no longer included anywhere in kernel sources. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/gadget/epautoconf.c | 2 - drivers/usb/gadget/function/f_acm.c | 1 - drivers/usb/gadget/function/f_mass_storage.c | 1 - drivers/usb/gadget/function/f_obex.c | 1 - drivers/usb/gadget/function/f_serial.c | 1 - drivers/usb/gadget/function/f_sourcesink.c | 1 - drivers/usb/gadget/function/u_ether.h | 2 - drivers/usb/gadget/function/u_uac1.h | 2 - drivers/usb/gadget/legacy/audio.c | 1 - drivers/usb/gadget/legacy/gmidi.c | 2 - drivers/usb/gadget/legacy/hid.c | 1 - drivers/usb/gadget/legacy/nokia.c | 1 - drivers/usb/gadget/legacy/printer.c | 2 - drivers/usb/gadget/legacy/serial.c | 1 - drivers/usb/gadget/udc/gadget_chips.h | 55 ---------------------------- 15 files changed, 74 deletions(-) delete mode 100644 drivers/usb/gadget/udc/gadget_chips.h (limited to 'drivers') diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 16c1cc90c406..978435a51038 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -20,8 +20,6 @@ #include #include -#include "gadget_chips.h" - /** * usb_ep_autoconfig_ss() - choose an endpoint matching the ep * descriptor and ep companion descriptor diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c index aad8165e98ef..be9df09fde26 100644 --- a/drivers/usb/gadget/function/f_acm.c +++ b/drivers/usb/gadget/function/f_acm.c @@ -21,7 +21,6 @@ #include #include "u_serial.h" -#include "gadget_chips.h" /* diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 04c3bb6e9dcd..11a7f5aa955b 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -219,7 +219,6 @@ #include #include -#include "gadget_chips.h" #include "configfs.h" diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c index 2682d59f5675..5460426057eb 100644 --- a/drivers/usb/gadget/function/f_obex.c +++ b/drivers/usb/gadget/function/f_obex.c @@ -20,7 +20,6 @@ #include #include "u_serial.h" -#include "gadget_chips.h" /* diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c index 2e02dfabc7ae..1d162e200e83 100644 --- a/drivers/usb/gadget/function/f_serial.c +++ b/drivers/usb/gadget/function/f_serial.c @@ -16,7 +16,6 @@ #include #include "u_serial.h" -#include "gadget_chips.h" /* diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c index e6af1719d851..cbfaf86fe456 100644 --- a/drivers/usb/gadget/function/f_sourcesink.c +++ b/drivers/usb/gadget/function/f_sourcesink.c @@ -20,7 +20,6 @@ #include #include "g_zero.h" -#include "gadget_chips.h" #include "u_f.h" /* diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 1384f000bd80..c77145bd6b5b 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -20,8 +20,6 @@ #include #include -#include "gadget_chips.h" - #define QMULT_DEFAULT 5 /* diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h index fe386df6dd3e..5c2ac8e8456d 100644 --- a/drivers/usb/gadget/function/u_uac1.h +++ b/drivers/usb/gadget/function/u_uac1.h @@ -21,8 +21,6 @@ #include #include -#include "gadget_chips.h" - #define FILE_PCM_PLAYBACK "/dev/snd/pcmC0D0p" #define FILE_PCM_CAPTURE "/dev/snd/pcmC0D0c" #define FILE_CONTROL "/dev/snd/controlC0" diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index 9b2c1c68746b..685cf3b4b78f 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -15,7 +15,6 @@ #include #include -#include "gadget_chips.h" #define DRIVER_DESC "Linux USB Audio Gadget" #define DRIVER_VERSION "Feb 2, 2012" diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c index 650568de0de3..8a18348ae86e 100644 --- a/drivers/usb/gadget/legacy/gmidi.c +++ b/drivers/usb/gadget/legacy/gmidi.c @@ -35,8 +35,6 @@ #include #include -#include "gadget_chips.h" - #include "u_midi.h" /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c index e4874d3183dc..7e5d2c48476e 100644 --- a/drivers/usb/gadget/legacy/hid.c +++ b/drivers/usb/gadget/legacy/hid.c @@ -19,7 +19,6 @@ #include #include -#include "gadget_chips.h" #define DRIVER_DESC "HID Gadget" #define DRIVER_VERSION "2010/03/16" diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index c20f3b58f126..8b3f6fb1825d 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -23,7 +23,6 @@ #include "u_ether.h" #include "u_phonet.h" #include "u_ecm.h" -#include "gadget_chips.h" #include "f_mass_storage.h" /* Defines */ diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index 0c1fc0622d09..a22d30a4def1 100644 --- a/drivers/usb/gadget/legacy/printer.c +++ b/drivers/usb/gadget/legacy/printer.c @@ -19,8 +19,6 @@ #include #include -#include "gadget_chips.h" - USB_GADGET_COMPOSITE_OPTIONS(); #define DRIVER_DESC "Printer Gadget" diff --git a/drivers/usb/gadget/legacy/serial.c b/drivers/usb/gadget/legacy/serial.c index 9836d164469a..c5d42e0347a9 100644 --- a/drivers/usb/gadget/legacy/serial.c +++ b/drivers/usb/gadget/legacy/serial.c @@ -17,7 +17,6 @@ #include #include "u_serial.h" -#include "gadget_chips.h" /* Defines */ diff --git a/drivers/usb/gadget/udc/gadget_chips.h b/drivers/usb/gadget/udc/gadget_chips.h deleted file mode 100644 index bcd04bc66b98..000000000000 --- a/drivers/usb/gadget/udc/gadget_chips.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * USB device controllers have lots of quirks. Use these macros in - * gadget drivers or other code that needs to deal with them, and which - * autoconfigures instead of using early binding to the hardware. - * - * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by - * some config file that gets updated as new hardware is supported. - * (And avoiding all runtime comparisons in typical one-choice configs!) - * - * NOTE: some of these controller drivers may not be available yet. - * Some are available on 2.4 kernels; several are available, but not - * yet pushed in the 2.6 mainline tree. - */ - -#ifndef __GADGET_CHIPS_H -#define __GADGET_CHIPS_H - -#include - -/* - * NOTICE: the entries below are alphabetical and should be kept - * that way. - * - * Always be sure to add new entries to the correct position or - * accept the bashing later. - * - * If you have forgotten the alphabetical order let VIM/EMACS - * do that for you. - */ -#define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) -#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) -#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) -#define gadget_is_net2280(g) (!strcmp("net2280", (g)->name)) -#define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name)) -#define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name)) - -/** - * gadget_supports_altsettings - return true if altsettings work - * @gadget: the gadget in question - */ -static inline bool gadget_supports_altsettings(struct usb_gadget *gadget) -{ - /* PXA 21x/25x/26x has no altsettings at all */ - if (gadget_is_pxa(gadget)) - return false; - - /* PXA 27x and 3xx have *broken* altsetting support */ - if (gadget_is_pxa27x(gadget)) - return false; - - /* Everything else is *presumably* fine ... */ - return true; -} - -#endif /* __GADGET_CHIPS_H */ -- cgit v1.3-6-gb490 From 03840fad004ce8a56bc8b3bb60a2df10f6f9481e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Aug 2015 10:47:16 -0500 Subject: usb: musb: gadget: remove remaining DMA ifdeferry Commit fb91cddc54e7 ("usb: musb: Remove DMA ifdef for musb_gadget.c short_packet") tried to remove DMA ifdeferry from musb_gadget.c but ended up leaving some around. Remove them so that when building kernels with all DMA engines enabled, we don't end up trying to allocte channels twice. Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 5f52bcb4bf78..cc503591b634 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -313,8 +313,7 @@ static void txstate(struct musb *musb, struct musb_request *req) /* MUSB_TXCSR_P_ISO is still set correctly */ -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) - { + if (musb_dma_inventra(musb) || musb_dma_ux500(musb)) { if (request_size < musb_ep->packet_sz) musb_ep->dma->desired_mode = 0; else @@ -365,7 +364,6 @@ static void txstate(struct musb *musb, struct musb_request *req) } } -#endif if (is_cppi_enabled(musb)) { /* program endpoint CSR first, then setup DMA */ csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); @@ -641,8 +639,10 @@ static void rxstate(struct musb *musb, struct musb_request *req) use_mode_1 = 0; if (request->actual < request->length) { -#ifdef CONFIG_USB_INVENTRA_DMA - if (is_buffer_mapped(req)) { + if (!is_buffer_mapped(req)) + goto buffer_aint_mapped; + + if (musb_dma_inventra(musb)) { struct dma_controller *c; struct dma_channel *channel; int use_dma = 0; @@ -716,8 +716,8 @@ static void rxstate(struct musb *musb, struct musb_request *req) if (use_dma) return; } -#elif defined(CONFIG_USB_UX500_DMA) - if ((is_buffer_mapped(req)) && + + if ((musb_dma_ux500(musb)) && (request->actual < request->length)) { struct dma_controller *c; @@ -765,7 +765,6 @@ static void rxstate(struct musb *musb, struct musb_request *req) return; } -#endif /* Mentor's DMA */ len = request->length - request->actual; dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n", @@ -775,8 +774,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) fifo_count = min_t(unsigned, len, fifo_count); -#ifdef CONFIG_USB_TUSB_OMAP_DMA - if (tusb_dma_omap(musb) && is_buffer_mapped(req)) { + if (tusb_dma_omap(musb)) { struct dma_controller *c = musb->dma_controller; struct dma_channel *channel = musb_ep->dma; u32 dma_addr = request->dma + request->actual; @@ -790,23 +788,22 @@ static void rxstate(struct musb *musb, struct musb_request *req) if (ret) return; } -#endif + /* * Unmap the dma buffer back to cpu if dma channel * programming fails. This buffer is mapped if the * channel allocation is successful */ - if (is_buffer_mapped(req)) { - unmap_dma_buffer(req, musb); - - /* - * Clear DMAENAB and AUTOCLEAR for the - * PIO mode transfer - */ - csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR); - musb_writew(epio, MUSB_RXCSR, csr); - } + unmap_dma_buffer(req, musb); + + /* + * Clear DMAENAB and AUTOCLEAR for the + * PIO mode transfer + */ + csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR); + musb_writew(epio, MUSB_RXCSR, csr); +buffer_aint_mapped: musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *) (request->buf + request->actual)); request->actual += fifo_count; -- cgit v1.3-6-gb490 From b0a688ddcc5015eb26000c63841db7c46cfb380a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Aug 2015 10:51:29 -0500 Subject: usb: musb: cppi41: allow it to work again since commit 33c300cb90a6 ("usb: musb: dsps: don't fake of_node to musb core") we have been preventing CPPI 4.1 from probing due to NULL of_node. We can't revert said commit otherwise a different regression would show up, so the fix is to look for the parent device's (glue layer's) of_node instead, since that's the thing which is actually described in DTS. Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_cppi41.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index 4d1b44c232ee..d07cafb7d5f5 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -614,7 +614,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) { struct musb *musb = controller->musb; struct device *dev = musb->controller; - struct device_node *np = dev->of_node; + struct device_node *np = dev->parent->of_node; struct cppi41_dma_channel *cppi41_channel; int count; int i; @@ -664,7 +664,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) musb_dma->status = MUSB_DMA_STATUS_FREE; musb_dma->max_len = SZ_4M; - dc = dma_request_slave_channel(dev, str); + dc = dma_request_slave_channel(dev->parent, str); if (!dc) { dev_err(dev, "Failed to request %s.\n", str); ret = -EPROBE_DEFER; @@ -695,7 +695,7 @@ cppi41_dma_controller_create(struct musb *musb, void __iomem *base) struct cppi41_dma_controller *controller; int ret = 0; - if (!musb->controller->of_node) { + if (!musb->controller->parent->of_node) { dev_err(musb->controller, "Need DT for the DMA engine.\n"); return NULL; } -- cgit v1.3-6-gb490 From 4a1e9211809d4130fe23cad1bea222222d6e94f4 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Aug 2015 11:23:32 -0500 Subject: usb: gadget: f_mass_storage: add mising was originally being pulled indirectly through some other header, however it's not anymore, so we need to include it directly Reported-by: Jim Davis Suggested-by: Alan Stern Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 11a7f5aa955b..a6eb537d7768 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -214,6 +214,7 @@ #include #include #include +#include #include #include -- cgit v1.3-6-gb490 From 2e8328fb87d02569511c4808a1b3f44f67bd83fd Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 6 Aug 2015 11:29:19 -0500 Subject: usb: gadget: legacy: nokia: add CONFIG_BLOCK dependency g_nokia now has mass_storage function, so it should depend on CONFIG_BLOCK. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/legacy/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index ddef41f6df3e..4d682ad7bf23 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -339,6 +339,7 @@ config USB_CDC_COMPOSITE config USB_G_NOKIA tristate "Nokia composite gadget" depends on PHONET + depends on BLOCK select USB_LIBCOMPOSITE select USB_U_SERIAL select USB_U_ETHER -- cgit v1.3-6-gb490 From 49bd706aac8fe7fa90988ecd3fd5c276575b194e Mon Sep 17 00:00:00 2001 From: Han Xu Date: Tue, 4 Aug 2015 10:25:22 -0500 Subject: mtd: spi-nor: fsl-quadspi: dynamically map memory space for AHB read QSPI may failed to map enough memory (256MB) for AHB read in previous implementation, especially in 3G/1G memory layout kernel. Dynamically map memory to avoid such issue. This implementation generally map QUADSPI_MAX_IOMAP (default 4MB) memory for AHB read, it should be enough for common scenarios, and the side effect (0.6% performance drop) is minor. Previous implementation root@imx6qdlsolo:~# dd if=/dev/mtd0 of=/dev/null bs=1K count=32K 32768+0 records in 32768+0 records out 33554432 bytes (34 MB) copied, 2.16006 s, 15.5 MB/s root@imx6qdlsolo:~# dd if=/dev/mtd0 of=/dev/null bs=32M count=1 1+0 records in 1+0 records out 33554432 bytes (34 MB) copied, 1.43149 s, 23.4 MB/s After applied the patch root@imx6qdlsolo:~# dd if=/dev/mtd0 of=/dev/null bs=1K count=32K 32768+0 records in 32768+0 records out 33554432 bytes (34 MB) copied, 2.1743 s, 15.4 MB/s root@imx6qdlsolo:~# dd if=/dev/mtd0 of=/dev/null bs=32M count=1 1+0 records in 1+0 records out 33554432 bytes (34 MB) copied, 1.43158 s, 23.4 MB/s Signed-off-by: Han Xu Signed-off-by: Frank Li Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 55 ++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 1946c6da76cd..2d460368ce5f 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -192,6 +192,8 @@ #define SEQID_EN4B 10 #define SEQID_BRWR 11 +#define QUADSPI_MIN_IOMAP SZ_4M + enum fsl_qspi_devtype { FSL_QUADSPI_VYBRID, FSL_QUADSPI_IMX6SX, @@ -223,8 +225,10 @@ struct fsl_qspi { struct mtd_info mtd[FSL_QSPI_MAX_CHIP]; struct spi_nor nor[FSL_QSPI_MAX_CHIP]; void __iomem *iobase; - void __iomem *ahb_base; /* Used when read from AHB bus */ + void __iomem *ahb_addr; u32 memmap_phy; + u32 memmap_offs; + u32 memmap_len; struct clk *clk, *clk_en; struct device *dev; struct completion c; @@ -732,11 +736,42 @@ static int fsl_qspi_read(struct spi_nor *nor, loff_t from, struct fsl_qspi *q = nor->priv; u8 cmd = nor->read_opcode; - dev_dbg(q->dev, "cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n", - cmd, q->ahb_base, q->chip_base_addr, (unsigned int)from, len); + /* if necessary,ioremap buffer before AHB read, */ + if (!q->ahb_addr) { + q->memmap_offs = q->chip_base_addr + from; + q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP; + + q->ahb_addr = ioremap_nocache( + q->memmap_phy + q->memmap_offs, + q->memmap_len); + if (!q->ahb_addr) { + dev_err(q->dev, "ioremap failed\n"); + return -ENOMEM; + } + /* ioremap if the data requested is out of range */ + } else if (q->chip_base_addr + from < q->memmap_offs + || q->chip_base_addr + from + len > + q->memmap_offs + q->memmap_len) { + iounmap(q->ahb_addr); + + q->memmap_offs = q->chip_base_addr + from; + q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP; + q->ahb_addr = ioremap_nocache( + q->memmap_phy + q->memmap_offs, + q->memmap_len); + if (!q->ahb_addr) { + dev_err(q->dev, "ioremap failed\n"); + return -ENOMEM; + } + } + + dev_dbg(q->dev, "cmd [%x],read from 0x%p, len:%d\n", + cmd, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, + len); /* Read out the data directly from the AHB buffer.*/ - memcpy(buf, q->ahb_base + q->chip_base_addr + from, len); + memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, + len); *retlen += len; return 0; @@ -821,9 +856,11 @@ static int fsl_qspi_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI-memory"); - q->ahb_base = devm_ioremap_resource(dev, res); - if (IS_ERR(q->ahb_base)) - return PTR_ERR(q->ahb_base); + if (!devm_request_mem_region(dev, res->start, resource_size(res), + res->name)) { + dev_err(dev, "can't request region for resource %pR\n", res); + return -EBUSY; + } q->memmap_phy = res->start; @@ -989,6 +1026,10 @@ static int fsl_qspi_remove(struct platform_device *pdev) mutex_destroy(&q->lock); clk_unprepare(q->clk); clk_unprepare(q->clk_en); + + if (q->ahb_addr) + iounmap(q->ahb_addr); + return 0; } -- cgit v1.3-6-gb490 From 80d37724089bc5d09fa12601a763bde01899ba88 Mon Sep 17 00:00:00 2001 From: Han Xu Date: Tue, 4 Aug 2015 10:25:29 -0500 Subject: mtd: spi-nor: fsl-quadspi: use quirk to distinguish different qspi version add several quirk to distinguish different version of qspi module. Signed-off-by: Han Xu Signed-off-by: Frank Li Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 2d460368ce5f..91bfeac79722 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -28,6 +28,11 @@ #include #include +/* Controller needs driver to swap endian */ +#define QUADSPI_QUIRK_SWAP_ENDIAN (1 << 0) +/* Controller needs 4x internal clock */ +#define QUADSPI_QUIRK_4X_INT_CLK (1 << 1) + /* The registers */ #define QUADSPI_MCR 0x00 #define QUADSPI_MCR_RESERVED_SHIFT 16 @@ -204,20 +209,23 @@ struct fsl_qspi_devtype_data { int rxfifo; int txfifo; int ahb_buf_size; + int driver_data; }; static struct fsl_qspi_devtype_data vybrid_data = { .devtype = FSL_QUADSPI_VYBRID, .rxfifo = 128, .txfifo = 64, - .ahb_buf_size = 1024 + .ahb_buf_size = 1024, + .driver_data = QUADSPI_QUIRK_SWAP_ENDIAN, }; static struct fsl_qspi_devtype_data imx6sx_data = { .devtype = FSL_QUADSPI_IMX6SX, .rxfifo = 128, .txfifo = 512, - .ahb_buf_size = 1024 + .ahb_buf_size = 1024, + .driver_data = QUADSPI_QUIRK_4X_INT_CLK, }; #define FSL_QSPI_MAX_CHIP 4 @@ -241,14 +249,14 @@ struct fsl_qspi { struct mutex lock; }; -static inline int is_vybrid_qspi(struct fsl_qspi *q) +static inline int needs_swap_endian(struct fsl_qspi *q) { - return q->devtype_data->devtype == FSL_QUADSPI_VYBRID; + return q->devtype_data->driver_data & QUADSPI_QUIRK_SWAP_ENDIAN; } -static inline int is_imx6sx_qspi(struct fsl_qspi *q) +static inline int needs_4x_clock(struct fsl_qspi *q) { - return q->devtype_data->devtype == FSL_QUADSPI_IMX6SX; + return q->devtype_data->driver_data & QUADSPI_QUIRK_4X_INT_CLK; } /* @@ -257,7 +265,7 @@ static inline int is_imx6sx_qspi(struct fsl_qspi *q) */ static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a) { - return is_vybrid_qspi(q) ? __swab32(a) : a; + return needs_swap_endian(q) ? __swab32(a) : a; } static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q) @@ -652,7 +660,7 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q) unsigned long rate = q->clk_rate; int ret; - if (is_imx6sx_qspi(q)) + if (needs_4x_clock(q)) rate *= 4; ret = clk_set_rate(q->clk, rate); -- cgit v1.3-6-gb490 From d371cbfc151c6a7229150da0954d1f74ea4dcd39 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 4 Aug 2015 10:25:35 -0500 Subject: mtd: spi-nor: fsl-quadspi: add imx7d support Support i.mx7d. quadspi in i.mx7d increase rxfifo. require fill at least 16byte to trigger data transfer. Signed-off-by: Frank Li Signed-off-by: Han Xu Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 91bfeac79722..b567756b4cc2 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -32,6 +32,11 @@ #define QUADSPI_QUIRK_SWAP_ENDIAN (1 << 0) /* Controller needs 4x internal clock */ #define QUADSPI_QUIRK_4X_INT_CLK (1 << 1) +/* + * TKT253890, Controller needs driver to fill txfifo till 16 byte to + * trigger data transfer even though extern data will not transferred. + */ +#define QUADSPI_QUIRK_TKT253890 (1 << 2) /* The registers */ #define QUADSPI_MCR 0x00 @@ -202,6 +207,7 @@ enum fsl_qspi_devtype { FSL_QUADSPI_VYBRID, FSL_QUADSPI_IMX6SX, + FSL_QUADSPI_IMX7D, }; struct fsl_qspi_devtype_data { @@ -228,6 +234,15 @@ static struct fsl_qspi_devtype_data imx6sx_data = { .driver_data = QUADSPI_QUIRK_4X_INT_CLK, }; +static struct fsl_qspi_devtype_data imx7d_data = { + .devtype = FSL_QUADSPI_IMX7D, + .rxfifo = 512, + .txfifo = 512, + .ahb_buf_size = 1024, + .driver_data = QUADSPI_QUIRK_TKT253890 + | QUADSPI_QUIRK_4X_INT_CLK, +}; + #define FSL_QSPI_MAX_CHIP 4 struct fsl_qspi { struct mtd_info mtd[FSL_QSPI_MAX_CHIP]; @@ -259,6 +274,11 @@ static inline int needs_4x_clock(struct fsl_qspi *q) return q->devtype_data->driver_data & QUADSPI_QUIRK_4X_INT_CLK; } +static inline int needs_fill_txfifo(struct fsl_qspi *q) +{ + return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT253890; +} + /* * An IC bug makes us to re-arrange the 32-bit data. * The following chips, such as IMX6SLX, have fixed this bug. @@ -560,6 +580,11 @@ static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, txbuf++; } + /* fill the TXFIFO upto 16 bytes for i.MX7d */ + if (needs_fill_txfifo(q)) + for (; i < 4; i++) + writel(tmp, q->iobase + QUADSPI_TBDR); + /* Trigger it */ ret = fsl_qspi_runcmd(q, opcode, to, count); @@ -679,6 +704,7 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q) static const struct of_device_id fsl_qspi_dt_ids[] = { { .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, }, { .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, }, + { .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids); -- cgit v1.3-6-gb490 From 74a081d14f579d0a1de845ba63e8ee5f0c511258 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 4 Aug 2015 10:25:47 -0500 Subject: mtd: spi-nor: fsl-quadspi: add i.mx6ul support Add i.mx6ul chip support Signed-off-by: Frank Li Acked-by: Han xu Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index b567756b4cc2..a5db7ad8fc20 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -208,6 +208,7 @@ enum fsl_qspi_devtype { FSL_QUADSPI_VYBRID, FSL_QUADSPI_IMX6SX, FSL_QUADSPI_IMX7D, + FSL_QUADSPI_IMX6UL, }; struct fsl_qspi_devtype_data { @@ -243,6 +244,15 @@ static struct fsl_qspi_devtype_data imx7d_data = { | QUADSPI_QUIRK_4X_INT_CLK, }; +static struct fsl_qspi_devtype_data imx6ul_data = { + .devtype = FSL_QUADSPI_IMX6UL, + .rxfifo = 128, + .txfifo = 512, + .ahb_buf_size = 1024, + .driver_data = QUADSPI_QUIRK_TKT253890 + | QUADSPI_QUIRK_4X_INT_CLK, +}; + #define FSL_QSPI_MAX_CHIP 4 struct fsl_qspi { struct mtd_info mtd[FSL_QSPI_MAX_CHIP]; @@ -705,6 +715,7 @@ static const struct of_device_id fsl_qspi_dt_ids[] = { { .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, }, { .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, }, { .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, }, + { .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids); -- cgit v1.3-6-gb490 From cacbef40aac478fb25fb7d18ac22d41a11ce06e2 Mon Sep 17 00:00:00 2001 From: Allen Xu Date: Tue, 4 Aug 2015 10:25:58 -0500 Subject: mtd: spi-nor: fsl-quadspi: i.MX6SX: fixed the random QSPI access failed issue We found there is a low probability(5%) QSPI access timeout issue, usually it happened on kernel boot stage, the first time kernel tried to access QSPI chip. The READ_ID command was sent but not executed, consequently the probe function failed. The root cause is that the divider is not glitchless in i.MX6SX chip. If qspi clock enabled then change clock frequency by call clk_set_rate, there will be glitch at low possiblity rate and pass to qspi controller. The controler will be hang by this glitch. Based on the new clock flag(CLK_SET_RATE_GATE) and new framework, we need to change the approach of seting clock rate. 1. Disable clock. 2. call clk_set_rate. 3. Enable clock again. Signed-off-by: Han Xu Signed-off-by: Frank Li Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 81 +++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index a5db7ad8fc20..8a69b2caa792 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -655,6 +655,32 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q) q->iobase + QUADSPI_BFGENCR); } +/* This function was used to prepare and enable QSPI clock */ +static int fsl_qspi_clk_prep_enable(struct fsl_qspi *q) +{ + int ret; + + ret = clk_prepare_enable(q->clk_en); + if (ret) + return ret; + + ret = clk_prepare_enable(q->clk); + if (ret) { + clk_disable_unprepare(q->clk_en); + return ret; + } + + return 0; +} + +/* This function was used to disable and unprepare QSPI clock */ +static void fsl_qspi_clk_disable_unprep(struct fsl_qspi *q) +{ + clk_disable_unprepare(q->clk); + clk_disable_unprepare(q->clk_en); + +} + /* We use this function to do some basic init for spi_nor_scan(). */ static int fsl_qspi_nor_setup(struct fsl_qspi *q) { @@ -662,11 +688,18 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q) u32 reg; int ret; - /* the default frequency, we will change it in the future.*/ + /* disable and unprepare clock to avoid glitch pass to controller */ + fsl_qspi_clk_disable_unprep(q); + + /* the default frequency, we will change it in the future. */ ret = clk_set_rate(q->clk, 66000000); if (ret) return ret; + ret = fsl_qspi_clk_prep_enable(q); + if (ret) + return ret; + /* Init the LUT table. */ fsl_qspi_init_lut(q); @@ -698,10 +731,17 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q) if (needs_4x_clock(q)) rate *= 4; + /* disable and unprepare clock to avoid glitch pass to controller */ + fsl_qspi_clk_disable_unprep(q); + ret = clk_set_rate(q->clk, rate); if (ret) return ret; + ret = fsl_qspi_clk_prep_enable(q); + if (ret) + return ret; + /* Init the LUT table again. */ fsl_qspi_init_lut(q); @@ -844,22 +884,16 @@ static int fsl_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) int ret; mutex_lock(&q->lock); - ret = clk_enable(q->clk_en); - if (ret) - goto err_mutex; - ret = clk_enable(q->clk); + ret = fsl_qspi_clk_prep_enable(q); if (ret) - goto err_clk; + goto err_mutex; fsl_qspi_set_base_addr(q, nor); return 0; -err_clk: - clk_disable(q->clk_en); err_mutex: mutex_unlock(&q->lock); - return ret; } @@ -867,8 +901,7 @@ static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) { struct fsl_qspi *q = nor->priv; - clk_disable(q->clk); - clk_disable(q->clk_en); + fsl_qspi_clk_disable_unprep(q); mutex_unlock(&q->lock); } @@ -918,15 +951,9 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (IS_ERR(q->clk)) return PTR_ERR(q->clk); - ret = clk_prepare_enable(q->clk_en); + ret = fsl_qspi_clk_prep_enable(q); if (ret) { - dev_err(dev, "cannot enable the qspi_en clock: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(q->clk); - if (ret) { - dev_err(dev, "cannot enable the qspi clock: %d\n", ret); + dev_err(dev, "can not enable the clock\n"); goto clk_failed; } @@ -1032,8 +1059,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (ret) goto last_init_failed; - clk_disable(q->clk); - clk_disable(q->clk_en); + fsl_qspi_clk_disable_unprep(q); return 0; last_init_failed: @@ -1046,9 +1072,9 @@ last_init_failed: mutex_failed: mutex_destroy(&q->lock); irq_failed: - clk_disable_unprepare(q->clk); + fsl_qspi_clk_disable_unprep(q); clk_failed: - clk_disable_unprepare(q->clk_en); + dev_err(dev, "Freescale QuadSPI probe failed\n"); return ret; } @@ -1069,8 +1095,6 @@ static int fsl_qspi_remove(struct platform_device *pdev) writel(0x0, q->iobase + QUADSPI_RSER); mutex_destroy(&q->lock); - clk_unprepare(q->clk); - clk_unprepare(q->clk_en); if (q->ahb_addr) iounmap(q->ahb_addr); @@ -1085,12 +1109,19 @@ static int fsl_qspi_suspend(struct platform_device *pdev, pm_message_t state) static int fsl_qspi_resume(struct platform_device *pdev) { + int ret; struct fsl_qspi *q = platform_get_drvdata(pdev); + ret = fsl_qspi_clk_prep_enable(q); + if (ret) + return ret; + fsl_qspi_nor_setup(q); fsl_qspi_set_map_addr(q); fsl_qspi_nor_setup_last(q); + fsl_qspi_clk_disable_unprep(q); + return 0; } -- cgit v1.3-6-gb490 From 5cc66cb7345d1bac71e94d7fd05dc86506f59dfe Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 4 Aug 2015 10:26:04 -0500 Subject: mtd: spi-nor: fsl-quadspi: workaround qspi can't wakeup from wait mode QSPI1 cannot wake up CCM from WAIT mode on SX ARD board, add pmqos to let PM NOT enter WAIT mode when accessing QSPI1, refer to TKT245618. Signed-off-by: Frank Li Signed-off-by: Han Xu Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 8a69b2caa792..676b36361076 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -27,6 +27,7 @@ #include #include #include +#include /* Controller needs driver to swap endian */ #define QUADSPI_QUIRK_SWAP_ENDIAN (1 << 0) @@ -37,6 +38,8 @@ * trigger data transfer even though extern data will not transferred. */ #define QUADSPI_QUIRK_TKT253890 (1 << 2) +/* Controller cannot wake up from wait mode, TKT245618 */ +#define QUADSPI_QUIRK_TKT245618 (1 << 3) /* The registers */ #define QUADSPI_MCR 0x00 @@ -232,7 +235,8 @@ static struct fsl_qspi_devtype_data imx6sx_data = { .rxfifo = 128, .txfifo = 512, .ahb_buf_size = 1024, - .driver_data = QUADSPI_QUIRK_4X_INT_CLK, + .driver_data = QUADSPI_QUIRK_4X_INT_CLK + | QUADSPI_QUIRK_TKT245618, }; static struct fsl_qspi_devtype_data imx7d_data = { @@ -272,6 +276,7 @@ struct fsl_qspi { unsigned int chip_base_addr; /* We may support two chips. */ bool has_second_chip; struct mutex lock; + struct pm_qos_request pm_qos_req; }; static inline int needs_swap_endian(struct fsl_qspi *q) @@ -289,6 +294,11 @@ static inline int needs_fill_txfifo(struct fsl_qspi *q) return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT253890; } +static inline int needs_wakeup_wait_mode(struct fsl_qspi *q) +{ + return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618; +} + /* * An IC bug makes us to re-arrange the 32-bit data. * The following chips, such as IMX6SLX, have fixed this bug. @@ -670,12 +680,18 @@ static int fsl_qspi_clk_prep_enable(struct fsl_qspi *q) return ret; } + if (needs_wakeup_wait_mode(q)) + pm_qos_add_request(&q->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, 0); + return 0; } /* This function was used to disable and unprepare QSPI clock */ static void fsl_qspi_clk_disable_unprep(struct fsl_qspi *q) { + if (needs_wakeup_wait_mode(q)) + pm_qos_remove_request(&q->pm_qos_req); + clk_disable_unprepare(q->clk); clk_disable_unprepare(q->clk_en); @@ -926,6 +942,10 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (!q->nor_num || q->nor_num > FSL_QSPI_MAX_CHIP) return -ENODEV; + q->dev = dev; + q->devtype_data = (struct fsl_qspi_devtype_data *)of_id->data; + platform_set_drvdata(pdev, q); + /* find the resources */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI"); q->iobase = devm_ioremap_resource(dev, res); @@ -971,10 +991,6 @@ static int fsl_qspi_probe(struct platform_device *pdev) goto irq_failed; } - q->dev = dev; - q->devtype_data = (struct fsl_qspi_devtype_data *)of_id->data; - platform_set_drvdata(pdev, q); - ret = fsl_qspi_nor_setup(q); if (ret) goto irq_failed; -- cgit v1.3-6-gb490 From 8b8319c8b7d0385659c2df6376955cb6a1d918b6 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 4 Aug 2015 10:26:10 -0500 Subject: mtd: spi-nor: fsl-quadspi: reset the module in the probe The uboot may run the QuadSpi controler with command: #sf probe So we should reset the module in the probe. This patch also clear the pending interrupts which arised by the uboot code. Signed-off-by: Huang Shijie Signed-off-by: Frank Li Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 676b36361076..0144821a3692 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -716,6 +716,11 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q) if (ret) return ret; + /* Reset the module */ + writel(QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK, + base + QUADSPI_MCR); + udelay(1); + /* Init the LUT table. */ fsl_qspi_init_lut(q); @@ -733,6 +738,9 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q) writel(QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK, base + QUADSPI_MCR); + /* clear all interrupt status */ + writel(0xffffffff, q->iobase + QUADSPI_FR); + /* enable the interrupt */ writel(QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER); -- cgit v1.3-6-gb490 From 788a6cddda9ba83276e37567c17bb78406904074 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Tue, 4 Aug 2015 10:26:16 -0500 Subject: mtd: spi-nor: fsl-quadspi: fix unsupported cmd when run flash_erase Erase function will use cmd 0x20 (SPINOR_OP_BE_4K) if kenrel enable option CONFIG_MTD_SPI_NOR_USE_4K_SECTORS. This command is not in fsl-quadspi driver LUT. So driver continue report fsl-quadspi 21e0000.qspi: Unsupported cmd 0x20. This patch fix this issue. Signed-off-by: Frank Li Acked-by: Han Xu Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 0144821a3692..d32b7e04ccca 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -397,14 +397,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) /* Erase a sector */ lut_base = SEQID_SE * 4; - if (q->nor_size <= SZ_16M) { - cmd = SPINOR_OP_SE; - addrlen = ADDR24BIT; - } else { - /* use the 4-byte address */ - cmd = SPINOR_OP_SE; - addrlen = ADDR32BIT; - } + cmd = q->nor[0].erase_opcode; + addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT; writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), base + QUADSPI_LUT(lut_base)); @@ -473,6 +467,8 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) case SPINOR_OP_BRWR: return SEQID_BRWR; default: + if (cmd == q->nor[0].erase_opcode) + return SEQID_SE; dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd); break; } -- cgit v1.3-6-gb490 From 93d988310bb2f5ed16ba075bbc4281aa06907e72 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 5 Aug 2015 16:23:43 +0800 Subject: ACPI / sysfs: Add ACPI_LV_REPAIR debug level. This patch updates debug_level file, adding ACPI_LV_REPAIR. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sysfs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 0876d77b3206..7ab6ba46866f 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -69,6 +69,7 @@ static const struct acpi_dlevel acpi_debug_levels[] = { ACPI_DEBUG_INIT(ACPI_LV_INIT), ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT), ACPI_DEBUG_INIT(ACPI_LV_INFO), + ACPI_DEBUG_INIT(ACPI_LV_REPAIR), ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES), ACPI_DEBUG_INIT(ACPI_LV_PARSE), -- cgit v1.3-6-gb490 From 7901a052a981691d18f4e8f91fc27e40849b7336 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 5 Aug 2015 16:23:51 +0800 Subject: ACPI / sysfs: Update method tracing facility. This patch updates the method tracing facility as the acpi_debug_trace() API has been updated to allow it to trace AML interpreter execution, the meanings and the usages of the API parameters are changed due to the updates. The new API: 1. Uses ACPI_TRACE_ENABLED flag to indicate the enabling of the tracer; 2. Allows tracer still can be enabled when method name is not specified so that the AML interpreter execution can be traced without knowing the method name, which is useful for kernel boot tracing; 3. Supports arbitrary full path name, it doesn't need to be a name related to an entrance of acpi_evaluate_object(). Note that the sysfs parameters are also updated so that when reading the attribute files, ACPICA internal settings are returned. In order to make the sysfs parameters (acpi.trace_state) available during boot, this patch adds code to bypass ACPICA semaphore/mutex invocations when acpi mutex utilities haven't been initialized. This patch doesn't update documentation of method tracing facility, it will be updated by further patches. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 8 +++ drivers/acpi/sysfs.c | 136 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 108 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 3b8963f21b36..6341cb523dc4 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -83,6 +83,7 @@ static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; static struct workqueue_struct *kacpi_notify_wq; static struct workqueue_struct *kacpi_hotplug_wq; +static bool acpi_os_initialized; /* * This list of permanent mappings is for memory that may be accessed from @@ -1316,6 +1317,9 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) long jiffies; int ret = 0; + if (!acpi_os_initialized) + return AE_OK; + if (!sem || (units < 1)) return AE_BAD_PARAMETER; @@ -1355,6 +1359,9 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) { struct semaphore *sem = (struct semaphore *)handle; + if (!acpi_os_initialized) + return AE_OK; + if (!sem || (units < 1)) return AE_BAD_PARAMETER; @@ -1863,6 +1870,7 @@ acpi_status __init acpi_os_initialize(void) rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register); pr_debug(PREFIX "%s: map reset_reg status %d\n", __func__, rv); } + acpi_os_initialized = true; return AE_OK; } diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 7ab6ba46866f..8979e4a8d066 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -70,6 +70,7 @@ static const struct acpi_dlevel acpi_debug_levels[] = { ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT), ACPI_DEBUG_INIT(ACPI_LV_INFO), ACPI_DEBUG_INIT(ACPI_LV_REPAIR), + ACPI_DEBUG_INIT(ACPI_LV_TRACE_POINT), ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES), ACPI_DEBUG_INIT(ACPI_LV_PARSE), @@ -163,55 +164,118 @@ static const struct kernel_param_ops param_ops_debug_level = { module_param_cb(debug_layer, ¶m_ops_debug_layer, &acpi_dbg_layer, 0644); module_param_cb(debug_level, ¶m_ops_debug_level, &acpi_dbg_level, 0644); -static char trace_method_name[6]; -module_param_string(trace_method_name, trace_method_name, 6, 0644); -static unsigned int trace_debug_layer; -module_param(trace_debug_layer, uint, 0644); -static unsigned int trace_debug_level; -module_param(trace_debug_level, uint, 0644); +static char* trace_method_name; +static bool trace_method_kmalloced; -static int param_set_trace_state(const char *val, struct kernel_param *kp) +int param_set_trace_method_name(const char *val, const struct kernel_param *kp) { - int result = 0; + u32 saved_flags = 0; - if (!strncmp(val, "enable", sizeof("enable") - 1)) { - result = acpi_debug_trace(trace_method_name, trace_debug_level, - trace_debug_layer, 0); - if (result) - result = -EBUSY; - goto exit; + if (strlen(val) > 1024) { + pr_err("%s: string parameter too long\n", kp->name); + return -ENOSPC; } - if (!strncmp(val, "disable", sizeof("disable") - 1)) { - int name = 0; - result = acpi_debug_trace((char *)&name, trace_debug_level, - trace_debug_layer, 0); - if (result) - result = -EBUSY; - goto exit; - } + /* + * It's not safe to update acpi_gbl_trace_method_name without + * having the tracer stopped, so we save the original tracer + * state and disable it. + */ + saved_flags = acpi_gbl_trace_flags; + (void)acpi_debug_trace(NULL, + acpi_gbl_trace_dbg_level, + acpi_gbl_trace_dbg_layer, + 0); + + if (trace_method_kmalloced) + kfree(trace_method_name); + trace_method_name = NULL; + trace_method_kmalloced = false; + + /* This is a hack. We can't kmalloc in early boot. */ + if (slab_is_available()) { + trace_method_name = kstrdup(val, GFP_KERNEL); + if (!trace_method_name) + return -ENOMEM; + trace_method_kmalloced = true; + } else + trace_method_name = (char *)val; - if (!strncmp(val, "1", 1)) { - result = acpi_debug_trace(trace_method_name, trace_debug_level, - trace_debug_layer, 1); - if (result) - result = -EBUSY; - goto exit; - } + /* Restore the original tracer state */ + (void)acpi_debug_trace(trace_method_name, + acpi_gbl_trace_dbg_level, + acpi_gbl_trace_dbg_layer, + saved_flags); - result = -EINVAL; -exit: - return result; + return 0; +} + +static int param_get_trace_method_name(char *buffer, const struct kernel_param *kp) +{ + return scnprintf(buffer, PAGE_SIZE, "%s", acpi_gbl_trace_method_name); +} + +static const struct kernel_param_ops param_ops_trace_method = { + .set = param_set_trace_method_name, + .get = param_get_trace_method_name, +}; + +static const struct kernel_param_ops param_ops_trace_attrib = { + .set = param_set_uint, + .get = param_get_uint, +}; + +module_param_cb(trace_method_name, ¶m_ops_trace_method, &trace_method_name, 0644); +module_param_cb(trace_debug_layer, ¶m_ops_trace_attrib, &acpi_gbl_trace_dbg_layer, 0644); +module_param_cb(trace_debug_level, ¶m_ops_trace_attrib, &acpi_gbl_trace_dbg_level, 0644); + +static int param_set_trace_state(const char *val, struct kernel_param *kp) +{ + acpi_status status; + const char *method = trace_method_name; + u32 flags = 0; + +/* So "xxx-once" comparison should go prior than "xxx" comparison */ +#define acpi_compare_param(val, key) \ + strncmp((val), (key), sizeof(key) - 1) + + if (!acpi_compare_param(val, "enable")) { + method = NULL; + flags = ACPI_TRACE_ENABLED; + } else if (!acpi_compare_param(val, "disable")) + method = NULL; + else if (!acpi_compare_param(val, "method-once")) + flags = ACPI_TRACE_ENABLED | ACPI_TRACE_ONESHOT; + else if (!acpi_compare_param(val, "method")) + flags = ACPI_TRACE_ENABLED; + else if (!acpi_compare_param(val, "opcode-once")) + flags = ACPI_TRACE_ENABLED | ACPI_TRACE_ONESHOT | ACPI_TRACE_OPCODE; + else if (!acpi_compare_param(val, "opcode")) + flags = ACPI_TRACE_ENABLED | ACPI_TRACE_OPCODE; + else + return -EINVAL; + + status = acpi_debug_trace(method, + acpi_gbl_trace_dbg_level, + acpi_gbl_trace_dbg_layer, + flags); + if (ACPI_FAILURE(status)) + return -EBUSY; + + return 0; } static int param_get_trace_state(char *buffer, struct kernel_param *kp) { - if (!acpi_gbl_trace_method_name) + if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED)) return sprintf(buffer, "disable"); else { - if (acpi_gbl_trace_flags & 1) - return sprintf(buffer, "1"); - else + if (acpi_gbl_trace_method_name) { + if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) + return sprintf(buffer, "method-once"); + else + return sprintf(buffer, "method"); + } else return sprintf(buffer, "enable"); } return 0; -- cgit v1.3-6-gb490 From a0186bcf7c21907c78ab2b4bc50f3fb2b5047806 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 5 Aug 2015 16:23:57 +0800 Subject: ACPI / sysfs: Add support to allow leading "\" missing in trace_method_name. Since _SB.PCI0 can be used as relative path from root and can be easily converted into internal trace_method_name format, we allow users to specify trace_method_name using relative paths from root. Note this is useful for grub2 for which users failed to pass "\" from the grub configuration file. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sysfs.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 8979e4a8d066..40a42655227c 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -164,14 +164,18 @@ static const struct kernel_param_ops param_ops_debug_level = { module_param_cb(debug_layer, ¶m_ops_debug_layer, &acpi_dbg_layer, 0644); module_param_cb(debug_level, ¶m_ops_debug_level, &acpi_dbg_level, 0644); -static char* trace_method_name; -static bool trace_method_kmalloced; +static char trace_method_name[1024]; int param_set_trace_method_name(const char *val, const struct kernel_param *kp) { u32 saved_flags = 0; + bool is_abs_path = true; - if (strlen(val) > 1024) { + if (*val != '\\') + is_abs_path = false; + + if ((is_abs_path && strlen(val) > 1023) || + (!is_abs_path && strlen(val) > 1022)) { pr_err("%s: string parameter too long\n", kp->name); return -ENOSPC; } @@ -187,19 +191,13 @@ int param_set_trace_method_name(const char *val, const struct kernel_param *kp) acpi_gbl_trace_dbg_layer, 0); - if (trace_method_kmalloced) - kfree(trace_method_name); - trace_method_name = NULL; - trace_method_kmalloced = false; - /* This is a hack. We can't kmalloc in early boot. */ - if (slab_is_available()) { - trace_method_name = kstrdup(val, GFP_KERNEL); - if (!trace_method_name) - return -ENOMEM; - trace_method_kmalloced = true; - } else - trace_method_name = (char *)val; + if (is_abs_path) + strcpy(trace_method_name, val); + else { + trace_method_name[0] = '\\'; + strcpy(trace_method_name+1, val); + } /* Restore the original tracer state */ (void)acpi_debug_trace(trace_method_name, -- cgit v1.3-6-gb490 From 10742619ac63641bcce0a7c07f0dc7509201ed72 Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Sat, 1 Aug 2015 21:32:17 +0800 Subject: ACPI: fix acpi_debugfs_init prototype acpi_debugfs_init function is declared with return type int in drivers/acpi/internal.h when CONFIG_DEBUG_FS is enabled, but its definition in drivers/acpi/debugfs.c has return type void. This is due to commit aecad432fd68 ("ACPI: Cleanup custom_method debug stuff"), which changed the return type from int to void without updating the declaration. Fix this inconsistency by updating acpi_debugfs_init prototype. While at it, include internal.h in debugfs.c so that the compiler can check that the declaration and definition remain compatible. Signed-off-by: Nicolas Iooss Signed-off-by: Rafael J. Wysocki --- drivers/acpi/debugfs.c | 2 ++ drivers/acpi/internal.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/debugfs.c b/drivers/acpi/debugfs.c index 6b1919f6bd82..68bb305b977f 100644 --- a/drivers/acpi/debugfs.c +++ b/drivers/acpi/debugfs.c @@ -7,6 +7,8 @@ #include #include +#include "internal.h" + #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("debugfs"); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 8c71cb8335c0..daf0974d863c 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -67,7 +67,7 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val); #ifdef CONFIG_DEBUG_FS extern struct dentry *acpi_debugfs_dir; -int acpi_debugfs_init(void); +void acpi_debugfs_init(void); #else static inline void acpi_debugfs_init(void) { return; } #endif -- cgit v1.3-6-gb490 From 737002b5de3d15b3012feea17f782a628b24699b Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 29 Jul 2015 16:22:58 +0530 Subject: PM / OPP: Relocate few routines In order to prepare for the later commits, this relocates few routines towards the top as they will be used earlier in the code. Reviewed-by: Stephen Boyd Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 277 ++++++++++++++++++++++++----------------------- 1 file changed, 139 insertions(+), 138 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 677fb2843553..8c3fd57975fb 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -437,6 +437,102 @@ static struct device_opp *_add_device_opp(struct device *dev) return dev_opp; } +/** + * _kfree_device_rcu() - Free device_opp RCU handler + * @head: RCU head + */ +static void _kfree_device_rcu(struct rcu_head *head) +{ + struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head); + + kfree_rcu(device_opp, rcu_head); +} + +/** + * _kfree_opp_rcu() - Free OPP RCU handler + * @head: RCU head + */ +static void _kfree_opp_rcu(struct rcu_head *head) +{ + struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head); + + kfree_rcu(opp, rcu_head); +} + +/** + * _opp_remove() - Remove an OPP from a table definition + * @dev_opp: points back to the device_opp struct this opp belongs to + * @opp: pointer to the OPP to remove + * + * This function removes an opp definition from the opp list. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * It is assumed that the caller holds required mutex for an RCU updater + * strategy. + */ +static void _opp_remove(struct device_opp *dev_opp, + struct dev_pm_opp *opp) +{ + /* + * Notify the changes in the availability of the operable + * frequency/voltage list. + */ + srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp); + list_del_rcu(&opp->node); + call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); + + if (list_empty(&dev_opp->opp_list)) { + list_del_rcu(&dev_opp->node); + call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head, + _kfree_device_rcu); + } +} + +/** + * dev_pm_opp_remove() - Remove an OPP from OPP list + * @dev: device for which we do this operation + * @freq: OPP to remove with matching 'freq' + * + * This function removes an opp from the opp list. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + */ +void dev_pm_opp_remove(struct device *dev, unsigned long freq) +{ + struct dev_pm_opp *opp; + struct device_opp *dev_opp; + bool found = false; + + /* Hold our list modification lock here */ + mutex_lock(&dev_opp_list_lock); + + dev_opp = _find_device_opp(dev); + if (IS_ERR(dev_opp)) + goto unlock; + + list_for_each_entry(opp, &dev_opp->opp_list, node) { + if (opp->rate == freq) { + found = true; + break; + } + } + + if (!found) { + dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n", + __func__, freq); + goto unlock; + } + + _opp_remove(dev_opp, opp); +unlock: + mutex_unlock(&dev_opp_list_lock); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_remove); + /** * _opp_add_dynamic() - Allocate a dynamic OPP. * @dev: device for which we do this operation @@ -569,102 +665,6 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) } EXPORT_SYMBOL_GPL(dev_pm_opp_add); -/** - * _kfree_opp_rcu() - Free OPP RCU handler - * @head: RCU head - */ -static void _kfree_opp_rcu(struct rcu_head *head) -{ - struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head); - - kfree_rcu(opp, rcu_head); -} - -/** - * _kfree_device_rcu() - Free device_opp RCU handler - * @head: RCU head - */ -static void _kfree_device_rcu(struct rcu_head *head) -{ - struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head); - - kfree_rcu(device_opp, rcu_head); -} - -/** - * _opp_remove() - Remove an OPP from a table definition - * @dev_opp: points back to the device_opp struct this opp belongs to - * @opp: pointer to the OPP to remove - * - * This function removes an opp definition from the opp list. - * - * Locking: The internal device_opp and opp structures are RCU protected. - * It is assumed that the caller holds required mutex for an RCU updater - * strategy. - */ -static void _opp_remove(struct device_opp *dev_opp, - struct dev_pm_opp *opp) -{ - /* - * Notify the changes in the availability of the operable - * frequency/voltage list. - */ - srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp); - list_del_rcu(&opp->node); - call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); - - if (list_empty(&dev_opp->opp_list)) { - list_del_rcu(&dev_opp->node); - call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head, - _kfree_device_rcu); - } -} - -/** - * dev_pm_opp_remove() - Remove an OPP from OPP list - * @dev: device for which we do this operation - * @freq: OPP to remove with matching 'freq' - * - * This function removes an opp from the opp list. - * - * Locking: The internal device_opp and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. - */ -void dev_pm_opp_remove(struct device *dev, unsigned long freq) -{ - struct dev_pm_opp *opp; - struct device_opp *dev_opp; - bool found = false; - - /* Hold our list modification lock here */ - mutex_lock(&dev_opp_list_lock); - - dev_opp = _find_device_opp(dev); - if (IS_ERR(dev_opp)) - goto unlock; - - list_for_each_entry(opp, &dev_opp->opp_list, node) { - if (opp->rate == freq) { - found = true; - break; - } - } - - if (!found) { - dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n", - __func__, freq); - goto unlock; - } - - _opp_remove(dev_opp, opp); -unlock: - mutex_unlock(&dev_opp_list_lock); -} -EXPORT_SYMBOL_GPL(dev_pm_opp_remove); - /** * _opp_set_availability() - helper to set the availability of an opp * @dev: device for which we do this operation @@ -824,6 +824,49 @@ struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev) EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier); #ifdef CONFIG_OF +/** + * of_free_opp_table() - Free OPP table entries created from static DT entries + * @dev: device pointer used to lookup device OPPs. + * + * Free OPPs created using static entries present in DT. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function indirectly uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + */ +void of_free_opp_table(struct device *dev) +{ + struct device_opp *dev_opp; + struct dev_pm_opp *opp, *tmp; + + /* Check for existing list for 'dev' */ + dev_opp = _find_device_opp(dev); + if (IS_ERR(dev_opp)) { + int error = PTR_ERR(dev_opp); + + if (error != -ENODEV) + WARN(1, "%s: dev_opp: %d\n", + IS_ERR_OR_NULL(dev) ? + "Invalid device" : dev_name(dev), + error); + return; + } + + /* Hold our list modification lock here */ + mutex_lock(&dev_opp_list_lock); + + /* Free static OPPs */ + list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) { + if (!opp->dynamic) + _opp_remove(dev_opp, opp); + } + + mutex_unlock(&dev_opp_list_lock); +} +EXPORT_SYMBOL_GPL(of_free_opp_table); + /** * of_init_opp_table() - Initialize opp table from device tree * @dev: device pointer used to lookup device OPPs. @@ -882,46 +925,4 @@ int of_init_opp_table(struct device *dev) return 0; } EXPORT_SYMBOL_GPL(of_init_opp_table); - -/** - * of_free_opp_table() - Free OPP table entries created from static DT entries - * @dev: device pointer used to lookup device OPPs. - * - * Free OPPs created using static entries present in DT. - * - * Locking: The internal device_opp and opp structures are RCU protected. - * Hence this function indirectly uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. - */ -void of_free_opp_table(struct device *dev) -{ - struct device_opp *dev_opp; - struct dev_pm_opp *opp, *tmp; - - /* Check for existing list for 'dev' */ - dev_opp = _find_device_opp(dev); - if (IS_ERR(dev_opp)) { - int error = PTR_ERR(dev_opp); - if (error != -ENODEV) - WARN(1, "%s: dev_opp: %d\n", - IS_ERR_OR_NULL(dev) ? - "Invalid device" : dev_name(dev), - error); - return; - } - - /* Hold our list modification lock here */ - mutex_lock(&dev_opp_list_lock); - - /* Free static OPPs */ - list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) { - if (!opp->dynamic) - _opp_remove(dev_opp, opp); - } - - mutex_unlock(&dev_opp_list_lock); -} -EXPORT_SYMBOL_GPL(of_free_opp_table); #endif -- cgit v1.3-6-gb490 From 3bac42caec612a1b82db7944570353cddca6a013 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 29 Jul 2015 16:22:59 +0530 Subject: PM / OPP: Create _remove_device_opp() for freeing dev_opp This will be used from multiple places later. Lets create a separate routine for that. Reviewed-by: Stephen Boyd Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 8c3fd57975fb..7895fdd64192 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -448,6 +448,22 @@ static void _kfree_device_rcu(struct rcu_head *head) kfree_rcu(device_opp, rcu_head); } +/** + * _remove_device_opp() - Removes a device OPP table + * @dev_opp: device OPP table to be removed. + * + * Removes/frees device OPP table it it doesn't contain any OPPs. + */ +static void _remove_device_opp(struct device_opp *dev_opp) +{ + if (!list_empty(&dev_opp->opp_list)) + return; + + list_del_rcu(&dev_opp->node); + call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head, + _kfree_device_rcu); +} + /** * _kfree_opp_rcu() - Free OPP RCU handler * @head: RCU head @@ -481,11 +497,7 @@ static void _opp_remove(struct device_opp *dev_opp, list_del_rcu(&opp->node); call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); - if (list_empty(&dev_opp->opp_list)) { - list_del_rcu(&dev_opp->node); - call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head, - _kfree_device_rcu); - } + _remove_device_opp(dev_opp); } /** -- cgit v1.3-6-gb490 From aa5f2f854f03e6dc3dec8874bbcff1452b4bc09e Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 29 Jul 2015 16:23:00 +0530 Subject: PM / OPP: Allocate dev_opp from _add_device_opp() There is no need to complicate _opp_add_dynamic() with allocation of dev_opp as well. Allocate it from _add_device_opp() instead. Reviewed-by: Stephen Boyd Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 50 ++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 7895fdd64192..28d70c9f86ed 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -408,11 +408,11 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); /** - * _add_device_opp() - Allocate a new device OPP table + * _add_device_opp() - Find device OPP table or allocate a new one * @dev: device for which we do this operation * - * New device node which uses OPPs - used when multiple devices with OPP tables - * are maintained. + * It tries to find an existing table first, if it couldn't find one, it + * allocates a new OPP table and returns that. * * Return: valid device_opp pointer if success, else NULL. */ @@ -420,6 +420,11 @@ static struct device_opp *_add_device_opp(struct device *dev) { struct device_opp *dev_opp; + /* Check for existing list for 'dev' first */ + dev_opp = _find_device_opp(dev); + if (!IS_ERR(dev_opp)) + return dev_opp; + /* * Allocate a new device OPP table. In the infrequent case where a new * device is needed to be added, we pay this penalty. @@ -575,7 +580,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove); static int _opp_add_dynamic(struct device *dev, unsigned long freq, long u_volt, bool dynamic) { - struct device_opp *dev_opp = NULL; + struct device_opp *dev_opp; struct dev_pm_opp *opp, *new_opp; struct list_head *head; int ret; @@ -592,19 +597,11 @@ static int _opp_add_dynamic(struct device *dev, unsigned long freq, new_opp->rate = freq; new_opp->u_volt = u_volt; new_opp->available = true; - new_opp->dynamic = dynamic; - - /* Check for existing list for 'dev' */ - dev_opp = _find_device_opp(dev); - if (IS_ERR(dev_opp)) { - dev_opp = _add_device_opp(dev); - if (!dev_opp) { - ret = -ENOMEM; - goto free_opp; - } - head = &dev_opp->opp_list; - goto list_add; + dev_opp = _add_device_opp(dev); + if (!dev_opp) { + ret = -ENOMEM; + goto free_opp; } /* @@ -612,15 +609,22 @@ static int _opp_add_dynamic(struct device *dev, unsigned long freq, * and discard if already present */ head = &dev_opp->opp_list; + + /* + * Need to use &dev_opp->opp_list in the condition part of the 'for' + * loop, don't replace it with head otherwise it will become an infinite + * loop. + */ list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) { - if (new_opp->rate <= opp->rate) - break; - else + if (new_opp->rate > opp->rate) { head = &opp->node; - } + continue; + } + + if (new_opp->rate < opp->rate) + break; - /* Duplicate OPPs ? */ - if (new_opp->rate == opp->rate) { + /* Duplicate OPPs */ ret = opp->available && new_opp->u_volt == opp->u_volt ? 0 : -EEXIST; @@ -630,7 +634,7 @@ static int _opp_add_dynamic(struct device *dev, unsigned long freq, goto free_opp; } -list_add: + new_opp->dynamic = dynamic; new_opp->dev_opp = dev_opp; list_add_rcu(&new_opp->node, head); mutex_unlock(&dev_opp_list_lock); -- cgit v1.3-6-gb490 From 23dacf6d2e993551ef3ae0629baf6f473930513c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 29 Jul 2015 16:23:01 +0530 Subject: PM / OPP: Break _opp_add_dynamic() into smaller functions Later commits would add support for new OPP bindings and this would be required then. So, lets do it in a separate patch to make it easily reviewable. Another change worth noticing is INIT_LIST_HEAD(&opp->node). We weren't doing it earlier as we never tried to delete a list node before it is added to list. But this wouldn't be the case anymore. We might try to delete a node (just to reuse the same code paths), without it being getting added to the list. Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Reviewed-by: Stephen Boyd Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 125 ++++++++++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 28d70c9f86ed..0d8dbf21c299 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -484,6 +484,7 @@ static void _kfree_opp_rcu(struct rcu_head *head) * _opp_remove() - Remove an OPP from a table definition * @dev_opp: points back to the device_opp struct this opp belongs to * @opp: pointer to the OPP to remove + * @notify: OPP_EVENT_REMOVE notification should be sent or not * * This function removes an opp definition from the opp list. * @@ -492,13 +493,14 @@ static void _kfree_opp_rcu(struct rcu_head *head) * strategy. */ static void _opp_remove(struct device_opp *dev_opp, - struct dev_pm_opp *opp) + struct dev_pm_opp *opp, bool notify) { /* * Notify the changes in the availability of the operable * frequency/voltage list. */ - srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp); + if (notify) + srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp); list_del_rcu(&opp->node); call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); @@ -544,12 +546,70 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) goto unlock; } - _opp_remove(dev_opp, opp); + _opp_remove(dev_opp, opp, true); unlock: mutex_unlock(&dev_opp_list_lock); } EXPORT_SYMBOL_GPL(dev_pm_opp_remove); +static struct dev_pm_opp *_allocate_opp(struct device *dev, + struct device_opp **dev_opp) +{ + struct dev_pm_opp *opp; + + /* allocate new OPP node */ + opp = kzalloc(sizeof(*opp), GFP_KERNEL); + if (!opp) + return NULL; + + INIT_LIST_HEAD(&opp->node); + + *dev_opp = _add_device_opp(dev); + if (!*dev_opp) { + kfree(opp); + return NULL; + } + + return opp; +} + +static int _opp_add(struct dev_pm_opp *new_opp, struct device_opp *dev_opp) +{ + struct dev_pm_opp *opp; + struct list_head *head = &dev_opp->opp_list; + + /* + * Insert new OPP in order of increasing frequency and discard if + * already present. + * + * Need to use &dev_opp->opp_list in the condition part of the 'for' + * loop, don't replace it with head otherwise it will become an infinite + * loop. + */ + list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) { + if (new_opp->rate > opp->rate) { + head = &opp->node; + continue; + } + + if (new_opp->rate < opp->rate) + break; + + /* Duplicate OPPs */ + dev_warn(dev_opp->dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n", + __func__, opp->rate, opp->u_volt, opp->available, + new_opp->rate, new_opp->u_volt, new_opp->available); + + return opp->available && new_opp->u_volt == opp->u_volt ? + 0 : -EEXIST; + } + + new_opp->dev_opp = dev_opp; + list_add_rcu(&new_opp->node, head); + + return 0; +} + /** * _opp_add_dynamic() - Allocate a dynamic OPP. * @dev: device for which we do this operation @@ -581,62 +641,28 @@ static int _opp_add_dynamic(struct device *dev, unsigned long freq, long u_volt, bool dynamic) { struct device_opp *dev_opp; - struct dev_pm_opp *opp, *new_opp; - struct list_head *head; + struct dev_pm_opp *new_opp; int ret; - /* allocate new OPP node */ - new_opp = kzalloc(sizeof(*new_opp), GFP_KERNEL); - if (!new_opp) - return -ENOMEM; - /* Hold our list modification lock here */ mutex_lock(&dev_opp_list_lock); + new_opp = _allocate_opp(dev, &dev_opp); + if (!new_opp) { + ret = -ENOMEM; + goto unlock; + } + /* populate the opp table */ new_opp->rate = freq; new_opp->u_volt = u_volt; new_opp->available = true; + new_opp->dynamic = dynamic; - dev_opp = _add_device_opp(dev); - if (!dev_opp) { - ret = -ENOMEM; - goto free_opp; - } - - /* - * Insert new OPP in order of increasing frequency - * and discard if already present - */ - head = &dev_opp->opp_list; - - /* - * Need to use &dev_opp->opp_list in the condition part of the 'for' - * loop, don't replace it with head otherwise it will become an infinite - * loop. - */ - list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) { - if (new_opp->rate > opp->rate) { - head = &opp->node; - continue; - } - - if (new_opp->rate < opp->rate) - break; - - /* Duplicate OPPs */ - ret = opp->available && new_opp->u_volt == opp->u_volt ? - 0 : -EEXIST; - - dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n", - __func__, opp->rate, opp->u_volt, opp->available, - new_opp->rate, new_opp->u_volt, new_opp->available); + ret = _opp_add(new_opp, dev_opp); + if (ret) goto free_opp; - } - new_opp->dynamic = dynamic; - new_opp->dev_opp = dev_opp; - list_add_rcu(&new_opp->node, head); mutex_unlock(&dev_opp_list_lock); /* @@ -647,8 +673,9 @@ static int _opp_add_dynamic(struct device *dev, unsigned long freq, return 0; free_opp: + _opp_remove(dev_opp, new_opp, false); +unlock: mutex_unlock(&dev_opp_list_lock); - kfree(new_opp); return ret; } @@ -876,7 +903,7 @@ void of_free_opp_table(struct device *dev) /* Free static OPPs */ list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) { if (!opp->dynamic) - _opp_remove(dev_opp, opp); + _opp_remove(dev_opp, opp, true); } mutex_unlock(&dev_opp_list_lock); -- cgit v1.3-6-gb490 From 274659029c9de5b11678d3a52a45e3dbc9177a48 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 29 Jul 2015 16:23:02 +0530 Subject: PM / OPP: Add support to parse "operating-points-v2" bindings This adds support in OPP library to parse and create list of OPPs from operating-points-v2 bindings. It takes care of most of the properties of new bindings (except shared-opp, which will be handled separately). For backward compatibility, we keep supporting earlier bindings. We try to search for the new bindings first, in case they aren't present we look for the old deprecated ones. There are few things marked as TODO: - Support for multiple OPP tables - Support for multiple regulators They should be fixed separately. Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Reviewed-by: Stephen Boyd Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 257 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 233 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 0d8dbf21c299..0e0eff4d9299 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -51,10 +51,15 @@ * order. * @dynamic: not-created from static DT entries. * @available: true/false - marks if this OPP as available or not + * @turbo: true if turbo (boost) OPP * @rate: Frequency in hertz - * @u_volt: Nominal voltage in microvolts corresponding to this OPP + * @u_volt: Target voltage in microvolts corresponding to this OPP + * @u_volt_min: Minimum voltage in microvolts corresponding to this OPP + * @u_volt_max: Maximum voltage in microvolts corresponding to this OPP + * @u_amp: Maximum current drawn by the device in microamperes * @dev_opp: points back to the device_opp struct this opp belongs to * @rcu_head: RCU callback head used for deferred freeing + * @np: OPP's device node. * * This structure stores the OPP information for a given device. */ @@ -63,11 +68,18 @@ struct dev_pm_opp { bool available; bool dynamic; + bool turbo; unsigned long rate; + unsigned long u_volt; + unsigned long u_volt_min; + unsigned long u_volt_max; + unsigned long u_amp; struct device_opp *dev_opp; struct rcu_head rcu_head; + + struct device_node *np; }; /** @@ -679,6 +691,125 @@ unlock: return ret; } +/* TODO: Support multiple regulators */ +static int opp_get_microvolt(struct dev_pm_opp *opp, struct device *dev) +{ + u32 microvolt[3] = {0}; + int count, ret; + + count = of_property_count_u32_elems(opp->np, "opp-microvolt"); + if (!count) + return 0; + + /* There can be one or three elements here */ + if (count != 1 && count != 3) { + dev_err(dev, "%s: Invalid number of elements in opp-microvolt property (%d)\n", + __func__, count); + return -EINVAL; + } + + ret = of_property_read_u32_array(opp->np, "opp-microvolt", microvolt, + count); + if (ret) { + dev_err(dev, "%s: error parsing opp-microvolt: %d\n", __func__, + ret); + return -EINVAL; + } + + opp->u_volt = microvolt[0]; + opp->u_volt_min = microvolt[1]; + opp->u_volt_max = microvolt[2]; + + return 0; +} + +/** + * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings) + * @dev: device for which we do this operation + * @np: device node + * + * This function adds an opp definition to the opp list and returns status. The + * opp can be controlled using dev_pm_opp_enable/disable functions and may be + * removed by dev_pm_opp_remove. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + * + * Return: + * 0 On success OR + * Duplicate OPPs (both freq and volt are same) and opp->available + * -EEXIST Freq are same and volt are different OR + * Duplicate OPPs (both freq and volt are same) and !opp->available + * -ENOMEM Memory allocation failure + * -EINVAL Failed parsing the OPP node + */ +static int _opp_add_static_v2(struct device *dev, struct device_node *np) +{ + struct device_opp *dev_opp; + struct dev_pm_opp *new_opp; + u64 rate; + int ret; + + /* Hold our list modification lock here */ + mutex_lock(&dev_opp_list_lock); + + new_opp = _allocate_opp(dev, &dev_opp); + if (!new_opp) { + ret = -ENOMEM; + goto unlock; + } + + ret = of_property_read_u64(np, "opp-hz", &rate); + if (ret < 0) { + dev_err(dev, "%s: opp-hz not found\n", __func__); + goto free_opp; + } + + /* + * Rate is defined as an unsigned long in clk API, and so casting + * explicitly to its type. Must be fixed once rate is 64 bit + * guaranteed in clk API. + */ + new_opp->rate = (unsigned long)rate; + new_opp->turbo = of_property_read_bool(np, "turbo-mode"); + + new_opp->np = np; + new_opp->dynamic = false; + new_opp->available = true; + + ret = opp_get_microvolt(new_opp, dev); + if (ret) + goto free_opp; + + of_property_read_u32(np, "opp-microamp", (u32 *)&new_opp->u_amp); + + ret = _opp_add(new_opp, dev_opp); + if (ret) + goto free_opp; + + mutex_unlock(&dev_opp_list_lock); + + pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu\n", + __func__, new_opp->turbo, new_opp->rate, new_opp->u_volt, + new_opp->u_volt_min, new_opp->u_volt_max); + + /* + * Notify the changes in the availability of the operable + * frequency/voltage list. + */ + srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ADD, new_opp); + return 0; + +free_opp: + _opp_remove(dev_opp, new_opp, false); +unlock: + mutex_unlock(&dev_opp_list_lock); + return ret; +} + /** * dev_pm_opp_add() - Add an OPP table from a table definitions * @dev: device for which we do this operation @@ -910,29 +1041,64 @@ void of_free_opp_table(struct device *dev) } EXPORT_SYMBOL_GPL(of_free_opp_table); -/** - * of_init_opp_table() - Initialize opp table from device tree - * @dev: device pointer used to lookup device OPPs. - * - * Register the initial OPP table with the OPP library for given device. - * - * Locking: The internal device_opp and opp structures are RCU protected. - * Hence this function indirectly uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. - * - * Return: - * 0 On success OR - * Duplicate OPPs (both freq and volt are same) and opp->available - * -EEXIST Freq are same and volt are different OR - * Duplicate OPPs (both freq and volt are same) and !opp->available - * -ENOMEM Memory allocation failure - * -ENODEV when 'operating-points' property is not found or is invalid data - * in device node. - * -ENODATA when empty 'operating-points' property is found - */ -int of_init_opp_table(struct device *dev) +/* Returns opp descriptor node from its phandle. Caller must do of_node_put() */ +static struct device_node * +_of_get_opp_desc_node_from_prop(struct device *dev, const struct property *prop) +{ + struct device_node *opp_np; + + opp_np = of_find_node_by_phandle(be32_to_cpup(prop->value)); + if (!opp_np) { + dev_err(dev, "%s: Prop: %s contains invalid opp desc phandle\n", + __func__, prop->name); + return ERR_PTR(-EINVAL); + } + + return opp_np; +} + +/* Initializes OPP tables based on new bindings */ +static int _of_init_opp_table_v2(struct device *dev, + const struct property *prop) +{ + struct device_node *opp_np, *np; + int ret = 0, count = 0; + + if (!prop->value) + return -ENODATA; + + /* Get opp node */ + opp_np = _of_get_opp_desc_node_from_prop(dev, prop); + if (IS_ERR(opp_np)) + return PTR_ERR(opp_np); + + /* We have opp-list node now, iterate over it and add OPPs */ + for_each_available_child_of_node(opp_np, np) { + count++; + + ret = _opp_add_static_v2(dev, np); + if (ret) { + dev_err(dev, "%s: Failed to add OPP, %d\n", __func__, + ret); + break; + } + } + + /* There should be one of more OPP defined */ + if (WARN_ON(!count)) + goto put_opp_np; + + if (ret) + of_free_opp_table(dev); + +put_opp_np: + of_node_put(opp_np); + + return ret; +} + +/* Initializes OPP tables based on old-deprecated bindings */ +static int _of_init_opp_table_v1(struct device *dev) { const struct property *prop; const __be32 *val; @@ -967,5 +1133,48 @@ int of_init_opp_table(struct device *dev) return 0; } + +/** + * of_init_opp_table() - Initialize opp table from device tree + * @dev: device pointer used to lookup device OPPs. + * + * Register the initial OPP table with the OPP library for given device. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function indirectly uses RCU updater strategy with mutex locks + * to keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex cannot be locked. + * + * Return: + * 0 On success OR + * Duplicate OPPs (both freq and volt are same) and opp->available + * -EEXIST Freq are same and volt are different OR + * Duplicate OPPs (both freq and volt are same) and !opp->available + * -ENOMEM Memory allocation failure + * -ENODEV when 'operating-points' property is not found or is invalid data + * in device node. + * -ENODATA when empty 'operating-points' property is found + * -EINVAL when invalid entries are found in opp-v2 table + */ +int of_init_opp_table(struct device *dev) +{ + const struct property *prop; + + /* + * OPPs have two version of bindings now. The older one is deprecated, + * try for the new binding first. + */ + prop = of_find_property(dev->of_node, "operating-points-v2", NULL); + if (!prop) { + /* + * Try old-deprecated bindings for backward compatibility with + * older dtbs. + */ + return _of_init_opp_table_v1(dev); + } + + return _of_init_opp_table_v2(dev, prop); +} EXPORT_SYMBOL_GPL(of_init_opp_table); #endif -- cgit v1.3-6-gb490 From 3ca9bb33c627f22640cfca97fdf88eec0a120dfd Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 29 Jul 2015 16:23:03 +0530 Subject: PM / OPP: Add clock-latency-ns support With "operating-points-v2" bindings, clock-latency is defined per OPP. Users of this value expect a single value which defines the latency to switch to any clock rate. Find maximum clock-latency-ns from the OPP table to service requests from such users. Reviewed-by: Stephen Boyd Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 41 +++++++++++++++++++++++++++++++++++++++-- include/linux/pm_opp.h | 6 ++++++ 2 files changed, 45 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 0e0eff4d9299..8638204c457e 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -57,6 +57,8 @@ * @u_volt_min: Minimum voltage in microvolts corresponding to this OPP * @u_volt_max: Maximum voltage in microvolts corresponding to this OPP * @u_amp: Maximum current drawn by the device in microamperes + * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's + * frequency from any other OPP's frequency. * @dev_opp: points back to the device_opp struct this opp belongs to * @rcu_head: RCU callback head used for deferred freeing * @np: OPP's device node. @@ -75,6 +77,7 @@ struct dev_pm_opp { unsigned long u_volt_min; unsigned long u_volt_max; unsigned long u_amp; + unsigned long clock_latency_ns; struct device_opp *dev_opp; struct rcu_head rcu_head; @@ -109,6 +112,8 @@ struct device_opp { struct srcu_notifier_head srcu_head; struct rcu_head rcu_head; struct list_head opp_list; + + unsigned long clock_latency_ns_max; }; /* @@ -225,6 +230,32 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp) } EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq); +/** + * dev_pm_opp_get_max_clock_latency() - Get max clock latency in nanoseconds + * @dev: device for which we do this operation + * + * Return: This function returns the max clock latency in nanoseconds. + * + * Locking: This function takes rcu_read_lock(). + */ +unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev) +{ + struct device_opp *dev_opp; + unsigned long clock_latency_ns; + + rcu_read_lock(); + + dev_opp = _find_device_opp(dev); + if (IS_ERR(dev_opp)) + clock_latency_ns = 0; + else + clock_latency_ns = dev_opp->clock_latency_ns_max; + + rcu_read_unlock(); + return clock_latency_ns; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency); + /** * dev_pm_opp_get_opp_count() - Get number of opps available in the opp list * @dev: device for which we do this operation @@ -779,6 +810,8 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) new_opp->np = np; new_opp->dynamic = false; new_opp->available = true; + of_property_read_u32(np, "clock-latency-ns", + (u32 *)&new_opp->clock_latency_ns); ret = opp_get_microvolt(new_opp, dev); if (ret) @@ -790,11 +823,15 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) if (ret) goto free_opp; + if (new_opp->clock_latency_ns > dev_opp->clock_latency_ns_max) + dev_opp->clock_latency_ns_max = new_opp->clock_latency_ns; + mutex_unlock(&dev_opp_list_lock); - pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu\n", + pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n", __func__, new_opp->turbo, new_opp->rate, new_opp->u_volt, - new_opp->u_volt_min, new_opp->u_volt_max); + new_opp->u_volt_min, new_opp->u_volt_max, + new_opp->clock_latency_ns); /* * Notify the changes in the availability of the operable diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index cec2d4540914..20324b579adc 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -31,6 +31,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp); unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp); int dev_pm_opp_get_opp_count(struct device *dev); +unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev); struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, unsigned long freq, @@ -67,6 +68,11 @@ static inline int dev_pm_opp_get_opp_count(struct device *dev) return 0; } +static inline unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev) +{ + return 0; +} + static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, unsigned long freq, bool available) { -- cgit v1.3-6-gb490 From 064416586190cb058d4c76a4e26b1996f434b6ca Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 29 Jul 2015 16:23:04 +0530 Subject: PM / OPP: Add OPP sharing information to OPP library An opp can be shared by multiple devices, for example its very common for CPUs to share the OPPs, i.e. when they share clock/voltage rails. This patch adds support of shared OPPs to the OPP library. Instead of a single device, dev_opp will now contain a list of devices that use it. It also senses if the device (we are trying to initialize OPPs for) shares OPPs with a device added earlier and in that case we update the list of devices managed by OPPs instead of duplicating OPPs again. The same infrastructure will be used for the old OPP bindings, with later patches. Reviewed-by: Stephen Boyd Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 174 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 150 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 8638204c457e..5d699e3ec136 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -85,6 +85,21 @@ struct dev_pm_opp { struct device_node *np; }; +/** + * struct device_list_opp - devices managed by 'struct device_opp' + * @node: list node + * @dev: device to which the struct object belongs + * @rcu_head: RCU callback head used for deferred freeing + * + * This is an internal data structure maintaining the list of devices that are + * managed by 'struct device_opp'. + */ +struct device_list_opp { + struct list_head node; + const struct device *dev; + struct rcu_head rcu_head; +}; + /** * struct device_opp - Device opp structure * @node: list node - contains the devices with OPPs that @@ -92,10 +107,12 @@ struct dev_pm_opp { * list. * RCU usage: nodes are not modified in the list of device_opp, * however addition is possible and is secured by dev_opp_list_lock - * @dev: device pointer * @srcu_head: notifier head to notify the OPP availability changes. * @rcu_head: RCU callback head used for deferred freeing + * @dev_list: list of devices that share these OPPs * @opp_list: list of opps + * @np: struct device_node pointer for opp's DT node. + * @shared_opp: OPP is shared between multiple devices. * * This is an internal data structure maintaining the link to opps attached to * a device. This structure is not meant to be shared to users as it is @@ -108,12 +125,14 @@ struct dev_pm_opp { struct device_opp { struct list_head node; - struct device *dev; struct srcu_notifier_head srcu_head; struct rcu_head rcu_head; + struct list_head dev_list; struct list_head opp_list; + struct device_node *np; unsigned long clock_latency_ns_max; + bool shared_opp; }; /* @@ -133,6 +152,38 @@ do { \ "dev_opp_list_lock protection"); \ } while (0) +static struct device_list_opp *_find_list_dev(const struct device *dev, + struct device_opp *dev_opp) +{ + struct device_list_opp *list_dev; + + list_for_each_entry(list_dev, &dev_opp->dev_list, node) + if (list_dev->dev == dev) + return list_dev; + + return NULL; +} + +static struct device_opp *_managed_opp(const struct device_node *np) +{ + struct device_opp *dev_opp; + + list_for_each_entry_rcu(dev_opp, &dev_opp_list, node) { + if (dev_opp->np == np) { + /* + * Multiple devices can point to the same OPP table and + * so will have same node-pointer, np. + * + * But the OPPs will be considered as shared only if the + * OPP table contains a "opp-shared" property. + */ + return dev_opp->shared_opp ? dev_opp : NULL; + } + } + + return NULL; +} + /** * _find_device_opp() - find device_opp struct using device pointer * @dev: device pointer used to lookup device OPPs @@ -149,21 +200,18 @@ do { \ */ static struct device_opp *_find_device_opp(struct device *dev) { - struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV); + struct device_opp *dev_opp; if (unlikely(IS_ERR_OR_NULL(dev))) { pr_err("%s: Invalid parameters\n", __func__); return ERR_PTR(-EINVAL); } - list_for_each_entry_rcu(tmp_dev_opp, &dev_opp_list, node) { - if (tmp_dev_opp->dev == dev) { - dev_opp = tmp_dev_opp; - break; - } - } + list_for_each_entry_rcu(dev_opp, &dev_opp_list, node) + if (_find_list_dev(dev, dev_opp)) + return dev_opp; - return dev_opp; + return ERR_PTR(-ENODEV); } /** @@ -450,6 +498,39 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, } EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); +/* List-dev Helpers */ +static void _kfree_list_dev_rcu(struct rcu_head *head) +{ + struct device_list_opp *list_dev; + + list_dev = container_of(head, struct device_list_opp, rcu_head); + kfree_rcu(list_dev, rcu_head); +} + +static void _remove_list_dev(struct device_list_opp *list_dev, + struct device_opp *dev_opp) +{ + list_del(&list_dev->node); + call_srcu(&dev_opp->srcu_head.srcu, &list_dev->rcu_head, + _kfree_list_dev_rcu); +} + +static struct device_list_opp *_add_list_dev(const struct device *dev, + struct device_opp *dev_opp) +{ + struct device_list_opp *list_dev; + + list_dev = kzalloc(sizeof(*list_dev), GFP_KERNEL); + if (!list_dev) + return NULL; + + /* Initialize list-dev */ + list_dev->dev = dev; + list_add_rcu(&list_dev->node, &dev_opp->dev_list); + + return list_dev; +} + /** * _add_device_opp() - Find device OPP table or allocate a new one * @dev: device for which we do this operation @@ -462,6 +543,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); static struct device_opp *_add_device_opp(struct device *dev) { struct device_opp *dev_opp; + struct device_list_opp *list_dev; /* Check for existing list for 'dev' first */ dev_opp = _find_device_opp(dev); @@ -476,7 +558,14 @@ static struct device_opp *_add_device_opp(struct device *dev) if (!dev_opp) return NULL; - dev_opp->dev = dev; + INIT_LIST_HEAD(&dev_opp->dev_list); + + list_dev = _add_list_dev(dev, dev_opp); + if (!list_dev) { + kfree(dev_opp); + return NULL; + } + srcu_init_notifier_head(&dev_opp->srcu_head); INIT_LIST_HEAD(&dev_opp->opp_list); @@ -504,9 +593,19 @@ static void _kfree_device_rcu(struct rcu_head *head) */ static void _remove_device_opp(struct device_opp *dev_opp) { + struct device_list_opp *list_dev; + if (!list_empty(&dev_opp->opp_list)) return; + list_dev = list_first_entry(&dev_opp->dev_list, struct device_list_opp, + node); + + _remove_list_dev(list_dev, dev_opp); + + /* dev_list must be empty now */ + WARN_ON(!list_empty(&dev_opp->dev_list)); + list_del_rcu(&dev_opp->node); call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head, _kfree_device_rcu); @@ -616,7 +715,8 @@ static struct dev_pm_opp *_allocate_opp(struct device *dev, return opp; } -static int _opp_add(struct dev_pm_opp *new_opp, struct device_opp *dev_opp) +static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, + struct device_opp *dev_opp) { struct dev_pm_opp *opp; struct list_head *head = &dev_opp->opp_list; @@ -639,7 +739,7 @@ static int _opp_add(struct dev_pm_opp *new_opp, struct device_opp *dev_opp) break; /* Duplicate OPPs */ - dev_warn(dev_opp->dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n", + dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n", __func__, opp->rate, opp->u_volt, opp->available, new_opp->rate, new_opp->u_volt, new_opp->available); @@ -702,7 +802,7 @@ static int _opp_add_dynamic(struct device *dev, unsigned long freq, new_opp->available = true; new_opp->dynamic = dynamic; - ret = _opp_add(new_opp, dev_opp); + ret = _opp_add(dev, new_opp, dev_opp); if (ret) goto free_opp; @@ -819,7 +919,7 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) of_property_read_u32(np, "opp-microamp", (u32 *)&new_opp->u_amp); - ret = _opp_add(new_opp, dev_opp); + ret = _opp_add(dev, new_opp, dev_opp); if (ret) goto free_opp; @@ -1052,6 +1152,9 @@ void of_free_opp_table(struct device *dev) struct device_opp *dev_opp; struct dev_pm_opp *opp, *tmp; + /* Hold our list modification lock here */ + mutex_lock(&dev_opp_list_lock); + /* Check for existing list for 'dev' */ dev_opp = _find_device_opp(dev); if (IS_ERR(dev_opp)) { @@ -1062,18 +1165,21 @@ void of_free_opp_table(struct device *dev) IS_ERR_OR_NULL(dev) ? "Invalid device" : dev_name(dev), error); - return; + goto unlock; } - /* Hold our list modification lock here */ - mutex_lock(&dev_opp_list_lock); - - /* Free static OPPs */ - list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) { - if (!opp->dynamic) - _opp_remove(dev_opp, opp, true); + /* Find if dev_opp manages a single device */ + if (list_is_singular(&dev_opp->dev_list)) { + /* Free static OPPs */ + list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) { + if (!opp->dynamic) + _opp_remove(dev_opp, opp, true); + } + } else { + _remove_list_dev(_find_list_dev(dev, dev_opp), dev_opp); } +unlock: mutex_unlock(&dev_opp_list_lock); } EXPORT_SYMBOL_GPL(of_free_opp_table); @@ -1099,6 +1205,7 @@ static int _of_init_opp_table_v2(struct device *dev, const struct property *prop) { struct device_node *opp_np, *np; + struct device_opp *dev_opp; int ret = 0, count = 0; if (!prop->value) @@ -1109,6 +1216,14 @@ static int _of_init_opp_table_v2(struct device *dev, if (IS_ERR(opp_np)) return PTR_ERR(opp_np); + dev_opp = _managed_opp(opp_np); + if (dev_opp) { + /* OPPs are already managed */ + if (!_add_list_dev(dev, dev_opp)) + ret = -ENOMEM; + goto put_opp_np; + } + /* We have opp-list node now, iterate over it and add OPPs */ for_each_available_child_of_node(opp_np, np) { count++; @@ -1125,8 +1240,19 @@ static int _of_init_opp_table_v2(struct device *dev, if (WARN_ON(!count)) goto put_opp_np; - if (ret) + if (!ret) { + if (!dev_opp) { + dev_opp = _find_device_opp(dev); + if (WARN_ON(!dev_opp)) + goto put_opp_np; + } + + dev_opp->np = opp_np; + dev_opp->shared_opp = of_property_read_bool(opp_np, + "opp-shared"); + } else { of_free_opp_table(dev); + } put_opp_np: of_node_put(opp_np); -- cgit v1.3-6-gb490 From ad656a6a8b1c8b4b2e723646e0402867f2f45395 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 13 Jun 2015 15:10:21 +0530 Subject: PM / OPP: Add support for opp-suspend With "operating-points-v2" bindings, it's possible to specify the OPP to which the device must be switched, before suspending. This patch adds support for getting that information. Reviewed-by: Stephen Boyd Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 5d699e3ec136..0ebcea49145a 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -133,6 +133,7 @@ struct device_opp { struct device_node *np; unsigned long clock_latency_ns_max; bool shared_opp; + struct dev_pm_opp *suspend_opp; }; /* @@ -923,6 +924,16 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) if (ret) goto free_opp; + /* OPP to select on device suspend */ + if (of_property_read_bool(np, "opp-suspend")) { + if (dev_opp->suspend_opp) + dev_warn(dev, "%s: Multiple suspend OPPs found (%lu %lu)\n", + __func__, dev_opp->suspend_opp->rate, + new_opp->rate); + else + dev_opp->suspend_opp = new_opp; + } + if (new_opp->clock_latency_ns > dev_opp->clock_latency_ns_max) dev_opp->clock_latency_ns_max = new_opp->clock_latency_ns; -- cgit v1.3-6-gb490 From 8d4d4e98acd68c31435ebb7beea591dbf60b9eb2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 12 Jun 2015 17:10:38 +0530 Subject: PM / OPP: Add helpers for initializing CPU OPPs With "operating-points-v2" its possible to tell which devices share OPPs. We already have infrastructure to decode that information. This patch adds following APIs: - of_get_cpus_sharing_opps: Returns cpumask of CPUs sharing OPPs (only valid with v2 bindings). - of_cpumask_init_opp_table: Initializes OPPs for all CPUs present in cpumask. - of_cpumask_free_opp_table: Frees OPPs for all CPUs present in cpumask. - set_cpus_sharing_opps: Sets which CPUs share OPPs (only valid with old OPP bindings, as this information isn't present in DT). Reviewed-by: Stephen Boyd Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_opp.h | 23 +++++++ 2 files changed, 198 insertions(+) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 0ebcea49145a..663aae1c9834 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -11,6 +11,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -1195,6 +1196,26 @@ unlock: } EXPORT_SYMBOL_GPL(of_free_opp_table); +void of_cpumask_free_opp_table(cpumask_var_t cpumask) +{ + struct device *cpu_dev; + int cpu; + + WARN_ON(cpumask_empty(cpumask)); + + for_each_cpu(cpu, cpumask) { + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + pr_err("%s: failed to get cpu%d device\n", __func__, + cpu); + continue; + } + + of_free_opp_table(cpu_dev); + } +} +EXPORT_SYMBOL_GPL(of_cpumask_free_opp_table); + /* Returns opp descriptor node from its phandle. Caller must do of_node_put() */ static struct device_node * _of_get_opp_desc_node_from_prop(struct device *dev, const struct property *prop) @@ -1211,6 +1232,31 @@ _of_get_opp_desc_node_from_prop(struct device *dev, const struct property *prop) return opp_np; } +/* Returns opp descriptor node for a device. Caller must do of_node_put() */ +static struct device_node *_of_get_opp_desc_node(struct device *dev) +{ + const struct property *prop; + + prop = of_find_property(dev->of_node, "operating-points-v2", NULL); + if (!prop) + return ERR_PTR(-ENODEV); + if (!prop->value) + return ERR_PTR(-ENODATA); + + /* + * TODO: Support for multiple OPP tables. + * + * There should be only ONE phandle present in "operating-points-v2" + * property. + */ + if (prop->length != sizeof(__be32)) { + dev_err(dev, "%s: Invalid opp desc phandle\n", __func__); + return ERR_PTR(-EINVAL); + } + + return _of_get_opp_desc_node_from_prop(dev, prop); +} + /* Initializes OPP tables based on new bindings */ static int _of_init_opp_table_v2(struct device *dev, const struct property *prop) @@ -1351,4 +1397,133 @@ int of_init_opp_table(struct device *dev) return _of_init_opp_table_v2(dev, prop); } EXPORT_SYMBOL_GPL(of_init_opp_table); + +int of_cpumask_init_opp_table(cpumask_var_t cpumask) +{ + struct device *cpu_dev; + int cpu, ret = 0; + + WARN_ON(cpumask_empty(cpumask)); + + for_each_cpu(cpu, cpumask) { + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + pr_err("%s: failed to get cpu%d device\n", __func__, + cpu); + continue; + } + + ret = of_init_opp_table(cpu_dev); + if (ret) { + pr_err("%s: couldn't find opp table for cpu:%d, %d\n", + __func__, cpu, ret); + + /* Free all other OPPs */ + of_cpumask_free_opp_table(cpumask); + break; + } + } + + return ret; +} +EXPORT_SYMBOL_GPL(of_cpumask_init_opp_table); + +/* Required only for V1 bindings, as v2 can manage it from DT itself */ +int set_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask) +{ + struct device_list_opp *list_dev; + struct device_opp *dev_opp; + struct device *dev; + int cpu, ret = 0; + + rcu_read_lock(); + + dev_opp = _find_device_opp(cpu_dev); + if (IS_ERR(dev_opp)) { + ret = -EINVAL; + goto out_rcu_read_unlock; + } + + for_each_cpu(cpu, cpumask) { + if (cpu == cpu_dev->id) + continue; + + dev = get_cpu_device(cpu); + if (!dev) { + dev_err(cpu_dev, "%s: failed to get cpu%d device\n", + __func__, cpu); + continue; + } + + list_dev = _add_list_dev(dev, dev_opp); + if (!list_dev) { + dev_err(dev, "%s: failed to add list-dev for cpu%d device\n", + __func__, cpu); + continue; + } + } +out_rcu_read_unlock: + rcu_read_unlock(); + + return 0; +} +EXPORT_SYMBOL_GPL(set_cpus_sharing_opps); + +/* + * Works only for OPP v2 bindings. + * + * cpumask should be already set to mask of cpu_dev->id. + * Returns -ENOENT if operating-points-v2 bindings aren't supported. + */ +int of_get_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask) +{ + struct device_node *np, *tmp_np; + struct device *tcpu_dev; + int cpu, ret = 0; + + /* Get OPP descriptor node */ + np = _of_get_opp_desc_node(cpu_dev); + if (IS_ERR(np)) { + dev_dbg(cpu_dev, "%s: Couldn't find opp node: %ld\n", __func__, + PTR_ERR(np)); + return -ENOENT; + } + + /* OPPs are shared ? */ + if (!of_property_read_bool(np, "opp-shared")) + goto put_cpu_node; + + for_each_possible_cpu(cpu) { + if (cpu == cpu_dev->id) + continue; + + tcpu_dev = get_cpu_device(cpu); + if (!tcpu_dev) { + dev_err(cpu_dev, "%s: failed to get cpu%d device\n", + __func__, cpu); + ret = -ENODEV; + goto put_cpu_node; + } + + /* Get OPP descriptor node */ + tmp_np = _of_get_opp_desc_node(tcpu_dev); + if (IS_ERR(tmp_np)) { + dev_err(tcpu_dev, "%s: Couldn't find opp node: %ld\n", + __func__, PTR_ERR(tmp_np)); + ret = PTR_ERR(tmp_np); + goto put_cpu_node; + } + + /* CPUs are sharing opp node */ + if (np == tmp_np) + cpumask_set_cpu(cpu, cpumask); + + of_node_put(tmp_np); + } + +put_cpu_node: + of_node_put(np); + return ret; +} +EXPORT_SYMBOL_GPL(of_get_cpus_sharing_opps); #endif diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 20324b579adc..bb52fae5b921 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -121,6 +121,10 @@ static inline struct srcu_notifier_head *dev_pm_opp_get_notifier( #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) int of_init_opp_table(struct device *dev); void of_free_opp_table(struct device *dev); +int of_cpumask_init_opp_table(cpumask_var_t cpumask); +void of_cpumask_free_opp_table(cpumask_var_t cpumask); +int of_get_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask); +int set_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask); #else static inline int of_init_opp_table(struct device *dev) { @@ -130,6 +134,25 @@ static inline int of_init_opp_table(struct device *dev) static inline void of_free_opp_table(struct device *dev) { } + +static inline int of_cpumask_init_opp_table(cpumask_var_t cpumask) +{ + return -ENOSYS; +} + +static inline void of_cpumask_free_opp_table(cpumask_var_t cpumask) +{ +} + +static inline int of_get_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask) +{ + return -ENOSYS; +} + +static inline int set_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask) +{ + return -ENOSYS; +} #endif #endif /* __LINUX_OPP_H__ */ -- cgit v1.3-6-gb490 From 19445b25e350ebebaa304bb2135619f643302947 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Thu, 9 Jul 2015 17:43:35 +0200 Subject: PM / OPP: add dev_pm_opp_is_turbo() helper Add dev_pm_opp_is_turbo() helper to verify if an opp is to be used only for turbo mode or not. Reviewed-by: Stephen Boyd Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 34 ++++++++++++++++++++++++++++++++++ include/linux/pm_opp.h | 7 +++++++ 2 files changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 663aae1c9834..204c6c945168 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -280,6 +280,40 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp) } EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq); +/** + * dev_pm_opp_is_turbo() - Returns if opp is turbo OPP or not + * @opp: opp for which turbo mode is being verified + * + * Turbo OPPs are not for normal use, and can be enabled (under certain + * conditions) for short duration of times to finish high throughput work + * quickly. Running on them for longer times may overheat the chip. + * + * Return: true if opp is turbo opp, else false. + * + * Locking: This function must be called under rcu_read_lock(). opp is a rcu + * protected pointer. This means that opp which could have been fetched by + * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are + * under RCU lock. The pointer returned by the opp_find_freq family must be + * used in the same section as the usage of this function with the pointer + * prior to unlocking with rcu_read_unlock() to maintain the integrity of the + * pointer. + */ +bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp) +{ + struct dev_pm_opp *tmp_opp; + + opp_rcu_lockdep_assert(); + + tmp_opp = rcu_dereference(opp); + if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available) { + pr_err("%s: Invalid parameters\n", __func__); + return false; + } + + return tmp_opp->turbo; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_is_turbo); + /** * dev_pm_opp_get_max_clock_latency() - Get max clock latency in nanoseconds * @dev: device for which we do this operation diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index bb52fae5b921..cab7ba55bedb 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -30,6 +30,8 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp); unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp); +bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp); + int dev_pm_opp_get_opp_count(struct device *dev); unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev); @@ -63,6 +65,11 @@ static inline unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp) return 0; } +static inline bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp) +{ + return false; +} + static inline int dev_pm_opp_get_opp_count(struct device *dev) { return 0; -- cgit v1.3-6-gb490 From 79eea44a5d7b9170d12d75c701d8c0e2d8d83c06 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 29 Jul 2015 16:23:08 +0530 Subject: cpufreq: Update boost flag while initializing freq table from OPPs cpufreq table entries for OPPs with turbo modes enabled, should be marked with CPUFREQ_BOOST_FREQ flag. This ensures that these states are only used while operating in boost or turbo mode. Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Reviewed-by: Stephen Boyd Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_opp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq_opp.c b/drivers/cpufreq/cpufreq_opp.c index 773bcde893c0..0f5e6d5f6da0 100644 --- a/drivers/cpufreq/cpufreq_opp.c +++ b/drivers/cpufreq/cpufreq_opp.c @@ -75,6 +75,10 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev, } freq_table[i].driver_data = i; freq_table[i].frequency = rate / 1000; + + /* Is Boost/turbo opp ? */ + if (dev_pm_opp_is_turbo(opp)) + freq_table[i].flags = CPUFREQ_BOOST_FREQ; } freq_table[i].driver_data = i; -- cgit v1.3-6-gb490 From 44139ed4943ee8ec186eea3e9072ca16d2b48133 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 29 Jul 2015 16:23:09 +0530 Subject: cpufreq: Allow drivers to enable boost support after registering driver In some cases it wouldn't be known at time of driver registration, if the driver needs to support boost frequencies. For example, while getting boost information from DT with opp-v2 bindings, we need to parse the bindings for all the CPUs to know if turbo/boost OPPs are supported or not. One way out to do that efficiently is to delay supporting boost mode (i.e. creating /sys/devices/system/cpu/cpufreq/boost file), until the time OPP bindings are parsed. At that point, the driver can enable boost support. This can be done at ->init(), where the frequency table is created. To do that, the driver requires few APIs from cpufreq core that let him do this. This patch provides these APIs. Signed-off-by: Viresh Kumar Reviewed-by: Stephen Boyd Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 68 +++++++++++++++++++++++++++++++------------- drivers/cpufreq/freq_table.c | 15 ++++++++++ include/linux/cpufreq.h | 12 ++++++++ 3 files changed, 75 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 76a26609d96b..e48242119d77 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2437,6 +2437,49 @@ int cpufreq_boost_supported(void) } EXPORT_SYMBOL_GPL(cpufreq_boost_supported); +static int create_boost_sysfs_file(void) +{ + int ret; + + if (!cpufreq_boost_supported()) + return 0; + + /* + * Check if driver provides function to enable boost - + * if not, use cpufreq_boost_set_sw as default + */ + if (!cpufreq_driver->set_boost) + cpufreq_driver->set_boost = cpufreq_boost_set_sw; + + ret = cpufreq_sysfs_create_file(&boost.attr); + if (ret) + pr_err("%s: cannot register global BOOST sysfs file\n", + __func__); + + return ret; +} + +static void remove_boost_sysfs_file(void) +{ + if (cpufreq_boost_supported()) + cpufreq_sysfs_remove_file(&boost.attr); +} + +int cpufreq_enable_boost_support(void) +{ + if (!cpufreq_driver) + return -EINVAL; + + if (cpufreq_boost_supported()) + return 0; + + cpufreq_driver->boost_supported = true; + + /* This will get removed on driver unregister */ + return create_boost_sysfs_file(); +} +EXPORT_SYMBOL_GPL(cpufreq_enable_boost_support); + int cpufreq_boost_enabled(void) { return cpufreq_driver->boost_enabled; @@ -2490,21 +2533,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) if (driver_data->setpolicy) driver_data->flags |= CPUFREQ_CONST_LOOPS; - if (cpufreq_boost_supported()) { - /* - * Check if driver provides function to enable boost - - * if not, use cpufreq_boost_set_sw as default - */ - if (!cpufreq_driver->set_boost) - cpufreq_driver->set_boost = cpufreq_boost_set_sw; - - ret = cpufreq_sysfs_create_file(&boost.attr); - if (ret) { - pr_err("%s: cannot register global BOOST sysfs file\n", - __func__); - goto err_null_driver; - } - } + ret = create_boost_sysfs_file(); + if (ret) + goto err_null_driver; ret = subsys_interface_register(&cpufreq_interface); if (ret) @@ -2528,8 +2559,7 @@ out: err_if_unreg: subsys_interface_unregister(&cpufreq_interface); err_boost_unreg: - if (cpufreq_boost_supported()) - cpufreq_sysfs_remove_file(&boost.attr); + remove_boost_sysfs_file(); err_null_driver: write_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_driver = NULL; @@ -2558,9 +2588,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) /* Protect against concurrent cpu hotplug */ get_online_cpus(); subsys_interface_unregister(&cpufreq_interface); - if (cpufreq_boost_supported()) - cpufreq_sysfs_remove_file(&boost.attr); - + remove_boost_sysfs_file(); unregister_hotcpu_notifier(&cpufreq_cpu_notifier); write_lock_irqsave(&cpufreq_driver_lock, flags); diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index dfbbf981ed56..a8f1daffc9bc 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -18,6 +18,21 @@ * FREQUENCY TABLE HELPERS * *********************************************************************/ +bool policy_has_boost_freq(struct cpufreq_policy *policy) +{ + struct cpufreq_frequency_table *pos, *table = policy->freq_table; + + if (!table) + return false; + + cpufreq_for_each_valid_entry(pos, table) + if (pos->flags & CPUFREQ_BOOST_FREQ) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(policy_has_boost_freq); + int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index bde1e567b3a9..95f018649abf 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -578,6 +578,8 @@ ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf); int cpufreq_boost_trigger_state(int state); int cpufreq_boost_supported(void); int cpufreq_boost_enabled(void); +int cpufreq_enable_boost_support(void); +bool policy_has_boost_freq(struct cpufreq_policy *policy); #else static inline int cpufreq_boost_trigger_state(int state) { @@ -591,6 +593,16 @@ static inline int cpufreq_boost_enabled(void) { return 0; } + +static inline int cpufreq_enable_boost_support(void) +{ + return -EINVAL; +} + +static inline bool policy_has_boost_freq(struct cpufreq_policy *policy) +{ + return false; +} #endif /* the following funtion is for cpufreq core use only */ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu); -- cgit v1.3-6-gb490 From 2e02d8723edf6599988852a8ade8f83b2f766cb8 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 29 Jul 2015 16:23:10 +0530 Subject: cpufreq: dt: Add support for operating-points-v2 bindings Support for parsing operating-points-v2 bindings is in place now, lets modify cpufreq-dt driver to use them. For backward compatibility we will continue to support earlier bindings. Special handling for that is required, to make sure OPPs are initialized for all the CPUs. Reviewed-by: Bartlomiej Zolnierkiewicz Signed-off-by: Viresh Kumar Reviewed-by: Stephen Boyd Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-dt.c | 56 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 528a82bf5038..c6e7033076de 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -184,7 +184,6 @@ try_again: static int cpufreq_init(struct cpufreq_policy *policy) { - struct cpufreq_dt_platform_data *pd; struct cpufreq_frequency_table *freq_table; struct device_node *np; struct private_data *priv; @@ -193,6 +192,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) struct clk *cpu_clk; unsigned long min_uV = ~0, max_uV = 0; unsigned int transition_latency; + bool need_update = false; int ret; ret = allocate_resources(policy->cpu, &cpu_dev, &cpu_reg, &cpu_clk); @@ -208,8 +208,47 @@ static int cpufreq_init(struct cpufreq_policy *policy) goto out_put_reg_clk; } - /* OPPs might be populated at runtime, don't check for error here */ - of_init_opp_table(cpu_dev); + /* Get OPP-sharing information from "operating-points-v2" bindings */ + ret = of_get_cpus_sharing_opps(cpu_dev, policy->cpus); + if (ret) { + /* + * operating-points-v2 not supported, fallback to old method of + * finding shared-OPPs for backward compatibility. + */ + if (ret == -ENOENT) + need_update = true; + else + goto out_node_put; + } + + /* + * Initialize OPP tables for all policy->cpus. They will be shared by + * all CPUs which have marked their CPUs shared with OPP bindings. + * + * For platforms not using operating-points-v2 bindings, we do this + * before updating policy->cpus. Otherwise, we will end up creating + * duplicate OPPs for policy->cpus. + * + * OPPs might be populated at runtime, don't check for error here + */ + of_cpumask_init_opp_table(policy->cpus); + + if (need_update) { + struct cpufreq_dt_platform_data *pd = cpufreq_get_driver_data(); + + if (!pd || !pd->independent_clocks) + cpumask_setall(policy->cpus); + + /* + * OPP tables are initialized only for policy->cpu, do it for + * others as well. + */ + set_cpus_sharing_opps(cpu_dev, policy->cpus); + + of_property_read_u32(np, "clock-latency", &transition_latency); + } else { + transition_latency = dev_pm_opp_get_max_clock_latency(cpu_dev); + } /* * But we need OPP table to function so if it is not there let's @@ -230,7 +269,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance); - if (of_property_read_u32(np, "clock-latency", &transition_latency)) + if (!transition_latency) transition_latency = CPUFREQ_ETERNAL; if (!IS_ERR(cpu_reg)) { @@ -293,10 +332,6 @@ static int cpufreq_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = transition_latency; - pd = cpufreq_get_driver_data(); - if (!pd || !pd->independent_clocks) - cpumask_setall(policy->cpus); - of_node_put(np); return 0; @@ -306,7 +341,8 @@ out_free_cpufreq_table: out_free_priv: kfree(priv); out_free_opp: - of_free_opp_table(cpu_dev); + of_cpumask_free_opp_table(policy->cpus); +out_node_put: of_node_put(np); out_put_reg_clk: clk_put(cpu_clk); @@ -322,7 +358,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy) cpufreq_cooling_unregister(priv->cdev); dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); - of_free_opp_table(priv->cpu_dev); + of_cpumask_free_opp_table(policy->related_cpus); clk_put(policy->clk); if (!IS_ERR(priv->cpu_reg)) regulator_put(priv->cpu_reg); -- cgit v1.3-6-gb490 From d15fa86276e8515443251c0d18930e392bc5afc5 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 29 Jul 2015 16:23:11 +0530 Subject: cpufreq: dt: Add support for turbo/boost mode With opp-v2 DT bindings, few OPPs can be used only for the boost mode. But using such OPPs require the boost mode to be supported by cpufreq driver. We will parse DT bindings only during ->init() and so can enable boost support only after registering cpufreq driver. This enables boost support as soon as any policy has boost/turbo OPPs for its CPUs. We don't need to disable boost support as that is done by the core, when the driver is unregistered. Signed-off-by: Viresh Kumar Reviewed-by: Stephen Boyd Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-dt.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index c6e7033076de..b9259abd25d4 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -330,6 +330,14 @@ static int cpufreq_init(struct cpufreq_policy *policy) goto out_free_cpufreq_table; } + /* Support turbo/boost mode */ + if (policy_has_boost_freq(policy)) { + /* This gets disabled by core on driver unregister */ + ret = cpufreq_enable_boost_support(); + if (ret) + goto out_free_cpufreq_table; + } + policy->cpuinfo.transition_latency = transition_latency; of_node_put(np); -- cgit v1.3-6-gb490 From 1c9391238753ffb370f02743b5f43bac6dea304b Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 5 Aug 2015 12:47:14 -0700 Subject: intel_pstate: Add SKY-S support Whitelist the SKL-S processor Signed-off-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index b9354b6f7149..f05f0633b2a9 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -908,6 +908,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = { ICPU(0x4c, byt_params), ICPU(0x4e, core_params), ICPU(0x4f, core_params), + ICPU(0x5e, core_params), ICPU(0x56, core_params), ICPU(0x57, knl_params), {} -- cgit v1.3-6-gb490 From 5aecc3c8a24a7c2db29ec4a927bbb08befcb508e Mon Sep 17 00:00:00 2001 From: Ethan Zhao Date: Wed, 5 Aug 2015 09:28:50 +0900 Subject: intel_pstate: append more Oracle OEM table id to vendor bypass list Append more Oracle X86 servers that have their own power management, SUN FIRE X4275 M3 SUN FIRE X4170 M3 and SUN FIRE X6-2 Signed-off-by: Ethan Zhao Acked-by: Viresh Kumar Acked-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index f05f0633b2a9..31d0548638e8 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -1174,6 +1174,10 @@ static struct hw_vendor_info vendor_info[] = { {1, "ORACLE", "X4270M3 ", PPC}, {1, "ORACLE", "X4270M2 ", PPC}, {1, "ORACLE", "X4170M2 ", PPC}, + {1, "ORACLE", "X4170 M3", PPC}, + {1, "ORACLE", "X4275 M3", PPC}, + {1, "ORACLE", "X6-2 ", PPC}, + {1, "ORACLE", "Sudbury ", PPC}, {0, "", ""}, }; -- cgit v1.3-6-gb490 From 6c4f7780a5dd6773a653c87bf7ee61c6aea6a4e7 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Mon, 3 Aug 2015 22:31:17 -0700 Subject: rocker: NULL port if port probe fails Set port to NULL if port probe fails so we don't try to remove partially initialized port on port probe err cleanup path. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 4cd5a71ad45e..5309d1fd8eb3 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -5008,6 +5008,7 @@ err_untagged_vlan: rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, ROCKER_OP_FLAG_REMOVE); err_port_ig_tbl: + rocker->ports[port_number] = NULL; unregister_netdev(dev); err_register_netdev: free_netdev(dev); -- cgit v1.3-6-gb490 From ff1470284493ca18da852e36afe39d29d0feb875 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Mon, 3 Aug 2015 22:31:18 -0700 Subject: rocker: use netdev_err after register_netdev After successful register_netdev, we can use netdev_err rather the more generic dev_err. Signed-off-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 5309d1fd8eb3..b77e0e7307d4 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4988,7 +4988,7 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) err = rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, 0); if (err) { - dev_err(&pdev->dev, "install ig port table failed\n"); + netdev_err(rocker_port->dev, "install ig port table failed\n"); goto err_port_ig_tbl; } -- cgit v1.3-6-gb490 From eddb755428e6e723bf587a4e2c15055c8ac02f5b Mon Sep 17 00:00:00 2001 From: Tej Parkash Date: Tue, 4 Aug 2015 09:37:27 +0300 Subject: cnic: Populate upper layer driver state in MFW Signed-off-by: Tej Parkash Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/cnic.c | 18 +++++++++++++++--- drivers/net/ethernet/broadcom/cnic_if.h | 5 +++++ 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c index 17c145fdf3ff..d9e35678277b 100644 --- a/drivers/net/ethernet/broadcom/cnic.c +++ b/drivers/net/ethernet/broadcom/cnic.c @@ -192,6 +192,7 @@ static void cnic_ctx_wr(struct cnic_dev *dev, u32 cid_addr, u32 off, u32 val) struct drv_ctl_info info; struct drv_ctl_io *io = &info.data.io; + memset(&info, 0, sizeof(struct drv_ctl_info)); info.cmd = DRV_CTL_CTX_WR_CMD; io->cid_addr = cid_addr; io->offset = off; @@ -206,6 +207,7 @@ static void cnic_ctx_tbl_wr(struct cnic_dev *dev, u32 off, dma_addr_t addr) struct drv_ctl_info info; struct drv_ctl_io *io = &info.data.io; + memset(&info, 0, sizeof(struct drv_ctl_info)); info.cmd = DRV_CTL_CTXTBL_WR_CMD; io->offset = off; io->dma_addr = addr; @@ -219,6 +221,7 @@ static void cnic_ring_ctl(struct cnic_dev *dev, u32 cid, u32 cl_id, int start) struct drv_ctl_info info; struct drv_ctl_l2_ring *ring = &info.data.ring; + memset(&info, 0, sizeof(struct drv_ctl_info)); if (start) info.cmd = DRV_CTL_START_L2_CMD; else @@ -236,6 +239,7 @@ static void cnic_reg_wr_ind(struct cnic_dev *dev, u32 off, u32 val) struct drv_ctl_info info; struct drv_ctl_io *io = &info.data.io; + memset(&info, 0, sizeof(struct drv_ctl_info)); info.cmd = DRV_CTL_IO_WR_CMD; io->offset = off; io->data = val; @@ -249,13 +253,14 @@ static u32 cnic_reg_rd_ind(struct cnic_dev *dev, u32 off) struct drv_ctl_info info; struct drv_ctl_io *io = &info.data.io; + memset(&info, 0, sizeof(struct drv_ctl_info)); info.cmd = DRV_CTL_IO_RD_CMD; io->offset = off; ethdev->drv_ctl(dev->netdev, &info); return io->data; } -static void cnic_ulp_ctl(struct cnic_dev *dev, int ulp_type, bool reg) +static void cnic_ulp_ctl(struct cnic_dev *dev, int ulp_type, bool reg, int state) { struct cnic_local *cp = dev->cnic_priv; struct cnic_eth_dev *ethdev = cp->ethdev; @@ -263,6 +268,7 @@ static void cnic_ulp_ctl(struct cnic_dev *dev, int ulp_type, bool reg) struct fcoe_capabilities *fcoe_cap = &info.data.register_data.fcoe_features; + memset(&info, 0, sizeof(struct drv_ctl_info)); if (reg) { info.cmd = DRV_CTL_ULP_REGISTER_CMD; if (ulp_type == CNIC_ULP_FCOE && dev->fcoe_cap) @@ -272,6 +278,7 @@ static void cnic_ulp_ctl(struct cnic_dev *dev, int ulp_type, bool reg) } info.data.ulp_type = ulp_type; + info.drv_state = state; ethdev->drv_ctl(dev->netdev, &info); } @@ -286,6 +293,7 @@ static void cnic_spq_completion(struct cnic_dev *dev, int cmd, u32 count) struct cnic_eth_dev *ethdev = cp->ethdev; struct drv_ctl_info info; + memset(&info, 0, sizeof(struct drv_ctl_info)); info.cmd = cmd; info.data.credit.credit_count = count; ethdev->drv_ctl(dev->netdev, &info); @@ -591,7 +599,7 @@ static int cnic_register_device(struct cnic_dev *dev, int ulp_type, mutex_unlock(&cnic_lock); - cnic_ulp_ctl(dev, ulp_type, true); + cnic_ulp_ctl(dev, ulp_type, true, DRV_ACTIVE); return 0; @@ -636,7 +644,10 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type) if (test_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[ulp_type])) netdev_warn(dev->netdev, "Failed waiting for ULP up call to complete\n"); - cnic_ulp_ctl(dev, ulp_type, false); + if (test_bit(ULP_F_INIT, &cp->ulp_flags[ulp_type])) + cnic_ulp_ctl(dev, ulp_type, false, DRV_UNLOADED); + else + cnic_ulp_ctl(dev, ulp_type, false, DRV_INACTIVE); return 0; } @@ -4267,6 +4278,7 @@ static void cnic_delete_task(struct work_struct *work) cnic_ulp_stop_one(cp, CNIC_ULP_ISCSI); + memset(&info, 0, sizeof(struct drv_ctl_info)); info.cmd = DRV_CTL_ISCSI_STOPPED_CMD; cp->ethdev->drv_ctl(dev->netdev, &info); } diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h index ef6125b0ee3e..d0cf006b5e0e 100644 --- a/drivers/net/ethernet/broadcom/cnic_if.h +++ b/drivers/net/ethernet/broadcom/cnic_if.h @@ -151,6 +151,11 @@ struct drv_ctl_register_data { struct drv_ctl_info { int cmd; + int drv_state; +#define DRV_NOP 0 +#define DRV_ACTIVE 1 +#define DRV_INACTIVE 2 +#define DRV_UNLOADED 3 union { struct drv_ctl_spq_credit credit; struct drv_ctl_io io; -- cgit v1.3-6-gb490 From 9b8d5044024df97edfcce8f0c4a6ca0abd99300e Mon Sep 17 00:00:00 2001 From: Adheer Chandravanshi Date: Tue, 4 Aug 2015 09:37:28 +0300 Subject: cnic: Add the interfaces to get FC-NPIV table. Signed-off-by: Adheer Chandravanshi Signed-off-by: Chad Dupuis Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/cnic.c | 18 ++++++++++++++++++ drivers/net/ethernet/broadcom/cnic_if.h | 16 ++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c index d9e35678277b..b69dc58faeab 100644 --- a/drivers/net/ethernet/broadcom/cnic.c +++ b/drivers/net/ethernet/broadcom/cnic.c @@ -5445,6 +5445,23 @@ static void cnic_free_dev(struct cnic_dev *dev) kfree(dev); } +static int cnic_get_fc_npiv_tbl(struct cnic_dev *dev, + struct cnic_fc_npiv_tbl *npiv_tbl) +{ + struct cnic_local *cp = dev->cnic_priv; + struct bnx2x *bp = netdev_priv(dev->netdev); + int ret; + + if (!test_bit(CNIC_F_CNIC_UP, &dev->flags)) + return -EAGAIN; /* bnx2x is down */ + + if (!BNX2X_CHIP_IS_E2_PLUS(bp)) + return -EINVAL; + + ret = cp->ethdev->drv_get_fc_npiv_tbl(dev->netdev, npiv_tbl); + return ret; +} + static struct cnic_dev *cnic_alloc_dev(struct net_device *dev, struct pci_dev *pdev) { @@ -5463,6 +5480,7 @@ static struct cnic_dev *cnic_alloc_dev(struct net_device *dev, cdev->register_device = cnic_register_device; cdev->unregister_device = cnic_unregister_device; cdev->iscsi_nl_msg_recv = cnic_iscsi_nl_msg_recv; + cdev->get_fc_npiv_tbl = cnic_get_fc_npiv_tbl; cp = cdev->cnic_priv; cp->dev = cdev; diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h index d0cf006b5e0e..789e5c7e9311 100644 --- a/drivers/net/ethernet/broadcom/cnic_if.h +++ b/drivers/net/ethernet/broadcom/cnic_if.h @@ -15,8 +15,8 @@ #include "bnx2x/bnx2x_mfw_req.h" -#define CNIC_MODULE_VERSION "2.5.21" -#define CNIC_MODULE_RELDATE "January 29, 2015" +#define CNIC_MODULE_VERSION "2.5.22" +#define CNIC_MODULE_RELDATE "July 20, 2015" #define CNIC_ULP_RDMA 0 #define CNIC_ULP_ISCSI 1 @@ -166,6 +166,15 @@ struct drv_ctl_info { } data; }; +#define MAX_NPIV_ENTRIES 64 +#define FC_NPIV_WWN_SIZE 8 + +struct cnic_fc_npiv_tbl { + u8 wwpn[MAX_NPIV_ENTRIES][FC_NPIV_WWN_SIZE]; + u8 wwnn[MAX_NPIV_ENTRIES][FC_NPIV_WWN_SIZE]; + u32 count; +}; + struct cnic_ops { struct module *cnic_owner; /* Calls to these functions are protected by RCU. When @@ -231,6 +240,8 @@ struct cnic_eth_dev { int (*drv_submit_kwqes_16)(struct net_device *, struct kwqe_16 *[], u32); int (*drv_ctl)(struct net_device *, struct drv_ctl_info *); + int (*drv_get_fc_npiv_tbl)(struct net_device *, + struct cnic_fc_npiv_tbl *); unsigned long reserved1[2]; union drv_info_to_mcp *addr_drv_info_to_mcp; }; @@ -319,6 +330,7 @@ struct cnic_dev { struct cnic_dev *(*cm_select_dev)(struct sockaddr_in *, int ulp_type); int (*iscsi_nl_msg_recv)(struct cnic_dev *dev, u32 msg_type, char *data, u16 data_size); + int (*get_fc_npiv_tbl)(struct cnic_dev *, struct cnic_fc_npiv_tbl *); unsigned long flags; #define CNIC_F_CNIC_UP 1 #define CNIC_F_BNX2_CLASS 3 -- cgit v1.3-6-gb490 From 97ac4ef78e6d44019745de7761da8536a9068cf8 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Tue, 4 Aug 2015 09:37:29 +0300 Subject: bnx2x: Add BD support for storage Commit 230d00eb4bfe ("bnx2x: new Multi-function mode - BD") adds support for the new mode in bnx2x. This expands this support by implementing APIs required by our storage drivers to support that mode. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 12 +++ .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 4 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 19 +++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 85 ++++++++++++++++++++++ 4 files changed, 118 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index fa7c53201265..e18a0e4d3ed1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -1386,4 +1386,16 @@ void bnx2x_schedule_sp_rtnl(struct bnx2x*, enum sp_rtnl_flag, * @state: OS_DRIVER_STATE_* value reflecting current driver state */ void bnx2x_set_os_driver_state(struct bnx2x *bp, u32 state); + +/** + * bnx2x_nvram_read - reads data from nvram [might sleep] + * + * @bp: driver handle + * @offset: byte offset in nvram + * @ret_buf: pointer to buffer where data is to be stored + * @buf_size: Length of 'ret_buf' in bytes + */ +int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf, + int buf_size); + #endif /* BNX2X_CMN_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 6b2050a198df..6f909077b919 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1348,8 +1348,8 @@ static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, __be32 *ret_val, return rc; } -static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf, - int buf_size) +int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf, + int buf_size) { int rc; u32 cmd_flags; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 08a08fa49caa..cafd5de675cf 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -2075,6 +2075,25 @@ enum curr_cfg_method_e { CURR_CFG_MET_VENDOR_SPEC = 2,/* e.g. Option ROM, NPAR, O/S Cfg Utils */ }; +#define FC_NPIV_WWPN_SIZE 8 +#define FC_NPIV_WWNN_SIZE 8 +struct bdn_npiv_settings { + u8 npiv_wwpn[FC_NPIV_WWPN_SIZE]; + u8 npiv_wwnn[FC_NPIV_WWNN_SIZE]; +}; + +struct bdn_fc_npiv_cfg { + /* hdr used internally by the MFW */ + u32 hdr; + u32 num_of_npiv; +}; + +#define MAX_NUMBER_NPIV 64 +struct bdn_fc_npiv_tbl { + struct bdn_fc_npiv_cfg fc_npiv_cfg; + struct bdn_npiv_settings settings[MAX_NUMBER_NPIV]; +}; + struct mdump_driver_info { u32 epoc; u32 drv_ver; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 31c63aa22521..ad73a60de333 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -14653,6 +14653,90 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl) rc = -EINVAL; } + /* For storage-only interfaces, change driver state */ + if (IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp)) { + switch (ctl->drv_state) { + case DRV_NOP: + break; + case DRV_ACTIVE: + bnx2x_set_os_driver_state(bp, + OS_DRIVER_STATE_ACTIVE); + break; + case DRV_INACTIVE: + bnx2x_set_os_driver_state(bp, + OS_DRIVER_STATE_DISABLED); + break; + case DRV_UNLOADED: + bnx2x_set_os_driver_state(bp, + OS_DRIVER_STATE_NOT_LOADED); + break; + default: + BNX2X_ERR("Unknown cnic driver state: %d\n", ctl->drv_state); + } + } + + return rc; +} + +static int bnx2x_get_fc_npiv(struct net_device *dev, + struct cnic_fc_npiv_tbl *cnic_tbl) +{ + struct bnx2x *bp = netdev_priv(dev); + struct bdn_fc_npiv_tbl *tbl = NULL; + u32 offset, entries; + int rc = -EINVAL; + int i; + + if (!SHMEM2_HAS(bp, fc_npiv_nvram_tbl_addr[0])) + goto out; + + DP(BNX2X_MSG_MCP, "About to read the FC-NPIV table\n"); + + tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); + if (!tbl) { + BNX2X_ERR("Failed to allocate fc_npiv table\n"); + goto out; + } + + offset = SHMEM2_RD(bp, fc_npiv_nvram_tbl_addr[BP_PORT(bp)]); + DP(BNX2X_MSG_MCP, "Offset of FC-NPIV in NVRAM: %08x\n", offset); + + /* Read the table contents from nvram */ + if (bnx2x_nvram_read(bp, offset, (u8 *)tbl, sizeof(*tbl))) { + BNX2X_ERR("Failed to read FC-NPIV table\n"); + goto out; + } + + /* Since bnx2x_nvram_read() returns data in be32, we need to convert + * the number of entries back to cpu endianness. + */ + entries = tbl->fc_npiv_cfg.num_of_npiv; + entries = (__force u32)be32_to_cpu((__force __be32)entries); + tbl->fc_npiv_cfg.num_of_npiv = entries; + + if (!tbl->fc_npiv_cfg.num_of_npiv) { + DP(BNX2X_MSG_MCP, + "No FC-NPIV table [valid, simply not present]\n"); + goto out; + } else if (tbl->fc_npiv_cfg.num_of_npiv > MAX_NUMBER_NPIV) { + BNX2X_ERR("FC-NPIV table with bad length 0x%08x\n", + tbl->fc_npiv_cfg.num_of_npiv); + goto out; + } else { + DP(BNX2X_MSG_MCP, "Read 0x%08x entries from NVRAM\n", + tbl->fc_npiv_cfg.num_of_npiv); + } + + /* Copy the data into cnic-provided struct */ + cnic_tbl->count = tbl->fc_npiv_cfg.num_of_npiv; + for (i = 0; i < cnic_tbl->count; i++) { + memcpy(cnic_tbl->wwpn[i], tbl->settings[i].npiv_wwpn, 8); + memcpy(cnic_tbl->wwnn[i], tbl->settings[i].npiv_wwnn, 8); + } + + rc = 0; +out: + kfree(tbl); return rc; } @@ -14798,6 +14882,7 @@ static struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev) cp->starting_cid = bnx2x_cid_ilt_lines(bp) * ILT_PAGE_CIDS; cp->drv_submit_kwqes_16 = bnx2x_cnic_sp_queue; cp->drv_ctl = bnx2x_drv_ctl; + cp->drv_get_fc_npiv_tbl = bnx2x_get_fc_npiv; cp->drv_register_cnic = bnx2x_register_cnic; cp->drv_unregister_cnic = bnx2x_unregister_cnic; cp->fcoe_init_cid = BNX2X_FCOE_ETH_CID(bp); -- cgit v1.3-6-gb490 From 2971ff67bd3283d187bd7a7906adfbbaad2257e1 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Tue, 4 Aug 2015 09:37:30 +0300 Subject: bnx2fc: Read npiv table from nvram and create vports. Signed-off-by: Joe Carnuccio Signed-off-by: Chad Dupuis Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 66 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 98d06d151958..d5cdc4776707 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -2051,9 +2051,49 @@ static int bnx2fc_disable(struct net_device *netdev) return rc; } +static uint bnx2fc_npiv_create_vports(struct fc_lport *lport, + struct cnic_fc_npiv_tbl *npiv_tbl) +{ + struct fc_vport_identifiers vpid; + uint i, created = 0; + + if (npiv_tbl->count > MAX_NPIV_ENTRIES) { + BNX2FC_HBA_DBG(lport, "Exceeded count max of npiv table\n"); + goto done; + } + + /* Sanity check the first entry to make sure it's not 0 */ + if (wwn_to_u64(npiv_tbl->wwnn[0]) == 0 && + wwn_to_u64(npiv_tbl->wwpn[0]) == 0) { + BNX2FC_HBA_DBG(lport, "First NPIV table entries invalid.\n"); + goto done; + } + + vpid.roles = FC_PORT_ROLE_FCP_INITIATOR; + vpid.vport_type = FC_PORTTYPE_NPIV; + vpid.disable = false; + + for (i = 0; i < npiv_tbl->count; i++) { + vpid.node_name = wwn_to_u64(npiv_tbl->wwnn[i]); + vpid.port_name = wwn_to_u64(npiv_tbl->wwpn[i]); + scnprintf(vpid.symbolic_name, sizeof(vpid.symbolic_name), + "NPIV[%u]:%016llx-%016llx", + created, vpid.port_name, vpid.node_name); + if (fc_vport_create(lport->host, 0, &vpid)) + created++; + else + BNX2FC_HBA_DBG(lport, "Failed to create vport\n"); + } +done: + return created; +} + static int __bnx2fc_enable(struct fcoe_ctlr *ctlr) { struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr); + struct bnx2fc_hba *hba; + struct cnic_fc_npiv_tbl npiv_tbl; + struct fc_lport *lport; if (interface->enabled == false) { if (!ctlr->lp) { @@ -2064,6 +2104,32 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr) interface->enabled = true; } } + + /* Create static NPIV ports if any are contained in NVRAM */ + hba = interface->hba; + lport = ctlr->lp; + + if (!hba) + goto done; + + if (!hba->cnic) + goto done; + + if (!lport) + goto done; + + if (!lport->host) + goto done; + + if (!hba->cnic->get_fc_npiv_tbl) + goto done; + + memset(&npiv_tbl, 0, sizeof(npiv_tbl)); + if (hba->cnic->get_fc_npiv_tbl(hba->cnic, &npiv_tbl)) + goto done; + + bnx2fc_npiv_create_vports(lport, &npiv_tbl); +done: return 0; } -- cgit v1.3-6-gb490 From 870915feabdc3af5f0ebb72d1fcf96bff01837b0 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Tue, 4 Aug 2015 16:06:18 +0530 Subject: drivers: net: cpsw: remove disable_irq/enable_irq as irq can be masked from cpsw itself CPSW interrupts can be disabled by masking CPSW interrupts and clearing interrupt by writing appropriate EOI. So removing all disable_irq/enable_irq as discussed in [1] [1] http://patchwork.ozlabs.org/patch/492741/ Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index d155bf2573cd..d68d759bb7a9 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -389,7 +389,6 @@ struct cpsw_priv { /* snapshot of IRQ numbers */ u32 irqs_table[4]; u32 num_irqs; - bool irq_enabled; struct cpts *cpts; u32 emac_port; }; @@ -767,12 +766,7 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) struct cpsw_priv *priv = dev_id; cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); - - cpsw_intr_disable(priv); - if (priv->irq_enabled == true) { - disable_irq_nosync(priv->irqs_table[0]); - priv->irq_enabled = false; - } + writel(0, &priv->wr_regs->rx_en); if (netif_running(priv->ndev)) { napi_schedule(&priv->napi); @@ -797,15 +791,8 @@ static int cpsw_poll(struct napi_struct *napi, int budget) num_rx = cpdma_chan_process(priv->rxch, budget); if (num_rx < budget) { - struct cpsw_priv *prim_cpsw; - napi_complete(napi); - cpsw_intr_enable(priv); - prim_cpsw = cpsw_get_slave_priv(priv, 0); - if (prim_cpsw->irq_enabled == false) { - prim_cpsw->irq_enabled = true; - enable_irq(priv->irqs_table[0]); - } + writel(0xff, &priv->wr_regs->rx_en); } if (num_rx) @@ -1230,7 +1217,6 @@ static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv) static int cpsw_ndo_open(struct net_device *ndev) { struct cpsw_priv *priv = netdev_priv(ndev); - struct cpsw_priv *prim_cpsw; int i, ret; u32 reg; @@ -1315,14 +1301,6 @@ static int cpsw_ndo_open(struct net_device *ndev) cpdma_ctlr_start(priv->dma); cpsw_intr_enable(priv); - prim_cpsw = cpsw_get_slave_priv(priv, 0); - if (prim_cpsw->irq_enabled == false) { - if ((priv == prim_cpsw) || !netif_running(prim_cpsw->ndev)) { - prim_cpsw->irq_enabled = true; - enable_irq(prim_cpsw->irqs_table[0]); - } - } - if (priv->data.dual_emac) priv->slaves[priv->emac_port].open_stat = true; return 0; @@ -2169,7 +2147,6 @@ static int cpsw_probe(struct platform_device *pdev) priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); priv->rx_packet_max = max(rx_packet_max, 128); priv->cpts = devm_kzalloc(&pdev->dev, sizeof(struct cpts), GFP_KERNEL); - priv->irq_enabled = true; if (!priv->cpts) { dev_err(&pdev->dev, "error allocating cpts\n"); ret = -ENOMEM; -- cgit v1.3-6-gb490 From d354eb85d61803e07831b68d1985cd9cfe2f8b59 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Tue, 4 Aug 2015 16:06:19 +0530 Subject: drivers: net: cpsw: dual_emac: simplify napi usage Since interrupt is shared between the two ethernet interface and in isr only one napi is scheduled at an instance so having two napis doesn't make any difference. So making napi also as a common resource for the dual ethernet interfaces. Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index d68d759bb7a9..1d923e812a3a 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -768,20 +768,8 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); writel(0, &priv->wr_regs->rx_en); - if (netif_running(priv->ndev)) { - napi_schedule(&priv->napi); - return IRQ_HANDLED; - } - - priv = cpsw_get_slave_priv(priv, 1); - if (!priv) - return IRQ_NONE; - - if (netif_running(priv->ndev)) { - napi_schedule(&priv->napi); - return IRQ_HANDLED; - } - return IRQ_NONE; + napi_schedule(&priv->napi); + return IRQ_HANDLED; } static int cpsw_poll(struct napi_struct *napi, int budget) @@ -1246,6 +1234,8 @@ static int cpsw_ndo_open(struct net_device *ndev) ALE_ALL_PORTS << priv->host_port, 0, 0); if (!cpsw_common_res_usage_state(priv)) { + struct cpsw_priv *priv_sl0 = cpsw_get_slave_priv(priv, 0); + /* setup tx dma to fixed prio and zero offset */ cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1); cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0); @@ -1259,6 +1249,8 @@ static int cpsw_ndo_open(struct net_device *ndev) /* Enable internal fifo flow control */ writel(0x7, &priv->regs->flow_control); + napi_enable(&priv_sl0->napi); + if (WARN_ON(!priv->data.rx_descs)) priv->data.rx_descs = 128; @@ -1297,7 +1289,6 @@ static int cpsw_ndo_open(struct net_device *ndev) cpsw_set_coalesce(ndev, &coal); } - napi_enable(&priv->napi); cpdma_ctlr_start(priv->dma); cpsw_intr_enable(priv); @@ -1319,10 +1310,12 @@ static int cpsw_ndo_stop(struct net_device *ndev) cpsw_info(priv, ifdown, "shutting down cpsw device\n"); netif_stop_queue(priv->ndev); - napi_disable(&priv->napi); netif_carrier_off(priv->ndev); if (cpsw_common_res_usage_state(priv) <= 1) { + struct cpsw_priv *priv_sl0 = cpsw_get_slave_priv(priv, 0); + + napi_disable(&priv_sl0->napi); cpts_unregister(priv->cpts); cpsw_intr_disable(priv); cpdma_ctlr_stop(priv->dma); @@ -2105,7 +2098,6 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev, ndev->netdev_ops = &cpsw_netdev_ops; ndev->ethtool_ops = &cpsw_ethtool_ops; - netif_napi_add(ndev, &priv_sl2->napi, cpsw_poll, CPSW_POLL_WEIGHT); /* register the network device */ SET_NETDEV_DEV(ndev, &pdev->dev); -- cgit v1.3-6-gb490 From 32a7432c0fb8b0117961bdc7ab256667d039de16 Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Tue, 4 Aug 2015 16:06:20 +0530 Subject: drivers: net: cpsw: add separate napi for tx Instead of processing tx events in isr adding separate napi for tx which improves performance by ~180Mbps with omap2plus_defconfig on DRA74x platform. Also cleaning up rx napis by renaming to napi_rx for better understanding the code. Signed-off-by: Mugunthan V N Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 44 +++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 1d923e812a3a..3b81b39bea6f 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -365,7 +365,8 @@ struct cpsw_priv { spinlock_t lock; struct platform_device *pdev; struct net_device *ndev; - struct napi_struct napi; + struct napi_struct napi_rx; + struct napi_struct napi_tx; struct device *dev; struct cpsw_platform_data data; struct cpsw_ss_regs __iomem *regs; @@ -751,13 +752,10 @@ static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) { struct cpsw_priv *priv = dev_id; + writel(0, &priv->wr_regs->tx_en); cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); - cpdma_chan_process(priv->txch, 128); - - priv = cpsw_get_slave_priv(priv, 1); - if (priv) - cpdma_chan_process(priv->txch, 128); + napi_schedule(&priv->napi_tx); return IRQ_HANDLED; } @@ -768,18 +766,35 @@ static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); writel(0, &priv->wr_regs->rx_en); - napi_schedule(&priv->napi); + napi_schedule(&priv->napi_rx); return IRQ_HANDLED; } -static int cpsw_poll(struct napi_struct *napi, int budget) +static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) +{ + struct cpsw_priv *priv = napi_to_priv(napi_tx); + int num_tx; + + num_tx = cpdma_chan_process(priv->txch, budget); + if (num_tx < budget) { + napi_complete(napi_tx); + writel(0xff, &priv->wr_regs->tx_en); + } + + if (num_tx) + cpsw_dbg(priv, intr, "poll %d tx pkts\n", num_tx); + + return num_tx; +} + +static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) { - struct cpsw_priv *priv = napi_to_priv(napi); + struct cpsw_priv *priv = napi_to_priv(napi_rx); int num_rx; num_rx = cpdma_chan_process(priv->rxch, budget); if (num_rx < budget) { - napi_complete(napi); + napi_complete(napi_rx); writel(0xff, &priv->wr_regs->rx_en); } @@ -1249,7 +1264,8 @@ static int cpsw_ndo_open(struct net_device *ndev) /* Enable internal fifo flow control */ writel(0x7, &priv->regs->flow_control); - napi_enable(&priv_sl0->napi); + napi_enable(&priv_sl0->napi_rx); + napi_enable(&priv_sl0->napi_tx); if (WARN_ON(!priv->data.rx_descs)) priv->data.rx_descs = 128; @@ -1315,7 +1331,8 @@ static int cpsw_ndo_stop(struct net_device *ndev) if (cpsw_common_res_usage_state(priv) <= 1) { struct cpsw_priv *priv_sl0 = cpsw_get_slave_priv(priv, 0); - napi_disable(&priv_sl0->napi); + napi_disable(&priv_sl0->napi_rx); + napi_disable(&priv_sl0->napi_tx); cpts_unregister(priv->cpts); cpsw_intr_disable(priv); cpdma_ctlr_stop(priv->dma); @@ -2349,7 +2366,8 @@ static int cpsw_probe(struct platform_device *pdev) ndev->netdev_ops = &cpsw_netdev_ops; ndev->ethtool_ops = &cpsw_ethtool_ops; - netif_napi_add(ndev, &priv->napi, cpsw_poll, CPSW_POLL_WEIGHT); + netif_napi_add(ndev, &priv->napi_rx, cpsw_rx_poll, CPSW_POLL_WEIGHT); + netif_napi_add(ndev, &priv->napi_tx, cpsw_tx_poll, CPSW_POLL_WEIGHT); /* register the network device */ SET_NETDEV_DEV(ndev, &pdev->dev); -- cgit v1.3-6-gb490 From 4cbeaff54f00f39493c4251bf115d02e26ac8bf2 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Tue, 4 Aug 2015 14:05:40 +0300 Subject: net/mlx5e: Unify the RX flow Generally an RX packet flows through the following objects: Flow table --> TIR --> RQT --> RQ Where: - TIR stands for "Transport Interface Receive", defining the RSS and LRO paramaters. - RQT stands for "RQ Table", implementing the RSS indirection table. - RQ stands for "Receive Queue" For flows that do not need LRO, nor RSS, the driver made a shortcut to the above RX flow by pointing to the RQ directly from the TIR, yielding this flow: Flow table --> TIR --> RQ In this commit we remove this shortcut by "inserting" a single-RQ RQT between the TIR and the RQ, i.e RX packets will reach the same RQ but will go through an RQT of size 1, pointing to just a single RQ. This way the RX traffic re-direction to/from the "Drop RQ" will be more uniform (AKA "one flow"), as it will involve only RQTs re-direction and no TIRs re-direction. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 10 +-- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 93 ++++++++++++++++------- 2 files changed, 69 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 45f6dc75c0df..af5791296584 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -344,10 +344,10 @@ enum mlx5e_traffic_types { MLX5E_NUM_TT, }; -enum { - MLX5E_RQT_SPREADING = 0, - MLX5E_RQT_DEFAULT_RQ = 1, - MLX5E_NUM_RQT = 2, +enum mlx5e_rqt_ix { + MLX5E_INDIRECTION_RQT, + MLX5E_SINGLE_RQ_RQT, + MLX5E_NUM_RQT, }; struct mlx5e_eth_addr_info { @@ -402,7 +402,7 @@ struct mlx5e_priv { struct mlx5e_channel **channel; u32 tisn[MLX5E_MAX_NUM_TC]; - u32 rqtn; + u32 rqtn[MLX5E_NUM_RQT]; u32 tirn[MLX5E_NUM_TT]; struct mlx5e_flow_table ft; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index bb815893d3a8..333c828c56da 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1184,16 +1184,49 @@ static int mlx5e_bits_invert(unsigned long a, int size) return inv; } -static int mlx5e_open_rqt(struct mlx5e_priv *priv) +static void mlx5e_fill_rqt_rqns(struct mlx5e_priv *priv, void *rqtc, + enum mlx5e_rqt_ix rqt_ix) +{ + int i; + int log_sz; + + switch (rqt_ix) { + case MLX5E_INDIRECTION_RQT: + log_sz = priv->params.rx_hash_log_tbl_sz; + for (i = 0; i < (1 << log_sz); i++) { + int ix = i; + + if (priv->params.rss_hfunc == ETH_RSS_HASH_XOR) + ix = mlx5e_bits_invert(i, log_sz); + + ix = ix % priv->params.num_channels; + MLX5_SET(rqtc, rqtc, rq_num[i], + priv->channel[ix]->rq.rqn); + } + + break; + + default: /* MLX5E_SINGLE_RQ_RQT */ + MLX5_SET(rqtc, rqtc, rq_num[0], + priv->channel[0]->rq.rqn); + + break; + } +} + +static int mlx5e_open_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix) { struct mlx5_core_dev *mdev = priv->mdev; u32 *in; void *rqtc; int inlen; + int log_sz; + int sz; int err; - int log_tbl_sz = priv->params.rx_hash_log_tbl_sz; - int sz = 1 << log_tbl_sz; - int i; + + log_sz = (rqt_ix == MLX5E_SINGLE_RQ_RQT) ? 0 : + priv->params.rx_hash_log_tbl_sz; + sz = 1 << log_sz; inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz; in = mlx5_vzalloc(inlen); @@ -1205,26 +1238,18 @@ static int mlx5e_open_rqt(struct mlx5e_priv *priv) MLX5_SET(rqtc, rqtc, rqt_actual_size, sz); MLX5_SET(rqtc, rqtc, rqt_max_size, sz); - for (i = 0; i < sz; i++) { - int ix = i; + mlx5e_fill_rqt_rqns(priv, rqtc, rqt_ix); - if (priv->params.rss_hfunc == ETH_RSS_HASH_XOR) - ix = mlx5e_bits_invert(i, log_tbl_sz); - - ix = ix % priv->params.num_channels; - MLX5_SET(rqtc, rqtc, rq_num[i], priv->channel[ix]->rq.rqn); - } - - err = mlx5_core_create_rqt(mdev, in, inlen, &priv->rqtn); + err = mlx5_core_create_rqt(mdev, in, inlen, &priv->rqtn[rqt_ix]); kvfree(in); return err; } -static void mlx5e_close_rqt(struct mlx5e_priv *priv) +static void mlx5e_close_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix) { - mlx5_core_destroy_rqt(priv->mdev, priv->rqtn); + mlx5_core_destroy_rqt(priv->mdev, priv->rqtn[rqt_ix]); } static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) @@ -1259,18 +1284,17 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) lro_timer_supported_periods[3])); } + MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT); + switch (tt) { case MLX5E_TT_ANY: - MLX5_SET(tirc, tirc, disp_type, - MLX5_TIRC_DISP_TYPE_DIRECT); - MLX5_SET(tirc, tirc, inline_rqn, - priv->channel[0]->rq.rqn); + MLX5_SET(tirc, tirc, indirect_table, + priv->rqtn[MLX5E_SINGLE_RQ_RQT]); + MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_INVERTED_XOR8); break; default: - MLX5_SET(tirc, tirc, disp_type, - MLX5_TIRC_DISP_TYPE_INDIRECT); MLX5_SET(tirc, tirc, indirect_table, - priv->rqtn); + priv->rqtn[MLX5E_INDIRECTION_RQT]); MLX5_SET(tirc, tirc, rx_hash_fn, mlx5e_rx_hash_fn(priv->params.rss_hfunc)); if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) { @@ -1472,18 +1496,25 @@ int mlx5e_open_locked(struct net_device *netdev) goto err_close_tises; } - err = mlx5e_open_rqt(priv); + err = mlx5e_open_rqt(priv, MLX5E_INDIRECTION_RQT); if (err) { - netdev_err(netdev, "%s: mlx5e_open_rqt failed, %d\n", + netdev_err(netdev, "%s: mlx5e_open_rqt(INDIR) failed, %d\n", __func__, err); goto err_close_channels; } + err = mlx5e_open_rqt(priv, MLX5E_SINGLE_RQ_RQT); + if (err) { + netdev_err(netdev, "%s: mlx5e_open_rqt(SINGLE) failed, %d\n", + __func__, err); + goto err_close_rqt_indir; + } + err = mlx5e_open_tirs(priv); if (err) { netdev_err(netdev, "%s: mlx5e_open_tir failed, %d\n", __func__, err); - goto err_close_rqls; + goto err_close_rqt_single; } err = mlx5e_open_flow_table(priv); @@ -1516,8 +1547,11 @@ err_close_flow_table: err_close_tirs: mlx5e_close_tirs(priv); -err_close_rqls: - mlx5e_close_rqt(priv); +err_close_rqt_single: + mlx5e_close_rqt(priv, MLX5E_SINGLE_RQ_RQT); + +err_close_rqt_indir: + mlx5e_close_rqt(priv, MLX5E_INDIRECTION_RQT); err_close_channels: mlx5e_close_channels(priv); @@ -1551,7 +1585,8 @@ int mlx5e_close_locked(struct net_device *netdev) netif_carrier_off(priv->netdev); mlx5e_close_flow_table(priv); mlx5e_close_tirs(priv); - mlx5e_close_rqt(priv); + mlx5e_close_rqt(priv, MLX5E_SINGLE_RQ_RQT); + mlx5e_close_rqt(priv, MLX5E_INDIRECTION_RQT); mlx5e_close_channels(priv); mlx5e_close_tises(priv); -- cgit v1.3-6-gb490 From 50cfa25aba67c658979c5a3188d514ee6780364b Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Tue, 4 Aug 2015 14:05:41 +0300 Subject: net/mlx5e: Introduce the "Drop RQ" RX traffic routed to this RQ will be silently dropped, at the NIC HW level. This is in preparation for netdev "light-weight" open/stop flow change described in previous commit. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 3 + drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 122 ++++++++++++++++++++-- 2 files changed, 114 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index af5791296584..31e9610926fe 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -217,6 +217,7 @@ struct mlx5e_cq { struct napi_struct *napi; struct mlx5_core_cq mcq; struct mlx5e_channel *channel; + struct mlx5e_priv *priv; /* control */ struct mlx5_wq_ctrl wq_ctrl; @@ -240,6 +241,7 @@ struct mlx5e_rq { struct mlx5_wq_ctrl wq_ctrl; u32 rqn; struct mlx5e_channel *channel; + struct mlx5e_priv *priv; } ____cacheline_aligned_in_smp; struct mlx5e_tx_skb_cb { @@ -399,6 +401,7 @@ struct mlx5e_priv { u32 pdn; u32 tdn; struct mlx5_core_mr mr; + struct mlx5e_rq drop_rq; struct mlx5e_channel **channel; u32 tisn[MLX5E_MAX_NUM_TC]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 333c828c56da..baa7a69bb694 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -307,6 +307,7 @@ static int mlx5e_create_rq(struct mlx5e_channel *c, rq->netdev = c->netdev; rq->channel = c; rq->ix = c->ix; + rq->priv = c->priv; return 0; @@ -324,8 +325,7 @@ static void mlx5e_destroy_rq(struct mlx5e_rq *rq) static int mlx5e_enable_rq(struct mlx5e_rq *rq, struct mlx5e_rq_param *param) { - struct mlx5e_channel *c = rq->channel; - struct mlx5e_priv *priv = c->priv; + struct mlx5e_priv *priv = rq->priv; struct mlx5_core_dev *mdev = priv->mdev; void *in; @@ -392,11 +392,7 @@ static int mlx5e_modify_rq(struct mlx5e_rq *rq, int curr_state, int next_state) static void mlx5e_disable_rq(struct mlx5e_rq *rq) { - struct mlx5e_channel *c = rq->channel; - struct mlx5e_priv *priv = c->priv; - struct mlx5_core_dev *mdev = priv->mdev; - - mlx5_core_destroy_rq(mdev, rq->rqn); + mlx5_core_destroy_rq(rq->priv->mdev, rq->rqn); } static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq) @@ -740,6 +736,7 @@ static int mlx5e_create_cq(struct mlx5e_channel *c, } cq->channel = c; + cq->priv = priv; return 0; } @@ -751,8 +748,7 @@ static void mlx5e_destroy_cq(struct mlx5e_cq *cq) static int mlx5e_enable_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param) { - struct mlx5e_channel *c = cq->channel; - struct mlx5e_priv *priv = c->priv; + struct mlx5e_priv *priv = cq->priv; struct mlx5_core_dev *mdev = priv->mdev; struct mlx5_core_cq *mcq = &cq->mcq; @@ -798,8 +794,7 @@ static int mlx5e_enable_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param) static void mlx5e_disable_cq(struct mlx5e_cq *cq) { - struct mlx5e_channel *c = cq->channel; - struct mlx5e_priv *priv = c->priv; + struct mlx5e_priv *priv = cq->priv; struct mlx5_core_dev *mdev = priv->mdev; mlx5_core_destroy_cq(mdev, &cq->mcq); @@ -1119,6 +1114,111 @@ static void mlx5e_close_channels(struct mlx5e_priv *priv) kfree(priv->channel); } +static int mlx5e_create_drop_rq(struct mlx5e_priv *priv, + struct mlx5e_rq *rq, + struct mlx5e_rq_param *param) +{ + struct mlx5_core_dev *mdev = priv->mdev; + void *rqc = param->rqc; + void *rqc_wq = MLX5_ADDR_OF(rqc, rqc, wq); + int err; + + param->wq.db_numa_node = param->wq.buf_numa_node; + + err = mlx5_wq_ll_create(mdev, ¶m->wq, rqc_wq, &rq->wq, + &rq->wq_ctrl); + if (err) + return err; + + rq->priv = priv; + + return 0; +} + +static int mlx5e_create_drop_cq(struct mlx5e_priv *priv, + struct mlx5e_cq *cq, + struct mlx5e_cq_param *param) +{ + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5_core_cq *mcq = &cq->mcq; + int eqn_not_used; + int irqn; + int err; + + err = mlx5_cqwq_create(mdev, ¶m->wq, param->cqc, &cq->wq, + &cq->wq_ctrl); + if (err) + return err; + + mlx5_vector2eqn(mdev, param->eq_ix, &eqn_not_used, &irqn); + + mcq->cqe_sz = 64; + mcq->set_ci_db = cq->wq_ctrl.db.db; + mcq->arm_db = cq->wq_ctrl.db.db + 1; + *mcq->set_ci_db = 0; + *mcq->arm_db = 0; + mcq->vector = param->eq_ix; + mcq->comp = mlx5e_completion_event; + mcq->event = mlx5e_cq_error_event; + mcq->irqn = irqn; + mcq->uar = &priv->cq_uar; + + cq->priv = priv; + + return 0; +} + +static int mlx5e_open_drop_rq(struct mlx5e_priv *priv) +{ + struct mlx5e_cq_param cq_param; + struct mlx5e_rq_param rq_param; + struct mlx5e_rq *rq = &priv->drop_rq; + struct mlx5e_cq *cq = &priv->drop_rq.cq; + int err; + + memset(&cq_param, 0, sizeof(cq_param)); + memset(&rq_param, 0, sizeof(rq_param)); + mlx5e_build_rx_cq_param(priv, &cq_param); + mlx5e_build_rq_param(priv, &rq_param); + + err = mlx5e_create_drop_cq(priv, cq, &cq_param); + if (err) + return err; + + err = mlx5e_enable_cq(cq, &cq_param); + if (err) + goto err_destroy_cq; + + err = mlx5e_create_drop_rq(priv, rq, &rq_param); + if (err) + goto err_disable_cq; + + err = mlx5e_enable_rq(rq, &rq_param); + if (err) + goto err_destroy_rq; + + return 0; + +err_destroy_rq: + mlx5e_destroy_rq(&priv->drop_rq); + +err_disable_cq: + mlx5e_disable_cq(&priv->drop_rq.cq); + +err_destroy_cq: + mlx5e_destroy_cq(&priv->drop_rq.cq); + + return err; +} + +static void mlx5e_close_drop_rq(struct mlx5e_priv *priv) +{ + mlx5e_disable_rq(&priv->drop_rq); + mlx5e_destroy_rq(&priv->drop_rq); + mlx5e_disable_cq(&priv->drop_rq.cq); + mlx5e_destroy_cq(&priv->drop_rq.cq); +} + static int mlx5e_open_tis(struct mlx5e_priv *priv, int tc) { struct mlx5_core_dev *mdev = priv->mdev; -- cgit v1.3-6-gb490 From d9eea403ca81f60cd535d354c77ada4c2bee8d66 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Tue, 4 Aug 2015 14:05:42 +0300 Subject: net/mlx5_core: Introduce access function to modify RSS/LRO params To be used by the mlx5 Eth driver in following commit. This is in preparation for netdev "light-weight" open/stop flow change described in previous commit. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/transobj.c | 12 ++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/transobj.h | 2 ++ include/linux/mlx5/mlx5_ifc.h | 9 ++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c index c4f3f74908ec..e6453f61141e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c @@ -163,6 +163,18 @@ int mlx5_core_create_tir(struct mlx5_core_dev *dev, u32 *in, int inlen, return err; } +int mlx5_core_modify_tir(struct mlx5_core_dev *dev, u32 tirn, u32 *in, + int inlen) +{ + u32 out[MLX5_ST_SZ_DW(modify_tir_out)]; + + MLX5_SET(modify_tir_in, in, tirn, tirn); + MLX5_SET(modify_tir_in, in, opcode, MLX5_CMD_OP_MODIFY_TIR); + + memset(out, 0, sizeof(out)); + return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); +} + void mlx5_core_destroy_tir(struct mlx5_core_dev *dev, u32 tirn) { u32 in[MLX5_ST_SZ_DW(destroy_tir_out)]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h index 10bd75e7d9b1..d436c2d8b527 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h @@ -45,6 +45,8 @@ int mlx5_core_modify_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *in, int inlen); void mlx5_core_destroy_sq(struct mlx5_core_dev *dev, u32 sqn); int mlx5_core_create_tir(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *tirn); +int mlx5_core_modify_tir(struct mlx5_core_dev *dev, u32 tirn, u32 *in, + int inlen); void mlx5_core_destroy_tir(struct mlx5_core_dev *dev, u32 tirn); int mlx5_core_create_tis(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *tisn); diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index c60a62bba652..469b7bda3304 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -4050,6 +4050,13 @@ struct mlx5_ifc_modify_tis_in_bits { struct mlx5_ifc_tisc_bits ctx; }; +struct mlx5_ifc_modify_tir_bitmask_bits { + u8 reserved[0x20]; + + u8 reserved1[0x1f]; + u8 lro[0x1]; +}; + struct mlx5_ifc_modify_tir_out_bits { u8 status[0x8]; u8 reserved_0[0x18]; @@ -4071,7 +4078,7 @@ struct mlx5_ifc_modify_tir_in_bits { u8 reserved_3[0x20]; - u8 modify_bitmask[0x40]; + struct mlx5_ifc_modify_tir_bitmask_bits bitmask; u8 reserved_4[0x40]; -- cgit v1.3-6-gb490 From 5c50368f38317627421bf24a0b66b1af0d44eddc Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Tue, 4 Aug 2015 14:05:43 +0300 Subject: net/mlx5e: Light-weight netdev open/stop Create/destroy TIRs, TISs and flow tables upon PCI probe/remove rather than upon the netdev ndo_open/stop. Upon ndo_stop(), redirect all RX traffic to the (lately introduced) "Drop RQ" and then close only the RX/TX rings, leaving the TIRs, TISs and flow tables alive. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 237 ++++++++++++++------- drivers/net/ethernet/mellanox/mlx5/core/transobj.c | 12 ++ drivers/net/ethernet/mellanox/mlx5/core/transobj.h | 2 + include/linux/mlx5/mlx5_ifc.h | 9 +- 4 files changed, 184 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index baa7a69bb694..33d08bb11f84 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1301,14 +1301,18 @@ static void mlx5e_fill_rqt_rqns(struct mlx5e_priv *priv, void *rqtc, ix = ix % priv->params.num_channels; MLX5_SET(rqtc, rqtc, rq_num[i], - priv->channel[ix]->rq.rqn); + test_bit(MLX5E_STATE_OPENED, &priv->state) ? + priv->channel[ix]->rq.rqn : + priv->drop_rq.rqn); } break; default: /* MLX5E_SINGLE_RQ_RQT */ MLX5_SET(rqtc, rqtc, rq_num[0], - priv->channel[0]->rq.rqn); + test_bit(MLX5E_STATE_OPENED, &priv->state) ? + priv->channel[0]->rq.rqn : + priv->drop_rq.rqn); break; } @@ -1347,19 +1351,95 @@ static int mlx5e_open_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix) return err; } +static int mlx5e_redirect_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix) +{ + struct mlx5_core_dev *mdev = priv->mdev; + u32 *in; + void *rqtc; + int inlen; + int log_sz; + int sz; + int err; + + log_sz = (rqt_ix == MLX5E_SINGLE_RQ_RQT) ? 0 : + priv->params.rx_hash_log_tbl_sz; + sz = 1 << log_sz; + + inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + sizeof(u32) * sz; + in = mlx5_vzalloc(inlen); + if (!in) + return -ENOMEM; + + rqtc = MLX5_ADDR_OF(modify_rqt_in, in, ctx); + + MLX5_SET(rqtc, rqtc, rqt_actual_size, sz); + + mlx5e_fill_rqt_rqns(priv, rqtc, rqt_ix); + + MLX5_SET(modify_rqt_in, in, bitmask.rqn_list, 1); + + err = mlx5_core_modify_rqt(mdev, priv->rqtn[rqt_ix], in, inlen); + + kvfree(in); + + return err; +} + static void mlx5e_close_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix) { mlx5_core_destroy_rqt(priv->mdev, priv->rqtn[rqt_ix]); } +static void mlx5e_build_tir_ctx_lro(void *tirc, struct mlx5e_priv *priv) +{ + if (!priv->params.lro_en) + return; + +#define ROUGH_MAX_L2_L3_HDR_SZ 256 + + MLX5_SET(tirc, tirc, lro_enable_mask, + MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO | + MLX5_TIRC_LRO_ENABLE_MASK_IPV6_LRO); + MLX5_SET(tirc, tirc, lro_max_ip_payload_size, + (priv->params.lro_wqe_sz - + ROUGH_MAX_L2_L3_HDR_SZ) >> 8); + MLX5_SET(tirc, tirc, lro_timeout_period_usecs, + MLX5_CAP_ETH(priv->mdev, + lro_timer_supported_periods[3])); +} + +static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt) +{ + struct mlx5_core_dev *mdev = priv->mdev; + + void *in; + void *tirc; + int inlen; + int err; + + inlen = MLX5_ST_SZ_BYTES(modify_tir_in); + in = mlx5_vzalloc(inlen); + if (!in) + return -ENOMEM; + + MLX5_SET(modify_tir_in, in, bitmask.lro, 1); + tirc = MLX5_ADDR_OF(modify_tir_in, in, ctx); + + mlx5e_build_tir_ctx_lro(tirc, priv); + + err = mlx5_core_modify_tir(mdev, priv->tirn[tt], in, inlen); + + kvfree(in); + + return err; +} + static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) { void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer); MLX5_SET(tirc, tirc, transport_domain, priv->tdn); -#define ROUGH_MAX_L2_L3_HDR_SZ 256 - #define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\ MLX5_HASH_FIELD_SEL_DST_IP) @@ -1372,17 +1452,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_HASH_FIELD_SEL_DST_IP |\ MLX5_HASH_FIELD_SEL_IPSEC_SPI) - if (priv->params.lro_en) { - MLX5_SET(tirc, tirc, lro_enable_mask, - MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO | - MLX5_TIRC_LRO_ENABLE_MASK_IPV6_LRO); - MLX5_SET(tirc, tirc, lro_max_ip_payload_size, - (priv->params.lro_wqe_sz - - ROUGH_MAX_L2_L3_HDR_SZ) >> 8); - MLX5_SET(tirc, tirc, lro_timeout_period_usecs, - MLX5_CAP_ETH(priv->mdev, - lro_timer_supported_periods[3])); - } + mlx5e_build_tir_ctx_lro(tirc, priv); MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT); @@ -1568,12 +1638,20 @@ static int mlx5e_set_dev_port_mtu(struct net_device *netdev) return 0; } +static void mlx5e_redirect_rqts(struct mlx5e_priv *priv) +{ + mlx5e_redirect_rqt(priv, MLX5E_INDIRECTION_RQT); + mlx5e_redirect_rqt(priv, MLX5E_SINGLE_RQ_RQT); +} + int mlx5e_open_locked(struct net_device *netdev) { struct mlx5e_priv *priv = netdev_priv(netdev); int num_txqs; int err; + set_bit(MLX5E_STATE_OPENED, &priv->state); + num_txqs = priv->params.num_channels * priv->params.num_tc; netif_set_real_num_tx_queues(netdev, num_txqs); netif_set_real_num_rx_queues(netdev, priv->params.num_channels); @@ -1582,83 +1660,32 @@ int mlx5e_open_locked(struct net_device *netdev) if (err) return err; - err = mlx5e_open_tises(priv); - if (err) { - netdev_err(netdev, "%s: mlx5e_open_tises failed, %d\n", - __func__, err); - return err; - } - err = mlx5e_open_channels(priv); if (err) { netdev_err(netdev, "%s: mlx5e_open_channels failed, %d\n", __func__, err); - goto err_close_tises; - } - - err = mlx5e_open_rqt(priv, MLX5E_INDIRECTION_RQT); - if (err) { - netdev_err(netdev, "%s: mlx5e_open_rqt(INDIR) failed, %d\n", - __func__, err); - goto err_close_channels; - } - - err = mlx5e_open_rqt(priv, MLX5E_SINGLE_RQ_RQT); - if (err) { - netdev_err(netdev, "%s: mlx5e_open_rqt(SINGLE) failed, %d\n", - __func__, err); - goto err_close_rqt_indir; - } - - err = mlx5e_open_tirs(priv); - if (err) { - netdev_err(netdev, "%s: mlx5e_open_tir failed, %d\n", - __func__, err); - goto err_close_rqt_single; - } - - err = mlx5e_open_flow_table(priv); - if (err) { - netdev_err(netdev, "%s: mlx5e_open_flow_table failed, %d\n", - __func__, err); - goto err_close_tirs; + return err; } err = mlx5e_add_all_vlan_rules(priv); if (err) { netdev_err(netdev, "%s: mlx5e_add_all_vlan_rules failed, %d\n", __func__, err); - goto err_close_flow_table; + goto err_close_channels; } mlx5e_init_eth_addr(priv); - set_bit(MLX5E_STATE_OPENED, &priv->state); - mlx5e_update_carrier(priv); + mlx5e_redirect_rqts(priv); mlx5e_set_rx_mode_core(priv); schedule_delayed_work(&priv->update_stats_work, 0); return 0; -err_close_flow_table: - mlx5e_close_flow_table(priv); - -err_close_tirs: - mlx5e_close_tirs(priv); - -err_close_rqt_single: - mlx5e_close_rqt(priv, MLX5E_SINGLE_RQ_RQT); - -err_close_rqt_indir: - mlx5e_close_rqt(priv, MLX5E_INDIRECTION_RQT); - err_close_channels: mlx5e_close_channels(priv); -err_close_tises: - mlx5e_close_tises(priv); - return err; } @@ -1682,13 +1709,9 @@ int mlx5e_close_locked(struct net_device *netdev) mlx5e_set_rx_mode_core(priv); mlx5e_del_all_vlan_rules(priv); + mlx5e_redirect_rqts(priv); netif_carrier_off(priv->netdev); - mlx5e_close_flow_table(priv); - mlx5e_close_tirs(priv); - mlx5e_close_rqt(priv, MLX5E_SINGLE_RQ_RQT); - mlx5e_close_rqt(priv, MLX5E_INDIRECTION_RQT); mlx5e_close_channels(priv); - mlx5e_close_tises(priv); return 0; } @@ -1766,6 +1789,8 @@ static int mlx5e_set_features(struct net_device *netdev, mlx5e_close_locked(priv->netdev); priv->params.lro_en = !!(features & NETIF_F_LRO); + mlx5e_modify_tir_lro(priv, MLX5E_TT_IPV4_TCP); + mlx5e_modify_tir_lro(priv, MLX5E_TT_IPV6_TCP); if (was_opened) err = mlx5e_open_locked(priv->netdev); @@ -2026,16 +2051,72 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev) goto err_dealloc_transport_domain; } + err = mlx5e_open_tises(priv); + if (err) { + mlx5_core_warn(mdev, "open tises failed, %d\n", err); + goto err_destroy_mkey; + } + + err = mlx5e_open_drop_rq(priv); + if (err) { + mlx5_core_err(mdev, "open drop rq failed, %d\n", err); + goto err_close_tises; + } + + err = mlx5e_open_rqt(priv, MLX5E_INDIRECTION_RQT); + if (err) { + mlx5_core_warn(mdev, "open rqt(INDIR) failed, %d\n", err); + goto err_close_drop_rq; + } + + err = mlx5e_open_rqt(priv, MLX5E_SINGLE_RQ_RQT); + if (err) { + mlx5_core_warn(mdev, "open rqt(SINGLE) failed, %d\n", err); + goto err_close_rqt_indir; + } + + err = mlx5e_open_tirs(priv); + if (err) { + mlx5_core_warn(mdev, "open tirs failed, %d\n", err); + goto err_close_rqt_single; + } + + err = mlx5e_open_flow_table(priv); + if (err) { + mlx5_core_warn(mdev, "open flow table failed, %d\n", err); + goto err_close_tirs; + } + + mlx5e_init_eth_addr(priv); + err = register_netdev(netdev); if (err) { mlx5_core_err(mdev, "register_netdev failed, %d\n", err); - goto err_destroy_mkey; + goto err_close_flow_table; } mlx5e_enable_async_events(priv); return priv; +err_close_flow_table: + mlx5e_close_flow_table(priv); + +err_close_tirs: + mlx5e_close_tirs(priv); + +err_close_rqt_single: + mlx5e_close_rqt(priv, MLX5E_SINGLE_RQ_RQT); + +err_close_rqt_indir: + mlx5e_close_rqt(priv, MLX5E_INDIRECTION_RQT); + +err_close_drop_rq: + mlx5e_close_drop_rq(priv); + +err_close_tises: + mlx5e_close_tises(priv); + err_destroy_mkey: mlx5_core_destroy_mkey(mdev, &priv->mr); @@ -2060,6 +2141,12 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv) struct net_device *netdev = priv->netdev; unregister_netdev(netdev); + mlx5e_close_flow_table(priv); + mlx5e_close_tirs(priv); + mlx5e_close_rqt(priv, MLX5E_SINGLE_RQ_RQT); + mlx5e_close_rqt(priv, MLX5E_INDIRECTION_RQT); + mlx5e_close_drop_rq(priv); + mlx5e_close_tises(priv); mlx5_core_destroy_mkey(priv->mdev, &priv->mr); mlx5_dealloc_transport_domain(priv->mdev, priv->tdn); mlx5_core_dealloc_pd(priv->mdev, priv->pdn); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c index e6453f61141e..b4c87c7b0cf0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.c @@ -387,6 +387,18 @@ int mlx5_core_create_rqt(struct mlx5_core_dev *dev, u32 *in, int inlen, return err; } +int mlx5_core_modify_rqt(struct mlx5_core_dev *dev, u32 rqtn, u32 *in, + int inlen) +{ + u32 out[MLX5_ST_SZ_DW(modify_rqt_out)]; + + MLX5_SET(modify_rqt_in, in, rqtn, rqtn); + MLX5_SET(modify_rqt_in, in, opcode, MLX5_CMD_OP_MODIFY_RQT); + + memset(out, 0, sizeof(out)); + return mlx5_cmd_exec_check_status(dev, in, inlen, out, sizeof(out)); +} + void mlx5_core_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn) { u32 in[MLX5_ST_SZ_DW(destroy_rqt_in)]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h index d436c2d8b527..74cae51436e4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/transobj.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/transobj.h @@ -65,6 +65,8 @@ int mlx5_core_arm_xsrq(struct mlx5_core_dev *dev, u32 rmpn, u16 lwm); int mlx5_core_create_rqt(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *rqtn); +int mlx5_core_modify_rqt(struct mlx5_core_dev *dev, u32 rqtn, u32 *in, + int inlen); void mlx5_core_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn); #endif /* __TRANSOBJ_H__ */ diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 469b7bda3304..dd2097455a2e 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -4123,6 +4123,13 @@ struct mlx5_ifc_modify_rqt_out_bits { u8 reserved_1[0x40]; }; +struct mlx5_ifc_rqt_bitmask_bits { + u8 reserved[0x20]; + + u8 reserved1[0x1f]; + u8 rqn_list[0x1]; +}; + struct mlx5_ifc_modify_rqt_in_bits { u8 opcode[0x10]; u8 reserved_0[0x10]; @@ -4135,7 +4142,7 @@ struct mlx5_ifc_modify_rqt_in_bits { u8 reserved_3[0x20]; - u8 modify_bitmask[0x40]; + struct mlx5_ifc_rqt_bitmask_bits bitmask; u8 reserved_4[0x40]; -- cgit v1.3-6-gb490 From 40ab6a6ebeebbcfc313233f5aa0d55930734f529 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Tue, 4 Aug 2015 14:05:44 +0300 Subject: net/mlx5e: Rename/move functions following the ndo_stop flow change Rename some functions that used to be invoked upon ndo_open/stop and are now invoked upon create/destroy_netdev() in order to better hint their place in the flow. Change some functions location in the file so that functions involved in ndo_open/stop flow will not be interleaved with other functions. This is a cosmetic change, no logical change here. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 4 +- .../ethernet/mellanox/mlx5/core/en_flow_table.c | 4 +- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 606 ++++++++++----------- 3 files changed, 306 insertions(+), 308 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 31e9610926fe..a6c4bd3265a5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -482,8 +482,8 @@ struct mlx5_cqe64 *mlx5e_get_cqe(struct mlx5e_cq *cq); void mlx5e_update_stats(struct mlx5e_priv *priv); -int mlx5e_open_flow_table(struct mlx5e_priv *priv); -void mlx5e_close_flow_table(struct mlx5e_priv *priv); +int mlx5e_create_flow_tables(struct mlx5e_priv *priv); +void mlx5e_destroy_flow_tables(struct mlx5e_priv *priv); void mlx5e_init_eth_addr(struct mlx5e_priv *priv); void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv); void mlx5e_set_rx_mode_work(struct work_struct *work); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c index 70ec31b9e1e9..d99be7892ebc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c @@ -929,7 +929,7 @@ static void mlx5e_destroy_vlan_flow_table(struct mlx5e_priv *priv) mlx5_destroy_flow_table(priv->ft.vlan); } -int mlx5e_open_flow_table(struct mlx5e_priv *priv) +int mlx5e_create_flow_tables(struct mlx5e_priv *priv) { int err; @@ -949,7 +949,7 @@ err_destroy_main_flow_table: return err; } -void mlx5e_close_flow_table(struct mlx5e_priv *priv) +void mlx5e_destroy_flow_tables(struct mlx5e_priv *priv) { mlx5e_destroy_vlan_flow_table(priv); mlx5e_destroy_main_flow_table(priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 33d08bb11f84..33a0488dc144 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1114,158 +1114,6 @@ static void mlx5e_close_channels(struct mlx5e_priv *priv) kfree(priv->channel); } -static int mlx5e_create_drop_rq(struct mlx5e_priv *priv, - struct mlx5e_rq *rq, - struct mlx5e_rq_param *param) -{ - struct mlx5_core_dev *mdev = priv->mdev; - void *rqc = param->rqc; - void *rqc_wq = MLX5_ADDR_OF(rqc, rqc, wq); - int err; - - param->wq.db_numa_node = param->wq.buf_numa_node; - - err = mlx5_wq_ll_create(mdev, ¶m->wq, rqc_wq, &rq->wq, - &rq->wq_ctrl); - if (err) - return err; - - rq->priv = priv; - - return 0; -} - -static int mlx5e_create_drop_cq(struct mlx5e_priv *priv, - struct mlx5e_cq *cq, - struct mlx5e_cq_param *param) -{ - struct mlx5_core_dev *mdev = priv->mdev; - struct mlx5_core_cq *mcq = &cq->mcq; - int eqn_not_used; - int irqn; - int err; - - err = mlx5_cqwq_create(mdev, ¶m->wq, param->cqc, &cq->wq, - &cq->wq_ctrl); - if (err) - return err; - - mlx5_vector2eqn(mdev, param->eq_ix, &eqn_not_used, &irqn); - - mcq->cqe_sz = 64; - mcq->set_ci_db = cq->wq_ctrl.db.db; - mcq->arm_db = cq->wq_ctrl.db.db + 1; - *mcq->set_ci_db = 0; - *mcq->arm_db = 0; - mcq->vector = param->eq_ix; - mcq->comp = mlx5e_completion_event; - mcq->event = mlx5e_cq_error_event; - mcq->irqn = irqn; - mcq->uar = &priv->cq_uar; - - cq->priv = priv; - - return 0; -} - -static int mlx5e_open_drop_rq(struct mlx5e_priv *priv) -{ - struct mlx5e_cq_param cq_param; - struct mlx5e_rq_param rq_param; - struct mlx5e_rq *rq = &priv->drop_rq; - struct mlx5e_cq *cq = &priv->drop_rq.cq; - int err; - - memset(&cq_param, 0, sizeof(cq_param)); - memset(&rq_param, 0, sizeof(rq_param)); - mlx5e_build_rx_cq_param(priv, &cq_param); - mlx5e_build_rq_param(priv, &rq_param); - - err = mlx5e_create_drop_cq(priv, cq, &cq_param); - if (err) - return err; - - err = mlx5e_enable_cq(cq, &cq_param); - if (err) - goto err_destroy_cq; - - err = mlx5e_create_drop_rq(priv, rq, &rq_param); - if (err) - goto err_disable_cq; - - err = mlx5e_enable_rq(rq, &rq_param); - if (err) - goto err_destroy_rq; - - return 0; - -err_destroy_rq: - mlx5e_destroy_rq(&priv->drop_rq); - -err_disable_cq: - mlx5e_disable_cq(&priv->drop_rq.cq); - -err_destroy_cq: - mlx5e_destroy_cq(&priv->drop_rq.cq); - - return err; -} - -static void mlx5e_close_drop_rq(struct mlx5e_priv *priv) -{ - mlx5e_disable_rq(&priv->drop_rq); - mlx5e_destroy_rq(&priv->drop_rq); - mlx5e_disable_cq(&priv->drop_rq.cq); - mlx5e_destroy_cq(&priv->drop_rq.cq); -} - -static int mlx5e_open_tis(struct mlx5e_priv *priv, int tc) -{ - struct mlx5_core_dev *mdev = priv->mdev; - u32 in[MLX5_ST_SZ_DW(create_tis_in)]; - void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx); - - memset(in, 0, sizeof(in)); - - MLX5_SET(tisc, tisc, prio, tc); - MLX5_SET(tisc, tisc, transport_domain, priv->tdn); - - return mlx5_core_create_tis(mdev, in, sizeof(in), &priv->tisn[tc]); -} - -static void mlx5e_close_tis(struct mlx5e_priv *priv, int tc) -{ - mlx5_core_destroy_tis(priv->mdev, priv->tisn[tc]); -} - -static int mlx5e_open_tises(struct mlx5e_priv *priv) -{ - int err; - int tc; - - for (tc = 0; tc < priv->params.num_tc; tc++) { - err = mlx5e_open_tis(priv, tc); - if (err) - goto err_close_tises; - } - - return 0; - -err_close_tises: - for (tc--; tc >= 0; tc--) - mlx5e_close_tis(priv, tc); - - return err; -} - -static void mlx5e_close_tises(struct mlx5e_priv *priv) -{ - int tc; - - for (tc = 0; tc < priv->params.num_tc; tc++) - mlx5e_close_tis(priv, tc); -} - static int mlx5e_rx_hash_fn(int hfunc) { return (hfunc == ETH_RSS_HASH_TOP) ? @@ -1318,7 +1166,7 @@ static void mlx5e_fill_rqt_rqns(struct mlx5e_priv *priv, void *rqtc, } } -static int mlx5e_open_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix) +static int mlx5e_create_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix) { struct mlx5_core_dev *mdev = priv->mdev; u32 *in; @@ -1385,11 +1233,17 @@ static int mlx5e_redirect_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix) return err; } -static void mlx5e_close_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix) +static void mlx5e_destroy_rqt(struct mlx5e_priv *priv, enum mlx5e_rqt_ix rqt_ix) { mlx5_core_destroy_rqt(priv->mdev, priv->rqtn[rqt_ix]); } +static void mlx5e_redirect_rqts(struct mlx5e_priv *priv) +{ + mlx5e_redirect_rqt(priv, MLX5E_INDIRECTION_RQT); + mlx5e_redirect_rqt(priv, MLX5E_SINGLE_RQ_RQT); +} + static void mlx5e_build_tir_ctx_lro(void *tirc, struct mlx5e_priv *priv) { if (!priv->params.lro_en) @@ -1434,6 +1288,261 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt) return err; } +static int mlx5e_set_dev_port_mtu(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + struct mlx5_core_dev *mdev = priv->mdev; + int hw_mtu; + int err; + + err = mlx5_set_port_mtu(mdev, MLX5E_SW2HW_MTU(netdev->mtu), 1); + if (err) + return err; + + mlx5_query_port_oper_mtu(mdev, &hw_mtu, 1); + + if (MLX5E_HW2SW_MTU(hw_mtu) != netdev->mtu) + netdev_warn(netdev, "%s: Port MTU %d is different than netdev mtu %d\n", + __func__, MLX5E_HW2SW_MTU(hw_mtu), netdev->mtu); + + netdev->mtu = MLX5E_HW2SW_MTU(hw_mtu); + return 0; +} + +int mlx5e_open_locked(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + int num_txqs; + int err; + + set_bit(MLX5E_STATE_OPENED, &priv->state); + + num_txqs = priv->params.num_channels * priv->params.num_tc; + netif_set_real_num_tx_queues(netdev, num_txqs); + netif_set_real_num_rx_queues(netdev, priv->params.num_channels); + + err = mlx5e_set_dev_port_mtu(netdev); + if (err) + return err; + + err = mlx5e_open_channels(priv); + if (err) { + netdev_err(netdev, "%s: mlx5e_open_channels failed, %d\n", + __func__, err); + return err; + } + + err = mlx5e_add_all_vlan_rules(priv); + if (err) { + netdev_err(netdev, "%s: mlx5e_add_all_vlan_rules failed, %d\n", + __func__, err); + goto err_close_channels; + } + + mlx5e_update_carrier(priv); + mlx5e_redirect_rqts(priv); + mlx5e_set_rx_mode_core(priv); + + schedule_delayed_work(&priv->update_stats_work, 0); + return 0; + +err_close_channels: + mlx5e_close_channels(priv); + + return err; +} + +static int mlx5e_open(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + int err; + + mutex_lock(&priv->state_lock); + err = mlx5e_open_locked(netdev); + mutex_unlock(&priv->state_lock); + + return err; +} + +int mlx5e_close_locked(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + clear_bit(MLX5E_STATE_OPENED, &priv->state); + + mlx5e_redirect_rqts(priv); + mlx5e_set_rx_mode_core(priv); + mlx5e_del_all_vlan_rules(priv); + netif_carrier_off(priv->netdev); + mlx5e_close_channels(priv); + + return 0; +} + +static int mlx5e_close(struct net_device *netdev) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + int err; + + mutex_lock(&priv->state_lock); + err = mlx5e_close_locked(netdev); + mutex_unlock(&priv->state_lock); + + return err; +} + +static int mlx5e_create_drop_rq(struct mlx5e_priv *priv, + struct mlx5e_rq *rq, + struct mlx5e_rq_param *param) +{ + struct mlx5_core_dev *mdev = priv->mdev; + void *rqc = param->rqc; + void *rqc_wq = MLX5_ADDR_OF(rqc, rqc, wq); + int err; + + param->wq.db_numa_node = param->wq.buf_numa_node; + + err = mlx5_wq_ll_create(mdev, ¶m->wq, rqc_wq, &rq->wq, + &rq->wq_ctrl); + if (err) + return err; + + rq->priv = priv; + + return 0; +} + +static int mlx5e_create_drop_cq(struct mlx5e_priv *priv, + struct mlx5e_cq *cq, + struct mlx5e_cq_param *param) +{ + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5_core_cq *mcq = &cq->mcq; + int eqn_not_used; + int irqn; + int err; + + err = mlx5_cqwq_create(mdev, ¶m->wq, param->cqc, &cq->wq, + &cq->wq_ctrl); + if (err) + return err; + + mlx5_vector2eqn(mdev, param->eq_ix, &eqn_not_used, &irqn); + + mcq->cqe_sz = 64; + mcq->set_ci_db = cq->wq_ctrl.db.db; + mcq->arm_db = cq->wq_ctrl.db.db + 1; + *mcq->set_ci_db = 0; + *mcq->arm_db = 0; + mcq->vector = param->eq_ix; + mcq->comp = mlx5e_completion_event; + mcq->event = mlx5e_cq_error_event; + mcq->irqn = irqn; + mcq->uar = &priv->cq_uar; + + cq->priv = priv; + + return 0; +} + +static int mlx5e_open_drop_rq(struct mlx5e_priv *priv) +{ + struct mlx5e_cq_param cq_param; + struct mlx5e_rq_param rq_param; + struct mlx5e_rq *rq = &priv->drop_rq; + struct mlx5e_cq *cq = &priv->drop_rq.cq; + int err; + + memset(&cq_param, 0, sizeof(cq_param)); + memset(&rq_param, 0, sizeof(rq_param)); + mlx5e_build_rx_cq_param(priv, &cq_param); + mlx5e_build_rq_param(priv, &rq_param); + + err = mlx5e_create_drop_cq(priv, cq, &cq_param); + if (err) + return err; + + err = mlx5e_enable_cq(cq, &cq_param); + if (err) + goto err_destroy_cq; + + err = mlx5e_create_drop_rq(priv, rq, &rq_param); + if (err) + goto err_disable_cq; + + err = mlx5e_enable_rq(rq, &rq_param); + if (err) + goto err_destroy_rq; + + return 0; + +err_destroy_rq: + mlx5e_destroy_rq(&priv->drop_rq); + +err_disable_cq: + mlx5e_disable_cq(&priv->drop_rq.cq); + +err_destroy_cq: + mlx5e_destroy_cq(&priv->drop_rq.cq); + + return err; +} + +static void mlx5e_close_drop_rq(struct mlx5e_priv *priv) +{ + mlx5e_disable_rq(&priv->drop_rq); + mlx5e_destroy_rq(&priv->drop_rq); + mlx5e_disable_cq(&priv->drop_rq.cq); + mlx5e_destroy_cq(&priv->drop_rq.cq); +} + +static int mlx5e_create_tis(struct mlx5e_priv *priv, int tc) +{ + struct mlx5_core_dev *mdev = priv->mdev; + u32 in[MLX5_ST_SZ_DW(create_tis_in)]; + void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx); + + memset(in, 0, sizeof(in)); + + MLX5_SET(tisc, tisc, prio, tc); + MLX5_SET(tisc, tisc, transport_domain, priv->tdn); + + return mlx5_core_create_tis(mdev, in, sizeof(in), &priv->tisn[tc]); +} + +static void mlx5e_destroy_tis(struct mlx5e_priv *priv, int tc) +{ + mlx5_core_destroy_tis(priv->mdev, priv->tisn[tc]); +} + +static int mlx5e_create_tises(struct mlx5e_priv *priv) +{ + int err; + int tc; + + for (tc = 0; tc < priv->params.num_tc; tc++) { + err = mlx5e_create_tis(priv, tc); + if (err) + goto err_close_tises; + } + + return 0; + +err_close_tises: + for (tc--; tc >= 0; tc--) + mlx5e_destroy_tis(priv, tc); + + return err; +} + +static void mlx5e_destroy_tises(struct mlx5e_priv *priv) +{ + int tc; + + for (tc = 0; tc < priv->params.num_tc; tc++) + mlx5e_destroy_tis(priv, tc); +} + static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) { void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer); @@ -1560,7 +1669,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) } } -static int mlx5e_open_tir(struct mlx5e_priv *priv, int tt) +static int mlx5e_create_tir(struct mlx5e_priv *priv, int tt) { struct mlx5_core_dev *mdev = priv->mdev; u32 *in; @@ -1584,148 +1693,37 @@ static int mlx5e_open_tir(struct mlx5e_priv *priv, int tt) return err; } -static void mlx5e_close_tir(struct mlx5e_priv *priv, int tt) +static void mlx5e_destroy_tir(struct mlx5e_priv *priv, int tt) { mlx5_core_destroy_tir(priv->mdev, priv->tirn[tt]); } -static int mlx5e_open_tirs(struct mlx5e_priv *priv) +static int mlx5e_create_tirs(struct mlx5e_priv *priv) { int err; int i; for (i = 0; i < MLX5E_NUM_TT; i++) { - err = mlx5e_open_tir(priv, i); + err = mlx5e_create_tir(priv, i); if (err) - goto err_close_tirs; + goto err_destroy_tirs; } return 0; -err_close_tirs: +err_destroy_tirs: for (i--; i >= 0; i--) - mlx5e_close_tir(priv, i); + mlx5e_destroy_tir(priv, i); return err; } -static void mlx5e_close_tirs(struct mlx5e_priv *priv) +static void mlx5e_destroy_tirs(struct mlx5e_priv *priv) { int i; for (i = 0; i < MLX5E_NUM_TT; i++) - mlx5e_close_tir(priv, i); -} - -static int mlx5e_set_dev_port_mtu(struct net_device *netdev) -{ - struct mlx5e_priv *priv = netdev_priv(netdev); - struct mlx5_core_dev *mdev = priv->mdev; - int hw_mtu; - int err; - - err = mlx5_set_port_mtu(mdev, MLX5E_SW2HW_MTU(netdev->mtu), 1); - if (err) - return err; - - mlx5_query_port_oper_mtu(mdev, &hw_mtu, 1); - - if (MLX5E_HW2SW_MTU(hw_mtu) != netdev->mtu) - netdev_warn(netdev, "%s: Port MTU %d is different than netdev mtu %d\n", - __func__, MLX5E_HW2SW_MTU(hw_mtu), netdev->mtu); - - netdev->mtu = MLX5E_HW2SW_MTU(hw_mtu); - return 0; -} - -static void mlx5e_redirect_rqts(struct mlx5e_priv *priv) -{ - mlx5e_redirect_rqt(priv, MLX5E_INDIRECTION_RQT); - mlx5e_redirect_rqt(priv, MLX5E_SINGLE_RQ_RQT); -} - -int mlx5e_open_locked(struct net_device *netdev) -{ - struct mlx5e_priv *priv = netdev_priv(netdev); - int num_txqs; - int err; - - set_bit(MLX5E_STATE_OPENED, &priv->state); - - num_txqs = priv->params.num_channels * priv->params.num_tc; - netif_set_real_num_tx_queues(netdev, num_txqs); - netif_set_real_num_rx_queues(netdev, priv->params.num_channels); - - err = mlx5e_set_dev_port_mtu(netdev); - if (err) - return err; - - err = mlx5e_open_channels(priv); - if (err) { - netdev_err(netdev, "%s: mlx5e_open_channels failed, %d\n", - __func__, err); - return err; - } - - err = mlx5e_add_all_vlan_rules(priv); - if (err) { - netdev_err(netdev, "%s: mlx5e_add_all_vlan_rules failed, %d\n", - __func__, err); - goto err_close_channels; - } - - mlx5e_init_eth_addr(priv); - - mlx5e_update_carrier(priv); - mlx5e_redirect_rqts(priv); - mlx5e_set_rx_mode_core(priv); - - schedule_delayed_work(&priv->update_stats_work, 0); - return 0; - -err_close_channels: - mlx5e_close_channels(priv); - - return err; -} - -static int mlx5e_open(struct net_device *netdev) -{ - struct mlx5e_priv *priv = netdev_priv(netdev); - int err; - - mutex_lock(&priv->state_lock); - err = mlx5e_open_locked(netdev); - mutex_unlock(&priv->state_lock); - - return err; -} - -int mlx5e_close_locked(struct net_device *netdev) -{ - struct mlx5e_priv *priv = netdev_priv(netdev); - - clear_bit(MLX5E_STATE_OPENED, &priv->state); - - mlx5e_set_rx_mode_core(priv); - mlx5e_del_all_vlan_rules(priv); - mlx5e_redirect_rqts(priv); - netif_carrier_off(priv->netdev); - mlx5e_close_channels(priv); - - return 0; -} - -static int mlx5e_close(struct net_device *netdev) -{ - struct mlx5e_priv *priv = netdev_priv(netdev); - int err; - - mutex_lock(&priv->state_lock); - err = mlx5e_close_locked(netdev); - mutex_unlock(&priv->state_lock); - - return err; + mlx5e_destroy_tir(priv, i); } static struct rtnl_link_stats64 * @@ -2051,40 +2049,40 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev) goto err_dealloc_transport_domain; } - err = mlx5e_open_tises(priv); + err = mlx5e_create_tises(priv); if (err) { - mlx5_core_warn(mdev, "open tises failed, %d\n", err); + mlx5_core_warn(mdev, "create tises failed, %d\n", err); goto err_destroy_mkey; } err = mlx5e_open_drop_rq(priv); if (err) { mlx5_core_err(mdev, "open drop rq failed, %d\n", err); - goto err_close_tises; + goto err_destroy_tises; } - err = mlx5e_open_rqt(priv, MLX5E_INDIRECTION_RQT); + err = mlx5e_create_rqt(priv, MLX5E_INDIRECTION_RQT); if (err) { - mlx5_core_warn(mdev, "open rqt(INDIR) failed, %d\n", err); + mlx5_core_warn(mdev, "create rqt(INDIR) failed, %d\n", err); goto err_close_drop_rq; } - err = mlx5e_open_rqt(priv, MLX5E_SINGLE_RQ_RQT); + err = mlx5e_create_rqt(priv, MLX5E_SINGLE_RQ_RQT); if (err) { - mlx5_core_warn(mdev, "open rqt(SINGLE) failed, %d\n", err); - goto err_close_rqt_indir; + mlx5_core_warn(mdev, "create rqt(SINGLE) failed, %d\n", err); + goto err_destroy_rqt_indir; } - err = mlx5e_open_tirs(priv); + err = mlx5e_create_tirs(priv); if (err) { - mlx5_core_warn(mdev, "open tirs failed, %d\n", err); - goto err_close_rqt_single; + mlx5_core_warn(mdev, "create tirs failed, %d\n", err); + goto err_destroy_rqt_single; } - err = mlx5e_open_flow_table(priv); + err = mlx5e_create_flow_tables(priv); if (err) { - mlx5_core_warn(mdev, "open flow table failed, %d\n", err); - goto err_close_tirs; + mlx5_core_warn(mdev, "create flow tables failed, %d\n", err); + goto err_destroy_tirs; } mlx5e_init_eth_addr(priv); @@ -2092,30 +2090,30 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev) err = register_netdev(netdev); if (err) { mlx5_core_err(mdev, "register_netdev failed, %d\n", err); - goto err_close_flow_table; + goto err_destroy_flow_tables; } mlx5e_enable_async_events(priv); return priv; -err_close_flow_table: - mlx5e_close_flow_table(priv); +err_destroy_flow_tables: + mlx5e_destroy_flow_tables(priv); -err_close_tirs: - mlx5e_close_tirs(priv); +err_destroy_tirs: + mlx5e_destroy_tirs(priv); -err_close_rqt_single: - mlx5e_close_rqt(priv, MLX5E_SINGLE_RQ_RQT); +err_destroy_rqt_single: + mlx5e_destroy_rqt(priv, MLX5E_SINGLE_RQ_RQT); -err_close_rqt_indir: - mlx5e_close_rqt(priv, MLX5E_INDIRECTION_RQT); +err_destroy_rqt_indir: + mlx5e_destroy_rqt(priv, MLX5E_INDIRECTION_RQT); err_close_drop_rq: mlx5e_close_drop_rq(priv); -err_close_tises: - mlx5e_close_tises(priv); +err_destroy_tises: + mlx5e_destroy_tises(priv); err_destroy_mkey: mlx5_core_destroy_mkey(mdev, &priv->mr); @@ -2141,12 +2139,12 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv) struct net_device *netdev = priv->netdev; unregister_netdev(netdev); - mlx5e_close_flow_table(priv); - mlx5e_close_tirs(priv); - mlx5e_close_rqt(priv, MLX5E_SINGLE_RQ_RQT); - mlx5e_close_rqt(priv, MLX5E_INDIRECTION_RQT); + mlx5e_destroy_flow_tables(priv); + mlx5e_destroy_tirs(priv); + mlx5e_destroy_rqt(priv, MLX5E_SINGLE_RQ_RQT); + mlx5e_destroy_rqt(priv, MLX5E_INDIRECTION_RQT); mlx5e_close_drop_rq(priv); - mlx5e_close_tises(priv); + mlx5e_destroy_tises(priv); mlx5_core_destroy_mkey(priv->mdev, &priv->mr); mlx5_dealloc_transport_domain(priv->mdev, priv->tdn); mlx5_core_dealloc_pd(priv->mdev, priv->pdn); -- cgit v1.3-6-gb490 From 1cefa326ff26dddb2c4a7f43802ce0ba5c35a2ba Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Tue, 4 Aug 2015 14:05:45 +0300 Subject: net/mlx5e: Disable async events before unregister_netdev() It does not make sense to allow events while the netdev is unregistered. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 33a0488dc144..436968806268 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2138,6 +2138,8 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv) struct mlx5e_priv *priv = vpriv; struct net_device *netdev = priv->netdev; + mlx5e_disable_async_events(priv); + flush_scheduled_work(); unregister_netdev(netdev); mlx5e_destroy_flow_tables(priv); mlx5e_destroy_tirs(priv); @@ -2149,8 +2151,6 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv) mlx5_dealloc_transport_domain(priv->mdev, priv->tdn); mlx5_core_dealloc_pd(priv->mdev, priv->pdn); mlx5_unmap_free_uar(priv->mdev, &priv->cq_uar); - mlx5e_disable_async_events(priv); - flush_scheduled_work(); free_netdev(netdev); } -- cgit v1.3-6-gb490 From 9b37b07fcb0e00a9c0b605b7b28c2d200f4eb064 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Tue, 4 Aug 2015 14:05:46 +0300 Subject: net/mlx5e: Take advantage of the light-weight netdev open/stop Now that TIRs, TISs and flow tables are kept alive while the netdev is stopped (after executing ndo_stop()) we can do the following improvements: - Obsolete the active_vlans SW shadow. - Do not delete/add flow table rules upon ndo_stop/open. In addition to simplifying the flow, this change also fastens the ndo_open/close operations. - Obsolete synchronization of threads accessing the flow tables with the netdev stop/open threads. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 5 +- .../ethernet/mellanox/mlx5/core/en_flow_table.c | 109 +++++---------------- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 24 ++--- 3 files changed, 32 insertions(+), 106 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index a6c4bd3265a5..35c33907a9ff 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -374,10 +374,10 @@ struct mlx5e_eth_addr_db { enum { MLX5E_STATE_ASYNC_EVENTS_ENABLE, MLX5E_STATE_OPENED, + MLX5E_STATE_DESTROYING, }; struct mlx5e_vlan_db { - unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; u32 active_vlans_ft_ix[VLAN_N_VID]; u32 untagged_rule_ft_ix; u32 any_vlan_rule_ft_ix; @@ -485,7 +485,6 @@ void mlx5e_update_stats(struct mlx5e_priv *priv); int mlx5e_create_flow_tables(struct mlx5e_priv *priv); void mlx5e_destroy_flow_tables(struct mlx5e_priv *priv); void mlx5e_init_eth_addr(struct mlx5e_priv *priv); -void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv); void mlx5e_set_rx_mode_work(struct work_struct *work); int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto, @@ -494,8 +493,6 @@ int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto, u16 vid); void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv); void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv); -int mlx5e_add_all_vlan_rules(struct mlx5e_priv *priv); -void mlx5e_del_all_vlan_rules(struct mlx5e_priv *priv); int mlx5e_open_locked(struct net_device *netdev); int mlx5e_close_locked(struct net_device *netdev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c index d99be7892ebc..e71563ce05d1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c @@ -594,44 +594,28 @@ static void mlx5e_del_vlan_rule(struct mlx5e_priv *priv, void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv) { - WARN_ON(!mutex_is_locked(&priv->state_lock)); + if (!priv->vlan.filter_disabled) + return; - if (priv->vlan.filter_disabled) { - priv->vlan.filter_disabled = false; - if (test_bit(MLX5E_STATE_OPENED, &priv->state)) - mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, - 0); - } + priv->vlan.filter_disabled = false; + mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0); } void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv) { - WARN_ON(!mutex_is_locked(&priv->state_lock)); + if (priv->vlan.filter_disabled) + return; - if (!priv->vlan.filter_disabled) { - priv->vlan.filter_disabled = true; - if (test_bit(MLX5E_STATE_OPENED, &priv->state)) - mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, - 0); - } + priv->vlan.filter_disabled = true; + mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0); } int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto, u16 vid) { struct mlx5e_priv *priv = netdev_priv(dev); - int err = 0; - - mutex_lock(&priv->state_lock); - - set_bit(vid, priv->vlan.active_vlans); - if (test_bit(MLX5E_STATE_OPENED, &priv->state)) - err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, - vid); - mutex_unlock(&priv->state_lock); - - return err; + return mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); } int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto, @@ -639,56 +623,11 @@ int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto, { struct mlx5e_priv *priv = netdev_priv(dev); - mutex_lock(&priv->state_lock); - - clear_bit(vid, priv->vlan.active_vlans); - if (test_bit(MLX5E_STATE_OPENED, &priv->state)) - mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); - - mutex_unlock(&priv->state_lock); - - return 0; -} - -int mlx5e_add_all_vlan_rules(struct mlx5e_priv *priv) -{ - u16 vid; - int err; - - for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) { - err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, - vid); - if (err) - return err; - } - - err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); - if (err) - return err; - - if (priv->vlan.filter_disabled) { - err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, - 0); - if (err) - return err; - } + mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); return 0; } -void mlx5e_del_all_vlan_rules(struct mlx5e_priv *priv) -{ - u16 vid; - - if (priv->vlan.filter_disabled) - mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0); - - mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); - - for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) - mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid); -} - #define mlx5e_for_each_hash_node(hn, tmp, hash, i) \ for (i = 0; i < MLX5E_ETH_ADDR_HASH_SIZE; i++) \ hlist_for_each_entry_safe(hn, tmp, &hash[i], hlist) @@ -752,18 +691,21 @@ static void mlx5e_handle_netdev_addr(struct mlx5e_priv *priv) mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_mc, i) hn->action = MLX5E_ACTION_DEL; - if (test_bit(MLX5E_STATE_OPENED, &priv->state)) + if (!test_bit(MLX5E_STATE_DESTROYING, &priv->state)) mlx5e_sync_netdev_addr(priv); mlx5e_apply_netdev_addr(priv); } -void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv) +void mlx5e_set_rx_mode_work(struct work_struct *work) { + struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv, + set_rx_mode_work); + struct mlx5e_eth_addr_db *ea = &priv->eth_addr; struct net_device *ndev = priv->netdev; - bool rx_mode_enable = test_bit(MLX5E_STATE_OPENED, &priv->state); + bool rx_mode_enable = !test_bit(MLX5E_STATE_DESTROYING, &priv->state); bool promisc_enabled = rx_mode_enable && (ndev->flags & IFF_PROMISC); bool allmulti_enabled = rx_mode_enable && (ndev->flags & IFF_ALLMULTI); bool broadcast_enabled = rx_mode_enable; @@ -796,17 +738,6 @@ void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv) ea->broadcast_enabled = broadcast_enabled; } -void mlx5e_set_rx_mode_work(struct work_struct *work) -{ - struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv, - set_rx_mode_work); - - mutex_lock(&priv->state_lock); - if (test_bit(MLX5E_STATE_OPENED, &priv->state)) - mlx5e_set_rx_mode_core(priv); - mutex_unlock(&priv->state_lock); -} - void mlx5e_init_eth_addr(struct mlx5e_priv *priv) { ether_addr_copy(priv->eth_addr.broadcast.addr, priv->netdev->broadcast); @@ -941,8 +872,15 @@ int mlx5e_create_flow_tables(struct mlx5e_priv *priv) if (err) goto err_destroy_main_flow_table; + err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); + if (err) + goto err_destroy_vlan_flow_table; + return 0; +err_destroy_vlan_flow_table: + mlx5e_destroy_vlan_flow_table(priv); + err_destroy_main_flow_table: mlx5e_destroy_main_flow_table(priv); @@ -951,6 +889,7 @@ err_destroy_main_flow_table: void mlx5e_destroy_flow_tables(struct mlx5e_priv *priv) { + mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0); mlx5e_destroy_vlan_flow_table(priv); mlx5e_destroy_main_flow_table(priv); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 436968806268..b8023a7484e0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1332,24 +1332,12 @@ int mlx5e_open_locked(struct net_device *netdev) return err; } - err = mlx5e_add_all_vlan_rules(priv); - if (err) { - netdev_err(netdev, "%s: mlx5e_add_all_vlan_rules failed, %d\n", - __func__, err); - goto err_close_channels; - } - mlx5e_update_carrier(priv); mlx5e_redirect_rqts(priv); - mlx5e_set_rx_mode_core(priv); schedule_delayed_work(&priv->update_stats_work, 0); - return 0; -err_close_channels: - mlx5e_close_channels(priv); - - return err; + return 0; } static int mlx5e_open(struct net_device *netdev) @@ -1371,8 +1359,6 @@ int mlx5e_close_locked(struct net_device *netdev) clear_bit(MLX5E_STATE_OPENED, &priv->state); mlx5e_redirect_rqts(priv); - mlx5e_set_rx_mode_core(priv); - mlx5e_del_all_vlan_rules(priv); netif_carrier_off(priv->netdev); mlx5e_close_channels(priv); @@ -1794,6 +1780,8 @@ static int mlx5e_set_features(struct net_device *netdev, err = mlx5e_open_locked(priv->netdev); } + mutex_unlock(&priv->state_lock); + if (changes & NETIF_F_HW_VLAN_CTAG_FILTER) { if (features & NETIF_F_HW_VLAN_CTAG_FILTER) mlx5e_enable_vlan_filter(priv); @@ -1801,8 +1789,6 @@ static int mlx5e_set_features(struct net_device *netdev, mlx5e_disable_vlan_filter(priv); } - mutex_unlock(&priv->state_lock); - return 0; } @@ -2094,6 +2080,7 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev) } mlx5e_enable_async_events(priv); + schedule_work(&priv->set_rx_mode_work); return priv; @@ -2138,6 +2125,9 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv) struct mlx5e_priv *priv = vpriv; struct net_device *netdev = priv->netdev; + set_bit(MLX5E_STATE_DESTROYING, &priv->state); + + schedule_work(&priv->set_rx_mode_work); mlx5e_disable_async_events(priv); flush_scheduled_work(); unregister_netdev(netdev); -- cgit v1.3-6-gb490 From efea389d3cc6427a9a94e92b2d7bf4c862f2cfcf Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Tue, 4 Aug 2015 14:05:47 +0300 Subject: net/mlx5_core: Support physical port counters Added physical port counters in the following standard formats to ethtool statistics: - IEEE 802.3 - RFC2863 - RFC2819 Signed-off-by: Gal Pressman Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 75 ++++++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 10 ++- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 42 ++++++++++++ include/linux/mlx5/device.h | 10 +++ include/linux/mlx5/driver.h | 1 + 5 files changed, 137 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 35c33907a9ff..e9d7d90363a8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -138,6 +138,80 @@ struct mlx5e_vport_stats { #define NUM_VPORT_COUNTERS 31 }; +static const char pport_strings[][ETH_GSTRING_LEN] = { + /* IEEE802.3 counters */ + "frames_tx", + "frames_rx", + "check_seq_err", + "alignment_err", + "octets_tx", + "octets_received", + "multicast_xmitted", + "broadcast_xmitted", + "multicast_rx", + "broadcast_rx", + "in_range_len_errors", + "out_of_range_len", + "too_long_errors", + "symbol_err", + "mac_control_tx", + "mac_control_rx", + "unsupported_op_rx", + "pause_ctrl_rx", + "pause_ctrl_tx", + + /* RFC2863 counters */ + "in_octets", + "in_ucast_pkts", + "in_discards", + "in_errors", + "in_unknown_protos", + "out_octets", + "out_ucast_pkts", + "out_discards", + "out_errors", + "in_multicast_pkts", + "in_broadcast_pkts", + "out_multicast_pkts", + "out_broadcast_pkts", + + /* RFC2819 counters */ + "drop_events", + "octets", + "pkts", + "broadcast_pkts", + "multicast_pkts", + "crc_align_errors", + "undersize_pkts", + "oversize_pkts", + "fragments", + "jabbers", + "collisions", + "p64octets", + "p65to127octets", + "p128to255octets", + "p256to511octets", + "p512to1023octets", + "p1024to1518octets", + "p1519to2047octets", + "p2048to4095octets", + "p4096to8191octets", + "p8192to10239octets", +}; + +#define NUM_IEEE_802_3_COUNTERS 19 +#define NUM_RFC_2863_COUNTERS 13 +#define NUM_RFC_2819_COUNTERS 21 +#define NUM_PPORT_COUNTERS (NUM_IEEE_802_3_COUNTERS + \ + NUM_RFC_2863_COUNTERS + \ + NUM_RFC_2819_COUNTERS) + +struct mlx5e_pport_stats { + __be64 IEEE_802_3_counters[NUM_IEEE_802_3_COUNTERS]; + __be64 RFC_2863_counters[NUM_RFC_2863_COUNTERS]; + __be64 RFC_2819_counters[NUM_RFC_2819_COUNTERS]; +}; + static const char rq_stats_strings[][ETH_GSTRING_LEN] = { "packets", "csum_none", @@ -180,6 +254,7 @@ struct mlx5e_sq_stats { struct mlx5e_stats { struct mlx5e_vport_stats vport; + struct mlx5e_pport_stats pport; }; struct mlx5e_params { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index b95aa3384c36..b549797b315f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -171,7 +171,7 @@ static int mlx5e_get_sset_count(struct net_device *dev, int sset) switch (sset) { case ETH_SS_STATS: - return NUM_VPORT_COUNTERS + + return NUM_VPORT_COUNTERS + NUM_PPORT_COUNTERS + priv->params.num_channels * NUM_RQ_STATS + priv->params.num_channels * priv->params.num_tc * NUM_SQ_STATS; @@ -200,6 +200,11 @@ static void mlx5e_get_strings(struct net_device *dev, strcpy(data + (idx++) * ETH_GSTRING_LEN, vport_strings[i]); + /* PPORT counters */ + for (i = 0; i < NUM_PPORT_COUNTERS; i++) + strcpy(data + (idx++) * ETH_GSTRING_LEN, + pport_strings[i]); + /* per channel counters */ for (i = 0; i < priv->params.num_channels; i++) for (j = 0; j < NUM_RQ_STATS; j++) @@ -234,6 +239,9 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev, for (i = 0; i < NUM_VPORT_COUNTERS; i++) data[idx++] = ((u64 *)&priv->stats.vport)[i]; + for (i = 0; i < NUM_PPORT_COUNTERS; i++) + data[idx++] = be64_to_cpu(((__be64 *)&priv->stats.pport)[i]); + /* per channel counters */ for (i = 0; i < priv->params.num_channels; i++) for (j = 0; j < NUM_RQ_STATS; j++) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index b8023a7484e0..111427b33ec8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -82,6 +82,47 @@ static void mlx5e_update_carrier_work(struct work_struct *work) mutex_unlock(&priv->state_lock); } +static void mlx5e_update_pport_counters(struct mlx5e_priv *priv) +{ + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5e_pport_stats *s = &priv->stats.pport; + u32 *in; + u32 *out; + int sz = MLX5_ST_SZ_BYTES(ppcnt_reg); + + in = mlx5_vzalloc(sz); + out = mlx5_vzalloc(sz); + if (!in || !out) + goto free_out; + + MLX5_SET(ppcnt_reg, in, local_port, 1); + + MLX5_SET(ppcnt_reg, in, grp, MLX5_IEEE_802_3_COUNTERS_GROUP); + mlx5_core_access_reg(mdev, in, sz, out, + sz, MLX5_REG_PPCNT, 0, 0); + memcpy(s->IEEE_802_3_counters, + MLX5_ADDR_OF(ppcnt_reg, out, counter_set), + sizeof(s->IEEE_802_3_counters)); + + MLX5_SET(ppcnt_reg, in, grp, MLX5_RFC_2863_COUNTERS_GROUP); + mlx5_core_access_reg(mdev, in, sz, out, + sz, MLX5_REG_PPCNT, 0, 0); + memcpy(s->RFC_2863_counters, + MLX5_ADDR_OF(ppcnt_reg, out, counter_set), + sizeof(s->RFC_2863_counters)); + + MLX5_SET(ppcnt_reg, in, grp, MLX5_RFC_2819_COUNTERS_GROUP); + mlx5_core_access_reg(mdev, in, sz, out, + sz, MLX5_REG_PPCNT, 0, 0); + memcpy(s->RFC_2819_counters, + MLX5_ADDR_OF(ppcnt_reg, out, counter_set), + sizeof(s->RFC_2819_counters)); + +free_out: + kvfree(in); + kvfree(out); +} + void mlx5e_update_stats(struct mlx5e_priv *priv) { struct mlx5_core_dev *mdev = priv->mdev; @@ -202,6 +243,7 @@ void mlx5e_update_stats(struct mlx5e_priv *priv) s->tx_csum_offload = s->tx_packets - tx_offload_none; s->rx_csum_good = s->rx_packets - s->rx_csum_none; + mlx5e_update_pport_counters(priv); free_out: kvfree(out); } diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index b943cd9e2097..250b1ff8b48d 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -1182,6 +1182,16 @@ enum { MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR = 0x40, }; +enum { + MLX5_IEEE_802_3_COUNTERS_GROUP = 0x0, + MLX5_RFC_2863_COUNTERS_GROUP = 0x1, + MLX5_RFC_2819_COUNTERS_GROUP = 0x2, + MLX5_RFC_3635_COUNTERS_GROUP = 0x3, + MLX5_ETHERNET_EXTENDED_COUNTERS_GROUP = 0x5, + MLX5_PER_PRIORITY_COUNTERS_GROUP = 0x10, + MLX5_PER_TRAFFIC_CLASS_COUNTERS_GROUP = 0x11 +}; + static inline u16 mlx5_to_sw_pkey_sz(int pkey_sz) { if (pkey_sz > MLX5_MAX_LOG_PKEY_TABLE) diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 5fe0cae1a515..2039546b0ec6 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -103,6 +103,7 @@ enum { MLX5_REG_PMTU = 0x5003, MLX5_REG_PTYS = 0x5004, MLX5_REG_PAOS = 0x5006, + MLX5_REG_PPCNT = 0x5008, MLX5_REG_PMAOS = 0x5012, MLX5_REG_PUDE = 0x5009, MLX5_REG_PMPE = 0x5010, -- cgit v1.3-6-gb490 From b49d15d138aa4632f35a2db93dee775d920f3653 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 7 Aug 2015 13:45:25 +1000 Subject: twl4030_charger: fix compile error when TWL4030_MADC not available. We can only use the madc to check for 'ac' availability if the madc has been compiled in. If not: assume always using USB. Reported-by: Tony Lindgren Signed-off-by: NeilBrown Acked-by: Tony Lindgren Signed-off-by: Sebastian Reichel --- drivers/power/twl4030_charger.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index 2c537ee11bbe..f4f2c1f76c32 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -91,6 +91,21 @@ #define TWL4030_MSTATEC_COMPLETE1 0x0b #define TWL4030_MSTATEC_COMPLETE4 0x0e +#if IS_ENABLED(CONFIG_TWL4030_MADC) +/* + * If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11) + * then AC is available. + */ +static inline int ac_available(void) +{ + return twl4030_get_madc_conversion(11) > 4500; +} +#else +static inline int ac_available(void) +{ + return 0; +} +#endif static bool allow_usb; module_param(allow_usb, bool, 0644); MODULE_PARM_DESC(allow_usb, "Allow USB charge drawing default current"); @@ -263,7 +278,7 @@ static int twl4030_charger_update_current(struct twl4030_bci *bci) * If AC (Accessory Charger) voltage exceeds 4.5V (MADC 11) * and AC is enabled, set current for 'ac' */ - if (twl4030_get_madc_conversion(11) > 4500) { + if (ac_available()) { cur = bci->ac_cur; bci->ac_is_active = true; } else { -- cgit v1.3-6-gb490 From 3b97487445ef3833fcb88ca4bb469b6df3b44329 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Tue, 4 Aug 2015 17:11:15 +0200 Subject: s390: remove unneeded semicolon Remove unneeded semicolon. The semantic patch that detects this change is available at scripts/coccinelle/misc/semicolon.cocci. Signed-off-by: Peter Senna Tschudin Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_alias.c | 6 +++--- drivers/s390/char/monreader.c | 2 +- drivers/s390/scsi/zfcp_fsf.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index ee3a6faae22a..fe07f3139bf6 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -58,7 +58,7 @@ static struct alias_server *_find_server(struct dasd_uid *uid) && !strncmp(pos->uid.serial, uid->serial, sizeof(uid->serial))) return pos; - }; + } return NULL; } @@ -69,7 +69,7 @@ static struct alias_lcu *_find_lcu(struct alias_server *server, list_for_each_entry(pos, &server->lculist, lcu) { if (pos->uid.ssid == uid->ssid) return pos; - }; + } return NULL; } @@ -97,7 +97,7 @@ static struct alias_pav_group *_find_group(struct alias_lcu *lcu, if (pos->uid.base_unit_addr == search_unit_addr && !strncmp(pos->uid.vduit, uid->vduit, sizeof(uid->vduit))) return pos; - }; + } return NULL; } diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 0da3ae3cd63b..b7d60306b0bc 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -95,7 +95,7 @@ static void dcss_mkname(char *ascii_name, char *ebcdic_name) if (ascii_name[i] == '\0') break; ebcdic_name[i] = toupper(ascii_name[i]); - }; + } for (; i < 8; i++) ebcdic_name[i] = ' '; ASCEBC(ebcdic_name, 8); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 21ec5e2f584c..4ac73e047c11 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -204,7 +204,7 @@ static void zfcp_fsf_status_read_link_down(struct zfcp_fsf_req *req) break; case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: zfcp_fsf_link_down_info_eval(req, NULL); - }; + } } static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) -- cgit v1.3-6-gb490 From b2f4de8b843567504ee12b652b35819b60e25a86 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Tue, 4 Aug 2015 17:11:47 +0200 Subject: s390: remove unneeded variables This patch remove unneeded variables used to store return values. These issues were detected with the Coccinelle script: scripts/coccinelle/misc/returnvar.cocci [heiko.carstens@de.ibm.com]: make qeth_l[2/3]_stop() return void Signed-off-by: Peter Senna Tschudin Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/eadm_sch.c | 3 +-- drivers/s390/net/qeth_l2_main.c | 5 +---- drivers/s390/net/qeth_l3_main.c | 5 +---- 3 files changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index bee8c11cd086..b3f44bc7f644 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c @@ -336,7 +336,6 @@ static int eadm_subchannel_sch_event(struct subchannel *sch, int process) { struct eadm_private *private; unsigned long flags; - int ret = 0; spin_lock_irqsave(sch->lock, flags); if (!device_is_registered(&sch->dev)) @@ -356,7 +355,7 @@ static int eadm_subchannel_sch_event(struct subchannel *sch, int process) out_unlock: spin_unlock_irqrestore(sch->lock, flags); - return ret; + return 0; } static struct css_device_id eadm_subchannel_ids[] = { diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 2e65b989a9ea..a8556692f632 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -390,10 +390,8 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev, return rc; } -static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode) +static void qeth_l2_stop_card(struct qeth_card *card, int recovery_mode) { - int rc = 0; - QETH_DBF_TEXT(SETUP , 2, "stopcard"); QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); @@ -427,7 +425,6 @@ static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode) qeth_clear_cmd_buffers(&card->read); qeth_clear_cmd_buffers(&card->write); } - return rc; } static int qeth_l2_process_inbound_buffer(struct qeth_card *card, diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 70eb2f61bb92..a1aaa36e9ebb 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2158,10 +2158,8 @@ static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev) return card ; } -static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) +static void qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) { - int rc = 0; - QETH_DBF_TEXT(SETUP, 2, "stopcard"); QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); @@ -2196,7 +2194,6 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) qeth_clear_cmd_buffers(&card->read); qeth_clear_cmd_buffers(&card->write); } - return rc; } /* -- cgit v1.3-6-gb490 From 12e035968191c05a574c9c20367cb3090bc7d99d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 6 Aug 2015 12:44:30 +0200 Subject: ath9k: fix build with CONFIG_ATH9K_STATION_STATISTICS=y kbuild bot reported that commit 592fa228f213 ("ath9k: remove struct ath_atx_ac") broke the build when CONFIG_ATH9K_STATION_STATISTICS is y. Reported-by: kbuild test robot Fixes: 592fa228f213 ("ath9k: remove struct ath_atx_ac") Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/debug_sta.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c index ffca918ff16a..c2ca57a2ed09 100644 --- a/drivers/net/wireless/ath/ath9k/debug_sta.c +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c @@ -26,12 +26,11 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, struct ath_node *an = file->private_data; struct ath_softc *sc = an->sc; struct ath_atx_tid *tid; - struct ath_atx_ac *ac; struct ath_txq *txq; u32 len = 0, size = 4096; char *buf; size_t retval; - int tidno, acno; + int tidno; buf = kzalloc(size, GFP_KERNEL); if (buf == NULL) @@ -48,19 +47,6 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, len += scnprintf(buf + len, size - len, "MPDU Density: %d\n\n", an->mpdudensity); - len += scnprintf(buf + len, size - len, - "%2s%7s\n", "AC", "SCHED"); - - for (acno = 0, ac = &an->ac[acno]; - acno < IEEE80211_NUM_ACS; acno++, ac++) { - txq = ac->txq; - ath_txq_lock(sc, txq); - len += scnprintf(buf + len, size - len, - "%2d%7d\n", - acno, ac->sched); - ath_txq_unlock(sc, txq); - } - len += scnprintf(buf + len, size - len, "\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n", "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", @@ -68,7 +54,7 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, for (tidno = 0, tid = &an->tid[tidno]; tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { - txq = tid->ac->txq; + txq = tid->txq; ath_txq_lock(sc, txq); if (tid->active) { len += scnprintf(buf + len, size - len, @@ -80,7 +66,7 @@ static ssize_t read_file_node_aggr(struct file *file, char __user *user_buf, tid->baw_head, tid->baw_tail, tid->bar_index, - tid->sched); + !list_empty(&tid->list)); } ath_txq_unlock(sc, txq); } -- cgit v1.3-6-gb490 From 971bd8fa369a37b047c26e9a47d4c1f5d2dce4d3 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 20 May 2015 23:54:02 +0900 Subject: treewide: Fix typo in printk This patch fix spelling typo inv various part of sources. Signed-off-by: Masanari Iida Acked-by: Randy Dunlap Signed-off-by: Jiri Kosina --- arch/powerpc/sysdev/fsl_pci.c | 2 +- drivers/crypto/img-hash.c | 2 +- drivers/input/touchscreen/ili210x.c | 4 ++-- drivers/isdn/mISDN/dsp_cmx.c | 2 +- drivers/mailbox/arm_mhu.c | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 2 +- drivers/regulator/max77843.c | 2 +- drivers/usb/dwc2/core.c | 2 +- fs/ecryptfs/mmap.c | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 9a8fcf0d79d7..ebc1f412cf49 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -1113,7 +1113,7 @@ static int fsl_pci_pme_probe(struct pci_controller *hose) IRQF_SHARED, "[PCI] PME", hose); if (res < 0) { - dev_err(&dev->dev, "Unable to requiest irq %d for PME\n", pme_irq); + dev_err(&dev->dev, "Unable to request irq %d for PME\n", pme_irq); irq_dispose_mapping(pme_irq); return -ENODEV; diff --git a/drivers/crypto/img-hash.c b/drivers/crypto/img-hash.c index ad47d0d61098..68e8aa90fe01 100644 --- a/drivers/crypto/img-hash.c +++ b/drivers/crypto/img-hash.c @@ -334,7 +334,7 @@ static int img_hash_dma_init(struct img_hash_dev *hdev) hdev->dma_lch = dma_request_slave_channel(hdev->dev, "tx"); if (!hdev->dma_lch) { - dev_err(hdev->dev, "Couldn't aquire a slave DMA channel.\n"); + dev_err(hdev->dev, "Couldn't acquire a slave DMA channel.\n"); return -EBUSY; } dma_conf.direction = DMA_MEM_TO_DEV; diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index da6dc819c846..586bee407d9a 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -216,7 +216,7 @@ static int ili210x_i2c_probe(struct i2c_client *client, /* get panel info */ error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel)); if (error) { - dev_err(dev, "Failed to get panel informations, err: %d\n", + dev_err(dev, "Failed to get panel information, err: %d\n", error); return error; } @@ -276,7 +276,7 @@ static int ili210x_i2c_probe(struct i2c_client *client, error = input_register_device(priv->input); if (error) { - dev_err(dev, "Cannot regiser input device, err: %d\n", error); + dev_err(dev, "Cannot register input device, err: %d\n", error); goto err_remove_sysfs; } diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 52c43821f746..8e3aa002767b 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -506,7 +506,7 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) __func__, conf->id); if (list_empty(&conf->mlist)) { - printk(KERN_ERR "%s: conference whithout members\n", + printk(KERN_ERR "%s: conference without members\n", __func__); return; } diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c index d9e99f981aa9..d0d0b0305345 100644 --- a/drivers/mailbox/arm_mhu.c +++ b/drivers/mailbox/arm_mhu.c @@ -96,7 +96,7 @@ static int mhu_startup(struct mbox_chan *chan) IRQF_SHARED, "mhu_link", chan); if (ret) { dev_err(chan->mbox->dev, - "Unable to aquire IRQ %d\n", mlink->irq); + "Unable to acquire IRQ %d\n", mlink->irq); return ret; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 12497f5ed8e9..906c83c7e8e7 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -1734,7 +1734,7 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) mfc_debug(1, "New context: %d\n", new_ctx); ctx = dev->ctx[new_ctx]; - mfc_debug(1, "Seting new context to %p\n", ctx); + mfc_debug(1, "Setting new context to %p\n", ctx); /* Got context to run in ctx */ mfc_debug(1, "ctx->dst_queue_cnt=%d ctx->dpb_count=%d ctx->src_queue_cnt=%d\n", ctx->dst_queue_cnt, ctx->pb_count, ctx->src_queue_cnt); diff --git a/drivers/regulator/max77843.c b/drivers/regulator/max77843.c index f4fd0d3cfa6e..3941fdb27ee2 100644 --- a/drivers/regulator/max77843.c +++ b/drivers/regulator/max77843.c @@ -162,7 +162,7 @@ static int max77843_regulator_probe(struct platform_device *pdev) &max77843_supported_regulators[i], &config); if (IS_ERR(regulator)) { dev_err(&pdev->dev, - "Failed to regiser regulator-%d\n", i); + "Failed to register regulator-%d\n", i); return PTR_ERR(regulator); } } diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index c3cc1a78d1e2..b00fe9539184 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -3175,7 +3175,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) hw->hs_phy_type); dev_dbg(hsotg->dev, " fs_phy_type=%d\n", hw->fs_phy_type); - dev_dbg(hsotg->dev, " utmi_phy_data_wdith=%d\n", + dev_dbg(hsotg->dev, " utmi_phy_data_width=%d\n", hw->utmi_phy_data_width); dev_dbg(hsotg->dev, " num_dev_ep=%d\n", hw->num_dev_ep); diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index cf208522998e..caba848ac763 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -299,7 +299,7 @@ static int ecryptfs_write_begin(struct file *file, rc = ecryptfs_read_lower_page_segment( page, index, 0, PAGE_CACHE_SIZE, mapping->host); if (rc) { - printk(KERN_ERR "%s: Error attemping to read " + printk(KERN_ERR "%s: Error attempting to read " "lower page segment; rc = [%d]\n", __func__, rc); ClearPageUptodate(page); -- cgit v1.3-6-gb490 From b527538fe6f9506d619c09ee5f86b27d91e779e4 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Thu, 21 May 2015 22:41:10 +0900 Subject: w1: Fix typo in MODULE_DESCRIPTION in matrox_w1.c This patch fix spelling typo in matrox_w1.c Signed-off-by: Masanari Iida Acked-by: Evgeniy Polyakov Signed-off-by: Jiri Kosina --- drivers/w1/masters/matrox_w1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index d8667b0212d7..eaac8eb71a30 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c @@ -40,7 +40,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Evgeniy Polyakov "); -MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire prtocol) over VGA DDC(matrox gpio)."); +MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire protocol) over VGA DDC(matrox gpio)."); static struct pci_device_id matrox_w1_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400) }, -- cgit v1.3-6-gb490 From 60acc4ebe710a8e5c56a8488e91c8b1903289ca8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 27 May 2015 15:05:42 +0300 Subject: treewide: Fix typo compatability -> compatibility Even though 'compatability' has a dedicated entry in the Wiktionary, it's listed as 'Mispelling of compatibility'. Fix it. Signed-off-by: Laurent Pinchart Acked-by: David S. Miller Acked-by: Daniel Vetter for the atomic_helper.c Signed-off-by: Jiri Kosina --- arch/metag/include/asm/elf.h | 2 +- arch/powerpc/kvm/book3s.c | 2 +- arch/sparc/include/uapi/asm/pstate.h | 2 +- drivers/gpu/drm/drm_atomic_helper.c | 4 ++-- drivers/media/dvb-frontends/au8522_dig.c | 2 +- drivers/net/wireless/ipw2x00/ipw2100.h | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/arch/metag/include/asm/elf.h b/arch/metag/include/asm/elf.h index d2baf6961794..87b0cf1e0acb 100644 --- a/arch/metag/include/asm/elf.h +++ b/arch/metag/include/asm/elf.h @@ -11,7 +11,7 @@ #define R_METAG_RELBRANCH 4 #define R_METAG_GETSETOFF 5 -/* Backward compatability */ +/* Backward compatibility */ #define R_METAG_REG32OP1 6 #define R_METAG_REG32OP2 7 #define R_METAG_REG32OP3 8 diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 05ea8fc7f829..6d6398f4d632 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -902,7 +902,7 @@ int kvmppc_core_check_processor_compat(void) { /* * We always return 0 for book3s. We check - * for compatability while loading the HV + * for compatibility while loading the HV * or PR module */ return 0; diff --git a/arch/sparc/include/uapi/asm/pstate.h b/arch/sparc/include/uapi/asm/pstate.h index 4b6b998afd99..cf832e14aa05 100644 --- a/arch/sparc/include/uapi/asm/pstate.h +++ b/arch/sparc/include/uapi/asm/pstate.h @@ -88,7 +88,7 @@ #define VERS_MAXTL _AC(0x000000000000ff00,UL) /* Max Trap Level. */ #define VERS_MAXWIN _AC(0x000000000000001f,UL) /* Max RegWindow Idx.*/ -/* Compatability Feature Register (%asr26), SPARC-T4 and later */ +/* Compatibility Feature Register (%asr26), SPARC-T4 and later */ #define CFR_AES _AC(0x0000000000000001,UL) /* Supports AES opcodes */ #define CFR_DES _AC(0x0000000000000002,UL) /* Supports DES opcodes */ #define CFR_KASUMI _AC(0x0000000000000004,UL) /* Supports KASUMI opcodes */ diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index aac212297b49..a420c6602df8 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -744,7 +744,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) * This function shuts down all the outputs that need to be shut down and * prepares them (if required) with the new mode. * - * For compatability with legacy crtc helpers this should be called before + * For compatibility with legacy crtc helpers this should be called before * drm_atomic_helper_commit_planes(), which is what the default commit function * does. But drivers with different needs can group the modeset commits together * and do the plane commits at the end. This is useful for drivers doing runtime @@ -769,7 +769,7 @@ EXPORT_SYMBOL(drm_atomic_helper_commit_modeset_disables); * This function enables all the outputs with the new configuration which had to * be turned off for the update. * - * For compatability with legacy crtc helpers this should be called after + * For compatibility with legacy crtc helpers this should be called after * drm_atomic_helper_commit_planes(), which is what the default commit function * does. But drivers with different needs can group the modeset commits together * and do the plane commits at the end. This is useful for drivers doing runtime diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c index b744a3f8d467..f956f13fb3dc 100644 --- a/drivers/media/dvb-frontends/au8522_dig.c +++ b/drivers/media/dvb-frontends/au8522_dig.c @@ -922,7 +922,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Enable verbose debug messages"); module_param(zv_mode, int, 0644); -MODULE_PARM_DESC(zv_mode, "Turn on/off ZeeVee modulator compatability mode (default:on).\n" +MODULE_PARM_DESC(zv_mode, "Turn on/off ZeeVee modulator compatibility mode (default:on).\n" "\t\ton - modified AU8522 QAM256 initialization.\n" "\t\tProvides faster lock when using ZeeVee modulator based sources"); diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h index c6d78790cb0d..193947865efd 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/ipw2x00/ipw2100.h @@ -746,7 +746,7 @@ struct ipw2100_priv { #define IPW_REG_GPIO IPW_REG_DOMAIN_0_OFFSET + 0x0030 #define IPW_REG_FW_TYPE IPW_REG_DOMAIN_1_OFFSET + 0x0188 #define IPW_REG_FW_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x018C -#define IPW_REG_FW_COMPATABILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190 +#define IPW_REG_FW_COMPATIBILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190 #define IPW_REG_INDIRECT_ADDR_MASK 0x00FFFFFC -- cgit v1.3-6-gb490 From 7cd71c3ba166913a0afb8ac0d6bd5d2730fea6df Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 7 Aug 2015 13:00:35 +0100 Subject: regulator: core: Drop regulator_list_mutex when we're done with it on remove When removing a regulator we hold regulator_list_mutex in order to ensure the regualtor doesn't become removed again. However we only need to protect the list until we remove the regulator from the list so move the unlock earlier to reduce the locked region. Signed-off-by: Mark Brown --- drivers/regulator/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 68b616580533..62e4f3bd5783 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3827,11 +3827,11 @@ void regulator_unregister(struct regulator_dev *rdev) WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); list_del(&rdev->list); + mutex_unlock(®ulator_list_mutex); kfree(rdev->constraints); regulator_ena_gpio_free(rdev); of_node_put(rdev->dev.of_node); device_unregister(&rdev->dev); - mutex_unlock(®ulator_list_mutex); } EXPORT_SYMBOL_GPL(regulator_unregister); -- cgit v1.3-6-gb490 From 1066c48281d0401cafff58e7eff1820936eef489 Mon Sep 17 00:00:00 2001 From: Diego Viola Date: Sun, 31 May 2015 15:52:41 -0300 Subject: drivers/usb/gadget/composite.c: i18n is not an acronym Signed-off-by: Diego Viola Signed-off-by: Jiri Kosina --- drivers/usb/gadget/composite.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 58b4657fc721..9ff3203b50e2 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -896,7 +896,7 @@ void usb_remove_config(struct usb_composite_dev *cdev, /* We support strings in multiple languages ... string descriptor zero * says which languages are supported. The typical case will be that - * only one language (probably English) is used, with I18N handled on + * only one language (probably English) is used, with i18n handled on * the host side. */ @@ -949,7 +949,7 @@ static int get_string(struct usb_composite_dev *cdev, struct usb_function *f; int len; - /* Yes, not only is USB's I18N support probably more than most + /* Yes, not only is USB's i18n support probably more than most * folk will ever care about ... also, it's all supported here. * (Except for UTF8 support for Unicode's "Astral Planes".) */ -- cgit v1.3-6-gb490 From bd0a1d6c10a43280a85f7283351623d16e21d9fc Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Thu, 4 Jun 2015 00:54:34 +0900 Subject: scsi:fcoe: Fix typo "a ethernet" in fcoe_transport.c This patch fix some "a ethernet" in MODULE_DESCRIPTIONS in fcoe_transport.c Signed-off-by: Masanari Iida Acked-by: Vasu Dev Signed-off-by: Jiri Kosina --- drivers/scsi/fcoe/fcoe_transport.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index bdc89899561a..d7597c08fa11 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -58,7 +58,7 @@ MODULE_PARM_DESC(show, " Show attached FCoE transports"); module_param_call(create, fcoe_transport_create, NULL, (void *)FIP_MODE_FABRIC, S_IWUSR); __MODULE_PARM_TYPE(create, "string"); -MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface"); +MODULE_PARM_DESC(create, " Creates fcoe instance on an ethernet interface"); module_param_call(create_vn2vn, fcoe_transport_create, NULL, (void *)FIP_MODE_VN2VN, S_IWUSR); @@ -68,15 +68,15 @@ MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance " module_param_call(destroy, fcoe_transport_destroy, NULL, NULL, S_IWUSR); __MODULE_PARM_TYPE(destroy, "string"); -MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface"); +MODULE_PARM_DESC(destroy, " Destroys fcoe instance on an ethernet interface"); module_param_call(enable, fcoe_transport_enable, NULL, NULL, S_IWUSR); __MODULE_PARM_TYPE(enable, "string"); -MODULE_PARM_DESC(enable, " Enables fcoe on a ethernet interface."); +MODULE_PARM_DESC(enable, " Enables fcoe on an ethernet interface."); module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR); __MODULE_PARM_TYPE(disable, "string"); -MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface."); +MODULE_PARM_DESC(disable, " Disables fcoe on an ethernet interface."); /* notification function for packets from net device */ static struct notifier_block libfcoe_notifier = { -- cgit v1.3-6-gb490 From 839b47bca58ac67657c7afea363ede72c1a2480c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 6 Jul 2015 15:41:18 +0200 Subject: staging: comedi: Grammar s/Enable support a/Enable support for a/ Signed-off-by: Geert Uytterhoeven Reviewed-by: Ian Abbott Signed-off-by: Jiri Kosina --- drivers/staging/comedi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 7dee73dfbf88..57e71f9f14a2 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -2,7 +2,7 @@ config COMEDI tristate "Data acquisition support (comedi)" depends on m ---help--- - Enable support a wide range of data acquisition devices + Enable support for a wide range of data acquisition devices for Linux. if COMEDI -- cgit v1.3-6-gb490 From 804ff603d2fe98c48aac4e2d6e4f5db687d78812 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Thu, 7 May 2015 23:21:27 +0900 Subject: [SCSI] Fix printk typos in drivers/scsi This patch fix spme spelling typos in printk within drivers/scsi. Signed-off-by: Masanari Iida Signed-off-by: Jiri Kosina --- drivers/scsi/53c700.c | 2 +- drivers/scsi/scsi_transport_iscsi.c | 2 +- drivers/scsi/scsi_transport_spi.c | 4 ++-- drivers/scsi/wd719x.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 82abfce1cb42..a209c3418898 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -299,7 +299,7 @@ NCR_700_detect(struct scsi_host_template *tpnt, memory = dma_alloc_noncoherent(hostdata->dev, TOTAL_MEM_SIZE, &pScript, GFP_KERNEL); if(memory == NULL) { - printk(KERN_ERR "53c700: Failed to allocate memory for driver, detatching\n"); + printk(KERN_ERR "53c700: Failed to allocate memory for driver, detaching\n"); return NULL; } diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 55647aae065c..da73d5524602 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -3037,7 +3037,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh) shost = scsi_host_lookup(ev->u.get_chap.host_no); if (!shost) { - printk(KERN_ERR "%s: failed. Cound not find host no %u\n", + printk(KERN_ERR "%s: failed. Could not find host no %u\n", __func__, ev->u.get_chap.host_no); return -ENODEV; } diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 31bbb0da3397..319868f3f674 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -786,10 +786,10 @@ spi_dv_retrain(struct scsi_device *sdev, u8 *buffer, u8 *ptr, * IU, then QAS (if we can control them), then finally * fall down the periods */ if (i->f->set_iu && spi_iu(starget)) { - starget_printk(KERN_ERR, starget, "Domain Validation Disabing Information Units\n"); + starget_printk(KERN_ERR, starget, "Domain Validation Disabling Information Units\n"); DV_SET(iu, 0); } else if (i->f->set_qas && spi_qas(starget)) { - starget_printk(KERN_ERR, starget, "Domain Validation Disabing Quick Arbitration and Selection\n"); + starget_printk(KERN_ERR, starget, "Domain Validation Disabling Quick Arbitration and Selection\n"); DV_SET(qas, 0); } else { newperiod = spi_period(starget); diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index 61346aa73178..e3da1a2fdb66 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -590,7 +590,7 @@ static inline void wd719x_interrupt_SCB(struct wd719x *wd, dev_dbg(&wd->pdev->dev, "selection timeout\n"); break; case WD719X_SUE_RESET: - dev_dbg(&wd->pdev->dev, "bus reset occured\n"); + dev_dbg(&wd->pdev->dev, "bus reset occurred\n"); result = DID_RESET; break; case WD719X_SUE_BUSERROR: -- cgit v1.3-6-gb490 From 4bb138a47b7f8a2867dd3ec1f897a07323598345 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Sun, 10 May 2015 00:55:18 +0900 Subject: drm/nouveau/gr: Fix typo in nv10.c This patch fix spelling typo in printk within nv10.c Signed-off-by: Masanari Iida Signed-off-by: Jiri Kosina --- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 389904eb603f..d6ace41830e9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -845,7 +845,7 @@ nv10_gr_ctx_regs_find_offset(struct nv10_gr_priv *priv, int reg) if (nv10_gr_ctx_regs[i] == reg) return i; } - nv_error(priv, "unknow offset nv10_ctx_regs %d\n", reg); + nv_error(priv, "unknown offset nv10_ctx_regs %d\n", reg); return -1; } @@ -857,7 +857,7 @@ nv17_gr_ctx_regs_find_offset(struct nv10_gr_priv *priv, int reg) if (nv17_gr_ctx_regs[i] == reg) return i; } - nv_error(priv, "unknow offset nv17_ctx_regs %d\n", reg); + nv_error(priv, "unknown offset nv17_ctx_regs %d\n", reg); return -1; } -- cgit v1.3-6-gb490 From 47268a4f9d179020cff766848086318a9e90d013 Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Tue, 30 Jun 2015 17:25:27 -0400 Subject: scsi/arcmsr: Fix typos in error log This fixes some typos in one of the error logs. Signed-off-by: Nik Nyby Signed-off-by: Jiri Kosina --- drivers/scsi/arcmsr/arcmsr_hba.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 914c39f9f388..6ac74fb4ea9a 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -3264,7 +3264,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) reg->doneq_index = 0; writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell); if (!arcmsr_hbaB_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \ + printk(KERN_NOTICE "arcmsr%d: cannot set driver mode\n", \ acb->host->host_no); return 1; } -- cgit v1.3-6-gb490 From 1635e88885a8e16dec21206c981421f1f3c3b1df Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 6 Aug 2015 10:35:23 +0800 Subject: regmap: debugfs: Fix misuse of IS_ENABLED IS_ENABLED should only be used for CONFIG_* symbols. I have done a small test: #define REGMAP_ALLOW_WRITE_DEBUGFS IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS) returns 0. #define REGMAP_ALLOW_WRITE_DEBUGFS 0 IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS) returns 0. #define REGMAP_ALLOW_WRITE_DEBUGFS 1 IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS) returns 1. #define REGMAP_ALLOW_WRITE_DEBUGFS 2 IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS) returns 0. So fix the misuse of IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS) and switch to use #if defined(REGMAP_ALLOW_WRITE_DEBUGFS) instead. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-debugfs.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 6a61e4fa73a2..f42f2bac6466 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -599,10 +599,11 @@ void regmap_debugfs_init(struct regmap *map, const char *name) if (map->max_register || regmap_readable(map, 0)) { umode_t registers_mode; - if (IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS)) - registers_mode = 0600; - else - registers_mode = 0400; +#if defined(REGMAP_ALLOW_WRITE_DEBUGFS) + registers_mode = 0600; +#else + registers_mode = 0400; +#endif debugfs_create_file("registers", registers_mode, map->debugfs, map, ®map_map_fops); -- cgit v1.3-6-gb490 From 5f367f0288c44c706ed4b2622aee451498fb3ab3 Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 6 Jul 2015 10:59:48 -0400 Subject: aic7xxx: Fix typo in error message This fixes "referenced" where it is spelled "referrenced". Signed-off-by: Nik Nyby Signed-off-by: Jiri Kosina --- drivers/scsi/aic7xxx/aic7xxx_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index c4829d84b335..64ab9eaec428 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -79,7 +79,7 @@ struct ahc_hard_error_entry { static const struct ahc_hard_error_entry ahc_hard_errors[] = { { ILLHADDR, "Illegal Host Access" }, - { ILLSADDR, "Illegal Sequencer Address referrenced" }, + { ILLSADDR, "Illegal Sequencer Address referenced" }, { ILLOPCODE, "Illegal Opcode in sequencer program" }, { SQPARERR, "Sequencer Parity Error" }, { DPARERR, "Data-path Parity Error" }, -- cgit v1.3-6-gb490 From 57d4248731f6ff7502ead0fedb6ad35c90dead31 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 6 Jul 2015 15:39:17 +0200 Subject: dm: Spelling s/consitent/consistent/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Jiri Kosina --- drivers/md/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index bfec3bdfe598..d5415eedba86 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -478,7 +478,7 @@ config DM_LOG_WRITES This device-mapper target takes two devices, one device to use normally, one to log all write operations done to the first device. This is for use by file system developers wishing to verify that - their fs is writing a consitent file system at all times by allowing + their fs is writing a consistent file system at all times by allowing them to replay the log in a variety of ways and to check the contents. -- cgit v1.3-6-gb490 From e1c05067c323fb92d27418fb3586171bd7ce2e12 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 7 Jul 2015 10:14:59 +0900 Subject: treewide: fix typos in comment blocks Looks like the word "contiguous" is often mistyped. Signed-off-by: Masahiro Yamada Signed-off-by: Jiri Kosina --- arch/mips/kernel/setup.c | 2 +- drivers/gpio/gpiolib-acpi.c | 2 +- drivers/gpu/drm/via/via_dmablit.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_drv.h | 2 +- drivers/media/platform/exynos4-is/fimc-m2m.c | 2 +- drivers/media/v4l2-core/videobuf2-memops.c | 2 +- drivers/net/ethernet/amd/xgbe/xgbe.h | 2 +- drivers/net/wireless/ath/ath6kl/wmi.c | 4 ++-- drivers/usb/gadget/udc/bdc/bdc.h | 2 +- fs/ocfs2/ocfs2_fs.h | 4 ++-- include/media/videobuf-core.h | 2 +- mm/nommu.c | 10 +++++----- 12 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 008b3378653a..35b8316002f8 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -476,7 +476,7 @@ static void __init bootmem_init(void) * o bootmem_init() * o sparse_init() * o paging_init() - * o dma_continguous_reserve() + * o dma_contiguous_reserve() * * At this stage the bootmem allocator is ready to use. * diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 533fe5dbe6f8..143a9bdbaa53 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -68,7 +68,7 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) * GPIO controller driver. * * Typically the returned offset is same as @pin, but if the GPIO - * controller uses pin controller and the mapping is not contigous the + * controller uses pin controller and the mapping is not contiguous the * offset might be different. */ static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, int pin) diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c index ba33cf679180..d0cbd5ecd7f0 100644 --- a/drivers/gpu/drm/via/via_dmablit.c +++ b/drivers/gpu/drm/via/via_dmablit.c @@ -260,7 +260,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) /* * Allocate DMA capable memory for the blit descriptor chain, and an array that keeps track of the * pages we allocate. We don't want to use kmalloc for the descriptor chain because it may be - * quite large for some blits, and pages don't need to be contingous. + * quite large for some blits, and pages don't need to be contiguous. */ static int diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index d26a6daa9719..0336d49e3d4c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -227,7 +227,7 @@ enum vmw_dma_map_mode { * device-specific information. * * @sgt: Pointer to a struct sg_table with binding information - * @num_regions: Number of regions with device-address contigous pages + * @num_regions: Number of regions with device-address contiguous pages */ struct vmw_sg_table { enum vmw_dma_map_mode mode; diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 0ad1b6f84a27..d2bfe7c2a6b4 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -188,7 +188,7 @@ static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, if (IS_ERR(f)) return PTR_ERR(f); /* - * Return number of non-contigous planes (plane buffers) + * Return number of non-contiguous planes (plane buffers) * depending on the configured color format. */ if (!f->fmt) diff --git a/drivers/media/v4l2-core/videobuf2-memops.c b/drivers/media/v4l2-core/videobuf2-memops.c index 81c1ad8b2cf1..0d49b7951f84 100644 --- a/drivers/media/v4l2-core/videobuf2-memops.c +++ b/drivers/media/v4l2-core/videobuf2-memops.c @@ -125,7 +125,7 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, } /* - * Memory is contigous, lock vma and return to the caller + * Memory is contiguous, lock vma and return to the caller */ *res_vma = vb2_get_vma(vma); if (*res_vma == NULL) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index 717ce21b6077..8c9d01ef730d 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -140,7 +140,7 @@ #define XGBE_TX_MAX_BUF_SIZE (0x3fff & ~(64 - 1)) -/* Descriptors required for maximum contigous TSO/GSO packet */ +/* Descriptors required for maximum contiguous TSO/GSO packet */ #define XGBE_TX_MAX_SPLIT ((GSO_MAX_SIZE / XGBE_TX_MAX_BUF_SIZE) + 1) /* Maximum possible descriptors needed for an SKB: diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index b921005ad7ee..a5e1de75a4a3 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -154,7 +154,7 @@ struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx) } /* Performs DIX to 802.3 encapsulation for transmit packets. - * Assumes the entire DIX header is contigous and that there is + * Assumes the entire DIX header is contiguous and that there is * enough room in the buffer for a 802.3 mac header and LLC+SNAP headers. */ int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb) @@ -449,7 +449,7 @@ int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb) /* * Performs 802.3 to DIX encapsulation for received packets. - * Assumes the entire 802.3 header is contigous. + * Assumes the entire 802.3 header is contiguous. */ int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb) { diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h index dc18a20bf040..916d47135cac 100644 --- a/drivers/usb/gadget/udc/bdc/bdc.h +++ b/drivers/usb/gadget/udc/bdc/bdc.h @@ -290,7 +290,7 @@ struct bdc_sr { __le32 offset[4]; }; -/* bd_table: contigous bd's in a table */ +/* bd_table: contiguous bd's in a table */ struct bd_table { struct bdc_bd *start_bd; /* dma address of start bd of table*/ diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index db64ce2d4667..540ab5b75dbb 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h @@ -168,7 +168,7 @@ /* Refcount tree support */ #define OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE 0x1000 -/* Discontigous block groups */ +/* Discontiguous block groups */ #define OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG 0x2000 /* @@ -939,7 +939,7 @@ struct ocfs2_group_desc /* * Block groups may be discontiguous when * OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG is set. - * The extents of a discontigous block group are + * The extents of a discontiguous block group are * stored in bg_list. It is a flat list. * l_tree_depth must always be zero. A * discontiguous group is signified by a non-zero diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 8c6e825940e5..d760aa73ebbb 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -37,7 +37,7 @@ struct videobuf_queue; * * about the mmap helpers (videobuf_mmap_*): * - * The mmaper function allows to map any subset of contingous buffers. + * The mmaper function allows to map any subset of contiguous buffers. * This includes one mmap() call for all buffers (which the original * video4linux API uses) as well as one mmap() for every single buffer * (which v4l2 uses). diff --git a/mm/nommu.c b/mm/nommu.c index 58ea3643b9e9..0b34f4033cb6 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -324,12 +324,12 @@ long vwrite(char *buf, char *addr, unsigned long count) } /* - * vmalloc - allocate virtually continguos memory + * vmalloc - allocate virtually contiguous memory * * @size: allocation size * * Allocate enough pages to cover @size from the page level - * allocator and map them into continguos kernel virtual space. + * allocator and map them into contiguous kernel virtual space. * * For tight control over page level allocator and protection flags * use __vmalloc() instead. @@ -341,12 +341,12 @@ void *vmalloc(unsigned long size) EXPORT_SYMBOL(vmalloc); /* - * vzalloc - allocate virtually continguos memory with zero fill + * vzalloc - allocate virtually contiguous memory with zero fill * * @size: allocation size * * Allocate enough pages to cover @size from the page level - * allocator and map them into continguos kernel virtual space. + * allocator and map them into contiguous kernel virtual space. * The memory allocated is set to zero. * * For tight control over page level allocator and protection flags @@ -420,7 +420,7 @@ void *vmalloc_exec(unsigned long size) * @size: allocation size * * Allocate enough 32bit PA addressable pages to cover @size from the - * page level allocator and map them into continguos kernel virtual space. + * page level allocator and map them into contiguous kernel virtual space. */ void *vmalloc_32(unsigned long size) { -- cgit v1.3-6-gb490 From e9e346a37b2bdcabc65d2537feccc3b563c1ac43 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Tue, 28 Jul 2015 20:11:23 +0900 Subject: i2c: Fix typo in i2c-bfin-twi.c This patch fix some typos found in a printk message and MODULE_DESCRIPTION. Signed-off-by: Masanari Iida Signed-off-by: Jiri Kosina --- drivers/i2c/busses/i2c-bfin-twi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index af162b4c7a6d..025686d41640 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -692,7 +692,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, iface); - dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, " + dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Controller, " "regs_base@%p\n", iface->regs_base); return 0; @@ -735,6 +735,6 @@ subsys_initcall(i2c_bfin_twi_init); module_exit(i2c_bfin_twi_exit); MODULE_AUTHOR("Bryan Wu, Sonic Zhang"); -MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver"); +MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Controller Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:i2c-bfin-twi"); -- cgit v1.3-6-gb490 From d23684d2738f1c4492d221b37eaee0028df93328 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 29 Jul 2015 19:19:45 +0100 Subject: scsi: a100u2w: trivial typo in printk Trivial typo fix, \b should be \n Signed-off-by: Colin Ian King Reviewed-by: Hannes Reinecke Signed-off-by: Jiri Kosina --- drivers/scsi/a100u2w.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index cac6b37d7b1b..8086bd0ac9fd 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -888,7 +888,7 @@ static int inia100_build_scb(struct orc_host * host, struct orc_scb * scb, struc scb->sense_len = SENSE_SIZE; scb->cdb_len = cmd->cmd_len; if (scb->cdb_len >= IMAX_CDB) { - printk("max cdb length= %x\b", cmd->cmd_len); + printk("max cdb length= %x\n", cmd->cmd_len); scb->cdb_len = IMAX_CDB; } scb->ident = (u8)(cmd->device->lun & 0xff) | DISC_ALLOW; -- cgit v1.3-6-gb490 From a568231f463225eb31593f71446a267a03ae0528 Mon Sep 17 00:00:00 2001 From: Leilk Liu Date: Fri, 7 Aug 2015 15:19:50 +0800 Subject: spi: mediatek: Add spi bus for Mediatek MT8173 This patch adds basic spi bus for MT8173. Signed-off-by: Leilk Liu Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 9 + drivers/spi/Makefile | 1 + drivers/spi/spi-mt65xx.c | 749 +++++++++++++++++++++++++++++++ include/linux/platform_data/spi-mt65xx.h | 22 + 4 files changed, 781 insertions(+) create mode 100644 drivers/spi/spi-mt65xx.c create mode 100644 include/linux/platform_data/spi-mt65xx.h (limited to 'drivers') diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 0cae1694014d..38ddfba49d76 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -326,6 +326,15 @@ config SPI_MESON_SPIFC This enables master mode support for the SPIFC (SPI flash controller) available in Amlogic Meson SoCs. +config SPI_MT65XX + tristate "MediaTek SPI controller" + depends on ARCH_MEDIATEK || COMPILE_TEST + help + This selects the MediaTek(R) SPI bus driver. + If you want to use MediaTek(R) SPI interface, + say Y or M here.If you are not sure, say N. + SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs. + config SPI_OC_TINY tristate "OpenCores tiny SPI" depends on GPIOLIB || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 1154dbac8f2c..9746beb21769 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o +obj-$(CONFIG_SPI_MT65XX) += spi-mt65xx.o obj-$(CONFIG_SPI_MXS) += spi-mxs.o obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c new file mode 100644 index 000000000000..4676b0122b89 --- /dev/null +++ b/drivers/spi/spi-mt65xx.c @@ -0,0 +1,749 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: Leilk Liu + * + * 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 +#include +#include +#include +#include +#include + +#define SPI_CFG0_REG 0x0000 +#define SPI_CFG1_REG 0x0004 +#define SPI_TX_SRC_REG 0x0008 +#define SPI_RX_DST_REG 0x000c +#define SPI_TX_DATA_REG 0x0010 +#define SPI_RX_DATA_REG 0x0014 +#define SPI_CMD_REG 0x0018 +#define SPI_STATUS0_REG 0x001c +#define SPI_PAD_SEL_REG 0x0024 + +#define SPI_CFG0_SCK_HIGH_OFFSET 0 +#define SPI_CFG0_SCK_LOW_OFFSET 8 +#define SPI_CFG0_CS_HOLD_OFFSET 16 +#define SPI_CFG0_CS_SETUP_OFFSET 24 + +#define SPI_CFG1_CS_IDLE_OFFSET 0 +#define SPI_CFG1_PACKET_LOOP_OFFSET 8 +#define SPI_CFG1_PACKET_LENGTH_OFFSET 16 +#define SPI_CFG1_GET_TICK_DLY_OFFSET 30 + +#define SPI_CFG1_CS_IDLE_MASK 0xff +#define SPI_CFG1_PACKET_LOOP_MASK 0xff00 +#define SPI_CFG1_PACKET_LENGTH_MASK 0x3ff0000 + +#define SPI_CMD_ACT_OFFSET 0 +#define SPI_CMD_RESUME_OFFSET 1 +#define SPI_CMD_CPHA_OFFSET 8 +#define SPI_CMD_CPOL_OFFSET 9 +#define SPI_CMD_TXMSBF_OFFSET 12 +#define SPI_CMD_RXMSBF_OFFSET 13 +#define SPI_CMD_RX_ENDIAN_OFFSET 14 +#define SPI_CMD_TX_ENDIAN_OFFSET 15 + +#define SPI_CMD_RST BIT(2) +#define SPI_CMD_PAUSE_EN BIT(4) +#define SPI_CMD_DEASSERT BIT(5) +#define SPI_CMD_CPHA BIT(8) +#define SPI_CMD_CPOL BIT(9) +#define SPI_CMD_RX_DMA BIT(10) +#define SPI_CMD_TX_DMA BIT(11) +#define SPI_CMD_TXMSBF BIT(12) +#define SPI_CMD_RXMSBF BIT(13) +#define SPI_CMD_RX_ENDIAN BIT(14) +#define SPI_CMD_TX_ENDIAN BIT(15) +#define SPI_CMD_FINISH_IE BIT(16) +#define SPI_CMD_PAUSE_IE BIT(17) + +#define MTK_SPI_QUIRK_PAD_SELECT 1 +/* Must explicitly send dummy Tx bytes to do Rx only transfer */ +#define MTK_SPI_QUIRK_MUST_TX 1 + +#define MT8173_SPI_MAX_PAD_SEL 3 + +#define MTK_SPI_IDLE 0 +#define MTK_SPI_PAUSED 1 + +#define MTK_SPI_MAX_FIFO_SIZE 32 +#define MTK_SPI_PACKET_SIZE 1024 + +struct mtk_spi_compatible { + u32 need_pad_sel; + u32 must_tx; +}; + +struct mtk_spi { + void __iomem *base; + u32 state; + u32 pad_sel; + struct clk *spi_clk, *parent_clk; + struct spi_transfer *cur_transfer; + u32 xfer_len; + struct scatterlist *tx_sgl, *rx_sgl; + u32 tx_sgl_len, rx_sgl_len; + const struct mtk_spi_compatible *dev_comp; +}; + +static const struct mtk_spi_compatible mt6589_compat = { + .need_pad_sel = 0, + .must_tx = 0, +}; + +static const struct mtk_spi_compatible mt8135_compat = { + .need_pad_sel = 0, + .must_tx = 0, +}; + +static const struct mtk_spi_compatible mt8173_compat = { + .need_pad_sel = MTK_SPI_QUIRK_PAD_SELECT, + .must_tx = MTK_SPI_QUIRK_MUST_TX, +}; + +/* + * A piece of default chip info unless the platform + * supplies it. + */ +static const struct mtk_chip_config mtk_default_chip_info = { + .rx_mlsb = 1, + .tx_mlsb = 1, + .tx_endian = 0, + .rx_endian = 0, +}; + +static const struct of_device_id mtk_spi_of_match[] = { + { .compatible = "mediatek,mt6589-spi", .data = (void *)&mt6589_compat }, + { .compatible = "mediatek,mt8135-spi", .data = (void *)&mt8135_compat }, + { .compatible = "mediatek,mt8173-spi", .data = (void *)&mt8173_compat }, + {} +}; +MODULE_DEVICE_TABLE(of, mtk_spi_of_match); + +static void mtk_spi_reset(struct mtk_spi *mdata) +{ + u32 reg_val; + + /* set the software reset bit in SPI_CMD_REG. */ + reg_val = readl(mdata->base + SPI_CMD_REG); + reg_val |= SPI_CMD_RST; + writel(reg_val, mdata->base + SPI_CMD_REG); + + reg_val = readl(mdata->base + SPI_CMD_REG); + reg_val &= ~SPI_CMD_RST; + writel(reg_val, mdata->base + SPI_CMD_REG); +} + +static void mtk_spi_config(struct mtk_spi *mdata, + struct mtk_chip_config *chip_config) +{ + u32 reg_val; + + reg_val = readl(mdata->base + SPI_CMD_REG); + + /* set the mlsbx and mlsbtx */ + reg_val &= ~(SPI_CMD_TXMSBF | SPI_CMD_RXMSBF); + reg_val |= (chip_config->tx_mlsb << SPI_CMD_TXMSBF_OFFSET); + reg_val |= (chip_config->rx_mlsb << SPI_CMD_RXMSBF_OFFSET); + + /* set the tx/rx endian */ + reg_val &= ~(SPI_CMD_TX_ENDIAN | SPI_CMD_RX_ENDIAN); + reg_val |= (chip_config->tx_endian << SPI_CMD_TX_ENDIAN_OFFSET); + reg_val |= (chip_config->rx_endian << SPI_CMD_RX_ENDIAN_OFFSET); + + /* set finish and pause interrupt always enable */ + reg_val |= SPI_CMD_FINISH_IE | SPI_CMD_PAUSE_EN; + + /* disable dma mode */ + reg_val &= ~(SPI_CMD_TX_DMA | SPI_CMD_RX_DMA); + + /* disable deassert mode */ + reg_val &= ~SPI_CMD_DEASSERT; + + writel(reg_val, mdata->base + SPI_CMD_REG); + + /* pad select */ + if (mdata->dev_comp->need_pad_sel) + writel(mdata->pad_sel, mdata->base + SPI_PAD_SEL_REG); +} + +static int mtk_spi_prepare_hardware(struct spi_master *master) +{ + struct spi_transfer *trans; + struct mtk_spi *mdata = spi_master_get_devdata(master); + struct spi_message *msg = master->cur_msg; + int ret; + + ret = clk_prepare_enable(mdata->spi_clk); + if (ret < 0) { + dev_err(&master->dev, "failed to enable clock (%d)\n", ret); + return ret; + } + + trans = list_first_entry(&msg->transfers, struct spi_transfer, + transfer_list); + if (trans->cs_change == 0) { + mdata->state = MTK_SPI_IDLE; + mtk_spi_reset(mdata); + } + + return ret; +} + +static int mtk_spi_unprepare_hardware(struct spi_master *master) +{ + struct mtk_spi *mdata = spi_master_get_devdata(master); + + clk_disable_unprepare(mdata->spi_clk); + + return 0; +} + +static int mtk_spi_prepare_message(struct spi_master *master, + struct spi_message *msg) +{ + u32 reg_val; + u8 cpha, cpol; + struct mtk_chip_config *chip_config; + struct spi_device *spi = msg->spi; + struct mtk_spi *mdata = spi_master_get_devdata(master); + + cpha = spi->mode & SPI_CPHA ? 1 : 0; + cpol = spi->mode & SPI_CPOL ? 1 : 0; + + reg_val = readl(mdata->base + SPI_CMD_REG); + reg_val &= ~(SPI_CMD_CPHA | SPI_CMD_CPOL); + reg_val |= (cpha << SPI_CMD_CPHA_OFFSET); + reg_val |= (cpol << SPI_CMD_CPOL_OFFSET); + writel(reg_val, mdata->base + SPI_CMD_REG); + + chip_config = spi->controller_data; + if (!chip_config) { + chip_config = (void *)&mtk_default_chip_info; + spi->controller_data = chip_config; + } + mtk_spi_config(mdata, chip_config); + + return 0; +} + +static void mtk_spi_set_cs(struct spi_device *spi, bool enable) +{ + u32 reg_val; + struct mtk_spi *mdata = spi_master_get_devdata(spi->master); + + reg_val = readl(mdata->base + SPI_CMD_REG); + if (!enable) + reg_val |= SPI_CMD_PAUSE_EN; + else + reg_val &= ~SPI_CMD_PAUSE_EN; + writel(reg_val, mdata->base + SPI_CMD_REG); +} + +static void mtk_spi_prepare_transfer(struct spi_master *master, + struct spi_transfer *xfer) +{ + u32 spi_clk_hz, div, high_time, low_time, holdtime, + setuptime, cs_idletime, reg_val = 0; + struct mtk_spi *mdata = spi_master_get_devdata(master); + + spi_clk_hz = clk_get_rate(mdata->spi_clk); + if (xfer->speed_hz < spi_clk_hz / 2) + div = DIV_ROUND_UP(spi_clk_hz, xfer->speed_hz); + else + div = 1; + + high_time = (div + 1) / 2; + low_time = (div + 1) / 2; + holdtime = (div + 1) / 2 * 2; + setuptime = (div + 1) / 2 * 2; + cs_idletime = (div + 1) / 2 * 2; + + reg_val |= (((high_time - 1) & 0xff) << SPI_CFG0_SCK_HIGH_OFFSET); + reg_val |= (((low_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET); + reg_val |= (((holdtime - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET); + reg_val |= (((setuptime - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET); + writel(reg_val, mdata->base + SPI_CFG0_REG); + + reg_val = readl(mdata->base + SPI_CFG1_REG); + reg_val &= ~SPI_CFG1_CS_IDLE_MASK; + reg_val |= (((cs_idletime - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET); + writel(reg_val, mdata->base + SPI_CFG1_REG); +} + +static void mtk_spi_setup_packet(struct spi_master *master) +{ + u32 packet_size, packet_loop, reg_val; + struct mtk_spi *mdata = spi_master_get_devdata(master); + + packet_size = min_t(unsigned, mdata->xfer_len, MTK_SPI_PACKET_SIZE); + packet_loop = mdata->xfer_len / packet_size; + + reg_val = readl(mdata->base + SPI_CFG1_REG); + reg_val &= ~(SPI_CFG1_PACKET_LENGTH_MASK + SPI_CFG1_PACKET_LOOP_MASK); + reg_val |= (packet_size - 1) << SPI_CFG1_PACKET_LENGTH_OFFSET; + reg_val |= (packet_loop - 1) << SPI_CFG1_PACKET_LOOP_OFFSET; + writel(reg_val, mdata->base + SPI_CFG1_REG); +} + +static void mtk_spi_enable_transfer(struct spi_master *master) +{ + int cmd; + struct mtk_spi *mdata = spi_master_get_devdata(master); + + cmd = readl(mdata->base + SPI_CMD_REG); + if (mdata->state == MTK_SPI_IDLE) + cmd |= 1 << SPI_CMD_ACT_OFFSET; + else + cmd |= 1 << SPI_CMD_RESUME_OFFSET; + writel(cmd, mdata->base + SPI_CMD_REG); +} + +static int mtk_spi_get_mult_delta(int xfer_len) +{ + int mult_delta; + + if (xfer_len > MTK_SPI_PACKET_SIZE) + mult_delta = xfer_len % MTK_SPI_PACKET_SIZE; + else + mult_delta = 0; + + return mult_delta; +} + +static void mtk_spi_update_mdata_len(struct spi_master *master) +{ + int mult_delta; + struct mtk_spi *mdata = spi_master_get_devdata(master); + + if (mdata->tx_sgl_len && mdata->rx_sgl_len) { + if (mdata->tx_sgl_len > mdata->rx_sgl_len) { + mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len); + mdata->xfer_len = mdata->rx_sgl_len - mult_delta; + mdata->rx_sgl_len = mult_delta; + mdata->tx_sgl_len -= mdata->xfer_len; + } else { + mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len); + mdata->xfer_len = mdata->tx_sgl_len - mult_delta; + mdata->tx_sgl_len = mult_delta; + mdata->rx_sgl_len -= mdata->xfer_len; + } + } else if (mdata->tx_sgl_len) { + mult_delta = mtk_spi_get_mult_delta(mdata->tx_sgl_len); + mdata->xfer_len = mdata->tx_sgl_len - mult_delta; + mdata->tx_sgl_len = mult_delta; + } else if (mdata->rx_sgl_len) { + mult_delta = mtk_spi_get_mult_delta(mdata->rx_sgl_len); + mdata->xfer_len = mdata->rx_sgl_len - mult_delta; + mdata->rx_sgl_len = mult_delta; + } +} + +static void mtk_spi_setup_dma_addr(struct spi_master *master, + struct spi_transfer *xfer) +{ + struct mtk_spi *mdata = spi_master_get_devdata(master); + + if (mdata->tx_sgl) + writel(cpu_to_le32(xfer->tx_dma), mdata->base + SPI_TX_SRC_REG); + if (mdata->rx_sgl) + writel(cpu_to_le32(xfer->rx_dma), mdata->base + SPI_RX_DST_REG); +} + +static int mtk_spi_fifo_transfer(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + int cnt, i; + struct mtk_spi *mdata = spi_master_get_devdata(master); + + mdata->cur_transfer = xfer; + mdata->xfer_len = xfer->len; + mtk_spi_prepare_transfer(master, xfer); + mtk_spi_setup_packet(master); + + if (xfer->len % 4) + cnt = xfer->len / 4 + 1; + else + cnt = xfer->len / 4; + + for (i = 0; i < cnt; i++) + writel(*((u32 *)xfer->tx_buf + i), + mdata->base + SPI_TX_DATA_REG); + + mtk_spi_enable_transfer(master); + + return 1; +} + +static int mtk_spi_dma_transfer(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + int cmd; + struct mtk_spi *mdata = spi_master_get_devdata(master); + + mdata->tx_sgl = NULL; + mdata->rx_sgl = NULL; + mdata->tx_sgl_len = 0; + mdata->rx_sgl_len = 0; + mdata->cur_transfer = xfer; + + mtk_spi_prepare_transfer(master, xfer); + + cmd = readl(mdata->base + SPI_CMD_REG); + if (xfer->tx_buf) + cmd |= SPI_CMD_TX_DMA; + if (xfer->rx_buf) + cmd |= SPI_CMD_RX_DMA; + writel(cmd, mdata->base + SPI_CMD_REG); + + if (xfer->tx_buf) + mdata->tx_sgl = xfer->tx_sg.sgl; + if (xfer->rx_buf) + mdata->rx_sgl = xfer->rx_sg.sgl; + + if (mdata->tx_sgl) { + xfer->tx_dma = sg_dma_address(mdata->tx_sgl); + mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl); + } + if (mdata->rx_sgl) { + xfer->rx_dma = sg_dma_address(mdata->rx_sgl); + mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl); + } + + mtk_spi_update_mdata_len(master); + mtk_spi_setup_packet(master); + mtk_spi_setup_dma_addr(master, xfer); + mtk_spi_enable_transfer(master); + + return 1; +} + +static int mtk_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + if (master->can_dma(master, spi, xfer)) + return mtk_spi_dma_transfer(master, spi, xfer); + else + return mtk_spi_fifo_transfer(master, spi, xfer); +} + +static bool mtk_spi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + return xfer->len > MTK_SPI_MAX_FIFO_SIZE; +} + +static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) +{ + u32 cmd, reg_val, i; + struct spi_master *master = dev_id; + struct mtk_spi *mdata = spi_master_get_devdata(master); + struct spi_transfer *trans = mdata->cur_transfer; + + reg_val = readl(mdata->base + SPI_STATUS0_REG); + if (reg_val & 0x2) + mdata->state = MTK_SPI_PAUSED; + else + mdata->state = MTK_SPI_IDLE; + + if (!master->can_dma(master, master->cur_msg->spi, trans)) { + /* xfer len is not N*4 bytes every time in a transfer, + * but SPI_RX_DATA_REG must reads 4 bytes once, + * so rx buffer byte by byte. + */ + if (trans->rx_buf) { + for (i = 0; i < mdata->xfer_len; i++) { + if (i % 4 == 0) + reg_val = + readl(mdata->base + SPI_RX_DATA_REG); + *((u8 *)(trans->rx_buf + i)) = + (reg_val >> ((i % 4) * 8)) & 0xff; + } + } + spi_finalize_current_transfer(master); + return IRQ_HANDLED; + } + + if (mdata->tx_sgl) + trans->tx_dma += mdata->xfer_len; + if (mdata->rx_sgl) + trans->rx_dma += mdata->xfer_len; + + if (mdata->tx_sgl && (mdata->tx_sgl_len == 0)) { + mdata->tx_sgl = sg_next(mdata->tx_sgl); + if (mdata->tx_sgl) { + trans->tx_dma = sg_dma_address(mdata->tx_sgl); + mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl); + } + } + if (mdata->rx_sgl && (mdata->rx_sgl_len == 0)) { + mdata->rx_sgl = sg_next(mdata->rx_sgl); + if (mdata->rx_sgl) { + trans->rx_dma = sg_dma_address(mdata->rx_sgl); + mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl); + } + } + + if (!mdata->tx_sgl && !mdata->rx_sgl) { + /* spi disable dma */ + cmd = readl(mdata->base + SPI_CMD_REG); + cmd &= ~SPI_CMD_TX_DMA; + cmd &= ~SPI_CMD_RX_DMA; + writel(cmd, mdata->base + SPI_CMD_REG); + + spi_finalize_current_transfer(master); + return IRQ_HANDLED; + } + + mtk_spi_update_mdata_len(master); + mtk_spi_setup_packet(master); + mtk_spi_setup_dma_addr(master, trans); + mtk_spi_enable_transfer(master); + + return IRQ_HANDLED; +} + +static int mtk_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct mtk_spi *mdata; + const struct of_device_id *of_id; + struct resource *res; + int irq, ret; + + master = spi_alloc_master(&pdev->dev, sizeof(*mdata)); + if (!master) { + dev_err(&pdev->dev, "failed to alloc spi master\n"); + return -ENOMEM; + } + + master->auto_runtime_pm = true; + master->dev.of_node = pdev->dev.of_node; + master->mode_bits = SPI_CPOL | SPI_CPHA; + + master->set_cs = mtk_spi_set_cs; + master->prepare_transfer_hardware = mtk_spi_prepare_hardware; + master->unprepare_transfer_hardware = mtk_spi_unprepare_hardware; + master->prepare_message = mtk_spi_prepare_message; + master->transfer_one = mtk_spi_transfer_one; + master->can_dma = mtk_spi_can_dma; + + of_id = of_match_node(mtk_spi_of_match, pdev->dev.of_node); + if (!of_id) { + dev_err(&pdev->dev, "failed to probe of_node\n"); + ret = -EINVAL; + goto err_put_master; + } + + mdata = spi_master_get_devdata(master); + mdata->dev_comp = of_id->data; + if (mdata->dev_comp->must_tx) + master->flags = SPI_MASTER_MUST_TX; + + if (mdata->dev_comp->need_pad_sel) { + ret = of_property_read_u32(pdev->dev.of_node, + "mediatek,pad-select", + &mdata->pad_sel); + if (ret) { + dev_err(&pdev->dev, "failed to read pad select: %d\n", + ret); + goto err_put_master; + } + + if (mdata->pad_sel > MT8173_SPI_MAX_PAD_SEL) { + dev_err(&pdev->dev, "wrong pad-select: %u\n", + mdata->pad_sel); + ret = -EINVAL; + goto err_put_master; + } + } + + platform_set_drvdata(pdev, master); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + dev_err(&pdev->dev, "failed to determine base address\n"); + goto err_put_master; + } + + mdata->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mdata->base)) { + ret = PTR_ERR(mdata->base); + goto err_put_master; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq (%d)\n", irq); + ret = irq; + goto err_put_master; + } + + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + + ret = devm_request_irq(&pdev->dev, irq, mtk_spi_interrupt, + IRQF_TRIGGER_NONE, dev_name(&pdev->dev), master); + if (ret) { + dev_err(&pdev->dev, "failed to register irq (%d)\n", ret); + goto err_put_master; + } + + mdata->spi_clk = devm_clk_get(&pdev->dev, "spi-clk"); + if (IS_ERR(mdata->spi_clk)) { + ret = PTR_ERR(mdata->spi_clk); + dev_err(&pdev->dev, "failed to get spi-clk: %d\n", ret); + goto err_put_master; + } + + mdata->parent_clk = devm_clk_get(&pdev->dev, "parent-clk"); + if (IS_ERR(mdata->parent_clk)) { + ret = PTR_ERR(mdata->parent_clk); + dev_err(&pdev->dev, "failed to get parent-clk: %d\n", ret); + goto err_put_master; + } + + ret = clk_prepare_enable(mdata->spi_clk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable spi_clk (%d)\n", ret); + goto err_put_master; + } + + ret = clk_set_parent(mdata->spi_clk, mdata->parent_clk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to clk_set_parent (%d)\n", ret); + goto err_disable_clk; + } + + clk_disable_unprepare(mdata->spi_clk); + + pm_runtime_enable(&pdev->dev); + + ret = devm_spi_register_master(&pdev->dev, master); + if (ret) { + dev_err(&pdev->dev, "failed to register master (%d)\n", ret); + goto err_put_master; + } + + return 0; + +err_disable_clk: + clk_disable_unprepare(mdata->spi_clk); +err_put_master: + spi_master_put(master); + + return ret; +} + +static int mtk_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct mtk_spi *mdata = spi_master_get_devdata(master); + + pm_runtime_disable(&pdev->dev); + + mtk_spi_reset(mdata); + clk_disable_unprepare(mdata->spi_clk); + spi_master_put(master); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mtk_spi_suspend(struct device *dev) +{ + int ret; + struct spi_master *master = dev_get_drvdata(dev); + struct mtk_spi *mdata = spi_master_get_devdata(master); + + ret = spi_master_suspend(master); + if (ret) + return ret; + + if (!pm_runtime_suspended(dev)) + clk_disable_unprepare(mdata->spi_clk); + + return ret; +} + +static int mtk_spi_resume(struct device *dev) +{ + int ret; + struct spi_master *master = dev_get_drvdata(dev); + struct mtk_spi *mdata = spi_master_get_devdata(master); + + if (!pm_runtime_suspended(dev)) { + ret = clk_prepare_enable(mdata->spi_clk); + if (ret < 0) + return ret; + } + + ret = spi_master_resume(master); + if (ret < 0) + clk_disable_unprepare(mdata->spi_clk); + + return ret; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM +static int mtk_spi_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct mtk_spi *mdata = spi_master_get_devdata(master); + + clk_disable_unprepare(mdata->spi_clk); + + return 0; +} + +static int mtk_spi_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct mtk_spi *mdata = spi_master_get_devdata(master); + + return clk_prepare_enable(mdata->spi_clk); +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops mtk_spi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(mtk_spi_suspend, mtk_spi_resume) + SET_RUNTIME_PM_OPS(mtk_spi_runtime_suspend, + mtk_spi_runtime_resume, NULL) +}; + +struct platform_driver mtk_spi_driver = { + .driver = { + .name = "mtk-spi", + .pm = &mtk_spi_pm, + .of_match_table = mtk_spi_of_match, + }, + .probe = mtk_spi_probe, + .remove = mtk_spi_remove, +}; + +module_platform_driver(mtk_spi_driver); + +MODULE_DESCRIPTION("MTK SPI Controller driver"); +MODULE_AUTHOR("Leilk Liu "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform: mtk_spi"); diff --git a/include/linux/platform_data/spi-mt65xx.h b/include/linux/platform_data/spi-mt65xx.h new file mode 100644 index 000000000000..751225569d27 --- /dev/null +++ b/include/linux/platform_data/spi-mt65xx.h @@ -0,0 +1,22 @@ +/* + * MTK SPI bus driver definitions + * + * Copyright (c) 2015 MediaTek Inc. + * Author: Leilk Liu + * + * 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 ____LINUX_PLATFORM_DATA_SPI_MTK_H +#define ____LINUX_PLATFORM_DATA_SPI_MTK_H + +/* Board specific platform_data */ +struct mtk_chip_config { + u32 tx_mlsb; + u32 rx_mlsb; + u32 tx_endian; + u32 rx_endian; +}; +#endif -- cgit v1.3-6-gb490 From bbb4d872c795ab3a1c0610f69d05fcd93aef83f6 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Wed, 8 Jul 2015 14:30:16 +0800 Subject: mfd: vexpress: Add parentheses around bridge->ops->regmap_init call regmap_init(...) is a macro since commit "regmap: Use different lockdep class for each regmap init call". That same name is used as a function pointer: prevent its expansion by adding parentheses around the function pointer. Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown --- drivers/bus/vexpress-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bus/vexpress-config.c b/drivers/bus/vexpress-config.c index a64763b6b5fd..6575c0fe6a4e 100644 --- a/drivers/bus/vexpress-config.c +++ b/drivers/bus/vexpress-config.c @@ -107,7 +107,7 @@ struct regmap *devm_regmap_init_vexpress_config(struct device *dev) if (!res) return ERR_PTR(-ENOMEM); - regmap = bridge->ops->regmap_init(dev, bridge->context); + regmap = (bridge->ops->regmap_init)(dev, bridge->context); if (IS_ERR(regmap)) { devres_free(res); return regmap; -- cgit v1.3-6-gb490 From 331a5fc9f2ed28033ddda89acb2a9b43592a545d Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Wed, 8 Jul 2015 14:30:17 +0800 Subject: thermal: sti: Add parentheses around bridge->ops->regmap_init call regmap_init(...) is a macro since commit "regmap: Use different lockdep class for each regmap init call". That same name is used as a function pointer: prevent its expansion by adding parentheses around the function pointer. Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown --- drivers/thermal/st/st_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/thermal/st/st_thermal.c b/drivers/thermal/st/st_thermal.c index 76c515dd802b..88c759d746c3 100644 --- a/drivers/thermal/st/st_thermal.c +++ b/drivers/thermal/st/st_thermal.c @@ -214,7 +214,7 @@ int st_thermal_register(struct platform_device *pdev, sensor->ops = sensor->cdata->ops; - ret = sensor->ops->regmap_init(sensor); + ret = (sensor->ops->regmap_init)(sensor); if (ret) return ret; -- cgit v1.3-6-gb490 From 3cfe7a74d42b7e3644f8b2b26aa20146d4f90f0f Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Wed, 8 Jul 2015 14:30:18 +0800 Subject: regmap: Use different lockdep class for each regmap init call Lockdep validator complains about recursive locking and deadlock when two different regmap instances are called in a nested order. That happens anytime a regmap read/write call needs to access another regmap. This is because, for performance reason, lockdep groups all locks initialized by the same mutex_init() in the same lock class. Therefore all regmap mutexes are in the same lock class, leading to lockdep "nested locking" warnings if a regmap accesses another regmap. In general, it is impossible to establish in advance the hierarchy of regmaps, so we make sure that each regmap init call initializes its own static lock_class_key. This is done by wrapping all regmap_init calls into macros. This also allows us to give meaningful names to the lock_class_key. For example, in rt5677 case, we have in /proc/lockdep_chains: irq_context: 0 [ffffffc0018d2198] &dev->mutex [ffffffc0018d2198] &dev->mutex [ffffffc001bd7f60] rt5677:5104:(&rt5677_regmap)->_lock [ffffffc001bd7f58] rt5677:5096:(&rt5677_regmap_physical)->_lock [ffffffc001b95448] &(&base->lock)->rlock The above would have resulted in a lockdep recursive warning previously. This is not the case anymore as the lockdep validator now clearly identifies the 2 regmaps as separate. Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-ac97.c | 22 +++-- drivers/base/regmap/regmap-i2c.c | 22 +++-- drivers/base/regmap/regmap-mmio.c | 27 ++++-- drivers/base/regmap/regmap-spi.c | 22 +++-- drivers/base/regmap/regmap-spmi.c | 44 +++++---- drivers/base/regmap/regmap.c | 31 +++--- include/linux/regmap.h | 192 ++++++++++++++++++++++++++++---------- 7 files changed, 250 insertions(+), 110 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap-ac97.c b/drivers/base/regmap/regmap-ac97.c index 8d304e2a943d..aa631be8b821 100644 --- a/drivers/base/regmap/regmap-ac97.c +++ b/drivers/base/regmap/regmap-ac97.c @@ -87,12 +87,15 @@ static const struct regmap_bus ac97_regmap_bus = { * The return value will be an ERR_PTR() on error or a valid pointer to * a struct regmap. */ -struct regmap *regmap_init_ac97(struct snd_ac97 *ac97, - const struct regmap_config *config) +struct regmap *__regmap_init_ac97(struct snd_ac97 *ac97, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { - return regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config); + return __regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(regmap_init_ac97); +EXPORT_SYMBOL_GPL(__regmap_init_ac97); /** * devm_regmap_init_ac97(): Initialise AC'97 register map @@ -104,11 +107,14 @@ EXPORT_SYMBOL_GPL(regmap_init_ac97); * to a struct regmap. The regmap will be automatically freed by the * device management code. */ -struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97, - const struct regmap_config *config) +struct regmap *__devm_regmap_init_ac97(struct snd_ac97 *ac97, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { - return devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config); + return __devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(devm_regmap_init_ac97); +EXPORT_SYMBOL_GPL(__devm_regmap_init_ac97); MODULE_LICENSE("GPL v2"); diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index 4b76e33110a2..3163b22e2baf 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -242,17 +242,20 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, * The return value will be an ERR_PTR() on error or a valid pointer to * a struct regmap. */ -struct regmap *regmap_init_i2c(struct i2c_client *i2c, - const struct regmap_config *config) +struct regmap *__regmap_init_i2c(struct i2c_client *i2c, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config); if (IS_ERR(bus)) return ERR_CAST(bus); - return regmap_init(&i2c->dev, bus, &i2c->dev, config); + return __regmap_init(&i2c->dev, bus, &i2c->dev, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(regmap_init_i2c); +EXPORT_SYMBOL_GPL(__regmap_init_i2c); /** * devm_regmap_init_i2c(): Initialise managed register map @@ -264,16 +267,19 @@ EXPORT_SYMBOL_GPL(regmap_init_i2c); * to a struct regmap. The regmap will be automatically freed by the * device management code. */ -struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, - const struct regmap_config *config) +struct regmap *__devm_regmap_init_i2c(struct i2c_client *i2c, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { const struct regmap_bus *bus = regmap_get_i2c_bus(i2c, config); if (IS_ERR(bus)) return ERR_CAST(bus); - return devm_regmap_init(&i2c->dev, bus, &i2c->dev, config); + return __devm_regmap_init(&i2c->dev, bus, &i2c->dev, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(devm_regmap_init_i2c); +EXPORT_SYMBOL_GPL(__devm_regmap_init_i2c); MODULE_LICENSE("GPL"); diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index 04a329a377e9..a1b2b270e4bc 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -307,9 +307,11 @@ err_free: * The return value will be an ERR_PTR() on error or a valid pointer to * a struct regmap. */ -struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, - void __iomem *regs, - const struct regmap_config *config) +struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id, + void __iomem *regs, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { struct regmap_mmio_context *ctx; @@ -317,9 +319,10 @@ struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, if (IS_ERR(ctx)) return ERR_CAST(ctx); - return regmap_init(dev, ®map_mmio, ctx, config); + return __regmap_init(dev, ®map_mmio, ctx, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(regmap_init_mmio_clk); +EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk); /** * devm_regmap_init_mmio_clk(): Initialise managed register map with clock @@ -333,9 +336,12 @@ EXPORT_SYMBOL_GPL(regmap_init_mmio_clk); * to a struct regmap. The regmap will be automatically freed by the * device management code. */ -struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, - void __iomem *regs, - const struct regmap_config *config) +struct regmap *__devm_regmap_init_mmio_clk(struct device *dev, + const char *clk_id, + void __iomem *regs, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { struct regmap_mmio_context *ctx; @@ -343,8 +349,9 @@ struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, if (IS_ERR(ctx)) return ERR_CAST(ctx); - return devm_regmap_init(dev, ®map_mmio, ctx, config); + return __devm_regmap_init(dev, ®map_mmio, ctx, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(devm_regmap_init_mmio_clk); +EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk); MODULE_LICENSE("GPL v2"); diff --git a/drivers/base/regmap/regmap-spi.c b/drivers/base/regmap/regmap-spi.c index 53d1148e80a0..4c7850d660d1 100644 --- a/drivers/base/regmap/regmap-spi.c +++ b/drivers/base/regmap/regmap-spi.c @@ -122,12 +122,15 @@ static struct regmap_bus regmap_spi = { * The return value will be an ERR_PTR() on error or a valid pointer to * a struct regmap. */ -struct regmap *regmap_init_spi(struct spi_device *spi, - const struct regmap_config *config) +struct regmap *__regmap_init_spi(struct spi_device *spi, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { - return regmap_init(&spi->dev, ®map_spi, &spi->dev, config); + return __regmap_init(&spi->dev, ®map_spi, &spi->dev, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(regmap_init_spi); +EXPORT_SYMBOL_GPL(__regmap_init_spi); /** * devm_regmap_init_spi(): Initialise register map @@ -139,11 +142,14 @@ EXPORT_SYMBOL_GPL(regmap_init_spi); * to a struct regmap. The map will be automatically freed by the * device management code. */ -struct regmap *devm_regmap_init_spi(struct spi_device *spi, - const struct regmap_config *config) +struct regmap *__devm_regmap_init_spi(struct spi_device *spi, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { - return devm_regmap_init(&spi->dev, ®map_spi, &spi->dev, config); + return __devm_regmap_init(&spi->dev, ®map_spi, &spi->dev, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(devm_regmap_init_spi); +EXPORT_SYMBOL_GPL(__devm_regmap_init_spi); MODULE_LICENSE("GPL"); diff --git a/drivers/base/regmap/regmap-spmi.c b/drivers/base/regmap/regmap-spmi.c index d7026dc33388..7f50f5862d39 100644 --- a/drivers/base/regmap/regmap-spmi.c +++ b/drivers/base/regmap/regmap-spmi.c @@ -99,12 +99,15 @@ static struct regmap_bus regmap_spmi_base = { * The return value will be an ERR_PTR() on error or a valid pointer to * a struct regmap. */ -struct regmap *regmap_init_spmi_base(struct spmi_device *sdev, - const struct regmap_config *config) +struct regmap *__regmap_init_spmi_base(struct spmi_device *sdev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { - return regmap_init(&sdev->dev, ®map_spmi_base, sdev, config); + return __regmap_init(&sdev->dev, ®map_spmi_base, sdev, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(regmap_init_spmi_base); +EXPORT_SYMBOL_GPL(__regmap_init_spmi_base); /** * devm_regmap_init_spmi_base(): Create managed regmap for Base register space @@ -115,12 +118,15 @@ EXPORT_SYMBOL_GPL(regmap_init_spmi_base); * to a struct regmap. The regmap will be automatically freed by the * device management code. */ -struct regmap *devm_regmap_init_spmi_base(struct spmi_device *sdev, - const struct regmap_config *config) +struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *sdev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { - return devm_regmap_init(&sdev->dev, ®map_spmi_base, sdev, config); + return __devm_regmap_init(&sdev->dev, ®map_spmi_base, sdev, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_base); +EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_base); static int regmap_spmi_ext_read(void *context, const void *reg, size_t reg_size, @@ -230,12 +236,15 @@ static struct regmap_bus regmap_spmi_ext = { * The return value will be an ERR_PTR() on error or a valid pointer to * a struct regmap. */ -struct regmap *regmap_init_spmi_ext(struct spmi_device *sdev, - const struct regmap_config *config) +struct regmap *__regmap_init_spmi_ext(struct spmi_device *sdev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { - return regmap_init(&sdev->dev, ®map_spmi_ext, sdev, config); + return __regmap_init(&sdev->dev, ®map_spmi_ext, sdev, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(regmap_init_spmi_ext); +EXPORT_SYMBOL_GPL(__regmap_init_spmi_ext); /** * devm_regmap_init_spmi_ext(): Create managed regmap for Ext register space @@ -246,11 +255,14 @@ EXPORT_SYMBOL_GPL(regmap_init_spmi_ext); * to a struct regmap. The regmap will be automatically freed by the * device management code. */ -struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *sdev, - const struct regmap_config *config) +struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *sdev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { - return devm_regmap_init(&sdev->dev, ®map_spmi_ext, sdev, config); + return __devm_regmap_init(&sdev->dev, ®map_spmi_ext, sdev, config, + lock_key, lock_name); } -EXPORT_SYMBOL_GPL(devm_regmap_init_spmi_ext); +EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_ext); MODULE_LICENSE("GPL"); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7111d04f2621..b9fddccd6e06 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -527,10 +527,12 @@ EXPORT_SYMBOL_GPL(regmap_get_val_endian); * a struct regmap. This function should generally not be called * directly, it should be called by bus-specific init functions. */ -struct regmap *regmap_init(struct device *dev, - const struct regmap_bus *bus, - void *bus_context, - const struct regmap_config *config) +struct regmap *__regmap_init(struct device *dev, + const struct regmap_bus *bus, + void *bus_context, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { struct regmap *map; int ret = -EINVAL; @@ -556,10 +558,14 @@ struct regmap *regmap_init(struct device *dev, spin_lock_init(&map->spinlock); map->lock = regmap_lock_spinlock; map->unlock = regmap_unlock_spinlock; + lockdep_set_class_and_name(&map->spinlock, + lock_key, lock_name); } else { mutex_init(&map->mutex); map->lock = regmap_lock_mutex; map->unlock = regmap_unlock_mutex; + lockdep_set_class_and_name(&map->mutex, + lock_key, lock_name); } map->lock_arg = map; } @@ -899,7 +905,7 @@ err_map: err: return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(regmap_init); +EXPORT_SYMBOL_GPL(__regmap_init); static void devm_regmap_release(struct device *dev, void *res) { @@ -919,10 +925,12 @@ static void devm_regmap_release(struct device *dev, void *res) * directly, it should be called by bus-specific init functions. The * map will be automatically freed by the device management code. */ -struct regmap *devm_regmap_init(struct device *dev, - const struct regmap_bus *bus, - void *bus_context, - const struct regmap_config *config) +struct regmap *__devm_regmap_init(struct device *dev, + const struct regmap_bus *bus, + void *bus_context, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name) { struct regmap **ptr, *regmap; @@ -930,7 +938,8 @@ struct regmap *devm_regmap_init(struct device *dev, if (!ptr) return ERR_PTR(-ENOMEM); - regmap = regmap_init(dev, bus, bus_context, config); + regmap = __regmap_init(dev, bus, bus_context, config, + lock_key, lock_name); if (!IS_ERR(regmap)) { *ptr = regmap; devres_add(dev, ptr); @@ -940,7 +949,7 @@ struct regmap *devm_regmap_init(struct device *dev, return regmap; } -EXPORT_SYMBOL_GPL(devm_regmap_init); +EXPORT_SYMBOL_GPL(__devm_regmap_init); static void regmap_field_init(struct regmap_field *rm_field, struct regmap *regmap, struct reg_field reg_field) diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 59c55ea0f0b5..5d7027286032 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -17,6 +17,7 @@ #include #include #include +#include struct module; struct device; @@ -324,46 +325,147 @@ struct regmap_bus { enum regmap_endian val_format_endian_default; }; -struct regmap *regmap_init(struct device *dev, - const struct regmap_bus *bus, - void *bus_context, - const struct regmap_config *config); -int regmap_attach_dev(struct device *dev, struct regmap *map, - const struct regmap_config *config); -struct regmap *regmap_init_i2c(struct i2c_client *i2c, - const struct regmap_config *config); -struct regmap *regmap_init_spi(struct spi_device *dev, - const struct regmap_config *config); -struct regmap *regmap_init_spmi_base(struct spmi_device *dev, - const struct regmap_config *config); -struct regmap *regmap_init_spmi_ext(struct spmi_device *dev, - const struct regmap_config *config); -struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, - void __iomem *regs, - const struct regmap_config *config); -struct regmap *regmap_init_ac97(struct snd_ac97 *ac97, - const struct regmap_config *config); - -struct regmap *devm_regmap_init(struct device *dev, - const struct regmap_bus *bus, - void *bus_context, - const struct regmap_config *config); -struct regmap *devm_regmap_init_i2c(struct i2c_client *i2c, - const struct regmap_config *config); -struct regmap *devm_regmap_init_spi(struct spi_device *dev, - const struct regmap_config *config); -struct regmap *devm_regmap_init_spmi_base(struct spmi_device *dev, - const struct regmap_config *config); -struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev, - const struct regmap_config *config); -struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, - void __iomem *regs, - const struct regmap_config *config); -struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97, - const struct regmap_config *config); +/* + * __regmap_init functions. + * + * These functions take a lock key and name parameter, and should not be called + * directly. Instead, use the regmap_init macros that generate a key and name + * for each call. + */ +struct regmap *__regmap_init(struct device *dev, + const struct regmap_bus *bus, + void *bus_context, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__regmap_init_i2c(struct i2c_client *i2c, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__regmap_init_spi(struct spi_device *dev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__regmap_init_spmi_base(struct spmi_device *dev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__regmap_init_spmi_ext(struct spmi_device *dev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id, + void __iomem *regs, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__regmap_init_ac97(struct snd_ac97 *ac97, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); + +struct regmap *__devm_regmap_init(struct device *dev, + const struct regmap_bus *bus, + void *bus_context, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__devm_regmap_init_i2c(struct i2c_client *i2c, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__devm_regmap_init_spi(struct spi_device *dev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *dev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *dev, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__devm_regmap_init_mmio_clk(struct device *dev, + const char *clk_id, + void __iomem *regs, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +struct regmap *__devm_regmap_init_ac97(struct snd_ac97 *ac97, + const struct regmap_config *config, + struct lock_class_key *lock_key, + const char *lock_name); +/* + * Wrapper for regmap_init macros to include a unique lockdep key and name + * for each call. No-op if CONFIG_LOCKDEP is not set. + * + * @fn: Real function to call (in the form __[*_]regmap_init[_*]) + * @name: Config variable name (#config in the calling macro) + **/ +#ifdef CONFIG_LOCKDEP +#define __regmap_lockdep_wrapper(fn, name, ...) \ +( \ + ({ \ + static struct lock_class_key _key; \ + fn(__VA_ARGS__, &_key, \ + KBUILD_BASENAME ":" \ + __stringify(__LINE__) ":" \ + "(" name ")->lock"); \ + }) \ +) +#else +#define __regmap_lockdep_wrapper(fn, name, ...) fn(__VA_ARGS__, NULL, NULL) +#endif + +#define regmap_init(dev, bus, bus_context, config) \ + __regmap_lockdep_wrapper(__regmap_init, #config, \ + dev, bus, bus_context, config) +int regmap_attach_dev(struct device *dev, struct regmap *map, + const struct regmap_config *config); +#define regmap_init_i2c(i2c, config) \ + __regmap_lockdep_wrapper(__regmap_init_i2c, #config, \ + i2c, config) +#define regmap_init_spi(dev, config) \ + __regmap_lockdep_wrapper(__regmap_init_spi, #config, \ + dev, config) +#define regmap_init_spmi_base(dev, config) \ + __regmap_lockdep_wrapper(__regmap_init_spmi_base, #config, \ + dev, config) +#define regmap_init_spmi_ext(dev, config) \ + __regmap_lockdep_wrapper(__regmap_init_spmi_ext, #config, \ + dev, config) +#define regmap_init_mmio_clk(dev, clk_id, regs, config) \ + __regmap_lockdep_wrapper(__regmap_init_mmio_clk, #config, \ + dev, clk_id, regs, config) +#define regmap_init_ac97(ac97, config) \ + __regmap_lockdep_wrapper(__regmap_init_ac97, #config, \ + ac97, config) bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); +#define devm_regmap_init(dev, bus, bus_context, config) \ + __regmap_lockdep_wrapper(__devm_regmap_init, #config, \ + dev, bus, bus_context, config) +#define devm_regmap_init_i2c(i2c, config) \ + __regmap_lockdep_wrapper(__devm_regmap_init_i2c, #config, \ + i2c, config) +#define devm_regmap_init_spi(dev, config) \ + __regmap_lockdep_wrapper(__devm_regmap_init_spi, #config, \ + dev, config) +#define devm_regmap_init_spmi_base(dev, config) \ + __regmap_lockdep_wrapper(__devm_regmap_init_spmi_base, #config, \ + dev, config) +#define devm_regmap_init_spmi_ext(dev, config) \ + __regmap_lockdep_wrapper(__devm_regmap_init_spmi_ext, #config, \ + dev, config) +#define devm_regmap_init_mmio_clk(dev, clk_id, regs, config) \ + __regmap_lockdep_wrapper(__devm_regmap_init_mmio_clk, #config, \ + dev, clk_id, regs, config) +#define devm_regmap_init_ac97(ac97, config) \ + __regmap_lockdep_wrapper(__devm_regmap_init_ac97, #config, \ + ac97, config) + /** * regmap_init_mmio(): Initialise register map * @@ -374,12 +476,8 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); * The return value will be an ERR_PTR() on error or a valid pointer to * a struct regmap. */ -static inline struct regmap *regmap_init_mmio(struct device *dev, - void __iomem *regs, - const struct regmap_config *config) -{ - return regmap_init_mmio_clk(dev, NULL, regs, config); -} +#define regmap_init_mmio(dev, regs, config) \ + regmap_init_mmio_clk(dev, NULL, regs, config) /** * devm_regmap_init_mmio(): Initialise managed register map @@ -392,12 +490,8 @@ static inline struct regmap *regmap_init_mmio(struct device *dev, * to a struct regmap. The regmap will be automatically freed by the * device management code. */ -static inline struct regmap *devm_regmap_init_mmio(struct device *dev, - void __iomem *regs, - const struct regmap_config *config) -{ - return devm_regmap_init_mmio_clk(dev, NULL, regs, config); -} +#define devm_regmap_init_mmio(dev, regs, config) \ + devm_regmap_init_mmio_clk(dev, NULL, regs, config) void regmap_exit(struct regmap *map); int regmap_reinit_cache(struct regmap *map, -- cgit v1.3-6-gb490 From b3d8ba746b5109dc890e7480db5d014d19ae6a05 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 30 Jul 2015 10:36:41 +0900 Subject: Input: max77693: Remove a read-only pwm_divisor field Storing a predefined PWM divisor in state container structure is meaningless. The field, after initialization, is only read so this only obfuscates the code. Remove the field and use directly enum value. Signed-off-by: Krzysztof Kozlowski Acked-by: Dmitry Torokhov Signed-off-by: Mark Brown --- drivers/input/misc/max77693-haptic.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c index 4524499ea72f..8dc43c1ebf0e 100644 --- a/drivers/input/misc/max77693-haptic.c +++ b/drivers/input/misc/max77693-haptic.c @@ -60,7 +60,6 @@ struct max77693_haptic { unsigned int pwm_duty; enum max77693_haptic_motor_type type; enum max77693_haptic_pulse_mode mode; - enum max77693_haptic_pwm_divisor pwm_divisor; struct work_struct work; }; @@ -88,7 +87,7 @@ static int max77693_haptic_configure(struct max77693_haptic *haptic, value = ((haptic->type << MAX77693_CONFIG2_MODE) | (enable << MAX77693_CONFIG2_MEN) | (haptic->mode << MAX77693_CONFIG2_HTYP) | - (haptic->pwm_divisor)); + MAX77693_HAPTIC_PWM_DIVISOR_128); error = regmap_write(haptic->regmap_haptic, MAX77693_HAPTIC_REG_CONFIG2, value); @@ -259,7 +258,6 @@ static int max77693_haptic_probe(struct platform_device *pdev) haptic->dev = &pdev->dev; haptic->type = MAX77693_HAPTIC_LRA; haptic->mode = MAX77693_HAPTIC_EXTERNAL_MODE; - haptic->pwm_divisor = MAX77693_HAPTIC_PWM_DIVISOR_128; haptic->suspend_state = false; INIT_WORK(&haptic->work, max77693_haptic_play_work); -- cgit v1.3-6-gb490 From 6eaa247a5bab775e45a74b52c17bf8bc37fd5f6f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 30 Jul 2015 10:36:42 +0900 Subject: Input: max77693: Prepare for adding support for Maxim 77843 Prepare the driver for supporting two devices: Maxim 77693 and 77843: 1. Add table of device ids and store current device type for later usage. 2. Differentiate the haptic device configuration. Signed-off-by: Krzysztof Kozlowski Acked-by: Dmitry Torokhov Signed-off-by: Mark Brown --- drivers/input/misc/max77693-haptic.c | 41 ++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c index 8dc43c1ebf0e..4c0f67ab66d9 100644 --- a/drivers/input/misc/max77693-haptic.c +++ b/drivers/input/misc/max77693-haptic.c @@ -47,6 +47,8 @@ enum max77693_haptic_pwm_divisor { }; struct max77693_haptic { + enum max77693_types dev_type; + struct regmap *regmap_pmic; struct regmap *regmap_haptic; struct device *dev; @@ -81,16 +83,23 @@ static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic) static int max77693_haptic_configure(struct max77693_haptic *haptic, bool enable) { - unsigned int value; + unsigned int value, config_reg; int error; - value = ((haptic->type << MAX77693_CONFIG2_MODE) | - (enable << MAX77693_CONFIG2_MEN) | - (haptic->mode << MAX77693_CONFIG2_HTYP) | - MAX77693_HAPTIC_PWM_DIVISOR_128); + switch (haptic->dev_type) { + case TYPE_MAX77693: + value = ((haptic->type << MAX77693_CONFIG2_MODE) | + (enable << MAX77693_CONFIG2_MEN) | + (haptic->mode << MAX77693_CONFIG2_HTYP) | + MAX77693_HAPTIC_PWM_DIVISOR_128); + config_reg = MAX77693_HAPTIC_REG_CONFIG2; + break; + default: + return -EINVAL; + } error = regmap_write(haptic->regmap_haptic, - MAX77693_HAPTIC_REG_CONFIG2, value); + config_reg, value); if (error) { dev_err(haptic->dev, "failed to update haptic config: %d\n", error); @@ -254,12 +263,23 @@ static int max77693_haptic_probe(struct platform_device *pdev) return -ENOMEM; haptic->regmap_pmic = max77693->regmap; - haptic->regmap_haptic = max77693->regmap_haptic; haptic->dev = &pdev->dev; haptic->type = MAX77693_HAPTIC_LRA; haptic->mode = MAX77693_HAPTIC_EXTERNAL_MODE; haptic->suspend_state = false; + /* Variant-specific init */ + haptic->dev_type = platform_get_device_id(pdev)->driver_data; + switch (haptic->dev_type) { + case TYPE_MAX77693: + haptic->regmap_haptic = max77693->regmap_haptic; + break; + default: + dev_err(&pdev->dev, "unsupported device type: %u\n", + haptic->dev_type); + return -EINVAL; + } + INIT_WORK(&haptic->work, max77693_haptic_play_work); /* Get pwm and regulatot for haptic device */ @@ -337,12 +357,19 @@ static int __maybe_unused max77693_haptic_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops, max77693_haptic_suspend, max77693_haptic_resume); +static const struct platform_device_id max77693_haptic_id[] = { + { "max77693-haptic", TYPE_MAX77693 }, + {}, +}; +MODULE_DEVICE_TABLE(platform, max77693_haptic_id); + static struct platform_driver max77693_haptic_driver = { .driver = { .name = "max77693-haptic", .pm = &max77693_haptic_pm_ops, }, .probe = max77693_haptic_probe, + .id_table = max77693_haptic_id, }; module_platform_driver(max77693_haptic_driver); -- cgit v1.3-6-gb490 From 56bbc99e6914eb183fb083f737178a1757083d41 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 30 Jul 2015 10:36:43 +0900 Subject: Input: max77693: Add support for Maxim 77843 The Maxim 77843 haptic driver differs from 77693 by: 1. Setting the bias. 2. Different configuration register. 3. Not enabling the low-sys DAC. 4. Using same regmap for PMIC and haptic blocks. Incorporate all differences into max77693 haptic driver so both devices can be supported. Signed-off-by: Krzysztof Kozlowski Acked-by: Dmitry Torokhov Signed-off-by: Mark Brown --- drivers/input/misc/Kconfig | 6 ++--- drivers/input/misc/max77693-haptic.c | 48 +++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index d4f0a817e858..f5d7a98a329d 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -167,12 +167,12 @@ config INPUT_M68K_BEEP depends on M68K config INPUT_MAX77693_HAPTIC - tristate "MAXIM MAX77693 haptic controller support" - depends on MFD_MAX77693 && PWM + tristate "MAXIM MAX77693/MAX77843 haptic controller support" + depends on (MFD_MAX77693 || MFD_MAX77843) && PWM select INPUT_FF_MEMLESS help This option enables support for the haptic controller on - MAXIM MAX77693 chip. + MAXIM MAX77693 and MAX77843 chips. To compile this driver as module, choose M here: the module will be called max77693-haptic. diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c index 4c0f67ab66d9..6d96bff32a0e 100644 --- a/drivers/input/misc/max77693-haptic.c +++ b/drivers/input/misc/max77693-haptic.c @@ -1,8 +1,9 @@ /* - * MAXIM MAX77693 Haptic device driver + * MAXIM MAX77693/MAX77843 Haptic device driver * - * Copyright (C) 2014 Samsung Electronics + * Copyright (C) 2014,2015 Samsung Electronics * Jaewon Kim + * Krzysztof Kozlowski * * This program is not provided / owned by Maxim Integrated Products. * @@ -26,6 +27,7 @@ #include #include #include +#include #define MAX_MAGNITUDE_SHIFT 16 @@ -80,6 +82,26 @@ static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic) return 0; } +static int max77843_haptic_bias(struct max77693_haptic *haptic, bool on) +{ + int error; + + if (haptic->dev_type != TYPE_MAX77843) + return 0; + + error = regmap_update_bits(haptic->regmap_haptic, + MAX77843_SYS_REG_MAINCTRL1, + MAX77843_MAINCTRL1_BIASEN_MASK, + on << MAINCTRL1_BIASEN_SHIFT); + if (error) { + dev_err(haptic->dev, "failed to %s bias: %d\n", + on ? "enable" : "disable", error); + return error; + } + + return 0; +} + static int max77693_haptic_configure(struct max77693_haptic *haptic, bool enable) { @@ -94,6 +116,12 @@ static int max77693_haptic_configure(struct max77693_haptic *haptic, MAX77693_HAPTIC_PWM_DIVISOR_128); config_reg = MAX77693_HAPTIC_REG_CONFIG2; break; + case TYPE_MAX77843: + value = (haptic->type << MCONFIG_MODE_SHIFT) | + (enable << MCONFIG_MEN_SHIFT) | + MAX77693_HAPTIC_PWM_DIVISOR_128; + config_reg = MAX77843_HAP_REG_MCONFIG; + break; default: return -EINVAL; } @@ -113,6 +141,9 @@ static int max77693_haptic_lowsys(struct max77693_haptic *haptic, bool enable) { int error; + if (haptic->dev_type != TYPE_MAX77693) + return 0; + error = regmap_update_bits(haptic->regmap_pmic, MAX77693_PMIC_REG_LSCNFG, MAX77693_PMIC_LOW_SYS_MASK, @@ -228,6 +259,10 @@ static int max77693_haptic_open(struct input_dev *dev) struct max77693_haptic *haptic = input_get_drvdata(dev); int error; + error = max77843_haptic_bias(haptic, true); + if (error) + return error; + error = regulator_enable(haptic->motor_reg); if (error) { dev_err(haptic->dev, @@ -250,6 +285,8 @@ static void max77693_haptic_close(struct input_dev *dev) if (error) dev_err(haptic->dev, "failed to disable regulator: %d\n", error); + + max77843_haptic_bias(haptic, false); } static int max77693_haptic_probe(struct platform_device *pdev) @@ -274,6 +311,9 @@ static int max77693_haptic_probe(struct platform_device *pdev) case TYPE_MAX77693: haptic->regmap_haptic = max77693->regmap_haptic; break; + case TYPE_MAX77843: + haptic->regmap_haptic = max77693->regmap; + break; default: dev_err(&pdev->dev, "unsupported device type: %u\n", haptic->dev_type); @@ -359,6 +399,7 @@ static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops, static const struct platform_device_id max77693_haptic_id[] = { { "max77693-haptic", TYPE_MAX77693 }, + { "max77843-haptic", TYPE_MAX77843 }, {}, }; MODULE_DEVICE_TABLE(platform, max77693_haptic_id); @@ -374,6 +415,7 @@ static struct platform_driver max77693_haptic_driver = { module_platform_driver(max77693_haptic_driver); MODULE_AUTHOR("Jaewon Kim "); -MODULE_DESCRIPTION("MAXIM MAX77693 Haptic driver"); +MODULE_AUTHOR("Krzysztof Kozlowski "); +MODULE_DESCRIPTION("MAXIM 77693/77843 Haptic driver"); MODULE_ALIAS("platform:max77693-haptic"); MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 38a986c0750db23aeb5968f8b6d37298b9be4b11 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 30 Jul 2015 10:36:44 +0900 Subject: Input: Remove the max77843 haptic driver The max77693 haptic driver supports Maxim 77843 device so remove the max77843 driver. Signed-off-by: Krzysztof Kozlowski Acked-by: Dmitry Torokhov Signed-off-by: Mark Brown --- drivers/input/misc/Kconfig | 12 -- drivers/input/misc/Makefile | 1 - drivers/input/misc/max77843-haptic.c | 359 ----------------------------------- 3 files changed, 372 deletions(-) delete mode 100644 drivers/input/misc/max77843-haptic.c (limited to 'drivers') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index f5d7a98a329d..c41dec819cdf 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -177,18 +177,6 @@ config INPUT_MAX77693_HAPTIC To compile this driver as module, choose M here: the module will be called max77693-haptic. -config INPUT_MAX77843_HAPTIC - tristate "MAXIM MAX77843 haptic controller support" - depends on MFD_MAX77843 && REGULATOR - select INPUT_FF_MEMLESS - help - This option enables support for the haptic controller on - MAXIM MAX77843 chip. The driver supports ff-memless interface - from input framework. - - To compile this driver as module, choose M here: the - module will be called max77843-haptic. - config INPUT_MAX8925_ONKEY tristate "MAX8925 ONKEY support" depends on MFD_MAX8925 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 53df07dcc23c..0357a088c6a9 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -41,7 +41,6 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o -obj-$(CONFIG_INPUT_MAX77843_HAPTIC) += max77843-haptic.o obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o diff --git a/drivers/input/misc/max77843-haptic.c b/drivers/input/misc/max77843-haptic.c deleted file mode 100644 index 30da81ab5a21..000000000000 --- a/drivers/input/misc/max77843-haptic.c +++ /dev/null @@ -1,359 +0,0 @@ -/* - * MAXIM MAX77693 Haptic device driver - * - * Copyright (C) 2015 Samsung Electronics - * Author: Jaewon Kim - * - * 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 -#include -#include -#include - -#define MAX_MAGNITUDE_SHIFT 16 - -enum max77843_haptic_motor_type { - MAX77843_HAPTIC_ERM = 0, - MAX77843_HAPTIC_LRA, -}; - -enum max77843_haptic_pwm_divisor { - MAX77843_HAPTIC_PWM_DIVISOR_32 = 0, - MAX77843_HAPTIC_PWM_DIVISOR_64, - MAX77843_HAPTIC_PWM_DIVISOR_128, - MAX77843_HAPTIC_PWM_DIVISOR_256, -}; - -struct max77843_haptic { - struct regmap *regmap_haptic; - struct device *dev; - struct input_dev *input_dev; - struct pwm_device *pwm_dev; - struct regulator *motor_reg; - struct work_struct work; - struct mutex mutex; - - unsigned int magnitude; - unsigned int pwm_duty; - - bool active; - bool suspended; - - enum max77843_haptic_motor_type type; - enum max77843_haptic_pwm_divisor pwm_divisor; -}; - -static int max77843_haptic_set_duty_cycle(struct max77843_haptic *haptic) -{ - int delta = (haptic->pwm_dev->period + haptic->pwm_duty) / 2; - int error; - - error = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period); - if (error) { - dev_err(haptic->dev, "failed to configure pwm: %d\n", error); - return error; - } - - return 0; -} - -static int max77843_haptic_bias(struct max77843_haptic *haptic, bool on) -{ - int error; - - error = regmap_update_bits(haptic->regmap_haptic, - MAX77843_SYS_REG_MAINCTRL1, - MAX77843_MAINCTRL1_BIASEN_MASK, - on << MAINCTRL1_BIASEN_SHIFT); - if (error) { - dev_err(haptic->dev, "failed to %s bias: %d\n", - on ? "enable" : "disable", error); - return error; - } - - return 0; -} - -static int max77843_haptic_config(struct max77843_haptic *haptic, bool enable) -{ - unsigned int value; - int error; - - value = (haptic->type << MCONFIG_MODE_SHIFT) | - (enable << MCONFIG_MEN_SHIFT) | - (haptic->pwm_divisor << MCONFIG_PDIV_SHIFT); - - error = regmap_write(haptic->regmap_haptic, - MAX77843_HAP_REG_MCONFIG, value); - if (error) { - dev_err(haptic->dev, - "failed to update haptic config: %d\n", error); - return error; - } - - return 0; -} - -static int max77843_haptic_enable(struct max77843_haptic *haptic) -{ - int error; - - if (haptic->active) - return 0; - - error = pwm_enable(haptic->pwm_dev); - if (error) { - dev_err(haptic->dev, - "failed to enable pwm device: %d\n", error); - return error; - } - - error = max77843_haptic_config(haptic, true); - if (error) - goto err_config; - - haptic->active = true; - - return 0; - -err_config: - pwm_disable(haptic->pwm_dev); - - return error; -} - -static int max77843_haptic_disable(struct max77843_haptic *haptic) -{ - int error; - - if (!haptic->active) - return 0; - - error = max77843_haptic_config(haptic, false); - if (error) - return error; - - pwm_disable(haptic->pwm_dev); - - haptic->active = false; - - return 0; -} - -static void max77843_haptic_play_work(struct work_struct *work) -{ - struct max77843_haptic *haptic = - container_of(work, struct max77843_haptic, work); - int error; - - mutex_lock(&haptic->mutex); - - if (haptic->suspended) - goto out_unlock; - - if (haptic->magnitude) { - error = max77843_haptic_set_duty_cycle(haptic); - if (error) { - dev_err(haptic->dev, - "failed to set duty cycle: %d\n", error); - goto out_unlock; - } - - error = max77843_haptic_enable(haptic); - if (error) - dev_err(haptic->dev, - "cannot enable haptic: %d\n", error); - } else { - error = max77843_haptic_disable(haptic); - if (error) - dev_err(haptic->dev, - "cannot disable haptic: %d\n", error); - } - -out_unlock: - mutex_unlock(&haptic->mutex); -} - -static int max77843_haptic_play_effect(struct input_dev *dev, void *data, - struct ff_effect *effect) -{ - struct max77843_haptic *haptic = input_get_drvdata(dev); - u64 period_mag_multi; - - haptic->magnitude = effect->u.rumble.strong_magnitude; - if (!haptic->magnitude) - haptic->magnitude = effect->u.rumble.weak_magnitude; - - period_mag_multi = (u64)haptic->pwm_dev->period * haptic->magnitude; - haptic->pwm_duty = (unsigned int)(period_mag_multi >> - MAX_MAGNITUDE_SHIFT); - - schedule_work(&haptic->work); - - return 0; -} - -static int max77843_haptic_open(struct input_dev *dev) -{ - struct max77843_haptic *haptic = input_get_drvdata(dev); - int error; - - error = max77843_haptic_bias(haptic, true); - if (error) - return error; - - error = regulator_enable(haptic->motor_reg); - if (error) { - dev_err(haptic->dev, - "failed to enable regulator: %d\n", error); - return error; - } - - return 0; -} - -static void max77843_haptic_close(struct input_dev *dev) -{ - struct max77843_haptic *haptic = input_get_drvdata(dev); - int error; - - cancel_work_sync(&haptic->work); - max77843_haptic_disable(haptic); - - error = regulator_disable(haptic->motor_reg); - if (error) - dev_err(haptic->dev, - "failed to disable regulator: %d\n", error); - - max77843_haptic_bias(haptic, false); -} - -static int max77843_haptic_probe(struct platform_device *pdev) -{ - struct max77693_dev *max77843 = dev_get_drvdata(pdev->dev.parent); - struct max77843_haptic *haptic; - int error; - - haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL); - if (!haptic) - return -ENOMEM; - - haptic->regmap_haptic = max77843->regmap; - haptic->dev = &pdev->dev; - haptic->type = MAX77843_HAPTIC_LRA; - haptic->pwm_divisor = MAX77843_HAPTIC_PWM_DIVISOR_128; - - INIT_WORK(&haptic->work, max77843_haptic_play_work); - mutex_init(&haptic->mutex); - - haptic->pwm_dev = devm_pwm_get(&pdev->dev, NULL); - if (IS_ERR(haptic->pwm_dev)) { - dev_err(&pdev->dev, "failed to get pwm device\n"); - return PTR_ERR(haptic->pwm_dev); - } - - haptic->motor_reg = devm_regulator_get_exclusive(&pdev->dev, "haptic"); - if (IS_ERR(haptic->motor_reg)) { - dev_err(&pdev->dev, "failed to get regulator\n"); - return PTR_ERR(haptic->motor_reg); - } - - haptic->input_dev = devm_input_allocate_device(&pdev->dev); - if (!haptic->input_dev) { - dev_err(&pdev->dev, "failed to allocate input device\n"); - return -ENOMEM; - } - - haptic->input_dev->name = "max77843-haptic"; - haptic->input_dev->id.version = 1; - haptic->input_dev->dev.parent = &pdev->dev; - haptic->input_dev->open = max77843_haptic_open; - haptic->input_dev->close = max77843_haptic_close; - input_set_drvdata(haptic->input_dev, haptic); - input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE); - - error = input_ff_create_memless(haptic->input_dev, NULL, - max77843_haptic_play_effect); - if (error) { - dev_err(&pdev->dev, "failed to create force-feedback\n"); - return error; - } - - error = input_register_device(haptic->input_dev); - if (error) { - dev_err(&pdev->dev, "failed to register input device\n"); - return error; - } - - platform_set_drvdata(pdev, haptic); - - return 0; -} - -static int __maybe_unused max77843_haptic_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct max77843_haptic *haptic = platform_get_drvdata(pdev); - int error; - - error = mutex_lock_interruptible(&haptic->mutex); - if (error) - return error; - - max77843_haptic_disable(haptic); - - haptic->suspended = true; - - mutex_unlock(&haptic->mutex); - - return 0; -} - -static int __maybe_unused max77843_haptic_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct max77843_haptic *haptic = platform_get_drvdata(pdev); - unsigned int magnitude; - - mutex_lock(&haptic->mutex); - - haptic->suspended = false; - - magnitude = ACCESS_ONCE(haptic->magnitude); - if (magnitude) - max77843_haptic_enable(haptic); - - mutex_unlock(&haptic->mutex); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(max77843_haptic_pm_ops, - max77843_haptic_suspend, max77843_haptic_resume); - -static struct platform_driver max77843_haptic_driver = { - .driver = { - .name = "max77843-haptic", - .pm = &max77843_haptic_pm_ops, - }, - .probe = max77843_haptic_probe, -}; -module_platform_driver(max77843_haptic_driver); - -MODULE_AUTHOR("Jaewon Kim "); -MODULE_DESCRIPTION("MAXIM MAX77843 Haptic driver"); -MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 2f3cc24f07b8bfe8302a46ceb1ed58cde62cbd09 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 7 Aug 2015 14:13:34 +0200 Subject: usb: musb: gadget: fix build break by adding missing 'break' Add missing break after 'default' label to fix compilation error. Signed-off-by: Robert Baldyga Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index cc503591b634..67ad630c86c9 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1703,6 +1703,7 @@ static struct usb_ep *musb_match_ep(struct usb_gadget *g, ep = gadget_find_ep_by_name(g, "ep2out"); break; default: + break; } if (ep && usb_gadget_ep_match_desc(g, ep, desc, ep_comp)) -- cgit v1.3-6-gb490 From 4299aaaa5da01f46f9186c4bb958200cf9c73532 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 7 Aug 2015 22:33:11 +0800 Subject: spi: mediatek: mtk_spi_driver can be static Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- drivers/spi/spi-mt65xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 4676b0122b89..e62d3043ad93 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -731,7 +731,7 @@ static const struct dev_pm_ops mtk_spi_pm = { mtk_spi_runtime_resume, NULL) }; -struct platform_driver mtk_spi_driver = { +static struct platform_driver mtk_spi_driver = { .driver = { .name = "mtk-spi", .pm = &mtk_spi_pm, -- cgit v1.3-6-gb490 From 0630db4f7a43a7d03560ba898134971c53d22a4a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 7 Aug 2015 18:10:17 +0200 Subject: drm: Remove two-level menu in Kconfig The Direct Rendering Manager Kconfig option is already a separate menu, so remove the extra level to make it easier to navigate. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/video/Kconfig | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 8bf495ffb020..e0606c01e8ac 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -22,9 +22,7 @@ source "drivers/gpu/vga/Kconfig" source "drivers/gpu/host1x/Kconfig" source "drivers/gpu/ipu-v3/Kconfig" -menu "Direct Rendering Manager" source "drivers/gpu/drm/Kconfig" -endmenu menu "Frame buffer Devices" source "drivers/video/fbdev/Kconfig" -- cgit v1.3-6-gb490 From da8b43c0e1dcea3bcac5f37ea59934ddaa137aed Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 4 Aug 2015 22:51:07 -0700 Subject: vxlan: combine VXLAN_FLOWBASED into VXLAN_COLLECT_METADATA IFLA_VXLAN_FLOWBASED is useless without IFLA_VXLAN_COLLECT_METADATA, so combine them into single IFLA_VXLAN_COLLECT_METADATA flag. 'flowbased' doesn't convey real meaning of the vxlan tunnel mode. This mode can be used by routing, tc+bpf and ovs. Only ovs is strictly flow based, so 'collect metadata' is a better name for this tunnel mode. Signed-off-by: Alexei Starovoitov Acked-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 17 ++++++----------- include/net/vxlan.h | 4 +--- include/uapi/linux/if_link.h | 1 - net/openvswitch/vport-vxlan.c | 2 +- 4 files changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index e90f7a484e1c..b6731fad19ba 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1141,7 +1141,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, union vxlan_addr *remote_ip; /* For flow based devices, map all packets to VNI 0 */ - if (vs->flags & VXLAN_F_FLOW_BASED) + if (vs->flags & VXLAN_F_COLLECT_METADATA) vni = 0; /* Is this VNI defined? */ @@ -1183,7 +1183,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, skb_reset_network_header(skb); /* In flow-based mode, GBP is carried in dst_metadata */ - if (!(vs->flags & VXLAN_F_FLOW_BASED)) + if (!(vs->flags & VXLAN_F_COLLECT_METADATA)) skb->mark = md->gbp; if (oip6) @@ -2129,7 +2129,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) #endif } - if (vxlan->flags & VXLAN_F_FLOW_BASED && + if (vxlan->flags & VXLAN_F_COLLECT_METADATA && info && info->mode == IP_TUNNEL_INFO_TX) { vxlan_xmit_one(skb, dev, NULL, false); return NETDEV_TX_OK; @@ -2462,7 +2462,6 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_RSC] = { .type = NLA_U8 }, [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 }, [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 }, - [IFLA_VXLAN_FLOWBASED] = { .type = NLA_U8 }, [IFLA_VXLAN_COLLECT_METADATA] = { .type = NLA_U8 }, [IFLA_VXLAN_PORT] = { .type = NLA_U16 }, [IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 }, @@ -2814,10 +2813,6 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, if (data[IFLA_VXLAN_LIMIT]) conf.addrmax = nla_get_u32(data[IFLA_VXLAN_LIMIT]); - if (data[IFLA_VXLAN_FLOWBASED] && - nla_get_u8(data[IFLA_VXLAN_FLOWBASED])) - conf.flags |= VXLAN_F_FLOW_BASED; - if (data[IFLA_VXLAN_COLLECT_METADATA] && nla_get_u8(data[IFLA_VXLAN_COLLECT_METADATA])) conf.flags |= VXLAN_F_COLLECT_METADATA; @@ -2903,7 +2898,7 @@ static size_t vxlan_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_RSC */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_L2MISS */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_L3MISS */ - nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_FLOWBASED */ + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_COLLECT_METADATA */ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_AGEING */ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LIMIT */ nla_total_size(sizeof(struct ifla_vxlan_port_range)) + @@ -2970,8 +2965,8 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) !!(vxlan->flags & VXLAN_F_L2MISS)) || nla_put_u8(skb, IFLA_VXLAN_L3MISS, !!(vxlan->flags & VXLAN_F_L3MISS)) || - nla_put_u8(skb, IFLA_VXLAN_FLOWBASED, - !!(vxlan->flags & VXLAN_F_FLOW_BASED)) || + nla_put_u8(skb, IFLA_VXLAN_COLLECT_METADATA, + !!(vxlan->flags & VXLAN_F_COLLECT_METADATA)) || nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->cfg.age_interval) || nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->cfg.addrmax) || nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->cfg.dst_port) || diff --git a/include/net/vxlan.h b/include/net/vxlan.h index eb8d721cdb67..e4534f1b2d8c 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -181,7 +181,6 @@ struct vxlan_dev { #define VXLAN_F_GBP 0x800 #define VXLAN_F_REMCSUM_NOPARTIAL 0x1000 #define VXLAN_F_COLLECT_METADATA 0x2000 -#define VXLAN_F_FLOW_BASED 0x4000 /* Flags that are used in the receive path. These flags must match in * order for a socket to be shareable @@ -190,8 +189,7 @@ struct vxlan_dev { VXLAN_F_UDP_ZERO_CSUM6_RX | \ VXLAN_F_REMCSUM_RX | \ VXLAN_F_REMCSUM_NOPARTIAL | \ - VXLAN_F_COLLECT_METADATA | \ - VXLAN_F_FLOW_BASED) + VXLAN_F_COLLECT_METADATA) struct net_device *vxlan_dev_create(struct net *net, const char *name, u8 name_assign_type, struct vxlan_config *conf); diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index ea047480a1f0..f24ec99a2262 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -382,7 +382,6 @@ enum { IFLA_VXLAN_REMCSUM_RX, IFLA_VXLAN_GBP, IFLA_VXLAN_REMCSUM_NOPARTIAL, - IFLA_VXLAN_FLOWBASED, IFLA_VXLAN_COLLECT_METADATA, __IFLA_VXLAN_MAX }; diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 547173336cd3..c6e937e36f8b 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -90,7 +90,7 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms) int err; struct vxlan_config conf = { .no_share = true, - .flags = VXLAN_F_FLOW_BASED | VXLAN_F_COLLECT_METADATA, + .flags = VXLAN_F_COLLECT_METADATA, }; if (!options) { -- cgit v1.3-6-gb490 From 00159f19a5057cb779146afce1cceede692af346 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 6 Aug 2015 19:15:30 -0700 Subject: Input: do not emit unneeded EV_SYN when suspending Do not emit EV_SYN/SYN_REPORT on suspend if there were no keys that are still pressed as we are suspending the device (and in all other cases when input core is forcibly releasing keys via input_dev_release_keys() call). Reviewed-by: Benson Leung Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/input.c b/drivers/input/input.c index 78d24990a816..5391abd28b27 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -674,13 +674,19 @@ EXPORT_SYMBOL(input_close_device); */ static void input_dev_release_keys(struct input_dev *dev) { + bool need_sync = false; int code; if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { - for_each_set_bit(code, dev->key, KEY_CNT) + for_each_set_bit(code, dev->key, KEY_CNT) { input_pass_event(dev, EV_KEY, code, 0); + need_sync = true; + } + + if (need_sync) + input_pass_event(dev, EV_SYN, SYN_REPORT, 1); + memset(dev->key, 0, sizeof(dev->key)); - input_pass_event(dev, EV_SYN, SYN_REPORT, 1); } } -- cgit v1.3-6-gb490 From afe10358e47a3ea1f69005cb1be78170d23f8afa Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 16 Apr 2015 18:14:55 -0700 Subject: Input: elants_i2c - wire up regulator support Elan touchscreen controllers use two power supplies, vcc33 and vccio, and we need to enable them before trying to access the device. On X86 firmware usually does this, but on ARM it is usually left to the kernel. Signed-off-by: Dmitry Torokhov Reviewed-by: Benson Leung Reviewed-by: Scott Liu Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/elants_i2c.txt | 3 + drivers/input/touchscreen/elants_i2c.c | 184 ++++++++++++++++++--- 2 files changed, 165 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/elants_i2c.txt b/Documentation/devicetree/bindings/input/elants_i2c.txt index a765232e6446..8a71038f3489 100644 --- a/Documentation/devicetree/bindings/input/elants_i2c.txt +++ b/Documentation/devicetree/bindings/input/elants_i2c.txt @@ -13,6 +13,9 @@ Optional properties: - pinctrl-names: should be "default" (see pinctrl binding [1]). - pinctrl-0: a phandle pointing to the pin settings for the device (see pinctrl binding [1]). +- reset-gpios: reset gpio the chip is connected to. +- vcc33-supply: a phandle for the regulator supplying 3.3V power. +- vccio-supply: a phandle for the regulator supplying IO power. [0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt [1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 42e43f14602e..19122652e71b 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include /* Device, Driver information */ @@ -102,6 +104,9 @@ /* calibration timeout definition */ #define ELAN_CALI_TIMEOUT_MSEC 10000 +#define ELAN_POWERON_DELAY_USEC 500 +#define ELAN_RESET_DELAY_MSEC 20 + enum elants_state { ELAN_STATE_NORMAL, ELAN_WAIT_QUEUE_HEADER, @@ -118,6 +123,10 @@ struct elants_data { struct i2c_client *client; struct input_dev *input; + struct regulator *vcc33; + struct regulator *vccio; + struct gpio_desc *reset_gpio; + u16 fw_version; u8 test_version; u8 solution_version; @@ -141,6 +150,7 @@ struct elants_data { u8 buf[MAX_PACKET_SIZE]; bool wake_irq_enabled; + bool keep_power_in_suspend; }; static int elants_i2c_send(struct i2c_client *client, @@ -1058,6 +1068,67 @@ static void elants_i2c_remove_sysfs_group(void *_data) sysfs_remove_group(&ts->client->dev.kobj, &elants_attribute_group); } +static int elants_i2c_power_on(struct elants_data *ts) +{ + int error; + + /* + * If we do not have reset gpio assume platform firmware + * controls regulators and does power them on for us. + */ + if (IS_ERR_OR_NULL(ts->reset_gpio)) + return 0; + + gpiod_set_value_cansleep(ts->reset_gpio, 1); + + error = regulator_enable(ts->vcc33); + if (error) { + dev_err(&ts->client->dev, + "failed to enable vcc33 regulator: %d\n", + error); + goto release_reset_gpio; + } + + error = regulator_enable(ts->vccio); + if (error) { + dev_err(&ts->client->dev, + "failed to enable vccio regulator: %d\n", + error); + regulator_disable(ts->vcc33); + goto release_reset_gpio; + } + + /* + * We need to wait a bit after powering on controller before + * we are allowed to release reset GPIO. + */ + udelay(ELAN_POWERON_DELAY_USEC); + +release_reset_gpio: + gpiod_set_value_cansleep(ts->reset_gpio, 0); + if (error) + return error; + + msleep(ELAN_RESET_DELAY_MSEC); + + return 0; +} + +static void elants_i2c_power_off(void *_data) +{ + struct elants_data *ts = _data; + + if (!IS_ERR_OR_NULL(ts->reset_gpio)) { + /* + * Activate reset gpio to prevent leakage through the + * pin once we shut off power to the controller. + */ + gpiod_set_value_cansleep(ts->reset_gpio, 1); + regulator_disable(ts->vccio); + regulator_disable(ts->vcc33); + } +} + static int elants_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1072,13 +1143,6 @@ static int elants_i2c_probe(struct i2c_client *client, return -ENXIO; } - /* Make sure there is something at this address */ - if (i2c_smbus_xfer(client->adapter, client->addr, 0, - I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { - dev_err(&client->dev, "nothing at this address\n"); - return -ENXIO; - } - ts = devm_kzalloc(&client->dev, sizeof(struct elants_data), GFP_KERNEL); if (!ts) return -ENOMEM; @@ -1089,6 +1153,70 @@ static int elants_i2c_probe(struct i2c_client *client, ts->client = client; i2c_set_clientdata(client, ts); + ts->vcc33 = devm_regulator_get(&client->dev, "vcc33"); + if (IS_ERR(ts->vcc33)) { + error = PTR_ERR(ts->vcc33); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, + "Failed to get 'vcc33' regulator: %d\n", + error); + return error; + } + + ts->vccio = devm_regulator_get(&client->dev, "vccio"); + if (IS_ERR(ts->vccio)) { + error = PTR_ERR(ts->vccio); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, + "Failed to get 'vccio' regulator: %d\n", + error); + return error; + } + + ts->reset_gpio = devm_gpiod_get(&client->dev, "reset"); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + + if (error == -EPROBE_DEFER) + return error; + + if (error != -ENOENT && error != -ENOSYS) { + dev_err(&client->dev, + "failed to get reset gpio: %d\n", + error); + return error; + } + + ts->keep_power_in_suspend = true; + } else { + error = gpiod_direction_output(ts->reset_gpio, 0); + if (error) { + dev_err(&client->dev, + "failed to configure reset gpio as output: %d\n", + error); + return error; + } + } + + error = elants_i2c_power_on(ts); + if (error) + return error; + + error = devm_add_action(&client->dev, elants_i2c_power_off, ts); + if (error) { + dev_err(&client->dev, + "failed to install power off action: %d\n", error); + elants_i2c_power_off(ts); + return error; + } + + /* Make sure there is something at this address */ + if (i2c_smbus_xfer(client->adapter, client->addr, 0, + I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { + dev_err(&client->dev, "nothing at this address\n"); + return -ENXIO; + } + error = elants_i2c_initialize(ts); if (error) { dev_err(&client->dev, "failed to initialize: %d\n", error); @@ -1196,17 +1324,23 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev) disable_irq(client->irq); - for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { - error = elants_i2c_send(client, set_sleep_cmd, - sizeof(set_sleep_cmd)); - if (!error) - break; + if (device_may_wakeup(dev) || ts->keep_power_in_suspend) { + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_send(client, set_sleep_cmd, + sizeof(set_sleep_cmd)); + if (!error) + break; - dev_err(&client->dev, "suspend command failed: %d\n", error); - } + dev_err(&client->dev, + "suspend command failed: %d\n", error); + } - if (device_may_wakeup(dev)) - ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); + if (device_may_wakeup(dev)) + ts->wake_irq_enabled = + (enable_irq_wake(client->irq) == 0); + } else { + elants_i2c_power_off(ts); + } return 0; } @@ -1222,13 +1356,19 @@ static int __maybe_unused elants_i2c_resume(struct device *dev) if (device_may_wakeup(dev) && ts->wake_irq_enabled) disable_irq_wake(client->irq); - for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { - error = elants_i2c_send(client, set_active_cmd, - sizeof(set_active_cmd)); - if (!error) - break; + if (ts->keep_power_in_suspend) { + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_send(client, set_active_cmd, + sizeof(set_active_cmd)); + if (!error) + break; - dev_err(&client->dev, "resume command failed: %d\n", error); + dev_err(&client->dev, + "resume command failed: %d\n", error); + } + } else { + elants_i2c_power_on(ts); + elants_i2c_initialize(ts); } ts->state = ELAN_STATE_NORMAL; -- cgit v1.3-6-gb490 From 9f6a07b67fc032fce28248da62d9342fd4e89954 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 14 Apr 2015 18:18:34 -0700 Subject: Input: elants_i2c - enable asynchronous probing It takes a bit of time to go through controller power up sequence and initialization. To not stall the overall boot progress let's probe the controller asynchronously, given that userspace is usually prepared for hot-plugging of input devices and thus does not rely on particular ordering. Signed-off-by: Dmitry Torokhov Reviewed-by: Benson Leung Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elants_i2c.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 19122652e71b..6f7155641591 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1410,6 +1410,7 @@ static struct i2c_driver elants_i2c_driver = { .pm = &elants_i2c_pm_ops, .acpi_match_table = ACPI_PTR(elants_acpi_id), .of_match_table = of_match_ptr(elants_of_match), + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; module_i2c_driver(elants_i2c_driver); -- cgit v1.3-6-gb490 From 71d0f562358c3274e78ef371dfeb71ad5e86cb91 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 5 Aug 2015 12:01:30 -0700 Subject: Input: elan_i2c - enable asynchronous probing It takes a bit of time to go through controller power up sequence and initialization. To not stall the overall boot progress let's probe the controller asynchronously, given that userspace is usually prepared for hot-plugging of input devices and thus does not rely on particular ordering. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 0a076d30be8b..67388f42ed9a 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1185,6 +1185,7 @@ static struct i2c_driver elan_driver = { .pm = &elan_pm_ops, .acpi_match_table = ACPI_PTR(elan_acpi_id), .of_match_table = of_match_ptr(elan_of_match), + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = elan_probe, .id_table = elan_id, -- cgit v1.3-6-gb490 From d855370186564b2dbfeb82547248a5e1f5f200b4 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:38 -0700 Subject: staging: comedi: me4000: remove 'dio_nchan' boardinfo All the boards supported by this driver have 32 digital I/O channels. Remove the unnecessary boardinfo. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 38 +++++++-------------------------- 1 file changed, 8 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index a8f3ca48784b..2b37c5354a33 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -194,7 +194,6 @@ struct me4000_board { int ai_diff_nchan; int ai_sh_nchan; int ex_trig_analog; - int dio_nchan; int has_counter; }; @@ -202,20 +201,17 @@ static const struct me4000_board me4000_boards[] = { [BOARD_ME4650] = { .name = "ME-4650", .ai_nchan = 16, - .dio_nchan = 32, }, [BOARD_ME4660] = { .name = "ME-4660", .ai_nchan = 32, .ai_diff_nchan = 16, - .dio_nchan = 32, .has_counter = 1, }, [BOARD_ME4660I] = { .name = "ME-4660i", .ai_nchan = 32, .ai_diff_nchan = 16, - .dio_nchan = 32, .has_counter = 1, }, [BOARD_ME4660S] = { @@ -223,7 +219,6 @@ static const struct me4000_board me4000_boards[] = { .ai_nchan = 32, .ai_diff_nchan = 16, .ai_sh_nchan = 8, - .dio_nchan = 32, .has_counter = 1, }, [BOARD_ME4660IS] = { @@ -231,7 +226,6 @@ static const struct me4000_board me4000_boards[] = { .ai_nchan = 32, .ai_diff_nchan = 16, .ai_sh_nchan = 8, - .dio_nchan = 32, .has_counter = 1, }, [BOARD_ME4670] = { @@ -240,7 +234,6 @@ static const struct me4000_board me4000_boards[] = { .ai_nchan = 32, .ai_diff_nchan = 16, .ex_trig_analog = 1, - .dio_nchan = 32, .has_counter = 1, }, [BOARD_ME4670I] = { @@ -249,7 +242,6 @@ static const struct me4000_board me4000_boards[] = { .ai_nchan = 32, .ai_diff_nchan = 16, .ex_trig_analog = 1, - .dio_nchan = 32, .has_counter = 1, }, [BOARD_ME4670S] = { @@ -259,7 +251,6 @@ static const struct me4000_board me4000_boards[] = { .ai_diff_nchan = 16, .ai_sh_nchan = 8, .ex_trig_analog = 1, - .dio_nchan = 32, .has_counter = 1, }, [BOARD_ME4670IS] = { @@ -269,7 +260,6 @@ static const struct me4000_board me4000_boards[] = { .ai_diff_nchan = 16, .ai_sh_nchan = 8, .ex_trig_analog = 1, - .dio_nchan = 32, .has_counter = 1, }, [BOARD_ME4680] = { @@ -279,7 +269,6 @@ static const struct me4000_board me4000_boards[] = { .ai_nchan = 32, .ai_diff_nchan = 16, .ex_trig_analog = 1, - .dio_nchan = 32, .has_counter = 1, }, [BOARD_ME4680I] = { @@ -289,7 +278,6 @@ static const struct me4000_board me4000_boards[] = { .ai_nchan = 32, .ai_diff_nchan = 16, .ex_trig_analog = 1, - .dio_nchan = 32, .has_counter = 1, }, [BOARD_ME4680S] = { @@ -300,7 +288,6 @@ static const struct me4000_board me4000_boards[] = { .ai_diff_nchan = 16, .ai_sh_nchan = 8, .ex_trig_analog = 1, - .dio_nchan = 32, .has_counter = 1, }, [BOARD_ME4680IS] = { @@ -311,7 +298,6 @@ static const struct me4000_board me4000_boards[] = { .ai_diff_nchan = 16, .ai_sh_nchan = 8, .ex_trig_analog = 1, - .dio_nchan = 32, .has_counter = 1, }, }; @@ -1343,23 +1329,15 @@ static int me4000_auto_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_UNUSED; } - /*========================================================================= - Digital I/O subdevice - ========================================================================*/ - + /* Digital I/O subdevice */ s = &dev->subdevices[2]; - - if (board->dio_nchan) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = board->dio_nchan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = me4000_dio_insn_bits; - s->insn_config = me4000_dio_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = me4000_dio_insn_bits; + s->insn_config = me4000_dio_insn_config; /* * Check for optoisolated ME-4000 version. If one the first -- cgit v1.3-6-gb490 From 14aa4789f0519d0d97f6bf672a077582b08f2cf6 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:39 -0700 Subject: staging: comedi: me4000: all board types have analog inputs All the boards supported by this driver have analog inputs. They just differ in the number of channels (32 or 16). Always initialize the analog input subdevice in me4000_auto_attach(). Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 39 +++++++++++++-------------------- 1 file changed, 15 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 2b37c5354a33..3d45217e9e18 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -1281,31 +1281,22 @@ static int me4000_auto_attach(struct comedi_device *dev, if (result) return result; - /*========================================================================= - Analog input subdevice - ========================================================================*/ - + /* Analog Input subdevice */ s = &dev->subdevices[0]; - - if (board->ai_nchan) { - s->type = COMEDI_SUBD_AI; - s->subdev_flags = - SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; - s->n_chan = board->ai_nchan; - s->maxdata = 0xFFFF; /* 16 bit ADC */ - s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT; - s->range_table = &me4000_ai_range; - s->insn_read = me4000_ai_insn_read; - - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->cancel = me4000_ai_cancel; - s->do_cmdtest = me4000_ai_do_cmd_test; - s->do_cmd = me4000_ai_do_cmd; - } - } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; + s->n_chan = board->ai_nchan; + s->maxdata = 0xffff; + s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT; + s->range_table = &me4000_ai_range; + s->insn_read = me4000_ai_insn_read; + + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->cancel = me4000_ai_cancel; + s->do_cmdtest = me4000_ai_do_cmd_test; + s->do_cmd = me4000_ai_do_cmd; } /*========================================================================= -- cgit v1.3-6-gb490 From 31bebc030fb2a6e2e7e7ea19ce58a0f196280281 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:40 -0700 Subject: staging: comedi: me4000: only set SDF_DIFF when supported Some of the boards supported by this driver do not have differential analog inputs. Only set the SDF_DIFF subdev_flag when the board supports it. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 3d45217e9e18..171749b06ef2 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -1284,7 +1284,9 @@ static int me4000_auto_attach(struct comedi_device *dev, /* Analog Input subdevice */ s = &dev->subdevices[0]; s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; + if (board->ai_diff_nchan) + s->subdev_flags |= SDF_DIFF; s->n_chan = board->ai_nchan; s->maxdata = 0xffff; s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT; -- cgit v1.3-6-gb490 From 03611e5491e488f30a5b7653e02ee65032cfba14 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:41 -0700 Subject: staging: comedi: me4000: remove 'chan' check in me4000_ai_insn_read() The comedi core validates that the 'chan' is valid for the subdevice before calling the (*insn_read) operation. Remove the unnecessary check. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 171749b06ef2..d6b7adc19056 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -477,11 +477,6 @@ static int me4000_ai_insn_read(struct comedi_device *dev, switch (aref) { case AREF_GROUND: case AREF_COMMON: - if (chan >= board->ai_nchan) { - dev_err(dev->class_dev, - "Analog input is not available\n"); - return -EINVAL; - } entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED | chan; break; -- cgit v1.3-6-gb490 From 1a02387063fbd32f51c98540499b90acc8b4317f Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:42 -0700 Subject: staging: comedi: me4000: remove 'board' from me4000_ai_insn_read() The 'board' pointer is only used in this function to verify that the 'chan' is valid for an aref of AREF_DIFF. For differential inputs, the maximum channel is half the subdevice 'n_chan'. Use that instead and remove the 'board' variable. Also, the comedi core does not validate the aref flags. Add a check to ensure that the subdevice actually supports the AREF_DIFF mode. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index d6b7adc19056..335fafc73a94 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -436,10 +436,10 @@ static void me4000_reset(struct comedi_device *dev) ===========================================================================*/ static int me4000_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *subdevice, - struct comedi_insn *insn, unsigned int *data) + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - const struct me4000_board *board = dev->board_ptr; int chan = CR_CHAN(insn->chanspec); int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); @@ -481,13 +481,19 @@ static int me4000_ai_insn_read(struct comedi_device *dev, break; case AREF_DIFF: + if (!(s->subdev_flags && SDF_DIFF)) { + dev_err(dev->class_dev, + "Differential inputs are not available\n"); + return -EINVAL; + } + if (rang == 0 || rang == 1) { dev_err(dev->class_dev, "Range must be bipolar when aref = diff\n"); return -EINVAL; } - if (chan >= board->ai_diff_nchan) { + if (chan >= (s->n_chan / 2)) { dev_err(dev->class_dev, "Analog input is not available\n"); return -EINVAL; -- cgit v1.3-6-gb490 From 4ec85dadb7c7bb6cf84f18b7207f60efe0095d72 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:43 -0700 Subject: staging: comedi: me4000: remove 'board' from me4000_ai_check_chanlist() The maximum differential channel is half the subdevice 'n_chan'. Use that instead and remove the need for the 'board' variable. Also, the comedi core does no validate the aref flags. Add a check to ensure that the subdevice actually supports the AREF_DIFF mode. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 335fafc73a94..008929e8d3fe 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -568,8 +568,6 @@ static int me4000_ai_check_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - const struct me4000_board *board = dev->board_ptr; - unsigned int max_diff_chan = board->ai_diff_nchan; unsigned int aref0 = CR_AREF(cmd->chanlist[0]); int i; @@ -585,7 +583,13 @@ static int me4000_ai_check_chanlist(struct comedi_device *dev, } if (aref == AREF_DIFF) { - if (chan >= max_diff_chan) { + if (!(s->subdev_flags && SDF_DIFF)) { + dev_err(dev->class_dev, + "Differential inputs are not available\n"); + return -EINVAL; + } + + if (chan >= (s->n_chan / 2)) { dev_dbg(dev->class_dev, "Channel number to high\n"); return -EINVAL; -- cgit v1.3-6-gb490 From 13a463ae576d2e238647b2e2bbfda0512b22dabf Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:44 -0700 Subject: staging: comedi: me4000: make boardinfo flags bit-fields Change the boardinfo 'has_counter' and 'ai_trig_analog' flags into bit-fields to save a bit of space. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 008929e8d3fe..cc05c88bf13e 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -193,8 +193,8 @@ struct me4000_board { int ai_nchan; int ai_diff_nchan; int ai_sh_nchan; - int ex_trig_analog; - int has_counter; + unsigned int ex_trig_analog:1; + unsigned int has_counter:1; }; static const struct me4000_board me4000_boards[] = { -- cgit v1.3-6-gb490 From 56f71de601468efc12d90db9cad6ccec062b74b8 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:45 -0700 Subject: staging: comedi: me4000: refactor 'ai_diff_nchan' boardinfo This member of the boardinfo is only used as a flag indicating that the board supports differential analog inputs. Convert the member to a bit- field to save a bit of space. For aesthetics, rename the member to 'can_do_diff_ai'. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index cc05c88bf13e..7eade91a04f6 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -191,8 +191,8 @@ struct me4000_board { int ao_nchan; int ao_fifo; int ai_nchan; - int ai_diff_nchan; int ai_sh_nchan; + unsigned int can_do_diff_ai:1; unsigned int ex_trig_analog:1; unsigned int has_counter:1; }; @@ -205,34 +205,34 @@ static const struct me4000_board me4000_boards[] = { [BOARD_ME4660] = { .name = "ME-4660", .ai_nchan = 32, - .ai_diff_nchan = 16, + .can_do_diff_ai = 1, .has_counter = 1, }, [BOARD_ME4660I] = { .name = "ME-4660i", .ai_nchan = 32, - .ai_diff_nchan = 16, + .can_do_diff_ai = 1, .has_counter = 1, }, [BOARD_ME4660S] = { .name = "ME-4660s", .ai_nchan = 32, - .ai_diff_nchan = 16, .ai_sh_nchan = 8, + .can_do_diff_ai = 1, .has_counter = 1, }, [BOARD_ME4660IS] = { .name = "ME-4660is", .ai_nchan = 32, - .ai_diff_nchan = 16, .ai_sh_nchan = 8, + .can_do_diff_ai = 1, .has_counter = 1, }, [BOARD_ME4670] = { .name = "ME-4670", .ao_nchan = 4, .ai_nchan = 32, - .ai_diff_nchan = 16, + .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_counter = 1, }, @@ -240,7 +240,7 @@ static const struct me4000_board me4000_boards[] = { .name = "ME-4670i", .ao_nchan = 4, .ai_nchan = 32, - .ai_diff_nchan = 16, + .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_counter = 1, }, @@ -248,8 +248,8 @@ static const struct me4000_board me4000_boards[] = { .name = "ME-4670s", .ao_nchan = 4, .ai_nchan = 32, - .ai_diff_nchan = 16, .ai_sh_nchan = 8, + .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_counter = 1, }, @@ -257,8 +257,8 @@ static const struct me4000_board me4000_boards[] = { .name = "ME-4670is", .ao_nchan = 4, .ai_nchan = 32, - .ai_diff_nchan = 16, .ai_sh_nchan = 8, + .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_counter = 1, }, @@ -267,7 +267,7 @@ static const struct me4000_board me4000_boards[] = { .ao_nchan = 4, .ao_fifo = 4, .ai_nchan = 32, - .ai_diff_nchan = 16, + .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_counter = 1, }, @@ -276,7 +276,7 @@ static const struct me4000_board me4000_boards[] = { .ao_nchan = 4, .ao_fifo = 4, .ai_nchan = 32, - .ai_diff_nchan = 16, + .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_counter = 1, }, @@ -285,8 +285,8 @@ static const struct me4000_board me4000_boards[] = { .ao_nchan = 4, .ao_fifo = 4, .ai_nchan = 32, - .ai_diff_nchan = 16, .ai_sh_nchan = 8, + .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_counter = 1, }, @@ -295,8 +295,8 @@ static const struct me4000_board me4000_boards[] = { .ao_nchan = 4, .ao_fifo = 4, .ai_nchan = 32, - .ai_diff_nchan = 16, .ai_sh_nchan = 8, + .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_counter = 1, }, @@ -1290,7 +1290,7 @@ static int me4000_auto_attach(struct comedi_device *dev, s = &dev->subdevices[0]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; - if (board->ai_diff_nchan) + if (board->can_do_diff_ai) s->subdev_flags |= SDF_DIFF; s->n_chan = board->ai_nchan; s->maxdata = 0xffff; -- cgit v1.3-6-gb490 From aed9b66316d2c6eb22c2a80a8af4d1f7beffe309 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:46 -0700 Subject: staging: comedi: me4000: refactor 'ao_nchan' boardinfo For the boards that have analog output capability, there are always 4 analog output channels. Convert the 'ao_nchan' member of the boardinfo into a bit-field, 'has_ao', to save a bit of space and set the analog output subdevice 'n_chan' to 4 when supported. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 7eade91a04f6..2f11cdd3eefb 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -188,12 +188,12 @@ enum me4000_boardid { struct me4000_board { const char *name; - int ao_nchan; int ao_fifo; int ai_nchan; int ai_sh_nchan; unsigned int can_do_diff_ai:1; unsigned int ex_trig_analog:1; + unsigned int has_ao:1; unsigned int has_counter:1; }; @@ -230,74 +230,74 @@ static const struct me4000_board me4000_boards[] = { }, [BOARD_ME4670] = { .name = "ME-4670", - .ao_nchan = 4, .ai_nchan = 32, .can_do_diff_ai = 1, .ex_trig_analog = 1, + .has_ao = 1, .has_counter = 1, }, [BOARD_ME4670I] = { .name = "ME-4670i", - .ao_nchan = 4, .ai_nchan = 32, .can_do_diff_ai = 1, .ex_trig_analog = 1, + .has_ao = 1, .has_counter = 1, }, [BOARD_ME4670S] = { .name = "ME-4670s", - .ao_nchan = 4, .ai_nchan = 32, .ai_sh_nchan = 8, .can_do_diff_ai = 1, .ex_trig_analog = 1, + .has_ao = 1, .has_counter = 1, }, [BOARD_ME4670IS] = { .name = "ME-4670is", - .ao_nchan = 4, .ai_nchan = 32, .ai_sh_nchan = 8, .can_do_diff_ai = 1, .ex_trig_analog = 1, + .has_ao = 1, .has_counter = 1, }, [BOARD_ME4680] = { .name = "ME-4680", - .ao_nchan = 4, .ao_fifo = 4, .ai_nchan = 32, .can_do_diff_ai = 1, .ex_trig_analog = 1, + .has_ao = 1, .has_counter = 1, }, [BOARD_ME4680I] = { .name = "ME-4680i", - .ao_nchan = 4, .ao_fifo = 4, .ai_nchan = 32, .can_do_diff_ai = 1, .ex_trig_analog = 1, + .has_ao = 1, .has_counter = 1, }, [BOARD_ME4680S] = { .name = "ME-4680s", - .ao_nchan = 4, .ao_fifo = 4, .ai_nchan = 32, .ai_sh_nchan = 8, .can_do_diff_ai = 1, .ex_trig_analog = 1, + .has_ao = 1, .has_counter = 1, }, [BOARD_ME4680IS] = { .name = "ME-4680is", - .ao_nchan = 4, .ao_fifo = 4, .ai_nchan = 32, .ai_sh_nchan = 8, .can_do_diff_ai = 1, .ex_trig_analog = 1, + .has_ao = 1, .has_counter = 1, }, }; @@ -1312,10 +1312,10 @@ static int me4000_auto_attach(struct comedi_device *dev, s = &dev->subdevices[1]; - if (board->ao_nchan) { + if (board->has_ao) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_COMMON | SDF_GROUND; - s->n_chan = board->ao_nchan; + s->n_chan = 4; s->maxdata = 0xFFFF; /* 16 bit DAC */ s->range_table = &range_bipolar10; s->insn_write = me4000_ao_insn_write; -- cgit v1.3-6-gb490 From 77714d31f6cd6886dadbdb34cf32eddc2853eb50 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:47 -0700 Subject: staging: comedi: me4000: refactor 'ao_fifo' boardinfo This member of the boardinfo is always '4' for the boards that have an analog output FIFO. Covert it to a bit-field, 'has_ao_fifo', to save a bit of space. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 2f11cdd3eefb..1d88c7172347 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -188,12 +188,12 @@ enum me4000_boardid { struct me4000_board { const char *name; - int ao_fifo; int ai_nchan; int ai_sh_nchan; unsigned int can_do_diff_ai:1; unsigned int ex_trig_analog:1; unsigned int has_ao:1; + unsigned int has_ao_fifo:1; unsigned int has_counter:1; }; @@ -264,40 +264,40 @@ static const struct me4000_board me4000_boards[] = { }, [BOARD_ME4680] = { .name = "ME-4680", - .ao_fifo = 4, .ai_nchan = 32, .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_ao = 1, + .has_ao_fifo = 1, .has_counter = 1, }, [BOARD_ME4680I] = { .name = "ME-4680i", - .ao_fifo = 4, .ai_nchan = 32, .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_ao = 1, + .has_ao_fifo = 1, .has_counter = 1, }, [BOARD_ME4680S] = { .name = "ME-4680s", - .ao_fifo = 4, .ai_nchan = 32, .ai_sh_nchan = 8, .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_ao = 1, + .has_ao_fifo = 1, .has_counter = 1, }, [BOARD_ME4680IS] = { .name = "ME-4680is", - .ao_fifo = 4, .ai_nchan = 32, .ai_sh_nchan = 8, .can_do_diff_ai = 1, .ex_trig_analog = 1, .has_ao = 1, + .has_ao_fifo = 1, .has_counter = 1, }, }; -- cgit v1.3-6-gb490 From e5f663502228edd9c540c9d550dea59cbdb13d3a Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:48 -0700 Subject: staging: comedi: me4000: refactor 'ai_sh_nchan' boardinfo Some of the boards supported by this driver can do analog input sample & hold on 8 of the channels. The 'ai_sh_nchan' member of the boardinfo is used to indicate which boards support this feature. To save a bit of space, convert this member to a bit-field, 'can_do_sh_ai'. Note, this feature is not currently supported. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 1d88c7172347..2a975e6f9e2a 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -189,8 +189,8 @@ enum me4000_boardid { struct me4000_board { const char *name; int ai_nchan; - int ai_sh_nchan; unsigned int can_do_diff_ai:1; + unsigned int can_do_sh_ai:1; /* sample & hold (8 channels) */ unsigned int ex_trig_analog:1; unsigned int has_ao:1; unsigned int has_ao_fifo:1; @@ -217,15 +217,15 @@ static const struct me4000_board me4000_boards[] = { [BOARD_ME4660S] = { .name = "ME-4660s", .ai_nchan = 32, - .ai_sh_nchan = 8, .can_do_diff_ai = 1, + .can_do_sh_ai = 1, .has_counter = 1, }, [BOARD_ME4660IS] = { .name = "ME-4660is", .ai_nchan = 32, - .ai_sh_nchan = 8, .can_do_diff_ai = 1, + .can_do_sh_ai = 1, .has_counter = 1, }, [BOARD_ME4670] = { @@ -247,8 +247,8 @@ static const struct me4000_board me4000_boards[] = { [BOARD_ME4670S] = { .name = "ME-4670s", .ai_nchan = 32, - .ai_sh_nchan = 8, .can_do_diff_ai = 1, + .can_do_sh_ai = 1, .ex_trig_analog = 1, .has_ao = 1, .has_counter = 1, @@ -256,8 +256,8 @@ static const struct me4000_board me4000_boards[] = { [BOARD_ME4670IS] = { .name = "ME-4670is", .ai_nchan = 32, - .ai_sh_nchan = 8, .can_do_diff_ai = 1, + .can_do_sh_ai = 1, .ex_trig_analog = 1, .has_ao = 1, .has_counter = 1, @@ -283,8 +283,8 @@ static const struct me4000_board me4000_boards[] = { [BOARD_ME4680S] = { .name = "ME-4680s", .ai_nchan = 32, - .ai_sh_nchan = 8, .can_do_diff_ai = 1, + .can_do_sh_ai = 1, .ex_trig_analog = 1, .has_ao = 1, .has_ao_fifo = 1, @@ -293,8 +293,8 @@ static const struct me4000_board me4000_boards[] = { [BOARD_ME4680IS] = { .name = "ME-4680is", .ai_nchan = 32, - .ai_sh_nchan = 8, .can_do_diff_ai = 1, + .can_do_sh_ai = 1, .ex_trig_analog = 1, .has_ao = 1, .has_ao_fifo = 1, -- cgit v1.3-6-gb490 From 3674a87ebe73be57fe412b8906b0004c6372bac4 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:49 -0700 Subject: staging: comedi: me4000: rename local variables used for 'dev->private' In comedi drivers the local variable used for the dev->private pointer is normally named 'devpriv'. For aesthetics, rename the variables in this driver. Also, rename the struct to follow the norm. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 2a975e6f9e2a..0a85ea5ccdca 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -166,7 +166,7 @@ broken. #define ME4000_AI_CHANNEL_LIST_COUNT 1024 -struct me4000_info { +struct me4000_private { unsigned long plx_regbase; }; @@ -316,7 +316,7 @@ static int me4000_xilinx_download(struct comedi_device *dev, unsigned long context) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - struct me4000_info *info = dev->private; + struct me4000_private *devpriv = dev->private; unsigned long xilinx_iobase = pci_resource_start(pcidev, 5); unsigned int file_length; unsigned int val; @@ -329,28 +329,28 @@ static int me4000_xilinx_download(struct comedi_device *dev, * Set PLX local interrupt 2 polarity to high. * Interrupt is thrown by init pin of xilinx. */ - outl(PLX9052_INTCSR_LI2POL, info->plx_regbase + PLX9052_INTCSR); + outl(PLX9052_INTCSR_LI2POL, devpriv->plx_regbase + PLX9052_INTCSR); /* Set /CS and /WRITE of the Xilinx */ - val = inl(info->plx_regbase + PLX9052_CNTRL); + val = inl(devpriv->plx_regbase + PLX9052_CNTRL); val |= PLX9052_CNTRL_UIO2_DATA; - outl(val, info->plx_regbase + PLX9052_CNTRL); + outl(val, devpriv->plx_regbase + PLX9052_CNTRL); /* Init Xilinx with CS1 */ inb(xilinx_iobase + 0xC8); /* Wait until /INIT pin is set */ udelay(20); - val = inl(info->plx_regbase + PLX9052_INTCSR); + val = inl(devpriv->plx_regbase + PLX9052_INTCSR); if (!(val & PLX9052_INTCSR_LI2STAT)) { dev_err(dev->class_dev, "Can't init Xilinx\n"); return -EIO; } /* Reset /CS and /WRITE of the Xilinx */ - val = inl(info->plx_regbase + PLX9052_CNTRL); + val = inl(devpriv->plx_regbase + PLX9052_CNTRL); val &= ~PLX9052_CNTRL_UIO2_DATA; - outl(val, info->plx_regbase + PLX9052_CNTRL); + outl(val, devpriv->plx_regbase + PLX9052_CNTRL); /* Download Xilinx firmware */ file_length = (((unsigned int)data[0] & 0xff) << 24) + @@ -364,7 +364,7 @@ static int me4000_xilinx_download(struct comedi_device *dev, udelay(10); /* Check if BUSY flag is low */ - val = inl(info->plx_regbase + PLX9052_CNTRL); + val = inl(devpriv->plx_regbase + PLX9052_CNTRL); if (val & PLX9052_CNTRL_UIO1_DATA) { dev_err(dev->class_dev, "Xilinx is still busy (i = %d)\n", i); @@ -373,7 +373,7 @@ static int me4000_xilinx_download(struct comedi_device *dev, } /* If done flag is high download was successful */ - val = inl(info->plx_regbase + PLX9052_CNTRL); + val = inl(devpriv->plx_regbase + PLX9052_CNTRL); if (!(val & PLX9052_CNTRL_UIO0_DATA)) { dev_err(dev->class_dev, "DONE flag is not set\n"); dev_err(dev->class_dev, "Download not successful\n"); @@ -381,25 +381,25 @@ static int me4000_xilinx_download(struct comedi_device *dev, } /* Set /CS and /WRITE */ - val = inl(info->plx_regbase + PLX9052_CNTRL); + val = inl(devpriv->plx_regbase + PLX9052_CNTRL); val |= PLX9052_CNTRL_UIO2_DATA; - outl(val, info->plx_regbase + PLX9052_CNTRL); + outl(val, devpriv->plx_regbase + PLX9052_CNTRL); return 0; } static void me4000_reset(struct comedi_device *dev) { - struct me4000_info *info = dev->private; + struct me4000_private *devpriv = dev->private; unsigned int val; int chan; /* Make a hardware reset */ - val = inl(info->plx_regbase + PLX9052_CNTRL); + val = inl(devpriv->plx_regbase + PLX9052_CNTRL); val |= PLX9052_CNTRL_PCI_RESET; - outl(val, info->plx_regbase + PLX9052_CNTRL); + outl(val, devpriv->plx_regbase + PLX9052_CNTRL); val &= ~PLX9052_CNTRL_PCI_RESET; - outl(val, info->plx_regbase + PLX9052_CNTRL); + outl(val, devpriv->plx_regbase + PLX9052_CNTRL); /* 0x8000 to the DACs means an output voltage of 0V */ for (chan = 0; chan < 4; chan++) @@ -417,7 +417,7 @@ static void me4000_reset(struct comedi_device *dev) /* Enable interrupts on the PLX */ outl(PLX9052_INTCSR_LI1ENAB | PLX9052_INTCSR_LI1POL | - PLX9052_INTCSR_PCIENAB, info->plx_regbase + PLX9052_INTCSR); + PLX9052_INTCSR_PCIENAB, devpriv->plx_regbase + PLX9052_INTCSR); /* Set the adustment register for AO demux */ outl(ME4000_AO_DEMUX_ADJUST_VALUE, @@ -1244,7 +1244,7 @@ static int me4000_auto_attach(struct comedi_device *dev, { struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct me4000_board *board = NULL; - struct me4000_info *info; + struct me4000_private *devpriv; struct comedi_subdevice *s; int result; @@ -1255,17 +1255,17 @@ static int me4000_auto_attach(struct comedi_device *dev, dev->board_ptr = board; dev->board_name = board->name; - info = comedi_alloc_devpriv(dev, sizeof(*info)); - if (!info) + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; result = comedi_pci_enable(dev); if (result) return result; - info->plx_regbase = pci_resource_start(pcidev, 1); + devpriv->plx_regbase = pci_resource_start(pcidev, 1); dev->iobase = pci_resource_start(pcidev, 2); - if (!info->plx_regbase || !dev->iobase) + if (!devpriv->plx_regbase || !dev->iobase) return -ENODEV; result = comedi_load_firmware(dev, &pcidev->dev, ME4000_FIRMWARE, -- cgit v1.3-6-gb490 From 271f5aa04be0ff3d0c6fc8ccc31a6b0d3294461b Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:50 -0700 Subject: staging: comedi: me4000: remove unnecessary ME4000_AI_LIST_INPUT_SINGLE_ENDED This define evaluates to 0 and is OR'ed with the 'entry' value that is written to the ME4000_AI_CHANNEL_LIST_REG when the channel aref is a single-ended type (AREF_GROUND or AREF_COMMON). OR'ing a zero value is pretty silly, just remove it. Remove the switch() in me4000_ai_insn_read() to simplify the code. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 0a85ea5ccdca..ba3313c069d0 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -110,7 +110,6 @@ broken. #define ME4000_AI_STATUS_BIT_FSM (1 << 29) #define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH (1 << 31) #define ME4000_AI_CHANNEL_LIST_REG 0x78 -#define ME4000_AI_LIST_INPUT_SINGLE_ENDED (0 << 5) #define ME4000_AI_LIST_INPUT_DIFFERENTIAL (1 << 5) #define ME4000_AI_LIST_RANGE_BIPOLAR_10 (0 << 6) #define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 (1 << 6) @@ -474,13 +473,8 @@ static int me4000_ai_insn_read(struct comedi_device *dev, return -EINVAL; } - switch (aref) { - case AREF_GROUND: - case AREF_COMMON: - entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED | chan; - break; - - case AREF_DIFF: + entry |= chan; + if (aref == AREF_DIFF) { if (!(s->subdev_flags && SDF_DIFF)) { dev_err(dev->class_dev, "Differential inputs are not available\n"); @@ -498,11 +492,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev, "Analog input is not available\n"); return -EINVAL; } - entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL | chan; - break; - default: - dev_err(dev->class_dev, "Invalid aref specified\n"); - return -EINVAL; + entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; } entry |= ME4000_AI_LIST_LAST_ENTRY; @@ -703,8 +693,6 @@ static int ai_write_chanlist(struct comedi_device *dev, if (aref == AREF_DIFF) entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; - else - entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED; outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG); } -- cgit v1.3-6-gb490 From 245bd462440ca5914286c71051fdc5af506e76cb Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:51 -0700 Subject: staging: comedi: me4000: simplify analog input range programming The comedi_lrange table for the analog inputs is inverted compared to the values that need to be written to the ME4000_AI_CHANNEL_LIST_REG to select the range. Create a macro, ME4000_AI_LIST_RANGE(), to handle the inversion. Remove the old defines and simplify the code a bit. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 41 ++++++++------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index ba3313c069d0..1001d6379480 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -111,10 +111,7 @@ broken. #define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH (1 << 31) #define ME4000_AI_CHANNEL_LIST_REG 0x78 #define ME4000_AI_LIST_INPUT_DIFFERENTIAL (1 << 5) -#define ME4000_AI_LIST_RANGE_BIPOLAR_10 (0 << 6) -#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 (1 << 6) -#define ME4000_AI_LIST_RANGE_UNIPOLAR_10 (2 << 6) -#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 (3 << 6) +#define ME4000_AI_LIST_RANGE(x) ((3 - ((x) & 3)) << 6) #define ME4000_AI_LIST_LAST_ENTRY (1 << 8) #define ME4000_AI_DATA_REG 0x7c #define ME4000_AI_CHAN_TIMER_REG 0x80 @@ -301,6 +298,12 @@ static const struct me4000_board me4000_boards[] = { }, }; +/* + * NOTE: the ranges here are inverted compared to the values + * written to the ME4000_AI_CHANNEL_LIST_REG, + * + * The ME4000_AI_LIST_RANGE() macro handles the inversion. + */ static const struct comedi_lrange me4000_ai_range = { 4, { UNI_RANGE(2.5), @@ -455,24 +458,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev, return -EINVAL; } - switch (rang) { - case 0: - entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5; - break; - case 1: - entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10; - break; - case 2: - entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5; - break; - case 3: - entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; - break; - default: - dev_err(dev->class_dev, "Invalid range specified\n"); - return -EINVAL; - } - + entry |= ME4000_AI_LIST_RANGE(rang); entry |= chan; if (aref == AREF_DIFF) { if (!(s->subdev_flags && SDF_DIFF)) { @@ -680,16 +666,7 @@ static int ai_write_chanlist(struct comedi_device *dev, rang = CR_RANGE(cmd->chanlist[i]); aref = CR_AREF(cmd->chanlist[i]); - entry = chan; - - if (rang == 0) - entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5; - else if (rang == 1) - entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10; - else if (rang == 2) - entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5; - else - entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; + entry = chan | ME4000_AI_LIST_RANGE(rang); if (aref == AREF_DIFF) entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; -- cgit v1.3-6-gb490 From 518c5b64f6014192e5f9bc3bb1ebf2311e14b621 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:52 -0700 Subject: staging: comedi: me4000: fix ai_write_chanlist() Rename this function so it has namespace associated with the driver. The last entry of the chanlist needs the ME4000_AI_LIST_LAST_ENTRY bit set to end the list. Fix the function and tidy if up a bit. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 1001d6379480..5b798a63589b 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -652,25 +652,26 @@ static void ai_write_timer(struct comedi_device *dev, outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_TIMER_REG); } -static int ai_write_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) +static int me4000_ai_write_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - unsigned int entry; - unsigned int chan; - unsigned int rang; - unsigned int aref; int i; for (i = 0; i < cmd->chanlist_len; i++) { - chan = CR_CHAN(cmd->chanlist[i]); - rang = CR_RANGE(cmd->chanlist[i]); - aref = CR_AREF(cmd->chanlist[i]); + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + unsigned int entry; - entry = chan | ME4000_AI_LIST_RANGE(rang); + entry = chan | ME4000_AI_LIST_RANGE(range); if (aref == AREF_DIFF) entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; + if (i == (cmd->chanlist_len - 1)) + entry |= ME4000_AI_LIST_LAST_ENTRY; + outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG); } @@ -738,7 +739,7 @@ static int ai_prepare(struct comedi_device *dev, outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Write the channel list */ - ai_write_chanlist(dev, s, cmd); + me4000_ai_write_chanlist(dev, s, cmd); return 0; } -- cgit v1.3-6-gb490 From a0861f87185a51b44c972a01bfc9730cb9cbbc2d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:53 -0700 Subject: staging: comedi: me4000: tidy up ME4000_AI_CHANNEL_LIST_REG bit defines Use the BIT() macro to define the bits of this register. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 5b798a63589b..39dbdafdc953 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -110,9 +110,9 @@ broken. #define ME4000_AI_STATUS_BIT_FSM (1 << 29) #define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH (1 << 31) #define ME4000_AI_CHANNEL_LIST_REG 0x78 -#define ME4000_AI_LIST_INPUT_DIFFERENTIAL (1 << 5) +#define ME4000_AI_LIST_INPUT_DIFFERENTIAL BIT(5) #define ME4000_AI_LIST_RANGE(x) ((3 - ((x) & 3)) << 6) -#define ME4000_AI_LIST_LAST_ENTRY (1 << 8) +#define ME4000_AI_LIST_LAST_ENTRY BIT(8) #define ME4000_AI_DATA_REG 0x7c #define ME4000_AI_CHAN_TIMER_REG 0x80 #define ME4000_AI_CHAN_PRE_TIMER_REG 0x84 -- cgit v1.3-6-gb490 From 023c129f0a90edf1a9cf2c7ba9086f029f56d488 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:54 -0700 Subject: staging: comedi: me4000: use comedi_timeout() to wait for ai (*insn_read) Use the comedi_timeout() helper to busy-wait for the analog input end-of- conversion instead of the udelay(). Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 39dbdafdc953..4231e393c577 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -433,9 +433,18 @@ static void me4000_reset(struct comedi_device *dev) outl(0x1, dev->iobase + ME4000_DIO_CTRL_REG); } -/*============================================================================= - Analog input section - ===========================================================================*/ +static int me4000_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inl(dev->iobase + ME4000_AI_STATUS_REG); + if (status & ME4000_AI_STATUS_BIT_EF_DATA) + return 0; + return -EBUSY; +} static int me4000_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, @@ -445,10 +454,10 @@ static int me4000_ai_insn_read(struct comedi_device *dev, int chan = CR_CHAN(insn->chanspec); int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); - unsigned int entry = 0; unsigned int tmp; unsigned int lval; + int ret; if (insn->n == 0) { return 0; @@ -509,13 +518,9 @@ static int me4000_ai_insn_read(struct comedi_device *dev, /* Start conversion by dummy read */ inl(dev->iobase + ME4000_AI_START_REG); - /* Wait until ready */ - udelay(10); - if (!(inl(dev->iobase + ME4000_AI_STATUS_REG) & - ME4000_AI_STATUS_BIT_EF_DATA)) { - dev_err(dev->class_dev, "Value not available after wait\n"); - return -EIO; - } + ret = comedi_timeout(dev, s, insn, me4000_ai_eoc, 0); + if (ret) + return ret; /* Read value from data fifo */ lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; -- cgit v1.3-6-gb490 From fb7891e48fc2eac16f615e81df06b7510981ef73 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:55 -0700 Subject: staging: comedi: me4000: fix me4000_ai_insn_read() The coemdi (*insn_read) functions are supposed to read insn->n values from the hardware. Make this function work like the core expects. Use the comedi_offset_munge() helper to munge the two's complement values to offset binary. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 4231e393c577..c15e731db6c0 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -456,16 +456,8 @@ static int me4000_ai_insn_read(struct comedi_device *dev, int aref = CR_AREF(insn->chanspec); unsigned int entry = 0; unsigned int tmp; - unsigned int lval; int ret; - - if (insn->n == 0) { - return 0; - } else if (insn->n > 1) { - dev_err(dev->class_dev, "Invalid instruction length %d\n", - insn->n); - return -EINVAL; - } + int i; entry |= ME4000_AI_LIST_RANGE(rang); entry |= chan; @@ -515,18 +507,22 @@ static int me4000_ai_insn_read(struct comedi_device *dev, outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_TIMER_REG); outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG); - /* Start conversion by dummy read */ - inl(dev->iobase + ME4000_AI_START_REG); + for (i = 0; i < insn->n; i++) { + unsigned int val; - ret = comedi_timeout(dev, s, insn, me4000_ai_eoc, 0); - if (ret) - return ret; + /* start conversion by dummy read */ + inl(dev->iobase + ME4000_AI_START_REG); - /* Read value from data fifo */ - lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; - data[0] = lval ^ 0x8000; + ret = comedi_timeout(dev, s, insn, me4000_ai_eoc, 0); + if (ret) + return ret; - return 1; + /* read two's complement value and munge to offset binary */ + val = inl(dev->iobase + ME4000_AI_DATA_REG); + data[i] = comedi_offset_munge(s, val); + } + + return insn->n; } static int me4000_ai_cancel(struct comedi_device *dev, -- cgit v1.3-6-gb490 From 959717a3f67a7b7ce0bded0ec7d0e7e2e74c786c Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:56 -0700 Subject: staging: comedi: me4000: use correct types for extracted chanspec values The chanspec channel, range, and aref are unsigned int values. Use the correct types when extracting them. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index c15e731db6c0..c7136c572a8a 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -451,9 +451,9 @@ static int me4000_ai_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); - int rang = CR_RANGE(insn->chanspec); - int aref = CR_AREF(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int rang = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); unsigned int entry = 0; unsigned int tmp; int ret; @@ -1107,7 +1107,7 @@ static int me4000_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); unsigned int tmp; /* Stop any running conversion */ -- cgit v1.3-6-gb490 From e978426116ba68069b8dd1a6492ec8a958f27218 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:57 -0700 Subject: staging: comedi: me4000: use comedi_range_is_bipolar() in ai (*insn_read) Use the helper function to check the range type instead of relying on the value. For aesthetics, rename the local variable used for the range. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index c7136c572a8a..c5a677a3d0da 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -452,15 +452,14 @@ static int me4000_ai_insn_read(struct comedi_device *dev, unsigned int *data) { unsigned int chan = CR_CHAN(insn->chanspec); - unsigned int rang = CR_RANGE(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); - unsigned int entry = 0; + unsigned int entry; unsigned int tmp; int ret; int i; - entry |= ME4000_AI_LIST_RANGE(rang); - entry |= chan; + entry = chan | ME4000_AI_LIST_RANGE(range); if (aref == AREF_DIFF) { if (!(s->subdev_flags && SDF_DIFF)) { dev_err(dev->class_dev, @@ -468,7 +467,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev, return -EINVAL; } - if (rang == 0 || rang == 1) { + if (!comedi_range_is_bipolar(s, range)) { dev_err(dev->class_dev, "Range must be bipolar when aref = diff\n"); return -EINVAL; -- cgit v1.3-6-gb490 From a9b586a52a97ca537882a879de583002d74d9e27 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:58 -0700 Subject: staging: comedi: me4000: tidy up ME4000_AI_STATUS_REG bit defines Use the BIT() marco to define the bits of this register. For aesthetics, rename all the defines to remove the '_BIT' from the name. Also, use ME4000_AI_STATUS_REG instead of ME4000_AI_CTRL_REG when reading the register (they happen to be the same). Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 36 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index c5a677a3d0da..e31efa473f00 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -100,14 +100,14 @@ broken. #define ME4000_AI_CTRL_BIT_SC_IRQ (1 << 19) #define ME4000_AI_CTRL_BIT_SC_IRQ_RESET (1 << 20) #define ME4000_AI_CTRL_BIT_SC_RELOAD (1 << 21) -#define ME4000_AI_STATUS_BIT_EF_CHANNEL (1 << 22) -#define ME4000_AI_STATUS_BIT_HF_CHANNEL (1 << 23) -#define ME4000_AI_STATUS_BIT_FF_CHANNEL (1 << 24) -#define ME4000_AI_STATUS_BIT_EF_DATA (1 << 25) -#define ME4000_AI_STATUS_BIT_HF_DATA (1 << 26) -#define ME4000_AI_STATUS_BIT_FF_DATA (1 << 27) -#define ME4000_AI_STATUS_BIT_LE (1 << 28) -#define ME4000_AI_STATUS_BIT_FSM (1 << 29) +#define ME4000_AI_STATUS_EF_CHANNEL BIT(22) +#define ME4000_AI_STATUS_HF_CHANNEL BIT(23) +#define ME4000_AI_STATUS_FF_CHANNEL BIT(24) +#define ME4000_AI_STATUS_EF_DATA BIT(25) +#define ME4000_AI_STATUS_HF_DATA BIT(26) +#define ME4000_AI_STATUS_FF_DATA BIT(27) +#define ME4000_AI_STATUS_LE BIT(28) +#define ME4000_AI_STATUS_FSM BIT(29) #define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH (1 << 31) #define ME4000_AI_CHANNEL_LIST_REG 0x78 #define ME4000_AI_LIST_INPUT_DIFFERENTIAL BIT(5) @@ -441,7 +441,7 @@ static int me4000_ai_eoc(struct comedi_device *dev, unsigned int status; status = inl(dev->iobase + ME4000_AI_STATUS_REG); - if (status & ME4000_AI_STATUS_BIT_EF_DATA) + if (status & ME4000_AI_STATUS_EF_DATA) return 0; return -EBUSY; } @@ -998,11 +998,11 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & ME4000_IRQ_STATUS_BIT_AI_HF) { /* Read status register to find out what happened */ - tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); + tmp = inl(dev->iobase + ME4000_AI_STATUS_REG); - if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) && - !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) && - (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { + if (!(tmp & ME4000_AI_STATUS_FF_DATA) && + !(tmp & ME4000_AI_STATUS_HF_DATA) && + (tmp & ME4000_AI_STATUS_EF_DATA)) { c = ME4000_AI_FIFO_COUNT; /* @@ -1017,9 +1017,9 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) s->async->events |= COMEDI_CB_ERROR; dev_err(dev->class_dev, "FIFO overflow\n"); - } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) - && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) - && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { + } else if ((tmp & ME4000_AI_STATUS_FF_DATA) && + !(tmp & ME4000_AI_STATUS_HF_DATA) && + (tmp & ME4000_AI_STATUS_EF_DATA)) { c = ME4000_AI_FIFO_COUNT / 2; } else { dev_err(dev->class_dev, @@ -1079,8 +1079,8 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Poll data until fifo empty */ - while (inl(dev->iobase + ME4000_AI_CTRL_REG) & - ME4000_AI_STATUS_BIT_EF_DATA) { + while (inl(dev->iobase + ME4000_AI_STATUS_REG) & + ME4000_AI_STATUS_EF_DATA) { /* Read value from data fifo */ lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; lval ^= 0x8000; -- cgit v1.3-6-gb490 From da772ad9a83ef3db24be12f355a4a90a21c1f209 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:44:59 -0700 Subject: staging: comedi: me4000: tidy up ME4000_AI_CTRL_REG bit defines Use the BIT() marco to define the bits of this register. For aesthetics, rename all the defines to remove the '_BIT' from the name. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 123 ++++++++++++++++---------------- 1 file changed, 61 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index e31efa473f00..b54f1deb7089 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -78,28 +78,28 @@ broken. #define ME4000_AO_TIMER_REG(x) (0x10 + ME4000_AO_CHAN(x)) #define ME4000_AI_CTRL_REG 0x74 #define ME4000_AI_STATUS_REG 0x74 -#define ME4000_AI_CTRL_BIT_MODE_0 (1 << 0) -#define ME4000_AI_CTRL_BIT_MODE_1 (1 << 1) -#define ME4000_AI_CTRL_BIT_MODE_2 (1 << 2) -#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD (1 << 3) -#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP (1 << 4) -#define ME4000_AI_CTRL_BIT_STOP (1 << 5) -#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO (1 << 6) -#define ME4000_AI_CTRL_BIT_DATA_FIFO (1 << 7) -#define ME4000_AI_CTRL_BIT_FULLSCALE (1 << 8) -#define ME4000_AI_CTRL_BIT_OFFSET (1 << 9) -#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG (1 << 10) -#define ME4000_AI_CTRL_BIT_EX_TRIG (1 << 11) -#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING (1 << 12) -#define ME4000_AI_CTRL_BIT_EX_IRQ (1 << 13) -#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET (1 << 14) -#define ME4000_AI_CTRL_BIT_LE_IRQ (1 << 15) -#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET (1 << 16) -#define ME4000_AI_CTRL_BIT_HF_IRQ (1 << 17) -#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET (1 << 18) -#define ME4000_AI_CTRL_BIT_SC_IRQ (1 << 19) -#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET (1 << 20) -#define ME4000_AI_CTRL_BIT_SC_RELOAD (1 << 21) +#define ME4000_AI_CTRL_MODE_0 BIT(0) +#define ME4000_AI_CTRL_MODE_1 BIT(1) +#define ME4000_AI_CTRL_MODE_2 BIT(2) +#define ME4000_AI_CTRL_SAMPLE_HOLD BIT(3) +#define ME4000_AI_CTRL_IMMEDIATE_STOP BIT(4) +#define ME4000_AI_CTRL_STOP BIT(5) +#define ME4000_AI_CTRL_CHANNEL_FIFO BIT(6) +#define ME4000_AI_CTRL_DATA_FIFO BIT(7) +#define ME4000_AI_CTRL_FULLSCALE BIT(8) +#define ME4000_AI_CTRL_OFFSET BIT(9) +#define ME4000_AI_CTRL_EX_TRIG_ANALOG BIT(10) +#define ME4000_AI_CTRL_EX_TRIG BIT(11) +#define ME4000_AI_CTRL_EX_TRIG_FALLING BIT(12) +#define ME4000_AI_CTRL_EX_IRQ BIT(13) +#define ME4000_AI_CTRL_EX_IRQ_RESET BIT(14) +#define ME4000_AI_CTRL_LE_IRQ BIT(15) +#define ME4000_AI_CTRL_LE_IRQ_RESET BIT(16) +#define ME4000_AI_CTRL_HF_IRQ BIT(17) +#define ME4000_AI_CTRL_HF_IRQ_RESET BIT(18) +#define ME4000_AI_CTRL_SC_IRQ BIT(19) +#define ME4000_AI_CTRL_SC_IRQ_RESET BIT(20) +#define ME4000_AI_CTRL_SC_RELOAD BIT(21) #define ME4000_AI_STATUS_EF_CHANNEL BIT(22) #define ME4000_AI_STATUS_HF_CHANNEL BIT(23) #define ME4000_AI_STATUS_FF_CHANNEL BIT(24) @@ -108,7 +108,7 @@ broken. #define ME4000_AI_STATUS_FF_DATA BIT(27) #define ME4000_AI_STATUS_LE BIT(28) #define ME4000_AI_STATUS_FSM BIT(29) -#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH (1 << 31) +#define ME4000_AI_CTRL_EX_TRIG_BOTH BIT(31) #define ME4000_AI_CHANNEL_LIST_REG 0x78 #define ME4000_AI_LIST_INPUT_DIFFERENTIAL BIT(5) #define ME4000_AI_LIST_RANGE(x) ((3 - ((x) & 3)) << 6) @@ -408,7 +408,7 @@ static void me4000_reset(struct comedi_device *dev) outl(0x8000, dev->iobase + ME4000_AO_SINGLE_REG(chan)); /* Set both stop bits in the analog input control register */ - outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP, + outl(ME4000_AI_CTRL_IMMEDIATE_STOP | ME4000_AI_CTRL_STOP, dev->iobase + ME4000_AI_CTRL_REG); /* Set both stop bits in the analog output control register */ @@ -485,18 +485,17 @@ static int me4000_ai_insn_read(struct comedi_device *dev, /* Clear channel list, data fifo and both stop bits */ tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); - tmp &= ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | - ME4000_AI_CTRL_BIT_DATA_FIFO | - ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); + tmp &= ~(ME4000_AI_CTRL_CHANNEL_FIFO | ME4000_AI_CTRL_DATA_FIFO | + ME4000_AI_CTRL_STOP | ME4000_AI_CTRL_IMMEDIATE_STOP); outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Set the acquisition mode to single */ - tmp &= ~(ME4000_AI_CTRL_BIT_MODE_0 | ME4000_AI_CTRL_BIT_MODE_1 | - ME4000_AI_CTRL_BIT_MODE_2); + tmp &= ~(ME4000_AI_CTRL_MODE_0 | ME4000_AI_CTRL_MODE_1 | + ME4000_AI_CTRL_MODE_2); outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Enable channel list and data fifo */ - tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO; + tmp |= ME4000_AI_CTRL_CHANNEL_FIFO | ME4000_AI_CTRL_DATA_FIFO; outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Generate channel list entry */ @@ -531,7 +530,7 @@ static int me4000_ai_cancel(struct comedi_device *dev, /* Stop any running conversion */ tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); - tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); + tmp &= ~(ME4000_AI_CTRL_STOP | ME4000_AI_CTRL_IMMEDIATE_STOP); outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Clear the control register */ @@ -699,40 +698,40 @@ static int ai_prepare(struct comedi_device *dev, (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_TIMER)) { - tmp = ME4000_AI_CTRL_BIT_MODE_1 | - ME4000_AI_CTRL_BIT_CHANNEL_FIFO | - ME4000_AI_CTRL_BIT_DATA_FIFO; + tmp = ME4000_AI_CTRL_MODE_1 | + ME4000_AI_CTRL_CHANNEL_FIFO | + ME4000_AI_CTRL_DATA_FIFO; } else if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT && cmd->convert_src == TRIG_TIMER) { - tmp = ME4000_AI_CTRL_BIT_MODE_2 | - ME4000_AI_CTRL_BIT_CHANNEL_FIFO | - ME4000_AI_CTRL_BIT_DATA_FIFO; + tmp = ME4000_AI_CTRL_MODE_2 | + ME4000_AI_CTRL_CHANNEL_FIFO | + ME4000_AI_CTRL_DATA_FIFO; } else if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT && cmd->convert_src == TRIG_EXT) { - tmp = ME4000_AI_CTRL_BIT_MODE_0 | - ME4000_AI_CTRL_BIT_MODE_1 | - ME4000_AI_CTRL_BIT_CHANNEL_FIFO | - ME4000_AI_CTRL_BIT_DATA_FIFO; + tmp = ME4000_AI_CTRL_MODE_0 | + ME4000_AI_CTRL_MODE_1 | + ME4000_AI_CTRL_CHANNEL_FIFO | + ME4000_AI_CTRL_DATA_FIFO; } else { - tmp = ME4000_AI_CTRL_BIT_MODE_0 | - ME4000_AI_CTRL_BIT_CHANNEL_FIFO | - ME4000_AI_CTRL_BIT_DATA_FIFO; + tmp = ME4000_AI_CTRL_MODE_0 | + ME4000_AI_CTRL_CHANNEL_FIFO | + ME4000_AI_CTRL_DATA_FIFO; } /* Stop triggers */ if (cmd->stop_src == TRIG_COUNT) { outl(cmd->chanlist_len * cmd->stop_arg, dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG); - tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ; + tmp |= ME4000_AI_CTRL_HF_IRQ | ME4000_AI_CTRL_SC_IRQ; } else if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_COUNT) { outl(cmd->scan_end_arg, dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG); - tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ; + tmp |= ME4000_AI_CTRL_HF_IRQ | ME4000_AI_CTRL_SC_IRQ; } else { - tmp |= ME4000_AI_CTRL_BIT_HF_IRQ; + tmp |= ME4000_AI_CTRL_HF_IRQ; } /* Write the setup to the control register */ @@ -1009,9 +1008,9 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) * FIFO overflow, so stop conversion * and disable all interrupts */ - tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; - tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | - ME4000_AI_CTRL_BIT_SC_IRQ); + tmp |= ME4000_AI_CTRL_IMMEDIATE_STOP; + tmp &= ~(ME4000_AI_CTRL_HF_IRQ | + ME4000_AI_CTRL_SC_IRQ); outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); s->async->events |= COMEDI_CB_ERROR; @@ -1030,9 +1029,9 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) * Undefined state, so stop conversion * and disable all interrupts */ - tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; - tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | - ME4000_AI_CTRL_BIT_SC_IRQ); + tmp |= ME4000_AI_CTRL_IMMEDIATE_STOP; + tmp &= ~(ME4000_AI_CTRL_HF_IRQ | + ME4000_AI_CTRL_SC_IRQ); outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); s->async->events |= COMEDI_CB_ERROR; @@ -1050,18 +1049,18 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) * Buffer overflow, so stop conversion * and disable all interrupts */ - tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; - tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | - ME4000_AI_CTRL_BIT_SC_IRQ); + tmp |= ME4000_AI_CTRL_IMMEDIATE_STOP; + tmp &= ~(ME4000_AI_CTRL_HF_IRQ | + ME4000_AI_CTRL_SC_IRQ); outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); break; } } /* Work is done, so reset the interrupt */ - tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET; + tmp |= ME4000_AI_CTRL_HF_IRQ_RESET; outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); - tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET; + tmp &= ~ME4000_AI_CTRL_HF_IRQ_RESET; outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); } @@ -1074,8 +1073,8 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) * conversion and disable all interrupts */ tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); - tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; - tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); + tmp |= ME4000_AI_CTRL_IMMEDIATE_STOP; + tmp &= ~(ME4000_AI_CTRL_HF_IRQ | ME4000_AI_CTRL_SC_IRQ); outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Poll data until fifo empty */ @@ -1090,9 +1089,9 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) } /* Work is done, so reset the interrupt */ - tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET; + tmp |= ME4000_AI_CTRL_SC_IRQ_RESET; outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); - tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET; + tmp &= ~ME4000_AI_CTRL_SC_IRQ_RESET; outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); } -- cgit v1.3-6-gb490 From 2ec0019a2f7605aad91b7684ca404757446ea1ad Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:00 -0700 Subject: staging: comedi: me4000: tidy up ME4000_IRQ_STATUS_REG bit defines Use the BIT() marco to define the bits of this register. For aesthetics, rename all the defines to remove the '_BIT' from the name. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index b54f1deb7089..e6e1d636cd49 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -122,14 +122,14 @@ broken. #define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 #define ME4000_AI_START_REG 0x98 #define ME4000_IRQ_STATUS_REG 0x9c -#define ME4000_IRQ_STATUS_BIT_EX (1 << 0) -#define ME4000_IRQ_STATUS_BIT_LE (1 << 1) -#define ME4000_IRQ_STATUS_BIT_AI_HF (1 << 2) -#define ME4000_IRQ_STATUS_BIT_AO_0_HF (1 << 3) -#define ME4000_IRQ_STATUS_BIT_AO_1_HF (1 << 4) -#define ME4000_IRQ_STATUS_BIT_AO_2_HF (1 << 5) -#define ME4000_IRQ_STATUS_BIT_AO_3_HF (1 << 6) -#define ME4000_IRQ_STATUS_BIT_SC (1 << 7) +#define ME4000_IRQ_STATUS_EX BIT(0) +#define ME4000_IRQ_STATUS_LE BIT(1) +#define ME4000_IRQ_STATUS_AI_HF BIT(2) +#define ME4000_IRQ_STATUS_AO_0_HF BIT(3) +#define ME4000_IRQ_STATUS_AO_1_HF BIT(4) +#define ME4000_IRQ_STATUS_AO_2_HF BIT(5) +#define ME4000_IRQ_STATUS_AO_3_HF BIT(6) +#define ME4000_IRQ_STATUS_SC BIT(7) #define ME4000_DIO_PORT_0_REG 0xa0 #define ME4000_DIO_PORT_1_REG 0xa4 #define ME4000_DIO_PORT_2_REG 0xa8 @@ -995,7 +995,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) return IRQ_NONE; if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & - ME4000_IRQ_STATUS_BIT_AI_HF) { + ME4000_IRQ_STATUS_AI_HF) { /* Read status register to find out what happened */ tmp = inl(dev->iobase + ME4000_AI_STATUS_REG); @@ -1065,7 +1065,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) } if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & - ME4000_IRQ_STATUS_BIT_SC) { + ME4000_IRQ_STATUS_SC) { s->async->events |= COMEDI_CB_EOA; /* -- cgit v1.3-6-gb490 From 4831748e7001b998adc209241f2d1fe9cd5c55c8 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:01 -0700 Subject: staging: comedi: me4000: tidy up ME4000_AO_STATUS_REG bit defines Use the BIT() marco to define the bits of this register. For aesthetics, rename all the defines to remove the '_BIT' from the name. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index e6e1d636cd49..a38ad886d802 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -69,10 +69,10 @@ broken. #define ME4000_AO_CTRL_BIT_ENABLE_IRQ (1 << 9) #define ME4000_AO_CTRL_BIT_RESET_IRQ (1 << 10) #define ME4000_AO_STATUS_REG(x) (0x04 + ME4000_AO_CHAN(x)) -#define ME4000_AO_STATUS_BIT_FSM (1 << 0) -#define ME4000_AO_STATUS_BIT_FF (1 << 1) -#define ME4000_AO_STATUS_BIT_HF (1 << 2) -#define ME4000_AO_STATUS_BIT_EF (1 << 3) +#define ME4000_AO_STATUS_FSM BIT(0) +#define ME4000_AO_STATUS_FF BIT(1) +#define ME4000_AO_STATUS_HF BIT(2) +#define ME4000_AO_STATUS_EF BIT(3) #define ME4000_AO_FIFO_REG(x) (0x08 + ME4000_AO_CHAN(x)) #define ME4000_AO_SINGLE_REG(x) (0x0c + ME4000_AO_CHAN(x)) #define ME4000_AO_TIMER_REG(x) (0x10 + ME4000_AO_CHAN(x)) -- cgit v1.3-6-gb490 From 7e92a5eba35e801c2af07814d400858e8f290cb9 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:02 -0700 Subject: staging: comedi: me4000: tidy up ME4000_AO_CTRL_REG bit defines Use the BIT() marco to define the bits of this register. For aesthetics, rename all the defines to remove the '_BIT' from the name. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index a38ad886d802..a40b3017183f 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -57,17 +57,16 @@ broken. #define ME4000_AO_CHAN(x) ((x) * 0x18) #define ME4000_AO_CTRL_REG(x) (0x00 + ME4000_AO_CHAN(x)) -#define ME4000_AO_CTRL_BIT_MODE_0 (1 << 0) -#define ME4000_AO_CTRL_BIT_MODE_1 (1 << 1) -#define ME4000_AO_CTRL_MASK_MODE (3 << 0) -#define ME4000_AO_CTRL_BIT_STOP (1 << 2) -#define ME4000_AO_CTRL_BIT_ENABLE_FIFO (1 << 3) -#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG (1 << 4) -#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE (1 << 5) -#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP (1 << 7) -#define ME4000_AO_CTRL_BIT_ENABLE_DO (1 << 8) -#define ME4000_AO_CTRL_BIT_ENABLE_IRQ (1 << 9) -#define ME4000_AO_CTRL_BIT_RESET_IRQ (1 << 10) +#define ME4000_AO_CTRL_MODE_0 BIT(0) +#define ME4000_AO_CTRL_MODE_1 BIT(1) +#define ME4000_AO_CTRL_STOP BIT(2) +#define ME4000_AO_CTRL_ENABLE_FIFO BIT(3) +#define ME4000_AO_CTRL_ENABLE_EX_TRIG BIT(4) +#define ME4000_AO_CTRL_EX_TRIG_EDGE BIT(5) +#define ME4000_AO_CTRL_IMMEDIATE_STOP BIT(7) +#define ME4000_AO_CTRL_ENABLE_DO BIT(8) +#define ME4000_AO_CTRL_ENABLE_IRQ BIT(9) +#define ME4000_AO_CTRL_RESET_IRQ BIT(10) #define ME4000_AO_STATUS_REG(x) (0x04 + ME4000_AO_CHAN(x)) #define ME4000_AO_STATUS_FSM BIT(0) #define ME4000_AO_STATUS_FF BIT(1) @@ -412,7 +411,7 @@ static void me4000_reset(struct comedi_device *dev) dev->iobase + ME4000_AI_CTRL_REG); /* Set both stop bits in the analog output control register */ - val = ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP; + val = ME4000_AO_CTRL_IMMEDIATE_STOP | ME4000_AO_CTRL_STOP; for (chan = 0; chan < 4; chan++) outl(val, dev->iobase + ME4000_AO_CTRL_REG(chan)); @@ -1110,7 +1109,7 @@ static int me4000_ao_insn_write(struct comedi_device *dev, /* Stop any running conversion */ tmp = inl(dev->iobase + ME4000_AO_CTRL_REG(chan)); - tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP; + tmp |= ME4000_AO_CTRL_IMMEDIATE_STOP; outl(tmp, dev->iobase + ME4000_AO_CTRL_REG(chan)); /* Clear control register and set to single mode */ -- cgit v1.3-6-gb490 From 55fb972ee8881e665c9251fa6cb806ab6e1bcadc Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:03 -0700 Subject: staging: comedi: me4000: tidy up ME4000_DIO_CTRL_REG bit defines Use the BIT() marco to define the bits of this register. For aesthetics, rename all the defines to remove the '_BIT' from the name. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 51 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index a40b3017183f..97c243fbaba0 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -136,20 +136,20 @@ broken. #define ME4000_DIO_DIR_REG 0xb0 #define ME4000_AO_LOADSETREG_XX 0xb4 #define ME4000_DIO_CTRL_REG 0xb8 -#define ME4000_DIO_CTRL_BIT_MODE_0 (1 << 0) -#define ME4000_DIO_CTRL_BIT_MODE_1 (1 << 1) -#define ME4000_DIO_CTRL_BIT_MODE_2 (1 << 2) -#define ME4000_DIO_CTRL_BIT_MODE_3 (1 << 3) -#define ME4000_DIO_CTRL_BIT_MODE_4 (1 << 4) -#define ME4000_DIO_CTRL_BIT_MODE_5 (1 << 5) -#define ME4000_DIO_CTRL_BIT_MODE_6 (1 << 6) -#define ME4000_DIO_CTRL_BIT_MODE_7 (1 << 7) -#define ME4000_DIO_CTRL_BIT_FUNCTION_0 (1 << 8) -#define ME4000_DIO_CTRL_BIT_FUNCTION_1 (1 << 9) -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 (1 << 10) -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 (1 << 11) -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 (1 << 12) -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 (1 << 13) +#define ME4000_DIO_CTRL_MODE_0 BIT(0) +#define ME4000_DIO_CTRL_MODE_1 BIT(1) +#define ME4000_DIO_CTRL_MODE_2 BIT(2) +#define ME4000_DIO_CTRL_MODE_3 BIT(3) +#define ME4000_DIO_CTRL_MODE_4 BIT(4) +#define ME4000_DIO_CTRL_MODE_5 BIT(5) +#define ME4000_DIO_CTRL_MODE_6 BIT(6) +#define ME4000_DIO_CTRL_MODE_7 BIT(7) +#define ME4000_DIO_CTRL_FUNCTION_0 BIT(8) +#define ME4000_DIO_CTRL_FUNCTION_1 BIT(9) +#define ME4000_DIO_CTRL_FIFO_HIGH_0 BIT(10) +#define ME4000_DIO_CTRL_FIFO_HIGH_1 BIT(11) +#define ME4000_DIO_CTRL_FIFO_HIGH_2 BIT(12) +#define ME4000_DIO_CTRL_FIFO_HIGH_3 BIT(13) #define ME4000_AO_DEMUX_ADJUST_REG 0xbc #define ME4000_AO_DEMUX_ADJUST_VALUE 0x4c #define ME4000_AI_SAMPLE_COUNTER_REG 0xc0 @@ -1172,18 +1172,18 @@ static int me4000_dio_insn_config(struct comedi_device *dev, return ret; tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG); - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | ME4000_DIO_CTRL_BIT_MODE_1 | - ME4000_DIO_CTRL_BIT_MODE_2 | ME4000_DIO_CTRL_BIT_MODE_3 | - ME4000_DIO_CTRL_BIT_MODE_4 | ME4000_DIO_CTRL_BIT_MODE_5 | - ME4000_DIO_CTRL_BIT_MODE_6 | ME4000_DIO_CTRL_BIT_MODE_7); + tmp &= ~(ME4000_DIO_CTRL_MODE_0 | ME4000_DIO_CTRL_MODE_1 | + ME4000_DIO_CTRL_MODE_2 | ME4000_DIO_CTRL_MODE_3 | + ME4000_DIO_CTRL_MODE_4 | ME4000_DIO_CTRL_MODE_5 | + ME4000_DIO_CTRL_MODE_6 | ME4000_DIO_CTRL_MODE_7); if (s->io_bits & 0x000000ff) - tmp |= ME4000_DIO_CTRL_BIT_MODE_0; + tmp |= ME4000_DIO_CTRL_MODE_0; if (s->io_bits & 0x0000ff00) - tmp |= ME4000_DIO_CTRL_BIT_MODE_2; + tmp |= ME4000_DIO_CTRL_MODE_2; if (s->io_bits & 0x00ff0000) - tmp |= ME4000_DIO_CTRL_BIT_MODE_4; + tmp |= ME4000_DIO_CTRL_MODE_4; if (s->io_bits & 0xff000000) - tmp |= ME4000_DIO_CTRL_BIT_MODE_6; + tmp |= ME4000_DIO_CTRL_MODE_6; /* * Check for optoisolated ME-4000 version. @@ -1193,9 +1193,8 @@ static int me4000_dio_insn_config(struct comedi_device *dev, if (inl(dev->iobase + ME4000_DIO_DIR_REG)) { s->io_bits |= 0x000000ff; s->io_bits &= ~0x0000ff00; - tmp |= ME4000_DIO_CTRL_BIT_MODE_0; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 | - ME4000_DIO_CTRL_BIT_MODE_3); + tmp |= ME4000_DIO_CTRL_MODE_0; + tmp &= ~(ME4000_DIO_CTRL_MODE_2 | ME4000_DIO_CTRL_MODE_3); } outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG); @@ -1307,7 +1306,7 @@ static int me4000_auto_attach(struct comedi_device *dev, */ if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) { s->io_bits |= 0xFF; - outl(ME4000_DIO_CTRL_BIT_MODE_0, + outl(ME4000_DIO_CTRL_MODE_0, dev->iobase + ME4000_DIO_DIR_REG); } -- cgit v1.3-6-gb490 From c72c4c6e3ab4e1a280ab21fd2a6063b4d37fd4ff Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:04 -0700 Subject: staging: comedi: me4000: return void from ai_round_cmd_args() This function always succeeds. Change the return type to void and remove the unnecessary error check in me4000_ai_do_cmd(). Move the function call in me4000_ai_do_cmd_test() from before Step 1 to Step 3 where the arguments are validated. There is no reason to get the values if the previous steps fail. Rename the function so it has namespace associated with the driver. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 97c243fbaba0..cd7dbb6dd281 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -580,11 +580,12 @@ static int me4000_ai_check_chanlist(struct comedi_device *dev, return 0; } -static int ai_round_cmd_args(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd, - unsigned int *init_ticks, - unsigned int *scan_ticks, unsigned int *chan_ticks) +static void me4000_ai_round_cmd_args(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd, + unsigned int *init_ticks, + unsigned int *scan_ticks, + unsigned int *chan_ticks) { int rest; @@ -630,8 +631,6 @@ static int ai_round_cmd_args(struct comedi_device *dev, (*chan_ticks)++; } } - - return 0; } static void ai_write_timer(struct comedi_device *dev, @@ -757,10 +756,8 @@ static int me4000_ai_do_cmd(struct comedi_device *dev, return err; /* Round the timer arguments */ - err = ai_round_cmd_args(dev, - s, cmd, &init_ticks, &scan_ticks, &chan_ticks); - if (err) - return err; + me4000_ai_round_cmd_args(dev, s, cmd, + &init_ticks, &scan_ticks, &chan_ticks); /* Prepare the AI for acquisition */ err = ai_prepare(dev, s, cmd, init_ticks, scan_ticks, chan_ticks); @@ -782,9 +779,6 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, unsigned int scan_ticks; int err = 0; - /* Round the timer arguments */ - ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks); - /* Step 1 : check if triggers are trivially valid */ err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); @@ -842,6 +836,11 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, cmd->chanlist_len = 1; err |= -EINVAL; } + + /* Round the timer arguments */ + me4000_ai_round_cmd_args(dev, s, cmd, + &init_ticks, &scan_ticks, &chan_ticks); + if (init_ticks < 66) { cmd->start_arg = 2000; err |= -EINVAL; -- cgit v1.3-6-gb490 From 0f97f5c92d4dcd561df1c9c064243fedf328177b Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:05 -0700 Subject: staging: comedi: me4000: move ai command timing values into private data The ai (*do_cmd_test) calls me4000_ai_round_cmd_args() to calculate the timing values needed to the command. The the command test passes, the core will then call the ai (*do_cmd) which then has to call me4000_ai_round_cmd_args() again in order to get the same values to pass to ai_prepare() in order to program the timing. Add members to the private data to allow the (*do_cmd_test) to calculate and save to values needed by ai_prepare(). Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 109 +++++++++++++++----------------- 1 file changed, 52 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index cd7dbb6dd281..ebc4307bbf17 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -163,6 +163,9 @@ broken. struct me4000_private { unsigned long plx_regbase; + unsigned int ai_init_ticks; + unsigned int ai_scan_ticks; + unsigned int ai_chan_ticks; }; enum me4000_boardid { @@ -582,71 +585,73 @@ static int me4000_ai_check_chanlist(struct comedi_device *dev, static void me4000_ai_round_cmd_args(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd, - unsigned int *init_ticks, - unsigned int *scan_ticks, - unsigned int *chan_ticks) + struct comedi_cmd *cmd) { + struct me4000_private *devpriv = dev->private; int rest; - *init_ticks = 0; - *scan_ticks = 0; - *chan_ticks = 0; + devpriv->ai_init_ticks = 0; + devpriv->ai_scan_ticks = 0; + devpriv->ai_chan_ticks = 0; if (cmd->start_arg) { - *init_ticks = (cmd->start_arg * 33) / 1000; + devpriv->ai_init_ticks = (cmd->start_arg * 33) / 1000; rest = (cmd->start_arg * 33) % 1000; if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) { if (rest > 33) - (*init_ticks)++; + devpriv->ai_init_ticks++; } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) { if (rest) - (*init_ticks)++; + devpriv->ai_init_ticks++; } } if (cmd->scan_begin_arg) { - *scan_ticks = (cmd->scan_begin_arg * 33) / 1000; + devpriv->ai_scan_ticks = (cmd->scan_begin_arg * 33) / 1000; rest = (cmd->scan_begin_arg * 33) % 1000; if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) { if (rest > 33) - (*scan_ticks)++; + devpriv->ai_scan_ticks++; } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) { if (rest) - (*scan_ticks)++; + devpriv->ai_scan_ticks++; } } if (cmd->convert_arg) { - *chan_ticks = (cmd->convert_arg * 33) / 1000; + devpriv->ai_chan_ticks = (cmd->convert_arg * 33) / 1000; rest = (cmd->convert_arg * 33) % 1000; if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_NEAREST) { if (rest > 33) - (*chan_ticks)++; + devpriv->ai_chan_ticks++; } else if ((cmd->flags & CMDF_ROUND_MASK) == CMDF_ROUND_UP) { if (rest) - (*chan_ticks)++; + devpriv->ai_chan_ticks++; } } } -static void ai_write_timer(struct comedi_device *dev, - unsigned int init_ticks, - unsigned int scan_ticks, unsigned int chan_ticks) +static void ai_write_timer(struct comedi_device *dev) { - outl(init_ticks - 1, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG); + struct me4000_private *devpriv = dev->private; + + outl(devpriv->ai_init_ticks - 1, + dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG); outl(0x0, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG); - if (scan_ticks) { - outl(scan_ticks - 1, dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG); + if (devpriv->ai_scan_ticks) { + outl(devpriv->ai_scan_ticks - 1, + dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG); outl(0x0, dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG); } - outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG); - outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_TIMER_REG); + outl(devpriv->ai_chan_ticks - 1, + dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG); + outl(devpriv->ai_chan_ticks - 1, + dev->iobase + ME4000_AI_CHAN_TIMER_REG); } static int me4000_ai_write_chanlist(struct comedi_device *dev, @@ -677,14 +682,12 @@ static int me4000_ai_write_chanlist(struct comedi_device *dev, static int ai_prepare(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd, - unsigned int init_ticks, - unsigned int scan_ticks, unsigned int chan_ticks) + struct comedi_cmd *cmd) { unsigned int tmp = 0; /* Write timer arguments */ - ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks); + ai_write_timer(dev); /* Reset control register */ outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); @@ -745,9 +748,6 @@ static int me4000_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { int err; - unsigned int init_ticks = 0; - unsigned int scan_ticks = 0; - unsigned int chan_ticks = 0; struct comedi_cmd *cmd = &s->async->cmd; /* Reset the analog input */ @@ -755,12 +755,8 @@ static int me4000_ai_do_cmd(struct comedi_device *dev, if (err) return err; - /* Round the timer arguments */ - me4000_ai_round_cmd_args(dev, s, cmd, - &init_ticks, &scan_ticks, &chan_ticks); - /* Prepare the AI for acquisition */ - err = ai_prepare(dev, s, cmd, init_ticks, scan_ticks, chan_ticks); + err = ai_prepare(dev, s, cmd); if (err) return err; @@ -774,9 +770,7 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - unsigned int init_ticks; - unsigned int chan_ticks; - unsigned int scan_ticks; + struct me4000_private *devpriv = dev->private; int err = 0; /* Step 1 : check if triggers are trivially valid */ @@ -838,18 +832,17 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, } /* Round the timer arguments */ - me4000_ai_round_cmd_args(dev, s, cmd, - &init_ticks, &scan_ticks, &chan_ticks); + me4000_ai_round_cmd_args(dev, s, cmd); - if (init_ticks < 66) { + if (devpriv->ai_init_ticks < 66) { cmd->start_arg = 2000; err |= -EINVAL; } - if (scan_ticks && scan_ticks < 67) { + if (devpriv->ai_scan_ticks && devpriv->ai_scan_ticks < 67) { cmd->scan_begin_arg = 2031; err |= -EINVAL; } - if (chan_ticks < 66) { + if (devpriv->ai_chan_ticks < 66) { cmd->convert_arg = 2000; err |= -EINVAL; } @@ -869,17 +862,18 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, cmd->scan_begin_src == TRIG_TIMER && cmd->convert_src == TRIG_TIMER) { /* Check timer arguments */ - if (init_ticks < ME4000_AI_MIN_TICKS) { + if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) { dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } - if (chan_ticks < ME4000_AI_MIN_TICKS) { + if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) { dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } - if (scan_ticks <= cmd->chanlist_len * chan_ticks) { + if (devpriv->ai_scan_ticks <= + cmd->chanlist_len * devpriv->ai_chan_ticks) { dev_err(dev->class_dev, "Invalid scan end arg\n"); /* At least one tick more */ @@ -890,12 +884,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_TIMER) { /* Check timer arguments */ - if (init_ticks < ME4000_AI_MIN_TICKS) { + if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) { dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } - if (chan_ticks < ME4000_AI_MIN_TICKS) { + if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) { dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; @@ -904,17 +898,18 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, cmd->scan_begin_src == TRIG_TIMER && cmd->convert_src == TRIG_TIMER) { /* Check timer arguments */ - if (init_ticks < ME4000_AI_MIN_TICKS) { + if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) { dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } - if (chan_ticks < ME4000_AI_MIN_TICKS) { + if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) { dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } - if (scan_ticks <= cmd->chanlist_len * chan_ticks) { + if (devpriv->ai_scan_ticks <= + cmd->chanlist_len * devpriv->ai_chan_ticks) { dev_err(dev->class_dev, "Invalid scan end arg\n"); /* At least one tick more */ @@ -925,12 +920,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_TIMER) { /* Check timer arguments */ - if (init_ticks < ME4000_AI_MIN_TICKS) { + if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) { dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } - if (chan_ticks < ME4000_AI_MIN_TICKS) { + if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) { dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; @@ -939,12 +934,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, cmd->scan_begin_src == TRIG_EXT && cmd->convert_src == TRIG_TIMER) { /* Check timer arguments */ - if (init_ticks < ME4000_AI_MIN_TICKS) { + if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) { dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } - if (chan_ticks < ME4000_AI_MIN_TICKS) { + if (devpriv->ai_chan_ticks < ME4000_AI_MIN_TICKS) { dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; @@ -953,7 +948,7 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, cmd->scan_begin_src == TRIG_EXT && cmd->convert_src == TRIG_EXT) { /* Check timer arguments */ - if (init_ticks < ME4000_AI_MIN_TICKS) { + if (devpriv->ai_init_ticks < ME4000_AI_MIN_TICKS) { dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; -- cgit v1.3-6-gb490 From 272e426ebca118cf202e4cf43dddf65ff358e953 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:06 -0700 Subject: staging: comedi: me4000: simplify ai_prepare() The ai (*do_cmd_test) validates the trigger sources in Step 2b to ensure that they are compatible. Save the 'ai_ctrl_mode' that will be used in the private data so that ai_prepare(), which is called by the ai (*do_cmd), does not have to recheck the sources in order to figure it out. Also, tidy up the stop trigger checks so that the ME4000_AI_CTRL_HF_IRQ bit is set in the common code path. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 52 ++++++++++++--------------------- 1 file changed, 18 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index ebc4307bbf17..60f62f3d434a 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -163,6 +163,7 @@ broken. struct me4000_private { unsigned long plx_regbase; + unsigned int ai_ctrl_mode; unsigned int ai_init_ticks; unsigned int ai_scan_ticks; unsigned int ai_chan_ticks; @@ -684,59 +685,35 @@ static int ai_prepare(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - unsigned int tmp = 0; + struct me4000_private *devpriv = dev->private; + unsigned int ctrl; /* Write timer arguments */ ai_write_timer(dev); /* Reset control register */ - outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); + outl(0, dev->iobase + ME4000_AI_CTRL_REG); /* Start sources */ - if ((cmd->start_src == TRIG_EXT && - cmd->scan_begin_src == TRIG_TIMER && - cmd->convert_src == TRIG_TIMER) || - (cmd->start_src == TRIG_EXT && - cmd->scan_begin_src == TRIG_FOLLOW && - cmd->convert_src == TRIG_TIMER)) { - tmp = ME4000_AI_CTRL_MODE_1 | - ME4000_AI_CTRL_CHANNEL_FIFO | - ME4000_AI_CTRL_DATA_FIFO; - } else if (cmd->start_src == TRIG_EXT && - cmd->scan_begin_src == TRIG_EXT && - cmd->convert_src == TRIG_TIMER) { - tmp = ME4000_AI_CTRL_MODE_2 | - ME4000_AI_CTRL_CHANNEL_FIFO | - ME4000_AI_CTRL_DATA_FIFO; - } else if (cmd->start_src == TRIG_EXT && - cmd->scan_begin_src == TRIG_EXT && - cmd->convert_src == TRIG_EXT) { - tmp = ME4000_AI_CTRL_MODE_0 | - ME4000_AI_CTRL_MODE_1 | - ME4000_AI_CTRL_CHANNEL_FIFO | - ME4000_AI_CTRL_DATA_FIFO; - } else { - tmp = ME4000_AI_CTRL_MODE_0 | - ME4000_AI_CTRL_CHANNEL_FIFO | - ME4000_AI_CTRL_DATA_FIFO; - } + ctrl = devpriv->ai_ctrl_mode | + ME4000_AI_CTRL_CHANNEL_FIFO | + ME4000_AI_CTRL_DATA_FIFO; /* Stop triggers */ if (cmd->stop_src == TRIG_COUNT) { outl(cmd->chanlist_len * cmd->stop_arg, dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG); - tmp |= ME4000_AI_CTRL_HF_IRQ | ME4000_AI_CTRL_SC_IRQ; + ctrl |= ME4000_AI_CTRL_SC_IRQ; } else if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_COUNT) { outl(cmd->scan_end_arg, dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG); - tmp |= ME4000_AI_CTRL_HF_IRQ | ME4000_AI_CTRL_SC_IRQ; - } else { - tmp |= ME4000_AI_CTRL_HF_IRQ; + ctrl |= ME4000_AI_CTRL_SC_IRQ; } + ctrl |= ME4000_AI_CTRL_HF_IRQ; /* Write the setup to the control register */ - outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); + outl(ctrl, dev->iobase + ME4000_AI_CTRL_REG); /* Write the channel list */ me4000_ai_write_chanlist(dev, s, cmd); @@ -800,21 +777,28 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, if (cmd->start_src == TRIG_NOW && cmd->scan_begin_src == TRIG_TIMER && cmd->convert_src == TRIG_TIMER) { + devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_0; } else if (cmd->start_src == TRIG_NOW && cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_TIMER) { + devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_0; } else if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER && cmd->convert_src == TRIG_TIMER) { + devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_1; } else if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_TIMER) { + devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_1; } else if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT && cmd->convert_src == TRIG_TIMER) { + devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_2; } else if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT && cmd->convert_src == TRIG_EXT) { + devpriv->ai_ctrl_mode = ME4000_AI_CTRL_MODE_0 | + ME4000_AI_CTRL_MODE_1; } else { err |= -EINVAL; } -- cgit v1.3-6-gb490 From 11e480c3a64355b55ac23aaa3250fcc85f260530 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:07 -0700 Subject: staging: comedi: me4000: absorb ai_prepare() This function never fails and it's only called by me4000_ai_do_cmd(). Absorb it and remove the unnecessary failure check. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 60f62f3d434a..c467eb75b17f 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -681,12 +681,18 @@ static int me4000_ai_write_chanlist(struct comedi_device *dev, return 0; } -static int ai_prepare(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int me4000_ai_do_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { struct me4000_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int ctrl; + int err; + + /* Reset the analog input */ + err = me4000_ai_cancel(dev, s); + if (err) + return err; /* Write timer arguments */ ai_write_timer(dev); @@ -718,25 +724,6 @@ static int ai_prepare(struct comedi_device *dev, /* Write the channel list */ me4000_ai_write_chanlist(dev, s, cmd); - return 0; -} - -static int me4000_ai_do_cmd(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - int err; - struct comedi_cmd *cmd = &s->async->cmd; - - /* Reset the analog input */ - err = me4000_ai_cancel(dev, s); - if (err) - return err; - - /* Prepare the AI for acquisition */ - err = ai_prepare(dev, s, cmd); - if (err) - return err; - /* Start acquistion by dummy read */ inl(dev->iobase + ME4000_AI_START_REG); -- cgit v1.3-6-gb490 From 576694d83e4b014f66e673fced80fb40be3c35b9 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:08 -0700 Subject: staging: comedi: me4000: absorb ai_write_timer() This function is only called by me4000_ai_do_cmd(). Absorb it. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 35 +++++++++++++-------------------- 1 file changed, 14 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index c467eb75b17f..ecdf6738ab02 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -635,26 +635,6 @@ static void me4000_ai_round_cmd_args(struct comedi_device *dev, } } -static void ai_write_timer(struct comedi_device *dev) -{ - struct me4000_private *devpriv = dev->private; - - outl(devpriv->ai_init_ticks - 1, - dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG); - outl(0x0, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG); - - if (devpriv->ai_scan_ticks) { - outl(devpriv->ai_scan_ticks - 1, - dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG); - outl(0x0, dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG); - } - - outl(devpriv->ai_chan_ticks - 1, - dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG); - outl(devpriv->ai_chan_ticks - 1, - dev->iobase + ME4000_AI_CHAN_TIMER_REG); -} - static int me4000_ai_write_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -695,7 +675,20 @@ static int me4000_ai_do_cmd(struct comedi_device *dev, return err; /* Write timer arguments */ - ai_write_timer(dev); + outl(devpriv->ai_init_ticks - 1, + dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG); + outl(0x0, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG); + + if (devpriv->ai_scan_ticks) { + outl(devpriv->ai_scan_ticks - 1, + dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG); + outl(0x0, dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG); + } + + outl(devpriv->ai_chan_ticks - 1, + dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG); + outl(devpriv->ai_chan_ticks - 1, + dev->iobase + ME4000_AI_CHAN_TIMER_REG); /* Reset control register */ outl(0, dev->iobase + ME4000_AI_CTRL_REG); -- cgit v1.3-6-gb490 From ffaeab349d0c5c28019ed395dac2c962560c34f6 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:09 -0700 Subject: staging: comedi: me4000: return void from me4000_ai_write_chanlist() This function always returns 0 and the return value is never checked. Just return void. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index ecdf6738ab02..b30305b44300 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -635,9 +635,9 @@ static void me4000_ai_round_cmd_args(struct comedi_device *dev, } } -static int me4000_ai_write_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static void me4000_ai_write_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int i; @@ -657,8 +657,6 @@ static int me4000_ai_write_chanlist(struct comedi_device *dev, outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG); } - - return 0; } static int me4000_ai_do_cmd(struct comedi_device *dev, -- cgit v1.3-6-gb490 From 6847df631faedfef33170eed8d81430a4917b8b0 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:10 -0700 Subject: staging: comedi: me4000: fix me4000_ai_cancel() The STOP and IMMEDIATE_STOP bits in the ME4000_AI_CTRL_REG should be set, not cleared, to stop any running conversions. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index b30305b44300..a171971b6a87 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -529,12 +529,12 @@ static int me4000_ai_insn_read(struct comedi_device *dev, static int me4000_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - unsigned int tmp; + unsigned int ctrl; /* Stop any running conversion */ - tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); - tmp &= ~(ME4000_AI_CTRL_STOP | ME4000_AI_CTRL_IMMEDIATE_STOP); - outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); + ctrl = inl(dev->iobase + ME4000_AI_CTRL_REG); + ctrl |= ME4000_AI_CTRL_STOP | ME4000_AI_CTRL_IMMEDIATE_STOP; + outl(ctrl, dev->iobase + ME4000_AI_CTRL_REG); /* Clear the control register */ outl(0x0, dev->iobase + ME4000_AI_CTRL_REG); -- cgit v1.3-6-gb490 From 78e4a573bfb01c287af8b81cd9d0a7329cbae7ca Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:11 -0700 Subject: staging: comedi: me4000: remove unnecessary ai control register reset The me4000_ai_cancel() already reset this register. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index a171971b6a87..4a051b86100a 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -688,9 +688,6 @@ static int me4000_ai_do_cmd(struct comedi_device *dev, outl(devpriv->ai_chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_TIMER_REG); - /* Reset control register */ - outl(0, dev->iobase + ME4000_AI_CTRL_REG); - /* Start sources */ ctrl = devpriv->ai_ctrl_mode | ME4000_AI_CTRL_CHANNEL_FIFO | -- cgit v1.3-6-gb490 From 2ff848c3be2d066ec0dc05f8477f97d9daa24e0d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:12 -0700 Subject: staging: comedi: me4000: remove unnecessary me4000_ai_cancel() The comedi core ensures that the subdevice is not busy before it allows starting a new command. The subdevice (*cancel) is called when the subdevice is set to not busy. In this driver the me4000_ai_cancel() is the ai (*cancel) so the extra call in the ai (*do_cmd) is not necessary. Remove it. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 4a051b86100a..b3d871b2b6a1 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -665,12 +665,6 @@ static int me4000_ai_do_cmd(struct comedi_device *dev, struct me4000_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int ctrl; - int err; - - /* Reset the analog input */ - err = me4000_ai_cancel(dev, s); - if (err) - return err; /* Write timer arguments */ outl(devpriv->ai_init_ticks - 1, -- cgit v1.3-6-gb490 From a31b50ed1b600ed198252acccf6ec570fabcfc03 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:13 -0700 Subject: staging: comedi: me4000: clear the ME4000_AI_CTRL_REG in me4000_reset() Reset the analog input control register after ensuring that any active conversions have been stopped. This mimics what the ai subdevice (*cancel) does. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index b3d871b2b6a1..3d4a9c841192 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -414,6 +414,9 @@ static void me4000_reset(struct comedi_device *dev) outl(ME4000_AI_CTRL_IMMEDIATE_STOP | ME4000_AI_CTRL_STOP, dev->iobase + ME4000_AI_CTRL_REG); + /* Clear the analog input control register */ + outl(0x0, dev->iobase + ME4000_AI_CTRL_REG); + /* Set both stop bits in the analog output control register */ val = ME4000_AO_CTRL_IMMEDIATE_STOP | ME4000_AO_CTRL_STOP; for (chan = 0; chan < 4; chan++) -- cgit v1.3-6-gb490 From b047d9ccc3a40b672594b4eab1eac91d7efebcd9 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:14 -0700 Subject: staging: comedi: me4000: introduce me4000_ai_reset() Introduce a helper function to stop any ai conversions and reset the ai control register. This consolidates the common code in me4000_reset() and me4000_ai_cancel(). Use the new helper in the ai (*insn_read) to ensure that the ai control register is set to a known state after reading the samples. The ai control register will now always be '0' after the (*cancel) of a command or doing an (*insn_read). Knowing this the programming of the register for single acquisition mode in the (*insn_read) can be simplified. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 56 ++++++++++++++------------------- 1 file changed, 23 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 3d4a9c841192..da0075b926a5 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -393,6 +393,19 @@ static int me4000_xilinx_download(struct comedi_device *dev, return 0; } +static void me4000_ai_reset(struct comedi_device *dev) +{ + unsigned int ctrl; + + /* Stop any running conversion */ + ctrl = inl(dev->iobase + ME4000_AI_CTRL_REG); + ctrl |= ME4000_AI_CTRL_STOP | ME4000_AI_CTRL_IMMEDIATE_STOP; + outl(ctrl, dev->iobase + ME4000_AI_CTRL_REG); + + /* Clear the control register */ + outl(0x0, dev->iobase + ME4000_AI_CTRL_REG); +} + static void me4000_reset(struct comedi_device *dev) { struct me4000_private *devpriv = dev->private; @@ -410,12 +423,7 @@ static void me4000_reset(struct comedi_device *dev) for (chan = 0; chan < 4; chan++) outl(0x8000, dev->iobase + ME4000_AO_SINGLE_REG(chan)); - /* Set both stop bits in the analog input control register */ - outl(ME4000_AI_CTRL_IMMEDIATE_STOP | ME4000_AI_CTRL_STOP, - dev->iobase + ME4000_AI_CTRL_REG); - - /* Clear the analog input control register */ - outl(0x0, dev->iobase + ME4000_AI_CTRL_REG); + me4000_ai_reset(dev); /* Set both stop bits in the analog output control register */ val = ME4000_AO_CTRL_IMMEDIATE_STOP | ME4000_AO_CTRL_STOP; @@ -461,8 +469,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev, unsigned int range = CR_RANGE(insn->chanspec); unsigned int aref = CR_AREF(insn->chanspec); unsigned int entry; - unsigned int tmp; - int ret; + int ret = 0; int i; entry = chan | ME4000_AI_LIST_RANGE(range); @@ -489,20 +496,9 @@ static int me4000_ai_insn_read(struct comedi_device *dev, entry |= ME4000_AI_LIST_LAST_ENTRY; - /* Clear channel list, data fifo and both stop bits */ - tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); - tmp &= ~(ME4000_AI_CTRL_CHANNEL_FIFO | ME4000_AI_CTRL_DATA_FIFO | - ME4000_AI_CTRL_STOP | ME4000_AI_CTRL_IMMEDIATE_STOP); - outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); - - /* Set the acquisition mode to single */ - tmp &= ~(ME4000_AI_CTRL_MODE_0 | ME4000_AI_CTRL_MODE_1 | - ME4000_AI_CTRL_MODE_2); - outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); - - /* Enable channel list and data fifo */ - tmp |= ME4000_AI_CTRL_CHANNEL_FIFO | ME4000_AI_CTRL_DATA_FIFO; - outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); + /* Enable channel list and data fifo for single acquisition mode */ + outl(ME4000_AI_CTRL_CHANNEL_FIFO | ME4000_AI_CTRL_DATA_FIFO, + dev->iobase + ME4000_AI_CTRL_REG); /* Generate channel list entry */ outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG); @@ -519,28 +515,22 @@ static int me4000_ai_insn_read(struct comedi_device *dev, ret = comedi_timeout(dev, s, insn, me4000_ai_eoc, 0); if (ret) - return ret; + break; /* read two's complement value and munge to offset binary */ val = inl(dev->iobase + ME4000_AI_DATA_REG); data[i] = comedi_offset_munge(s, val); } - return insn->n; + me4000_ai_reset(dev); + + return ret ? ret : insn->n; } static int me4000_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - unsigned int ctrl; - - /* Stop any running conversion */ - ctrl = inl(dev->iobase + ME4000_AI_CTRL_REG); - ctrl |= ME4000_AI_CTRL_STOP | ME4000_AI_CTRL_IMMEDIATE_STOP; - outl(ctrl, dev->iobase + ME4000_AI_CTRL_REG); - - /* Clear the control register */ - outl(0x0, dev->iobase + ME4000_AI_CTRL_REG); + me4000_ai_reset(dev); return 0; } -- cgit v1.3-6-gb490 From 8f3f3eb7a264630a73c23cecfa2af2235775e09a Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:15 -0700 Subject: staging: comedi: me4000: only enable PLX interrupt if we have and irq Currently me4000_reset() always enables the PLX interrupt. Move the enable of the interrupt into me4000_auto_attach() and only do the enable if we actually have and irq. Make sure the PLX interrupt is disabled in me4000_reset() before we try to request the irq. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index da0075b926a5..a4c28fa90759 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -412,7 +412,10 @@ static void me4000_reset(struct comedi_device *dev) unsigned int val; int chan; - /* Make a hardware reset */ + /* Disable interrupts on the PLX */ + outl(0, devpriv->plx_regbase + PLX9052_INTCSR); + + /* Software reset the PLX */ val = inl(devpriv->plx_regbase + PLX9052_CNTRL); val |= PLX9052_CNTRL_PCI_RESET; outl(val, devpriv->plx_regbase + PLX9052_CNTRL); @@ -430,11 +433,6 @@ static void me4000_reset(struct comedi_device *dev) for (chan = 0; chan < 4; chan++) outl(val, dev->iobase + ME4000_AO_CTRL_REG(chan)); - /* Enable interrupts on the PLX */ - outl(PLX9052_INTCSR_LI1ENAB | - PLX9052_INTCSR_LI1POL | - PLX9052_INTCSR_PCIENAB, devpriv->plx_regbase + PLX9052_INTCSR); - /* Set the adustment register for AO demux */ outl(ME4000_AO_DEMUX_ADJUST_VALUE, dev->iobase + ME4000_AO_DEMUX_ADJUST_REG); @@ -1181,8 +1179,14 @@ static int me4000_auto_attach(struct comedi_device *dev, if (pcidev->irq > 0) { result = request_irq(pcidev->irq, me4000_ai_isr, IRQF_SHARED, dev->board_name, dev); - if (result == 0) + if (result == 0) { dev->irq = pcidev->irq; + + /* Enable interrupts on the PLX */ + outl(PLX9052_INTCSR_LI1ENAB | PLX9052_INTCSR_LI1POL | + PLX9052_INTCSR_PCIENAB, + devpriv->plx_regbase + PLX9052_INTCSR); + } } result = comedi_alloc_subdevices(dev, 4); -- cgit v1.3-6-gb490 From 607d993942512f6b005b0465be85f21db7725ecc Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:16 -0700 Subject: staging: comedi: me4000: fix me4000_detach() There is no real reason to reset the board when detaching. The comedi core will ensure that any commands are canceled before the detach. But the PLX interrupts should be disabled. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index a4c28fa90759..4f2ff860cf63 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -1276,8 +1276,12 @@ static int me4000_auto_attach(struct comedi_device *dev, static void me4000_detach(struct comedi_device *dev) { - if (dev->iobase) - me4000_reset(dev); + if (dev->irq) { + struct me4000_private *devpriv = dev->private; + + /* Disable interrupts on the PLX */ + outl(0, devpriv->plx_regbase + PLX9052_INTCSR); + } comedi_pci_detach(dev); } -- cgit v1.3-6-gb490 From b36e4fa78ddbb342480031beec5fc63473b340e0 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:17 -0700 Subject: staging: comedi: me4000: tidy up analog output subdevice init For aesthetics, add some white space to the analog output subdevice initialization. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 4f2ff860cf63..b2d9d61a6173 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -1213,25 +1213,21 @@ static int me4000_auto_attach(struct comedi_device *dev, s->do_cmd = me4000_ai_do_cmd; } - /*========================================================================= - Analog output subdevice - ========================================================================*/ - + /* Analog Output subdevice */ s = &dev->subdevices[1]; - if (board->has_ao) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_COMMON | SDF_GROUND; - s->n_chan = 4; - s->maxdata = 0xFFFF; /* 16 bit DAC */ - s->range_table = &range_bipolar10; - s->insn_write = me4000_ao_insn_write; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_COMMON | SDF_GROUND; + s->n_chan = 4; + s->maxdata = 0xffff; + s->range_table = &range_bipolar10; + s->insn_write = me4000_ao_insn_write; result = comedi_alloc_subdev_readback(s); if (result) return result; } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_UNUSED; } /* Digital I/O subdevice */ -- cgit v1.3-6-gb490 From 36d59d70babc9ad4275d0c7c5e63241a077f572c Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:18 -0700 Subject: staging: comedi: me4000: comedi_handle_events() will stop conversions The irq handler does not need to manually stop conversions and disable interrupts when "end-of-acquisition", "error", or "overflow" events are detected. The comedi_handle_events() will call the subdevice (*cancel) when these are detected and stop the acquisition. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 54 +++++---------------------------- 1 file changed, 7 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index b2d9d61a6173..b17183dee7fb 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -939,41 +939,17 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) if (!(tmp & ME4000_AI_STATUS_FF_DATA) && !(tmp & ME4000_AI_STATUS_HF_DATA) && (tmp & ME4000_AI_STATUS_EF_DATA)) { - c = ME4000_AI_FIFO_COUNT; - - /* - * FIFO overflow, so stop conversion - * and disable all interrupts - */ - tmp |= ME4000_AI_CTRL_IMMEDIATE_STOP; - tmp &= ~(ME4000_AI_CTRL_HF_IRQ | - ME4000_AI_CTRL_SC_IRQ); - outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); - - s->async->events |= COMEDI_CB_ERROR; - dev_err(dev->class_dev, "FIFO overflow\n"); + s->async->events |= COMEDI_CB_ERROR; + c = ME4000_AI_FIFO_COUNT; } else if ((tmp & ME4000_AI_STATUS_FF_DATA) && !(tmp & ME4000_AI_STATUS_HF_DATA) && (tmp & ME4000_AI_STATUS_EF_DATA)) { c = ME4000_AI_FIFO_COUNT / 2; } else { - dev_err(dev->class_dev, - "Can't determine state of fifo\n"); - c = 0; - - /* - * Undefined state, so stop conversion - * and disable all interrupts - */ - tmp |= ME4000_AI_CTRL_IMMEDIATE_STOP; - tmp &= ~(ME4000_AI_CTRL_HF_IRQ | - ME4000_AI_CTRL_SC_IRQ); - outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); - - s->async->events |= COMEDI_CB_ERROR; - dev_err(dev->class_dev, "Undefined FIFO state\n"); + s->async->events |= COMEDI_CB_ERROR; + c = 0; } for (i = 0; i < c; i++) { @@ -981,17 +957,8 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; lval ^= 0x8000; - if (!comedi_buf_write_samples(s, &lval, 1)) { - /* - * Buffer overflow, so stop conversion - * and disable all interrupts - */ - tmp |= ME4000_AI_CTRL_IMMEDIATE_STOP; - tmp &= ~(ME4000_AI_CTRL_HF_IRQ | - ME4000_AI_CTRL_SC_IRQ); - outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); + if (!comedi_buf_write_samples(s, &lval, 1)) break; - } } /* Work is done, so reset the interrupt */ @@ -1003,17 +970,9 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & ME4000_IRQ_STATUS_SC) { + /* Acquisition is complete */ s->async->events |= COMEDI_CB_EOA; - /* - * Acquisition is complete, so stop - * conversion and disable all interrupts - */ - tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); - tmp |= ME4000_AI_CTRL_IMMEDIATE_STOP; - tmp &= ~(ME4000_AI_CTRL_HF_IRQ | ME4000_AI_CTRL_SC_IRQ); - outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); - /* Poll data until fifo empty */ while (inl(dev->iobase + ME4000_AI_STATUS_REG) & ME4000_AI_STATUS_EF_DATA) { @@ -1026,6 +985,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) } /* Work is done, so reset the interrupt */ + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); tmp |= ME4000_AI_CTRL_SC_IRQ_RESET; outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~ME4000_AI_CTRL_SC_IRQ_RESET; -- cgit v1.3-6-gb490 From 7022781c460290687b374dab1c230c06091bba10 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:19 -0700 Subject: staging: comedi: me4000: introduce me4000_ai_get_sample() The hardware returns two's complement values for the analog input samples. These need to be converted to the unsigned binary format that the comedi core expects. Introduce a helper function to handle this. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index b17183dee7fb..3974f59c0478 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -445,6 +445,16 @@ static void me4000_reset(struct comedi_device *dev) outl(0x1, dev->iobase + ME4000_DIO_CTRL_REG); } +static unsigned int me4000_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; + + /* read two's complement value and munge to offset binary */ + val = inl(dev->iobase + ME4000_AI_DATA_REG); + return comedi_offset_munge(s, val); +} + static int me4000_ai_eoc(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -515,8 +525,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev, if (ret) break; - /* read two's complement value and munge to offset binary */ - val = inl(dev->iobase + ME4000_AI_DATA_REG); + val = me4000_ai_get_sample(dev, s); data[i] = comedi_offset_munge(s, val); } @@ -953,10 +962,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) } for (i = 0; i < c; i++) { - /* Read value from data fifo */ - lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; - lval ^= 0x8000; - + lval = me4000_ai_get_sample(dev, s); if (!comedi_buf_write_samples(s, &lval, 1)) break; } @@ -976,10 +982,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) /* Poll data until fifo empty */ while (inl(dev->iobase + ME4000_AI_STATUS_REG) & ME4000_AI_STATUS_EF_DATA) { - /* Read value from data fifo */ - lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; - lval ^= 0x8000; - + lval = me4000_ai_get_sample(dev, s); if (!comedi_buf_write_samples(s, &lval, 1)) break; } -- cgit v1.3-6-gb490 From 3fe6929bbbca11b015d182d4864d92d0bf5c244d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:20 -0700 Subject: staging: comedi: me4000: usleep_range is preferred over udelay Fix checkpatch issue: "CHECK: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt". `udelay()` is only used in the firmware upload process. Replace them with `usleep_range()` with a reasonable upper limit. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 3974f59c0478..74c16dbd1f8b 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -345,7 +345,7 @@ static int me4000_xilinx_download(struct comedi_device *dev, inb(xilinx_iobase + 0xC8); /* Wait until /INIT pin is set */ - udelay(20); + usleep_range(20, 1000); val = inl(devpriv->plx_regbase + PLX9052_INTCSR); if (!(val & PLX9052_INTCSR_LI2STAT)) { dev_err(dev->class_dev, "Can't init Xilinx\n"); @@ -362,11 +362,11 @@ static int me4000_xilinx_download(struct comedi_device *dev, (((unsigned int)data[1] & 0xff) << 16) + (((unsigned int)data[2] & 0xff) << 8) + ((unsigned int)data[3] & 0xff); - udelay(10); + usleep_range(10, 1000); for (i = 0; i < file_length; i++) { outb(data[16 + i], xilinx_iobase); - udelay(10); + usleep_range(10, 1000); /* Check if BUSY flag is low */ val = inl(devpriv->plx_regbase + PLX9052_CNTRL); -- cgit v1.3-6-gb490 From 751dcb48c7ec8585644d2e62d81ce54228e92c8b Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:21 -0700 Subject: staging: comedi: me4000: cleanup multi-line comments Format the multi-line comments in the kernel CodingStyle. Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 74 ++++++++++++++++----------------- 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 74c16dbd1f8b..56da64d25b86 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -1,43 +1,43 @@ /* - comedi/drivers/me4000.c - Source code for the Meilhaus ME-4000 board family. - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef - - 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. + * me4000.c + * Source code for the Meilhaus ME-4000 board family. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef + * + * 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. */ -/* -Driver: me4000 -Description: Meilhaus ME-4000 series boards -Devices: [Meilhaus] ME-4650 (me4000), ME-4670i, ME-4680, ME-4680i, ME-4680is -Author: gg (Guenter Gebhardt ) -Updated: Mon, 18 Mar 2002 15:34:01 -0800 -Status: broken (no support for loading firmware) - -Supports: - - - Analog Input - - Analog Output - - Digital I/O - - Counter - -Configuration Options: not applicable, uses PCI auto config - -The firmware required by these boards is available in the -comedi_nonfree_firmware tarball available from -http://www.comedi.org. However, the driver's support for -loading the firmware through comedi_config is currently -broken. +/* + * Driver: me4000 + * Description: Meilhaus ME-4000 series boards + * Devices: [Meilhaus] ME-4650 (me4000), ME-4670i, ME-4680, ME-4680i, + * ME-4680is + * Author: gg (Guenter Gebhardt ) + * Updated: Mon, 18 Mar 2002 15:34:01 -0800 + * Status: broken (no support for loading firmware) + * + * Supports: + * - Analog Input + * - Analog Output + * - Digital I/O + * - Counter + * + * Configuration Options: not applicable, uses PCI auto config + * + * The firmware required by these boards is available in the + * comedi_nonfree_firmware tarball available from + * http://www.comedi.org. However, the driver's support for + * loading the firmware through comedi_config is currently + * broken. */ #include -- cgit v1.3-6-gb490 From 4627c547c031459ad9f504d95c6a56a1d7a1e079 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:22 -0700 Subject: staging: comedi: me4000: updata driver status in comedi comment Firmware loading was fixed by: Commit: ac584af5 "staging: comedi: me4000: fix firmware downloading" Change the driver status to "untested" and remove the comments about the driver being broken, Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 56da64d25b86..ac6931acb039 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -23,7 +23,7 @@ * ME-4680is * Author: gg (Guenter Gebhardt ) * Updated: Mon, 18 Mar 2002 15:34:01 -0800 - * Status: broken (no support for loading firmware) + * Status: untested * * Supports: * - Analog Input @@ -35,9 +35,7 @@ * * The firmware required by these boards is available in the * comedi_nonfree_firmware tarball available from - * http://www.comedi.org. However, the driver's support for - * loading the firmware through comedi_config is currently - * broken. + * http://www.comedi.org. */ #include -- cgit v1.3-6-gb490 From b96e53df92ab6ed1ca58639f0bbfacaf717e285b Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 5 Aug 2015 10:45:23 -0700 Subject: staging: comedi: me4000: update MODULE_DESCRIPTION Change the MODULE_DESCRIPTION to something more useful than "Comedi low- level driver" Signed-off-by: H Hartley Sweeten Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/me4000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index ac6931acb039..5aa1780cf42b 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -1282,6 +1282,6 @@ static struct pci_driver me4000_pci_driver = { module_comedi_pci_driver(me4000_driver, me4000_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Meilhaus ME-4000 series boards"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(ME4000_FIRMWARE); -- cgit v1.3-6-gb490 From 1461d66728648540a043ba69ace1081ed5006faf Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 18:31:13 +0530 Subject: staging: sm7xxfb: merge sm712fb with fbdev Now since all cleanups are done and the code is ready to be merged lets move it out of staging into fbdev location. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/sm7xxfb/Kconfig | 13 - drivers/staging/sm7xxfb/Makefile | 1 - drivers/staging/sm7xxfb/TODO | 12 - drivers/staging/sm7xxfb/sm7xx.h | 116 --- drivers/staging/sm7xxfb/sm7xxfb.c | 1653 ------------------------------------- drivers/video/fbdev/Kconfig | 14 + drivers/video/fbdev/Makefile | 1 + drivers/video/fbdev/sm712.h | 116 +++ drivers/video/fbdev/sm712fb.c | 1653 +++++++++++++++++++++++++++++++++++++ 11 files changed, 1784 insertions(+), 1798 deletions(-) delete mode 100644 drivers/staging/sm7xxfb/Kconfig delete mode 100644 drivers/staging/sm7xxfb/Makefile delete mode 100644 drivers/staging/sm7xxfb/TODO delete mode 100644 drivers/staging/sm7xxfb/sm7xx.h delete mode 100644 drivers/staging/sm7xxfb/sm7xxfb.c create mode 100644 drivers/video/fbdev/sm712.h create mode 100644 drivers/video/fbdev/sm712fb.c (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 4f0b12d88fdc..39c5df6154aa 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -56,8 +56,6 @@ source "drivers/staging/vt6656/Kconfig" source "drivers/staging/iio/Kconfig" -source "drivers/staging/sm7xxfb/Kconfig" - source "drivers/staging/sm750fb/Kconfig" source "drivers/staging/xgifb/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 37149ca6a331..018093d60e85 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -22,7 +22,6 @@ obj-$(CONFIG_VT6655) += vt6655/ obj-$(CONFIG_VT6656) += vt6656/ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_IIO) += iio/ -obj-$(CONFIG_FB_SM7XX) += sm7xxfb/ obj-$(CONFIG_FB_SM750) += sm750fb/ obj-$(CONFIG_FB_XGI) += xgifb/ obj-$(CONFIG_USB_EMXX) += emxx_udc/ diff --git a/drivers/staging/sm7xxfb/Kconfig b/drivers/staging/sm7xxfb/Kconfig deleted file mode 100644 index e2922ae3a3ee..000000000000 --- a/drivers/staging/sm7xxfb/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config FB_SM7XX - tristate "Silicon Motion SM7XX framebuffer support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Frame buffer driver for the Silicon Motion SM710, SM712, SM721 - and SM722 chips. - - This driver is also available as a module. The module will be - called sm7xxfb. If you want to compile it as a module, say M - here and read . diff --git a/drivers/staging/sm7xxfb/Makefile b/drivers/staging/sm7xxfb/Makefile deleted file mode 100644 index 48f471cf9f36..000000000000 --- a/drivers/staging/sm7xxfb/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_FB_SM7XX) += sm7xxfb.o diff --git a/drivers/staging/sm7xxfb/TODO b/drivers/staging/sm7xxfb/TODO deleted file mode 100644 index 7cb0b242f204..000000000000 --- a/drivers/staging/sm7xxfb/TODO +++ /dev/null @@ -1,12 +0,0 @@ -TODO: -- Dual head support -- 2D acceleration support -- use kernel coding style -- refine the code and remove unused code -- move it to drivers/video/fbdev/sm7xxfb.c - -Please send any patches to - Greg Kroah-Hartman - Sudip Mukherjee - Teddy Wang - Sudip Mukherjee diff --git a/drivers/staging/sm7xxfb/sm7xx.h b/drivers/staging/sm7xxfb/sm7xx.h deleted file mode 100644 index aad1cc4be34a..000000000000 --- a/drivers/staging/sm7xxfb/sm7xx.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Silicon Motion SM712 frame buffer device - * - * Copyright (C) 2006 Silicon Motion Technology Corp. - * Authors: Ge Wang, gewang@siliconmotion.com - * Boyod boyod.yang@siliconmotion.com.cn - * - * Copyright (C) 2009 Lemote, Inc. - * Author: Wu Zhangjin, wuzhangjin@gmail.com - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#define FB_ACCEL_SMI_LYNX 88 - -#define SCREEN_X_RES 1024 -#define SCREEN_Y_RES 600 -#define SCREEN_BPP 16 - -/*Assume SM712 graphics chip has 4MB VRAM */ -#define SM712_VIDEOMEMORYSIZE 0x00400000 -/*Assume SM722 graphics chip has 8MB VRAM */ -#define SM722_VIDEOMEMORYSIZE 0x00800000 - -#define dac_reg (0x3c8) -#define dac_val (0x3c9) - -extern void __iomem *smtc_regbaseaddress; -#define smtc_mmiowb(dat, reg) writeb(dat, smtc_regbaseaddress + reg) - -#define smtc_mmiorb(reg) readb(smtc_regbaseaddress + reg) - -#define SIZE_SR00_SR04 (0x04 - 0x00 + 1) -#define SIZE_SR10_SR24 (0x24 - 0x10 + 1) -#define SIZE_SR30_SR75 (0x75 - 0x30 + 1) -#define SIZE_SR80_SR93 (0x93 - 0x80 + 1) -#define SIZE_SRA0_SRAF (0xAF - 0xA0 + 1) -#define SIZE_GR00_GR08 (0x08 - 0x00 + 1) -#define SIZE_AR00_AR14 (0x14 - 0x00 + 1) -#define SIZE_CR00_CR18 (0x18 - 0x00 + 1) -#define SIZE_CR30_CR4D (0x4D - 0x30 + 1) -#define SIZE_CR90_CRA7 (0xA7 - 0x90 + 1) - -static inline void smtc_crtcw(int reg, int val) -{ - smtc_mmiowb(reg, 0x3d4); - smtc_mmiowb(val, 0x3d5); -} - -static inline void smtc_grphw(int reg, int val) -{ - smtc_mmiowb(reg, 0x3ce); - smtc_mmiowb(val, 0x3cf); -} - -static inline void smtc_attrw(int reg, int val) -{ - smtc_mmiorb(0x3da); - smtc_mmiowb(reg, 0x3c0); - smtc_mmiorb(0x3c1); - smtc_mmiowb(val, 0x3c0); -} - -static inline void smtc_seqw(int reg, int val) -{ - smtc_mmiowb(reg, 0x3c4); - smtc_mmiowb(val, 0x3c5); -} - -static inline unsigned int smtc_seqr(int reg) -{ - smtc_mmiowb(reg, 0x3c4); - return smtc_mmiorb(0x3c5); -} - -/* The next structure holds all information relevant for a specific video mode. - */ - -struct modeinit { - int mmsizex; - int mmsizey; - int bpp; - int hz; - unsigned char init_misc; - unsigned char init_sr00_sr04[SIZE_SR00_SR04]; - unsigned char init_sr10_sr24[SIZE_SR10_SR24]; - unsigned char init_sr30_sr75[SIZE_SR30_SR75]; - unsigned char init_sr80_sr93[SIZE_SR80_SR93]; - unsigned char init_sra0_sraf[SIZE_SRA0_SRAF]; - unsigned char init_gr00_gr08[SIZE_GR00_GR08]; - unsigned char init_ar00_ar14[SIZE_AR00_AR14]; - unsigned char init_cr00_cr18[SIZE_CR00_CR18]; - unsigned char init_cr30_cr4d[SIZE_CR30_CR4D]; - unsigned char init_cr90_cra7[SIZE_CR90_CRA7]; -}; - -#ifdef __BIG_ENDIAN -#define pal_rgb(r, g, b, val) (((r & 0xf800) >> 8) | \ - ((g & 0xe000) >> 13) | \ - ((g & 0x1c00) << 3) | \ - ((b & 0xf800) >> 3)) -#define big_addr 0x800000 -#define mmio_addr 0x00800000 -#define seqw17() smtc_seqw(0x17, 0x30) -#define big_pixel_depth(p, d) {if (p == 24) {p = 32; d = 32; } } -#define big_swap(p) ((p & 0xff00ff00 >> 8) | (p & 0x00ff00ff << 8)) -#else -#define pal_rgb(r, g, b, val) val -#define big_addr 0 -#define mmio_addr 0x00c00000 -#define seqw17() do { } while (0) -#define big_pixel_depth(p, d) do { } while (0) -#define big_swap(p) p -#endif diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c deleted file mode 100644 index 07c2199c9ac7..000000000000 --- a/drivers/staging/sm7xxfb/sm7xxfb.c +++ /dev/null @@ -1,1653 +0,0 @@ -/* - * Silicon Motion SM7XX frame buffer device - * - * Copyright (C) 2006 Silicon Motion Technology Corp. - * Authors: Ge Wang, gewang@siliconmotion.com - * Boyod boyod.yang@siliconmotion.com.cn - * - * Copyright (C) 2009 Lemote, Inc. - * Author: Wu Zhangjin, wuzhangjin@gmail.com - * - * Copyright (C) 2011 Igalia, S.L. - * Author: Javier M. Mellid - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_PM -#include -#endif - -#include "sm7xx.h" - -/* -* Private structure -*/ -struct smtcfb_info { - struct pci_dev *pdev; - struct fb_info *fb; - u16 chip_id; - u8 chip_rev_id; - - void __iomem *lfb; /* linear frame buffer */ - void __iomem *dp_regs; /* drawing processor control regs */ - void __iomem *vp_regs; /* video processor control regs */ - void __iomem *cp_regs; /* capture processor control regs */ - void __iomem *mmio; /* memory map IO port */ - - u_int width; - u_int height; - u_int hz; - - u32 colreg[17]; -}; - -void __iomem *smtc_regbaseaddress; /* Memory Map IO starting address */ - -static struct fb_var_screeninfo smtcfb_var = { - .xres = 1024, - .yres = 600, - .xres_virtual = 1024, - .yres_virtual = 600, - .bits_per_pixel = 16, - .red = {16, 8, 0}, - .green = {8, 8, 0}, - .blue = {0, 8, 0}, - .activate = FB_ACTIVATE_NOW, - .height = -1, - .width = -1, - .vmode = FB_VMODE_NONINTERLACED, - .nonstd = 0, - .accel_flags = FB_ACCELF_TEXT, -}; - -static struct fb_fix_screeninfo smtcfb_fix = { - .id = "smXXXfb", - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_TRUECOLOR, - .line_length = 800 * 3, - .accel = FB_ACCEL_SMI_LYNX, - .type_aux = 0, - .xpanstep = 0, - .ypanstep = 0, - .ywrapstep = 0, -}; - -struct vesa_mode { - char index[6]; - u16 lfb_width; - u16 lfb_height; - u16 lfb_depth; -}; - -static const struct vesa_mode vesa_mode_table[] = { - {"0x301", 640, 480, 8}, - {"0x303", 800, 600, 8}, - {"0x305", 1024, 768, 8}, - {"0x307", 1280, 1024, 8}, - - {"0x311", 640, 480, 16}, - {"0x314", 800, 600, 16}, - {"0x317", 1024, 768, 16}, - {"0x31A", 1280, 1024, 16}, - - {"0x312", 640, 480, 24}, - {"0x315", 800, 600, 24}, - {"0x318", 1024, 768, 24}, - {"0x31B", 1280, 1024, 24}, -}; - -/********************************************************************** - SM712 Mode table. - **********************************************************************/ -static const struct modeinit vgamode[] = { - { - /* mode#0: 640 x 480 16Bpp 60Hz */ - 640, 480, 16, 60, - /* Init_MISC */ - 0xE3, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x00, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, - 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, - 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, - 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, - 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, - 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, - 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, - 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, - 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, - }, - }, - { - /* mode#1: 640 x 480 24Bpp 60Hz */ - 640, 480, 24, 60, - /* Init_MISC */ - 0xE3, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x00, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, - 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, - 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, - 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, - 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, - 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, - 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, - 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, - 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, - }, - }, - { - /* mode#0: 640 x 480 32Bpp 60Hz */ - 640, 480, 32, 60, - /* Init_MISC */ - 0xE3, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x00, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, - 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, - 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, - 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, - 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, - 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, - 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, - 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, - 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, - }, - }, - - { /* mode#2: 800 x 600 16Bpp 60Hz */ - 800, 600, 16, 60, - /* Init_MISC */ - 0x2B, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, - 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, - 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, - 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, - 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, - 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, - 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, - 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, - 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, - }, - }, - { /* mode#3: 800 x 600 24Bpp 60Hz */ - 800, 600, 24, 60, - 0x2B, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, - 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, - 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, - 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, - 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, - 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, - 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, - 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, - 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, - }, - }, - { /* mode#7: 800 x 600 32Bpp 60Hz */ - 800, 600, 32, 60, - /* Init_MISC */ - 0x2B, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, - 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, - 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, - 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, - 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, - 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, - 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, - 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, - 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, - }, - }, - /* We use 1024x768 table to light 1024x600 panel for lemote */ - { /* mode#4: 1024 x 600 16Bpp 60Hz */ - 1024, 600, 16, 60, - /* Init_MISC */ - 0xEB, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x00, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, - 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x00, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, - 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, - 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, - 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, - 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, - 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, - 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, - 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, - 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, - }, - { /* Init_CR90_CRA7 */ - 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, - 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, - }, - }, - { /* mode#5: 1024 x 768 24Bpp 60Hz */ - 1024, 768, 24, 60, - /* Init_MISC */ - 0xEB, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, - 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, - 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, - 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, - 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, - 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, - 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, - 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, - 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, - }, - { /* Init_CR90_CRA7 */ - 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, - 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, - }, - }, - { /* mode#4: 1024 x 768 32Bpp 60Hz */ - 1024, 768, 32, 60, - /* Init_MISC */ - 0xEB, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x32, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, - 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, - 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, - 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, - 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, - 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, - 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, - 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, - 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, - }, - { /* Init_CR90_CRA7 */ - 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, - 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, - }, - }, - { /* mode#6: 320 x 240 16Bpp 60Hz */ - 320, 240, 16, 60, - /* Init_MISC */ - 0xEB, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x32, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, - 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, - 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, - 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, - 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, - 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, - 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, - 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, - 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, - 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, - }, - { /* Init_CR90_CRA7 */ - 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, - 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, - }, - }, - - { /* mode#8: 320 x 240 32Bpp 60Hz */ - 320, 240, 32, 60, - /* Init_MISC */ - 0xEB, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x32, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, - 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, - 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, - 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, - 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, - 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, - 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, - 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, - 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, - 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, - }, - { /* Init_CR90_CRA7 */ - 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, - 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, - }, - }, -}; - -static struct screen_info smtc_scr_info; - -static char *mode_option; - -/* process command line options, get vga parameter */ -static void __init sm7xx_vga_setup(char *options) -{ - int i; - - if (!options || !*options) - return; - - smtc_scr_info.lfb_width = 0; - smtc_scr_info.lfb_height = 0; - smtc_scr_info.lfb_depth = 0; - - pr_debug("sm7xx_vga_setup = %s\n", options); - - for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { - if (strstr(options, vesa_mode_table[i].index)) { - smtc_scr_info.lfb_width = vesa_mode_table[i].lfb_width; - smtc_scr_info.lfb_height = - vesa_mode_table[i].lfb_height; - smtc_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; - return; - } - } -} - -static void sm712_setpalette(int regno, unsigned red, unsigned green, - unsigned blue, struct fb_info *info) -{ - /* set bit 5:4 = 01 (write LCD RAM only) */ - smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10); - - smtc_mmiowb(regno, dac_reg); - smtc_mmiowb(red >> 10, dac_val); - smtc_mmiowb(green >> 10, dac_val); - smtc_mmiowb(blue >> 10, dac_val); -} - -/* chan_to_field - * - * convert a colour value into a field position - * - * from pxafb.c - */ - -static inline unsigned int chan_to_field(unsigned int chan, - struct fb_bitfield *bf) -{ - chan &= 0xffff; - chan >>= 16 - bf->length; - return chan << bf->offset; -} - -static int smtc_blank(int blank_mode, struct fb_info *info) -{ - /* clear DPMS setting */ - switch (blank_mode) { - case FB_BLANK_UNBLANK: - /* Screen On: HSync: On, VSync : On */ - smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); - smtc_seqw(0x6a, 0x16); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77)); - smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); - smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); - smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); - smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03)); - break; - case FB_BLANK_NORMAL: - /* Screen Off: HSync: On, VSync : On Soft blank */ - smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); - smtc_seqw(0x6a, 0x16); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); - smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); - smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); - break; - case FB_BLANK_VSYNC_SUSPEND: - /* Screen On: HSync: On, VSync : Off */ - smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); - smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); - smtc_seqw(0x6a, 0x0c); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); - smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20)); - smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20)); - smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); - smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); - break; - case FB_BLANK_HSYNC_SUSPEND: - /* Screen On: HSync: Off, VSync : On */ - smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); - smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); - smtc_seqw(0x6a, 0x0c); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); - smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10)); - smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); - smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); - smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); - break; - case FB_BLANK_POWERDOWN: - /* Screen On: HSync: Off, VSync : Off */ - smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); - smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); - smtc_seqw(0x6a, 0x0c); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); - smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30)); - smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); - smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); - smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned trans, struct fb_info *info) -{ - struct smtcfb_info *sfb; - u32 val; - - sfb = info->par; - - if (regno > 255) - return 1; - - switch (sfb->fb->fix.visual) { - case FB_VISUAL_DIRECTCOLOR: - case FB_VISUAL_TRUECOLOR: - /* - * 16/32 bit true-colour, use pseudo-palette for 16 base color - */ - if (regno >= 16) - break; - if (sfb->fb->var.bits_per_pixel == 16) { - u32 *pal = sfb->fb->pseudo_palette; - - val = chan_to_field(red, &sfb->fb->var.red); - val |= chan_to_field(green, &sfb->fb->var.green); - val |= chan_to_field(blue, &sfb->fb->var.blue); - pal[regno] = pal_rgb(red, green, blue, val); - } else { - u32 *pal = sfb->fb->pseudo_palette; - - val = chan_to_field(red, &sfb->fb->var.red); - val |= chan_to_field(green, &sfb->fb->var.green); - val |= chan_to_field(blue, &sfb->fb->var.blue); - pal[regno] = big_swap(val); - } - break; - - case FB_VISUAL_PSEUDOCOLOR: - /* color depth 8 bit */ - sm712_setpalette(regno, red, green, blue, info); - break; - - default: - return 1; /* unknown type */ - } - - return 0; -} - -static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, - size_t count, loff_t *ppos) -{ - unsigned long p = *ppos; - - u32 *buffer, *dst; - u32 __iomem *src; - int c, i, cnt = 0, err = 0; - unsigned long total_size; - - if (!info || !info->screen_base) - return -ENODEV; - - if (info->state != FBINFO_STATE_RUNNING) - return -EPERM; - - total_size = info->screen_size; - - if (total_size == 0) - total_size = info->fix.smem_len; - - if (p >= total_size) - return 0; - - if (count >= total_size) - count = total_size; - - if (count + p > total_size) - count = total_size - p; - - buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - src = (u32 __iomem *)(info->screen_base + p); - - if (info->fbops->fb_sync) - info->fbops->fb_sync(info); - - while (count) { - c = (count > PAGE_SIZE) ? PAGE_SIZE : count; - dst = buffer; - for (i = c >> 2; i--;) { - *dst = fb_readl(src++); - *dst = big_swap(*dst); - dst++; - } - if (c & 3) { - u8 *dst8 = (u8 *)dst; - u8 __iomem *src8 = (u8 __iomem *)src; - - for (i = c & 3; i--;) { - if (i & 1) { - *dst8++ = fb_readb(++src8); - } else { - *dst8++ = fb_readb(--src8); - src8 += 2; - } - } - src = (u32 __iomem *)src8; - } - - if (copy_to_user(buf, buffer, c)) { - err = -EFAULT; - break; - } - *ppos += c; - buf += c; - cnt += c; - count -= c; - } - - kfree(buffer); - - return (err) ? err : cnt; -} - -static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - unsigned long p = *ppos; - - u32 *buffer, *src; - u32 __iomem *dst; - int c, i, cnt = 0, err = 0; - unsigned long total_size; - - if (!info || !info->screen_base) - return -ENODEV; - - if (info->state != FBINFO_STATE_RUNNING) - return -EPERM; - - total_size = info->screen_size; - - if (total_size == 0) - total_size = info->fix.smem_len; - - if (p > total_size) - return -EFBIG; - - if (count > total_size) { - err = -EFBIG; - count = total_size; - } - - if (count + p > total_size) { - if (!err) - err = -ENOSPC; - - count = total_size - p; - } - - buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - dst = (u32 __iomem *)(info->screen_base + p); - - if (info->fbops->fb_sync) - info->fbops->fb_sync(info); - - while (count) { - c = (count > PAGE_SIZE) ? PAGE_SIZE : count; - src = buffer; - - if (copy_from_user(src, buf, c)) { - err = -EFAULT; - break; - } - - for (i = c >> 2; i--;) { - fb_writel(big_swap(*src), dst++); - src++; - } - if (c & 3) { - u8 *src8 = (u8 *)src; - u8 __iomem *dst8 = (u8 __iomem *)dst; - - for (i = c & 3; i--;) { - if (i & 1) { - fb_writeb(*src8++, ++dst8); - } else { - fb_writeb(*src8++, --dst8); - dst8 += 2; - } - } - dst = (u32 __iomem *)dst8; - } - - *ppos += c; - buf += c; - cnt += c; - count -= c; - } - - kfree(buffer); - - return (cnt) ? cnt : err; -} - -static void sm7xx_set_timing(struct smtcfb_info *sfb) -{ - int i = 0, j = 0; - u32 m_nscreenstride; - - dev_dbg(&sfb->pdev->dev, - "sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n", - sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz); - - for (j = 0; j < ARRAY_SIZE(vgamode); j++) { - if (vgamode[j].mmsizex != sfb->width || - vgamode[j].mmsizey != sfb->height || - vgamode[j].bpp != sfb->fb->var.bits_per_pixel || - vgamode[j].hz != sfb->hz) - continue; - - dev_dbg(&sfb->pdev->dev, - "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n", - vgamode[j].mmsizex, vgamode[j].mmsizey, - vgamode[j].bpp, vgamode[j].hz); - - dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j); - - smtc_mmiowb(0x0, 0x3c6); - - smtc_seqw(0, 0x1); - - smtc_mmiowb(vgamode[j].init_misc, 0x3c2); - - /* init SEQ register SR00 - SR04 */ - for (i = 0; i < SIZE_SR00_SR04; i++) - smtc_seqw(i, vgamode[j].init_sr00_sr04[i]); - - /* init SEQ register SR10 - SR24 */ - for (i = 0; i < SIZE_SR10_SR24; i++) - smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]); - - /* init SEQ register SR30 - SR75 */ - for (i = 0; i < SIZE_SR30_SR75; i++) - if ((i + 0x30) != 0x62 && (i + 0x30) != 0x6a && - (i + 0x30) != 0x6b) - smtc_seqw(i + 0x30, - vgamode[j].init_sr30_sr75[i]); - - /* init SEQ register SR80 - SR93 */ - for (i = 0; i < SIZE_SR80_SR93; i++) - smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]); - - /* init SEQ register SRA0 - SRAF */ - for (i = 0; i < SIZE_SRA0_SRAF; i++) - smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]); - - /* init Graphic register GR00 - GR08 */ - for (i = 0; i < SIZE_GR00_GR08; i++) - smtc_grphw(i, vgamode[j].init_gr00_gr08[i]); - - /* init Attribute register AR00 - AR14 */ - for (i = 0; i < SIZE_AR00_AR14; i++) - smtc_attrw(i, vgamode[j].init_ar00_ar14[i]); - - /* init CRTC register CR00 - CR18 */ - for (i = 0; i < SIZE_CR00_CR18; i++) - smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]); - - /* init CRTC register CR30 - CR4D */ - for (i = 0; i < SIZE_CR30_CR4D; i++) - smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]); - - /* init CRTC register CR90 - CRA7 */ - for (i = 0; i < SIZE_CR90_CRA7; i++) - smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]); - } - smtc_mmiowb(0x67, 0x3c2); - - /* set VPR registers */ - writel(0x0, sfb->vp_regs + 0x0C); - writel(0x0, sfb->vp_regs + 0x40); - - /* set data width */ - m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64; - switch (sfb->fb->var.bits_per_pixel) { - case 8: - writel(0x0, sfb->vp_regs + 0x0); - break; - case 16: - writel(0x00020000, sfb->vp_regs + 0x0); - break; - case 24: - writel(0x00040000, sfb->vp_regs + 0x0); - break; - case 32: - writel(0x00030000, sfb->vp_regs + 0x0); - break; - } - writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride), - sfb->vp_regs + 0x10); -} - -static void smtc_set_timing(struct smtcfb_info *sfb) -{ - switch (sfb->chip_id) { - case 0x710: - case 0x712: - case 0x720: - sm7xx_set_timing(sfb); - break; - } -} - -static void smtcfb_setmode(struct smtcfb_info *sfb) -{ - switch (sfb->fb->var.bits_per_pixel) { - case 32: - sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; - sfb->fb->fix.line_length = sfb->fb->var.xres * 4; - sfb->fb->var.red.length = 8; - sfb->fb->var.green.length = 8; - sfb->fb->var.blue.length = 8; - sfb->fb->var.red.offset = 16; - sfb->fb->var.green.offset = 8; - sfb->fb->var.blue.offset = 0; - break; - case 24: - sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; - sfb->fb->fix.line_length = sfb->fb->var.xres * 3; - sfb->fb->var.red.length = 8; - sfb->fb->var.green.length = 8; - sfb->fb->var.blue.length = 8; - sfb->fb->var.red.offset = 16; - sfb->fb->var.green.offset = 8; - sfb->fb->var.blue.offset = 0; - break; - case 8: - sfb->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; - sfb->fb->fix.line_length = sfb->fb->var.xres; - sfb->fb->var.red.length = 3; - sfb->fb->var.green.length = 3; - sfb->fb->var.blue.length = 2; - sfb->fb->var.red.offset = 5; - sfb->fb->var.green.offset = 2; - sfb->fb->var.blue.offset = 0; - break; - case 16: - default: - sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; - sfb->fb->fix.line_length = sfb->fb->var.xres * 2; - sfb->fb->var.red.length = 5; - sfb->fb->var.green.length = 6; - sfb->fb->var.blue.length = 5; - sfb->fb->var.red.offset = 11; - sfb->fb->var.green.offset = 5; - sfb->fb->var.blue.offset = 0; - break; - } - - sfb->width = sfb->fb->var.xres; - sfb->height = sfb->fb->var.yres; - sfb->hz = 60; - smtc_set_timing(sfb); -} - -static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - /* sanity checks */ - if (var->xres_virtual < var->xres) - var->xres_virtual = var->xres; - - if (var->yres_virtual < var->yres) - var->yres_virtual = var->yres; - - /* set valid default bpp */ - if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) && - (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32)) - var->bits_per_pixel = 16; - - return 0; -} - -static int smtc_set_par(struct fb_info *info) -{ - smtcfb_setmode(info->par); - - return 0; -} - -static struct fb_ops smtcfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = smtc_check_var, - .fb_set_par = smtc_set_par, - .fb_setcolreg = smtc_setcolreg, - .fb_blank = smtc_blank, - .fb_fillrect = cfb_fillrect, - .fb_imageblit = cfb_imageblit, - .fb_copyarea = cfb_copyarea, - .fb_read = smtcfb_read, - .fb_write = smtcfb_write, -}; - -/* - * Unmap in the memory mapped IO registers - */ - -static void smtc_unmap_mmio(struct smtcfb_info *sfb) -{ - if (sfb && smtc_regbaseaddress) - smtc_regbaseaddress = NULL; -} - -/* - * Map in the screen memory - */ - -static int smtc_map_smem(struct smtcfb_info *sfb, - struct pci_dev *pdev, u_long smem_len) -{ - sfb->fb->fix.smem_start = pci_resource_start(pdev, 0); - - if (sfb->fb->var.bits_per_pixel == 32) - sfb->fb->fix.smem_start += big_addr; - - sfb->fb->fix.smem_len = smem_len; - - sfb->fb->screen_base = sfb->lfb; - - if (!sfb->fb->screen_base) { - dev_err(&pdev->dev, - "%s: unable to map screen memory\n", sfb->fb->fix.id); - return -ENOMEM; - } - - return 0; -} - -/* - * Unmap in the screen memory - * - */ -static void smtc_unmap_smem(struct smtcfb_info *sfb) -{ - if (sfb && sfb->fb->screen_base) { - iounmap(sfb->fb->screen_base); - sfb->fb->screen_base = NULL; - } -} - -/* - * We need to wake up the device and make sure its in linear memory mode. - */ -static inline void sm7xx_init_hw(void) -{ - outb_p(0x18, 0x3c4); - outb_p(0x11, 0x3c5); -} - -static int smtcfb_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct smtcfb_info *sfb; - struct fb_info *info; - u_long smem_size = 0x00800000; /* default 8MB */ - int err; - unsigned long mmio_base; - - dev_info(&pdev->dev, "Silicon Motion display driver.\n"); - - err = pci_enable_device(pdev); /* enable SMTC chip */ - if (err) - return err; - - err = pci_request_region(pdev, 0, "sm7xxfb"); - if (err < 0) { - dev_err(&pdev->dev, "cannot reserve framebuffer region\n"); - goto failed_regions; - } - - sprintf(smtcfb_fix.id, "sm%Xfb", ent->device); - - info = framebuffer_alloc(sizeof(*sfb), &pdev->dev); - if (!info) { - dev_err(&pdev->dev, "framebuffer_alloc failed\n"); - err = -ENOMEM; - goto failed_free; - } - - sfb = info->par; - sfb->fb = info; - sfb->chip_id = ent->device; - sfb->pdev = pdev; - info->flags = FBINFO_FLAG_DEFAULT; - info->fbops = &smtcfb_ops; - info->fix = smtcfb_fix; - info->var = smtcfb_var; - info->pseudo_palette = sfb->colreg; - info->par = sfb; - - pci_set_drvdata(pdev, sfb); - - sm7xx_init_hw(); - - /* get mode parameter from smtc_scr_info */ - if (smtc_scr_info.lfb_width != 0) { - sfb->fb->var.xres = smtc_scr_info.lfb_width; - sfb->fb->var.yres = smtc_scr_info.lfb_height; - sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth; - } else { - /* default resolution 1024x600 16bit mode */ - sfb->fb->var.xres = SCREEN_X_RES; - sfb->fb->var.yres = SCREEN_Y_RES; - sfb->fb->var.bits_per_pixel = SCREEN_BPP; - } - - big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth); - /* Map address and memory detection */ - mmio_base = pci_resource_start(pdev, 0); - pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); - - switch (sfb->chip_id) { - case 0x710: - case 0x712: - sfb->fb->fix.mmio_start = mmio_base + 0x00400000; - sfb->fb->fix.mmio_len = 0x00400000; - smem_size = SM712_VIDEOMEMORYSIZE; - sfb->lfb = ioremap(mmio_base, mmio_addr); - if (!sfb->lfb) { - dev_err(&pdev->dev, - "%s: unable to map memory mapped IO!\n", - sfb->fb->fix.id); - err = -ENOMEM; - goto failed_fb; - } - - sfb->mmio = (smtc_regbaseaddress = - sfb->lfb + 0x00700000); - sfb->dp_regs = sfb->lfb + 0x00408000; - sfb->vp_regs = sfb->lfb + 0x0040c000; - if (sfb->fb->var.bits_per_pixel == 32) { - sfb->lfb += big_addr; - dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb); - } - - /* set MCLK = 14.31818 * (0x16 / 0x2) */ - smtc_seqw(0x6a, 0x16); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x62, 0x3e); - /* enable PCI burst */ - smtc_seqw(0x17, 0x20); - /* enable word swap */ - if (sfb->fb->var.bits_per_pixel == 32) - seqw17(); - break; - case 0x720: - sfb->fb->fix.mmio_start = mmio_base; - sfb->fb->fix.mmio_len = 0x00200000; - smem_size = SM722_VIDEOMEMORYSIZE; - sfb->dp_regs = ioremap(mmio_base, 0x00a00000); - sfb->lfb = sfb->dp_regs + 0x00200000; - sfb->mmio = (smtc_regbaseaddress = - sfb->dp_regs + 0x000c0000); - sfb->vp_regs = sfb->dp_regs + 0x800; - - smtc_seqw(0x62, 0xff); - smtc_seqw(0x6a, 0x0d); - smtc_seqw(0x6b, 0x02); - break; - default: - dev_err(&pdev->dev, - "No valid Silicon Motion display chip was detected!\n"); - - goto failed_fb; - } - - /* can support 32 bpp */ - if (15 == sfb->fb->var.bits_per_pixel) - sfb->fb->var.bits_per_pixel = 16; - - sfb->fb->var.xres_virtual = sfb->fb->var.xres; - sfb->fb->var.yres_virtual = sfb->fb->var.yres; - err = smtc_map_smem(sfb, pdev, smem_size); - if (err) - goto failed; - - smtcfb_setmode(sfb); - - err = register_framebuffer(info); - if (err < 0) - goto failed; - - dev_info(&pdev->dev, - "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n", - sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres, - sfb->fb->var.yres, sfb->fb->var.bits_per_pixel); - - return 0; - -failed: - dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n"); - - smtc_unmap_smem(sfb); - smtc_unmap_mmio(sfb); -failed_fb: - framebuffer_release(info); - -failed_free: - pci_release_region(pdev, 0); - -failed_regions: - pci_disable_device(pdev); - - return err; -} - -/* - * 0x710 (LynxEM) - * 0x712 (LynxEM+) - * 0x720 (Lynx3DM, Lynx3DM+) - */ -static const struct pci_device_id smtcfb_pci_table[] = { - { PCI_DEVICE(0x126f, 0x710), }, - { PCI_DEVICE(0x126f, 0x712), }, - { PCI_DEVICE(0x126f, 0x720), }, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, smtcfb_pci_table); - -static void smtcfb_pci_remove(struct pci_dev *pdev) -{ - struct smtcfb_info *sfb; - - sfb = pci_get_drvdata(pdev); - smtc_unmap_smem(sfb); - smtc_unmap_mmio(sfb); - unregister_framebuffer(sfb->fb); - framebuffer_release(sfb->fb); - pci_release_region(pdev, 0); - pci_disable_device(pdev); -} - -#ifdef CONFIG_PM -static int smtcfb_pci_suspend(struct device *device) -{ - struct pci_dev *pdev = to_pci_dev(device); - struct smtcfb_info *sfb; - - sfb = pci_get_drvdata(pdev); - - /* set the hw in sleep mode use external clock and self memory refresh - * so that we can turn off internal PLLs later on - */ - smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0)); - smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7)); - - console_lock(); - fb_set_suspend(sfb->fb, 1); - console_unlock(); - - /* additionally turn off all function blocks including internal PLLs */ - smtc_seqw(0x21, 0xff); - - return 0; -} - -static int smtcfb_pci_resume(struct device *device) -{ - struct pci_dev *pdev = to_pci_dev(device); - struct smtcfb_info *sfb; - - sfb = pci_get_drvdata(pdev); - - /* reinit hardware */ - sm7xx_init_hw(); - switch (sfb->chip_id) { - case 0x710: - case 0x712: - /* set MCLK = 14.31818 * (0x16 / 0x2) */ - smtc_seqw(0x6a, 0x16); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x62, 0x3e); - /* enable PCI burst */ - smtc_seqw(0x17, 0x20); - if (sfb->fb->var.bits_per_pixel == 32) - seqw17(); - break; - case 0x720: - smtc_seqw(0x62, 0xff); - smtc_seqw(0x6a, 0x0d); - smtc_seqw(0x6b, 0x02); - break; - } - - smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0)); - smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb)); - - smtcfb_setmode(sfb); - - console_lock(); - fb_set_suspend(sfb->fb, 0); - console_unlock(); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume); -#define SM7XX_PM_OPS (&sm7xx_pm_ops) - -#else /* !CONFIG_PM */ - -#define SM7XX_PM_OPS NULL - -#endif /* !CONFIG_PM */ - -static struct pci_driver smtcfb_driver = { - .name = "smtcfb", - .id_table = smtcfb_pci_table, - .probe = smtcfb_pci_probe, - .remove = smtcfb_pci_remove, - .driver.pm = SM7XX_PM_OPS, -}; - -static int __init sm712fb_init(void) -{ - char *option = NULL; - - if (fb_get_options("sm712fb", &option)) - return -ENODEV; - if (option && *option) - mode_option = option; - sm7xx_vga_setup(mode_option); - - return pci_register_driver(&smtcfb_driver); -} - -module_init(sm712fb_init); - -static void __exit sm712fb_exit(void) -{ - pci_unregister_driver(&smtcfb_driver); -} - -module_exit(sm712fb_exit); - -MODULE_AUTHOR("Siliconmotion "); -MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index 2d98de535e0f..230790984088 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -2475,3 +2475,17 @@ config FB_SSD1307 help This driver implements support for the Solomon SSD1307 OLED controller over I2C. + +config FB_SM712 + tristate "Silicon Motion SM712 framebuffer support" + depends on FB && PCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + Frame buffer driver for the Silicon Motion SM710, SM712, SM721 + and SM722 chips. + + This driver is also available as a module. The module will be + called sm712fb. If you want to compile it as a module, say M + here and read . diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index cecea5063a80..50ed1b4fc2bf 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -131,6 +131,7 @@ obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o obj-$(CONFIG_FB_OPENCORES) += ocfb.o +obj-$(CONFIG_FB_SM712) += sm712fb.o # Platform or fallback drivers go here obj-$(CONFIG_FB_UVESA) += uvesafb.o diff --git a/drivers/video/fbdev/sm712.h b/drivers/video/fbdev/sm712.h new file mode 100644 index 000000000000..aad1cc4be34a --- /dev/null +++ b/drivers/video/fbdev/sm712.h @@ -0,0 +1,116 @@ +/* + * Silicon Motion SM712 frame buffer device + * + * Copyright (C) 2006 Silicon Motion Technology Corp. + * Authors: Ge Wang, gewang@siliconmotion.com + * Boyod boyod.yang@siliconmotion.com.cn + * + * Copyright (C) 2009 Lemote, Inc. + * Author: Wu Zhangjin, wuzhangjin@gmail.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#define FB_ACCEL_SMI_LYNX 88 + +#define SCREEN_X_RES 1024 +#define SCREEN_Y_RES 600 +#define SCREEN_BPP 16 + +/*Assume SM712 graphics chip has 4MB VRAM */ +#define SM712_VIDEOMEMORYSIZE 0x00400000 +/*Assume SM722 graphics chip has 8MB VRAM */ +#define SM722_VIDEOMEMORYSIZE 0x00800000 + +#define dac_reg (0x3c8) +#define dac_val (0x3c9) + +extern void __iomem *smtc_regbaseaddress; +#define smtc_mmiowb(dat, reg) writeb(dat, smtc_regbaseaddress + reg) + +#define smtc_mmiorb(reg) readb(smtc_regbaseaddress + reg) + +#define SIZE_SR00_SR04 (0x04 - 0x00 + 1) +#define SIZE_SR10_SR24 (0x24 - 0x10 + 1) +#define SIZE_SR30_SR75 (0x75 - 0x30 + 1) +#define SIZE_SR80_SR93 (0x93 - 0x80 + 1) +#define SIZE_SRA0_SRAF (0xAF - 0xA0 + 1) +#define SIZE_GR00_GR08 (0x08 - 0x00 + 1) +#define SIZE_AR00_AR14 (0x14 - 0x00 + 1) +#define SIZE_CR00_CR18 (0x18 - 0x00 + 1) +#define SIZE_CR30_CR4D (0x4D - 0x30 + 1) +#define SIZE_CR90_CRA7 (0xA7 - 0x90 + 1) + +static inline void smtc_crtcw(int reg, int val) +{ + smtc_mmiowb(reg, 0x3d4); + smtc_mmiowb(val, 0x3d5); +} + +static inline void smtc_grphw(int reg, int val) +{ + smtc_mmiowb(reg, 0x3ce); + smtc_mmiowb(val, 0x3cf); +} + +static inline void smtc_attrw(int reg, int val) +{ + smtc_mmiorb(0x3da); + smtc_mmiowb(reg, 0x3c0); + smtc_mmiorb(0x3c1); + smtc_mmiowb(val, 0x3c0); +} + +static inline void smtc_seqw(int reg, int val) +{ + smtc_mmiowb(reg, 0x3c4); + smtc_mmiowb(val, 0x3c5); +} + +static inline unsigned int smtc_seqr(int reg) +{ + smtc_mmiowb(reg, 0x3c4); + return smtc_mmiorb(0x3c5); +} + +/* The next structure holds all information relevant for a specific video mode. + */ + +struct modeinit { + int mmsizex; + int mmsizey; + int bpp; + int hz; + unsigned char init_misc; + unsigned char init_sr00_sr04[SIZE_SR00_SR04]; + unsigned char init_sr10_sr24[SIZE_SR10_SR24]; + unsigned char init_sr30_sr75[SIZE_SR30_SR75]; + unsigned char init_sr80_sr93[SIZE_SR80_SR93]; + unsigned char init_sra0_sraf[SIZE_SRA0_SRAF]; + unsigned char init_gr00_gr08[SIZE_GR00_GR08]; + unsigned char init_ar00_ar14[SIZE_AR00_AR14]; + unsigned char init_cr00_cr18[SIZE_CR00_CR18]; + unsigned char init_cr30_cr4d[SIZE_CR30_CR4D]; + unsigned char init_cr90_cra7[SIZE_CR90_CRA7]; +}; + +#ifdef __BIG_ENDIAN +#define pal_rgb(r, g, b, val) (((r & 0xf800) >> 8) | \ + ((g & 0xe000) >> 13) | \ + ((g & 0x1c00) << 3) | \ + ((b & 0xf800) >> 3)) +#define big_addr 0x800000 +#define mmio_addr 0x00800000 +#define seqw17() smtc_seqw(0x17, 0x30) +#define big_pixel_depth(p, d) {if (p == 24) {p = 32; d = 32; } } +#define big_swap(p) ((p & 0xff00ff00 >> 8) | (p & 0x00ff00ff << 8)) +#else +#define pal_rgb(r, g, b, val) val +#define big_addr 0 +#define mmio_addr 0x00c00000 +#define seqw17() do { } while (0) +#define big_pixel_depth(p, d) do { } while (0) +#define big_swap(p) p +#endif diff --git a/drivers/video/fbdev/sm712fb.c b/drivers/video/fbdev/sm712fb.c new file mode 100644 index 000000000000..629bfa2d2f51 --- /dev/null +++ b/drivers/video/fbdev/sm712fb.c @@ -0,0 +1,1653 @@ +/* + * Silicon Motion SM7XX frame buffer device + * + * Copyright (C) 2006 Silicon Motion Technology Corp. + * Authors: Ge Wang, gewang@siliconmotion.com + * Boyod boyod.yang@siliconmotion.com.cn + * + * Copyright (C) 2009 Lemote, Inc. + * Author: Wu Zhangjin, wuzhangjin@gmail.com + * + * Copyright (C) 2011 Igalia, S.L. + * Author: Javier M. Mellid + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM +#include +#endif + +#include "sm712.h" + +/* +* Private structure +*/ +struct smtcfb_info { + struct pci_dev *pdev; + struct fb_info *fb; + u16 chip_id; + u8 chip_rev_id; + + void __iomem *lfb; /* linear frame buffer */ + void __iomem *dp_regs; /* drawing processor control regs */ + void __iomem *vp_regs; /* video processor control regs */ + void __iomem *cp_regs; /* capture processor control regs */ + void __iomem *mmio; /* memory map IO port */ + + u_int width; + u_int height; + u_int hz; + + u32 colreg[17]; +}; + +void __iomem *smtc_regbaseaddress; /* Memory Map IO starting address */ + +static struct fb_var_screeninfo smtcfb_var = { + .xres = 1024, + .yres = 600, + .xres_virtual = 1024, + .yres_virtual = 600, + .bits_per_pixel = 16, + .red = {16, 8, 0}, + .green = {8, 8, 0}, + .blue = {0, 8, 0}, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, + .nonstd = 0, + .accel_flags = FB_ACCELF_TEXT, +}; + +static struct fb_fix_screeninfo smtcfb_fix = { + .id = "smXXXfb", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .line_length = 800 * 3, + .accel = FB_ACCEL_SMI_LYNX, + .type_aux = 0, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, +}; + +struct vesa_mode { + char index[6]; + u16 lfb_width; + u16 lfb_height; + u16 lfb_depth; +}; + +static const struct vesa_mode vesa_mode_table[] = { + {"0x301", 640, 480, 8}, + {"0x303", 800, 600, 8}, + {"0x305", 1024, 768, 8}, + {"0x307", 1280, 1024, 8}, + + {"0x311", 640, 480, 16}, + {"0x314", 800, 600, 16}, + {"0x317", 1024, 768, 16}, + {"0x31A", 1280, 1024, 16}, + + {"0x312", 640, 480, 24}, + {"0x315", 800, 600, 24}, + {"0x318", 1024, 768, 24}, + {"0x31B", 1280, 1024, 24}, +}; + +/********************************************************************** + SM712 Mode table. + **********************************************************************/ +static const struct modeinit vgamode[] = { + { + /* mode#0: 640 x 480 16Bpp 60Hz */ + 640, 480, 16, 60, + /* Init_MISC */ + 0xE3, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, + 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, + 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, + 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, + 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, + 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, + 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, + 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, + }, + }, + { + /* mode#1: 640 x 480 24Bpp 60Hz */ + 640, 480, 24, 60, + /* Init_MISC */ + 0xE3, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, + 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, + 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, + 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, + 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, + 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, + 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, + 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, + }, + }, + { + /* mode#0: 640 x 480 32Bpp 60Hz */ + 640, 480, 32, 60, + /* Init_MISC */ + 0xE3, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, + 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, + 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, + 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, + 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, + 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, + 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, + 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, + }, + }, + + { /* mode#2: 800 x 600 16Bpp 60Hz */ + 800, 600, 16, 60, + /* Init_MISC */ + 0x2B, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, + 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, + 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, + 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, + 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, + 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, + 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, + 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, + 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, + }, + }, + { /* mode#3: 800 x 600 24Bpp 60Hz */ + 800, 600, 24, 60, + 0x2B, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, + 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, + 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, + 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, + 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, + 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, + 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, + 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, + }, + }, + { /* mode#7: 800 x 600 32Bpp 60Hz */ + 800, 600, 32, 60, + /* Init_MISC */ + 0x2B, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, + 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, + 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, + 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, + 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, + 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, + 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, + 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, + 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, + }, + }, + /* We use 1024x768 table to light 1024x600 panel for lemote */ + { /* mode#4: 1024 x 600 16Bpp 60Hz */ + 1024, 600, 16, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, + 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x00, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, + 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, + 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, + 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + { /* mode#5: 1024 x 768 24Bpp 60Hz */ + 1024, 768, 24, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, + 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + { /* mode#4: 1024 x 768 32Bpp 60Hz */ + 1024, 768, 32, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x32, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, + 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + { /* mode#6: 320 x 240 16Bpp 60Hz */ + 320, 240, 16, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x32, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, + 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + + { /* mode#8: 320 x 240 32Bpp 60Hz */ + 320, 240, 32, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x32, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, + 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, +}; + +static struct screen_info smtc_scr_info; + +static char *mode_option; + +/* process command line options, get vga parameter */ +static void __init sm7xx_vga_setup(char *options) +{ + int i; + + if (!options || !*options) + return; + + smtc_scr_info.lfb_width = 0; + smtc_scr_info.lfb_height = 0; + smtc_scr_info.lfb_depth = 0; + + pr_debug("sm7xx_vga_setup = %s\n", options); + + for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { + if (strstr(options, vesa_mode_table[i].index)) { + smtc_scr_info.lfb_width = vesa_mode_table[i].lfb_width; + smtc_scr_info.lfb_height = + vesa_mode_table[i].lfb_height; + smtc_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; + return; + } + } +} + +static void sm712_setpalette(int regno, unsigned red, unsigned green, + unsigned blue, struct fb_info *info) +{ + /* set bit 5:4 = 01 (write LCD RAM only) */ + smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10); + + smtc_mmiowb(regno, dac_reg); + smtc_mmiowb(red >> 10, dac_val); + smtc_mmiowb(green >> 10, dac_val); + smtc_mmiowb(blue >> 10, dac_val); +} + +/* chan_to_field + * + * convert a colour value into a field position + * + * from pxafb.c + */ + +static inline unsigned int chan_to_field(unsigned int chan, + struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int smtc_blank(int blank_mode, struct fb_info *info) +{ + /* clear DPMS setting */ + switch (blank_mode) { + case FB_BLANK_UNBLANK: + /* Screen On: HSync: On, VSync : On */ + smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77)); + smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); + smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); + smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); + smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03)); + break; + case FB_BLANK_NORMAL: + /* Screen Off: HSync: On, VSync : On Soft blank */ + smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); + smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); + smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + break; + case FB_BLANK_VSYNC_SUSPEND: + /* Screen On: HSync: On, VSync : Off */ + smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); + smtc_seqw(0x6a, 0x0c); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); + smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20)); + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20)); + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); + break; + case FB_BLANK_HSYNC_SUSPEND: + /* Screen On: HSync: Off, VSync : On */ + smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); + smtc_seqw(0x6a, 0x0c); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); + smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10)); + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); + break; + case FB_BLANK_POWERDOWN: + /* Screen On: HSync: Off, VSync : Off */ + smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); + smtc_seqw(0x6a, 0x0c); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); + smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30)); + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned trans, struct fb_info *info) +{ + struct smtcfb_info *sfb; + u32 val; + + sfb = info->par; + + if (regno > 255) + return 1; + + switch (sfb->fb->fix.visual) { + case FB_VISUAL_DIRECTCOLOR: + case FB_VISUAL_TRUECOLOR: + /* + * 16/32 bit true-colour, use pseudo-palette for 16 base color + */ + if (regno >= 16) + break; + if (sfb->fb->var.bits_per_pixel == 16) { + u32 *pal = sfb->fb->pseudo_palette; + + val = chan_to_field(red, &sfb->fb->var.red); + val |= chan_to_field(green, &sfb->fb->var.green); + val |= chan_to_field(blue, &sfb->fb->var.blue); + pal[regno] = pal_rgb(red, green, blue, val); + } else { + u32 *pal = sfb->fb->pseudo_palette; + + val = chan_to_field(red, &sfb->fb->var.red); + val |= chan_to_field(green, &sfb->fb->var.green); + val |= chan_to_field(blue, &sfb->fb->var.blue); + pal[regno] = big_swap(val); + } + break; + + case FB_VISUAL_PSEUDOCOLOR: + /* color depth 8 bit */ + sm712_setpalette(regno, red, green, blue, info); + break; + + default: + return 1; /* unknown type */ + } + + return 0; +} + +static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + + u32 *buffer, *dst; + u32 __iomem *src; + int c, i, cnt = 0, err = 0; + unsigned long total_size; + + if (!info || !info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p >= total_size) + return 0; + + if (count >= total_size) + count = total_size; + + if (count + p > total_size) + count = total_size - p; + + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + src = (u32 __iomem *)(info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + dst = buffer; + for (i = c >> 2; i--;) { + *dst = fb_readl(src++); + *dst = big_swap(*dst); + dst++; + } + if (c & 3) { + u8 *dst8 = (u8 *)dst; + u8 __iomem *src8 = (u8 __iomem *)src; + + for (i = c & 3; i--;) { + if (i & 1) { + *dst8++ = fb_readb(++src8); + } else { + *dst8++ = fb_readb(--src8); + src8 += 2; + } + } + src = (u32 __iomem *)src8; + } + + if (copy_to_user(buf, buffer, c)) { + err = -EFAULT; + break; + } + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + + kfree(buffer); + + return (err) ? err : cnt; +} + +static ssize_t smtcfb_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + + u32 *buffer, *src; + u32 __iomem *dst; + int c, i, cnt = 0, err = 0; + unsigned long total_size; + + if (!info || !info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; + } + + if (count + p > total_size) { + if (!err) + err = -ENOSPC; + + count = total_size - p; + } + + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + dst = (u32 __iomem *)(info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + src = buffer; + + if (copy_from_user(src, buf, c)) { + err = -EFAULT; + break; + } + + for (i = c >> 2; i--;) { + fb_writel(big_swap(*src), dst++); + src++; + } + if (c & 3) { + u8 *src8 = (u8 *)src; + u8 __iomem *dst8 = (u8 __iomem *)dst; + + for (i = c & 3; i--;) { + if (i & 1) { + fb_writeb(*src8++, ++dst8); + } else { + fb_writeb(*src8++, --dst8); + dst8 += 2; + } + } + dst = (u32 __iomem *)dst8; + } + + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + + kfree(buffer); + + return (cnt) ? cnt : err; +} + +static void sm7xx_set_timing(struct smtcfb_info *sfb) +{ + int i = 0, j = 0; + u32 m_nscreenstride; + + dev_dbg(&sfb->pdev->dev, + "sfb->width=%d sfb->height=%d sfb->fb->var.bits_per_pixel=%d sfb->hz=%d\n", + sfb->width, sfb->height, sfb->fb->var.bits_per_pixel, sfb->hz); + + for (j = 0; j < ARRAY_SIZE(vgamode); j++) { + if (vgamode[j].mmsizex != sfb->width || + vgamode[j].mmsizey != sfb->height || + vgamode[j].bpp != sfb->fb->var.bits_per_pixel || + vgamode[j].hz != sfb->hz) + continue; + + dev_dbg(&sfb->pdev->dev, + "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n", + vgamode[j].mmsizex, vgamode[j].mmsizey, + vgamode[j].bpp, vgamode[j].hz); + + dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j); + + smtc_mmiowb(0x0, 0x3c6); + + smtc_seqw(0, 0x1); + + smtc_mmiowb(vgamode[j].init_misc, 0x3c2); + + /* init SEQ register SR00 - SR04 */ + for (i = 0; i < SIZE_SR00_SR04; i++) + smtc_seqw(i, vgamode[j].init_sr00_sr04[i]); + + /* init SEQ register SR10 - SR24 */ + for (i = 0; i < SIZE_SR10_SR24; i++) + smtc_seqw(i + 0x10, vgamode[j].init_sr10_sr24[i]); + + /* init SEQ register SR30 - SR75 */ + for (i = 0; i < SIZE_SR30_SR75; i++) + if ((i + 0x30) != 0x62 && (i + 0x30) != 0x6a && + (i + 0x30) != 0x6b) + smtc_seqw(i + 0x30, + vgamode[j].init_sr30_sr75[i]); + + /* init SEQ register SR80 - SR93 */ + for (i = 0; i < SIZE_SR80_SR93; i++) + smtc_seqw(i + 0x80, vgamode[j].init_sr80_sr93[i]); + + /* init SEQ register SRA0 - SRAF */ + for (i = 0; i < SIZE_SRA0_SRAF; i++) + smtc_seqw(i + 0xa0, vgamode[j].init_sra0_sraf[i]); + + /* init Graphic register GR00 - GR08 */ + for (i = 0; i < SIZE_GR00_GR08; i++) + smtc_grphw(i, vgamode[j].init_gr00_gr08[i]); + + /* init Attribute register AR00 - AR14 */ + for (i = 0; i < SIZE_AR00_AR14; i++) + smtc_attrw(i, vgamode[j].init_ar00_ar14[i]); + + /* init CRTC register CR00 - CR18 */ + for (i = 0; i < SIZE_CR00_CR18; i++) + smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]); + + /* init CRTC register CR30 - CR4D */ + for (i = 0; i < SIZE_CR30_CR4D; i++) + smtc_crtcw(i + 0x30, vgamode[j].init_cr30_cr4d[i]); + + /* init CRTC register CR90 - CRA7 */ + for (i = 0; i < SIZE_CR90_CRA7; i++) + smtc_crtcw(i + 0x90, vgamode[j].init_cr90_cra7[i]); + } + smtc_mmiowb(0x67, 0x3c2); + + /* set VPR registers */ + writel(0x0, sfb->vp_regs + 0x0C); + writel(0x0, sfb->vp_regs + 0x40); + + /* set data width */ + m_nscreenstride = (sfb->width * sfb->fb->var.bits_per_pixel) / 64; + switch (sfb->fb->var.bits_per_pixel) { + case 8: + writel(0x0, sfb->vp_regs + 0x0); + break; + case 16: + writel(0x00020000, sfb->vp_regs + 0x0); + break; + case 24: + writel(0x00040000, sfb->vp_regs + 0x0); + break; + case 32: + writel(0x00030000, sfb->vp_regs + 0x0); + break; + } + writel((u32)(((m_nscreenstride + 2) << 16) | m_nscreenstride), + sfb->vp_regs + 0x10); +} + +static void smtc_set_timing(struct smtcfb_info *sfb) +{ + switch (sfb->chip_id) { + case 0x710: + case 0x712: + case 0x720: + sm7xx_set_timing(sfb); + break; + } +} + +static void smtcfb_setmode(struct smtcfb_info *sfb) +{ + switch (sfb->fb->var.bits_per_pixel) { + case 32: + sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; + sfb->fb->fix.line_length = sfb->fb->var.xres * 4; + sfb->fb->var.red.length = 8; + sfb->fb->var.green.length = 8; + sfb->fb->var.blue.length = 8; + sfb->fb->var.red.offset = 16; + sfb->fb->var.green.offset = 8; + sfb->fb->var.blue.offset = 0; + break; + case 24: + sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; + sfb->fb->fix.line_length = sfb->fb->var.xres * 3; + sfb->fb->var.red.length = 8; + sfb->fb->var.green.length = 8; + sfb->fb->var.blue.length = 8; + sfb->fb->var.red.offset = 16; + sfb->fb->var.green.offset = 8; + sfb->fb->var.blue.offset = 0; + break; + case 8: + sfb->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; + sfb->fb->fix.line_length = sfb->fb->var.xres; + sfb->fb->var.red.length = 3; + sfb->fb->var.green.length = 3; + sfb->fb->var.blue.length = 2; + sfb->fb->var.red.offset = 5; + sfb->fb->var.green.offset = 2; + sfb->fb->var.blue.offset = 0; + break; + case 16: + default: + sfb->fb->fix.visual = FB_VISUAL_TRUECOLOR; + sfb->fb->fix.line_length = sfb->fb->var.xres * 2; + sfb->fb->var.red.length = 5; + sfb->fb->var.green.length = 6; + sfb->fb->var.blue.length = 5; + sfb->fb->var.red.offset = 11; + sfb->fb->var.green.offset = 5; + sfb->fb->var.blue.offset = 0; + break; + } + + sfb->width = sfb->fb->var.xres; + sfb->height = sfb->fb->var.yres; + sfb->hz = 60; + smtc_set_timing(sfb); +} + +static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + /* sanity checks */ + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + /* set valid default bpp */ + if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) && + (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32)) + var->bits_per_pixel = 16; + + return 0; +} + +static int smtc_set_par(struct fb_info *info) +{ + smtcfb_setmode(info->par); + + return 0; +} + +static struct fb_ops smtcfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = smtc_check_var, + .fb_set_par = smtc_set_par, + .fb_setcolreg = smtc_setcolreg, + .fb_blank = smtc_blank, + .fb_fillrect = cfb_fillrect, + .fb_imageblit = cfb_imageblit, + .fb_copyarea = cfb_copyarea, + .fb_read = smtcfb_read, + .fb_write = smtcfb_write, +}; + +/* + * Unmap in the memory mapped IO registers + */ + +static void smtc_unmap_mmio(struct smtcfb_info *sfb) +{ + if (sfb && smtc_regbaseaddress) + smtc_regbaseaddress = NULL; +} + +/* + * Map in the screen memory + */ + +static int smtc_map_smem(struct smtcfb_info *sfb, + struct pci_dev *pdev, u_long smem_len) +{ + sfb->fb->fix.smem_start = pci_resource_start(pdev, 0); + + if (sfb->fb->var.bits_per_pixel == 32) + sfb->fb->fix.smem_start += big_addr; + + sfb->fb->fix.smem_len = smem_len; + + sfb->fb->screen_base = sfb->lfb; + + if (!sfb->fb->screen_base) { + dev_err(&pdev->dev, + "%s: unable to map screen memory\n", sfb->fb->fix.id); + return -ENOMEM; + } + + return 0; +} + +/* + * Unmap in the screen memory + * + */ +static void smtc_unmap_smem(struct smtcfb_info *sfb) +{ + if (sfb && sfb->fb->screen_base) { + iounmap(sfb->fb->screen_base); + sfb->fb->screen_base = NULL; + } +} + +/* + * We need to wake up the device and make sure its in linear memory mode. + */ +static inline void sm7xx_init_hw(void) +{ + outb_p(0x18, 0x3c4); + outb_p(0x11, 0x3c5); +} + +static int smtcfb_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct smtcfb_info *sfb; + struct fb_info *info; + u_long smem_size = 0x00800000; /* default 8MB */ + int err; + unsigned long mmio_base; + + dev_info(&pdev->dev, "Silicon Motion display driver.\n"); + + err = pci_enable_device(pdev); /* enable SMTC chip */ + if (err) + return err; + + err = pci_request_region(pdev, 0, "sm7xxfb"); + if (err < 0) { + dev_err(&pdev->dev, "cannot reserve framebuffer region\n"); + goto failed_regions; + } + + sprintf(smtcfb_fix.id, "sm%Xfb", ent->device); + + info = framebuffer_alloc(sizeof(*sfb), &pdev->dev); + if (!info) { + dev_err(&pdev->dev, "framebuffer_alloc failed\n"); + err = -ENOMEM; + goto failed_free; + } + + sfb = info->par; + sfb->fb = info; + sfb->chip_id = ent->device; + sfb->pdev = pdev; + info->flags = FBINFO_FLAG_DEFAULT; + info->fbops = &smtcfb_ops; + info->fix = smtcfb_fix; + info->var = smtcfb_var; + info->pseudo_palette = sfb->colreg; + info->par = sfb; + + pci_set_drvdata(pdev, sfb); + + sm7xx_init_hw(); + + /* get mode parameter from smtc_scr_info */ + if (smtc_scr_info.lfb_width != 0) { + sfb->fb->var.xres = smtc_scr_info.lfb_width; + sfb->fb->var.yres = smtc_scr_info.lfb_height; + sfb->fb->var.bits_per_pixel = smtc_scr_info.lfb_depth; + } else { + /* default resolution 1024x600 16bit mode */ + sfb->fb->var.xres = SCREEN_X_RES; + sfb->fb->var.yres = SCREEN_Y_RES; + sfb->fb->var.bits_per_pixel = SCREEN_BPP; + } + + big_pixel_depth(sfb->fb->var.bits_per_pixel, smtc_scr_info.lfb_depth); + /* Map address and memory detection */ + mmio_base = pci_resource_start(pdev, 0); + pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); + + switch (sfb->chip_id) { + case 0x710: + case 0x712: + sfb->fb->fix.mmio_start = mmio_base + 0x00400000; + sfb->fb->fix.mmio_len = 0x00400000; + smem_size = SM712_VIDEOMEMORYSIZE; + sfb->lfb = ioremap(mmio_base, mmio_addr); + if (!sfb->lfb) { + dev_err(&pdev->dev, + "%s: unable to map memory mapped IO!\n", + sfb->fb->fix.id); + err = -ENOMEM; + goto failed_fb; + } + + sfb->mmio = (smtc_regbaseaddress = + sfb->lfb + 0x00700000); + sfb->dp_regs = sfb->lfb + 0x00408000; + sfb->vp_regs = sfb->lfb + 0x0040c000; + if (sfb->fb->var.bits_per_pixel == 32) { + sfb->lfb += big_addr; + dev_info(&pdev->dev, "sfb->lfb=%p\n", sfb->lfb); + } + + /* set MCLK = 14.31818 * (0x16 / 0x2) */ + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x62, 0x3e); + /* enable PCI burst */ + smtc_seqw(0x17, 0x20); + /* enable word swap */ + if (sfb->fb->var.bits_per_pixel == 32) + seqw17(); + break; + case 0x720: + sfb->fb->fix.mmio_start = mmio_base; + sfb->fb->fix.mmio_len = 0x00200000; + smem_size = SM722_VIDEOMEMORYSIZE; + sfb->dp_regs = ioremap(mmio_base, 0x00a00000); + sfb->lfb = sfb->dp_regs + 0x00200000; + sfb->mmio = (smtc_regbaseaddress = + sfb->dp_regs + 0x000c0000); + sfb->vp_regs = sfb->dp_regs + 0x800; + + smtc_seqw(0x62, 0xff); + smtc_seqw(0x6a, 0x0d); + smtc_seqw(0x6b, 0x02); + break; + default: + dev_err(&pdev->dev, + "No valid Silicon Motion display chip was detected!\n"); + + goto failed_fb; + } + + /* can support 32 bpp */ + if (15 == sfb->fb->var.bits_per_pixel) + sfb->fb->var.bits_per_pixel = 16; + + sfb->fb->var.xres_virtual = sfb->fb->var.xres; + sfb->fb->var.yres_virtual = sfb->fb->var.yres; + err = smtc_map_smem(sfb, pdev, smem_size); + if (err) + goto failed; + + smtcfb_setmode(sfb); + + err = register_framebuffer(info); + if (err < 0) + goto failed; + + dev_info(&pdev->dev, + "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.\n", + sfb->chip_id, sfb->chip_rev_id, sfb->fb->var.xres, + sfb->fb->var.yres, sfb->fb->var.bits_per_pixel); + + return 0; + +failed: + dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.\n"); + + smtc_unmap_smem(sfb); + smtc_unmap_mmio(sfb); +failed_fb: + framebuffer_release(info); + +failed_free: + pci_release_region(pdev, 0); + +failed_regions: + pci_disable_device(pdev); + + return err; +} + +/* + * 0x710 (LynxEM) + * 0x712 (LynxEM+) + * 0x720 (Lynx3DM, Lynx3DM+) + */ +static const struct pci_device_id smtcfb_pci_table[] = { + { PCI_DEVICE(0x126f, 0x710), }, + { PCI_DEVICE(0x126f, 0x712), }, + { PCI_DEVICE(0x126f, 0x720), }, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, smtcfb_pci_table); + +static void smtcfb_pci_remove(struct pci_dev *pdev) +{ + struct smtcfb_info *sfb; + + sfb = pci_get_drvdata(pdev); + smtc_unmap_smem(sfb); + smtc_unmap_mmio(sfb); + unregister_framebuffer(sfb->fb); + framebuffer_release(sfb->fb); + pci_release_region(pdev, 0); + pci_disable_device(pdev); +} + +#ifdef CONFIG_PM +static int smtcfb_pci_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct smtcfb_info *sfb; + + sfb = pci_get_drvdata(pdev); + + /* set the hw in sleep mode use external clock and self memory refresh + * so that we can turn off internal PLLs later on + */ + smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0)); + smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7)); + + console_lock(); + fb_set_suspend(sfb->fb, 1); + console_unlock(); + + /* additionally turn off all function blocks including internal PLLs */ + smtc_seqw(0x21, 0xff); + + return 0; +} + +static int smtcfb_pci_resume(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct smtcfb_info *sfb; + + sfb = pci_get_drvdata(pdev); + + /* reinit hardware */ + sm7xx_init_hw(); + switch (sfb->chip_id) { + case 0x710: + case 0x712: + /* set MCLK = 14.31818 * (0x16 / 0x2) */ + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x62, 0x3e); + /* enable PCI burst */ + smtc_seqw(0x17, 0x20); + if (sfb->fb->var.bits_per_pixel == 32) + seqw17(); + break; + case 0x720: + smtc_seqw(0x62, 0xff); + smtc_seqw(0x6a, 0x0d); + smtc_seqw(0x6b, 0x02); + break; + } + + smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0)); + smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb)); + + smtcfb_setmode(sfb); + + console_lock(); + fb_set_suspend(sfb->fb, 0); + console_unlock(); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume); +#define SM7XX_PM_OPS (&sm7xx_pm_ops) + +#else /* !CONFIG_PM */ + +#define SM7XX_PM_OPS NULL + +#endif /* !CONFIG_PM */ + +static struct pci_driver smtcfb_driver = { + .name = "smtcfb", + .id_table = smtcfb_pci_table, + .probe = smtcfb_pci_probe, + .remove = smtcfb_pci_remove, + .driver.pm = SM7XX_PM_OPS, +}; + +static int __init sm712fb_init(void) +{ + char *option = NULL; + + if (fb_get_options("sm712fb", &option)) + return -ENODEV; + if (option && *option) + mode_option = option; + sm7xx_vga_setup(mode_option); + + return pci_register_driver(&smtcfb_driver); +} + +module_init(sm712fb_init); + +static void __exit sm712fb_exit(void) +{ + pci_unregister_driver(&smtcfb_driver); +} + +module_exit(sm712fb_exit); + +MODULE_AUTHOR("Siliconmotion "); +MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 8fc8cf4482fa1b983a5e971aa037aaa76179b28c Mon Sep 17 00:00:00 2001 From: Johannes Postma Date: Thu, 6 Aug 2015 12:21:52 +0100 Subject: staging: rtl8723au: Fix sparse warning: cast to restricted __le16 usPtr is used as __le16 *, but was defined as u16 *. This was reported by sparse as: drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c:1850:29: warning: cast to restricted __le16 This patch fixes the type of usPtr. Signed-off-by: Johannes Postma Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c index cb5076abda8b..eb76ac473630 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c +++ b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c @@ -1838,7 +1838,7 @@ Hal_EfuseParseThermalMeter_8723A(struct rtw_adapter *padapter, static void rtl8723a_cal_txdesc_chksum(struct tx_desc *ptxdesc) { - u16 *usPtr = (u16 *) ptxdesc; + __le16 *usPtr = (__le16 *)ptxdesc; u32 count = 16; /* (32 bytes / 2 bytes per XOR) => 16 times */ u32 index; u16 checksum = 0; -- cgit v1.3-6-gb490 From 25e66320167117d428d2c99076be5e5de557b7d1 Mon Sep 17 00:00:00 2001 From: Johannes Postma Date: Fri, 7 Aug 2015 14:04:34 +0100 Subject: staging: rtl8723au: rtl8723a_hal_init: Improve code readability This patch improves code readability in the function rtl8723a_cal_txdesc_chksum. It improves the readability of the argument of the function le16_to_cpu. Signed-off-by: Johannes Postma Acked-by: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c index eb76ac473630..cf2388f4f6e7 100644 --- a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c +++ b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c @@ -1847,7 +1847,7 @@ static void rtl8723a_cal_txdesc_chksum(struct tx_desc *ptxdesc) ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); for (index = 0; index < count; index++) - checksum ^= le16_to_cpu(*(usPtr + index)); + checksum ^= le16_to_cpu(usPtr[index]); ptxdesc->txdw7 |= cpu_to_le32(checksum & 0x0000ffff); } -- cgit v1.3-6-gb490 From dbb588a4f7bf5dd8ad871f5d5dec228295cc4b7e Mon Sep 17 00:00:00 2001 From: Fabio Falzoi Date: Sun, 2 Aug 2015 22:30:14 +0200 Subject: Staging: fbtft: Use a struct to describe each LCD controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a struct flexfb_lcd_controller to holds chip properties, instead of relying on a long 'if - else if' chain. This allows to: - use a simple linear search to verify if a certain LCD controller model is supported or not. - add support for a new LCD chip controller simply defining a new flexfb_lcd_controller struct. Signed-off-by: Fabio Falzoi Acked-by: Noralf Trønnes Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/flexfb.c | 232 ++++++++++++++++++++++++----------------- 1 file changed, 136 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c index 5b4c7124a6ee..c763efc5de7d 100644 --- a/drivers/staging/fbtft/flexfb.c +++ b/drivers/staging/fbtft/flexfb.c @@ -126,6 +126,109 @@ static int ssd1351_init[] = { -1, 0xfd, 0x12, -1, 0xfd, 0xb1, -1, 0xae, -1, 0xb3 -1, 0xab, 0x01, -1, 0xb1, 0x32, -1, 0xb4, 0xa0, 0xb5, 0x55, -1, 0xbb, 0x17, -1, 0xbe, 0x05, -1, 0xc1, 0xc8, 0x80, 0xc8, -1, 0xc7, 0x0f, -1, 0xb6, 0x01, -1, 0xa6, -1, 0xaf, -3 }; +/** + * struct flexfb_lcd_controller - Describes the LCD controller properties + * @name: Model name of the chip + * @width: Width of display in pixels + * @height: Height of display in pixels + * @setaddrwin: Which set_addr_win() implementation to use + * @regwidth: LCD Controller Register width in bits + * @init_seq: LCD initialization sequence + * @init_seq_sz: Size of LCD initialization sequence + */ +struct flexfb_lcd_controller { + const char *name; + unsigned int width; + unsigned int height; + unsigned int setaddrwin; + unsigned int regwidth; + int *init_seq; + int init_seq_sz; +}; + +static const struct flexfb_lcd_controller flexfb_chip_table[] = { + { + .name = "st7735r", + .width = 120, + .height = 160, + .init_seq = st7735r_init, + .init_seq_sz = ARRAY_SIZE(st7735r_init), + }, + { + .name = "hx8340bn", + .width = 176, + .height = 220, + .init_seq = hx8340bn_init, + .init_seq_sz = ARRAY_SIZE(hx8340bn_init), + }, + { + .name = "ili9225", + .width = 176, + .height = 220, + .regwidth = 16, + .init_seq = ili9225_init, + .init_seq_sz = ARRAY_SIZE(ili9225_init), + }, + { + .name = "ili9225", + .width = 176, + .height = 220, + .regwidth = 16, + .init_seq = ili9225_init, + .init_seq_sz = ARRAY_SIZE(ili9225_init), + }, + { + .name = "ili9225", + .width = 176, + .height = 220, + .regwidth = 16, + .init_seq = ili9225_init, + .init_seq_sz = ARRAY_SIZE(ili9225_init), + }, + { + .name = "ili9320", + .width = 240, + .height = 320, + .setaddrwin = 1, + .regwidth = 16, + .init_seq = ili9320_init, + .init_seq_sz = ARRAY_SIZE(ili9320_init), + }, + { + .name = "ili9325", + .width = 240, + .height = 320, + .setaddrwin = 1, + .regwidth = 16, + .init_seq = ili9325_init, + .init_seq_sz = ARRAY_SIZE(ili9325_init), + }, + { + .name = "ili9341", + .width = 240, + .height = 320, + .init_seq = ili9341_init, + .init_seq_sz = ARRAY_SIZE(ili9341_init), + }, + { + .name = "ssd1289", + .width = 240, + .height = 320, + .setaddrwin = 2, + .regwidth = 16, + .init_seq = ssd1289_init, + .init_seq_sz = ARRAY_SIZE(ssd1289_init), + }, + { + .name = "ssd1351", + .width = 128, + .height = 128, + .setaddrwin = 3, + .init_seq = ssd1351_init, + .init_seq_sz = ARRAY_SIZE(ssd1351_init), + }, +}; + /* ili9320, ili9325 */ static void flexfb_set_addr_win_1(struct fbtft_par *par, int xs, int ys, int xe, int ye) @@ -247,8 +350,38 @@ static int flexfb_verify_gpios_db(struct fbtft_par *par) return 0; } +static void flexfb_chip_load_param(const struct flexfb_lcd_controller *chip) +{ + if (!width) + width = chip->width; + if (!height) + height = chip->height; + setaddrwin = chip->setaddrwin; + if (chip->regwidth) + regwidth = chip->regwidth; + if (!init_num) { + initp = chip->init_seq; + initp_num = chip->init_seq_sz; + } +} + static struct fbtft_display flex_display = { }; +static int flexfb_chip_init(const struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(flexfb_chip_table); i++) + if (!strcmp(chip, flexfb_chip_table[i].name)) { + flexfb_chip_load_param(&flexfb_chip_table[i]); + return 0; + } + + dev_err(dev, "chip=%s is not supported\n", chip); + + return -EINVAL; +} + static int flexfb_probe_common(struct spi_device *sdev, struct platform_device *pdev) { @@ -269,102 +402,9 @@ static int flexfb_probe_common(struct spi_device *sdev, sdev ? "'SPI device'" : "'Platform device'"); if (chip) { - - if (!strcmp(chip, "st7735r")) { - if (!width) - width = 128; - if (!height) - height = 160; - if (init_num == 0) { - initp = st7735r_init; - initp_num = ARRAY_SIZE(st7735r_init); - } - - } else if (!strcmp(chip, "hx8340bn")) { - if (!width) - width = 176; - if (!height) - height = 220; - setaddrwin = 0; - if (init_num == 0) { - initp = hx8340bn_init; - initp_num = ARRAY_SIZE(hx8340bn_init); - } - - } else if (!strcmp(chip, "ili9225")) { - if (!width) - width = 176; - if (!height) - height = 220; - setaddrwin = 0; - regwidth = 16; - if (init_num == 0) { - initp = ili9225_init; - initp_num = ARRAY_SIZE(ili9225_init); - } - - } else if (!strcmp(chip, "ili9320")) { - if (!width) - width = 240; - if (!height) - height = 320; - setaddrwin = 1; - regwidth = 16; - if (init_num == 0) { - initp = ili9320_init; - initp_num = ARRAY_SIZE(ili9320_init); - } - - } else if (!strcmp(chip, "ili9325")) { - if (!width) - width = 240; - if (!height) - height = 320; - setaddrwin = 1; - regwidth = 16; - if (init_num == 0) { - initp = ili9325_init; - initp_num = ARRAY_SIZE(ili9325_init); - } - - } else if (!strcmp(chip, "ili9341")) { - if (!width) - width = 240; - if (!height) - height = 320; - setaddrwin = 0; - regwidth = 8; - if (init_num == 0) { - initp = ili9341_init; - initp_num = ARRAY_SIZE(ili9341_init); - } - - } else if (!strcmp(chip, "ssd1289")) { - if (!width) - width = 240; - if (!height) - height = 320; - setaddrwin = 2; - regwidth = 16; - if (init_num == 0) { - initp = ssd1289_init; - initp_num = ARRAY_SIZE(ssd1289_init); - } - - } else if (!strcmp(chip, "ssd1351")) { - if (!width) - width = 128; - if (!height) - height = 128; - setaddrwin = 3; - if (init_num == 0) { - initp = ssd1351_init; - initp_num = ARRAY_SIZE(ssd1351_init); - } - } else { - dev_err(dev, "chip=%s is not supported\n", chip); - return -EINVAL; - } + ret = flexfb_chip_init(dev); + if (ret) + return ret; } if (width == 0 || height == 0) { -- cgit v1.3-6-gb490 From e2622fb31635d3ffd8a2aa3d7f253d2c13c71ad3 Mon Sep 17 00:00:00 2001 From: Okash Khawaja Date: Wed, 5 Aug 2015 21:13:52 +0100 Subject: staging: octeon: fix coding style warnings for block comments The Linux kernel coding style suggests starting every line in a block comment with an asterisk and finishing the block comment with */ on a separate line. This patch fixes those warnings, clearing all warnings and errors in this file, as reported by the checkpatch script. Signed-off-by: Okash Khawaja Signed-off-by: Greg Kroah-Hartman --- drivers/staging/octeon/ethernet-rgmii.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c index beb7aac9c289..51dcb611702f 100644 --- a/drivers/staging/octeon/ethernet-rgmii.c +++ b/drivers/staging/octeon/ethernet-rgmii.c @@ -118,9 +118,10 @@ static void cvm_oct_rgmii_poll(struct net_device *dev) } /* Since the 10Mbps preamble workaround is allowed we need to enable - preamble checking, FCS stripping, and clear error bits on - every speed change. If errors occur during 10Mbps operation - the above code will change this stuff */ + * preamble checking, FCS stripping, and clear error bits on + * every speed change. If errors occur during 10Mbps operation + * the above code will change this stuff + */ cvm_oct_set_hw_preamble(priv, true); if (priv->phydev == NULL) { -- cgit v1.3-6-gb490 From 44ae5443ef9fac059a2892cbb3f7e4d95f7f8d12 Mon Sep 17 00:00:00 2001 From: Navy Cheng Date: Thu, 6 Aug 2015 09:47:57 +0800 Subject: Staging: vme: remove an unnecessary and wrong warning message The wrong warning message in vme_user_probe() will mislead developers and users. As the error message which prompt cdev_add() error already exists, just remove the unnecessary and wrong message. Signed-off-by: Navy Cheng Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index b3e3c2d546a1..8e61a3b3e7e4 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -561,10 +561,8 @@ static int vme_user_probe(struct vme_dev *vdev) vme_user_cdev->ops = &vme_user_fops; vme_user_cdev->owner = THIS_MODULE; err = cdev_add(vme_user_cdev, MKDEV(VME_MAJOR, 0), VME_DEVS); - if (err) { - dev_warn(&vdev->dev, "cdev_all failed\n"); + if (err) goto err_char; - } /* Request slave resources and allocate buffers (128kB wide) */ for (i = SLAVE_MINOR; i < (SLAVE_MAX + 1); i++) { -- cgit v1.3-6-gb490 From c9eda12565a7df27bf67af99830923d4887c74b5 Mon Sep 17 00:00:00 2001 From: Stuart Yoder Date: Thu, 6 Aug 2015 20:09:24 -0500 Subject: staging: fsl-mc: add DPAA2 overview readme add README file providing an overview of the DPAA2 architecture and how it is integrated in Linux Signed-off-by: Stuart Yoder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fsl-mc/README.txt | 364 ++++++++++++++++++++++++++++++++++++++ drivers/staging/fsl-mc/TODO | 4 - 2 files changed, 364 insertions(+), 4 deletions(-) create mode 100644 drivers/staging/fsl-mc/README.txt (limited to 'drivers') diff --git a/drivers/staging/fsl-mc/README.txt b/drivers/staging/fsl-mc/README.txt new file mode 100644 index 000000000000..8214102f104b --- /dev/null +++ b/drivers/staging/fsl-mc/README.txt @@ -0,0 +1,364 @@ +Copyright (C) 2015 Freescale Semiconductor Inc. + +DPAA2 (Data Path Acceleration Architecture Gen2) +------------------------------------------------ + +This document provides an overview of the Freescale DPAA2 architecture +and how it is integrated into the Linux kernel. + +Contents summary + -DPAA2 overview + -Overview of DPAA2 objects + -DPAA2 Linux driver architecture overview + -bus driver + -dprc driver + -allocator + -dpio driver + -Ethernet + -mac + +DPAA2 Overview +-------------- + +DPAA2 is a hardware architecture designed for high-speeed network +packet processing. DPAA2 consists of sophisticated mechanisms for +processing Ethernet packets, queue management, buffer management, +autonomous L2 switching, virtual Ethernet bridging, and accelerator +(e.g. crypto) sharing. + +A DPAA2 hardware component called the Management Complex (or MC) manages the +DPAA2 hardware resources. The MC provides an object-based abstraction for +software drivers to use the DPAA2 hardware. + +The MC uses DPAA2 hardware resources such as queues, buffer pools, and +network ports to create functional objects/devices such as network +interfaces, an L2 switch, or accelerator instances. + +The MC provides memory-mapped I/O command interfaces (MC portals) +which DPAA2 software drivers use to operate on DPAA2 objects: + + +--------------------------------------+ + | OS | + | DPAA2 drivers | + | | | + +-----------------------------|--------+ + | + | (create,discover,connect + | config,use,destroy) + | + DPAA2 | + +------------------------| mc portal |-+ + | | | + | +- - - - - - - - - - - - -V- - -+ | + | | | | + | | Management Complex (MC) | | + | | | | + | +- - - - - - - - - - - - - - - -+ | + | | + | Hardware Hardware | + | Resources Objects | + | --------- ------- | + | -queues -DPRC | + | -buffer pools -DPMCP | + | -Eth MACs/ports -DPIO | + | -network interface -DPNI | + | profiles -DPMAC | + | -queue portals -DPBP | + | -MC portals ... | + | ... | + | | + +--------------------------------------+ + +The MC mediates operations such as create, discover, +connect, configuration, and destroy. Fast-path operations +on data, such as packet transmit/receive, are not mediated by +the MC and are done directly using memory mapped regions in +DPIO objects. + +Overview of DPAA2 Objects +------------------------- +The section provides a brief overview of some key objects +in the DPAA2 hardware. A simple scenario is described illustrating +the objects involved in creating a network interfaces. + +-DPRC (Datapath Resource Container) + + A DPRC is an container object that holds all the other + types of DPAA2 objects. In the example diagram below there + are 8 objects of 5 types (DPMCP, DPIO, DPBP, DPNI, and DPMAC) + in the container. + + +---------------------------------------------------------+ + | DPRC | + | | + | +-------+ +-------+ +-------+ +-------+ +-------+ | + | | DPMCP | | DPIO | | DPBP | | DPNI | | DPMAC | | + | +-------+ +-------+ +-------+ +---+---+ +---+---+ | + | | DPMCP | | DPIO | | + | +-------+ +-------+ | + | | DPMCP | | + | +-------+ | + | | + +---------------------------------------------------------+ + + From the point of view of an OS, a DPRC is bus-like. Like + a plug-and-play bus, such as PCI, DPRC commands can be used to + enumerate the contents of the DPRC, discover the hardware + objects present (including mappable regions and interrupts). + + dprc.1 (bus) + | + +--+--------+-------+-------+-------+ + | | | | | + dpmcp.1 dpio.1 dpbp.1 dpni.1 dpmac.1 + dpmcp.2 dpio.2 + dpmcp.3 + + Hardware objects can be created and destroyed dynamically, providing + the ability to hot plug/unplug objects in and out of the DPRC. + + A DPRC has a mappable mmio region (an MC portal) that can be used + to send MC commands. It has an interrupt for status events (like + hotplug). + + All objects in a container share the same hardware "isolation context". + This means that with respect to an IOMMU the isolation granularity + is at the DPRC (container) level, not at the individual object + level. + + DPRCs can be defined statically and populated with objects + via a config file passed to the MC when firmware starts + it. There is also a Linux user space tool called "restool" + that can be used to create/destroy containers and objects + dynamically. + +-DPAA2 Objects for an Ethernet Network Interface + + A typical Ethernet NIC is monolithic-- the NIC device contains TX/RX + queuing mechanisms, configuration mechanisms, buffer management, + physical ports, and interrupts. DPAA2 uses a more granular approach + utilizing multiple hardware objects. Each object has specialized + functions, and are used together by software to provide Ethernet network + interface functionality. This approach provides efficient use of finite + hardware resources, flexibility, and performance advantages. + + The diagram below shows the objects needed for a simple + network interface configuration on a system with 2 CPUs. + + +---+---+ +---+---+ + CPU0 CPU1 + +---+---+ +---+---+ + | | + +---+---+ +---+---+ + DPIO DPIO + +---+---+ +---+---+ + \ / + \ / + \ / + +---+---+ + DPNI --- DPBP,DPMCP + +---+---+ + | + | + +---+---+ + DPMAC + +---+---+ + | + port/PHY + + Below the objects are described. For each object a brief description + is provided along with a summary of the kinds of operations the object + supports and a summary of key resources of the object (mmio regions + and irqs). + + -DPMAC (Datapath Ethernet MAC): represents an Ethernet MAC, a + hardware device that connects to an Ethernet PHY and allows + physical transmission and reception of Ethernet frames. + -mmio regions: none + -irqs: dpni link change + -commands: set link up/down, link config, get stats, + irq config, enable, reset + + -DPNI (Datapath Network Interface): contains TX/RX queues, + network interface configuration, and rx buffer pool configuration + mechanisms. + -mmio regions: none + -irqs: link state + -commands: port config, offload config, queue config, + parse/classify config, irq config, enable, reset + + -DPIO (Datapath I/O): provides interfaces to enqueue and dequeue + packets and do hardware buffer pool management operations. For + optimum performance there is typically DPIO per CPU. This allows + each CPU to perform simultaneous enqueue/dequeue operations. + -mmio regions: queue operations, buffer mgmt + -irqs: data availability, congestion notification, buffer + pool depletion + -commands: irq config, enable, reset + + -DPBP (Datapath Buffer Pool): represents a hardware buffer + pool. + -mmio regions: none + -irqs: none + -commands: enable, reset + + -DPMCP (Datapath MC Portal): provides an MC command portal. + Used by drivers to send commands to the MC to manage + objects. + -mmio regions: MC command portal + -irqs: command completion + -commands: irq config, enable, reset + + Object Connections + ------------------ + Some objects have explicit relationships that must + be configured: + + -DPNI <--> DPMAC + -DPNI <--> DPNI + -DPNI <--> L2-switch-port + A DPNI must be connected to something such as a DPMAC, + another DPNI, or L2 switch port. The DPNI connection + is made via a DPRC command. + + +-------+ +-------+ + | DPNI | | DPMAC | + +---+---+ +---+---+ + | | + +==========+ + + -DPNI <--> DPBP + A network interface requires a 'buffer pool' (DPBP + object) which provides a list of pointers to memory + where received Ethernet data is to be copied. The + Ethernet driver configures the DPBPs associated with + the network interface. + + Interrupts + ---------- + All interrupts generated by DPAA2 objects are message + interrupts. At the hardware level message interrupts + generated by devices will normally have 3 components-- + 1) a non-spoofable 'device-id' expressed on the hardware + bus, 2) an address, 3) a data value. + + In the case of DPAA2 devices/objects, all objects in the + same container/DPRC share the same 'device-id'. + For ARM-based SoC this is the same as the stream ID. + + +DPAA2 Linux Driver Overview +--------------------------- + +This section provides an overview of the Linux kernel drivers for +DPAA2-- 1) the bus driver and associated "DPAA2 infrastructure" +drivers and 2) functional object drivers (such as Ethernet). + +As described previously, a DPRC is a container that holds the other +types of DPAA2 objects. It is functionally similar to a plug-and-play +bus controller. + +Each object in the DPRC is a Linux "device" and is bound to a driver. +The diagram below shows the Linux drivers involved in a networking +scenario and the objects bound to each driver. A brief description +of each driver follows. + + +------------+ + | OS Network | + | Stack | + +------------+ +------------+ + | Allocator |. . . . . . . | Ethernet | + |(dpmcp,dpbp)| | (dpni) | + +-.----------+ +---+---+----+ + . . ^ | + . . | | dequeue> + +-------------+ . | | + | DPRC driver | . +---+---V----+ +---------+ + | (dprc) | . . . . . .| DPIO driver| | MAC | + +----------+--+ | (dpio) | | (dpmac) | + | +------+-----+ +-----+---+ + | | | + | | | + +----+--------------+ | +--+---+ + | mc-bus driver | | | PHY | + | | | |driver| + | /fsl-mc@80c000000 | | +--+---+ + +-------------------+ | | + | | + ================================ HARDWARE =========|=================|====== + DPIO | + | | + DPNI---DPBP | + | | + DPMAC | + | | + PHY ---------------+ + ===================================================|======================== + +A brief description of each driver is provided below. + + mc-bus driver + ------------- + The mc-bus driver is a platform driver and is probed from an + "/fsl-mc@xxxx" node in the device tree passed in by boot firmware. + It is responsible for bootstrapping the DPAA2 kernel infrastructure. + Key functions include: + -registering a new bus type named "fsl-mc" with the kernel, + and implementing bus call-backs (e.g. match/uevent/dev_groups) + -implemeting APIs for DPAA2 driver registration and for device + add/remove + -creates an MSI irq domain + -do a device add of the 'root' DPRC device, which is needed + to bootstrap things + + DPRC driver + ----------- + The dprc-driver is bound DPRC objects and does runtime management + of a bus instance. It performs the initial bus scan of the DPRC + and handles interrupts for container events such as hot plug. + + Allocator + ---------- + Certain objects such as DPMCP and DPBP are generic and fungible, + and are intended to be used by other drivers. For example, + the DPAA2 Ethernet driver needs: + -DPMCPs to send MC commands, to configure network interfaces + -DPBPs for network buffer pools + + The allocator driver registers for these allocatable object types + and those objects are bound to the allocator when the bus is probed. + The allocator maintains a pool of objects that are available for + allocation by other DPAA2 drivers. + + DPIO driver + ----------- + The DPIO driver is bound to DPIO objects and provides services that allow + other drivers such as the Ethernet driver to receive and transmit data. + Key services include: + -data availability notifications + -hardware queuing operations (enqueue and dequeue of data) + -hardware buffer pool management + + There is typically one DPIO object per physical CPU for optimum + performance, allowing each CPU to simultaneously enqueue + and dequeue data. + + The DPIO driver operates on behalf of all DPAA2 drivers + active in the kernel-- Ethernet, crypto, compression, + etc. + + Ethernet + -------- + The Ethernet driver is bound to a DPNI and implements the kernel + interfaces needed to connect the DPAA2 network interface to + the network stack. + + Each DPNI corresponds to a Linux network interface. + + MAC driver + ---------- + An Ethernet PHY is an off-chip, board specific component and is managed + by the appropriate PHY driver via an mdio bus. The MAC driver + plays a role of being a proxy between the PHY driver and the + MC. It does this proxy via the MC commands to a DPMAC object. diff --git a/drivers/staging/fsl-mc/TODO b/drivers/staging/fsl-mc/TODO index c29516b4b9b6..389436891b93 100644 --- a/drivers/staging/fsl-mc/TODO +++ b/drivers/staging/fsl-mc/TODO @@ -1,7 +1,3 @@ -* Add README file (with ASCII art) describing relationships between - DPAA2 objects and how combine them to make a NIC, an LS2 switch, etc. - Also, define all acronyms used. - * Decide if multiple root fsl-mc buses will be supported per Linux instance, and if so add support for this. -- cgit v1.3-6-gb490 From 66a84f8ae131a7111ce8a6b0a77edf42b2c01d6c Mon Sep 17 00:00:00 2001 From: Miguel Bernabeu Diaz Date: Wed, 5 Aug 2015 23:43:08 +0200 Subject: staging: lustre: Unnecessary line continuation Fix checkpatch.pl warning: WARNING: Avoid unnecessary line continuations Signed-off-by: Miguel Bernabeu Diaz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index 477aa8b76f32..5a8ebe1b3c84 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -3133,8 +3133,7 @@ kiblnd_connd(void *arg) dropped_lock = 0; if (!list_empty(&kiblnd_data.kib_connd_zombies)) { - conn = list_entry(kiblnd_data. \ - kib_connd_zombies.next, + conn = list_entry(kiblnd_data.kib_connd_zombies.next, kib_conn_t, ibc_list); list_del(&conn->ibc_list); -- cgit v1.3-6-gb490 From e39f6efaa1d9203527683213a1cf039c4d6c29aa Mon Sep 17 00:00:00 2001 From: Miguel Bernabeu Diaz Date: Wed, 5 Aug 2015 23:44:36 +0200 Subject: staging: lustre: Fix code indent error Fix checkpatch.pl error: ERROR: code indent should use tabs where possible Signed-off-by: Miguel Bernabeu Diaz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index f429d25306c1..24b2c978dfb6 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -1390,7 +1390,7 @@ static int kiblnd_create_fmr_pool(kib_fmr_poolset_t *fps, .max_pages_per_fmr = LNET_MAX_PAYLOAD/PAGE_SIZE, .page_shift = PAGE_SHIFT, .access = (IB_ACCESS_LOCAL_WRITE | - IB_ACCESS_REMOTE_WRITE), + IB_ACCESS_REMOTE_WRITE), .pool_size = fps->fps_pool_size, .dirty_watermark = fps->fps_flush_trigger, .flush_function = NULL, -- cgit v1.3-6-gb490 From 83b912c67b0b42af7bb7cbcb9d4fdb64bcd8dc65 Mon Sep 17 00:00:00 2001 From: Miguel Bernabeu Diaz Date: Wed, 5 Aug 2015 23:45:50 +0200 Subject: staging: lustre: Fix space before '++' error Fix checkpatch.pl error: ERROR: space prohibited before that '++' (ctx:WxO) Signed-off-by: Miguel Bernabeu Diaz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index 8bc05770382c..e676e8adfc33 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -887,7 +887,7 @@ kiblnd_rd_consume_frag(kib_rdma_desc_t *rd, int index, __u32 nob) rd->rd_frags[index].rf_addr += nob; rd->rd_frags[index].rf_nob -= nob; } else { - index ++; + index++; } return index; -- cgit v1.3-6-gb490 From 270f0c31b47eeedee7d6c538c0f5753df24a7726 Mon Sep 17 00:00:00 2001 From: Miguel Bernabeu Diaz Date: Wed, 5 Aug 2015 23:47:41 +0200 Subject: staging: lustre: Fix space before '(' warnings Fix several instances of checkpatch.pl warning: WARNING: space prohibited between function name and open parenthesis '(' Signed-off-by: Miguel Bernabeu Diaz Signed-off-by: Greg Kroah-Hartman --- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 100 ++++++++++----------- 1 file changed, 50 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index e676e8adfc33..71c37e476c9b 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -519,7 +519,7 @@ typedef struct kib_rx /* receive message */ enum ib_wc_status rx_status; /* completion status */ kib_msg_t *rx_msg; /* message buffer (host vaddr) */ __u64 rx_msgaddr; /* message buffer (I/O addr) */ - DECLARE_PCI_UNMAP_ADDR (rx_msgunmap); /* for dma_unmap_single() */ + DECLARE_PCI_UNMAP_ADDR(rx_msgunmap); /* for dma_unmap_single() */ struct ib_recv_wr rx_wrq; /* receive work item... */ struct ib_sge rx_sge; /* ...and its memory */ } kib_rx_t; @@ -546,7 +546,7 @@ typedef struct kib_tx /* transmit message */ * completion */ kib_msg_t *tx_msg; /* message buffer (host vaddr) */ __u64 tx_msgaddr; /* message buffer (I/O addr) */ - DECLARE_PCI_UNMAP_ADDR (tx_msgunmap); /* for dma_unmap_single() */ + DECLARE_PCI_UNMAP_ADDR(tx_msgunmap); /* for dma_unmap_single() */ int tx_nwrq; /* # send work items */ struct ib_send_wr *tx_wrq; /* send work items... */ struct ib_sge *tx_sge; /* ...and their memory */ @@ -647,14 +647,14 @@ extern void kiblnd_hdev_destroy(kib_hca_dev_t *hdev); static inline void kiblnd_hdev_addref_locked(kib_hca_dev_t *hdev) { - LASSERT (atomic_read(&hdev->ibh_ref) > 0); + LASSERT(atomic_read(&hdev->ibh_ref) > 0); atomic_inc(&hdev->ibh_ref); } static inline void kiblnd_hdev_decref(kib_hca_dev_t *hdev) { - LASSERT (atomic_read(&hdev->ibh_ref) > 0); + LASSERT(atomic_read(&hdev->ibh_ref) > 0); if (atomic_dec_and_test(&hdev->ibh_ref)) kiblnd_hdev_destroy(hdev); } @@ -701,7 +701,7 @@ do { \ do { \ CDEBUG(D_NET, "peer[%p] -> %s (%d)++\n", \ (peer), libcfs_nid2str((peer)->ibp_nid), \ - atomic_read (&(peer)->ibp_refcount)); \ + atomic_read(&(peer)->ibp_refcount)); \ atomic_inc(&(peer)->ibp_refcount); \ } while (0) @@ -709,14 +709,14 @@ do { \ do { \ CDEBUG(D_NET, "peer[%p] -> %s (%d)--\n", \ (peer), libcfs_nid2str((peer)->ibp_nid), \ - atomic_read (&(peer)->ibp_refcount)); \ + atomic_read(&(peer)->ibp_refcount)); \ LASSERT_ATOMIC_POS(&(peer)->ibp_refcount); \ if (atomic_dec_and_test(&(peer)->ibp_refcount)) \ kiblnd_destroy_peer(peer); \ } while (0) static inline struct list_head * -kiblnd_nid2peerlist (lnet_nid_t nid) +kiblnd_nid2peerlist(lnet_nid_t nid) { unsigned int hash = ((unsigned int)nid) % kiblnd_data.kib_peer_hash_size; @@ -725,16 +725,16 @@ kiblnd_nid2peerlist (lnet_nid_t nid) } static inline int -kiblnd_peer_active (kib_peer_t *peer) +kiblnd_peer_active(kib_peer_t *peer) { /* Am I in the peer hash table? */ return (!list_empty(&peer->ibp_list)); } static inline kib_conn_t * -kiblnd_get_conn_locked (kib_peer_t *peer) +kiblnd_get_conn_locked(kib_peer_t *peer) { - LASSERT (!list_empty(&peer->ibp_conns)); + LASSERT(!list_empty(&peer->ibp_conns)); /* just return the first connection */ return list_entry(peer->ibp_conns.next, kib_conn_t, ibc_list); @@ -751,7 +751,7 @@ kiblnd_send_keepalive(kib_conn_t *conn) static inline int kiblnd_need_noop(kib_conn_t *conn) { - LASSERT (conn->ibc_state >= IBLND_CONN_ESTABLISHED); + LASSERT(conn->ibc_state >= IBLND_CONN_ESTABLISHED); if (conn->ibc_outstanding_credits < IBLND_CREDITS_HIGHWATER(conn->ibc_version) && @@ -788,7 +788,7 @@ kiblnd_abort_receives(kib_conn_t *conn) } static inline const char * -kiblnd_queue2str (kib_conn_t *conn, struct list_head *q) +kiblnd_queue2str(kib_conn_t *conn, struct list_head *q) { if (q == &conn->ibc_tx_queue) return "tx_queue"; @@ -815,43 +815,43 @@ kiblnd_queue2str (kib_conn_t *conn, struct list_head *q) #define IBLND_WID_MASK 3UL static inline __u64 -kiblnd_ptr2wreqid (void *ptr, int type) +kiblnd_ptr2wreqid(void *ptr, int type) { unsigned long lptr = (unsigned long)ptr; - LASSERT ((lptr & IBLND_WID_MASK) == 0); - LASSERT ((type & ~IBLND_WID_MASK) == 0); + LASSERT((lptr & IBLND_WID_MASK) == 0); + LASSERT((type & ~IBLND_WID_MASK) == 0); return (__u64)(lptr | type); } static inline void * -kiblnd_wreqid2ptr (__u64 wreqid) +kiblnd_wreqid2ptr(__u64 wreqid) { return (void *)(((unsigned long)wreqid) & ~IBLND_WID_MASK); } static inline int -kiblnd_wreqid2type (__u64 wreqid) +kiblnd_wreqid2type(__u64 wreqid) { return (wreqid & IBLND_WID_MASK); } static inline void -kiblnd_set_conn_state (kib_conn_t *conn, int state) +kiblnd_set_conn_state(kib_conn_t *conn, int state) { conn->ibc_state = state; mb(); } static inline void -kiblnd_init_msg (kib_msg_t *msg, int type, int body_nob) +kiblnd_init_msg(kib_msg_t *msg, int type, int body_nob) { msg->ibm_type = type; msg->ibm_nob = offsetof(kib_msg_t, ibm_u) + body_nob; } static inline int -kiblnd_rd_size (kib_rdma_desc_t *rd) +kiblnd_rd_size(kib_rdma_desc_t *rd) { int i; int size; @@ -896,8 +896,8 @@ kiblnd_rd_consume_frag(kib_rdma_desc_t *rd, int index, __u32 nob) static inline int kiblnd_rd_msg_size(kib_rdma_desc_t *rd, int msgtype, int n) { - LASSERT (msgtype == IBLND_MSG_GET_REQ || - msgtype == IBLND_MSG_PUT_ACK); + LASSERT(msgtype == IBLND_MSG_GET_REQ || + msgtype == IBLND_MSG_PUT_ACK); return msgtype == IBLND_MSG_GET_REQ ? offsetof(kib_get_msg_t, ibgm_rd.rd_frags[n]) : @@ -982,53 +982,53 @@ int kiblnd_pmr_pool_map(kib_pmr_poolset_t *pps, kib_hca_dev_t *hdev, kib_rdma_desc_t *rd, __u64 *iova, kib_phys_mr_t **pp_pmr); void kiblnd_pmr_pool_unmap(kib_phys_mr_t *pmr); -int kiblnd_startup (lnet_ni_t *ni); -void kiblnd_shutdown (lnet_ni_t *ni); -int kiblnd_ctl (lnet_ni_t *ni, unsigned int cmd, void *arg); -void kiblnd_query (struct lnet_ni *ni, lnet_nid_t nid, unsigned long *when); +int kiblnd_startup(lnet_ni_t *ni); +void kiblnd_shutdown(lnet_ni_t *ni); +int kiblnd_ctl(lnet_ni_t *ni, unsigned int cmd, void *arg); +void kiblnd_query(struct lnet_ni *ni, lnet_nid_t nid, unsigned long *when); int kiblnd_tunables_init(void); void kiblnd_tunables_fini(void); -int kiblnd_connd (void *arg); +int kiblnd_connd(void *arg); int kiblnd_scheduler(void *arg); int kiblnd_thread_start(int (*fn)(void *arg), void *arg, char *name); -int kiblnd_failover_thread (void *arg); +int kiblnd_failover_thread(void *arg); int kiblnd_alloc_pages(kib_pages_t **pp, int cpt, int npages); -void kiblnd_free_pages (kib_pages_t *p); +void kiblnd_free_pages(kib_pages_t *p); int kiblnd_cm_callback(struct rdma_cm_id *cmid, struct rdma_cm_event *event); int kiblnd_translate_mtu(int value); int kiblnd_dev_failover(kib_dev_t *dev); -int kiblnd_create_peer (lnet_ni_t *ni, kib_peer_t **peerp, lnet_nid_t nid); -void kiblnd_destroy_peer (kib_peer_t *peer); -void kiblnd_destroy_dev (kib_dev_t *dev); -void kiblnd_unlink_peer_locked (kib_peer_t *peer); -void kiblnd_peer_alive (kib_peer_t *peer); -kib_peer_t *kiblnd_find_peer_locked (lnet_nid_t nid); -void kiblnd_peer_connect_failed (kib_peer_t *peer, int active, int error); -int kiblnd_close_stale_conns_locked (kib_peer_t *peer, +int kiblnd_create_peer(lnet_ni_t *ni, kib_peer_t **peerp, lnet_nid_t nid); +void kiblnd_destroy_peer(kib_peer_t *peer); +void kiblnd_destroy_dev(kib_dev_t *dev); +void kiblnd_unlink_peer_locked(kib_peer_t *peer); +void kiblnd_peer_alive(kib_peer_t *peer); +kib_peer_t *kiblnd_find_peer_locked(lnet_nid_t nid); +void kiblnd_peer_connect_failed(kib_peer_t *peer, int active, int error); +int kiblnd_close_stale_conns_locked(kib_peer_t *peer, int version, __u64 incarnation); -int kiblnd_close_peer_conns_locked (kib_peer_t *peer, int why); +int kiblnd_close_peer_conns_locked(kib_peer_t *peer, int why); void kiblnd_connreq_done(kib_conn_t *conn, int status); -kib_conn_t *kiblnd_create_conn (kib_peer_t *peer, struct rdma_cm_id *cmid, +kib_conn_t *kiblnd_create_conn(kib_peer_t *peer, struct rdma_cm_id *cmid, int state, int version); -void kiblnd_destroy_conn (kib_conn_t *conn); -void kiblnd_close_conn (kib_conn_t *conn, int error); -void kiblnd_close_conn_locked (kib_conn_t *conn, int error); +void kiblnd_destroy_conn(kib_conn_t *conn); +void kiblnd_close_conn(kib_conn_t *conn, int error); +void kiblnd_close_conn_locked(kib_conn_t *conn, int error); -int kiblnd_init_rdma (kib_conn_t *conn, kib_tx_t *tx, int type, +int kiblnd_init_rdma(kib_conn_t *conn, kib_tx_t *tx, int type, int nob, kib_rdma_desc_t *dstrd, __u64 dstcookie); -void kiblnd_launch_tx (lnet_ni_t *ni, kib_tx_t *tx, lnet_nid_t nid); -void kiblnd_queue_tx_locked (kib_tx_t *tx, kib_conn_t *conn); -void kiblnd_queue_tx (kib_tx_t *tx, kib_conn_t *conn); -void kiblnd_init_tx_msg (lnet_ni_t *ni, kib_tx_t *tx, int type, int body_nob); -void kiblnd_txlist_done (lnet_ni_t *ni, struct list_head *txlist, +void kiblnd_launch_tx(lnet_ni_t *ni, kib_tx_t *tx, lnet_nid_t nid); +void kiblnd_queue_tx_locked(kib_tx_t *tx, kib_conn_t *conn); +void kiblnd_queue_tx(kib_tx_t *tx, kib_conn_t *conn); +void kiblnd_init_tx_msg(lnet_ni_t *ni, kib_tx_t *tx, int type, int body_nob); +void kiblnd_txlist_done(lnet_ni_t *ni, struct list_head *txlist, int status); void kiblnd_check_sends (kib_conn_t *conn); @@ -1036,10 +1036,10 @@ void kiblnd_qp_event(struct ib_event *event, void *arg); void kiblnd_cq_event(struct ib_event *event, void *arg); void kiblnd_cq_completion(struct ib_cq *cq, void *arg); -void kiblnd_pack_msg (lnet_ni_t *ni, kib_msg_t *msg, int version, +void kiblnd_pack_msg(lnet_ni_t *ni, kib_msg_t *msg, int version, int credits, lnet_nid_t dstnid, __u64 dststamp); int kiblnd_unpack_msg(kib_msg_t *msg, int nob); -int kiblnd_post_rx (kib_rx_t *rx, int credit); +int kiblnd_post_rx(kib_rx_t *rx, int credit); int kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg); int kiblnd_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed, -- cgit v1.3-6-gb490 From 276479ff684792fefadec795afd1cb84a81dc8e5 Mon Sep 17 00:00:00 2001 From: Miguel Bernabeu Diaz Date: Wed, 5 Aug 2015 23:48:48 +0200 Subject: staging: lustre: Fix space before '[' error Fix checkpatch.pl error: ERROR: space prohibited before open square bracket '[' Signed-off-by: Miguel Bernabeu Diaz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index 71c37e476c9b..92fbd6d3c7a9 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -721,7 +721,7 @@ kiblnd_nid2peerlist(lnet_nid_t nid) unsigned int hash = ((unsigned int)nid) % kiblnd_data.kib_peer_hash_size; - return (&kiblnd_data.kib_peers [hash]); + return (&kiblnd_data.kib_peers[hash]); } static inline int -- cgit v1.3-6-gb490 From 8a1d7b09e7e3c2c7097712331ac64ccfdbcf8f6d Mon Sep 17 00:00:00 2001 From: Miguel Bernabeu Diaz Date: Wed, 5 Aug 2015 23:49:57 +0200 Subject: Staging: lustre: lnet: Remove unnecessary parentheses on return Removed three instances of parentheses in return calls that are unnecessary and do not contribute to readability. Signed-off-by: Miguel Bernabeu Diaz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index 92fbd6d3c7a9..2991be85d8b3 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -721,14 +721,14 @@ kiblnd_nid2peerlist(lnet_nid_t nid) unsigned int hash = ((unsigned int)nid) % kiblnd_data.kib_peer_hash_size; - return (&kiblnd_data.kib_peers[hash]); + return &kiblnd_data.kib_peers[hash]; } static inline int kiblnd_peer_active(kib_peer_t *peer) { /* Am I in the peer hash table? */ - return (!list_empty(&peer->ibp_list)); + return !list_empty(&peer->ibp_list); } static inline kib_conn_t * @@ -833,7 +833,7 @@ kiblnd_wreqid2ptr(__u64 wreqid) static inline int kiblnd_wreqid2type(__u64 wreqid) { - return (wreqid & IBLND_WID_MASK); + return wreqid & IBLND_WID_MASK; } static inline void -- cgit v1.3-6-gb490 From 5dab10f444774dd119e3c370cd332df9c1c646c7 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Wed, 5 Aug 2015 17:17:14 -0700 Subject: staging: rtl8712: fix buggy size calculation r8712_get_ndis_wlan_bssid_ex_sz has a "6 * sizeof(unsigned long)" where the underlying struct has a 6 * unsigned char. Simplify the calculation by just subtracting the variable part from the size of the struct. This also gets rid of a use of typedef NDIS_802_11_RATES_EX Signed-off-by: Joshua Clayton Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl871x_mlme.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index c044b0e55ba9..6b3451f7017b 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -210,17 +210,7 @@ void r8712_generate_random_ibss(u8 *pibss) uint r8712_get_ndis_wlan_bssid_ex_sz(struct ndis_wlan_bssid_ex *bss) { - uint t_len; - - t_len = sizeof(u32) + 6 * sizeof(unsigned long) + 2 + - sizeof(struct ndis_802_11_ssid) + sizeof(u32) + - sizeof(s32) + - sizeof(enum NDIS_802_11_NETWORK_TYPE) + - sizeof(struct NDIS_802_11_CONFIGURATION) + - sizeof(enum NDIS_802_11_NETWORK_INFRASTRUCTURE) + - sizeof(NDIS_802_11_RATES_EX) + - sizeof(u32) + bss->IELength; - return t_len; + return sizeof(*bss) + bss->IELength - MAX_IE_SZ; } u8 *r8712_get_capability_from_ie(u8 *ie) -- cgit v1.3-6-gb490 From 5fd93ddf32f3ae77e66bee9c341036e03dd389ae Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 17:34:02 +0530 Subject: staging: sm750fb: remove multiple blank line Multiple blank lines are not kernel coding style and so checkpatch complains. Remove them. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index c7ab8189671f..8990ff499332 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -26,7 +26,6 @@ int smi_indent; - /* * #ifdef __BIG_ENDIAN * ssize_t lynxfb_ops_write(struct fb_info *info, const char __user *buf, @@ -40,7 +39,6 @@ typedef void (*PROC_SPEC_SETUP)(struct lynx_share*, char *); typedef int (*PROC_SPEC_MAP)(struct lynx_share*, struct pci_dev*); typedef int (*PROC_SPEC_INITHW)(struct lynx_share*, struct pci_dev*); - /* common var for all device */ static int g_hwcursor = 1; static int g_noaccel; @@ -51,7 +49,6 @@ static char *g_settings; static int g_dualview; static char *g_option; - static const struct fb_videomode lynx750_ext[] = { /* 1024x600-60 VESA [1.71:1] */ {NULL, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3, @@ -115,8 +112,6 @@ static const struct fb_videomode lynx750_ext[] = { }; - - /* no hardware cursor supported under version 2.6.10, kernel bug */ static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor) { @@ -160,7 +155,6 @@ static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor) cursor->setColor(cursor, fg, bg); } - if (fbcursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) { cursor->setData(cursor, fbcursor->rop, @@ -300,7 +294,6 @@ static int lynxfb_ops_pan_display(struct fb_var_screeninfo *var, struct lynxfb_crtc *crtc; int ret; - if (!info) return -EINVAL; @@ -466,7 +459,6 @@ static int lynxfb_resume(struct pci_dev *pdev) int ret; - ret = 0; share = pci_get_drvdata(pdev); @@ -478,7 +470,6 @@ static int lynxfb_resume(struct pci_dev *pdev) return ret; } - if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) { pci_restore_state(pdev); ret = pci_enable_device(pdev); @@ -493,7 +484,6 @@ static int lynxfb_resume(struct pci_dev *pdev) hw_sm750_inithw(share, pdev); - info = share->fbinfo[0]; if (info) { @@ -518,7 +508,6 @@ static int lynxfb_resume(struct pci_dev *pdev) fb_set_suspend(info, 0); } - console_unlock(); return ret; } @@ -534,7 +523,6 @@ static int lynxfb_ops_check_var(struct fb_var_screeninfo *var, int ret; resource_size_t request; - par = info->par; crtc = &par->crtc; output = &par->output; @@ -546,7 +534,6 @@ static int lynxfb_ops_check_var(struct fb_var_screeninfo *var, var->yres, var->bits_per_pixel); - switch (var->bits_per_pixel) { case 8: case 16: @@ -617,7 +604,6 @@ exit: return ret; } - static int lynxfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green, @@ -652,7 +638,6 @@ static int lynxfb_ops_setcolreg(unsigned regno, goto exit; } - if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 256) { u32 val; @@ -782,7 +767,6 @@ static struct fb_ops lynxfb_ops = { .fb_cursor = lynxfb_ops_cursor, }; - static int lynxfb_set_fbinfo(struct fb_info *info, int index) { int i; @@ -803,7 +787,6 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) "kernel HELPERS prepared vesa_modes", }; - static const char *fixId[2] = { "sm750_fb1", "sm750_fb2", }; @@ -824,7 +807,6 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) sm750fb_set_drv(par); lynxfb_ops.fb_pan_display = lynxfb_ops_pan_display; - /* set current cursor variable and proc pointer, * must be set after crtc member initialized */ crtc->cursor.offset = crtc->oScreen + crtc->vidmem_size - 1024; @@ -841,7 +823,6 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) crtc->cursor.setData = hw_cursor_setData; crtc->cursor.vstart = share->pvMem + crtc->cursor.offset; - crtc->cursor.share = share; memset_io(crtc->cursor.vstart, 0, crtc->cursor.size); if (!g_hwcursor) { @@ -849,7 +830,6 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) crtc->cursor.disable(&crtc->cursor); } - /* set info->fbops, must be set before fb_find_mode */ if (!share->accel_off) { /* use 2d acceleration */ @@ -865,7 +845,6 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) g_fbmode[index] = g_fbmode[0]; } - for (i = 0; i < 3; i++) { ret = fb_find_mode(var, info, g_fbmode[index], @@ -935,7 +914,6 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) strlcpy(fix->id, fixId[index], sizeof(fix->id)); - fix->smem_start = crtc->oScreen + share->vidmem_start; pr_info("fix->smem_start = %lx\n", fix->smem_start); /* according to mmap experiment from user space application, @@ -998,7 +976,6 @@ static void sm750fb_setup(struct lynx_share *share, char *src) #endif int swap; - spec_share = container_of(share, struct sm750_share, share); #ifdef CAP_EXPENSIION exp_res = NULL; @@ -1096,7 +1073,6 @@ static int lynxfb_pci_probe(struct pci_dev *pdev, size_t spec_offset = 0; int fbidx; - /* enable device */ if (pci_enable_device(pdev)) { pr_err("can not enable device.\n"); @@ -1268,7 +1244,6 @@ static int __init lynxfb_setup(char *options) int len; char *opt, *tmp; - if (!options || !*options) { pr_warn("no options.\n"); return 0; @@ -1332,7 +1307,6 @@ static struct pci_driver lynxfb_driver = { #endif }; - static int __init lynxfb_init(void) { char *option; -- cgit v1.3-6-gb490 From 13ef3458227d4095a4f86270b1f29690dfc248bd Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 17:34:03 +0530 Subject: staging: sm750fb: space around operator Kernel coding style says to have a space around the operators. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index 8990ff499332..c16b2934fec7 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -144,12 +144,12 @@ static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor) /* get the 16bit color of kernel means */ u16 fg, bg; - fg = ((info->cmap.red[fbcursor->image.fg_color] & 0xf800))| - ((info->cmap.green[fbcursor->image.fg_color] & 0xfc00) >> 5)| + fg = ((info->cmap.red[fbcursor->image.fg_color] & 0xf800)) | + ((info->cmap.green[fbcursor->image.fg_color] & 0xfc00) >> 5) | ((info->cmap.blue[fbcursor->image.fg_color] & 0xf800) >> 11); - bg = ((info->cmap.red[fbcursor->image.bg_color] & 0xf800))| - ((info->cmap.green[fbcursor->image.bg_color] & 0xfc00) >> 5)| + bg = ((info->cmap.red[fbcursor->image.bg_color] & 0xf800)) | + ((info->cmap.green[fbcursor->image.bg_color] & 0xfc00) >> 5) | ((info->cmap.blue[fbcursor->image.bg_color] & 0xf800) >> 11); cursor->setColor(cursor, fg, bg); @@ -188,8 +188,9 @@ static void lynxfb_ops_fillrect(struct fb_info *info, pitch = info->fix.line_length; Bpp = info->var.bits_per_pixel >> 3; - color = (Bpp == 1)?region->color:((u32 *)info->pseudo_palette)[region->color]; - rop = (region->rop != ROP_COPY) ? HW_ROP2_XOR:HW_ROP2_COPY; + color = (Bpp == 1) ? region->color : + ((u32 *)info->pseudo_palette)[region->color]; + rop = (region->rop != ROP_COPY) ? HW_ROP2_XOR : HW_ROP2_COPY; /* * If not use spin_lock,system will die if user load driver @@ -278,7 +279,7 @@ _do_work: spin_lock(&share->slock); share->accel.de_imageblit(&share->accel, - image->data, image->width>>3, 0, + image->data, image->width >> 3, 0, base, pitch, Bpp, image->dx, image->dy, image->width, image->height, @@ -684,7 +685,8 @@ static int sm750fb_set_drv(struct lynxfb_par *par) output = &par->output; crtc = &par->crtc; - crtc->vidmem_size = (share->dual)?share->vidmem_size>>1:share->vidmem_size; + crtc->vidmem_size = (share->dual) ? share->vidmem_size >> 1 : + share->vidmem_size; /* setup crtc and output member */ spec_share->hwCursor = g_hwcursor; @@ -701,10 +703,12 @@ static int sm750fb_set_drv(struct lynxfb_par *par) output->proc_setMode = hw_sm750_output_setMode; output->proc_checkMode = hw_sm750_output_checkMode; - output->proc_setBLANK = (share->revid == SM750LE_REVISION_ID)?hw_sm750le_setBLANK:hw_sm750_setBLANK; + output->proc_setBLANK = (share->revid == SM750LE_REVISION_ID) ? + hw_sm750le_setBLANK : hw_sm750_setBLANK; output->clear = hw_sm750_output_clear; /* chip specific phase */ - share->accel.de_wait = (share->revid == SM750LE_REVISION_ID)?hw_sm750le_deWait : hw_sm750_deWait; + share->accel.de_wait = (share->revid == SM750LE_REVISION_ID) ? + hw_sm750le_deWait : hw_sm750_deWait; switch (spec_share->state.dataflow) { case sm750_simul_pri: output->paths = sm750_pnc; @@ -814,7 +818,7 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) pr_info("crtc->cursor.mmio = %p\n", crtc->cursor.mmio); crtc->cursor.maxH = crtc->cursor.maxW = 64; - crtc->cursor.size = crtc->cursor.maxH*crtc->cursor.maxW*2/8; + crtc->cursor.size = crtc->cursor.maxH * crtc->cursor.maxW * 2 / 8; crtc->cursor.disable = hw_cursor_disable; crtc->cursor.enable = hw_cursor_enable; crtc->cursor.setColor = hw_cursor_setColor; @@ -896,13 +900,13 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) /* set info */ line_length = PADDING(crtc->line_pad, - (var->xres_virtual * var->bits_per_pixel/8)); + (var->xres_virtual * var->bits_per_pixel / 8)); info->pseudo_palette = &par->pseudo_palette[0]; info->screen_base = crtc->vScreen; pr_debug("screen_base vaddr = %p\n", info->screen_base); info->screen_size = line_length * var->yres_virtual; - info->flags = FBINFO_FLAG_DEFAULT|0; + info->flags = FBINFO_FLAG_DEFAULT | 0; /* set info->fix */ fix->type = FB_TYPE_PACKED_PIXELS; -- cgit v1.3-6-gb490 From d11ac7cbcc266c6c2a6ae504e070b6dc4536c1f7 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 17:34:04 +0530 Subject: staging: sm750fb: fix multiline comment Multiline comments are edited to be in the kernel coding style. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750.c | 63 +++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index c16b2934fec7..fa2183d33bda 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -182,8 +182,10 @@ static void lynxfb_ops_fillrect(struct fb_info *info, par = info->par; share = par->share; - /* each time 2d function begin to work,below three variable always need - * be set, seems we can put them together in some place */ + /* + * each time 2d function begin to work,below three variable always need + * be set, seems we can put them together in some place + */ base = par->crtc.oScreen; pitch = info->fix.line_length; Bpp = info->var.bits_per_pixel >> 3; @@ -218,8 +220,10 @@ static void lynxfb_ops_copyarea(struct fb_info *info, par = info->par; share = par->share; - /* each time 2d function begin to work,below three variable always need - * be set, seems we can put them together in some place */ + /* + * each time 2d function begin to work,below three variable always need + * be set, seems we can put them together in some place + */ base = par->crtc.oScreen; pitch = info->fix.line_length; Bpp = info->var.bits_per_pixel >> 3; @@ -249,8 +253,10 @@ static void lynxfb_ops_imageblit(struct fb_info *info, par = info->par; share = par->share; - /* each time 2d function begin to work,below three variable always need - * be set, seems we can put them together in some place */ + /* + * each time 2d function begin to work,below three variable always need + * be set, seems we can put them together in some place + */ base = par->crtc.oScreen; pitch = info->fix.line_length; Bpp = info->var.bits_per_pixel >> 3; @@ -334,9 +340,10 @@ static int lynxfb_ops_set_par(struct fb_info *info) fix->line_length = line_length; pr_info("fix->line_length = %d\n", fix->line_length); - /* var->red,green,blue,transp are need to be set by driver + /* + * var->red,green,blue,transp are need to be set by driver * and these data should be set before setcolreg routine - * */ + */ switch (var->bits_per_pixel) { case 8: @@ -811,8 +818,10 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) sm750fb_set_drv(par); lynxfb_ops.fb_pan_display = lynxfb_ops_pan_display; - /* set current cursor variable and proc pointer, - * must be set after crtc member initialized */ + /* + * set current cursor variable and proc pointer, + * must be set after crtc member initialized + */ crtc->cursor.offset = crtc->oScreen + crtc->vidmem_size - 1024; crtc->cursor.mmio = share->pvReg + 0x800f0 + (int)crtc->channel * 0x140; @@ -920,12 +929,13 @@ static int lynxfb_set_fbinfo(struct fb_info *info, int index) fix->smem_start = crtc->oScreen + share->vidmem_start; pr_info("fix->smem_start = %lx\n", fix->smem_start); - /* according to mmap experiment from user space application, + /* + * according to mmap experiment from user space application, * fix->mmio_len should not larger than virtual size * (xres_virtual x yres_virtual x ByPP) * Below line maybe buggy when user mmap fb dev node and write * data into the bound over virtual size - * */ + */ fix->smem_len = crtc->vidmem_size; pr_info("fix->smem_len = %x\n", fix->smem_len); info->screen_size = fix->smem_len; @@ -1083,8 +1093,10 @@ static int lynxfb_pci_probe(struct pci_dev *pdev, goto err_enable; } - /* though offset of share in sm750_share is 0, - * we use this marcro as the same */ + /* + * though offset of share in sm750_share is 0, + * we use this marcro as the same + */ spec_offset = offsetof(struct sm750_share, share); spec_share = kzalloc(sizeof(*spec_share), GFP_KERNEL); @@ -1108,10 +1120,12 @@ static int lynxfb_pci_probe(struct pci_dev *pdev, spin_lock_init(&share->slock); if (!share->accel_off) { - /* hook deInit and 2d routines, notes that below hw_xxx + /* + * hook deInit and 2d routines, notes that below hw_xxx * routine can work on most of lynx chips * if some chip need specific function, - * please hook it in smXXX_set_drv routine */ + * please hook it in smXXX_set_drv routine + */ share->accel.de_init = hw_de_init; share->accel.de_fillrect = hw_fillrect; share->accel.de_copyarea = hw_copyarea; @@ -1262,14 +1276,15 @@ static int __init lynxfb_setup(char *options) tmp = g_settings; - /* Notes: - char * strsep(char **s,const char * ct); - @s: the string to be searched - @ct :the characters to search for - - strsep() updates @options to pointer after the first found token - it also returns the pointer ahead the token. - */ + /* + * Notes: + * char * strsep(char **s,const char * ct); + * @s: the string to be searched + * @ct :the characters to search for + * + * strsep() updates @options to pointer after the first found token + * it also returns the pointer ahead the token. + */ while ((opt = strsep(&options, ":")) != NULL) { /* options that mean for any lynx chips are configured here */ if (!strncmp(opt, "noaccel", strlen("noaccel"))) -- cgit v1.3-6-gb490 From f8fbc838f4b2cd72da11568b09b956806b98c29e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 17:34:05 +0530 Subject: staging: sm750fb: rearrange code Rearrange the code to remove one exit label which also makes the code less indented and more readable. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index fa2183d33bda..e7fad0f2cdf8 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -261,22 +261,21 @@ static void lynxfb_ops_imageblit(struct fb_info *info, pitch = info->fix.line_length; Bpp = info->var.bits_per_pixel >> 3; - if (image->depth == 1) { - if (info->fix.visual == FB_VISUAL_TRUECOLOR || - info->fix.visual == FB_VISUAL_DIRECTCOLOR) { - fgcol = ((u32 *)info->pseudo_palette)[image->fg_color]; - bgcol = ((u32 *)info->pseudo_palette)[image->bg_color]; - } else { - fgcol = image->fg_color; - bgcol = image->bg_color; - } - goto _do_work; - } /* TODO: Implement hardware acceleration for image->depth > 1 */ - cfb_imageblit(info, image); - return; + if (image->depth != 1) { + cfb_imageblit(info, image); + return; + } + + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + fgcol = ((u32 *)info->pseudo_palette)[image->fg_color]; + bgcol = ((u32 *)info->pseudo_palette)[image->bg_color]; + } else { + fgcol = image->fg_color; + bgcol = image->bg_color; + } -_do_work: /* * If not use spin_lock, system will die if user load driver * and immediately unload driver frequently (dual) -- cgit v1.3-6-gb490 From 4063ea9af6d287975732a0c992e7fe870591d365 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 17:34:06 +0530 Subject: staging: sm750fb: simplify return Lets return the return value directly instead of using a variable to store the result. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/sm750.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c index e7fad0f2cdf8..07f8afd2defe 100644 --- a/drivers/staging/sm750fb/sm750.c +++ b/drivers/staging/sm750fb/sm750.c @@ -298,17 +298,13 @@ static int lynxfb_ops_pan_display(struct fb_var_screeninfo *var, { struct lynxfb_par *par; struct lynxfb_crtc *crtc; - int ret; if (!info) return -EINVAL; - ret = 0; par = info->par; crtc = &par->crtc; - ret = crtc->proc_panDisplay(crtc, var, info); - - return ret; + return crtc->proc_panDisplay(crtc, var, info); } static int lynxfb_ops_set_par(struct fb_info *info) -- cgit v1.3-6-gb490 From 881edf67b26813f91288790bbb575c570b9de901 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Wed, 5 Aug 2015 17:17:15 -0700 Subject: staging: rtl8712: simplify size calculation replace item-by-item size calculation of a struct with the size of the struct. This gets rid of a use of typedef NDIS_802_11_RATES_EX Signed-off-by: Joshua Clayton Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl871x_cmd.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c index e35854d28f90..f07050ddd82d 100644 --- a/drivers/staging/rtl8712/rtl871x_cmd.c +++ b/drivers/staging/rtl8712/rtl871x_cmd.c @@ -471,7 +471,6 @@ u8 r8712_createbss_cmd(struct _adapter *padapter) u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork) { - uint t_len = 0; struct ndis_wlan_bssid_ex *psecnetwork; struct cmd_obj *pcmd; struct cmd_priv *pcmdpriv = &padapter->cmdpriv; @@ -486,14 +485,6 @@ u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork) pcmd = kmalloc(sizeof(*pcmd), GFP_ATOMIC); if (pcmd == NULL) return _FAIL; - t_len = sizeof(u32) + 6 * sizeof(unsigned char) + 2 + - sizeof(struct ndis_802_11_ssid) + sizeof(u32) + - sizeof(s32) + - sizeof(enum NDIS_802_11_NETWORK_TYPE) + - sizeof(struct NDIS_802_11_CONFIGURATION) + - sizeof(enum NDIS_802_11_NETWORK_INFRASTRUCTURE) + - sizeof(NDIS_802_11_RATES_EX) + - sizeof(u32) + MAX_IE_SZ; /* for hidden ap to set fw_state here */ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE) != @@ -516,7 +507,7 @@ u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork) kfree(pcmd); return _FAIL; } - memcpy(psecnetwork, &pnetwork->network, t_len); + memcpy(psecnetwork, &pnetwork->network, sizeof(*psecnetwork)); psecuritypriv->authenticator_ie[0] = (unsigned char) psecnetwork->IELength; if ((psecnetwork->IELength-12) < (256 - 1)) -- cgit v1.3-6-gb490 From 9bdb70ecddd4441be8818ab2f6cbea269c84b3fb Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Wed, 5 Aug 2015 17:17:16 -0700 Subject: staging: rtl8712: fix comment The old comment refers to a typedef name which is being removed, and to a style of calculation which is no longer being used. It falsely states that IELength is variable length, instead of IEs. Change comment to simply state that the IEs field is a buffer of variable size and that IELength refers to the current size. Signed-off-by: Joshua Clayton Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/wlan_bssdef.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/wlan_bssdef.h b/drivers/staging/rtl8712/wlan_bssdef.h index 2ea8a3d6b705..8c5d6e7f82d2 100644 --- a/drivers/staging/rtl8712/wlan_bssdef.h +++ b/drivers/staging/rtl8712/wlan_bssdef.h @@ -83,17 +83,6 @@ struct NDIS_802_11_FIXED_IEs { u16 Capabilities; }; -/* - * Length is the 4 bytes multiples of the sume of - * 6 * sizeof (unsigned char) + 2 + sizeof (ndis_802_11_ssid) + sizeof (u32) - * + sizeof (s32) + sizeof (NDIS_802_11_NETWORK_TYPE) - * + sizeof (struct NDIS_802_11_CONFIGURATION) - * + sizeof (NDIS_802_11_RATES_EX) + IELength - - * Except the IELength, all other fields are fixed length. Therefore, we can - * define a macro to present the partial sum. - */ - struct ndis_wlan_bssid_ex { u32 Length; unsigned char MacAddress[6]; @@ -105,6 +94,7 @@ struct ndis_wlan_bssid_ex { struct NDIS_802_11_CONFIGURATION Configuration; enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; NDIS_802_11_RATES_EX SupportedRates; + /* number of content bytes in EIs, which varies */ u32 IELength; /*(timestamp, beacon interval, and capability information) */ u8 IEs[MAX_IE_SZ]; -- cgit v1.3-6-gb490 From ebe92393cac834c89c774f93d92c8118b69e6016 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Wed, 5 Aug 2015 17:17:17 -0700 Subject: staging: rtl8712: removed unused wrapper structs Remove wrapper structs that just wrap struct ndis_wlan_bssid_ex, and are unused. Signed-off-by: Joshua Clayton Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl871x_cmd.h | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/rtl871x_cmd.h b/drivers/staging/rtl8712/rtl871x_cmd.h index cb8225b94cf1..818cd8807a38 100644 --- a/drivers/staging/rtl8712/rtl871x_cmd.h +++ b/drivers/staging/rtl8712/rtl871x_cmd.h @@ -122,15 +122,6 @@ struct usb_suspend_parm { u32 action; /* 1: sleep, 0:resume */ }; -/* - * Caller Mode: Infra, Ad-Hoc - * Notes: To join the specified bss - * Command Event Mode - */ -struct joinbss_parm { - struct ndis_wlan_bssid_ex network; -}; - /* * Caller Mode: Infra, Ad-HoC(C) * Notes: To disconnect the current associated BSS @@ -140,15 +131,6 @@ struct disconnect_parm { u32 rsvd; }; -/* - * Caller Mode: AP, Ad-HoC(M) - * Notes: To create a BSS - * Command Mode - */ -struct createbss_parm { - struct ndis_wlan_bssid_ex network; -}; - /* * Caller Mode: AP, Ad-HoC, Infra * Notes: To set the NIC mode of RTL8711 -- cgit v1.3-6-gb490 From 44367877c6c5048ac352c529c63ce0698c1ddd5c Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Wed, 5 Aug 2015 17:17:18 -0700 Subject: staging: rtl8712: remove duplicate struct struct ndis_wlan_bssid_ex is a doppelganger of struct wlan_bssid_ex, and is used about a third as often. Switch all instances to wlan_bssid_ex, and remove ndis_wlan_bssid_ex This also gets rid of a use of typedef NDIS_802_11_RATES_EX Signed-off-by: Joshua Clayton Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl871x_cmd.c | 11 ++++------- drivers/staging/rtl8712/rtl871x_event.h | 2 +- drivers/staging/rtl8712/rtl871x_ioctl_linux.c | 10 +++++----- drivers/staging/rtl8712/rtl871x_mlme.c | 23 +++++++++++------------ drivers/staging/rtl8712/rtl871x_mlme.h | 2 +- drivers/staging/rtl8712/rtl871x_mp_ioctl.c | 4 ++-- drivers/staging/rtl8712/wlan_bssdef.h | 23 ++--------------------- 7 files changed, 26 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c index f07050ddd82d..06d9844ac722 100644 --- a/drivers/staging/rtl8712/rtl871x_cmd.c +++ b/drivers/staging/rtl8712/rtl871x_cmd.c @@ -456,9 +456,7 @@ u8 r8712_createbss_cmd(struct _adapter *padapter) INIT_LIST_HEAD(&pcmd->list); pcmd->cmdcode = _CreateBss_CMD_; pcmd->parmbuf = (unsigned char *)pdev_network; - pcmd->cmdsz = r8712_get_ndis_wlan_bssid_ex_sz(( - struct ndis_wlan_bssid_ex *) - pdev_network); + pcmd->cmdsz = r8712_get_ndis_wlan_bssid_ex_sz(pdev_network); pcmd->rsp = NULL; pcmd->rspsz = 0; /* notes: translate IELength & Length after assign to cmdsz; */ @@ -471,7 +469,7 @@ u8 r8712_createbss_cmd(struct _adapter *padapter) u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork) { - struct ndis_wlan_bssid_ex *psecnetwork; + struct wlan_bssid_ex *psecnetwork; struct cmd_obj *pcmd; struct cmd_priv *pcmdpriv = &padapter->cmdpriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -502,7 +500,7 @@ u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork) break; } } - psecnetwork = (struct ndis_wlan_bssid_ex *)&psecuritypriv->sec_bss; + psecnetwork = &psecuritypriv->sec_bss; if (psecnetwork == NULL) { kfree(pcmd); return _FAIL; @@ -894,8 +892,7 @@ void r8712_createbss_cmd_callback(struct _adapter *padapter, struct sta_info *psta = NULL; struct wlan_network *pwlan = NULL; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ndis_wlan_bssid_ex *pnetwork = (struct ndis_wlan_bssid_ex *) - pcmd->parmbuf; + struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf; struct wlan_network *tgt_network = &(pmlmepriv->cur_network); if (pcmd->res != H2C_SUCCESS) diff --git a/drivers/staging/rtl8712/rtl871x_event.h b/drivers/staging/rtl8712/rtl871x_event.h index e03ee90d2870..697c8d735150 100644 --- a/drivers/staging/rtl8712/rtl871x_event.h +++ b/drivers/staging/rtl8712/rtl871x_event.h @@ -36,7 +36,7 @@ * Used to report a bss has been scanned */ struct survey_event { - struct ndis_wlan_bssid_ex bss; + struct wlan_bssid_ex bss; }; /* diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c index 3388f971fb48..4f5f69c950cc 100644 --- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c @@ -634,7 +634,7 @@ static int r8711_wx_get_name(struct net_device *dev, char *p; u8 ht_cap = false; struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; + struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; NDIS_802_11_RATES_EX *prates = NULL; if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == @@ -723,7 +723,7 @@ static int r8711_wx_get_freq(struct net_device *dev, { struct _adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; + struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; if (check_fwstate(pmlmepriv, _FW_LINKED) == true) { wrqu->freq.m = ieee80211_wlan_frequencies[ @@ -1111,7 +1111,7 @@ static int r8711_wx_get_wap(struct net_device *dev, { struct _adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; + struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; wrqu->ap_addr.sa_family = ARPHRD_ETHER; if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE | @@ -1327,7 +1327,7 @@ static int r8711_wx_get_essid(struct net_device *dev, { struct _adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; + struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; u32 len, ret = 0; if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE)) { @@ -1419,7 +1419,7 @@ static int r8711_wx_get_rate(struct net_device *dev, { struct _adapter *padapter = netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ndis_wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; + struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; struct ieee80211_ht_cap *pht_capie; unsigned char rf_type = padapter->registrypriv.rf_config; int i; diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index 6b3451f7017b..7af96993c6a5 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -208,7 +208,7 @@ void r8712_generate_random_ibss(u8 *pibss) pibss[5] = (u8)((curtime>>16) & 0xff); } -uint r8712_get_ndis_wlan_bssid_ex_sz(struct ndis_wlan_bssid_ex *bss) +uint r8712_get_ndis_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss) { return sizeof(*bss) + bss->IELength - MAX_IE_SZ; } @@ -276,8 +276,8 @@ int r8712_is_same_ibss(struct _adapter *adapter, struct wlan_network *pnetwork) } -static int is_same_network(struct ndis_wlan_bssid_ex *src, - struct ndis_wlan_bssid_ex *dst) +static int is_same_network(struct wlan_bssid_ex *src, + struct wlan_bssid_ex *dst) { u16 s_cap, d_cap; @@ -322,8 +322,8 @@ struct wlan_network *r8712_get_oldest_wlan_network( return oldest; } -static void update_network(struct ndis_wlan_bssid_ex *dst, - struct ndis_wlan_bssid_ex *src, +static void update_network(struct wlan_bssid_ex *dst, + struct wlan_bssid_ex *src, struct _adapter *padapter) { u32 last_evm = 0, tmpVal; @@ -360,7 +360,7 @@ static void update_network(struct ndis_wlan_bssid_ex *dst, } static void update_current_network(struct _adapter *adapter, - struct ndis_wlan_bssid_ex *pnetwork) + struct wlan_bssid_ex *pnetwork) { struct mlme_priv *pmlmepriv = &adapter->mlmepriv; @@ -378,7 +378,7 @@ static void update_current_network(struct _adapter *adapter, Caller must hold pmlmepriv->lock first. */ static void update_scanned_network(struct _adapter *adapter, - struct ndis_wlan_bssid_ex *target) + struct wlan_bssid_ex *target) { struct list_head *plist, *phead; @@ -441,7 +441,7 @@ static void update_scanned_network(struct _adapter *adapter, } static void rtl8711_add_network(struct _adapter *adapter, - struct ndis_wlan_bssid_ex *pnetwork) + struct wlan_bssid_ex *pnetwork) { unsigned long irqL; struct mlme_priv *pmlmepriv = &(((struct _adapter *)adapter)->mlmepriv); @@ -497,10 +497,10 @@ void r8712_survey_event_callback(struct _adapter *adapter, u8 *pbuf) { unsigned long flags; u32 len; - struct ndis_wlan_bssid_ex *pnetwork; + struct wlan_bssid_ex *pnetwork; struct mlme_priv *pmlmepriv = &adapter->mlmepriv; - pnetwork = (struct ndis_wlan_bssid_ex *)pbuf; + pnetwork = (struct wlan_bssid_ex *)pbuf; #ifdef __BIG_ENDIAN /* endian_convert */ pnetwork->Length = le32_to_cpu(pnetwork->Length); @@ -1658,8 +1658,7 @@ void r8712_update_registrypriv_dev_network(struct _adapter *adapter) */ sz = r8712_generate_ie(pregistrypriv); pdev_network->IELength = sz; - pdev_network->Length = r8712_get_ndis_wlan_bssid_ex_sz( - (struct ndis_wlan_bssid_ex *)pdev_network); + pdev_network->Length = r8712_get_ndis_wlan_bssid_ex_sz(pdev_network); } /*the function is at passive_level*/ diff --git a/drivers/staging/rtl8712/rtl871x_mlme.h b/drivers/staging/rtl8712/rtl871x_mlme.h index 42bd0bf8a816..47bb9c5e9708 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.h +++ b/drivers/staging/rtl8712/rtl871x_mlme.h @@ -202,7 +202,7 @@ sint r8712_set_key(struct _adapter *adapter, struct security_priv *psecuritypriv, sint keyid); sint r8712_set_auth(struct _adapter *adapter, struct security_priv *psecuritypriv); -uint r8712_get_ndis_wlan_bssid_ex_sz(struct ndis_wlan_bssid_ex *bss); +uint r8712_get_ndis_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss); void r8712_generate_random_ibss(u8 *pibss); u8 *r8712_get_capability_from_ie(u8 *ie); struct wlan_network *r8712_get_oldest_wlan_network( diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c index 0b5461208eb9..c77b63affdc5 100644 --- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c +++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c @@ -160,13 +160,13 @@ static int mp_start_test(struct _adapter *padapter) struct mp_priv *pmppriv = &padapter->mppriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct wlan_network *tgt_network = &pmlmepriv->cur_network; - struct ndis_wlan_bssid_ex bssid; + struct wlan_bssid_ex bssid; struct sta_info *psta; unsigned long length; unsigned long irqL; int res = _SUCCESS; - /* 3 1. initialize a new struct ndis_wlan_bssid_ex */ + /* 3 1. initialize a new struct wlan_bssid_ex */ memcpy(bssid.MacAddress, pmppriv->network_macaddr, ETH_ALEN); bssid.Ssid.SsidLength = 16; memcpy(bssid.Ssid.Ssid, (unsigned char *)"mp_pseudo_adhoc", diff --git a/drivers/staging/rtl8712/wlan_bssdef.h b/drivers/staging/rtl8712/wlan_bssdef.h index 8c5d6e7f82d2..cd3e62a20161 100644 --- a/drivers/staging/rtl8712/wlan_bssdef.h +++ b/drivers/staging/rtl8712/wlan_bssdef.h @@ -83,7 +83,7 @@ struct NDIS_802_11_FIXED_IEs { u16 Capabilities; }; -struct ndis_wlan_bssid_ex { +struct wlan_bssid_ex { u32 Length; unsigned char MacAddress[6]; u8 Reserved[2]; @@ -203,7 +203,7 @@ struct wlan_network { unsigned int last_scanned; /*timestamp for the network */ int aid; /*will only be valid when a BSS is joined. */ int join_res; - struct ndis_wlan_bssid_ex network; /*must be the last item */ + struct wlan_bssid_ex network; /*must be the last item */ }; enum VRTL_CARRIER_SENSE { @@ -234,24 +234,5 @@ enum UAPSD_MAX_SP { #define NUM_PRE_AUTH_KEY 16 #define NUM_PMKID_CACHE NUM_PRE_AUTH_KEY -/* - * WPA2 - */ -struct wlan_bssid_ex { - u32 Length; - unsigned char MacAddress[6]; - u8 Reserved[2]; - struct ndis_802_11_ssid Ssid; - u32 Privacy; - s32 Rssi; - enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; - struct NDIS_802_11_CONFIGURATION Configuration; - enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; - NDIS_802_11_RATES_EX SupportedRates; - u32 IELength; - u8 IEs[MAX_IE_SZ]; /* (timestamp, beacon interval, and capability - * information) */ -}; - #endif /* #ifndef WLAN_BSSDEF_H_ */ -- cgit v1.3-6-gb490 From 986fc8e7410d65fe5adfee787ce14d56f72b4c4c Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Wed, 5 Aug 2015 17:17:19 -0700 Subject: staging: rtl8712: rename function Rename r8712_get_ndis_wlan_bssid_ex_sz() to r8712_get_wlan_bssid_ex_sz(), which corresponds to the struct whose size it measures. Signed-off-by: Joshua Clayton Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl871x_cmd.c | 8 ++++---- drivers/staging/rtl8712/rtl871x_mlme.c | 16 ++++++++-------- drivers/staging/rtl8712/rtl871x_mlme.h | 2 +- drivers/staging/rtl8712/rtl871x_mp_ioctl.c | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c index 06d9844ac722..ef7182961002 100644 --- a/drivers/staging/rtl8712/rtl871x_cmd.c +++ b/drivers/staging/rtl8712/rtl871x_cmd.c @@ -456,7 +456,7 @@ u8 r8712_createbss_cmd(struct _adapter *padapter) INIT_LIST_HEAD(&pcmd->list); pcmd->cmdcode = _CreateBss_CMD_; pcmd->parmbuf = (unsigned char *)pdev_network; - pcmd->cmdsz = r8712_get_ndis_wlan_bssid_ex_sz(pdev_network); + pcmd->cmdsz = r8712_get_wlan_bssid_ex_sz(pdev_network); pcmd->rsp = NULL; pcmd->rspsz = 0; /* notes: translate IELength & Length after assign to cmdsz; */ @@ -564,7 +564,7 @@ u8 r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork) memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0], 255); /* get cmdsz before endian conversion */ - pcmd->cmdsz = r8712_get_ndis_wlan_bssid_ex_sz(psecnetwork); + pcmd->cmdsz = r8712_get_wlan_bssid_ex_sz(psecnetwork); #ifdef __BIG_ENDIAN /* wlan_network endian conversion */ psecnetwork->Length = cpu_to_le32(psecnetwork->Length); @@ -946,11 +946,11 @@ void r8712_createbss_cmd_callback(struct _adapter *padapter, } else list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); - pnetwork->Length = r8712_get_ndis_wlan_bssid_ex_sz(pnetwork); + pnetwork->Length = r8712_get_wlan_bssid_ex_sz(pnetwork); memcpy(&(pwlan->network), pnetwork, pnetwork->Length); pwlan->fixed = true; memcpy(&tgt_network->network, pnetwork, - (r8712_get_ndis_wlan_bssid_ex_sz(pnetwork))); + (r8712_get_wlan_bssid_ex_sz(pnetwork))); if (pmlmepriv->fw_state & _FW_UNDER_LINKING) pmlmepriv->fw_state ^= _FW_UNDER_LINKING; /* we will set _FW_LINKED when there is one more sat to diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index 7af96993c6a5..fc5dbea08cb4 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -208,7 +208,7 @@ void r8712_generate_random_ibss(u8 *pibss) pibss[5] = (u8)((curtime>>16) & 0xff); } -uint r8712_get_ndis_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss) +uint r8712_get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss) { return sizeof(*bss) + bss->IELength - MAX_IE_SZ; } @@ -356,7 +356,7 @@ static void update_network(struct wlan_bssid_ex *dst, src->Rssi = padapter->recvpriv.signal; } else src->Rssi = (src->Rssi + dst->Rssi) / 2; - memcpy((u8 *)dst, (u8 *)src, r8712_get_ndis_wlan_bssid_ex_sz(src)); + memcpy((u8 *)dst, (u8 *)src, r8712_get_wlan_bssid_ex_sz(src)); } static void update_current_network(struct _adapter *adapter, @@ -416,7 +416,7 @@ static void update_scanned_network(struct _adapter *adapter, target->Rssi = (pnetwork->network.Rssi + target->Rssi) / 2; memcpy(&pnetwork->network, target, - r8712_get_ndis_wlan_bssid_ex_sz(target)); + r8712_get_wlan_bssid_ex_sz(target)); pnetwork->last_scanned = jiffies; } else { /* Otherwise just pull from the free list */ @@ -424,7 +424,7 @@ static void update_scanned_network(struct _adapter *adapter, pnetwork = alloc_network(pmlmepriv); if (pnetwork == NULL) return; - bssid_ex_sz = r8712_get_ndis_wlan_bssid_ex_sz(target); + bssid_ex_sz = r8712_get_wlan_bssid_ex_sz(target); target->Length = bssid_ex_sz; memcpy(&pnetwork->network, target, bssid_ex_sz); list_add_tail(&pnetwork->list, &queue->queue); @@ -528,7 +528,7 @@ void r8712_survey_event_callback(struct _adapter *adapter, u8 *pbuf) le32_to_cpu(pnetwork->InfrastructureMode); pnetwork->IELength = le32_to_cpu(pnetwork->IELength); #endif - len = r8712_get_ndis_wlan_bssid_ex_sz(pnetwork); + len = r8712_get_wlan_bssid_ex_sz(pnetwork); if (len > sizeof(struct wlan_bssid_ex)) return; spin_lock_irqsave(&pmlmepriv->lock2, flags); @@ -759,7 +759,7 @@ void r8712_joinbss_event_callback(struct _adapter *adapter, u8 *pbuf) the_same_macaddr = !memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN); pnetwork->network.Length = - r8712_get_ndis_wlan_bssid_ex_sz(&pnetwork->network); + r8712_get_wlan_bssid_ex_sz(&pnetwork->network); spin_lock_irqsave(&pmlmepriv->lock, irqL); if (pnetwork->network.Length > sizeof(struct wlan_bssid_ex)) goto ignore_joinbss_callback; @@ -991,7 +991,7 @@ void r8712_stadel_event_callback(struct _adapter *adapter, u8 *pbuf) pdev_network = &(adapter->registrypriv.dev_network); pibss = adapter->registrypriv.dev_network.MacAddress; memcpy(pdev_network, &tgt_network->network, - r8712_get_ndis_wlan_bssid_ex_sz(&tgt_network-> + r8712_get_wlan_bssid_ex_sz(&tgt_network-> network)); memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, @@ -1658,7 +1658,7 @@ void r8712_update_registrypriv_dev_network(struct _adapter *adapter) */ sz = r8712_generate_ie(pregistrypriv); pdev_network->IELength = sz; - pdev_network->Length = r8712_get_ndis_wlan_bssid_ex_sz(pdev_network); + pdev_network->Length = r8712_get_wlan_bssid_ex_sz(pdev_network); } /*the function is at passive_level*/ diff --git a/drivers/staging/rtl8712/rtl871x_mlme.h b/drivers/staging/rtl8712/rtl871x_mlme.h index 47bb9c5e9708..08d6c986c11e 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.h +++ b/drivers/staging/rtl8712/rtl871x_mlme.h @@ -202,7 +202,7 @@ sint r8712_set_key(struct _adapter *adapter, struct security_priv *psecuritypriv, sint keyid); sint r8712_set_auth(struct _adapter *adapter, struct security_priv *psecuritypriv); -uint r8712_get_ndis_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss); +uint r8712_get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss); void r8712_generate_random_ibss(u8 *pibss); u8 *r8712_get_capability_from_ie(u8 *ie); struct wlan_network *r8712_get_oldest_wlan_network( diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c index c77b63affdc5..77f01bf1ca3c 100644 --- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c +++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c @@ -174,7 +174,7 @@ static int mp_start_test(struct _adapter *padapter) bssid.InfrastructureMode = Ndis802_11IBSS; bssid.NetworkTypeInUse = Ndis802_11DS; bssid.IELength = 0; - length = r8712_get_ndis_wlan_bssid_ex_sz(&bssid); + length = r8712_get_wlan_bssid_ex_sz(&bssid); if (length % 4) { /*round up to multiple of 4 bytes.*/ bssid.Length = ((length >> 2) + 1) << 2; -- cgit v1.3-6-gb490 From db55b1652e5b126d0dbfd1ce0bcbaacddac8f36e Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Wed, 5 Aug 2015 17:17:20 -0700 Subject: staging: rtl8712: remove typedefs Coding style fix. Get rid of typedefs NDIS_802_11_RATES and NDIS_802_11_RATES_EX Undo any casting that was done as a result of the typedef. Signed-off-by: Joshua Clayton Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl871x_ioctl_linux.c | 12 ++++++------ drivers/staging/rtl8712/wlan_bssdef.h | 7 +------ 2 files changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c index 4f5f69c950cc..83d4bca006a2 100644 --- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c @@ -203,13 +203,13 @@ static inline char *translate_scan(struct _adapter *padapter, } /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; - if ((r8712_is_cckratesonly_included((u8 *)&pnetwork->network. + if ((r8712_is_cckratesonly_included(pnetwork->network. SupportedRates)) == true) { if (ht_cap == true) snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn"); else snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b"); - } else if ((r8712_is_cckrates_included((u8 *)&pnetwork->network. + } else if ((r8712_is_cckrates_included(pnetwork->network. SupportedRates)) == true) { if (ht_cap == true) snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn"); @@ -635,7 +635,7 @@ static int r8711_wx_get_name(struct net_device *dev, u8 ht_cap = false; struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; - NDIS_802_11_RATES_EX *prates = NULL; + u8 *prates; if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) { @@ -644,15 +644,15 @@ static int r8711_wx_get_name(struct net_device *dev, &ht_ielen, pcur_bss->IELength - 12); if (p && ht_ielen > 0) ht_cap = true; - prates = &pcur_bss->SupportedRates; - if (r8712_is_cckratesonly_included((u8 *)prates) == true) { + prates = pcur_bss->SupportedRates; + if (r8712_is_cckratesonly_included(prates) == true) { if (ht_cap == true) snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bn"); else snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b"); - } else if ((r8712_is_cckrates_included((u8 *)prates)) == true) { + } else if ((r8712_is_cckrates_included(prates)) == true) { if (ht_cap == true) snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bgn"); diff --git a/drivers/staging/rtl8712/wlan_bssdef.h b/drivers/staging/rtl8712/wlan_bssdef.h index cd3e62a20161..ff86fbd1d52b 100644 --- a/drivers/staging/rtl8712/wlan_bssdef.h +++ b/drivers/staging/rtl8712/wlan_bssdef.h @@ -32,11 +32,6 @@ #define NDIS_802_11_LENGTH_RATES 8 #define NDIS_802_11_LENGTH_RATES_EX 16 -/* Set of 8 data rates*/ -typedef unsigned char NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; -/* Set of 16 data rates */ -typedef unsigned char NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; - struct ndis_802_11_ssid { u32 SsidLength; u8 Ssid[32]; @@ -93,7 +88,7 @@ struct wlan_bssid_ex { enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; struct NDIS_802_11_CONFIGURATION Configuration; enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; - NDIS_802_11_RATES_EX SupportedRates; + u8 SupportedRates[NDIS_802_11_LENGTH_RATES_EX]; /* number of content bytes in EIs, which varies */ u32 IELength; /*(timestamp, beacon interval, and capability information) */ -- cgit v1.3-6-gb490 From 7fb539eda2be9fce93b7f1cc933ef318e9c3771b Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Wed, 5 Aug 2015 17:17:21 -0700 Subject: staging: rtl8712: change SupportedRates to rates Change the value to a name that conforms to Linux coding style. "rates" is equally expressive in this context, and I have left alone a comment and function name that describe the rates as supported rates. Signed-off-by: Joshua Clayton Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/ieee80211.c | 25 +++++++++++-------------- drivers/staging/rtl8712/rtl871x_ioctl_linux.c | 18 ++++++++---------- drivers/staging/rtl8712/wlan_bssdef.h | 2 +- 3 files changed, 20 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/ieee80211.c b/drivers/staging/rtl8712/ieee80211.c index 57868085ce58..c5527c1ccaa6 100644 --- a/drivers/staging/rtl8712/ieee80211.c +++ b/drivers/staging/rtl8712/ieee80211.c @@ -134,22 +134,20 @@ u8 *r8712_get_ie(u8 *pbuf, sint index, sint *len, sint limit) return NULL; } -static void set_supported_rate(u8 *SupportedRates, uint mode) +static void set_supported_rate(u8 *rates, uint mode) { - memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX); + memset(rates, 0, NDIS_802_11_LENGTH_RATES_EX); switch (mode) { case WIRELESS_11B: - memcpy(SupportedRates, WIFI_CCKRATES, - IEEE80211_CCK_RATE_LEN); + memcpy(rates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); break; case WIRELESS_11G: case WIRELESS_11A: - memcpy(SupportedRates, WIFI_OFDMRATES, - IEEE80211_NUM_OFDM_RATESLEN); + memcpy(rates, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN); break; case WIRELESS_11BG: - memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); - memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, + memcpy(rates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN); + memcpy(rates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES, IEEE80211_NUM_OFDM_RATESLEN); break; } @@ -195,17 +193,16 @@ int r8712_generate_ie(struct registry_priv *pregistrypriv) ie = r8712_set_ie(ie, _SSID_IE_, pdev_network->Ssid.SsidLength, pdev_network->Ssid.Ssid, &sz); /*supported rates*/ - set_supported_rate(pdev_network->SupportedRates, - pregistrypriv->wireless_mode); - rateLen = r8712_get_rateset_len(pdev_network->SupportedRates); + set_supported_rate(pdev_network->rates, pregistrypriv->wireless_mode); + rateLen = r8712_get_rateset_len(pdev_network->rates); if (rateLen > 8) { ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_, 8, - pdev_network->SupportedRates, &sz); + pdev_network->rates, &sz); ie = r8712_set_ie(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), - (pdev_network->SupportedRates + 8), &sz); + (pdev_network->rates + 8), &sz); } else ie = r8712_set_ie(ie, _SUPPORTEDRATES_IE_, - rateLen, pdev_network->SupportedRates, &sz); + rateLen, pdev_network->rates, &sz); /*DS parameter set*/ ie = r8712_set_ie(ie, _DSSET_IE_, 1, (u8 *)&(pdev_network->Configuration.DSConfig), &sz); diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c index 83d4bca006a2..143be0fdc578 100644 --- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c @@ -203,14 +203,12 @@ static inline char *translate_scan(struct _adapter *padapter, } /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; - if ((r8712_is_cckratesonly_included(pnetwork->network. - SupportedRates)) == true) { + if (r8712_is_cckratesonly_included(pnetwork->network.rates)) { if (ht_cap == true) snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bn"); else snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11b"); - } else if ((r8712_is_cckrates_included(pnetwork->network. - SupportedRates)) == true) { + } else if (r8712_is_cckrates_included(pnetwork->network.rates)) { if (ht_cap == true) snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bgn"); else @@ -270,9 +268,9 @@ static inline char *translate_scan(struct _adapter *padapter, iwe.u.bitrate.disabled = 0; iwe.u.bitrate.value = 0; i = 0; - while (pnetwork->network.SupportedRates[i] != 0) { + while (pnetwork->network.rates[i] != 0) { /* Bit rate given in 500 kb/s units */ - iwe.u.bitrate.value = (pnetwork->network.SupportedRates[i++] & + iwe.u.bitrate.value = (pnetwork->network.rates[i++] & 0x7F) * 500000; current_val = iwe_stream_add_value(info, start, current_val, stop, &iwe, IW_EV_PARAM_LEN); @@ -644,7 +642,7 @@ static int r8711_wx_get_name(struct net_device *dev, &ht_ielen, pcur_bss->IELength - 12); if (p && ht_ielen > 0) ht_cap = true; - prates = pcur_bss->SupportedRates; + prates = pcur_bss->rates; if (r8712_is_cckratesonly_included(prates) == true) { if (ht_cap == true) snprintf(wrqu->name, IFNAMSIZ, @@ -1444,9 +1442,9 @@ static int r8711_wx_get_rate(struct net_device *dev, (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40)) ? 1 : 0; } - while ((pcur_bss->SupportedRates[i] != 0) && - (pcur_bss->SupportedRates[i] != 0xFF)) { - rate = pcur_bss->SupportedRates[i] & 0x7F; + while ((pcur_bss->rates[i] != 0) && + (pcur_bss->rates[i] != 0xFF)) { + rate = pcur_bss->rates[i] & 0x7F; if (rate > max_rate) max_rate = rate; wrqu->bitrate.fixed = 0; /* no auto select */ diff --git a/drivers/staging/rtl8712/wlan_bssdef.h b/drivers/staging/rtl8712/wlan_bssdef.h index ff86fbd1d52b..fda5707c4acd 100644 --- a/drivers/staging/rtl8712/wlan_bssdef.h +++ b/drivers/staging/rtl8712/wlan_bssdef.h @@ -88,7 +88,7 @@ struct wlan_bssid_ex { enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse; struct NDIS_802_11_CONFIGURATION Configuration; enum NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode; - u8 SupportedRates[NDIS_802_11_LENGTH_RATES_EX]; + u8 rates[NDIS_802_11_LENGTH_RATES_EX]; /* number of content bytes in EIs, which varies */ u32 IELength; /*(timestamp, beacon interval, and capability information) */ -- cgit v1.3-6-gb490 From e8f35aabae837e6d1a1d82a8cc54f8ce7366ed49 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 7 Aug 2015 09:59:16 +0200 Subject: clk/mmp: use kmemdup rather than duplicating its implementation The patch was generated using fixed coccinelle semantic patch scripts/coccinelle/api/memdup.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2014320 Signed-off-by: Andrzej Hajda Signed-off-by: Stephen Boyd --- drivers/clk/mmp/clk-mix.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c index 665cb6794639..33834105a09f 100644 --- a/drivers/clk/mmp/clk-mix.c +++ b/drivers/clk/mmp/clk-mix.c @@ -469,20 +469,20 @@ struct clk *mmp_clk_register_mix(struct device *dev, memcpy(&mix->reg_info, &config->reg_info, sizeof(config->reg_info)); if (config->table) { table_bytes = sizeof(*config->table) * config->table_size; - mix->table = kzalloc(table_bytes, GFP_KERNEL); + mix->table = kmemdup(config->table, table_bytes, GFP_KERNEL); if (!mix->table) { pr_err("%s:%s: could not allocate mmp mix table\n", __func__, name); kfree(mix); return ERR_PTR(-ENOMEM); } - memcpy(mix->table, config->table, table_bytes); mix->table_size = config->table_size; } if (config->mux_table) { table_bytes = sizeof(u32) * num_parents; - mix->mux_table = kzalloc(table_bytes, GFP_KERNEL); + mix->mux_table = kmemdup(config->mux_table, table_bytes, + GFP_KERNEL); if (!mix->mux_table) { pr_err("%s:%s: could not allocate mmp mix mux-table\n", __func__, name); @@ -490,7 +490,6 @@ struct clk *mmp_clk_register_mix(struct device *dev, kfree(mix); return ERR_PTR(-ENOMEM); } - memcpy(mix->mux_table, config->mux_table, table_bytes); } mix->div_flags = config->div_flags; -- cgit v1.3-6-gb490 From 741a3b0745596f18a20da30b167e46c11bb3ce53 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 7 Aug 2015 09:59:25 +0200 Subject: staging/lustre: use kmemdup rather than duplicating its implementation The patch was generated using fixed coccinelle semantic patch scripts/coccinelle/api/memdup.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2014320 Signed-off-by: Andrzej Hajda Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/obdclass/acl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/obdclass/acl.c b/drivers/staging/lustre/lustre/obdclass/acl.c index bc3fc4780cb9..933456c502d1 100644 --- a/drivers/staging/lustre/lustre/obdclass/acl.c +++ b/drivers/staging/lustre/lustre/obdclass/acl.c @@ -104,11 +104,10 @@ static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header, if (unlikely(old_count <= new_count)) return old_size; - new = kzalloc(new_size, GFP_NOFS); + new = kmemdup(*header, new_size, GFP_NOFS); if (unlikely(new == NULL)) return -ENOMEM; - memcpy(new, *header, new_size); kfree(*header); *header = new; return new_size; @@ -125,11 +124,10 @@ static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header, if (unlikely(old_count <= ext_count)) return 0; - new = kzalloc(ext_size, GFP_NOFS); + new = kmemdup(*header, ext_size, GFP_NOFS); if (unlikely(new == NULL)) return -ENOMEM; - memcpy(new, *header, ext_size); kfree(*header); *header = new; return 0; -- cgit v1.3-6-gb490 From 2cc468378a4f8dd3517d9fc1d613c2f328e070c4 Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Fri, 7 Aug 2015 09:02:01 +0900 Subject: staging: wilc1000: use memset instead of WILC_memset Use memset instead of WILC_memset. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/coreconfigurator.c | 16 +-- drivers/staging/wilc1000/host_interface.c | 134 +++++++++++----------- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 16 +-- 3 files changed, 83 insertions(+), 83 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c index 342a3368d4a2..93942b211fcd 100644 --- a/drivers/staging/wilc1000/coreconfigurator.c +++ b/drivers/staging/wilc1000/coreconfigurator.c @@ -681,9 +681,9 @@ s32 CoreConfiguratorInit(void) goto _fail_; } - WILC_memset((void *)gps8ConfigPacket, 0, MAX_PACKET_BUFF_SIZE); + memset((void *)gps8ConfigPacket, 0, MAX_PACKET_BUFF_SIZE); - WILC_memset((void *)(&gstrConfigPktInfo), 0, sizeof(tstrConfigPktInfo)); + memset((void *)(&gstrConfigPktInfo), 0, sizeof(tstrConfigPktInfo)); _fail_: return s32Error; } @@ -812,7 +812,7 @@ s32 ParseNetworkInfo(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo) u32 u32Tsf_Hi; pstrNetworkInfo = (tstrNetworkInfo *)WILC_MALLOC(sizeof(tstrNetworkInfo)); - WILC_memset((void *)(pstrNetworkInfo), 0, sizeof(tstrNetworkInfo)); + memset((void *)(pstrNetworkInfo), 0, sizeof(tstrNetworkInfo)); pstrNetworkInfo->s8rssi = pu8WidVal[0]; @@ -862,7 +862,7 @@ s32 ParseNetworkInfo(u8 *pu8MsgBuffer, tstrNetworkInfo **ppstrNetworkInfo) if (u16IEsLen > 0) { pstrNetworkInfo->pu8IEs = (u8 *)WILC_MALLOC(u16IEsLen); - WILC_memset((void *)(pstrNetworkInfo->pu8IEs), 0, u16IEsLen); + memset((void *)(pstrNetworkInfo->pu8IEs), 0, u16IEsLen); WILC_memcpy(pstrNetworkInfo->pu8IEs, pu8IEs, u16IEsLen); } @@ -929,7 +929,7 @@ s32 ParseAssocRespInfo(u8 *pu8Buffer, u32 u32BufferLen, u16 u16IEsLen = 0; pstrConnectRespInfo = (tstrConnectRespInfo *)WILC_MALLOC(sizeof(tstrConnectRespInfo)); - WILC_memset((void *)(pstrConnectRespInfo), 0, sizeof(tstrConnectRespInfo)); + memset((void *)(pstrConnectRespInfo), 0, sizeof(tstrConnectRespInfo)); /* u16AssocRespLen = pu8Buffer[0]; */ u16AssocRespLen = (u16)u32BufferLen; @@ -949,7 +949,7 @@ s32 ParseAssocRespInfo(u8 *pu8Buffer, u32 u32BufferLen, u16IEsLen = u16AssocRespLen - (CAP_INFO_LEN + STATUS_CODE_LEN + AID_LEN); pstrConnectRespInfo->pu8RespIEs = (u8 *)WILC_MALLOC(u16IEsLen); - WILC_memset((void *)(pstrConnectRespInfo->pu8RespIEs), 0, u16IEsLen); + memset((void *)(pstrConnectRespInfo->pu8RespIEs), 0, u16IEsLen); WILC_memcpy(pstrConnectRespInfo->pu8RespIEs, pu8IEs, u16IEsLen); pstrConnectRespInfo->u16RespIEsLen = u16IEsLen; @@ -1023,7 +1023,7 @@ s32 ParseSurveyResults(u8 ppu8RcvdSiteSurveyResults[][MAX_SURVEY_RESULT_FRAG_SIZ WILC_ERRORREPORT(s32Error, WILC_NO_MEM); } - WILC_memset((void *)(pstrSurveyResults), 0, u32SurveyResultsCount * sizeof(wid_site_survey_reslts_s)); + memset((void *)(pstrSurveyResults), 0, u32SurveyResultsCount * sizeof(wid_site_survey_reslts_s)); u32SurveyResultsCount = 0; @@ -1871,7 +1871,7 @@ s32 ConfigWaitResponse(char *pcRespBuffer, s32 s32MaxRespBuffLen, s32 *ps32Bytes *ps32BytesRead = gstrConfigPktInfo.s32BytesRead; } - WILC_memset((void *)(&gstrConfigPktInfo), 0, sizeof(tstrConfigPktInfo)); + memset((void *)(&gstrConfigPktInfo), 0, sizeof(tstrConfigPktInfo)); return s32Error; } diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 02aaf39bf28d..0c06ac27b4a7 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -1494,8 +1494,8 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon PRINT_D(GENERIC_DBG, "Handling connect request\n"); #ifndef CONNECT_DIRECT - WILC_memset(gapu8RcvdSurveyResults[0], 0, MAX_SURVEY_RESULT_FRAG_SIZE); - WILC_memset(gapu8RcvdSurveyResults[1], 0, MAX_SURVEY_RESULT_FRAG_SIZE); + memset(gapu8RcvdSurveyResults[0], 0, MAX_SURVEY_RESULT_FRAG_SIZE); + memset(gapu8RcvdSurveyResults[1], 0, MAX_SURVEY_RESULT_FRAG_SIZE); PRINT_D(HOSTINF_DBG, "Getting site survey results\n"); @@ -1972,7 +1972,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon PRINT_D(HOSTINF_DBG, "could not start connecting to the required network\n"); - WILC_memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); + memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); if (pstrHostIFconnectAttr->pfConnectResult != NULL) { if (pstrHostIFconnectAttr->pu8bssid != NULL) @@ -2124,7 +2124,7 @@ static s32 Handle_ConnectTimeout(void *drvHandler) gbScanWhileConnected = false; - WILC_memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); + memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); /* First, we will notify the upper layer with the Connection failure {through the Connect Callback function}, @@ -2190,7 +2190,7 @@ static s32 Handle_ConnectTimeout(void *drvHandler) pstrWFIDrv->strWILC_UsrConnReq.pu8ConnReqIEs = NULL; } - WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + memset(u8ConnectedSSID, 0, ETH_ALEN); /*BugID_5213*/ /*Freeing flushed join request params on connect timeout*/ if (gu8FlushedJoinReq != NULL && gu8FlushedJoinReqDrvHandler == (u32)drvHandler) { @@ -2399,10 +2399,10 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst PRINT_D(HOSTINF_DBG, "Recieved MAC status = %d with Reason = %d , Code = %d\n", u8MacStatus, u8MacStatusReasonCode, u8MacStatusAdditionalInfo); - WILC_memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); + memset(&strConnectInfo, 0, sizeof(tstrConnectInfo)); if (u8MacStatus == MAC_CONNECTED) { - WILC_memset(gapu8RcvdAssocResp, 0, MAX_ASSOC_RESP_FRAME_SIZE); + memset(gapu8RcvdAssocResp, 0, MAX_ASSOC_RESP_FRAME_SIZE); host_int_get_assoc_res_info((WILC_WFIDrvHandle)pstrWFIDrv, gapu8RcvdAssocResp, @@ -2449,11 +2449,11 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst if ((u8MacStatus == MAC_CONNECTED) && (strConnectInfo.u16ConnectStatus != SUCCESSFUL_STATUSCODE)) { PRINT_ER("Received MAC status is MAC_CONNECTED while the received status code in Asoc Resp is not SUCCESSFUL_STATUSCODE\n"); - WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + memset(u8ConnectedSSID, 0, ETH_ALEN); } else if (u8MacStatus == MAC_DISCONNECTED) { PRINT_ER("Received MAC status is MAC_DISCONNECTED\n"); - WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + memset(u8ConnectedSSID, 0, ETH_ALEN); } /* TODO: mostafa: correct BSSID should be retrieved from actual BSSID received from AP */ @@ -2554,7 +2554,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst /* Disassociation or Deauthentication frame has been received */ PRINT_D(HOSTINF_DBG, "Received MAC_DISCONNECTED from the FW\n"); - WILC_memset(&strDisconnectNotifInfo, 0, sizeof(tstrDisconnectNotifInfo)); + memset(&strDisconnectNotifInfo, 0, sizeof(tstrDisconnectNotifInfo)); if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { PRINT_D(HOSTINF_DBG, "\n\n<< Abort the running OBSS Scan >>\n\n"); @@ -2583,7 +2583,7 @@ static s32 Handle_RcvdGnrlAsyncInfo(void *drvHandler, tstrRcvdGnrlAsyncInfo *pst PRINT_ER("Connect result callback function is NULL\n"); } - WILC_memset(pstrWFIDrv->au8AssociatedBSSID, 0, ETH_ALEN); + memset(pstrWFIDrv->au8AssociatedBSSID, 0, ETH_ALEN); /* Deallocation */ @@ -2791,7 +2791,7 @@ static int Handle_Key(void *drvHandler, tstrHostIFkeyAttr *pstrHostIFkeyAttr) goto _WPARxGtk_end_case_; } - WILC_memset(pu8keybuf, 0, RX_MIC_KEY_MSG_LEN); + memset(pu8keybuf, 0, RX_MIC_KEY_MSG_LEN); /*|----------------------------------------------------------------------------| @@ -2842,7 +2842,7 @@ static int Handle_Key(void *drvHandler, tstrHostIFkeyAttr *pstrHostIFkeyAttr) goto _WPARxGtk_end_case_; } - WILC_memset(pu8keybuf, 0, RX_MIC_KEY_MSG_LEN); + memset(pu8keybuf, 0, RX_MIC_KEY_MSG_LEN); /*|----------------------------------------------------------------------------| @@ -3053,7 +3053,7 @@ static void Handle_Disconnect(void *drvHandler) host_int_set_power_mgmt((WILC_WFIDrvHandle)pstrWFIDrv, 0, 0); #endif - WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + memset(u8ConnectedSSID, 0, ETH_ALEN); s32Error = SendConfigPkt(SET_CFG, &strWID, 1, false, (u32)pstrWFIDrv); @@ -3063,7 +3063,7 @@ static void Handle_Disconnect(void *drvHandler) } else { tstrDisconnectNotifInfo strDisconnectNotifInfo; - WILC_memset(&strDisconnectNotifInfo, 0, sizeof(tstrDisconnectNotifInfo)); + memset(&strDisconnectNotifInfo, 0, sizeof(tstrDisconnectNotifInfo)); strDisconnectNotifInfo.u16reason = 0; strDisconnectNotifInfo.ie = NULL; @@ -3096,7 +3096,7 @@ static void Handle_Disconnect(void *drvHandler) pstrWFIDrv->enuHostIFstate = HOST_IF_IDLE; - WILC_memset(pstrWFIDrv->au8AssociatedBSSID, 0, ETH_ALEN); + memset(pstrWFIDrv->au8AssociatedBSSID, 0, ETH_ALEN); /* Deallocation */ @@ -3990,7 +3990,7 @@ static void ListenTimerCB(void *pvArg) WILC_TimerStop(&(pstrWFIDrv->hRemainOnChannel), NULL); /* prepare the Timer Callback message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_LISTEN_TIMER_FIRED; strHostIFmsg.drvHandler = pstrWFIDrv; strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan.u32ListenSessionID = pstrWFIDrv->strHostIfRemainOnChan.u32ListenSessionID; @@ -4329,7 +4329,7 @@ static int hostIFthread(void *pvArg) tstrHostIFmsg strHostIFmsg; tstrWILC_WFIDrv *pstrWFIDrv; - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); while (1) { WILC_MsgQueueRecv(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), &u32Ret, NULL); @@ -4551,7 +4551,7 @@ static void TimerCB_Scan(void *pvArg) tstrHostIFmsg strHostIFmsg; /* prepare the Timer Callback message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.drvHandler = pvArg; strHostIFmsg.u16MsgId = HOST_IF_MSG_SCAN_TIMER_FIRED; @@ -4564,7 +4564,7 @@ static void TimerCB_Connect(void *pvArg) tstrHostIFmsg strHostIFmsg; /* prepare the Timer Callback message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.drvHandler = pvArg; strHostIFmsg.u16MsgId = HOST_IF_MSG_CONNECT_TIMER_FIRED; @@ -4626,7 +4626,7 @@ s32 host_int_remove_wep_key(WILC_WFIDrvHandle hWFIDrv, u8 u8keyIdx) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); /* prepare the Remove Wep Key Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; @@ -4675,7 +4675,7 @@ s32 host_int_set_WEPDefaultKeyID(WILC_WFIDrvHandle hWFIDrv, u8 u8Index) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); /* prepare the Key Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; @@ -4732,7 +4732,7 @@ s32 host_int_add_wep_key_bss_sta(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8WepKey, /* prepare the Key Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; @@ -4798,7 +4798,7 @@ s32 host_int_add_wep_key_bss_ap(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8WepKey, /* prepare the Key Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); if (INFO) { for (i = 0; i < u8WepKeylen; i++) @@ -4877,7 +4877,7 @@ s32 host_int_add_ptk(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8Ptk, u8 u8PtkKeylen u8KeyLen += TX_MIC_KEY_LEN; /* prepare the Key Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; @@ -4972,7 +4972,7 @@ s32 host_int_add_rx_gtk(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8RxGtk, u8 u8GtkK if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); /* prepare the Key Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); if (pu8RxMic != NULL) @@ -5079,7 +5079,7 @@ s32 host_int_set_pmkid_info(WILC_WFIDrvHandle hWFIDrv, tstrHostIFpmkidAttr *pu8P WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); /* prepare the Key Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_KEY; strHostIFmsg.uniHostIFmsgBody.strHostIFkeyAttr.enuKeyType = PMKSA; @@ -5194,7 +5194,7 @@ s32 host_int_get_MacAddress(WILC_WFIDrvHandle hWFIDrv, u8 *pu8MacAddress) /* prepare the Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_MAC_ADDRESS; strHostIFmsg.uniHostIFmsgBody.strHostIfGetMacAddress.u8MacAddress = pu8MacAddress; @@ -5229,7 +5229,7 @@ s32 host_int_set_MacAddress(WILC_WFIDrvHandle hWFIDrv, u8 *pu8MacAddress) PRINT_D(GENERIC_DBG, "mac addr = %x:%x:%x\n", pu8MacAddress[0], pu8MacAddress[1], pu8MacAddress[2]); /* prepare setting mac address message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_SET_MAC_ADDRESS; WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIfSetMacAddress.u8MacAddress, pu8MacAddress, ETH_ALEN); strHostIFmsg.drvHandler = hWFIDrv; @@ -5448,7 +5448,7 @@ s32 host_int_set_join_req(WILC_WFIDrvHandle hWFIDrv, u8 *pu8bssid, * } */ /* prepare the Connect Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_CONNECT; @@ -5575,7 +5575,7 @@ s32 host_int_disconnect(WILC_WFIDrvHandle hWFIDrv, u16 u16ReasonCode) } /* prepare the Disconnect Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_DISCONNECT; strHostIFmsg.drvHandler = hWFIDrv; @@ -5765,7 +5765,7 @@ s32 host_int_set_mac_chnl_num(WILC_WFIDrvHandle hWFIDrv, u8 u8ChNum) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); /* prepare the set channel message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_SET_CHANNEL; strHostIFmsg.uniHostIFmsgBody.strHostIFSetChan.u8SetChan = u8ChNum; strHostIFmsg.drvHandler = hWFIDrv; @@ -5790,7 +5790,7 @@ s32 host_int_wait_msg_queue_idle(void) /* prepare the set driver handler message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_Q_IDLE; s32Error = WILC_MsgQueueSend(&gMsgQHostIF, &strHostIFmsg, sizeof(tstrHostIFmsg), NULL); if (s32Error) @@ -5816,7 +5816,7 @@ s32 host_int_set_wfi_drv_handler(u32 u32address) /* prepare the set driver handler message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_SET_WFIDRV_HANDLER; strHostIFmsg.uniHostIFmsgBody.strHostIfSetDrvHandler.u32Address = u32address; /* strHostIFmsg.drvHandler=hWFIDrv; */ @@ -5843,7 +5843,7 @@ s32 host_int_set_operation_mode(WILC_WFIDrvHandle hWFIDrv, u32 u32mode) /* prepare the set driver handler message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_SET_OPERATION_MODE; strHostIFmsg.uniHostIFmsgBody.strHostIfSetOperationMode.u32Mode = u32mode; strHostIFmsg.drvHandler = hWFIDrv; @@ -5886,7 +5886,7 @@ s32 host_int_get_host_chnl_num(WILC_WFIDrvHandle hWFIDrv, u8 *pu8ChNo) } /* prepare the Get Channel Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_CHNL; strHostIFmsg.drvHandler = hWFIDrv; @@ -5978,7 +5978,7 @@ s32 host_int_get_inactive_time(WILC_WFIDrvHandle hWFIDrv, const u8 *mac, u32 *pu WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); } - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIfStaInactiveT.mac, @@ -6070,7 +6070,7 @@ s32 host_int_get_rssi(WILC_WFIDrvHandle hWFIDrv, s8 *ps8Rssi) /* prepare the Get RSSI Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_RSSI; strHostIFmsg.drvHandler = hWFIDrv; @@ -6107,7 +6107,7 @@ s32 host_int_get_link_speed(WILC_WFIDrvHandle hWFIDrv, s8 *ps8lnkspd) /* prepare the Get LINKSPEED Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_LINKSPEED; strHostIFmsg.drvHandler = hWFIDrv; @@ -6141,7 +6141,7 @@ s32 host_int_get_statistics(WILC_WFIDrvHandle hWFIDrv, tstrStatistics *pstrStati /* prepare the Get RSSI Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_STATISTICS; strHostIFmsg.uniHostIFmsgBody.pUserData = (char *)pstrStatistics; @@ -6190,7 +6190,7 @@ s32 host_int_scan(WILC_WFIDrvHandle hWFIDrv, u8 u8ScanSource, /* prepare the Scan Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_SCAN; @@ -6259,7 +6259,7 @@ s32 hif_set_cfg(WILC_WFIDrvHandle hWFIDrv, tstrCfgParamVal *pstrCfgParamVal) if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); /* prepare the WiphyParams Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_CFG_PARAMS; strHostIFmsg.uniHostIFmsgBody.strHostIFCfgParamAttr.pstrCfgParamVal = *pstrCfgParamVal; strHostIFmsg.drvHandler = hWFIDrv; @@ -6437,7 +6437,7 @@ void GetPeriodicRSSI(void *pvArg) tstrHostIFmsg strHostIFmsg; /* prepare the Get RSSI Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_RSSI; strHostIFmsg.drvHandler = pstrWFIDrv; @@ -6497,7 +6497,7 @@ s32 host_int_init(WILC_WFIDrvHandle *phWFIDrv) PRINT_ER("Failed to allocate memory\n"); goto _fail_timer_2; } - WILC_memset(pstrWFIDrv, 0, sizeof(tstrWILC_WFIDrv)); + memset(pstrWFIDrv, 0, sizeof(tstrWILC_WFIDrv)); /*return driver handle to user*/ *phWFIDrv = (WILC_WFIDrvHandle)pstrWFIDrv; /*save into globl handle*/ @@ -6720,7 +6720,7 @@ s32 host_int_deinit(WILC_WFIDrvHandle hWFIDrv) gbScanWhileConnected = false; - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); if (clients_count == 1) { if (WILC_TimerDestroy(&g_hPeriodicRSSI, NULL)) { @@ -6791,7 +6791,7 @@ void NetworkInfoReceived(u8 *pu8Buffer, u32 u32Length) } /* prepare the Asynchronous Network Info message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_RCVD_NTWRK_INFO; strHostIFmsg.drvHandler = pstrWFIDrv; @@ -6852,7 +6852,7 @@ void GnrlAsyncInfoReceived(u8 *pu8Buffer, u32 u32Length) } /* prepare the General Asynchronous Info message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_RCVD_GNRL_ASYNC_INFO; @@ -6902,7 +6902,7 @@ void host_int_ScanCompleteReceived(u8 *pu8Buffer, u32 u32Length) /*if there is an ongoing scan request*/ if (pstrWFIDrv->strWILC_UsrScanReq.pfUserScanResult) { /* prepare theScan Done message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_RCVD_SCAN_COMPLETE; strHostIFmsg.drvHandler = pstrWFIDrv; @@ -6952,7 +6952,7 @@ s32 host_int_remain_on_channel(WILC_WFIDrvHandle hWFIDrv, u32 u32SessionID, u32 WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); /* prepare the remainonchan Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); /* prepare the WiphyParams Message */ strHostIFmsg.u16MsgId = HOST_IF_MSG_REMAIN_ON_CHAN; @@ -7002,7 +7002,7 @@ s32 host_int_ListenStateExpired(WILC_WFIDrvHandle hWFIDrv, u32 u32SessionID) WILC_TimerStop(&(pstrWFIDrv->hRemainOnChannel), NULL); /* prepare the timer fire Message */ - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); strHostIFmsg.u16MsgId = HOST_IF_MSG_LISTEN_TIMER_FIRED; strHostIFmsg.drvHandler = hWFIDrv; strHostIFmsg.uniHostIFmsgBody.strHostIfRemainOnChan.u32ListenSessionID = u32SessionID; @@ -7034,7 +7034,7 @@ s32 host_int_frame_register(WILC_WFIDrvHandle hWFIDrv, u16 u16FrameType, bool bR if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); /* prepare the WiphyParams Message */ strHostIFmsg.u16MsgId = HOST_IF_MSG_REGISTER_FRAME; @@ -7096,7 +7096,7 @@ s32 host_int_add_beacon(WILC_WFIDrvHandle hWFIDrv, u32 u32Interval, if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); PRINT_D(HOSTINF_DBG, "Setting adding beacon message queue params\n"); @@ -7194,7 +7194,7 @@ s32 host_int_add_station(WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam *pstrSt if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); PRINT_D(HOSTINF_DBG, "Setting adding station message queue params\n"); @@ -7243,7 +7243,7 @@ s32 host_int_del_station(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8MacAddr) if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); PRINT_D(HOSTINF_DBG, "Setting deleting station message queue params\n"); @@ -7255,7 +7255,7 @@ s32 host_int_del_station(WILC_WFIDrvHandle hWFIDrv, const u8 *pu8MacAddr) /*BugID_4795: Handling situation of deleting all stations*/ if (pu8MacAddr == NULL) - WILC_memset(pstrDelStationMsg->au8MacAddr, 255, ETH_ALEN); + memset(pstrDelStationMsg->au8MacAddr, 255, ETH_ALEN); else WILC_memcpy(pstrDelStationMsg->au8MacAddr, pu8MacAddr, ETH_ALEN); @@ -7291,7 +7291,7 @@ s32 host_int_del_allstation(WILC_WFIDrvHandle hWFIDrv, u8 pu8MacAddr[][ETH_ALEN] if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); PRINT_D(HOSTINF_DBG, "Setting deauthenticating station message queue params\n"); @@ -7351,7 +7351,7 @@ s32 host_int_edit_station(WILC_WFIDrvHandle hWFIDrv, tstrWILC_AddStaParam *pstrS PRINT_D(HOSTINF_DBG, "Setting editing station message queue params\n"); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); /* prepare the WiphyParams Message */ @@ -7392,7 +7392,7 @@ s32 host_int_set_power_mgmt(WILC_WFIDrvHandle hWFIDrv, bool bIsEnabled, u32 u32T PRINT_D(HOSTINF_DBG, "Setting Power management message queue params\n"); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); /* prepare the WiphyParams Message */ @@ -7426,7 +7426,7 @@ s32 host_int_setup_multicast_filter(WILC_WFIDrvHandle hWFIDrv, bool bIsEnabled, PRINT_D(HOSTINF_DBG, "Setting Multicast Filter params\n"); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); /* prepare the WiphyParams Message */ @@ -7479,7 +7479,7 @@ static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo) pNewJoinBssParam = WILC_MALLOC(sizeof(tstrJoinBssParam)); if (pNewJoinBssParam != NULL) { - WILC_memset(pNewJoinBssParam, 0, sizeof(tstrJoinBssParam)); + memset(pNewJoinBssParam, 0, sizeof(tstrJoinBssParam)); pNewJoinBssParam->dtim_period = ptstrNetworkInfo->u8DtimPeriod; pNewJoinBssParam->beacon_period = ptstrNetworkInfo->u16BeaconPeriod; pNewJoinBssParam->cap_info = ptstrNetworkInfo->u16CapInfo; @@ -7488,8 +7488,8 @@ static void *host_int_ParseJoinBssParam(tstrNetworkInfo *ptstrNetworkInfo) * PRINT_D(HOSTINF_DBG,"%c",pNewJoinBssParam->au8bssid[i]);*/ WILC_memcpy((u8 *)pNewJoinBssParam->ssid, ptstrNetworkInfo->au8ssid, ptstrNetworkInfo->u8SsidLen + 1); pNewJoinBssParam->ssidLen = ptstrNetworkInfo->u8SsidLen; - WILC_memset(pNewJoinBssParam->rsn_pcip_policy, 0xFF, 3); - WILC_memset(pNewJoinBssParam->rsn_auth_policy, 0xFF, 3); + memset(pNewJoinBssParam->rsn_pcip_policy, 0xFF, 3); + memset(pNewJoinBssParam->rsn_auth_policy, 0xFF, 3); /*for(i=0; issidLen;i++) * PRINT_D(HOSTINF_DBG,"%c",pNewJoinBssParam->ssid[i]);*/ @@ -7693,7 +7693,7 @@ static int host_int_addBASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char T if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); /* prepare the WiphyParams Message */ strHostIFmsg.u16MsgId = HOST_IF_MSG_ADD_BA_SESSION; @@ -7726,7 +7726,7 @@ s32 host_int_delBASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char TID) if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); /* prepare the WiphyParams Message */ strHostIFmsg.u16MsgId = HOST_IF_MSG_DEL_BA_SESSION; @@ -7759,7 +7759,7 @@ s32 host_int_del_All_Rx_BASession(WILC_WFIDrvHandle hWFIDrv, char *pBSSID, char if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); /* prepare the WiphyParams Message */ strHostIFmsg.u16MsgId = HOST_IF_MSG_DEL_ALL_RX_BA_SESSIONS; @@ -7802,7 +7802,7 @@ s32 host_int_setup_ipaddress(WILC_WFIDrvHandle hWFIDrv, u8 *u16ipadd, u8 idx) if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); /* prepare the WiphyParams Message */ strHostIFmsg.u16MsgId = HOST_IF_MSG_SET_IPADDRESS; @@ -7841,7 +7841,7 @@ s32 host_int_get_ipaddress(WILC_WFIDrvHandle hWFIDrv, u8 *u16ipadd, u8 idx) if (pstrWFIDrv == NULL) WILC_ERRORREPORT(s32Error, WILC_INVALID_ARGUMENT); - WILC_memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); + memset(&strHostIFmsg, 0, sizeof(tstrHostIFmsg)); /* prepare the WiphyParams Message */ strHostIFmsg.u16MsgId = HOST_IF_MSG_GET_IPADDRESS; diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 2c0789e499d4..e38aad049ac7 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -574,7 +574,7 @@ static void CfgConnectResult(tenuConnDisconnEvent enuConnDisconnEvent, * = SUCCESSFUL_STATUSCODE, while mac status is MAC_DISCONNECTED (which means something wrong happened) */ u16ConnectStatus = WLAN_STATUS_UNSPECIFIED_FAILURE; linux_wlan_set_bssid(priv->dev, NullBssid); - WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + memset(u8ConnectedSSID, 0, ETH_ALEN); /*BugID_5457*/ /*Invalidate u8WLANChannel value on wlan0 disconnect*/ @@ -640,9 +640,9 @@ static void CfgConnectResult(tenuConnDisconnEvent enuConnDisconnEvent, u8P2Plocalrandom = 0x01; u8P2Precvrandom = 0x00; bWilc_ie = false; - WILC_memset(priv->au8AssociatedBss, 0, ETH_ALEN); + memset(priv->au8AssociatedBss, 0, ETH_ALEN); linux_wlan_set_bssid(priv->dev, NullBssid); - WILC_memset(u8ConnectedSSID, 0, ETH_ALEN); + memset(u8ConnectedSSID, 0, ETH_ALEN); /*BugID_5457*/ /*Invalidate u8WLANChannel value on wlan0 disconnect*/ @@ -887,8 +887,8 @@ static int WILC_WFI_CfgConnect(struct wiphy *wiphy, struct net_device *dev, } priv->WILC_WFI_wep_default = 0; - WILC_memset(priv->WILC_WFI_wep_key, 0, sizeof(priv->WILC_WFI_wep_key)); - WILC_memset(priv->WILC_WFI_wep_key_len, 0, sizeof(priv->WILC_WFI_wep_key_len)); + memset(priv->WILC_WFI_wep_key, 0, sizeof(priv->WILC_WFI_wep_key)); + memset(priv->WILC_WFI_wep_key_len, 0, sizeof(priv->WILC_WFI_wep_key_len)); PRINT_INFO(CFG80211_DBG, "sme->crypto.wpa_versions=%x\n", sme->crypto.wpa_versions); PRINT_INFO(CFG80211_DBG, "sme->crypto.cipher_group=%x\n", sme->crypto.cipher_group); @@ -1490,7 +1490,7 @@ static int WILC_WFI_del_key(struct wiphy *wiphy, struct net_device *netdev, } if (key_index >= 0 && key_index <= 3) { - WILC_memset(priv->WILC_WFI_wep_key[key_index], 0, priv->WILC_WFI_wep_key_len[key_index]); + memset(priv->WILC_WFI_wep_key[key_index], 0, priv->WILC_WFI_wep_key_len[key_index]); priv->WILC_WFI_wep_key_len[key_index] = 0; PRINT_D(CFG80211_DBG, "Removing WEP key with index = %d\n", key_index); @@ -1950,7 +1950,7 @@ static int WILC_WFI_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, ETH_ALEN)) { /*If bssid is found, reset the values*/ PRINT_D(CFG80211_DBG, "Reseting PMKID values\n"); - WILC_memset(&priv->pmkid_list.pmkidlist[i], 0, sizeof(tstrHostIFpmkid)); + memset(&priv->pmkid_list.pmkidlist[i], 0, sizeof(tstrHostIFpmkid)); flag = PMKID_FOUND; break; } @@ -1989,7 +1989,7 @@ static int WILC_WFI_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) PRINT_D(CFG80211_DBG, "Flushing PMKID key values\n"); /*Get cashed Pmkids and set all with zeros*/ - WILC_memset(&priv->pmkid_list, 0, sizeof(tstrHostIFpmkidAttr)); + memset(&priv->pmkid_list, 0, sizeof(tstrHostIFpmkidAttr)); return 0; } -- cgit v1.3-6-gb490 From 70b801cb539ae812662927bb327668aa3c7c21ab Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Fri, 7 Aug 2015 09:02:02 +0900 Subject: staging: wilc1000: remove WILC_memset function Remove WILC_memset function because it is changed to memset. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_strutils.c | 9 --------- drivers/staging/wilc1000/wilc_strutils.h | 12 ------------ 2 files changed, 21 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_strutils.c b/drivers/staging/wilc1000/wilc_strutils.c index e0145953ceef..c15375eaef81 100644 --- a/drivers/staging/wilc1000/wilc_strutils.c +++ b/drivers/staging/wilc1000/wilc_strutils.c @@ -25,15 +25,6 @@ void WILC_memcpy_INTERNAL(void *pvTarget, const void *pvSource, u32 u32Count) memcpy(pvTarget, pvSource, u32Count); } -/*! - * @author syounan - * @date 18 Aug 2010 - * @version 1.0 - */ -void *WILC_memset(void *pvTarget, u8 u8SetValue, u32 u32Count) -{ - return memset(pvTarget, u8SetValue, u32Count); -} /*! * @author syounan diff --git a/drivers/staging/wilc1000/wilc_strutils.h b/drivers/staging/wilc1000/wilc_strutils.h index d1445575a25e..acc0ca4a447d 100644 --- a/drivers/staging/wilc1000/wilc_strutils.h +++ b/drivers/staging/wilc1000/wilc_strutils.h @@ -71,18 +71,6 @@ static WILC_ErrNo WILC_memcpy(void *pvTarget, const void *pvSource, u32 u32Count } } -/*! - * @brief Sets the contents of a memory buffer with the given value - * @param[in] pvTarget the target buffer which contsnts will be set - * @param[in] u8SetValue the value to be used - * @param[in] u32Count the size of the memory buffer - * @return value of pvTarget - * @note this function repeats the functionality of standard memset - * @author syounan - * @date 18 Aug 2010 - * @version 1.0 - */ -void *WILC_memset(void *pvTarget, u8 u8SetValue, u32 u32Count); /*! * @brief copies the contents of source string into the target string -- cgit v1.3-6-gb490 From 1a646e7e9e4227d4eeb9ccbbc2d976b3b256a1e6 Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Fri, 7 Aug 2015 09:02:03 +0900 Subject: staging: wilc1000: use memcmp instead of WILC_memcmp Use memcmp instead of WILC_memcmp. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 20 +++++++------- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 32 +++++++++++------------ 2 files changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 0c06ac27b4a7..bc06d56ebaf5 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -801,7 +801,7 @@ s32 Handle_get_IPAddress(void *drvHandler, u8 *pu8IPAddr, u8 idx) /*get the value by searching the local copy*/ WILC_FREE(strWID.ps8WidVal); - if (WILC_memcmp(gs8GetIP[idx], gs8SetIP[idx], IP_ALEN) != 0) + if (memcmp(gs8GetIP[idx], gs8SetIP[idx], IP_ALEN) != 0) host_int_setup_ipaddress((WILC_WFIDrvHandle)pstrWFIDrv, gs8SetIP[idx], idx); if (s32Error != WILC_SUCCESS) { @@ -1527,7 +1527,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon for (i = 0; i < pstrWFIDrv->u32SurveyResultsCount; i++) { - if (WILC_memcmp(pstrWFIDrv->astrSurveyResults[i].SSID, + if (memcmp(pstrWFIDrv->astrSurveyResults[i].SSID, pstrHostIFconnectAttr->pu8ssid, pstrHostIFconnectAttr->ssidLen) == 0) { PRINT_INFO(HOSTINF_DBG, "Network with required SSID is found %s\n", pstrHostIFconnectAttr->pu8ssid); @@ -1540,7 +1540,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon /* BSSID is also passed from the user, so decision of matching * should consider also this passed BSSID */ - if (WILC_memcmp(pstrWFIDrv->astrSurveyResults[i].BSSID, + if (memcmp(pstrWFIDrv->astrSurveyResults[i].BSSID, pstrHostIFconnectAttr->pu8bssid, 6) == 0) { PRINT_INFO(HOSTINF_DBG, "BSSID is passed from the user and matched\n"); @@ -1648,7 +1648,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon /* if we try to connect to an already connected AP then discard the request */ - if (WILC_memcmp(pstrHostIFconnectAttr->pu8bssid, u8ConnectedSSID, ETH_ALEN) == 0) { + if (memcmp(pstrHostIFconnectAttr->pu8bssid, u8ConnectedSSID, ETH_ALEN) == 0) { s32Error = WILC_SUCCESS; PRINT_ER("Trying to connect to an already connected AP, Discard connect request\n"); @@ -1720,7 +1720,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon u32WidsCount++; /*BugID_5137*/ - if (WILC_memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) { + if (memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) { gu32FlushedInfoElemAsocSize = pstrWFIDrv->strWILC_UsrConnReq.ConnReqIEsLen; gu8FlushedInfoElemAsoc = WILC_MALLOC(gu32FlushedInfoElemAsocSize); @@ -1735,7 +1735,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon u32WidsCount++; /*BugID_5137*/ - if (WILC_memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) + if (memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) gu8Flushed11iMode = pstrWFIDrv->strWILC_UsrConnReq.u8security; PRINT_INFO(HOSTINF_DBG, "Encrypt Mode = %x\n", pstrWFIDrv->strWILC_UsrConnReq.u8security); @@ -1748,7 +1748,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon u32WidsCount++; /*BugID_5137*/ - if (WILC_memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) + if (memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) gu8FlushedAuthType = (u8)pstrWFIDrv->strWILC_UsrConnReq.tenuAuth_type; PRINT_INFO(HOSTINF_DBG, "Authentication Type = %x\n", pstrWFIDrv->strWILC_UsrConnReq.tenuAuth_type); @@ -1803,7 +1803,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon strWIDList[u32WidsCount].ps8WidVal = WILC_MALLOC(strWIDList[u32WidsCount].s32ValueSize); /*BugID_5137*/ - if (WILC_memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) { + if (memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) { gu32FlushedJoinReqSize = strWIDList[u32WidsCount].s32ValueSize; gu8FlushedJoinReq = WILC_MALLOC(gu32FlushedJoinReqSize); } @@ -1940,7 +1940,7 @@ static s32 Handle_Connect(void *drvHandler, tstrHostIFconnectAttr *pstrHostIFcon /* ////////////////////// */ /*BugID_5137*/ - if (WILC_memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) { + if (memcmp("DIRECT-", pstrHostIFconnectAttr->pu8ssid, 7)) { memcpy(gu8FlushedJoinReq, pu8CurrByte, gu32FlushedJoinReqSize); gu8FlushedJoinReqDrvHandler = (u32)pstrWFIDrv; } @@ -2246,7 +2246,7 @@ static s32 Handle_RcvdNtwrkInfo(void *drvHandler, tstrRcvdNetworkInfo *pstrRcvdN if ((pstrWFIDrv->strWILC_UsrScanReq.astrFoundNetworkInfo[i].au8bssid != NULL) && (pstrNetworkInfo->au8bssid != NULL)) { - if (WILC_memcmp(pstrWFIDrv->strWILC_UsrScanReq.astrFoundNetworkInfo[i].au8bssid, + if (memcmp(pstrWFIDrv->strWILC_UsrScanReq.astrFoundNetworkInfo[i].au8bssid, pstrNetworkInfo->au8bssid, 6) == 0) { if (pstrNetworkInfo->s8rssi <= pstrWFIDrv->strWILC_UsrScanReq.astrFoundNetworkInfo[i].s8rssi) { /*we have already found this network with better rssi, so keep the old cached one and don't diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index e38aad049ac7..060288a3460d 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -202,7 +202,7 @@ void refresh_scan(void *pUserVoid, uint8_t all, bool bDirectScan) channel = ieee80211_get_channel(wiphy, s32Freq); rssi = get_rssi_avg(pstrNetworkInfo); - if (WILC_memcmp("DIRECT-", pstrNetworkInfo->au8ssid, 7) || bDirectScan) { + if (memcmp("DIRECT-", pstrNetworkInfo->au8ssid, 7) || bDirectScan) { bss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, pstrNetworkInfo->au8bssid, pstrNetworkInfo->u64Tsf, pstrNetworkInfo->u16CapInfo, pstrNetworkInfo->u16BeaconPeriod, (const u8 *)pstrNetworkInfo->pu8IEs, (size_t)pstrNetworkInfo->u16IEsLen, (((s32)rssi) * 100), GFP_KERNEL); @@ -283,7 +283,7 @@ int8_t is_network_in_shadow(tstrNetworkInfo *pstrNetworkInfo, void *pUserVoid) } else { /* Linear search for now */ for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { - if (WILC_memcmp(astrLastScannedNtwrksShadow[i].au8bssid, + if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid, pstrNetworkInfo->au8bssid, 6) == 0) { state = i; break; @@ -414,7 +414,7 @@ static void CfgScanResult(tenuScanEvent enuScanEvent, tstrNetworkInfo *pstrNetwo /*P2P peers are sent to WPA supplicant and added to shadow table*/ - if (!(WILC_memcmp("DIRECT-", pstrNetworkInfo->au8ssid, 7))) { + if (!(memcmp("DIRECT-", pstrNetworkInfo->au8ssid, 7))) { bss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN, pstrNetworkInfo->au8bssid, pstrNetworkInfo->u64Tsf, pstrNetworkInfo->u16CapInfo, pstrNetworkInfo->u16BeaconPeriod, (const u8 *)pstrNetworkInfo->pu8IEs, (size_t)pstrNetworkInfo->u16IEsLen, (((s32)pstrNetworkInfo->s8rssi) * 100), GFP_KERNEL); @@ -429,7 +429,7 @@ static void CfgScanResult(tenuScanEvent enuScanEvent, tstrNetworkInfo *pstrNetwo u32 i; /* So this network is discovered before, we'll just update its RSSI */ for (i = 0; i < priv->u32RcvdChCount; i++) { - if (WILC_memcmp(astrLastScannedNtwrksShadow[i].au8bssid, pstrNetworkInfo->au8bssid, 6) == 0) { + if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid, pstrNetworkInfo->au8bssid, 6) == 0) { PRINT_D(CFG80211_DBG, "Update RSSI of %s \n", astrLastScannedNtwrksShadow[i].au8ssid); astrLastScannedNtwrksShadow[i].s8rssi = pstrNetworkInfo->s8rssi; @@ -503,7 +503,7 @@ int WILC_WFI_Set_PMKSA(u8 *bssid, struct WILC_WFI_priv *priv) for (i = 0; i < priv->pmkid_list.numpmkid; i++) { - if (!WILC_memcmp(bssid, priv->pmkid_list.pmkidlist[i].bssid, + if (!memcmp(bssid, priv->pmkid_list.pmkidlist[i].bssid, ETH_ALEN)) { PRINT_D(CFG80211_DBG, "PMKID successful comparison"); @@ -599,7 +599,7 @@ static void CfgConnectResult(tenuConnDisconnEvent enuConnDisconnEvent, * Linux kernel warning generated at the nl80211 layer */ for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { - if (WILC_memcmp(astrLastScannedNtwrksShadow[i].au8bssid, + if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid, pstrConnectInfo->au8bssid, ETH_ALEN) == 0) { unsigned long now = jiffies; @@ -845,7 +845,7 @@ static int WILC_WFI_CfgConnect(struct wiphy *wiphy, struct net_device *dev, for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { if ((sme->ssid_len == astrLastScannedNtwrksShadow[i].u8SsidLen) && - WILC_memcmp(astrLastScannedNtwrksShadow[i].au8ssid, + memcmp(astrLastScannedNtwrksShadow[i].au8ssid, sme->ssid, sme->ssid_len) == 0) { PRINT_INFO(CFG80211_DBG, "Network with required SSID is found %s\n", sme->ssid); @@ -857,7 +857,7 @@ static int WILC_WFI_CfgConnect(struct wiphy *wiphy, struct net_device *dev, } else { /* BSSID is also passed from the user, so decision of matching * should consider also this passed BSSID */ - if (WILC_memcmp(astrLastScannedNtwrksShadow[i].au8bssid, + if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid, sme->bssid, ETH_ALEN) == 0) { PRINT_INFO(CFG80211_DBG, "BSSID is passed from the user and matched\n"); @@ -1170,7 +1170,7 @@ static int WILC_WFI_add_key(struct wiphy *wiphy, struct net_device *netdev, u8 k break; } #endif - if (WILC_memcmp(params->key, priv->WILC_WFI_wep_key[key_index], params->key_len)) { + if (memcmp(params->key, priv->WILC_WFI_wep_key[key_index], params->key_len)) { priv->WILC_WFI_wep_default = key_index; priv->WILC_WFI_wep_key_len[key_index] = params->key_len; WILC_memcpy(priv->WILC_WFI_wep_key[key_index], params->key, params->key_len); @@ -1896,7 +1896,7 @@ static int WILC_WFI_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, for (i = 0; i < priv->pmkid_list.numpmkid; i++) { - if (!WILC_memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid, + if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid, ETH_ALEN)) { /*If bssid already exists and pmkid value needs to reset*/ flag = PMKID_FOUND; @@ -1946,7 +1946,7 @@ static int WILC_WFI_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, PRINT_D(CFG80211_DBG, "Deleting PMKSA keys\n"); for (i = 0; i < priv->pmkid_list.numpmkid; i++) { - if (!WILC_memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid, + if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid, ETH_ALEN)) { /*If bssid is found, reset the values*/ PRINT_D(CFG80211_DBG, "Reseting PMKID values\n"); @@ -2257,11 +2257,11 @@ void WILC_WFI_p2p_rx (struct net_device *dev, uint8_t *buff, uint32_t size) case PUBLIC_ACT_VENDORSPEC: /*Now we have a public action vendor specific action frame, check if its a p2p public action frame * based on the standard its should have the p2p_oui attribute with the following values 50 6f 9A 09*/ - if (!WILC_memcmp(u8P2P_oui, &buff[ACTION_SUBTYPE_ID + 1], 4)) { + if (!memcmp(u8P2P_oui, &buff[ACTION_SUBTYPE_ID + 1], 4)) { if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP)) { if (!bWilc_ie) { for (i = P2P_PUB_ACTION_SUBTYPE; i < size; i++) { - if (!WILC_memcmp(u8P2P_vendorspec, &buff[i], 6)) { + if (!memcmp(u8P2P_vendorspec, &buff[i], 6)) { u8P2Precvrandom = buff[i + 6]; bWilc_ie = true; PRINT_D(GENERIC_DBG, "WILC Vendor specific IE:%02x\n", u8P2Precvrandom); @@ -2274,7 +2274,7 @@ void WILC_WFI_p2p_rx (struct net_device *dev, uint8_t *buff, uint32_t size) if ((buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP || buff[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_REQ || buff[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_RSP)) { for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < size; i++) { - if (buff[i] == P2PELEM_ATTR_ID && !(WILC_memcmp(u8P2P_oui, &buff[i + 2], 4))) { + if (buff[i] == P2PELEM_ATTR_ID && !(memcmp(u8P2P_oui, &buff[i + 2], 4))) { WILC_WFI_CfgParseRxAction(&buff[i + 6], size - (i + 6)); break; } @@ -2570,7 +2570,7 @@ int WILC_WFI_mgmt_tx(struct wiphy *wiphy, { /*Now we have a public action vendor specific action frame, check if its a p2p public action frame * based on the standard its should have the p2p_oui attribute with the following values 50 6f 9A 09*/ - if (!WILC_memcmp(u8P2P_oui, &buf[ACTION_SUBTYPE_ID + 1], 4)) { + if (!memcmp(u8P2P_oui, &buf[ACTION_SUBTYPE_ID + 1], 4)) { /*For the connection of two WILC's connection generate a rand number to determine who will be a GO*/ if ((buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == GO_NEG_RSP)) { if (u8P2Plocalrandom == 1 && u8P2Precvrandom < u8P2Plocalrandom) { @@ -2587,7 +2587,7 @@ int WILC_WFI_mgmt_tx(struct wiphy *wiphy, /*Search for the p2p information information element , after the Public action subtype theres a byte for teh dialog token, skip that*/ for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < len; i++) { - if (buf[i] == P2PELEM_ATTR_ID && !(WILC_memcmp(u8P2P_oui, &buf[i + 2], 4))) { + if (buf[i] == P2PELEM_ATTR_ID && !(memcmp(u8P2P_oui, &buf[i + 2], 4))) { if (buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_REQ || buf[P2P_PUB_ACTION_SUBTYPE] == P2P_INV_RSP) WILC_WFI_CfgParseTxAction(&mgmt_tx->buff[i + 6], len - (i + 6), true, nic->iftype); -- cgit v1.3-6-gb490 From f6356a9617cbaebf1159fe50f2e05d57e7e4242e Mon Sep 17 00:00:00 2001 From: Chaehyun Lim Date: Fri, 7 Aug 2015 09:02:04 +0900 Subject: staging: wilc1000: remove WILC_memcmp function Remove WILC_memcmp function because it is changed to memcmp. Signed-off-by: Chaehyun Lim Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_strutils.c | 9 --------- drivers/staging/wilc1000/wilc_strutils.h | 13 ------------- 2 files changed, 22 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_strutils.c b/drivers/staging/wilc1000/wilc_strutils.c index c15375eaef81..3600706ed231 100644 --- a/drivers/staging/wilc1000/wilc_strutils.c +++ b/drivers/staging/wilc1000/wilc_strutils.c @@ -4,15 +4,6 @@ #include "wilc_strutils.h" -/*! - * @author syounan - * @date 18 Aug 2010 - * @version 1.0 - */ -s32 WILC_memcmp(const void *pvArg1, const void *pvArg2, u32 u32Count) -{ - return memcmp(pvArg1, pvArg2, u32Count); -} /*! diff --git a/drivers/staging/wilc1000/wilc_strutils.h b/drivers/staging/wilc1000/wilc_strutils.h index acc0ca4a447d..9e3c5d9c5001 100644 --- a/drivers/staging/wilc1000/wilc_strutils.h +++ b/drivers/staging/wilc1000/wilc_strutils.h @@ -14,19 +14,6 @@ #include #include "wilc_errorsupport.h" -/*! - * @brief Compares two memory buffers - * @param[in] pvArg1 pointer to the first memory location - * @param[in] pvArg2 pointer to the second memory location - * @param[in] u32Count the size of the memory buffers - * @return 0 if the 2 buffers are equal, 1 if pvArg1 is bigger than pvArg2, - * -1 if pvArg1 smaller than pvArg2 - * @note this function repeats the functionality of standard memcmp - * @author syounan - * @date 18 Aug 2010 - * @version 1.0 - */ -s32 WILC_memcmp(const void *pvArg1, const void *pvArg2, u32 u32Count); /*! * @brief Internal implementation for memory copy -- cgit v1.3-6-gb490 From 1695cd29b24eca077fa8ae467f1184009ceb9d05 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 16:06:28 +0530 Subject: staging: rtl8188eu: remove unused argument The function rtw_os_recv_resource_alloc() only uses the argument struct recv_frame *. So remove the other unused argument. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_recv.c | 2 +- drivers/staging/rtl8188eu/include/recv_osdep.h | 3 +-- drivers/staging/rtl8188eu/os_dep/recv_linux.c | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index 8501eb898824..cce07463efb6 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -89,7 +89,7 @@ int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) list_add_tail(&(precvframe->list), &(precvpriv->free_recv_queue.queue)); - res = rtw_os_recv_resource_alloc(padapter, precvframe); + res = rtw_os_recv_resource_alloc(precvframe); precvframe->len = 0; diff --git a/drivers/staging/rtl8188eu/include/recv_osdep.h b/drivers/staging/rtl8188eu/include/recv_osdep.h index 0809963ce6aa..0f3200567758 100644 --- a/drivers/staging/rtl8188eu/include/recv_osdep.h +++ b/drivers/staging/rtl8188eu/include/recv_osdep.h @@ -38,8 +38,7 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup); int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); void rtw_free_recv_priv(struct recv_priv *precvpriv); -int rtw_os_recv_resource_alloc(struct adapter *adapt, - struct recv_frame *recvfr); +int rtw_os_recv_resource_alloc(struct recv_frame *recvfr); int rtw_os_recvbuf_resource_alloc(struct adapter *adapt, struct recv_buf *buf); diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c index 05701328dce4..4849e6b87a21 100644 --- a/drivers/staging/rtl8188eu/os_dep/recv_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c @@ -29,8 +29,7 @@ #include /* alloc os related resource in struct recv_frame */ -int rtw_os_recv_resource_alloc(struct adapter *padapter, - struct recv_frame *precvframe) +int rtw_os_recv_resource_alloc(struct recv_frame *precvframe) { precvframe->pkt_newalloc = NULL; precvframe->pkt = NULL; -- cgit v1.3-6-gb490 From 0b47649c78c09afa43e93e902027d211cd1c6991 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 16:06:29 +0530 Subject: staging: rtl8188eu: make function void The return value of rtw_os_recv_resource_alloc() is never checked, so make it as void. Moreover as of now the function can not fail. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_recv.c | 2 +- drivers/staging/rtl8188eu/include/recv_osdep.h | 2 +- drivers/staging/rtl8188eu/os_dep/recv_linux.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index cce07463efb6..b347a8190274 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -89,7 +89,7 @@ int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) list_add_tail(&(precvframe->list), &(precvpriv->free_recv_queue.queue)); - res = rtw_os_recv_resource_alloc(precvframe); + rtw_os_recv_resource_alloc(precvframe); precvframe->len = 0; diff --git a/drivers/staging/rtl8188eu/include/recv_osdep.h b/drivers/staging/rtl8188eu/include/recv_osdep.h index 0f3200567758..fdeb603b6cc1 100644 --- a/drivers/staging/rtl8188eu/include/recv_osdep.h +++ b/drivers/staging/rtl8188eu/include/recv_osdep.h @@ -38,7 +38,7 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup); int rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter); void rtw_free_recv_priv(struct recv_priv *precvpriv); -int rtw_os_recv_resource_alloc(struct recv_frame *recvfr); +void rtw_os_recv_resource_alloc(struct recv_frame *recvfr); int rtw_os_recvbuf_resource_alloc(struct adapter *adapt, struct recv_buf *buf); diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c index 4849e6b87a21..49d88455dbb4 100644 --- a/drivers/staging/rtl8188eu/os_dep/recv_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c @@ -29,11 +29,10 @@ #include /* alloc os related resource in struct recv_frame */ -int rtw_os_recv_resource_alloc(struct recv_frame *precvframe) +void rtw_os_recv_resource_alloc(struct recv_frame *precvframe) { precvframe->pkt_newalloc = NULL; precvframe->pkt = NULL; - return _SUCCESS; } /* alloc os related resource in struct recv_buf */ -- cgit v1.3-6-gb490 From 469d3807e7f99f950348af5f031a580f13863263 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 16:06:30 +0530 Subject: staging: rtl8188eu: rearrange code Re-arrange the code to directly return success or failure, thus removing the variable used in the function. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/recv_linux.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c index 49d88455dbb4..3350bf35fb28 100644 --- a/drivers/staging/rtl8188eu/os_dep/recv_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c @@ -39,14 +39,12 @@ void rtw_os_recv_resource_alloc(struct recv_frame *precvframe) int rtw_os_recvbuf_resource_alloc(struct adapter *padapter, struct recv_buf *precvbuf) { - int res = _SUCCESS; - - precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); - if (precvbuf->purb == NULL) - res = _FAIL; precvbuf->pskb = NULL; precvbuf->reuse = false; - return res; + precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL); + if (!precvbuf->purb) + return _FAIL; + return _SUCCESS; } void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup) -- cgit v1.3-6-gb490 From ea31f616b630723bc220ff4daa123774532f96ea Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 16:06:31 +0530 Subject: staging: rtl8188eu: remove unused define _RECV_OSDEP_C_ was only defined here but never checked anywhere. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/recv_linux.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/recv_linux.c b/drivers/staging/rtl8188eu/os_dep/recv_linux.c index 3350bf35fb28..3ebb8b206e46 100644 --- a/drivers/staging/rtl8188eu/os_dep/recv_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/recv_linux.c @@ -17,8 +17,6 @@ * * ******************************************************************************/ -#define _RECV_OSDEP_C_ - #include #include -- cgit v1.3-6-gb490 From fbd0968708c5e6a4811e62b103fa3d8c165f65c3 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 16:06:32 +0530 Subject: staging: rtl8188eu: remove exit label An exit label which does nothing except return, is not worth having. So remove it. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_recv.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index b347a8190274..c011dc85436d 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -74,10 +74,8 @@ int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) precvpriv->pallocated_frame_buf = vzalloc(NR_RECVFRAME * sizeof(struct recv_frame) + RXFRAME_ALIGN_SZ); - if (precvpriv->pallocated_frame_buf == NULL) { - res = _FAIL; - goto exit; - } + if (!precvpriv->pallocated_frame_buf) + return _FAIL; precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ); @@ -107,8 +105,6 @@ int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) precvpriv->signal_stat_sampling_interval = 1000; /* ms */ rtw_set_signal_stat_timer(precvpriv); -exit: - return res; } -- cgit v1.3-6-gb490 From a45515f3838328334cfac3d1fcddca9f67fb9172 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 16:06:33 +0530 Subject: staging: rtl8188eu: remove unused function The function rtw_init_recvframe() was not being used. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_recv.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index c011dc85436d..0bb5cccb967b 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -166,14 +166,6 @@ struct recv_frame *rtw_alloc_recvframe(struct __queue *pfree_recv_queue) return precvframe; } -void rtw_init_recvframe(struct recv_frame *precvframe, struct recv_priv *precvpriv) -{ - /* Perry: This can be removed */ - INIT_LIST_HEAD(&precvframe->list); - - precvframe->len = 0; -} - int rtw_free_recvframe(struct recv_frame *precvframe, struct __queue *pfree_recv_queue) { -- cgit v1.3-6-gb490 From b17c858def70b03a1652dcb74e061e8077f72c42 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 7 Aug 2015 16:06:34 +0530 Subject: staging: rtl8188eu: remove multiple blank line Multiple blank lines is against the kernel coding style and checkpatch complains for that. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_recv.c | 26 -------------------------- 1 file changed, 26 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index 0bb5cccb967b..44eeb03213e6 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -113,7 +113,6 @@ void _rtw_free_recv_priv(struct recv_priv *precvpriv) { struct adapter *padapter = precvpriv->adapter; - rtw_free_uc_swdec_pending_queue(padapter); if (precvpriv->pallocated_frame_buf) { @@ -149,7 +148,6 @@ struct recv_frame *_rtw_alloc_recvframe(struct __queue *pfree_recv_queue) } } - return (struct recv_frame *)hdr; } @@ -196,7 +194,6 @@ int rtw_free_recvframe(struct recv_frame *precvframe, spin_unlock_bh(&pfree_recv_queue->lock); - return _SUCCESS; } @@ -205,7 +202,6 @@ int _rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue) struct adapter *padapter = precvframe->adapter; struct recv_priv *precvpriv = &padapter->recvpriv; - list_del_init(&(precvframe->list)); list_add_tail(&(precvframe->list), get_list_head(queue)); @@ -214,7 +210,6 @@ int _rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue) precvpriv->free_recvframe_cnt++; } - return _SUCCESS; } @@ -409,7 +404,6 @@ static int recvframe_chkmic(struct adapter *adapter, exit: - return res; } @@ -471,7 +465,6 @@ static struct recv_frame *decryptor(struct adapter *padapter, return_packet = NULL; } - return return_packet; } @@ -490,7 +483,6 @@ static struct recv_frame *portctrl(struct adapter *adapter, struct rx_pkt_attrib *pattrib; __be16 be_tmp; - pstapriv = &adapter->stapriv; auth_alg = adapter->securitypriv.dot11AuthAlgrthm; @@ -549,7 +541,6 @@ static struct recv_frame *portctrl(struct adapter *adapter, prtnframe = precv_frame; } - return prtnframe; } @@ -561,7 +552,6 @@ static int recv_decache(struct recv_frame *precv_frame, u8 bretry, u16 seq_ctrl = ((precv_frame->attrib.seq_num&0xffff) << 4) | (precv_frame->attrib.frag_num & 0xf); - if (tid > 15) { RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("recv_decache, (tid>15)! seq_ctrl=0x%x, tid=0x%x\n", seq_ctrl, tid)); @@ -578,7 +568,6 @@ static int recv_decache(struct recv_frame *precv_frame, u8 bretry, prxcache->tid_rxseq[tid] = seq_ctrl; - return _SUCCESS; } @@ -715,7 +704,6 @@ int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame, u8 *sta_addr = NULL; int bmcast = IS_MCAST(pattrib->dst); - if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) || (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) { /* filter packets that SA is myself or multicast or broadcast */ @@ -803,7 +791,6 @@ static int ap2sta_data_frame( u8 *myhwaddr = myid(&adapter->eeprompriv); int bmcast = IS_MCAST(pattrib->dst); - if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) && (check_fwstate(pmlmepriv, _FW_LINKED) == true || check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) { @@ -895,7 +882,6 @@ static int ap2sta_data_frame( exit: - return ret; } @@ -910,7 +896,6 @@ static int sta2ap_data_frame(struct adapter *adapter, unsigned char *mybssid = get_bssid(pmlmepriv); int ret = _SUCCESS; - if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { /* For AP mode, RA = BSSID, TX = STA(SRC_ADDR), A3 = DST_ADDR */ if (memcmp(pattrib->bssid, mybssid, ETH_ALEN)) { @@ -955,7 +940,6 @@ static int sta2ap_data_frame(struct adapter *adapter, exit: - return ret; } @@ -1137,7 +1121,6 @@ static int validate_recv_data_frame(struct adapter *adapter, struct security_priv *psecuritypriv = &adapter->securitypriv; int ret = _SUCCESS; - bretry = GetRetry(ptr); pda = get_da(ptr); psa = get_sa(ptr); @@ -1241,7 +1224,6 @@ static int validate_recv_data_frame(struct adapter *adapter, exit: - return ret; } @@ -1261,7 +1243,6 @@ static int validate_recv_frame(struct adapter *adapter, u8 ver = (unsigned char)(*ptr)&0x3; struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; - if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { int ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, rtw_get_oper_ch(adapter)); if (ch_set_idx >= 0) @@ -1350,7 +1331,6 @@ static int validate_recv_frame(struct adapter *adapter, exit: - return retval; } @@ -1433,7 +1413,6 @@ static struct recv_frame *recvframe_defrag(struct adapter *adapter, struct recv_frame *prframe, *pnextrframe; struct __queue *pfree_recv_queue; - curfragnum = 0; pfree_recv_queue = &adapter->recvpriv.free_recv_queue; @@ -1498,7 +1477,6 @@ static struct recv_frame *recvframe_defrag(struct adapter *adapter, RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("Performance defrag!!!!!\n")); - return prframe; } @@ -1516,7 +1494,6 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter, struct recv_frame *prtnframe = NULL; struct __queue *pfree_recv_queue, *pdefrag_q; - pstapriv = &padapter->stapriv; pfhdr = precv_frame; @@ -1600,7 +1577,6 @@ struct recv_frame *recvframe_chk_defrag(struct adapter *padapter, } } - return prtnframe; } @@ -2104,7 +2080,6 @@ s32 rtw_recv_entry(struct recv_frame *precvframe) struct recv_priv *precvpriv; s32 ret = _SUCCESS; - padapter = precvframe->adapter; precvpriv = &padapter->recvpriv; @@ -2117,7 +2092,6 @@ s32 rtw_recv_entry(struct recv_frame *precvframe) precvpriv->rx_pkts++; - return ret; _recv_entry_drop: -- cgit v1.3-6-gb490 From ddb2c42b677eb2883e532f0928e445fc205d0019 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 6 Aug 2015 12:29:37 +0800 Subject: mtd: brcmnand: Fix misuse of IS_ENABLED While IS_ENABLED() is perfectly fine for CONFIG_* symbols, it is not for other symbols such as __BIG_ENDIAN that is provided directly by the compiler. Switch to use CONFIG_CPU_BIG_ENDIAN instead of __BIG_ENDIAN. Fixes: 27c5b17cd1b1 ("mtd: nand: add NAND driver "library" for Broadcom STB NAND controller") Signed-off-by: Axel Lin Signed-off-by: Brian Norris --- drivers/mtd/nand/brcmnand/brcmnand.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/brcmnand/brcmnand.h b/drivers/mtd/nand/brcmnand/brcmnand.h index a20c73630b7b..169f99e38a26 100644 --- a/drivers/mtd/nand/brcmnand/brcmnand.h +++ b/drivers/mtd/nand/brcmnand/brcmnand.h @@ -50,7 +50,7 @@ static inline u32 brcmnand_readl(void __iomem *addr) * Other architectures (e.g., ARM) either do not support big endian, or * else leave I/O in little endian mode. */ - if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN)) + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) return __raw_readl(addr); else return readl_relaxed(addr); @@ -59,7 +59,7 @@ static inline u32 brcmnand_readl(void __iomem *addr) static inline void brcmnand_writel(u32 val, void __iomem *addr) { /* See brcmnand_readl() comments */ - if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN)) + if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) __raw_writel(val, addr); else writel_relaxed(val, addr); -- cgit v1.3-6-gb490 From 28c1f1628ee4b163e615eefe1b6463e3d229a873 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 4 Aug 2015 21:36:12 +0200 Subject: PM / AVS: rockchip-io: depend on CONFIG_POWER_AVS The rockchip io-domain driver currently only depends on ARCH_ROCKCHIP itself. This makes it possible to select the power-domain driver, but not the POWER_AVS class and results in the iodomain-driver not getting build in this case. So add the additional dependency, which also results in the driver config option now being placed nicely into the AVS submenu. Fixes: 662a958638bd ("PM / AVS: rockchip-io: add driver handling Rockchip io domains") Signed-off-by: Heiko Stuebner Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/power/avs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/avs/Kconfig b/drivers/power/avs/Kconfig index 7f3d389bd601..a67eeace6a89 100644 --- a/drivers/power/avs/Kconfig +++ b/drivers/power/avs/Kconfig @@ -13,7 +13,7 @@ menuconfig POWER_AVS config ROCKCHIP_IODOMAIN tristate "Rockchip IO domain support" - depends on ARCH_ROCKCHIP && OF + depends on POWER_AVS && ARCH_ROCKCHIP && OF help Say y here to enable support io domains on Rockchip SoCs. It is necessary for the io domain setting of the SoC to match the -- cgit v1.3-6-gb490 From 3fc147e9156f6c176e5543c59d31182252f14933 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 4 Aug 2015 21:37:01 +0200 Subject: PM / AVS: rockchip-io: add io selectors and supplies for rk3368 This adds the necessary data for handling io voltage domains on the rk3368. As interesting tidbit, the rk3368 contains two separate iodomain areas. One in the regular General Register Files (GRF) and one in PMUGRF in the pmu power domain. Signed-off-by: Heiko Stuebner Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- .../bindings/power/rockchip-io-domain.txt | 14 +++++ drivers/power/avs/rockchip-io-domain.c | 59 ++++++++++++++++++++++ 2 files changed, 73 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/power/rockchip-io-domain.txt b/Documentation/devicetree/bindings/power/rockchip-io-domain.txt index 8b70db103ca7..b8627e763dba 100644 --- a/Documentation/devicetree/bindings/power/rockchip-io-domain.txt +++ b/Documentation/devicetree/bindings/power/rockchip-io-domain.txt @@ -33,6 +33,8 @@ Required properties: - compatible: should be one of: - "rockchip,rk3188-io-voltage-domain" for rk3188 - "rockchip,rk3288-io-voltage-domain" for rk3288 + - "rockchip,rk3368-io-voltage-domain" for rk3368 + - "rockchip,rk3368-pmu-io-voltage-domain" for rk3368 pmu-domains - rockchip,grf: phandle to the syscon managing the "general register files" @@ -64,6 +66,18 @@ Possible supplies for rk3288: - sdcard-supply: The supply connected to SDMMC0_VDD. - wifi-supply: The supply connected to APIO3_VDD. Also known as SDIO0. +Possible supplies for rk3368: +- audio-supply: The supply connected to APIO3_VDD. +- dvp-supply: The supply connected to DVPIO_VDD. +- flash0-supply: The supply connected to FLASH0_VDD. Typically for eMMC +- gpio30-supply: The supply connected to APIO1_VDD. +- gpio1830 The supply connected to APIO4_VDD. +- sdcard-supply: The supply connected to SDMMC0_VDD. +- wifi-supply: The supply connected to APIO2_VDD. Also known as SDIO0. + +Possible supplies for rk3368 pmu-domains: +- pmu-supply: The supply connected to PMUIO_VDD. +- vop-supply: The supply connected to LCDC_VDD. Example: diff --git a/drivers/power/avs/rockchip-io-domain.c b/drivers/power/avs/rockchip-io-domain.c index 3ae35d0590d2..2e300028f0f7 100644 --- a/drivers/power/avs/rockchip-io-domain.c +++ b/drivers/power/avs/rockchip-io-domain.c @@ -43,6 +43,10 @@ #define RK3288_SOC_CON2_FLASH0 BIT(7) #define RK3288_SOC_FLASH_SUPPLY_NUM 2 +#define RK3368_SOC_CON15 0x43c +#define RK3368_SOC_CON15_FLASH0 BIT(14) +#define RK3368_SOC_FLASH_SUPPLY_NUM 2 + struct rockchip_iodomain; /** @@ -158,6 +162,25 @@ static void rk3288_iodomain_init(struct rockchip_iodomain *iod) dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); } +static void rk3368_iodomain_init(struct rockchip_iodomain *iod) +{ + int ret; + u32 val; + + /* if no flash supply we should leave things alone */ + if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg) + return; + + /* + * set flash0 iodomain to also use this framework + * instead of a special gpio. + */ + val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16); + ret = regmap_write(iod->grf, RK3368_SOC_CON15, val); + if (ret < 0) + dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); +} + /* * On the rk3188 the io-domains are handled by a shared register with the * lower 8 bits being still being continuing drive-strength settings. @@ -201,6 +224,34 @@ static const struct rockchip_iodomain_soc_data soc_data_rk3288 = { .init = rk3288_iodomain_init, }; +static const struct rockchip_iodomain_soc_data soc_data_rk3368 = { + .grf_offset = 0x900, + .supply_names = { + NULL, /* reserved */ + "dvp", /* DVPIO_VDD */ + "flash0", /* FLASH0_VDD (emmc) */ + "wifi", /* APIO2_VDD (sdio0) */ + NULL, + "audio", /* APIO3_VDD */ + "sdcard", /* SDMMC0_VDD (sdmmc) */ + "gpio30", /* APIO1_VDD */ + "gpio1830", /* APIO4_VDD (gpujtag) */ + }, + .init = rk3368_iodomain_init, +}; + +static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = { + .grf_offset = 0x100, + .supply_names = { + NULL, + NULL, + NULL, + NULL, + "pmu", /*PMU IO domain*/ + "vop", /*LCDC IO domain*/ + }, +}; + static const struct of_device_id rockchip_iodomain_match[] = { { .compatible = "rockchip,rk3188-io-voltage-domain", @@ -210,6 +261,14 @@ static const struct of_device_id rockchip_iodomain_match[] = { .compatible = "rockchip,rk3288-io-voltage-domain", .data = (void *)&soc_data_rk3288 }, + { + .compatible = "rockchip,rk3368-io-voltage-domain", + .data = (void *)&soc_data_rk3368 + }, + { + .compatible = "rockchip,rk3368-pmu-io-voltage-domain", + .data = (void *)&soc_data_rk3368_pmu + }, { /* sentinel */ }, }; -- cgit v1.3-6-gb490 From 21c36d35711d24a7689b7fb9606ce78f3b4c3d3b Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 7 Aug 2015 13:59:16 +0200 Subject: cpufreq-dt: make scaling_boost_freqs sysfs attr available when boost is enabled Make scaling_boost_freqs sysfs attribute is available when cpufreq-dt driver is used and boost support is enabled. Suggested-by: Viresh Kumar Acked-by: Viresh Kumar Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-dt.c | 9 ++++++++- include/linux/cpufreq.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index b9259abd25d4..c3583cdfadbd 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -36,6 +36,12 @@ struct private_data { unsigned int voltage_tolerance; /* in percentage */ }; +static struct freq_attr *cpufreq_dt_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, /* Extra space for boost-attr if required */ + NULL, +}; + static int set_target(struct cpufreq_policy *policy, unsigned int index) { struct dev_pm_opp *opp; @@ -336,6 +342,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) ret = cpufreq_enable_boost_support(); if (ret) goto out_free_cpufreq_table; + cpufreq_dt_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs; } policy->cpuinfo.transition_latency = transition_latency; @@ -411,7 +418,7 @@ static struct cpufreq_driver dt_cpufreq_driver = { .exit = cpufreq_exit, .ready = cpufreq_ready, .name = "cpufreq-dt", - .attr = cpufreq_generic_attr, + .attr = cpufreq_dt_attr, }; static int dt_cpufreq_probe(struct platform_device *pdev) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 95f018649abf..657542d3e23b 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -609,6 +609,7 @@ struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu); /* the following are really really optional */ extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs; +extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs; extern struct freq_attr *cpufreq_generic_attr[]; int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table); -- cgit v1.3-6-gb490 From cf184dc2dd33847f4b211b01d8c7ec0526e6c5e4 Mon Sep 17 00:00:00 2001 From: Jaiprakash Singh Date: Wed, 20 May 2015 21:17:11 -0500 Subject: fsl_ifc: Change IO accessor based on endianness IFC IO accressor are set at run time based on IFC IP registers endianness.IFC node in DTS file contains information about endianness. Signed-off-by: Jaiprakash Singh Signed-off-by: Scott Wood Acked-by: Brian Norris --- .../bindings/memory-controllers/fsl/ifc.txt | 3 + drivers/memory/fsl_ifc.c | 43 ++-- drivers/mtd/nand/fsl_ifc_nand.c | 258 +++++++++++---------- include/linux/fsl_ifc.h | 50 ++++ 4 files changed, 213 insertions(+), 141 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt b/Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt index d5e370450ac0..89427b018ba7 100644 --- a/Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt +++ b/Documentation/devicetree/bindings/memory-controllers/fsl/ifc.txt @@ -18,6 +18,8 @@ Properties: interrupt (NAND_EVTER_STAT). If there is only one, that interrupt reports both types of event. +- little-endian : If this property is absent, the big-endian mode will + be in use as default for registers. - ranges : Each range corresponds to a single chipselect, and covers the entire access window as configured. @@ -34,6 +36,7 @@ Example: #size-cells = <1>; reg = <0x0 0xffe1e000 0 0x2000>; interrupts = <16 2 19 2>; + little-endian; /* NOR, NAND Flashes and CPLD on board */ ranges = <0x0 0x0 0x0 0xee000000 0x02000000 diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c index 410c39749872..e87459f6d686 100644 --- a/drivers/memory/fsl_ifc.c +++ b/drivers/memory/fsl_ifc.c @@ -62,7 +62,7 @@ int fsl_ifc_find(phys_addr_t addr_base) return -ENODEV; for (i = 0; i < fsl_ifc_ctrl_dev->banks; i++) { - u32 cspr = in_be32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr); + u32 cspr = ifc_in32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr); if (cspr & CSPR_V && (cspr & CSPR_BA) == convert_ifc_address(addr_base)) return i; @@ -79,16 +79,16 @@ static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl) /* * Clear all the common status and event registers */ - if (in_be32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER) - out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER); + if (ifc_in32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER) + ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat); /* enable all error and events */ - out_be32(&ifc->cm_evter_en, IFC_CM_EVTER_EN_CSEREN); + ifc_out32(IFC_CM_EVTER_EN_CSEREN, &ifc->cm_evter_en); /* enable all error and event interrupts */ - out_be32(&ifc->cm_evter_intr_en, IFC_CM_EVTER_INTR_EN_CSERIREN); - out_be32(&ifc->cm_erattr0, 0x0); - out_be32(&ifc->cm_erattr1, 0x0); + ifc_out32(IFC_CM_EVTER_INTR_EN_CSERIREN, &ifc->cm_evter_intr_en); + ifc_out32(0x0, &ifc->cm_erattr0); + ifc_out32(0x0, &ifc->cm_erattr1); return 0; } @@ -127,9 +127,9 @@ static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl) spin_lock_irqsave(&nand_irq_lock, flags); - stat = in_be32(&ifc->ifc_nand.nand_evter_stat); + stat = ifc_in32(&ifc->ifc_nand.nand_evter_stat); if (stat) { - out_be32(&ifc->ifc_nand.nand_evter_stat, stat); + ifc_out32(stat, &ifc->ifc_nand.nand_evter_stat); ctrl->nand_stat = stat; wake_up(&ctrl->nand_wait); } @@ -161,16 +161,16 @@ static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data) irqreturn_t ret = IRQ_NONE; /* read for chip select error */ - cs_err = in_be32(&ifc->cm_evter_stat); + cs_err = ifc_in32(&ifc->cm_evter_stat); if (cs_err) { dev_err(ctrl->dev, "transaction sent to IFC is not mapped to" "any memory bank 0x%08X\n", cs_err); /* clear the chip select error */ - out_be32(&ifc->cm_evter_stat, IFC_CM_EVTER_STAT_CSER); + ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat); /* read error attribute registers print the error information */ - status = in_be32(&ifc->cm_erattr0); - err_addr = in_be32(&ifc->cm_erattr1); + status = ifc_in32(&ifc->cm_erattr0); + err_addr = ifc_in32(&ifc->cm_erattr1); if (status & IFC_CM_ERATTR0_ERTYP_READ) dev_err(ctrl->dev, "Read transaction error" @@ -231,6 +231,23 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev) goto err; } + version = ifc_in32(&fsl_ifc_ctrl_dev->regs->ifc_rev) & + FSL_IFC_VERSION_MASK; + banks = (version == FSL_IFC_VERSION_1_0_0) ? 4 : 8; + dev_info(&dev->dev, "IFC version %d.%d, %d banks\n", + version >> 24, (version >> 16) & 0xf, banks); + + fsl_ifc_ctrl_dev->version = version; + fsl_ifc_ctrl_dev->banks = banks; + + if (of_property_read_bool(dev->dev.of_node, "little-endian")) { + fsl_ifc_ctrl_dev->little_endian = true; + dev_dbg(&dev->dev, "IFC REGISTERS are LITTLE endian\n"); + } else { + fsl_ifc_ctrl_dev->little_endian = false; + dev_dbg(&dev->dev, "IFC REGISTERS are BIG endian\n"); + } + version = ioread32be(&fsl_ifc_ctrl_dev->regs->ifc_rev) & FSL_IFC_VERSION_MASK; banks = (version == FSL_IFC_VERSION_1_0_0) ? 4 : 8; diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 51394e59901b..a4e27e891153 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -238,8 +238,8 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) ifc_nand_ctrl->page = page_addr; /* Program ROW0/COL0 */ - iowrite32be(page_addr, &ifc->ifc_nand.row0); - iowrite32be((oob ? IFC_NAND_COL_MS : 0) | column, &ifc->ifc_nand.col0); + ifc_out32(page_addr, &ifc->ifc_nand.row0); + ifc_out32((oob ? IFC_NAND_COL_MS : 0) | column, &ifc->ifc_nand.col0); buf_num = page_addr & priv->bufnum_mask; @@ -301,19 +301,19 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) int i; /* set the chip select for NAND Transaction */ - iowrite32be(priv->bank << IFC_NAND_CSEL_SHIFT, - &ifc->ifc_nand.nand_csel); + ifc_out32(priv->bank << IFC_NAND_CSEL_SHIFT, + &ifc->ifc_nand.nand_csel); dev_vdbg(priv->dev, "%s: fir0=%08x fcr0=%08x\n", __func__, - ioread32be(&ifc->ifc_nand.nand_fir0), - ioread32be(&ifc->ifc_nand.nand_fcr0)); + ifc_in32(&ifc->ifc_nand.nand_fir0), + ifc_in32(&ifc->ifc_nand.nand_fcr0)); ctrl->nand_stat = 0; /* start read/write seq */ - iowrite32be(IFC_NAND_SEQ_STRT_FIR_STRT, &ifc->ifc_nand.nandseq_strt); + ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT, &ifc->ifc_nand.nandseq_strt); /* wait for command complete flag or timeout */ wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, @@ -336,7 +336,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) int sector_end = sector + chip->ecc.steps - 1; for (i = sector / 4; i <= sector_end / 4; i++) - eccstat[i] = ioread32be(&ifc->ifc_nand.nand_eccstat[i]); + eccstat[i] = ifc_in32(&ifc->ifc_nand.nand_eccstat[i]); for (i = sector; i <= sector_end; i++) { errors = check_read_ecc(mtd, ctrl, eccstat, i); @@ -376,33 +376,33 @@ static void fsl_ifc_do_read(struct nand_chip *chip, /* Program FIR/IFC_NAND_FCR0 for Small/Large page */ if (mtd->writesize > 512) { - iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT), - &ifc->ifc_nand.nand_fir0); - iowrite32be(0x0, &ifc->ifc_nand.nand_fir1); - - iowrite32be((NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT), - &ifc->ifc_nand.nand_fcr0); + ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | + (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) | + (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT), + &ifc->ifc_nand.nand_fir0); + ifc_out32(0x0, &ifc->ifc_nand.nand_fir1); + + ifc_out32((NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | + (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT), + &ifc->ifc_nand.nand_fcr0); } else { - iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT), - &ifc->ifc_nand.nand_fir0); - iowrite32be(0x0, &ifc->ifc_nand.nand_fir1); + ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | + (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT), + &ifc->ifc_nand.nand_fir0); + ifc_out32(0x0, &ifc->ifc_nand.nand_fir1); if (oob) - iowrite32be(NAND_CMD_READOOB << - IFC_NAND_FCR0_CMD0_SHIFT, - &ifc->ifc_nand.nand_fcr0); + ifc_out32(NAND_CMD_READOOB << + IFC_NAND_FCR0_CMD0_SHIFT, + &ifc->ifc_nand.nand_fcr0); else - iowrite32be(NAND_CMD_READ0 << - IFC_NAND_FCR0_CMD0_SHIFT, - &ifc->ifc_nand.nand_fcr0); + ifc_out32(NAND_CMD_READ0 << + IFC_NAND_FCR0_CMD0_SHIFT, + &ifc->ifc_nand.nand_fcr0); } } @@ -422,7 +422,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, switch (command) { /* READ0 read the entire buffer to use hardware ECC. */ case NAND_CMD_READ0: - iowrite32be(0, &ifc->ifc_nand.nand_fbcr); + ifc_out32(0, &ifc->ifc_nand.nand_fbcr); set_addr(mtd, 0, page_addr, 0); ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize; @@ -437,7 +437,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* READOOB reads only the OOB because no ECC is performed. */ case NAND_CMD_READOOB: - iowrite32be(mtd->oobsize - column, &ifc->ifc_nand.nand_fbcr); + ifc_out32(mtd->oobsize - column, &ifc->ifc_nand.nand_fbcr); set_addr(mtd, column, page_addr, 1); ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize; @@ -453,19 +453,19 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, if (command == NAND_CMD_PARAM) timing = IFC_FIR_OP_RBCD; - iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | - (timing << IFC_NAND_FIR0_OP2_SHIFT), - &ifc->ifc_nand.nand_fir0); - iowrite32be(command << IFC_NAND_FCR0_CMD0_SHIFT, - &ifc->ifc_nand.nand_fcr0); - iowrite32be(column, &ifc->ifc_nand.row3); + ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | + (timing << IFC_NAND_FIR0_OP2_SHIFT), + &ifc->ifc_nand.nand_fir0); + ifc_out32(command << IFC_NAND_FCR0_CMD0_SHIFT, + &ifc->ifc_nand.nand_fcr0); + ifc_out32(column, &ifc->ifc_nand.row3); /* * although currently it's 8 bytes for READID, we always read * the maximum 256 bytes(for PARAM) */ - iowrite32be(256, &ifc->ifc_nand.nand_fbcr); + ifc_out32(256, &ifc->ifc_nand.nand_fbcr); ifc_nand_ctrl->read_bytes = 256; set_addr(mtd, 0, 0, 0); @@ -480,16 +480,16 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* ERASE2 uses the block and page address from ERASE1 */ case NAND_CMD_ERASE2: - iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT), - &ifc->ifc_nand.nand_fir0); + ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT), + &ifc->ifc_nand.nand_fir0); - iowrite32be((NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT), - &ifc->ifc_nand.nand_fcr0); + ifc_out32((NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) | + (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT), + &ifc->ifc_nand.nand_fcr0); - iowrite32be(0, &ifc->ifc_nand.nand_fbcr); + ifc_out32(0, &ifc->ifc_nand.nand_fbcr); ifc_nand_ctrl->read_bytes = 0; fsl_ifc_run_command(mtd); return; @@ -506,19 +506,18 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, (NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) | (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT); - iowrite32be( - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT), - &ifc->ifc_nand.nand_fir0); - iowrite32be( - (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) | - (IFC_FIR_OP_RDSTAT << - IFC_NAND_FIR1_OP6_SHIFT) | - (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT), - &ifc->ifc_nand.nand_fir1); + ifc_out32( + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | + (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) | + (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT), + &ifc->ifc_nand.nand_fir0); + ifc_out32( + (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) | + (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR1_OP6_SHIFT) | + (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT), + &ifc->ifc_nand.nand_fir1); } else { nand_fcr0 = ((NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT) | @@ -527,20 +526,19 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, (NAND_CMD_STATUS << IFC_NAND_FCR0_CMD3_SHIFT)); - iowrite32be( + ifc_out32( (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) | (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) | (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) | (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT), &ifc->ifc_nand.nand_fir0); - iowrite32be( - (IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) | - (IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) | - (IFC_FIR_OP_RDSTAT << - IFC_NAND_FIR1_OP7_SHIFT) | - (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT), - &ifc->ifc_nand.nand_fir1); + ifc_out32( + (IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) | + (IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) | + (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR1_OP7_SHIFT) | + (IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT), + &ifc->ifc_nand.nand_fir1); if (column >= mtd->writesize) nand_fcr0 |= @@ -555,7 +553,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, column -= mtd->writesize; ifc_nand_ctrl->oob = 1; } - iowrite32be(nand_fcr0, &ifc->ifc_nand.nand_fcr0); + ifc_out32(nand_fcr0, &ifc->ifc_nand.nand_fcr0); set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob); return; } @@ -563,24 +561,26 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ case NAND_CMD_PAGEPROG: { if (ifc_nand_ctrl->oob) { - iowrite32be(ifc_nand_ctrl->index - - ifc_nand_ctrl->column, - &ifc->ifc_nand.nand_fbcr); + ifc_out32(ifc_nand_ctrl->index - + ifc_nand_ctrl->column, + &ifc->ifc_nand.nand_fbcr); } else { - iowrite32be(0, &ifc->ifc_nand.nand_fbcr); + ifc_out32(0, &ifc->ifc_nand.nand_fbcr); } fsl_ifc_run_command(mtd); return; } - case NAND_CMD_STATUS: - iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT), - &ifc->ifc_nand.nand_fir0); - iowrite32be(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT, - &ifc->ifc_nand.nand_fcr0); - iowrite32be(1, &ifc->ifc_nand.nand_fbcr); + case NAND_CMD_STATUS: { + void __iomem *addr; + + ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT), + &ifc->ifc_nand.nand_fir0); + ifc_out32(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT, + &ifc->ifc_nand.nand_fcr0); + ifc_out32(1, &ifc->ifc_nand.nand_fbcr); set_addr(mtd, 0, 0, 0); ifc_nand_ctrl->read_bytes = 1; @@ -590,17 +590,19 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, * The chip always seems to report that it is * write-protected, even when it is not. */ + addr = ifc_nand_ctrl->addr; if (chip->options & NAND_BUSWIDTH_16) - setbits16(ifc_nand_ctrl->addr, NAND_STATUS_WP); + ifc_out16(ifc_in16(addr) | (NAND_STATUS_WP), addr); else - setbits8(ifc_nand_ctrl->addr, NAND_STATUS_WP); + ifc_out8(ifc_in8(addr) | (NAND_STATUS_WP), addr); return; + } case NAND_CMD_RESET: - iowrite32be(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT, - &ifc->ifc_nand.nand_fir0); - iowrite32be(NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT, - &ifc->ifc_nand.nand_fcr0); + ifc_out32(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT, + &ifc->ifc_nand.nand_fir0); + ifc_out32(NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT, + &ifc->ifc_nand.nand_fcr0); fsl_ifc_run_command(mtd); return; @@ -658,7 +660,7 @@ static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd) */ if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) { offset = ifc_nand_ctrl->index++; - return in_8(ifc_nand_ctrl->addr + offset); + return ifc_in8(ifc_nand_ctrl->addr + offset); } dev_err(priv->dev, "%s: beyond end of buffer\n", __func__); @@ -680,7 +682,7 @@ static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd) * next byte. */ if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) { - data = in_be16(ifc_nand_ctrl->addr + ifc_nand_ctrl->index); + data = ifc_in16(ifc_nand_ctrl->addr + ifc_nand_ctrl->index); ifc_nand_ctrl->index += 2; return (uint8_t) data; } @@ -726,18 +728,18 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) u32 nand_fsr; /* Use READ_STATUS command, but wait for the device to be ready */ - iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT), - &ifc->ifc_nand.nand_fir0); - iowrite32be(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT, - &ifc->ifc_nand.nand_fcr0); - iowrite32be(1, &ifc->ifc_nand.nand_fbcr); + ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT), + &ifc->ifc_nand.nand_fir0); + ifc_out32(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT, + &ifc->ifc_nand.nand_fcr0); + ifc_out32(1, &ifc->ifc_nand.nand_fbcr); set_addr(mtd, 0, 0, 0); ifc_nand_ctrl->read_bytes = 1; fsl_ifc_run_command(mtd); - nand_fsr = ioread32be(&ifc->ifc_nand.nand_fsr); + nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr); /* * The chip always seems to report that it is @@ -829,34 +831,34 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) uint32_t cs = priv->bank; /* Save CSOR and CSOR_ext */ - csor = ioread32be(&ifc->csor_cs[cs].csor); - csor_ext = ioread32be(&ifc->csor_cs[cs].csor_ext); + csor = ifc_in32(&ifc->csor_cs[cs].csor); + csor_ext = ifc_in32(&ifc->csor_cs[cs].csor_ext); /* chage PageSize 8K and SpareSize 1K*/ csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000; - iowrite32be(csor_8k, &ifc->csor_cs[cs].csor); - iowrite32be(0x0000400, &ifc->csor_cs[cs].csor_ext); + ifc_out32(csor_8k, &ifc->csor_cs[cs].csor); + ifc_out32(0x0000400, &ifc->csor_cs[cs].csor_ext); /* READID */ - iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT), - &ifc->ifc_nand.nand_fir0); - iowrite32be(NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT, - &ifc->ifc_nand.nand_fcr0); - iowrite32be(0x0, &ifc->ifc_nand.row3); + ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | + (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT), + &ifc->ifc_nand.nand_fir0); + ifc_out32(NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT, + &ifc->ifc_nand.nand_fcr0); + ifc_out32(0x0, &ifc->ifc_nand.row3); - iowrite32be(0x0, &ifc->ifc_nand.nand_fbcr); + ifc_out32(0x0, &ifc->ifc_nand.nand_fbcr); /* Program ROW0/COL0 */ - iowrite32be(0x0, &ifc->ifc_nand.row0); - iowrite32be(0x0, &ifc->ifc_nand.col0); + ifc_out32(0x0, &ifc->ifc_nand.row0); + ifc_out32(0x0, &ifc->ifc_nand.col0); /* set the chip select for NAND Transaction */ - iowrite32be(cs << IFC_NAND_CSEL_SHIFT, &ifc->ifc_nand.nand_csel); + ifc_out32(cs << IFC_NAND_CSEL_SHIFT, &ifc->ifc_nand.nand_csel); /* start read seq */ - iowrite32be(IFC_NAND_SEQ_STRT_FIR_STRT, &ifc->ifc_nand.nandseq_strt); + ifc_out32(IFC_NAND_SEQ_STRT_FIR_STRT, &ifc->ifc_nand.nandseq_strt); /* wait for command complete flag or timeout */ wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, @@ -866,8 +868,8 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n"); /* Restore CSOR and CSOR_ext */ - iowrite32be(csor, &ifc->csor_cs[cs].csor); - iowrite32be(csor_ext, &ifc->csor_cs[cs].csor_ext); + ifc_out32(csor, &ifc->csor_cs[cs].csor); + ifc_out32(csor_ext, &ifc->csor_cs[cs].csor_ext); } static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) @@ -884,7 +886,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) /* fill in nand_chip structure */ /* set up function call table */ - if ((ioread32be(&ifc->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16) + if ((ifc_in32(&ifc->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16) chip->read_byte = fsl_ifc_read_byte16; else chip->read_byte = fsl_ifc_read_byte; @@ -898,13 +900,13 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) chip->bbt_td = &bbt_main_descr; chip->bbt_md = &bbt_mirror_descr; - iowrite32be(0x0, &ifc->ifc_nand.ncfgr); + ifc_out32(0x0, &ifc->ifc_nand.ncfgr); /* set up nand options */ chip->bbt_options = NAND_BBT_USE_FLASH; chip->options = NAND_NO_SUBPAGE_WRITE; - if (ioread32be(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) { + if (ifc_in32(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) { chip->read_byte = fsl_ifc_read_byte16; chip->options |= NAND_BUSWIDTH_16; } else { @@ -917,7 +919,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) chip->ecc.read_page = fsl_ifc_read_page; chip->ecc.write_page = fsl_ifc_write_page; - csor = ioread32be(&ifc->csor_cs[priv->bank].csor); + csor = ifc_in32(&ifc->csor_cs[priv->bank].csor); /* Hardware generates ECC per 512 Bytes */ chip->ecc.size = 512; @@ -1006,7 +1008,7 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv) static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank, phys_addr_t addr) { - u32 cspr = ioread32be(&ifc->cspr_cs[bank].cspr); + u32 cspr = ifc_in32(&ifc->cspr_cs[bank].cspr); if (!(cspr & CSPR_V)) return 0; @@ -1092,16 +1094,16 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) dev_set_drvdata(priv->dev, priv); - iowrite32be(IFC_NAND_EVTER_EN_OPC_EN | - IFC_NAND_EVTER_EN_FTOER_EN | - IFC_NAND_EVTER_EN_WPER_EN, - &ifc->ifc_nand.nand_evter_en); + ifc_out32(IFC_NAND_EVTER_EN_OPC_EN | + IFC_NAND_EVTER_EN_FTOER_EN | + IFC_NAND_EVTER_EN_WPER_EN, + &ifc->ifc_nand.nand_evter_en); /* enable NAND Machine Interrupts */ - iowrite32be(IFC_NAND_EVTER_INTR_OPCIR_EN | - IFC_NAND_EVTER_INTR_FTOERIR_EN | - IFC_NAND_EVTER_INTR_WPERIR_EN, - &ifc->ifc_nand.nand_evter_intr_en); + ifc_out32(IFC_NAND_EVTER_INTR_OPCIR_EN | + IFC_NAND_EVTER_INTR_FTOERIR_EN | + IFC_NAND_EVTER_INTR_WPERIR_EN, + &ifc->ifc_nand.nand_evter_intr_en); priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start); if (!priv->mtd.name) { ret = -ENOMEM; diff --git a/include/linux/fsl_ifc.h b/include/linux/fsl_ifc.h index bf0321eabbda..0023088b253b 100644 --- a/include/linux/fsl_ifc.h +++ b/include/linux/fsl_ifc.h @@ -841,9 +841,59 @@ struct fsl_ifc_ctrl { u32 nand_stat; wait_queue_head_t nand_wait; + bool little_endian; }; extern struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev; +static inline u32 ifc_in32(void __iomem *addr) +{ + u32 val; + + if (fsl_ifc_ctrl_dev->little_endian) + val = ioread32(addr); + else + val = ioread32be(addr); + + return val; +} + +static inline u16 ifc_in16(void __iomem *addr) +{ + u16 val; + + if (fsl_ifc_ctrl_dev->little_endian) + val = ioread16(addr); + else + val = ioread16be(addr); + + return val; +} + +static inline u8 ifc_in8(void __iomem *addr) +{ + return ioread8(addr); +} + +static inline void ifc_out32(u32 val, void __iomem *addr) +{ + if (fsl_ifc_ctrl_dev->little_endian) + iowrite32(val, addr); + else + iowrite32be(val, addr); +} + +static inline void ifc_out16(u16 val, void __iomem *addr) +{ + if (fsl_ifc_ctrl_dev->little_endian) + iowrite16(val, addr); + else + iowrite16be(val, addr); +} + +static inline void ifc_out8(u8 val, void __iomem *addr) +{ + iowrite8(val, addr); +} #endif /* __ASM_FSL_IFC_H */ -- cgit v1.3-6-gb490 From 18422bb3c1d89b510bb7c590c716dd6ad8e1a1e4 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Wed, 29 Jul 2015 23:39:36 +0200 Subject: iio:accel:stk8312: improve error handling Improve error handling in the following ways: - set return value on error condition to an appropriate error code - return error code immediately in case of an error (slightly changes code structure) - pass up real error code - add missing error handling - return 0 when error have been caught already - put device back in active mode after error occurs Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 60 ++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 8280a37e0068..82ad283b8c60 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -146,8 +146,10 @@ static int stk8312_otp_init(struct stk8312_data *data) count--; } while (!(ret & 0x80) && count > 0); - if (count == 0) + if (count == 0) { + ret = -ETIMEDOUT; goto exit_err; + } ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPDATA); if (ret == 0) @@ -161,7 +163,7 @@ static int stk8312_otp_init(struct stk8312_data *data) goto exit_err; msleep(150); - return ret; + return 0; exit_err: dev_err(&client->dev, "failed to initialize sensor\n"); @@ -205,8 +207,11 @@ static int stk8312_set_interrupts(struct stk8312_data *data, u8 int_mask) return ret; ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU, int_mask); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "failed to set interrupts\n"); + stk8312_set_mode(data, mode); + return ret; + } return stk8312_set_mode(data, mode); } @@ -230,7 +235,7 @@ static int stk8312_data_rdy_trigger_set_state(struct iio_trigger *trig, data->dready_trigger_on = state; - return ret; + return 0; } static const struct iio_trigger_ops stk8312_trigger_ops = { @@ -255,20 +260,24 @@ static int stk8312_set_sample_rate(struct stk8312_data *data, int rate) return ret; ret = i2c_smbus_read_byte_data(client, STK8312_REG_SR); - if (ret < 0) { - dev_err(&client->dev, "failed to set sampling rate\n"); - return ret; - } + if (ret < 0) + goto err_activate; masked_reg = (ret & (~STK8312_SR_MASK)) | rate; ret = i2c_smbus_write_byte_data(client, STK8312_REG_SR, masked_reg); if (ret < 0) - dev_err(&client->dev, "failed to set sampling rate\n"); - else - data->sample_rate_idx = rate; + goto err_activate; + + data->sample_rate_idx = rate; return stk8312_set_mode(data, mode); + +err_activate: + dev_err(&client->dev, "failed to set sampling rate\n"); + stk8312_set_mode(data, mode); + + return ret; } static int stk8312_set_range(struct stk8312_data *data, u8 range) @@ -290,21 +299,25 @@ static int stk8312_set_range(struct stk8312_data *data, u8 range) return ret; ret = i2c_smbus_read_byte_data(client, STK8312_REG_STH); - if (ret < 0) { - dev_err(&client->dev, "failed to change sensor range\n"); - return ret; - } + if (ret < 0) + goto err_activate; masked_reg = ret & (~STK8312_RNG_MASK); masked_reg |= range << STK8312_RNG_SHIFT; ret = i2c_smbus_write_byte_data(client, STK8312_REG_STH, masked_reg); if (ret < 0) - dev_err(&client->dev, "failed to change sensor range\n"); - else - data->range = range; + goto err_activate; + + data->range = range; return stk8312_set_mode(data, mode); + +err_activate: + dev_err(&client->dev, "failed to change sensor range\n"); + stk8312_set_mode(data, mode); + + return ret; } static int stk8312_read_accel(struct stk8312_data *data, u8 address) @@ -337,18 +350,21 @@ static int stk8312_read_raw(struct iio_dev *indio_dev, ret = stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE); if (ret < 0) { mutex_unlock(&data->lock); - return -EINVAL; + return ret; } ret = stk8312_read_accel(data, chan->address); if (ret < 0) { stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE)); mutex_unlock(&data->lock); - return -EINVAL; + return ret; } *val = sign_extend32(ret, 7); - stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE)); + ret = stk8312_set_mode(data, + data->mode & (~STK8312_MODE_ACTIVE)); mutex_unlock(&data->lock); + if (ret < 0) + return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = stk8312_scale_table[data->range - 1][0]; @@ -608,7 +624,7 @@ static int stk8312_probe(struct i2c_client *client, goto err_buffer_cleanup; } - return ret; + return 0; err_buffer_cleanup: iio_triggered_buffer_cleanup(indio_dev); -- cgit v1.3-6-gb490 From 03ecd50c50450b3e3173c9dda8adab241b46ae1e Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Wed, 29 Jul 2015 23:39:37 +0200 Subject: iio:accel:stk8312: rework macro definitions Make use of BIT to describe register bits, GENMASK for consecutive bitmasks, rename and sort existing definitions, replace magic value with an expressive definition, drop an unused definition. Signed-off-by: Hartmut Knaack Reviewed-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 82ad283b8c60..d406ad05b8e5 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -37,16 +37,16 @@ #define STK8312_REG_OTPDATA 0x3E #define STK8312_REG_OTPCTRL 0x3F -#define STK8312_MODE_ACTIVE 0x01 +#define STK8312_MODE_ACTIVE BIT(0) #define STK8312_MODE_STANDBY 0x00 -#define STK8312_DREADY_BIT 0x10 -#define STK8312_INT_MODE 0xC0 -#define STK8312_RNG_MASK 0xC0 -#define STK8312_SR_MASK 0x07 -#define STK8312_SR_400HZ_IDX 0 +#define STK8312_MODE_INT_AH_PP 0xC0 /* active-high, push-pull */ +#define STK8312_DREADY_BIT BIT(4) +#define STK8312_RNG_6G 1 #define STK8312_RNG_SHIFT 6 -#define STK8312_READ_RETRIES 16 -#define STK8312_ALL_CHANNEL_MASK 7 +#define STK8312_RNG_MASK GENMASK(7, 6) +#define STK8312_SR_MASK GENMASK(2, 0) +#define STK8312_SR_400HZ_IDX 0 +#define STK8312_ALL_CHANNEL_MASK GENMASK(2, 0) #define STK8312_ALL_CHANNEL_SIZE 3 #define STK8312_DRIVER_NAME "stk8312" @@ -144,7 +144,7 @@ static int stk8312_otp_init(struct stk8312_data *data) if (ret < 0) goto exit_err; count--; - } while (!(ret & 0x80) && count > 0); + } while (!(ret & BIT(7)) && count > 0); if (count == 0) { ret = -ETIMEDOUT; @@ -565,11 +565,12 @@ static int stk8312_probe(struct i2c_client *client, return ret; } data->sample_rate_idx = STK8312_SR_400HZ_IDX; - ret = stk8312_set_range(data, 1); + ret = stk8312_set_range(data, STK8312_RNG_6G); if (ret < 0) return ret; - ret = stk8312_set_mode(data, STK8312_INT_MODE | STK8312_MODE_ACTIVE); + ret = stk8312_set_mode(data, + STK8312_MODE_INT_AH_PP | STK8312_MODE_ACTIVE); if (ret < 0) return ret; @@ -691,7 +692,7 @@ MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id); static struct i2c_driver stk8312_driver = { .driver = { - .name = "stk8312", + .name = STK8312_DRIVER_NAME, .pm = STK8312_PM_OPS, .acpi_match_table = ACPI_PTR(stk8312_acpi_id), }, -- cgit v1.3-6-gb490 From 7d73e02c5d11ac1298b0a363b57d713969c02bbd Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Wed, 29 Jul 2015 23:39:38 +0200 Subject: iio:accel:stk8312: use appropriate variable types Adapt some variable types to reduce unnecessary casting. Signed-off-by: Hartmut Knaack Reviewed-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index d406ad05b8e5..4a697446f196 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -69,8 +69,8 @@ static const int stk8312_scale_table[][2] = { }; static const struct { - u16 val; - u32 val2; + int val; + int val2; } stk8312_samp_freq_table[] = { {400, 0}, {200, 0}, {100, 0}, {50, 0}, {25, 0}, {12, 500000}, {6, 250000}, {3, 125000} @@ -103,7 +103,7 @@ static const struct iio_chan_spec stk8312_channels[] = { struct stk8312_data { struct i2c_client *client; struct mutex lock; - int range; + u8 range; u8 sample_rate_idx; u8 mode; struct iio_trigger *dready_trig; @@ -243,7 +243,7 @@ static const struct iio_trigger_ops stk8312_trigger_ops = { .owner = THIS_MODULE, }; -static int stk8312_set_sample_rate(struct stk8312_data *data, int rate) +static int stk8312_set_sample_rate(struct stk8312_data *data, u8 rate) { int ret; u8 masked_reg; -- cgit v1.3-6-gb490 From dca5d2846514c0f3d95827d291310a403fc0ebb7 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Wed, 29 Jul 2015 23:39:39 +0200 Subject: iio:accel:stk8312: code style cleanup Adjust some indentation issues to make checkpatch.pl happy in strict mode. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index 4a697446f196..c5a47650b453 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -157,8 +157,7 @@ static int stk8312_otp_init(struct stk8312_data *data) if (ret < 0) goto exit_err; - ret = i2c_smbus_write_byte_data(data->client, - STK8312_REG_AFECTRL, ret); + ret = i2c_smbus_write_byte_data(data->client, STK8312_REG_AFECTRL, ret); if (ret < 0) goto exit_err; msleep(150); @@ -458,7 +457,7 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) data->buffer[2] = buffer[2]; } else { for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) { + indio_dev->masklength) { ret = stk8312_read_accel(data, bit); if (ret < 0) { mutex_unlock(&data->lock); -- cgit v1.3-6-gb490 From 7a9fbd250ce274a1a625b1e2055abfe26328e46b Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Wed, 29 Jul 2015 23:39:40 +0200 Subject: iio:accel:stk8312: drop local buffer Drop the local buffer in stk8312_trigger_handler() and use data->buffer instead for bulk reads. Signed-off-by: Hartmut Knaack Reviewed-by: Tiberiu Breana Signed-off-by: Jonathan Cameron --- drivers/iio/accel/stk8312.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index c5a47650b453..c764af284c94 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -435,7 +435,6 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct stk8312_data *data = iio_priv(indio_dev); int bit, ret, i = 0; - u8 buffer[STK8312_ALL_CHANNEL_SIZE]; mutex_lock(&data->lock); /* @@ -446,15 +445,12 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) ret = i2c_smbus_read_i2c_block_data(data->client, STK8312_REG_XOUT, STK8312_ALL_CHANNEL_SIZE, - buffer); + data->buffer); if (ret < STK8312_ALL_CHANNEL_SIZE) { dev_err(&data->client->dev, "register read failed\n"); mutex_unlock(&data->lock); goto err; } - data->buffer[0] = buffer[0]; - data->buffer[1] = buffer[1]; - data->buffer[2] = buffer[2]; } else { for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { -- cgit v1.3-6-gb490 From 8e563b0dabcce7cad80af9bb40b220004f411092 Mon Sep 17 00:00:00 2001 From: Cristina Opriceana Date: Thu, 6 Aug 2015 14:56:02 +0300 Subject: iio: trigger: Add missing fields in kernel docs Fix kernel docs warnings by adding the missing description for each of the existing function parameters. Signed-off-by: Cristina Opriceana Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-trigger.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index d31098e0c43f..570606c2adbd 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -40,7 +40,14 @@ static DEFINE_MUTEX(iio_trigger_list_lock); /** * iio_trigger_read_name() - retrieve useful identifying name - **/ + * @dev: device associated with the iio_trigger + * @attr: pointer to the device_attribute structure that is + * being processed + * @buf: buffer to print the name into + * + * Return: a negative number on failure or the number of written + * characters on success. + */ static ssize_t iio_trigger_read_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -288,10 +295,17 @@ EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc); /** * iio_trigger_read_current() - trigger consumer sysfs query current trigger + * @dev: device associated with an industrial I/O device + * @attr: pointer to the device_attribute structure that + * is being processed + * @buf: buffer where the current trigger name will be printed into * * For trigger consumers the current_trigger interface allows the trigger * used by the device to be queried. - **/ + * + * Return: a negative number on failure, the number of characters written + * on success or 0 if no trigger is available + */ static ssize_t iio_trigger_read_current(struct device *dev, struct device_attribute *attr, char *buf) @@ -305,11 +319,18 @@ static ssize_t iio_trigger_read_current(struct device *dev, /** * iio_trigger_write_current() - trigger consumer sysfs set current trigger + * @dev: device associated with an industrial I/O device + * @attr: device attribute that is being processed + * @buf: string buffer that holds the name of the trigger + * @len: length of the trigger name held by buf * * For trigger consumers the current_trigger interface allows the trigger * used for this device to be specified at run time based on the trigger's * name. - **/ + * + * Return: negative error code on failure or length of the buffer + * on success + */ static ssize_t iio_trigger_write_current(struct device *dev, struct device_attribute *attr, const char *buf, -- cgit v1.3-6-gb490 From 8166537283b31d7abaae9e56bd48fbbc30cdc579 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:13 +0200 Subject: iio: adis16400: Fix adis16448 gyroscope scale Use the correct scale for the adis16448 gyroscope output. Signed-off-by: Lars-Peter Clausen Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index 2fd68f2219a7..d42e4fe2c7ed 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -780,7 +780,7 @@ static struct adis16400_chip_info adis16400_chips[] = { .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SERIAL_NUMBER | ADIS16400_BURST_DIAG_STAT, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */ + .gyro_scale_micro = IIO_DEGREE_TO_RAD(40000), /* 0.04 deg/s */ .accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */ .temp_scale_nano = 73860000, /* 0.07386 C */ .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ -- cgit v1.3-6-gb490 From 7abad1063deb0f77d275c61f58863ec319c58c5c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:15 +0200 Subject: iio: adis16480: Fix scale factors The different devices support by the adis16480 driver have slightly different scales for the gyroscope and accelerometer channels. Signed-off-by: Lars-Peter Clausen Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16480.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 989605dd6f78..b94bfd3f595b 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -110,6 +110,10 @@ struct adis16480_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; + unsigned int gyro_max_val; + unsigned int gyro_max_scale; + unsigned int accel_max_val; + unsigned int accel_max_scale; }; struct adis16480 { @@ -497,19 +501,21 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, static int adis16480_read_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long info) { + struct adis16480 *st = iio_priv(indio_dev); + switch (info) { case IIO_CHAN_INFO_RAW: return adis_single_conversion(indio_dev, chan, 0, val); case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: - *val = 0; - *val2 = IIO_DEGREE_TO_RAD(20000); /* 0.02 degree/sec */ - return IIO_VAL_INT_PLUS_MICRO; + *val = st->chip_info->gyro_max_scale; + *val2 = st->chip_info->gyro_max_val; + return IIO_VAL_FRACTIONAL; case IIO_ACCEL: - *val = 0; - *val2 = IIO_G_TO_M_S_2(800); /* 0.8 mg */ - return IIO_VAL_INT_PLUS_MICRO; + *val = st->chip_info->accel_max_scale; + *val2 = st->chip_info->accel_max_val; + return IIO_VAL_FRACTIONAL; case IIO_MAGN: *val = 0; *val2 = 100; /* 0.0001 gauss */ @@ -674,18 +680,39 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16375] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), + /* + * storing the value in rad/degree and the scale in degree + * gives us the result in rad and better precession than + * storing the scale directly in rad. + */ + .gyro_max_val = IIO_RAD_TO_DEGREE(22887), + .gyro_max_scale = 300, + .accel_max_val = IIO_M_S_2_TO_G(21973), + .accel_max_scale = 18, }, [ADIS16480] = { .channels = adis16480_channels, .num_channels = ARRAY_SIZE(adis16480_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(12500), + .accel_max_scale = 5, }, [ADIS16485] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(20000), + .accel_max_scale = 5, }, [ADIS16488] = { .channels = adis16480_channels, .num_channels = ARRAY_SIZE(adis16480_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(22500), + .accel_max_scale = 18, }, }; -- cgit v1.3-6-gb490 From bd95a89e7a80cb0ee57e9ccd62de0dd80f98a270 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:16 +0200 Subject: iio: adis16400: adis16300 has product ID and serial number The ADIS16300 has the product ID and serial number registers, they are just not documented. Set the appropriate flags so the driver makes use of them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index d42e4fe2c7ed..7d612ab79a87 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -696,7 +696,8 @@ static struct adis16400_chip_info adis16400_chips[] = { [ADIS16300] = { .channels = adis16300_channels, .num_channels = ARRAY_SIZE(adis16300_channels), - .flags = ADIS16400_HAS_SLOW_MODE, + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ .accel_scale_micro = 5884, .temp_scale_nano = 140000000, /* 0.14 C */ -- cgit v1.3-6-gb490 From 3c386760790e3d3d5cb3ac2f0e09f3710eab7f99 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:17 +0200 Subject: iio: adis16400: Add ADIS16305 support The ADIS16305 is fully register map compatible to the ADIS16300. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index 7d612ab79a87..e4cc2ecb42e2 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -927,6 +927,7 @@ static int adis16400_remove(struct spi_device *spi) static const struct spi_device_id adis16400_id[] = { {"adis16300", ADIS16300}, + {"adis16305", ADIS16300}, {"adis16334", ADIS16334}, {"adis16350", ADIS16350}, {"adis16354", ADIS16350}, -- cgit v1.3-6-gb490 From f1afda124badf1cf4b013722d55934536ff0892c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:18 +0200 Subject: iio: adis16260: Add ADIS16266 support The ADIS16266 is mostly register compatible to the ADIS16260. The difference is a different gyroscope scale factor as well not having the relative angular displacement channel. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/adis16260.c | 137 +++++++++++++++++++++++++++++++------------ 1 file changed, 98 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 75fe0edd3d0f..00c6ad9bf35f 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -101,19 +101,24 @@ #define ADIS16260_SCAN_TEMP 3 #define ADIS16260_SCAN_ANGL 4 -/* Power down the device */ -static int adis16260_stop_device(struct iio_dev *indio_dev) -{ - struct adis *adis = iio_priv(indio_dev); - int ret; - u16 val = ADIS16260_SLP_CNT_POWER_OFF; +struct adis16260_chip_info { + unsigned int gyro_max_val; + unsigned int gyro_max_scale; + const struct iio_chan_spec *channels; + unsigned int num_channels; +}; - ret = adis_write_reg_16(adis, ADIS16260_SLP_CNT, val); - if (ret) - dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT"); +struct adis16260 { + const struct adis16260_chip_info *info; - return ret; -} + struct adis adis; +}; + +enum adis16260_type { + ADIS16251, + ADIS16260, + ADIS16266, +}; static const struct iio_chan_spec adis16260_channels[] = { ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, @@ -131,6 +136,55 @@ static const struct iio_chan_spec adis16260_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(5), }; +static const struct iio_chan_spec adis16266_channels[] = { + ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + BIT(IIO_CHAN_INFO_SAMP_FREQ), 14), + ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), + ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), + ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static const struct adis16260_chip_info adis16260_chip_info_table[] = { + [ADIS16251] = { + .gyro_max_scale = 80, + .gyro_max_val = IIO_RAD_TO_DEGREE(4368), + .channels = adis16260_channels, + .num_channels = ARRAY_SIZE(adis16260_channels), + }, + [ADIS16260] = { + .gyro_max_scale = 320, + .gyro_max_val = IIO_RAD_TO_DEGREE(4368), + .channels = adis16260_channels, + .num_channels = ARRAY_SIZE(adis16260_channels), + }, + [ADIS16266] = { + .gyro_max_scale = 14000, + .gyro_max_val = IIO_RAD_TO_DEGREE(3357), + .channels = adis16266_channels, + .num_channels = ARRAY_SIZE(adis16266_channels), + }, +}; + +/* Power down the device */ +static int adis16260_stop_device(struct iio_dev *indio_dev) +{ + struct adis16260 *adis16260 = iio_priv(indio_dev); + int ret; + u16 val = ADIS16260_SLP_CNT_POWER_OFF; + + ret = adis_write_reg_16(&adis16260->adis, ADIS16260_SLP_CNT, val); + if (ret) + dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT"); + + return ret; +} + static const u8 adis16260_addresses[][2] = { [ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE }, }; @@ -140,7 +194,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { - struct adis *adis = iio_priv(indio_dev); + struct adis16260 *adis16260 = iio_priv(indio_dev); + const struct adis16260_chip_info *info = adis16260->info; + struct adis *adis = &adis16260->adis; int ret; u8 addr; s16 val16; @@ -152,15 +208,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: - *val = 0; - if (spi_get_device_id(adis->spi)->driver_data) { - /* 0.01832 degree / sec */ - *val2 = IIO_DEGREE_TO_RAD(18320); - } else { - /* 0.07326 degree / sec */ - *val2 = IIO_DEGREE_TO_RAD(73260); - } - return IIO_VAL_INT_PLUS_MICRO; + *val = info->gyro_max_scale; + *val2 = info->gyro_max_val; + return IIO_VAL_FRACTIONAL; case IIO_INCLI: *val = 0; *val2 = IIO_DEGREE_TO_RAD(36630); @@ -224,7 +274,8 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, int val2, long mask) { - struct adis *adis = iio_priv(indio_dev); + struct adis16260 *adis16260 = iio_priv(indio_dev); + struct adis *adis = &adis16260->adis; int ret; u8 addr; u8 t; @@ -305,35 +356,42 @@ static const struct adis_data adis16260_data = { static int adis16260_probe(struct spi_device *spi) { + const struct spi_device_id *id; + struct adis16260 *adis16260; struct iio_dev *indio_dev; - struct adis *adis; int ret; + id = spi_get_device_id(spi); + if (!id) + return -ENODEV; + /* setup the industrialio driver allocated elements */ - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16260)); if (!indio_dev) return -ENOMEM; - adis = iio_priv(indio_dev); + adis16260 = iio_priv(indio_dev); /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); - indio_dev->name = spi_get_device_id(spi)->name; + adis16260->info = &adis16260_chip_info_table[id->driver_data]; + + indio_dev->name = id->name; indio_dev->dev.parent = &spi->dev; indio_dev->info = &adis16260_info; - indio_dev->channels = adis16260_channels; - indio_dev->num_channels = ARRAY_SIZE(adis16260_channels); + indio_dev->channels = adis16260->info->channels; + indio_dev->num_channels = adis16260->info->num_channels; indio_dev->modes = INDIO_DIRECT_MODE; - ret = adis_init(adis, indio_dev, spi, &adis16260_data); + ret = adis_init(&adis16260->adis, indio_dev, spi, &adis16260_data); if (ret) return ret; - ret = adis_setup_buffer_and_trigger(adis, indio_dev, NULL); + ret = adis_setup_buffer_and_trigger(&adis16260->adis, indio_dev, NULL); if (ret) return ret; /* Get the device into a sane initial state */ - ret = adis_initial_startup(adis); + ret = adis_initial_startup(&adis16260->adis); if (ret) goto error_cleanup_buffer_trigger; ret = iio_device_register(indio_dev); @@ -343,18 +401,18 @@ static int adis16260_probe(struct spi_device *spi) return 0; error_cleanup_buffer_trigger: - adis_cleanup_buffer_and_trigger(adis, indio_dev); + adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev); return ret; } static int adis16260_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adis *adis = iio_priv(indio_dev); + struct adis16260 *adis16260 = iio_priv(indio_dev); iio_device_unregister(indio_dev); adis16260_stop_device(indio_dev); - adis_cleanup_buffer_and_trigger(adis, indio_dev); + adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev); return 0; } @@ -364,11 +422,12 @@ static int adis16260_remove(struct spi_device *spi) * support for the on chip filtering. */ static const struct spi_device_id adis16260_id[] = { - {"adis16260", 0}, - {"adis16265", 0}, - {"adis16250", 0}, - {"adis16255", 0}, - {"adis16251", 1}, + {"adis16260", ADIS16260}, + {"adis16265", ADIS16260}, + {"adis16266", ADIS16266}, + {"adis16250", ADIS16260}, + {"adis16255", ADIS16260}, + {"adis16251", ADIS16251}, {} }; MODULE_DEVICE_TABLE(spi, adis16260_id); -- cgit v1.3-6-gb490 From dc8615ce34cf72955f098750eef81a5501c107d1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:19 +0200 Subject: iio: adis16400: Add ADIS16367 support The ADIS16367 is mostly register compatible to the ADIS16360. The only difference is the scale factor for the gyroscope output. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index e4cc2ecb42e2..a9f4043b409f 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -139,6 +139,7 @@ enum adis16400_chip_variant { ADIS16360, ADIS16362, ADIS16364, + ADIS16367, ADIS16400, ADIS16448, }; @@ -764,6 +765,18 @@ static struct adis16400_chip_info adis16400_chips[] = { .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, }, + [ADIS16367] = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(2000), /* 0.2 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ + .temp_scale_nano = 136000000, /* 0.136 C */ + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + }, [ADIS16400] = { .channels = adis16400_channels, .num_channels = ARRAY_SIZE(adis16400_channels), @@ -936,6 +949,7 @@ static const struct spi_device_id adis16400_id[] = { {"adis16362", ADIS16362}, {"adis16364", ADIS16364}, {"adis16365", ADIS16360}, + {"adis16367", ADIS16367}, {"adis16400", ADIS16400}, {"adis16405", ADIS16400}, {"adis16448", ADIS16448}, -- cgit v1.3-6-gb490 From 72d9c9869df3149316af6cd70585eee15f643f40 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:20 +0200 Subject: iio: adis16400: Add ADIS16445 support The ADIS16445 is similar to the ADIS16448, but without the magnetometer and pressure channels as well as different scale factors for the gyroscope and accelerometer outputs. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/imu/adis16400_core.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index a9f4043b409f..abc4c50de9e8 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -141,6 +141,7 @@ enum adis16400_chip_variant { ADIS16364, ADIS16367, ADIS16400, + ADIS16445, ADIS16448, }; @@ -623,6 +624,17 @@ static const struct iio_chan_spec adis16400_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; +static const struct iio_chan_spec adis16445_channels[] = { + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16), + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16), + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16), + ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12), + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), +}; + static const struct iio_chan_spec adis16448_channels[] = { ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16), ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16), @@ -788,6 +800,19 @@ static struct adis16400_chip_info adis16400_chips[] = { .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, }, + [ADIS16445] = { + .channels = adis16445_channels, + .num_channels = ARRAY_SIZE(adis16445_channels), + .flags = ADIS16400_HAS_PROD_ID | + ADIS16400_HAS_SERIAL_NUMBER | + ADIS16400_BURST_DIAG_STAT, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(250), /* 1/4000 g */ + .temp_scale_nano = 73860000, /* 0.07386 C */ + .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ + .set_freq = adis16334_set_freq, + .get_freq = adis16334_get_freq, + }, [ADIS16448] = { .channels = adis16448_channels, .num_channels = ARRAY_SIZE(adis16448_channels), @@ -952,6 +977,7 @@ static const struct spi_device_id adis16400_id[] = { {"adis16367", ADIS16367}, {"adis16400", ADIS16400}, {"adis16405", ADIS16400}, + {"adis16445", ADIS16445}, {"adis16448", ADIS16448}, {} }; -- cgit v1.3-6-gb490 From 5450c360d4608b70ebd85f4ae2f2ce779a296a93 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 5 Aug 2015 15:38:21 +0200 Subject: iio: adis16136: Add ADIS16137 support The ADIS16137 is register map compatible to the ADIS16136, but has a different scale factor for the gyroscope output. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/adis16136.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index 591bd555e1f3..26de876b223d 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -473,6 +473,7 @@ enum adis16136_id { ID_ADIS16133, ID_ADIS16135, ID_ADIS16136, + ID_ADIS16137, }; static const struct adis16136_chip_info adis16136_chip_info[] = { @@ -488,6 +489,10 @@ static const struct adis16136_chip_info adis16136_chip_info[] = { .precision = IIO_DEGREE_TO_RAD(450), .fullscale = 24623, }, + [ID_ADIS16137] = { + .precision = IIO_DEGREE_TO_RAD(1000), + .fullscale = 24609, + }, }; static int adis16136_probe(struct spi_device *spi) @@ -557,6 +562,7 @@ static const struct spi_device_id adis16136_ids[] = { { "adis16133", ID_ADIS16133 }, { "adis16135", ID_ADIS16135 }, { "adis16136", ID_ADIS16136 }, + { "adis16137", ID_ADIS16137 }, { } }; MODULE_DEVICE_TABLE(spi, adis16136_ids); -- cgit v1.3-6-gb490 From ee33ddd2915cca51ce9acb1e5584631b74d92b3c Mon Sep 17 00:00:00 2001 From: Lars Svensson Date: Wed, 5 Aug 2015 14:15:12 +0200 Subject: staging: iio_simple_dummy: Fix indentation errors Fixing indentation errors in drivers/staging/iio/iio_simple_dummy_events.c. Signed-off-by: Lars Svensson Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/staging/iio/iio_simple_dummy_events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c index ecc563cb6cb9..73108baf80ad 100644 --- a/drivers/staging/iio/iio_simple_dummy_events.c +++ b/drivers/staging/iio/iio_simple_dummy_events.c @@ -120,7 +120,7 @@ int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - enum iio_event_info info, + enum iio_event_info info, int *val, int *val2) { struct iio_dummy_state *st = iio_priv(indio_dev); @@ -143,7 +143,7 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, - enum iio_event_info info, + enum iio_event_info info, int val, int val2) { struct iio_dummy_state *st = iio_priv(indio_dev); -- cgit v1.3-6-gb490 From c4eaab798bd459f0c3f8917e74abf1851f3e1cb5 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 23 Jul 2015 17:20:59 +0200 Subject: iio:accel:bmc150-accel: Move bmc150_accel_chip_init() Move bmc150_accel_chip_init() so that we can use bmc150_accel_chip_info_tbl[] in it. Signed-off-by: Bastien Nocera Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 114 +++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 21b665fc0739..5be65e2cb244 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -345,63 +345,6 @@ static int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t, return 0; } -static int bmc150_accel_chip_init(struct bmc150_accel_data *data) -{ - int ret; - - ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); - if (ret < 0) { - dev_err(&data->client->dev, "Error: Reading chip id\n"); - return ret; - } - - dev_dbg(&data->client->dev, "Chip Id %x\n", ret); - if (ret != data->chip_info->chip_id) { - dev_err(&data->client->dev, "Invalid chip %x\n", ret); - return -ENODEV; - } - - ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); - if (ret < 0) - return ret; - - /* Set Bandwidth */ - ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0); - if (ret < 0) - return ret; - - /* Set Default Range */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_PMU_RANGE, - BMC150_ACCEL_DEF_RANGE_4G); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_pmu_range\n"); - return ret; - } - - data->range = BMC150_ACCEL_DEF_RANGE_4G; - - /* Set default slope duration and thresholds */ - data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; - data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION; - ret = bmc150_accel_update_slope(data); - if (ret < 0) - return ret; - - /* Set default as latched interrupts */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); - if (ret < 0) { - dev_err(&data->client->dev, - "Error writing reg_int_rst_latch\n"); - return ret; - } - - return 0; -} - static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, int *val2) { @@ -1618,6 +1561,63 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = { .postdisable = bmc150_accel_buffer_postdisable, }; +static int bmc150_accel_chip_init(struct bmc150_accel_data *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); + if (ret < 0) { + dev_err(&data->client->dev, "Error: Reading chip id\n"); + return ret; + } + + dev_dbg(&data->client->dev, "Chip Id %x\n", ret); + if (ret != data->chip_info->chip_id) { + dev_err(&data->client->dev, "Invalid chip %x\n", ret); + return -ENODEV; + } + + ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + if (ret < 0) + return ret; + + /* Set Bandwidth */ + ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0); + if (ret < 0) + return ret; + + /* Set Default Range */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_PMU_RANGE, + BMC150_ACCEL_DEF_RANGE_4G); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_pmu_range\n"); + return ret; + } + + data->range = BMC150_ACCEL_DEF_RANGE_4G; + + /* Set default slope duration and thresholds */ + data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; + data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION; + ret = bmc150_accel_update_slope(data); + if (ret < 0) + return ret; + + /* Set default as latched interrupts */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + return 0; +} + static int bmc150_accel_probe(struct i2c_client *client, const struct i2c_device_id *id) { -- cgit v1.3-6-gb490 From 0ad4bf37017621e25fe157fa095fd8849779a873 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 23 Jul 2015 17:21:07 +0200 Subject: iio:accel:bmc150-accel: Use the chip ID to detect sensor variant Instead of using the I2C or ACPI ID to determine which variant of the chipset to use, determine that from the chip ID. Under Windows, the same driver is used for those variants and, despite incorrect ACPI data, it is able to load and operate the accelerometer. Fixes the accelerometer failing with: bmc150_accel i2c-BMA250E:00: Invalid chip f8 on the WinBook TW100 Signed-off-by: Bastien Nocera Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 46 +++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 5be65e2cb244..a7b66edf2a38 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -151,6 +151,7 @@ struct bmc150_scale_info { }; struct bmc150_accel_chip_info { + const char *name; u8 chip_id; const struct iio_chan_spec *channels; int num_channels; @@ -1062,6 +1063,7 @@ enum { static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { [bmc150] = { + .name = "BMC150A", .chip_id = 0xFA, .channels = bmc150_accel_channels, .num_channels = ARRAY_SIZE(bmc150_accel_channels), @@ -1071,6 +1073,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {76590, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bmi055] = { + .name = "BMI055A", .chip_id = 0xFA, .channels = bmc150_accel_channels, .num_channels = ARRAY_SIZE(bmc150_accel_channels), @@ -1080,6 +1083,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {76590, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma255] = { + .name = "BMA0255", .chip_id = 0xFA, .channels = bmc150_accel_channels, .num_channels = ARRAY_SIZE(bmc150_accel_channels), @@ -1089,6 +1093,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {76590, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma250e] = { + .name = "BMA250E", .chip_id = 0xF9, .channels = bma250e_accel_channels, .num_channels = ARRAY_SIZE(bma250e_accel_channels), @@ -1098,6 +1103,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {306457, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma222e] = { + .name = "BMA222E", .chip_id = 0xF8, .channels = bma222e_accel_channels, .num_channels = ARRAY_SIZE(bma222e_accel_channels), @@ -1107,6 +1113,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {1225831, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma280] = { + .name = "BMA0280", .chip_id = 0xFB, .channels = bma280_accel_channels, .num_channels = ARRAY_SIZE(bma280_accel_channels), @@ -1353,20 +1360,6 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private) return IRQ_NONE; } -static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - - if (!id) - return NULL; - - *data = (int)id->driver_data; - - return dev_name(dev); -} - static int bmc150_accel_gpio_probe(struct i2c_client *client, struct bmc150_accel_data *data) { @@ -1563,7 +1556,7 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = { static int bmc150_accel_chip_init(struct bmc150_accel_data *data) { - int ret; + int ret, i; ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); if (ret < 0) { @@ -1572,8 +1565,15 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) } dev_dbg(&data->client->dev, "Chip Id %x\n", ret); - if (ret != data->chip_info->chip_id) { - dev_err(&data->client->dev, "Invalid chip %x\n", ret); + for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) { + if (bmc150_accel_chip_info_tbl[i].chip_id == ret) { + data->chip_info = &bmc150_accel_chip_info_tbl[i]; + break; + } + } + + if (!data->chip_info) { + dev_err(&data->client->dev, "Unsupported chip %x\n", ret); return -ENODEV; } @@ -1625,7 +1625,6 @@ static int bmc150_accel_probe(struct i2c_client *client, struct iio_dev *indio_dev; int ret; const char *name = NULL; - int chip_id = 0; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1635,15 +1634,8 @@ static int bmc150_accel_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); data->client = client; - if (id) { + if (id) name = id->name; - chip_id = id->driver_data; - } - - if (ACPI_HANDLE(&client->dev)) - name = bmc150_accel_match_acpi_device(&client->dev, &chip_id); - - data->chip_info = &bmc150_accel_chip_info_tbl[chip_id]; ret = bmc150_accel_chip_init(data); if (ret < 0) @@ -1654,7 +1646,7 @@ static int bmc150_accel_probe(struct i2c_client *client, indio_dev->dev.parent = &client->dev; indio_dev->channels = data->chip_info->channels; indio_dev->num_channels = data->chip_info->num_channels; - indio_dev->name = name; + indio_dev->name = name ? name : data->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bmc150_accel_info; -- cgit v1.3-6-gb490 From 001fceb9c64a39aebb85d31134182d39c1628a21 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:46 +0200 Subject: iio:accel:mma8452: fix _get_hp_filter_index To iterate through the available frequencies of mma8452_hp_filter_cutoff[], the array size of a row of that table needs to be provided to _get_int_plus_micros_index(). Fixes: 1e79841a00e46 ("iio: mma8452: Add highpass filter configuration.") Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 3c4ad1563ca4..d78d4a97d753 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -229,7 +229,7 @@ static int mma8452_get_hp_filter_index(struct mma8452_data *data, int i = mma8452_get_odr_index(data); return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i], - ARRAY_SIZE(mma8452_scales[0]), val, val2); + ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2); } static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz) -- cgit v1.3-6-gb490 From 8337455296385b45822dc46c2b25db4c361d734c Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:47 +0200 Subject: iio:accel:mma8452: drop double include One inclusion of linux/iio/trigger_consumer.h is sufficient. Fixes: ae6d9ce05691b ("iio: mma8452: Add support for interrupt driven triggers.") Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index d78d4a97d753..d87799fe7161 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include -- cgit v1.3-6-gb490 From b9fddcdb44c2e274193b119dd6c3af3a9324640a Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:48 +0200 Subject: iio:accel:mma8452: pass up real error code Pass up the error code provided by functions. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index d87799fe7161..9607f830a13b 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -343,7 +343,7 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, i = mma8452_get_hp_filter_index(data, val, val2); if (i < 0) - return -EINVAL; + return i; reg = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF); @@ -369,7 +369,7 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SAMP_FREQ: i = mma8452_get_samp_freq_index(data, val, val2); if (i < 0) - return -EINVAL; + return i; data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; @@ -378,7 +378,7 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: i = mma8452_get_scale_index(data, val, val2); if (i < 0) - return -EINVAL; + return i; data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; data->data_cfg |= i; return mma8452_change_config(data, MMA8452_DATA_CFG, -- cgit v1.3-6-gb490 From 11218226184b6b2be5cde4bf16f647dda225d4f3 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:49 +0200 Subject: iio:accel:mma8452: check values to be written Check values to be written to the device for valid lower and upper bounds. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 9607f830a13b..42640b1df870 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -471,15 +471,17 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, switch (info) { case IIO_EV_INFO_VALUE: - return mma8452_change_config(data, MMA8452_TRANSIENT_THS, - val & MMA8452_TRANSIENT_THS_MASK); + if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK) + return -EINVAL; + + return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val); case IIO_EV_INFO_PERIOD: steps = (val * USEC_PER_SEC + val2) / mma8452_transient_time_step_us[ mma8452_get_odr_index(data)]; - if (steps > 0xff) + if (steps < 0 || steps > 0xff) return -EINVAL; return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT, -- cgit v1.3-6-gb490 From 69abff81d7fa59a0dfca5c72a7f1006f17a06d11 Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:50 +0200 Subject: iio:accel:mma8452: rework register definitions Rework register definitions to be sorted by register and bit number, with bit definitions cascaded under the appropriate register, use GENMASK for consecutive bitmasks and realign properly. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 93 ++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 42640b1df870..2d5ee4607081 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -23,54 +23,51 @@ #include #include -#define MMA8452_STATUS 0x00 -#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ -#define MMA8452_OUT_Y 0x03 -#define MMA8452_OUT_Z 0x05 -#define MMA8452_INT_SRC 0x0c -#define MMA8452_WHO_AM_I 0x0d -#define MMA8452_DATA_CFG 0x0e -#define MMA8452_HP_FILTER_CUTOFF 0x0f -#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK (BIT(0) | BIT(1)) -#define MMA8452_TRANSIENT_CFG 0x1d -#define MMA8452_TRANSIENT_CFG_ELE BIT(4) -#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) -#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) -#define MMA8452_TRANSIENT_SRC 0x1e -#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1) -#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3) -#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5) -#define MMA8452_TRANSIENT_THS 0x1f -#define MMA8452_TRANSIENT_THS_MASK 0x7f -#define MMA8452_TRANSIENT_COUNT 0x20 -#define MMA8452_OFF_X 0x2f -#define MMA8452_OFF_Y 0x30 -#define MMA8452_OFF_Z 0x31 -#define MMA8452_CTRL_REG1 0x2a -#define MMA8452_CTRL_REG2 0x2b -#define MMA8452_CTRL_REG2_RST BIT(6) -#define MMA8452_CTRL_REG4 0x2d -#define MMA8452_CTRL_REG5 0x2e - -#define MMA8452_MAX_REG 0x31 - -#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) - -#define MMA8452_CTRL_DR_MASK (BIT(5) | BIT(4) | BIT(3)) -#define MMA8452_CTRL_DR_SHIFT 3 -#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ -#define MMA8452_CTRL_ACTIVE BIT(0) - -#define MMA8452_DATA_CFG_FS_MASK (BIT(1) | BIT(0)) -#define MMA8452_DATA_CFG_FS_2G 0 -#define MMA8452_DATA_CFG_FS_4G 1 -#define MMA8452_DATA_CFG_FS_8G 2 -#define MMA8452_DATA_CFG_HPF_MASK BIT(4) - -#define MMA8452_INT_DRDY BIT(0) -#define MMA8452_INT_TRANS BIT(5) - -#define MMA8452_DEVICE_ID 0x2a +#define MMA8452_STATUS 0x00 +#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) +#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ +#define MMA8452_OUT_Y 0x03 +#define MMA8452_OUT_Z 0x05 +#define MMA8452_INT_SRC 0x0c +#define MMA8452_WHO_AM_I 0x0d +#define MMA8452_DATA_CFG 0x0e +#define MMA8452_DATA_CFG_FS_MASK GENMASK(1, 0) +#define MMA8452_DATA_CFG_FS_2G 0 +#define MMA8452_DATA_CFG_FS_4G 1 +#define MMA8452_DATA_CFG_FS_8G 2 +#define MMA8452_DATA_CFG_HPF_MASK BIT(4) +#define MMA8452_HP_FILTER_CUTOFF 0x0f +#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0) +#define MMA8452_TRANSIENT_CFG 0x1d +#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) +#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) +#define MMA8452_TRANSIENT_CFG_ELE BIT(4) +#define MMA8452_TRANSIENT_SRC 0x1e +#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1) +#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3) +#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5) +#define MMA8452_TRANSIENT_THS 0x1f +#define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0) +#define MMA8452_TRANSIENT_COUNT 0x20 +#define MMA8452_CTRL_REG1 0x2a +#define MMA8452_CTRL_ACTIVE BIT(0) +#define MMA8452_CTRL_DR_MASK GENMASK(5, 3) +#define MMA8452_CTRL_DR_SHIFT 3 +#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ +#define MMA8452_CTRL_REG2 0x2b +#define MMA8452_CTRL_REG2_RST BIT(6) +#define MMA8452_CTRL_REG4 0x2d +#define MMA8452_CTRL_REG5 0x2e +#define MMA8452_OFF_X 0x2f +#define MMA8452_OFF_Y 0x30 +#define MMA8452_OFF_Z 0x31 + +#define MMA8452_MAX_REG 0x31 + +#define MMA8452_INT_DRDY BIT(0) +#define MMA8452_INT_TRANS BIT(5) + +#define MMA8452_DEVICE_ID 0x2a struct mma8452_data { struct i2c_client *client; -- cgit v1.3-6-gb490 From 686027fbc602e715aae2d1b7987daefc2ff82a8a Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:51 +0200 Subject: iio:accel:mma8452: coding style cleanup Some coding style cleanups, mainly indicated by checkpatch.pl, which includes indentation changes, drop spaces after casts and befor tabs. Also insert empty lines after logical blocks and before unconditional returns. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma8452.c | 106 ++++++++++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 2d5ee4607081..85283eab2ea7 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -87,30 +87,34 @@ static int mma8452_drdy(struct mma8452_data *data) return ret; if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY) return 0; + msleep(20); } dev_err(&data->client->dev, "data not ready\n"); + return -EIO; } static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) { int ret = mma8452_drdy(data); + if (ret < 0) return ret; - return i2c_smbus_read_i2c_block_data(data->client, - MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf); + + return i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X, + 3 * sizeof(__be16), (u8 *)buf); } -static ssize_t mma8452_show_int_plus_micros(char *buf, - const int (*vals)[2], int n) +static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2], + int n) { size_t len = 0; while (n-- > 0) - len += scnprintf(buf + len, PAGE_SIZE - len, - "%d.%06d ", vals[n][0], vals[n][1]); + len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ", + vals[n][0], vals[n][1]); /* replace trailing space by newline */ buf[len - 1] = '\n'; @@ -119,7 +123,7 @@ static ssize_t mma8452_show_int_plus_micros(char *buf, } static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n, - int val, int val2) + int val, int val2) { while (n-- > 0) if (val == vals[n][0] && val2 == vals[n][1]) @@ -143,7 +147,7 @@ static const int mma8452_samp_freq[8][2] = { * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048 * The userspace interface uses m/s^2 and we declare micro units * So scale factor is given by: - * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665 + * g * N * 1000000 / 2048 for N = 2, 4, 8 and g = 9.80665 */ static const int mma8452_scales[3][2] = { {0, 9577}, {0, 19154}, {0, 38307} @@ -174,17 +178,19 @@ static const int mma8452_hp_filter_cutoff[8][4][2] = { }; static ssize_t mma8452_show_samp_freq_avail(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { return mma8452_show_int_plus_micros(buf, mma8452_samp_freq, - ARRAY_SIZE(mma8452_samp_freq)); + ARRAY_SIZE(mma8452_samp_freq)); } static ssize_t mma8452_show_scale_avail(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { return mma8452_show_int_plus_micros(buf, mma8452_scales, - ARRAY_SIZE(mma8452_scales)); + ARRAY_SIZE(mma8452_scales)); } static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, @@ -201,22 +207,23 @@ static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail); static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO, - mma8452_show_scale_avail, NULL, 0); + mma8452_show_scale_avail, NULL, 0); static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available, - S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0); + S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0); static int mma8452_get_samp_freq_index(struct mma8452_data *data, - int val, int val2) + int val, int val2) { return mma8452_get_int_plus_micros_index(mma8452_samp_freq, - ARRAY_SIZE(mma8452_samp_freq), val, val2); + ARRAY_SIZE(mma8452_samp_freq), + val, val2); } -static int mma8452_get_scale_index(struct mma8452_data *data, - int val, int val2) +static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2) { return mma8452_get_int_plus_micros_index(mma8452_scales, - ARRAY_SIZE(mma8452_scales), val, val2); + ARRAY_SIZE(mma8452_scales), + val, val2); } static int mma8452_get_hp_filter_index(struct mma8452_data *data, @@ -262,25 +269,31 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, mutex_unlock(&data->lock); if (ret < 0) return ret; - *val = sign_extend32( - be16_to_cpu(buffer[chan->scan_index]) >> 4, 11); + + *val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]) >> 4, + 11); + return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; *val = mma8452_scales[i][0]; *val2 = mma8452_scales[i][1]; + return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: i = mma8452_get_odr_index(data); *val = mma8452_samp_freq[i][0]; *val2 = mma8452_samp_freq[i][1]; + return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_CALIBBIAS: - ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X + - chan->scan_index); + ret = i2c_smbus_read_byte_data(data->client, + MMA8452_OFF_X + chan->scan_index); if (ret < 0) return ret; + *val = sign_extend32(ret, 7); + return IIO_VAL_INT; case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) { @@ -291,21 +304,23 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, *val = 0; *val2 = 0; } + return IIO_VAL_INT_PLUS_MICRO; } + return -EINVAL; } static int mma8452_standby(struct mma8452_data *data) { return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, - data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); + data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); } static int mma8452_active(struct mma8452_data *data) { return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, - data->ctrl_reg1); + data->ctrl_reg1); } static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) @@ -330,6 +345,7 @@ static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) ret = 0; fail: mutex_unlock(&data->lock); + return ret; } @@ -346,6 +362,7 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, MMA8452_HP_FILTER_CUTOFF); if (reg < 0) return reg; + reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK; reg |= i; @@ -370,21 +387,26 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; + return mma8452_change_config(data, MMA8452_CTRL_REG1, - data->ctrl_reg1); + data->ctrl_reg1); case IIO_CHAN_INFO_SCALE: i = mma8452_get_scale_index(data, val, val2); if (i < 0) return i; + data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; data->data_cfg |= i; + return mma8452_change_config(data, MMA8452_DATA_CFG, - data->data_cfg); + data->data_cfg); case IIO_CHAN_INFO_CALIBBIAS: if (val < -128 || val > 127) return -EINVAL; - return mma8452_change_config(data, MMA8452_OFF_X + - chan->scan_index, val); + + return mma8452_change_config(data, + MMA8452_OFF_X + chan->scan_index, + val); case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: if (val == 0 && val2 == 0) { @@ -395,8 +417,9 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; } + return mma8452_change_config(data, MMA8452_DATA_CFG, - data->data_cfg); + data->data_cfg); default: return -EINVAL; @@ -421,6 +444,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, return ret; *val = ret & MMA8452_TRANSIENT_THS_MASK; + return IIO_VAL_INT; case IIO_EV_INFO_PERIOD: @@ -433,6 +457,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, mma8452_get_odr_index(data)]; *val = us / USEC_PER_SEC; *val2 = us % USEC_PER_SEC; + return IIO_VAL_INT_PLUS_MICRO; case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: @@ -449,6 +474,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, if (ret < 0) return ret; } + return IIO_VAL_INT_PLUS_MICRO; default: @@ -483,6 +509,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT, steps); + case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: reg = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG); @@ -497,6 +524,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, if (ret < 0) return ret; } + return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg); default: @@ -606,15 +634,16 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p) u8 buffer[16]; /* 3 16-bit channels + padding + ts */ int ret; - ret = mma8452_read(data, (__be16 *) buffer); + ret = mma8452_read(data, (__be16 *)buffer); if (ret < 0) goto done; iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns()); + iio_get_time_ns()); done: iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; } @@ -672,10 +701,10 @@ static struct attribute_group mma8452_event_attribute_group = { .modified = 1, \ .channel2 = IIO_MOD_##axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_CALIBBIAS), \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ - BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ .scan_index = idx, \ .scan_type = { \ .sign = 's', \ @@ -778,6 +807,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev) return ret; indio_dev->trig = trig; + return 0; } @@ -847,7 +877,7 @@ static int mma8452_probe(struct i2c_client *client, data->data_cfg = MMA8452_DATA_CFG_FS_2G; ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG, - data->data_cfg); + data->data_cfg); if (ret < 0) return ret; @@ -889,14 +919,14 @@ static int mma8452_probe(struct i2c_client *client, } data->ctrl_reg1 = MMA8452_CTRL_ACTIVE | - (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); + (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1, data->ctrl_reg1); if (ret < 0) goto trigger_cleanup; ret = iio_triggered_buffer_setup(indio_dev, NULL, - mma8452_trigger_handler, NULL); + mma8452_trigger_handler, NULL); if (ret < 0) goto trigger_cleanup; -- cgit v1.3-6-gb490 From 8838cc7f3c584d6aaf56c66577f8a2bfb21081ec Mon Sep 17 00:00:00 2001 From: Hartmut Knaack Date: Sun, 2 Aug 2015 22:43:52 +0200 Subject: iio:accel:mma8452: reorder Kconfig entry Move the entry in Kconfig to its alphabetically correct position. Signed-off-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index c99d8e242218..a59047d7657e 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -86,18 +86,6 @@ config KXSD9 To compile this driver as a module, choose M here: the module will be called kxsd9. -config MMA8452 - tristate "Freescale MMA8452Q Accelerometer Driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for the Freescale MMA8452Q 3-axis - accelerometer. - - To compile this driver as a module, choose M here: the module - will be called mma8452. - config KXCJK1013 tristate "Kionix 3-Axis Accelerometer Driver" depends on I2C @@ -111,6 +99,18 @@ config KXCJK1013 To compile this driver as a module, choose M here: the module will be called kxcjk-1013. +config MMA8452 + tristate "Freescale MMA8452Q Accelerometer Driver" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the Freescale MMA8452Q 3-axis + accelerometer. + + To compile this driver as a module, choose M here: the module + will be called mma8452. + config MMA9551_CORE tristate -- cgit v1.3-6-gb490 From 6c05cb145d6716f00d452aeb27916efb6d190cca Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Thu, 6 Aug 2015 19:23:57 +0300 Subject: usb: xhci: make USB_XHCI_PLATFORM selectable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now xhci-plat-hcd can be built when using one of platform specific drivers only (mvebu/rcar). There shouldn't be such limitation as some platforms may not require any quirks and may want to just use a generic driver ("generic-xhci" / "xhci-hcd"). Signed-off-by: Rafał Miłecki Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 8afc3c1efdab..5f0567927f1f 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -32,7 +32,14 @@ config USB_XHCI_PCI default y config USB_XHCI_PLATFORM - tristate + tristate "Generic xHCI driver for a platform device" + ---help--- + Adds an xHCI host driver for a generic platform device, which + provides a memory space and an irq. + It is also a prerequisite for platform specific drivers that + implement some extra quirks. + + If unsure, say N. config USB_XHCI_MVEBU tristate "xHCI support for Marvell Armada 375/38x" -- cgit v1.3-6-gb490 From 4758dcd19a7d9ba9610b38fecb93f65f56f86346 Mon Sep 17 00:00:00 2001 From: Reyad Attiyat Date: Thu, 6 Aug 2015 19:23:58 +0300 Subject: usb: xhci: Add support for URB_ZERO_PACKET to bulk/sg transfers This commit checks for the URB_ZERO_PACKET flag and creates an extra zero-length td if the urb transfer length is a multiple of the endpoint's max packet length. Signed-off-by: Reyad Attiyat Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 66 ++++++++++++++++++++++++++++++++++---------- drivers/usb/host/xhci.c | 5 ++++ 2 files changed, 57 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 6a8fc52aed58..463562d11929 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3041,9 +3041,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct xhci_td *td; struct scatterlist *sg; int num_sgs; - int trb_buff_len, this_sg_len, running_total; + int trb_buff_len, this_sg_len, running_total, ret; unsigned int total_packet_count; + bool zero_length_needed; bool first_trb; + int last_trb_num; u64 addr; bool more_trbs_coming; @@ -3059,13 +3061,27 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, total_packet_count = DIV_ROUND_UP(urb->transfer_buffer_length, usb_endpoint_maxp(&urb->ep->desc)); - trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id], + ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, num_trbs, urb, 0, mem_flags); - if (trb_buff_len < 0) - return trb_buff_len; + if (ret < 0) + return ret; urb_priv = urb->hcpriv; + + /* Deal with URB_ZERO_PACKET - need one more td/trb */ + zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET && + urb_priv->length == 2; + if (zero_length_needed) { + num_trbs++; + xhci_dbg(xhci, "Creating zero length td.\n"); + ret = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, + 1, urb, 1, mem_flags); + if (ret < 0) + return ret; + } + td = urb_priv->td[0]; /* @@ -3095,6 +3111,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trb_buff_len = urb->transfer_buffer_length; first_trb = true; + last_trb_num = zero_length_needed ? 2 : 1; /* Queue the first TRB, even if it's zero-length */ do { u32 field = 0; @@ -3112,12 +3129,15 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. */ - if (num_trbs > 1) { + if (num_trbs > last_trb_num) { field |= TRB_CHAIN; - } else { - /* FIXME - add check for ZERO_PACKET flag before this */ + } else if (num_trbs == last_trb_num) { td->last_trb = ep_ring->enqueue; field |= TRB_IOC; + } else if (zero_length_needed && num_trbs == 1) { + trb_buff_len = 0; + urb_priv->td[1]->last_trb = ep_ring->enqueue; + field |= TRB_IOC; } /* Only set interrupt on short packet for IN endpoints */ @@ -3179,7 +3199,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (running_total + trb_buff_len > urb->transfer_buffer_length) trb_buff_len = urb->transfer_buffer_length - running_total; - } while (running_total < urb->transfer_buffer_length); + } while (num_trbs > 0); check_trb_math(urb, num_trbs, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, @@ -3197,7 +3217,9 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, int num_trbs; struct xhci_generic_trb *start_trb; bool first_trb; + int last_trb_num; bool more_trbs_coming; + bool zero_length_needed; int start_cycle; u32 field, length_field; @@ -3228,7 +3250,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, num_trbs++; running_total += TRB_MAX_BUFF_SIZE; } - /* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */ ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, @@ -3237,6 +3258,20 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return ret; urb_priv = urb->hcpriv; + + /* Deal with URB_ZERO_PACKET - need one more td/trb */ + zero_length_needed = urb->transfer_flags & URB_ZERO_PACKET && + urb_priv->length == 2; + if (zero_length_needed) { + num_trbs++; + xhci_dbg(xhci, "Creating zero length td.\n"); + ret = prepare_transfer(xhci, xhci->devs[slot_id], + ep_index, urb->stream_id, + 1, urb, 1, mem_flags); + if (ret < 0) + return ret; + } + td = urb_priv->td[0]; /* @@ -3258,7 +3293,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trb_buff_len = urb->transfer_buffer_length; first_trb = true; - + last_trb_num = zero_length_needed ? 2 : 1; /* Queue the first TRB, even if it's zero-length */ do { u32 remainder = 0; @@ -3275,12 +3310,15 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Chain all the TRBs together; clear the chain bit in the last * TRB to indicate it's the last TRB in the chain. */ - if (num_trbs > 1) { + if (num_trbs > last_trb_num) { field |= TRB_CHAIN; - } else { - /* FIXME - add check for ZERO_PACKET flag before this */ + } else if (num_trbs == last_trb_num) { td->last_trb = ep_ring->enqueue; field |= TRB_IOC; + } else if (zero_length_needed && num_trbs == 1) { + trb_buff_len = 0; + urb_priv->td[1]->last_trb = ep_ring->enqueue; + field |= TRB_IOC; } /* Only set interrupt on short packet for IN endpoints */ @@ -3318,7 +3356,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trb_buff_len = urb->transfer_buffer_length - running_total; if (trb_buff_len > TRB_MAX_BUFF_SIZE) trb_buff_len = TRB_MAX_BUFF_SIZE; - } while (running_total < urb->transfer_buffer_length); + } while (num_trbs > 0); check_trb_math(urb, num_trbs, running_total); giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 91fd32835312..6b0f4a47e402 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1340,6 +1340,11 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) if (usb_endpoint_xfer_isoc(&urb->ep->desc)) size = urb->number_of_packets; + else if (usb_endpoint_is_bulk_out(&urb->ep->desc) && + urb->transfer_buffer_length > 0 && + urb->transfer_flags & URB_ZERO_PACKET && + !(urb->transfer_buffer_length % usb_endpoint_maxp(&urb->ep->desc))) + size = 2; else size = 1; -- cgit v1.3-6-gb490 From 79b8094f60d8ce54ee76e631ab665c5e3012e6ba Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Thu, 6 Aug 2015 19:24:00 +0300 Subject: xhci: xHCI 1.1: Contiguous Frame ID Capability (CFC) If the Contiguous Frame ID Capability is supported (CFC = 1), then the xHC shall match the Frame ID in every Isoch TD with SIA = 0 against the Frame Index of the MFINDEX register. This rule ensures resynchronization of Isoch TDs even if some are dropped due to Missed Service Errors or Stopping the endpoint. This patch enables xHCI driver to support CFC by calculating and setting the Frame ID field of an Isoch TRB. [made some dbg messages checkpatch friendly -Mathias] Signed-off-by: Lu Baolu Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-dbg.c | 2 + drivers/usb/host/xhci-ring.c | 191 ++++++++++++++++++++++++++++++++++++++++--- drivers/usb/host/xhci.h | 7 ++ 3 files changed, 187 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 745717ec9c89..c867ecbeaa60 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -99,6 +99,8 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " HC generates %s bit addresses\n", HCC_64BIT_ADDR(temp) ? "64" : "32"); + xhci_dbg(xhci, " HC %s Contiguous Frame ID Capability\n", + HCC_CFC(temp) ? "has" : "hasn't"); /* FIXME */ xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n"); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 463562d11929..af8c0f24cf46 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3555,6 +3555,97 @@ static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci, } } +/* + * Calculates Frame ID field of the isochronous TRB identifies the + * target frame that the Interval associated with this Isochronous + * Transfer Descriptor will start on. Refer to 4.11.2.5 in 1.1 spec. + * + * Returns actual frame id on success, negative value on error. + */ +static int xhci_get_isoc_frame_id(struct xhci_hcd *xhci, + struct urb *urb, int index) +{ + int start_frame, ist, ret = 0; + int start_frame_id, end_frame_id, current_frame_id; + + if (urb->dev->speed == USB_SPEED_LOW || + urb->dev->speed == USB_SPEED_FULL) + start_frame = urb->start_frame + index * urb->interval; + else + start_frame = (urb->start_frame + index * urb->interval) >> 3; + + /* Isochronous Scheduling Threshold (IST, bits 0~3 in HCSPARAMS2): + * + * If bit [3] of IST is cleared to '0', software can add a TRB no + * later than IST[2:0] Microframes before that TRB is scheduled to + * be executed. + * If bit [3] of IST is set to '1', software can add a TRB no later + * than IST[2:0] Frames before that TRB is scheduled to be executed. + */ + ist = HCS_IST(xhci->hcs_params2) & 0x7; + if (HCS_IST(xhci->hcs_params2) & (1 << 3)) + ist <<= 3; + + /* Software shall not schedule an Isoch TD with a Frame ID value that + * is less than the Start Frame ID or greater than the End Frame ID, + * where: + * + * End Frame ID = (Current MFINDEX register value + 895 ms.) MOD 2048 + * Start Frame ID = (Current MFINDEX register value + IST + 1) MOD 2048 + * + * Both the End Frame ID and Start Frame ID values are calculated + * in microframes. When software determines the valid Frame ID value; + * The End Frame ID value should be rounded down to the nearest Frame + * boundary, and the Start Frame ID value should be rounded up to the + * nearest Frame boundary. + */ + current_frame_id = readl(&xhci->run_regs->microframe_index); + start_frame_id = roundup(current_frame_id + ist + 1, 8); + end_frame_id = rounddown(current_frame_id + 895 * 8, 8); + + start_frame &= 0x7ff; + start_frame_id = (start_frame_id >> 3) & 0x7ff; + end_frame_id = (end_frame_id >> 3) & 0x7ff; + + xhci_dbg(xhci, "%s: index %d, reg 0x%x start_frame_id 0x%x, end_frame_id 0x%x, start_frame 0x%x\n", + __func__, index, readl(&xhci->run_regs->microframe_index), + start_frame_id, end_frame_id, start_frame); + + if (start_frame_id < end_frame_id) { + if (start_frame > end_frame_id || + start_frame < start_frame_id) + ret = -EINVAL; + } else if (start_frame_id > end_frame_id) { + if ((start_frame > end_frame_id && + start_frame < start_frame_id)) + ret = -EINVAL; + } else { + ret = -EINVAL; + } + + if (index == 0) { + if (ret == -EINVAL || start_frame == start_frame_id) { + start_frame = start_frame_id + 1; + if (urb->dev->speed == USB_SPEED_LOW || + urb->dev->speed == USB_SPEED_FULL) + urb->start_frame = start_frame; + else + urb->start_frame = start_frame << 3; + ret = 0; + } + } + + if (ret) { + xhci_warn(xhci, "Frame ID %d (reg %d, index %d) beyond range (%d, %d)\n", + start_frame, current_frame_id, index, + start_frame_id, end_frame_id); + xhci_warn(xhci, "Ignore frame ID field, use SIA bit instead\n"); + return ret; + } + + return start_frame; +} + /* This is for isoc transfer */ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) @@ -3571,7 +3662,9 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, u64 start_addr, addr; int i, j; bool more_trbs_coming; + struct xhci_virt_ep *xep; + xep = &xhci->devs[slot_id]->eps[ep_index]; ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; num_tds = urb->number_of_packets; @@ -3619,6 +3712,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, td = urb_priv->td[i]; for (j = 0; j < trbs_per_td; j++) { + int frame_id = 0; u32 remainder = 0; field = 0; @@ -3627,8 +3721,20 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, TRB_TLBPC(residue); /* Queue the isoc TRB */ field |= TRB_TYPE(TRB_ISOC); - /* Assume URB_ISO_ASAP is set */ - field |= TRB_SIA; + + /* Calculate Frame ID and SIA fields */ + if (!(urb->transfer_flags & URB_ISO_ASAP) && + HCC_CFC(xhci->hcc_params)) { + frame_id = xhci_get_isoc_frame_id(xhci, + urb, + i); + if (frame_id >= 0) + field |= TRB_FRAME_ID(frame_id); + else + field |= TRB_SIA; + } else + field |= TRB_SIA; + if (i == 0) { if (start_cycle == 0) field |= 0x1; @@ -3704,6 +3810,10 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } } + /* store the next frame id */ + if (HCC_CFC(xhci->hcc_params)) + xep->next_frame_id = urb->start_frame + num_tds * urb->interval; + if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) { if (xhci->quirks & XHCI_AMD_PLL_FIX) usb_amd_quirk_pll_disable(); @@ -3737,12 +3847,34 @@ cleanup: return ret; } +static int ep_ring_is_processing(struct xhci_hcd *xhci, + int slot_id, unsigned int ep_index) +{ + struct xhci_virt_device *xdev; + struct xhci_ring *ep_ring; + struct xhci_ep_ctx *ep_ctx; + struct xhci_virt_ep *xep; + dma_addr_t hw_deq; + + xdev = xhci->devs[slot_id]; + xep = &xhci->devs[slot_id]->eps[ep_index]; + ep_ring = xep->ring; + ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); + + if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) != EP_STATE_RUNNING) + return 0; + + hw_deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK; + return (hw_deq != + xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue)); +} + /* * Check transfer ring to guarantee there is enough room for the urb. * Update ISO URB start_frame and interval. - * Update interval as xhci_queue_intr_tx does. Just use xhci frame_index to - * update the urb->start_frame by now. - * Always assume URB_ISO_ASAP set, and NEVER use urb->start_frame as input. + * Update interval as xhci_queue_intr_tx does. Use xhci frame_index to + * update urb->start_frame if URB_ISO_ASAP is set in transfer_flags or + * Contiguous Frame ID is not supported by HC. */ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) @@ -3755,8 +3887,11 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, int ep_interval; int num_tds, num_trbs, i; int ret; + struct xhci_virt_ep *xep; + int ist; xdev = xhci->devs[slot_id]; + xep = &xhci->devs[slot_id]->eps[ep_index]; ep_ring = xdev->eps[ep_index].ring; ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); @@ -3773,14 +3908,10 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, if (ret) return ret; - start_frame = readl(&xhci->run_regs->microframe_index); - start_frame &= 0x3fff; - - urb->start_frame = start_frame; - if (urb->dev->speed == USB_SPEED_LOW || - urb->dev->speed == USB_SPEED_FULL) - urb->start_frame >>= 3; - + /* + * Check interval value. This should be done before we start to + * calculate the start frame value. + */ xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info)); ep_interval = urb->interval; /* Convert to microframes */ @@ -3801,6 +3932,40 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, urb->dev->speed == USB_SPEED_FULL) urb->interval /= 8; } + + /* Calculate the start frame and put it in urb->start_frame. */ + if (HCC_CFC(xhci->hcc_params) && + ep_ring_is_processing(xhci, slot_id, ep_index)) { + urb->start_frame = xep->next_frame_id; + goto skip_start_over; + } + + start_frame = readl(&xhci->run_regs->microframe_index); + start_frame &= 0x3fff; + /* + * Round up to the next frame and consider the time before trb really + * gets scheduled by hardare. + */ + ist = HCS_IST(xhci->hcs_params2) & 0x7; + if (HCS_IST(xhci->hcs_params2) & (1 << 3)) + ist <<= 3; + start_frame += ist + XHCI_CFC_DELAY; + start_frame = roundup(start_frame, 8); + + /* + * Round up to the next ESIT (Endpoint Service Interval Time) if ESIT + * is greate than 8 microframes. + */ + if (urb->dev->speed == USB_SPEED_LOW || + urb->dev->speed == USB_SPEED_FULL) { + start_frame = roundup(start_frame, urb->interval << 3); + urb->start_frame = start_frame >> 3; + } else { + start_frame = roundup(start_frame, urb->interval); + urb->start_frame = start_frame; + } + +skip_start_over: ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free; return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ed2ebf647c38..73686928cae3 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -119,6 +119,8 @@ struct xhci_cap_regs { #define HCC_LTC(p) ((p) & (1 << 6)) /* true: no secondary Stream ID Support */ #define HCC_NSS(p) ((p) & (1 << 7)) +/* true: HC has Contiguous Frame ID Capability */ +#define HCC_CFC(p) ((p) & (1 << 11)) /* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */ #define HCC_MAX_PSA(p) (1 << ((((p) >> 12) & 0xf) + 1)) /* Extended Capabilities pointer from PCI base - section 5.3.6 */ @@ -891,6 +893,8 @@ struct xhci_virt_ep { /* Bandwidth checking storage */ struct xhci_bw_info bw_info; struct list_head bw_endpoint_list; + /* Isoch Frame ID checking storage */ + int next_frame_id; }; enum xhci_overhead_type { @@ -1165,6 +1169,7 @@ enum xhci_setup_dev { /* Isochronous TRB specific fields */ #define TRB_SIA (1<<31) +#define TRB_FRAME_ID(p) (((p) & 0x7ff) << 20) struct xhci_generic_trb { __le32 field[4]; @@ -1601,6 +1606,8 @@ struct xhci_driver_overrides { int (*start)(struct usb_hcd *hcd); }; +#define XHCI_CFC_DELAY 10 + /* convert between an HCD pointer and the corresponding EHCI_HCD */ static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd) { -- cgit v1.3-6-gb490 From 40a3b775f49c2784c96b19170fd2478e5e5511a1 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Thu, 6 Aug 2015 19:24:01 +0300 Subject: xhci: xHCI 1.1: Stopped - Short Packet Capability (SPC) This patch enables xhci driver to support SPC by handling Stopped - Short Packet event in transfer event path. If SPC = '1' and the stop endpoint command is executed, after a Short Packet condition has been detected, but before the end of the TD has been reached, (i.e. the TD is in progress for pipe), then a Transfer Event TRB with its Completion Code set to Stopped - Short Packet and its TRB Transfer Length set to value of the EDTLA shall be forced for the interrupted TRB, irrespective of whether its IOC or ISP flags are set. This Transfer Event TRB will precede the Command Completion Event TRB for the command, and is referred to as a Stopped Transfer Event. Signed-off-by: Lu Baolu Signed-off-by: Mathias Nyman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-dbg.c | 2 ++ drivers/usb/host/xhci-ring.c | 44 +++++++++++++++++++++++++++++++++++++++++--- drivers/usb/host/xhci.h | 6 ++++-- 3 files changed, 47 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index c867ecbeaa60..2d16faefb429 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -101,6 +101,8 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci) HCC_64BIT_ADDR(temp) ? "64" : "32"); xhci_dbg(xhci, " HC %s Contiguous Frame ID Capability\n", HCC_CFC(temp) ? "has" : "hasn't"); + xhci_dbg(xhci, " HC %s generate Stopped - Short Package event\n", + HCC_SPC(temp) ? "can" : "can't"); /* FIXME */ xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n"); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index af8c0f24cf46..5fbf33987a85 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1812,7 +1812,9 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, if (skip) goto td_cleanup; - if (trb_comp_code == COMP_STOP_INVAL || trb_comp_code == COMP_STOP) { + if (trb_comp_code == COMP_STOP_INVAL || + trb_comp_code == COMP_STOP || + trb_comp_code == COMP_STOP_SHORT) { /* The Endpoint Stop Command completion will take care of any * stopped TDs. A stopped TD may be restarted, so don't update * the ring dequeue pointer or take this TD off any lists yet. @@ -1919,8 +1921,22 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, else *status = 0; break; - case COMP_STOP_INVAL: + case COMP_STOP_SHORT: + if (event_trb == ep_ring->dequeue || event_trb == td->last_trb) + xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl setup or status TRB\n"); + else + td->urb->actual_length = + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + + return finish_td(xhci, td, event_trb, event, ep, status, false); case COMP_STOP: + /* Did we stop at data stage? */ + if (event_trb != ep_ring->dequeue && event_trb != td->last_trb) + td->urb->actual_length = + td->urb->transfer_buffer_length - + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + /* fall through */ + case COMP_STOP_INVAL: return finish_td(xhci, td, event_trb, event, ep, status, false); default: if (!xhci_requires_manual_halt_cleanup(xhci, @@ -2014,6 +2030,8 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, } if ((xhci->quirks & XHCI_TRUST_TX_LENGTH)) trb_comp_code = COMP_SHORT_TX; + /* fallthrough */ + case COMP_STOP_SHORT: case COMP_SHORT_TX: frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ? -EREMOTEIO : 0; @@ -2049,6 +2067,10 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, if (trb_comp_code == COMP_SUCCESS || skip_td) { frame->actual_length = frame->length; td->urb->actual_length += frame->length; + } else if (trb_comp_code == COMP_STOP_SHORT) { + frame->actual_length = + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + td->urb->actual_length += frame->actual_length; } else { for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg; cur_trb != event_trb; @@ -2129,6 +2151,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, *status = 0; } break; + case COMP_STOP_SHORT: case COMP_SHORT_TX: if (td->urb->transfer_flags & URB_SHORT_NOT_OK) *status = -EREMOTEIO; @@ -2145,8 +2168,20 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, td->urb->ep->desc.bEndpointAddress, td->urb->transfer_buffer_length, EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); + /* Stopped - short packet completion */ + if (trb_comp_code == COMP_STOP_SHORT) { + td->urb->actual_length = + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); + + if (td->urb->transfer_buffer_length < + td->urb->actual_length) { + xhci_warn(xhci, "HC gave bad length of %d bytes txed\n", + EVENT_TRB_LEN(le32_to_cpu(event->transfer_len))); + td->urb->actual_length = 0; + /* status will be set by usb core for canceled urbs */ + } /* Fast path - was this the last TRB in the TD for this URB? */ - if (event_trb == td->last_trb) { + } else if (event_trb == td->last_trb) { if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { td->urb->actual_length = td->urb->transfer_buffer_length - @@ -2300,6 +2335,9 @@ static int handle_tx_event(struct xhci_hcd *xhci, case COMP_STOP_INVAL: xhci_dbg(xhci, "Stopped on No-op or Link TRB\n"); break; + case COMP_STOP_SHORT: + xhci_dbg(xhci, "Stopped with short packet transfer detected\n"); + break; case COMP_STALL: xhci_dbg(xhci, "Stalled endpoint\n"); ep->ep_state |= EP_HALTED; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 73686928cae3..dbda41e91c84 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -119,6 +119,8 @@ struct xhci_cap_regs { #define HCC_LTC(p) ((p) & (1 << 6)) /* true: no secondary Stream ID Support */ #define HCC_NSS(p) ((p) & (1 << 7)) +/* true: HC supports Stopped - Short Packet */ +#define HCC_SPC(p) ((p) & (1 << 9)) /* true: HC has Contiguous Frame ID Capability */ #define HCC_CFC(p) ((p) & (1 << 11)) /* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */ @@ -1063,8 +1065,8 @@ struct xhci_transfer_event { #define COMP_STOP 26 /* Same as COMP_EP_STOPPED, but the transferred length in the event is invalid */ #define COMP_STOP_INVAL 27 -/* Control Abort Error - Debug Capability - control pipe aborted */ -#define COMP_DBG_ABORT 28 +/* Same as COMP_EP_STOPPED, but a short packet detected */ +#define COMP_STOP_SHORT 28 /* Max Exit Latency Too Large Error */ #define COMP_MEL_ERR 29 /* TRB type 30 reserved */ -- cgit v1.3-6-gb490 From f355e830a54ebe1601613d78a8d5b85eeafde358 Mon Sep 17 00:00:00 2001 From: Kris Borer Date: Fri, 7 Aug 2015 07:22:44 -0400 Subject: usb: devio: fix spacing Fix two occurrences of the checkpatch.pl error: ERROR: space prohibited before that ',' (ctx:WxW) Fix one occurrence of the checkpatch error: ERROR: space required before the open parenthesis '(' Signed-off-by: Kris Borer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index ed6d1d5031f1..38ae877c46e3 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -103,7 +103,7 @@ MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic"); #define snoop(dev, format, arg...) \ do { \ if (usbfs_snoop) \ - dev_info(dev , format , ## arg); \ + dev_info(dev, format, ## arg); \ } while (0) enum snoop_when { @@ -1321,7 +1321,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0; u = 0; - switch(uurb->type) { + switch (uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; -- cgit v1.3-6-gb490 From 166b8639f52ebeec1bfbe966239530a83040c428 Mon Sep 17 00:00:00 2001 From: Chase Metzger Date: Sat, 8 Aug 2015 01:03:34 -0700 Subject: usb: core: hub.c: Removed some warnings generated by checkpatch.pl Removed some checkpatch.pl warnings saying there was an unwanted space between function names and their arguments. Signed-off-by: Chase Metzger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 917c27c4675a..a0b22be1509d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -50,8 +50,8 @@ DEFINE_MUTEX(usb_port_peer_mutex); /* cycle leds on hubs that aren't blinking for attention */ static bool blinkenlights = 0; -module_param (blinkenlights, bool, S_IRUGO); -MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs"); +module_param(blinkenlights, bool, S_IRUGO); +MODULE_PARM_DESC(blinkenlights, "true to cycle leds on hubs"); /* * Device SATA8000 FW1.0 from DATAST0R Technology Corp requires about @@ -439,7 +439,7 @@ static void set_port_led(struct usb_hub *hub, int port1, int selector) #define LED_CYCLE_PERIOD ((2*HZ)/3) -static void led_work (struct work_struct *work) +static void led_work(struct work_struct *work) { struct usb_hub *hub = container_of(work, struct usb_hub, leds.work); @@ -646,7 +646,7 @@ static void hub_irq(struct urb *urb) default: /* presumably an error */ /* Cause a hub reset after 10 consecutive errors */ - dev_dbg (hub->intfdev, "transfer --> %d\n", status); + dev_dbg(hub->intfdev, "transfer --> %d\n", status); if ((++hub->nerrors < 10) || hub->error) goto resubmit; hub->error = status; @@ -671,14 +671,14 @@ resubmit: if (hub->quiescing) return; - if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 + if ((status = usb_submit_urb(hub->urb, GFP_ATOMIC)) != 0 && status != -ENODEV && status != -EPERM) - dev_err (hub->intfdev, "resubmit --> %d\n", status); + dev_err(hub->intfdev, "resubmit --> %d\n", status); } /* USB 2.0 spec Section 11.24.2.3 */ static inline int -hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) +hub_clear_tt_buffer(struct usb_device *hdev, u16 devinfo, u16 tt) { /* Need to clear both directions for control ep */ if (((devinfo >> 11) & USB_ENDPOINT_XFERTYPE_MASK) == @@ -706,7 +706,7 @@ static void hub_tt_work(struct work_struct *work) container_of(work, struct usb_hub, tt.clear_work); unsigned long flags; - spin_lock_irqsave (&hub->tt.lock, flags); + spin_lock_irqsave(&hub->tt.lock, flags); while (!list_empty(&hub->tt.clear_list)) { struct list_head *next; struct usb_tt_clear *clear; @@ -715,14 +715,14 @@ static void hub_tt_work(struct work_struct *work) int status; next = hub->tt.clear_list.next; - clear = list_entry (next, struct usb_tt_clear, clear_list); - list_del (&clear->clear_list); + clear = list_entry(next, struct usb_tt_clear, clear_list); + list_del(&clear->clear_list); /* drop lock so HCD can concurrently report other TT errors */ - spin_unlock_irqrestore (&hub->tt.lock, flags); - status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); + spin_unlock_irqrestore(&hub->tt.lock, flags); + status = hub_clear_tt_buffer(hdev, clear->devinfo, clear->tt); if (status && status != -ENODEV) - dev_err (&hdev->dev, + dev_err(&hdev->dev, "clear tt %d (%04x) error %d\n", clear->tt, clear->devinfo, status); @@ -734,7 +734,7 @@ static void hub_tt_work(struct work_struct *work) kfree(clear); spin_lock_irqsave(&hub->tt.lock, flags); } - spin_unlock_irqrestore (&hub->tt.lock, flags); + spin_unlock_irqrestore(&hub->tt.lock, flags); } /** @@ -797,7 +797,7 @@ int usb_hub_clear_tt_buffer(struct urb *urb) */ clear = kmalloc(sizeof *clear, GFP_ATOMIC); if (clear == NULL) { - dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); + dev_err(&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); /* FIXME recover somehow ... RESET_TT? */ return -ENOMEM; } @@ -806,10 +806,10 @@ int usb_hub_clear_tt_buffer(struct urb *urb) clear->tt = tt->multi ? udev->ttport : 1; clear->devinfo = usb_pipeendpoint (pipe); clear->devinfo |= udev->devnum << 4; - clear->devinfo |= usb_pipecontrol (pipe) + clear->devinfo |= usb_pipecontrol(pipe) ? (USB_ENDPOINT_XFER_CONTROL << 11) : (USB_ENDPOINT_XFER_BULK << 11); - if (usb_pipein (pipe)) + if (usb_pipein(pipe)) clear->devinfo |= 1 << 15; /* info for completion callback */ @@ -817,10 +817,10 @@ int usb_hub_clear_tt_buffer(struct urb *urb) clear->ep = urb->ep; /* tell keventd to clear state for this TT */ - spin_lock_irqsave (&tt->lock, flags); - list_add_tail (&clear->clear_list, &tt->clear_list); + spin_lock_irqsave(&tt->lock, flags); + list_add_tail(&clear->clear_list, &tt->clear_list); schedule_work(&tt->clear_work); - spin_unlock_irqrestore (&tt->lock, flags); + spin_unlock_irqrestore(&tt->lock, flags); return 0; } EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer); -- cgit v1.3-6-gb490 From a2b4041ab6ec8b6f07d2da2c993b003dd39f0868 Mon Sep 17 00:00:00 2001 From: Chandra S Gorentla Date: Sat, 8 Aug 2015 17:41:33 +0530 Subject: staging: wilc1000: Add space between the braces Inserted space between nested braces. This fixes the checkpatch.pl error - space required after that close brace '}'. Signed-off-by: Chandra S Gorentla Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 060288a3460d..3d5210b726d0 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -3332,7 +3332,7 @@ static int WILC_WFI_add_station(struct wiphy *wiphy, struct net_device *dev, { s32 s32Error = WILC_SUCCESS; struct WILC_WFI_priv *priv; - tstrWILC_AddStaParam strStaParams = {{0}}; + tstrWILC_AddStaParam strStaParams = { {0} }; perInterface_wlan_t *nic; @@ -3463,7 +3463,7 @@ static int WILC_WFI_change_station(struct wiphy *wiphy, struct net_device *dev, { s32 s32Error = WILC_SUCCESS; struct WILC_WFI_priv *priv; - tstrWILC_AddStaParam strStaParams = {{0}}; + tstrWILC_AddStaParam strStaParams = { {0} }; perInterface_wlan_t *nic; -- cgit v1.3-6-gb490 From 1bff1fe8c9dbb1a35d3129caaea9e91d4368b36a Mon Sep 17 00:00:00 2001 From: Chandra S Gorentla Date: Sat, 8 Aug 2015 17:41:34 +0530 Subject: staging: wilc1000: Remove unused extern declarations 'extern' declarations which are not referenced within the file are removed. Signed-off-by: Chandra S Gorentla Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 1 - drivers/staging/wilc1000/linux_wlan_sdio.c | 1 - drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 2 -- drivers/staging/wilc1000/wilc_wlan.c | 3 --- 4 files changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index bc06d56ebaf5..8b36683ef335 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -9,7 +9,6 @@ extern u8 connecting; extern WILC_TimerHandle hDuringIpTimer; #endif -extern bool bEnablePS; /*BugID_5137*/ extern u8 g_wilc_initialized; /*****************************************************************************/ diff --git a/drivers/staging/wilc1000/linux_wlan_sdio.c b/drivers/staging/wilc1000/linux_wlan_sdio.c index 858e3a191bce..37f31f4558b5 100644 --- a/drivers/staging/wilc1000/linux_wlan_sdio.c +++ b/drivers/staging/wilc1000/linux_wlan_sdio.c @@ -31,7 +31,6 @@ struct sdio_func *local_sdio_func; extern linux_wlan_t *g_linux_wlan; extern int wilc_netdev_init(void); -extern int sdio_clear_int(void); extern void wilc_handle_isr(void); static unsigned int sdio_default_speed; diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 3d5210b726d0..2361a80857cd 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -22,7 +22,6 @@ #define IS_MGMT_STATUS_SUCCES 0x040 #define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff) -extern void linux_wlan_free(void *vp); extern int linux_wlan_get_firmware(perInterface_wlan_t *p_nic); extern void linux_wlan_unlock(void *vp); extern u16 Set_machw_change_vir_if(bool bValue); @@ -1620,7 +1619,6 @@ static int WILC_WFI_dump_survey(struct wiphy *wiphy, struct net_device *netdev, * @version 1.0 */ -extern uint32_t Statisitcs_totalAcks, Statisitcs_DroppedAcks; static int WILC_WFI_get_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac, struct station_info *sinfo) { diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index 1eb13f90d0e4..75782a2c36ea 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -16,7 +16,6 @@ * Global * ********************************************/ -extern unsigned int int_clrd; extern wilc_hif_func_t hif_sdio; extern wilc_hif_func_t hif_spi; extern wilc_cfg_func_t mac_cfg; @@ -24,8 +23,6 @@ extern wilc_cfg_func_t mac_cfg; extern u8 g_wilc_initialized; /* AMR : 0422 RK3026 Crash issue */ #endif extern void WILC_WFI_mgmt_rx(uint8_t *buff, uint32_t size); -extern void frmw_to_linux(uint8_t *buff, uint32_t size); -int sdio_xfer_cnt(void); uint32_t wilc_get_chipid(uint8_t update); u16 Set_machw_change_vir_if(bool bValue); -- cgit v1.3-6-gb490 From 17aacd43c8d4e733d77f093a18de9d8d2b115407 Mon Sep 17 00:00:00 2001 From: Chandra S Gorentla Date: Sat, 8 Aug 2015 17:41:35 +0530 Subject: staging: wilc1000: Remove ' ' before quoted '\n' Fixes the checkpatch.pl warning - 'unnecessary whitespace before a quoted newline'. Signed-off-by: Chandra S Gorentla Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/linux_wlan.c | 20 +++++------ drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 42 +++++++++++------------ drivers/staging/wilc1000/wilc_wlan.c | 10 +++--- drivers/staging/wilc1000/wilc_wlan_cfg.c | 8 ++--- 4 files changed, 40 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 0a8052e717c2..92aa671ab1fd 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -296,7 +296,7 @@ static int dev_state_ev_handler(struct notifier_block *this, unsigned long event PRINT_D(GENERIC_DBG, "[%s] Up IP\n", dev_iface->ifa_label); pIP_Add_buff = (char *) (&(dev_iface->ifa_address)); - PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d \n", pIP_Add_buff[0], pIP_Add_buff[1], pIP_Add_buff[2], pIP_Add_buff[3]); + PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n", pIP_Add_buff[0], pIP_Add_buff[1], pIP_Add_buff[2], pIP_Add_buff[3]); host_int_setup_ipaddress((WILC_WFIDrvHandle)pstrWFIDrv, pIP_Add_buff, nic->u8IfIdx); break; @@ -318,7 +318,7 @@ static int dev_state_ev_handler(struct notifier_block *this, unsigned long event PRINT_D(GENERIC_DBG, "[%s] Down IP\n", dev_iface->ifa_label); pIP_Add_buff = null_ip; - PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d \n", pIP_Add_buff[0], pIP_Add_buff[1], pIP_Add_buff[2], pIP_Add_buff[3]); + PRINT_D(GENERIC_DBG, "IP add=%d:%d:%d:%d\n", pIP_Add_buff[0], pIP_Add_buff[1], pIP_Add_buff[2], pIP_Add_buff[3]); host_int_setup_ipaddress((WILC_WFIDrvHandle)pstrWFIDrv, pIP_Add_buff, nic->u8IfIdx); @@ -1020,7 +1020,7 @@ static int linux_wlan_firmware_download(linux_wlan_t *p_nic) release_firmware(g_linux_wlan->wilc_firmware); g_linux_wlan->wilc_firmware = NULL; - PRINT_D(INIT_DBG, "Download Succeeded \n"); + PRINT_D(INIT_DBG, "Download Succeeded\n"); _FAIL_: return ret; @@ -1774,7 +1774,7 @@ int repeat_power_cycle(perInterface_wlan_t *nic) #endif if (linux_wlan_get_firmware(nic)) { - PRINT_ER("Can't get firmware \n"); + PRINT_ER("Can't get firmware\n"); ret = -1; goto __fail__; } @@ -1859,7 +1859,7 @@ int wilc1000_wlan_init(struct net_device *dev, perInterface_wlan_t *p_nic) #endif if (linux_wlan_get_firmware(nic)) { - PRINT_ER("Can't get firmware \n"); + PRINT_ER("Can't get firmware\n"); ret = -EIO; goto _fail_irq_enable_; } @@ -2080,13 +2080,13 @@ static void wilc_set_multicast_list(struct net_device *dev) if (!dev) return; - PRINT_D(INIT_DBG, "Setting Multicast List with count = %d. \n", dev->mc.count); + PRINT_D(INIT_DBG, "Setting Multicast List with count = %d.\n", dev->mc.count); if (dev->flags & IFF_PROMISC) { /* Normally, we should configure the chip to retrive all packets * but we don't wanna support this right now */ /* TODO: add promiscuous mode support */ - PRINT_D(INIT_DBG, "Set promiscuous mode ON, retrive all packets \n"); + PRINT_D(INIT_DBG, "Set promiscuous mode ON, retrive all packets\n"); return; } @@ -2145,7 +2145,7 @@ int mac_xmit(struct sk_buff *skb, struct net_device *ndev) struct ethhdr *eth_h; nic = netdev_priv(ndev); - PRINT_D(INT_DBG, "\n========\n IntUH: %d - IntBH: %d - IntCld: %d \n========\n", int_rcvdU, int_rcvdB, int_clrd); + PRINT_D(INT_DBG, "\n========\n IntUH: %d - IntBH: %d - IntCld: %d\n========\n", int_rcvdU, int_rcvdB, int_clrd); PRINT_D(TX_DBG, "Sending packet just received from TCP/IP\n"); /* Stop the network interface queue */ @@ -2551,7 +2551,7 @@ int wilc_netdev_init(void) #ifndef WILC_SDIO if (!linux_spi_init(&g_linux_wlan->wilc_spidev)) { - PRINT_ER("Can't initialize SPI \n"); + PRINT_ER("Can't initialize SPI\n"); return -1; /* ERROR */ } g_linux_wlan->wilc_spidev = wilc_spi_dev; @@ -2636,7 +2636,7 @@ static void __exit exit_wilc_driver(void) } } for (i = 0; i < NUM_CONCURRENT_IFC; i++) { - PRINT_D(INIT_DBG, "Unregistering netdev %p \n", g_linux_wlan->strInterfaceInfo[i].wilc_netdev); + PRINT_D(INIT_DBG, "Unregistering netdev %p\n", g_linux_wlan->strInterfaceInfo[i].wilc_netdev); unregister_netdev(g_linux_wlan->strInterfaceInfo[i].wilc_netdev); #ifdef USE_WIRELESS PRINT_D(INIT_DBG, "Freeing Wiphy...\n"); diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 2361a80857cd..97df19393e7f 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -239,7 +239,7 @@ void remove_network_from_shadow(void *pUserVoid) for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { if (time_after(now, astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan + (unsigned long)(SCAN_RESULT_EXPIRE))) { - PRINT_D(CFG80211_DBG, "Network expired in ScanShadow: %s \n", astrLastScannedNtwrksShadow[i].au8ssid); + PRINT_D(CFG80211_DBG, "Network expired in ScanShadow: %s\n", astrLastScannedNtwrksShadow[i].au8ssid); if (astrLastScannedNtwrksShadow[i].pu8IEs != NULL) { WILC_FREE(astrLastScannedNtwrksShadow[i].pu8IEs); @@ -393,7 +393,7 @@ static void CfgScanResult(tenuScanEvent enuScanEvent, tstrNetworkInfo *pstrNetwo WILC_NULLCHECK(s32Error, channel); PRINT_INFO(CFG80211_DBG, "Network Info:: CHANNEL Frequency: %d, RSSI: %d, CapabilityInfo: %d," - "BeaconPeriod: %d \n", channel->center_freq, (((s32)pstrNetworkInfo->s8rssi) * 100), + "BeaconPeriod: %d\n", channel->center_freq, (((s32)pstrNetworkInfo->s8rssi) * 100), pstrNetworkInfo->u16CapInfo, pstrNetworkInfo->u16BeaconPeriod); if (pstrNetworkInfo->bNewNetwork == true) { @@ -429,7 +429,7 @@ static void CfgScanResult(tenuScanEvent enuScanEvent, tstrNetworkInfo *pstrNetwo /* So this network is discovered before, we'll just update its RSSI */ for (i = 0; i < priv->u32RcvdChCount; i++) { if (memcmp(astrLastScannedNtwrksShadow[i].au8bssid, pstrNetworkInfo->au8bssid, 6) == 0) { - PRINT_D(CFG80211_DBG, "Update RSSI of %s \n", astrLastScannedNtwrksShadow[i].au8ssid); + PRINT_D(CFG80211_DBG, "Update RSSI of %s\n", astrLastScannedNtwrksShadow[i].au8ssid); astrLastScannedNtwrksShadow[i].s8rssi = pstrNetworkInfo->s8rssi; astrLastScannedNtwrksShadow[i].u32TimeRcvdInScan = jiffies; @@ -439,14 +439,14 @@ static void CfgScanResult(tenuScanEvent enuScanEvent, tstrNetworkInfo *pstrNetwo } } } else if (enuScanEvent == SCAN_EVENT_DONE) { - PRINT_D(CFG80211_DBG, "Scan Done[%p] \n", priv->dev); - PRINT_D(CFG80211_DBG, "Refreshing Scan ... \n"); + PRINT_D(CFG80211_DBG, "Scan Done[%p]\n", priv->dev); + PRINT_D(CFG80211_DBG, "Refreshing Scan ...\n"); refresh_scan(priv, 1, false); if (priv->u32RcvdChCount > 0) { - PRINT_D(CFG80211_DBG, "%d Network(s) found \n", priv->u32RcvdChCount); + PRINT_D(CFG80211_DBG, "%d Network(s) found\n", priv->u32RcvdChCount); } else { - PRINT_D(CFG80211_DBG, "No networks found \n"); + PRINT_D(CFG80211_DBG, "No networks found\n"); } down(&(priv->hSemScanReq)); @@ -464,7 +464,7 @@ static void CfgScanResult(tenuScanEvent enuScanEvent, tstrNetworkInfo *pstrNetwo else if (enuScanEvent == SCAN_EVENT_ABORTED) { down(&(priv->hSemScanReq)); - PRINT_D(CFG80211_DBG, "Scan Aborted \n"); + PRINT_D(CFG80211_DBG, "Scan Aborted\n"); if (priv->pstrScanReq != NULL) { update_scan_time(priv); @@ -582,7 +582,7 @@ static void CfgConnectResult(tenuConnDisconnEvent enuConnDisconnEvent, u8WLANChannel = INVALID_CHANNEL; #endif - PRINT_ER("Unspecified failure: Connection status %d : MAC status = %d \n", u16ConnectStatus, u8MacStatus); + PRINT_ER("Unspecified failure: Connection status %d : MAC status = %d\n", u16ConnectStatus, u8MacStatus); } if (u16ConnectStatus == WLAN_STATUS_SUCCESS) { @@ -768,17 +768,17 @@ static int WILC_WFI_CfgScan(struct wiphy *wiphy, struct cfg80211_scan_request *r WILC_memcpy(strHiddenNetwork.pstrHiddenNetworkInfo[i].pu8ssid, request->ssids[i].ssid, request->ssids[i].ssid_len); strHiddenNetwork.pstrHiddenNetworkInfo[i].u8ssidlen = request->ssids[i].ssid_len; } else { - PRINT_D(CFG80211_DBG, "Received one NULL SSID \n"); + PRINT_D(CFG80211_DBG, "Received one NULL SSID\n"); strHiddenNetwork.u8ssidnum -= 1; } } - PRINT_D(CFG80211_DBG, "Trigger Scan Request \n"); + PRINT_D(CFG80211_DBG, "Trigger Scan Request\n"); s32Error = host_int_scan(priv->hWILCWFIDrv, USER_SCAN, ACTIVE_SCAN, au8ScanChanList, request->n_channels, (const u8 *)request->ie, request->ie_len, CfgScanResult, (void *)priv, &strHiddenNetwork); } else { - PRINT_D(CFG80211_DBG, "Trigger Scan Request \n"); + PRINT_D(CFG80211_DBG, "Trigger Scan Request\n"); s32Error = host_int_scan(priv->hWILCWFIDrv, USER_SCAN, ACTIVE_SCAN, au8ScanChanList, request->n_channels, (const u8 *)request->ie, request->ie_len, @@ -787,7 +787,7 @@ static int WILC_WFI_CfgScan(struct wiphy *wiphy, struct cfg80211_scan_request *r } else { PRINT_ER("Requested num of scanned channels is greater than the max, supported" - " channels \n"); + " channels\n"); } if (s32Error != WILC_SUCCESS) { @@ -840,7 +840,7 @@ static int WILC_WFI_CfgConnect(struct wiphy *wiphy, struct net_device *dev, } else pstrWFIDrv->u8P2PConnect = 0; #endif - PRINT_INFO(CFG80211_DBG, "Required SSID = %s\n , AuthType = %d \n", sme->ssid, sme->auth_type); + PRINT_INFO(CFG80211_DBG, "Required SSID = %s\n , AuthType = %d\n", sme->ssid, sme->auth_type); for (i = 0; i < u32LastScannedNtwrksCountShadow; i++) { if ((sme->ssid_len == astrLastScannedNtwrksShadow[i].u8SsidLen) && @@ -1045,7 +1045,7 @@ static int WILC_WFI_CfgConnect(struct wiphy *wiphy, struct net_device *dev, tenuAuth_type, pstrNetworkInfo->u8channel, pstrNetworkInfo->pJoinParams); if (s32Error != WILC_SUCCESS) { - PRINT_ER("host_int_set_join_req(): Error(%d) \n", s32Error); + PRINT_ER("host_int_set_join_req(): Error(%d)\n", s32Error); s32Error = -ENOENT; goto done; } @@ -1574,7 +1574,7 @@ static int WILC_WFI_set_default_key(struct wiphy *wiphy, struct net_device *netd priv = wiphy_priv(wiphy); - PRINT_D(CFG80211_DBG, "Setting default key with idx = %d \n", key_index); + PRINT_D(CFG80211_DBG, "Setting default key with idx = %d\n", key_index); if (key_index != priv->WILC_WFI_wep_default) { @@ -1811,7 +1811,7 @@ static int WILC_WFI_set_wiphy_params(struct wiphy *wiphy, u32 changed) priv = wiphy_priv(wiphy); pstrCfgParamVal.u32SetCfgFlag = 0; - PRINT_D(CFG80211_DBG, "Setting Wiphy params \n"); + PRINT_D(CFG80211_DBG, "Setting Wiphy params\n"); if (changed & WIPHY_PARAM_RETRY_SHORT) { PRINT_D(CFG80211_DBG, "Setting WIPHY_PARAM_RETRY_SHORT %d\n", @@ -2336,7 +2336,7 @@ static void WILC_WFI_RemainOnChannelReady(void *pUserVoid) struct WILC_WFI_priv *priv; priv = (struct WILC_WFI_priv *)pUserVoid; - PRINT_D(HOSTINF_DBG, "Remain on channel ready \n"); + PRINT_D(HOSTINF_DBG, "Remain on channel ready\n"); priv->bInP2PlistenState = true; @@ -2364,7 +2364,7 @@ static void WILC_WFI_RemainOnChannelExpired(void *pUserVoid, u32 u32SessionID) /*BugID_5477*/ if (u32SessionID == priv->strRemainOnChanParams.u32ListenSessionID) { - PRINT_D(GENERIC_DBG, "Remain on channel expired \n"); + PRINT_D(GENERIC_DBG, "Remain on channel expired\n"); priv->bInP2PlistenState = false; @@ -3211,7 +3211,7 @@ static int WILC_WFI_start_ap(struct wiphy *wiphy, struct net_device *dev, priv = wiphy_priv(wiphy); PRINT_D(HOSTAPD_DBG, "Starting ap\n"); - PRINT_D(HOSTAPD_DBG, "Interval = %d \n DTIM period = %d\n Head length = %zu Tail length = %zu\n", + PRINT_D(HOSTAPD_DBG, "Interval = %d\n DTIM period = %d\n Head length = %zu Tail length = %zu\n", settings->beacon_interval, settings->dtim_period, beacon->head_len, beacon->tail_len); s32Error = WILC_WFI_CfgSetChannel(wiphy, &settings->chandef); @@ -3427,7 +3427,7 @@ static int WILC_WFI_del_station(struct wiphy *wiphy, struct net_device *dev, if (mac == NULL) { - PRINT_D(HOSTAPD_DBG, "All associated stations \n"); + PRINT_D(HOSTAPD_DBG, "All associated stations\n"); s32Error = host_int_del_allstation(priv->hWILCWFIDrv, priv->assoc_stainfo.au8Sta_AssociatedBss); } else { PRINT_D(HOSTAPD_DBG, "With mac address: %x%x%x%x%x%x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index 75782a2c36ea..bd5c2564f313 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -447,7 +447,7 @@ static int wilc_wlan_txq_filter_dup_tcp_ack(void) for (i = PendingAcks_arrBase; i < (PendingAcks_arrBase + Pending_Acks); i++) { if (Pending_Acks_info[i].ack_num < Acks_keep_track_info[Pending_Acks_info[i].Session_index].Bigger_Ack_num) { struct txq_entry_t *tqe; - PRINT_D(TCP_ENH, "DROP ACK: %u \n", Pending_Acks_info[i].ack_num); + PRINT_D(TCP_ENH, "DROP ACK: %u\n", Pending_Acks_info[i].ack_num); tqe = Pending_Acks_info[i].txqe; if (tqe) { wilc_wlan_txq_remove(tqe); @@ -992,7 +992,7 @@ static int wilc_wlan_handle_txq(uint32_t *pu32TxqCount) /** * wait for vmm table is ready **/ - PRINT_WRN(GENERIC_DBG, "[wilc txq]: warn, vmm table not clear yet, wait... \n"); + PRINT_WRN(GENERIC_DBG, "[wilc txq]: warn, vmm table not clear yet, wait...\n"); release_bus(RELEASE_ALLOW_SLEEP); p->os_func.os_sleep(3); /* wait 3 ms */ acquire_bus(ACQUIRE_AND_WAKEUP); @@ -1059,7 +1059,7 @@ static int wilc_wlan_handle_txq(uint32_t *pu32TxqCount) } if (entries == 0) { - PRINT_WRN(GENERIC_DBG, "[wilc txq]: no more buffer in the chip (reg: %08x), retry later [[ %d, %x ]] \n", reg, i, vmm_table[i - 1]); + PRINT_WRN(GENERIC_DBG, "[wilc txq]: no more buffer in the chip (reg: %08x), retry later [[ %d, %x ]]\n", reg, i, vmm_table[i - 1]); /* undo the transaction. */ ret = p->hif_func.hif_read_reg(WILC_HOST_TX_CTRL, ®); @@ -1209,7 +1209,7 @@ static void wilc_wlan_handle_rxq(void) do { if (p->quit) { - PRINT_D(RX_DBG, "exit 1st do-while due to Clean_UP function \n"); + PRINT_D(RX_DBG, "exit 1st do-while due to Clean_UP function\n"); p->os_func.os_signal(p->cfg_wait); break; } @@ -1326,7 +1326,7 @@ static void wilc_wlan_handle_rxq(void) } while (1); p->rxq_exit = 1; - PRINT_D(RX_DBG, "THREAD: Exiting RX thread \n"); + PRINT_D(RX_DBG, "THREAD: Exiting RX thread\n"); return; } diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wilc_wlan_cfg.c index 04d032783dae..c10dffe4633e 100644 --- a/drivers/staging/wilc1000/wilc_wlan_cfg.c +++ b/drivers/staging/wilc1000/wilc_wlan_cfg.c @@ -551,7 +551,7 @@ static int wilc_wlan_cfg_indicate_rx(uint8_t *frame, int size, wilc_cfg_rsp_t *r case 'L': #ifndef SWITCH_LOG_TERMINAL - PRINT_ER("Unexpected firmware log message received \n"); + PRINT_ER("Unexpected firmware log message received\n"); #else PRINT_D(FIRM_DBG, "\nFIRMWARE LOGS :\n<<\n%s\n>>\n", frame); break; @@ -566,18 +566,18 @@ static int wilc_wlan_cfg_indicate_rx(uint8_t *frame, int size, wilc_cfg_rsp_t *r #endif /*bug3819:*/ case 'S': - PRINT_INFO(RX_DBG, "Scan Notification Received \n"); + PRINT_INFO(RX_DBG, "Scan Notification Received\n"); host_int_ScanCompleteReceived(frame - 4, size + 4); break; #ifdef WILC_FULLY_HOSTING_AP case 'T': - PRINT_INFO(RX_DBG, "TBTT Notification Received \n"); + PRINT_INFO(RX_DBG, "TBTT Notification Received\n"); process_tbtt_isr(); break; case 'A': - PRINT_INFO(RX_DBG, "HOSTAPD ACK Notification Received \n"); + PRINT_INFO(RX_DBG, "HOSTAPD ACK Notification Received\n"); WILC_mgm_HOSTAPD_ACK(ptru32Frame, bStatus); break; #endif -- cgit v1.3-6-gb490 From 78174adaf59e85274bb3dde5c5084619ed06020b Mon Sep 17 00:00:00 2001 From: Chandra S Gorentla Date: Sat, 8 Aug 2015 17:41:36 +0530 Subject: staging: wilc1000: Remove braces for single statement 'if' and 'else' Fixes the checkpatch.pl warning - braces {} are not necessary for any arm of this statement Signed-off-by: Chandra S Gorentla Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/coreconfigurator.c | 10 ++++----- drivers/staging/wilc1000/host_interface.c | 19 ++++++++--------- drivers/staging/wilc1000/linux_wlan.c | 25 +++++++++-------------- drivers/staging/wilc1000/wilc_debugfs.c | 10 ++++----- drivers/staging/wilc1000/wilc_memory.c | 5 ++--- drivers/staging/wilc1000/wilc_spi.c | 15 ++++++-------- drivers/staging/wilc1000/wilc_strutils.c | 5 ++--- drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 20 ++++++++---------- drivers/staging/wilc1000/wilc_wlan.c | 20 ++++++++---------- 9 files changed, 52 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c index 93942b211fcd..72ff7d42377e 100644 --- a/drivers/staging/wilc1000/coreconfigurator.c +++ b/drivers/staging/wilc1000/coreconfigurator.c @@ -706,11 +706,10 @@ u8 *get_tim_elm(u8 *pu8msa, u16 u16RxLen, u16 u16TagParamOffset) /* Search for the TIM Element Field and return if the element is found */ while (u16index < (u16RxLen - FCS_LEN)) { - if (pu8msa[u16index] == ITIM) { + if (pu8msa[u16index] == ITIM) return &pu8msa[u16index]; - } else { + else u16index += (IE_HDR_LEN + pu8msa[u16index + 1]); - } } return 0; @@ -1527,11 +1526,10 @@ s32 further_process_response(u8 *resp, u8 cfg_str[256] = {0}; tenuWIDtype enuWIDtype = WID_UNDEF; - if (process_wid_num) { + if (process_wid_num) enuWIDtype = get_wid_type(g_wid_num); - } else { + else enuWIDtype = gastrWIDs[cnt].enuWIDtype; - } switch (enuWIDtype) { diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 8b36683ef335..cc549c2c5213 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -1350,11 +1350,10 @@ static s32 Handle_Scan(void *drvHandler, tstrHostIFscanAttr *pstrHostIFscanAttr) /*keep the state as is , no need to change it*/ /* gWFiDrvHandle->enuHostIFstate = HOST_IF_SCANNING; */ - if (pstrWFIDrv->enuHostIFstate == HOST_IF_CONNECTED) { + if (pstrWFIDrv->enuHostIFstate == HOST_IF_CONNECTED) gbScanWhileConnected = true; - } else if (pstrWFIDrv->enuHostIFstate == HOST_IF_IDLE) { + else if (pstrWFIDrv->enuHostIFstate == HOST_IF_IDLE) gbScanWhileConnected = false; - } s32Error = SendConfigPkt(SET_CFG, strWIDList, u32WidsCount, false, (u32)pstrWFIDrv); @@ -2849,11 +2848,10 @@ static int Handle_Key(void *drvHandler, tstrHostIFkeyAttr *pstrHostIFkeyAttr) * |------------|---------|-------|------------|---------------|----------------| | 6 bytes | 8 byte |1 byte | 1 byte | 16 bytes | 8 bytes |*/ - if (pstrWFIDrv->enuHostIFstate == HOST_IF_CONNECTED) { + if (pstrWFIDrv->enuHostIFstate == HOST_IF_CONNECTED) WILC_memcpy(pu8keybuf, pstrWFIDrv->au8AssociatedBSSID, ETH_ALEN); - } else { + else PRINT_ER("Couldn't handle WPARxGtk while enuHostIFstate is not HOST_IF_CONNECTED\n"); - } WILC_memcpy(pu8keybuf + 6, pstrHostIFkeyAttr->uniHostIFkeyAttr.strHostIFwpaAttr.pu8seq, 8); @@ -4024,11 +4022,10 @@ static void Handle_PowerManagement(void *drvHandler, tstrHostIfPowerMgmtParam *s strWID.u16WIDid = (u16)WID_POWER_MANAGEMENT; - if (strPowerMgmtParam->bIsEnabled == true) { + if (strPowerMgmtParam->bIsEnabled == true) s8PowerMode = MIN_FAST_PS; - } else { + else s8PowerMode = NO_POWERSAVE; - } PRINT_D(HOSTINF_DBG, "Handling power mgmt to %d\n", s8PowerMode); strWID.ps8WidVal = &s8PowerMode; strWID.s32ValueSize = sizeof(char); @@ -5479,9 +5476,9 @@ s32 host_int_set_join_req(WILC_WFIDrvHandle hWFIDrv, u8 *pu8bssid, WILC_memcpy(strHostIFmsg.uniHostIFmsgBody.strHostIFconnectAttr.pu8IEs, pu8IEs, IEsLen); } - if (pstrWFIDrv->enuHostIFstate < HOST_IF_CONNECTING) { + if (pstrWFIDrv->enuHostIFstate < HOST_IF_CONNECTING) pstrWFIDrv->enuHostIFstate = HOST_IF_CONNECTING; - } else + else PRINT_D(GENERIC_DBG, "Don't set state to 'connecting' as state is %d\n", pstrWFIDrv->enuHostIFstate); /* send the message */ diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c index 92aa671ab1fd..1384846a5d01 100644 --- a/drivers/staging/wilc1000/linux_wlan.c +++ b/drivers/staging/wilc1000/linux_wlan.c @@ -422,11 +422,10 @@ static void isr_bh_routine(struct work_struct *work) int_rcvdB++; PRINT_D(INT_DBG, "Interrupt received BH\n"); - if (g_linux_wlan->oup.wlan_handle_rx_isr != 0) { + if (g_linux_wlan->oup.wlan_handle_rx_isr != 0) g_linux_wlan->oup.wlan_handle_rx_isr(); - } else { + else PRINT_ER("wlan_handle_rx_isr() hasn't been initialized\n"); - } #if (RX_BH_TYPE == RX_BH_THREADED_IRQ) return IRQ_HANDLED; @@ -450,11 +449,10 @@ static int isr_bh_routine(void *vp) } int_rcvdB++; PRINT_D(INT_DBG, "Interrupt received BH\n"); - if (g_linux_wlan->oup.wlan_handle_rx_isr != 0) { + if (g_linux_wlan->oup.wlan_handle_rx_isr != 0) g_linux_wlan->oup.wlan_handle_rx_isr(); - } else { + else PRINT_ER("wlan_handle_rx_isr() hasn't been initialized\n"); - } } return 0; @@ -607,22 +605,20 @@ static int linux_wlan_lock_timeout(void *vp, u32 timeout) { int error = -1; PRINT_D(LOCK_DBG, "Locking %p\n", vp); - if (vp != NULL) { + if (vp != NULL) error = down_timeout((struct semaphore *)vp, msecs_to_jiffies(timeout)); - } else { + else PRINT_ER("Failed, mutex is NULL\n"); - } return error; } void linux_wlan_unlock(void *vp) { PRINT_D(LOCK_DBG, "Unlocking %p\n", vp); - if (vp != NULL) { + if (vp != NULL) up((struct semaphore *)vp); - } else { + else PRINT_ER("Failed, mutex is NULL\n"); - } } static void linux_wlan_init_mutex(char *lockName, void *plock, int count) @@ -2125,11 +2121,10 @@ static void linux_wlan_tx_complete(void *priv, int status) { struct tx_complete_data *pv_data = (struct tx_complete_data *)priv; - if (status == 1) { + if (status == 1) PRINT_D(TX_DBG, "Packet sent successfully - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb); - } else { + else PRINT_D(TX_DBG, "Couldn't send packet - Size = %d - Address = %p - SKB = %p\n", pv_data->size, pv_data->buff, pv_data->skb); - } /* Free the SK Buffer, its work is done */ dev_kfree_skb(pv_data->skb); linux_wlan_free(pv_data); diff --git a/drivers/staging/wilc1000/wilc_debugfs.c b/drivers/staging/wilc1000/wilc_debugfs.c index c328208cda29..be2e901b448d 100644 --- a/drivers/staging/wilc1000/wilc_debugfs.c +++ b/drivers/staging/wilc1000/wilc_debugfs.c @@ -62,11 +62,10 @@ static ssize_t wilc_debug_level_write(struct file *filp, const char *buf, size_t flag = buffer[0] - '0'; - if (flag > 0) { + if (flag > 0) flag = DEBUG | ERR; - } else if (flag < 0) { + else if (flag < 0) flag = 100; - } if (flag > DBG_LEVEL_ALL) { printk("%s, value (0x%08x) is out of range, stay previous flag (0x%08x)\n", __func__, flag, atomic_read(&DEBUG_LEVEL)); @@ -75,11 +74,10 @@ static ssize_t wilc_debug_level_write(struct file *filp, const char *buf, size_t atomic_set(&DEBUG_LEVEL, (int)flag); - if (flag == 0) { + if (flag == 0) printk("Debug-level disabled\n"); - } else { + else printk("Debug-level enabled\n"); - } return count; } diff --git a/drivers/staging/wilc1000/wilc_memory.c b/drivers/staging/wilc1000/wilc_memory.c index c70707fefb66..34ef13e8e243 100644 --- a/drivers/staging/wilc1000/wilc_memory.c +++ b/drivers/staging/wilc1000/wilc_memory.c @@ -9,11 +9,10 @@ void *WILC_MemoryAlloc(u32 u32Size, tstrWILC_MemoryAttrs *strAttrs, char *pcFileName, u32 u32LineNo) { - if (u32Size > 0) { + if (u32Size > 0) return kmalloc(u32Size, GFP_ATOMIC); - } else { + else return NULL; - } } /*! diff --git a/drivers/staging/wilc1000/wilc_spi.c b/drivers/staging/wilc1000/wilc_spi.c index abea5df656d7..1bf7d314ae34 100644 --- a/drivers/staging/wilc1000/wilc_spi.c +++ b/drivers/staging/wilc1000/wilc_spi.c @@ -374,11 +374,10 @@ static int spi_cmd_complete(uint8_t cmd, uint32_t adr, uint8_t *b, uint32_t sz, return result; } - if (!g_spi.crc_off) { + if (!g_spi.crc_off) wb[len - 1] = (crc7(0x7f, (const uint8_t *)&wb[0], len - 1)) << 1; - } else { + else len -= 1; - } #define NUM_SKIP_BYTES (1) #define NUM_RSP_BYTES (2) @@ -522,11 +521,10 @@ static int spi_cmd_complete(uint8_t cmd, uint32_t adr, uint8_t *b, uint32_t sz, if (sz > 0) { int nbytes; - if (sz <= (DATA_PKT_SZ - ix)) { + if (sz <= (DATA_PKT_SZ - ix)) nbytes = sz; - } else { + else nbytes = DATA_PKT_SZ - ix; - } /** * Read bytes @@ -557,11 +555,10 @@ static int spi_cmd_complete(uint8_t cmd, uint32_t adr, uint8_t *b, uint32_t sz, while (sz > 0) { int nbytes; - if (sz <= DATA_PKT_SZ) { + if (sz <= DATA_PKT_SZ) nbytes = sz; - } else { + else nbytes = DATA_PKT_SZ; - } /** * read data response only on the next DMA cycles not diff --git a/drivers/staging/wilc1000/wilc_strutils.c b/drivers/staging/wilc1000/wilc_strutils.c index 3600706ed231..a32b9c13e872 100644 --- a/drivers/staging/wilc1000/wilc_strutils.c +++ b/drivers/staging/wilc1000/wilc_strutils.c @@ -41,11 +41,10 @@ s32 WILC_strncmp(const char *pcStr1, const char *pcStr2, s32Result = 1; } else { s32Result = strncmp(pcStr1, pcStr2, u32Count); - if (s32Result < 0) { + if (s32Result < 0) s32Result = -1; - } else if (s32Result > 0) { + else if (s32Result > 0) s32Result = 1; - } } return s32Result; diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c index 97df19393e7f..5c459679aa5a 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c @@ -443,11 +443,10 @@ static void CfgScanResult(tenuScanEvent enuScanEvent, tstrNetworkInfo *pstrNetwo PRINT_D(CFG80211_DBG, "Refreshing Scan ...\n"); refresh_scan(priv, 1, false); - if (priv->u32RcvdChCount > 0) { + if (priv->u32RcvdChCount > 0) PRINT_D(CFG80211_DBG, "%d Network(s) found\n", priv->u32RcvdChCount); - } else { + else PRINT_D(CFG80211_DBG, "No networks found\n"); - } down(&(priv->hSemScanReq)); @@ -1686,11 +1685,10 @@ static int WILC_WFI_get_station(struct wiphy *wiphy, struct net_device *dev, sinfo->txrate.legacy = strStatistics.u8LinkSpeed * 10; #ifdef TCP_ENHANCEMENTS - if ((strStatistics.u8LinkSpeed > TCP_ACK_FILTER_LINK_SPEED_THRESH) && (strStatistics.u8LinkSpeed != DEFAULT_LINK_SPEED)) { + if ((strStatistics.u8LinkSpeed > TCP_ACK_FILTER_LINK_SPEED_THRESH) && (strStatistics.u8LinkSpeed != DEFAULT_LINK_SPEED)) Enable_TCP_ACK_Filter(true); - } else if (strStatistics.u8LinkSpeed != DEFAULT_LINK_SPEED) { + else if (strStatistics.u8LinkSpeed != DEFAULT_LINK_SPEED) Enable_TCP_ACK_Filter(false); - } #endif PRINT_D(CORECONFIG_DBG, "*** stats[%d][%d][%d][%d][%d]\n", sinfo->signal, sinfo->rx_packets, sinfo->tx_packets, @@ -2059,11 +2057,10 @@ void WILC_WFI_CfgParseRxAction(u8 *buf, u32 len) } #endif /* USE_SUPPLICANT_GO_INTENT */ - if (buf[index] == CHANLIST_ATTR_ID) { + if (buf[index] == CHANLIST_ATTR_ID) channel_list_attr_index = index; - } else if (buf[index] == OPERCHAN_ATTR_ID) { + else if (buf[index] == OPERCHAN_ATTR_ID) op_channel_attr_index = index; - } index += buf[index + 1] + 3; /* ID,Length byte */ } @@ -2145,11 +2142,10 @@ void WILC_WFI_CfgParseTxAction(u8 *buf, u32 len, bool bOperChan, u8 iftype) } #endif - if (buf[index] == CHANLIST_ATTR_ID) { + if (buf[index] == CHANLIST_ATTR_ID) channel_list_attr_index = index; - } else if (buf[index] == OPERCHAN_ATTR_ID) { + else if (buf[index] == OPERCHAN_ATTR_ID) op_channel_attr_index = index; - } index += buf[index + 1] + 3; /* ID,Length byte */ } diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wilc_wlan.c index bd5c2564f313..192f36cde59e 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wilc_wlan.c @@ -463,11 +463,10 @@ static int wilc_wlan_txq_filter_dup_tcp_ack(void) Pending_Acks = 0; Opened_TCP_session = 0; - if (PendingAcks_arrBase == 0) { + if (PendingAcks_arrBase == 0) PendingAcks_arrBase = MAX_TCP_SESSION; - } else { + else PendingAcks_arrBase = 0; - } p->os_func.os_spin_unlock(p->txq_spinlock, &p->txq_spinlock_flags); @@ -1110,11 +1109,10 @@ static int wilc_wlan_handle_txq(uint32_t *pu32TxqCount) /*Bug3959: transmitting mgmt frames received from host*/ /*setting bit 30 in the host header to indicate mgmt frame*/ #ifdef WILC_AP_EXTERNAL_MLME - if (tqe->type == WILC_MGMT_PKT) { + if (tqe->type == WILC_MGMT_PKT) header |= (1 << 30); - } else { + else header &= ~(1 << 30); - } #endif #ifdef BIG_ENDIAN @@ -1541,11 +1539,10 @@ static int wilc_wlan_firmware_download(const uint8_t *buffer, uint32_t buffer_si acquire_bus(ACQUIRE_ONLY); offset += 8; while (((int)size) && (offset < buffer_size)) { - if (size <= blksz) { + if (size <= blksz) size2 = size; - } else { + else size2 = blksz; - } /* Copy firmware into a DMA coherent buffer */ memcpy(dma_buffer, &buffer[offset], size2); ret = p->hif_func.hif_block_tx(addr, dma_buffer, size2); @@ -2302,11 +2299,10 @@ u16 Set_machw_change_vir_if(bool bValue) PRINT_ER("Error while Reading reg WILC_CHANGING_VIR_IF\n"); } - if (bValue) { + if (bValue) reg |= (BIT31); - } else { + else reg &= ~(BIT31); - } ret = (&g_wlan)->hif_func.hif_write_reg(WILC_CHANGING_VIR_IF, reg); -- cgit v1.3-6-gb490 From c915aadb5d5ffddfd59170931873a5b102aa7d31 Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Sat, 8 Aug 2015 20:00:07 +0200 Subject: Staging: wilc1000: wilc_platform.h: Fixed include guard spelling error Fixed spelling error Signed-off-by: Daniel Machon Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/wilc_platform.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/wilc1000/wilc_platform.h b/drivers/staging/wilc1000/wilc_platform.h index d03532cc3af2..ccceaae212a5 100644 --- a/drivers/staging/wilc1000/wilc_platform.h +++ b/drivers/staging/wilc1000/wilc_platform.h @@ -1,5 +1,5 @@ -#ifndef __WILC_platfrom_H__ -#define __WILC_platfrom_H__ +#ifndef __WILC_platform_H__ +#define __WILC_platform_H__ #include #include -- cgit v1.3-6-gb490 From 550d35d816da2ad141cf05f176118df6f2c75cdb Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Sat, 8 Aug 2015 20:34:59 +0200 Subject: Staging: lustre/lnet/selftest: framework.c: Fixed coding style issues Fixed coding style issues where statement should be on the next line Signed-off-by: Daniel Machon Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lnet/selftest/framework.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lnet/selftest/framework.c b/drivers/staging/lustre/lnet/selftest/framework.c index 7c5185a2a795..257de3537671 100644 --- a/drivers/staging/lustre/lnet/selftest/framework.c +++ b/drivers/staging/lustre/lnet/selftest/framework.c @@ -203,7 +203,8 @@ sfw_deactivate_session(void) sfw_batch_t *tsb; sfw_test_case_t *tsc; - if (sn == NULL) return; + if (sn == NULL) + return; LASSERT(!sn->sn_timer_active); @@ -613,7 +614,8 @@ sfw_destroy_test_instance(sfw_test_instance_t *tsi) srpc_client_rpc_t *rpc; sfw_test_unit_t *tsu; - if (!tsi->tsi_is_client) goto clean; + if (!tsi->tsi_is_client) + goto clean; tsi->tsi_ops->tso_fini(tsi); @@ -1700,7 +1702,8 @@ sfw_startup(void) for (i = 0; ; i++) { sv = &sfw_services[i]; - if (sv->sv_name == NULL) break; + if (sv->sv_name == NULL) + break; sv->sv_bulk_ready = NULL; sv->sv_handler = sfw_handle_server_rpc; @@ -1717,7 +1720,8 @@ sfw_startup(void) } /* about to sfw_shutdown, no need to add buffer */ - if (error) continue; + if (error) + continue; rc = srpc_service_add_buffers(sv, sv->sv_wi_total); if (rc != 0) { -- cgit v1.3-6-gb490 From b963e7223cb3278dda35a6550a8df08ff2be2ee5 Mon Sep 17 00:00:00 2001 From: Daniel Machon Date: Sat, 8 Aug 2015 20:43:25 +0200 Subject: Staging: lustre/lustre/ptlrpc: service.c: Fixed issue with global integer being initialized to 0 Fixed global integer initialization issue. Global variables should not be explicitly initialized to 0 or NULL. Signed-off-by: Daniel Machon Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ptlrpc/service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/ptlrpc/service.c b/drivers/staging/lustre/lustre/ptlrpc/service.c index d3265a89538a..003344ccfffc 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/service.c +++ b/drivers/staging/lustre/lustre/ptlrpc/service.c @@ -43,7 +43,7 @@ #include "ptlrpc_internal.h" /* The following are visible and mutable through /sys/module/ptlrpc */ -int test_req_buffer_pressure = 0; +int test_req_buffer_pressure; module_param(test_req_buffer_pressure, int, 0444); MODULE_PARM_DESC(test_req_buffer_pressure, "set non-zero to put pressure on request buffer pools"); module_param(at_min, int, 0644); -- cgit v1.3-6-gb490 From 1eb38023ddb480276c6b75e0db6463c47251eb7b Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Fri, 7 Aug 2015 13:19:03 +0200 Subject: s390/dasd: fix failing path verification DASD path verification requires the usage of sleep_on_immediatly to ensure that no other I/O request is blocking the recovery of disconnected devices. But two concurrent path verification workers for the same device may kill each others requests due to the usage of the immediate sleep_on function. This may lead to unsuccessful path verifications. Prevent that two parallel path verification workers conflict with each other by implementing a device flag signalling a already running worker. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_eckd.c | 8 ++++++-- drivers/s390/block/dasd_int.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 6215f6455eb8..d8144513fadc 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1259,7 +1259,11 @@ static void do_path_verification_work(struct work_struct *work) schedule_work(work); return; } - + /* check if path verification already running and delay if so */ + if (test_and_set_bit(DASD_FLAG_PATH_VERIFY, &device->flags)) { + schedule_work(work); + return; + } opm = 0; npm = 0; ppm = 0; @@ -1402,7 +1406,7 @@ static void do_path_verification_work(struct work_struct *work) device->path_data.hpfpm |= hpfpm; spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); } - + clear_bit(DASD_FLAG_PATH_VERIFY, &device->flags); dasd_put_device(device); if (data->isglobal) mutex_unlock(&dasd_path_verification_mutex); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 227e3dea3155..4aed5ed70836 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -534,6 +534,7 @@ struct dasd_attention_data { #define DASD_FLAG_SAFE_OFFLINE 10 /* safe offline processing requested*/ #define DASD_FLAG_SAFE_OFFLINE_RUNNING 11 /* safe offline running */ #define DASD_FLAG_ABORTALL 12 /* Abort all noretry requests */ +#define DASD_FLAG_PATH_VERIFY 13 /* Path verification worker running */ #define DASD_SLEEPON_START_TAG ((void *) 1) #define DASD_SLEEPON_END_TAG ((void *) 2) -- cgit v1.3-6-gb490 From b179b037e568a27ab3e8f5bedea1f4455aba7378 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Fri, 7 Aug 2015 13:20:16 +0200 Subject: s390/dasd: enhance CUIR scope detection This patch adds an enhanced detection for control unit initiated reconfiguration request scope. The first approach assumed the scope of the reconfiguration request to be restricted to the path on which the message was received. The enhanced approach determines the full scope of the reconfiguration request by evaluating additional path and device selection information contained in the reconfiguration message. Reviewed-by: Peter Oberparleiter Reviewed-by: Sebastian Ott Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_eckd.c | 323 +++++++++++++++++++++++++++++++---------- drivers/s390/block/dasd_eckd.h | 11 +- 2 files changed, 255 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index d8144513fadc..72cdaae8ce99 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1036,7 +1036,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device) { void *conf_data; int conf_len, conf_data_saved; - int rc, path_err; + int rc, path_err, pos; __u8 lpm, opm; struct dasd_eckd_private *private, path_private; struct dasd_path *path_data; @@ -1068,6 +1068,17 @@ static int dasd_eckd_read_conf(struct dasd_device *device) path_data->opm |= lpm; continue; /* no error */ } + /* translate path mask to position in mask */ + pos = 8 - ffs(lpm); + kfree(private->path_conf_data[pos]); + if ((__u8 *)private->path_conf_data[pos] == + private->conf_data) { + private->conf_data = NULL; + private->conf_len = 0; + conf_data_saved = 0; + } + private->path_conf_data[pos] = + (struct dasd_conf_data *) conf_data; /* save first valid configuration data */ if (!conf_data_saved) { kfree(private->conf_data); @@ -1095,7 +1106,6 @@ static int dasd_eckd_read_conf(struct dasd_device *device) kfree(conf_data); continue; } - if (dasd_eckd_compare_path_uid( device, &path_private)) { uid = &path_private.uid; @@ -1157,9 +1167,6 @@ static int dasd_eckd_read_conf(struct dasd_device *device) path_data->cablepm &= ~lpm; path_data->hpfpm &= ~lpm; path_data->cuirpm &= ~lpm; - - if (conf_data != private->conf_data) - kfree(conf_data); } return path_err; @@ -1814,6 +1821,7 @@ out_err1: static void dasd_eckd_uncheck_device(struct dasd_device *device) { struct dasd_eckd_private *private; + int i; private = (struct dasd_eckd_private *) device->private; dasd_alias_disconnect_device_from_lcu(device); @@ -1822,6 +1830,15 @@ static void dasd_eckd_uncheck_device(struct dasd_device *device) private->vdsneq = NULL; private->gneq = NULL; private->conf_len = 0; + for (i = 0; i < 8; i++) { + kfree(private->path_conf_data[i]); + if ((__u8 *)private->path_conf_data[i] == + private->conf_data) { + private->conf_data = NULL; + private->conf_len = 0; + } + private->path_conf_data[i] = NULL; + } kfree(private->conf_data); private->conf_data = NULL; } @@ -4529,12 +4546,13 @@ static int dasd_eckd_read_message_buffer(struct dasd_device *device, cqr->startdev = device; cqr->memdev = device; cqr->block = NULL; - cqr->retries = 256; cqr->expires = 10 * HZ; - - /* we need to check for messages on exactly this path */ set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags); - cqr->lpm = lpum; + /* dasd_sleep_on_immediatly does not do complex error + * recovery so clear erp flag and set retry counter to + * do basic erp */ + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + cqr->retries = 256; /* Prepare for Read Subsystem Data */ prssdp = (struct dasd_psf_prssd_data *) cqr->data; @@ -4609,10 +4627,10 @@ dasd_eckd_psf_cuir_response(struct dasd_device *device, int response, psf_cuir->message_id = message_id; psf_cuir->cssid = sch_id.cssid; psf_cuir->ssid = sch_id.ssid; - ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_PSF; ccw->cda = (__u32)(addr_t)psf_cuir; + ccw->flags = CCW_FLAG_SLI; ccw->count = sizeof(struct dasd_psf_cuir_response); cqr->startdev = device; @@ -4622,6 +4640,7 @@ dasd_eckd_psf_cuir_response(struct dasd_device *device, int response, cqr->expires = 10*HZ; cqr->buildclk = get_tod_clock(); cqr->status = DASD_CQR_FILLED; + set_bit(DASD_CQR_VERIFY_PATH, &cqr->flags); rc = dasd_sleep_on(cqr); @@ -4629,118 +4648,252 @@ dasd_eckd_psf_cuir_response(struct dasd_device *device, int response, return rc; } -static int dasd_eckd_cuir_change_state(struct dasd_device *device, __u8 lpum) +/* + * return configuration data that is referenced by record selector + * if a record selector is specified or per default return the + * conf_data pointer for the path specified by lpum + */ +static struct dasd_conf_data *dasd_eckd_get_ref_conf(struct dasd_device *device, + __u8 lpum, + struct dasd_cuir_message *cuir) { - unsigned long flags; - __u8 tbcpm; + struct dasd_eckd_private *private; + struct dasd_conf_data *conf_data; + int path, pos; - spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); - tbcpm = device->path_data.opm & ~lpum; - if (tbcpm) { - device->path_data.opm = tbcpm; - device->path_data.cuirpm |= lpum; + private = (struct dasd_eckd_private *) device->private; + if (cuir->record_selector == 0) + goto out; + for (path = 0x80, pos = 0; path; path >>= 1, pos++) { + conf_data = private->path_conf_data[pos]; + if (conf_data->gneq.record_selector == + cuir->record_selector) + return conf_data; } - spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); - return tbcpm ? 0 : PSF_CUIR_LAST_PATH; +out: + return private->path_conf_data[8 - ffs(lpum)]; } /* - * walk through all devices and quiesce them - * if it is the last path return error + * This function determines the scope of a reconfiguration request by + * analysing the path and device selection data provided in the CUIR request. + * Returns a path mask containing CUIR affected paths for the give device. + * + * If the CUIR request does not contain the required information return the + * path mask of the path the attention message for the CUIR request was reveived + * on. + */ +static int dasd_eckd_cuir_scope(struct dasd_device *device, __u8 lpum, + struct dasd_cuir_message *cuir) +{ + struct dasd_conf_data *ref_conf_data; + unsigned long bitmask = 0, mask = 0; + struct dasd_eckd_private *private; + struct dasd_conf_data *conf_data; + unsigned int pos, path; + char *ref_gneq, *gneq; + char *ref_ned, *ned; + int tbcpm = 0; + + /* if CUIR request does not specify the scope use the path + the attention message was presented on */ + if (!cuir->ned_map || + !(cuir->neq_map[0] | cuir->neq_map[1] | cuir->neq_map[2])) + return lpum; + + private = (struct dasd_eckd_private *) device->private; + /* get reference conf data */ + ref_conf_data = dasd_eckd_get_ref_conf(device, lpum, cuir); + /* reference ned is determined by ned_map field */ + pos = 8 - ffs(cuir->ned_map); + ref_ned = (char *)&ref_conf_data->neds[pos]; + ref_gneq = (char *)&ref_conf_data->gneq; + /* transfer 24 bit neq_map to mask */ + mask = cuir->neq_map[2]; + mask |= cuir->neq_map[1] << 8; + mask |= cuir->neq_map[0] << 16; + + for (path = 0x80; path; path >>= 1) { + /* initialise data per path */ + bitmask = mask; + pos = 8 - ffs(path); + conf_data = private->path_conf_data[pos]; + pos = 8 - ffs(cuir->ned_map); + ned = (char *) &conf_data->neds[pos]; + /* compare reference ned and per path ned */ + if (memcmp(ref_ned, ned, sizeof(*ned)) != 0) + continue; + gneq = (char *)&conf_data->gneq; + /* compare reference gneq and per_path gneq under + 24 bit mask where mask bit 0 equals byte 7 of + the gneq and mask bit 24 equals byte 31 */ + while (bitmask) { + pos = ffs(bitmask) - 1; + if (memcmp(&ref_gneq[31 - pos], &gneq[31 - pos], 1) + != 0) + break; + clear_bit(pos, &bitmask); + } + if (bitmask) + continue; + /* device and path match the reference values + add path to CUIR scope */ + tbcpm |= path; + } + return tbcpm; +} + +static void dasd_eckd_cuir_notify_user(struct dasd_device *device, + unsigned long paths, + struct subchannel_id sch_id, int action) +{ + struct channel_path_desc *desc; + int pos; + + while (paths) { + /* get position of bit in mask */ + pos = ffs(paths) - 1; + /* get channel path descriptor from this position */ + desc = ccw_device_get_chp_desc(device->cdev, 7 - pos); + if (action == CUIR_QUIESCE) + pr_warn("Service on the storage server caused path " + "%x.%02x to go offline", sch_id.cssid, + desc ? desc->chpid : 0); + else if (action == CUIR_RESUME) + pr_info("Path %x.%02x is back online after service " + "on the storage server", sch_id.cssid, + desc ? desc->chpid : 0); + kfree(desc); + clear_bit(pos, &paths); + } +} + +static int dasd_eckd_cuir_remove_path(struct dasd_device *device, __u8 lpum, + struct dasd_cuir_message *cuir) +{ + unsigned long tbcpm; + + tbcpm = dasd_eckd_cuir_scope(device, lpum, cuir); + /* nothing to do if path is not in use */ + if (!(device->path_data.opm & tbcpm)) + return 0; + if (!(device->path_data.opm & ~tbcpm)) { + /* no path would be left if the CUIR action is taken + return error */ + return -EINVAL; + } + /* remove device from operational path mask */ + device->path_data.opm &= ~tbcpm; + device->path_data.cuirpm |= tbcpm; + return tbcpm; +} + +/* + * walk through all devices and build a path mask to quiesce them + * return an error if the last path to a device would be removed * * if only part of the devices are quiesced and an error * occurs no onlining necessary, the storage server will * notify the already set offline devices again */ static int dasd_eckd_cuir_quiesce(struct dasd_device *device, __u8 lpum, - struct channel_path_desc *desc, - struct subchannel_id sch_id) + struct subchannel_id sch_id, + struct dasd_cuir_message *cuir) { struct alias_pav_group *pavgroup, *tempgroup; struct dasd_eckd_private *private; struct dasd_device *dev, *n; - int rc; + unsigned long paths = 0; + unsigned long flags; + int tbcpm; private = (struct dasd_eckd_private *) device->private; - rc = 0; - /* active devices */ - list_for_each_entry_safe(dev, n, - &private->lcu->active_devices, + list_for_each_entry_safe(dev, n, &private->lcu->active_devices, alias_list) { - rc = dasd_eckd_cuir_change_state(dev, lpum); - if (rc) - goto out; + spin_lock_irqsave(get_ccwdev_lock(dev->cdev), flags); + tbcpm = dasd_eckd_cuir_remove_path(dev, lpum, cuir); + spin_unlock_irqrestore(get_ccwdev_lock(dev->cdev), flags); + if (tbcpm < 0) + goto out_err; + paths |= tbcpm; } - /* inactive devices */ - list_for_each_entry_safe(dev, n, - &private->lcu->inactive_devices, + list_for_each_entry_safe(dev, n, &private->lcu->inactive_devices, alias_list) { - rc = dasd_eckd_cuir_change_state(dev, lpum); - if (rc) - goto out; + spin_lock_irqsave(get_ccwdev_lock(dev->cdev), flags); + tbcpm = dasd_eckd_cuir_remove_path(dev, lpum, cuir); + spin_unlock_irqrestore(get_ccwdev_lock(dev->cdev), flags); + if (tbcpm < 0) + goto out_err; + paths |= tbcpm; } - /* devices in PAV groups */ list_for_each_entry_safe(pavgroup, tempgroup, &private->lcu->grouplist, group) { list_for_each_entry_safe(dev, n, &pavgroup->baselist, alias_list) { - rc = dasd_eckd_cuir_change_state(dev, lpum); - if (rc) - goto out; + spin_lock_irqsave(get_ccwdev_lock(dev->cdev), flags); + tbcpm = dasd_eckd_cuir_remove_path(dev, lpum, cuir); + spin_unlock_irqrestore( + get_ccwdev_lock(dev->cdev), flags); + if (tbcpm < 0) + goto out_err; + paths |= tbcpm; } list_for_each_entry_safe(dev, n, &pavgroup->aliaslist, alias_list) { - rc = dasd_eckd_cuir_change_state(dev, lpum); - if (rc) - goto out; + spin_lock_irqsave(get_ccwdev_lock(dev->cdev), flags); + tbcpm = dasd_eckd_cuir_remove_path(dev, lpum, cuir); + spin_unlock_irqrestore( + get_ccwdev_lock(dev->cdev), flags); + if (tbcpm < 0) + goto out_err; + paths |= tbcpm; } } - - pr_warn("Service on the storage server caused path %x.%02x to go offline", - sch_id.cssid, desc ? desc->chpid : 0); - rc = PSF_CUIR_COMPLETED; -out: - return rc; + /* notify user about all paths affected by CUIR action */ + dasd_eckd_cuir_notify_user(device, paths, sch_id, CUIR_QUIESCE); + return 0; +out_err: + return tbcpm; } static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum, - struct channel_path_desc *desc, - struct subchannel_id sch_id) + struct subchannel_id sch_id, + struct dasd_cuir_message *cuir) { struct alias_pav_group *pavgroup, *tempgroup; struct dasd_eckd_private *private; struct dasd_device *dev, *n; + unsigned long paths = 0; + int tbcpm; - pr_info("Path %x.%02x is back online after service on the storage server", - sch_id.cssid, desc ? desc->chpid : 0); private = (struct dasd_eckd_private *) device->private; - /* * the path may have been added through a generic path event before * only trigger path verification if the path is not already in use */ - list_for_each_entry_safe(dev, n, &private->lcu->active_devices, alias_list) { - if (!(dev->path_data.opm & lpum)) { - dev->path_data.tbvpm |= lpum; + tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); + paths |= tbcpm; + if (!(dev->path_data.opm & tbcpm)) { + dev->path_data.tbvpm |= tbcpm; dasd_schedule_device_bh(dev); } } - list_for_each_entry_safe(dev, n, &private->lcu->inactive_devices, alias_list) { - if (!(dev->path_data.opm & lpum)) { - dev->path_data.tbvpm |= lpum; + tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); + paths |= tbcpm; + if (!(dev->path_data.opm & tbcpm)) { + dev->path_data.tbvpm |= tbcpm; dasd_schedule_device_bh(dev); } } - /* devices in PAV groups */ list_for_each_entry_safe(pavgroup, tempgroup, &private->lcu->grouplist, @@ -4748,21 +4901,27 @@ static int dasd_eckd_cuir_resume(struct dasd_device *device, __u8 lpum, list_for_each_entry_safe(dev, n, &pavgroup->baselist, alias_list) { - if (!(dev->path_data.opm & lpum)) { - dev->path_data.tbvpm |= lpum; + tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); + paths |= tbcpm; + if (!(dev->path_data.opm & tbcpm)) { + dev->path_data.tbvpm |= tbcpm; dasd_schedule_device_bh(dev); } } list_for_each_entry_safe(dev, n, &pavgroup->aliaslist, alias_list) { - if (!(dev->path_data.opm & lpum)) { - dev->path_data.tbvpm |= lpum; + tbcpm = dasd_eckd_cuir_scope(dev, lpum, cuir); + paths |= tbcpm; + if (!(dev->path_data.opm & tbcpm)) { + dev->path_data.tbvpm |= tbcpm; dasd_schedule_device_bh(dev); } } } - return PSF_CUIR_COMPLETED; + /* notify user about all paths affected by CUIR action */ + dasd_eckd_cuir_notify_user(device, paths, sch_id, CUIR_RESUME); + return 0; } static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages, @@ -4772,8 +4931,12 @@ static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages, struct channel_path_desc *desc; struct subchannel_id sch_id; int pos, response; - ccw_device_get_schid(device->cdev, &sch_id); + DBF_DEV_EVENT(DBF_WARNING, device, + "CUIR request: %016llx %016llx %016llx %08x", + ((u64 *)cuir)[0], ((u64 *)cuir)[1], ((u64 *)cuir)[2], + ((u32 *)cuir)[3]); + ccw_device_get_schid(device->cdev, &sch_id); /* get position of path in mask */ pos = 8 - ffs(lpum); /* get channel path descriptor from this position */ @@ -4781,18 +4944,26 @@ static void dasd_eckd_handle_cuir(struct dasd_device *device, void *messages, if (cuir->code == CUIR_QUIESCE) { /* quiesce */ - response = dasd_eckd_cuir_quiesce(device, lpum, desc, sch_id); + if (dasd_eckd_cuir_quiesce(device, lpum, sch_id, cuir)) + response = PSF_CUIR_LAST_PATH; + else + response = PSF_CUIR_COMPLETED; } else if (cuir->code == CUIR_RESUME) { /* resume */ - response = dasd_eckd_cuir_resume(device, lpum, desc, sch_id); + dasd_eckd_cuir_resume(device, lpum, sch_id, cuir); + response = PSF_CUIR_COMPLETED; } else response = PSF_CUIR_NOT_SUPPORTED; - dasd_eckd_psf_cuir_response(device, response, cuir->message_id, - desc, sch_id); - + dasd_eckd_psf_cuir_response(device, response, + cuir->message_id, desc, sch_id); + DBF_DEV_EVENT(DBF_WARNING, device, + "CUIR response: %d on message ID %08x", response, + cuir->message_id); /* free descriptor copy */ kfree(desc); + /* to make sure there is no attention left schedule work again */ + device->discipline->check_attention(device, lpum); } static void dasd_eckd_check_attention_work(struct work_struct *work) @@ -4804,22 +4975,18 @@ static void dasd_eckd_check_attention_work(struct work_struct *work) data = container_of(work, struct check_attention_work_data, worker); device = data->device; - messages = kzalloc(sizeof(*messages), GFP_KERNEL); if (!messages) { DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Could not allocate attention message buffer"); goto out; } - rc = dasd_eckd_read_message_buffer(device, messages, data->lpum); if (rc) goto out; - if (messages->length == ATTENTION_LENGTH_CUIR && messages->format == ATTENTION_FORMAT_CUIR) dasd_eckd_handle_cuir(device, messages, data->lpum); - out: dasd_put_device(device); kfree(messages); diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index ddab7df36e25..f8f91ee652d3 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -355,7 +355,8 @@ struct dasd_gneq { __u8 identifier:2; __u8 reserved:6; } __attribute__ ((packed)) flags; - __u8 reserved[5]; + __u8 record_selector; + __u8 reserved[4]; struct { __u8 value:2; __u8 number:6; @@ -492,10 +493,18 @@ struct alias_pav_group { struct dasd_device *next; }; +struct dasd_conf_data { + struct dasd_ned neds[5]; + u8 reserved[64]; + struct dasd_gneq gneq; +} __packed; + struct dasd_eckd_private { struct dasd_eckd_characteristics rdc_data; u8 *conf_data; int conf_len; + /* per path configuration data */ + struct dasd_conf_data *path_conf_data[8]; /* pointers to specific parts in the conf_data */ struct dasd_ned *ned; struct dasd_sneq *sneq; -- cgit v1.3-6-gb490 From fcdc5739dce03d8050ebfa7153412c2efcdee94f Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Wed, 1 Jul 2015 09:52:23 +0300 Subject: hwmon: (nct7802) add temperature sensor type attribute Sensor type: 3 diode (current mode), MD=1 4 thermistor, MD=2 Reference: Nuvoton Hardware Monitoring IC NCT7802Y 7.2.32 Mode Selection Register Location : Index 22h Signed-off-by: Constantine Shulyupin Signed-off-by: Guenter Roeck --- drivers/hwmon/nct7802.c | 72 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index fbfc02bb2cfa..344cbec79802 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -49,7 +49,7 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = { #define REG_VOLTAGE_LOW 0x0f #define REG_FANCOUNT_LOW 0x13 #define REG_START 0x21 -#define REG_MODE 0x22 +#define REG_MODE 0x22 /* 7.2.32 Mode Selection Register */ #define REG_PECI_ENABLE 0x23 #define REG_FAN_ENABLE 0x24 #define REG_VMON_ENABLE 0x25 @@ -66,6 +66,43 @@ struct nct7802_data { struct mutex access_lock; /* for multi-byte read and write operations */ }; +static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct nct7802_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + unsigned int mode; + int ret; + + ret = regmap_read(data->regmap, REG_MODE, &mode); + if (ret < 0) + return ret; + + return sprintf(buf, "%u\n", (mode >> (2 * sattr->index) & 3) + 2); +} + +static ssize_t store_temp_type(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nct7802_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + unsigned int type; + int err; + + err = kstrtouint(buf, 0, &type); + if (err < 0) + return err; + if (sattr->index == 2 && type != 4) /* RD3 */ + return -EINVAL; + if (type < 3 || type > 4) + return -EINVAL; + err = regmap_update_bits(data->regmap, REG_MODE, + 3 << 2 * sattr->index, (type - 2) << 2 * sattr->index); + return err ? : count; +} + + static int nct7802_read_temp(struct nct7802_data *data, u8 reg_temp, u8 reg_temp_low, int *temp) { @@ -377,6 +414,8 @@ store_beep(struct device *dev, struct device_attribute *attr, const char *buf, return err ? : count; } +static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR, + show_temp_type, store_temp_type, 0); static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0x01, REG_TEMP_LSB); static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, @@ -386,6 +425,8 @@ static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x3a, 0); +static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, + show_temp_type, store_temp_type, 1); static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0x02, REG_TEMP_LSB); static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, @@ -395,6 +436,8 @@ static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x3b, 0); +static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, + show_temp_type, store_temp_type, 2); static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0x03, REG_TEMP_LSB); static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, @@ -475,6 +518,7 @@ static SENSOR_DEVICE_ATTR_2(temp6_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, 0x5c, 5); static struct attribute *nct7802_temp_attrs[] = { + &sensor_dev_attr_temp1_type.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, @@ -485,7 +529,8 @@ static struct attribute *nct7802_temp_attrs[] = { &sensor_dev_attr_temp1_fault.dev_attr.attr, &sensor_dev_attr_temp1_beep.dev_attr.attr, - &sensor_dev_attr_temp2_input.dev_attr.attr, /* 9 */ + &sensor_dev_attr_temp2_type.dev_attr.attr, /* 10 */ + &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, @@ -495,7 +540,8 @@ static struct attribute *nct7802_temp_attrs[] = { &sensor_dev_attr_temp2_fault.dev_attr.attr, &sensor_dev_attr_temp2_beep.dev_attr.attr, - &sensor_dev_attr_temp3_input.dev_attr.attr, /* 18 */ + &sensor_dev_attr_temp3_type.dev_attr.attr, /* 20 */ + &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_crit.dev_attr.attr, @@ -505,7 +551,7 @@ static struct attribute *nct7802_temp_attrs[] = { &sensor_dev_attr_temp3_fault.dev_attr.attr, &sensor_dev_attr_temp3_beep.dev_attr.attr, - &sensor_dev_attr_temp4_input.dev_attr.attr, /* 27 */ + &sensor_dev_attr_temp4_input.dev_attr.attr, /* 30 */ &sensor_dev_attr_temp4_min.dev_attr.attr, &sensor_dev_attr_temp4_max.dev_attr.attr, &sensor_dev_attr_temp4_crit.dev_attr.attr, @@ -514,7 +560,7 @@ static struct attribute *nct7802_temp_attrs[] = { &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp4_beep.dev_attr.attr, - &sensor_dev_attr_temp5_input.dev_attr.attr, /* 35 */ + &sensor_dev_attr_temp5_input.dev_attr.attr, /* 38 */ &sensor_dev_attr_temp5_min.dev_attr.attr, &sensor_dev_attr_temp5_max.dev_attr.attr, &sensor_dev_attr_temp5_crit.dev_attr.attr, @@ -523,7 +569,7 @@ static struct attribute *nct7802_temp_attrs[] = { &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp5_beep.dev_attr.attr, - &sensor_dev_attr_temp6_input.dev_attr.attr, /* 43 */ + &sensor_dev_attr_temp6_input.dev_attr.attr, /* 46 */ &sensor_dev_attr_temp6_beep.dev_attr.attr, NULL @@ -541,25 +587,27 @@ static umode_t nct7802_temp_is_visible(struct kobject *kobj, if (err < 0) return 0; - if (index < 9 && + if (index < 10 && (reg & 03) != 0x01 && (reg & 0x03) != 0x02) /* RD1 */ return 0; - if (index >= 9 && index < 18 && + + if (index >= 10 && index < 20 && (reg & 0x0c) != 0x04 && (reg & 0x0c) != 0x08) /* RD2 */ return 0; - if (index >= 18 && index < 27 && (reg & 0x30) != 0x20) /* RD3 */ + if (index >= 20 && index < 30 && (reg & 0x30) != 0x20) /* RD3 */ return 0; - if (index >= 27 && index < 35) /* local */ + + if (index >= 30 && index < 38) /* local */ return attr->mode; err = regmap_read(data->regmap, REG_PECI_ENABLE, ®); if (err < 0) return 0; - if (index >= 35 && index < 43 && !(reg & 0x01)) /* PECI 0 */ + if (index >= 38 && index < 46 && !(reg & 0x01)) /* PECI 0 */ return 0; - if (index >= 0x43 && (!(reg & 0x02))) /* PECI 1 */ + if (index >= 0x46 && (!(reg & 0x02))) /* PECI 1 */ return 0; return attr->mode; -- cgit v1.3-6-gb490 From ea33597c6f9862d7b926bdb9c3ac25012f307dd5 Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Sat, 4 Jul 2015 21:49:51 +0300 Subject: hwmon: (nct7802) Add pwm control Added fan output control registers. Modes of operation are PWM (default) and DC. Introduced show_pwm, store_pwm, nct7802_pwm_attrs, nct7802_pwm_group. Signed-off-by: Guenter Roeck --- drivers/hwmon/nct7802.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'drivers') diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 344cbec79802..457b0f2678a4 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -102,6 +102,36 @@ static ssize_t store_temp_type(struct device *dev, return err ? : count; } +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct nct7802_data *data = dev_get_drvdata(dev); + unsigned int val; + int ret; + + ret = regmap_read(data->regmap, attr->index, &val); + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", val); +} + +static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct nct7802_data *data = dev_get_drvdata(dev); + int err; + u8 val; + + err = kstrtou8(buf, 0, &val); + if (err < 0) + return err; + + err = regmap_write(data->regmap, attr->index, val); + return err ? : count; +} static int nct7802_read_temp(struct nct7802_data *data, u8 reg_temp, u8 reg_temp_low, int *temp) @@ -735,6 +765,11 @@ static SENSOR_DEVICE_ATTR_2(fan3_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 2); static SENSOR_DEVICE_ATTR_2(fan3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, 0x5b, 2); +/* 7.2.91... Fan Control Output Value */ +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x60); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x61); +static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x62); + static struct attribute *nct7802_fan_attrs[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, @@ -773,10 +808,22 @@ static struct attribute_group nct7802_fan_group = { .is_visible = nct7802_fan_is_visible, }; +static struct attribute *nct7802_pwm_attrs[] = { + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, + NULL +}; + +static struct attribute_group nct7802_pwm_group = { + .attrs = nct7802_pwm_attrs, +}; + static const struct attribute_group *nct7802_groups[] = { &nct7802_temp_group, &nct7802_in_group, &nct7802_fan_group, + &nct7802_pwm_group, NULL }; -- cgit v1.3-6-gb490 From 876420e05a0fda4801c0a0de67e9bbe9831dffee Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Sun, 5 Jul 2015 01:41:31 +0300 Subject: hwmon: (nct7802) Add pwm mode attributes Introduced: show_pwm_mode, pwm1_mode, pwm2_mode, pwm2_mode Signed-off-by: Guenter Roeck --- drivers/hwmon/nct7802.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 457b0f2678a4..1c80aa48ee04 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -102,6 +102,24 @@ static ssize_t store_temp_type(struct device *dev, return err ? : count; } +static ssize_t show_pwm_mode(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + struct nct7802_data *data = dev_get_drvdata(dev); + unsigned int regval; + int ret; + + if (sattr->index > 1) + return sprintf(buf, "1\n"); + + ret = regmap_read(data->regmap, 0x5E, ®val); + if (ret < 0) + return ret; + + return sprintf(buf, "%u\n", !(regval & (1 << sattr->index))); +} + static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -765,6 +783,11 @@ static SENSOR_DEVICE_ATTR_2(fan3_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 2); static SENSOR_DEVICE_ATTR_2(fan3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep, 0x5b, 2); +/* 7.2.89 Fan Control Output Type */ +static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0); +static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO, show_pwm_mode, NULL, 1); +static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2); + /* 7.2.91... Fan Control Output Value */ static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x60); static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x61); @@ -809,8 +832,11 @@ static struct attribute_group nct7802_fan_group = { }; static struct attribute *nct7802_pwm_attrs[] = { + &sensor_dev_attr_pwm1_mode.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2_mode.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3_mode.dev_attr.attr, &sensor_dev_attr_pwm3.dev_attr.attr, NULL }; -- cgit v1.3-6-gb490 From 2725fe2b74e264a649af72beaaf6cc2c2e1f3495 Mon Sep 17 00:00:00 2001 From: Peter Hung Date: Tue, 7 Jul 2015 16:22:36 +0800 Subject: hwmon: (f71882fg) Add support for F81866 and F71868 Add New Fintek SuperIO F81866(0x1010) & F71868(0x1106) with H/W Monitor functions. We increased F71882FG_MAX_INS from 9 to 10 to read F71868 10 voltage sets. Signed-off-by: Peter Hung Signed-off-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 53 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 2e5c6f46e442..3a7185ab6c50 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -51,6 +51,7 @@ #define SIO_F71808A_ID 0x1001 /* Chipset ID */ #define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ +#define SIO_F71868_ID 0x1106 /* Chipset ID */ #define SIO_F71869_ID 0x0814 /* Chipset ID */ #define SIO_F71869A_ID 0x1007 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ @@ -59,6 +60,7 @@ #define SIO_F71889A_ID 0x1005 /* Chipset ID */ #define SIO_F8000_ID 0x0581 /* Chipset ID */ #define SIO_F81865_ID 0x0704 /* Chipset ID */ +#define SIO_F81866_ID 0x1010 /* Chipset ID */ #define REGION_LENGTH 8 #define ADDR_REG_OFFSET 5 @@ -101,7 +103,7 @@ #define F71882FG_REG_START 0x01 -#define F71882FG_MAX_INS 9 +#define F71882FG_MAX_INS 10 #define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */ @@ -109,14 +111,15 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); -enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71869a, f71882fg, - f71889fg, f71889ed, f71889a, f8000, f81865f }; +enum chips { f71808e, f71808a, f71858fg, f71862fg, f71868a, f71869, f71869a, + f71882fg, f71889fg, f71889ed, f71889a, f8000, f81865f, f81866a}; static const char *const f71882fg_names[] = { "f71808e", "f71808a", "f71858fg", "f71862fg", + "f71868a", "f71869", /* Both f71869f and f71869e, reg. compatible and same id */ "f71869a", "f71882fg", @@ -125,21 +128,24 @@ static const char *const f71882fg_names[] = { "f71889a", "f8000", "f81865f", + "f81866a", }; static const char f71882fg_has_in[][F71882FG_MAX_INS] = { - [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1 }, - [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1 }, - [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, - [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, - [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1, 0 }, + [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1, 0 }, + [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, + [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71868a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, + [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + [f81866a] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, }; static const char f71882fg_has_in1_alarm[] = { @@ -147,6 +153,7 @@ static const char f71882fg_has_in1_alarm[] = { [f71808a] = 0, [f71858fg] = 0, [f71862fg] = 0, + [f71868a] = 0, [f71869] = 0, [f71869a] = 0, [f71882fg] = 1, @@ -155,6 +162,7 @@ static const char f71882fg_has_in1_alarm[] = { [f71889a] = 1, [f8000] = 0, [f81865f] = 1, + [f81866a] = 1, }; static const char f71882fg_fan_has_beep[] = { @@ -162,6 +170,7 @@ static const char f71882fg_fan_has_beep[] = { [f71808a] = 0, [f71858fg] = 0, [f71862fg] = 1, + [f71868a] = 1, [f71869] = 1, [f71869a] = 1, [f71882fg] = 1, @@ -170,6 +179,7 @@ static const char f71882fg_fan_has_beep[] = { [f71889a] = 1, [f8000] = 0, [f81865f] = 1, + [f81866a] = 1, }; static const char f71882fg_nr_fans[] = { @@ -177,6 +187,7 @@ static const char f71882fg_nr_fans[] = { [f71808a] = 2, /* +1 fan which is monitor + simple pwm only */ [f71858fg] = 3, [f71862fg] = 3, + [f71868a] = 3, [f71869] = 3, [f71869a] = 3, [f71882fg] = 4, @@ -185,6 +196,7 @@ static const char f71882fg_nr_fans[] = { [f71889a] = 3, [f8000] = 3, /* +1 fan which is monitor only */ [f81865f] = 2, + [f81866a] = 3, }; static const char f71882fg_temp_has_beep[] = { @@ -192,6 +204,7 @@ static const char f71882fg_temp_has_beep[] = { [f71808a] = 1, [f71858fg] = 0, [f71862fg] = 1, + [f71868a] = 1, [f71869] = 1, [f71869a] = 1, [f71882fg] = 1, @@ -200,6 +213,7 @@ static const char f71882fg_temp_has_beep[] = { [f71889a] = 1, [f8000] = 0, [f81865f] = 1, + [f81866a] = 1, }; static const char f71882fg_nr_temps[] = { @@ -207,6 +221,7 @@ static const char f71882fg_nr_temps[] = { [f71808a] = 2, [f71858fg] = 3, [f71862fg] = 3, + [f71868a] = 3, [f71869] = 3, [f71869a] = 3, [f71882fg] = 3, @@ -215,6 +230,7 @@ static const char f71882fg_nr_temps[] = { [f71889a] = 3, [f8000] = 3, [f81865f] = 2, + [f81866a] = 3, }; static struct platform_device *f71882fg_pdev; @@ -531,6 +547,7 @@ static struct sensor_device_attribute_2 fxxxx_in_attr[] = { SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6), SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7), SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8), + SENSOR_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 0, 9), }; /* For models with in1 alarm capability */ @@ -2551,6 +2568,9 @@ static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data) case SIO_F71862_ID: sio_data->type = f71862fg; break; + case SIO_F71868_ID: + sio_data->type = f71868a; + break; case SIO_F71869_ID: sio_data->type = f71869; break; @@ -2575,6 +2595,9 @@ static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data) case SIO_F81865_ID: sio_data->type = f81865f; break; + case SIO_F81866_ID: + sio_data->type = f81866a; + break; default: pr_info("Unsupported Fintek device: %04x\n", (unsigned int)devid); -- cgit v1.3-6-gb490 From dcd956fc0b01135e6a00922165e653178d2b177b Mon Sep 17 00:00:00 2001 From: Peter Hung Date: Tue, 7 Jul 2015 16:22:37 +0800 Subject: hwmon: (f71882fg) Fix f81866a temp/beep setting The temperature value of Fintek F81866 is the same with f71882fg. It located with 0x6c + 2*(nr), others located with 0x6c + 2*(nr+1). We change the rule in f71882fg_probe(), If type = f71858fg/f8000/f81866a. the temp_start will set to 0, others are 1. The F81866 over-temperature beep setting is not the same with f71882fg too. They are using the same address 63H, but F81866 is using bit 0/1/2 & 4/5/6, others are using bit 1/2/3 & 5/6/7, So we copy from fxxxx_temp_beep_attr[] to f81866_temp_beep_attr and change bit setting. Signed-off-by: Peter Hung Signed-off-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 60 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 3a7185ab6c50..79f1f50de451 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -506,6 +506,23 @@ static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { { store_temp_beep, 0, 7), } }; +static struct sensor_device_attribute_2 f81866_temp_beep_attr[3][2] = { { + SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 0), + SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 4), +}, { + SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 1), + SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 5), +}, { + SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 2), + SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0, 6), +} }; + /* * Temp attr for the f8000 * Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max) @@ -2287,6 +2304,7 @@ static int f71882fg_probe(struct platform_device *pdev) int nr_fans = f71882fg_nr_fans[sio_data->type]; int nr_temps = f71882fg_nr_temps[sio_data->type]; int err, i; + int size; u8 start_reg, reg; data = devm_kzalloc(&pdev->dev, sizeof(struct f71882fg_data), @@ -2297,7 +2315,8 @@ static int f71882fg_probe(struct platform_device *pdev) data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; data->type = sio_data->type; data->temp_start = - (data->type == f71858fg || data->type == f8000) ? 0 : 1; + (data->type == f71858fg || data->type == f8000 || + data->type == f81866a) ? 0 : 1; mutex_init(&data->update_lock); platform_set_drvdata(pdev, data); @@ -2339,6 +2358,11 @@ static int f71882fg_probe(struct platform_device *pdev) f8000_temp_attr, ARRAY_SIZE(f8000_temp_attr)); break; + case f81866a: + err = f71882fg_create_sysfs_files(pdev, + f71858fg_temp_attr, + ARRAY_SIZE(f71858fg_temp_attr)); + break; default: err = f71882fg_create_sysfs_files(pdev, &fxxxx_temp_attr[0][0], @@ -2348,10 +2372,18 @@ static int f71882fg_probe(struct platform_device *pdev) goto exit_unregister_sysfs; if (f71882fg_temp_has_beep[data->type]) { - err = f71882fg_create_sysfs_files(pdev, - &fxxxx_temp_beep_attr[0][0], - ARRAY_SIZE(fxxxx_temp_beep_attr[0]) - * nr_temps); + if (data->type == f81866a) { + size = ARRAY_SIZE(f81866_temp_beep_attr[0]); + err = f71882fg_create_sysfs_files(pdev, + &f81866_temp_beep_attr[0][0], + size * nr_temps); + + } else { + size = ARRAY_SIZE(fxxxx_temp_beep_attr[0]); + err = f71882fg_create_sysfs_files(pdev, + &fxxxx_temp_beep_attr[0][0], + size * nr_temps); + } if (err) goto exit_unregister_sysfs; } @@ -2468,15 +2500,27 @@ static int f71882fg_remove(struct platform_device *pdev) f8000_temp_attr, ARRAY_SIZE(f8000_temp_attr)); break; + case f81866a: + f71882fg_remove_sysfs_files(pdev, + f71858fg_temp_attr, + ARRAY_SIZE(f71858fg_temp_attr)); + break; default: f71882fg_remove_sysfs_files(pdev, &fxxxx_temp_attr[0][0], ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps); } if (f71882fg_temp_has_beep[data->type]) { - f71882fg_remove_sysfs_files(pdev, - &fxxxx_temp_beep_attr[0][0], - ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps); + if (data->type == f81866a) + f71882fg_remove_sysfs_files(pdev, + &f81866_temp_beep_attr[0][0], + ARRAY_SIZE(f81866_temp_beep_attr[0]) + * nr_temps); + else + f71882fg_remove_sysfs_files(pdev, + &fxxxx_temp_beep_attr[0][0], + ARRAY_SIZE(fxxxx_temp_beep_attr[0]) + * nr_temps); } for (i = 0; i < F71882FG_MAX_INS; i++) { -- cgit v1.3-6-gb490 From 3e40b8602aa5309e0b117701c36971367af40682 Mon Sep 17 00:00:00 2001 From: Peter Hung Date: Tue, 7 Jul 2015 16:22:38 +0800 Subject: hwmon:(f71882fg) Fix f81866a voltage protection The f81866a voltage-1 protector(VIN1) address is differ from f71882. f71882 status:12H, beep:13H, v-high:32H f81866a status:16H, beep:17H, v-high:3aH Signed-off-by: Peter Hung Signed-off-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 50 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 79f1f50de451..e4ff21f8270c 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -71,6 +71,10 @@ #define F71882FG_REG_IN(nr) (0x20 + (nr)) #define F71882FG_REG_IN1_HIGH 0x32 /* f7188x only */ +#define F81866_REG_IN_STATUS 0x16 /* F81866 only */ +#define F81866_REG_IN_BEEP 0x17 /* F81866 only */ +#define F81866_REG_IN1_HIGH 0x3a /* F81866 only */ + #define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr))) #define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr))) #define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr))) @@ -1204,10 +1208,21 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) if (time_after(jiffies, data->last_limits + 60 * HZ) || !data->valid) { if (f71882fg_has_in1_alarm[data->type]) { - data->in1_max = - f71882fg_read8(data, F71882FG_REG_IN1_HIGH); - data->in_beep = - f71882fg_read8(data, F71882FG_REG_IN_BEEP); + if (data->type == f81866a) { + data->in1_max = + f71882fg_read8(data, + F81866_REG_IN1_HIGH); + data->in_beep = + f71882fg_read8(data, + F81866_REG_IN_BEEP); + } else { + data->in1_max = + f71882fg_read8(data, + F71882FG_REG_IN1_HIGH); + data->in_beep = + f71882fg_read8(data, + F71882FG_REG_IN_BEEP); + } } /* Get High & boundary temps*/ @@ -1331,9 +1346,16 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) data->fan[3] = f71882fg_read16(data, F71882FG_REG_FAN(3)); - if (f71882fg_has_in1_alarm[data->type]) - data->in_status = f71882fg_read8(data, + if (f71882fg_has_in1_alarm[data->type]) { + if (data->type == f81866a) + data->in_status = f71882fg_read8(data, + F81866_REG_IN_STATUS); + + else + data->in_status = f71882fg_read8(data, F71882FG_REG_IN_STATUS); + } + for (nr = 0; nr < F71882FG_MAX_INS; nr++) if (f71882fg_has_in[data->type][nr]) data->in[nr] = f71882fg_read8(data, @@ -1474,7 +1496,10 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute val = clamp_val(val, 0, 255); mutex_lock(&data->update_lock); - f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val); + if (data->type == f81866a) + f71882fg_write8(data, F81866_REG_IN1_HIGH, val); + else + f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val); data->in1_max = val; mutex_unlock(&data->update_lock); @@ -1505,13 +1530,20 @@ static ssize_t store_in_beep(struct device *dev, struct device_attribute return err; mutex_lock(&data->update_lock); - data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP); + if (data->type == f81866a) + data->in_beep = f71882fg_read8(data, F81866_REG_IN_BEEP); + else + data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP); + if (val) data->in_beep |= 1 << nr; else data->in_beep &= ~(1 << nr); - f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep); + if (data->type == f81866a) + f71882fg_write8(data, F81866_REG_IN_BEEP, data->in_beep); + else + f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep); mutex_unlock(&data->update_lock); return count; -- cgit v1.3-6-gb490 From 5102f022688ccd59b1fe4efc8a46ec3aca02dfc5 Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Wed, 8 Jul 2015 00:40:10 +0300 Subject: hwmon: (nct7802) Add pwmX_enable attribute Introduced REG_SMARTFAN_EN, SMARTFAN_EN_SHIFT, pwmX_enable, show_pwm_enable, store_pwm_enable. Signed-off-by: Constantine Shulyupin Signed-off-by: Guenter Roeck --- drivers/hwmon/nct7802.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers') diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 1c80aa48ee04..f4908bb228b8 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -53,6 +53,8 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = { #define REG_PECI_ENABLE 0x23 #define REG_FAN_ENABLE 0x24 #define REG_VMON_ENABLE 0x25 +#define REG_SMARTFAN_EN(x) (0x64 + (x) / 2) +#define SMARTFAN_EN_SHIFT(x) ((x) % 2 * 4) #define REG_VENDOR_ID 0xfd #define REG_CHIP_ID 0xfe #define REG_VERSION_ID 0xff @@ -151,6 +153,41 @@ static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, return err ? : count; } +static ssize_t show_pwm_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nct7802_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + unsigned int reg, enabled; + int ret; + + ret = regmap_read(data->regmap, REG_SMARTFAN_EN(sattr->index), ®); + if (ret < 0) + return ret; + enabled = reg >> SMARTFAN_EN_SHIFT(sattr->index) & 1; + return sprintf(buf, "%u\n", enabled + 1); +} + +static ssize_t store_pwm_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nct7802_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); + u8 val; + int ret; + + ret = kstrtou8(buf, 0, &val); + if (ret < 0) + return ret; + if (val < 1 || val > 2) + return -EINVAL; + ret = regmap_update_bits(data->regmap, REG_SMARTFAN_EN(sattr->index), + 1 << SMARTFAN_EN_SHIFT(sattr->index), + (val - 1) << SMARTFAN_EN_SHIFT(sattr->index)); + return ret ? : count; +} + static int nct7802_read_temp(struct nct7802_data *data, u8 reg_temp, u8 reg_temp_low, int *temp) { @@ -793,6 +830,14 @@ static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x60); static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x61); static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x62); +/* 7.2.95... Temperature to Fan mapping Relationships Register */ +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + store_pwm_enable, 0); +static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + store_pwm_enable, 1); +static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable, + store_pwm_enable, 2); + static struct attribute *nct7802_fan_attrs[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, @@ -832,10 +877,13 @@ static struct attribute_group nct7802_fan_group = { }; static struct attribute *nct7802_pwm_attrs[] = { + &sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm1_mode.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, &sensor_dev_attr_pwm2_mode.dev_attr.attr, &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3_enable.dev_attr.attr, &sensor_dev_attr_pwm3_mode.dev_attr.attr, &sensor_dev_attr_pwm3.dev_attr.attr, NULL -- cgit v1.3-6-gb490 From d8363bb5ad4ff3986c03c6895cc74e2a30041aee Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 7 Jul 2015 19:16:53 -0600 Subject: hwmon: (f71882fg) Add support for f81768d Add f81768d (id 0x1210) currently found on Jetway motherboards. It has 11 voltages but otherwise needed no special handling in this driver. Signed-off-by: George Joseph Signed-off-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index e4ff21f8270c..cb28e4b4fb10 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -59,6 +59,7 @@ #define SIO_F71889E_ID 0x0909 /* Chipset ID */ #define SIO_F71889A_ID 0x1005 /* Chipset ID */ #define SIO_F8000_ID 0x0581 /* Chipset ID */ +#define SIO_F81768D_ID 0x1210 /* Chipset ID */ #define SIO_F81865_ID 0x0704 /* Chipset ID */ #define SIO_F81866_ID 0x1010 /* Chipset ID */ @@ -107,7 +108,7 @@ #define F71882FG_REG_START 0x01 -#define F71882FG_MAX_INS 10 +#define F71882FG_MAX_INS 11 #define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */ @@ -116,7 +117,8 @@ module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); enum chips { f71808e, f71808a, f71858fg, f71862fg, f71868a, f71869, f71869a, - f71882fg, f71889fg, f71889ed, f71889a, f8000, f81865f, f81866a}; + f71882fg, f71889fg, f71889ed, f71889a, f8000, f81768d, f81865f, + f81866a}; static const char *const f71882fg_names[] = { "f71808e", @@ -131,25 +133,27 @@ static const char *const f71882fg_names[] = { "f71889ed", "f71889a", "f8000", + "f81768d", "f81865f", "f81866a", }; static const char f71882fg_has_in[][F71882FG_MAX_INS] = { - [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1, 0 }, - [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1, 0 }, - [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, - [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71868a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, - [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, - [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, - [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, - [f81866a] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0 }, + [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0 }, + [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71868a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 }, + [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }, + [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, + [f81768d] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, + [f81866a] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, }; static const char f71882fg_has_in1_alarm[] = { @@ -165,6 +169,7 @@ static const char f71882fg_has_in1_alarm[] = { [f71889ed] = 1, [f71889a] = 1, [f8000] = 0, + [f81768d] = 1, [f81865f] = 1, [f81866a] = 1, }; @@ -182,6 +187,7 @@ static const char f71882fg_fan_has_beep[] = { [f71889ed] = 1, [f71889a] = 1, [f8000] = 0, + [f81768d] = 1, [f81865f] = 1, [f81866a] = 1, }; @@ -199,6 +205,7 @@ static const char f71882fg_nr_fans[] = { [f71889ed] = 3, [f71889a] = 3, [f8000] = 3, /* +1 fan which is monitor only */ + [f81768d] = 3, [f81865f] = 2, [f81866a] = 3, }; @@ -216,6 +223,7 @@ static const char f71882fg_temp_has_beep[] = { [f71889ed] = 1, [f71889a] = 1, [f8000] = 0, + [f81768d] = 1, [f81865f] = 1, [f81866a] = 1, }; @@ -233,6 +241,7 @@ static const char f71882fg_nr_temps[] = { [f71889ed] = 3, [f71889a] = 3, [f8000] = 3, + [f81768d] = 3, [f81865f] = 2, [f81866a] = 3, }; @@ -569,6 +578,7 @@ static struct sensor_device_attribute_2 fxxxx_in_attr[] = { SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7), SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8), SENSOR_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 0, 9), + SENSOR_ATTR_2(in10_input, S_IRUGO, show_in, NULL, 0, 10), }; /* For models with in1 alarm capability */ @@ -2668,6 +2678,9 @@ static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data) case SIO_F8000_ID: sio_data->type = f8000; break; + case SIO_F81768D_ID: + sio_data->type = f81768d; + break; case SIO_F81865_ID: sio_data->type = f81865f; break; -- cgit v1.3-6-gb490 From d4068a59277d0ad5374f71163d45599d589bd617 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:51:32 +0900 Subject: hwmon: (g762) Drop owner assignment from struct i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Guenter Roeck --- drivers/hwmon/g762.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index 85d106fe3ce8..b96a2a9e4df7 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -1113,7 +1113,6 @@ static int g762_remove(struct i2c_client *client) static struct i2c_driver g762_driver = { .driver = { .name = DRVNAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(g762_dt_match), }, .probe = g762_probe, -- cgit v1.3-6-gb490 From 7b7a8b4237a0d7808df5aa12f49f7979f879cf12 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 10 Jul 2015 12:59:13 +0800 Subject: hwmon: (pmbus) Explicitly set regulator type for pmbus_regulator_ops The pmbus_regulator_ops is for voltage regulators, so explicitly set regulator type for better readability. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 89a23ff836e7..21f8b2fa7fc4 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -390,6 +390,7 @@ extern struct regulator_ops pmbus_regulator_ops; .of_match = of_match_ptr(_name # _id), \ .regulators_node = of_match_ptr("regulators"), \ .ops = &pmbus_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ } -- cgit v1.3-6-gb490 From a07d73113febf0e17299338b9a6401955fe63b14 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 10 Jul 2015 13:00:08 +0800 Subject: hwmon: (pmbus_core) Constify pmbus_regulator_ops pmbus_regulator_ops is not modified after initialized, so make it const. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus.h | 2 +- drivers/hwmon/pmbus/pmbus_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 21f8b2fa7fc4..58262b54f09f 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -380,7 +380,7 @@ struct pmbus_driver_info { /* Regulator ops */ -extern struct regulator_ops pmbus_regulator_ops; +extern const struct regulator_ops pmbus_regulator_ops; /* Macro for filling in array of struct regulator_desc */ #define PMBUS_REGULATOR(_name, _id) \ diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index f2e47c7dd808..12d85b178358 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1796,7 +1796,7 @@ static int pmbus_regulator_disable(struct regulator_dev *rdev) return _pmbus_regulator_on_off(rdev, 0); } -struct regulator_ops pmbus_regulator_ops = { +const struct regulator_ops pmbus_regulator_ops = { .enable = pmbus_regulator_enable, .disable = pmbus_regulator_disable, .is_enabled = pmbus_regulator_is_enabled, -- cgit v1.3-6-gb490 From 99b416085ce99b03b8be63d6ba8872902e9809ae Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 4 Jul 2015 09:19:48 -0700 Subject: hwmon: (adm1275) Use BIT macro Use BIT macro to simplify adding new bit masks. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1275.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 60aad9570f01..d34ba4f10c30 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "pmbus.h" enum chips { adm1075, adm1275, adm1276 }; @@ -30,28 +31,28 @@ enum chips { adm1075, adm1275, adm1276 }; #define ADM1275_PEAK_VOUT 0xd2 #define ADM1275_PMON_CONFIG 0xd4 -#define ADM1275_VIN_VOUT_SELECT (1 << 6) -#define ADM1275_VRANGE (1 << 5) -#define ADM1075_IRANGE_50 (1 << 4) -#define ADM1075_IRANGE_25 (1 << 3) -#define ADM1075_IRANGE_MASK ((1 << 3) | (1 << 4)) +#define ADM1275_VIN_VOUT_SELECT BIT(6) +#define ADM1275_VRANGE BIT(5) +#define ADM1075_IRANGE_50 BIT(4) +#define ADM1075_IRANGE_25 BIT(3) +#define ADM1075_IRANGE_MASK (BIT(3) | BIT(4)) #define ADM1275_IOUT_WARN2_LIMIT 0xd7 #define ADM1275_DEVICE_CONFIG 0xd8 -#define ADM1275_IOUT_WARN2_SELECT (1 << 4) +#define ADM1275_IOUT_WARN2_SELECT BIT(4) #define ADM1276_PEAK_PIN 0xda -#define ADM1275_MFR_STATUS_IOUT_WARN2 (1 << 0) +#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) #define ADM1075_READ_VAUX 0xdd #define ADM1075_VAUX_OV_WARN_LIMIT 0xde #define ADM1075_VAUX_UV_WARN_LIMIT 0xdf #define ADM1075_VAUX_STATUS 0xf6 -#define ADM1075_VAUX_OV_WARN (1<<7) -#define ADM1075_VAUX_UV_WARN (1<<6) +#define ADM1075_VAUX_OV_WARN BIT(7) +#define ADM1075_VAUX_UV_WARN BIT(6) struct adm1275_data { int id; -- cgit v1.3-6-gb490 From 904b296f308dc70d5560a2b4311bbe255de12fd7 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 4 Jul 2015 08:39:18 -0700 Subject: hwmon: (adm1275) Introduce configuration data structure for coeffcients Each new chip supported by the driver has a new set of coefficients, making hard-coding coefficients more and more cumbersome. Introduce a datastructure and table to simplify configuration. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1275.c | 113 +++++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index d34ba4f10c30..3a8d69b6c9a6 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -62,6 +62,34 @@ struct adm1275_data { #define to_adm1275_data(x) container_of(x, struct adm1275_data, info) +struct coefficients { + s16 m; + s16 b; + s16 R; +}; + +static const struct coefficients adm1075_coefficients[] = { + [0] = { 27169, 0, -1 }, /* voltage */ + [1] = { 806, 20475, -1 }, /* current, irange25 */ + [2] = { 404, 20475, -1 }, /* current, irange50 */ + [3] = { 0, -1, 8549 }, /* power, irange25 */ + [4] = { 0, -1, 4279 }, /* power, irange50 */ +}; + +static const struct coefficients adm1275_coefficients[] = { + [0] = { 19199, 0, -2 }, /* voltage, vrange set */ + [1] = { 6720, 0, -1 }, /* voltage, vrange not set */ + [2] = { 807, 20475, -1 }, /* current */ +}; + +static const struct coefficients adm1276_coefficients[] = { + [0] = { 19199, 0, -2 }, /* voltage, vrange set */ + [1] = { 6720, 0, -1 }, /* voltage, vrange not set */ + [2] = { 807, 20475, -1 }, /* current */ + [3] = { 6043, 0, -2 }, /* power, vrange set */ + [4] = { 2115, 0, -1 }, /* power, vrange not set */ +}; + static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); @@ -235,6 +263,8 @@ static int adm1275_probe(struct i2c_client *client, struct pmbus_driver_info *info; struct adm1275_data *data; const struct i2c_device_id *mid; + const struct coefficients *coefficients; + int vindex = -1, cindex = -1, pindex = -1; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA @@ -291,61 +321,34 @@ static int adm1275_probe(struct i2c_client *client, info->format[PSC_VOLTAGE_IN] = direct; info->format[PSC_VOLTAGE_OUT] = direct; info->format[PSC_CURRENT_OUT] = direct; - info->m[PSC_CURRENT_OUT] = 807; - info->b[PSC_CURRENT_OUT] = 20475; - info->R[PSC_CURRENT_OUT] = -1; + info->format[PSC_POWER] = direct; info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; info->read_word_data = adm1275_read_word_data; info->read_byte_data = adm1275_read_byte_data; info->write_word_data = adm1275_write_word_data; - if (data->id == adm1075) { - info->m[PSC_VOLTAGE_IN] = 27169; - info->b[PSC_VOLTAGE_IN] = 0; - info->R[PSC_VOLTAGE_IN] = -1; - info->m[PSC_VOLTAGE_OUT] = 27169; - info->b[PSC_VOLTAGE_OUT] = 0; - info->R[PSC_VOLTAGE_OUT] = -1; - } else if (config & ADM1275_VRANGE) { - info->m[PSC_VOLTAGE_IN] = 19199; - info->b[PSC_VOLTAGE_IN] = 0; - info->R[PSC_VOLTAGE_IN] = -2; - info->m[PSC_VOLTAGE_OUT] = 19199; - info->b[PSC_VOLTAGE_OUT] = 0; - info->R[PSC_VOLTAGE_OUT] = -2; - } else { - info->m[PSC_VOLTAGE_IN] = 6720; - info->b[PSC_VOLTAGE_IN] = 0; - info->R[PSC_VOLTAGE_IN] = -1; - info->m[PSC_VOLTAGE_OUT] = 6720; - info->b[PSC_VOLTAGE_OUT] = 0; - info->R[PSC_VOLTAGE_OUT] = -1; - } - if (device_config & ADM1275_IOUT_WARN2_SELECT) data->have_oc_fault = true; switch (data->id) { case adm1075: - info->format[PSC_POWER] = direct; - info->b[PSC_POWER] = 0; - info->R[PSC_POWER] = -1; + coefficients = adm1075_coefficients; + vindex = 0; switch (config & ADM1075_IRANGE_MASK) { case ADM1075_IRANGE_25: - info->m[PSC_POWER] = 8549; - info->m[PSC_CURRENT_OUT] = 806; + cindex = 1; + pindex = 3; break; case ADM1075_IRANGE_50: - info->m[PSC_POWER] = 4279; - info->m[PSC_CURRENT_OUT] = 404; + cindex = 2; + pindex = 4; break; default: dev_err(&client->dev, "Invalid input current range"); - info->m[PSC_POWER] = 0; - info->m[PSC_CURRENT_OUT] = 0; break; } + info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT; if (config & ADM1275_VIN_VOUT_SELECT) @@ -353,6 +356,10 @@ static int adm1275_probe(struct i2c_client *client, PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; break; case adm1275: + coefficients = adm1275_coefficients; + vindex = (config & ADM1275_VRANGE) ? 0 : 1; + cindex = 2; + if (config & ADM1275_VIN_VOUT_SELECT) info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; @@ -361,22 +368,38 @@ static int adm1275_probe(struct i2c_client *client, PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; break; case adm1276: - info->format[PSC_POWER] = direct; + coefficients = adm1276_coefficients; + vindex = (config & ADM1275_VRANGE) ? 0 : 1; + cindex = 2; + pindex = (config & ADM1275_VRANGE) ? 3 : 4; + info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT; if (config & ADM1275_VIN_VOUT_SELECT) info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; - if (config & ADM1275_VRANGE) { - info->m[PSC_POWER] = 6043; - info->b[PSC_POWER] = 0; - info->R[PSC_POWER] = -2; - } else { - info->m[PSC_POWER] = 2115; - info->b[PSC_POWER] = 0; - info->R[PSC_POWER] = -1; - } break; + default: + dev_err(&client->dev, "Unsupported device\n"); + return -ENODEV; + } + if (vindex >= 0) { + info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m; + info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b; + info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R; + info->m[PSC_VOLTAGE_OUT] = coefficients[vindex].m; + info->b[PSC_VOLTAGE_OUT] = coefficients[vindex].b; + info->R[PSC_VOLTAGE_OUT] = coefficients[vindex].R; + } + if (cindex >= 0) { + info->m[PSC_CURRENT_OUT] = coefficients[cindex].m; + info->b[PSC_CURRENT_OUT] = coefficients[cindex].b; + info->R[PSC_CURRENT_OUT] = coefficients[cindex].R; + } + if (pindex >= 0) { + info->m[PSC_POWER] = coefficients[pindex].m; + info->b[PSC_POWER] = coefficients[pindex].b; + info->R[PSC_POWER] = coefficients[pindex].R; } return pmbus_do_probe(client, id, info); -- cgit v1.3-6-gb490 From 9048539b7cd6ca99e03e6d9745779473349426f7 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 4 Jul 2015 10:09:54 -0700 Subject: hwmon: (adm1275) Introduce new feature flags Introduce have_vout, have_vaux_status, have_pin_max, and have_uc_fault to simplify adding support for new chips. Also simplify error returns where appropriate to return immediately on error. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1275.c | 97 ++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 3a8d69b6c9a6..1c19a2ee415c 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -57,6 +57,10 @@ enum chips { adm1075, adm1275, adm1276 }; struct adm1275_data { int id; bool have_oc_fault; + bool have_uc_fault; + bool have_vout; + bool have_vaux_status; + bool have_pin_max; struct pmbus_driver_info info; }; @@ -101,40 +105,30 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) switch (reg) { case PMBUS_IOUT_UC_FAULT_LIMIT: - if (data->have_oc_fault) { - ret = -ENXIO; - break; - } + if (!data->have_uc_fault) + return -ENXIO; ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); break; case PMBUS_IOUT_OC_FAULT_LIMIT: - if (!data->have_oc_fault) { - ret = -ENXIO; - break; - } + if (!data->have_oc_fault) + return -ENXIO; ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); break; case PMBUS_VOUT_OV_WARN_LIMIT: - if (data->id != adm1075) { - ret = -ENODATA; - break; - } + if (data->have_vout) + return -ENODATA; ret = pmbus_read_word_data(client, 0, ADM1075_VAUX_OV_WARN_LIMIT); break; case PMBUS_VOUT_UV_WARN_LIMIT: - if (data->id != adm1075) { - ret = -ENODATA; - break; - } + if (data->have_vout) + return -ENODATA; ret = pmbus_read_word_data(client, 0, ADM1075_VAUX_UV_WARN_LIMIT); break; case PMBUS_READ_VOUT: - if (data->id != adm1075) { - ret = -ENODATA; - break; - } + if (data->have_vout) + return -ENODATA; ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX); break; case PMBUS_VIRT_READ_IOUT_MAX: @@ -147,10 +141,8 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); break; case PMBUS_VIRT_READ_PIN_MAX: - if (data->id == adm1275) { - ret = -ENXIO; - break; - } + if (!data->have_pin_max) + return -ENXIO; ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN); break; case PMBUS_VIRT_RESET_IOUT_HISTORY: @@ -158,8 +150,8 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) case PMBUS_VIRT_RESET_VIN_HISTORY: break; case PMBUS_VIRT_RESET_PIN_HISTORY: - if (data->id == adm1275) - ret = -ENXIO; + if (!data->have_pin_max) + return -ENXIO; break; default: ret = -ENODATA; @@ -215,29 +207,31 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT); if (ret < 0) break; + if (!data->have_oc_fault && !data->have_uc_fault) + break; mfr_status = pmbus_read_byte_data(client, page, PMBUS_STATUS_MFR_SPECIFIC); - if (mfr_status < 0) { - ret = mfr_status; - break; - } + if (mfr_status < 0) + return mfr_status; if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) { ret |= data->have_oc_fault ? PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT; } break; case PMBUS_STATUS_VOUT: - if (data->id != adm1075) { - ret = -ENODATA; - break; - } + if (data->have_vout) + return -ENODATA; ret = 0; - mfr_status = pmbus_read_byte_data(client, 0, - ADM1075_VAUX_STATUS); - if (mfr_status & ADM1075_VAUX_OV_WARN) - ret |= PB_VOLTAGE_OV_WARNING; - if (mfr_status & ADM1075_VAUX_UV_WARN) - ret |= PB_VOLTAGE_UV_WARNING; + if (data->have_vaux_status) { + mfr_status = pmbus_read_byte_data(client, 0, + ADM1075_VAUX_STATUS); + if (mfr_status < 0) + return mfr_status; + if (mfr_status & ADM1075_VAUX_OV_WARN) + ret |= PB_VOLTAGE_OV_WARNING; + if (mfr_status & ADM1075_VAUX_UV_WARN) + ret |= PB_VOLTAGE_UV_WARNING; + } break; default: ret = -ENODATA; @@ -328,11 +322,15 @@ static int adm1275_probe(struct i2c_client *client, info->read_byte_data = adm1275_read_byte_data; info->write_word_data = adm1275_write_word_data; - if (device_config & ADM1275_IOUT_WARN2_SELECT) - data->have_oc_fault = true; - switch (data->id) { case adm1075: + if (device_config & ADM1275_IOUT_WARN2_SELECT) + data->have_oc_fault = true; + else + data->have_uc_fault = true; + data->have_pin_max = true; + data->have_vaux_status = true; + coefficients = adm1075_coefficients; vindex = 0; switch (config & ADM1075_IRANGE_MASK) { @@ -356,6 +354,12 @@ static int adm1275_probe(struct i2c_client *client, PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; break; case adm1275: + if (device_config & ADM1275_IOUT_WARN2_SELECT) + data->have_oc_fault = true; + else + data->have_uc_fault = true; + data->have_vout = true; + coefficients = adm1275_coefficients; vindex = (config & ADM1275_VRANGE) ? 0 : 1; cindex = 2; @@ -368,6 +372,13 @@ static int adm1275_probe(struct i2c_client *client, PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; break; case adm1276: + if (device_config & ADM1275_IOUT_WARN2_SELECT) + data->have_oc_fault = true; + else + data->have_uc_fault = true; + data->have_vout = true; + data->have_pin_max = true; + coefficients = adm1276_coefficients; vindex = (config & ADM1275_VRANGE) ? 0 : 1; cindex = 2; -- cgit v1.3-6-gb490 From 48065a138acb8435c60739ffa62622d69f61b712 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 5 Jul 2015 13:45:43 -0700 Subject: hwmon: (pmbus) Add support for lowest power value attributes Add support for powerX_input_lowest for both input and output power. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus.h | 50 +++++++++++++++++++++------------------- drivers/hwmon/pmbus/pmbus_core.c | 8 +++++++ 2 files changed, 34 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 58262b54f09f..2427f6e7c641 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -162,30 +162,32 @@ #define PMBUS_VIRT_READ_IIN_MAX (PMBUS_VIRT_BASE + 10) #define PMBUS_VIRT_RESET_IIN_HISTORY (PMBUS_VIRT_BASE + 11) #define PMBUS_VIRT_READ_PIN_AVG (PMBUS_VIRT_BASE + 12) -#define PMBUS_VIRT_READ_PIN_MAX (PMBUS_VIRT_BASE + 13) -#define PMBUS_VIRT_RESET_PIN_HISTORY (PMBUS_VIRT_BASE + 14) -#define PMBUS_VIRT_READ_POUT_AVG (PMBUS_VIRT_BASE + 15) -#define PMBUS_VIRT_READ_POUT_MAX (PMBUS_VIRT_BASE + 16) -#define PMBUS_VIRT_RESET_POUT_HISTORY (PMBUS_VIRT_BASE + 17) -#define PMBUS_VIRT_READ_VOUT_AVG (PMBUS_VIRT_BASE + 18) -#define PMBUS_VIRT_READ_VOUT_MIN (PMBUS_VIRT_BASE + 19) -#define PMBUS_VIRT_READ_VOUT_MAX (PMBUS_VIRT_BASE + 20) -#define PMBUS_VIRT_RESET_VOUT_HISTORY (PMBUS_VIRT_BASE + 21) -#define PMBUS_VIRT_READ_IOUT_AVG (PMBUS_VIRT_BASE + 22) -#define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 23) -#define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 24) -#define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 25) -#define PMBUS_VIRT_READ_TEMP2_AVG (PMBUS_VIRT_BASE + 26) -#define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 27) -#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 28) -#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 29) - -#define PMBUS_VIRT_READ_VMON (PMBUS_VIRT_BASE + 30) -#define PMBUS_VIRT_VMON_UV_WARN_LIMIT (PMBUS_VIRT_BASE + 31) -#define PMBUS_VIRT_VMON_OV_WARN_LIMIT (PMBUS_VIRT_BASE + 32) -#define PMBUS_VIRT_VMON_UV_FAULT_LIMIT (PMBUS_VIRT_BASE + 33) -#define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 34) -#define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 35) +#define PMBUS_VIRT_READ_PIN_MIN (PMBUS_VIRT_BASE + 13) +#define PMBUS_VIRT_READ_PIN_MAX (PMBUS_VIRT_BASE + 14) +#define PMBUS_VIRT_RESET_PIN_HISTORY (PMBUS_VIRT_BASE + 15) +#define PMBUS_VIRT_READ_POUT_AVG (PMBUS_VIRT_BASE + 16) +#define PMBUS_VIRT_READ_POUT_MIN (PMBUS_VIRT_BASE + 17) +#define PMBUS_VIRT_READ_POUT_MAX (PMBUS_VIRT_BASE + 18) +#define PMBUS_VIRT_RESET_POUT_HISTORY (PMBUS_VIRT_BASE + 19) +#define PMBUS_VIRT_READ_VOUT_AVG (PMBUS_VIRT_BASE + 20) +#define PMBUS_VIRT_READ_VOUT_MIN (PMBUS_VIRT_BASE + 21) +#define PMBUS_VIRT_READ_VOUT_MAX (PMBUS_VIRT_BASE + 22) +#define PMBUS_VIRT_RESET_VOUT_HISTORY (PMBUS_VIRT_BASE + 23) +#define PMBUS_VIRT_READ_IOUT_AVG (PMBUS_VIRT_BASE + 24) +#define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 25) +#define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 26) +#define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 27) +#define PMBUS_VIRT_READ_TEMP2_AVG (PMBUS_VIRT_BASE + 28) +#define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 29) +#define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 30) +#define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 31) + +#define PMBUS_VIRT_READ_VMON (PMBUS_VIRT_BASE + 32) +#define PMBUS_VIRT_VMON_UV_WARN_LIMIT (PMBUS_VIRT_BASE + 33) +#define PMBUS_VIRT_VMON_OV_WARN_LIMIT (PMBUS_VIRT_BASE + 34) +#define PMBUS_VIRT_VMON_UV_FAULT_LIMIT (PMBUS_VIRT_BASE + 35) +#define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 36) +#define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 37) /* * OPERATION diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 12d85b178358..306a1b175557 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1328,6 +1328,10 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = { .reg = PMBUS_VIRT_READ_PIN_AVG, .update = true, .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_PIN_MIN, + .update = true, + .attr = "input_lowest", }, { .reg = PMBUS_VIRT_READ_PIN_MAX, .update = true, @@ -1358,6 +1362,10 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = { .reg = PMBUS_VIRT_READ_POUT_AVG, .update = true, .attr = "average", + }, { + .reg = PMBUS_VIRT_READ_POUT_MIN, + .update = true, + .attr = "input_lowest", }, { .reg = PMBUS_VIRT_READ_POUT_MAX, .update = true, -- cgit v1.3-6-gb490 From 68a403823600fc9d8277f930981d3a013353b2fe Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 17 Mar 2015 13:19:51 -0700 Subject: hwmon: (adm1275) Add support for ADM1293 and ADM1294 ADM1293 and ADM1294 are mostly compatible with other chips of the same series, but have more configuration options. There are also some differences in register details. Signed-off-by: Guenter Roeck --- Documentation/hwmon/adm1275 | 40 +++++++----- drivers/hwmon/pmbus/Kconfig | 4 +- drivers/hwmon/pmbus/adm1275.c | 141 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 158 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275 index 15b4a20d5062..d697229e3c18 100644 --- a/Documentation/hwmon/adm1275 +++ b/Documentation/hwmon/adm1275 @@ -14,6 +14,10 @@ Supported chips: Prefix: 'adm1276' Addresses scanned: - Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1276.pdf + * Analog Devices ADM1293/ADM1294 + Prefix: 'adm1293', 'adm1294' + Addresses scanned: - + Datasheet: http://www.analog.com/media/en/technical-documentation/data-sheets/ADM1293_1294.pdf Author: Guenter Roeck @@ -22,12 +26,12 @@ Description ----------- This driver supports hardware montoring for Analog Devices ADM1075, ADM1275, -and ADM1276 Hot-Swap Controller and Digital Power Monitor. +ADM1276, ADM1293, and ADM1294 Hot-Swap Controller and Digital Power Monitors. -ADM1075, ADM1275, and ADM1276 are hot-swap controllers that allow a circuit -board to be removed from or inserted into a live backplane. They also feature -current and voltage readback via an integrated 12-bit analog-to-digital -converter (ADC), accessed using a PMBus interface. +ADM1075, ADM1275, ADM1276, ADM1293, and ADM1294 are hot-swap controllers that +allow a circuit board to be removed from or inserted into a live backplane. +They also feature current and voltage readback via an integrated 12 +bit analog-to-digital converter (ADC), accessed using a PMBus interface. The driver is a client driver to the core PMBus driver. Please see Documentation/hwmon/pmbus for details on PMBus client drivers. @@ -58,16 +62,16 @@ Sysfs entries The following attributes are supported. Limits are read-write, history reset attributes are write-only, all other attributes are read-only. -in1_label "vin1" or "vout1" depending on chip variant and - configuration. On ADM1075, vout1 reports the voltage on - the VAUX pin. -in1_input Measured voltage. -in1_min Minimum Voltage. -in1_max Maximum voltage. -in1_min_alarm Voltage low alarm. -in1_max_alarm Voltage high alarm. -in1_highest Historical maximum voltage. -in1_reset_history Write any value to reset history. +inX_label "vin1" or "vout1" depending on chip variant and + configuration. On ADM1075, ADM1293, and ADM1294, + vout1 reports the voltage on the VAUX pin. +inX_input Measured voltage. +inX_min Minimum Voltage. +inX_max Maximum voltage. +inX_min_alarm Voltage low alarm. +inX_max_alarm Voltage high alarm. +inX_highest Historical maximum voltage. +inX_reset_history Write any value to reset history. curr1_label "iout1" curr1_input Measured current. @@ -86,7 +90,9 @@ curr1_reset_history Write any value to reset history. power1_label "pin1" power1_input Input power. +power1_input_lowest Lowest observed input power. ADM1293 and ADM1294 only. +power1_input_highest Highest observed input power. power1_reset_history Write any value to reset history. - Power attributes are supported on ADM1075 and ADM1276 - only. + Power attributes are supported on ADM1075, ADM1276, + ADM1293, and ADM1294. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 9f7dbd189c97..67901cb08f77 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -30,8 +30,8 @@ config SENSORS_ADM1275 default n help If you say yes here you get hardware monitoring support for Analog - Devices ADM1075, ADM1275, and ADM1276 Hot-Swap Controller and Digital - Power Monitors. + Devices ADM1075, ADM1275, ADM1276, ADM1293, and ADM1294 Hot-Swap + Controller and Digital Power Monitors. This driver can also be built as a module. If so, the module will be called adm1275. diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 1c19a2ee415c..188af4c89f40 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -24,7 +24,11 @@ #include #include "pmbus.h" -enum chips { adm1075, adm1275, adm1276 }; +enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 }; + +#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) +#define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5) +#define ADM1293_MFR_STATUS_VAUX_OV_WARN BIT(6) #define ADM1275_PEAK_IOUT 0xd0 #define ADM1275_PEAK_VIN 0xd1 @@ -37,18 +41,30 @@ enum chips { adm1075, adm1275, adm1276 }; #define ADM1075_IRANGE_25 BIT(3) #define ADM1075_IRANGE_MASK (BIT(3) | BIT(4)) +#define ADM1293_IRANGE_25 0 +#define ADM1293_IRANGE_50 BIT(6) +#define ADM1293_IRANGE_100 BIT(7) +#define ADM1293_IRANGE_200 (BIT(6) | BIT(7)) +#define ADM1293_IRANGE_MASK (BIT(6) | BIT(7)) + +#define ADM1293_VIN_SEL_012 BIT(2) +#define ADM1293_VIN_SEL_074 BIT(3) +#define ADM1293_VIN_SEL_210 (BIT(2) | BIT(3)) +#define ADM1293_VIN_SEL_MASK (BIT(2) | BIT(3)) + +#define ADM1293_VAUX_EN BIT(1) + #define ADM1275_IOUT_WARN2_LIMIT 0xd7 #define ADM1275_DEVICE_CONFIG 0xd8 #define ADM1275_IOUT_WARN2_SELECT BIT(4) #define ADM1276_PEAK_PIN 0xda - -#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) - #define ADM1075_READ_VAUX 0xdd #define ADM1075_VAUX_OV_WARN_LIMIT 0xde #define ADM1075_VAUX_UV_WARN_LIMIT 0xdf +#define ADM1293_IOUT_MIN 0xe3 +#define ADM1293_PIN_MIN 0xe4 #define ADM1075_VAUX_STATUS 0xf6 #define ADM1075_VAUX_OV_WARN BIT(7) @@ -60,6 +76,9 @@ struct adm1275_data { bool have_uc_fault; bool have_vout; bool have_vaux_status; + bool have_mfr_vaux_status; + bool have_iout_min; + bool have_pin_min; bool have_pin_max; struct pmbus_driver_info info; }; @@ -94,6 +113,28 @@ static const struct coefficients adm1276_coefficients[] = { [4] = { 2115, 0, -1 }, /* power, vrange not set */ }; +static const struct coefficients adm1293_coefficients[] = { + [0] = { 3333, -1, 0 }, /* voltage, vrange 1.2V */ + [1] = { 5552, -5, -1 }, /* voltage, vrange 7.4V */ + [2] = { 19604, -50, -2 }, /* voltage, vrange 21V */ + [3] = { 8000, -100, -2 }, /* current, irange25 */ + [4] = { 4000, -100, -2 }, /* current, irange50 */ + [5] = { 20000, -1000, -3 }, /* current, irange100 */ + [6] = { 10000, -1000, -3 }, /* current, irange200 */ + [7] = { 10417, 0, -1 }, /* power, 1.2V, irange25 */ + [8] = { 5208, 0, -1 }, /* power, 1.2V, irange50 */ + [9] = { 26042, 0, -2 }, /* power, 1.2V, irange100 */ + [10] = { 13021, 0, -2 }, /* power, 1.2V, irange200 */ + [11] = { 17351, 0, -2 }, /* power, 7.4V, irange25 */ + [12] = { 8676, 0, -2 }, /* power, 7.4V, irange50 */ + [13] = { 4338, 0, -2 }, /* power, 7.4V, irange100 */ + [14] = { 21689, 0, -3 }, /* power, 7.4V, irange200 */ + [15] = { 6126, 0, -2 }, /* power, 21V, irange25 */ + [16] = { 30631, 0, -3 }, /* power, 21V, irange50 */ + [17] = { 15316, 0, -3 }, /* power, 21V, irange100 */ + [18] = { 7658, 0, -3 }, /* power, 21V, irange200 */ +}; + static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) { const struct pmbus_driver_info *info = pmbus_get_driver_info(client); @@ -131,6 +172,11 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) return -ENODATA; ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX); break; + case PMBUS_VIRT_READ_IOUT_MIN: + if (!data->have_iout_min) + return -ENXIO; + ret = pmbus_read_word_data(client, 0, ADM1293_IOUT_MIN); + break; case PMBUS_VIRT_READ_IOUT_MAX: ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT); break; @@ -140,6 +186,11 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) case PMBUS_VIRT_READ_VIN_MAX: ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); break; + case PMBUS_VIRT_READ_PIN_MIN: + if (!data->have_pin_min) + return -ENXIO; + ret = pmbus_read_word_data(client, 0, ADM1293_PIN_MIN); + break; case PMBUS_VIRT_READ_PIN_MAX: if (!data->have_pin_max) return -ENXIO; @@ -163,6 +214,8 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, u16 word) { + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct adm1275_data *data = to_adm1275_data(info); int ret; if (page) @@ -176,6 +229,9 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, break; case PMBUS_VIRT_RESET_IOUT_HISTORY: ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0); + if (!ret && data->have_iout_min) + ret = pmbus_write_word_data(client, 0, + ADM1293_IOUT_MIN, 0); break; case PMBUS_VIRT_RESET_VOUT_HISTORY: ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0); @@ -185,6 +241,9 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, break; case PMBUS_VIRT_RESET_PIN_HISTORY: ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0); + if (!ret && data->have_pin_min) + ret = pmbus_write_word_data(client, 0, + ADM1293_PIN_MIN, 0); break; default: ret = -ENODATA; @@ -231,6 +290,15 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) ret |= PB_VOLTAGE_OV_WARNING; if (mfr_status & ADM1075_VAUX_UV_WARN) ret |= PB_VOLTAGE_UV_WARNING; + } else if (data->have_mfr_vaux_status) { + mfr_status = pmbus_read_byte_data(client, page, + PMBUS_STATUS_MFR_SPECIFIC); + if (mfr_status < 0) + return mfr_status; + if (mfr_status & ADM1293_MFR_STATUS_VAUX_OV_WARN) + ret |= PB_VOLTAGE_OV_WARNING; + if (mfr_status & ADM1293_MFR_STATUS_VAUX_UV_WARN) + ret |= PB_VOLTAGE_UV_WARNING; } break; default: @@ -244,6 +312,8 @@ static const struct i2c_device_id adm1275_id[] = { { "adm1075", adm1075 }, { "adm1275", adm1275 }, { "adm1276", adm1276 }, + { "adm1293", adm1293 }, + { "adm1294", adm1294 }, { } }; MODULE_DEVICE_TABLE(i2c, adm1275_id); @@ -258,7 +328,7 @@ static int adm1275_probe(struct i2c_client *client, struct adm1275_data *data; const struct i2c_device_id *mid; const struct coefficients *coefficients; - int vindex = -1, cindex = -1, pindex = -1; + int vindex = -1, voindex = -1, cindex = -1, pindex = -1; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA @@ -390,17 +460,72 @@ static int adm1275_probe(struct i2c_client *client, info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; break; + case adm1293: + case adm1294: + data->have_iout_min = true; + data->have_pin_min = true; + data->have_pin_max = true; + data->have_mfr_vaux_status = true; + + coefficients = adm1293_coefficients; + + voindex = 0; + switch (config & ADM1293_VIN_SEL_MASK) { + case ADM1293_VIN_SEL_012: /* 1.2V */ + vindex = 0; + break; + case ADM1293_VIN_SEL_074: /* 7.4V */ + vindex = 1; + break; + case ADM1293_VIN_SEL_210: /* 21V */ + vindex = 2; + break; + default: /* disabled */ + break; + } + + switch (config & ADM1293_IRANGE_MASK) { + case ADM1293_IRANGE_25: + cindex = 3; + break; + case ADM1293_IRANGE_50: + cindex = 4; + break; + case ADM1293_IRANGE_100: + cindex = 5; + break; + case ADM1293_IRANGE_200: + cindex = 6; + break; + } + + if (vindex >= 0) + pindex = 7 + vindex * 4 + (cindex - 3); + + if (config & ADM1293_VAUX_EN) + info->func[0] |= + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; + + info->func[0] |= PMBUS_HAVE_PIN | + PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; + + break; default: dev_err(&client->dev, "Unsupported device\n"); return -ENODEV; } + + if (voindex < 0) + voindex = vindex; if (vindex >= 0) { info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m; info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b; info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R; - info->m[PSC_VOLTAGE_OUT] = coefficients[vindex].m; - info->b[PSC_VOLTAGE_OUT] = coefficients[vindex].b; - info->R[PSC_VOLTAGE_OUT] = coefficients[vindex].R; + } + if (voindex >= 0) { + info->m[PSC_VOLTAGE_OUT] = coefficients[voindex].m; + info->b[PSC_VOLTAGE_OUT] = coefficients[voindex].b; + info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R; } if (cindex >= 0) { info->m[PSC_CURRENT_OUT] = coefficients[cindex].m; -- cgit v1.3-6-gb490 From aeaa4d9f812bfd841643b37f65c6b6597045be37 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 8 Jun 2015 11:01:50 -0700 Subject: hwmon: (ltc2978) LTM4676 supports CLEAR_PEAKS Use the CLEAR_PEAKS command on LTM4676. Reviewed-by: Jean Delvare Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ltc2978.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 0835050ec245..33081d1d1c5a 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -313,7 +313,7 @@ static int ltc2978_clear_peaks(struct i2c_client *client, int page, { int ret; - if (id == ltc3880 || id == ltc3883) + if (id == ltc3880 || id == ltc3883 || id == ltm4676) ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); else ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); -- cgit v1.3-6-gb490 From a1dc86ebd2f2eb6652c8be9311c16acccd1708f8 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sun, 19 Jul 2015 00:29:14 +0200 Subject: hwmon: (lm70) add device tree support Allow the lm70 to be probed from a device tree. Signed-off-by: Rabin Vincent Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/lm70.txt | 21 +++++++++++++++ drivers/hwmon/lm70.c | 34 +++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/hwmon/lm70.txt (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/hwmon/lm70.txt b/Documentation/devicetree/bindings/hwmon/lm70.txt new file mode 100644 index 000000000000..e7fd921aa4f1 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/lm70.txt @@ -0,0 +1,21 @@ +* LM70/TMP121/LM71/LM74 thermometer. + +Required properties: +- compatible: one of + "ti,lm70" + "ti,tmp121" + "ti,lm71" + "ti,lm74" + +See Documentation/devicetree/bindings/spi/spi-bus.txt for more required and +optional properties. + +Example: + +spi_master { + temperature-sensor@0 { + compatible = "ti,lm70"; + reg = <0>; + spi-max-frequency = <1000000>; + }; +}; diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 97204dce162d..9296e9daf774 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -37,6 +37,7 @@ #include #include #include +#include #define DRVNAME "lm70" @@ -130,11 +131,41 @@ ATTRIBUTE_GROUPS(lm70); /*----------------------------------------------------------------------*/ +#ifdef CONFIG_OF +static const struct of_device_id lm70_of_ids[] = { + { + .compatible = "ti,lm70", + .data = (void *) LM70_CHIP_LM70, + }, + { + .compatible = "ti,tmp121", + .data = (void *) LM70_CHIP_TMP121, + }, + { + .compatible = "ti,lm71", + .data = (void *) LM70_CHIP_LM71, + }, + { + .compatible = "ti,lm74", + .data = (void *) LM70_CHIP_LM74, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, lm70_of_ids); +#endif + static int lm70_probe(struct spi_device *spi) { - int chip = spi_get_device_id(spi)->driver_data; + const struct of_device_id *match; struct device *hwmon_dev; struct lm70 *p_lm70; + int chip; + + match = of_match_device(lm70_of_ids, &spi->dev); + if (match) + chip = (int)(uintptr_t)match->data; + else + chip = spi_get_device_id(spi)->driver_data; /* signaling is SPI_MODE_0 */ if (spi->mode & (SPI_CPOL | SPI_CPHA)) @@ -169,6 +200,7 @@ static struct spi_driver lm70_driver = { .driver = { .name = "lm70", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lm70_of_ids), }, .id_table = lm70_ids, .probe = lm70_probe, -- cgit v1.3-6-gb490 From 1c6e8f6ba89c59270db223284d47e3c928c6fbfc Mon Sep 17 00:00:00 2001 From: Constantine Shulyupin Date: Tue, 28 Jul 2015 01:01:07 +0300 Subject: hwmon: (nct7802) Add auto_point attributes Introduced REG_PWM, pwm[1..3]_auto_point[1..5]_temp, pwm[1..3]_auto_point[1..5]_pwm, nct7802_auto_point_attrs, nct7802_auto_point_group, updated nct7802_regmap_is_volatile Signed-off-by: Constantine Shulyupin Signed-off-by: Guenter Roeck --- Documentation/hwmon/nct7802 | 3 +- drivers/hwmon/nct7802.c | 130 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/nct7802 b/Documentation/hwmon/nct7802 index 2e00f5e344bc..5438deb6be02 100644 --- a/Documentation/hwmon/nct7802 +++ b/Documentation/hwmon/nct7802 @@ -17,8 +17,7 @@ This driver implements support for the Nuvoton NCT7802Y hardware monitoring chip. NCT7802Y supports 6 temperature sensors, 5 voltage sensors, and 3 fan speed sensors. -The chip also supports intelligent fan speed control. This functionality is -not currently supported by the driver. +Smart Fan™ speed control is available via pwmX_auto_point attributes. Tested Boards and BIOS Versions ------------------------------- diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index f4908bb228b8..3ce33d244cc0 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -53,6 +53,7 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = { #define REG_PECI_ENABLE 0x23 #define REG_FAN_ENABLE 0x24 #define REG_VMON_ENABLE 0x25 +#define REG_PWM(x) (0x60 + (x)) #define REG_SMARTFAN_EN(x) (0x64 + (x) / 2) #define SMARTFAN_EN_SHIFT(x) ((x) % 2 * 4) #define REG_VENDOR_ID 0xfd @@ -130,6 +131,9 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, unsigned int val; int ret; + if (!attr->index) + return sprintf(buf, "255\n"); + ret = regmap_read(data->regmap, attr->index, &val); if (ret < 0) return ret; @@ -826,9 +830,12 @@ static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO, show_pwm_mode, NULL, 1); static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2); /* 7.2.91... Fan Control Output Value */ -static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x60); -static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x61); -static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0x62); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, + REG_PWM(0)); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, + REG_PWM(1)); +static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, + REG_PWM(2)); /* 7.2.95... Temperature to Fan mapping Relationships Register */ static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, @@ -893,11 +900,125 @@ static struct attribute_group nct7802_pwm_group = { .attrs = nct7802_pwm_attrs, }; +/* 7.2.115... 0x80-0x83, 0x84 Temperature (X-axis) transition */ +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x80, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x81, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x82, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x83, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point5_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x84, 0); + +/* 7.2.120... 0x85-0x88 PWM (Y-axis) transition */ +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x85); +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x86); +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x87); +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x88); +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0); + +/* 7.2.124 Table 2 X-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x90, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x91, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x92, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x93, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point5_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x94, 0); + +/* 7.2.129 Table 2 Y-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x95); +static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x96); +static SENSOR_DEVICE_ATTR(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x97); +static SENSOR_DEVICE_ATTR(pwm2_auto_point4_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0x98); +static SENSOR_DEVICE_ATTR(pwm2_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0); + +/* 7.2.133 Table 3 X-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA0, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA1, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA2, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA3, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point5_temp, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0xA4, 0); + +/* 7.2.138 Table 3 Y-axis Transition Point 1 Register */ +static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA5); +static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA6); +static SENSOR_DEVICE_ATTR(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA7); +static SENSOR_DEVICE_ATTR(pwm3_auto_point4_pwm, S_IRUGO | S_IWUSR, + show_pwm, store_pwm, 0xA8); +static SENSOR_DEVICE_ATTR(pwm3_auto_point5_pwm, S_IRUGO, show_pwm, NULL, 0); + +static struct attribute *nct7802_auto_point_attrs[] = { + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr, + + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr, + + &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point5_temp.dev_attr.attr, + + &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point5_pwm.dev_attr.attr, + + &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point5_temp.dev_attr.attr, + + &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point5_pwm.dev_attr.attr, + + NULL +}; + +static struct attribute_group nct7802_auto_point_group = { + .attrs = nct7802_auto_point_attrs, +}; + static const struct attribute_group *nct7802_groups[] = { &nct7802_temp_group, &nct7802_in_group, &nct7802_fan_group, &nct7802_pwm_group, + &nct7802_auto_point_group, NULL }; @@ -945,7 +1066,8 @@ static int nct7802_detect(struct i2c_client *client, static bool nct7802_regmap_is_volatile(struct device *dev, unsigned int reg) { - return reg != REG_BANK && reg <= 0x20; + return (reg != REG_BANK && reg <= 0x20) || + (reg >= REG_PWM(0) && reg <= REG_PWM(2)); } static const struct regmap_config nct7802_regmap_config = { -- cgit v1.3-6-gb490 From ead8080351c988b9c4bb5ec261d7b4c97ebb2773 Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Wed, 5 Aug 2015 12:53:08 -0700 Subject: hwmon: (it87) Add support for IT8732F Add support for the IT8732F. This chip is pretty similar to IT8721F, with the main difference being that the ADC LSB is 10.9 mV instead of 12 mV. Signed-off-by: Justin Maggard Signed-off-by: Guenter Roeck --- Documentation/hwmon/it87 | 35 ++++++++++++++++++++++------------- drivers/hwmon/Kconfig | 4 ++-- drivers/hwmon/it87.c | 43 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 60 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index e87294878334..733296d65449 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -38,6 +38,10 @@ Supported chips: Prefix: 'it8728' Addresses scanned: from Super I/O config space (8 I/O ports) Datasheet: Not publicly available + * IT8732F + Prefix: 'it8732' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Not publicly available * IT8771E Prefix: 'it8771' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -111,9 +115,9 @@ Description ----------- This driver implements support for the IT8603E, IT8620E, IT8623E, IT8705F, -IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, -IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and SiS950 -chips. +IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F, +IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and +SiS950 chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they @@ -137,10 +141,10 @@ The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E and later IT8712F revisions have support for 2 additional fans. The additional fans are supported by the driver. -The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8781F, IT8782F, IT8783E/F, -and late IT8712F and IT8705F also have optional 16-bit tachometer counters -for fans 1 to 3. This is better (no more fan clock divider mess) but not -compatible with the older chips and revisions. The 16-bit tachometer mode +The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8732F, IT8781F, IT8782F, +IT8783E/F, and late IT8712F and IT8705F also have optional 16-bit tachometer +counters for fans 1 to 3. This is better (no more fan clock divider mess) but +not compatible with the older chips and revisions. The 16-bit tachometer mode is enabled by the driver when one of the above chips is detected. The IT8726F is just bit enhanced IT8716F with additional hardware @@ -159,6 +163,9 @@ IT8728F. It only supports 16-bit fan mode. The IT8790E supports up to 3 fans. 16-bit fan mode is always enabled. +The IT8732F supports a closed-loop mode for fan control, but this is not +currently implemented by the driver. + Temperatures are measured in degrees Celsius. An alarm is triggered once when the Overtemperature Shutdown limit is crossed. @@ -173,12 +180,14 @@ is done. Voltage sensors (also known as IN sensors) report their values in volts. An alarm is triggered if the voltage has crossed a programmable minimum or maximum limit. Note that minimum in this case always means 'closest to -zero'; this is important for negative voltage measurements. All voltage -inputs can measure voltages between 0 and 4.08 volts, with a resolution of -0.016 volt (except IT8603E, IT8721F/IT8758E and IT8728F: 0.012 volt.) The -battery voltage in8 does not have limit registers. - -On the IT8603E, IT8721F/IT8758E, IT8781F, IT8782F, and IT8783E/F, some +zero'; this is important for negative voltage measurements. On most chips, all +voltage inputs can measure voltages between 0 and 4.08 volts, with a resolution +of 0.016 volt. IT8603E, IT8721F/IT8758E and IT8728F can measure between 0 and +3.06 volts, with a resolution of 0.012 volt. IT8732F can measure between 0 and +2.8 volts with a resolution of 0.0109 volt. The battery voltage in8 does not +have limit registers. + +On the IT8603E, IT8721F/IT8758E, IT8732F, IT8781F, IT8782F, and IT8783E/F, some voltage inputs are internal and scaled inside the chip: * in3 (optional) * in7 (optional for IT8781F, IT8782F, and IT8783E/F) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 7c65b7334738..500b262b89bb 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -609,8 +609,8 @@ config SENSORS_IT87 depends on !PPC select HWMON_VID help - If you say yes here you get support for ITE IT8705F, IT8712F, - IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, + If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F, + IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F, IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, IT8603E, IT8620E, and IT8623E sensor chips, and the SiS950 clone. diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index d0ee556e8ce0..1896e26df634 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -21,6 +21,7 @@ * IT8721F Super I/O chip w/LPC interface * IT8726F Super I/O chip w/LPC interface * IT8728F Super I/O chip w/LPC interface + * IT8732F Super I/O chip w/LPC interface * IT8758E Super I/O chip w/LPC interface * IT8771E Super I/O chip w/LPC interface * IT8772E Super I/O chip w/LPC interface @@ -69,8 +70,9 @@ #define DRVNAME "it87" -enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771, - it8772, it8781, it8782, it8783, it8786, it8790, it8603, it8620 }; +enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732, + it8771, it8772, it8781, it8782, it8783, it8786, it8790, it8603, + it8620 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -148,6 +150,7 @@ static inline void superio_exit(void) #define IT8721F_DEVID 0x8721 #define IT8726F_DEVID 0x8726 #define IT8728F_DEVID 0x8728 +#define IT8732F_DEVID 0x8732 #define IT8771E_DEVID 0x8771 #define IT8772E_DEVID 0x8772 #define IT8781F_DEVID 0x8781 @@ -265,6 +268,7 @@ struct it87_devices { #define FEAT_VID (1 << 9) /* Set if chip supports VID */ #define FEAT_IN7_INTERNAL (1 << 10) /* Set if in7 is internal */ #define FEAT_SIX_FANS (1 << 11) /* Supports six fans */ +#define FEAT_10_9MV_ADC (1 << 12) static const struct it87_devices it87_devices[] = { [it87] = { @@ -315,6 +319,15 @@ static const struct it87_devices it87_devices[] = { | FEAT_IN7_INTERNAL, .peci_mask = 0x07, }, + [it8732] = { + .name = "it8732", + .suffix = "F", + .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI + | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL, + .peci_mask = 0x07, + .old_peci_mask = 0x02, /* Actually reports PCH */ + }, [it8771] = { .name = "it8771", .suffix = "E", @@ -391,6 +404,7 @@ static const struct it87_devices it87_devices[] = { #define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS) #define has_12mv_adc(data) ((data)->features & FEAT_12MV_ADC) +#define has_10_9mv_adc(data) ((data)->features & FEAT_10_9MV_ADC) #define has_newer_autopwm(data) ((data)->features & FEAT_NEWER_AUTOPWM) #define has_old_autopwm(data) ((data)->features & FEAT_OLD_AUTOPWM) #define has_temp_offset(data) ((data)->features & FEAT_TEMP_OFFSET) @@ -475,7 +489,14 @@ struct it87_data { static int adc_lsb(const struct it87_data *data, int nr) { - int lsb = has_12mv_adc(data) ? 12 : 16; + int lsb; + + if (has_12mv_adc(data)) + lsb = 120; + else if (has_10_9mv_adc(data)) + lsb = 109; + else + lsb = 160; if (data->in_scaled & (1 << nr)) lsb <<= 1; return lsb; @@ -483,13 +504,13 @@ static int adc_lsb(const struct it87_data *data, int nr) static u8 in_to_reg(const struct it87_data *data, int nr, long val) { - val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr)); + val = DIV_ROUND_CLOSEST(val * 10, adc_lsb(data, nr)); return clamp_val(val, 0, 255); } static int in_from_reg(const struct it87_data *data, int nr, int val) { - return val * adc_lsb(data, nr); + return DIV_ROUND_CLOSEST(val * adc_lsb(data, nr), 10); } static inline u8 FAN_TO_REG(long rpm, int div) @@ -1515,9 +1536,14 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, }; struct it87_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr(attr)->index; + const char *label; - return sprintf(buf, "%s\n", has_12mv_adc(data) ? labels_it8721[nr] - : labels[nr]); + if (has_12mv_adc(data) || has_10_9mv_adc(data)) + label = labels_it8721[nr]; + else + label = labels[nr]; + + return sprintf(buf, "%s\n", label); } static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); @@ -1853,6 +1879,9 @@ static int __init it87_find(unsigned short *address, case IT8728F_DEVID: sio_data->type = it8728; break; + case IT8732F_DEVID: + sio_data->type = it8732; + break; case IT8771E_DEVID: sio_data->type = it8771; break; -- cgit v1.3-6-gb490 From 068c227056b9223fea1a759e08db2558d5cbb5ad Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 20 Jul 2015 09:47:33 -0700 Subject: hwmon: (pmbus) Add support for VR12 Newer chips such as MAX20751 support VR12. Add support for it. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus.c | 1 + drivers/hwmon/pmbus/pmbus.h | 2 ++ drivers/hwmon/pmbus/pmbus_core.c | 16 ++++++++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 554d0249dcde..bbfa35d82e42 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -129,6 +129,7 @@ static int pmbus_identify(struct i2c_client *client, break; case 1: info->format[PSC_VOLTAGE_OUT] = vid; + info->vrm_version = vr11; break; case 2: info->format[PSC_VOLTAGE_OUT] = direct; diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 2427f6e7c641..eece5f5e2282 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -338,10 +338,12 @@ enum pmbus_sensor_classes { #define PMBUS_HAVE_STATUS_VMON (1 << 19) enum pmbus_data_format { linear = 0, direct, vid }; +enum vrm_version { vr11 = 0, vr12 }; struct pmbus_driver_info { int pages; /* Total number of pages */ enum pmbus_data_format format[PSC_NUM_CLASSES]; + enum vrm_version vrm_version; /* * Support one set of coefficients for each sensor type * Used for chips providing data in direct mode. diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 306a1b175557..398198140b81 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -515,16 +515,24 @@ static long pmbus_reg2data_direct(struct pmbus_data *data, /* * Convert VID sensor values to milli- or micro-units * depending on sensor type. - * We currently only support VR11. */ static long pmbus_reg2data_vid(struct pmbus_data *data, struct pmbus_sensor *sensor) { long val = sensor->data; + long rv = 0; - if (val < 0x02 || val > 0xb2) - return 0; - return DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); + switch (data->info->vrm_version) { + case vr11: + if (val >= 0x02 && val <= 0xb2) + rv = DIV_ROUND_CLOSEST(160000 - (val - 2) * 625, 100); + break; + case vr12: + if (val >= 0x01) + rv = 250 + (val - 1) * 5; + break; + } + return rv; } static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) -- cgit v1.3-6-gb490 From 1f61cab8a729e00af77b51b44c3a8dc8ef3b3eb9 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 8 Jun 2015 11:15:23 -0700 Subject: hwmon: (pmbus) Add support for MAX20751 MAX20751 is a multiphase power controller with internal buck converter. It uses VR12.0 to report the output voltage. This requires an explicit driver, since the VR version can not be auto-detected. The chip supports a manufacturer specific command to fine-tune the output voltage. This command is not currently supported. Signed-off-by: Guenter Roeck --- Documentation/hwmon/max20751 | 77 ++++++++++++++++++++++++++++++++++++++++++ MAINTAINERS | 7 ++++ drivers/hwmon/pmbus/Kconfig | 10 ++++++ drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/max20751.c | 64 +++++++++++++++++++++++++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 Documentation/hwmon/max20751 create mode 100644 drivers/hwmon/pmbus/max20751.c (limited to 'drivers') diff --git a/Documentation/hwmon/max20751 b/Documentation/hwmon/max20751 new file mode 100644 index 000000000000..f9fa25ebb521 --- /dev/null +++ b/Documentation/hwmon/max20751 @@ -0,0 +1,77 @@ +Kernel driver max20751 +====================== + +Supported chips: + * maxim MAX20751 + Prefix: 'max20751' + Addresses scanned: - + Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX20751.pdf + Application note: http://pdfserv.maximintegrated.com/en/an/AN5941.pdf + +Author: Guenter Roeck + + +Description +----------- + +This driver supports MAX20751 Multiphase Master with PMBus Interface +and Internal Buck Converter. + +The driver is a client driver to the core PMBus driver. +Please see Documentation/hwmon/pmbus for details on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices for +details. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. + + +Sysfs entries +------------- + +The following attributes are supported. + +in1_label "vin1" +in1_input Measured voltage. +in1_min Minimum input voltage. +in1_max Maximum input voltage. +in1_lcrit Critical minimum input voltage. +in1_crit Critical maximum input voltage. +in1_min_alarm Input voltage low alarm. +in1_lcrit_alarm Input voltage critical low alarm. +in1_min_alarm Input voltage low alarm. +in1_max_alarm Input voltage high alarm. + +in2_label "vout1" +in2_input Measured voltage. +in2_min Minimum output voltage. +in2_max Maximum output voltage. +in2_lcrit Critical minimum output voltage. +in2_crit Critical maximum output voltage. +in2_min_alarm Output voltage low alarm. +in2_lcrit_alarm Output voltage critical low alarm. +in2_min_alarm Output voltage low alarm. +in2_max_alarm Output voltage high alarm. + +curr1_input Measured output current. +curr1_label "iout1" +curr1_max Maximum output current. +curr1_alarm Current high alarm. + +temp1_input Measured temperature. +temp1_max Maximum temperature. +temp1_crit Critical high temperature. +temp1_max_alarm Chip temperature high alarm. +temp1_crit_alarm Chip temperature critical high alarm. + +power1_input Output power. +power1_label "pout1" diff --git a/MAINTAINERS b/MAINTAINERS index a9ae6c105520..6a406b607eeb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6539,6 +6539,13 @@ S: Maintained F: Documentation/hwmon/max16065 F: drivers/hwmon/max16065.c +MAX20751 HARDWARE MONITOR DRIVER +M: Guenter Roeck +L: lm-sensors@lm-sensors.org +S: Maintained +F: Documentation/hwmon/max20751 +F: drivers/hwmon/max20751.c + MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER M: "Hans J. Koch" L: lm-sensors@lm-sensors.org diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 67901cb08f77..6e1e6fe434f7 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -73,6 +73,16 @@ config SENSORS_MAX16064 This driver can also be built as a module. If so, the module will be called max16064. +config SENSORS_MAX20751 + tristate "Maxim MAX20751" + default n + help + If you say yes here you get hardware monitoring support for Maxim + MAX20751. + + This driver can also be built as a module. If so, the module will + be called max20751. + config SENSORS_MAX34440 tristate "Maxim MAX34440 and compatibles" default n diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 1454293e985c..bce046d37f02 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_LM25066) += lm25066.o obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o obj-$(CONFIG_SENSORS_MAX16064) += max16064.o +obj-$(CONFIG_SENSORS_MAX20751) += max20751.o obj-$(CONFIG_SENSORS_MAX34440) += max34440.o obj-$(CONFIG_SENSORS_MAX8688) += max8688.o obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c new file mode 100644 index 000000000000..ab74aeae8cf2 --- /dev/null +++ b/drivers/hwmon/pmbus/max20751.c @@ -0,0 +1,64 @@ +/* + * Hardware monitoring driver for Maxim MAX20751 + * + * Copyright (c) 2015 Guenter Roeck + * + * 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 +#include +#include "pmbus.h" + +static struct pmbus_driver_info max20751_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = vid, + .vrm_version = vr12, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_POUT, +}; + +static int max20751_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return pmbus_do_probe(client, id, &max20751_info); +} + +static const struct i2c_device_id max20751_id[] = { + {"max20751", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, max20751_id); + +static struct i2c_driver max20751_driver = { + .driver = { + .name = "max20751", + }, + .probe = max20751_probe, + .remove = pmbus_do_remove, + .id_table = max20751_id, +}; + +module_i2c_driver(max20751_driver); + +MODULE_AUTHOR("Guenter Roeck "); +MODULE_DESCRIPTION("PMBus driver for Maxim MAX20751"); +MODULE_LICENSE("GPL"); -- cgit v1.3-6-gb490 From 135d9f7d135a11ff4a5279325b06c5e8c82952b5 Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Fri, 5 Jun 2015 13:32:27 +0900 Subject: extcon: max77843: Clear IRQ bits state before request IRQ IRQ signal before driver probe is needless because driver sends current state after platform booting done. So, this patch clears MUIC IRQ bits before request IRQ. Signed-off-by: Jaewon Kim Acked-by: MyungJoo Ham Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-max77843.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c index fac2f1417a79..cc5e7bca38c8 100644 --- a/drivers/extcon/extcon-max77843.c +++ b/drivers/extcon/extcon-max77843.c @@ -781,6 +781,15 @@ static int max77843_muic_probe(struct platform_device *pdev) /* Support virtual irq domain for max77843 MUIC device */ INIT_WORK(&info->irq_work, max77843_muic_irq_work); + /* Clear IRQ bits before request IRQs */ + ret = regmap_bulk_read(max77843->regmap_muic, + MAX77843_MUIC_REG_INT1, info->status, + MAX77843_MUIC_IRQ_NUM); + if (ret) { + dev_err(&pdev->dev, "Failed to Clear IRQ bits\n"); + goto err_muic_irq; + } + for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) { struct max77843_muic_irq *muic_irq = &max77843_muic_irqs[i]; unsigned int virq = 0; -- cgit v1.3-6-gb490 From 2519b7650e99d90643a7a20d623513de9c95a817 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 11 Jun 2015 20:17:02 +0900 Subject: extcon: Remove optional print_state() function pointer of struct extcon_dev This patch removes the optional print_state() function pointer which included in 'struct extcon_dev' because the extcon must maintain the consistent name of extcon device on sysfs instead of inconsistent state of external connectors. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-gpio.c | 18 ------------------ drivers/extcon/extcon.c | 8 -------- include/linux/extcon.h | 5 ----- 3 files changed, 31 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index 355459a54e8b..57c24fa52edb 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -65,22 +65,6 @@ static irqreturn_t gpio_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf) -{ - struct device *dev = edev->dev.parent; - struct gpio_extcon_data *extcon_data = dev_get_drvdata(dev); - const char *state; - - if (extcon_get_state(edev)) - state = extcon_data->state_on; - else - state = extcon_data->state_off; - - if (state) - return sprintf(buf, "%s\n", state); - return -EINVAL; -} - static int gpio_extcon_probe(struct platform_device *pdev) { struct gpio_extcon_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -110,8 +94,6 @@ static int gpio_extcon_probe(struct platform_device *pdev) extcon_data->state_on = pdata->state_on; extcon_data->state_off = pdata->state_off; extcon_data->check_on_resume = pdata->check_on_resume; - if (pdata->state_on && pdata->state_off) - extcon_data->edev->print_state = extcon_gpio_print_state; ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN, pdev->name); diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 43b57b02d050..d1fb5b4d024a 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -172,14 +172,6 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, int i, count = 0; struct extcon_dev *edev = dev_get_drvdata(dev); - if (edev->print_state) { - int ret = edev->print_state(edev, buf); - - if (ret >= 0) - return ret; - /* Use default if failed */ - } - if (edev->max_supported == 0) return sprintf(buf, "%u\n", edev->state); diff --git a/include/linux/extcon.h b/include/linux/extcon.h index 1656c98175f5..c0f8c4fc5d45 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -75,8 +75,6 @@ struct extcon_cable; * be attached simulataneously. {0x7, 0} is equivalent to * {0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there * can be no simultaneous connections. - * @print_state: An optional callback to override the method to print the - * status of the extcon device. * @dev: Device of this extcon. * @state: Attach/detach state of this extcon. Do not provide at * register-time. @@ -100,9 +98,6 @@ struct extcon_dev { const unsigned int *supported_cable; const u32 *mutually_exclusive; - /* Optional callbacks to override class functions */ - ssize_t (*print_state)(struct extcon_dev *edev, char *buf); - /* Internal data. Please do not set. */ struct device dev; struct raw_notifier_head *nh; -- cgit v1.3-6-gb490 From 1fe189bfb0fa2b01cea6464a0a6a98f5f118a376 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Thu, 11 Jun 2015 20:46:07 +0900 Subject: extcon: palmas: Remove the mutually_exclusive array This patch removes the mutually_exclusive array of extcon-palmas.c. After used the unique id of each external connector on 2a9de9c0f08d ("extcon: Use the unique id for external connector instead of string"), extcon driver can't directly handle the bit value indicating the external connectors. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-palmas.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c index eebdf2a33bfe..8933e7e0d9da 100644 --- a/drivers/extcon/extcon-palmas.c +++ b/drivers/extcon/extcon-palmas.c @@ -35,8 +35,6 @@ static const unsigned int palmas_extcon_cable[] = { EXTCON_NONE, }; -static const int mutually_exclusive[] = {0x3, 0x0}; - static void palmas_usb_wakeup(struct palmas *palmas, int enable) { if (enable) @@ -195,7 +193,6 @@ static int palmas_usb_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to allocate extcon device\n"); return -ENOMEM; } - palmas_usb->edev->mutually_exclusive = mutually_exclusive; status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev); if (status) { -- cgit v1.3-6-gb490 From feffb0cc63015798803082a330d2fd96b00e1773 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 19 Jun 2015 17:23:29 +0100 Subject: extcon: arizona: Update to use the new device properties API The device properties API will load data from both device tree and ACPI, update the binding to use this API instead of the OF API. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index ad87f263056f..a366ee33610a 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -1110,12 +1111,12 @@ static void arizona_micd_set_level(struct arizona *arizona, int index, regmap_update_bits(arizona->regmap, reg, mask, level); } -static int arizona_extcon_of_get_pdata(struct arizona *arizona) +static int arizona_extcon_device_get_pdata(struct arizona *arizona) { struct arizona_pdata *pdata = &arizona->pdata; unsigned int val = ARIZONA_ACCDET_MODE_HPL; - of_property_read_u32(arizona->dev->of_node, "wlf,hpdet-channel", &val); + device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val); switch (val) { case ARIZONA_ACCDET_MODE_HPL: case ARIZONA_ACCDET_MODE_HPR: @@ -1147,10 +1148,8 @@ static int arizona_extcon_probe(struct platform_device *pdev) if (!info) return -ENOMEM; - if (IS_ENABLED(CONFIG_OF)) { - if (!dev_get_platdata(arizona->dev)) - arizona_extcon_of_get_pdata(arizona); - } + if (!dev_get_platdata(arizona->dev)) + arizona_extcon_device_get_pdata(arizona); info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD"); if (IS_ERR(info->micvdd)) { -- cgit v1.3-6-gb490 From 4778d44ff3126b64f784ce9bf2b9dd3dbab1551b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 19 Jun 2015 17:23:30 +0100 Subject: extcon: arizona: Add basic microphone detection DT/ACPI bindings This patch adds bindings for the basic microphone detection platform data. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index a366ee33610a..7af42cb72e54 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1128,6 +1128,24 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona) pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL; } + device_property_read_u32(arizona->dev, "wlf,micd-detect-debounce", + &pdata->micd_detect_debounce); + + device_property_read_u32(arizona->dev, "wlf,micd-bias-start-time", + &pdata->micd_bias_start_time); + + device_property_read_u32(arizona->dev, "wlf,micd-rate", + &pdata->micd_rate); + + device_property_read_u32(arizona->dev, "wlf,micd-dbtime", + &pdata->micd_dbtime); + + device_property_read_u32(arizona->dev, "wlf,micd-timeout", + &pdata->micd_timeout); + + pdata->micd_force_micbias = device_property_read_bool(arizona->dev, + "wlf,micd-force-micbias"); + return 0; } -- cgit v1.3-6-gb490 From 8e5838dd7b8c226cca235aa64c2f210517ef9b64 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 19 Jun 2015 17:23:31 +0100 Subject: extcon: arizona: Use gpiod inteface to handle micd_pol_gpio gpio Convert to using the newer gpiod interface for the micd_pol_gpio. Although we still carry support for the old gpio interface from pdata. Signed-off-by: Charles Keepax [cw00.choi: Modify the patch titlei to include the detailed content] Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 7af42cb72e54..4dd684a32c3b 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,8 @@ struct arizona_extcon_info { int hpdet_ip_version; struct extcon_dev *edev; + + struct gpio_desc *micd_pol_gpio; }; static const struct arizona_micd_config micd_default_modes[] = { @@ -205,6 +208,10 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) if (arizona->pdata.micd_pol_gpio > 0) gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio, info->micd_modes[mode].gpio); + else + gpiod_set_value_cansleep(info->micd_pol_gpio, + info->micd_modes[mode].gpio); + regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, ARIZONA_MICD_BIAS_SRC_MASK, info->micd_modes[mode].bias << @@ -1258,6 +1265,27 @@ static int arizona_extcon_probe(struct platform_device *pdev) arizona->pdata.micd_pol_gpio, ret); goto err_register; } + } else { + if (info->micd_modes[0].gpio) + mode = GPIOD_OUT_HIGH; + else + mode = GPIOD_OUT_LOW; + + /* We can't use devm here because we need to do the get + * against the MFD device, as that is where the of_node + * will reside, but if we devm against that the GPIO + * will not be freed if the extcon driver is unloaded. + */ + info->micd_pol_gpio = gpiod_get_optional(arizona->dev, + "wlf,micd-pol", + GPIOD_OUT_LOW); + if (IS_ERR(info->micd_pol_gpio)) { + ret = PTR_ERR(info->micd_pol_gpio); + dev_err(arizona->dev, + "Failed to get microphone polarity GPIO: %d\n", + ret); + goto err_register; + } } if (arizona->pdata.hpdet_id_gpio > 0) { @@ -1268,7 +1296,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) if (ret != 0) { dev_err(arizona->dev, "Failed to request GPIO%d: %d\n", arizona->pdata.hpdet_id_gpio, ret); - goto err_register; + goto err_gpio; } } @@ -1312,7 +1340,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) dev_err(arizona->dev, "MICD ranges must be sorted\n"); ret = -EINVAL; - goto err_input; + goto err_gpio; } } } @@ -1331,7 +1359,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) dev_err(arizona->dev, "Unsupported MICD level %d\n", info->micd_ranges[i].max); ret = -EINVAL; - goto err_input; + goto err_gpio; } dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n", @@ -1404,7 +1432,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) if (ret != 0) { dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n", ret); - goto err_input; + goto err_gpio; } ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1); @@ -1475,7 +1503,8 @@ err_rise_wake: arizona_set_irq_wake(arizona, jack_irq_rise, 0); err_rise: arizona_free_irq(arizona, jack_irq_rise, info); -err_input: +err_gpio: + gpiod_put(info->micd_pol_gpio); err_register: pm_runtime_disable(&pdev->dev); return ret; @@ -1487,6 +1516,8 @@ static int arizona_extcon_remove(struct platform_device *pdev) struct arizona *arizona = info->arizona; int jack_irq_rise, jack_irq_fall; + gpiod_put(info->micd_pol_gpio); + pm_runtime_disable(&pdev->dev); regmap_update_bits(arizona->regmap, -- cgit v1.3-6-gb490 From 0ffe8cbd51dafa5ad6686435bb1bd0afdd2b006b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 19 Jun 2015 17:23:32 +0100 Subject: extcon: arizona: Ensure variables are set for headphone detection The detecting flag really refers to the microphone detection stage and as such should be cleared before arizona_identify_headphones is called. Also the mic flag should be set before identify headphones is called as well. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 4dd684a32c3b..2336de66f442 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -765,10 +765,11 @@ static void arizona_micd_timeout_work(struct work_struct *work) mutex_lock(&info->lock); dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n"); - arizona_identify_headphone(info); info->detecting = false; + arizona_identify_headphone(info); + arizona_stop_mic(info); mutex_unlock(&info->lock); @@ -834,6 +835,9 @@ static void arizona_micd_detect(struct work_struct *work) /* If we got a high impedence we should have a headset, report it. */ if (info->detecting && (val & ARIZONA_MICD_LVL_8)) { + info->mic = true; + info->detecting = false; + arizona_identify_headphone(info); ret = extcon_set_cable_state_(info->edev, @@ -849,8 +853,6 @@ static void arizona_micd_detect(struct work_struct *work) ret); } - info->mic = true; - info->detecting = false; goto handled; } @@ -863,10 +865,11 @@ static void arizona_micd_detect(struct work_struct *work) if (info->detecting && (val & MICD_LVL_1_TO_7)) { if (info->jack_flips >= info->micd_num_modes * 10) { dev_dbg(arizona->dev, "Detected HP/line\n"); - arizona_identify_headphone(info); info->detecting = false; + arizona_identify_headphone(info); + arizona_stop_mic(info); } else { info->micd_mode++; -- cgit v1.3-6-gb490 From 7eae43aeab27e8f65c0a2e31567fafcfc7aa4649 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Sun, 21 Jun 2015 23:48:36 +0900 Subject: extcon: Add exception handling to prevent the NULL pointer access This patch check whether argument is NULL to prevent NULL pointer access. Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index d1fb5b4d024a..8301a72b1073 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -264,6 +264,9 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) unsigned long flags; bool attached; + if (!edev) + return -EINVAL; + spin_lock_irqsave(&edev->lock, flags); if (edev->state != ((edev->state & ~mask) | (state & mask))) { @@ -337,6 +340,9 @@ EXPORT_SYMBOL_GPL(extcon_update_state); */ int extcon_set_state(struct extcon_dev *edev, u32 state) { + if (!edev) + return -EINVAL; + return extcon_update_state(edev, 0xffffffff, state); } EXPORT_SYMBOL_GPL(extcon_set_state); @@ -350,6 +356,9 @@ int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id) { int index; + if (!edev) + return -EINVAL; + index = find_cable_index_by_id(edev, id); if (index < 0) return index; @@ -394,6 +403,9 @@ int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, u32 state; int index; + if (!edev) + return -EINVAL; + index = find_cable_index_by_id(edev, id); if (index < 0) return index; @@ -436,6 +448,9 @@ struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) { struct extcon_dev *sd; + if (!extcon_name) + return ERR_PTR(-EINVAL); + mutex_lock(&extcon_dev_list_lock); list_for_each_entry(sd, &extcon_dev_list, entry) { if (!strcmp(sd->name, extcon_name)) @@ -564,6 +579,9 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, unsigned long flags; int ret, idx; + if (!edev || !nb) + return -EINVAL; + idx = find_cable_index_by_id(edev, id); spin_lock_irqsave(&edev->lock, flags); @@ -586,6 +604,9 @@ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, unsigned long flags; int ret, idx; + if (!edev || !nb) + return -EINVAL; + idx = find_cable_index_by_id(edev, id); spin_lock_irqsave(&edev->lock, flags); @@ -646,6 +667,9 @@ struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable) { struct extcon_dev *edev; + if (!supported_cable) + return ERR_PTR(-EINVAL); + edev = kzalloc(sizeof(*edev), GFP_KERNEL); if (!edev) return ERR_PTR(-ENOMEM); @@ -746,7 +770,7 @@ int extcon_dev_register(struct extcon_dev *edev) return ret; } - if (!edev->supported_cable) + if (!edev || !edev->supported_cable) return -EINVAL; for (; edev->supported_cable[index] != EXTCON_NONE; index++); @@ -952,6 +976,9 @@ void extcon_dev_unregister(struct extcon_dev *edev) { int index; + if (!edev) + return; + mutex_lock(&extcon_dev_list_lock); list_del(&edev->entry); mutex_unlock(&extcon_dev_list_lock); @@ -1058,6 +1085,9 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) struct device_node *node; struct extcon_dev *edev; + if (!dev) + return ERR_PTR(-EINVAL); + if (!dev->of_node) { dev_err(dev, "device does not have a device node entry\n"); return ERR_PTR(-EINVAL); -- cgit v1.3-6-gb490 From 57f70ef9bd19378b51a282be6b46b45b70d4980d Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 25 Jun 2015 16:47:02 +0100 Subject: extcon: arizona: Declare 3-pole jack if we detect open circuit on mic Detecting an open-circuit on the microphone pin, usually means the headset has a microphone but the cable is faulty. Currently the code will simply stop detecting and declare nothing in this situation. It is better to declare this as headphones such that the user can still use their headset as plain headphones even if the microphone is faulty. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 2336de66f442..eaf0644b5506 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -829,7 +829,10 @@ static void arizona_micd_detect(struct work_struct *work) /* Due to jack detect this should never happen */ if (!(val & ARIZONA_MICD_STS)) { dev_warn(arizona->dev, "Detected open circuit\n"); + info->mic = false; + arizona_stop_mic(info); info->detecting = false; + arizona_identify_headphone(info); goto handled; } -- cgit v1.3-6-gb490 From bb327e92a9651c4d9bbf8ee9a367d575d7e6a102 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 30 Jun 2015 13:32:39 +0100 Subject: extcon: arizona: Simplify pdata symantics for micd_dbtime Currently micd_dbtime can be set to 0 for default, 1 for 4 measurements, or a greater than 16-bit value for 2 measurements. This patch simplifies the symantics to 2 for 2 measurements, 4 for 4 measurements and any other value for the default. I am not super keen on changing the symantics of the pdata at this stage in the drivers life, but acceptance of the DT binding for this field has been made conditional on this happening. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index eaf0644b5506..4b9f09cc38d8 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -48,6 +48,9 @@ #define HPDET_DEBOUNCE 500 #define DEFAULT_MICD_TIMEOUT 2000 +#define MICD_DBTIME_TWO_READINGS 2 +#define MICD_DBTIME_FOUR_READINGS 4 + #define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \ ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \ ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \ @@ -1318,11 +1321,19 @@ static int arizona_extcon_probe(struct platform_device *pdev) arizona->pdata.micd_rate << ARIZONA_MICD_RATE_SHIFT); - if (arizona->pdata.micd_dbtime) + switch (arizona->pdata.micd_dbtime) { + case MICD_DBTIME_FOUR_READINGS: regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, ARIZONA_MICD_DBTIME_MASK, - arizona->pdata.micd_dbtime - << ARIZONA_MICD_DBTIME_SHIFT); + ARIZONA_MICD_DBTIME); + break; + case MICD_DBTIME_TWO_READINGS: + regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, + ARIZONA_MICD_DBTIME_MASK, 0); + break; + default: + break; + } BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40); -- cgit v1.3-6-gb490 From bef025a1f8e0e566f954613f4e5087f6b156e2a5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:50:20 +0900 Subject: extcon: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-rt8973a.c | 1 - drivers/extcon/extcon-sm5502.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c index 92c939221a41..11592e980bc1 100644 --- a/drivers/extcon/extcon-rt8973a.c +++ b/drivers/extcon/extcon-rt8973a.c @@ -693,7 +693,6 @@ MODULE_DEVICE_TABLE(i2c, rt8973a_i2c_id); static struct i2c_driver rt8973a_muic_i2c_driver = { .driver = { .name = "rt8973a", - .owner = THIS_MODULE, .pm = &rt8973a_muic_pm_ops, .of_match_table = rt8973a_dt_match, }, diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c index 817dece23b4c..0ffefefa2e26 100644 --- a/drivers/extcon/extcon-sm5502.c +++ b/drivers/extcon/extcon-sm5502.c @@ -685,7 +685,6 @@ MODULE_DEVICE_TABLE(i2c, sm5502_i2c_id); static struct i2c_driver sm5502_muic_i2c_driver = { .driver = { .name = "sm5502", - .owner = THIS_MODULE, .pm = &sm5502_muic_pm_ops, .of_match_table = sm5502_dt_match, }, -- cgit v1.3-6-gb490 From a598af7f0279195abffbfb9bf2070457e9c89ff3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 4 Aug 2015 10:47:23 +0300 Subject: extcon: Fix signedness bugs about break error handling Unsigned is never less than zero so this error handling won't work. Fixes: be052cc87745 ('extcon: Fix hang and extcon_get/set_cable_state().') Signed-off-by: Dan Carpenter Reviewed-by: Roger Quadros [cw00.choi: Change the patch title and fix signedness bug of find_cable_index_by_id() ] Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 8301a72b1073..a07addde297b 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -126,7 +126,7 @@ static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id static int find_cable_id_by_name(struct extcon_dev *edev, const char *name) { - unsigned int id = -EINVAL; + int id = -EINVAL; int i = 0; /* Find the id of extcon cable */ @@ -143,7 +143,7 @@ static int find_cable_id_by_name(struct extcon_dev *edev, const char *name) static int find_cable_index_by_name(struct extcon_dev *edev, const char *name) { - unsigned int id; + int id; if (edev->max_supported == 0) return -EINVAL; @@ -379,7 +379,7 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state_); */ int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name) { - unsigned int id; + int id; id = find_cable_id_by_name(edev, cable_name); if (id < 0) @@ -430,7 +430,7 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_); int extcon_set_cable_state(struct extcon_dev *edev, const char *cable_name, bool cable_state) { - unsigned int id; + int id; id = find_cable_id_by_name(edev, cable_name); if (id < 0) -- cgit v1.3-6-gb490 From 1525c386a1f01612c6f3f27241113d7fc8e6d72d Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 6 Aug 2015 01:44:02 -0400 Subject: net: switchdev: change fdb addr for a byte array The address in the switchdev_obj_fdb structure is currently represented as a pointer. Replacing it for a 6-byte array allows switchdev to carry addresses directly read from hardware registers, not stored by the switch chip driver (as in Rocker). Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 2 +- include/net/switchdev.h | 2 +- net/bridge/br_fdb.c | 2 +- net/switchdev/switchdev.c | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index b77e0e7307d4..80bb25c5a644 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4543,7 +4543,7 @@ static int rocker_port_fdb_dump(const struct rocker_port *rocker_port, hash_for_each_safe(rocker->fdb_tbl, bkt, tmp, found, entry) { if (found->key.pport != rocker_port->pport) continue; - fdb->addr = found->key.addr; + ether_addr_copy(fdb->addr, found->key.addr); fdb->vid = rocker_port_vlan_to_vid(rocker_port, found->key.vlan_id); err = obj->cb(rocker_port->dev, obj); diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 89da8934519b..e90e1a0fa579 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -70,7 +70,7 @@ struct switchdev_obj { u32 tb_id; } ipv4_fib; struct switchdev_obj_fdb { /* PORT_FDB */ - const unsigned char *addr; + u8 addr[ETH_ALEN]; u16 vid; } fdb; } u; diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 9e9875da0a4f..5656b44bf3de 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -136,11 +136,11 @@ static void fdb_del_external_learn(struct net_bridge_fdb_entry *f) struct switchdev_obj obj = { .id = SWITCHDEV_OBJ_PORT_FDB, .u.fdb = { - .addr = f->addr.addr, .vid = f->vlan_id, }, }; + ether_addr_copy(obj.u.fdb.addr, f->addr.addr); switchdev_port_obj_del(f->dst->dev, &obj); } diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 33bafa2e703e..9db87a34f866 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -742,11 +743,11 @@ int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct switchdev_obj obj = { .id = SWITCHDEV_OBJ_PORT_FDB, .u.fdb = { - .addr = addr, .vid = vid, }, }; + ether_addr_copy(obj.u.fdb.addr, addr); return switchdev_port_obj_add(dev, &obj); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_add); @@ -769,11 +770,11 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct switchdev_obj obj = { .id = SWITCHDEV_OBJ_PORT_FDB, .u.fdb = { - .addr = addr, .vid = vid, }, }; + ether_addr_copy(obj.u.fdb.addr, addr); return switchdev_port_obj_del(dev, &obj); } EXPORT_SYMBOL_GPL(switchdev_port_fdb_del); -- cgit v1.3-6-gb490 From 55045ddded0f39d84c2ca019508973be8c595a78 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 6 Aug 2015 01:44:04 -0400 Subject: net: dsa: add support for switchdev FDB objects Remove the fdb_{add,del,getnext} function pointer in favor of new port_fdb_{add,del,getnext}. Implement the switchdev_port_obj_{add,del,dump} functions in DSA to support the SWITCHDEV_OBJ_PORT_FDB objects. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6171.c | 3 - drivers/net/dsa/mv88e6352.c | 3 - include/net/dsa.h | 16 ++-- net/dsa/slave.c | 218 +++++++++++++++++++++++--------------------- 4 files changed, 126 insertions(+), 114 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 1c7808495a9d..cfa21ed1f734 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -116,9 +116,6 @@ struct dsa_switch_driver mv88e6171_switch_driver = { .port_join_bridge = mv88e6xxx_join_bridge, .port_leave_bridge = mv88e6xxx_leave_bridge, .port_stp_update = mv88e6xxx_port_stp_update, - .fdb_add = mv88e6xxx_port_fdb_add, - .fdb_del = mv88e6xxx_port_fdb_del, - .fdb_getnext = mv88e6xxx_port_fdb_getnext, }; MODULE_ALIAS("platform:mv88e6171"); diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index af210efecc55..eb4630fec6f1 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -341,9 +341,6 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .port_join_bridge = mv88e6xxx_join_bridge, .port_leave_bridge = mv88e6xxx_leave_bridge, .port_stp_update = mv88e6xxx_port_stp_update, - .fdb_add = mv88e6xxx_port_fdb_add, - .fdb_del = mv88e6xxx_port_fdb_del, - .fdb_getnext = mv88e6xxx_port_fdb_getnext, }; MODULE_ALIAS("platform:mv88e6172"); diff --git a/include/net/dsa.h b/include/net/dsa.h index fbca63ba8f73..091d35f77180 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -296,12 +296,16 @@ struct dsa_switch_driver { u32 br_port_mask); int (*port_stp_update)(struct dsa_switch *ds, int port, u8 state); - int (*fdb_add)(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid); - int (*fdb_del)(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid); - int (*fdb_getnext)(struct dsa_switch *ds, int port, - unsigned char *addr, bool *is_static); + + /* + * Forwarding database + */ + int (*port_fdb_add)(struct dsa_switch *ds, int port, u16 vid, + const u8 addr[ETH_ALEN]); + int (*port_fdb_del)(struct dsa_switch *ds, int port, u16 vid, + const u8 addr[ETH_ALEN]); + int (*port_fdb_getnext)(struct dsa_switch *ds, int port, u16 *vid, + u8 addr[ETH_ALEN], bool *is_static); }; void register_switch_driver(struct dsa_switch_driver *type); diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 0010c690cc67..1dbdeaab2bb4 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "dsa_priv.h" /* slave mii_bus handling ***************************************************/ @@ -200,105 +201,6 @@ out: return 0; } -static int dsa_slave_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, u16 vid, u16 nlm_flags) -{ - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->parent; - int ret = -EOPNOTSUPP; - - if (ds->drv->fdb_add) - ret = ds->drv->fdb_add(ds, p->port, addr, vid); - - return ret; -} - -static int dsa_slave_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, u16 vid) -{ - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->parent; - int ret = -EOPNOTSUPP; - - if (ds->drv->fdb_del) - ret = ds->drv->fdb_del(ds, p->port, addr, vid); - - return ret; -} - -static int dsa_slave_fill_info(struct net_device *dev, struct sk_buff *skb, - const unsigned char *addr, u16 vid, - bool is_static, - u32 portid, u32 seq, int type, - unsigned int flags) -{ - struct nlmsghdr *nlh; - struct ndmsg *ndm; - - nlh = nlmsg_put(skb, portid, seq, type, sizeof(*ndm), flags); - if (!nlh) - return -EMSGSIZE; - - ndm = nlmsg_data(nlh); - ndm->ndm_family = AF_BRIDGE; - ndm->ndm_pad1 = 0; - ndm->ndm_pad2 = 0; - ndm->ndm_flags = NTF_EXT_LEARNED; - ndm->ndm_type = 0; - ndm->ndm_ifindex = dev->ifindex; - ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; - - if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr)) - goto nla_put_failure; - - if (vid && nla_put_u16(skb, NDA_VLAN, vid)) - goto nla_put_failure; - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -/* Dump information about entries, in response to GETNEIGH */ -static int dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct net_device *dev, - struct net_device *filter_dev, int idx) -{ - struct dsa_slave_priv *p = netdev_priv(dev); - struct dsa_switch *ds = p->parent; - unsigned char addr[ETH_ALEN] = { 0 }; - int ret; - - if (!ds->drv->fdb_getnext) - return -EOPNOTSUPP; - - for (; ; idx++) { - bool is_static; - - ret = ds->drv->fdb_getnext(ds, p->port, addr, &is_static); - if (ret < 0) - break; - - if (idx < cb->args[0]) - continue; - - ret = dsa_slave_fill_info(dev, skb, addr, 0, - is_static, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWNEIGH, NLM_F_MULTI); - if (ret < 0) - break; - } - - return idx; -} - static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct dsa_slave_priv *p = netdev_priv(dev); @@ -364,6 +266,115 @@ static int dsa_slave_port_attr_set(struct net_device *dev, return ret; } +static int dsa_slave_port_fdb_add(struct net_device *dev, + struct switchdev_obj *obj) +{ + struct switchdev_obj_fdb *fdb = &obj->u.fdb; + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->parent; + int err; + + if (obj->trans == SWITCHDEV_TRANS_PREPARE) + err = ds->drv->port_fdb_add ? 0 : -EOPNOTSUPP; + else if (obj->trans == SWITCHDEV_TRANS_COMMIT) + err = ds->drv->port_fdb_add(ds, p->port, fdb->vid, fdb->addr); + else + err = -EOPNOTSUPP; + + return err; +} + +static int dsa_slave_port_fdb_del(struct net_device *dev, + struct switchdev_obj *obj) +{ + struct switchdev_obj_fdb *fdb = &obj->u.fdb; + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->parent; + + if (!ds->drv->port_fdb_del) + return -EOPNOTSUPP; + + return ds->drv->port_fdb_del(ds, p->port, fdb->vid, fdb->addr); +} + +static int dsa_slave_port_fdb_dump(struct net_device *dev, + struct switchdev_obj *obj) +{ + struct switchdev_obj_fdb *fdb = &obj->u.fdb; + struct dsa_slave_priv *p = netdev_priv(dev); + struct dsa_switch *ds = p->parent; + int err; + + if (!ds->drv->port_fdb_getnext) + return -EOPNOTSUPP; + + memset(fdb, 0, sizeof(*fdb)); + + for (;;) { + err = ds->drv->port_fdb_getnext(ds, p->port, &fdb->vid, + fdb->addr, &fdb->is_static); + if (err) + break; + + err = obj->cb(dev, obj); + if (err) + break; + } + + return err == -ENOENT ? 0 : err; +} + +static int dsa_slave_port_obj_add(struct net_device *dev, + struct switchdev_obj *obj) +{ + int err; + + switch (obj->id) { + case SWITCHDEV_OBJ_PORT_FDB: + err = dsa_slave_port_fdb_add(dev, obj); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static int dsa_slave_port_obj_del(struct net_device *dev, + struct switchdev_obj *obj) +{ + int err; + + switch (obj->id) { + case SWITCHDEV_OBJ_PORT_FDB: + err = dsa_slave_port_fdb_del(dev, obj); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static int dsa_slave_port_obj_dump(struct net_device *dev, + struct switchdev_obj *obj) +{ + int err; + + switch (obj->id) { + case SWITCHDEV_OBJ_PORT_FDB: + err = dsa_slave_port_fdb_dump(dev, obj); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + static int dsa_slave_bridge_port_join(struct net_device *dev, struct net_device *br) { @@ -765,9 +776,9 @@ static const struct net_device_ops dsa_slave_netdev_ops = { .ndo_change_rx_flags = dsa_slave_change_rx_flags, .ndo_set_rx_mode = dsa_slave_set_rx_mode, .ndo_set_mac_address = dsa_slave_set_mac_address, - .ndo_fdb_add = dsa_slave_fdb_add, - .ndo_fdb_del = dsa_slave_fdb_del, - .ndo_fdb_dump = dsa_slave_fdb_dump, + .ndo_fdb_add = switchdev_port_fdb_add, + .ndo_fdb_del = switchdev_port_fdb_del, + .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_do_ioctl = dsa_slave_ioctl, .ndo_get_iflink = dsa_slave_get_iflink, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -780,6 +791,9 @@ static const struct net_device_ops dsa_slave_netdev_ops = { static const struct switchdev_ops dsa_slave_switchdev_ops = { .switchdev_port_attr_get = dsa_slave_port_attr_get, .switchdev_port_attr_set = dsa_slave_port_attr_set, + .switchdev_port_obj_add = dsa_slave_port_obj_add, + .switchdev_port_obj_del = dsa_slave_port_obj_del, + .switchdev_port_obj_dump = dsa_slave_port_obj_dump, }; static void dsa_slave_adjust_link(struct net_device *dev) -- cgit v1.3-6-gb490 From 368b1d9c10acf99a855961ae6a1430591ee55f03 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 6 Aug 2015 01:44:05 -0400 Subject: net: dsa: mv88e6xxx: extend fid mask The driver currently manages one FID per port (or bridge group), with a mask of DSA_MAX_PORTS bits, where 0 means that the FID is in use. The Marvell 88E6xxx switches support up to 4094 FIDs (from 1 to 0xfff; FID 0 means that multiple address databases are not being used). This patch changes the fid_mask for an fid_bitmap of 4096 bits. >From now on, FIDs 1 to num_ports are reserved for non-bridged ports and bridge groups (a bridge group gets the FID of its first member). The remaining bits will be reserved for VLAN entries. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 20 +++++++++++++------- drivers/net/dsa/mv88e6xxx.h | 8 +++++--- 2 files changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 109452056eff..982151e64f43 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1091,7 +1091,7 @@ int mv88e6xxx_join_bridge(struct dsa_switch *ds, int port, u32 br_port_mask) ps->bridge_mask[fid] = br_port_mask; if (fid != ps->fid[port]) { - ps->fid_mask |= 1 << ps->fid[port]; + clear_bit(ps->fid[port], ps->fid_bitmap); ps->fid[port] = fid; ret = _mv88e6xxx_update_bridge_config(ds, fid); } @@ -1125,9 +1125,16 @@ int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask) mutex_lock(&ps->smi_mutex); - newfid = __ffs(ps->fid_mask); + newfid = find_next_zero_bit(ps->fid_bitmap, VLAN_N_VID, 1); + if (unlikely(newfid > ps->num_ports)) { + netdev_err(ds->ports[port], "all first %d FIDs are used\n", + ps->num_ports); + ret = -ENOSPC; + goto unlock; + } + ps->fid[port] = newfid; - ps->fid_mask &= ~(1 << newfid); + set_bit(newfid, ps->fid_bitmap); ps->bridge_mask[fid] &= ~(1 << port); ps->bridge_mask[newfid] = 1 << port; @@ -1135,6 +1142,7 @@ int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask) if (!ret) ret = _mv88e6xxx_update_bridge_config(ds, newfid); +unlock: mutex_unlock(&ps->smi_mutex); return ret; @@ -1552,9 +1560,9 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) * ports, and allow each of the 'real' ports to only talk to * the upstream port. */ - fid = __ffs(ps->fid_mask); + fid = port + 1; ps->fid[port] = fid; - ps->fid_mask &= ~(1 << fid); + set_bit(fid, ps->fid_bitmap); if (!dsa_is_cpu_port(ds, port)) ps->bridge_mask[fid] = 1 << port; @@ -1853,8 +1861,6 @@ int mv88e6xxx_setup_common(struct dsa_switch *ds) ps->id = REG_READ(REG_PORT(0), PORT_SWITCH_ID) & 0xfff0; - ps->fid_mask = (1 << DSA_MAX_PORTS) - 1; - INIT_WORK(&ps->bridge_work, mv88e6xxx_bridge_work); name = kasprintf(GFP_KERNEL, "dsa%d", ds->index); diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 78e37226a37d..33dcc16ed294 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -11,6 +11,8 @@ #ifndef __MV88E6XXX_H #define __MV88E6XXX_H +#include + #ifndef UINT64_MAX #define UINT64_MAX (u64)(~((u64)0)) #endif @@ -347,9 +349,9 @@ struct mv88e6xxx_priv_state { /* hw bridging */ - u32 fid_mask; - u8 fid[DSA_MAX_PORTS]; - u16 bridge_mask[DSA_MAX_PORTS]; + DECLARE_BITMAP(fid_bitmap, VLAN_N_VID); /* FIDs 1 to 4095 available */ + u16 fid[DSA_MAX_PORTS]; /* per (non-bridged) port FID */ + u16 bridge_mask[DSA_MAX_PORTS]; /* br groups (indexed by FID) */ unsigned long port_state_update_mask; u8 port_state[DSA_MAX_PORTS]; -- cgit v1.3-6-gb490 From 395059fb9269d97198ae3c94a798851e43062da6 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 6 Aug 2015 01:44:06 -0400 Subject: net: dsa: mv88e6xxx: rename ATU MAC accessors Rename the __mv88e6xxx_{read,write}_addr functions to more explicit _mv88e6xxx_atu_mac_{read,write} functions, which also respect the single underscore convention used in the file (meaning SMI lock must be held). In the meantime, define their MAC address parameters as an array of ETH_ALEN bytes instead of a char pointer. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 982151e64f43..1215e599b4e6 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1182,8 +1182,8 @@ int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state) return 0; } -static int __mv88e6xxx_write_addr(struct dsa_switch *ds, - const unsigned char *addr) +static int _mv88e6xxx_atu_mac_write(struct dsa_switch *ds, + const u8 addr[ETH_ALEN]) { int i, ret; @@ -1198,7 +1198,7 @@ static int __mv88e6xxx_write_addr(struct dsa_switch *ds, return 0; } -static int __mv88e6xxx_read_addr(struct dsa_switch *ds, unsigned char *addr) +static int _mv88e6xxx_atu_mac_read(struct dsa_switch *ds, u8 addr[ETH_ALEN]) { int i, ret; @@ -1225,7 +1225,7 @@ static int __mv88e6xxx_port_fdb_cmd(struct dsa_switch *ds, int port, if (ret < 0) return ret; - ret = __mv88e6xxx_write_addr(ds, addr); + ret = _mv88e6xxx_atu_mac_write(ds, addr); if (ret < 0) return ret; @@ -1280,7 +1280,7 @@ static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port, if (ret < 0) return ret; - ret = __mv88e6xxx_write_addr(ds, addr); + ret = _mv88e6xxx_atu_mac_write(ds, addr); if (ret < 0) return ret; @@ -1297,7 +1297,7 @@ static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port, return -ENOENT; } while (!(((ret >> 4) & 0xff) & (1 << port))); - ret = __mv88e6xxx_read_addr(ds, addr); + ret = _mv88e6xxx_atu_mac_read(ds, addr); if (ret < 0) return ret; @@ -1659,7 +1659,7 @@ static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds, unsigned char addr[6]; int ret, data, state; - ret = __mv88e6xxx_write_addr(ds, bcast); + ret = _mv88e6xxx_atu_mac_write(ds, bcast); if (ret < 0) return ret; @@ -1674,7 +1674,7 @@ static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds, state = data & GLOBAL_ATU_DATA_STATE_MASK; if (state == GLOBAL_ATU_DATA_STATE_UNUSED) break; - ret = __mv88e6xxx_read_addr(ds, addr); + ret = _mv88e6xxx_atu_mac_read(ds, addr); if (ret < 0) return ret; mv88e6xxx_atu_show_entry(s, dbnum, addr, data); -- cgit v1.3-6-gb490 From 6630e236179f278b5d471c10d458df309067341c Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 6 Aug 2015 01:44:07 -0400 Subject: net: dsa: mv88e6xxx: rework FDB getnext operation This commit adds a low level _mv88e6xxx_atu_getnext function and helpers to rewrite the mv88e6xxx_port_fdb_getnext operation. A mv88e6xxx_atu_entry structure is added for convenient access to the hardware, and GLOBAL_ATU_FID is defined instead of the raw 0x01 value. The previous implementation did not handle the eventual trunk mapping. If the related bit is set, then the ATU data register would contain the trunk ID, and not the port vector. Check this in the FDB getnext operation and do not handle it (yet). Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6171.c | 1 + drivers/net/dsa/mv88e6352.c | 1 + drivers/net/dsa/mv88e6xxx.c | 97 +++++++++++++++++++++++++++++++++------------ drivers/net/dsa/mv88e6xxx.h | 15 ++++++- 4 files changed, 87 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index cfa21ed1f734..b99fa50634bf 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -116,6 +116,7 @@ struct dsa_switch_driver mv88e6171_switch_driver = { .port_join_bridge = mv88e6xxx_join_bridge, .port_leave_bridge = mv88e6xxx_leave_bridge, .port_stp_update = mv88e6xxx_port_stp_update, + .port_fdb_getnext = mv88e6xxx_port_fdb_getnext, }; MODULE_ALIAS("platform:mv88e6171"); diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index eb4630fec6f1..0a77135dd2b0 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -341,6 +341,7 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .port_join_bridge = mv88e6xxx_join_bridge, .port_leave_bridge = mv88e6xxx_leave_bridge, .port_stp_update = mv88e6xxx_port_stp_update, + .port_fdb_getnext = mv88e6xxx_port_fdb_getnext, }; MODULE_ALIAS("platform:mv88e6172"); diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 1215e599b4e6..0e588b9809d9 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -964,7 +964,7 @@ static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd) { int ret; - ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, 0x01, fid); + ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, fid); if (ret < 0) return ret; @@ -1269,12 +1269,14 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, return ret; } -static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port, - unsigned char *addr, bool *is_static) +static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid, + const u8 addr[ETH_ALEN], + struct mv88e6xxx_atu_entry *entry) { - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - u8 fid = ps->fid[port]; - int ret, state; + struct mv88e6xxx_atu_entry next = { 0 }; + int ret; + + next.fid = fid; ret = _mv88e6xxx_atu_wait(ds); if (ret < 0) @@ -1284,39 +1286,84 @@ static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port, if (ret < 0) return ret; - do { - ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB); - if (ret < 0) - return ret; + ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB); + if (ret < 0) + return ret; - ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA); - if (ret < 0) - return ret; - state = ret & GLOBAL_ATU_DATA_STATE_MASK; - if (state == GLOBAL_ATU_DATA_STATE_UNUSED) - return -ENOENT; - } while (!(((ret >> 4) & 0xff) & (1 << port))); + ret = _mv88e6xxx_atu_mac_read(ds, next.mac); + if (ret < 0) + return ret; - ret = _mv88e6xxx_atu_mac_read(ds, addr); + ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA); if (ret < 0) return ret; - *is_static = state == (is_multicast_ether_addr(addr) ? - GLOBAL_ATU_DATA_STATE_MC_STATIC : - GLOBAL_ATU_DATA_STATE_UC_STATIC); + next.state = ret & GLOBAL_ATU_DATA_STATE_MASK; + if (next.state != GLOBAL_ATU_DATA_STATE_UNUSED) { + unsigned int mask, shift; + + if (ret & GLOBAL_ATU_DATA_TRUNK) { + next.trunk = true; + mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK; + shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT; + } else { + next.trunk = false; + mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK; + shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT; + } + + next.portv_trunkid = (ret & mask) >> shift; + } + *entry = next; return 0; } -/* get next entry for port */ -int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, - unsigned char *addr, bool *is_static) +static int _mv88e6xxx_port_vid_to_fid(struct dsa_switch *ds, int port, u16 vid) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + if (vid == 0) + return ps->fid[port]; + + return -ENOENT; +} + +int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, u16 *vid, + u8 addr[ETH_ALEN], bool *is_static) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + struct mv88e6xxx_atu_entry next; + u16 fid; int ret; mutex_lock(&ps->smi_mutex); - ret = __mv88e6xxx_port_getnext(ds, port, addr, is_static); + + ret = _mv88e6xxx_port_vid_to_fid(ds, port, *vid); + if (ret < 0) + goto unlock; + fid = ret; + + do { + if (is_broadcast_ether_addr(addr)) { + ret = -ENOENT; + goto unlock; + } + + ret = _mv88e6xxx_atu_getnext(ds, fid, addr, &next); + if (ret < 0) + goto unlock; + + ether_addr_copy(addr, next.mac); + + if (next.state == GLOBAL_ATU_DATA_STATE_UNUSED) + continue; + } while (next.trunk || (next.portv_trunkid & BIT(port)) == 0); + + *is_static = next.state == (is_multicast_ether_addr(addr) ? + GLOBAL_ATU_DATA_STATE_MC_STATIC : + GLOBAL_ATU_DATA_STATE_UC_STATIC); +unlock: mutex_unlock(&ps->smi_mutex); return ret; diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 33dcc16ed294..ae640c7b6b0c 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -171,6 +171,7 @@ #define GLOBAL_MAC_01 0x01 #define GLOBAL_MAC_23 0x02 #define GLOBAL_MAC_45 0x03 +#define GLOBAL_ATU_FID 0x01 /* 6097 6165 6351 6352 */ #define GLOBAL_CONTROL 0x04 #define GLOBAL_CONTROL_SW_RESET BIT(15) #define GLOBAL_CONTROL_PPU_ENABLE BIT(14) @@ -205,6 +206,8 @@ #define GLOBAL_ATU_OP_GET_CLR_VIOLATION ((7 << 12) | GLOBAL_ATU_OP_BUSY) #define GLOBAL_ATU_DATA 0x0c #define GLOBAL_ATU_DATA_TRUNK BIT(15) +#define GLOBAL_ATU_DATA_TRUNK_ID_MASK 0x00f0 +#define GLOBAL_ATU_DATA_TRUNK_ID_SHIFT 4 #define GLOBAL_ATU_DATA_PORT_VECTOR_MASK 0x3ff0 #define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT 4 #define GLOBAL_ATU_DATA_STATE_MASK 0x0f @@ -311,6 +314,14 @@ #define GLOBAL2_QOS_WEIGHT 0x1c #define GLOBAL2_MISC 0x1d +struct mv88e6xxx_atu_entry { + u16 fid; + u8 state; + bool trunk; + u16 portv_trunkid; + u8 mac[ETH_ALEN]; +}; + struct mv88e6xxx_priv_state { /* When using multi-chip addressing, this mutex protects * access to the indirect access registers. (In single-chip @@ -415,11 +426,11 @@ int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid); int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid); -int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, - unsigned char *addr, bool *is_static); int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg); int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, int reg, int val); +int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, u16 *vid, + u8 addr[ETH_ALEN], bool *is_static); extern struct dsa_switch_driver mv88e6131_switch_driver; extern struct dsa_switch_driver mv88e6123_61_65_switch_driver; -- cgit v1.3-6-gb490 From 878205101ff1bedfc504bfaa5e999bf426bacd89 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 6 Aug 2015 01:44:08 -0400 Subject: net: dsa: mv88e6xxx: rework FDB add/del operations Add a low level function for the ATU Load operation, and provide FDB add and delete wrappers functions. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6171.c | 2 + drivers/net/dsa/mv88e6352.c | 2 + drivers/net/dsa/mv88e6xxx.c | 110 +++++++++++++++++++++++++++++--------------- drivers/net/dsa/mv88e6xxx.h | 8 ++-- 4 files changed, 80 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index b99fa50634bf..735f04cd83ee 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -116,6 +116,8 @@ struct dsa_switch_driver mv88e6171_switch_driver = { .port_join_bridge = mv88e6xxx_join_bridge, .port_leave_bridge = mv88e6xxx_leave_bridge, .port_stp_update = mv88e6xxx_port_stp_update, + .port_fdb_add = mv88e6xxx_port_fdb_add, + .port_fdb_del = mv88e6xxx_port_fdb_del, .port_fdb_getnext = mv88e6xxx_port_fdb_getnext, }; diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 0a77135dd2b0..191fb2531efe 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -341,6 +341,8 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .port_join_bridge = mv88e6xxx_join_bridge, .port_leave_bridge = mv88e6xxx_leave_bridge, .port_stp_update = mv88e6xxx_port_stp_update, + .port_fdb_add = mv88e6xxx_port_fdb_add, + .port_fdb_del = mv88e6xxx_port_fdb_del, .port_fdb_getnext = mv88e6xxx_port_fdb_getnext, }; diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 0e588b9809d9..9c6781de533b 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1214,59 +1214,42 @@ static int _mv88e6xxx_atu_mac_read(struct dsa_switch *ds, u8 addr[ETH_ALEN]) return 0; } -static int __mv88e6xxx_port_fdb_cmd(struct dsa_switch *ds, int port, - const unsigned char *addr, int state) +static int _mv88e6xxx_atu_load(struct dsa_switch *ds, + struct mv88e6xxx_atu_entry *entry) { - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - u8 fid = ps->fid[port]; + u16 reg = 0; int ret; ret = _mv88e6xxx_atu_wait(ds); if (ret < 0) return ret; - ret = _mv88e6xxx_atu_mac_write(ds, addr); + ret = _mv88e6xxx_atu_mac_write(ds, entry->mac); if (ret < 0) return ret; - ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, - (0x10 << port) | state); - if (ret) - return ret; + if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) { + unsigned int mask, shift; - ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_LOAD_DB); + if (entry->trunk) { + reg |= GLOBAL_ATU_DATA_TRUNK; + mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK; + shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT; + } else { + mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK; + shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT; + } - return ret; -} + reg |= (entry->portv_trunkid << shift) & mask; + } -int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid) -{ - int state = is_multicast_ether_addr(addr) ? - GLOBAL_ATU_DATA_STATE_MC_STATIC : - GLOBAL_ATU_DATA_STATE_UC_STATIC; - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int ret; + reg |= entry->state & GLOBAL_ATU_DATA_STATE_MASK; - mutex_lock(&ps->smi_mutex); - ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, state); - mutex_unlock(&ps->smi_mutex); + ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, reg); + if (ret < 0) + return ret; - return ret; -} - -int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int ret; - - mutex_lock(&ps->smi_mutex); - ret = __mv88e6xxx_port_fdb_cmd(ds, port, addr, - GLOBAL_ATU_DATA_STATE_UNUSED); - mutex_unlock(&ps->smi_mutex); - - return ret; + return _mv88e6xxx_atu_cmd(ds, entry->fid, GLOBAL_ATU_OP_LOAD_DB); } static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid, @@ -1329,6 +1312,57 @@ static int _mv88e6xxx_port_vid_to_fid(struct dsa_switch *ds, int port, u16 vid) return -ENOENT; } +static int _mv88e6xxx_port_fdb_load(struct dsa_switch *ds, int port, u16 vid, + const u8 addr[ETH_ALEN], u8 state) +{ + struct mv88e6xxx_atu_entry entry = { 0 }; + int ret; + + ret = _mv88e6xxx_port_vid_to_fid(ds, port, vid); + if (ret < 0) + return ret; + + entry.fid = ret; + entry.state = state; + ether_addr_copy(entry.mac, addr); + if (state != GLOBAL_ATU_DATA_STATE_UNUSED) { + entry.trunk = false; + entry.portv_trunkid = BIT(port); + } + + return _mv88e6xxx_atu_load(ds, &entry); +} + +int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, u16 vid, + const u8 addr[ETH_ALEN]) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + u8 state = is_multicast_ether_addr(addr) ? + GLOBAL_ATU_DATA_STATE_MC_STATIC : + GLOBAL_ATU_DATA_STATE_UC_STATIC; + int ret; + + mutex_lock(&ps->smi_mutex); + ret = _mv88e6xxx_port_fdb_load(ds, port, vid, addr, state); + mutex_unlock(&ps->smi_mutex); + + return ret; +} + +int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, u16 vid, + const u8 addr[ETH_ALEN]) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + u8 state = GLOBAL_ATU_DATA_STATE_UNUSED; + int ret; + + mutex_lock(&ps->smi_mutex); + ret = _mv88e6xxx_port_fdb_load(ds, port, vid, addr, state); + mutex_unlock(&ps->smi_mutex); + + return ret; +} + int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, u16 *vid, u8 addr[ETH_ALEN], bool *is_static) { diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index ae640c7b6b0c..a8c727d846dd 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -422,13 +422,13 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, int mv88e6xxx_join_bridge(struct dsa_switch *ds, int port, u32 br_port_mask); int mv88e6xxx_leave_bridge(struct dsa_switch *ds, int port, u32 br_port_mask); int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state); -int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid); -int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid); int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg); int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, int reg, int val); +int mv88e6xxx_port_fdb_add(struct dsa_switch *ds, int port, u16 vid, + const u8 addr[ETH_ALEN]); +int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port, u16 vid, + const u8 addr[ETH_ALEN]); int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, u16 *vid, u8 addr[ETH_ALEN], bool *is_static); -- cgit v1.3-6-gb490 From 0024f8920045c6a57d98b44290bbaebb0e3c6c00 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Thu, 6 Aug 2015 19:03:35 +0800 Subject: net: phy: add RealTek RTL8211DN phy id RTL8211DN is compatible with RTL8211E. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/phy/realtek.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 45353613b2ed..43ab691362d4 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -136,6 +136,19 @@ static struct phy_driver realtek_drvs[] = { .ack_interrupt = &rtl821x_ack_interrupt, .config_intr = &rtl8211b_config_intr, .driver = { .owner = THIS_MODULE,}, + }, { + .phy_id = 0x001cc914, + .name = "RTL8211DN Gigabit Ethernet", + .phy_id_mask = 0x001fffff, + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = rtl821x_ack_interrupt, + .config_intr = rtl8211e_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, + .driver = { .owner = THIS_MODULE,}, }, { .phy_id = 0x001cc915, .name = "RTL8211E Gigabit Ethernet", @@ -170,6 +183,7 @@ module_phy_driver(realtek_drvs); static struct mdio_device_id __maybe_unused realtek_tbl[] = { { 0x001cc912, 0x001fffff }, + { 0x001cc914, 0x001fffff }, { 0x001cc915, 0x001fffff }, { 0x001cc916, 0x001fffff }, { } -- cgit v1.3-6-gb490 From 26a80f6e542e6b86c9ad9c3d217d74ca8c3fed66 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 6 Aug 2015 16:41:52 +0200 Subject: mlxsw: Call free_netdev when removing port When removing a port's netdevice we should also free the memory allocated by alloc_etherdev(). Do this by calling free_netdev() at the end of the teardown sequence. Reported-by: Or Gerlitz Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c index 29b46eef9769..687f5cbef25b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c @@ -1079,6 +1079,7 @@ static void mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port) unregister_netdev(mlxsw_sx_port->dev); /* This calls ndo_stop */ mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT); free_percpu(mlxsw_sx_port->pcpu_stats); + free_netdev(mlxsw_sx_port->dev); } static void mlxsw_sx_ports_remove(struct mlxsw_sx *mlxsw_sx) -- cgit v1.3-6-gb490 From e61011b5e044b15727fc6ee330c17f1fc69faef8 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 6 Aug 2015 16:41:53 +0200 Subject: mlxsw: Make system port to local port mapping explicit System ports are unique identifiers in a multi-ASIC environment that represent all the available ports in the system. Local ports on the other hand, are unique only within the local ASIC. Since system port to local port mapping is not part of the HW-SW contract and since only single-ASIC configurations are currently supported, set an explicit 1:1 mapping by configuring the Switch System Port Record (SSPR) register. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 60 ++++++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 18 ++++++++ 2 files changed, 78 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index b5a72f8e78b1..096e1c12175a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -150,6 +150,64 @@ static inline void mlxsw_reg_smid_pack(char *payload, u16 mid) mlxsw_reg_smid_port_mask_set(payload, MLXSW_PORT_CPU_PORT, 1); } +/* SSPR - Switch System Port Record Register + * ----------------------------------------- + * Configures the system port to local port mapping. + */ +#define MLXSW_REG_SSPR_ID 0x2008 +#define MLXSW_REG_SSPR_LEN 0x8 + +static const struct mlxsw_reg_info mlxsw_reg_sspr = { + .id = MLXSW_REG_SSPR_ID, + .len = MLXSW_REG_SSPR_LEN, +}; + +/* reg_sspr_m + * Master - if set, then the record describes the master system port. + * This is needed in case a local port is mapped into several system ports + * (for multipathing). That number will be reported as the source system + * port when packets are forwarded to the CPU. Only one master port is allowed + * per local port. + * + * Note: Must be set for Spectrum. + * Access: RW + */ +MLXSW_ITEM32(reg, sspr, m, 0x00, 31, 1); + +/* reg_sspr_local_port + * Local port number. + * + * Access: RW + */ +MLXSW_ITEM32(reg, sspr, local_port, 0x00, 16, 8); + +/* reg_sspr_sub_port + * Virtual port within the physical port. + * Should be set to 0 when virtual ports are not enabled on the port. + * + * Access: RW + */ +MLXSW_ITEM32(reg, sspr, sub_port, 0x00, 8, 8); + +/* reg_sspr_system_port + * Unique identifier within the stacking domain that represents all the ports + * that are available in the system (external ports). + * + * Currently, only single-ASIC configurations are supported, so we default to + * 1:1 mapping between system ports and local ports. + * Access: Index + */ +MLXSW_ITEM32(reg, sspr, system_port, 0x04, 0, 16); + +static inline void mlxsw_reg_sspr_pack(char *payload, u8 local_port) +{ + MLXSW_REG_ZERO(sspr, payload); + mlxsw_reg_sspr_m_set(payload, 1); + mlxsw_reg_sspr_local_port_set(payload, local_port); + mlxsw_reg_sspr_sub_port_set(payload, 0); + mlxsw_reg_sspr_system_port_set(payload, local_port); +} + /* SPMS - Switch Port MSTP/RSTP State Register * ------------------------------------------- * Configures the spanning tree state of a physical port. @@ -1216,6 +1274,8 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id) return "SPAD"; case MLXSW_REG_SMID_ID: return "SMID"; + case MLXSW_REG_SSPR_ID: + return "SSPR"; case MLXSW_REG_SPMS_ID: return "SPMS"; case MLXSW_REG_SFGC_ID: diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c index 687f5cbef25b..7eb045ef797a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c @@ -245,6 +245,16 @@ static int mlxsw_sx_port_swid_set(struct mlxsw_sx_port *mlxsw_sx_port, u8 swid) return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(pspa), pspa_pl); } +static int +mlxsw_sx_port_system_port_mapping_set(struct mlxsw_sx_port *mlxsw_sx_port) +{ + struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx; + char sspr_pl[MLXSW_REG_SSPR_LEN]; + + mlxsw_reg_sspr_pack(sspr_pl, mlxsw_sx_port->local_port); + return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sspr), sspr_pl); +} + static int mlxsw_sx_port_module_check(struct mlxsw_sx_port *mlxsw_sx_port, bool *p_usable) { @@ -1001,6 +1011,13 @@ static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port) goto port_not_usable; } + err = mlxsw_sx_port_system_port_mapping_set(mlxsw_sx_port); + if (err) { + dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set system port mapping\n", + mlxsw_sx_port->local_port); + goto err_port_system_port_mapping_set; + } + err = mlxsw_sx_port_swid_set(mlxsw_sx_port, 0); if (err) { dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set SWID\n", @@ -1061,6 +1078,7 @@ err_port_stp_state_set: err_port_mtu_set: err_port_speed_set: err_port_swid_set: +err_port_system_port_mapping_set: port_not_usable: err_port_module_check: err_dev_addr_get: -- cgit v1.3-6-gb490 From 74ed207e2a82dece0de0849df62cd450dec9d4d7 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 6 Aug 2015 16:41:54 +0200 Subject: mlxsw: Make pci module dependent on HAS_DMA and HAS_IOMEM This resolves compile errors on um-allyesconfig. Note that there are many other drivers which have the same issue. Reported-by: kbuild test robot Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig index 8d1080da49b5..2941d9c5ae48 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig @@ -12,7 +12,7 @@ config MLXSW_CORE config MLXSW_PCI tristate "PCI bus implementation for Mellanox Technologies Switch ASICs" - depends on PCI && MLXSW_CORE + depends on PCI && HAS_DMA && HAS_IOMEM && MLXSW_CORE default m ---help--- This is PCI bus implementation for Mellanox Technologies Switch ASICs. -- cgit v1.3-6-gb490 From 7b7b9cff7468fdf38ab189dde6ecb4750b171bc8 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 6 Aug 2015 16:41:55 +0200 Subject: mlxsw: Strip FCS from incoming packets FCS of incoming packets is already checked by HW. Just strip it out. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 6 +++++- drivers/net/ethernet/mellanox/mlxsw/pci.h | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 298ead5b42ca..3ec52ea10f83 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -667,6 +667,7 @@ static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci, char *wqe; struct sk_buff *skb; struct mlxsw_rx_info rx_info; + u16 byte_count; int err; elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); @@ -686,7 +687,10 @@ static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci, rx_info.sys_port = mlxsw_pci_cqe_system_port_get(cqe); rx_info.trap_id = mlxsw_pci_cqe_trap_id_get(cqe); - skb_put(skb, mlxsw_pci_cqe_byte_count_get(cqe)); + byte_count = mlxsw_pci_cqe_byte_count_get(cqe); + if (mlxsw_pci_cqe_crc_get(cqe)) + byte_count -= ETH_FCS_LEN; + skb_put(skb, byte_count); mlxsw_core_skb_receive(mlxsw_pci->core, skb, &rx_info); put_new_skb: diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.h b/drivers/net/ethernet/mellanox/mlxsw/pci.h index 887af8459149..1ef9664b4512 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.h @@ -155,6 +155,12 @@ MLXSW_ITEM32(pci, cqe, byte_count, 0x04, 0, 14); */ MLXSW_ITEM32(pci, cqe, trap_id, 0x08, 0, 8); +/* pci_cqe_crc + * Length include CRC. Indicates the length field includes + * the packet's CRC. + */ +MLXSW_ITEM32(pci, cqe, crc, 0x0C, 8, 1); + /* pci_cqe_e * CQE with Error. */ -- cgit v1.3-6-gb490 From d003462a50de8605e66be0966e6370ab9821e07e Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 6 Aug 2015 16:41:56 +0200 Subject: mlxsw: Simplify mlxsw_sx_port_xmit function Previously we only checked if the transmission queue is not full in the middle of the xmit function. This lead to complex logic due to the fact that sometimes we need to reallocate the headroom for our Tx header. Allow the switch driver to know if the transmission queue is not full before sending the packet and remove this complex logic. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 10 ++++++++++ drivers/net/ethernet/mellanox/mlxsw/core.h | 5 +++++ drivers/net/ethernet/mellanox/mlxsw/pci.c | 20 +++++++++++++++----- drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 25 ++++++++++--------------- 4 files changed, 40 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index ad66ae44a0d7..7562802bc6c8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -865,6 +865,16 @@ static struct mlxsw_core *__mlxsw_core_get(void *driver_priv) return container_of(driver_priv, struct mlxsw_core, driver_priv); } +bool mlxsw_core_skb_transmit_busy(void *driver_priv, + const struct mlxsw_tx_info *tx_info) +{ + struct mlxsw_core *mlxsw_core = __mlxsw_core_get(driver_priv); + + return mlxsw_core->bus->skb_transmit_busy(mlxsw_core->bus_priv, + tx_info); +} +EXPORT_SYMBOL(mlxsw_core_skb_transmit_busy); + int mlxsw_core_skb_transmit(void *driver_priv, struct sk_buff *skb, const struct mlxsw_tx_info *tx_info) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index 2280b319c362..165808471188 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -73,6 +73,9 @@ struct mlxsw_tx_info { bool is_emad; }; +bool mlxsw_core_skb_transmit_busy(void *driver_priv, + const struct mlxsw_tx_info *tx_info); + int mlxsw_core_skb_transmit(void *driver_priv, struct sk_buff *skb, const struct mlxsw_tx_info *tx_info); @@ -177,6 +180,8 @@ struct mlxsw_bus { int (*init)(void *bus_priv, struct mlxsw_core *mlxsw_core, const struct mlxsw_config_profile *profile); void (*fini)(void *bus_priv); + bool (*skb_transmit_busy)(void *bus_priv, + const struct mlxsw_tx_info *tx_info); int (*skb_transmit)(void *bus_priv, struct sk_buff *skb, const struct mlxsw_tx_info *tx_info); int (*cmd_exec)(void *bus_priv, u16 opcode, u8 opcode_mod, diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 3ec52ea10f83..a34f4742aa00 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1443,6 +1443,15 @@ mlxsw_pci_sdq_pick(struct mlxsw_pci *mlxsw_pci, return mlxsw_pci_sdq_get(mlxsw_pci, sdqn); } +static bool mlxsw_pci_skb_transmit_busy(void *bus_priv, + const struct mlxsw_tx_info *tx_info) +{ + struct mlxsw_pci *mlxsw_pci = bus_priv; + struct mlxsw_pci_queue *q = mlxsw_pci_sdq_pick(mlxsw_pci, tx_info); + + return !mlxsw_pci_queue_elem_info_producer_get(q); +} + static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb, const struct mlxsw_tx_info *tx_info) { @@ -1625,11 +1634,12 @@ err_in_mbox_map: } static const struct mlxsw_bus mlxsw_pci_bus = { - .kind = "pci", - .init = mlxsw_pci_init, - .fini = mlxsw_pci_fini, - .skb_transmit = mlxsw_pci_skb_transmit, - .cmd_exec = mlxsw_pci_cmd_exec, + .kind = "pci", + .init = mlxsw_pci_init, + .fini = mlxsw_pci_fini, + .skb_transmit_busy = mlxsw_pci_skb_transmit_busy, + .skb_transmit = mlxsw_pci_skb_transmit, + .cmd_exec = mlxsw_pci_cmd_exec, }; static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci) diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c index 7eb045ef797a..fce9b453433b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c @@ -300,31 +300,26 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb, .local_port = mlxsw_sx_port->local_port, .is_emad = false, }; - struct sk_buff *skb_old = NULL; int err; + if (mlxsw_core_skb_transmit_busy(mlxsw_sx, &tx_info)) + return NETDEV_TX_BUSY; + if (unlikely(skb_headroom(skb) < MLXSW_TXHDR_LEN)) { - struct sk_buff *skb_new; + struct sk_buff *skb_orig = skb; - skb_old = skb; - skb_new = skb_realloc_headroom(skb, MLXSW_TXHDR_LEN); - if (!skb_new) { + skb = skb_realloc_headroom(skb, MLXSW_TXHDR_LEN); + if (!skb) { this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped); - dev_kfree_skb_any(skb_old); + dev_kfree_skb_any(skb_orig); return NETDEV_TX_OK; } - skb = skb_new; } mlxsw_sx_txhdr_construct(skb, &tx_info); + /* Due to a race we might fail here because of a full queue. In that + * unlikely case we simply drop the packet. + */ err = mlxsw_core_skb_transmit(mlxsw_sx, skb, &tx_info); - if (err == -EAGAIN) { - if (skb_old) - dev_kfree_skb_any(skb); - return NETDEV_TX_BUSY; - } - - if (skb_old) - dev_kfree_skb_any(skb_old); if (!err) { pcpu_stats = this_cpu_ptr(mlxsw_sx_port->pcpu_stats); -- cgit v1.3-6-gb490 From 3bfcd34764cbd3bcb48f6e9009eacf1d19856213 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 6 Aug 2015 16:41:57 +0200 Subject: mlxsw: Use correct skb length when dumping payload Do not use the length of the transmitted skb (which was freed), but that of the response skb. This issue was discovered using the Kernel Address sanitizer (KASan). Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 7562802bc6c8..09325b72d524 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -1073,7 +1073,7 @@ static int mlxsw_core_reg_access_emad(struct mlxsw_core *mlxsw_core, mlxsw_core->emad.tid - 1); mlxsw_core_buf_dump_dbg(mlxsw_core, mlxsw_core->emad.resp_skb->data, - skb->len); + mlxsw_core->emad.resp_skb->len); dev_kfree_skb(mlxsw_core->emad.resp_skb); } -- cgit v1.3-6-gb490 From e577516b9db3e0f19df82b6430fe3b06e05d6304 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 6 Aug 2015 16:41:58 +0200 Subject: mlxsw: Fix use-after-free bug in mlxsw_sx_port_xmit Store the length of the skb before transmitting it and use it for stats instead of skb->len, since skb might have been freed already. This issue was discovered using the Kernel Address sanitizer (KASan). Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c index fce9b453433b..3e52ee93438c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c @@ -300,6 +300,7 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb, .local_port = mlxsw_sx_port->local_port, .is_emad = false, }; + u64 len; int err; if (mlxsw_core_skb_transmit_busy(mlxsw_sx, &tx_info)) @@ -316,6 +317,7 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb, } } mlxsw_sx_txhdr_construct(skb, &tx_info); + len = skb->len; /* Due to a race we might fail here because of a full queue. In that * unlikely case we simply drop the packet. */ @@ -325,7 +327,7 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb, pcpu_stats = this_cpu_ptr(mlxsw_sx_port->pcpu_stats); u64_stats_update_begin(&pcpu_stats->syncp); pcpu_stats->tx_packets++; - pcpu_stats->tx_bytes += skb->len; + pcpu_stats->tx_bytes += len; u64_stats_update_end(&pcpu_stats->syncp); } else { this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped); -- cgit v1.3-6-gb490 From c5f3d544a7f29b16de37c10f51b38c4b7ad31804 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 18 Jun 2015 18:33:46 +0530 Subject: i2c: parport: use dev_* Now parport is using device model so use dev_* macros instead of printk. Signed-off-by: Sudip Mukherjee Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-parport.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 9b94c3db80ab..3794f7d18442 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -215,7 +215,8 @@ static void i2c_parport_attach(struct parport *port) adapter->adapter.dev.parent = port->physport->dev; if (parport_claim_or_block(adapter->pdev) < 0) { - printk(KERN_ERR "i2c-parport: Could not claim parallel port\n"); + dev_err(&adapter->pdev->dev, + "Could not claim parallel port\n"); goto err_unregister; } @@ -230,7 +231,7 @@ static void i2c_parport_attach(struct parport *port) } if (i2c_bit_add_bus(&adapter->adapter) < 0) { - printk(KERN_ERR "i2c-parport: Unable to register with I2C\n"); + dev_err(&adapter->pdev->dev, "Unable to register with I2C\n"); goto err_unregister; } @@ -242,8 +243,8 @@ static void i2c_parport_attach(struct parport *port) if (adapter->ara) parport_enable_irq(port); else - printk(KERN_WARNING "i2c-parport: Failed to register " - "ARA client\n"); + dev_warn(&adapter->pdev->dev, + "Failed to register ARA client\n"); } /* Add the new adapter to the list */ -- cgit v1.3-6-gb490 From 20226118bceed7b432f4bc5bae34c1c160689bf7 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 18 Jun 2015 18:33:47 +0530 Subject: i2c: parport: start using pr_fmt Start using pr_fmt and convert all remaining printk to use pr_* family of macros. Signed-off-by: Sudip Mukherjee [wsa: remove print on kzalloc failure] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-parport.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 3794f7d18442..a8e54df4aed6 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -20,6 +20,8 @@ GNU General Public License for more details. * ------------------------------------------------------------------------ */ +#define pr_fmt(fmt) "i2c-parport: " fmt + #include #include #include @@ -176,26 +178,24 @@ static void i2c_parport_attach(struct parport *port) break; } if (i == MAX_DEVICE) { - pr_debug("i2c-parport: Not using parport%d.\n", port->number); + pr_debug("Not using parport%d.\n", port->number); return; } adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL); - if (adapter == NULL) { - printk(KERN_ERR "i2c-parport: Failed to kzalloc\n"); + if (!adapter) return; - } memset(&i2c_parport_cb, 0, sizeof(i2c_parport_cb)); i2c_parport_cb.flags = PARPORT_FLAG_EXCL; i2c_parport_cb.irq_func = i2c_parport_irq; i2c_parport_cb.private = adapter; - pr_debug("i2c-parport: attaching to %s\n", port->name); + pr_debug("attaching to %s\n", port->name); parport_disable_irq(port); adapter->pdev = parport_register_dev_model(port, "i2c-parport", &i2c_parport_cb, i); if (!adapter->pdev) { - printk(KERN_ERR "i2c-parport: Unable to register with parport\n"); + pr_err("Unable to register with parport\n"); goto err_free; } @@ -299,12 +299,12 @@ static struct parport_driver i2c_parport_driver = { static int __init i2c_parport_init(void) { if (type < 0) { - printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); + pr_warn("adapter type unspecified\n"); return -ENODEV; } if (type >= ARRAY_SIZE(adapter_parm)) { - printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); + pr_warn("invalid type (%d)\n", type); return -ENODEV; } -- cgit v1.3-6-gb490 From c680e3291857216465714ba1d3336befaa5b4725 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 13 Jul 2015 15:38:02 -0500 Subject: i2c: omap: switch to dev_get_drvdata() there's no need to fetch the platform_device in order to dereference it back to the dev pointer to access drvdata, we can use dev_get_drvdata() instead. Signed-off-by: Felipe Balbi Acked-by: Alexander Sverdlin Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index fc9bf7f30e35..ce34f431a3ac 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1476,8 +1476,7 @@ static int omap_i2c_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int omap_i2c_runtime_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); + struct omap_i2c_dev *_dev = dev_get_drvdata(dev); _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); @@ -1503,8 +1502,7 @@ static int omap_i2c_runtime_suspend(struct device *dev) static int omap_i2c_runtime_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); + struct omap_i2c_dev *_dev = dev_get_drvdata(dev); pinctrl_pm_select_default_state(dev); -- cgit v1.3-6-gb490 From 63f8f85625fa726bdf28862dd4d2e1bf3d230bb8 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 13 Jul 2015 15:38:03 -0500 Subject: i2c: omap: abolish variable name confusion struct device pointers are usually called dev. Calling our struct omap_i2c_dev pointers also dev has caused enough confusion. This is the result of a few simple sed rules to convert all struct omap_i2c_dev pointers to be called omap instead. Signed-off-by: Felipe Balbi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 598 +++++++++++++++++++++--------------------- 1 file changed, 299 insertions(+), 299 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ce34f431a3ac..e359ad39753b 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -270,35 +270,35 @@ static const u8 reg_map_ip_v2[] = { [OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30, }; -static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev, +static inline void omap_i2c_write_reg(struct omap_i2c_dev *omap, int reg, u16 val) { - writew_relaxed(val, i2c_dev->base + - (i2c_dev->regs[reg] << i2c_dev->reg_shift)); + writew_relaxed(val, omap->base + + (omap->regs[reg] << omap->reg_shift)); } -static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) +static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *omap, int reg) { - return readw_relaxed(i2c_dev->base + - (i2c_dev->regs[reg] << i2c_dev->reg_shift)); + return readw_relaxed(omap->base + + (omap->regs[reg] << omap->reg_shift)); } -static void __omap_i2c_init(struct omap_i2c_dev *dev) +static void __omap_i2c_init(struct omap_i2c_dev *omap) { - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */ - omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate); + omap_i2c_write_reg(omap, OMAP_I2C_PSC_REG, omap->pscstate); /* SCL low and high time values */ - omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate); - omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate); - if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) - omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); + omap_i2c_write_reg(omap, OMAP_I2C_SCLL_REG, omap->scllstate); + omap_i2c_write_reg(omap, OMAP_I2C_SCLH_REG, omap->sclhstate); + if (omap->rev >= OMAP_I2C_REV_ON_3430_3530) + omap_i2c_write_reg(omap, OMAP_I2C_WE_REG, omap->westate); /* Take the I2C module out of reset: */ - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); /* * NOTE: right after setting CON_EN, STAT_BB could be 0 while the @@ -310,32 +310,32 @@ static void __omap_i2c_init(struct omap_i2c_dev *dev) * Don't write to this register if the IE state is 0 as it can * cause deadlock. */ - if (dev->iestate) - omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); + if (omap->iestate) + omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, omap->iestate); } -static int omap_i2c_reset(struct omap_i2c_dev *dev) +static int omap_i2c_reset(struct omap_i2c_dev *omap) { unsigned long timeout; u16 sysc; - if (dev->rev >= OMAP_I2C_OMAP1_REV_2) { - sysc = omap_i2c_read_reg(dev, OMAP_I2C_SYSC_REG); + if (omap->rev >= OMAP_I2C_OMAP1_REV_2) { + sysc = omap_i2c_read_reg(omap, OMAP_I2C_SYSC_REG); /* Disable I2C controller before soft reset */ - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, - omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) & + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, + omap_i2c_read_reg(omap, OMAP_I2C_CON_REG) & ~(OMAP_I2C_CON_EN)); - omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK); + omap_i2c_write_reg(omap, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK); /* For some reason we need to set the EN bit before the * reset done bit gets set. */ timeout = jiffies + OMAP_I2C_TIMEOUT; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); - while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) & + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); + while (!(omap_i2c_read_reg(omap, OMAP_I2C_SYSS_REG) & SYSS_RESETDONE_MASK)) { if (time_after(jiffies, timeout)) { - dev_warn(dev->dev, "timeout waiting " + dev_warn(omap->dev, "timeout waiting " "for controller reset\n"); return -ETIMEDOUT; } @@ -343,18 +343,18 @@ static int omap_i2c_reset(struct omap_i2c_dev *dev) } /* SYSC register is cleared by the reset; rewrite it */ - omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, sysc); + omap_i2c_write_reg(omap, OMAP_I2C_SYSC_REG, sysc); - if (dev->rev > OMAP_I2C_REV_ON_3430_3530) { + if (omap->rev > OMAP_I2C_REV_ON_3430_3530) { /* Schedule I2C-bus monitoring on the next transfer */ - dev->bb_valid = 0; + omap->bb_valid = 0; } } return 0; } -static int omap_i2c_init(struct omap_i2c_dev *dev) +static int omap_i2c_init(struct omap_i2c_dev *omap) { u16 psc = 0, scll = 0, sclh = 0; u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0; @@ -362,23 +362,23 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) unsigned long internal_clk = 0; struct clk *fclk; - if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) { + if (omap->rev >= OMAP_I2C_REV_ON_3430_3530) { /* * Enabling all wakup sources to stop I2C freezing on * WFI instruction. * REVISIT: Some wkup sources might not be needed. */ - dev->westate = OMAP_I2C_WE_ALL; + omap->westate = OMAP_I2C_WE_ALL; } - if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { + if (omap->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { /* * The I2C functional clock is the armxor_ck, so there's * no need to get "armxor_ck" separately. Now, if OMAP2420 * always returns 12MHz for the functional clock, we can * do this bit unconditionally. */ - fclk = clk_get(dev->dev, "fck"); + fclk = clk_get(omap->dev, "fck"); fclk_rate = clk_get_rate(fclk); clk_put(fclk); @@ -395,7 +395,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) psc = fclk_rate / 12000000; } - if (!(dev->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { + if (!(omap->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { /* * HSI2C controller internal clk rate should be 19.2 Mhz for @@ -403,14 +403,14 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) * to get longer filter period for better noise suppression. * The filter is iclk (fclk for HS) period. */ - if (dev->speed > 400 || - dev->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) + if (omap->speed > 400 || + omap->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) internal_clk = 19200; - else if (dev->speed > 100) + else if (omap->speed > 100) internal_clk = 9600; else internal_clk = 4000; - fclk = clk_get(dev->dev, "fck"); + fclk = clk_get(omap->dev, "fck"); fclk_rate = clk_get_rate(fclk) / 1000; clk_put(fclk); @@ -419,7 +419,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) psc = psc - 1; /* If configured for High Speed */ - if (dev->speed > 400) { + if (omap->speed > 400) { unsigned long scl; /* For first phase of HS mode */ @@ -428,20 +428,20 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) fssclh = (scl / 3) - 5; /* For second phase of HS mode */ - scl = fclk_rate / dev->speed; + scl = fclk_rate / omap->speed; hsscll = scl - (scl / 3) - 7; hssclh = (scl / 3) - 5; - } else if (dev->speed > 100) { + } else if (omap->speed > 100) { unsigned long scl; /* Fast mode */ - scl = internal_clk / dev->speed; + scl = internal_clk / omap->speed; fsscll = scl - (scl / 3) - 7; fssclh = (scl / 3) - 5; } else { /* Standard mode */ - fsscll = internal_clk / (dev->speed * 2) - 7; - fssclh = internal_clk / (dev->speed * 2) - 5; + fsscll = internal_clk / (omap->speed * 2) - 7; + fssclh = internal_clk / (omap->speed * 2) - 5; } scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll; sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh; @@ -450,25 +450,25 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) fclk_rate /= (psc + 1) * 1000; if (psc > 2) psc = 2; - scll = fclk_rate / (dev->speed * 2) - 7 + psc; - sclh = fclk_rate / (dev->speed * 2) - 7 + psc; + scll = fclk_rate / (omap->speed * 2) - 7 + psc; + sclh = fclk_rate / (omap->speed * 2) - 7 + psc; } - dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | + omap->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY | OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK | - OMAP_I2C_IE_AL) | ((dev->fifo_size) ? + OMAP_I2C_IE_AL) | ((omap->fifo_size) ? (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0); - dev->pscstate = psc; - dev->scllstate = scll; - dev->sclhstate = sclh; + omap->pscstate = psc; + omap->scllstate = scll; + omap->sclhstate = sclh; - if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) { + if (omap->rev <= OMAP_I2C_REV_ON_3430_3530) { /* Not implemented */ - dev->bb_valid = 1; + omap->bb_valid = 1; } - __omap_i2c_init(dev); + __omap_i2c_init(omap); return 0; } @@ -476,14 +476,14 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) /* * Waiting on Bus Busy */ -static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) +static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap) { unsigned long timeout; timeout = jiffies + OMAP_I2C_TIMEOUT; - while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) { + while (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) { if (time_after(jiffies, timeout)) - return i2c_recover_bus(&dev->adapter); + return i2c_recover_bus(&omap->adapter); msleep(1); } @@ -518,19 +518,19 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev) * 3. Any transfer started in the middle of another master's transfer * results in unpredictable results and data corruption */ -static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *dev) +static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *omap) { unsigned long bus_free_timeout = 0; unsigned long timeout; int bus_free = 0; u16 stat, systest; - if (dev->bb_valid) + if (omap->bb_valid) return 0; timeout = jiffies + OMAP_I2C_TIMEOUT; while (1) { - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); /* * We will see BB or BF event in a case IP had detected any * activity on the I2C bus. Now IP correctly tracks the bus @@ -543,7 +543,7 @@ static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *dev) * Otherwise, we must look signals on the bus to make * the right decision. */ - systest = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG); + systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG); if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) && (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC)) { if (!bus_free) { @@ -564,22 +564,22 @@ static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *dev) } if (time_after(jiffies, timeout)) { - dev_warn(dev->dev, "timeout waiting for bus ready\n"); + dev_warn(omap->dev, "timeout waiting for bus ready\n"); return -ETIMEDOUT; } msleep(1); } - dev->bb_valid = 1; + omap->bb_valid = 1; return 0; } -static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) +static void omap_i2c_resize_fifo(struct omap_i2c_dev *omap, u8 size, bool is_rx) { u16 buf; - if (dev->flags & OMAP_I2C_FLAG_NO_FIFO) + if (omap->flags & OMAP_I2C_FLAG_NO_FIFO) return; /* @@ -589,29 +589,29 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) * then we might use draining feature to transfer the remaining bytes. */ - dev->threshold = clamp(size, (u8) 1, dev->fifo_size); + omap->threshold = clamp(size, (u8) 1, omap->fifo_size); - buf = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); + buf = omap_i2c_read_reg(omap, OMAP_I2C_BUF_REG); if (is_rx) { /* Clear RX Threshold */ buf &= ~(0x3f << 8); - buf |= ((dev->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR; + buf |= ((omap->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR; } else { /* Clear TX Threshold */ buf &= ~0x3f; - buf |= (dev->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR; + buf |= (omap->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR; } - omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); + omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, buf); - if (dev->rev < OMAP_I2C_REV_ON_3630) - dev->b_hw = 1; /* Enable hardware fixes */ + if (omap->rev < OMAP_I2C_REV_ON_3630) + omap->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - if (dev->set_mpu_wkup_lat != NULL) - dev->latency = (1000000 * dev->threshold) / - (1000 * dev->speed / 8); + if (omap->set_mpu_wkup_lat != NULL) + omap->latency = (1000000 * omap->threshold) / + (1000 * omap->speed / 8); } /* @@ -620,42 +620,42 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) static int omap_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) { - struct omap_i2c_dev *dev = i2c_get_adapdata(adap); + struct omap_i2c_dev *omap = i2c_get_adapdata(adap); unsigned long timeout; u16 w; - dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", + dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", msg->addr, msg->len, msg->flags, stop); if (msg->len == 0) return -EINVAL; - dev->receiver = !!(msg->flags & I2C_M_RD); - omap_i2c_resize_fifo(dev, msg->len, dev->receiver); + omap->receiver = !!(msg->flags & I2C_M_RD); + omap_i2c_resize_fifo(omap, msg->len, omap->receiver); - omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr); + omap_i2c_write_reg(omap, OMAP_I2C_SA_REG, msg->addr); /* REVISIT: Could the STB bit of I2C_CON be used with probing? */ - dev->buf = msg->buf; - dev->buf_len = msg->len; + omap->buf = msg->buf; + omap->buf_len = msg->len; - /* make sure writes to dev->buf_len are ordered */ + /* make sure writes to omap->buf_len are ordered */ barrier(); - omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len); + omap_i2c_write_reg(omap, OMAP_I2C_CNT_REG, omap->buf_len); /* Clear the FIFO Buffers */ - w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); + w = omap_i2c_read_reg(omap, OMAP_I2C_BUF_REG); w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR; - omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w); + omap_i2c_write_reg(omap, OMAP_I2C_BUF_REG, w); - reinit_completion(&dev->cmd_complete); - dev->cmd_err = 0; + reinit_completion(&omap->cmd_complete); + omap->cmd_err = 0; w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; /* High speed configuration */ - if (dev->speed > 400) + if (omap->speed > 400) w |= OMAP_I2C_CON_OPMODE_HS; if (msg->flags & I2C_M_STOP) @@ -665,27 +665,27 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, if (!(msg->flags & I2C_M_RD)) w |= OMAP_I2C_CON_TRX; - if (!dev->b_hw && stop) + if (!omap->b_hw && stop) w |= OMAP_I2C_CON_STP; /* * NOTE: STAT_BB bit could became 1 here if another master occupy * the bus. IP successfully complete transfer when the bus will be * free again (BB reset to 0). */ - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w); /* * Don't write stt and stp together on some hardware. */ - if (dev->b_hw && stop) { + if (omap->b_hw && stop) { unsigned long delay = jiffies + OMAP_I2C_TIMEOUT; - u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); + u16 con = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG); while (con & OMAP_I2C_CON_STT) { - con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); + con = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG); /* Let the user know if i2c is in a bad state */ if (time_after(jiffies, delay)) { - dev_err(dev->dev, "controller timed out " + dev_err(omap->dev, "controller timed out " "waiting for start condition to finish\n"); return -ETIMEDOUT; } @@ -694,42 +694,42 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, w |= OMAP_I2C_CON_STP; w &= ~OMAP_I2C_CON_STT; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w); } /* * REVISIT: We should abort the transfer on signals, but the bus goes * into arbitration and we're currently unable to recover from it. */ - timeout = wait_for_completion_timeout(&dev->cmd_complete, + timeout = wait_for_completion_timeout(&omap->cmd_complete, OMAP_I2C_TIMEOUT); if (timeout == 0) { - dev_err(dev->dev, "controller timed out\n"); - omap_i2c_reset(dev); - __omap_i2c_init(dev); + dev_err(omap->dev, "controller timed out\n"); + omap_i2c_reset(omap); + __omap_i2c_init(omap); return -ETIMEDOUT; } - if (likely(!dev->cmd_err)) + if (likely(!omap->cmd_err)) return 0; /* We have an error */ - if (dev->cmd_err & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF)) { - omap_i2c_reset(dev); - __omap_i2c_init(dev); + if (omap->cmd_err & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_XUDF)) { + omap_i2c_reset(omap); + __omap_i2c_init(omap); return -EIO; } - if (dev->cmd_err & OMAP_I2C_STAT_AL) + if (omap->cmd_err & OMAP_I2C_STAT_AL) return -EAGAIN; - if (dev->cmd_err & OMAP_I2C_STAT_NACK) { + if (omap->cmd_err & OMAP_I2C_STAT_NACK) { if (msg->flags & I2C_M_IGNORE_NAK) return 0; - w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG); + w = omap_i2c_read_reg(omap, OMAP_I2C_CON_REG); w |= OMAP_I2C_CON_STP; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, w); return -EREMOTEIO; } return -EIO; @@ -743,24 +743,24 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, static int omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { - struct omap_i2c_dev *dev = i2c_get_adapdata(adap); + struct omap_i2c_dev *omap = i2c_get_adapdata(adap); int i; int r; - r = pm_runtime_get_sync(dev->dev); + r = pm_runtime_get_sync(omap->dev); if (r < 0) goto out; - r = omap_i2c_wait_for_bb_valid(dev); + r = omap_i2c_wait_for_bb_valid(omap); if (r < 0) goto out; - r = omap_i2c_wait_for_bb(dev); + r = omap_i2c_wait_for_bb(omap); if (r < 0) goto out; - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, dev->latency); + if (omap->set_mpu_wkup_lat != NULL) + omap->set_mpu_wkup_lat(omap->dev, omap->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); @@ -771,14 +771,14 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r == 0) r = num; - omap_i2c_wait_for_bb(dev); + omap_i2c_wait_for_bb(omap); - if (dev->set_mpu_wkup_lat != NULL) - dev->set_mpu_wkup_lat(dev->dev, -1); + if (omap->set_mpu_wkup_lat != NULL) + omap->set_mpu_wkup_lat(omap->dev, -1); out: - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); + pm_runtime_mark_last_busy(omap->dev); + pm_runtime_put_autosuspend(omap->dev); return r; } @@ -790,19 +790,19 @@ omap_i2c_func(struct i2c_adapter *adap) } static inline void -omap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err) +omap_i2c_complete_cmd(struct omap_i2c_dev *omap, u16 err) { - dev->cmd_err |= err; - complete(&dev->cmd_complete); + omap->cmd_err |= err; + complete(&omap->cmd_complete); } static inline void -omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat) +omap_i2c_ack_stat(struct omap_i2c_dev *omap, u16 stat) { - omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat); + omap_i2c_write_reg(omap, OMAP_I2C_STAT_REG, stat); } -static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat) +static inline void i2c_omap_errata_i207(struct omap_i2c_dev *omap, u16 stat) { /* * I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8) @@ -813,17 +813,17 @@ static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat) */ if (stat & OMAP_I2C_STAT_RDR) { /* Step 1: If RDR is set, clear it */ - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR); /* Step 2: */ - if (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) + if (!(omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB)) { /* Step 3: */ - if (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) + if (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_RDR) { - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); - dev_dbg(dev->dev, "RDR when bus is busy.\n"); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR); + dev_dbg(omap->dev, "RDR when bus is busy.\n"); } } @@ -836,50 +836,50 @@ static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat) static irqreturn_t omap_i2c_omap1_isr(int this_irq, void *dev_id) { - struct omap_i2c_dev *dev = dev_id; + struct omap_i2c_dev *omap = dev_id; u16 iv, w; - if (pm_runtime_suspended(dev->dev)) + if (pm_runtime_suspended(omap->dev)) return IRQ_NONE; - iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); + iv = omap_i2c_read_reg(omap, OMAP_I2C_IV_REG); switch (iv) { case 0x00: /* None */ break; case 0x01: /* Arbitration lost */ - dev_err(dev->dev, "Arbitration lost\n"); - omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL); + dev_err(omap->dev, "Arbitration lost\n"); + omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_AL); break; case 0x02: /* No acknowledgement */ - omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK); - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP); + omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_NACK); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP); break; case 0x03: /* Register access ready */ - omap_i2c_complete_cmd(dev, 0); + omap_i2c_complete_cmd(omap, 0); break; case 0x04: /* Receive data ready */ - if (dev->buf_len) { - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - *dev->buf++ = w; - dev->buf_len--; - if (dev->buf_len) { - *dev->buf++ = w >> 8; - dev->buf_len--; + if (omap->buf_len) { + w = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG); + *omap->buf++ = w; + omap->buf_len--; + if (omap->buf_len) { + *omap->buf++ = w >> 8; + omap->buf_len--; } } else - dev_err(dev->dev, "RRDY IRQ while no data requested\n"); + dev_err(omap->dev, "RRDY IRQ while no data requested\n"); break; case 0x05: /* Transmit data ready */ - if (dev->buf_len) { - w = *dev->buf++; - dev->buf_len--; - if (dev->buf_len) { - w |= *dev->buf++ << 8; - dev->buf_len--; + if (omap->buf_len) { + w = *omap->buf++; + omap->buf_len--; + if (omap->buf_len) { + w |= *omap->buf++ << 8; + omap->buf_len--; } - omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); + omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, w); } else - dev_err(dev->dev, "XRDY IRQ while no data to send\n"); + dev_err(omap->dev, "XRDY IRQ while no data to send\n"); break; default: return IRQ_NONE; @@ -896,28 +896,28 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id) * data to DATA_REG. Otherwise some data bytes can be lost while transferring * them from the memory to the I2C interface. */ -static int errata_omap3_i462(struct omap_i2c_dev *dev) +static int errata_omap3_i462(struct omap_i2c_dev *omap) { unsigned long timeout = 10000; u16 stat; do { - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); if (stat & OMAP_I2C_STAT_XUDF) break; if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY | + omap_i2c_ack_stat(omap, (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); if (stat & OMAP_I2C_STAT_NACK) { - dev->cmd_err |= OMAP_I2C_STAT_NACK; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + omap->cmd_err |= OMAP_I2C_STAT_NACK; + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK); } if (stat & OMAP_I2C_STAT_AL) { - dev_err(dev->dev, "Arbitration lost\n"); - dev->cmd_err |= OMAP_I2C_STAT_AL; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); + dev_err(omap->dev, "Arbitration lost\n"); + omap->cmd_err |= OMAP_I2C_STAT_AL; + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AL); } return -EIO; @@ -927,61 +927,61 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev) } while (--timeout); if (!timeout) { - dev_err(dev->dev, "timeout waiting on XUDF bit\n"); + dev_err(omap->dev, "timeout waiting on XUDF bit\n"); return 0; } return 0; } -static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, +static void omap_i2c_receive_data(struct omap_i2c_dev *omap, u8 num_bytes, bool is_rdr) { u16 w; while (num_bytes--) { - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); - *dev->buf++ = w; - dev->buf_len--; + w = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG); + *omap->buf++ = w; + omap->buf_len--; /* * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ - if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { - *dev->buf++ = w >> 8; - dev->buf_len--; + if (omap->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + *omap->buf++ = w >> 8; + omap->buf_len--; } } } -static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, +static int omap_i2c_transmit_data(struct omap_i2c_dev *omap, u8 num_bytes, bool is_xdr) { u16 w; while (num_bytes--) { - w = *dev->buf++; - dev->buf_len--; + w = *omap->buf++; + omap->buf_len--; /* * Data reg in 2430, omap3 and * omap4 is 8 bit wide */ - if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { - w |= *dev->buf++ << 8; - dev->buf_len--; + if (omap->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { + w |= *omap->buf++ << 8; + omap->buf_len--; } - if (dev->errata & I2C_OMAP_ERRATA_I462) { + if (omap->errata & I2C_OMAP_ERRATA_I462) { int ret; - ret = errata_omap3_i462(dev); + ret = errata_omap3_i462(omap); if (ret < 0) return ret; } - omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); + omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, w); } return 0; @@ -990,19 +990,19 @@ static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, static irqreturn_t omap_i2c_isr(int irq, void *dev_id) { - struct omap_i2c_dev *dev = dev_id; + struct omap_i2c_dev *omap = dev_id; irqreturn_t ret = IRQ_HANDLED; u16 mask; u16 stat; - spin_lock(&dev->lock); - mask = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + spin_lock(&omap->lock); + mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); + stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); if (stat & mask) ret = IRQ_WAKE_THREAD; - spin_unlock(&dev->lock); + spin_unlock(&omap->lock); return ret; } @@ -1010,20 +1010,20 @@ omap_i2c_isr(int irq, void *dev_id) static irqreturn_t omap_i2c_isr_thread(int this_irq, void *dev_id) { - struct omap_i2c_dev *dev = dev_id; + struct omap_i2c_dev *omap = dev_id; unsigned long flags; u16 bits; u16 stat; int err = 0, count = 0; - spin_lock_irqsave(&dev->lock, flags); + spin_lock_irqsave(&omap->lock, flags); do { - bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); - stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + bits = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); + stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); stat &= bits; /* If we're in receiver mode, ignore XDR/XRDY */ - if (dev->receiver) + if (omap->receiver) stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY); else stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY); @@ -1033,32 +1033,32 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) goto out; } - dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat); + dev_dbg(omap->dev, "IRQ (ISR = 0x%04x)\n", stat); if (count++ == 100) { - dev_warn(dev->dev, "Too much work in one IRQ\n"); + dev_warn(omap->dev, "Too much work in one IRQ\n"); break; } if (stat & OMAP_I2C_STAT_NACK) { err |= OMAP_I2C_STAT_NACK; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK); } if (stat & OMAP_I2C_STAT_AL) { - dev_err(dev->dev, "Arbitration lost\n"); + dev_err(omap->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_AL); } /* * ProDB0017052: Clear ARDY bit twice */ if (stat & OMAP_I2C_STAT_ARDY) - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ARDY); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_ARDY); if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { - omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | + omap_i2c_ack_stat(omap, (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | @@ -1069,28 +1069,28 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) if (stat & OMAP_I2C_STAT_RDR) { u8 num_bytes = 1; - if (dev->fifo_size) - num_bytes = dev->buf_len; + if (omap->fifo_size) + num_bytes = omap->buf_len; - if (dev->errata & I2C_OMAP_ERRATA_I207) { - i2c_omap_errata_i207(dev, stat); - num_bytes = (omap_i2c_read_reg(dev, + if (omap->errata & I2C_OMAP_ERRATA_I207) { + i2c_omap_errata_i207(omap, stat); + num_bytes = (omap_i2c_read_reg(omap, OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; } - omap_i2c_receive_data(dev, num_bytes, true); - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); + omap_i2c_receive_data(omap, num_bytes, true); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RDR); continue; } if (stat & OMAP_I2C_STAT_RRDY) { u8 num_bytes = 1; - if (dev->threshold) - num_bytes = dev->threshold; + if (omap->threshold) + num_bytes = omap->threshold; - omap_i2c_receive_data(dev, num_bytes, false); - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY); + omap_i2c_receive_data(omap, num_bytes, false); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_RRDY); continue; } @@ -1098,14 +1098,14 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) u8 num_bytes = 1; int ret; - if (dev->fifo_size) - num_bytes = dev->buf_len; + if (omap->fifo_size) + num_bytes = omap->buf_len; - ret = omap_i2c_transmit_data(dev, num_bytes, true); + ret = omap_i2c_transmit_data(omap, num_bytes, true); if (ret < 0) break; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XDR); continue; } @@ -1113,36 +1113,36 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) u8 num_bytes = 1; int ret; - if (dev->threshold) - num_bytes = dev->threshold; + if (omap->threshold) + num_bytes = omap->threshold; - ret = omap_i2c_transmit_data(dev, num_bytes, false); + ret = omap_i2c_transmit_data(omap, num_bytes, false); if (ret < 0) break; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XRDY); continue; } if (stat & OMAP_I2C_STAT_ROVR) { - dev_err(dev->dev, "Receive overrun\n"); + dev_err(omap->dev, "Receive overrun\n"); err |= OMAP_I2C_STAT_ROVR; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_ROVR); break; } if (stat & OMAP_I2C_STAT_XUDF) { - dev_err(dev->dev, "Transmit underflow\n"); + dev_err(omap->dev, "Transmit underflow\n"); err |= OMAP_I2C_STAT_XUDF; - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); + omap_i2c_ack_stat(omap, OMAP_I2C_STAT_XUDF); break; } } while (stat); - omap_i2c_complete_cmd(dev, err); + omap_i2c_complete_cmd(omap, err); out: - spin_unlock_irqrestore(&dev->lock, flags); + spin_unlock_irqrestore(&omap->lock, flags); return IRQ_HANDLED; } @@ -1284,7 +1284,7 @@ static struct i2c_bus_recovery_info omap_i2c_bus_recovery_info = { static int omap_i2c_probe(struct platform_device *pdev) { - struct omap_i2c_dev *dev; + struct omap_i2c_dev *omap; struct i2c_adapter *adap; struct resource *mem; const struct omap_i2c_bus_platform_data *pdata = @@ -1302,47 +1302,47 @@ omap_i2c_probe(struct platform_device *pdev) return irq; } - dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); - if (!dev) + omap = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); + if (!omap) return -ENOMEM; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->base = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(dev->base)) - return PTR_ERR(dev->base); + omap->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(omap->base)) + return PTR_ERR(omap->base); match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); if (match) { u32 freq = 100000; /* default to 100000 Hz */ pdata = match->data; - dev->flags = pdata->flags; + omap->flags = pdata->flags; of_property_read_u32(node, "clock-frequency", &freq); /* convert DT freq value in Hz into kHz for speed */ - dev->speed = freq / 1000; + omap->speed = freq / 1000; } else if (pdata != NULL) { - dev->speed = pdata->clkrate; - dev->flags = pdata->flags; - dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; + omap->speed = pdata->clkrate; + omap->flags = pdata->flags; + omap->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; } - dev->dev = &pdev->dev; - dev->irq = irq; + omap->dev = &pdev->dev; + omap->irq = irq; - spin_lock_init(&dev->lock); + spin_lock_init(&omap->lock); - platform_set_drvdata(pdev, dev); - init_completion(&dev->cmd_complete); + platform_set_drvdata(pdev, omap); + init_completion(&omap->cmd_complete); - dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; + omap->reg_shift = (omap->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; - pm_runtime_enable(dev->dev); - pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT); - pm_runtime_use_autosuspend(dev->dev); + pm_runtime_enable(omap->dev); + pm_runtime_set_autosuspend_delay(omap->dev, OMAP_I2C_PM_TIMEOUT); + pm_runtime_use_autosuspend(omap->dev); - r = pm_runtime_get_sync(dev->dev); - if (r < 0) + r = pm_runtime_get_sync(omap->dev); + if (IS_ERR_VALUE(r)) goto err_free_mem; /* @@ -1351,42 +1351,42 @@ omap_i2c_probe(struct platform_device *pdev) * Also since the omap_i2c_read_reg uses reg_map_ip_* a * readw_relaxed is done. */ - rev = readw_relaxed(dev->base + 0x04); + rev = readw_relaxed(omap->base + 0x04); - dev->scheme = OMAP_I2C_SCHEME(rev); - switch (dev->scheme) { + omap->scheme = OMAP_I2C_SCHEME(rev); + switch (omap->scheme) { case OMAP_I2C_SCHEME_0: - dev->regs = (u8 *)reg_map_ip_v1; - dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG); - minor = OMAP_I2C_REV_SCHEME_0_MAJOR(dev->rev); - major = OMAP_I2C_REV_SCHEME_0_MAJOR(dev->rev); + omap->regs = (u8 *)reg_map_ip_v1; + omap->rev = omap_i2c_read_reg(omap, OMAP_I2C_REV_REG); + minor = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev); + major = OMAP_I2C_REV_SCHEME_0_MAJOR(omap->rev); break; case OMAP_I2C_SCHEME_1: /* FALLTHROUGH */ default: - dev->regs = (u8 *)reg_map_ip_v2; + omap->regs = (u8 *)reg_map_ip_v2; rev = (rev << 16) | - omap_i2c_read_reg(dev, OMAP_I2C_IP_V2_REVNB_LO); + omap_i2c_read_reg(omap, OMAP_I2C_IP_V2_REVNB_LO); minor = OMAP_I2C_REV_SCHEME_1_MINOR(rev); major = OMAP_I2C_REV_SCHEME_1_MAJOR(rev); - dev->rev = rev; + omap->rev = rev; } - dev->errata = 0; + omap->errata = 0; - if (dev->rev >= OMAP_I2C_REV_ON_2430 && - dev->rev < OMAP_I2C_REV_ON_4430_PLUS) - dev->errata |= I2C_OMAP_ERRATA_I207; + if (omap->rev >= OMAP_I2C_REV_ON_2430 && + omap->rev < OMAP_I2C_REV_ON_4430_PLUS) + omap->errata |= I2C_OMAP_ERRATA_I207; - if (dev->rev <= OMAP_I2C_REV_ON_3430_3530) - dev->errata |= I2C_OMAP_ERRATA_I462; + if (omap->rev <= OMAP_I2C_REV_ON_3430_3530) + omap->errata |= I2C_OMAP_ERRATA_I462; - if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) { + if (!(omap->flags & OMAP_I2C_FLAG_NO_FIFO)) { u16 s; /* Set up the fifo size - Get total size */ - s = (omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3; - dev->fifo_size = 0x8 << s; + s = (omap_i2c_read_reg(omap, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3; + omap->fifo_size = 0x8 << s; /* * Set up notification threshold as half the total available @@ -1394,36 +1394,36 @@ omap_i2c_probe(struct platform_device *pdev) * call back latencies. */ - dev->fifo_size = (dev->fifo_size / 2); + omap->fifo_size = (omap->fifo_size / 2); - if (dev->rev < OMAP_I2C_REV_ON_3630) - dev->b_hw = 1; /* Enable hardware fixes */ + if (omap->rev < OMAP_I2C_REV_ON_3630) + omap->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - if (dev->set_mpu_wkup_lat != NULL) - dev->latency = (1000000 * dev->fifo_size) / - (1000 * dev->speed / 8); + if (omap->set_mpu_wkup_lat != NULL) + omap->latency = (1000000 * omap->fifo_size) / + (1000 * omap->speed / 8); } /* reset ASAP, clearing any IRQs */ - omap_i2c_init(dev); + omap_i2c_init(omap); - if (dev->rev < OMAP_I2C_OMAP1_REV_2) - r = devm_request_irq(&pdev->dev, dev->irq, omap_i2c_omap1_isr, - IRQF_NO_SUSPEND, pdev->name, dev); + if (omap->rev < OMAP_I2C_OMAP1_REV_2) + r = devm_request_irq(&pdev->dev, omap->irq, omap_i2c_omap1_isr, + IRQF_NO_SUSPEND, pdev->name, omap); else - r = devm_request_threaded_irq(&pdev->dev, dev->irq, + r = devm_request_threaded_irq(&pdev->dev, omap->irq, omap_i2c_isr, omap_i2c_isr_thread, IRQF_NO_SUSPEND | IRQF_ONESHOT, - pdev->name, dev); + pdev->name, omap); if (r) { - dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); + dev_err(omap->dev, "failure requesting irq %i\n", omap->irq); goto err_unuse_clocks; } - adap = &dev->adapter; - i2c_set_adapdata(adap, dev); + adap = &omap->adapter; + i2c_set_adapdata(adap, omap); adap->owner = THIS_MODULE; adap->class = I2C_CLASS_DEPRECATED; strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); @@ -1436,21 +1436,21 @@ omap_i2c_probe(struct platform_device *pdev) adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); if (r) { - dev_err(dev->dev, "failure adding adapter\n"); + dev_err(omap->dev, "failure adding adapter\n"); goto err_unuse_clocks; } - dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr, - major, minor, dev->speed); + dev_info(omap->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr, + major, minor, omap->speed); - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); + pm_runtime_mark_last_busy(omap->dev); + pm_runtime_put_autosuspend(omap->dev); return 0; err_unuse_clocks: - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); - pm_runtime_put(dev->dev); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); + pm_runtime_put(omap->dev); pm_runtime_disable(&pdev->dev); err_free_mem: @@ -1459,15 +1459,15 @@ err_free_mem: static int omap_i2c_remove(struct platform_device *pdev) { - struct omap_i2c_dev *dev = platform_get_drvdata(pdev); + struct omap_i2c_dev *omap = platform_get_drvdata(pdev); int ret; - i2c_del_adapter(&dev->adapter); + i2c_del_adapter(&omap->adapter); ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) return ret; - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; @@ -1476,23 +1476,23 @@ static int omap_i2c_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int omap_i2c_runtime_suspend(struct device *dev) { - struct omap_i2c_dev *_dev = dev_get_drvdata(dev); + struct omap_i2c_dev *omap = dev_get_drvdata(dev); - _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); + omap->iestate = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); - if (_dev->scheme == OMAP_I2C_SCHEME_0) - omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); + if (omap->scheme == OMAP_I2C_SCHEME_0) + omap_i2c_write_reg(omap, OMAP_I2C_IE_REG, 0); else - omap_i2c_write_reg(_dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, + omap_i2c_write_reg(omap, OMAP_I2C_IP_V2_IRQENABLE_CLR, OMAP_I2C_IP_V2_INTERRUPTS_MASK); - if (_dev->rev < OMAP_I2C_OMAP1_REV_2) { - omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */ + if (omap->rev < OMAP_I2C_OMAP1_REV_2) { + omap_i2c_read_reg(omap, OMAP_I2C_IV_REG); /* Read clears */ } else { - omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate); + omap_i2c_write_reg(omap, OMAP_I2C_STAT_REG, omap->iestate); /* Flush posted write */ - omap_i2c_read_reg(_dev, OMAP_I2C_STAT_REG); + omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); } pinctrl_pm_select_sleep_state(dev); @@ -1502,14 +1502,14 @@ static int omap_i2c_runtime_suspend(struct device *dev) static int omap_i2c_runtime_resume(struct device *dev) { - struct omap_i2c_dev *_dev = dev_get_drvdata(dev); + struct omap_i2c_dev *omap = dev_get_drvdata(dev); pinctrl_pm_select_default_state(dev); - if (!_dev->regs) + if (!omap->regs) return 0; - __omap_i2c_init(_dev); + __omap_i2c_init(omap); return 0; } -- cgit v1.3-6-gb490 From 1c4828f916ffd5b7cc4d57d832cce615475b36da Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 13 Jul 2015 15:38:04 -0500 Subject: i2c: omap: on ->remove() call pm_runtime_put_sync() we're about to remove the module, so we can't really schedule a PM transition in the future, we must wait for it to finish. Signed-off-by: Felipe Balbi Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index e359ad39753b..afc3bfca0b6c 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1468,7 +1468,7 @@ static int omap_i2c_remove(struct platform_device *pdev) return ret; omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); - pm_runtime_put(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; } -- cgit v1.3-6-gb490 From e1069878b957c5f6d0eb2f441a8372db8d6198b2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 11 Jul 2015 09:46:22 +0200 Subject: clk: shmobile: emev2: deassert reset for IIC0/1 We have a driver now for IIC, so disable reset for them. Signed-off-by: Wolfram Sang Acked-by: Stephen Boyd Signed-off-by: Wolfram Sang --- drivers/clk/shmobile/clk-emev2.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/shmobile/clk-emev2.c b/drivers/clk/shmobile/clk-emev2.c index 5b60beb7d0eb..a91825471c79 100644 --- a/drivers/clk/shmobile/clk-emev2.c +++ b/drivers/clk/shmobile/clk-emev2.c @@ -28,6 +28,8 @@ #define USIBU1_RSTCTRL 0x0ac #define USIBU2_RSTCTRL 0x0b0 #define USIBU3_RSTCTRL 0x0b4 +#define IIC0_RSTCTRL 0x0dc +#define IIC1_RSTCTRL 0x0e0 #define STI_RSTCTRL 0x124 #define STI_CLKSEL 0x688 @@ -66,6 +68,10 @@ static void __init emev2_smu_init(void) emev2_smu_write(2, USIBU1_RSTCTRL); emev2_smu_write(2, USIBU2_RSTCTRL); emev2_smu_write(2, USIBU3_RSTCTRL); + + /* deassert reset for IIC0->IIC1 */ + emev2_smu_write(1, IIC0_RSTCTRL); + emev2_smu_write(1, IIC1_RSTCTRL); } static void __init emev2_smu_clkdiv_init(struct device_node *np) -- cgit v1.3-6-gb490 From 5faf6e1f58b4488a8b24a722ccf317ed67a8e8d8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 11 Jul 2015 09:46:23 +0200 Subject: i2c: emev2: add driver Add a basic driver for the Renesas EMEV2 SoC. Based on the driver from the BSP which was first worked on by Ian, and made ready for upstream by me. Signed-off-by: Ian Molton Reviewed-by: Laurent Pinchart Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-emev2.txt | 22 ++ drivers/i2c/busses/Kconfig | 7 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-emev2.c | 332 +++++++++++++++++++++ 4 files changed, 362 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-emev2.txt create mode 100644 drivers/i2c/busses/i2c-emev2.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/i2c/i2c-emev2.txt b/Documentation/devicetree/bindings/i2c/i2c-emev2.txt new file mode 100644 index 000000000000..5ed1ea1c7e14 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-emev2.txt @@ -0,0 +1,22 @@ +Device tree configuration for Renesas EMEV2 IIC controller + +Required properties: +- compatible : "renesas,iic-emev2" +- reg : address start and address range size of device +- interrupts : specifier for the IIC controller interrupt +- clocks : phandle to the IP core SCLK +- clock-names : must be "sclk" +- #address-cells : should be <1> +- #size-cells : should be <0> + +Example: + + iic0: i2c@e0070000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-emev2"; + reg = <0xe0070000 0x28>; + interrupts = <0 32 IRQ_TYPE_EDGE_RISING>; + clocks = <&iic0_sclk>; + clock-names = "sclk"; + }; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 577d58d1f1a1..0b798ae708fe 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -526,6 +526,13 @@ config I2C_EG20T ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. +config I2C_EMEV2 + tristate "EMMA Mobile series I2C adapter" + depends on HAVE_CLK + help + If you say yes to this option, support will be included for the + I2C interface on the Renesas Electronics EM/EV family of processors. + config I2C_EXYNOS5 tristate "Exynos5 high-speed I2C driver" depends on ARCH_EXYNOS && OF diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index e5f537c80da0..50e8bbb65f1c 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -48,6 +48,7 @@ i2c-designware-pci-objs := i2c-designware-pcidrv.o obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o +obj-$(CONFIG_I2C_EMEV2) += i2c-emev2.o obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c new file mode 100644 index 000000000000..192ef6b50c79 --- /dev/null +++ b/drivers/i2c/busses/i2c-emev2.c @@ -0,0 +1,332 @@ +/* + * I2C driver for the Renesas EMEV2 SoC + * + * Copyright (C) 2015 Wolfram Sang + * Copyright 2013 Codethink Ltd. + * Copyright 2010-2015 Renesas Electronics 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 published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* I2C Registers */ +#define I2C_OFS_IICACT0 0x00 /* start */ +#define I2C_OFS_IIC0 0x04 /* shift */ +#define I2C_OFS_IICC0 0x08 /* control */ +#define I2C_OFS_SVA0 0x0c /* slave address */ +#define I2C_OFS_IICCL0 0x10 /* clock select */ +#define I2C_OFS_IICX0 0x14 /* extension */ +#define I2C_OFS_IICS0 0x18 /* status */ +#define I2C_OFS_IICSE0 0x1c /* status For emulation */ +#define I2C_OFS_IICF0 0x20 /* IIC flag */ + +/* I2C IICACT0 Masks */ +#define I2C_BIT_IICE0 0x0001 + +/* I2C IICC0 Masks */ +#define I2C_BIT_LREL0 0x0040 +#define I2C_BIT_WREL0 0x0020 +#define I2C_BIT_SPIE0 0x0010 +#define I2C_BIT_WTIM0 0x0008 +#define I2C_BIT_ACKE0 0x0004 +#define I2C_BIT_STT0 0x0002 +#define I2C_BIT_SPT0 0x0001 + +/* I2C IICCL0 Masks */ +#define I2C_BIT_SMC0 0x0008 +#define I2C_BIT_DFC0 0x0004 + +/* I2C IICSE0 Masks */ +#define I2C_BIT_MSTS0 0x0080 +#define I2C_BIT_ALD0 0x0040 +#define I2C_BIT_EXC0 0x0020 +#define I2C_BIT_COI0 0x0010 +#define I2C_BIT_TRC0 0x0008 +#define I2C_BIT_ACKD0 0x0004 +#define I2C_BIT_STD0 0x0002 +#define I2C_BIT_SPD0 0x0001 + +/* I2C IICF0 Masks */ +#define I2C_BIT_STCF 0x0080 +#define I2C_BIT_IICBSY 0x0040 +#define I2C_BIT_STCEN 0x0002 +#define I2C_BIT_IICRSV 0x0001 + +struct em_i2c_device { + void __iomem *base; + struct i2c_adapter adap; + struct completion msg_done; + struct clk *sclk; +}; + +static inline void em_clear_set_bit(struct em_i2c_device *priv, u8 clear, u8 set, u8 reg) +{ + writeb((readb(priv->base + reg) & ~clear) | set, priv->base + reg); +} + +static int em_i2c_wait_for_event(struct em_i2c_device *priv) +{ + unsigned long time_left; + int status; + + reinit_completion(&priv->msg_done); + + time_left = wait_for_completion_timeout(&priv->msg_done, priv->adap.timeout); + + if (!time_left) + return -ETIMEDOUT; + + status = readb(priv->base + I2C_OFS_IICSE0); + return status & I2C_BIT_ALD0 ? -EAGAIN : status; +} + +static void em_i2c_stop(struct em_i2c_device *priv) +{ + /* Send Stop condition */ + em_clear_set_bit(priv, 0, I2C_BIT_SPT0 | I2C_BIT_SPIE0, I2C_OFS_IICC0); + + /* Wait for stop condition */ + em_i2c_wait_for_event(priv); +} + +static void em_i2c_reset(struct i2c_adapter *adap) +{ + struct em_i2c_device *priv = i2c_get_adapdata(adap); + int retr; + + /* If I2C active */ + if (readb(priv->base + I2C_OFS_IICACT0) & I2C_BIT_IICE0) { + /* Disable I2C operation */ + writeb(0, priv->base + I2C_OFS_IICACT0); + + retr = 1000; + while (readb(priv->base + I2C_OFS_IICACT0) == 1 && retr) + retr--; + WARN_ON(retr == 0); + } + + /* Transfer mode set */ + writeb(I2C_BIT_DFC0, priv->base + I2C_OFS_IICCL0); + + /* Can Issue start without detecting a stop, Reservation disabled. */ + writeb(I2C_BIT_STCEN | I2C_BIT_IICRSV, priv->base + I2C_OFS_IICF0); + + /* I2C enable, 9 bit interrupt mode */ + writeb(I2C_BIT_WTIM0, priv->base + I2C_OFS_IICC0); + + /* Enable I2C operation */ + writeb(I2C_BIT_IICE0, priv->base + I2C_OFS_IICACT0); + + retr = 1000; + while (readb(priv->base + I2C_OFS_IICACT0) == 0 && retr) + retr--; + WARN_ON(retr == 0); +} + +static int __em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int stop) +{ + struct em_i2c_device *priv = i2c_get_adapdata(adap); + int count, status, read = !!(msg->flags & I2C_M_RD); + + /* Send start condition */ + em_clear_set_bit(priv, 0, I2C_BIT_ACKE0 | I2C_BIT_WTIM0, I2C_OFS_IICC0); + em_clear_set_bit(priv, 0, I2C_BIT_STT0, I2C_OFS_IICC0); + + /* Send slave address and R/W type */ + writeb((msg->addr << 1) | read, priv->base + I2C_OFS_IIC0); + + /* Wait for transaction */ + status = em_i2c_wait_for_event(priv); + if (status < 0) + goto out_reset; + + /* Received NACK (result of setting slave address and R/W) */ + if (!(status & I2C_BIT_ACKD0)) { + em_i2c_stop(priv); + goto out; + } + + /* Extra setup for read transactions */ + if (read) { + /* 8 bit interrupt mode */ + em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_ACKE0, I2C_OFS_IICC0); + em_clear_set_bit(priv, I2C_BIT_WTIM0, I2C_BIT_WREL0, I2C_OFS_IICC0); + + /* Wait for transaction */ + status = em_i2c_wait_for_event(priv); + if (status < 0) + goto out_reset; + } + + /* Send / receive data */ + for (count = 0; count < msg->len; count++) { + if (read) { /* Read transaction */ + msg->buf[count] = readb(priv->base + I2C_OFS_IIC0); + em_clear_set_bit(priv, 0, I2C_BIT_WREL0, I2C_OFS_IICC0); + + } else { /* Write transaction */ + /* Received NACK */ + if (!(status & I2C_BIT_ACKD0)) { + em_i2c_stop(priv); + goto out; + } + + /* Write data */ + writeb(msg->buf[count], priv->base + I2C_OFS_IIC0); + } + + /* Wait for R/W transaction */ + status = em_i2c_wait_for_event(priv); + if (status < 0) + goto out_reset; + } + + if (stop) + em_i2c_stop(priv); + + return count; + +out_reset: + em_i2c_reset(adap); +out: + return status < 0 ? status : -ENXIO; +} + +static int em_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct em_i2c_device *priv = i2c_get_adapdata(adap); + int ret, i; + + if (readb(priv->base + I2C_OFS_IICF0) & I2C_BIT_IICBSY) + return -EAGAIN; + + for (i = 0; i < num; i++) { + ret = __em_i2c_xfer(adap, &msgs[i], (i == (num - 1))); + if (ret < 0) + return ret; + } + + /* I2C transfer completed */ + return num; +} + +static irqreturn_t em_i2c_irq_handler(int this_irq, void *dev_id) +{ + struct em_i2c_device *priv = dev_id; + + complete(&priv->msg_done); + return IRQ_HANDLED; +} + +static u32 em_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm em_i2c_algo = { + .master_xfer = em_i2c_xfer, + .functionality = em_i2c_func, +}; + +static int em_i2c_probe(struct platform_device *pdev) +{ + struct em_i2c_device *priv; + struct resource *r; + int irq, ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + strlcpy(priv->adap.name, "EMEV2 I2C", sizeof(priv->adap.name)); + + priv->sclk = devm_clk_get(&pdev->dev, "sclk"); + if (IS_ERR(priv->sclk)) + return PTR_ERR(priv->sclk); + + clk_prepare_enable(priv->sclk); + + priv->adap.timeout = msecs_to_jiffies(100); + priv->adap.retries = 5; + priv->adap.dev.parent = &pdev->dev; + priv->adap.algo = &em_i2c_algo; + priv->adap.owner = THIS_MODULE; + priv->adap.dev.of_node = pdev->dev.of_node; + + init_completion(&priv->msg_done); + + platform_set_drvdata(pdev, priv); + i2c_set_adapdata(&priv->adap, priv); + + em_i2c_reset(&priv->adap); + + irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, irq, em_i2c_irq_handler, 0, + "em_i2c", priv); + if (ret) + goto err_clk; + + ret = i2c_add_adapter(&priv->adap); + + if (ret) + goto err_clk; + + dev_info(&pdev->dev, "Added i2c controller %d, irq %d\n", priv->adap.nr, irq); + + return 0; + +err_clk: + clk_disable_unprepare(priv->sclk); + return ret; +} + +static int em_i2c_remove(struct platform_device *dev) +{ + struct em_i2c_device *priv = platform_get_drvdata(dev); + + i2c_del_adapter(&priv->adap); + clk_disable_unprepare(priv->sclk); + + return 0; +} + +static const struct of_device_id em_i2c_ids[] = { + { .compatible = "renesas,iic-emev2", }, + { } +}; + +static struct platform_driver em_i2c_driver = { + .probe = em_i2c_probe, + .remove = em_i2c_remove, + .driver = { + .name = "em-i2c", + .of_match_table = em_i2c_ids, + } +}; +module_platform_driver(em_i2c_driver); + +MODULE_DESCRIPTION("EMEV2 I2C bus driver"); +MODULE_AUTHOR("Ian Molton and Wolfram Sang "); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, em_i2c_ids); -- cgit v1.3-6-gb490 From abf8a1fba9a48535595857ed46ad642272eea05c Mon Sep 17 00:00:00 2001 From: Leilei Shang Date: Tue, 14 Jul 2015 13:06:40 +0530 Subject: i2c: pxa: keep i2c irq ON in suspend During suspend there may still be some i2c access happening, as the interrupt is shared between multiple drivers. And if we don't keep i2c irq ON, there may be i2c access timeout if i2c is in irq mode of operation. Signed-off-by: Raul Xiong Signed-off-by: Xiaofan Tian [vaibhav.hiremath@linaro.org: updated Changelog] Signed-off-by: Vaibhav Hiremath Cc: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index d9c0d6a17ad6..f4ac8c595a45 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1232,8 +1232,9 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.algo = &i2c_pxa_pio_algorithm; } else { i2c->adap.algo = &i2c_pxa_algorithm; - ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED, - dev_name(&dev->dev), i2c); + ret = request_irq(irq, i2c_pxa_handler, + IRQF_SHARED | IRQF_NO_SUSPEND, + dev_name(&dev->dev), i2c); if (ret) goto ereqirq; } -- cgit v1.3-6-gb490 From e087b4272effeacc10629316d47a257c88f82898 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Tue, 14 Jul 2015 13:06:41 +0530 Subject: i2c: pxa: No need to set slave addr for i2c master mode reset Normally i2c controller works as master, so slave addr is not needed, or it will impact some slave device (eg. ST NFC chip) i2c accesses, because it has the same i2c address with controller. For example, On the pxa1928 based platform, where PMIC (88pm860) is present @0x30 address on TWSI0 interface, and if we set 0x30 as a slave address in pxa1928 TWSI0 module, all the transactions towards PMIC would go for toss. Signed-off-by: Jett.Zhou Signed-off-by: Vaibhav Hiremath Acked-by: Robert Jarzmik Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index f4ac8c595a45..023e59fda650 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -459,7 +459,7 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c) writel(I2C_ISR_INIT, _ISR(i2c)); writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c)); - if (i2c->reg_isar) + if (i2c->reg_isar && IS_ENABLED(CONFIG_I2C_PXA_SLAVE)) writel(i2c->slave_addr, _ISAR(i2c)); /* set control register values */ -- cgit v1.3-6-gb490 From 8bd75bd3038df5e743c7daa84c2d34d13493b395 Mon Sep 17 00:00:00 2001 From: Shouming Wang Date: Tue, 14 Jul 2015 13:06:42 +0530 Subject: i2c: pxa: Return I2C_RETRY when timeout in pio mode In case of timeout in pio mode of operation return I2C_RETRY. This behavior will be same as interrupt mode of operation. Signed-off-by: Shouming Wang [vaibhav.hiremath@linaro.org: Updated changelog] Signed-off-by: Vaibhav Hiremath Acked-by: Robert Jarzmik Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 023e59fda650..632008f24098 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -745,8 +745,10 @@ static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c, ret = i2c->msg_idx; out: - if (timeout == 0) + if (timeout == 0) { i2c_pxa_scream_blue_murder(i2c, "timeout"); + ret = I2C_RETRY; + } return ret; } -- cgit v1.3-6-gb490 From e2b498fd55a871ab3913914b982e3dd07d32e90e Mon Sep 17 00:00:00 2001 From: Yipeng Yao Date: Tue, 14 Jul 2015 13:06:43 +0530 Subject: i2c: pxa: Fix compile warning in 64bit mode Fix below warning message, coming from 64 bit toolchain. drivers/i2c/busses/i2c-pxa.c:1237:15: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] Signed-off-by: Yipeng Yao [vaibhav.hiremath@linaro.org: Updated Changelog] Signed-off-by: Vaibhav Hiremath Cc: Wolfram Sang Acked-by: Robert Jarzmik Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 632008f24098..d0cc058f42c3 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1116,7 +1116,9 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c, i2c->use_pio = 1; if (of_get_property(np, "mrvl,i2c-fast-mode", NULL)) i2c->fast_mode = 1; - *i2c_types = (u32)(of_id->data); + + *i2c_types = (enum pxa_i2c_types)(of_id->data); + return 0; } -- cgit v1.3-6-gb490 From 3a2dc1677b60af250bea85d470ef5151c70a1264 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Tue, 14 Jul 2015 13:06:44 +0530 Subject: i2c: pxa: Update debug function to dump more info on error Update i2c_pxa_scream_blue_murder() fn to print more information in case of error. Also, use dev_err variants instead of printk. Signed-off-by: Jett.Zhou Signed-off-by: Vaibhav Hiremath Cc: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index d0cc058f42c3..beeed7c53f2d 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -132,6 +132,7 @@ struct pxa_i2c { unsigned int msg_idx; unsigned int msg_ptr; unsigned int slave_addr; + unsigned int req_slave_addr; struct i2c_adapter adap; struct clk *clk; @@ -253,15 +254,20 @@ static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname) static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) { unsigned int i; - printk(KERN_ERR "i2c: error: %s\n", why); - printk(KERN_ERR "i2c: msg_num: %d msg_idx: %d msg_ptr: %d\n", + struct device *dev = &i2c->adap.dev; + + dev_err(dev, "slave_0x%x error: %s\n", + i2c->req_slave_addr >> 1, why); + dev_err(dev, "msg_num: %d msg_idx: %d msg_ptr: %d\n", i2c->msg_num, i2c->msg_idx, i2c->msg_ptr); - printk(KERN_ERR "i2c: ICR: %08x ISR: %08x\n", - readl(_ICR(i2c)), readl(_ISR(i2c))); - printk(KERN_DEBUG "i2c: log: "); + dev_err(dev, "IBMR: %08x IDBR: %08x ICR: %08x ISR: %08x\n", + readl(_IBMR(i2c)), readl(_IDBR(i2c)), readl(_ICR(i2c)), + readl(_ISR(i2c))); + dev_dbg(dev, "log: "); for (i = 0; i < i2c->irqlogidx; i++) - printk("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]); - printk("\n"); + pr_debug("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]); + + pr_debug("\n"); } #else /* ifdef DEBUG */ @@ -638,6 +644,7 @@ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c) * Step 1: target slave address into IDBR */ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c)); + i2c->req_slave_addr = i2c_pxa_addr_byte(i2c->msg); /* * Step 2: initiate the write. @@ -951,6 +958,7 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) * Write the next address. */ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c)); + i2c->req_slave_addr = i2c_pxa_addr_byte(i2c->msg); /* * And trigger a repeated start, and send the byte. -- cgit v1.3-6-gb490 From 51fcce86a70f6f63d733619afc425821118838dc Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Tue, 14 Jul 2015 13:06:45 +0530 Subject: i2c: pxa: Use devm_ variants in probe function This patch cleans up i2c_pxa_probe() function, - Use devm_ variants wherever This will clean both probe exit and i2c_pxa_remove() functions - Check platform resource before parsing any other data from DT/platform - Use dev_err on failure from i2c_add_numbered_adapter() - Use pr_info instead of printk for KERN_INFO Signed-off-by: Vaibhav Hiremath Acked-by: Robert Jarzmik [wsa: removed unneeded error prinout after devm_ioremap_resource] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa.c | 77 +++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index beeed7c53f2d..645e4b79d968 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1158,10 +1158,19 @@ static int i2c_pxa_probe(struct platform_device *dev) struct resource *res = NULL; int ret, irq; - i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL); - if (!i2c) { - ret = -ENOMEM; - goto emalloc; + i2c = devm_kzalloc(&dev->dev, sizeof(struct pxa_i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + i2c->reg_base = devm_ioremap_resource(&dev->dev, res); + if (IS_ERR(i2c->reg_base)) + return PTR_ERR(i2c->reg_base); + + irq = platform_get_irq(dev, 0); + if (irq < 0) { + dev_err(&dev->dev, "no irq resource: %d\n", irq); + return irq; } /* Default adapter num to device id; i2c_pxa_probe_dt can override. */ @@ -1171,19 +1180,7 @@ static int i2c_pxa_probe(struct platform_device *dev) if (ret > 0) ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type); if (ret < 0) - goto eclk; - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - irq = platform_get_irq(dev, 0); - if (res == NULL || irq < 0) { - ret = -ENODEV; - goto eclk; - } - - if (!request_mem_region(res->start, resource_size(res), res->name)) { - ret = -ENOMEM; - goto eclk; - } + return ret; i2c->adap.owner = THIS_MODULE; i2c->adap.retries = 5; @@ -1193,16 +1190,10 @@ static int i2c_pxa_probe(struct platform_device *dev) strlcpy(i2c->adap.name, "pxa_i2c-i2c", sizeof(i2c->adap.name)); - i2c->clk = clk_get(&dev->dev, NULL); + i2c->clk = devm_clk_get(&dev->dev, NULL); if (IS_ERR(i2c->clk)) { - ret = PTR_ERR(i2c->clk); - goto eclk; - } - - i2c->reg_base = ioremap(res->start, resource_size(res)); - if (!i2c->reg_base) { - ret = -EIO; - goto eremap; + dev_err(&dev->dev, "failed to get the clk: %ld\n", PTR_ERR(i2c->clk)); + return PTR_ERR(i2c->clk); } i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr; @@ -1244,11 +1235,13 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.algo = &i2c_pxa_pio_algorithm; } else { i2c->adap.algo = &i2c_pxa_algorithm; - ret = request_irq(irq, i2c_pxa_handler, + ret = devm_request_irq(&dev->dev, irq, i2c_pxa_handler, IRQF_SHARED | IRQF_NO_SUSPEND, dev_name(&dev->dev), i2c); - if (ret) + if (ret) { + dev_err(&dev->dev, "failed to request irq: %d\n", ret); goto ereqirq; + } } i2c_pxa_reset(i2c); @@ -1261,33 +1254,22 @@ static int i2c_pxa_probe(struct platform_device *dev) ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { - printk(KERN_INFO "I2C: Failed to add bus\n"); - goto eadapt; + dev_err(&dev->dev, "failed to add bus: %d\n", ret); + goto ereqirq; } platform_set_drvdata(dev, i2c); #ifdef CONFIG_I2C_PXA_SLAVE - printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n", - dev_name(&i2c->adap.dev), i2c->slave_addr); + dev_info(&i2c->adap.dev, " PXA I2C adapter, slave address %d\n", + i2c->slave_addr); #else - printk(KERN_INFO "I2C: %s: PXA I2C adapter\n", - dev_name(&i2c->adap.dev)); + dev_info(&i2c->adap.dev, " PXA I2C adapter\n"); #endif return 0; -eadapt: - if (!i2c->use_pio) - free_irq(irq, i2c); ereqirq: clk_disable_unprepare(i2c->clk); - iounmap(i2c->reg_base); -eremap: - clk_put(i2c->clk); -eclk: - kfree(i2c); -emalloc: - release_mem_region(res->start, resource_size(res)); return ret; } @@ -1296,15 +1278,8 @@ static int i2c_pxa_remove(struct platform_device *dev) struct pxa_i2c *i2c = platform_get_drvdata(dev); i2c_del_adapter(&i2c->adap); - if (!i2c->use_pio) - free_irq(i2c->irq, i2c); clk_disable_unprepare(i2c->clk); - clk_put(i2c->clk); - - iounmap(i2c->reg_base); - release_mem_region(i2c->iobase, i2c->iosize); - kfree(i2c); return 0; } -- cgit v1.3-6-gb490 From 0387fc1645fed3b723e8556d83452bc09f79fd24 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Wed, 17 Jun 2015 20:48:11 +0530 Subject: i2c: xiic: Remove the disabling of interrupts Currently the interrupts are disabled at the start of the isr and enabled at the end of the isr. Remove the same. In case the slave device NACKs the transaction while in the isr the transfer will continue and the NACK interrupt will arrive only after the isr is serviced. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 4dda23f22a67..912780a3a65e 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -604,14 +604,11 @@ static irqreturn_t xiic_isr(int irq, void *dev_id) struct xiic_i2c *i2c = dev_id; spin_lock(&i2c->lock); - /* disable interrupts globally */ - xiic_setreg32(i2c, XIIC_DGIER_OFFSET, 0); dev_dbg(i2c->adap.dev.parent, "%s entry\n", __func__); xiic_process(i2c); - xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); spin_unlock(&i2c->lock); return IRQ_HANDLED; -- cgit v1.3-6-gb490 From fcc2fac60a95b4e63682ae4128e86d8768602fab Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Wed, 17 Jun 2015 20:48:12 +0530 Subject: i2c: xiic: move the xiic_process to thread context The xiic_process is a 154 line code that runs in isr context currently move it to thread context. Also the name xiic_process suggests that the intension was to run in process context. Signed-off-by: Shubhrajyoti Datta [wsa: initialized irqreturn_t to IRQ_NONE instead of IRQ_HANDLED] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 912780a3a65e..3664dffdcab7 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -358,8 +358,9 @@ static void xiic_wakeup(struct xiic_i2c *i2c, int code) wake_up(&i2c->wait); } -static void xiic_process(struct xiic_i2c *i2c) +static irqreturn_t xiic_process(int irq, void *dev_id) { + struct xiic_i2c *i2c = dev_id; u32 pend, isr, ier; u32 clr = 0; @@ -368,6 +369,7 @@ static void xiic_process(struct xiic_i2c *i2c) * To find which interrupts are pending; AND interrupts pending with * interrupts masked. */ + spin_lock(&i2c->lock); isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET); ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); pend = isr & ier; @@ -378,11 +380,6 @@ static void xiic_process(struct xiic_i2c *i2c) __func__, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET), i2c->tx_msg, i2c->nmsgs); - /* Do not processes a devices interrupts if the device has no - * interrupts pending - */ - if (!pend) - return; /* Service requesting interrupt */ if ((pend & XIIC_INTR_ARB_LOST_MASK) || @@ -502,6 +499,8 @@ out: dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr); xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr); + spin_unlock(&i2c->lock); + return IRQ_HANDLED; } static int xiic_bus_busy(struct xiic_i2c *i2c) @@ -602,16 +601,21 @@ static void xiic_start_send(struct xiic_i2c *i2c) static irqreturn_t xiic_isr(int irq, void *dev_id) { struct xiic_i2c *i2c = dev_id; - - spin_lock(&i2c->lock); + u32 pend, isr, ier; + irqreturn_t ret = IRQ_NONE; + /* Do not processes a devices interrupts if the device has no + * interrupts pending + */ dev_dbg(i2c->adap.dev.parent, "%s entry\n", __func__); - xiic_process(i2c); - - spin_unlock(&i2c->lock); + isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET); + ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); + pend = isr & ier; + if (pend) + ret = IRQ_WAKE_THREAD; - return IRQ_HANDLED; + return ret; } static void __xiic_start_xfer(struct xiic_i2c *i2c) @@ -752,7 +756,10 @@ static int xiic_i2c_probe(struct platform_device *pdev) spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); - ret = devm_request_irq(&pdev->dev, irq, xiic_isr, 0, pdev->name, i2c); + ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr, + xiic_process, IRQF_ONESHOT, + pdev->name, i2c); + if (ret < 0) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); return ret; -- cgit v1.3-6-gb490 From d701667bb3318f27152ad61a6f5cc8b36cc5fcad Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Wed, 17 Jun 2015 20:48:13 +0530 Subject: i2c: xiic: Do not reset controller before every transfer Currently before every transfer the controller is reinitialised. We are already resetting the controller upon errors so upon every transfer is a performance kill. Remove the same. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 3664dffdcab7..43bcfeddc54e 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -667,7 +667,6 @@ static void xiic_start_xfer(struct xiic_i2c *i2c) unsigned long flags; spin_lock_irqsave(&i2c->lock, flags); - xiic_reinit(i2c); /* disable interrupts globally */ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, 0); spin_unlock_irqrestore(&i2c->lock, flags); -- cgit v1.3-6-gb490 From e6c9a037bc8afdce055a2a23bb61903b3844dfda Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Wed, 17 Jun 2015 20:48:14 +0530 Subject: i2c: xiic: Remove the disabling of interrupts Currently before every transfer the interrupts are disabled. So incase the slave nacks in the middle of the transfer the current transfer is not aborted. Upon enabling the interrupts conditions like NACK , arbitration lost will not be masked. Remove the disabling of the interrupts. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 43bcfeddc54e..5d133d487ec0 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -664,15 +664,8 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c) static void xiic_start_xfer(struct xiic_i2c *i2c) { - unsigned long flags; - - spin_lock_irqsave(&i2c->lock, flags); - /* disable interrupts globally */ - xiic_setreg32(i2c, XIIC_DGIER_OFFSET, 0); - spin_unlock_irqrestore(&i2c->lock, flags); __xiic_start_xfer(i2c); - xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); } static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) -- cgit v1.3-6-gb490 From b33aa252785eb6de2f5325a3338fa917a9b4bc66 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Wed, 17 Jun 2015 20:48:15 +0530 Subject: i2c: xiic: Remove busy loop while waiting for bus busy Remove the busy loop while waiting for bus busy. Instead let the processor sleep. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 5d133d487ec0..41da9028b6ea 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -524,7 +524,7 @@ static int xiic_busy(struct xiic_i2c *i2c) */ err = xiic_bus_busy(i2c); while (err && tries--) { - mdelay(1); + msleep(1); err = xiic_bus_busy(i2c); } -- cgit v1.3-6-gb490 From 542e2a9b739068c1b72db530987382662201469a Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Wed, 17 Jun 2015 20:48:17 +0530 Subject: i2c: xiic: Remove the Addressed as slave interrupt Currently there is no slave mode support in the driver also in the isr we just ack it and do nothing. So disable the AAS interrupt. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 41da9028b6ea..08dfb8c88bbb 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -283,7 +283,7 @@ static void xiic_reinit(struct xiic_i2c *i2c) /* Enable interrupts */ xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); - xiic_irq_clr_en(i2c, XIIC_INTR_AAS_MASK | XIIC_INTR_ARB_LOST_MASK); + xiic_irq_clr_en(i2c, XIIC_INTR_ARB_LOST_MASK); } static void xiic_deinit(struct xiic_i2c *i2c) -- cgit v1.3-6-gb490 From 7f9906bd7f7211327ba58657caa216608f9c93de Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Wed, 17 Jun 2015 20:48:18 +0530 Subject: i2c: xiic: Service all interrupts in isr Currently only one interrupt is serviced in the isr. In case the multiple interrupts happen simultenously we service and ack only one of them. Check for all the causes in the isr and service them. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 08dfb8c88bbb..987a18c8b6e3 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -401,11 +401,11 @@ static irqreturn_t xiic_process(int irq, void *dev_id) if (i2c->tx_msg) xiic_wakeup(i2c, STATE_ERROR); - - } else if (pend & XIIC_INTR_RX_FULL_MASK) { + } + if (pend & XIIC_INTR_RX_FULL_MASK) { /* Receive register/FIFO is full */ - clr = XIIC_INTR_RX_FULL_MASK; + clr |= XIIC_INTR_RX_FULL_MASK; if (!i2c->rx_msg) { dev_dbg(i2c->adap.dev.parent, "%s unexpexted RX IRQ\n", __func__); @@ -438,9 +438,10 @@ static irqreturn_t xiic_process(int irq, void *dev_id) __xiic_start_xfer(i2c); } } - } else if (pend & XIIC_INTR_BNB_MASK) { + } + if (pend & XIIC_INTR_BNB_MASK) { /* IIC bus has transitioned to not busy */ - clr = XIIC_INTR_BNB_MASK; + clr |= XIIC_INTR_BNB_MASK; /* The bus is not busy, disable BusNotBusy interrupt */ xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK); @@ -453,12 +454,12 @@ static irqreturn_t xiic_process(int irq, void *dev_id) xiic_wakeup(i2c, STATE_DONE); else xiic_wakeup(i2c, STATE_ERROR); - - } else if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) { + } + if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) { /* Transmit register/FIFO is empty or ½ empty */ - clr = pend & - (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK); + clr |= (pend & + (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)); if (!i2c->tx_msg) { dev_dbg(i2c->adap.dev.parent, @@ -489,11 +490,6 @@ static irqreturn_t xiic_process(int irq, void *dev_id) * make sure to disable tx half */ xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK); - } else { - /* got IRQ which is not acked */ - dev_err(i2c->adap.dev.parent, "%s Got unexpected IRQ\n", - __func__); - clr = pend; } out: dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr); -- cgit v1.3-6-gb490 From 6b0c8dc3104253a5e4b2ec923eeb48cece0abcb9 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Wed, 17 Jun 2015 20:48:19 +0530 Subject: i2c: xiic: Do not continue in case of errors in Rx In case of error conditions like Arbitration lost or NACK lets signal the waiting process. Handle error cases in the Rx path Signed-off-by: Shubhrajyoti Datta Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xiic.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 987a18c8b6e3..e23a7b068c60 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -399,6 +399,8 @@ static irqreturn_t xiic_process(int irq, void *dev_id) */ xiic_reinit(i2c); + if (i2c->rx_msg) + xiic_wakeup(i2c, STATE_ERROR); if (i2c->tx_msg) xiic_wakeup(i2c, STATE_ERROR); } -- cgit v1.3-6-gb490 From 77441ac00d324c037c088da090fa505b45dad9d4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 14 Jul 2015 14:07:08 +0200 Subject: i2c: omap: fix cleanup regression Patch "i2c: omap: abolish variable name confusion" triggered a coccinelle warning which we fix here: drivers/i2c/busses/i2c-omap.c:1333:5-24: pm_runtime_get_sync returns < 0 as error. Unecessary IS_ERR_VALUE at line 1334 Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index afc3bfca0b6c..08d26ba61ed3 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1342,7 +1342,7 @@ omap_i2c_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(omap->dev); r = pm_runtime_get_sync(omap->dev); - if (IS_ERR_VALUE(r)) + if (r < 0) goto err_free_mem; /* -- cgit v1.3-6-gb490 From 6f4664b2e2c2cfa35b48271423c5e602b6970f14 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 30 Jun 2015 16:24:26 +0530 Subject: i2c: tegra: update CONFIG_LOAD for new conifiguration Once the new configuration is set on the conifg register of I2C controller, it is require to update the CONFIG_LOAD register to transfer the new SW configuration to actual HW internal registers that would be used in the actual logic. It is like, SW is programming only shadow registers through regular configuration and when these load_config bit fields are set to 1, it causes the regular/shadows registers configuration transferred to the HW internal active registers. So SW has to set these bit fields at the end of all regular registers configuration. And these config_load bits are HW auto-clear bits. HW clears these bit fields once the register configuration is moved to HW internal active registers. So SW has to wait until these bits are auto-cleared before going for any further programming This mechanism is supported on T124 and after this SoCs. Signed-off-by: Chaitanya Bandi Signed-off-by: Laxman Dewangan Tested-by: Stephen Warren Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 78a366814696..348870acfef2 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -100,6 +100,12 @@ #define I2C_HEADER_CONTINUE_XFER (1<<15) #define I2C_HEADER_MASTER_ADDR_SHIFT 12 #define I2C_HEADER_SLAVE_ADDR_SHIFT 1 + +#define I2C_CONFIG_LOAD 0x08C +#define I2C_MSTR_CONFIG_LOAD (1 << 0) +#define I2C_SLV_CONFIG_LOAD (1 << 1) +#define I2C_TIMEOUT_CONFIG_LOAD (1 << 2) + /* * msg_end_type: The bus control which need to be send at end of transfer. * @MSG_END_STOP: Send stop pulse at end of transfer. @@ -121,6 +127,8 @@ enum msg_end_type { * @has_single_clk_source: The i2c controller has single clock source. Tegra30 * and earlier Socs has two clock sources i.e. div-clk and * fast-clk. + * @has_config_load_reg: Has the config load register to load the new + * configuration. * @clk_divisor_hs_mode: Clock divisor in HS mode. * @clk_divisor_std_fast_mode: Clock divisor in standard/fast mode. It is * applicable if there is no fast clock source i.e. single clock @@ -131,6 +139,7 @@ struct tegra_i2c_hw_feature { bool has_continue_xfer_support; bool has_per_pkt_xfer_complete_irq; bool has_single_clk_source; + bool has_config_load_reg; int clk_divisor_hs_mode; int clk_divisor_std_fast_mode; }; @@ -410,6 +419,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) u32 val; int err = 0; u32 clk_divisor; + unsigned long timeout = jiffies + HZ; err = tegra_i2c_clock_enable(i2c_dev); if (err < 0) { @@ -451,6 +461,18 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (tegra_i2c_flush_fifos(i2c_dev)) err = -ETIMEDOUT; + if (i2c_dev->hw->has_config_load_reg) { + i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD); + while (i2c_readl(i2c_dev, I2C_CONFIG_LOAD) != 0) { + if (time_after(jiffies, timeout)) { + dev_warn(i2c_dev->dev, + "timeout waiting for config load\n"); + return -ETIMEDOUT; + } + msleep(1); + } + } + tegra_i2c_clock_disable(i2c_dev); if (i2c_dev->irq_disabled) { @@ -681,6 +703,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { .has_single_clk_source = false, .clk_divisor_hs_mode = 3, .clk_divisor_std_fast_mode = 0, + .has_config_load_reg = false, }; static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { @@ -689,6 +712,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { .has_single_clk_source = false, .clk_divisor_hs_mode = 3, .clk_divisor_std_fast_mode = 0, + .has_config_load_reg = false, }; static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { @@ -697,10 +721,21 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { .has_single_clk_source = true, .clk_divisor_hs_mode = 1, .clk_divisor_std_fast_mode = 0x19, + .has_config_load_reg = false, +}; + +static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { + .has_continue_xfer_support = true, + .has_per_pkt_xfer_complete_irq = true, + .has_single_clk_source = true, + .clk_divisor_hs_mode = 1, + .clk_divisor_std_fast_mode = 0x19, + .has_config_load_reg = true, }; /* Match table for of_platform binding */ static const struct of_device_id tegra_i2c_of_match[] = { + { .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, }, { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, }, { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, }, { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, }, -- cgit v1.3-6-gb490 From d57f5dedde18253d5c72a823c0a7ff3b20b57560 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 30 Jun 2015 16:24:27 +0530 Subject: i2c: tegra: add support for fast plus (FM+) mode clock rate Tegra I2C controller required to configure the clock divisor register inside controller to different value based on the clock speed. The recommended clock divisor for the I2C controller for standard/fast mode is 0x19 and for fast-mode plus is 0x10. Add support to configure clock divisor register of I2C controller based on bus clock rate. This clock divisor is supported form T114 onwards. Signed-off-by: Chaitanya Bandi Signed-off-by: Laxman Dewangan Tested-by: Stephen Warren Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-tegra.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 348870acfef2..b7e1a3655421 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -142,6 +142,7 @@ struct tegra_i2c_hw_feature { bool has_config_load_reg; int clk_divisor_hs_mode; int clk_divisor_std_fast_mode; + u16 clk_divisor_fast_plus_mode; }; /** @@ -181,6 +182,7 @@ struct tegra_i2c_dev { size_t msg_buf_remaining; int msg_read; u32 bus_clk_rate; + u16 clk_divisor_non_hs_mode; bool is_suspended; }; @@ -441,7 +443,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) /* Make sure clock divisor programmed correctly */ clk_divisor = i2c_dev->hw->clk_divisor_hs_mode; - clk_divisor |= i2c_dev->hw->clk_divisor_std_fast_mode << + clk_divisor |= i2c_dev->clk_divisor_non_hs_mode << I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT; i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR); @@ -703,6 +705,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { .has_single_clk_source = false, .clk_divisor_hs_mode = 3, .clk_divisor_std_fast_mode = 0, + .clk_divisor_fast_plus_mode = 0, .has_config_load_reg = false, }; @@ -712,6 +715,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { .has_single_clk_source = false, .clk_divisor_hs_mode = 3, .clk_divisor_std_fast_mode = 0, + .clk_divisor_fast_plus_mode = 0, .has_config_load_reg = false, }; @@ -721,6 +725,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { .has_single_clk_source = true, .clk_divisor_hs_mode = 1, .clk_divisor_std_fast_mode = 0x19, + .clk_divisor_fast_plus_mode = 0x10, .has_config_load_reg = false, }; @@ -730,6 +735,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { .has_single_clk_source = true, .clk_divisor_hs_mode = 1, .clk_divisor_std_fast_mode = 0x19, + .clk_divisor_fast_plus_mode = 0x10, .has_config_load_reg = true, }; @@ -828,7 +834,14 @@ static int tegra_i2c_probe(struct platform_device *pdev) } } - clk_multiplier *= (i2c_dev->hw->clk_divisor_std_fast_mode + 1); + i2c_dev->clk_divisor_non_hs_mode = + i2c_dev->hw->clk_divisor_std_fast_mode; + if (i2c_dev->hw->clk_divisor_fast_plus_mode && + (i2c_dev->bus_clk_rate == 1000000)) + i2c_dev->clk_divisor_non_hs_mode = + i2c_dev->hw->clk_divisor_fast_plus_mode; + + clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1); ret = clk_set_rate(i2c_dev->div_clk, i2c_dev->bus_clk_rate * clk_multiplier); if (ret) { -- cgit v1.3-6-gb490 From 63cab195bf498676619951e81ad5791e9d47c420 Mon Sep 17 00:00:00 2001 From: Anurag Kumar Vulisha Date: Fri, 10 Jul 2015 20:10:14 +0530 Subject: i2c: removed work arounds in i2c driver for Zynq Ultrascale+ MPSoC Cadence 1.0 version has bugs which have been fixed in the cadence 1.4 version. This patch removes the quirks present in the driver for cadence 1.4 version. Signed-off-by: Anurag Kumar Vulisha [wsa: fixed indentation issues in r1p10_i2c_def] Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-cadence.txt | 6 +- drivers/i2c/busses/i2c-cadence.c | 68 ++++++++++++++++++---- 2 files changed, 62 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/i2c/i2c-cadence.txt b/Documentation/devicetree/bindings/i2c/i2c-cadence.txt index 7cb0b5608f49..ebaa90c58c8e 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-cadence.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-cadence.txt @@ -2,7 +2,11 @@ Binding for the Cadence I2C controller Required properties: - reg: Physical base address and size of the controller's register area. - - compatible: Compatibility string. Must be 'cdns,i2c-r1p10'. + - compatible: Should contain one of: + * "cdns,i2c-r1p10" + Note: Use this when cadence i2c controller version 1.0 is used. + * "cdns,i2c-r1p14" + Note: Use this when cadence i2c controller version 1.4 is used. - clocks: Input clock specifier. Refer to common clock bindings. - interrupts: Interrupt specifier. Refer to interrupt bindings. - #address-cells: Should be 1. diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 2ee78e099d30..18e48ae4a60d 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -17,6 +17,7 @@ #include #include #include +#include /* Register offsets for the I2C device. */ #define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */ @@ -113,6 +114,8 @@ #define CDNS_I2C_TIMEOUT_MAX 0xFF +#define CDNS_I2C_BROKEN_HOLD_BIT BIT(0) + #define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset) #define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset) @@ -135,6 +138,7 @@ * @bus_hold_flag: Flag used in repeated start for clearing HOLD bit * @clk: Pointer to struct clk * @clk_rate_change_nb: Notifier block for clock rate changes + * @quirks: flag for broken hold bit usage in r1p10 */ struct cdns_i2c { void __iomem *membase; @@ -154,6 +158,11 @@ struct cdns_i2c { unsigned int bus_hold_flag; struct clk *clk; struct notifier_block clk_rate_change_nb; + u32 quirks; +}; + +struct cdns_platform_data { + u32 quirks; }; #define to_cdns_i2c(_nb) container_of(_nb, struct cdns_i2c, \ @@ -172,6 +181,12 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id) cdns_i2c_writereg(reg & ~CDNS_I2C_CR_HOLD, CDNS_I2C_CR_OFFSET); } +static inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround) +{ + return (hold_wrkaround && + (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)); +} + /** * cdns_i2c_isr - Interrupt handler for the I2C device * @irq: irq number for the I2C device @@ -186,6 +201,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) { unsigned int isr_status, avail_bytes, updatetx; unsigned int bytes_to_send; + bool hold_quirk; struct cdns_i2c *id = ptr; /* Signal completion only after everything is updated */ int done_flag = 0; @@ -208,6 +224,8 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) if (id->recv_count > id->curr_recv_count) updatetx = 1; + hold_quirk = (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx; + /* When receiving, handle data interrupt and completion interrupt */ if (id->p_recv_buf && ((isr_status & CDNS_I2C_IXR_COMP) || @@ -229,8 +247,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) id->recv_count--; id->curr_recv_count--; - if (updatetx && - (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) + if (cdns_is_holdquirk(id, hold_quirk)) break; } @@ -241,8 +258,7 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) * maintain transfer size non-zero while performing a large * receive operation. */ - if (updatetx && - (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) { + if (cdns_is_holdquirk(id, hold_quirk)) { /* wait while fifo is full */ while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) != (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH)) @@ -264,6 +280,22 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) CDNS_I2C_XFER_SIZE_OFFSET); id->curr_recv_count = id->recv_count; } + } else if (id->recv_count && !hold_quirk && + !id->curr_recv_count) { + + /* Set the slave address in address register*/ + cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK, + CDNS_I2C_ADDR_OFFSET); + + if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) { + cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE; + } else { + cdns_i2c_writereg(id->recv_count, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = id->recv_count; + } } /* Clear hold (if not repeated start) and signal completion */ @@ -535,11 +567,13 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int ret, count; u32 reg; struct cdns_i2c *id = adap->algo_data; + bool hold_quirk; /* Check if the bus is free */ if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) return -EAGAIN; + hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT); /* * Set the flag to one when multiple messages are to be * processed with a repeated start. @@ -552,7 +586,7 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, * followed by any other message, an error is returned * indicating that this sequence is not supported. */ - for (count = 0; count < num - 1; count++) { + for (count = 0; (count < num - 1 && hold_quirk); count++) { if (msgs[count].flags & I2C_M_RD) { dev_warn(adap->dev.parent, "Can't do repeated start after a receive message\n"); @@ -815,6 +849,17 @@ static int __maybe_unused cdns_i2c_resume(struct device *_dev) static SIMPLE_DEV_PM_OPS(cdns_i2c_dev_pm_ops, cdns_i2c_suspend, cdns_i2c_resume); +static const struct cdns_platform_data r1p10_i2c_def = { + .quirks = CDNS_I2C_BROKEN_HOLD_BIT, +}; + +static const struct of_device_id cdns_i2c_of_match[] = { + { .compatible = "cdns,i2c-r1p10", .data = &r1p10_i2c_def }, + { .compatible = "cdns,i2c-r1p14",}, + { /* end of table */ } +}; +MODULE_DEVICE_TABLE(of, cdns_i2c_of_match); + /** * cdns_i2c_probe - Platform registration call * @pdev: Handle to the platform device structure @@ -830,6 +875,7 @@ static int cdns_i2c_probe(struct platform_device *pdev) struct resource *r_mem; struct cdns_i2c *id; int ret; + const struct of_device_id *match; id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL); if (!id) @@ -837,6 +883,12 @@ static int cdns_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, id); + match = of_match_node(cdns_i2c_of_match, pdev->dev.of_node); + if (match && match->data) { + const struct cdns_platform_data *data = match->data; + id->quirks = data->quirks; + } + r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); id->membase = devm_ioremap_resource(&pdev->dev, r_mem); if (IS_ERR(id->membase)) @@ -935,12 +987,6 @@ static int cdns_i2c_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id cdns_i2c_of_match[] = { - { .compatible = "cdns,i2c-r1p10", }, - { /* end of table */ } -}; -MODULE_DEVICE_TABLE(of, cdns_i2c_of_match); - static struct platform_driver cdns_i2c_drv = { .driver = { .name = DRIVER_NAME, -- cgit v1.3-6-gb490 From 82cd5d041c8c2cdceaa6833d2f73905279d1c94f Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 13 Jul 2015 19:31:12 +0200 Subject: i2c: parport: Add VCT-jig adapter Add support for VCT-jig parallel port I2C adapter to i2c-parport. The adapter schematic can be found here (in the RAR file): http://remont-aud.net/shop/22/desc/vct-jig-komplekt-dlja-samostojatelnoj-sborki Signed-off-by: Ondrej Zary Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- Documentation/i2c/busses/i2c-parport | 1 + drivers/i2c/busses/i2c-parport.h | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/Documentation/i2c/busses/i2c-parport b/Documentation/i2c/busses/i2c-parport index 0e2d17b460fd..c3dbb3bfd814 100644 --- a/Documentation/i2c/busses/i2c-parport +++ b/Documentation/i2c/busses/i2c-parport @@ -20,6 +20,7 @@ It currently supports the following devices: * (type=5) Analog Devices evaluation boards: ADM1025, ADM1030, ADM1031 * (type=6) Barco LPT->DVI (K5800236) adapter * (type=7) One For All JP1 parallel port adapter + * (type=8) VCT-jig These devices use different pinout configurations, so you have to tell the driver what you have, using the type module parameter. There is no diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h index 4e1294536805..84a6616b072f 100644 --- a/drivers/i2c/busses/i2c-parport.h +++ b/drivers/i2c/busses/i2c-parport.h @@ -89,6 +89,13 @@ static const struct adapter_parm adapter_parm[] = { .getsda = { 0x80, PORT_STAT, 1 }, .init = { 0x04, PORT_DATA, 1 }, }, + /* type 8: VCT-jig */ + { + .setsda = { 0x04, PORT_DATA, 1 }, + .setscl = { 0x01, PORT_DATA, 1 }, + .getsda = { 0x40, PORT_STAT, 0 }, + .getscl = { 0x80, PORT_STAT, 1 }, + }, }; static int type = -1; @@ -103,4 +110,5 @@ MODULE_PARM_DESC(type, " 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n" " 6 = Barco LPT->DVI (K5800236) adapter\n" " 7 = One For All JP1 parallel port adapter\n" + " 8 = VCT-jig\n" ); -- cgit v1.3-6-gb490 From b0898fdaffb2932aba0108986b90d9d69888e189 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 Jul 2015 13:15:36 +0300 Subject: i2c: designware-pci: use IRQF_COND_SUSPEND flag The mentioned flag fixes a warning on Intel Edison board since one of the I2C controller shares IRQ line with watchdog timer. Signed-off-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 6643d2dc0b25..df23e8c30e6f 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -260,8 +260,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, 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); + r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, + IRQF_SHARED | IRQF_COND_SUSPEND, adap->name, dev); if (r) { dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); return r; -- cgit v1.3-6-gb490 From 069d5b745b2a98ebc8c239fe0b7bdb6c5ff0f475 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:52:31 +0900 Subject: i2c: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-slave-eeprom.c | 1 - drivers/i2c/muxes/i2c-mux-pca9541.c | 1 - drivers/i2c/muxes/i2c-mux-pca954x.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c index 1da449614779..b2039f94c9d8 100644 --- a/drivers/i2c/i2c-slave-eeprom.c +++ b/drivers/i2c/i2c-slave-eeprom.c @@ -157,7 +157,6 @@ MODULE_DEVICE_TABLE(i2c, i2c_slave_eeprom_id); static struct i2c_driver i2c_slave_eeprom_driver = { .driver = { .name = "i2c-slave-eeprom", - .owner = THIS_MODULE, }, .probe = i2c_slave_eeprom_probe, .remove = i2c_slave_eeprom_remove, diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index 0c8d4d2cbdaf..d0ba424adebc 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -386,7 +386,6 @@ static int pca9541_remove(struct i2c_client *client) static struct i2c_driver pca9541_driver = { .driver = { .name = "pca9541", - .owner = THIS_MODULE, }, .probe = pca9541_probe, .remove = pca9541_remove, diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index ea4aa9dfcea9..acfcef3d4068 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -300,7 +300,6 @@ static struct i2c_driver pca954x_driver = { .driver = { .name = "pca954x", .pm = &pca954x_pm, - .owner = THIS_MODULE, }, .probe = pca954x_probe, .remove = pca954x_remove, -- cgit v1.3-6-gb490 From 141124e6e0db645396321aabed01c5e0b12cccc1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:23:17 +0900 Subject: misc: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Wolfram Sang --- drivers/misc/ad525x_dpot-i2c.c | 1 - drivers/misc/apds990x.c | 1 - drivers/misc/bh1770glc.c | 1 - drivers/misc/bmp085-i2c.c | 1 - drivers/misc/eeprom/at24.c | 1 - drivers/misc/isl29003.c | 1 - drivers/misc/lis3lv02d/lis3lv02d_i2c.c | 1 - drivers/misc/ti-st/st_kim.c | 1 - drivers/misc/tsl2550.c | 1 - 9 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index 705b881e186d..d11187d36ddd 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c @@ -106,7 +106,6 @@ MODULE_DEVICE_TABLE(i2c, ad_dpot_id); static struct i2c_driver ad_dpot_i2c_driver = { .driver = { .name = "ad_dpot", - .owner = THIS_MODULE, }, .probe = ad_dpot_i2c_probe, .remove = ad_dpot_i2c_remove, diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index 3739ffa9cdf1..a3e789b85cc8 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -1275,7 +1275,6 @@ static const struct dev_pm_ops apds990x_pm_ops = { static struct i2c_driver apds990x_driver = { .driver = { .name = "apds990x", - .owner = THIS_MODULE, .pm = &apds990x_pm_ops, }, .probe = apds990x_probe, diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index b756381b8250..753d7ecdadaa 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c @@ -1396,7 +1396,6 @@ static const struct dev_pm_ops bh1770_pm_ops = { static struct i2c_driver bh1770_driver = { .driver = { .name = "bh1770glc", - .owner = THIS_MODULE, .pm = &bh1770_pm_ops, }, .probe = bh1770_probe, diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c index a7c16295b816..f35c218aaa1a 100644 --- a/drivers/misc/bmp085-i2c.c +++ b/drivers/misc/bmp085-i2c.c @@ -66,7 +66,6 @@ MODULE_DEVICE_TABLE(i2c, bmp085_id); static struct i2c_driver bmp085_i2c_driver = { .driver = { - .owner = THIS_MODULE, .name = BMP085_NAME, }, .id_table = bmp085_id, diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 6ded3dc36644..2b254f3a1154 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -686,7 +686,6 @@ static int at24_remove(struct i2c_client *client) static struct i2c_driver at24_driver = { .driver = { .name = "at24", - .owner = THIS_MODULE, }, .probe = at24_probe, .remove = at24_remove, diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c index 12c30b486b27..976df0013633 100644 --- a/drivers/misc/isl29003.c +++ b/drivers/misc/isl29003.c @@ -465,7 +465,6 @@ MODULE_DEVICE_TABLE(i2c, isl29003_id); static struct i2c_driver isl29003_driver = { .driver = { .name = ISL29003_DRV_NAME, - .owner = THIS_MODULE, .pm = ISL29003_PM_OPS, }, .probe = isl29003_probe, diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c index e3e7f1dc27ba..0c3bb7e3ee80 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c @@ -274,7 +274,6 @@ static const struct dev_pm_ops lis3_pm_ops = { static struct i2c_driver lis3lv02d_i2c_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &lis3_pm_ops, .of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids), }, diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 5027b8ffae43..c84093e639e0 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -939,7 +939,6 @@ static struct platform_driver kim_platform_driver = { .resume = kim_resume, .driver = { .name = "kim", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(kim_of_match), }, }; diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c index b00335652e52..87a13374fdc0 100644 --- a/drivers/misc/tsl2550.c +++ b/drivers/misc/tsl2550.c @@ -446,7 +446,6 @@ MODULE_DEVICE_TABLE(i2c, tsl2550_id); static struct i2c_driver tsl2550_driver = { .driver = { .name = TSL2550_DRV_NAME, - .owner = THIS_MODULE, .pm = TSL2550_PM_OPS, }, .probe = tsl2550_probe, -- cgit v1.3-6-gb490 From 611e12ea0f121a31d9e9c4ce2a18a77abc2f28d6 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 17:30:49 +0300 Subject: i2c: core: manage i2c bus device refcount in i2c_[get|put]_adapter In addition to module_get()/module_put() add get_device()/put_device() calls into i2c_get_adapter()/i2c_put_adapter() exported interfaces. This is done to lock I2C bus device, if it is in use by a client. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index c83e4d13cfc5..f80992d0a608 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -2413,9 +2413,15 @@ struct i2c_adapter *i2c_get_adapter(int nr) mutex_lock(&core_lock); adapter = idr_find(&i2c_adapter_idr, nr); - if (adapter && !try_module_get(adapter->owner)) + if (!adapter) + goto exit; + + if (try_module_get(adapter->owner)) + get_device(&adapter->dev); + else adapter = NULL; + exit: mutex_unlock(&core_lock); return adapter; } @@ -2423,8 +2429,11 @@ EXPORT_SYMBOL(i2c_get_adapter); void i2c_put_adapter(struct i2c_adapter *adap) { - if (adap) - module_put(adap->owner); + if (!adap) + return; + + put_device(&adap->dev); + module_put(adap->owner); } EXPORT_SYMBOL(i2c_put_adapter); -- cgit v1.3-6-gb490 From 48e9743dd6483c5fd3f10c8e42c60d52d64b0e27 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 17:30:50 +0300 Subject: i2c: core: add and export of_get_i2c_adapter_by_node() interface of_find_i2c_adapter_by_node() call requires quite often missing put_device(), and i2c_put_adapter() releases a device locked by i2c_get_adapter() only. In general module_put(adapter->owner) and put_device(dev) are not interchangeable. This is a common error reproduction scenario as a result of the misusage described above (for clearness this is run on iMX6 platform with HDMI and I2C bus drivers compiled as kernel modules): root@mx6q:~# lsmod | grep i2c i2c_imx 10213 0 root@mx6q:~# lsmod | grep dw_hdmi_imx dw_hdmi_imx 3631 0 dw_hdmi 11846 1 dw_hdmi_imx imxdrm 8674 3 dw_hdmi_imx,imx_ipuv3_crtc,imx_ldb drm_kms_helper 113765 5 dw_hdmi,imxdrm,imx_ipuv3_crtc,imx_ldb root@mx6q:~# rmmod dw_hdmi_imx root@mx6q:~# lsmod | grep i2c i2c_imx 10213 -1 ^^^^^ root@mx6q:~# rmmod i2c_imx rmmod: ERROR: Module i2c_imx is in use To fix existing users of these interfaces and to avoid any further confusion and misusage in future, add one more interface of_get_i2c_adapter_by_node(), it is similar to i2c_get_adapter() in sense that an I2C bus device driver found and locked by user can be correctly unlocked by i2c_put_adapter(). Signed-off-by: Vladimir Zapolskiy Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 18 ++++++++++++++++++ include/linux/i2c.h | 7 +++++++ 2 files changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index f80992d0a608..07a83f34ed58 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1371,6 +1371,24 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) return adapter; } EXPORT_SYMBOL(of_find_i2c_adapter_by_node); + +/* must call i2c_put_adapter() when done with returned i2c_adapter device */ +struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node) +{ + struct i2c_adapter *adapter; + + adapter = of_find_i2c_adapter_by_node(node); + if (!adapter) + return NULL; + + if (!try_module_get(adapter->owner)) { + put_device(&adapter->dev); + adapter = NULL; + } + + return adapter; +} +EXPORT_SYMBOL(of_get_i2c_adapter_by_node); #else static void of_i2c_register_devices(struct i2c_adapter *adap) { } #endif /* CONFIG_OF */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index e83a738a3b87..e2c859b74f8b 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -638,6 +638,8 @@ extern struct i2c_client *of_find_i2c_device_by_node(struct device_node *node); /* must call put_device() when done with returned i2c_adapter device */ extern struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node); +/* must call i2c_put_adapter() when done with returned i2c_adapter device */ +struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node); #else static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) @@ -649,6 +651,11 @@ static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node { return NULL; } + +static inline struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node) +{ + return NULL; +} #endif /* CONFIG_OF */ #endif /* _LINUX_I2C_H */ -- cgit v1.3-6-gb490 From 0d1ad98dd837c069572d16faf77fa7f50748c7d5 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 17:30:51 +0300 Subject: i2c: arb-gpio-challenge: use of_get_i2c_adapter_by_node interface This change is needed to properly lock I2C parent bus driver. Prior to this change i2c_put_adapter() is misused, which may lead to an overflow over zero of I2C bus driver user counter. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-arb-gpio-challenge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index 5cf1b60b69e2..71aac0911bf7 100644 --- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -196,7 +196,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) dev_err(dev, "Cannot parse i2c-parent\n"); return -EINVAL; } - arb->parent = of_find_i2c_adapter_by_node(parent_np); + arb->parent = of_get_i2c_adapter_by_node(parent_np); if (!arb->parent) { dev_err(dev, "Cannot find parent bus\n"); return -EPROBE_DEFER; -- cgit v1.3-6-gb490 From fb427466dcde21fc4aab27153735bdd5c62b422d Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 7 Aug 2015 14:53:03 +0300 Subject: i2c: designware: Make debug print in i2c_dw_isr() shorter Printing adapter name is irrelevant from this debug print and makes output needlessly long. Having already device and functions names printed here is enough for debugging. While at it remove extra space from "enabled= 0x" and use "%#x" for printing "0x" prefixed hexadecimal values. Signed-off-by: Jarkko Nikula [wsa: made it a oneliner] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 6f19a33773fe..7441cdc1b34a 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -777,8 +777,7 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) enabled = dw_readl(dev, DW_IC_ENABLE); stat = dw_readl(dev, DW_IC_RAW_INTR_STAT); - dev_dbg(dev->dev, "%s: %s enabled= 0x%x stat=0x%x\n", __func__, - dev->adapter.name, enabled, stat); + dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled, stat); if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) return IRQ_NONE; -- cgit v1.3-6-gb490 From c49c1f0873faddf78c3545a8e25dfe23e8d15c2f Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 7 Aug 2015 14:04:19 +0200 Subject: misc: eeprom: Export I2C module alias information in missing drivers The I2C core always reports the MODALIAS uevent as "i2c:" regardless if the driver later is match using the I2C id_table or the of_match_table. So the driver needs to export the I2C table and this be built into the module or udev won't have the necessary information to auto load the correct module when the device is added. Signed-off-by: Javier Martinez Canillas Reviewed-by: Jean Delvare Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/max6875.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c index 580ff9df5529..c74920cc3d18 100644 --- a/drivers/misc/eeprom/max6875.c +++ b/drivers/misc/eeprom/max6875.c @@ -197,6 +197,7 @@ static const struct i2c_device_id max6875_id[] = { { "max6875", 0 }, { } }; +MODULE_DEVICE_TABLE(i2c, max6875_id); static struct i2c_driver max6875_driver = { .driver = { -- cgit v1.3-6-gb490 From a1f64317bbf5febe4c763cd6e022d533a802b847 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 21 Jul 2015 16:14:36 +0900 Subject: i2c: cadence: set THIS_MODULE to the owner of the adapter The owner of the adapter is missing, while this driver is tristate. Signed-off-by: Masahiro Yamada Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-cadence.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 18e48ae4a60d..84deed6571bd 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -896,6 +896,7 @@ static int cdns_i2c_probe(struct platform_device *pdev) id->irq = platform_get_irq(pdev, 0); + id->adap.owner = THIS_MODULE; id->adap.dev.of_node = pdev->dev.of_node; id->adap.algo = &cdns_i2c_algo; id->adap.timeout = CDNS_I2C_TIMEOUT; -- cgit v1.3-6-gb490 From 66621f96c95175cc64d91dd213781bf65bbf8ec4 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 17 Jul 2015 13:01:23 +0100 Subject: i2c: viperboard: clean up inconsistent indenting Minor clean up of indenting, no functional change Signed-off-by: Colin Ian King [wsa: squashed two lines into one] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-viperboard.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c index 47e88adf2011..543456a0a338 100644 --- a/drivers/i2c/busses/i2c-viperboard.c +++ b/drivers/i2c/busses/i2c-viperboard.c @@ -391,11 +391,11 @@ static int vprbrd_i2c_probe(struct platform_device *pdev) VPRBRD_USB_REQUEST_I2C_FREQ, VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, &vb_i2c->bus_freq_param, 1, VPRBRD_USB_TIMEOUT_MS); - if (ret != 1) { - dev_err(&pdev->dev, - "failure setting i2c_bus_freq to %d\n", i2c_bus_freq); - return -EIO; - } + if (ret != 1) { + dev_err(&pdev->dev, "failure setting i2c_bus_freq to %d\n", + i2c_bus_freq); + return -EIO; + } } else { dev_err(&pdev->dev, "invalid i2c_bus_freq setting:%d\n", i2c_bus_freq); -- cgit v1.3-6-gb490 From 64d0ed94f5dfde5efac15941128f60edf7f15c17 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Wed, 5 Aug 2015 15:45:30 -0700 Subject: HID: wacom: Do not repeatedly attempt to set device mode on error As an extension of aef3156d7, there is no sense in repeatedly calling the 'wacom_set_report' and 'wacom_get_report' functions if they return an error. Getting an error from them implies that the device is out to lunch: either a hard error code was returned or repeated attempts at recovering from a "soft" error all failed. In either case, doing even more retries is not likely to resolve whatever is wrong. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 20d15c5fccec..6edb7d136476 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -335,7 +335,7 @@ static int wacom_set_device_mode(struct hid_device *hdev, int report_id, if (error >= 0) error = wacom_get_report(hdev, HID_FEATURE_REPORT, rep_data, length, 1); - } while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES); + } while (error >= 0 && rep_data[1] != mode && limit++ < WAC_MSG_RETRIES); kfree(rep_data); -- cgit v1.3-6-gb490 From 0cc67945ea5933d53db69606312cf52f553d1b81 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Fri, 31 Jul 2015 11:48:05 +0100 Subject: mailbox: switch to hrtimer for tx_complete polling The mailbox core uses jiffy based timer to handle polling for the transmit completion. If the client/protocol have/support notification of the last packet transmit completion via ACK packet, then we tick the Tx state machine immediately in the callback. However if the client doesn't support that mechanism we might end-up waiting for atleast a jiffy even though the remote is ready to receive the next request. This patch switches the timer used for that polling from jiffy-based to hrtimer-based so that we can support polling at much higher time resolution. Reported-and-suggested-by: Juri Lelli Signed-off-by: Sudeep Holla Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox.c | 27 +++++++++++++++------------ include/linux/mailbox_controller.h | 7 ++++--- 2 files changed, 19 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index c7fdb57fd166..6a4811f85705 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -26,8 +26,6 @@ static LIST_HEAD(mbox_cons); static DEFINE_MUTEX(con_mutex); -static void poll_txdone(unsigned long data); - static int add_to_rbuf(struct mbox_chan *chan, void *mssg) { int idx; @@ -88,7 +86,9 @@ exit: spin_unlock_irqrestore(&chan->lock, flags); if (!err && (chan->txdone_method & TXDONE_BY_POLL)) - poll_txdone((unsigned long)chan->mbox); + /* kick start the timer immediately to avoid delays */ + hrtimer_start(&chan->mbox->poll_hrt, ktime_set(0, 0), + HRTIMER_MODE_REL); } static void tx_tick(struct mbox_chan *chan, int r) @@ -112,9 +112,10 @@ static void tx_tick(struct mbox_chan *chan, int r) complete(&chan->tx_complete); } -static void poll_txdone(unsigned long data) +static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer) { - struct mbox_controller *mbox = (struct mbox_controller *)data; + struct mbox_controller *mbox = + container_of(hrtimer, struct mbox_controller, poll_hrt); bool txdone, resched = false; int i; @@ -130,9 +131,11 @@ static void poll_txdone(unsigned long data) } } - if (resched) - mod_timer(&mbox->poll, jiffies + - msecs_to_jiffies(mbox->txpoll_period)); + if (resched) { + hrtimer_forward_now(hrtimer, ms_to_ktime(mbox->txpoll_period)); + return HRTIMER_RESTART; + } + return HRTIMER_NORESTART; } /** @@ -451,9 +454,9 @@ int mbox_controller_register(struct mbox_controller *mbox) txdone = TXDONE_BY_ACK; if (txdone == TXDONE_BY_POLL) { - mbox->poll.function = &poll_txdone; - mbox->poll.data = (unsigned long)mbox; - init_timer(&mbox->poll); + hrtimer_init(&mbox->poll_hrt, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + mbox->poll_hrt.function = txdone_hrtimer; } for (i = 0; i < mbox->num_chans; i++) { @@ -495,7 +498,7 @@ void mbox_controller_unregister(struct mbox_controller *mbox) mbox_free_channel(&mbox->chans[i]); if (mbox->txdone_poll) - del_timer_sync(&mbox->poll); + hrtimer_cancel(&mbox->poll_hrt); mutex_unlock(&con_mutex); } diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h index 68c42454439b..74deadb42d76 100644 --- a/include/linux/mailbox_controller.h +++ b/include/linux/mailbox_controller.h @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include @@ -67,7 +67,8 @@ struct mbox_chan_ops { * @txpoll_period: If 'txdone_poll' is in effect, the API polls for * last TX's status after these many millisecs * @of_xlate: Controller driver specific mapping of channel via DT - * @poll: API private. Used to poll for TXDONE on all channels. + * @poll_hrt: API private. hrtimer used to poll for TXDONE on all + * channels. * @node: API private. To hook into list of controllers. */ struct mbox_controller { @@ -81,7 +82,7 @@ struct mbox_controller { struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox, const struct of_phandle_args *sp); /* Internal to API */ - struct timer_list poll; + struct hrtimer poll_hrt; struct list_head node; }; -- cgit v1.3-6-gb490 From 86e488adaab77a733b01e759bf7bfda054479660 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 22 Jul 2015 13:28:51 +0100 Subject: mailbox: arm_mhu: reduce txpoll_period from 10ms to 1 ms Since the mailbox core users hrtimers now, it can handle much higher resolutions. We can reduce the txpoll_period to 1 ms as the transmit usually takes just few microseconds. Reported-and-suggested-by: Juri Lelli Signed-off-by: Sudeep Holla Signed-off-by: Jassi Brar --- drivers/mailbox/arm_mhu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c index d9e99f981aa9..438c2896ef22 100644 --- a/drivers/mailbox/arm_mhu.c +++ b/drivers/mailbox/arm_mhu.c @@ -148,7 +148,7 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id) mhu->mbox.ops = &mhu_ops; mhu->mbox.txdone_irq = false; mhu->mbox.txdone_poll = true; - mhu->mbox.txpoll_period = 10; + mhu->mbox.txpoll_period = 1; amba_set_drvdata(adev, mhu); -- cgit v1.3-6-gb490 From 02760b116c56376ad564e959f81835008848861d Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 17 Jun 2015 19:42:30 +0800 Subject: clockevents/drivers/Kconfig: Replace USE_OF with OF USE_OF is used as intermediate Kconfig option by few arch's (ARM, MIPS, Xtensa); in all these cases it implies setting option OF too. Replace the only instance of USE_OF in clocksource with OF. Signed-off-by: Antonio Borneo Signed-off-by: Daniel Lezcano --- drivers/clocksource/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4e57730e0be4..c03f04d82c6a 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -277,7 +277,7 @@ config CLKSRC_MIPS_GIC config CLKSRC_PXA def_bool y if ARCH_PXA || ARCH_SA1100 - select CLKSRC_OF if USE_OF + select CLKSRC_OF if OF help This enables OST0 support available on PXA and SA-11x0 platforms. -- cgit v1.3-6-gb490 From 479a932982944786269296a31682e5642f87b89a Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Sun, 21 Jun 2015 23:41:39 +0300 Subject: clockevents/drivers/exynos_mct: Remove unneeded container_of() Patch removes unneeded container_of() macro in exynos4_local_timer_setup(). Instead let's pass mevt pointer to setup and stop functions from exynos4_mct_cpu_notify() and let them get evt pointer. Tested on odroid-xu3. Signed-off-by: Alexey Klimov Acked-by: Stephen Boyd Signed-off-by: Daniel Lezcano Reviewed-by: Krzysztof Kozlowski --- drivers/clocksource/exynos_mct.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 9064ff743598..4d2330a92b27 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -442,13 +442,11 @@ static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int exynos4_local_timer_setup(struct clock_event_device *evt) +static int exynos4_local_timer_setup(struct mct_clock_event_device *mevt) { - struct mct_clock_event_device *mevt; + struct clock_event_device *evt = &mevt->evt; unsigned int cpu = smp_processor_id(); - mevt = container_of(evt, struct mct_clock_event_device, evt); - mevt->base = EXYNOS4_MCT_L_BASE(cpu); snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu); @@ -477,8 +475,10 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt) return 0; } -static void exynos4_local_timer_stop(struct clock_event_device *evt) +static void exynos4_local_timer_stop(struct mct_clock_event_device *mevt) { + struct clock_event_device *evt = &mevt->evt; + evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); if (mct_int_type == MCT_INT_SPI) { if (evt->irq != -1) @@ -500,11 +500,11 @@ static int exynos4_mct_cpu_notify(struct notifier_block *self, switch (action & ~CPU_TASKS_FROZEN) { case CPU_STARTING: mevt = this_cpu_ptr(&percpu_mct_tick); - exynos4_local_timer_setup(&mevt->evt); + exynos4_local_timer_setup(mevt); break; case CPU_DYING: mevt = this_cpu_ptr(&percpu_mct_tick); - exynos4_local_timer_stop(&mevt->evt); + exynos4_local_timer_stop(mevt); break; } @@ -570,7 +570,7 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem goto out_irq; /* Immediately configure the timer on the boot CPU */ - exynos4_local_timer_setup(&mevt->evt); + exynos4_local_timer_setup(mevt); return; out_irq: -- cgit v1.3-6-gb490 From 59252d187763ef3675fba1623be6996761fc2400 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Jun 2015 14:56:28 +0200 Subject: clockevents/drivers/sh_cmt: Remove obsolete sh-cmt-32-fast platform_device_id entry Since commit 59b89af1d5551c12 ("ARM: shmobile: sh7372: Remove Legacy C SoC code"), there are no more users left of the "sh-cmt-32-fast" platform device name. Hence remove the corresponding platform_device_id entry from the driver. Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano Acked-by: Simon Horman --- drivers/clocksource/sh_cmt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index b8ff3c64cc45..0aa6293f6317 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -929,7 +929,6 @@ static int sh_cmt_map_memory(struct sh_cmt_device *cmt) static const struct platform_device_id sh_cmt_id_table[] = { { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, - { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] }, { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] }, { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] }, { } -- cgit v1.3-6-gb490 From 0fae62eafec3c033d49160344228a4fa7d6303bc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Jun 2015 14:56:29 +0200 Subject: clockevents/drivers/sh_cmt: Remove obsolete sh-cmt-48-gen2 platform_device_id entry Since commit 914d7d148411997c ("ARM: shmobile: r8a73a4: Remove legacy code"), all former users of the "sh-cmt-48-gen2" platform device name are only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the corresponding platform_device_id entry. Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano Acked-by: Simon Horman --- drivers/clocksource/sh_cmt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 0aa6293f6317..d56d4e0e3fb3 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -930,7 +930,6 @@ static const struct platform_device_id sh_cmt_id_table[] = { { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] }, - { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] }, { } }; MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); -- cgit v1.3-6-gb490 From 3465f60917f2dbbc227e2a2e7913ad75bb604c12 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 30 Jun 2015 14:30:48 +0530 Subject: clockevents/drivers/asm9260: Migrate to new 'set-state' interface Migrate asm9260 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. As a default the timer was stopped when entering in the set_mode(RESUME) function, now this is done explicitly with the new API. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Oleksij Rempel Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/asm9260_timer.c | 64 ++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c index 4c2ba59897e8..217438d39eb3 100644 --- a/drivers/clocksource/asm9260_timer.c +++ b/drivers/clocksource/asm9260_timer.c @@ -120,38 +120,52 @@ static int asm9260_timer_set_next_event(unsigned long delta, return 0; } -static void asm9260_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static inline void __asm9260_timer_shutdown(struct clock_event_device *evt) { /* stop timer0 */ writel_relaxed(BM_C0_EN, priv.base + HW_TCR + CLR_REG); +} + +static int asm9260_timer_shutdown(struct clock_event_device *evt) +{ + __asm9260_timer_shutdown(evt); + return 0; +} + +static int asm9260_timer_set_oneshot(struct clock_event_device *evt) +{ + __asm9260_timer_shutdown(evt); + + /* enable reset and stop on match */ + writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0), + priv.base + HW_MCR + SET_REG); + return 0; +} + +static int asm9260_timer_set_periodic(struct clock_event_device *evt) +{ + __asm9260_timer_shutdown(evt); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* disable reset and stop on match */ - writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0), - priv.base + HW_MCR + CLR_REG); - /* configure match count for TC0 */ - writel_relaxed(priv.ticks_per_jiffy, priv.base + HW_MR0); - /* enable TC0 */ - writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* enable reset and stop on match */ - writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0), - priv.base + HW_MCR + SET_REG); - break; - default: - break; - } + /* disable reset and stop on match */ + writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0), + priv.base + HW_MCR + CLR_REG); + /* configure match count for TC0 */ + writel_relaxed(priv.ticks_per_jiffy, priv.base + HW_MR0); + /* enable TC0 */ + writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG); + return 0; } static struct clock_event_device event_dev = { - .name = DRIVER_NAME, - .rating = 200, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_next_event = asm9260_timer_set_next_event, - .set_mode = asm9260_timer_set_mode, + .name = DRIVER_NAME, + .rating = 200, + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = asm9260_timer_set_next_event, + .set_state_shutdown = asm9260_timer_shutdown, + .set_state_periodic = asm9260_timer_set_periodic, + .set_state_oneshot = asm9260_timer_set_oneshot, + .tick_resume = asm9260_timer_shutdown, }; static irqreturn_t asm9260_timer_interrupt(int irq, void *dev_id) -- cgit v1.3-6-gb490 From 5c0a4bbefc0571ba3addb39da0eb53368c018b64 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:16 +0530 Subject: clockevents/drivers/cadence_ttc: Migrate to new 'set-state' interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate cadence_ttc driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Michal Simek Cc: Sören Brinkmann Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Tested-by: Sören Brinkmann --- drivers/clocksource/cadence_ttc_timer.c | 59 ++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index 510c8a1d37b3..e47e0e0887eb 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -191,40 +191,42 @@ static int ttc_set_next_event(unsigned long cycles, } /** - * ttc_set_mode - Sets the mode of timer + * ttc_set_{shutdown|oneshot|periodic} - Sets the state of timer * - * @mode: Mode to be set * @evt: Address of clock event instance **/ -static void ttc_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int ttc_shutdown(struct clock_event_device *evt) { struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); struct ttc_timer *timer = &ttce->ttc; u32 ctrl_reg; - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - ttc_set_interval(timer, DIV_ROUND_CLOSEST(ttce->ttc.freq, - PRESCALE * HZ)); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - ctrl_reg = readl_relaxed(timer->base_addr + - TTC_CNT_CNTRL_OFFSET); - ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; - writel_relaxed(ctrl_reg, - timer->base_addr + TTC_CNT_CNTRL_OFFSET); - break; - case CLOCK_EVT_MODE_RESUME: - ctrl_reg = readl_relaxed(timer->base_addr + - TTC_CNT_CNTRL_OFFSET); - ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; - writel_relaxed(ctrl_reg, - timer->base_addr + TTC_CNT_CNTRL_OFFSET); - break; - } + ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET); + ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; + writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); + return 0; +} + +static int ttc_set_periodic(struct clock_event_device *evt) +{ + struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); + struct ttc_timer *timer = &ttce->ttc; + + ttc_set_interval(timer, + DIV_ROUND_CLOSEST(ttce->ttc.freq, PRESCALE * HZ)); + return 0; +} + +static int ttc_resume(struct clock_event_device *evt) +{ + struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); + struct ttc_timer *timer = &ttce->ttc; + u32 ctrl_reg; + + ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET); + ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; + writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); + return 0; } static int ttc_rate_change_clocksource_cb(struct notifier_block *nb, @@ -430,7 +432,10 @@ static void __init ttc_setup_clockevent(struct clk *clk, ttcce->ce.name = "ttc_clockevent"; ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; ttcce->ce.set_next_event = ttc_set_next_event; - ttcce->ce.set_mode = ttc_set_mode; + ttcce->ce.set_state_shutdown = ttc_shutdown; + ttcce->ce.set_state_periodic = ttc_set_periodic; + ttcce->ce.set_state_oneshot = ttc_shutdown; + ttcce->ce.tick_resume = ttc_resume; ttcce->ce.rating = 200; ttcce->ce.irq = irq; ttcce->ce.cpumask = cpu_possible_mask; -- cgit v1.3-6-gb490 From bd88420c589afc0c58542a5d1953637ef2fa64e4 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:17 +0530 Subject: clockevents/drivers/clps711x: Migrate to new 'set-state' interface Migrate clps711x driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Cc: Alexander Shiyan Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/clps711x-timer.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/clps711x-timer.c b/drivers/clocksource/clps711x-timer.c index d83ec1f2fddc..cdd86e3525bb 100644 --- a/drivers/clocksource/clps711x-timer.c +++ b/drivers/clocksource/clps711x-timer.c @@ -61,11 +61,6 @@ static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void clps711x_clockevent_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ -} - static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base, unsigned int irq) { @@ -91,7 +86,6 @@ static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base, clkevt->name = "clps711x-clockevent"; clkevt->rating = 300; clkevt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_C3STOP; - clkevt->set_mode = clps711x_clockevent_set_mode; clkevt->cpumask = cpumask_of(0); clockevents_config_and_register(clkevt, HZ, 0, 0); -- cgit v1.3-6-gb490 From 5c78b265454e6199754b61fa33ea3c1337e6aeab Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:18 +0530 Subject: clockevents/drivers/dummy_timer: Migrate to new 'set-state' interface Migrate dummy_timer driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Cc: Mark Rutland Signed-off-by: Viresh Kumae Signed-off-by: Daniel Lezcano --- drivers/clocksource/dummy_timer.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/dummy_timer.c b/drivers/clocksource/dummy_timer.c index 31990600fcff..776b6c86dcd5 100644 --- a/drivers/clocksource/dummy_timer.c +++ b/drivers/clocksource/dummy_timer.c @@ -16,15 +16,6 @@ static DEFINE_PER_CPU(struct clock_event_device, dummy_timer_evt); -static void dummy_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* - * Core clockevents code will call this when exchanging timer devices. - * We don't need to do anything here. - */ -} - static void dummy_timer_setup(void) { int cpu = smp_processor_id(); @@ -35,7 +26,6 @@ static void dummy_timer_setup(void) CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DUMMY; evt->rating = 100; - evt->set_mode = dummy_timer_set_mode; evt->cpumask = cpumask_of(cpu); clockevents_register_device(evt); -- cgit v1.3-6-gb490 From 226be92b3e6ec2412cd29520fa09fb41a2606cb6 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:19 +0530 Subject: clockevents/drivers/dw_apb: Migrate to new 'set-state' interface Migrate dw_apb driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Jacob Pan Cc: Jamie Iles Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/dw_apb_timer.c | 143 +++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c index 35a88097af3c..97ba7cbc2cbd 100644 --- a/drivers/clocksource/dw_apb_timer.c +++ b/drivers/clocksource/dw_apb_timer.c @@ -110,71 +110,87 @@ static void apbt_enable_int(struct dw_apb_timer *timer) apbt_writel(timer, ctrl, APBTMR_N_CONTROL); } -static void apbt_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int apbt_shutdown(struct clock_event_device *evt) { + struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); unsigned long ctrl; - unsigned long period; + + pr_debug("%s CPU %d state=shutdown\n", __func__, + cpumask_first(evt->cpumask)); + + ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + return 0; +} + +static int apbt_set_oneshot(struct clock_event_device *evt) +{ struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); + unsigned long ctrl; - pr_debug("%s CPU %d mode=%d\n", __func__, - cpumask_first(evt->cpumask), - mode); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - ctrl |= APBTMR_CONTROL_MODE_PERIODIC; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - /* - * DW APB p. 46, have to disable timer before load counter, - * may cause sync problem. - */ - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - udelay(1); - pr_debug("Setting clock period %lu for HZ %d\n", period, HZ); - apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT); - ctrl |= APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_ONESHOT: - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - /* - * set free running mode, this mode will let timer reload max - * timeout which will give time (3min on 25MHz clock) to rearm - * the next event, therefore emulate the one-shot mode. - */ - ctrl &= ~APBTMR_CONTROL_ENABLE; - ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; - - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - /* write again to set free running mode */ - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - - /* - * DW APB p. 46, load counter with all 1s before starting free - * running mode. - */ - apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT); - ctrl &= ~APBTMR_CONTROL_INT; - ctrl |= APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_RESUME: - apbt_enable_int(&dw_ced->timer); - break; - } + pr_debug("%s CPU %d state=oneshot\n", __func__, + cpumask_first(evt->cpumask)); + + ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); + /* + * set free running mode, this mode will let timer reload max + * timeout which will give time (3min on 25MHz clock) to rearm + * the next event, therefore emulate the one-shot mode. + */ + ctrl &= ~APBTMR_CONTROL_ENABLE; + ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; + + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + /* write again to set free running mode */ + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + + /* + * DW APB p. 46, load counter with all 1s before starting free + * running mode. + */ + apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT); + ctrl &= ~APBTMR_CONTROL_INT; + ctrl |= APBTMR_CONTROL_ENABLE; + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + return 0; +} + +static int apbt_set_periodic(struct clock_event_device *evt) +{ + struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); + unsigned long period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); + unsigned long ctrl; + + pr_debug("%s CPU %d state=periodic\n", __func__, + cpumask_first(evt->cpumask)); + + ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); + ctrl |= APBTMR_CONTROL_MODE_PERIODIC; + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + /* + * DW APB p. 46, have to disable timer before load counter, + * may cause sync problem. + */ + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + udelay(1); + pr_debug("Setting clock period %lu for HZ %d\n", period, HZ); + apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT); + ctrl |= APBTMR_CONTROL_ENABLE; + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + return 0; +} + +static int apbt_resume(struct clock_event_device *evt) +{ + struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); + + pr_debug("%s CPU %d state=resume\n", __func__, + cpumask_first(evt->cpumask)); + + apbt_enable_int(&dw_ced->timer); + return 0; } static int apbt_next_event(unsigned long delta, @@ -233,7 +249,10 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced); dw_ced->ced.cpumask = cpumask_of(cpu); dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - dw_ced->ced.set_mode = apbt_set_mode; + dw_ced->ced.set_state_shutdown = apbt_shutdown; + dw_ced->ced.set_state_periodic = apbt_set_periodic; + dw_ced->ced.set_state_oneshot = apbt_set_oneshot; + dw_ced->ced.tick_resume = apbt_resume; dw_ced->ced.set_next_event = apbt_next_event; dw_ced->ced.irq = dw_ced->timer.irq; dw_ced->ced.rating = rating; -- cgit v1.3-6-gb490 From 737663401897f84610d00552eeb83ffa4d730142 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:21 +0530 Subject: clockevents/drivers/fsl_ftm: Migrate to new 'set-state' interface Migrate fsl_ftm driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Xiubo Li Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/fsl_ftm_timer.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c index 454227d4f895..ef434699c80a 100644 --- a/drivers/clocksource/fsl_ftm_timer.c +++ b/drivers/clocksource/fsl_ftm_timer.c @@ -153,19 +153,16 @@ static int ftm_set_next_event(unsigned long delta, return 0; } -static void ftm_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int ftm_set_oneshot(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - ftm_set_next_event(priv->periodic_cyc, evt); - break; - case CLOCK_EVT_MODE_ONESHOT: - ftm_counter_disable(priv->clkevt_base); - break; - default: - return; - } + ftm_counter_disable(priv->clkevt_base); + return 0; +} + +static int ftm_set_periodic(struct clock_event_device *evt) +{ + ftm_set_next_event(priv->periodic_cyc, evt); + return 0; } static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id) @@ -174,7 +171,7 @@ static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id) ftm_irq_acknowledge(priv->clkevt_base); - if (likely(evt->mode == CLOCK_EVT_MODE_ONESHOT)) { + if (likely(clockevent_state_oneshot(evt))) { ftm_irq_disable(priv->clkevt_base); ftm_counter_disable(priv->clkevt_base); } @@ -185,11 +182,13 @@ static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id) } static struct clock_event_device ftm_clockevent = { - .name = "Freescale ftm timer", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = ftm_set_mode, - .set_next_event = ftm_set_next_event, - .rating = 300, + .name = "Freescale ftm timer", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_state_periodic = ftm_set_periodic, + .set_state_oneshot = ftm_set_oneshot, + .set_next_event = ftm_set_next_event, + .rating = 300, }; static struct irqaction ftm_timer_irq = { -- cgit v1.3-6-gb490 From 8eda41b0863ca82010010e951b7aa13b66a06e78 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:22 +0530 Subject: clockevents/drivers/i8253: Migrate to new 'set-state' interface Migrate i8253 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Russell King Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- arch/x86/kernel/i8253.c | 2 +- drivers/clocksource/i8253.c | 77 ++++++++++++++++++++++----------------------- 2 files changed, 39 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c index f2b96de3c7c1..efb82f07b29c 100644 --- a/arch/x86/kernel/i8253.c +++ b/arch/x86/kernel/i8253.c @@ -34,7 +34,7 @@ static int __init init_pit_clocksource(void) * - when local APIC timer is active (PIT is switched off) */ if (num_possible_cpus() > 1 || is_hpet_enabled() || - i8253_clockevent.mode != CLOCK_EVT_MODE_PERIODIC) + !clockevent_state_periodic(&i8253_clockevent)) return 0; return clocksource_i8253_init(); diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c index 14ee3efcc404..0efd36e483ab 100644 --- a/drivers/clocksource/i8253.c +++ b/drivers/clocksource/i8253.c @@ -100,44 +100,40 @@ int __init clocksource_i8253_init(void) #endif #ifdef CONFIG_CLKEVT_I8253 -/* - * Initialize the PIT timer. - * - * This is also called after resume to bring the PIT into operation again. - */ -static void init_pit_timer(enum clock_event_mode mode, - struct clock_event_device *evt) +static int pit_shutdown(struct clock_event_device *evt) { + if (!clockevent_state_oneshot(evt) && !clockevent_state_periodic(evt)) + return 0; + raw_spin_lock(&i8253_lock); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* binary, mode 2, LSB/MSB, ch 0 */ - outb_p(0x34, PIT_MODE); - outb_p(PIT_LATCH & 0xff , PIT_CH0); /* LSB */ - outb_p(PIT_LATCH >> 8 , PIT_CH0); /* MSB */ - break; - - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - if (evt->mode == CLOCK_EVT_MODE_PERIODIC || - evt->mode == CLOCK_EVT_MODE_ONESHOT) { - outb_p(0x30, PIT_MODE); - outb_p(0, PIT_CH0); - outb_p(0, PIT_CH0); - } - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* One shot setup */ - outb_p(0x38, PIT_MODE); - break; - - case CLOCK_EVT_MODE_RESUME: - /* Nothing to do here */ - break; - } + outb_p(0x30, PIT_MODE); + outb_p(0, PIT_CH0); + outb_p(0, PIT_CH0); + + raw_spin_unlock(&i8253_lock); + return 0; +} + +static int pit_set_oneshot(struct clock_event_device *evt) +{ + raw_spin_lock(&i8253_lock); + outb_p(0x38, PIT_MODE); + raw_spin_unlock(&i8253_lock); + return 0; +} + +static int pit_set_periodic(struct clock_event_device *evt) +{ + raw_spin_lock(&i8253_lock); + + /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(0x34, PIT_MODE); + outb_p(PIT_LATCH & 0xff, PIT_CH0); /* LSB */ + outb_p(PIT_LATCH >> 8, PIT_CH0); /* MSB */ + raw_spin_unlock(&i8253_lock); + return 0; } /* @@ -160,10 +156,11 @@ static int pit_next_event(unsigned long delta, struct clock_event_device *evt) * it can be solely used for the global tick. */ struct clock_event_device i8253_clockevent = { - .name = "pit", - .features = CLOCK_EVT_FEAT_PERIODIC, - .set_mode = init_pit_timer, - .set_next_event = pit_next_event, + .name = "pit", + .features = CLOCK_EVT_FEAT_PERIODIC, + .set_state_shutdown = pit_shutdown, + .set_state_periodic = pit_set_periodic, + .set_next_event = pit_next_event, }; /* @@ -172,8 +169,10 @@ struct clock_event_device i8253_clockevent = { */ void __init clockevent_i8253_init(bool oneshot) { - if (oneshot) + if (oneshot) { i8253_clockevent.features |= CLOCK_EVT_FEAT_ONESHOT; + i8253_clockevent.set_state_oneshot = pit_set_oneshot; + } /* * Start pit with the boot cpu mask. x86 might make it global * when it is used as broadcast device later. -- cgit v1.3-6-gb490 From 40117bd559d3119eb06206f5323680d712db7775 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:23 +0530 Subject: clockevents/drivers/meson6: Migrate to new 'set-state' interface Migrate meson6 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Carlo Caione Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Carlo Caione --- drivers/clocksource/meson6_timer.c | 50 ++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/meson6_timer.c b/drivers/clocksource/meson6_timer.c index 5c15cba41dca..1fa22c4d2d49 100644 --- a/drivers/clocksource/meson6_timer.c +++ b/drivers/clocksource/meson6_timer.c @@ -67,25 +67,25 @@ static void meson6_clkevt_time_start(unsigned char timer, bool periodic) writel(val | TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); } -static void meson6_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *clk) +static int meson6_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - meson6_clkevt_time_stop(CED_ID); - meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC/HZ - 1); - meson6_clkevt_time_start(CED_ID, true); - break; - case CLOCK_EVT_MODE_ONESHOT: - meson6_clkevt_time_stop(CED_ID); - meson6_clkevt_time_start(CED_ID, false); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - meson6_clkevt_time_stop(CED_ID); - break; - } + meson6_clkevt_time_stop(CED_ID); + return 0; +} + +static int meson6_set_oneshot(struct clock_event_device *evt) +{ + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_start(CED_ID, false); + return 0; +} + +static int meson6_set_periodic(struct clock_event_device *evt) +{ + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC / HZ - 1); + meson6_clkevt_time_start(CED_ID, true); + return 0; } static int meson6_clkevt_next_event(unsigned long evt, @@ -99,11 +99,15 @@ static int meson6_clkevt_next_event(unsigned long evt, } static struct clock_event_device meson6_clockevent = { - .name = "meson6_tick", - .rating = 400, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = meson6_clkevt_mode, - .set_next_event = meson6_clkevt_next_event, + .name = "meson6_tick", + .rating = 400, + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = meson6_shutdown, + .set_state_periodic = meson6_set_periodic, + .set_state_oneshot = meson6_set_oneshot, + .tick_resume = meson6_shutdown, + .set_next_event = meson6_clkevt_next_event, }; static irqreturn_t meson6_timer_interrupt(int irq, void *dev_id) -- cgit v1.3-6-gb490 From 3f583d01d796f7b9fda0203b134585ca06a242ad Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:24 +0530 Subject: clockevents/drivers/metag_generic: Migrate to new 'set-state' interface Migrate metag_generic driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. Even the WARN() for periodic or unused modes isn't required anymore as the core is taking care of that now. So, this patch doesn't provide any set-state callbacks. Cc: James Hogan Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/metag_generic.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/metag_generic.c b/drivers/clocksource/metag_generic.c index b7384b853e5a..bcd5c0d602a0 100644 --- a/drivers/clocksource/metag_generic.c +++ b/drivers/clocksource/metag_generic.c @@ -56,25 +56,6 @@ static int metag_timer_set_next_event(unsigned long delta, return 0; } -static void metag_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_RESUME: - break; - - case CLOCK_EVT_MODE_SHUTDOWN: - /* We should disable the IRQ here */ - break; - - case CLOCK_EVT_MODE_PERIODIC: - case CLOCK_EVT_MODE_UNUSED: - WARN_ON(1); - break; - }; -} - static cycle_t metag_clocksource_read(struct clocksource *cs) { return __core_reg_get(TXTIMER); @@ -129,7 +110,6 @@ static void arch_timer_setup(unsigned int cpu) clk->rating = 200, clk->shift = 12, clk->irq = tbisig_map(TBID_SIGNUM_TRT), - clk->set_mode = metag_timer_set_mode, clk->set_next_event = metag_timer_set_next_event, clk->mult = div_sc(hwtimer_freq, NSEC_PER_SEC, clk->shift); -- cgit v1.3-6-gb490 From d47409347e76ca5e7cdbbb515a9000878b5222cc Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:25 +0530 Subject: clockevents/drivers/mips-gic: Migrate to new 'set-state' interface Migrate mips-gic driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Cc: Andrew Bresticker Cc: Steven J. Hill Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/mips-gic-timer.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index b81ed1a5342d..c3810b61c815 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -33,12 +33,6 @@ static int gic_next_event(unsigned long delta, struct clock_event_device *evt) return res; } -static void gic_set_clock_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* Nothing to do ... */ -} - static irqreturn_t gic_compare_interrupt(int irq, void *dev_id) { struct clock_event_device *cd = dev_id; @@ -67,7 +61,6 @@ static void gic_clockevent_cpu_init(struct clock_event_device *cd) cd->irq = gic_timer_irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = gic_next_event; - cd->set_mode = gic_set_clock_mode; clockevents_config_and_register(cd, gic_frequency, 0x300, 0x7fffffff); -- cgit v1.3-6-gb490 From 37ae24716a584da33253cf6630a91c01b6656cc0 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:26 +0530 Subject: clockevents/drivers/moxart: Migrate to new 'set-state' interface Migrate moxart driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Jonas Jensen Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/moxart_timer.c | 49 ++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c index 5eb2c35932b1..19857af651c1 100644 --- a/drivers/clocksource/moxart_timer.c +++ b/drivers/clocksource/moxart_timer.c @@ -58,25 +58,24 @@ static void __iomem *base; static unsigned int clock_count_per_tick; -static void moxart_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *clk) +static int moxart_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_ONESHOT: - writel(TIMER1_DISABLE, base + TIMER_CR); - writel(~0, base + TIMER1_BASE + REG_LOAD); - break; - case CLOCK_EVT_MODE_PERIODIC: - writel(clock_count_per_tick, base + TIMER1_BASE + REG_LOAD); - writel(TIMER1_ENABLE, base + TIMER_CR); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - writel(TIMER1_DISABLE, base + TIMER_CR); - break; - } + writel(TIMER1_DISABLE, base + TIMER_CR); + return 0; +} + +static int moxart_set_oneshot(struct clock_event_device *evt) +{ + writel(TIMER1_DISABLE, base + TIMER_CR); + writel(~0, base + TIMER1_BASE + REG_LOAD); + return 0; +} + +static int moxart_set_periodic(struct clock_event_device *evt) +{ + writel(clock_count_per_tick, base + TIMER1_BASE + REG_LOAD); + writel(TIMER1_ENABLE, base + TIMER_CR); + return 0; } static int moxart_clkevt_next_event(unsigned long cycles, @@ -95,11 +94,15 @@ static int moxart_clkevt_next_event(unsigned long cycles, } static struct clock_event_device moxart_clockevent = { - .name = "moxart_timer", - .rating = 200, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = moxart_clkevt_mode, - .set_next_event = moxart_clkevt_next_event, + .name = "moxart_timer", + .rating = 200, + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = moxart_shutdown, + .set_state_periodic = moxart_set_periodic, + .set_state_oneshot = moxart_set_oneshot, + .tick_resume = moxart_set_oneshot, + .set_next_event = moxart_clkevt_next_event, }; static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id) -- cgit v1.3-6-gb490 From a2b7e10d29051a084b490c2911c3e1388b5f9677 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:27 +0530 Subject: clockevents/drivers/mtk: Migrate to new 'set-state' interface Migrate mtk driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Matthias Brugger Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/mtk_timer.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c index 68ab42356d0e..50f0641c65b6 100644 --- a/drivers/clocksource/mtk_timer.c +++ b/drivers/clocksource/mtk_timer.c @@ -102,27 +102,20 @@ static void mtk_clkevt_time_start(struct mtk_clock_event_device *evt, evt->gpt_base + TIMER_CTRL_REG(timer)); } -static void mtk_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *clk) +static int mtk_clkevt_shutdown(struct clock_event_device *clk) +{ + mtk_clkevt_time_stop(to_mtk_clk(clk), GPT_CLK_EVT); + return 0; +} + +static int mtk_clkevt_set_periodic(struct clock_event_device *clk) { struct mtk_clock_event_device *evt = to_mtk_clk(clk); mtk_clkevt_time_stop(evt, GPT_CLK_EVT); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - mtk_clkevt_time_setup(evt, evt->ticks_per_jiffy, GPT_CLK_EVT); - mtk_clkevt_time_start(evt, true, GPT_CLK_EVT); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Timer is enabled in set_next_event */ - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - /* No more interrupts will occur as source is disabled */ - break; - } + mtk_clkevt_time_setup(evt, evt->ticks_per_jiffy, GPT_CLK_EVT); + mtk_clkevt_time_start(evt, true, GPT_CLK_EVT); + return 0; } static int mtk_clkevt_next_event(unsigned long event, @@ -196,7 +189,10 @@ static void __init mtk_timer_init(struct device_node *node) evt->dev.name = "mtk_tick"; evt->dev.rating = 300; evt->dev.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - evt->dev.set_mode = mtk_clkevt_mode; + evt->dev.set_state_shutdown = mtk_clkevt_shutdown; + evt->dev.set_state_periodic = mtk_clkevt_set_periodic; + evt->dev.set_state_oneshot = mtk_clkevt_shutdown; + evt->dev.tick_resume = mtk_clkevt_shutdown; evt->dev.set_next_event = mtk_clkevt_next_event; evt->dev.cpumask = cpu_possible_mask; -- cgit v1.3-6-gb490 From eb8703e2ef7c311900174818e884bd49f64d4511 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:28 +0530 Subject: clockevents/drivers/mxs: Migrate to new 'set-state' interface Migrate mxs driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Also drop: - 'mxs_clockevent_mode': as we have helpers available from core for the same. same state twice and so perhaps the check wasn't required. - 'clock_event_mode_label': CLOCK_EVT_MODE_* shouldn't be used anymore by drivers and it was used just to print old-state:new-state. The debug prints are called from mxs_irq_clear() now based on the state-name passed to it. The printed name will be same for shutdown and resume states as they use the same callback pointer. Cc: Shawn Guo Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/mxs_timer.c | 80 +++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c index 445b68a01dc5..f5ce2961c0d6 100644 --- a/drivers/clocksource/mxs_timer.c +++ b/drivers/clocksource/mxs_timer.c @@ -77,7 +77,6 @@ #define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS 0xf static struct clock_event_device mxs_clockevent_device; -static enum clock_event_mode mxs_clockevent_mode = CLOCK_EVT_MODE_UNUSED; static void __iomem *mxs_timrot_base; static u32 timrot_major_version; @@ -141,64 +140,49 @@ static struct irqaction mxs_timer_irq = { .handler = mxs_timer_interrupt, }; -#ifdef DEBUG -static const char *clock_event_mode_label[] const = { - [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC", - [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT", - [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN", - [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED" -}; -#endif /* DEBUG */ - -static void mxs_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static void mxs_irq_clear(char *state) { /* Disable interrupt in timer module */ timrot_irq_disable(); - if (mode != mxs_clockevent_mode) { - /* Set event time into the furthest future */ - if (timrot_is_v1()) - __raw_writel(0xffff, - mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)); - else - __raw_writel(0xffffffff, - mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1)); - - /* Clear pending interrupt */ - timrot_irq_acknowledge(); - } + /* Set event time into the furthest future */ + if (timrot_is_v1()) + __raw_writel(0xffff, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)); + else + __raw_writel(0xffffffff, + mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1)); + + /* Clear pending interrupt */ + timrot_irq_acknowledge(); #ifdef DEBUG - pr_info("%s: changing mode from %s to %s\n", __func__, - clock_event_mode_label[mxs_clockevent_mode], - clock_event_mode_label[mode]); + pr_info("%s: changing mode to %s\n", __func__, state) #endif /* DEBUG */ +} - /* Remember timer mode */ - mxs_clockevent_mode = mode; - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - pr_err("%s: Periodic mode is not implemented\n", __func__); - break; - case CLOCK_EVT_MODE_ONESHOT: - timrot_irq_enable(); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - /* Left event sources disabled, no more interrupts appear */ - break; - } +static int mxs_shutdown(struct clock_event_device *evt) +{ + mxs_irq_clear("shutdown"); + + return 0; +} + +static int mxs_set_oneshot(struct clock_event_device *evt) +{ + if (clockevent_state_oneshot(evt)) + mxs_irq_clear("oneshot"); + timrot_irq_enable(); + return 0; } static struct clock_event_device mxs_clockevent_device = { - .name = "mxs_timrot", - .features = CLOCK_EVT_FEAT_ONESHOT, - .set_mode = mxs_set_mode, - .set_next_event = timrotv2_set_next_event, - .rating = 200, + .name = "mxs_timrot", + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = mxs_shutdown, + .set_state_oneshot = mxs_set_oneshot, + .tick_resume = mxs_shutdown, + .set_next_event = timrotv2_set_next_event, + .rating = 200, }; static int __init mxs_clockevent_init(struct clk *timer_clk) -- cgit v1.3-6-gb490 From 9b0af69947562858059b379794b6e94309f367ed Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:29 +0530 Subject: clockevents/drivers/nomadik-mtu: Migrate to new 'set-state' interface Migrate nomadik-mtu driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Linus Walleij Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Linus Walleij --- drivers/clocksource/nomadik-mtu.c | 58 ++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index a709cfa49d85..bc8dd443c727 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c @@ -119,28 +119,27 @@ static void nmdk_clkevt_reset(void) } } -static void nmdk_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *dev) +static int nmdk_clkevt_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - clkevt_periodic = true; - nmdk_clkevt_reset(); - break; - case CLOCK_EVT_MODE_ONESHOT: - clkevt_periodic = false; - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - writel(0, mtu_base + MTU_IMSC); - /* disable timer */ - writel(0, mtu_base + MTU_CR(1)); - /* load some high default value */ - writel(0xffffffff, mtu_base + MTU_LR(1)); - break; - case CLOCK_EVT_MODE_RESUME: - break; - } + writel(0, mtu_base + MTU_IMSC); + /* disable timer */ + writel(0, mtu_base + MTU_CR(1)); + /* load some high default value */ + writel(0xffffffff, mtu_base + MTU_LR(1)); + return 0; +} + +static int nmdk_clkevt_set_oneshot(struct clock_event_device *evt) +{ + clkevt_periodic = false; + return 0; +} + +static int nmdk_clkevt_set_periodic(struct clock_event_device *evt) +{ + clkevt_periodic = true; + nmdk_clkevt_reset(); + return 0; } static void nmdk_clksrc_reset(void) @@ -163,13 +162,16 @@ static void nmdk_clkevt_resume(struct clock_event_device *cedev) } static struct clock_event_device nmdk_clkevt = { - .name = "mtu_1", - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_DYNIRQ, - .rating = 200, - .set_mode = nmdk_clkevt_mode, - .set_next_event = nmdk_clkevt_next, - .resume = nmdk_clkevt_resume, + .name = "mtu_1", + .features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_DYNIRQ, + .rating = 200, + .set_state_shutdown = nmdk_clkevt_shutdown, + .set_state_periodic = nmdk_clkevt_set_periodic, + .set_state_oneshot = nmdk_clkevt_set_oneshot, + .set_next_event = nmdk_clkevt_next, + .resume = nmdk_clkevt_resume, }; /* -- cgit v1.3-6-gb490 From 47d490ea1529633f02209fcb4e89438995375a6f Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:30 +0530 Subject: clockevents/drivers/pxa: Migrate to new 'set-state' interface Migrate pxa driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Both oneshot and shutdown modes had exactly same code and so only a single callback is sufficient now, which will be called for both the modes. Cc: Robert Jarzmik Cc: Russell King Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Robert Jarzmik --- drivers/clocksource/pxa_timer.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c index d9438af2bbd6..45b6a4999713 100644 --- a/drivers/clocksource/pxa_timer.c +++ b/drivers/clocksource/pxa_timer.c @@ -88,26 +88,12 @@ pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev) return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; } -static void -pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) +static int pxa_osmr0_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); - timer_writel(OSSR_M0, OSSR); - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - /* initializing, released, or preparing for suspend */ - timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); - timer_writel(OSSR_M0, OSSR); - break; - - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_PERIODIC: - break; - } + /* initializing, released, or preparing for suspend */ + timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); + timer_writel(OSSR_M0, OSSR); + return 0; } #ifdef CONFIG_PM @@ -147,13 +133,14 @@ static void pxa_timer_resume(struct clock_event_device *cedev) #endif static struct clock_event_device ckevt_pxa_osmr0 = { - .name = "osmr0", - .features = CLOCK_EVT_FEAT_ONESHOT, - .rating = 200, - .set_next_event = pxa_osmr0_set_next_event, - .set_mode = pxa_osmr0_set_mode, - .suspend = pxa_timer_suspend, - .resume = pxa_timer_resume, + .name = "osmr0", + .features = CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_next_event = pxa_osmr0_set_next_event, + .set_state_shutdown = pxa_osmr0_shutdown, + .set_state_oneshot = pxa_osmr0_shutdown, + .suspend = pxa_timer_suspend, + .resume = pxa_timer_resume, }; static struct irqaction pxa_ost0_irq = { -- cgit v1.3-6-gb490 From 736b2df2abc1f128ce381e9f2e578502cabc2973 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:31 +0530 Subject: clockevents/drivers/qcom: Migrate to new 'set-state' interface Migrate qcom driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Periodic mode isn't supported by the driver and so the callback isn't provided anymore. Cc: Stephen Boyd Cc: Kumar Gala Cc: Andy Gross Cc: David Brown Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Stephen Boyd --- drivers/clocksource/qcom-timer.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c index cba2d015564c..f8e09f923651 100644 --- a/drivers/clocksource/qcom-timer.c +++ b/drivers/clocksource/qcom-timer.c @@ -47,7 +47,7 @@ static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = dev_id; /* Stop the timer tick */ - if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { + if (clockevent_state_oneshot(evt)) { u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); ctrl &= ~TIMER_ENABLE_EN; writel_relaxed(ctrl, event_base + TIMER_ENABLE); @@ -75,26 +75,14 @@ static int msm_timer_set_next_event(unsigned long cycles, return 0; } -static void msm_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int msm_timer_shutdown(struct clock_event_device *evt) { u32 ctrl; ctrl = readl_relaxed(event_base + TIMER_ENABLE); ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN); - - switch (mode) { - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_PERIODIC: - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Timer is enabled in set_next_event */ - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - break; - } writel_relaxed(ctrl, event_base + TIMER_ENABLE); + return 0; } static struct clock_event_device __percpu *msm_evt; @@ -126,7 +114,9 @@ static int msm_local_timer_setup(struct clock_event_device *evt) evt->name = "msm_timer"; evt->features = CLOCK_EVT_FEAT_ONESHOT; evt->rating = 200; - evt->set_mode = msm_timer_set_mode; + evt->set_state_shutdown = msm_timer_shutdown; + evt->set_state_oneshot = msm_timer_shutdown; + evt->tick_resume = msm_timer_shutdown; evt->set_next_event = msm_timer_set_next_event; evt->cpumask = cpumask_of(cpu); @@ -147,7 +137,7 @@ static int msm_local_timer_setup(struct clock_event_device *evt) static void msm_local_timer_stop(struct clock_event_device *evt) { - evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + evt->set_state_shutdown(evt); disable_percpu_irq(evt->irq); } -- cgit v1.3-6-gb490 From 99b3fa72efc545a7e21955c17f6a2f6f87dfacde Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:32 +0530 Subject: clockevents/drivers/rockchip: Migrate to new 'set-state' interface Migrate rockchip driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything for oneshot or resume modes, and so the callbacks aren't provided. Cc: Heiko Stuebner Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/rockchip_timer.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c index a35993bafb20..bb2c2b050964 100644 --- a/drivers/clocksource/rockchip_timer.c +++ b/drivers/clocksource/rockchip_timer.c @@ -82,23 +82,18 @@ static inline int rk_timer_set_next_event(unsigned long cycles, return 0; } -static inline void rk_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *ce) +static int rk_timer_shutdown(struct clock_event_device *ce) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - rk_timer_disable(ce); - rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce); - rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_RESUME: - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - rk_timer_disable(ce); - break; - } + rk_timer_disable(ce); + return 0; +} + +static int rk_timer_set_periodic(struct clock_event_device *ce) +{ + rk_timer_disable(ce); + rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce); + rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING); + return 0; } static irqreturn_t rk_timer_interrupt(int irq, void *dev_id) @@ -107,7 +102,7 @@ static irqreturn_t rk_timer_interrupt(int irq, void *dev_id) rk_timer_interrupt_clear(ce); - if (ce->mode == CLOCK_EVT_MODE_ONESHOT) + if (clockevent_state_oneshot(ce)) rk_timer_disable(ce); ce->event_handler(ce); @@ -161,7 +156,8 @@ static void __init rk_timer_init(struct device_node *np) ce->name = TIMER_NAME; ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; ce->set_next_event = rk_timer_set_next_event; - ce->set_mode = rk_timer_set_mode; + ce->set_state_shutdown = rk_timer_shutdown; + ce->set_state_periodic = rk_timer_set_periodic; ce->irq = irq; ce->cpumask = cpumask_of(0); ce->rating = 250; -- cgit v1.3-6-gb490 From b49b570474490bad8ee5289b103563d978f20a7e Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:33 +0530 Subject: clockevents/drivers/samsung_pwm: Migrate to new 'set-state' interface Migrate samsung_pwm driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Tomasz Figa Cc: Kukjin Kim Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/samsung_pwm_timer.c | 41 +++++++++++++++------------------ 1 file changed, 19 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 5645cfc90c41..bc90e13338cc 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -207,25 +207,18 @@ static int samsung_set_next_event(unsigned long cycles, return 0; } -static void samsung_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int samsung_shutdown(struct clock_event_device *evt) { samsung_time_stop(pwm.event_id); + return 0; +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1); - samsung_time_start(pwm.event_id, true); - break; - - case CLOCK_EVT_MODE_ONESHOT: - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - break; - } +static int samsung_set_periodic(struct clock_event_device *evt) +{ + samsung_time_stop(pwm.event_id); + samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1); + samsung_time_start(pwm.event_id, true); + return 0; } static void samsung_clockevent_resume(struct clock_event_device *cev) @@ -240,12 +233,16 @@ static void samsung_clockevent_resume(struct clock_event_device *cev) } static struct clock_event_device time_event_device = { - .name = "samsung_event_timer", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .rating = 200, - .set_next_event = samsung_set_next_event, - .set_mode = samsung_set_mode, - .resume = samsung_clockevent_resume, + .name = "samsung_event_timer", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_next_event = samsung_set_next_event, + .set_state_shutdown = samsung_shutdown, + .set_state_periodic = samsung_set_periodic, + .set_state_oneshot = samsung_shutdown, + .tick_resume = samsung_shutdown, + .resume = samsung_clockevent_resume, }; static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) -- cgit v1.3-6-gb490 From 051b782e2406af7f831602c70f887ca9b510b511 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:34 +0530 Subject: clockevents/drivers/sh_cmt: Migrate to new 'set-state' interface Migrate sh_cmt driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Magnus Damm Cc: Laurent Pinchart Cc: Paul Mundt Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Laurent Pinchart --- drivers/clocksource/sh_cmt.c | 62 ++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index d56d4e0e3fb3..e903026ae835 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -538,7 +538,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) if (ch->flags & FLAG_CLOCKEVENT) { if (!(ch->flags & FLAG_SKIPEVENT)) { - if (ch->ced.mode == CLOCK_EVT_MODE_ONESHOT) { + if (clockevent_state_oneshot(&ch->ced)) { ch->next_match_value = ch->max_match_value; ch->flags |= FLAG_REPROGRAM; } @@ -554,7 +554,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) sh_cmt_clock_event_program_verify(ch, 1); if (ch->flags & FLAG_CLOCKEVENT) - if ((ch->ced.mode == CLOCK_EVT_MODE_SHUTDOWN) + if ((clockevent_state_shutdown(&ch->ced)) || (ch->match_value == ch->next_match_value)) ch->flags &= ~FLAG_REPROGRAM; } @@ -720,39 +720,37 @@ static void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic) sh_cmt_set_next(ch, ch->max_match_value); } -static void sh_cmt_clock_event_mode(enum clock_event_mode mode, - struct clock_event_device *ced) +static int sh_cmt_clock_event_shutdown(struct clock_event_device *ced) +{ + struct sh_cmt_channel *ch = ced_to_sh_cmt(ced); + + sh_cmt_stop(ch, FLAG_CLOCKEVENT); + return 0; +} + +static int sh_cmt_clock_event_set_state(struct clock_event_device *ced, + int periodic) { struct sh_cmt_channel *ch = ced_to_sh_cmt(ced); /* deal with old setting first */ - switch (ced->mode) { - case CLOCK_EVT_MODE_PERIODIC: - case CLOCK_EVT_MODE_ONESHOT: + if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) sh_cmt_stop(ch, FLAG_CLOCKEVENT); - break; - default: - break; - } - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - dev_info(&ch->cmt->pdev->dev, - "ch%u: used for periodic clock events\n", ch->index); - sh_cmt_clock_event_start(ch, 1); - break; - case CLOCK_EVT_MODE_ONESHOT: - dev_info(&ch->cmt->pdev->dev, - "ch%u: used for oneshot clock events\n", ch->index); - sh_cmt_clock_event_start(ch, 0); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - sh_cmt_stop(ch, FLAG_CLOCKEVENT); - break; - default: - break; - } + dev_info(&ch->cmt->pdev->dev, "ch%u: used for %s clock events\n", + ch->index, periodic ? "periodic" : "oneshot"); + sh_cmt_clock_event_start(ch, periodic); + return 0; +} + +static int sh_cmt_clock_event_set_oneshot(struct clock_event_device *ced) +{ + return sh_cmt_clock_event_set_state(ced, 0); +} + +static int sh_cmt_clock_event_set_periodic(struct clock_event_device *ced) +{ + return sh_cmt_clock_event_set_state(ced, 1); } static int sh_cmt_clock_event_next(unsigned long delta, @@ -760,7 +758,7 @@ static int sh_cmt_clock_event_next(unsigned long delta, { struct sh_cmt_channel *ch = ced_to_sh_cmt(ced); - BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); + BUG_ON(!clockevent_state_oneshot(ced)); if (likely(ch->flags & FLAG_IRQCONTEXT)) ch->next_match_value = delta - 1; else @@ -814,7 +812,9 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch, ced->rating = 125; ced->cpumask = cpu_possible_mask; ced->set_next_event = sh_cmt_clock_event_next; - ced->set_mode = sh_cmt_clock_event_mode; + ced->set_state_shutdown = sh_cmt_clock_event_shutdown; + ced->set_state_periodic = sh_cmt_clock_event_set_periodic; + ced->set_state_oneshot = sh_cmt_clock_event_set_oneshot; ced->suspend = sh_cmt_clock_event_suspend; ced->resume = sh_cmt_clock_event_resume; -- cgit v1.3-6-gb490 From 19a9ffb3d6e9ed1d3a46aee18d0b7f8eff41c82b Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:35 +0530 Subject: clockevents/drivers/sh_mtu2: Migrate to new 'set-state' interface Migrate sh_mtu2 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Magnus Damm Cc: Laurent Pinchart Cc: Paul Mundt Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Laurent Pinchart --- drivers/clocksource/sh_mtu2.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 3d88698cf2b8..f1985da8113f 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -276,36 +276,25 @@ static struct sh_mtu2_channel *ced_to_sh_mtu2(struct clock_event_device *ced) return container_of(ced, struct sh_mtu2_channel, ced); } -static void sh_mtu2_clock_event_mode(enum clock_event_mode mode, - struct clock_event_device *ced) +static int sh_mtu2_clock_event_shutdown(struct clock_event_device *ced) { struct sh_mtu2_channel *ch = ced_to_sh_mtu2(ced); - int disabled = 0; - /* deal with old setting first */ - switch (ced->mode) { - case CLOCK_EVT_MODE_PERIODIC: + sh_mtu2_disable(ch); + return 0; +} + +static int sh_mtu2_clock_event_set_periodic(struct clock_event_device *ced) +{ + struct sh_mtu2_channel *ch = ced_to_sh_mtu2(ced); + + if (clockevent_state_periodic(ced)) sh_mtu2_disable(ch); - disabled = 1; - break; - default: - break; - } - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - dev_info(&ch->mtu->pdev->dev, - "ch%u: used for periodic clock events\n", ch->index); - sh_mtu2_enable(ch); - break; - case CLOCK_EVT_MODE_UNUSED: - if (!disabled) - sh_mtu2_disable(ch); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - default: - break; - } + dev_info(&ch->mtu->pdev->dev, "ch%u: used for periodic clock events\n", + ch->index); + sh_mtu2_enable(ch); + return 0; } static void sh_mtu2_clock_event_suspend(struct clock_event_device *ced) @@ -327,7 +316,8 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, ced->features = CLOCK_EVT_FEAT_PERIODIC; ced->rating = 200; ced->cpumask = cpu_possible_mask; - ced->set_mode = sh_mtu2_clock_event_mode; + ced->set_state_shutdown = sh_mtu2_clock_event_shutdown; + ced->set_state_periodic = sh_mtu2_clock_event_set_periodic; ced->suspend = sh_mtu2_clock_event_suspend; ced->resume = sh_mtu2_clock_event_resume; -- cgit v1.3-6-gb490 From 2bcc4da3d45c5c69e529f7f454191a749277ab1d Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:36 +0530 Subject: clockevents/drivers/sh_tmu: Migrate to new 'set-state' interface Migrate sh_tmu driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Magnus Damm Cc: Laurent Pinchart Cc: Paul Mundt Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Laurent Pinchart --- drivers/clocksource/sh_tmu.c | 63 +++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index b6b8fa3cd211..43c98143f79a 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -240,7 +240,7 @@ static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id) struct sh_tmu_channel *ch = dev_id; /* disable or acknowledge interrupt */ - if (ch->ced.mode == CLOCK_EVT_MODE_ONESHOT) + if (clockevent_state_oneshot(&ch->ced)) sh_tmu_write(ch, TCR, TCR_TPSC_CLK4); else sh_tmu_write(ch, TCR, TCR_UNIE | TCR_TPSC_CLK4); @@ -358,42 +358,37 @@ static void sh_tmu_clock_event_start(struct sh_tmu_channel *ch, int periodic) } } -static void sh_tmu_clock_event_mode(enum clock_event_mode mode, - struct clock_event_device *ced) +static int sh_tmu_clock_event_shutdown(struct clock_event_device *ced) +{ + struct sh_tmu_channel *ch = ced_to_sh_tmu(ced); + + sh_tmu_disable(ch); + return 0; +} + +static int sh_tmu_clock_event_set_state(struct clock_event_device *ced, + int periodic) { struct sh_tmu_channel *ch = ced_to_sh_tmu(ced); - int disabled = 0; /* deal with old setting first */ - switch (ced->mode) { - case CLOCK_EVT_MODE_PERIODIC: - case CLOCK_EVT_MODE_ONESHOT: + if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) sh_tmu_disable(ch); - disabled = 1; - break; - default: - break; - } - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - dev_info(&ch->tmu->pdev->dev, - "ch%u: used for periodic clock events\n", ch->index); - sh_tmu_clock_event_start(ch, 1); - break; - case CLOCK_EVT_MODE_ONESHOT: - dev_info(&ch->tmu->pdev->dev, - "ch%u: used for oneshot clock events\n", ch->index); - sh_tmu_clock_event_start(ch, 0); - break; - case CLOCK_EVT_MODE_UNUSED: - if (!disabled) - sh_tmu_disable(ch); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - default: - break; - } + dev_info(&ch->tmu->pdev->dev, "ch%u: used for %s clock events\n", + ch->index, periodic ? "periodic" : "oneshot"); + sh_tmu_clock_event_start(ch, periodic); + return 0; +} + +static int sh_tmu_clock_event_set_oneshot(struct clock_event_device *ced) +{ + return sh_tmu_clock_event_set_state(ced, 0); +} + +static int sh_tmu_clock_event_set_periodic(struct clock_event_device *ced) +{ + return sh_tmu_clock_event_set_state(ced, 1); } static int sh_tmu_clock_event_next(unsigned long delta, @@ -401,7 +396,7 @@ static int sh_tmu_clock_event_next(unsigned long delta, { struct sh_tmu_channel *ch = ced_to_sh_tmu(ced); - BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); + BUG_ON(!clockevent_state_oneshot(ced)); /* program new delta value */ sh_tmu_set_next(ch, delta, 0); @@ -430,7 +425,9 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch, ced->rating = 200; ced->cpumask = cpu_possible_mask; ced->set_next_event = sh_tmu_clock_event_next; - ced->set_mode = sh_tmu_clock_event_mode; + ced->set_state_shutdown = sh_tmu_clock_event_shutdown; + ced->set_state_periodic = sh_tmu_clock_event_set_periodic; + ced->set_state_oneshot = sh_tmu_clock_event_set_oneshot; ced->suspend = sh_tmu_clock_event_suspend; ced->resume = sh_tmu_clock_event_resume; -- cgit v1.3-6-gb490 From 6de6c977bdf61b1ca6f321aba468275c32952d79 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:37 +0530 Subject: clockevents/drivers/sun4i: Migrate to new 'set-state' interface Migrate sun4i driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Maxime Ripard Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Maxime Ripard --- drivers/clocksource/sun4i_timer.c | 41 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 1928a8912584..6f3719d73390 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -81,25 +81,25 @@ static void sun4i_clkevt_time_start(u8 timer, bool periodic) timer_base + TIMER_CTL_REG(timer)); } -static void sun4i_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *clk) +static int sun4i_clkevt_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - sun4i_clkevt_time_stop(0); - sun4i_clkevt_time_setup(0, ticks_per_jiffy); - sun4i_clkevt_time_start(0, true); - break; - case CLOCK_EVT_MODE_ONESHOT: - sun4i_clkevt_time_stop(0); - sun4i_clkevt_time_start(0, false); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - sun4i_clkevt_time_stop(0); - break; - } + sun4i_clkevt_time_stop(0); + return 0; +} + +static int sun4i_clkevt_set_oneshot(struct clock_event_device *evt) +{ + sun4i_clkevt_time_stop(0); + sun4i_clkevt_time_start(0, false); + return 0; +} + +static int sun4i_clkevt_set_periodic(struct clock_event_device *evt) +{ + sun4i_clkevt_time_stop(0); + sun4i_clkevt_time_setup(0, ticks_per_jiffy); + sun4i_clkevt_time_start(0, true); + return 0; } static int sun4i_clkevt_next_event(unsigned long evt, @@ -116,7 +116,10 @@ static struct clock_event_device sun4i_clockevent = { .name = "sun4i_tick", .rating = 350, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = sun4i_clkevt_mode, + .set_state_shutdown = sun4i_clkevt_shutdown, + .set_state_periodic = sun4i_clkevt_set_periodic, + .set_state_oneshot = sun4i_clkevt_set_oneshot, + .tick_resume = sun4i_clkevt_shutdown, .set_next_event = sun4i_clkevt_next_event, }; -- cgit v1.3-6-gb490 From 4134d29bfc4703d4000fc3a49ea4aeeae494d85a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 3 Jul 2015 14:24:35 +0530 Subject: clockevents/drivers/tegra20: Migrate to new 'set-state' interface Migrate tegra20 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Thierry Reding Cc: Stephen Warren Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/tegra20_timer.c | 45 ++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 5a112d72fc2d..6ebda1177e79 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -72,33 +72,36 @@ static int tegra_timer_set_next_event(unsigned long cycles, return 0; } -static void tegra_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static inline void timer_shutdown(struct clock_event_device *evt) { - u32 reg; - timer_writel(0, TIMER3_BASE + TIMER_PTV); +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - reg = 0xC0000000 | ((1000000/HZ)-1); - timer_writel(reg, TIMER3_BASE + TIMER_PTV); - break; - case CLOCK_EVT_MODE_ONESHOT: - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - break; - } +static int tegra_timer_shutdown(struct clock_event_device *evt) +{ + timer_shutdown(evt); + return 0; +} + +static int tegra_timer_set_periodic(struct clock_event_device *evt) +{ + u32 reg = 0xC0000000 | ((1000000 / HZ) - 1); + + timer_shutdown(evt); + timer_writel(reg, TIMER3_BASE + TIMER_PTV); + return 0; } static struct clock_event_device tegra_clockevent = { - .name = "timer0", - .rating = 300, - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .set_next_event = tegra_timer_set_next_event, - .set_mode = tegra_timer_set_mode, + .name = "timer0", + .rating = 300, + .features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC, + .set_next_event = tegra_timer_set_next_event, + .set_state_shutdown = tegra_timer_shutdown, + .set_state_periodic = tegra_timer_set_periodic, + .set_state_oneshot = tegra_timer_shutdown, + .tick_resume = tegra_timer_shutdown, }; static u64 notrace tegra_read_sched_clock(void) -- cgit v1.3-6-gb490 From d96f4412bcbd6698b6241146f01021dabdf052f3 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:40 +0530 Subject: clockevents/drivers/time-armada-370-xp: Migrate to new 'set-state' interface Migrate time-armada-370-xp driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Jason Cooper Cc: Andrew Lunn Cc: Gregory Clement Cc: Sebastian Hesselbarth Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/time-armada-370-xp.c | 53 +++++++++++++++++--------------- 1 file changed, 28 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 0c8c5e337540..2162796fd504 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -121,33 +121,33 @@ armada_370_xp_clkevt_next_event(unsigned long delta, return 0; } -static void -armada_370_xp_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *dev) +static int armada_370_xp_clkevt_shutdown(struct clock_event_device *evt) { - if (mode == CLOCK_EVT_MODE_PERIODIC) { + /* + * Disable timer. + */ + local_timer_ctrl_clrset(TIMER0_EN, 0); - /* - * Setup timer to fire at 1/HZ intervals. - */ - writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF); - writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF); + /* + * ACK pending timer interrupt. + */ + writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); + return 0; +} - /* - * Enable timer. - */ - local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask); - } else { - /* - * Disable timer. - */ - local_timer_ctrl_clrset(TIMER0_EN, 0); +static int armada_370_xp_clkevt_set_periodic(struct clock_event_device *evt) +{ + /* + * Setup timer to fire at 1/HZ intervals. + */ + writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF); + writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF); - /* - * ACK pending timer interrupt. - */ - writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); - } + /* + * Enable timer. + */ + local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask); + return 0; } static int armada_370_xp_clkevt_irq; @@ -185,7 +185,10 @@ static int armada_370_xp_timer_setup(struct clock_event_device *evt) evt->shift = 32, evt->rating = 300, evt->set_next_event = armada_370_xp_clkevt_next_event, - evt->set_mode = armada_370_xp_clkevt_mode, + evt->set_state_shutdown = armada_370_xp_clkevt_shutdown; + evt->set_state_periodic = armada_370_xp_clkevt_set_periodic; + evt->set_state_oneshot = armada_370_xp_clkevt_shutdown; + evt->tick_resume = armada_370_xp_clkevt_shutdown; evt->irq = armada_370_xp_clkevt_irq; evt->cpumask = cpumask_of(cpu); @@ -197,7 +200,7 @@ static int armada_370_xp_timer_setup(struct clock_event_device *evt) static void armada_370_xp_timer_stop(struct clock_event_device *evt) { - evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + evt->set_state_shutdown(evt); disable_percpu_irq(evt->irq); } -- cgit v1.3-6-gb490 From 20bf54f1172931df634d8f8cf05ba2c2d371dc10 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:41 +0530 Subject: clockevents/drivers/efm32: Migrate to new 'set-state' interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate efm32 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. There is nothing to be done for resume state and so isn't implemented. Cc: Uwe Kleine-König Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/time-efm32.c | 66 +++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/time-efm32.c b/drivers/clocksource/time-efm32.c index 5b6e3d5644c9..b06e4c2be406 100644 --- a/drivers/clocksource/time-efm32.c +++ b/drivers/clocksource/time-efm32.c @@ -48,40 +48,42 @@ struct efm32_clock_event_ddata { unsigned periodic_top; }; -static void efm32_clock_event_set_mode(enum clock_event_mode mode, - struct clock_event_device *evtdev) +static int efm32_clock_event_shutdown(struct clock_event_device *evtdev) { struct efm32_clock_event_ddata *ddata = container_of(evtdev, struct efm32_clock_event_ddata, evtdev); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); - writel_relaxed(ddata->periodic_top, ddata->base + TIMERn_TOP); - writel_relaxed(TIMERn_CTRL_PRESC_1024 | - TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | - TIMERn_CTRL_MODE_DOWN, - ddata->base + TIMERn_CTRL); - writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD); - break; - - case CLOCK_EVT_MODE_ONESHOT: - writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); - writel_relaxed(TIMERn_CTRL_PRESC_1024 | - TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | - TIMERn_CTRL_OSMEN | - TIMERn_CTRL_MODE_DOWN, - ddata->base + TIMERn_CTRL); - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); - break; - - case CLOCK_EVT_MODE_RESUME: - break; - } + writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); + return 0; +} + +static int efm32_clock_event_set_oneshot(struct clock_event_device *evtdev) +{ + struct efm32_clock_event_ddata *ddata = + container_of(evtdev, struct efm32_clock_event_ddata, evtdev); + + writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); + writel_relaxed(TIMERn_CTRL_PRESC_1024 | + TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | + TIMERn_CTRL_OSMEN | + TIMERn_CTRL_MODE_DOWN, + ddata->base + TIMERn_CTRL); + return 0; +} + +static int efm32_clock_event_set_periodic(struct clock_event_device *evtdev) +{ + struct efm32_clock_event_ddata *ddata = + container_of(evtdev, struct efm32_clock_event_ddata, evtdev); + + writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); + writel_relaxed(ddata->periodic_top, ddata->base + TIMERn_TOP); + writel_relaxed(TIMERn_CTRL_PRESC_1024 | + TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | + TIMERn_CTRL_MODE_DOWN, + ddata->base + TIMERn_CTRL); + writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD); + return 0; } static int efm32_clock_event_set_next_event(unsigned long evt, @@ -112,7 +114,9 @@ static struct efm32_clock_event_ddata clock_event_ddata = { .evtdev = { .name = "efm32 clockevent", .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .set_mode = efm32_clock_event_set_mode, + .set_state_shutdown = efm32_clock_event_shutdown, + .set_state_periodic = efm32_clock_event_set_periodic, + .set_state_oneshot = efm32_clock_event_set_oneshot, .set_next_event = efm32_clock_event_set_next_event, .rating = 200, }, -- cgit v1.3-6-gb490 From 5dd2482c8e7d8108e8d5d59a25f7b7a16d1ea64e Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:42 +0530 Subject: clockevents/drivers/orion: Migrate to new 'set-state' interface Migrate orion driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Jason Cooper Cc: Andrew Lunn Cc: Sebastian Hesselbarth Cc: Gregory Clement Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/time-orion.c | 46 +++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c index 0b3ce0399c51..0ece7427b497 100644 --- a/drivers/clocksource/time-orion.c +++ b/drivers/clocksource/time-orion.c @@ -60,30 +60,36 @@ static int orion_clkevt_next_event(unsigned long delta, return 0; } -static void orion_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *dev) +static int orion_clkevt_shutdown(struct clock_event_device *dev) { - if (mode == CLOCK_EVT_MODE_PERIODIC) { - /* setup and enable periodic timer at 1/HZ intervals */ - writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD); - writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL); - atomic_io_modify(timer_base + TIMER_CTRL, - TIMER1_RELOAD_EN | TIMER1_EN, - TIMER1_RELOAD_EN | TIMER1_EN); - } else { - /* disable timer */ - atomic_io_modify(timer_base + TIMER_CTRL, - TIMER1_RELOAD_EN | TIMER1_EN, 0); - } + /* disable timer */ + atomic_io_modify(timer_base + TIMER_CTRL, + TIMER1_RELOAD_EN | TIMER1_EN, 0); + return 0; +} + +static int orion_clkevt_set_periodic(struct clock_event_device *dev) +{ + /* setup and enable periodic timer at 1/HZ intervals */ + writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD); + writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL); + atomic_io_modify(timer_base + TIMER_CTRL, + TIMER1_RELOAD_EN | TIMER1_EN, + TIMER1_RELOAD_EN | TIMER1_EN); + return 0; } static struct clock_event_device orion_clkevt = { - .name = "orion_event", - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .shift = 32, - .rating = 300, - .set_next_event = orion_clkevt_next_event, - .set_mode = orion_clkevt_mode, + .name = "orion_event", + .features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC, + .shift = 32, + .rating = 300, + .set_next_event = orion_clkevt_next_event, + .set_state_shutdown = orion_clkevt_shutdown, + .set_state_periodic = orion_clkevt_set_periodic, + .set_state_oneshot = orion_clkevt_shutdown, + .tick_resume = orion_clkevt_shutdown, }; static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id) -- cgit v1.3-6-gb490 From 1e729d378e75063bf3fa91c62ea372fb73012b24 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:43 +0530 Subject: clockevents/drivers/atlas7: Migrate to new 'set-state' interface Migrate atlas7 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Barry Song Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-atlas7.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-atlas7.c b/drivers/clocksource/timer-atlas7.c index 60f9de3438b0..27fa13680be1 100644 --- a/drivers/clocksource/timer-atlas7.c +++ b/drivers/clocksource/timer-atlas7.c @@ -76,7 +76,7 @@ static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) /* clear timer interrupt */ writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); - if (ce->mode == CLOCK_EVT_MODE_ONESHOT) + if (clockevent_state_oneshot(ce)) sirfsoc_timer_count_disable(cpu); ce->event_handler(ce); @@ -117,18 +117,11 @@ static int sirfsoc_timer_set_next_event(unsigned long delta, return 0; } -static void sirfsoc_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *ce) +/* Oneshot is enabled in set_next_event */ +static int sirfsoc_timer_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - /* enable in set_next_event */ - break; - default: - break; - } - sirfsoc_timer_count_disable(smp_processor_id()); + return 0; } static void sirfsoc_clocksource_suspend(struct clocksource *cs) @@ -193,7 +186,9 @@ static int sirfsoc_local_timer_setup(struct clock_event_device *ce) ce->name = "local_timer"; ce->features = CLOCK_EVT_FEAT_ONESHOT; ce->rating = 200; - ce->set_mode = sirfsoc_timer_set_mode; + ce->set_state_shutdown = sirfsoc_timer_shutdown; + ce->set_state_oneshot = sirfsoc_timer_shutdown; + ce->tick_resume = sirfsoc_timer_shutdown; ce->set_next_event = sirfsoc_timer_set_next_event; clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60); ce->max_delta_ns = clockevent_delta2ns(-2, ce); -- cgit v1.3-6-gb490 From 85250fb89be3792c8a6793a594e30307c4e39214 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:44 +0530 Subject: clockevents/drivers/atmel: Migrate to new 'set-state' interface Migrate atmel driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: Jean-Christophe Plagniol-Villard Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Alexandre Belloni --- drivers/clocksource/timer-atmel-pit.c | 41 +++++++++++++++-------------------- 1 file changed, 18 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c index c0304ff608b0..58753223585b 100644 --- a/drivers/clocksource/timer-atmel-pit.c +++ b/drivers/clocksource/timer-atmel-pit.c @@ -90,33 +90,27 @@ static cycle_t read_pit_clk(struct clocksource *cs) return elapsed; } +static int pit_clkevt_shutdown(struct clock_event_device *dev) +{ + struct pit_data *data = clkevt_to_pit_data(dev); + + /* disable irq, leaving the clocksource active */ + pit_write(data->base, AT91_PIT_MR, (data->cycle - 1) | AT91_PIT_PITEN); + return 0; +} + /* * Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16) */ -static void -pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) +static int pit_clkevt_set_periodic(struct clock_event_device *dev) { struct pit_data *data = clkevt_to_pit_data(dev); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* update clocksource counter */ - data->cnt += data->cycle * PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR)); - pit_write(data->base, AT91_PIT_MR, - (data->cycle - 1) | AT91_PIT_PITEN | AT91_PIT_PITIEN); - break; - case CLOCK_EVT_MODE_ONESHOT: - BUG(); - /* FALLTHROUGH */ - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - /* disable irq, leaving the clocksource active */ - pit_write(data->base, AT91_PIT_MR, - (data->cycle - 1) | AT91_PIT_PITEN); - break; - case CLOCK_EVT_MODE_RESUME: - break; - } + /* update clocksource counter */ + data->cnt += data->cycle * PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR)); + pit_write(data->base, AT91_PIT_MR, + (data->cycle - 1) | AT91_PIT_PITEN | AT91_PIT_PITIEN); + return 0; } static void at91sam926x_pit_suspend(struct clock_event_device *cedev) @@ -162,7 +156,7 @@ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id) WARN_ON_ONCE(!irqs_disabled()); /* The PIT interrupt may be disabled, and is shared */ - if ((data->clkevt.mode == CLOCK_EVT_MODE_PERIODIC) && + if (clockevent_state_periodic(&data->clkevt) && (pit_read(data->base, AT91_PIT_SR) & AT91_PIT_PITS)) { unsigned nr_ticks; @@ -227,7 +221,8 @@ static void __init at91sam926x_pit_common_init(struct pit_data *data) data->clkevt.rating = 100; data->clkevt.cpumask = cpumask_of(0); - data->clkevt.set_mode = pit_clkevt_mode; + data->clkevt.set_state_shutdown = pit_clkevt_shutdown; + data->clkevt.set_state_periodic = pit_clkevt_set_periodic; data->clkevt.resume = at91sam926x_pit_resume; data->clkevt.suspend = at91sam926x_pit_suspend; clockevents_register_device(&data->clkevt); -- cgit v1.3-6-gb490 From 8ab282305f88c693275925330a0f93b16cab9c37 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:45 +0530 Subject: clockevents/drivers/atmel-st: Migrate to new 'set-state' interface Migrate atmel-st driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: Jean-Christophe Plagniol-Villard Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Alexandre Belloni Tested-by: Alexandre Belloni --- drivers/clocksource/timer-atmel-st.c | 69 ++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-atmel-st.c b/drivers/clocksource/timer-atmel-st.c index 1692e17e096b..41b7b6dc1d0d 100644 --- a/drivers/clocksource/timer-atmel-st.c +++ b/drivers/clocksource/timer-atmel-st.c @@ -106,36 +106,47 @@ static struct clocksource clk32k = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static void -clkevt32k_mode(enum clock_event_mode mode, struct clock_event_device *dev) +static void clkdev32k_disable_and_flush_irq(void) { unsigned int val; /* Disable and flush pending timer interrupts */ regmap_write(regmap_st, AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS); regmap_read(regmap_st, AT91_ST_SR, &val); - last_crtr = read_CRTR(); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* PIT for periodic irqs; fixed rate of 1/HZ */ - irqmask = AT91_ST_PITS; - regmap_write(regmap_st, AT91_ST_PIMR, RM9200_TIMER_LATCH); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* ALM for oneshot irqs, set by next_event() - * before 32 seconds have passed - */ - irqmask = AT91_ST_ALMS; - regmap_write(regmap_st, AT91_ST_RTAR, last_crtr); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - irqmask = 0; - break; - } +} + +static int clkevt32k_shutdown(struct clock_event_device *evt) +{ + clkdev32k_disable_and_flush_irq(); + irqmask = 0; + regmap_write(regmap_st, AT91_ST_IER, irqmask); + return 0; +} + +static int clkevt32k_set_oneshot(struct clock_event_device *dev) +{ + clkdev32k_disable_and_flush_irq(); + + /* + * ALM for oneshot irqs, set by next_event() + * before 32 seconds have passed. + */ + irqmask = AT91_ST_ALMS; + regmap_write(regmap_st, AT91_ST_RTAR, last_crtr); regmap_write(regmap_st, AT91_ST_IER, irqmask); + return 0; +} + +static int clkevt32k_set_periodic(struct clock_event_device *dev) +{ + clkdev32k_disable_and_flush_irq(); + + /* PIT for periodic irqs; fixed rate of 1/HZ */ + irqmask = AT91_ST_PITS; + regmap_write(regmap_st, AT91_ST_PIMR, RM9200_TIMER_LATCH); + regmap_write(regmap_st, AT91_ST_IER, irqmask); + return 0; } static int @@ -170,11 +181,15 @@ clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev) } static struct clock_event_device clkevt = { - .name = "at91_tick", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .rating = 150, - .set_next_event = clkevt32k_next_event, - .set_mode = clkevt32k_mode, + .name = "at91_tick", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .rating = 150, + .set_next_event = clkevt32k_next_event, + .set_state_shutdown = clkevt32k_shutdown, + .set_state_periodic = clkevt32k_set_periodic, + .set_state_oneshot = clkevt32k_set_oneshot, + .tick_resume = clkevt32k_shutdown, }; /* -- cgit v1.3-6-gb490 From e0d1ca332c1e91febd0de0ef69a45957cdc39fd8 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:46 +0530 Subject: clockevents/drivers/digicolor: Migrate to new 'set-state' interface Migrate digicolor driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Baruch Siach Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Baruch Siach Tested-by: Baruch Siach --- drivers/clocksource/timer-digicolor.c | 41 +++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c index 7f8388cfa810..e73947f0f86d 100644 --- a/drivers/clocksource/timer-digicolor.c +++ b/drivers/clocksource/timer-digicolor.c @@ -87,27 +87,27 @@ static inline void dc_timer_set_count(struct clock_event_device *ce, writel(count, dt->base + COUNT(dt->timer_id)); } -static void digicolor_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *ce) +static int digicolor_clkevt_shutdown(struct clock_event_device *ce) +{ + dc_timer_disable(ce); + return 0; +} + +static int digicolor_clkevt_set_oneshot(struct clock_event_device *ce) +{ + dc_timer_disable(ce); + dc_timer_enable(ce, CONTROL_MODE_ONESHOT); + return 0; +} + +static int digicolor_clkevt_set_periodic(struct clock_event_device *ce) { struct digicolor_timer *dt = dc_timer(ce); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - dc_timer_disable(ce); - dc_timer_set_count(ce, dt->ticks_per_jiffy); - dc_timer_enable(ce, CONTROL_MODE_PERIODIC); - break; - case CLOCK_EVT_MODE_ONESHOT: - dc_timer_disable(ce); - dc_timer_enable(ce, CONTROL_MODE_ONESHOT); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - dc_timer_disable(ce); - break; - } + dc_timer_disable(ce); + dc_timer_set_count(ce, dt->ticks_per_jiffy); + dc_timer_enable(ce, CONTROL_MODE_PERIODIC); + return 0; } static int digicolor_clkevt_next_event(unsigned long evt, @@ -125,7 +125,10 @@ static struct digicolor_timer dc_timer_dev = { .name = "digicolor_tick", .rating = 340, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = digicolor_clkevt_mode, + .set_state_shutdown = digicolor_clkevt_shutdown, + .set_state_periodic = digicolor_clkevt_set_periodic, + .set_state_oneshot = digicolor_clkevt_set_oneshot, + .tick_resume = digicolor_clkevt_shutdown, .set_next_event = digicolor_clkevt_next_event, }, .timer_id = TIMER_C, -- cgit v1.3-6-gb490 From f710bdeecffe9ce3ad8bdc358c6109d3848f6352 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:47 +0530 Subject: clockevents/drivers/integrator: Migrate to new 'set-state' interface Migrate integrator driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. For oneshot mode the clkevt device was first getting disabled by clearing TIMER_CTRL_ENABLE bits in TIMER_CTRL register, followed by clearing TIMER_CTRL_PERIODIC bit. Both these are done with a single write operation now. Cc: Linus Walleij Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Linus Walleij --- drivers/clocksource/timer-integrator-ap.c | 58 ++++++++++++++++++------------- 1 file changed, 33 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c index a68866e0ecd4..3f59ac2180dc 100644 --- a/drivers/clocksource/timer-integrator-ap.c +++ b/drivers/clocksource/timer-integrator-ap.c @@ -75,33 +75,37 @@ static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) +static int clkevt_shutdown(struct clock_event_device *evt) { u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; /* Disable timer */ writel(ctrl, clkevt_base + TIMER_CTRL); + return 0; +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* Enable the timer and start the periodic tick */ - writel(timer_reload, clkevt_base + TIMER_LOAD); - ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; - writel(ctrl, clkevt_base + TIMER_CTRL); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Leave the timer disabled, .set_next_event will enable it */ - ctrl &= ~TIMER_CTRL_PERIODIC; - writel(ctrl, clkevt_base + TIMER_CTRL); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - default: - /* Just leave in disabled state */ - break; - } +static int clkevt_set_oneshot(struct clock_event_device *evt) +{ + u32 ctrl = readl(clkevt_base + TIMER_CTRL) & + ~(TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC); + + /* Leave the timer disabled, .set_next_event will enable it */ + writel(ctrl, clkevt_base + TIMER_CTRL); + return 0; +} +static int clkevt_set_periodic(struct clock_event_device *evt) +{ + u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; + + /* Disable timer */ + writel(ctrl, clkevt_base + TIMER_CTRL); + + /* Enable the timer and start the periodic tick */ + writel(timer_reload, clkevt_base + TIMER_LOAD); + ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + writel(ctrl, clkevt_base + TIMER_CTRL); + return 0; } static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) @@ -116,11 +120,15 @@ static int clkevt_set_next_event(unsigned long next, struct clock_event_device * } static struct clock_event_device integrator_clockevent = { - .name = "timer1", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = clkevt_set_mode, - .set_next_event = clkevt_set_next_event, - .rating = 300, + .name = "timer1", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = clkevt_shutdown, + .set_state_periodic = clkevt_set_periodic, + .set_state_oneshot = clkevt_set_oneshot, + .tick_resume = clkevt_shutdown, + .set_next_event = clkevt_set_next_event, + .rating = 300, }; static struct irqaction integrator_timer_irq = { -- cgit v1.3-6-gb490 From 634eb0ec8c210ca3ea81b5b9493b4a39999bbf4a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:48 +0530 Subject: clockevents/drivers/keystone: Migrate to new 'set-state' interface Migrate keystone driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Also pass the mode-mask to keystone_timer_config() instead of the mode as mode macro's aren't valid anymore. Cc: Santosh Shilimkar Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-keystone.c | 44 +++++++++++++----------------------- 1 file changed, 16 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c index 0250354f7e55..edacf3902e10 100644 --- a/drivers/clocksource/timer-keystone.c +++ b/drivers/clocksource/timer-keystone.c @@ -72,10 +72,10 @@ static inline void keystone_timer_barrier(void) /** * keystone_timer_config: configures timer to work in oneshot/periodic modes. - * @ mode: mode to configure + * @ mask: mask of the mode to configure * @ period: cycles number to configure for */ -static int keystone_timer_config(u64 period, enum clock_event_mode mode) +static int keystone_timer_config(u64 period, int mask) { u32 tcr; u32 off; @@ -84,16 +84,7 @@ static int keystone_timer_config(u64 period, enum clock_event_mode mode) off = tcr & ~(TCR_ENAMODE_MASK); /* set enable mode */ - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - tcr |= TCR_ENAMODE_ONESHOT_MASK; - break; - case CLOCK_EVT_MODE_PERIODIC: - tcr |= TCR_ENAMODE_PERIODIC_MASK; - break; - default: - return -1; - } + tcr |= mask; /* disable timer */ keystone_timer_writel(off, TCR); @@ -138,24 +129,19 @@ static irqreturn_t keystone_timer_interrupt(int irq, void *dev_id) static int keystone_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - return keystone_timer_config(cycles, evt->mode); + return keystone_timer_config(cycles, TCR_ENAMODE_ONESHOT_MASK); } -static void keystone_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int keystone_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - keystone_timer_config(timer.hz_period, CLOCK_EVT_MODE_PERIODIC); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_ONESHOT: - keystone_timer_disable(); - break; - default: - break; - } + keystone_timer_disable(); + return 0; +} + +static int keystone_set_periodic(struct clock_event_device *evt) +{ + keystone_timer_config(timer.hz_period, TCR_ENAMODE_PERIODIC_MASK); + return 0; } static void __init keystone_timer_init(struct device_node *np) @@ -222,7 +208,9 @@ static void __init keystone_timer_init(struct device_node *np) /* setup clockevent */ event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; event_dev->set_next_event = keystone_set_next_event; - event_dev->set_mode = keystone_set_mode; + event_dev->set_state_shutdown = keystone_shutdown; + event_dev->set_state_periodic = keystone_set_periodic; + event_dev->set_state_oneshot = keystone_shutdown; event_dev->cpumask = cpu_all_mask; event_dev->owner = THIS_MODULE; event_dev->name = TIMER_NAME; -- cgit v1.3-6-gb490 From 53cba064443c1f36a55aa9dbc38f1d0d2aac96a4 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:49 +0530 Subject: clockevents/drivers/prima2: Migrate to new 'set-state' interface Migrate prima2 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Barry Song Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-prima2.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index ce18d570e1cd..78de982cc640 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -104,26 +104,21 @@ static int sirfsoc_timer_set_next_event(unsigned long delta, return next - now > delta ? -ETIME : 0; } -static void sirfsoc_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *ce) +static int sirfsoc_timer_shutdown(struct clock_event_device *evt) { u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - WARN_ON(1); - break; - case CLOCK_EVT_MODE_ONESHOT: - writel_relaxed(val | BIT(0), - sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - writel_relaxed(val & ~BIT(0), - sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - break; - } + + writel_relaxed(val & ~BIT(0), + sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + return 0; +} + +static int sirfsoc_timer_set_oneshot(struct clock_event_device *evt) +{ + u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + + writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + return 0; } static void sirfsoc_clocksource_suspend(struct clocksource *cs) @@ -157,7 +152,8 @@ static struct clock_event_device sirfsoc_clockevent = { .name = "sirfsoc_clockevent", .rating = 200, .features = CLOCK_EVT_FEAT_ONESHOT, - .set_mode = sirfsoc_timer_set_mode, + .set_state_shutdown = sirfsoc_timer_shutdown, + .set_state_oneshot = sirfsoc_timer_set_oneshot, .set_next_event = sirfsoc_timer_set_next_event, }; -- cgit v1.3-6-gb490 From 8e8af4cd3b4227d1bc64db0f0a4081095eb519b2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:50 +0530 Subject: clockevents/drivers/stm32: Migrate to new 'set-state' interface Migrate stm32 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Maxime Coquelin Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Tested-by: Maxime Coquelin Acked-by: Maxime Coquelin --- drivers/clocksource/timer-stm32.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c index a97e8b50701c..f3dcb76799b4 100644 --- a/drivers/clocksource/timer-stm32.c +++ b/drivers/clocksource/timer-stm32.c @@ -40,24 +40,25 @@ struct stm32_clock_event_ddata { void __iomem *base; }; -static void stm32_clock_event_set_mode(enum clock_event_mode mode, - struct clock_event_device *evtdev) +static int stm32_clock_event_shutdown(struct clock_event_device *evtdev) { struct stm32_clock_event_ddata *data = container_of(evtdev, struct stm32_clock_event_ddata, evtdev); void *base = data->base; - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - writel_relaxed(data->periodic_top, base + TIM_ARR); - writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1); - break; + writel_relaxed(0, base + TIM_CR1); + return 0; +} - case CLOCK_EVT_MODE_ONESHOT: - default: - writel_relaxed(0, base + TIM_CR1); - break; - } +static int stm32_clock_event_set_periodic(struct clock_event_device *evtdev) +{ + struct stm32_clock_event_ddata *data = + container_of(evtdev, struct stm32_clock_event_ddata, evtdev); + void *base = data->base; + + writel_relaxed(data->periodic_top, base + TIM_ARR); + writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1); + return 0; } static int stm32_clock_event_set_next_event(unsigned long evt, @@ -88,7 +89,10 @@ static struct stm32_clock_event_ddata clock_event_ddata = { .evtdev = { .name = "stm32 clockevent", .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .set_mode = stm32_clock_event_set_mode, + .set_state_shutdown = stm32_clock_event_shutdown, + .set_state_periodic = stm32_clock_event_set_periodic, + .set_state_oneshot = stm32_clock_event_shutdown, + .tick_resume = stm32_clock_event_shutdown, .set_next_event = stm32_clock_event_set_next_event, .rating = 200, }, -- cgit v1.3-6-gb490 From 7486f5ad27f6833397d55972878e7d73e84bede2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:51 +0530 Subject: clockevents/drivers/sun5i: Migrate to new 'set-state' interface Migrate sun5i driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Maxime Ripard Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Maxime Ripard --- drivers/clocksource/timer-sun5i.c | 45 ++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index 0ffb4ea7c925..bca9573e036a 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -103,27 +103,31 @@ static void sun5i_clkevt_time_start(struct sun5i_timer_clkevt *ce, u8 timer, boo ce->timer.base + TIMER_CTL_REG(timer)); } -static void sun5i_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *clkevt) +static int sun5i_clkevt_shutdown(struct clock_event_device *clkevt) { struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - sun5i_clkevt_time_stop(ce, 0); - sun5i_clkevt_time_setup(ce, 0, ce->timer.ticks_per_jiffy); - sun5i_clkevt_time_start(ce, 0, true); - break; - case CLOCK_EVT_MODE_ONESHOT: - sun5i_clkevt_time_stop(ce, 0); - sun5i_clkevt_time_start(ce, 0, false); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - sun5i_clkevt_time_stop(ce, 0); - break; - } + sun5i_clkevt_time_stop(ce, 0); + return 0; +} + +static int sun5i_clkevt_set_oneshot(struct clock_event_device *clkevt) +{ + struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt); + + sun5i_clkevt_time_stop(ce, 0); + sun5i_clkevt_time_start(ce, 0, false); + return 0; +} + +static int sun5i_clkevt_set_periodic(struct clock_event_device *clkevt) +{ + struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt); + + sun5i_clkevt_time_stop(ce, 0); + sun5i_clkevt_time_setup(ce, 0, ce->timer.ticks_per_jiffy); + sun5i_clkevt_time_start(ce, 0, true); + return 0; } static int sun5i_clkevt_next_event(unsigned long evt, @@ -286,7 +290,10 @@ static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem ce->clkevt.name = node->name; ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; ce->clkevt.set_next_event = sun5i_clkevt_next_event; - ce->clkevt.set_mode = sun5i_clkevt_mode; + ce->clkevt.set_state_shutdown = sun5i_clkevt_shutdown; + ce->clkevt.set_state_periodic = sun5i_clkevt_set_periodic; + ce->clkevt.set_state_oneshot = sun5i_clkevt_set_oneshot; + ce->clkevt.tick_resume = sun5i_clkevt_shutdown; ce->clkevt.rating = 340; ce->clkevt.irq = irq; ce->clkevt.cpumask = cpu_possible_mask; -- cgit v1.3-6-gb490 From 8ff8fc13bdd4f1474720669042fccfbf304638f1 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:52 +0530 Subject: clockevents/drivers/u300: Migrate to new 'set-state' interface Migrate u300 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Linus Walleij Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Linus Walleij --- drivers/clocksource/timer-u300.c | 155 +++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-u300.c b/drivers/clocksource/timer-u300.c index 5dcf756970e7..1744b243898a 100644 --- a/drivers/clocksource/timer-u300.c +++ b/drivers/clocksource/timer-u300.c @@ -187,85 +187,82 @@ struct u300_clockevent_data { unsigned ticks_per_jiffy; }; +static int u300_shutdown(struct clock_event_device *evt) +{ + /* Disable interrupts on GP1 */ + writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, + u300_timer_base + U300_TIMER_APP_GPT1IE); + /* Disable GP1 */ + writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, + u300_timer_base + U300_TIMER_APP_DGPT1); + return 0; +} + /* - * The u300_set_mode() function is always called first, if we - * have oneshot timer active, the oneshot scheduling function + * If we have oneshot timer active, the oneshot scheduling function * u300_set_next_event() is called immediately after. */ -static void u300_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int u300_set_oneshot(struct clock_event_device *evt) +{ + /* Just return; here? */ + /* + * The actual event will be programmed by the next event hook, + * so we just set a dummy value somewhere at the end of the + * universe here. + */ + /* Disable interrupts on GPT1 */ + writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, + u300_timer_base + U300_TIMER_APP_GPT1IE); + /* Disable GP1 while we're reprogramming it. */ + writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, + u300_timer_base + U300_TIMER_APP_DGPT1); + /* + * Expire far in the future, u300_set_next_event() will be + * called soon... + */ + writel(0xFFFFFFFF, u300_timer_base + U300_TIMER_APP_GPT1TC); + /* We run one shot per tick here! */ + writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT, + u300_timer_base + U300_TIMER_APP_SGPT1M); + /* Enable interrupts for this timer */ + writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, + u300_timer_base + U300_TIMER_APP_GPT1IE); + /* Enable timer */ + writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, + u300_timer_base + U300_TIMER_APP_EGPT1); + return 0; +} + +static int u300_set_periodic(struct clock_event_device *evt) { struct u300_clockevent_data *cevdata = container_of(evt, struct u300_clockevent_data, cevd); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* Disable interrupts on GPT1 */ - writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, - u300_timer_base + U300_TIMER_APP_GPT1IE); - /* Disable GP1 while we're reprogramming it. */ - writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, - u300_timer_base + U300_TIMER_APP_DGPT1); - /* - * Set the periodic mode to a certain number of ticks per - * jiffy. - */ - writel(cevdata->ticks_per_jiffy, - u300_timer_base + U300_TIMER_APP_GPT1TC); - /* - * Set continuous mode, so the timer keeps triggering - * interrupts. - */ - writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS, - u300_timer_base + U300_TIMER_APP_SGPT1M); - /* Enable timer interrupts */ - writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, - u300_timer_base + U300_TIMER_APP_GPT1IE); - /* Then enable the OS timer again */ - writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, - u300_timer_base + U300_TIMER_APP_EGPT1); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Just break; here? */ - /* - * The actual event will be programmed by the next event hook, - * so we just set a dummy value somewhere at the end of the - * universe here. - */ - /* Disable interrupts on GPT1 */ - writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, - u300_timer_base + U300_TIMER_APP_GPT1IE); - /* Disable GP1 while we're reprogramming it. */ - writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, - u300_timer_base + U300_TIMER_APP_DGPT1); - /* - * Expire far in the future, u300_set_next_event() will be - * called soon... - */ - writel(0xFFFFFFFF, u300_timer_base + U300_TIMER_APP_GPT1TC); - /* We run one shot per tick here! */ - writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT, - u300_timer_base + U300_TIMER_APP_SGPT1M); - /* Enable interrupts for this timer */ - writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, - u300_timer_base + U300_TIMER_APP_GPT1IE); - /* Enable timer */ - writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, - u300_timer_base + U300_TIMER_APP_EGPT1); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - /* Disable interrupts on GP1 */ - writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, - u300_timer_base + U300_TIMER_APP_GPT1IE); - /* Disable GP1 */ - writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, - u300_timer_base + U300_TIMER_APP_DGPT1); - break; - case CLOCK_EVT_MODE_RESUME: - /* Ignore this call */ - break; - } + /* Disable interrupts on GPT1 */ + writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, + u300_timer_base + U300_TIMER_APP_GPT1IE); + /* Disable GP1 while we're reprogramming it. */ + writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, + u300_timer_base + U300_TIMER_APP_DGPT1); + /* + * Set the periodic mode to a certain number of ticks per + * jiffy. + */ + writel(cevdata->ticks_per_jiffy, + u300_timer_base + U300_TIMER_APP_GPT1TC); + /* + * Set continuous mode, so the timer keeps triggering + * interrupts. + */ + writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS, + u300_timer_base + U300_TIMER_APP_SGPT1M); + /* Enable timer interrupts */ + writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, + u300_timer_base + U300_TIMER_APP_GPT1IE); + /* Then enable the OS timer again */ + writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, + u300_timer_base + U300_TIMER_APP_EGPT1); + return 0; } /* @@ -309,13 +306,15 @@ static int u300_set_next_event(unsigned long cycles, static struct u300_clockevent_data u300_clockevent_data = { /* Use general purpose timer 1 as clock event */ .cevd = { - .name = "GPT1", + .name = "GPT1", /* Reasonably fast and accurate clock event */ - .rating = 300, - .features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_ONESHOT, - .set_next_event = u300_set_next_event, - .set_mode = u300_set_mode, + .rating = 300, + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = u300_set_next_event, + .set_state_shutdown = u300_shutdown, + .set_state_periodic = u300_set_periodic, + .set_state_oneshot = u300_set_oneshot, }, }; -- cgit v1.3-6-gb490 From 9552a6af8c807ab547c053399b40bd05781fa0a8 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:53 +0530 Subject: clockevents/drivers/vf_pit: Migrate to new 'set-state' interface Migrate vf_pit driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Jingchang Lu Cc: Stefan Agner Cc: Shawn Guo Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Stefan Agner --- drivers/clocksource/vf_pit_timer.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c index b45ac6229b57..f07ba9932171 100644 --- a/drivers/clocksource/vf_pit_timer.c +++ b/drivers/clocksource/vf_pit_timer.c @@ -86,20 +86,16 @@ static int pit_set_next_event(unsigned long delta, return 0; } -static void pit_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int pit_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - pit_set_next_event(cycle_per_jiffy, evt); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - pit_timer_disable(); - break; - default: - break; - } + pit_timer_disable(); + return 0; +} + +static int pit_set_periodic(struct clock_event_device *evt) +{ + pit_set_next_event(cycle_per_jiffy, evt); + return 0; } static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) @@ -114,7 +110,7 @@ static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) * and start the counter again. So software need to disable the timer * to stop the counter loop in ONESHOT mode. */ - if (likely(evt->mode == CLOCK_EVT_MODE_ONESHOT)) + if (likely(clockevent_state_oneshot(evt))) pit_timer_disable(); evt->event_handler(evt); @@ -125,7 +121,8 @@ static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) static struct clock_event_device clockevent_pit = { .name = "VF pit timer", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = pit_set_mode, + .set_state_shutdown = pit_shutdown, + .set_state_periodic = pit_set_periodic, .set_next_event = pit_set_next_event, .rating = 300, }; -- cgit v1.3-6-gb490 From 214bc755b67029821106acc0b73abdc9b4ca6968 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:54 +0530 Subject: clockevents/drivers/vt8500: Migrate to new 'set-state' interface Migrate vt8500 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Tony Prisk Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/vt8500_timer.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index 1098ed3b9b89..a92e94b40b5b 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -88,29 +88,20 @@ static int vt8500_timer_set_next_event(unsigned long cycles, return 0; } -static void vt8500_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int vt8500_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_PERIODIC: - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - writel(readl(regbase + TIMER_CTRL_VAL) | 1, - regbase + TIMER_CTRL_VAL); - writel(0, regbase + TIMER_IER_VAL); - break; - } + writel(readl(regbase + TIMER_CTRL_VAL) | 1, regbase + TIMER_CTRL_VAL); + writel(0, regbase + TIMER_IER_VAL); + return 0; } static struct clock_event_device clockevent = { - .name = "vt8500_timer", - .features = CLOCK_EVT_FEAT_ONESHOT, - .rating = 200, - .set_next_event = vt8500_timer_set_next_event, - .set_mode = vt8500_timer_set_mode, + .name = "vt8500_timer", + .features = CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_next_event = vt8500_timer_set_next_event, + .set_state_shutdown = vt8500_shutdown, + .set_state_oneshot = vt8500_shutdown, }; static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id) -- cgit v1.3-6-gb490 From f0753793d33931bffbc7eee3289bf4d289728ef6 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:55 +0530 Subject: clockevents/drivers/zevio: Migrate to new 'set-state' interface Migrate zevio driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Daniel Tang Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/zevio-timer.c | 44 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/zevio-timer.c index 7ce442148c3f..ceaa6133f9c2 100644 --- a/drivers/clocksource/zevio-timer.c +++ b/drivers/clocksource/zevio-timer.c @@ -76,32 +76,28 @@ static int zevio_timer_set_event(unsigned long delta, return 0; } -static void zevio_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *dev) +static int zevio_timer_shutdown(struct clock_event_device *dev) { struct zevio_timer *timer = container_of(dev, struct zevio_timer, clkevt); - switch (mode) { - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_ONESHOT: - /* Enable timer interrupts */ - writel(TIMER_INTR_MSK, timer->interrupt_regs + IO_INTR_MSK); - writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - /* Disable timer interrupts */ - writel(0, timer->interrupt_regs + IO_INTR_MSK); - writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK); - /* Stop timer */ - writel(CNTL_STOP_TIMER, timer->timer1 + IO_CONTROL); - break; - case CLOCK_EVT_MODE_PERIODIC: - default: - /* Unsupported */ - break; - } + /* Disable timer interrupts */ + writel(0, timer->interrupt_regs + IO_INTR_MSK); + writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK); + /* Stop timer */ + writel(CNTL_STOP_TIMER, timer->timer1 + IO_CONTROL); + return 0; +} + +static int zevio_timer_set_oneshot(struct clock_event_device *dev) +{ + struct zevio_timer *timer = container_of(dev, struct zevio_timer, + clkevt); + + /* Enable timer interrupts */ + writel(TIMER_INTR_MSK, timer->interrupt_regs + IO_INTR_MSK); + writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK); + return 0; } static irqreturn_t zevio_timer_interrupt(int irq, void *dev_id) @@ -162,7 +158,9 @@ static int __init zevio_timer_add(struct device_node *node) if (timer->interrupt_regs && irqnr) { timer->clkevt.name = timer->clockevent_name; timer->clkevt.set_next_event = zevio_timer_set_event; - timer->clkevt.set_mode = zevio_timer_set_mode; + timer->clkevt.set_state_shutdown = zevio_timer_shutdown; + timer->clkevt.set_state_oneshot = zevio_timer_set_oneshot; + timer->clkevt.tick_resume = zevio_timer_set_oneshot; timer->clkevt.rating = 200; timer->clkevt.cpumask = cpu_all_mask; timer->clkevt.features = CLOCK_EVT_FEAT_ONESHOT; -- cgit v1.3-6-gb490 From cf4541c101ea497f68639cc94a2639a05cc3710f Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:38 +0530 Subject: clockevents/drivers/tcb_clksrc: Migrate to new 'set-state' interface Migrate tcb_clksrc driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Nicolas Ferre Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/tcb_clksrc.c | 93 ++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 8bdbc45c6dad..d28d2fe798d5 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -91,55 +91,62 @@ static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt) */ static u32 timer_clock; -static void tc_mode(enum clock_event_mode m, struct clock_event_device *d) +static int tc_shutdown(struct clock_event_device *d) { struct tc_clkevt_device *tcd = to_tc_clkevt(d); void __iomem *regs = tcd->regs; - if (tcd->clkevt.mode == CLOCK_EVT_MODE_PERIODIC - || tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) { - __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); - __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); - clk_disable(tcd->clk); - } + __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); + __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); + clk_disable(tcd->clk); - switch (m) { + return 0; +} - /* By not making the gentime core emulate periodic mode on top - * of oneshot, we get lower overhead and improved accuracy. - */ - case CLOCK_EVT_MODE_PERIODIC: - clk_enable(tcd->clk); +static int tc_set_oneshot(struct clock_event_device *d) +{ + struct tc_clkevt_device *tcd = to_tc_clkevt(d); + void __iomem *regs = tcd->regs; - /* slow clock, count up to RC, then irq and restart */ - __raw_writel(timer_clock - | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, - regs + ATMEL_TC_REG(2, CMR)); - __raw_writel((32768 + HZ/2) / HZ, tcaddr + ATMEL_TC_REG(2, RC)); + if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) + tc_shutdown(d); - /* Enable clock and interrupts on RC compare */ - __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); + clk_enable(tcd->clk); - /* go go gadget! */ - __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, - regs + ATMEL_TC_REG(2, CCR)); - break; + /* slow clock, count up to RC, then irq and stop */ + __raw_writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE | + ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR)); + __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); - case CLOCK_EVT_MODE_ONESHOT: - clk_enable(tcd->clk); + /* set_next_event() configures and starts the timer */ + return 0; +} - /* slow clock, count up to RC, then irq and stop */ - __raw_writel(timer_clock | ATMEL_TC_CPCSTOP - | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, - regs + ATMEL_TC_REG(2, CMR)); - __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); +static int tc_set_periodic(struct clock_event_device *d) +{ + struct tc_clkevt_device *tcd = to_tc_clkevt(d); + void __iomem *regs = tcd->regs; - /* set_next_event() configures and starts the timer */ - break; + if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) + tc_shutdown(d); - default: - break; - } + /* By not making the gentime core emulate periodic mode on top + * of oneshot, we get lower overhead and improved accuracy. + */ + clk_enable(tcd->clk); + + /* slow clock, count up to RC, then irq and restart */ + __raw_writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, + regs + ATMEL_TC_REG(2, CMR)); + __raw_writel((32768 + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC)); + + /* Enable clock and interrupts on RC compare */ + __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); + + /* go go gadget! */ + __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, regs + + ATMEL_TC_REG(2, CCR)); + return 0; } static int tc_next_event(unsigned long delta, struct clock_event_device *d) @@ -154,13 +161,15 @@ static int tc_next_event(unsigned long delta, struct clock_event_device *d) static struct tc_clkevt_device clkevt = { .clkevt = { - .name = "tc_clkevt", - .features = CLOCK_EVT_FEAT_PERIODIC - | CLOCK_EVT_FEAT_ONESHOT, + .name = "tc_clkevt", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, /* Should be lower than at91rm9200's system timer */ - .rating = 125, - .set_next_event = tc_next_event, - .set_mode = tc_mode, + .rating = 125, + .set_next_event = tc_next_event, + .set_state_shutdown = tc_shutdown, + .set_state_periodic = tc_set_periodic, + .set_state_oneshot = tc_set_oneshot, }, }; -- cgit v1.3-6-gb490 From 79e436d3a7d0510dfe6be3973efd78f6ccfe1492 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 18 Jun 2015 16:24:20 +0530 Subject: clockevents/drivers/exynos_mct: Migrate to new 'set-state' interface Migrate exynos_mct driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Kukjin Kim Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/exynos_mct.c | 85 +++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 4d2330a92b27..029f96ab131a 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -257,15 +257,14 @@ static void exynos4_mct_comp0_stop(void) exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB); } -static void exynos4_mct_comp0_start(enum clock_event_mode mode, - unsigned long cycles) +static void exynos4_mct_comp0_start(bool periodic, unsigned long cycles) { unsigned int tcon; cycle_t comp_cycle; tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON); - if (mode == CLOCK_EVT_MODE_PERIODIC) { + if (periodic) { tcon |= MCT_G_TCON_COMP0_AUTO_INC; exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR); } @@ -283,38 +282,38 @@ static void exynos4_mct_comp0_start(enum clock_event_mode mode, static int exynos4_comp_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - exynos4_mct_comp0_start(evt->mode, cycles); + exynos4_mct_comp0_start(false, cycles); return 0; } -static void exynos4_comp_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int mct_set_state_shutdown(struct clock_event_device *evt) { - unsigned long cycles_per_jiffy; exynos4_mct_comp0_stop(); + return 0; +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - cycles_per_jiffy = - (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift); - exynos4_mct_comp0_start(mode, cycles_per_jiffy); - break; +static int mct_set_state_periodic(struct clock_event_device *evt) +{ + unsigned long cycles_per_jiffy; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - break; - } + cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult) + >> evt->shift); + exynos4_mct_comp0_stop(); + exynos4_mct_comp0_start(true, cycles_per_jiffy); + return 0; } static struct clock_event_device mct_comp_device = { - .name = "mct-comp", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .rating = 250, - .set_next_event = exynos4_comp_set_next_event, - .set_mode = exynos4_comp_set_mode, + .name = "mct-comp", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .rating = 250, + .set_next_event = exynos4_comp_set_next_event, + .set_state_periodic = mct_set_state_periodic, + .set_state_shutdown = mct_set_state_shutdown, + .set_state_oneshot = mct_set_state_shutdown, + .tick_resume = mct_set_state_shutdown, }; static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id) @@ -390,39 +389,32 @@ static int exynos4_tick_set_next_event(unsigned long cycles, return 0; } -static inline void exynos4_tick_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int set_state_shutdown(struct clock_event_device *evt) +{ + exynos4_mct_tick_stop(this_cpu_ptr(&percpu_mct_tick)); + return 0; +} + +static int set_state_periodic(struct clock_event_device *evt) { struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); unsigned long cycles_per_jiffy; + cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult) + >> evt->shift); exynos4_mct_tick_stop(mevt); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - cycles_per_jiffy = - (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift); - exynos4_mct_tick_start(cycles_per_jiffy, mevt); - break; - - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - break; - } + exynos4_mct_tick_start(cycles_per_jiffy, mevt); + return 0; } static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) { - struct clock_event_device *evt = &mevt->evt; - /* * This is for supporting oneshot mode. * Mct would generate interrupt periodically * without explicit stopping. */ - if (evt->mode != CLOCK_EVT_MODE_PERIODIC) + if (!clockevent_state_periodic(&mevt->evt)) exynos4_mct_tick_stop(mevt); /* Clear the MCT tick interrupt */ @@ -453,7 +445,10 @@ static int exynos4_local_timer_setup(struct mct_clock_event_device *mevt) evt->name = mevt->name; evt->cpumask = cpumask_of(cpu); evt->set_next_event = exynos4_tick_set_next_event; - evt->set_mode = exynos4_tick_set_mode; + evt->set_state_periodic = set_state_periodic; + evt->set_state_shutdown = set_state_shutdown; + evt->set_state_oneshot = set_state_shutdown; + evt->tick_resume = set_state_shutdown; evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; evt->rating = 450; @@ -479,7 +474,7 @@ static void exynos4_local_timer_stop(struct mct_clock_event_device *mevt) { struct clock_event_device *evt = &mevt->evt; - evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + evt->set_state_shutdown(evt); if (mct_int_type == MCT_INT_SPI) { if (evt->irq != -1) disable_irq_nosync(evt->irq); -- cgit v1.3-6-gb490 From 8b5f0010fe0d666bb8dfc74b881f2401324a0e89 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Sat, 4 Jul 2015 13:06:43 +0800 Subject: clockevents/drivers/dw_apb_timer: Add dynamic irq flag to the timer Commit d2348fb6fdc6 ("tick: Dynamically set broadcast irq affinity") adds one excellent feature CLOCK_EVT_FEAT_DYNIRQ to let the core set the interrupt affinity of the broadcast interrupt to the cpu which has the earliest expiry time. This patch adds CLOCK_EVT_FEAT_DYNIRQ flag to avoid unnecessary wakeups and IPIs when the dw_apb_timer is used as broadcast timer. A simple test: ~ # rm /tmp/test.sh ~ # cat > /tmp/test.sh cat /proc/interrupts for i in `seq 10` ; do sleep $i; done cat /proc/interrupts ~ # chmod +x /tmp/test.sh ~ # taskset 0x2 /tmp/test.sh without the patch: CPU0 CPU1 27: 115 36 GIC 27 arch_timer 45: 62 0 GIC 45 mmc0 160: 88 0 interrupt-controller 8 timer 227: 0 0 interrupt-controller 4 f7e81400.i2c 228: 0 0 interrupt-controller 5 f7e81800.i2c 229: 0 0 interrupt-controller 7 dw_spi65535 230: 0 0 interrupt-controller 21 f7e84000.i2c 231: 0 0 interrupt-controller 20 f7e84800.i2c 265: 445 0 interrupt-controller 8 serial IPI0: 0 0 CPU wakeup interrupts IPI1: 0 11 Timer broadcast interrupts IPI2: 56 104 Rescheduling interrupts IPI3: 0 0 Function call interrupts IPI4: 0 4 Single function call interrupts IPI5: 0 0 CPU stop interrupts IPI6: 25 27 IRQ work interrupts IPI7: 0 0 completion interrupts IPI8: 0 0 CPU backtrace Err: 0 CPU0 CPU1 27: 115 38 GIC 27 arch_timer 45: 62 0 GIC 45 mmc0 160: 160 0 interrupt-controller 8 timer 227: 0 0 interrupt-controller 4 f7e81400.i2c 228: 0 0 interrupt-controller 5 f7e81800.i2c 229: 0 0 interrupt-controller 7 dw_spi65535 230: 0 0 interrupt-controller 21 f7e84000.i2c 231: 0 0 interrupt-controller 20 f7e84800.i2c 265: 514 0 interrupt-controller 8 serial IPI0: 0 0 CPU wakeup interrupts IPI1: 0 83 Timer broadcast interrupts IPI2: 56 104 Rescheduling interrupts IPI3: 0 0 Function call interrupts IPI4: 0 4 Single function call interrupts IPI5: 0 0 CPU stop interrupts IPI6: 25 46 IRQ work interrupts IPI7: 0 0 completion interrupts IPI8: 0 0 CPU backtrace Err: 0 cpu0 get 160-88=72 timer interrupts, CPU1 got 83-11=72 broadcast timer IPIs So, overall system got 72+72=144 wake ups and 72 broadcast timer IPIs With the patch: CPU0 CPU1 27: 107 37 GIC 27 arch_timer 45: 62 0 GIC 45 mmc0 160: 66 7 interrupt-controller 8 timer 227: 0 0 interrupt-controller 4 f7e81400.i2c 228: 0 0 interrupt-controller 5 f7e81800.i2c 229: 0 0 interrupt-controller 7 dw_spi65535 230: 0 0 interrupt-controller 21 f7e84000.i2c 231: 0 0 interrupt-controller 20 f7e84800.i2c 265: 311 0 interrupt-controller 8 serial IPI0: 0 0 CPU wakeup interrupts IPI1: 2 4 Timer broadcast interrupts IPI2: 58 100 Rescheduling interrupts IPI3: 0 0 Function call interrupts IPI4: 0 4 Single function call interrupts IPI5: 0 0 CPU stop interrupts IPI6: 21 24 IRQ work interrupts IPI7: 0 0 completion interrupts IPI8: 0 0 CPU backtrace Err: 0 CPU0 CPU1 27: 107 39 GIC 27 arch_timer 45: 62 0 GIC 45 mmc0 160: 69 75 interrupt-controller 8 timer 227: 0 0 interrupt-controller 4 f7e81400.i2c 228: 0 0 interrupt-controller 5 f7e81800.i2c 229: 0 0 interrupt-controller 7 dw_spi65535 230: 0 0 interrupt-controller 21 f7e84000.i2c 231: 0 0 interrupt-controller 20 f7e84800.i2c 265: 380 0 interrupt-controller 8 serial IPI0: 0 0 CPU wakeup interrupts IPI1: 3 6 Timer broadcast interrupts IPI2: 60 100 Rescheduling interrupts IPI3: 0 0 Function call interrupts IPI4: 0 4 Single function call interrupts IPI5: 0 0 CPU stop interrupts IPI6: 21 45 IRQ work interrupts IPI7: 0 0 completion interrupts IPI8: 0 0 CPU backtrace Err: 0 cpu0 got 69-66=3, cpu1 got 75-7=68 timer interrupts. cpu0 got 3-2=1 broadcast timer IPIs, cpu1 got 6-4=2 broadcast timer IPIs. So, overall system got 3+68+1+2=74 wakeups and 1+2=3 broadcast timer IPIs This patch removes 50% wakeups and almost 100% broadcast timer IPIs! Signed-off-by: Jisheng Zhang Signed-off-by: Daniel Lezcano --- drivers/clocksource/dw_apb_timer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c index 97ba7cbc2cbd..c76c75006ea6 100644 --- a/drivers/clocksource/dw_apb_timer.c +++ b/drivers/clocksource/dw_apb_timer.c @@ -248,7 +248,8 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, &dw_ced->ced); dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced); dw_ced->ced.cpumask = cpumask_of(cpu); - dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ; dw_ced->ced.set_state_shutdown = apbt_shutdown; dw_ced->ced.set_state_periodic = apbt_set_periodic; dw_ced->ced.set_state_oneshot = apbt_set_oneshot; -- cgit v1.3-6-gb490 From 8c436f84800c570ecde517dcd8709258bb34e498 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 14 Jul 2015 14:00:47 +0200 Subject: clockevents/drivers/sh_cmt: Remove obsolete sh-cmt-48 platform_device_id entry Since the removal of the r8a7740 legacy SoC code in commit 44d88c754e57a6d9 ("ARM: shmobile: Remove legacy SoC code for R-Mobile A1"), all former users of the "sh-cmt-48-gen2" platform device name are only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the corresponding platform_device_id entry. Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Lezcano Acked-by: Simon Horman --- drivers/clocksource/sh_cmt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index e903026ae835..33c33775d2a1 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -929,7 +929,6 @@ static int sh_cmt_map_memory(struct sh_cmt_device *cmt) static const struct platform_device_id sh_cmt_id_table[] = { { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, - { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] }, { } }; MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); -- cgit v1.3-6-gb490 From 26b91f043abda63dd240374f0eac05e7283a509c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 15:39:18 +0530 Subject: clockevents/drivers/timer-imx-gpt: Migrate to new 'set-state' interface Migrate timer-imx-gpt driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Also drop: - 'imx_timer.cem': It was caching the last state of the clockevent device. The same behavior can be achieved by using clockevents state helpers. These helpers are only required for oneshot mode as shutdown/resume wouldn't be done twice by the core. - 'clock_event_mode_label': CLOCK_EVT_MODE_* shouldn't be used anymore by drivers. The prints are modified to print the set-state functions name now to debug the driver. Cc: Shawn Guo Cc: Daniel Lezcano Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-imx-gpt.c | 75 +++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index 2d59038dec43..85111a763bc8 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -83,7 +83,6 @@ struct imx_timer { struct clk *clk_ipg; const struct imx_gpt_data *gpt; struct clock_event_device ced; - enum clock_event_mode cem; struct irqaction act; }; @@ -212,18 +211,38 @@ static int v2_set_next_event(unsigned long evt, -ETIME : 0; } +static int mxc_shutdown(struct clock_event_device *ced) +{ + struct imx_timer *imxtm = to_imx_timer(ced); + unsigned long flags; + u32 tcn; + + /* + * The timer interrupt generation is disabled at least + * for enough time to call mxc_set_next_event() + */ + local_irq_save(flags); + + /* Disable interrupt in GPT module */ + imxtm->gpt->gpt_irq_disable(imxtm); + + tcn = readl_relaxed(imxtm->base + imxtm->gpt->reg_tcn); + /* Set event time into far-far future */ + writel_relaxed(tcn - 3, imxtm->base + imxtm->gpt->reg_tcmp); + + /* Clear pending interrupt */ + imxtm->gpt->gpt_irq_acknowledge(imxtm); + #ifdef DEBUG -static const char *clock_event_mode_label[] = { - [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC", - [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT", - [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN", - [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED", - [CLOCK_EVT_MODE_RESUME] = "CLOCK_EVT_MODE_RESUME", -}; + printk(KERN_INFO "%s: changing mode\n", __func__); #endif /* DEBUG */ -static void mxc_set_mode(enum clock_event_mode mode, - struct clock_event_device *ced) + local_irq_restore(flags); + + return 0; +} + +static int mxc_set_oneshot(struct clock_event_device *ced) { struct imx_timer *imxtm = to_imx_timer(ced); unsigned long flags; @@ -237,7 +256,7 @@ static void mxc_set_mode(enum clock_event_mode mode, /* Disable interrupt in GPT module */ imxtm->gpt->gpt_irq_disable(imxtm); - if (mode != imxtm->cem) { + if (!clockevent_state_oneshot(ced)) { u32 tcn = readl_relaxed(imxtm->base + imxtm->gpt->reg_tcn); /* Set event time into far-far future */ writel_relaxed(tcn - 3, imxtm->base + imxtm->gpt->reg_tcmp); @@ -247,37 +266,19 @@ static void mxc_set_mode(enum clock_event_mode mode, } #ifdef DEBUG - printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n", - clock_event_mode_label[imxtm->cem], - clock_event_mode_label[mode]); + printk(KERN_INFO "%s: changing mode\n", __func__); #endif /* DEBUG */ - /* Remember timer mode */ - imxtm->cem = mode; - local_irq_restore(flags); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - printk(KERN_ERR"mxc_set_mode: Periodic mode is not " - "supported for i.MX\n"); - break; - case CLOCK_EVT_MODE_ONESHOT: /* * Do not put overhead of interrupt enable/disable into * mxc_set_next_event(), the core has about 4 minutes * to call mxc_set_next_event() or shutdown clock after * mode switching */ - local_irq_save(flags); - imxtm->gpt->gpt_irq_enable(imxtm); - local_irq_restore(flags); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - /* Left event sources disabled, no more interrupts appear */ - break; - } + imxtm->gpt->gpt_irq_enable(imxtm); + local_irq_restore(flags); + + return 0; } /* @@ -303,11 +304,11 @@ static int __init mxc_clockevent_init(struct imx_timer *imxtm) struct clock_event_device *ced = &imxtm->ced; struct irqaction *act = &imxtm->act; - imxtm->cem = CLOCK_EVT_MODE_UNUSED; - ced->name = "mxc_timer1"; ced->features = CLOCK_EVT_FEAT_ONESHOT; - ced->set_mode = mxc_set_mode; + ced->set_state_shutdown = mxc_shutdown; + ced->set_state_oneshot = mxc_set_oneshot; + ced->tick_resume = mxc_shutdown; ced->set_next_event = imxtm->gpt->set_next_event; ced->rating = 200; ced->cpumask = cpumask_of(0); -- cgit v1.3-6-gb490 From daea72831d3a18c561f028258ca5fb65ac3c8947 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 15:39:19 +0530 Subject: clockevents/drivers/timer-sp804: Migrate to new 'set-state' interface Migrate timer-sp driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. There are few more changes worth noticing: - The clockevent device was disabled by writing: 'TIMER_CTRL_32BIT | TIMER_CTRL_IE' to ctrl register earlier. i.e. by un-setting the TIMER_CTRL_ENABLE bit. Its done by writing zero now and should have the same effect. - For shutdown and resume we were writing the same value twice to the register (to disable the timer), which is fixed now. - Switching to oneshot mode was divided into two parts earlier: - Firstly set_mode() was writing: 'TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ONESHOT' to ctrl register (device not enabled yet) - Then sp804_set_next_event() was enabling the device by writing 'readl(ctrl) | TIMER_CTRL_ENABLE' to the ctrl register. This was unnecessarily complicated. - Change this to: Stop device on set_state_oneshot and configure it in sp804_set_next_event(). Cc: Daniel Lezcano Cc: Russell King Cc: Sudeep Holla Cc: Arnd Bergmann Cc: Catalin Marinas Cc: Olof Johansson Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-sp804.c | 54 +++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c index ca02503f17d1..5f45b9adef60 100644 --- a/drivers/clocksource/timer-sp804.c +++ b/drivers/clocksource/timer-sp804.c @@ -133,50 +133,50 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void sp804_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static inline void timer_shutdown(struct clock_event_device *evt) { - unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE; + writel(0, clkevt_base + TIMER_CTRL); +} - writel(ctrl, clkevt_base + TIMER_CTRL); +static int sp804_shutdown(struct clock_event_device *evt) +{ + timer_shutdown(evt); + return 0; +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - writel(clkevt_reload, clkevt_base + TIMER_LOAD); - ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* period set, and timer enabled in 'next_event' hook */ - ctrl |= TIMER_CTRL_ONESHOT; - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - break; - } +static int sp804_set_periodic(struct clock_event_device *evt) +{ + unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE | + TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + timer_shutdown(evt); + writel(clkevt_reload, clkevt_base + TIMER_LOAD); writel(ctrl, clkevt_base + TIMER_CTRL); + return 0; } static int sp804_set_next_event(unsigned long next, struct clock_event_device *evt) { - unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); + unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE | + TIMER_CTRL_ONESHOT | TIMER_CTRL_ENABLE; writel(next, clkevt_base + TIMER_LOAD); - writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + writel(ctrl, clkevt_base + TIMER_CTRL); return 0; } static struct clock_event_device sp804_clockevent = { - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_DYNIRQ, - .set_mode = sp804_set_mode, - .set_next_event = sp804_set_next_event, - .rating = 300, + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_DYNIRQ, + .set_state_shutdown = sp804_shutdown, + .set_state_periodic = sp804_set_periodic, + .set_state_oneshot = sp804_shutdown, + .tick_resume = sp804_shutdown, + .set_next_event = sp804_set_next_event, + .rating = 300, }; static struct irqaction sp804_timer_irq = { -- cgit v1.3-6-gb490 From 005e56272b28193540dcd1dab3dadb3da8375eaf Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Aug 2015 11:59:42 +0200 Subject: clockevents/drivers/timer-atmel-pit: Fix typo in structure initialization Reported-by: Peter Mamonov Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-atmel-pit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c index 58753223585b..d911c5dca8f1 100644 --- a/drivers/clocksource/timer-atmel-pit.c +++ b/drivers/clocksource/timer-atmel-pit.c @@ -202,8 +202,8 @@ static void __init at91sam926x_pit_common_init(struct pit_data *data) data->clksrc.mask = CLOCKSOURCE_MASK(bits); data->clksrc.name = "pit"; data->clksrc.rating = 175; - data->clksrc.read = read_pit_clk, - data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS, + data->clksrc.read = read_pit_clk; + data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS; clocksource_register_hz(&data->clksrc, pit_rate); /* Set up irq handler */ -- cgit v1.3-6-gb490 From 452b13248fe8499b2d9a487999d3610095aecca5 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 21 Jul 2015 08:01:14 +0530 Subject: clocksource/drivers/sh_tmu: Fix traceback spotted in -next Traceback in -next due to commit 'clockevents/drivers/sh_tmu: Migrate to new 'set-state' interface'. Commit ("clockevents/drivers/sh_tmu: Migrate to new 'set-state' interface") in -next causes the following traceback. This is seen with qemu runs for the sh target. ------------[ cut here ]------------ WARNING: at drivers/clocksource/sh_tmu.c:202 Modules linked in: CPU: 0 PID: 0 Comm: swapper Not tainted 4.2.0-rc3-next-20150720 #1 task: 8c411ed8 ti: 8c40e000 task.ti: 8c40e000 PC is at sh_tmu_disable+0x40/0x60 PR is at sh_tmu_clock_event_shutdown+0x8/0x20 PC : 8c271220 SP : 8c40ff10 SR : 400081f1 TEA : 00000000 R0 : 8c271240 R1 : 8fc08cfc R2 : 00000000 R3 : 3fffffff R4 : 8fc08c00 R5 : 00000001 R6 : 00000002 R7 : ffffffff R8 : 00000001 R9 : 8fc08c20 R10 : 00000000 R11 : 00000000 R12 : 8c012820 R13 : 00000000 R14 : 00000000 MACH: 3b9ac9ff MACL: 80000000 GBR : 00000000 PR : 8c271248 Call trace: [<8c065836>] clockevents_switch_state+0x16/0x60 [<8c06588c>] clockevents_shutdown+0xc/0x40 [<8c066330>] tick_check_new_device+0x90/0xc0 [<8c065556>] clockevents_register_device+0x56/0x120 [<8c0662a0>] tick_check_new_device+0x0/0xc0 [<8c27167a>] sh_tmu_probe+0x29a/0x4e0 [<8c18a994>] kasprintf+0x14/0x20 [<8c442782>] early_platform_driver_probe+0x20e/0x2bc [<8c1fade0>] platform_match+0x0/0x100 [<8c33babc>] printk+0x0/0x24 [<8c434892>] start_kernel+0x32e/0x574 [<8c33babc>] printk+0x0/0x24 [<8c17d320>] strlen+0x0/0x58 [<8c43430c>] unknown_bootoption+0x0/0x1e0 [<8c011024>] _stext+0x24/0x30 ---[ end trace cb88537fdc8fa200 ]--- Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano Tested-by: Geert Uytterhoeven --- drivers/clocksource/sh_tmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index 43c98143f79a..469e776ec17a 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -362,7 +362,8 @@ static int sh_tmu_clock_event_shutdown(struct clock_event_device *ced) { struct sh_tmu_channel *ch = ced_to_sh_tmu(ced); - sh_tmu_disable(ch); + if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) + sh_tmu_disable(ch); return 0; } -- cgit v1.3-6-gb490 From fc2b2f5df6d8dbf78c958a34628a3880150d6c9e Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 27 Jul 2015 15:02:00 +0530 Subject: clockevents/drivers/h8300_timer8: Migrate to new 'set-state' interface Migrate h8300_timer8 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Signed-off-by: Daniel Lezcano --- drivers/clocksource/h8300_timer8.c | 51 +++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c index 0214cb3a7f5e..f9b3b7033a97 100644 --- a/drivers/clocksource/h8300_timer8.c +++ b/drivers/clocksource/h8300_timer8.c @@ -81,7 +81,7 @@ static irqreturn_t timer8_interrupt(int irq, void *dev_id) p->flags |= FLAG_IRQCONTEXT; ctrl_outw(p->tcora, p->mapbase + TCORA); if (!(p->flags & FLAG_SKIPEVENT)) { - if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT) + if (clockevent_state_oneshot(&p->ced)) ctrl_outw(0x0000, p->mapbase + _8TCR); p->ced.event_handler(&p->ced); } @@ -169,29 +169,32 @@ static void timer8_clock_event_start(struct timer8_priv *p, int periodic) timer8_set_next(p, periodic?(p->rate + HZ/2) / HZ:0x10000); } -static void timer8_clock_event_mode(enum clock_event_mode mode, - struct clock_event_device *ced) +static int timer8_clock_event_shutdown(struct clock_event_device *ced) +{ + timer8_stop(ced_to_priv(ced)); + return 0; +} + +static int timer8_clock_event_periodic(struct clock_event_device *ced) { struct timer8_priv *p = ced_to_priv(ced); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - dev_info(&p->pdev->dev, "used for periodic clock events\n"); - timer8_stop(p); - timer8_clock_event_start(p, PERIODIC); - break; - case CLOCK_EVT_MODE_ONESHOT: - dev_info(&p->pdev->dev, "used for oneshot clock events\n"); - timer8_stop(p); - timer8_clock_event_start(p, ONESHOT); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - timer8_stop(p); - break; - default: - break; - } + dev_info(&p->pdev->dev, "used for periodic clock events\n"); + timer8_stop(p); + timer8_clock_event_start(p, PERIODIC); + + return 0; +} + +static int timer8_clock_event_oneshot(struct clock_event_device *ced) +{ + struct timer8_priv *p = ced_to_priv(ced); + + dev_info(&p->pdev->dev, "used for oneshot clock events\n"); + timer8_stop(p); + timer8_clock_event_start(p, ONESHOT); + + return 0; } static int timer8_clock_event_next(unsigned long delta, @@ -199,7 +202,7 @@ static int timer8_clock_event_next(unsigned long delta, { struct timer8_priv *p = ced_to_priv(ced); - BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); + BUG_ON(!clockevent_state_oneshot(ced)); timer8_set_next(p, delta - 1); return 0; @@ -246,7 +249,9 @@ static int timer8_setup(struct timer8_priv *p, p->ced.rating = 200; p->ced.cpumask = cpumask_of(0); p->ced.set_next_event = timer8_clock_event_next; - p->ced.set_mode = timer8_clock_event_mode; + p->ced.set_state_shutdown = timer8_clock_event_shutdown; + p->ced.set_state_periodic = timer8_clock_event_periodic; + p->ced.set_state_oneshot = timer8_clock_event_oneshot; ret = setup_irq(irq, &p->irqaction); if (ret < 0) { -- cgit v1.3-6-gb490 From 8d77a9404ec38be34ffc491a2022022a56e72c90 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:32:35 +0200 Subject: drm/gem: Be more friendly with locking checks BUG_ON kills the driver, WARN_ON is much friendlier. And usually nothing bad happens when the locking is slightly busted. v2: Fix typos in commit message Thierry spotted. Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 27a4228b4343..3c2d4abd71c5 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -766,7 +766,7 @@ drm_gem_object_free(struct kref *kref) struct drm_gem_object *obj = (struct drm_gem_object *) kref; struct drm_device *dev = obj->dev; - BUG_ON(!mutex_is_locked(&dev->struct_mutex)); + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); if (dev->driver->gem_free_object != NULL) dev->driver->gem_free_object(obj); -- cgit v1.3-6-gb490 From a66b2ea224c40cf341ca2096aad225536aa25956 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:32:36 +0200 Subject: drm/ast: Don't grab dev->struct_mutex for in mmap offset ioctl Since David Herrmann's mmap vma manager rework we don't need to grab dev->struct_mutex any more to prevent races when looking up the mmap offset. Drop it and instead don't forget to use the unref_unlocked variant (since the drm core still cares). Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/ast/ast_main.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 035dacc93382..838217f8ce7d 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -571,24 +571,18 @@ ast_dumb_mmap_offset(struct drm_file *file, uint64_t *offset) { struct drm_gem_object *obj; - int ret; struct ast_bo *bo; - mutex_lock(&dev->struct_mutex); obj = drm_gem_object_lookup(dev, file, handle); - if (obj == NULL) { - ret = -ENOENT; - goto out_unlock; - } + if (obj == NULL) + return -ENOENT; bo = gem_to_ast_bo(obj); *offset = ast_bo_mmap_offset(bo); - drm_gem_object_unreference(obj); - ret = 0; -out_unlock: - mutex_unlock(&dev->struct_mutex); - return ret; + drm_gem_object_unreference_unlocked(obj); + + return 0; } -- cgit v1.3-6-gb490 From 37ae75c8fdf5c48293e8a3c39ace8a68fbcca019 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:32:37 +0200 Subject: drm/bochs: Don't grab dev->struct_mutex for in mmap offset ioctl Since David Herrmann's mmap vma manager rework we don't need to grab dev->struct_mutex any more to prevent races when looking up the mmap offset. Drop it and instead don't forget to use the unref_unlocked variant (since the drm core still cares). Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/bochs/bochs_mm.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index 66286ff518d4..f69e6bf9bb0e 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -454,25 +454,17 @@ int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, uint32_t handle, uint64_t *offset) { struct drm_gem_object *obj; - int ret; struct bochs_bo *bo; - mutex_lock(&dev->struct_mutex); obj = drm_gem_object_lookup(dev, file, handle); - if (obj == NULL) { - ret = -ENOENT; - goto out_unlock; - } + if (obj == NULL) + return -ENOENT; bo = gem_to_bochs_bo(obj); *offset = bochs_bo_mmap_offset(bo); - drm_gem_object_unreference(obj); - ret = 0; -out_unlock: - mutex_unlock(&dev->struct_mutex); - return ret; - + drm_gem_object_unreference_unlocked(obj); + return 0; } /* ---------------------------------------------------------------------- */ -- cgit v1.3-6-gb490 From 34c294f5a6c0dca7fb75ddc1be3ec8974b24455f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:32:38 +0200 Subject: drm/mga200g: Don't grab dev->struct_mutex for in mmap offset ioctl Since David Herrmann's mmap vma manager rework we don't need to grab dev->struct_mutex any more to prevent races when looking up the mmap offset. Drop it and instead don't forget to use the unref_unlocked variant (since the drm core still cares). Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/mgag200/mgag200_main.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index f6b283b8375e..c99c2cb28939 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -345,23 +345,15 @@ mgag200_dumb_mmap_offset(struct drm_file *file, uint64_t *offset) { struct drm_gem_object *obj; - int ret; struct mgag200_bo *bo; - mutex_lock(&dev->struct_mutex); obj = drm_gem_object_lookup(dev, file, handle); - if (obj == NULL) { - ret = -ENOENT; - goto out_unlock; - } + if (obj == NULL) + return -ENOENT; bo = gem_to_mga_bo(obj); *offset = mgag200_bo_mmap_offset(bo); - drm_gem_object_unreference(obj); - ret = 0; -out_unlock: - mutex_unlock(&dev->struct_mutex); - return ret; - + drm_gem_object_unreference_unlocked(obj); + return 0; } -- cgit v1.3-6-gb490 From bf89209a6de37074e3ccdb7b40500798de750698 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:32:39 +0200 Subject: drm/mga200g: Hold a proper reference for cursor_set Looking up an obj, immediate dropping the acquired reference and then continuing to use it isn't how this is supposed to work. Fix this by holding a reference for the entire function. While at it stop grabbing dev->struct_mutex, it doesn't protect anything here. Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/mgag200/mgag200_cursor.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/mgag200/mgag200_cursor.c b/drivers/gpu/drm/mgag200/mgag200_cursor.c index 9f9780b7ddf0..4f2068fe5d88 100644 --- a/drivers/gpu/drm/mgag200/mgag200_cursor.c +++ b/drivers/gpu/drm/mgag200/mgag200_cursor.c @@ -70,18 +70,22 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc, BUG_ON(pixels_2 != pixels_current && pixels_2 != pixels_prev); BUG_ON(pixels_current == pixels_prev); + obj = drm_gem_object_lookup(dev, file_priv, handle); + if (!obj) + return -ENOENT; + ret = mgag200_bo_reserve(pixels_1, true); if (ret) { WREG8(MGA_CURPOSXL, 0); WREG8(MGA_CURPOSXH, 0); - return ret; + goto out_unref; } ret = mgag200_bo_reserve(pixels_2, true); if (ret) { WREG8(MGA_CURPOSXL, 0); WREG8(MGA_CURPOSXH, 0); mgag200_bo_unreserve(pixels_1); - return ret; + goto out_unreserve1; } if (!handle) { @@ -106,16 +110,6 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc, } } - mutex_lock(&dev->struct_mutex); - obj = drm_gem_object_lookup(dev, file_priv, handle); - if (!obj) { - mutex_unlock(&dev->struct_mutex); - ret = -ENOENT; - goto out1; - } - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); - bo = gem_to_mga_bo(obj); ret = mgag200_bo_reserve(bo, true); if (ret) { @@ -252,7 +246,11 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc, if (ret) mga_hide_cursor(mdev); mgag200_bo_unreserve(pixels_1); +out_unreserve1: mgag200_bo_unreserve(pixels_2); +out_unref: + drm_gem_object_unreference_unlocked(obj); + return ret; } -- cgit v1.3-6-gb490 From 6cc56234fe4d76a4c0cfefbf196a33718ba9db73 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:32:40 +0200 Subject: drm/cirrus: Don't grab dev->struct_mutex for in mmap offset ioctl Since David Herrmann's mmap vma manager rework we don't need to grab dev->struct_mutex any more to prevent races when looking up the mmap offset. Drop it and instead don't forget to use the unref_unlocked variant (since the drm core still cares). Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/cirrus/cirrus_main.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index e4b976658087..055fd86ba717 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -293,25 +293,18 @@ cirrus_dumb_mmap_offset(struct drm_file *file, uint64_t *offset) { struct drm_gem_object *obj; - int ret; struct cirrus_bo *bo; - mutex_lock(&dev->struct_mutex); obj = drm_gem_object_lookup(dev, file, handle); - if (obj == NULL) { - ret = -ENOENT; - goto out_unlock; - } + if (obj == NULL) + return -ENOENT; bo = gem_to_cirrus_bo(obj); *offset = cirrus_bo_mmap_offset(bo); - drm_gem_object_unreference(obj); - ret = 0; -out_unlock: - mutex_unlock(&dev->struct_mutex); - return ret; + drm_gem_object_unreference_unlocked(obj); + return 0; } bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height, -- cgit v1.3-6-gb490 From 141518b64f611536fb7968d291c794d71879099e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:32:41 +0200 Subject: drm/cma-helper: Don't grab dev->struct_mutex for in mmap offset ioctl Since David Herrmann's mmap vma manager rework we don't need to grab dev->struct_mutex any more to prevent races when looking up the mmap offset. Drop it and instead don't forget to use the unref_unlocked variant (since the drm core still cares). Cc: Laurent Pinchart Cc: Rob Clark Reviewed-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_gem_cma_helper.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index 9edad11dca98..86cc793cdf79 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -289,20 +289,15 @@ int drm_gem_cma_dumb_map_offset(struct drm_file *file_priv, { struct drm_gem_object *gem_obj; - mutex_lock(&drm->struct_mutex); - gem_obj = drm_gem_object_lookup(drm, file_priv, handle); if (!gem_obj) { dev_err(drm->dev, "failed to lookup GEM object\n"); - mutex_unlock(&drm->struct_mutex); return -EINVAL; } *offset = drm_vma_node_offset_addr(&gem_obj->vma_node); - drm_gem_object_unreference(gem_obj); - - mutex_unlock(&drm->struct_mutex); + drm_gem_object_unreference_unlocked(gem_obj); return 0; } -- cgit v1.3-6-gb490 From a1c173dac102d7d91e5cafdb8cb212300063eaa3 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Wed, 5 Aug 2015 15:45:30 -0700 Subject: HID: wacom: Do not repeatedly attempt to set device mode on error As an extension of aef3156d7, there is no sense in repeatedly calling the 'wacom_set_report' and 'wacom_get_report' functions if they return an error. Getting an error from them implies that the device is out to lunch: either a hard error code was returned or repeated attempts at recovering from a "soft" error all failed. In either case, doing even more retries is not likely to resolve whatever is wrong. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 936ad7770ec3..177e49b11e33 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -335,7 +335,7 @@ static int wacom_set_device_mode(struct hid_device *hdev, int report_id, if (error >= 0) error = wacom_get_report(hdev, HID_FEATURE_REPORT, rep_data, length, 1); - } while ((error < 0 || rep_data[1] != mode) && limit++ < WAC_MSG_RETRIES); + } while (error >= 0 && rep_data[1] != mode && limit++ < WAC_MSG_RETRIES); kfree(rep_data); -- cgit v1.3-6-gb490 From 92b7cb5dc885b38b21093eefed8028b615952965 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 3 Aug 2015 17:40:51 +0300 Subject: extcon: palmas: Support GPIO based USB ID detection Some palmas based chip variants do not have OTG based ID logic. For these variants we rely on GPIO based USB ID detection. These chips do have VBUS comparator for VBUS detection so we continue to use the old way of detecting VBUS. Signed-off-by: Roger Quadros Acked-by: Chanwoo Choi Acked-by: Lee Jones Signed-off-by: Chanwoo Choi --- .../devicetree/bindings/extcon/extcon-palmas.txt | 5 +- drivers/extcon/extcon-palmas.c | 129 ++++++++++++++++++--- drivers/extcon/extcon-usb-gpio.c | 1 + include/linux/mfd/palmas.h | 7 ++ 4 files changed, 126 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/extcon/extcon-palmas.txt b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt index 45414bbcd945..f61d5af44a27 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-palmas.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt @@ -10,8 +10,11 @@ Required Properties: Optional Properties: - ti,wakeup : To enable the wakeup comparator in probe - - ti,enable-id-detection: Perform ID detection. + - ti,enable-id-detection: Perform ID detection. If id-gpio is specified + it performs id-detection using GPIO else using OTG core. - ti,enable-vbus-detection: Perform VBUS detection. + - id-gpio: gpio for GPIO ID detection. See gpio binding. + - debounce-delay-ms: debounce delay for GPIO ID pin in milliseconds. palmas-usb { compatible = "ti,twl6035-usb", "ti,palmas-usb"; diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c index 8933e7e0d9da..662e91778cb0 100644 --- a/drivers/extcon/extcon-palmas.c +++ b/drivers/extcon/extcon-palmas.c @@ -28,6 +28,10 @@ #include #include #include +#include +#include + +#define USB_GPIO_DEBOUNCE_MS 20 /* ms */ static const unsigned int palmas_extcon_cable[] = { EXTCON_USB, @@ -118,19 +122,54 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb) return IRQ_HANDLED; } +static void palmas_gpio_id_detect(struct work_struct *work) +{ + int id; + struct palmas_usb *palmas_usb = container_of(to_delayed_work(work), + struct palmas_usb, + wq_detectid); + struct extcon_dev *edev = palmas_usb->edev; + + if (!palmas_usb->id_gpiod) + return; + + id = gpiod_get_value_cansleep(palmas_usb->id_gpiod); + + if (id) { + extcon_set_cable_state_(edev, EXTCON_USB_HOST, false); + dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); + } else { + extcon_set_cable_state_(edev, EXTCON_USB_HOST, true); + dev_info(palmas_usb->dev, "USB-HOST cable is attached\n"); + } +} + +static irqreturn_t palmas_gpio_id_irq_handler(int irq, void *_palmas_usb) +{ + struct palmas_usb *palmas_usb = _palmas_usb; + + queue_delayed_work(system_power_efficient_wq, &palmas_usb->wq_detectid, + palmas_usb->sw_debounce_jiffies); + + return IRQ_HANDLED; +} + static void palmas_enable_irq(struct palmas_usb *palmas_usb) { palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_VBUS_CTRL_SET, PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP); - palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, - PALMAS_USB_ID_CTRL_SET, PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP); + if (palmas_usb->enable_id_detection) { + palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, + PALMAS_USB_ID_CTRL_SET, + PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP); - palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, - PALMAS_USB_ID_INT_EN_HI_SET, - PALMAS_USB_ID_INT_EN_HI_SET_ID_GND | - PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT); + palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, + PALMAS_USB_ID_INT_EN_HI_SET, + PALMAS_USB_ID_INT_EN_HI_SET_ID_GND | + PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT); + } if (palmas_usb->enable_vbus_detection) palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb); @@ -169,20 +208,36 @@ static int palmas_usb_probe(struct platform_device *pdev) palmas_usb->wakeup = pdata->wakeup; } + palmas_usb->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id"); + if (IS_ERR(palmas_usb->id_gpiod)) { + dev_err(&pdev->dev, "failed to get id gpio\n"); + return PTR_ERR(palmas_usb->id_gpiod); + } + + if (palmas_usb->enable_id_detection && palmas_usb->id_gpiod) { + palmas_usb->enable_id_detection = false; + palmas_usb->enable_gpio_id_detection = true; + } + + if (palmas_usb->enable_gpio_id_detection) { + u32 debounce; + + if (of_property_read_u32(node, "debounce-delay-ms", &debounce)) + debounce = USB_GPIO_DEBOUNCE_MS; + + status = gpiod_set_debounce(palmas_usb->id_gpiod, + debounce * 1000); + if (status < 0) + palmas_usb->sw_debounce_jiffies = msecs_to_jiffies(debounce); + } + + INIT_DELAYED_WORK(&palmas_usb->wq_detectid, palmas_gpio_id_detect); + palmas->usb = palmas_usb; palmas_usb->palmas = palmas; palmas_usb->dev = &pdev->dev; - palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data, - PALMAS_ID_OTG_IRQ); - palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data, - PALMAS_ID_IRQ); - palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data, - PALMAS_VBUS_OTG_IRQ); - palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data, - PALMAS_VBUS_IRQ); - palmas_usb_wakeup(palmas, palmas_usb->wakeup); platform_set_drvdata(pdev, palmas_usb); @@ -201,6 +256,10 @@ static int palmas_usb_probe(struct platform_device *pdev) } if (palmas_usb->enable_id_detection) { + palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data, + PALMAS_ID_OTG_IRQ); + palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data, + PALMAS_ID_IRQ); status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->id_irq, NULL, palmas_id_irq_handler, @@ -212,9 +271,33 @@ static int palmas_usb_probe(struct platform_device *pdev) palmas_usb->id_irq, status); return status; } + } else if (palmas_usb->enable_gpio_id_detection) { + palmas_usb->gpio_id_irq = gpiod_to_irq(palmas_usb->id_gpiod); + if (palmas_usb->gpio_id_irq < 0) { + dev_err(&pdev->dev, "failed to get id irq\n"); + return palmas_usb->gpio_id_irq; + } + status = devm_request_threaded_irq(&pdev->dev, + palmas_usb->gpio_id_irq, + NULL, + palmas_gpio_id_irq_handler, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "palmas_usb_id", + palmas_usb); + if (status < 0) { + dev_err(&pdev->dev, + "failed to request handler for id irq\n"); + return status; + } } if (palmas_usb->enable_vbus_detection) { + palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data, + PALMAS_VBUS_OTG_IRQ); + palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data, + PALMAS_VBUS_IRQ); status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->vbus_irq, NULL, palmas_vbus_irq_handler, @@ -229,10 +312,21 @@ static int palmas_usb_probe(struct platform_device *pdev) } palmas_enable_irq(palmas_usb); + /* perform initial detection */ + palmas_gpio_id_detect(&palmas_usb->wq_detectid.work); device_set_wakeup_capable(&pdev->dev, true); return 0; } +static int palmas_usb_remove(struct platform_device *pdev) +{ + struct palmas_usb *palmas_usb = platform_get_drvdata(pdev); + + cancel_delayed_work_sync(&palmas_usb->wq_detectid); + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int palmas_usb_suspend(struct device *dev) { @@ -243,6 +337,8 @@ static int palmas_usb_suspend(struct device *dev) enable_irq_wake(palmas_usb->vbus_irq); if (palmas_usb->enable_id_detection) enable_irq_wake(palmas_usb->id_irq); + if (palmas_usb->enable_gpio_id_detection) + enable_irq_wake(palmas_usb->gpio_id_irq); } return 0; } @@ -256,6 +352,8 @@ static int palmas_usb_resume(struct device *dev) disable_irq_wake(palmas_usb->vbus_irq); if (palmas_usb->enable_id_detection) disable_irq_wake(palmas_usb->id_irq); + if (palmas_usb->enable_gpio_id_detection) + disable_irq_wake(palmas_usb->gpio_id_irq); } return 0; }; @@ -273,6 +371,7 @@ static const struct of_device_id of_palmas_match_tbl[] = { static struct platform_driver palmas_usb_driver = { .probe = palmas_usb_probe, + .remove = palmas_usb_remove, .driver = { .name = "palmas-usb", .of_match_table = of_palmas_match_tbl, diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index a2a44536a608..2b2fecffb1ad 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index bb270bd03eed..13e1d96935ed 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #define PALMAS_NUM_CLIENTS 3 @@ -551,10 +552,16 @@ struct palmas_usb { int vbus_otg_irq; int vbus_irq; + int gpio_id_irq; + struct gpio_desc *id_gpiod; + unsigned long sw_debounce_jiffies; + struct delayed_work wq_detectid; + enum palmas_usb_state linkstat; int wakeup; bool enable_vbus_detection; bool enable_id_detection; + bool enable_gpio_id_detection; }; #define comparator_to_palmas(x) container_of((x), struct palmas_usb, comparator) -- cgit v1.3-6-gb490 From cfd093bbb5fe84ec8c7bb069fe618159a8b601f5 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Sun, 9 Aug 2015 00:02:41 +0200 Subject: phy: lpc18xx-usb-otg: fix clock order in phy init Changing the frequency of the USB clock must be done before the PLL is powered on (prepared). This matters when the USB clock is not setup by either boot ROM or boot loader. Reorder the function calls to adhere to the order noted in the user manual. Signed-off-by: Joachim Eastwood Signed-off-by: Kishon Vijay Abraham I --- drivers/phy/phy-lpc18xx-usb-otg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/phy/phy-lpc18xx-usb-otg.c b/drivers/phy/phy-lpc18xx-usb-otg.c index 3aa8e4de1b03..3b7a71eb5b7e 100644 --- a/drivers/phy/phy-lpc18xx-usb-otg.c +++ b/drivers/phy/phy-lpc18xx-usb-otg.c @@ -33,12 +33,12 @@ static int lpc18xx_usb_otg_phy_init(struct phy *phy) struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy); int ret; - ret = clk_prepare(lpc->clk); + /* The PHY must be clocked at 480 MHz */ + ret = clk_set_rate(lpc->clk, 480000000); if (ret) return ret; - /* The PHY must be clocked at 480 MHz */ - return clk_set_rate(lpc->clk, 480000000); + return clk_prepare(lpc->clk); } static int lpc18xx_usb_otg_phy_exit(struct phy *phy) -- cgit v1.3-6-gb490 From e7472422392461f59bc5d7ddd8542c6a48740336 Mon Sep 17 00:00:00 2001 From: Victoria Milhoan Date: Wed, 5 Aug 2015 11:28:35 -0700 Subject: crypto: caam - Add cache coherency support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Freescale i.MX6 ARM platforms do not support hardware cache coherency. This patch adds cache coherency support to the CAAM driver. Signed-off-by: Victoria Milhoan Tested-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 2 +- drivers/crypto/caam/caamrng.c | 4 ++++ drivers/crypto/caam/jr.c | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index dae1e8099969..9622a81f4336 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -127,7 +127,7 @@ struct caam_hash_state { int buflen_0; u8 buf_1[CAAM_MAX_HASH_BLOCK_SIZE] ____cacheline_aligned; int buflen_1; - u8 caam_ctx[MAX_CTX_LEN]; + u8 caam_ctx[MAX_CTX_LEN] ____cacheline_aligned; int (*update)(struct ahash_request *req); int (*final)(struct ahash_request *req); int (*finup)(struct ahash_request *req); diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index 5095337205b8..a1d21d5fb2ff 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -108,6 +108,10 @@ static void rng_done(struct device *jrdev, u32 *desc, u32 err, void *context) atomic_set(&bd->empty, BUF_NOT_EMPTY); complete(&bd->filled); + + /* Buffer refilled, invalidate cache */ + dma_sync_single_for_cpu(jrdev, bd->addr, RN_BUF_SIZE, DMA_FROM_DEVICE); + #ifdef DEBUG print_hex_dump(KERN_ERR, "rng refreshed buf@: ", DUMP_PREFIX_ADDRESS, 16, 4, bd->buf, RN_BUF_SIZE, 1); diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index b8b5d47acd7a..b7ec1ad38841 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -202,6 +202,13 @@ static void caam_jr_dequeue(unsigned long devarg) userdesc = jrp->entinfo[sw_idx].desc_addr_virt; userstatus = jrp->outring[hw_idx].jrstatus; + /* + * Make sure all information from the job has been obtained + * before telling CAAM that the job has been removed from the + * output ring. + */ + mb(); + /* set done */ wr_reg32(&jrp->rregs->outring_rmvd, 1); @@ -351,12 +358,23 @@ int caam_jr_enqueue(struct device *dev, u32 *desc, jrp->inpring[jrp->inp_ring_write_index] = desc_dma; + /* + * Guarantee that the descriptor's DMA address has been written to + * the next slot in the ring before the write index is updated, since + * other cores may update this index independently. + */ smp_wmb(); jrp->inp_ring_write_index = (jrp->inp_ring_write_index + 1) & (JOBR_DEPTH - 1); jrp->head = (head + 1) & (JOBR_DEPTH - 1); + /* + * Ensure that all job information has been written before + * notifying CAAM that a new job was added to the input ring. + */ + wmb(); + wr_reg32(&jrp->rregs->inpring_jobadd, 1); spin_unlock_bh(&jrp->inplock); -- cgit v1.3-6-gb490 From 509da8fda4f06d7914dbada7af121c9f00284173 Mon Sep 17 00:00:00 2001 From: Victoria Milhoan Date: Wed, 5 Aug 2015 11:28:36 -0700 Subject: crypto: caam - Add setbits32/clrbits32/clrsetbits primitives for ARM compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add set/clear 32-bit primitives for compatibility with ARM devices since the primitives were previously only defined for the Power architecture. Signed-off-by: Victoria Milhoan Tested-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/ctrl.c | 6 +++--- drivers/crypto/caam/regs.h | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 189180976167..660cc3edd4a7 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -445,9 +445,9 @@ static int caam_probe(struct platform_device *pdev) * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, * long pointers in master configuration register */ - clrsetbits_be32(&ctrl->mcr, MCFGR_AWCACHE_MASK, MCFGR_AWCACHE_CACH | - MCFGR_WDENABLE | (sizeof(dma_addr_t) == sizeof(u64) ? - MCFGR_LONG_PTR : 0)); + clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK, MCFGR_AWCACHE_CACH | + MCFGR_WDENABLE | (sizeof(dma_addr_t) == sizeof(u64) ? + MCFGR_LONG_PTR : 0)); /* * Read the Compile Time paramters and SCFGR to determine diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h index 5e643523de15..3a2a788dadba 100644 --- a/drivers/crypto/caam/regs.h +++ b/drivers/crypto/caam/regs.h @@ -65,9 +65,31 @@ * */ +#ifdef CONFIG_ARM +/* These are common macros for Power, put here for ARM */ +#define setbits32(_addr, _v) writel((readl(_addr) | (_v)), (_addr)) +#define clrbits32(_addr, _v) writel((readl(_addr) & ~(_v)), (_addr)) + +#define out_arch(type, endian, a, v) __raw_write##type(cpu_to_##endian(v), a) +#define in_arch(type, endian, a) endian##_to_cpu(__raw_read##type(a)) + +#define out_le32(a, v) out_arch(l, le32, a, v) +#define in_le32(a) in_arch(l, le32, a) + +#define out_be32(a, v) out_arch(l, be32, a, v) +#define in_be32(a) in_arch(l, be32, a) + +#define clrsetbits(type, addr, clear, set) \ + out_##type((addr), (in_##type(addr) & ~(clear)) | (set)) + +#define clrsetbits_be32(addr, clear, set) clrsetbits(be32, addr, clear, set) +#define clrsetbits_le32(addr, clear, set) clrsetbits(le32, addr, clear, set) +#endif + #ifdef __BIG_ENDIAN #define wr_reg32(reg, data) out_be32(reg, data) #define rd_reg32(reg) in_be32(reg) +#define clrsetbits_32(addr, clear, set) clrsetbits_be32(addr, clear, set) #ifdef CONFIG_64BIT #define wr_reg64(reg, data) out_be64(reg, data) #define rd_reg64(reg) in_be64(reg) @@ -76,6 +98,7 @@ #ifdef __LITTLE_ENDIAN #define wr_reg32(reg, data) __raw_writel(data, reg) #define rd_reg32(reg) __raw_readl(reg) +#define clrsetbits_32(addr, clear, set) clrsetbits_le32(addr, clear, set) #ifdef CONFIG_64BIT #define wr_reg64(reg, data) __raw_writeq(data, reg) #define rd_reg64(reg) __raw_readq(reg) -- cgit v1.3-6-gb490 From 24821c4652dbf85a69e732574874dc191a813da4 Mon Sep 17 00:00:00 2001 From: Victoria Milhoan Date: Wed, 5 Aug 2015 11:28:37 -0700 Subject: crypto: caam - Enable and disable clocks on Freescale i.MX platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARM-based systems may disable clocking to the CAAM device on the Freescale i.MX platform for power management purposes. This patch enables the required clocks when the CAAM module is initialized and disables the required clocks when the CAAM module is shut down. Signed-off-by: Victoria Milhoan Tested-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/compat.h | 1 + drivers/crypto/caam/ctrl.c | 88 ++++++++++++++++++++++++++++++++++++++++++++ drivers/crypto/caam/intern.h | 5 +++ 3 files changed, 94 insertions(+) (limited to 'drivers') diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h index f57f395db33f..b6955ecdfb3f 100644 --- a/drivers/crypto/caam/compat.h +++ b/drivers/crypto/caam/compat.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 660cc3edd4a7..37c2d8d965a6 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -15,6 +15,24 @@ #include "desc_constr.h" #include "error.h" +/* + * ARM targets tend to have clock control subsystems that can + * enable/disable clocking to our device. + */ +#ifdef CONFIG_ARM +static inline struct clk *caam_drv_identify_clk(struct device *dev, + char *clk_name) +{ + return devm_clk_get(dev, clk_name); +} +#else +static inline struct clk *caam_drv_identify_clk(struct device *dev, + char *clk_name) +{ + return NULL; +} +#endif + /* * Descriptor to instantiate RNG State Handle 0 in normal mode and * load the JDKEK, TDKEK and TDSK registers @@ -304,6 +322,12 @@ static int caam_remove(struct platform_device *pdev) /* Unmap controller region */ iounmap(ctrl); + /* shut clocks off before finalizing shutdown */ + clk_disable_unprepare(ctrlpriv->caam_ipg); + clk_disable_unprepare(ctrlpriv->caam_mem); + clk_disable_unprepare(ctrlpriv->caam_aclk); + clk_disable_unprepare(ctrlpriv->caam_emi_slow); + return ret; } @@ -391,6 +415,7 @@ static int caam_probe(struct platform_device *pdev) struct device_node *nprop, *np; struct caam_ctrl __iomem *ctrl; struct caam_drv_private *ctrlpriv; + struct clk *clk; #ifdef CONFIG_DEBUG_FS struct caam_perfmon *perfmon; #endif @@ -409,6 +434,69 @@ static int caam_probe(struct platform_device *pdev) ctrlpriv->pdev = pdev; nprop = pdev->dev.of_node; + /* Enable clocking */ + clk = caam_drv_identify_clk(&pdev->dev, "ipg"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(&pdev->dev, + "can't identify CAAM ipg clk: %d\n", ret); + return -ENODEV; + } + ctrlpriv->caam_ipg = clk; + + clk = caam_drv_identify_clk(&pdev->dev, "mem"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(&pdev->dev, + "can't identify CAAM mem clk: %d\n", ret); + return -ENODEV; + } + ctrlpriv->caam_mem = clk; + + clk = caam_drv_identify_clk(&pdev->dev, "aclk"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(&pdev->dev, + "can't identify CAAM aclk clk: %d\n", ret); + return -ENODEV; + } + ctrlpriv->caam_aclk = clk; + + clk = caam_drv_identify_clk(&pdev->dev, "emi_slow"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(&pdev->dev, + "can't identify CAAM emi_slow clk: %d\n", ret); + return -ENODEV; + } + ctrlpriv->caam_emi_slow = clk; + + ret = clk_prepare_enable(ctrlpriv->caam_ipg); + if (ret < 0) { + dev_err(&pdev->dev, "can't enable CAAM ipg clock: %d\n", ret); + return -ENODEV; + } + + ret = clk_prepare_enable(ctrlpriv->caam_mem); + if (ret < 0) { + dev_err(&pdev->dev, "can't enable CAAM secure mem clock: %d\n", + ret); + return -ENODEV; + } + + ret = clk_prepare_enable(ctrlpriv->caam_aclk); + if (ret < 0) { + dev_err(&pdev->dev, "can't enable CAAM aclk clock: %d\n", ret); + return -ENODEV; + } + + ret = clk_prepare_enable(ctrlpriv->caam_emi_slow); + if (ret < 0) { + dev_err(&pdev->dev, "can't enable CAAM emi slow clock: %d\n", + ret); + return -ENODEV; + } + /* Get configuration properties from device tree */ /* First, get register page */ ctrl = of_iomap(nprop, 0); diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index 89b94cc9e7a2..e2bcacc1a921 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -91,6 +91,11 @@ struct caam_drv_private { Handles of the RNG4 block are initialized by this driver */ + struct clk *caam_ipg; + struct clk *caam_mem; + struct clk *caam_aclk; + struct clk *caam_emi_slow; + /* * debugfs entries for developer view into driver/device * variables at runtime. -- cgit v1.3-6-gb490 From 1f06ec1d48f31a454e4292f3761a4f4178bb916c Mon Sep 17 00:00:00 2001 From: Victoria Milhoan Date: Wed, 5 Aug 2015 11:28:38 -0700 Subject: crypto: caam - Modify Freescale CAAM driver Scatter Gather entry definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modify the Scatter-Gather entry definitions for the Freescale CAAM driver to include support for both 64- and 32-bit DMA pointers. Signed-off-by: Victoria Milhoan Tested-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/desc.h | 25 +++++++++++++++++++++---- drivers/crypto/caam/sg_sw_sec4.h | 1 - 2 files changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h index d397ff9d56fd..405acbf13dac 100644 --- a/drivers/crypto/caam/desc.h +++ b/drivers/crypto/caam/desc.h @@ -8,12 +8,29 @@ #ifndef DESC_H #define DESC_H +/* + * 16-byte hardware scatter/gather table + * An 8-byte table exists in the hardware spec, but has never been + * implemented to date. The 8/16 option is selected at RTL-compile-time. + * and this selection is visible in the Compile Time Parameters Register + */ + +#define SEC4_SG_LEN_EXT 0x80000000 /* Entry points to table */ +#define SEC4_SG_LEN_FIN 0x40000000 /* Last ent in table */ +#define SEC4_SG_BPID_MASK 0x000000ff +#define SEC4_SG_BPID_SHIFT 16 +#define SEC4_SG_LEN_MASK 0x3fffffff /* Excludes EXT and FINAL */ +#define SEC4_SG_OFFS_MASK 0x00001fff + struct sec4_sg_entry { - u64 ptr; -#define SEC4_SG_LEN_FIN 0x40000000 -#define SEC4_SG_LEN_EXT 0x80000000 +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + dma_addr_t ptr; +#else + u32 rsvd1; + dma_addr_t ptr; +#endif u32 len; - u8 reserved; + u8 rsvd2; u8 buf_pool_id; u16 offset; }; diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h index b68b74cc7b77..711bb3949779 100644 --- a/drivers/crypto/caam/sg_sw_sec4.h +++ b/drivers/crypto/caam/sg_sw_sec4.h @@ -15,7 +15,6 @@ static inline void dma_to_sec4_sg_one(struct sec4_sg_entry *sec4_sg_ptr, { sec4_sg_ptr->ptr = dma; sec4_sg_ptr->len = len; - sec4_sg_ptr->reserved = 0; sec4_sg_ptr->buf_pool_id = 0; sec4_sg_ptr->offset = offset; #ifdef DEBUG -- cgit v1.3-6-gb490 From dde20ae9d63835178ef4ba9655f530e052c08ab9 Mon Sep 17 00:00:00 2001 From: Victoria Milhoan Date: Wed, 5 Aug 2015 11:28:39 -0700 Subject: crypto: caam - Change kmalloc to kzalloc to avoid residual data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since fields must be ORed in to operate correctly using any order of operations, changed allocations of the combination of extended descriptor structs + hardware scatterlists to use kzalloc() instead of kmalloc(), so as to ensure that residue data would not be ORed in with the correct data. Signed-off-by: Steve Cornelius Signed-off-by: Victoria Milhoan Tested-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 12 ++++++------ drivers/crypto/caam/caamhash.c | 25 ++++++++++++------------- 2 files changed, 18 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index b09c1711b37c..3d1ca083a2ac 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -2199,8 +2199,8 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kzalloc(sizeof(struct aead_edesc) + desc_bytes + - sec4_sg_bytes, GFP_DMA | flags); + edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes, + GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); return ERR_PTR(-ENOMEM); @@ -2503,8 +2503,8 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct ablkcipher_edesc) + desc_bytes + - sec4_sg_bytes, GFP_DMA | flags); + edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes, + GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); return ERR_PTR(-ENOMEM); @@ -2682,8 +2682,8 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(*edesc) + desc_bytes + - sec4_sg_bytes, GFP_DMA | flags); + edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes, + GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); return ERR_PTR(-ENOMEM); diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 9622a81f4336..2361beb9fe55 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -807,7 +807,7 @@ static int ahash_update_ctx(struct ahash_request *req) * allocate space for base edesc and hw desc commands, * link tables */ - edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN + sec4_sg_bytes, GFP_DMA | flags); if (!edesc) { dev_err(jrdev, @@ -918,8 +918,8 @@ static int ahash_final_ctx(struct ahash_request *req) sec4_sg_bytes = (1 + (buflen ? 1 : 0)) * sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + - sec4_sg_bytes, GFP_DMA | flags); + edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN + sec4_sg_bytes, + GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); return -ENOMEM; @@ -1005,8 +1005,8 @@ static int ahash_finup_ctx(struct ahash_request *req) sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + - sec4_sg_bytes, GFP_DMA | flags); + edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN + sec4_sg_bytes, + GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); return -ENOMEM; @@ -1091,8 +1091,8 @@ static int ahash_digest(struct ahash_request *req) sec4_sg_bytes = src_nents * sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct ahash_edesc) + sec4_sg_bytes + - DESC_JOB_IO_LEN, GFP_DMA | flags); + edesc = kzalloc(sizeof(*edesc) + sec4_sg_bytes + DESC_JOB_IO_LEN, + GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); return -ENOMEM; @@ -1165,8 +1165,7 @@ static int ahash_final_no_ctx(struct ahash_request *req) int sh_len; /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN, - GFP_DMA | flags); + edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN, GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); return -ENOMEM; @@ -1245,7 +1244,7 @@ static int ahash_update_no_ctx(struct ahash_request *req) * allocate space for base edesc and hw desc commands, * link tables */ - edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN + sec4_sg_bytes, GFP_DMA | flags); if (!edesc) { dev_err(jrdev, @@ -1353,8 +1352,8 @@ static int ahash_finup_no_ctx(struct ahash_request *req) sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ - edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + - sec4_sg_bytes, GFP_DMA | flags); + edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN + sec4_sg_bytes, + GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); return -ENOMEM; @@ -1448,7 +1447,7 @@ static int ahash_update_first(struct ahash_request *req) * allocate space for base edesc and hw desc commands, * link tables */ - edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + edesc = kzalloc(sizeof(*edesc) + DESC_JOB_IO_LEN + sec4_sg_bytes, GFP_DMA | flags); if (!edesc) { dev_err(jrdev, -- cgit v1.3-6-gb490 From 7d5196aba3c81999d56b26daa5ea7590513cdc1f Mon Sep 17 00:00:00 2001 From: Victoria Milhoan Date: Wed, 5 Aug 2015 11:28:40 -0700 Subject: crypto: caam - Correct DMA unmap size in ahash_update_ctx() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change fixes: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 456 at lib/dma-debug.c:1103 check_unmap+0x438/0x958() caam_jr 2101000.jr0: DMA-API: device driver frees DMA memory with different size [device address=0x000000003a241080] [map ] Modules linked in: tcrypt(+) CPU: 0 PID: 456 Comm: insmod Not tainted 4.1.0-248766-gf823586-dirty #82 Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) [<80015e0c>] (unwind_backtrace) from [<80012764>] (show_stack+0x10/0x14) [<80012764>] (show_stack) from [<806df8e8>] (dump_stack+0x84/0xc4) [<806df8e8>] (dump_stack) from [<800266fc>] (warn_slowpath_common+0x84/0xb4) [<800266fc>] (warn_slowpath_common) from [<8002675c>] (warn_slowpath_fmt+0x30/0x40) [<8002675c>] (warn_slowpath_fmt) from [<802c7db8>] (check_unmap+0x438/0x958) [<802c7db8>] (check_unmap) from [<802c835c>] (debug_dma_unmap_page+0x84/0x8c) [<802c835c>] (debug_dma_unmap_page) from [<804d3b94>] (ahash_update_ctx+0xb08/0xec4) [<804d3b94>] (ahash_update_ctx) from [<7f002984>] (test_ahash_pnum.isra.9.constprop.19+0x2b8/0x514 [tcrypt]) [<7f002984>] (test_ahash_pnum.isra.9.constprop.19 [tcrypt]) from [<7f005998>] (do_test+0x2db8/0x37cc [tcrypt]) [<7f005998>] (do_test [tcrypt]) from [<7f00b050>] (tcrypt_mod_init+0x50/0x9c [tcrypt]) [<7f00b050>] (tcrypt_mod_init [tcrypt]) from [<80009730>] (do_one_initcall+0x8c/0x1d4) [<80009730>] (do_one_initcall) from [<806dda4c>] (do_init_module+0x5c/0x1a8) [<806dda4c>] (do_init_module) from [<80085308>] (load_module+0x17e0/0x1da0) [<80085308>] (load_module) from [<80085998>] (SyS_init_module+0xd0/0x120) [<80085998>] (SyS_init_module) from [<8000f4c0>] (ret_fast_syscall+0x0/0x3c) ---[ end trace 60807cfb6521c79f ]--- Signed-off-by: Victoria Milhoan Tested-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 2361beb9fe55..16c03f84fd9a 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -829,7 +829,7 @@ static int ahash_update_ctx(struct ahash_request *req) state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, buf, state->buf_dma, - *buflen, last_buflen); + *next_buflen, *buflen); if (src_nents) { src_map_to_sec4_sg(jrdev, req->src, src_nents, -- cgit v1.3-6-gb490 From ec0273039b6606ae08132f41854381e0d7371ded Mon Sep 17 00:00:00 2001 From: Victoria Milhoan Date: Wed, 5 Aug 2015 11:28:41 -0700 Subject: crypto: caam - Use local sg pointers to walk the scatterlist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid moving the head of the scatterlist entry by using temporary pointers to walk the scatterlist. Signed-off-by: Victoria Milhoan Tested-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/sg_sw_sec4.h | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h index 711bb3949779..18cd6d1f5870 100644 --- a/drivers/crypto/caam/sg_sw_sec4.h +++ b/drivers/crypto/caam/sg_sw_sec4.h @@ -105,9 +105,15 @@ static inline void dma_unmap_sg_chained( { if (unlikely(chained)) { int i; + struct scatterlist *tsg = sg; + + /* + * Use a local copy of the sg pointer to avoid moving the + * head of the list pointed to by sg as we walk the list. + */ for (i = 0; i < nents; i++) { - dma_unmap_sg(dev, sg, 1, dir); - sg = sg_next(sg); + dma_unmap_sg(dev, tsg, 1, dir); + tsg = sg_next(tsg); } } else if (nents) { dma_unmap_sg(dev, sg, nents, dir); @@ -118,19 +124,23 @@ static inline int dma_map_sg_chained( struct device *dev, struct scatterlist *sg, unsigned int nents, enum dma_data_direction dir, bool chained) { - struct scatterlist *first = sg; - if (unlikely(chained)) { int i; + struct scatterlist *tsg = sg; + + /* + * Use a local copy of the sg pointer to avoid moving the + * head of the list pointed to by sg as we walk the list. + */ for (i = 0; i < nents; i++) { - if (!dma_map_sg(dev, sg, 1, dir)) { - dma_unmap_sg_chained(dev, first, i, dir, + if (!dma_map_sg(dev, tsg, 1, dir)) { + dma_unmap_sg_chained(dev, sg, i, dir, chained); nents = 0; break; } - sg = sg_next(sg); + tsg = sg_next(tsg); } } else nents = dma_map_sg(dev, sg, nents, dir); -- cgit v1.3-6-gb490 From dd503f66098e37dd0090897c099fa6ca343db84d Mon Sep 17 00:00:00 2001 From: Victoria Milhoan Date: Wed, 5 Aug 2015 11:28:43 -0700 Subject: ARM: clk-imx6q: Add CAAM clock support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add CAAM clock support to the i.MX6 clocking infrastructure. Signed-off-by: Victoria Milhoan Tested-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/clk/imx/clk-imx6q.c | 3 +++ include/dt-bindings/clock/imx6qdl-clock.h | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index d046f8e43de8..15e855745216 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -381,6 +381,9 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_ASRC] = imx_clk_gate2_shared("asrc", "asrc_podf", base + 0x68, 6, &share_count_asrc); clk[IMX6QDL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc); clk[IMX6QDL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc); + clk[IMX6QDL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); + clk[IMX6QDL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); + clk[IMX6QDL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); clk[IMX6QDL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14); clk[IMX6QDL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_root", base + 0x68, 16); clk[IMX6QDL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18); diff --git a/include/dt-bindings/clock/imx6qdl-clock.h b/include/dt-bindings/clock/imx6qdl-clock.h index 8780868458a0..8de173ff19f3 100644 --- a/include/dt-bindings/clock/imx6qdl-clock.h +++ b/include/dt-bindings/clock/imx6qdl-clock.h @@ -251,6 +251,9 @@ #define IMX6QDL_CLK_VIDEO_27M 238 #define IMX6QDL_CLK_MIPI_CORE_CFG 239 #define IMX6QDL_CLK_MIPI_IPG 240 -#define IMX6QDL_CLK_END 241 +#define IMX6QDL_CLK_CAAM_MEM 241 +#define IMX6QDL_CLK_CAAM_ACLK 242 +#define IMX6QDL_CLK_CAAM_IPG 243 +#define IMX6QDL_CLK_END 244 #endif /* __DT_BINDINGS_CLOCK_IMX6QDL_H */ -- cgit v1.3-6-gb490 From 350cdfeba888c21341ad2989c5930a2708def579 Mon Sep 17 00:00:00 2001 From: Steve Cornelius Date: Wed, 5 Aug 2015 11:28:46 -0700 Subject: crypto: caam - Enable MXC devices to select CAAM driver in Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow CAAM to be selected in the kernel for Freescale i.MX devices if ARCH_MXC is enabled. Signed-off-by: Steve Cornelius Signed-off-by: Victoria Milhoan Tested-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index e286e285aa8a..66ef0c09af73 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -1,6 +1,6 @@ config CRYPTO_DEV_FSL_CAAM tristate "Freescale CAAM-Multicore driver backend" - depends on FSL_SOC + depends on FSL_SOC || ARCH_MXC help Enables the driver module for Freescale's Cryptographic Accelerator and Assurance Module (CAAM), also known as the SEC version 4 (SEC4). -- cgit v1.3-6-gb490 From bf83490ee4207de3af59b63870eb9f72f1e523f1 Mon Sep 17 00:00:00 2001 From: Victoria Milhoan Date: Wed, 5 Aug 2015 11:28:48 -0700 Subject: crypto: caam - Detect hardware features during algorithm registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register only algorithms supported by CAAM hardware, using the CHA version and instantiation registers to identify hardware capabilities. Signed-off-by: Victoria Milhoan Tested-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 68 ++++++++++++++++++++++++++++++++++++++---- drivers/crypto/caam/caamhash.c | 38 ++++++++++++++++++----- drivers/crypto/caam/caamrng.c | 6 +++- drivers/crypto/caam/regs.h | 16 ++++++++-- 4 files changed, 110 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 3d1ca083a2ac..336125927377 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -4371,8 +4371,10 @@ static int __init caam_algapi_init(void) struct device_node *dev_node; struct platform_device *pdev; struct device *ctrldev; - void *priv; + struct caam_drv_private *priv; int i = 0, err = 0; + u32 cha_vid, cha_inst, des_inst, aes_inst, md_inst; + unsigned int md_limit = SHA512_DIGEST_SIZE; bool registered = false; dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); @@ -4402,16 +4404,39 @@ static int __init caam_algapi_init(void) INIT_LIST_HEAD(&alg_list); - /* register crypto algorithms the device supports */ + /* + * Register crypto algorithms the device supports. + * First, detect presence and attributes of DES, AES, and MD blocks. + */ + cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls); + cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls); + des_inst = (cha_inst & CHA_ID_LS_DES_MASK) >> CHA_ID_LS_DES_SHIFT; + aes_inst = (cha_inst & CHA_ID_LS_AES_MASK) >> CHA_ID_LS_AES_SHIFT; + md_inst = (cha_inst & CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT; + + /* If MD is present, limit digest size based on LP256 */ + if (md_inst && ((cha_vid & CHA_ID_LS_MD_MASK) == CHA_ID_LS_MD_LP256)) + md_limit = SHA256_DIGEST_SIZE; + for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { - /* TODO: check if h/w supports alg */ struct caam_crypto_alg *t_alg; + struct caam_alg_template *alg = driver_algs + i; + u32 alg_sel = alg->class1_alg_type & OP_ALG_ALGSEL_MASK; + + /* Skip DES algorithms if not supported by device */ + if (!des_inst && + ((alg_sel == OP_ALG_ALGSEL_3DES) || + (alg_sel == OP_ALG_ALGSEL_DES))) + continue; + + /* Skip AES algorithms if not supported by device */ + if (!aes_inst && (alg_sel == OP_ALG_ALGSEL_AES)) + continue; - t_alg = caam_alg_alloc(&driver_algs[i]); + t_alg = caam_alg_alloc(alg); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); - pr_warn("%s alg allocation failed\n", - driver_algs[i].driver_name); + pr_warn("%s alg allocation failed\n", alg->driver_name); continue; } @@ -4429,6 +4454,37 @@ static int __init caam_algapi_init(void) for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) { struct caam_aead_alg *t_alg = driver_aeads + i; + u32 c1_alg_sel = t_alg->caam.class1_alg_type & + OP_ALG_ALGSEL_MASK; + u32 c2_alg_sel = t_alg->caam.class2_alg_type & + OP_ALG_ALGSEL_MASK; + u32 alg_aai = t_alg->caam.class1_alg_type & OP_ALG_AAI_MASK; + + /* Skip DES algorithms if not supported by device */ + if (!des_inst && + ((c1_alg_sel == OP_ALG_ALGSEL_3DES) || + (c1_alg_sel == OP_ALG_ALGSEL_DES))) + continue; + + /* Skip AES algorithms if not supported by device */ + if (!aes_inst && (c1_alg_sel == OP_ALG_ALGSEL_AES)) + continue; + + /* + * Check support for AES algorithms not available + * on LP devices. + */ + if ((cha_vid & CHA_ID_LS_AES_MASK) == CHA_ID_LS_AES_LP) + if (alg_aai == OP_ALG_AAI_GCM) + continue; + + /* + * Skip algorithms requiring message digests + * if MD or MD size is not supported by device. + */ + if (c2_alg_sel && + (!md_inst || (t_alg->aead.maxauthsize > md_limit))) + continue; caam_aead_alg_init(t_alg); diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 16c03f84fd9a..bb0935a3817c 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -1883,8 +1883,10 @@ static int __init caam_algapi_hash_init(void) struct device_node *dev_node; struct platform_device *pdev; struct device *ctrldev; - void *priv; int i = 0, err = 0; + struct caam_drv_private *priv; + unsigned int md_limit = SHA512_DIGEST_SIZE; + u32 cha_inst, cha_vid; dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); if (!dev_node) { @@ -1910,19 +1912,40 @@ static int __init caam_algapi_hash_init(void) if (!priv) return -ENODEV; + /* + * Register crypto algorithms the device supports. First, identify + * presence and attributes of MD block. + */ + cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls); + cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls); + + /* + * Skip registration of any hashing algorithms if MD block + * is not present. + */ + if (!((cha_inst & CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT)) + return -ENODEV; + + /* Limit digest size based on LP256 */ + if ((cha_vid & CHA_ID_LS_MD_MASK) == CHA_ID_LS_MD_LP256) + md_limit = SHA256_DIGEST_SIZE; + INIT_LIST_HEAD(&hash_list); /* register crypto algorithms the device supports */ for (i = 0; i < ARRAY_SIZE(driver_hash); i++) { - /* TODO: check if h/w supports alg */ struct caam_hash_alg *t_alg; + struct caam_hash_template *alg = driver_hash + i; + + /* If MD size is not supported by device, skip registration */ + if (alg->template_ahash.halg.digestsize > md_limit) + continue; /* register hmac version */ - t_alg = caam_hash_alloc(&driver_hash[i], true); + t_alg = caam_hash_alloc(alg, true); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); - pr_warn("%s alg allocation failed\n", - driver_hash[i].driver_name); + pr_warn("%s alg allocation failed\n", alg->driver_name); continue; } @@ -1935,11 +1958,10 @@ static int __init caam_algapi_hash_init(void) list_add_tail(&t_alg->entry, &hash_list); /* register unkeyed version */ - t_alg = caam_hash_alloc(&driver_hash[i], false); + t_alg = caam_hash_alloc(alg, false); if (IS_ERR(t_alg)) { err = PTR_ERR(t_alg); - pr_warn("%s alg allocation failed\n", - driver_hash[i].driver_name); + pr_warn("%s alg allocation failed\n", alg->driver_name); continue; } diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index a1d21d5fb2ff..345024c22467 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -315,7 +315,7 @@ static int __init caam_rng_init(void) struct device_node *dev_node; struct platform_device *pdev; struct device *ctrldev; - void *priv; + struct caam_drv_private *priv; int err; dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); @@ -342,6 +342,10 @@ static int __init caam_rng_init(void) if (!priv) return -ENODEV; + /* Check for an instantiated RNG before registration */ + if (!(rd_reg32(&priv->ctrl->perfmon.cha_num_ls) & CHA_ID_LS_RNG_MASK)) + return -ENODEV; + dev = caam_jr_alloc(); if (IS_ERR(dev)) { pr_err("Job Ring Device allocation for transform failed\n"); diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h index 3a2a788dadba..d7c3579af791 100644 --- a/drivers/crypto/caam/regs.h +++ b/drivers/crypto/caam/regs.h @@ -156,18 +156,28 @@ struct jr_outentry { #define CHA_NUM_MS_DECONUM_SHIFT 24 #define CHA_NUM_MS_DECONUM_MASK (0xfull << CHA_NUM_MS_DECONUM_SHIFT) -/* CHA Version IDs */ +/* + * CHA version IDs / instantiation bitfields + * Defined for use with the cha_id fields in perfmon, but the same shift/mask + * selectors can be used to pull out the number of instantiated blocks within + * cha_num fields in perfmon because the locations are the same. + */ #define CHA_ID_LS_AES_SHIFT 0 -#define CHA_ID_LS_AES_MASK (0xfull << CHA_ID_LS_AES_SHIFT) +#define CHA_ID_LS_AES_MASK (0xfull << CHA_ID_LS_AES_SHIFT) +#define CHA_ID_LS_AES_LP (0x3ull << CHA_ID_LS_AES_SHIFT) +#define CHA_ID_LS_AES_HP (0x4ull << CHA_ID_LS_AES_SHIFT) #define CHA_ID_LS_DES_SHIFT 4 -#define CHA_ID_LS_DES_MASK (0xfull << CHA_ID_LS_DES_SHIFT) +#define CHA_ID_LS_DES_MASK (0xfull << CHA_ID_LS_DES_SHIFT) #define CHA_ID_LS_ARC4_SHIFT 8 #define CHA_ID_LS_ARC4_MASK (0xfull << CHA_ID_LS_ARC4_SHIFT) #define CHA_ID_LS_MD_SHIFT 12 #define CHA_ID_LS_MD_MASK (0xfull << CHA_ID_LS_MD_SHIFT) +#define CHA_ID_LS_MD_LP256 (0x0ull << CHA_ID_LS_MD_SHIFT) +#define CHA_ID_LS_MD_LP512 (0x1ull << CHA_ID_LS_MD_SHIFT) +#define CHA_ID_LS_MD_HP (0x2ull << CHA_ID_LS_MD_SHIFT) #define CHA_ID_LS_RNG_SHIFT 16 #define CHA_ID_LS_RNG_MASK (0xfull << CHA_ID_LS_RNG_SHIFT) -- cgit v1.3-6-gb490 From 35a3bb3d39d5a84b1adc02e5289d01a33d1073b6 Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Wed, 5 Aug 2015 16:52:08 -0500 Subject: crypto: talitos - Prevent panic in probe error path The probe error path for this driver, for all intents and purposes, is the talitos_remove() function due to the common "goto err_out". Without this patch applied, talitos_remove() will panic under these two conditions: 1. If the RNG device hasn't been registered via talitos_register_rng() prior to entry into talitos_remove(), then the attempt to unregister the RNG "device" will cause a panic. 2. If the priv->chan array has not been allocated prior to entry into talitos_remove(), then the per-channel FIFO cleanup will panic because of the dereference of that NULL "array". Both of the above scenarios occur if talitos_probe_irq() fails. This patch resolves issue #1 by introducing a boolean to mask the hwrng_unregister() call in talitos_unregister_rng() if RNG device registration was unsuccessful. It resolves issue #2 by checking that priv->chan is not NULL in the per-channel FIFO cleanup for loop. Signed-off-by: Aaron Sierra Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 13 +++++++++++-- drivers/crypto/talitos.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 43727c915a59..1bc8dd91e217 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -766,6 +766,7 @@ static int talitos_rng_init(struct hwrng *rng) static int talitos_register_rng(struct device *dev) { struct talitos_private *priv = dev_get_drvdata(dev); + int err; priv->rng.name = dev_driver_string(dev), priv->rng.init = talitos_rng_init, @@ -773,14 +774,22 @@ static int talitos_register_rng(struct device *dev) priv->rng.data_read = talitos_rng_data_read, priv->rng.priv = (unsigned long)dev; - return hwrng_register(&priv->rng); + err = hwrng_register(&priv->rng); + if (!err) + priv->rng_registered = true; + + return err; } static void talitos_unregister_rng(struct device *dev) { struct talitos_private *priv = dev_get_drvdata(dev); + if (!priv->rng_registered) + return; + hwrng_unregister(&priv->rng); + priv->rng_registered = false; } /* @@ -2673,7 +2682,7 @@ static int talitos_remove(struct platform_device *ofdev) if (hw_supports(dev, DESC_HDR_SEL0_RNG)) talitos_unregister_rng(dev); - for (i = 0; i < priv->num_channels; i++) + for (i = 0; priv->chan && i < priv->num_channels; i++) kfree(priv->chan[i].fifo); kfree(priv->chan); diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h index 163cfe733bf0..0090f3211d68 100644 --- a/drivers/crypto/talitos.h +++ b/drivers/crypto/talitos.h @@ -149,6 +149,7 @@ struct talitos_private { /* hwrng device */ struct hwrng rng; + bool rng_registered; }; extern int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc, -- cgit v1.3-6-gb490 From a57331394cf5228555dbf4bca21abb2fc1597f04 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 7 Aug 2015 11:34:20 -0700 Subject: crypto: qat - Move adf admin and adf hw arbitrer to common code Adf admin and HW arbiter function can be used by dh895xcc specific code well as the new dh895xccvf and future devices so moving them to qat_common so that they can be shared. Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/Makefile | 2 + drivers/crypto/qat/qat_common/adf_accel_devices.h | 5 +- drivers/crypto/qat/qat_common/adf_admin.c | 185 +++++++++++++++++++++ drivers/crypto/qat/qat_common/adf_common_drv.h | 7 +- drivers/crypto/qat/qat_common/adf_hw_arbiter.c | 168 +++++++++++++++++++ drivers/crypto/qat/qat_common/adf_init.c | 84 +--------- drivers/crypto/qat/qat_common/adf_transport.c | 7 +- drivers/crypto/qat/qat_common/qat_crypto.c | 3 +- drivers/crypto/qat/qat_dh895xcc/Makefile | 5 +- drivers/crypto/qat/qat_dh895xcc/adf_admin.c | 145 ---------------- .../crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c | 6 +- .../crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h | 5 - drivers/crypto/qat/qat_dh895xcc/adf_drv.c | 3 - drivers/crypto/qat/qat_dh895xcc/adf_drv.h | 9 - drivers/crypto/qat/qat_dh895xcc/adf_hw_arbiter.c | 159 ------------------ drivers/crypto/qat/qat_dh895xcc/qat_admin.c | 107 ------------ 16 files changed, 378 insertions(+), 522 deletions(-) create mode 100644 drivers/crypto/qat/qat_common/adf_admin.c create mode 100644 drivers/crypto/qat/qat_common/adf_hw_arbiter.c delete mode 100644 drivers/crypto/qat/qat_dh895xcc/adf_admin.c delete mode 100644 drivers/crypto/qat/qat_dh895xcc/adf_hw_arbiter.c delete mode 100644 drivers/crypto/qat/qat_dh895xcc/qat_admin.c (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile index 184605f76bea..e5fe4e723355 100644 --- a/drivers/crypto/qat/qat_common/Makefile +++ b/drivers/crypto/qat/qat_common/Makefile @@ -9,6 +9,8 @@ intel_qat-objs := adf_cfg.o \ adf_accel_engine.o \ adf_aer.o \ adf_transport.o \ + adf_admin.o \ + adf_hw_arbiter.o \ qat_crypto.o \ qat_algs.o \ qat_rsakey-asn1.o \ diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index 99cbce6b3cbc..a7d3d11142f2 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -141,15 +141,16 @@ struct adf_hw_device_data { uint32_t (*get_num_aes)(struct adf_hw_device_data *self); uint32_t (*get_num_accels)(struct adf_hw_device_data *self); enum dev_sku_info (*get_sku)(struct adf_hw_device_data *self); - void (*hw_arb_ring_enable)(struct adf_etr_ring_data *ring); - void (*hw_arb_ring_disable)(struct adf_etr_ring_data *ring); int (*alloc_irq)(struct adf_accel_dev *accel_dev); void (*free_irq)(struct adf_accel_dev *accel_dev); void (*enable_error_correction)(struct adf_accel_dev *accel_dev); int (*init_admin_comms)(struct adf_accel_dev *accel_dev); void (*exit_admin_comms)(struct adf_accel_dev *accel_dev); + int (*send_admin_init)(struct adf_accel_dev *accel_dev); int (*init_arb)(struct adf_accel_dev *accel_dev); void (*exit_arb)(struct adf_accel_dev *accel_dev); + void (*get_arb_mapping)(struct adf_accel_dev *accel_dev, + const uint32_t **cfg); void (*enable_ints)(struct adf_accel_dev *accel_dev); const char *fw_name; const char *fw_mmp_name; diff --git a/drivers/crypto/qat/qat_common/adf_admin.c b/drivers/crypto/qat/qat_common/adf_admin.c new file mode 100644 index 000000000000..0a76168e4923 --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_admin.c @@ -0,0 +1,185 @@ +/* + 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. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2014 Intel Corporation. + 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 of 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 +#include "adf_accel_devices.h" +#include "icp_qat_fw_init_admin.h" + +/* Admin Messages Registers */ +#define ADF_DH895XCC_ADMINMSGUR_OFFSET (0x3A000 + 0x574) +#define ADF_DH895XCC_ADMINMSGLR_OFFSET (0x3A000 + 0x578) +#define ADF_DH895XCC_MAILBOX_BASE_OFFSET 0x20970 +#define ADF_DH895XCC_MAILBOX_STRIDE 0x1000 +#define ADF_ADMINMSG_LEN 32 + +struct adf_admin_comms { + dma_addr_t phy_addr; + void *virt_addr; + void __iomem *mailbox_addr; + struct mutex lock; /* protects adf_admin_comms struct */ +}; + +static int adf_put_admin_msg_sync(struct adf_accel_dev *accel_dev, u32 ae, + void *in, void *out) +{ + struct adf_admin_comms *admin = accel_dev->admin; + int offset = ae * ADF_ADMINMSG_LEN * 2; + void __iomem *mailbox = admin->mailbox_addr; + int mb_offset = ae * ADF_DH895XCC_MAILBOX_STRIDE; + int times, received; + + mutex_lock(&admin->lock); + + if (ADF_CSR_RD(mailbox, mb_offset) == 1) { + mutex_unlock(&admin->lock); + return -EAGAIN; + } + + memcpy(admin->virt_addr + offset, in, ADF_ADMINMSG_LEN); + ADF_CSR_WR(mailbox, mb_offset, 1); + received = 0; + for (times = 0; times < 50; times++) { + msleep(20); + if (ADF_CSR_RD(mailbox, mb_offset) == 0) { + received = 1; + break; + } + } + if (received) + memcpy(out, admin->virt_addr + offset + + ADF_ADMINMSG_LEN, ADF_ADMINMSG_LEN); + else + dev_err(&GET_DEV(accel_dev), + "Failed to send admin msg to accelerator\n"); + + mutex_unlock(&admin->lock); + return received ? 0 : -EFAULT; +} + +static int adf_send_admin_cmd(struct adf_accel_dev *accel_dev, int cmd) +{ + struct adf_hw_device_data *hw_device = accel_dev->hw_device; + struct icp_qat_fw_init_admin_req req; + struct icp_qat_fw_init_admin_resp resp; + int i; + + memset(&req, 0, sizeof(struct icp_qat_fw_init_admin_req)); + req.init_admin_cmd_id = cmd; + for (i = 0; i < hw_device->get_num_aes(hw_device); i++) { + memset(&resp, 0, sizeof(struct icp_qat_fw_init_admin_resp)); + if (adf_put_admin_msg_sync(accel_dev, i, &req, &resp) || + resp.init_resp_hdr.status) + return -EFAULT; + } + return 0; +} + +/** + * adf_send_admin_init() - Function sends init message to FW + * @accel_dev: Pointer to acceleration device. + * + * Function sends admin init message to the FW + * + * Return: 0 on success, error code otherwise. + */ +int adf_send_admin_init(struct adf_accel_dev *accel_dev) +{ + return adf_send_admin_cmd(accel_dev, ICP_QAT_FW_INIT_ME); +} +EXPORT_SYMBOL_GPL(adf_send_admin_init); + +int adf_init_admin_comms(struct adf_accel_dev *accel_dev) +{ + struct adf_admin_comms *admin; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + struct adf_bar *pmisc = + &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; + void __iomem *csr = pmisc->virt_addr; + void __iomem *mailbox = csr + ADF_DH895XCC_MAILBOX_BASE_OFFSET; + u64 reg_val; + + admin = kzalloc_node(sizeof(*accel_dev->admin), GFP_KERNEL, + dev_to_node(&GET_DEV(accel_dev))); + if (!admin) + return -ENOMEM; + admin->virt_addr = dma_zalloc_coherent(&GET_DEV(accel_dev), PAGE_SIZE, + &admin->phy_addr, GFP_KERNEL); + if (!admin->virt_addr) { + dev_err(&GET_DEV(accel_dev), "Failed to allocate dma buff\n"); + kfree(admin); + return -ENOMEM; + } + reg_val = (u64)admin->phy_addr; + ADF_CSR_WR(csr, ADF_DH895XCC_ADMINMSGUR_OFFSET, reg_val >> 32); + ADF_CSR_WR(csr, ADF_DH895XCC_ADMINMSGLR_OFFSET, reg_val); + mutex_init(&admin->lock); + admin->mailbox_addr = mailbox; + accel_dev->admin = admin; + return 0; +} +EXPORT_SYMBOL_GPL(adf_init_admin_comms); + +void adf_exit_admin_comms(struct adf_accel_dev *accel_dev) +{ + struct adf_admin_comms *admin = accel_dev->admin; + + if (!admin) + return; + + if (admin->virt_addr) + dma_free_coherent(&GET_DEV(accel_dev), PAGE_SIZE, + admin->virt_addr, admin->phy_addr); + + mutex_destroy(&admin->lock); + kfree(admin); + accel_dev->admin = NULL; +} +EXPORT_SYMBOL_GPL(adf_exit_admin_comms); diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index 3c33feefee67..7935a38cb88f 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -91,7 +91,6 @@ struct service_hndl { unsigned long start_status; char *name; struct list_head list; - int admin; }; static inline int get_current_node(void) @@ -135,6 +134,12 @@ int adf_enable_aer(struct adf_accel_dev *accel_dev, struct pci_driver *adf); void adf_disable_aer(struct adf_accel_dev *accel_dev); int adf_init_aer(void); void adf_exit_aer(void); +int adf_init_admin_comms(struct adf_accel_dev *accel_dev); +void adf_exit_admin_comms(struct adf_accel_dev *accel_dev); +int adf_send_admin_init(struct adf_accel_dev *accel_dev); +int adf_init_arb(struct adf_accel_dev *accel_dev); +void adf_exit_arb(struct adf_accel_dev *accel_dev); +void adf_update_ring_arb(struct adf_etr_ring_data *ring); int adf_dev_get(struct adf_accel_dev *accel_dev); void adf_dev_put(struct adf_accel_dev *accel_dev); diff --git a/drivers/crypto/qat/qat_common/adf_hw_arbiter.c b/drivers/crypto/qat/qat_common/adf_hw_arbiter.c new file mode 100644 index 000000000000..6849422e04bb --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_hw_arbiter.c @@ -0,0 +1,168 @@ +/* + 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. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2014 Intel Corporation. + 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 of 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 "adf_accel_devices.h" +#include "adf_transport_internal.h" + +#define ADF_ARB_NUM 4 +#define ADF_ARB_REQ_RING_NUM 8 +#define ADF_ARB_REG_SIZE 0x4 +#define ADF_ARB_WTR_SIZE 0x20 +#define ADF_ARB_OFFSET 0x30000 +#define ADF_ARB_REG_SLOT 0x1000 +#define ADF_ARB_WTR_OFFSET 0x010 +#define ADF_ARB_RO_EN_OFFSET 0x090 +#define ADF_ARB_WQCFG_OFFSET 0x100 +#define ADF_ARB_WRK_2_SER_MAP_OFFSET 0x180 +#define ADF_ARB_RINGSRVARBEN_OFFSET 0x19C + +#define WRITE_CSR_ARB_RINGSRVARBEN(csr_addr, index, value) \ + ADF_CSR_WR(csr_addr, ADF_ARB_RINGSRVARBEN_OFFSET + \ + (ADF_ARB_REG_SLOT * index), value) + +#define WRITE_CSR_ARB_RESPORDERING(csr_addr, index, value) \ + ADF_CSR_WR(csr_addr, (ADF_ARB_OFFSET + \ + ADF_ARB_RO_EN_OFFSET) + (ADF_ARB_REG_SIZE * index), value) + +#define WRITE_CSR_ARB_WEIGHT(csr_addr, arb, index, value) \ + ADF_CSR_WR(csr_addr, (ADF_ARB_OFFSET + \ + ADF_ARB_WTR_OFFSET) + (ADF_ARB_WTR_SIZE * arb) + \ + (ADF_ARB_REG_SIZE * index), value) + +#define WRITE_CSR_ARB_SARCONFIG(csr_addr, index, value) \ + ADF_CSR_WR(csr_addr, ADF_ARB_OFFSET + \ + (ADF_ARB_REG_SIZE * index), value) + +#define WRITE_CSR_ARB_WRK_2_SER_MAP(csr_addr, index, value) \ + ADF_CSR_WR(csr_addr, (ADF_ARB_OFFSET + \ + ADF_ARB_WRK_2_SER_MAP_OFFSET) + \ + (ADF_ARB_REG_SIZE * index), value) + +#define WRITE_CSR_ARB_WQCFG(csr_addr, index, value) \ + ADF_CSR_WR(csr_addr, (ADF_ARB_OFFSET + \ + ADF_ARB_WQCFG_OFFSET) + (ADF_ARB_REG_SIZE * index), value) + +int adf_init_arb(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + void __iomem *csr = accel_dev->transport->banks[0].csr_addr; + u32 arb_cfg = 0x1 << 31 | 0x4 << 4 | 0x1; + u32 arb, i; + const u32 *thd_2_arb_cfg; + + /* Service arb configured for 32 bytes responses and + * ring flow control check enabled. */ + for (arb = 0; arb < ADF_ARB_NUM; arb++) + WRITE_CSR_ARB_SARCONFIG(csr, arb, arb_cfg); + + /* Setup service weighting */ + for (arb = 0; arb < ADF_ARB_NUM; arb++) + for (i = 0; i < ADF_ARB_REQ_RING_NUM; i++) + WRITE_CSR_ARB_WEIGHT(csr, arb, i, 0xFFFFFFFF); + + /* Setup ring response ordering */ + for (i = 0; i < ADF_ARB_REQ_RING_NUM; i++) + WRITE_CSR_ARB_RESPORDERING(csr, i, 0xFFFFFFFF); + + /* Setup worker queue registers */ + for (i = 0; i < hw_data->num_engines; i++) + WRITE_CSR_ARB_WQCFG(csr, i, i); + + /* Map worker threads to service arbiters */ + hw_data->get_arb_mapping(accel_dev, &thd_2_arb_cfg); + + if (!thd_2_arb_cfg) + return -EFAULT; + + for (i = 0; i < hw_data->num_engines; i++) + WRITE_CSR_ARB_WRK_2_SER_MAP(csr, i, *(thd_2_arb_cfg + i)); + + return 0; +} +EXPORT_SYMBOL_GPL(adf_init_arb); + +/** + * adf_update_ring_arb() - update ring arbitration rgister + * @accel_dev: Pointer to ring data. + * + * Function enables or disables rings for/from arbitration. + */ +void adf_update_ring_arb(struct adf_etr_ring_data *ring) +{ + WRITE_CSR_ARB_RINGSRVARBEN(ring->bank->csr_addr, + ring->bank->bank_number, + ring->bank->ring_mask & 0xFF); +} +EXPORT_SYMBOL_GPL(adf_update_ring_arb); + +void adf_exit_arb(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + void __iomem *csr; + unsigned int i; + + if (!accel_dev->transport) + return; + + csr = accel_dev->transport->banks[0].csr_addr; + + /* Reset arbiter configuration */ + for (i = 0; i < ADF_ARB_NUM; i++) + WRITE_CSR_ARB_SARCONFIG(csr, i, 0); + + /* Shutdown work queue */ + for (i = 0; i < hw_data->num_engines; i++) + WRITE_CSR_ARB_WQCFG(csr, i, 0); + + /* Unmap worker threads to service arbiters */ + for (i = 0; i < hw_data->num_engines; i++) + WRITE_CSR_ARB_WRK_2_SER_MAP(csr, i, 0); + + /* Disable arbitration on all rings */ + for (i = 0; i < GET_MAX_BANKS(accel_dev); i++) + WRITE_CSR_ARB_RINGSRVARBEN(csr, i, 0); +} +EXPORT_SYMBOL_GPL(adf_exit_arb); diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c index 9a90b287ad68..1aaa5fd92bb2 100644 --- a/drivers/crypto/qat/qat_common/adf_init.c +++ b/drivers/crypto/qat/qat_common/adf_init.c @@ -177,20 +177,6 @@ int adf_dev_init(struct adf_accel_dev *accel_dev) */ list_for_each(list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list); - if (!service->admin) - continue; - if (service->event_hld(accel_dev, ADF_EVENT_INIT)) { - dev_err(&GET_DEV(accel_dev), - "Failed to initialise service %s\n", - service->name); - return -EFAULT; - } - set_bit(accel_dev->accel_id, &service->init_status); - } - list_for_each(list_itr, &service_table) { - service = list_entry(list_itr, struct service_hndl, list); - if (service->admin) - continue; if (service->event_hld(accel_dev, ADF_EVENT_INIT)) { dev_err(&GET_DEV(accel_dev), "Failed to initialise service %s\n", @@ -218,6 +204,7 @@ EXPORT_SYMBOL_GPL(adf_dev_init); */ int adf_dev_start(struct adf_accel_dev *accel_dev) { + struct adf_hw_device_data *hw_data = accel_dev->hw_device; struct service_hndl *service; struct list_head *list_itr; @@ -229,22 +216,13 @@ int adf_dev_start(struct adf_accel_dev *accel_dev) } set_bit(ADF_STATUS_AE_STARTED, &accel_dev->status); - list_for_each(list_itr, &service_table) { - service = list_entry(list_itr, struct service_hndl, list); - if (!service->admin) - continue; - if (service->event_hld(accel_dev, ADF_EVENT_START)) { - dev_err(&GET_DEV(accel_dev), - "Failed to start service %s\n", - service->name); - return -EFAULT; - } - set_bit(accel_dev->accel_id, &service->start_status); + if (hw_data->send_admin_init(accel_dev)) { + dev_err(&GET_DEV(accel_dev), "Failed to send init message\n"); + return -EFAULT; } + list_for_each(list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list); - if (service->admin) - continue; if (service->event_hld(accel_dev, ADF_EVENT_START)) { dev_err(&GET_DEV(accel_dev), "Failed to start service %s\n", @@ -300,8 +278,6 @@ int adf_dev_stop(struct adf_accel_dev *accel_dev) list_for_each(list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list); - if (service->admin) - continue; if (!test_bit(accel_dev->accel_id, &service->start_status)) continue; ret = service->event_hld(accel_dev, ADF_EVENT_STOP); @@ -312,19 +288,6 @@ int adf_dev_stop(struct adf_accel_dev *accel_dev) clear_bit(accel_dev->accel_id, &service->start_status); } } - list_for_each(list_itr, &service_table) { - service = list_entry(list_itr, struct service_hndl, list); - if (!service->admin) - continue; - if (!test_bit(accel_dev->accel_id, &service->start_status)) - continue; - if (service->event_hld(accel_dev, ADF_EVENT_STOP)) - dev_err(&GET_DEV(accel_dev), - "Failed to shutdown service %s\n", - service->name); - else - clear_bit(accel_dev->accel_id, &service->start_status); - } if (wait) msleep(100); @@ -375,21 +338,6 @@ void adf_dev_shutdown(struct adf_accel_dev *accel_dev) list_for_each(list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list); - if (service->admin) - continue; - if (!test_bit(accel_dev->accel_id, &service->init_status)) - continue; - if (service->event_hld(accel_dev, ADF_EVENT_SHUTDOWN)) - dev_err(&GET_DEV(accel_dev), - "Failed to shutdown service %s\n", - service->name); - else - clear_bit(accel_dev->accel_id, &service->init_status); - } - list_for_each(list_itr, &service_table) { - service = list_entry(list_itr, struct service_hndl, list); - if (!service->admin) - continue; if (!test_bit(accel_dev->accel_id, &service->init_status)) continue; if (service->event_hld(accel_dev, ADF_EVENT_SHUTDOWN)) @@ -426,17 +374,6 @@ int adf_dev_restarting_notify(struct adf_accel_dev *accel_dev) list_for_each(list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list); - if (service->admin) - continue; - if (service->event_hld(accel_dev, ADF_EVENT_RESTARTING)) - dev_err(&GET_DEV(accel_dev), - "Failed to restart service %s.\n", - service->name); - } - list_for_each(list_itr, &service_table) { - service = list_entry(list_itr, struct service_hndl, list); - if (!service->admin) - continue; if (service->event_hld(accel_dev, ADF_EVENT_RESTARTING)) dev_err(&GET_DEV(accel_dev), "Failed to restart service %s.\n", @@ -452,17 +389,6 @@ int adf_dev_restarted_notify(struct adf_accel_dev *accel_dev) list_for_each(list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list); - if (service->admin) - continue; - if (service->event_hld(accel_dev, ADF_EVENT_RESTARTED)) - dev_err(&GET_DEV(accel_dev), - "Failed to restart service %s.\n", - service->name); - } - list_for_each(list_itr, &service_table) { - service = list_entry(list_itr, struct service_hndl, list); - if (!service->admin) - continue; if (service->event_hld(accel_dev, ADF_EVENT_RESTARTED)) dev_err(&GET_DEV(accel_dev), "Failed to restart service %s.\n", diff --git a/drivers/crypto/qat/qat_common/adf_transport.c b/drivers/crypto/qat/qat_common/adf_transport.c index df0331d26838..d5d81985cd4b 100644 --- a/drivers/crypto/qat/qat_common/adf_transport.c +++ b/drivers/crypto/qat/qat_common/adf_transport.c @@ -285,7 +285,7 @@ int adf_create_ring(struct adf_accel_dev *accel_dev, const char *section, goto err; /* Enable HW arbitration for the given ring */ - accel_dev->hw_device->hw_arb_ring_enable(ring); + adf_update_ring_arb(ring); if (adf_ring_debugfs_add(ring, ring_name)) { dev_err(&GET_DEV(accel_dev), @@ -302,14 +302,13 @@ int adf_create_ring(struct adf_accel_dev *accel_dev, const char *section, err: adf_cleanup_ring(ring); adf_unreserve_ring(bank, ring_num); - accel_dev->hw_device->hw_arb_ring_disable(ring); + adf_update_ring_arb(ring); return ret; } void adf_remove_ring(struct adf_etr_ring_data *ring) { struct adf_etr_bank_data *bank = ring->bank; - struct adf_accel_dev *accel_dev = bank->accel_dev; /* Disable interrupts for the given ring */ adf_disable_ring_irq(bank, ring->ring_number); @@ -322,7 +321,7 @@ void adf_remove_ring(struct adf_etr_ring_data *ring) adf_ring_debugfs_rm(ring); adf_unreserve_ring(bank, ring->ring_number); /* Disable HW arbitration for the given ring */ - accel_dev->hw_device->hw_arb_ring_disable(ring); + adf_update_ring_arb(ring); adf_cleanup_ring(ring); } diff --git a/drivers/crypto/qat/qat_common/qat_crypto.c b/drivers/crypto/qat/qat_common/qat_crypto.c index e23ce6fe074b..359ae94430b8 100644 --- a/drivers/crypto/qat/qat_common/qat_crypto.c +++ b/drivers/crypto/qat/qat_common/qat_crypto.c @@ -152,7 +152,6 @@ static int qat_crypto_create_instances(struct adf_accel_dev *accel_dev) INIT_LIST_HEAD(&accel_dev->crypto_list); strlcpy(key, ADF_NUM_CY, sizeof(key)); - if (adf_cfg_get_param_value(accel_dev, SEC, key, val)) return -EFAULT; @@ -181,7 +180,9 @@ static int qat_crypto_create_instances(struct adf_accel_dev *accel_dev) if (kstrtoul(val, 10, &num_msg_sym)) goto err; + num_msg_sym = num_msg_sym >> 1; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_SIZE, i); if (adf_cfg_get_param_value(accel_dev, SEC, key, val)) goto err; diff --git a/drivers/crypto/qat/qat_dh895xcc/Makefile b/drivers/crypto/qat/qat_dh895xcc/Makefile index 25171c557043..8c79c543740f 100644 --- a/drivers/crypto/qat/qat_dh895xcc/Makefile +++ b/drivers/crypto/qat/qat_dh895xcc/Makefile @@ -2,7 +2,4 @@ ccflags-y := -I$(src)/../qat_common obj-$(CONFIG_CRYPTO_DEV_QAT_DH895xCC) += qat_dh895xcc.o qat_dh895xcc-objs := adf_drv.o \ adf_isr.o \ - adf_dh895xcc_hw_data.o \ - adf_hw_arbiter.o \ - qat_admin.o \ - adf_admin.o + adf_dh895xcc_hw_data.o diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_admin.c b/drivers/crypto/qat/qat_dh895xcc/adf_admin.c deleted file mode 100644 index e4666065c399..000000000000 --- a/drivers/crypto/qat/qat_dh895xcc/adf_admin.c +++ /dev/null @@ -1,145 +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) 2014 Intel Corporation. - 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. - - Contact Information: - qat-linux@intel.com - - BSD LICENSE - Copyright(c) 2014 Intel Corporation. - 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 of 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 -#include -#include "adf_drv.h" -#include "adf_dh895xcc_hw_data.h" - -#define ADF_ADMINMSG_LEN 32 - -struct adf_admin_comms { - dma_addr_t phy_addr; - void *virt_addr; - void __iomem *mailbox_addr; - struct mutex lock; /* protects adf_admin_comms struct */ -}; - -int adf_put_admin_msg_sync(struct adf_accel_dev *accel_dev, - uint32_t ae, void *in, void *out) -{ - struct adf_admin_comms *admin = accel_dev->admin; - int offset = ae * ADF_ADMINMSG_LEN * 2; - void __iomem *mailbox = admin->mailbox_addr; - int mb_offset = ae * ADF_DH895XCC_MAILBOX_STRIDE; - int times, received; - - mutex_lock(&admin->lock); - - if (ADF_CSR_RD(mailbox, mb_offset) == 1) { - mutex_unlock(&admin->lock); - return -EAGAIN; - } - - memcpy(admin->virt_addr + offset, in, ADF_ADMINMSG_LEN); - ADF_CSR_WR(mailbox, mb_offset, 1); - received = 0; - for (times = 0; times < 50; times++) { - msleep(20); - if (ADF_CSR_RD(mailbox, mb_offset) == 0) { - received = 1; - break; - } - } - if (received) - memcpy(out, admin->virt_addr + offset + - ADF_ADMINMSG_LEN, ADF_ADMINMSG_LEN); - else - dev_err(&GET_DEV(accel_dev), - "Failed to send admin msg to accelerator\n"); - - mutex_unlock(&admin->lock); - return received ? 0 : -EFAULT; -} - -int adf_init_admin_comms(struct adf_accel_dev *accel_dev) -{ - struct adf_admin_comms *admin; - struct adf_bar *pmisc = &GET_BARS(accel_dev)[ADF_DH895XCC_PMISC_BAR]; - void __iomem *csr = pmisc->virt_addr; - void __iomem *mailbox = csr + ADF_DH895XCC_MAILBOX_BASE_OFFSET; - uint64_t reg_val; - - admin = kzalloc_node(sizeof(*accel_dev->admin), GFP_KERNEL, - dev_to_node(&GET_DEV(accel_dev))); - if (!admin) - return -ENOMEM; - admin->virt_addr = dma_zalloc_coherent(&GET_DEV(accel_dev), PAGE_SIZE, - &admin->phy_addr, GFP_KERNEL); - if (!admin->virt_addr) { - dev_err(&GET_DEV(accel_dev), "Failed to allocate dma buff\n"); - kfree(admin); - return -ENOMEM; - } - reg_val = (uint64_t)admin->phy_addr; - ADF_CSR_WR(csr, ADF_DH895XCC_ADMINMSGUR_OFFSET, reg_val >> 32); - ADF_CSR_WR(csr, ADF_DH895XCC_ADMINMSGLR_OFFSET, reg_val); - mutex_init(&admin->lock); - admin->mailbox_addr = mailbox; - accel_dev->admin = admin; - return 0; -} - -void adf_exit_admin_comms(struct adf_accel_dev *accel_dev) -{ - struct adf_admin_comms *admin = accel_dev->admin; - - if (!admin) - return; - - if (admin->virt_addr) - dma_free_coherent(&GET_DEV(accel_dev), PAGE_SIZE, - admin->virt_addr, admin->phy_addr); - - mutex_destroy(&admin->lock); - kfree(admin); - accel_dev->admin = NULL; -} diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c index 155ace9d4a43..a3b1be895af9 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -45,8 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include #include "adf_dh895xcc_hw_data.h" -#include "adf_common_drv.h" #include "adf_drv.h" /* Worker thread to service arbiter mappings based on dev SKUs */ @@ -215,8 +215,6 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) hw_data->alloc_irq = adf_isr_resource_alloc; hw_data->free_irq = adf_isr_resource_free; hw_data->enable_error_correction = adf_enable_error_correction; - hw_data->hw_arb_ring_enable = adf_update_ring_arb_enable; - hw_data->hw_arb_ring_disable = adf_update_ring_arb_enable; hw_data->get_accel_mask = get_accel_mask; hw_data->get_ae_mask = get_ae_mask; hw_data->get_num_accels = get_num_accels; @@ -229,8 +227,10 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) hw_data->fw_mmp_name = ADF_DH895XCC_MMP; hw_data->init_admin_comms = adf_init_admin_comms; hw_data->exit_admin_comms = adf_exit_admin_comms; + hw_data->send_admin_init = adf_send_admin_init; hw_data->init_arb = adf_init_arb; hw_data->exit_arb = adf_exit_arb; + hw_data->get_arb_mapping = adf_get_arbiter_mapping; hw_data->enable_ints = adf_enable_ints; } diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h index a4963a9b687b..d410afb4f3d7 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h @@ -80,11 +80,6 @@ #define ADF_DH895XCC_CERRSSMSH(i) (i * 0x4000 + 0x10) #define ADF_DH895XCC_ERRSSMSH_EN BIT(3) -/* Admin Messages Registers */ -#define ADF_DH895XCC_ADMINMSGUR_OFFSET (0x3A000 + 0x574) -#define ADF_DH895XCC_ADMINMSGLR_OFFSET (0x3A000 + 0x578) -#define ADF_DH895XCC_MAILBOX_BASE_OFFSET 0x20970 -#define ADF_DH895XCC_MAILBOX_STRIDE 0x1000 /* FW names */ #define ADF_DH895XCC_FW "qat_895xcc.bin" #define ADF_DH895XCC_MMP "qat_mmp.bin" diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c index 4abeca1b1c33..1837c32fa306 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c @@ -386,8 +386,6 @@ static void adf_remove(struct pci_dev *pdev) static int __init adfdrv_init(void) { request_module("intel_qat"); - if (qat_admin_register()) - return -EFAULT; if (pci_register_driver(&adf_driver)) { pr_err("QAT: Driver initialization failed\n"); @@ -399,7 +397,6 @@ static int __init adfdrv_init(void) static void __exit adfdrv_release(void) { pci_unregister_driver(&adf_driver); - qat_admin_unregister(); } module_init(adfdrv_init); diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.h b/drivers/crypto/qat/qat_dh895xcc/adf_drv.h index a2fbb6ce75cd..85ff245bd1d8 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.h +++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.h @@ -53,15 +53,6 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data); void adf_clean_hw_data_dh895xcc(struct adf_hw_device_data *hw_data); int adf_isr_resource_alloc(struct adf_accel_dev *accel_dev); void adf_isr_resource_free(struct adf_accel_dev *accel_dev); -void adf_update_ring_arb_enable(struct adf_etr_ring_data *ring); void adf_get_arbiter_mapping(struct adf_accel_dev *accel_dev, uint32_t const **arb_map_config); -int adf_init_admin_comms(struct adf_accel_dev *accel_dev); -void adf_exit_admin_comms(struct adf_accel_dev *accel_dev); -int adf_put_admin_msg_sync(struct adf_accel_dev *accel_dev, - uint32_t ae, void *in, void *out); -int qat_admin_register(void); -int qat_admin_unregister(void); -int adf_init_arb(struct adf_accel_dev *accel_dev); -void adf_exit_arb(struct adf_accel_dev *accel_dev); #endif diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_hw_arbiter.c b/drivers/crypto/qat/qat_dh895xcc/adf_hw_arbiter.c deleted file mode 100644 index 1864bdb36f8f..000000000000 --- a/drivers/crypto/qat/qat_dh895xcc/adf_hw_arbiter.c +++ /dev/null @@ -1,159 +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) 2014 Intel Corporation. - 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. - - Contact Information: - qat-linux@intel.com - - BSD LICENSE - Copyright(c) 2014 Intel Corporation. - 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 of 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 "adf_drv.h" - -#define ADF_ARB_NUM 4 -#define ADF_ARB_REQ_RING_NUM 8 -#define ADF_ARB_REG_SIZE 0x4 -#define ADF_ARB_WTR_SIZE 0x20 -#define ADF_ARB_OFFSET 0x30000 -#define ADF_ARB_REG_SLOT 0x1000 -#define ADF_ARB_WTR_OFFSET 0x010 -#define ADF_ARB_RO_EN_OFFSET 0x090 -#define ADF_ARB_WQCFG_OFFSET 0x100 -#define ADF_ARB_WRK_2_SER_MAP_OFFSET 0x180 -#define ADF_ARB_WRK_2_SER_MAP 10 -#define ADF_ARB_RINGSRVARBEN_OFFSET 0x19C - -#define WRITE_CSR_ARB_RINGSRVARBEN(csr_addr, index, value) \ - ADF_CSR_WR(csr_addr, ADF_ARB_RINGSRVARBEN_OFFSET + \ - (ADF_ARB_REG_SLOT * index), value) - -#define WRITE_CSR_ARB_RESPORDERING(csr_addr, index, value) \ - ADF_CSR_WR(csr_addr, (ADF_ARB_OFFSET + \ - ADF_ARB_RO_EN_OFFSET) + (ADF_ARB_REG_SIZE * index), value) - -#define WRITE_CSR_ARB_WEIGHT(csr_addr, arb, index, value) \ - ADF_CSR_WR(csr_addr, (ADF_ARB_OFFSET + \ - ADF_ARB_WTR_OFFSET) + (ADF_ARB_WTR_SIZE * arb) + \ - (ADF_ARB_REG_SIZE * index), value) - -#define WRITE_CSR_ARB_SARCONFIG(csr_addr, index, value) \ - ADF_CSR_WR(csr_addr, ADF_ARB_OFFSET + \ - (ADF_ARB_REG_SIZE * index), value) - -#define WRITE_CSR_ARB_WRK_2_SER_MAP(csr_addr, index, value) \ - ADF_CSR_WR(csr_addr, (ADF_ARB_OFFSET + \ - ADF_ARB_WRK_2_SER_MAP_OFFSET) + \ - (ADF_ARB_REG_SIZE * index), value) - -#define WRITE_CSR_ARB_WQCFG(csr_addr, index, value) \ - ADF_CSR_WR(csr_addr, (ADF_ARB_OFFSET + \ - ADF_ARB_WQCFG_OFFSET) + (ADF_ARB_REG_SIZE * index), value) - -int adf_init_arb(struct adf_accel_dev *accel_dev) -{ - void __iomem *csr = accel_dev->transport->banks[0].csr_addr; - uint32_t arb_cfg = 0x1 << 31 | 0x4 << 4 | 0x1; - uint32_t arb, i; - const uint32_t *thd_2_arb_cfg; - - /* Service arb configured for 32 bytes responses and - * ring flow control check enabled. */ - for (arb = 0; arb < ADF_ARB_NUM; arb++) - WRITE_CSR_ARB_SARCONFIG(csr, arb, arb_cfg); - - /* Setup service weighting */ - for (arb = 0; arb < ADF_ARB_NUM; arb++) - for (i = 0; i < ADF_ARB_REQ_RING_NUM; i++) - WRITE_CSR_ARB_WEIGHT(csr, arb, i, 0xFFFFFFFF); - - /* Setup ring response ordering */ - for (i = 0; i < ADF_ARB_REQ_RING_NUM; i++) - WRITE_CSR_ARB_RESPORDERING(csr, i, 0xFFFFFFFF); - - /* Setup worker queue registers */ - for (i = 0; i < ADF_ARB_WRK_2_SER_MAP; i++) - WRITE_CSR_ARB_WQCFG(csr, i, i); - - /* Map worker threads to service arbiters */ - adf_get_arbiter_mapping(accel_dev, &thd_2_arb_cfg); - - if (!thd_2_arb_cfg) - return -EFAULT; - - for (i = 0; i < ADF_ARB_WRK_2_SER_MAP; i++) - WRITE_CSR_ARB_WRK_2_SER_MAP(csr, i, *(thd_2_arb_cfg + i)); - - return 0; -} - -void adf_update_ring_arb_enable(struct adf_etr_ring_data *ring) -{ - WRITE_CSR_ARB_RINGSRVARBEN(ring->bank->csr_addr, - ring->bank->bank_number, - ring->bank->ring_mask & 0xFF); -} - -void adf_exit_arb(struct adf_accel_dev *accel_dev) -{ - void __iomem *csr; - unsigned int i; - - if (!accel_dev->transport) - return; - - csr = accel_dev->transport->banks[0].csr_addr; - - /* Reset arbiter configuration */ - for (i = 0; i < ADF_ARB_NUM; i++) - WRITE_CSR_ARB_SARCONFIG(csr, i, 0); - - /* Shutdown work queue */ - for (i = 0; i < ADF_ARB_WRK_2_SER_MAP; i++) - WRITE_CSR_ARB_WQCFG(csr, i, 0); - - /* Unmap worker threads to service arbiters */ - for (i = 0; i < ADF_ARB_WRK_2_SER_MAP; i++) - WRITE_CSR_ARB_WRK_2_SER_MAP(csr, i, 0); - - /* Disable arbitration on all rings */ - for (i = 0; i < GET_MAX_BANKS(accel_dev); i++) - WRITE_CSR_ARB_RINGSRVARBEN(csr, i, 0); -} diff --git a/drivers/crypto/qat/qat_dh895xcc/qat_admin.c b/drivers/crypto/qat/qat_dh895xcc/qat_admin.c deleted file mode 100644 index 55b7a8e48bad..000000000000 --- a/drivers/crypto/qat/qat_dh895xcc/qat_admin.c +++ /dev/null @@ -1,107 +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) 2014 Intel Corporation. - 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. - - Contact Information: - qat-linux@intel.com - - BSD LICENSE - Copyright(c) 2014 Intel Corporation. - 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 of 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 "adf_drv.h" - -static struct service_hndl qat_admin; - -static int qat_send_admin_cmd(struct adf_accel_dev *accel_dev, int cmd) -{ - struct adf_hw_device_data *hw_device = accel_dev->hw_device; - struct icp_qat_fw_init_admin_req req; - struct icp_qat_fw_init_admin_resp resp; - int i; - - memset(&req, 0, sizeof(struct icp_qat_fw_init_admin_req)); - req.init_admin_cmd_id = cmd; - for (i = 0; i < hw_device->get_num_aes(hw_device); i++) { - memset(&resp, 0, sizeof(struct icp_qat_fw_init_admin_resp)); - if (adf_put_admin_msg_sync(accel_dev, i, &req, &resp) || - resp.init_resp_hdr.status) - return -EFAULT; - } - return 0; -} - -static int qat_admin_start(struct adf_accel_dev *accel_dev) -{ - return qat_send_admin_cmd(accel_dev, ICP_QAT_FW_INIT_ME); -} - -static int qat_admin_event_handler(struct adf_accel_dev *accel_dev, - enum adf_event event) -{ - int ret; - - switch (event) { - case ADF_EVENT_START: - ret = qat_admin_start(accel_dev); - break; - case ADF_EVENT_STOP: - case ADF_EVENT_INIT: - case ADF_EVENT_SHUTDOWN: - default: - ret = 0; - } - return ret; -} - -int qat_admin_register(void) -{ - memset(&qat_admin, 0, sizeof(struct service_hndl)); - qat_admin.event_hld = qat_admin_event_handler; - qat_admin.name = "qat_admin"; - qat_admin.admin = 1; - return adf_service_register(&qat_admin); -} - -int qat_admin_unregister(void) -{ - return adf_service_unregister(&qat_admin); -} -- cgit v1.3-6-gb490 From ed8ccaef52fa03fb03cff45b380f72c9f869f273 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 7 Aug 2015 11:34:25 -0700 Subject: crypto: qat - Add support for SRIOV Add code that enables SRIOV on dh895xcc devices. Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/Makefile | 1 + drivers/crypto/qat/qat_common/adf_accel_devices.h | 37 ++ drivers/crypto/qat/qat_common/adf_aer.c | 3 + drivers/crypto/qat/qat_common/adf_cfg.c | 3 + drivers/crypto/qat/qat_common/adf_cfg_common.h | 3 +- drivers/crypto/qat/qat_common/adf_common_drv.h | 37 +- drivers/crypto/qat/qat_common/adf_ctl_drv.c | 6 +- drivers/crypto/qat/qat_common/adf_dev_mgr.c | 283 +++++++++++++- drivers/crypto/qat/qat_common/adf_init.c | 10 +- drivers/crypto/qat/qat_common/adf_pf2vf_msg.c | 336 +++++++++++++++++ drivers/crypto/qat/qat_common/adf_pf2vf_msg.h | 144 ++++++++ drivers/crypto/qat/qat_common/adf_sriov.c | 406 +++++++++++++++++++++ drivers/crypto/qat/qat_common/qat_crypto.c | 4 +- .../crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c | 24 +- .../crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h | 4 + drivers/crypto/qat/qat_dh895xcc/adf_drv.c | 80 ++-- drivers/crypto/qat/qat_dh895xcc/adf_isr.c | 139 +++++-- 17 files changed, 1426 insertions(+), 94 deletions(-) create mode 100644 drivers/crypto/qat/qat_common/adf_pf2vf_msg.c create mode 100644 drivers/crypto/qat/qat_common/adf_pf2vf_msg.h create mode 100644 drivers/crypto/qat/qat_common/adf_sriov.c (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/Makefile b/drivers/crypto/qat/qat_common/Makefile index e5fe4e723355..df20a9de1c58 100644 --- a/drivers/crypto/qat/qat_common/Makefile +++ b/drivers/crypto/qat/qat_common/Makefile @@ -19,3 +19,4 @@ intel_qat-objs := adf_cfg.o \ qat_hal.o intel_qat-$(CONFIG_DEBUG_FS) += adf_transport_debug.o +intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_pf2vf_msg.o diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index a7d3d11142f2..ca853d50b4b7 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -46,13 +46,17 @@ */ #ifndef ADF_ACCEL_DEVICES_H_ #define ADF_ACCEL_DEVICES_H_ +#include #include #include #include +#include #include "adf_cfg_common.h" #define ADF_DH895XCC_DEVICE_NAME "dh895xcc" +#define ADF_DH895XCCVF_DEVICE_NAME "dh895xccvf" #define ADF_DH895XCC_PCI_DEVICE_ID 0x435 +#define ADF_DH895XCCIOV_PCI_DEVICE_ID 0x443 #define ADF_PCI_MAX_BARS 3 #define ADF_DEVICE_NAME_LENGTH 32 #define ADF_ETR_MAX_RINGS_PER_BANK 16 @@ -79,6 +83,7 @@ struct adf_bar { struct adf_accel_msix { struct msix_entry *entries; char **names; + u32 num_entries; } __packed; struct adf_accel_pci { @@ -99,6 +104,7 @@ enum dev_sku_info { DEV_SKU_2, DEV_SKU_3, DEV_SKU_4, + DEV_SKU_VF, DEV_SKU_UNKNOWN, }; @@ -113,6 +119,8 @@ static inline const char *get_sku_info(enum dev_sku_info info) return "SKU3"; case DEV_SKU_4: return "SKU4"; + case DEV_SKU_VF: + return "SKUVF"; case DEV_SKU_UNKNOWN: default: break; @@ -140,6 +148,8 @@ struct adf_hw_device_data { uint32_t (*get_etr_bar_id)(struct adf_hw_device_data *self); uint32_t (*get_num_aes)(struct adf_hw_device_data *self); uint32_t (*get_num_accels)(struct adf_hw_device_data *self); + uint32_t (*get_pf2vf_offset)(uint32_t i); + uint32_t (*get_vintmsk_offset)(uint32_t i); enum dev_sku_info (*get_sku)(struct adf_hw_device_data *self); int (*alloc_irq)(struct adf_accel_dev *accel_dev); void (*free_irq)(struct adf_accel_dev *accel_dev); @@ -151,7 +161,9 @@ struct adf_hw_device_data { void (*exit_arb)(struct adf_accel_dev *accel_dev); void (*get_arb_mapping)(struct adf_accel_dev *accel_dev, const uint32_t **cfg); + void (*disable_iov)(struct adf_accel_dev *accel_dev); void (*enable_ints)(struct adf_accel_dev *accel_dev); + int (*enable_vf2pf_comms)(struct adf_accel_dev *accel_dev); const char *fw_name; const char *fw_mmp_name; uint32_t fuses; @@ -165,6 +177,7 @@ struct adf_hw_device_data { uint8_t num_accel; uint8_t num_logical_accel; uint8_t num_engines; + uint8_t min_iov_compat_ver; } __packed; /* CSR write macro */ @@ -189,6 +202,15 @@ struct adf_fw_loader_data { const struct firmware *mmp_fw; }; +struct adf_accel_vf_info { + struct adf_accel_dev *accel_dev; + struct tasklet_struct vf2pf_bh_tasklet; + struct mutex pf2vf_lock; /* protect CSR access for PF2VF messages */ + struct ratelimit_state vf2pf_ratelimit; + u32 vf_nr; + bool init; +}; + struct adf_accel_dev { struct adf_etr_data *transport; struct adf_hw_device_data *hw_device; @@ -202,6 +224,21 @@ struct adf_accel_dev { struct list_head list; struct module *owner; struct adf_accel_pci accel_pci_dev; + union { + struct { + /* vf_info is non-zero when SR-IOV is init'ed */ + struct adf_accel_vf_info *vf_info; + } pf; + struct { + char *irq_name; + struct tasklet_struct pf2vf_bh_tasklet; + struct mutex vf2pf_lock; /* protect CSR access */ + struct completion iov_msg_completion; + uint8_t compatible; + uint8_t pf_version; + } vf; + }; + bool is_vf; uint8_t accel_id; } __packed; #endif diff --git a/drivers/crypto/qat/qat_common/adf_aer.c b/drivers/crypto/qat/qat_common/adf_aer.c index 8f34a5fce72a..a57b4194de28 100644 --- a/drivers/crypto/qat/qat_common/adf_aer.c +++ b/drivers/crypto/qat/qat_common/adf_aer.c @@ -91,6 +91,9 @@ static void adf_dev_restore(struct adf_accel_dev *accel_dev) dev_info(&GET_DEV(accel_dev), "Resetting device qat_dev%d\n", accel_dev->accel_id); + if (!parent) + parent = pdev; + if (!pci_wait_for_pending_transaction(pdev)) dev_info(&GET_DEV(accel_dev), "Transaction still in progress. Proceeding\n"); diff --git a/drivers/crypto/qat/qat_common/adf_cfg.c b/drivers/crypto/qat/qat_common/adf_cfg.c index 76eccb8d96a8..d0879790561f 100644 --- a/drivers/crypto/qat/qat_common/adf_cfg.c +++ b/drivers/crypto/qat/qat_common/adf_cfg.c @@ -178,6 +178,9 @@ void adf_cfg_dev_remove(struct adf_accel_dev *accel_dev) { struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg; + if (!dev_cfg_data) + return; + down_write(&dev_cfg_data->lock); adf_cfg_section_del_all(&dev_cfg_data->sec_list); up_write(&dev_cfg_data->lock); diff --git a/drivers/crypto/qat/qat_common/adf_cfg_common.h b/drivers/crypto/qat/qat_common/adf_cfg_common.h index 88b82187ac35..c697fb1cdfb5 100644 --- a/drivers/crypto/qat/qat_common/adf_cfg_common.h +++ b/drivers/crypto/qat/qat_common/adf_cfg_common.h @@ -60,7 +60,7 @@ #define ADF_CFG_NO_DEVICE 0xFF #define ADF_CFG_AFFINITY_WHATEVER 0xFF #define MAX_DEVICE_NAME_SIZE 32 -#define ADF_MAX_DEVICES 32 +#define ADF_MAX_DEVICES (32 * 32) enum adf_cfg_val_type { ADF_DEC, @@ -71,6 +71,7 @@ enum adf_cfg_val_type { enum adf_device_type { DEV_UNKNOWN = 0, DEV_DH895XCC, + DEV_DH895XCCVF, }; struct adf_dev_status_info { diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index 7935a38cb88f..0f5f5e8c5003 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -54,8 +54,8 @@ #include "icp_qat_hal.h" #define ADF_MAJOR_VERSION 0 -#define ADF_MINOR_VERSION 1 -#define ADF_BUILD_VERSION 4 +#define ADF_MINOR_VERSION 2 +#define ADF_BUILD_VERSION 0 #define ADF_DRV_VERSION __stringify(ADF_MAJOR_VERSION) "." \ __stringify(ADF_MINOR_VERSION) "." \ __stringify(ADF_BUILD_VERSION) @@ -95,7 +95,7 @@ struct service_hndl { static inline int get_current_node(void) { - return cpu_data(current_thread_info()->cpu).phys_proc_id; + return topology_physical_package_id(smp_processor_id()); } int adf_service_register(struct service_hndl *service); @@ -106,13 +106,23 @@ int adf_dev_start(struct adf_accel_dev *accel_dev); int adf_dev_stop(struct adf_accel_dev *accel_dev); void adf_dev_shutdown(struct adf_accel_dev *accel_dev); +void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev); +void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev); +int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr); +void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev); +int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev); +void adf_devmgr_update_class_index(struct adf_hw_device_data *hw_data); +void adf_clean_vf_map(bool); + int adf_ctl_dev_register(void); void adf_ctl_dev_unregister(void); int adf_processes_dev_register(void); void adf_processes_dev_unregister(void); -int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev); -void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev); +int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev, + struct adf_accel_dev *pf); +void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev, + struct adf_accel_dev *pf); struct list_head *adf_devmgr_get_head(void); struct adf_accel_dev *adf_devmgr_get_dev_by_id(uint32_t id); struct adf_accel_dev *adf_devmgr_get_first(void); @@ -211,4 +221,21 @@ int qat_uclo_map_uof_obj(struct icp_qat_fw_loader_handle *handle, void *addr_ptr, int mem_size); void qat_uclo_wr_mimage(struct icp_qat_fw_loader_handle *handle, void *addr_ptr, int mem_size); +#if defined(CONFIG_PCI_IOV) +int adf_sriov_configure(struct pci_dev *pdev, int numvfs); +void adf_disable_sriov(struct adf_accel_dev *accel_dev); +void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, + uint32_t vf_mask); +void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, + uint32_t vf_mask); +#else +static inline int adf_sriov_configure(struct pci_dev *pdev, int numvfs) +{ + return 0; +} + +static inline void adf_disable_sriov(struct adf_accel_dev *accel_dev) +{ +} +#endif #endif diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c index e056b9e9bf8a..cd8a12af8ec5 100644 --- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c +++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c @@ -398,10 +398,9 @@ static int adf_ctl_ioctl_get_status(struct file *fp, unsigned int cmd, } accel_dev = adf_devmgr_get_dev_by_id(dev_info.accel_id); - if (!accel_dev) { - pr_err("QAT: Device %d not found\n", dev_info.accel_id); + if (!accel_dev) return -ENODEV; - } + hw_data = accel_dev->hw_device; dev_info.state = adf_dev_started(accel_dev) ? DEV_UP : DEV_DOWN; dev_info.num_ae = hw_data->get_num_aes(hw_data); @@ -495,6 +494,7 @@ static void __exit adf_unregister_ctl_device_driver(void) adf_exit_aer(); qat_crypto_unregister(); qat_algs_exit(); + adf_clean_vf_map(false); mutex_destroy(&adf_ctl_lock); } diff --git a/drivers/crypto/qat/qat_common/adf_dev_mgr.c b/drivers/crypto/qat/qat_common/adf_dev_mgr.c index b574a82368a4..8dfdb8f90797 100644 --- a/drivers/crypto/qat/qat_common/adf_dev_mgr.c +++ b/drivers/crypto/qat/qat_common/adf_dev_mgr.c @@ -50,21 +50,125 @@ #include "adf_common_drv.h" static LIST_HEAD(accel_table); +static LIST_HEAD(vfs_table); static DEFINE_MUTEX(table_lock); static uint32_t num_devices; +struct vf_id_map { + u32 bdf; + u32 id; + u32 fake_id; + bool attached; + struct list_head list; +}; + +static int adf_get_vf_id(struct adf_accel_dev *vf) +{ + return ((7 * (PCI_SLOT(accel_to_pci_dev(vf)->devfn) - 1)) + + PCI_FUNC(accel_to_pci_dev(vf)->devfn) + + (PCI_SLOT(accel_to_pci_dev(vf)->devfn) - 1)); +} + +static int adf_get_vf_num(struct adf_accel_dev *vf) +{ + return (accel_to_pci_dev(vf)->bus->number << 8) | adf_get_vf_id(vf); +} + +static struct vf_id_map *adf_find_vf(u32 bdf) +{ + struct list_head *itr; + + list_for_each(itr, &vfs_table) { + struct vf_id_map *ptr = + list_entry(itr, struct vf_id_map, list); + + if (ptr->bdf == bdf) + return ptr; + } + return NULL; +} + +static int adf_get_vf_real_id(u32 fake) +{ + struct list_head *itr; + + list_for_each(itr, &vfs_table) { + struct vf_id_map *ptr = + list_entry(itr, struct vf_id_map, list); + if (ptr->fake_id == fake) + return ptr->id; + } + return -1; +} + +/** + * adf_clean_vf_map() - Cleans VF id mapings + * + * Function cleans internal ids for virtual functions. + * @vf: flag indicating whether mappings is cleaned + * for vfs only or for vfs and pfs + */ +void adf_clean_vf_map(bool vf) +{ + struct vf_id_map *map; + struct list_head *ptr, *tmp; + + mutex_lock(&table_lock); + list_for_each_safe(ptr, tmp, &vfs_table) { + map = list_entry(ptr, struct vf_id_map, list); + if (map->bdf != -1) + num_devices--; + + if (vf && map->bdf == -1) + continue; + + list_del(ptr); + kfree(map); + } + mutex_unlock(&table_lock); +} +EXPORT_SYMBOL_GPL(adf_clean_vf_map); + +/** + * adf_devmgr_update_class_index() - Update internal index + * @hw_data: Pointer to internal device data. + * + * Function updates internal dev index for VFs + */ +void adf_devmgr_update_class_index(struct adf_hw_device_data *hw_data) +{ + struct adf_hw_device_class *class = hw_data->dev_class; + struct list_head *itr; + int i = 0; + + list_for_each(itr, &accel_table) { + struct adf_accel_dev *ptr = + list_entry(itr, struct adf_accel_dev, list); + + if (ptr->hw_device->dev_class == class) + ptr->hw_device->instance_id = i++; + + if (i == class->instances) + break; + } +} +EXPORT_SYMBOL_GPL(adf_devmgr_update_class_index); + /** * adf_devmgr_add_dev() - Add accel_dev to the acceleration framework * @accel_dev: Pointer to acceleration device. + * @pf: Corresponding PF if the accel_dev is a VF * * Function adds acceleration device to the acceleration framework. * To be used by QAT device specific drivers. * * Return: 0 on success, error code otherwise. */ -int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev) +int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev, + struct adf_accel_dev *pf) { struct list_head *itr; + int ret = 0; if (num_devices == ADF_MAX_DEVICES) { dev_err(&GET_DEV(accel_dev), "Only support up to %d devices\n", @@ -73,20 +177,77 @@ int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev) } mutex_lock(&table_lock); - list_for_each(itr, &accel_table) { - struct adf_accel_dev *ptr = + atomic_set(&accel_dev->ref_count, 0); + + /* PF on host or VF on guest */ + if (!accel_dev->is_vf || (accel_dev->is_vf && !pf)) { + struct vf_id_map *map; + + list_for_each(itr, &accel_table) { + struct adf_accel_dev *ptr = list_entry(itr, struct adf_accel_dev, list); - if (ptr == accel_dev) { - mutex_unlock(&table_lock); - return -EEXIST; + if (ptr == accel_dev) { + ret = -EEXIST; + goto unlock; + } } + + list_add_tail(&accel_dev->list, &accel_table); + accel_dev->accel_id = num_devices++; + + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (!map) { + ret = -ENOMEM; + goto unlock; + } + map->bdf = ~0; + map->id = accel_dev->accel_id; + map->fake_id = map->id; + map->attached = true; + list_add_tail(&map->list, &vfs_table); + } else if (accel_dev->is_vf && pf) { + /* VF on host */ + struct adf_accel_vf_info *vf_info; + struct vf_id_map *map; + + vf_info = pf->pf.vf_info + adf_get_vf_id(accel_dev); + + map = adf_find_vf(adf_get_vf_num(accel_dev)); + if (map) { + struct vf_id_map *next; + + accel_dev->accel_id = map->id; + list_add_tail(&accel_dev->list, &accel_table); + map->fake_id++; + map->attached = true; + next = list_next_entry(map, list); + while (next && &next->list != &vfs_table) { + next->fake_id++; + next = list_next_entry(next, list); + } + + ret = 0; + goto unlock; + } + + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (!map) { + ret = -ENOMEM; + goto unlock; + } + + accel_dev->accel_id = num_devices++; + list_add_tail(&accel_dev->list, &accel_table); + map->bdf = adf_get_vf_num(accel_dev); + map->id = accel_dev->accel_id; + map->fake_id = map->id; + map->attached = true; + list_add_tail(&map->list, &vfs_table); } - atomic_set(&accel_dev->ref_count, 0); - list_add_tail(&accel_dev->list, &accel_table); - accel_dev->accel_id = num_devices++; +unlock: mutex_unlock(&table_lock); - return 0; + return ret; } EXPORT_SYMBOL_GPL(adf_devmgr_add_dev); @@ -98,17 +259,37 @@ struct list_head *adf_devmgr_get_head(void) /** * adf_devmgr_rm_dev() - Remove accel_dev from the acceleration framework. * @accel_dev: Pointer to acceleration device. + * @pf: Corresponding PF if the accel_dev is a VF * * Function removes acceleration device from the acceleration framework. * To be used by QAT device specific drivers. * * Return: void */ -void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev) +void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev, + struct adf_accel_dev *pf) { mutex_lock(&table_lock); + if (!accel_dev->is_vf || (accel_dev->is_vf && !pf)) { + num_devices--; + } else if (accel_dev->is_vf && pf) { + struct vf_id_map *map, *next; + + map = adf_find_vf(adf_get_vf_num(accel_dev)); + if (!map) { + dev_err(&GET_DEV(accel_dev), "Failed to find VF map\n"); + goto unlock; + } + map->fake_id--; + map->attached = false; + next = list_next_entry(map, list); + while (next && &next->list != &vfs_table) { + next->fake_id--; + next = list_next_entry(next, list); + } + } +unlock: list_del(&accel_dev->list); - num_devices--; mutex_unlock(&table_lock); } EXPORT_SYMBOL_GPL(adf_devmgr_rm_dev); @@ -154,17 +335,24 @@ EXPORT_SYMBOL_GPL(adf_devmgr_pci_to_accel_dev); struct adf_accel_dev *adf_devmgr_get_dev_by_id(uint32_t id) { struct list_head *itr; + int real_id; mutex_lock(&table_lock); + real_id = adf_get_vf_real_id(id); + if (real_id < 0) + goto unlock; + + id = real_id; + list_for_each(itr, &accel_table) { struct adf_accel_dev *ptr = list_entry(itr, struct adf_accel_dev, list); - if (ptr->accel_id == id) { mutex_unlock(&table_lock); return ptr; } } +unlock: mutex_unlock(&table_lock); return NULL; } @@ -180,16 +368,52 @@ int adf_devmgr_verify_id(uint32_t id) return -ENODEV; } +static int adf_get_num_dettached_vfs(void) +{ + struct list_head *itr; + int vfs = 0; + + mutex_lock(&table_lock); + list_for_each(itr, &vfs_table) { + struct vf_id_map *ptr = + list_entry(itr, struct vf_id_map, list); + if (ptr->bdf != ~0 && !ptr->attached) + vfs++; + } + mutex_unlock(&table_lock); + return vfs; +} + void adf_devmgr_get_num_dev(uint32_t *num) { - *num = num_devices; + *num = num_devices - adf_get_num_dettached_vfs(); } +/** + * adf_dev_in_use() - Check whether accel_dev is currently in use + * @accel_dev: Pointer to acceleration device. + * + * To be used by QAT device specific drivers. + * + * Return: 1 when device is in use, 0 otherwise. + */ int adf_dev_in_use(struct adf_accel_dev *accel_dev) { return atomic_read(&accel_dev->ref_count) != 0; } +EXPORT_SYMBOL_GPL(adf_dev_in_use); +/** + * adf_dev_get() - Increment accel_dev reference count + * @accel_dev: Pointer to acceleration device. + * + * Increment the accel_dev refcount and if this is the first time + * incrementing it during this period the accel_dev is in use, + * increment the module refcount too. + * To be used by QAT device specific drivers. + * + * Return: 0 when successful, EFAULT when fail to bump module refcount + */ int adf_dev_get(struct adf_accel_dev *accel_dev) { if (atomic_add_return(1, &accel_dev->ref_count) == 1) @@ -197,19 +421,50 @@ int adf_dev_get(struct adf_accel_dev *accel_dev) return -EFAULT; return 0; } +EXPORT_SYMBOL_GPL(adf_dev_get); +/** + * adf_dev_put() - Decrement accel_dev reference count + * @accel_dev: Pointer to acceleration device. + * + * Decrement the accel_dev refcount and if this is the last time + * decrementing it during this period the accel_dev is in use, + * decrement the module refcount too. + * To be used by QAT device specific drivers. + * + * Return: void + */ void adf_dev_put(struct adf_accel_dev *accel_dev) { if (atomic_sub_return(1, &accel_dev->ref_count) == 0) module_put(accel_dev->owner); } +EXPORT_SYMBOL_GPL(adf_dev_put); +/** + * adf_devmgr_in_reset() - Check whether device is in reset + * @accel_dev: Pointer to acceleration device. + * + * To be used by QAT device specific drivers. + * + * Return: 1 when the device is being reset, 0 otherwise. + */ int adf_devmgr_in_reset(struct adf_accel_dev *accel_dev) { return test_bit(ADF_STATUS_RESTARTING, &accel_dev->status); } +EXPORT_SYMBOL_GPL(adf_devmgr_in_reset); +/** + * adf_dev_started() - Check whether device has started + * @accel_dev: Pointer to acceleration device. + * + * To be used by QAT device specific drivers. + * + * Return: 1 when the device has started, 0 otherwise + */ int adf_dev_started(struct adf_accel_dev *accel_dev) { return test_bit(ADF_STATUS_STARTED, &accel_dev->status); } +EXPORT_SYMBOL_GPL(adf_dev_started); diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c index 1aaa5fd92bb2..ac37a89965ac 100644 --- a/drivers/crypto/qat/qat_common/adf_init.c +++ b/drivers/crypto/qat/qat_common/adf_init.c @@ -187,6 +187,7 @@ int adf_dev_init(struct adf_accel_dev *accel_dev) } hw_data->enable_error_correction(accel_dev); + hw_data->enable_vf2pf_comms(accel_dev); return 0; } @@ -235,7 +236,8 @@ int adf_dev_start(struct adf_accel_dev *accel_dev) clear_bit(ADF_STATUS_STARTING, &accel_dev->status); set_bit(ADF_STATUS_STARTED, &accel_dev->status); - if (qat_algs_register() || qat_asym_algs_register()) { + if (!list_empty(&accel_dev->crypto_list) && + (qat_algs_register() || qat_asym_algs_register())) { dev_err(&GET_DEV(accel_dev), "Failed to register crypto algs\n"); set_bit(ADF_STATUS_STARTING, &accel_dev->status); @@ -270,11 +272,12 @@ int adf_dev_stop(struct adf_accel_dev *accel_dev) clear_bit(ADF_STATUS_STARTING, &accel_dev->status); clear_bit(ADF_STATUS_STARTED, &accel_dev->status); - if (qat_algs_unregister()) + if (!list_empty(&accel_dev->crypto_list) && qat_algs_unregister()) dev_err(&GET_DEV(accel_dev), "Failed to unregister crypto algs\n"); - qat_asym_algs_unregister(); + if (!list_empty(&accel_dev->crypto_list)) + qat_asym_algs_unregister(); list_for_each(list_itr, &service_table) { service = list_entry(list_itr, struct service_hndl, list); @@ -363,6 +366,7 @@ void adf_dev_shutdown(struct adf_accel_dev *accel_dev) if (hw_data->exit_admin_comms) hw_data->exit_admin_comms(accel_dev); + hw_data->disable_iov(accel_dev); adf_cleanup_etr_data(accel_dev); } EXPORT_SYMBOL_GPL(adf_dev_shutdown); diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c new file mode 100644 index 000000000000..c5790cd0b91b --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -0,0 +1,336 @@ +/* + 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) 2015 Intel Corporation. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2015 Intel Corporation. + 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 of 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 "adf_accel_devices.h" +#include "adf_common_drv.h" +#include "adf_pf2vf_msg.h" + +#define ADF_DH895XCC_EP_OFFSET 0x3A000 +#define ADF_DH895XCC_ERRMSK3 (ADF_DH895XCC_EP_OFFSET + 0x1C) +#define ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask) ((vf_mask & 0xFFFF) << 9) +#define ADF_DH895XCC_ERRMSK5 (ADF_DH895XCC_EP_OFFSET + 0xDC) +#define ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask) (vf_mask >> 16) + +/** + * adf_enable_pf2vf_interrupts() - Enable PF to VF interrupts + * @accel_dev: Pointer to acceleration device. + * + * Function enables PF to VF interrupts + */ +void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev) +{ + struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + void __iomem *pmisc_bar_addr = + pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr; + + ADF_CSR_WR(pmisc_bar_addr, hw_data->get_vintmsk_offset(0), 0x0); +} +EXPORT_SYMBOL_GPL(adf_enable_pf2vf_interrupts); + +/** + * adf_disable_pf2vf_interrupts() - Disable PF to VF interrupts + * @accel_dev: Pointer to acceleration device. + * + * Function disables PF to VF interrupts + */ +void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev) +{ + struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + void __iomem *pmisc_bar_addr = + pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr; + + ADF_CSR_WR(pmisc_bar_addr, hw_data->get_vintmsk_offset(0), 0x2); +} +EXPORT_SYMBOL_GPL(adf_disable_pf2vf_interrupts); + +void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, + u32 vf_mask) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + struct adf_bar *pmisc = + &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; + void __iomem *pmisc_addr = pmisc->virt_addr; + u32 reg; + + /* Enable VF2PF Messaging Ints - VFs 1 through 16 per vf_mask[15:0] */ + if (vf_mask & 0xFFFF) { + reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK3); + reg &= ~ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask); + ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK3, reg); + } + + /* Enable VF2PF Messaging Ints - VFs 17 through 32 per vf_mask[31:16] */ + if (vf_mask >> 16) { + reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK5); + reg &= ~ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask); + ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK5, reg); + } +} + +/** + * adf_disable_pf2vf_interrupts() - Disable VF to PF interrupts + * @accel_dev: Pointer to acceleration device. + * + * Function disables VF to PF interrupts + */ +void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + struct adf_bar *pmisc = + &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; + void __iomem *pmisc_addr = pmisc->virt_addr; + u32 reg; + + /* Disable VF2PF interrupts for VFs 1 through 16 per vf_mask[15:0] */ + if (vf_mask & 0xFFFF) { + reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK3) | + ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask); + ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK3, reg); + } + + /* Disable VF2PF interrupts for VFs 17 through 32 per vf_mask[31:16] */ + if (vf_mask >> 16) { + reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK5) | + ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask); + ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK5, reg); + } +} +EXPORT_SYMBOL_GPL(adf_disable_vf2pf_interrupts); + +static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) +{ + struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + void __iomem *pmisc_bar_addr = + pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr; + u32 val, pf2vf_offset, count = 0; + u32 local_in_use_mask, local_in_use_pattern; + u32 remote_in_use_mask, remote_in_use_pattern; + struct mutex *lock; /* lock preventing concurrent acces of CSR */ + u32 int_bit; + int ret = 0; + + if (accel_dev->is_vf) { + pf2vf_offset = hw_data->get_pf2vf_offset(0); + lock = &accel_dev->vf.vf2pf_lock; + local_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK; + local_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF; + remote_in_use_mask = ADF_PF2VF_IN_USE_BY_PF_MASK; + remote_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF; + int_bit = ADF_VF2PF_INT; + } else { + pf2vf_offset = hw_data->get_pf2vf_offset(vf_nr); + lock = &accel_dev->pf.vf_info[vf_nr].pf2vf_lock; + local_in_use_mask = ADF_PF2VF_IN_USE_BY_PF_MASK; + local_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF; + remote_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK; + remote_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF; + int_bit = ADF_PF2VF_INT; + } + + mutex_lock(lock); + + /* Check if PF2VF CSR is in use by remote function */ + val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset); + if ((val & remote_in_use_mask) == remote_in_use_pattern) { + dev_dbg(&GET_DEV(accel_dev), + "PF2VF CSR in use by remote function\n"); + ret = -EBUSY; + goto out; + } + + /* Attempt to get ownership of PF2VF CSR */ + msg &= ~local_in_use_mask; + msg |= local_in_use_pattern; + ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, msg); + + /* Wait in case remote func also attempting to get ownership */ + msleep(ADF_IOV_MSG_COLLISION_DETECT_DELAY); + + val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset); + if ((val & local_in_use_mask) != local_in_use_pattern) { + dev_dbg(&GET_DEV(accel_dev), + "PF2VF CSR in use by remote - collision detected\n"); + ret = -EBUSY; + goto out; + } + + /* + * This function now owns the PV2VF CSR. The IN_USE_BY pattern must + * remain in the PF2VF CSR for all writes including ACK from remote + * until this local function relinquishes the CSR. Send the message + * by interrupting the remote. + */ + ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, msg | int_bit); + + /* Wait for confirmation from remote func it received the message */ + do { + msleep(ADF_IOV_MSG_ACK_DELAY); + val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset); + } while ((val & int_bit) && (count++ < ADF_IOV_MSG_ACK_MAX_RETRY)); + + if (val & int_bit) { + dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n"); + val &= ~int_bit; + ret = -EIO; + } + + /* Finished with PF2VF CSR; relinquish it and leave msg in CSR */ + ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, val & ~local_in_use_mask); +out: + mutex_unlock(lock); + return ret; +} + +/** + * adf_iov_putmsg() - send PF2VF message + * @accel_dev: Pointer to acceleration device. + * @msg: Message to send + * @vf_nr: VF number to which the message will be sent + * + * Function sends a messge from the PF to a VF + * + * Return: 0 on success, error code otherwise. + */ +int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) +{ + u32 count = 0; + int ret; + + do { + ret = __adf_iov_putmsg(accel_dev, msg, vf_nr); + if (ret) + msleep(ADF_IOV_MSG_RETRY_DELAY); + } while (ret && (count++ < ADF_IOV_MSG_MAX_RETRIES)); + + return ret; +} +EXPORT_SYMBOL_GPL(adf_iov_putmsg); + +void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev) +{ + struct adf_accel_vf_info *vf; + u32 msg = (ADF_PF2VF_MSGORIGIN_SYSTEM | + (ADF_PF2VF_MSGTYPE_RESTARTING << ADF_PF2VF_MSGTYPE_SHIFT)); + int i, num_vfs = pci_num_vf(accel_to_pci_dev(accel_dev)); + + for (i = 0, vf = accel_dev->pf.vf_info; i < num_vfs; i++, vf++) { + if (vf->init && adf_iov_putmsg(accel_dev, msg, i)) + dev_err(&GET_DEV(accel_dev), + "Failed to send restarting msg to VF%d\n", i); + } +} + +static int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev) +{ + unsigned long timeout = msecs_to_jiffies(ADF_IOV_MSG_RESP_TIMEOUT); + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + u32 msg = 0; + int ret; + + msg = ADF_VF2PF_MSGORIGIN_SYSTEM; + msg |= ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ << ADF_VF2PF_MSGTYPE_SHIFT; + msg |= ADF_PFVF_COMPATIBILITY_VERSION << ADF_VF2PF_COMPAT_VER_REQ_SHIFT; + BUILD_BUG_ON(ADF_PFVF_COMPATIBILITY_VERSION > 255); + + /* Send request from VF to PF */ + ret = adf_iov_putmsg(accel_dev, msg, 0); + if (ret) { + dev_err(&GET_DEV(accel_dev), + "Failed to send Compatibility Version Request.\n"); + return ret; + } + + /* Wait for response */ + if (!wait_for_completion_timeout(&accel_dev->vf.iov_msg_completion, + timeout)) { + dev_err(&GET_DEV(accel_dev), + "IOV request/response message timeout expired\n"); + return -EIO; + } + + /* Response from PF received, check compatibility */ + switch (accel_dev->vf.compatible) { + case ADF_PF2VF_VF_COMPATIBLE: + break; + case ADF_PF2VF_VF_COMPAT_UNKNOWN: + /* VF is newer than PF and decides whether it is compatible */ + if (accel_dev->vf.pf_version >= hw_data->min_iov_compat_ver) + break; + /* fall through */ + case ADF_PF2VF_VF_INCOMPATIBLE: + dev_err(&GET_DEV(accel_dev), + "PF (vers %d) and VF (vers %d) are not compatible\n", + accel_dev->vf.pf_version, + ADF_PFVF_COMPATIBILITY_VERSION); + return -EINVAL; + default: + dev_err(&GET_DEV(accel_dev), + "Invalid response from PF; assume not compatible\n"); + return -EINVAL; + } + return ret; +} + +/** + * adf_enable_vf2pf_comms() - Function enables communication from vf to pf + * + * @accel_dev: Pointer to acceleration device virtual function. + * + * Return: 0 on success, error code otherwise. + */ +int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev) +{ + adf_enable_pf2vf_interrupts(accel_dev); + return adf_vf2pf_request_version(accel_dev); +} +EXPORT_SYMBOL_GPL(adf_enable_vf2pf_comms); diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h new file mode 100644 index 000000000000..3ceaa3829414 --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h @@ -0,0 +1,144 @@ +/* + 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) 2015 Intel Corporation. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2015 Intel Corporation. + 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 of 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 ADF_PF2VF_MSG_H +#define ADF_PF2VF_MSG_H + +/* + * PF<->VF Messaging + * The PF has an array of 32-bit PF2VF registers, one for each VF. The + * PF can access all these registers; each VF can access only the one + * register associated with that particular VF. + * + * The register functionally is split into two parts: + * The bottom half is for PF->VF messages. In particular when the first + * bit of this register (bit 0) gets set an interrupt will be triggered + * in the respective VF. + * The top half is for VF->PF messages. In particular when the first bit + * of this half of register (bit 16) gets set an interrupt will be triggered + * in the PF. + * + * The remaining bits within this register are available to encode messages. + * and implement a collision control mechanism to prevent concurrent use of + * the PF2VF register by both the PF and VF. + * + * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 + * _______________________________________________ + * | | | | | | | | | | | | | | | | | + * +-----------------------------------------------+ + * \___________________________/ \_________/ ^ ^ + * ^ ^ | | + * | | | VF2PF Int + * | | Message Origin + * | Message Type + * Message-specific Data/Reserved + * + * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + * _______________________________________________ + * | | | | | | | | | | | | | | | | | + * +-----------------------------------------------+ + * \___________________________/ \_________/ ^ ^ + * ^ ^ | | + * | | | PF2VF Int + * | | Message Origin + * | Message Type + * Message-specific Data/Reserved + * + * Message Origin (Should always be 1) + * A legacy out-of-tree QAT driver allowed for a set of messages not supported + * by this driver; these had a Msg Origin of 0 and are ignored by this driver. + * + * When a PF or VF attempts to send a message in the lower or upper 16 bits, + * respectively, the other 16 bits are written to first with a defined + * IN_USE_BY pattern as part of a collision control scheme (see adf_iov_putmsg). + */ + +#define ADF_PFVF_COMPATIBILITY_VERSION 0x1 /* PF<->VF compat */ + +/* PF->VF messages */ +#define ADF_PF2VF_INT BIT(0) +#define ADF_PF2VF_MSGORIGIN_SYSTEM BIT(1) +#define ADF_PF2VF_MSGTYPE_MASK 0x0000003C +#define ADF_PF2VF_MSGTYPE_SHIFT 2 +#define ADF_PF2VF_MSGTYPE_RESTARTING 0x01 +#define ADF_PF2VF_MSGTYPE_VERSION_RESP 0x02 +#define ADF_PF2VF_IN_USE_BY_PF 0x6AC20000 +#define ADF_PF2VF_IN_USE_BY_PF_MASK 0xFFFE0000 + +/* PF->VF Version Response */ +#define ADF_PF2VF_VERSION_RESP_VERS_MASK 0x00003FC0 +#define ADF_PF2VF_VERSION_RESP_VERS_SHIFT 6 +#define ADF_PF2VF_VERSION_RESP_RESULT_MASK 0x0000C000 +#define ADF_PF2VF_VERSION_RESP_RESULT_SHIFT 14 +#define ADF_PF2VF_VF_COMPATIBLE 1 +#define ADF_PF2VF_VF_INCOMPATIBLE 2 +#define ADF_PF2VF_VF_COMPAT_UNKNOWN 3 + +/* VF->PF messages */ +#define ADF_VF2PF_IN_USE_BY_VF 0x00006AC2 +#define ADF_VF2PF_IN_USE_BY_VF_MASK 0x0000FFFE +#define ADF_VF2PF_INT BIT(16) +#define ADF_VF2PF_MSGORIGIN_SYSTEM BIT(17) +#define ADF_VF2PF_MSGTYPE_MASK 0x003C0000 +#define ADF_VF2PF_MSGTYPE_SHIFT 18 +#define ADF_VF2PF_MSGTYPE_INIT 0x3 +#define ADF_VF2PF_MSGTYPE_SHUTDOWN 0x4 +#define ADF_VF2PF_MSGTYPE_VERSION_REQ 0x5 +#define ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ 0x6 + +/* VF->PF Compatible Version Request */ +#define ADF_VF2PF_COMPAT_VER_REQ_SHIFT 22 + +/* Collision detection */ +#define ADF_IOV_MSG_COLLISION_DETECT_DELAY 10 +#define ADF_IOV_MSG_ACK_DELAY 2 +#define ADF_IOV_MSG_ACK_MAX_RETRY 100 +#define ADF_IOV_MSG_RETRY_DELAY 5 +#define ADF_IOV_MSG_MAX_RETRIES 3 +#define ADF_IOV_MSG_RESP_TIMEOUT (ADF_IOV_MSG_ACK_DELAY * \ + ADF_IOV_MSG_ACK_MAX_RETRY + \ + ADF_IOV_MSG_COLLISION_DETECT_DELAY) +#endif /* ADF_IOV_MSG_H */ diff --git a/drivers/crypto/qat/qat_common/adf_sriov.c b/drivers/crypto/qat/qat_common/adf_sriov.c new file mode 100644 index 000000000000..a766fb59e71b --- /dev/null +++ b/drivers/crypto/qat/qat_common/adf_sriov.c @@ -0,0 +1,406 @@ +/* + 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) 2015 Intel Corporation. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2015 Intel Corporation. + 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 of 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 "adf_common_drv.h" +#include "adf_cfg.h" +#include "adf_pf2vf_msg.h" + +static struct workqueue_struct *pf2vf_resp_wq; + +#define ME2FUNCTION_MAP_A_OFFSET (0x3A400 + 0x190) +#define ME2FUNCTION_MAP_A_NUM_REGS 96 + +#define ME2FUNCTION_MAP_B_OFFSET (0x3A400 + 0x310) +#define ME2FUNCTION_MAP_B_NUM_REGS 12 + +#define ME2FUNCTION_MAP_REG_SIZE 4 +#define ME2FUNCTION_MAP_VALID BIT(7) + +#define READ_CSR_ME2FUNCTION_MAP_A(pmisc_bar_addr, index) \ + ADF_CSR_RD(pmisc_bar_addr, ME2FUNCTION_MAP_A_OFFSET + \ + ME2FUNCTION_MAP_REG_SIZE * index) + +#define WRITE_CSR_ME2FUNCTION_MAP_A(pmisc_bar_addr, index, value) \ + ADF_CSR_WR(pmisc_bar_addr, ME2FUNCTION_MAP_A_OFFSET + \ + ME2FUNCTION_MAP_REG_SIZE * index, value) + +#define READ_CSR_ME2FUNCTION_MAP_B(pmisc_bar_addr, index) \ + ADF_CSR_RD(pmisc_bar_addr, ME2FUNCTION_MAP_B_OFFSET + \ + ME2FUNCTION_MAP_REG_SIZE * index) + +#define WRITE_CSR_ME2FUNCTION_MAP_B(pmisc_bar_addr, index, value) \ + ADF_CSR_WR(pmisc_bar_addr, ME2FUNCTION_MAP_B_OFFSET + \ + ME2FUNCTION_MAP_REG_SIZE * index, value) + +struct adf_pf2vf_resp_data { + struct work_struct pf2vf_resp_work; + struct adf_accel_dev *accel_dev; + u32 resp; + u8 vf_nr; +}; + +static void adf_iov_send_resp(struct work_struct *work) +{ + struct adf_pf2vf_resp_data *pf2vf_resp_data = + container_of(work, struct adf_pf2vf_resp_data, pf2vf_resp_work); + + if (adf_iov_putmsg(pf2vf_resp_data->accel_dev, pf2vf_resp_data->resp, + pf2vf_resp_data->vf_nr)) { + dev_err(&GET_DEV(pf2vf_resp_data->accel_dev), + "Failed to send response\n"); + } + + kfree(pf2vf_resp_data); +} + +static void adf_vf2pf_bh_handler(void *data) +{ + struct adf_accel_vf_info *vf_info = (struct adf_accel_vf_info *)data; + struct adf_accel_dev *accel_dev = vf_info->accel_dev; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + struct adf_bar *pmisc = + &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; + void __iomem *pmisc_addr = pmisc->virt_addr; + u32 msg; + + /* Read message from the VF */ + msg = ADF_CSR_RD(pmisc_addr, hw_data->get_pf2vf_offset(vf_info->vf_nr)); + + if (!(msg & ADF_VF2PF_MSGORIGIN_SYSTEM)) + /* Ignore legacy non-system (non-kernel) VF2PF messages */ + goto err; + + switch ((msg & ADF_VF2PF_MSGTYPE_MASK) >> ADF_VF2PF_MSGTYPE_SHIFT) { + case ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ: + { + u8 vf_compat_ver = msg >> ADF_VF2PF_COMPAT_VER_REQ_SHIFT; + struct adf_pf2vf_resp_data *pf2vf_resp_data; + u32 resp = (ADF_PF2VF_MSGORIGIN_SYSTEM | + (ADF_PF2VF_MSGTYPE_VERSION_RESP << + ADF_PF2VF_MSGTYPE_SHIFT) | + (ADF_PFVF_COMPATIBILITY_VERSION << + ADF_PF2VF_VERSION_RESP_VERS_SHIFT)); + + dev_dbg(&GET_DEV(accel_dev), + "Compatibility Version Request from VF%d vers=%u\n", + vf_info->vf_nr + 1, vf_compat_ver); + + if (vf_compat_ver < hw_data->min_iov_compat_ver) { + dev_err(&GET_DEV(accel_dev), + "VF (vers %d) incompatible with PF (vers %d)\n", + vf_compat_ver, ADF_PFVF_COMPATIBILITY_VERSION); + resp |= ADF_PF2VF_VF_INCOMPATIBLE << + ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + } else if (vf_compat_ver > ADF_PFVF_COMPATIBILITY_VERSION) { + dev_err(&GET_DEV(accel_dev), + "VF (vers %d) compat with PF (vers %d) unkn.\n", + vf_compat_ver, ADF_PFVF_COMPATIBILITY_VERSION); + resp |= ADF_PF2VF_VF_COMPAT_UNKNOWN << + ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + } else { + dev_dbg(&GET_DEV(accel_dev), + "VF (vers %d) compatible with PF (vers %d)\n", + vf_compat_ver, ADF_PFVF_COMPATIBILITY_VERSION); + resp |= ADF_PF2VF_VF_COMPATIBLE << + ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + } + + pf2vf_resp_data = kzalloc(sizeof(*pf2vf_resp_data), GFP_ATOMIC); + if (!pf2vf_resp_data) + return; + + pf2vf_resp_data->accel_dev = accel_dev; + pf2vf_resp_data->vf_nr = vf_info->vf_nr; + pf2vf_resp_data->resp = resp; + INIT_WORK(&pf2vf_resp_data->pf2vf_resp_work, adf_iov_send_resp); + queue_work(pf2vf_resp_wq, &pf2vf_resp_data->pf2vf_resp_work); + } + break; + case ADF_VF2PF_MSGTYPE_INIT: + { + dev_dbg(&GET_DEV(accel_dev), + "Init message received from VF%d 0x%x\n", + vf_info->vf_nr + 1, msg); + vf_info->init = true; + } + break; + case ADF_VF2PF_MSGTYPE_SHUTDOWN: + { + dev_dbg(&GET_DEV(accel_dev), + "Shutdown message received from VF%d 0x%x\n", + vf_info->vf_nr + 1, msg); + vf_info->init = false; + } + break; + case ADF_VF2PF_MSGTYPE_VERSION_REQ: + dev_err(&GET_DEV(accel_dev), + "Incompatible VersionRequest received from VF%d 0x%x\n", + vf_info->vf_nr + 1, msg); + break; + default: + goto err; + } + + /* To ACK, clear the VF2PFINT bit */ + msg &= ~ADF_VF2PF_INT; + ADF_CSR_WR(pmisc_addr, hw_data->get_pf2vf_offset(vf_info->vf_nr), msg); + + /* re-enable interrupt on PF from this VF */ + adf_enable_vf2pf_interrupts(accel_dev, (1 << vf_info->vf_nr)); + return; +err: + dev_err(&GET_DEV(accel_dev), "Unknown message from VF%d (0x%x);\n", + vf_info->vf_nr + 1, msg); +} + +static int adf_enable_sriov(struct adf_accel_dev *accel_dev) +{ + struct pci_dev *pdev = accel_to_pci_dev(accel_dev); + int totalvfs = pci_sriov_get_totalvfs(pdev); + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + struct adf_bar *pmisc = + &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; + void __iomem *pmisc_addr = pmisc->virt_addr; + struct adf_accel_vf_info *vf_info; + int i, ret; + u32 reg; + + /* Workqueue for PF2VF responses */ + pf2vf_resp_wq = create_workqueue("qat_pf2vf_resp_wq"); + if (!pf2vf_resp_wq) + return -ENOMEM; + + for (i = 0, vf_info = accel_dev->pf.vf_info; i < totalvfs; + i++, vf_info++) { + /* This ptr will be populated when VFs will be created */ + vf_info->accel_dev = accel_dev; + vf_info->vf_nr = i; + + tasklet_init(&vf_info->vf2pf_bh_tasklet, + (void *)adf_vf2pf_bh_handler, + (unsigned long)vf_info); + mutex_init(&vf_info->pf2vf_lock); + ratelimit_state_init(&vf_info->vf2pf_ratelimit, + DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); + } + + /* Set Valid bits in ME Thread to PCIe Function Mapping Group A */ + for (i = 0; i < ME2FUNCTION_MAP_A_NUM_REGS; i++) { + reg = READ_CSR_ME2FUNCTION_MAP_A(pmisc_addr, i); + reg |= ME2FUNCTION_MAP_VALID; + WRITE_CSR_ME2FUNCTION_MAP_A(pmisc_addr, i, reg); + } + + /* Set Valid bits in ME Thread to PCIe Function Mapping Group B */ + for (i = 0; i < ME2FUNCTION_MAP_B_NUM_REGS; i++) { + reg = READ_CSR_ME2FUNCTION_MAP_B(pmisc_addr, i); + reg |= ME2FUNCTION_MAP_VALID; + WRITE_CSR_ME2FUNCTION_MAP_B(pmisc_addr, i, reg); + } + + /* Enable VF to PF interrupts for all VFs */ + adf_enable_vf2pf_interrupts(accel_dev, GENMASK_ULL(totalvfs - 1, 0)); + + /* + * Due to the hardware design, when SR-IOV and the ring arbiter + * are enabled all the VFs supported in hardware must be enabled in + * order for all the hardware resources (i.e. bundles) to be usable. + * When SR-IOV is enabled, each of the VFs will own one bundle. + */ + ret = pci_enable_sriov(pdev, totalvfs); + if (ret) + return ret; + + return 0; +} + +/** + * adf_disable_sriov() - Disable SRIOV for the device + * @pdev: Pointer to pci device. + * + * Function disables SRIOV for the pci device. + * + * Return: 0 on success, error code otherwise. + */ +void adf_disable_sriov(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + struct adf_bar *pmisc = + &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; + void __iomem *pmisc_addr = pmisc->virt_addr; + int totalvfs = pci_sriov_get_totalvfs(accel_to_pci_dev(accel_dev)); + struct adf_accel_vf_info *vf; + u32 reg; + int i; + + if (!accel_dev->pf.vf_info) + return; + + adf_pf2vf_notify_restarting(accel_dev); + + pci_disable_sriov(accel_to_pci_dev(accel_dev)); + + /* Disable VF to PF interrupts */ + adf_disable_vf2pf_interrupts(accel_dev, 0xFFFFFFFF); + + /* Clear Valid bits in ME Thread to PCIe Function Mapping Group A */ + for (i = 0; i < ME2FUNCTION_MAP_A_NUM_REGS; i++) { + reg = READ_CSR_ME2FUNCTION_MAP_A(pmisc_addr, i); + reg &= ~ME2FUNCTION_MAP_VALID; + WRITE_CSR_ME2FUNCTION_MAP_A(pmisc_addr, i, reg); + } + + /* Clear Valid bits in ME Thread to PCIe Function Mapping Group B */ + for (i = 0; i < ME2FUNCTION_MAP_B_NUM_REGS; i++) { + reg = READ_CSR_ME2FUNCTION_MAP_B(pmisc_addr, i); + reg &= ~ME2FUNCTION_MAP_VALID; + WRITE_CSR_ME2FUNCTION_MAP_B(pmisc_addr, i, reg); + } + + for (i = 0, vf = accel_dev->pf.vf_info; i < totalvfs; i++, vf++) { + tasklet_disable(&vf->vf2pf_bh_tasklet); + tasklet_kill(&vf->vf2pf_bh_tasklet); + mutex_destroy(&vf->pf2vf_lock); + } + + kfree(accel_dev->pf.vf_info); + accel_dev->pf.vf_info = NULL; + + if (pf2vf_resp_wq) { + destroy_workqueue(pf2vf_resp_wq); + pf2vf_resp_wq = NULL; + } +} +EXPORT_SYMBOL_GPL(adf_disable_sriov); + +/** + * adf_sriov_configure() - Enable SRIOV for the device + * @pdev: Pointer to pci device. + * + * Function enables SRIOV for the pci device. + * + * Return: 0 on success, error code otherwise. + */ +int adf_sriov_configure(struct pci_dev *pdev, int numvfs) +{ + struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); + int totalvfs = pci_sriov_get_totalvfs(pdev); + unsigned long val; + int ret; + + if (!accel_dev) { + dev_err(&pdev->dev, "Failed to find accel_dev\n"); + return -EFAULT; + } + + if (!iommu_present(&pci_bus_type)) { + dev_err(&pdev->dev, + "IOMMU must be enabled for SR-IOV to work\n"); + return -EINVAL; + } + + if (accel_dev->pf.vf_info) { + dev_info(&pdev->dev, "Already enabled for this device\n"); + return -EINVAL; + } + + if (adf_dev_started(accel_dev)) { + if (adf_devmgr_in_reset(accel_dev) || + adf_dev_in_use(accel_dev)) { + dev_err(&GET_DEV(accel_dev), "Device busy\n"); + return -EBUSY; + } + + if (adf_dev_stop(accel_dev)) { + dev_err(&GET_DEV(accel_dev), + "Failed to stop qat_dev%d\n", + accel_dev->accel_id); + return -EFAULT; + } + + adf_dev_shutdown(accel_dev); + } + + if (adf_cfg_section_add(accel_dev, ADF_KERNEL_SEC)) + return -EFAULT; + val = 0; + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + ADF_NUM_CY, (void *)&val, ADF_DEC)) + return -EFAULT; + + set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status); + + /* Allocate memory for VF info structs */ + accel_dev->pf.vf_info = kcalloc(totalvfs, + sizeof(struct adf_accel_vf_info), + GFP_KERNEL); + if (!accel_dev->pf.vf_info) + return -ENOMEM; + + if (adf_dev_init(accel_dev)) { + dev_err(&GET_DEV(accel_dev), "Failed to init qat_dev%d\n", + accel_dev->accel_id); + return -EFAULT; + } + + if (adf_dev_start(accel_dev)) { + dev_err(&GET_DEV(accel_dev), "Failed to start qat_dev%d\n", + accel_dev->accel_id); + return -EFAULT; + } + + ret = adf_enable_sriov(accel_dev); + if (ret) + return ret; + + return numvfs; +} +EXPORT_SYMBOL_GPL(adf_sriov_configure); diff --git a/drivers/crypto/qat/qat_common/qat_crypto.c b/drivers/crypto/qat/qat_common/qat_crypto.c index 359ae94430b8..07c2f9f9d1fc 100644 --- a/drivers/crypto/qat/qat_common/qat_crypto.c +++ b/drivers/crypto/qat/qat_common/qat_crypto.c @@ -103,9 +103,11 @@ struct qat_crypto_instance *qat_crypto_get_instance_node(int node) list_for_each(itr, adf_devmgr_get_head()) { accel_dev = list_entry(itr, struct adf_accel_dev, list); + if ((node == dev_to_node(&GET_DEV(accel_dev)) || dev_to_node(&GET_DEV(accel_dev)) < 0) && - adf_dev_started(accel_dev)) + adf_dev_started(accel_dev) && + !list_empty(&accel_dev->crypto_list)) break; accel_dev = NULL; } diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c index a3b1be895af9..ff54257eced4 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include #include #include "adf_dh895xcc_hw_data.h" #include "adf_drv.h" @@ -161,6 +162,16 @@ void adf_get_arbiter_mapping(struct adf_accel_dev *accel_dev, } } +static uint32_t get_pf2vf_offset(uint32_t i) +{ + return ADF_DH895XCC_PF2VF_OFFSET(i); +} + +static uint32_t get_vintmsk_offset(uint32_t i) +{ + return ADF_DH895XCC_VINTMSK_OFFSET(i); +} + static void adf_enable_error_correction(struct adf_accel_dev *accel_dev) { struct adf_hw_device_data *hw_device = accel_dev->hw_device; @@ -197,11 +208,17 @@ static void adf_enable_ints(struct adf_accel_dev *accel_dev) /* Enable bundle and misc interrupts */ ADF_CSR_WR(addr, ADF_DH895XCC_SMIAPF0_MASK_OFFSET, - ADF_DH895XCC_SMIA0_MASK); + accel_dev->pf.vf_info ? 0 : + GENMASK_ULL(GET_MAX_BANKS(accel_dev) - 1, 0)); ADF_CSR_WR(addr, ADF_DH895XCC_SMIAPF1_MASK_OFFSET, ADF_DH895XCC_SMIA1_MASK); } +static int adf_pf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev) +{ + return 0; +} + void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) { hw_data->dev_class = &dh895xcc_class; @@ -221,17 +238,22 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) hw_data->get_num_aes = get_num_aes; hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; + hw_data->get_pf2vf_offset = get_pf2vf_offset; + hw_data->get_vintmsk_offset = get_vintmsk_offset; hw_data->get_sram_bar_id = get_sram_bar_id; hw_data->get_sku = get_sku; hw_data->fw_name = ADF_DH895XCC_FW; hw_data->fw_mmp_name = ADF_DH895XCC_MMP; hw_data->init_admin_comms = adf_init_admin_comms; hw_data->exit_admin_comms = adf_exit_admin_comms; + hw_data->disable_iov = adf_disable_sriov; hw_data->send_admin_init = adf_send_admin_init; hw_data->init_arb = adf_init_arb; hw_data->exit_arb = adf_exit_arb; hw_data->get_arb_mapping = adf_get_arbiter_mapping; hw_data->enable_ints = adf_enable_ints; + hw_data->enable_vf2pf_comms = adf_pf_enable_vf2pf_comms; + hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; } void adf_clean_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h index d410afb4f3d7..88dffb297346 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h @@ -80,6 +80,10 @@ #define ADF_DH895XCC_CERRSSMSH(i) (i * 0x4000 + 0x10) #define ADF_DH895XCC_ERRSSMSH_EN BIT(3) +#define ADF_DH895XCC_ERRSOU3 (0x3A000 + 0x00C) +#define ADF_DH895XCC_ERRSOU5 (0x3A000 + 0x0D8) +#define ADF_DH895XCC_PF2VF_OFFSET(i) (0x3A000 + 0x280 + ((i) * 0x04)) +#define ADF_DH895XCC_VINTMSK_OFFSET(i) (0x3A000 + 0x200 + ((i) * 0x04)) /* FW names */ #define ADF_DH895XCC_FW "qat_895xcc.bin" #define ADF_DH895XCC_MMP "qat_mmp.bin" diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c index 1837c32fa306..f8dd14f232c8 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c @@ -82,16 +82,21 @@ static struct pci_driver adf_driver = { .id_table = adf_pci_tbl, .name = adf_driver_name, .probe = adf_probe, - .remove = adf_remove + .remove = adf_remove, + .sriov_configure = adf_sriov_configure, }; +static void adf_cleanup_pci_dev(struct adf_accel_dev *accel_dev) +{ + pci_release_regions(accel_dev->accel_pci_dev.pci_dev); + pci_disable_device(accel_dev->accel_pci_dev.pci_dev); +} + static void adf_cleanup_accel(struct adf_accel_dev *accel_dev) { struct adf_accel_pci *accel_pci_dev = &accel_dev->accel_pci_dev; int i; - adf_dev_shutdown(accel_dev); - for (i = 0; i < ADF_PCI_MAX_BARS; i++) { struct adf_bar *bar = &accel_pci_dev->pci_bars[i]; @@ -108,13 +113,11 @@ static void adf_cleanup_accel(struct adf_accel_dev *accel_dev) break; } kfree(accel_dev->hw_device); + accel_dev->hw_device = NULL; } adf_cfg_dev_remove(accel_dev); debugfs_remove(accel_dev->debugfs_dir); - adf_devmgr_rm_dev(accel_dev); - pci_release_regions(accel_pci_dev->pci_dev); - pci_disable_device(accel_pci_dev->pci_dev); - kfree(accel_dev); + adf_devmgr_rm_dev(accel_dev, NULL); } static int adf_dev_configure(struct adf_accel_dev *accel_dev) @@ -205,7 +208,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct adf_hw_device_data *hw_data; char name[ADF_DEVICE_NAME_LENGTH]; unsigned int i, bar_nr; - int ret; + int ret, bar_mask; switch (ent->device) { case ADF_DH895XCC_PCI_DEVICE_ID: @@ -229,10 +232,12 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENOMEM; INIT_LIST_HEAD(&accel_dev->crypto_list); + accel_pci_dev = &accel_dev->accel_pci_dev; + accel_pci_dev->pci_dev = pdev; /* Add accel device to accel table. * This should be called before adf_cleanup_accel is called */ - if (adf_devmgr_add_dev(accel_dev)) { + if (adf_devmgr_add_dev(accel_dev, NULL)) { dev_err(&pdev->dev, "Failed to add new accelerator device.\n"); kfree(accel_dev); return -EFAULT; @@ -255,7 +260,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) default: return -ENODEV; } - accel_pci_dev = &accel_dev->accel_pci_dev; pci_read_config_byte(pdev, PCI_REVISION_ID, &accel_pci_dev->revid); pci_read_config_dword(pdev, ADF_DH895XCC_FUSECTL_OFFSET, &hw_data->fuses); @@ -264,7 +268,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw_data->accel_mask = hw_data->get_accel_mask(hw_data->fuses); hw_data->ae_mask = hw_data->get_ae_mask(hw_data->fuses); accel_pci_dev->sku = hw_data->get_sku(hw_data); - accel_pci_dev->pci_dev = pdev; /* If the device has no acceleration engines then ignore it. */ if (!hw_data->accel_mask || !hw_data->ae_mask || ((~hw_data->ae_mask) & 0x01)) { @@ -274,11 +277,14 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Create dev top level debugfs entry */ - snprintf(name, sizeof(name), "%s%s_dev%d", ADF_DEVICE_NAME_PREFIX, - hw_data->dev_class->name, hw_data->instance_id); + snprintf(name, sizeof(name), "%s%s_%02x:%02d.%02d", + ADF_DEVICE_NAME_PREFIX, hw_data->dev_class->name, + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); + accel_dev->debugfs_dir = debugfs_create_dir(name, NULL); if (!accel_dev->debugfs_dir) { - dev_err(&pdev->dev, "Could not create debugfs dir\n"); + dev_err(&pdev->dev, "Could not create debugfs dir %s\n", name); ret = -EINVAL; goto out_err; } @@ -301,7 +307,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) { dev_err(&pdev->dev, "No usable DMA configuration\n"); ret = -EFAULT; - goto out_err; + goto out_err_disable; } else { pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); } @@ -312,7 +318,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_request_regions(pdev, adf_driver_name)) { ret = -EFAULT; - goto out_err; + goto out_err_disable; } /* Read accelerator capabilities mask */ @@ -320,19 +326,21 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) &hw_data->accel_capabilities_mask); /* Find and map all the device's BARS */ - for (i = 0; i < ADF_PCI_MAX_BARS; i++) { - struct adf_bar *bar = &accel_pci_dev->pci_bars[i]; + i = 0; + bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); + for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask, + ADF_PCI_MAX_BARS * 2) { + struct adf_bar *bar = &accel_pci_dev->pci_bars[i++]; - bar_nr = i * 2; bar->base_addr = pci_resource_start(pdev, bar_nr); if (!bar->base_addr) break; bar->size = pci_resource_len(pdev, bar_nr); bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0); if (!bar->virt_addr) { - dev_err(&pdev->dev, "Failed to map BAR %d\n", i); + dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr); ret = -EFAULT; - goto out_err; + goto out_err_free_reg; } } pci_set_master(pdev); @@ -340,32 +348,40 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (adf_enable_aer(accel_dev, &adf_driver)) { dev_err(&pdev->dev, "Failed to enable aer\n"); ret = -EFAULT; - goto out_err; + goto out_err_free_reg; } if (pci_save_state(pdev)) { dev_err(&pdev->dev, "Failed to save pci state\n"); ret = -ENOMEM; - goto out_err; + goto out_err_free_reg; } ret = adf_dev_configure(accel_dev); if (ret) - goto out_err; + goto out_err_free_reg; ret = adf_dev_init(accel_dev); if (ret) - goto out_err; + goto out_err_dev_shutdown; ret = adf_dev_start(accel_dev); - if (ret) { - adf_dev_stop(accel_dev); - goto out_err; - } + if (ret) + goto out_err_dev_stop; - return 0; + return ret; + +out_err_dev_stop: + adf_dev_stop(accel_dev); +out_err_dev_shutdown: + adf_dev_shutdown(accel_dev); +out_err_free_reg: + pci_release_regions(accel_pci_dev->pci_dev); +out_err_disable: + pci_disable_device(accel_pci_dev->pci_dev); out_err: adf_cleanup_accel(accel_dev); + kfree(accel_dev); return ret; } @@ -379,8 +395,12 @@ static void adf_remove(struct pci_dev *pdev) } if (adf_dev_stop(accel_dev)) dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n"); + + adf_dev_shutdown(accel_dev); adf_disable_aer(accel_dev); adf_cleanup_accel(accel_dev); + adf_cleanup_pci_dev(accel_dev); + kfree(accel_dev); } static int __init adfdrv_init(void) diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_isr.c b/drivers/crypto/qat/qat_dh895xcc/adf_isr.c index 0d03c109c2d3..5570f78795c1 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_isr.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_isr.c @@ -59,21 +59,30 @@ #include #include #include "adf_drv.h" +#include "adf_dh895xcc_hw_data.h" static int adf_enable_msix(struct adf_accel_dev *accel_dev) { struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev; struct adf_hw_device_data *hw_data = accel_dev->hw_device; - uint32_t msix_num_entries = hw_data->num_banks + 1; - int i; - - for (i = 0; i < msix_num_entries; i++) - pci_dev_info->msix_entries.entries[i].entry = i; + u32 msix_num_entries = 1; + + /* If SR-IOV is disabled, add entries for each bank */ + if (!accel_dev->pf.vf_info) { + int i; + + msix_num_entries += hw_data->num_banks; + for (i = 0; i < msix_num_entries; i++) + pci_dev_info->msix_entries.entries[i].entry = i; + } else { + pci_dev_info->msix_entries.entries[0].entry = + hw_data->num_banks; + } if (pci_enable_msix_exact(pci_dev_info->pci_dev, pci_dev_info->msix_entries.entries, msix_num_entries)) { - dev_err(&GET_DEV(accel_dev), "Failed to enable MSIX IRQ\n"); + dev_err(&GET_DEV(accel_dev), "Failed to enable MSI-X IRQ(s)\n"); return -EFAULT; } return 0; @@ -97,9 +106,58 @@ static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr) { struct adf_accel_dev *accel_dev = dev_ptr; - dev_info(&GET_DEV(accel_dev), "qat_dev%d spurious AE interrupt\n", - accel_dev->accel_id); - return IRQ_HANDLED; +#ifdef CONFIG_PCI_IOV + /* If SR-IOV is enabled (vf_info is non-NULL), check for VF->PF ints */ + if (accel_dev->pf.vf_info) { + void __iomem *pmisc_bar_addr = + (&GET_BARS(accel_dev)[ADF_DH895XCC_PMISC_BAR])->virt_addr; + u32 vf_mask; + + /* Get the interrupt sources triggered by VFs */ + vf_mask = ((ADF_CSR_RD(pmisc_bar_addr, ADF_DH895XCC_ERRSOU5) & + 0x0000FFFF) << 16) | + ((ADF_CSR_RD(pmisc_bar_addr, ADF_DH895XCC_ERRSOU3) & + 0x01FFFE00) >> 9); + + if (vf_mask) { + struct adf_accel_vf_info *vf_info; + bool irq_handled = false; + int i; + + /* Disable VF2PF interrupts for VFs with pending ints */ + adf_disable_vf2pf_interrupts(accel_dev, vf_mask); + + /* + * Schedule tasklets to handle VF2PF interrupt BHs + * unless the VF is malicious and is attempting to + * flood the host OS with VF2PF interrupts. + */ + for_each_set_bit(i, (const unsigned long *)&vf_mask, + (sizeof(vf_mask) * BITS_PER_BYTE)) { + vf_info = accel_dev->pf.vf_info + i; + + if (!__ratelimit(&vf_info->vf2pf_ratelimit)) { + dev_info(&GET_DEV(accel_dev), + "Too many ints from VF%d\n", + vf_info->vf_nr + 1); + continue; + } + + /* Tasklet will re-enable ints from this VF */ + tasklet_hi_schedule(&vf_info->vf2pf_bh_tasklet); + irq_handled = true; + } + + if (irq_handled) + return IRQ_HANDLED; + } + } +#endif /* CONFIG_PCI_IOV */ + + dev_dbg(&GET_DEV(accel_dev), "qat_dev%d spurious AE interrupt\n", + accel_dev->accel_id); + + return IRQ_NONE; } static int adf_request_irqs(struct adf_accel_dev *accel_dev) @@ -108,28 +166,32 @@ static int adf_request_irqs(struct adf_accel_dev *accel_dev) struct adf_hw_device_data *hw_data = accel_dev->hw_device; struct msix_entry *msixe = pci_dev_info->msix_entries.entries; struct adf_etr_data *etr_data = accel_dev->transport; - int ret, i; + int ret, i = 0; char *name; - /* Request msix irq for all banks */ - for (i = 0; i < hw_data->num_banks; i++) { - struct adf_etr_bank_data *bank = &etr_data->banks[i]; - unsigned int cpu, cpus = num_online_cpus(); - - name = *(pci_dev_info->msix_entries.names + i); - snprintf(name, ADF_MAX_MSIX_VECTOR_NAME, - "qat%d-bundle%d", accel_dev->accel_id, i); - ret = request_irq(msixe[i].vector, - adf_msix_isr_bundle, 0, name, bank); - if (ret) { - dev_err(&GET_DEV(accel_dev), - "failed to enable irq %d for %s\n", - msixe[i].vector, name); - return ret; + /* Request msix irq for all banks unless SR-IOV enabled */ + if (!accel_dev->pf.vf_info) { + for (i = 0; i < hw_data->num_banks; i++) { + struct adf_etr_bank_data *bank = &etr_data->banks[i]; + unsigned int cpu, cpus = num_online_cpus(); + + name = *(pci_dev_info->msix_entries.names + i); + snprintf(name, ADF_MAX_MSIX_VECTOR_NAME, + "qat%d-bundle%d", accel_dev->accel_id, i); + ret = request_irq(msixe[i].vector, + adf_msix_isr_bundle, 0, name, bank); + if (ret) { + dev_err(&GET_DEV(accel_dev), + "failed to enable irq %d for %s\n", + msixe[i].vector, name); + return ret; + } + + cpu = ((accel_dev->accel_id * hw_data->num_banks) + + i) % cpus; + irq_set_affinity_hint(msixe[i].vector, + get_cpu_mask(cpu)); } - - cpu = ((accel_dev->accel_id * hw_data->num_banks) + i) % cpus; - irq_set_affinity_hint(msixe[i].vector, get_cpu_mask(cpu)); } /* Request msix irq for AE */ @@ -152,11 +214,13 @@ static void adf_free_irqs(struct adf_accel_dev *accel_dev) struct adf_hw_device_data *hw_data = accel_dev->hw_device; struct msix_entry *msixe = pci_dev_info->msix_entries.entries; struct adf_etr_data *etr_data = accel_dev->transport; - int i; + int i = 0; - for (i = 0; i < hw_data->num_banks; i++) { - irq_set_affinity_hint(msixe[i].vector, NULL); - free_irq(msixe[i].vector, &etr_data->banks[i]); + if (pci_dev_info->msix_entries.num_entries > 1) { + for (i = 0; i < hw_data->num_banks; i++) { + irq_set_affinity_hint(msixe[i].vector, NULL); + free_irq(msixe[i].vector, &etr_data->banks[i]); + } } irq_set_affinity_hint(msixe[i].vector, NULL); free_irq(msixe[i].vector, accel_dev); @@ -168,7 +232,11 @@ static int adf_isr_alloc_msix_entry_table(struct adf_accel_dev *accel_dev) char **names; struct msix_entry *entries; struct adf_hw_device_data *hw_data = accel_dev->hw_device; - uint32_t msix_num_entries = hw_data->num_banks + 1; + u32 msix_num_entries = 1; + + /* If SR-IOV is disabled (vf_info is NULL), add entries for each bank */ + if (!accel_dev->pf.vf_info) + msix_num_entries += hw_data->num_banks; entries = kzalloc_node(msix_num_entries * sizeof(*entries), GFP_KERNEL, dev_to_node(&GET_DEV(accel_dev))); @@ -185,6 +253,7 @@ static int adf_isr_alloc_msix_entry_table(struct adf_accel_dev *accel_dev) if (!(*(names + i))) goto err; } + accel_dev->accel_pci_dev.msix_entries.num_entries = msix_num_entries; accel_dev->accel_pci_dev.msix_entries.entries = entries; accel_dev->accel_pci_dev.msix_entries.names = names; return 0; @@ -198,13 +267,11 @@ err: static void adf_isr_free_msix_entry_table(struct adf_accel_dev *accel_dev) { - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - uint32_t msix_num_entries = hw_data->num_banks + 1; char **names = accel_dev->accel_pci_dev.msix_entries.names; int i; kfree(accel_dev->accel_pci_dev.msix_entries.entries); - for (i = 0; i < msix_num_entries; i++) + for (i = 0; i < accel_dev->accel_pci_dev.msix_entries.num_entries; i++) kfree(*(names + i)); kfree(names); } -- cgit v1.3-6-gb490 From dd0f368398ea100e34259bf812bc482e15c81991 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 7 Aug 2015 11:34:31 -0700 Subject: crypto: qat - Add qat dh895xcc VF driver Add code specific for the dh895xcc virtual function. Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/Kconfig | 11 + drivers/crypto/qat/Makefile | 1 + drivers/crypto/qat/qat_dh895xccvf/Makefile | 5 + .../qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c | 172 +++++++++ .../qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h | 68 ++++ drivers/crypto/qat/qat_dh895xccvf/adf_drv.c | 393 +++++++++++++++++++++ drivers/crypto/qat/qat_dh895xccvf/adf_drv.h | 57 +++ drivers/crypto/qat/qat_dh895xccvf/adf_isr.c | 258 ++++++++++++++ 8 files changed, 965 insertions(+) create mode 100644 drivers/crypto/qat/qat_dh895xccvf/Makefile create mode 100644 drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c create mode 100644 drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h create mode 100644 drivers/crypto/qat/qat_dh895xccvf/adf_drv.c create mode 100644 drivers/crypto/qat/qat_dh895xccvf/adf_drv.h create mode 100644 drivers/crypto/qat/qat_dh895xccvf/adf_isr.c (limited to 'drivers') diff --git a/drivers/crypto/qat/Kconfig b/drivers/crypto/qat/Kconfig index d8c3d595d98b..95a956625a2e 100644 --- a/drivers/crypto/qat/Kconfig +++ b/drivers/crypto/qat/Kconfig @@ -21,3 +21,14 @@ config CRYPTO_DEV_QAT_DH895xCC To compile this as a module, choose M here: the module will be called qat_dh895xcc. + +config CRYPTO_DEV_QAT_DH895xCCVF + tristate "Support for Intel(R) DH895xCC Virtual Function" + select PCI_IOV + + help + Support for Intel(R) DH895xcc with Intel(R) QuickAssist Technology + Virtual Function for accelerating crypto and compression workloads. + + To compile this as a module, choose M here: the module + will be called qat_dh895xccvf. diff --git a/drivers/crypto/qat/Makefile b/drivers/crypto/qat/Makefile index d11481be225e..a3ce0b70e32f 100644 --- a/drivers/crypto/qat/Makefile +++ b/drivers/crypto/qat/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_CRYPTO_DEV_QAT) += qat_common/ obj-$(CONFIG_CRYPTO_DEV_QAT_DH895xCC) += qat_dh895xcc/ +obj-$(CONFIG_CRYPTO_DEV_QAT_DH895xCCVF) += qat_dh895xccvf/ diff --git a/drivers/crypto/qat/qat_dh895xccvf/Makefile b/drivers/crypto/qat/qat_dh895xccvf/Makefile new file mode 100644 index 000000000000..85399fcbbad4 --- /dev/null +++ b/drivers/crypto/qat/qat_dh895xccvf/Makefile @@ -0,0 +1,5 @@ +ccflags-y := -I$(src)/../qat_common +obj-$(CONFIG_CRYPTO_DEV_QAT_DH895xCCVF) += qat_dh895xccvf.o +qat_dh895xccvf-objs := adf_drv.o \ + adf_isr.o \ + adf_dh895xccvf_hw_data.o diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c new file mode 100644 index 000000000000..7bbf846a53ca --- /dev/null +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c @@ -0,0 +1,172 @@ +/* + 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) 2015 Intel Corporation. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2015 Intel Corporation. + 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 of 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 "adf_dh895xccvf_hw_data.h" +#include "adf_drv.h" + +static struct adf_hw_device_class dh895xcciov_class = { + .name = ADF_DH895XCCVF_DEVICE_NAME, + .type = DEV_DH895XCCVF, + .instances = 0 +}; + +static u32 get_accel_mask(u32 fuse) +{ + return ADF_DH895XCCIOV_ACCELERATORS_MASK; +} + +static u32 get_ae_mask(u32 fuse) +{ + return ADF_DH895XCCIOV_ACCELENGINES_MASK; +} + +static u32 get_num_accels(struct adf_hw_device_data *self) +{ + return ADF_DH895XCCIOV_MAX_ACCELERATORS; +} + +static u32 get_num_aes(struct adf_hw_device_data *self) +{ + return ADF_DH895XCCIOV_MAX_ACCELENGINES; +} + +static u32 get_misc_bar_id(struct adf_hw_device_data *self) +{ + return ADF_DH895XCCIOV_PMISC_BAR; +} + +static u32 get_etr_bar_id(struct adf_hw_device_data *self) +{ + return ADF_DH895XCCIOV_ETR_BAR; +} + +static enum dev_sku_info get_sku(struct adf_hw_device_data *self) +{ + return DEV_SKU_VF; +} + +static u32 get_pf2vf_offset(u32 i) +{ + return ADF_DH895XCCIOV_PF2VF_OFFSET; +} + +static u32 get_vintmsk_offset(u32 i) +{ + return ADF_DH895XCCIOV_VINTMSK_OFFSET; +} + +static int adf_vf_int_noop(struct adf_accel_dev *accel_dev) +{ + return 0; +} + +static void adf_vf_void_noop(struct adf_accel_dev *accel_dev) +{ +} + +static int adf_vf2pf_init(struct adf_accel_dev *accel_dev) +{ + u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM | + (ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT)); + + if (adf_iov_putmsg(accel_dev, msg, 0)) { + dev_err(&GET_DEV(accel_dev), + "Failed to send Init event to PF\n"); + return -EFAULT; + } + return 0; +} + +static void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev) +{ + u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM | + (ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT)); + + if (adf_iov_putmsg(accel_dev, msg, 0)) + dev_err(&GET_DEV(accel_dev), + "Failed to send Shutdown event to PF\n"); +} + +void adf_init_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data) +{ + hw_data->dev_class = &dh895xcciov_class; + hw_data->instance_id = dh895xcciov_class.instances++; + hw_data->num_banks = ADF_DH895XCCIOV_ETR_MAX_BANKS; + hw_data->num_accel = ADF_DH895XCCIOV_MAX_ACCELERATORS; + hw_data->num_logical_accel = 1; + hw_data->num_engines = ADF_DH895XCCIOV_MAX_ACCELENGINES; + hw_data->tx_rx_gap = ADF_DH895XCCIOV_RX_RINGS_OFFSET; + hw_data->tx_rings_mask = ADF_DH895XCCIOV_TX_RINGS_MASK; + hw_data->alloc_irq = adf_isr_resource_alloc; + hw_data->free_irq = adf_isr_resource_free; + hw_data->enable_error_correction = adf_vf_void_noop; + hw_data->init_admin_comms = adf_vf_int_noop; + hw_data->exit_admin_comms = adf_vf_void_noop; + hw_data->send_admin_init = adf_vf2pf_init; + hw_data->init_arb = adf_vf_int_noop; + hw_data->exit_arb = adf_vf_void_noop; + hw_data->disable_iov = adf_vf2pf_shutdown; + hw_data->get_accel_mask = get_accel_mask; + hw_data->get_ae_mask = get_ae_mask; + hw_data->get_num_accels = get_num_accels; + hw_data->get_num_aes = get_num_aes; + hw_data->get_etr_bar_id = get_etr_bar_id; + hw_data->get_misc_bar_id = get_misc_bar_id; + hw_data->get_pf2vf_offset = get_pf2vf_offset; + hw_data->get_vintmsk_offset = get_vintmsk_offset; + hw_data->get_sku = get_sku; + hw_data->enable_ints = adf_vf_void_noop; + hw_data->enable_vf2pf_comms = adf_enable_vf2pf_comms; + hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; +} + +void adf_clean_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data) +{ + hw_data->dev_class->instances--; +} diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h new file mode 100644 index 000000000000..8f6babfef629 --- /dev/null +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h @@ -0,0 +1,68 @@ +/* + 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) 2015 Intel Corporation. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2015 Intel Corporation. + 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 of 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 ADF_DH895XVF_HW_DATA_H_ +#define ADF_DH895XVF_HW_DATA_H_ + +#define ADF_DH895XCCIOV_PMISC_BAR 1 +#define ADF_DH895XCCIOV_ACCELERATORS_MASK 0x1 +#define ADF_DH895XCCIOV_ACCELENGINES_MASK 0x1 +#define ADF_DH895XCCIOV_MAX_ACCELERATORS 1 +#define ADF_DH895XCCIOV_MAX_ACCELENGINES 1 +#define ADF_DH895XCCIOV_RX_RINGS_OFFSET 8 +#define ADF_DH895XCCIOV_TX_RINGS_MASK 0xFF +#define ADF_DH895XCCIOV_ETR_BAR 0 +#define ADF_DH895XCCIOV_ETR_MAX_BANKS 1 + +#define ADF_DH895XCCIOV_PF2VF_OFFSET 0x200 +#define ADF_DH895XCC_PF2VF_PF2VFINT BIT(0) + +#define ADF_DH895XCCIOV_VINTSOU_OFFSET 0x204 +#define ADF_DH895XCC_VINTSOU_BUN BIT(0) +#define ADF_DH895XCC_VINTSOU_PF2VF BIT(1) + +#define ADF_DH895XCCIOV_VINTMSK_OFFSET 0x208 +#endif diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c new file mode 100644 index 000000000000..789426f21882 --- /dev/null +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c @@ -0,0 +1,393 @@ +/* + 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. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2014 Intel Corporation. + 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 of 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adf_dh895xccvf_hw_data.h" +#include "adf_drv.h" + +static const char adf_driver_name[] = ADF_DH895XCCVF_DEVICE_NAME; + +#define ADF_SYSTEM_DEVICE(device_id) \ + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} + +static const struct pci_device_id adf_pci_tbl[] = { + ADF_SYSTEM_DEVICE(ADF_DH895XCCIOV_PCI_DEVICE_ID), + {0,} +}; +MODULE_DEVICE_TABLE(pci, adf_pci_tbl); + +static int adf_probe(struct pci_dev *dev, const struct pci_device_id *ent); +static void adf_remove(struct pci_dev *dev); + +static struct pci_driver adf_driver = { + .id_table = adf_pci_tbl, + .name = adf_driver_name, + .probe = adf_probe, + .remove = adf_remove, +}; + +static void adf_cleanup_pci_dev(struct adf_accel_dev *accel_dev) +{ + pci_release_regions(accel_dev->accel_pci_dev.pci_dev); + pci_disable_device(accel_dev->accel_pci_dev.pci_dev); +} + +static void adf_cleanup_accel(struct adf_accel_dev *accel_dev) +{ + struct adf_accel_pci *accel_pci_dev = &accel_dev->accel_pci_dev; + struct adf_accel_dev *pf; + int i; + + for (i = 0; i < ADF_PCI_MAX_BARS; i++) { + struct adf_bar *bar = &accel_pci_dev->pci_bars[i]; + + if (bar->virt_addr) + pci_iounmap(accel_pci_dev->pci_dev, bar->virt_addr); + } + + if (accel_dev->hw_device) { + switch (accel_pci_dev->pci_dev->device) { + case ADF_DH895XCCIOV_PCI_DEVICE_ID: + adf_clean_hw_data_dh895xcciov(accel_dev->hw_device); + break; + default: + break; + } + kfree(accel_dev->hw_device); + accel_dev->hw_device = NULL; + } + adf_cfg_dev_remove(accel_dev); + debugfs_remove(accel_dev->debugfs_dir); + pf = adf_devmgr_pci_to_accel_dev(accel_pci_dev->pci_dev->physfn); + adf_devmgr_rm_dev(accel_dev, pf); +} + +static int adf_dev_configure(struct adf_accel_dev *accel_dev) +{ + char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES]; + unsigned long val, bank = 0; + + if (adf_cfg_section_add(accel_dev, ADF_KERNEL_SEC)) + goto err; + if (adf_cfg_section_add(accel_dev, "Accelerator0")) + goto err; + + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_BANK_NUM, 0); + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, key, + (void *)&bank, ADF_DEC)) + goto err; + + val = bank; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_ETRMGR_CORE_AFFINITY, 0); + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, key, + (void *)&val, ADF_DEC)) + goto err; + + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_SIZE, 0); + + val = 128; + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, key, + (void *)&val, ADF_DEC)) + goto err; + + val = 512; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_SYM_SIZE, 0); + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, (void *)&val, ADF_DEC)) + goto err; + + val = 0; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_TX, 0); + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, (void *)&val, ADF_DEC)) + goto err; + + val = 2; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_SYM_TX, 0); + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, (void *)&val, ADF_DEC)) + goto err; + + val = 8; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_RX, 0); + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, (void *)&val, ADF_DEC)) + goto err; + + val = 10; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_SYM_RX, 0); + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, (void *)&val, ADF_DEC)) + goto err; + + val = ADF_COALESCING_DEF_TIME; + snprintf(key, sizeof(key), ADF_ETRMGR_COALESCE_TIMER_FORMAT, + (int)bank); + if (adf_cfg_add_key_value_param(accel_dev, "Accelerator0", + key, (void *)&val, ADF_DEC)) + goto err; + + val = 1; + if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + ADF_NUM_CY, (void *)&val, ADF_DEC)) + goto err; + + set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status); + return 0; +err: + dev_err(&GET_DEV(accel_dev), "Failed to configure QAT accel dev\n"); + return -EINVAL; +} + +static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct adf_accel_dev *accel_dev; + struct adf_accel_dev *pf; + struct adf_accel_pci *accel_pci_dev; + struct adf_hw_device_data *hw_data; + char name[ADF_DEVICE_NAME_LENGTH]; + unsigned int i, bar_nr; + int ret, bar_mask; + + switch (ent->device) { + case ADF_DH895XCCIOV_PCI_DEVICE_ID: + break; + default: + dev_err(&pdev->dev, "Invalid device 0x%x.\n", ent->device); + return -ENODEV; + } + + accel_dev = kzalloc_node(sizeof(*accel_dev), GFP_KERNEL, + dev_to_node(&pdev->dev)); + if (!accel_dev) + return -ENOMEM; + + accel_dev->is_vf = true; + pf = adf_devmgr_pci_to_accel_dev(pdev->physfn); + accel_pci_dev = &accel_dev->accel_pci_dev; + accel_pci_dev->pci_dev = pdev; + + /* Add accel device to accel table */ + if (adf_devmgr_add_dev(accel_dev, pf)) { + dev_err(&pdev->dev, "Failed to add new accelerator device.\n"); + kfree(accel_dev); + return -EFAULT; + } + INIT_LIST_HEAD(&accel_dev->crypto_list); + + accel_dev->owner = THIS_MODULE; + /* Allocate and configure device configuration structure */ + hw_data = kzalloc_node(sizeof(*hw_data), GFP_KERNEL, + dev_to_node(&pdev->dev)); + if (!hw_data) { + ret = -ENOMEM; + goto out_err; + } + accel_dev->hw_device = hw_data; + switch (ent->device) { + case ADF_DH895XCCIOV_PCI_DEVICE_ID: + adf_init_hw_data_dh895xcciov(accel_dev->hw_device); + break; + default: + ret = -ENODEV; + goto out_err; + } + + /* Get Accelerators and Accelerators Engines masks */ + hw_data->accel_mask = hw_data->get_accel_mask(hw_data->fuses); + hw_data->ae_mask = hw_data->get_ae_mask(hw_data->fuses); + accel_pci_dev->sku = hw_data->get_sku(hw_data); + + /* Create dev top level debugfs entry */ + snprintf(name, sizeof(name), "%s%s_%02x:%02d.%02d", + ADF_DEVICE_NAME_PREFIX, hw_data->dev_class->name, + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); + + accel_dev->debugfs_dir = debugfs_create_dir(name, NULL); + if (!accel_dev->debugfs_dir) { + dev_err(&pdev->dev, "Could not create debugfs dir %s\n", name); + ret = -EINVAL; + goto out_err; + } + + /* Create device configuration table */ + ret = adf_cfg_dev_add(accel_dev); + if (ret) + goto out_err; + + /* enable PCI device */ + if (pci_enable_device(pdev)) { + ret = -EFAULT; + goto out_err; + } + + /* set dma identifier */ + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) { + dev_err(&pdev->dev, "No usable DMA configuration\n"); + ret = -EFAULT; + goto out_err_disable; + } else { + pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + } + + } else { + pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + } + + if (pci_request_regions(pdev, adf_driver_name)) { + ret = -EFAULT; + goto out_err_disable; + } + + /* Find and map all the device's BARS */ + i = 0; + bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); + for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask, + ADF_PCI_MAX_BARS * 2) { + struct adf_bar *bar = &accel_pci_dev->pci_bars[i++]; + + bar->base_addr = pci_resource_start(pdev, bar_nr); + if (!bar->base_addr) + break; + bar->size = pci_resource_len(pdev, bar_nr); + bar->virt_addr = pci_iomap(accel_pci_dev->pci_dev, bar_nr, 0); + if (!bar->virt_addr) { + dev_err(&pdev->dev, "Failed to map BAR %d\n", bar_nr); + ret = -EFAULT; + goto out_err_free_reg; + } + } + pci_set_master(pdev); + /* Completion for VF2PF request/response message exchange */ + init_completion(&accel_dev->vf.iov_msg_completion); + + ret = adf_dev_configure(accel_dev); + if (ret) + goto out_err_free_reg; + + ret = adf_dev_init(accel_dev); + if (ret) + goto out_err_dev_shutdown; + + ret = adf_dev_start(accel_dev); + if (ret) + goto out_err_dev_stop; + + return ret; + +out_err_dev_stop: + adf_dev_stop(accel_dev); +out_err_dev_shutdown: + adf_dev_shutdown(accel_dev); +out_err_free_reg: + pci_release_regions(accel_pci_dev->pci_dev); +out_err_disable: + pci_disable_device(accel_pci_dev->pci_dev); +out_err: + adf_cleanup_accel(accel_dev); + kfree(accel_dev); + return ret; +} + +static void adf_remove(struct pci_dev *pdev) +{ + struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); + + if (!accel_dev) { + pr_err("QAT: Driver removal failed\n"); + return; + } + if (adf_dev_stop(accel_dev)) + dev_err(&GET_DEV(accel_dev), "Failed to stop QAT accel dev\n"); + + adf_dev_shutdown(accel_dev); + adf_cleanup_accel(accel_dev); + adf_cleanup_pci_dev(accel_dev); + kfree(accel_dev); +} + +static int __init adfdrv_init(void) +{ + request_module("intel_qat"); + + if (pci_register_driver(&adf_driver)) { + pr_err("QAT: Driver initialization failed\n"); + return -EFAULT; + } + return 0; +} + +static void __exit adfdrv_release(void) +{ + pci_unregister_driver(&adf_driver); + adf_clean_vf_map(true); +} + +module_init(adfdrv_init); +module_exit(adfdrv_release); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Intel"); +MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); +MODULE_VERSION(ADF_DRV_VERSION); diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.h b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.h new file mode 100644 index 000000000000..041d2a0a0215 --- /dev/null +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.h @@ -0,0 +1,57 @@ +/* + 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. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2014 Intel Corporation. + 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 of 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 ADF_DH895xVF_DRV_H_ +#define ADF_DH895xVF_DRV_H_ +#include +#include + +void adf_init_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data); +void adf_clean_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data); +int adf_isr_resource_alloc(struct adf_accel_dev *accel_dev); +void adf_isr_resource_free(struct adf_accel_dev *accel_dev); +void adf_update_ring_arb_enable(struct adf_etr_ring_data *ring); +#endif diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_isr.c b/drivers/crypto/qat/qat_dh895xccvf/adf_isr.c new file mode 100644 index 000000000000..7fdc84a407cc --- /dev/null +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_isr.c @@ -0,0 +1,258 @@ +/* + 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. + 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. + + Contact Information: + qat-linux@intel.com + + BSD LICENSE + Copyright(c) 2014 Intel Corporation. + 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 of 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adf_drv.h" +#include "adf_dh895xccvf_hw_data.h" + +static int adf_enable_msi(struct adf_accel_dev *accel_dev) +{ + struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev; + int stat = pci_enable_msi(pci_dev_info->pci_dev); + + if (stat) { + dev_err(&GET_DEV(accel_dev), + "Failed to enable MSI interrupts\n"); + return stat; + } + + accel_dev->vf.irq_name = kzalloc(ADF_MAX_MSIX_VECTOR_NAME, GFP_KERNEL); + if (!accel_dev->vf.irq_name) + return -ENOMEM; + + return stat; +} + +static void adf_disable_msi(struct adf_accel_dev *accel_dev) +{ + struct pci_dev *pdev = accel_to_pci_dev(accel_dev); + + kfree(accel_dev->vf.irq_name); + pci_disable_msi(pdev); +} + +static void adf_pf2vf_bh_handler(void *data) +{ + struct adf_accel_dev *accel_dev = data; + void __iomem *pmisc_bar_addr = + (&GET_BARS(accel_dev)[ADF_DH895XCCIOV_PMISC_BAR])->virt_addr; + u32 msg; + + /* Read the message from PF */ + msg = ADF_CSR_RD(pmisc_bar_addr, ADF_DH895XCCIOV_PF2VF_OFFSET); + + if (!(msg & ADF_PF2VF_MSGORIGIN_SYSTEM)) + /* Ignore legacy non-system (non-kernel) PF2VF messages */ + goto err; + + switch ((msg & ADF_PF2VF_MSGTYPE_MASK) >> ADF_PF2VF_MSGTYPE_SHIFT) { + case ADF_PF2VF_MSGTYPE_RESTARTING: + dev_dbg(&GET_DEV(accel_dev), + "Restarting msg received from PF 0x%x\n", msg); + adf_dev_stop(accel_dev); + break; + case ADF_PF2VF_MSGTYPE_VERSION_RESP: + dev_dbg(&GET_DEV(accel_dev), + "Version resp received from PF 0x%x\n", msg); + accel_dev->vf.pf_version = + (msg & ADF_PF2VF_VERSION_RESP_VERS_MASK) >> + ADF_PF2VF_VERSION_RESP_VERS_SHIFT; + accel_dev->vf.compatible = + (msg & ADF_PF2VF_VERSION_RESP_RESULT_MASK) >> + ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; + complete(&accel_dev->vf.iov_msg_completion); + break; + default: + goto err; + } + + /* To ack, clear the PF2VFINT bit */ + msg &= ~ADF_DH895XCC_PF2VF_PF2VFINT; + ADF_CSR_WR(pmisc_bar_addr, ADF_DH895XCCIOV_PF2VF_OFFSET, msg); + + /* Re-enable PF2VF interrupts */ + adf_enable_pf2vf_interrupts(accel_dev); + return; +err: + dev_err(&GET_DEV(accel_dev), + "Unknown message from PF (0x%x); leaving PF2VF ints disabled\n", + msg); +} + +static int adf_setup_pf2vf_bh(struct adf_accel_dev *accel_dev) +{ + tasklet_init(&accel_dev->vf.pf2vf_bh_tasklet, + (void *)adf_pf2vf_bh_handler, (unsigned long)accel_dev); + + mutex_init(&accel_dev->vf.vf2pf_lock); + return 0; +} + +static void adf_cleanup_pf2vf_bh(struct adf_accel_dev *accel_dev) +{ + tasklet_disable(&accel_dev->vf.pf2vf_bh_tasklet); + tasklet_kill(&accel_dev->vf.pf2vf_bh_tasklet); + mutex_destroy(&accel_dev->vf.vf2pf_lock); +} + +static irqreturn_t adf_isr(int irq, void *privdata) +{ + struct adf_accel_dev *accel_dev = privdata; + void __iomem *pmisc_bar_addr = + (&GET_BARS(accel_dev)[ADF_DH895XCCIOV_PMISC_BAR])->virt_addr; + u32 v_int; + + /* Read VF INT source CSR to determine the source of VF interrupt */ + v_int = ADF_CSR_RD(pmisc_bar_addr, ADF_DH895XCCIOV_VINTSOU_OFFSET); + + /* Check for PF2VF interrupt */ + if (v_int & ADF_DH895XCC_VINTSOU_PF2VF) { + /* Disable PF to VF interrupt */ + adf_disable_pf2vf_interrupts(accel_dev); + + /* Schedule tasklet to handle interrupt BH */ + tasklet_hi_schedule(&accel_dev->vf.pf2vf_bh_tasklet); + return IRQ_HANDLED; + } + + /* Check bundle interrupt */ + if (v_int & ADF_DH895XCC_VINTSOU_BUN) { + struct adf_etr_data *etr_data = accel_dev->transport; + struct adf_etr_bank_data *bank = &etr_data->banks[0]; + + /* Disable Flag and Coalesce Ring Interrupts */ + WRITE_CSR_INT_FLAG_AND_COL(bank->csr_addr, bank->bank_number, + 0); + tasklet_hi_schedule(&bank->resp_handler); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int adf_request_msi_irq(struct adf_accel_dev *accel_dev) +{ + struct pci_dev *pdev = accel_to_pci_dev(accel_dev); + unsigned int cpu; + int ret; + + snprintf(accel_dev->vf.irq_name, ADF_MAX_MSIX_VECTOR_NAME, + "qat_%02x:%02d.%02d", pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); + ret = request_irq(pdev->irq, adf_isr, 0, accel_dev->vf.irq_name, + (void *)accel_dev); + if (ret) { + dev_err(&GET_DEV(accel_dev), "failed to enable irq for %s\n", + accel_dev->vf.irq_name); + return ret; + } + cpu = accel_dev->accel_id % num_online_cpus(); + irq_set_affinity_hint(pdev->irq, get_cpu_mask(cpu)); + + return ret; +} + +static int adf_setup_bh(struct adf_accel_dev *accel_dev) +{ + struct adf_etr_data *priv_data = accel_dev->transport; + + tasklet_init(&priv_data->banks[0].resp_handler, adf_response_handler, + (unsigned long)priv_data->banks); + return 0; +} + +static void adf_cleanup_bh(struct adf_accel_dev *accel_dev) +{ + struct adf_etr_data *priv_data = accel_dev->transport; + + tasklet_disable(&priv_data->banks[0].resp_handler); + tasklet_kill(&priv_data->banks[0].resp_handler); +} + +void adf_isr_resource_free(struct adf_accel_dev *accel_dev) +{ + struct pci_dev *pdev = accel_to_pci_dev(accel_dev); + + irq_set_affinity_hint(pdev->irq, NULL); + free_irq(pdev->irq, (void *)accel_dev); + adf_cleanup_bh(accel_dev); + adf_cleanup_pf2vf_bh(accel_dev); + adf_disable_msi(accel_dev); +} + +int adf_isr_resource_alloc(struct adf_accel_dev *accel_dev) +{ + if (adf_enable_msi(accel_dev)) + goto err_out; + + if (adf_setup_pf2vf_bh(accel_dev)) + goto err_out; + + if (adf_setup_bh(accel_dev)) + goto err_out; + + if (adf_request_msi_irq(accel_dev)) + goto err_out; + + return 0; +err_out: + adf_isr_resource_free(accel_dev); + return -EFAULT; +} -- cgit v1.3-6-gb490 From 89c07b8a18a264ba84d135e07b1ee057839d3bda Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 7 Aug 2015 11:34:36 -0700 Subject: crypto: qat - Add FW const table Some VF drivers need FW const table, so the PF driver needs to load it. Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/crypto/qat/qat_common/adf_admin.c | 107 +++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/qat/qat_common/adf_admin.c b/drivers/crypto/qat/qat_common/adf_admin.c index 0a76168e4923..147d755fed97 100644 --- a/drivers/crypto/qat/qat_common/adf_admin.c +++ b/drivers/crypto/qat/qat_common/adf_admin.c @@ -60,8 +60,90 @@ #define ADF_DH895XCC_MAILBOX_STRIDE 0x1000 #define ADF_ADMINMSG_LEN 32 +static const u8 const_tab[1024] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x02, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, +0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, +0x54, 0x32, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, +0x89, 0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0, +0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x05, 0x9e, +0xd8, 0x36, 0x7c, 0xd5, 0x07, 0x30, 0x70, 0xdd, 0x17, 0xf7, 0x0e, 0x59, 0x39, +0xff, 0xc0, 0x0b, 0x31, 0x68, 0x58, 0x15, 0x11, 0x64, 0xf9, 0x8f, 0xa7, 0xbe, +0xfa, 0x4f, 0xa4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, +0x85, 0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f, 0xf5, 0x3a, 0x51, 0x0e, 0x52, 0x7f, +0x9b, 0x05, 0x68, 0x8c, 0x1f, 0x83, 0xd9, 0xab, 0x5b, 0xe0, 0xcd, 0x19, 0x05, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xcb, 0xbb, 0x9d, 0x5d, 0xc1, 0x05, 0x9e, 0xd8, 0x62, 0x9a, 0x29, +0x2a, 0x36, 0x7c, 0xd5, 0x07, 0x91, 0x59, 0x01, 0x5a, 0x30, 0x70, 0xdd, 0x17, +0x15, 0x2f, 0xec, 0xd8, 0xf7, 0x0e, 0x59, 0x39, 0x67, 0x33, 0x26, 0x67, 0xff, +0xc0, 0x0b, 0x31, 0x8e, 0xb4, 0x4a, 0x87, 0x68, 0x58, 0x15, 0x11, 0xdb, 0x0c, +0x2e, 0x0d, 0x64, 0xf9, 0x8f, 0xa7, 0x47, 0xb5, 0x48, 0x1d, 0xbe, 0xfa, 0x4f, +0xa4, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x6a, 0x09, 0xe6, 0x67, 0xf3, 0xbc, 0xc9, 0x08, 0xbb, +0x67, 0xae, 0x85, 0x84, 0xca, 0xa7, 0x3b, 0x3c, 0x6e, 0xf3, 0x72, 0xfe, 0x94, +0xf8, 0x2b, 0xa5, 0x4f, 0xf5, 0x3a, 0x5f, 0x1d, 0x36, 0xf1, 0x51, 0x0e, 0x52, +0x7f, 0xad, 0xe6, 0x82, 0xd1, 0x9b, 0x05, 0x68, 0x8c, 0x2b, 0x3e, 0x6c, 0x1f, +0x1f, 0x83, 0xd9, 0xab, 0xfb, 0x41, 0xbd, 0x6b, 0x5b, 0xe0, 0xcd, 0x19, 0x13, +0x7e, 0x21, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + struct adf_admin_comms { dma_addr_t phy_addr; + dma_addr_t const_tbl_addr; void *virt_addr; void __iomem *mailbox_addr; struct mutex lock; /* protects adf_admin_comms struct */ @@ -113,6 +195,11 @@ static int adf_send_admin_cmd(struct adf_accel_dev *accel_dev, int cmd) memset(&req, 0, sizeof(struct icp_qat_fw_init_admin_req)); req.init_admin_cmd_id = cmd; + + if (cmd == ICP_QAT_FW_CONSTANTS_CFG) { + req.init_cfg_sz = 1024; + req.init_cfg_ptr = accel_dev->admin->const_tbl_addr; + } for (i = 0; i < hw_device->get_num_aes(hw_device); i++) { memset(&resp, 0, sizeof(struct icp_qat_fw_init_admin_resp)); if (adf_put_admin_msg_sync(accel_dev, i, &req, &resp) || @@ -132,7 +219,11 @@ static int adf_send_admin_cmd(struct adf_accel_dev *accel_dev, int cmd) */ int adf_send_admin_init(struct adf_accel_dev *accel_dev) { - return adf_send_admin_cmd(accel_dev, ICP_QAT_FW_INIT_ME); + int ret = adf_send_admin_cmd(accel_dev, ICP_QAT_FW_INIT_ME); + + if (ret) + return ret; + return adf_send_admin_cmd(accel_dev, ICP_QAT_FW_CONSTANTS_CFG); } EXPORT_SYMBOL_GPL(adf_send_admin_init); @@ -157,6 +248,18 @@ int adf_init_admin_comms(struct adf_accel_dev *accel_dev) kfree(admin); return -ENOMEM; } + + admin->const_tbl_addr = dma_map_single(&GET_DEV(accel_dev), + (void *) const_tab, 1024, + DMA_TO_DEVICE); + + if (unlikely(dma_mapping_error(&GET_DEV(accel_dev), + admin->const_tbl_addr))) { + dma_free_coherent(&GET_DEV(accel_dev), PAGE_SIZE, + admin->virt_addr, admin->phy_addr); + kfree(admin); + return -ENOMEM; + } reg_val = (u64)admin->phy_addr; ADF_CSR_WR(csr, ADF_DH895XCC_ADMINMSGUR_OFFSET, reg_val >> 32); ADF_CSR_WR(csr, ADF_DH895XCC_ADMINMSGLR_OFFSET, reg_val); @@ -178,6 +281,8 @@ void adf_exit_admin_comms(struct adf_accel_dev *accel_dev) dma_free_coherent(&GET_DEV(accel_dev), PAGE_SIZE, admin->virt_addr, admin->phy_addr); + dma_unmap_single(&GET_DEV(accel_dev), admin->const_tbl_addr, 1024, + DMA_TO_DEVICE); mutex_destroy(&admin->lock); kfree(admin); accel_dev->admin = NULL; -- cgit v1.3-6-gb490 From 3388a614b609ad9ac4f542e56ada737557a19651 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 7 Aug 2015 11:34:42 -0700 Subject: PCI: Add quirk for Intel DH895xCC VF PCI config erratum The PCI capabilities list for Intel DH895xCC VFs (device id 0x0443) with QuickAssist Technology is prematurely terminated in hardware. Workaround the issue by hard-coding the known expected next capability pointer and saving the PCIE cap into internal buffer. Patch generated against cryptodev-2.6 Signed-off-by: Tadeusz Struk Signed-off-by: Herbert Xu --- drivers/pci/quirks.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e9fd0e90fa3b..6a80f5ac7bd8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4008,3 +4008,88 @@ void pci_dev_specific_enable_acs(struct pci_dev *dev) } } } + +/* + * The PCI capabilities list for Intel DH895xCC VFs (device id 0x0443) with + * QuickAssist Technology (QAT) is prematurely terminated in hardware. The + * Next Capability pointer in the MSI Capability Structure should point to + * the PCIe Capability Structure but is incorrectly hardwired as 0 terminating + * the list. + */ +static void quirk_intel_qat_vf_cap(struct pci_dev *pdev) +{ + int pos, i = 0; + u8 next_cap; + u16 reg16, *cap; + struct pci_cap_saved_state *state; + + /* Bail if the hardware bug is fixed */ + if (pdev->pcie_cap || pci_find_capability(pdev, PCI_CAP_ID_EXP)) + return; + + /* Bail if MSI Capability Structure is not found for some reason */ + pos = pci_find_capability(pdev, PCI_CAP_ID_MSI); + if (!pos) + return; + + /* + * Bail if Next Capability pointer in the MSI Capability Structure + * is not the expected incorrect 0x00. + */ + pci_read_config_byte(pdev, pos + 1, &next_cap); + if (next_cap) + return; + + /* + * PCIe Capability Structure is expected to be at 0x50 and should + * terminate the list (Next Capability pointer is 0x00). Verify + * Capability Id and Next Capability pointer is as expected. + * Open-code some of set_pcie_port_type() and pci_cfg_space_size_ext() + * to correctly set kernel data structures which have already been + * set incorrectly due to the hardware bug. + */ + pos = 0x50; + pci_read_config_word(pdev, pos, ®16); + if (reg16 == (0x0000 | PCI_CAP_ID_EXP)) { + u32 status; +#ifndef PCI_EXP_SAVE_REGS +#define PCI_EXP_SAVE_REGS 7 +#endif + int size = PCI_EXP_SAVE_REGS * sizeof(u16); + + pdev->pcie_cap = pos; + pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16); + pdev->pcie_flags_reg = reg16; + pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, ®16); + pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD; + + pdev->cfg_size = PCI_CFG_SPACE_EXP_SIZE; + if (pci_read_config_dword(pdev, PCI_CFG_SPACE_SIZE, &status) != + PCIBIOS_SUCCESSFUL || (status == 0xffffffff)) + pdev->cfg_size = PCI_CFG_SPACE_SIZE; + + if (pci_find_saved_cap(pdev, PCI_CAP_ID_EXP)) + return; + + /* + * Save PCIE cap + */ + state = kzalloc(sizeof(*state) + size, GFP_KERNEL); + if (!state) + return; + + state->cap.cap_nr = PCI_CAP_ID_EXP; + state->cap.cap_extended = 0; + state->cap.size = size; + cap = (u16 *)&state->cap.data[0]; + pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &cap[i++]); + pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &cap[i++]); + pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &cap[i++]); + pcie_capability_read_word(pdev, PCI_EXP_RTCTL, &cap[i++]); + pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &cap[i++]); + pcie_capability_read_word(pdev, PCI_EXP_LNKCTL2, &cap[i++]); + pcie_capability_read_word(pdev, PCI_EXP_SLTCTL2, &cap[i++]); + hlist_add_head(&state->next, &pdev->saved_cap_space); + } +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x443, quirk_intel_qat_vf_cap); -- cgit v1.3-6-gb490 From 9cfaf082b8775e9f99fa5f2e8b2ae0ca8baff785 Mon Sep 17 00:00:00 2001 From: Leonidas Da Silva Barbosa Date: Sat, 8 Aug 2015 18:31:01 -0300 Subject: crypto: nx - Removing CTR mode from NX driver CTR hardware implementation does not match with kernel spec causing a counter bug where just low 8 bytes are used for counter, when should be all 16bytes. Since we already have other counter modes working according with specs not worth to keep CTR itself on NX. Signed-off-by: Leonidas S. Barbosa Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-aes-ctr.c | 21 --------------------- drivers/crypto/nx/nx.c | 9 +-------- drivers/crypto/nx/nx.h | 1 - 3 files changed, 1 insertion(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx-aes-ctr.c b/drivers/crypto/nx/nx-aes-ctr.c index dd7e9f3f5b6b..898c0a280511 100644 --- a/drivers/crypto/nx/nx-aes-ctr.c +++ b/drivers/crypto/nx/nx-aes-ctr.c @@ -144,27 +144,6 @@ static int ctr3686_aes_nx_crypt(struct blkcipher_desc *desc, return ctr_aes_nx_crypt(desc, dst, src, nbytes); } -struct crypto_alg nx_ctr_aes_alg = { - .cra_name = "ctr(aes)", - .cra_driver_name = "ctr-aes-nx", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct nx_crypto_ctx), - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_init = nx_crypto_ctx_aes_ctr_init, - .cra_exit = nx_crypto_ctx_exit, - .cra_blkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .setkey = ctr_aes_nx_set_key, - .encrypt = ctr_aes_nx_crypt, - .decrypt = ctr_aes_nx_crypt, - } -}; - struct crypto_alg nx_ctr3686_aes_alg = { .cra_name = "rfc3686(ctr(aes))", .cra_driver_name = "rfc3686-ctr-aes-nx", diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index 9a5e643af5bc..0794f1cc0018 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -596,13 +596,9 @@ static int nx_register_algs(void) if (rc) goto out_unreg_ecb; - rc = nx_register_alg(&nx_ctr_aes_alg, NX_FC_AES, NX_MODE_AES_CTR); - if (rc) - goto out_unreg_cbc; - rc = nx_register_alg(&nx_ctr3686_aes_alg, NX_FC_AES, NX_MODE_AES_CTR); if (rc) - goto out_unreg_ctr; + goto out_unreg_cbc; rc = nx_register_aead(&nx_gcm_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); if (rc) @@ -653,8 +649,6 @@ out_unreg_gcm: nx_unregister_aead(&nx_gcm_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); out_unreg_ctr3686: nx_unregister_alg(&nx_ctr3686_aes_alg, NX_FC_AES, NX_MODE_AES_CTR); -out_unreg_ctr: - nx_unregister_alg(&nx_ctr_aes_alg, NX_FC_AES, NX_MODE_AES_CTR); out_unreg_cbc: nx_unregister_alg(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC); out_unreg_ecb: @@ -821,7 +815,6 @@ static int nx_remove(struct vio_dev *viodev) NX_FC_AES, NX_MODE_AES_GCM); nx_unregister_alg(&nx_ctr3686_aes_alg, NX_FC_AES, NX_MODE_AES_CTR); - nx_unregister_alg(&nx_ctr_aes_alg, NX_FC_AES, NX_MODE_AES_CTR); nx_unregister_alg(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC); nx_unregister_alg(&nx_ecb_aes_alg, NX_FC_AES, NX_MODE_AES_ECB); } diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h index 8a4d1fd752d6..591632d9c654 100644 --- a/drivers/crypto/nx/nx.h +++ b/drivers/crypto/nx/nx.h @@ -187,7 +187,6 @@ extern struct crypto_alg nx_cbc_aes_alg; extern struct crypto_alg nx_ecb_aes_alg; extern struct aead_alg nx_gcm_aes_alg; extern struct aead_alg nx_gcm4106_aes_alg; -extern struct crypto_alg nx_ctr_aes_alg; extern struct crypto_alg nx_ctr3686_aes_alg; extern struct aead_alg nx_ccm_aes_alg; extern struct aead_alg nx_ccm4309_aes_alg; -- cgit v1.3-6-gb490 From 38755e897ec2c371b8e71561622d525b3b94012b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 9 Aug 2015 18:37:36 -0700 Subject: libata: fix libata-core.c kernel-doc warning Fix kernel-doc warning in libata-core.c: Warning(..//drivers/ata/libata-core.c:4763): No description found for parameter 'tag' Signed-off-by: Randy Dunlap Signed-off-by: Tejun Heo --- drivers/ata/libata-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index e83fc3d0da9c..bea6c571db58 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4754,6 +4754,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) /** * ata_qc_new_init - Request an available ATA command, and initialize it * @dev: Device from whom we request an available command structure + * @tag: tag * * LOCKING: * None. -- cgit v1.3-6-gb490 From bdbbd38106c9f72c569be18314f68387e384536c Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:28:07 +0200 Subject: spi: atmel: remove useless include Definitions from linux/platform_data/atmel.h are not used, remove the include. Signed-off-by: Alexandre Belloni Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index c9eca347787d..bf9ed380bb1c 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include -- cgit v1.3-6-gb490 From 4863e4cc31d647e11f69e1f4d37a870ff3094fcc Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 6 Aug 2015 03:43:09 -0700 Subject: Bluetooth: btmrvl: release sdio bus after firmware is up We will not release sdio bus until firmware is completely downloaded and becomes ready. Our 8887 A2 chip can have separate firmware images for WLAN and bluetooth. This patch fixes an issue observed when both drivers simultaneously try to download respective firmwares. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index b9a811900f6a..7c097629e593 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1071,8 +1071,6 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) } } - sdio_release_host(card->func); - /* * winner or not, with this test the FW synchronizes when the * module can continue its initialization @@ -1082,6 +1080,8 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card) return -ETIMEDOUT; } + sdio_release_host(card->func); + return 0; done: -- cgit v1.3-6-gb490 From fc0719e6a144402197a2147117f10b66ee623fbb Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 10 Aug 2015 21:15:57 +0200 Subject: at86rf230: use STATE_TX_ARET mode only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch changes the state change behaviour of at86rf230 to always TX_ARET mode. According the at86rf2xx datasheets TX_ARET mode doesn't mean to be always waiting for ack frames after transmit. The transceiver will automatically wait for ack frames or not if the acknowledge request bit is set. See section "TX_ARET_ON – Transmit with Automatic Frame Retransmission and CSMA-CA Retry". Reviewed-by: Stefan Schmidt Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 52 ++++++++++---------------------------- 1 file changed, 14 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index d0d5bf6cbb68..6422caac8d40 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -97,9 +97,7 @@ struct at86rf230_local { struct at86rf230_state_change irq; - bool tx_aret; unsigned long cal_timeout; - s8 max_frame_retries; bool is_tx; bool is_tx_from_off; u8 tx_retry; @@ -651,7 +649,7 @@ at86rf230_tx_complete(void *context) enable_irq(ctx->irq); - ieee802154_xmit_complete(lp->hw, lp->tx_skb, !lp->tx_aret); + ieee802154_xmit_complete(lp->hw, lp->tx_skb, false); } static void @@ -760,17 +758,10 @@ at86rf230_irq_trx_end(struct at86rf230_local *lp) { if (lp->is_tx) { lp->is_tx = 0; - - if (lp->tx_aret) - at86rf230_async_state_change(lp, &lp->irq, - STATE_FORCE_TX_ON, - at86rf230_tx_trac_status, - true); - else - at86rf230_async_state_change(lp, &lp->irq, - STATE_RX_AACK_ON, - at86rf230_tx_complete, - true); + at86rf230_async_state_change(lp, &lp->irq, + STATE_FORCE_TX_ON, + at86rf230_tx_trac_status, + true); } else { at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq, at86rf230_rx_trac_check, true); @@ -876,24 +867,16 @@ at86rf230_xmit_start(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; - /* In ARET mode we need to go into STATE_TX_ARET_ON after we - * are in STATE_TX_ON. The pfad differs here, so we change - * the complete handler. - */ - if (lp->tx_aret) { - if (lp->is_tx_from_off) { - lp->is_tx_from_off = false; - at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, - at86rf230_write_frame, - false); - } else { - at86rf230_async_state_change(lp, ctx, STATE_TX_ON, - at86rf230_xmit_tx_on, - false); - } + /* check if we change from off state */ + if (lp->is_tx_from_off) { + lp->is_tx_from_off = false; + at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, + at86rf230_write_frame, + false); } else { at86rf230_async_state_change(lp, ctx, STATE_TX_ON, - at86rf230_write_frame, false); + at86rf230_xmit_tx_on, + false); } } @@ -1267,15 +1250,8 @@ static int at86rf230_set_frame_retries(struct ieee802154_hw *hw, s8 retries) { struct at86rf230_local *lp = hw->priv; - int rc = 0; - - lp->tx_aret = retries >= 0; - lp->max_frame_retries = retries; - if (retries >= 0) - rc = at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries); - - return rc; + return at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries); } static int -- cgit v1.3-6-gb490 From 100a008331072e678ffcf2d903e48c633c2795fe Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Tue, 28 Jul 2015 07:22:20 -0700 Subject: mwifiex: correct TDLS link delete failure message priority Commit d8d2f19feb16 ("mwifiex: silence TDLS link delete failure for nonexistent link") lowers the priority of error message when TDLS link is already deleted. But it had got increased by commit acebe8c10a6e ("mwifiex: change dbg print func to mwifiex_dbg") Reported-by: Nicholas Mc Guire Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 89e8dafb4738..87b69d8ad120 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -895,7 +895,7 @@ static int mwifiex_ret_tdls_oper(struct mwifiex_private *priv, case ACT_TDLS_DELETE: if (reason) { if (!node || reason == TDLS_ERR_LINK_NONEXISTENT) - mwifiex_dbg(priv->adapter, ERROR, + mwifiex_dbg(priv->adapter, MSG, "TDLS link delete for %pM failed: reason %d\n", cmd_tdls_oper->peer_mac, reason); else -- cgit v1.3-6-gb490 From 6d5c898798aca634f493cabd2e7a47407ee5e95d Mon Sep 17 00:00:00 2001 From: "Machani, Yaniv" Date: Thu, 30 Jul 2015 22:38:19 +0300 Subject: wlcore/wl18xx : add time sync event handling Added support for a new time sync event the event data contains the WiLink TSF value. To trigger the event, a HW modification is required, so as a supporting firmware binary. Signed-off-by: Yaniv Machani Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/event.c | 13 +++++++++++++ drivers/net/wireless/ti/wl18xx/event.h | 12 ++++++++---- drivers/net/wireless/ti/wl18xx/main.c | 4 ++-- 3 files changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c index 548bb9e7e91e..09c7e098f460 100644 --- a/drivers/net/wireless/ti/wl18xx/event.c +++ b/drivers/net/wireless/ti/wl18xx/event.c @@ -112,6 +112,14 @@ static int wlcore_smart_config_decode_event(struct wl1271 *wl, return 0; } +static void wlcore_event_time_sync(struct wl1271 *wl, u16 tsf_msb, u16 tsf_lsb) +{ + u32 clock; + /* convert the MSB+LSB to a u32 TSF value */ + clock = (tsf_msb << 16) | tsf_lsb; + wl1271_info("TIME_SYNC_EVENT_ID: clock %u", clock); +} + int wl18xx_process_mailbox_events(struct wl1271 *wl) { struct wl18xx_event_mailbox *mbox = wl->mbox; @@ -128,6 +136,11 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl) wl18xx_scan_completed(wl, wl->scan_wlvif); } + if (vector & TIME_SYNC_EVENT_ID) + wlcore_event_time_sync(wl, + mbox->time_sync_tsf_msb, + mbox->time_sync_tsf_lsb); + if (vector & RADAR_DETECTED_EVENT_ID) { wl1271_info("radar event: channel %d type %s", mbox->radar_channel, diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h index 266ee87834e4..f3d4f13379cb 100644 --- a/drivers/net/wireless/ti/wl18xx/event.h +++ b/drivers/net/wireless/ti/wl18xx/event.h @@ -38,8 +38,9 @@ enum { REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(18), DFS_CHANNELS_CONFIG_COMPLETE_EVENT = BIT(19), PERIODIC_SCAN_REPORT_EVENT_ID = BIT(20), - SMART_CONFIG_SYNC_EVENT_ID = BIT(22), - SMART_CONFIG_DECODE_EVENT_ID = BIT(23), + SMART_CONFIG_SYNC_EVENT_ID = BIT(22), + SMART_CONFIG_DECODE_EVENT_ID = BIT(23), + TIME_SYNC_EVENT_ID = BIT(24), }; enum wl18xx_radar_types { @@ -95,13 +96,16 @@ struct wl18xx_event_mailbox { /* smart config sync channel */ u8 sc_sync_channel; u8 sc_sync_band; - u8 padding2[2]; + /* time sync msb*/ + u16 time_sync_tsf_msb; /* radar detect */ u8 radar_channel; u8 radar_type; - u8 padding3[2]; + /* time sync lsb*/ + u16 time_sync_tsf_lsb; + } __packed; int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 8ce9825ee577..3da6ac60c65d 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1026,8 +1026,8 @@ static int wl18xx_boot(struct wl1271 *wl) CHANNEL_SWITCH_COMPLETE_EVENT_ID | DFS_CHANNELS_CONFIG_COMPLETE_EVENT | SMART_CONFIG_SYNC_EVENT_ID | - SMART_CONFIG_DECODE_EVENT_ID; -; + SMART_CONFIG_DECODE_EVENT_ID | + TIME_SYNC_EVENT_ID; wl->ap_event_mask = MAX_TX_FAILURE_EVENT_ID; -- cgit v1.3-6-gb490 From 8698a3a4fff2b63831fdc0283da87f9f46c2aeb8 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 30 Jul 2015 22:38:20 +0300 Subject: wl18xx: use long intervals in sched scan Add support for long intervals on sched scan. If configured, the original request interval will be used num_short_interval times, and then the long interval will be used. While on it, fix the scan command field names to reflect the expected value is in ms (rather than secs). These values will be taken from the conf file, so bump its version accordingly. Signed-off-by: Eyal Shapira Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl18xx/main.c | 2 ++ drivers/net/wireless/ti/wl18xx/scan.c | 17 ++++++++++++++--- drivers/net/wireless/ti/wl18xx/scan.h | 4 ++-- drivers/net/wireless/ti/wlcore/conf.h | 11 ++++++++++- drivers/net/wireless/ti/wlcore/scan.h | 6 ++++++ 5 files changed, 34 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 3da6ac60c65d..f9c9d5cf0854 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -422,6 +422,8 @@ static struct wlcore_conf wl18xx_conf = { .num_probe_reqs = 2, .rssi_threshold = -90, .snr_threshold = 0, + .num_short_intervals = SCAN_MAX_SHORT_INTERVALS, + .long_interval = 30000, }, .ht = { .rx_ba_win_size = 32, diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c index 98666f235a12..ec2eb147add3 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.c +++ b/drivers/net/wireless/ti/wl18xx/scan.c @@ -223,9 +223,20 @@ int wl18xx_scan_sched_scan_config(struct wl1271 *wl, SCAN_TYPE_PERIODIC); wl18xx_adjust_channels(cmd, cmd_channels); - cmd->short_cycles_sec = 0; - cmd->long_cycles_sec = cpu_to_le16(req->interval); - cmd->short_cycles_count = 0; + if (c->num_short_intervals && c->long_interval && + c->long_interval > req->interval) { + cmd->short_cycles_msec = cpu_to_le16(req->interval); + cmd->long_cycles_msec = cpu_to_le16(c->long_interval); + cmd->short_cycles_count = c->num_short_intervals; + } else { + cmd->short_cycles_msec = 0; + cmd->long_cycles_msec = cpu_to_le16(req->interval); + cmd->short_cycles_count = 0; + } + wl1271_debug(DEBUG_SCAN, "short_interval: %d, long_interval: %d, num_short: %d", + le16_to_cpu(cmd->short_cycles_msec), + le16_to_cpu(cmd->long_cycles_msec), + cmd->short_cycles_count); cmd->total_cycles = 0; diff --git a/drivers/net/wireless/ti/wl18xx/scan.h b/drivers/net/wireless/ti/wl18xx/scan.h index 2e636aa5dba9..66a763f644d2 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.h +++ b/drivers/net/wireless/ti/wl18xx/scan.h @@ -74,8 +74,8 @@ struct wl18xx_cmd_scan_params { u8 dfs; /* number of dfs channels in 5ghz */ u8 passive_active; /* number of passive before active channels 2.4ghz */ - __le16 short_cycles_sec; - __le16 long_cycles_sec; + __le16 short_cycles_msec; + __le16 long_cycles_msec; u8 short_cycles_count; u8 total_cycles; /* 0 - infinite */ u8 padding[2]; diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h index 166add00b50f..52a9d1b14020 100644 --- a/drivers/net/wireless/ti/wlcore/conf.h +++ b/drivers/net/wireless/ti/wlcore/conf.h @@ -1186,6 +1186,15 @@ struct conf_sched_scan_settings { /* SNR threshold to be used for filtering */ s8 snr_threshold; + + /* + * number of short intervals scheduled scan cycles before + * switching to long intervals + */ + u8 num_short_intervals; + + /* interval between each long scheduled scan cycle (in ms) */ + u16 long_interval; } __packed; struct conf_ht_setting { @@ -1352,7 +1361,7 @@ struct conf_recovery_settings { * version, the two LSB are the lower driver's private conf * version. */ -#define WLCORE_CONF_VERSION (0x0006 << 16) +#define WLCORE_CONF_VERSION (0x0007 << 16) #define WLCORE_CONF_MASK 0xffff0000 #define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \ sizeof(struct wlcore_conf)) diff --git a/drivers/net/wireless/ti/wlcore/scan.h b/drivers/net/wireless/ti/wlcore/scan.h index 4dadd0c62cde..782eb297c196 100644 --- a/drivers/net/wireless/ti/wlcore/scan.h +++ b/drivers/net/wireless/ti/wlcore/scan.h @@ -83,6 +83,12 @@ struct wl1271_cmd_trigger_scan_to { #define MAX_CHANNELS_5GHZ 42 #define SCAN_MAX_CYCLE_INTERVALS 16 + +/* The FW intervals can take up to 16 entries. + * The 1st entry isn't used (scan is immediate). The last + * entry should be used for the long_interval + */ +#define SCAN_MAX_SHORT_INTERVALS (SCAN_MAX_CYCLE_INTERVALS - 2) #define SCAN_MAX_BANDS 3 enum { -- cgit v1.3-6-gb490 From c32e35f29ce96da371e798a8a04ed299f4ecfc44 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 30 Jul 2015 22:38:21 +0300 Subject: wlcore: add generic_cfg_feature command definitions Add definitions and function prototypes for generic_cfg command. Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/cmd.c | 30 ++++++++++++++++++++++++++++++ drivers/net/wireless/ti/wlcore/cmd.h | 15 +++++++++++++++ 2 files changed, 45 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 68919f8d4310..dbc55a0aa905 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -2059,3 +2059,33 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) out: return ret; } + +int wlcore_cmd_generic_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 feature, u8 enable, u8 value) +{ + struct wlcore_cmd_generic_cfg *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, + "cmd generic cfg (role %d feature %d enable %d value %d)", + wlvif->role_id, feature, enable, value); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->role_id = wlvif->role_id; + cmd->feature = feature; + cmd->enable = enable; + cmd->value = value; + + ret = wl1271_cmd_send(wl, CMD_GENERIC_CFG, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send generic cfg command"); + goto out_free; + } +out_free: + kfree(cmd); + return ret; +} +EXPORT_SYMBOL_GPL(wlcore_cmd_generic_cfg); diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index e14cd407a6ae..8dc46c0a489a 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -92,6 +92,8 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel, enum ieee80211_band band); int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl); +int wlcore_cmd_generic_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, + u8 feature, u8 enable, u8 value); int wl12xx_cmd_config_fwlog(struct wl1271 *wl); int wl12xx_cmd_start_fwlog(struct wl1271 *wl); int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); @@ -652,6 +654,19 @@ struct wl12xx_cmd_regdomain_dfs_config { u8 padding[3]; } __packed; +enum wlcore_generic_cfg_feature { + WLCORE_CFG_FEATURE_RADAR_DEBUG = 2, +}; + +struct wlcore_cmd_generic_cfg { + struct wl1271_cmd_header header; + + u8 role_id; + u8 feature; + u8 enable; + u8 value; +} __packed; + struct wl12xx_cmd_config_fwlog { struct wl1271_cmd_header header; -- cgit v1.3-6-gb490 From 7845af35e0deeb7537de759ebc69d6395d4123bf Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 30 Jul 2015 22:38:22 +0300 Subject: wlcore: add p2p device support When starting a p2p mgmt interface, enable its device role. This allows us to keep the sta role disabled and scan on the dev role. In general, p2p management interfaces cannot send vif-specific commands to FW, as the vif role id is invalid. Only off-channel data and scans happen on this vif, so most ops are not relevant. If the vif is a p2p mgmt vif, block some mac80211 ops. Configure rate policies for p2p mgmt interface, as otherwise p2p packets come out with arbitrary rates. Since wpa_supplicant currently doesn't support standalone p2p device mode (without another attached managed interface), add p2p device to the allowed interface combinations without decreasing the allowed station count. Moreover, increase the station count in some cases, as AP mode usually starts as station interface, and the AP interface is now different from the p2p management one). Signed-off-by: Arik Nemtsov Signed-off-by: Eliad Peller Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wl12xx/scan.c | 6 ++- drivers/net/wireless/ti/wl18xx/main.c | 48 ++++++++++++++++++++- drivers/net/wireless/ti/wl18xx/scan.c | 6 ++- drivers/net/wireless/ti/wlcore/cmd.c | 26 +++++++----- drivers/net/wireless/ti/wlcore/init.c | 2 +- drivers/net/wireless/ti/wlcore/init.h | 1 + drivers/net/wireless/ti/wlcore/main.c | 69 +++++++++++++++++++++++++------ drivers/net/wireless/ti/wlcore/wlcore_i.h | 5 +++ 8 files changed, 136 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wl12xx/scan.c b/drivers/net/wireless/ti/wl12xx/scan.c index 0c0d5cd98514..7c355fff2c5e 100644 --- a/drivers/net/wireless/ti/wl12xx/scan.c +++ b/drivers/net/wireless/ti/wl12xx/scan.c @@ -118,7 +118,11 @@ static int wl1271_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; - cmd->params.role_id = wlvif->role_id; + /* scan on the dev role if the regular one is not started */ + if (wlcore_is_p2p_mgmt(wlvif)) + cmd->params.role_id = wlvif->dev_role_id; + else + cmd->params.role_id = wlvif->role_id; if (WARN_ON(cmd->params.role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index f9c9d5cf0854..abbf054fb6da 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -1804,7 +1804,7 @@ static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = { static const struct ieee80211_iface_limit wl18xx_iface_limits[] = { { - .max = 3, + .max = 2, .types = BIT(NL80211_IFTYPE_STATION), }, { @@ -1813,6 +1813,10 @@ static const struct ieee80211_iface_limit wl18xx_iface_limits[] = { BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, }; static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = { @@ -1820,6 +1824,48 @@ static const struct ieee80211_iface_limit wl18xx_iface_ap_limits[] = { .max = 2, .types = BIT(NL80211_IFTYPE_AP), }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + +static const struct ieee80211_iface_limit wl18xx_iface_ap_cl_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + +static const struct ieee80211_iface_limit wl18xx_iface_ap_go_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, }; static const struct ieee80211_iface_combination diff --git a/drivers/net/wireless/ti/wl18xx/scan.c b/drivers/net/wireless/ti/wl18xx/scan.c index ec2eb147add3..c938c494c785 100644 --- a/drivers/net/wireless/ti/wl18xx/scan.c +++ b/drivers/net/wireless/ti/wl18xx/scan.c @@ -51,7 +51,11 @@ static int wl18xx_scan_send(struct wl1271 *wl, struct wl12xx_vif *wlvif, goto out; } - cmd->role_id = wlvif->role_id; + /* scan on the dev role if the regular one is not started */ + if (wlcore_is_p2p_mgmt(wlvif)) + cmd->role_id = wlvif->dev_role_id; + else + cmd->role_id = wlvif->role_id; if (WARN_ON(cmd->role_id == WL12XX_INVALID_ROLE_ID)) { ret = -EINVAL; diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index dbc55a0aa905..f01d24baff7c 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -2003,12 +2003,15 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif, wlvif->bss_type == BSS_TYPE_IBSS))) return -EINVAL; - ret = wl12xx_cmd_role_enable(wl, - wl12xx_wlvif_to_vif(wlvif)->addr, - WL1271_ROLE_DEVICE, - &wlvif->dev_role_id); - if (ret < 0) - goto out; + /* the dev role is already started for p2p mgmt interfaces */ + if (!wlcore_is_p2p_mgmt(wlvif)) { + ret = wl12xx_cmd_role_enable(wl, + wl12xx_wlvif_to_vif(wlvif)->addr, + WL1271_ROLE_DEVICE, + &wlvif->dev_role_id); + if (ret < 0) + goto out; + } ret = wl12xx_cmd_role_start_dev(wl, wlvif, band, channel); if (ret < 0) @@ -2023,7 +2026,8 @@ int wl12xx_start_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif, out_stop: wl12xx_cmd_role_stop_dev(wl, wlvif); out_disable: - wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); + if (!wlcore_is_p2p_mgmt(wlvif)) + wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); out: return ret; } @@ -2052,9 +2056,11 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) if (ret < 0) goto out; - ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); - if (ret < 0) - goto out; + if (!wlcore_is_p2p_mgmt(wlvif)) { + ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); + if (ret < 0) + goto out; + } out: return ret; diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index 5ca1fb161a50..e92f2639af2c 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c @@ -348,7 +348,7 @@ static int wl12xx_init_fwlog(struct wl1271 *wl) } /* generic sta initialization (non vif-specific) */ -static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) +int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif) { int ret; diff --git a/drivers/net/wireless/ti/wlcore/init.h b/drivers/net/wireless/ti/wlcore/init.h index a45fbfddec19..fd1cdb6bc3e4 100644 --- a/drivers/net/wireless/ti/wlcore/init.h +++ b/drivers/net/wireless/ti/wlcore/init.h @@ -35,5 +35,6 @@ int wl1271_hw_init(struct wl1271 *wl); int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif); int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif); int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif); +int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif); #endif diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 337223b9f6f8..e819369d8f8f 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1792,6 +1792,9 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, wl->wow_enabled = true; wl12xx_for_each_wlvif(wl, wlvif) { + if (wlcore_is_p2p_mgmt(wlvif)) + continue; + ret = wl1271_configure_suspend(wl, wlvif, wow); if (ret < 0) { mutex_unlock(&wl->mutex); @@ -1901,6 +1904,9 @@ static int wl1271_op_resume(struct ieee80211_hw *hw) goto out; wl12xx_for_each_wlvif(wl, wlvif) { + if (wlcore_is_p2p_mgmt(wlvif)) + continue; + wl1271_configure_resume(wl, wlvif); } @@ -2256,6 +2262,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) wlvif->p2p = 1; /* fall-through */ case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_DEVICE: wlvif->bss_type = BSS_TYPE_STA_BSS; break; case NL80211_IFTYPE_ADHOC: @@ -2477,7 +2484,8 @@ static void wlcore_hw_queue_iter(void *data, u8 *mac, { struct wlcore_hw_queue_iter_data *iter_data = data; - if (WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE)) + if (vif->type == NL80211_IFTYPE_P2P_DEVICE || + WARN_ON_ONCE(vif->hw_queue[0] == IEEE80211_INVAL_HW_QUEUE)) return; if (iter_data->cur_running || vif == iter_data->vif) { @@ -2495,6 +2503,11 @@ static int wlcore_allocate_hw_queue_base(struct wl1271 *wl, struct wlcore_hw_queue_iter_data iter_data = {}; int i, q_base; + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { + vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; + return 0; + } + iter_data.vif = vif; /* mark all bits taken by active interfaces */ @@ -2618,14 +2631,27 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } - ret = wl12xx_cmd_role_enable(wl, vif->addr, - role_type, &wlvif->role_id); - if (ret < 0) - goto out; + if (!wlcore_is_p2p_mgmt(wlvif)) { + ret = wl12xx_cmd_role_enable(wl, vif->addr, + role_type, &wlvif->role_id); + if (ret < 0) + goto out; - ret = wl1271_init_vif_specific(wl, vif); - if (ret < 0) - goto out; + ret = wl1271_init_vif_specific(wl, vif); + if (ret < 0) + goto out; + + } else { + ret = wl12xx_cmd_role_enable(wl, vif->addr, WL1271_ROLE_DEVICE, + &wlvif->dev_role_id); + if (ret < 0) + goto out; + + /* needed mainly for configuring rate policies */ + ret = wl1271_sta_hw_init(wl, wlvif); + if (ret < 0) + goto out; + } list_add(&wlvif->list, &wl->wlvif_list); set_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags); @@ -2696,9 +2722,15 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl12xx_stop_dev(wl, wlvif); } - ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); - if (ret < 0) - goto deinit; + if (!wlcore_is_p2p_mgmt(wlvif)) { + ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); + if (ret < 0) + goto deinit; + } else { + ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); + if (ret < 0) + goto deinit; + } wl1271_ps_elp_sleep(wl); } @@ -3088,6 +3120,9 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, { int ret; + if (wlcore_is_p2p_mgmt(wlvif)) + return 0; + if (conf->power_level != wlvif->power_level) { ret = wl1271_acx_tx_power(wl, wlvif, conf->power_level); if (ret < 0) @@ -3207,6 +3242,9 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, goto out; wl12xx_for_each_wlvif(wl, wlvif) { + if (wlcore_is_p2p_mgmt(wlvif)) + continue; + if (wlvif->bss_type != BSS_TYPE_AP_BSS) { if (*total & FIF_ALLMULTI) ret = wl1271_acx_group_address_tbl(wl, wlvif, @@ -4837,6 +4875,9 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u8 ps_scheme; int ret = 0; + if (wlcore_is_p2p_mgmt(wlvif)) + return 0; + mutex_lock(&wl->mutex); wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); @@ -6078,8 +6119,10 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); wl->hw->wiphy->max_scan_ssids = 1; wl->hw->wiphy->max_sched_scan_ssids = 16; wl->hw->wiphy->max_match_sets = 16; diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 39efc6d78b10..27c56876b2c1 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -503,6 +503,11 @@ struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif) return container_of((void *)wlvif, struct ieee80211_vif, drv_priv); } +static inline bool wlcore_is_p2p_mgmt(struct wl12xx_vif *wlvif) +{ + return wl12xx_wlvif_to_vif(wlvif)->type == NL80211_IFTYPE_P2P_DEVICE; +} + #define wl12xx_for_each_wlvif(wl, wlvif) \ list_for_each_entry(wlvif, &wl->wlvif_list, list) -- cgit v1.3-6-gb490 From bed429e1ae8b7ee207e01f3aa60dcc0d06a8ed4d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 31 Jul 2015 15:04:46 +0200 Subject: mt7601u: fix dma from stack address DMA to variables located on the stack is a bad idea. For simplicity and to avoid frequent allocations create a buffer inside the device structure. Protect this buffer with vendor_req_mutex. Don't protect vendor requests which don't use this buffer. Signed-off-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 4 +- drivers/net/wireless/mediatek/mt7601u/usb.c | 63 ++++++++++++------------- drivers/net/wireless/mediatek/mt7601u/usb.h | 2 + 3 files changed, 34 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h index 9102be6b95cb..6bdfc1103fcc 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h @@ -146,7 +146,7 @@ enum { * @rx_lock: protects @rx_q. * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. * @mutex: ensures exclusive access from mac80211 callbacks. - * @vendor_req_mutex: ensures atomicity of vendor requests. + * @vendor_req_mutex: protects @vend_buf, ensures atomicity of split writes. * @reg_atomic_mutex: ensures atomicity of indirect register accesses * (accesses to RF and BBP). * @hw_atomic_mutex: ensures exclusive access to HW during critical @@ -184,6 +184,8 @@ struct mt7601u_dev { struct mt7601u_eeprom_params *ee; struct mutex vendor_req_mutex; + void *vend_buf; + struct mutex reg_atomic_mutex; struct mutex hw_atomic_mutex; diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c index 54dba4001865..416c6045ff31 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.c +++ b/drivers/net/wireless/mediatek/mt7601u/usb.c @@ -92,10 +92,9 @@ void mt7601u_complete_urb(struct urb *urb) complete(cmpl); } -static int -__mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, - const u8 direction, const u16 val, const u16 offset, - void *buf, const size_t buflen) +int mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, + const u8 direction, const u16 val, const u16 offset, + void *buf, const size_t buflen) { int i, ret; struct usb_device *usb_dev = mt7601u_to_usb_dev(dev); @@ -110,6 +109,8 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, trace_mt_vend_req(dev, pipe, req, req_type, val, offset, buf, buflen, ret); + if (ret == -ENODEV) + set_bit(MT7601U_STATE_REMOVED, &dev->state); if (ret >= 0 || ret == -ENODEV) return ret; @@ -122,25 +123,6 @@ __mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, return ret; } -int -mt7601u_vendor_request(struct mt7601u_dev *dev, const u8 req, - const u8 direction, const u16 val, const u16 offset, - void *buf, const size_t buflen) -{ - int ret; - - mutex_lock(&dev->vendor_req_mutex); - - ret = __mt7601u_vendor_request(dev, req, direction, val, offset, - buf, buflen); - if (ret == -ENODEV) - set_bit(MT7601U_STATE_REMOVED, &dev->state); - - mutex_unlock(&dev->vendor_req_mutex); - - return ret; -} - void mt7601u_vendor_reset(struct mt7601u_dev *dev) { mt7601u_vendor_request(dev, MT_VEND_DEV_MODE, USB_DIR_OUT, @@ -150,19 +132,21 @@ void mt7601u_vendor_reset(struct mt7601u_dev *dev) u32 mt7601u_rr(struct mt7601u_dev *dev, u32 offset) { int ret; - __le32 reg; - u32 val; + u32 val = ~0; WARN_ONCE(offset > USHRT_MAX, "read high off:%08x", offset); + mutex_lock(&dev->vendor_req_mutex); + ret = mt7601u_vendor_request(dev, MT_VEND_MULTI_READ, USB_DIR_IN, - 0, offset, ®, sizeof(reg)); - val = le32_to_cpu(reg); - if (ret > 0 && ret != sizeof(reg)) { + 0, offset, dev->vend_buf, MT_VEND_BUF); + if (ret == MT_VEND_BUF) + val = get_unaligned_le32(dev->vend_buf); + else if (ret > 0) dev_err(dev->dev, "Error: wrong size read:%d off:%08x\n", ret, offset); - val = ~0; - } + + mutex_unlock(&dev->vendor_req_mutex); trace_reg_read(dev, offset, val); return val; @@ -173,12 +157,17 @@ int mt7601u_vendor_single_wr(struct mt7601u_dev *dev, const u8 req, { int ret; + mutex_lock(&dev->vendor_req_mutex); + ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, val & 0xffff, offset, NULL, 0); - if (ret) - return ret; - return mt7601u_vendor_request(dev, req, USB_DIR_OUT, - val >> 16, offset + 2, NULL, 0); + if (!ret) + ret = mt7601u_vendor_request(dev, req, USB_DIR_OUT, + val >> 16, offset + 2, NULL, 0); + + mutex_unlock(&dev->vendor_req_mutex); + + return ret; } void mt7601u_wr(struct mt7601u_dev *dev, u32 offset, u32 val) @@ -275,6 +264,12 @@ static int mt7601u_probe(struct usb_interface *usb_intf, usb_set_intfdata(usb_intf, dev); + dev->vend_buf = devm_kmalloc(dev->dev, MT_VEND_BUF, GFP_KERNEL); + if (!dev->vend_buf) { + ret = -ENOMEM; + goto err; + } + ret = mt7601u_assign_pipes(usb_intf, dev); if (ret) goto err; diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.h b/drivers/net/wireless/mediatek/mt7601u/usb.h index 49e188fa3798..bc182022b9d6 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.h +++ b/drivers/net/wireless/mediatek/mt7601u/usb.h @@ -23,6 +23,8 @@ #define MT_VEND_DEV_MODE_RESET 1 +#define MT_VEND_BUF sizeof(__le32) + enum mt_vendor_req { MT_VEND_DEV_MODE = 1, MT_VEND_WRITE = 2, -- cgit v1.3-6-gb490 From d9517c0a5d7468a7ea63086057604fcb0fff480e Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 31 Jul 2015 15:04:47 +0200 Subject: mt7601u: use correct ieee80211_rx variant Rx is run inside a tasklet so ieee80211_rx() should be used instead of ieee80211_rx_ni(). Signed-off-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index 7217da4f1543..fb183e369d92 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -112,7 +112,7 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, if (!skb) return; - ieee80211_rx_ni(dev->hw, skb); + ieee80211_rx(dev->hw, skb); } static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) -- cgit v1.3-6-gb490 From 4513493d188d5e3052aee68eda85eaaa1a4e41c2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 31 Jul 2015 15:04:48 +0200 Subject: mt7601u: fix tx status reporting contexts mac80211 requires that rx path does not run concurrently with tx status reporting. Since rx path is run in driver tasklet, tx status cannot be reported directly from interrupt context (there would be no way to lock it out). Add tasklet for tx and move all possible code from irq handler there. Note: tx tasklet is needed because workqueue is queued very rarely and that kills TCP performance. Signed-off-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/dma.c | 30 +++++++++++++++++++++---- drivers/net/wireless/mediatek/mt7601u/init.c | 1 + drivers/net/wireless/mediatek/mt7601u/mac.c | 4 ++++ drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 2 ++ 4 files changed, 33 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index fb183e369d92..63c485443a38 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -236,23 +236,42 @@ static void mt7601u_complete_tx(struct urb *urb) skb = q->e[q->start].skb; trace_mt_tx_dma_done(dev, skb); - mt7601u_tx_status(dev, skb); + __skb_queue_tail(&dev->tx_skb_done, skb); + tasklet_schedule(&dev->tx_tasklet); if (q->used == q->entries - q->entries / 8) ieee80211_wake_queue(dev->hw, skb_get_queue_mapping(skb)); q->start = (q->start + 1) % q->entries; q->used--; +out: + spin_unlock_irqrestore(&dev->tx_lock, flags); +} - if (urb->status) - goto out; +static void mt7601u_tx_tasklet(unsigned long data) +{ + struct mt7601u_dev *dev = (struct mt7601u_dev *) data; + struct sk_buff_head skbs; + unsigned long flags; + + __skb_queue_head_init(&skbs); + + spin_lock_irqsave(&dev->tx_lock, flags); set_bit(MT7601U_STATE_MORE_STATS, &dev->state); if (!test_and_set_bit(MT7601U_STATE_READING_STATS, &dev->state)) queue_delayed_work(dev->stat_wq, &dev->stat_work, msecs_to_jiffies(10)); -out: + + skb_queue_splice_init(&dev->tx_skb_done, &skbs); + spin_unlock_irqrestore(&dev->tx_lock, flags); + + while (!skb_queue_empty(&skbs)) { + struct sk_buff *skb = __skb_dequeue(&skbs); + + mt7601u_tx_status(dev, skb); + } } static int mt7601u_dma_submit_tx(struct mt7601u_dev *dev, @@ -475,6 +494,7 @@ int mt7601u_dma_init(struct mt7601u_dev *dev) { int ret = -ENOMEM; + tasklet_init(&dev->tx_tasklet, mt7601u_tx_tasklet, (unsigned long) dev); tasklet_init(&dev->rx_tasklet, mt7601u_rx_tasklet, (unsigned long) dev); ret = mt7601u_alloc_tx(dev); @@ -502,4 +522,6 @@ void mt7601u_dma_cleanup(struct mt7601u_dev *dev) mt7601u_free_rx(dev); mt7601u_free_tx(dev); + + tasklet_kill(&dev->tx_tasklet); } diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c index df3dd56199a7..38eb20ba6e58 100644 --- a/drivers/net/wireless/mediatek/mt7601u/init.c +++ b/drivers/net/wireless/mediatek/mt7601u/init.c @@ -456,6 +456,7 @@ struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) spin_lock_init(&dev->lock); spin_lock_init(&dev->con_mon_lock); atomic_set(&dev->avg_ampdu_len, 1); + skb_queue_head_init(&dev->tx_skb_done); dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0); if (!dev->stat_wq) { diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c index 7514bce1ac91..e3928cfa3d63 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mac.c +++ b/drivers/net/wireless/mediatek/mt7601u/mac.c @@ -181,7 +181,11 @@ void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) } mt76_mac_fill_tx_status(dev, &info, stat); + + local_bh_disable(); ieee80211_tx_status_noskb(dev->hw, sta, &info); + local_bh_enable(); + rcu_read_unlock(); } diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h index 6bdfc1103fcc..bc5e294feb8c 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h @@ -199,7 +199,9 @@ struct mt7601u_dev { /* TX */ spinlock_t tx_lock; + struct tasklet_struct tx_tasklet; struct mt7601u_tx_queue *tx_q; + struct sk_buff_head tx_skb_done; atomic_t avg_ampdu_len; -- cgit v1.3-6-gb490 From 78623bfb6f4cbdba3183621e8e0e781611217022 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 31 Jul 2015 15:04:49 +0200 Subject: mt7601u: lock out rx path and tx status reporting mac80211 requires that rx path does not run concurrently with tx status reporting. Add a spinlock which will ensure that. Signed-off-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/dma.c | 2 ++ drivers/net/wireless/mediatek/mt7601u/init.c | 1 + drivers/net/wireless/mediatek/mt7601u/mac.c | 4 ++-- drivers/net/wireless/mediatek/mt7601u/mt7601u.h | 4 +++- drivers/net/wireless/mediatek/mt7601u/tx.c | 3 +++ 5 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index 63c485443a38..57a80cfa39b1 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -112,7 +112,9 @@ static void mt7601u_rx_process_seg(struct mt7601u_dev *dev, u8 *data, if (!skb) return; + spin_lock(&dev->mac_lock); ieee80211_rx(dev->hw, skb); + spin_unlock(&dev->mac_lock); } static u16 mt7601u_rx_next_seg_len(u8 *data, u32 data_len) diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c index 38eb20ba6e58..26190fd33407 100644 --- a/drivers/net/wireless/mediatek/mt7601u/init.c +++ b/drivers/net/wireless/mediatek/mt7601u/init.c @@ -454,6 +454,7 @@ struct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) spin_lock_init(&dev->tx_lock); spin_lock_init(&dev->rx_lock); spin_lock_init(&dev->lock); + spin_lock_init(&dev->mac_lock); spin_lock_init(&dev->con_mon_lock); atomic_set(&dev->avg_ampdu_len, 1); skb_queue_head_init(&dev->tx_skb_done); diff --git a/drivers/net/wireless/mediatek/mt7601u/mac.c b/drivers/net/wireless/mediatek/mt7601u/mac.c index e3928cfa3d63..e21c53ed09fb 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mac.c +++ b/drivers/net/wireless/mediatek/mt7601u/mac.c @@ -182,9 +182,9 @@ void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) mt76_mac_fill_tx_status(dev, &info, stat); - local_bh_disable(); + spin_lock_bh(&dev->mac_lock); ieee80211_tx_status_noskb(dev->hw, sta, &info); - local_bh_enable(); + spin_unlock_bh(&dev->mac_lock); rcu_read_unlock(); } diff --git a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h index bc5e294feb8c..428bd2f10b7b 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mt7601u.h +++ b/drivers/net/wireless/mediatek/mt7601u/mt7601u.h @@ -141,8 +141,9 @@ enum { /** * struct mt7601u_dev - adapter structure * @lock: protects @wcid->tx_rate. + * @mac_lock: locks out mac80211's tx status and rx paths. * @tx_lock: protects @tx_q and changes of MT7601U_STATE_*_STATS - flags in @state. + * flags in @state. * @rx_lock: protects @rx_q. * @con_mon_lock: protects @ap_bssid, @bcn_*, @avg_rssi. * @mutex: ensures exclusive access from mac80211 callbacks. @@ -177,6 +178,7 @@ struct mt7601u_dev { struct mt76_wcid __rcu *wcid[N_WCIDS]; spinlock_t lock; + spinlock_t mac_lock; const u16 *beacon_offsets; diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c index 0be2080ceab3..a0a33dc8f6bc 100644 --- a/drivers/net/wireless/mediatek/mt7601u/tx.c +++ b/drivers/net/wireless/mediatek/mt7601u/tx.c @@ -116,7 +116,10 @@ void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb) ieee80211_tx_info_clear_status(info); info->status.rates[0].idx = -1; info->flags |= IEEE80211_TX_STAT_ACK; + + spin_lock(&dev->mac_lock); ieee80211_tx_status(dev->hw, skb); + spin_unlock(&dev->mac_lock); } static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb) -- cgit v1.3-6-gb490 From 53cd2fdb00aab34f91762f6345f83625a30480f0 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 2 Aug 2015 20:26:52 +0200 Subject: bcma: fix access to host_pdev for PCIe devices bus->host_pdev is part of a union so bus->host_pdev != NULL is probably also true for PCIe devices, because there it accesses bus->host_pci. If we access the dev member at the offset defined in struct platform_device in struct pci_dev instead we probably get something else. This patch adds a new function which returns the host dev struct and NULL if we do not have a host dev. When this gets registered on MIPS brcm47xx we do not have a host dev in some situations. This function could also be used in other places. This problem was introduced in this commit: commit cae761b5a6bdc597ba476a040fdcd5b4bc559b85 Author: Rafa? Mi?ecki Date: Sun Jun 28 17:17:13 2015 +0200 bcma: populate bus DT subnodes as platform_device-s Signed-off-by: Hauke Mehrtens Signed-off-by: Kalle Valo --- drivers/bcma/bcma_private.h | 1 + drivers/bcma/main.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index 15f2b2e242ea..38f156745d53 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -34,6 +34,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus); int bcma_bus_suspend(struct bcma_bus *bus); int bcma_bus_resume(struct bcma_bus *bus); #endif +struct device *bcma_bus_get_host_dev(struct bcma_bus *bus); /* scan.c */ void bcma_detect_chip(struct bcma_bus *bus); diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 8d973c4fc84e..24882c18fcbe 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -7,7 +7,9 @@ #include "bcma_private.h" #include +#include #include +#include #include #include #include @@ -269,6 +271,28 @@ void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) } } +struct device *bcma_bus_get_host_dev(struct bcma_bus *bus) +{ + switch (bus->hosttype) { + case BCMA_HOSTTYPE_PCI: + if (bus->host_pci) + return &bus->host_pci->dev; + else + return NULL; + case BCMA_HOSTTYPE_SOC: + if (bus->host_pdev) + return &bus->host_pdev->dev; + else + return NULL; + case BCMA_HOSTTYPE_SDIO: + if (bus->host_sdio) + return &bus->host_sdio->dev; + else + return NULL; + } + return NULL; +} + void bcma_init_bus(struct bcma_bus *bus) { mutex_lock(&bcma_buses_mutex); @@ -388,6 +412,7 @@ int bcma_bus_register(struct bcma_bus *bus) { int err; struct bcma_device *core; + struct device *dev; /* Scan for devices (cores) */ err = bcma_bus_scan(bus); @@ -410,13 +435,12 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_pci_early_init(&bus->drv_pci[0]); } + dev = bcma_bus_get_host_dev(bus); /* TODO: remove check for IS_BUILTIN(CONFIG_BCMA) check when * of_default_bus_match_table is exported or in some other way * accessible. This is just a temporary workaround. */ - if (IS_BUILTIN(CONFIG_BCMA) && bus->host_pdev) { - struct device *dev = &bus->host_pdev->dev; - + if (IS_BUILTIN(CONFIG_BCMA) && dev) { of_platform_populate(dev->of_node, of_default_bus_match_table, NULL, dev); } -- cgit v1.3-6-gb490 From 9b412590faaea65dab54f9bc5ae5b48ba0e73c5d Mon Sep 17 00:00:00 2001 From: Bertold Van den Bergh Date: Mon, 3 Aug 2015 15:45:41 +0200 Subject: ath: Make ath_opmode_to_string understand OCB mode Make ath_opmode_to_string return "OCB" for NL80211_IFTYPE_OCB. Currently it will return "UNKNOWN". Signed-off-by: Bertold Van den Bergh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/debug.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/debug.c b/drivers/net/wireless/ath/debug.c index 508eccf5d982..d59d83e0ce4b 100644 --- a/drivers/net/wireless/ath/debug.c +++ b/drivers/net/wireless/ath/debug.c @@ -40,6 +40,8 @@ const char *ath_opmode_to_string(enum nl80211_iftype opmode) return "P2P-CLIENT"; case NL80211_IFTYPE_P2P_GO: return "P2P-GO"; + case NL80211_IFTYPE_OCB: + return "OCB"; default: return "UNKNOWN"; } -- cgit v1.3-6-gb490 From 1469d17dd341458267a08c8d8bb517cb986ec56d Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Tue, 21 Jul 2015 12:25:30 -0400 Subject: PCI: pciehp: Handle invalid data when reading from non-existent devices It's platform-dependent, but an MMIO read to a non-existent PCI device generally returns data with all bits set. This happens when the host bridge or Root Complex times out waiting for a response from the device and fabricates return data to complete the CPU's read. One example, reported in the bugzilla below, involved this hierarchy: pci 0000:00:1c.0: PCI bridge to [bus 02-3a] Root Port pci 0000:02:00.0: PCI bridge to [bus 03-0a] Upstream Port pci 0000:03:03.0: PCI bridge to [bus 05-07] Downstream Port pci 0000:05:00.0: PCI bridge to [bus 06-07] Thunderbolt Upstream Port pci 0000:06:00.0: PCI bridge to [bus 07] Thunderbolt Downstream Port pci 0000:07:00.0: BCM57762 NIC Unplugging the Thunderbolt switch and the NIC below it resulted in this: pciehp 0000:03:03.0: Surprise Removal tg3 0000:07:00.0: tg3_abort_hw timed out, TX_MODE_ENABLE will not clear MAC_TX_MODE=ffffffff pciehp 0000:06:00.0: unloading service driver pciehp pciehp 0000:06:00.0: pcie_isr: intr_loc 11f pciehp 0000:06:00.0: Switch interrupt received pciehp 0000:06:00.0: Latch open on Slot pciehp 0000:06:00.0: Attention button interrupt received pciehp 0000:06:00.0: Button pressed on Slot pciehp 0000:06:00.0: Presence/Notify input change pciehp 0000:06:00.0: Card present on Slot pciehp 0000:06:00.0: Power fault interrupt received pciehp 0000:06:00.0: Data Link Layer State change pciehp 0000:06:00.0: Link Up event The pciehp driver correctly noticed that the Thunderbolt switch (05:00.0 and 06:00.0) and NIC (07:00.0) had been removed, and it called their driver remove methods. Since the NIC was already gone, tg3 received 0xffffffff when it tried to read from the device. The resulting timeout is a tg3 issue and not of interest here. Similarly, since the 06:00.0 Thunderbolt switch was already gone, pcie_isr() received 0xffff when it tried to read PCI_EXP_SLTSTA, and pciehp thought that was valid status showing that many events had happened: the latch had been opened, the attention button had been pressed, a card was now present, and the link was now up. These are all wrong, of course, but pciehp went on to try to power up and enumerate devices below the non-existent bridge: pciehp 0000:06:00.0: PCI slot - powering on due to button press pciehp 0000:06:00.0: Surprise Insertion pci 0000:07:00.0 id reading try 50 times with interval 20 ms to get ffffffff [bhelgaas: changelog, also check in pcie_poll_cmd() & pcie_do_write_cmd()] Link: https://bugzilla.kernel.org/show_bug.cgi?id=99841 Suggested-by: Bjorn Helgaas Signed-off-by: Jarod Wilson Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp_hpc.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index daf54bee720d..8f3d3cff3581 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -111,6 +111,12 @@ static int pcie_poll_cmd(struct controller *ctrl, int timeout) while (true) { pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status); + if (slot_status == (u16) ~0) { + ctrl_info(ctrl, "%s: no response from device\n", + __func__); + return 0; + } + if (slot_status & PCI_EXP_SLTSTA_CC) { pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC); @@ -186,6 +192,11 @@ static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd, pcie_wait_cmd(ctrl); pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl); + if (slot_ctrl == (u16) ~0) { + ctrl_info(ctrl, "%s: no response from device\n", __func__); + goto out; + } + slot_ctrl &= ~mask; slot_ctrl |= (cmd & mask); ctrl->cmd_busy = 1; @@ -201,6 +212,7 @@ static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd, if (wait) pcie_wait_cmd(ctrl); +out: mutex_unlock(&ctrl->ctrl_lock); } @@ -542,6 +554,11 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) intr_loc = 0; do { pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &detected); + if (detected == (u16) ~0) { + ctrl_info(ctrl, "%s: no response from device\n", + __func__); + return IRQ_HANDLED; + } detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | -- cgit v1.3-6-gb490 From 58fa2405bd44805cb6166603100b0183ce26a0c8 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 1 Jul 2015 17:01:03 -0500 Subject: PCI: pciehp: Remove unused interrupt events The list of interrupt events (INT_BUTTON_IGNORE, INT_PRESENCE_ON, etc.) was copied from other hotplug drivers, but pciehp doesn't use them all. Remove the interrupt events that aren't used by pciehp. Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 57cd1327346f..aca84e1b81be 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -101,18 +101,14 @@ struct controller { unsigned int power_fault_detected; }; -#define INT_BUTTON_IGNORE 0 #define INT_PRESENCE_ON 1 #define INT_PRESENCE_OFF 2 #define INT_SWITCH_CLOSE 3 #define INT_SWITCH_OPEN 4 #define INT_POWER_FAULT 5 -#define INT_POWER_FAULT_CLEAR 6 -#define INT_BUTTON_PRESS 7 -#define INT_BUTTON_RELEASE 8 -#define INT_BUTTON_CANCEL 9 -#define INT_LINK_UP 10 -#define INT_LINK_DOWN 11 +#define INT_BUTTON_PRESS 6 +#define INT_LINK_UP 7 +#define INT_LINK_DOWN 8 #define STATIC_STATE 0 #define BLINKINGON_STATE 1 -- cgit v1.3-6-gb490 From 2db0f71f56795f6b04d386b15c3b32b570558ebd Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 1 Jul 2015 17:17:49 -0500 Subject: PCI: pciehp: Remove ignored MRL sensor interrupt events We queued interrupt events for the MRL being opened or closed, but the code in interrupt_event_handler() that handles these events ignored them. Stop enabling MRL interrupts and remove the ignored events. Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp.h | 10 ++++------ drivers/pci/hotplug/pciehp_hpc.c | 17 +++-------------- 2 files changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index aca84e1b81be..62d6fe6c3714 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -103,12 +103,10 @@ struct controller { #define INT_PRESENCE_ON 1 #define INT_PRESENCE_OFF 2 -#define INT_SWITCH_CLOSE 3 -#define INT_SWITCH_OPEN 4 -#define INT_POWER_FAULT 5 -#define INT_BUTTON_PRESS 6 -#define INT_LINK_UP 7 -#define INT_LINK_DOWN 8 +#define INT_POWER_FAULT 3 +#define INT_BUTTON_PRESS 4 +#define INT_LINK_UP 5 +#define INT_LINK_DOWN 6 #define STATIC_STATE 0 #define BLINKINGON_STATE 1 diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 8f3d3cff3581..5c24e938042f 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -543,7 +543,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) struct pci_dev *dev; struct slot *slot = ctrl->slot; u16 detected, intr_loc; - u8 open, present; + u8 present; bool link; /* @@ -561,7 +561,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) } detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | - PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | + PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC); detected &= ~intr_loc; intr_loc |= detected; @@ -594,15 +594,6 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) if (!(intr_loc & ~PCI_EXP_SLTSTA_CC)) return IRQ_HANDLED; - /* Check MRL Sensor Changed */ - if (intr_loc & PCI_EXP_SLTSTA_MRLSC) { - pciehp_get_latch_status(slot, &open); - ctrl_info(ctrl, "Latch %s on Slot(%s)\n", - open ? "open" : "close", slot_name(slot)); - pciehp_queue_interrupt_event(slot, open ? INT_SWITCH_OPEN : - INT_SWITCH_CLOSE); - } - /* Check Attention Button Pressed */ if (intr_loc & PCI_EXP_SLTSTA_ABP) { ctrl_info(ctrl, "Button pressed on Slot(%s)\n", @@ -662,13 +653,11 @@ void pcie_enable_notification(struct controller *ctrl) cmd |= PCI_EXP_SLTCTL_ABPE; else cmd |= PCI_EXP_SLTCTL_PDCE; - if (MRL_SENS(ctrl)) - cmd |= PCI_EXP_SLTCTL_MRLSCE; if (!pciehp_poll_mode) cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE; mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | - PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | + PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | PCI_EXP_SLTCTL_DLLSCE); -- cgit v1.3-6-gb490 From c4bc44c65b6b24722506ad5d1bbf557a71d3df90 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Fri, 7 Aug 2015 13:52:37 +0800 Subject: net: fec: fix the race between xmit and bdp reclaiming path When we transmit a fragmented skb, we may run into a race like the following scenario (assume txq->cur_tx is next to txq->dirty_tx): cpu 0 cpu 1 fec_enet_txq_submit_skb reserve a bdp for the first fragment fec_enet_txq_submit_frag_skb update the bdp for the other fragment update txq->cur_tx fec_enet_tx_queue bdp = fec_enet_get_nextdesc(txq->dirty_tx, fep, queue_id); This bdp is the bdp reserved for the first segment. Given that this bdp BD_ENET_TX_READY bit is not set and txq->cur_tx is already pointed to a bdp beyond this one. We think this is a completed bdp and try to reclaim it. update the bdp for the first segment update txq->cur_tx So we shouldn't update the txq->cur_tx until all the update to the bdps used for fragments are performed. Also add the corresponding memory barrier to guarantee that the update to the bdps, dirty_tx and cur_tx performed in the proper order. Signed-off-by: Kevin Hao Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 35 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 32e3807c650e..ca792368f5df 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -364,7 +364,7 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev) return 0; } -static int +static struct bufdesc * fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq, struct sk_buff *skb, struct net_device *ndev) @@ -439,10 +439,7 @@ fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq, bdp->cbd_sc = status; } - txq->cur_tx = bdp; - - return 0; - + return bdp; dma_mapping_error: bdp = txq->cur_tx; for (i = 0; i < frag; i++) { @@ -450,7 +447,7 @@ dma_mapping_error: dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, bdp->cbd_datlen, DMA_TO_DEVICE); } - return NETDEV_TX_OK; + return ERR_PTR(-ENOMEM); } static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq, @@ -467,7 +464,6 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq, unsigned int estatus = 0; unsigned int index; int entries_free; - int ret; entries_free = fec_enet_get_free_txdesc_num(fep, txq); if (entries_free < MAX_SKB_FRAGS + 1) { @@ -485,6 +481,7 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq, /* Fill in a Tx ring entry */ bdp = txq->cur_tx; + last_bdp = bdp; status = bdp->cbd_sc; status &= ~BD_ENET_TX_STATS; @@ -513,9 +510,9 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq, } if (nr_frags) { - ret = fec_enet_txq_submit_frag_skb(txq, skb, ndev); - if (ret) - return ret; + last_bdp = fec_enet_txq_submit_frag_skb(txq, skb, ndev); + if (IS_ERR(last_bdp)) + return NETDEV_TX_OK; } else { status |= (BD_ENET_TX_INTR | BD_ENET_TX_LAST); if (fep->bufdesc_ex) { @@ -544,7 +541,6 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq, ebdp->cbd_esc = estatus; } - last_bdp = txq->cur_tx; index = fec_enet_get_bd_index(txq->tx_bd_base, last_bdp, fep); /* Save skb pointer */ txq->tx_skbuff[index] = skb; @@ -563,6 +559,10 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq, skb_tx_timestamp(skb); + /* Make sure the update to bdp and tx_skbuff are performed before + * cur_tx. + */ + wmb(); txq->cur_tx = bdp; /* Trigger transmission start */ @@ -1218,10 +1218,11 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id) /* get next bdp of dirty_tx */ bdp = fec_enet_get_nextdesc(bdp, fep, queue_id); - while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { - - /* current queue is empty */ - if (bdp == txq->cur_tx) + while (bdp != READ_ONCE(txq->cur_tx)) { + /* Order the load of cur_tx and cbd_sc */ + rmb(); + status = READ_ONCE(bdp->cbd_sc); + if (status & BD_ENET_TX_READY) break; index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep); @@ -1275,6 +1276,10 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id) /* Free the sk buffer associated with this last transmit */ dev_kfree_skb_any(skb); + /* Make sure the update to bdp and tx_skbuff are performed + * before dirty_tx + */ + wmb(); txq->dirty_tx = bdp; /* Update pointer to next buffer descriptor to be transmitted */ -- cgit v1.3-6-gb490 From 07151bc9f7f53731b355b704141ffaccc8d08752 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Fri, 7 Aug 2015 17:07:50 +0800 Subject: net: phy: select copper mode when Marvel 88e1111 in SGMII For the Marvel 88e1111 PHY only two SGMII modes are available, both allowing only SGMII to copper mode (with or without clock). SGMII to fiber mode is not supported. Make sure the fiber/copper registers selector bits are cleared for selecting copper mode. Signed-off-by: Madalin Bucur Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 3320a179ee36..e6897b6a8a53 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -52,6 +52,7 @@ #define MII_M1011_PHY_SCR_MDI_X 0x0020 #define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 +#define MII_M1145_PHY_EXT_ADDR_PAGE 0x16 #define MII_M1145_PHY_EXT_SR 0x1b #define MII_M1145_PHY_EXT_CR 0x14 #define MII_M1145_RGMII_RX_DELAY 0x0080 @@ -552,6 +553,16 @@ static int m88e1111_config_init(struct phy_device *phydev) err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); if (err < 0) return err; + + /* make sure copper is selected */ + err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE); + if (err < 0) + return err; + + err = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, + err & (~0xff)); + if (err < 0) + return err; } if (phydev->interface == PHY_INTERFACE_MODE_RTBI) { -- cgit v1.3-6-gb490 From a930a4639d8ce8882a44adcafcfa20049bd67cdf Mon Sep 17 00:00:00 2001 From: Harish Patil Date: Fri, 7 Aug 2015 07:17:02 -0400 Subject: qlcnic: Rearrange ordering of header files inclusion Include local headers files after kernel's header files. Signed-off-by: Harish Patil Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 2 -- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 5 +++-- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 1 + drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 6 +++--- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 9 ++++----- drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c | 4 ++-- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h | 3 ++- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 3 ++- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 3 ++- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | 7 +++---- 10 files changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 055f3763e577..c6dca5df7320 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -24,9 +24,7 @@ #include #include #include - #include - #include #include #include diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 840bf36b5e9d..172192d3606b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -5,14 +5,15 @@ * See LICENSE.qlcnic for copyright and licensing details. */ -#include "qlcnic.h" -#include "qlcnic_sriov.h" #include #include #include #include #include +#include "qlcnic.h" +#include "qlcnic_sriov.h" + static void __qlcnic_83xx_process_aen(struct qlcnic_adapter *); static int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8); static void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 69f828eb42cf..999a90e2f697 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -10,6 +10,7 @@ #include #include + #include "qlcnic_hw.h" #define QLCNIC_83XX_BAR0_LENGTH 0x4000 diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 75ee9e4ced51..509b596cf1e8 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -5,13 +5,13 @@ * See LICENSE.qlcnic for copyright and licensing details. */ -#include "qlcnic.h" -#include "qlcnic_hdr.h" - #include #include #include +#include "qlcnic.h" +#include "qlcnic_hdr.h" + #define MASK(n) ((1ULL<<(n))-1) #define OCM_WIN_P3P(addr) (addr & 0xffc0000) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 7dbab3c20db5..b714cee26d05 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -7,11 +7,6 @@ #include #include - -#include "qlcnic.h" -#include "qlcnic_sriov.h" -#include "qlcnic_hw.h" - #include #include #include @@ -25,6 +20,10 @@ #include #endif +#include "qlcnic.h" +#include "qlcnic_sriov.h" +#include "qlcnic_hw.h" + MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(QLCNIC_LINUX_VERSIONID); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index 332bb8a3f430..6f33e2d57f14 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -5,13 +5,13 @@ * See LICENSE.qlcnic for copyright and licensing details. */ +#include + #include "qlcnic.h" #include "qlcnic_hdr.h" #include "qlcnic_83xx_hw.h" #include "qlcnic_hw.h" -#include - #define QLC_83XX_MINIDUMP_FLASH 0x520000 #define QLC_83XX_OCM_INDEX 3 #define QLC_83XX_PCI_INDEX 0 diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h index 4677b2edccca..017d8c2c8285 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h @@ -8,10 +8,11 @@ #ifndef _QLCNIC_83XX_SRIOV_H_ #define _QLCNIC_83XX_SRIOV_H_ -#include "qlcnic.h" #include #include +#include "qlcnic.h" + extern const u32 qlcnic_83xx_reg_tbl[]; extern const u32 qlcnic_83xx_ext_reg_tbl[]; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index e6312465fe45..546cd5f1c85a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -5,10 +5,11 @@ * See LICENSE.qlcnic for copyright and licensing details. */ +#include + #include "qlcnic_sriov.h" #include "qlcnic.h" #include "qlcnic_83xx_hw.h" -#include #define QLC_BC_COMMAND 0 #define QLC_BC_RESPONSE 1 diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index a29538b86edf..afd687e5e779 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -5,9 +5,10 @@ * See LICENSE.qlcnic for copyright and licensing details. */ +#include + #include "qlcnic_sriov.h" #include "qlcnic.h" -#include #define QLCNIC_SRIOV_VF_MAX_MAC 7 #define QLC_VF_MIN_TX_RATE 100 diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index 05c28f2c6df7..ccbb04503b27 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -7,10 +7,6 @@ #include #include - -#include "qlcnic.h" -#include "qlcnic_hw.h" - #include #include #include @@ -24,6 +20,9 @@ #include #endif +#include "qlcnic.h" +#include "qlcnic_hw.h" + int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable) { return -EOPNOTSUPP; -- cgit v1.3-6-gb490 From d01a6d3c8ae1425565ff1615d29fab6023c82932 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Fri, 7 Aug 2015 07:17:03 -0400 Subject: qlcnic: Add support to enable capability to extend minidump for iSCSI In some cases it is required to capture minidump for iSCSI functions as part of default minidump collection process. To enable this, firmware exports it's capability and driver need to enable that capability by issuing a mailbox command. With this feature, firmware can provide additional iSCSI function's minidump with smaller minidump capture mask (0x1f). Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 1 + .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 26 ++++++++++++++++++ .../net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h | 1 + drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h | 1 + .../net/ethernet/qlogic/qlcnic/qlcnic_minidump.c | 32 ++++++++++++++++++++++ 5 files changed, 61 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index c6dca5df7320..a8615921da81 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -924,6 +924,7 @@ struct qlcnic_mac_vlan_list { #define QLCNIC_FW_CAPABILITY_SET_DRV_VER BIT_5 #define QLCNIC_FW_CAPABILITY_2_BEACON BIT_7 #define QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG BIT_9 +#define QLCNIC_FW_CAPABILITY_2_EXT_ISCSI_DUMP BIT_13 #define QLCNIC_83XX_FW_CAPAB_ENCAP_RX_OFFLOAD BIT_0 #define QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD BIT_1 diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 172192d3606b..5ab3adf88166 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -119,6 +119,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = { {QLCNIC_CMD_DCB_QUERY_CAP, 1, 2}, {QLCNIC_CMD_DCB_QUERY_PARAM, 1, 50}, {QLCNIC_CMD_SET_INGRESS_ENCAP, 2, 1}, + {QLCNIC_CMD_83XX_EXTEND_ISCSI_DUMP_CAP, 4, 1}, }; const u32 qlcnic_83xx_ext_reg_tbl[] = { @@ -3514,6 +3515,31 @@ out: qlcnic_free_mbx_args(&cmd); } +#define QLCNIC_83XX_ADD_PORT0 BIT_0 +#define QLCNIC_83XX_ADD_PORT1 BIT_1 +#define QLCNIC_83XX_EXTENDED_MEM_SIZE 13 /* In MB */ +int qlcnic_83xx_extend_md_capab(struct qlcnic_adapter *adapter) +{ + struct qlcnic_cmd_args cmd; + int err; + + err = qlcnic_alloc_mbx_args(&cmd, adapter, + QLCNIC_CMD_83XX_EXTEND_ISCSI_DUMP_CAP); + if (err) + return err; + + cmd.req.arg[1] = (QLCNIC_83XX_ADD_PORT0 | QLCNIC_83XX_ADD_PORT1); + cmd.req.arg[2] = QLCNIC_83XX_EXTENDED_MEM_SIZE; + cmd.req.arg[3] = QLCNIC_83XX_EXTENDED_MEM_SIZE; + + err = qlcnic_issue_cmd(adapter, &cmd); + if (err) + dev_err(&adapter->pdev->dev, + "failed to issue extend iSCSI minidump capability\n"); + + return err; +} + int qlcnic_83xx_reg_test(struct qlcnic_adapter *adapter) { u32 major, minor, sub; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 999a90e2f697..331ae2c20f40 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -627,6 +627,7 @@ int qlcnic_83xx_set_port_eswitch_status(struct qlcnic_adapter *, int, int *); void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *); void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data); +int qlcnic_83xx_extend_md_capab(struct qlcnic_adapter *); int qlcnic_83xx_get_settings(struct qlcnic_adapter *, struct ethtool_cmd *); int qlcnic_83xx_set_settings(struct qlcnic_adapter *, struct ethtool_cmd *); void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index cbe2399c30a0..4bb33af8e2b3 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -109,6 +109,7 @@ enum qlcnic_regs { #define QLCNIC_CMD_GET_LED_CONFIG 0x6A #define QLCNIC_CMD_83XX_SET_DRV_VER 0x6F #define QLCNIC_CMD_ADD_RCV_RINGS 0x0B +#define QLCNIC_CMD_83XX_EXTEND_ISCSI_DUMP_CAP 0x37 #define QLCNIC_INTRPT_INTX 1 #define QLCNIC_INTRPT_MSIX 3 diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index 6f33e2d57f14..aca47fd4b06c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -1396,19 +1396,51 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) return 0; } +static inline bool +qlcnic_83xx_md_check_extended_dump_capability(struct qlcnic_adapter *adapter) +{ + /* For special adapters (with 0x8830 device ID), where iSCSI firmware + * dump needs to be captured as part of regular firmware dump + * collection process, firmware exports it's capability through + * capability registers + */ + return ((adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE8830) && + (adapter->ahw->extra_capability[0] & + QLCNIC_FW_CAPABILITY_2_EXT_ISCSI_DUMP)); +} + void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter) { u32 prev_version, current_version; struct qlcnic_hardware_context *ahw = adapter->ahw; struct qlcnic_fw_dump *fw_dump = &ahw->fw_dump; struct pci_dev *pdev = adapter->pdev; + bool extended = false; prev_version = adapter->fw_version; current_version = qlcnic_83xx_get_fw_version(adapter); if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) { vfree(fw_dump->tmpl_hdr); + + if (qlcnic_83xx_md_check_extended_dump_capability(adapter)) + extended = !qlcnic_83xx_extend_md_capab(adapter); + if (!qlcnic_fw_cmd_get_minidump_temp(adapter)) dev_info(&pdev->dev, "Supports FW dump capability\n"); + + /* Once we have minidump template with extended iSCSI dump + * capability, update the minidump capture mask to 0x1f as + * per FW requirement + */ + if (extended) { + struct qlcnic_83xx_dump_template_hdr *hdr; + + hdr = fw_dump->tmpl_hdr; + hdr->drv_cap_mask = 0x1f; + fw_dump->cap_mask = 0x1f; + dev_info(&pdev->dev, + "Extended iSCSI dump capability and updated capture mask to 0x1f\n"); + } } } -- cgit v1.3-6-gb490 From 642de51025c3623a9d8c7f3b5e930be0fa95b536 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Fri, 7 Aug 2015 07:17:04 -0400 Subject: qlcnic: Print firmware minidump buffer and template header addresses Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index aca47fd4b06c..cda9e604a95f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -1388,8 +1388,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) fw_dump->clr = 1; snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", adapter->netdev->name); netdev_info(adapter->netdev, - "Dump data %d bytes captured, template header size %d bytes\n", - fw_dump->size, fw_dump->tmpl_hdr_size); + "Dump data %d bytes captured, dump data address = %p, template header size %d bytes, template address = %p\n", + fw_dump->size, fw_dump->data, fw_dump->tmpl_hdr_size, + fw_dump->tmpl_hdr); /* Send a udev event to notify availability of FW dump */ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, msg); -- cgit v1.3-6-gb490 From da286a6fd1e6913779c0a479f428ec3763dfc16c Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Fri, 7 Aug 2015 07:17:05 -0400 Subject: qlcnic: Add new VF device ID 0x8C30 This is a 83xx series based VF device Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 12 ++++++++---- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 5 ++++- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index a8615921da81..17f37b7da80a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -2290,8 +2290,9 @@ extern const struct ethtool_ops qlcnic_ethtool_failed_ops; #define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020 #define PCI_DEVICE_ID_QLOGIC_QLE834X 0x8030 -#define PCI_DEVICE_ID_QLOGIC_QLE8830 0x8830 #define PCI_DEVICE_ID_QLOGIC_VF_QLE834X 0x8430 +#define PCI_DEVICE_ID_QLOGIC_QLE8830 0x8830 +#define PCI_DEVICE_ID_QLOGIC_VF_QLE8C30 0x8C30 #define PCI_DEVICE_ID_QLOGIC_QLE844X 0x8040 #define PCI_DEVICE_ID_QLOGIC_VF_QLE844X 0x8440 @@ -2318,7 +2319,8 @@ static inline bool qlcnic_83xx_check(struct qlcnic_adapter *adapter) (device == PCI_DEVICE_ID_QLOGIC_QLE8830) || (device == PCI_DEVICE_ID_QLOGIC_QLE844X) || (device == PCI_DEVICE_ID_QLOGIC_VF_QLE844X) || - (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X)) ? true : false; + (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X) || + (device == PCI_DEVICE_ID_QLOGIC_VF_QLE8C30)) ? true : false; return status; } @@ -2334,7 +2336,8 @@ static inline bool qlcnic_sriov_vf_check(struct qlcnic_adapter *adapter) bool status; status = ((device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X) || - (device == PCI_DEVICE_ID_QLOGIC_VF_QLE844X)) ? true : false; + (device == PCI_DEVICE_ID_QLOGIC_VF_QLE844X) || + (device == PCI_DEVICE_ID_QLOGIC_VF_QLE8C30)) ? true : false; return status; } @@ -2350,7 +2353,8 @@ static inline bool qlcnic_83xx_vf_check(struct qlcnic_adapter *adapter) { unsigned short device = adapter->pdev->device; - return (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X) ? true : false; + return ((device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X) || + (device == PCI_DEVICE_ID_QLOGIC_VF_QLE8C30)) ? true : false; } static inline bool qlcnic_sriov_check(struct qlcnic_adapter *adapter) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index b714cee26d05..8b08b20e8b30 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -110,8 +110,9 @@ static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter) static const struct pci_device_id qlcnic_pci_tbl[] = { ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X), ENTRY(PCI_DEVICE_ID_QLOGIC_QLE834X), - ENTRY(PCI_DEVICE_ID_QLOGIC_QLE8830), ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE834X), + ENTRY(PCI_DEVICE_ID_QLOGIC_QLE8830), + ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE8C30), ENTRY(PCI_DEVICE_ID_QLOGIC_QLE844X), ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE844X), {0,} @@ -1148,6 +1149,7 @@ static void qlcnic_get_bar_length(u32 dev_id, ulong *bar) case PCI_DEVICE_ID_QLOGIC_QLE844X: case PCI_DEVICE_ID_QLOGIC_VF_QLE834X: case PCI_DEVICE_ID_QLOGIC_VF_QLE844X: + case PCI_DEVICE_ID_QLOGIC_VF_QLE8C30: *bar = QLCNIC_83XX_BAR0_LENGTH; break; default: @@ -2490,6 +2492,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) qlcnic_83xx_register_map(ahw); break; case PCI_DEVICE_ID_QLOGIC_VF_QLE834X: + case PCI_DEVICE_ID_QLOGIC_VF_QLE8C30: case PCI_DEVICE_ID_QLOGIC_VF_QLE844X: qlcnic_sriov_vf_register_map(ahw); break; -- cgit v1.3-6-gb490 From 0e90ad9bfdcc8835945ccb49f39c21ff3cb0b785 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Fri, 7 Aug 2015 07:17:06 -0400 Subject: qlcnic: Don't use kzalloc unncecessarily for allocating large chunk of memory Driver allocates a large chunk of temporary buffer using kzalloc to copy FW image. As there is no real need of this memory to be physically contiguous, use vzalloc instead. Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 753ea8bad953..bf892160dd5f 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -1384,7 +1384,7 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter) size_t size; u64 addr; - temp = kzalloc(fw->size, GFP_KERNEL); + temp = vzalloc(fw->size); if (!temp) { release_firmware(fw); fw_info->fw = NULL; @@ -1430,7 +1430,7 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter) exit: release_firmware(fw); fw_info->fw = NULL; - kfree(temp); + vfree(temp); return ret; } -- cgit v1.3-6-gb490 From 02509f171d2379e79328f5e447e6c97c58ae8d52 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Fri, 7 Aug 2015 07:17:07 -0400 Subject: qlcnic: Update version to 5.3.63 Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 17f37b7da80a..06bcc734fe8d 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -37,8 +37,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 3 -#define _QLCNIC_LINUX_SUBVERSION 62 -#define QLCNIC_LINUX_VERSIONID "5.3.62" +#define _QLCNIC_LINUX_SUBVERSION 63 +#define QLCNIC_LINUX_VERSIONID "5.3.63" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) -- cgit v1.3-6-gb490 From 966bce38e7fdb75eedaec90e40e4d22b9fbce79f Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 8 Aug 2015 17:04:50 +0200 Subject: net: dsa: mv88e6352: Use mnemonics for EEPROM registers and bits Add register definitions #defines for accessing the EEPROM. Signed-off-by: Andrew Lunn Acked-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6352.c | 18 ++++++++++-------- drivers/net/dsa/mv88e6xxx.h | 8 ++++++-- 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 191fb2531efe..a18f7c83d4cb 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -123,8 +123,9 @@ static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr) mutex_lock(&ps->eeprom_mutex); - ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, 0x14, - 0xc000 | (addr & 0xff)); + ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP, + GLOBAL2_EEPROM_OP_READ | + (addr & GLOBAL2_EEPROM_OP_ADDR_MASK)); if (ret < 0) goto error; @@ -132,7 +133,7 @@ static int mv88e6352_read_eeprom_word(struct dsa_switch *ds, int addr) if (ret < 0) goto error; - ret = mv88e6xxx_reg_read(ds, REG_GLOBAL2, 0x15); + ret = mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_EEPROM_DATA); error: mutex_unlock(&ps->eeprom_mutex); return ret; @@ -205,11 +206,11 @@ static int mv88e6352_eeprom_is_readonly(struct dsa_switch *ds) { int ret; - ret = mv88e6xxx_reg_read(ds, REG_GLOBAL2, 0x14); + ret = mv88e6xxx_reg_read(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP); if (ret < 0) return ret; - if (!(ret & 0x0400)) + if (!(ret & GLOBAL2_EEPROM_OP_WRITE_EN)) return -EROFS; return 0; @@ -223,12 +224,13 @@ static int mv88e6352_write_eeprom_word(struct dsa_switch *ds, int addr, mutex_lock(&ps->eeprom_mutex); - ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, 0x15, data); + ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_EEPROM_DATA, data); if (ret < 0) goto error; - ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, 0x14, - 0xb000 | (addr & 0xff)); + ret = mv88e6xxx_reg_write(ds, REG_GLOBAL2, GLOBAL2_EEPROM_OP, + GLOBAL2_EEPROM_OP_WRITE | + (addr & GLOBAL2_EEPROM_OP_ADDR_MASK)); if (ret < 0) goto error; diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index a8c727d846dd..a94c0cbb3813 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -290,8 +290,12 @@ #define GLOBAL2_PRIO_OVERRIDE_FORCE_ARP BIT(3) #define GLOBAL2_PRIO_OVERRIDE_ARP_SHIFT 0 #define GLOBAL2_EEPROM_OP 0x14 -#define GLOBAL2_EEPROM_OP_BUSY BIT(15) -#define GLOBAL2_EEPROM_OP_LOAD BIT(11) +#define GLOBAL2_EEPROM_OP_BUSY BIT(15) +#define GLOBAL2_EEPROM_OP_WRITE ((3 << 12) | GLOBAL2_EEPROM_OP_BUSY) +#define GLOBAL2_EEPROM_OP_READ ((4 << 12) | GLOBAL2_EEPROM_OP_BUSY) +#define GLOBAL2_EEPROM_OP_LOAD BIT(11) +#define GLOBAL2_EEPROM_OP_WRITE_EN BIT(10) +#define GLOBAL2_EEPROM_OP_ADDR_MASK 0xff #define GLOBAL2_EEPROM_DATA 0x15 #define GLOBAL2_PTP_AVB_OP 0x16 #define GLOBAL2_PTP_AVB_DATA 0x17 -- cgit v1.3-6-gb490 From 2f3a87326dd4948d21eee8245cde43e8fca9dddf Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 8 Aug 2015 22:15:59 +0300 Subject: cxgb4: cleanup some indenting Add or remove some tabs so that statements line up correctly. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index b6577349cf4e..f65ab64e108b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -346,11 +346,11 @@ static int cim_qcfg_show(struct seq_file *seq, void *v) if (is_t4(adap->params.chip)) { i = t4_cim_read(adap, UP_OBQ_0_REALADDR_A, ARRAY_SIZE(obq_wr_t4), obq_wr_t4); - wr = obq_wr_t4; + wr = obq_wr_t4; } else { i = t4_cim_read(adap, UP_OBQ_0_SHADOW_REALADDR_A, ARRAY_SIZE(obq_wr_t5), obq_wr_t5); - wr = obq_wr_t5; + wr = obq_wr_t5; } } if (i) @@ -2095,7 +2095,7 @@ do { \ #undef T #undef S #undef S3 -return 0; + return 0; } static int sge_queue_entries(const struct adapter *adap) -- cgit v1.3-6-gb490 From bec7a630a66a7d688486ae7ceb3f0b5307bdb2c5 Mon Sep 17 00:00:00 2001 From: yalin wang Date: Mon, 10 Aug 2015 17:15:57 +0800 Subject: isdn: Remove reverse_bits(), use revbit8() This change isdn driver, remove reverse_bits() function, use the generic revbit8() function instead. Signed-off-by: yalin wang Signed-off-by: David S. Miller --- drivers/isdn/mISDN/dsp_audio.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c index 06022952a437..bbef98e7a16e 100644 --- a/drivers/isdn/mISDN/dsp_audio.c +++ b/drivers/isdn/mISDN/dsp_audio.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "core.h" #include "dsp.h" @@ -137,27 +138,14 @@ static unsigned char linear2ulaw(short sample) return ulawbyte; } -static int reverse_bits(int i) -{ - int z, j; - z = 0; - - for (j = 0; j < 8; j++) { - if ((i & (1 << j)) != 0) - z |= 1 << (7 - j); - } - return z; -} - - void dsp_audio_generate_law_tables(void) { int i; for (i = 0; i < 256; i++) - dsp_audio_alaw_to_s32[i] = alaw2linear(reverse_bits(i)); + dsp_audio_alaw_to_s32[i] = alaw2linear(bitrev8((u8)i)); for (i = 0; i < 256; i++) - dsp_audio_ulaw_to_s32[i] = ulaw2linear(reverse_bits(i)); + dsp_audio_ulaw_to_s32[i] = ulaw2linear(bitrev8((u8)i)); for (i = 0; i < 256; i++) { dsp_audio_alaw_to_ulaw[i] = @@ -176,13 +164,13 @@ dsp_audio_generate_s2law_table(void) /* generating ulaw-table */ for (i = -32768; i < 32768; i++) { dsp_audio_s16_to_law[i & 0xffff] = - reverse_bits(linear2ulaw(i)); + bitrev8(linear2ulaw(i)); } } else { /* generating alaw-table */ for (i = -32768; i < 32768; i++) { dsp_audio_s16_to_law[i & 0xffff] = - reverse_bits(linear2alaw(i)); + bitrev8(linear2alaw(i)); } } } -- cgit v1.3-6-gb490 From d3d73f4b38a8ece19846b8fa2519cdc8583f35bb Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Fri, 7 Aug 2015 13:18:17 +1000 Subject: cxl: Compile with -Werror It's a good idea, and it brings us in line with the rest of arch/powerpc. Signed-off-by: Daniel Axtens Acked-by: Michael Neuling Signed-off-by: Michael Ellerman --- drivers/misc/cxl/Makefile | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/cxl/Makefile b/drivers/misc/cxl/Makefile index 14e3f8219a11..6f484dfe78f9 100644 --- a/drivers/misc/cxl/Makefile +++ b/drivers/misc/cxl/Makefile @@ -1,3 +1,5 @@ +ccflags-y := -Werror + cxl-y += main.o file.o irq.o fault.o native.o cxl-y += context.o sysfs.o debugfs.o pci.o trace.o cxl-y += vphb.o api.o -- cgit v1.3-6-gb490 From 83e81961ff7ef75f97756f316caea5aa6bcc19cc Mon Sep 17 00:00:00 2001 From: Ben Young Tae Kim Date: Mon, 10 Aug 2015 14:24:12 -0700 Subject: Bluetooth: btqca: Introduce generic QCA ROME support This is for supporting BT for QCA ROME with vendor specific HCI commands and initialization on the chip. This will have USB/UART implementation both, but for now, adding UART vendor specific commands to patch downloading and set Bluetooth device address using vendor specific command. Signed-off-by: Ben Young Tae Kim Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 4 + drivers/bluetooth/Makefile | 1 + drivers/bluetooth/btqca.c | 392 +++++++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/btqca.h | 135 ++++++++++++++++ 4 files changed, 532 insertions(+) create mode 100644 drivers/bluetooth/btqca.c create mode 100644 drivers/bluetooth/btqca.h (limited to 'drivers') diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 79e8234b1aa5..f5803345e305 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -13,6 +13,10 @@ config BT_RTL tristate select FW_LOADER +config BT_QCA + tristate + select FW_LOADER + config BT_HCIBTUSB tristate "HCI USB driver" depends on USB diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index f40e194e7080..15a0d1de4db4 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o obj-$(CONFIG_BT_WILINK) += btwilink.o obj-$(CONFIG_BT_BCM) += btbcm.o obj-$(CONFIG_BT_RTL) += btrtl.o +obj-$(CONFIG_BT_QCA) += btqca.o btmrvl-y := btmrvl_main.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c new file mode 100644 index 000000000000..4a6208168850 --- /dev/null +++ b/drivers/bluetooth/btqca.c @@ -0,0 +1,392 @@ +/* + * Bluetooth supports for Qualcomm Atheros chips + * + * Copyright (c) 2015 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 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 + * + */ +#include +#include + +#include +#include + +#include "btqca.h" + +#define VERSION "0.1" + +static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) +{ + struct sk_buff *skb; + struct edl_event_hdr *edl; + struct rome_version *ver; + char cmd; + int err = 0; + + BT_DBG("%s: ROME Patch Version Request", hdev->name); + + cmd = EDL_PATCH_VER_REQ_CMD; + skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN, + &cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: Failed to read version of ROME (%d)", hdev->name, + err); + return err; + } + + if (skb->len != sizeof(*edl) + sizeof(*ver)) { + BT_ERR("%s: Version size mismatch len %d", hdev->name, + skb->len); + err = -EILSEQ; + goto out; + } + + edl = (struct edl_event_hdr *)(skb->data); + if (!edl || !edl->data) { + BT_ERR("%s: TLV with no header or no data", hdev->name); + err = -EILSEQ; + goto out; + } + + if (edl->cresp != EDL_CMD_REQ_RES_EVT || + edl->rtype != EDL_APP_VER_RES_EVT) { + BT_ERR("%s: Wrong packet received %d %d", hdev->name, + edl->cresp, edl->rtype); + err = -EIO; + goto out; + } + + ver = (struct rome_version *)(edl->data); + + BT_DBG("%s: Product:0x%08x", hdev->name, le32_to_cpu(ver->product_id)); + BT_DBG("%s: Patch :0x%08x", hdev->name, le16_to_cpu(ver->patch_ver)); + BT_DBG("%s: ROM :0x%08x", hdev->name, le16_to_cpu(ver->rome_ver)); + BT_DBG("%s: SOC :0x%08x", hdev->name, le32_to_cpu(ver->soc_id)); + + /* ROME chipset version can be decided by patch and SoC + * version, combination with upper 2 bytes from SoC + * and lower 2 bytes from patch will be used. + */ + *rome_version = (le32_to_cpu(ver->soc_id) << 16) | + (le16_to_cpu(ver->rome_ver) & 0x0000ffff); + +out: + kfree_skb(skb); + + return err; +} + +static int rome_reset(struct hci_dev *hdev) +{ + struct sk_buff *skb; + int err; + + BT_DBG("%s: ROME HCI_RESET", hdev->name); + + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: Reset failed (%d)", hdev->name, err); + return err; + } + + kfree_skb(skb); + + return 0; +} + +static void rome_tlv_check_data(struct rome_config *config, + const struct firmware *fw) +{ + const u8 *data; + u32 type_len; + u16 tag_id, tag_len; + int idx, length; + struct tlv_type_hdr *tlv; + struct tlv_type_patch *tlv_patch; + struct tlv_type_nvm *tlv_nvm; + + tlv = (struct tlv_type_hdr *)fw->data; + + type_len = le32_to_cpu(tlv->type_len); + length = (type_len >> 8) & 0x00ffffff; + + BT_DBG("TLV Type\t\t : 0x%x", type_len & 0x000000ff); + BT_DBG("Length\t\t : %d bytes", length); + + switch (config->type) { + case TLV_TYPE_PATCH: + tlv_patch = (struct tlv_type_patch *)tlv->data; + BT_DBG("Total Length\t\t : %d bytes", + le32_to_cpu(tlv_patch->total_size)); + BT_DBG("Patch Data Length\t : %d bytes", + le32_to_cpu(tlv_patch->data_length)); + BT_DBG("Signing Format Version : 0x%x", + tlv_patch->format_version); + BT_DBG("Signature Algorithm\t : 0x%x", + tlv_patch->signature); + BT_DBG("Reserved\t\t : 0x%x", + le16_to_cpu(tlv_patch->reserved1)); + BT_DBG("Product ID\t\t : 0x%04x", + le16_to_cpu(tlv_patch->product_id)); + BT_DBG("Rom Build Version\t : 0x%04x", + le16_to_cpu(tlv_patch->rom_build)); + BT_DBG("Patch Version\t\t : 0x%04x", + le16_to_cpu(tlv_patch->patch_version)); + BT_DBG("Reserved\t\t : 0x%x", + le16_to_cpu(tlv_patch->reserved2)); + BT_DBG("Patch Entry Address\t : 0x%x", + le32_to_cpu(tlv_patch->entry)); + break; + + case TLV_TYPE_NVM: + idx = 0; + data = tlv->data; + while (idx < length) { + tlv_nvm = (struct tlv_type_nvm *)(data + idx); + + tag_id = le16_to_cpu(tlv_nvm->tag_id); + tag_len = le16_to_cpu(tlv_nvm->tag_len); + + /* Update NVM tags as needed */ + switch (tag_id) { + case EDL_TAG_ID_HCI: + /* HCI transport layer parameters + * enabling software inband sleep + * onto controller side. + */ + tlv_nvm->data[0] |= 0x80; + + /* UART Baud Rate */ + tlv_nvm->data[2] = config->user_baud_rate; + + break; + + case EDL_TAG_ID_DEEP_SLEEP: + /* Sleep enable mask + * enabling deep sleep feature on controller. + */ + tlv_nvm->data[0] |= 0x01; + + break; + } + + idx += (sizeof(u16) + sizeof(u16) + 8 + tag_len); + } + break; + + default: + BT_ERR("Unknown TLV type %d", config->type); + break; + } +} + +static int rome_tlv_send_segment(struct hci_dev *hdev, int idx, int seg_size, + const u8 *data) +{ + struct sk_buff *skb; + struct edl_event_hdr *edl; + struct tlv_seg_resp *tlv_resp; + u8 cmd[MAX_SIZE_PER_TLV_SEGMENT + 2]; + int err = 0; + + BT_DBG("%s: Download segment #%d size %d", hdev->name, idx, seg_size); + + cmd[0] = EDL_PATCH_TLV_REQ_CMD; + cmd[1] = seg_size; + memcpy(cmd + 2, data, seg_size); + + skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, seg_size + 2, cmd, + HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: Failed to send TLV segment (%d)", hdev->name, err); + return err; + } + + if (skb->len != sizeof(*edl) + sizeof(*tlv_resp)) { + BT_ERR("%s: TLV response size mismatch", hdev->name); + err = -EILSEQ; + goto out; + } + + edl = (struct edl_event_hdr *)(skb->data); + if (!edl || !edl->data) { + BT_ERR("%s: TLV with no header or no data", hdev->name); + err = -EILSEQ; + goto out; + } + + tlv_resp = (struct tlv_seg_resp *)(edl->data); + + if (edl->cresp != EDL_CMD_REQ_RES_EVT || + edl->rtype != EDL_TVL_DNLD_RES_EVT || tlv_resp->result != 0x00) { + BT_ERR("%s: TLV with error stat 0x%x rtype 0x%x (0x%x)", + hdev->name, edl->cresp, edl->rtype, tlv_resp->result); + err = -EIO; + } + +out: + kfree_skb(skb); + + return err; +} + +static int rome_tlv_download_request(struct hci_dev *hdev, + const struct firmware *fw) +{ + const u8 *buffer, *data; + int total_segment, remain_size; + int ret, i; + + if (!fw || !fw->data) + return -EINVAL; + + total_segment = fw->size / MAX_SIZE_PER_TLV_SEGMENT; + remain_size = fw->size % MAX_SIZE_PER_TLV_SEGMENT; + + BT_DBG("%s: Total segment num %d remain size %d total size %zu", + hdev->name, total_segment, remain_size, fw->size); + + data = fw->data; + for (i = 0; i < total_segment; i++) { + buffer = data + i * MAX_SIZE_PER_TLV_SEGMENT; + ret = rome_tlv_send_segment(hdev, i, MAX_SIZE_PER_TLV_SEGMENT, + buffer); + if (ret < 0) + return -EIO; + } + + if (remain_size) { + buffer = data + total_segment * MAX_SIZE_PER_TLV_SEGMENT; + ret = rome_tlv_send_segment(hdev, total_segment, remain_size, + buffer); + if (ret < 0) + return -EIO; + } + + return 0; +} + +static int rome_download_firmware(struct hci_dev *hdev, + struct rome_config *config) +{ + const struct firmware *fw; + int ret; + + BT_INFO("%s: ROME Downloading %s", hdev->name, config->fwname); + + ret = request_firmware(&fw, config->fwname, &hdev->dev); + if (ret) { + BT_ERR("%s: Failed to request file: %s (%d)", hdev->name, + config->fwname, ret); + return ret; + } + + rome_tlv_check_data(config, fw); + + ret = rome_tlv_download_request(hdev, fw); + if (ret) { + BT_ERR("%s: Failed to download file: %s (%d)", hdev->name, + config->fwname, ret); + } + + release_firmware(fw); + + return ret; +} + +int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + u8 cmd[9]; + int err; + + cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD; + cmd[1] = 0x02; /* TAG ID */ + cmd[2] = sizeof(bdaddr_t); /* size */ + memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t)); + skb = __hci_cmd_sync_ev(hdev, EDL_NVM_ACCESS_OPCODE, sizeof(cmd), cmd, + HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: Change address command failed (%d)", + hdev->name, err); + return err; + } + + kfree_skb(skb); + + return 0; +} +EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome); + +int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate) +{ + u32 rome_ver = 0; + struct rome_config config; + int err; + + BT_DBG("%s: ROME setup on UART", hdev->name); + + config.user_baud_rate = baudrate; + + /* Get ROME version information */ + err = rome_patch_ver_req(hdev, &rome_ver); + if (err < 0 || rome_ver == 0) { + BT_ERR("%s: Failed to get version 0x%x", hdev->name, err); + return err; + } + + BT_INFO("%s: ROME controller version 0x%08x", hdev->name, rome_ver); + + /* Download rampatch file */ + config.type = TLV_TYPE_PATCH; + snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.bin", + rome_ver); + err = rome_download_firmware(hdev, &config); + if (err < 0) { + BT_ERR("%s: Failed to download patch (%d)", hdev->name, err); + return err; + } + + /* Download NVM configuration */ + config.type = TLV_TYPE_NVM; + snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin", + rome_ver); + err = rome_download_firmware(hdev, &config); + if (err < 0) { + BT_ERR("%s: Failed to download NVM (%d)", hdev->name, err); + return err; + } + + /* Perform HCI reset */ + err = rome_reset(hdev); + if (err < 0) { + BT_ERR("%s: Failed to run HCI_RESET (%d)", hdev->name, err); + return err; + } + + BT_INFO("%s: ROME setup on UART is completed", hdev->name); + + return 0; +} +EXPORT_SYMBOL_GPL(qca_uart_setup_rome); + +MODULE_AUTHOR("Ben Young Tae Kim "); +MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h new file mode 100644 index 000000000000..65e994b96c47 --- /dev/null +++ b/drivers/bluetooth/btqca.h @@ -0,0 +1,135 @@ +/* + * Bluetooth supports for Qualcomm Atheros ROME chips + * + * Copyright (c) 2015 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 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 EDL_PATCH_CMD_OPCODE (0xFC00) +#define EDL_NVM_ACCESS_OPCODE (0xFC0B) +#define EDL_PATCH_CMD_LEN (1) +#define EDL_PATCH_VER_REQ_CMD (0x19) +#define EDL_PATCH_TLV_REQ_CMD (0x1E) +#define EDL_NVM_ACCESS_SET_REQ_CMD (0x01) +#define MAX_SIZE_PER_TLV_SEGMENT (243) + +#define EDL_CMD_REQ_RES_EVT (0x00) +#define EDL_PATCH_VER_RES_EVT (0x19) +#define EDL_APP_VER_RES_EVT (0x02) +#define EDL_TVL_DNLD_RES_EVT (0x04) +#define EDL_CMD_EXE_STATUS_EVT (0x00) +#define EDL_SET_BAUDRATE_RSP_EVT (0x92) +#define EDL_NVM_ACCESS_CODE_EVT (0x0B) + +#define EDL_TAG_ID_HCI (17) +#define EDL_TAG_ID_DEEP_SLEEP (27) + +enum qca_bardrate { + QCA_BAUDRATE_115200 = 0, + QCA_BAUDRATE_57600, + QCA_BAUDRATE_38400, + QCA_BAUDRATE_19200, + QCA_BAUDRATE_9600, + QCA_BAUDRATE_230400, + QCA_BAUDRATE_250000, + QCA_BAUDRATE_460800, + QCA_BAUDRATE_500000, + QCA_BAUDRATE_720000, + QCA_BAUDRATE_921600, + QCA_BAUDRATE_1000000, + QCA_BAUDRATE_1250000, + QCA_BAUDRATE_2000000, + QCA_BAUDRATE_3000000, + QCA_BAUDRATE_4000000, + QCA_BAUDRATE_1600000, + QCA_BAUDRATE_3200000, + QCA_BAUDRATE_3500000, + QCA_BAUDRATE_AUTO = 0xFE, + QCA_BAUDRATE_RESERVED +}; + +enum rome_tlv_type { + TLV_TYPE_PATCH = 1, + TLV_TYPE_NVM +}; + +struct rome_config { + u8 type; + char fwname[64]; + uint8_t user_baud_rate; +}; + +struct edl_event_hdr { + __u8 cresp; + __u8 rtype; + __u8 data[0]; +} __packed; + +struct rome_version { + __le32 product_id; + __le16 patch_ver; + __le16 rome_ver; + __le32 soc_id; +} __packed; + +struct tlv_seg_resp { + __u8 result; +} __packed; + +struct tlv_type_patch { + __le32 total_size; + __le32 data_length; + __u8 format_version; + __u8 signature; + __le16 reserved1; + __le16 product_id; + __le16 rom_build; + __le16 patch_version; + __le16 reserved2; + __le32 entry; +} __packed; + +struct tlv_type_nvm { + __le16 tag_id; + __le16 tag_len; + __le32 reserve1; + __le32 reserve2; + __u8 data[0]; +} __packed; + +struct tlv_type_hdr { + __le32 type_len; + __u8 data[0]; +} __packed; + +#if IS_ENABLED(CONFIG_BT_QCA) + +int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr); +int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate); + +#else + +static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + return -EOPNOTSUPP; +} + +static inline int qca_uart_setup_rome(struct hci_dev *hdev, int speed) +{ + return -EOPNOTSUPP; +} + +#endif -- cgit v1.3-6-gb490 From 0ff252c1976da5d80db1377eb39b551931e61826 Mon Sep 17 00:00:00 2001 From: Ben Young Tae Kim Date: Mon, 10 Aug 2015 14:24:17 -0700 Subject: Bluetooth: hciuart: Add support QCA chipset for UART QCA61x4 chips have supported sleep feature using In-Band-Sleep commands to enable sleep feature based on H4 protocol. After sending patch/nvm configuration is done, IBS mode will be up and running Signed-off-by: Ben Young Tae Kim Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 13 + drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_qca.c | 969 ++++++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_uart.h | 8 +- 5 files changed, 996 insertions(+), 1 deletion(-) create mode 100644 drivers/bluetooth/hci_qca.c (limited to 'drivers') diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index f5803345e305..0bd88c942a52 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -155,6 +155,19 @@ config BT_HCIUART_BCM Say Y here to compile support for Broadcom protocol. +config BT_HCIUART_QCA + bool "Qualcomm Atheros protocol support" + depends on BT_HCIUART + select BT_HCIUART_H4 + select BT_QCA + help + The Qualcomm Atheros protocol supports HCI In-Band Sleep feature + over serial port interface(H4) between controller and host. + This protocol is required for UART clock control for QCA Bluetooth + devices. + + Say Y here to compile support for QCA protocol. + config BT_HCIBCM203X tristate "HCI BCM203x USB driver" depends on USB diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 15a0d1de4db4..07c9cf381e5a 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -35,6 +35,7 @@ hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o hci_uart-$(CONFIG_BT_HCIUART_INTEL) += hci_intel.o hci_uart-$(CONFIG_BT_HCIUART_BCM) += hci_bcm.o +hci_uart-$(CONFIG_BT_HCIUART_QCA) += hci_qca.o hci_uart-objs := $(hci_uart-y) ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 20c2ac193ff9..0d5a05a7c1fd 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -810,6 +810,9 @@ static int __init hci_uart_init(void) #ifdef CONFIG_BT_HCIUART_BCM bcm_init(); #endif +#ifdef CONFIG_BT_HCIUART_QCA + qca_init(); +#endif return 0; } @@ -839,6 +842,9 @@ static void __exit hci_uart_exit(void) #ifdef CONFIG_BT_HCIUART_BCM bcm_deinit(); #endif +#ifdef CONFIG_BT_HCIUART_QCA + qca_deinit(); +#endif /* Release tty registration of line discipline */ err = tty_unregister_ldisc(N_HCI); diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c new file mode 100644 index 000000000000..62e45fff0b4b --- /dev/null +++ b/drivers/bluetooth/hci_qca.c @@ -0,0 +1,969 @@ +/* + * Bluetooth Software UART Qualcomm protocol + * + * HCI_IBS (HCI In-Band Sleep) is Qualcomm's power management + * protocol extension to H4. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * Copyright (c) 2010, 2012 The Linux Foundation. All rights reserved. + * + * Acknowledgements: + * This file is based on hci_ll.c, which was... + * Written by Ohad Ben-Cohen + * which was in turn based on hci_h4.c, which was written + * by Maxim Krasnyansky and Marcel Holtmann. + * + * 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 + * + */ + +#include +#include + +#include +#include + +#include "hci_uart.h" +#include "btqca.h" + +/* HCI_IBS protocol messages */ +#define HCI_IBS_SLEEP_IND 0xFE +#define HCI_IBS_WAKE_IND 0xFD +#define HCI_IBS_WAKE_ACK 0xFC +#define HCI_MAX_IBS_SIZE 10 + +/* Controller states */ +#define STATE_IN_BAND_SLEEP_ENABLED 1 + +#define IBS_WAKE_RETRANS_TIMEOUT_MS 100 +#define IBS_TX_IDLE_TIMEOUT_MS 2000 +#define BAUDRATE_SETTLE_TIMEOUT_MS 300 + +/* HCI_IBS transmit side sleep protocol states */ +enum tx_ibs_states { + HCI_IBS_TX_ASLEEP, + HCI_IBS_TX_WAKING, + HCI_IBS_TX_AWAKE, +}; + +/* HCI_IBS receive side sleep protocol states */ +enum rx_states { + HCI_IBS_RX_ASLEEP, + HCI_IBS_RX_AWAKE, +}; + +/* HCI_IBS transmit and receive side clock state vote */ +enum hci_ibs_clock_state_vote { + HCI_IBS_VOTE_STATS_UPDATE, + HCI_IBS_TX_VOTE_CLOCK_ON, + HCI_IBS_TX_VOTE_CLOCK_OFF, + HCI_IBS_RX_VOTE_CLOCK_ON, + HCI_IBS_RX_VOTE_CLOCK_OFF, +}; + +struct qca_data { + struct hci_uart *hu; + struct sk_buff *rx_skb; + struct sk_buff_head txq; + struct sk_buff_head tx_wait_q; /* HCI_IBS wait queue */ + spinlock_t hci_ibs_lock; /* HCI_IBS state lock */ + u8 tx_ibs_state; /* HCI_IBS transmit side power state*/ + u8 rx_ibs_state; /* HCI_IBS receive side power state */ + bool tx_vote; /* Clock must be on for TX */ + bool rx_vote; /* Clock must be on for RX */ + struct timer_list tx_idle_timer; + u32 tx_idle_delay; + struct timer_list wake_retrans_timer; + u32 wake_retrans; + struct workqueue_struct *workqueue; + struct work_struct ws_awake_rx; + struct work_struct ws_awake_device; + struct work_struct ws_rx_vote_off; + struct work_struct ws_tx_vote_off; + unsigned long flags; + + /* For debugging purpose */ + u64 ibs_sent_wacks; + u64 ibs_sent_slps; + u64 ibs_sent_wakes; + u64 ibs_recv_wacks; + u64 ibs_recv_slps; + u64 ibs_recv_wakes; + u64 vote_last_jif; + u32 vote_on_ms; + u32 vote_off_ms; + u64 tx_votes_on; + u64 rx_votes_on; + u64 tx_votes_off; + u64 rx_votes_off; + u64 votes_on; + u64 votes_off; +}; + +static void __serial_clock_on(struct tty_struct *tty) +{ + /* TODO: Some chipset requires to enable UART clock on client + * side to save power consumption or manual work is required. + * Please put your code to control UART clock here if needed + */ +} + +static void __serial_clock_off(struct tty_struct *tty) +{ + /* TODO: Some chipset requires to disable UART clock on client + * side to save power consumption or manual work is required. + * Please put your code to control UART clock off here if needed + */ +} + +/* serial_clock_vote needs to be called with the ibs lock held */ +static void serial_clock_vote(unsigned long vote, struct hci_uart *hu) +{ + struct qca_data *qca = hu->priv; + unsigned int diff; + + bool old_vote = (qca->tx_vote | qca->rx_vote); + bool new_vote; + + switch (vote) { + case HCI_IBS_VOTE_STATS_UPDATE: + diff = jiffies_to_msecs(jiffies - qca->vote_last_jif); + + if (old_vote) + qca->vote_off_ms += diff; + else + qca->vote_on_ms += diff; + return; + + case HCI_IBS_TX_VOTE_CLOCK_ON: + qca->tx_vote = true; + qca->tx_votes_on++; + new_vote = true; + break; + + case HCI_IBS_RX_VOTE_CLOCK_ON: + qca->rx_vote = true; + qca->rx_votes_on++; + new_vote = true; + break; + + case HCI_IBS_TX_VOTE_CLOCK_OFF: + qca->tx_vote = false; + qca->tx_votes_off++; + new_vote = qca->rx_vote | qca->tx_vote; + break; + + case HCI_IBS_RX_VOTE_CLOCK_OFF: + qca->rx_vote = false; + qca->rx_votes_off++; + new_vote = qca->rx_vote | qca->tx_vote; + break; + + default: + BT_ERR("Voting irregularity"); + return; + } + + if (new_vote != old_vote) { + if (new_vote) + __serial_clock_on(hu->tty); + else + __serial_clock_off(hu->tty); + + BT_DBG("Vote serial clock %s(%s)", new_vote? "true" : "false", + vote? "true" : "false"); + + diff = jiffies_to_msecs(jiffies - qca->vote_last_jif); + + if (new_vote) { + qca->votes_on++; + qca->vote_off_ms += diff; + } else { + qca->votes_off++; + qca->vote_on_ms += diff; + } + qca->vote_last_jif = jiffies; + } +} + +/* Builds and sends an HCI_IBS command packet. + * These are very simple packets with only 1 cmd byte. + */ +static int send_hci_ibs_cmd(u8 cmd, struct hci_uart *hu) +{ + int err = 0; + struct sk_buff *skb = NULL; + struct qca_data *qca = hu->priv; + + BT_DBG("hu %p send hci ibs cmd 0x%x", hu, cmd); + + skb = bt_skb_alloc(1, GFP_ATOMIC); + if (!skb) { + BT_ERR("Failed to allocate memory for HCI_IBS packet"); + return -ENOMEM; + } + + /* Assign HCI_IBS type */ + *skb_put(skb, 1) = cmd; + + skb_queue_tail(&qca->txq, skb); + + return err; +} + +static void qca_wq_awake_device(struct work_struct *work) +{ + struct qca_data *qca = container_of(work, struct qca_data, + ws_awake_device); + struct hci_uart *hu = qca->hu; + unsigned long retrans_delay; + + BT_DBG("hu %p wq awake device", hu); + + /* Vote for serial clock */ + serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu); + + spin_lock(&qca->hci_ibs_lock); + + /* Send wake indication to device */ + if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) + BT_ERR("Failed to send WAKE to device"); + + qca->ibs_sent_wakes++; + + /* Start retransmit timer */ + retrans_delay = msecs_to_jiffies(qca->wake_retrans); + mod_timer(&qca->wake_retrans_timer, jiffies + retrans_delay); + + spin_unlock(&qca->hci_ibs_lock); + + /* Actually send the packets */ + hci_uart_tx_wakeup(hu); +} + +static void qca_wq_awake_rx(struct work_struct *work) +{ + struct qca_data *qca = container_of(work, struct qca_data, + ws_awake_rx); + struct hci_uart *hu = qca->hu; + + BT_DBG("hu %p wq awake rx", hu); + + serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu); + + spin_lock(&qca->hci_ibs_lock); + qca->rx_ibs_state = HCI_IBS_RX_AWAKE; + + /* Always acknowledge device wake up, + * sending IBS message doesn't count as TX ON. + */ + if (send_hci_ibs_cmd(HCI_IBS_WAKE_ACK, hu) < 0) + BT_ERR("Failed to acknowledge device wake up"); + + qca->ibs_sent_wacks++; + + spin_unlock(&qca->hci_ibs_lock); + + /* Actually send the packets */ + hci_uart_tx_wakeup(hu); +} + +static void qca_wq_serial_rx_clock_vote_off(struct work_struct *work) +{ + struct qca_data *qca = container_of(work, struct qca_data, + ws_rx_vote_off); + struct hci_uart *hu = qca->hu; + + BT_DBG("hu %p rx clock vote off", hu); + + serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu); +} + +static void qca_wq_serial_tx_clock_vote_off(struct work_struct *work) +{ + struct qca_data *qca = container_of(work, struct qca_data, + ws_tx_vote_off); + struct hci_uart *hu = qca->hu; + + BT_DBG("hu %p tx clock vote off", hu); + + /* Run HCI tx handling unlocked */ + hci_uart_tx_wakeup(hu); + + /* Now that message queued to tty driver, vote for tty clocks off. + * It is up to the tty driver to pend the clocks off until tx done. + */ + serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu); +} + +static void hci_ibs_tx_idle_timeout(unsigned long arg) +{ + struct hci_uart *hu = (struct hci_uart *)arg; + struct qca_data *qca = hu->priv; + unsigned long flags; + + BT_DBG("hu %p idle timeout in %d state", hu, qca->tx_ibs_state); + + spin_lock_irqsave_nested(&qca->hci_ibs_lock, + flags, SINGLE_DEPTH_NESTING); + + switch (qca->tx_ibs_state) { + case HCI_IBS_TX_AWAKE: + /* TX_IDLE, go to SLEEP */ + if (send_hci_ibs_cmd(HCI_IBS_SLEEP_IND, hu) < 0) { + BT_ERR("Failed to send SLEEP to device"); + break; + } + qca->tx_ibs_state = HCI_IBS_TX_ASLEEP; + qca->ibs_sent_slps++; + queue_work(qca->workqueue, &qca->ws_tx_vote_off); + break; + + case HCI_IBS_TX_ASLEEP: + case HCI_IBS_TX_WAKING: + /* Fall through */ + + default: + BT_ERR("Spurrious timeout tx state %d", qca->tx_ibs_state); + break; + } + + spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); +} + +static void hci_ibs_wake_retrans_timeout(unsigned long arg) +{ + struct hci_uart *hu = (struct hci_uart *)arg; + struct qca_data *qca = hu->priv; + unsigned long flags, retrans_delay; + unsigned long retransmit = 0; + + BT_DBG("hu %p wake retransmit timeout in %d state", + hu, qca->tx_ibs_state); + + spin_lock_irqsave_nested(&qca->hci_ibs_lock, + flags, SINGLE_DEPTH_NESTING); + + switch (qca->tx_ibs_state) { + case HCI_IBS_TX_WAKING: + /* No WAKE_ACK, retransmit WAKE */ + retransmit = 1; + if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) { + BT_ERR("Failed to acknowledge device wake up"); + break; + } + qca->ibs_sent_wakes++; + retrans_delay = msecs_to_jiffies(qca->wake_retrans); + mod_timer(&qca->wake_retrans_timer, jiffies + retrans_delay); + break; + + case HCI_IBS_TX_ASLEEP: + case HCI_IBS_TX_AWAKE: + /* Fall through */ + + default: + BT_ERR("Spurrious timeout tx state %d", qca->tx_ibs_state); + break; + } + + spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); + + if (retransmit) + hci_uart_tx_wakeup(hu); +} + +/* Initialize protocol */ +static int qca_open(struct hci_uart *hu) +{ + struct qca_data *qca; + + BT_DBG("hu %p qca_open", hu); + + qca = kzalloc(sizeof(struct qca_data), GFP_ATOMIC); + if (!qca) + return -ENOMEM; + + skb_queue_head_init(&qca->txq); + skb_queue_head_init(&qca->tx_wait_q); + spin_lock_init(&qca->hci_ibs_lock); + qca->workqueue = create_singlethread_workqueue("qca_wq"); + if (!qca->workqueue) { + BT_ERR("QCA Workqueue not initialized properly"); + kfree(qca); + return -ENOMEM; + } + + INIT_WORK(&qca->ws_awake_rx, qca_wq_awake_rx); + INIT_WORK(&qca->ws_awake_device, qca_wq_awake_device); + INIT_WORK(&qca->ws_rx_vote_off, qca_wq_serial_rx_clock_vote_off); + INIT_WORK(&qca->ws_tx_vote_off, qca_wq_serial_tx_clock_vote_off); + + qca->hu = hu; + + /* Assume we start with both sides asleep -- extra wakes OK */ + qca->tx_ibs_state = HCI_IBS_TX_ASLEEP; + qca->rx_ibs_state = HCI_IBS_RX_ASLEEP; + + /* clocks actually on, but we start votes off */ + qca->tx_vote = false; + qca->rx_vote = false; + qca->flags = 0; + + qca->ibs_sent_wacks = 0; + qca->ibs_sent_slps = 0; + qca->ibs_sent_wakes = 0; + qca->ibs_recv_wacks = 0; + qca->ibs_recv_slps = 0; + qca->ibs_recv_wakes = 0; + qca->vote_last_jif = jiffies; + qca->vote_on_ms = 0; + qca->vote_off_ms = 0; + qca->votes_on = 0; + qca->votes_off = 0; + qca->tx_votes_on = 0; + qca->tx_votes_off = 0; + qca->rx_votes_on = 0; + qca->rx_votes_off = 0; + + hu->priv = qca; + + init_timer(&qca->wake_retrans_timer); + qca->wake_retrans_timer.function = hci_ibs_wake_retrans_timeout; + qca->wake_retrans_timer.data = (u_long)hu; + qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS; + + init_timer(&qca->tx_idle_timer); + qca->tx_idle_timer.function = hci_ibs_tx_idle_timeout; + qca->tx_idle_timer.data = (u_long)hu; + qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS; + + BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u", + qca->tx_idle_delay, qca->wake_retrans); + + return 0; +} + +static void qca_debugfs_init(struct hci_dev *hdev) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + struct qca_data *qca = hu->priv; + struct dentry *ibs_dir; + umode_t mode; + + if (!hdev->debugfs) + return; + + ibs_dir = debugfs_create_dir("ibs", hdev->debugfs); + + /* read only */ + mode = S_IRUGO; + debugfs_create_u8("tx_ibs_state", mode, ibs_dir, &qca->tx_ibs_state); + debugfs_create_u8("rx_ibs_state", mode, ibs_dir, &qca->rx_ibs_state); + debugfs_create_u64("ibs_sent_sleeps", mode, ibs_dir, + &qca->ibs_sent_slps); + debugfs_create_u64("ibs_sent_wakes", mode, ibs_dir, + &qca->ibs_sent_wakes); + debugfs_create_u64("ibs_sent_wake_acks", mode, ibs_dir, + &qca->ibs_sent_wacks); + debugfs_create_u64("ibs_recv_sleeps", mode, ibs_dir, + &qca->ibs_recv_slps); + debugfs_create_u64("ibs_recv_wakes", mode, ibs_dir, + &qca->ibs_recv_wakes); + debugfs_create_u64("ibs_recv_wake_acks", mode, ibs_dir, + &qca->ibs_recv_wacks); + debugfs_create_bool("tx_vote", mode, ibs_dir, (u32 *)&qca->tx_vote); + debugfs_create_u64("tx_votes_on", mode, ibs_dir, &qca->tx_votes_on); + debugfs_create_u64("tx_votes_off", mode, ibs_dir, &qca->tx_votes_off); + debugfs_create_bool("rx_vote", mode, ibs_dir, (u32 *)&qca->rx_vote); + debugfs_create_u64("rx_votes_on", mode, ibs_dir, &qca->rx_votes_on); + debugfs_create_u64("rx_votes_off", mode, ibs_dir, &qca->rx_votes_off); + debugfs_create_u64("votes_on", mode, ibs_dir, &qca->votes_on); + debugfs_create_u64("votes_off", mode, ibs_dir, &qca->votes_off); + debugfs_create_u32("vote_on_ms", mode, ibs_dir, &qca->vote_on_ms); + debugfs_create_u32("vote_off_ms", mode, ibs_dir, &qca->vote_off_ms); + + /* read/write */ + mode = S_IRUGO | S_IWUSR; + debugfs_create_u32("wake_retrans", mode, ibs_dir, &qca->wake_retrans); + debugfs_create_u32("tx_idle_delay", mode, ibs_dir, + &qca->tx_idle_delay); +} + +/* Flush protocol data */ +static int qca_flush(struct hci_uart *hu) +{ + struct qca_data *qca = hu->priv; + + BT_DBG("hu %p qca flush", hu); + + skb_queue_purge(&qca->tx_wait_q); + skb_queue_purge(&qca->txq); + + return 0; +} + +/* Close protocol */ +static int qca_close(struct hci_uart *hu) +{ + struct qca_data *qca = hu->priv; + + BT_DBG("hu %p qca close", hu); + + serial_clock_vote(HCI_IBS_VOTE_STATS_UPDATE, hu); + + skb_queue_purge(&qca->tx_wait_q); + skb_queue_purge(&qca->txq); + del_timer(&qca->tx_idle_timer); + del_timer(&qca->wake_retrans_timer); + destroy_workqueue(qca->workqueue); + qca->hu = NULL; + + kfree_skb(qca->rx_skb); + + hu->priv = NULL; + + kfree(qca); + + return 0; +} + +/* Called upon a wake-up-indication from the device. + */ +static void device_want_to_wakeup(struct hci_uart *hu) +{ + unsigned long flags; + struct qca_data *qca = hu->priv; + + BT_DBG("hu %p want to wake up", hu); + + spin_lock_irqsave(&qca->hci_ibs_lock, flags); + + qca->ibs_recv_wakes++; + + switch (qca->rx_ibs_state) { + case HCI_IBS_RX_ASLEEP: + /* Make sure clock is on - we may have turned clock off since + * receiving the wake up indicator awake rx clock. + */ + queue_work(qca->workqueue, &qca->ws_awake_rx); + spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); + return; + + case HCI_IBS_RX_AWAKE: + /* Always acknowledge device wake up, + * sending IBS message doesn't count as TX ON. + */ + if (send_hci_ibs_cmd(HCI_IBS_WAKE_ACK, hu) < 0) { + BT_ERR("Failed to acknowledge device wake up"); + break; + } + qca->ibs_sent_wacks++; + break; + + default: + /* Any other state is illegal */ + BT_ERR("Received HCI_IBS_WAKE_IND in rx state %d", + qca->rx_ibs_state); + break; + } + + spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); + + /* Actually send the packets */ + hci_uart_tx_wakeup(hu); +} + +/* Called upon a sleep-indication from the device. + */ +static void device_want_to_sleep(struct hci_uart *hu) +{ + unsigned long flags; + struct qca_data *qca = hu->priv; + + BT_DBG("hu %p want to sleep", hu); + + spin_lock_irqsave(&qca->hci_ibs_lock, flags); + + qca->ibs_recv_slps++; + + switch (qca->rx_ibs_state) { + case HCI_IBS_RX_AWAKE: + /* Update state */ + qca->rx_ibs_state = HCI_IBS_RX_ASLEEP; + /* Vote off rx clock under workqueue */ + queue_work(qca->workqueue, &qca->ws_rx_vote_off); + break; + + case HCI_IBS_RX_ASLEEP: + /* Fall through */ + + default: + /* Any other state is illegal */ + BT_ERR("Received HCI_IBS_SLEEP_IND in rx state %d", + qca->rx_ibs_state); + break; + } + + spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); +} + +/* Called upon wake-up-acknowledgement from the device + */ +static void device_woke_up(struct hci_uart *hu) +{ + unsigned long flags, idle_delay; + struct qca_data *qca = hu->priv; + struct sk_buff *skb = NULL; + + BT_DBG("hu %p woke up", hu); + + spin_lock_irqsave(&qca->hci_ibs_lock, flags); + + qca->ibs_recv_wacks++; + + switch (qca->tx_ibs_state) { + case HCI_IBS_TX_AWAKE: + /* Expect one if we send 2 WAKEs */ + BT_DBG("Received HCI_IBS_WAKE_ACK in tx state %d", + qca->tx_ibs_state); + break; + + case HCI_IBS_TX_WAKING: + /* Send pending packets */ + while ((skb = skb_dequeue(&qca->tx_wait_q))) + skb_queue_tail(&qca->txq, skb); + + /* Switch timers and change state to HCI_IBS_TX_AWAKE */ + del_timer(&qca->wake_retrans_timer); + idle_delay = msecs_to_jiffies(qca->tx_idle_delay); + mod_timer(&qca->tx_idle_timer, jiffies + idle_delay); + qca->tx_ibs_state = HCI_IBS_TX_AWAKE; + break; + + case HCI_IBS_TX_ASLEEP: + /* Fall through */ + + default: + BT_ERR("Received HCI_IBS_WAKE_ACK in tx state %d", + qca->tx_ibs_state); + break; + } + + spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); + + /* Actually send the packets */ + hci_uart_tx_wakeup(hu); +} + +/* Enqueue frame for transmittion (padding, crc, etc) may be called from + * two simultaneous tasklets. + */ +static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb) +{ + unsigned long flags = 0, idle_delay; + struct qca_data *qca = hu->priv; + + BT_DBG("hu %p qca enq skb %p tx_ibs_state %d", hu, skb, + qca->tx_ibs_state); + + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); + + /* Don't go to sleep in middle of patch download or + * Out-Of-Band(GPIOs control) sleep is selected. + */ + if (!test_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags)) { + skb_queue_tail(&qca->txq, skb); + return 0; + } + + spin_lock_irqsave(&qca->hci_ibs_lock, flags); + + /* Act according to current state */ + switch (qca->tx_ibs_state) { + case HCI_IBS_TX_AWAKE: + BT_DBG("Device awake, sending normally"); + skb_queue_tail(&qca->txq, skb); + idle_delay = msecs_to_jiffies(qca->tx_idle_delay); + mod_timer(&qca->tx_idle_timer, jiffies + idle_delay); + break; + + case HCI_IBS_TX_ASLEEP: + BT_DBG("Device asleep, waking up and queueing packet"); + /* Save packet for later */ + skb_queue_tail(&qca->tx_wait_q, skb); + + qca->tx_ibs_state = HCI_IBS_TX_WAKING; + /* Schedule a work queue to wake up device */ + queue_work(qca->workqueue, &qca->ws_awake_device); + break; + + case HCI_IBS_TX_WAKING: + BT_DBG("Device waking up, queueing packet"); + /* Transient state; just keep packet for later */ + skb_queue_tail(&qca->tx_wait_q, skb); + break; + + default: + BT_ERR("Illegal tx state: %d (losing packet)", + qca->tx_ibs_state); + kfree_skb(skb); + break; + } + + spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); + + return 0; +} + +static int qca_ibs_sleep_ind(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + + BT_DBG("hu %p recv hci ibs cmd 0x%x", hu, HCI_IBS_SLEEP_IND); + + device_want_to_sleep(hu); + + kfree_skb(skb); + return 0; +} + +static int qca_ibs_wake_ind(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + + BT_DBG("hu %p recv hci ibs cmd 0x%x", hu, HCI_IBS_WAKE_IND); + + device_want_to_wakeup(hu); + + kfree_skb(skb); + return 0; +} + +static int qca_ibs_wake_ack(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + + BT_DBG("hu %p recv hci ibs cmd 0x%x", hu, HCI_IBS_WAKE_ACK); + + device_woke_up(hu); + + kfree_skb(skb); + return 0; +} + +#define QCA_IBS_SLEEP_IND_EVENT \ + .type = HCI_IBS_SLEEP_IND, \ + .hlen = 0, \ + .loff = 0, \ + .lsize = 0, \ + .maxlen = HCI_MAX_IBS_SIZE + +#define QCA_IBS_WAKE_IND_EVENT \ + .type = HCI_IBS_WAKE_IND, \ + .hlen = 0, \ + .loff = 0, \ + .lsize = 0, \ + .maxlen = HCI_MAX_IBS_SIZE + +#define QCA_IBS_WAKE_ACK_EVENT \ + .type = HCI_IBS_WAKE_ACK, \ + .hlen = 0, \ + .loff = 0, \ + .lsize = 0, \ + .maxlen = HCI_MAX_IBS_SIZE + +static const struct h4_recv_pkt qca_recv_pkts[] = { + { H4_RECV_ACL, .recv = hci_recv_frame }, + { H4_RECV_SCO, .recv = hci_recv_frame }, + { H4_RECV_EVENT, .recv = hci_recv_frame }, + { QCA_IBS_WAKE_IND_EVENT, .recv = qca_ibs_wake_ind }, + { QCA_IBS_WAKE_ACK_EVENT, .recv = qca_ibs_wake_ack }, + { QCA_IBS_SLEEP_IND_EVENT, .recv = qca_ibs_sleep_ind }, +}; + +static int qca_recv(struct hci_uart *hu, const void *data, int count) +{ + struct qca_data *qca = hu->priv; + + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) + return -EUNATCH; + + qca->rx_skb = h4_recv_buf(hu->hdev, qca->rx_skb, data, count, + qca_recv_pkts, ARRAY_SIZE(qca_recv_pkts)); + if (IS_ERR(qca->rx_skb)) { + int err = PTR_ERR(qca->rx_skb); + BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + qca->rx_skb = NULL; + return err; + } + + return count; +} + +static struct sk_buff *qca_dequeue(struct hci_uart *hu) +{ + struct qca_data *qca = hu->priv; + + return skb_dequeue(&qca->txq); +} + +static uint8_t qca_get_baudrate_value(int speed) +{ + switch(speed) { + case 9600: + return QCA_BAUDRATE_9600; + case 19200: + return QCA_BAUDRATE_19200; + case 38400: + return QCA_BAUDRATE_38400; + case 57600: + return QCA_BAUDRATE_57600; + case 115200: + return QCA_BAUDRATE_115200; + case 230400: + return QCA_BAUDRATE_230400; + case 460800: + return QCA_BAUDRATE_460800; + case 500000: + return QCA_BAUDRATE_500000; + case 921600: + return QCA_BAUDRATE_921600; + case 1000000: + return QCA_BAUDRATE_1000000; + case 2000000: + return QCA_BAUDRATE_2000000; + case 3000000: + return QCA_BAUDRATE_3000000; + case 3500000: + return QCA_BAUDRATE_3500000; + default: + return QCA_BAUDRATE_115200; + } +} + +static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + struct qca_data *qca = hu->priv; + struct sk_buff *skb; + u8 cmd[] = { 0x01, 0x48, 0xFC, 0x01, 0x00 }; + + if (baudrate > QCA_BAUDRATE_3000000) + return -EINVAL; + + cmd[4] = baudrate; + + skb = bt_skb_alloc(sizeof(cmd), GFP_ATOMIC); + if (!skb) { + BT_ERR("Failed to allocate memory for baudrate packet"); + return -ENOMEM; + } + + /* Assign commands to change baudrate and packet type. */ + memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); + bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; + + skb_queue_tail(&qca->txq, skb); + hci_uart_tx_wakeup(hu); + + /* wait 300ms to change new baudrate on controller side + * controller will come back after they receive this HCI command + * then host can communicate with new baudrate to controller + */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(BAUDRATE_SETTLE_TIMEOUT_MS)); + set_current_state(TASK_INTERRUPTIBLE); + + return 0; +} + +static int qca_setup(struct hci_uart *hu) +{ + struct hci_dev *hdev = hu->hdev; + struct qca_data *qca = hu->priv; + unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200; + int ret; + + BT_INFO("%s: ROME setup", hdev->name); + + /* Patch downloading has to be done without IBS mode */ + clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); + + /* Setup initial baudrate */ + speed = 0; + if (hu->init_speed) + speed = hu->init_speed; + else if (hu->proto->init_speed) + speed = hu->proto->init_speed; + + if (speed) + hci_uart_set_baudrate(hu, speed); + + /* Setup user speed if needed */ + speed = 0; + if (hu->oper_speed) + speed = hu->oper_speed; + else if (hu->proto->oper_speed) + speed = hu->proto->oper_speed; + + if (speed) { + qca_baudrate = qca_get_baudrate_value(speed); + + BT_INFO("%s: Set UART speed to %d", hdev->name, speed); + ret = qca_set_baudrate(hdev, qca_baudrate); + if (ret) { + BT_ERR("%s: Failed to change the baud rate (%d)", + hdev->name, ret); + return ret; + } + hci_uart_set_baudrate(hu, speed); + } + + /* Setup patch / NVM configurations */ + ret = qca_uart_setup_rome(hdev, qca_baudrate); + if (!ret) { + set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); + qca_debugfs_init(hdev); + } + + /* Setup bdaddr */ + hu->hdev->set_bdaddr = qca_set_bdaddr_rome; + + return ret; +} + +static struct hci_uart_proto qca_proto = { + .id = HCI_UART_QCA, + .name = "QCA", + .init_speed = 115200, + .oper_speed = 3000000, + .open = qca_open, + .close = qca_close, + .flush = qca_flush, + .setup = qca_setup, + .recv = qca_recv, + .enqueue = qca_enqueue, + .dequeue = qca_dequeue, +}; + +int __init qca_init(void) +{ + return hci_uart_register_proto(&qca_proto); +} + +int __exit qca_deinit(void) +{ + return hci_uart_unregister_proto(&qca_proto); +} diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 496587a73a9d..495b9ef52bb0 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -35,7 +35,7 @@ #define HCIUARTGETFLAGS _IOR('U', 204, int) /* UART protocols */ -#define HCI_UART_MAX_PROTO 8 +#define HCI_UART_MAX_PROTO 9 #define HCI_UART_H4 0 #define HCI_UART_BCSP 1 @@ -45,6 +45,7 @@ #define HCI_UART_ATH3K 5 #define HCI_UART_INTEL 6 #define HCI_UART_BCM 7 +#define HCI_UART_QCA 8 #define HCI_UART_RAW_DEVICE 0 #define HCI_UART_RESET_ON_INIT 1 @@ -176,3 +177,8 @@ int intel_deinit(void); int bcm_init(void); int bcm_deinit(void); #endif + +#ifdef CONFIG_BT_HCIUART_QCA +int qca_init(void); +int qca_deinit(void); +#endif -- cgit v1.3-6-gb490 From 025bcc154027fc52b1aee192c4599bb6ee6a3c9c Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 3 Aug 2015 10:18:10 -0700 Subject: HID: wacom: Simplify 'wacom_pl_irq' Unlike other IRQ functions, 'wacom_pl_irq' uses the second element of the 'tool' array to store information about its single pen. This makes the function more difficult to understand (since it doesn't follow the general pattern of other IRQ functions) and prevents the possibility of refactoring how pen state is stored. This patch rewrites 'wacom_pl_irq' to follow the usual IRQ conventions, including storing tool type in 'tool[0]' and implicitly tracking prox with the 'id[0]' variable. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 84 +++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 4d11c7857e70..fe164dfc8a7c 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -125,61 +125,47 @@ static int wacom_pl_irq(struct wacom_wac *wacom) prox = data[1] & 0x40; - if (prox) { - wacom->id[0] = ERASER_DEVICE_ID; - pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); - if (features->pressure_max > 255) - pressure = (pressure << 1) | ((data[4] >> 6) & 1); - pressure += (features->pressure_max + 1) / 2; - - /* - * if going from out of proximity into proximity select between the eraser - * and the pen based on the state of the stylus2 button, choose eraser if - * pressed else choose pen. if not a proximity change from out to in, send - * an out of proximity for previous tool then a in for new tool. - */ - if (!wacom->tool[0]) { - /* Eraser bit set for DTF */ - if (data[1] & 0x10) - wacom->tool[1] = BTN_TOOL_RUBBER; - else - /* Going into proximity select tool */ - wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - } else { - /* was entered with stylus2 pressed */ - if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) { - /* report out proximity for previous tool */ - input_report_key(input, wacom->tool[1], 0); - input_sync(input); - wacom->tool[1] = BTN_TOOL_PEN; - return 0; - } + if (!wacom->id[0]) { + if ((data[0] & 0x10) || (data[4] & 0x20)) { + wacom->tool[0] = BTN_TOOL_RUBBER; + wacom->id[0] = ERASER_DEVICE_ID; } - if (wacom->tool[1] != BTN_TOOL_RUBBER) { - /* Unknown tool selected default to pen tool */ - wacom->tool[1] = BTN_TOOL_PEN; + else { + wacom->tool[0] = BTN_TOOL_PEN; wacom->id[0] = STYLUS_DEVICE_ID; } - input_report_key(input, wacom->tool[1], prox); /* report in proximity for tool */ - input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ - input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); - input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); - input_report_abs(input, ABS_PRESSURE, pressure); + } - input_report_key(input, BTN_TOUCH, data[4] & 0x08); - input_report_key(input, BTN_STYLUS, data[4] & 0x10); - /* Only allow the stylus2 button to be reported for the pen tool. */ - input_report_key(input, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20)); - } else { - /* report proximity-out of a (valid) tool */ - if (wacom->tool[1] != BTN_TOOL_RUBBER) { - /* Unknown tool selected default to pen tool */ - wacom->tool[1] = BTN_TOOL_PEN; - } - input_report_key(input, wacom->tool[1], prox); + /* If the eraser is in prox, STYLUS2 is always set. If we + * mis-detected the type and notice that STYLUS2 isn't set + * then force the eraser out of prox and let the pen in. + */ + if (wacom->tool[0] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) { + input_report_key(input, BTN_TOOL_RUBBER, 0); + input_report_abs(input, ABS_MISC, 0); + input_sync(input); + wacom->tool[0] = BTN_TOOL_PEN; + wacom->id[0] = STYLUS_DEVICE_ID; } - wacom->tool[0] = prox; /* Save proximity state */ + pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); + if (features->pressure_max > 255) + pressure = (pressure << 1) | ((data[4] >> 6) & 1); + pressure += (features->pressure_max + 1) / 2; + + input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); + input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); + input_report_abs(input, ABS_PRESSURE, pressure); + + input_report_key(input, BTN_TOUCH, data[4] & 0x08); + input_report_key(input, BTN_STYLUS, data[4] & 0x10); + /* Only allow the stylus2 button to be reported for the pen tool. */ + input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20)); + + if (!prox) + wacom->id[0] = 0; + input_report_key(input, wacom->tool[0], prox); + input_report_abs(input, ABS_MISC, wacom->id[0]); return 1; } -- cgit v1.3-6-gb490 From a73e99cb67e7438e5ab0c524ae63a8a27616c839 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 10 Aug 2015 17:49:51 +0200 Subject: staging: ozwpan: Remove from tree Ozwpan is completely unmaintained and potentially a security problem. As this is a staging driver, it should be removed, since it has been abandoned. Cc: Shigekatsu Tateno Signed-off-by: Jason A. Donenfeld Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 5 - drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/ozwpan/Kconfig | 9 - drivers/staging/ozwpan/Makefile | 16 - drivers/staging/ozwpan/README | 25 - drivers/staging/ozwpan/TODO | 14 - drivers/staging/ozwpan/ozappif.h | 36 - drivers/staging/ozwpan/ozcdev.c | 554 -------- drivers/staging/ozwpan/ozcdev.h | 17 - drivers/staging/ozwpan/ozdbg.h | 54 - drivers/staging/ozwpan/ozeltbuf.c | 252 ---- drivers/staging/ozwpan/ozeltbuf.h | 65 - drivers/staging/ozwpan/ozhcd.c | 2301 -------------------------------- drivers/staging/ozwpan/ozhcd.h | 15 - drivers/staging/ozwpan/ozmain.c | 71 - drivers/staging/ozwpan/ozpd.c | 886 ------------ drivers/staging/ozwpan/ozpd.h | 134 -- drivers/staging/ozwpan/ozproto.c | 813 ----------- drivers/staging/ozwpan/ozproto.h | 62 - drivers/staging/ozwpan/ozprotocol.h | 375 ------ drivers/staging/ozwpan/ozurbparanoia.c | 54 - drivers/staging/ozwpan/ozurbparanoia.h | 19 - drivers/staging/ozwpan/ozusbif.h | 43 - drivers/staging/ozwpan/ozusbsvc.c | 263 ---- drivers/staging/ozwpan/ozusbsvc.h | 32 - drivers/staging/ozwpan/ozusbsvc1.c | 472 ------- 27 files changed, 6590 deletions(-) delete mode 100644 drivers/staging/ozwpan/Kconfig delete mode 100644 drivers/staging/ozwpan/Makefile delete mode 100644 drivers/staging/ozwpan/README delete mode 100644 drivers/staging/ozwpan/TODO delete mode 100644 drivers/staging/ozwpan/ozappif.h delete mode 100644 drivers/staging/ozwpan/ozcdev.c delete mode 100644 drivers/staging/ozwpan/ozcdev.h delete mode 100644 drivers/staging/ozwpan/ozdbg.h delete mode 100644 drivers/staging/ozwpan/ozeltbuf.c delete mode 100644 drivers/staging/ozwpan/ozeltbuf.h delete mode 100644 drivers/staging/ozwpan/ozhcd.c delete mode 100644 drivers/staging/ozwpan/ozhcd.h delete mode 100644 drivers/staging/ozwpan/ozmain.c delete mode 100644 drivers/staging/ozwpan/ozpd.c delete mode 100644 drivers/staging/ozwpan/ozpd.h delete mode 100644 drivers/staging/ozwpan/ozproto.c delete mode 100644 drivers/staging/ozwpan/ozproto.h delete mode 100644 drivers/staging/ozwpan/ozprotocol.h delete mode 100644 drivers/staging/ozwpan/ozurbparanoia.c delete mode 100644 drivers/staging/ozwpan/ozurbparanoia.h delete mode 100644 drivers/staging/ozwpan/ozusbif.h delete mode 100644 drivers/staging/ozwpan/ozusbsvc.c delete mode 100644 drivers/staging/ozwpan/ozusbsvc.h delete mode 100644 drivers/staging/ozwpan/ozusbsvc1.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 5ac00cb37256..fb7d3b6acd70 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9734,11 +9734,6 @@ W: http://wiki.laptop.org/go/DCON S: Maintained F: drivers/staging/olpc_dcon/ -STAGING - OZMO DEVICES USB OVER WIFI DRIVER -M: Shigekatsu Tateno -S: Maintained -F: drivers/staging/ozwpan/ - STAGING - PARALLEL LCD/KEYPAD PANEL DRIVER M: Willy Tarreau S: Odd Fixes diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 39c5df6154aa..e29293c0c71e 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -76,8 +76,6 @@ source "drivers/staging/android/Kconfig" source "drivers/staging/board/Kconfig" -source "drivers/staging/ozwpan/Kconfig" - source "drivers/staging/gdm72xx/Kconfig" source "drivers/staging/gdm724x/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 018093d60e85..50824dde2c09 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -31,7 +31,6 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ obj-$(CONFIG_MFD_NVEC) += nvec/ obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_STAGING_BOARD) += board/ -obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/ obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/ obj-$(CONFIG_LTE_GDM724X) += gdm724x/ obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/ diff --git a/drivers/staging/ozwpan/Kconfig b/drivers/staging/ozwpan/Kconfig deleted file mode 100644 index 7904caec546a..000000000000 --- a/drivers/staging/ozwpan/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config USB_WPAN_HCD - tristate "USB over WiFi Host Controller" - depends on USB && NET - help - A driver for USB Host Controllers that are compatible with - Ozmo Devices USB over WiFi technology. - - To compile this driver a module, choose M here: the module - will be called "ozwpan". diff --git a/drivers/staging/ozwpan/Makefile b/drivers/staging/ozwpan/Makefile deleted file mode 100644 index 29529c1a8e3c..000000000000 --- a/drivers/staging/ozwpan/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# ----------------------------------------------------------------------------- -# Copyright (c) 2011 Ozmo Inc -# Released under the GNU General Public License Version 2 (GPLv2). -# ----------------------------------------------------------------------------- - -obj-$(CONFIG_USB_WPAN_HCD) += ozwpan.o -ozwpan-y := \ - ozmain.o \ - ozpd.o \ - ozusbsvc.o \ - ozusbsvc1.o \ - ozhcd.o \ - ozeltbuf.o \ - ozproto.o \ - ozcdev.o \ - ozurbparanoia.o diff --git a/drivers/staging/ozwpan/README b/drivers/staging/ozwpan/README deleted file mode 100644 index 7c055ec99544..000000000000 --- a/drivers/staging/ozwpan/README +++ /dev/null @@ -1,25 +0,0 @@ -OZWPAN USB Host Controller Driver ---------------------------------- -This driver is a USB HCD driver that does not have an associated a physical -device but instead uses Wi-Fi to communicate with the wireless peripheral. -The USB requests are converted into a layer 2 network protocol and transmitted -on the network using an ethertype (0x892e) regestered to Ozmo Device Inc. -This driver is compatible with existing wireless devices that use Ozmo Devices -technology. - -To operate the driver must be bound to a suitable network interface. This can -be done when the module is loaded (specifying the name of the network interface -as a parameter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after -loading using an ioctl call. See the ozappif.h file and the ioctls -OZ_IOCTL_ADD_BINDING and OZ_IOCTL_REMOVE_BINDING. - -The devices connect to the host use Wi-Fi Direct so a network card that supports -Wi-Fi direct is required. A recent version (0.8.x or later) version of the -wpa_supplicant can be used to setup the network interface to create a persistent -autonomous group (for older pre-WFD peripherals) or put in a listen state to -allow group negotiation to occur for more recent devices that support WFD. - -The protocol used over the network does not directly mimic the USB bus -transactions as this would be rather busy and inefficient. Instead the chapter 9 -requests are converted into a request/response pair of messages. (See -ozprotocol.h for data structures used in the protocol). diff --git a/drivers/staging/ozwpan/TODO b/drivers/staging/ozwpan/TODO deleted file mode 100644 index f32c1c0bc875..000000000000 --- a/drivers/staging/ozwpan/TODO +++ /dev/null @@ -1,14 +0,0 @@ -TODO: - - Convert event tracing code to in-kernel tracing infrastructure - - Check for remaining ioctl & check if that can be converted into - sysfs entries - - Convert debug prints to appropriate dev_debug or something better - - Modify Kconfig to add CONFIG option for enabling/disabling event - tracing. - - check USB HCD implementation is complete and correct. - - code review by USB developer community. - - testing with as many devices as possible. - -Please send any patches for this driver to -Shigekatsu Tateno -and Greg Kroah-Hartman . diff --git a/drivers/staging/ozwpan/ozappif.h b/drivers/staging/ozwpan/ozappif.h deleted file mode 100644 index ea1b271fdcda..000000000000 --- a/drivers/staging/ozwpan/ozappif.h +++ /dev/null @@ -1,36 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#ifndef _OZAPPIF_H -#define _OZAPPIF_H - -#define OZ_IOCTL_MAGIC 0xf4 - -struct oz_mac_addr { - __u8 a[6]; -}; - -#define OZ_MAX_PDS 8 - -struct oz_pd_list { - __u32 count; - struct oz_mac_addr addr[OZ_MAX_PDS]; -}; - -#define OZ_MAX_BINDING_LEN 32 - -struct oz_binding_info { - char name[OZ_MAX_BINDING_LEN]; -}; - -#define OZ_IOCTL_GET_PD_LIST _IOR(OZ_IOCTL_MAGIC, 0, struct oz_pd_list) -#define OZ_IOCTL_SET_ACTIVE_PD _IOW(OZ_IOCTL_MAGIC, 1, struct oz_mac_addr) -#define OZ_IOCTL_GET_ACTIVE_PD _IOR(OZ_IOCTL_MAGIC, 2, struct oz_mac_addr) -#define OZ_IOCTL_ADD_BINDING _IOW(OZ_IOCTL_MAGIC, 3, struct oz_binding_info) -#define OZ_IOCTL_REMOVE_BINDING _IOW(OZ_IOCTL_MAGIC, 4, struct oz_binding_info) -#define OZ_IOCTL_MAX 5 - - -#endif /* _OZAPPIF_H */ diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c deleted file mode 100644 index da0e1fd50f26..000000000000 --- a/drivers/staging/ozwpan/ozcdev.c +++ /dev/null @@ -1,554 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "ozdbg.h" -#include "ozprotocol.h" -#include "ozappif.h" -#include "ozeltbuf.h" -#include "ozpd.h" -#include "ozproto.h" -#include "ozcdev.h" - -#define OZ_RD_BUF_SZ 256 -struct oz_cdev { - dev_t devnum; - struct cdev cdev; - wait_queue_head_t rdq; - spinlock_t lock; - u8 active_addr[ETH_ALEN]; - struct oz_pd *active_pd; -}; - -/* Per PD context for the serial service stored in the PD. */ -struct oz_serial_ctx { - atomic_t ref_count; - u8 tx_seq_num; - u8 rx_seq_num; - u8 rd_buf[OZ_RD_BUF_SZ]; - int rd_in; - int rd_out; -}; - -static struct oz_cdev g_cdev; -static struct class *g_oz_class; - -/* - * Context: process and softirq - */ -static struct oz_serial_ctx *oz_cdev_claim_ctx(struct oz_pd *pd) -{ - struct oz_serial_ctx *ctx; - - spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL]); - ctx = (struct oz_serial_ctx *) pd->app_ctx[OZ_APPID_SERIAL]; - if (ctx) - atomic_inc(&ctx->ref_count); - spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL]); - return ctx; -} - -/* - * Context: softirq or process - */ -static void oz_cdev_release_ctx(struct oz_serial_ctx *ctx) -{ - if (atomic_dec_and_test(&ctx->ref_count)) { - oz_dbg(ON, "Dealloc serial context\n"); - kfree(ctx); - } -} - -/* - * Context: process - */ -static int oz_cdev_open(struct inode *inode, struct file *filp) -{ - struct oz_cdev *dev = container_of(inode->i_cdev, struct oz_cdev, cdev); - - oz_dbg(ON, "major = %d minor = %d\n", imajor(inode), iminor(inode)); - - filp->private_data = dev; - return 0; -} - -/* - * Context: process - */ -static int oz_cdev_release(struct inode *inode, struct file *filp) -{ - return 0; -} - -/* - * Context: process - */ -static ssize_t oz_cdev_read(struct file *filp, char __user *buf, size_t count, - loff_t *fpos) -{ - int n; - int ix; - - struct oz_pd *pd; - struct oz_serial_ctx *ctx; - - spin_lock_bh(&g_cdev.lock); - pd = g_cdev.active_pd; - if (pd) - oz_pd_get(pd); - spin_unlock_bh(&g_cdev.lock); - if (pd == NULL) - return -1; - ctx = oz_cdev_claim_ctx(pd); - if (ctx == NULL) - goto out2; - n = ctx->rd_in - ctx->rd_out; - if (n < 0) - n += OZ_RD_BUF_SZ; - if (count > n) - count = n; - ix = ctx->rd_out; - n = OZ_RD_BUF_SZ - ix; - if (n > count) - n = count; - if (copy_to_user(buf, &ctx->rd_buf[ix], n)) { - count = 0; - goto out1; - } - ix += n; - if (ix == OZ_RD_BUF_SZ) - ix = 0; - if (n < count) { - if (copy_to_user(&buf[n], ctx->rd_buf, count-n)) { - count = 0; - goto out1; - } - ix = count-n; - } - ctx->rd_out = ix; -out1: - oz_cdev_release_ctx(ctx); -out2: - oz_pd_put(pd); - return count; -} - -/* - * Context: process - */ -static ssize_t oz_cdev_write(struct file *filp, const char __user *buf, - size_t count, loff_t *fpos) -{ - struct oz_pd *pd; - struct oz_elt_buf *eb; - struct oz_elt_info *ei; - struct oz_elt *elt; - struct oz_app_hdr *app_hdr; - struct oz_serial_ctx *ctx; - - if (count > sizeof(ei->data) - sizeof(*elt) - sizeof(*app_hdr)) - return -EINVAL; - - spin_lock_bh(&g_cdev.lock); - pd = g_cdev.active_pd; - if (pd) - oz_pd_get(pd); - spin_unlock_bh(&g_cdev.lock); - if (pd == NULL) - return -ENXIO; - if (!(pd->state & OZ_PD_S_CONNECTED)) - return -EAGAIN; - eb = &pd->elt_buff; - ei = oz_elt_info_alloc(eb); - if (ei == NULL) { - count = 0; - goto out; - } - elt = (struct oz_elt *)ei->data; - app_hdr = (struct oz_app_hdr *)(elt+1); - elt->length = sizeof(struct oz_app_hdr) + count; - elt->type = OZ_ELT_APP_DATA; - ei->app_id = OZ_APPID_SERIAL; - ei->length = elt->length + sizeof(struct oz_elt); - app_hdr->app_id = OZ_APPID_SERIAL; - if (copy_from_user(app_hdr+1, buf, count)) - goto out; - spin_lock_bh(&pd->app_lock[OZ_APPID_USB]); - ctx = (struct oz_serial_ctx *) pd->app_ctx[OZ_APPID_SERIAL]; - if (ctx) { - app_hdr->elt_seq_num = ctx->tx_seq_num++; - if (ctx->tx_seq_num == 0) - ctx->tx_seq_num = 1; - spin_lock(&eb->lock); - if (oz_queue_elt_info(eb, 0, 0, ei) == 0) - ei = NULL; - spin_unlock(&eb->lock); - } - spin_unlock_bh(&pd->app_lock[OZ_APPID_USB]); -out: - if (ei) { - count = 0; - spin_lock_bh(&eb->lock); - oz_elt_info_free(eb, ei); - spin_unlock_bh(&eb->lock); - } - oz_pd_put(pd); - return count; -} - -/* - * Context: process - */ -static int oz_set_active_pd(const u8 *addr) -{ - int rc = 0; - struct oz_pd *pd; - struct oz_pd *old_pd; - - pd = oz_pd_find(addr); - if (pd) { - spin_lock_bh(&g_cdev.lock); - ether_addr_copy(g_cdev.active_addr, addr); - old_pd = g_cdev.active_pd; - g_cdev.active_pd = pd; - spin_unlock_bh(&g_cdev.lock); - if (old_pd) - oz_pd_put(old_pd); - } else { - if (is_zero_ether_addr(addr)) { - spin_lock_bh(&g_cdev.lock); - pd = g_cdev.active_pd; - g_cdev.active_pd = NULL; - memset(g_cdev.active_addr, 0, - sizeof(g_cdev.active_addr)); - spin_unlock_bh(&g_cdev.lock); - if (pd) - oz_pd_put(pd); - } else { - rc = -1; - } - } - return rc; -} - -/* - * Context: process - */ -static long oz_cdev_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - int rc = 0; - - if (_IOC_TYPE(cmd) != OZ_IOCTL_MAGIC) - return -ENOTTY; - if (_IOC_NR(cmd) > OZ_IOCTL_MAX) - return -ENOTTY; - if (_IOC_DIR(cmd) & _IOC_READ) - rc = !access_ok(VERIFY_WRITE, (void __user *)arg, - _IOC_SIZE(cmd)); - else if (_IOC_DIR(cmd) & _IOC_WRITE) - rc = !access_ok(VERIFY_READ, (void __user *)arg, - _IOC_SIZE(cmd)); - if (rc) - return -EFAULT; - switch (cmd) { - case OZ_IOCTL_GET_PD_LIST: { - struct oz_pd_list list; - - oz_dbg(ON, "OZ_IOCTL_GET_PD_LIST\n"); - memset(&list, 0, sizeof(list)); - list.count = oz_get_pd_list(list.addr, OZ_MAX_PDS); - if (copy_to_user((void __user *)arg, &list, - sizeof(list))) - return -EFAULT; - } - break; - case OZ_IOCTL_SET_ACTIVE_PD: { - u8 addr[ETH_ALEN]; - - oz_dbg(ON, "OZ_IOCTL_SET_ACTIVE_PD\n"); - if (copy_from_user(addr, (void __user *)arg, ETH_ALEN)) - return -EFAULT; - rc = oz_set_active_pd(addr); - } - break; - case OZ_IOCTL_GET_ACTIVE_PD: { - u8 addr[ETH_ALEN]; - - oz_dbg(ON, "OZ_IOCTL_GET_ACTIVE_PD\n"); - spin_lock_bh(&g_cdev.lock); - ether_addr_copy(addr, g_cdev.active_addr); - spin_unlock_bh(&g_cdev.lock); - if (copy_to_user((void __user *)arg, addr, ETH_ALEN)) - return -EFAULT; - } - break; - case OZ_IOCTL_ADD_BINDING: - case OZ_IOCTL_REMOVE_BINDING: { - struct oz_binding_info b; - - if (copy_from_user(&b, (void __user *)arg, - sizeof(struct oz_binding_info))) { - return -EFAULT; - } - /* Make sure name is null terminated. */ - b.name[OZ_MAX_BINDING_LEN-1] = 0; - if (cmd == OZ_IOCTL_ADD_BINDING) - oz_binding_add(b.name); - else - oz_binding_remove(b.name); - } - break; - } - return rc; -} - -/* - * Context: process - */ -static unsigned int oz_cdev_poll(struct file *filp, poll_table *wait) -{ - unsigned int ret = 0; - struct oz_cdev *dev = filp->private_data; - - oz_dbg(ON, "Poll called wait = %p\n", wait); - spin_lock_bh(&dev->lock); - if (dev->active_pd) { - struct oz_serial_ctx *ctx = oz_cdev_claim_ctx(dev->active_pd); - - if (ctx) { - if (ctx->rd_in != ctx->rd_out) - ret |= POLLIN | POLLRDNORM; - oz_cdev_release_ctx(ctx); - } - } - spin_unlock_bh(&dev->lock); - if (wait) - poll_wait(filp, &dev->rdq, wait); - return ret; -} - -/* - */ -static const struct file_operations oz_fops = { - .owner = THIS_MODULE, - .open = oz_cdev_open, - .release = oz_cdev_release, - .read = oz_cdev_read, - .write = oz_cdev_write, - .unlocked_ioctl = oz_cdev_ioctl, - .poll = oz_cdev_poll -}; - -/* - * Context: process - */ -int oz_cdev_register(void) -{ - int err; - struct device *dev; - - memset(&g_cdev, 0, sizeof(g_cdev)); - err = alloc_chrdev_region(&g_cdev.devnum, 0, 1, "ozwpan"); - if (err < 0) - return err; - oz_dbg(ON, "Alloc dev number %d:%d\n", - MAJOR(g_cdev.devnum), MINOR(g_cdev.devnum)); - cdev_init(&g_cdev.cdev, &oz_fops); - g_cdev.cdev.owner = THIS_MODULE; - spin_lock_init(&g_cdev.lock); - init_waitqueue_head(&g_cdev.rdq); - err = cdev_add(&g_cdev.cdev, g_cdev.devnum, 1); - if (err < 0) { - oz_dbg(ON, "Failed to add cdev\n"); - goto unregister; - } - g_oz_class = class_create(THIS_MODULE, "ozmo_wpan"); - if (IS_ERR(g_oz_class)) { - oz_dbg(ON, "Failed to register ozmo_wpan class\n"); - err = PTR_ERR(g_oz_class); - goto delete; - } - dev = device_create(g_oz_class, NULL, g_cdev.devnum, NULL, "ozwpan"); - if (IS_ERR(dev)) { - oz_dbg(ON, "Failed to create sysfs entry for cdev\n"); - err = PTR_ERR(dev); - goto delete; - } - return 0; - -delete: - cdev_del(&g_cdev.cdev); -unregister: - unregister_chrdev_region(g_cdev.devnum, 1); - return err; -} - -/* - * Context: process - */ -int oz_cdev_deregister(void) -{ - cdev_del(&g_cdev.cdev); - unregister_chrdev_region(g_cdev.devnum, 1); - if (g_oz_class) { - device_destroy(g_oz_class, g_cdev.devnum); - class_destroy(g_oz_class); - } - return 0; -} - -/* - * Context: process - */ -int oz_cdev_init(void) -{ - oz_app_enable(OZ_APPID_SERIAL, 1); - return 0; -} - -/* - * Context: process - */ -void oz_cdev_term(void) -{ - oz_app_enable(OZ_APPID_SERIAL, 0); -} - -/* - * Context: softirq-serialized - */ -int oz_cdev_start(struct oz_pd *pd, int resume) -{ - struct oz_serial_ctx *ctx; - struct oz_serial_ctx *old_ctx; - - if (resume) { - oz_dbg(ON, "Serial service resumed\n"); - return 0; - } - ctx = kzalloc(sizeof(struct oz_serial_ctx), GFP_ATOMIC); - if (ctx == NULL) - return -ENOMEM; - atomic_set(&ctx->ref_count, 1); - ctx->tx_seq_num = 1; - spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL]); - old_ctx = pd->app_ctx[OZ_APPID_SERIAL]; - if (old_ctx) { - spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL]); - kfree(ctx); - } else { - pd->app_ctx[OZ_APPID_SERIAL] = ctx; - spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL]); - } - spin_lock(&g_cdev.lock); - if ((g_cdev.active_pd == NULL) && - ether_addr_equal(pd->mac_addr, g_cdev.active_addr)) { - oz_pd_get(pd); - g_cdev.active_pd = pd; - oz_dbg(ON, "Active PD arrived\n"); - } - spin_unlock(&g_cdev.lock); - oz_dbg(ON, "Serial service started\n"); - return 0; -} - -/* - * Context: softirq or process - */ -void oz_cdev_stop(struct oz_pd *pd, int pause) -{ - struct oz_serial_ctx *ctx; - - if (pause) { - oz_dbg(ON, "Serial service paused\n"); - return; - } - spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL]); - ctx = (struct oz_serial_ctx *) pd->app_ctx[OZ_APPID_SERIAL]; - pd->app_ctx[OZ_APPID_SERIAL] = NULL; - spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL]); - if (ctx) - oz_cdev_release_ctx(ctx); - spin_lock(&g_cdev.lock); - if (pd == g_cdev.active_pd) - g_cdev.active_pd = NULL; - else - pd = NULL; - spin_unlock(&g_cdev.lock); - if (pd) { - oz_pd_put(pd); - oz_dbg(ON, "Active PD departed\n"); - } - oz_dbg(ON, "Serial service stopped\n"); -} - -/* - * Context: softirq-serialized - */ -void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt) -{ - struct oz_serial_ctx *ctx; - struct oz_app_hdr *app_hdr; - u8 *data; - int len; - int space; - int copy_sz; - int ix; - - ctx = oz_cdev_claim_ctx(pd); - if (ctx == NULL) { - oz_dbg(ON, "Cannot claim serial context\n"); - return; - } - - app_hdr = (struct oz_app_hdr *)(elt+1); - /* If sequence number is non-zero then check it is not a duplicate. - */ - if (app_hdr->elt_seq_num != 0) { - if (((ctx->rx_seq_num - app_hdr->elt_seq_num) & 0x80) == 0) { - /* Reject duplicate element. */ - oz_dbg(ON, "Duplicate element:%02x %02x\n", - app_hdr->elt_seq_num, ctx->rx_seq_num); - goto out; - } - } - ctx->rx_seq_num = app_hdr->elt_seq_num; - len = elt->length - sizeof(struct oz_app_hdr); - data = ((u8 *)(elt+1)) + sizeof(struct oz_app_hdr); - if (len <= 0) - goto out; - space = ctx->rd_out - ctx->rd_in - 1; - if (space < 0) - space += OZ_RD_BUF_SZ; - if (len > space) { - oz_dbg(ON, "Not enough space:%d %d\n", len, space); - len = space; - } - ix = ctx->rd_in; - copy_sz = OZ_RD_BUF_SZ - ix; - if (copy_sz > len) - copy_sz = len; - memcpy(&ctx->rd_buf[ix], data, copy_sz); - len -= copy_sz; - ix += copy_sz; - if (ix == OZ_RD_BUF_SZ) - ix = 0; - if (len) { - memcpy(ctx->rd_buf, data+copy_sz, len); - ix = len; - } - ctx->rd_in = ix; - wake_up(&g_cdev.rdq); -out: - oz_cdev_release_ctx(ctx); -} diff --git a/drivers/staging/ozwpan/ozcdev.h b/drivers/staging/ozwpan/ozcdev.h deleted file mode 100644 index dd11935a093f..000000000000 --- a/drivers/staging/ozwpan/ozcdev.h +++ /dev/null @@ -1,17 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#ifndef _OZCDEV_H -#define _OZCDEV_H - -int oz_cdev_register(void); -int oz_cdev_deregister(void); -int oz_cdev_init(void); -void oz_cdev_term(void); -int oz_cdev_start(struct oz_pd *pd, int resume); -void oz_cdev_stop(struct oz_pd *pd, int pause); -void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt); - -#endif /* _OZCDEV_H */ diff --git a/drivers/staging/ozwpan/ozdbg.h b/drivers/staging/ozwpan/ozdbg.h deleted file mode 100644 index b86a2b7e0178..000000000000 --- a/drivers/staging/ozwpan/ozdbg.h +++ /dev/null @@ -1,54 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ---------------------------------------------------------------------------*/ - -#ifndef _OZDBG_H -#define _OZDBG_H - -#define OZ_WANT_DBG 0 -#define OZ_WANT_VERBOSE_DBG 1 - -#define OZ_DBG_ON 0x0 -#define OZ_DBG_STREAM 0x1 -#define OZ_DBG_URB 0x2 -#define OZ_DBG_CTRL_DETAIL 0x4 -#define OZ_DBG_HUB 0x8 -#define OZ_DBG_RX_FRAMES 0x10 -#define OZ_DBG_TX_FRAMES 0x20 - -#define OZ_DEFAULT_DBG_MASK \ - ( \ - /* OZ_DBG_STREAM | */ \ - /* OZ_DBG_URB | */ \ - /* OZ_DBG_CTRL_DETAIL | */ \ - OZ_DBG_HUB | \ - /* OZ_DBG_RX_FRAMES | */ \ - /* OZ_DBG_TX_FRAMES | */ \ - 0) - -extern unsigned int oz_dbg_mask; - -#define oz_want_dbg(mask) \ - ((OZ_WANT_DBG && (OZ_DBG_##mask == OZ_DBG_ON)) || \ - (OZ_WANT_VERBOSE_DBG && (OZ_DBG_##mask & oz_dbg_mask))) - -#define oz_dbg(mask, fmt, ...) \ -do { \ - if (oz_want_dbg(mask)) \ - pr_debug(fmt, ##__VA_ARGS__); \ -} while (0) - -#define oz_cdev_dbg(cdev, mask, fmt, ...) \ -do { \ - if (oz_want_dbg(mask)) \ - netdev_dbg((cdev)->dev, fmt, ##__VA_ARGS__); \ -} while (0) - -#define oz_pd_dbg(pd, mask, fmt, ...) \ -do { \ - if (oz_want_dbg(mask)) \ - pr_debug(fmt, ##__VA_ARGS__); \ -} while (0) - -#endif /* _OZDBG_H */ diff --git a/drivers/staging/ozwpan/ozeltbuf.c b/drivers/staging/ozwpan/ozeltbuf.c deleted file mode 100644 index 01b25da44241..000000000000 --- a/drivers/staging/ozwpan/ozeltbuf.c +++ /dev/null @@ -1,252 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#include -#include -#include "ozdbg.h" -#include "ozprotocol.h" -#include "ozeltbuf.h" -#include "ozpd.h" - -/* - * Context: softirq-serialized - */ -void oz_elt_buf_init(struct oz_elt_buf *buf) -{ - memset(buf, 0, sizeof(struct oz_elt_buf)); - INIT_LIST_HEAD(&buf->stream_list); - INIT_LIST_HEAD(&buf->order_list); - INIT_LIST_HEAD(&buf->isoc_list); - spin_lock_init(&buf->lock); -} - -/* - * Context: softirq or process - */ -void oz_elt_buf_term(struct oz_elt_buf *buf) -{ - struct oz_elt_info *ei, *n; - - list_for_each_entry_safe(ei, n, &buf->isoc_list, link_order) - kfree(ei); - list_for_each_entry_safe(ei, n, &buf->order_list, link_order) - kfree(ei); -} - -/* - * Context: softirq or process - */ -struct oz_elt_info *oz_elt_info_alloc(struct oz_elt_buf *buf) -{ - struct oz_elt_info *ei; - - ei = kmem_cache_zalloc(oz_elt_info_cache, GFP_ATOMIC); - if (ei) { - INIT_LIST_HEAD(&ei->link); - INIT_LIST_HEAD(&ei->link_order); - } - return ei; -} - -/* - * Precondition: oz_elt_buf.lock must be held. - * Context: softirq or process - */ -void oz_elt_info_free(struct oz_elt_buf *buf, struct oz_elt_info *ei) -{ - if (ei) - kmem_cache_free(oz_elt_info_cache, ei); -} - -/*------------------------------------------------------------------------------ - * Context: softirq - */ -void oz_elt_info_free_chain(struct oz_elt_buf *buf, struct list_head *list) -{ - struct oz_elt_info *ei, *n; - - spin_lock_bh(&buf->lock); - list_for_each_entry_safe(ei, n, list->next, link) - oz_elt_info_free(buf, ei); - spin_unlock_bh(&buf->lock); -} - -int oz_elt_stream_create(struct oz_elt_buf *buf, u8 id, int max_buf_count) -{ - struct oz_elt_stream *st; - - oz_dbg(ON, "%s: (0x%x)\n", __func__, id); - - st = kzalloc(sizeof(struct oz_elt_stream), GFP_ATOMIC); - if (st == NULL) - return -ENOMEM; - atomic_set(&st->ref_count, 1); - st->id = id; - st->max_buf_count = max_buf_count; - INIT_LIST_HEAD(&st->elt_list); - spin_lock_bh(&buf->lock); - list_add_tail(&st->link, &buf->stream_list); - spin_unlock_bh(&buf->lock); - return 0; -} - -int oz_elt_stream_delete(struct oz_elt_buf *buf, u8 id) -{ - struct list_head *e, *n; - struct oz_elt_stream *st = NULL; - - oz_dbg(ON, "%s: (0x%x)\n", __func__, id); - spin_lock_bh(&buf->lock); - list_for_each(e, &buf->stream_list) { - st = list_entry(e, struct oz_elt_stream, link); - if (st->id == id) { - list_del(e); - break; - } - st = NULL; - } - if (!st) { - spin_unlock_bh(&buf->lock); - return -1; - } - list_for_each_safe(e, n, &st->elt_list) { - struct oz_elt_info *ei = - list_entry(e, struct oz_elt_info, link); - list_del_init(&ei->link); - list_del_init(&ei->link_order); - st->buf_count -= ei->length; - oz_dbg(STREAM, "Stream down: %d %d %d\n", - st->buf_count, ei->length, atomic_read(&st->ref_count)); - oz_elt_stream_put(st); - oz_elt_info_free(buf, ei); - } - spin_unlock_bh(&buf->lock); - oz_elt_stream_put(st); - return 0; -} - -void oz_elt_stream_get(struct oz_elt_stream *st) -{ - atomic_inc(&st->ref_count); -} - -void oz_elt_stream_put(struct oz_elt_stream *st) -{ - if (atomic_dec_and_test(&st->ref_count)) { - oz_dbg(ON, "Stream destroyed\n"); - kfree(st); - } -} - -/* - * Precondition: Element buffer lock must be held. - * If this function fails the caller is responsible for deallocating the elt - * info structure. - */ -int oz_queue_elt_info(struct oz_elt_buf *buf, u8 isoc, u8 id, - struct oz_elt_info *ei) -{ - struct oz_elt_stream *st = NULL; - struct list_head *e; - - if (id) { - list_for_each(e, &buf->stream_list) { - st = list_entry(e, struct oz_elt_stream, link); - if (st->id == id) - break; - } - if (e == &buf->stream_list) { - /* Stream specified but stream not known so fail. - * Caller deallocates element info. */ - return -1; - } - } - if (st) { - /* If this is an ISOC fixed element that needs a frame number - * then insert that now. Earlier we stored the unit count in - * this field. - */ - struct oz_isoc_fixed *body = (struct oz_isoc_fixed *) - &ei->data[sizeof(struct oz_elt)]; - if ((body->app_id == OZ_APPID_USB) && (body->type - == OZ_USB_ENDPOINT_DATA) && - (body->format == OZ_DATA_F_ISOC_FIXED)) { - u8 unit_count = body->frame_number; - - body->frame_number = st->frame_number; - st->frame_number += unit_count; - } - /* Claim stream and update accounts */ - oz_elt_stream_get(st); - ei->stream = st; - st->buf_count += ei->length; - /* Add to list in stream. */ - list_add_tail(&ei->link, &st->elt_list); - oz_dbg(STREAM, "Stream up: %d %d\n", st->buf_count, ei->length); - /* Check if we have too much buffered for this stream. If so - * start dropping elements until we are back in bounds. - */ - while ((st->buf_count > st->max_buf_count) && - !list_empty(&st->elt_list)) { - struct oz_elt_info *ei2 = - list_first_entry(&st->elt_list, - struct oz_elt_info, link); - list_del_init(&ei2->link); - list_del_init(&ei2->link_order); - st->buf_count -= ei2->length; - oz_elt_info_free(buf, ei2); - oz_elt_stream_put(st); - } - } - list_add_tail(&ei->link_order, isoc ? - &buf->isoc_list : &buf->order_list); - return 0; -} - -int oz_select_elts_for_tx(struct oz_elt_buf *buf, u8 isoc, unsigned *len, - unsigned max_len, struct list_head *list) -{ - int count = 0; - struct list_head *el; - struct oz_elt_info *ei, *n; - - spin_lock_bh(&buf->lock); - if (isoc) - el = &buf->isoc_list; - else - el = &buf->order_list; - - list_for_each_entry_safe(ei, n, el, link_order) { - if ((*len + ei->length) <= max_len) { - struct oz_app_hdr *app_hdr = (struct oz_app_hdr *) - &ei->data[sizeof(struct oz_elt)]; - app_hdr->elt_seq_num = buf->tx_seq_num[ei->app_id]++; - if (buf->tx_seq_num[ei->app_id] == 0) - buf->tx_seq_num[ei->app_id] = 1; - *len += ei->length; - list_del(&ei->link); - list_del(&ei->link_order); - if (ei->stream) { - ei->stream->buf_count -= ei->length; - oz_dbg(STREAM, "Stream down: %d %d\n", - ei->stream->buf_count, ei->length); - oz_elt_stream_put(ei->stream); - ei->stream = NULL; - } - INIT_LIST_HEAD(&ei->link_order); - list_add_tail(&ei->link, list); - count++; - } else { - break; - } - } - spin_unlock_bh(&buf->lock); - return count; -} - -int oz_are_elts_available(struct oz_elt_buf *buf) -{ - return !list_empty(&buf->order_list); -} diff --git a/drivers/staging/ozwpan/ozeltbuf.h b/drivers/staging/ozwpan/ozeltbuf.h deleted file mode 100644 index f09f5fe3ffbe..000000000000 --- a/drivers/staging/ozwpan/ozeltbuf.h +++ /dev/null @@ -1,65 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#ifndef _OZELTBUF_H -#define _OZELTBUF_H - -#include "ozprotocol.h" - -/*----------------------------------------------------------------------------- - */ -struct oz_pd; -typedef void (*oz_elt_callback_t)(struct oz_pd *pd, long context); - -struct oz_elt_stream { - struct list_head link; - struct list_head elt_list; - atomic_t ref_count; - unsigned buf_count; - unsigned max_buf_count; - u8 frame_number; - u8 id; -}; - -#define OZ_MAX_ELT_PAYLOAD 255 -struct oz_elt_info { - struct list_head link; - struct list_head link_order; - u8 flags; - u8 app_id; - oz_elt_callback_t callback; - long context; - struct oz_elt_stream *stream; - u8 data[sizeof(struct oz_elt) + OZ_MAX_ELT_PAYLOAD]; - int length; -}; -/* Flags values */ -#define OZ_EI_F_MARKED 0x1 - -struct oz_elt_buf { - spinlock_t lock; - struct list_head stream_list; - struct list_head order_list; - struct list_head isoc_list; - u8 tx_seq_num[OZ_NB_APPS]; -}; - -void oz_elt_buf_init(struct oz_elt_buf *buf); -void oz_elt_buf_term(struct oz_elt_buf *buf); -struct oz_elt_info *oz_elt_info_alloc(struct oz_elt_buf *buf); -void oz_elt_info_free(struct oz_elt_buf *buf, struct oz_elt_info *ei); -void oz_elt_info_free_chain(struct oz_elt_buf *buf, struct list_head *list); -int oz_elt_stream_create(struct oz_elt_buf *buf, u8 id, int max_buf_count); -int oz_elt_stream_delete(struct oz_elt_buf *buf, u8 id); -void oz_elt_stream_get(struct oz_elt_stream *st); -void oz_elt_stream_put(struct oz_elt_stream *st); -int oz_queue_elt_info(struct oz_elt_buf *buf, u8 isoc, u8 id, - struct oz_elt_info *ei); -int oz_select_elts_for_tx(struct oz_elt_buf *buf, u8 isoc, unsigned *len, - unsigned max_len, struct list_head *list); -int oz_are_elts_available(struct oz_elt_buf *buf); - -#endif /* _OZELTBUF_H */ - diff --git a/drivers/staging/ozwpan/ozhcd.c b/drivers/staging/ozwpan/ozhcd.c deleted file mode 100644 index 784b5ecfa849..000000000000 --- a/drivers/staging/ozwpan/ozhcd.c +++ /dev/null @@ -1,2301 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * - * This file provides the implementation of a USB host controller device that - * does not have any associated hardware. Instead the virtual device is - * connected to the WiFi network and emulates the operation of a USB hcd by - * receiving and sending network frames. - * Note: - * We take great pains to reduce the amount of code where interrupts need to be - * disabled and in this respect we are different from standard HCD's. In - * particular we don't want in_irq() code bleeding over to the protocol side of - * the driver. - * The troublesome functions are the urb enqueue and dequeue functions both of - * which can be called in_irq(). So for these functions we put the urbs into a - * queue and request a tasklet to process them. This means that a spinlock with - * interrupts disabled must be held for insertion and removal but most code is - * is in tasklet or soft irq context. The lock that protects this list is called - * the tasklet lock and serves the purpose of the 'HCD lock' which must be held - * when calling the following functions. - * usb_hcd_link_urb_to_ep() - * usb_hcd_unlink_urb_from_ep() - * usb_hcd_flush_endpoint() - * usb_hcd_check_unlink_urb() - * ----------------------------------------------------------------------------- - */ -#include -#include -#include -#include -#include "linux/usb/hcd.h" -#include -#include "ozdbg.h" -#include "ozusbif.h" -#include "ozurbparanoia.h" -#include "ozhcd.h" - -/* - * Number of units of buffering to capture for an isochronous IN endpoint before - * allowing data to be indicated up. - */ -#define OZ_IN_BUFFERING_UNITS 100 - -/* Name of our platform device. - */ -#define OZ_PLAT_DEV_NAME "ozwpan" - -/*EP0 timeout before ep0 request is again added to TX queue. (13*8 = 98mSec) - */ -#define EP0_TIMEOUT_COUNTER 13 - -/* Debounce time HCD driver should wait before unregistering. - */ -#define OZ_HUB_DEBOUNCE_TIMEOUT 1500 - -/* - * Used to link urbs together and also store some status information for each - * urb. - * A cache of these are kept in a pool to reduce number of calls to kmalloc. - */ -struct oz_urb_link { - struct list_head link; - struct urb *urb; - struct oz_port *port; - u8 req_id; - u8 ep_num; - unsigned submit_counter; -}; - -static struct kmem_cache *oz_urb_link_cache; - -/* Holds state information about a USB endpoint. - */ -#define OZ_EP_BUFFER_SIZE_ISOC (1024 * 24) -#define OZ_EP_BUFFER_SIZE_INT 512 -struct oz_endpoint { - struct list_head urb_list; /* List of oz_urb_link items. */ - struct list_head link; /* For isoc ep, links in to isoc - lists of oz_port. */ - struct timespec timestamp; - int credit; - int credit_ceiling; - u8 ep_num; - u8 attrib; - u8 *buffer; - int buffer_size; - int in_ix; - int out_ix; - int buffered_units; - unsigned flags; - int start_frame; -}; - -/* Bits in the flags field. */ -#define OZ_F_EP_BUFFERING 0x1 -#define OZ_F_EP_HAVE_STREAM 0x2 - -/* Holds state information about a USB interface. - */ -struct oz_interface { - unsigned ep_mask; - u8 alt; -}; - -/* Holds state information about an hcd port. - */ -#define OZ_NB_ENDPOINTS 16 -struct oz_port { - unsigned flags; - unsigned status; - void *hpd; - struct oz_hcd *ozhcd; - spinlock_t port_lock; - u8 bus_addr; - u8 next_req_id; - u8 config_num; - int num_iface; - struct oz_interface *iface; - struct oz_endpoint *out_ep[OZ_NB_ENDPOINTS]; - struct oz_endpoint *in_ep[OZ_NB_ENDPOINTS]; - struct list_head isoc_out_ep; - struct list_head isoc_in_ep; -}; - -#define OZ_PORT_F_PRESENT 0x1 -#define OZ_PORT_F_CHANGED 0x2 -#define OZ_PORT_F_DYING 0x4 - -/* Data structure in the private context area of struct usb_hcd. - */ -#define OZ_NB_PORTS 8 -struct oz_hcd { - spinlock_t hcd_lock; - struct list_head urb_pending_list; - struct list_head urb_cancel_list; - struct list_head orphanage; - int conn_port; /* Port that is currently connecting, -1 if none.*/ - struct oz_port ports[OZ_NB_PORTS]; - uint flags; - struct usb_hcd *hcd; -}; - -/* Bits in flags field. - */ -#define OZ_HDC_F_SUSPENDED 0x1 - -/* - * Static function prototypes. - */ -static int oz_hcd_start(struct usb_hcd *hcd); -static void oz_hcd_stop(struct usb_hcd *hcd); -static void oz_hcd_shutdown(struct usb_hcd *hcd); -static int oz_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags); -static int oz_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); -static void oz_hcd_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *ep); -static void oz_hcd_endpoint_reset(struct usb_hcd *hcd, - struct usb_host_endpoint *ep); -static int oz_hcd_get_frame_number(struct usb_hcd *hcd); -static int oz_hcd_hub_status_data(struct usb_hcd *hcd, char *buf); -static int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue, - u16 windex, char *buf, u16 wlength); -static int oz_hcd_bus_suspend(struct usb_hcd *hcd); -static int oz_hcd_bus_resume(struct usb_hcd *hcd); -static int oz_plat_probe(struct platform_device *dev); -static int oz_plat_remove(struct platform_device *dev); -static void oz_plat_shutdown(struct platform_device *dev); -static int oz_plat_suspend(struct platform_device *dev, pm_message_t msg); -static int oz_plat_resume(struct platform_device *dev); -static void oz_urb_process_tasklet(unsigned long unused); -static int oz_build_endpoints_for_config(struct usb_hcd *hcd, - struct oz_port *port, struct usb_host_config *config, - gfp_t mem_flags); -static void oz_clean_endpoints_for_config(struct usb_hcd *hcd, - struct oz_port *port); -static int oz_build_endpoints_for_interface(struct usb_hcd *hcd, - struct oz_port *port, - struct usb_host_interface *intf, gfp_t mem_flags); -static void oz_clean_endpoints_for_interface(struct usb_hcd *hcd, - struct oz_port *port, int if_ix); -static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, - gfp_t mem_flags); -static struct oz_urb_link *oz_remove_urb(struct oz_endpoint *ep, - struct urb *urb); -static void oz_hcd_clear_orphanage(struct oz_hcd *ozhcd, int status); - -/* - * Static external variables. - */ -static struct platform_device *g_plat_dev; -static struct oz_hcd *g_ozhcd; -static DEFINE_SPINLOCK(g_hcdlock); /* Guards g_ozhcd. */ -static const char g_hcd_name[] = "Ozmo WPAN"; -static DEFINE_SPINLOCK(g_tasklet_lock); -static struct tasklet_struct g_urb_process_tasklet; -static struct tasklet_struct g_urb_cancel_tasklet; -static atomic_t g_pending_urbs = ATOMIC_INIT(0); -static atomic_t g_usb_frame_number = ATOMIC_INIT(0); -static const struct hc_driver g_oz_hc_drv = { - .description = g_hcd_name, - .product_desc = "Ozmo Devices WPAN", - .hcd_priv_size = sizeof(struct oz_hcd), - .flags = HCD_USB11, - .start = oz_hcd_start, - .stop = oz_hcd_stop, - .shutdown = oz_hcd_shutdown, - .urb_enqueue = oz_hcd_urb_enqueue, - .urb_dequeue = oz_hcd_urb_dequeue, - .endpoint_disable = oz_hcd_endpoint_disable, - .endpoint_reset = oz_hcd_endpoint_reset, - .get_frame_number = oz_hcd_get_frame_number, - .hub_status_data = oz_hcd_hub_status_data, - .hub_control = oz_hcd_hub_control, - .bus_suspend = oz_hcd_bus_suspend, - .bus_resume = oz_hcd_bus_resume, -}; - -static struct platform_driver g_oz_plat_drv = { - .probe = oz_plat_probe, - .remove = oz_plat_remove, - .shutdown = oz_plat_shutdown, - .suspend = oz_plat_suspend, - .resume = oz_plat_resume, - .driver = { - .name = OZ_PLAT_DEV_NAME, - }, -}; - -/* - * Gets our private context area (which is of type struct oz_hcd) from the - * usb_hcd structure. - * Context: any - */ -static inline struct oz_hcd *oz_hcd_private(struct usb_hcd *hcd) -{ - return (struct oz_hcd *)hcd->hcd_priv; -} - -/* - * Searches list of ports to find the index of the one with a specified USB - * bus address. If none of the ports has the bus address then the connection - * port is returned, if there is one or -1 otherwise. - * Context: any - */ -static int oz_get_port_from_addr(struct oz_hcd *ozhcd, u8 bus_addr) -{ - int i; - - for (i = 0; i < OZ_NB_PORTS; i++) { - if (ozhcd->ports[i].bus_addr == bus_addr) - return i; - } - return ozhcd->conn_port; -} - -/* - * Context: any - */ -static struct oz_urb_link *oz_alloc_urb_link(void) -{ - return kmem_cache_alloc(oz_urb_link_cache, GFP_ATOMIC); -} - -/* - * Context: any - */ -static void oz_free_urb_link(struct oz_urb_link *urbl) -{ - if (!urbl) - return; - - kmem_cache_free(oz_urb_link_cache, urbl); -} - -/* - * Allocates endpoint structure and optionally a buffer. If a buffer is - * allocated it immediately follows the endpoint structure. - * Context: softirq - */ -static struct oz_endpoint *oz_ep_alloc(int buffer_size, gfp_t mem_flags) -{ - struct oz_endpoint *ep; - - ep = kzalloc(sizeof(struct oz_endpoint)+buffer_size, mem_flags); - if (!ep) - return NULL; - - INIT_LIST_HEAD(&ep->urb_list); - INIT_LIST_HEAD(&ep->link); - ep->credit = -1; - if (buffer_size) { - ep->buffer_size = buffer_size; - ep->buffer = (u8 *)(ep+1); - } - - return ep; -} - -/* - * Pre-condition: Must be called with g_tasklet_lock held and interrupts - * disabled. - * Context: softirq or process - */ -static struct oz_urb_link *oz_uncancel_urb(struct oz_hcd *ozhcd, - struct urb *urb) -{ - struct oz_urb_link *urbl; - - list_for_each_entry(urbl, &ozhcd->urb_cancel_list, link) { - if (urb == urbl->urb) { - list_del_init(&urbl->link); - return urbl; - } - } - return NULL; -} - -/* - * This is called when we have finished processing an urb. It unlinks it from - * the ep and returns it to the core. - * Context: softirq or process - */ -static void oz_complete_urb(struct usb_hcd *hcd, struct urb *urb, - int status) -{ - struct oz_hcd *ozhcd = oz_hcd_private(hcd); - unsigned long irq_state; - struct oz_urb_link *cancel_urbl; - - spin_lock_irqsave(&g_tasklet_lock, irq_state); - usb_hcd_unlink_urb_from_ep(hcd, urb); - /* Clear hcpriv which will prevent it being put in the cancel list - * in the event that an attempt is made to cancel it. - */ - urb->hcpriv = NULL; - /* Walk the cancel list in case the urb is already sitting there. - * Since we process the cancel list in a tasklet rather than in - * the dequeue function this could happen. - */ - cancel_urbl = oz_uncancel_urb(ozhcd, urb); - /* Note: we release lock but do not enable local irqs. - * It appears that usb_hcd_giveback_urb() expects irqs to be disabled, - * or at least other host controllers disable interrupts at this point - * so we do the same. We must, however, release the lock otherwise a - * deadlock will occur if an urb is submitted to our driver in the urb - * completion function. Because we disable interrupts it is possible - * that the urb_enqueue function can be called with them disabled. - */ - spin_unlock(&g_tasklet_lock); - if (oz_forget_urb(urb)) { - oz_dbg(ON, "ERROR Unknown URB %p\n", urb); - } else { - atomic_dec(&g_pending_urbs); - usb_hcd_giveback_urb(hcd, urb, status); - } - spin_lock(&g_tasklet_lock); - spin_unlock_irqrestore(&g_tasklet_lock, irq_state); - oz_free_urb_link(cancel_urbl); -} - -/* - * Deallocates an endpoint including deallocating any associated stream and - * returning any queued urbs to the core. - * Context: softirq - */ -static void oz_ep_free(struct oz_port *port, struct oz_endpoint *ep) -{ - if (port) { - LIST_HEAD(list); - struct oz_hcd *ozhcd = port->ozhcd; - - if (ep->flags & OZ_F_EP_HAVE_STREAM) - oz_usb_stream_delete(port->hpd, ep->ep_num); - /* Transfer URBs to the orphanage while we hold the lock. */ - spin_lock_bh(&ozhcd->hcd_lock); - /* Note: this works even if ep->urb_list is empty.*/ - list_replace_init(&ep->urb_list, &list); - /* Put the URBs in the orphanage. */ - list_splice_tail(&list, &ozhcd->orphanage); - spin_unlock_bh(&ozhcd->hcd_lock); - } - oz_dbg(ON, "Freeing endpoint memory\n"); - kfree(ep); -} - -/* - * Context: softirq - */ -static void oz_complete_buffered_urb(struct oz_port *port, - struct oz_endpoint *ep, - struct urb *urb) -{ - int data_len, available_space, copy_len; - - data_len = ep->buffer[ep->out_ix]; - if (data_len <= urb->transfer_buffer_length) - available_space = data_len; - else - available_space = urb->transfer_buffer_length; - - if (++ep->out_ix == ep->buffer_size) - ep->out_ix = 0; - copy_len = ep->buffer_size - ep->out_ix; - if (copy_len >= available_space) - copy_len = available_space; - memcpy(urb->transfer_buffer, &ep->buffer[ep->out_ix], copy_len); - - if (copy_len < available_space) { - memcpy((urb->transfer_buffer + copy_len), ep->buffer, - (available_space - copy_len)); - ep->out_ix = available_space - copy_len; - } else { - ep->out_ix += copy_len; - } - urb->actual_length = available_space; - if (ep->out_ix == ep->buffer_size) - ep->out_ix = 0; - - ep->buffered_units--; - oz_dbg(ON, "Trying to give back buffered frame of size=%d\n", - available_space); - oz_complete_urb(port->ozhcd->hcd, urb, 0); -} - -/* - * Context: softirq - */ -static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir, - struct urb *urb, u8 req_id) -{ - struct oz_urb_link *urbl; - struct oz_endpoint *ep = NULL; - int err = 0; - - if (ep_addr >= OZ_NB_ENDPOINTS) { - oz_dbg(ON, "%s: Invalid endpoint number\n", __func__); - return -EINVAL; - } - urbl = oz_alloc_urb_link(); - if (!urbl) - return -ENOMEM; - urbl->submit_counter = 0; - urbl->urb = urb; - urbl->req_id = req_id; - urbl->ep_num = ep_addr; - /* Hold lock while we insert the URB into the list within the - * endpoint structure. - */ - spin_lock_bh(&port->ozhcd->hcd_lock); - /* If the urb has been unlinked while out of any list then - * complete it now. - */ - if (urb->unlinked) { - spin_unlock_bh(&port->ozhcd->hcd_lock); - oz_dbg(ON, "urb %p unlinked so complete immediately\n", urb); - oz_complete_urb(port->ozhcd->hcd, urb, 0); - oz_free_urb_link(urbl); - return 0; - } - - if (in_dir) - ep = port->in_ep[ep_addr]; - else - ep = port->out_ep[ep_addr]; - if (!ep) { - err = -ENOMEM; - goto out; - } - - /*For interrupt endpoint check for buffered data - * & complete urb - */ - if (((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) - && ep->buffered_units > 0) { - oz_free_urb_link(urbl); - spin_unlock_bh(&port->ozhcd->hcd_lock); - oz_complete_buffered_urb(port, ep, urb); - return 0; - } - - if (port->hpd) { - list_add_tail(&urbl->link, &ep->urb_list); - if (!in_dir && ep_addr && (ep->credit < 0)) { - getrawmonotonic(&ep->timestamp); - ep->credit = 0; - } - } else { - err = -EPIPE; - } -out: - spin_unlock_bh(&port->ozhcd->hcd_lock); - if (err) - oz_free_urb_link(urbl); - return err; -} - -/* - * Removes an urb from the queue in the endpoint. - * Returns 0 if it is found and -EIDRM otherwise. - * Context: softirq - */ -static int oz_dequeue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir, - struct urb *urb) -{ - struct oz_urb_link *urbl = NULL; - struct oz_endpoint *ep; - - spin_lock_bh(&port->ozhcd->hcd_lock); - if (in_dir) - ep = port->in_ep[ep_addr]; - else - ep = port->out_ep[ep_addr]; - if (ep) { - struct list_head *e; - - list_for_each(e, &ep->urb_list) { - urbl = list_entry(e, struct oz_urb_link, link); - if (urbl->urb == urb) { - list_del_init(e); - break; - } - urbl = NULL; - } - } - spin_unlock_bh(&port->ozhcd->hcd_lock); - oz_free_urb_link(urbl); - return urbl ? 0 : -EIDRM; -} - -/* - * Finds an urb given its request id. - * Context: softirq - */ -static struct urb *oz_find_urb_by_id(struct oz_port *port, int ep_ix, - u8 req_id) -{ - struct oz_hcd *ozhcd = port->ozhcd; - struct urb *urb = NULL; - struct oz_urb_link *urbl; - struct oz_endpoint *ep; - - spin_lock_bh(&ozhcd->hcd_lock); - ep = port->out_ep[ep_ix]; - if (ep) { - struct list_head *e; - - list_for_each(e, &ep->urb_list) { - urbl = list_entry(e, struct oz_urb_link, link); - if (urbl->req_id == req_id) { - urb = urbl->urb; - list_del_init(e); - break; - } - } - } - spin_unlock_bh(&ozhcd->hcd_lock); - /* If urb is non-zero then we we must have an urb link to delete. - */ - if (urb) - oz_free_urb_link(urbl); - return urb; -} - -/* - * Pre-condition: Port lock must be held. - * Context: softirq - */ -static void oz_acquire_port(struct oz_port *port, void *hpd) -{ - INIT_LIST_HEAD(&port->isoc_out_ep); - INIT_LIST_HEAD(&port->isoc_in_ep); - port->flags |= OZ_PORT_F_PRESENT | OZ_PORT_F_CHANGED; - port->status |= USB_PORT_STAT_CONNECTION | - (USB_PORT_STAT_C_CONNECTION << 16); - oz_usb_get(hpd); - port->hpd = hpd; -} - -/* - * Context: softirq - */ -static struct oz_hcd *oz_hcd_claim(void) -{ - struct oz_hcd *ozhcd; - - spin_lock_bh(&g_hcdlock); - ozhcd = g_ozhcd; - if (ozhcd) - usb_get_hcd(ozhcd->hcd); - spin_unlock_bh(&g_hcdlock); - return ozhcd; -} - -/* - * Context: softirq - */ -static inline void oz_hcd_put(struct oz_hcd *ozhcd) -{ - if (ozhcd) - usb_put_hcd(ozhcd->hcd); -} - -/* - * This is called by the protocol handler to notify that a PD has arrived. - * We allocate a port to associate with the PD and create a structure for - * endpoint 0. This port is made the connection port. - * In the event that one of the other port is already a connection port then - * we fail. - * TODO We should be able to do better than fail and should be able remember - * that this port needs configuring and make it the connection port once the - * current connection port has been assigned an address. Collisions here are - * probably very rare indeed. - * Context: softirq - */ -struct oz_port *oz_hcd_pd_arrived(void *hpd) -{ - int i; - struct oz_port *hport; - struct oz_hcd *ozhcd; - struct oz_endpoint *ep; - - ozhcd = oz_hcd_claim(); - if (!ozhcd) - return NULL; - /* Allocate an endpoint object in advance (before holding hcd lock) to - * use for out endpoint 0. - */ - ep = oz_ep_alloc(0, GFP_ATOMIC); - if (!ep) - goto err_put; - - spin_lock_bh(&ozhcd->hcd_lock); - if (ozhcd->conn_port >= 0) - goto err_unlock; - - for (i = 0; i < OZ_NB_PORTS; i++) { - struct oz_port *port = &ozhcd->ports[i]; - - spin_lock(&port->port_lock); - if (!(port->flags & (OZ_PORT_F_PRESENT | OZ_PORT_F_CHANGED))) { - oz_acquire_port(port, hpd); - spin_unlock(&port->port_lock); - break; - } - spin_unlock(&port->port_lock); - } - if (i == OZ_NB_PORTS) - goto err_unlock; - - ozhcd->conn_port = i; - hport = &ozhcd->ports[i]; - hport->out_ep[0] = ep; - spin_unlock_bh(&ozhcd->hcd_lock); - if (ozhcd->flags & OZ_HDC_F_SUSPENDED) - usb_hcd_resume_root_hub(ozhcd->hcd); - usb_hcd_poll_rh_status(ozhcd->hcd); - oz_hcd_put(ozhcd); - - return hport; - -err_unlock: - spin_unlock_bh(&ozhcd->hcd_lock); - oz_ep_free(NULL, ep); -err_put: - oz_hcd_put(ozhcd); - return NULL; -} - -/* - * This is called by the protocol handler to notify that the PD has gone away. - * We need to deallocate all resources and then request that the root hub is - * polled. We release the reference we hold on the PD. - * Context: softirq - */ -void oz_hcd_pd_departed(struct oz_port *port) -{ - struct oz_hcd *ozhcd; - void *hpd; - struct oz_endpoint *ep = NULL; - - if (port == NULL) { - oz_dbg(ON, "%s: port = 0\n", __func__); - return; - } - ozhcd = port->ozhcd; - if (ozhcd == NULL) - return; - /* Check if this is the connection port - if so clear it. - */ - spin_lock_bh(&ozhcd->hcd_lock); - if ((ozhcd->conn_port >= 0) && - (port == &ozhcd->ports[ozhcd->conn_port])) { - oz_dbg(ON, "Clearing conn_port\n"); - ozhcd->conn_port = -1; - } - spin_lock(&port->port_lock); - port->flags |= OZ_PORT_F_DYING; - spin_unlock(&port->port_lock); - spin_unlock_bh(&ozhcd->hcd_lock); - - oz_clean_endpoints_for_config(ozhcd->hcd, port); - spin_lock_bh(&port->port_lock); - hpd = port->hpd; - port->hpd = NULL; - port->bus_addr = 0xff; - port->config_num = 0; - port->flags &= ~(OZ_PORT_F_PRESENT | OZ_PORT_F_DYING); - port->flags |= OZ_PORT_F_CHANGED; - port->status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE); - port->status |= (USB_PORT_STAT_C_CONNECTION << 16); - /* If there is an endpont 0 then clear the pointer while we hold - * the spinlock be we deallocate it after releasing the lock. - */ - if (port->out_ep[0]) { - ep = port->out_ep[0]; - port->out_ep[0] = NULL; - } - spin_unlock_bh(&port->port_lock); - if (ep) - oz_ep_free(port, ep); - usb_hcd_poll_rh_status(ozhcd->hcd); - oz_usb_put(hpd); -} - -/* - * Context: softirq - */ -void oz_hcd_pd_reset(void *hpd, void *hport) -{ - /* Cleanup the current configuration and report reset to the core. - */ - struct oz_port *port = hport; - struct oz_hcd *ozhcd = port->ozhcd; - - oz_dbg(ON, "PD Reset\n"); - spin_lock_bh(&port->port_lock); - port->flags |= OZ_PORT_F_CHANGED; - port->status |= USB_PORT_STAT_RESET; - port->status |= (USB_PORT_STAT_C_RESET << 16); - spin_unlock_bh(&port->port_lock); - oz_clean_endpoints_for_config(ozhcd->hcd, port); - usb_hcd_poll_rh_status(ozhcd->hcd); -} - -/* - * Context: softirq - */ -void oz_hcd_get_desc_cnf(void *hport, u8 req_id, u8 status, const u8 *desc, - u8 length, u16 offset, u16 total_size) -{ - struct oz_port *port = hport; - struct urb *urb; - int err = 0; - - oz_dbg(ON, "oz_hcd_get_desc_cnf length = %d offs = %d tot_size = %d\n", - length, offset, total_size); - urb = oz_find_urb_by_id(port, 0, req_id); - if (!urb) - return; - if (status == 0) { - unsigned int copy_len; - unsigned int required_size = urb->transfer_buffer_length; - - if (required_size > total_size) - required_size = total_size; - copy_len = required_size-offset; - if (length <= copy_len) - copy_len = length; - memcpy(urb->transfer_buffer+offset, desc, copy_len); - offset += copy_len; - if (offset < required_size) { - struct usb_ctrlrequest *setup = - (struct usb_ctrlrequest *)urb->setup_packet; - unsigned wvalue = le16_to_cpu(setup->wValue); - - if (oz_enqueue_ep_urb(port, 0, 0, urb, req_id)) - err = -ENOMEM; - else if (oz_usb_get_desc_req(port->hpd, req_id, - setup->bRequestType, (u8)(wvalue>>8), - (u8)wvalue, setup->wIndex, offset, - required_size-offset)) { - oz_dequeue_ep_urb(port, 0, 0, urb); - err = -ENOMEM; - } - if (err == 0) - return; - } - } - urb->actual_length = total_size; - oz_complete_urb(port->ozhcd->hcd, urb, 0); -} - -/* - * Context: softirq - */ -static void oz_display_conf_type(u8 t) -{ - switch (t) { - case USB_REQ_GET_STATUS: - oz_dbg(ON, "USB_REQ_GET_STATUS - cnf\n"); - break; - case USB_REQ_CLEAR_FEATURE: - oz_dbg(ON, "USB_REQ_CLEAR_FEATURE - cnf\n"); - break; - case USB_REQ_SET_FEATURE: - oz_dbg(ON, "USB_REQ_SET_FEATURE - cnf\n"); - break; - case USB_REQ_SET_ADDRESS: - oz_dbg(ON, "USB_REQ_SET_ADDRESS - cnf\n"); - break; - case USB_REQ_GET_DESCRIPTOR: - oz_dbg(ON, "USB_REQ_GET_DESCRIPTOR - cnf\n"); - break; - case USB_REQ_SET_DESCRIPTOR: - oz_dbg(ON, "USB_REQ_SET_DESCRIPTOR - cnf\n"); - break; - case USB_REQ_GET_CONFIGURATION: - oz_dbg(ON, "USB_REQ_GET_CONFIGURATION - cnf\n"); - break; - case USB_REQ_SET_CONFIGURATION: - oz_dbg(ON, "USB_REQ_SET_CONFIGURATION - cnf\n"); - break; - case USB_REQ_GET_INTERFACE: - oz_dbg(ON, "USB_REQ_GET_INTERFACE - cnf\n"); - break; - case USB_REQ_SET_INTERFACE: - oz_dbg(ON, "USB_REQ_SET_INTERFACE - cnf\n"); - break; - case USB_REQ_SYNCH_FRAME: - oz_dbg(ON, "USB_REQ_SYNCH_FRAME - cnf\n"); - break; - } -} - -/* - * Context: softirq - */ -static void oz_hcd_complete_set_config(struct oz_port *port, struct urb *urb, - u8 rcode, u8 config_num) -{ - int rc = 0; - struct usb_hcd *hcd = port->ozhcd->hcd; - - if (rcode == 0) { - port->config_num = config_num; - oz_clean_endpoints_for_config(hcd, port); - if (oz_build_endpoints_for_config(hcd, port, - &urb->dev->config[port->config_num-1], GFP_ATOMIC)) { - rc = -ENOMEM; - } - } else { - rc = -ENOMEM; - } - oz_complete_urb(hcd, urb, rc); -} - -/* - * Context: softirq - */ -static void oz_hcd_complete_set_interface(struct oz_port *port, struct urb *urb, - u8 rcode, u8 if_num, u8 alt) -{ - struct usb_hcd *hcd = port->ozhcd->hcd; - int rc = 0; - - if ((rcode == 0) && (port->config_num > 0)) { - struct usb_host_config *config; - struct usb_host_interface *intf; - - oz_dbg(ON, "Set interface %d alt %d\n", if_num, alt); - oz_clean_endpoints_for_interface(hcd, port, if_num); - config = &urb->dev->config[port->config_num-1]; - intf = &config->intf_cache[if_num]->altsetting[alt]; - if (oz_build_endpoints_for_interface(hcd, port, intf, - GFP_ATOMIC)) - rc = -ENOMEM; - else - port->iface[if_num].alt = alt; - } else { - rc = -ENOMEM; - } - oz_complete_urb(hcd, urb, rc); -} - -/* - * Context: softirq - */ -void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, const u8 *data, - int data_len) -{ - struct oz_port *port = hport; - struct urb *urb; - struct usb_ctrlrequest *setup; - struct usb_hcd *hcd = port->ozhcd->hcd; - unsigned windex; - unsigned wvalue; - - oz_dbg(ON, "oz_hcd_control_cnf rcode=%u len=%d\n", rcode, data_len); - urb = oz_find_urb_by_id(port, 0, req_id); - if (!urb) { - oz_dbg(ON, "URB not found\n"); - return; - } - setup = (struct usb_ctrlrequest *)urb->setup_packet; - windex = le16_to_cpu(setup->wIndex); - wvalue = le16_to_cpu(setup->wValue); - if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - /* Standard requests */ - oz_display_conf_type(setup->bRequest); - switch (setup->bRequest) { - case USB_REQ_SET_CONFIGURATION: - oz_hcd_complete_set_config(port, urb, rcode, - (u8)wvalue); - break; - case USB_REQ_SET_INTERFACE: - oz_hcd_complete_set_interface(port, urb, rcode, - (u8)windex, (u8)wvalue); - break; - default: - oz_complete_urb(hcd, urb, 0); - } - - } else { - int copy_len; - - oz_dbg(ON, "VENDOR-CLASS - cnf\n"); - if (data_len) { - if (data_len <= urb->transfer_buffer_length) - copy_len = data_len; - else - copy_len = urb->transfer_buffer_length; - memcpy(urb->transfer_buffer, data, copy_len); - urb->actual_length = copy_len; - } - oz_complete_urb(hcd, urb, 0); - } -} - -/* - * Context: softirq-serialized - */ -static int oz_hcd_buffer_data(struct oz_endpoint *ep, const u8 *data, - int data_len) -{ - int space; - int copy_len; - - if (!ep->buffer) - return -1; - space = ep->out_ix-ep->in_ix-1; - if (space < 0) - space += ep->buffer_size; - if (space < (data_len+1)) { - oz_dbg(ON, "Buffer full\n"); - return -1; - } - ep->buffer[ep->in_ix] = (u8)data_len; - if (++ep->in_ix == ep->buffer_size) - ep->in_ix = 0; - copy_len = ep->buffer_size - ep->in_ix; - if (copy_len > data_len) - copy_len = data_len; - memcpy(&ep->buffer[ep->in_ix], data, copy_len); - - if (copy_len < data_len) { - memcpy(ep->buffer, data+copy_len, data_len-copy_len); - ep->in_ix = data_len-copy_len; - } else { - ep->in_ix += copy_len; - } - if (ep->in_ix == ep->buffer_size) - ep->in_ix = 0; - ep->buffered_units++; - return 0; -} - -/* - * Context: softirq-serialized - */ -void oz_hcd_data_ind(void *hport, u8 endpoint, const u8 *data, int data_len) -{ - struct oz_port *port = (struct oz_port *)hport; - struct oz_endpoint *ep; - struct oz_hcd *ozhcd = port->ozhcd; - - spin_lock_bh(&ozhcd->hcd_lock); - ep = port->in_ep[endpoint & USB_ENDPOINT_NUMBER_MASK]; - if (ep == NULL) - goto done; - switch (ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_INT: - case USB_ENDPOINT_XFER_BULK: - if (!list_empty(&ep->urb_list)) { - struct oz_urb_link *urbl = - list_first_entry(&ep->urb_list, - struct oz_urb_link, link); - struct urb *urb; - int copy_len; - - list_del_init(&urbl->link); - spin_unlock_bh(&ozhcd->hcd_lock); - urb = urbl->urb; - oz_free_urb_link(urbl); - if (data_len <= urb->transfer_buffer_length) - copy_len = data_len; - else - copy_len = urb->transfer_buffer_length; - memcpy(urb->transfer_buffer, data, copy_len); - urb->actual_length = copy_len; - oz_complete_urb(port->ozhcd->hcd, urb, 0); - return; - } - oz_dbg(ON, "buffering frame as URB is not available\n"); - oz_hcd_buffer_data(ep, data, data_len); - break; - case USB_ENDPOINT_XFER_ISOC: - oz_hcd_buffer_data(ep, data, data_len); - break; - } -done: - spin_unlock_bh(&ozhcd->hcd_lock); -} - -/* - * Context: unknown - */ -static inline int oz_usb_get_frame_number(void) -{ - return atomic_inc_return(&g_usb_frame_number); -} - -/* - * Context: softirq - */ -int oz_hcd_heartbeat(void *hport) -{ - int rc = 0; - struct oz_port *port = hport; - struct oz_hcd *ozhcd = port->ozhcd; - struct oz_urb_link *urbl, *n; - LIST_HEAD(xfr_list); - struct urb *urb; - struct oz_endpoint *ep; - struct timespec ts, delta; - - getrawmonotonic(&ts); - /* Check the OUT isoc endpoints to see if any URB data can be sent. - */ - spin_lock_bh(&ozhcd->hcd_lock); - list_for_each_entry(ep, &port->isoc_out_ep, link) { - if (ep->credit < 0) - continue; - delta = timespec_sub(ts, ep->timestamp); - ep->credit += div_u64(timespec_to_ns(&delta), NSEC_PER_MSEC); - if (ep->credit > ep->credit_ceiling) - ep->credit = ep->credit_ceiling; - ep->timestamp = ts; - while (ep->credit && !list_empty(&ep->urb_list)) { - urbl = list_first_entry(&ep->urb_list, - struct oz_urb_link, link); - urb = urbl->urb; - if ((ep->credit + 1) < urb->number_of_packets) - break; - ep->credit -= urb->number_of_packets; - if (ep->credit < 0) - ep->credit = 0; - list_move_tail(&urbl->link, &xfr_list); - } - } - spin_unlock_bh(&ozhcd->hcd_lock); - /* Send to PD and complete URBs. - */ - list_for_each_entry_safe(urbl, n, &xfr_list, link) { - urb = urbl->urb; - list_del_init(&urbl->link); - urb->error_count = 0; - urb->start_frame = oz_usb_get_frame_number(); - oz_usb_send_isoc(port->hpd, urbl->ep_num, urb); - oz_free_urb_link(urbl); - oz_complete_urb(port->ozhcd->hcd, urb, 0); - } - /* Check the IN isoc endpoints to see if any URBs can be completed. - */ - spin_lock_bh(&ozhcd->hcd_lock); - list_for_each_entry(ep, &port->isoc_in_ep, link) { - if (ep->flags & OZ_F_EP_BUFFERING) { - if (ep->buffered_units >= OZ_IN_BUFFERING_UNITS) { - ep->flags &= ~OZ_F_EP_BUFFERING; - ep->credit = 0; - ep->timestamp = ts; - ep->start_frame = 0; - } - continue; - } - delta = timespec_sub(ts, ep->timestamp); - ep->credit += div_u64(timespec_to_ns(&delta), NSEC_PER_MSEC); - ep->timestamp = ts; - list_for_each_entry_safe(urbl, n, &ep->urb_list, link) { - struct urb *urb = urbl->urb; - int len = 0; - int copy_len; - int i; - - if (ep->credit < urb->number_of_packets) - break; - if (ep->buffered_units < urb->number_of_packets) - break; - urb->actual_length = 0; - for (i = 0; i < urb->number_of_packets; i++) { - len = ep->buffer[ep->out_ix]; - if (++ep->out_ix == ep->buffer_size) - ep->out_ix = 0; - copy_len = ep->buffer_size - ep->out_ix; - if (copy_len > len) - copy_len = len; - memcpy(urb->transfer_buffer, - &ep->buffer[ep->out_ix], copy_len); - if (copy_len < len) { - memcpy(urb->transfer_buffer+copy_len, - ep->buffer, len-copy_len); - ep->out_ix = len-copy_len; - } else - ep->out_ix += copy_len; - if (ep->out_ix == ep->buffer_size) - ep->out_ix = 0; - urb->iso_frame_desc[i].offset = - urb->actual_length; - urb->actual_length += len; - urb->iso_frame_desc[i].actual_length = len; - urb->iso_frame_desc[i].status = 0; - } - ep->buffered_units -= urb->number_of_packets; - urb->error_count = 0; - urb->start_frame = ep->start_frame; - ep->start_frame += urb->number_of_packets; - list_move_tail(&urbl->link, &xfr_list); - ep->credit -= urb->number_of_packets; - } - } - if (!list_empty(&port->isoc_out_ep) || !list_empty(&port->isoc_in_ep)) - rc = 1; - spin_unlock_bh(&ozhcd->hcd_lock); - /* Complete the filled URBs. - */ - list_for_each_entry_safe(urbl, n, &xfr_list, link) { - urb = urbl->urb; - list_del_init(&urbl->link); - oz_free_urb_link(urbl); - oz_complete_urb(port->ozhcd->hcd, urb, 0); - } - /* Check if there are any ep0 requests that have timed out. - * If so resent to PD. - */ - ep = port->out_ep[0]; - if (ep) { - spin_lock_bh(&ozhcd->hcd_lock); - list_for_each_entry_safe(urbl, n, &ep->urb_list, link) { - if (urbl->submit_counter > EP0_TIMEOUT_COUNTER) { - oz_dbg(ON, "Request 0x%p timeout\n", urbl->urb); - list_move_tail(&urbl->link, &xfr_list); - urbl->submit_counter = 0; - } else { - urbl->submit_counter++; - } - } - if (!list_empty(&ep->urb_list)) - rc = 1; - spin_unlock_bh(&ozhcd->hcd_lock); - list_for_each_entry_safe(urbl, n, &xfr_list, link) { - oz_dbg(ON, "Resending request to PD\n"); - oz_process_ep0_urb(ozhcd, urbl->urb, GFP_ATOMIC); - oz_free_urb_link(urbl); - } - } - return rc; -} - -/* - * Context: softirq - */ -static int oz_build_endpoints_for_interface(struct usb_hcd *hcd, - struct oz_port *port, - struct usb_host_interface *intf, gfp_t mem_flags) -{ - struct oz_hcd *ozhcd = port->ozhcd; - int i; - int if_ix = intf->desc.bInterfaceNumber; - int request_heartbeat = 0; - - oz_dbg(ON, "interface[%d] = %p\n", if_ix, intf); - if (if_ix >= port->num_iface || port->iface == NULL) - return -ENOMEM; - for (i = 0; i < intf->desc.bNumEndpoints; i++) { - struct usb_host_endpoint *hep = &intf->endpoint[i]; - u8 ep_addr = hep->desc.bEndpointAddress; - u8 ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; - struct oz_endpoint *ep; - int buffer_size = 0; - - oz_dbg(ON, "%d bEndpointAddress = %x\n", i, ep_addr); - if (ep_addr & USB_ENDPOINT_DIR_MASK) { - switch (hep->desc.bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_ISOC: - buffer_size = OZ_EP_BUFFER_SIZE_ISOC; - break; - case USB_ENDPOINT_XFER_INT: - buffer_size = OZ_EP_BUFFER_SIZE_INT; - break; - } - } - - ep = oz_ep_alloc(buffer_size, mem_flags); - if (!ep) { - oz_clean_endpoints_for_interface(hcd, port, if_ix); - return -ENOMEM; - } - ep->attrib = hep->desc.bmAttributes; - ep->ep_num = ep_num; - if ((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_ISOC) { - oz_dbg(ON, "wMaxPacketSize = %d\n", - usb_endpoint_maxp(&hep->desc)); - ep->credit_ceiling = 200; - if (ep_addr & USB_ENDPOINT_DIR_MASK) { - ep->flags |= OZ_F_EP_BUFFERING; - } else { - ep->flags |= OZ_F_EP_HAVE_STREAM; - if (oz_usb_stream_create(port->hpd, ep_num)) - ep->flags &= ~OZ_F_EP_HAVE_STREAM; - } - } - spin_lock_bh(&ozhcd->hcd_lock); - if (ep_addr & USB_ENDPOINT_DIR_MASK) { - port->in_ep[ep_num] = ep; - port->iface[if_ix].ep_mask |= - (1<<(ep_num+OZ_NB_ENDPOINTS)); - if ((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_ISOC) { - list_add_tail(&ep->link, &port->isoc_in_ep); - request_heartbeat = 1; - } - } else { - port->out_ep[ep_num] = ep; - port->iface[if_ix].ep_mask |= (1<attrib & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_ISOC) { - list_add_tail(&ep->link, &port->isoc_out_ep); - request_heartbeat = 1; - } - } - spin_unlock_bh(&ozhcd->hcd_lock); - if (request_heartbeat && port->hpd) - oz_usb_request_heartbeat(port->hpd); - } - return 0; -} - -/* - * Context: softirq - */ -static void oz_clean_endpoints_for_interface(struct usb_hcd *hcd, - struct oz_port *port, int if_ix) -{ - struct oz_hcd *ozhcd = port->ozhcd; - unsigned mask; - int i; - LIST_HEAD(ep_list); - struct oz_endpoint *ep, *n; - - oz_dbg(ON, "Deleting endpoints for interface %d\n", if_ix); - if (if_ix >= port->num_iface) - return; - spin_lock_bh(&ozhcd->hcd_lock); - mask = port->iface[if_ix].ep_mask; - port->iface[if_ix].ep_mask = 0; - for (i = 0; i < OZ_NB_ENDPOINTS; i++) { - struct list_head *e; - /* Gather OUT endpoints. - */ - if ((mask & (1<out_ep[i]) { - e = &port->out_ep[i]->link; - port->out_ep[i] = NULL; - /* Remove from isoc list if present. - */ - list_move_tail(e, &ep_list); - } - /* Gather IN endpoints. - */ - if ((mask & (1<<(i+OZ_NB_ENDPOINTS))) && port->in_ep[i]) { - e = &port->in_ep[i]->link; - port->in_ep[i] = NULL; - list_move_tail(e, &ep_list); - } - } - spin_unlock_bh(&ozhcd->hcd_lock); - list_for_each_entry_safe(ep, n, &ep_list, link) { - list_del_init(&ep->link); - oz_ep_free(port, ep); - } -} - -/* - * Context: softirq - */ -static int oz_build_endpoints_for_config(struct usb_hcd *hcd, - struct oz_port *port, struct usb_host_config *config, - gfp_t mem_flags) -{ - struct oz_hcd *ozhcd = port->ozhcd; - int i; - int num_iface = config->desc.bNumInterfaces; - - if (num_iface) { - struct oz_interface *iface; - - iface = kmalloc_array(num_iface, sizeof(struct oz_interface), - mem_flags | __GFP_ZERO); - if (!iface) - return -ENOMEM; - spin_lock_bh(&ozhcd->hcd_lock); - port->iface = iface; - port->num_iface = num_iface; - spin_unlock_bh(&ozhcd->hcd_lock); - } - for (i = 0; i < num_iface; i++) { - struct usb_host_interface *intf = - &config->intf_cache[i]->altsetting[0]; - if (oz_build_endpoints_for_interface(hcd, port, intf, - mem_flags)) - goto fail; - } - return 0; -fail: - oz_clean_endpoints_for_config(hcd, port); - return -1; -} - -/* - * Context: softirq - */ -static void oz_clean_endpoints_for_config(struct usb_hcd *hcd, - struct oz_port *port) -{ - struct oz_hcd *ozhcd = port->ozhcd; - int i; - - oz_dbg(ON, "Deleting endpoints for configuration\n"); - for (i = 0; i < port->num_iface; i++) - oz_clean_endpoints_for_interface(hcd, port, i); - spin_lock_bh(&ozhcd->hcd_lock); - if (port->iface) { - oz_dbg(ON, "Freeing interfaces object\n"); - kfree(port->iface); - port->iface = NULL; - } - port->num_iface = 0; - spin_unlock_bh(&ozhcd->hcd_lock); -} - -/* - * Context: tasklet - */ -static void *oz_claim_hpd(struct oz_port *port) -{ - void *hpd; - struct oz_hcd *ozhcd = port->ozhcd; - - spin_lock_bh(&ozhcd->hcd_lock); - hpd = port->hpd; - if (hpd) - oz_usb_get(hpd); - spin_unlock_bh(&ozhcd->hcd_lock); - return hpd; -} - -/* - * Context: tasklet - */ -static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, - gfp_t mem_flags) -{ - struct usb_ctrlrequest *setup; - unsigned windex; - unsigned wvalue; - unsigned wlength; - void *hpd; - u8 req_id; - int rc = 0; - unsigned complete = 0; - - int port_ix = -1; - struct oz_port *port = NULL; - - oz_dbg(URB, "[%s]:(%p)\n", __func__, urb); - port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum); - if (port_ix < 0) { - rc = -EPIPE; - goto out; - } - port = &ozhcd->ports[port_ix]; - if (((port->flags & OZ_PORT_F_PRESENT) == 0) - || (port->flags & OZ_PORT_F_DYING)) { - oz_dbg(ON, "Refusing URB port_ix = %d devnum = %d\n", - port_ix, urb->dev->devnum); - rc = -EPIPE; - goto out; - } - /* Store port in private context data. - */ - urb->hcpriv = port; - setup = (struct usb_ctrlrequest *)urb->setup_packet; - windex = le16_to_cpu(setup->wIndex); - wvalue = le16_to_cpu(setup->wValue); - wlength = le16_to_cpu(setup->wLength); - oz_dbg(CTRL_DETAIL, "bRequestType = %x\n", setup->bRequestType); - oz_dbg(CTRL_DETAIL, "bRequest = %x\n", setup->bRequest); - oz_dbg(CTRL_DETAIL, "wValue = %x\n", wvalue); - oz_dbg(CTRL_DETAIL, "wIndex = %x\n", windex); - oz_dbg(CTRL_DETAIL, "wLength = %x\n", wlength); - - req_id = port->next_req_id++; - hpd = oz_claim_hpd(port); - if (hpd == NULL) { - oz_dbg(ON, "Cannot claim port\n"); - rc = -EPIPE; - goto out; - } - - if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - /* Standard requests - */ - switch (setup->bRequest) { - case USB_REQ_GET_DESCRIPTOR: - oz_dbg(ON, "USB_REQ_GET_DESCRIPTOR - req\n"); - break; - case USB_REQ_SET_ADDRESS: - oz_dbg(ON, "USB_REQ_SET_ADDRESS - req\n"); - oz_dbg(ON, "Port %d address is 0x%x\n", - ozhcd->conn_port, - (u8)le16_to_cpu(setup->wValue)); - spin_lock_bh(&ozhcd->hcd_lock); - if (ozhcd->conn_port >= 0) { - ozhcd->ports[ozhcd->conn_port].bus_addr = - (u8)le16_to_cpu(setup->wValue); - oz_dbg(ON, "Clearing conn_port\n"); - ozhcd->conn_port = -1; - } - spin_unlock_bh(&ozhcd->hcd_lock); - complete = 1; - break; - case USB_REQ_SET_CONFIGURATION: - oz_dbg(ON, "USB_REQ_SET_CONFIGURATION - req\n"); - break; - case USB_REQ_GET_CONFIGURATION: - /* We short circuit this case and reply directly since - * we have the selected configuration number cached. - */ - oz_dbg(ON, "USB_REQ_GET_CONFIGURATION - reply now\n"); - if (urb->transfer_buffer_length >= 1) { - urb->actual_length = 1; - *((u8 *)urb->transfer_buffer) = - port->config_num; - complete = 1; - } else { - rc = -EPIPE; - } - break; - case USB_REQ_GET_INTERFACE: - /* We short circuit this case and reply directly since - * we have the selected interface alternative cached. - */ - oz_dbg(ON, "USB_REQ_GET_INTERFACE - reply now\n"); - if (urb->transfer_buffer_length >= 1) { - urb->actual_length = 1; - *((u8 *)urb->transfer_buffer) = - port->iface[(u8)windex].alt; - oz_dbg(ON, "interface = %d alt = %d\n", - windex, port->iface[(u8)windex].alt); - complete = 1; - } else { - rc = -EPIPE; - } - break; - case USB_REQ_SET_INTERFACE: - oz_dbg(ON, "USB_REQ_SET_INTERFACE - req\n"); - break; - } - } - if (!rc && !complete) { - int data_len = 0; - - if ((setup->bRequestType & USB_DIR_IN) == 0) - data_len = wlength; - urb->actual_length = data_len; - if (oz_usb_control_req(port->hpd, req_id, setup, - urb->transfer_buffer, data_len)) { - rc = -ENOMEM; - } else { - /* Note: we are queuing the request after we have - * submitted it to be transmitted. If the request were - * to complete before we queued it then it would not - * be found in the queue. It seems impossible for - * this to happen but if it did the request would - * be resubmitted so the problem would hopefully - * resolve itself. Putting the request into the - * queue before it has been sent is worse since the - * urb could be cancelled while we are using it - * to build the request. - */ - if (oz_enqueue_ep_urb(port, 0, 0, urb, req_id)) - rc = -ENOMEM; - } - } - oz_usb_put(hpd); -out: - if (rc || complete) { - oz_dbg(ON, "Completing request locally\n"); - oz_complete_urb(ozhcd->hcd, urb, rc); - } else { - oz_usb_request_heartbeat(port->hpd); - } -} - -/* - * Context: tasklet - */ -static int oz_urb_process(struct oz_hcd *ozhcd, struct urb *urb) -{ - int rc = 0; - struct oz_port *port = urb->hcpriv; - u8 ep_addr; - - /* When we are paranoid we keep a list of urbs which we check against - * before handing one back. This is just for debugging during - * development and should be turned off in the released driver. - */ - oz_remember_urb(urb); - /* Check buffer is valid. - */ - if (!urb->transfer_buffer && urb->transfer_buffer_length) - return -EINVAL; - /* Check if there is a device at the port - refuse if not. - */ - if ((port->flags & OZ_PORT_F_PRESENT) == 0) - return -EPIPE; - ep_addr = usb_pipeendpoint(urb->pipe); - if (ep_addr) { - /* If the request is not for EP0 then queue it. - */ - if (oz_enqueue_ep_urb(port, ep_addr, usb_pipein(urb->pipe), - urb, 0)) - rc = -EPIPE; - } else { - oz_process_ep0_urb(ozhcd, urb, GFP_ATOMIC); - } - return rc; -} - -/* - * Context: tasklet - */ -static void oz_urb_process_tasklet(unsigned long unused) -{ - unsigned long irq_state; - struct urb *urb; - struct oz_hcd *ozhcd = oz_hcd_claim(); - struct oz_urb_link *urbl, *n; - int rc = 0; - - if (ozhcd == NULL) - return; - /* This is called from a tasklet so is in softirq context but the urb - * list is filled from any context so we need to lock - * appropriately while removing urbs. - */ - spin_lock_irqsave(&g_tasklet_lock, irq_state); - list_for_each_entry_safe(urbl, n, &ozhcd->urb_pending_list, link) { - list_del_init(&urbl->link); - spin_unlock_irqrestore(&g_tasklet_lock, irq_state); - urb = urbl->urb; - oz_free_urb_link(urbl); - rc = oz_urb_process(ozhcd, urb); - if (rc) - oz_complete_urb(ozhcd->hcd, urb, rc); - spin_lock_irqsave(&g_tasklet_lock, irq_state); - } - spin_unlock_irqrestore(&g_tasklet_lock, irq_state); - oz_hcd_put(ozhcd); -} - -/* - * This function searches for the urb in any of the lists it could be in. - * If it is found it is removed from the list and completed. If the urb is - * being processed then it won't be in a list so won't be found. However, the - * call to usb_hcd_check_unlink_urb() will set the value of the unlinked field - * to a non-zero value. When an attempt is made to put the urb back in a list - * the unlinked field will be checked and the urb will then be completed. - * Context: tasklet - */ -static void oz_urb_cancel(struct oz_port *port, u8 ep_num, struct urb *urb) -{ - struct oz_urb_link *urbl = NULL; - struct list_head *e; - struct oz_hcd *ozhcd; - unsigned long irq_state; - u8 ix; - - if (port == NULL) { - oz_dbg(ON, "%s: ERROR: (%p) port is null\n", __func__, urb); - return; - } - ozhcd = port->ozhcd; - if (ozhcd == NULL) { - oz_dbg(ON, "%s; ERROR: (%p) ozhcd is null\n", __func__, urb); - return; - } - - /* Look in the tasklet queue. - */ - spin_lock_irqsave(&g_tasklet_lock, irq_state); - list_for_each(e, &ozhcd->urb_cancel_list) { - urbl = list_entry(e, struct oz_urb_link, link); - if (urb == urbl->urb) { - list_del_init(e); - spin_unlock_irqrestore(&g_tasklet_lock, irq_state); - goto out2; - } - } - spin_unlock_irqrestore(&g_tasklet_lock, irq_state); - urbl = NULL; - - /* Look in the orphanage. - */ - spin_lock_irqsave(&ozhcd->hcd_lock, irq_state); - list_for_each(e, &ozhcd->orphanage) { - urbl = list_entry(e, struct oz_urb_link, link); - if (urbl->urb == urb) { - list_del(e); - oz_dbg(ON, "Found urb in orphanage\n"); - goto out; - } - } - ix = (ep_num & 0xf); - urbl = NULL; - if ((ep_num & USB_DIR_IN) && ix) - urbl = oz_remove_urb(port->in_ep[ix], urb); - else - urbl = oz_remove_urb(port->out_ep[ix], urb); -out: - spin_unlock_irqrestore(&ozhcd->hcd_lock, irq_state); -out2: - if (urbl) { - urb->actual_length = 0; - oz_free_urb_link(urbl); - oz_complete_urb(ozhcd->hcd, urb, -EPIPE); - } -} - -/* - * Context: tasklet - */ -static void oz_urb_cancel_tasklet(unsigned long unused) -{ - unsigned long irq_state; - struct urb *urb; - struct oz_urb_link *urbl, *n; - struct oz_hcd *ozhcd = oz_hcd_claim(); - - if (ozhcd == NULL) - return; - spin_lock_irqsave(&g_tasklet_lock, irq_state); - list_for_each_entry_safe(urbl, n, &ozhcd->urb_cancel_list, link) { - list_del_init(&urbl->link); - spin_unlock_irqrestore(&g_tasklet_lock, irq_state); - urb = urbl->urb; - if (urb->unlinked) - oz_urb_cancel(urbl->port, urbl->ep_num, urb); - oz_free_urb_link(urbl); - spin_lock_irqsave(&g_tasklet_lock, irq_state); - } - spin_unlock_irqrestore(&g_tasklet_lock, irq_state); - oz_hcd_put(ozhcd); -} - -/* - * Context: unknown - */ -static void oz_hcd_clear_orphanage(struct oz_hcd *ozhcd, int status) -{ - if (ozhcd) { - struct oz_urb_link *urbl, *n; - - list_for_each_entry_safe(urbl, n, &ozhcd->orphanage, link) { - list_del(&urbl->link); - oz_complete_urb(ozhcd->hcd, urbl->urb, status); - oz_free_urb_link(urbl); - } - } -} - -/* - * Context: unknown - */ -static int oz_hcd_start(struct usb_hcd *hcd) -{ - hcd->power_budget = 200; - hcd->state = HC_STATE_RUNNING; - hcd->uses_new_polling = 1; - return 0; -} - -/* - * Context: unknown - */ -static void oz_hcd_stop(struct usb_hcd *hcd) -{ -} - -/* - * Context: unknown - */ -static void oz_hcd_shutdown(struct usb_hcd *hcd) -{ -} - -/* - * Called to queue an urb for the device. - * This function should return a non-zero error code if it fails the urb but - * should not call usb_hcd_giveback_urb(). - * Context: any - */ -static int oz_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct oz_hcd *ozhcd = oz_hcd_private(hcd); - int rc; - int port_ix; - struct oz_port *port; - unsigned long irq_state; - struct oz_urb_link *urbl; - - oz_dbg(URB, "%s: (%p)\n", __func__, urb); - if (unlikely(ozhcd == NULL)) { - oz_dbg(URB, "Refused urb(%p) not ozhcd\n", urb); - return -EPIPE; - } - if (unlikely(hcd->state != HC_STATE_RUNNING)) { - oz_dbg(URB, "Refused urb(%p) not running\n", urb); - return -EPIPE; - } - port_ix = oz_get_port_from_addr(ozhcd, urb->dev->devnum); - if (port_ix < 0) - return -EPIPE; - port = &ozhcd->ports[port_ix]; - if (port == NULL) - return -EPIPE; - if (!(port->flags & OZ_PORT_F_PRESENT) || - (port->flags & OZ_PORT_F_CHANGED)) { - oz_dbg(ON, "Refusing URB port_ix = %d devnum = %d\n", - port_ix, urb->dev->devnum); - return -EPIPE; - } - urb->hcpriv = port; - /* Put request in queue for processing by tasklet. - */ - urbl = oz_alloc_urb_link(); - if (unlikely(urbl == NULL)) - return -ENOMEM; - urbl->urb = urb; - spin_lock_irqsave(&g_tasklet_lock, irq_state); - rc = usb_hcd_link_urb_to_ep(hcd, urb); - if (unlikely(rc)) { - spin_unlock_irqrestore(&g_tasklet_lock, irq_state); - oz_free_urb_link(urbl); - return rc; - } - list_add_tail(&urbl->link, &ozhcd->urb_pending_list); - spin_unlock_irqrestore(&g_tasklet_lock, irq_state); - tasklet_schedule(&g_urb_process_tasklet); - atomic_inc(&g_pending_urbs); - return 0; -} - -/* - * Context: tasklet - */ -static struct oz_urb_link *oz_remove_urb(struct oz_endpoint *ep, - struct urb *urb) -{ - struct oz_urb_link *urbl; - - if (unlikely(ep == NULL)) - return NULL; - - list_for_each_entry(urbl, &ep->urb_list, link) { - if (urbl->urb == urb) { - list_del_init(&urbl->link); - if (usb_pipeisoc(urb->pipe)) { - ep->credit -= urb->number_of_packets; - if (ep->credit < 0) - ep->credit = 0; - } - return urbl; - } - } - return NULL; -} - -/* - * Called to dequeue a previously submitted urb for the device. - * Context: any - */ -static int oz_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct oz_hcd *ozhcd = oz_hcd_private(hcd); - struct oz_urb_link *urbl; - int rc; - unsigned long irq_state; - - oz_dbg(URB, "%s: (%p)\n", __func__, urb); - urbl = oz_alloc_urb_link(); - if (unlikely(urbl == NULL)) - return -ENOMEM; - spin_lock_irqsave(&g_tasklet_lock, irq_state); - /* The following function checks the urb is still in the queue - * maintained by the core and that the unlinked field is zero. - * If both are true the function sets the unlinked field and returns - * zero. Otherwise it returns an error. - */ - rc = usb_hcd_check_unlink_urb(hcd, urb, status); - /* We have to check we haven't completed the urb or are about - * to complete it. When we do we set hcpriv to 0 so if this has - * already happened we don't put the urb in the cancel queue. - */ - if ((rc == 0) && urb->hcpriv) { - urbl->urb = urb; - urbl->port = (struct oz_port *)urb->hcpriv; - urbl->ep_num = usb_pipeendpoint(urb->pipe); - if (usb_pipein(urb->pipe)) - urbl->ep_num |= USB_DIR_IN; - list_add_tail(&urbl->link, &ozhcd->urb_cancel_list); - spin_unlock_irqrestore(&g_tasklet_lock, irq_state); - tasklet_schedule(&g_urb_cancel_tasklet); - } else { - spin_unlock_irqrestore(&g_tasklet_lock, irq_state); - oz_free_urb_link(urbl); - } - return rc; -} - -/* - * Context: unknown - */ -static void oz_hcd_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) -{ -} - -/* - * Context: unknown - */ -static void oz_hcd_endpoint_reset(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) -{ -} - -/* - * Context: unknown - */ -static int oz_hcd_get_frame_number(struct usb_hcd *hcd) -{ - oz_dbg(ON, "oz_hcd_get_frame_number\n"); - return oz_usb_get_frame_number(); -} - -/* - * Context: softirq - * This is called as a consquence of us calling usb_hcd_poll_rh_status() and we - * always do that in softirq context. - */ -static int oz_hcd_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct oz_hcd *ozhcd = oz_hcd_private(hcd); - int i; - - buf[0] = 0; - buf[1] = 0; - - spin_lock_bh(&ozhcd->hcd_lock); - for (i = 0; i < OZ_NB_PORTS; i++) { - if (ozhcd->ports[i].flags & OZ_PORT_F_CHANGED) { - oz_dbg(HUB, "Port %d changed\n", i); - ozhcd->ports[i].flags &= ~OZ_PORT_F_CHANGED; - if (i < 7) - buf[0] |= 1 << (i + 1); - else - buf[1] |= 1 << (i - 7); - } - } - spin_unlock_bh(&ozhcd->hcd_lock); - if (buf[0] != 0 || buf[1] != 0) - return 2; - return 0; -} - -/* - * Context: process - */ -static void oz_get_hub_descriptor(struct usb_hcd *hcd, - struct usb_hub_descriptor *desc) -{ - memset(desc, 0, sizeof(*desc)); - desc->bDescriptorType = 0x29; - desc->bDescLength = 9; - desc->wHubCharacteristics = cpu_to_le16(0x0001); - desc->bNbrPorts = OZ_NB_PORTS; -} - -/* - * Context: process - */ -static int oz_set_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex) -{ - struct oz_port *port; - u8 port_id = (u8)windex; - struct oz_hcd *ozhcd = oz_hcd_private(hcd); - unsigned set_bits = 0; - unsigned clear_bits = 0; - - if ((port_id < 1) || (port_id > OZ_NB_PORTS)) - return -EPIPE; - port = &ozhcd->ports[port_id-1]; - switch (wvalue) { - case USB_PORT_FEAT_CONNECTION: - oz_dbg(HUB, "USB_PORT_FEAT_CONNECTION\n"); - break; - case USB_PORT_FEAT_ENABLE: - oz_dbg(HUB, "USB_PORT_FEAT_ENABLE\n"); - break; - case USB_PORT_FEAT_SUSPEND: - oz_dbg(HUB, "USB_PORT_FEAT_SUSPEND\n"); - break; - case USB_PORT_FEAT_OVER_CURRENT: - oz_dbg(HUB, "USB_PORT_FEAT_OVER_CURRENT\n"); - break; - case USB_PORT_FEAT_RESET: - oz_dbg(HUB, "USB_PORT_FEAT_RESET\n"); - set_bits = USB_PORT_STAT_ENABLE | (USB_PORT_STAT_C_RESET<<16); - clear_bits = USB_PORT_STAT_RESET; - ozhcd->ports[port_id-1].bus_addr = 0; - break; - case USB_PORT_FEAT_POWER: - oz_dbg(HUB, "USB_PORT_FEAT_POWER\n"); - set_bits |= USB_PORT_STAT_POWER; - break; - case USB_PORT_FEAT_LOWSPEED: - oz_dbg(HUB, "USB_PORT_FEAT_LOWSPEED\n"); - break; - case USB_PORT_FEAT_C_CONNECTION: - oz_dbg(HUB, "USB_PORT_FEAT_C_CONNECTION\n"); - break; - case USB_PORT_FEAT_C_ENABLE: - oz_dbg(HUB, "USB_PORT_FEAT_C_ENABLE\n"); - break; - case USB_PORT_FEAT_C_SUSPEND: - oz_dbg(HUB, "USB_PORT_FEAT_C_SUSPEND\n"); - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - oz_dbg(HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n"); - break; - case USB_PORT_FEAT_C_RESET: - oz_dbg(HUB, "USB_PORT_FEAT_C_RESET\n"); - break; - case USB_PORT_FEAT_TEST: - oz_dbg(HUB, "USB_PORT_FEAT_TEST\n"); - break; - case USB_PORT_FEAT_INDICATOR: - oz_dbg(HUB, "USB_PORT_FEAT_INDICATOR\n"); - break; - default: - oz_dbg(HUB, "Other %d\n", wvalue); - break; - } - if (set_bits || clear_bits) { - spin_lock_bh(&port->port_lock); - port->status &= ~clear_bits; - port->status |= set_bits; - spin_unlock_bh(&port->port_lock); - } - oz_dbg(HUB, "Port[%d] status = 0x%x\n", port_id, port->status); - return 0; -} - -/* - * Context: process - */ -static int oz_clear_port_feature(struct usb_hcd *hcd, u16 wvalue, u16 windex) -{ - struct oz_port *port; - u8 port_id = (u8)windex; - struct oz_hcd *ozhcd = oz_hcd_private(hcd); - unsigned clear_bits = 0; - - if ((port_id < 1) || (port_id > OZ_NB_PORTS)) - return -EPIPE; - port = &ozhcd->ports[port_id-1]; - switch (wvalue) { - case USB_PORT_FEAT_CONNECTION: - oz_dbg(HUB, "USB_PORT_FEAT_CONNECTION\n"); - break; - case USB_PORT_FEAT_ENABLE: - oz_dbg(HUB, "USB_PORT_FEAT_ENABLE\n"); - clear_bits = USB_PORT_STAT_ENABLE; - break; - case USB_PORT_FEAT_SUSPEND: - oz_dbg(HUB, "USB_PORT_FEAT_SUSPEND\n"); - break; - case USB_PORT_FEAT_OVER_CURRENT: - oz_dbg(HUB, "USB_PORT_FEAT_OVER_CURRENT\n"); - break; - case USB_PORT_FEAT_RESET: - oz_dbg(HUB, "USB_PORT_FEAT_RESET\n"); - break; - case USB_PORT_FEAT_POWER: - oz_dbg(HUB, "USB_PORT_FEAT_POWER\n"); - clear_bits |= USB_PORT_STAT_POWER; - break; - case USB_PORT_FEAT_LOWSPEED: - oz_dbg(HUB, "USB_PORT_FEAT_LOWSPEED\n"); - break; - case USB_PORT_FEAT_C_CONNECTION: - oz_dbg(HUB, "USB_PORT_FEAT_C_CONNECTION\n"); - clear_bits = USB_PORT_STAT_C_CONNECTION << 16; - break; - case USB_PORT_FEAT_C_ENABLE: - oz_dbg(HUB, "USB_PORT_FEAT_C_ENABLE\n"); - clear_bits = USB_PORT_STAT_C_ENABLE << 16; - break; - case USB_PORT_FEAT_C_SUSPEND: - oz_dbg(HUB, "USB_PORT_FEAT_C_SUSPEND\n"); - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - oz_dbg(HUB, "USB_PORT_FEAT_C_OVER_CURRENT\n"); - break; - case USB_PORT_FEAT_C_RESET: - oz_dbg(HUB, "USB_PORT_FEAT_C_RESET\n"); - clear_bits = USB_PORT_FEAT_C_RESET << 16; - break; - case USB_PORT_FEAT_TEST: - oz_dbg(HUB, "USB_PORT_FEAT_TEST\n"); - break; - case USB_PORT_FEAT_INDICATOR: - oz_dbg(HUB, "USB_PORT_FEAT_INDICATOR\n"); - break; - default: - oz_dbg(HUB, "Other %d\n", wvalue); - break; - } - if (clear_bits) { - spin_lock_bh(&port->port_lock); - port->status &= ~clear_bits; - spin_unlock_bh(&port->port_lock); - } - oz_dbg(HUB, "Port[%d] status = 0x%x\n", - port_id, ozhcd->ports[port_id-1].status); - return 0; -} - -/* - * Context: process - */ -static int oz_get_port_status(struct usb_hcd *hcd, u16 windex, char *buf) -{ - struct oz_hcd *ozhcd; - u32 status; - - if ((windex < 1) || (windex > OZ_NB_PORTS)) - return -EPIPE; - ozhcd = oz_hcd_private(hcd); - oz_dbg(HUB, "GetPortStatus windex = %d\n", windex); - status = ozhcd->ports[windex-1].status; - put_unaligned(cpu_to_le32(status), (__le32 *)buf); - oz_dbg(HUB, "Port[%d] status = %x\n", windex, status); - return 0; -} - -/* - * Context: process - */ -static int oz_hcd_hub_control(struct usb_hcd *hcd, u16 req_type, u16 wvalue, - u16 windex, char *buf, u16 wlength) -{ - int err = 0; - - switch (req_type) { - case ClearHubFeature: - oz_dbg(HUB, "ClearHubFeature: %d\n", req_type); - break; - case ClearPortFeature: - err = oz_clear_port_feature(hcd, wvalue, windex); - break; - case GetHubDescriptor: - oz_get_hub_descriptor(hcd, (struct usb_hub_descriptor *)buf); - break; - case GetHubStatus: - oz_dbg(HUB, "GetHubStatus: req_type = 0x%x\n", req_type); - put_unaligned(cpu_to_le32(0), (__le32 *)buf); - break; - case GetPortStatus: - err = oz_get_port_status(hcd, windex, buf); - break; - case SetHubFeature: - oz_dbg(HUB, "SetHubFeature: %d\n", req_type); - break; - case SetPortFeature: - err = oz_set_port_feature(hcd, wvalue, windex); - break; - default: - oz_dbg(HUB, "Other: %d\n", req_type); - break; - } - return err; -} - -/* - * Context: process - */ -static int oz_hcd_bus_suspend(struct usb_hcd *hcd) -{ - struct oz_hcd *ozhcd; - - ozhcd = oz_hcd_private(hcd); - spin_lock_bh(&ozhcd->hcd_lock); - hcd->state = HC_STATE_SUSPENDED; - ozhcd->flags |= OZ_HDC_F_SUSPENDED; - spin_unlock_bh(&ozhcd->hcd_lock); - return 0; -} - -/* - * Context: process - */ -static int oz_hcd_bus_resume(struct usb_hcd *hcd) -{ - struct oz_hcd *ozhcd; - - ozhcd = oz_hcd_private(hcd); - spin_lock_bh(&ozhcd->hcd_lock); - ozhcd->flags &= ~OZ_HDC_F_SUSPENDED; - hcd->state = HC_STATE_RUNNING; - spin_unlock_bh(&ozhcd->hcd_lock); - return 0; -} - -static void oz_plat_shutdown(struct platform_device *dev) -{ -} - -/* - * Context: process - */ -static int oz_plat_probe(struct platform_device *dev) -{ - int i; - int err; - struct usb_hcd *hcd; - struct oz_hcd *ozhcd; - - hcd = usb_create_hcd(&g_oz_hc_drv, &dev->dev, dev_name(&dev->dev)); - if (hcd == NULL) { - oz_dbg(ON, "Failed to created hcd object OK\n"); - return -ENOMEM; - } - ozhcd = oz_hcd_private(hcd); - memset(ozhcd, 0, sizeof(*ozhcd)); - INIT_LIST_HEAD(&ozhcd->urb_pending_list); - INIT_LIST_HEAD(&ozhcd->urb_cancel_list); - INIT_LIST_HEAD(&ozhcd->orphanage); - ozhcd->hcd = hcd; - ozhcd->conn_port = -1; - spin_lock_init(&ozhcd->hcd_lock); - for (i = 0; i < OZ_NB_PORTS; i++) { - struct oz_port *port = &ozhcd->ports[i]; - - port->ozhcd = ozhcd; - port->flags = 0; - port->status = 0; - port->bus_addr = 0xff; - spin_lock_init(&port->port_lock); - } - err = usb_add_hcd(hcd, 0, 0); - if (err) { - oz_dbg(ON, "Failed to add hcd object OK\n"); - usb_put_hcd(hcd); - return -1; - } - device_wakeup_enable(hcd->self.controller); - - spin_lock_bh(&g_hcdlock); - g_ozhcd = ozhcd; - spin_unlock_bh(&g_hcdlock); - return 0; -} - -/* - * Context: unknown - */ -static int oz_plat_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct oz_hcd *ozhcd; - - if (hcd == NULL) - return -1; - ozhcd = oz_hcd_private(hcd); - spin_lock_bh(&g_hcdlock); - if (ozhcd == g_ozhcd) - g_ozhcd = NULL; - spin_unlock_bh(&g_hcdlock); - oz_dbg(ON, "Clearing orphanage\n"); - oz_hcd_clear_orphanage(ozhcd, -EPIPE); - oz_dbg(ON, "Removing hcd\n"); - usb_remove_hcd(hcd); - usb_put_hcd(hcd); - return 0; -} - -/* - * Context: unknown - */ -static int oz_plat_suspend(struct platform_device *dev, pm_message_t msg) -{ - return 0; -} - - -/* - * Context: unknown - */ -static int oz_plat_resume(struct platform_device *dev) -{ - return 0; -} - -/* - * Context: process - */ -int oz_hcd_init(void) -{ - int err; - - if (usb_disabled()) - return -ENODEV; - - oz_urb_link_cache = KMEM_CACHE(oz_urb_link, 0); - if (!oz_urb_link_cache) - return -ENOMEM; - - tasklet_init(&g_urb_process_tasklet, oz_urb_process_tasklet, 0); - tasklet_init(&g_urb_cancel_tasklet, oz_urb_cancel_tasklet, 0); - err = platform_driver_register(&g_oz_plat_drv); - oz_dbg(ON, "platform_driver_register() returned %d\n", err); - if (err) - goto error; - g_plat_dev = platform_device_alloc(OZ_PLAT_DEV_NAME, -1); - if (g_plat_dev == NULL) { - err = -ENOMEM; - goto error1; - } - oz_dbg(ON, "platform_device_alloc() succeeded\n"); - err = platform_device_add(g_plat_dev); - if (err) - goto error2; - oz_dbg(ON, "platform_device_add() succeeded\n"); - return 0; -error2: - platform_device_put(g_plat_dev); -error1: - platform_driver_unregister(&g_oz_plat_drv); -error: - tasklet_disable(&g_urb_process_tasklet); - tasklet_disable(&g_urb_cancel_tasklet); - oz_dbg(ON, "oz_hcd_init() failed %d\n", err); - return err; -} - -/* - * Context: process - */ -void oz_hcd_term(void) -{ - msleep(OZ_HUB_DEBOUNCE_TIMEOUT); - tasklet_kill(&g_urb_process_tasklet); - tasklet_kill(&g_urb_cancel_tasklet); - platform_device_unregister(g_plat_dev); - platform_driver_unregister(&g_oz_plat_drv); - oz_dbg(ON, "Pending urbs:%d\n", atomic_read(&g_pending_urbs)); - kmem_cache_destroy(oz_urb_link_cache); -} diff --git a/drivers/staging/ozwpan/ozhcd.h b/drivers/staging/ozwpan/ozhcd.h deleted file mode 100644 index 55e97b1c7079..000000000000 --- a/drivers/staging/ozwpan/ozhcd.h +++ /dev/null @@ -1,15 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ---------------------------------------------------------------------------*/ -#ifndef _OZHCD_H -#define _OZHCD_H - -int oz_hcd_init(void); -void oz_hcd_term(void); -struct oz_port *oz_hcd_pd_arrived(void *ctx); -void oz_hcd_pd_departed(struct oz_port *hport); -void oz_hcd_pd_reset(void *hpd, void *hport); - -#endif /* _OZHCD_H */ - diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c deleted file mode 100644 index 74ef34815b98..000000000000 --- a/drivers/staging/ozwpan/ozmain.c +++ /dev/null @@ -1,71 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ozdbg.h" -#include "ozpd.h" -#include "ozproto.h" -#include "ozcdev.h" - -unsigned int oz_dbg_mask = OZ_DEFAULT_DBG_MASK; - -/* - * The name of the 802.11 mac device. Empty string is the default value but a - * value can be supplied as a parameter to the module. An empty string means - * bind to nothing. '*' means bind to all netcards - this includes non-802.11 - * netcards. Bindings can be added later using an IOCTL. - */ -static char *g_net_dev = ""; -module_param(g_net_dev, charp, S_IRUGO); -MODULE_PARM_DESC(g_net_dev, "The device(s) to bind to; " - "'*' means all, '' (empty string; default) means none."); - -/* - * Context: process - */ -static int __init ozwpan_init(void) -{ - int err; - - err = oz_cdev_register(); - if (err) - return err; - err = oz_protocol_init(g_net_dev); - if (err) - goto err_protocol; - oz_app_enable(OZ_APPID_USB, 1); - oz_apps_init(); - return 0; - -err_protocol: - oz_cdev_deregister(); - return err; -} - -/* - * Context: process - */ -static void __exit ozwpan_exit(void) -{ - oz_protocol_term(); - oz_apps_term(); - oz_cdev_deregister(); -} - -module_init(ozwpan_init); -module_exit(ozwpan_exit); - -MODULE_AUTHOR("Chris Kelly"); -MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver"); -MODULE_VERSION("1.0.13"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c deleted file mode 100644 index 021d74a132dd..000000000000 --- a/drivers/staging/ozwpan/ozpd.c +++ /dev/null @@ -1,886 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include "ozdbg.h" -#include "ozprotocol.h" -#include "ozeltbuf.h" -#include "ozpd.h" -#include "ozproto.h" -#include "ozcdev.h" -#include "ozusbsvc.h" -#include -#include -#include - -static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd); -static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f); -static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f); -static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f); -static int oz_send_isoc_frame(struct oz_pd *pd); -static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f); -static void oz_isoc_stream_free(struct oz_isoc_stream *st); -static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data); -static void oz_isoc_destructor(struct sk_buff *skb); - -/* - * Counts the uncompleted isoc frames submitted to netcard. - */ -static atomic_t g_submitted_isoc = ATOMIC_INIT(0); - -/* Application handler functions. - */ -static const struct oz_app_if g_app_if[OZ_NB_APPS] = { - [OZ_APPID_USB] = { - .init = oz_usb_init, - .term = oz_usb_term, - .start = oz_usb_start, - .stop = oz_usb_stop, - .rx = oz_usb_rx, - .heartbeat = oz_usb_heartbeat, - .farewell = oz_usb_farewell, - }, - [OZ_APPID_SERIAL] = { - .init = oz_cdev_init, - .term = oz_cdev_term, - .start = oz_cdev_start, - .stop = oz_cdev_stop, - .rx = oz_cdev_rx, - }, -}; - - -/* - * Context: softirq or process - */ -void oz_pd_set_state(struct oz_pd *pd, unsigned state) -{ - pd->state = state; - switch (state) { - case OZ_PD_S_IDLE: - oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_IDLE\n"); - break; - case OZ_PD_S_CONNECTED: - oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_CONNECTED\n"); - break; - case OZ_PD_S_STOPPED: - oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_STOPPED\n"); - break; - case OZ_PD_S_SLEEP: - oz_pd_dbg(pd, ON, "PD State: OZ_PD_S_SLEEP\n"); - break; - } -} - -/* - * Context: softirq or process - */ -void oz_pd_get(struct oz_pd *pd) -{ - atomic_inc(&pd->ref_count); -} - -/* - * Context: softirq or process - */ -void oz_pd_put(struct oz_pd *pd) -{ - if (atomic_dec_and_test(&pd->ref_count)) - oz_pd_destroy(pd); -} - -/* - * Context: softirq-serialized - */ -struct oz_pd *oz_pd_alloc(const u8 *mac_addr) -{ - struct oz_pd *pd; - int i; - - pd = kzalloc(sizeof(struct oz_pd), GFP_ATOMIC); - if (!pd) - return NULL; - - atomic_set(&pd->ref_count, 2); - for (i = 0; i < OZ_NB_APPS; i++) - spin_lock_init(&pd->app_lock[i]); - pd->last_rx_pkt_num = 0xffffffff; - oz_pd_set_state(pd, OZ_PD_S_IDLE); - pd->max_tx_size = OZ_MAX_TX_SIZE; - ether_addr_copy(pd->mac_addr, mac_addr); - oz_elt_buf_init(&pd->elt_buff); - spin_lock_init(&pd->tx_frame_lock); - INIT_LIST_HEAD(&pd->tx_queue); - INIT_LIST_HEAD(&pd->farewell_list); - pd->last_sent_frame = &pd->tx_queue; - spin_lock_init(&pd->stream_lock); - INIT_LIST_HEAD(&pd->stream_list); - tasklet_init(&pd->heartbeat_tasklet, oz_pd_heartbeat_handler, - (unsigned long)pd); - tasklet_init(&pd->timeout_tasklet, oz_pd_timeout_handler, - (unsigned long)pd); - hrtimer_init(&pd->heartbeat, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hrtimer_init(&pd->timeout, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - pd->heartbeat.function = oz_pd_heartbeat_event; - pd->timeout.function = oz_pd_timeout_event; - - return pd; -} - -/* - * Context: softirq or process - */ -static void oz_pd_free(struct work_struct *work) -{ - struct list_head *e, *n; - struct oz_pd *pd; - - oz_pd_dbg(pd, ON, "Destroying PD\n"); - pd = container_of(work, struct oz_pd, workitem); - /*Disable timer tasklets*/ - tasklet_kill(&pd->heartbeat_tasklet); - tasklet_kill(&pd->timeout_tasklet); - - /* Free streams, queued tx frames and farewells. */ - - list_for_each_safe(e, n, &pd->stream_list) - oz_isoc_stream_free(list_entry(e, struct oz_isoc_stream, link)); - - list_for_each_safe(e, n, &pd->tx_queue) { - struct oz_tx_frame *f = list_entry(e, struct oz_tx_frame, link); - - if (f->skb != NULL) - kfree_skb(f->skb); - oz_retire_frame(pd, f); - } - - oz_elt_buf_term(&pd->elt_buff); - - list_for_each_safe(e, n, &pd->farewell_list) - kfree(list_entry(e, struct oz_farewell, link)); - - if (pd->net_dev) - dev_put(pd->net_dev); - kfree(pd); -} - -/* - * Context: softirq or Process - */ -void oz_pd_destroy(struct oz_pd *pd) -{ - if (hrtimer_active(&pd->timeout)) - hrtimer_cancel(&pd->timeout); - if (hrtimer_active(&pd->heartbeat)) - hrtimer_cancel(&pd->heartbeat); - - INIT_WORK(&pd->workitem, oz_pd_free); - if (!schedule_work(&pd->workitem)) - oz_pd_dbg(pd, ON, "failed to schedule workitem\n"); -} - -/* - * Context: softirq-serialized - */ -int oz_services_start(struct oz_pd *pd, u16 apps, int resume) -{ - int i, rc = 0; - - oz_pd_dbg(pd, ON, "%s: (0x%x) resume(%d)\n", __func__, apps, resume); - for (i = 0; i < OZ_NB_APPS; i++) { - if (g_app_if[i].start && (apps & (1 << i))) { - if (g_app_if[i].start(pd, resume)) { - rc = -1; - oz_pd_dbg(pd, ON, - "Unable to start service %d\n", i); - break; - } - spin_lock_bh(&g_polling_lock); - pd->total_apps |= (1 << i); - if (resume) - pd->paused_apps &= ~(1 << i); - spin_unlock_bh(&g_polling_lock); - } - } - return rc; -} - -/* - * Context: softirq or process - */ -void oz_services_stop(struct oz_pd *pd, u16 apps, int pause) -{ - int i; - - oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, apps, pause); - for (i = 0; i < OZ_NB_APPS; i++) { - if (g_app_if[i].stop && (apps & (1 << i))) { - spin_lock_bh(&g_polling_lock); - if (pause) { - pd->paused_apps |= (1 << i); - } else { - pd->total_apps &= ~(1 << i); - pd->paused_apps &= ~(1 << i); - } - spin_unlock_bh(&g_polling_lock); - g_app_if[i].stop(pd, pause); - } - } -} - -/* - * Context: softirq - */ -void oz_pd_heartbeat(struct oz_pd *pd, u16 apps) -{ - int i, more = 0; - - for (i = 0; i < OZ_NB_APPS; i++) { - if (g_app_if[i].heartbeat && (apps & (1 << i))) { - if (g_app_if[i].heartbeat(pd)) - more = 1; - } - } - if ((!more) && (hrtimer_active(&pd->heartbeat))) - hrtimer_cancel(&pd->heartbeat); - if (pd->mode & OZ_F_ISOC_ANYTIME) { - int count = 8; - - while (count-- && (oz_send_isoc_frame(pd) >= 0)) - ; - } -} - -/* - * Context: softirq or process - */ -void oz_pd_stop(struct oz_pd *pd) -{ - u16 stop_apps; - - oz_dbg(ON, "oz_pd_stop() State = 0x%x\n", pd->state); - oz_pd_indicate_farewells(pd); - spin_lock_bh(&g_polling_lock); - stop_apps = pd->total_apps; - pd->total_apps = 0; - pd->paused_apps = 0; - spin_unlock_bh(&g_polling_lock); - oz_services_stop(pd, stop_apps, 0); - spin_lock_bh(&g_polling_lock); - oz_pd_set_state(pd, OZ_PD_S_STOPPED); - /* Remove from PD list.*/ - list_del(&pd->link); - spin_unlock_bh(&g_polling_lock); - oz_dbg(ON, "pd ref count = %d\n", atomic_read(&pd->ref_count)); - oz_pd_put(pd); -} - -/* - * Context: softirq - */ -int oz_pd_sleep(struct oz_pd *pd) -{ - int do_stop = 0; - u16 stop_apps; - - spin_lock_bh(&g_polling_lock); - if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) { - spin_unlock_bh(&g_polling_lock); - return 0; - } - if (pd->keep_alive && pd->session_id) - oz_pd_set_state(pd, OZ_PD_S_SLEEP); - else - do_stop = 1; - - stop_apps = pd->total_apps; - spin_unlock_bh(&g_polling_lock); - if (do_stop) { - oz_pd_stop(pd); - } else { - oz_services_stop(pd, stop_apps, 1); - oz_timer_add(pd, OZ_TIMER_STOP, pd->keep_alive); - } - return do_stop; -} - -/* - * Context: softirq - */ -static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd) -{ - struct oz_tx_frame *f; - - f = kmem_cache_alloc(oz_tx_frame_cache, GFP_ATOMIC); - if (f) { - f->total_size = sizeof(struct oz_hdr); - INIT_LIST_HEAD(&f->link); - INIT_LIST_HEAD(&f->elt_list); - } - return f; -} - -/* - * Context: softirq or process - */ -static void oz_tx_isoc_free(struct oz_pd *pd, struct oz_tx_frame *f) -{ - pd->nb_queued_isoc_frames--; - list_del_init(&f->link); - - kmem_cache_free(oz_tx_frame_cache, f); - - oz_dbg(TX_FRAMES, "Releasing ISOC Frame isoc_nb= %d\n", - pd->nb_queued_isoc_frames); -} - -/* - * Context: softirq or process - */ -static void oz_tx_frame_free(struct oz_pd *pd, struct oz_tx_frame *f) -{ - kmem_cache_free(oz_tx_frame_cache, f); -} - -/* - * Context: softirq-serialized - */ -static void oz_set_more_bit(struct sk_buff *skb) -{ - struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb); - - oz_hdr->control |= OZ_F_MORE_DATA; -} - -/* - * Context: softirq-serialized - */ -static void oz_set_last_pkt_nb(struct oz_pd *pd, struct sk_buff *skb) -{ - struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb); - - oz_hdr->last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK; -} - -/* - * Context: softirq - */ -int oz_prepare_frame(struct oz_pd *pd, int empty) -{ - struct oz_tx_frame *f; - - if ((pd->mode & OZ_MODE_MASK) != OZ_MODE_TRIGGERED) - return -1; - if (pd->nb_queued_frames >= OZ_MAX_QUEUED_FRAMES) - return -1; - if (!empty && !oz_are_elts_available(&pd->elt_buff)) - return -1; - f = oz_tx_frame_alloc(pd); - if (f == NULL) - return -1; - f->skb = NULL; - f->hdr.control = - (OZ_PROTOCOL_VERSION<last_tx_pkt_num; - put_unaligned(cpu_to_le32(pd->last_tx_pkt_num), &f->hdr.pkt_num); - if (empty == 0) { - oz_select_elts_for_tx(&pd->elt_buff, 0, &f->total_size, - pd->max_tx_size, &f->elt_list); - } - spin_lock(&pd->tx_frame_lock); - list_add_tail(&f->link, &pd->tx_queue); - pd->nb_queued_frames++; - spin_unlock(&pd->tx_frame_lock); - return 0; -} - -/* - * Context: softirq-serialized - */ -static struct sk_buff *oz_build_frame(struct oz_pd *pd, struct oz_tx_frame *f) -{ - struct sk_buff *skb; - struct net_device *dev = pd->net_dev; - struct oz_hdr *oz_hdr; - struct oz_elt *elt; - struct oz_elt_info *ei; - - /* Allocate skb with enough space for the lower layers as well - * as the space we need. - */ - skb = alloc_skb(f->total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC); - if (skb == NULL) - return NULL; - /* Reserve the head room for lower layers. - */ - skb_reserve(skb, LL_RESERVED_SPACE(dev)); - skb_reset_network_header(skb); - skb->dev = dev; - skb->protocol = htons(OZ_ETHERTYPE); - if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr, - dev->dev_addr, skb->len) < 0) - goto fail; - /* Push the tail to the end of the area we are going to copy to. - */ - oz_hdr = (struct oz_hdr *)skb_put(skb, f->total_size); - f->hdr.last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK; - memcpy(oz_hdr, &f->hdr, sizeof(struct oz_hdr)); - /* Copy the elements into the frame body. - */ - elt = (struct oz_elt *)(oz_hdr+1); - list_for_each_entry(ei, &f->elt_list, link) { - memcpy(elt, ei->data, ei->length); - elt = oz_next_elt(elt); - } - return skb; -fail: - kfree_skb(skb); - return NULL; -} - -/* - * Context: softirq or process - */ -static void oz_retire_frame(struct oz_pd *pd, struct oz_tx_frame *f) -{ - struct oz_elt_info *ei, *n; - - list_for_each_entry_safe(ei, n, &f->elt_list, link) { - list_del_init(&ei->link); - if (ei->callback) - ei->callback(pd, ei->context); - spin_lock_bh(&pd->elt_buff.lock); - oz_elt_info_free(&pd->elt_buff, ei); - spin_unlock_bh(&pd->elt_buff.lock); - } - oz_tx_frame_free(pd, f); -} - -/* - * Context: softirq-serialized - */ -static int oz_send_next_queued_frame(struct oz_pd *pd, int more_data) -{ - struct sk_buff *skb; - struct oz_tx_frame *f; - struct list_head *e; - - spin_lock(&pd->tx_frame_lock); - e = pd->last_sent_frame->next; - if (e == &pd->tx_queue) { - spin_unlock(&pd->tx_frame_lock); - return -1; - } - f = list_entry(e, struct oz_tx_frame, link); - - if (f->skb != NULL) { - skb = f->skb; - oz_tx_isoc_free(pd, f); - spin_unlock(&pd->tx_frame_lock); - if (more_data) - oz_set_more_bit(skb); - oz_set_last_pkt_nb(pd, skb); - if ((int)atomic_read(&g_submitted_isoc) < - OZ_MAX_SUBMITTED_ISOC) { - if (dev_queue_xmit(skb) < 0) { - oz_dbg(TX_FRAMES, "Dropping ISOC Frame\n"); - return -1; - } - atomic_inc(&g_submitted_isoc); - oz_dbg(TX_FRAMES, "Sending ISOC Frame, nb_isoc= %d\n", - pd->nb_queued_isoc_frames); - return 0; - } - kfree_skb(skb); - oz_dbg(TX_FRAMES, "Dropping ISOC Frame>\n"); - return -1; - } - - pd->last_sent_frame = e; - skb = oz_build_frame(pd, f); - spin_unlock(&pd->tx_frame_lock); - if (!skb) - return -1; - if (more_data) - oz_set_more_bit(skb); - oz_dbg(TX_FRAMES, "TX frame PN=0x%x\n", f->hdr.pkt_num); - if (dev_queue_xmit(skb) < 0) - return -1; - - return 0; -} - -/* - * Context: softirq-serialized - */ -void oz_send_queued_frames(struct oz_pd *pd, int backlog) -{ - while (oz_prepare_frame(pd, 0) >= 0) - backlog++; - - switch (pd->mode & (OZ_F_ISOC_NO_ELTS | OZ_F_ISOC_ANYTIME)) { - - case OZ_F_ISOC_NO_ELTS: { - backlog += pd->nb_queued_isoc_frames; - if (backlog <= 0) - goto out; - if (backlog > OZ_MAX_SUBMITTED_ISOC) - backlog = OZ_MAX_SUBMITTED_ISOC; - break; - } - case OZ_NO_ELTS_ANYTIME: { - if ((backlog <= 0) && (pd->isoc_sent == 0)) - goto out; - break; - } - default: { - if (backlog <= 0) - goto out; - break; - } - } - while (backlog--) { - if (oz_send_next_queued_frame(pd, backlog) < 0) - break; - } - return; - -out: oz_prepare_frame(pd, 1); - oz_send_next_queued_frame(pd, 0); -} - -/* - * Context: softirq - */ -static int oz_send_isoc_frame(struct oz_pd *pd) -{ - struct sk_buff *skb; - struct net_device *dev = pd->net_dev; - struct oz_hdr *oz_hdr; - struct oz_elt *elt; - struct oz_elt_info *ei; - LIST_HEAD(list); - int total_size = sizeof(struct oz_hdr); - - oz_select_elts_for_tx(&pd->elt_buff, 1, &total_size, - pd->max_tx_size, &list); - if (list_empty(&list)) - return 0; - skb = alloc_skb(total_size + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC); - if (skb == NULL) { - oz_dbg(ON, "Cannot alloc skb\n"); - oz_elt_info_free_chain(&pd->elt_buff, &list); - return -1; - } - skb_reserve(skb, LL_RESERVED_SPACE(dev)); - skb_reset_network_header(skb); - skb->dev = dev; - skb->protocol = htons(OZ_ETHERTYPE); - if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr, - dev->dev_addr, skb->len) < 0) { - kfree_skb(skb); - return -1; - } - oz_hdr = (struct oz_hdr *)skb_put(skb, total_size); - oz_hdr->control = (OZ_PROTOCOL_VERSION<last_pkt_num = pd->trigger_pkt_num & OZ_LAST_PN_MASK; - elt = (struct oz_elt *)(oz_hdr+1); - - list_for_each_entry(ei, &list, link) { - memcpy(elt, ei->data, ei->length); - elt = oz_next_elt(elt); - } - dev_queue_xmit(skb); - oz_elt_info_free_chain(&pd->elt_buff, &list); - return 0; -} - -/* - * Context: softirq-serialized - */ -void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn) -{ - struct oz_tx_frame *f, *tmp = NULL; - u8 diff; - u32 pkt_num; - - LIST_HEAD(list); - - spin_lock(&pd->tx_frame_lock); - list_for_each_entry(f, &pd->tx_queue, link) { - pkt_num = le32_to_cpu(get_unaligned(&f->hdr.pkt_num)); - diff = (lpn - (pkt_num & OZ_LAST_PN_MASK)) & OZ_LAST_PN_MASK; - if ((diff > OZ_LAST_PN_HALF_CYCLE) || (pkt_num == 0)) - break; - oz_dbg(TX_FRAMES, "Releasing pkt_num= %u, nb= %d\n", - pkt_num, pd->nb_queued_frames); - tmp = f; - pd->nb_queued_frames--; - } - if (tmp) - list_cut_position(&list, &pd->tx_queue, &tmp->link); - pd->last_sent_frame = &pd->tx_queue; - spin_unlock(&pd->tx_frame_lock); - - list_for_each_entry_safe(f, tmp, &list, link) - oz_retire_frame(pd, f); -} - -/* - * Precondition: stream_lock must be held. - * Context: softirq - */ -static struct oz_isoc_stream *pd_stream_find(struct oz_pd *pd, u8 ep_num) -{ - struct oz_isoc_stream *st; - - list_for_each_entry(st, &pd->stream_list, link) { - if (st->ep_num == ep_num) - return st; - } - return NULL; -} - -/* - * Context: softirq - */ -int oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num) -{ - struct oz_isoc_stream *st; - - st = kzalloc(sizeof(struct oz_isoc_stream), GFP_ATOMIC); - if (!st) - return -ENOMEM; - st->ep_num = ep_num; - spin_lock_bh(&pd->stream_lock); - if (!pd_stream_find(pd, ep_num)) { - list_add(&st->link, &pd->stream_list); - st = NULL; - } - spin_unlock_bh(&pd->stream_lock); - kfree(st); - return 0; -} - -/* - * Context: softirq or process - */ -static void oz_isoc_stream_free(struct oz_isoc_stream *st) -{ - kfree_skb(st->skb); - kfree(st); -} - -/* - * Context: softirq - */ -int oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num) -{ - struct oz_isoc_stream *st; - - spin_lock_bh(&pd->stream_lock); - st = pd_stream_find(pd, ep_num); - if (st) - list_del(&st->link); - spin_unlock_bh(&pd->stream_lock); - if (st) - oz_isoc_stream_free(st); - return 0; -} - -/* - * Context: any - */ -static void oz_isoc_destructor(struct sk_buff *skb) -{ - atomic_dec(&g_submitted_isoc); -} - -/* - * Context: softirq - */ -int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len) -{ - struct net_device *dev = pd->net_dev; - struct oz_isoc_stream *st; - u8 nb_units = 0; - struct sk_buff *skb = NULL; - struct oz_hdr *oz_hdr = NULL; - int size = 0; - - spin_lock_bh(&pd->stream_lock); - st = pd_stream_find(pd, ep_num); - if (st) { - skb = st->skb; - st->skb = NULL; - nb_units = st->nb_units; - st->nb_units = 0; - oz_hdr = st->oz_hdr; - size = st->size; - } - spin_unlock_bh(&pd->stream_lock); - if (!st) - return 0; - if (!skb) { - /* Allocate enough space for max size frame. */ - skb = alloc_skb(pd->max_tx_size + OZ_ALLOCATED_SPACE(dev), - GFP_ATOMIC); - if (skb == NULL) - return 0; - /* Reserve the head room for lower layers. */ - skb_reserve(skb, LL_RESERVED_SPACE(dev)); - skb_reset_network_header(skb); - skb->dev = dev; - skb->protocol = htons(OZ_ETHERTYPE); - /* For audio packet set priority to AC_VO */ - skb->priority = 0x7; - size = sizeof(struct oz_hdr) + sizeof(struct oz_isoc_large); - oz_hdr = (struct oz_hdr *)skb_put(skb, size); - } - memcpy(skb_put(skb, len), data, len); - size += len; - if (++nb_units < pd->ms_per_isoc) { - spin_lock_bh(&pd->stream_lock); - st->skb = skb; - st->nb_units = nb_units; - st->oz_hdr = oz_hdr; - st->size = size; - spin_unlock_bh(&pd->stream_lock); - } else { - struct oz_hdr oz; - struct oz_isoc_large iso; - - spin_lock_bh(&pd->stream_lock); - iso.frame_number = st->frame_num; - st->frame_num += nb_units; - spin_unlock_bh(&pd->stream_lock); - oz.control = - (OZ_PROTOCOL_VERSION<trigger_pkt_num & OZ_LAST_PN_MASK; - oz.pkt_num = 0; - iso.endpoint = ep_num; - iso.format = OZ_DATA_F_ISOC_LARGE; - iso.ms_data = nb_units; - memcpy(oz_hdr, &oz, sizeof(oz)); - memcpy(oz_hdr+1, &iso, sizeof(iso)); - if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr, - dev->dev_addr, skb->len) < 0) - goto out; - - skb->destructor = oz_isoc_destructor; - /*Queue for Xmit if mode is not ANYTIME*/ - if (!(pd->mode & OZ_F_ISOC_ANYTIME)) { - struct oz_tx_frame *isoc_unit = NULL; - int nb = pd->nb_queued_isoc_frames; - - if (nb >= pd->isoc_latency) { - struct oz_tx_frame *f; - - oz_dbg(TX_FRAMES, "Dropping ISOC Unit nb= %d\n", - nb); - spin_lock(&pd->tx_frame_lock); - list_for_each_entry(f, &pd->tx_queue, link) { - if (f->skb != NULL) { - oz_tx_isoc_free(pd, f); - break; - } - } - spin_unlock(&pd->tx_frame_lock); - } - isoc_unit = oz_tx_frame_alloc(pd); - if (isoc_unit == NULL) - goto out; - isoc_unit->hdr = oz; - isoc_unit->skb = skb; - spin_lock_bh(&pd->tx_frame_lock); - list_add_tail(&isoc_unit->link, &pd->tx_queue); - pd->nb_queued_isoc_frames++; - spin_unlock_bh(&pd->tx_frame_lock); - oz_dbg(TX_FRAMES, - "Added ISOC Frame to Tx Queue isoc_nb= %d, nb= %d\n", - pd->nb_queued_isoc_frames, pd->nb_queued_frames); - return 0; - } - - /*In ANYTIME mode Xmit unit immediately*/ - if (atomic_read(&g_submitted_isoc) < OZ_MAX_SUBMITTED_ISOC) { - atomic_inc(&g_submitted_isoc); - if (dev_queue_xmit(skb) < 0) - return -1; - return 0; - } - -out: kfree_skb(skb); - return -1; - - } - return 0; -} - -/* - * Context: process - */ -void oz_apps_init(void) -{ - int i; - - for (i = 0; i < OZ_NB_APPS; i++) { - if (g_app_if[i].init) - g_app_if[i].init(); - } -} - -/* - * Context: process - */ -void oz_apps_term(void) -{ - int i; - - /* Terminate all the apps. */ - for (i = 0; i < OZ_NB_APPS; i++) { - if (g_app_if[i].term) - g_app_if[i].term(); - } -} - -/* - * Context: softirq-serialized - */ -void oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt) -{ - if (app_id < OZ_NB_APPS && g_app_if[app_id].rx) - g_app_if[app_id].rx(pd, elt); -} - -/* - * Context: softirq or process - */ -void oz_pd_indicate_farewells(struct oz_pd *pd) -{ - struct oz_farewell *f; - const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB]; - - while (1) { - spin_lock_bh(&g_polling_lock); - if (list_empty(&pd->farewell_list)) { - spin_unlock_bh(&g_polling_lock); - break; - } - f = list_first_entry(&pd->farewell_list, - struct oz_farewell, link); - list_del(&f->link); - spin_unlock_bh(&g_polling_lock); - if (ai->farewell) - ai->farewell(pd, f->ep_num, f->report, f->len); - kfree(f); - } -} diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h deleted file mode 100644 index 212fab0d807a..000000000000 --- a/drivers/staging/ozwpan/ozpd.h +++ /dev/null @@ -1,134 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#ifndef _OZPD_H_ -#define _OZPD_H_ - -#include -#include "ozeltbuf.h" - -/* PD state - */ -#define OZ_PD_S_IDLE 0x1 -#define OZ_PD_S_CONNECTED 0x2 -#define OZ_PD_S_SLEEP 0x4 -#define OZ_PD_S_STOPPED 0x8 - -/* Timer event types. - */ -#define OZ_TIMER_TOUT 1 -#define OZ_TIMER_HEARTBEAT 2 -#define OZ_TIMER_STOP 3 - -/* - *External spinlock variable - */ -extern spinlock_t g_polling_lock; - -/* Data structure that hold information on a frame for transmisson. This is - * built when the frame is first transmitted and is used to rebuild the frame - * if a re-transmission is required. - */ -struct oz_tx_frame { - struct list_head link; - struct list_head elt_list; - struct oz_hdr hdr; - struct sk_buff *skb; - int total_size; -}; - -struct oz_isoc_stream { - struct list_head link; - u8 ep_num; - u8 frame_num; - u8 nb_units; - int size; - struct sk_buff *skb; - struct oz_hdr *oz_hdr; -}; - -struct oz_farewell { - struct list_head link; - u8 ep_num; - u8 index; - u8 len; - u8 report[0]; -}; - -/* Data structure that holds information on a specific peripheral device (PD). - */ -struct oz_pd { - struct list_head link; - atomic_t ref_count; - u8 mac_addr[ETH_ALEN]; - unsigned state; - unsigned state_flags; - unsigned send_flags; - u16 total_apps; - u16 paused_apps; - u8 session_id; - u8 param_rsp_status; - u8 pd_info; - u8 isoc_sent; - u32 last_rx_pkt_num; - u32 last_tx_pkt_num; - struct timespec last_rx_timestamp; - u32 trigger_pkt_num; - unsigned long pulse_time; - unsigned long pulse_period; - unsigned long presleep; - unsigned long keep_alive; - struct oz_elt_buf elt_buff; - void *app_ctx[OZ_NB_APPS]; - spinlock_t app_lock[OZ_NB_APPS]; - int max_tx_size; - u8 mode; - u8 ms_per_isoc; - unsigned isoc_latency; - unsigned max_stream_buffering; - int nb_queued_frames; - int nb_queued_isoc_frames; - spinlock_t tx_frame_lock; - struct list_head *last_sent_frame; - struct list_head tx_queue; - struct list_head farewell_list; - spinlock_t stream_lock; - struct list_head stream_list; - struct net_device *net_dev; - struct hrtimer heartbeat; - struct hrtimer timeout; - u8 timeout_type; - struct tasklet_struct heartbeat_tasklet; - struct tasklet_struct timeout_tasklet; - struct work_struct workitem; -}; - -#define OZ_MAX_QUEUED_FRAMES 4 - -struct oz_pd *oz_pd_alloc(const u8 *mac_addr); -void oz_pd_destroy(struct oz_pd *pd); -void oz_pd_get(struct oz_pd *pd); -void oz_pd_put(struct oz_pd *pd); -void oz_pd_set_state(struct oz_pd *pd, unsigned state); -void oz_pd_indicate_farewells(struct oz_pd *pd); -int oz_pd_sleep(struct oz_pd *pd); -void oz_pd_stop(struct oz_pd *pd); -void oz_pd_heartbeat(struct oz_pd *pd, u16 apps); -int oz_services_start(struct oz_pd *pd, u16 apps, int resume); -void oz_services_stop(struct oz_pd *pd, u16 apps, int pause); -int oz_prepare_frame(struct oz_pd *pd, int empty); -void oz_send_queued_frames(struct oz_pd *pd, int backlog); -void oz_retire_tx_frames(struct oz_pd *pd, u8 lpn); -int oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num); -int oz_isoc_stream_delete(struct oz_pd *pd, u8 ep_num); -int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, const u8 *data, int len); -void oz_handle_app_elt(struct oz_pd *pd, u8 app_id, struct oz_elt *elt); -void oz_apps_init(void); -void oz_apps_term(void); - -extern struct kmem_cache *oz_elt_info_cache; -extern struct kmem_cache *oz_tx_frame_cache; - -#endif /* Sentry */ diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c deleted file mode 100644 index 1ba24a2aef83..000000000000 --- a/drivers/staging/ozwpan/ozproto.c +++ /dev/null @@ -1,813 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "ozdbg.h" -#include "ozprotocol.h" -#include "ozeltbuf.h" -#include "ozpd.h" -#include "ozproto.h" -#include "ozusbsvc.h" - -#include "ozappif.h" -#include -#include -#include - -#define OZ_CF_CONN_SUCCESS 1 -#define OZ_CF_CONN_FAILURE 2 - -#define OZ_DO_STOP 1 -#define OZ_DO_SLEEP 2 - -struct oz_binding { - struct packet_type ptype; - char name[OZ_MAX_BINDING_LEN]; - struct list_head link; -}; - -/* - * External variable - */ - -DEFINE_SPINLOCK(g_polling_lock); -/* - * Static external variables. - */ -static LIST_HEAD(g_pd_list); -static LIST_HEAD(g_binding); -static DEFINE_SPINLOCK(g_binding_lock); -static struct sk_buff_head g_rx_queue; -static u8 g_session_id; -static u16 g_apps = 0x1; -static int g_processing_rx; - -struct kmem_cache *oz_elt_info_cache; -struct kmem_cache *oz_tx_frame_cache; - -/* - * Context: softirq-serialized - */ -static u8 oz_get_new_session_id(u8 exclude) -{ - if (++g_session_id == 0) - g_session_id = 1; - if (g_session_id == exclude) { - if (++g_session_id == 0) - g_session_id = 1; - } - return g_session_id; -} - -/* - * Context: softirq-serialized - */ -static void oz_send_conn_rsp(struct oz_pd *pd, u8 status) -{ - struct sk_buff *skb; - struct net_device *dev = pd->net_dev; - struct oz_hdr *oz_hdr; - struct oz_elt *elt; - struct oz_elt_connect_rsp *body; - - int sz = sizeof(struct oz_hdr) + sizeof(struct oz_elt) + - sizeof(struct oz_elt_connect_rsp); - skb = alloc_skb(sz + OZ_ALLOCATED_SPACE(dev), GFP_ATOMIC); - if (skb == NULL) - return; - skb_reserve(skb, LL_RESERVED_SPACE(dev)); - skb_reset_network_header(skb); - oz_hdr = (struct oz_hdr *)skb_put(skb, sz); - elt = (struct oz_elt *)(oz_hdr+1); - body = (struct oz_elt_connect_rsp *)(elt+1); - skb->dev = dev; - skb->protocol = htons(OZ_ETHERTYPE); - /* Fill in device header */ - if (dev_hard_header(skb, dev, OZ_ETHERTYPE, pd->mac_addr, - dev->dev_addr, skb->len) < 0) { - kfree_skb(skb); - return; - } - oz_hdr->control = OZ_PROTOCOL_VERSION<last_pkt_num = 0; - put_unaligned(0, &oz_hdr->pkt_num); - elt->type = OZ_ELT_CONNECT_RSP; - elt->length = sizeof(struct oz_elt_connect_rsp); - memset(body, 0, sizeof(struct oz_elt_connect_rsp)); - body->status = status; - if (status == 0) { - body->mode = pd->mode; - body->session_id = pd->session_id; - put_unaligned(cpu_to_le16(pd->total_apps), &body->apps); - } - oz_dbg(ON, "TX: OZ_ELT_CONNECT_RSP %d", status); - dev_queue_xmit(skb); -} - -/* - * Context: softirq-serialized - */ -static void pd_set_keepalive(struct oz_pd *pd, u8 kalive) -{ - unsigned long keep_alive = kalive & OZ_KALIVE_VALUE_MASK; - - switch (kalive & OZ_KALIVE_TYPE_MASK) { - case OZ_KALIVE_SPECIAL: - pd->keep_alive = keep_alive * 1000*60*60*24*20; - break; - case OZ_KALIVE_SECS: - pd->keep_alive = keep_alive*1000; - break; - case OZ_KALIVE_MINS: - pd->keep_alive = keep_alive*1000*60; - break; - case OZ_KALIVE_HOURS: - pd->keep_alive = keep_alive*1000*60*60; - break; - default: - pd->keep_alive = 0; - } - oz_dbg(ON, "Keepalive = %lu mSec\n", pd->keep_alive); -} - -/* - * Context: softirq-serialized - */ -static void pd_set_presleep(struct oz_pd *pd, u8 presleep, u8 start_timer) -{ - if (presleep) - pd->presleep = presleep*100; - else - pd->presleep = OZ_PRESLEEP_TOUT; - if (start_timer) { - spin_unlock(&g_polling_lock); - oz_timer_add(pd, OZ_TIMER_TOUT, pd->presleep); - spin_lock(&g_polling_lock); - } - oz_dbg(ON, "Presleep time = %lu mSec\n", pd->presleep); -} - -/* - * Context: softirq-serialized - */ -static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt, - const u8 *pd_addr, struct net_device *net_dev) -{ - struct oz_pd *pd; - struct oz_elt_connect_req *body = - (struct oz_elt_connect_req *)(elt+1); - u8 rsp_status = OZ_STATUS_SUCCESS; - u8 stop_needed = 0; - u16 new_apps = g_apps; - struct net_device *old_net_dev = NULL; - struct oz_pd *free_pd = NULL; - - if (cur_pd) { - pd = cur_pd; - spin_lock_bh(&g_polling_lock); - } else { - struct oz_pd *pd2 = NULL; - struct list_head *e; - - pd = oz_pd_alloc(pd_addr); - if (pd == NULL) - return NULL; - getnstimeofday(&pd->last_rx_timestamp); - spin_lock_bh(&g_polling_lock); - list_for_each(e, &g_pd_list) { - pd2 = list_entry(e, struct oz_pd, link); - if (ether_addr_equal(pd2->mac_addr, pd_addr)) { - free_pd = pd; - pd = pd2; - break; - } - } - if (pd != pd2) - list_add_tail(&pd->link, &g_pd_list); - } - if (pd == NULL) { - spin_unlock_bh(&g_polling_lock); - return NULL; - } - if (pd->net_dev != net_dev) { - old_net_dev = pd->net_dev; - dev_hold(net_dev); - pd->net_dev = net_dev; - } - oz_dbg(ON, "Host vendor: %d\n", body->host_vendor); - pd->max_tx_size = OZ_MAX_TX_SIZE; - pd->mode = body->mode; - pd->pd_info = body->pd_info; - if (pd->mode & OZ_F_ISOC_NO_ELTS) { - pd->ms_per_isoc = body->ms_per_isoc; - if (!pd->ms_per_isoc) - pd->ms_per_isoc = 4; - - switch (body->ms_isoc_latency & OZ_LATENCY_MASK) { - case OZ_ONE_MS_LATENCY: - pd->isoc_latency = (body->ms_isoc_latency & - ~OZ_LATENCY_MASK) / pd->ms_per_isoc; - break; - case OZ_TEN_MS_LATENCY: - pd->isoc_latency = ((body->ms_isoc_latency & - ~OZ_LATENCY_MASK) * 10) / pd->ms_per_isoc; - break; - default: - pd->isoc_latency = OZ_MAX_TX_QUEUE_ISOC; - } - } - if (body->max_len_div16) - pd->max_tx_size = ((u16)body->max_len_div16)<<4; - oz_dbg(ON, "Max frame:%u Ms per isoc:%u\n", - pd->max_tx_size, pd->ms_per_isoc); - pd->max_stream_buffering = 3*1024; - pd->pulse_period = OZ_QUANTUM; - pd_set_presleep(pd, body->presleep, 0); - pd_set_keepalive(pd, body->keep_alive); - - new_apps &= le16_to_cpu(get_unaligned(&body->apps)); - if ((new_apps & 0x1) && (body->session_id)) { - if (pd->session_id) { - if (pd->session_id != body->session_id) { - rsp_status = OZ_STATUS_SESSION_MISMATCH; - goto done; - } - } else { - new_apps &= ~0x1; /* Resume not permitted */ - pd->session_id = - oz_get_new_session_id(body->session_id); - } - } else { - if (pd->session_id && !body->session_id) { - rsp_status = OZ_STATUS_SESSION_TEARDOWN; - stop_needed = 1; - } else { - new_apps &= ~0x1; /* Resume not permitted */ - pd->session_id = - oz_get_new_session_id(body->session_id); - } - } -done: - if (rsp_status == OZ_STATUS_SUCCESS) { - u16 start_apps = new_apps & ~pd->total_apps & ~0x1; - u16 stop_apps = pd->total_apps & ~new_apps & ~0x1; - u16 resume_apps = new_apps & pd->paused_apps & ~0x1; - - spin_unlock_bh(&g_polling_lock); - oz_pd_set_state(pd, OZ_PD_S_CONNECTED); - oz_dbg(ON, "new_apps=0x%x total_apps=0x%x paused_apps=0x%x\n", - new_apps, pd->total_apps, pd->paused_apps); - if (start_apps) { - if (oz_services_start(pd, start_apps, 0)) - rsp_status = OZ_STATUS_TOO_MANY_PDS; - } - if (resume_apps) - if (oz_services_start(pd, resume_apps, 1)) - rsp_status = OZ_STATUS_TOO_MANY_PDS; - if (stop_apps) - oz_services_stop(pd, stop_apps, 0); - oz_pd_request_heartbeat(pd); - } else { - spin_unlock_bh(&g_polling_lock); - } - oz_send_conn_rsp(pd, rsp_status); - if (rsp_status != OZ_STATUS_SUCCESS) { - if (stop_needed) - oz_pd_stop(pd); - oz_pd_put(pd); - pd = NULL; - } - if (old_net_dev) - dev_put(old_net_dev); - if (free_pd) - oz_pd_destroy(free_pd); - return pd; -} - -/* - * Context: softirq-serialized - */ -static void oz_add_farewell(struct oz_pd *pd, u8 ep_num, u8 index, - const u8 *report, u8 len) -{ - struct oz_farewell *f; - struct oz_farewell *f2; - int found = 0; - - f = kmalloc(sizeof(struct oz_farewell) + len, GFP_ATOMIC); - if (!f) - return; - f->ep_num = ep_num; - f->index = index; - f->len = len; - memcpy(f->report, report, len); - oz_dbg(ON, "RX: Adding farewell report\n"); - spin_lock(&g_polling_lock); - list_for_each_entry(f2, &pd->farewell_list, link) { - if ((f2->ep_num == ep_num) && (f2->index == index)) { - found = 1; - list_del(&f2->link); - break; - } - } - list_add_tail(&f->link, &pd->farewell_list); - spin_unlock(&g_polling_lock); - if (found) - kfree(f2); -} - -/* - * Context: softirq-serialized - */ -static void oz_rx_frame(struct sk_buff *skb) -{ - u8 *mac_hdr; - u8 *src_addr; - struct oz_elt *elt; - int length; - struct oz_pd *pd = NULL; - struct oz_hdr *oz_hdr = (struct oz_hdr *)skb_network_header(skb); - struct timespec current_time; - int dup = 0; - u32 pkt_num; - - oz_dbg(RX_FRAMES, "RX frame PN=0x%x LPN=0x%x control=0x%x\n", - oz_hdr->pkt_num, oz_hdr->last_pkt_num, oz_hdr->control); - mac_hdr = skb_mac_header(skb); - src_addr = &mac_hdr[ETH_ALEN]; - length = skb->len; - - /* Check the version field */ - if (oz_get_prot_ver(oz_hdr->control) != OZ_PROTOCOL_VERSION) { - oz_dbg(ON, "Incorrect protocol version: %d\n", - oz_get_prot_ver(oz_hdr->control)); - goto done; - } - - pkt_num = le32_to_cpu(get_unaligned(&oz_hdr->pkt_num)); - - pd = oz_pd_find(src_addr); - if (pd) { - if (!(pd->state & OZ_PD_S_CONNECTED)) - oz_pd_set_state(pd, OZ_PD_S_CONNECTED); - getnstimeofday(¤t_time); - if ((current_time.tv_sec != pd->last_rx_timestamp.tv_sec) || - (pd->presleep < MSEC_PER_SEC)) { - oz_timer_add(pd, OZ_TIMER_TOUT, pd->presleep); - pd->last_rx_timestamp = current_time; - } - if (pkt_num != pd->last_rx_pkt_num) { - pd->last_rx_pkt_num = pkt_num; - } else { - dup = 1; - oz_dbg(ON, "Duplicate frame\n"); - } - } - - if (pd && !dup && ((pd->mode & OZ_MODE_MASK) == OZ_MODE_TRIGGERED)) { - oz_dbg(RX_FRAMES, "Received TRIGGER Frame\n"); - pd->last_sent_frame = &pd->tx_queue; - if (oz_hdr->control & OZ_F_ACK) { - /* Retire completed frames */ - oz_retire_tx_frames(pd, oz_hdr->last_pkt_num); - } - if ((oz_hdr->control & OZ_F_ACK_REQUESTED) && - (pd->state == OZ_PD_S_CONNECTED)) { - int backlog = pd->nb_queued_frames; - - pd->trigger_pkt_num = pkt_num; - /* Send queued frames */ - oz_send_queued_frames(pd, backlog); - } - } - - length -= sizeof(struct oz_hdr); - elt = (struct oz_elt *)((u8 *)oz_hdr + sizeof(struct oz_hdr)); - - while (length >= sizeof(struct oz_elt)) { - length -= sizeof(struct oz_elt) + elt->length; - if (length < 0) - break; - switch (elt->type) { - case OZ_ELT_CONNECT_REQ: - oz_dbg(ON, "RX: OZ_ELT_CONNECT_REQ\n"); - pd = oz_connect_req(pd, elt, src_addr, skb->dev); - break; - case OZ_ELT_DISCONNECT: - oz_dbg(ON, "RX: OZ_ELT_DISCONNECT\n"); - if (pd) - oz_pd_sleep(pd); - break; - case OZ_ELT_UPDATE_PARAM_REQ: { - struct oz_elt_update_param *body = - (struct oz_elt_update_param *)(elt + 1); - oz_dbg(ON, "RX: OZ_ELT_UPDATE_PARAM_REQ\n"); - if (pd && (pd->state & OZ_PD_S_CONNECTED)) { - spin_lock(&g_polling_lock); - pd_set_keepalive(pd, body->keepalive); - pd_set_presleep(pd, body->presleep, 1); - spin_unlock(&g_polling_lock); - } - } - break; - case OZ_ELT_FAREWELL_REQ: { - struct oz_elt_farewell *body = - (struct oz_elt_farewell *)(elt + 1); - oz_dbg(ON, "RX: OZ_ELT_FAREWELL_REQ\n"); - oz_add_farewell(pd, body->ep_num, - body->index, body->report, - elt->length + 1 - sizeof(*body)); - } - break; - case OZ_ELT_APP_DATA: - if (pd && (pd->state & OZ_PD_S_CONNECTED)) { - struct oz_app_hdr *app_hdr = - (struct oz_app_hdr *)(elt+1); - if (dup) - break; - oz_handle_app_elt(pd, app_hdr->app_id, elt); - } - break; - default: - oz_dbg(ON, "RX: Unknown elt %02x\n", elt->type); - } - elt = oz_next_elt(elt); - } -done: - if (pd) - oz_pd_put(pd); - consume_skb(skb); -} - -/* - * Context: process - */ -void oz_protocol_term(void) -{ - struct oz_binding *b, *t; - - /* Walk the list of bindings and remove each one. - */ - spin_lock_bh(&g_binding_lock); - list_for_each_entry_safe(b, t, &g_binding, link) { - list_del(&b->link); - spin_unlock_bh(&g_binding_lock); - dev_remove_pack(&b->ptype); - if (b->ptype.dev) - dev_put(b->ptype.dev); - kfree(b); - spin_lock_bh(&g_binding_lock); - } - spin_unlock_bh(&g_binding_lock); - /* Walk the list of PDs and stop each one. This causes the PD to be - * removed from the list so we can just pull each one from the head - * of the list. - */ - spin_lock_bh(&g_polling_lock); - while (!list_empty(&g_pd_list)) { - struct oz_pd *pd = - list_first_entry(&g_pd_list, struct oz_pd, link); - oz_pd_get(pd); - spin_unlock_bh(&g_polling_lock); - oz_pd_stop(pd); - oz_pd_put(pd); - spin_lock_bh(&g_polling_lock); - } - spin_unlock_bh(&g_polling_lock); - oz_dbg(ON, "Protocol stopped\n"); - - kmem_cache_destroy(oz_tx_frame_cache); - kmem_cache_destroy(oz_elt_info_cache); -} - -/* - * Context: softirq - */ -void oz_pd_heartbeat_handler(unsigned long data) -{ - struct oz_pd *pd = (struct oz_pd *)data; - u16 apps = 0; - - spin_lock_bh(&g_polling_lock); - if (pd->state & OZ_PD_S_CONNECTED) - apps = pd->total_apps; - spin_unlock_bh(&g_polling_lock); - if (apps) - oz_pd_heartbeat(pd, apps); - oz_pd_put(pd); -} - -/* - * Context: softirq - */ -void oz_pd_timeout_handler(unsigned long data) -{ - int type; - struct oz_pd *pd = (struct oz_pd *)data; - - spin_lock_bh(&g_polling_lock); - type = pd->timeout_type; - spin_unlock_bh(&g_polling_lock); - switch (type) { - case OZ_TIMER_TOUT: - oz_pd_sleep(pd); - break; - case OZ_TIMER_STOP: - oz_pd_stop(pd); - break; - } - oz_pd_put(pd); -} - -/* - * Context: Interrupt - */ -enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer) -{ - struct oz_pd *pd; - - pd = container_of(timer, struct oz_pd, heartbeat); - hrtimer_forward_now(timer, ktime_set(pd->pulse_period / - MSEC_PER_SEC, (pd->pulse_period % MSEC_PER_SEC) * NSEC_PER_MSEC)); - oz_pd_get(pd); - tasklet_schedule(&pd->heartbeat_tasklet); - return HRTIMER_RESTART; -} - -/* - * Context: Interrupt - */ -enum hrtimer_restart oz_pd_timeout_event(struct hrtimer *timer) -{ - struct oz_pd *pd; - - pd = container_of(timer, struct oz_pd, timeout); - oz_pd_get(pd); - tasklet_schedule(&pd->timeout_tasklet); - return HRTIMER_NORESTART; -} - -/* - * Context: softirq or process - */ -void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time) -{ - spin_lock_bh(&g_polling_lock); - switch (type) { - case OZ_TIMER_TOUT: - case OZ_TIMER_STOP: - if (hrtimer_active(&pd->timeout)) { - hrtimer_set_expires(&pd->timeout, ktime_set(due_time / - MSEC_PER_SEC, (due_time % MSEC_PER_SEC) * - NSEC_PER_MSEC)); - hrtimer_start_expires(&pd->timeout, HRTIMER_MODE_REL); - } else { - hrtimer_start(&pd->timeout, ktime_set(due_time / - MSEC_PER_SEC, (due_time % MSEC_PER_SEC) * - NSEC_PER_MSEC), HRTIMER_MODE_REL); - } - pd->timeout_type = type; - break; - case OZ_TIMER_HEARTBEAT: - if (!hrtimer_active(&pd->heartbeat)) - hrtimer_start(&pd->heartbeat, ktime_set(due_time / - MSEC_PER_SEC, (due_time % MSEC_PER_SEC) * - NSEC_PER_MSEC), HRTIMER_MODE_REL); - break; - } - spin_unlock_bh(&g_polling_lock); -} - -/* - * Context: softirq or process - */ -void oz_pd_request_heartbeat(struct oz_pd *pd) -{ - oz_timer_add(pd, OZ_TIMER_HEARTBEAT, pd->pulse_period > 0 ? - pd->pulse_period : OZ_QUANTUM); -} - -/* - * Context: softirq or process - */ -struct oz_pd *oz_pd_find(const u8 *mac_addr) -{ - struct oz_pd *pd; - - spin_lock_bh(&g_polling_lock); - list_for_each_entry(pd, &g_pd_list, link) { - if (ether_addr_equal(pd->mac_addr, mac_addr)) { - oz_pd_get(pd); - spin_unlock_bh(&g_polling_lock); - return pd; - } - } - spin_unlock_bh(&g_polling_lock); - return NULL; -} - -/* - * Context: process - */ -void oz_app_enable(int app_id, int enable) -{ - if (app_id < OZ_NB_APPS) { - spin_lock_bh(&g_polling_lock); - if (enable) - g_apps |= (1<ptype.type = htons(OZ_ETHERTYPE); - binding->ptype.func = oz_pkt_recv; - if (net_dev && *net_dev) { - memcpy(binding->name, net_dev, OZ_MAX_BINDING_LEN); - oz_dbg(ON, "Adding binding: %s\n", net_dev); - binding->ptype.dev = dev_get_by_name(&init_net, net_dev); - if (binding->ptype.dev == NULL) { - oz_dbg(ON, "Netdev %s not found\n", net_dev); - kfree(binding); - return; - } - } - dev_add_pack(&binding->ptype); - spin_lock_bh(&g_binding_lock); - list_add_tail(&binding->link, &g_binding); - spin_unlock_bh(&g_binding_lock); -} - -/* - * Context: process - */ -static void pd_stop_all_for_device(struct net_device *net_dev) -{ - LIST_HEAD(h); - struct oz_pd *pd; - struct oz_pd *n; - - spin_lock_bh(&g_polling_lock); - list_for_each_entry_safe(pd, n, &g_pd_list, link) { - if (pd->net_dev == net_dev) { - list_move(&pd->link, &h); - oz_pd_get(pd); - } - } - spin_unlock_bh(&g_polling_lock); - while (!list_empty(&h)) { - pd = list_first_entry(&h, struct oz_pd, link); - oz_pd_stop(pd); - oz_pd_put(pd); - } -} - -/* - * Context: process - */ -void oz_binding_remove(const char *net_dev) -{ - struct oz_binding *binding; - int found = 0; - - oz_dbg(ON, "Removing binding: %s\n", net_dev); - spin_lock_bh(&g_binding_lock); - list_for_each_entry(binding, &g_binding, link) { - if (strncmp(binding->name, net_dev, OZ_MAX_BINDING_LEN) == 0) { - oz_dbg(ON, "Binding '%s' found\n", net_dev); - found = 1; - break; - } - } - spin_unlock_bh(&g_binding_lock); - if (found) { - dev_remove_pack(&binding->ptype); - if (binding->ptype.dev) { - dev_put(binding->ptype.dev); - pd_stop_all_for_device(binding->ptype.dev); - } - list_del(&binding->link); - kfree(binding); - } -} - -/* - * Context: process - */ -static char *oz_get_next_device_name(char *s, char *dname, int max_size) -{ - while (*s == ',') - s++; - while (*s && (*s != ',') && max_size > 1) { - *dname++ = *s++; - max_size--; - } - *dname = 0; - return s; -} - -/* - * Context: process - */ -int oz_protocol_init(char *devs) -{ - oz_elt_info_cache = KMEM_CACHE(oz_elt_info, 0); - if (!oz_elt_info_cache) - return -ENOMEM; - - oz_tx_frame_cache = KMEM_CACHE(oz_tx_frame, 0); - if (!oz_tx_frame_cache) { - kmem_cache_destroy(oz_elt_info_cache); - return -ENOMEM; - } - - skb_queue_head_init(&g_rx_queue); - if (devs[0] == '*') { - oz_binding_add(NULL); - } else { - char d[32]; - - while (*devs) { - devs = oz_get_next_device_name(devs, d, sizeof(d)); - if (d[0]) - oz_binding_add(d); - } - } - return 0; -} - -/* - * Context: process - */ -int oz_get_pd_list(struct oz_mac_addr *addr, int max_count) -{ - struct oz_pd *pd; - int count = 0; - - spin_lock_bh(&g_polling_lock); - list_for_each_entry(pd, &g_pd_list, link) { - if (count >= max_count) - break; - ether_addr_copy((u8 *)&addr[count++], pd->mac_addr); - } - spin_unlock_bh(&g_polling_lock); - return count; -} - diff --git a/drivers/staging/ozwpan/ozproto.h b/drivers/staging/ozwpan/ozproto.h deleted file mode 100644 index 30c2db91c000..000000000000 --- a/drivers/staging/ozwpan/ozproto.h +++ /dev/null @@ -1,62 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#ifndef _OZPROTO_H -#define _OZPROTO_H - -#include -#include "ozdbg.h" -#include "ozappif.h" - -#define OZ_ALLOCATED_SPACE(__x) (LL_RESERVED_SPACE(__x)+(__x)->needed_tailroom) - -/* Quantum in MS */ -#define OZ_QUANTUM 8 -/* Default timeouts. - */ -#define OZ_PRESLEEP_TOUT 11 - -/* Maximun sizes of tx frames. */ -#define OZ_MAX_TX_SIZE 760 - -/* Maximum number of uncompleted isoc frames that can be pending in network. */ -#define OZ_MAX_SUBMITTED_ISOC 16 - -/* Maximum number of uncompleted isoc frames that can be pending in Tx Queue. */ -#define OZ_MAX_TX_QUEUE_ISOC 32 - -/* Application handler functions. - */ -struct oz_app_if { - int (*init)(void); - void (*term)(void); - int (*start)(struct oz_pd *pd, int resume); - void (*stop)(struct oz_pd *pd, int pause); - void (*rx)(struct oz_pd *pd, struct oz_elt *elt); - int (*heartbeat)(struct oz_pd *pd); - void (*farewell)(struct oz_pd *pd, u8 ep_num, u8 *data, u8 len); -}; - -int oz_protocol_init(char *devs); -void oz_protocol_term(void); -int oz_get_pd_list(struct oz_mac_addr *addr, int max_count); -void oz_app_enable(int app_id, int enable); -struct oz_pd *oz_pd_find(const u8 *mac_addr); -void oz_binding_add(const char *net_dev); -void oz_binding_remove(const char *net_dev); -void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time); -void oz_timer_delete(struct oz_pd *pd, int type); -void oz_pd_request_heartbeat(struct oz_pd *pd); -void oz_pd_heartbeat_handler(unsigned long data); -void oz_pd_timeout_handler(unsigned long data); -enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer); -enum hrtimer_restart oz_pd_timeout_event(struct hrtimer *timer); -int oz_get_pd_status_list(char *pd_list, int max_count); -int oz_get_binding_list(char *buf, int max_if); - -extern struct kmem_cache *oz_elt_info_cache; -extern struct kmem_cache *oz_tx_frame_cache; - -#endif /* _OZPROTO_H */ diff --git a/drivers/staging/ozwpan/ozprotocol.h b/drivers/staging/ozwpan/ozprotocol.h deleted file mode 100644 index 4642072596da..000000000000 --- a/drivers/staging/ozwpan/ozprotocol.h +++ /dev/null @@ -1,375 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#ifndef _OZPROTOCOL_H -#define _OZPROTOCOL_H - -#define PACKED __packed - -#define OZ_ETHERTYPE 0x892e - -/* Status codes - */ -#define OZ_STATUS_SUCCESS 0 -#define OZ_STATUS_INVALID_PARAM 1 -#define OZ_STATUS_TOO_MANY_PDS 2 -#define OZ_STATUS_NOT_ALLOWED 4 -#define OZ_STATUS_SESSION_MISMATCH 5 -#define OZ_STATUS_SESSION_TEARDOWN 6 - -/* This is the generic element header. - Every element starts with this. - */ -struct oz_elt { - u8 type; - u8 length; -} PACKED; - -#define oz_next_elt(__elt) \ - (struct oz_elt *)((u8 *)((__elt) + 1) + (__elt)->length) - -/* Protocol element IDs. - */ -#define OZ_ELT_CONNECT_REQ 0x06 -#define OZ_ELT_CONNECT_RSP 0x07 -#define OZ_ELT_DISCONNECT 0x08 -#define OZ_ELT_UPDATE_PARAM_REQ 0x11 -#define OZ_ELT_FAREWELL_REQ 0x12 -#define OZ_ELT_APP_DATA 0x31 - -/* This is the Ozmo header which is the first Ozmo specific part - * of a frame and comes after the MAC header. - */ -struct oz_hdr { - u8 control; - u8 last_pkt_num; - u32 pkt_num; -} PACKED; - -#define OZ_PROTOCOL_VERSION 0x1 -/* Bits in the control field. */ -#define OZ_VERSION_MASK 0xc -#define OZ_VERSION_SHIFT 2 -#define OZ_F_ACK 0x10 -#define OZ_F_ISOC 0x20 -#define OZ_F_MORE_DATA 0x40 -#define OZ_F_ACK_REQUESTED 0x80 - -#define oz_get_prot_ver(__x) (((__x) & OZ_VERSION_MASK) >> OZ_VERSION_SHIFT) - -/* Used to select the bits of packet number to put in the last_pkt_num. - */ -#define OZ_LAST_PN_MASK 0x00ff - -#define OZ_LAST_PN_HALF_CYCLE 127 - -#define OZ_LATENCY_MASK 0xc0 -#define OZ_ONE_MS_LATENCY 0x40 -#define OZ_TEN_MS_LATENCY 0x80 - -/* Connect request data structure. - */ -struct oz_elt_connect_req { - u8 mode; - u8 resv1[16]; - u8 pd_info; - u8 session_id; - u8 presleep; - u8 ms_isoc_latency; - u8 host_vendor; - u8 keep_alive; - u16 apps; - u8 max_len_div16; - u8 ms_per_isoc; - u8 resv3[2]; -} PACKED; - -/* mode field bits. - */ -#define OZ_MODE_POLLED 0x0 -#define OZ_MODE_TRIGGERED 0x1 -#define OZ_MODE_MASK 0xf -#define OZ_F_ISOC_NO_ELTS 0x40 -#define OZ_F_ISOC_ANYTIME 0x80 -#define OZ_NO_ELTS_ANYTIME 0xc0 - -/* Keep alive field. - */ -#define OZ_KALIVE_TYPE_MASK 0xc0 -#define OZ_KALIVE_VALUE_MASK 0x3f -#define OZ_KALIVE_SPECIAL 0x00 -#define OZ_KALIVE_SECS 0x40 -#define OZ_KALIVE_MINS 0x80 -#define OZ_KALIVE_HOURS 0xc0 - -/* Connect response data structure. - */ -struct oz_elt_connect_rsp { - u8 mode; - u8 status; - u8 resv1[3]; - u8 session_id; - u16 apps; - u32 resv2; -} PACKED; - -struct oz_elt_farewell { - u8 ep_num; - u8 index; - u8 report[1]; -} PACKED; - -struct oz_elt_update_param { - u8 resv1[16]; - u8 presleep; - u8 resv2; - u8 host_vendor; - u8 keepalive; -} PACKED; - -/* Header common to all application elements. - */ -struct oz_app_hdr { - u8 app_id; - u8 elt_seq_num; -} PACKED; - -/* Values for app_id. - */ -#define OZ_APPID_USB 0x1 -#define OZ_APPID_SERIAL 0x4 -#define OZ_APPID_MAX OZ_APPID_SERIAL -#define OZ_NB_APPS (OZ_APPID_MAX+1) - -/* USB header common to all elements for the USB application. - * This header extends the oz_app_hdr and comes directly after - * the element header in a USB application. - */ -struct oz_usb_hdr { - u8 app_id; - u8 elt_seq_num; - u8 type; -} PACKED; - - - -/* USB requests element subtypes (type field of hs_usb_hdr). - */ -#define OZ_GET_DESC_REQ 1 -#define OZ_GET_DESC_RSP 2 -#define OZ_SET_CONFIG_REQ 3 -#define OZ_SET_CONFIG_RSP 4 -#define OZ_SET_INTERFACE_REQ 5 -#define OZ_SET_INTERFACE_RSP 6 -#define OZ_VENDOR_CLASS_REQ 7 -#define OZ_VENDOR_CLASS_RSP 8 -#define OZ_GET_STATUS_REQ 9 -#define OZ_GET_STATUS_RSP 10 -#define OZ_CLEAR_FEATURE_REQ 11 -#define OZ_CLEAR_FEATURE_RSP 12 -#define OZ_SET_FEATURE_REQ 13 -#define OZ_SET_FEATURE_RSP 14 -#define OZ_GET_CONFIGURATION_REQ 15 -#define OZ_GET_CONFIGURATION_RSP 16 -#define OZ_GET_INTERFACE_REQ 17 -#define OZ_GET_INTERFACE_RSP 18 -#define OZ_SYNCH_FRAME_REQ 19 -#define OZ_SYNCH_FRAME_RSP 20 -#define OZ_USB_ENDPOINT_DATA 23 - -#define OZ_REQD_D2H 0x80 - -struct oz_get_desc_req { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - u16 offset; - u16 size; - u8 req_type; - u8 desc_type; - __le16 w_index; - u8 index; -} PACKED; - -/* Values for desc_type field. -*/ -#define OZ_DESC_DEVICE 0x01 -#define OZ_DESC_CONFIG 0x02 -#define OZ_DESC_STRING 0x03 - -/* Values for req_type field. - */ -#define OZ_RECP_MASK 0x1F -#define OZ_RECP_DEVICE 0x00 -#define OZ_RECP_INTERFACE 0x01 -#define OZ_RECP_ENDPOINT 0x02 - -#define OZ_REQT_MASK 0x60 -#define OZ_REQT_STD 0x00 -#define OZ_REQT_CLASS 0x20 -#define OZ_REQT_VENDOR 0x40 - -struct oz_get_desc_rsp { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - __le16 offset; - __le16 total_size; - u8 rcode; - u8 data[1]; -} PACKED; - -struct oz_feature_req { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - u8 recipient; - u8 index; - u16 feature; -} PACKED; - -struct oz_feature_rsp { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - u8 rcode; -} PACKED; - -struct oz_set_config_req { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - u8 index; -} PACKED; - -struct oz_set_config_rsp { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - u8 rcode; -} PACKED; - -struct oz_set_interface_req { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - u8 index; - u8 alternative; -} PACKED; - -struct oz_set_interface_rsp { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - u8 rcode; -} PACKED; - -struct oz_get_interface_req { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - u8 index; -} PACKED; - -struct oz_get_interface_rsp { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - u8 rcode; - u8 alternative; -} PACKED; - -struct oz_vendor_class_req { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - u8 req_type; - u8 request; - u16 value; - u16 index; - u8 data[1]; -} PACKED; - -struct oz_vendor_class_rsp { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 req_id; - u8 rcode; - u8 data[1]; -} PACKED; - -struct oz_data { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 endpoint; - u8 format; -} PACKED; - -struct oz_isoc_fixed { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 endpoint; - u8 format; - u8 unit_size; - u8 frame_number; - u8 data[1]; -} PACKED; - -struct oz_multiple_fixed { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 endpoint; - u8 format; - u8 unit_size; - u8 data[1]; -} PACKED; - -struct oz_fragmented { - u8 app_id; - u8 elt_seq_num; - u8 type; - u8 endpoint; - u8 format; - u16 total_size; - u16 offset; - u8 data[1]; -} PACKED; - -/* Note: the following does not get packaged in an element in the same way - * that other data formats are packaged. Instead the data is put in a frame - * directly after the oz_header and is the only permitted data in such a - * frame. The length of the data is directly determined from the frame size. - */ -struct oz_isoc_large { - u8 endpoint; - u8 format; - u8 ms_data; - u8 frame_number; -} PACKED; - -#define OZ_DATA_F_TYPE_MASK 0xF -#define OZ_DATA_F_MULTIPLE_FIXED 0x1 -#define OZ_DATA_F_MULTIPLE_VAR 0x2 -#define OZ_DATA_F_ISOC_FIXED 0x3 -#define OZ_DATA_F_ISOC_VAR 0x4 -#define OZ_DATA_F_FRAGMENTED 0x5 -#define OZ_DATA_F_ISOC_LARGE 0x7 - -#endif /* _OZPROTOCOL_H */ diff --git a/drivers/staging/ozwpan/ozurbparanoia.c b/drivers/staging/ozwpan/ozurbparanoia.c deleted file mode 100644 index cf6278a198a8..000000000000 --- a/drivers/staging/ozwpan/ozurbparanoia.c +++ /dev/null @@ -1,54 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#include -#include "ozdbg.h" - -#ifdef WANT_URB_PARANOIA - -#include "ozurbparanoia.h" - -#define OZ_MAX_URBS 1000 -struct urb *g_urb_memory[OZ_MAX_URBS]; -int g_nb_urbs; -DEFINE_SPINLOCK(g_urb_mem_lock); - -void oz_remember_urb(struct urb *urb) -{ - unsigned long irq_state; - - spin_lock_irqsave(&g_urb_mem_lock, irq_state); - if (g_nb_urbs < OZ_MAX_URBS) { - g_urb_memory[g_nb_urbs++] = urb; - oz_dbg(ON, "urb up = %d %p\n", g_nb_urbs, urb); - } else { - oz_dbg(ON, "ERROR urb buffer full\n"); - } - spin_unlock_irqrestore(&g_urb_mem_lock, irq_state); -} - -/* - */ -int oz_forget_urb(struct urb *urb) -{ - unsigned long irq_state; - int i; - int rc = -1; - - spin_lock_irqsave(&g_urb_mem_lock, irq_state); - for (i = 0; i < g_nb_urbs; i++) { - if (g_urb_memory[i] == urb) { - rc = 0; - if (--g_nb_urbs > i) - memcpy(&g_urb_memory[i], &g_urb_memory[i+1], - (g_nb_urbs - i) * sizeof(struct urb *)); - oz_dbg(ON, "urb down = %d %p\n", g_nb_urbs, urb); - } - } - spin_unlock_irqrestore(&g_urb_mem_lock, irq_state); - return rc; -} -#endif /* #ifdef WANT_URB_PARANOIA */ - diff --git a/drivers/staging/ozwpan/ozurbparanoia.h b/drivers/staging/ozwpan/ozurbparanoia.h deleted file mode 100644 index 5080ea76f507..000000000000 --- a/drivers/staging/ozwpan/ozurbparanoia.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _OZURBPARANOIA_H -#define _OZURBPARANOIA_H -/* ----------------------------------------------------------------------------- - * Released under the GNU General Public License Version 2 (GPLv2). - * Copyright (c) 2011 Ozmo Inc - * ----------------------------------------------------------------------------- - */ - -#ifdef WANT_URB_PARANOIA -void oz_remember_urb(struct urb *urb); -int oz_forget_urb(struct urb *urb); -#else -static inline void oz_remember_urb(struct urb *urb) {} -static inline int oz_forget_urb(struct urb *urb) { return 0; } -#endif /* WANT_URB_PARANOIA */ - - -#endif /* _OZURBPARANOIA_H */ - diff --git a/drivers/staging/ozwpan/ozusbif.h b/drivers/staging/ozwpan/ozusbif.h deleted file mode 100644 index d2a6085345be..000000000000 --- a/drivers/staging/ozwpan/ozusbif.h +++ /dev/null @@ -1,43 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#ifndef _OZUSBIF_H -#define _OZUSBIF_H - -#include - -/* Reference counting functions. - */ -void oz_usb_get(void *hpd); -void oz_usb_put(void *hpd); - -/* Stream functions. - */ -int oz_usb_stream_create(void *hpd, u8 ep_num); -int oz_usb_stream_delete(void *hpd, u8 ep_num); - -/* Request functions. - */ -int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup, - const u8 *data, int data_len); -int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type, - u8 index, __le16 windex, int offset, int len); -int oz_usb_send_isoc(void *hpd, u8 ep_num, struct urb *urb); -void oz_usb_request_heartbeat(void *hpd); - -/* Confirmation functions. - */ -void oz_hcd_get_desc_cnf(void *hport, u8 req_id, u8 status, - const u8 *desc, u8 length, u16 offset, u16 total_size); -void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, - const u8 *data, int data_len); - -/* Indication functions. - */ -void oz_hcd_data_ind(void *hport, u8 endpoint, const u8 *data, int data_len); - -int oz_hcd_heartbeat(void *hport); - -#endif /* _OZUSBIF_H */ diff --git a/drivers/staging/ozwpan/ozusbsvc.c b/drivers/staging/ozwpan/ozusbsvc.c deleted file mode 100644 index bf15dc301cb5..000000000000 --- a/drivers/staging/ozwpan/ozusbsvc.c +++ /dev/null @@ -1,263 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * - * This file provides protocol independent part of the implementation of the USB - * service for a PD. - * The implementation of this service is split into two parts the first of which - * is protocol independent and the second contains protocol specific details. - * This split is to allow alternative protocols to be defined. - * The implementation of this service uses ozhcd.c to implement a USB HCD. - * ----------------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ozdbg.h" -#include "ozprotocol.h" -#include "ozeltbuf.h" -#include "ozpd.h" -#include "ozproto.h" -#include "ozusbif.h" -#include "ozhcd.h" -#include "ozusbsvc.h" - -/* - * This is called once when the driver is loaded to initialise the USB service. - * Context: process - */ -int oz_usb_init(void) -{ - return oz_hcd_init(); -} - -/* - * This is called once when the driver is unloaded to terminate the USB service. - * Context: process - */ -void oz_usb_term(void) -{ - oz_hcd_term(); -} - -/* - * This is called when the USB service is started or resumed for a PD. - * Context: softirq - */ -int oz_usb_start(struct oz_pd *pd, int resume) -{ - int rc = 0; - struct oz_usb_ctx *usb_ctx; - struct oz_usb_ctx *old_ctx; - - if (resume) { - oz_dbg(ON, "USB service resumed\n"); - return 0; - } - oz_dbg(ON, "USB service started\n"); - /* Create a USB context in case we need one. If we find the PD already - * has a USB context then we will destroy it. - */ - usb_ctx = kzalloc(sizeof(struct oz_usb_ctx), GFP_ATOMIC); - if (usb_ctx == NULL) - return -ENOMEM; - atomic_set(&usb_ctx->ref_count, 1); - usb_ctx->pd = pd; - usb_ctx->stopped = 0; - /* Install the USB context if the PD doesn't already have one. - * If it does already have one then destroy the one we have just - * created. - */ - spin_lock_bh(&pd->app_lock[OZ_APPID_USB]); - old_ctx = pd->app_ctx[OZ_APPID_USB]; - if (old_ctx == NULL) - pd->app_ctx[OZ_APPID_USB] = usb_ctx; - oz_usb_get(pd->app_ctx[OZ_APPID_USB]); - spin_unlock_bh(&pd->app_lock[OZ_APPID_USB]); - if (old_ctx) { - oz_dbg(ON, "Already have USB context\n"); - kfree(usb_ctx); - usb_ctx = old_ctx; - } else if (usb_ctx) { - /* Take a reference to the PD. This will be released when - * the USB context is destroyed. - */ - oz_pd_get(pd); - } - /* If we already had a USB context and had obtained a port from - * the USB HCD then just reset the port. If we didn't have a port - * then report the arrival to the USB HCD so we get one. - */ - if (usb_ctx->hport) { - oz_hcd_pd_reset(usb_ctx, usb_ctx->hport); - } else { - usb_ctx->hport = oz_hcd_pd_arrived(usb_ctx); - if (usb_ctx->hport == NULL) { - oz_dbg(ON, "USB hub returned null port\n"); - spin_lock_bh(&pd->app_lock[OZ_APPID_USB]); - pd->app_ctx[OZ_APPID_USB] = NULL; - spin_unlock_bh(&pd->app_lock[OZ_APPID_USB]); - oz_usb_put(usb_ctx); - rc = -1; - } - } - oz_usb_put(usb_ctx); - return rc; -} - -/* - * This is called when the USB service is stopped or paused for a PD. - * Context: softirq or process - */ -void oz_usb_stop(struct oz_pd *pd, int pause) -{ - struct oz_usb_ctx *usb_ctx; - - if (pause) { - oz_dbg(ON, "USB service paused\n"); - return; - } - spin_lock_bh(&pd->app_lock[OZ_APPID_USB]); - usb_ctx = (struct oz_usb_ctx *) pd->app_ctx[OZ_APPID_USB]; - pd->app_ctx[OZ_APPID_USB] = NULL; - spin_unlock_bh(&pd->app_lock[OZ_APPID_USB]); - if (usb_ctx) { - struct timespec ts, now; - - getnstimeofday(&ts); - oz_dbg(ON, "USB service stopping...\n"); - usb_ctx->stopped = 1; - /* At this point the reference count on the usb context should - * be 2 - one from when we created it and one from the hcd - * which claims a reference. Since stopped = 1 no one else - * should get in but someone may already be in. So wait - * until they leave but timeout after 1 second. - */ - while ((atomic_read(&usb_ctx->ref_count) > 2)) { - getnstimeofday(&now); - /*Approx 1 Sec. this is not perfect calculation*/ - if (now.tv_sec != ts.tv_sec) - break; - } - oz_dbg(ON, "USB service stopped\n"); - oz_hcd_pd_departed(usb_ctx->hport); - /* Release the reference taken in oz_usb_start. - */ - oz_usb_put(usb_ctx); - } -} - -/* - * This increments the reference count of the context area for a specific PD. - * This ensures this context area does not disappear while still in use. - * Context: softirq - */ -void oz_usb_get(void *hpd) -{ - struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; - - atomic_inc(&usb_ctx->ref_count); -} - -/* - * This decrements the reference count of the context area for a specific PD - * and destroys the context area if the reference count becomes zero. - * Context: irq or process - */ -void oz_usb_put(void *hpd) -{ - struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; - - if (atomic_dec_and_test(&usb_ctx->ref_count)) { - oz_dbg(ON, "Dealloc USB context\n"); - oz_pd_put(usb_ctx->pd); - kfree(usb_ctx); - } -} - -/* - * Context: softirq - */ -int oz_usb_heartbeat(struct oz_pd *pd) -{ - struct oz_usb_ctx *usb_ctx; - int rc = 0; - - spin_lock_bh(&pd->app_lock[OZ_APPID_USB]); - usb_ctx = (struct oz_usb_ctx *) pd->app_ctx[OZ_APPID_USB]; - if (usb_ctx) - oz_usb_get(usb_ctx); - spin_unlock_bh(&pd->app_lock[OZ_APPID_USB]); - if (usb_ctx == NULL) - return rc; - if (usb_ctx->stopped) - goto done; - if (usb_ctx->hport) - if (oz_hcd_heartbeat(usb_ctx->hport)) - rc = 1; -done: - oz_usb_put(usb_ctx); - return rc; -} - -/* - * Context: softirq - */ -int oz_usb_stream_create(void *hpd, u8 ep_num) -{ - struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; - struct oz_pd *pd = usb_ctx->pd; - - oz_dbg(ON, "%s: (0x%x)\n", __func__, ep_num); - if (pd->mode & OZ_F_ISOC_NO_ELTS) { - oz_isoc_stream_create(pd, ep_num); - } else { - oz_pd_get(pd); - if (oz_elt_stream_create(&pd->elt_buff, ep_num, - 4*pd->max_tx_size)) { - oz_pd_put(pd); - return -1; - } - } - return 0; -} - -/* - * Context: softirq - */ -int oz_usb_stream_delete(void *hpd, u8 ep_num) -{ - struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; - - if (usb_ctx) { - struct oz_pd *pd = usb_ctx->pd; - - if (pd) { - oz_dbg(ON, "%s: (0x%x)\n", __func__, ep_num); - if (pd->mode & OZ_F_ISOC_NO_ELTS) { - oz_isoc_stream_delete(pd, ep_num); - } else { - if (oz_elt_stream_delete(&pd->elt_buff, ep_num)) - return -1; - oz_pd_put(pd); - } - } - } - return 0; -} - -/* - * Context: softirq or process - */ -void oz_usb_request_heartbeat(void *hpd) -{ - struct oz_usb_ctx *usb_ctx = (struct oz_usb_ctx *)hpd; - - if (usb_ctx && usb_ctx->pd) - oz_pd_request_heartbeat(usb_ctx->pd); -} diff --git a/drivers/staging/ozwpan/ozusbsvc.h b/drivers/staging/ozwpan/ozusbsvc.h deleted file mode 100644 index 58e05a59be31..000000000000 --- a/drivers/staging/ozwpan/ozusbsvc.h +++ /dev/null @@ -1,32 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * ----------------------------------------------------------------------------- - */ -#ifndef _OZUSBSVC_H -#define _OZUSBSVC_H - -/*------------------------------------------------------------------------------ - * Per PD context info stored in application context area of PD. - * This object is reference counted to ensure it doesn't disappear while - * still in use. - */ -struct oz_usb_ctx { - atomic_t ref_count; - u8 tx_seq_num; - u8 rx_seq_num; - struct oz_pd *pd; - void *hport; - int stopped; -}; - -int oz_usb_init(void); -void oz_usb_term(void); -int oz_usb_start(struct oz_pd *pd, int resume); -void oz_usb_stop(struct oz_pd *pd, int pause); -void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt); -int oz_usb_heartbeat(struct oz_pd *pd); -void oz_usb_farewell(struct oz_pd *pd, u8 ep_num, u8 *data, u8 len); - -#endif /* _OZUSBSVC_H */ - diff --git a/drivers/staging/ozwpan/ozusbsvc1.c b/drivers/staging/ozwpan/ozusbsvc1.c deleted file mode 100644 index b6cfecbeabf7..000000000000 --- a/drivers/staging/ozwpan/ozusbsvc1.c +++ /dev/null @@ -1,472 +0,0 @@ -/* ----------------------------------------------------------------------------- - * Copyright (c) 2011 Ozmo Inc - * Released under the GNU General Public License Version 2 (GPLv2). - * - * This file implements the protocol specific parts of the USB service for a PD. - * ----------------------------------------------------------------------------- - */ -#include -#include -#include -#include -#include -#include -#include -#include "ozdbg.h" -#include "ozprotocol.h" -#include "ozeltbuf.h" -#include "ozpd.h" -#include "ozproto.h" -#include "ozusbif.h" -#include "ozhcd.h" -#include "ozusbsvc.h" - -#define MAX_ISOC_FIXED_DATA (253-sizeof(struct oz_isoc_fixed)) - -/* - * Context: softirq - */ -static int oz_usb_submit_elt(struct oz_elt_buf *eb, struct oz_elt_info *ei, - struct oz_usb_ctx *usb_ctx, u8 strid, u8 isoc) -{ - int ret; - struct oz_elt *elt = (struct oz_elt *)ei->data; - struct oz_app_hdr *app_hdr = (struct oz_app_hdr *)(elt+1); - - elt->type = OZ_ELT_APP_DATA; - ei->app_id = OZ_APPID_USB; - ei->length = elt->length + sizeof(struct oz_elt); - app_hdr->app_id = OZ_APPID_USB; - spin_lock_bh(&eb->lock); - if (isoc == 0) { - app_hdr->elt_seq_num = usb_ctx->tx_seq_num++; - if (usb_ctx->tx_seq_num == 0) - usb_ctx->tx_seq_num = 1; - } - ret = oz_queue_elt_info(eb, isoc, strid, ei); - if (ret) - oz_elt_info_free(eb, ei); - spin_unlock_bh(&eb->lock); - return ret; -} - -/* - * Context: softirq - */ -int oz_usb_get_desc_req(void *hpd, u8 req_id, u8 req_type, u8 desc_type, - u8 index, __le16 windex, int offset, int len) -{ - struct oz_usb_ctx *usb_ctx = hpd; - struct oz_pd *pd = usb_ctx->pd; - struct oz_elt *elt; - struct oz_get_desc_req *body; - struct oz_elt_buf *eb = &pd->elt_buff; - struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff); - - oz_dbg(ON, " req_type = 0x%x\n", req_type); - oz_dbg(ON, " desc_type = 0x%x\n", desc_type); - oz_dbg(ON, " index = 0x%x\n", index); - oz_dbg(ON, " windex = 0x%x\n", windex); - oz_dbg(ON, " offset = 0x%x\n", offset); - oz_dbg(ON, " len = 0x%x\n", len); - if (len > 200) - len = 200; - if (ei == NULL) - return -1; - elt = (struct oz_elt *)ei->data; - elt->length = sizeof(struct oz_get_desc_req); - body = (struct oz_get_desc_req *)(elt+1); - body->type = OZ_GET_DESC_REQ; - body->req_id = req_id; - put_unaligned(cpu_to_le16(offset), &body->offset); - put_unaligned(cpu_to_le16(len), &body->size); - body->req_type = req_type; - body->desc_type = desc_type; - body->w_index = windex; - body->index = index; - return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0); -} - -/* - * Context: tasklet - */ -static int oz_usb_set_config_req(void *hpd, u8 req_id, u8 index) -{ - struct oz_usb_ctx *usb_ctx = hpd; - struct oz_pd *pd = usb_ctx->pd; - struct oz_elt *elt; - struct oz_elt_buf *eb = &pd->elt_buff; - struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff); - struct oz_set_config_req *body; - - if (ei == NULL) - return -1; - elt = (struct oz_elt *)ei->data; - elt->length = sizeof(struct oz_set_config_req); - body = (struct oz_set_config_req *)(elt+1); - body->type = OZ_SET_CONFIG_REQ; - body->req_id = req_id; - body->index = index; - return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0); -} - -/* - * Context: tasklet - */ -static int oz_usb_set_interface_req(void *hpd, u8 req_id, u8 index, u8 alt) -{ - struct oz_usb_ctx *usb_ctx = hpd; - struct oz_pd *pd = usb_ctx->pd; - struct oz_elt *elt; - struct oz_elt_buf *eb = &pd->elt_buff; - struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff); - struct oz_set_interface_req *body; - - if (ei == NULL) - return -1; - elt = (struct oz_elt *)ei->data; - elt->length = sizeof(struct oz_set_interface_req); - body = (struct oz_set_interface_req *)(elt+1); - body->type = OZ_SET_INTERFACE_REQ; - body->req_id = req_id; - body->index = index; - body->alternative = alt; - return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0); -} - -/* - * Context: tasklet - */ -static int oz_usb_set_clear_feature_req(void *hpd, u8 req_id, u8 type, - u8 recipient, u8 index, __le16 feature) -{ - struct oz_usb_ctx *usb_ctx = hpd; - struct oz_pd *pd = usb_ctx->pd; - struct oz_elt *elt; - struct oz_elt_buf *eb = &pd->elt_buff; - struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff); - struct oz_feature_req *body; - - if (ei == NULL) - return -1; - elt = (struct oz_elt *)ei->data; - elt->length = sizeof(struct oz_feature_req); - body = (struct oz_feature_req *)(elt+1); - body->type = type; - body->req_id = req_id; - body->recipient = recipient; - body->index = index; - put_unaligned(feature, &body->feature); - return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0); -} - -/* - * Context: tasklet - */ -static int oz_usb_vendor_class_req(void *hpd, u8 req_id, u8 req_type, - u8 request, __le16 value, __le16 index, const u8 *data, int data_len) -{ - struct oz_usb_ctx *usb_ctx = hpd; - struct oz_pd *pd = usb_ctx->pd; - struct oz_elt *elt; - struct oz_elt_buf *eb = &pd->elt_buff; - struct oz_elt_info *ei = oz_elt_info_alloc(&pd->elt_buff); - struct oz_vendor_class_req *body; - - if (ei == NULL) - return -1; - elt = (struct oz_elt *)ei->data; - elt->length = sizeof(struct oz_vendor_class_req) - 1 + data_len; - body = (struct oz_vendor_class_req *)(elt+1); - body->type = OZ_VENDOR_CLASS_REQ; - body->req_id = req_id; - body->req_type = req_type; - body->request = request; - put_unaligned(value, &body->value); - put_unaligned(index, &body->index); - if (data_len) - memcpy(body->data, data, data_len); - return oz_usb_submit_elt(eb, ei, usb_ctx, 0, 0); -} - -/* - * Context: tasklet - */ -int oz_usb_control_req(void *hpd, u8 req_id, struct usb_ctrlrequest *setup, - const u8 *data, int data_len) -{ - unsigned wvalue = le16_to_cpu(setup->wValue); - unsigned windex = le16_to_cpu(setup->wIndex); - unsigned wlength = le16_to_cpu(setup->wLength); - int rc = 0; - - if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - switch (setup->bRequest) { - case USB_REQ_GET_DESCRIPTOR: - rc = oz_usb_get_desc_req(hpd, req_id, - setup->bRequestType, (u8)(wvalue>>8), - (u8)wvalue, setup->wIndex, 0, wlength); - break; - case USB_REQ_SET_CONFIGURATION: - rc = oz_usb_set_config_req(hpd, req_id, (u8)wvalue); - break; - case USB_REQ_SET_INTERFACE: { - u8 if_num = (u8)windex; - u8 alt = (u8)wvalue; - - rc = oz_usb_set_interface_req(hpd, req_id, - if_num, alt); - } - break; - case USB_REQ_SET_FEATURE: - rc = oz_usb_set_clear_feature_req(hpd, req_id, - OZ_SET_FEATURE_REQ, - setup->bRequestType & 0xf, (u8)windex, - setup->wValue); - break; - case USB_REQ_CLEAR_FEATURE: - rc = oz_usb_set_clear_feature_req(hpd, req_id, - OZ_CLEAR_FEATURE_REQ, - setup->bRequestType & 0xf, - (u8)windex, setup->wValue); - break; - } - } else { - rc = oz_usb_vendor_class_req(hpd, req_id, setup->bRequestType, - setup->bRequest, setup->wValue, setup->wIndex, - data, data_len); - } - return rc; -} - -/* - * Context: softirq - */ -int oz_usb_send_isoc(void *hpd, u8 ep_num, struct urb *urb) -{ - struct oz_usb_ctx *usb_ctx = hpd; - struct oz_pd *pd = usb_ctx->pd; - struct oz_elt_buf *eb; - int i; - int hdr_size; - u8 *data; - struct usb_iso_packet_descriptor *desc; - - if (pd->mode & OZ_F_ISOC_NO_ELTS) { - for (i = 0; i < urb->number_of_packets; i++) { - u8 *data; - - desc = &urb->iso_frame_desc[i]; - data = ((u8 *)urb->transfer_buffer)+desc->offset; - oz_send_isoc_unit(pd, ep_num, data, desc->length); - } - return 0; - } - - hdr_size = sizeof(struct oz_isoc_fixed) - 1; - eb = &pd->elt_buff; - i = 0; - while (i < urb->number_of_packets) { - struct oz_elt_info *ei = oz_elt_info_alloc(eb); - struct oz_elt *elt; - struct oz_isoc_fixed *body; - int unit_count; - int unit_size; - int rem; - - if (ei == NULL) - return -1; - rem = MAX_ISOC_FIXED_DATA; - elt = (struct oz_elt *)ei->data; - body = (struct oz_isoc_fixed *)(elt + 1); - body->type = OZ_USB_ENDPOINT_DATA; - body->endpoint = ep_num; - body->format = OZ_DATA_F_ISOC_FIXED; - unit_size = urb->iso_frame_desc[i].length; - body->unit_size = (u8)unit_size; - data = ((u8 *)(elt+1)) + hdr_size; - unit_count = 0; - while (i < urb->number_of_packets) { - desc = &urb->iso_frame_desc[i]; - if ((unit_size == desc->length) && - (desc->length <= rem)) { - memcpy(data, ((u8 *)urb->transfer_buffer) + - desc->offset, unit_size); - data += unit_size; - rem -= unit_size; - unit_count++; - desc->status = 0; - desc->actual_length = desc->length; - i++; - } else { - break; - } - } - elt->length = hdr_size + MAX_ISOC_FIXED_DATA - rem; - /* Store the number of units in body->frame_number for the - * moment. This field will be correctly determined before - * the element is sent. */ - body->frame_number = (u8)unit_count; - oz_usb_submit_elt(eb, ei, usb_ctx, ep_num, - pd->mode & OZ_F_ISOC_ANYTIME); - } - return 0; -} - -/* - * Context: softirq-serialized - */ -static void oz_usb_handle_ep_data(struct oz_usb_ctx *usb_ctx, - struct oz_usb_hdr *usb_hdr, int len) -{ - struct oz_data *data_hdr = (struct oz_data *)usb_hdr; - - switch (data_hdr->format) { - case OZ_DATA_F_MULTIPLE_FIXED: { - struct oz_multiple_fixed *body = - (struct oz_multiple_fixed *)data_hdr; - u8 *data = body->data; - unsigned int n; - - if (!body->unit_size || - len < sizeof(struct oz_multiple_fixed) - 1) - break; - n = (len - (sizeof(struct oz_multiple_fixed) - 1)) - / body->unit_size; - while (n--) { - oz_hcd_data_ind(usb_ctx->hport, body->endpoint, - data, body->unit_size); - data += body->unit_size; - } - } - break; - case OZ_DATA_F_ISOC_FIXED: { - struct oz_isoc_fixed *body = - (struct oz_isoc_fixed *)data_hdr; - int data_len; - int unit_size = body->unit_size; - u8 *data = body->data; - int count; - int i; - - if (len < sizeof(struct oz_isoc_fixed) - 1) - break; - data_len = len - (sizeof(struct oz_isoc_fixed) - 1); - - if (!unit_size) - break; - count = data_len/unit_size; - for (i = 0; i < count; i++) { - oz_hcd_data_ind(usb_ctx->hport, - body->endpoint, data, unit_size); - data += unit_size; - } - } - break; - } - -} - -/* - * This is called when the PD has received a USB element. The type of element - * is determined and is then passed to an appropriate handler function. - * Context: softirq-serialized - */ -void oz_usb_rx(struct oz_pd *pd, struct oz_elt *elt) -{ - struct oz_usb_hdr *usb_hdr = (struct oz_usb_hdr *)(elt + 1); - struct oz_usb_ctx *usb_ctx; - - spin_lock_bh(&pd->app_lock[OZ_APPID_USB]); - usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB]; - if (usb_ctx) - oz_usb_get(usb_ctx); - spin_unlock_bh(&pd->app_lock[OZ_APPID_USB]); - if (usb_ctx == NULL) - return; /* Context has gone so nothing to do. */ - if (usb_ctx->stopped) - goto done; - /* If sequence number is non-zero then check it is not a duplicate. - * Zero sequence numbers are always accepted. - */ - if (usb_hdr->elt_seq_num != 0) { - if (((usb_ctx->rx_seq_num - usb_hdr->elt_seq_num) & 0x80) == 0) - /* Reject duplicate element. */ - goto done; - } - usb_ctx->rx_seq_num = usb_hdr->elt_seq_num; - switch (usb_hdr->type) { - case OZ_GET_DESC_RSP: { - struct oz_get_desc_rsp *body = - (struct oz_get_desc_rsp *)usb_hdr; - u16 offs, total_size; - u8 data_len; - - if (elt->length < sizeof(struct oz_get_desc_rsp) - 1) - break; - data_len = elt->length - - (sizeof(struct oz_get_desc_rsp) - 1); - offs = le16_to_cpu(get_unaligned(&body->offset)); - total_size = - le16_to_cpu(get_unaligned(&body->total_size)); - oz_dbg(ON, "USB_REQ_GET_DESCRIPTOR - cnf\n"); - oz_hcd_get_desc_cnf(usb_ctx->hport, body->req_id, - body->rcode, body->data, - data_len, offs, total_size); - } - break; - case OZ_SET_CONFIG_RSP: { - struct oz_set_config_rsp *body = - (struct oz_set_config_rsp *)usb_hdr; - oz_hcd_control_cnf(usb_ctx->hport, body->req_id, - body->rcode, NULL, 0); - } - break; - case OZ_SET_INTERFACE_RSP: { - struct oz_set_interface_rsp *body = - (struct oz_set_interface_rsp *)usb_hdr; - oz_hcd_control_cnf(usb_ctx->hport, - body->req_id, body->rcode, NULL, 0); - } - break; - case OZ_VENDOR_CLASS_RSP: { - struct oz_vendor_class_rsp *body = - (struct oz_vendor_class_rsp *)usb_hdr; - - if (elt->length < - sizeof(struct oz_vendor_class_rsp) - 1) - break; - - oz_hcd_control_cnf(usb_ctx->hport, body->req_id, - body->rcode, body->data, elt->length- - sizeof(struct oz_vendor_class_rsp)+1); - } - break; - case OZ_USB_ENDPOINT_DATA: - oz_usb_handle_ep_data(usb_ctx, usb_hdr, elt->length); - break; - } -done: - oz_usb_put(usb_ctx); -} - -/* - * Context: softirq, process - */ -void oz_usb_farewell(struct oz_pd *pd, u8 ep_num, u8 *data, u8 len) -{ - struct oz_usb_ctx *usb_ctx; - - spin_lock_bh(&pd->app_lock[OZ_APPID_USB]); - usb_ctx = (struct oz_usb_ctx *)pd->app_ctx[OZ_APPID_USB]; - if (usb_ctx) - oz_usb_get(usb_ctx); - spin_unlock_bh(&pd->app_lock[OZ_APPID_USB]); - if (usb_ctx == NULL) - return; /* Context has gone so nothing to do. */ - if (!usb_ctx->stopped) { - oz_dbg(ON, "Farewell indicated ep = 0x%x\n", ep_num); - oz_hcd_data_ind(usb_ctx->hport, ep_num, data, len); - } - oz_usb_put(usb_ctx); -} -- cgit v1.3-6-gb490 From 2584cf83578c26db144730ef498f4070f82ee3ea Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 10 Aug 2015 23:07:05 -0400 Subject: arch, drivers: don't include directly, use instead Preparation for uniform definition of ioremap, ioremap_wc, ioremap_wt, and ioremap_cache, tree-wide. Acked-by: Christoph Hellwig Signed-off-by: Dan Williams --- arch/arm/mach-shmobile/pm-rcar.c | 2 +- arch/ia64/kernel/cyclone.c | 2 +- drivers/isdn/icn/icn.h | 2 +- drivers/mtd/devices/slram.c | 2 +- drivers/mtd/nand/diskonchip.c | 2 +- drivers/mtd/onenand/generic.c | 2 +- drivers/scsi/sun3x_esp.c | 2 +- drivers/staging/comedi/drivers/ii_pci20kc.c | 1 + drivers/tty/serial/8250/8250_core.c | 2 +- drivers/video/fbdev/s1d13xxxfb.c | 3 +-- drivers/video/fbdev/stifb.c | 1 + include/linux/io-mapping.h | 2 +- include/linux/mtd/map.h | 2 +- include/video/vga.h | 2 +- 14 files changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-shmobile/pm-rcar.c b/arch/arm/mach-shmobile/pm-rcar.c index 00022ee56f80..9d3dde00c2fe 100644 --- a/arch/arm/mach-shmobile/pm-rcar.c +++ b/arch/arm/mach-shmobile/pm-rcar.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "pm-rcar.h" /* SYSC */ diff --git a/arch/ia64/kernel/cyclone.c b/arch/ia64/kernel/cyclone.c index 4826ff957a3d..5fa3848ba224 100644 --- a/arch/ia64/kernel/cyclone.c +++ b/arch/ia64/kernel/cyclone.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include /* IBM Summit (EXA) Cyclone counter code*/ #define CYCLONE_CBAR_ADDR 0xFEB00CD0 diff --git a/drivers/isdn/icn/icn.h b/drivers/isdn/icn/icn.h index b713466997a0..f8f2e76d34bf 100644 --- a/drivers/isdn/icn/icn.h +++ b/drivers/isdn/icn/icn.h @@ -38,7 +38,7 @@ typedef struct icn_cdef { #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 2fc4957cbe7f..a70eb83e68f1 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 7da266a53979..0802158a3f75 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 32a216d31141..ab7bda0bb245 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include /* * Note: Driver name and platform data format have been updated! diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index e26e81de7c45..d50c5ed8f428 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -12,9 +12,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index 0768bc42a5db..14ef1f67dd42 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -28,6 +28,7 @@ */ #include +#include #include "../comedidev.h" /* diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 37fff12dd4d0..fe902ff52e58 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -38,11 +38,11 @@ #include #include #include +#include #ifdef CONFIG_SPARC #include #endif -#include #include #include "8250.h" diff --git a/drivers/video/fbdev/s1d13xxxfb.c b/drivers/video/fbdev/s1d13xxxfb.c index 83433cb0dfba..96aa46dc696c 100644 --- a/drivers/video/fbdev/s1d13xxxfb.c +++ b/drivers/video/fbdev/s1d13xxxfb.c @@ -32,8 +32,7 @@ #include #include #include - -#include +#include #include